Information about optimizaion in R

http://cran.r-project.org/web/views/Optimization.html

https://www.rdocumentation.org/packages/ROI/versions/0.2-1

This file can be downloaded at https://github.com/ECON457-fa16/labs/raw/master/lab03/lab03.Rmd

The R Optimization Infrastructure (ROI)

The R Optimization Infrastructure (ROI) package promotes the development and use of interoperable (open source) optimization problem solvers for R.

ROI handle LP up to MILP and MIQCP problems using the following supported solvers :

  1. lpSolve

  2. quadprog

  3. Rcplex

  4. Rglpk (default)

  5. Rsymphony

more…

Solvers

CPLEX is a commercial solver. Students can get academic license.

GLPK is free. R has the high level interface Rglpk.

http://winglpk.sourceforge.net/

https://cran.r-project.org/web/packages/Rglpk/index.html

Install all the packages.

Uncomment the code in follow chunk and install all packages.

#install.packages("ROI")
#install.packages(c( "Rglpk","ROI.plugin.symphony","ROI.plugin.glpk","ROI.plugin.quadprog","ROI.plugin.nloptr","ROI.plugin.ipop","ROI.plugin.ecos"))

Linear Progarmming

library("ROI")
ROI: R Optimization Infrastructure
Registered solver plugins: nlminb, ecos, glpk, ipop, nloptr, quadprog, symphony.
Default solver: auto.
$$ \[\begin{align*} \text{maximize: } 2 x_1 &+ 4 x_2 + 3 x_3\\ \text{subject to: } 3 x_1 &+ 4 x_2 + 2 x_3 & <= 60 \\ 2 x_1 &+ x_2 + x_3 & <= 40 \\ x_1 &+ 3 x_2 + 2 x_3 & <= 80 \end{align*}\]

$$

LP # model named as LP
ROI Optimization Problem:

Maximize a linear objective function with
- 3 objective variables,

subject to
- 3 constraints of type linear.

Solve

sol
Optimal solution found.
The objective value is: 9.000000e+01

Solutions

solution(sol, type = c("dual"))  # solution for dual problem: minimize by subject to A'y >= c
[1] -2.5 -2.0  0.0

Extract solutions

sol$message # detailed message for solution 
$optimum
[1] 90

$solution
[1]  0  0 30

$status
[1] 5

$solution_dual
[1] -2.5 -2.0  0.0

$auxiliary
$auxiliary$primal
[1] 60 30 60

$auxiliary$dual
[1] 1.5 0.0 0.0

Quadratic Progarmming

It will require putting problem in matrix form.

three decision variables: x1, x2, x3

$$ \[\begin{align*} \text{minimize: } - 5 x_2 + 1/2 (x_1^2 + x_2^2 + x_3^2)\\ \text{subject to: } -4 x_1 - 3 x_2 & >= -8 \\ 2 x_1 + x_2 & >= 2 \\ - 2 x_2 + x_3 & >= 0 \end{align*}\]

$$

QP
ROI Optimization Problem:

Minimize a quadratic objective function with
- 3 objective variables,

subject to
- 3 constraints of type linear.

Solve

sol
Optimal solution found.
The objective value is: -2.380952e+00

Extract solutions

sol$message
NULL

Solutions

solution(sol, type = c("dual"))
[1] NA

Portfolio optimization - minimum variance

To minimize the risk, we choose invest in 30 stocks and we need to decide the share for each stock. Decision variables: x1, x2,…, x30. sum(x, i) = 1. If xi is allowed to negative, it means we can borrow stock and sell it.

(op <- OP( objective = obj, constraints = full_invest )) 
ROI Optimization Problem:

Minimize a quadratic objective function with
- 30 objective variables,

subject to
- 1 constraints of type linear.

Solution

round( sol[ which(sol > 1/10^6) ], 3 )
  IBM   MCD   MRK    PG     T    VZ   WMT   XOM 
0.165 0.301 0.005 0.138 0.031 0.091 0.169 0.101 

LP with boundary

three decision variables: x1, x2

$$ \[\begin{align*} \text{minimize: } x_1 + 2* x_2\\ \text{subject to: } x_1 + x_2 & = 2 \\ x_1 & <= 3 \\ x_2 & <= 3 \end{align*}\]

$$

lp
ROI Optimization Problem:

Minimize a linear objective function with
- 2 objective variables,

subject to
- 1 constraints of type linear.

Solutions

 x$solution
[1] 2 0

Change boundary

$$ \[\begin{align*} \text{minimize: } x_1 + 2* x_2\\ \text{subject to: } x_1 + x_2 & = 2 \\ x_1 & <= 1 \\ x_2 & <= 1 \end{align*}\]

$$

Solutions

 y$solution
[1] 1 1

Other optimization package in R

We also can solve optimization problem using other packages.

Install packages

Uncomment the code in follow chunk and install all packages.

install.packages(c("quadprog", "nlme","Rglpk"))
Error in install.packages : Updating loaded packages
suppressMessages(library(Rglpk))
Error in library(Rglpk) : there is no package called æ… glpk?

args() function tells us how we can use those functions such as lp, solve.QP, Rglpk_solve_LP

args(lp)
args(solve.QP)
args(Rglpk_solve_LP)
#args(nlminb)
#args(optim)
#args(Rcplex)

Linear Programming by lpsolve

Here is a list of some key features of lp_solve:

  • Mixed Integer Linear Programming (MILP) solver

  • Basically no limit on model size

  • It is free and with sources

  • Supports Integer variables, Semi-continuous variables and Special Ordered Sets

Example by lpSolveAPI

straightforward

If we have 4 decision variables: x1,…, x4

\[\begin{align*} \text{minimize: } x_1 + 3 x_2 + 6.24 x_3 + 0.1 x_4\\ \text{subject to: } 78.26 x_2 + 2.9 x_4 & >= 92.3 \\ 0.2 x_1 + 11.91 x_3 & <= 14.8 \\ 12.68 x_1 + 0.08 x_3 + 0.9 x_4 &>= 4 \\ 18 <= x_4 & <= 48.98 \\ x_1 & >= 28.6 \end{align*}\]

Set up model
Setup objective function
set.objfn(lpmodel, c(1, 3, 6.24, 0.1))  # object function, vector c 
Error in set.objfn(lpmodel, c(1, 3, 6.24, 0.1)) : 
  object 'lpmodel' not found
Add constraints
Set bounds
Setup names

Show model setting

lpmodel

Not necessary

lpmodel
Model name: 
             C1     C2     C3     C4          
Minimize      1      3   6.24    0.1          
R1            0  78.26      0    2.9  >=  92.3
R2         0.24      0  11.31      0  <=  14.8
R3        12.68      0   0.08    0.9  >=     4
Kind        Std    Std    Std    Std          
Type       Real   Real   Real   Real          
Upper       Inf    Inf    Inf  48.98          
Lower      28.6      0      0     18          
Solve the model
solve(lpmodel)
[1] 0
Extract solutions
get.constraints(lpmodel)
[1]  92.3000   6.8640 391.2928

Example by lpSolve

provide a lot of information including sensitivities analysis.

\[\begin{align*} \text{maximize: } x_1 + 9 x_2 + x_3 \\ \text{subject to: } x_1 + 2 x_2 + 3 x_3 & <= 9 \\ 3 x_1 + 2 x_2 + 2 x_3 & <= 15 \end{align*}\]

Setup objective function
Setup constraints
Solve the model
lp ("max", model_obj, model_con, model_dir, model_rhs)
Success: the objective function is 40.5 
Extract solutions
lp ("max", model_obj, model_con, model_dir, model_rhs)$solution
[1] 0.0 4.5 0.0
Get sensitivities
lp ("max", model_obj, model_con, model_dir, model_rhs, compute.sens=TRUE)$duals.to  
[1] 1.5e+01 1.0e+30 3.0e+00 1.0e+30 3.0e+00

