1 Trading basics

https://quantstrattrader.wordpress.com/

1.1 Why do people trade?

1.1.1 Identifying types of trading philosophies

Hello and welcome to Financial Trading in R! This course will teach you how to construct a basic trading strategy in quantstrat, R’s industrial-strength backtesting platform developed by Brian Peterson, Director of Algorithmic Trading at DV Trading. Over the next few chapters, you’ll build a trading strategy in quantstrat from start to finish, including the code to set up a new strategy, as well as the design of indicators, signals, and rules for your strategy. By the end of the course, you’ll be ready to design and implement your own trading strategies directly in R!

quantstrat is currently only available on GitHub. If you want to install it on your own machine, you first need to remotes package.

install.packages("remotes")

Then you can install quantstrat using

remotes::install_github("braverock/quantstrat")

“Introduction to Quantitative Trading With R.”

**Above doesnt seem to work, you can do the below**

  1. download package from github (blotter and quantstrat)
  2. Open command line
  3. build packages using R CMD BUILD
  4. install packages using R CMD INSTALL

Before getting into the meat and potatoes of the course, let’s review some phrases and mechanics you may have heard in the world of financial trading, or even in pop culture. As you learned in the video, the mechanics of trading usually come in one of two forms:

  • Trend trading (also divergence or momentum), which is a bet that a quantity, such as a price, will keep moving in its current direction.
  • Reversion trading (also convergence, cycle, or oscillation), which is a bet that a quantity, such as a price, will reverse. “Buying the dip” can refer to both trend trading and reversion trading.
library(blotter)
Loading required package: xts
package 㤼㸱xts㤼㸲 was built under R version 4.0.3Loading required package: zoo
package 㤼㸱zoo㤼㸲 was built under R version 4.0.3
Attaching package: 㤼㸱zoo㤼㸲

The following objects are masked from 㤼㸱package:base㤼㸲:

    as.Date, as.Date.numeric

Loading required package: FinancialInstrument
package 㤼㸱FinancialInstrument㤼㸲 was built under R version 4.0.3Loading required package: quantmod
package 㤼㸱quantmod㤼㸲 was built under R version 4.0.3Loading required package: TTR
package 㤼㸱TTR㤼㸲 was built under R version 4.0.3Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
Version 0.4-0 included new data defaults. See ?getSymbols.
Loading required package: PerformanceAnalytics
package 㤼㸱PerformanceAnalytics㤼㸲 was built under R version 4.0.3
Attaching package: 㤼㸱PerformanceAnalytics㤼㸲

The following object is masked from 㤼㸱package:graphics㤼㸲:

    legend
library(foreach)
package 㤼㸱foreach㤼㸲 was built under R version 4.0.3
library(quantstrat)

1.2 Pitfalls of various trading systems

1.2.1 How to prevent overfitting

When developing a trading system, a major pitfall that can creep into system development is the desire to find a strategy that worked phenomenally in the past. This is known as overfitting. Research by leading authors in the quantitative field has shown that not only is an overfitted system unlikely to generate profits in the future, but also that its performance can lead to losses.

Overfitting can be reduced by:

  • Examining the robustness of system performance.
  • Reducing the number of parameters in the trading system.
  • Conducting tests to determine statistical significance of a strategy.

1.3 Getting financial data

1.3.1 Plotting financial data

Trading strategies developed using quantstrat contain several characteristics, including indicators developed from market data, signals triggered by certain combinations of indicators, and rules acted on by certain signals. The first step in developing any trading system is to obtain market data, and maybe even examine how it looks.

The quantmod package has a function to obtain data from various sources. This is the getSymbols() command, which returns an object with the same name as the symbol.

You will obtain data for SPY, an exchange traded fund (ETF) that tracks the top 500 companies in the United States by market cap. This data is from Yahoo! Finance, which is a sufficient source of data for strategies that do not require instantaneous “see the close, buy the close” execution. You will then plot it and add a trendline to it.

For example, to obtain adjusted data for SPY in 2013 from Yahoo! Finance and then plot the maximum values traded each day, you would run the following code. Notice how only the first reference to the SPY data is enclosed in quotation marks.

getSymbols("SPY", 
           from = "2013-01-01",
           to = "2013-12-31",
           src = "yahoo",
           adjust = TRUE)
plot(Hi(SPY))
# Get SPY from yahoo
getSymbols("SPY", 
           from = "2000-01-01", 
           to = "2016-06-30", 
           src =  "yahoo", 
           adjust =  TRUE)
㤼㸱getSymbols㤼㸲 currently uses auto.assign=TRUE by default, but will
use auto.assign=FALSE in 0.5-0. You will still be able to use
㤼㸱loadSymbols㤼㸲 to automatically load data. getOption("getSymbols.env")
and getOption("getSymbols.auto.assign") will still be checked for
alternate defaults.

This message is shown once per session and may be disabled by setting 
options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.

incomplete final line found by readTableHeader on 'https://query2.finance.yahoo.com/v7/finance/download/SPY?period1=-2208988800&period2=1605139200&interval=1d&events=split&crumb=babpKD7rHPl'incomplete final line found by readTableHeader on 'https://query2.finance.yahoo.com/v7/finance/download/SPY?period1=-2208988800&period2=1605139200&interval=1d&events=split&crumb=babpKD7rHPl'
[1] "SPY"
# Plot the closing price of SPY
plot(Cl(SPY))

1.4 Adding indicators to financial data

1.4.1 Adding a moving average to financial data

One of the most popular indicators to add to a trading strategy is the 200-day simple moving average (SMA). This is a technical indicator of the average closing price of a stock over the past 200 days. Other moving averages can be of varying length, such as 50-day, 100-day, etc.

Whenever the price is above the 200-day moving average, a whole assortment of good things usually happen, such as the asset appreciating in price, low volatility, and so on. Getting a long-lasting visual might shed light on why this indicator is mentioned so often.

The TTR package has a function that calculates moving averages, SMA(), which takes in a price series x and computes the arithmetic mean over n days. A call of SMA() with a lookback window of 50 days could look like the following:

SMA(Cl(GDX), n = 50)
# Plot the closing prices of SPY
plot(Cl(SPY))


# Add a 200-day SMA using lines()
lines(SMA(Cl(SPY), n = 200), col = "red")

As you can see from your plot, indicators such as the 200-day SMA help you identify trends in your data.

2 A boilerplate for quantstrat strategies

2.1 Setting up a strategy I

2.1.1 Understanding initialization settings – Define boilerplate code

Let’s get started with creating our first strategy in quantstrat. In this exercise, you will need to fill in three dates:

  • An initialization date for your backtest.
  • The start of your data.
  • The end of your data. The initialization date must always come before the start of the data, otherwise there will be serious errors in the output of your backtest.

You should also specify what time zone and currency you will be working with with the functions Sys.setenv() and currency(), respectively. An example is here:

Sys.setenv(TZ = "Europe/London")
currency("EUR")

You’ll use UTC (Coordinated Universal Time) and USD (United States Dollars) for your portfolio settings.

# Load the quantstrat package
library(quantstrat)

# Create initdate, from, and to strings
initdate <- "1999-01-01"
from <- "2003-01-01"
to <- "2015-12-31"

# Set the timezone to UTC
Sys.setenv(TZ = "UTC")

# Set the currency to USD 
currency("USD")
[1] "USD"

2.1.2 Understanding initialization settings – stock()

Like in the previous chapter, you will use getSymbols() to obtain the SPY data from Yahoo! Finance.

After importing the data, use stock() to tell quantstrat what instruments will be present for the simulation, and to treat them just as they are, as opposed to creating a minimum buy size, as with futures. Furthermore, this command specifies which currency to use with the given instruments. Note that whenever you use a function to initialize a data set such as GDX or SPY, you must enclose it in quotation marks:

stock("GDX", currency = "USD")
# Load the quantmod package
library(quantmod)

# Retrieve SPY from yahoo
getSymbols("SPY", from = from, to = to, src = "yahoo", adjust = TRUE)
incomplete final line found by readTableHeader on 'https://query1.finance.yahoo.com/v7/finance/download/SPY?period1=-2208988800&period2=1605139200&interval=1d&events=split&crumb=babpKD7rHPl'incomplete final line found by readTableHeader on 'https://query2.finance.yahoo.com/v7/finance/download/SPY?period1=-2208988800&period2=1605139200&interval=1d&events=split&crumb=babpKD7rHPl'
[1] "SPY"
# Use stock() to initialize SPY and set currency to USD
stock("SPY", currency = "USD")
[1] "SPY"

2.1.3 Understanding initialization settings - account, porfolio and strategy

Let’s continue the setup of your strategy. First, you will set a trade size of 100,000 USD in an object called tradesize which determines the amount you wager on each trade. Second, you will set your initial equity to 100,000 USD in an object called initeq.

Quantstrat requires three different objects to work: an account, a portfolio, and a strategy. An account is comprised of portfolios, and a portfolio is comprised of strategies. For your first strategy, there will only be one account, one portfolio, and one strategy. Let’s call them “firststrat” for “first strategy”.

Finally, before proceeding, you must remove any existing strategies using the strategy removal command rm.strat() which takes in a string of the name of a strategy.

# Define your trade size and initial equity
tradesize <- 100000
initeq <- 100000

# Define the names of your strategy, portfolio and account
strategy.st <- "firststrat"
portfolio.st <- "firststrat"
account.st <- "firststrat"

# Remove the existing strategy if it exists
rm.strat(strategy.st)

2.1.4 Understanding initialization settings – IV

Now that everything has been named, you must initialize the portfolio, the account, the orders, and the strategy to produce results.

  • The portfolio initialization initPortf() needs a portfolio string name, a vector for symbols used in the backtest, an initialization date initDate, and a currency.
  • The account initialization call initAcct() is identical to the portfolio initialization call except it takes an account string name instead of a new portfolio name, an existing portfolios name, and an initial equity initEq.
  • The orders initialization initOrders() needs a portfolio string portfolio and an initialization date initDate.
  • The strategy initialization strategy() needs a name of this new strategy and must have store set to TRUE.
# Initialize the portfolio
initPortf(portfolio.st, symbols = "SPY", initDate = initdate, currency = "USD")
[1] "firststrat"
# Initialize the account
initAcct(account.st, portfolios = portfolio.st, initDate = initdate, currency = "USD", initEq = initeq)
[1] "firststrat"
# Initialize the orders
initOrders(portfolio.st, initDate = initdate)

# Store the strategy
strategy(strategy.st, store = TRUE)

Your quantstrat strategy strategy.st is now up and running.

3 Indicators

3.1 Introduction

3.1.1 The SMA and RSI functions

Welcome to the chapter on indicators! An indicator is a transformation of market data that is used to generate signals or filter noise. Indicators form the backbone of many trading systems, and the system you will build in this course uses several of them.

The simple moving average (SMA) and relative strength index (RSI) are two classic indicators. The SMA is an arithmetic moving average of past prices, while the RSI is a bounded oscillating indicator that ranges from 0 to 100. Their respective functions SMA() and RSI() both take in a series of prices, denoted by x and price respectively, and a lookback period n, for example:

SMA(x = Cl(GDX), n = 50)
RSI(price = Cl(GDX), n = 50)
# Create a 200-day SMA
spy_sma <- SMA(x = Cl(SPY), n = 200)

# Create an RSI with a 3-day lookback period
spy_rsi <- RSI(price = Cl(SPY), n = 3)

3.1.2 Visualize an indicator and guess its purpose – SMA

Now you will visualize these indicators to understand why you might want to use the indicator and what it may represent. Recall that a trend indicator attempts to predict whether a price will continue in its current direction, whereas a reversion indicator attempts to predict whether an increasing price will soon decrease, or the opposite.

In this exercise, you will revisit the 200-day SMA. As a refresher, this indicator attempts to smooth out prices, but comes with a tradeoff - a lag. You will plot the prices of SPY and plot a 200-day SMA on top of the price series. Using this information, you will determine if it is a trend indicator or reversion indicator

# Plot the closing prices of SPY
plot(Cl(SPY))


# Overlay a 200-day SMA
lines(SMA(Cl(SPY), n = 200), col = "red")


# What kind of indicator?
print("trend")
[1] "trend"

By averaging over a moving period of 200 days, the SMA helps indicate a trend rather than a reversion.

3.1.3 Visualize an indicator and guess its purpose – RSI

The Relative Strength Index (RSI) is another indicator that rises with positive price changes and falls with negative price changes. It is equal to 100 - 100/(1 + RS), where RS is the average gain over average loss over the lookback period. At various lengths, this indicator can range from a reversion indicator, to a trend filter, or anywhere in between. There are various ways of computing the RSI.

As you already know, RSI() takes in a price series price and a number of periods n which has a default value of 14. Some traders believe that the 2-period RSI, also known as the RSI 2, has even more important properties than the 14-period RSI. Rather than plotting this indicator on the actual price series, you’ll look at a small, one year subset of SPY and how the RSI interacts with the price.

# Plot the closing price of SPY
plot(Cl(SPY))


# Plot the RSI 2
plot(RSI(Cl(SPY), n = 2))


# What kind of indicator?
print("reversion")
[1] "reversion"

By measuring the change of price movements, the RSI indicates a reversion rather than a trend.

3.2 Indicator mechanics

3.2.1 Implementing an indicator – SMA200

At this point, it’s time to start getting into the mechanics of implementing an indicator within the scope of the quantstrat library. In this exercise you will learn how to add an indicator to your strategy. For this exercise you will use the strategy you created in earlier exercises, strategy.st. For your first indicator, you will add a 200-day simple moving average. To add an indicator to your strategy, you will use the add.indicator(). Set strategy equal to the name of your strategy, name to the name of a function in quotes, and arguments to the arguments of the named function in the form of a list. For instance, if your function name was SMA, the arguments argument will contain the arguments to the SMA function:

add.indicator(strategy = strategy.st, 
              name = "SMA", 
              arguments = list(x = quote(Cl(mktdata)), n = 500), 
              label = "SMA500")

When referencing dynamic market data in your add.indicator() call, include mktdata inside the quote() function because it is created inside quantstrat and will change depending on whichever instrument the package is using at the time. quote() ensures that the data can dynamically change over the course of running your strategy.

#Add a 200-day SMA indicator to strategy.st
add.indicator(strategy = strategy.st, 
              
              # Add the SMA function
              name = "SMA", 
              
              # Create a lookback period
              arguments = list(x = quote(Cl(mktdata)), n = 200), 
              
              # Label your indicator SMA50
              label = "SMA200")
[1] "firststrat"

3.2.2 Implementing an indicator – SMA50

Now, you’ll make your strategy even more robust by adding a 50-day SMA. A fast moving average with a slower moving average is a simple and standard way to predict when prices in an asset are expected to rise in the future. While a single indicator can provide a lot of information, a truly robust trading system requires multiple indicators to operate effectively.

# Add a 50-day SMA indicator to strategy.st
add.indicator(strategy = strategy.st, 
              
              # Add the SMA function
              name = "SMA", 
              
              # Create a lookback period
              arguments = list(x = quote(Cl(mktdata)), n = 50), 
              
              # Label your indicator SMA50
              label = "SMA50")
[1] "firststrat"

By adding a second indicator to your strategy, you’ve made it more robust.

3.2.3 Implementing an indicator – RSI

In financial markets, the goal is to buy low and sell high. The RSI can predict when a price has sufficiently pulled back, especially with a short period such as 2 or 3.

Here, you’ll create a 3-period RSI, or RSI 3, to give you more practice in implementing pre-coded indicators.

# Add an RSI 3 indicator to strategy.st
add.indicator(strategy = strategy.st, 
              
              # Add the RSI 3 function
              name = "RSI", 
              
              # Create a lookback period
              arguments = list(price = quote(Cl(mktdata)), n = 3), 
              
              # Label your indicator RSI_3
              label = "RSI_3")
[1] "firststrat"

3.3 Indicator structure review

3.3.1 Code your own indicator – RSI 3.5

So far, you’ve used indicators that have been completely pre-written for you by using the add.indicator() function. Now it’s time for you to write and apply your own indicator.

Your indicator function will calculate the average of two different indicators to create an RSI of 3.5. Here’s how:

  • Take in a price series.
  • Calculate RSI 3.
  • Calculate RSI 4.
  • Return the average of RSI 3 and RSI 4.

This RSI can be thought of as an RSI 3.5, because it’s longer than an RSI 3 and shorter than an RSI 4. By averaging, this indicator takes into account the impact of four days ago while still being faster than a simple RSI 4, and also removes the noise of both RSI 3 and RSI 4.

You will create a function for this indicator called calc_RSI_avg() and add it to your strategy strategy.st. All relevant packages are also loaded for you.

# Write the calc_RSI_avg function
calc_RSI_avg <- function(price, n1, n2) {
  
  # RSI 1 takes an input of the price and n1
  RSI_1 <- RSI(price = price, n = n1)
  
  # RSI 2 takes an input of the price and n2
  RSI_2 <- RSI(price = price, n = n2)
  
  # RSI_avg is the average of RSI_1 and RSI_2
  RSI_avg <- (RSI_1 + RSI_2)/2
  
  # Your output of RSI_avg needs a column name of RSI_avg
  colnames(RSI_avg) <- "RSI_avg"
  return(RSI_avg)
}

# Add this function as RSI_3_4 to your strategy with n1 = 3 and n2 = 4
add.indicator(strategy.st, name = "calc_RSI_avg", arguments = list(price = quote(Cl(mktdata)), n1 = 3, n2 = 4), label = "RSI_3_4")
[1] "firststrat"

3.3.2 Code your own indicator – DVO

While the RSI is decent, it is somewhat outdated as far as indicators go. In this exercise, you will code a simplified version of another indicator from scratch. The indicator is called the David Varadi Oscillator (DVO), originated by David Varadi, a quantitative research director.

The purpose of this oscillator is similar to something like the RSI in that it attempts to find opportunities to buy a temporary dip and sell in a temporary uptrend. In addition to obligatory market data, an oscillator function takes in two lookback periods.

First, the function computes a ratio between the closing price and average of high and low prices. Next, it applies an SMA to that quantity to smooth out noise, usually on a very small time frame, such as two days. Finally, it uses the runPercentRank() function to take a running percentage rank of this average ratio, and multiplies it by 100 to convert it to a 0-100 quantity.

Think about the way that students get percentile scores after taking a standardized test (that is, if a student got an 800 on her math section, she might be in the 95th percentile nationally). runPercentRank() does the same thing, except over time. This indicator provides the rank for the latest observation when taken in the context over some past period that the user specifies. For example, if something has a runPercentRank value of .90 when using a lookback period of 126, it means it’s in the 90th percentile when compared to itself and the past 125 observations.

Your job is to implement this indicator and save it as DVO.

# Declare the DVO function
DVO <- function(HLC, navg = 2, percentlookback = 126) {
  
  # Compute the ratio between closing prices to the average of high and low
  ratio <- Cl(HLC)/(Hi(HLC) + Lo(HLC))/2
  
  # Smooth out the ratio outputs using a moving average
  avgratio <- SMA(ratio, n = navg)
  
  # Convert ratio into a 0-100 value using runPercentRank()
  out <- runPercentRank(avgratio, n = percentlookback, exact.multiplier = 1) * 100
  colnames(out) <- "DVO"
  return(out)
}

3.3.3 Apply your own indicator

Now you have a better understanding of indicators as functions that anyone can write. It’s time to apply the indicator you created in the previous exercise. To do so, you will make use of the applyIndicators() command.

From debugging to subsetting, knowing how to step inside your strategy is a valuable piece of knowledge. Every so often, you might have an error in your strategy, and will want to track it down. Knowing how to use the applyIndicators() command will help you identify your errors. Furthermore, sometimes you may want to look at a small chunk of time in your strategy. This exercise will help train you to do this as well.

In order to subset time series data, use brackets with the start date, forward slash symbol, and end date.

# Add the DVO indicator to your strategy
add.indicator(strategy = strategy.st, name = "DVO", 
              arguments = list(HLC = quote(HLC(mktdata)), navg = 2, percentlookback = 126),
              label = "DVO_2_126")
[1] "firststrat"
# Use applyIndicators to test out your indicators
test <- applyIndicators(strategy = strategy.st, mktdata = HLC(SPY))

# Subset your data between Sep. 1 and Sep. 5 of 2013
test_subset <- test["2013-09-01/2013-09-05"]

4 Signals

4.1 Introduction to signals

4.1.1 Signal or not? – I

A signal is an interaction of market data with indicators, or indicators with other indicators, which tells you whether you may wish to buy or sell an asset. Signals can be triggered for a variety of reasons. For example, a signal may be triggered by a shorter lookback moving average going from less than to greater than a longer lookback moving average. Another signal may be triggered when an oscillator goes from being above a certain set quantity (for example, 20) to below, and so on.

In this chapter, you will see various ways in which indicators interact with each other. You will focus on the strategy you developed in the previous chapter (strategy.st). To keep thing simple, you will remove all of the RSI indicators and stick to the DVO (David Varadi’s Oscillator). sigThreshold is a signal threshold argument which assesses whether or not a value is above or below a certain static quantity.

4.2 sigComparison and sigCrossover

4.2.1 Using sigComparison

A sigComparison signal is a simple and useful way to compare two (hopefully related) quantities, such as two moving averages. Often, a sigComparison signal does not create a buy or sell signal by itself (as such a signal would involve buying or selling on every such day), but is most often useful as a filter for when another buy or sell rule should be followed.

In this exercise, you will use sigComparison() to generate a signal comparison that specifies that the 50-day simple moving average (SMA) must be above the 200-day simple moving average (SMA). You will label this signal longfilter, because it signals that the short-term average is above the long-term average.

# Add a sigComparison which specifies that SMA50 must be greater than SMA200, call it longfilter
add.signal(strategy.st, name = "sigComparison", 
           
           # We are interested in the relationship between the SMA50 and the SMA200
           arguments = list(columns = c("SMA50", "SMA200"), 
                            
                            # Particularly, we are interested when the SMA50 is greater than the SMA200
                            relationship = "gt"),
           
           # Label this signal longfilter
           label = "longfilter")
[1] "firststrat"

4.2.2 Using sigCrossover

While having a long filter is necessary, it is not sufficient to put on a trade for this strategy. However, the moment the condition does not hold, the strategy should not hold any position whatsoever. For this exercise, you will implement the opposite of the rule specified above using the sigCrossover() function.

As opposed to sigComparison(), which will always state whether or not a condition holds, sigCrossover() only gives a positive the moment the signal first occurs, and then not again. This is useful for a signal that will be used to initiate a transaction, as you only want one transaction in most cases, rather than having transactions fire again and again.

In this case, you will implement the sigCrossover() function specifying that the SMA50 crosses under the SMA200. You will label this signal filterexit, as it will exit your position when the moving average filter states that the environment is not conducive for the strategy to hold a position.

# Add a sigCrossover which specifies that the SMA50 is less than the SMA200 and label it filterexit
add.signal(strategy.st, name = "sigCrossover",
           
           # We're interested in the relationship between the SMA50 and the SMA200
           arguments = list(columns = c("SMA50", "SMA200"),
                            
                            # The relationship is that the SMA50 crosses under the SMA200
                            relationship = "lt"),
           
           # Label it filterexit
           label = "filterexit")
[1] "firststrat"

4.3 sigThreshold

4.3.1 Using sigThreshold – threshold

In the next two exercises, you will focus on the sigThreshold signal. The sigThreshold signal is mainly used for comparing an indicator to a fixed number, which usually has applications for bounded oscillators, or perhaps rolling statistical scores (for example, for a trading strategy that might choose to go long when a ratio of mean to standard deviation is at -2, or vice versa). Whereas sigComparison and sigCrossover deal with quantities that are usually based off of an indicator that takes values in the same general area as prices, sigThreshold exists specifically to cover those situations outside the bounds of indicators that take values similar to prices.

Furthermore, the sigThreshold() function takes the cross argument, which specifies whether it will function similarly to sigComparison (cross = FALSE) or sigCrossover (cross = TRUE), respectively. In this exercise, you will implement a variant of sigThreshold that functions similarly to sigComparison.

Your job will be to implement a sigThreshold that checks whether or not DVO_2_126 is under 20. This signal will serve as one of the two switches that need to be “on” in order to enter into a long position in the strategy.

# Implement a sigThreshold which specifies that DVO_2_126 must be less than 20, label it longthreshold
add.signal(strategy.st, name = "sigThreshold", 
           
           # Use the DVO_2_126 column
           arguments = list(column = "DVO_2_126", 
                            
                            # The threshold is 20
                            threshold = 20, 
                            
                            # We want the oscillator to be under this value
                            relationship = "lt", 
                            
                            # We're interested in every instance that the oscillator is less than 20
                            cross = FALSE), 
           
           # Label it longthreshold
           label = "longthreshold")
[1] "firststrat"

4.3.2 Using sigThreshold() – exit

In this exercise, you will implement a signal to exit a position given a certain threshold value of the DVO. While there are two entry signals that are both necessary but neither sufficient on its own, the two exit signals (this one and the one you implemented in an earlier exercise) are both sufficient on their own (but neither necessary in the existence of the other) to exit a position.

In this exercise, you will again use sigThreshold(), this time counting when the DVO_2_126 crosses above a threshold of 80. To mimic a sigCrossover signal, set cross equal to TRUE Label this signal thresholdexit.

# Add a sigThreshold signal to your strategy that specifies that DVO_2_126 must cross above 80 and label it thresholdexit
add.signal(strategy.st, name = "sigThreshold", 
           
           # Reference the column of DVO_2_126
           arguments = list(column = "DVO_2_126", 
                            
                            # Set a threshold of 80
                            threshold = 80, 
                            
                            # The oscillator must be greater than 80
                            relationship = "gt", 
                            
                            # We are interested only in the cross
                            cross = TRUE), 
           
           # Label it thresholdexit
           label = "thresholdexit")
[1] "firststrat"

4.4 sigFormula

4.4.1 Using sigFormula()

The last signal function is a bit more open-ended. The sigFormula() function uses string evaluation to offer immense flexibility in combining various indicators and signals you already added to your strategy in order to create composite signals. While such catch-all functionality may seem complicated at first, with proper signal implementation and labeling, a sigFormula signal turns out to be the simplest of logical programming statements encapsulated in some quantstrat syntactical structuring.

# Create your dataset: test
test_init <- applyIndicators(strategy.st, mktdata = OHLC(SPY))
test <- applySignals(strategy = strategy.st, mktdata = test_init)

4.4.2 Combining signals – longfilter & longthreshold

