pacman::p_load(tidyverse,tidyquant,PortfolioAnalytics,quantmod,PerformanceAnalytics,zoo,
               plotly,timekit,ggthemes,timetk)

Portfolio optimization is the process of selecting proportions of various assets to include in a portfolio, in such a way as to make the portfolio better than any other according to some criterion. The criterion will combine, directly or indirectly, considerations of the expected value of the portfolio’s rate of return as well as of the return’s dispersion and possibly other measures of financial risk. The objective of porrtfolio optimization is to maximize a measure of gain per unit measure of risk and minimize a measure of risk.

Modern portfolio theory was introduced by Harry Markowitz in 1952. It assumes that in general, an investor wants to maximize a portfolio’s expected return contingent on any given amount of risk, with risk measured by the standard deviation of the portfolio’s rate of return. For portfolios that meet this criterion, known as efficient portfolios, achieving a higher expected return requires taking on more risk, so investors are faced with a trade-off between risk and expected return. This risk-expected return relationship of efficient portfolios is graphically represented by a curve known as the efficient frontier. All efficient portfolios, each represented by a point on the efficient frontier, are well-diversified. For the specific formulas for efficient portfolios,[3] see Portfolio separation in mean-variance analysis. While ignoring higher moments can lead to significant over-investment in risky securities, especially when volatility is high[4], the development of portfolios for non-Gaussian economies is mathematically challenging.

Some of the best performing stocks year to date(November,2017) include Dynavax Tech(DVAX). Most of the best performing stocks were all from the Biotech space. Dynavax Tech (NASDAQ:DVAX) ranks first with a YTD gain of 444%. Straight Path (NYSEMKT:STRP) ranks second at +432.79%. Sangamo Therapeutics (NASDAQ:SGMO), Calithera Biosciences (NASDAQ:CALA), and Pieris Pharma (NASDAQ:PIRS) round out the top five. Eight of the top nine are Biotech stocks, and then Weight Watchers (NYSE:WTW) ranks tenth with a gain of 280%.

# Get data of the stock
Symbols=c("DVAX","STRP","SGMO","CALA","PIRS","KITE")
#Adjusted_price <- merge.zoo(SWX[,6], SPY[,6], ICUI[,6], MSFT[,6])
stock_prices  <- tq_get(Symbols, get = "stock.prices", from = " 2016-01-01")
stock_prices=stock_prices%>%select(symbol,date,adjusted)%>%rename(Stock=symbol,Price=adjusted) 
stock_prices%>%head()
#remove duplicated rows
stock_prices=stock_prices[!duplicated(stock_prices), ]
#Alternatively
#stock_prices[unique(stock_prices), ]
stock_prices2=stock_prices%>%spread(Stock,Price)
stock_prices2%>%head()

Alternatively

Use quantmod periodReturn to Convert daily Prices to daily Returns.

# Get stock pairs
stock_prices2 <- Symbols %>%
    tq_get(get  = "stock.prices",
           from = "2016-01-01",
           to   = today()) %>%
    group_by(symbol) 
stock_prices2%>%head()
stock_returns <- stock_prices2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "daily",
                 type       = "arithmetic",
                 col_rename = "returns") %>%
    spread(key = symbol, value = returns)
stock_returns%>%head()
stock_prices2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns") %>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_bar(stat = "identity", width = 30) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    scale_y_continuous(labels = scales::percent) +
    labs(title = " Monthly Returns",
         subtitle = "",
         y = "Monthly Returns", x = "") + 
    facet_wrap(~ symbol, ncol = 2,scales = "free") +
    theme_tq() + 
    scale_fill_tq()
stock_prices_daily <- stock_prices2 %>%
    group_by(symbol)
stock_prices_daily %>%
    ggplot(aes(x = date, y = adjusted, color = symbol)) +
    geom_line(size = 1) +
    labs(title = "Daily Stock Prices",
         x = "", y = "Adjusted Prices", color = "") +
    facet_wrap(~ symbol, ncol = 2, scales = "free") +
    scale_y_continuous(labels = scales::dollar) +
    theme_tq() + 
    scale_color_tq()

stock_prices2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_line(aes(color=symbol)) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    scale_y_continuous(labels = scales::percent) +
    labs(title = " Monthly Returns",
         subtitle = "",
         y = "Monthly Returns", x = "") + 
    facet_wrap(~ symbol, ncol = 2,scales = "free") +
    theme_tq() + 
    scale_fill_tq()

stock_prices2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol)) +
    geom_smooth(aes(color=symbol),method = 'loess' , formula = y ~ x) +
    geom_hline(yintercept = 0, color = palette_light()[[1]]) +
    scale_y_continuous(labels = scales::percent) +
    labs(title = " Monthly Returns",
         subtitle = "",
         y = "Monthly Returns", x = "") + 
    facet_wrap(~ symbol, ncol = 2,scales = "free") +
    theme_tq() + 
    scale_fill_tq()

stock_prices2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "monthly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol))+geom_density(stat = "identity") +
  theme_bw()

stock_prices2 %>%
    tq_transmute(select     = adjusted,
                 mutate_fun = periodReturn,
                 period     = "quarterly",
                 type       = "arithmetic",
                 col_rename = "returns")%>%
    ggplot(aes(x = date, y = returns, fill = symbol))+geom_density(stat = "identity",alpha=0.6) +
  labs(title = " Monthly Returns",
         subtitle = "",
         y = "Monthly Returns", x = "") + 
    facet_wrap(~ symbol, ncol = 2,scales = "free") +
    theme_tq() + 
    scale_fill_tq()

library(ggthemes)
#AAPL <- tq_get("AAPL")
# SMA
#AAPL %>%
stockd=tq_get(Symbols, get = "stock.prices", from = " 2016-01-01")
stockd%>%ggplot(aes(x = date, y = adjusted)) +
geom_line() + # Plot stock price
geom_bbands(aes(high = high, low = low, close = close), ma_fun = SMA, n = 100,show.legend=TRUE) +
ggthemes::theme_hc() +
  scale_colour_hc()+facet_wrap(~  symbol, ncol = 2,scales = "free") 

#coord_x_date(xlim = c(today() - years(1), today()), ylim = c(15, 30))

Convert stock returns to time series object.

stock_returns=stock_returns%>%tk_xts()
#stock_returns%>%tk_zoo(),tk_ts(),tk_xts()
stock_returns%>%head()
                  CALA          DVAX         KITE        PIRS         SGMO         STRP
2016-01-04  0.00000000  0.0000000000  0.000000000  0.00000000  0.000000000  0.000000000
2016-01-05  0.04704301  0.0004319654  0.006298498 -0.02620087 -0.004469274 -0.051810638
2016-01-06 -0.09627728 -0.0854922280 -0.083132722 -0.04484305 -0.077441077 -0.033489953
2016-01-07 -0.08948864  0.4022663362 -0.043759845 -0.06103286 -0.069343066 -0.077203704
2016-01-08 -0.06708268 -0.0979797947 -0.008786363  0.00500000 -0.031372549 -0.009222661
2016-01-11 -0.06521739 -0.0656961528 -0.035826462 -0.04477612 -0.133603239 -0.059840426
# Save mean return vector and sample covariance matrix
returns.portfolio<-na.omit(stock_returns)
meanReturns <- colMeans(returns.portfolio)
covMat <- cov(returns.portfolio)

The optimal portfolio in your setting is independent of the initial weights.

p <- portfolio.spec(assets = colnames(returns.portfolio))
p
**************************************************
PortfolioAnalytics Portfolio Specification 
**************************************************

Call:
portfolio.spec(assets = colnames(returns.portfolio))

Number of assets: 6 
Asset Names
[1] "CALA" "DVAX" "KITE" "PIRS" "SGMO" "STRP"

Markowitz Optimization involves minimizing the risk(variance) of returns and maximizing returns.

p <- add.objective(portfolio = p, type = "risk", name = "var")
p <- add.constraint(portfolio = p, type = "full_investment")

The full_investment part is equivalent to setting a constraint on the sum of the portfolio weights such that they always sum-up to 1. This is a case where the investor cares about the risk of the portfolio. Your optimization therefore returns the portfolio weights which attain the lowest possible portfolio variance. This is the global minimum variance portfolio. If the efficient portfolio is of interest, then an additional constraint, namely the minimal expected return can be added.

p <- add.constraint(portfolio=p, type = "return",     return_target= 0.0035)

The return_target=0.0035 can be replaced with any number,I have chosen the overall mean of returns.You can also chose something such as 0.15/250 (There are 250 work days in a year) to reflect that you have daily data and in this case you would like to have a portfolio which makes 15% per year in expectation.

The input R should be the time-series of returns you have. You also specify the optimizing function apropriate for the objective function ,here in this case ROI.

#Optimize
optimize.portfolio(R=returns.portfolio, portfolio = p, 
          optimize_method = "ROI", trace = TRUE)
***********************************
PortfolioAnalytics Optimization
***********************************

Call:
optimize.portfolio(R = returns.portfolio, portfolio = p, optimize_method = "ROI", 
    trace = TRUE)

Optimal Weights:
  CALA   DVAX   KITE   PIRS   SGMO   STRP 
0.1188 0.0675 0.3648 0.2493 0.0711 0.1286 

Objective Measure:
 StdDev 
0.02919 

creating a portfolio specification. This can be done by using portfolio.spec()

# Start with the names of the assets
port <- portfolio.spec(assets = colnames(stock_returns))

Now for some constraints. Let’s use the following:

Box constraints Leverage (weight sum)

# Box
port <- add.constraint(port, type = "box", min = 0.05, max = 0.8)
# Leverage
port <- add.constraint(portfolio = port, type = "full_investment")

The random solver is used to create a set of feasible portfolios that satisfy all the constraints specified above.

# Generate random portfolios
rportfolios <- random_portfolios(port, permutations = 5000, rp_method = "sample")

Add some objectives and optimize. For simplicity’s sake let’s do some mean-variance optimization.

# Get minimum variance portfolio
minvar.port <- add.objective(port, type = "risk", name = "var")
# Optimize
minvar.opt <- optimize.portfolio(stock_returns, minvar.port, optimize_method = "random", 
                                 rp = rportfolios)
# Generate maximum return portfolio
maxret.port <- add.objective(port, type = "return", name = "mean")
# Optimize
maxret.opt <- optimize.portfolio(stock_returns, maxret.port, optimize_method = "random", 
                                 rp = rportfolios)
# Generate vector of returns
minret <- 0.06/100
maxret <- maxret.opt$weights %*% meanReturns
vec <- seq(minret, maxret, length.out = 50)

We can build the efficient frontier at this stage after specifying the minimum variance as well as the maximum return portfolios. We add a weight concentration objective to prevent highly concentrated portfolios. random_portfolios() function ignores any diversification constraints.

# Get a character vector of the fund names
fund.names <- colnames(stock_returns)

Creating the Portfolio Object

The portfolio object is instantiated with the portfolio.spec function. The main argument to portfolio.spec is assets, this is a required argument. The assets argument can be a scalar value for the number of assets, a character vector of fund names, or a named vector of initial weights. If initial weights are not speci ed, an equal weight portfolio will be assumed. The pspec object is an S3 object of class “portfolio”. When rst created, the portfolio object has an element named assets with the initial weights, an element named category_labels, an element named weight_seq with sequence of weights if speci ed, an empty constraints list and an empty objectives list.

# Specify a portfolio object by passing a character vector for the
# assets argument.
pspec <- portfolio.spec(assets=fund.names)
print.default(pspec)
$assets
     CALA      DVAX      KITE      PIRS      SGMO      STRP 
0.1666667 0.1666667 0.1666667 0.1666667 0.1666667 0.1666667 

$category_labels
NULL

$weight_seq
NULL

$constraints
list()

$objectives
list()

$call
portfolio.spec(assets = fund.names)

attr(,"class")
[1] "portfolio.spec" "portfolio"     

Adding Constraints to the Portfolio Object

Adding constraints to the portfolio object is done with add.constraint. The add.constraint function is the main interface for adding and/or updating constraints to the portfolio object. This function allows the user to specify the portfolio to add the constraints to, the type of constraints, arguments for the constraint, and whether or not to enable the constraint (enabled=TRUE is the default). If updating an existing constraint, the indexnum argument can be speci ed.

Sum of Weights Constraint

The weight_sum constraint speci es the constraint on the sum of the weights. Aliases for the weight_sum constraint type include weight and leverage. Here we add a constraint that the weights must sum to 1, or the full investment constraint.

# Add the full investment constraint that specifies the weights must sum to 1.
pspec <- add.constraint(portfolio=pspec,
type="weight_sum",
min_sum=1,
max_sum=1)

There are two special cases for the leverage constraint: 1. The sum of the weights equal 1, i.e. the full investment constraint. The full investment con- straint can be speci ed with type=“full_investment”. This automatically sets min_sum=1 and max_sum=1. 2. The sum of the weights equal 0, i.e. the dollar neutral or active constraint. This constraint can be specified with type=“dollar_neutral” or type=“active”.

# The full investment constraint can also be specified with type="full_investment"
# pspec <- add.constraint(portfolio=pspec, type="full_investment")
# Another common constraint is that portfolio weights sum to 0.
# This can be specified any of the following ways
# pspec <- add.constraint(portfolio=pspec, type="weight_sum",
# min_sum=0,
# max_sum=0)
# pspec <- add.constraint(portfolio=pspec, type="dollar_neutral")
# pspec <- add.constraint(portfolio=pspec, type="active")

Box Constraint

Box constraints allows the user to specify upper and lower bounds on the weights of the assets. Here we add box constraints for the asset weights so that the minimum weight of any asset must be greater than or equal to 0.05 and the maximum weight of any asset must be less than or equal to 0.4. The values for min and max can be passed in as scalars or vectors. If min and max are scalars, the values for min and max will be replicated as vectors to the length of assets. If min and max are not speci ed, a minimum weight of 0 and maximum weight of 1 are assumed. Note that min and max can be speci ed as vectors with di erent weights for linear inequality constraints.

# Add box constraints
pspec <- add.constraint(portfolio=pspec,
 type="box",
 min=0.05,
 max=0.4)
# min and max can also be specified per asset
# pspec <- add.constraint(portfolio=pspec,
# type="box",
# min=c(0.05, 0, 0.08, 0.1),
# max=c(0.4, 0.3, 0.7, 0.55))
# A special case of box constraints is long only where min=0 and max=1
# The default action is long only if min and max are not specified
# pspec <- add.constraint(portfolio=pspec, type="box")
# pspec <- add.constraint(portfolio=pspec, type="long_only")

Group Constraint

Group constraints allow the user to specify the the sum of weights by group. Group constraints are currently supported by the ROI, DEoptim, and random portfolio solvers. The following code groups the assets such that the rst 3 assets are grouped together labeled GroupA and the fourth asset is in its own group labeled GroupB. The group_min argument speci es that the sum of the weights in GroupA must be greater than or equal to 0.1 and the sum of the weights in GroupB must be greater than or equal to 0.15. The group_max argument speci es that the sum of the weights in GroupA must be less than or equal to 0.85 and the sum of the weights in GroupB must be less than or equal to 0.55.The group_labels argument is optional and is useful if groups is not a named list for labeling groups in terms of market capitalization, sector, etc.

# Add group constraints
pspec <- add.constraint(portfolio=pspec, type="group",
groups=list(groupA=c(1, 2, 3),
grouB=4),
group_min=c(0.1, 0.15),
group_max=c(0.85, 0.55))

Position Limit Constraint

The position limit constraint allows the user to specify limits on the number of assets with non- zero, long, or short positions. The ROI solver interfaces to the Rglpk package (i.e. using the glpk plugin) for solving maximizing return and ETL/ES/cVaR objectives. The Rglpk package supports integer programming and thus supports position limit constraints for the max_pos argument. The quadprog package does not support integer programming, and therefore max_pos is not supported for the ROI solver using the quadprog plugin. Note that max_pos_long and max_pos_short are not supported for either ROI solver. All position limit constraints are fully supported for DEoptim and random solvers.

