1 Bisection Method

The bisection method is another approach to finding the root of a continuous function \(f(x)\) on an interval \([a,b]\). The method takes advantage of a corollary of the intermediate value theorem called Bolzano’s theorem which states that if the values of \(f(a)\) and \(f(b)\) have opposite signs, the interval must contain at least one root. The iteration steps of the bisection method are relatively straightforward, however; convergence towards a solution is slow compared to other root-finding methods.

1.1 Mathematical Formula

The Bisection Mathematical formula is \[c = \frac {(a+b)}{2}\]

1.2 The Bisection Algorithm

The bisection algorithm is a simple method for finding the roots of one-dimensional functions. The goal is to find a root \(x_0∈[a,b]\) such that \(f(x_0)=0\). The algorithm starts with a large interval, known to contain \(x_0\) and then successively reduces the size of the interval until it brackets the root.

So, we can present the bisection algorithm. First, we must check that \(sign(f(a))≠sign(f(b))\). Otherwise, the interval does not contain the root and might need to be widened. Then we can proceed:

  • Let \(c = \frac {(a+b)}{2}\)

  • If \(f(c)=0\), stop and return \(c\)

  • If \(sign(f(a))≠sign(f(c))\), then set \(b←c\). Else if \(sign(f(b))≠sign(f(c))\), then set \(a←c\).

  • Goto the beginning and repeat until convergence.

After \(n\) iterations, the size of the interval bracketing the root will be \(2^{-n}(b-a)\).

1.3 Bisection Algorithm in R

Suppose we want to find the root of the function \(x^3−2x−5\). It is often valuable to plot the function to find an interval containing the root.

1.3.1 Visualize the function

As we can see from the visualization above, we know that the root appears to lie close in 2. Next, we will use the interval [2,3] in Bisection Method.

1.3.2 Use NLRoot packages

On of the most usefull package for the Bisection Method in R is the NLRoot package, here you will apply BFfzero() to find the solution, as you can see below:

## [1] 1
## [1] 2.094553
## [1] 1.262094e-05
## [1] "finding root is successful"

The output of the function shows the root is located at \(x=2.094553\), which matches the results found in previous examples on other root finding methods such as the Newton-Raphson method and Secant method.

2 Newton’s Method

The Newton-Raphson method is a method for approximating the roots of polynomial equations of any order. In fact the method works for any equation, polynomial or not, as long as the function is differentiable in a desired interval. ’s often become increasingly better approximations of the function’s root. Newton’s method usually use for solving equations is another numerical method for solving an equation \(f(x)=0\). It is based on the geometry of a curve, using the tangent lines to a curve. As such, it requires calculus, in particular differentiation. Roughly, the idea of Newton’s method is as follows.

2.1 Mathematical Formula

