1 Using future

[1] "1.14.0"

The package future (Bengtsson (2019)) allows a single-threaded R process to launch a task in another thread to achieve asynchronous programming. It is the main entry point for a task to be asynchronous.

To make an expression a Future, we simply wrap it with a future function call:

Then we can collect the result of a Future:

[1] 2

In order for a Future to be useful, we need to configure the execution plan. That is, how we’d like to run a given task in a separate process.

1.1 Execution Plan

1.1.1 Sequential Plan

The default execution plan for future is sequential:

sequential:
- args: function (expr, envir = parent.frame(), substitute = TRUE, lazy = FALSE, seed = NULL, globals = TRUE, local = TRUE, earlySignal = FALSE, label = NULL, ...)
- tweaked: FALSE
- call: NULL

It means that all function calls are executed sequentially in the current R session. So the following future expression will block the session for 1 second:1

Classes 'SequentialFuture', 'UniprocessFuture', 'Future', 'environment' <environment: 0x3dbb7f8> 

=== Execution Time: 1.01056122779846 Sec ===

The return value from a future is refered to as a promise in the asynchronous programming terminology. As we discussed already, to access the bounded value from a future expression (i.e., a promise) we use value function:

[1] "I'm from the future!"

Or a syntactic sugar can be used:

[1] "I'm from the future!"

=== Execution Time: 1.01539325714111 Sec ===

1.1.2 Multi-Processing Plan

A SequentialFuture is of course not very useful at all. The advantage of asynchgronous programming is to have multi-processing execution plan such that our function calls become non-blocking (asynchronous). To enable such setting:

multiprocess:
- args: function (expr, envir = parent.frame(), substitute = TRUE, lazy = FALSE, seed = NULL, globals = TRUE, workers = availableCores(), gc = FALSE, earlySignal = FALSE, label = NULL, ...)
- tweaked: FALSE
- call: plan(multiprocess)

Depending on the running platform, the actual execution plan will be either multicore using fork (for Linux and macOS) or multisession using multiple R sessions (for Windows). So multiprocess is just a platform-independent convenience plan for multi-threading.

It is worth noting that the behavior is technically NOT the same between multicore and multisession, especially when it comes to variable scoping, which we will discussed latter.

Under a multiprocess plan now our future expression becomes non-blocking:

[1] "MulticoreFuture"    "MultiprocessFuture" "Future"            
[4] "environment"       

=== Execution Time: 0.0269737243652344 Sec ===

Again we can use value to access the bounded value. But keep in mind that value is a blocking call. If the promised value is not yet resolved, it will wait until resolved:

[1] "I'm from the future!"

=== Execution Time: 1.03893327713013 Sec ===

One interesting fact about the pipe sugar %<-% in a multiprocess plan is that it is still non-blocking even if it seems to contain the value call implicitly:

=== Execution Time: 0.0218565464019775 Sec ===

This is because %<-% is lazy in its implicit value call. Only when the value is actually used will the call to value be executed.2

To see this in action:

[1] "I'm from the future!"

=== Execution Time: 1.05203032493591 Sec ===

When using the future pipe operator, one can still access the promise object without value. This is done by futureOf:

[1] "MulticoreFuture"    "MultiprocessFuture" "Future"            
[4] "environment"       

1.1.3 Nested Futures

future expression can be nested and the corresponding plan can be configured accordingly. By default the second-layer future will be sequential no matter what plan the first layer uses.

To specify the so-called future topology, for example a sequential for the first layer and a multiprocess for the second layer, we can give a list to the plan call:

1.2 Scope of a future

The scope of a future expression can be tricky. In this section we will spend some time experimenting a bit on its scoping nature.

1.2.1 Global Variables

Since future relies on a separate R process to handle asynchronous calls, how does it deal with global variable in the master process? By default future will automatically scan the given expression and determine which variable to copy for the separate thread to access. This is controlled by the following call:

future(expr, envir=parent.frame(), globals=TRUE)

Setting globals=TRUE enables the auto-search feature, which in theory can result in error by overlooking variables required by expr. The search includes the envir (by default it is the calling environment) AND its parents until found (a.k.a. lexical scoping):

$x
[1] 0

$y
[1] 64

The search behavior can be controlled explicitly by setting globals to a variable name vector and specify the enviroment to search for:

$x
[1] 42

$y
[1] 64

1.2.2 Inconsistency between Plans

When it comes to scoping, future is not very consistent across different execution plan. In this section we discuss several notable examples that can be confusing.

Super Assignment Inconsistency

Super assignment (<<-) behaves differently by execution plan. For a sequential plan:

[1] 42

But for a multisession plan:

[1] 0

Or for a multicore plan:

[1] 0

1.3 Non-Blocking Resolution Check

Since now a future expression may be or may not be resolved already, and a value call to the promised value will block if the value is not yet resolved, it becomes important to have the ability that allows us to check whether a promise is already resolved, without being blocked.

This is exactly what the function resolved is doing:

[1] FALSE
[1] TRUE

Now it is theoretically possible to create one non-blocking future thread to wait for another non-blocking future thread:

Whether such pattern is useful at all depends on the actual use case. But in the next section we will learn how to control even more on a promise to arrive at a full-fletched asynchronous programming framework in R.

1.4 Error Propogation

Error from a future expression will propogate to the actual bounded value but not the Future object itself.

[1] "MulticoreFuture"    "MultiprocessFuture" "Future"            
[4] "environment"       
<simpleError in eval(quote(stop("Error from the future!")), new.env()): Error from the future!>

For explicit error handling it is better to resort to using promises.

2 Using promises

Using promises (Cheng (2018)) is one big step ahead of future, enabling even more flexibility on asynchronous programming. But it also drastically changes how we should write our code–specifically, in a promise-style.

[1] "1.0.1"

2.1 From future to promises

A future expression return a promise. Such promise can be converted explicitly to a promise object using then:

[1] "promise"
List of 3
 $ then   :function (onFulfilled = NULL, onRejected = NULL)  
 $ catch  :function (onRejected)  
 $ finally:function (onFinally)  
 - attr(*, "class")= chr "promise"
 - attr(*, "promise_impl")=Classes 'Promise', 'R6' <Promise [pending]> 

Unlike the original return value from a future, a promise, even under multiprocess, is always resolved:

[1] TRUE

=== Execution Time: 0.0291604995727539 Sec ===

Put it differently, resolved only works (or is only meaningful) for a Future object but not for a promise object.

We loosely call the return value of a future as a promise as well since this is the common wording used in asynchronous programming. But here we explicitly refer to the object class promise implemented by the R package promises. When we refer to the general concept of promise, we will avoid using the syntax highlight for code for readers’ ease of distinguishing the difference.

A Future is not, but can be a promise. Indeed, when a Future object is fed to a then function, it will be immediately converted to a promise-like object by attribute assignment. This can be easily seen in the following code:

Classes 'MulticoreFuture', 'MultiprocessFuture', 'Future', 'environment' <environment: 0x4c28a60> 
Classes 'MulticoreFuture', 'MultiprocessFuture', 'Future', 'environment' <environment: 0x4c28a60> 
 - attr(*, "converted_promise")=List of 3
  ..$ then   :function (onFulfilled = NULL, onRejected = NULL)  
  ..$ catch  :function (onRejected)  
  ..$ finally:function (onFinally)  
  ..- attr(*, "class")= chr "promise"
  ..- attr(*, "promise_impl")=Classes 'Promise', 'R6' <Promise [pending]> 

A Future is either resolved or not resolved. While a promise is either pending, fulfilled, or rejected (due to error).

<Promise [pending]>

Due to the specialty of the notebook rendering environment, a promise is always shown as pending no matter how long we wait for. For an actual R session the result will be something like:

<Promise [fulfilled: character]>

2.2 No Way Back Once promised

How do we extract the bounded value from a promise, like what we do with a Future by using the value function?

It turns out that, we cannot.

Indeed, a promise is ALWAYS a promise. There is simply no way back once we pipe our task into a promise. The design philosophy is that we never know when the promised value will be available, and hence the return value from a promise must always be a promise.

To process the return value from a promise, we simply chain it with another promise:

2.3 Error Handling

When a then job failed at either its onFulfilled or onRejected task, it returns a rejected promise with the corresponding error type. Rejection does NOT propagate, though. When a then job processes a rejected promise, it will go to the onRejected branch (by default simply propagate the error if not specified) and if that task is done without error, the resulting value is a fulfilled promise.

The following example illustrates the above idea:

<Promise [pending]>
<Promise [pending]>

The first promise object p1 will have a value of

<Promise [rejected: simpleError]>

after running its own onFulfilled task. But the second promise object p2 instead will have a value of

<Promise [fulfilled: character]>

after running its own onRejected task and also print the message

[1] "From onRejected: Error in onFulfilled(value): 2"

Then same logic applies to Future object (i.e., converted promise):

This time p1 will print

[1] "From onRejected"

with a value of

<Promise [fulfilled: simpleError]>

And p2 will print

[1] "From onFulfilled."

with a value of

<Promise [fulfilled: simpleError]>

Both promises are fulfilled (i.e., no further error at the branch) on their corresponding task, whether it is a branch task of onFulfilled or onRejected.

2.4 Syntactic Sugars

There are several syntactic sugars available when using the then API.

Promise-Aware Pipe

The pipe %...>% only supports onFulfilled function. In such case the onRejected task is simply an error propagation.

For onRejected function one can use %...!% instead. And the onFulfilled task is a simple identity.

For a complete custom branch handling one should always use the then API explicitly.

3 Async with Reactive Programming

Reactive programming in R is introduced by the well-known shiny package (Chang et al. (2018)) which facilitates the ease of web application development purely using R, usually for data-driven dashboard building purpose.

A huge limitation about such web app is that R is a single-threaded process. Reactive programming itself does not provide asynchrony. In order for a web app to be scalable for a multi-session use case, reactive programming must combine with asynchronous programming.

The good news is that shiny has come fully support for future and promises under its reactive programming framework after its major release of v1.1.

3.1 A Quick Recap: Reactive Programming

[1] "1.3.2"

Broadly speaking there are two types of handler in reactive programmning for shiny: value handler and event handler.

3.1.1 Value Handler

To register an object whose value changes reactively (according to, say, user input from a web app portal), we can use reactiveVal or reactiveValues. reactiveVal is designed for a single value (single object) while reactiveValues is designed for a list of values (multiple objects).

To initialize a reactive value without a default (NULL as default):

To update the value we simply call:

And to retrieve the value we can call without argument:

In general reactiveVal is only callable under a reactive context (all the render* function such as renderText, renderPrint). To test it interactively, we can also use isolate to directly retrieve the value non-reactively:

NULL
[1] 42

To initialize a list of reactive values:

reactiveValues can be directly update by using the list assignment syntax:

To test it:

[1] 2

We can create reactive functions which depend on reactive values. The function will re-execute everytime any of the dependent reactive values change.

[1] 3

Or we can create reactive observer functions similar to reactive but only for its side-effects (i.e., no return value):

3.1.2 Event Handler

We can also create handlers that explicitly respond to UI component or other reactive events defined by a reactive function.

For example, we can react to a user button click by a eventReactive function:

Not just UI component, eventReactive can react to anything reactive:

[1] 456

We can do the same but only for side-effects by using observeEvent:

3.2 Promise-Aware Reactive Expression

All reactive functions provided by shiny are both future and promise aware. It means that reactive expressions can be a Future:

[1] 3

or a promise:

List of 3
 $ then   :function (onFulfilled = NULL, onRejected = NULL)  
 $ catch  :function (onRejected)  
 $ finally:function (onFinally)  
 - attr(*, "class")= chr "promise"
 - attr(*, "promise_impl")=Classes 'Promise', 'R6' <Promise [pending]> 

3.3 Experimental App on Async

To see how one session is blocking another in a single-threaded app, here is a minimum app for pure illustration purpose:

To play around with the actual app, run:

for synchronous mode.

The app will be listening on 127.0.0.1:8787. Open more than 1 tab and click the do button for all the opening tabs. For a sequential app we shall observe the timer stop jumping when there is any other session (browser tab) still working and hence blocking. The more other sessions are still working, the more times you will see the timer jump and stop. The start time recorded in the output text is always roughly 5 seconds before it ended. However the start time is NOT the time we hit the do button.

Now close the app. For asynchronous mode run:

and investigate again.