Intergr Programming

Previous model with constraints that all decision variables are integer.

lp ("max", model_obj, model_con, model_dir, model_rhs, int.vec=1:3, compute.sens=TRUE)$duals
[1]  1  0  0  7 -2

Quadratic Programming by quadprog

solving quadratic programming problems of the form

min(c’ x + 1/2 x’ D x)

with the constraints A’ x >= b_0.

$$ \[\begin{align*} \text{minimize: } - 5 x_2 + 1/2 (x_1^2 + x_2^2 + x_3^2)\\ \text{subject to: } -4 x_1 - 3 x_2 & >= -8 \\ 2 x_1 + x_2 & >= 2 \\ - 2 x_2 + x_3 & >= 0 \end{align*}\]

$$

D is diagnal matix . 1/2 is convetion.

solve.QP(Dmat,cvec,Amat,bvec=bvec)
$solution
[1] 0.4761905 1.0476190 2.0952381

$value
[1] -2.380952

$unconstrained.solution
[1] 0 5 0

$iterations
[1] 3 0

$Lagrangian
[1] 0.0000000 0.2380952 2.0952381

$iact
[1] 3 2

Football MIP by glpk

Trying to pick the best possible fantasy football team given different constraints.

Goal is to pick the players that maximize the sum of their projected points.

Decision variabls are binary, 0 or 1 for one player to play in this match.

The constraints are:

  1. The team must include:

    • 1 QB

    • 2 RBs

    • 2 WRs

    • 1 TE

  2. A player’s risk must not exceed 6

  3. The sum of the players’ costs must not exceed 300.

maximize cx points

subject Ax <= b

pos == "TE"
 [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE

Solve the model with glpk

sol
$optimum
[1] 836

$solution
 [1] 1 0 1 0 1 1 0 1 1 0

$status
[1] 0

$solution_dual
[1] NA

$auxiliary
$auxiliary$primal
 [1]   1.0   2.0   2.0   1.0   2.9   0.0   0.7   0.0   3.5   5.0   0.0   4.7   3.7   0.0 298.0

$auxiliary$dual
[1] NA

Solve it using ROI

football <- OP( f, # objective function, vector c
          L_constraint(L = A, # linear constraint: Maxtrix A
          dir = dir,  # direction
          rhs = b), # right hand side: vector b 
          types = var.types,  
          max = TRUE)
football
ROI Optimization Problem:

Maximize a linear objective function with
- 10 objective variables,

subject to
- 15 constraints of type linear.

Some of the objective variables are of type binary or integer.

Solve

sol
Optimal solution found.
The objective value is: 8.360000e+02

Solutions

solution(sol, type = c("dual"))  # solution for dual problem: minimize by subject to A'y >= c
[1] NA

Extract solutions

sol$message # detailed message for solution 
$optimum
[1] 836

$solution
 [1] 1 0 1 0 1 1 0 1 1 0

$status
[1] 5

$solution_dual
[1] NA

$auxiliary
$auxiliary$primal
 [1]   1.0   2.0   2.0   1.0   2.9   0.0   0.7   0.0   3.5   5.0   0.0   4.7   3.7   0.0 298.0

$auxiliary$dual
[1] NA
LS0tDQp0aXRsZTogIkVDT040NTcgUiBsYWIgMyBPcHRpbWl6YXRpb24gaW4gUiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyMgSW5mb3JtYXRpb24gYWJvdXQgb3B0aW1pemFpb24gaW4gUg0KDQpodHRwOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi92aWV3cy9PcHRpbWl6YXRpb24uaHRtbA0KDQpodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvUk9JL3ZlcnNpb25zLzAuMi0xDQoNCg0KVGhpcyBmaWxlIGNhbiBiZSBkb3dubG9hZGVkIGF0IGh0dHBzOi8vZ2l0aHViLmNvbS9FQ09ONDU3LWZhMTYvbGFicy9yYXcvbWFzdGVyL2xhYjAzL2xhYjAzLlJtZA0KDQojIyBUaGUgUiBPcHRpbWl6YXRpb24gSW5mcmFzdHJ1Y3R1cmUgKFJPSSkNCg0KVGhlIFIgT3B0aW1pemF0aW9uIEluZnJhc3RydWN0dXJlIChST0kpIHBhY2thZ2UgcHJvbW90ZXMgdGhlIGRldmVsb3BtZW50IGFuZCB1c2Ugb2YgaW50ZXJvcGVyYWJsZSAob3BlbiBzb3VyY2UpIG9wdGltaXphdGlvbiBwcm9ibGVtIHNvbHZlcnMgZm9yIFIuDQoNCg0KUk9JIGhhbmRsZSBMUCB1cCB0byBNSUxQIGFuZCBNSVFDUCBwcm9ibGVtcyB1c2luZyB0aGUgZm9sbG93aW5nIHN1cHBvcnRlZCBzb2x2ZXJzIDoNCg0KMS4gbHBTb2x2ZQ0KDQoyLiBxdWFkcHJvZw0KDQozLiBSY3BsZXgNCg0KNC4gUmdscGsgKGRlZmF1bHQpDQoNCjUuIFJzeW1waG9ueQ0KDQptb3JlLi4uIA0KDQoNCg0KDQojIyBTb2x2ZXJzDQoNCkNQTEVYIGlzIGEgY29tbWVyY2lhbCBzb2x2ZXIuIFN0dWRlbnRzIGNhbiBnZXQgYWNhZGVtaWMgbGljZW5zZS4gDQoNCkdMUEsgaXMgZnJlZS4gUiBoYXMgdGhlIGhpZ2ggbGV2ZWwgaW50ZXJmYWNlIFJnbHBrLg0KDQpodHRwOi8vd2luZ2xway5zb3VyY2Vmb3JnZS5uZXQvDQoNCmh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9SZ2xway9pbmRleC5odG1sDQoNCg0KDQojIyBJbnN0YWxsIGFsbCB0aGUgcGFja2FnZXMuDQoNClVuY29tbWVudCB0aGUgY29kZSBpbiBmb2xsb3cgY2h1bmsgYW5kIGluc3RhbGwgYWxsIHBhY2thZ2VzLg0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJST0kiKQ0KI2luc3RhbGwucGFja2FnZXMoYyggIlJnbHBrIiwiUk9JLnBsdWdpbi5zeW1waG9ueSIsIlJPSS5wbHVnaW4uZ2xwayIsIlJPSS5wbHVnaW4ucXVhZHByb2ciLCJST0kucGx1Z2luLm5sb3B0ciIsIlJPSS5wbHVnaW4uaXBvcCIsIlJPSS5wbHVnaW4uZWNvcyIpKQ0KYGBgDQoNCg0KDQoNCiMjIExpbmVhciBQcm9nYXJtbWluZw0KDQoNCg0KDQoNCmBgYHtyfQ0KDQoNCmxpYnJhcnkoIlJPSSIpDQoNCiNsaWJyYXJ5KCJST0kucGx1Z2luLmdscGsiKQ0KI2xpYnJhcnkoIlJPSS5wbHVnaW4uc3ltcGhvbnkiKQ0KI2xpYnJhcnkoUk9JLnBsdWdpbi5pcG9wKQ0KDQojbGlicmFyeShST0kucGx1Z2luLm5sb3B0cikNCiNsaWJyYXJ5KFJPSS5wbHVnaW4ucXVhZHByb2cpDQojbGlicmFyeShST0kucGx1Z2luLmVjb3MpDQoNClJPSV9yZWdpc3RlcmVkX3NvbHZlcnMoKQ0KYGBgDQoNCg0KDQokJFxiZWdpbnthbGlnbip9IA0KICAgIFx0ZXh0e21heGltaXplOiB9ICAgMiB4XzEgJisgNCB4XzIgKyAzIHhfM1xcDQpcdGV4dHtzdWJqZWN0IHRvOiB9ICAgICAzIHhfMSAmKyA0IHhfMiArIDIgeF8zICYgPD0gNjAgXFwNCiAgICAgICAgICAgICAgICAgICAgICAgIDIgeF8xICYrICAgeF8yICsgICB4XzMgJiA8PSA0MCBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4XzEgJisgMyB4XzIgKyAyIHhfMyAmIDw9IDgwDQoNClxlbmR7YWxpZ24qfSQkDQoNCg0KDQoNCmBgYHtyfQ0KIyMgU2ltcGxlIGxpbmVhciBwcm9ncmFtLg0KIyMgdGhyZWUgZGVjaXNpb24gdmFyaWFibGVzOiB4MSwgeDIsIHgzDQojIyBtYXRyaXggZm9ybTogICAgb2JqZWN0aXZlOiBjKnggDQojIyAgICAgICAgICAgICAgIGNvbnN0cmFpbnRzOiBBKnggPD0gYiAgDQojIyBtYXhpbWl6ZTogICAyIHhfMSArIDQgeF8yICsgMyB4XzMNCiMjIHN1YmplY3QgdG86IDMgeF8xICsgNCB4XzIgKyAyIHhfMyA8PSA2MA0KIyMgICAgICAgICAgICAgMiB4XzEgKyAgIHhfMiArICAgeF8zIDw9IDQwDQojIyAgICAgICAgICAgICAgIHhfMSArIDMgeF8yICsgMiB4XzMgPD0gODANCiMjICAgICAgICAgICAgICAgeF8xLCB4XzIsIHhfMyBhcmUgbm9uLW5lZ2F0aXZlIHJlYWwgbnVtYmVycw0KDQpMUCA8LSBPUCggYygyLCA0LCAzKSwgIyBvYmplY3RpdmUgZnVuY3Rpb24sIHZlY3RvciBjIA0KICAgICAgICAgIExfY29uc3RyYWludChMID0gbWF0cml4KGMoMywgMiwgMSwgNCwgMSwgMywgMiwgMSwgMiksIG5yb3cgPSAzKSwgIyBsaW5lYXIgY29uc3RyYWludDogTWF4dHJpeCBBDQogICAgICAgICAgICAgICAgICAgICAgIGRpciA9IGMoIjw9IiwgIjw9IiwgIjw9IiksICMgZGlyZWN0aW9uDQogICAgICAgICAgICAgICAgICAgICAgIHJocyA9IGMoNjAsIDQwLCA4MCkpLCAgICAgICMgcmlnaHQgaGFuZCBzaWRlOiB2ZWN0b3IgYiANCiAgICAgICAgICBtYXggPSBUUlVFICkgICMgZGVmYXVsdHMgaXMgbWluaW1pemU6IG1heCA9IEZBTFNFLiBjaGFuZ2UgdG8gbWF4DQpMUCAjIG1vZGVsIG5hbWVkIGFzIExQDQpgYGANCg0KIyMjIyBTb2x2ZQ0KDQpgYGB7cn0NCnNvbCA8LSBST0lfc29sdmUoTFApIyAsIHNvbHZlciA9ICJnbHBrIikgICMgU29sdmUgbW9kZWwgTFAgd2l0aCBzcGVjaWZpYyBzb2x2ZXIgZ2xwayBvciBhdXRvbWF0aWNhbGx5IGNob29zZSBieSBST0kuDQpzb2wNCmBgYA0KDQojIyMjIFNvbHV0aW9ucw0KDQpgYGB7cn0NCnNvbHV0aW9uKHNvbCwgdHlwZSA9IGMoInByaW1hbCIpKSAjIHNvbHV0aW9uIGZvciBwcmltYWwgcHJvYmxlbQ0Kc29sdXRpb24oc29sLCB0eXBlID0gYygiZHVhbCIpKSAgIyBzb2x1dGlvbiBmb3IgZHVhbCBwcm9ibGVtOiBtaW5pbWl6ZSBieSBzdWJqZWN0IHRvIEEneSA+PSBjDQpgYGANCg0KDQojIyMjIEV4dHJhY3Qgc29sdXRpb25zDQpgYGB7cn0NCnNvbCRzb2x1dGlvbg0Kc29sJG9ianZhbA0Kc29sJHN0YXR1cw0Kc29sJG1lc3NhZ2UgIyBkZXRhaWxlZCBtZXNzYWdlIGZvciBzb2x1dGlvbiANCmBgYA0KDQojIyBRdWFkcmF0aWMgUHJvZ2FybW1pbmcNCg0KDQpJdCB3aWxsIHJlcXVpcmUgcHV0dGluZyBwcm9ibGVtIGluIG1hdHJpeCBmb3JtLg0KDQp0aHJlZSBkZWNpc2lvbiB2YXJpYWJsZXM6IHgxLCB4MiwgeDMNCg0KJCRcYmVnaW57YWxpZ24qfSANCiAgICBcdGV4dHttaW5pbWl6ZTogfSAgIC0gNSB4XzIgKyAxLzIgKHhfMV4yICsgeF8yXjIgKyB4XzNeMilcXA0KXHRleHR7c3ViamVjdCB0bzogfSAgICAgLTQgeF8xIC0gMyB4XzIgICAgICAgJiA+PSAtOCBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgIDIgeF8xICsgICB4XzIgICAgICAgJiA+PSAyIFxcDQogICAgICAgICAgICAgICAgICAgICAgICAgLSAyIHhfMiArIHhfMyAmID49IDANCg0KXGVuZHthbGlnbip9JCQNCg0KDQoNCmBgYHtyfQ0KIyMgU2ltcGxlIHF1YWRyYXRpYyBwcm9ncmFtLg0KIyMgbWluaW1pemU6IC0gNSB4XzIgKyAxLzIgKHhfMV4yICsgeF8yXjIgKyB4XzNeMikNCiMjIHN1YmplY3QgdG86IC00IHhfMSAtIDMgeF8yICAgICAgID49IC04DQojIyAgICAgICAgICAgICAgMiB4XzEgKyAgIHhfMiAgICAgICA+PSAgMg0KIyMgICAgICAgICAgICAgICAgICAgIC0gMiB4XzIgKyB4XzMgPj0gIDANCg0KUVAgPC0gT1AoIFFfb2JqZWN0aXZlIChRID0gZGlhZygxLCAzKSwgTCA9IGMoMCwgLTUsIDApKSwgICAjIHF1YWRyYXRpYyBvYmplY3RpdmUNCiAgICAgICAgICAjIHF1ZHJhdGljIHBhcnQ6IHgnUXgsICAgICBsaW5lYXIgcGFydDogTHgNCiAgICAgICAgICBMX2NvbnN0cmFpbnQoTCA9IG1hdHJpeChjKC00LC0zLDAsMiwxLDAsMCwtMiwxKSwgIyAgbGluZWFyIGNvbnN0cmFpbnQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuY29sID0gMywgYnlyb3cgPSBUUlVFKSwgI+OAgGJ5cm93IGlzIGVhc3kgZm9yIHJlYWRpbmcNCiAgICAgICAgICAgICAgICAgICAgICAgIyBMaW5lYXI6ICAgIEF4DQogICAgICAgICAgICAgICAgICAgICAgIGRpciA9IHJlcCgiPj0iLCAzKSwgDQogICAgICAgICAgICAgICAgICAgICAgIHJocyA9IGMoLTgsMiwwKSkgKSAjIHJpZ2h0IGhhbmQgc2lkZSwgdmVjdG9yIGINClFQDQpgYGANCg0KIyMjIyBTb2x2ZQ0KDQpgYGB7cn0NCnNvbCA8LSBST0lfc29sdmUoUVAsIHNvbHZlciA9ICJxdWFkcHJvZyIpICMgY2hvb3NlIHF1YWRyYXRpYyBzb2x2ZXINCnNvbA0KYGBgDQoNCg0KIyMjIyBFeHRyYWN0IHNvbHV0aW9ucw0KYGBge3J9DQpzb2wkc29sdXRpb24NCnNvbCRvYmp2YWwNCnNvbCRzdGF0dXMNCnNvbCRtZXNzYWdlICNub3QgbXVjaCBpbmZvcm1hdGlvbg0KYGBgDQoNCg0KIyMjIyBTb2x1dGlvbnMNCg0KYGBge3J9DQpzb2x1dGlvbihzb2wsIHR5cGUgPSBjKCJwcmltYWwiKSkNCnNvbHV0aW9uKHNvbCwgdHlwZSA9IGMoImR1YWwiKSkgIyBxdWFkcmF0aWMgc29sdmVyIGlzIG5vdCBnb29kIGF0IGl0Lg0KYGBgDQoNCg0KDQojIyBQb3J0Zm9saW8gb3B0aW1pemF0aW9uIC0gbWluaW11bSB2YXJpYW5jZQ0KDQpUbyBtaW5pbWl6ZSB0aGUgcmlzaywgd2UgY2hvb3NlIGludmVzdCBpbiAzMCBzdG9ja3MgYW5kIHdlIG5lZWQgdG8gZGVjaWRlIHRoZSBzaGFyZSBmb3IgZWFjaCBzdG9jay4NCkRlY2lzaW9uIHZhcmlhYmxlczogeDEsIHgyLC4uLiwgeDMwLiBzdW0oeCwgaSkgPSAxLg0KSWYgeGkgaXMgYWxsb3dlZCB0byBuZWdhdGl2ZSwgaXQgbWVhbnMgd2UgY2FuIGJvcnJvdyBzdG9jayBhbmQgc2VsbCBpdC4NCg0KDQpgYGB7cn0NCiMjIFBvcnRmb2xpbyBvcHRpbWl6YXRpb24gLSBtaW5pbXVtIHZhcmlhbmNlDQojIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyMgZ2V0IG1vbnRobHkgcmV0dXJucyBvZiAzMCBVUyBzdG9ja3MNCg0KIyMgICANCmRhdGEoIFVTMzAgKSAgIyAxODAgbW9udGhzIGZvciAzMCBzdG9ja3MNCnIgPC0gbmEub21pdCggVVMzMCApDQojIyBvYmplY3RpdmUgZnVuY3Rpb24gdG8gbWluaW1pemUNCm9iaiA8LSBRX29iamVjdGl2ZSggMipjb3YocikgKSAjIHF1YWRyYXRpYyBvYmplY3RpdmU6IHgnTXggLiBNIGlzIHZhcmlhbmNlIGNvbnZhcmlhbmNlIG1hdHJpeDogY292KHIpIC4gIA0KIyMgZnVsbCBpbnZlc3RtZW50IGNvbnN0cmFpbnQNCmZ1bGxfaW52ZXN0IDwtIExfY29uc3RyYWludCggcmVwKDEsIG5jb2woVVMzMCkpLCAiPT0iLCAxICkgIyAgbGluZWFyIGNvbnN0cmFpbnQgZm9yIHN0b2NrIHNoYXJlcw0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICgxLDEsIC4uLiwgMSkgKiAoeDEseDIsLi4uLCB4MzApID09MQ0KIw0KIyMgY3JlYXRlIG9wdGltaXphdGlvbiBwcm9ibGVtIC8gbG9uZy1vbmx5DQojIyANCihvcCA8LSBPUCggb2JqZWN0aXZlID0gb2JqLCBjb25zdHJhaW50cyA9IGZ1bGxfaW52ZXN0ICkpIA0KYGBgDQoNCiMjIyMgU29sdXRpb24NCg0KDQpgYGB7cn0NCg0KIyMgc29sdmUgdGhlIHByb2JsZW0gLSBvbmx5IHdvcmtzIGlmIGEgUVAgc29sdmVyIGlzIHJlZ2lzdGVyZWQNCiMjICANCnJlcyA8LSBST0lfc29sdmUoIG9wICkNCnJlcw0Kc29sIDwtIHNvbHV0aW9uKCByZXMgKQ0KbmFtZXMoIHNvbCApIDwtIGNvbG5hbWVzKCBVUzMwICkNCnJvdW5kKCBzb2xbIHdoaWNoKHNvbCA+IDEvMTBeNikgXSwgMyApICMgb25seSBzaG93IGxhcmdlIHNoYXJlIHN0b2NrLiBOb3QgYWxsIDMwIHhpLg0KYGBgDQoNCg0KDQoNCiMjIyBMUCB3aXRoIGJvdW5kYXJ5DQoNCg0KDQp0aHJlZSBkZWNpc2lvbiB2YXJpYWJsZXM6IHgxLCB4Mg0KDQokJFxiZWdpbnthbGlnbip9IA0KICAgIFx0ZXh0e21pbmltaXplOiB9ICAgeF8xICsgMiogeF8yXFwNClx0ZXh0e3N1YmplY3QgdG86IH0gICAgICB4XzEgKyAgeF8yICAgICAgICYgPSAyIFxcDQogICAgICAgICAgICAgICAgICAgICAgICAgIHhfMSAgICAgICYgPD0gMyBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4XzIgICYgPD0gMw0KDQpcZW5ke2FsaWduKn0kJA0KDQoNCg0KDQoNCmBgYHtyfQ0KDQpscF9vYmogPC0gTF9vYmplY3RpdmUoYygxLCAyKSkgIyAgbGluZWFyIG9iamVjdGl2ZQ0KIGxwX2NvbiA8LSBMX2NvbnN0cmFpbnQoYygxLCAxKSwgZGlyPSI9PSIsIHJocz0yKSAgIyAgbGluZWFyIGNvbnN0cmFpbnQNCiBscF9ib3VuZCA8LSBWX2JvdW5kKHVpPTE6MiwgdWI9YygzLCAzKSkNCiAjdWkgYW4gaW50ZWdlciB2ZWN0b3Igc3BlY2lmeWluZyB0aGUgaW5kaWNlcyBvZiBub24tc3RhbmRhcmQgKGkuZS4sIHZhbHVlcyAhPSBJbmYpIHVwcGVyIGJvdW5kcy4NCiAjIHgxIGFuZCB4MiBib3RoIGhhdmUgdXAgYm91bmQNCiAjIHViIHVwIGJvdW5kDQogbHAgPC0gT1Aob2JqZWN0aXZlPWxwX29iaiwgDQogICAgICAgICAgY29uc3RyYWludHM9bHBfY29uLCANCiAgICAgICAgICBib3VuZHM9bHBfYm91bmQsIA0KICAgICAgICAgIG1heGltdW09RkFMU0UpDQogYm91bmRzKGxwKQ0KbHANCmBgYA0KDQogDQojIyMjIFNvbHV0aW9ucyANCiANCmBgYHtyfQ0KIHggPC0gUk9JX3NvbHZlKGxwKQ0KIHgkb2JqdmFsDQogeCRzb2x1dGlvbg0KYGBgDQoNCiMjIyMgIENoYW5nZSBib3VuZGFyeSANCg0KJCRcYmVnaW57YWxpZ24qfSANCiAgICBcdGV4dHttaW5pbWl6ZTogfSAgIHhfMSArIDIqIHhfMlxcDQpcdGV4dHtzdWJqZWN0IHRvOiB9ICAgICAgeF8xICsgIHhfMiAgICAgICAmID0gMiBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4XzEgICAgICAmIDw9IDEgXFwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeF8yICAmIDw9IDENCg0KXGVuZHthbGlnbip9JCQNCg0KYGBge3J9DQojIGNoYW5nZSBib3VuZGFyeSANCiBib3VuZHMobHApIDwtIFZfYm91bmQodWk9MToyLCB1Yj1jKDEsIDEpKQ0KDQpgYGANCg0KDQojIyMjIFNvbHV0aW9ucyANCg0KYGBge3J9DQogeSA8LSBST0lfc29sdmUobHApDQogeSRvYmp2YWwNCiB5JHNvbHV0aW9uDQpgYGANCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyBPdGhlciBvcHRpbWl6YXRpb24gcGFja2FnZSBpbiBSDQoNCg0KV2UgYWxzbyBjYW4gc29sdmUgb3B0aW1pemF0aW9uIHByb2JsZW0gdXNpbmcgb3RoZXIgcGFja2FnZXMuDQoNCiMjIyBJbnN0YWxsIHBhY2thZ2VzDQoNClVuY29tbWVudCB0aGUgY29kZSBpbiBmb2xsb3cgY2h1bmsgYW5kIGluc3RhbGwgYWxsIHBhY2thZ2VzLg0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKGMoImxwU29sdmUiLCAibHBTb2x2ZUFQSSIpKQ0KI2luc3RhbGwucGFja2FnZXMoYygicXVhZHByb2ciLCAibmxtZSIsIlJnbHBrIikpDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkobHBTb2x2ZSkpDQoNCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShscFNvbHZlQVBJKSkNCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShxdWFkcHJvZykpDQojc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KG5sbWUpKQ0KDQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoUmdscGspKQ0KYGBgDQoNCmFyZ3MoKSBmdW5jdGlvbiB0ZWxscyB1cyBob3cgd2UgY2FuIHVzZSB0aG9zZSBmdW5jdGlvbnMgc3VjaCBhcyBscCwgc29sdmUuUVAsIFJnbHBrX3NvbHZlX0xQDQoNCmBgYHtyfQ0KYXJncyhscCkNCmFyZ3Moc29sdmUuUVApDQphcmdzKFJnbHBrX3NvbHZlX0xQKQ0KI2FyZ3MobmxtaW5iKQ0KI2FyZ3Mob3B0aW0pDQojYXJncyhSY3BsZXgpDQpgYGANCg0KDQojIyMgIExpbmVhciBQcm9ncmFtbWluZyBieSBscHNvbHZlDQoNCkhlcmUgaXMgYSBsaXN0IG9mIHNvbWUga2V5IGZlYXR1cmVzIG9mIGxwX3NvbHZlOg0KDQotIE1peGVkIEludGVnZXIgTGluZWFyIFByb2dyYW1taW5nIChNSUxQKSBzb2x2ZXINCg0KLSBCYXNpY2FsbHkgbm8gbGltaXQgb24gbW9kZWwgc2l6ZQ0KDQotIEl0IGlzIGZyZWUgYW5kIHdpdGggc291cmNlcw0KDQotIFN1cHBvcnRzIEludGVnZXIgdmFyaWFibGVzLCBTZW1pLWNvbnRpbnVvdXMgdmFyaWFibGVzIGFuZCBTcGVjaWFsIE9yZGVyZWQgU2V0cw0KDQoNCiMjIyMgRXhhbXBsZSBieSBscFNvbHZlQVBJDQoNCnN0cmFpZ2h0Zm9yd2FyZA0KDQpJZiB3ZSBoYXZlIDQgZGVjaXNpb24gdmFyaWFibGVzOiB4MSwuLi4sIHg0DQoNCiQkXGJlZ2lue2FsaWduKn0gDQogICAgXHRleHR7bWluaW1pemU6IH0gICB4XzEgKyAzIHhfMiArIDYuMjQgeF8zICsgMC4xIHhfNFxcDQogICAgXHRleHR7c3ViamVjdCB0bzogfSAgICAgNzguMjYgeF8yICsgMi45IHhfNCAgICAgICAmID49IDkyLjMgXFwNCiAgICAgICAgICAgICAgICAgICAgICAgICAwLjIgeF8xICsgIDExLjkxIHhfMyAgICAgICAmIDw9IDE0LjggXFwNCiAgICAgICAgICAgICAgICAgICAgICAgICAxMi42OCB4XzEgKyAwLjA4IHhfMyArIDAuOSB4XzQgJj49IDQgXFwNCiAgICAgICAgICAgICAgICAgICAgICAgIDE4ICA8PSAgeF80ICYgPD0gNDguOTggXFwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeF8xICYgPj0gIDI4LjYgDQpcZW5ke2FsaWduKn0kJA0KDQoNCiMjIyMjIFNldCB1cCBtb2RlbA0KDQpgYGB7cn0NCmxpYnJhcnkobHBTb2x2ZUFQSSkNCiNjcmVhdGUgYW4gZW1wdHkgbW9kZWwNCmxwbW9kZWwgPC0gbWFrZS5scChucm93ID0wLCBuY29sPSA0KSAjIDQgdmFyaWFibGVzLCB3ZSBhcmUgZ29pbmcgdG8gYWRkIG9iamVjdGl2ZSBhbmQgY29uc3RyYWludHMNCiMgbnJvdwk6ICMgYSBub25uZWdhdGl2ZSBpbnRlZ2VyIHZhbHVlIHNwZWNpZnlpbmcgdGhlIG51bWJlciBvZiBjb25zdGFpbnRzIGluIHRoZSBsaW5lYXIgcHJvZ3JhbS4NCiMgbmNvbAk6ICMgYSBub25uZWdhdGl2ZSBpbnRlZ2VyIHZhbHVlIHNwZWNpZnlpbmcgdGhlIG51bWJlciBvZiBkZWNpc2lvbiB2YXJpYWJsZXMgaW4gdGhlIGxpbmVhciBwcm9ncmFtLg0KDQoNCmBgYA0KDQojIyMjIyBTZXR1cCBvYmplY3RpdmUgZnVuY3Rpb24NCg0KYGBge3J9DQojIG9iamVjdDogY3ggDQpzZXQub2JqZm4obHBtb2RlbCwgYygxLCAzLCA2LjI0LCAwLjEpKSAgI+OAgG9iamVjdCBmdW5jdGlvbiwgdmVjdG9yIGMgDQpgYGANCg0KIyMjIyMgQWRkIGNvbnN0cmFpbnRzDQoNCmBgYHtyfQ0KDQojY29uc3RyYWludDogQXgNCmFkZC5jb25zdHJhaW50KGxwbW9kZWwsIGMoMCwgNzguMjYsIDAsIDIuOSksICI+PSIsIDkyLjMpDQphZGQuY29uc3RyYWludChscG1vZGVsLCBjKDAuMjQsIDAsIDExLjMxLCAwKSwgIjw9IiwgMTQuOCkNCmFkZC5jb25zdHJhaW50KGxwbW9kZWwsIGMoMTIuNjgsIDAsIDAuMDgsIDAuOSksICI+PSIsIDQpDQoNCmBgYA0KDQoNCiMjIyMjIFNldCBib3VuZHMNCg0KYGBge3J9DQpzZXQuYm91bmRzKGxwbW9kZWwsIGxvd2VyID0gYygyOC42LCAxOCksIGNvbHVtbnMgPSBjKDEsIDQpKSMgb25seSB4MSwgeDQgaGF2ZSBsb3dlciBib3VuZHMNCnNldC5ib3VuZHMobHBtb2RlbCwgdXBwZXIgPSA0OC45OCwgY29sdW1ucyA9IDQpICMgb25seSB4NCBoYXMgdXBwZXIgYm91bmQNCg0KYGBgDQoNCg0KIyMjIyMgU2V0dXAgbmFtZXMgDQoNClNob3cgbW9kZWwgc2V0dGluZw0KDQpgYGB7cn0NCmxwbW9kZWwNCmBgYA0KDQpOb3QgbmVjZXNzYXJ5DQoNCmBgYHtyfQ0KUm93TmFtZXMgPC0gYygiVEhJU1JPVyIsICJUSEFUUk9XIiwgIkxBU1RST1ciKQ0KQ29sTmFtZXMgPC0gYygiQ09MT05FIiwgIkNPTFRXTyIsICJDT0xUSFJFRSIsICJDT0xGT1VSIikNCmRpbW5hbWVzKGxwbW9kZWwpIDwtIGxpc3QoUm93TmFtZXMsIENvbE5hbWVzKQ0KbHBtb2RlbA0KYGBgDQoNCg0KDQoNCiMjIyMjIFNvbHZlIHRoZSBtb2RlbA0KDQpgYGB7cn0NCnNvbHZlKGxwbW9kZWwpDQoNCmBgYA0KDQoNCg0KIyMjIyMgRXh0cmFjdCBzb2x1dGlvbnMNCg0KDQpgYGB7cn0NCmdldC5vYmplY3RpdmUobHBtb2RlbCkNCiAgIyBbMV0gMzEuNzgyNzYNCiAgIyANCmdldC52YXJpYWJsZXMobHBtb2RlbCkNCiAgIyBbMV0gMjguNjAwMDAgIDAuMDAwMDAgIDAuMDAwMDAgMzEuODI3NTkNCiAgIyANCmdldC5jb25zdHJhaW50cyhscG1vZGVsKSAgI+OAgHNoYXdkb3cgcHJpY2UNCiAgIyBbMV0gIDkyLjMwMDAgICA2Ljg2NDAgMzkxLjI5MjgNCmBgYA0KDQoNCg0KIyMjIyBFeGFtcGxlIGJ5IGxwU29sdmUNCg0KcHJvdmlkZSBhIGxvdCBvZiBpbmZvcm1hdGlvbiBpbmNsdWRpbmcgc2Vuc2l0aXZpdGllcyBhbmFseXNpcy4gDQoNCiQkXGJlZ2lue2FsaWduKn0gDQogICAgXHRleHR7bWF4aW1pemU6IH0gICB4XzEgKyA5IHhfMiArICB4XzMgXFwNCiAgICBcdGV4dHtzdWJqZWN0IHRvOiB9ICAgICB4XzEgKyAyIHhfMiArIDMgeF8zICAgICAgICYgPD0gOSBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgIDMgeF8xICsgMiB4XzIgICsgMiB4XzMgICAgICAgJiA8PSAxNSAgDQpcZW5ke2FsaWduKn0kJA0KDQoNCiMjIyMjIFNldHVwIG9iamVjdGl2ZSBmdW5jdGlvbg0KDQpgYGB7cn0NCmxpYnJhcnkobHBTb2x2ZSkNCiMNCiMgU2V0IHVwIHByb2JsZW06IG1heGltaXplDQojICAgeDEgKyA5IHgyICsgICB4MyBzdWJqZWN0IHRvDQojICAgeDEgKyAyIHgyICsgMyB4MyAgPD0gOQ0KIyAzIHgxICsgMiB4MiArIDIgeDMgPD0gMTUNCiMgIG9iamVjdGl2ZTogY3ggDQptb2RlbF9vYmogPC0gYygxLCA5LCAxKSAgIyBjIHZlY3Rvcg0KYGBgIA0KDQojIyMjIyBTZXR1cCBjb25zdHJhaW50cw0KDQpgYGB7cn0NCm1vZGVsX2NvbiA8LSBtYXRyaXggKGMoMSwgMiwgMywgMywgMiwgMiksIG5yb3c9MiwgYnlyb3c9VFJVRSkgIyBjb25zdHJhaW50czogQXggPD0gYiwgMiBjb250cmFpbnRzDQptb2RlbF9kaXIgPC0gYygiPD0iLCAiPD0iKQ0KbW9kZWxfcmhzIDwtIGMoOSwgMTUpICMgYiB2ZWN0b3INCg0KYGBgDQoNCiMjIyMjIFNvbHZlIHRoZSBtb2RlbA0KDQpgYGB7cn0NCiMNCmxwICgibWF4IiwgbW9kZWxfb2JqLCBtb2RlbF9jb24sIG1vZGVsX2RpciwgbW9kZWxfcmhzKQ0KIyMgIFN1Y2Nlc3M6IHRoZSBvYmplY3RpdmUgZnVuY3Rpb24gaXMgNDAuNQ0KDQpgYGANCg0KDQojIyMjIyBFeHRyYWN0IHNvbHV0aW9ucw0KDQpgYGB7cn0NCg0KbHAgKCJtYXgiLCBtb2RlbF9vYmosIG1vZGVsX2NvbiwgbW9kZWxfZGlyLCBtb2RlbF9yaHMpJHNvbHV0aW9uDQpgYGANCg0KIyMjIyMjICBHZXQgc2Vuc2l0aXZpdGllcw0KDQpgYGB7cn0NCiMgR2V0IHNlbnNpdGl2aXRpZXMNCiMjIA0KIyBSaWdodCBub3cgdGhlIGR1YWwgdmFsdWVzIGZvciB0aGUgY29uc3RyYWludHMgYW5kIHRoZSB2YXJpYWJsZXMgYXJlDQojIGNvbWJpbmVkLCBjb25zdHJhaW50cyBjb21pbmcgZmlyc3QuIFNvIGluIHRoaXMgZXhhbXBsZS4uLg0KIw0KbHAgKCJtYXgiLCBtb2RlbF9vYmosIG1vZGVsX2NvbiwgbW9kZWxfZGlyLCBtb2RlbF9yaHMsIGNvbXB1dGUuc2Vucz1UUlVFKSRkdWFscyAgICAgDQojIyAgWzFdICAgNC41ICAgMC4wICAtMy41ICAgMC4wIC0xMC41DQojDQojIC4uLnRoZSBkdWFscyBvZiB0aGUgY29uc3RyYWludHMgYXJlIDQuNSBhbmQgMCwgDQojIGFuZCBvZiB0aGUgdmFyaWFibGVzLCAtMy41LCAwLjAsIC0xMC41LiAjDQpgYGANCg0KIyMjIyBJbnRlcmdyIFByb2dyYW1taW5nDQoNClByZXZpb3VzIG1vZGVsIHdpdGggY29uc3RyYWludHMgdGhhdCBhbGwgZGVjaXNpb24gdmFyaWFibGVzIGFyZSBpbnRlZ2VyLg0KDQpgYGB7cn0NCiMgUnVuIGFnYWluLCB0aGlzIHRpbWUgcmVxdWlyaW5nIHRoYXQgYWxsIHRocmVlIHZhcmlhYmxlcyBiZSBpbnRlZ2VyDQojDQpscCAoIm1heCIsIG1vZGVsX29iaiwgbW9kZWxfY29uLCBtb2RlbF9kaXIsIG1vZGVsX3JocywgaW50LnZlYz0xOjMpDQojIyAgU3VjY2VzczogdGhlIG9iamVjdGl2ZSBmdW5jdGlvbiBpcyAzNw0KbHAgKCJtYXgiLCBtb2RlbF9vYmosIG1vZGVsX2NvbiwgbW9kZWxfZGlyLCBtb2RlbF9yaHMsIGludC52ZWM9MTozKSRzb2x1dGlvbg0KIyMgIFsxXSAxIDQgMA0KIw0KIyBZb3UgY2FuIGdldCBzZW5zaXRpdml0aWVzIGluIHRoZSBpbnRlZ2VyIGNhc2UsIGJ1dCB0aGV5J3JlIGhhcmRlciB0bw0KIyBpbnRlcnByZXQuDQojDQpscCAoIm1heCIsIG1vZGVsX29iaiwgbW9kZWxfY29uLCBtb2RlbF9kaXIsIG1vZGVsX3JocywgaW50LnZlYz0xOjMsIGNvbXB1dGUuc2Vucz1UUlVFKSRkdWFscw0KIyMgIFsxXSAxIDAgMCA3IDANCiMNCmBgYA0KDQoNCg0KDQojIyMgUXVhZHJhdGljIFByb2dyYW1taW5nIGJ5IHF1YWRwcm9nDQoNCg0Kc29sdmluZyBxdWFkcmF0aWMgcHJvZ3JhbW1pbmcgcHJvYmxlbXMgb2YgdGhlIGZvcm0gDQoNCm1pbihjJyB4ICsgMS8yIHgnIEQgeCkgDQoNCndpdGggdGhlIGNvbnN0cmFpbnRzIEEnIHggPj0gYl8wLg0KDQoNCiQkXGJlZ2lue2FsaWduKn0gDQogICAgXHRleHR7bWluaW1pemU6IH0gICAtIDUgeF8yICsgMS8yICh4XzFeMiArIHhfMl4yICsgeF8zXjIpXFwNClx0ZXh0e3N1YmplY3QgdG86IH0gICAgIC00IHhfMSAtIDMgeF8yICAgICAgICYgPj0gLTggXFwNCiAgICAgICAgICAgICAgICAgICAgICAgICAyIHhfMSArICAgeF8yICAgICAgICYgPj0gMiBcXA0KICAgICAgICAgICAgICAgICAgICAgICAgIC0gMiB4XzIgKyB4XzMgJiA+PSAwDQoNClxlbmR7YWxpZ24qfSQkDQoNCg0KDQpEIGlzIGRpYWduYWwgbWF0aXggLiAxLzIgaXMgY29udmV0aW9uLiANCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShxdWFkcHJvZykNCg0KIyMgQXNzdW1lIHdlIHdhbnQgdG8gbWluaW1pemU6IC0oMCA1IDApICUqJSB4ICsgMS8yIHheVCBEIHgNCiMjIHVuZGVyIHRoZSBjb25zdHJhaW50czogICAgICBBXlQgeCA+PSBiMA0KIyMgICAgICAgICAgMSAwIDANCiMjICAgICAgRCA9IDAgMSAwDQojIyAgICAgICAgICAwIDAgMQ0KIyMgd2l0aCBiMCA9ICgtOCwyLDApXlQNCiMjIGFuZCAgICAgICgtNCAgMiAgMCkgDQojIyAgICAgIEEgPSAoLTMgIDEgLTIpDQojIyAgICAgICAgICAoIDAgIDAgIDEpDQojIyB3ZSBjYW4gdXNlIHNvbHZlLlFQIGFzIGZvbGxvd3M6DQojIw0KRG1hdCAgICAgICA8LSBtYXRyaXgoMCwzLDMpDQpkaWFnKERtYXQpIDwtIDENCmN2ZWMgICAgICAgPC0gYygwLDUsMCkNCkFtYXQgICAgICAgPC0gbWF0cml4KGMoLTQsLTMsMCwyLDEsMCwwLC0yLDEpLDMsMykNCmJ2ZWMgICAgICAgPC0gYygtOCwyLDApDQpzb2x2ZS5RUChEbWF0LGN2ZWMsQW1hdCxidmVjPWJ2ZWMpDQoNCmBgYA0KDQoNCg0KDQoNCiMjIyBGb290YmFsbCBNSVAgYnkgZ2xwaw0KDQoNCg0KVHJ5aW5nIHRvIHBpY2sgdGhlIGJlc3QgcG9zc2libGUgZmFudGFzeSBmb290YmFsbCB0ZWFtIGdpdmVuIGRpZmZlcmVudCBjb25zdHJhaW50cy4gIA0KDQpHb2FsIGlzIHRvIHBpY2sgdGhlIHBsYXllcnMgdGhhdCBtYXhpbWl6ZSB0aGUgc3VtIG9mIHRoZWlyIHByb2plY3RlZCBwb2ludHMuDQoNCkRlY2lzaW9uIHZhcmlhYmxzIGFyZSBiaW5hcnksIDAgb3IgMSBmb3Igb25lIHBsYXllciB0byBwbGF5IGluIHRoaXMgbWF0Y2guDQoNClRoZSBjb25zdHJhaW50cyBhcmU6DQoNCjEpIFRoZSB0ZWFtIG11c3QgaW5jbHVkZToNCg0KICAgIC0gMSBRQg0KICANCiAgICAtIDIgUkJzDQoNCiAgICAtIDIgV1JzDQoNCiAgICAtIDEgVEUNCg0KMikgQSBwbGF5ZXIncyByaXNrIG11c3Qgbm90IGV4Y2VlZCA2DQoNCjMpIFRoZSBzdW0gb2YgdGhlIHBsYXllcnMnIGNvc3RzIG11c3Qgbm90IGV4Y2VlZCAzMDAuIA0KDQoNCg0KbWF4aW1pemUgY3ggIHBvaW50cw0KDQpzdWJqZWN0IEF4IDw9IGINCg0KDQpgYGB7cn0NCiNodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzE1MTQ3Mzk4L29wdGltaXplLXZhbHVlLXdpdGgtbGluZWFyLW9yLW5vbi1saW5lYXItY29uc3RyYWludHMtaW4tcg0KIyBXZSBhcmUgZ29pbmcgdG8gc29sdmU6DQojIG1heGltaXplIGYneCBzdWJqZWN0IHRvIEEqeCA8ZGlyPiBiDQojIHdoZXJlOg0KIyAgIHggaXMgdGhlIHZhcmlhYmxlIHRvIHNvbHZlIGZvcjogYSB2ZWN0b3Igb2YgMCBvciAxOg0KIyAgICAgMSB3aGVuIHRoZSBwbGF5ZXIgaXMgc2VsZWN0ZWQsIDAgb3RoZXJ3aXNlLA0KIyAgIGYgaXMgeW91ciBvYmplY3RpdmUgdmVjdG9yLA0KIyAgIEEgaXMgYSBtYXRyaXgsIGIgYSB2ZWN0b3IsIGFuZCA8ZGlyPiBhIHZlY3RvciBvZiAiPD0iLCAiPT0iLCBvciAiPj0iLA0KIyAgIGRlZmluaW5nIHlvdXIgbGluZWFyIGNvbnN0cmFpbnRzLg0KDQoj44CAcGxheWVyJ3MgbmFtZXMNCm5hbWUgPC0gYygiQWFyb24gUm9kZ2VycyIsIlRvbSBCcmFkeSIsIkFyaWFuIEZvc3RlciIsIlJheSBSaWNlIiwiTGVTZWFuIE1jQ295IiwiQ2FsdmluIEpvaG5zb24iLCJMYXJyeSBGaXR6Z2VyYWxkIiwiV2VzIFdlbGtlciIsIlJvYiBHcm9ua293c2tpIiwiSmltbXkgR3JhaGFtIikNCiMgcGxheWVycycgcG9zaXRpb24gaW4gdGhlIGdhbWUNCnBvcyA8LSBjKCJRQiIsIlFCIiwiUkIiLCJSQiIsIlJCIiwiV1IiLCJXUiIsIldSIiwiVEUiLCJURSIpDQojIHBsYXllcnMnIHBvaW50cw0KcHRzIDwtIGMoMTY3LCAxMzYsIDE5NSwgMTc0LCAxNDQsIDEzNSwgODksIDgxLCAxMTQsIDExMSkgDQojIHBsYXllcnMnIHJpc2sNCnJpc2sgPC0gYygyLjksIDMuNCwgMC43LCAxLjEsIDMuNSwgNS4wLCA2LjcsIDQuNywgMy43LCA4LjgpIA0KIyBwbGF5ZXJzJyBjb3N0DQpjb3N0IDwtIGMoNjAsIDQ3LCA2MywgNjIsIDQwLCA2MCwgNTAsIDM1LCA0MCwgNDApIA0KI215ZGF0YSA8LSBkYXRhLmZyYW1lKG5hbWUsIHBvcywgcHRzLCByaXNrLCBjb3N0KSANCg0KIyBudW1iZXIgb2YgdmFyaWFibGVzDQpudW0ucGxheWVycyA8LSBsZW5ndGgobmFtZSkNCiMgb2JqZWN0aXZlOg0KZiA8LSBwdHMNCiMgdGhlIHZhcmlhYmxlIGFyZSBib29sZWFucw0KdmFyLnR5cGVzIDwtIHJlcCgiQiIsIG51bS5wbGF5ZXJzKQ0KIyB0aGUgY29uc3RyYWludHMNCkEgPC0gcmJpbmQoYXMubnVtZXJpYyhwb3MgPT0gIlFCIiksICMgbnVtIFFCICAjIFRSVUUgIFRSVUUgRkFMU0UgRkFMU0UgRkFMU0UgRkFMU0UgRkFMU0UgRkFMU0UgRkFMU0UgRkFMU0UgdG8gMSAxIC4uLiAwIDAgDQogICAgICAgICAgIGFzLm51bWVyaWMocG9zID09ICJSQiIpLCAjIG51bSBSQiAgIyBGQUxTRSBGQUxTRSAgVFJVRSAgVFJVRSAgVFJVRSBGQUxTRSBGQUxTRSBGQUxTRSBGQUxTRSBGQUxTRSB0byAwIDEgLi4uIDAgMA0KICAgICAgICAgICBhcy5udW1lcmljKHBvcyA9PSAiV1IiKSwgIyBudW0gV1IgICMgRkFMU0UgRkFMU0UgRkFMU0UgRkFMU0UgRkFMU0UgIFRSVUUgIFRSVUUgIFRSVUUgRkFMU0UgRkFMU0UgdG8gMCAwIC4uLiAwIDANCiAgICAgICAgICAgYXMubnVtZXJpYyhwb3MgPT0gIlRFIiksICMgbnVtIFRFICAjIEZBTFNFIEZBTFNFIEZBTFNFIEZBTFNFIEZBTFNFIEZBTFNFIEZBTFNFIEZBTFNFICBUUlVFICBUUlVFIHRvIDAgMCAuLi4gMSAxDQogICAgICAgICAgIGRpYWcocmlzayksICAgICAgICAgICAgICAjIHBsYXllcidzIHJpc2ssIGEgc2V0IG9mIG11bHRpcGxlIGNvbnN0cmFpbnRzDQogICAgICAgICAgIGNvc3QpICAgICAgICAgICAgICAgICAgICAjIHRvdGFsIGNvc3QNCg0KIyBkaXJldGlvbg0KZGlyIDwtIGMoIj09IiwNCiAgICAgICAgICI9PSIsDQogICAgICAgICAiPT0iLA0KICAgICAgICAgIj09IiwNCiAgICAgICAgIHJlcCgiPD0iLCBudW0ucGxheWVycyksDQogICAgICAgICAiPD0iKQ0KDQojIHJocyBiIHZlY3Rvcg0KYiA8LSBjKDEsDQogICAgICAgMiwNCiAgICAgICAyLA0KICAgICAgIDEsDQogICAgICAgcmVwKDYsIG51bS5wbGF5ZXJzKSwNCiAgICAgICAzMDApDQoNCg0KDQpgYGANCg0KDQoNCiMjIyMgU29sdmUgdGhlIG1vZGVsIHdpdGggZ2xwaw0KDQpgYGB7cn0NCiMgc29sdmUNCmxpYnJhcnkoUmdscGspDQpzb2wgPC0gUmdscGtfc29sdmVfTFAob2JqID0gZiwgDQogICAgICAgICAgICAgICAgICAgICAgbWF0ID0gQSwgDQogICAgICAgICAgICAgICAgICAgICAgZGlyID0gZGlyLCANCiAgICAgICAgICAgICAgICAgICAgICByaHMgPSBiLA0KICAgICAgICAgICAgICAgICAgICAgIHR5cGVzID0gdmFyLnR5cGVzLCANCiAgICAgICAgICAgICAgICAgICAgICBtYXggPSBUUlVFKQ0Kc29sDQojICRvcHRpbXVtDQojIFsxXSA4MzYgICAgICAgICAgICAgICAgICAgICAgIyMjIDwtIHRoZSBvcHRpbWFsIHRvdGFsIHBvaW50cw0KIyAkc29sdXRpb24NCiMgIFsxXSAxIDAgMSAwIDEgMSAwIDEgMSAwICAgICAjIyMgPC0gYSBgMWAgZm9yIHRoZSBzZWxlY3RlZCBwbGF5ZXJzDQojICRzdGF0dXMNCiMgWzFdIDAgICAgICAgICAgICAgICAgICAgICAgICAjIyMgPC0gYW4gb3B0aW1hbCBzb2x1dGlvbiBoYXMgYmVlbiBmb3VuZA0KIyB5b3VyIGRyZWFtIHRlYW0NCm5hbWVbc29sJHNvbHV0aW9uID09IDFdDQojIFsxXSAiQWFyb24gUm9kZ2VycyIgICJBcmlhbiBGb3N0ZXIiICAgIkxlU2VhbiBNY0NveSINCiMgWzRdICJDYWx2aW4gSm9obnNvbiIgIldlcyBXZWxrZXIiICAgICAiUm9iIEdyb25rb3dza2kNCiMgdG90YWwgY29zdA0Kc3VtKGNvc3QgKiBzb2wkc29sdXRpb24pDQpgYGANCg0KIyMgU29sdmUgaXQgdXNpbmcgUk9JIA0KDQoNCmBgYHtyfQ0KZm9vdGJhbGwgPC0gT1AoIGYsICMgb2JqZWN0aXZlIGZ1bmN0aW9uLCB2ZWN0b3IgYw0KICAgICAgICAgIExfY29uc3RyYWludChMID0gQSwgIyBsaW5lYXIgY29uc3RyYWludDogTWF4dHJpeCBBDQogICAgICAgICAgZGlyID0gZGlyLCAgIyBkaXJlY3Rpb24NCiAgICAgICAgICByaHMgPSBiKSwgIyByaWdodCBoYW5kIHNpZGU6IHZlY3RvciBiIA0KICAgICAgICAgIHR5cGVzID0gdmFyLnR5cGVzLCAgDQogICAgICAgICAgbWF4ID0gVFJVRSkNCmZvb3RiYWxsDQpgYGANCg0KIyMjIyBTb2x2ZQ0KDQpgYGB7cn0NCnNvbCA8LSBST0lfc29sdmUoZm9vdGJhbGwpIyAsIHNvbHZlciA9ICJnbHBrIikgICMgU29sdmUgbW9kZWwgTFAgd2l0aCBzcGVjaWZpYyBzb2x2ZXIgZ2xwayBvciBhdXRvbWF0aWNhbGx5IGNob29zZSBieSBST0kuDQpzb2wNCmBgYA0KDQojIyMjIFNvbHV0aW9ucw0KDQpgYGB7cn0NCnNvbHV0aW9uKHNvbCwgdHlwZSA9IGMoInByaW1hbCIpKSAjIHNvbHV0aW9uIGZvciBwcmltYWwgcHJvYmxlbQ0KYGBgDQoNCg0KIyMjIyBFeHRyYWN0IHNvbHV0aW9ucw0KYGBge3J9DQpzb2wkc29sdXRpb24NCnNvbCRvYmp2YWwNCnNvbCRzdGF0dXMNCnNvbCRtZXNzYWdlICMgZGV0YWlsZWQgbWVzc2FnZSBmb3Igc29sdXRpb24gDQpgYGANCg==