Newton’s method build a sequence of values \(\brace x_n\) via functional iteration that converges to the root of a function \(f\). The mathematical formula is \[x_{n+1} = x_n - \frac {f(x_n)}{f'(x_n)}\]

2.2 The Newton’s Algorithm

The Newton’s algorithm is a commonly used technique for locating zeros of a function. This the present of newton’s algorithm :

  • Find \(f(x_n)\) and \(f'(x-n)\) \[x_{n+1} = x_n - \frac {f(x_n)}{f'(x_n)}\]

  • If \(f(x_{n+1})=0\) then \(x_n\) is an exact root, else \(x_{n+1}=x_n\)

  • Repeat that until \(f(x_{n+1})=0\) or \(|f(x_{n+1})|\) \(\leq\) accuracy

2.3 Newton’s Method in R

Suppose we want to find the root of the function \(f(x)=x^2−9 \text{ for, } x>0\). We assume that \(f\) is smooth (differentiable). Our goal is to find a root of \(f\) i.e a \(x\) value for which \(f(x)=0\). We illustrate the method with a simple example for which you know the root.

2.3.1 Visualize the function

##       x         f
## 1 0.100 -8.990000
## 2 0.199 -8.960399
## 3 0.298 -8.911196
## 4 0.397 -8.842391
## 5 0.496 -8.753984
## 6 0.595 -8.645975

By considering the visualization above, it’s looks like the function is 0 around 3. How do we know that exactly correct, let’s try zoom the visualization.

Next, let us visualize this to find the root of our function \(f(x)=x^2−9.\) First we need to create a function that returns the tangent line to the function f at some point a.

Then, plot the tangent line to the initial value \(f\) at \(x(0)=4\) which will be our first guess of the root.

Next, let us zoom in on \(2≤x≤4\) and try to see where the tangent line is equal to 0.

By considering the visualization above, looks like the tangent line is 0 around 3.1. This will be our updated guess at the root. Understand the rationale behind this. If f is approximately equal to its tangent line at 4, then the root of \(f\) is approximately equal to the root of the tangent line. Can you see this in the plot above?

The exact value when the tangent line is 0 is given by

\[ x^{(1)}=4−{f(4) \over f′(4)} =3.125\]

Then, add the tangent line at 3.125 to our data frame

Now let us zoom in on around 3 and try to see where the tangent line is equal to 0.

Looks like the tangent line is 0 around 3. In just two steps we are very close. This will be our updated guess at the root. The exact value when the tangent line is 0 is given by

\[ x^{(2)}=x^{(1)}−{f(x^{(1)}) \over f′(x^{(1)})}\] \[ x^{(2)}=3.125−{f(3.125) \over f′(3.125)} = 3.0025\]

We can continue until our guesses keep getting smaller and smaller.

2.3.2 Use NLRoot packages

The same packages as we use to the Bisection Method, this packages also available for Newton’s method.

## [1] 3
## [1] 1.081801e-12
## [1] "finding root is successful"

3 Case Study

3.1 Model Building

In this lesson we will construct two functions that you will need for this course and begin to explore the R programming language. Run through the Chapter 1 of the book which talks about model building for a one-variable optimization problem. Example 1.1 (Meerschaert) A pig weighing 200 lbs gains 5 lbs per day and costs 45 cents per day to keep (feed and board). The market price for pigs is 65 cents per pound, but is falling 1 cent per day. When should the pig be sold?

3.1.1 Modeling the Problem

Variables :

  • \(t\) = time (days)

  • \(w\) = weight of the pig(lbs)

  • \(p\) = price for pigs ($/lb)

  • \(C\) = cost of keeping pig t days ($)

  • \(R\) = revenue obtained by selling pig ($)

  • \(P\) = profit from selling pig ($)

Assumptions:

  • \(w = 200 + 5t\)

  • \(p = 0.65 − 0.01t\)

  • \(C = 0.45t\)

  • \(R = p⋅w\)

  • \(P = R − C\)

  • \(t \geq 0\)

Objective: Maximize profits from the sell of the pig

Let x be the time to sell the pig and develop the profit function using x as the independent variable. In the case of an optimization, the variable on which you will make a decision on is generally called a decision variable. There can be multiple decision variables in a problem.

3.1.2 Profit Function = Objective function

Given the description and mathematical explanation of the variables, lets write out the profit function:

\[profit(x) = \underbrace {(0.65-0.01x)}_{\text {price of the pig on day x}} \overbrace {(200+5x)}^{\text{weight of the pig on day x}} - \underbrace {(0.45x)}_{\text {cost of keeping pig x day}}\]

Lets use R to “see” what the profit function looks like over the next 20 days.

## [1] 133.2

As you can see, there is a good and bad day to sell the pig if our assumptions remain the same over the next 20 days. Although we could use this graph in order to select the “winner”, we want to be able to use this tool (R programming language) to assist us in ensuring that we have all of the information needed to make a decision. That means that we need to get our hands dirty and figure out how to use our tools (in this case, R).

3.2 Build the functions that we need to solve the problem

We will create two functions that will be able to solve for an optimal point in R using mathematics / programming that we already know how to do. From calculus, you should remember the definition of the derivative and why tweaking it a little can get us a better estimation of the derivative of a function:

\[f'(x)={\frac{f(x+h)-f(x-h)}{2h}}\]

Using this simple formula, let’s build a derivative of the profit function that we defined above. Notice how our function fprime\((f,x)\) will work for ANY function that we assign to it.

3.3 Root-Finding Solver

Although we could use the graph above to find the solution for this particular problem, it is more appropriate to use math to make our solution automatic. There are many root-finding algorithms out there and feel free to use another, but we will use a simple algorithm known as the bisection method. This method only requires that you select two points that have opposite signs: if \(f(a)= −\) then \(f(b) = +\).

3.4 Bisection Algorithm for finding the root of an equation

The simple idea of the bisection method is that you start with an interval \([a,b]\) that has a positive and negative value for the function \(f(a)\) and \(f(b)\) - it does not matter which one is positive. You cut the interval in half and proceed with the interval that keeps one side positive and the other negative. In Figure 1, we start on the interval \([2,9]\) which works because \(f(2)\) is positive and \(f(9)\) is negative. The first step cuts the interval in half and the decision must be made to continue with \([2,5.5]\) or \([5.5,9]\). It should be pretty obvous from the picture that \([2,5.5]\) is the right answer (we want to keep a root in the interval), but from an algorithm perspective, we simply test \(f(5.5)\) and find out that it is negative which causes us to replace 9 \((f[9]\) was negative) with 5.5. We would continue this algorithm until we are satisfied that the width of the interval is small enough to make a conclusion about the value of the root.

Figure 1: Bisection Example

## [1] 1.709967

3.5 Use our tool to solve the pig problem

Use the tools at your disposal to solve the problem. Be able to make several alternatives to the proposed model and investigate the relationship between multiple variables. When do we sell the pig?

## [1] 8.000488

As you can see, we got approximately the same answer as the book. The difference is that our solution uses an estimation of the derivative instead of the closed-form solution as well as a solver for finding the day \(x\) where the profit is maximized (profit function derivative = 0). In the case of most problems, you will use numerical methods (like we did) because real world problems do not ususally have a easy answer. To become a good problem solver, you are going to need to invest in your coding abilities because you will usually need to develop some original code to help you solve a particular problem.

3.6 Sensitivity Analysis: Price of the Pig

Let’s go back and examine more closely one of our original assumptions that may or may not hold to see how our solution is afftected by a different assumption. Does the optimal day to sell change if we assume some different price of the pig. Here we let the pig price drop to recreate the numbers in the book, but we are able to do so much more which will be demonstrated in the next analysis.

## [1] 15.000000 11.110840  8.000488  5.454102  3.332520

3.7 Sensitivity Analysis: Growth Rate of the Pig

Since we are also concerned about the growth rate of the pig, let’s conduct see how the days to sell are affected by the growth rate. The weight (w) is calculated using the assumption that the pig will grow 5lbs per day so that: \(w = 200 + gt\) where \(g = 5\). Let’s see what happens if \(g\) is between 3 and 7. Remember the bisection method needs two boundary points that have the opposite values and if the growth rate is too small, think about what that does to the profit. Experiment with large and small growth rates and the profit function to figure it out for yourself if you don’t see it. We needed to make the starting point of the bisection method to the left (negative number) in order for it to find the zero for 3lbs and 3.5lbs per day.

##  [1] -90.002441 -49.169922 -28.749084 -16.499329  -8.332825  -2.500916
##  [7]   1.875305   5.278778   8.000183  10.227203  12.083435  13.653564
## [13]  14.999390  16.166687  17.187500  18.088150  18.889236  19.605637
## [19]  20.249939  20.833588  21.363449  21.847534  22.291565

LS0tDQp0aXRsZTogIkxhYjQ6IFNvbHZpbmcgTm9ubGluZWFyIEVxdWF0aW9ucyINCmF1dGhvcjogIkVsdnJpYW5hIEVsdmFuaSAoMjAxODQ5MjAwMTIpIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge3IgTG9nbywgZWNobz1GQUxTRSxmaWcuYWxpZ249J2NlbnRlcicsIG91dC53aWR0aCA9ICc0MCUnfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vZ2l0aHViLmNvbS9CYWt0aS1TaXJlZ2FyL2ltYWdlcy9ibG9iL21hc3Rlci9sb2dvLnBuZz9yYXc9dHJ1ZSIpDQpgYGANCg0KIyBCaXNlY3Rpb24gTWV0aG9kDQoNClRoZSBiaXNlY3Rpb24gbWV0aG9kIGlzIGFub3RoZXIgYXBwcm9hY2ggdG8gZmluZGluZyB0aGUgcm9vdCBvZiBhIGNvbnRpbnVvdXMgZnVuY3Rpb24gJGYoeCkkIG9uIGFuIGludGVydmFsICRbYSxiXSQuIFRoZSBtZXRob2QgdGFrZXMgYWR2YW50YWdlIG9mIGEgY29yb2xsYXJ5IG9mIHRoZSBpbnRlcm1lZGlhdGUgdmFsdWUgdGhlb3JlbSBjYWxsZWQgQm9semFub+KAmXMgdGhlb3JlbSB3aGljaCBzdGF0ZXMgdGhhdCBpZiB0aGUgdmFsdWVzIG9mICRmKGEpJCBhbmQgJGYoYikkIGhhdmUgb3Bwb3NpdGUgc2lnbnMsIHRoZSBpbnRlcnZhbCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIHJvb3QuIFRoZSBpdGVyYXRpb24gc3RlcHMgb2YgdGhlIGJpc2VjdGlvbiBtZXRob2QgYXJlIHJlbGF0aXZlbHkgc3RyYWlnaHRmb3J3YXJkLCBob3dldmVyOyBjb252ZXJnZW5jZSB0b3dhcmRzIGEgc29sdXRpb24gaXMgc2xvdyBjb21wYXJlZCB0byBvdGhlciByb290LWZpbmRpbmcgbWV0aG9kcy4NCg0KDQojIyBNYXRoZW1hdGljYWwgRm9ybXVsYQ0KDQpUaGUgQmlzZWN0aW9uIE1hdGhlbWF0aWNhbCBmb3JtdWxhIGlzICQkYyA9IFxmcmFjIHsoYStiKX17Mn0kJA0KDQojIyBUaGUgQmlzZWN0aW9uIEFsZ29yaXRobQ0KDQpUaGUgYmlzZWN0aW9uIGFsZ29yaXRobSBpcyBhIHNpbXBsZSBtZXRob2QgZm9yIGZpbmRpbmcgdGhlIHJvb3RzIG9mIG9uZS1kaW1lbnNpb25hbCBmdW5jdGlvbnMuIFRoZSBnb2FsIGlzIHRvIGZpbmQgYSByb290ICR4XzDiiIhbYSxiXSQgc3VjaCB0aGF0ICRmKHhfMCk9MCQuIFRoZSBhbGdvcml0aG0gc3RhcnRzIHdpdGggYSBsYXJnZSBpbnRlcnZhbCwga25vd24gdG8gY29udGFpbiAkeF8wJCBhbmQgdGhlbiBzdWNjZXNzaXZlbHkgcmVkdWNlcyB0aGUgc2l6ZSBvZiB0aGUgaW50ZXJ2YWwgdW50aWwgaXQgYnJhY2tldHMgdGhlIHJvb3QuDQoNClNvLCB3ZSBjYW4gcHJlc2VudCB0aGUgYmlzZWN0aW9uIGFsZ29yaXRobS4gRmlyc3QsIHdlIG11c3QgY2hlY2sgdGhhdCAkc2lnbihmKGEpKeKJoHNpZ24oZihiKSkkLiBPdGhlcndpc2UsIHRoZSBpbnRlcnZhbCBkb2VzIG5vdCBjb250YWluIHRoZSByb290IGFuZCBtaWdodCBuZWVkIHRvIGJlIHdpZGVuZWQuIFRoZW4gd2UgY2FuIHByb2NlZWQ6DQoNCiogTGV0ICRjID0gXGZyYWMgeyhhK2IpfXsyfSQNCg0KKiBJZiAkZihjKT0wJCwgc3RvcCBhbmQgcmV0dXJuICRjJA0KDQoqIElmICRzaWduKGYoYSkp4omgc2lnbihmKGMpKSQsIHRoZW4gc2V0ICRi4oaQYyQuIEVsc2UgaWYgJHNpZ24oZihiKSniiaBzaWduKGYoYykpJCwgdGhlbiBzZXQgJGHihpBjJC4NCg0KKiBHb3RvIHRoZSBiZWdpbm5pbmcgYW5kIHJlcGVhdCB1bnRpbCBjb252ZXJnZW5jZS4NCg0KQWZ0ZXIgJG4kIGl0ZXJhdGlvbnMsIHRoZSBzaXplIG9mIHRoZSBpbnRlcnZhbCBicmFja2V0aW5nIHRoZSByb290IHdpbGwgYmUgJDJeey1ufShiLWEpJC4NCg0KIyMgQmlzZWN0aW9uIEFsZ29yaXRobSBpbiBSDQoNClN1cHBvc2Ugd2Ugd2FudCB0byBmaW5kIHRoZSByb290IG9mIHRoZSBmdW5jdGlvbiAkeF4z4oiSMnjiiJI1JC4gSXQgaXMgb2Z0ZW4gdmFsdWFibGUgdG8gcGxvdCB0aGUgZnVuY3Rpb24gdG8gZmluZCBhbiBpbnRlcnZhbCBjb250YWluaW5nIHRoZSByb290Lg0KDQojIyMgVmlzdWFsaXplIHRoZSBmdW5jdGlvbg0KDQpgYGB7cn0NCmZ1bmMgPC0gZnVuY3Rpb24oeCkgew0KICB4XjMgLSAyICogeCAtIDUNCn0NCg0KY3VydmUoZnVuYywgeGxpbT1jKC0zLDMpLCBjb2w9J2JsdWUnLCBsd2Q9MS41LCBsdHk9MikNCmFibGluZShoPTApDQphYmxpbmUodj0wKQ0KYGBgDQoNCkFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgdmlzdWFsaXphdGlvbiBhYm92ZSwgd2Uga25vdyB0aGF0IHRoZSByb290IGFwcGVhcnMgdG8gbGllIGNsb3NlIGluIDIuIE5leHQsIHdlIHdpbGwgdXNlIHRoZSBpbnRlcnZhbCBbMiwzXSBpbiBCaXNlY3Rpb24gTWV0aG9kLg0KDQojIyMgVXNlIGBOTFJvb3RgIHBhY2thZ2VzDQoNCk9uIG9mIHRoZSBtb3N0IHVzZWZ1bGwgcGFja2FnZSBmb3IgdGhlIEJpc2VjdGlvbiBNZXRob2QgaW4gUiBpcyB0aGUgYE5MUm9vdGAgcGFja2FnZSwgaGVyZSB5b3Ugd2lsbCBhcHBseSBgQkZmemVybygpYCB0byBmaW5kIHRoZSBzb2x1dGlvbiwgYXMgeW91IGNhbiBzZWUgYmVsb3c6DQoNCmBgYHtyfQ0KbGlicmFyeShOTFJvb3QpICAgICAgICAgICAgICAjIGxvYWRpbmcgdGhlIHBhY2thZ2UgDQpCRmZ6ZXJvKGZ1bmMsIDIsIDMpICAgICAgICAgICMgdG8gZmluZCB0aGUgc29sdXRpb24gKGp1c3QgYXMgc2ltcGxlIGxpa2UgdGhpcykNCmBgYA0KDQpUaGUgb3V0cHV0IG9mIHRoZSBmdW5jdGlvbiBzaG93cyB0aGUgcm9vdCBpcyBsb2NhdGVkIGF0ICR4PTIuMDk0NTUzJCwgd2hpY2ggbWF0Y2hlcyB0aGUgcmVzdWx0cyBmb3VuZCBpbiBwcmV2aW91cyBleGFtcGxlcyBvbiBvdGhlciByb290IGZpbmRpbmcgbWV0aG9kcyBzdWNoIGFzIHRoZSBOZXd0b24tUmFwaHNvbiBtZXRob2QgYW5kIFNlY2FudCBtZXRob2QuDQoNCg0KIyMjIFdyaXRlIEZ1bmN0aW9uDQoNCldlIGNhbiBhbHNvIHdyaXRlIGEgZnVuY3Rpb24gdGhhdCBpbXBsZW1lbnRzIHRoZSBiaXNlY3Rpb24gbWV0aG9kIHVzaW5nIHRoZSBpdGVyYXRpb24gc3RlcHMgZGV0YWlsZWQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgcG9zdC4NCg0KYGBge3J9DQpCYWt0aV9CaXNlY3Rpb24gPC0gZnVuY3Rpb24oZiwgYSwgYiwgbiA9IDEwMDAsIHRvbCA9IDFlLTcpIHsNCiAgIyBJZiB0aGUgc2lnbnMgb2YgdGhlIGZ1bmN0aW9uIGF0IHRoZSBldmFsdWF0ZWQgcG9pbnRzLCBhIGFuZCBiLCBzdG9wIHRoZSBmdW5jdGlvbiBhbmQgcmV0dXJuIG1lc3NhZ2UuDQogIGlmICghKGYoYSkgPCAwKSAmJiAoZihiKSA+IDApKSB7DQogICAgc3RvcCgnc2lnbnMgb2YgZihhKSBhbmQgZihiKSBkaWZmZXInKQ0KICB9IGVsc2UgaWYgKChmKGEpID4gMCkgJiYgKGYoYikgPCAwKSkgew0KICAgIHN0b3AoJ3NpZ25zIG9mIGYoYSkgYW5kIGYoYikgZGlmZmVyJykNCiAgfQ0KICANCiAgZm9yIChpIGluIDE6bikgew0KICAgIGMgPC0gKGEgKyBiKSAvIDIgIyBDYWxjdWxhdGUgbWlkcG9pbnQNCiAgICANCiAgICAjIElmIHRoZSBmdW5jdGlvbiBlcXVhbHMgMCBhdCB0aGUgbWlkcG9pbnQgb3IgdGhlIG1pZHBvaW50IGlzIGJlbG93IHRoZSBkZXNpcmVkIHRvbGVyYW5jZSwgc3RvcCB0aGUgDQogICAgIyBmdW5jdGlvbiBhbmQgcmV0dXJuIHRoZSByb290Lg0KICAgIGlmICgoZihjKSA9PSAwKSB8fCAoKGIgLSBhKSAvIDIpIDwgdG9sKSB7DQogICAgICByZXR1cm4oYykNCiAgICB9DQogICAgDQogICAgIyBJZiBhbm90aGVyIGl0ZXJhdGlvbiBpcyByZXF1aXJlZCwgDQogICAgIyBjaGVjayB0aGUgc2lnbnMgb2YgdGhlIGZ1bmN0aW9uIGF0IHRoZSBwb2ludHMgYyBhbmQgYSBhbmQgcmVhc3NpZ24NCiAgICAjIGEgb3IgYiBhY2NvcmRpbmdseSBhcyB0aGUgbWlkcG9pbnQgdG8gYmUgdXNlZCBpbiB0aGUgbmV4dCBpdGVyYXRpb24uDQogICAgaWZlbHNlKHNpZ24oZihjKSkgPT0gc2lnbihmKGEpKSwgDQogICAgICAgICAgIGEgPC0gYywNCiAgICAgICAgICAgYiA8LSBjKQ0KICB9DQogICMgSWYgdGhlIG1heCBudW1iZXIgb2YgaXRlcmF0aW9ucyBpcyByZWFjaGVkIGFuZCBubyByb290IGhhcyBiZWVuIGZvdW5kLCANCiAgIyByZXR1cm4gbWVzc2FnZSBhbmQgZW5kIGZ1bmN0aW9uLg0KICBwcmludCgnVG9vIG1hbnkgaXRlcmF0aW9ucycpDQp9DQpgYGANCg0KTm93LCB3ZSBjYW4gYXBwbHkgb3VyIGZ1bmN0aW9uIGZpbmQgdGhlIHJvb3Qgb2YgdGhlIGZ1bmN0aW9uICR4XjPiiJIyeOKIkjUkIGFzIHdlIGhhdmUgZG9uZSBhYm92ZSBieSB1c2luZyBgTkxSb290YCBwYWNrYWdlcy4gDQoNCmBgYHtyfQ0KQmFrdGlfQmlzZWN0aW9uKGZ1bmMsIDIsIDMpDQpgYGANCiMjIyBZb3VyIE93biBGdW5jdGlvbg0KDQpgYGB7cn0NCm93biA8LSBmdW5jdGlvbih4KSB7DQogIHheMyAtIDQgKiB4IC0gMg0KfQ0KDQpjdXJ2ZShvd24sIHhsaW09YygtMywzKSwgY29sPSdncmVlbicsIGx3ZD0xLjUsIGx0eT0yKQ0KYWJsaW5lKGg9MCkNCmFibGluZSh2PTApDQoNCg0KbGlicmFyeShOTFJvb3QpICAgICAgICAgICAgICANCkJGZnplcm8ob3duLCAyLCAzKSANCg0KDQp2X0Jpc2VjdGlvbiA8LSBmdW5jdGlvbihmLCBhLCBiLCBuID0gMTAwMDAsIHRvbCA9IDFlLTkpIHsNCiAgaWYgKCEoZihhKSA8IDApICYmIChmKGIpID4gMCkpIHsNCiAgICBzdG9wKCdzaWducyBvZiBmKGEpIGFuZCBmKGIpIGRpZmZlcicpDQogIH0gZWxzZSBpZiAoKGYoYSkgPiAwKSAmJiAoZihiKSA8IDApKSB7DQogICAgc3RvcCgnc2lnbnMgb2YgZihhKSBhbmQgZihiKSBkaWZmZXInKQ0KICB9DQogIA0KICBmb3IgKGkgaW4gMTpuKSB7DQogICAgYyA8LSAoYSArIGIpIC8gMiANCiAgICANCiAgICBpZiAoKGYoYykgPT0gMCkgfHwgKChiIC0gYSkgLyAyKSA8IHRvbCkgew0KICAgICAgcmV0dXJuKGMpDQogICAgfQ0KICAgIA0KICBpZmVsc2Uoc2lnbihmKGMpKSA9PSBzaWduKGYoYSkpLCANCiAgICAgICAgICAgYSA8LSBjLA0KICAgICAgICAgICBiIDwtIGMpDQogIH0NCiAgcHJpbnQoJ1RvbyBtYW55IGl0ZXJhdGlvbnMnKQ0KfQ0KDQoNCnZfQmlzZWN0aW9uKG93biwgMiwzKQ0KYGBgDQoNCg0KIyBOZXd0b27igJlzIE1ldGhvZA0KDQoNClRoZSBOZXd0b24tUmFwaHNvbiBtZXRob2QgaXMgYSBtZXRob2QgZm9yIGFwcHJveGltYXRpbmcgdGhlIHJvb3RzIG9mIHBvbHlub21pYWwgZXF1YXRpb25zIG9mIGFueSBvcmRlci4gSW4gZmFjdCB0aGUgbWV0aG9kIHdvcmtzIGZvciBhbnkgZXF1YXRpb24sIHBvbHlub21pYWwgb3Igbm90LCBhcyBsb25nIGFzIHRoZSBmdW5jdGlvbiBpcyBkaWZmZXJlbnRpYWJsZSBpbiBhIGRlc2lyZWQgaW50ZXJ2YWwuICdzIG9mdGVuIGJlY29tZSBpbmNyZWFzaW5nbHkgYmV0dGVyIGFwcHJveGltYXRpb25zIG9mIHRoZSBmdW5jdGlvbidzIHJvb3QuIE5ld3RvbidzIG1ldGhvZCB1c3VhbGx5IHVzZSBmb3Igc29sdmluZyBlcXVhdGlvbnMgaXMgYW5vdGhlciBudW1lcmljYWwgbWV0aG9kIGZvciBzb2x2aW5nIGFuIGVxdWF0aW9uICRmKHgpPTAkLiBJdCBpcyBiYXNlZCBvbiB0aGUgZ2VvbWV0cnkgb2YgYSBjdXJ2ZSwgdXNpbmcgdGhlIHRhbmdlbnQgbGluZXMgdG8gYSBjdXJ2ZS4gQXMgc3VjaCwgaXQgcmVxdWlyZXMgW2NhbGN1bHVzXShodHRwczovL3R1dG9yaWFsLm1hdGgubGFtYXIuZWR1L2NsYXNzZXMvY2FsY2kvbmV3dG9uc21ldGhvZC5hc3B4KSwgaW4gcGFydGljdWxhciBkaWZmZXJlbnRpYXRpb24uIFJvdWdobHksIHRoZSBpZGVhIG9mIE5ld3RvbidzIG1ldGhvZCBpcyBhcyBmb2xsb3dzLg0KDQojIyBNYXRoZW1hdGljYWwgRm9ybXVsYQ0KDQpOZXd0b27igJlzIG1ldGhvZCBidWlsZCBhIHNlcXVlbmNlIG9mIHZhbHVlcyAkXGJyYWNlIHhfbiQgdmlhIGZ1bmN0aW9uYWwgaXRlcmF0aW9uIHRoYXQgY29udmVyZ2VzIHRvIHRoZSByb290IG9mIGEgZnVuY3Rpb24gJGYkLg0KVGhlIG1hdGhlbWF0aWNhbCBmb3JtdWxhIGlzICQkeF97bisxfSA9IHhfbiAtIFxmcmFjIHtmKHhfbil9e2YnKHhfbil9JCQNCg0KIyMgVGhlIE5ld3RvbuKAmXMgQWxnb3JpdGhtDQoNClRoZSBOZXd0b24ncyBhbGdvcml0aG0gaXMgYSBjb21tb25seSB1c2VkIHRlY2huaXF1ZSBmb3IgbG9jYXRpbmcgemVyb3Mgb2YgYSBmdW5jdGlvbi4gVGhpcyB0aGUgcHJlc2VudCBvZiBuZXd0b24ncyBhbGdvcml0aG0gOg0KDQoqIEZpbmQgJGYoeF9uKSQgYW5kICRmJyh4LW4pJCAkJHhfe24rMX0gPSB4X24gLSBcZnJhYyB7Zih4X24pfXtmJyh4X24pfSQkDQoNCiogSWYgJGYoeF97bisxfSk9MCQgdGhlbiAkeF9uJCBpcyBhbiBleGFjdCByb290LCBlbHNlICR4X3tuKzF9PXhfbiQNCg0KKiBSZXBlYXQgdGhhdCB1bnRpbCAkZih4X3tuKzF9KT0wJCBvciAkfGYoeF97bisxfSl8JCAkXGxlcSQgYWNjdXJhY3kNCg0KIyMgTmV3dG9u4oCZcyBNZXRob2QgaW4gUg0KDQpTdXBwb3NlIHdlIHdhbnQgdG8gZmluZCB0aGUgcm9vdCBvZiB0aGUgZnVuY3Rpb24gJGYoeCk9eF4y4oiSOSBcdGV4dHsgZm9yLCAgfSB4PjAkLiBXZSBhc3N1bWUgdGhhdCAkZiQgaXMgc21vb3RoIChkaWZmZXJlbnRpYWJsZSkuIE91ciBnb2FsIGlzIHRvIGZpbmQgYSByb290IG9mICRmJCBpLmUgYSAkeCQgdmFsdWUgZm9yIHdoaWNoICRmKHgpPTAkLiBXZSBpbGx1c3RyYXRlIHRoZSBtZXRob2Qgd2l0aCBhIHNpbXBsZSBleGFtcGxlIGZvciB3aGljaCB5b3Uga25vdyB0aGUgcm9vdC4NCg0KIyMjIFZpc3VhbGl6ZSB0aGUgZnVuY3Rpb24NCg0KYGBge3J9DQojIGZpcnN0IGdlbmVyYXRlIHRoZSBzZXF1ZW5jZQ0KeC5zZXEgPC0gc2VxKGZyb20gPSAwLjEsIHRvID0gMTAsIGxlbmd0aC5vdXQgPSAxMDEpDQpmIDwtIHNhcHBseSh4LnNlcSwgZnVuY3Rpb24oeCkgeF4yIC0gOSkNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KIyBwdXQgdGhlIHggYW5kIHkgdmFsdWVzIGluIGEgZGF0YSBmcmFtZQ0KcGxvdF9kYXRhIDwtIGRhdGEuZnJhbWUoIngiID0geC5zZXEsICJmIiA9IGYpDQpoZWFkKHBsb3RfZGF0YSkNCmBgYA0KYGBge3J9DQojIGNyZWF0ZSB0aGUgYmFzZSBsYXllciBvZiBnZ3Bsb3Qgd2l0aCBnZW9tX0xpbmUNCnBsb3RfZiA8LSBnZ3Bsb3QocGxvdF9kYXRhLCBhZXMoeCA9IHgsIHkgPSBmKSkgKyANCiAgZ2VvbV9saW5lKGNvbG9yID0gInJlZCIsIHNpemUgPSAxLjApICsgDQogIGxhYnMoeCA9ICJ4IiwgeSA9ICJmKHgpID0geF4yIC0gOSIpDQojIGJlYXV0aWZ5IDogSW5jcmVhc2UgZm9udCBzaXplIGluIGF4ZXMgDQpwbG90X2YgKyB0aGVtZShheGlzLnRleHQueCA9IA0KICAgICAgICAgICAgICAgICBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIixzaXplID0gMTIpLA0KICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSANCiAgICAgICAgICAgICAgICAgZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMiksDQogICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImJsYWNrIiwgDQogICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEsIGxpbmV0eXBlID0gInNvbGlkIikpDQpgYGANCg0KQnkgY29uc2lkZXJpbmcgdGhlIHZpc3VhbGl6YXRpb24gYWJvdmUsIGl0J3MgbG9va3MgbGlrZSB0aGUgZnVuY3Rpb24gaXMgMCBhcm91bmQgMy4gSG93IGRvIHdlIGtub3cgdGhhdCBleGFjdGx5IGNvcnJlY3QsIGxldCdzIHRyeSB6b29tIHRoZSB2aXN1YWxpemF0aW9uLg0KDQpgYGB7cn0NCnBsb3RfZiArIA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjAwLCBjb2xvciA9ICJncmVlbiIsIHNpemUgPSAxKSArDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygyLDQpLCB5bGltID0gYygtMSwgMykpDQpgYGANCg0KTmV4dCwgbGV0IHVzIHZpc3VhbGl6ZSB0aGlzIHRvIGZpbmQgdGhlIHJvb3Qgb2Ygb3VyIGZ1bmN0aW9uICRmKHgpPXheMuKIkjkuJCBGaXJzdCB3ZSBuZWVkIHRvIGNyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyB0aGUgdGFuZ2VudCBsaW5lIHRvIHRoZSBmdW5jdGlvbiBmIGF0IHNvbWUgcG9pbnQgYS4NCg0KYGBge3J9DQojIExldCB1cyBjcmVhdGUgb3VyIHRhbmdlbnQgbGluZSBmdW5jdGlvbiBhdCBzb21lIHBvaW50IGENCmZfdGFuZ2VudCA8LSBmdW5jdGlvbih4LCBmLCBkZiwgYSl7DQogICMgV2UgbmVlZCB0aGUgZnVuY3Rpb24gYW5kIGl0cyBkZXJpdmF0aXZlIGRmDQogICMgYSBpcyB0aGUgcG9pbnQgd2hlcmUgd2UgY3JlYXRlIHRoZSB0YW5nZW50IHRvIHRoZSBmdW5jdGlvbg0KICAjIHJldHVybnMgdGhlIHRhbmdlbnQgbGluZSANCiAgZGYoYSkqKHggLSBhKSArIGYoYSkNCn0NCmBgYA0KDQpUaGVuLCBwbG90IHRoZSB0YW5nZW50IGxpbmUgdG8gdGhlIGluaXRpYWwgdmFsdWUgJGYkICBhdCAkeCgwKT00JCAgd2hpY2ggd2lsbCBiZSBvdXIgZmlyc3QgZ3Vlc3Mgb2YgdGhlIHJvb3QuDQoNCmBgYHtyfQ0KIyBhZGQgdGhlIHRhbmdlbnQgbGluZSBhdCA0IHRvIG91ciBkYXRhIGZyYW1lDQpwbG90X2RhdGEkZi50YW4gPC0gc2FwcGx5KHBsb3RfZGF0YSR4LCBmX3RhbmdlbnQsIGYgPSBmdW5jdGlvbih4KSB4XjIgLSA5LCBkZiA9IGZ1bmN0aW9uKHgpIDIqeCwgYSA9IDQpDQoNCiMgY3JlYXRlIHRoZSBiYXNlIGxheWVyIG9mIGdncGxvdCB3aXRoIGdlb21fTGluZQ0KcGxvdF90YW5nZW50X2xpbmUgPC0gZ2dwbG90KHBsb3RfZGF0YSwgYWVzKHggPSB4KSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gZiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjk1KSArDQogIGdlb21fbGluZShhZXMoeSA9IGYudGFuKSwgY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAwLjk1KSArDQogIGxhYnMoeCA9ICJ4IiwgeSA9ICJmKHgpIGFuZCB0YW5nZW50IGxpbmUgYXQgNCIpIA0KcGxvdF90YW5nZW50X2xpbmUNCmBgYA0KDQpOZXh0LCBsZXQgdXMgem9vbSBpbiBvbiAkMuKJpHjiiaQ0JCBhbmQgdHJ5IHRvIHNlZSB3aGVyZSB0aGUgdGFuZ2VudCBsaW5lIGlzIGVxdWFsIHRvIDAuDQoNCmBgYHtyfQ0KIyB6b29tIGluIGJldHdlZW4gMyBhbmQgNA0KcGxvdF90YW5nZW50X2xpbmUgKyANCiAgIyBhZGQgYSBob3Jpem9udGFsIGxpbmUgYXQgMA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjAwLCBjb2xvciA9ICJncmVlbiIsIHNpemUgPSAxKSArDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygyLDQpLCB5bGltID0gYygtNSwgMTApKQ0KYGBgDQoNCkJ5IGNvbnNpZGVyaW5nIHRoZSB2aXN1YWxpemF0aW9uIGFib3ZlLCBsb29rcyBsaWtlIHRoZSB0YW5nZW50IGxpbmUgaXMgMCBhcm91bmQgMy4xLiBUaGlzIHdpbGwgYmUgb3VyIHVwZGF0ZWQgZ3Vlc3MgYXQgdGhlIHJvb3QuIFVuZGVyc3RhbmQgdGhlIHJhdGlvbmFsZSBiZWhpbmQgdGhpcy4gSWYgZiBpcyBhcHByb3hpbWF0ZWx5IGVxdWFsIHRvIGl0cyB0YW5nZW50IGxpbmUgYXQgNCwgdGhlbiB0aGUgcm9vdCBvZiAkZiQgaXMgYXBwcm94aW1hdGVseSBlcXVhbCB0byB0aGUgcm9vdCBvZiB0aGUgdGFuZ2VudCBsaW5lLiBDYW4geW91IHNlZSB0aGlzIGluIHRoZSBwbG90IGFib3ZlPw0KDQpUaGUgZXhhY3QgdmFsdWUgd2hlbiB0aGUgdGFuZ2VudCBsaW5lIGlzIDAgaXMgZ2l2ZW4gYnkNCg0KJCQgeF57KDEpfT004oiSe2YoNCkgXG92ZXIgZuKAsig0KX0gPTMuMTI1JCQNCg0KVGhlbiwgYWRkIHRoZSB0YW5nZW50IGxpbmUgYXQgMy4xMjUgdG8gb3VyIGRhdGEgZnJhbWUNCg0KYGBge3J9DQpwbG90X2RhdGEkZi50YW4gPC0gc2FwcGx5KHBsb3RfZGF0YSR4LCBmX3RhbmdlbnQsIGYgPSBmdW5jdGlvbih4KSB4XjIgLSA5LCBkZiA9IGZ1bmN0aW9uKHgpIDIqeCwgYSA9IDMuMTI1KQ0KDQojIGNyZWF0ZSB0aGUgYmFzZSBsYXllciBvZiBnZ3Bsb3Qgd2l0aCBnZW9tX0xpbmUNCnBsb3RfdGFuZ2VudF9saW5lIDwtIGdncGxvdChwbG90X2RhdGEsIGFlcyh4ID0geCkpICsgDQogIGdlb21fbGluZShhZXMoeSA9IGYpLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMC45NSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBmLnRhbiksIGNvbG9yID0gImJsdWUiLCBzaXplID0gMC45NSkgKw0KICBsYWJzKHggPSAieCIsIHkgPSAiZih4KSBhbmQgdGFuZ2VudCBsaW5lIGF0IDQiKSANCnBsb3RfdGFuZ2VudF9saW5lDQpgYGANCg0KTm93IGxldCB1cyB6b29tIGluIG9uIGFyb3VuZCAzIGFuZCB0cnkgdG8gc2VlIHdoZXJlIHRoZSB0YW5nZW50IGxpbmUgaXMgZXF1YWwgdG8gMC4NCg0KYGBge3J9DQojIHpvb20gaW4gYmV0d2VlbiAyLjkgYW5kIDMuMQ0KcGxvdF90YW5nZW50X2xpbmUgKyANCiAgIyBhZGQgYSBob3Jpem9udGFsIGxpbmUgYXQgMA0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjAwLCBjb2xvciA9ICJncmVlbiIsIHNpemUgPSAxKSArDQogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygyLjksMy4xKSwgeWxpbSA9IGMoLTIuNSwgMi41KSkNCmBgYA0KDQpMb29rcyBsaWtlIHRoZSB0YW5nZW50IGxpbmUgaXMgMCBhcm91bmQgMy4gSW4ganVzdCB0d28gc3RlcHMgd2UgYXJlIHZlcnkgY2xvc2UuIFRoaXMgd2lsbCBiZSBvdXIgdXBkYXRlZCBndWVzcyBhdCB0aGUgcm9vdC4gVGhlIGV4YWN0IHZhbHVlIHdoZW4gdGhlIHRhbmdlbnQgbGluZSBpcyAwIGlzIGdpdmVuIGJ5DQoNCiQkIHheeygyKX09eF57KDEpfeKIkntmKHheeygxKX0pIFxvdmVyIGbigLIoeF57KDEpfSl9JCQNCiQkIHheeygyKX09My4xMjXiiJJ7ZigzLjEyNSkgXG92ZXIgZuKAsigzLjEyNSl9ID0gMy4wMDI1JCQNCg0KV2UgY2FuIGNvbnRpbnVlIHVudGlsIG91ciBndWVzc2VzIGtlZXAgZ2V0dGluZyBzbWFsbGVyIGFuZCBzbWFsbGVyLg0KDQojIyMgVXNlIGBOTFJvb3RgIHBhY2thZ2VzDQoNClRoZSBzYW1lIHBhY2thZ2VzIGFzIHdlIHVzZSB0byB0aGUgQmlzZWN0aW9uIE1ldGhvZCwgdGhpcyBwYWNrYWdlcyBhbHNvIGF2YWlsYWJsZSBmb3IgTmV3dG9uJ3MgbWV0aG9kLiANCg0KYGBge3J9DQpsaWJyYXJ5KE5MUm9vdCkNCiMgZmlyc3QgYXJndW1lbnQgaXMgdGhlIGZ1bmN0aW9uIHdob3NlIHJvb3Qgd2UgbmVlZCB0byBmaW5kDQojIHNlY29uZCBhcmd1bWVudCBpcyB0aGUgdGhlIGRlcml2YXRpdmUgb2YgdGhlIGZ1bmN0aW9uIHdob3NlIA0KIyByb290IHdlIG5lZWQgdG8gZmluZC4NCiMgdGhpcmQgYXJndW1lbnQgaXMgYW4gaW5pdGlhbCBndWVzcw0KTklNZnplcm8oZnVuY3Rpb24oeCkgeF4yLTksIGZ1bmN0aW9uKHgpIDIqeCwgeDAgPSA0KQ0KYGBgDQoNCg0KIyBbQ2FzZSBTdHVkeV0oaHR0cHM6Ly9ycHVicy5jb20val9sYXBvcnRlLzU2NDI4MCkgDQoNCiMjIE1vZGVsIEJ1aWxkaW5nDQoNCkluIHRoaXMgbGVzc29uIHdlIHdpbGwgY29uc3RydWN0IHR3byBmdW5jdGlvbnMgdGhhdCB5b3Ugd2lsbCBuZWVkIGZvciB0aGlzIGNvdXJzZSBhbmQgYmVnaW4gdG8gZXhwbG9yZSB0aGUgUiBwcm9ncmFtbWluZyBsYW5ndWFnZS4gUnVuIHRocm91Z2ggdGhlIENoYXB0ZXIgMSBvZiB0aGUgYm9vayB3aGljaCB0YWxrcyBhYm91dCBtb2RlbCBidWlsZGluZyBmb3IgYSBvbmUtdmFyaWFibGUgb3B0aW1pemF0aW9uIHByb2JsZW0uIEV4YW1wbGUgMS4xIChNZWVyc2NoYWVydCkgQSBwaWcgd2VpZ2hpbmcgMjAwIGxicyBnYWlucyA1IGxicyBwZXIgZGF5IGFuZCBjb3N0cyA0NSBjZW50cyBwZXIgZGF5IHRvIGtlZXAgKGZlZWQgYW5kIGJvYXJkKS4gVGhlIG1hcmtldCBwcmljZSBmb3IgcGlncyBpcyA2NSBjZW50cyBwZXIgcG91bmQsIGJ1dCBpcyBmYWxsaW5nIDEgY2VudCBwZXIgZGF5LiBXaGVuIHNob3VsZCB0aGUgcGlnIGJlIHNvbGQ/DQoNCiMjIyBNb2RlbGluZyB0aGUgUHJvYmxlbQ0KDQpWYXJpYWJsZXMgOg0KDQoqICR0JCA9IHRpbWUgKGRheXMpDQoNCiogJHckID0gd2VpZ2h0IG9mIHRoZSBwaWcobGJzKQ0KDQoqICRwJCA9IHByaWNlIGZvciBwaWdzICgkL2xiKQ0KDQoqICRDJCA9IGNvc3Qgb2Yga2VlcGluZyBwaWcgdCBkYXlzICgkKQ0KDQoqICRSJCA9IHJldmVudWUgb2J0YWluZWQgYnkgc2VsbGluZyBwaWcgKCQpDQoNCiogJFAkID0gcHJvZml0IGZyb20gc2VsbGluZyBwaWcgKCQpDQoNCkFzc3VtcHRpb25zOg0KDQoqICR3ID0gMjAwICsgNXQkDQoNCiogJHAgPSAwLjY1IOKIkiAwLjAxdCQNCg0KKiAkQyA9IDAuNDV0JA0KDQoqICRSID0gcOKLhXckDQoNCiogJFAgPSBSIOKIkiBDJA0KDQoqICAkdCBcZ2VxIDAkDQoNCg0KT2JqZWN0aXZlOiBNYXhpbWl6ZSBwcm9maXRzIGZyb20gdGhlIHNlbGwgb2YgdGhlIHBpZw0KDQpMZXQgeCBiZSB0aGUgdGltZSB0byBzZWxsIHRoZSBwaWcgYW5kIGRldmVsb3AgdGhlIHByb2ZpdCBmdW5jdGlvbiB1c2luZyB4IGFzIHRoZSBpbmRlcGVuZGVudCB2YXJpYWJsZS4gSW4gdGhlIGNhc2Ugb2YgYW4gb3B0aW1pemF0aW9uLCB0aGUgdmFyaWFibGUgb24gd2hpY2ggeW91IHdpbGwgbWFrZSBhIGRlY2lzaW9uIG9uIGlzIGdlbmVyYWxseSBjYWxsZWQgYSBkZWNpc2lvbiB2YXJpYWJsZS4gVGhlcmUgY2FuIGJlIG11bHRpcGxlIGRlY2lzaW9uIHZhcmlhYmxlcyBpbiBhIHByb2JsZW0uDQoNCiMjIyBQcm9maXQgRnVuY3Rpb24gPSBPYmplY3RpdmUgZnVuY3Rpb24NCg0KR2l2ZW4gdGhlIGRlc2NyaXB0aW9uIGFuZCBtYXRoZW1hdGljYWwgZXhwbGFuYXRpb24gb2YgdGhlIHZhcmlhYmxlcywgbGV0cyB3cml0ZSBvdXQgdGhlIHByb2ZpdCBmdW5jdGlvbjoNCg0KJCRwcm9maXQoeCkgPSBcdW5kZXJicmFjZSB7KDAuNjUtMC4wMXgpfV97XHRleHQge3ByaWNlIG9mIHRoZSBwaWcgb24gZGF5IHh9fSBcb3ZlcmJyYWNlIHsoMjAwKzV4KX1ee1x0ZXh0e3dlaWdodCBvZiB0aGUgcGlnIG9uIGRheSB4fX0gLSBcdW5kZXJicmFjZSB7KDAuNDV4KX1fe1x0ZXh0IHtjb3N0IG9mIGtlZXBpbmcgcGlnIHggZGF5fX0kJA0KDQpMZXRzIHVzZSBSIHRvIOKAnHNlZeKAnSB3aGF0IHRoZSBwcm9maXQgZnVuY3Rpb24gbG9va3MgbGlrZSBvdmVyIHRoZSBuZXh0IDIwIGRheXMuDQoNCmBgYHtyfQ0KcHJvZml0ID0gZnVuY3Rpb24gKHgpew0KICByZXR1cm4oKDAuNjUtMC4wMSp4KSooMjAwKzUqeCktLjQ1KngpDQp9DQp4ICAgICAgPSBzZXEoMCwyMCwxKQ0KcGxvdCh4LHByb2ZpdCh4KSx0eXBlPSJvIikNCnByaW50KHByb2ZpdCg4KSkNCmBgYA0KDQpBcyB5b3UgY2FuIHNlZSwgdGhlcmUgaXMgYSBnb29kIGFuZCBiYWQgZGF5IHRvIHNlbGwgdGhlIHBpZyBpZiBvdXIgYXNzdW1wdGlvbnMgcmVtYWluIHRoZSBzYW1lIG92ZXIgdGhlIG5leHQgMjAgZGF5cy4gQWx0aG91Z2ggd2UgY291bGQgdXNlIHRoaXMgZ3JhcGggaW4gb3JkZXIgdG8gc2VsZWN0IHRoZSDigJx3aW5uZXLigJ0sIHdlIHdhbnQgdG8gYmUgYWJsZSB0byB1c2UgdGhpcyB0b29sIChSIHByb2dyYW1taW5nIGxhbmd1YWdlKSB0byBhc3Npc3QgdXMgaW4gZW5zdXJpbmcgdGhhdCB3ZSBoYXZlIGFsbCBvZiB0aGUgaW5mb3JtYXRpb24gbmVlZGVkIHRvIG1ha2UgYSBkZWNpc2lvbi4gVGhhdCBtZWFucyB0aGF0IHdlIG5lZWQgdG8gZ2V0IG91ciBoYW5kcyBkaXJ0eSBhbmQgZmlndXJlIG91dCBob3cgdG8gdXNlIG91ciB0b29scyAoaW4gdGhpcyBjYXNlLCBSKS4NCg0KDQojIyBCdWlsZCB0aGUgZnVuY3Rpb25zIHRoYXQgd2UgbmVlZCB0byBzb2x2ZSB0aGUgcHJvYmxlbQ0KDQpXZSB3aWxsIGNyZWF0ZSB0d28gZnVuY3Rpb25zIHRoYXQgd2lsbCBiZSBhYmxlIHRvIHNvbHZlIGZvciBhbiBvcHRpbWFsIHBvaW50IGluIFIgdXNpbmcgbWF0aGVtYXRpY3MgLyBwcm9ncmFtbWluZyB0aGF0IHdlIGFscmVhZHkga25vdyBob3cgdG8gZG8uIEZyb20gY2FsY3VsdXMsIHlvdSBzaG91bGQgcmVtZW1iZXIgdGhlIGRlZmluaXRpb24gb2YgdGhlIGRlcml2YXRpdmUgYW5kIHdoeSB0d2Vha2luZyBpdCBhIGxpdHRsZSBjYW4gZ2V0IHVzIGEgYmV0dGVyIGVzdGltYXRpb24gb2YgdGhlIGRlcml2YXRpdmUgb2YgYSBmdW5jdGlvbjoNCg0KJCRmJyh4KT17XGZyYWN7Zih4K2gpLWYoeC1oKX17Mmh9fSQkDQoNClVzaW5nIHRoaXMgc2ltcGxlIGZvcm11bGEsIGxldOKAmXMgYnVpbGQgYSBkZXJpdmF0aXZlIG9mIHRoZSBwcm9maXQgZnVuY3Rpb24gdGhhdCB3ZSBkZWZpbmVkIGFib3ZlLiBOb3RpY2UgaG93IG91ciBmdW5jdGlvbiBmcHJpbWUkKGYseCkkIHdpbGwgd29yayBmb3IgQU5ZIGZ1bmN0aW9uIHRoYXQgd2UgYXNzaWduIHRvIGl0Lg0KYGBge3J9DQp4ICAgICAgPSBzZXEoMCwyMCkNCmZwcmltZSA9IGZ1bmN0aW9uIChmLGEsaD0wLjAwMDEpeyhmKGEraCktZihhLWgpKS8oMipoKX0NCnBsb3QoeCxmcHJpbWUocHJvZml0LHgpKQ0KYGBgDQoNCiMjIFJvb3QtRmluZGluZyBTb2x2ZXINCg0KQWx0aG91Z2ggd2UgY291bGQgdXNlIHRoZSBncmFwaCBhYm92ZSB0byBmaW5kIHRoZSBzb2x1dGlvbiBmb3IgdGhpcyBwYXJ0aWN1bGFyIHByb2JsZW0sIGl0IGlzIG1vcmUgYXBwcm9wcmlhdGUgdG8gdXNlIG1hdGggdG8gbWFrZSBvdXIgc29sdXRpb24gYXV0b21hdGljLiBUaGVyZSBhcmUgbWFueSByb290LWZpbmRpbmcgYWxnb3JpdGhtcyBvdXQgdGhlcmUgYW5kIGZlZWwgZnJlZSB0byB1c2UgYW5vdGhlciwgYnV0IHdlIHdpbGwgdXNlIGEgc2ltcGxlIGFsZ29yaXRobSBrbm93biBhcyB0aGUgYmlzZWN0aW9uIG1ldGhvZC4gVGhpcyBtZXRob2Qgb25seSByZXF1aXJlcyB0aGF0IHlvdSBzZWxlY3QgdHdvIHBvaW50cyB0aGF0IGhhdmUgb3Bwb3NpdGUgc2lnbnM6IGlmICRmKGEpPSDiiJIkIHRoZW4gJGYoYikgPSArJC4NCg0KDQojIyBCaXNlY3Rpb24gQWxnb3JpdGhtIGZvciBmaW5kaW5nIHRoZSByb290IG9mIGFuIGVxdWF0aW9uDQoNClRoZSBzaW1wbGUgaWRlYSBvZiB0aGUgYmlzZWN0aW9uIG1ldGhvZCBpcyB0aGF0IHlvdSBzdGFydCB3aXRoIGFuIGludGVydmFsICRbYSxiXSQgdGhhdCBoYXMgYSBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgdmFsdWUgZm9yIHRoZSBmdW5jdGlvbiAkZihhKSQgYW5kICRmKGIpJCAtIGl0IGRvZXMgbm90IG1hdHRlciB3aGljaCBvbmUgaXMgcG9zaXRpdmUuIFlvdSBjdXQgdGhlIGludGVydmFsIGluIGhhbGYgYW5kIHByb2NlZWQgd2l0aCB0aGUgaW50ZXJ2YWwgdGhhdCBrZWVwcyBvbmUgc2lkZSBwb3NpdGl2ZSBhbmQgdGhlIG90aGVyIG5lZ2F0aXZlLiBJbiBGaWd1cmUgMSwgd2Ugc3RhcnQgb24gdGhlIGludGVydmFsICRbMiw5XSQgd2hpY2ggd29ya3MgYmVjYXVzZSAkZigyKSQgaXMgcG9zaXRpdmUgYW5kICRmKDkpJCBpcyBuZWdhdGl2ZS4gVGhlIGZpcnN0IHN0ZXAgY3V0cyB0aGUgaW50ZXJ2YWwgaW4gaGFsZiBhbmQgdGhlIGRlY2lzaW9uIG11c3QgYmUgbWFkZSB0byBjb250aW51ZSB3aXRoICRbMiw1LjVdJCBvciAkWzUuNSw5XSQuIEl0IHNob3VsZCBiZSBwcmV0dHkgb2J2b3VzIGZyb20gdGhlIHBpY3R1cmUgdGhhdCAkWzIsNS41XSQgaXMgdGhlIHJpZ2h0IGFuc3dlciAod2Ugd2FudCB0byBrZWVwIGEgcm9vdCBpbiB0aGUgaW50ZXJ2YWwpLCBidXQgZnJvbSBhbiBhbGdvcml0aG0gcGVyc3BlY3RpdmUsIHdlIHNpbXBseSB0ZXN0ICRmKDUuNSkkIGFuZCBmaW5kIG91dCB0aGF0IGl0IGlzIG5lZ2F0aXZlIHdoaWNoIGNhdXNlcyB1cyB0byByZXBsYWNlIDkgJChmWzldJCB3YXMgbmVnYXRpdmUpIHdpdGggNS41LiBXZSB3b3VsZCBjb250aW51ZSB0aGlzIGFsZ29yaXRobSB1bnRpbCB3ZSBhcmUgc2F0aXNmaWVkIHRoYXQgdGhlIHdpZHRoIG9mIHRoZSBpbnRlcnZhbCBpcyBzbWFsbCBlbm91Z2ggdG8gbWFrZSBhIGNvbmNsdXNpb24gYWJvdXQgdGhlIHZhbHVlIG9mIHRoZSByb290Lg0KDQohW10oQzovVXNlcnMvaHAvRG93bmxvYWRzL2Jpc2VjdGlvbi5wbmcpDQpGaWd1cmUgMTogQmlzZWN0aW9uIEV4YW1wbGUNCg0KYGBge3J9DQpiaXNlY3Rpb24gPSBmdW5jdGlvbihmLGEsYix0b2w9MC4wMDAxKXsNCiAgaWYgKGYoYSkqZihiKSA+IDApew0KICAgIHJldHVybiAoIkJvdW5kYXJ5IENvbmRpdGlvbnMgTm90IE1ldCIpDQogIH0NCiAgZWxzZXsNCiAgICBtaWRkbGUgPSBhDQogICAgd2hpbGUgKGFicyhmKG1pZGRsZSkpPnRvbCl7DQogICAgICBtaWRkbGUgPSAoYStiKS8yDQogICAgICBpZiAoZihtaWRkbGUpKmYoYSk+MCkgKGEgPSBtaWRkbGUpDQogICAgICBlbHNlIChiID0gbWlkZGxlKQ0KICAgICAgeD1taWRkbGUNCiAgICAgIHk9ZihtaWRkbGUpDQogICAgICAjIyBpZiB5b3Ugd2FudCB0byAic2VlIiB3aGF0IGhhcHBlbnMgYXQgZXZlcnkgc3RlcCwgdGFrZSBvZmYgdGhlICMgb2YgdGhlIG5leHQgbGluZSAjIw0KICAgICAgI2NhdChzcHJpbnRmKCJ4LVZhbDogJS40ZiA7IGYoeC12YWwpOiAlLjRmXG4iLHgseSkpDQogICAgfQ0KICAgIHJldHVybiAobWlkZGxlKQ0KICB9DQp9DQojRXhhbXBsZSBvZiBhIGZpbmRpbmcgYSByb290IG9mIGEgZnVuY3Rpb24NCmYgICAgPSBmdW5jdGlvbiAoeCl7eF4zLTV9ICNzaW5sZ2UgbGluZSBmdW5jdGlvbiBkZWZpbml0aW9uDQp6ZXJvID0gYmlzZWN0aW9uIChmLC0xMCwyMCkNCnggICAgPSBzZXEoLTEsMiwwLjAxKQ0KcGxvdCh4LGYoeCksImwiKQ0KYWJsaW5lKGg9MCxjb2w9InJlZCIpDQphYmxpbmUodj16ZXJvLGNvbD0iYmx1ZSIpDQoNCnByaW50KHplcm8pDQpgYGANCg0KIyMgVXNlIG91ciB0b29sIHRvIHNvbHZlIHRoZSBwaWcgcHJvYmxlbQ0KDQpVc2UgdGhlIHRvb2xzIGF0IHlvdXIgZGlzcG9zYWwgdG8gc29sdmUgdGhlIHByb2JsZW0uIEJlIGFibGUgdG8gbWFrZSBzZXZlcmFsIGFsdGVybmF0aXZlcyB0byB0aGUgcHJvcG9zZWQgbW9kZWwgYW5kIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBtdWx0aXBsZSB2YXJpYWJsZXMuIFdoZW4gZG8gd2Ugc2VsbCB0aGUgcGlnPw0KDQpgYGB7cn0NCmRQcm9maXQgPSBmdW5jdGlvbih4KXtmcHJpbWUocHJvZml0LHgpfSAjZGVyaXZhdGl2ZSBvZiBwcm9maXQgZnVuY3Rpb24NCmJpc2VjdGlvbihkUHJvZml0LDAsMjApDQpgYGANCg0KQXMgeW91IGNhbiBzZWUsIHdlIGdvdCBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIGFuc3dlciBhcyB0aGUgYm9vay4gVGhlIGRpZmZlcmVuY2UgaXMgdGhhdCBvdXIgc29sdXRpb24gdXNlcyBhbiBlc3RpbWF0aW9uIG9mIHRoZSBkZXJpdmF0aXZlIGluc3RlYWQgb2YgdGhlIGNsb3NlZC1mb3JtIHNvbHV0aW9uIGFzIHdlbGwgYXMgYSBzb2x2ZXIgZm9yIGZpbmRpbmcgdGhlIGRheSAkeCQgd2hlcmUgdGhlIHByb2ZpdCBpcyBtYXhpbWl6ZWQgKHByb2ZpdCBmdW5jdGlvbiBkZXJpdmF0aXZlID0gMCkuIEluIHRoZSBjYXNlIG9mIG1vc3QgcHJvYmxlbXMsIHlvdSB3aWxsIHVzZSBudW1lcmljYWwgbWV0aG9kcyAobGlrZSB3ZSBkaWQpIGJlY2F1c2UgcmVhbCB3b3JsZCBwcm9ibGVtcyBkbyBub3QgdXN1c2FsbHkgaGF2ZSBhIGVhc3kgYW5zd2VyLiBUbyBiZWNvbWUgYSBnb29kIHByb2JsZW0gc29sdmVyLCB5b3UgYXJlIGdvaW5nIHRvIG5lZWQgdG8gaW52ZXN0IGluIHlvdXIgY29kaW5nIGFiaWxpdGllcyBiZWNhdXNlIHlvdSB3aWxsIHVzdWFsbHkgbmVlZCB0byBkZXZlbG9wIHNvbWUgb3JpZ2luYWwgY29kZSB0byBoZWxwIHlvdSBzb2x2ZSBhIHBhcnRpY3VsYXIgcHJvYmxlbS4NCg0KIyMgU2Vuc2l0aXZpdHkgQW5hbHlzaXM6IFByaWNlIG9mIHRoZSBQaWcNCg0KTGV04oCZcyBnbyBiYWNrIGFuZCBleGFtaW5lIG1vcmUgY2xvc2VseSBvbmUgb2Ygb3VyIG9yaWdpbmFsIGFzc3VtcHRpb25zIHRoYXQgbWF5IG9yIG1heSBub3QgaG9sZCB0byBzZWUgaG93IG91ciBzb2x1dGlvbiBpcyBhZmZ0ZWN0ZWQgYnkgYSBkaWZmZXJlbnQgYXNzdW1wdGlvbi4gRG9lcyB0aGUgb3B0aW1hbCBkYXkgdG8gc2VsbCBjaGFuZ2UgaWYgd2UgYXNzdW1lIHNvbWUgZGlmZmVyZW50IHByaWNlIG9mIHRoZSBwaWcuIEhlcmUgd2UgbGV0IHRoZSBwaWcgcHJpY2UgZHJvcCB0byByZWNyZWF0ZSB0aGUgbnVtYmVycyBpbiB0aGUgYm9vaywgYnV0IHdlIGFyZSBhYmxlIHRvIGRvIHNvIG11Y2ggbW9yZSB3aGljaCB3aWxsIGJlIGRlbW9uc3RyYXRlZCBpbiB0aGUgbmV4dCBhbmFseXNpcy4NCg0KYGBge3J9DQojUHJpY2UgZmFsbGluZyBwZXIgZGF5ID0gcCANCnAgICA9IHNlcSgwLjAwOCwwLjAxMiwwLjAwMSkNCmFucyA9IGFycmF5KDAsbGVuZ3RoKHApKQ0KZm9yIChpIGluIDE6bGVuZ3RoKHApKXsNCiAgICBwcm9maXQgPSBmdW5jdGlvbiAoeCl7DQogICAgICByZXR1cm4oKDAuNjUtcFtpXSp4KSooMjAwKzUqeCktLjQ1KngpDQogICAgfQ0KICAgIGRQcm9maXQgPSBmdW5jdGlvbih4KXtmcHJpbWUocHJvZml0LHgsKX0NCiAgICBhbnNbaV0gPSBiaXNlY3Rpb24oZFByb2ZpdCwwLDIwLDAuMDAwMSkNCn0NCnByaW50KGFucykNCg0KcGxvdChwLGFucywibyIseGxhYj0icCgkL2RheSkiLHlsYWI9IngoRGF5cyB0byBTZWxsKSIpDQp0aXRsZSgiU2Vuc2l0aXZpdHkgb2YgRmFsbGluZyBQcmljZSBvZiBQaWciKQ0KYGBgDQoNCiMjIFNlbnNpdGl2aXR5IEFuYWx5c2lzOiBHcm93dGggUmF0ZSBvZiB0aGUgUGlnDQoNClNpbmNlIHdlIGFyZSBhbHNvIGNvbmNlcm5lZCBhYm91dCB0aGUgZ3Jvd3RoIHJhdGUgb2YgdGhlIHBpZywgbGV04oCZcyBjb25kdWN0IHNlZSBob3cgdGhlIGRheXMgdG8gc2VsbCBhcmUgYWZmZWN0ZWQgYnkgdGhlIGdyb3d0aCByYXRlLiBUaGUgd2VpZ2h0ICh3KSBpcyBjYWxjdWxhdGVkIHVzaW5nIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIHBpZyB3aWxsIGdyb3cgNWxicyBwZXIgZGF5IHNvIHRoYXQ6ICR3ID0gMjAwICsgZ3QkIHdoZXJlICRnID0gNSQuIExldOKAmXMgc2VlIHdoYXQgaGFwcGVucyBpZiAkZyQgaXMgYmV0d2VlbiAzIGFuZCA3LiBSZW1lbWJlciB0aGUgYmlzZWN0aW9uIG1ldGhvZCBuZWVkcyB0d28gYm91bmRhcnkgcG9pbnRzIHRoYXQgaGF2ZSB0aGUgb3Bwb3NpdGUgdmFsdWVzIGFuZCBpZiB0aGUgZ3Jvd3RoIHJhdGUgaXMgdG9vIHNtYWxsLCB0aGluayBhYm91dCB3aGF0IHRoYXQgZG9lcyB0byB0aGUgcHJvZml0LiBFeHBlcmltZW50IHdpdGggbGFyZ2UgYW5kIHNtYWxsIGdyb3d0aCByYXRlcyBhbmQgdGhlIHByb2ZpdCBmdW5jdGlvbiB0byBmaWd1cmUgaXQgb3V0IGZvciB5b3Vyc2VsZiBpZiB5b3UgZG9u4oCZdCBzZWUgaXQuIFdlIG5lZWRlZCB0byBtYWtlIHRoZSBzdGFydGluZyBwb2ludCBvZiB0aGUgYmlzZWN0aW9uIG1ldGhvZCB0byB0aGUgbGVmdCAobmVnYXRpdmUgbnVtYmVyKSBpbiBvcmRlciBmb3IgaXQgdG8gZmluZCB0aGUgemVybyBmb3IgM2xicyBhbmQgMy41bGJzIHBlciBkYXkuDQoNCmBgYHtyfQ0KI0dyb3d0aCByYXRlIG9mIHRoZSBwaWcgPSBnDQpnICAgPSBzZXEoMSwxMiwwLjUpDQphbnMgPSBhcnJheSgwLGxlbmd0aChnKSkNCmZvciAoaSBpbiAxOmxlbmd0aChnKSl7DQogICAgcHJvZml0ID0gZnVuY3Rpb24gKHgpew0KICAgICAgcmV0dXJuKCgwLjY1LTAuMDEqeCkqKDIwMCtnW2ldKngpLS40NSp4KQ0KICAgIH0NCiAgICBkUHJvZml0ID0gZnVuY3Rpb24oeCl7ZnByaW1lKHByb2ZpdCx4LCl9DQogICAgYW5zW2ldID0gYmlzZWN0aW9uKGRQcm9maXQsLTEwMCw1MCwwLjAwMDEpDQp9DQpwcmludChhbnMpDQoNCnBsb3QoZyxhbnMsIm8iLHhsYWI9ImcoZ3Jvd3RoL2RheSkiLHlsYWI9IngoRGF5cyB0byBTZWxsKSIpDQp0aXRsZSgiU2Vuc2l0aXZpdHkgb2YgR3Jvd3RoIFJhdGUgb2YgUGlnIikNCmBgYA==