you created a dataset test containing information about whether longfilter is equal to 1 AND longthreshold is equal to 1.

Next, you’ll want to create a signal when BOTH longfilter and longthreshold are equal to 1. Have a look at test on October 8, 2013. Are longfilter and longthreshold both equal to 1 on that date?

test["2013-10-08"]
           SPY.Open SPY.High  SPY.Low SPY.Close SMA.SMA200 SMA.SMA50 rsi.RSI_3 RSI_avg.RSI_3_4
2013-10-08 160.0033 160.2136 158.0535  158.1682   151.4826  160.0628   17.8146        19.85266
           DVO.DVO_2_126 longfilter filterexit longthreshold thresholdexit
2013-10-08      3.174603          1         NA             1             0
print("longfilter = 1, longthreshold = 1")
[1] "longfilter = 1, longthreshold = 1"

4.4.3 Combining signals – longentry

In the previous exercise, you approximated a sigFormula signal by comparing the value of two other signals. In this final exercise, you will take this one step futher by using the sigFormula() function to generate a sigFormula signal.

The goal of this exercise is simple. You want to enter into a position when both longfilter and longthreshold become true at the same time. The idea is this: You don’t want to keep entering into a position for as long as conditions hold true, but you do want to hold a position when there’s a pullback in an uptrending environment.

Writing a sigFormula function is as simple as writing the argument of an “if statement” in base R inside the formula() function. In this case, you want to create a signal labeled longentry, which is true when both longfilter and longthreshold cross over to true at the same time.

# Add a sigFormula signal to your code specifying that both longfilter and longthreshold must be TRUE, label it longentry
add.signal(strategy.st, name = "sigFormula",
           
           # Specify that longfilter and longthreshold must be TRUE
           arguments = list(formula = "longfilter & longthreshold", 
                            
                            # Specify that cross must be TRUE
                            cross = TRUE),
           
           # Label it longentry
           label = "longentry")
[1] "firststrat"

5 Rules

5.1 Introduction to rules

5.1.1 Using add.rule() to implement an exit rule

While rules in quantstrat can become very complex, this chapter will fill in many of the details for you to help you develop an understanding of the actual mechanics of rules. Rules are the final mechanic in the trinity of quantstrat mechanics – indicators, signals, and rules. Rules are a way for you to specify exactly how you will shape your transaction once you decide you wish to execute on a signal.

Throughout this chapter, you will continue working the strategy developed in earlier chapters (strategy.st). Given that there are three rules to the strategy (two exit rules and one entry rule), there will be a handful of exercises to build up some intuition of the mechanics of rules.

This exercise will introduce you to the add.rule() function, which allows you to add customized rules to your strategy.

# Fill in the rule's type as exit
add.rule(strategy.st, name = "ruleSignal", 
         arguments = list(sigcol = "filterexit", sigval = TRUE, orderqty = "all", 
                        ordertype = "market", orderside = "long", 
                        replace = FALSE, prefer = "Open"), 
         type = "exit")
[1] "firststrat"

5.1.2 Specifying sigcol in add.rule()

Although the add.rule() command looks complex, each argument is quite simple. To understand this command, you will explore each argument individually.

First, add.rule() takes the argument sigcol, which specifies the signal column in your strategy. Like signals and indicators, all rules reference a column already present in your strategy. Rules relies on signals, and must therefore reference the signal columns in your strategy.

In this exercise, you will supply the add.rule() call with the sigcol value, which will be set to filterexit (to reference the filterexit signal you created in the previous chapter). Specifically, the filterexit signal refers to the condition that the 50 day SMA has crossed under the 200 day SMA in your strategy. By creating a rule for this signal, you will be indicating that you wish to exit in this condition, as the market environment is no longer conducive to your position.

sigcol = "filterexit"

5.1.3 Specifying sigval in add.rule()

Now that you’ve specified the column containing the relevant signal in your strategy, the next argument to specify in add.rule() is sigval, or the value that your signal should take to trigger the rule.

Remember that all signal outputs are either 1s or 0s. Effectively, a signal is either “on” or “off” at any given time. For our purposes, this is equivalent to two possible logical values: TRUE or FALSE. When specifying sigval in your add.rule() command, you need to indicate whether the rule is triggered when the signal value is TRUE or FALSE.

To proceed with the new exit rule in your strategy, you will want to specify that a transaction should occcur when filterexit is equal to TRUE.

sigval = TRUE

sigval tells your rule which value to look for in your signal in order to act.

5.2 More rule mechanics

5.2.1 Specifying orderqty in add.rule()

Now that you have a grasp of the first set of arguments in the add.rule() function, it’s time to move on to the more important arguments: the actual order being bought or sold! The orderqty argument in the ruleSignal specifies exactly how much of an asset you want to buy or sell, in numbers of shares.

However, one salient feature of the exit rule type is that you can reduce your position to zero instantly with the all argument (hence, exiting).

orderqty = "all"

Remember that the orderqty argument can also take numerical values to indicate the number of shares being bought or sold.

5.2.2 Specifying ordertype in add.rule()

To this point you’ve specified the signal column, signal value, and order quantity associated with your rule. Next you will specify the type of order you will execute (ordertype).

While there are multiple types of orders in quantstrat, for the scope of this course you will stick to market orders (ordertype = “market”). A market order is an order that states that you will buy or sell the asset at the prevailing price, regardless of the conditions in the market. An alternative type of orders is a limit order, which specifies that the transaction will only take place if certain price conditions are met (namely, if the price falls below a certain further threshold on the day of the order).

ordertype = "market"

It is important to specify ordertype for your strategy to function properly.

5.2.3 Specifying orderside in add.rule()

The next critical argument to specify in your order is orderside, which can take two values: either long or short. In quantstrat, long and short side trades are siloed off separately so that quantstrat knows whether a trade is a long trade or a short trade. A long trade is one that profits by buying an asset in the hopes that the asset’s price will rise. A short trade is one that sells an asset before owning it, hoping to buy it back later at a lower price.

For your strategy, you will want to take only long orders.

orderside = "long"

5.2.4 Specifying replace in add.rule()

In quantstrat, the replace argument specifies whether or not to ignore all other signals on the same date when the strategy acts upon one signal. This is generally not a desired quality in a well-crafted trading system. Therefore, for your exit rule, you should set replace to FALSE.

Furthermore, you will be working with a new rule. Previously, the exit rule you worked with was when the market environment was no longer conducive to a trade. In this case, you will be working with a rule that sells when the DVO has crossed a certain threshold. In particular, you will be working with the thresholdexit rule now.

replace = FALSE

5.2.5 Specifying prefer in add.rule()

Lastly, of the basic rule arguments, there is the aspect of the prefer argument. In quantstrat, orders have a “next-bar” mechanism. That is, if you would gain a signal on Tuesday, the earliest that a position would actually fulfil itself would be on the Wednesday after. However, this can be solved by placing orders to execute on the next possible opening price, rather than wait for an entire day to pass before being able to actually purchase/sell the asset.

prefer = "Open"

The prefer argument is the final critical argument to specify to make sure your rule works properly.

5.2.6 Using add.rule() to implement an entry rule

You’ve mastered every element of the rule building process in quantstrat. While thus far you’ve added rules step-by-step, now it’s time to put it all together and see how well you’ve been able to absorb the material in this chapter.

The opposite of an exit rule is an enter rule. On enter rules, orderqty cannot be set to “all” because there is no initial position on which to act. In this exercise, you will implement an enter rule that references the longentry signal in your strategy and will buy one share of an asset.

# Create an entry rule of 1 share when all conditions line up to enter into a position
add.rule(strategy.st, name = "ruleSignal", 
         
         # Use the longentry column as the sigcol
         arguments=list(sigcol = "longentry", 
                        
                        # Set sigval to TRUE
                        sigval = TRUE, 
                        
                        # Set orderqty to 1
                        orderqty = 1,
                        
                        # Use a market type of order
                        ordertype = "market",
                        
                        # Take the long orderside
                        orderside = "long",
                        
                        # Do not replace other signals
                        replace = FALSE, 
                        
                        # Buy at the next day's opening price
                        prefer = "Open"),
         
         # This is an enter type rule, not an exit
         type = "enter")
[1] "firststrat"

5.3 Order sizing functions

5.3.1 Implementing a rule with an order sizing function

In quantstrat, the amount of an asset transacted may not always be a fixed quantity in regards to the actual shares. The constructs that allow quantstrat to vary the amount of shares bought or sold are called order sizing functions. Using a pre-coded order sizing function is straightforward. The first thing to know is that when using an order sizing function, the orderqty argument is no longer relevant, as the order quantity is determined by the order sizing function. Calling an order sizing function with your add.rule() call is fairly straightforward. The inputs for the order sizing function are mixed in with the rest of the inputs inside the arguments that you have been working with throughout this chapter. In this exercise, you will use the osFUN argument to specify a function called osMaxDollar. This is not passed in as a string, but rather as an object. The only difference is that the name of the order sizing function is not encased in quotes.

The additional arguments to this function are tradeSize and maxSize, both of which should take tradesize, which you defined several chapters earlier.

osMaxDollar <- function (data, timestamp, orderqty, ordertype, orderside, portfolio, 
    symbol, prefer = "Open", tradeSize, maxSize, integerQty = TRUE, 
    ...) 
{
    pos <- getPosQty(portfolio, symbol, timestamp)
    if (prefer == "Close") {
        price <- as.numeric(Cl(mktdata[timestamp, ]))
    }
    else {
        price <- as.numeric(Op(mktdata[timestamp, ]))
    }
    posVal <- pos * price
    if (orderside == "short") {
        dollarsToTransact <- max(tradeSize, maxSize - posVal)
        if (dollarsToTransact > 0) {
            dollarsToTransact = 0
        }
    }
    else {
        dollarsToTransact <- min(tradeSize, maxSize - posVal)
        if (dollarsToTransact < 0) {
            dollarsToTransact = 0
        }
    }
    qty <- dollarsToTransact/price
    if (integerQty) {
        qty <- trunc(qty)
    }
    return(qty)
}
# Add a rule that uses an osFUN to size an entry position
add.rule(strategy = strategy.st, name = "ruleSignal",
         arguments = list(sigcol = "longentry", sigval = TRUE, ordertype = "market",
                          orderside = "long", replace = FALSE, prefer = "Open",
                          
                          # Use the osFUN called osMaxDollar
                          osFUN = osMaxDollar,
                          
                          # The tradeSize argument should be equal to tradesize (defined earlier)
                          tradeSize = tradesize,
                          
                          # The maxSize argument should be equal to tradesize as well
                          maxSize = tradesize),
         type = "enter")
[1] "firststrat"

Implementing a rule with an order size function allows much more flexibility than a standard set rule.

6 Analyzing results

6.1 Analyzing your strategy

6.1.1 Running your strategy

To review, your strategy uses three separate indicators and five separate signals. The strategy requires both the threshold of the DVO_2_126 indicator to be under 20 and the SMA50 to be greater than the SMA200. The strategy sells when the DVO_2_126 crosses above 80, or the SMA50 crosses under the SMA200.

For this strategy to work properly, you specified five separate signals:

  1. sigComparison for SMA50 being greater than SMA200;
  2. sigThreshold with cross set to FALSE for DVO_2_126 less than 20;
  3. sigFormula to tie them together and set cross to TRUE;
  4. sigCrossover with SMA50 less than SMA200; and
  5. sigThreshold with cross set to TRUE for DVO_2_126 greater than 80.

The strategy invests $100,000 (your initeq) into each trade, and may have some small dollar cost averaging if the DVO_2_126 oscillates around 20 (though the effect is mostly negligible compared to the initial allocation).

# Use applyStrategy() to apply your strategy. Save this to out
out <- applyStrategy(strategy = strategy.st, portfolios = portfolio.st)
[1] "2003-11-04 00:00:00 SPY 1 @ 82.8469578360576"
[1] "2003-11-04 00:00:00 SPY 1209 @ 82.8469578360576"
[1] "2003-11-11 00:00:00 SPY 1 @ 82.1434723265441"
[1] "2003-11-17 00:00:00 SPY 1 @ 82.0027817904916"
[1] "2003-11-19 00:00:00 SPY 1 @ 81.3149269126141"
[1] "2003-11-19 00:00:00 SPY 3 @ 81.3149269126141"
[1] "2003-12-04 00:00:00 SPY 1 @ 83.7693034544295"
[1] "2003-12-17 00:00:00 SPY 1 @ 84.4649709123541"
[1] "2004-01-26 00:00:00 SPY 1 @ 89.8352933883476"
[1] "2004-01-29 00:00:00 SPY 1 @ 89.1834585776171"
[1] "2004-02-05 00:00:00 SPY 1 @ 88.8771751199046"
[1] "2004-02-17 00:00:00 SPY 1 @ 90.9818922139293"
[1] "2004-02-20 00:00:00 SPY 1 @ 90.691319526913"
[1] "2004-03-04 00:00:00 SPY 1 @ 90.8798000840517"
[1] "2004-03-09 00:00:00 SPY 1 @ 90.3928855644821"
[1] "2004-03-23 00:00:00 SPY 1 @ 86.8875112703844"
[1] "2004-04-14 00:00:00 SPY 1 @ 88.7474170616372"
[1] "2004-04-21 00:00:00 SPY 1 @ 88.4242948197242"
[1] "2004-04-29 00:00:00 SPY 1 @ 88.8341075490725"
[1] "2004-05-10 00:00:00 SPY 1 @ 86.2491556209151"
[1] "2004-05-20 00:00:00 SPY 1 @ 86.2570326338416"
[1] "2004-06-07 00:00:00 SPY 1 @ 89.393654452605"
[1] "2004-06-22 00:00:00 SPY 1 @ 89.4826721872208"
[1] "2004-06-28 00:00:00 SPY 1 @ 90.5821234171208"
[1] "2004-07-06 00:00:00 SPY 1 @ 88.8815381310937"
[1] "2004-07-16 00:00:00 SPY 1 @ 88.248758071904"
[1] "2004-07-22 00:00:00 SPY 1 @ 86.5007105045458"
[1] "2004-08-06 00:00:00 SPY 1 @ 85.1323255940912"
[1] "2004-08-26 00:00:00 SPY -1238 @ 87.7662642951484"
[1] "2004-11-11 00:00:00 SPY 1 @ 93.0719232673771"
[1] "2004-11-11 00:00:00 SPY 1075 @ 93.0719232673771"
[1] "2004-11-30 00:00:00 SPY 1 @ 94.0009737487592"
[1] "2004-12-06 00:00:00 SPY 1 @ 94.9648812422764"
[1] "2004-12-08 00:00:00 SPY 1 @ 94.1682628206767"
[1] "2004-12-28 00:00:00 SPY 1 @ 96.5580225549442"
[1] "2005-01-03 00:00:00 SPY 1 @ 97.2943727284263"
[1] "2005-01-21 00:00:00 SPY 1 @ 94.2769368997169"
[1] "2005-02-10 00:00:00 SPY 1 @ 95.7736526933884"
[1] "2005-02-23 00:00:00 SPY 1 @ 95.1893710017315"
[1] "2005-03-10 00:00:00 SPY 1 @ 97.006234590446"
[1] "2005-03-17 00:00:00 SPY 1 @ 95.4935143684339"
[1] "2005-03-23 00:00:00 SPY 1 @ 93.9722829469485"
[1] "2005-04-04 00:00:00 SPY 1 @ 94.3017315393874"
[1] "2005-04-12 00:00:00 SPY 1 @ 94.7275983482366"
[1] "2005-04-15 00:00:00 SPY 1 @ 93.0000181217213"
[1] "2005-04-21 00:00:00 SPY 1 @ 92.2366714849296"
[1] "2005-05-16 00:00:00 SPY 1 @ 92.9678763056753"
[1] "2005-06-09 00:00:00 SPY 1 @ 96.2141193737957"
[1] "2005-06-24 00:00:00 SPY 1 @ 96.7153856513278"
[1] "2005-07-01 00:00:00 SPY 1 @ 96.3684752670201"
[1] "2005-08-08 00:00:00 SPY 1 @ 99.3535221425788"
[1] "2005-08-18 00:00:00 SPY 1 @ 98.4660777801881"
[1] "2005-08-26 00:00:00 SPY 1 @ 98.0062198288965"
[1] "2005-09-14 00:00:00 SPY 1 @ 99.829512233509"
[1] "2005-09-21 00:00:00 SPY 1 @ 98.6745715803002"
[1] "2005-10-05 00:00:00 SPY 1 @ 98.2370613833183"
[1] "2005-10-11 00:00:00 SPY 1 @ 96.406001958985"
[1] "2005-10-24 00:00:00 SPY 1 @ 95.9603937873348"
[1] "2005-10-28 00:00:00 SPY 1 @ 95.9522901412486"
[1] "2005-11-02 00:00:00 SPY 1 @ 97.3620409893546"
[1] "2005-11-30 00:00:00 SPY 1 @ 102.215159233548"
[1] "2005-12-08 00:00:00 SPY 1 @ 102.263768957027"
[1] "2005-12-19 00:00:00 SPY 1 @ 103.221266810963"
[1] "2005-12-28 00:00:00 SPY 1 @ 102.414910243219"
[1] "2006-01-03 00:00:00 SPY 1 @ 101.966939892734"
[1] "2006-01-23 00:00:00 SPY 1 @ 102.797724868596"
[1] "2006-02-01 00:00:00 SPY 1 @ 104.109066609722"
[1] "2006-02-06 00:00:00 SPY 1 @ 102.985061730178"
[1] "2006-02-09 00:00:00 SPY 1 @ 103.376017257767"
[1] "2006-03-01 00:00:00 SPY 1 @ 104.744379523272"
[1] "2006-03-07 00:00:00 SPY 1 @ 104.141647323017"
[1] "2006-03-22 00:00:00 SPY 1 @ 105.905045203611"
[1] "2006-04-10 00:00:00 SPY 1 @ 106.093132767411"
[1] "2006-05-15 00:00:00 SPY 1 @ 105.31627331495"
[1] "2006-05-18 00:00:00 SPY 1 @ 104.138736897255"
[1] "2006-05-24 00:00:00 SPY 1 @ 102.773118639915"
[1] "2006-06-06 00:00:00 SPY 1 @ 104.024254610205"
[1] "2006-06-08 00:00:00 SPY 1 @ 102.691346629112"
[1] "2006-06-13 00:00:00 SPY 1 @ 101.186708266684"
[1] "2006-06-20 00:00:00 SPY 1 @ 101.855723704104"
[1] "2006-07-14 00:00:00 SPY 1 @ 101.9542817024"
[1] "2006-07-24 00:00:00 SPY 1 @ 102.208904580536"
[1] "2006-07-26 00:00:00 SPY -1127 @ 103.974804034594"
[1] "2006-10-03 00:00:00 SPY 1 @ 109.629354814303"
[1] "2006-10-03 00:00:00 SPY 907 @ 109.629354814303"
[1] "2006-11-02 00:00:00 SPY 1 @ 112.61571818925"
[1] "2006-11-28 00:00:00 SPY 1 @ 114.042912722695"
[1] "2006-12-08 00:00:00 SPY 1 @ 116.427056283516"
[1] "2006-12-19 00:00:00 SPY 1 @ 117.424163570766"
[1] "2006-12-22 00:00:00 SPY 1 @ 117.498820616338"
[1] "2007-01-03 00:00:00 SPY 1 @ 118.004852800614"
[1] "2007-01-18 00:00:00 SPY 1 @ 118.768045971558"
[1] "2007-01-26 00:00:00 SPY 1 @ 118.270317678858"
[1] "2007-02-13 00:00:00 SPY 1 @ 119.265786707653"
[1] "2007-02-27 00:00:00 SPY 1 @ 119.357039092981"
[1] "2007-03-06 00:00:00 SPY 1 @ 115.126280166357"
[1] "2007-03-09 00:00:00 SPY 1 @ 117.225065119473"
[1] "2007-03-14 00:00:00 SPY 1 @ 114.835929329737"
[1] "2007-03-19 00:00:00 SPY 1 @ 115.982674771383"
[1] "2007-05-01 00:00:00 SPY 1 @ 123.611582476384"
[1] "2007-05-11 00:00:00 SPY 1 @ 124.719274526864"
[1] "2007-05-16 00:00:00 SPY 1 @ 125.59376943445"
[1] "2007-05-23 00:00:00 SPY 1 @ 127.384391751092"
[1] "2007-06-07 00:00:00 SPY 1 @ 126.22673120436"
[1] "2007-06-13 00:00:00 SPY 1 @ 125.34391196189"
[1] "2007-06-19 00:00:00 SPY 1 @ 127.598848330385"
[1] "2007-06-21 00:00:00 SPY 1 @ 126.36928142802"
[1] "2007-06-26 00:00:00 SPY 1 @ 125.64158324467"
[1] "2007-07-11 00:00:00 SPY 1 @ 126.093254719933"
[1] "2007-07-18 00:00:00 SPY 1 @ 129.004060836367"
[1] "2007-07-23 00:00:00 SPY 1 @ 128.962236352017"
[1] "2007-07-30 00:00:00 SPY 1 @ 122.061610471821"
[1] "2007-08-10 00:00:00 SPY 1 @ 120.773498659489"
[1] "2007-08-29 00:00:00 SPY 1 @ 120.756766523718"
[1] "2007-09-21 00:00:00 SPY 1 @ 128.338641306101"
[1] "2007-10-22 00:00:00 SPY 1 @ 125.103067234912"
[1] "2007-11-09 00:00:00 SPY 1 @ 122.43897617373"
[1] "2007-11-16 00:00:00 SPY 1 @ 122.960025486859"
[1] "2007-11-27 00:00:00 SPY 1 @ 119.119368912215"
[1] "2007-12-05 00:00:00 SPY 1 @ 124.321481499513"
[1] "2007-12-12 00:00:00 SPY 1 @ 126.951961301543"
[1] "2007-12-18 00:00:00 SPY 1 @ 122.783546626733"
[1] "2007-12-31 00:00:00 SPY -945 @ 124.280064849843"
[1] "2009-06-23 00:00:00 SPY 1 @ 78.4042142019373"
[1] "2009-06-23 00:00:00 SPY 1252 @ 78.4042142019373"
[1] "2009-07-06 00:00:00 SPY 1 @ 77.9397662902533"
[1] "2009-08-26 00:00:00 SPY 1 @ 90.1205877365573"
[1] "2009-09-02 00:00:00 SPY 1 @ 87.4390558536496"
[1] "2009-09-24 00:00:00 SPY 1 @ 93.6932113415245"
[1] "2009-10-02 00:00:00 SPY 1 @ 89.8278430661716"
[1] "2009-10-22 00:00:00 SPY 1 @ 95.2604862455034"
[1] "2009-10-27 00:00:00 SPY 1 @ 94.2391122942741"
[1] "2009-11-02 00:00:00 SPY 1 @ 91.6856822589097"
[1] "2009-12-04 00:00:00 SPY 1 @ 98.4742786182327"
[1] "2010-01-04 00:00:00 SPY 1 @ 99.4736144672957"
[1] "2010-01-22 00:00:00 SPY 1 @ 98.4378867582876"
[1] "2010-02-01 00:00:00 SPY 1 @ 95.7379310881149"
[1] "2010-02-05 00:00:00 SPY 1 @ 94.3304073658146"
[1] "2010-02-10 00:00:00 SPY 1 @ 94.7641758730295"
[1] "2010-02-24 00:00:00 SPY 1 @ 97.4995417411739"
[1] "2010-03-29 00:00:00 SPY 1 @ 104.149863026265"
[1] "2010-04-19 00:00:00 SPY 1 @ 105.785402565728"
[1] "2010-04-28 00:00:00 SPY 1 @ 105.820958584692"
[1] "2010-05-03 00:00:00 SPY 1 @ 106.114283074631"
[1] "2010-05-06 00:00:00 SPY 1 @ 103.340987372324"
[1] "2010-05-17 00:00:00 SPY 1 @ 101.509893728511"
[1] "2010-05-19 00:00:00 SPY 1 @ 99.3499195757947"
[1] "2010-06-02 00:00:00 SPY 1 @ 96.0699632697649"
[1] "2010-06-07 00:00:00 SPY 1 @ 95.2877459634846"
[1] "2010-06-22 00:00:00 SPY 1 @ 99.5010824293916"
[1] "2010-06-30 00:00:00 SPY 1 @ 92.8117037592083"
[1] "2010-07-07 00:00:00 SPY 1 @ 92.1061481376476"
[1] "2010-07-08 00:00:00 SPY -1280 @ 95.5624758791401"
[1] "2010-11-16 00:00:00 SPY 1 @ 107.10912927803"
[1] "2010-11-16 00:00:00 SPY 923 @ 107.10912927803"
[1] "2010-12-08 00:00:00 SPY 1 @ 110.42233992386"
[1] "2011-01-20 00:00:00 SPY 1 @ 115.498053371796"
[1] "2011-01-31 00:00:00 SPY 1 @ 115.597347760313"
[1] "2011-02-23 00:00:00 SPY 1 @ 118.918948504635"
[1] "2011-03-02 00:00:00 SPY 1 @ 118.016337889799"
[1] "2011-03-08 00:00:00 SPY 1 @ 118.819660434392"
[1] "2011-03-11 00:00:00 SPY 1 @ 116.906130443993"
[1] "2011-03-18 00:00:00 SPY 1 @ 116.797541917344"
[1] "2011-03-29 00:00:00 SPY 1 @ 118.637800382539"
[1] "2011-04-04 00:00:00 SPY 1 @ 120.958519747613"
[1] "2011-04-11 00:00:00 SPY 1 @ 120.568717457945"
[1] "2011-05-06 00:00:00 SPY 1 @ 122.327390788816"
[1] "2011-05-17 00:00:00 SPY 1 @ 120.287694440843"
[1] "2011-05-24 00:00:00 SPY 1 @ 120.061061513291"
[1] "2011-06-02 00:00:00 SPY 1 @ 119.625930825048"
[1] "2011-06-07 00:00:00 SPY 1 @ 117.577160094657"
[1] "2011-06-14 00:00:00 SPY 1 @ 116.824736962119"
[1] "2011-06-16 00:00:00 SPY 1 @ 115.183917286234"
[1] "2011-07-12 00:00:00 SPY 1 @ 119.973017034815"
[1] "2011-07-28 00:00:00 SPY 1 @ 118.980002328384"
[1] "2011-08-03 00:00:00 SPY 1 @ 114.479532018588"
[1] "2011-08-05 00:00:00 SPY 1 @ 110.926528758843"
[1] "2011-08-18 00:00:00 SPY -946 @ 106.134530125954"
[1] "2012-04-10 00:00:00 SPY 1 @ 127.684538407341"
[1] "2012-04-10 00:00:00 SPY 782 @ 127.684538407341"
[1] "2012-04-17 00:00:00 SPY 1 @ 127.582723059644"
[1] "2012-04-20 00:00:00 SPY 1 @ 128.036265584381"
[1] "2012-05-07 00:00:00 SPY 1 @ 126.351693212168"
[1] "2012-05-14 00:00:00 SPY 1 @ 124.315407546699"
[1] "2012-05-14 00:00:00 SPY 13 @ 124.315407546699"
[1] "2012-06-01 00:00:00 SPY 1 @ 119.780043387983"
[1] "2012-06-01 00:00:00 SPY 20 @ 119.780043387983"
[1] "2012-06-12 00:00:00 SPY 1 @ 121.982927066767"
[1] "2012-06-22 00:00:00 SPY 1 @ 123.861694859222"
[1] "2012-07-11 00:00:00 SPY 1 @ 124.866508749008"
[1] "2012-07-24 00:00:00 SPY 1 @ 125.778277975289"
[1] "2012-08-01 00:00:00 SPY 1 @ 129.043912417707"
[1] "2012-09-26 00:00:00 SPY 1 @ 134.755594949074"
[1] "2012-10-10 00:00:00 SPY 1 @ 134.858470135761"
[1] "2012-10-22 00:00:00 SPY 1 @ 133.895062616513"
[1] "2012-11-06 00:00:00 SPY 1 @ 133.081314520924"
[1] "2012-11-09 00:00:00 SPY 1 @ 128.722589033494"
[1] "2012-11-14 00:00:00 SPY 1 @ 129.274455586031"
[1] "2012-12-04 00:00:00 SPY 1 @ 132.295624995064"
[1] "2012-12-13 00:00:00 SPY 1 @ 134.147610321731"
[1] "2013-02-01 00:00:00 SPY 1 @ 141.909563425788"
[1] "2013-02-06 00:00:00 SPY 1 @ 141.787115202194"
[1] "2013-02-22 00:00:00 SPY 1 @ 142.38055436199"
[1] "2013-02-26 00:00:00 SPY 1 @ 141.033526878325"
[1] "2013-04-04 00:00:00 SPY 1 @ 147.06343231595"
[1] "2013-04-16 00:00:00 SPY 1 @ 147.877139820857"
[1] "2013-04-19 00:00:00 SPY 1 @ 146.18349942803"
[1] "2013-05-22 00:00:00 SPY 1 @ 158.332337925907"
[1] "2013-05-30 00:00:00 SPY 1 @ 156.449466068128"
[1] "2013-06-03 00:00:00 SPY 1 @ 155.011281577095"
[1] "2013-06-06 00:00:00 SPY 1 @ 152.52284575565"
[1] "2013-06-12 00:00:00 SPY 1 @ 155.380287522684"
[1] "2013-06-18 00:00:00 SPY 1 @ 155.673598800714"
[1] "2013-06-20 00:00:00 SPY 1 @ 153.147322741777"
[1] "2013-07-01 00:00:00 SPY 1 @ 153.386964644818"
[1] "2013-07-25 00:00:00 SPY 1 @ 160.007169452897"
[1] "2013-08-01 00:00:00 SPY 1 @ 161.690758373814"
[1] "2013-08-16 00:00:00 SPY 1 @ 157.952622050774"
[1] "2013-08-28 00:00:00 SPY 1 @ 155.289320708327"
[1] "2013-09-23 00:00:00 SPY 1 @ 162.956795401376"
[1] "2013-09-26 00:00:00 SPY 1 @ 161.838494509156"
[1] "2013-10-09 00:00:00 SPY 1 @ 158.474024130731"
[1] "2013-11-01 00:00:00 SPY 1 @ 168.242447868879"
[1] "2013-11-08 00:00:00 SPY 1 @ 167.143252749946"
[1] "2013-11-21 00:00:00 SPY 1 @ 171.062097370113"
[1] "2013-12-12 00:00:00 SPY 1 @ 170.746676718937"
[1] "2014-01-06 00:00:00 SPY 1 @ 176.334543928472"
[1] "2014-01-14 00:00:00 SPY 1 @ 175.18132815125"
[1] "2014-01-27 00:00:00 SPY 1 @ 172.077291529657"
[1] "2014-02-04 00:00:00 SPY 1 @ 168.12756602891"
[1] "2014-02-20 00:00:00 SPY 1 @ 176.123122189186"
[1] "2014-02-25 00:00:00 SPY 1 @ 177.843312755559"
[1] "2014-03-14 00:00:00 SPY 1 @ 177.64150970068"
[1] "2014-03-24 00:00:00 SPY 1 @ 180.346364511244"
[1] "2014-03-27 00:00:00 SPY 1 @ 178.329006405312"
[1] "2014-04-07 00:00:00 SPY 1 @ 179.487297461871"
[1] "2014-04-11 00:00:00 SPY 1 @ 175.809716093826"
[1] "2014-05-15 00:00:00 SPY 1 @ 182.122412342361"
[1] "2014-06-25 00:00:00 SPY 1 @ 188.436075649539"
[1] "2014-07-18 00:00:00 SPY 1 @ 190.43402088343"
[1] "2014-07-31 00:00:00 SPY 1 @ 189.716312081201"
[1] "2014-08-07 00:00:00 SPY 1 @ 187.126759599473"
[1] "2014-08-13 00:00:00 SPY 1 @ 188.436075649539"
[1] "2014-09-05 00:00:00 SPY 1 @ 194.138917313647"
[1] "2014-09-10 00:00:00 SPY 1 @ 193.421208511418"
[1] "2014-09-23 00:00:00 SPY 1 @ 193.350934585068"
[1] "2014-09-26 00:00:00 SPY 1 @ 191.665219949033"
[1] "2014-10-02 00:00:00 SPY 1 @ 189.209718534193"
[1] "2014-10-08 00:00:00 SPY 1 @ 188.420453423893"
[1] "2014-10-13 00:00:00 SPY 1 @ 185.58495012661"
[1] "2014-10-24 00:00:00 SPY 1 @ 190.252337396064"
[1] "2014-12-02 00:00:00 SPY 1 @ 200.542039328959"
[1] "2014-12-09 00:00:00 SPY 1 @ 199.138894967333"
[1] "2014-12-12 00:00:00 SPY 1 @ 197.453180331298"
[1] "2014-12-22 00:00:00 SPY 1 @ 202.56987175323"
[1] "2015-01-02 00:00:00 SPY 1 @ 202.207357413693"
[1] "2015-01-13 00:00:00 SPY 1 @ 199.993040916179"
[1] "2015-01-29 00:00:00 SPY 1 @ 196.328667060516"
[1] "2015-02-10 00:00:00 SPY 1 @ 201.717466550928"
[1] "2015-03-09 00:00:00 SPY 1 @ 203.539860560413"
[1] "2015-03-12 00:00:00 SPY 1 @ 201.109992083283"
[1] "2015-03-25 00:00:00 SPY 1 @ 205.75734015615"
[1] "2015-04-28 00:00:00 SPY 1 @ 207.400877416595"
[1] "2015-05-06 00:00:00 SPY 1 @ 206.239567359885"
[1] "2015-05-27 00:00:00 SPY 1 @ 207.902791661487"
[1] "2015-06-05 00:00:00 SPY 1 @ 206.623386914182"
[1] "2015-06-25 00:00:00 SPY 1 @ 208.765742549324"
[1] "2015-07-10 00:00:00 SPY 1 @ 204.997859221705"
[1] "2015-07-27 00:00:00 SPY 1 @ 204.651738288859"
[1] "2015-08-06 00:00:00 SPY 1 @ 207.964686364514"
[1] "2015-08-21 00:00:00 SPY 1 @ 199.499342550526"
[1] "2015-09-02 00:00:00 SPY 1 @ 192.467961233126"
[1] "2015-09-04 00:00:00 SPY -906 @ 190.717544097235"
[1] "2015-12-10 00:00:00 SPY 1 @ 204.204684925897"
[1] "2015-12-10 00:00:00 SPY 487 @ 204.204684925897"
[1] "2015-12-21 00:00:00 SPY 1 @ 201.410004"
[1] "2015-12-21 00:00:00 SPY 5 @ 201.410004"
# Update your portfolio (portfolio.st)
updatePortf(portfolio.st)
[1] "firststrat"
daterange <- time(getPortfolio(portfolio.st)$summary)[-1]

