Notebook Setup and API Access

First create an account in porfolio effect website to get an API and use their package.

https://www.portfolioeffect.com

Windows

The setup for windows should be set automatically no need to set path or special java configurations.

Linux

export JAVA_HOME=/path/to/java/folder
export PATH=$PATH:$JAVA_HOME/bin

macOS - Version 10.12.6

Install java 8 or higher in mac using brew:

brew cask install java

Now create a soft link to the current java library so RStudio can find the correct jvm. The path may be different for other versions of java, you can check the java path on macOS with /usr/libexec/java_home

Create the symbolic link:

sudo ln -f -s /Library/Java/JavaVirtualMachines/jdk-9.0.1.jdk/Contents/Home/lib/server/libjvm.dylib /usr/local/lib

Now setup the R java configuration

sudo R CMD javareconf

Install and load package credentials

options(scipen = 9999)
# INSTALL PACKAGE
install.packages("PortfolioEffectHFT",repos = "https://cloud.r-project.org")

# LOAD PACKAGE
require("PortfolioEffectHFT")

# SET CREDENTIALS
util_setCredentials(username = "YOUR_USERNAME", password = "YOUR_PSW", apiKey = "YOUR_API_KEY")

1. Intraday Risk Metrics Exercise

1.1 Create a portfolio

Create a portfolio from this start date 2016-09-01 to this end date 2016-09-05. PortfolioEffectHFT package is required. Use portfolio_create to create an empty portfolio. Buy 200 stocks of Google (GOOG) and 200 of Microsoft (MSFT). You will do that using the position_add function. e.g.: position_add(portfolio, "AAPL", 100)

dateStart = "2016-09-01"
dateEnd = "2016-09-05"
portfolio<-portfolio_create(fromTime=dateStart,toTime=dateEnd)
### Add two stocks to the portfolio
positionGOOG = position_add(portfolio,"GOOG",200)
positionAAPL = position_add(portfolio,"AAPL",200)
### Shows the portfolio holdings
show(portfolio)
PORTFOLIO SETTINGS                                      
 Portfolio metrics mode      portfolio
 Window length               1d       
 Time scale                  1d       
 Holding periods only        FALSE    
 Short sales mode            lintner  
 Price jumps model           moments  
 Microstructure noise model  TRUE     
 Fractal price model         TRUE     
 Portfolio factor model      sim      
 Density model               GLD      
 Drift term enabled          FALSE    
 Results NA filter           TRUE     
 Results sampling interval   1s       
 Input sampling interval     1s       
 Transaction cost per share  0        
 Transaction cost fixed      0        
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 13.84 sec )

    POSITION SUMMARY    
       Quantity   Weight (in %)   Profit   Return (in %)   Value   Price
GOOG        200          87.743      388             0.1  154246  771.23
AAPL        200          12.257      316             0.7   21546  107.73


PORTFOLIO SUMMARY
            Profit   Return (in %)   Value
Portfolio  704.001             0.2  175792

We can plot the portfolio profits

plot(profit(portfolio),font_size=6,bw=TRUE,title="Portfolio profit")
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.43 sec )

1.4 Get position summary

Show the description of the position AAPL and plot it. Use positionMSFT that we created earlier.

summary_appl = show(positionAAPL)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 10.64 sec )

    POSITION SUMMARY    
       Quantity   Weight (in %)   Profit   Return (in %)   Value   Price
AAPL        200          12.257      316             0.7   21546  107.73
summary_appl
       Quantity   Weight (in %)   Profit   Return (in %)   Value   Price
AAPL        200          12.257      316             0.7   21546  107.73

1.5 Plot portfolio analytics

Plot expected return of Google position, Microsoft position and the portfolio.

plot(expected_return(positionGOOG),expected_return(positionAAPL),expected_return(portfolio),
           title="Expected Return, daily",legend=c('GOOG','APPL','Portfolio'),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 5.20 sec )

Plot variance of Google position, Microsoft position and the portfolio.

plot(variance(positionGOOG),variance(positionAAPL),variance(portfolio),
     title="Variance, daily",legend=c('GOOG','MSFT','Portfolio'),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 5.42 sec )

Plot VaR of the portfolio for different confidence interval. Put the confidence interval to 0.9, 0.95, 0.99.

plot(value_at_risk(portfolio,0.9),value_at_risk(portfolio,0.95),value_at_risk(portfolio,0.99),
     title="Portfolio Value at Risk, daily",legend=c('0.9','0.95','0.99'),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 7.05 sec )

1.6 Controlling porfolio settings: noise filter off

Change the portfolio settings and remove any filter for the noise : noiseModel = F. Use portfolio_settings to do that. Then plot value-at-risk of the portfolio for different confidence interval: 0.9, 0.95 and 0.99.

#Change porfolio settings: add the parameter noiseModel=F
portfolio_settings(portfolio,  noiseModel=F)
#Plot VaR for CI: 0.9, 0.95, 0.99
plot(value_at_risk(portfolio,0.9),value_at_risk(portfolio,0.95),value_at_risk(portfolio,0.99),
     title="Portfolio Value at Risk, daily",legend=c('0.9','0.95','0.99'),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 7.48 sec )

1.7 Controlling porfolio settings: noise filter on

Change the portfolio settings and add filter for the noise noiseModel = T. Plot Sharpe ratio of the position Google and position Microsoft.

#Change porfolio settings: noiseModel=T
portfolio_settings(portfolio, noiseModel=T)
plot(sharpe_ratio(positionGOOG),sharpe_ratio(positionAAPL),title="Portfolio Sharpe Ratio, daily",
     legend=c('GOOG','MSFT'),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.82 sec )

1.8 Manipulating the analytics

Calculate expected return of the portfolio using expected_return function. Use the function compute() for the calculation to actually take place. Assign the results to expectedReturn. Note that compute return a list of list.

#Compute expected return of Portfolio
expectedReturn=compute(expected_return(portfolio))[[1]]
#Print first row of expectedReturn
expectedReturn[1,]
                    time                    value 
1472736602000.0000000000            -0.0004112651 

Calculate alpha and variance of the portfolio. Use the function compute() for the calculation to actually take place. Assign the results to list_of_list_results. Note that compute return a list of list.

Compute expected return of Portfolio

list_of_list_results=compute(beta(portfolio),variance(portfolio))
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.40 sec )
beta=list_of_list_results[[1]]
variance=list_of_list_results[[2]]
#Print first row of expectedReturn
print("Beta")
[1] "Beta"
beta[1,]
               time               value 
1472736601000.00000             1.58049 
print("Variance")
[1] "Variance"
variance[1,]
                    time                    value 
1472736601000.0000000000             0.0001716066 

2. Backtesting Portfolio Exercise

We will develop a strategy based on moving average. We define the function MA(z, order) for moving average that you can use in the following exercise. Recall: To execute the cell below, click on it and press ctrl+enter or click in Cell-> run cells

# Moving Average Function
MA=function(x,order){
  result<-x
  x1<-c(0,x)
  result[(order):NROW(x)]<-(cumsum(x1)[-(1:(order))]-cumsum(x1)[-((NROW(x1)-order+1):NROW(x1))])/order
  result[1:(order-1)]<-cumsum(x[1:(order-1)])/(1:(order-1))
  return(result-0.0000000001)
}

2.1 Create a portfolio

Create a portfolio starting on “2017-03-27” and ending “2017-03-31”. Create a portfolio using the function portfolio_create. Buy 1 stock of GOOG. Get prices and time in different vectors.

# Fill the start date and end date
dateStart = "2017-03-27"
dateEnd = "2017-03-31"
#Create portfolio
portfolio=portfolio_create(fromTime=dateStart,toTime=dateEnd)
#Buy 1 stock of GOOG. Fill the quantity.
symbol = "GOOG"
position=position_add(portfolio,symbol,quantity = 1)

Let see how to access the price and the time. Calculate the price of the position using compute() function. Save your time vector (the first column) and the price vector (second column) separately. compute() function return a list of list hence [[1]]. head() function allows in R to see the first elements of a dataframe. Using head(), check the price and time vector.

#Save your time vector (the first column) and the price vector (second column) separately.
price=compute(price(position))[[1]]
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 3.23 sec )
printTime=price[,1]
#Using head(), check first elements of price
head(price)
              time  value
[1,] 1490621401000 814.32
[2,] 1490621402000 808.16
[3,] 1490621403000 807.93
[4,] 1490621404000 807.19
[5,] 1490621405000 807.14
[6,] 1490621406000 807.21

2.2 Price vector creation

Use price vector to create a strategy based on moving average. We assume that prices tend to revert to its moving average. Therefore, if the prices are below its moving average, we get into the position by 1 unit. If prices are above the moving average, we are out of position. Use the window=100 and MA() function that you were given in advance.

#Initialize an array of the same length as price using NROW(price)
Strategy = array(0,dim=nrow(price))
#Fill the window length
Strategy[price[,"value"]<MA(price[,"value"],100)]=1
#We assume that we will use the signal strategy to enter the position in the next second.
#To do this, move the vector signal by adding the first element of 0 and removing the last element.
Strategy=c(0,Strategy[-length(Strategy)])

2.3 Portfolio strategy

Create a portfolio strategy based on on the previous parts. Use the same time interval as before from sateStart to endDate. When adding item GOOG pass a variable ‘quantity’ vector of your strategy, and variable ‘time’ vector time that you saved previously. These vectors must be the same length. Then plot log return of portfolio.

#dateStart = "2017-10-01"
#dateEnd = "2017-03-07"
#Create a portfolio strategy based on that. Fill the parameters fromTime with dateStart & toTime with dateEnd
portfolio=portfolio_create(fromTime=dateStart,toTime=dateEnd)
#Add position to the empty portfolio using quantity=Strategy and time=printTime
#Recall we calculated the vector Strategy in part 2. and printTime in part1
position=position_add(portfolio=portfolio,symbol=symbol,quantity=Strategy,time=printTime)
#Plot log return of portfolio.
plot(log_return(portfolio),font_size=6,bw=TRUE,title="Portfolio log return")
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.49 sec )

2.4 Find the optimal moving average window length

Let’s find the optimal length of a moving average window. For that we will create a loop in which the window will vary from 5 to 50 with a step of 5. We are speaking here about the window of the moving average. To record the result, create an empty vector result = NULL. Add a new setting in the portfolio to accelerate the work : portfolio_settings(portfolio,resultsSamplingInterval='last'). Calculate the value of the logarithmic portfolio returns and add them to the vector result as : result=rbind(result,c(window,compute(log return(portfolio))[[1]][2]))