The timer will still stop jumping when we hit the do button. But this time it didn’t stop more than once. It only stop for its own session.

And the timer is stopping because we didn’t implement the timer asynchronously. In the experimental app only the do_heavy_work operation is implemented in asynchronous mode.

In general we will only make those heavy tasks asynchronous instead of trying to make everything asynchronous.

4 Closing Remarks

Up to now we’ve equiped with the basic knowledge to start developing asynchronous web application using R. There are far more features then what we just discussed here for all these packages: future, promises, and shiny. But we will leave it for exploration and retain the scope of this notebook at a entry-level.

5 References

Bengtsson, Henrik. 2019. Future: Unified Parallel and Distributed Processing in R for Everyone. https://CRAN.R-project.org/package=future.

Chang, Winston, Joe Cheng, JJ Allaire, Yihui Xie, and Jonathan McPherson. 2018. Shiny: Web Application Framework for R. https://CRAN.R-project.org/package=shiny.

Cheng, Joe. 2018. Promises: Abstractions for Promise-Based Asynchronous Programming. https://CRAN.R-project.org/package=promises.


  1. In this notebook we use a custom knit_hooks to time the relevant code chunk to showcase the blocking/non-blocking execution time.

  2. Readers should not confuse the laziness here with the lazy function argument in a future call. By setting lazy=FALSE (which is the default) in a future call it enables the expression to start execution immediately, otherwise not.