# Update your account (account.st)
updateAcct(account.st, daterange)
[1] "firststrat"
updateEndEq(account.st)
[1] "firststrat"

You are on your way to seeing the results of your strategy. The date of the last trade was 2015-12-23

6.1.2 Profit factor

One of the most vital statistics of any systematic trading strategy is the profit factor. The profit factor is how many dollars you make for each dollar you lose. A profit factor above 1 means your strategy is profitable. A profit factor below 1 means you should head back to the drawing board.

In this exercise, you will explore the profit factor in your strategy by creating an object called tstats that displays the trade statistics for your system. In general, trade statistics are generated by using the tradeStats() command.

# Get the tradeStats for your portfolio
tstats <- tradeStats(Portfolios = portfolio.st)

# Print the profit factor
tstats$Profit.Factor
[1] 92.30839

Trade statistics such as the profit factor are a valuable component of assessing the effectiveness of your strategy.

6.1.3 Percent positive

While profit factor is one important statistic, it may be heavily influenced by only a few good trades. The percent positive statistic lets you know how many of your trades were winners. A trading system based on oscillation trading (such as yours!) will likely have a high percentage of winners. This is certainly a statistic you should look for in your own trade statistics.

tstats$Percent.Positive This percent positive statistic means that approximately 71% of your trades returned a positive result. That’s a great start!

6.2 Using chart.Posn()

6.2.1 Using chart.Posn()

One of the most enlightening things about a trading system is exploring what positions it took over the course of the trading simulation, as well as when it had its profits and drawdowns. Looking at a picture of the performance can deliver a great deal of insight in terms of refining similar trading systems in the future.

In this exercise, you will use the chart.Posn() function. This generates a crisp and informative visualization of the performance of your trading system over the course of the simulation.

# Use chart.Posn to view your system's performance on SPY
chart.Posn(Portfolio = portfolio.st, Symbol = "SPY")

6.2.2 Adding an indicator to a chart.Posn() chart

One of the more interesting things you can do with the chart.Posn() function is to superimpose indicators on top of it. This can help show what the strategy has actually been doing and why. However, in order to do this, you will need to recalculate the indicators outside the scope of your strategy. Once this is done, you simply add them to the chart.Posn plot.

In this exercise, you will add the three indicators from your strategy to the chart.Posn plot you just created. The two moving averages (SMA50 and SMA200) will be superimposed on the price series, while the DVO_2_126 will have its own window.

# Compute the SMA50
sma50 <- SMA(x = Cl(SPY), n = 50)

# Compute the SMA200
sma200 <- SMA(x = Cl(SPY), n = 200)

# Compute the DVO_2_126 with an navg of 2 and a percentlookback of 126
dvo <- DVO(HLC = HLC(SPY), navg = 2, percentlookback = 126)

# Recreate the chart.Posn of the strategy from the previous exercise
chart.Posn(Portfolio = portfolio.st, Symbol = "SPY")


# Overlay the SMA50 on your plot as a blue line
add_TA(sma50, on = 1, col = "blue")


# Overlay the SMA200 on your plot as a red line
add_TA(sma200, on = 1, col = "red")


# Add the DVO_2_126 to the plot in a new window
add_TA(dvo, on = 2, col = "red")

The plot may look a bit complicated, but only because it contains so much vital information about your portfolio performance.

6.3 Additional analytics

6.3.1 Cash Sharpe ratio

When working with cash profit and loss statistics, quantstrat offers a way to compute a Sharpe ratio not just from returns, but from the actual profit and loss statistics themselves. A Sharpe ratio is a metric that compares the average reward to the average risk taken. Generally, a Sharpe ratio above 1 is a marker of a strong strategy.

In this exercise, you will see that because of trading P&L (profit and loss), one can compute a Sharpe ratio based on these metrics. The code below can be used to compute the Sharpe ratio based off of P&L.

portpl <- .blotter$portfolio.firststrat$summary$Net.Trading.PL
SharpeRatio.annualized(portpl, geometric=FALSE)
                                Net.Trading.PL
Annualized Sharpe Ratio (Rf=0%)      0.5629363

Remember that a Sharpe ratio above 1 is indicative of a strong strategy. The Sharpe ratio identified here is a bit low.

6.3.2 Returns Sharpe ratio in quantstrat

One of the main reasons to include an initial equity (in this case, initeq, which is set to 100,000) in your strategy is to be able to work with returns, which are based off of your profit and loss over your initial equity.

While you just computed a cash Sharpe ratio in the previous exercise, you will see in this exercise that quantstrat can also compute the standard returns-based Sharpe ratio as well.

# Get instrument returns
instrets <- PortfReturns(portfolio.st)

# Compute Sharpe ratio from returns
SharpeRatio.annualized(instrets, geometric = FALSE)
                                SPY.DailyEqPL