#Create an empty vector result to NULL
result=NULL
#Create a loop with window varying from 5 to 50
for(window  in seq(5,50,by=5)){
  #Inside the loop, we use the previously written code for the creation of a strategic portfolio in part1, and 2
  # but instead of the previously set window in MA function using changing variable.
  portfolio=portfolio_create(fromTime=dateStart,toTime=dateEnd)
  Strategy = array(0,dim=nrow(price))
  
  #Put the parameter window as the second argument to MA fucntion   
  Strategy[price[,"value"]<MA(price[,"value"], window)]=1
  Strategy=c(0,Strategy[-length(Strategy)])
  position=position_add(portfolio=portfolio,symbol=symbol,quantity=Strategy,time=printTime)
  
  #Add a new setting in the portfolio to accelerate the work: resultsSamplingInterval='last'
  portfolio_settings(portfolio,resultsSamplingInterval='last')
  
  #Calculate the value of the logarithmic portfolio returns and 
  #add them to the vector result as: result=rbind(result,c(window,compute(log_return(portfolio))[[1]][2]))
  result=rbind(result,c(window,compute(log_return(portfolio))[[1]][2]))
}
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.27 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.11 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.14 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.12 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.96 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.05 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.95 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.16 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.93 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.95 sec )

Logarithmic portfolio returns

#plot result
plot(result,type='l', ann=FALSE)
title(main="Optimal MA window length", xlab="window length", ylab="log return")

2.5 Finding the optimal moving average window length with transaction costs

Do the samething as in 4., just add a new setting in the portfolio as the transaction costs which is 0.03 per share: portfolio_settings(portfolio,resultsSamplingInterval='last',txnCostPerShare=0.03). Use the previously written code. Observe how the results change.

#Create an empty vector resultWithTxn = NULL
resultWithTxn=NULL
#Create a loop with window varying from 5:50
for(window in seq(5,50,by=5)){
  portfolio=portfolio_create(fromTime=dateStart,toTime=dateEnd)
    
  #Add the transaction costs per share txnCostPerShare=0.03
  portfolio_settings(portfolio,resultsSamplingInterval='last',txnCostPerShare=0.03)
  Strategy = array(0,dim=NROW(price))
  Strategy[price[,"value"]<MA(price[,"value"],window)]=1
  Strategy=c(0,Strategy[-length(Strategy)])
  
  position=position_add(portfolio=portfolio,symbol=symbol,quantity=Strategy,time=printTime)
  
  resultWithTxn=rbind(resultWithTxn,c(window,compute(log_return(portfolio))[[1]][2]))
}
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.95 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.15 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.30 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.30 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.39 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.25 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.99 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 2.16 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.93 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 1.94 sec )
#Plot resultWithTxn
plot(resultWithTxn,type='l', ann=FALSE)
title(main="Optimal MA window length with transaction cost", xlab="window length", ylab="log return")

We have seen that the optimal window will increase with the addition of transaction costs.


3. Volatility Forecasting Exercise

3.1 Create a portfolio

Create a portfolio starting on 2015-01-01 and ending 2015-12-31. Buy 1 stock of google (“GOOG”).

#Create a portfolio starting 2015-01-01 and ending 2015-12-31
dateStart = "2015-01-01"
dateEnd = "2015-12-31"
portfolio = portfolio_create(fromTime=dateStart,toTime=dateEnd)
#Add "GOOG" stocks volume of 1 units as positionGOOG.
positionGOOG = position_add(portfolio = portfolio,symbol = "GOOG",quantity = 1)

3.2 Change portfolio settings

In portfolio’s settings set the resultsSamplingInterval and inputSamplingInterval as one hour (“1h”). inputSamplingInterval corresponds the frequency between the market data input. resultsSamplingInterval correponds to the frequency between the output of the results.

#In the settings set the resultsSamplingInterval and inputSamplingInterval as one hour '1h'.
portfolio_settings(portfolio,inputSamplingInterval="1h",resultsSamplingInterval="1h")

3.3 Create forecast object

Create forecast object of variance on the positionGOOG using model EWMA and forecast_builder() function. Then use forecast_apply().

#Create forecast object of variance GOOG position, model 'EWMA' 
forecast_Builder_EWMA=forecast_builder(variance(positionGOOG),model="EWMA")
#Apply it as forecast_Variance_EWMA.
forecast_Variance_EWMA=forecast_apply(forecast_Builder_EWMA)

Print sum of squared forecast errors.

#Print sum of squared forecast errors of forecast_Variance_EWMA and variance_GOOG
print("Error with EWMA model")
[1] "Error with EWMA model"
error_EWMA=sum(compute(forecast_Variance_EWMA-variance(positionGOOG))[[1]][,2]^2)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 51.44 sec )
print(error_EWMA)
[1] 0.0000141724

3.4 Use HAR model

Do the same steps than in 1,2,3 but use HAR model instead

#Create a portfolio again. Do the same thing, specify only model 'HAR'
portfolio=portfolio_create(fromTime=dateStart,toTime=dateEnd)
positionGOOG=position_add(portfolio,"GOOG",1)
##In the settings set the resultsSamplingInterval and inputSamplingInterval as one hour '1h'
portfolio_settings(portfolio,inputSamplingInterval="1h",resultsSamplingInterval="1h")
#Use 'HAR' model
forecast_Builder_HAR=forecast_builder(variance(positionGOOG),model="HAR")
#Apply forecast_apply function to for forecast_Builder_HAR object
forecast_Variance_HAR=forecast_apply(forecast_Builder_HAR)
#Print sum of squared forecast errors of forecast_Variance_HAR and variance_GOOG
print("Error with HAR model")
[1] "Error with HAR model"
error_HAR=sum(compute(forecast_Variance_HAR-variance(positionGOOG))[[1]][,2]^2)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 44.12 sec )
print(error_HAR)
[1] 0.000004898218

3.5 Add metric beta

Repeat steps 1,2,3 and add the metric beta of positionGOOG in regression using function forecast_input(). We will see if we add the variable beta it will improve the forecast. 90% of the case adding beta will give a better forecasting volatility but will require more powerful computational power.

#We see that the error HAR forecast is smaller. Will it improve the forecast, if we add a variable beta in the regression ?
#Create a portfolio
portfolio=portfolio_create(fromTime=dateStart,toTime=dateEnd)
positionGOOG=position_add(portfolio,"GOOG",1)
portfolio_settings(portfolio,inputSamplingInterval='1h',resultsSamplingInterval='1h')
#Use forecast_builder to create the forecast object
forecast_Builder_HAR_beta=forecast_builder(variance(positionGOOG),model='HAR')
#Add the metric beta of positionGOOG (beta(positionGOOG)) in regression using function forecast_input.
forecast_Builder_HAR_beta=forecast_input(forecast_Builder_HAR_beta,beta(positionGOOG))
forecast_Variance_HAR_beta=forecast_apply(forecast_Builder_HAR_beta)
#Calculate the sum of squares of forecast errors again between forecast_Variance_HAR_beta and variance(positionGOOG)
print("Error with HAR model and beta")
[1] "Error with HAR model and beta"
error_HAR_and_beta=sum(compute(forecast_Variance_HAR_beta-variance(positionGOOG))[[1]][,2]^2)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 47.02 sec )
print(error_HAR_and_beta)
[1] 0.000004936916

3.6 Compare results

Compare the 3 methods above and find which methdology is the best for forecasting the variance of Google in this case.

#Create a vector with the 3 errors: error_EWMA, error_HAR and error_HAR_and_beta
vector_error<-c(error_EWMA,error_HAR,error_HAR_and_beta)
names(vector_error)=c("error_EWMA","error_HAR","error_HAR_and_beta")
#print vector_error
#Get which indice has the smaller minimum
inds = which(vector_error == min(vector_error), arr.ind=TRUE)
inds
error_HAR 
        2 
#Print the error
print("The best forecasting model in this case is:")
[1] "The best forecasting model in this case is:"
rnames = vector_error[inds[1]]
rnames
     error_HAR 
0.000004898218 

4. Portfolio Optimization Exercise

4.1 Create a portfolio

Create a portfolio starting 5 days ago and ending “2017-03-17”. Buy 1000 stocks for MSFT, GOOG, SPY.

dateStart = "2017-03-13"
dateEnd = "2017-03-17"
#Create a portfolio starting 5 days ago "2017-03-13" and ending today "2017-03-17".
portfolio<-portfolio_create(dateStart, dateEnd)
#Add three liquid stocks: "AAPL", "GOOG", "SPY" volume of 1000 units.
position_AAPL=position_add(portfolio,symbol="AAPL",quantity = 1000)
position_GOOG=position_add(portfolio,symbol="GOOG",quantity = 1000)
position_SPY=position_add(portfolio,symbol="SPY",quantity = 1000)

4.2 Settings change

In the settings set the portfolioMetricsMode as the price, and resultsSamplingInterval one minute to speed up the optimization.

#Set the portfolioMetricsMode as the price, 
#and resultsSamplingInterval one minute
portfolio_settings(portfolio,portfolioMetricsMode="price",resultsSamplingInterval="1m")

4.3 Goal optimization

Create a goal optimization object to maximize the Sharpe ratio of the portfolio.

#Direction should be set to "max"
#Fist parameter of optimization_goal should be set to sharpe_ratio(portfolio)
optimizer=optimization_goal(sharpe_ratio(portfolio),direction="max")

4.4 Constraint

Set the constraint for value (portfolio) equal to 100,000 to declare the volume of the optimal portfolio. Calculate the optimal portfolio.Name the optimal portfolio as a optimPortfolioNoConstraints.

#Set the constraint for value (portfolio) equal to 100000
optimizer=optimization_constraint(optimizer,value(portfolio),'=',100000)
#Calculate the optimal portfolio. Name the optimal portfolio as a optimPortfolioNoConstraints
optimPortfolioNoConstraints=optimization_run(optimizer)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 10.64 sec )

4.5 Create another optimization portfolio

You will add an additional constraint. Make the same optimization, just add an additional constraint on the portfolio beta of zero. Name the optimal portfolio as a optimPortfolioOneConstraints

#Same method as above
optimizer=optimization_goal(sharpe_ratio(portfolio),direction="max")
optimizer=optimization_constraint(optimizer,value(portfolio),'=',100000)
#Set portfolio beta to zero
optimizer=optimization_constraint(optimizer,beta(portfolio),"=",0)
# Name the optimal portfolio as a optimPortfolioOneConstraints
optimPortfolioOneConstraints=optimization_run(optimizer)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 22.49 sec )

4.6 Plot optimization results

Display the charts of the two optimal portfolios for the beta. You will need to specify a legend for graphs.

#Input calculation of beta(optimPortfolioOneConstraints) and beta(optimPortfolioNoConstraints) 
beta_one_constrain = beta(optimPortfolioOneConstraints)
beta_no_constrain = beta(optimPortfolioNoConstraints)
plot(beta_one_constrain,beta_no_constrain,title="beta",legend=c('One Constraints','No Constraints'),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 4.25 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 4.15 sec )

Display the charts of the two optimal portfolios for Sharpe ratio. You will need to specify a legend for graphs.

#Input calculation of sharpe_ratio(optimPortfolioOneConstraints) and sharpe_ratio(optimPortfolioNoConstraints) 
sharpe_one_constrain = sharpe_ratio(optimPortfolioOneConstraints)
sharpe_no_constrain = sharpe_ratio(optimPortfolioNoConstraints)
plot(sharpe_one_constrain,sharpe_no_constrain,title="sharpe_ratio",
     legend=c('One Constraints','No Constraints'),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 4.61 sec )
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 4.54 sec )

4.7. Optimal position portfolios