# Add position limit constraint such that we have a maximum number of three assets with non-zero > 
pspec <- add.constraint(portfolio=pspec, type="position_limit", max_pos=3)
# Can also specify maximum number of long positions and short positions
# pspec <- add.constraint(portfolio=pspec, type="position_limit", max_pos_long=3, max_pos_short=3)

Diversification Constraint

The diversi cation constraint allows the user to target diversi cation. Diversi cation is de ned as diversification = PN i=1 w2 i for N assets. The diversi cation constraint is implemented for the global optimizers by applying a penalty if the diversi cation value is more than 5% away from div_target. Note that diversi cation as a constraint is not supported for the ROI solvers, it is only supported for the global numeric solvers.

pspec <- add.constraint(portfolio=pspec, type="diversification", div_target=0.7)

Turnover Constraint

A target turnover can be specified as a constraint. The turnover is calculated from a set of initial weights. The initial weights can be speci ed, by default they are the initial weights in the portfolio object. The turnover constraint is implemented for the global optimizers by applying a penalty if the turnover value is more than 5% away from turnover_target. Note that the turnover constraint is not currently supported for quadratic utility and minimum variance problems using the ROI solver.

pspec <- add.constraint(portfolio=pspec, type="turnover", turnover_target=0.2)

Target Return Constraint

The target return constraint allows the user to specify a target mean return.

pspec <- add.constraint(portfolio=pspec, type="return", return_target=0.007)

Factor Exposure Constraint

The factor exposure constraint allows the user to set upper and lower bounds on exposures to risk factors. The exposures can be passed in as a vector or matrix. Here we specify a vector for B with arbitrary values, e.g. betas of the assets, with a market risk exposure range of 0.6 to 0.9.

pspec <- add.constraint(portfolio=pspec, type="factor_exposure",
B=c(0.08, 0.37, 0.79, 1.43,0.5,0.4),
lower=0.6, upper=0.9)

Transaction Cost Constraint

The transaction cost constraint allows the user to specify proportional transaction costs. Propor- tional transaction cost constraints can be implemented for quadratic utility and minimum variance 7 problems using the ROI solver. Transaction costs are supported as a penalty for the global numeric solvers. Here we add the transaction cost contraint with the proportional transaction cost value of 1%.

pspec <- add.constraint(portfolio=pspec, type="transaction_cost", ptc=0.01)

The print method for the portfolio object shows a concise view of the portfolio and the con- straints that have been added.

print(pspec)
**************************************************
PortfolioAnalytics Portfolio Specification 
**************************************************

Call:
portfolio.spec(assets = fund.names)

Number of assets: 6 
Asset Names
[1] "CALA" "DVAX" "KITE" "PIRS" "SGMO" "STRP"

Constraints
Enabled constraint types
        - weight_sum 
        - box 
        - group 
        - position_limit 
        - diversification 
        - turnover 
        - return 
        - factor_exposure 
        - transaction_cost 

The summary method gives a more detailed view of the constraints.

summary(pspec)
$assets
     CALA      DVAX      KITE      PIRS      SGMO      STRP 
0.1666667 0.1666667 0.1666667 0.1666667 0.1666667 0.1666667 

$enabled_constraints
$enabled_constraints[[1]]
An object containing 6 nonlinear constraints.

$enabled_constraints[[2]]
An object containing 5 nonlinear constraints.

$enabled_constraints[[3]]
An object containing 7 nonlinear constraints.

$enabled_constraints[[4]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[5]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[6]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[7]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[8]]
An object containing 6 nonlinear constraints.

$enabled_constraints[[9]]
An object containing 4 nonlinear constraints.


$disabled_constraints
list()

$enabled_objectives
list()

$disabled_objectives
list()

attr(,"class")
[1] "summary.portfolio"

This demonstrates adding constraints to the portfolio object. As an alternative to adding constraints directly to the portfolio object, constraints can be specified as separate objects.

Specifying Constraints as Separate Objects

The following examples will demonstrate how to specify constraints as separate objects for all constraints types.

# full investment constraint
weight_constr <- weight_sum_constraint(min_sum=1, max_sum=1)
# box constraint
box_constr <- box_constraint(assets=pspec$assets, min=0, max=1)
# group constraint
group_constr<-group_constraint(assets=pspec$assets,
groups=list(c(1, 2, 3),
4),
group_min=c(0.1, 0.15),
group_max=c(0.85, 0.55),
group_labels=c("GroupA", "GroupB"))
# position limit constraint
poslimit_constr <- position_limit_constraint(assets=pspec$assets, max_pos=3)
# diversification constraint
div_constr <- diversification_constraint(div_target=0.7)
# turnover constraint
to_constr <- turnover_constraint(turnover_target=0.2)
# target return constraint
ret_constr <- return_constraint(return_target=0.007)
# factor exposure constraint
exp_constr <- factor_exposure_constraint(assets=pspec$assets,
B=c(0.08, 0.37, 0.79, 1.43,0.5,0.4),
 lower=0.6, upper=0.9)

Adding Objectives

Objectives can be added to the portfolio object with add.objective. The add.objective function is the main function for adding and/or updating business objectives to the portfolio object. This function allows the user to specify the portfolio to add the objectives to, the type (currently ‘return’, ‘risk’, ‘risk budget’, or ‘weight concentration’), name of the objective function, arguments to the objective function, and whether or not to enable the objective. If updating an existing constraint, the indexnum argument can be specified.

Portfolio Risk Objective

The portfolio risk objective allows the user to specify a risk function to minimize Here we add a risk objective to minimize portfolio expected tail loss with a con dence level of 0.95. Other default arguments to the function can be passed in as a named list to arguments. Note that the name of the function must correspond to a function in R. Many functions are available in the PerformanceAnalytics package or a user de ned function.

pspec <- add.objective(portfolio=pspec,
 type='risk',
 name='ETL',
 arguments=list(p=0.95))

Portfolio Return Objective

The return objective allows the user to specify a return function to maximize. Here we add a return objective to maximize the portfolio mean return.