Annualized Sharpe Ratio (Rf=0%)     0.5630224
LS0tDQp0aXRsZTogIkZpbmFuY2lhbCBUcmFkaW5nIGluIFIiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2NvbGxhcHNlZDogZmFsc2UNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICANCnRvY19kZXB0aDogMw0KLS0tDQojIFRyYWRpbmcgYmFzaWNzDQoNCmh0dHBzOi8vcXVhbnRzdHJhdHRyYWRlci53b3JkcHJlc3MuY29tLw0KDQojIyBXaHkgZG8gcGVvcGxlIHRyYWRlPw0KDQojIyMgSWRlbnRpZnlpbmcgdHlwZXMgb2YgdHJhZGluZyBwaGlsb3NvcGhpZXMNCg0KSGVsbG8gYW5kIHdlbGNvbWUgdG8gRmluYW5jaWFsIFRyYWRpbmcgaW4gUiEgVGhpcyBjb3Vyc2Ugd2lsbCB0ZWFjaCB5b3UgaG93IHRvIGNvbnN0cnVjdCBhIGJhc2ljIHRyYWRpbmcgc3RyYXRlZ3kgaW4gcXVhbnRzdHJhdCwgUidzIGluZHVzdHJpYWwtc3RyZW5ndGggYmFja3Rlc3RpbmcgcGxhdGZvcm0gZGV2ZWxvcGVkIGJ5IEJyaWFuIFBldGVyc29uLCBEaXJlY3RvciBvZiBBbGdvcml0aG1pYyBUcmFkaW5nIGF0IERWIFRyYWRpbmcuIE92ZXIgdGhlIG5leHQgZmV3IGNoYXB0ZXJzLCB5b3UnbGwgYnVpbGQgYSB0cmFkaW5nIHN0cmF0ZWd5IGluIHF1YW50c3RyYXQgZnJvbSBzdGFydCB0byBmaW5pc2gsIGluY2x1ZGluZyB0aGUgY29kZSB0byBzZXQgdXAgYSBuZXcgc3RyYXRlZ3ksIGFzIHdlbGwgYXMgdGhlIGRlc2lnbiBvZiBpbmRpY2F0b3JzLCBzaWduYWxzLCBhbmQgcnVsZXMgZm9yIHlvdXIgc3RyYXRlZ3kuIEJ5IHRoZSBlbmQgb2YgdGhlIGNvdXJzZSwgeW91J2xsIGJlIHJlYWR5IHRvIGRlc2lnbiBhbmQgaW1wbGVtZW50IHlvdXIgb3duIHRyYWRpbmcgc3RyYXRlZ2llcyBkaXJlY3RseSBpbiBSIQ0KDQpxdWFudHN0cmF0IGlzIGN1cnJlbnRseSBvbmx5IGF2YWlsYWJsZSBvbiBHaXRIdWIuIElmIHlvdSB3YW50IHRvIGluc3RhbGwgaXQgb24geW91ciBvd24gbWFjaGluZSwgeW91IGZpcnN0IG5lZWQgdG8gcmVtb3RlcyBwYWNrYWdlLg0KDQogICAgaW5zdGFsbC5wYWNrYWdlcygicmVtb3RlcyIpDQogICAgDQpUaGVuIHlvdSBjYW4gaW5zdGFsbCBxdWFudHN0cmF0IHVzaW5nDQoNCiAgICByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigiYnJhdmVyb2NrL3F1YW50c3RyYXQiKQ0KICAgIA0KIkludHJvZHVjdGlvbiB0byBRdWFudGl0YXRpdmUgVHJhZGluZyBXaXRoIFIuIg0KDQpcKlwqQWJvdmUgZG9lc250IHNlZW0gdG8gd29yaywgeW91IGNhbiBkbyB0aGUgYmVsb3cqKg0KDQoxLiBkb3dubG9hZCBwYWNrYWdlIGZyb20gZ2l0aHViIChibG90dGVyIGFuZCBxdWFudHN0cmF0KQ0KMi4gT3BlbiBjb21tYW5kIGxpbmUNCjMuIGJ1aWxkIHBhY2thZ2VzIHVzaW5nIFIgQ01EIEJVSUxEDQo0LiBpbnN0YWxsIHBhY2thZ2VzIHVzaW5nIFIgQ01EIElOU1RBTEwNCg0KQmVmb3JlIGdldHRpbmcgaW50byB0aGUgbWVhdCBhbmQgcG90YXRvZXMgb2YgdGhlIGNvdXJzZSwgbGV0J3MgcmV2aWV3IHNvbWUgcGhyYXNlcyBhbmQgbWVjaGFuaWNzIHlvdSBtYXkgaGF2ZSBoZWFyZCBpbiB0aGUgd29ybGQgb2YgZmluYW5jaWFsIHRyYWRpbmcsIG9yIGV2ZW4gaW4gcG9wIGN1bHR1cmUuIEFzIHlvdSBsZWFybmVkIGluIHRoZSB2aWRlbywgdGhlIG1lY2hhbmljcyBvZiB0cmFkaW5nIHVzdWFsbHkgY29tZSBpbiBvbmUgb2YgdHdvIGZvcm1zOg0KDQotCVRyZW5kIHRyYWRpbmcgKGFsc28gZGl2ZXJnZW5jZSBvciBtb21lbnR1bSksIHdoaWNoIGlzIGEgYmV0IHRoYXQgYSBxdWFudGl0eSwgc3VjaCBhcyBhIHByaWNlLCB3aWxsIGtlZXAgbW92aW5nIGluIGl0cyBjdXJyZW50IGRpcmVjdGlvbi4NCi0JUmV2ZXJzaW9uIHRyYWRpbmcgKGFsc28gY29udmVyZ2VuY2UsIGN5Y2xlLCBvciBvc2NpbGxhdGlvbiksIHdoaWNoIGlzIGEgYmV0IHRoYXQgYSBxdWFudGl0eSwgc3VjaCBhcyBhIHByaWNlLCB3aWxsIHJldmVyc2UuDQoiQnV5aW5nIHRoZSBkaXAiIGNhbiByZWZlciB0byBib3RoIHRyZW5kIHRyYWRpbmcgYW5kIHJldmVyc2lvbiB0cmFkaW5nLg0KDQpgYGB7cn0NCmxpYnJhcnkoYmxvdHRlcikNCmxpYnJhcnkoZm9yZWFjaCkNCmxpYnJhcnkocXVhbnRzdHJhdCkNCmBgYA0KDQoNCiMjIFBpdGZhbGxzIG9mIHZhcmlvdXMgdHJhZGluZyBzeXN0ZW1zDQoNCiMjIyBIb3cgdG8gcHJldmVudCBvdmVyZml0dGluZw0KDQpXaGVuIGRldmVsb3BpbmcgYSB0cmFkaW5nIHN5c3RlbSwgYSBtYWpvciBwaXRmYWxsIHRoYXQgY2FuIGNyZWVwIGludG8gc3lzdGVtIGRldmVsb3BtZW50IGlzIHRoZSBkZXNpcmUgdG8gZmluZCBhIHN0cmF0ZWd5IHRoYXQgd29ya2VkIHBoZW5vbWVuYWxseSBpbiB0aGUgcGFzdC4gVGhpcyBpcyBrbm93biBhcyBvdmVyZml0dGluZy4gUmVzZWFyY2ggYnkgbGVhZGluZyBhdXRob3JzIGluIHRoZSBxdWFudGl0YXRpdmUgZmllbGQgaGFzIHNob3duIHRoYXQgbm90IG9ubHkgaXMgYW4gb3ZlcmZpdHRlZCBzeXN0ZW0gdW5saWtlbHkgdG8gZ2VuZXJhdGUgcHJvZml0cyBpbiB0aGUgZnV0dXJlLCBidXQgYWxzbyB0aGF0IGl0cyBwZXJmb3JtYW5jZSBjYW4gbGVhZCB0byBsb3NzZXMuDQoNCk92ZXJmaXR0aW5nIGNhbiBiZSByZWR1Y2VkIGJ5Og0KDQotCUV4YW1pbmluZyB0aGUgcm9idXN0bmVzcyBvZiBzeXN0ZW0gcGVyZm9ybWFuY2UuDQotCVJlZHVjaW5nIHRoZSBudW1iZXIgb2YgcGFyYW1ldGVycyBpbiB0aGUgdHJhZGluZyBzeXN0ZW0uDQotCUNvbmR1Y3RpbmcgdGVzdHMgdG8gZGV0ZXJtaW5lIHN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBvZiBhIHN0cmF0ZWd5Lg0KDQojIyBHZXR0aW5nIGZpbmFuY2lhbCBkYXRhDQoNCiMjIyBQbG90dGluZyBmaW5hbmNpYWwgZGF0YQ0KDQpUcmFkaW5nIHN0cmF0ZWdpZXMgZGV2ZWxvcGVkIHVzaW5nIHF1YW50c3RyYXQgY29udGFpbiBzZXZlcmFsIGNoYXJhY3RlcmlzdGljcywgaW5jbHVkaW5nIGluZGljYXRvcnMgZGV2ZWxvcGVkIGZyb20gbWFya2V0IGRhdGEsIHNpZ25hbHMgdHJpZ2dlcmVkIGJ5IGNlcnRhaW4gY29tYmluYXRpb25zIG9mIGluZGljYXRvcnMsIGFuZCBydWxlcyBhY3RlZCBvbiBieSBjZXJ0YWluIHNpZ25hbHMuIFRoZSBmaXJzdCBzdGVwIGluIGRldmVsb3BpbmcgYW55IHRyYWRpbmcgc3lzdGVtIGlzIHRvIG9idGFpbiBtYXJrZXQgZGF0YSwgYW5kIG1heWJlIGV2ZW4gZXhhbWluZSBob3cgaXQgbG9va3MuDQoNClRoZSBxdWFudG1vZCBwYWNrYWdlIGhhcyBhIGZ1bmN0aW9uIHRvIG9idGFpbiBkYXRhIGZyb20gdmFyaW91cyBzb3VyY2VzLiBUaGlzIGlzIHRoZSBnZXRTeW1ib2xzKCkgY29tbWFuZCwgd2hpY2ggcmV0dXJucyBhbiBvYmplY3Qgd2l0aCB0aGUgc2FtZSBuYW1lIGFzIHRoZSBzeW1ib2wuDQoNCllvdSB3aWxsIG9idGFpbiBkYXRhIGZvciBTUFksIGFuIGV4Y2hhbmdlIHRyYWRlZCBmdW5kIChFVEYpIHRoYXQgdHJhY2tzIHRoZSB0b3AgNTAwIGNvbXBhbmllcyBpbiB0aGUgVW5pdGVkIFN0YXRlcyBieSBtYXJrZXQgY2FwLiBUaGlzIGRhdGEgaXMgZnJvbSBZYWhvbyEgRmluYW5jZSwgd2hpY2ggaXMgYSBzdWZmaWNpZW50IHNvdXJjZSBvZiBkYXRhIGZvciBzdHJhdGVnaWVzIHRoYXQgZG8gbm90IHJlcXVpcmUgaW5zdGFudGFuZW91cyAic2VlIHRoZSBjbG9zZSwgYnV5IHRoZSBjbG9zZSIgZXhlY3V0aW9uLiBZb3Ugd2lsbCB0aGVuIHBsb3QgaXQgYW5kIGFkZCBhIHRyZW5kbGluZSB0byBpdC4NCg0KRm9yIGV4YW1wbGUsIHRvIG9idGFpbiBhZGp1c3RlZCBkYXRhIGZvciBTUFkgaW4gMjAxMyBmcm9tIFlhaG9vISBGaW5hbmNlIGFuZCB0aGVuIHBsb3QgdGhlIG1heGltdW0gdmFsdWVzIHRyYWRlZCBlYWNoIGRheSwgeW91IHdvdWxkIHJ1biB0aGUgZm9sbG93aW5nIGNvZGUuIE5vdGljZSBob3cgb25seSB0aGUgZmlyc3QgcmVmZXJlbmNlIHRvIHRoZSBTUFkgZGF0YSBpcyBlbmNsb3NlZCBpbiBxdW90YXRpb24gbWFya3MuDQoNCiAgICBnZXRTeW1ib2xzKCJTUFkiLCANCiAgICAgICAgICAgICAgIGZyb20gPSAiMjAxMy0wMS0wMSIsDQogICAgICAgICAgICAgICB0byA9ICIyMDEzLTEyLTMxIiwNCiAgICAgICAgICAgICAgIHNyYyA9ICJ5YWhvbyIsDQogICAgICAgICAgICAgICBhZGp1c3QgPSBUUlVFKQ0KICAgIHBsb3QoSGkoU1BZKSkNCg0KYGBge3J9DQojIEdldCBTUFkgZnJvbSB5YWhvbw0KZ2V0U3ltYm9scygiU1BZIiwgDQogICAgICAgICAgIGZyb20gPSAiMjAwMC0wMS0wMSIsIA0KICAgICAgICAgICB0byA9ICIyMDE2LTA2LTMwIiwgDQogICAgICAgICAgIHNyYyA9ICAieWFob28iLCANCiAgICAgICAgICAgYWRqdXN0ID0gIFRSVUUpDQoNCiMgUGxvdCB0aGUgY2xvc2luZyBwcmljZSBvZiBTUFkNCnBsb3QoQ2woU1BZKSkNCmBgYA0KIyMgQWRkaW5nIGluZGljYXRvcnMgdG8gZmluYW5jaWFsIGRhdGENCg0KIyMjIEFkZGluZyBhIG1vdmluZyBhdmVyYWdlIHRvIGZpbmFuY2lhbCBkYXRhDQoNCk9uZSBvZiB0aGUgbW9zdCBwb3B1bGFyIGluZGljYXRvcnMgdG8gYWRkIHRvIGEgdHJhZGluZyBzdHJhdGVneSBpcyB0aGUgMjAwLWRheSBzaW1wbGUgbW92aW5nIGF2ZXJhZ2UgKFNNQSkuIFRoaXMgaXMgYSB0ZWNobmljYWwgaW5kaWNhdG9yIG9mIHRoZSBhdmVyYWdlIGNsb3NpbmcgcHJpY2Ugb2YgYSBzdG9jayBvdmVyIHRoZSBwYXN0IDIwMCBkYXlzLiBPdGhlciBtb3ZpbmcgYXZlcmFnZXMgY2FuIGJlIG9mIHZhcnlpbmcgbGVuZ3RoLCBzdWNoIGFzIDUwLWRheSwgMTAwLWRheSwgZXRjLg0KDQpXaGVuZXZlciB0aGUgcHJpY2UgaXMgYWJvdmUgdGhlIDIwMC1kYXkgbW92aW5nIGF2ZXJhZ2UsIGEgd2hvbGUgYXNzb3J0bWVudCBvZiBnb29kIHRoaW5ncyB1c3VhbGx5IGhhcHBlbiwgc3VjaCBhcyB0aGUgYXNzZXQgYXBwcmVjaWF0aW5nIGluIHByaWNlLCBsb3cgdm9sYXRpbGl0eSwgYW5kIHNvIG9uLiBHZXR0aW5nIGEgbG9uZy1sYXN0aW5nIHZpc3VhbCBtaWdodCBzaGVkIGxpZ2h0IG9uIHdoeSB0aGlzIGluZGljYXRvciBpcyBtZW50aW9uZWQgc28gb2Z0ZW4uDQoNClRoZSBUVFIgcGFja2FnZSBoYXMgYSBmdW5jdGlvbiB0aGF0IGNhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2VzLCBTTUEoKSwgd2hpY2ggdGFrZXMgaW4gYSBwcmljZSBzZXJpZXMgeCBhbmQgY29tcHV0ZXMgdGhlIGFyaXRobWV0aWMgbWVhbiBvdmVyIG4gZGF5cy4gQSBjYWxsIG9mIFNNQSgpIHdpdGggYSBsb29rYmFjayB3aW5kb3cgb2YgNTAgZGF5cyBjb3VsZCBsb29rIGxpa2UgdGhlIGZvbGxvd2luZzoNCg0KICAgIFNNQShDbChHRFgpLCBuID0gNTApDQoNCmBgYHtyfQ0KIyBQbG90IHRoZSBjbG9zaW5nIHByaWNlcyBvZiBTUFkNCnBsb3QoQ2woU1BZKSkNCg0KIyBBZGQgYSAyMDAtZGF5IFNNQSB1c2luZyBsaW5lcygpDQpsaW5lcyhTTUEoQ2woU1BZKSwgbiA9IDIwMCksIGNvbCA9ICJyZWQiKQ0KYGBgDQpBcyB5b3UgY2FuIHNlZSBmcm9tIHlvdXIgcGxvdCwgaW5kaWNhdG9ycyBzdWNoIGFzIHRoZSAyMDAtZGF5IFNNQSBoZWxwIHlvdSBpZGVudGlmeSB0cmVuZHMgaW4geW91ciBkYXRhLg0KDQojIEEgYm9pbGVycGxhdGUgZm9yIHF1YW50c3RyYXQgc3RyYXRlZ2llcw0KDQojIyBTZXR0aW5nIHVwIGEgc3RyYXRlZ3kgSQ0KDQojIyMgVW5kZXJzdGFuZGluZyBpbml0aWFsaXphdGlvbiBzZXR0aW5ncyDigJMgRGVmaW5lIGJvaWxlcnBsYXRlIGNvZGUNCg0KTGV0J3MgZ2V0IHN0YXJ0ZWQgd2l0aCBjcmVhdGluZyBvdXIgZmlyc3Qgc3RyYXRlZ3kgaW4gcXVhbnRzdHJhdC4gSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgbmVlZCB0byBmaWxsIGluIHRocmVlIGRhdGVzOg0KDQotCUFuIGluaXRpYWxpemF0aW9uIGRhdGUgZm9yIHlvdXIgYmFja3Rlc3QuDQotCVRoZSBzdGFydCBvZiB5b3VyIGRhdGEuDQotCVRoZSBlbmQgb2YgeW91ciBkYXRhLg0KVGhlIGluaXRpYWxpemF0aW9uIGRhdGUgbXVzdCBhbHdheXMgY29tZSBiZWZvcmUgdGhlIHN0YXJ0IG9mIHRoZSBkYXRhLCBvdGhlcndpc2UgdGhlcmUgd2lsbCBiZSBzZXJpb3VzIGVycm9ycyBpbiB0aGUgb3V0cHV0IG9mIHlvdXIgYmFja3Rlc3QuDQoNCllvdSBzaG91bGQgYWxzbyBzcGVjaWZ5IHdoYXQgdGltZSB6b25lIGFuZCBjdXJyZW5jeSB5b3Ugd2lsbCBiZSB3b3JraW5nIHdpdGggd2l0aCB0aGUgZnVuY3Rpb25zIFN5cy5zZXRlbnYoKSBhbmQgY3VycmVuY3koKSwgcmVzcGVjdGl2ZWx5LiBBbiBleGFtcGxlIGlzIGhlcmU6DQoNCiAgICBTeXMuc2V0ZW52KFRaID0gIkV1cm9wZS9Mb25kb24iKQ0KICAgIGN1cnJlbmN5KCJFVVIiKQ0KICAgIA0KWW91J2xsIHVzZSBVVEMgKENvb3JkaW5hdGVkIFVuaXZlcnNhbCBUaW1lKSBhbmQgVVNEIChVbml0ZWQgU3RhdGVzIERvbGxhcnMpIGZvciB5b3VyIHBvcnRmb2xpbyBzZXR0aW5ncy4NCmBgYHtyfQ0KIyBMb2FkIHRoZSBxdWFudHN0cmF0IHBhY2thZ2UNCmxpYnJhcnkocXVhbnRzdHJhdCkNCg0KIyBDcmVhdGUgaW5pdGRhdGUsIGZyb20sIGFuZCB0byBzdHJpbmdzDQppbml0ZGF0ZSA8LSAiMTk5OS0wMS0wMSINCmZyb20gPC0gIjIwMDMtMDEtMDEiDQp0byA8LSAiMjAxNS0xMi0zMSINCg0KIyBTZXQgdGhlIHRpbWV6b25lIHRvIFVUQw0KU3lzLnNldGVudihUWiA9ICJVVEMiKQ0KDQojIFNldCB0aGUgY3VycmVuY3kgdG8gVVNEIA0KY3VycmVuY3koIlVTRCIpDQpgYGANCiMjIyBVbmRlcnN0YW5kaW5nIGluaXRpYWxpemF0aW9uIHNldHRpbmdzIOKAkyBzdG9jaygpDQoNCkxpa2UgaW4gdGhlIHByZXZpb3VzIGNoYXB0ZXIsIHlvdSB3aWxsIHVzZSBnZXRTeW1ib2xzKCkgdG8gb2J0YWluIHRoZSBTUFkgZGF0YSBmcm9tIFlhaG9vISBGaW5hbmNlLg0KDQpBZnRlciBpbXBvcnRpbmcgdGhlIGRhdGEsIHVzZSBzdG9jaygpIHRvIHRlbGwgcXVhbnRzdHJhdCB3aGF0IGluc3RydW1lbnRzIHdpbGwgYmUgcHJlc2VudCBmb3IgdGhlIHNpbXVsYXRpb24sIGFuZCB0byB0cmVhdCB0aGVtIGp1c3QgYXMgdGhleSBhcmUsIGFzIG9wcG9zZWQgdG8gY3JlYXRpbmcgYSBtaW5pbXVtIGJ1eSBzaXplLCBhcyB3aXRoIGZ1dHVyZXMuIEZ1cnRoZXJtb3JlLCB0aGlzIGNvbW1hbmQgc3BlY2lmaWVzIHdoaWNoIGN1cnJlbmN5IHRvIHVzZSB3aXRoIHRoZSBnaXZlbiBpbnN0cnVtZW50cy4gTm90ZSB0aGF0IHdoZW5ldmVyIHlvdSB1c2UgYSBmdW5jdGlvbiB0byBpbml0aWFsaXplIGEgZGF0YSBzZXQgc3VjaCBhcyBHRFggb3IgU1BZLCB5b3UgbXVzdCBlbmNsb3NlIGl0IGluIHF1b3RhdGlvbiBtYXJrczoNCg0KICAgIHN0b2NrKCJHRFgiLCBjdXJyZW5jeSA9ICJVU0QiKQ0KDQpgYGB7cn0NCiMgTG9hZCB0aGUgcXVhbnRtb2QgcGFja2FnZQ0KbGlicmFyeShxdWFudG1vZCkNCg0KIyBSZXRyaWV2ZSBTUFkgZnJvbSB5YWhvbw0KZ2V0U3ltYm9scygiU1BZIiwgZnJvbSA9IGZyb20sIHRvID0gdG8sIHNyYyA9ICJ5YWhvbyIsIGFkanVzdCA9IFRSVUUpDQoNCiMgVXNlIHN0b2NrKCkgdG8gaW5pdGlhbGl6ZSBTUFkgYW5kIHNldCBjdXJyZW5jeSB0byBVU0QNCnN0b2NrKCJTUFkiLCBjdXJyZW5jeSA9ICJVU0QiKQ0KYGBgDQojIyMgVW5kZXJzdGFuZGluZyBpbml0aWFsaXphdGlvbiBzZXR0aW5ncyAtIGFjY291bnQsIHBvcmZvbGlvIGFuZCBzdHJhdGVneQ0KDQpMZXQncyBjb250aW51ZSB0aGUgc2V0dXAgb2YgeW91ciBzdHJhdGVneS4gRmlyc3QsIHlvdSB3aWxsIHNldCBhIHRyYWRlIHNpemUgb2YgMTAwLDAwMCBVU0QgaW4gYW4gb2JqZWN0IGNhbGxlZCB0cmFkZXNpemUgd2hpY2ggZGV0ZXJtaW5lcyB0aGUgYW1vdW50IHlvdSB3YWdlciBvbiBlYWNoIHRyYWRlLiBTZWNvbmQsIHlvdSB3aWxsIHNldCB5b3VyIGluaXRpYWwgZXF1aXR5IHRvIDEwMCwwMDAgVVNEIGluIGFuIG9iamVjdCBjYWxsZWQgaW5pdGVxLg0KDQpRdWFudHN0cmF0IHJlcXVpcmVzIHRocmVlIGRpZmZlcmVudCBvYmplY3RzIHRvIHdvcms6IGFuIGFjY291bnQsIGEgcG9ydGZvbGlvLCBhbmQgYSBzdHJhdGVneS4gQW4gYWNjb3VudCBpcyBjb21wcmlzZWQgb2YgcG9ydGZvbGlvcywgYW5kIGEgcG9ydGZvbGlvIGlzIGNvbXByaXNlZCBvZiBzdHJhdGVnaWVzLiBGb3IgeW91ciBmaXJzdCBzdHJhdGVneSwgdGhlcmUgd2lsbCBvbmx5IGJlIG9uZSBhY2NvdW50LCBvbmUgcG9ydGZvbGlvLCBhbmQgb25lIHN0cmF0ZWd5LiBMZXQncyBjYWxsIHRoZW0gImZpcnN0c3RyYXQiIGZvciAiZmlyc3Qgc3RyYXRlZ3kiLg0KDQpGaW5hbGx5LCBiZWZvcmUgcHJvY2VlZGluZywgeW91IG11c3QgcmVtb3ZlIGFueSBleGlzdGluZyBzdHJhdGVnaWVzIHVzaW5nIHRoZSBzdHJhdGVneSByZW1vdmFsIGNvbW1hbmQgcm0uc3RyYXQoKSB3aGljaCB0YWtlcyBpbiBhIHN0cmluZyBvZiB0aGUgbmFtZSBvZiBhIHN0cmF0ZWd5Lg0KYGBge3J9DQojIERlZmluZSB5b3VyIHRyYWRlIHNpemUgYW5kIGluaXRpYWwgZXF1aXR5DQp0cmFkZXNpemUgPC0gMTAwMDAwDQppbml0ZXEgPC0gMTAwMDAwDQoNCiMgRGVmaW5lIHRoZSBuYW1lcyBvZiB5b3VyIHN0cmF0ZWd5LCBwb3J0Zm9saW8gYW5kIGFjY291bnQNCnN0cmF0ZWd5LnN0IDwtICJmaXJzdHN0cmF0Ig0KcG9ydGZvbGlvLnN0IDwtICJmaXJzdHN0cmF0Ig0KYWNjb3VudC5zdCA8LSAiZmlyc3RzdHJhdCINCg0KIyBSZW1vdmUgdGhlIGV4aXN0aW5nIHN0cmF0ZWd5IGlmIGl0IGV4aXN0cw0Kcm0uc3RyYXQoc3RyYXRlZ3kuc3QpDQpgYGANCiMjIyBVbmRlcnN0YW5kaW5nIGluaXRpYWxpemF0aW9uIHNldHRpbmdzIOKAkyBJVg0KDQpOb3cgdGhhdCBldmVyeXRoaW5nIGhhcyBiZWVuIG5hbWVkLCB5b3UgbXVzdCBpbml0aWFsaXplIHRoZSBwb3J0Zm9saW8sIHRoZSBhY2NvdW50LCB0aGUgb3JkZXJzLCBhbmQgdGhlIHN0cmF0ZWd5IHRvIHByb2R1Y2UgcmVzdWx0cy4NCg0KLQlUaGUgcG9ydGZvbGlvIGluaXRpYWxpemF0aW9uIGluaXRQb3J0ZigpIG5lZWRzIGEgcG9ydGZvbGlvIHN0cmluZyBuYW1lLCBhIHZlY3RvciBmb3Igc3ltYm9scyB1c2VkIGluIHRoZSBiYWNrdGVzdCwgYW4gaW5pdGlhbGl6YXRpb24gZGF0ZSBpbml0RGF0ZSwgYW5kIGEgY3VycmVuY3kuDQotCVRoZSBhY2NvdW50IGluaXRpYWxpemF0aW9uIGNhbGwgaW5pdEFjY3QoKSBpcyBpZGVudGljYWwgdG8gdGhlIHBvcnRmb2xpbyBpbml0aWFsaXphdGlvbiBjYWxsIGV4Y2VwdCBpdCB0YWtlcyBhbiBhY2NvdW50IHN0cmluZyBuYW1lIGluc3RlYWQgb2YgYSBuZXcgcG9ydGZvbGlvIG5hbWUsIGFuIGV4aXN0aW5nIHBvcnRmb2xpb3MgbmFtZSwgYW5kIGFuIGluaXRpYWwgZXF1aXR5IGluaXRFcS4NCi0JVGhlIG9yZGVycyBpbml0aWFsaXphdGlvbiBpbml0T3JkZXJzKCkgbmVlZHMgYSBwb3J0Zm9saW8gc3RyaW5nIHBvcnRmb2xpbyBhbmQgYW4gaW5pdGlhbGl6YXRpb24gZGF0ZSBpbml0RGF0ZS4NCi0JVGhlIHN0cmF0ZWd5IGluaXRpYWxpemF0aW9uIHN0cmF0ZWd5KCkgbmVlZHMgYSBuYW1lIG9mIHRoaXMgbmV3IHN0cmF0ZWd5IGFuZCBtdXN0IGhhdmUgc3RvcmUgc2V0IHRvIFRSVUUuDQpgYGB7cn0NCiMgSW5pdGlhbGl6ZSB0aGUgcG9ydGZvbGlvDQppbml0UG9ydGYocG9ydGZvbGlvLnN0LCBzeW1ib2xzID0gIlNQWSIsIGluaXREYXRlID0gaW5pdGRhdGUsIGN1cnJlbmN5ID0gIlVTRCIpDQoNCiMgSW5pdGlhbGl6ZSB0aGUgYWNjb3VudA0KaW5pdEFjY3QoYWNjb3VudC5zdCwgcG9ydGZvbGlvcyA9IHBvcnRmb2xpby5zdCwgaW5pdERhdGUgPSBpbml0ZGF0ZSwgY3VycmVuY3kgPSAiVVNEIiwgaW5pdEVxID0gaW5pdGVxKQ0KDQojIEluaXRpYWxpemUgdGhlIG9yZGVycw0KaW5pdE9yZGVycyhwb3J0Zm9saW8uc3QsIGluaXREYXRlID0gaW5pdGRhdGUpDQoNCiMgU3RvcmUgdGhlIHN0cmF0ZWd5DQpzdHJhdGVneShzdHJhdGVneS5zdCwgc3RvcmUgPSBUUlVFKQ0KYGBgDQpZb3VyIHF1YW50c3RyYXQgc3RyYXRlZ3kgc3RyYXRlZ3kuc3QgaXMgbm93IHVwIGFuZCBydW5uaW5nLg0KDQojIEluZGljYXRvcnMNCg0KIyMgSW50cm9kdWN0aW9uDQoNCiMjIyBUaGUgU01BIGFuZCBSU0kgZnVuY3Rpb25zDQoNCldlbGNvbWUgdG8gdGhlIGNoYXB0ZXIgb24gaW5kaWNhdG9ycyEgQW4gaW5kaWNhdG9yIGlzIGEgdHJhbnNmb3JtYXRpb24gb2YgbWFya2V0IGRhdGEgdGhhdCBpcyB1c2VkIHRvIGdlbmVyYXRlIHNpZ25hbHMgb3IgZmlsdGVyIG5vaXNlLiBJbmRpY2F0b3JzIGZvcm0gdGhlIGJhY2tib25lIG9mIG1hbnkgdHJhZGluZyBzeXN0ZW1zLCBhbmQgdGhlIHN5c3RlbSB5b3Ugd2lsbCBidWlsZCBpbiB0aGlzIGNvdXJzZSB1c2VzIHNldmVyYWwgb2YgdGhlbS4NCg0KVGhlIHNpbXBsZSBtb3ZpbmcgYXZlcmFnZSAoU01BKSBhbmQgcmVsYXRpdmUgc3RyZW5ndGggaW5kZXggKFJTSSkgYXJlIHR3byBjbGFzc2ljIGluZGljYXRvcnMuIFRoZSBTTUEgaXMgYW4gYXJpdGhtZXRpYyBtb3ZpbmcgYXZlcmFnZSBvZiBwYXN0IHByaWNlcywgd2hpbGUgdGhlIFJTSSBpcyBhIGJvdW5kZWQgb3NjaWxsYXRpbmcgaW5kaWNhdG9yIHRoYXQgcmFuZ2VzIGZyb20gMCB0byAxMDAuIFRoZWlyIHJlc3BlY3RpdmUgZnVuY3Rpb25zIFNNQSgpIGFuZCBSU0koKSBib3RoIHRha2UgaW4gYSBzZXJpZXMgb2YgcHJpY2VzLCBkZW5vdGVkIGJ5IHggYW5kIHByaWNlIHJlc3BlY3RpdmVseSwgYW5kIGEgbG9va2JhY2sgcGVyaW9kIG4sIGZvciBleGFtcGxlOg0KDQogICAgU01BKHggPSBDbChHRFgpLCBuID0gNTApDQogICAgUlNJKHByaWNlID0gQ2woR0RYKSwgbiA9IDUwKQ0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgMjAwLWRheSBTTUENCnNweV9zbWEgPC0gU01BKHggPSBDbChTUFkpLCBuID0gMjAwKQ0KDQojIENyZWF0ZSBhbiBSU0kgd2l0aCBhIDMtZGF5IGxvb2tiYWNrIHBlcmlvZA0Kc3B5X3JzaSA8LSBSU0kocHJpY2UgPSBDbChTUFkpLCBuID0gMykNCmBgYA0KIyMjIFZpc3VhbGl6ZSBhbiBpbmRpY2F0b3IgYW5kIGd1ZXNzIGl0cyBwdXJwb3NlIOKAkyBTTUENCg0KTm93IHlvdSB3aWxsIHZpc3VhbGl6ZSB0aGVzZSBpbmRpY2F0b3JzIHRvIHVuZGVyc3RhbmQgd2h5IHlvdSBtaWdodCB3YW50IHRvIHVzZSB0aGUgaW5kaWNhdG9yIGFuZCB3aGF0IGl0IG1heSByZXByZXNlbnQuIFJlY2FsbCB0aGF0IGEgdHJlbmQgaW5kaWNhdG9yIGF0dGVtcHRzIHRvIHByZWRpY3Qgd2hldGhlciBhIHByaWNlIHdpbGwgY29udGludWUgaW4gaXRzIGN1cnJlbnQgZGlyZWN0aW9uLCB3aGVyZWFzIGEgcmV2ZXJzaW9uIGluZGljYXRvciBhdHRlbXB0cyB0byBwcmVkaWN0IHdoZXRoZXIgYW4gaW5jcmVhc2luZyBwcmljZSB3aWxsIHNvb24gZGVjcmVhc2UsIG9yIHRoZSBvcHBvc2l0ZS4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgcmV2aXNpdCB0aGUgMjAwLWRheSBTTUEuIEFzIGEgcmVmcmVzaGVyLCB0aGlzIGluZGljYXRvciBhdHRlbXB0cyB0byBzbW9vdGggb3V0IHByaWNlcywgYnV0IGNvbWVzIHdpdGggYSB0cmFkZW9mZiAtIGEgbGFnLiBZb3Ugd2lsbCBwbG90IHRoZSBwcmljZXMgb2YgU1BZIGFuZCBwbG90IGEgMjAwLWRheSBTTUEgb24gdG9wIG9mIHRoZSBwcmljZSBzZXJpZXMuIFVzaW5nIHRoaXMgaW5mb3JtYXRpb24sIHlvdSB3aWxsIGRldGVybWluZSBpZiBpdCBpcyBhIHRyZW5kIGluZGljYXRvciBvciByZXZlcnNpb24gaW5kaWNhdG9yDQoNCmBgYHtyfQ0KIyBQbG90IHRoZSBjbG9zaW5nIHByaWNlcyBvZiBTUFkNCnBsb3QoQ2woU1BZKSkNCg0KIyBPdmVybGF5IGEgMjAwLWRheSBTTUENCmxpbmVzKFNNQShDbChTUFkpLCBuID0gMjAwKSwgY29sID0gInJlZCIpDQoNCiMgV2hhdCBraW5kIG9mIGluZGljYXRvcj8NCnByaW50KCJ0cmVuZCIpDQpgYGANCkJ5IGF2ZXJhZ2luZyBvdmVyIGEgbW92aW5nIHBlcmlvZCBvZiAyMDAgZGF5cywgdGhlIFNNQSBoZWxwcyBpbmRpY2F0ZSBhIHRyZW5kIHJhdGhlciB0aGFuIGEgcmV2ZXJzaW9uLg0KDQojIyMgVmlzdWFsaXplIGFuIGluZGljYXRvciBhbmQgZ3Vlc3MgaXRzIHB1cnBvc2Ug4oCTIFJTSQ0KDQpUaGUgUmVsYXRpdmUgU3RyZW5ndGggSW5kZXggKFJTSSkgaXMgYW5vdGhlciBpbmRpY2F0b3IgdGhhdCByaXNlcyB3aXRoIHBvc2l0aXZlIHByaWNlIGNoYW5nZXMgYW5kIGZhbGxzIHdpdGggbmVnYXRpdmUgcHJpY2UgY2hhbmdlcy4gSXQgaXMgZXF1YWwgdG8gMTAwIC0gMTAwLygxICsgUlMpLCB3aGVyZSBSUyBpcyB0aGUgYXZlcmFnZSBnYWluIG92ZXIgYXZlcmFnZSBsb3NzIG92ZXIgdGhlIGxvb2tiYWNrIHBlcmlvZC4gQXQgdmFyaW91cyBsZW5ndGhzLCB0aGlzIGluZGljYXRvciBjYW4gcmFuZ2UgZnJvbSBhIHJldmVyc2lvbiBpbmRpY2F0b3IsIHRvIGEgdHJlbmQgZmlsdGVyLCBvciBhbnl3aGVyZSBpbiBiZXR3ZWVuLiBUaGVyZSBhcmUgdmFyaW91cyB3YXlzIG9mIGNvbXB1dGluZyB0aGUgUlNJLg0KDQpBcyB5b3UgYWxyZWFkeSBrbm93LCBSU0koKSB0YWtlcyBpbiBhIHByaWNlIHNlcmllcyBwcmljZSBhbmQgYSBudW1iZXIgb2YgcGVyaW9kcyBuIHdoaWNoIGhhcyBhIGRlZmF1bHQgdmFsdWUgb2YgMTQuIFNvbWUgdHJhZGVycyBiZWxpZXZlIHRoYXQgdGhlIDItcGVyaW9kIFJTSSwgYWxzbyBrbm93biBhcyB0aGUgUlNJIDIsIGhhcyBldmVuIG1vcmUgaW1wb3J0YW50IHByb3BlcnRpZXMgdGhhbiB0aGUgMTQtcGVyaW9kIFJTSS4NClJhdGhlciB0aGFuIHBsb3R0aW5nIHRoaXMgaW5kaWNhdG9yIG9uIHRoZSBhY3R1YWwgcHJpY2Ugc2VyaWVzLCB5b3UnbGwgbG9vayBhdCBhIHNtYWxsLCBvbmUgeWVhciBzdWJzZXQgb2YgU1BZIGFuZCBob3cgdGhlIFJTSSBpbnRlcmFjdHMgd2l0aCB0aGUgcHJpY2UuDQpgYGB7cn0NCiMgUGxvdCB0aGUgY2xvc2luZyBwcmljZSBvZiBTUFkNCnBsb3QoQ2woU1BZKSkNCg0KIyBQbG90IHRoZSBSU0kgMg0KcGxvdChSU0koQ2woU1BZKSwgbiA9IDIpKQ0KDQojIFdoYXQga2luZCBvZiBpbmRpY2F0b3I/DQpwcmludCgicmV2ZXJzaW9uIikNCmBgYA0KQnkgbWVhc3VyaW5nIHRoZSBjaGFuZ2Ugb2YgcHJpY2UgbW92ZW1lbnRzLCB0aGUgUlNJIGluZGljYXRlcyBhIHJldmVyc2lvbiByYXRoZXIgdGhhbiBhIHRyZW5kLg0KDQojIyBJbmRpY2F0b3IgbWVjaGFuaWNzDQoNCiMjIyBJbXBsZW1lbnRpbmcgYW4gaW5kaWNhdG9yIOKAkyBTTUEyMDANCg0KQXQgdGhpcyBwb2ludCwgaXQncyB0aW1lIHRvIHN0YXJ0IGdldHRpbmcgaW50byB0aGUgbWVjaGFuaWNzIG9mIGltcGxlbWVudGluZyBhbiBpbmRpY2F0b3Igd2l0aGluIHRoZSBzY29wZSBvZiB0aGUgcXVhbnRzdHJhdCBsaWJyYXJ5LiBJbiB0aGlzIGV4ZXJjaXNlIHlvdSB3aWxsIGxlYXJuIGhvdyB0byBhZGQgYW4gaW5kaWNhdG9yIHRvIHlvdXIgc3RyYXRlZ3kuIEZvciB0aGlzIGV4ZXJjaXNlIHlvdSB3aWxsIHVzZSB0aGUgc3RyYXRlZ3kgeW91IGNyZWF0ZWQgaW4gZWFybGllciBleGVyY2lzZXMsIHN0cmF0ZWd5LnN0LiBGb3IgeW91ciBmaXJzdCBpbmRpY2F0b3IsIHlvdSB3aWxsIGFkZCBhIDIwMC1kYXkgc2ltcGxlIG1vdmluZyBhdmVyYWdlLg0KVG8gYWRkIGFuIGluZGljYXRvciB0byB5b3VyIHN0cmF0ZWd5LCB5b3Ugd2lsbCB1c2UgdGhlIGFkZC5pbmRpY2F0b3IoKS4gU2V0IHN0cmF0ZWd5IGVxdWFsIHRvIHRoZSBuYW1lIG9mIHlvdXIgc3RyYXRlZ3ksIG5hbWUgdG8gdGhlIG5hbWUgb2YgYSBmdW5jdGlvbiBpbiBxdW90ZXMsIGFuZCBhcmd1bWVudHMgdG8gdGhlIGFyZ3VtZW50cyBvZiB0aGUgbmFtZWQgZnVuY3Rpb24gaW4gdGhlIGZvcm0gb2YgYSBsaXN0LiBGb3IgaW5zdGFuY2UsIGlmIHlvdXIgZnVuY3Rpb24gbmFtZSB3YXMgU01BLCB0aGUgYXJndW1lbnRzIGFyZ3VtZW50IHdpbGwgY29udGFpbiB0aGUgYXJndW1lbnRzIHRvIHRoZSBTTUEgZnVuY3Rpb246DQoNCiAgICBhZGQuaW5kaWNhdG9yKHN0cmF0ZWd5ID0gc3RyYXRlZ3kuc3QsIA0KICAgICAgICAgICAgICAgICAgbmFtZSA9ICJTTUEiLCANCiAgICAgICAgICAgICAgICAgIGFyZ3VtZW50cyA9IGxpc3QoeCA9IHF1b3RlKENsKG1rdGRhdGEpKSwgbiA9IDUwMCksIA0KICAgICAgICAgICAgICAgICAgbGFiZWwgPSAiU01BNTAwIikNCg0KV2hlbiByZWZlcmVuY2luZyBkeW5hbWljIG1hcmtldCBkYXRhIGluIHlvdXIgYWRkLmluZGljYXRvcigpIGNhbGwsIGluY2x1ZGUgbWt0ZGF0YSBpbnNpZGUgdGhlIHF1b3RlKCkgZnVuY3Rpb24gYmVjYXVzZSBpdCBpcyBjcmVhdGVkIGluc2lkZSBxdWFudHN0cmF0IGFuZCB3aWxsIGNoYW5nZSBkZXBlbmRpbmcgb24gd2hpY2hldmVyIGluc3RydW1lbnQgdGhlIHBhY2thZ2UgaXMgdXNpbmcgYXQgdGhlIHRpbWUuIHF1b3RlKCkgZW5zdXJlcyB0aGF0IHRoZSBkYXRhIGNhbiBkeW5hbWljYWxseSBjaGFuZ2Ugb3ZlciB0aGUgY291cnNlIG9mIHJ1bm5pbmcgeW91ciBzdHJhdGVneS4NCmBgYHtyfQ0KI0FkZCBhIDIwMC1kYXkgU01BIGluZGljYXRvciB0byBzdHJhdGVneS5zdA0KYWRkLmluZGljYXRvcihzdHJhdGVneSA9IHN0cmF0ZWd5LnN0LCANCiAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICMgQWRkIHRoZSBTTUEgZnVuY3Rpb24NCiAgICAgICAgICAgICAgbmFtZSA9ICJTTUEiLCANCiAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICMgQ3JlYXRlIGEgbG9va2JhY2sgcGVyaW9kDQogICAgICAgICAgICAgIGFyZ3VtZW50cyA9IGxpc3QoeCA9IHF1b3RlKENsKG1rdGRhdGEpKSwgbiA9IDIwMCksIA0KICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgIyBMYWJlbCB5b3VyIGluZGljYXRvciBTTUE1MA0KICAgICAgICAgICAgICBsYWJlbCA9ICJTTUEyMDAiKQ0KYGBgDQoNCiMjIyBJbXBsZW1lbnRpbmcgYW4gaW5kaWNhdG9yIOKAkyBTTUE1MA0KDQpOb3csIHlvdSdsbCBtYWtlIHlvdXIgc3RyYXRlZ3kgZXZlbiBtb3JlIHJvYnVzdCBieSBhZGRpbmcgYSA1MC1kYXkgU01BLiBBIGZhc3QgbW92aW5nIGF2ZXJhZ2Ugd2l0aCBhIHNsb3dlciBtb3ZpbmcgYXZlcmFnZSBpcyBhIHNpbXBsZSBhbmQgc3RhbmRhcmQgd2F5IHRvIHByZWRpY3Qgd2hlbiBwcmljZXMgaW4gYW4gYXNzZXQgYXJlIGV4cGVjdGVkIHRvIHJpc2UgaW4gdGhlIGZ1dHVyZS4gV2hpbGUgYSBzaW5nbGUgaW5kaWNhdG9yIGNhbiBwcm92aWRlIGEgbG90IG9mIGluZm9ybWF0aW9uLCBhIHRydWx5IHJvYnVzdCB0cmFkaW5nIHN5c3RlbSByZXF1aXJlcyBtdWx0aXBsZSBpbmRpY2F0b3JzIHRvIG9wZXJhdGUgZWZmZWN0aXZlbHkuDQpgYGB7cn0NCiMgQWRkIGEgNTAtZGF5IFNNQSBpbmRpY2F0b3IgdG8gc3RyYXRlZ3kuc3QNCmFkZC5pbmRpY2F0b3Ioc3RyYXRlZ3kgPSBzdHJhdGVneS5zdCwgDQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAjIEFkZCB0aGUgU01BIGZ1bmN0aW9uDQogICAgICAgICAgICAgIG5hbWUgPSAiU01BIiwgDQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAjIENyZWF0ZSBhIGxvb2tiYWNrIHBlcmlvZA0KICAgICAgICAgICAgICBhcmd1bWVudHMgPSBsaXN0KHggPSBxdW90ZShDbChta3RkYXRhKSksIG4gPSA1MCksIA0KICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgIyBMYWJlbCB5b3VyIGluZGljYXRvciBTTUE1MA0KICAgICAgICAgICAgICBsYWJlbCA9ICJTTUE1MCIpDQoNCmBgYA0KQnkgYWRkaW5nIGEgc2Vjb25kIGluZGljYXRvciB0byB5b3VyIHN0cmF0ZWd5LCB5b3UndmUgbWFkZSBpdCBtb3JlIHJvYnVzdC4NCg0KIyMjIEltcGxlbWVudGluZyBhbiBpbmRpY2F0b3Ig4oCTIFJTSQ0KDQpJbiBmaW5hbmNpYWwgbWFya2V0cywgdGhlIGdvYWwgaXMgdG8gYnV5IGxvdyBhbmQgc2VsbCBoaWdoLiBUaGUgUlNJIGNhbiBwcmVkaWN0IHdoZW4gYSBwcmljZSBoYXMgc3VmZmljaWVudGx5IHB1bGxlZCBiYWNrLCBlc3BlY2lhbGx5IHdpdGggYSBzaG9ydCBwZXJpb2Qgc3VjaCBhcyAyIG9yIDMuDQoNCkhlcmUsIHlvdSdsbCBjcmVhdGUgYSAzLXBlcmlvZCBSU0ksIG9yIFJTSSAzLCB0byBnaXZlIHlvdSBtb3JlIHByYWN0aWNlIGluIGltcGxlbWVudGluZyBwcmUtY29kZWQgaW5kaWNhdG9ycy4NCmBgYHtyfQ0KIyBBZGQgYW4gUlNJIDMgaW5kaWNhdG9yIHRvIHN0cmF0ZWd5LnN0DQphZGQuaW5kaWNhdG9yKHN0cmF0ZWd5ID0gc3RyYXRlZ3kuc3QsIA0KICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgIyBBZGQgdGhlIFJTSSAzIGZ1bmN0aW9uDQogICAgICAgICAgICAgIG5hbWUgPSAiUlNJIiwgDQogICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAjIENyZWF0ZSBhIGxvb2tiYWNrIHBlcmlvZA0KICAgICAgICAgICAgICBhcmd1bWVudHMgPSBsaXN0KHByaWNlID0gcXVvdGUoQ2wobWt0ZGF0YSkpLCBuID0gMyksIA0KICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgIyBMYWJlbCB5b3VyIGluZGljYXRvciBSU0lfMw0KICAgICAgICAgICAgICBsYWJlbCA9ICJSU0lfMyIpDQpgYGANCiMjIEluZGljYXRvciBzdHJ1Y3R1cmUgcmV2aWV3DQoNCiMjIyBDb2RlIHlvdXIgb3duIGluZGljYXRvciDigJMgUlNJIDMuNQ0KDQpTbyBmYXIsIHlvdSd2ZSB1c2VkIGluZGljYXRvcnMgdGhhdCBoYXZlIGJlZW4gY29tcGxldGVseSBwcmUtd3JpdHRlbiBmb3IgeW91IGJ5IHVzaW5nIHRoZSBhZGQuaW5kaWNhdG9yKCkgZnVuY3Rpb24uIE5vdyBpdCdzIHRpbWUgZm9yIHlvdSB0byB3cml0ZSBhbmQgYXBwbHkgeW91ciBvd24gaW5kaWNhdG9yLg0KDQpZb3VyIGluZGljYXRvciBmdW5jdGlvbiB3aWxsIGNhbGN1bGF0ZSB0aGUgYXZlcmFnZSBvZiB0d28gZGlmZmVyZW50IGluZGljYXRvcnMgdG8gY3JlYXRlIGFuIFJTSSBvZiAzLjUuIEhlcmUncyBob3c6DQoNCi0gVGFrZSBpbiBhIHByaWNlIHNlcmllcy4NCi0gQ2FsY3VsYXRlIFJTSSAzLg0KLSBDYWxjdWxhdGUgUlNJIDQuDQotIFJldHVybiB0aGUgYXZlcmFnZSBvZiBSU0kgMyBhbmQgUlNJIDQuDQoNClRoaXMgUlNJIGNhbiBiZSB0aG91Z2h0IG9mIGFzIGFuIFJTSSAzLjUsIGJlY2F1c2UgaXQncyBsb25nZXIgdGhhbiBhbiBSU0kgMyBhbmQgc2hvcnRlciB0aGFuIGFuIFJTSSA0LiBCeSBhdmVyYWdpbmcsIHRoaXMgaW5kaWNhdG9yIHRha2VzIGludG8gYWNjb3VudCB0aGUgaW1wYWN0IG9mIGZvdXIgZGF5cyBhZ28gd2hpbGUgc3RpbGwgYmVpbmcgZmFzdGVyIHRoYW4gYSBzaW1wbGUgUlNJIDQsIGFuZCBhbHNvIHJlbW92ZXMgdGhlIG5vaXNlIG9mIGJvdGggUlNJIDMgYW5kIFJTSSA0Lg0KDQpZb3Ugd2lsbCBjcmVhdGUgYSBmdW5jdGlvbiBmb3IgdGhpcyBpbmRpY2F0b3IgY2FsbGVkIGNhbGNfUlNJX2F2ZygpIGFuZCBhZGQgaXQgdG8geW91ciBzdHJhdGVneSBzdHJhdGVneS5zdC4gQWxsIHJlbGV2YW50IHBhY2thZ2VzIGFyZSBhbHNvIGxvYWRlZCBmb3IgeW91Lg0KYGBge3J9DQojIFdyaXRlIHRoZSBjYWxjX1JTSV9hdmcgZnVuY3Rpb24NCmNhbGNfUlNJX2F2ZyA8LSBmdW5jdGlvbihwcmljZSwgbjEsIG4yKSB7DQogIA0KICAjIFJTSSAxIHRha2VzIGFuIGlucHV0IG9mIHRoZSBwcmljZSBhbmQgbjENCiAgUlNJXzEgPC0gUlNJKHByaWNlID0gcHJpY2UsIG4gPSBuMSkNCiAgDQogICMgUlNJIDIgdGFrZXMgYW4gaW5wdXQgb2YgdGhlIHByaWNlIGFuZCBuMg0KICBSU0lfMiA8LSBSU0kocHJpY2UgPSBwcmljZSwgbiA9IG4yKQ0KICANCiAgIyBSU0lfYXZnIGlzIHRoZSBhdmVyYWdlIG9mIFJTSV8xIGFuZCBSU0lfMg0KICBSU0lfYXZnIDwtIChSU0lfMSArIFJTSV8yKS8yDQogIA0KICAjIFlvdXIgb3V0cHV0IG9mIFJTSV9hdmcgbmVlZHMgYSBjb2x1bW4gbmFtZSBvZiBSU0lfYXZnDQogIGNvbG5hbWVzKFJTSV9hdmcpIDwtICJSU0lfYXZnIg0KICByZXR1cm4oUlNJX2F2ZykNCn0NCg0KIyBBZGQgdGhpcyBmdW5jdGlvbiBhcyBSU0lfM180IHRvIHlvdXIgc3RyYXRlZ3kgd2l0aCBuMSA9IDMgYW5kIG4yID0gNA0KYWRkLmluZGljYXRvcihzdHJhdGVneS5zdCwgbmFtZSA9ICJjYWxjX1JTSV9hdmciLCBhcmd1bWVudHMgPSBsaXN0KHByaWNlID0gcXVvdGUoQ2wobWt0ZGF0YSkpLCBuMSA9IDMsIG4yID0gNCksIGxhYmVsID0gIlJTSV8zXzQiKQ0KYGBgDQojIyMgQ29kZSB5b3VyIG93biBpbmRpY2F0b3Ig4oCTIERWTw0KDQpXaGlsZSB0aGUgUlNJIGlzIGRlY2VudCwgaXQgaXMgc29tZXdoYXQgb3V0ZGF0ZWQgYXMgZmFyIGFzIGluZGljYXRvcnMgZ28uIEluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGNvZGUgYSBzaW1wbGlmaWVkIHZlcnNpb24gb2YgYW5vdGhlciBpbmRpY2F0b3IgZnJvbSBzY3JhdGNoLiBUaGUgaW5kaWNhdG9yIGlzIGNhbGxlZCB0aGUgRGF2aWQgVmFyYWRpIE9zY2lsbGF0b3IgKERWTyksIG9yaWdpbmF0ZWQgYnkgRGF2aWQgVmFyYWRpLCBhIHF1YW50aXRhdGl2ZSByZXNlYXJjaCBkaXJlY3Rvci4NCg0KVGhlIHB1cnBvc2Ugb2YgdGhpcyBvc2NpbGxhdG9yIGlzIHNpbWlsYXIgdG8gc29tZXRoaW5nIGxpa2UgdGhlIFJTSSBpbiB0aGF0IGl0IGF0dGVtcHRzIHRvIGZpbmQgb3Bwb3J0dW5pdGllcyB0byBidXkgYSB0ZW1wb3JhcnkgZGlwIGFuZCBzZWxsIGluIGEgdGVtcG9yYXJ5IHVwdHJlbmQuIEluIGFkZGl0aW9uIHRvIG9ibGlnYXRvcnkgbWFya2V0IGRhdGEsIGFuIG9zY2lsbGF0b3IgZnVuY3Rpb24gdGFrZXMgaW4gdHdvIGxvb2tiYWNrIHBlcmlvZHMuDQoNCkZpcnN0LCB0aGUgZnVuY3Rpb24gY29tcHV0ZXMgYSByYXRpbyBiZXR3ZWVuIHRoZSBjbG9zaW5nIHByaWNlIGFuZCBhdmVyYWdlIG9mIGhpZ2ggYW5kIGxvdyBwcmljZXMuIE5leHQsIGl0IGFwcGxpZXMgYW4gU01BIHRvIHRoYXQgcXVhbnRpdHkgdG8gc21vb3RoIG91dCBub2lzZSwgdXN1YWxseSBvbiBhIHZlcnkgc21hbGwgdGltZSBmcmFtZSwgc3VjaCBhcyB0d28gZGF5cy4gRmluYWxseSwgaXQgdXNlcyB0aGUgcnVuUGVyY2VudFJhbmsoKSBmdW5jdGlvbiB0byB0YWtlIGEgcnVubmluZyBwZXJjZW50YWdlIHJhbmsgb2YgdGhpcyBhdmVyYWdlIHJhdGlvLCBhbmQgbXVsdGlwbGllcyBpdCBieSAxMDAgdG8gY29udmVydCBpdCB0byBhIDAtMTAwIHF1YW50aXR5Lg0KDQpUaGluayBhYm91dCB0aGUgd2F5IHRoYXQgc3R1ZGVudHMgZ2V0IHBlcmNlbnRpbGUgc2NvcmVzIGFmdGVyIHRha2luZyBhIHN0YW5kYXJkaXplZCB0ZXN0ICh0aGF0IGlzLCBpZiBhIHN0dWRlbnQgZ290IGFuIDgwMCBvbiBoZXIgbWF0aCBzZWN0aW9uLCBzaGUgbWlnaHQgYmUgaW4gdGhlIDk1dGggcGVyY2VudGlsZSBuYXRpb25hbGx5KS4gcnVuUGVyY2VudFJhbmsoKSBkb2VzIHRoZSBzYW1lIHRoaW5nLCBleGNlcHQgb3ZlciB0aW1lLiBUaGlzIGluZGljYXRvciBwcm92aWRlcyB0aGUgcmFuayBmb3IgdGhlIGxhdGVzdCBvYnNlcnZhdGlvbiB3aGVuIHRha2VuIGluIHRoZSBjb250ZXh0IG92ZXIgc29tZSBwYXN0IHBlcmlvZCB0aGF0IHRoZSB1c2VyIHNwZWNpZmllcy4gRm9yIGV4YW1wbGUsIGlmIHNvbWV0aGluZyBoYXMgYSBydW5QZXJjZW50UmFuayB2YWx1ZSBvZiAuOTAgd2hlbiB1c2luZyBhIGxvb2tiYWNrIHBlcmlvZCBvZiAxMjYsIGl0IG1lYW5zIGl0J3MgaW4gdGhlIDkwdGggcGVyY2VudGlsZSB3aGVuIGNvbXBhcmVkIHRvIGl0c2VsZiBhbmQgdGhlIHBhc3QgMTI1IG9ic2VydmF0aW9ucy4NCg0KWW91ciBqb2IgaXMgdG8gaW1wbGVtZW50IHRoaXMgaW5kaWNhdG9yIGFuZCBzYXZlIGl0IGFzIERWTy4NCmBgYHtyfQ0KIyBEZWNsYXJlIHRoZSBEVk8gZnVuY3Rpb24NCkRWTyA8LSBmdW5jdGlvbihITEMsIG5hdmcgPSAyLCBwZXJjZW50bG9va2JhY2sgPSAxMjYpIHsNCiAgDQogICMgQ29tcHV0ZSB0aGUgcmF0aW8gYmV0d2VlbiBjbG9zaW5nIHByaWNlcyB0byB0aGUgYXZlcmFnZSBvZiBoaWdoIGFuZCBsb3cNCiAgcmF0aW8gPC0gQ2woSExDKS8oSGkoSExDKSArIExvKEhMQykpLzINCiAgDQogICMgU21vb3RoIG91dCB0aGUgcmF0aW8gb3V0cHV0cyB1c2luZyBhIG1vdmluZyBhdmVyYWdlDQogIGF2Z3JhdGlvIDwtIFNNQShyYXRpbywgbiA9IG5hdmcpDQogIA0KICAjIENvbnZlcnQgcmF0aW8gaW50byBhIDAtMTAwIHZhbHVlIHVzaW5nIHJ1blBlcmNlbnRSYW5rKCkNCiAgb3V0IDwtIHJ1blBlcmNlbnRSYW5rKGF2Z3JhdGlvLCBuID0gcGVyY2VudGxvb2tiYWNrLCBleGFjdC5tdWx0aXBsaWVyID0gMSkgKiAxMDANCiAgY29sbmFtZXMob3V0KSA8LSAiRFZPIg0KICByZXR1cm4ob3V0KQ0KfQ0KYGBgDQojIyMgQXBwbHkgeW91ciBvd24gaW5kaWNhdG9yDQoNCk5vdyB5b3UgaGF2ZSBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIGluZGljYXRvcnMgYXMgZnVuY3Rpb25zIHRoYXQgYW55b25lIGNhbiB3cml0ZS4gSXQncyB0aW1lIHRvIGFwcGx5IHRoZSBpbmRpY2F0b3IgeW91IGNyZWF0ZWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLiBUbyBkbyBzbywgeW91IHdpbGwgbWFrZSB1c2Ugb2YgdGhlIGFwcGx5SW5kaWNhdG9ycygpIGNvbW1hbmQuDQoNCkZyb20gZGVidWdnaW5nIHRvIHN1YnNldHRpbmcsIGtub3dpbmcgaG93IHRvIHN0ZXAgaW5zaWRlIHlvdXIgc3RyYXRlZ3kgaXMgYSB2YWx1YWJsZSBwaWVjZSBvZiBrbm93bGVkZ2UuIEV2ZXJ5IHNvIG9mdGVuLCB5b3UgbWlnaHQgaGF2ZSBhbiBlcnJvciBpbiB5b3VyIHN0cmF0ZWd5LCBhbmQgd2lsbCB3YW50IHRvIHRyYWNrIGl0IGRvd24uIEtub3dpbmcgaG93IHRvIHVzZSB0aGUgYXBwbHlJbmRpY2F0b3JzKCkgY29tbWFuZCB3aWxsIGhlbHAgeW91IGlkZW50aWZ5IHlvdXIgZXJyb3JzLiBGdXJ0aGVybW9yZSwgc29tZXRpbWVzIHlvdSBtYXkgd2FudCB0byBsb29rIGF0IGEgc21hbGwgY2h1bmsgb2YgdGltZSBpbiB5b3VyIHN0cmF0ZWd5LiBUaGlzIGV4ZXJjaXNlIHdpbGwgaGVscCB0cmFpbiB5b3UgdG8gZG8gdGhpcyBhcyB3ZWxsLg0KDQpJbiBvcmRlciB0byBzdWJzZXQgdGltZSBzZXJpZXMgZGF0YSwgdXNlIGJyYWNrZXRzIHdpdGggdGhlIHN0YXJ0IGRhdGUsIGZvcndhcmQgc2xhc2ggc3ltYm9sLCBhbmQgZW5kIGRhdGUuDQpgYGB7cn0NCiMgQWRkIHRoZSBEVk8gaW5kaWNhdG9yIHRvIHlvdXIgc3RyYXRlZ3kNCmFkZC5pbmRpY2F0b3Ioc3RyYXRlZ3kgPSBzdHJhdGVneS5zdCwgbmFtZSA9ICJEVk8iLCANCiAgICAgICAgICAgICAgYXJndW1lbnRzID0gbGlzdChITEMgPSBxdW90ZShITEMobWt0ZGF0YSkpLCBuYXZnID0gMiwgcGVyY2VudGxvb2tiYWNrID0gMTI2KSwNCiAgICAgICAgICAgICAgbGFiZWwgPSAiRFZPXzJfMTI2IikNCg0KIyBVc2UgYXBwbHlJbmRpY2F0b3JzIHRvIHRlc3Qgb3V0IHlvdXIgaW5kaWNhdG9ycw0KdGVzdCA8LSBhcHBseUluZGljYXRvcnMoc3RyYXRlZ3kgPSBzdHJhdGVneS5zdCwgbWt0ZGF0YSA9IEhMQyhTUFkpKQ0KDQojIFN1YnNldCB5b3VyIGRhdGEgYmV0d2VlbiBTZXAuIDEgYW5kIFNlcC4gNSBvZiAyMDEzDQp0ZXN0X3N1YnNldCA8LSB0ZXN0WyIyMDEzLTA5LTAxLzIwMTMtMDktMDUiXQ0KYGBgDQojIFNpZ25hbHMNCg0KIyMgSW50cm9kdWN0aW9uIHRvIHNpZ25hbHMNCg0KIyMjIFNpZ25hbCBvciBub3Q/IOKAkyBJDQoNCkEgc2lnbmFsIGlzIGFuIGludGVyYWN0aW9uIG9mIG1hcmtldCBkYXRhIHdpdGggaW5kaWNhdG9ycywgb3IgaW5kaWNhdG9ycyB3aXRoIG90aGVyIGluZGljYXRvcnMsIHdoaWNoIHRlbGxzIHlvdSB3aGV0aGVyIHlvdSBtYXkgd2lzaCB0byBidXkgb3Igc2VsbCBhbiBhc3NldC4gU2lnbmFscyBjYW4gYmUgdHJpZ2dlcmVkIGZvciBhIHZhcmlldHkgb2YgcmVhc29ucy4gRm9yIGV4YW1wbGUsIGEgc2lnbmFsIG1heSBiZSB0cmlnZ2VyZWQgYnkgYSBzaG9ydGVyIGxvb2tiYWNrIG1vdmluZyBhdmVyYWdlIGdvaW5nIGZyb20gbGVzcyB0aGFuIHRvIGdyZWF0ZXIgdGhhbiBhIGxvbmdlciBsb29rYmFjayBtb3ZpbmcgYXZlcmFnZS4gQW5vdGhlciBzaWduYWwgbWF5IGJlIHRyaWdnZXJlZCB3aGVuIGFuIG9zY2lsbGF0b3IgZ29lcyBmcm9tIGJlaW5nIGFib3ZlIGEgY2VydGFpbiBzZXQgcXVhbnRpdHkgKGZvciBleGFtcGxlLCAyMCkgdG8gYmVsb3csIGFuZCBzbyBvbi4NCg0KSW4gdGhpcyBjaGFwdGVyLCB5b3Ugd2lsbCBzZWUgdmFyaW91cyB3YXlzIGluIHdoaWNoIGluZGljYXRvcnMgaW50ZXJhY3Qgd2l0aCBlYWNoIG90aGVyLiBZb3Ugd2lsbCBmb2N1cyBvbiB0aGUgc3RyYXRlZ3kgeW91IGRldmVsb3BlZCBpbiB0aGUgcHJldmlvdXMgY2hhcHRlciAoc3RyYXRlZ3kuc3QpLiBUbyBrZWVwIHRoaW5nIHNpbXBsZSwgeW91IHdpbGwgcmVtb3ZlIGFsbCBvZiB0aGUgUlNJIGluZGljYXRvcnMgYW5kIHN0aWNrIHRvIHRoZSBEVk8gKERhdmlkIFZhcmFkaSdzIE9zY2lsbGF0b3IpLg0Kc2lnVGhyZXNob2xkIGlzIGEgc2lnbmFsIHRocmVzaG9sZCBhcmd1bWVudCB3aGljaCBhc3Nlc3NlcyB3aGV0aGVyIG9yIG5vdCBhIHZhbHVlIGlzIGFib3ZlIG9yIGJlbG93IGEgY2VydGFpbiBzdGF0aWMgcXVhbnRpdHkuDQoNCiMjIHNpZ0NvbXBhcmlzb24gYW5kIHNpZ0Nyb3Nzb3Zlcg0KDQojIyMgVXNpbmcgc2lnQ29tcGFyaXNvbg0KDQpBIHNpZ0NvbXBhcmlzb24gc2lnbmFsIGlzIGEgc2ltcGxlIGFuZCB1c2VmdWwgd2F5IHRvIGNvbXBhcmUgdHdvIChob3BlZnVsbHkgcmVsYXRlZCkgcXVhbnRpdGllcywgc3VjaCBhcyB0d28gbW92aW5nIGF2ZXJhZ2VzLiBPZnRlbiwgYSBzaWdDb21wYXJpc29uIHNpZ25hbCBkb2VzIG5vdCBjcmVhdGUgYSBidXkgb3Igc2VsbCBzaWduYWwgYnkgaXRzZWxmIChhcyBzdWNoIGEgc2lnbmFsIHdvdWxkIGludm9sdmUgYnV5aW5nIG9yIHNlbGxpbmcgb24gZXZlcnkgc3VjaCBkYXkpLCBidXQgaXMgbW9zdCBvZnRlbiB1c2VmdWwgYXMgYSBmaWx0ZXIgZm9yIHdoZW4gYW5vdGhlciBidXkgb3Igc2VsbCBydWxlIHNob3VsZCBiZSBmb2xsb3dlZC4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgdXNlIHNpZ0NvbXBhcmlzb24oKSB0byBnZW5lcmF0ZSBhIHNpZ25hbCBjb21wYXJpc29uIHRoYXQgc3BlY2lmaWVzIHRoYXQgdGhlIDUwLWRheSBzaW1wbGUgbW92aW5nIGF2ZXJhZ2UgKFNNQSkgbXVzdCBiZSBhYm92ZSB0aGUgMjAwLWRheSBzaW1wbGUgbW92aW5nIGF2ZXJhZ2UgKFNNQSkuIFlvdSB3aWxsIGxhYmVsIHRoaXMgc2lnbmFsIGxvbmdmaWx0ZXIsIGJlY2F1c2UgaXQgc2lnbmFscyB0aGF0IHRoZSBzaG9ydC10ZXJtIGF2ZXJhZ2UgaXMgYWJvdmUgdGhlIGxvbmctdGVybSBhdmVyYWdlLg0KYGBge3J9DQojIEFkZCBhIHNpZ0NvbXBhcmlzb24gd2hpY2ggc3BlY2lmaWVzIHRoYXQgU01BNTAgbXVzdCBiZSBncmVhdGVyIHRoYW4gU01BMjAwLCBjYWxsIGl0IGxvbmdmaWx0ZXINCmFkZC5zaWduYWwoc3RyYXRlZ3kuc3QsIG5hbWUgPSAic2lnQ29tcGFyaXNvbiIsIA0KICAgICAgICAgICANCiAgICAgICAgICAgIyBXZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIFNNQTUwIGFuZCB0aGUgU01BMjAwDQogICAgICAgICAgIGFyZ3VtZW50cyA9IGxpc3QoY29sdW1ucyA9IGMoIlNNQTUwIiwgIlNNQTIwMCIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFBhcnRpY3VsYXJseSwgd2UgYXJlIGludGVyZXN0ZWQgd2hlbiB0aGUgU01BNTAgaXMgZ3JlYXRlciB0aGFuIHRoZSBTTUEyMDANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxhdGlvbnNoaXAgPSAiZ3QiKSwNCiAgICAgICAgICAgDQogICAgICAgICAgICMgTGFiZWwgdGhpcyBzaWduYWwgbG9uZ2ZpbHRlcg0KICAgICAgICAgICBsYWJlbCA9ICJsb25nZmlsdGVyIikNCmBgYA0KIyMjIFVzaW5nIHNpZ0Nyb3Nzb3Zlcg0KDQpXaGlsZSBoYXZpbmcgYSBsb25nIGZpbHRlciBpcyBuZWNlc3NhcnksIGl0IGlzIG5vdCBzdWZmaWNpZW50IHRvIHB1dCBvbiBhIHRyYWRlIGZvciB0aGlzIHN0cmF0ZWd5LiBIb3dldmVyLCB0aGUgbW9tZW50IHRoZSBjb25kaXRpb24gZG9lcyBub3QgaG9sZCwgdGhlIHN0cmF0ZWd5IHNob3VsZCBub3QgaG9sZCBhbnkgcG9zaXRpb24gd2hhdHNvZXZlci4gRm9yIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGltcGxlbWVudCB0aGUgb3Bwb3NpdGUgb2YgdGhlIHJ1bGUgc3BlY2lmaWVkIGFib3ZlIHVzaW5nIHRoZSBzaWdDcm9zc292ZXIoKSBmdW5jdGlvbi4NCg0KQXMgb3Bwb3NlZCB0byBzaWdDb21wYXJpc29uKCksIHdoaWNoIHdpbGwgYWx3YXlzIHN0YXRlIHdoZXRoZXIgb3Igbm90IGEgY29uZGl0aW9uIGhvbGRzLCBzaWdDcm9zc292ZXIoKSBvbmx5IGdpdmVzIGEgcG9zaXRpdmUgdGhlIG1vbWVudCB0aGUgc2lnbmFsIGZpcnN0IG9jY3VycywgYW5kIHRoZW4gbm90IGFnYWluLiBUaGlzIGlzIHVzZWZ1bCBmb3IgYSBzaWduYWwgdGhhdCB3aWxsIGJlIHVzZWQgdG8gaW5pdGlhdGUgYSB0cmFuc2FjdGlvbiwgYXMgeW91IG9ubHkgd2FudCBvbmUgdHJhbnNhY3Rpb24gaW4gbW9zdCBjYXNlcywgcmF0aGVyIHRoYW4gaGF2aW5nIHRyYW5zYWN0aW9ucyBmaXJlIGFnYWluIGFuZCBhZ2Fpbi4NCg0KSW4gdGhpcyBjYXNlLCB5b3Ugd2lsbCBpbXBsZW1lbnQgdGhlIHNpZ0Nyb3Nzb3ZlcigpIGZ1bmN0aW9uIHNwZWNpZnlpbmcgdGhhdCB0aGUgU01BNTAgY3Jvc3NlcyB1bmRlciB0aGUgU01BMjAwLiBZb3Ugd2lsbCBsYWJlbCB0aGlzIHNpZ25hbCBmaWx0ZXJleGl0LCBhcyBpdCB3aWxsIGV4aXQgeW91ciBwb3NpdGlvbiB3aGVuIHRoZSBtb3ZpbmcgYXZlcmFnZSBmaWx0ZXIgc3RhdGVzIHRoYXQgdGhlIGVudmlyb25tZW50IGlzIG5vdCBjb25kdWNpdmUgZm9yIHRoZSBzdHJhdGVneSB0byBob2xkIGEgcG9zaXRpb24uDQpgYGB7cn0NCiMgQWRkIGEgc2lnQ3Jvc3NvdmVyIHdoaWNoIHNwZWNpZmllcyB0aGF0IHRoZSBTTUE1MCBpcyBsZXNzIHRoYW4gdGhlIFNNQTIwMCBhbmQgbGFiZWwgaXQgZmlsdGVyZXhpdA0KYWRkLnNpZ25hbChzdHJhdGVneS5zdCwgbmFtZSA9ICJzaWdDcm9zc292ZXIiLA0KICAgICAgICAgICANCiAgICAgICAgICAgIyBXZSdyZSBpbnRlcmVzdGVkIGluIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgU01BNTAgYW5kIHRoZSBTTUEyMDANCiAgICAgICAgICAgYXJndW1lbnRzID0gbGlzdChjb2x1bW5zID0gYygiU01BNTAiLCAiU01BMjAwIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgcmVsYXRpb25zaGlwIGlzIHRoYXQgdGhlIFNNQTUwIGNyb3NzZXMgdW5kZXIgdGhlIFNNQTIwMA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0aW9uc2hpcCA9ICJsdCIpLA0KICAgICAgICAgICANCiAgICAgICAgICAgIyBMYWJlbCBpdCBmaWx0ZXJleGl0DQogICAgICAgICAgIGxhYmVsID0gImZpbHRlcmV4aXQiKQ0KYGBgDQojIyBzaWdUaHJlc2hvbGQNCg0KIyMjIFVzaW5nIHNpZ1RocmVzaG9sZCDigJMgdGhyZXNob2xkDQoNCkluIHRoZSBuZXh0IHR3byBleGVyY2lzZXMsIHlvdSB3aWxsIGZvY3VzIG9uIHRoZSBzaWdUaHJlc2hvbGQgc2lnbmFsLiBUaGUgc2lnVGhyZXNob2xkIHNpZ25hbCBpcyBtYWlubHkgdXNlZCBmb3IgY29tcGFyaW5nIGFuIGluZGljYXRvciB0byBhIGZpeGVkIG51bWJlciwgd2hpY2ggdXN1YWxseSBoYXMgYXBwbGljYXRpb25zIGZvciBib3VuZGVkIG9zY2lsbGF0b3JzLCBvciBwZXJoYXBzIHJvbGxpbmcgc3RhdGlzdGljYWwgc2NvcmVzIChmb3IgZXhhbXBsZSwgZm9yIGEgdHJhZGluZyBzdHJhdGVneSB0aGF0IG1pZ2h0IGNob29zZSB0byBnbyBsb25nIHdoZW4gYSByYXRpbyBvZiBtZWFuIHRvIHN0YW5kYXJkIGRldmlhdGlvbiBpcyBhdCAtMiwgb3IgdmljZSB2ZXJzYSkuIFdoZXJlYXMgc2lnQ29tcGFyaXNvbiBhbmQgc2lnQ3Jvc3NvdmVyIGRlYWwgd2l0aCBxdWFudGl0aWVzIHRoYXQgYXJlIHVzdWFsbHkgYmFzZWQgb2ZmIG9mIGFuIGluZGljYXRvciB0aGF0IHRha2VzIHZhbHVlcyBpbiB0aGUgc2FtZSBnZW5lcmFsIGFyZWEgYXMgcHJpY2VzLCBzaWdUaHJlc2hvbGQgZXhpc3RzIHNwZWNpZmljYWxseSB0byBjb3ZlciB0aG9zZSBzaXR1YXRpb25zIG91dHNpZGUgdGhlIGJvdW5kcyBvZiBpbmRpY2F0b3JzIHRoYXQgdGFrZSB2YWx1ZXMgc2ltaWxhciB0byBwcmljZXMuDQoNCkZ1cnRoZXJtb3JlLCB0aGUgc2lnVGhyZXNob2xkKCkgZnVuY3Rpb24gdGFrZXMgdGhlIGNyb3NzIGFyZ3VtZW50LCB3aGljaCBzcGVjaWZpZXMgd2hldGhlciBpdCB3aWxsIGZ1bmN0aW9uIHNpbWlsYXJseSB0byBzaWdDb21wYXJpc29uIChjcm9zcyA9IEZBTFNFKSBvciBzaWdDcm9zc292ZXIgKGNyb3NzID0gVFJVRSksIHJlc3BlY3RpdmVseS4gSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgaW1wbGVtZW50IGEgdmFyaWFudCBvZiBzaWdUaHJlc2hvbGQgdGhhdCBmdW5jdGlvbnMgc2ltaWxhcmx5IHRvIHNpZ0NvbXBhcmlzb24uDQoNCllvdXIgam9iIHdpbGwgYmUgdG8gaW1wbGVtZW50IGEgc2lnVGhyZXNob2xkIHRoYXQgY2hlY2tzIHdoZXRoZXIgb3Igbm90IERWT18yXzEyNiBpcyB1bmRlciAyMC4gVGhpcyBzaWduYWwgd2lsbCBzZXJ2ZSBhcyBvbmUgb2YgdGhlIHR3byBzd2l0Y2hlcyB0aGF0IG5lZWQgdG8gYmUgIm9uIiBpbiBvcmRlciB0byBlbnRlciBpbnRvIGEgbG9uZyBwb3NpdGlvbiBpbiB0aGUgc3RyYXRlZ3kuDQoNCmBgYHtyfQ0KIyBJbXBsZW1lbnQgYSBzaWdUaHJlc2hvbGQgd2hpY2ggc3BlY2lmaWVzIHRoYXQgRFZPXzJfMTI2IG11c3QgYmUgbGVzcyB0aGFuIDIwLCBsYWJlbCBpdCBsb25ndGhyZXNob2xkDQphZGQuc2lnbmFsKHN0cmF0ZWd5LnN0LCBuYW1lID0gInNpZ1RocmVzaG9sZCIsIA0KICAgICAgICAgICANCiAgICAgICAgICAgIyBVc2UgdGhlIERWT18yXzEyNiBjb2x1bW4NCiAgICAgICAgICAgYXJndW1lbnRzID0gbGlzdChjb2x1bW4gPSAiRFZPXzJfMTI2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgdGhyZXNob2xkIGlzIDIwDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyZXNob2xkID0gMjAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgV2Ugd2FudCB0aGUgb3NjaWxsYXRvciB0byBiZSB1bmRlciB0aGlzIHZhbHVlDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVsYXRpb25zaGlwID0gImx0IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBXZSdyZSBpbnRlcmVzdGVkIGluIGV2ZXJ5IGluc3RhbmNlIHRoYXQgdGhlIG9zY2lsbGF0b3IgaXMgbGVzcyB0aGFuIDIwDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY3Jvc3MgPSBGQUxTRSksIA0KICAgICAgICAgICANCiAgICAgICAgICAgIyBMYWJlbCBpdCBsb25ndGhyZXNob2xkDQogICAgICAgICAgIGxhYmVsID0gImxvbmd0aHJlc2hvbGQiKQ0KYGBgDQojIyMgVXNpbmcgc2lnVGhyZXNob2xkKCkg4oCTIGV4aXQNCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgaW1wbGVtZW50IGEgc2lnbmFsIHRvIGV4aXQgYSBwb3NpdGlvbiBnaXZlbiBhIGNlcnRhaW4gdGhyZXNob2xkIHZhbHVlIG9mIHRoZSBEVk8uIFdoaWxlIHRoZXJlIGFyZSB0d28gZW50cnkgc2lnbmFscyB0aGF0IGFyZSBib3RoIG5lY2Vzc2FyeSBidXQgbmVpdGhlciBzdWZmaWNpZW50IG9uIGl0cyBvd24sIHRoZSB0d28gZXhpdCBzaWduYWxzICh0aGlzIG9uZSBhbmQgdGhlIG9uZSB5b3UgaW1wbGVtZW50ZWQgaW4gYW4gZWFybGllciBleGVyY2lzZSkgYXJlIGJvdGggc3VmZmljaWVudCBvbiB0aGVpciBvd24gKGJ1dCBuZWl0aGVyIG5lY2Vzc2FyeSBpbiB0aGUgZXhpc3RlbmNlIG9mIHRoZSBvdGhlcikgdG8gZXhpdCBhIHBvc2l0aW9uLg0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBhZ2FpbiB1c2Ugc2lnVGhyZXNob2xkKCksIHRoaXMgdGltZSBjb3VudGluZyB3aGVuIHRoZSBEVk9fMl8xMjYgY3Jvc3NlcyBhYm92ZSBhIHRocmVzaG9sZCBvZiA4MC4gVG8gbWltaWMgYSBzaWdDcm9zc292ZXIgc2lnbmFsLCBzZXQgY3Jvc3MgZXF1YWwgdG8gVFJVRSBMYWJlbCB0aGlzIHNpZ25hbCB0aHJlc2hvbGRleGl0Lg0KYGBge3J9DQojIEFkZCBhIHNpZ1RocmVzaG9sZCBzaWduYWwgdG8geW91ciBzdHJhdGVneSB0aGF0IHNwZWNpZmllcyB0aGF0IERWT18yXzEyNiBtdXN0IGNyb3NzIGFib3ZlIDgwIGFuZCBsYWJlbCBpdCB0aHJlc2hvbGRleGl0DQphZGQuc2lnbmFsKHN0cmF0ZWd5LnN0LCBuYW1lID0gInNpZ1RocmVzaG9sZCIsIA0KICAgICAgICAgICANCiAgICAgICAgICAgIyBSZWZlcmVuY2UgdGhlIGNvbHVtbiBvZiBEVk9fMl8xMjYNCiAgICAgICAgICAgYXJndW1lbnRzID0gbGlzdChjb2x1bW4gPSAiRFZPXzJfMTI2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBTZXQgYSB0aHJlc2hvbGQgb2YgODANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJlc2hvbGQgPSA4MCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgb3NjaWxsYXRvciBtdXN0IGJlIGdyZWF0ZXIgdGhhbiA4MA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGF0aW9uc2hpcCA9ICJndCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgV2UgYXJlIGludGVyZXN0ZWQgb25seSBpbiB0aGUgY3Jvc3MNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcm9zcyA9IFRSVUUpLCANCiAgICAgICAgICAgDQogICAgICAgICAgICMgTGFiZWwgaXQgdGhyZXNob2xkZXhpdA0KICAgICAgICAgICBsYWJlbCA9ICJ0aHJlc2hvbGRleGl0IikNCmBgYA0KIyMgc2lnRm9ybXVsYQ0KDQojIyMgVXNpbmcgc2lnRm9ybXVsYSgpDQoNClRoZSBsYXN0IHNpZ25hbCBmdW5jdGlvbiBpcyBhIGJpdCBtb3JlIG9wZW4tZW5kZWQuIFRoZSBzaWdGb3JtdWxhKCkgZnVuY3Rpb24gdXNlcyBzdHJpbmcgZXZhbHVhdGlvbiB0byBvZmZlciBpbW1lbnNlIGZsZXhpYmlsaXR5IGluIGNvbWJpbmluZyB2YXJpb3VzIGluZGljYXRvcnMgYW5kIHNpZ25hbHMgeW91IGFscmVhZHkgYWRkZWQgdG8geW91ciBzdHJhdGVneSBpbiBvcmRlciB0byBjcmVhdGUgY29tcG9zaXRlIHNpZ25hbHMuIFdoaWxlIHN1Y2ggY2F0Y2gtYWxsIGZ1bmN0aW9uYWxpdHkgbWF5IHNlZW0gY29tcGxpY2F0ZWQgYXQgZmlyc3QsIHdpdGggcHJvcGVyIHNpZ25hbCBpbXBsZW1lbnRhdGlvbiBhbmQgbGFiZWxpbmcsIGEgc2lnRm9ybXVsYSBzaWduYWwgdHVybnMgb3V0IHRvIGJlIHRoZSBzaW1wbGVzdCBvZiBsb2dpY2FsIHByb2dyYW1taW5nIHN0YXRlbWVudHMgZW5jYXBzdWxhdGVkIGluIHNvbWUgcXVhbnRzdHJhdCBzeW50YWN0aWNhbCBzdHJ1Y3R1cmluZy4NCmBgYHtyfQ0KIyBDcmVhdGUgeW91ciBkYXRhc2V0OiB0ZXN0DQp0ZXN0X2luaXQgPC0gYXBwbHlJbmRpY2F0b3JzKHN0cmF0ZWd5LnN0LCBta3RkYXRhID0gT0hMQyhTUFkpKQ0KdGVzdCA8LSBhcHBseVNpZ25hbHMoc3RyYXRlZ3kgPSBzdHJhdGVneS5zdCwgbWt0ZGF0YSA9IHRlc3RfaW5pdCkNCmBgYA0KIyMjIENvbWJpbmluZyBzaWduYWxzIOKAkyBsb25nZmlsdGVyICYgbG9uZ3RocmVzaG9sZA0KDQp5b3UgY3JlYXRlZCBhIGRhdGFzZXQgdGVzdCBjb250YWluaW5nIGluZm9ybWF0aW9uIGFib3V0IHdoZXRoZXIgbG9uZ2ZpbHRlciBpcyBlcXVhbCB0byAxIEFORCBsb25ndGhyZXNob2xkIGlzIGVxdWFsIHRvIDEuDQoNCk5leHQsIHlvdSdsbCB3YW50IHRvIGNyZWF0ZSBhIHNpZ25hbCB3aGVuIEJPVEggbG9uZ2ZpbHRlciBhbmQgbG9uZ3RocmVzaG9sZCBhcmUgZXF1YWwgdG8gMS4NCkhhdmUgYSBsb29rIGF0IHRlc3Qgb24gT2N0b2JlciA4LCAyMDEzLiBBcmUgbG9uZ2ZpbHRlciBhbmQgbG9uZ3RocmVzaG9sZCBib3RoIGVxdWFsIHRvIDEgb24gdGhhdCBkYXRlPw0KYGBge3J9DQp0ZXN0WyIyMDEzLTEwLTA4Il0NCmBgYA0KYGBge3J9DQpwcmludCgibG9uZ2ZpbHRlciA9IDEsIGxvbmd0aHJlc2hvbGQgPSAxIikNCmBgYA0KIyMjIENvbWJpbmluZyBzaWduYWxzIOKAkyBsb25nZW50cnkNCg0KSW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLCB5b3UgYXBwcm94aW1hdGVkIGEgc2lnRm9ybXVsYSBzaWduYWwgYnkgY29tcGFyaW5nIHRoZSB2YWx1ZSBvZiB0d28gb3RoZXIgc2lnbmFscy4gSW4gdGhpcyBmaW5hbCBleGVyY2lzZSwgeW91IHdpbGwgdGFrZSB0aGlzIG9uZSBzdGVwIGZ1dGhlciBieSB1c2luZyB0aGUgc2lnRm9ybXVsYSgpIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIGEgc2lnRm9ybXVsYSBzaWduYWwuDQoNClRoZSBnb2FsIG9mIHRoaXMgZXhlcmNpc2UgaXMgc2ltcGxlLiBZb3Ugd2FudCB0byBlbnRlciBpbnRvIGEgcG9zaXRpb24gd2hlbiBib3RoIGxvbmdmaWx0ZXIgYW5kIGxvbmd0aHJlc2hvbGQgYmVjb21lIHRydWUgYXQgdGhlIHNhbWUgdGltZS4gVGhlIGlkZWEgaXMgdGhpczogWW91IGRvbid0IHdhbnQgdG8ga2VlcCBlbnRlcmluZyBpbnRvIGEgcG9zaXRpb24gZm9yIGFzIGxvbmcgYXMgY29uZGl0aW9ucyBob2xkIHRydWUsIGJ1dCB5b3UgZG8gd2FudCB0byBob2xkIGEgcG9zaXRpb24gd2hlbiB0aGVyZSdzIGEgcHVsbGJhY2sgaW4gYW4gdXB0cmVuZGluZyBlbnZpcm9ubWVudC4NCg0KV3JpdGluZyBhIHNpZ0Zvcm11bGEgZnVuY3Rpb24gaXMgYXMgc2ltcGxlIGFzIHdyaXRpbmcgdGhlIGFyZ3VtZW50IG9mIGFuICJpZiBzdGF0ZW1lbnQiIGluIGJhc2UgUiBpbnNpZGUgdGhlIGZvcm11bGEoKSBmdW5jdGlvbi4gSW4gdGhpcyBjYXNlLCB5b3Ugd2FudCB0byBjcmVhdGUgYSBzaWduYWwgbGFiZWxlZCBsb25nZW50cnksIHdoaWNoIGlzIHRydWUgd2hlbiBib3RoIGxvbmdmaWx0ZXIgYW5kIGxvbmd0aHJlc2hvbGQgY3Jvc3Mgb3ZlciB0byB0cnVlIGF0IHRoZSBzYW1lIHRpbWUuDQpgYGB7cn0NCiMgQWRkIGEgc2lnRm9ybXVsYSBzaWduYWwgdG8geW91ciBjb2RlIHNwZWNpZnlpbmcgdGhhdCBib3RoIGxvbmdmaWx0ZXIgYW5kIGxvbmd0aHJlc2hvbGQgbXVzdCBiZSBUUlVFLCBsYWJlbCBpdCBsb25nZW50cnkNCmFkZC5zaWduYWwoc3RyYXRlZ3kuc3QsIG5hbWUgPSAic2lnRm9ybXVsYSIsDQogICAgICAgICAgIA0KICAgICAgICAgICAjIFNwZWNpZnkgdGhhdCBsb25nZmlsdGVyIGFuZCBsb25ndGhyZXNob2xkIG11c3QgYmUgVFJVRQ0KICAgICAgICAgICBhcmd1bWVudHMgPSBsaXN0KGZvcm11bGEgPSAibG9uZ2ZpbHRlciAmIGxvbmd0aHJlc2hvbGQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFNwZWNpZnkgdGhhdCBjcm9zcyBtdXN0IGJlIFRSVUUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjcm9zcyA9IFRSVUUpLA0KICAgICAgICAgICANCiAgICAgICAgICAgIyBMYWJlbCBpdCBsb25nZW50cnkNCiAgICAgICAgICAgbGFiZWwgPSAibG9uZ2VudHJ5IikNCmBgYA0KIyBSdWxlcw0KDQojIyBJbnRyb2R1Y3Rpb24gdG8gcnVsZXMNCg0KIyMjIFVzaW5nIGFkZC5ydWxlKCkgdG8gaW1wbGVtZW50IGFuIGV4aXQgcnVsZQ0KDQpXaGlsZSBydWxlcyBpbiBxdWFudHN0cmF0IGNhbiBiZWNvbWUgdmVyeSBjb21wbGV4LCB0aGlzIGNoYXB0ZXIgd2lsbCBmaWxsIGluIG1hbnkgb2YgdGhlIGRldGFpbHMgZm9yIHlvdSB0byBoZWxwIHlvdSBkZXZlbG9wIGFuIHVuZGVyc3RhbmRpbmcgb2YgdGhlIGFjdHVhbCBtZWNoYW5pY3Mgb2YgcnVsZXMuIFJ1bGVzIGFyZSB0aGUgZmluYWwgbWVjaGFuaWMgaW4gdGhlIHRyaW5pdHkgb2YgcXVhbnRzdHJhdCBtZWNoYW5pY3MgLS0gaW5kaWNhdG9ycywgc2lnbmFscywgYW5kIHJ1bGVzLiBSdWxlcyBhcmUgYSB3YXkgZm9yIHlvdSB0byBzcGVjaWZ5IGV4YWN0bHkgaG93IHlvdSB3aWxsIHNoYXBlIHlvdXIgdHJhbnNhY3Rpb24gb25jZSB5b3UgZGVjaWRlIHlvdSB3aXNoIHRvIGV4ZWN1dGUgb24gYSBzaWduYWwuDQoNClRocm91Z2hvdXQgdGhpcyBjaGFwdGVyLCB5b3Ugd2lsbCBjb250aW51ZSB3b3JraW5nIHRoZSBzdHJhdGVneSBkZXZlbG9wZWQgaW4gZWFybGllciBjaGFwdGVycyAoc3RyYXRlZ3kuc3QpLiBHaXZlbiB0aGF0IHRoZXJlIGFyZSB0aHJlZSBydWxlcyB0byB0aGUgc3RyYXRlZ3kgKHR3byBleGl0IHJ1bGVzIGFuZCBvbmUgZW50cnkgcnVsZSksIHRoZXJlIHdpbGwgYmUgYSBoYW5kZnVsIG9mIGV4ZXJjaXNlcyB0byBidWlsZCB1cCBzb21lIGludHVpdGlvbiBvZiB0aGUgbWVjaGFuaWNzIG9mIHJ1bGVzLg0KDQpUaGlzIGV4ZXJjaXNlIHdpbGwgaW50cm9kdWNlIHlvdSB0byB0aGUgYWRkLnJ1bGUoKSBmdW5jdGlvbiwgd2hpY2ggYWxsb3dzIHlvdSB0byBhZGQgY3VzdG9taXplZCBydWxlcyB0byB5b3VyIHN0cmF0ZWd5Lg0KYGBge3J9DQojIEZpbGwgaW4gdGhlIHJ1bGUncyB0eXBlIGFzIGV4aXQNCmFkZC5ydWxlKHN0cmF0ZWd5LnN0LCBuYW1lID0gInJ1bGVTaWduYWwiLCANCiAgICAgICAgIGFyZ3VtZW50cyA9IGxpc3Qoc2lnY29sID0gImZpbHRlcmV4aXQiLCBzaWd2YWwgPSBUUlVFLCBvcmRlcnF0eSA9ICJhbGwiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVydHlwZSA9ICJtYXJrZXQiLCBvcmRlcnNpZGUgPSAibG9uZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZSA9IEZBTFNFLCBwcmVmZXIgPSAiT3BlbiIpLCANCiAgICAgICAgIHR5cGUgPSAiZXhpdCIpDQpgYGANCiMjIyBTcGVjaWZ5aW5nIHNpZ2NvbCBpbiBhZGQucnVsZSgpDQoNCkFsdGhvdWdoIHRoZSBhZGQucnVsZSgpIGNvbW1hbmQgbG9va3MgY29tcGxleCwgZWFjaCBhcmd1bWVudCBpcyBxdWl0ZSBzaW1wbGUuIFRvIHVuZGVyc3RhbmQgdGhpcyBjb21tYW5kLCB5b3Ugd2lsbCBleHBsb3JlIGVhY2ggYXJndW1lbnQgaW5kaXZpZHVhbGx5Lg0KDQpGaXJzdCwgYWRkLnJ1bGUoKSB0YWtlcyB0aGUgYXJndW1lbnQgc2lnY29sLCB3aGljaCBzcGVjaWZpZXMgdGhlIHNpZ25hbCBjb2x1bW4gaW4geW91ciBzdHJhdGVneS4gTGlrZSBzaWduYWxzIGFuZCBpbmRpY2F0b3JzLCBhbGwgcnVsZXMgcmVmZXJlbmNlIGEgY29sdW1uIGFscmVhZHkgcHJlc2VudCBpbiB5b3VyIHN0cmF0ZWd5LiBSdWxlcyByZWxpZXMgb24gc2lnbmFscywgYW5kIG11c3QgdGhlcmVmb3JlIHJlZmVyZW5jZSB0aGUgc2lnbmFsIGNvbHVtbnMgaW4geW91ciBzdHJhdGVneS4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgc3VwcGx5IHRoZSBhZGQucnVsZSgpIGNhbGwgd2l0aCB0aGUgc2lnY29sIHZhbHVlLCB3aGljaCB3aWxsIGJlIHNldCB0byBmaWx0ZXJleGl0ICh0byByZWZlcmVuY2UgdGhlIGZpbHRlcmV4aXQgc2lnbmFsIHlvdSBjcmVhdGVkIGluIHRoZSBwcmV2aW91cyBjaGFwdGVyKS4gU3BlY2lmaWNhbGx5LCB0aGUgZmlsdGVyZXhpdCBzaWduYWwgcmVmZXJzIHRvIHRoZSBjb25kaXRpb24gdGhhdCB0aGUgNTAgZGF5IFNNQSBoYXMgY3Jvc3NlZCB1bmRlciB0aGUgMjAwIGRheSBTTUEgaW4geW91ciBzdHJhdGVneS4gQnkgY3JlYXRpbmcgYSBydWxlIGZvciB0aGlzIHNpZ25hbCwgeW91IHdpbGwgYmUgaW5kaWNhdGluZyB0aGF0IHlvdSB3aXNoIHRvIGV4aXQgaW4gdGhpcyBjb25kaXRpb24sIGFzIHRoZSBtYXJrZXQgZW52aXJvbm1lbnQgaXMgbm8gbG9uZ2VyIGNvbmR1Y2l2ZSB0byB5b3VyIHBvc2l0aW9uLg0KDQogICAgc2lnY29sID0gImZpbHRlcmV4aXQiDQoNCiMjIyBTcGVjaWZ5aW5nIHNpZ3ZhbCBpbiBhZGQucnVsZSgpDQoNCk5vdyB0aGF0IHlvdSd2ZSBzcGVjaWZpZWQgdGhlIGNvbHVtbiBjb250YWluaW5nIHRoZSByZWxldmFudCBzaWduYWwgaW4geW91ciBzdHJhdGVneSwgdGhlIG5leHQgYXJndW1lbnQgdG8gc3BlY2lmeSBpbiBhZGQucnVsZSgpIGlzIHNpZ3ZhbCwgb3IgdGhlIHZhbHVlIHRoYXQgeW91ciBzaWduYWwgc2hvdWxkIHRha2UgdG8gdHJpZ2dlciB0aGUgcnVsZS4NCg0KUmVtZW1iZXIgdGhhdCBhbGwgc2lnbmFsIG91dHB1dHMgYXJlIGVpdGhlciAxcyBvciAwcy4gRWZmZWN0aXZlbHksIGEgc2lnbmFsIGlzIGVpdGhlciAib24iIG9yICJvZmYiIGF0IGFueSBnaXZlbiB0aW1lLiBGb3Igb3VyIHB1cnBvc2VzLCB0aGlzIGlzIGVxdWl2YWxlbnQgdG8gdHdvIHBvc3NpYmxlIGxvZ2ljYWwgdmFsdWVzOiBUUlVFIG9yIEZBTFNFLiBXaGVuIHNwZWNpZnlpbmcgc2lndmFsIGluIHlvdXIgYWRkLnJ1bGUoKSBjb21tYW5kLCB5b3UgbmVlZCB0byBpbmRpY2F0ZSB3aGV0aGVyIHRoZSBydWxlIGlzIHRyaWdnZXJlZCB3aGVuIHRoZSBzaWduYWwgdmFsdWUgaXMgVFJVRSBvciBGQUxTRS4NCg0KVG8gcHJvY2VlZCB3aXRoIHRoZSBuZXcgZXhpdCBydWxlIGluIHlvdXIgc3RyYXRlZ3ksIHlvdSB3aWxsIHdhbnQgdG8gc3BlY2lmeSB0aGF0IGEgdHJhbnNhY3Rpb24gc2hvdWxkIG9jY2N1ciB3aGVuIGZpbHRlcmV4aXQgaXMgZXF1YWwgdG8gVFJVRS4NCg0KICAgIHNpZ3ZhbCA9IFRSVUUNCiAgICANCiAgICANCnNpZ3ZhbCB0ZWxscyB5b3VyIHJ1bGUgd2hpY2ggdmFsdWUgdG8gbG9vayBmb3IgaW4geW91ciBzaWduYWwgaW4gb3JkZXIgdG8gYWN0Lg0KDQojIyBNb3JlIHJ1bGUgbWVjaGFuaWNzDQoNCiMjIyBTcGVjaWZ5aW5nIG9yZGVycXR5IGluIGFkZC5ydWxlKCkNCg0KTm93IHRoYXQgeW91IGhhdmUgYSBncmFzcCBvZiB0aGUgZmlyc3Qgc2V0IG9mIGFyZ3VtZW50cyBpbiB0aGUgYWRkLnJ1bGUoKSBmdW5jdGlvbiwgaXQncyB0aW1lIHRvIG1vdmUgb24gdG8gdGhlIG1vcmUgaW1wb3J0YW50IGFyZ3VtZW50czogdGhlIGFjdHVhbCBvcmRlciBiZWluZyBib3VnaHQgb3Igc29sZCEgVGhlIG9yZGVycXR5IGFyZ3VtZW50IGluIHRoZSBydWxlU2lnbmFsIHNwZWNpZmllcyBleGFjdGx5IGhvdyBtdWNoIG9mIGFuIGFzc2V0IHlvdSB3YW50IHRvIGJ1eSBvciBzZWxsLCBpbiBudW1iZXJzIG9mIHNoYXJlcy4NCg0KSG93ZXZlciwgb25lIHNhbGllbnQgZmVhdHVyZSBvZiB0aGUgZXhpdCBydWxlIHR5cGUgaXMgdGhhdCB5b3UgY2FuIHJlZHVjZSB5b3VyIHBvc2l0aW9uIHRvIHplcm8gaW5zdGFudGx5IHdpdGggdGhlIGFsbCBhcmd1bWVudCAoaGVuY2UsIGV4aXRpbmcpLg0KDQogICAgb3JkZXJxdHkgPSAiYWxsIg0KDQpSZW1lbWJlciB0aGF0IHRoZSBvcmRlcnF0eSBhcmd1bWVudCBjYW4gYWxzbyB0YWtlIG51bWVyaWNhbCB2YWx1ZXMgdG8gaW5kaWNhdGUgdGhlIG51bWJlciBvZiBzaGFyZXMgYmVpbmcgYm91Z2h0IG9yIHNvbGQuDQoNCiMjIyBTcGVjaWZ5aW5nIG9yZGVydHlwZSBpbiBhZGQucnVsZSgpDQoNClRvIHRoaXMgcG9pbnQgeW91J3ZlIHNwZWNpZmllZCB0aGUgc2lnbmFsIGNvbHVtbiwgc2lnbmFsIHZhbHVlLCBhbmQgb3JkZXIgcXVhbnRpdHkgYXNzb2NpYXRlZCB3aXRoIHlvdXIgcnVsZS4gTmV4dCB5b3Ugd2lsbCBzcGVjaWZ5IHRoZSB0eXBlIG9mIG9yZGVyIHlvdSB3aWxsIGV4ZWN1dGUgKG9yZGVydHlwZSkuDQoNCldoaWxlIHRoZXJlIGFyZSBtdWx0aXBsZSB0eXBlcyBvZiBvcmRlcnMgaW4gcXVhbnRzdHJhdCwgZm9yIHRoZSBzY29wZSBvZiB0aGlzIGNvdXJzZSB5b3Ugd2lsbCBzdGljayB0byBtYXJrZXQgb3JkZXJzIChvcmRlcnR5cGUgPSAibWFya2V0IikuIEEgbWFya2V0IG9yZGVyIGlzIGFuIG9yZGVyIHRoYXQgc3RhdGVzIHRoYXQgeW91IHdpbGwgYnV5IG9yIHNlbGwgdGhlIGFzc2V0IGF0IHRoZSBwcmV2YWlsaW5nIHByaWNlLCByZWdhcmRsZXNzIG9mIHRoZSBjb25kaXRpb25zIGluIHRoZSBtYXJrZXQuIEFuIGFsdGVybmF0aXZlIHR5cGUgb2Ygb3JkZXJzIGlzIGEgbGltaXQgb3JkZXIsIHdoaWNoIHNwZWNpZmllcyB0aGF0IHRoZSB0cmFuc2FjdGlvbiB3aWxsIG9ubHkgdGFrZSBwbGFjZSBpZiBjZXJ0YWluIHByaWNlIGNvbmRpdGlvbnMgYXJlIG1ldCAobmFtZWx5LCBpZiB0aGUgcHJpY2UgZmFsbHMgYmVsb3cgYSBjZXJ0YWluIGZ1cnRoZXIgdGhyZXNob2xkIG9uIHRoZSBkYXkgb2YgdGhlIG9yZGVyKS4NCg0KICAgIG9yZGVydHlwZSA9ICJtYXJrZXQiDQogICAgDQpJdCBpcyBpbXBvcnRhbnQgdG8gc3BlY2lmeSBvcmRlcnR5cGUgZm9yIHlvdXIgc3RyYXRlZ3kgdG8gZnVuY3Rpb24gcHJvcGVybHkuDQoNCiMjIyBTcGVjaWZ5aW5nIG9yZGVyc2lkZSBpbiBhZGQucnVsZSgpDQoNClRoZSBuZXh0IGNyaXRpY2FsIGFyZ3VtZW50IHRvIHNwZWNpZnkgaW4geW91ciBvcmRlciBpcyBvcmRlcnNpZGUsIHdoaWNoIGNhbiB0YWtlIHR3byB2YWx1ZXM6IGVpdGhlciBsb25nIG9yIHNob3J0LiBJbiBxdWFudHN0cmF0LCBsb25nIGFuZCBzaG9ydCBzaWRlIHRyYWRlcyBhcmUgc2lsb2VkIG9mZiBzZXBhcmF0ZWx5IHNvIHRoYXQgcXVhbnRzdHJhdCBrbm93cyB3aGV0aGVyIGEgdHJhZGUgaXMgYSBsb25nIHRyYWRlIG9yIGEgc2hvcnQgdHJhZGUuIEEgbG9uZyB0cmFkZSBpcyBvbmUgdGhhdCBwcm9maXRzIGJ5IGJ1eWluZyBhbiBhc3NldCBpbiB0aGUgaG9wZXMgdGhhdCB0aGUgYXNzZXQncyBwcmljZSB3aWxsIHJpc2UuIEEgc2hvcnQgdHJhZGUgaXMgb25lIHRoYXQgc2VsbHMgYW4gYXNzZXQgYmVmb3JlIG93bmluZyBpdCwgaG9waW5nIHRvIGJ1eSBpdCBiYWNrIGxhdGVyIGF0IGEgbG93ZXIgcHJpY2UuDQoNCkZvciB5b3VyIHN0cmF0ZWd5LCB5b3Ugd2lsbCB3YW50IHRvIHRha2Ugb25seSBsb25nIG9yZGVycy4NCg0KICAgIG9yZGVyc2lkZSA9ICJsb25nIg0KDQojIyMgU3BlY2lmeWluZyByZXBsYWNlIGluIGFkZC5ydWxlKCkNCg0KSW4gcXVhbnRzdHJhdCwgdGhlIHJlcGxhY2UgYXJndW1lbnQgc3BlY2lmaWVzIHdoZXRoZXIgb3Igbm90IHRvIGlnbm9yZSBhbGwgb3RoZXIgc2lnbmFscyBvbiB0aGUgc2FtZSBkYXRlIHdoZW4gdGhlIHN0cmF0ZWd5IGFjdHMgdXBvbiBvbmUgc2lnbmFsLiBUaGlzIGlzIGdlbmVyYWxseSBub3QgYSBkZXNpcmVkIHF1YWxpdHkgaW4gYSB3ZWxsLWNyYWZ0ZWQgdHJhZGluZyBzeXN0ZW0uIFRoZXJlZm9yZSwgZm9yIHlvdXIgZXhpdCBydWxlLCB5b3Ugc2hvdWxkIHNldCByZXBsYWNlIHRvIEZBTFNFLg0KDQpGdXJ0aGVybW9yZSwgeW91IHdpbGwgYmUgd29ya2luZyB3aXRoIGEgbmV3IHJ1bGUuIFByZXZpb3VzbHksIHRoZSBleGl0IHJ1bGUgeW91IHdvcmtlZCB3aXRoIHdhcyB3aGVuIHRoZSBtYXJrZXQgZW52aXJvbm1lbnQgd2FzIG5vIGxvbmdlciBjb25kdWNpdmUgdG8gYSB0cmFkZS4gSW4gdGhpcyBjYXNlLCB5b3Ugd2lsbCBiZSB3b3JraW5nIHdpdGggYSBydWxlIHRoYXQgc2VsbHMgd2hlbiB0aGUgRFZPIGhhcyBjcm9zc2VkIGEgY2VydGFpbiB0aHJlc2hvbGQuIEluIHBhcnRpY3VsYXIsIHlvdSB3aWxsIGJlIHdvcmtpbmcgd2l0aCB0aGUgdGhyZXNob2xkZXhpdCBydWxlIG5vdy4NCg0KDQogICAgcmVwbGFjZSA9IEZBTFNFDQoNCiMjIyBTcGVjaWZ5aW5nIHByZWZlciBpbiBhZGQucnVsZSgpDQoNCkxhc3RseSwgb2YgdGhlIGJhc2ljIHJ1bGUgYXJndW1lbnRzLCB0aGVyZSBpcyB0aGUgYXNwZWN0IG9mIHRoZSBwcmVmZXIgYXJndW1lbnQuIEluIHF1YW50c3RyYXQsIG9yZGVycyBoYXZlIGEgIm5leHQtYmFyIiBtZWNoYW5pc20uIFRoYXQgaXMsIGlmIHlvdSB3b3VsZCBnYWluIGEgc2lnbmFsIG9uIFR1ZXNkYXksIHRoZSBlYXJsaWVzdCB0aGF0IGEgcG9zaXRpb24gd291bGQgYWN0dWFsbHkgZnVsZmlsIGl0c2VsZiB3b3VsZCBiZSBvbiB0aGUgV2VkbmVzZGF5IGFmdGVyLiBIb3dldmVyLCB0aGlzIGNhbiBiZSBzb2x2ZWQgYnkgcGxhY2luZyBvcmRlcnMgdG8gZXhlY3V0ZSBvbiB0aGUgbmV4dCBwb3NzaWJsZSBvcGVuaW5nIHByaWNlLCByYXRoZXIgdGhhbiB3YWl0IGZvciBhbiBlbnRpcmUgZGF5IHRvIHBhc3MgYmVmb3JlIGJlaW5nIGFibGUgdG8gYWN0dWFsbHkgcHVyY2hhc2Uvc2VsbCB0aGUgYXNzZXQuDQoNCiAgICBwcmVmZXIgPSAiT3BlbiINCiAgICANClRoZSBwcmVmZXIgYXJndW1lbnQgaXMgdGhlIGZpbmFsIGNyaXRpY2FsIGFyZ3VtZW50IHRvIHNwZWNpZnkgdG8gbWFrZSBzdXJlIHlvdXIgcnVsZSB3b3JrcyBwcm9wZXJseS4NCg0KIyMjIFVzaW5nIGFkZC5ydWxlKCkgdG8gaW1wbGVtZW50IGFuIGVudHJ5IHJ1bGUNCg0KWW91J3ZlIG1hc3RlcmVkIGV2ZXJ5IGVsZW1lbnQgb2YgdGhlIHJ1bGUgYnVpbGRpbmcgcHJvY2VzcyBpbiBxdWFudHN0cmF0LiBXaGlsZSB0aHVzIGZhciB5b3UndmUgYWRkZWQgcnVsZXMgc3RlcC1ieS1zdGVwLCBub3cgaXQncyB0aW1lIHRvIHB1dCBpdCBhbGwgdG9nZXRoZXIgYW5kIHNlZSBob3cgd2VsbCB5b3UndmUgYmVlbiBhYmxlIHRvIGFic29yYiB0aGUgbWF0ZXJpYWwgaW4gdGhpcyBjaGFwdGVyLg0KDQpUaGUgb3Bwb3NpdGUgb2YgYW4gZXhpdCBydWxlIGlzIGFuIGVudGVyIHJ1bGUuIE9uIGVudGVyIHJ1bGVzLCBvcmRlcnF0eSBjYW5ub3QgYmUgc2V0IHRvICJhbGwiIGJlY2F1c2UgdGhlcmUgaXMgbm8gaW5pdGlhbCBwb3NpdGlvbiBvbiB3aGljaCB0byBhY3QuIEluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIGltcGxlbWVudCBhbiBlbnRlciBydWxlIHRoYXQgcmVmZXJlbmNlcyB0aGUgbG9uZ2VudHJ5IHNpZ25hbCBpbiB5b3VyIHN0cmF0ZWd5IGFuZCB3aWxsIGJ1eSBvbmUgc2hhcmUgb2YgYW4gYXNzZXQuDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYW4gZW50cnkgcnVsZSBvZiAxIHNoYXJlIHdoZW4gYWxsIGNvbmRpdGlvbnMgbGluZSB1cCB0byBlbnRlciBpbnRvIGEgcG9zaXRpb24NCmFkZC5ydWxlKHN0cmF0ZWd5LnN0LCBuYW1lID0gInJ1bGVTaWduYWwiLCANCiAgICAgICAgIA0KICAgICAgICAgIyBVc2UgdGhlIGxvbmdlbnRyeSBjb2x1bW4gYXMgdGhlIHNpZ2NvbA0KICAgICAgICAgYXJndW1lbnRzPWxpc3Qoc2lnY29sID0gImxvbmdlbnRyeSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAjIFNldCBzaWd2YWwgdG8gVFJVRQ0KICAgICAgICAgICAgICAgICAgICAgICAgc2lndmFsID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICMgU2V0IG9yZGVycXR5IHRvIDENCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVycXR5ID0gMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgIyBVc2UgYSBtYXJrZXQgdHlwZSBvZiBvcmRlcg0KICAgICAgICAgICAgICAgICAgICAgICAgb3JkZXJ0eXBlID0gIm1hcmtldCIsDQogICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICMgVGFrZSB0aGUgbG9uZyBvcmRlcnNpZGUNCiAgICAgICAgICAgICAgICAgICAgICAgIG9yZGVyc2lkZSA9ICJsb25nIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgIyBEbyBub3QgcmVwbGFjZSBvdGhlciBzaWduYWxzDQogICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgICAjIEJ1eSBhdCB0aGUgbmV4dCBkYXkncyBvcGVuaW5nIHByaWNlDQogICAgICAgICAgICAgICAgICAgICAgICBwcmVmZXIgPSAiT3BlbiIpLA0KICAgICAgICAgDQogICAgICAgICAjIFRoaXMgaXMgYW4gZW50ZXIgdHlwZSBydWxlLCBub3QgYW4gZXhpdA0KICAgICAgICAgdHlwZSA9ICJlbnRlciIpDQpgYGANCiMjICBPcmRlciBzaXppbmcgZnVuY3Rpb25zDQoNCiMjIyBJbXBsZW1lbnRpbmcgYSBydWxlIHdpdGggYW4gb3JkZXIgc2l6aW5nIGZ1bmN0aW9uDQoNCkluIHF1YW50c3RyYXQsIHRoZSBhbW91bnQgb2YgYW4gYXNzZXQgdHJhbnNhY3RlZCBtYXkgbm90IGFsd2F5cyBiZSBhIGZpeGVkIHF1YW50aXR5IGluIHJlZ2FyZHMgdG8gdGhlIGFjdHVhbCBzaGFyZXMuIFRoZSBjb25zdHJ1Y3RzIHRoYXQgYWxsb3cgcXVhbnRzdHJhdCB0byB2YXJ5IHRoZSBhbW91bnQgb2Ygc2hhcmVzIGJvdWdodCBvciBzb2xkIGFyZSBjYWxsZWQgb3JkZXIgc2l6aW5nIGZ1bmN0aW9ucy4NClVzaW5nIGEgcHJlLWNvZGVkIG9yZGVyIHNpemluZyBmdW5jdGlvbiBpcyBzdHJhaWdodGZvcndhcmQuIFRoZSBmaXJzdCB0aGluZyB0byBrbm93IGlzIHRoYXQgd2hlbiB1c2luZyBhbiBvcmRlciBzaXppbmcgZnVuY3Rpb24sIHRoZSBvcmRlcnF0eSBhcmd1bWVudCBpcyBubyBsb25nZXIgcmVsZXZhbnQsIGFzIHRoZSBvcmRlciBxdWFudGl0eSBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBvcmRlciBzaXppbmcgZnVuY3Rpb24uIENhbGxpbmcgYW4gb3JkZXIgc2l6aW5nIGZ1bmN0aW9uIHdpdGggeW91ciBhZGQucnVsZSgpIGNhbGwgaXMgZmFpcmx5IHN0cmFpZ2h0Zm9yd2FyZC4gVGhlIGlucHV0cyBmb3IgdGhlIG9yZGVyIHNpemluZyBmdW5jdGlvbiBhcmUgbWl4ZWQgaW4gd2l0aCB0aGUgcmVzdCBvZiB0aGUgaW5wdXRzIGluc2lkZSB0aGUgYXJndW1lbnRzIHRoYXQgeW91IGhhdmUgYmVlbiB3b3JraW5nIHdpdGggdGhyb3VnaG91dCB0aGlzIGNoYXB0ZXIuDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCB1c2UgdGhlIG9zRlVOIGFyZ3VtZW50IHRvIHNwZWNpZnkgYSBmdW5jdGlvbiBjYWxsZWQgb3NNYXhEb2xsYXIuIFRoaXMgaXMgbm90IHBhc3NlZCBpbiBhcyBhIHN0cmluZywgYnV0IHJhdGhlciBhcyBhbiBvYmplY3QuIFRoZSBvbmx5IGRpZmZlcmVuY2UgaXMgdGhhdCB0aGUgbmFtZSBvZiB0aGUgb3JkZXIgc2l6aW5nIGZ1bmN0aW9uIGlzIG5vdCBlbmNhc2VkIGluIHF1b3Rlcy4NCg0KVGhlIGFkZGl0aW9uYWwgYXJndW1lbnRzIHRvIHRoaXMgZnVuY3Rpb24gYXJlIHRyYWRlU2l6ZSBhbmQgbWF4U2l6ZSwgYm90aCBvZiB3aGljaCBzaG91bGQgdGFrZSB0cmFkZXNpemUsIHdoaWNoIHlvdSBkZWZpbmVkIHNldmVyYWwgY2hhcHRlcnMgZWFybGllci4NCmBgYHtyfQ0Kb3NNYXhEb2xsYXIgPC0gZnVuY3Rpb24gKGRhdGEsIHRpbWVzdGFtcCwgb3JkZXJxdHksIG9yZGVydHlwZSwgb3JkZXJzaWRlLCBwb3J0Zm9saW8sIA0KICAgIHN5bWJvbCwgcHJlZmVyID0gIk9wZW4iLCB0cmFkZVNpemUsIG1heFNpemUsIGludGVnZXJRdHkgPSBUUlVFLCANCiAgICAuLi4pIA0Kew0KICAgIHBvcyA8LSBnZXRQb3NRdHkocG9ydGZvbGlvLCBzeW1ib2wsIHRpbWVzdGFtcCkNCiAgICBpZiAocHJlZmVyID09ICJDbG9zZSIpIHsNCiAgICAgICAgcHJpY2UgPC0gYXMubnVtZXJpYyhDbChta3RkYXRhW3RpbWVzdGFtcCwgXSkpDQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICBwcmljZSA8LSBhcy5udW1lcmljKE9wKG1rdGRhdGFbdGltZXN0YW1wLCBdKSkNCiAgICB9DQogICAgcG9zVmFsIDwtIHBvcyAqIHByaWNlDQogICAgaWYgKG9yZGVyc2lkZSA9PSAic2hvcnQiKSB7DQogICAgICAgIGRvbGxhcnNUb1RyYW5zYWN0IDwtIG1heCh0cmFkZVNpemUsIG1heFNpemUgLSBwb3NWYWwpDQogICAgICAgIGlmIChkb2xsYXJzVG9UcmFuc2FjdCA+IDApIHsNCiAgICAgICAgICAgIGRvbGxhcnNUb1RyYW5zYWN0ID0gMA0KICAgICAgICB9DQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICBkb2xsYXJzVG9UcmFuc2FjdCA8LSBtaW4odHJhZGVTaXplLCBtYXhTaXplIC0gcG9zVmFsKQ0KICAgICAgICBpZiAoZG9sbGFyc1RvVHJhbnNhY3QgPCAwKSB7DQogICAgICAgICAgICBkb2xsYXJzVG9UcmFuc2FjdCA9IDANCiAgICAgICAgfQ0KICAgIH0NCiAgICBxdHkgPC0gZG9sbGFyc1RvVHJhbnNhY3QvcHJpY2UNCiAgICBpZiAoaW50ZWdlclF0eSkgew0KICAgICAgICBxdHkgPC0gdHJ1bmMocXR5KQ0KICAgIH0NCiAgICByZXR1cm4ocXR5KQ0KfQ0KYGBgDQpgYGB7cn0NCiMgQWRkIGEgcnVsZSB0aGF0IHVzZXMgYW4gb3NGVU4gdG8gc2l6ZSBhbiBlbnRyeSBwb3NpdGlvbg0KYWRkLnJ1bGUoc3RyYXRlZ3kgPSBzdHJhdGVneS5zdCwgbmFtZSA9ICJydWxlU2lnbmFsIiwNCiAgICAgICAgIGFyZ3VtZW50cyA9IGxpc3Qoc2lnY29sID0gImxvbmdlbnRyeSIsIHNpZ3ZhbCA9IFRSVUUsIG9yZGVydHlwZSA9ICJtYXJrZXQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBvcmRlcnNpZGUgPSAibG9uZyIsIHJlcGxhY2UgPSBGQUxTRSwgcHJlZmVyID0gIk9wZW4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBVc2UgdGhlIG9zRlVOIGNhbGxlZCBvc01heERvbGxhcg0KICAgICAgICAgICAgICAgICAgICAgICAgICBvc0ZVTiA9IG9zTWF4RG9sbGFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgdHJhZGVTaXplIGFyZ3VtZW50IHNob3VsZCBiZSBlcXVhbCB0byB0cmFkZXNpemUgKGRlZmluZWQgZWFybGllcikNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhZGVTaXplID0gdHJhZGVzaXplLA0KICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIyBUaGUgbWF4U2l6ZSBhcmd1bWVudCBzaG91bGQgYmUgZXF1YWwgdG8gdHJhZGVzaXplIGFzIHdlbGwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4U2l6ZSA9IHRyYWRlc2l6ZSksDQogICAgICAgICB0eXBlID0gImVudGVyIikNCmBgYA0KSW1wbGVtZW50aW5nIGEgcnVsZSB3aXRoIGFuIG9yZGVyIHNpemUgZnVuY3Rpb24gYWxsb3dzIG11Y2ggbW9yZSBmbGV4aWJpbGl0eSB0aGFuIGEgc3RhbmRhcmQgc2V0IHJ1bGUuDQoNCiMgQW5hbHl6aW5nIHJlc3VsdHMNCg0KIyMgQW5hbHl6aW5nIHlvdXIgc3RyYXRlZ3kNCg0KIyMjIFJ1bm5pbmcgeW91ciBzdHJhdGVneQ0KDQpUbyByZXZpZXcsIHlvdXIgc3RyYXRlZ3kgdXNlcyB0aHJlZSBzZXBhcmF0ZSBpbmRpY2F0b3JzIGFuZCBmaXZlIHNlcGFyYXRlIHNpZ25hbHMuIFRoZSBzdHJhdGVneSByZXF1aXJlcyBib3RoIHRoZSB0aHJlc2hvbGQgb2YgdGhlIERWT18yXzEyNiBpbmRpY2F0b3IgdG8gYmUgdW5kZXIgMjAgYW5kIHRoZSBTTUE1MCB0byBiZSBncmVhdGVyIHRoYW4gdGhlIFNNQTIwMC4gVGhlIHN0cmF0ZWd5IHNlbGxzIHdoZW4gdGhlIERWT18yXzEyNiBjcm9zc2VzIGFib3ZlIDgwLCBvciB0aGUgU01BNTAgY3Jvc3NlcyB1bmRlciB0aGUgU01BMjAwLg0KDQpGb3IgdGhpcyBzdHJhdGVneSB0byB3b3JrIHByb3Blcmx5LCB5b3Ugc3BlY2lmaWVkIGZpdmUgc2VwYXJhdGUgc2lnbmFsczoNCg0KMS4Jc2lnQ29tcGFyaXNvbiBmb3IgU01BNTAgYmVpbmcgZ3JlYXRlciB0aGFuIFNNQTIwMDsNCjIuCXNpZ1RocmVzaG9sZCB3aXRoIGNyb3NzIHNldCB0byBGQUxTRSBmb3IgRFZPXzJfMTI2IGxlc3MgdGhhbiAyMDsNCjMuCXNpZ0Zvcm11bGEgdG8gdGllIHRoZW0gdG9nZXRoZXIgYW5kIHNldCBjcm9zcyB0byBUUlVFOw0KNC4Jc2lnQ3Jvc3NvdmVyIHdpdGggU01BNTAgbGVzcyB0aGFuIFNNQTIwMDsgYW5kDQo1LglzaWdUaHJlc2hvbGQgd2l0aCBjcm9zcyBzZXQgdG8gVFJVRSBmb3IgRFZPXzJfMTI2IGdyZWF0ZXIgdGhhbiA4MC4NCg0KVGhlIHN0cmF0ZWd5IGludmVzdHMgJDEwMCwwMDAgKHlvdXIgaW5pdGVxKSBpbnRvIGVhY2ggdHJhZGUsIGFuZCBtYXkgaGF2ZSBzb21lIHNtYWxsIGRvbGxhciBjb3N0IGF2ZXJhZ2luZyBpZiB0aGUgRFZPXzJfMTI2IG9zY2lsbGF0ZXMgYXJvdW5kIDIwICh0aG91Z2ggdGhlIGVmZmVjdCBpcyBtb3N0bHkgbmVnbGlnaWJsZSBjb21wYXJlZCB0byB0aGUgaW5pdGlhbCBhbGxvY2F0aW9uKS4NCg0KYGBge3J9DQojIFVzZSBhcHBseVN0cmF0ZWd5KCkgdG8gYXBwbHkgeW91ciBzdHJhdGVneS4gU2F2ZSB0aGlzIHRvIG91dA0Kb3V0IDwtIGFwcGx5U3RyYXRlZ3koc3RyYXRlZ3kgPSBzdHJhdGVneS5zdCwgcG9ydGZvbGlvcyA9IHBvcnRmb2xpby5zdCkNCg0KIyBVcGRhdGUgeW91ciBwb3J0Zm9saW8gKHBvcnRmb2xpby5zdCkNCnVwZGF0ZVBvcnRmKHBvcnRmb2xpby5zdCkNCmRhdGVyYW5nZSA8LSB0aW1lKGdldFBvcnRmb2xpbyhwb3J0Zm9saW8uc3QpJHN1bW1hcnkpWy0xXQ0KDQojIFVwZGF0ZSB5b3VyIGFjY291bnQgKGFjY291bnQuc3QpDQp1cGRhdGVBY2N0KGFjY291bnQuc3QsIGRhdGVyYW5nZSkNCnVwZGF0ZUVuZEVxKGFjY291bnQuc3QpDQpgYGANCllvdSBhcmUgb24geW91ciB3YXkgdG8gc2VlaW5nIHRoZSByZXN1bHRzIG9mIHlvdXIgc3RyYXRlZ3kuIFRoZSBkYXRlIG9mIHRoZSBsYXN0IHRyYWRlIHdhcyAyMDE1LTEyLTIzDQoNCiMjIyBQcm9maXQgZmFjdG9yDQoNCk9uZSBvZiB0aGUgbW9zdCB2aXRhbCBzdGF0aXN0aWNzIG9mIGFueSBzeXN0ZW1hdGljIHRyYWRpbmcgc3RyYXRlZ3kgaXMgdGhlIHByb2ZpdCBmYWN0b3IuIFRoZSBwcm9maXQgZmFjdG9yIGlzIGhvdyBtYW55IGRvbGxhcnMgeW91IG1ha2UgZm9yIGVhY2ggZG9sbGFyIHlvdSBsb3NlLiBBIHByb2ZpdCBmYWN0b3IgYWJvdmUgMSBtZWFucyB5b3VyIHN0cmF0ZWd5IGlzIHByb2ZpdGFibGUuIEEgcHJvZml0IGZhY3RvciBiZWxvdyAxIG1lYW5zIHlvdSBzaG91bGQgaGVhZCBiYWNrIHRvIHRoZSBkcmF3aW5nIGJvYXJkLg0KDQpJbiB0aGlzIGV4ZXJjaXNlLCB5b3Ugd2lsbCBleHBsb3JlIHRoZSBwcm9maXQgZmFjdG9yIGluIHlvdXIgc3RyYXRlZ3kgYnkgY3JlYXRpbmcgYW4gb2JqZWN0IGNhbGxlZCB0c3RhdHMgdGhhdCBkaXNwbGF5cyB0aGUgdHJhZGUgc3RhdGlzdGljcyBmb3IgeW91ciBzeXN0ZW0uIEluIGdlbmVyYWwsIHRyYWRlIHN0YXRpc3RpY3MgYXJlIGdlbmVyYXRlZCBieSB1c2luZyB0aGUgdHJhZGVTdGF0cygpIGNvbW1hbmQuDQpgYGB7cn0NCiMgR2V0IHRoZSB0cmFkZVN0YXRzIGZvciB5b3VyIHBvcnRmb2xpbw0KdHN0YXRzIDwtIHRyYWRlU3RhdHMoUG9ydGZvbGlvcyA9IHBvcnRmb2xpby5zdCkNCg0KIyBQcmludCB0aGUgcHJvZml0IGZhY3Rvcg0KdHN0YXRzJFByb2ZpdC5GYWN0b3INCmBgYA0KVHJhZGUgc3RhdGlzdGljcyBzdWNoIGFzIHRoZSBwcm9maXQgZmFjdG9yIGFyZSBhIHZhbHVhYmxlIGNvbXBvbmVudCBvZiBhc3Nlc3NpbmcgdGhlIGVmZmVjdGl2ZW5lc3Mgb2YgeW91ciBzdHJhdGVneS4NCg0KIyMjIFBlcmNlbnQgcG9zaXRpdmUNCg0KV2hpbGUgcHJvZml0IGZhY3RvciBpcyBvbmUgaW1wb3J0YW50IHN0YXRpc3RpYywgaXQgbWF5IGJlIGhlYXZpbHkgaW5mbHVlbmNlZCBieSBvbmx5IGEgZmV3IGdvb2QgdHJhZGVzLiBUaGUgcGVyY2VudCBwb3NpdGl2ZSBzdGF0aXN0aWMgbGV0cyB5b3Uga25vdyBob3cgbWFueSBvZiB5b3VyIHRyYWRlcyB3ZXJlIHdpbm5lcnMuIEEgdHJhZGluZyBzeXN0ZW0gYmFzZWQgb24gb3NjaWxsYXRpb24gdHJhZGluZyAoc3VjaCBhcyB5b3VycyEpIHdpbGwgbGlrZWx5IGhhdmUgYSBoaWdoIHBlcmNlbnRhZ2Ugb2Ygd2lubmVycy4gVGhpcyBpcyBjZXJ0YWlubHkgYSBzdGF0aXN0aWMgeW91IHNob3VsZCBsb29rIGZvciBpbiB5b3VyIG93biB0cmFkZSBzdGF0aXN0aWNzLg0KDQp0c3RhdHMkUGVyY2VudC5Qb3NpdGl2ZQ0KVGhpcyBwZXJjZW50IHBvc2l0aXZlIHN0YXRpc3RpYyBtZWFucyB0aGF0IGFwcHJveGltYXRlbHkgNzElIG9mIHlvdXIgdHJhZGVzIHJldHVybmVkIGEgcG9zaXRpdmUgcmVzdWx0LiBUaGF0J3MgYSBncmVhdCBzdGFydCENCg0KIyMgVXNpbmcgY2hhcnQuUG9zbigpDQoNCiMjIyBVc2luZyBjaGFydC5Qb3NuKCkNCg0KT25lIG9mIHRoZSBtb3N0IGVubGlnaHRlbmluZyB0aGluZ3MgYWJvdXQgYSB0cmFkaW5nIHN5c3RlbSBpcyBleHBsb3Jpbmcgd2hhdCBwb3NpdGlvbnMgaXQgdG9vayBvdmVyIHRoZSBjb3Vyc2Ugb2YgdGhlIHRyYWRpbmcgc2ltdWxhdGlvbiwgYXMgd2VsbCBhcyB3aGVuIGl0IGhhZCBpdHMgcHJvZml0cyBhbmQgZHJhd2Rvd25zLiBMb29raW5nIGF0IGEgcGljdHVyZSBvZiB0aGUgcGVyZm9ybWFuY2UgY2FuIGRlbGl2ZXIgYSBncmVhdCBkZWFsIG9mIGluc2lnaHQgaW4gdGVybXMgb2YgcmVmaW5pbmcgc2ltaWxhciB0cmFkaW5nIHN5c3RlbXMgaW4gdGhlIGZ1dHVyZS4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgdXNlIHRoZSBjaGFydC5Qb3NuKCkgZnVuY3Rpb24uIFRoaXMgZ2VuZXJhdGVzIGEgY3Jpc3AgYW5kIGluZm9ybWF0aXZlIHZpc3VhbGl6YXRpb24gb2YgdGhlIHBlcmZvcm1hbmNlIG9mIHlvdXIgdHJhZGluZyBzeXN0ZW0gb3ZlciB0aGUgY291cnNlIG9mIHRoZSBzaW11bGF0aW9uLg0KYGBge3J9DQojIFVzZSBjaGFydC5Qb3NuIHRvIHZpZXcgeW91ciBzeXN0ZW0ncyBwZXJmb3JtYW5jZSBvbiBTUFkNCmNoYXJ0LlBvc24oUG9ydGZvbGlvID0gcG9ydGZvbGlvLnN0LCBTeW1ib2wgPSAiU1BZIikNCmBgYA0KIyMjIEFkZGluZyBhbiBpbmRpY2F0b3IgdG8gYSBjaGFydC5Qb3NuKCkgY2hhcnQNCg0KT25lIG9mIHRoZSBtb3JlIGludGVyZXN0aW5nIHRoaW5ncyB5b3UgY2FuIGRvIHdpdGggdGhlIGNoYXJ0LlBvc24oKSBmdW5jdGlvbiBpcyB0byBzdXBlcmltcG9zZSBpbmRpY2F0b3JzIG9uIHRvcCBvZiBpdC4gVGhpcyBjYW4gaGVscCBzaG93IHdoYXQgdGhlIHN0cmF0ZWd5IGhhcyBhY3R1YWxseSBiZWVuIGRvaW5nIGFuZCB3aHkuIEhvd2V2ZXIsIGluIG9yZGVyIHRvIGRvIHRoaXMsIHlvdSB3aWxsIG5lZWQgdG8gcmVjYWxjdWxhdGUgdGhlIGluZGljYXRvcnMgb3V0c2lkZSB0aGUgc2NvcGUgb2YgeW91ciBzdHJhdGVneS4gT25jZSB0aGlzIGlzIGRvbmUsIHlvdSBzaW1wbHkgYWRkIHRoZW0gdG8gdGhlIGNoYXJ0LlBvc24gcGxvdC4NCg0KSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgYWRkIHRoZSB0aHJlZSBpbmRpY2F0b3JzIGZyb20geW91ciBzdHJhdGVneSB0byB0aGUgY2hhcnQuUG9zbiBwbG90IHlvdSBqdXN0IGNyZWF0ZWQuIFRoZSB0d28gbW92aW5nIGF2ZXJhZ2VzIChTTUE1MCBhbmQgU01BMjAwKSB3aWxsIGJlIHN1cGVyaW1wb3NlZCBvbiB0aGUgcHJpY2Ugc2VyaWVzLCB3aGlsZSB0aGUgRFZPXzJfMTI2IHdpbGwgaGF2ZSBpdHMgb3duIHdpbmRvdy4NCmBgYHtyfQ0KIyBDb21wdXRlIHRoZSBTTUE1MA0Kc21hNTAgPC0gU01BKHggPSBDbChTUFkpLCBuID0gNTApDQoNCiMgQ29tcHV0ZSB0aGUgU01BMjAwDQpzbWEyMDAgPC0gU01BKHggPSBDbChTUFkpLCBuID0gMjAwKQ0KDQojIENvbXB1dGUgdGhlIERWT18yXzEyNiB3aXRoIGFuIG5hdmcgb2YgMiBhbmQgYSBwZXJjZW50bG9va2JhY2sgb2YgMTI2DQpkdm8gPC0gRFZPKEhMQyA9IEhMQyhTUFkpLCBuYXZnID0gMiwgcGVyY2VudGxvb2tiYWNrID0gMTI2KQ0KDQojIFJlY3JlYXRlIHRoZSBjaGFydC5Qb3NuIG9mIHRoZSBzdHJhdGVneSBmcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZQ0KY2hhcnQuUG9zbihQb3J0Zm9saW8gPSBwb3J0Zm9saW8uc3QsIFN5bWJvbCA9ICJTUFkiKQ0KDQojIE92ZXJsYXkgdGhlIFNNQTUwIG9uIHlvdXIgcGxvdCBhcyBhIGJsdWUgbGluZQ0KYWRkX1RBKHNtYTUwLCBvbiA9IDEsIGNvbCA9ICJibHVlIikNCg0KIyBPdmVybGF5IHRoZSBTTUEyMDAgb24geW91ciBwbG90IGFzIGEgcmVkIGxpbmUNCmFkZF9UQShzbWEyMDAsIG9uID0gMSwgY29sID0gInJlZCIpDQoNCiMgQWRkIHRoZSBEVk9fMl8xMjYgdG8gdGhlIHBsb3QgaW4gYSBuZXcgd2luZG93DQphZGRfVEEoZHZvLCBvbiA9IDIsIGNvbCA9ICJyZWQiKQ0KDQpgYGANClRoZSBwbG90IG1heSBsb29rIGEgYml0IGNvbXBsaWNhdGVkLCBidXQgb25seSBiZWNhdXNlIGl0IGNvbnRhaW5zIHNvIG11Y2ggdml0YWwgaW5mb3JtYXRpb24gYWJvdXQgeW91ciBwb3J0Zm9saW8gcGVyZm9ybWFuY2UuDQoNCiMjIEFkZGl0aW9uYWwgYW5hbHl0aWNzDQoNCiMjIyBDYXNoIFNoYXJwZSByYXRpbw0KDQpXaGVuIHdvcmtpbmcgd2l0aCBjYXNoIHByb2ZpdCBhbmQgbG9zcyBzdGF0aXN0aWNzLCBxdWFudHN0cmF0IG9mZmVycyBhIHdheSB0byBjb21wdXRlIGEgU2hhcnBlIHJhdGlvIG5vdCBqdXN0IGZyb20gcmV0dXJucywgYnV0IGZyb20gdGhlIGFjdHVhbCBwcm9maXQgYW5kIGxvc3Mgc3RhdGlzdGljcyB0aGVtc2VsdmVzLiBBIFNoYXJwZSByYXRpbyBpcyBhIG1ldHJpYyB0aGF0IGNvbXBhcmVzIHRoZSBhdmVyYWdlIHJld2FyZCB0byB0aGUgYXZlcmFnZSByaXNrIHRha2VuLiBHZW5lcmFsbHksIGEgU2hhcnBlIHJhdGlvIGFib3ZlIDEgaXMgYSBtYXJrZXIgb2YgYSBzdHJvbmcgc3RyYXRlZ3kuDQoNCkluIHRoaXMgZXhlcmNpc2UsIHlvdSB3aWxsIHNlZSB0aGF0IGJlY2F1c2Ugb2YgdHJhZGluZyBQJkwgKHByb2ZpdCBhbmQgbG9zcyksIG9uZSBjYW4gY29tcHV0ZSBhIFNoYXJwZSByYXRpbyBiYXNlZCBvbiB0aGVzZSBtZXRyaWNzLiBUaGUgY29kZSBiZWxvdyBjYW4gYmUgdXNlZCB0byBjb21wdXRlIHRoZSBTaGFycGUgcmF0aW8gYmFzZWQgb2ZmIG9mIFAmTC4NCg0KYGBge3J9DQpwb3J0cGwgPC0gLmJsb3R0ZXIkcG9ydGZvbGlvLmZpcnN0c3RyYXQkc3VtbWFyeSROZXQuVHJhZGluZy5QTA0KU2hhcnBlUmF0aW8uYW5udWFsaXplZChwb3J0cGwsIGdlb21ldHJpYz1GQUxTRSkNCmBgYA0KUmVtZW1iZXIgdGhhdCBhIFNoYXJwZSByYXRpbyBhYm92ZSAxIGlzIGluZGljYXRpdmUgb2YgYSBzdHJvbmcgc3RyYXRlZ3kuIFRoZSBTaGFycGUgcmF0aW8gaWRlbnRpZmllZCBoZXJlIGlzIGEgYml0IGxvdy4NCg0KIyMjIFJldHVybnMgU2hhcnBlIHJhdGlvIGluIHF1YW50c3RyYXQNCg0KT25lIG9mIHRoZSBtYWluIHJlYXNvbnMgdG8gaW5jbHVkZSBhbiBpbml0aWFsIGVxdWl0eSAoaW4gdGhpcyBjYXNlLCBpbml0ZXEsIHdoaWNoIGlzIHNldCB0byAxMDAsMDAwKSBpbiB5b3VyIHN0cmF0ZWd5IGlzIHRvIGJlIGFibGUgdG8gd29yayB3aXRoIHJldHVybnMsIHdoaWNoIGFyZSBiYXNlZCBvZmYgb2YgeW91ciBwcm9maXQgYW5kIGxvc3Mgb3ZlciB5b3VyIGluaXRpYWwgZXF1aXR5Lg0KDQpXaGlsZSB5b3UganVzdCBjb21wdXRlZCBhIGNhc2ggU2hhcnBlIHJhdGlvIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZSwgeW91IHdpbGwgc2VlIGluIHRoaXMgZXhlcmNpc2UgdGhhdCBxdWFudHN0cmF0IGNhbiBhbHNvIGNvbXB1dGUgdGhlIHN0YW5kYXJkIHJldHVybnMtYmFzZWQgU2hhcnBlIHJhdGlvIGFzIHdlbGwuDQpgYGB7cn0NCiMgR2V0IGluc3RydW1lbnQgcmV0dXJucw0KaW5zdHJldHMgPC0gUG9ydGZSZXR1cm5zKHBvcnRmb2xpby5zdCkNCg0KIyBDb21wdXRlIFNoYXJwZSByYXRpbyBmcm9tIHJldHVybnMNClNoYXJwZVJhdGlvLmFubnVhbGl6ZWQoaW5zdHJldHMsIGdlb21ldHJpYyA9IEZBTFNFKQ0KYGBgDQoNCg==