LS0tCnRpdGxlOiAiQXN5bmNocm9ub3VzIFByb2dyYW1taW5nIGluIFIiCnN1YnRpdGxlOiAiVG8ga2ljay1TdGFydCBEZXZlbG9waW5nIGEgU2NhbGFibGUgYHNoaW55YCBBcHAiCmF1dGhvcjoKLSBuYW1lOiBLeWxlIENodW5nCiAgYWZmaWxpYXRpb246CmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICViICVZJylgIExhc3QgVXBkYXRlZCAoMTQgU2VwIDIwMTkgRmlyc3QgVXBsb2FkZWQpIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGhpZ2hsaWdodDogcHlnbWVudHMKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogcGFwZXIKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBpbmNsdWRlczoKICAgICAgaW5faGVhZGVyOiAvdG1wL21ldGFfaGVhZGVyLmh0bWwKICBjb2RlX2Rvd25sb2FkOiB0cnVlCmJpYmxpb2dyYXBoeTogYXN5bmNfci5iaWIKYWJzdHJhY3Q6IHwKICBUaGUgbm90ZWJvb2sgaXMgYSBwcmFjdGljYWwgd2Fsay10aHJvdWdoIG9mIGltcGxlbWVudGluZyBhc3luY2hyb25vdXMgcHJvZ3JhbW1pbmcgaW4gUiB1c2luZyBwYWNrYWdlIGBmdXR1cmVgIGFuZCBgcHJvbWlzZXNgLCBtYWlubHkgZm9yIHRoZSBwdXJwb3NlIG9mIGtpY2stc3RhcnRpbmcgZGV2ZWxvcGluZyBhIHNjYWxhYmxlIGBzaGlueWAgYXBwbGljYXRpb24uIEluZGVlZCwgYWxsIDMgcGFja2FnZXMgY29tZSB3aXRoIHZlcnkgd2VsbC1zdHJ1Y3R1cmVkIG9mZmljaWFsIHR1dG9yaWFscyBhbHJlYWR5LiBUaGlzIG5vdGVib29rIHNlcnZlcyBtb3JlIGFzIGEgbWluaW1hbGx5IHN1ZmZpY2llbnQgb25lLXN0b3AgcmVmZXJlbmNlIGZvciBkZXZlbG9wZXJzIHRvIHF1aWNrbHkgaGFuZHMtb24gb24gdGhlIHRvcGljIGFuZCBnZXQgcmVhZHkgZm9yIHRoZSBhY3R1YWwgYXBwbGljYXRpb24gZGV2ZWxvcG1lbnQuCi0tLQoKYGBge3IgbWV0YSwgaW5jbHVkZT1GQUxTRX0KbWV0YV9oZWFkZXJfZmlsZSA8LSBmaWxlKCIvdG1wL21ldGFfaGVhZGVyLmh0bWwiKQoKIyBBZGQgb3BlbiBncmFwaCBtZXRhLgptZXRhIDwtIGMoCiAgJzxtZXRhIG5hbWU9ImF1dGhvciIgY29udGVudD0iS3lsZSBDaHVuZyI+JywKICAnPG1ldGEgcHJvcGVydHk9Im9nOnRpdGxlIiBjb250ZW50PSJBc3luY2hyb25vdXMgUHJvZ3JhbW1pbmcgaW4gUiI+JywKICAnPG1ldGEgcHJvcGVydHk9Im9nOnR5cGUiIGNvbnRlbnQ9ImFydGljbGUiPicsCiAgJzxtZXRhIHByb3BlcnR5PSJvZzp1cmwiIGNvbnRlbnQ9Imh0dHBzOi8vZXZlcmRhcmsuZ2l0aHViLmlvL2s5L3Byb2dyYW1taW5nL2FzeW5jL2FzeW5jX3IubmIuaHRtbCI+JywKICAnPG1ldGEgcHJvcGVydHk9Im9nOmltYWdlIiBjb250ZW50PSJodHRwczovL2V2ZXJkYXJrLmdpdGh1Yi5pby9rOS9hc3NldHMvYXZhdGFyLmpwZyI+JywKICAnPG1ldGEgcHJvcGVydHk9Im9nOmRlc2NyaXB0aW9uIiBjb250ZW50PSJPbmUtc3RvcCBxdWljayBoYW5kcy1vbiBmb3IgZGV2ZWxvcGluZyBzY2FsYWJsZSBzaGlueSBhcHBsaWNhdGlvbiB3aXRoIGFzeW5jaHJvbm91cyBwcm9ncmFtbWluZy4iPicKKQpjb250ZW50cyA8LSBtZXRhCgojIEFkZCBHaXRodWIgY29ybmVyLgpnaXRodWJfY29ybmVyX3N2ZyA8LSAiLi4vLi4vLi4vYXNzZXRzL2dpdGh1Yl9jb3JuZXIuaHRtbCIKZ2l0aHViX2Nvcm5lcl9jb25mIDwtIGxpc3QoZ2l0aHViX2xpbms9Imh0dHBzOi8vZ2l0aHViLmNvbS9ldmVyZGFyay9rOS90cmVlL21hc3Rlci9wcm9ncmFtbWluZy9yL2FzeW5jIikKY29udGVudHMgPC0gYyhjb250ZW50cywgc3RyaW5ncjo6c3RyX2ludGVycChyZWFkTGluZXMoZ2l0aHViX2Nvcm5lcl9zdmcpLCBnaXRodWJfY29ybmVyX2NvbmYpKQp3cml0ZUxpbmVzKGNvbnRlbnRzLCBtZXRhX2hlYWRlcl9maWxlKQoKY2xvc2UobWV0YV9oZWFkZXJfZmlsZSkKYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBDcmVhdGUgYSBob29rIGZvciBjb2RlIGNodW5rIGV4ZWN1dGlvbiB0aW1lLgprbml0cjo6a25pdF9ob29rcyRzZXQodGltZWl0PWxvY2FsKHsKICBub3c9TlVMTAogIGZ1bmN0aW9uKGJlZm9yZSwgb3B0aW9ucykgewogICAgaWYgKCBiZWZvcmUgKSB7CiAgICAgIG5vdyA8PC0gU3lzLnRpbWUoKQogICAgfSBlbHNlIHsKICAgICAgZCA8LSBkaWZmdGltZShTeXMudGltZSgpLCBub3cpCiAgICAgIG5vdyA8PC0gTlVMTAogICAgICBwYXN0ZShzcHJpbnRmKCI9PT0gRXhlY3V0aW9uIFRpbWU6ICVzIFNlYyA9PT0iLCBhcy5jaGFyYWN0ZXIoZCkpKQogICAgfQogIH19KQopCmBgYAoKIyBVc2luZyBgZnV0dXJlYAoKYGBge3IgaW1wb3J0X2Z1dHVyZX0KbGlicmFyeShmdXR1cmUpCnByaW50KGluc3RhbGxlZC5wYWNrYWdlcygpWyJmdXR1cmUiLCAiVmVyc2lvbiJdKQpgYGAKClRoZSBwYWNrYWdlIGBmdXR1cmVgIChAZnV0dXJlKSBhbGxvd3MgYSBzaW5nbGUtdGhyZWFkZWQgUiBwcm9jZXNzIHRvIGxhdW5jaCBhIHRhc2sgaW4gYW5vdGhlciB0aHJlYWQgdG8gYWNoaWV2ZSBhc3luY2hyb25vdXMgcHJvZ3JhbW1pbmcuCkl0IGlzIHRoZSBtYWluIGVudHJ5IHBvaW50IGZvciBhIHRhc2sgdG8gYmUgYXN5bmNocm9ub3VzLgoKVG8gbWFrZSBhbiBleHByZXNzaW9uIGEgYEZ1dHVyZWAsCndlIHNpbXBseSB3cmFwIGl0IHdpdGggYSBgZnV0dXJlYCBmdW5jdGlvbiBjYWxsOgoKYGBge3IgZnV0dXJlfQpmIDwtIGZ1dHVyZSh7CiAgIyBTdXBwb3NlZGx5IGFueXRoaW5nIGV4cGVuc2l2ZSB0byBjb21wdXRlIGhlcmUuCiAgMSArIDEKfSkKYGBgCgpUaGVuIHdlIGNhbiBjb2xsZWN0IHRoZSByZXN1bHQgb2YgYSBgRnV0dXJlYDoKCmBgYHtyIHZhbHVlfQpwcmludCh2YWx1ZShmKSkKYGBgCgpJbiBvcmRlciBmb3IgYSBgRnV0dXJlYCB0byBiZSB1c2VmdWwsCndlIG5lZWQgdG8gY29uZmlndXJlIHRoZSBleGVjdXRpb24gcGxhbi4KVGhhdCBpcywKaG93IHdlJ2QgbGlrZSB0byBydW4gYSBnaXZlbiB0YXNrIGluIGEgc2VwYXJhdGUgcHJvY2Vzcy4KCiMjIEV4ZWN1dGlvbiBQbGFuCgojIyMgU2VxdWVudGlhbCBQbGFuCgpUaGUgZGVmYXVsdCBleGVjdXRpb24gcGxhbiBmb3IgYGZ1dHVyZWAgaXMgYHNlcXVlbnRpYWxgOgoKYGBge3IgZnV0dXJlX3BsYW59CnBsYW4oKSAgIyBDaGVjayB0aGUgY3VycmVudCBleGVjdXRpb24gcGxhbi4KYGBgCgpJdCBtZWFucyB0aGF0IGFsbCBmdW5jdGlvbiBjYWxscyBhcmUgZXhlY3V0ZWQgc2VxdWVudGlhbGx5IGluIHRoZSBjdXJyZW50IFIgc2Vzc2lvbi4KU28gdGhlIGZvbGxvd2luZyBmdXR1cmUgZXhwcmVzc2lvbiB3aWxsIGJsb2NrIHRoZSBzZXNzaW9uIGZvciAxIHNlY29uZDpeW0luIHRoaXMgbm90ZWJvb2sgd2UgdXNlIGEgY3VzdG9tIGBrbml0X2hvb2tzYCB0byB0aW1lIHRoZSByZWxldmFudCBjb2RlIGNodW5rIHRvIHNob3djYXNlIHRoZSBibG9ja2luZy9ub24tYmxvY2tpbmcgZXhlY3V0aW9uIHRpbWUuXQoKYGBge3Igc2VxdWVudGlhbF9mdXR1cmUsIHRpbWVpdD1UUlVFfQpwbGFuKHNlcXVlbnRpYWwpICAjIFNldCBleHBsaWNpdGx5IHRvIGEgc2VxdWVudGlhbCBwbGFuLgoKZiA8LSBmdXR1cmUoewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSkKCnN0cihmKSAgIyBBIFNlcXVlbnRpYWxGdXR1cmUgb2JqZWN0LgpgYGAKClRoZSByZXR1cm4gdmFsdWUgZnJvbSBhIGBmdXR1cmVgIGlzIHJlZmVyZWQgdG8gYXMgYSAqcHJvbWlzZSogaW4gdGhlIGFzeW5jaHJvbm91cyBwcm9ncmFtbWluZyB0ZXJtaW5vbG9neS4KQXMgd2UgZGlzY3Vzc2VkIGFscmVhZHksCnRvIGFjY2VzcyB0aGUgYm91bmRlZCB2YWx1ZSBmcm9tIGEgYGZ1dHVyZWAgZXhwcmVzc2lvbiAoaS5lLiwgYSBwcm9taXNlKSB3ZSB1c2UgYHZhbHVlYCBmdW5jdGlvbjoKCmBgYHtyIGZ1dHVyZV92YWx1ZX0KcHJpbnQodmFsdWUoZikpCmBgYAoKT3IgYSBzeW50YWN0aWMgc3VnYXIgY2FuIGJlIHVzZWQ6CgpgYGB7ciBmdXR1cmVfc3VnYXIsIHRpbWVpdD1UUlVFfQp2ICU8LSUgewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfQoKcHJpbnQodikKYGBgCgojIyMgTXVsdGktUHJvY2Vzc2luZyBQbGFuCgpBIGBTZXF1ZW50aWFsRnV0dXJlYCBpcyBvZiBjb3Vyc2Ugbm90IHZlcnkgdXNlZnVsIGF0IGFsbC4KVGhlIGFkdmFudGFnZSBvZiBhc3luY2hncm9ub3VzIHByb2dyYW1taW5nIGlzIHRvIGhhdmUgbXVsdGktcHJvY2Vzc2luZyBleGVjdXRpb24gcGxhbiBzdWNoIHRoYXQgb3VyIGZ1bmN0aW9uIGNhbGxzIGJlY29tZSBub24tYmxvY2tpbmcgKGFzeW5jaHJvbm91cykuClRvIGVuYWJsZSBzdWNoIHNldHRpbmc6CgpgYGB7ciBmdXR1cmVfcGxhbl9tdWx0aXByb2Nlc3N9CnBsYW4obXVsdGlwcm9jZXNzKQpwbGFuKCkKYGBgCgpEZXBlbmRpbmcgb24gdGhlIHJ1bm5pbmcgcGxhdGZvcm0sCnRoZSBhY3R1YWwgZXhlY3V0aW9uIHBsYW4gd2lsbCBiZSBlaXRoZXIgYG11bHRpY29yZWAgdXNpbmcgZm9yayAoZm9yIExpbnV4IGFuZCBtYWNPUykgb3IgYG11bHRpc2Vzc2lvbmAgdXNpbmcgbXVsdGlwbGUgUiBzZXNzaW9ucyAoZm9yIFdpbmRvd3MpLgpTbyBgbXVsdGlwcm9jZXNzYCBpcyBqdXN0IGEgcGxhdGZvcm0taW5kZXBlbmRlbnQgY29udmVuaWVuY2UgcGxhbiBmb3IgbXVsdGktdGhyZWFkaW5nLgoKSXQgaXMgd29ydGggbm90aW5nIHRoYXQgdGhlIGJlaGF2aW9yIGlzIHRlY2huaWNhbGx5IE5PVCB0aGUgc2FtZSBiZXR3ZWVuIGBtdWx0aWNvcmVgIGFuZCBgbXVsdGlzZXNzaW9uYCwKZXNwZWNpYWxseSB3aGVuIGl0IGNvbWVzIHRvIHZhcmlhYmxlIHNjb3BpbmcsCndoaWNoIHdlIHdpbGwgZGlzY3Vzc2VkIGxhdHRlci4KClVuZGVyIGEgYG11bHRpcHJvY2Vzc2AgcGxhbiBub3cgb3VyIGBmdXR1cmVgIGV4cHJlc3Npb24gYmVjb21lcyBub24tYmxvY2tpbmc6CgpgYGB7ciBtdWx0aXByb2Nlc3NfZnV0dXJlLCB0aW1laXQ9VFJVRX0KZiA8LSBmdXR1cmUoewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSkgICMgVGhlIGNhbGwgd2lsbCByZXR1cm4gaW1tZWRpYXRlbHkuCgpwcmludChjbGFzcyhmKSkgICMgQSBNdWx0aXByb2Nlc3NGdXR1cmUgb2JqZWN0LgpgYGAKCkFnYWluIHdlIGNhbiB1c2UgYHZhbHVlYCB0byBhY2Nlc3MgdGhlIGJvdW5kZWQgdmFsdWUuCkJ1dCBrZWVwIGluIG1pbmQgdGhhdCAqYHZhbHVlYCBpcyBhIGJsb2NraW5nIGNhbGwuKgpJZiB0aGUgcHJvbWlzZWQgdmFsdWUgaXMgbm90IHlldCBgcmVzb2x2ZWRgLAppdCB3aWxsIHdhaXQgdW50aWwgYHJlc29sdmVkYDoKCmBgYHtyIHZhbHVlX2Jsb2NraW5nLCB0aW1laXQ9VFJVRX0KZiA8LSBmdXR1cmUoewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSkgICMgVGhlIGNhbGwgd2lsbCByZXR1cm4gaW1tZWRpYXRlbHkuCgpwcmludCh2YWx1ZShmKSkgICMgVGhpcyBpcyBibG9ja2luZyBzaW5jZSBgdmFsdWVgIGlzIHdhaXRpbmcgZm9yIGBmYCB0byBiZSByZXNvbHZlZC4KYGBgCgpPbmUgaW50ZXJlc3RpbmcgZmFjdCBhYm91dCB0aGUgcGlwZSBzdWdhciBgJTwtJWAgaW4gYSBgbXVsdGlwcm9jZXNzYCBwbGFuIGlzIHRoYXQgaXQgaXMgc3RpbGwgbm9uLWJsb2NraW5nIGV2ZW4gaWYgaXQgc2VlbXMgdG8gY29udGFpbiB0aGUgYHZhbHVlYCBjYWxsIGltcGxpY2l0bHk6CgpgYGB7ciBmdXR1cmVfc3VnYXJfbm9uYmxvY2tpbmcsIHRpbWVpdD1UUlVFfQp2ICU8LSUgewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfQpgYGAKClRoaXMgaXMgYmVjYXVzZSBgJTwtJWAgaXMgKmxhenkqIGluIGl0cyBpbXBsaWNpdCBgdmFsdWVgIGNhbGwuCk9ubHkgd2hlbiB0aGUgdmFsdWUgaXMgYWN0dWFsbHkgdXNlZCB3aWxsIHRoZSBjYWxsIHRvIGB2YWx1ZWAgYmUgZXhlY3V0ZWQuXltSZWFkZXJzIHNob3VsZCBub3QgY29uZnVzZSB0aGUgbGF6aW5lc3MgaGVyZSB3aXRoIHRoZSBgbGF6eWAgZnVuY3Rpb24gYXJndW1lbnQgaW4gYSBgZnV0dXJlYCBjYWxsLiBCeSBzZXR0aW5nIGBsYXp5PUZBTFNFYCAod2hpY2ggaXMgdGhlIGRlZmF1bHQpIGluIGEgYGZ1dHVyZWAgY2FsbCBpdCBlbmFibGVzIHRoZSBleHByZXNzaW9uIHRvIHN0YXJ0IGV4ZWN1dGlvbiBpbW1lZGlhdGVseSwgb3RoZXJ3aXNlIG5vdC5dCgpUbyBzZWUgdGhpcyBpbiBhY3Rpb246CgpgYGB7ciBmdXR1cmVfc3VnYXJfYmxvY2tpbmcsIHRpbWVpdD1UUlVFfQp2ICU8LSUgewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSAgIyBOb24tYmxvY2tpbmcuCgpwcmludCh2KSAgIyBCbG9ja2luZy4KYGBgCgpXaGVuIHVzaW5nIHRoZSBmdXR1cmUgcGlwZSBvcGVyYXRvciwKb25lIGNhbiBzdGlsbCBhY2Nlc3MgdGhlIHByb21pc2Ugb2JqZWN0IHdpdGhvdXQgYHZhbHVlYC4KVGhpcyBpcyBkb25lIGJ5IGBmdXR1cmVPZmA6CgpgYGB7ciBmdXR1cmVfc3VnYXJfZ2V0X2Z1dHVyZX0KdiAlPC0lIHsKICBTeXMuc2xlZXAoMSkKICAiSSdtIGZyb20gdGhlIGZ1dHVyZSEiCn0gICMgTm9uLWJsb2NraW5nLgoKcHJpbnQoY2xhc3MoZnV0dXJlT2YodikpKSAgIyBBIEZ1dHVyZSBvYmplY3QuCmBgYAoKIyMjIE5lc3RlZCBGdXR1cmVzCgpgZnV0dXJlYCBleHByZXNzaW9uIGNhbiBiZSBuZXN0ZWQgYW5kIHRoZSBjb3JyZXNwb25kaW5nIHBsYW4gY2FuIGJlIGNvbmZpZ3VyZWQgYWNjb3JkaW5nbHkuCkJ5IGRlZmF1bHQgdGhlIHNlY29uZC1sYXllciBgZnV0dXJlYCB3aWxsIGJlIGBzZXF1ZW50aWFsYCBubyBtYXR0ZXIgd2hhdCBwbGFuIHRoZSBmaXJzdCBsYXllciB1c2VzLgoKVG8gc3BlY2lmeSB0aGUgc28tY2FsbGVkICpmdXR1cmUgdG9wb2xvZ3kqLApmb3IgZXhhbXBsZSBhIGBzZXF1ZW50aWFsYCBmb3IgdGhlIGZpcnN0IGxheWVyIGFuZCBhIGBtdWx0aXByb2Nlc3NgIGZvciB0aGUgc2Vjb25kIGxheWVyLAp3ZSBjYW4gZ2l2ZSBhIGxpc3QgdG8gdGhlIGBwbGFuYCBjYWxsOgoKYGBgcgpwbGFuKGxpc3Qoc2VxdWVudGlhbCwgbXVsdGlwcm9jZXNzKSkKYGBgCgojIyBTY29wZSBvZiBhIGBmdXR1cmVgCgpUaGUgc2NvcGUgb2YgYSBgZnV0dXJlYCBleHByZXNzaW9uIGNhbiBiZSB0cmlja3kuCkluIHRoaXMgc2VjdGlvbiB3ZSB3aWxsIHNwZW5kIHNvbWUgdGltZSBleHBlcmltZW50aW5nIGEgYml0IG9uIGl0cyBzY29waW5nIG5hdHVyZS4KCiMjIyBHbG9iYWwgVmFyaWFibGVzCgpTaW5jZSBgZnV0dXJlYCByZWxpZXMgb24gYSBzZXBhcmF0ZSBSIHByb2Nlc3MgdG8gaGFuZGxlIGFzeW5jaHJvbm91cyBjYWxscywKaG93IGRvZXMgaXQgZGVhbCB3aXRoIGdsb2JhbCB2YXJpYWJsZSBpbiB0aGUgbWFzdGVyIHByb2Nlc3M/CkJ5IGRlZmF1bHQgYGZ1dHVyZWAgd2lsbCBhdXRvbWF0aWNhbGx5IHNjYW4gdGhlIGdpdmVuIGV4cHJlc3Npb24gYW5kIGRldGVybWluZSB3aGljaCB2YXJpYWJsZSB0byAqY29weSogZm9yIHRoZSBzZXBhcmF0ZSB0aHJlYWQgdG8gYWNjZXNzLgpUaGlzIGlzIGNvbnRyb2xsZWQgYnkgdGhlIGZvbGxvd2luZyBjYWxsOgoKYGBgCmZ1dHVyZShleHByLCBlbnZpcj1wYXJlbnQuZnJhbWUoKSwgZ2xvYmFscz1UUlVFKQpgYGAKClNldHRpbmcgYGdsb2JhbHM9VFJVRWAgZW5hYmxlcyB0aGUgYXV0by1zZWFyY2ggZmVhdHVyZSwKd2hpY2ggaW4gdGhlb3J5IGNhbiByZXN1bHQgaW4gZXJyb3IgYnkgb3Zlcmxvb2tpbmcgdmFyaWFibGVzIHJlcXVpcmVkIGJ5IGBleHByYC4KVGhlIHNlYXJjaCBpbmNsdWRlcyB0aGUgYGVudmlyYCAoYnkgZGVmYXVsdCBpdCBpcyB0aGUgY2FsbGluZyBgZW52aXJvbm1lbnRgKSBBTkQgaXRzIHBhcmVudHMgdW50aWwgZm91bmQgKGEuay5hLiAqbGV4aWNhbCBzY29waW5nKik6CgpgYGB7ciwgZnV0dXJlX2dsb2JhbF9zZWFyY2h9CnggPC0gNDIKeSA8LSA2NCAgIyBTZWFyY2ggdXAgdG8gaGVyZSBmb3IgeS4KayA8LSBmdW5jdGlvbigpIHsKICB4IDwtIDAgICMgU2VhcmNoIHVwIHRvIGhlcmUgZm9yIHguCiAgZyA8LSBmdW5jdGlvbigpIHsKICAgIGYgPC0gZnV0dXJlKHsKICAgICAgbGlzdCh4PXgsIHk9eSkKICAgIH0sIGdsb2JhbHM9VFJVRSkKICAgIHZhbHVlKGYpCiAgfQogIGcoKQp9CmsoKQpgYGAKClRoZSBzZWFyY2ggYmVoYXZpb3IgY2FuIGJlIGNvbnRyb2xsZWQgZXhwbGljaXRseSBieSBzZXR0aW5nIGBnbG9iYWxzYCB0byBhIHZhcmlhYmxlIG5hbWUgdmVjdG9yIGFuZCBzcGVjaWZ5IHRoZSBgZW52aXJvbWVudGAgdG8gc2VhcmNoIGZvcjoKCmBgYHtyIGZ1dHVyZV9nbG9iYWxfZXhwbGljaXR9CnggPC0gNDIgICMgRXhwb3NlZCB0byBmdXR1cmUgZXhwbGljaXRseS4KeSA8LSA2NCAgIyBFeHBvc2VkIHRvIGZ1dHVyZSBleHBsaWNpdGx5LgprIDwtIGZ1bmN0aW9uKCkgewogIHggPC0gMCAgIyBUaGlzIGlzIGlnbm9yZWQgc2luY2UgaXQgaXMgbm90IGluIHRoZSBzcGVjaWZpZWQgc2VhcmNoIGVudmlyb25tZW50LgogIGcgPC0gZnVuY3Rpb24oKSB7CiAgICBmIDwtIGZ1dHVyZSh7CiAgICAgIGxpc3QoeD14LCB5PXkpCiAgICB9LCBnbG9iYWxzPWMoIngiLCAieSIpLCBlbnZpcj0uR2xvYmFsRW52KQogICAgdmFsdWUoZikKICB9CiAgZygpCn0KaygpCmBgYAoKIyMjIEluY29uc2lzdGVuY3kgYmV0d2VlbiBQbGFucwoKV2hlbiBpdCBjb21lcyB0byBzY29waW5nLApgZnV0dXJlYCBpcyBub3QgdmVyeSBjb25zaXN0ZW50IGFjcm9zcyBkaWZmZXJlbnQgZXhlY3V0aW9uIHBsYW4uCkluIHRoaXMgc2VjdGlvbiB3ZSBkaXNjdXNzIHNldmVyYWwgbm90YWJsZSBleGFtcGxlcyB0aGF0IGNhbiBiZSBjb25mdXNpbmcuCgojIyMjIEF1dG8tU2VhcmNoIFNjb3BlIEluY29uc2lzdGVuY3kgey19CgpUbyBzZWUgaG93IHRoZSBnbG9iYWwgaXMgTk9UIGNvcGllZCBjb3JyZWN0bHkgYnkgdGhlIGF1dG8tc2VhcmNoIGZlYXR1cmUsCmNvbnNpZGVyIHRoZSBmb2xsb3dpbmcgZXhhbXBsZToKCmBgYHtyIGZ1dHVyZV9nbG9iYWxfbm90X2ZvdW5kfQpwbGFuKG11bHRpc2Vzc2lvbikKeiA8LSAxMApmIDwtIGZ1dHVyZSh7CiAgZ2V0KCJ6IiwgZW52aXI9ZW52aXJvbm1lbnQoKSwgaW5oZXJpdHM9VFJVRSkgICMgRXJyb3IuCn0pCnRyeUNhdGNoKHZhbHVlKGYpLCBlcnJvcj1mdW5jdGlvbihlKSBwcmludChlKSkKYGBgCgpBIGNvbnRyYXN0aW5nIGV4YW1wbGUgaXMgdG8gbWFrZSB0aGUgZXhwcmVzc2lvbiBlYXN5IGZvciB0aGUgYGZ1dHVyZWAgdG8gdW5kZXJzdGFuZCB0aGF0IHdlIG5lZWQgdGhlIHZhcmlhYmxlOgoKYGBge3IgZnV0dXJlX2dsb2JhbF9mb3VuZH0KcGxhbihtdWx0aXNlc3Npb24pCnogPC0gMTAKZiA8LSBmdXR1cmUoewogIGdldCgieiIsIGVudmlyPWVudmlyb25tZW50KCksIGluaGVyaXRzPVRSVUUpICAjIFRoaXMgbm93IGlzIHdvcmtpbmcgZXZlbiBCRUZPUkUgdGhlIGV2YWwgdG8gei4KICB6ICAjIFRoaXMgbWFrZXMgdGhlIGF1dG8tc2VhcmNoIHdvcmsgYW5kIGV4cG9ydCB0aGUgdmFyaWFibGUgZnJvbSBnbG9iYWwuCn0pCnRyeUNhdGNoKHZhbHVlKGYpLCBlcnJvcj1mdW5jdGlvbihlKSBwcmludChlKSkKYGBgCgpCdXQgdGhlIHNhbWUgZnVuY3Rpb24gY2FsbCB3b3JrcyBwZXJmZWN0bHkgdW5kZXIgZWl0aGVyIGBtdWx0aWNvcmVgIG9yIGBzZXF1ZW50aWFsYDoKCmBgYHtyIGZ1dHVyZV9nbG9iYWxfZm91bmRfc2VxdWVudGlhbH0KcGxhbihzZXF1ZW50aWFsKQp6IDwtIDEwCmYgPC0gZnV0dXJlKHsKICBnZXQoInoiLCBlbnZpcj1lbnZpcm9ubWVudCgpLCBpbmhlcml0cz1UUlVFKQp9KQp0cnlDYXRjaCh2YWx1ZShmKSwgZXJyb3I9ZnVuY3Rpb24oZSkgcHJpbnQoZSkpCmBgYAoKYGBge3IgZnV0dXJlX2dsb2JhbF9mb3VuZF9tdWx0aWNvcmV9CnBsYW4obXVsdGljb3JlKSAgIyBUaGlzIGlzIG5vdCBzdXBwb3J0ZWQgaW4gV2luZG93cyBhbmQgd2lsbCBmYWxsYmFjayB0byBhIHNlcXVlbnRpYWwgcGxhbi4KeiA8LSAxMApmIDwtIGZ1dHVyZSh7CiAgZ2V0KCJ6IiwgZW52aXI9ZW52aXJvbm1lbnQoKSwgaW5oZXJpdHM9VFJVRSkKfSkKdHJ5Q2F0Y2godmFsdWUoZiksIGVycm9yPWZ1bmN0aW9uKGUpIHByaW50KGUpKQpgYGAKCiMjIyMgR2xvYmFsIENvcHkgSW5jb25zaXN0ZW5jeSB7LX0KClJlbWVtYmVyIHRoYXQgYWxsIGdsb2JhbHMgYXJlICpjb3BpZWQqIHRvIHRoZSBgZnV0dXJlYCBibG9jaywKd2hpY2ggbWVhbnMgaW4tcGxhY2UgY2hhbmdlIHdpbGwgbm90IHJlZmxlY3Qgb24gdGhlIG9yaWdpbmFsIG9iamVjdCBldmVuIGlmIHRoZSBvYmplY3QgaXMgbXV0YWJsZToKCmBgYHtyIGZ1dHVyZV9nbG9iYWxfY29weV9tdWx0aXNlc3Npb259CnBsYW4obXVsdGlzZXNzaW9uKQplIDwtIG5ldy5lbnYoKSAgIyBBIGdsb2JhbCBtdXRhYmxlLgplJHggPC0gMAoKZiA8LSBmdXR1cmUoewogIGUkeCA8LSA0MiAgIyBgZWAgaXMgYXV0b21hdGljYWxseSBzZWFyY2hlZCBhbmQgYWNjZXNzYWJsZSwgYnV0IGNoYW5nZWQgaW4gYSBjb3B5Lgp9KQppbnZpc2libGUodmFsdWUoZikpCgpscy5zdHIoZSkgICMgVGhlIG9yaWdpbmFsIGNvcHkgaXMgaW50YWN0LgpgYGAKCmBgYHtyIGZ1dHVyZV9nbG9iYWxfY29weV9tdWx0aWNvcmV9CnBsYW4obXVsdGljb3JlKSAgIyBUaGlzIGlzIG5vdCBzdXBwb3J0ZWQgaW4gV2luZG93cyBhbmQgd2lsbCBmYWxsYmFjayB0byBhIHNlcXVlbnRpYWwgcGxhbi4KZSA8LSBuZXcuZW52KCkgICMgQSBnbG9iYWwgbXV0YWJsZS4KZSR4IDwtIDAKCmYgPC0gZnV0dXJlKHsKICBlJHggPC0gNDIKfSkKaW52aXNpYmxlKHZhbHVlKGYpKQoKbHMuc3RyKGUpCmBgYAoKSG93ZXZlciwKdGhlIGFib3ZlIGZhY3Qgb25seSBob2xkcyBmb3IgYSBgbXVsdGlwcm9jZXNzYCBwbGFuLgpVbmRlciBgc2VxdWVudGlhbGAgcGxhbiB0aGUgZ2xvYmFsIG9yaWdpbmFsIGlzIGluZGVlZCBjaGFuZ2VkIGluLXBsYWNlOgoKYGBge3IgZnV0dXJlX2dsb2JhbF9jb3B5X3NlcXVlbnRpYWx9CnBsYW4oc2VxdWVudGlhbCkKZSA8LSBuZXcuZW52KCkgICMgQSBnbG9iYWwgbXV0YWJsZS4KZSR4IDwtIDAKCmYgPC0gZnV0dXJlKHsKICBlJHggPC0gNDIKfSkKaW52aXNpYmxlKHZhbHVlKGYpKQoKbHMuc3RyKGUpICAjIFRoZSBvcmlnaW5hbCBjb3B5IGhhcyBiZWVuIG1vZGlmaWVkIQpgYGAKCiMjIyMgU3VwZXIgQXNzaWdubWVudCBJbmNvbnNpc3RlbmN5IHstfQoKU3VwZXIgYXNzaWdubWVudCAoYDw8LWApIGJlaGF2ZXMgZGlmZmVyZW50bHkgYnkgZXhlY3V0aW9uIHBsYW4uCkZvciBhIGBzZXF1ZW50aWFsYCBwbGFuOgoKYGBge3IgZnV0dXJlX3Njb3BlX3N1cGVyYXNzaWduX3NlcXVlbnRpYWx9CnBsYW4oc2VxdWVudGlhbCkKeCA8LSAwCmYgPC0gZnV0dXJlKHsKICB4IDw8LSA0MgogIHkgPC0gMAp9KQppbnZpc2libGUodmFsdWUoZikpCngKYGBgCgpCdXQgZm9yIGEgYG11bHRpc2Vzc2lvbmAgcGxhbjoKCmBgYHtyIGZ1dHVyZV9zY29wZV9zdXBlcmFzc2lnbl9tdWx0aXNlc3Npb259CnBsYW4obXVsdGlzZXNzaW9uKQp4IDwtIDAKZiA8LSBmdXR1cmUoewogIHggPDwtIDQyCiAgeSA8LSAwCn0pCmludmlzaWJsZSh2YWx1ZShmKSkKeApgYGAKCk9yIGZvciBhIGBtdWx0aWNvcmVgIHBsYW46CgpgYGB7ciBmdXR1cmVfc2NvcGVfc3VwZXJhc3NpZ25fbXVsdGljb3JlfQpwbGFuKG11bHRpY29yZSkgICMgVGhpcyBpcyBub3Qgc3VwcG9ydGVkIGluIFdpbmRvd3MgYW5kIHdpbGwgZmFsbGJhY2sgdG8gYSBzZXF1ZW50aWFsIHBsYW4uCnggPC0gMApmIDwtIGZ1dHVyZSh7CiAgeCA8PC0gNDIKICB5IDwtIDAKfSkKaW52aXNpYmxlKHZhbHVlKGYpKQp4CmBgYAoKIyMgTm9uLUJsb2NraW5nIFJlc29sdXRpb24gQ2hlY2sKClNpbmNlIG5vdyBhIGBmdXR1cmVgIGV4cHJlc3Npb24gbWF5IGJlIG9yIG1heSBub3QgYmUgYHJlc29sdmVkYCBhbHJlYWR5LAphbmQgYSBgdmFsdWVgIGNhbGwgdG8gdGhlIHByb21pc2VkIHZhbHVlIHdpbGwgYmxvY2sgaWYgdGhlIHZhbHVlIGlzIG5vdCB5ZXQgYHJlc29sdmVkYCwKaXQgYmVjb21lcyBpbXBvcnRhbnQgdG8gaGF2ZSB0aGUgYWJpbGl0eSB0aGF0IGFsbG93cyB1cyB0byBjaGVjayB3aGV0aGVyIGEgcHJvbWlzZSBpcyBhbHJlYWR5IGByZXNvbHZlZGAsCndpdGhvdXQgYmVpbmcgYmxvY2tlZC4KClRoaXMgaXMgZXhhY3RseSB3aGF0IHRoZSBmdW5jdGlvbiBgcmVzb2x2ZWRgIGlzIGRvaW5nOgoKYGBge3IgZnV0dXJlX3Jlc29sdmVkfQpwbGFuKG11bHRpcHJvY2VzcykKCmYgPC0gZnV0dXJlKHsKICBTeXMuc2xlZXAoMSkKICAiSSdtIGZyb20gdGhlIGZ1dHVyZSEiCn0pCgpyZXNvbHZlZChmKSAgIyBSZXR1cm4gaW1tZWRpYXRlbHkgYW5kIGBmYCBpcyBub3QgeWV0IHJlc29sdmVkLgoKU3lzLnNsZWVwKDEpCgpyZXNvbHZlZChmKSAgIyBSZXR1cm4gaW1tZWRpYXRlbHkgYW5kIGBmYCBzaG91bGQgYmUgYWxyZWFkeSByZXNvbHZlZC4KYGBgCgpOb3cgaXQgaXMgdGhlb3JldGljYWxseSBwb3NzaWJsZSB0byBjcmVhdGUgb25lIG5vbi1ibG9ja2luZyBmdXR1cmUgdGhyZWFkIHRvIHdhaXQgZm9yIGFub3RoZXIgbm9uLWJsb2NraW5nIGZ1dHVyZSB0aHJlYWQ6CgpgYGB7ciBub25ibG9ja2luZ19mdXR1cmVfd2FpdF9mb3JfZnV0dXJlfQojIEVkdWNhdGlvbmFsIHB1cnBvc2Ugb25seS4KIyBUaGlzIHBhdHRlcm4gbWF5IG5vdCBiZSB2ZXJ5IHVzZWZ1bCBpbiBwcmFjdGljZS4KZjEgPC0gZnV0dXJlKHsKICBTeXMuc2xlZXAoMykKICAiSSdtIGZyb20gdGhlIGZ1dHVyZSEiCn0pCgpmMiA8LSBmdXR1cmUoewogIHdoaWxlICggVFJVRSApIHsKICAgIGlmICggcmVzb2x2ZWQoZikgKSB7CiAgICAgIHZhbHVlKGYpCiAgICAgIGJyZWFrCiAgICB9CiAgfQp9KQpgYGAKCldoZXRoZXIgc3VjaCBwYXR0ZXJuIGlzIHVzZWZ1bCBhdCBhbGwgZGVwZW5kcyBvbiB0aGUgYWN0dWFsIHVzZSBjYXNlLgpCdXQgaW4gW3RoZSBuZXh0IHNlY3Rpb25dKCNwcm9taXNlcykgd2Ugd2lsbCBsZWFybiBob3cgdG8gY29udHJvbCBldmVuIG1vcmUgb24gYSBwcm9taXNlIHRvIGFycml2ZSBhdCBhIGZ1bGwtZmxldGNoZWQgYXN5bmNocm9ub3VzIHByb2dyYW1taW5nIGZyYW1ld29yayBpbiBSLgoKIyMgRXJyb3IgUHJvcG9nYXRpb24KCkVycm9yIGZyb20gYSBgZnV0dXJlYCBleHByZXNzaW9uIHdpbGwgcHJvcG9nYXRlIHRvIHRoZSBhY3R1YWwgYm91bmRlZCB2YWx1ZSBidXQgbm90IHRoZSBgRnV0dXJlYCBvYmplY3QgaXRzZWxmLgoKYGBge3IgZnV0dXJlX2Vycm9yfQpmZSA8LSBmdXR1cmUoc3RvcCgiRXJyb3IgZnJvbSB0aGUgZnV0dXJlISIpKQpwcmludChjbGFzcyhmZSkpICAjIE5vIGV4Y2VwdGlvbiBiZWZvcmUgYWNjZXNzIHRoZSB2YWx1ZS4KCnRyeUNhdGNoKHZhbHVlKGZlKSwgZXJyb3I9ZnVuY3Rpb24oZSkgcHJpbnQoZSkpCmBgYAoKRm9yIGV4cGxpY2l0IGVycm9yIGhhbmRsaW5nIGl0IGlzIGJldHRlciB0byByZXNvcnQgdG8gdXNpbmcgYHByb21pc2VzYC4KCiMgVXNpbmcgYHByb21pc2VzYCB7I3Byb21pc2VzfQoKVXNpbmcgYHByb21pc2VzYCAoQHByb21pc2VzKSBpcyBvbmUgYmlnIHN0ZXAgYWhlYWQgb2YgYGZ1dHVyZWAsCmVuYWJsaW5nIGV2ZW4gbW9yZSBmbGV4aWJpbGl0eSBvbiBhc3luY2hyb25vdXMgcHJvZ3JhbW1pbmcuCkJ1dCBpdCBhbHNvIGRyYXN0aWNhbGx5IGNoYW5nZXMgaG93IHdlIHNob3VsZCB3cml0ZSBvdXIgY29kZS0tc3BlY2lmaWNhbGx5LCBpbiBhIHByb21pc2Utc3R5bGUuCgpgYGB7ciBpbXBvcnRfcG9ybWlzZXN9CmxpYnJhcnkocHJvbWlzZXMpCnByaW50KGluc3RhbGxlZC5wYWNrYWdlcygpWyJwcm9taXNlcyIsICJWZXJzaW9uIl0pCmBgYAoKYGBge3IgbXVsdGlwcm9jZXNzX3BsYW5fcHJvbWlzZXN9CiMgRml4IHRoZSBwbGFuIHRvIG11bHRpcHJvY2VzcyBmb3IgcHJvbWlzZXMuCnBsYW4obXVsdGlwcm9jZXNzKQpgYGAKCiMjIEZyb20gYGZ1dHVyZWAgdG8gYHByb21pc2VzYAoKQSBgZnV0dXJlYCBleHByZXNzaW9uIHJldHVybiBhICpwcm9taXNlKi4KU3VjaCBwcm9taXNlIGNhbiBiZSBjb252ZXJ0ZWQgZXhwbGljaXRseSB0byBhIGBwcm9taXNlYCBvYmplY3QgdXNpbmcgYHRoZW5gOgoKYGBge3IgcHJvbWlzZX0KZiA8LSBmdXR1cmUoewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSkKCnAgPC0gdGhlbihmLCBvbkZ1bGZpbGxlZD1mdW5jdGlvbih2KSB2KQpwcmludChjbGFzcyhwKSkgICMgQSBwcm9taXNlIG9iamVjdC4Kc3RyKHApCmBgYAoKVW5saWtlIHRoZSBvcmlnaW5hbCByZXR1cm4gdmFsdWUgZnJvbSBhIGBmdXR1cmVgLAphIHByb21pc2UsCmV2ZW4gdW5kZXIgYG11bHRpcHJvY2Vzc2AsCmlzIGFsd2F5cyBgcmVzb2x2ZWRgOgoKYGBge3IgYWx3YXlzX3Jlc29sdmVkX3Byb21pc2UsIHRpbWVpdD1UUlVFfQpmIDwtIGZ1dHVyZSh7CiAgU3lzLnNsZWVwKDEpCiAgIkknbSBmcm9tIHRoZSBmdXR1cmUhIgp9KQoKcCA8LSB0aGVuKGYsIG9uRnVsZmlsbGVkPWZ1bmN0aW9uKHYpIHYpCnJlc29sdmVkKHApICAjIFRoaXMgaXMgYWx3YXlzLCBpbW1lZGlhdGVseSwgVFJVRS4KYGBgCgpQdXQgaXQgZGlmZmVyZW50bHksCmByZXNvbHZlZGAgb25seSB3b3JrcyAob3IgaXMgb25seSBtZWFuaW5nZnVsKSBmb3IgYSBgRnV0dXJlYCBvYmplY3QgYnV0IG5vdCBmb3IgYSBgcHJvbWlzZWAgb2JqZWN0LgoKV2UgbG9vc2VseSBjYWxsIHRoZSByZXR1cm4gdmFsdWUgb2YgYSBgZnV0dXJlYCBhcyBhIHByb21pc2UgYXMgd2VsbCBzaW5jZSB0aGlzIGlzIHRoZSBjb21tb24gd29yZGluZyB1c2VkIGluIGFzeW5jaHJvbm91cyBwcm9ncmFtbWluZy4KQnV0IGhlcmUgd2UgZXhwbGljaXRseSByZWZlciB0byB0aGUgb2JqZWN0IGNsYXNzIGBwcm9taXNlYCBpbXBsZW1lbnRlZCBieSB0aGUgUiBwYWNrYWdlIGBwcm9taXNlc2AuCldoZW4gd2UgcmVmZXIgdG8gdGhlIGdlbmVyYWwgY29uY2VwdCBvZiBwcm9taXNlLAp3ZSB3aWxsIGF2b2lkIHVzaW5nIHRoZSBzeW50YXggaGlnaGxpZ2h0IGZvciBjb2RlIGZvciByZWFkZXJzJyBlYXNlIG9mIGRpc3Rpbmd1aXNoaW5nIHRoZSBkaWZmZXJlbmNlLgoKQSBgRnV0dXJlYCBpcyBub3QsCmJ1dCBjYW4gYmUgYSBgcHJvbWlzZWAuCkluZGVlZCwKd2hlbiBhIGBGdXR1cmVgIG9iamVjdCBpcyBmZWQgdG8gYSBgdGhlbmAgZnVuY3Rpb24sCml0IHdpbGwgYmUgaW1tZWRpYXRlbHkgY29udmVydGVkIHRvIGEgYHByb21pc2VgLWxpa2Ugb2JqZWN0IGJ5IGF0dHJpYnV0ZSBhc3NpZ25tZW50LgpUaGlzIGNhbiBiZSBlYXNpbHkgc2VlbiBpbiB0aGUgZm9sbG93aW5nIGNvZGU6CgpgYGB7ciBmdXR1cmVfaW1wbGljaXRfcHJvbWlzZX0KZiA8LSBmdXR1cmUoewogIFN5cy5zbGVlcCgxKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSkKc3RyKGYpICAjIEEgRnV0dXJlLCBiZWZvcmUgY2FsbGVkIHdpdGggYSB0aGVuIGZ1bmN0aW9uLgoKcCA8LSB0aGVuKGYsIG9uRnVsZmlsbGVkPWZ1bmN0aW9uKHYpIHYpCnN0cihmKSAgIyBUaGUgc2FtZSBGdXR1cmUsIGFmdGVyIGNhbGxlZCB3aXRoIHRoZW4gYW5kIGhhcyBiZWVuIGF0dGFjaGVkIHByb21pc2UgYXR0cmlidXRlcy4KYGBgCgpBIGBGdXR1cmVgIGlzIGVpdGhlciBgcmVzb2x2ZWRgIG9yIG5vdCBgcmVzb2x2ZWRgLgpXaGlsZSBhIGBwcm9taXNlYCBpcyBlaXRoZXIgKnBlbmRpbmcqLCAqZnVsZmlsbGVkKiwgb3IgKnJlamVjdGVkKiAoZHVlIHRvIGVycm9yKS4KCmBgYHtyIHByb21pc2Vfc3RhdHVzfQpmIDwtIGZ1dHVyZSh7CiAgU3lzLnNsZWVwKC4xKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSkKCnAgPC0gdGhlbihmLCBvbkZ1bGZpbGxlZD1mdW5jdGlvbih2KSB2KQpwcmludChwKSAgIyBTdGlsbCBwZW5kaW5nLgpgYGAKCkR1ZSB0byB0aGUgc3BlY2lhbHR5IG9mIHRoZSBub3RlYm9vayByZW5kZXJpbmcgZW52aXJvbm1lbnQsCmEgcHJvbWlzZSBpcyBhbHdheXMgc2hvd24gYXMgcGVuZGluZyBubyBtYXR0ZXIgaG93IGxvbmcgd2Ugd2FpdCBmb3IuCkZvciBhbiBhY3R1YWwgUiBzZXNzaW9uIHRoZSByZXN1bHQgd2lsbCBiZSBzb21ldGhpbmcgbGlrZToKCmBgYAo8UHJvbWlzZSBbZnVsZmlsbGVkOiBjaGFyYWN0ZXJdPgpgYGAKCiMjIE5vIFdheSBCYWNrIE9uY2UgYHByb21pc2VgZAoKSG93IGRvIHdlIGV4dHJhY3QgdGhlIGJvdW5kZWQgdmFsdWUgZnJvbSBhIGBwcm9taXNlYCwKbGlrZSB3aGF0IHdlIGRvIHdpdGggYSBgRnV0dXJlYCBieSB1c2luZyB0aGUgYHZhbHVlYCBmdW5jdGlvbj8KCkl0IHR1cm5zIG91dCB0aGF0LAoqKndlIGNhbm5vdC4qKgoKSW5kZWVkLAoqKmEgYHByb21pc2VgIGlzIEFMV0FZUyBhIGBwcm9taXNlYC4qKgpUaGVyZSBpcyBzaW1wbHkgbm8gd2F5IGJhY2sgb25jZSB3ZSBwaXBlIG91ciB0YXNrIGludG8gYSBgcHJvbWlzZWAuClRoZSBkZXNpZ24gcGhpbG9zb3BoeSBpcyB0aGF0IHdlIG5ldmVyIGtub3cgd2hlbiB0aGUgYHByb21pc2VgZCB2YWx1ZSB3aWxsIGJlIGF2YWlsYWJsZSwKYW5kIGhlbmNlIHRoZSByZXR1cm4gdmFsdWUgZnJvbSBhIGBwcm9taXNlYCBtdXN0IGFsd2F5cyBiZSBhIGBwcm9taXNlYC4KClRvIHByb2Nlc3MgdGhlIHJldHVybiB2YWx1ZSBmcm9tIGEgYHByb21pc2VgLAp3ZSBzaW1wbHkgY2hhaW4gaXQgd2l0aCBhbm90aGVyIGBwcm9taXNlYDoKCmBgYHtyIHByb21pc2VfY2hhaW59CmYgPC0gZnV0dXJlKDEgKyAxKQpwMSA8LSB0aGVuKGYsIG9uRnVsZmlsbGVkPWZ1bmN0aW9uKHYpIHYgKyAxKQpwMiA8LSB0aGVuKHAxLCBvbkZ1bGZpbGxlZD1mdW5jdGlvbih2KSB2ICsgMikKYGBgCgojIyBFcnJvciBIYW5kbGluZwoKV2hlbiBhIGB0aGVuYCBqb2IgZmFpbGVkIGF0IGVpdGhlciBpdHMgYG9uRnVsZmlsbGVkYCBvciBgb25SZWplY3RlZGAgdGFzaywKaXQgcmV0dXJucyBhIHJlamVjdGVkIGBwcm9taXNlYCB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIGVycm9yIHR5cGUuClJlamVjdGlvbiBkb2VzIE5PVCBwcm9wYWdhdGUsIHRob3VnaC4KV2hlbiBhIGB0aGVuYCBqb2IgcHJvY2Vzc2VzIGEgcmVqZWN0ZWQgYHByb21pc2VgLAppdCB3aWxsIGdvIHRvIHRoZSBgb25SZWplY3RlZGAgYnJhbmNoIChieSBkZWZhdWx0IHNpbXBseSBwcm9wYWdhdGUgdGhlIGVycm9yIGlmIG5vdCBzcGVjaWZpZWQpIGFuZCBpZiB0aGF0IHRhc2sgaXMgZG9uZSB3aXRob3V0IGVycm9yLAp0aGUgcmVzdWx0aW5nIHZhbHVlIGlzIGEgZnVsZmlsbGVkIGBwcm9taXNlYC4KClRoZSBmb2xsb3dpbmcgZXhhbXBsZSBpbGx1c3RyYXRlcyB0aGUgYWJvdmUgaWRlYToKCmBgYHtyIHByb21pc2VfZXJyb3JfMX0KcGxhbihzZXF1ZW50aWFsKQoKZiA8LSBmdXR1cmUoMSArIDEpCgojIFRoZSBmaXJzdCBwcm9taXNlIHdpbGwgZmFpbCBhdCBpdHMgb25GdWlsZmlsbGVkIHRhc2sgKG9uIHB1cnBvc2UpLgpwMSA8LSB0aGVuKAogIGYsICAjIFRoaXMgaXMgYSBmdWxmaWxsZWQgcHJvbWlzZS4KICBvbkZ1bGZpbGxlZD1mdW5jdGlvbih2KSBzdG9wKHYpLCAgIyBIZW5jZSB3ZSBmb2xsb3cgdGhpcyBicmFuY2guIChBbmQgdGhlbiB3aWxsIGZhaWwuKQogIG9uUmVqZWN0ZWQ9ZnVuY3Rpb24oZSkgZQopCgojIFRoZSBzZWNvbmQgcHJvbWlzZSB3aWxsIGdvIHRvIHRoZSBvblJlamVjdGVkIGJyYW5jaCBzaW5jZSB0aGUgZmlyc3QgcHJvbWlzZSBmYWlsZWQuCnAyIDwtIHRoZW4oCiAgcDEsICAjIFRoaXMgaXMgZmFpbGVkIG9uIGl0cyBvd24gb25GdWxmaWxsZWQgdGFzay4KICBvbkZ1bGZpbGxlZD1mdW5jdGlvbih2KSBwcmludChzcHJpbnRmKCJGcm9tIG9uRnVsZmlsbGVkOiAlcyIsIHYpKSwKICBvblJlamVjdGVkPWZ1bmN0aW9uKGUpIHByaW50KHNwcmludGYoIkZyb20gb25SZWplY3RlZDogJXMiLCBlKSkgICMgSGVuY2Ugd2UgZ28gaGVyZS4KKQoKCgpwMQpwMgpgYGAKClRoZSBmaXJzdCBgcHJvbWlzZWAgb2JqZWN0IGBwMWAgd2lsbCBoYXZlIGEgdmFsdWUgb2YKCmBgYAo8UHJvbWlzZSBbcmVqZWN0ZWQ6IHNpbXBsZUVycm9yXT4KYGBgCgphZnRlciBydW5uaW5nIGl0cyBvd24gYG9uRnVsZmlsbGVkYCB0YXNrLgpCdXQgdGhlIHNlY29uZCBgcHJvbWlzZWAgb2JqZWN0IGBwMmAgaW5zdGVhZCB3aWxsIGhhdmUgYSB2YWx1ZSBvZgoKYGBgCjxQcm9taXNlIFtmdWxmaWxsZWQ6IGNoYXJhY3Rlcl0+CmBgYAoKYWZ0ZXIgcnVubmluZyBpdHMgb3duIGBvblJlamVjdGVkYCB0YXNrIGFuZCBhbHNvIHByaW50IHRoZSBtZXNzYWdlCgpgYGAKWzFdICJGcm9tIG9uUmVqZWN0ZWQ6IEVycm9yIGluIG9uRnVsZmlsbGVkKHZhbHVlKTogMiIKYGBgCgpUaGVuIHNhbWUgbG9naWMgYXBwbGllcyB0byBgRnV0dXJlYCBvYmplY3QgKGkuZS4sIGNvbnZlcnRlZCBgcHJvbWlzZWApOgoKYGBge3IgcHJvbWlzZV9lcnJvcl8yLCBldmFsPUZBTFNFfQojIEVycm9yIGF0IHRoZSBmdXR1cmUgZXhwcmVzc2lvbi4KZiA8LSBmdXR1cmUoc3RvcCgiU29tZXRoaW5nIGp1c3Qgd2VudCB3cm9uZyBhdCB0aGUgdmVyeSBiZWdpbm5pbmcuIikpCgojIFRoZSBmaXJzdCBwcm9taXNlIHdpbGwgZ28gZm9yIHRoZSBvblJlamVjdGVkIHRhc2ssIGFuZCByZXR1cm4gc3VjY2Vzc2Z1bGx5LgpwMSA8LSB0aGVuKAogIGYsCiAgb25GdWxmaWxsZWQ9ZnVuY3Rpb24odikgewogICAgcHJpbnQoIkZyb20gb25GdWxmaWxsZWQuIikKICAgIHYKICB9LAogIG9uUmVqZWN0ZWQ9ZnVuY3Rpb24oZSkgewogICAgcHJpbnQoIkZyb20gb25SZWplY3RlZCIpCiAgICBlCiAgfQopCgojIFNpbmNlIHRoZSBvblJlamVjdGVkIHRhc2sgaXMgc3VjY2Vzc2Z1bGx5IGV4Y2VjdXRlZCwgcDEgYmVjb21lcyBhIGZ1bGZpbGxlZCBwcm9taXNlLgojIHAyIHRoZW4gd2lsbCBnbyBmb3IgdGhlIG9uRnVsZmlsbGVkIHRhc2suCnAyIDwtIHRoZW4oCiAgcDEsCiAgb25GdWxmaWxsZWQ9ZnVuY3Rpb24odikgewogICAgcHJpbnQoIkZyb20gb25GdWxmaWxsZWQuIikKICAgIHYKICB9LAogIG9uUmVqZWN0ZWQ9ZnVuY3Rpb24oZSkgewogICAgcHJpbnQoIkZyb20gb25SZWplY3RlZCIpCiAgICBlCiAgfQopCgpTeXMuc2xlZXAoMykgICMgV2FpdCBsb25nZXIgdG8gYWxsb3cgZm9yIHBvdGVudGlhbCBiYWNrZW5kIG92ZXJoZWFkLgoKcDEKcDIKYGBgCgpUaGlzIHRpbWUgYHAxYCB3aWxsIHByaW50CgpgYGAKWzFdICJGcm9tIG9uUmVqZWN0ZWQiCmBgYAoKd2l0aCBhIHZhbHVlIG9mCgpgYGAKPFByb21pc2UgW2Z1bGZpbGxlZDogc2ltcGxlRXJyb3JdPgpgYGAKCkFuZCBgcDJgIHdpbGwgcHJpbnQKCmBgYApbMV0gIkZyb20gb25GdWxmaWxsZWQuIgpgYGAKCndpdGggYSB2YWx1ZSBvZgoKYGBgCjxQcm9taXNlIFtmdWxmaWxsZWQ6IHNpbXBsZUVycm9yXT4KYGBgCgpCb3RoIGBwcm9taXNlYHMgYXJlIGBmdWxmaWxsZWRgIChpLmUuLCBubyBmdXJ0aGVyIGVycm9yIGF0IHRoZSBicmFuY2gpIG9uIHRoZWlyIGNvcnJlc3BvbmRpbmcgdGFzaywKd2hldGhlciBpdCBpcyBhIGJyYW5jaCB0YXNrIG9mIGBvbkZ1bGZpbGxlZGAgb3IgYG9uUmVqZWN0ZWRgLgoKIyMgU3ludGFjdGljIFN1Z2FycwoKVGhlcmUgYXJlIHNldmVyYWwgc3ludGFjdGljIHN1Z2FycyBhdmFpbGFibGUgd2hlbiB1c2luZyB0aGUgYHRoZW5gIEFQSS4KCiMjIyBMYW1iZGEgRXhwcmVzc2lvbiB7LX0KCmBgYHtyIHByb21pc2Vfc3VnYXJfbGFtYmRhfQpmIDwtIGZ1dHVyZSh7CiAgU3lzLnNsZWVwKC4xKQogICJJJ20gZnJvbSB0aGUgZnV0dXJlISIKfSkKCnAgPC0gdGhlbihmLCB+ewogIC4gICMgUmV0dXJuIHRoZSBGdXR1cmUgdmFsdWUgYXMtaXMuCn0pCmBgYAoKIyMjIFByb21pc2UtQXdhcmUgUGlwZSB7LX0KCmBgYHtyIHByb21pc2Vfc3VnYXJfcGlwZX0KZiA8LSBmdXR1cmUoewogIFN5cy5zbGVlcCguMSkKICAiSSdtIGZyb20gdGhlIGZ1dHVyZSEiCn0pICUuLi4+JSB7CiAgY2F0KC4pICAjIFRoaXMgd29uJ3Qgb3V0cHV0IHRvIHRoZSBub3RlYm9vayBjb2RlIGNodW5rLgp9CmBgYAoKVGhlIHBpcGUgYCUuLi4+JWAgb25seSBzdXBwb3J0cyBgb25GdWxmaWxsZWRgIGZ1bmN0aW9uLgpJbiBzdWNoIGNhc2UgdGhlIGBvblJlamVjdGVkYCB0YXNrIGlzIHNpbXBseSBhbiBlcnJvciBwcm9wYWdhdGlvbi4KCkZvciBgb25SZWplY3RlZGAgZnVuY3Rpb24gb25lIGNhbiB1c2UgYCUuLi4hJWAgaW5zdGVhZC4KQW5kIHRoZSBgb25GdWxmaWxsZWRgIHRhc2sgaXMgYSBzaW1wbGUgYGlkZW50aXR5YC4KCkZvciBhIGNvbXBsZXRlIGN1c3RvbSBicmFuY2ggaGFuZGxpbmcgb25lIHNob3VsZCBhbHdheXMgdXNlIHRoZSBgdGhlbmAgQVBJIGV4cGxpY2l0bHkuCgojIEFzeW5jIHdpdGggUmVhY3RpdmUgUHJvZ3JhbW1pbmcKClJlYWN0aXZlIHByb2dyYW1taW5nIGluIFIgaXMgaW50cm9kdWNlZCBieSB0aGUgd2VsbC1rbm93biBgc2hpbnlgIHBhY2thZ2UgKEBzaGlueSkgd2hpY2ggZmFjaWxpdGF0ZXMgdGhlIGVhc2Ugb2Ygd2ViIGFwcGxpY2F0aW9uIGRldmVsb3BtZW50IHB1cmVseSB1c2luZyBSLAp1c3VhbGx5IGZvciBkYXRhLWRyaXZlbiBkYXNoYm9hcmQgYnVpbGRpbmcgcHVycG9zZS4KCkEgaHVnZSBsaW1pdGF0aW9uIGFib3V0IHN1Y2ggd2ViIGFwcCBpcyB0aGF0IFIgaXMgYSBzaW5nbGUtdGhyZWFkZWQgcHJvY2Vzcy4KUmVhY3RpdmUgcHJvZ3JhbW1pbmcgaXRzZWxmIGRvZXMgbm90IHByb3ZpZGUgYXN5bmNocm9ueS4KSW4gb3JkZXIgZm9yIGEgd2ViIGFwcCB0byBiZSBzY2FsYWJsZSBmb3IgYSBtdWx0aS1zZXNzaW9uIHVzZSBjYXNlLApyZWFjdGl2ZSBwcm9ncmFtbWluZyBtdXN0IGNvbWJpbmUgd2l0aCBhc3luY2hyb25vdXMgcHJvZ3JhbW1pbmcuCgpUaGUgZ29vZCBuZXdzIGlzIHRoYXQgYHNoaW55YCBoYXMgY29tZSBmdWxseSBzdXBwb3J0IGZvciBgZnV0dXJlYCBhbmQgYHByb21pc2VzYCB1bmRlciBpdHMgcmVhY3RpdmUgcHJvZ3JhbW1pbmcgZnJhbWV3b3JrIGFmdGVyIGl0cyBtYWpvciByZWxlYXNlIG9mIHYxLjEuCgojIyBBIFF1aWNrIFJlY2FwOiBSZWFjdGl2ZSBQcm9ncmFtbWluZwoKYGBge3IgaW1wb3J0X3NoaW55fQpsaWJyYXJ5KHNoaW55KQpwcmludChpbnN0YWxsZWQucGFja2FnZXMoKVsic2hpbnkiLCAiVmVyc2lvbiJdKQpgYGAKCkJyb2FkbHkgc3BlYWtpbmcgdGhlcmUgYXJlIHR3byB0eXBlcyBvZiBoYW5kbGVyIGluIHJlYWN0aXZlIHByb2dyYW1tbmluZyBmb3IgYHNoaW55YDoKdmFsdWUgaGFuZGxlciBhbmQgZXZlbnQgaGFuZGxlci4KCiMjIyBWYWx1ZSBIYW5kbGVyCgpUbyByZWdpc3RlciBhbiBvYmplY3Qgd2hvc2UgdmFsdWUgY2hhbmdlcyByZWFjdGl2ZWx5IChhY2NvcmRpbmcgdG8sIHNheSwgdXNlciBpbnB1dCBmcm9tIGEgd2ViIGFwcCBwb3J0YWwpLAp3ZSBjYW4gdXNlIGByZWFjdGl2ZVZhbGAgb3IgYHJlYWN0aXZlVmFsdWVzYC4KYHJlYWN0aXZlVmFsYCBpcyBkZXNpZ25lZCBmb3IgYSBzaW5nbGUgdmFsdWUgKHNpbmdsZSBvYmplY3QpIHdoaWxlIGByZWFjdGl2ZVZhbHVlc2AgaXMgZGVzaWduZWQgZm9yIGEgbGlzdCBvZiB2YWx1ZXMgKG11bHRpcGxlIG9iamVjdHMpLgoKVG8gaW5pdGlhbGl6ZSBhIHJlYWN0aXZlIHZhbHVlIHdpdGhvdXQgYSBkZWZhdWx0IChgTlVMTGAgYXMgZGVmYXVsdCk6CgpgYGByCnIgPC0gcmVhY3RpdmVWYWwodmFsdWU9TlVMTCkKYGBgCgpUbyB1cGRhdGUgdGhlIHZhbHVlIHdlIHNpbXBseSBjYWxsOgoKYGBgcgpyKHgpICAjIGB4YCBpcyB0aGUgbmV3IHZhbHVlIGFzc2lnbmVkIHJlYWN0aXZlbHkgdG8gYHJgLgpgYGAKCkFuZCB0byByZXRyaWV2ZSB0aGUgdmFsdWUgd2UgY2FuIGNhbGwgd2l0aG91dCBhcmd1bWVudDoKCmBgYHIKcigpCmBgYAoKSW4gZ2VuZXJhbCBgcmVhY3RpdmVWYWxgIGlzIG9ubHkgY2FsbGFibGUgdW5kZXIgYSByZWFjdGl2ZSBjb250ZXh0IChhbGwgdGhlIGByZW5kZXIqYCBmdW5jdGlvbiBzdWNoIGFzIGByZW5kZXJUZXh0YCwgYHJlbmRlclByaW50YCkuClRvIHRlc3QgaXQgaW50ZXJhY3RpdmVseSwKd2UgY2FuIGFsc28gdXNlIGBpc29sYXRlYCB0byBkaXJlY3RseSByZXRyaWV2ZSB0aGUgdmFsdWUgbm9uLXJlYWN0aXZlbHk6CgpgYGB7ciByZWFjdGl2ZVZhbF9pc29sYXRlfQpyIDwtIHJlYWN0aXZlVmFsKHZhbHVlPU5VTEwpCmlzb2xhdGUocigpKQpyKDQyKQppc29sYXRlKHIoKSkKYGBgCgpUbyBpbml0aWFsaXplIGEgbGlzdCBvZiByZWFjdGl2ZSB2YWx1ZXM6CgpgYGByCnJsIDwtIHJlYWN0aXZlVmFsdWVzKCkKYGBgCgpgcmVhY3RpdmVWYWx1ZXNgIGNhbiBiZSBkaXJlY3RseSB1cGRhdGUgYnkgdXNpbmcgdGhlIGxpc3QgYXNzaWdubWVudCBzeW50YXg6CgpgYGByCnJsJGEgPC0gMQpybCRiIDwtIDEKYGBgCgpUbyB0ZXN0IGl0OgoKYGBge3IgcmVhY3RpdmVWYWx1ZXNfaXNvbGF0ZX0KcmwgPC0gcmVhY3RpdmVWYWx1ZXMoKQpybCRhIDwtIDEKcmwkYiA8LSAxCmlzb2xhdGUocmwkYSArIHJsJGIpCmBgYAoKV2UgY2FuIGNyZWF0ZSByZWFjdGl2ZSBmdW5jdGlvbnMgd2hpY2ggZGVwZW5kIG9uIHJlYWN0aXZlIHZhbHVlcy4KVGhlIGZ1bmN0aW9uIHdpbGwgcmUtZXhlY3V0ZSBldmVyeXRpbWUgYW55IG9mIHRoZSBkZXBlbmRlbnQgcmVhY3RpdmUgdmFsdWVzIGNoYW5nZS4KCmBgYHtyIHJlYWN0aXZlX2Z1bmN0aW9ufQpybCA8LSByZWFjdGl2ZVZhbHVlcyhhPTEsIGI9MikKCnJmIDwtIHJlYWN0aXZlKHsKICBybCRhICsgcmwkYgp9KQoKaXNvbGF0ZShyZigpKQpgYGAKCk9yIHdlIGNhbiBjcmVhdGUgcmVhY3RpdmUgb2JzZXJ2ZXIgZnVuY3Rpb25zIHNpbWlsYXIgdG8gYHJlYWN0aXZlYCBidXQgb25seSBmb3IgaXRzIHNpZGUtZWZmZWN0cyAoaS5lLiwgbm8gcmV0dXJuIHZhbHVlKToKCmBgYHtyIHJlYWN0aXZlX29ic2VydmVyfQpybCA8LSByZWFjdGl2ZVZhbHVlcyhhPTEsIGI9MikKCiMgTm90aGluZyB3aWxsIGJlIHByaW50ZWQgc2luY2UgdGhlIHZhbHVlIGRvZXNuJ3QgY2hhbmdlIHdpdGhvdXQgYSByZWFjdGl2ZSBjb250ZXh0LgpvYnNlcnZlKHsKICBwcmludChybCRhICsgcmwkYikKfSkKYGBgCgojIyMgRXZlbnQgSGFuZGxlcgoKV2UgY2FuIGFsc28gY3JlYXRlIGhhbmRsZXJzIHRoYXQgZXhwbGljaXRseSByZXNwb25kIHRvIFVJIGNvbXBvbmVudCBvciBvdGhlciByZWFjdGl2ZSBldmVudHMgZGVmaW5lZCBieSBhIHJlYWN0aXZlIGZ1bmN0aW9uLgoKRm9yIGV4YW1wbGUsCndlIGNhbiByZWFjdCB0byBhIHVzZXIgYnV0dG9uIGNsaWNrIGJ5IGEgYGV2ZW50UmVhY3RpdmVgIGZ1bmN0aW9uOgoKYGBgcgpyIDwtIGV2ZW50UmVhY3RpdmUoaW5wdXQkcnVuLCB7ZXhwcn0pICAjIEFzc3VtZSBgcnVuYCBpcyB0aGUgaWQgZm9yIGEgYnV0dG9uIGluIHRoZSBVSSBjb2RlLgpgYGAKCk5vdCBqdXN0IFVJIGNvbXBvbmVudCwKYGV2ZW50UmVhY3RpdmVgIGNhbiByZWFjdCB0byBhbnl0aGluZyByZWFjdGl2ZToKCmBgYHtyIGV2ZW50UmVhY3RpdmV9CnIgPC0gcmVhY3RpdmVWYWwoKQpyKDEyMykKZXIgPC0gZXZlbnRSZWFjdGl2ZShyKCksIDQ1NikKaXNvbGF0ZShlcigpKQpgYGAKCldlIGNhbiBkbyB0aGUgc2FtZSBidXQgb25seSBmb3Igc2lkZS1lZmZlY3RzIGJ5IHVzaW5nIGBvYnNlcnZlRXZlbnRgOgoKYGBgcgpvYnNlcnZlRXZlbnQoaW5wdXQkcnVuLCB7ZXhwcn0pICAjIEFzc3VtZSBgcnVuYCBpcyB0aGUgaWQgZm9yIGEgYnV0dG9uIGluIHRoZSBVSSBjb2RlLgpgYGAKCiMjIyBBIE1pbmltdW0gQXBwIFRlbXBsYXRlCgpGb3IgY29tcGxldGVuZXNzLAp0aGUgZm9sbG93aW5nIGNvZGUgY2h1bmsgcHJvdmlkZXMgYSBtaW5pbXVtIHNpbmdsZS1maWxlIHdvcmtpbmcgYHNoaW55YCBhcHAgd2l0aCBhIHVzZXIgaW5wdXQgYnV0dG9uIGFuZCBhIG91dHB1dCB0ZXh0IHdpbmRvdy4KCmBgYHtyIG1pbl9hcHAsIGV2YWw9RkFMU0V9CiMgRGVmaW5lIGZyb250ZW5kIGNvZGUuCnVpIDwtIGZsdWlkUGFnZSgKCiAgdGl0bGVQYW5lbCgiVGVzdCBSZWFjdGl2ZSBQcm9ncmFtbWluZyBpbiBSIiksCiAgYWN0aW9uQnV0dG9uKCJkbyIsICJEbyBzb21ldGhpbmcuIiksCiAgdWlPdXRwdXQoIm91dCIpCgopCgojIERlZmluZSBiYWNrZW5kIGNvZGUuCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0LCBzZXNzaW9uKSB7CgogIG9ic2VydmVFdmVudChpbnB1dCRkbywgewogICAgb3V0cHV0JG91dCA8LSByZW5kZXJUZXh0KHsKICAgICAgIlNvbWV0aGluZy4iCiAgICB9KQogIH0pCgp9CgojIExhdW5jaCB0aGUgYXBwLgpzaGlueUFwcCh1aT11aSwgc2VydmVyPXNlcnZlciwgb3B0aW9ucz1saXN0KHBvcnQ9ODc4NykpCmBgYAoKIyMgUHJvbWlzZS1Bd2FyZSBSZWFjdGl2ZSBFeHByZXNzaW9uCgpBbGwgcmVhY3RpdmUgZnVuY3Rpb25zIHByb3ZpZGVkIGJ5IGBzaGlueWAgYXJlIGJvdGggYGZ1dHVyZWAgYW5kIGBwcm9taXNlYCBhd2FyZS4KSXQgbWVhbnMgdGhhdCByZWFjdGl2ZSBleHByZXNzaW9ucyBjYW4gYmUgYSBgRnV0dXJlYDoKCmBgYHtyIHJlYWN0aXZlX2Z1dHVyZX0KcmwgPC0gcmVhY3RpdmVWYWx1ZXMoYT0xLCBiPTIpCgpyZiA8LSByZWFjdGl2ZSh7CiAgZnV0dXJlKHJsJGEgKyBybCRiKQp9KQoKaXNvbGF0ZSh2YWx1ZShyZigpKSkKYGBgCgpvciBhIGBwcm9taXNlYDoKCmBgYHtyIHJlYWN0aXZlX3Byb21pc2V9CnJsIDwtIHJlYWN0aXZlVmFsdWVzKGE9MSwgYj0yKQoKcmYgPC0gcmVhY3RpdmUoewogIGZ1dHVyZShybCRhICsgcmwkYikgJS4uLj4lIHsKICAgIC4KICB9Cn0pCgppc29sYXRlKHN0cihyZigpKSkKYGBgCgojIyBFeHBlcmltZW50YWwgQXBwIG9uIEFzeW5jCgpUbyBzZWUgaG93IG9uZSBzZXNzaW9uIGlzIGJsb2NraW5nIGFub3RoZXIgaW4gYSBzaW5nbGUtdGhyZWFkZWQgYXBwLApoZXJlIGlzIGEgbWluaW11bSBhcHAgZm9yIHB1cmUgaWxsdXN0cmF0aW9uIHB1cnBvc2U6CgpgYGB7ciBzaGlueV9hc3luY19hcHAsIGV2YWw9RkFMU0V9CmxpYnJhcnkoc2hpbnkpCmxpYnJhcnkoZnV0dXJlKQpsaWJyYXJ5KHByb21pc2VzKQoKCmV4ZWNfcGxhbiA8LSBjb21tYW5kQXJncyh0cmFpbGluZ09ubHk9VFJVRSlbMV0KaWYgKCBpcy5uYShleGVjX3BsYW4pICkgZXhlY19wbGFuIDwtICJzZXF1ZW50aWFsIgoKcGxhbihleGVjX3BsYW4pCgoKIyBEZWZpbmUgZnJvbnRlbmQgY29kZS4KdWkgPC0gZmx1aWRQYWdlKAoKICB0aXRsZVBhbmVsKCJBc3luYyBTaGlueSBBcHAiKSwKICB0ZXh0T3V0cHV0KCJ0aW1lIiksCiAgYWN0aW9uQnV0dG9uKCJkbyIsICJEbyBzb21lIGhlYXZ5IHdvcmtzLiIpLAogIHZlcmJhdGltVGV4dE91dHB1dCgib3V0IikKCikKCgpkb19oZWF2eV93b3JrIDwtIGZ1bmN0aW9uKCkgewogIHN0IDwtIFN5cy50aW1lKCkKCiAgU3lzLnNsZWVwKDUpICMgT3IgYW55dGhpbmcgZXhwZW5zaXZlIGhlcmUuCgogIGV0IDwtIFN5cy50aW1lKCkKICBsaXN0KHN0PXN0LCBldD1ldCkKfQoKCiMgRGVmaW5lIGJhY2tlbmQgY29kZS4Kc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQsIHNlc3Npb24pIHsKCiAgb3V0cHV0JHRpbWUgPC0gcmVuZGVyVGV4dCh7CiAgICBpbnZhbGlkYXRlTGF0ZXIoMTAwMCwgc2Vzc2lvbikKICAgIHBhc3RlKCJUaGUgY3VycmVudCB0aW1lIGlzIiwgU3lzLnRpbWUoKSkKICB9KQoKICBvYnNlcnZlRXZlbnQoaW5wdXQkZG8sIHsKICAgIHN0IDwtIFN5cy50aW1lKCkgICMgVGhpcyBvbmx5IHJlY29yZCB3aGVuIHRoZSBhcHAgc3RhcnRzIHByb2Nlc3MgdGhlIGlucHV0IGJ1dCBOT1Qgd2hlbiB0aGUgdXNlciBoaXQgdGhlIGJ1dHRvbi4KICAgIG91dHB1dCRvdXQgPC0gcmVuZGVyVGV4dCh7CiAgICAgIGZ1dHVyZShkb19oZWF2eV93b3JrKCkpICUuLi4+JSB7CiAgICAgICAgcGFzdGUoCiAgICAgICAgICAiSGVhdnkgd29yayBkb25lISIsCiAgICAgICAgICBzcHJpbnRmKCJTdGFydGVkIGF0ICVzIiwgc3QpLAogICAgICAgICAgc3ByaW50ZigiRW5kZWQgYXQgJXMiLCAuJGV0KSwKICAgICAgICAgIHNwcmludGYoIlRpbWUgdXNlZDogJXMiLCAuJGV0IC0gc3QpLAogICAgICAgICAgc2VwPSJcbiIKICAgICAgICApCiAgICAgIH0KICAgIH0pCiAgfSkKCn0KCiMgTGF1bmNoIHRoZSBhcHAuCnNoaW55QXBwKHVpPXVpLCBzZXJ2ZXI9c2VydmVyLCBvcHRpb25zPWxpc3QocG9ydD04Nzg3KSkKYGBgCgpUbyBwbGF5IGFyb3VuZCB3aXRoIHRoZSBhY3R1YWwgYXBwLApydW46CgpgYGBzaApSc2NyaXB0IGFwcC5SCmBgYAoKZm9yIHN5bmNocm9ub3VzIG1vZGUuCgpUaGUgYXBwIHdpbGwgYmUgbGlzdGVuaW5nIG9uIGAxMjcuMC4wLjE6ODc4N2AuCk9wZW4gbW9yZSB0aGFuIDEgdGFiIGFuZCBjbGljayB0aGUgYGRvYCBidXR0b24gZm9yIGFsbCB0aGUgb3BlbmluZyB0YWJzLgpGb3IgYSBgc2VxdWVudGlhbGAgYXBwIHdlIHNoYWxsIG9ic2VydmUgdGhlIHRpbWVyIHN0b3AganVtcGluZyB3aGVuIHRoZXJlIGlzIGFueSBvdGhlciBzZXNzaW9uIChicm93c2VyIHRhYikgc3RpbGwgd29ya2luZyBhbmQgaGVuY2UgYmxvY2tpbmcuClRoZSBtb3JlIG90aGVyIHNlc3Npb25zIGFyZSBzdGlsbCB3b3JraW5nLAp0aGUgbW9yZSB0aW1lcyB5b3Ugd2lsbCBzZWUgdGhlIHRpbWVyIGp1bXAgYW5kIHN0b3AuClRoZSBzdGFydCB0aW1lIHJlY29yZGVkIGluIHRoZSBvdXRwdXQgdGV4dCBpcyBhbHdheXMgcm91Z2hseSA1IHNlY29uZHMgYmVmb3JlIGl0IGVuZGVkLgpIb3dldmVyIHRoZSBzdGFydCB0aW1lIGlzIE5PVCB0aGUgdGltZSB3ZSBoaXQgdGhlIGBkb2AgYnV0dG9uLgoKTm93IGNsb3NlIHRoZSBhcHAuCkZvciBhc3luY2hyb25vdXMgbW9kZSBydW46CgpgYGBzaApSc2NyaXB0IGFwcC5SIG11bHRpcHJvY2VzcwpgYGAKCmFuZCBpbnZlc3RpZ2F0ZSBhZ2Fpbi4KClRoZSB0aW1lciB3aWxsIHN0aWxsIHN0b3AganVtcGluZyB3aGVuIHdlIGhpdCB0aGUgYGRvYCBidXR0b24uCkJ1dCB0aGlzIHRpbWUgaXQgZGlkbid0IHN0b3AgbW9yZSB0aGFuIG9uY2UuCipJdCBvbmx5IHN0b3AgZm9yIGl0cyBvd24gc2Vzc2lvbi4qCgpBbmQgdGhlIHRpbWVyIGlzIHN0b3BwaW5nIGJlY2F1c2Ugd2UgZGlkbid0IGltcGxlbWVudCB0aGUgdGltZXIgYXN5bmNocm9ub3VzbHkuCkluIHRoZSBleHBlcmltZW50YWwgYXBwIG9ubHkgdGhlIGBkb19oZWF2eV93b3JrYCBvcGVyYXRpb24gaXMgaW1wbGVtZW50ZWQgaW4gYXN5bmNocm9ub3VzIG1vZGUuCgpJbiBnZW5lcmFsIHdlIHdpbGwgb25seSBtYWtlIHRob3NlIGhlYXZ5IHRhc2tzIGFzeW5jaHJvbm91cyBpbnN0ZWFkIG9mIHRyeWluZyB0byBtYWtlIGV2ZXJ5dGhpbmcgYXN5bmNocm9ub3VzLgoKIyBDbG9zaW5nIFJlbWFya3MKClVwIHRvIG5vdyB3ZSd2ZSBlcXVpcGVkIHdpdGggdGhlIGJhc2ljIGtub3dsZWRnZSB0byBzdGFydCBkZXZlbG9waW5nIGFzeW5jaHJvbm91cyB3ZWIgYXBwbGljYXRpb24gdXNpbmcgUi4KVGhlcmUgYXJlIGZhciBtb3JlIGZlYXR1cmVzIHRoZW4gd2hhdCB3ZSBqdXN0IGRpc2N1c3NlZCBoZXJlIGZvciBhbGwgdGhlc2UgcGFja2FnZXM6CmBmdXR1cmVgLCBgcHJvbWlzZXNgLCBhbmQgYHNoaW55YC4KQnV0IHdlIHdpbGwgbGVhdmUgaXQgZm9yIGV4cGxvcmF0aW9uIGFuZCByZXRhaW4gdGhlIHNjb3BlIG9mIHRoaXMgbm90ZWJvb2sgYXQgYSBlbnRyeS1sZXZlbC4KCiMgUmVmZXJlbmNlcwo=