pspec <- add.objective(portfolio=pspec,

Portfolio Risk Budget Objective

The portfolio risk objective allows the user to specify constraints to minimize component con- tribution (i.e. equal risk contribution) or specify upper and lower bounds on percentage risk contribution. Here we specify that no asset can contribute more than 30% to total portfolio risk. See the risk budget optimization vignette for more detailed examples of portfolio optimizations with risk budgets.

pspec <- add.objective(portfolio=pspec, type="risk_budget", name="ETL",
arguments=list(p=0.95), max_prisk=0.3)
# for an equal risk contribution portfolio, set min_concentration=TRUE
# pspec <- add.objective(portfolio=pspec, type="risk_budget", name="ETL",
# arguments=list(p=0.95), min_concentration=TRUE)

Portfolio Weight Concentration Objective

The weight concentration objective allows the user to specify an objective to minimize concentra- tion as measured by the Her ndahl-Hirschman Index. For otpimization problems solved with the global numeric optimizers, the portfolio HHI value is penalized using conc_aversion value as the multiplier. For quadratic utility problems with weight concentration as an objective using the ROI solver, this is implemented as a penalty to the objective function. The objective function is implemented as follows:

Where μ is the estimated mean asset returns,  is the risk aversion parameter, lambdahhi is the concentration aversion parameter, HHI is the portfolio HHI,  is the estimated covariance matrix of asset returns and w is the set of weights. Here we add a weight concentration objective for the overall portfolio HHI.

pspec <- add.objective(portfolio=pspec, type="weight_concentration",
 name="HHI", conc_aversion=0.1)

The weight concentration aversion parameter by groups can also be speci ed. Here we add a weight concentration objective specifying groups and concentration aversion parameters by group.

pspec <- add.objective(portfolio=pspec, type="weight_concentration",
 name="HHI",
conc_aversion=c(0.03, 0.06),
conc_groups=list(c(1, 2),
c(3, 4)))

The print method for the portfolio object will now show all the constraints and objectives that have been added.

print(pspec)
**************************************************
PortfolioAnalytics Portfolio Specification 
**************************************************

Call:
portfolio.spec(assets = fund.names)

Number of assets: 6 
Asset Names
[1] "CALA" "DVAX" "KITE" "PIRS" "SGMO" "STRP"

Constraints
Enabled constraint types
        - weight_sum 
        - box 
        - group 
        - position_limit 
        - diversification 
        - turnover 
        - return 
        - factor_exposure 
        - transaction_cost 

Objectives:
Enabled objective names
        - ETL 
        - mean 
        - ETL 
        - HHI 
        - HHI 

The summary function gives a more detailed view.

 summary(pspec)
$assets
     CALA      DVAX      KITE      PIRS      SGMO      STRP 
0.1666667 0.1666667 0.1666667 0.1666667 0.1666667 0.1666667 

$enabled_constraints
$enabled_constraints[[1]]
An object containing 6 nonlinear constraints.

$enabled_constraints[[2]]
An object containing 5 nonlinear constraints.

$enabled_constraints[[3]]
An object containing 7 nonlinear constraints.

$enabled_constraints[[4]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[5]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[6]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[7]]
An object containing 4 nonlinear constraints.

$enabled_constraints[[8]]
An object containing 6 nonlinear constraints.

$enabled_constraints[[9]]
An object containing 4 nonlinear constraints.


$disabled_constraints
list()

$enabled_objectives
$enabled_objectives[[1]]
$name
[1] "ETL"

$target
NULL

$arguments
$arguments$p
[1] 0.95

$arguments$portfolio_method
[1] "single"


$enabled
[1] TRUE

$multiplier
[1] 1

$call
add.objective(portfolio = pspec, type = "risk", name = "ETL", 
    arguments = list(p = 0.95))

attr(,"class")
[1] "portfolio_risk_objective" "objective"               

$enabled_objectives[[2]]
$name
[1] "mean"

$target
NULL

$arguments
list()

$enabled
[1] TRUE

$multiplier
[1] -1

$call
add.objective(portfolio = pspec, type = "return", name = "mean")

attr(,"class")
[1] "return_objective" "objective"       

$enabled_objectives[[3]]
$name
[1] "ETL"

$target
NULL

$arguments
$arguments$p
[1] 0.95

$arguments$portfolio_method
[1] "component"


$enabled
[1] TRUE

$multiplier
[1] 1

$max_prisk
CALA DVAX KITE PIRS SGMO STRP 
 0.3  0.3  0.3  0.3  0.3  0.3 

$min_concentration
[1] FALSE

$min_difference
[1] FALSE

$call
add.objective(portfolio = pspec, type = "risk_budget", name = "ETL", 
    arguments = list(p = 0.95), max_prisk = 0.3)

attr(,"class")
[1] "risk_budget_objective" "objective"            

$enabled_objectives[[4]]
$name
[1] "HHI"

$target
NULL

$arguments
list()

$enabled
[1] TRUE

$multiplier
[1] 1

$conc_aversion
[1] 0.1

$call
add.objective(portfolio = pspec, type = "weight_concentration", 
    name = "HHI", conc_aversion = 0.1)

attr(,"class")
[1] "weight_concentration_objective" "objective"                     

$enabled_objectives[[5]]
$name
[1] "HHI"

$target
NULL

$arguments
$arguments$groups
$arguments$groups[[1]]
[1] 1 2

$arguments$groups[[2]]
[1] 3 4



$enabled
[1] TRUE

$multiplier
[1] 1

$conc_aversion
[1] 0.03 0.06

$conc_groups
$conc_groups[[1]]
[1] 1 2

$conc_groups[[2]]
[1] 3 4


$call
add.objective(portfolio = pspec, type = "weight_concentration", 
    name = "HHI", conc_aversion = c(0.03, 0.06), conc_groups = list(c(1, 
        2), c(3, 4)))

attr(,"class")
[1] "weight_concentration_objective" "objective"                     


$disabled_objectives
list()

attr(,"class")
[1] "summary.portfolio"

Solvers

The PortfolioAnalytics package currently supports random portfolios, DEoptim, pso, GenSA, and ROI as back ends. Note that some of the QP/LP problems are solved directly with Rglpk and quad- prog. The solver can be speci ed with the optimize_method argument in optimize.portfolio and optimize.portfolio.rebalancing.

DEoptim

PortfolioAnalytics uses the DEoptim function from the R package DEoptim. Di erential evolution is a stochastic global optimization algorithm. See ?DEoptim and the references contained therein for more information. See also Large scale portfolio optimization with DEoptim. 5.2 Random Portfolios PortfolioAnalytics has three methods to generate random portfolios. 1. The ‘sample’ method to generate random portfolios is based on an idea by Pat Burns. This is the most exible method, but also the slowest, and can generate portfolios to satisfy leverage, box, group, and position limit constraints. 2. The ‘simplex’ method to generate random portfolios is based on a paper by W. T. Shaw. The simplex method is useful to generate random portfolios with the full investment constraint, where the sum of the weights is equal to 1, and min box constraints. Values for min_sum and max_sum of the leverage constraint will be ignored, the sum of weights will equal 1. All other constraints such as the box constraint max, group and position limit constraints will be handled by elimination. If the constraints are very restrictive, this may result in very few feasible portfolios remaining. Another key point to note is that the solution may not be along the vertexes depending on the objective. For example, a risk budget objective will likely place the portfolio somewhere on the interior. 3. The ‘grid’ method to generate random portfolios is based on the gridSearch function in package NMOF. The grid search method only satis es the min and max box constraints. The min_sum and max_sum leverage constraint will likely be violated and the weights in the random portfolios should be normalized. Normalization may cause the box constraints to be violated and will be penalized in constrained_objective. The following plots illustrate the various methods to generate random portfolios.

pso

PortfolioAnalytics uses the psoptim function from the R package pso. Particle swarm optimization is a heuristic optimization algorithm. See ?psoptim and the references contained therein for more information.

GenSA

PortfolioAnalytics uses the GenSA function from the R package GenSA. Generalized simmulated annealing is generic probabilistic heuristic optimization algorithm. See ?GenSA and the references contained therein for more information.

ROI

The ROI package serves as an interface to the Rglpk package and the quadprog package to solve linear and quadratic programming problems. The interface to the ROI package solves a limited type of convex optimization problems: 1. Maxmimize portfolio return subject leverage, box, group, position limit, target mean return, and/or factor exposure constraints on weights. 2. Minimize portfolio variance subject to leverage, box, group, turnover, and/or factor exposure constraints (otherwise known as global minimum variance portfolio). 3. Minimize portfolio variance subject to leverage, box, group, and/or factor exposure con- straints and a desired portfolio return. 4. Maximize quadratic utility subject to leverage, box, group, target mean return, turnover, and/or factor exposure constraints and risk aversion parameter. (The risk aversion parameter is passed into optimize.portfolio as an added argument to the portfolio object).

  1. Minimize ETL subject to leverage, box, group, position limit, target mean return, and/or factor exposure constraints and target portfolio return. 6 Optimization The previous sections demonstrated how to specify a portfolio object, add constraints, add objec- tives, and the solvers available. This section will demonstrate run the optimizations via optimize.portfolio. Only a small number of examples will be shown here, see the demos for several more examples.

Initial Portfolio Object

pacman::p_load("DEoptim","ROI","ROI.plugin.glpk","ROI.plugin.quadprog")
#library(DEoptim)
#library(ROI)
#require(ROI.plugin.glpk)
#require(ROI.plugin.quadprog)
funds <- colnames(stock_returns)
# Create an initial portfolio object with leverage and box constraints
init <- portfolio.spec(assets=funds)
init <- add.constraint(portfolio=init, type="leverage",
min_sum=0.99, max_sum=1.01)
init <- add.constraint(portfolio=init, type="box", min=0.05, max=0.65)
#init <- add.constraint(portfolio = init, type = "full_investment")

Maximize mean return with ROI

Add an objective to maximize mean return.

maxret <- add.objective(portfolio=init, type="return", name="mean")

Run the optimization.

opt_maxret <- optimize.portfolio(R=stock_returns, portfolio=maxret,
optimize_method="ROI",
trace=TRUE)
print(opt_maxret)
***********************************
PortfolioAnalytics Optimization
***********************************

Call:
optimize.portfolio(R = stock_returns, portfolio = maxret, optimize_method = "ROI", 
    trace = TRUE)

Optimal Weights:
CALA DVAX KITE PIRS SGMO STRP 
0.05 0.05 0.05 0.16 0.05 0.65 

Objective Measure:
    mean 
0.005823 

Minimize variance with ROI

Add an objective to minimize portfolio variance.

minvar <- add.objective(portfolio=init, type="risk", name="var")

Run the optimization. Note that although ‘var’ is the risk metric, ‘StdDev’ is returned as an objective measure.

opt_minvar <- optimize.portfolio(R=stock_returns, portfolio=minvar,
optimize_method="ROI", trace=TRUE)
print(opt_minvar)
***********************************
PortfolioAnalytics Optimization
***********************************

Call:
optimize.portfolio(R = stock_returns, portfolio = minvar, optimize_method = "ROI", 
    trace = TRUE)

Optimal Weights:
  CALA   DVAX   KITE   PIRS   SGMO   STRP 
0.0947 0.0845 0.3554 0.2806 0.0937 0.0810 

Objective Measure:
 StdDev 
0.02839 

Maximize quadratic utility with ROI

Add mean and var objectives for quadratic utility. Note that the risk aversion parameter for quadratic utility is specifed in the objective as shown below.

qu <- add.objective(portfolio=init, type="return", name="mean")
qu <- add.objective(portfolio=qu, type="risk", name="var", risk_aversion=0.25)

Run the optimization.

opt_qu <- optimize.portfolio(R=stock_returns, portfolio=qu,
optimize_method="ROI",
trace=TRUE)
print(opt_qu)
***********************************
PortfolioAnalytics Optimization
***********************************

Call:
optimize.portfolio(R = stock_returns, portfolio = qu, optimize_method = "ROI", 
    trace = TRUE)

Optimal Weights:
  CALA   DVAX   KITE   PIRS   SGMO   STRP 
0.0500 0.0500 0.1281 0.0819 0.0500 0.6500 

Objective Measure:
    mean 
0.005822 


 StdDev 
0.05839 
LS0tCnRpdGxlOiAiUG9ydGZvbGlvIE9wdGltaXphdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCnRoZW1lOiBjb3Ntbwp0b2NfZmxvYXQ6IG5vCnRvY19kZXB0aDogMgphdXRob3I6IE5hbmEgQm9hdGVuZwpkZl9wcmludDogcGFnZWQKVGltZTogJ2ByIFN5cy50aW1lKClgJwpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclQiAlZCwgJVknKWAiCi0tLQoKYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0Kcm0obGlzdD1scygpKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICBvdXQud2lkdGggPSIxMDAlIiwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5hbGlnbiA9ICdkZWZhdWx0JywgCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgZmlnLmNhcCA9IkZpZy4gMzAiLCAKICAgICAgICAgICAgICAgICAgICAgIG91dC53aWR0aD0iMTAwJSIpCgpgYGAKCgoKYGBge3J9CnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSx0aWR5cXVhbnQsUG9ydGZvbGlvQW5hbHl0aWNzLHF1YW50bW9kLFBlcmZvcm1hbmNlQW5hbHl0aWNzLHpvbywKICAgICAgICAgICAgICAgcGxvdGx5LHRpbWVraXQsZ2d0aGVtZXMsdGltZXRrKQpgYGAKCgpQb3J0Zm9saW8gb3B0aW1pemF0aW9uIGlzIHRoZSBwcm9jZXNzICBvZiBzZWxlY3RpbmcgIHByb3BvcnRpb25zIG9mIHZhcmlvdXMgYXNzZXRzIHRvIGluY2x1ZGUgIGluIGEgcG9ydGZvbGlvLCBpbiBzdWNoIGEgd2F5IGFzIHRvIG1ha2UgdGhlIHBvcnRmb2xpbyBiZXR0ZXIgdGhhbiBhbnkgb3RoZXIgYWNjb3JkaW5nIHRvIHNvbWUgY3JpdGVyaW9uLiBUaGUgY3JpdGVyaW9uIHdpbGwgY29tYmluZSwgZGlyZWN0bHkgb3IgaW5kaXJlY3RseSwgY29uc2lkZXJhdGlvbnMgb2YgdGhlIGV4cGVjdGVkIHZhbHVlIG9mIHRoZSBwb3J0Zm9saW8ncyByYXRlIG9mIHJldHVybiBhcyB3ZWxsIGFzIG9mIHRoZSByZXR1cm4ncyBkaXNwZXJzaW9uIGFuZCBwb3NzaWJseSBvdGhlciBtZWFzdXJlcyBvZiBmaW5hbmNpYWwgcmlzay4gVGhlIG9iamVjdGl2ZSBvZiBwb3JydGZvbGlvIG9wdGltaXphdGlvbiBpcyB0byBtYXhpbWl6ZSBhIG1lYXN1cmUgb2YgZ2FpbiBwZXIgdW5pdCBtZWFzdXJlIG9mIHJpc2sgYW5kIG1pbmltaXplIGEgbWVhc3VyZSBvZiByaXNrLgoKCk1vZGVybiBwb3J0Zm9saW8gdGhlb3J5IHdhcyBpbnRyb2R1Y2VkICBieSBIYXJyeSBNYXJrb3dpdHogaW4gMTk1Mi4gSXQgIGFzc3VtZXMgdGhhdCBpbiBnZW5lcmFsLCBhbiBpbnZlc3RvciB3YW50cyB0byBtYXhpbWl6ZSBhIHBvcnRmb2xpbydzIGV4cGVjdGVkIHJldHVybiBjb250aW5nZW50IG9uIGFueSBnaXZlbiBhbW91bnQgb2Ygcmlzaywgd2l0aCByaXNrIG1lYXN1cmVkIGJ5IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHBvcnRmb2xpbydzIHJhdGUgb2YgcmV0dXJuLiBGb3IgcG9ydGZvbGlvcyB0aGF0IG1lZXQgdGhpcyBjcml0ZXJpb24sIGtub3duIGFzIGVmZmljaWVudCBwb3J0Zm9saW9zLCBhY2hpZXZpbmcgYSBoaWdoZXIgZXhwZWN0ZWQgcmV0dXJuIHJlcXVpcmVzIHRha2luZyBvbiBtb3JlIHJpc2ssIHNvIGludmVzdG9ycyBhcmUgZmFjZWQgd2l0aCBhIHRyYWRlLW9mZiBiZXR3ZWVuIHJpc2sgYW5kIGV4cGVjdGVkIHJldHVybi4gVGhpcyByaXNrLWV4cGVjdGVkIHJldHVybiByZWxhdGlvbnNoaXAgb2YgZWZmaWNpZW50IHBvcnRmb2xpb3MgaXMgZ3JhcGhpY2FsbHkgcmVwcmVzZW50ZWQgYnkgYSBjdXJ2ZSBrbm93biBhcyB0aGUgZWZmaWNpZW50IGZyb250aWVyLiBBbGwgZWZmaWNpZW50IHBvcnRmb2xpb3MsIGVhY2ggcmVwcmVzZW50ZWQgYnkgYSBwb2ludCBvbiB0aGUgZWZmaWNpZW50IGZyb250aWVyLCBhcmUgd2VsbC1kaXZlcnNpZmllZC4gRm9yIHRoZSBzcGVjaWZpYyBmb3JtdWxhcyBmb3IgZWZmaWNpZW50IHBvcnRmb2xpb3MsWzNdIHNlZSBQb3J0Zm9saW8gc2VwYXJhdGlvbiBpbiBtZWFuLXZhcmlhbmNlIGFuYWx5c2lzLiBXaGlsZSBpZ25vcmluZyBoaWdoZXIgbW9tZW50cyBjYW4gbGVhZCB0byBzaWduaWZpY2FudCBvdmVyLWludmVzdG1lbnQgaW4gcmlza3kgc2VjdXJpdGllcywgZXNwZWNpYWxseSB3aGVuIHZvbGF0aWxpdHkgaXMgaGlnaFs0XSwgdGhlIGRldmVsb3BtZW50IG9mIHBvcnRmb2xpb3MgZm9yIG5vbi1HYXVzc2lhbiBlY29ub21pZXMgaXMgbWF0aGVtYXRpY2FsbHkgY2hhbGxlbmdpbmcuCgpTb21lIG9mIHRoZSBiZXN0IHBlcmZvcm1pbmcgc3RvY2tzIHllYXIgdG8gZGF0ZShOb3ZlbWJlciwyMDE3KSBpbmNsdWRlIER5bmF2YXggVGVjaChEVkFYKS4gTW9zdCBvZiB0aGUgYmVzdCBwZXJmb3JtaW5nIHN0b2NrcyB3ZXJlICBhbGwgIGZyb20gdGhlIEJpb3RlY2ggc3BhY2UuIER5bmF2YXggVGVjaCAoTkFTREFROkRWQVgpIHJhbmtzIGZpcnN0IHdpdGggYSBZVEQgZ2FpbiBvZiA0NDQlLiBTdHJhaWdodCBQYXRoIChOWVNFTUtUOlNUUlApIHJhbmtzIHNlY29uZCBhdCArNDMyLjc5JS4gU2FuZ2FtbyBUaGVyYXBldXRpY3MgKE5BU0RBUTpTR01PKSwgQ2FsaXRoZXJhIEJpb3NjaWVuY2VzIChOQVNEQVE6Q0FMQSksIGFuZCBQaWVyaXMgUGhhcm1hIChOQVNEQVE6UElSUykgcm91bmQgb3V0IHRoZSB0b3AgZml2ZS4gRWlnaHQgb2YgdGhlIHRvcCBuaW5lIGFyZSBCaW90ZWNoIHN0b2NrcywgYW5kIHRoZW4gV2VpZ2h0IFdhdGNoZXJzIChOWVNFOldUVykgcmFua3MgdGVudGggd2l0aCBhIGdhaW4gb2YgMjgwJS4KCmBgYHtyfQojIEdldCBkYXRhIG9mIHRoZSBzdG9jawoKU3ltYm9scz1jKCJEVkFYIiwiU1RSUCIsIlNHTU8iLCJDQUxBIiwiUElSUyIsIktJVEUiKQoKI0FkanVzdGVkX3ByaWNlIDwtIG1lcmdlLnpvbyhTV1hbLDZdLCBTUFlbLDZdLCBJQ1VJWyw2XSwgTVNGVFssNl0pCgoKc3RvY2tfcHJpY2VzICA8LSB0cV9nZXQoU3ltYm9scywgZ2V0ID0gInN0b2NrLnByaWNlcyIsIGZyb20gPSAiIDIwMTYtMDEtMDEiKQoKCnN0b2NrX3ByaWNlcz1zdG9ja19wcmljZXMlPiVzZWxlY3Qoc3ltYm9sLGRhdGUsYWRqdXN0ZWQpJT4lcmVuYW1lKFN0b2NrPXN5bWJvbCxQcmljZT1hZGp1c3RlZCkgCgpzdG9ja19wcmljZXMlPiVoZWFkKCkKCgoKCgpgYGAKCgpgYGB7cn0KCiNyZW1vdmUgZHVwbGljYXRlZCByb3dzCgpzdG9ja19wcmljZXM9c3RvY2tfcHJpY2VzWyFkdXBsaWNhdGVkKHN0b2NrX3ByaWNlcyksIF0KCgojQWx0ZXJuYXRpdmVseQoKI3N0b2NrX3ByaWNlc1t1bmlxdWUoc3RvY2tfcHJpY2VzKSwgXQoKc3RvY2tfcHJpY2VzMj1zdG9ja19wcmljZXMlPiVzcHJlYWQoU3RvY2ssUHJpY2UpCgpzdG9ja19wcmljZXMyJT4laGVhZCgpCgoKYGBgCgoKCgoKCgojIyMjIEFsdGVybmF0aXZlbHkKClVzZSBxdWFudG1vZCBwZXJpb2RSZXR1cm4gdG8gQ29udmVydCBkYWlseSBQcmljZXMgdG8gIGRhaWx5IFJldHVybnMuCgpgYGB7cn0KIyBHZXQgc3RvY2sgcGFpcnMKc3RvY2tfcHJpY2VzMiA8LSBTeW1ib2xzICU+JQogICAgdHFfZ2V0KGdldCAgPSAic3RvY2sucHJpY2VzIiwKICAgICAgICAgICBmcm9tID0gIjIwMTYtMDEtMDEiLAogICAgICAgICAgIHRvICAgPSB0b2RheSgpKSAlPiUKICAgIGdyb3VwX2J5KHN5bWJvbCkgCgoKc3RvY2tfcHJpY2VzMiU+JWhlYWQoKQoKCnN0b2NrX3JldHVybnMgPC0gc3RvY2tfcHJpY2VzMiAlPiUKICAgIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gYWRqdXN0ZWQsCiAgICAgICAgICAgICAgICAgbXV0YXRlX2Z1biA9IHBlcmlvZFJldHVybiwKICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gImRhaWx5IiwKICAgICAgICAgICAgICAgICB0eXBlICAgICAgID0gImFyaXRobWV0aWMiLAogICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAicmV0dXJucyIpICU+JQogICAgc3ByZWFkKGtleSA9IHN5bWJvbCwgdmFsdWUgPSByZXR1cm5zKQoKc3RvY2tfcmV0dXJucyU+JWhlYWQoKQpgYGAKCgoKCmBgYHtyfQoKCnN0b2NrX3ByaWNlczIgJT4lCiAgICB0cV90cmFuc211dGUoc2VsZWN0ICAgICA9IGFkanVzdGVkLAogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBwZXJpb2RSZXR1cm4sCiAgICAgICAgICAgICAgICAgcGVyaW9kICAgICA9ICJtb250aGx5IiwKICAgICAgICAgICAgICAgICB0eXBlICAgICAgID0gImFyaXRobWV0aWMiLAogICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAicmV0dXJucyIpICU+JQogICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHJldHVybnMsIGZpbGwgPSBzeW1ib2wpKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAzMCkgKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSBwYWxldHRlX2xpZ2h0KClbWzFdXSkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKwogICAgbGFicyh0aXRsZSA9ICIgTW9udGhseSBSZXR1cm5zIiwKICAgICAgICAgc3VidGl0bGUgPSAiIiwKICAgICAgICAgeSA9ICJNb250aGx5IFJldHVybnMiLCB4ID0gIiIpICsgCiAgICBmYWNldF93cmFwKH4gc3ltYm9sLCBuY29sID0gMixzY2FsZXMgPSAiZnJlZSIpICsKICAgIHRoZW1lX3RxKCkgKyAKICAgIHNjYWxlX2ZpbGxfdHEoKQpgYGAKCgoKYGBge3J9CnN0b2NrX3ByaWNlc19kYWlseSA8LSBzdG9ja19wcmljZXMyICU+JQogICAgZ3JvdXBfYnkoc3ltYm9sKQoKc3RvY2tfcHJpY2VzX2RhaWx5ICU+JQogICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGFkanVzdGVkLCBjb2xvciA9IHN5bWJvbCkpICsKICAgIGdlb21fbGluZShzaXplID0gMSkgKwogICAgbGFicyh0aXRsZSA9ICJEYWlseSBTdG9jayBQcmljZXMiLAogICAgICAgICB4ID0gIiIsIHkgPSAiQWRqdXN0ZWQgUHJpY2VzIiwgY29sb3IgPSAiIikgKwogICAgZmFjZXRfd3JhcCh+IHN5bWJvbCwgbmNvbCA9IDIsIHNjYWxlcyA9ICJmcmVlIikgKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKSArCiAgICB0aGVtZV90cSgpICsgCiAgICBzY2FsZV9jb2xvcl90cSgpCmBgYAoKCmBgYHtyfQpzdG9ja19wcmljZXMyICU+JQogICAgdHFfdHJhbnNtdXRlKHNlbGVjdCAgICAgPSBhZGp1c3RlZCwKICAgICAgICAgICAgICAgICBtdXRhdGVfZnVuID0gcGVyaW9kUmV0dXJuLAogICAgICAgICAgICAgICAgIHBlcmlvZCAgICAgPSAibW9udGhseSIsCiAgICAgICAgICAgICAgICAgdHlwZSAgICAgICA9ICJhcml0aG1ldGljIiwKICAgICAgICAgICAgICAgICBjb2xfcmVuYW1lID0gInJldHVybnMiKSU+JQogICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHJldHVybnMsIGZpbGwgPSBzeW1ib2wpKSArCiAgICBnZW9tX2xpbmUoYWVzKGNvbG9yPXN5bWJvbCkpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gcGFsZXR0ZV9saWdodCgpW1sxXV0pICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICAgIGxhYnModGl0bGUgPSAiIE1vbnRobHkgUmV0dXJucyIsCiAgICAgICAgIHN1YnRpdGxlID0gIiIsCiAgICAgICAgIHkgPSAiTW9udGhseSBSZXR1cm5zIiwgeCA9ICIiKSArIAogICAgZmFjZXRfd3JhcCh+IHN5bWJvbCwgbmNvbCA9IDIsc2NhbGVzID0gImZyZWUiKSArCiAgICB0aGVtZV90cSgpICsgCiAgICBzY2FsZV9maWxsX3RxKCkKYGBgCgoKYGBge3J9CnN0b2NrX3ByaWNlczIgJT4lCiAgICB0cV90cmFuc211dGUoc2VsZWN0ICAgICA9IGFkanVzdGVkLAogICAgICAgICAgICAgICAgIG11dGF0ZV9mdW4gPSBwZXJpb2RSZXR1cm4sCiAgICAgICAgICAgICAgICAgcGVyaW9kICAgICA9ICJtb250aGx5IiwKICAgICAgICAgICAgICAgICB0eXBlICAgICAgID0gImFyaXRobWV0aWMiLAogICAgICAgICAgICAgICAgIGNvbF9yZW5hbWUgPSAicmV0dXJucyIpJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gcmV0dXJucywgZmlsbCA9IHN5bWJvbCkpICsKICAgIGdlb21fc21vb3RoKGFlcyhjb2xvcj1zeW1ib2wpLG1ldGhvZCA9ICdsb2VzcycgLCBmb3JtdWxhID0geSB+IHgpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gcGFsZXR0ZV9saWdodCgpW1sxXV0pICsKICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICAgIGxhYnModGl0bGUgPSAiIE1vbnRobHkgUmV0dXJucyIsCiAgICAgICAgIHN1YnRpdGxlID0gIiIsCiAgICAgICAgIHkgPSAiTW9udGhseSBSZXR1cm5zIiwgeCA9ICIiKSArIAogICAgZmFjZXRfd3JhcCh+IHN5bWJvbCwgbmNvbCA9IDIsc2NhbGVzID0gImZyZWUiKSArCiAgICB0aGVtZV90cSgpICsgCiAgICBzY2FsZV9maWxsX3RxKCkKYGBgCgoKYGBge3J9CgoKc3RvY2tfcHJpY2VzMiAlPiUKICAgIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gYWRqdXN0ZWQsCiAgICAgICAgICAgICAgICAgbXV0YXRlX2Z1biA9IHBlcmlvZFJldHVybiwKICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gIm1vbnRobHkiLAogICAgICAgICAgICAgICAgIHR5cGUgICAgICAgPSAiYXJpdGhtZXRpYyIsCiAgICAgICAgICAgICAgICAgY29sX3JlbmFtZSA9ICJyZXR1cm5zIiklPiUKICAgIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSByZXR1cm5zLCBmaWxsID0gc3ltYm9sKSkrZ2VvbV9kZW5zaXR5KHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgdGhlbWVfYncoKQpgYGAKCgoKCmBgYHtyfQoKc3RvY2tfcHJpY2VzMiAlPiUKICAgIHRxX3RyYW5zbXV0ZShzZWxlY3QgICAgID0gYWRqdXN0ZWQsCiAgICAgICAgICAgICAgICAgbXV0YXRlX2Z1biA9IHBlcmlvZFJldHVybiwKICAgICAgICAgICAgICAgICBwZXJpb2QgICAgID0gInF1YXJ0ZXJseSIsCiAgICAgICAgICAgICAgICAgdHlwZSAgICAgICA9ICJhcml0aG1ldGljIiwKICAgICAgICAgICAgICAgICBjb2xfcmVuYW1lID0gInJldHVybnMiKSU+JQogICAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IHJldHVybnMsIGZpbGwgPSBzeW1ib2wpKStnZW9tX2RlbnNpdHkoc3RhdCA9ICJpZGVudGl0eSIsYWxwaGE9MC42KSArCiAgbGFicyh0aXRsZSA9ICIgTW9udGhseSBSZXR1cm5zIiwKICAgICAgICAgc3VidGl0bGUgPSAiIiwKICAgICAgICAgeSA9ICJNb250aGx5IFJldHVybnMiLCB4ID0gIiIpICsgCiAgICBmYWNldF93cmFwKH4gc3ltYm9sLCBuY29sID0gMixzY2FsZXMgPSAiZnJlZSIpICsKICAgIHRoZW1lX3RxKCkgKyAKICAgIHNjYWxlX2ZpbGxfdHEoKQpgYGAKCgoKCmBgYHtyfQpsaWJyYXJ5KGdndGhlbWVzKQojQUFQTCA8LSB0cV9nZXQoIkFBUEwiKQojIFNNQQojQUFQTCAlPiUKCnN0b2NrZD10cV9nZXQoU3ltYm9scywgZ2V0ID0gInN0b2NrLnByaWNlcyIsIGZyb20gPSAiIDIwMTYtMDEtMDEiKQoKc3RvY2tkJT4lZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGFkanVzdGVkKSkgKwpnZW9tX2xpbmUoKSArICMgUGxvdCBzdG9jayBwcmljZQpnZW9tX2JiYW5kcyhhZXMoaGlnaCA9IGhpZ2gsIGxvdyA9IGxvdywgY2xvc2UgPSBjbG9zZSksIG1hX2Z1biA9IFNNQSwgbiA9IDEwMCxzaG93LmxlZ2VuZD1UUlVFKSArCmdndGhlbWVzOjp0aGVtZV9oYygpICsKICBzY2FsZV9jb2xvdXJfaGMoKStmYWNldF93cmFwKH4gIHN5bWJvbCwgbmNvbCA9IDIsc2NhbGVzID0gImZyZWUiKSAKI2Nvb3JkX3hfZGF0ZSh4bGltID0gYyh0b2RheSgpIC0geWVhcnMoMSksIHRvZGF5KCkpLCB5bGltID0gYygxNSwgMzApKQoKYGBgCgoKCgpDb252ZXJ0IHN0b2NrIHJldHVybnMgdG8gdGltZSBzZXJpZXMgb2JqZWN0LgoKYGBge3J9CnN0b2NrX3JldHVybnM9c3RvY2tfcmV0dXJucyU+JXRrX3h0cygpCgojc3RvY2tfcmV0dXJucyU+JXRrX3pvbygpLHRrX3RzKCksdGtfeHRzKCkKCnN0b2NrX3JldHVybnMlPiVoZWFkKCkKYGBgCgoKCgpgYGB7cn0KIyBTYXZlIG1lYW4gcmV0dXJuIHZlY3RvciBhbmQgc2FtcGxlIGNvdmFyaWFuY2UgbWF0cml4CnJldHVybnMucG9ydGZvbGlvPC1uYS5vbWl0KHN0b2NrX3JldHVybnMpCm1lYW5SZXR1cm5zIDwtIGNvbE1lYW5zKHJldHVybnMucG9ydGZvbGlvKQpjb3ZNYXQgPC0gY292KHJldHVybnMucG9ydGZvbGlvKQpgYGAKCgoKCgogVGhlIG9wdGltYWwgcG9ydGZvbGlvIGluIHlvdXIgc2V0dGluZyBpcyBpbmRlcGVuZGVudCBvZiB0aGUgaW5pdGlhbCB3ZWlnaHRzLgogCmBgYHtyfQpwIDwtIHBvcnRmb2xpby5zcGVjKGFzc2V0cyA9IGNvbG5hbWVzKHJldHVybnMucG9ydGZvbGlvKSkKcApgYGAKIAoKCgpNYXJrb3dpdHogT3B0aW1pemF0aW9uIGludm9sdmVzIG1pbmltaXppbmcgdGhlIHJpc2sodmFyaWFuY2UpIG9mIHJldHVybnMgYW5kIG1heGltaXppbmcgcmV0dXJucy4KCmBgYHtyfQpwIDwtIGFkZC5vYmplY3RpdmUocG9ydGZvbGlvID0gcCwgdHlwZSA9ICJyaXNrIiwgbmFtZSA9ICJ2YXIiKQpwIDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbyA9IHAsIHR5cGUgPSAiZnVsbF9pbnZlc3RtZW50IikKYGBgCgpUaGUgZnVsbF9pbnZlc3RtZW50IHBhcnQgaXMgZXF1aXZhbGVudCB0byBzZXR0aW5nIGEgY29uc3RyYWludCBvbiB0aGUgc3VtIG9mIHRoZSBwb3J0Zm9saW8gd2VpZ2h0cyBzdWNoIHRoYXQgdGhleSBhbHdheXMgc3VtLXVwIHRvIDEuIFRoaXMgaXMgYSBjYXNlIHdoZXJlIHRoZSAgaW52ZXN0b3IgIGNhcmVzIGFib3V0IHRoZSByaXNrIG9mIHRoZSBwb3J0Zm9saW8uIFlvdXIgb3B0aW1pemF0aW9uIHRoZXJlZm9yZSByZXR1cm5zIHRoZSBwb3J0Zm9saW8gd2VpZ2h0cyB3aGljaCBhdHRhaW4gdGhlIGxvd2VzdCBwb3NzaWJsZSBwb3J0Zm9saW8gdmFyaWFuY2UuIFRoaXMgaXMgdGhlIGdsb2JhbCBtaW5pbXVtIHZhcmlhbmNlIHBvcnRmb2xpby4gSWYgdGhlIGVmZmljaWVudCBwb3J0Zm9saW8gaXMgb2YgaW50ZXJlc3QsIHRoZW4gICBhbiBhZGRpdGlvbmFsIGNvbnN0cmFpbnQsIG5hbWVseSB0aGUgbWluaW1hbCBleHBlY3RlZCByZXR1cm4gY2FuIGJlIGFkZGVkLgoKYGBge3J9CnAgPC0gYWRkLmNvbnN0cmFpbnQocG9ydGZvbGlvPXAsIHR5cGUgPSAicmV0dXJuIiwgICAgIHJldHVybl90YXJnZXQ9IDAuMDAzNSkKYGBgCgoKVGhlIHJldHVybl90YXJnZXQ9MC4wMDM1IGNhbiBiZSByZXBsYWNlZCB3aXRoIGFueSBudW1iZXIsSSBoYXZlIGNob3NlbiB0aGUgb3ZlcmFsbCBtZWFuIG9mIHJldHVybnMuWW91IGNhbiBhbHNvIGNob3NlIHNvbWV0aGluZyBzdWNoIGFzIDAuMTUvMjUwIChUaGVyZSBhcmUgMjUwICB3b3JrIGRheXMgaW4gYSB5ZWFyKSB0byByZWZsZWN0IHRoYXQgeW91IGhhdmUgZGFpbHkgZGF0YSBhbmQgaW4gdGhpcyBjYXNlIHlvdSB3b3VsZCBsaWtlIHRvIGhhdmUgYSBwb3J0Zm9saW8gd2hpY2ggbWFrZXMgMTUlIHBlciB5ZWFyIGluIGV4cGVjdGF0aW9uLgoKVGhlIGlucHV0IFIgc2hvdWxkIGJlIHRoZSB0aW1lLXNlcmllcyBvZiByZXR1cm5zIHlvdSBoYXZlLiBZb3UgYWxzbyBzcGVjaWZ5IHRoZSBvcHRpbWl6aW5nIGZ1bmN0aW9uIGFwcm9wcmlhdGUgZm9yIHRoZSBvYmplY3RpdmUgZnVuY3Rpb24gLGhlcmUgaW4gdGhpcyBjYXNlIFJPSS4gCgpgYGB7cn0KI09wdGltaXplCm9wdGltaXplLnBvcnRmb2xpbyhSPXJldHVybnMucG9ydGZvbGlvLCBwb3J0Zm9saW8gPSBwLCAKICAgICAgICAgIG9wdGltaXplX21ldGhvZCA9ICJST0kiLCB0cmFjZSA9IFRSVUUpCmBgYAoKCgoKCgoKCmNyZWF0aW5nIGEgcG9ydGZvbGlvIHNwZWNpZmljYXRpb24uIFRoaXMgY2FuIGJlIGRvbmUgYnkgdXNpbmcgcG9ydGZvbGlvLnNwZWMoKQoKYGBge3J9CiMgU3RhcnQgd2l0aCB0aGUgbmFtZXMgb2YgdGhlIGFzc2V0cwpwb3J0IDwtIHBvcnRmb2xpby5zcGVjKGFzc2V0cyA9IGNvbG5hbWVzKHN0b2NrX3JldHVybnMpKQpgYGAKCgpOb3cgZm9yIHNvbWUgY29uc3RyYWludHMuIExldOKAmXMgdXNlIHRoZSBmb2xsb3dpbmc6CgpCb3ggY29uc3RyYWludHMKTGV2ZXJhZ2UgKHdlaWdodCBzdW0pCgoKYGBge3J9CiMgQm94CnBvcnQgPC0gYWRkLmNvbnN0cmFpbnQocG9ydCwgdHlwZSA9ICJib3giLCBtaW4gPSAwLjA1LCBtYXggPSAwLjgpCgojIExldmVyYWdlCnBvcnQgPC0gYWRkLmNvbnN0cmFpbnQocG9ydGZvbGlvID0gcG9ydCwgdHlwZSA9ICJmdWxsX2ludmVzdG1lbnQiKQpgYGAKClRoZSByYW5kb20gc29sdmVyIGlzIHVzZWQgdG8gY3JlYXRlIGEgc2V0IG9mIGZlYXNpYmxlIHBvcnRmb2xpb3MgdGhhdCBzYXRpc2Z5IGFsbCB0aGUgY29uc3RyYWludHMgc3BlY2lmaWVkIGFib3ZlLgoKCmBgYHtyfQojIEdlbmVyYXRlIHJhbmRvbSBwb3J0Zm9saW9zCnJwb3J0Zm9saW9zIDwtIHJhbmRvbV9wb3J0Zm9saW9zKHBvcnQsIHBlcm11dGF0aW9ucyA9IDUwMDAsIHJwX21ldGhvZCA9ICJzYW1wbGUiKQpgYGAKCgpBZGQgc29tZSBvYmplY3RpdmVzIGFuZCBvcHRpbWl6ZS4gRm9yIHNpbXBsaWNpdHnigJlzIHNha2UgbGV04oCZcyBkbyBzb21lIG1lYW4tdmFyaWFuY2Ugb3B0aW1pemF0aW9uLgoKCmBgYHtyfQoKIyBHZXQgbWluaW11bSB2YXJpYW5jZSBwb3J0Zm9saW8KbWludmFyLnBvcnQgPC0gYWRkLm9iamVjdGl2ZShwb3J0LCB0eXBlID0gInJpc2siLCBuYW1lID0gInZhciIpCgojIE9wdGltaXplCm1pbnZhci5vcHQgPC0gb3B0aW1pemUucG9ydGZvbGlvKHN0b2NrX3JldHVybnMsIG1pbnZhci5wb3J0LCBvcHRpbWl6ZV9tZXRob2QgPSAicmFuZG9tIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJwID0gcnBvcnRmb2xpb3MpCgojIEdlbmVyYXRlIG1heGltdW0gcmV0dXJuIHBvcnRmb2xpbwptYXhyZXQucG9ydCA8LSBhZGQub2JqZWN0aXZlKHBvcnQsIHR5cGUgPSAicmV0dXJuIiwgbmFtZSA9ICJtZWFuIikKCiMgT3B0aW1pemUKbWF4cmV0Lm9wdCA8LSBvcHRpbWl6ZS5wb3J0Zm9saW8oc3RvY2tfcmV0dXJucywgbWF4cmV0LnBvcnQsIG9wdGltaXplX21ldGhvZCA9ICJyYW5kb20iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcnAgPSBycG9ydGZvbGlvcykKCiMgR2VuZXJhdGUgdmVjdG9yIG9mIHJldHVybnMKbWlucmV0IDwtIDAuMDYvMTAwCm1heHJldCA8LSBtYXhyZXQub3B0JHdlaWdodHMgJSolIG1lYW5SZXR1cm5zCgp2ZWMgPC0gc2VxKG1pbnJldCwgbWF4cmV0LCBsZW5ndGgub3V0ID0gNTApCgoKCmBgYAoKCgoKV2UgY2FuIGJ1aWxkIHRoZSBlZmZpY2llbnQgZnJvbnRpZXIgYXQgdGhpcyBzdGFnZSBhZnRlciBzcGVjaWZ5aW5nIHRoZSBtaW5pbXVtIHZhcmlhbmNlIGFzIHdlbGwgYXMgdGhlIG1heGltdW0gcmV0dXJuIHBvcnRmb2xpb3MuIFdlICBhZGQgYSB3ZWlnaHQgY29uY2VudHJhdGlvbiBvYmplY3RpdmUgIHRvIHByZXZlbnQgIGhpZ2hseSBjb25jZW50cmF0ZWQgcG9ydGZvbGlvcy4gcmFuZG9tX3BvcnRmb2xpb3MoKSBmdW5jdGlvbiBpZ25vcmVzIGFueSBkaXZlcnNpZmljYXRpb24gY29uc3RyYWludHMuCgoKCgoKCgpgYGB7cn0KCiMgR2V0IGEgY2hhcmFjdGVyIHZlY3RvciBvZiB0aGUgZnVuZCBuYW1lcwpmdW5kLm5hbWVzIDwtIGNvbG5hbWVzKHN0b2NrX3JldHVybnMpCgpgYGAKCgojIyMjIENyZWF0aW5nIHRoZSBQb3J0Zm9saW8gT2JqZWN0ClRoZSBwb3J0Zm9saW8gb2JqZWN0IGlzIGluc3RhbnRpYXRlZCB3aXRoIHRoZSBwb3J0Zm9saW8uc3BlYyBmdW5jdGlvbi4gVGhlIG1haW4gYXJndW1lbnQgdG8KcG9ydGZvbGlvLnNwZWMgaXMgYXNzZXRzLCB0aGlzIGlzIGEgcmVxdWlyZWQgYXJndW1lbnQuIFRoZSBhc3NldHMgYXJndW1lbnQgY2FuIGJlIGEgc2NhbGFyIHZhbHVlCmZvciB0aGUgbnVtYmVyIG9mIGFzc2V0cywgYSBjaGFyYWN0ZXIgdmVjdG9yIG9mIGZ1bmQgbmFtZXMsIG9yIGEgbmFtZWQgdmVjdG9yIG9mIGluaXRpYWwgd2VpZ2h0cy4gSWYKaW5pdGlhbCB3ZWlnaHRzIGFyZSBub3Qgc3BlY2kMZWQsIGFuIGVxdWFsIHdlaWdodCBwb3J0Zm9saW8gd2lsbCBiZSBhc3N1bWVkLgpUaGUgcHNwZWMgb2JqZWN0IGlzIGFuIFMzIG9iamVjdCBvZiBjbGFzcyAicG9ydGZvbGlvIi4gV2hlbiAMcnN0IGNyZWF0ZWQsIHRoZSBwb3J0Zm9saW8gb2JqZWN0CmhhcyBhbiBlbGVtZW50IG5hbWVkIGFzc2V0cyB3aXRoIHRoZSBpbml0aWFsIHdlaWdodHMsIGFuIGVsZW1lbnQgbmFtZWQgY2F0ZWdvcnlfbGFiZWxzLCBhbgplbGVtZW50IG5hbWVkIHdlaWdodF9zZXEgd2l0aCBzZXF1ZW5jZSBvZiB3ZWlnaHRzIGlmIHNwZWNpDGVkLCBhbiBlbXB0eSBjb25zdHJhaW50cyBsaXN0IGFuZCBhbgplbXB0eSBvYmplY3RpdmVzIGxpc3QuCgpgYGB7cn0KIyBTcGVjaWZ5IGEgcG9ydGZvbGlvIG9iamVjdCBieSBwYXNzaW5nIGEgY2hhcmFjdGVyIHZlY3RvciBmb3IgdGhlCiMgYXNzZXRzIGFyZ3VtZW50Lgpwc3BlYyA8LSBwb3J0Zm9saW8uc3BlYyhhc3NldHM9ZnVuZC5uYW1lcykKcHJpbnQuZGVmYXVsdChwc3BlYykKCmBgYAoKIyMjIyBBZGRpbmcgQ29uc3RyYWludHMgdG8gdGhlIFBvcnRmb2xpbyBPYmplY3QKQWRkaW5nIGNvbnN0cmFpbnRzIHRvIHRoZSBwb3J0Zm9saW8gb2JqZWN0IGlzIGRvbmUgd2l0aCBhZGQuY29uc3RyYWludC4gVGhlIGFkZC5jb25zdHJhaW50CmZ1bmN0aW9uIGlzIHRoZSBtYWluIGludGVyZmFjZSBmb3IgYWRkaW5nIGFuZC9vciB1cGRhdGluZyBjb25zdHJhaW50cyB0byB0aGUgcG9ydGZvbGlvIG9iamVjdC4gVGhpcwpmdW5jdGlvbiBhbGxvd3MgdGhlIHVzZXIgdG8gc3BlY2lmeSB0aGUgcG9ydGZvbGlvIHRvIGFkZCB0aGUgY29uc3RyYWludHMgdG8sIHRoZSB0eXBlIG9mIGNvbnN0cmFpbnRzLAphcmd1bWVudHMgZm9yIHRoZSBjb25zdHJhaW50LCBhbmQgd2hldGhlciBvciBub3QgdG8gZW5hYmxlIHRoZSBjb25zdHJhaW50IChlbmFibGVkPVRSVUUgaXMgdGhlCmRlZmF1bHQpLiBJZiB1cGRhdGluZyBhbiBleGlzdGluZyBjb25zdHJhaW50LCB0aGUgaW5kZXhudW0gYXJndW1lbnQgY2FuIGJlIHNwZWNpDGVkLgoKIyMjIyMgU3VtIG9mIFdlaWdodHMgQ29uc3RyYWludApUaGUgd2VpZ2h0X3N1bSBjb25zdHJhaW50IHNwZWNpDGVzIHRoZSBjb25zdHJhaW50IG9uIHRoZSBzdW0gb2YgdGhlIHdlaWdodHMuIEFsaWFzZXMgZm9yIHRoZQp3ZWlnaHRfc3VtIGNvbnN0cmFpbnQgdHlwZSBpbmNsdWRlIHdlaWdodCBhbmQgbGV2ZXJhZ2UuIEhlcmUgd2UgYWRkIGEgY29uc3RyYWludCB0aGF0IHRoZQp3ZWlnaHRzIG11c3Qgc3VtIHRvIDEsIG9yIHRoZSBmdWxsIGludmVzdG1lbnQgY29uc3RyYWludC4KCmBgYHtyfQojIEFkZCB0aGUgZnVsbCBpbnZlc3RtZW50IGNvbnN0cmFpbnQgdGhhdCBzcGVjaWZpZXMgdGhlIHdlaWdodHMgbXVzdCBzdW0gdG8gMS4KcHNwZWMgPC0gYWRkLmNvbnN0cmFpbnQocG9ydGZvbGlvPXBzcGVjLAp0eXBlPSJ3ZWlnaHRfc3VtIiwKbWluX3N1bT0xLAptYXhfc3VtPTEpCgpgYGAKCgpUaGVyZSBhcmUgdHdvIHNwZWNpYWwgY2FzZXMgZm9yIHRoZSBsZXZlcmFnZSBjb25zdHJhaW50OgoxLiBUaGUgc3VtIG9mIHRoZSB3ZWlnaHRzIGVxdWFsIDEsIGkuZS4gdGhlIGZ1bGwgaW52ZXN0bWVudCBjb25zdHJhaW50LiBUaGUgZnVsbCBpbnZlc3RtZW50IGNvbi0Kc3RyYWludCBjYW4gYmUgc3BlY2kMZWQgd2l0aCB0eXBlPSJmdWxsX2ludmVzdG1lbnQiLiBUaGlzIGF1dG9tYXRpY2FsbHkgc2V0cyBtaW5fc3VtPTEKYW5kIG1heF9zdW09MS4KMi4gVGhlIHN1bSBvZiB0aGUgd2VpZ2h0cyBlcXVhbCAwLCBpLmUuIHRoZSBkb2xsYXIgbmV1dHJhbCBvciBhY3RpdmUgY29uc3RyYWludC4gVGhpcyBjb25zdHJhaW50CmNhbiBiZSBzcGVjaWZpZWQgd2l0aCB0eXBlPSJkb2xsYXJfbmV1dHJhbCIgb3IgdHlwZT0iYWN0aXZlIi4KCmBgYHtyfQojIFRoZSBmdWxsIGludmVzdG1lbnQgY29uc3RyYWludCBjYW4gYWxzbyBiZSBzcGVjaWZpZWQgd2l0aCB0eXBlPSJmdWxsX2ludmVzdG1lbnQiCiMgcHNwZWMgPC0gYWRkLmNvbnN0cmFpbnQocG9ydGZvbGlvPXBzcGVjLCB0eXBlPSJmdWxsX2ludmVzdG1lbnQiKQojIEFub3RoZXIgY29tbW9uIGNvbnN0cmFpbnQgaXMgdGhhdCBwb3J0Zm9saW8gd2VpZ2h0cyBzdW0gdG8gMC4KIyBUaGlzIGNhbiBiZSBzcGVjaWZpZWQgYW55IG9mIHRoZSBmb2xsb3dpbmcgd2F5cwojIHBzcGVjIDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1wc3BlYywgdHlwZT0id2VpZ2h0X3N1bSIsCiMgbWluX3N1bT0wLAojIG1heF9zdW09MCkKIyBwc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89cHNwZWMsIHR5cGU9ImRvbGxhcl9uZXV0cmFsIikKIyBwc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89cHNwZWMsIHR5cGU9ImFjdGl2ZSIpCmBgYAoKCiMjIyMgQm94IENvbnN0cmFpbnQKQm94IGNvbnN0cmFpbnRzIGFsbG93cyB0aGUgdXNlciB0byBzcGVjaWZ5IHVwcGVyIGFuZCBsb3dlciBib3VuZHMgb24gdGhlIHdlaWdodHMgb2YgdGhlIGFzc2V0cy4KSGVyZSB3ZSBhZGQgYm94IGNvbnN0cmFpbnRzIGZvciB0aGUgYXNzZXQgd2VpZ2h0cyBzbyB0aGF0IHRoZSBtaW5pbXVtIHdlaWdodCBvZiBhbnkgYXNzZXQgbXVzdApiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gMC4wNSBhbmQgdGhlIG1heGltdW0gd2VpZ2h0IG9mIGFueSBhc3NldCBtdXN0IGJlIGxlc3MgdGhhbiBvciBlcXVhbAp0byAwLjQuIFRoZSB2YWx1ZXMgZm9yIG1pbiBhbmQgbWF4IGNhbiBiZSBwYXNzZWQgaW4gYXMgc2NhbGFycyBvciB2ZWN0b3JzLiBJZiBtaW4gYW5kIG1heCBhcmUKc2NhbGFycywgdGhlIHZhbHVlcyBmb3IgbWluIGFuZCBtYXggd2lsbCBiZSByZXBsaWNhdGVkIGFzIHZlY3RvcnMgdG8gdGhlIGxlbmd0aCBvZiBhc3NldHMuIElmIG1pbiBhbmQKbWF4IGFyZSBub3Qgc3BlY2kMZWQsIGEgbWluaW11bSB3ZWlnaHQgb2YgMCBhbmQgbWF4aW11bSB3ZWlnaHQgb2YgMSBhcmUgYXNzdW1lZC4gTm90ZSB0aGF0Cm1pbiBhbmQgbWF4IGNhbiBiZSBzcGVjaQxlZCBhcyB2ZWN0b3JzIHdpdGggZGkLZXJlbnQgd2VpZ2h0cyBmb3IgbGluZWFyIGluZXF1YWxpdHkgY29uc3RyYWludHMuCgpgYGB7cn0KIyBBZGQgYm94IGNvbnN0cmFpbnRzCnBzcGVjIDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1wc3BlYywKIHR5cGU9ImJveCIsCiBtaW49MC4wNSwKIG1heD0wLjQpCgojIG1pbiBhbmQgbWF4IGNhbiBhbHNvIGJlIHNwZWNpZmllZCBwZXIgYXNzZXQKIyBwc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89cHNwZWMsCiMgdHlwZT0iYm94IiwKIyBtaW49YygwLjA1LCAwLCAwLjA4LCAwLjEpLAojIG1heD1jKDAuNCwgMC4zLCAwLjcsIDAuNTUpKQoKIyBBIHNwZWNpYWwgY2FzZSBvZiBib3ggY29uc3RyYWludHMgaXMgbG9uZyBvbmx5IHdoZXJlIG1pbj0wIGFuZCBtYXg9MQojIFRoZSBkZWZhdWx0IGFjdGlvbiBpcyBsb25nIG9ubHkgaWYgbWluIGFuZCBtYXggYXJlIG5vdCBzcGVjaWZpZWQKIyBwc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89cHNwZWMsIHR5cGU9ImJveCIpCiMgcHNwZWMgPC0gYWRkLmNvbnN0cmFpbnQocG9ydGZvbGlvPXBzcGVjLCB0eXBlPSJsb25nX29ubHkiKQoKYGBgCgoKIyMjIyBHcm91cCBDb25zdHJhaW50Ckdyb3VwIGNvbnN0cmFpbnRzIGFsbG93IHRoZSB1c2VyIHRvIHNwZWNpZnkgdGhlIHRoZSBzdW0gb2Ygd2VpZ2h0cyBieSBncm91cC4gR3JvdXAgY29uc3RyYWludHMKYXJlIGN1cnJlbnRseSBzdXBwb3J0ZWQgYnkgdGhlIFJPSSwgREVvcHRpbSwgYW5kIHJhbmRvbSBwb3J0Zm9saW8gc29sdmVycy4gVGhlIGZvbGxvd2luZyBjb2RlCmdyb3VwcyB0aGUgYXNzZXRzIHN1Y2ggdGhhdCB0aGUgDHJzdCAzIGFzc2V0cyBhcmUgZ3JvdXBlZCB0b2dldGhlciBsYWJlbGVkIEdyb3VwQSBhbmQgdGhlIGZvdXJ0aAphc3NldCBpcyBpbiBpdHMgb3duIGdyb3VwIGxhYmVsZWQgR3JvdXBCLiBUaGUgZ3JvdXBfbWluIGFyZ3VtZW50IHNwZWNpDGVzIHRoYXQgdGhlIHN1bSBvZiB0aGUKd2VpZ2h0cyBpbiBHcm91cEEgbXVzdCBiZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gMC4xIGFuZCB0aGUgc3VtIG9mIHRoZSB3ZWlnaHRzIGluIEdyb3VwQgptdXN0IGJlIGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAwLjE1LiBUaGUgZ3JvdXBfbWF4IGFyZ3VtZW50IHNwZWNpDGVzIHRoYXQgdGhlIHN1bSBvZiB0aGUKd2VpZ2h0cyBpbiBHcm91cEEgbXVzdCBiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gMC44NSBhbmQgdGhlIHN1bSBvZiB0aGUgd2VpZ2h0cyBpbiBHcm91cEIgbXVzdApiZSBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gMC41NS5UaGUgZ3JvdXBfbGFiZWxzIGFyZ3VtZW50IGlzIG9wdGlvbmFsIGFuZCBpcyB1c2VmdWwgaWYgZ3JvdXBzIGlzIG5vdAphIG5hbWVkIGxpc3QgZm9yIGxhYmVsaW5nIGdyb3VwcyBpbiB0ZXJtcyBvZiBtYXJrZXQgY2FwaXRhbGl6YXRpb24sIHNlY3RvciwgZXRjLgoKYGBge3J9CiMgQWRkIGdyb3VwIGNvbnN0cmFpbnRzCnBzcGVjIDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1wc3BlYywgdHlwZT0iZ3JvdXAiLApncm91cHM9bGlzdChncm91cEE9YygxLCAyLCAzKSwKZ3JvdUI9NCksCmdyb3VwX21pbj1jKDAuMSwgMC4xNSksCmdyb3VwX21heD1jKDAuODUsIDAuNTUpKQpgYGAKCgojIyMjIFBvc2l0aW9uIExpbWl0IENvbnN0cmFpbnQKVGhlIHBvc2l0aW9uIGxpbWl0IGNvbnN0cmFpbnQgYWxsb3dzIHRoZSB1c2VyIHRvIHNwZWNpZnkgbGltaXRzIG9uIHRoZSBudW1iZXIgb2YgYXNzZXRzIHdpdGggbm9uLQp6ZXJvLCBsb25nLCBvciBzaG9ydCBwb3NpdGlvbnMuIFRoZSBST0kgc29sdmVyIGludGVyZmFjZXMgdG8gdGhlIFJnbHBrIHBhY2thZ2UgKGkuZS4gdXNpbmcgdGhlIGdscGsKcGx1Z2luKSBmb3Igc29sdmluZyBtYXhpbWl6aW5nIHJldHVybiBhbmQgRVRML0VTL2NWYVIgb2JqZWN0aXZlcy4gVGhlIFJnbHBrIHBhY2thZ2Ugc3VwcG9ydHMKaW50ZWdlciBwcm9ncmFtbWluZyBhbmQgdGh1cyBzdXBwb3J0cyBwb3NpdGlvbiBsaW1pdCBjb25zdHJhaW50cyBmb3IgdGhlIG1heF9wb3MgYXJndW1lbnQuIFRoZQpxdWFkcHJvZyBwYWNrYWdlIGRvZXMgbm90IHN1cHBvcnQgaW50ZWdlciBwcm9ncmFtbWluZywgYW5kIHRoZXJlZm9yZSBtYXhfcG9zIGlzIG5vdCBzdXBwb3J0ZWQKZm9yIHRoZSBST0kgc29sdmVyIHVzaW5nIHRoZSBxdWFkcHJvZyBwbHVnaW4uIE5vdGUgdGhhdCBtYXhfcG9zX2xvbmcgYW5kIG1heF9wb3Nfc2hvcnQgYXJlCm5vdCBzdXBwb3J0ZWQgZm9yIGVpdGhlciBST0kgc29sdmVyLiBBbGwgcG9zaXRpb24gbGltaXQgY29uc3RyYWludHMgYXJlIGZ1bGx5IHN1cHBvcnRlZCBmb3IgREVvcHRpbQphbmQgcmFuZG9tIHNvbHZlcnMuCgoKYGBge3J9CgojIEFkZCBwb3NpdGlvbiBsaW1pdCBjb25zdHJhaW50IHN1Y2ggdGhhdCB3ZSBoYXZlIGEgbWF4aW11bSBudW1iZXIgb2YgdGhyZWUgYXNzZXRzIHdpdGggbm9uLXplcm8gPiAKCnBzcGVjIDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1wc3BlYywgdHlwZT0icG9zaXRpb25fbGltaXQiLCBtYXhfcG9zPTMpCgojIENhbiBhbHNvIHNwZWNpZnkgbWF4aW11bSBudW1iZXIgb2YgbG9uZyBwb3NpdGlvbnMgYW5kIHNob3J0IHBvc2l0aW9ucwojIHBzcGVjIDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1wc3BlYywgdHlwZT0icG9zaXRpb25fbGltaXQiLCBtYXhfcG9zX2xvbmc9MywgbWF4X3Bvc19zaG9ydD0zKQoKYGBgCgoKIyMjIyBEaXZlcnNpZmljYXRpb24gQ29uc3RyYWludApUaGUgZGl2ZXJzaQxjYXRpb24gY29uc3RyYWludCBhbGxvd3MgdGhlIHVzZXIgdG8gdGFyZ2V0IGRpdmVyc2kMY2F0aW9uLiBEaXZlcnNpDGNhdGlvbiBpcyBkZQxuZWQKYXMgZGl2ZXJzaWZpY2F0aW9uID0gUE4KaT0xIHcyCmkgZm9yIE4gYXNzZXRzLiBUaGUgZGl2ZXJzaQxjYXRpb24gY29uc3RyYWludCBpcyBpbXBsZW1lbnRlZCBmb3IgdGhlCmdsb2JhbCBvcHRpbWl6ZXJzIGJ5IGFwcGx5aW5nIGEgcGVuYWx0eSBpZiB0aGUgZGl2ZXJzaQxjYXRpb24gdmFsdWUgaXMgbW9yZSB0aGFuIDUlIGF3YXkgZnJvbQpkaXZfdGFyZ2V0LiBOb3RlIHRoYXQgZGl2ZXJzaQxjYXRpb24gYXMgYSBjb25zdHJhaW50IGlzIG5vdCBzdXBwb3J0ZWQgZm9yIHRoZSBST0kgc29sdmVycywgaXQgaXMKb25seSBzdXBwb3J0ZWQgZm9yIHRoZSBnbG9iYWwgbnVtZXJpYyBzb2x2ZXJzLgoKCmBgYHtyfQpwc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89cHNwZWMsIHR5cGU9ImRpdmVyc2lmaWNhdGlvbiIsIGRpdl90YXJnZXQ9MC43KQpgYGAKCgojIyMjIFR1cm5vdmVyIENvbnN0cmFpbnQKQSB0YXJnZXQgdHVybm92ZXIgY2FuIGJlIHNwZWNpZmllZCBhcyBhIGNvbnN0cmFpbnQuIFRoZSB0dXJub3ZlciBpcyBjYWxjdWxhdGVkIGZyb20gYSBzZXQgb2YgaW5pdGlhbAp3ZWlnaHRzLiBUaGUgaW5pdGlhbCB3ZWlnaHRzIGNhbiBiZSBzcGVjaQxlZCwgYnkgZGVmYXVsdCB0aGV5IGFyZSB0aGUgaW5pdGlhbCB3ZWlnaHRzIGluIHRoZSBwb3J0Zm9saW8Kb2JqZWN0LiBUaGUgdHVybm92ZXIgY29uc3RyYWludCBpcyBpbXBsZW1lbnRlZCBmb3IgdGhlIGdsb2JhbCBvcHRpbWl6ZXJzIGJ5IGFwcGx5aW5nIGEgcGVuYWx0eQppZiB0aGUgdHVybm92ZXIgdmFsdWUgaXMgbW9yZSB0aGFuIDUlIGF3YXkgZnJvbSB0dXJub3Zlcl90YXJnZXQuIE5vdGUgdGhhdCB0aGUgdHVybm92ZXIKY29uc3RyYWludCBpcyBub3QgY3VycmVudGx5IHN1cHBvcnRlZCBmb3IgcXVhZHJhdGljIHV0aWxpdHkgYW5kIG1pbmltdW0gdmFyaWFuY2UgcHJvYmxlbXMgdXNpbmcKdGhlIFJPSSBzb2x2ZXIuCgpgYGB7cn0KcHNwZWMgPC0gYWRkLmNvbnN0cmFpbnQocG9ydGZvbGlvPXBzcGVjLCB0eXBlPSJ0dXJub3ZlciIsIHR1cm5vdmVyX3RhcmdldD0wLjIpCmBgYAoKIyMjIyBUYXJnZXQgUmV0dXJuIENvbnN0cmFpbnQKVGhlIHRhcmdldCByZXR1cm4gY29uc3RyYWludCBhbGxvd3MgdGhlIHVzZXIgdG8gc3BlY2lmeSBhIHRhcmdldCBtZWFuIHJldHVybi4KCmBgYHtyfQpwc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89cHNwZWMsIHR5cGU9InJldHVybiIsIHJldHVybl90YXJnZXQ9MC4wMDcpCmBgYAoKCiMjIyMgIEZhY3RvciBFeHBvc3VyZSBDb25zdHJhaW50ClRoZSBmYWN0b3IgZXhwb3N1cmUgY29uc3RyYWludCBhbGxvd3MgdGhlIHVzZXIgdG8gc2V0IHVwcGVyIGFuZCBsb3dlciBib3VuZHMgb24gZXhwb3N1cmVzIHRvIHJpc2sKZmFjdG9ycy4gVGhlIGV4cG9zdXJlcyBjYW4gYmUgcGFzc2VkIGluIGFzIGEgdmVjdG9yIG9yIG1hdHJpeC4gSGVyZSB3ZSBzcGVjaWZ5IGEgdmVjdG9yIGZvciBCIHdpdGgKYXJiaXRyYXJ5IHZhbHVlcywgZS5nLiBiZXRhcyBvZiB0aGUgYXNzZXRzLCB3aXRoIGEgbWFya2V0IHJpc2sgZXhwb3N1cmUgcmFuZ2Ugb2YgMC42IHRvIDAuOS4KCgoKYGBge3J9CnBzcGVjIDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1wc3BlYywgdHlwZT0iZmFjdG9yX2V4cG9zdXJlIiwKQj1jKDAuMDgsIDAuMzcsIDAuNzksIDEuNDMsMC41LDAuNCksCmxvd2VyPTAuNiwgdXBwZXI9MC45KQpgYGAKCgoKIyMjIyBUcmFuc2FjdGlvbiBDb3N0IENvbnN0cmFpbnQKVGhlIHRyYW5zYWN0aW9uIGNvc3QgY29uc3RyYWludCBhbGxvd3MgdGhlIHVzZXIgdG8gc3BlY2lmeSBwcm9wb3J0aW9uYWwgdHJhbnNhY3Rpb24gY29zdHMuIFByb3Bvci0KdGlvbmFsIHRyYW5zYWN0aW9uIGNvc3QgY29uc3RyYWludHMgY2FuIGJlIGltcGxlbWVudGVkIGZvciBxdWFkcmF0aWMgdXRpbGl0eSBhbmQgbWluaW11bSB2YXJpYW5jZSA3CnByb2JsZW1zIHVzaW5nIHRoZSBST0kgc29sdmVyLiBUcmFuc2FjdGlvbiBjb3N0cyBhcmUgc3VwcG9ydGVkIGFzIGEgcGVuYWx0eSBmb3IgdGhlIGdsb2JhbCBudW1lcmljCnNvbHZlcnMuIEhlcmUgd2UgYWRkIHRoZSB0cmFuc2FjdGlvbiBjb3N0IGNvbnRyYWludCB3aXRoIHRoZSBwcm9wb3J0aW9uYWwgdHJhbnNhY3Rpb24gY29zdCB2YWx1ZSBvZgoxJS4KCmBgYHtyfQpwc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0Zm9saW89cHNwZWMsIHR5cGU9InRyYW5zYWN0aW9uX2Nvc3QiLCBwdGM9MC4wMSkKYGBgCgoKVGhlIHByaW50IG1ldGhvZCBmb3IgdGhlIHBvcnRmb2xpbyBvYmplY3Qgc2hvd3MgYSBjb25jaXNlIHZpZXcgb2YgdGhlIHBvcnRmb2xpbyBhbmQgdGhlIGNvbi0Kc3RyYWludHMgdGhhdCBoYXZlIGJlZW4gYWRkZWQuCgpgYGB7cn0KcHJpbnQocHNwZWMpCmBgYAoKCgoKVGhlIHN1bW1hcnkgbWV0aG9kIGdpdmVzIGEgbW9yZSBkZXRhaWxlZCB2aWV3IG9mIHRoZSBjb25zdHJhaW50cy4KCmBgYHtyfQpzdW1tYXJ5KHBzcGVjKQpgYGAKCgpUaGlzIGRlbW9uc3RyYXRlcyBhZGRpbmcgY29uc3RyYWludHMgdG8gdGhlIHBvcnRmb2xpbyBvYmplY3QuIEFzIGFuIGFsdGVybmF0aXZlIHRvIGFkZGluZwpjb25zdHJhaW50cyBkaXJlY3RseSB0byB0aGUgcG9ydGZvbGlvIG9iamVjdCwgY29uc3RyYWludHMgY2FuIGJlIHNwZWNpZmllZCBhcyBzZXBhcmF0ZSBvYmplY3RzLgoKIyMjIyBTcGVjaWZ5aW5nIENvbnN0cmFpbnRzIGFzIFNlcGFyYXRlIE9iamVjdHMKVGhlIGZvbGxvd2luZyBleGFtcGxlcyB3aWxsIGRlbW9uc3RyYXRlIGhvdyB0byBzcGVjaWZ5IGNvbnN0cmFpbnRzIGFzIHNlcGFyYXRlIG9iamVjdHMgZm9yIGFsbApjb25zdHJhaW50cyB0eXBlcy4KCmBgYHtyfQojIGZ1bGwgaW52ZXN0bWVudCBjb25zdHJhaW50CndlaWdodF9jb25zdHIgPC0gd2VpZ2h0X3N1bV9jb25zdHJhaW50KG1pbl9zdW09MSwgbWF4X3N1bT0xKQoKIyBib3ggY29uc3RyYWludApib3hfY29uc3RyIDwtIGJveF9jb25zdHJhaW50KGFzc2V0cz1wc3BlYyRhc3NldHMsIG1pbj0wLCBtYXg9MSkKCiMgZ3JvdXAgY29uc3RyYWludApncm91cF9jb25zdHI8LWdyb3VwX2NvbnN0cmFpbnQoYXNzZXRzPXBzcGVjJGFzc2V0cywKZ3JvdXBzPWxpc3QoYygxLCAyLCAzKSwKNCksCmdyb3VwX21pbj1jKDAuMSwgMC4xNSksCmdyb3VwX21heD1jKDAuODUsIDAuNTUpLApncm91cF9sYWJlbHM9YygiR3JvdXBBIiwgIkdyb3VwQiIpKQoKIyBwb3NpdGlvbiBsaW1pdCBjb25zdHJhaW50CnBvc2xpbWl0X2NvbnN0ciA8LSBwb3NpdGlvbl9saW1pdF9jb25zdHJhaW50KGFzc2V0cz1wc3BlYyRhc3NldHMsIG1heF9wb3M9MykKCiMgZGl2ZXJzaWZpY2F0aW9uIGNvbnN0cmFpbnQKZGl2X2NvbnN0ciA8LSBkaXZlcnNpZmljYXRpb25fY29uc3RyYWludChkaXZfdGFyZ2V0PTAuNykKCiMgdHVybm92ZXIgY29uc3RyYWludAp0b19jb25zdHIgPC0gdHVybm92ZXJfY29uc3RyYWludCh0dXJub3Zlcl90YXJnZXQ9MC4yKQoKIyB0YXJnZXQgcmV0dXJuIGNvbnN0cmFpbnQKcmV0X2NvbnN0ciA8LSByZXR1cm5fY29uc3RyYWludChyZXR1cm5fdGFyZ2V0PTAuMDA3KQoKIyBmYWN0b3IgZXhwb3N1cmUgY29uc3RyYWludApleHBfY29uc3RyIDwtIGZhY3Rvcl9leHBvc3VyZV9jb25zdHJhaW50KGFzc2V0cz1wc3BlYyRhc3NldHMsCkI9YygwLjA4LCAwLjM3LCAwLjc5LCAxLjQzLDAuNSwwLjQpLAogbG93ZXI9MC42LCB1cHBlcj0wLjkpCgojIHRyYW5zYWN0aW9uIGNvc3QgY29uc3RyYWludApwdGNfY29uc3RyIDwtIHRyYW5zYWN0aW9uX2Nvc3RfY29uc3RyYWludChhc3NldHM9cHNwZWMkYXNzZXRzLCBwdGM9MC4wMSkKCmBgYAoKCiMjIyMgQWRkaW5nIE9iamVjdGl2ZXMKT2JqZWN0aXZlcyBjYW4gYmUgYWRkZWQgdG8gdGhlIHBvcnRmb2xpbyBvYmplY3Qgd2l0aCBhZGQub2JqZWN0aXZlLiBUaGUgYWRkLm9iamVjdGl2ZSBmdW5jdGlvbgppcyB0aGUgbWFpbiBmdW5jdGlvbiBmb3IgYWRkaW5nIGFuZC9vciB1cGRhdGluZyBidXNpbmVzcyBvYmplY3RpdmVzIHRvIHRoZSBwb3J0Zm9saW8gb2JqZWN0LiBUaGlzCmZ1bmN0aW9uIGFsbG93cyB0aGUgdXNlciB0byBzcGVjaWZ5IHRoZSBwb3J0Zm9saW8gdG8gYWRkIHRoZSBvYmplY3RpdmVzIHRvLCB0aGUgdHlwZSAoY3VycmVudGx5CidyZXR1cm4nLCAncmlzaycsICdyaXNrIGJ1ZGdldCcsIG9yICd3ZWlnaHQgY29uY2VudHJhdGlvbicpLCBuYW1lIG9mIHRoZSBvYmplY3RpdmUgZnVuY3Rpb24sIGFyZ3VtZW50cwp0byB0aGUgb2JqZWN0aXZlIGZ1bmN0aW9uLCBhbmQgd2hldGhlciBvciBub3QgdG8gZW5hYmxlIHRoZSBvYmplY3RpdmUuIElmIHVwZGF0aW5nIGFuIGV4aXN0aW5nCmNvbnN0cmFpbnQsIHRoZSBpbmRleG51bSBhcmd1bWVudCBjYW4gYmUgc3BlY2lmaWVkLgoKIyMjIyBQb3J0Zm9saW8gUmlzayBPYmplY3RpdmUKVGhlIHBvcnRmb2xpbyByaXNrIG9iamVjdGl2ZSBhbGxvd3MgdGhlIHVzZXIgdG8gc3BlY2lmeSBhIHJpc2sgZnVuY3Rpb24gdG8gbWluaW1pemUgSGVyZSB3ZSBhZGQKYSByaXNrIG9iamVjdGl2ZSB0byBtaW5pbWl6ZSBwb3J0Zm9saW8gZXhwZWN0ZWQgdGFpbCBsb3NzIHdpdGggYSBjb24MZGVuY2UgbGV2ZWwgb2YgMC45NS4gT3RoZXIKZGVmYXVsdCBhcmd1bWVudHMgdG8gdGhlIGZ1bmN0aW9uIGNhbiBiZSBwYXNzZWQgaW4gYXMgYSBuYW1lZCBsaXN0IHRvIGFyZ3VtZW50cy4gTm90ZSB0aGF0IHRoZQpuYW1lIG9mIHRoZSBmdW5jdGlvbiBtdXN0IGNvcnJlc3BvbmQgdG8gYSBmdW5jdGlvbiBpbiBSLiBNYW55IGZ1bmN0aW9ucyBhcmUgYXZhaWxhYmxlIGluIHRoZQpQZXJmb3JtYW5jZUFuYWx5dGljcyBwYWNrYWdlIG9yIGEgdXNlciBkZQxuZWQgZnVuY3Rpb24uCgoKYGBge3J9CnBzcGVjIDwtIGFkZC5vYmplY3RpdmUocG9ydGZvbGlvPXBzcGVjLAogdHlwZT0ncmlzaycsCiBuYW1lPSdFVEwnLAogYXJndW1lbnRzPWxpc3QocD0wLjk1KSkKYGBgCgoKIyMjIyBQb3J0Zm9saW8gUmV0dXJuIE9iamVjdGl2ZQpUaGUgcmV0dXJuIG9iamVjdGl2ZSBhbGxvd3MgdGhlIHVzZXIgdG8gc3BlY2lmeSBhIHJldHVybiBmdW5jdGlvbiB0byBtYXhpbWl6ZS4gSGVyZSB3ZSBhZGQgYQpyZXR1cm4gb2JqZWN0aXZlIHRvIG1heGltaXplIHRoZSBwb3J0Zm9saW8gbWVhbiByZXR1cm4uCgpgYGB7cn0KcHNwZWMgPC0gYWRkLm9iamVjdGl2ZShwb3J0Zm9saW89cHNwZWMsCiB0eXBlPSdyZXR1cm4nLAogbmFtZT0nbWVhbicpCmBgYAoKCgojIyMjIFBvcnRmb2xpbyBSaXNrIEJ1ZGdldCBPYmplY3RpdmUKVGhlIHBvcnRmb2xpbyByaXNrIG9iamVjdGl2ZSBhbGxvd3MgdGhlIHVzZXIgdG8gc3BlY2lmeSBjb25zdHJhaW50cyB0byBtaW5pbWl6ZSBjb21wb25lbnQgY29uLQp0cmlidXRpb24gKGkuZS4gZXF1YWwgcmlzayBjb250cmlidXRpb24pIG9yIHNwZWNpZnkgdXBwZXIgYW5kIGxvd2VyIGJvdW5kcyBvbiBwZXJjZW50YWdlIHJpc2sKY29udHJpYnV0aW9uLiBIZXJlIHdlIHNwZWNpZnkgdGhhdCBubyBhc3NldCBjYW4gY29udHJpYnV0ZSBtb3JlIHRoYW4gMzAlIHRvIHRvdGFsIHBvcnRmb2xpbyByaXNrLgpTZWUgdGhlIHJpc2sgYnVkZ2V0IG9wdGltaXphdGlvbiB2aWduZXR0ZSBmb3IgbW9yZSBkZXRhaWxlZCBleGFtcGxlcyBvZiBwb3J0Zm9saW8gb3B0aW1pemF0aW9ucwp3aXRoIHJpc2sgYnVkZ2V0cy4KCgpgYGB7cn0KcHNwZWMgPC0gYWRkLm9iamVjdGl2ZShwb3J0Zm9saW89cHNwZWMsIHR5cGU9InJpc2tfYnVkZ2V0IiwgbmFtZT0iRVRMIiwKYXJndW1lbnRzPWxpc3QocD0wLjk1KSwgbWF4X3ByaXNrPTAuMykKCiMgZm9yIGFuIGVxdWFsIHJpc2sgY29udHJpYnV0aW9uIHBvcnRmb2xpbywgc2V0IG1pbl9jb25jZW50cmF0aW9uPVRSVUUKIyBwc3BlYyA8LSBhZGQub2JqZWN0aXZlKHBvcnRmb2xpbz1wc3BlYywgdHlwZT0icmlza19idWRnZXQiLCBuYW1lPSJFVEwiLAojIGFyZ3VtZW50cz1saXN0KHA9MC45NSksIG1pbl9jb25jZW50cmF0aW9uPVRSVUUpCgpgYGAKCgoKIyMjIyBQb3J0Zm9saW8gV2VpZ2h0IENvbmNlbnRyYXRpb24gT2JqZWN0aXZlClRoZSB3ZWlnaHQgY29uY2VudHJhdGlvbiBvYmplY3RpdmUgYWxsb3dzIHRoZSB1c2VyIHRvIHNwZWNpZnkgYW4gb2JqZWN0aXZlIHRvIG1pbmltaXplIGNvbmNlbnRyYS0KdGlvbiBhcyBtZWFzdXJlZCBieSB0aGUgSGVyDG5kYWhsLUhpcnNjaG1hbiBJbmRleC4gRm9yIG90cGltaXphdGlvbiBwcm9ibGVtcyBzb2x2ZWQgd2l0aCB0aGUKZ2xvYmFsIG51bWVyaWMgb3B0aW1pemVycywgdGhlIHBvcnRmb2xpbyBISEkgdmFsdWUgaXMgcGVuYWxpemVkIHVzaW5nIGNvbmNfYXZlcnNpb24gdmFsdWUgYXMgdGhlCm11bHRpcGxpZXIuCkZvciBxdWFkcmF0aWMgdXRpbGl0eSBwcm9ibGVtcyB3aXRoIHdlaWdodCBjb25jZW50cmF0aW9uIGFzIGFuIG9iamVjdGl2ZSB1c2luZyB0aGUgUk9JIHNvbHZlciwKdGhpcyBpcyBpbXBsZW1lbnRlZCBhcyBhIHBlbmFsdHkgdG8gdGhlIG9iamVjdGl2ZSBmdW5jdGlvbi4gVGhlIG9iamVjdGl2ZSBmdW5jdGlvbiBpcyBpbXBsZW1lbnRlZAphcyBmb2xsb3dzOgoKV2hlcmUgzrwgaXMgdGhlIGVzdGltYXRlZCBtZWFuIGFzc2V0IHJldHVybnMsIBUgaXMgdGhlIHJpc2sgYXZlcnNpb24gcGFyYW1ldGVyLCBsYW1iZGFoaGkgaXMgdGhlCmNvbmNlbnRyYXRpb24gYXZlcnNpb24gcGFyYW1ldGVyLCBISEkgaXMgdGhlIHBvcnRmb2xpbyBISEksIAYgaXMgdGhlIGVzdGltYXRlZCBjb3ZhcmlhbmNlIG1hdHJpeApvZiBhc3NldCByZXR1cm5zIGFuZCB3IGlzIHRoZSBzZXQgb2Ygd2VpZ2h0cy4KSGVyZSB3ZSBhZGQgYSB3ZWlnaHQgY29uY2VudHJhdGlvbiBvYmplY3RpdmUgZm9yIHRoZSBvdmVyYWxsIHBvcnRmb2xpbyBISEkuCgpgYGB7cn0KcHNwZWMgPC0gYWRkLm9iamVjdGl2ZShwb3J0Zm9saW89cHNwZWMsIHR5cGU9IndlaWdodF9jb25jZW50cmF0aW9uIiwKIG5hbWU9IkhISSIsIGNvbmNfYXZlcnNpb249MC4xKQpgYGAKCgpUaGUgd2VpZ2h0IGNvbmNlbnRyYXRpb24gYXZlcnNpb24gcGFyYW1ldGVyIGJ5IGdyb3VwcyBjYW4gYWxzbyBiZSBzcGVjaQxlZC4gSGVyZSB3ZSBhZGQgYQp3ZWlnaHQgY29uY2VudHJhdGlvbiBvYmplY3RpdmUgc3BlY2lmeWluZyBncm91cHMgYW5kIGNvbmNlbnRyYXRpb24gYXZlcnNpb24gcGFyYW1ldGVycyBieSBncm91cC4KCmBgYHtyfQpwc3BlYyA8LSBhZGQub2JqZWN0aXZlKHBvcnRmb2xpbz1wc3BlYywgdHlwZT0id2VpZ2h0X2NvbmNlbnRyYXRpb24iLAogbmFtZT0iSEhJIiwKY29uY19hdmVyc2lvbj1jKDAuMDMsIDAuMDYpLApjb25jX2dyb3Vwcz1saXN0KGMoMSwgMiksCmMoMywgNCkpKQoKYGBgCgpUaGUgcHJpbnQgbWV0aG9kIGZvciB0aGUgcG9ydGZvbGlvIG9iamVjdCB3aWxsIG5vdyBzaG93IGFsbCB0aGUgY29uc3RyYWludHMgYW5kIG9iamVjdGl2ZXMgdGhhdApoYXZlIGJlZW4gYWRkZWQuCgpgYGB7cn0KcHJpbnQocHNwZWMpCmBgYAoKClRoZSBzdW1tYXJ5IGZ1bmN0aW9uIGdpdmVzIGEgbW9yZSBkZXRhaWxlZCB2aWV3LgoKYGBge3J9CiBzdW1tYXJ5KHBzcGVjKQpgYGAKCgojIyMjIFNvbHZlcnMKVGhlIFBvcnRmb2xpb0FuYWx5dGljcyBwYWNrYWdlIGN1cnJlbnRseSBzdXBwb3J0cyByYW5kb20gcG9ydGZvbGlvcywgREVvcHRpbSwgcHNvLCBHZW5TQSwgYW5kClJPSSBhcyBiYWNrIGVuZHMuIE5vdGUgdGhhdCBzb21lIG9mIHRoZSBRUC9MUCBwcm9ibGVtcyBhcmUgc29sdmVkIGRpcmVjdGx5IHdpdGggUmdscGsgYW5kIHF1YWQtCnByb2cuIFRoZSBzb2x2ZXIgY2FuIGJlIHNwZWNpDGVkIHdpdGggdGhlIG9wdGltaXplX21ldGhvZCBhcmd1bWVudCBpbiBvcHRpbWl6ZS5wb3J0Zm9saW8KYW5kIG9wdGltaXplLnBvcnRmb2xpby5yZWJhbGFuY2luZy4KCgojIyMjICBERW9wdGltClBvcnRmb2xpb0FuYWx5dGljcyB1c2VzIHRoZSBERW9wdGltIGZ1bmN0aW9uIGZyb20gdGhlIFIgcGFja2FnZSBERW9wdGltLiBEaQtlcmVudGlhbCBldm9sdXRpb24KaXMgYSBzdG9jaGFzdGljIGdsb2JhbCBvcHRpbWl6YXRpb24gYWxnb3JpdGhtLiBTZWUgP0RFb3B0aW0gYW5kIHRoZSByZWZlcmVuY2VzIGNvbnRhaW5lZCB0aGVyZWluCmZvciBtb3JlIGluZm9ybWF0aW9uLiBTZWUgYWxzbyBMYXJnZSBzY2FsZSBwb3J0Zm9saW8gb3B0aW1pemF0aW9uIHdpdGggREVvcHRpbS4KNS4yIFJhbmRvbSBQb3J0Zm9saW9zClBvcnRmb2xpb0FuYWx5dGljcyBoYXMgdGhyZWUgbWV0aG9kcyB0byBnZW5lcmF0ZSByYW5kb20gcG9ydGZvbGlvcy4KMS4gVGhlICdzYW1wbGUnIG1ldGhvZCB0byBnZW5lcmF0ZSByYW5kb20gcG9ydGZvbGlvcyBpcyBiYXNlZCBvbiBhbiBpZGVhIGJ5IFBhdCBCdXJucy4gVGhpcyBpcwp0aGUgbW9zdCAKZXhpYmxlIG1ldGhvZCwgYnV0IGFsc28gdGhlIHNsb3dlc3QsIGFuZCBjYW4gZ2VuZXJhdGUgcG9ydGZvbGlvcyB0byBzYXRpc2Z5IGxldmVyYWdlLApib3gsIGdyb3VwLCBhbmQgcG9zaXRpb24gbGltaXQgY29uc3RyYWludHMuCjIuIFRoZSAnc2ltcGxleCcgbWV0aG9kIHRvIGdlbmVyYXRlIHJhbmRvbSBwb3J0Zm9saW9zIGlzIGJhc2VkIG9uIGEgcGFwZXIgYnkgVy4gVC4gU2hhdy4gVGhlCnNpbXBsZXggbWV0aG9kIGlzIHVzZWZ1bCB0byBnZW5lcmF0ZSByYW5kb20gcG9ydGZvbGlvcyB3aXRoIHRoZSBmdWxsIGludmVzdG1lbnQgY29uc3RyYWludCwKd2hlcmUgdGhlIHN1bSBvZiB0aGUgd2VpZ2h0cyBpcyBlcXVhbCB0byAxLCBhbmQgbWluIGJveCBjb25zdHJhaW50cy4gVmFsdWVzIGZvciBtaW5fc3VtCmFuZCBtYXhfc3VtIG9mIHRoZSBsZXZlcmFnZSBjb25zdHJhaW50IHdpbGwgYmUgaWdub3JlZCwgdGhlIHN1bSBvZiB3ZWlnaHRzIHdpbGwgZXF1YWwgMS4gQWxsCm90aGVyIGNvbnN0cmFpbnRzIHN1Y2ggYXMgdGhlIGJveCBjb25zdHJhaW50IG1heCwgZ3JvdXAgYW5kIHBvc2l0aW9uIGxpbWl0IGNvbnN0cmFpbnRzIHdpbGwKYmUgaGFuZGxlZCBieSBlbGltaW5hdGlvbi4gSWYgdGhlIGNvbnN0cmFpbnRzIGFyZSB2ZXJ5IHJlc3RyaWN0aXZlLCB0aGlzIG1heSByZXN1bHQgaW4gdmVyeQpmZXcgZmVhc2libGUgcG9ydGZvbGlvcyByZW1haW5pbmcuIEFub3RoZXIga2V5IHBvaW50IHRvIG5vdGUgaXMgdGhhdCB0aGUgc29sdXRpb24gbWF5IG5vdApiZSBhbG9uZyB0aGUgdmVydGV4ZXMgZGVwZW5kaW5nIG9uIHRoZSBvYmplY3RpdmUuIEZvciBleGFtcGxlLCBhIHJpc2sgYnVkZ2V0IG9iamVjdGl2ZSB3aWxsCmxpa2VseSBwbGFjZSB0aGUgcG9ydGZvbGlvIHNvbWV3aGVyZSBvbiB0aGUgaW50ZXJpb3IuCjMuIFRoZSAnZ3JpZCcgbWV0aG9kIHRvIGdlbmVyYXRlIHJhbmRvbSBwb3J0Zm9saW9zIGlzIGJhc2VkIG9uIHRoZSBncmlkU2VhcmNoIGZ1bmN0aW9uIGluCnBhY2thZ2UgTk1PRi4gVGhlIGdyaWQgc2VhcmNoIG1ldGhvZCBvbmx5IHNhdGlzDGVzIHRoZSBtaW4gYW5kIG1heCBib3ggY29uc3RyYWludHMuIFRoZQptaW5fc3VtIGFuZCBtYXhfc3VtIGxldmVyYWdlIGNvbnN0cmFpbnQgd2lsbCBsaWtlbHkgYmUgdmlvbGF0ZWQgYW5kIHRoZSB3ZWlnaHRzIGluIHRoZSByYW5kb20KcG9ydGZvbGlvcyBzaG91bGQgYmUgbm9ybWFsaXplZC4gTm9ybWFsaXphdGlvbiBtYXkgY2F1c2UgdGhlIGJveCBjb25zdHJhaW50cyB0byBiZSB2aW9sYXRlZAphbmQgd2lsbCBiZSBwZW5hbGl6ZWQgaW4gY29uc3RyYWluZWRfb2JqZWN0aXZlLgpUaGUgZm9sbG93aW5nIHBsb3RzIGlsbHVzdHJhdGUgdGhlIHZhcmlvdXMgbWV0aG9kcyB0byBnZW5lcmF0ZSByYW5kb20gcG9ydGZvbGlvcy4KCgoKCgoKCgoKCgoKCgoKCgoKIyMjIyBwc28KClBvcnRmb2xpb0FuYWx5dGljcyB1c2VzIHRoZSBwc29wdGltIGZ1bmN0aW9uIGZyb20gdGhlIFIgcGFja2FnZSBwc28uIFBhcnRpY2xlIHN3YXJtIG9wdGltaXphdGlvbgppcyBhIGhldXJpc3RpYyBvcHRpbWl6YXRpb24gYWxnb3JpdGhtLiBTZWUgP3Bzb3B0aW0gYW5kIHRoZSByZWZlcmVuY2VzIGNvbnRhaW5lZCB0aGVyZWluIGZvciBtb3JlCmluZm9ybWF0aW9uLgoKIyMjIyBHZW5TQQoKUG9ydGZvbGlvQW5hbHl0aWNzIHVzZXMgdGhlIEdlblNBIGZ1bmN0aW9uIGZyb20gdGhlIFIgcGFja2FnZSBHZW5TQS4gR2VuZXJhbGl6ZWQgc2ltbXVsYXRlZAphbm5lYWxpbmcgaXMgZ2VuZXJpYyBwcm9iYWJpbGlzdGljIGhldXJpc3RpYyBvcHRpbWl6YXRpb24gYWxnb3JpdGhtLiBTZWUgP0dlblNBIGFuZCB0aGUgcmVmZXJlbmNlcwpjb250YWluZWQgdGhlcmVpbiBmb3IgbW9yZSBpbmZvcm1hdGlvbi4KCiMjIyMgUk9JClRoZSBST0kgcGFja2FnZSBzZXJ2ZXMgYXMgYW4gaW50ZXJmYWNlIHRvIHRoZSBSZ2xwayBwYWNrYWdlIGFuZCB0aGUgcXVhZHByb2cgcGFja2FnZSB0byBzb2x2ZQpsaW5lYXIgYW5kIHF1YWRyYXRpYyBwcm9ncmFtbWluZyBwcm9ibGVtcy4gVGhlIGludGVyZmFjZSB0byB0aGUgUk9JIHBhY2thZ2Ugc29sdmVzIGEgbGltaXRlZAp0eXBlIG9mIGNvbnZleCBvcHRpbWl6YXRpb24gcHJvYmxlbXM6CjEuIE1heG1pbWl6ZSBwb3J0Zm9saW8gcmV0dXJuIHN1YmplY3QgbGV2ZXJhZ2UsIGJveCwgZ3JvdXAsIHBvc2l0aW9uIGxpbWl0LCB0YXJnZXQgbWVhbiByZXR1cm4sCmFuZC9vciBmYWN0b3IgZXhwb3N1cmUgY29uc3RyYWludHMgb24gd2VpZ2h0cy4KMi4gTWluaW1pemUgcG9ydGZvbGlvIHZhcmlhbmNlIHN1YmplY3QgdG8gbGV2ZXJhZ2UsIGJveCwgZ3JvdXAsIHR1cm5vdmVyLCBhbmQvb3IgZmFjdG9yIGV4cG9zdXJlCmNvbnN0cmFpbnRzIChvdGhlcndpc2Uga25vd24gYXMgZ2xvYmFsIG1pbmltdW0gdmFyaWFuY2UgcG9ydGZvbGlvKS4KMy4gTWluaW1pemUgcG9ydGZvbGlvIHZhcmlhbmNlIHN1YmplY3QgdG8gbGV2ZXJhZ2UsIGJveCwgZ3JvdXAsIGFuZC9vciBmYWN0b3IgZXhwb3N1cmUgY29uLQpzdHJhaW50cyBhbmQgYSBkZXNpcmVkIHBvcnRmb2xpbyByZXR1cm4uCjQuIE1heGltaXplIHF1YWRyYXRpYyB1dGlsaXR5IHN1YmplY3QgdG8gbGV2ZXJhZ2UsIGJveCwgZ3JvdXAsIHRhcmdldCBtZWFuIHJldHVybiwgdHVybm92ZXIsCmFuZC9vciBmYWN0b3IgZXhwb3N1cmUgY29uc3RyYWludHMgYW5kIHJpc2sgYXZlcnNpb24gcGFyYW1ldGVyLiAoVGhlIHJpc2sgYXZlcnNpb24gcGFyYW1ldGVyCmlzIHBhc3NlZCBpbnRvIG9wdGltaXplLnBvcnRmb2xpbyBhcyBhbiBhZGRlZCBhcmd1bWVudCB0byB0aGUgcG9ydGZvbGlvIG9iamVjdCkuCgo1LiBNaW5pbWl6ZSBFVEwgc3ViamVjdCB0byBsZXZlcmFnZSwgYm94LCBncm91cCwgcG9zaXRpb24gbGltaXQsIHRhcmdldCBtZWFuIHJldHVybiwgYW5kL29yCmZhY3RvciBleHBvc3VyZSBjb25zdHJhaW50cyBhbmQgdGFyZ2V0IHBvcnRmb2xpbyByZXR1cm4uCjYgT3B0aW1pemF0aW9uClRoZSBwcmV2aW91cyBzZWN0aW9ucyBkZW1vbnN0cmF0ZWQgaG93IHRvIHNwZWNpZnkgYSBwb3J0Zm9saW8gb2JqZWN0LCBhZGQgY29uc3RyYWludHMsIGFkZCBvYmplYy0KdGl2ZXMsIGFuZCB0aGUgc29sdmVycyBhdmFpbGFibGUuIFRoaXMgc2VjdGlvbiB3aWxsIGRlbW9uc3RyYXRlIHJ1biB0aGUgb3B0aW1pemF0aW9ucyB2aWEgb3B0aW1pemUucG9ydGZvbGlvLgpPbmx5IGEgc21hbGwgbnVtYmVyIG9mIGV4YW1wbGVzIHdpbGwgYmUgc2hvd24gaGVyZSwgc2VlIHRoZSBkZW1vcyBmb3Igc2V2ZXJhbCBtb3JlIGV4YW1wbGVzLgoKIyMjIyBJbml0aWFsIFBvcnRmb2xpbyBPYmplY3QKCmBgYHtyfQoKcGFjbWFuOjpwX2xvYWQoIkRFb3B0aW0iLCJST0kiLCJST0kucGx1Z2luLmdscGsiLCJST0kucGx1Z2luLnF1YWRwcm9nIikKI2xpYnJhcnkoREVvcHRpbSkKI2xpYnJhcnkoUk9JKQojcmVxdWlyZShST0kucGx1Z2luLmdscGspCiNyZXF1aXJlKFJPSS5wbHVnaW4ucXVhZHByb2cpCgpmdW5kcyA8LSBjb2xuYW1lcyhzdG9ja19yZXR1cm5zKQojIENyZWF0ZSBhbiBpbml0aWFsIHBvcnRmb2xpbyBvYmplY3Qgd2l0aCBsZXZlcmFnZSBhbmQgYm94IGNvbnN0cmFpbnRzCmluaXQgPC0gcG9ydGZvbGlvLnNwZWMoYXNzZXRzPWZ1bmRzKQppbml0IDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1pbml0LCB0eXBlPSJsZXZlcmFnZSIsCm1pbl9zdW09MC45OSwgbWF4X3N1bT0xLjAxKQppbml0IDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbz1pbml0LCB0eXBlPSJib3giLCBtaW49MC4wNSwgbWF4PTAuNjUpCiNpbml0IDwtIGFkZC5jb25zdHJhaW50KHBvcnRmb2xpbyA9IGluaXQsIHR5cGUgPSAiZnVsbF9pbnZlc3RtZW50IikKYGBgCgoKIyMjIyBNYXhpbWl6ZSBtZWFuIHJldHVybiB3aXRoIFJPSQpBZGQgYW4gb2JqZWN0aXZlIHRvIG1heGltaXplIG1lYW4gcmV0dXJuLgoKYGBge3J9Cm1heHJldCA8LSBhZGQub2JqZWN0aXZlKHBvcnRmb2xpbz1pbml0LCB0eXBlPSJyZXR1cm4iLCBuYW1lPSJtZWFuIikKYGBgCgpSdW4gdGhlIG9wdGltaXphdGlvbi4KCmBgYHtyfQpvcHRfbWF4cmV0IDwtIG9wdGltaXplLnBvcnRmb2xpbyhSPXN0b2NrX3JldHVybnMsIHBvcnRmb2xpbz1tYXhyZXQsCm9wdGltaXplX21ldGhvZD0iUk9JIiwKdHJhY2U9VFJVRSkKcHJpbnQob3B0X21heHJldCkKCmBgYAoKCgoKCiMjIyMgTWluaW1pemUgdmFyaWFuY2Ugd2l0aCBST0kKQWRkIGFuIG9iamVjdGl2ZSB0byBtaW5pbWl6ZSBwb3J0Zm9saW8gdmFyaWFuY2UuCgpgYGB7cn0KbWludmFyIDwtIGFkZC5vYmplY3RpdmUocG9ydGZvbGlvPWluaXQsIHR5cGU9InJpc2siLCBuYW1lPSJ2YXIiKQpgYGAKClJ1biB0aGUgb3B0aW1pemF0aW9uLiBOb3RlIHRoYXQgYWx0aG91Z2ggJ3ZhcicgaXMgdGhlIHJpc2sgbWV0cmljLCAnU3RkRGV2JyBpcyByZXR1cm5lZCBhcyBhbgpvYmplY3RpdmUgbWVhc3VyZS4KCmBgYHtyfQpvcHRfbWludmFyIDwtIG9wdGltaXplLnBvcnRmb2xpbyhSPXN0b2NrX3JldHVybnMsIHBvcnRmb2xpbz1taW52YXIsCm9wdGltaXplX21ldGhvZD0iUk9JIiwgdHJhY2U9VFJVRSkKcHJpbnQob3B0X21pbnZhcikKYGBgCgoKCgojIyMjIE1heGltaXplIHF1YWRyYXRpYyB1dGlsaXR5IHdpdGggUk9JCkFkZCBtZWFuIGFuZCB2YXIgb2JqZWN0aXZlcyBmb3IgcXVhZHJhdGljIHV0aWxpdHkuIE5vdGUgdGhhdCB0aGUgcmlzayBhdmVyc2lvbiBwYXJhbWV0ZXIgZm9yCnF1YWRyYXRpYyB1dGlsaXR5IGlzIHNwZWNpZmVkIGluIHRoZSBvYmplY3RpdmUgYXMgc2hvd24gYmVsb3cuCgpgYGB7cn0KcXUgPC0gYWRkLm9iamVjdGl2ZShwb3J0Zm9saW89aW5pdCwgdHlwZT0icmV0dXJuIiwgbmFtZT0ibWVhbiIpCnF1IDwtIGFkZC5vYmplY3RpdmUocG9ydGZvbGlvPXF1LCB0eXBlPSJyaXNrIiwgbmFtZT0idmFyIiwgcmlza19hdmVyc2lvbj0wLjI1KQpgYGAKClJ1biB0aGUgb3B0aW1pemF0aW9uLgoKYGBge3J9Cm9wdF9xdSA8LSBvcHRpbWl6ZS5wb3J0Zm9saW8oUj1zdG9ja19yZXR1cm5zLCBwb3J0Zm9saW89cXUsCm9wdGltaXplX21ldGhvZD0iUk9JIiwKdHJhY2U9VFJVRSkKcHJpbnQob3B0X3F1KQpgYGAKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCg==