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 Matematical Formula

Let’s say we want to solve the equation \(f(x) = 0\) and there are two poinst whuch are \(a\) dan \(b\), so there will be \(f(a)\) and \(f(b)\) which have opposite sighns. Since, we know about intermediate value theorem that explain \(f\) must have at least one rood in the interval \([a,b]\) as lonf as \(f\) is continuous on this interval. Then we use \(c=(a+b)/2\) or \(m = (a+b)/2\) to divides the interval in two. Hence, there are two possibilities either \(f(a)\) dan \(f(c)\) have opposite signs or \(f(c)\) and \(f(b)\) have opposite signs. The bisection algorithm is then applied recursively to the sub-interval where the sign change occurs. The mid-point of subintervals are annotated in the graph by both texts and blue straight lines, and the end points are denoted in dashed red lines. The root of each iteration is also plotted in the right margin of the graph.

The number of iteration n needed to converge towards a root withing the imposed tolerance ε is calculated as

Way to get this formula:

Every iteration the algorithm generates a series of intervals \([a_n, b_n]\) which is \(b_n\)-\(a_n\) = \((b-a)\over2^n\) = \(|c-x|\)

The tolerance \(ε\) is the absolute value of the difference between the actual root of the function x and approximation \(c\) : \(ε\) = \(|c-x|\).

From the algorithm above: \(|c-x|\) \(≤ε\)

Then we get: \((b-a)\over2^n\) \(≤ε\)

Then we obtain: \(2^n\) \(≥\) \((b−a)\overε\)

Then we apply the logarithm function to the both sides: \(log(2^n)\) \(≥\) \(log (b-a)\over ε\)

So, we get: \(n * log(2) ≥\) \(log (b-a)\over ε\) $ n≥$ $ (log (b-a)/ε)/log(2)$

1.2 The Bisection Algorithm

Bisection algorithm is used to estimate the smallest value of \(ω\) which applied for the matrix A.

For example, f(x) function is given . The bisection algorthm works as follows:

  1. Two valus \(a\) and \(b\) are chosen for which \(f(a)>0\) and \(f(b)<0\) or another way around. 2.Interval halving: \(c =\) \((a + b) \over 2\) 3.The function f is evaluated for the value of \(c\)
  2. If \(f(c) = 0\) means that we found the root of the function, which is \(c\)
  3. if \(f(c) ≠ 0\) we check the sign of \(f(c)\):

if \(f(c)\) has the same sign as \(f(a)\) we replace \(a\) with \(c\) and we keep the same value for \(b\) if \(f(c)\) has the same sign as \(f(b)\), we replace \(b\) with \(c\) and we keep the same value for \(a\) 6. we go back to step 2. and recalculate \(c\) with the new value of \(a\) or \(b\)

The algorithm ends when the values of \(f(c)\) is less than a defined tolerance (e.g. 0.001). In this case we say that c is close enough to be the root of the function for which \(f(c)\) ~= 0.

The bisection method also work as follow:

  1. Start

  2. Define function f(x)

  3. Input

    1. Lower and Upper guesses a and b
    2. tolerable error e
  4. If f(a)*f(b) > 0 print “Incorrect initial guesses” goto 3 End If

  5. Do c = (a+b)/2

    If f(a)*f(c) < 0 b = c Else a = c End If

    while (fabs(f(c)) > e) // fabs -> returns absolute value

  6. Print root as c

  7. Stop

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 Matematical Formula

So, let \(f(x)\) be a differentiable function. Slect a point \(x_0\) based on a first approximation to the root. To approximate we can calulate using this formula: \(x_{(n+1)}\) = \(n_n\) - \(f(x_n)\over f'(x_n)\)

2.2 The Newton’s Algorithm

Newton’s method is a way to find a solution to the equation to as many decimal places as you want. It is what is called an "iterative procedure,’’ meaning that it can be repeated again and again to get an answer of greater and greater accuracy. Iterative procedures like Newton’s method are well suited to programming for a computer.The Newton algorithm consists in replacing the function to be minimized to get the new point. In the quasi Newton algorithm, the second order terms in the expansion are replaced by some approximations.

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

## Warning: package 'ggplot2' was built under R version 3.6.3
##       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 Lesson1: Model Building - R tutorial

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>=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:

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.1.3 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:

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.1.4 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.1.4.1 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.

## [1] 1.709967

3.1.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.1.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.1.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

LS0tDQp0aXRsZTogIkxhYjQ6IFNvbHZpbmcgTm9ubGluZWFyIEVxdWF0aW9ucyINCmF1dGhvcjogIlNvZmlhIE5pY2tsYXVzIFMuIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge3IgTG9nbywgZWNobz1GQUxTRSxmaWcuYWxpZ249J2NlbnRlcicsIG91dC53aWR0aCA9ICc0MCUnfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vZ2l0aHViLmNvbS9CYWt0aS1TaXJlZ2FyL2ltYWdlcy9ibG9iL21hc3Rlci9sb2dvLnBuZz9yYXc9dHJ1ZSIpDQpgYGANCg0KIyBCaXNlY3Rpb24gTWV0aG9kDQoNClRoZSBiaXNlY3Rpb24gbWV0aG9kIGlzIGFub3RoZXIgYXBwcm9hY2ggdG8gZmluZGluZyB0aGUgcm9vdCBvZiBhIGNvbnRpbnVvdXMgZnVuY3Rpb24gJGYoeCkkIG9uIGFuIGludGVydmFsICRbYSxiXSQuIFRoZSBtZXRob2QgdGFrZXMgYWR2YW50YWdlIG9mIGEgY29yb2xsYXJ5IG9mIHRoZSBpbnRlcm1lZGlhdGUgdmFsdWUgdGhlb3JlbSBjYWxsZWQgQm9semFub+KAmXMgdGhlb3JlbSB3aGljaCBzdGF0ZXMgdGhhdCBpZiB0aGUgdmFsdWVzIG9mICRmKGEpJCBhbmQgJGYoYikkIGhhdmUgb3Bwb3NpdGUgc2lnbnMsIHRoZSBpbnRlcnZhbCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIHJvb3QuIFRoZSBpdGVyYXRpb24gc3RlcHMgb2YgdGhlIGJpc2VjdGlvbiBtZXRob2QgYXJlIHJlbGF0aXZlbHkgc3RyYWlnaHRmb3J3YXJkLCBob3dldmVyOyBjb252ZXJnZW5jZSB0b3dhcmRzIGEgc29sdXRpb24gaXMgc2xvdyBjb21wYXJlZCB0byBvdGhlciByb290LWZpbmRpbmcgbWV0aG9kcy4NCg0KDQojIyBNYXRlbWF0aWNhbCBGb3JtdWxhDQoNCkxldCdzIHNheSB3ZSB3YW50IHRvIHNvbHZlIHRoZSBlcXVhdGlvbiAkZih4KSA9IDAkIGFuZCB0aGVyZSBhcmUgdHdvIHBvaW5zdCB3aHVjaCBhcmUgJGEkIGRhbiAkYiQsIHNvIHRoZXJlIHdpbGwgYmUgJGYoYSkkIGFuZCAkZihiKSQgd2hpY2ggaGF2ZSBvcHBvc2l0ZSBzaWdobnMuIFNpbmNlLCB3ZSBrbm93IGFib3V0IGludGVybWVkaWF0ZSB2YWx1ZSB0aGVvcmVtIHRoYXQgZXhwbGFpbiAkZiQgbXVzdCBoYXZlIGF0IGxlYXN0IG9uZSByb29kIGluIHRoZSBpbnRlcnZhbCAkW2EsYl0kIGFzIGxvbmYgYXMgJGYkIGlzIGNvbnRpbnVvdXMgb24gdGhpcyBpbnRlcnZhbC4gIFRoZW4gd2UgdXNlICRjPShhK2IpLzIkICBvciAkbSA9IChhK2IpLzIkIHRvIGRpdmlkZXMgdGhlIGludGVydmFsIGluIHR3by4gSGVuY2UsIHRoZXJlIGFyZSB0d28gcG9zc2liaWxpdGllcyBlaXRoZXIgJGYoYSkkIGRhbiAkZihjKSQgaGF2ZSBvcHBvc2l0ZSBzaWducyBvciAkZihjKSQgYW5kICRmKGIpJCBoYXZlIG9wcG9zaXRlIHNpZ25zLiBUaGUgYmlzZWN0aW9uIGFsZ29yaXRobSBpcyB0aGVuIGFwcGxpZWQgcmVjdXJzaXZlbHkgdG8gdGhlIHN1Yi1pbnRlcnZhbCB3aGVyZSB0aGUgc2lnbiBjaGFuZ2Ugb2NjdXJzLiBUaGUgbWlkLXBvaW50IG9mIHN1YmludGVydmFscyBhcmUgYW5ub3RhdGVkIGluIHRoZSBncmFwaCBieSBib3RoIHRleHRzIGFuZCBibHVlIHN0cmFpZ2h0IGxpbmVzLCBhbmQgdGhlIGVuZCBwb2ludHMgYXJlIGRlbm90ZWQgaW4gZGFzaGVkIHJlZCBsaW5lcy4gVGhlIHJvb3Qgb2YgZWFjaCBpdGVyYXRpb24gaXMgYWxzbyBwbG90dGVkIGluIHRoZSByaWdodCBtYXJnaW4gb2YgdGhlIGdyYXBoLg0KDQpUaGUgbnVtYmVyIG9mICBpdGVyYXRpb24gbiBuZWVkZWQgdG8gY29udmVyZ2UgdG93YXJkcyBhIHJvb3Qgd2l0aGluZyB0aGUgaW1wb3NlZCB0b2xlcmFuY2UgzrUgaXMgY2FsY3VsYXRlZCBhcyANCmBgYHtyfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL3VzZXIvRG93bmxvYWRzL0NhcHR1cmUucG5nIikNCmBgYA0KDQoqKldheSB0byBnZXQgdGhpcyBmb3JtdWxhOioqDQoNCkV2ZXJ5IGl0ZXJhdGlvbiB0aGUgYWxnb3JpdGhtIGdlbmVyYXRlcyBhIHNlcmllcyBvZiBpbnRlcnZhbHMgJFthX24sIGJfbl0kIHdoaWNoIGlzICRiX24kLSRhX24kID0gJChiLWEpXG92ZXIyXm4kID0gJHxjLXh8JA0KDQpUaGUgdG9sZXJhbmNlICTOtSQgaXMgdGhlIGFic29sdXRlIHZhbHVlIG9mIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGFjdHVhbCByb290IG9mIHRoZSBmdW5jdGlvbiB4IGFuZCBhcHByb3hpbWF0aW9uICRjJCA6ICTOtSQgPSAkfGMteHwkLg0KDQoqKkZyb20gdGhlIGFsZ29yaXRobSBhYm92ZToqKg0KJHxjLXh8JCAk4omkzrUkDQoNCioqVGhlbiB3ZSBnZXQ6KiogJChiLWEpXG92ZXIyXm4kICTiiaTOtSQNCg0KKipUaGVuIHdlIG9idGFpbjoqKiAkMl5uJCAk4omlJCAkKGLiiJJhKVxvdmVyzrUkDQoNClRoZW4gd2UgYXBwbHkgdGhlIGxvZ2FyaXRobSBmdW5jdGlvbiB0byB0aGUgYm90aCBzaWRlczogJGxvZygyXm4pJCAk4omlJCAkbG9nIChiLWEpXG92ZXIgzrUkDQoNClNvLCB3ZSBnZXQ6ICRuICogbG9nKDIpIOKJpSQgJGxvZyAoYi1hKVxvdmVyIM61JA0KJCBu4omlJCAkIChsb2cgKGItYSkvzrUpL2xvZygyKSQNCg0KIyMgVGhlIEJpc2VjdGlvbiBBbGdvcml0aG0NCg0KQmlzZWN0aW9uIGFsZ29yaXRobSBpcyB1c2VkIHRvIGVzdGltYXRlIHRoZSBzbWFsbGVzdCB2YWx1ZSBvZiAkz4kkIHdoaWNoIGFwcGxpZWQgZm9yIHRoZSBtYXRyaXggQS4gDQoNCkZvciBleGFtcGxlLCBmKHgpIGZ1bmN0aW9uIGlzIGdpdmVuIC4gVGhlIGJpc2VjdGlvbiBhbGdvcnRobSB3b3JrcyBhcyBmb2xsb3dzOg0KDQoxLiBUd28gdmFsdXMgJGEkIGFuZCAkYiQgYXJlIGNob3NlbiBmb3Igd2hpY2ggJGYoYSk+MCQgYW5kICRmKGIpPDAkIG9yIGFub3RoZXIgd2F5IGFyb3VuZC4NCjIuSW50ZXJ2YWwgaGFsdmluZzogJGMgPSQgJChhICsgYikgXG92ZXIgMiQNCjMuVGhlIGZ1bmN0aW9uIGYgaXMgZXZhbHVhdGVkIGZvciB0aGUgdmFsdWUgb2YgJGMkDQo0LiBJZiAkZihjKSA9IDAkIG1lYW5zIHRoYXQgd2UgZm91bmQgdGhlIHJvb3Qgb2YgdGhlIGZ1bmN0aW9uLCB3aGljaCBpcyAkYyQNCjUuIGlmICRmKGMpIOKJoCAwJCB3ZSBjaGVjayB0aGUgc2lnbiBvZiAkZihjKSQ6DQoNCiAgKmlmICRmKGMpJCBoYXMgdGhlIHNhbWUgc2lnbiBhcyAkZihhKSQgd2UgcmVwbGFjZSAkYSQgd2l0aCAkYyQgYW5kIHdlIGtlZXAgdGhlIHNhbWUgdmFsdWUgZm9yICRiJA0KICAqaWYgJGYoYykkIGhhcyB0aGUgc2FtZSBzaWduIGFzICRmKGIpJCwgd2UgcmVwbGFjZSAkYiQgd2l0aCAkYyQgYW5kIHdlIGtlZXAgdGhlIHNhbWUgdmFsdWUgZm9yICRhJA0KNi4gd2UgZ28gYmFjayB0byBzdGVwIDIuIGFuZCByZWNhbGN1bGF0ZSAkYyQgd2l0aCB0aGUgbmV3IHZhbHVlIG9mICRhJCBvciAkYiQNCg0KVGhlIGFsZ29yaXRobSBlbmRzIHdoZW4gdGhlIHZhbHVlcyBvZiAkZihjKSQgaXMgbGVzcyB0aGFuIGEgZGVmaW5lZCB0b2xlcmFuY2UgKGUuZy4gMC4wMDEpLiBJbiB0aGlzIGNhc2Ugd2Ugc2F5IHRoYXQgYyBpcyBjbG9zZSBlbm91Z2ggdG8gYmUgdGhlIHJvb3Qgb2YgdGhlIGZ1bmN0aW9uIGZvciB3aGljaCAkZihjKSQgfj0gMC4NCg0KVGhlIGJpc2VjdGlvbiBtZXRob2QgYWxzbyB3b3JrIGFzIGZvbGxvdzoNCg0KMS4gU3RhcnQNCg0KMi4gRGVmaW5lIGZ1bmN0aW9uIGYoeCkNCg0KMy4gSW5wdXQgDQoJYS4gTG93ZXIgYW5kIFVwcGVyIGd1ZXNzZXMgYSBhbmQgYg0KCWIuIHRvbGVyYWJsZSBlcnJvciBlDQoJDQo0LiBJZiBmKGEpKmYoYikgPiAwDQoJcHJpbnQgIkluY29ycmVjdCBpbml0aWFsIGd1ZXNzZXMiDQogICAJZ290byAzDQogICBFbmQgSWYNCg0KNS4gRG8gDQoJYyA9IChhK2IpLzINCgkNCglJZiBmKGEpKmYoYykgPCAwDQoJCWIgPSBjDQoJRWxzZQ0KCQlhID0gYw0KCUVuZCBJZg0KCQkNCiAgIHdoaWxlIChmYWJzKGYoYykpID4gZSkgICAvLyBmYWJzIC0+IHJldHVybnMgYWJzb2x1dGUgdmFsdWUgDQogICANCjYuIFByaW50IHJvb3QgYXMgYw0KDQo3LiBTdG9wDQoNCg0KIyMgQmlzZWN0aW9uIEFsZ29yaXRobSBpbiBSDQoNClN1cHBvc2Ugd2Ugd2FudCB0byBmaW5kIHRoZSByb290IG9mIHRoZSBmdW5jdGlvbiAkeF4z4oiSMnjiiJI1JC4gSXQgaXMgb2Z0ZW4gdmFsdWFibGUgdG8gcGxvdCB0aGUgZnVuY3Rpb24gdG8gZmluZCBhbiBpbnRlcnZhbCBjb250YWluaW5nIHRoZSByb290Lg0KDQojIyMgVmlzdWFsaXplIHRoZSBmdW5jdGlvbg0KDQpgYGB7cn0NCmZ1bmMgPC0gZnVuY3Rpb24oeCkgew0KICB4XjMgLSAyICogeCAtIDUNCn0NCg0KY3VydmUoZnVuYywgeGxpbT1jKC0zLDMpLCBjb2w9J2JsdWUnLCBsd2Q9MS41LCBsdHk9MikNCmFibGluZShoPTApDQphYmxpbmUodj0wKQ0KYGBgDQoNCkFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgdmlzdWFsaXphdGlvbiBhYm92ZSwgd2Uga25vdyB0aGF0IHRoZSByb290IGFwcGVhcnMgdG8gbGllIGNsb3NlIGluIDIuIE5leHQsIHdlIHdpbGwgdXNlIHRoZSBpbnRlcnZhbCBbMiwzXSBpbiBCaXNlY3Rpb24gTWV0aG9kLg0KDQojIyMgVXNlIGBOTFJvb3RgIHBhY2thZ2VzDQoNCk9uIG9mIHRoZSBtb3N0IHVzZWZ1bGwgcGFja2FnZSBmb3IgdGhlIEJpc2VjdGlvbiBNZXRob2QgaW4gUiBpcyB0aGUgYE5MUm9vdGAgcGFja2FnZSwgaGVyZSB5b3Ugd2lsbCBhcHBseSBgQkZmemVybygpYCB0byBmaW5kIHRoZSBzb2x1dGlvbiwgYXMgeW91IGNhbiBzZWUgYmVsb3c6DQoNCmBgYHtyfQ0KbGlicmFyeShOTFJvb3QpICAgICAgICAgICAgICAjIGxvYWRpbmcgdGhlIHBhY2thZ2UgDQpCRmZ6ZXJvKGZ1bmMsIDIsIDMpICAgICAgICAgICMgdG8gZmluZCB0aGUgc29sdXRpb24gKGp1c3QgYXMgc2ltcGxlIGxpa2UgdGhpcykNCmBgYA0KDQpUaGUgb3V0cHV0IG9mIHRoZSBmdW5jdGlvbiBzaG93cyB0aGUgcm9vdCBpcyBsb2NhdGVkIGF0ICR4PTIuMDk0NTUzJCwgd2hpY2ggbWF0Y2hlcyB0aGUgcmVzdWx0cyBmb3VuZCBpbiBwcmV2aW91cyBleGFtcGxlcyBvbiBvdGhlciByb290IGZpbmRpbmcgbWV0aG9kcyBzdWNoIGFzIHRoZSBOZXd0b24tUmFwaHNvbiBtZXRob2QgYW5kIFNlY2FudCBtZXRob2QuDQoNCg0KIyMjIFdyaXRlIEZ1bmN0aW9uDQoNCldlIGNhbiBhbHNvIHdyaXRlIGEgZnVuY3Rpb24gdGhhdCBpbXBsZW1lbnRzIHRoZSBiaXNlY3Rpb24gbWV0aG9kIHVzaW5nIHRoZSBpdGVyYXRpb24gc3RlcHMgZGV0YWlsZWQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgcG9zdC4NCg0KYGBge3J9DQpCYWt0aV9CaXNlY3Rpb24gPC0gZnVuY3Rpb24oZiwgYSwgYiwgbiA9IDEwMDAsIHRvbCA9IDFlLTcpIHsNCiAgIyBJZiB0aGUgc2lnbnMgb2YgdGhlIGZ1bmN0aW9uIGF0IHRoZSBldmFsdWF0ZWQgcG9pbnRzLCBhIGFuZCBiLCBzdG9wIHRoZSBmdW5jdGlvbiBhbmQgcmV0dXJuIG1lc3NhZ2UuDQogIGlmICghKGYoYSkgPCAwKSAmJiAoZihiKSA+IDApKSB7DQogICAgc3RvcCgnc2lnbnMgb2YgZihhKSBhbmQgZihiKSBkaWZmZXInKQ0KICB9IGVsc2UgaWYgKChmKGEpID4gMCkgJiYgKGYoYikgPCAwKSkgew0KICAgIHN0b3AoJ3NpZ25zIG9mIGYoYSkgYW5kIGYoYikgZGlmZmVyJykNCiAgfQ0KICANCiAgZm9yIChpIGluIDE6bikgew0KICAgIGMgPC0gKGEgKyBiKSAvIDIgIyBDYWxjdWxhdGUgbWlkcG9pbnQNCiAgICANCiAgICAjIElmIHRoZSBmdW5jdGlvbiBlcXVhbHMgMCBhdCB0aGUgbWlkcG9pbnQgb3IgdGhlIG1pZHBvaW50IGlzIGJlbG93IHRoZSBkZXNpcmVkIHRvbGVyYW5jZSwgc3RvcCB0aGUgDQogICAgIyBmdW5jdGlvbiBhbmQgcmV0dXJuIHRoZSByb290Lg0KICAgIGlmICgoZihjKSA9PSAwKSB8fCAoKGIgLSBhKSAvIDIpIDwgdG9sKSB7DQogICAgICByZXR1cm4oYykNCiAgICB9DQogICAgDQogICAgIyBJZiBhbm90aGVyIGl0ZXJhdGlvbiBpcyByZXF1aXJlZCwgDQogICAgIyBjaGVjayB0aGUgc2lnbnMgb2YgdGhlIGZ1bmN0aW9uIGF0IHRoZSBwb2ludHMgYyBhbmQgYSBhbmQgcmVhc3NpZ24NCiAgICAjIGEgb3IgYiBhY2NvcmRpbmdseSBhcyB0aGUgbWlkcG9pbnQgdG8gYmUgdXNlZCBpbiB0aGUgbmV4dCBpdGVyYXRpb24uDQogICAgaWZlbHNlKHNpZ24oZihjKSkgPT0gc2lnbihmKGEpKSwgDQogICAgICAgICAgIGEgPC0gYywNCiAgICAgICAgICAgYiA8LSBjKQ0KICB9DQogICMgSWYgdGhlIG1heCBudW1iZXIgb2YgaXRlcmF0aW9ucyBpcyByZWFjaGVkIGFuZCBubyByb290IGhhcyBiZWVuIGZvdW5kLCANCiAgIyByZXR1cm4gbWVzc2FnZSBhbmQgZW5kIGZ1bmN0aW9uLg0KICBwcmludCgnVG9vIG1hbnkgaXRlcmF0aW9ucycpDQp9DQpgYGANCg0KTm93LCB3ZSBjYW4gYXBwbHkgb3VyIGZ1bmN0aW9uIGZpbmQgdGhlIHJvb3Qgb2YgdGhlIGZ1bmN0aW9uICR4XjPiiJIyeOKIkjUkIGFzIHdlIGhhdmUgZG9uZSBhYm92ZSBieSB1c2luZyBgTkxSb290YCBwYWNrYWdlcy4gDQoNCmBgYHtyfQ0KQmFrdGlfQmlzZWN0aW9uKGZ1bmMsIDIsIDMpDQpgYGANCiMjIyBZb3VyIE93biBGdW5jdGlvbg0KDQpgYGB7cn0NCmxpYnJhcnkoYW5pbWF0aW9uKQ0KYW5pLm9wdGlvbnMobm1heCA9IDMwKQ0KDQojZGVmYXVsdCBleGFtcGxlDQpmID0gZnVuY3Rpb24oeCkgeF4z4oiSMip44oiSNQ0KeHg9IGJpc2VjdGlvbi5tZXRob2QoZiwgYyAoMiwzKSwgdG9sID0gMWUtNyApDQpgYGANCg0KYGBge3J9DQppZihpbnRlcmFjdGl2ZSgpKSBiaXNlY3Rpb24ubWV0aG9kKGYsIGMoMiwzKSwgaW50ZXJhY3Q9IFRSVUUpDQpgYGANCg0KDQojIE5ld3RvbuKAmXMgTWV0aG9kDQoNCg0KVGhlIE5ld3Rvbi1SYXBoc29uIG1ldGhvZCBpcyBhIG1ldGhvZCBmb3IgYXBwcm94aW1hdGluZyB0aGUgcm9vdHMgb2YgcG9seW5vbWlhbCBlcXVhdGlvbnMgb2YgYW55IG9yZGVyLiBJbiBmYWN0IHRoZSBtZXRob2Qgd29ya3MgZm9yIGFueSBlcXVhdGlvbiwgcG9seW5vbWlhbCBvciBub3QsIGFzIGxvbmcgYXMgdGhlIGZ1bmN0aW9uIGlzIGRpZmZlcmVudGlhYmxlIGluIGEgZGVzaXJlZCBpbnRlcnZhbC4gJ3Mgb2Z0ZW4gYmVjb21lIGluY3JlYXNpbmdseSBiZXR0ZXIgYXBwcm94aW1hdGlvbnMgb2YgdGhlIGZ1bmN0aW9uJ3Mgcm9vdC4gTmV3dG9uJ3MgbWV0aG9kIHVzdWFsbHkgdXNlIGZvciBzb2x2aW5nIGVxdWF0aW9ucyBpcyBhbm90aGVyIG51bWVyaWNhbCBtZXRob2QgZm9yIHNvbHZpbmcgYW4gZXF1YXRpb24gJGYoeCk9MCQuIEl0IGlzIGJhc2VkIG9uIHRoZSBnZW9tZXRyeSBvZiBhIGN1cnZlLCB1c2luZyB0aGUgdGFuZ2VudCBsaW5lcyB0byBhIGN1cnZlLiBBcyBzdWNoLCBpdCByZXF1aXJlcyBbY2FsY3VsdXNdKGh0dHBzOi8vdHV0b3JpYWwubWF0aC5sYW1hci5lZHUvY2xhc3Nlcy9jYWxjaS9uZXd0b25zbWV0aG9kLmFzcHgpLCBpbiBwYXJ0aWN1bGFyIGRpZmZlcmVudGlhdGlvbi4gUm91Z2hseSwgdGhlIGlkZWEgb2YgTmV3dG9uJ3MgbWV0aG9kIGlzIGFzIGZvbGxvd3MuDQoNCiMjIE1hdGVtYXRpY2FsIEZvcm11bGENCg0KU28sIGxldCAkZih4KSQgYmUgYSBkaWZmZXJlbnRpYWJsZSBmdW5jdGlvbi4gU2xlY3QgYSBwb2ludCAkeF8wJCBiYXNlZCBvbiBhIGZpcnN0IGFwcHJveGltYXRpb24gdG8gdGhlIHJvb3QuIFRvIGFwcHJveGltYXRlIHdlIGNhbiBjYWx1bGF0ZSB1c2luZyB0aGlzIGZvcm11bGE6IA0KJHhfeyhuKzEpfSQgPSAkbl9uJCAtICRmKHhfbilcb3ZlciBmJyh4X24pJA0KDQojIyBUaGUgTmV3dG9u4oCZcyBBbGdvcml0aG0NCg0KTmV3dG9uJ3MgbWV0aG9kIGlzIGEgd2F5IHRvIGZpbmQgYSBzb2x1dGlvbiB0byB0aGUgZXF1YXRpb24gdG8gYXMgbWFueSBkZWNpbWFsIHBsYWNlcyBhcyB5b3Ugd2FudC4gSXQgaXMgd2hhdCBpcyBjYWxsZWQgYW4gIml0ZXJhdGl2ZSBwcm9jZWR1cmUsJycgbWVhbmluZyB0aGF0IGl0IGNhbiBiZSByZXBlYXRlZCBhZ2FpbiBhbmQgYWdhaW4gdG8gZ2V0IGFuIGFuc3dlciBvZiBncmVhdGVyIGFuZCBncmVhdGVyIGFjY3VyYWN5LiBJdGVyYXRpdmUgcHJvY2VkdXJlcyBsaWtlIE5ld3RvbidzIG1ldGhvZCBhcmUgd2VsbCBzdWl0ZWQgdG8gcHJvZ3JhbW1pbmcgZm9yIGEgY29tcHV0ZXIuVGhlIE5ld3RvbiBhbGdvcml0aG0gY29uc2lzdHMgaW4gcmVwbGFjaW5nIHRoZSBmdW5jdGlvbiB0byBiZSBtaW5pbWl6ZWQgdG8gZ2V0IHRoZSBuZXcgcG9pbnQuIEluIHRoZSBxdWFzaSBOZXd0b24gYWxnb3JpdGhtLCB0aGUgc2Vjb25kIG9yZGVyIHRlcm1zIGluIHRoZSBleHBhbnNpb24gYXJlIHJlcGxhY2VkIGJ5IHNvbWUgYXBwcm94aW1hdGlvbnMuDQoNCiMjIE5ld3RvbuKAmXMgTWV0aG9kIGluIFINCg0KU3VwcG9zZSB3ZSB3YW50IHRvIGZpbmQgdGhlIHJvb3Qgb2YgdGhlIGZ1bmN0aW9uICRmKHgpPXheMuKIkjkgXHRleHR7IGZvciwgIH0geD4wJC4gV2UgYXNzdW1lIHRoYXQgJGYkIGlzIHNtb290aCAoZGlmZmVyZW50aWFibGUpLiBPdXIgZ29hbCBpcyB0byBmaW5kIGEgcm9vdCBvZiAkZiQgaS5lIGEgJHgkIHZhbHVlIGZvciB3aGljaCAkZih4KT0wJC4gV2UgaWxsdXN0cmF0ZSB0aGUgbWV0aG9kIHdpdGggYSBzaW1wbGUgZXhhbXBsZSBmb3Igd2hpY2ggeW91IGtub3cgdGhlIHJvb3QuDQoNCiMjIyBWaXN1YWxpemUgdGhlIGZ1bmN0aW9uDQoNCmBgYHtyfQ0KIyBmaXJzdCBnZW5lcmF0ZSB0aGUgc2VxdWVuY2UNCnguc2VxIDwtIHNlcShmcm9tID0gMC4xLCB0byA9IDEwLCBsZW5ndGgub3V0ID0gMTAxKQ0KZiA8LSBzYXBwbHkoeC5zZXEsIGZ1bmN0aW9uKHgpIHheMiAtIDkpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCiMgcHV0IHRoZSB4IGFuZCB5IHZhbHVlcyBpbiBhIGRhdGEgZnJhbWUNCnBsb3RfZGF0YSA8LSBkYXRhLmZyYW1lKCJ4IiA9IHguc2VxLCAiZiIgPSBmKQ0KaGVhZChwbG90X2RhdGEpDQpgYGANCmBgYHtyfQ0KIyBjcmVhdGUgdGhlIGJhc2UgbGF5ZXIgb2YgZ2dwbG90IHdpdGggZ2VvbV9MaW5lDQpwbG90X2YgPC0gZ2dwbG90KHBsb3RfZGF0YSwgYWVzKHggPSB4LCB5ID0gZikpICsgDQogIGdlb21fbGluZShjb2xvciA9ICJyZWQiLCBzaXplID0gMS4wKSArIA0KICBsYWJzKHggPSAieCIsIHkgPSAiZih4KSA9IHheMiAtIDkiKQ0KIyBiZWF1dGlmeSA6IEluY3JlYXNlIGZvbnQgc2l6ZSBpbiBheGVzIA0KcGxvdF9mICsgdGhlbWUoYXhpcy50ZXh0LnggPSANCiAgICAgICAgICAgICAgICAgZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsc2l6ZSA9IDEyKSwNCiAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gDQogICAgICAgICAgICAgICAgIGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTIpLA0KICAgICAgICAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIsIA0KICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJzb2xpZCIpKQ0KYGBgDQpCeSBjb25zaWRlcmluZyB0aGUgdmlzdWFsaXphdGlvbiBhYm92ZSwgaXQncyBsb29rcyBsaWtlIHRoZSBmdW5jdGlvbiBpcyAwIGFyb3VuZCAzLiBIb3cgZG8gd2Uga25vdyB0aGF0IGV4YWN0bHkgY29ycmVjdCwgbGV0J3MgdHJ5IHpvb20gdGhlIHZpc3VhbGl6YXRpb24uDQoNCmBgYHtyfQ0KcGxvdF9mICsgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMDAsIGNvbG9yID0gImdyZWVuIiwgc2l6ZSA9IDEpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDIsNCksIHlsaW0gPSBjKC0xLCAzKSkNCmBgYA0KDQpOZXh0LCBsZXQgdXMgdmlzdWFsaXplIHRoaXMgdG8gZmluZCB0aGUgcm9vdCBvZiBvdXIgZnVuY3Rpb24gJGYoeCk9eF4y4oiSOS4kIEZpcnN0IHdlIG5lZWQgdG8gY3JlYXRlIGEgZnVuY3Rpb24gdGhhdCByZXR1cm5zIHRoZSB0YW5nZW50IGxpbmUgdG8gdGhlIGZ1bmN0aW9uIGYgYXQgc29tZSBwb2ludCBhLg0KDQpgYGB7cn0NCiMgTGV0IHVzIGNyZWF0ZSBvdXIgdGFuZ2VudCBsaW5lIGZ1bmN0aW9uIGF0IHNvbWUgcG9pbnQgYQ0KZl90YW5nZW50IDwtIGZ1bmN0aW9uKHgsIGYsIGRmLCBhKXsNCiAgIyBXZSBuZWVkIHRoZSBmdW5jdGlvbiBhbmQgaXRzIGRlcml2YXRpdmUgZGYNCiAgIyBhIGlzIHRoZSBwb2ludCB3aGVyZSB3ZSBjcmVhdGUgdGhlIHRhbmdlbnQgdG8gdGhlIGZ1bmN0aW9uDQogICMgcmV0dXJucyB0aGUgdGFuZ2VudCBsaW5lIA0KICBkZihhKSooeCAtIGEpICsgZihhKQ0KfQ0KYGBgDQoNClRoZW4sIHBsb3QgdGhlIHRhbmdlbnQgbGluZSB0byB0aGUgaW5pdGlhbCB2YWx1ZSAkZiQgIGF0ICR4KDApPTQkICB3aGljaCB3aWxsIGJlIG91ciBmaXJzdCBndWVzcyBvZiB0aGUgcm9vdC4NCg0KYGBge3J9DQojIGFkZCB0aGUgdGFuZ2VudCBsaW5lIGF0IDQgdG8gb3VyIGRhdGEgZnJhbWUNCnBsb3RfZGF0YSRmLnRhbiA8LSBzYXBwbHkocGxvdF9kYXRhJHgsIGZfdGFuZ2VudCwgZiA9IGZ1bmN0aW9uKHgpIHheMiAtIDksIGRmID0gZnVuY3Rpb24oeCkgMip4LCBhID0gNCkNCg0KIyBjcmVhdGUgdGhlIGJhc2UgbGF5ZXIgb2YgZ2dwbG90IHdpdGggZ2VvbV9MaW5lDQpwbG90X3RhbmdlbnRfbGluZSA8LSBnZ3Bsb3QocGxvdF9kYXRhLCBhZXMoeCA9IHgpKSArIA0KICBnZW9tX2xpbmUoYWVzKHkgPSBmKSwgY29sb3IgPSAicmVkIiwgc2l6ZSA9IDAuOTUpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gZi50YW4pLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDAuOTUpICsNCiAgbGFicyh4ID0gIngiLCB5ID0gImYoeCkgYW5kIHRhbmdlbnQgbGluZSBhdCA0IikgDQpwbG90X3RhbmdlbnRfbGluZQ0KYGBgDQoNCk5leHQsIGxldCB1cyB6b29tIGluIG9uICQy4omkeOKJpDQkIGFuZCB0cnkgdG8gc2VlIHdoZXJlIHRoZSB0YW5nZW50IGxpbmUgaXMgZXF1YWwgdG8gMC4NCg0KYGBge3J9DQojIHpvb20gaW4gYmV0d2VlbiAzIGFuZCA0DQpwbG90X3RhbmdlbnRfbGluZSArIA0KICAjIGFkZCBhIGhvcml6b250YWwgbGluZSBhdCAwDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMDAsIGNvbG9yID0gImdyZWVuIiwgc2l6ZSA9IDEpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDIsNCksIHlsaW0gPSBjKC01LCAxMCkpDQpgYGANCg0KQnkgY29uc2lkZXJpbmcgdGhlIHZpc3VhbGl6YXRpb24gYWJvdmUsIGxvb2tzIGxpa2UgdGhlIHRhbmdlbnQgbGluZSBpcyAwIGFyb3VuZCAzLjEuIFRoaXMgd2lsbCBiZSBvdXIgdXBkYXRlZCBndWVzcyBhdCB0aGUgcm9vdC4gVW5kZXJzdGFuZCB0aGUgcmF0aW9uYWxlIGJlaGluZCB0aGlzLiBJZiBmIGlzIGFwcHJveGltYXRlbHkgZXF1YWwgdG8gaXRzIHRhbmdlbnQgbGluZSBhdCA0LCB0aGVuIHRoZSByb290IG9mICRmJCBpcyBhcHByb3hpbWF0ZWx5IGVxdWFsIHRvIHRoZSByb290IG9mIHRoZSB0YW5nZW50IGxpbmUuIENhbiB5b3Ugc2VlIHRoaXMgaW4gdGhlIHBsb3QgYWJvdmU/DQoNClRoZSBleGFjdCB2YWx1ZSB3aGVuIHRoZSB0YW5nZW50IGxpbmUgaXMgMCBpcyBnaXZlbiBieQ0KDQokJCB4XnsoMSl9PTTiiJJ7Zig0KSBcb3ZlciBm4oCyKDQpfSA9My4xMjUkJA0KDQpUaGVuLCBhZGQgdGhlIHRhbmdlbnQgbGluZSBhdCAzLjEyNSB0byBvdXIgZGF0YSBmcmFtZQ0KDQpgYGB7cn0NCnBsb3RfZGF0YSRmLnRhbiA8LSBzYXBwbHkocGxvdF9kYXRhJHgsIGZfdGFuZ2VudCwgZiA9IGZ1bmN0aW9uKHgpIHheMiAtIDksIGRmID0gZnVuY3Rpb24oeCkgMip4LCBhID0gMy4xMjUpDQoNCiMgY3JlYXRlIHRoZSBiYXNlIGxheWVyIG9mIGdncGxvdCB3aXRoIGdlb21fTGluZQ0KcGxvdF90YW5nZW50X2xpbmUgPC0gZ2dwbG90KHBsb3RfZGF0YSwgYWVzKHggPSB4KSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gZiksIGNvbG9yID0gInJlZCIsIHNpemUgPSAwLjk1KSArDQogIGdlb21fbGluZShhZXMoeSA9IGYudGFuKSwgY29sb3IgPSAiYmx1ZSIsIHNpemUgPSAwLjk1KSArDQogIGxhYnMoeCA9ICJ4IiwgeSA9ICJmKHgpIGFuZCB0YW5nZW50IGxpbmUgYXQgNCIpIA0KcGxvdF90YW5nZW50X2xpbmUNCmBgYA0KDQpOb3cgbGV0IHVzIHpvb20gaW4gb24gYXJvdW5kIDMgYW5kIHRyeSB0byBzZWUgd2hlcmUgdGhlIHRhbmdlbnQgbGluZSBpcyBlcXVhbCB0byAwLg0KDQpgYGB7cn0NCiMgem9vbSBpbiBiZXR3ZWVuIDIuOSBhbmQgMy4xDQpwbG90X3RhbmdlbnRfbGluZSArIA0KICAjIGFkZCBhIGhvcml6b250YWwgbGluZSBhdCAwDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuMDAsIGNvbG9yID0gImdyZWVuIiwgc2l6ZSA9IDEpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDIuOSwzLjEpLCB5bGltID0gYygtMi41LCAyLjUpKQ0KYGBgDQoNCkxvb2tzIGxpa2UgdGhlIHRhbmdlbnQgbGluZSBpcyAwIGFyb3VuZCAzLiBJbiBqdXN0IHR3byBzdGVwcyB3ZSBhcmUgdmVyeSBjbG9zZS4gVGhpcyB3aWxsIGJlIG91ciB1cGRhdGVkIGd1ZXNzIGF0IHRoZSByb290LiBUaGUgZXhhY3QgdmFsdWUgd2hlbiB0aGUgdGFuZ2VudCBsaW5lIGlzIDAgaXMgZ2l2ZW4gYnkNCg0KJCQgeF57KDIpfT14XnsoMSl94oiSe2YoeF57KDEpfSkgXG92ZXIgZuKAsih4XnsoMSl9KX0kJA0KJCQgeF57KDIpfT0zLjEyNeKIkntmKDMuMTI1KSBcb3ZlciBm4oCyKDMuMTI1KX0gPSAzLjAwMjUkJA0KDQpXZSBjYW4gY29udGludWUgdW50aWwgb3VyIGd1ZXNzZXMga2VlcCBnZXR0aW5nIHNtYWxsZXIgYW5kIHNtYWxsZXIuDQoNCiMjIyBVc2UgYE5MUm9vdGAgcGFja2FnZXMNCg0KVGhlIHNhbWUgcGFja2FnZXMgYXMgd2UgdXNlIHRvIHRoZSBCaXNlY3Rpb24gTWV0aG9kLCB0aGlzIHBhY2thZ2VzIGFsc28gYXZhaWxhYmxlIGZvciBOZXd0b24ncyBtZXRob2QuIA0KDQpgYGB7cn0NCmxpYnJhcnkoTkxSb290KQ0KIyBmaXJzdCBhcmd1bWVudCBpcyB0aGUgZnVuY3Rpb24gd2hvc2Ugcm9vdCB3ZSBuZWVkIHRvIGZpbmQNCiMgc2Vjb25kIGFyZ3VtZW50IGlzIHRoZSB0aGUgZGVyaXZhdGl2ZSBvZiB0aGUgZnVuY3Rpb24gd2hvc2UgDQojIHJvb3Qgd2UgbmVlZCB0byBmaW5kLg0KIyB0aGlyZCBhcmd1bWVudCBpcyBhbiBpbml0aWFsIGd1ZXNzDQpOSU1memVybyhmdW5jdGlvbih4KSB4XjItOSwgZnVuY3Rpb24oeCkgMip4LCB4MCA9IDQpDQpgYGANCg0KDQojIFtDYXNlIFN0dWR5XShodHRwczovL3JwdWJzLmNvbS9qX2xhcG9ydGUvNTY0MjgwKSANCg0KIyMgTGVzc29uMTogTW9kZWwgQnVpbGRpbmcgLSBSIHR1dG9yaWFsDQoNCkluIHRoaXMgbGVzc29uIHdlIHdpbGwgY29uc3RydWN0IHR3byBmdW5jdGlvbnMgdGhhdCB5b3Ugd2lsbCBuZWVkIGZvciB0aGlzIGNvdXJzZSBhbmQgYmVnaW4gdG8gZXhwbG9yZSB0aGUgUiBwcm9ncmFtbWluZyBsYW5ndWFnZS4gUnVuIHRocm91Z2ggdGhlIENoYXB0ZXIgMSBvZiB0aGUgYm9vayB3aGljaCB0YWxrcyBhYm91dCBtb2RlbCBidWlsZGluZyBmb3IgYSBvbmUtdmFyaWFibGUgb3B0aW1pemF0aW9uIHByb2JsZW0uIEV4YW1wbGUgMS4xIChNZWVyc2NoYWVydCkgQSBwaWcgd2VpZ2hpbmcgMjAwIGxicyBnYWlucyA1IGxicyBwZXIgZGF5IGFuZCBjb3N0cyA0NSBjZW50cyBwZXIgZGF5IHRvIGtlZXAgKGZlZWQgYW5kIGJvYXJkKS4gVGhlIG1hcmtldCBwcmljZSBmb3IgcGlncyBpcyA2NSBjZW50cyBwZXIgcG91bmQsIGJ1dCBpcyBmYWxsaW5nIDEgY2VudCBwZXIgZGF5LiBXaGVuIHNob3VsZCB0aGUgcGlnIGJlIHNvbGQ/DQoNCiMjIyBNb2RlbGluZyB0aGUgUHJvYmxlbSBWYXJpYWJsZXM6DQoNCiAgJHQkID0gdGltZSAoZGF5cykNCg0KICAkdyQgPSB3ZWlnaHQgb2YgdGhlIHBpZyhsYnMpDQoNCiAgJHAkID0gcHJpY2UgZm9yIHBpZ3MgKCQvbGIpDQoNCiAgJEMkID0gY29zdCBvZiBrZWVwaW5nIHBpZyB0IGRheXMgKCQpDQoNCiAgJFIkID0gcmV2ZW51ZSBvYnRhaW5lZCBieSBzZWxsaW5nIHBpZyAoJCkNCg0KICAkUCQgPSBwcm9maXQgZnJvbSBzZWxsaW5nIHBpZyAoJCkNCg0KQXNzdW1wdGlvbnM6DQoNCiAgJHc9MjAwKzV0JA0KDQogICRwPTAuNjXiiJIwLjAxdCQNCg0KICAkQz0wLjQ1dCQNCg0KICAkUj1w4ouFdyQNCg0KICAkUD1S4oiSQyQNCg0KICAkdD49MCQNCg0KT2JqZWN0aXZlOiBNYXhpbWl6ZSBwcm9maXRzIGZyb20gdGhlIHNlbGwgb2YgdGhlIHBpZw0KTGV0IHggYmUgdGhlIHRpbWUgdG8gc2VsbCB0aGUgcGlnIGFuZCBkZXZlbG9wIHRoZSBwcm9maXQgZnVuY3Rpb24gdXNpbmcgeCBhcyB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUuIEluIHRoZSBjYXNlIG9mIGFuIG9wdGltaXphdGlvbiwgdGhlIHZhcmlhYmxlIG9uIHdoaWNoIHlvdSB3aWxsIG1ha2UgYSBkZWNpc2lvbiBvbiBpcyBnZW5lcmFsbHkgY2FsbGVkIGEgZGVjaXNpb24gdmFyaWFibGUuIFRoZXJlIGNhbiBiZSBtdWx0aXBsZSBkZWNpc2lvbiB2YXJpYWJsZXMgaW4gYSBwcm9ibGVtLg0KDQojIyMgUHJvZml0IEZ1bmN0aW9uID0gT2JqZWN0aXZlIGZ1bmN0aW9uDQoNCkdpdmVuIHRoZSBkZXNjcmlwdGlvbiBhbmQgbWF0aGVtYXRpY2FsIGV4cGxhbmF0aW9uIG9mIHRoZSB2YXJpYWJsZXMsIGxldHMgd3JpdGUgb3V0IHRoZSBwcm9maXQgZnVuY3Rpb246DQoNCmBgYHtyfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL3VzZXIvRG93bmxvYWRzLzEucG5nIikNCmBgYA0KDQpMZXRzIHVzZSBSIHRvIOKAnHNlZeKAnSB3aGF0IHRoZSBwcm9maXQgZnVuY3Rpb24gbG9va3MgbGlrZSBvdmVyIHRoZSBuZXh0IDIwIGRheXMuDQpgYGB7cn0NCnByb2ZpdCA9IGZ1bmN0aW9uICh4KXsNCiAgcmV0dXJuKCgwLjY1LTAuMDEqeCkqKDIwMCs1KngpLS40NSp4KQ0KfQ0KeCA9IHNlcSgwLDIwLDEpDQpwbG90KHgscHJvZml0KHgpLHR5cGU9Im8iKQ0KYGBgDQoNCmBgYHtyfQ0KcHJpbnQocHJvZml0KDgpKQ0KYGBgDQoNCkFzIHlvdSBjYW4gc2VlLCB0aGVyZSBpcyBhIGdvb2QgYW5kIGJhZCBkYXkgdG8gc2VsbCB0aGUgcGlnIGlmIG91ciBhc3N1bXB0aW9ucyByZW1haW4gdGhlIHNhbWUgb3ZlciB0aGUgbmV4dCAyMCBkYXlzLiBBbHRob3VnaCB3ZSBjb3VsZCB1c2UgdGhpcyBncmFwaCBpbiBvcmRlciB0byBzZWxlY3QgdGhlIOKAnHdpbm5lcuKAnSwgd2Ugd2FudCB0byBiZSBhYmxlIHRvIHVzZSB0aGlzIHRvb2wgKFIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UpIHRvIGFzc2lzdCB1cyBpbiBlbnN1cmluZyB0aGF0IHdlIGhhdmUgYWxsIG9mIHRoZSBpbmZvcm1hdGlvbiBuZWVkZWQgdG8gbWFrZSBhIGRlY2lzaW9uLiBUaGF0IG1lYW5zIHRoYXQgd2UgbmVlZCB0byBnZXQgb3VyIGhhbmRzIGRpcnR5IGFuZCBmaWd1cmUgb3V0IGhvdyB0byB1c2Ugb3VyIHRvb2xzIChpbiB0aGlzIGNhc2UsIFIpLg0KDQojIyMgQnVpbGQgdGhlIGZ1bmN0aW9ucyB0aGF0IHdlIG5lZWQgdG8gc29sdmUgdGhlIHByb2JsZW0NCg0KV2Ugd2lsbCBjcmVhdGUgdHdvIGZ1bmN0aW9ucyB0aGF0IHdpbGwgYmUgYWJsZSB0byBzb2x2ZSBmb3IgYW4gb3B0aW1hbCBwb2ludCBpbiBSIHVzaW5nIG1hdGhlbWF0aWNzIC8gcHJvZ3JhbW1pbmcgdGhhdCB3ZSBhbHJlYWR5IGtub3cgaG93IHRvIGRvLiBGcm9tIGNhbGN1bHVzLCB5b3Ugc2hvdWxkIHJlbWVtYmVyIHRoZSBkZWZpbml0aW9uIG9mIHRoZSBkZXJpdmF0aXZlIGFuZCB3aHkgdHdlYWtpbmcgaXQgYSBsaXR0bGUgY2FuIGdldCB1cyBhIGJldHRlciBlc3RpbWF0aW9uIG9mIHRoZSBkZXJpdmF0aXZlIG9mIGEgZnVuY3Rpb246DQoNCmBgYHtyfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL3VzZXIvRG93bmxvYWRzLzIucG5nIikNCmBgYA0KDQpVc2luZyB0aGlzIHNpbXBsZSBmb3JtdWxhLCBsZXTigJlzIGJ1aWxkIGEgZGVyaXZhdGl2ZSBvZiB0aGUgcHJvZml0IGZ1bmN0aW9uIHRoYXQgd2UgZGVmaW5lZCBhYm92ZS4gTm90aWNlIGhvdyBvdXIgZnVuY3Rpb24gZnByaW1lICQoZix4KSQgd2lsbCB3b3JrIGZvciBBTlkgZnVuY3Rpb24gdGhhdCB3ZSBhc3NpZ24gdG8gaXQuDQoNCmBgYHtyfQ0KeD1zZXEoMCwyMCkNCmZwcmltZSA9IGZ1bmN0aW9uIChmLGEsaD0wLjAwMDEpeyhmKGEraCktZihhLWgpKS8oMipoKX0NCnBsb3QoeCxmcHJpbWUocHJvZml0LHgpKQ0KYGBgDQoNCiMjIyBSb290LUZpbmRpbmcgU29sdmVyDQoNCkFsdGhvdWdoIHdlIGNvdWxkIHVzZSB0aGUgZ3JhcGggYWJvdmUgdG8gZmluZCB0aGUgc29sdXRpb24gZm9yIHRoaXMgcGFydGljdWxhciBwcm9ibGVtLCBpdCBpcyBtb3JlIGFwcHJvcHJpYXRlIHRvIHVzZSBtYXRoIHRvIG1ha2Ugb3VyIHNvbHV0aW9uIGF1dG9tYXRpYy4gVGhlcmUgYXJlIG1hbnkgcm9vdC1maW5kaW5nIGFsZ29yaXRobXMgb3V0IHRoZXJlIGFuZCBmZWVsIGZyZWUgdG8gdXNlIGFub3RoZXIsIGJ1dCB3ZSB3aWxsIHVzZSBhIHNpbXBsZSBhbGdvcml0aG0ga25vd24gYXMgdGhlIGJpc2VjdGlvbiBtZXRob2QuIFRoaXMgbWV0aG9kIG9ubHkgcmVxdWlyZXMgdGhhdCB5b3Ugc2VsZWN0IHR3byBwb2ludHMgdGhhdCBoYXZlIG9wcG9zaXRlIHNpZ25zOiBpZiAkZihhKT3iiJIkIHRoZW4gJGYoYik9KyQuDQoNCiMjIyMgQmlzZWN0aW9uIEFsZ29yaXRobSBmb3IgZmluZGluZyB0aGUgcm9vdCBvZiBhbiBlcXVhdGlvbi4NCg0KVGhlIHNpbXBsZSBpZGVhIG9mIHRoZSBiaXNlY3Rpb24gbWV0aG9kIGlzIHRoYXQgeW91IHN0YXJ0IHdpdGggYW4gaW50ZXJ2YWwgJFthLGJdJCB0aGF0IGhhcyBhIHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSB2YWx1ZSBmb3IgdGhlIGZ1bmN0aW9uICRmKGEpJCBhbmQgJGYoYikkIC0gaXQgZG9lcyBub3QgbWF0dGVyIHdoaWNoIG9uZSBpcyBwb3NpdGl2ZS4gWW91IGN1dCB0aGUgaW50ZXJ2YWwgaW4gaGFsZiBhbmQgcHJvY2VlZCB3aXRoIHRoZSBpbnRlcnZhbCB0aGF0IGtlZXBzIG9uZSBzaWRlIHBvc2l0aXZlIGFuZCB0aGUgb3RoZXIgbmVnYXRpdmUuIEluIEZpZ3VyZSAxLCB3ZSBzdGFydCBvbiB0aGUgaW50ZXJ2YWwgJFsyLDldJCB3aGljaCB3b3JrcyBiZWNhdXNlICRmKDIpJCBpcyBwb3NpdGl2ZSBhbmQgJGYoOSkkIGlzIG5lZ2F0aXZlLiBUaGUgZmlyc3Qgc3RlcCBjdXRzIHRoZSBpbnRlcnZhbCBpbiBoYWxmIGFuZCB0aGUgZGVjaXNpb24gbXVzdCBiZSBtYWRlIHRvIGNvbnRpbnVlIHdpdGggJFsyLDUuNV0kIG9yICRbNS41LDldJC4gSXQgc2hvdWxkIGJlIHByZXR0eSBvYnZvdXMgZnJvbSB0aGUgcGljdHVyZSB0aGF0ICRbMiw1LjVdJCBpcyB0aGUgcmlnaHQgYW5zd2VyICh3ZSB3YW50IHRvIGtlZXAgYSByb290IGluIHRoZSBpbnRlcnZhbCksIGJ1dCBmcm9tIGFuIGFsZ29yaXRobSBwZXJzcGVjdGl2ZSwgd2Ugc2ltcGx5IHRlc3QgJGYoNS41KSQgYW5kIGZpbmQgb3V0IHRoYXQgaXQgaXMgbmVnYXRpdmUgd2hpY2ggY2F1c2VzIHVzIHRvIHJlcGxhY2UgOSAoJGZbOV0kIHdhcyBuZWdhdGl2ZSkgd2l0aCA1LjUuIFdlIHdvdWxkIGNvbnRpbnVlIHRoaXMgYWxnb3JpdGhtIHVudGlsIHdlIGFyZSBzYXRpc2ZpZWQgdGhhdCB0aGUgd2lkdGggb2YgdGhlIGludGVydmFsIGlzIHNtYWxsIGVub3VnaCB0byBtYWtlIGEgY29uY2x1c2lvbiBhYm91dCB0aGUgdmFsdWUgb2YgdGhlIHJvb3QuDQoNCmBgYHtyfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoIkM6L1VzZXJzL3VzZXIvRG93bmxvYWRzLzMucG5nIikNCmBgYA0KDQpgYGB7cn0NCmJpc2VjdGlvbiA9IGZ1bmN0aW9uKGYsYSxiLHRvbD0wLjAwMDEpew0KICBpZiAoZihhKSpmKGIpID4gMCl7DQogICAgcmV0dXJuICgiQm91bmRhcnkgQ29uZGl0aW9ucyBOb3QgTWV0IikNCiAgfQ0KICBlbHNlew0KICAgIG1pZGRsZSA9IGENCiAgICB3aGlsZSAoYWJzKGYobWlkZGxlKSk+dG9sKXsNCiAgICAgIG1pZGRsZSA9IChhK2IpLzINCiAgICAgIGlmIChmKG1pZGRsZSkqZihhKT4wKSAoYSA9IG1pZGRsZSkNCiAgICAgIGVsc2UgKGIgPSBtaWRkbGUpDQogICAgICB4PW1pZGRsZQ0KICAgICAgeT1mKG1pZGRsZSkNCiAgICAgICMjIGlmIHlvdSB3YW50IHRvICJzZWUiIHdoYXQgaGFwcGVucyBhdCBldmVyeSBzdGVwLCB0YWtlIG9mZiB0aGUgIyBvZiB0aGUgbmV4dCBsaW5lICMjDQogICAgICAjY2F0KHNwcmludGYoIngtVmFsOiAlLjRmIDsgZih4LXZhbCk6ICUuNGZcbiIseCx5KSkNCiAgICB9DQogICAgcmV0dXJuIChtaWRkbGUpDQogIH0NCn0NCiNFeGFtcGxlIG9mIGEgZmluZGluZyBhIHJvb3Qgb2YgYSBmdW5jdGlvbg0KZiA9IGZ1bmN0aW9uICh4KXt4XjMtNX0gI3NpbmxnZSBsaW5lIGZ1bmN0aW9uIGRlZmluaXRpb24NCnplcm89YmlzZWN0aW9uIChmLC0xMCwyMCkNCng9c2VxKC0xLDIsMC4wMSkNCnBsb3QoeCxmKHgpLCJsIikNCmFibGluZShoPTAsY29sPSJyZWQiKQ0KYWJsaW5lKHY9emVybyxjb2w9ImJsdWUiKQ0KYGBgDQoNCmBgYHtyfQ0KcHJpbnQoemVybykNCmBgYA0KDQojIyMgVXNlIG91ciB0b29sIHRvIHNvbHZlIHRoZSBwaWcgcHJvYmxlbQ0KDQpVc2UgdGhlIHRvb2xzIGF0IHlvdXIgZGlzcG9zYWwgdG8gc29sdmUgdGhlIHByb2JsZW0uIEJlIGFibGUgdG8gbWFrZSBzZXZlcmFsIGFsdGVybmF0aXZlcyB0byB0aGUgcHJvcG9zZWQgbW9kZWwgYW5kIGludmVzdGlnYXRlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBtdWx0aXBsZSB2YXJpYWJsZXMuIFdoZW4gZG8gd2Ugc2VsbCB0aGUgcGlnPw0KDQpgYGB7cn0NCmRQcm9maXQgPSBmdW5jdGlvbih4KXtmcHJpbWUocHJvZml0LHgpfSAjZGVyaXZhdGl2ZSBvZiBwcm9maXQgZnVuY3Rpb24NCmJpc2VjdGlvbihkUHJvZml0LDAsMjApDQpgYGANCg0KQXMgeW91IGNhbiBzZWUsIHdlIGdvdCBhcHByb3hpbWF0ZWx5IHRoZSBzYW1lIGFuc3dlciBhcyB0aGUgYm9vay4gVGhlIGRpZmZlcmVuY2UgaXMgdGhhdCBvdXIgc29sdXRpb24gdXNlcyBhbiBlc3RpbWF0aW9uIG9mIHRoZSBkZXJpdmF0aXZlIGluc3RlYWQgb2YgdGhlIGNsb3NlZC1mb3JtIHNvbHV0aW9uIGFzIHdlbGwgYXMgYSBzb2x2ZXIgZm9yIGZpbmRpbmcgdGhlIGRheSAkeCQgd2hlcmUgdGhlIHByb2ZpdCBpcyBtYXhpbWl6ZWQgKHByb2ZpdCBmdW5jdGlvbiBkZXJpdmF0aXZlID0gMCkuIEluIHRoZSBjYXNlIG9mIG1vc3QgcHJvYmxlbXMsIHlvdSB3aWxsIHVzZSBudW1lcmljYWwgbWV0aG9kcyAobGlrZSB3ZSBkaWQpIGJlY2F1c2UgcmVhbCB3b3JsZCBwcm9ibGVtcyBkbyBub3QgdXN1c2FsbHkgaGF2ZSBhIGVhc3kgYW5zd2VyLiBUbyBiZWNvbWUgYSBnb29kIHByb2JsZW0gc29sdmVyLCB5b3UgYXJlIGdvaW5nIHRvIG5lZWQgdG8gaW52ZXN0IGluIHlvdXIgY29kaW5nIGFiaWxpdGllcyBiZWNhdXNlIHlvdSB3aWxsIHVzdWFsbHkgbmVlZCB0byBkZXZlbG9wIHNvbWUgb3JpZ2luYWwgY29kZSB0byBoZWxwIHlvdSBzb2x2ZSBhIHBhcnRpY3VsYXIgcHJvYmxlbS4NCg0KIyMjIFNlbnNpdGl2aXR5IEFuYWx5c2lzOiBQcmljZSBvZiB0aGUgUGlnDQoNCkxldOKAmXMgZ28gYmFjayBhbmQgZXhhbWluZSBtb3JlIGNsb3NlbHkgb25lIG9mIG91ciBvcmlnaW5hbCBhc3N1bXB0aW9ucyB0aGF0IG1heSBvciBtYXkgbm90IGhvbGQgdG8gc2VlIGhvdyBvdXIgc29sdXRpb24gaXMgYWZmdGVjdGVkIGJ5IGEgZGlmZmVyZW50IGFzc3VtcHRpb24uIERvZXMgdGhlIG9wdGltYWwgZGF5IHRvIHNlbGwgY2hhbmdlIGlmIHdlIGFzc3VtZSBzb21lIGRpZmZlcmVudCBwcmljZSBvZiB0aGUgcGlnLiBIZXJlIHdlIGxldCB0aGUgcGlnIHByaWNlIGRyb3AgdG8gcmVjcmVhdGUgdGhlIG51bWJlcnMgaW4gdGhlIGJvb2ssIGJ1dCB3ZSBhcmUgYWJsZSB0byBkbyBzbyBtdWNoIG1vcmUgd2hpY2ggd2lsbCBiZSBkZW1vbnN0cmF0ZWQgaW4gdGhlIG5leHQgYW5hbHlzaXMuDQoNCmBgYHtyfQ0KI1ByaWNlIGZhbGxpbmcgcGVyIGRheSA9IHAgDQpwID0gc2VxKDAuMDA4LDAuMDEyLDAuMDAxKQ0KYW5zID0gYXJyYXkoMCxsZW5ndGgocCkpDQpmb3IgKGkgaW4gMTpsZW5ndGgocCkpew0KICAgIHByb2ZpdCA9IGZ1bmN0aW9uICh4KXsNCiAgICAgIHJldHVybigoMC42NS1wW2ldKngpKigyMDArNSp4KS0uNDUqeCkNCiAgICB9DQogICAgZFByb2ZpdCA9IGZ1bmN0aW9uKHgpe2ZwcmltZShwcm9maXQseCwpfQ0KICAgIGFuc1tpXSA9IGJpc2VjdGlvbihkUHJvZml0LDAsMjAsMC4wMDAxKQ0KfQ0KcHJpbnQoYW5zKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChwLGFucywibyIseGxhYj0icCgkL2RheSkiLHlsYWI9IngoRGF5cyB0byBTZWxsKSIpDQp0aXRsZSgiU2Vuc2l0aXZpdHkgb2YgRmFsbGluZyBQcmljZSBvZiBQaWciKQ0KYGBgDQoNCiMjIyBTZW5zaXRpdml0eSBBbmFseXNpczogR3Jvd3RoIFJhdGUgb2YgdGhlIFBpZw0KDQpTaW5jZSB3ZSBhcmUgYWxzbyBjb25jZXJuZWQgYWJvdXQgdGhlIGdyb3d0aCByYXRlIG9mIHRoZSBwaWcsIGxldOKAmXMgY29uZHVjdCBzZWUgaG93IHRoZSBkYXlzIHRvIHNlbGwgYXJlIGFmZmVjdGVkIGJ5IHRoZSBncm93dGggcmF0ZS4gVGhlIHdlaWdodCAoJHckKSBpcyBjYWxjdWxhdGVkIHVzaW5nIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIHBpZyB3aWxsIGdyb3cgNWxicyBwZXIgZGF5IHNvIHRoYXQ6ICR3PTIwMCtndCQgd2hlcmUgJGc9NSQuIExldOKAmXMgc2VlIHdoYXQgaGFwcGVucyBpZiAkZyQgaXMgYmV0d2VlbiAzIGFuZCA3LiBSZW1lbWJlciB0aGUgYmlzZWN0aW9uIG1ldGhvZCBuZWVkcyB0d28gYm91bmRhcnkgcG9pbnRzIHRoYXQgaGF2ZSB0aGUgb3Bwb3NpdGUgdmFsdWVzIGFuZCBpZiB0aGUgZ3Jvd3RoIHJhdGUgaXMgdG9vIHNtYWxsLCB0aGluayBhYm91dCB3aGF0IHRoYXQgZG9lcyB0byB0aGUgcHJvZml0LiBFeHBlcmltZW50IHdpdGggbGFyZ2UgYW5kIHNtYWxsIGdyb3d0aCByYXRlcyBhbmQgdGhlIHByb2ZpdCBmdW5jdGlvbiB0byBmaWd1cmUgaXQgb3V0IGZvciB5b3Vyc2VsZiBpZiB5b3UgZG9u4oCZdCBzZWUgaXQuIFdlIG5lZWRlZCB0byBtYWtlIHRoZSBzdGFydGluZyBwb2ludCBvZiB0aGUgYmlzZWN0aW9uIG1ldGhvZCB0byB0aGUgbGVmdCAobmVnYXRpdmUgbnVtYmVyKSBpbiBvcmRlciBmb3IgaXQgdG8gZmluZCB0aGUgemVybyBmb3IgM2xicyBhbmQgMy41bGJzIHBlciBkYXkuDQoNCmBgYHtyfQ0KI0dyb3d0aCByYXRlIG9mIHRoZSBwaWcgPSBnDQpnID0gc2VxKDEsMTIsMC41KQ0KYW5zID0gYXJyYXkoMCxsZW5ndGgoZykpDQpmb3IgKGkgaW4gMTpsZW5ndGgoZykpew0KICAgIHByb2ZpdCA9IGZ1bmN0aW9uICh4KXsNCiAgICAgIHJldHVybigoMC42NS0wLjAxKngpKigyMDArZ1tpXSp4KS0uNDUqeCkNCiAgICB9DQogICAgZFByb2ZpdCA9IGZ1bmN0aW9uKHgpe2ZwcmltZShwcm9maXQseCwpfQ0KICAgIGFuc1tpXSA9IGJpc2VjdGlvbihkUHJvZml0LC0xMDAsNTAsMC4wMDAxKQ0KfQ0KcHJpbnQoYW5zKQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChnLGFucywibyIseGxhYj0iZyhncm93dGgvZGF5KSIseWxhYj0ieChEYXlzIHRvIFNlbGwpIikNCnRpdGxlKCJTZW5zaXRpdml0eSBvZiBHcm93dGggUmF0ZSBvZiBQaWciKQ0KYGBgDQoNCg0KDQo=