Notebook Instructions
About
In this lab, we will focus on linear and non-linear programming.
Linear programming, as discussed in the previous lab, works with simple and multiple linear regression techniques; sometimes the variables have completely direct or completely non-direct relationships and these techniques can model them.
Sometimes, however, the variables do not predict each other in a linear way. For example, looking at the stock market vs. time, we know that generally the market was booming before the crash, then the market crashed and the great depression hit, and slowly the market started to rise again.
This pattern is not linear, and in fact a non-linear programming technique can be used to model it and predict the value of the market based on the year.
In this lab, we will explore topics like optimization, solve a marketing model, and perform linear and non-linear regression on the cost of servers.
Load Packages in R/RStudio
We are going to use tidyverse a collection of R packages designed for data science.
Loading required package: lpSolveAPI
there is no package called <U+393C><U+3E31>lpSolveAPI<U+393C><U+3E32>Installing package into <U+393C><U+3E31>C:/Users/fasha/OneDrive/Documents/R/win-library/3.4<U+393C><U+3E32>
(as <U+393C><U+3E31>lib<U+393C><U+3E32> is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.4/lpSolveAPI_5.5.2.0-17.zip'
Content type 'application/zip' length 1044053 bytes (1019 KB)
downloaded 1019 KB
package lpSolveAPI successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\fasha\AppData\Local\Temp\RtmpgvPb8H\downloaded_packages
Loading required package: tidyverse
[30m-- [1mAttaching packages[22m --------------------------------------- tidyverse 1.2.1 --[39m
[30m[32mv[30m [34mggplot2[30m 2.2.1 [32mv[30m [34mpurrr [30m 0.2.4
[32mv[30m [34mtibble [30m 1.4.2 [32mv[30m [34mdplyr [30m 0.7.4
[32mv[30m [34mtidyr [30m 0.8.0 [32mv[30m [34mstringr[30m 1.2.0
[32mv[30m [34mreadr [30m 1.1.1 [32mv[30m [34mforcats[30m 0.2.0[39m
[30m-- [1mConflicts[22m ------------------------------------------ tidyverse_conflicts() --
[31mx[30m [34mdplyr[30m::[32mfilter()[30m masks [34mstats[30m::filter()
[31mx[30m [34mdplyr[30m::[32mlag()[30m masks [34mstats[30m::lag()[39m
Loading required package: rvest
Loading required package: xml2
Attaching package: <U+393C><U+3E31>rvest<U+393C><U+3E32>
The following object is masked from <U+393C><U+3E31>package:purrr<U+393C><U+3E32>:
pluck
The following object is masked from <U+393C><U+3E31>package:readr<U+393C><U+3E32>:
guess_encoding
Task 1: Linear Programming - Solving Marketing Model
1A) Create the model object in R.
lprec <- make.lp(0, 2)
Set the constrains and objective function for the model.
lp.control(lprec, sense="max")
$anti.degen
[1] "fixedvars" "stalling"
$basis.crash
[1] "none"
$bb.depthlimit
[1] -50
$bb.floorfirst
[1] "automatic"
$bb.rule
[1] "pseudononint" "greedy" "dynamic" "rcostfixing"
$break.at.first
[1] FALSE
$break.at.value
[1] 1e+30
$epsilon
epsb epsd epsel epsint epsperturb epspivot
1e-10 1e-09 1e-12 1e-07 1e-05 2e-07
$improve
[1] "dualfeas" "thetagap"
$infinite
[1] 1e+30
$maxpivot
[1] 250
$mip.gap
absolute relative
1e-11 1e-11
$negrange
[1] -1e+06
$obj.in.basis
[1] TRUE
$pivoting
[1] "devex" "adaptive"
$presolve
[1] "none"
$scalelimit
[1] 5
$scaling
[1] "geometric" "equilibrate" "integers"
$sense
[1] "maximize"
$simplextype
[1] "dual" "primal"
$timeout
[1] 0
$verbose
[1] "neutral"
set.objfn(lprec, c(275.691, 48.341))
1B) Add constrains
add.constraint(lprec, c(1, 1), "<=", 350000)
add.constraint(lprec, c(1, 0), ">=", 15000)
add.constraint(lprec, c(0, 1), ">=", 75000)
add.constraint(lprec, c(2, -1), "=", 0)
1C) Solve the optimization problem
# solve
solve(lprec)
[1] 0
Display the objective function optimum value
get.objective(lprec)
[1] 43443517
Display the variables optimum values
get.variables(lprec)
[1] 116666.7 233333.3
Task 2: Regression Analysis - Linear Regression
- A linear model is of the form y = x0 + x1 + …+ x_n
2A) Read the csv file into R Studio and display the dataset.
mydata <- read.csv(file="data/ServersCost.csv")
mydata
head(mydata)
2B) Create a correlation table for your to compare the correlations between all variables. What can you tell about the correlation between the variables.
cor(mydata)
servers cost
servers 1.00000000 0.03356606
cost 0.03356606 1.00000000
The points make a U shape going from a negative slope to a positive one. The trend line shows the best fit for the data. However, this data doesn’t have a very good fit and doesn’t go through a single point.
2D) Create a linear regression model by identifying the dependent variable (y) and independent variable (x_n)
- Commands: linear_model <- lm( DEPENDENT ~ INDEPENDENT )
linear_model <- lm( cost ~ servers )
linear_model
Call:
lm(formula = cost ~ servers)
Coefficients:
(Intercept) servers
14747 48
Use the regression model to create a report. Note the R-Squared and Adjusted R-Squared values, determine if this is a good or bad fit for your data?
- Commands: summary( linear_model )
summary( linear_model )
Call:
lm(formula = cost ~ servers)
Residuals:
Min 1Q Median 3Q Max
-10646.2 -8646.2 -544.7 7066.0 12858.8
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 14747.2 4035.5 3.654 0.00181 **
servers 48.0 336.9 0.142 0.88828
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
Residual standard error: 8687 on 18 degrees of freedom
Multiple R-squared: 0.001127, Adjusted R-squared: -0.05437
F-statistic: 0.0203 on 1 and 18 DF, p-value: 0.8883
## R-squared is .001127 and the adjusted is -0.05437. This shows that this is not a very good fit for the data. It’s better the higher the number becomes and this is a low number.
Task 3: Regression Analysis - Non-linear Regression
Both the r-squared and adjusted are 1 which would lead people to believe that this is a perfect fit.
3B) Compute the predicted values based on the quadratic model.
Commands: predicted_2 <- predict( quad_model, data = mydata )
servers2 = servers^2
quad_model = lm(cost ~ servers + servers2 )
quad_model
Call:
lm(formula = cost ~ servers + servers2)
Coefficients:
(Intercept) servers servers2
35417.8 -5589.4 268.4
predicted2 = predict(quad_model,data=mydata)
predicted2
1 2 3 4 5 6 7 8
30096.790 25312.706 21065.520 17355.233 14181.844 11545.354 9445.762 7883.068
9 10 11 12 13 14 15 16
6857.273 6368.376 6416.377 7001.277 8123.076 9781.772 11977.367 14709.861
17 18 19 20
17979.252 21785.543 26128.731 31008.818
Create a plot using the quadratic model predicted values in color red. Noted the shape, looking at the plot is this a good or bad fit for your data?
Commands: qplot( x = DEPENDENT, y = INDEPENDENT/PREDICTED, colour = “red” )
qplot( x = servers, y = predicted2, colour = "red" )

The shape is a perfect U which seems to be a better fit for the data as it seems more evenly distributed.
R-squared is .932 and the adjusted is 0.9193 which is pretty close to 1 which leads us to believe that this a good fit for the data.
3D) Compute the predicted values based on the cubic model.
Commands: predicted3 <- predict( cubic_model, data = mydata )
predicted3 <- predict( cubic_model, data = mydata )
predicted3
1 2 3 4 5 6 7 8
30488.507 25457.022 21031.159 17202.831 13963.954 11306.443 9222.212 7703.177
9 10 11 12 13 14 15 16
6741.253 6328.355 6456.398 7117.297 8302.966 10005.322 12216.278 14927.751
17 18 19 20
18131.654 21819.904 25984.414 30617.101
Create a plot using the cubic model predicted values in color green. Noted the shape, looking at the plot is this a good or bad fit for your data? Is this model better than the previous?
Commands: qplot( x = DEPENDENT, y = INDEPENDENT/PREDICTED, colour = “red” )
qplot( x = servers, y = predicted3, colour = "green" )

This model seems evenly distributed which makes it look like it will be a good fit for the data.
3E) Overlay the all models on top of the data. Which model seems to fit the best in your opinion? Justify your answer.
variables: LINEAR_MODEL , PREDICTED_QUADRATIC, PREDICTED_CUBIC
# Black = Actual Data
plot(servers, cost, pch = 16)
# Blue = Linear Line based on Linear Regression Model
abline(linear_model, col = "blue", lwd = 2)
# Red = Quadratic Model based on Quadratric Regression found above
# Needed to overlay new points without the labels and annotations
par(new = TRUE, xaxt = "n", yaxt = "n", ann = FALSE)
plot(predicted2, col = "red", pch = 16)
# Green = Cubic Model based on Cubic Regression found above
# Overlay new points without the labels and annotations
par(new = TRUE, xaxt = "n", yaxt = "n", ann = FALSE)
plot(predicted3, col = "green", pch = 16)

The quadratic model looks the best because the trend line goes directly through two points where as it only goes directly through one poin for the cubic graph and none for the linear.
LS0tDQp0aXRsZTogIkJ1c2luZXNzIEFuYWx5dGljcyBMYWIgV29ya3NoZWV0IDA2Ig0KYXV0aG9yOiAiQXNobGV5IEtyZW56Ig0KZGF0ZTogIk1hcmNoIDI5LCAyMDE4Ig0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQpzdWJ0aXRsZTogQ01FIEdyb3VwIEZvdW5kYXRpb24gQnVzaW5lc3MgQW5hbHl0aWNzIExhYg0KLS0tDQoNCi0tLS0tLS0tLS0tLS0NCg0KIyMgTm90ZWJvb2sgSW5zdHJ1Y3Rpb25zDQoNCi0tLS0tLS0tLS0tLS0NCg0KIyMjIEFib3V0DQoNCiogSW4gdGhpcyBsYWIsIHdlIHdpbGwgZm9jdXMgb24gbGluZWFyIGFuZCBub24tbGluZWFyIHByb2dyYW1taW5nLiANCg0KKiBMaW5lYXIgcHJvZ3JhbW1pbmcsIGFzIGRpc2N1c3NlZCBpbiB0aGUgcHJldmlvdXMgbGFiLCB3b3JrcyB3aXRoIHNpbXBsZSBhbmQgbXVsdGlwbGUgbGluZWFyIHJlZ3Jlc3Npb24gdGVjaG5pcXVlczsgc29tZXRpbWVzIHRoZSB2YXJpYWJsZXMgaGF2ZSBjb21wbGV0ZWx5IGRpcmVjdCBvciBjb21wbGV0ZWx5IG5vbi1kaXJlY3QgcmVsYXRpb25zaGlwcyBhbmQgdGhlc2UgdGVjaG5pcXVlcyBjYW4gbW9kZWwgdGhlbS4NCg0KKiBTb21ldGltZXMsIGhvd2V2ZXIsIHRoZSB2YXJpYWJsZXMgZG8gbm90IHByZWRpY3QgZWFjaCBvdGhlciBpbiBhIGxpbmVhciB3YXkuIEZvciBleGFtcGxlLCBsb29raW5nIGF0IHRoZSBzdG9jayBtYXJrZXQgdnMuIHRpbWUsIHdlIGtub3cgdGhhdCBnZW5lcmFsbHkgdGhlIG1hcmtldCB3YXMgYm9vbWluZyBiZWZvcmUgdGhlIGNyYXNoLCB0aGVuIHRoZSBtYXJrZXQgY3Jhc2hlZCBhbmQgdGhlIGdyZWF0IGRlcHJlc3Npb24gaGl0LCBhbmQgc2xvd2x5IHRoZSBtYXJrZXQgc3RhcnRlZCB0byByaXNlIGFnYWluLiANCg0KKiBUaGlzIHBhdHRlcm4gaXMgbm90IGxpbmVhciwgYW5kIGluIGZhY3QgYSBub24tbGluZWFyIHByb2dyYW1taW5nIHRlY2huaXF1ZSBjYW4gYmUgdXNlZCB0byBtb2RlbCBpdCBhbmQgcHJlZGljdCB0aGUgdmFsdWUgb2YgdGhlIG1hcmtldCBiYXNlZCBvbiB0aGUgeWVhci4gDQoNCiogSW4gdGhpcyBsYWIsIHdlIHdpbGwgZXhwbG9yZSB0b3BpY3MgbGlrZSBvcHRpbWl6YXRpb24sIHNvbHZlIGEgbWFya2V0aW5nIG1vZGVsLCBhbmQgcGVyZm9ybSBsaW5lYXIgYW5kIG5vbi1saW5lYXIgcmVncmVzc2lvbiBvbiB0aGUgY29zdCBvZiBzZXJ2ZXJzLg0KDQoNCiMjIyBMb2FkIFBhY2thZ2VzIGluIFIvUlN0dWRpbyANCg0KV2UgYXJlIGdvaW5nIHRvIHVzZSB0aWR5dmVyc2UgYSBjb2xsZWN0aW9uIG9mIFIgcGFja2FnZXMgZGVzaWduZWQgZm9yIGRhdGEgc2NpZW5jZS4gDQoNCiogSW5mbzogaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZy8NCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCg0KIyBIZXJlIHdlIGFyZSBjaGVja2luZyBpZiB0aGUgcGFja2FnZSBpcyBpbnN0YWxsZWQNCmlmKCFyZXF1aXJlKCJscFNvbHZlQVBJIikpew0KICANCiAgIyBJZiB0aGUgcGFja2FnZSBpcyBub3QgaW4gdGhlIHN5c3RlbSB0aGVuIGl0IHdpbGwgYmUgaW5zdGFsbA0KICBpbnN0YWxsLnBhY2thZ2VzKCJscFNvbHZlQVBJIiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgDQogICMgSGVyZSB3ZSBhcmUgbG9hZGluZyB0aGUgcGFja2FnZQ0KICBsaWJyYXJ5KCJscFNvbHZlQVBJIikNCn0NCg0KYGBgDQoNCmBgYHtyLCBlY2hvID0gRkFMU0V9DQoNCiMgSGVyZSB3ZSBhcmUgY2hlY2tpbmcgaWYgdGhlIHBhY2thZ2UgaXMgaW5zdGFsbGVkDQppZighcmVxdWlyZSgidGlkeXZlcnNlIikpew0KICANCiAgIyBJZiB0aGUgcGFja2FnZSBpcyBub3QgaW4gdGhlIHN5c3RlbSB0aGVuIGl0IHdpbGwgYmUgaW5zdGFsbA0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQ0KICANCiAgIyBIZXJlIHdlIGFyZSBsb2FkaW5nIHRoZSBwYWNrYWdlDQogIGxpYnJhcnkoInRpZHl2ZXJzZSIpDQp9DQoNCiMgSGVyZSB3ZSBhcmUgY2hlY2tpbmcgaWYgdGhlIHBhY2thZ2UgaXMgaW5zdGFsbGVkDQppZighcmVxdWlyZSgicnZlc3QiKSl7DQogIA0KICAjIElmIHRoZSBwYWNrYWdlIGlzIG5vdCBpbiB0aGUgc3lzdGVtIHRoZW4gaXQgd2lsbCBiZSBpbnN0YWxsDQogIGluc3RhbGwucGFja2FnZXMoInJ2ZXN0IiwgZGVwZW5kZW5jaWVzID0gVFJVRSkNCiAgDQogICMgSGVyZSB3ZSBhcmUgbG9hZGluZyB0aGUgcGFja2FnZQ0KICBsaWJyYXJ5KCJydmVzdCIpDQp9DQoNCmBgYA0KDQotLS0tLS0tLS0tLS0tDQoNCiMjIFRhc2sgMTogTGluZWFyIFByb2dyYW1taW5nIC0gU29sdmluZyBNYXJrZXRpbmcgTW9kZWwNCg0KLS0tLS0tLS0tLS0tLQ0KDQojIyMgMUEpIENyZWF0ZSB0aGUgbW9kZWwgb2JqZWN0IGluIFIuDQoNCmBgYHtyfQ0KDQpscHJlYyA8LSBtYWtlLmxwKDAsIDIpIA0KDQpgYGANCg0KIyMjIyBTZXQgdGhlIGNvbnN0cmFpbnMgYW5kIG9iamVjdGl2ZSBmdW5jdGlvbiBmb3IgdGhlIG1vZGVsLg0KDQoqIFNldCBmb3IgbWF4aW11bQ0KYGBge3J9DQoNCmxwLmNvbnRyb2wobHByZWMsIHNlbnNlPSJtYXgiKSAgDQpzZXQub2JqZm4obHByZWMsIGMoMjc1LjY5MSwgNDguMzQxKSkNCg0KYGBgDQoNCiMjIyAxQikgQWRkIGNvbnN0cmFpbnMNCg0KYGBge3J9DQoNCmFkZC5jb25zdHJhaW50KGxwcmVjLCBjKDEsIDEpLCAiPD0iLCAzNTAwMDApDQphZGQuY29uc3RyYWludChscHJlYywgYygxLCAwKSwgIj49IiwgMTUwMDApDQphZGQuY29uc3RyYWludChscHJlYywgYygwLCAxKSwgIj49IiwgNzUwMDApDQphZGQuY29uc3RyYWludChscHJlYywgYygyLCAtMSksICI9IiwgMCkNCg0KYGBgDQoNCiMjIyMgVmlldyB0aGUgcHJvYmxlbSBmb3JtdWxhdGlvbiBpbiB0YWJ1bGFyL21hdHJpeCBmb3JtIHRvIGNvbmZpcm0gdGhhdCB0aGUgbW9kZWwgd2FzIGNyZWF0ZWQgY29ycmVjdGx5Lg0KDQpgYGB7cn0NCg0KbHByZWMNCg0KYGBgDQoNCiMjIyAxQykgU29sdmUgdGhlIG9wdGltaXphdGlvbiBwcm9ibGVtDQpgYGB7cn0NCiMgc29sdmUgDQpzb2x2ZShscHJlYykgDQoNCmBgYA0KDQojIyMjIERpc3BsYXkgdGhlIG9iamVjdGl2ZSBmdW5jdGlvbiBvcHRpbXVtIHZhbHVlDQpgYGB7cn0NCg0KZ2V0Lm9iamVjdGl2ZShscHJlYykNCg0KYGBgDQoNCiMjIyMgRGlzcGxheSB0aGUgdmFyaWFibGVzIG9wdGltdW0gdmFsdWVzDQpgYGB7cn0NCg0KZ2V0LnZhcmlhYmxlcyhscHJlYykgDQoNCmBgYA0KDQotLS0tLS0tLS0tLS0tDQoNCiMjIFRhc2sgMjogUmVncmVzc2lvbiBBbmFseXNpcyAtIExpbmVhciBSZWdyZXNzaW9uDQoNCi0tLS0tLS0tLS0tLS0NCg0KKiBBIGxpbmVhciBtb2RlbCBpcyBvZiB0aGUgZm9ybSB5ID0geDAgKyB4MSArIC4uLisgeF9uDQoNCiMjIyAyQSkgUmVhZCB0aGUgY3N2IGZpbGUgaW50byBSIFN0dWRpbyBhbmQgZGlzcGxheSB0aGUgZGF0YXNldC4gDQoNCiogTmFtZSB5b3VyIGRhdGFzZXQgJ215ZGF0YScgc28gaXQgZWFzeSB0byB3b3JrIHdpdGguDQoNCiogQ29tbWFuZHM6IHJlYWRfY3N2KCkgaGVhZCgpDQoNCmBgYHtyfQ0KbXlkYXRhIDwtIHJlYWQuY3N2KGZpbGU9ImRhdGEvU2VydmVyc0Nvc3QuY3N2IikNCm15ZGF0YQ0KYGBgDQpgYGB7cn0NCmhlYWQobXlkYXRhKQ0KYGBgDQoNCg0KIyMjIyBFeHRyYWN0IHRoZSBhc3NpZ25lZCBmZWF0dXJlcyAoY29sdW1ucykgdG8gcGVyZm9ybSBzb21lIGFuYWx5dGljcy4gDQpgYGB7cn0NCnNlcnZlcnMgPC0gbXlkYXRhJHNlcnZlcnMNCmNvc3QgPC0gbXlkYXRhJGNvc3QNCmBgYA0KDQojIyMgMkIpIENyZWF0ZSBhIGNvcnJlbGF0aW9uIHRhYmxlIGZvciB5b3VyIHRvIGNvbXBhcmUgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGFsbCB2YXJpYWJsZXMuIFdoYXQgY2FuIHlvdSB0ZWxsIGFib3V0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMuICANCg0KYGBge3J9DQpjb3IobXlkYXRhKQ0KYGBgDQojIyBUaGUgdHdvIHZhcmlhYmxlcyBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdoaWNoIG1lYW5zIHRoZXkgbW92ZSB0b2dldGhlci4gSG93ZXZlciBpdCdzIGEgc21hbGwgcG9zaXRpdmUgY29ycmVsYXRpb24uIA0KDQojIyMgMkMpIENyZWF0ZSBhIHBsb3QgZm9yIHRoZSBkZXBlbmRlbnQgKHkpIGFuZCBpbmRlcGVuZGVudCAoeCkgdmFyaWFibGVzLiBOb3RlIGFueSBwYXR0ZXJucyBvciByZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28gdmFyaWFibGVzIGRlc2NyaWJlIHRoZSB0cmVuZCBsaW5lLg0KDQoqIFRoZSBibHVlIGxpbmUgaGVyZSByZXByZXNlbnRzIHRoZSBsaW5lYXIgbW9kZWwgd2UgY3JlYXRlZCBhbmQgdGhlIGJsYWNrIGRvdHMgYXJlIHRoZSBkYXRhIHBvaW50cy4gDQoNCkNvbW1hbmRzOiBwIDwtIHFwbG90KCB4ID0gSU5ERVBFTkRFTlQsIHkgPSBERVBFTkRFTlQsIGRhdGEgPSBteWRhdGEpICsgZ2VvbV9wb2ludCgpDQoNCmBgYHtyfQ0KcCA8LSBxcGxvdCggeCA9IHNlcnZlcnMsIHkgPSBjb3N0LCBkYXRhID0gbXlkYXRhKSArIGdlb21fcG9pbnQoKQ0KcA0KYGBgDQoNCkNvbW1tYW5kOiBwICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikNCg0KIyMjIyBBZGQgYSB0cmVuZCBsaW5lIHBsb3QgdXNpbmcgdGhlIGEgbGluZWFyIG1vZGVsDQpgYGB7cn0NCnAgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKQ0KYGBgDQojIyBUaGUgcG9pbnRzIG1ha2UgYSBVIHNoYXBlIGdvaW5nIGZyb20gYSBuZWdhdGl2ZSBzbG9wZSB0byBhIHBvc2l0aXZlIG9uZS4gVGhlIHRyZW5kIGxpbmUgc2hvd3MgdGhlIGJlc3QgZml0IGZvciB0aGUgZGF0YS4gSG93ZXZlciwgdGhpcyBkYXRhIGRvZXNuJ3QgaGF2ZSBhIHZlcnkgZ29vZCBmaXQgYW5kIGRvZXNuJ3QgZ28gdGhyb3VnaCBhIHNpbmdsZSBwb2ludC4gDQoNCiMjIyAyRCkgQ3JlYXRlIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgYnkgaWRlbnRpZnlpbmcgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAoeSkgYW5kIGluZGVwZW5kZW50IHZhcmlhYmxlICh4X24pDQoNCiogQ29tbWFuZHM6IGxpbmVhcl9tb2RlbCA8LSBsbSggREVQRU5ERU5UIH4gSU5ERVBFTkRFTlQgKSANCg0KYGBge3J9DQoNCmxpbmVhcl9tb2RlbCA8LSBsbSggY29zdCB+IHNlcnZlcnMgKSANCmxpbmVhcl9tb2RlbA0KDQpgYGANCg0KIyMjIyBVc2UgdGhlIHJlZ3Jlc3Npb24gbW9kZWwgdG8gY3JlYXRlIGEgcmVwb3J0LiBOb3RlIHRoZSBSLVNxdWFyZWQgYW5kIEFkanVzdGVkIFItU3F1YXJlZCB2YWx1ZXMsIGRldGVybWluZSBpZiB0aGlzIGlzIGEgZ29vZCBvciBiYWQgZml0IGZvciB5b3VyIGRhdGE/DQoNCiogQ29tbWFuZHM6IHN1bW1hcnkoIGxpbmVhcl9tb2RlbCApDQoNCmBgYHtyfQ0KIHN1bW1hcnkoIGxpbmVhcl9tb2RlbCApDQpgYGANCiMjIFItc3F1YXJlZCBpcyAuMDAxMTI3IGFuZCB0aGUgYWRqdXN0ZWQgaXMgLTAuMDU0MzcuIFRoaXMgc2hvd3MgdGhhdCB0aGlzIGlzIG5vdCBhIHZlcnkgZ29vZCBmaXQgZm9yIHRoZSBkYXRhLiBJdCdzIGJldHRlciB0aGUgaGlnaGVyIHRoZSBudW1iZXIgYmVjb21lcyBhbmQgdGhpcyBpcyBhIGxvdyBudW1iZXIuIA0KLS0tLS0tLS0tLS0tLQ0KDQojIyBUYXNrIDM6IFJlZ3Jlc3Npb24gQW5hbHlzaXMgLSBOb24tbGluZWFyIFJlZ3Jlc3Npb24NCg0KLS0tLS0tLS0tLS0tLQ0KDQoqIFdlIHVzZSBhIHRyYW5zZm9ybWF0aW9uIGFuZCB1c2UgYSBub25saW5lYXIgcXVhZHJhdGljIG1vZGVsIHRvIHNlZSBob3cgdGhlIG1vZGVsIGZpdHMgdG8gdGhlIGRhdGEuDQoNCiogQSBxdWFkcmF0aWMgbW9kZWwgdHJhbnNmb3JtcyB0aGUgcHJlZGljdG9yIGJ5IHNxdWFyaW5nIGl0IGFuZCBhZGRpbmcgdG8gdGhlIG1vZGVsLiANCiogUXVhZHJhdGljIE1vZGVsOiB5ID0geCArIHheMg0KDQojIyMgM0EpIENyZWF0ZSBhIG5vbi1saW5lYXIgcXVhZHJhdGljIHJlZ3Jlc3Npb24gbW9kZWwgYnkgaWRlbnRpZnlpbmcgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAoeSkgYW5kIGluZGVwZW5kZW50IHZhcmlhYmxlcyAoeCkuIFRyYW5zZm9ybXMgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlIGJ5IHNxdWFyaW5nIGl0IGFuZCBhZGRpbmcgdG8gdGhlIG1vZGVsLiANCg0KKiBUaGUgUXVhZHJhdGljIG1vZGVsIGZvcm11bGEgaXM6IHkgPSB4ICsgeF4yDQoqIENvbW1hbmRzOiBxdWFkX21vZGVsIDwtIGxtKHkgfiB4ICsgeF9zcXVhcmVkKQ0KKiBDb21tYW5kczogVG8gc3F1YXJlZCBhIHZhcmlhYmxlIHVzZSAoXikgc3VjaCBhcyAgeF4yDQoNCmBgYHtyfQ0KeCA9IG15ZGF0YSRzZXJ2ZXJzDQp4MiA9IG15ZGF0YSRzZXJ2ZXJzXjINCnkgPSB4ICsgeDIgDQpxdWFkX21vZGVsIDwtIGxtKHkgfiB4ICsgeDIpDQpxdWFkX21vZGVsDQpgYGANCg0KIyMjIyBVc2UgdGhlIHF1YWRyYXRpYyBtb2RlbCB0byBjcmVhdGUgYSByZXBvcnQuIE5vdGUgdGhlIFItU3F1YXJlZCBhbmQgQWRqdXN0ZWQgUi1TcXVhcmVkIHZhbHVlcywgZGV0ZXJtaW5lIGlmIHRoaXMgaXMgYSBnb29kIG9yIGJhZCBmaXQgZm9yIHlvdXIgZGF0YT8NCg0KKiBDb21tYW5kczogc3VtbWFyeSggcXVhZF9tb2RlbCApDQoNCmBgYHtyfQ0Kc3VtbWFyeSggcXVhZF9tb2RlbCApDQpgYGANCg0KIyMgQm90aCB0aGUgci1zcXVhcmVkIGFuZCBhZGp1c3RlZCBhcmUgMSB3aGljaCB3b3VsZCBsZWFkIHBlb3BsZSB0byBiZWxpZXZlIHRoYXQgdGhpcyBpcyBhIHBlcmZlY3QgZml0LiANCg0KIyMjIDNCKSBDb21wdXRlIHRoZSBwcmVkaWN0ZWQgdmFsdWVzIGJhc2VkIG9uIHRoZSBxdWFkcmF0aWMgbW9kZWwuDQoNCkNvbW1hbmRzOiBwcmVkaWN0ZWRfMiA8LSBwcmVkaWN0KCBxdWFkX21vZGVsLCBkYXRhID0gbXlkYXRhICkNCg0KYGBge3J9DQpzZXJ2ZXJzMiA9IHNlcnZlcnNeMg0KDQpxdWFkX21vZGVsID0gbG0oY29zdCB+IHNlcnZlcnMgKyBzZXJ2ZXJzMiApDQpxdWFkX21vZGVsDQoNCnByZWRpY3RlZDIgPSBwcmVkaWN0KHF1YWRfbW9kZWwsZGF0YT1teWRhdGEpDQpwcmVkaWN0ZWQyDQoNCmBgYA0KDQojIyMjIENyZWF0ZSBhIHBsb3QgdXNpbmcgdGhlIHF1YWRyYXRpYyBtb2RlbCBwcmVkaWN0ZWQgdmFsdWVzIGluIGNvbG9yIHJlZC4gTm90ZWQgdGhlIHNoYXBlLCBsb29raW5nIGF0IHRoZSBwbG90IGlzIHRoaXMgYSBnb29kIG9yIGJhZCBmaXQgZm9yIHlvdXIgZGF0YT8NCg0KQ29tbWFuZHM6IHFwbG90KCB4ID0gREVQRU5ERU5ULCB5ID0gSU5ERVBFTkRFTlQvUFJFRElDVEVELCBjb2xvdXIgPSAicmVkIiApDQoNCmBgYHtyfQ0KcXBsb3QoIHggPSBzZXJ2ZXJzLCB5ID0gcHJlZGljdGVkMiwgY29sb3VyID0gInJlZCIgKQ0KDQpgYGANCiMjIFRoZSBzaGFwZSBpcyBhIHBlcmZlY3QgVSB3aGljaCBzZWVtcyB0byBiZSBhIGJldHRlciBmaXQgZm9yIHRoZSBkYXRhIGFzIGl0IHNlZW1zIG1vcmUgZXZlbmx5IGRpc3RyaWJ1dGVkLiANCg0KIyMjIDNDKSBDcmVhdGUgYSBub24tbGluZWFyIGN1YmljIHJlZ3Jlc3Npb24gbW9kZWwgYnkgaWRlbnRpZnlpbmcgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSAoeSkgYW5kIGluZGVwZW5kZW50IHZhcmlhYmxlcyAoeCkuIFRyYW5zZm9ybXMgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlIGJ5IHNxdWFyaW5nIGl0IHRvIHNlY29uZCAoeF4yKSBhbmQgdGhpcmQgKXheMykgZGVncmVlcyBhbmQgYWRkaW5nIHRoZW0gdG8gdGhlIG1vZGVsLiANCg0KKiBUaGUgQ3ViaWMgbW9kZWwgZm9ybXVsYSBpczogeSA9IHggKyB4XjIgKyB4XjMNCiogQ29tbWFuZHM6IGN1YmljX21vZGVsIDwtIGxtKHkgfiB4ICsgeF9zcXVhcmVkICsgeF9jdWJpYykNCiogQ29tbWFuZHM6IFRvIHNxdWFyZWQgYSB2YXJpYWJsZSB1c2UgKF4pIHN1Y2ggYXMgIHheMiwgeF4zDQoNCmBgYHtyfQ0Kc2VydmVycyA8LSBteWRhdGEkc2VydmVycw0Kc2VydmVyczIgPC0gbXlkYXRhJHNlcnZlcnNeMg0Kc2VydmVyczMgPC0gbXlkYXRhJHNlcnZlcnNeMw0Kc2VydmVyczQgPC0gbXlkYXRhJHNlcnZlcnNeNA0Kc2VydmVyczUgPC0gbXlkYXRhJHNlcnZlcnNeNQ0KDQpjdWJpY19tb2RlbCA8LSBsbShjb3N0IH4gc2VydmVycyArIHNlcnZlcnMyICsgc2VydmVyczMpDQpjdWJpY19tb2RlbA0KYGBgDQoNCiMjIyMgVXNlIHRoZSBjdWJpYyBtb2RlbCB0byBjcmVhdGUgYSByZXBvcnQuIE5vdGUgdGhlIFItU3F1YXJlZCBhbmQgQWRqdXN0ZWQgUi1TcXVhcmVkIHZhbHVlcywgZGV0ZXJtaW5lIGlmIHRoaXMgaXMgYSBnb29kIG9yIGJhZCBmaXQgZm9yIHlvdXIgZGF0YT8NCg0KKiBDb21tYW5kczogc3VtbWFyeSggY3ViaWNfbW9kZWwgKQ0KDQpgYGB7cn0NCnN1bW1hcnkoIGN1YmljX21vZGVsICkNCmBgYA0KIyMgUi1zcXVhcmVkIGlzIC45MzIgYW5kIHRoZSBhZGp1c3RlZCBpcyAwLjkxOTMgd2hpY2ggaXMgcHJldHR5IGNsb3NlIHRvIDEgd2hpY2ggbGVhZHMgdXMgdG8gYmVsaWV2ZSB0aGF0IHRoaXMgYSBnb29kIGZpdCBmb3IgdGhlIGRhdGEuIA0KDQojIyMgM0QpIENvbXB1dGUgdGhlIHByZWRpY3RlZCB2YWx1ZXMgYmFzZWQgb24gdGhlIGN1YmljIG1vZGVsLg0KDQpDb21tYW5kczogcHJlZGljdGVkMyA8LSBwcmVkaWN0KCBjdWJpY19tb2RlbCwgZGF0YSA9IG15ZGF0YSApDQoNCmBgYHtyfQ0KcHJlZGljdGVkMyA8LSBwcmVkaWN0KCBjdWJpY19tb2RlbCwgZGF0YSA9IG15ZGF0YSApDQpwcmVkaWN0ZWQzDQpgYGANCg0KIyMjIyBDcmVhdGUgYSBwbG90IHVzaW5nIHRoZSBjdWJpYyBtb2RlbCBwcmVkaWN0ZWQgdmFsdWVzIGluIGNvbG9yIGdyZWVuLiBOb3RlZCB0aGUgc2hhcGUsIGxvb2tpbmcgYXQgdGhlIHBsb3QgaXMgdGhpcyBhIGdvb2Qgb3IgYmFkIGZpdCBmb3IgeW91ciBkYXRhPyBJcyB0aGlzIG1vZGVsIGJldHRlciB0aGFuIHRoZSBwcmV2aW91cz8NCg0KQ29tbWFuZHM6IHFwbG90KCB4ID0gREVQRU5ERU5ULCB5ID0gSU5ERVBFTkRFTlQvUFJFRElDVEVELCBjb2xvdXIgPSAicmVkIiApDQoNCmBgYHtyfQ0KcXBsb3QoIHggPSBzZXJ2ZXJzLCB5ID0gcHJlZGljdGVkMywgY29sb3VyID0gImdyZWVuIiApDQoNCmBgYA0KDQojIyBUaGlzIG1vZGVsIHNlZW1zIGV2ZW5seSBkaXN0cmlidXRlZCB3aGljaCBtYWtlcyBpdCBsb29rIGxpa2UgaXQgd2lsbCBiZSBhIGdvb2QgZml0IGZvciB0aGUgZGF0YS4gDQoNCiMjIyAzRSkgT3ZlcmxheSB0aGUgYWxsIG1vZGVscyBvbiB0b3Agb2YgdGhlIGRhdGEuIFdoaWNoIG1vZGVsIHNlZW1zIHRvIGZpdCB0aGUgYmVzdCBpbiB5b3VyIG9waW5pb24/IEp1c3RpZnkgeW91ciBhbnN3ZXIuIA0KDQp2YXJpYWJsZXM6IExJTkVBUl9NT0RFTCAsIFBSRURJQ1RFRF9RVUFEUkFUSUMsIFBSRURJQ1RFRF9DVUJJQw0KDQpgYGB7cn0NCg0KIyBCbGFjayA9IEFjdHVhbCBEYXRhDQpwbG90KHNlcnZlcnMsIGNvc3QsIHBjaCA9IDE2KSANCiMgQmx1ZSA9IExpbmVhciBMaW5lIGJhc2VkIG9uIExpbmVhciBSZWdyZXNzaW9uIE1vZGVsDQphYmxpbmUobGluZWFyX21vZGVsLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpIA0KDQojIFJlZCA9IFF1YWRyYXRpYyBNb2RlbCBiYXNlZCBvbiBRdWFkcmF0cmljIFJlZ3Jlc3Npb24gZm91bmQgYWJvdmUNCiMgTmVlZGVkIHRvIG92ZXJsYXkgbmV3IHBvaW50cyB3aXRob3V0IHRoZSBsYWJlbHMgYW5kIGFubm90YXRpb25zDQpwYXIobmV3ID0gVFJVRSwgeGF4dCA9ICJuIiwgeWF4dCA9ICJuIiwgYW5uID0gRkFMU0UpIA0KcGxvdChwcmVkaWN0ZWQyLCBjb2wgPSAicmVkIiwgcGNoID0gMTYpIA0KDQojIEdyZWVuID0gQ3ViaWMgTW9kZWwgYmFzZWQgb24gQ3ViaWMgUmVncmVzc2lvbiBmb3VuZCBhYm92ZQ0KIyBPdmVybGF5IG5ldyBwb2ludHMgd2l0aG91dCB0aGUgbGFiZWxzIGFuZCBhbm5vdGF0aW9ucyANCnBhcihuZXcgPSBUUlVFLCB4YXh0ID0gIm4iLCB5YXh0ID0gIm4iLCBhbm4gPSBGQUxTRSkgDQpwbG90KHByZWRpY3RlZDMsIGNvbCA9ICJncmVlbiIsIHBjaCA9IDE2KQ0KDQpgYGANCiMjIFRoZSBxdWFkcmF0aWMgbW9kZWwgbG9va3MgdGhlIGJlc3QgYmVjYXVzZSB0aGUgdHJlbmQgbGluZSBnb2VzIGRpcmVjdGx5IHRocm91Z2ggdHdvIHBvaW50cyB3aGVyZSBhcyBpdCBvbmx5IGdvZXMgZGlyZWN0bHkgdGhyb3VnaCBvbmUgcG9pbiBmb3IgdGhlIGN1YmljIGdyYXBoIGFuZCBub25lIGZvciB0aGUgbGluZWFyLiANCg==