About

In this lab, we will learn how to run a sensitivity analysis on the marketing use case, and how to generate random samples from a simple normal distribution similar to a Monte Carlo simulation.

Setup

Remember to always set your working directory to the source file location. Go to ‘Session’, scroll down to ‘Set Working Directory’, and click ‘To Source File Location’. Read carefully the below and follow the instructions to complete the tasks and answer any questions. Submit your work in Sakai as detailed in previous notes.

Note

For your assignment you may be using different data sets than what is included here. Always read carefully the instructions provided, before executing any included code chunks and/or adding your own code. For clarity, tasks/questions to be completed/answered are highlighted in red color and numbered according to their particular placement in the task section. The red color is only apparent when in Preview mode. Quite often you will need to add your own code chunk.

Execute all code chunks (already included and own added), preview, check integrity, and submit final work (\(html\) file) in Sakai.


Task 1: Sensitivity Analysis

Sensitivity analysis is the study of how the uncertainty in the output of a mathematical model or system (numerical or otherwise) can be apportioned to different sources of uncertainty in its inputs. We will use the lpSolveAPI R-package as we did in the previous lab.

In order to conduct a sensitivity analysis, we will need to download again the lpSolveAPI package unless you have it already installed in your R environment

# Require will load the package only if not installed 
# Dependencies = TRUE makes sure that dependencies are install
if(!require("lpSolveAPI",quietly = TRUE))
  install.packages("lpSolveAPI",dependencies = TRUE, repos = "https://cloud.r-project.org")

We will revisit and solve again the marketing case discussed in class (also part of previous lab).

# We start with `0` constraint and `2` decision variables. The object name `lpmark` is discretionary.
lpmark = make.lp(0, 2)

# Define type of optimization as maximum and dump the screen output into a `dummy` variable
dummy = lp.control(lpmark, sense="max") 
# Set the objective function coefficients 
set.objfn(lpmark, c(275.691, 48.341))

Add all constraints to the model.

add.constraint(lpmark, c(1, 1), "<=", 350000)
add.constraint(lpmark, c(1, 0), ">=", 15000)
add.constraint(lpmark, c(0, 1), ">=", 75000)
add.constraint(lpmark, c(2, -1), "=", 0)
add.constraint(lpmark, c(1, 0), ">=", 0)
add.constraint(lpmark, c(0, 1), ">=", 0)

Now, view the problem setting in tabular/matrix form. This is a good checkpoint to confirm that our contraints have been properly set.

lpmark
Model name: 
               C1       C2            
Maximize  275.691   48.341            
R1              1        1  <=  350000
R2              1        0  >=   15000
R3              0        1  >=   75000
R4              2       -1   =       0
R5              1        0  >=       0
R6              0        1  >=       0
Kind          Std      Std            
Type         Real     Real            
Upper         Inf      Inf            
Lower           0        0            
# solve
solve(lpmark) 
[1] 0

Next we get the optimum results.

# display the objective function optimum value
get.objective(lpmark)
[1] 43443517
# display the decision variables optimum values
get.variables(lpmark)
[1] 116666.7 233333.3

For sensitivity we will introduce the code command to obtain the sensitivities due to changes in resources as expressed in the right hand side (rhs) constraints.

# display sensitivity to rhs constraints. 
# There will be a total of m+n values where m is the number of contraints and n is the number of decision variables
get.sensitivity.rhs(lpmark) 
$duals
[1] 124.12433   0.00000   0.00000  75.78333   0.00000
[6]   0.00000   0.00000   0.00000

$dualsfrom
[1]  1.125e+05 -1.000e+30 -1.000e+30 -3.050e+05
[5] -1.000e+30 -1.000e+30 -1.000e+30 -1.000e+30

$dualstill
[1] 1.00e+30 1.00e+30 1.00e+30 4.75e+05 1.00e+30
[6] 1.00e+30 1.00e+30 1.00e+30

For this exercise we are only interested in the first six values (corresponding to the six constraints) of the output labeled duals.

##### 1A) Identify and explain what the binding/non-binding constraints, the surplus/slack, and the marginal values are and what they represent in the context of our marketing use case (4pts) Binding values have nonzero marginal values. In this case, it is the first and forth contraints. (max budget of 350,000 [x1+x2<=350000] and tv ads must be 2x more than radio ads [2x1-x1=0]) The marginal value for the first constraint means that for each $1 increase in the overall budget (350,000 to 350,001) sales will increase by 124.12 dollars The marginal value for the forth constraint is that for each dollar increase in the limit/contraint, the sales will increase by 75.78 dollars. The marginal value for the second, third, fifth and sixth constraint means that for every $1 increase in their limit (ex: second constraint goes from 15,000 to 15,001, etc.), sales will increase by zero dollars. The surplus of the first constraint is zero. This means that the outcome was equal to the limit. (116,666.7+223,3333.3 =350,000 350,000-350,000=0) The surplus of the second constraint is 101,666.7. This means the outcome was over the minimun by 101,666.7 (116,666.7-15,000=101,666.7) The Surplus of the third constraint is 233,333.3. This means the outcome was over the minimum by 233,333.3 (233,333.3-75,000=158,333.3) The surplus of the forth constraint is zero. This means that the outcome was equal to the limit. (2(116,666.7)-1(233,333.3)=0) The surplus of the fifth constraint is 116,666.7. This means the outcome was over the minimym by 116,666.7 (116,666.7-0=116,666.7) The surplus of the sixth constraint is 233,333.3. This means the outcome was over the minimum by 233,333.3 (233,333.3-0=233,333.3) The non binding contraints are the second, third, fifth, and sixth constraints. (x1>=15000, x2=>75000, x1>=0, and x2>=0)

To acquire a better understanding of the sensitivity results, and to confirm integrity of the calculations, independent tests can be conducted. To demonstrate, we will repeat the linear programming (LP) optimization problem by slightly tweaking one binding constraint and verifying the impact.

##### 1B) Define a new model object lpmark1 and add the constraints exactly as entered at beginning of this task. All being equal, change the budget constraint by a marginal $1 value and solve the LP problem. Note the new optimum value for sales. Calculate the differential change in optimum sales from the earlier computed optimum sales, and compare your calculation to the value obtained from the prior sensitivity calculation (4pts)

# Define a new model object called lpmark1
lpmark1 = make.lp(0, 2)
dummy = lp.control(lpmark1, sense="max") 
# Set the objective function coefficients 
set.objfn(lpmark1, c(275.691, 48.341))
# Repeat rest of commands with the one constraint change for budget. Solve and display the objective function optimum value
add.constraint(lpmark1, c(1, 1), "<=", 350001)
add.constraint(lpmark1, c(1, 0), ">=", 15000)
add.constraint(lpmark1, c(0, 1), ">=", 75000)
add.constraint(lpmark1, c(2, -1), "=", 0)
add.constraint(lpmark1, c(1, 0), ">=", 0)
add.constraint(lpmark1, c(0, 1), ">=", 0)
lpmark1
Model name: 
               C1       C2            
Maximize  275.691   48.341            
R1              1        1  <=  350001
R2              1        0  >=   15000
R3              0        1  >=   75000
R4              2       -1   =       0
R5              1        0  >=       0
R6              0        1  >=       0
Kind          Std      Std            
Type         Real     Real            
Upper         Inf      Inf            
Lower           0        0            
solve(lpmark1) 
[1] 0
get.objective(lpmark1)
[1] 43443641
get.variables(lpmark1)
[1] 116667 233334

This data (lpmark1) shows sales is 43,443,641 compared to 43443517 sales from lpmark. This difference is a $124 difference. This number matches the marginal value calculated in the previous park. This means for the dollar increase in budget, sales increased by 124 dollars, which it did.

1C) Following the logic of calculations in 1B) and without running another code, explain the steps to validate the integrity of the other remaining marginal value identified in 1A). Use a different line to explain each step (4pts)

You could use another lpmark to do that. You would define another lpmark, called lpmark2 and make it analze two variables. You would set the objective to maximize sales and use the function coefficients to have x1=275.691 and x2=48.341. Then you would set the contraints. You would use the same ones as lpmark, but the forth constraint would be 2x1-1x1=1, instead of 2x1-1x1=0. Then you would solve, get the objective, and get the variables. Then you could see the new maximized sales. You would use this to find the difference from lmpark sales and lpmark2 sales.This difference should equal $75, the same as the marginal value.


Task 2: Random Sampling & Monte Carlo Simulation

Monte Carlo Simulations utilize repeated random sampling from a given universe or population distribution to derive certain results. This type of simulation is known as a probabilistic simulation, as opposed to a deterministic simulation.

An example of a Monte Carlo simulation is the one applied to approximate the value of pi. The simulation is based on generating random points within a unit square and see how many points fall within the circle enclosed by the unit square (marked in red). The value of pi is estimated by the number of points inside the circle over the total number of points generated inside the square. The higher the number of sampled points the closer the result is to the actual result. After selecting 30,000 random points, the estimate for pi is much closer to the actual value within the four decimal points of precision. The interested and curious reader is encouraged to explore the mathematical foundation behind the logic.

For this task we will be running a Monte Carlo simulation to calculate the probability that the daily return from S&P will be > 5%. We will assume that the historical S&P daily return follows a normal distribution with an average daily return of 0.03 (%) and a standard deviation of 0.97 (%). Consider this as our population.

To begin we will generate 100 random samples from the normal distribution. For the generated samples we will calculate the mean, standard deviation, and probability of occurrence where the simulation result is greater than 5%.

To generate random samples from a normal distribution we will use the rnorm() function in R. In the example below we set the number of runs (or samples) to 100.

# number of simulations/samples
runs = 100
# random number generator per defined normal distribution with given mean and standard deviation
sims =  rnorm(runs,mean=0.03,sd=0.97)
# Mean calculated from the random distribution of samples
average = mean(sims)
average
[1] -0.04732575
# STD calculated from the random distribution of samples
std = sd(sims) 
std
[1] 0.9802492
# probability of occurrence on any given day based on samples will be equal to count (or sum) where sample result is greater than 5% divided by total number of samples. 
prob = sum(sims >=0.05)/runs
prob
[1] 0.474

##### 2A) Repeat the above calculations for the two cases where the number of simulations/samples is equal to 1000 and 10000. For each case record the mean, standard deviation, and probability (4pts)

# Repeat calculations here
# simulations/sample
runs = 1000
# random number generator per defined normal distribution with given mean and standard deviation
sims =  rnorm(runs,mean=0.03,sd=0.97)
##Mean calculated from the random distribution of samples
average = mean(sims)
average
[1] 0.03134824
# STD calculated from the random distribution of samples
std = sd(sims) 
std
[1] 0.9733819
prob = sum(sims >=0.05)/runs
probprob = sum(sims >=0.05)/runs
prob
[1] 0.483
# Repeat calculations here
# simulations/sample
runs = 10000
# random number generator per defined normal distribution with given mean and standard deviation
sims =  rnorm(runs,mean=0.03,sd=0.97)
##Mean calculated from the random distribution of samples
average = mean(sims)
average
[1] 0.02370166
# STD calculated from the random distribution of samples
std = sd(sims) 
std
[1] 0.9676935
prob = sum(sims >=0.05)/runs
probprob = sum(sims >=0.05)/runs
prob
[1] 0.4852

##### 2B) List in seperate lines the values for mean, standard deviation, and probability for all three cases: 100, 1000, and 10000 simulations. Describe how the values change/behave as the number of simulations is increased. What is your best bet on the probability of occurrence greater than 5% and why? How is this behavior similar to the use case demonstration to calculate pi? (4pts) 100 runs: mean: -0.04732575 standard deviation: 0.9802492 probability: 0.474

1000 runs: mean:0.03134824 standard deviation: 0.9733819 probability:0.483

10000 runs: mean:0.02370166 standard deviation:0.9676935 probability:0.4852

As the number of runs increased, the probability got bigger, but the increase in probability was not as great from 1000 to 10000 runs compared to the 100 to 1000 run change. The standard deviation decreased as the run count got larger. The same case was true here, as the standard deviation changed from 1000 to 10000 runs, the change was not as large as the change from 100 to 1000 runs. This is similar to a graph converging to a line. As the x value, or # of runs increases, it will get closer and closer to the true value. I think the 10,000 run simulation would be closer to the actual true value. The larger the sample/number of runs, the less impact an outlier would have on the data. Just like in statistics, the larger sample gives better data, in accuracy and representation. Just like pi, after selecting more random points, (pi was 30,000 but here it’s 10,000) the estimate will get closer to the actual value.

LS0tDQp0aXRsZTogIlNlbnNpdGl2aXR5IEFuYWx5c2lzICYgU2ltdWxhdGlvbnMgKGxhYjA5KSINCmF1dGhvcjogIkxhdXJlbiBLcm9sbCINCmRhdGU6ICI0LzkvMjAyMCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0Kc3VidGl0bGU6IEJTQUQgMzQzSCwgQnVzaW5lc3MgQW5hbHl0aWNzLCBTcHJpbmcgMjAyMA0KLS0tDQoNCg0KIyMjIEFib3V0DQoNCkluIHRoaXMgbGFiLCB3ZSB3aWxsIGxlYXJuIGhvdyB0byBydW4gYSBzZW5zaXRpdml0eSBhbmFseXNpcyBvbiB0aGUgbWFya2V0aW5nIHVzZSBjYXNlLCBhbmQgaG93IHRvIGdlbmVyYXRlIHJhbmRvbSBzYW1wbGVzIGZyb20gYSBzaW1wbGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiBzaW1pbGFyIHRvIGEgTW9udGUgQ2FybG8gc2ltdWxhdGlvbi4NCg0KIyMjIFNldHVwDQoNClJlbWVtYmVyIHRvIGFsd2F5cyBzZXQgeW91ciB3b3JraW5nIGRpcmVjdG9yeSB0byB0aGUgc291cmNlIGZpbGUgbG9jYXRpb24uIEdvIHRvICdTZXNzaW9uJywgc2Nyb2xsIGRvd24gdG8gJ1NldCBXb3JraW5nIERpcmVjdG9yeScsIGFuZCBjbGljayAnVG8gU291cmNlIEZpbGUgTG9jYXRpb24nLiBSZWFkIGNhcmVmdWxseSB0aGUgYmVsb3cgYW5kIGZvbGxvdyB0aGUgaW5zdHJ1Y3Rpb25zIHRvIGNvbXBsZXRlIHRoZSB0YXNrcyBhbmQgYW5zd2VyIGFueSBxdWVzdGlvbnMuICBTdWJtaXQgeW91ciB3b3JrIGluIFNha2FpIGFzIGRldGFpbGVkIGluIHByZXZpb3VzIG5vdGVzLiANCg0KIyMjIE5vdGUNCg0KRm9yIHlvdXIgYXNzaWdubWVudCB5b3UgbWF5IGJlIHVzaW5nIGRpZmZlcmVudCBkYXRhIHNldHMgdGhhbiB3aGF0IGlzIGluY2x1ZGVkIGhlcmUuIEFsd2F5cyByZWFkIGNhcmVmdWxseSB0aGUgaW5zdHJ1Y3Rpb25zIHByb3ZpZGVkLCBiZWZvcmUgZXhlY3V0aW5nIGFueSBpbmNsdWRlZCBjb2RlIGNodW5rcyBhbmQvb3IgYWRkaW5nIHlvdXIgb3duIGNvZGUuICBGb3IgY2xhcml0eSwgdGFza3MvcXVlc3Rpb25zIHRvIGJlIGNvbXBsZXRlZC9hbnN3ZXJlZCBhcmUgaGlnaGxpZ2h0ZWQgaW4gcmVkIGNvbG9yIGFuZCBudW1iZXJlZCBhY2NvcmRpbmcgdG8gdGhlaXIgcGFydGljdWxhciBwbGFjZW1lbnQgaW4gdGhlIHRhc2sgc2VjdGlvbi4gIFRoZSByZWQgY29sb3IgaXMgb25seSBhcHBhcmVudCB3aGVuIGluIFByZXZpZXcgbW9kZS4gUXVpdGUgb2Z0ZW4geW91IHdpbGwgbmVlZCB0byBhZGQgeW91ciBvd24gY29kZSBjaHVuay4NCg0KRXhlY3V0ZSBhbGwgY29kZSBjaHVua3MgKGFscmVhZHkgaW5jbHVkZWQgYW5kIG93biBhZGRlZCksIHByZXZpZXcsIGNoZWNrIGludGVncml0eSwgYW5kIHN1Ym1pdCBmaW5hbCB3b3JrICgkaHRtbCQgZmlsZSkgaW4gU2FrYWkuDQoNCi0tLS0tLS0tLS0tLS0tDQoNCiMjIyBUYXNrIDE6IFNlbnNpdGl2aXR5IEFuYWx5c2lzDQoNClNlbnNpdGl2aXR5IGFuYWx5c2lzIGlzIHRoZSBzdHVkeSBvZiBob3cgdGhlIHVuY2VydGFpbnR5IGluIHRoZSBvdXRwdXQgb2YgYSBtYXRoZW1hdGljYWwgbW9kZWwgb3Igc3lzdGVtIChudW1lcmljYWwgb3Igb3RoZXJ3aXNlKSBjYW4gYmUgYXBwb3J0aW9uZWQgdG8gZGlmZmVyZW50IHNvdXJjZXMgb2YgdW5jZXJ0YWludHkgaW4gaXRzIGlucHV0cy4gV2Ugd2lsbCB1c2UgdGhlIGBscFNvbHZlQVBJYCBSLXBhY2thZ2UgYXMgd2UgZGlkIGluIHRoZSBwcmV2aW91cyBsYWIuIA0KDQpJbiBvcmRlciB0byBjb25kdWN0IGEgc2Vuc2l0aXZpdHkgYW5hbHlzaXMsIHdlIHdpbGwgbmVlZCB0byBkb3dubG9hZCBhZ2FpbiB0aGUgYGxwU29sdmVBUElgIHBhY2thZ2UgdW5sZXNzIHlvdSBoYXZlIGl0IGFscmVhZHkgaW5zdGFsbGVkIGluIHlvdXIgUiBlbnZpcm9ubWVudA0KDQpgYGB7cn0NCiMgUmVxdWlyZSB3aWxsIGxvYWQgdGhlIHBhY2thZ2Ugb25seSBpZiBub3QgaW5zdGFsbGVkIA0KIyBEZXBlbmRlbmNpZXMgPSBUUlVFIG1ha2VzIHN1cmUgdGhhdCBkZXBlbmRlbmNpZXMgYXJlIGluc3RhbGwNCmlmKCFyZXF1aXJlKCJscFNvbHZlQVBJIixxdWlldGx5ID0gVFJVRSkpDQogIGluc3RhbGwucGFja2FnZXMoImxwU29sdmVBUEkiLGRlcGVuZGVuY2llcyA9IFRSVUUsIHJlcG9zID0gImh0dHBzOi8vY2xvdWQuci1wcm9qZWN0Lm9yZyIpDQpgYGANCg0KV2Ugd2lsbCByZXZpc2l0IGFuZCBzb2x2ZSBhZ2FpbiB0aGUgbWFya2V0aW5nIGNhc2UgZGlzY3Vzc2VkIGluIGNsYXNzIChhbHNvIHBhcnQgb2YgcHJldmlvdXMgbGFiKS4gDQpgYGB7cn0NCiMgV2Ugc3RhcnQgd2l0aCBgMGAgY29uc3RyYWludCBhbmQgYDJgIGRlY2lzaW9uIHZhcmlhYmxlcy4gVGhlIG9iamVjdCBuYW1lIGBscG1hcmtgIGlzIGRpc2NyZXRpb25hcnkuDQpscG1hcmsgPSBtYWtlLmxwKDAsIDIpDQoNCiMgRGVmaW5lIHR5cGUgb2Ygb3B0aW1pemF0aW9uIGFzIG1heGltdW0gYW5kIGR1bXAgdGhlIHNjcmVlbiBvdXRwdXQgaW50byBhIGBkdW1teWAgdmFyaWFibGUNCmR1bW15ID0gbHAuY29udHJvbChscG1hcmssIHNlbnNlPSJtYXgiKSANCiMgU2V0IHRoZSBvYmplY3RpdmUgZnVuY3Rpb24gY29lZmZpY2llbnRzIA0Kc2V0Lm9iamZuKGxwbWFyaywgYygyNzUuNjkxLCA0OC4zNDEpKQ0KYGBgDQoNCkFkZCBhbGwgY29uc3RyYWludHMgdG8gdGhlIG1vZGVsLg0KDQpgYGB7cn0NCmFkZC5jb25zdHJhaW50KGxwbWFyaywgYygxLCAxKSwgIjw9IiwgMzUwMDAwKQ0KYWRkLmNvbnN0cmFpbnQobHBtYXJrLCBjKDEsIDApLCAiPj0iLCAxNTAwMCkNCmFkZC5jb25zdHJhaW50KGxwbWFyaywgYygwLCAxKSwgIj49IiwgNzUwMDApDQphZGQuY29uc3RyYWludChscG1hcmssIGMoMiwgLTEpLCAiPSIsIDApDQphZGQuY29uc3RyYWludChscG1hcmssIGMoMSwgMCksICI+PSIsIDApDQphZGQuY29uc3RyYWludChscG1hcmssIGMoMCwgMSksICI+PSIsIDApDQpgYGANCg0KTm93LCB2aWV3IHRoZSBwcm9ibGVtIHNldHRpbmcgaW4gdGFidWxhci9tYXRyaXggZm9ybS4gVGhpcyBpcyBhIGdvb2QgY2hlY2twb2ludCB0byBjb25maXJtIHRoYXQgb3VyIGNvbnRyYWludHMgaGF2ZSBiZWVuIHByb3Blcmx5IHNldC4NCg0KYGBge3J9DQpscG1hcmsNCiMgc29sdmUNCnNvbHZlKGxwbWFyaykgDQpgYGANCg0KTmV4dCB3ZSBnZXQgdGhlIG9wdGltdW0gcmVzdWx0cy4NCmBgYHtyfQ0KIyBkaXNwbGF5IHRoZSBvYmplY3RpdmUgZnVuY3Rpb24gb3B0aW11bSB2YWx1ZQ0KZ2V0Lm9iamVjdGl2ZShscG1hcmspDQoNCiMgZGlzcGxheSB0aGUgZGVjaXNpb24gdmFyaWFibGVzIG9wdGltdW0gdmFsdWVzDQpnZXQudmFyaWFibGVzKGxwbWFyaykNCmBgYA0KDQpGb3Igc2Vuc2l0aXZpdHkgd2Ugd2lsbCBpbnRyb2R1Y2UgdGhlIGNvZGUgY29tbWFuZCB0byBvYnRhaW4gdGhlIHNlbnNpdGl2aXRpZXMgZHVlIHRvIGNoYW5nZXMgaW4gcmVzb3VyY2VzIGFzIGV4cHJlc3NlZCBpbiB0aGUgcmlnaHQgaGFuZCBzaWRlIChyaHMpIGNvbnN0cmFpbnRzLiANCg0KYGBge3J9DQojIGRpc3BsYXkgc2Vuc2l0aXZpdHkgdG8gcmhzIGNvbnN0cmFpbnRzLiANCiMgVGhlcmUgd2lsbCBiZSBhIHRvdGFsIG9mIG0rbiB2YWx1ZXMgd2hlcmUgbSBpcyB0aGUgbnVtYmVyIG9mIGNvbnRyYWludHMgYW5kIG4gaXMgdGhlIG51bWJlciBvZiBkZWNpc2lvbiB2YXJpYWJsZXMNCmdldC5zZW5zaXRpdml0eS5yaHMobHBtYXJrKSANCmBgYA0KDQpGb3IgdGhpcyBleGVyY2lzZSB3ZSBhcmUgb25seSBpbnRlcmVzdGVkIGluIHRoZSBmaXJzdCBzaXggdmFsdWVzIChjb3JyZXNwb25kaW5nIHRvIHRoZSBzaXggY29uc3RyYWludHMpIG9mIHRoZSBvdXRwdXQgbGFiZWxlZCBgZHVhbHNgLiANCg0KPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+DQojIyMjIyAxQSkgIElkZW50aWZ5IGFuZCBleHBsYWluIHdoYXQgdGhlIGJpbmRpbmcvbm9uLWJpbmRpbmcgY29uc3RyYWludHMsIHRoZSBzdXJwbHVzL3NsYWNrLCBhbmQgdGhlIG1hcmdpbmFsIHZhbHVlcyBhcmUgYW5kIHdoYXQgdGhleSByZXByZXNlbnQgaW4gdGhlIGNvbnRleHQgb2Ygb3VyIG1hcmtldGluZyB1c2UgY2FzZSAoNHB0cykNCjwvc3Bhbj4NCkJpbmRpbmcgdmFsdWVzIGhhdmUgbm9uemVybyBtYXJnaW5hbCB2YWx1ZXMuIEluIHRoaXMgY2FzZSwgaXQgaXMgdGhlIGZpcnN0IGFuZCBmb3J0aCBjb250cmFpbnRzLiAobWF4IGJ1ZGdldCBvZiAzNTAsMDAwIFt4MSt4Mjw9MzUwMDAwXSBhbmQgdHYgYWRzIG11c3QgYmUgMnggbW9yZSB0aGFuIHJhZGlvIGFkcyBbMngxLXgxPTBdKQ0KVGhlIG1hcmdpbmFsIHZhbHVlIGZvciB0aGUgZmlyc3QgY29uc3RyYWludCBtZWFucyB0aGF0IGZvciBlYWNoICQxIGluY3JlYXNlIGluIHRoZSBvdmVyYWxsIGJ1ZGdldCAoMzUwLDAwMCB0byAzNTAsMDAxKSBzYWxlcyB3aWxsIGluY3JlYXNlIGJ5IDEyNC4xMiBkb2xsYXJzDQpUaGUgbWFyZ2luYWwgdmFsdWUgZm9yIHRoZSBmb3J0aCBjb25zdHJhaW50IGlzIHRoYXQgZm9yIGVhY2ggZG9sbGFyIGluY3JlYXNlIGluIHRoZSBsaW1pdC9jb250cmFpbnQsIHRoZSBzYWxlcyB3aWxsIGluY3JlYXNlIGJ5IDc1Ljc4IGRvbGxhcnMuDQpUaGUgbWFyZ2luYWwgdmFsdWUgZm9yIHRoZSBzZWNvbmQsIHRoaXJkLCBmaWZ0aCBhbmQgc2l4dGggY29uc3RyYWludCBtZWFucyB0aGF0IGZvciBldmVyeSAkMSBpbmNyZWFzZSBpbiB0aGVpciBsaW1pdCAoZXg6IHNlY29uZCBjb25zdHJhaW50IGdvZXMgZnJvbSAxNSwwMDAgdG8gMTUsMDAxLCBldGMuKSwgc2FsZXMgd2lsbCBpbmNyZWFzZSBieSB6ZXJvIGRvbGxhcnMuDQpUaGUgc3VycGx1cyBvZiB0aGUgZmlyc3QgY29uc3RyYWludCBpcyB6ZXJvLiBUaGlzIG1lYW5zIHRoYXQgdGhlIG91dGNvbWUgd2FzIGVxdWFsIHRvIHRoZSBsaW1pdC4gKDExNiw2NjYuNysyMjMsMzMzMy4zID0zNTAsMDAwIDM1MCwwMDAtMzUwLDAwMD0wKQ0KVGhlIHN1cnBsdXMgb2YgdGhlIHNlY29uZCBjb25zdHJhaW50IGlzIDEwMSw2NjYuNy4gVGhpcyBtZWFucyB0aGUgb3V0Y29tZSB3YXMgb3ZlciB0aGUgbWluaW11biBieSAxMDEsNjY2LjcNCigxMTYsNjY2LjctMTUsMDAwPTEwMSw2NjYuNykNClRoZSBTdXJwbHVzIG9mIHRoZSB0aGlyZCBjb25zdHJhaW50IGlzIDIzMywzMzMuMy4gVGhpcyBtZWFucyB0aGUgb3V0Y29tZSB3YXMgb3ZlciB0aGUgbWluaW11bSBieSAyMzMsMzMzLjMNCigyMzMsMzMzLjMtNzUsMDAwPTE1OCwzMzMuMykNClRoZSBzdXJwbHVzIG9mIHRoZSBmb3J0aCBjb25zdHJhaW50IGlzIHplcm8uIFRoaXMgbWVhbnMgdGhhdCB0aGUgb3V0Y29tZSB3YXMgZXF1YWwgdG8gdGhlIGxpbWl0Lg0KKDIoMTE2LDY2Ni43KS0xKDIzMywzMzMuMyk9MCkNClRoZSBzdXJwbHVzIG9mIHRoZSBmaWZ0aCBjb25zdHJhaW50IGlzIDExNiw2NjYuNy4gVGhpcyBtZWFucyB0aGUgb3V0Y29tZSB3YXMgb3ZlciB0aGUgbWluaW15bSBieSAxMTYsNjY2LjcNCigxMTYsNjY2LjctMD0xMTYsNjY2LjcpDQpUaGUgc3VycGx1cyBvZiB0aGUgc2l4dGggY29uc3RyYWludCBpcyAyMzMsMzMzLjMuIFRoaXMgbWVhbnMgdGhlIG91dGNvbWUgd2FzIG92ZXIgdGhlIG1pbmltdW0gYnkgMjMzLDMzMy4zDQooMjMzLDMzMy4zLTA9MjMzLDMzMy4zKQ0KVGhlIG5vbiBiaW5kaW5nIGNvbnRyYWludHMgYXJlIHRoZSBzZWNvbmQsIHRoaXJkLCBmaWZ0aCwgYW5kIHNpeHRoIGNvbnN0cmFpbnRzLiAoeDE+PTE1MDAwLCB4Mj0+NzUwMDAsIHgxPj0wLCBhbmQgeDI+PTApDQoNCg0KVG8gYWNxdWlyZSBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIHRoZSBzZW5zaXRpdml0eSByZXN1bHRzLCBhbmQgdG8gY29uZmlybSBpbnRlZ3JpdHkgb2YgdGhlIGNhbGN1bGF0aW9ucywgaW5kZXBlbmRlbnQgdGVzdHMgY2FuIGJlIGNvbmR1Y3RlZC4gIFRvIGRlbW9uc3RyYXRlLCB3ZSB3aWxsIHJlcGVhdCB0aGUgbGluZWFyIHByb2dyYW1taW5nIChMUCkgb3B0aW1pemF0aW9uIHByb2JsZW0gYnkgc2xpZ2h0bHkgdHdlYWtpbmcgb25lIGJpbmRpbmcgY29uc3RyYWludCBhbmQgdmVyaWZ5aW5nIHRoZSBpbXBhY3QuDQoNCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPg0KIyMjIyMgMUIpICBEZWZpbmUgYSBuZXcgbW9kZWwgb2JqZWN0IGBscG1hcmsxYCBhbmQgYWRkIHRoZSBjb25zdHJhaW50cyBleGFjdGx5IGFzIGVudGVyZWQgYXQgYmVnaW5uaW5nIG9mIHRoaXMgdGFzay4gQWxsIGJlaW5nIGVxdWFsLCBjaGFuZ2UgdGhlIGJ1ZGdldCBjb25zdHJhaW50IGJ5IGEgbWFyZ2luYWwgJDEgdmFsdWUgYW5kIHNvbHZlIHRoZSBMUCBwcm9ibGVtLiAgTm90ZSB0aGUgbmV3IG9wdGltdW0gdmFsdWUgZm9yIHNhbGVzLiBDYWxjdWxhdGUgdGhlIGRpZmZlcmVudGlhbCBjaGFuZ2UgaW4gb3B0aW11bSBzYWxlcyBmcm9tIHRoZSBlYXJsaWVyIGNvbXB1dGVkIG9wdGltdW0gc2FsZXMsICBhbmQgY29tcGFyZSB5b3VyIGNhbGN1bGF0aW9uIHRvIHRoZSB2YWx1ZSBvYnRhaW5lZCBmcm9tIHRoZSBwcmlvciBzZW5zaXRpdml0eSBjYWxjdWxhdGlvbiAoNHB0cykNCjwvc3Bhbj4NCg0KYGBge3J9DQojIERlZmluZSBhIG5ldyBtb2RlbCBvYmplY3QgY2FsbGVkIGxwbWFyazENCmxwbWFyazEgPSBtYWtlLmxwKDAsIDIpDQpkdW1teSA9IGxwLmNvbnRyb2wobHBtYXJrMSwgc2Vuc2U9Im1heCIpIA0KIyBTZXQgdGhlIG9iamVjdGl2ZSBmdW5jdGlvbiBjb2VmZmljaWVudHMgDQpzZXQub2JqZm4obHBtYXJrMSwgYygyNzUuNjkxLCA0OC4zNDEpKQ0KIyBSZXBlYXQgcmVzdCBvZiBjb21tYW5kcyB3aXRoIHRoZSBvbmUgY29uc3RyYWludCBjaGFuZ2UgZm9yIGJ1ZGdldC4gU29sdmUgYW5kIGRpc3BsYXkgdGhlIG9iamVjdGl2ZSBmdW5jdGlvbiBvcHRpbXVtIHZhbHVlDQoNCmBgYA0KYGBge3J9DQphZGQuY29uc3RyYWludChscG1hcmsxLCBjKDEsIDEpLCAiPD0iLCAzNTAwMDEpDQphZGQuY29uc3RyYWludChscG1hcmsxLCBjKDEsIDApLCAiPj0iLCAxNTAwMCkNCmFkZC5jb25zdHJhaW50KGxwbWFyazEsIGMoMCwgMSksICI+PSIsIDc1MDAwKQ0KYWRkLmNvbnN0cmFpbnQobHBtYXJrMSwgYygyLCAtMSksICI9IiwgMCkNCmFkZC5jb25zdHJhaW50KGxwbWFyazEsIGMoMSwgMCksICI+PSIsIDApDQphZGQuY29uc3RyYWludChscG1hcmsxLCBjKDAsIDEpLCAiPj0iLCAwKQ0KYGBgDQpgYGB7cn0NCmxwbWFyazENCnNvbHZlKGxwbWFyazEpIA0KZ2V0Lm9iamVjdGl2ZShscG1hcmsxKQ0KZ2V0LnZhcmlhYmxlcyhscG1hcmsxKQ0KYGBgDQpUaGlzIGRhdGEgKGxwbWFyazEpIHNob3dzIHNhbGVzIGlzIDQzLDQ0Myw2NDEgY29tcGFyZWQgdG8gNDM0NDM1MTcgc2FsZXMgZnJvbSBscG1hcmsuIFRoaXMgZGlmZmVyZW5jZSBpcyBhICQxMjQgZGlmZmVyZW5jZS4gVGhpcyBudW1iZXIgbWF0Y2hlcyB0aGUgbWFyZ2luYWwgdmFsdWUgY2FsY3VsYXRlZCBpbiB0aGUgcHJldmlvdXMgcGFyay4gVGhpcyBtZWFucyBmb3IgdGhlIGRvbGxhciBpbmNyZWFzZSBpbiBidWRnZXQsIHNhbGVzIGluY3JlYXNlZCBieSAxMjQgZG9sbGFycywgd2hpY2ggaXQgZGlkLg0KPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+DQoNCiMjIyMjIDFDKSAgRm9sbG93aW5nIHRoZSBsb2dpYyBvZiBjYWxjdWxhdGlvbnMgaW4gMUIpIGFuZCB3aXRob3V0IHJ1bm5pbmcgYW5vdGhlciBjb2RlLCBleHBsYWluIHRoZSBzdGVwcyB0byB2YWxpZGF0ZSB0aGUgaW50ZWdyaXR5IG9mIHRoZSBvdGhlciByZW1haW5pbmcgbWFyZ2luYWwgdmFsdWUgaWRlbnRpZmllZCBpbiAxQSkuIFVzZSBhIGRpZmZlcmVudCBsaW5lIHRvIGV4cGxhaW4gZWFjaCBzdGVwICg0cHRzKQ0KWW91IGNvdWxkIHVzZSBhbm90aGVyIGxwbWFyayB0byBkbyB0aGF0Lg0KWW91IHdvdWxkIGRlZmluZSBhbm90aGVyIGxwbWFyaywgY2FsbGVkIGxwbWFyazIgYW5kIG1ha2UgaXQgYW5hbHplIHR3byB2YXJpYWJsZXMuDQpZb3Ugd291bGQgc2V0IHRoZSBvYmplY3RpdmUgdG8gbWF4aW1pemUgc2FsZXMgYW5kIHVzZSB0aGUgZnVuY3Rpb24gY29lZmZpY2llbnRzIHRvIGhhdmUgeDE9Mjc1LjY5MSBhbmQgeDI9NDguMzQxLg0KVGhlbiB5b3Ugd291bGQgc2V0IHRoZSBjb250cmFpbnRzLiBZb3Ugd291bGQgdXNlIHRoZSBzYW1lIG9uZXMgYXMgbHBtYXJrLCBidXQgdGhlIGZvcnRoIGNvbnN0cmFpbnQgd291bGQgYmUgMngxLTF4MT0xLCBpbnN0ZWFkIG9mICAyeDEtMXgxPTAuDQpUaGVuIHlvdSB3b3VsZCBzb2x2ZSwgZ2V0IHRoZSBvYmplY3RpdmUsIGFuZCBnZXQgdGhlIHZhcmlhYmxlcy4NClRoZW4geW91IGNvdWxkIHNlZSB0aGUgbmV3IG1heGltaXplZCBzYWxlcy4gDQpZb3Ugd291bGQgdXNlIHRoaXMgdG8gZmluZCB0aGUgZGlmZmVyZW5jZSBmcm9tIGxtcGFyayBzYWxlcyBhbmQgbHBtYXJrMiBzYWxlcy5UaGlzIGRpZmZlcmVuY2Ugc2hvdWxkIGVxdWFsICQ3NSwgdGhlIHNhbWUgYXMgdGhlIG1hcmdpbmFsIHZhbHVlLg0KPC9zcGFuPg0KDQotLS0tLS0tLS0tDQoNCiMjIyBUYXNrIDI6IFJhbmRvbSBTYW1wbGluZyAmIE1vbnRlIENhcmxvIFNpbXVsYXRpb24NCg0KTW9udGUgQ2FybG8gU2ltdWxhdGlvbnMgdXRpbGl6ZSByZXBlYXRlZCByYW5kb20gc2FtcGxpbmcgZnJvbSBhIGdpdmVuIHVuaXZlcnNlIG9yIHBvcHVsYXRpb24gZGlzdHJpYnV0aW9uIHRvIGRlcml2ZSBjZXJ0YWluIHJlc3VsdHMuIFRoaXMgdHlwZSBvZiBzaW11bGF0aW9uIGlzIGtub3duIGFzIGEgcHJvYmFiaWxpc3RpYyBzaW11bGF0aW9uLCBhcyBvcHBvc2VkIHRvIGEgZGV0ZXJtaW5pc3RpYyBzaW11bGF0aW9uLg0KDQpBbiBleGFtcGxlIG9mIGEgTW9udGUgQ2FybG8gc2ltdWxhdGlvbiBpcyB0aGUgb25lIGFwcGxpZWQgdG8gYXBwcm94aW1hdGUgdGhlIHZhbHVlIG9mIGBwaWAuIFRoZSBzaW11bGF0aW9uIGlzIGJhc2VkIG9uIGdlbmVyYXRpbmcgcmFuZG9tIHBvaW50cyB3aXRoaW4gYSB1bml0IHNxdWFyZSBhbmQgc2VlIGhvdyBtYW55IHBvaW50cyBmYWxsIHdpdGhpbiB0aGUgY2lyY2xlIGVuY2xvc2VkIGJ5IHRoZSB1bml0IHNxdWFyZSAobWFya2VkIGluIHJlZCkuIFRoZSB2YWx1ZSBvZiBgcGlgIGlzIGVzdGltYXRlZCBieSB0aGUgbnVtYmVyIG9mIHBvaW50cyBpbnNpZGUgdGhlIGNpcmNsZSBvdmVyIHRoZSB0b3RhbCBudW1iZXIgb2YgcG9pbnRzIGdlbmVyYXRlZCBpbnNpZGUgdGhlIHNxdWFyZS4gIFRoZSBoaWdoZXIgdGhlIG51bWJlciBvZiBzYW1wbGVkIHBvaW50cyB0aGUgY2xvc2VyIHRoZSByZXN1bHQgaXMgdG8gdGhlIGFjdHVhbCByZXN1bHQuICBBZnRlciBzZWxlY3RpbmcgMzAsMDAwIHJhbmRvbSBwb2ludHMsIHRoZSBlc3RpbWF0ZSBmb3IgYHBpYCBpcyBtdWNoIGNsb3NlciB0byB0aGUgYWN0dWFsIHZhbHVlIHdpdGhpbiB0aGUgZm91ciBkZWNpbWFsIHBvaW50cyBvZiBwcmVjaXNpb24uIFRoZSBpbnRlcmVzdGVkIGFuZCBjdXJpb3VzIHJlYWRlciBpcyBlbmNvdXJhZ2VkIHRvIGV4cGxvcmUgdGhlIG1hdGhlbWF0aWNhbCBmb3VuZGF0aW9uIGJlaGluZCB0aGUgbG9naWMuDQoNCiFbXShtb250ZWNhcmxvLmdpZikNCg0KDQpGb3IgdGhpcyB0YXNrIHdlIHdpbGwgYmUgcnVubmluZyBhIE1vbnRlIENhcmxvIHNpbXVsYXRpb24gdG8gY2FsY3VsYXRlIHRoZSBwcm9iYWJpbGl0eSB0aGF0IHRoZSBkYWlseSByZXR1cm4gZnJvbSBTJlAgd2lsbCBiZSA+IDUlLiANCldlIHdpbGwgYXNzdW1lIHRoYXQgdGhlIGhpc3RvcmljYWwgUyZQIGRhaWx5IHJldHVybiBmb2xsb3dzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoIGFuIGF2ZXJhZ2UgZGFpbHkgcmV0dXJuIG9mIDAuMDMgKCUpIGFuZCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAwLjk3ICglKS4gQ29uc2lkZXIgdGhpcyBhcyBvdXIgcG9wdWxhdGlvbi4NCg0KVG8gYmVnaW4gd2Ugd2lsbCBnZW5lcmF0ZSAxMDAgcmFuZG9tIHNhbXBsZXMgZnJvbSB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gRm9yIHRoZSBnZW5lcmF0ZWQgc2FtcGxlcyB3ZSB3aWxsIGNhbGN1bGF0ZSB0aGUgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uLCBhbmQgcHJvYmFiaWxpdHkgb2Ygb2NjdXJyZW5jZSB3aGVyZSB0aGUgc2ltdWxhdGlvbiByZXN1bHQgaXMgZ3JlYXRlciB0aGFuIDUlLiANCg0KVG8gZ2VuZXJhdGUgcmFuZG9tIHNhbXBsZXMgZnJvbSBhIG5vcm1hbCBkaXN0cmlidXRpb24gd2Ugd2lsbCB1c2UgdGhlIGBybm9ybSgpYCBmdW5jdGlvbiBpbiBSLiBJbiB0aGUgZXhhbXBsZSBiZWxvdyB3ZSBzZXQgdGhlIG51bWJlciBvZiBydW5zIChvciBzYW1wbGVzKSB0byAxMDAuDQoNCmBgYHtyfQ0KIyBudW1iZXIgb2Ygc2ltdWxhdGlvbnMvc2FtcGxlcw0KcnVucyA9IDEwMA0KIyByYW5kb20gbnVtYmVyIGdlbmVyYXRvciBwZXIgZGVmaW5lZCBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggZ2l2ZW4gbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uDQpzaW1zID0gIHJub3JtKHJ1bnMsbWVhbj0wLjAzLHNkPTAuOTcpDQpgYGANCg0KYGBge3J9DQojIE1lYW4gY2FsY3VsYXRlZCBmcm9tIHRoZSByYW5kb20gZGlzdHJpYnV0aW9uIG9mIHNhbXBsZXMNCmF2ZXJhZ2UgPSBtZWFuKHNpbXMpDQphdmVyYWdlDQpgYGANCg0KYGBge3J9DQojIFNURCBjYWxjdWxhdGVkIGZyb20gdGhlIHJhbmRvbSBkaXN0cmlidXRpb24gb2Ygc2FtcGxlcw0Kc3RkID0gc2Qoc2ltcykgDQpzdGQNCmBgYA0KDQpgYGB7cn0NCiMgcHJvYmFiaWxpdHkgb2Ygb2NjdXJyZW5jZSBvbiBhbnkgZ2l2ZW4gZGF5IGJhc2VkIG9uIHNhbXBsZXMgd2lsbCBiZSBlcXVhbCB0byBjb3VudCAob3Igc3VtKSB3aGVyZSBzYW1wbGUgcmVzdWx0IGlzIGdyZWF0ZXIgdGhhbiA1JSBkaXZpZGVkIGJ5IHRvdGFsIG51bWJlciBvZiBzYW1wbGVzLiANCnByb2IgPSBzdW0oc2ltcyA+PTAuMDUpL3J1bnMNCnByb2INCmBgYA0KDQo8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4NCiMjIyMjIDJBKSAgUmVwZWF0IHRoZSBhYm92ZSBjYWxjdWxhdGlvbnMgZm9yIHRoZSB0d28gY2FzZXMgd2hlcmUgdGhlIG51bWJlciBvZiBzaW11bGF0aW9ucy9zYW1wbGVzIGlzIGVxdWFsIHRvIDEwMDAgYW5kIDEwMDAwLiAgRm9yIGVhY2ggY2FzZSByZWNvcmQgdGhlIG1lYW4sIHN0YW5kYXJkIGRldmlhdGlvbiwgYW5kIHByb2JhYmlsaXR5ICg0cHRzKQ0KPC9zcGFuPg0KDQpgYGBge3J9DQojIFJlcGVhdCBjYWxjdWxhdGlvbnMgaGVyZQ0KIyBzaW11bGF0aW9ucy9zYW1wbGUNCnJ1bnMgPSAxMDAwDQojIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yIHBlciBkZWZpbmVkIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBnaXZlbiBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24NCnNpbXMgPSAgcm5vcm0ocnVucyxtZWFuPTAuMDMsc2Q9MC45NykNCiMjTWVhbiBjYWxjdWxhdGVkIGZyb20gdGhlIHJhbmRvbSBkaXN0cmlidXRpb24gb2Ygc2FtcGxlcw0KYXZlcmFnZSA9IG1lYW4oc2ltcykNCmF2ZXJhZ2UNCiMgU1REIGNhbGN1bGF0ZWQgZnJvbSB0aGUgcmFuZG9tIGRpc3RyaWJ1dGlvbiBvZiBzYW1wbGVzDQpzdGQgPSBzZChzaW1zKSANCnN0ZA0KcHJvYiA9IHN1bShzaW1zID49MC4wNSkvcnVucw0KcHJvYnByb2IgPSBzdW0oc2ltcyA+PTAuMDUpL3J1bnMNCnByb2INCmBgYA0KYGBge3J9DQojIFJlcGVhdCBjYWxjdWxhdGlvbnMgaGVyZQ0KIyBzaW11bGF0aW9ucy9zYW1wbGUNCnJ1bnMgPSAxMDAwMA0KIyByYW5kb20gbnVtYmVyIGdlbmVyYXRvciBwZXIgZGVmaW5lZCBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggZ2l2ZW4gbWVhbiBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uDQpzaW1zID0gIHJub3JtKHJ1bnMsbWVhbj0wLjAzLHNkPTAuOTcpDQojI01lYW4gY2FsY3VsYXRlZCBmcm9tIHRoZSByYW5kb20gZGlzdHJpYnV0aW9uIG9mIHNhbXBsZXMNCmF2ZXJhZ2UgPSBtZWFuKHNpbXMpDQphdmVyYWdlDQojIFNURCBjYWxjdWxhdGVkIGZyb20gdGhlIHJhbmRvbSBkaXN0cmlidXRpb24gb2Ygc2FtcGxlcw0Kc3RkID0gc2Qoc2ltcykgDQpzdGQNCnByb2IgPSBzdW0oc2ltcyA+PTAuMDUpL3J1bnMNCnByb2Jwcm9iID0gc3VtKHNpbXMgPj0wLjA1KS9ydW5zDQpwcm9iDQpgYGANCg0KPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+DQojIyMjIyAyQikgIExpc3QgaW4gc2VwZXJhdGUgbGluZXMgdGhlIHZhbHVlcyBmb3IgbWVhbiwgc3RhbmRhcmQgZGV2aWF0aW9uLCBhbmQgcHJvYmFiaWxpdHkgZm9yIGFsbCB0aHJlZSBjYXNlczogMTAwLCAxMDAwLCBhbmQgMTAwMDAgc2ltdWxhdGlvbnMuIERlc2NyaWJlIGhvdyB0aGUgdmFsdWVzIGNoYW5nZS9iZWhhdmUgYXMgdGhlIG51bWJlciBvZiBzaW11bGF0aW9ucyBpcyBpbmNyZWFzZWQuIFdoYXQgaXMgeW91ciBiZXN0IGJldCBvbiB0aGUgcHJvYmFiaWxpdHkgb2Ygb2NjdXJyZW5jZSBncmVhdGVyIHRoYW4gNSUgYW5kIHdoeT8gSG93IGlzIHRoaXMgYmVoYXZpb3Igc2ltaWxhciB0byB0aGUgdXNlIGNhc2UgZGVtb25zdHJhdGlvbiB0byBjYWxjdWxhdGUgYHBpYD8gICg0cHRzKSANCjwvc3Bhbj4NCjEwMCBydW5zOg0KbWVhbjogLTAuMDQ3MzI1NzUNCnN0YW5kYXJkIGRldmlhdGlvbjogMC45ODAyNDkyDQpwcm9iYWJpbGl0eTogMC40NzQNCg0KMTAwMCBydW5zOg0KbWVhbjowLjAzMTM0ODI0DQpzdGFuZGFyZCBkZXZpYXRpb246IDAuOTczMzgxOQ0KcHJvYmFiaWxpdHk6MC40ODMNCg0KMTAwMDAgcnVuczoNCm1lYW46MC4wMjM3MDE2Ng0Kc3RhbmRhcmQgZGV2aWF0aW9uOjAuOTY3NjkzNQ0KcHJvYmFiaWxpdHk6MC40ODUyDQoNCkFzIHRoZSBudW1iZXIgb2YgcnVucyBpbmNyZWFzZWQsIHRoZSBwcm9iYWJpbGl0eSBnb3QgYmlnZ2VyLCBidXQgdGhlIGluY3JlYXNlIGluIHByb2JhYmlsaXR5IHdhcyBub3QgYXMgZ3JlYXQgZnJvbSAxMDAwIHRvIDEwMDAwIHJ1bnMgY29tcGFyZWQgdG8gdGhlIDEwMCB0byAxMDAwIHJ1biBjaGFuZ2UuIFRoZSBzdGFuZGFyZCBkZXZpYXRpb24gZGVjcmVhc2VkIGFzIHRoZSBydW4gY291bnQgZ290IGxhcmdlci4gVGhlIHNhbWUgY2FzZSB3YXMgdHJ1ZSBoZXJlLCBhcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGNoYW5nZWQgZnJvbSAxMDAwIHRvIDEwMDAwIHJ1bnMsIHRoZSBjaGFuZ2Ugd2FzIG5vdCBhcyBsYXJnZSBhcyB0aGUgY2hhbmdlIGZyb20gMTAwIHRvIDEwMDAgcnVucy4gVGhpcyBpcyBzaW1pbGFyIHRvIGEgZ3JhcGggY29udmVyZ2luZyB0byBhIGxpbmUuIEFzIHRoZSB4IHZhbHVlLCBvciAjIG9mIHJ1bnMgaW5jcmVhc2VzLCBpdCB3aWxsIGdldCBjbG9zZXIgYW5kIGNsb3NlciB0byB0aGUgdHJ1ZSB2YWx1ZS4gSSB0aGluayB0aGUgMTAsMDAwIHJ1biBzaW11bGF0aW9uIHdvdWxkIGJlIGNsb3NlciB0byB0aGUgYWN0dWFsIHRydWUgdmFsdWUuIFRoZSBsYXJnZXIgdGhlIHNhbXBsZS9udW1iZXIgb2YgcnVucywgdGhlIGxlc3MgaW1wYWN0IGFuIG91dGxpZXIgd291bGQgaGF2ZSBvbiB0aGUgZGF0YS4gSnVzdCBsaWtlIGluIHN0YXRpc3RpY3MsIHRoZSBsYXJnZXIgc2FtcGxlIGdpdmVzIGJldHRlciBkYXRhLCBpbiBhY2N1cmFjeSBhbmQgcmVwcmVzZW50YXRpb24uDQpKdXN0IGxpa2UgcGksIGFmdGVyIHNlbGVjdGluZyBtb3JlIHJhbmRvbSBwb2ludHMsIChwaSB3YXMgMzAsMDAwIGJ1dCBoZXJlIGl0J3MgMTAsMDAwKSB0aGUgZXN0aW1hdGUgd2lsbCBnZXQgY2xvc2VyIHRvIHRoZSBhY3R1YWwgdmFsdWUuIA0KDQoNCg0K