To get the optimal position portfolios use the function portfolio_getPosition(portfolio, symbol). Build charts weights optimal positions.

#Caculate "AAPL" weight
weight_AAPL=weight(portfolio_getPosition(optimPortfolioOneConstraints,"AAPL"))
#Caculate "GOOG" weight
weight_GOOG=weight(portfolio_getPosition(optimPortfolioOneConstraints,"GOOG") )
#Caculate "SPY" weight
weight_SPY=weight(portfolio_getPosition(optimPortfolioOneConstraints,"SPY"))
 
#Plot weights: weight_AAPL, weight_GOOG and weight_SPY
plot(weight_AAPL,
     weight_GOOG,
     weight_SPY,
     title='Optimal positions portfolio', legend=c("AAPL","GOOG","SPY"),font_size=6,bw=TRUE)
[0%.....10%.....20%.....30%.....40%.....50%.....60%.....70%.....80%.....90%.....100%] ( 4.08 sec )

LS0tCnRpdGxlOiAiQWxnb3JpdGhtaWMgVHJhZGluZyBpbiBSIFdvcmtzaG9wIgphdXRob3I6ICJKb3NlIEx1aXMgUm9kcmlndWV6IgpkYXRlOiAiMjAxNy0xMC0yMiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0CnN1YnRpdGxlOiAiUG9ydGZvbGlvIEVmZmVjdCBXb3Jrc2hvcCAtIDIwMTctMTAtMjIiCi0tLQoKCi0tLS0gCgojIyMjIE5vdGVib29rIFNldHVwIGFuZCBBUEkgQWNjZXNzCgpGaXJzdCBjcmVhdGUgYW4gYWNjb3VudCBpbiBwb3Jmb2xpbyBlZmZlY3Qgd2Vic2l0ZSB0byBnZXQgYW4gQVBJIGFuZCB1c2UgdGhlaXIgcGFja2FnZS4KCltodHRwczovL3d3dy5wb3J0Zm9saW9lZmZlY3QuY29tXShodHRwczovL3d3dy5wb3J0Zm9saW9lZmZlY3QuY29tKQoKCiogU291cmNlOiBTdGVwaGFuaWUgVG9wZXIgLS0gQWxnbyBUcmFkaW5nIFIgV29ya3Nob3AgKDIwMTctMTAtMjIpCgoqKldpbmRvd3MqKgoKVGhlIHNldHVwIGZvciB3aW5kb3dzIHNob3VsZCBiZSBzZXQgYXV0b21hdGljYWxseSBubyBuZWVkIHRvIHNldCBwYXRoIG9yIHNwZWNpYWwgamF2YSBjb25maWd1cmF0aW9ucy4KCgoqKkxpbnV4KioKCgpgYGAKZXhwb3J0IEpBVkFfSE9NRT0vcGF0aC90by9qYXZhL2ZvbGRlcgpleHBvcnQgUEFUSD0kUEFUSDokSkFWQV9IT01FL2JpbgpgYGAKCioqbWFjT1MgLSBWZXJzaW9uIDEwLjEyLjYqKgoKCkluc3RhbGwgamF2YSA4IG9yIGhpZ2hlciBpbiBtYWMgdXNpbmcgYnJldzoKCmBgYApicmV3IGNhc2sgaW5zdGFsbCBqYXZhCmBgYAoKTm93IGNyZWF0ZSBhIHNvZnQgbGluayB0byB0aGUgY3VycmVudCBqYXZhIGxpYnJhcnkgc28gUlN0dWRpbyBjYW4gZmluZCB0aGUgY29ycmVjdCBqdm0uIFRoZSBwYXRoIG1heSBiZSBkaWZmZXJlbnQgZm9yIG90aGVyIHZlcnNpb25zIG9mIGphdmEsIHlvdSBjYW4gY2hlY2sgdGhlIGphdmEgcGF0aCBvbiBtYWNPUyB3aXRoIGAvdXNyL2xpYmV4ZWMvamF2YV9ob21lYAoKQ3JlYXRlIHRoZSBzeW1ib2xpYyBsaW5rOgpgYGAKc3VkbyBsbiAtZiAtcyAvTGlicmFyeS9KYXZhL0phdmFWaXJ0dWFsTWFjaGluZXMvamRrLTkuMC4xLmpkay9Db250ZW50cy9Ib21lL2xpYi9zZXJ2ZXIvbGlianZtLmR5bGliIC91c3IvbG9jYWwvbGliCmBgYAoKTm93IHNldHVwIHRoZSBSIGphdmEgY29uZmlndXJhdGlvbiAKYGBgCnN1ZG8gUiBDTUQgamF2YXJlY29uZgpgYGAKCiMjIyMgSW5zdGFsbCBhbmQgbG9hZCBwYWNrYWdlIGNyZWRlbnRpYWxzCgpgYGB7cixldmFsPUZBTFNFfQpvcHRpb25zKHNjaXBlbiA9IDk5OTkpCiMgSU5TVEFMTCBQQUNLQUdFCmluc3RhbGwucGFja2FnZXMoIlBvcnRmb2xpb0VmZmVjdEhGVCIscmVwb3MgPSAiaHR0cHM6Ly9jbG91ZC5yLXByb2plY3Qub3JnIikKCiMgTE9BRCBQQUNLQUdFCnJlcXVpcmUoIlBvcnRmb2xpb0VmZmVjdEhGVCIpCgojIFNFVCBDUkVERU5USUFMUwp1dGlsX3NldENyZWRlbnRpYWxzKHVzZXJuYW1lID0gIllPVVJfVVNFUk5BTUUiLCBwYXNzd29yZCA9ICJZT1VSX1BTVyIsIGFwaUtleSA9ICJZT1VSX0FQSV9LRVkiKQoKYGBgCgojIyAxLiBJbnRyYWRheSBSaXNrIE1ldHJpY3MgRXhlcmNpc2UKCiMjIyMgMS4xIENyZWF0ZSBhIHBvcnRmb2xpbwoKQ3JlYXRlIGEgcG9ydGZvbGlvIGZyb20gdGhpcyBzdGFydCBkYXRlIDIwMTYtMDktMDEgdG8gdGhpcyBlbmQgZGF0ZSAyMDE2LTA5LTA1LiBQb3J0Zm9saW9FZmZlY3RIRlQgcGFja2FnZSBpcyByZXF1aXJlZC4gVXNlIGBwb3J0Zm9saW9fY3JlYXRlYCB0byBjcmVhdGUgYW4gZW1wdHkgcG9ydGZvbGlvLiBCdXkgMjAwIHN0b2NrcyBvZiBHb29nbGUgKEdPT0cpIGFuZCAyMDAgb2YgTWljcm9zb2Z0IChNU0ZUKS4gWW91IHdpbGwgZG8gdGhhdCB1c2luZyB0aGUgYHBvc2l0aW9uX2FkZGAgZnVuY3Rpb24uIGUuZy46IGBwb3NpdGlvbl9hZGQocG9ydGZvbGlvLCAiQUFQTCIsIDEwMClgCgpgYGB7cn0KZGF0ZVN0YXJ0ID0gIjIwMTYtMDktMDEiCmRhdGVFbmQgPSAiMjAxNi0wOS0wNSIKCnBvcnRmb2xpbzwtcG9ydGZvbGlvX2NyZWF0ZShmcm9tVGltZT1kYXRlU3RhcnQsdG9UaW1lPWRhdGVFbmQpCgojIyMgQWRkIHR3byBzdG9ja3MgdG8gdGhlIHBvcnRmb2xpbwpwb3NpdGlvbkdPT0cgPSBwb3NpdGlvbl9hZGQocG9ydGZvbGlvLCJHT09HIiwyMDApCnBvc2l0aW9uQUFQTCA9IHBvc2l0aW9uX2FkZChwb3J0Zm9saW8sIkFBUEwiLDIwMCkKCiMjIyBTaG93cyB0aGUgcG9ydGZvbGlvIGhvbGRpbmdzCnNob3cocG9ydGZvbGlvKQpgYGAKCldlIGNhbiBwbG90IHRoZSBwb3J0Zm9saW8gcHJvZml0cwoKYGBge3J9CnBsb3QocHJvZml0KHBvcnRmb2xpbyksZm9udF9zaXplPTYsYnc9VFJVRSx0aXRsZT0iUG9ydGZvbGlvIHByb2ZpdCIpCmBgYAoKCiMjIyMgMS40IEdldCBwb3NpdGlvbiBzdW1tYXJ5CgpTaG93IHRoZSBkZXNjcmlwdGlvbiBvZiB0aGUgcG9zaXRpb24gQUFQTCBhbmQgcGxvdCBpdC4gVXNlIHBvc2l0aW9uTVNGVCB0aGF0IHdlIGNyZWF0ZWQgZWFybGllci4KCmBgYHtyfQpzdW1tYXJ5X2FwcGwgPSBzaG93KHBvc2l0aW9uQUFQTCkKc3VtbWFyeV9hcHBsCmBgYAoKIyMgMS41IFBsb3QgcG9ydGZvbGlvIGFuYWx5dGljcwoKUGxvdCBleHBlY3RlZCByZXR1cm4gb2YgR29vZ2xlIHBvc2l0aW9uLCBNaWNyb3NvZnQgcG9zaXRpb24gYW5kIHRoZSBwb3J0Zm9saW8uIAoKYGBge3J9CnBsb3QoZXhwZWN0ZWRfcmV0dXJuKHBvc2l0aW9uR09PRyksZXhwZWN0ZWRfcmV0dXJuKHBvc2l0aW9uQUFQTCksZXhwZWN0ZWRfcmV0dXJuKHBvcnRmb2xpbyksCiAgICAgICAgICAgdGl0bGU9IkV4cGVjdGVkIFJldHVybiwgZGFpbHkiLGxlZ2VuZD1jKCdHT09HJywnQVBQTCcsJ1BvcnRmb2xpbycpLGZvbnRfc2l6ZT02LGJ3PVRSVUUpCmBgYAoKUGxvdCB2YXJpYW5jZSBvZiBHb29nbGUgcG9zaXRpb24sIE1pY3Jvc29mdCBwb3NpdGlvbiBhbmQgdGhlIHBvcnRmb2xpby4KCmBgYHtyfQpwbG90KHZhcmlhbmNlKHBvc2l0aW9uR09PRyksdmFyaWFuY2UocG9zaXRpb25BQVBMKSx2YXJpYW5jZShwb3J0Zm9saW8pLAogICAgIHRpdGxlPSJWYXJpYW5jZSwgZGFpbHkiLGxlZ2VuZD1jKCdHT09HJywnTVNGVCcsJ1BvcnRmb2xpbycpLGZvbnRfc2l6ZT02LGJ3PVRSVUUpCmBgYAoKUGxvdCBWYVIgb2YgdGhlIHBvcnRmb2xpbyBmb3IgZGlmZmVyZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWwuIFB1dCB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCB0byAwLjksIDAuOTUsIDAuOTkuCgpgYGB7cn0KcGxvdCh2YWx1ZV9hdF9yaXNrKHBvcnRmb2xpbywwLjkpLHZhbHVlX2F0X3Jpc2socG9ydGZvbGlvLDAuOTUpLHZhbHVlX2F0X3Jpc2socG9ydGZvbGlvLDAuOTkpLAogICAgIHRpdGxlPSJQb3J0Zm9saW8gVmFsdWUgYXQgUmlzaywgZGFpbHkiLGxlZ2VuZD1jKCcwLjknLCcwLjk1JywnMC45OScpLGZvbnRfc2l6ZT02LGJ3PVRSVUUpCmBgYAoKCiMjIyAxLjYgQ29udHJvbGxpbmcgcG9yZm9saW8gc2V0dGluZ3M6IG5vaXNlIGZpbHRlciBvZmYKCkNoYW5nZSB0aGUgcG9ydGZvbGlvIHNldHRpbmdzIGFuZCByZW1vdmUgYW55IGZpbHRlciBmb3IgdGhlIG5vaXNlIDogYG5vaXNlTW9kZWwgPSBGYC4gVXNlIGBwb3J0Zm9saW9fc2V0dGluZ3NgIHRvIGRvIHRoYXQuIFRoZW4gcGxvdCB2YWx1ZS1hdC1yaXNrIG9mIHRoZSBwb3J0Zm9saW8gZm9yIGRpZmZlcmVudCBjb25maWRlbmNlIGludGVydmFsOiAwLjksIDAuOTUgYW5kIDAuOTkuCgpgYGB7cn0KI0NoYW5nZSBwb3Jmb2xpbyBzZXR0aW5nczogYWRkIHRoZSBwYXJhbWV0ZXIgbm9pc2VNb2RlbD1GCnBvcnRmb2xpb19zZXR0aW5ncyhwb3J0Zm9saW8sICBub2lzZU1vZGVsPUYpCgojUGxvdCBWYVIgZm9yIENJOiAwLjksIDAuOTUsIDAuOTkKcGxvdCh2YWx1ZV9hdF9yaXNrKHBvcnRmb2xpbywwLjkpLHZhbHVlX2F0X3Jpc2socG9ydGZvbGlvLDAuOTUpLHZhbHVlX2F0X3Jpc2socG9ydGZvbGlvLDAuOTkpLAogICAgIHRpdGxlPSJQb3J0Zm9saW8gVmFsdWUgYXQgUmlzaywgZGFpbHkiLGxlZ2VuZD1jKCcwLjknLCcwLjk1JywnMC45OScpLGZvbnRfc2l6ZT02LGJ3PVRSVUUpCmBgYAoKIyMjIyAxLjcgIENvbnRyb2xsaW5nIHBvcmZvbGlvIHNldHRpbmdzOiBub2lzZSBmaWx0ZXIgb24KCkNoYW5nZSB0aGUgcG9ydGZvbGlvIHNldHRpbmdzIGFuZCBhZGQgZmlsdGVyIGZvciB0aGUgbm9pc2UgYG5vaXNlTW9kZWwgPSBUYC4gUGxvdCBTaGFycGUgcmF0aW8gb2YgdGhlIHBvc2l0aW9uIEdvb2dsZSBhbmQgcG9zaXRpb24gTWljcm9zb2Z0LgoKYGBge3J9CiNDaGFuZ2UgcG9yZm9saW8gc2V0dGluZ3M6IG5vaXNlTW9kZWw9VApwb3J0Zm9saW9fc2V0dGluZ3MocG9ydGZvbGlvLCBub2lzZU1vZGVsPVQpCgpwbG90KHNoYXJwZV9yYXRpbyhwb3NpdGlvbkdPT0cpLHNoYXJwZV9yYXRpbyhwb3NpdGlvbkFBUEwpLHRpdGxlPSJQb3J0Zm9saW8gU2hhcnBlIFJhdGlvLCBkYWlseSIsCiAgICAgbGVnZW5kPWMoJ0dPT0cnLCdNU0ZUJyksZm9udF9zaXplPTYsYnc9VFJVRSkKYGBgCgoKIyMjIyAxLjggTWFuaXB1bGF0aW5nIHRoZSBhbmFseXRpY3MKCkNhbGN1bGF0ZSBleHBlY3RlZCByZXR1cm4gb2YgdGhlIHBvcnRmb2xpbyB1c2luZyBgZXhwZWN0ZWRfcmV0dXJuYCBmdW5jdGlvbi4gVXNlIHRoZSBmdW5jdGlvbiBgY29tcHV0ZSgpYCBmb3IgdGhlIGNhbGN1bGF0aW9uIHRvIGFjdHVhbGx5IHRha2UgcGxhY2UuIEFzc2lnbiB0aGUgcmVzdWx0cyB0byBgZXhwZWN0ZWRSZXR1cm5gLgpOb3RlIHRoYXQgY29tcHV0ZSByZXR1cm4gYSBsaXN0IG9mIGxpc3QuCgpgYGB7cn0KI0NvbXB1dGUgZXhwZWN0ZWQgcmV0dXJuIG9mIFBvcnRmb2xpbwpleHBlY3RlZFJldHVybj1jb21wdXRlKGV4cGVjdGVkX3JldHVybihwb3J0Zm9saW8pKVtbMV1dCgojUHJpbnQgZmlyc3Qgcm93IG9mIGV4cGVjdGVkUmV0dXJuCmV4cGVjdGVkUmV0dXJuWzEsXQpgYGAKCkNhbGN1bGF0ZSBhbHBoYSBhbmQgdmFyaWFuY2Ugb2YgdGhlIHBvcnRmb2xpby4gVXNlIHRoZSBmdW5jdGlvbiBgY29tcHV0ZSgpYCBmb3IgdGhlIGNhbGN1bGF0aW9uIHRvIGFjdHVhbGx5IHRha2UgcGxhY2UuIEFzc2lnbiB0aGUgcmVzdWx0cyB0byBgbGlzdF9vZl9saXN0X3Jlc3VsdHNgLiBOb3RlIHRoYXQgY29tcHV0ZSByZXR1cm4gYSBsaXN0IG9mIGxpc3QuCgoqKkNvbXB1dGUgZXhwZWN0ZWQgcmV0dXJuIG9mIFBvcnRmb2xpbyoqCmBgYHtyfQpsaXN0X29mX2xpc3RfcmVzdWx0cz1jb21wdXRlKGJldGEocG9ydGZvbGlvKSx2YXJpYW5jZShwb3J0Zm9saW8pKQoKYmV0YT1saXN0X29mX2xpc3RfcmVzdWx0c1tbMV1dCnZhcmlhbmNlPWxpc3Rfb2ZfbGlzdF9yZXN1bHRzW1syXV0KCiNQcmludCBmaXJzdCByb3cgb2YgZXhwZWN0ZWRSZXR1cm4KcHJpbnQoIkJldGEiKQpiZXRhWzEsXQpwcmludCgiVmFyaWFuY2UiKQp2YXJpYW5jZVsxLF0KYGBgCgotLS0tCgojIyAyLiBCYWNrdGVzdGluZyBQb3J0Zm9saW8gRXhlcmNpc2UKCldlIHdpbGwgZGV2ZWxvcCBhIHN0cmF0ZWd5IGJhc2VkIG9uIG1vdmluZyBhdmVyYWdlLiBXZSBkZWZpbmUgdGhlIGZ1bmN0aW9uIGBNQSh6LCBvcmRlcilgIGZvciBtb3ZpbmcgYXZlcmFnZSB0aGF0IHlvdSBjYW4gdXNlIGluIHRoZSBmb2xsb3dpbmcgZXhlcmNpc2UuIApSZWNhbGw6IFRvIGV4ZWN1dGUgdGhlIGNlbGwgYmVsb3csIGNsaWNrIG9uIGl0IGFuZCBwcmVzcyBjdHJsK2VudGVyIG9yIGNsaWNrIGluIENlbGwtPiBydW4gY2VsbHMKCmBgYHtyfQojIE1vdmluZyBBdmVyYWdlIEZ1bmN0aW9uCgpNQT1mdW5jdGlvbih4LG9yZGVyKXsKICByZXN1bHQ8LXgKICB4MTwtYygwLHgpCiAgcmVzdWx0WyhvcmRlcik6TlJPVyh4KV08LShjdW1zdW0oeDEpWy0oMToob3JkZXIpKV0tY3Vtc3VtKHgxKVstKChOUk9XKHgxKS1vcmRlcisxKTpOUk9XKHgxKSldKS9vcmRlcgogIHJlc3VsdFsxOihvcmRlci0xKV08LWN1bXN1bSh4WzE6KG9yZGVyLTEpXSkvKDE6KG9yZGVyLTEpKQogIHJldHVybihyZXN1bHQtMC4wMDAwMDAwMDAxKQp9CmBgYAoKCiMjIyMgMi4xIENyZWF0ZSBhIHBvcnRmb2xpbwoKQ3JlYXRlIGEgcG9ydGZvbGlvIHN0YXJ0aW5nIG9uICIyMDE3LTAzLTI3IiBhbmQgZW5kaW5nICIyMDE3LTAzLTMxIi4gQ3JlYXRlIGEgcG9ydGZvbGlvIHVzaW5nIHRoZSBmdW5jdGlvbiBgcG9ydGZvbGlvX2NyZWF0ZWAuIEJ1eSAxIHN0b2NrIG9mIEdPT0cuIEdldCBwcmljZXMgYW5kIHRpbWUgaW4gZGlmZmVyZW50IHZlY3RvcnMuCgpgYGB7cn0KIyBGaWxsIHRoZSBzdGFydCBkYXRlIGFuZCBlbmQgZGF0ZQpkYXRlU3RhcnQgPSAiMjAxNy0wMy0yNyIKZGF0ZUVuZCA9ICIyMDE3LTAzLTMxIgoKI0NyZWF0ZSBwb3J0Zm9saW8KcG9ydGZvbGlvPXBvcnRmb2xpb19jcmVhdGUoZnJvbVRpbWU9ZGF0ZVN0YXJ0LHRvVGltZT1kYXRlRW5kKQoKI0J1eSAxIHN0b2NrIG9mIEdPT0cuIEZpbGwgdGhlIHF1YW50aXR5LgpzeW1ib2wgPSAiR09PRyIKcG9zaXRpb249cG9zaXRpb25fYWRkKHBvcnRmb2xpbyxzeW1ib2wscXVhbnRpdHkgPSAxKQpgYGAKCkxldCBzZWUgaG93IHRvIGFjY2VzcyB0aGUgcHJpY2UgYW5kIHRoZSB0aW1lLiBDYWxjdWxhdGUgdGhlIHByaWNlIG9mIHRoZSBwb3NpdGlvbiB1c2luZyBgY29tcHV0ZSgpYCBmdW5jdGlvbi4KU2F2ZSB5b3VyIHRpbWUgdmVjdG9yICh0aGUgZmlyc3QgY29sdW1uKSBhbmQgdGhlIHByaWNlIHZlY3RvciAoc2Vjb25kIGNvbHVtbikgc2VwYXJhdGVseS4gYGNvbXB1dGUoKWAgZnVuY3Rpb24gcmV0dXJuIGEgbGlzdCBvZiBsaXN0IGhlbmNlIFtbMV1dLiBgaGVhZCgpYCBmdW5jdGlvbiBhbGxvd3MgaW4gUiB0byBzZWUgdGhlIGZpcnN0IGVsZW1lbnRzIG9mIGEgZGF0YWZyYW1lLiBVc2luZyBoZWFkKCksIGNoZWNrIHRoZSBwcmljZSBhbmQgdGltZSB2ZWN0b3IuCgpgYGB7cn0KI1NhdmUgeW91ciB0aW1lIHZlY3RvciAodGhlIGZpcnN0IGNvbHVtbikgYW5kIHRoZSBwcmljZSB2ZWN0b3IgKHNlY29uZCBjb2x1bW4pIHNlcGFyYXRlbHkuCnByaWNlPWNvbXB1dGUocHJpY2UocG9zaXRpb24pKVtbMV1dCnByaW50VGltZT1wcmljZVssMV0KCiNVc2luZyBoZWFkKCksIGNoZWNrIGZpcnN0IGVsZW1lbnRzIG9mIHByaWNlCmhlYWQocHJpY2UpCmBgYAoKCiMjIyMgMi4yIFByaWNlIHZlY3RvciBjcmVhdGlvbgoKVXNlIHByaWNlIHZlY3RvciB0byBjcmVhdGUgYSBzdHJhdGVneSBiYXNlZCBvbiBtb3ZpbmcgYXZlcmFnZS4gV2UgYXNzdW1lIHRoYXQgcHJpY2VzIHRlbmQgdG8gcmV2ZXJ0IHRvIGl0cyBtb3ZpbmcgYXZlcmFnZS4gVGhlcmVmb3JlLCBpZiB0aGUgcHJpY2VzIGFyZSBiZWxvdyBpdHMgbW92aW5nIGF2ZXJhZ2UsIHdlIGdldCBpbnRvIHRoZSBwb3NpdGlvbiBieSAxIHVuaXQuIElmIHByaWNlcyBhcmUgYWJvdmUgdGhlIG1vdmluZyBhdmVyYWdlLCB3ZSBhcmUgb3V0IG9mIHBvc2l0aW9uLiBVc2UgdGhlIHdpbmRvdz0xMDAgYW5kIE1BKCkgZnVuY3Rpb24gdGhhdCB5b3Ugd2VyZSBnaXZlbiBpbiBhZHZhbmNlLgoKYGBge3J9CiNJbml0aWFsaXplIGFuIGFycmF5IG9mIHRoZSBzYW1lIGxlbmd0aCBhcyBwcmljZSB1c2luZyBOUk9XKHByaWNlKQpTdHJhdGVneSA9IGFycmF5KDAsZGltPW5yb3cocHJpY2UpKQoKI0ZpbGwgdGhlIHdpbmRvdyBsZW5ndGgKU3RyYXRlZ3lbcHJpY2VbLCJ2YWx1ZSJdPE1BKHByaWNlWywidmFsdWUiXSwxMDApXT0xCgojV2UgYXNzdW1lIHRoYXQgd2Ugd2lsbCB1c2UgdGhlIHNpZ25hbCBzdHJhdGVneSB0byBlbnRlciB0aGUgcG9zaXRpb24gaW4gdGhlIG5leHQgc2Vjb25kLgojVG8gZG8gdGhpcywgbW92ZSB0aGUgdmVjdG9yIHNpZ25hbCBieSBhZGRpbmcgdGhlIGZpcnN0IGVsZW1lbnQgb2YgMCBhbmQgcmVtb3ZpbmcgdGhlIGxhc3QgZWxlbWVudC4KU3RyYXRlZ3k9YygwLFN0cmF0ZWd5Wy1sZW5ndGgoU3RyYXRlZ3kpXSkKYGBgCgojIyMjIDIuMyBQb3J0Zm9saW8gc3RyYXRlZ3kKCkNyZWF0ZSBhIHBvcnRmb2xpbyBzdHJhdGVneSBiYXNlZCBvbiBvbiB0aGUgcHJldmlvdXMgcGFydHMuIFVzZSB0aGUgc2FtZSB0aW1lIGludGVydmFsIGFzIGJlZm9yZSBmcm9tIHNhdGVTdGFydCB0byBlbmREYXRlLiBXaGVuIGFkZGluZyBpdGVtIEdPT0cgcGFzcyBhIHZhcmlhYmxlICdxdWFudGl0eScgdmVjdG9yIG9mIHlvdXIgc3RyYXRlZ3ksIGFuZCB2YXJpYWJsZSAndGltZScgdmVjdG9yIHRpbWUgdGhhdCB5b3Ugc2F2ZWQgcHJldmlvdXNseS4gVGhlc2UgdmVjdG9ycyBtdXN0IGJlIHRoZSBzYW1lIGxlbmd0aC4gVGhlbiBwbG90IGxvZyByZXR1cm4gb2YgcG9ydGZvbGlvLgoKYGBge3J9CiNkYXRlU3RhcnQgPSAiMjAxNy0xMC0wMSIKI2RhdGVFbmQgPSAiMjAxNy0wMy0wNyIKCiNDcmVhdGUgYSBwb3J0Zm9saW8gc3RyYXRlZ3kgYmFzZWQgb24gdGhhdC4gRmlsbCB0aGUgcGFyYW1ldGVycyBmcm9tVGltZSB3aXRoIGRhdGVTdGFydCAmIHRvVGltZSB3aXRoIGRhdGVFbmQKcG9ydGZvbGlvPXBvcnRmb2xpb19jcmVhdGUoZnJvbVRpbWU9ZGF0ZVN0YXJ0LHRvVGltZT1kYXRlRW5kKQoKI0FkZCBwb3NpdGlvbiB0byB0aGUgZW1wdHkgcG9ydGZvbGlvIHVzaW5nIHF1YW50aXR5PVN0cmF0ZWd5IGFuZCB0aW1lPXByaW50VGltZQojUmVjYWxsIHdlIGNhbGN1bGF0ZWQgdGhlIHZlY3RvciBTdHJhdGVneSBpbiBwYXJ0IDIuIGFuZCBwcmludFRpbWUgaW4gcGFydDEKcG9zaXRpb249cG9zaXRpb25fYWRkKHBvcnRmb2xpbz1wb3J0Zm9saW8sc3ltYm9sPXN5bWJvbCxxdWFudGl0eT1TdHJhdGVneSx0aW1lPXByaW50VGltZSkKCiNQbG90IGxvZyByZXR1cm4gb2YgcG9ydGZvbGlvLgpwbG90KGxvZ19yZXR1cm4ocG9ydGZvbGlvKSxmb250X3NpemU9Nixidz1UUlVFLHRpdGxlPSJQb3J0Zm9saW8gbG9nIHJldHVybiIpCmBgYAoKCiMjIyMgMi40IEZpbmQgdGhlIG9wdGltYWwgbW92aW5nIGF2ZXJhZ2Ugd2luZG93IGxlbmd0aAoKTGV0J3MgZmluZCB0aGUgb3B0aW1hbCBsZW5ndGggb2YgYSBtb3ZpbmcgYXZlcmFnZSB3aW5kb3cuICBGb3IgdGhhdCB3ZSB3aWxsIGNyZWF0ZSBhIGxvb3AgaW4gd2hpY2ggdGhlIHdpbmRvdyB3aWxsIHZhcnkgZnJvbSA1IHRvIDUwIHdpdGggYSBzdGVwIG9mIDUuIFdlIGFyZSBzcGVha2luZyBoZXJlIGFib3V0IHRoZSB3aW5kb3cgb2YgdGhlIG1vdmluZyBhdmVyYWdlLiBUbyByZWNvcmQgdGhlIHJlc3VsdCwgY3JlYXRlIGFuIGVtcHR5IHZlY3RvciBgcmVzdWx0ID0gTlVMTGAuIEFkZCBhIG5ldyBzZXR0aW5nIGluIHRoZSBwb3J0Zm9saW8gdG8gYWNjZWxlcmF0ZSB0aGUgd29yayA6IGBwb3J0Zm9saW9fc2V0dGluZ3MocG9ydGZvbGlvLHJlc3VsdHNTYW1wbGluZ0ludGVydmFsPSdsYXN0JylgLiBDYWxjdWxhdGUgdGhlIHZhbHVlIG9mIHRoZSBsb2dhcml0aG1pYyBwb3J0Zm9saW8gcmV0dXJucyBhbmQgYWRkIHRoZW0gdG8gdGhlIHZlY3RvciByZXN1bHQgYXMgOiBgcmVzdWx0PXJiaW5kKHJlc3VsdCxjKHdpbmRvdyxjb21wdXRlKGxvZyByZXR1cm4ocG9ydGZvbGlvKSlbWzFdXVsyXSkpYAoKYGBge3J9CiNDcmVhdGUgYW4gZW1wdHkgdmVjdG9yIHJlc3VsdCB0byBOVUxMCnJlc3VsdD1OVUxMCgojQ3JlYXRlIGEgbG9vcCB3aXRoIHdpbmRvdyB2YXJ5aW5nIGZyb20gNSB0byA1MApmb3Iod2luZG93ICBpbiBzZXEoNSw1MCxieT01KSl7CiAgI0luc2lkZSB0aGUgbG9vcCwgd2UgdXNlIHRoZSBwcmV2aW91c2x5IHdyaXR0ZW4gY29kZSBmb3IgdGhlIGNyZWF0aW9uIG9mIGEgc3RyYXRlZ2ljIHBvcnRmb2xpbyBpbiBwYXJ0MSwgYW5kIDIKICAjIGJ1dCBpbnN0ZWFkIG9mIHRoZSBwcmV2aW91c2x5IHNldCB3aW5kb3cgaW4gTUEgZnVuY3Rpb24gdXNpbmcgY2hhbmdpbmcgdmFyaWFibGUuCiAgcG9ydGZvbGlvPXBvcnRmb2xpb19jcmVhdGUoZnJvbVRpbWU9ZGF0ZVN0YXJ0LHRvVGltZT1kYXRlRW5kKQogIFN0cmF0ZWd5ID0gYXJyYXkoMCxkaW09bnJvdyhwcmljZSkpCiAgCiAgI1B1dCB0aGUgcGFyYW1ldGVyIHdpbmRvdyBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IHRvIE1BIGZ1Y250aW9uICAgCiAgU3RyYXRlZ3lbcHJpY2VbLCJ2YWx1ZSJdPE1BKHByaWNlWywidmFsdWUiXSwgd2luZG93KV09MQogIFN0cmF0ZWd5PWMoMCxTdHJhdGVneVstbGVuZ3RoKFN0cmF0ZWd5KV0pCiAgcG9zaXRpb249cG9zaXRpb25fYWRkKHBvcnRmb2xpbz1wb3J0Zm9saW8sc3ltYm9sPXN5bWJvbCxxdWFudGl0eT1TdHJhdGVneSx0aW1lPXByaW50VGltZSkKICAKICAjQWRkIGEgbmV3IHNldHRpbmcgaW4gdGhlIHBvcnRmb2xpbyB0byBhY2NlbGVyYXRlIHRoZSB3b3JrOiByZXN1bHRzU2FtcGxpbmdJbnRlcnZhbD0nbGFzdCcKICBwb3J0Zm9saW9fc2V0dGluZ3MocG9ydGZvbGlvLHJlc3VsdHNTYW1wbGluZ0ludGVydmFsPSdsYXN0JykKICAKICAjQ2FsY3VsYXRlIHRoZSB2YWx1ZSBvZiB0aGUgbG9nYXJpdGhtaWMgcG9ydGZvbGlvIHJldHVybnMgYW5kIAogICNhZGQgdGhlbSB0byB0aGUgdmVjdG9yIHJlc3VsdCBhczogcmVzdWx0PXJiaW5kKHJlc3VsdCxjKHdpbmRvdyxjb21wdXRlKGxvZ19yZXR1cm4ocG9ydGZvbGlvKSlbWzFdXVsyXSkpCiAgcmVzdWx0PXJiaW5kKHJlc3VsdCxjKHdpbmRvdyxjb21wdXRlKGxvZ19yZXR1cm4ocG9ydGZvbGlvKSlbWzFdXVsyXSkpCn0KYGBgCgpMb2dhcml0aG1pYyBwb3J0Zm9saW8gcmV0dXJucwoKYGBge3J9CiNwbG90IHJlc3VsdApwbG90KHJlc3VsdCx0eXBlPSdsJywgYW5uPUZBTFNFKQp0aXRsZShtYWluPSJPcHRpbWFsIE1BIHdpbmRvdyBsZW5ndGgiLCB4bGFiPSJ3aW5kb3cgbGVuZ3RoIiwgeWxhYj0ibG9nIHJldHVybiIpCmBgYAoKIyMjIyAyLjUgRmluZGluZyB0aGUgb3B0aW1hbCBtb3ZpbmcgYXZlcmFnZSB3aW5kb3cgbGVuZ3RoIHdpdGggdHJhbnNhY3Rpb24gY29zdHMKCkRvIHRoZSBzYW1ldGhpbmcgYXMgaW4gNC4sIGp1c3QgYWRkIGEgbmV3IHNldHRpbmcgaW4gdGhlIHBvcnRmb2xpbyBhcyB0aGUgdHJhbnNhY3Rpb24gY29zdHMgd2hpY2ggaXMgMC4wMyBwZXIgc2hhcmU6IGBwb3J0Zm9saW9fc2V0dGluZ3MocG9ydGZvbGlvLHJlc3VsdHNTYW1wbGluZ0ludGVydmFsPSdsYXN0Jyx0eG5Db3N0UGVyU2hhcmU9MC4wMylgLiBVc2UgdGhlIHByZXZpb3VzbHkgd3JpdHRlbiBjb2RlLiBPYnNlcnZlIGhvdyB0aGUgcmVzdWx0cyBjaGFuZ2UuCgpgYGB7cn0KI0NyZWF0ZSBhbiBlbXB0eSB2ZWN0b3IgcmVzdWx0V2l0aFR4biA9IE5VTEwKcmVzdWx0V2l0aFR4bj1OVUxMCgojQ3JlYXRlIGEgbG9vcCB3aXRoIHdpbmRvdyB2YXJ5aW5nIGZyb20gNTo1MApmb3Iod2luZG93IGluIHNlcSg1LDUwLGJ5PTUpKXsKICBwb3J0Zm9saW89cG9ydGZvbGlvX2NyZWF0ZShmcm9tVGltZT1kYXRlU3RhcnQsdG9UaW1lPWRhdGVFbmQpCiAgICAKICAjQWRkIHRoZSB0cmFuc2FjdGlvbiBjb3N0cyBwZXIgc2hhcmUgdHhuQ29zdFBlclNoYXJlPTAuMDMKICBwb3J0Zm9saW9fc2V0dGluZ3MocG9ydGZvbGlvLHJlc3VsdHNTYW1wbGluZ0ludGVydmFsPSdsYXN0Jyx0eG5Db3N0UGVyU2hhcmU9MC4wMykKICBTdHJhdGVneSA9IGFycmF5KDAsZGltPU5ST1cocHJpY2UpKQogIFN0cmF0ZWd5W3ByaWNlWywidmFsdWUiXTxNQShwcmljZVssInZhbHVlIl0sd2luZG93KV09MQogIFN0cmF0ZWd5PWMoMCxTdHJhdGVneVstbGVuZ3RoKFN0cmF0ZWd5KV0pCiAgCiAgcG9zaXRpb249cG9zaXRpb25fYWRkKHBvcnRmb2xpbz1wb3J0Zm9saW8sc3ltYm9sPXN5bWJvbCxxdWFudGl0eT1TdHJhdGVneSx0aW1lPXByaW50VGltZSkKICAKICByZXN1bHRXaXRoVHhuPXJiaW5kKHJlc3VsdFdpdGhUeG4sYyh3aW5kb3csY29tcHV0ZShsb2dfcmV0dXJuKHBvcnRmb2xpbykpW1sxXV1bMl0pKQp9CmBgYAoKCmBgYHtyfQojUGxvdCByZXN1bHRXaXRoVHhuCnBsb3QocmVzdWx0V2l0aFR4bix0eXBlPSdsJywgYW5uPUZBTFNFKQp0aXRsZShtYWluPSJPcHRpbWFsIE1BIHdpbmRvdyBsZW5ndGggd2l0aCB0cmFuc2FjdGlvbiBjb3N0IiwgeGxhYj0id2luZG93IGxlbmd0aCIsIHlsYWI9ImxvZyByZXR1cm4iKQpgYGAKCldlIGhhdmUgc2VlbiB0aGF0IHRoZSBvcHRpbWFsIHdpbmRvdyB3aWxsIGluY3JlYXNlIHdpdGggdGhlIGFkZGl0aW9uIG9mIHRyYW5zYWN0aW9uIGNvc3RzLgoKLS0tLS0KCiMjIDMuIFZvbGF0aWxpdHkgRm9yZWNhc3RpbmcgRXhlcmNpc2UKCiMjIyMgMy4xIENyZWF0ZSBhIHBvcnRmb2xpbwpDcmVhdGUgYSBwb3J0Zm9saW8gc3RhcnRpbmcgb24gMjAxNS0wMS0wMSBhbmQgZW5kaW5nIDIwMTUtMTItMzEuIEJ1eSAxIHN0b2NrIG9mIGdvb2dsZSAoIkdPT0ciKS4KCmBgYHtyfQojQ3JlYXRlIGEgcG9ydGZvbGlvIHN0YXJ0aW5nIDIwMTUtMDEtMDEgYW5kIGVuZGluZyAyMDE1LTEyLTMxCmRhdGVTdGFydCA9ICIyMDE1LTAxLTAxIgpkYXRlRW5kID0gIjIwMTUtMTItMzEiCgpwb3J0Zm9saW8gPSBwb3J0Zm9saW9fY3JlYXRlKGZyb21UaW1lPWRhdGVTdGFydCx0b1RpbWU9ZGF0ZUVuZCkKCiNBZGQgIkdPT0ciIHN0b2NrcyB2b2x1bWUgb2YgMSB1bml0cyBhcyBwb3NpdGlvbkdPT0cuCnBvc2l0aW9uR09PRyA9IHBvc2l0aW9uX2FkZChwb3J0Zm9saW8gPSBwb3J0Zm9saW8sc3ltYm9sID0gIkdPT0ciLHF1YW50aXR5ID0gMSkKYGBgCgoKIyMjIyAzLjIgQ2hhbmdlIHBvcnRmb2xpbyBzZXR0aW5ncwoKSW4gcG9ydGZvbGlvJ3Mgc2V0dGluZ3Mgc2V0IHRoZSByZXN1bHRzU2FtcGxpbmdJbnRlcnZhbCBhbmQgaW5wdXRTYW1wbGluZ0ludGVydmFsIGFzIG9uZSBob3VyICgiMWgiKS4gaW5wdXRTYW1wbGluZ0ludGVydmFsIGNvcnJlc3BvbmRzIHRoZSBmcmVxdWVuY3kgYmV0d2VlbiB0aGUgbWFya2V0IGRhdGEgaW5wdXQuIHJlc3VsdHNTYW1wbGluZ0ludGVydmFsIGNvcnJlcG9uZHMgdG8gdGhlIGZyZXF1ZW5jeSBiZXR3ZWVuIHRoZSBvdXRwdXQgb2YgdGhlIHJlc3VsdHMuCgpgYGB7cn0KI0luIHRoZSBzZXR0aW5ncyBzZXQgdGhlIHJlc3VsdHNTYW1wbGluZ0ludGVydmFsIGFuZCBpbnB1dFNhbXBsaW5nSW50ZXJ2YWwgYXMgb25lIGhvdXIgJzFoJy4KcG9ydGZvbGlvX3NldHRpbmdzKHBvcnRmb2xpbyxpbnB1dFNhbXBsaW5nSW50ZXJ2YWw9IjFoIixyZXN1bHRzU2FtcGxpbmdJbnRlcnZhbD0iMWgiKQpgYGAKCiMjIDMuMyBDcmVhdGUgZm9yZWNhc3Qgb2JqZWN0CgpDcmVhdGUgZm9yZWNhc3Qgb2JqZWN0IG9mIHZhcmlhbmNlIG9uIHRoZSBwb3NpdGlvbkdPT0cgdXNpbmcgbW9kZWwgRVdNQSBhbmQgYGZvcmVjYXN0X2J1aWxkZXIoKWAgZnVuY3Rpb24uIFRoZW4gdXNlIGBmb3JlY2FzdF9hcHBseSgpYC4KCmBgYHtyfQojQ3JlYXRlIGZvcmVjYXN0IG9iamVjdCBvZiB2YXJpYW5jZSBHT09HIHBvc2l0aW9uLCBtb2RlbCAnRVdNQScgCmZvcmVjYXN0X0J1aWxkZXJfRVdNQT1mb3JlY2FzdF9idWlsZGVyKHZhcmlhbmNlKHBvc2l0aW9uR09PRyksbW9kZWw9IkVXTUEiKQoKI0FwcGx5IGl0IGFzIGZvcmVjYXN0X1ZhcmlhbmNlX0VXTUEuCmZvcmVjYXN0X1ZhcmlhbmNlX0VXTUE9Zm9yZWNhc3RfYXBwbHkoZm9yZWNhc3RfQnVpbGRlcl9FV01BKQpgYGAKClByaW50IHN1bSBvZiBzcXVhcmVkIGZvcmVjYXN0IGVycm9ycy4KCmBgYHtyfQojUHJpbnQgc3VtIG9mIHNxdWFyZWQgZm9yZWNhc3QgZXJyb3JzIG9mIGZvcmVjYXN0X1ZhcmlhbmNlX0VXTUEgYW5kIHZhcmlhbmNlX0dPT0cKcHJpbnQoIkVycm9yIHdpdGggRVdNQSBtb2RlbCIpCmVycm9yX0VXTUE9c3VtKGNvbXB1dGUoZm9yZWNhc3RfVmFyaWFuY2VfRVdNQS12YXJpYW5jZShwb3NpdGlvbkdPT0cpKVtbMV1dWywyXV4yKQpwcmludChlcnJvcl9FV01BKQpgYGAKCiMjIyMgMy40IFVzZSBIQVIgbW9kZWwKCkRvIHRoZSBzYW1lIHN0ZXBzIHRoYW4gaW4gMSwyLDMgYnV0IHVzZSBIQVIgbW9kZWwgaW5zdGVhZAoKYGBge3J9CiNDcmVhdGUgYSBwb3J0Zm9saW8gYWdhaW4uIERvIHRoZSBzYW1lIHRoaW5nLCBzcGVjaWZ5IG9ubHkgbW9kZWwgJ0hBUicKcG9ydGZvbGlvPXBvcnRmb2xpb19jcmVhdGUoZnJvbVRpbWU9ZGF0ZVN0YXJ0LHRvVGltZT1kYXRlRW5kKQpwb3NpdGlvbkdPT0c9cG9zaXRpb25fYWRkKHBvcnRmb2xpbywiR09PRyIsMSkKCiMjSW4gdGhlIHNldHRpbmdzIHNldCB0aGUgcmVzdWx0c1NhbXBsaW5nSW50ZXJ2YWwgYW5kIGlucHV0U2FtcGxpbmdJbnRlcnZhbCBhcyBvbmUgaG91ciAnMWgnCnBvcnRmb2xpb19zZXR0aW5ncyhwb3J0Zm9saW8saW5wdXRTYW1wbGluZ0ludGVydmFsPSIxaCIscmVzdWx0c1NhbXBsaW5nSW50ZXJ2YWw9IjFoIikKCiNVc2UgJ0hBUicgbW9kZWwKZm9yZWNhc3RfQnVpbGRlcl9IQVI9Zm9yZWNhc3RfYnVpbGRlcih2YXJpYW5jZShwb3NpdGlvbkdPT0cpLG1vZGVsPSJIQVIiKQoKI0FwcGx5IGZvcmVjYXN0X2FwcGx5IGZ1bmN0aW9uIHRvIGZvciBmb3JlY2FzdF9CdWlsZGVyX0hBUiBvYmplY3QKZm9yZWNhc3RfVmFyaWFuY2VfSEFSPWZvcmVjYXN0X2FwcGx5KGZvcmVjYXN0X0J1aWxkZXJfSEFSKQoKI1ByaW50IHN1bSBvZiBzcXVhcmVkIGZvcmVjYXN0IGVycm9ycyBvZiBmb3JlY2FzdF9WYXJpYW5jZV9IQVIgYW5kIHZhcmlhbmNlX0dPT0cKcHJpbnQoIkVycm9yIHdpdGggSEFSIG1vZGVsIikKZXJyb3JfSEFSPXN1bShjb21wdXRlKGZvcmVjYXN0X1ZhcmlhbmNlX0hBUi12YXJpYW5jZShwb3NpdGlvbkdPT0cpKVtbMV1dWywyXV4yKQpwcmludChlcnJvcl9IQVIpCmBgYAoKCgojIyMjIDMuNSBBZGQgbWV0cmljIGJldGEgCgpSZXBlYXQgc3RlcHMgMSwyLDMgYW5kIGFkZCB0aGUgbWV0cmljIGJldGEgb2YgcG9zaXRpb25HT09HIGluIHJlZ3Jlc3Npb24gdXNpbmcgZnVuY3Rpb24gYGZvcmVjYXN0X2lucHV0KClgLiBXZSB3aWxsIHNlZSBpZiB3ZSBhZGQgdGhlIHZhcmlhYmxlIGJldGEgaXQgd2lsbCBpbXByb3ZlIHRoZSBmb3JlY2FzdC4gOTAlIG9mIHRoZSBjYXNlIGFkZGluZyBiZXRhIHdpbGwgZ2l2ZSBhIGJldHRlciBmb3JlY2FzdGluZyB2b2xhdGlsaXR5IGJ1dCB3aWxsIHJlcXVpcmUgbW9yZSBwb3dlcmZ1bCBjb21wdXRhdGlvbmFsIHBvd2VyLgoKYGBge3J9CiNXZSBzZWUgdGhhdCB0aGUgZXJyb3IgSEFSIGZvcmVjYXN0IGlzIHNtYWxsZXIuIFdpbGwgaXQgaW1wcm92ZSB0aGUgZm9yZWNhc3QsIGlmIHdlIGFkZCBhIHZhcmlhYmxlIGJldGEgaW4gdGhlIHJlZ3Jlc3Npb24gPwojQ3JlYXRlIGEgcG9ydGZvbGlvCnBvcnRmb2xpbz1wb3J0Zm9saW9fY3JlYXRlKGZyb21UaW1lPWRhdGVTdGFydCx0b1RpbWU9ZGF0ZUVuZCkKcG9zaXRpb25HT09HPXBvc2l0aW9uX2FkZChwb3J0Zm9saW8sIkdPT0ciLDEpCnBvcnRmb2xpb19zZXR0aW5ncyhwb3J0Zm9saW8saW5wdXRTYW1wbGluZ0ludGVydmFsPScxaCcscmVzdWx0c1NhbXBsaW5nSW50ZXJ2YWw9JzFoJykKCiNVc2UgZm9yZWNhc3RfYnVpbGRlciB0byBjcmVhdGUgdGhlIGZvcmVjYXN0IG9iamVjdApmb3JlY2FzdF9CdWlsZGVyX0hBUl9iZXRhPWZvcmVjYXN0X2J1aWxkZXIodmFyaWFuY2UocG9zaXRpb25HT09HKSxtb2RlbD0nSEFSJykKCiNBZGQgdGhlIG1ldHJpYyBiZXRhIG9mIHBvc2l0aW9uR09PRyAoYmV0YShwb3NpdGlvbkdPT0cpKSBpbiByZWdyZXNzaW9uIHVzaW5nIGZ1bmN0aW9uIGZvcmVjYXN0X2lucHV0Lgpmb3JlY2FzdF9CdWlsZGVyX0hBUl9iZXRhPWZvcmVjYXN0X2lucHV0KGZvcmVjYXN0X0J1aWxkZXJfSEFSX2JldGEsYmV0YShwb3NpdGlvbkdPT0cpKQpmb3JlY2FzdF9WYXJpYW5jZV9IQVJfYmV0YT1mb3JlY2FzdF9hcHBseShmb3JlY2FzdF9CdWlsZGVyX0hBUl9iZXRhKQoKI0NhbGN1bGF0ZSB0aGUgc3VtIG9mIHNxdWFyZXMgb2YgZm9yZWNhc3QgZXJyb3JzIGFnYWluIGJldHdlZW4gZm9yZWNhc3RfVmFyaWFuY2VfSEFSX2JldGEgYW5kIHZhcmlhbmNlKHBvc2l0aW9uR09PRykKcHJpbnQoIkVycm9yIHdpdGggSEFSIG1vZGVsIGFuZCBiZXRhIikKZXJyb3JfSEFSX2FuZF9iZXRhPXN1bShjb21wdXRlKGZvcmVjYXN0X1ZhcmlhbmNlX0hBUl9iZXRhLXZhcmlhbmNlKHBvc2l0aW9uR09PRykpW1sxXV1bLDJdXjIpCnByaW50KGVycm9yX0hBUl9hbmRfYmV0YSkKYGBgCgojIyMjIDMuNiBDb21wYXJlIHJlc3VsdHMKCkNvbXBhcmUgdGhlIDMgbWV0aG9kcyBhYm92ZSBhbmQgZmluZCB3aGljaCBtZXRoZG9sb2d5IGlzIHRoZSBiZXN0IGZvciBmb3JlY2FzdGluZyB0aGUgdmFyaWFuY2Ugb2YgR29vZ2xlIGluIHRoaXMgY2FzZS4KCmBgYHtyfQojQ3JlYXRlIGEgdmVjdG9yIHdpdGggdGhlIDMgZXJyb3JzOiBlcnJvcl9FV01BLCBlcnJvcl9IQVIgYW5kIGVycm9yX0hBUl9hbmRfYmV0YQp2ZWN0b3JfZXJyb3I8LWMoZXJyb3JfRVdNQSxlcnJvcl9IQVIsZXJyb3JfSEFSX2FuZF9iZXRhKQpuYW1lcyh2ZWN0b3JfZXJyb3IpPWMoImVycm9yX0VXTUEiLCJlcnJvcl9IQVIiLCJlcnJvcl9IQVJfYW5kX2JldGEiKQoKI3ByaW50IHZlY3Rvcl9lcnJvcgoKI0dldCB3aGljaCBpbmRpY2UgaGFzIHRoZSBzbWFsbGVyIG1pbmltdW0KaW5kcyA9IHdoaWNoKHZlY3Rvcl9lcnJvciA9PSBtaW4odmVjdG9yX2Vycm9yKSwgYXJyLmluZD1UUlVFKQppbmRzCgojUHJpbnQgdGhlIGVycm9yCnByaW50KCJUaGUgYmVzdCBmb3JlY2FzdGluZyBtb2RlbCBpbiB0aGlzIGNhc2UgaXM6IikKcm5hbWVzID0gdmVjdG9yX2Vycm9yW2luZHNbMV1dCnJuYW1lcwpgYGAKCi0tLS0tLQoKIyMgNC4gUG9ydGZvbGlvIE9wdGltaXphdGlvbiBFeGVyY2lzZQoKIyMjIyA0LjEgQ3JlYXRlIGEgcG9ydGZvbGlvCgpDcmVhdGUgYSBwb3J0Zm9saW8gc3RhcnRpbmcgNSBkYXlzIGFnbyBhbmQgZW5kaW5nICIyMDE3LTAzLTE3Ii4gQnV5IDEwMDAgc3RvY2tzIGZvciBNU0ZULCBHT09HLCBTUFkuCgpgYGB7cn0KZGF0ZVN0YXJ0ID0gIjIwMTctMDMtMTMiCmRhdGVFbmQgPSAiMjAxNy0wMy0xNyIKCiNDcmVhdGUgYSBwb3J0Zm9saW8gc3RhcnRpbmcgNSBkYXlzIGFnbyAiMjAxNy0wMy0xMyIgYW5kIGVuZGluZyB0b2RheSAiMjAxNy0wMy0xNyIuCnBvcnRmb2xpbzwtcG9ydGZvbGlvX2NyZWF0ZShkYXRlU3RhcnQsIGRhdGVFbmQpCgojQWRkIHRocmVlIGxpcXVpZCBzdG9ja3M6ICJBQVBMIiwgIkdPT0ciLCAiU1BZIiB2b2x1bWUgb2YgMTAwMCB1bml0cy4KcG9zaXRpb25fQUFQTD1wb3NpdGlvbl9hZGQocG9ydGZvbGlvLHN5bWJvbD0iQUFQTCIscXVhbnRpdHkgPSAxMDAwKQpwb3NpdGlvbl9HT09HPXBvc2l0aW9uX2FkZChwb3J0Zm9saW8sc3ltYm9sPSJHT09HIixxdWFudGl0eSA9IDEwMDApCnBvc2l0aW9uX1NQWT1wb3NpdGlvbl9hZGQocG9ydGZvbGlvLHN5bWJvbD0iU1BZIixxdWFudGl0eSA9IDEwMDApCmBgYAoKCiMjIyMgNC4yIFNldHRpbmdzIGNoYW5nZQoKSW4gdGhlIHNldHRpbmdzIHNldCB0aGUgcG9ydGZvbGlvTWV0cmljc01vZGUgYXMgdGhlIHByaWNlLCBhbmQgcmVzdWx0c1NhbXBsaW5nSW50ZXJ2YWwgb25lIG1pbnV0ZSB0byBzcGVlZCB1cCB0aGUgb3B0aW1pemF0aW9uLgoKYGBge3J9CiNTZXQgdGhlIHBvcnRmb2xpb01ldHJpY3NNb2RlIGFzIHRoZSBwcmljZSwgCiNhbmQgcmVzdWx0c1NhbXBsaW5nSW50ZXJ2YWwgb25lIG1pbnV0ZQpwb3J0Zm9saW9fc2V0dGluZ3MocG9ydGZvbGlvLHBvcnRmb2xpb01ldHJpY3NNb2RlPSJwcmljZSIscmVzdWx0c1NhbXBsaW5nSW50ZXJ2YWw9IjFtIikKYGBgCgojIyMjIDQuMyBHb2FsIG9wdGltaXphdGlvbgoKQ3JlYXRlIGEgZ29hbCBvcHRpbWl6YXRpb24gb2JqZWN0IHRvIG1heGltaXplIHRoZSBTaGFycGUgcmF0aW8gb2YgdGhlIHBvcnRmb2xpby4KCmBgYHtyfQojRGlyZWN0aW9uIHNob3VsZCBiZSBzZXQgdG8gIm1heCIKI0Zpc3QgcGFyYW1ldGVyIG9mIG9wdGltaXphdGlvbl9nb2FsIHNob3VsZCBiZSBzZXQgdG8gc2hhcnBlX3JhdGlvKHBvcnRmb2xpbykKb3B0aW1pemVyPW9wdGltaXphdGlvbl9nb2FsKHNoYXJwZV9yYXRpbyhwb3J0Zm9saW8pLGRpcmVjdGlvbj0ibWF4IikKCmBgYAoKIyMjIyA0LjQgQ29uc3RyYWludAoKU2V0IHRoZSBjb25zdHJhaW50IGZvciB2YWx1ZSAocG9ydGZvbGlvKSBlcXVhbCB0byAxMDAsMDAwIHRvIGRlY2xhcmUgdGhlIHZvbHVtZSBvZiB0aGUgb3B0aW1hbCBwb3J0Zm9saW8uIENhbGN1bGF0ZSB0aGUgb3B0aW1hbCBwb3J0Zm9saW8uTmFtZSB0aGUgb3B0aW1hbCBwb3J0Zm9saW8gYXMgYSBvcHRpbVBvcnRmb2xpb05vQ29uc3RyYWludHMuCgpgYGB7cn0KI1NldCB0aGUgY29uc3RyYWludCBmb3IgdmFsdWUgKHBvcnRmb2xpbykgZXF1YWwgdG8gMTAwMDAwCm9wdGltaXplcj1vcHRpbWl6YXRpb25fY29uc3RyYWludChvcHRpbWl6ZXIsdmFsdWUocG9ydGZvbGlvKSwnPScsMTAwMDAwKQoKI0NhbGN1bGF0ZSB0aGUgb3B0aW1hbCBwb3J0Zm9saW8uIE5hbWUgdGhlIG9wdGltYWwgcG9ydGZvbGlvIGFzIGEgb3B0aW1Qb3J0Zm9saW9Ob0NvbnN0cmFpbnRzCm9wdGltUG9ydGZvbGlvTm9Db25zdHJhaW50cz1vcHRpbWl6YXRpb25fcnVuKG9wdGltaXplcikKYGBgCgojIyMjIDQuNSAgQ3JlYXRlIGFub3RoZXIgb3B0aW1pemF0aW9uIHBvcnRmb2xpbwoKWW91IHdpbGwgYWRkIGFuIGFkZGl0aW9uYWwgY29uc3RyYWludC4gTWFrZSB0aGUgc2FtZSBvcHRpbWl6YXRpb24sIGp1c3QgYWRkIGFuIGFkZGl0aW9uYWwgY29uc3RyYWludCBvbiB0aGUgcG9ydGZvbGlvIGJldGEgb2YgemVyby4gTmFtZSB0aGUgb3B0aW1hbCBwb3J0Zm9saW8gYXMgYSBvcHRpbVBvcnRmb2xpb09uZUNvbnN0cmFpbnRzCgpgYGB7cn0KI1NhbWUgbWV0aG9kIGFzIGFib3ZlCm9wdGltaXplcj1vcHRpbWl6YXRpb25fZ29hbChzaGFycGVfcmF0aW8ocG9ydGZvbGlvKSxkaXJlY3Rpb249Im1heCIpCm9wdGltaXplcj1vcHRpbWl6YXRpb25fY29uc3RyYWludChvcHRpbWl6ZXIsdmFsdWUocG9ydGZvbGlvKSwnPScsMTAwMDAwKQoKI1NldCBwb3J0Zm9saW8gYmV0YSB0byB6ZXJvCm9wdGltaXplcj1vcHRpbWl6YXRpb25fY29uc3RyYWludChvcHRpbWl6ZXIsYmV0YShwb3J0Zm9saW8pLCI9IiwwKQoKIyBOYW1lIHRoZSBvcHRpbWFsIHBvcnRmb2xpbyBhcyBhIG9wdGltUG9ydGZvbGlvT25lQ29uc3RyYWludHMKb3B0aW1Qb3J0Zm9saW9PbmVDb25zdHJhaW50cz1vcHRpbWl6YXRpb25fcnVuKG9wdGltaXplcikKYGBgCgojIyMjIDQuNiBQbG90IG9wdGltaXphdGlvbiByZXN1bHRzCgpEaXNwbGF5IHRoZSBjaGFydHMgb2YgdGhlIHR3byBvcHRpbWFsIHBvcnRmb2xpb3MgZm9yIHRoZSBiZXRhLiBZb3Ugd2lsbCBuZWVkIHRvIHNwZWNpZnkgYSBsZWdlbmQgZm9yIGdyYXBocy4KCmBgYHtyfQojSW5wdXQgY2FsY3VsYXRpb24gb2YgYmV0YShvcHRpbVBvcnRmb2xpb09uZUNvbnN0cmFpbnRzKSBhbmQgYmV0YShvcHRpbVBvcnRmb2xpb05vQ29uc3RyYWludHMpIApiZXRhX29uZV9jb25zdHJhaW4gPSBiZXRhKG9wdGltUG9ydGZvbGlvT25lQ29uc3RyYWludHMpCmJldGFfbm9fY29uc3RyYWluID0gYmV0YShvcHRpbVBvcnRmb2xpb05vQ29uc3RyYWludHMpCnBsb3QoYmV0YV9vbmVfY29uc3RyYWluLGJldGFfbm9fY29uc3RyYWluLHRpdGxlPSJiZXRhIixsZWdlbmQ9YygnT25lIENvbnN0cmFpbnRzJywnTm8gQ29uc3RyYWludHMnKSxmb250X3NpemU9Nixidz1UUlVFKQpgYGAKCkRpc3BsYXkgdGhlIGNoYXJ0cyBvZiB0aGUgdHdvIG9wdGltYWwgcG9ydGZvbGlvcyBmb3IgU2hhcnBlIHJhdGlvLiBZb3Ugd2lsbCBuZWVkIHRvIHNwZWNpZnkgYSBsZWdlbmQgZm9yIGdyYXBocy4gCgpgYGB7cn0KI0lucHV0IGNhbGN1bGF0aW9uIG9mIHNoYXJwZV9yYXRpbyhvcHRpbVBvcnRmb2xpb09uZUNvbnN0cmFpbnRzKSBhbmQgc2hhcnBlX3JhdGlvKG9wdGltUG9ydGZvbGlvTm9Db25zdHJhaW50cykgCnNoYXJwZV9vbmVfY29uc3RyYWluID0gc2hhcnBlX3JhdGlvKG9wdGltUG9ydGZvbGlvT25lQ29uc3RyYWludHMpCnNoYXJwZV9ub19jb25zdHJhaW4gPSBzaGFycGVfcmF0aW8ob3B0aW1Qb3J0Zm9saW9Ob0NvbnN0cmFpbnRzKQoKcGxvdChzaGFycGVfb25lX2NvbnN0cmFpbixzaGFycGVfbm9fY29uc3RyYWluLHRpdGxlPSJzaGFycGVfcmF0aW8iLAogICAgIGxlZ2VuZD1jKCdPbmUgQ29uc3RyYWludHMnLCdObyBDb25zdHJhaW50cycpLGZvbnRfc2l6ZT02LGJ3PVRSVUUpCmBgYAoKIyMjIyA0LjcuICBPcHRpbWFsIHBvc2l0aW9uIHBvcnRmb2xpb3MKClRvIGdldCB0aGUgb3B0aW1hbCBwb3NpdGlvbiBwb3J0Zm9saW9zIHVzZSB0aGUgZnVuY3Rpb24gYHBvcnRmb2xpb19nZXRQb3NpdGlvbihwb3J0Zm9saW8sIHN5bWJvbClgLiBCdWlsZCBjaGFydHMgd2VpZ2h0cyBvcHRpbWFsCnBvc2l0aW9ucy4KCmBgYHtyfQojQ2FjdWxhdGUgIkFBUEwiIHdlaWdodAp3ZWlnaHRfQUFQTD13ZWlnaHQocG9ydGZvbGlvX2dldFBvc2l0aW9uKG9wdGltUG9ydGZvbGlvT25lQ29uc3RyYWludHMsIkFBUEwiKSkKI0NhY3VsYXRlICJHT09HIiB3ZWlnaHQKd2VpZ2h0X0dPT0c9d2VpZ2h0KHBvcnRmb2xpb19nZXRQb3NpdGlvbihvcHRpbVBvcnRmb2xpb09uZUNvbnN0cmFpbnRzLCJHT09HIikgKQojQ2FjdWxhdGUgIlNQWSIgd2VpZ2h0CndlaWdodF9TUFk9d2VpZ2h0KHBvcnRmb2xpb19nZXRQb3NpdGlvbihvcHRpbVBvcnRmb2xpb09uZUNvbnN0cmFpbnRzLCJTUFkiKSkKIAojUGxvdCB3ZWlnaHRzOiB3ZWlnaHRfQUFQTCwgd2VpZ2h0X0dPT0cgYW5kIHdlaWdodF9TUFkKcGxvdCh3ZWlnaHRfQUFQTCwKICAgICB3ZWlnaHRfR09PRywKICAgICB3ZWlnaHRfU1BZLAogICAgIHRpdGxlPSdPcHRpbWFsIHBvc2l0aW9ucyBwb3J0Zm9saW8nLCBsZWdlbmQ9YygiQUFQTCIsIkdPT0ciLCJTUFkiKSxmb250X3NpemU9Nixidz1UUlVFKQpgYGAKCgo=