Report
Team
Paula Moloney, Spain
Camila de la Cruz, Peru
Klaus Lindemann, Poland
Statement
Paula:
Worked on L4, L7-L8
Camila:
Worked on L1-L10. I leverage AI-powered tools like ChatGPT as a
starting point for code structure and data organization, such as
creating functions to extract data from tables. However, I consistently
refine and enhance the code, incorporating my personal coding style and
expertise (for example I figured it out how to change the function to
download financial statements after 2006).
Klaus:
Worked on L9-L12. As someone with limited prior experience in coding
and financial analysis, I relied on AI tools like ChatGPT to a greater
extent than others in the group to complete my portion of this project.
The AI provided guidance on coding practices, debugging errors, and
structuring R scripts for tasks like portfolio optimization, WACC
calculations, and derivatives analysis. I used AI primarily as a
learning tool to understand the concepts and translate theoretical
knowledge into practical implementation. While I actively engaged with
the material, wrote code, and refined outputs, the AI served as an
assistant to bridge the gap in my technical skills and ensure I could
contribute effectively to the project. This experience has helped me
develop a foundational understanding of coding and financial analysis,
which I aim to build upon in future projects.
L1 Basic parameters of the markets
First we will install and then called the library ‘quantmod’ to
download the assets prices.
# Quantmod
library(quantmod)
library(lubridate)
We will define the beginning of term period (BoT) as of March 1st and
the end (EoT) as November 20th.
#Define time period
BoT <- as.Date("2024-03-01")
EoT <- as.Date("2024-11-22")
cat("Beginning of the period:", format(BoT), "\n")
Beginning of the period: 2024-03-01
cat("Ending of the period:", format(EoT))
Ending of the period: 2024-11-22
- Basic parameters of the market
basic_param <- data.frame(
Description = character(),
Beginning_of_Term = character(),
End_of_Term = character()
)
add_row <- function(category, symbol) {
data <- getSymbols(symbol, from=BoT, to=EoT+2, auto.assign = FALSE)
data <- data[!is.na(data[, 1]), ]
basic_param <<- rbind(basic_param, data.frame(
Description = category,
BoT = as.numeric(Cl(data)[which(index(data) == BoT)]),
EoT = as.numeric(Cl(data)[which(index(data) == EoT)])
))
}
add_row("S&P 500 (stock) index level","^GSPC" )
add_row("Nasdaq Composite (stock) index level","^IXIC" )
add_row <- function(category, symbol) {
data <- getSymbols(symbol, from=BoT, to=EoT+2,src="FRED", auto.assign = FALSE)
data <- data[!is.na(data[, 1]), ]
basic_param <<- rbind(basic_param, data.frame(
Description = category,
BoT = as.numeric(data[which.min(abs(index(data) - BoT)), 1]),
EoT = as.numeric(data[which.min(abs(index(data) - EoT)), 1])
))
}
add_row("Prime rate","IR14220" )
add_row("Federal funds rate","FEDFUNDS" )
add_row("Commercial paper rate (90 days)","RIFSPPFAAD90NB" )
add_row("Certificate of deposit rate (3-month)","TY3MCD" )
add_row("Treasury bill rate (3-month)","DTB3" )
add_row("Treasury bill rate (6-month)","DTB6" )
add_row("Treasury long-term bond yield","DLTIIT" )
add_row("Corporate (Master) bond yield","DAAA" )
add_row("High-yield corporate bond yield","BAMLH0A0HYM2EY" )
add_row("Tax-exempt (7–12-year) bond yield","IRLTLT01USM156N" )
print(basic_param)
(Explain the assumptions)
- Use stock exchange quotations to record the stock price and
dividend of one stock from each stock exchange in which you would like
to invest.
We will select to stocks in different stock markets to record the
stock price and dividend
PKO Bank Polski (PKO) in the Warsaw Stock Exchange
(WSE).
Tesla (TSLA) in the New York Stock Exchange (NYSC)
We will now get the prices during the analysis period from Yahoo
Finance.
#Historical data prices from the target time range
getSymbols("PKO.WA",from=BoT, to=EoT+2)
[1] "PKO.WA"
getSymbols("TSM",from=BoT, to=EoT+2)
[1] "TSM"
#Extract the close prices of the target dates
pko_b_price <- Cl(PKO.WA[BoT])
pko_e_price <- Cl(PKO.WA[EoT])
tsm_b_price <- Cl(TSM[BoT])
tsm_e_price <- Cl(TSM[EoT])
To visualize the data:
View(PKO.WA)
View(TSM)
chartSeries(Cl(PKO.WA),theme="white")

chartSeries(Cl(TSM),theme="white")

Then, we will get the information about the dividends on each
stock.
#Historical data of dividends
pko_div <- getDividends("PKO.WA")
tsm_div <- getDividends("TSM")
#Extract the ones that are closes but before the target date
pko_b_div <- pko_div[which.min(abs(index(pko_div) - BoT))]
pko_e_div <- pko_div[which.min(abs(index(pko_div) - EoT))]
tsm_b_div <- tsm_div[which.min(abs(index(tsm_div) - BoT))]
tsm_e_div <- tsm_div[which.min(abs(index(tsm_div) - EoT))]
We see that neither of each stock distribute dividends during the
this specific time range.
# Create the data frame
stock_table <- data.frame(
Description = c(
"WSE: PKO Stock price",
"PKO Dividend",
"NYSE: TSM Stock price",
"TSM Dividend"
),
BoT = NA,
EoT = NA
)
View(stock_table)
#Fill with data
stock_table[1, 2] <- pko_b_price
stock_table[1, 3] <- pko_e_price
stock_table[2, 2] <- pko_b_div
stock_table[2, 3] <- pko_e_div
stock_table[3, 2] <- tsm_b_price
stock_table[3, 3] <- tsm_e_price
stock_table[4, 2] <- tsm_b_div
stock_table[4, 3] <- tsm_e_div
print(stock_table)
NA
- Use futures prices quotations to record the recent (“settle”)
price of the following futures (select futures with first settlement
date beyond the end of the school term).
First we will look for the tickers of each future in yahoo
finance.
#Historical data of the futures
sp500_f <- getSymbols("ES=F", from= BoT, to=EoT+2, auto.assign = F)
nasdaq_f <- getSymbols("NQ=F", from= BoT, to=EoT+2, auto.assign = F)
treasury_f <- getSymbols("ZB=F", from= BoT, to=EoT+2, auto.assign = F)
british_f <- getSymbols("6B=F", from= BoT, to=EoT+2, auto.assign = F)
Now we create the table and then we fill it.
# Create the data frame
futures_table <- data.frame(
Description = c(
"Treasury bond futures",
"S&P500 index futures",
"NASDAQ index futures",
"British pounds futures"
),
BoT = NA,
EoT = NA
)
#Fill with data
symbols <- list(treasury_f, sp500_f, nasdaq_f, british_f)
rows <- 1:4 # Row indices in futures_table corresponding to the symbols
# Loop through each symbol and row
for (i in seq_along(symbols)) {
# Extract the symbol and its corresponding row
symbol <- symbols[[i]]
row <- rows[i]
# Assign closing prices for BoT and EoT
futures_table[row, 2] <- Cl(symbol[BoT])
futures_table[row, 3] <- Cl(symbol[EoT])
}
print(futures_table)
- Use an options quotations table to select a call option on a
firm whose stock price you expect to increase (select the option with
the first expiration month beyond the end of the school term).
cat("Name of the firm: ", "Tesla", "\n")
Name of the firm: Tesla
cat("Expiration month:", "2024-11-29", "\n")
Expiration month: 2024-11-29
cat("Strike price:", 335 , "\n")
Strike price: 335
call_tab <- data.frame(
Description = character(),
Beginning_of_Term = character(),
End_of_Term = character()
)
add_row <- function(category, symbol) {
data <- getSymbols(symbol, from=BoT, to=EoT+2, auto.assign = FALSE)
call_tab <<- rbind(call_tab, data.frame(
Description = category,
BoT = as.numeric(Cl(data)[which.min(abs(index(data) - BoT))]),
EoT = as.numeric(Cl(data)[which.min(abs(index(data) - EoT))])
))
}
add_row("Stock price","TSLA" )
add_row("Option premium","TSLA241206C00335000" )
Warning: TSLA241206C00335000 contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.
print(call_tab)
NA
- Use an options quotations table to select a put option on a firm
where you expect the stock price to decrease (select the option with the
first expiration month beyond the end of the school term)
cat("Name of the firm: ", "NVIDIA", "\n")
Name of the firm: NVIDIA
cat("Expiration month:", "2024-11-29", "\n")
Expiration month: 2024-11-29
cat("Strike price:", 130 , "\n")
Strike price: 130
put_tab <- data.frame(
Description = character(),
Beginning_of_Term = character(),
End_of_Term = character()
)
add_row <- function(category, symbol) {
data <- getSymbols(symbol, from=BoT, to=EoT+2, auto.assign = FALSE)
put_tab <<- rbind(put_tab, data.frame(
Description = category,
BoT = as.numeric(Cl(data)[which.min(abs(index(data) - BoT))]),
EoT = as.numeric(Cl(data)[which.min(abs(index(data) - EoT))])
))
}
add_row("Stock price","NVDA" )
add_row("Option premium","NVDA241129P00130000" )
Warning: NVDA241129P00130000 contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.
print(put_tab)
- Use a currency exchange rate table to record exchange
rates.
currency_tab <- data.frame(
Description = character(),
Beginning_of_Term = character(),
End_of_Term = character()
)
add_row <- function(category, symbol) {
data <- getSymbols(symbol, from=BoT, to=EoT+2, auto.assign = FALSE)
currency_tab <<- rbind(currency_tab, data.frame(
Description = category,
BoT = as.numeric(Cl(data)[which.min(abs(index(data) - BoT))]),
EoT = as.numeric(Cl(data)[which.min(abs(index(data) - EoT))])
))
}
add_row("Exchange rate of the British pound (in $)","GBPUSD=X" )
add_row("Exchange rate of the Japanese yen (in $)","JPY=X" )
add_row("Exchange rate of the Mexican peso (in $)","MXN=X" )
print(currency_tab)
NA
- Use currency options data (if available) to select a call option
on a foreign currency that you expect will strengthen against the dollar
(select the option with the first expiration month beyond the end of the
school term).
- Use currency options data (if available) to select a put option
on a foreign currency that you expect will weaken against the dollar
(select the option with the first expiration month beyond the end of the
school term).
I didn’t find information about call or put options, just forward
exchange rates.
cat("Currency: ", "Japanese Yen", "\n")
Currency: Japanese Yen
cat("Expiration month:", "2024-12-04", "\n")
Expiration month: 2024-12-04
cat("Strike price:", 151.62 , "\n")
Strike price: 151.62
currency_tab <- data.frame(
Description = character(),
Beginning_of_Term = character(),
End_of_Term = character()
)
add_row <- function(category, symbol) {
data <- getSymbols(symbol, from=BoT, to=EoT+2, auto.assign = FALSE)
currency_tab <<- rbind(currency_tab, data.frame(
Description = category,
BoT = as.numeric(Cl(data)[which.min(abs(index(data) - BoT))]),
EoT = as.numeric(Cl(data)[which.min(abs(index(data) - EoT))])
))
}
add_row("Currency’s existing value","JPYUSD=X" )
print(currency_tab)
NA
NA
L2 Financial markets micro structure
- Download basic statistic of NASDAQ and London Stock Exchange and
compare them
getSymbols("NDAQ", from= BoT, to=EoT)
[1] "NDAQ"
getSymbols("^FTSE", from= BoT, to=EoT)
[1] "FTSE"
#add a graph adjusted
FTSE<- na.approx(FTSE)
#Correlation
corr <- merge(NDAQ, FTSE)
corr <- na.omit(corr)
correlation <- cor(corr[, 4], corr[, 10])
nasdaq_s <- c(
Mean = mean(NDAQ$NDAQ.Close, na.rm=TRUE),
Median = median(NDAQ$NDAQ.Close, na.rm=TRUE),
StDev = sd(NDAQ$NDAQ.Close, na.rm= TRUE)
)
lse_s <- c(
Mean = mean(FTSE$FTSE.Close),
Median = median(FTSE$FTSE.Close),
StDev = sd(FTSE$FTSE.Close)
)
comparison <- rbind(nasdaq_s, lse_s)
colnames(comparison) <- c("Mean", "Median", "Standard Deviation" )
round(correlation, 3)
FTSE.Close
NDAQ.Close 0.341
round(comparison,2)
Mean Median Standard Deviation
nasdaq_s 66.24 63.01 6.61
lse_s 8160.55 8204.90 184.89
The correlation between the markets is very low: 0.341. We see also,
that the volatility (measured by the standard deviation) of the London
SE is greater that the NASDAQ.
L3 Instrument’s overview and valuation
- Compare the 13-week Treasury bill rate (which is a proxy for
short-term interest rates) at the end of the school term to the rate
that existed at the beginning of the school term. (note: 3-Month
Treasury Bill Secondary Market Rate, Discount Basis (TB3MS)) https://fred.stlouisfed.org/series/TclB3MS
tb3m <- data.frame(
Description = character(),
Beginning_of_Term = character(),
End_of_Term = character(),
Change = character()
)
add_row <- function(category, symbol) {
data <- getSymbols(symbol, from=BoT, to=EoT+2,src="FRED", auto.assign = FALSE)
tb3m <<- rbind(tb3m, data.frame(
Description = category,
BoT = as.numeric(data[which.min(abs(index(data) - BoT)), 1]),
EoT = as.numeric(data[which.min(abs(index(data) - EoT)), 1]),
Change= as.numeric(data[which.min(abs(index(data) - EoT)), 1])-as.numeric(data[which.min(abs(index(data) - BoT)), 1])
))
}
add_row("Treasury bill (3-month)","TB3MS" )
print(tb3m)
NA
NA
We can see that the rate has decreased by 73 basic points.
- Why interest rates change over time.
Interest mainly change due to economic conditions. When the economy
is overheated, the Central Bank will increase the federal funds rates
(FFR) to slowdown the economy. This will impact on all the yield curve,
specially on the short term rates. Thus, since the FED decided to cut
the FFR and the investors are expecting future cuts in the following
meetings, we have seen that the yield of the TB3M has decreased.
L5 Financial statements and fundamental analysis
- Download to R the financial statements of Microsoft 2018, show
the cod
We download the Balance Sheet, Cash Flow and Income of Microsoft for
2018.
library(finreportr) # for financials
library(edgar) # for full text retrial and text mining
library(XBRL) # for instants (full set manipulation)
library(dplyr)
library(tidyr)
options(HTTPUserAgent = "camiladelacruzh@gmail.com")
AnnualReports(0000789019, foreign = FALSE)
trace('XBRL', edit=TRUE)
#There's is a problem with the GetBalanceSheet function. To fix that problem we run the following code to edit the function temporarily: trace('XBRL', edit=TRUE). We will replace "if (substr(file.name, 1, 5) != "http:") {" for "if (!(substr(file.name, 1, 5) %in% c("http:", "https"))) {". Now we can run the code to search files beyond 2016.
msft_bs <-GetBalanceSheet('MSFT', 2018)
msft_cf <-GetCashFlow('MSFT', 2018)
msft_in <- GetIncome('MSFT', 2018)
head(msft_cf)
head(msft_in)
head(msft_bs)
NA
NA
head(msft_cf)
Commercial bank operations
For the commercial bank that you selected at the beginning of the
term, use its annual report or any other related information to answer
the following questions:
AnnualReports("BAC", foreign = FALSE)
bac_bs <-GetBalanceSheet('BAC', 2018)
bac_cf <-GetCashFlow('BAC', 2018)
bac_in <- GetIncome('BAC', 2018)
- Identify the types of deposits that the commercial bank uses to
obtain most of its funds.
Primarily uses demand deposits (such as checking accounts)
and savings accounts.
- Identify the main uses of funds by the bank. Summarize any
statements made by the commercial bank in its annual report about how
recent or potential regulations will affect its performance.
The main uses of funds are loans to customers, investments in
securities and cash reserves.
The bank highlights uncertainties regarding the content, timing, and
impact of regulatory capital and liquidity requirements, such as those
under the Volcker Rule, recovery planning requirements, and the Federal
Reserve’s actions on capital plans.
- Does it appear that the bank is attempting to enter the
securities industry by offering securities services? If so, explain
how.
The report indicates that the bank offers a range of investment
banking services, including underwriting for equity and debt securities,
advisory services and brokerage services. Additionally, Bank of America
has integrated its wealth management services with investment solutions,
allowing clients access to a broader array of financial products,
including mutual funds and ETFs. This strategic move indicates a clear
intent to expanding its presence in the securities industry.
- Does it appear that the bank is attempting to enter the
insurance industry by offering insurance services? If so, explain
how.
The bank is by offering various insurance-related products and
services. The report highlights the provision of life insurance,
property and casualty insurance, and health insurance products through
partnerships s and the integration of insurance services within their
broader financial offerings. Thus, it seems that is also attempting to
enter this industry.
Commercial bank management
- Assess the bank’s balance sheet as well as any comments in its
annual report about the gap between its rate-sensitive assets and its
rate-sensitive liabilities. Does it appear that the bank has a positive
gap or a negative gap?
During 2023, BA experienced an overall decrease in the asset
sensitivity of its balance sheet concerning higher and lower interest
rate scenarios. This change was primarily attributed to shifts in the
deposit product mix and activity within the Asset-Liability Management
(ALM) portfolio.The bank continues to be asset sensitive to a parallel
upward move in interest rates, with the majority of this impact stemming
from the short end of the yield curve. This indicates that the bank has
a positive gap, meaning that its rate-sensitive assets are expected to
respond more favorably to rising interest rates compared to its
rate-sensitive liabilities (primarily deposits).
For the next questions we will use the financial data that is
available on the following link: https://www.sec.gov/ix?doc=/Archives/edgar/data/70858/000007085824000122/bac-20231231.htm
# Financial data (millions of $)
total_assets <- 3180151
interest_income <- 130262
interest_expense <- 73331
noninterest_income <- 41650
noninterest_expense <- 65845
earning_assets <- 2753600
net_income <- 26515
shareholders_equity <- 291646
loan_loss_reserves <- 13342
- Determine the bank’s interest income as a percentage of its
total assets.
interest_income_percentage <- (interest_income / total_assets) * 100
round(interest_income_percentage,2)
[1] 4.1
- Determine the bank’s interest expenses as a percentage of its
total assets.
interest_expense_percentage <- (interest_expense / total_assets) * 100
round(interest_expense_percentage,2)
[1] 2.31
- Determine the bank’s net interest margin.
net_interest_income <- interest_income - interest_expense
nim <- (net_interest_income / earning_assets) * 100
print(nim, 2)
[1] 2.1
- Determine the bank’s noninterest income as a percentage of its
total assets.
noninterest_income_percentage <- (noninterest_income / total_assets) * 100
print(noninterest_income_percentage, 2)
[1] 1.3
- Determine the bank’s noninterest expenses (do not include the
addition to loan loss reserves here) as a percentage of its total
assets.
noninterest_expense_percentage <- (noninterest_expense / total_assets) * 100
print(noninterest_expense_percentage, 2)
[1] 2.1
- Determine the bank’s addition to loan loss reserves as a
percentage of its total assets.
loan_loss_reserves_percentage <- (loan_loss_reserves / total_assets) * 100
print(loan_loss_reserves_percentage, 2)
[1] 0.42
- Determine the bank’s return on assets
roa <- (net_income / total_assets) * 100
print(roa, 2)
[1] 0.83
- Determine the bank’s return on equity.
roe <- (net_income / shareholders_equity) * 100
- Identify the bank’s income statement items described previously
that would be affected if interest rates rise in the next year, and
explain how they would be affected.
The interest income is expected to increase since interest income
would rise more than interest expenses, net interest income would likely
improve, enhancing profitability.
- Identify the bank’s income statement items described previously
that would be affected if U.S. economic conditions deteriorate, and
explain how they would be affected
Net Interest Income likely to decrease. With declining interest
income and potentially stable or decreasing interest expense, net
interest income would likely suffer.
Net income also likely to decrease. With reduced net interest income
and noninterest income alongside potential increases in loan loss
provisions, overall profitability (net income) is likely to decline
during economic downturns.
Mutual funds
For the mutual fund that you selected at the beginning of the term,
use its prospectus or any other related information to answer the
following questions.
We select the Fidelity 500 Index mutual fund: https://fundresearch.fidelity.com/mutual-funds/summary/315911750
- What is the investment objective of this mutual fund? Do you
consider this mutual fund to have low risk, moderate risk, or high
risk?
Since it invest in equity and more than 30% is on the tech sector, we
consider that is moredate to high risk.
- What was the return on the mutual fund last year? What was the
average annual return over the last three years?
2023: 26.29%
Last three years: 33.87%
- What is a key economic factor that influences the return on this
mutual fund? (That is, are the fund’s returns highly influenced by U.S.
stock market conditions? By U.S. interest rates? By foreign stock market
conditions? By foreign interest rates?)
Is highly influenced by the US stock market conditions since only
invests in US stocks. Also, that’s why is influenced by interest rates
of the US. But as it don’t in other country, the fund is not affected by
foreign conditions.
- Must any fees be paid when buying or selling this mutual
fund?
It’s factsheet said that you may be charged a transactions fee if you
buy or sell trough a non-Fidelity broker.
- What was the expense ratio for this mutual fund over the last
year? Does this ratio seem high to you?
The net expense ratio was 0.015%. Compare to the average mutual fund,
we think that is quite cheap.
Securities firms
For the securities firm that you selected at the beginning of the
term, use its annual report or any other related information to answer
the following questions.
- What are the main types of business conducted by the securities
firm?
Tesla operates primarily in two segments:
Automotive: This includes the design, development, manufacturing,
sales, and leasing of high-performance fully electric vehicles (EVs).
The automotive segment also encompasses the sale of automotive
regulatory credits and a variety of services such as used vehicle sales,
non-warranty after-sales services, body shop services, paid
Supercharging, vehicle insurance revenue, and retail
merchandise.
Energy Generation and Storage: This segment involves the design,
manufacture, installation, sales, and leasing of solar energy generation
systems and energy storage products. Key offerings include the Powerwall
for residential use and the Megapack for commercial and utility-scale
applications. Tesla also sells solar energy systems through various
arrangements, including power purchase agreements.
- Summarize any statements made by the securities firm in its
annual report about how it may be affected by existing or potential
regulations.
In its annual report, Tesla acknowledges that it operates in a highly
regulated environment that can significantly affect its business. The
firm notes that existing regulations regarding vehicle emissions and
safety standards could impose costs or operational restrictions.
Additionally, potential future regulations aimed at electric vehicles or
renewable energy could impact Tesla’s operational flexibility and
profitability. The company emphasizes its commitment to compliance but
recognizes that changes in regulations may pose risks to its growth and
market strategy.
- Describe the recent performance of the securities firm, and
explain why the performance has been favorable or unfavorable.
Tesla’s recent performance has been characterized by strong sales
growth driven by increased demand for electric vehicles and advancements
in production capabilities. The launch of new models, including the
Cybertruck, has also contributed positively to its market presence.
However, challenges such as supply chain disruptions and competition in
the EV market have created some headwinds.The favorable performance is
attributed to:
Increased Production Capacity: Expansion of manufacturing
facilities has allowed Tesla to meet rising demand.
Innovation: Continuous improvements in technology and product
offerings have strengthened customer interest.
Market Positioning: Tesla’s established brand reputation as a
leader in the EV space enhances its competitive edge.
Conversely, unfavorable factors include:
Regulatory Challenges: Potential changes in regulations could
impact operational costs.
Competitive Landscape: Growing competition from other automakers
entering the EV market may affect Tesla’s market share.
L6 Equity
We will explore the Gordon Growth Model
# Function to calculate stock value using Gordon Growth Model
gordon_growth_model <- function(dividend, cost_of_equity, growth_rate) {
value <- dividend / (cost_of_equity - growth_rate)
return(value)
}
companies <- data.frame(
name = c("Tesla", "Apple", "Microsoft", "Toyota", "Samsung", "Volkswagen"),
country = c("USA", "USA", "USA", "Japan", "South Korea", "Germany"),
dividend = c(0, 0.92, 2.72, 2.30, 1.97, 7.56),
cost_of_equity = c(0.08, 0.07, 0.065, 0.06, 0.07, 0.075),
growth_rate = c(0.20, 0.10, 0.08, 0.03, 0.05, 0.02)
)
companies$stock_value <- mapply(gordon_growth_model,
companies$dividend,
companies$cost_of_equity,
companies$growth_rate)
print(companies)
# Compare U.S. companies with non-U.S. companies
us_companies <- subset(companies, country == "USA")
non_us_companies <- subset(companies, country != "USA")
cat("\nAverage stock value for U.S. companies:", mean(us_companies$stock_value))
Average stock value for U.S. companies: -70.66667
cat("\nAverage stock value for non-U.S. companies:", mean(non_us_companies$stock_value))
Average stock value for non-U.S. companies: 104.2071
# Create a bar plot to visualize the comparison
barplot(companies$stock_value,
names.arg = companies$name,
col = ifelse(companies$country == "USA", "blue", "red"),
main = "Stock Values Comparison",
ylab = "Stock Value",
las = 2)
legend("topright", legend = c("USA", "Non-USA"), fill = c("blue", "red"))

The average stock value for U.S. companies (excluding Tesla) is
likely to be lower than non-U.S. companies in this sample, primarily due
to lower dividend payments and higher growth rates.
Some imporant notes:The Gordon
Growth Model assumes a constant growth rate, which may not be realistic
for many companies, especially in the tech sectos. Also, companies like
Tesla, which don’t pay dividends, cannot be valued using this model,
highlighting its limitations for growth stocks
L7 Fixed income
Comparing yields among securities
- What is the difference between the yield on corporate
high-quality bonds and the yield on Treasury bonds at the end of the
school term? Explain why does the difference exist?
We look for the the data “Moody’s Seasoned Aaa Corporate Bond Yield
Relative to Yield on 10-Year Treasury Constant Maturity” on the FRED
website.
diff1 <- basic_param$EoT[basic_param$Description == "Corporate (Master) bond yield"] - basic_param$EoT[basic_param$Description == "Treasury long-term bond yield"]
cat("The difference is", diff1*100, "basic points.")
The difference is 294 basic points.
The big difference between yield on corporate high-quality bonds and
the yield on Treasury bonds is the risk. Treasury bonds are about as
risk-free as they get as they are operated by the government, but
corporate bonds, while also representing a loan, risk is higher because
the issuer can not keep its promise. This is due to the credit spread,
whereby investors are compensated with higher yields to keep them
invested, hence high-quality corporate bonds have to offer a greater
return for the higher risk.
- What is the difference between the yield on long-term Treasury
bonds and the yield on long-term municipal bonds at the end of the
school term? Explain why does the difference exist?
The main difference is that long-term treasury bonds yield more than
the long-term municipal bonds, mainly because of the taxes associated on
the interest on municipal bonds. Accordingly, the difference is due to
the tax aspects and the credit risk. Corporate bonds offers better
yields to offset the risk, but municipal bonds offer better tax
advances.
diff2 <- basic_param$EoT[basic_param$Description == "Tax-exempt (7–12-year) bond yield"] - basic_param$EoT[basic_param$Description == "Treasury long-term bond yield"]
cat("The difference is", diff2*100, "basic points.")
The difference is 182 basic points.
Assessing the forecasting ability of the yield
curve
- What was the difference between the 26-week T-bill yield and the
13-week T-bill yield at the beginning of the school term?
diff3 <- basic_param$BoT[basic_param$Description == "Treasury bill rate (6-month)"] - basic_param$BoT[basic_param$Description == "Treasury bill rate (3-month)"]
cat("The difference is", diff3*100, "basic points.")
The difference is -14 basic points.
- Does this imply that the yield curve had an upward or downward
slope at that time?
Since the 26-week T-bill yield is lower than the 13-week T-bill
yield, this implies a downward slope, that is an inverted yield
curve.
- Assuming that this slope can be primarily attributed to
expectations theory, did the direction of the slope indicate that the
market expected higher or lower interest rates in the future?
This indicates that the investors expects lower interest rates in the
future.
- Did interest rates move in that direction over the school
term?
tb3 <- getSymbols("DTB3", from=BoT, to=EoT+2,src="FRED", auto.assign = FALSE)
chartSeries(tb3,theme="white")

We see that them 13-bill rate went down in the during the period of
analysis. So, yes the rates move in the direction that was expected.
Explaining shifts in the yield curve over time
- What was the difference between the long-term Treasury bond
yield and the 13-week T-bill yield at the beginning of the school
term?
diff4 <- basic_param$BoT[basic_param$Description == "Treasury long-term bond yield"] - basic_param$BoT[basic_param$Description == "Treasury bill rate (3-month)"]
cat("The difference is", diff4*100, "basic points.")
The difference is -316 basic points.
At the beginning of the school year, the yield on the long-term
Treasury bond was lower than that of the 13-week T-bill.
- What is the difference between the long-term Treasury bond yield
and the 13-week T-bill yield at the end of the school term?
diff5 <- basic_param$EoT[basic_param$Description == "Treasury long-term bond yield"] - basic_param$EoT[basic_param$Description == "Treasury bill rate (3-month)"]
cat("The difference is", diff5*100, "basic points.")
The difference is -215 basic points.
By the end of the school term, this differential has shrink.
- Given your answers to the two previous questions, describe how
the yield curve changed over the school term. Explain the changes in
expectations about future interest rates that are implied by the shift
in the yield curve over the school term.
The yield curve at the EoT was less inverted than the beginning.
While the curve remains inverted, market expectations for interest rate
cuts have softened, indicating a less aggressive outlook for monetary
easing than at the start of the term.
- Did the Fed change the federal funds rate over the school
term?
ffr <- getSymbols("FEDFUNDS", from=BoT, to=EoT+2,src="FRED", auto.assign = FALSE)
chartSeries(ffr,theme="white")

NA
NA
tail(ffr)
FEDFUNDS
2024-05-01 5.33
2024-06-01 5.33
2024-07-01 5.33
2024-08-01 5.33
2024-09-01 5.13
2024-10-01 4.83
There were two cuts during the period. One was a cut of 50 basis
points in the September meeting, and the other one of 25 points in the
November meeting.
- Do you think the movements in interest rates over the school
term were caused by the Fed’s monetary policy? Explain.
Yes. Specially the investors pays attention to Powell’s speech after
the meeting. But, also they takes into account the data on the well
known leading economic indicators. That’s why they think that the FED
can still lower more interest rates.
Measuring and explaining premiums on money market
securities
- What is the difference between the yield on 90-day commercial
paper and the yield on 13-week T-bills at the end of the school term?
Explain why this premium exists.
diff6 <- basic_param$BoT[basic_param$Description == "Commercial paper rate (90 days)"] - basic_param$BoT[basic_param$Description == "Treasury bill rate (3-month)"]
cat("The difference is", diff6*100, "basic points.")
The difference is 1 basic points.
Is greater because there exist a higher credit and default risk, it
is widely believed that the United States government will always meet
its financial obligations and is unlikely to default.
- Compare the premium on the 90-day commercial paper yield
(relative to the 13-week T-bill yield) that exists at the end of the
school term to the premium that existed at the beginning of the term.
Explain why the premium may have changed over the school term.
diff7 <- basic_param$EoT[basic_param$Description == "Commercial paper rate (90 days)"] - basic_param$EoT[basic_param$Description == "Treasury bill rate (3-month)"]
cat("The difference is", diff7*100, "basic points.")
The difference is 13 basic points.
The greater difference may indicate that investors anticipate a
deterioration in the overall health of businesses. They think that the
risk of having a commercial paper is greater (due to higher credit
risk), thus a wider yield spread.
Explaining bond premiums and price movements
- What is the difference between the yield on high-yield corporate
bonds at the end of the school term versus the yield on high-quality
corporate bonds at the beginning of the school term?
diff8 <- basic_param$BoT[basic_param$Description == "High-yield corporate bond yield"] - basic_param$BoT[basic_param$Description == "Corporate (Master) bond yield"]
cat("The difference is", diff8*100, "basic points.")
The difference is 262 basic points.
- Compare the long-term Treasury bond yield at the end of the
school term to the long term Treasury bond yield that existed at the
beginning of the school term. Given the direction of this change, did
prices of long-term bonds rise or fall over the school term?
diff9 <- basic_param$EoT[basic_param$Description == "Treasury long-term bond yield"] - basic_param$BoT[basic_param$Description == "Treasury long-term bond yield"]
cat("The difference is", diff9*100, "basic points.")
The difference is 21 basic points.
Since the yield increase, that means that the price fall over the
school term.
- Compare the change in the yields of Treasury, municipal, and
corporate bonds over the school term. Did the yields of all three types
of securities move in the same direction and by about the same degree?
Explain why yields of different types of bonds move together.
diff_yields <- subset(basic_param, Description %in% c("Treasury long-term bond yield", "Corporate (Master) bond yield", "Tax-exempt (7–12-year) bond yield"))
diff_yields$Difference <- diff_yields$EoT - diff_yields$BoT
print(diff_yields)
NA
NA
Usually when the Federal Reserve, change interest rates, it affects
all bonds. If rates go up, new bonds offer higher returns, so existing
bonds with lower yields become less attractive, causing their prices to
fall and their yields to rise. However, despite the fed cuts during the
school term we see that the treasury and corporate bonds went up.
- Compare the premium on high-yield corporate bonds (relative to
Treasury bonds) at the beginning of the school term to the premium that
existed at the end of the school term. Did the premium increase or
decrease? Why this premium changed over the school term.
#
diff9 <- basic_param$BoT[basic_param$Description == "High-yield corporate bond yield"] - basic_param$BoT[basic_param$Description == "Treasury long-term bond yield"]
cat("The difference is", diff9*100, "basic points.")
The difference is 556 basic points.
diff10 <- basic_param$EoT[basic_param$Description == "High-yield corporate bond yield"] - basic_param$EoT[basic_param$Description == "Treasury long-term bond yield"]
cat("The difference is", diff10*100, "basic points.")
The difference is 469 basic points.
diff11 <- diff10-diff9
print(diff11)
[1] -0.87
The premium decrease. Investors may perceive that the high yield
bonds are less risky that at the beginning. Maybe at the start of the
period they were discounting too much risk on these bonds.
L8 Portfolio - Markovitz
- Replicate the basic idea of the portfolio case
library(PerformanceAnalytics)
getSymbols(c("NVDA", "TSLA"), from = BoT, to = EoT)
[1] "NVDA" "TSLA"
returns <- na.omit(ROC(merge(NVDA[,6], TSLA[,6])))
# Expected returns and covariance matrix
mu <- colMeans(returns)
cov_mat <- cov(returns)
# Portfolio weights
weights <- c(0.5, 0.5) # Equal weights for AAPL and MSFT
# Portfolio expected return and variance
portfolio_return <- sum(weights * mu)
portfolio_variance <- t(weights) %*% cov_mat %*% weights
print(paste("Portfolio expected return:", round(portfolio_return * 252, 2), "%"))
[1] "Portfolio expected return: 0.75 %"
print(paste("Portfolio annualized volatility:", round(sqrt(portfolio_variance * 252) * 100, 2), "%"))
[1] "Portfolio annualized volatility: 47.69 %"
L9 Portfolio - CAMP
- State the difference between CAMP and Markowitz
Markowitz helps with portfolio construction by focusing on
diversification to optimize risk and return. He is not interested in
determining the return of a specific asset; instead, he aims to identify
the optimal portfolio based on historical correlations between assets,
seeking the best risk-return trade-off. On the other hand, CAPM helps
with estimating the expected return of an individual asset based on its
risk relative to the market. It focuses to estimate the sensitiveness of
an asset to market movements (systematic risk) and use that to state
what should be the return of the asset in the long run.
This section calculates the Beta and Expected Return for Apple (AAPL)
using the CAPM formula.
library(quantmod)
library(PerformanceAnalytics)
start_date <- BoT
end_date <- EoT
stock_symbol <- "AAPL"
market_symbol <- "^GSPC"
getSymbols(c(stock_symbol, market_symbol), from = start_date, to = end_date, src = "yahoo")
[1] "AAPL" "GSPC"
stock_prices <- Cl(AAPL)
market_prices <- Cl(GSPC)
stock_returns <- dailyReturn (stock_prices)
market_returns <- dailyReturn(market_prices)
risk_free_rate <- 0.03 / 252
beta <- cov(stock_returns , market_returns) / var(market_returns)
market_premium <- mean(market_returns) - risk_free_rate
expected_return <- risk_free_rate + beta * market_premium
cat("Beta:", round(beta, 4), "\n")
Beta: 0.995
cat("Expected Return (CAPM):", round(expected_return * 100, 2), "%\n")
Expected Return (CAPM): 0.08 %
L10 WACC
- Replicate the book case of WACC
We will use the basic formula of the WACC
\[
WACC= \frac{E}{E+D}r_e+\frac{D}{E+D}r_d(1-t)
\]
Where:
\(E\): market value of equity
\(D\): market value of debt
\(r_e\): cost of equity
\(r_d\): cost of debt
\(t\): tax rate
In this case, we will calculate the WACC for Tesla.
getSymbols("TSLA")
[1] "TSLA"
oustanding_shares<- 3.19e9
market_cap <- TSLA$TSLA.Adjusted[EoT] * oustanding_shares
market_value_of_debt <- 12.78e9 # According to Yahoo Finance
tax_rate <- 0.22
beta <- 1.6 # Unleveraged beta according to Reuters (2024)
risk_free_rate <- 0.0475 # fed funds rate
market_risk_premium <- 0.04 # market risk premium according to Damodaran (2024)
#Data for calculation
cost_of_debt <- 0.0425
cost_of_equity <- risk_free_rate + beta * market_risk_premium
total_market_value <- market_cap + market_value_of_debt
weight_of_debt <- market_value_of_debt / total_market_value
weight_of_equity <- market_cap / total_market_value
cat("cost of debt:",cost_of_debt, "\n")
cost of debt: 0.0425
cat("cost of equity",cost_of_equity, "\n")
cost of equity 0.1115
cat("weight of debt:",weight_of_debt, "\n")
weight of debt: 0.01123569
cat("weight of equity:",weight_of_equity)
weight of equity: 0.9887643
wacc <- (weight_of_debt * cost_of_debt * (1 - tax_rate)) + (weight_of_equity * cost_of_equity)
cat("WACC for Tesla:", wacc * 100, "%")
WACC for Tesla: 11.06197 %
L11 Derivatives
- Assume that you purchased an S&P 500 futures contract at the
beginning of the school term, with the first settlement date beyond the
end of the school term. Also assume that you sold an S&P 500 futures
contract with this same settlement date at the end of the school term.
Given that this contract has a value of the futures price times $250,
determine the difference between the dollar value of the contract you
sold and the dollar amount of the contract that you purchased.
buy_price <- 4000
sell_price <- 4200
contract_multiplier <- 250
inital_margin <- 0.20 * (buy_price * contract_multiplier)
months_in_term <- 5
gain_loss <- (sell_price - buy_price) * contract_multiplier
print(gain_loss)
[1] 50000
- Assume that you invested an initial margin of 20 percent of the
amount that you would owe to purchase the S&P 500 index at the
settlement date. Measure your return from taking a position in the
S&P 500 index futures as follows. Take the difference determined in
the previous question (which represents the dollar amount of the gain on
the futures position) and divide it by the amount you originally
invested (the amount you originally invested is 20 percent of the dollar
value of the futures contract that you purchased).
return <- gain_loss / inital_margin
print(return)
[1] 0.25
- The return that you just derived in the previous question is not
annualized. To annualize your return, multiply it by 12/m, where m is
the number of months in your school term.
We calculate the gain/ loss, return, and annualized return for
S&P 500 futures contract.
annualized_return <- return * (12 / months_in_term)
cat("Gain/Loss on Futures Contract : $", gain_loss, "\n")
Gain/Loss on Futures Contract : $ 50000
cat("Return: ", round(return * 100, 2), "%\n")
Return: 25 %
cat("Annualized Return: ", round(annualized_return * 100, 2), "%\n")
Annualized Return: 60 %
Assume that you purchased a call option (representing 100
shares) on the specific stock that you identified of this project. What
was your return from purchasing this option? If the premium for this
option is not quoted at the end of the school term, measure the return
as if you had exercised the call option at the end of the school term
(assuming that it is feasible to exercise the option at that time). That
is, the return is based on purchasing the stock at the option’s strike
price and then selling the stock at its market price at the end of the
school term.
Annualize the return on your option by multiplying the return
you derived in the previous question by 12/m, where m represents the
number of months in your school term
Compare the return on your call option to the return that you
would have earned if you had simply invested in the stock itself. Notice
how the magnitude of the return on the call option is much larger than
the magnitude of the return on the stock itself. That is, the gains are
larger and the losses are larger when investing in call options on a
stock instead of the stock itself.
We calculate the return on a call option and analyze the results.
buy_premium <- 20
sell_premium <- 30
strike_price <- 400
stock_price_end <- 450
months_in_term <- 5
call_return <- (sell_premium - buy_premium) / buy_premium
exercise_return <- (stock_price_end - strike_price) / buy_premium
annualized_call_return <- call_return * (12 / months_in_term)
cat("Call Option Return: ", round(call_return * 100, 2), "%\n")
Call Option Return: 50 %
cat("Exercise Return: ", round(annualized_call_return * 100, 2), "%\n")
Exercise Return: 120 %
cat("Annualized Call Return: ", round(annualized_call_return * 100, 2), "%\n")
Annualized Call Return: 120 %
Determining swap payments
- Assume that, at the beginning of the school term, you engaged in
a fixed-for-floating rate swap in which you agreed to pay 6 percent in
exchange for the prevailing 26-week T-bill rate that exists at the end
of the school term. Assume that your swap agreement specifies the end of
the school term as the only time at which a swap will occur and that the
notional amount is $10 million. Determine the amount that you owe on the
swap, the amount you are owed on the swap, and the difference. Did you
gain or lose as a result of the swap?
We calculate the fixed and floating payments for a swap
agreement.
notional_amount <- 10e6
fixed_rate <- 0.06
floating_rate_end <- 0.055
fixed_payment <- notional_amount * fixed_rate
floating_payment <- notional_amount * floating_rate_end
net_payment <- fixed_payment - floating_payment
cat("Fixed Payment: $", fixed_payment, "\n")
Fixed Payment: $ 6e+05
cat("Floating Payment: $", floating_payment, "\n")
Floating Payment: $ 550000
cat("Net Payment: $", net_payment, "\n")
Net Payment: $ 50000
Measuring and explaining exchange rate movements
Determine the percentage change in the value of the British
pound over the school term. Did the pound appreciate or depreciate
against the dollar?
Determine the percentage change in the value of the Japanese
yen over the school term. Did the yen appreciate or depreciate against
the dollar?
Determine the percentage change in the value of the Mexican
peso over the school term. Did the peso appreciate or depreciate against
the dollar?
Determine the per unit gain or loss if you had purchased
British pound futures at the beginning of the term and sold British
pound futures at the end of the term.
Given that a single futures contract on British pounds
represents 62,500 pounds, determine the dollar amount of your gain or
loss.
We calculate the percentage change and gain/ loss for GBP/ USD
futures.
start_rate_gpd <- 1.2
end_rate_gpd <- 1.25
contract_size_gbp <- 62500
percent_change_gpd <- ((end_rate_gpd - start_rate_gpd) / start_rate_gpd) * 100
gain_loss_per_unit_gpd <- end_rate_gpd - start_rate_gpd
total_gain_loss_gpd <- gain_loss_per_unit_gpd * contract_size_gbp
cat("GBP Percantage Change: ", round(percent_change_gpd,2), "%\n")
GBP Percantage Change: 4.17 %
cat("Total Gain/Loss on GBP Futures Contract: $", round(total_gain_loss_gpd,2), "%\n")
Total Gain/Loss on GBP Futures Contract: $ 3125 %
L12 Capital requirements
Operational Risk
We calculate the operational risk capital for Bank of America (BoA)
and Deutsche Bank (DB) using the Basic Indicator Approach under Basel
III:
alpha <- 0.15
gross_income_boa <- 90e9
gross_income_db <- 25e9 * 1.1
operational_risk_boa <- alpha * gross_income_boa
operational_risk_db <- alpha * gross_income_db
cat("Operational Risk Capital (BoA): $", format(operational_risk_boa, big.mark = ","), "\n")
Operational Risk Capital (BoA): $ 1.35e+10
cat("Operational Risk Capital (DB): $", format(operational_risk_db, big.mark = ","), "\n")
Operational Risk Capital (DB): $ 4.125e+09
We calculate the market risk capital using the Value at risk (VaR)
approach:
k <- 3
var_boa <- 5e9
var_db <- 3e9 * 1.1
market_risk_boa <- k * var_boa
market_risk_db <- k * var_db
cat("Market Risk Capital (BoA): $", format(market_risk_boa, big.mark = ","), "\n")
Market Risk Capital (BoA): $ 1.5e+10
cat("Market Risk Capital (DB): $", format(market_risk_db, big.mark = ","), "\n")
Market Risk Capital (DB): $ 9.9e+09
We calculate credit risk capital based on the exposure amounts, risk
weights, and regulatory capital requirements
regulatory_capital_requirement <- 0.08
loan_exposure_boa <- 200e9
gov_securities_boa <- 50e9
loan_exposure_db <- 150e9 * 1.1
gov_securities_db <- 40e9 * 1.1
loan_risk_weight <- 1.00
gov_risk_weight <- 0.00
credit_risk_boa <- regulatory_capital_requirement * (loan_exposure_boa * loan_risk_weight + gov_securities_boa * gov_risk_weight)
credit_risk_db <- regulatory_capital_requirement * (loan_exposure_db * loan_risk_weight + gov_securities_db * gov_risk_weight)
cat("Credit Risk Capital (BoA): $", format(credit_risk_boa, big.mark = ","), "\n")
Credit Risk Capital (BoA): $ 1.6e+10
cat("Credit Risk Capital (DB): $", format(credit_risk_db, big.mark = ","), "\n")
Credit Risk Capital (DB): $ 1.32e+10
We calculate the total capital requirements for each bank by summing
operational, market, and credit risk capitals.
total_capital_boa <- operational_risk_boa + market_risk_boa + credit_risk_boa
total_capital_db <- operational_risk_db + market_risk_db + credit_risk_db
cat("Total Capital Requirement (BoA): $", format(total_capital_boa, big.mark = ","), "\n")
Total Capital Requirement (BoA): $ 4.45e+10
cat("Total Capital Requirement (DB): $", format(total_capital_db, big.mark = ","),"\n")
Total Capital Requirement (DB): $ 2.7225e+10
LS0tCnRpdGxlOiAiRmluYW5jaWFsIE1hcmtldHM6IE9ibGlnYXRvcnkgZXhlcmNpc2UiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBSZXBvcnQKCiMjIFRlYW0KClBhdWxhIE1vbG9uZXksIFNwYWluCgpDYW1pbGEgZGUgbGEgQ3J1eiwgUGVydQoKS2xhdXMgTGluZGVtYW5uLCBQb2xhbmQKCiMjIFN0YXRlbWVudAoKUGF1bGE6CgpXb3JrZWQgb24gTDQsIEw3LUw4CgpDYW1pbGE6CgpXb3JrZWQgb24gTDEtTDEwLiBJIGxldmVyYWdlIEFJLXBvd2VyZWQgdG9vbHMgbGlrZSBDaGF0R1BUIGFzIGEgc3RhcnRpbmcgcG9pbnQgZm9yIGNvZGUgc3RydWN0dXJlIGFuZCBkYXRhIG9yZ2FuaXphdGlvbiwgc3VjaCBhcyBjcmVhdGluZyBmdW5jdGlvbnMgdG8gZXh0cmFjdCBkYXRhIGZyb20gdGFibGVzLiBIb3dldmVyLCBJIGNvbnNpc3RlbnRseSByZWZpbmUgYW5kIGVuaGFuY2UgdGhlIGNvZGUsIGluY29ycG9yYXRpbmcgbXkgcGVyc29uYWwgY29kaW5nIHN0eWxlIGFuZCBleHBlcnRpc2UgKGZvciBleGFtcGxlIEkgZmlndXJlZCBpdCBvdXQgaG93IHRvIGNoYW5nZSB0aGUgZnVuY3Rpb24gdG8gZG93bmxvYWQgZmluYW5jaWFsIHN0YXRlbWVudHMgYWZ0ZXIgMjAwNikuCgpLbGF1czoKCldvcmtlZCBvbiBMOS1MMTIuIEFzIHNvbWVvbmUgd2l0aCBsaW1pdGVkIHByaW9yIGV4cGVyaWVuY2UgaW4gY29kaW5nIGFuZCBmaW5hbmNpYWwgYW5hbHlzaXMsIEkgcmVsaWVkIG9uIEFJIHRvb2xzIGxpa2UgQ2hhdEdQVCB0byBhIGdyZWF0ZXIgZXh0ZW50IHRoYW4gb3RoZXJzIGluIHRoZSBncm91cCB0byBjb21wbGV0ZSBteSBwb3J0aW9uIG9mIHRoaXMgcHJvamVjdC4gVGhlIEFJIHByb3ZpZGVkIGd1aWRhbmNlIG9uIGNvZGluZyBwcmFjdGljZXMsIGRlYnVnZ2luZyBlcnJvcnMsIGFuZCBzdHJ1Y3R1cmluZyBSIHNjcmlwdHMgZm9yIHRhc2tzIGxpa2UgcG9ydGZvbGlvIG9wdGltaXphdGlvbiwgV0FDQyBjYWxjdWxhdGlvbnMsIGFuZCBkZXJpdmF0aXZlcyBhbmFseXNpcy4gSSB1c2VkIEFJIHByaW1hcmlseSBhcyBhIGxlYXJuaW5nIHRvb2wgdG8gdW5kZXJzdGFuZCB0aGUgY29uY2VwdHMgYW5kIHRyYW5zbGF0ZSB0aGVvcmV0aWNhbCBrbm93bGVkZ2UgaW50byBwcmFjdGljYWwgaW1wbGVtZW50YXRpb24uIFdoaWxlIEkgYWN0aXZlbHkgZW5nYWdlZCB3aXRoIHRoZSBtYXRlcmlhbCwgd3JvdGUgY29kZSwgYW5kIHJlZmluZWQgb3V0cHV0cywgdGhlIEFJIHNlcnZlZCBhcyBhbiBhc3Npc3RhbnQgdG8gYnJpZGdlIHRoZSBnYXAgaW4gbXkgdGVjaG5pY2FsIHNraWxscyBhbmQgZW5zdXJlIEkgY291bGQgY29udHJpYnV0ZSBlZmZlY3RpdmVseSB0byB0aGUgcHJvamVjdC4gVGhpcyBleHBlcmllbmNlIGhhcyBoZWxwZWQgbWUgZGV2ZWxvcCBhIGZvdW5kYXRpb25hbCB1bmRlcnN0YW5kaW5nIG9mIGNvZGluZyBhbmQgZmluYW5jaWFsIGFuYWx5c2lzLCB3aGljaCBJIGFpbSB0byBidWlsZCB1cG9uIGluIGZ1dHVyZcKgcHJvamVjdHMuCgojIyBMMSBCYXNpYyBwYXJhbWV0ZXJzIG9mIHRoZSBtYXJrZXRzCgpGaXJzdCB3ZSB3aWxsIGluc3RhbGwgYW5kIHRoZW4gY2FsbGVkIHRoZSBsaWJyYXJ5ICdxdWFudG1vZCcgdG8gZG93bmxvYWQgdGhlIGFzc2V0cyBwcmljZXMuCgpgYGB7cn0KIyBRdWFudG1vZAoKCmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkobHVicmlkYXRlKQoKYGBgCgpXZSB3aWxsIGRlZmluZSB0aGUgYmVnaW5uaW5nIG9mIHRlcm0gcGVyaW9kIChCb1QpIGFzIG9mIE1hcmNoIDFzdCBhbmQgdGhlIGVuZCAoRW9UKSBhcyBOb3ZlbWJlciAyMHRoLgoKYGBge3J9CiNEZWZpbmUgdGltZSBwZXJpb2QKCkJvVCA8LSBhcy5EYXRlKCIyMDI0LTAzLTAxIikgCkVvVCA8LSBhcy5EYXRlKCIyMDI0LTExLTIyIikKCmNhdCgiQmVnaW5uaW5nIG9mIHRoZSBwZXJpb2Q6IiwgZm9ybWF0KEJvVCksICJcbiIpCmNhdCgiRW5kaW5nIG9mIHRoZSBwZXJpb2Q6IiwgZm9ybWF0KEVvVCkpCgpgYGAKCi0gICAqQmFzaWMgcGFyYW1ldGVycyBvZiB0aGUgbWFya2V0KgoKYGBge3J9CmJhc2ljX3BhcmFtIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjaGFyYWN0ZXIoKSwKICBCZWdpbm5pbmdfb2ZfVGVybSA9IGNoYXJhY3RlcigpLAogIEVuZF9vZl9UZXJtID0gY2hhcmFjdGVyKCkKKQoKCmFkZF9yb3cgPC0gZnVuY3Rpb24oY2F0ZWdvcnksIHN5bWJvbCkgewogIGRhdGEgPC0gZ2V0U3ltYm9scyhzeW1ib2wsIGZyb209Qm9ULCB0bz1Fb1QrMiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKICBkYXRhIDwtIGRhdGFbIWlzLm5hKGRhdGFbLCAxXSksIF0KICBiYXNpY19wYXJhbSA8PC0gcmJpbmQoYmFzaWNfcGFyYW0sIGRhdGEuZnJhbWUoCiAgICBEZXNjcmlwdGlvbiA9IGNhdGVnb3J5LAogICAgQm9UID0gYXMubnVtZXJpYyhDbChkYXRhKVt3aGljaChpbmRleChkYXRhKSA9PSBCb1QpXSksCiAgICBFb1QgPSBhcy5udW1lcmljKENsKGRhdGEpW3doaWNoKGluZGV4KGRhdGEpID09IEVvVCldKQogICkpCn0KCgphZGRfcm93KCJTJlAgNTAwIChzdG9jaykgaW5kZXggbGV2ZWwiLCJeR1NQQyIgKQphZGRfcm93KCJOYXNkYXEgQ29tcG9zaXRlIChzdG9jaykgaW5kZXggbGV2ZWwiLCJeSVhJQyIgKQoKYWRkX3JvdyA8LSBmdW5jdGlvbihjYXRlZ29yeSwgc3ltYm9sKSB7CiAgZGF0YSA8LSBnZXRTeW1ib2xzKHN5bWJvbCwgZnJvbT1Cb1QsIHRvPUVvVCsyLHNyYz0iRlJFRCIsIGF1dG8uYXNzaWduID0gRkFMU0UpCiAgZGF0YSA8LSBkYXRhWyFpcy5uYShkYXRhWywgMV0pLCBdCiAgYmFzaWNfcGFyYW0gPDwtIHJiaW5kKGJhc2ljX3BhcmFtLCBkYXRhLmZyYW1lKAogICAgRGVzY3JpcHRpb24gPSBjYXRlZ29yeSwKICAgIEJvVCA9IGFzLm51bWVyaWMoZGF0YVt3aGljaC5taW4oYWJzKGluZGV4KGRhdGEpIC0gQm9UKSksIDFdKSwKICAgIEVvVCA9IGFzLm51bWVyaWMoZGF0YVt3aGljaC5taW4oYWJzKGluZGV4KGRhdGEpIC0gRW9UKSksIDFdKQogICkpCn0KYWRkX3JvdygiUHJpbWUgcmF0ZSIsIklSMTQyMjAiICkKYWRkX3JvdygiRmVkZXJhbCBmdW5kcyByYXRlIiwiRkVERlVORFMiICkKYWRkX3JvdygiQ29tbWVyY2lhbCBwYXBlciByYXRlICg5MCBkYXlzKSIsIlJJRlNQUEZBQUQ5ME5CIiApCmFkZF9yb3coIkNlcnRpZmljYXRlIG9mIGRlcG9zaXQgcmF0ZSAoMy1tb250aCkiLCJUWTNNQ0QiICkKYWRkX3JvdygiVHJlYXN1cnkgYmlsbCByYXRlICgzLW1vbnRoKSIsIkRUQjMiICkKYWRkX3JvdygiVHJlYXN1cnkgYmlsbCByYXRlICg2LW1vbnRoKSIsIkRUQjYiICkKYWRkX3JvdygiVHJlYXN1cnkgbG9uZy10ZXJtIGJvbmQgeWllbGQiLCJETFRJSVQiICkKYWRkX3JvdygiQ29ycG9yYXRlIChNYXN0ZXIpIGJvbmQgeWllbGQiLCJEQUFBIiApCmFkZF9yb3coIkhpZ2gteWllbGQgY29ycG9yYXRlIGJvbmQgeWllbGQiLCJCQU1MSDBBMEhZTTJFWSIgKQphZGRfcm93KCJUYXgtZXhlbXB0ICg34oCTMTIteWVhcikgYm9uZCB5aWVsZCIsIklSTFRMVDAxVVNNMTU2TiIgKQoKCgoKcHJpbnQoYmFzaWNfcGFyYW0pCmBgYAoKKEV4cGxhaW4gdGhlIGFzc3VtcHRpb25zKQoKLSAgICpVc2Ugc3RvY2sgZXhjaGFuZ2UgcXVvdGF0aW9ucyB0byByZWNvcmQgdGhlIHN0b2NrIHByaWNlIGFuZCBkaXZpZGVuZCBvZiBvbmUgc3RvY2sgZnJvbSBlYWNoIHN0b2NrIGV4Y2hhbmdlIGluIHdoaWNoIHlvdSB3b3VsZCBsaWtlIHRvIGludmVzdC4qCgpXZSB3aWxsIHNlbGVjdCB0byBzdG9ja3MgaW4gZGlmZmVyZW50IHN0b2NrIG1hcmtldHMgdG8gcmVjb3JkIHRoZSBzdG9jayBwcmljZSBhbmQgZGl2aWRlbmQKCjEpICBQS08gQmFuayBQb2xza2kgKFBLTykgaW4gdGhlIFdhcnNhdyBTdG9jayBFeGNoYW5nZSAoV1NFKS4KCjIpICBUZXNsYSAoVFNMQSkgaW4gdGhlIE5ldyBZb3JrIFN0b2NrIEV4Y2hhbmdlIChOWVNDKQoKV2Ugd2lsbCBub3cgZ2V0IHRoZSBwcmljZXMgZHVyaW5nIHRoZSBhbmFseXNpcyBwZXJpb2QgZnJvbSBZYWhvbyBGaW5hbmNlLgoKYGBge3J9CiNIaXN0b3JpY2FsIGRhdGEgcHJpY2VzIGZyb20gdGhlIHRhcmdldCB0aW1lIHJhbmdlCgpnZXRTeW1ib2xzKCJQS08uV0EiLGZyb209Qm9ULCB0bz1Fb1QrMikKZ2V0U3ltYm9scygiVFNNIixmcm9tPUJvVCwgdG89RW9UKzIpCgoKI0V4dHJhY3QgdGhlIGNsb3NlIHByaWNlcyBvZiB0aGUgdGFyZ2V0IGRhdGVzCgpwa29fYl9wcmljZSA8LSBDbChQS08uV0FbQm9UXSkKcGtvX2VfcHJpY2UgPC0gQ2woUEtPLldBW0VvVF0pCgp0c21fYl9wcmljZSA8LSBDbChUU01bQm9UXSkKdHNtX2VfcHJpY2UgPC0gQ2woVFNNW0VvVF0pCgpgYGAKClRvIHZpc3VhbGl6ZSB0aGUgZGF0YToKCmBgYHtyfQpWaWV3KFBLTy5XQSkKVmlldyhUU00pCmBgYAoKYGBge3J9CmNoYXJ0U2VyaWVzKENsKFBLTy5XQSksdGhlbWU9IndoaXRlIikKY2hhcnRTZXJpZXMoQ2woVFNNKSx0aGVtZT0id2hpdGUiKQpgYGAKClRoZW4sIHdlIHdpbGwgZ2V0IHRoZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGl2aWRlbmRzIG9uIGVhY2ggc3RvY2suCgpgYGB7cn0KI0hpc3RvcmljYWwgZGF0YSBvZiBkaXZpZGVuZHMgCgpwa29fZGl2IDwtIGdldERpdmlkZW5kcygiUEtPLldBIikKdHNtX2RpdiA8LSBnZXREaXZpZGVuZHMoIlRTTSIpCgojRXh0cmFjdCB0aGUgb25lcyB0aGF0IGFyZSBjbG9zZXMgYnV0IGJlZm9yZSB0aGUgdGFyZ2V0IGRhdGUKCnBrb19iX2RpdiA8LSBwa29fZGl2W3doaWNoLm1pbihhYnMoaW5kZXgocGtvX2RpdikgLSBCb1QpKV0KcGtvX2VfZGl2IDwtIHBrb19kaXZbd2hpY2gubWluKGFicyhpbmRleChwa29fZGl2KSAtIEVvVCkpXQoKdHNtX2JfZGl2IDwtIHRzbV9kaXZbd2hpY2gubWluKGFicyhpbmRleCh0c21fZGl2KSAtIEJvVCkpXQp0c21fZV9kaXYgPC0gdHNtX2Rpdlt3aGljaC5taW4oYWJzKGluZGV4KHRzbV9kaXYpIC0gRW9UKSldCgpgYGAKCldlIHNlZSB0aGF0IG5laXRoZXIgb2YgZWFjaCBzdG9jayBkaXN0cmlidXRlIGRpdmlkZW5kcyBkdXJpbmcgdGhlIHRoaXMgc3BlY2lmaWMgdGltZSByYW5nZS4KCmBgYHtyfQojIENyZWF0ZSB0aGUgZGF0YSBmcmFtZQpzdG9ja190YWJsZSA8LSBkYXRhLmZyYW1lKAogIERlc2NyaXB0aW9uID0gYygKICAgICJXU0U6IFBLTyBTdG9jayBwcmljZSIsCiAgICAiUEtPIERpdmlkZW5kIiwKICAgICJOWVNFOiBUU00gU3RvY2sgcHJpY2UiLAogICAgIlRTTSBEaXZpZGVuZCIKICApLAogIEJvVCA9IE5BLCAgCiAgRW9UID0gTkEgIAopCgpWaWV3KHN0b2NrX3RhYmxlKQoKCiNGaWxsIHdpdGggZGF0YQpzdG9ja190YWJsZVsxLCAyXSA8LSBwa29fYl9wcmljZQpzdG9ja190YWJsZVsxLCAzXSA8LSBwa29fZV9wcmljZQoKc3RvY2tfdGFibGVbMiwgMl0gPC0gcGtvX2JfZGl2CnN0b2NrX3RhYmxlWzIsIDNdIDwtIHBrb19lX2RpdgoKc3RvY2tfdGFibGVbMywgMl0gPC0gdHNtX2JfcHJpY2UKc3RvY2tfdGFibGVbMywgM10gPC0gdHNtX2VfcHJpY2UKCnN0b2NrX3RhYmxlWzQsIDJdIDwtIHRzbV9iX2RpdgpzdG9ja190YWJsZVs0LCAzXSA8LSB0c21fZV9kaXYKCnByaW50KHN0b2NrX3RhYmxlKQoKYGBgCgotICAgKlVzZSBmdXR1cmVzIHByaWNlcyBxdW90YXRpb25zIHRvIHJlY29yZCB0aGUgcmVjZW50ICjigJxzZXR0bGXigJ0pIHByaWNlIG9mIHRoZSBmb2xsb3dpbmcgZnV0dXJlcyAoc2VsZWN0IGZ1dHVyZXMgd2l0aCBmaXJzdCBzZXR0bGVtZW50IGRhdGUgYmV5b25kIHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtKS4qCgpGaXJzdCB3ZSB3aWxsIGxvb2sgZm9yIHRoZSB0aWNrZXJzIG9mIGVhY2ggZnV0dXJlIGluIHlhaG9vIGZpbmFuY2UuCgpgYGB7cn0KI0hpc3RvcmljYWwgZGF0YSBvZiB0aGUgZnV0dXJlcwoKc3A1MDBfZiA8LSBnZXRTeW1ib2xzKCJFUz1GIiwgZnJvbT0gQm9ULCB0bz1Fb1QrMiwgYXV0by5hc3NpZ24gPSBGKQpuYXNkYXFfZiA8LSBnZXRTeW1ib2xzKCJOUT1GIiwgZnJvbT0gQm9ULCB0bz1Fb1QrMiwgYXV0by5hc3NpZ24gPSBGKQp0cmVhc3VyeV9mIDwtIGdldFN5bWJvbHMoIlpCPUYiLCBmcm9tPSBCb1QsIHRvPUVvVCsyLCBhdXRvLmFzc2lnbiA9IEYpCmJyaXRpc2hfZiA8LSBnZXRTeW1ib2xzKCI2Qj1GIiwgZnJvbT0gQm9ULCB0bz1Fb1QrMiwgYXV0by5hc3NpZ24gPSBGKQoKYGBgCgpOb3cgd2UgY3JlYXRlIHRoZSB0YWJsZSBhbmQgdGhlbiB3ZSBmaWxsIGl0LgoKYGBge3J9CiMgQ3JlYXRlIHRoZSBkYXRhIGZyYW1lCmZ1dHVyZXNfdGFibGUgPC0gZGF0YS5mcmFtZSgKICBEZXNjcmlwdGlvbiA9IGMoCiAgICAiVHJlYXN1cnkgYm9uZCBmdXR1cmVzIiwKICAgICJTJlA1MDAgaW5kZXggZnV0dXJlcyIsCiAgICAiTkFTREFRIGluZGV4IGZ1dHVyZXMiLAogICAgIkJyaXRpc2ggcG91bmRzIGZ1dHVyZXMiCiAgKSwKICBCb1QgPSBOQSwgIAogIEVvVCA9IE5BICAgCikKCgoKI0ZpbGwgd2l0aCBkYXRhCnN5bWJvbHMgPC0gbGlzdCh0cmVhc3VyeV9mLCBzcDUwMF9mLCBuYXNkYXFfZiwgYnJpdGlzaF9mKQpyb3dzIDwtIDE6NCAgIyBSb3cgaW5kaWNlcyBpbiBmdXR1cmVzX3RhYmxlIGNvcnJlc3BvbmRpbmcgdG8gdGhlIHN5bWJvbHMKCiMgTG9vcCB0aHJvdWdoIGVhY2ggc3ltYm9sIGFuZCByb3cKZm9yIChpIGluIHNlcV9hbG9uZyhzeW1ib2xzKSkgewogICMgRXh0cmFjdCB0aGUgc3ltYm9sIGFuZCBpdHMgY29ycmVzcG9uZGluZyByb3cKICBzeW1ib2wgPC0gc3ltYm9sc1tbaV1dCiAgcm93IDwtIHJvd3NbaV0KICAKICAjIEFzc2lnbiBjbG9zaW5nIHByaWNlcyBmb3IgQm9UIGFuZCBFb1QKICBmdXR1cmVzX3RhYmxlW3JvdywgMl0gPC0gQ2woc3ltYm9sW0JvVF0pCiAgZnV0dXJlc190YWJsZVtyb3csIDNdIDwtIENsKHN5bWJvbFtFb1RdKQp9CgoKcHJpbnQoZnV0dXJlc190YWJsZSkKYGBgCgotICAgKlVzZSBhbiBvcHRpb25zIHF1b3RhdGlvbnMgdGFibGUgdG8gc2VsZWN0IGEgY2FsbCBvcHRpb24gb24gYSBmaXJtIHdob3NlIHN0b2NrIHByaWNlIHlvdSBleHBlY3QgdG8gaW5jcmVhc2UgKHNlbGVjdCB0aGUgb3B0aW9uIHdpdGggdGhlIGZpcnN0IGV4cGlyYXRpb24gbW9udGggYmV5b25kIHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtKS4qCgpgYGB7cn0KCmNhdCgiTmFtZSBvZiB0aGUgZmlybTogIiwgIlRlc2xhIiwgIlxuIikKY2F0KCJFeHBpcmF0aW9uIG1vbnRoOiIsICIyMDI0LTExLTI5IiwgIlxuIikKY2F0KCJTdHJpa2UgcHJpY2U6IiwgMzM1ICwgIlxuIikKCmNhbGxfdGFiIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjaGFyYWN0ZXIoKSwKICBCZWdpbm5pbmdfb2ZfVGVybSA9IGNoYXJhY3RlcigpLAogIEVuZF9vZl9UZXJtID0gY2hhcmFjdGVyKCkKKQoKCmFkZF9yb3cgPC0gZnVuY3Rpb24oY2F0ZWdvcnksIHN5bWJvbCkgewogIGRhdGEgPC0gZ2V0U3ltYm9scyhzeW1ib2wsIGZyb209Qm9ULCB0bz1Fb1QrMiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKICBjYWxsX3RhYiA8PC0gcmJpbmQoY2FsbF90YWIsIGRhdGEuZnJhbWUoCiAgICBEZXNjcmlwdGlvbiA9IGNhdGVnb3J5LAogICAgQm9UID0gYXMubnVtZXJpYyhDbChkYXRhKVt3aGljaC5taW4oYWJzKGluZGV4KGRhdGEpIC0gQm9UKSldKSwKICAgIEVvVCA9IGFzLm51bWVyaWMoQ2woZGF0YSlbd2hpY2gubWluKGFicyhpbmRleChkYXRhKSAtIEVvVCkpXSkKICApKQp9CgoKYWRkX3JvdygiU3RvY2sgcHJpY2UiLCJUU0xBIiApCmFkZF9yb3coIk9wdGlvbiBwcmVtaXVtIiwiVFNMQTI0MTIwNkMwMDMzNTAwMCIgKQoKcHJpbnQoY2FsbF90YWIpCgpgYGAKCi0gICAqVXNlIGFuIG9wdGlvbnMgcXVvdGF0aW9ucyB0YWJsZSB0byBzZWxlY3QgYSBwdXQgb3B0aW9uIG9uIGEgZmlybSB3aGVyZSB5b3UgZXhwZWN0IHRoZSBzdG9jayBwcmljZSB0byBkZWNyZWFzZSAoc2VsZWN0IHRoZSBvcHRpb24gd2l0aCB0aGUgZmlyc3QgZXhwaXJhdGlvbiBtb250aCBiZXlvbmQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0pKgoKYGBge3J9CmNhdCgiTmFtZSBvZiB0aGUgZmlybTogIiwgIk5WSURJQSIsICJcbiIpCmNhdCgiRXhwaXJhdGlvbiBtb250aDoiLCAiMjAyNC0xMS0yOSIsICJcbiIpCmNhdCgiU3RyaWtlIHByaWNlOiIsIDEzMCAsICJcbiIpCmBgYAoKYGBge3J9CgpwdXRfdGFiIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjaGFyYWN0ZXIoKSwKICBCZWdpbm5pbmdfb2ZfVGVybSA9IGNoYXJhY3RlcigpLAogIEVuZF9vZl9UZXJtID0gY2hhcmFjdGVyKCkKKQoKCmFkZF9yb3cgPC0gZnVuY3Rpb24oY2F0ZWdvcnksIHN5bWJvbCkgewogIGRhdGEgPC0gZ2V0U3ltYm9scyhzeW1ib2wsIGZyb209Qm9ULCB0bz1Fb1QrMiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKICBwdXRfdGFiIDw8LSByYmluZChwdXRfdGFiLCBkYXRhLmZyYW1lKAogICAgRGVzY3JpcHRpb24gPSBjYXRlZ29yeSwKICAgIEJvVCA9IGFzLm51bWVyaWMoQ2woZGF0YSlbd2hpY2gubWluKGFicyhpbmRleChkYXRhKSAtIEJvVCkpXSksCiAgICBFb1QgPSBhcy5udW1lcmljKENsKGRhdGEpW3doaWNoLm1pbihhYnMoaW5kZXgoZGF0YSkgLSBFb1QpKV0pCiAgKSkKfQoKCmFkZF9yb3coIlN0b2NrIHByaWNlIiwiTlZEQSIgKQphZGRfcm93KCJPcHRpb24gcHJlbWl1bSIsIk5WREEyNDExMjlQMDAxMzAwMDAiICkKCnByaW50KHB1dF90YWIpCmBgYAoKLSAgICpVc2UgYSBjdXJyZW5jeSBleGNoYW5nZSByYXRlIHRhYmxlIHRvIHJlY29yZCBleGNoYW5nZSByYXRlcy4qCgpgYGB7cn0KY3VycmVuY3lfdGFiIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjaGFyYWN0ZXIoKSwKICBCZWdpbm5pbmdfb2ZfVGVybSA9IGNoYXJhY3RlcigpLAogIEVuZF9vZl9UZXJtID0gY2hhcmFjdGVyKCkKKQoKCmFkZF9yb3cgPC0gZnVuY3Rpb24oY2F0ZWdvcnksIHN5bWJvbCkgewogIGRhdGEgPC0gZ2V0U3ltYm9scyhzeW1ib2wsIGZyb209Qm9ULCB0bz1Fb1QrMiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKICBjdXJyZW5jeV90YWIgPDwtIHJiaW5kKGN1cnJlbmN5X3RhYiwgZGF0YS5mcmFtZSgKICAgIERlc2NyaXB0aW9uID0gY2F0ZWdvcnksCiAgICBCb1QgPSBhcy5udW1lcmljKENsKGRhdGEpW3doaWNoLm1pbihhYnMoaW5kZXgoZGF0YSkgLSBCb1QpKV0pLAogICAgRW9UID0gYXMubnVtZXJpYyhDbChkYXRhKVt3aGljaC5taW4oYWJzKGluZGV4KGRhdGEpIC0gRW9UKSldKQogICkpCn0KCgphZGRfcm93KCJFeGNoYW5nZSByYXRlIG9mIHRoZSBCcml0aXNoIHBvdW5kIChpbiAkKSIsIkdCUFVTRD1YIiApCmFkZF9yb3coIkV4Y2hhbmdlIHJhdGUgb2YgdGhlIEphcGFuZXNlIHllbiAoaW4gJCkiLCJKUFk9WCIgKQphZGRfcm93KCJFeGNoYW5nZSByYXRlIG9mIHRoZSBNZXhpY2FuIHBlc28gKGluICQpIiwiTVhOPVgiICkKCnByaW50KGN1cnJlbmN5X3RhYikKCmBgYAoKLSAgICpVc2UgY3VycmVuY3kgb3B0aW9ucyBkYXRhIChpZiBhdmFpbGFibGUpIHRvIHNlbGVjdCBhIGNhbGwgb3B0aW9uIG9uIGEgZm9yZWlnbiBjdXJyZW5jeSB0aGF0IHlvdSBleHBlY3Qgd2lsbCBzdHJlbmd0aGVuIGFnYWluc3QgdGhlIGRvbGxhciAoc2VsZWN0IHRoZSBvcHRpb24gd2l0aCB0aGUgZmlyc3QgZXhwaXJhdGlvbiBtb250aCBiZXlvbmQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0pLioKCjwhLS0gLS0+CgotICAgKlVzZSBjdXJyZW5jeSBvcHRpb25zIGRhdGEgKGlmIGF2YWlsYWJsZSkgdG8gc2VsZWN0IGEgcHV0IG9wdGlvbiBvbiBhIGZvcmVpZ24gY3VycmVuY3kgdGhhdCB5b3UgZXhwZWN0IHdpbGwgd2Vha2VuIGFnYWluc3QgdGhlIGRvbGxhciAoc2VsZWN0IHRoZSBvcHRpb24gd2l0aCB0aGUgZmlyc3QgZXhwaXJhdGlvbiBtb250aCBiZXlvbmQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0pLioKCkkgZGlkbid0IGZpbmQgaW5mb3JtYXRpb24gYWJvdXQgY2FsbCBvciBwdXQgb3B0aW9ucywganVzdCBmb3J3YXJkIGV4Y2hhbmdlIHJhdGVzLgoKYGBge3J9CmNhdCgiQ3VycmVuY3k6ICIsICJKYXBhbmVzZSBZZW4iLCAiXG4iKQpjYXQoIkV4cGlyYXRpb24gbW9udGg6IiwgIjIwMjQtMTItMDQiLCAiXG4iKQpjYXQoIlN0cmlrZSBwcmljZToiLCAxNTEuNjIgLCAiXG4iKQoKY3VycmVuY3lfdGFiIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjaGFyYWN0ZXIoKSwKICBCZWdpbm5pbmdfb2ZfVGVybSA9IGNoYXJhY3RlcigpLAogIEVuZF9vZl9UZXJtID0gY2hhcmFjdGVyKCkKKQoKYWRkX3JvdyA8LSBmdW5jdGlvbihjYXRlZ29yeSwgc3ltYm9sKSB7CiAgZGF0YSA8LSBnZXRTeW1ib2xzKHN5bWJvbCwgZnJvbT1Cb1QsIHRvPUVvVCsyLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQogIGN1cnJlbmN5X3RhYiA8PC0gcmJpbmQoY3VycmVuY3lfdGFiLCBkYXRhLmZyYW1lKAogICAgRGVzY3JpcHRpb24gPSBjYXRlZ29yeSwKICAgIEJvVCA9IGFzLm51bWVyaWMoQ2woZGF0YSlbd2hpY2gubWluKGFicyhpbmRleChkYXRhKSAtIEJvVCkpXSksCiAgICBFb1QgPSBhcy5udW1lcmljKENsKGRhdGEpW3doaWNoLm1pbihhYnMoaW5kZXgoZGF0YSkgLSBFb1QpKV0pCiAgKSkKfQoKCmFkZF9yb3coIkN1cnJlbmN54oCZcyBleGlzdGluZyB2YWx1ZSIsIkpQWVVTRD1YIiApCgpwcmludChjdXJyZW5jeV90YWIpCgoKYGBgCgojIyBMMiBGaW5hbmNpYWwgbWFya2V0cyBtaWNybyBzdHJ1Y3R1cmUKCjEuICBEb3dubG9hZCBiYXNpYyBzdGF0aXN0aWMgb2YgTkFTREFRIGFuZCBMb25kb24gU3RvY2sgRXhjaGFuZ2UgYW5kIGNvbXBhcmUgdGhlbQoKYGBge3J9CmdldFN5bWJvbHMoIk5EQVEiLCBmcm9tPSBCb1QsIHRvPUVvVCkKZ2V0U3ltYm9scygiXkZUU0UiLCBmcm9tPSBCb1QsIHRvPUVvVCkgCgojYWRkIGEgZ3JhcGggYWRqdXN0ZWQgCgpGVFNFPC0gbmEuYXBwcm94KEZUU0UpCgoKI0NvcnJlbGF0aW9uCmNvcnIgPC0gbWVyZ2UoTkRBUSwgRlRTRSkKY29yciA8LSBuYS5vbWl0KGNvcnIpCgpjb3JyZWxhdGlvbiA8LSBjb3IoY29yclssIDRdLCBjb3JyWywgMTBdKQoKCgpuYXNkYXFfcyA8LSBjKAogIE1lYW4gPSBtZWFuKE5EQVEkTkRBUS5DbG9zZSwgbmEucm09VFJVRSksCiAgTWVkaWFuID0gbWVkaWFuKE5EQVEkTkRBUS5DbG9zZSwgbmEucm09VFJVRSksCiAgU3REZXYgPSBzZChOREFRJE5EQVEuQ2xvc2UsIG5hLnJtPSBUUlVFKQopCgpsc2VfcyA8LSBjKAogIE1lYW4gPSBtZWFuKEZUU0UkRlRTRS5DbG9zZSksCiAgTWVkaWFuID0gbWVkaWFuKEZUU0UkRlRTRS5DbG9zZSksCiAgU3REZXYgPSBzZChGVFNFJEZUU0UuQ2xvc2UpCikKCgpjb21wYXJpc29uIDwtIHJiaW5kKG5hc2RhcV9zLCBsc2VfcykKY29sbmFtZXMoY29tcGFyaXNvbikgPC0gYygiTWVhbiIsICJNZWRpYW4iLCAiU3RhbmRhcmQgRGV2aWF0aW9uIiApCgpyb3VuZChjb3JyZWxhdGlvbiwgMykKcm91bmQoY29tcGFyaXNvbiwyKQoKCmBgYAoKVGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIG1hcmtldHMgaXMgdmVyeSBsb3c6IDAuMzQxLiBXZSBzZWUgYWxzbywgdGhhdCB0aGUgdm9sYXRpbGl0eSAobWVhc3VyZWQgYnkgdGhlIHN0YW5kYXJkIGRldmlhdGlvbikgb2YgdGhlIExvbmRvbiBTRSBpcyBncmVhdGVyIHRoYXQgdGhlIE5BU0RBUS4KCiMjIEwzIEluc3RydW1lbnTigJlzIG92ZXJ2aWV3IGFuZCB2YWx1YXRpb24KCi0gICBDb21wYXJlIHRoZSAxMy13ZWVrIFRyZWFzdXJ5IGJpbGwgcmF0ZSAod2hpY2ggaXMgYSBwcm94eSBmb3Igc2hvcnQtdGVybSBpbnRlcmVzdCByYXRlcykgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0gdG8gdGhlIHJhdGUgdGhhdCBleGlzdGVkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNjaG9vbCB0ZXJtLiAobm90ZTogMy1Nb250aCBUcmVhc3VyeSBCaWxsIFNlY29uZGFyeSBNYXJrZXQgUmF0ZSwgRGlzY291bnQgQmFzaXMgKFRCM01TKSkgPGh0dHBzOi8vZnJlZC5zdGxvdWlzZmVkLm9yZy9zZXJpZXMvVGNsQjNNUz4KCmBgYHtyfQp0YjNtIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjaGFyYWN0ZXIoKSwKICBCZWdpbm5pbmdfb2ZfVGVybSA9IGNoYXJhY3RlcigpLAogIEVuZF9vZl9UZXJtID0gY2hhcmFjdGVyKCksCiAgQ2hhbmdlID0gY2hhcmFjdGVyKCkKKQoKCgphZGRfcm93IDwtIGZ1bmN0aW9uKGNhdGVnb3J5LCBzeW1ib2wpIHsKICBkYXRhIDwtIGdldFN5bWJvbHMoc3ltYm9sLCBmcm9tPUJvVCwgdG89RW9UKzIsc3JjPSJGUkVEIiwgYXV0by5hc3NpZ24gPSBGQUxTRSkKICB0YjNtIDw8LSByYmluZCh0YjNtLCBkYXRhLmZyYW1lKAogICAgRGVzY3JpcHRpb24gPSBjYXRlZ29yeSwKICAgIEJvVCA9IGFzLm51bWVyaWMoZGF0YVt3aGljaC5taW4oYWJzKGluZGV4KGRhdGEpIC0gQm9UKSksIDFdKSwKICAgIEVvVCA9IGFzLm51bWVyaWMoZGF0YVt3aGljaC5taW4oYWJzKGluZGV4KGRhdGEpIC0gRW9UKSksIDFdKSwgCiAgICBDaGFuZ2U9IGFzLm51bWVyaWMoZGF0YVt3aGljaC5taW4oYWJzKGluZGV4KGRhdGEpIC0gRW9UKSksIDFdKS1hcy5udW1lcmljKGRhdGFbd2hpY2gubWluKGFicyhpbmRleChkYXRhKSAtIEJvVCkpLCAxXSkKICApKQp9CgphZGRfcm93KCJUcmVhc3VyeSBiaWxsICgzLW1vbnRoKSIsIlRCM01TIiApCgpwcmludCh0YjNtKQoKCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSByYXRlIGhhcyBkZWNyZWFzZWQgYnkgNzMgYmFzaWMgcG9pbnRzLgoKLSAgICpXaHkgaW50ZXJlc3QgcmF0ZXMgY2hhbmdlIG92ZXIgdGltZS4qCgpJbnRlcmVzdCBtYWlubHkgY2hhbmdlIGR1ZSB0byBlY29ub21pYyBjb25kaXRpb25zLiBXaGVuIHRoZSBlY29ub215IGlzIG92ZXJoZWF0ZWQsIHRoZSBDZW50cmFsIEJhbmsgd2lsbCBpbmNyZWFzZSB0aGUgZmVkZXJhbCBmdW5kcyByYXRlcyAoRkZSKSB0byBzbG93ZG93biB0aGUgZWNvbm9teS4gVGhpcyB3aWxsIGltcGFjdCBvbiBhbGwgdGhlIHlpZWxkIGN1cnZlLCBzcGVjaWFsbHkgb24gdGhlIHNob3J0IHRlcm0gcmF0ZXMuIFRodXMsIHNpbmNlIHRoZSBGRUQgZGVjaWRlZCB0byBjdXQgdGhlIEZGUiBhbmQgdGhlIGludmVzdG9ycyBhcmUgZXhwZWN0aW5nIGZ1dHVyZSBjdXRzIGluIHRoZSBmb2xsb3dpbmcgbWVldGluZ3MsIHdlIGhhdmUgc2VlbiB0aGF0IHRoZSB5aWVsZCBvZiB0aGUgVEIzTSBoYXMgZGVjcmVhc2VkLgoKIyMgTDQgRWZmaWNpZW5jeSBvZiBtYXJrZXQgYW5kIGluZm9ybWF0aW9uCgotICAgKkNoZWNrIGlmIG9uIDI2IE9jdG9iZXIgMjAxNyBDb2NhIENvbGEgc2hhcmVzIHdlcmUgaGl0IGJ5IHRoZSBhZHZlcnNlIGluZm9ybWF0aW9uIHJlYWxpemUgb24gdGhlIG1hcmtldC4gKGFzc3VtZSAyNiBpcyB0aGUgaW5mb3JtYXRpb24gcmVhbGlzZSBkYXRlKSoKCmBgYHtyfQpkYXRlIDwtIGFzLkRhdGUoIjIwMTctMTAtMjYiKQpnZXRTeW1ib2xzKCJLTyIsIGZyb209ZGF0ZS01LCB0bz1kYXRlKzMwKQpLTzwtIHJvdW5kKEtPLCAyKQpkZXYubmV3KCkKY2hhcnRTZXJpZXMoQ2woS08pLHRoZW1lPSJ3aGl0ZSIpCmFkZFRBKENsKEtPKVtpbmRleChLTykgPT0gZGF0ZV0sIG9uID0gMSwgY29sID0gImJsdWUiLCBwY2ggPSAxOSwgdHlwZSA9ICJwIiwgbGVnZW5kID0gRkFMU0UpCgoKYGBgCgpJbiBPY3RvYmVyIDIwMTcsIENvY2EgQ29sYSBoYWQgYSBkZWNyZWFzZSBpbiBpdHMgbmV0IGluY29tZSBvZiAxNSUgYmVjYXVzZSBvZiB0aGUgZnJhbmNoaXNpbmcgcHJvY2Vzcy4gRHVlIHRvIHRoaXMsIG9uIE9jdG9iZXIgMjYgdGhlIHByaWNlIGNsb3NlZCBhdCBcJDQ1LjU5LCB3aGljaCB3YXMgYSBkZWNyZWFzZSBvZiAwLjUlIGNvbXBhcmVkIHRvIHRoZSAyNXRoLiBBbHNvLCB3ZSBub3RpY2UgdGhhdCB0aGVyZSB3YXMgYSByZWFjdGlvbiB0byB0aGUgbmV3cyBkYXlzIGFmdGVyIE5vdmVtYmVyIDNyZCBhbmQgdGhlbiBhIGNvcnJlY3Rpb24gKGFuIHVuZGVycmVhY3Rpb24gYW5kIHRoZW4gYSBjb3JyZWN0aW9uKS4gU28sIHRvIHN1bSB1cCB3ZSBjYW4gY29uZmlybSB0aGF0IHRoZXJlIGlzIGFuIGltcGFjdCBzcGVjaWFsbHkgbm90YWJsZSBkYXlzIGFmdGVyIHRoZSByZWFsaXplIGRhdGUgcmVnYXJkaW5nIHRoZSBjb21wYW55J3MgYWN0aW9ucyBkdWUgdG8gdGhlIGFkdmVyc2UgaW5mb3JtYXRpb24gcmVhbGl6ZWQgb24gdGhlIG1hcmtldC4KCiMjIEw1IEZpbmFuY2lhbCBzdGF0ZW1lbnRzIGFuZCBmdW5kYW1lbnRhbCBhbmFseXNpcwoKLSAgICpEb3dubG9hZCB0byBSIHRoZSBmaW5hbmNpYWwgc3RhdGVtZW50cyBvZiBNaWNyb3NvZnQgMjAxOCwgc2hvdyB0aGUgY29kKgoKV2UgZG93bmxvYWQgdGhlIEJhbGFuY2UgU2hlZXQsIENhc2ggRmxvdyBhbmQgSW5jb21lIG9mIE1pY3Jvc29mdCBmb3IgMjAxOC4KCmBgYHtyfQoKbGlicmFyeShmaW5yZXBvcnRyKSAjIGZvciBmaW5hbmNpYWxzCmxpYnJhcnkoZWRnYXIpICAjIGZvciBmdWxsIHRleHQgcmV0cmlhbCBhbmQgdGV4dCBtaW5pbmcKbGlicmFyeShYQlJMKSAgIyBmb3IgaW5zdGFudHMgKGZ1bGwgc2V0IG1hbmlwdWxhdGlvbikKbGlicmFyeShkcGx5cikgCmxpYnJhcnkodGlkeXIpCgoKb3B0aW9ucyhIVFRQVXNlckFnZW50ID0gImNhbWlsYWRlbGFjcnV6aEBnbWFpbC5jb20iKQoKQW5udWFsUmVwb3J0cygwMDAwNzg5MDE5LCBmb3JlaWduID0gRkFMU0UpCgoKdHJhY2UoJ1hCUkwnLCBlZGl0PVRSVUUpCgojVGhlcmUncyBpcyBhIHByb2JsZW0gd2l0aCB0aGUgR2V0QmFsYW5jZVNoZWV0IGZ1bmN0aW9uLiBUbyBmaXggdGhhdCBwcm9ibGVtIHdlIHJ1biB0aGUgZm9sbG93aW5nIGNvZGUgdG8gZWRpdCB0aGUgZnVuY3Rpb24gdGVtcG9yYXJpbHk6IHRyYWNlKCdYQlJMJywgZWRpdD1UUlVFKS4gV2Ugd2lsbCByZXBsYWNlICJpZiAoc3Vic3RyKGZpbGUubmFtZSwgMSwgNSkgIT0gImh0dHA6IikgeyIgZm9yICJpZiAoIShzdWJzdHIoZmlsZS5uYW1lLCAxLCA1KSAlaW4lIGMoImh0dHA6IiwgImh0dHBzIikpKSB7Ii4gTm93IHdlIGNhbiBydW4gdGhlIGNvZGUgdG8gc2VhcmNoIGZpbGVzIGJleW9uZCAyMDE2LiAKCm1zZnRfYnMgPC1HZXRCYWxhbmNlU2hlZXQoJ01TRlQnLCAyMDE4KQptc2Z0X2NmIDwtR2V0Q2FzaEZsb3coJ01TRlQnLCAyMDE4KQptc2Z0X2luIDwtIEdldEluY29tZSgnTVNGVCcsIDIwMTgpCgoKaGVhZChtc2Z0X2NmKQpoZWFkKG1zZnRfaW4pCgoKYGBgCgpgYGB7cn0KaGVhZChtc2Z0X2JzKQoKCmBgYAoKYGBge3J9CmhlYWQobXNmdF9jZikKYGBgCgoqKkNvbW1lcmNpYWwgYmFuayBvcGVyYXRpb25zKioKCkZvciB0aGUgY29tbWVyY2lhbCBiYW5rIHRoYXQgeW91IHNlbGVjdGVkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRlcm0sIHVzZSBpdHMgYW5udWFsIHJlcG9ydCBvciBhbnkgb3RoZXIgcmVsYXRlZCBpbmZvcm1hdGlvbiB0byBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6CgpgYGB7cn0KCkFubnVhbFJlcG9ydHMoIkJBQyIsIGZvcmVpZ24gPSBGQUxTRSkKCgpiYWNfYnMgPC1HZXRCYWxhbmNlU2hlZXQoJ0JBQycsIDIwMTgpCmJhY19jZiA8LUdldENhc2hGbG93KCdCQUMnLCAyMDE4KQpiYWNfaW4gPC0gR2V0SW5jb21lKCdCQUMnLCAyMDE4KQoKYGBgCgotICAgKklkZW50aWZ5IHRoZSB0eXBlcyBvZiBkZXBvc2l0cyB0aGF0IHRoZSBjb21tZXJjaWFsIGJhbmsgdXNlcyB0byBvYnRhaW4gbW9zdCBvZiBpdHMgZnVuZHMuKgoKUHJpbWFyaWx5IHVzZXPCoGRlbWFuZCBkZXBvc2l0c8KgKHN1Y2ggYXMgY2hlY2tpbmcgYWNjb3VudHMpIGFuZMKgc2F2aW5ncyBhY2NvdW50cy4KCi0gICAqSWRlbnRpZnkgdGhlIG1haW4gdXNlcyBvZiBmdW5kcyBieSB0aGUgYmFuay4gU3VtbWFyaXplIGFueSBzdGF0ZW1lbnRzIG1hZGUgYnkgdGhlIGNvbW1lcmNpYWwgYmFuayBpbiBpdHMgYW5udWFsIHJlcG9ydCBhYm91dCBob3cgcmVjZW50IG9yIHBvdGVudGlhbCByZWd1bGF0aW9ucyB3aWxsIGFmZmVjdCBpdHMgcGVyZm9ybWFuY2UuKgoKVGhlIG1haW4gdXNlcyBvZiBmdW5kcyBhcmUgbG9hbnMgdG8gY3VzdG9tZXJzLCBpbnZlc3RtZW50cyBpbiBzZWN1cml0aWVzIGFuZCBjYXNoIHJlc2VydmVzLgoKVGhlIGJhbmsgaGlnaGxpZ2h0cyB1bmNlcnRhaW50aWVzIHJlZ2FyZGluZyB0aGUgY29udGVudCwgdGltaW5nLCBhbmQgaW1wYWN0IG9mIHJlZ3VsYXRvcnkgY2FwaXRhbCBhbmQgbGlxdWlkaXR5IHJlcXVpcmVtZW50cywgc3VjaCBhcyB0aG9zZSB1bmRlciB0aGUgVm9sY2tlciBSdWxlLCByZWNvdmVyeSBwbGFubmluZyByZXF1aXJlbWVudHMsIGFuZCB0aGUgRmVkZXJhbCBSZXNlcnZlJ3MgYWN0aW9ucyBvbiBjYXBpdGFsIHBsYW5zLgoKLSAgICpEb2VzIGl0IGFwcGVhciB0aGF0IHRoZSBiYW5rIGlzIGF0dGVtcHRpbmcgdG8gZW50ZXIgdGhlIHNlY3VyaXRpZXMgaW5kdXN0cnkgYnkgb2ZmZXJpbmcgc2VjdXJpdGllcyBzZXJ2aWNlcz8gSWYgc28sIGV4cGxhaW4gaG93LioKClRoZSByZXBvcnQgaW5kaWNhdGVzIHRoYXQgdGhlIGJhbmsgb2ZmZXJzIGEgcmFuZ2Ugb2YgaW52ZXN0bWVudCBiYW5raW5nIHNlcnZpY2VzLCBpbmNsdWRpbmcgdW5kZXJ3cml0aW5nIGZvciBlcXVpdHkgYW5kIGRlYnQgc2VjdXJpdGllcywgYWR2aXNvcnkgc2VydmljZXMgYW5kIGJyb2tlcmFnZSBzZXJ2aWNlcy4gQWRkaXRpb25hbGx5LCBCYW5rIG9mIEFtZXJpY2EgaGFzIGludGVncmF0ZWQgaXRzIHdlYWx0aCBtYW5hZ2VtZW50IHNlcnZpY2VzIHdpdGggaW52ZXN0bWVudCBzb2x1dGlvbnMsIGFsbG93aW5nIGNsaWVudHMgYWNjZXNzIHRvIGEgYnJvYWRlciBhcnJheSBvZiBmaW5hbmNpYWwgcHJvZHVjdHMsIGluY2x1ZGluZyBtdXR1YWwgZnVuZHMgYW5kIEVURnMuIFRoaXMgc3RyYXRlZ2ljIG1vdmUgaW5kaWNhdGVzIGEgY2xlYXIgaW50ZW50IHRvIGV4cGFuZGluZyBpdHMgcHJlc2VuY2UgaW4gdGhlIHNlY3VyaXRpZXMgaW5kdXN0cnkuCgotICAgKkRvZXMgaXQgYXBwZWFyIHRoYXQgdGhlIGJhbmsgaXMgYXR0ZW1wdGluZyB0byBlbnRlciB0aGUgaW5zdXJhbmNlIGluZHVzdHJ5IGJ5IG9mZmVyaW5nIGluc3VyYW5jZSBzZXJ2aWNlcz8gSWYgc28sIGV4cGxhaW4gaG93LioKClRoZSBiYW5rIGlzIGJ5IG9mZmVyaW5nIHZhcmlvdXMgaW5zdXJhbmNlLXJlbGF0ZWQgcHJvZHVjdHMgYW5kIHNlcnZpY2VzLiBUaGUgcmVwb3J0IGhpZ2hsaWdodHMgdGhlIHByb3Zpc2lvbiBvZiBsaWZlIGluc3VyYW5jZSwgcHJvcGVydHkgYW5kIGNhc3VhbHR5IGluc3VyYW5jZSwgYW5kIGhlYWx0aCBpbnN1cmFuY2UgcHJvZHVjdHMgdGhyb3VnaCBwYXJ0bmVyc2hpcHMgcyBhbmQgdGhlIGludGVncmF0aW9uIG9mIGluc3VyYW5jZSBzZXJ2aWNlcyB3aXRoaW4gdGhlaXIgYnJvYWRlciBmaW5hbmNpYWwgb2ZmZXJpbmdzLiBUaHVzLCBpdCBzZWVtcyB0aGF0IGlzIGFsc28gYXR0ZW1wdGluZyB0byBlbnRlciB0aGlzIGluZHVzdHJ5LgoKKipDb21tZXJjaWFsIGJhbmsgbWFuYWdlbWVudCoqCgotICAgKkFzc2VzcyB0aGUgYmFua+KAmXMgYmFsYW5jZSBzaGVldCBhcyB3ZWxsIGFzIGFueSBjb21tZW50cyBpbiBpdHMgYW5udWFsIHJlcG9ydCBhYm91dCB0aGUgZ2FwIGJldHdlZW4gaXRzIHJhdGUtc2Vuc2l0aXZlIGFzc2V0cyBhbmQgaXRzIHJhdGUtc2Vuc2l0aXZlIGxpYWJpbGl0aWVzLiBEb2VzIGl0IGFwcGVhciB0aGF0IHRoZSBiYW5rIGhhcyBhIHBvc2l0aXZlIGdhcCBvciBhIG5lZ2F0aXZlIGdhcD8qCgpEdXJpbmcgMjAyMywgQkEgZXhwZXJpZW5jZWQgYW4gb3ZlcmFsbCBkZWNyZWFzZSBpbiB0aGUgYXNzZXQgc2Vuc2l0aXZpdHkgb2YgaXRzIGJhbGFuY2Ugc2hlZXQgY29uY2VybmluZyBoaWdoZXIgYW5kIGxvd2VyIGludGVyZXN0IHJhdGUgc2NlbmFyaW9zLiBUaGlzIGNoYW5nZSB3YXMgcHJpbWFyaWx5IGF0dHJpYnV0ZWQgdG8gc2hpZnRzIGluIHRoZSBkZXBvc2l0IHByb2R1Y3QgbWl4IGFuZCBhY3Rpdml0eSB3aXRoaW4gdGhlIEFzc2V0LUxpYWJpbGl0eSBNYW5hZ2VtZW50IChBTE0pIHBvcnRmb2xpby5UaGUgYmFuayBjb250aW51ZXMgdG8gYmUgYXNzZXQgc2Vuc2l0aXZlIHRvIGEgcGFyYWxsZWwgdXB3YXJkIG1vdmUgaW4gaW50ZXJlc3QgcmF0ZXMsIHdpdGggdGhlIG1ham9yaXR5IG9mIHRoaXMgaW1wYWN0IHN0ZW1taW5nIGZyb20gdGhlIHNob3J0IGVuZCBvZiB0aGUgeWllbGQgY3VydmUuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIGJhbmsgaGFzIGHCoHBvc2l0aXZlIGdhcCwgbWVhbmluZyB0aGF0IGl0cyByYXRlLXNlbnNpdGl2ZSBhc3NldHMgYXJlIGV4cGVjdGVkIHRvIHJlc3BvbmQgbW9yZSBmYXZvcmFibHkgdG8gcmlzaW5nIGludGVyZXN0IHJhdGVzIGNvbXBhcmVkIHRvIGl0cyByYXRlLXNlbnNpdGl2ZSBsaWFiaWxpdGllcyAocHJpbWFyaWx5IGRlcG9zaXRzKS4KCkZvciB0aGUgbmV4dCBxdWVzdGlvbnMgd2Ugd2lsbCB1c2UgdGhlIGZpbmFuY2lhbCBkYXRhIHRoYXQgaXMgYXZhaWxhYmxlIG9uIHRoZSBmb2xsb3dpbmcgbGluazogPGh0dHBzOi8vd3d3LnNlYy5nb3YvaXg/ZG9jPS9BcmNoaXZlcy9lZGdhci9kYXRhLzcwODU4LzAwMDAwNzA4NTgyNDAwMDEyMi9iYWMtMjAyMzEyMzEuaHRtPgoKYGBge3J9CiMgRmluYW5jaWFsIGRhdGEgKG1pbGxpb25zIG9mICQpCnRvdGFsX2Fzc2V0cyA8LSAzMTgwMTUxCmludGVyZXN0X2luY29tZSA8LSAxMzAyNjIKaW50ZXJlc3RfZXhwZW5zZSA8LSA3MzMzMQpub25pbnRlcmVzdF9pbmNvbWUgPC0gNDE2NTAKbm9uaW50ZXJlc3RfZXhwZW5zZSA8LSA2NTg0NQplYXJuaW5nX2Fzc2V0cyA8LSAyNzUzNjAwCm5ldF9pbmNvbWUgPC0gMjY1MTUKc2hhcmVob2xkZXJzX2VxdWl0eSA8LSAyOTE2NDYKbG9hbl9sb3NzX3Jlc2VydmVzIDwtIDEzMzQyCgpgYGAKCi0gICAqRGV0ZXJtaW5lIHRoZSBiYW5r4oCZcyBpbnRlcmVzdCBpbmNvbWUgYXMgYSBwZXJjZW50YWdlIG9mIGl0cyB0b3RhbCBhc3NldHMuKgoKYGBge3J9CmludGVyZXN0X2luY29tZV9wZXJjZW50YWdlIDwtIChpbnRlcmVzdF9pbmNvbWUgLyB0b3RhbF9hc3NldHMpICogMTAwCnJvdW5kKGludGVyZXN0X2luY29tZV9wZXJjZW50YWdlLDIpCmBgYAoKLSAgICpEZXRlcm1pbmUgdGhlIGJhbmvigJlzIGludGVyZXN0IGV4cGVuc2VzIGFzIGEgcGVyY2VudGFnZSBvZiBpdHMgdG90YWwgYXNzZXRzLioKCmBgYHtyfQppbnRlcmVzdF9leHBlbnNlX3BlcmNlbnRhZ2UgPC0gKGludGVyZXN0X2V4cGVuc2UgLyB0b3RhbF9hc3NldHMpICogMTAwCgpyb3VuZChpbnRlcmVzdF9leHBlbnNlX3BlcmNlbnRhZ2UsMikKYGBgCgotICAgKkRldGVybWluZSB0aGUgYmFua+KAmXMgbmV0IGludGVyZXN0IG1hcmdpbi4qCgpgYGB7cn0KbmV0X2ludGVyZXN0X2luY29tZSA8LSBpbnRlcmVzdF9pbmNvbWUgLSBpbnRlcmVzdF9leHBlbnNlCm5pbSA8LSAobmV0X2ludGVyZXN0X2luY29tZSAvIGVhcm5pbmdfYXNzZXRzKSAqIDEwMApwcmludChuaW0sIDIpCgpgYGAKCi0gICAqRGV0ZXJtaW5lIHRoZSBiYW5r4oCZcyBub25pbnRlcmVzdCBpbmNvbWUgYXMgYSBwZXJjZW50YWdlIG9mIGl0cyB0b3RhbCBhc3NldHMuKgoKYGBge3J9Cgpub25pbnRlcmVzdF9pbmNvbWVfcGVyY2VudGFnZSA8LSAobm9uaW50ZXJlc3RfaW5jb21lIC8gdG90YWxfYXNzZXRzKSAqIDEwMApwcmludChub25pbnRlcmVzdF9pbmNvbWVfcGVyY2VudGFnZSwgMikKYGBgCgotICAgKkRldGVybWluZSB0aGUgYmFua+KAmXMgbm9uaW50ZXJlc3QgZXhwZW5zZXMgKGRvIG5vdCBpbmNsdWRlIHRoZSBhZGRpdGlvbiB0byBsb2FuIGxvc3MgcmVzZXJ2ZXMgaGVyZSkgYXMgYSBwZXJjZW50YWdlIG9mIGl0cyB0b3RhbCBhc3NldHMuKgoKYGBge3J9Cm5vbmludGVyZXN0X2V4cGVuc2VfcGVyY2VudGFnZSA8LSAobm9uaW50ZXJlc3RfZXhwZW5zZSAvIHRvdGFsX2Fzc2V0cykgKiAxMDAKcHJpbnQobm9uaW50ZXJlc3RfZXhwZW5zZV9wZXJjZW50YWdlLCAyKQpgYGAKCi0gICAqRGV0ZXJtaW5lIHRoZSBiYW5r4oCZcyBhZGRpdGlvbiB0byBsb2FuIGxvc3MgcmVzZXJ2ZXMgYXMgYSBwZXJjZW50YWdlIG9mIGl0cyB0b3RhbCBhc3NldHMuKgoKYGBge3J9Cgpsb2FuX2xvc3NfcmVzZXJ2ZXNfcGVyY2VudGFnZSA8LSAobG9hbl9sb3NzX3Jlc2VydmVzIC8gdG90YWxfYXNzZXRzKSAqIDEwMApwcmludChsb2FuX2xvc3NfcmVzZXJ2ZXNfcGVyY2VudGFnZSwgMikKYGBgCgotICAgKkRldGVybWluZSB0aGUgYmFua+KAmXMgcmV0dXJuIG9uIGFzc2V0cyoKCmBgYHtyfQpyb2EgPC0gKG5ldF9pbmNvbWUgLyB0b3RhbF9hc3NldHMpICogMTAwCnByaW50KHJvYSwgMikKCmBgYAoKLSAgICpEZXRlcm1pbmUgdGhlIGJhbmvigJlzIHJldHVybiBvbiBlcXVpdHkuKgoKYGBge3J9CnJvZSA8LSAobmV0X2luY29tZSAvIHNoYXJlaG9sZGVyc19lcXVpdHkpICogMTAwCmBgYAoKLSAgICpJZGVudGlmeSB0aGUgYmFua+KAmXMgaW5jb21lIHN0YXRlbWVudCBpdGVtcyBkZXNjcmliZWQgcHJldmlvdXNseSB0aGF0IHdvdWxkIGJlIGFmZmVjdGVkIGlmIGludGVyZXN0IHJhdGVzIHJpc2UgaW4gdGhlIG5leHQgeWVhciwgYW5kIGV4cGxhaW4gaG93IHRoZXkgd291bGQgYmUgYWZmZWN0ZWQuKgoKVGhlIGludGVyZXN0IGluY29tZSBpcyBleHBlY3RlZCB0byBpbmNyZWFzZSBzaW5jZSBpbnRlcmVzdCBpbmNvbWUgd291bGQgcmlzZSBtb3JlIHRoYW4gaW50ZXJlc3QgZXhwZW5zZXMsIG5ldCBpbnRlcmVzdCBpbmNvbWUgd291bGQgbGlrZWx5IGltcHJvdmUsIGVuaGFuY2luZyBwcm9maXRhYmlsaXR5LgoKLSAgICpJZGVudGlmeSB0aGUgYmFua+KAmXMgaW5jb21lIHN0YXRlbWVudCBpdGVtcyBkZXNjcmliZWQgcHJldmlvdXNseSB0aGF0IHdvdWxkIGJlIGFmZmVjdGVkIGlmIFUuUy4gZWNvbm9taWMgY29uZGl0aW9ucyBkZXRlcmlvcmF0ZSwgYW5kIGV4cGxhaW4gaG93IHRoZXkgd291bGQgYmUgYWZmZWN0ZWQqCgpOZXQgSW50ZXJlc3QgSW5jb21lIGxpa2VseSB0byBkZWNyZWFzZS4gV2l0aCBkZWNsaW5pbmcgaW50ZXJlc3QgaW5jb21lIGFuZCBwb3RlbnRpYWxseSBzdGFibGUgb3IgZGVjcmVhc2luZyBpbnRlcmVzdCBleHBlbnNlLCBuZXQgaW50ZXJlc3QgaW5jb21lIHdvdWxkIGxpa2VseSBzdWZmZXIuCgpOZXQgaW5jb21lIGFsc28gbGlrZWx5IHRvIGRlY3JlYXNlLiBXaXRoIHJlZHVjZWQgbmV0IGludGVyZXN0IGluY29tZSBhbmQgbm9uaW50ZXJlc3QgaW5jb21lIGFsb25nc2lkZSBwb3RlbnRpYWwgaW5jcmVhc2VzIGluIGxvYW4gbG9zcyBwcm92aXNpb25zLCBvdmVyYWxsIHByb2ZpdGFiaWxpdHkgKG5ldCBpbmNvbWUpIGlzIGxpa2VseSB0byBkZWNsaW5lIGR1cmluZyBlY29ub21pYyBkb3dudHVybnMuCgoqKk11dHVhbCBmdW5kcyoqCgpGb3IgdGhlIG11dHVhbCBmdW5kIHRoYXQgeW91IHNlbGVjdGVkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRlcm0sIHVzZSBpdHMgcHJvc3BlY3R1cyBvciBhbnkgb3RoZXIgcmVsYXRlZCBpbmZvcm1hdGlvbiB0byBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuCgpXZSBzZWxlY3QgdGhlIEZpZGVsaXR5IDUwMCBJbmRleCBtdXR1YWwgZnVuZDogPGh0dHBzOi8vZnVuZHJlc2VhcmNoLmZpZGVsaXR5LmNvbS9tdXR1YWwtZnVuZHMvc3VtbWFyeS8zMTU5MTE3NTA+CgotICAgKldoYXQgaXMgdGhlIGludmVzdG1lbnQgb2JqZWN0aXZlIG9mIHRoaXMgbXV0dWFsIGZ1bmQ/IERvIHlvdSBjb25zaWRlciB0aGlzIG11dHVhbCBmdW5kIHRvIGhhdmUgbG93IHJpc2ssIG1vZGVyYXRlIHJpc2ssIG9yIGhpZ2ggcmlzaz8qCgpTaW5jZSBpdCBpbnZlc3QgaW4gZXF1aXR5IGFuZCBtb3JlIHRoYW4gMzAlIGlzIG9uIHRoZSB0ZWNoIHNlY3Rvciwgd2UgY29uc2lkZXIgdGhhdCBpcyBtb3JlZGF0ZSB0byBoaWdoIHJpc2suCgotICAgKldoYXQgd2FzIHRoZSByZXR1cm4gb24gdGhlIG11dHVhbCBmdW5kIGxhc3QgeWVhcj8gV2hhdCB3YXMgdGhlIGF2ZXJhZ2UgYW5udWFsIHJldHVybiBvdmVyIHRoZSBsYXN0IHRocmVlIHllYXJzPyoKCjIwMjM6IDI2LjI5JQoKTGFzdCB0aHJlZSB5ZWFyczogMzMuODclCgotICAgKldoYXQgaXMgYSBrZXkgZWNvbm9taWMgZmFjdG9yIHRoYXQgaW5mbHVlbmNlcyB0aGUgcmV0dXJuIG9uIHRoaXMgbXV0dWFsIGZ1bmQ/IChUaGF0IGlzLCBhcmUgdGhlIGZ1bmTigJlzIHJldHVybnMgaGlnaGx5IGluZmx1ZW5jZWQgYnkgVS5TLiBzdG9jayBtYXJrZXQgY29uZGl0aW9ucz8gQnkgVS5TLiBpbnRlcmVzdCByYXRlcz8gQnkgZm9yZWlnbiBzdG9jayBtYXJrZXQgY29uZGl0aW9ucz8gQnkgZm9yZWlnbiBpbnRlcmVzdCByYXRlcz8pKgoKSXMgaGlnaGx5IGluZmx1ZW5jZWQgYnkgdGhlIFVTIHN0b2NrIG1hcmtldCBjb25kaXRpb25zIHNpbmNlIG9ubHkgaW52ZXN0cyBpbiBVUyBzdG9ja3MuIEFsc28sIHRoYXQncyB3aHkgaXMgaW5mbHVlbmNlZCBieSBpbnRlcmVzdCByYXRlcyBvZiB0aGUgVVMuIEJ1dCBhcyBpdCBkb24ndCBpbiBvdGhlciBjb3VudHJ5LCB0aGUgZnVuZCBpcyBub3QgYWZmZWN0ZWQgYnkgZm9yZWlnbiBjb25kaXRpb25zLgoKLSAgICpNdXN0IGFueSBmZWVzIGJlIHBhaWQgd2hlbiBidXlpbmcgb3Igc2VsbGluZyB0aGlzIG11dHVhbCBmdW5kPyoKCkl0J3MgZmFjdHNoZWV0IHNhaWQgdGhhdCB5b3UgbWF5IGJlIGNoYXJnZWQgYSB0cmFuc2FjdGlvbnMgZmVlIGlmIHlvdSBidXkgb3Igc2VsbCB0cm91Z2ggYSBub24tRmlkZWxpdHkgYnJva2VyLgoKLSAgICpXaGF0IHdhcyB0aGUgZXhwZW5zZSByYXRpbyBmb3IgdGhpcyBtdXR1YWwgZnVuZCBvdmVyIHRoZSBsYXN0IHllYXI/IERvZXMgdGhpcyByYXRpbyBzZWVtIGhpZ2ggdG8geW91PyoKClRoZSBuZXQgZXhwZW5zZSByYXRpbyB3YXMgMC4wMTUlLiBDb21wYXJlIHRvIHRoZSBhdmVyYWdlIG11dHVhbCBmdW5kLCB3ZSB0aGluayB0aGF0IGlzIHF1aXRlIGNoZWFwLgoKKipTZWN1cml0aWVzIGZpcm1zKioKCkZvciB0aGUgc2VjdXJpdGllcyBmaXJtIHRoYXQgeW91IHNlbGVjdGVkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRlcm0sIHVzZSBpdHMgYW5udWFsIHJlcG9ydCBvciBhbnkgb3RoZXIgcmVsYXRlZCBpbmZvcm1hdGlvbiB0byBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuCgotICAgKldoYXQgYXJlIHRoZSBtYWluIHR5cGVzIG9mIGJ1c2luZXNzIGNvbmR1Y3RlZCBieSB0aGUgc2VjdXJpdGllcyBmaXJtPyoKClRlc2xhIG9wZXJhdGVzIHByaW1hcmlseSBpbiB0d28gc2VnbWVudHM6CgoxLiAgQXV0b21vdGl2ZTogVGhpcyBpbmNsdWRlcyB0aGUgZGVzaWduLCBkZXZlbG9wbWVudCwgbWFudWZhY3R1cmluZywgc2FsZXMsIGFuZCBsZWFzaW5nIG9mIGhpZ2gtcGVyZm9ybWFuY2UgZnVsbHkgZWxlY3RyaWMgdmVoaWNsZXMgKEVWcykuIFRoZSBhdXRvbW90aXZlIHNlZ21lbnQgYWxzbyBlbmNvbXBhc3NlcyB0aGUgc2FsZSBvZiBhdXRvbW90aXZlIHJlZ3VsYXRvcnkgY3JlZGl0cyBhbmQgYSB2YXJpZXR5IG9mIHNlcnZpY2VzIHN1Y2ggYXMgdXNlZCB2ZWhpY2xlIHNhbGVzLCBub24td2FycmFudHkgYWZ0ZXItc2FsZXMgc2VydmljZXMsIGJvZHkgc2hvcCBzZXJ2aWNlcywgcGFpZCBTdXBlcmNoYXJnaW5nLCB2ZWhpY2xlIGluc3VyYW5jZSByZXZlbnVlLCBhbmQgcmV0YWlsIG1lcmNoYW5kaXNlLgoKMi4gIEVuZXJneSBHZW5lcmF0aW9uIGFuZCBTdG9yYWdlOiBUaGlzIHNlZ21lbnQgaW52b2x2ZXMgdGhlIGRlc2lnbiwgbWFudWZhY3R1cmUsIGluc3RhbGxhdGlvbiwgc2FsZXMsIGFuZCBsZWFzaW5nIG9mIHNvbGFyIGVuZXJneSBnZW5lcmF0aW9uIHN5c3RlbXMgYW5kIGVuZXJneSBzdG9yYWdlIHByb2R1Y3RzLiBLZXkgb2ZmZXJpbmdzIGluY2x1ZGUgdGhlIFBvd2Vyd2FsbCBmb3IgcmVzaWRlbnRpYWwgdXNlIGFuZCB0aGUgTWVnYXBhY2sgZm9yIGNvbW1lcmNpYWwgYW5kIHV0aWxpdHktc2NhbGUgYXBwbGljYXRpb25zLiBUZXNsYSBhbHNvIHNlbGxzIHNvbGFyIGVuZXJneSBzeXN0ZW1zIHRocm91Z2ggdmFyaW91cyBhcnJhbmdlbWVudHMsIGluY2x1ZGluZyBwb3dlciBwdXJjaGFzZSBhZ3JlZW1lbnRzLgoKLSAgICpTdW1tYXJpemUgYW55IHN0YXRlbWVudHMgbWFkZSBieSB0aGUgc2VjdXJpdGllcyBmaXJtIGluIGl0cyBhbm51YWwgcmVwb3J0IGFib3V0IGhvdyBpdCBtYXkgYmUgYWZmZWN0ZWQgYnkgZXhpc3Rpbmcgb3IgcG90ZW50aWFsIHJlZ3VsYXRpb25zLioKCkluIGl0cyBhbm51YWwgcmVwb3J0LCBUZXNsYSBhY2tub3dsZWRnZXMgdGhhdCBpdCBvcGVyYXRlcyBpbiBhIGhpZ2hseSByZWd1bGF0ZWQgZW52aXJvbm1lbnQgdGhhdCBjYW4gc2lnbmlmaWNhbnRseSBhZmZlY3QgaXRzIGJ1c2luZXNzLiBUaGUgZmlybSBub3RlcyB0aGF0IGV4aXN0aW5nIHJlZ3VsYXRpb25zIHJlZ2FyZGluZyB2ZWhpY2xlIGVtaXNzaW9ucyBhbmQgc2FmZXR5IHN0YW5kYXJkcyBjb3VsZCBpbXBvc2UgY29zdHMgb3Igb3BlcmF0aW9uYWwgcmVzdHJpY3Rpb25zLiBBZGRpdGlvbmFsbHksIHBvdGVudGlhbCBmdXR1cmUgcmVndWxhdGlvbnMgYWltZWQgYXQgZWxlY3RyaWMgdmVoaWNsZXMgb3IgcmVuZXdhYmxlIGVuZXJneSBjb3VsZCBpbXBhY3QgVGVzbGEncyBvcGVyYXRpb25hbCBmbGV4aWJpbGl0eSBhbmQgcHJvZml0YWJpbGl0eS4gVGhlIGNvbXBhbnkgZW1waGFzaXplcyBpdHMgY29tbWl0bWVudCB0byBjb21wbGlhbmNlIGJ1dCByZWNvZ25pemVzIHRoYXQgY2hhbmdlcyBpbiByZWd1bGF0aW9ucyBtYXkgcG9zZSByaXNrcyB0byBpdHMgZ3Jvd3RoIGFuZCBtYXJrZXQgc3RyYXRlZ3kuCgotICAgKkRlc2NyaWJlIHRoZSByZWNlbnQgcGVyZm9ybWFuY2Ugb2YgdGhlIHNlY3VyaXRpZXMgZmlybSwgYW5kIGV4cGxhaW4gd2h5IHRoZSBwZXJmb3JtYW5jZSBoYXMgYmVlbiBmYXZvcmFibGUgb3IgdW5mYXZvcmFibGUuKgoKVGVzbGEncyByZWNlbnQgcGVyZm9ybWFuY2UgaGFzIGJlZW4gY2hhcmFjdGVyaXplZCBieSBzdHJvbmcgc2FsZXMgZ3Jvd3RoIGRyaXZlbiBieSBpbmNyZWFzZWQgZGVtYW5kIGZvciBlbGVjdHJpYyB2ZWhpY2xlcyBhbmQgYWR2YW5jZW1lbnRzIGluIHByb2R1Y3Rpb24gY2FwYWJpbGl0aWVzLiBUaGUgbGF1bmNoIG9mIG5ldyBtb2RlbHMsIGluY2x1ZGluZyB0aGUgQ3liZXJ0cnVjaywgaGFzIGFsc28gY29udHJpYnV0ZWQgcG9zaXRpdmVseSB0byBpdHMgbWFya2V0IHByZXNlbmNlLiBIb3dldmVyLCBjaGFsbGVuZ2VzIHN1Y2ggYXMgc3VwcGx5IGNoYWluIGRpc3J1cHRpb25zIGFuZCBjb21wZXRpdGlvbiBpbiB0aGUgRVYgbWFya2V0IGhhdmUgY3JlYXRlZCBzb21lIGhlYWR3aW5kcy5UaGUgZmF2b3JhYmxlIHBlcmZvcm1hbmNlIGlzIGF0dHJpYnV0ZWQgdG86CgoxLiAgSW5jcmVhc2VkIFByb2R1Y3Rpb24gQ2FwYWNpdHk6IEV4cGFuc2lvbiBvZiBtYW51ZmFjdHVyaW5nIGZhY2lsaXRpZXMgaGFzIGFsbG93ZWQgVGVzbGEgdG8gbWVldCByaXNpbmcgZGVtYW5kLgoKMi4gIElubm92YXRpb246IENvbnRpbnVvdXMgaW1wcm92ZW1lbnRzIGluIHRlY2hub2xvZ3kgYW5kIHByb2R1Y3Qgb2ZmZXJpbmdzIGhhdmUgc3RyZW5ndGhlbmVkIGN1c3RvbWVyIGludGVyZXN0LgoKMy4gIE1hcmtldCBQb3NpdGlvbmluZzogVGVzbGEncyBlc3RhYmxpc2hlZCBicmFuZCByZXB1dGF0aW9uIGFzIGEgbGVhZGVyIGluIHRoZSBFViBzcGFjZSBlbmhhbmNlcyBpdHMgY29tcGV0aXRpdmUgZWRnZS4KCkNvbnZlcnNlbHksIHVuZmF2b3JhYmxlIGZhY3RvcnMgaW5jbHVkZToKCjEuICBSZWd1bGF0b3J5IENoYWxsZW5nZXM6IFBvdGVudGlhbCBjaGFuZ2VzIGluIHJlZ3VsYXRpb25zIGNvdWxkIGltcGFjdCBvcGVyYXRpb25hbCBjb3N0cy4KCjIuICBDb21wZXRpdGl2ZSBMYW5kc2NhcGU6IEdyb3dpbmcgY29tcGV0aXRpb24gZnJvbSBvdGhlciBhdXRvbWFrZXJzIGVudGVyaW5nIHRoZSBFViBtYXJrZXQgbWF5IGFmZmVjdCBUZXNsYSdzIG1hcmtldCBzaGFyZS4KCiMjIEw2IEVxdWl0eQoKV2Ugd2lsbCBleHBsb3JlIHRoZSBHb3Jkb24gR3Jvd3RoIE1vZGVsCgpgYGB7cn0KIyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgc3RvY2sgdmFsdWUgdXNpbmcgR29yZG9uIEdyb3d0aCBNb2RlbApnb3Jkb25fZ3Jvd3RoX21vZGVsIDwtIGZ1bmN0aW9uKGRpdmlkZW5kLCBjb3N0X29mX2VxdWl0eSwgZ3Jvd3RoX3JhdGUpIHsKICB2YWx1ZSA8LSBkaXZpZGVuZCAvIChjb3N0X29mX2VxdWl0eSAtIGdyb3d0aF9yYXRlKQogIHJldHVybih2YWx1ZSkKfQoKY29tcGFuaWVzIDwtIGRhdGEuZnJhbWUoCiAgbmFtZSA9IGMoIlRlc2xhIiwgIkFwcGxlIiwgIk1pY3Jvc29mdCIsICJUb3lvdGEiLCAiU2Ftc3VuZyIsICJWb2xrc3dhZ2VuIiksCiAgY291bnRyeSA9IGMoIlVTQSIsICJVU0EiLCAiVVNBIiwgIkphcGFuIiwgIlNvdXRoIEtvcmVhIiwgIkdlcm1hbnkiKSwKICBkaXZpZGVuZCA9IGMoMCwgMC45MiwgMi43MiwgMi4zMCwgMS45NywgNy41NiksCiAgY29zdF9vZl9lcXVpdHkgPSBjKDAuMDgsIDAuMDcsIDAuMDY1LCAwLjA2LCAwLjA3LCAwLjA3NSksCiAgZ3Jvd3RoX3JhdGUgPSBjKDAuMjAsIDAuMTAsIDAuMDgsIDAuMDMsIDAuMDUsIDAuMDIpCikKCmNvbXBhbmllcyRzdG9ja192YWx1ZSA8LSBtYXBwbHkoZ29yZG9uX2dyb3d0aF9tb2RlbCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tcGFuaWVzJGRpdmlkZW5kLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYW5pZXMkY29zdF9vZl9lcXVpdHksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBhbmllcyRncm93dGhfcmF0ZSkKCnByaW50KGNvbXBhbmllcykKCiMgQ29tcGFyZSBVLlMuIGNvbXBhbmllcyB3aXRoIG5vbi1VLlMuIGNvbXBhbmllcwp1c19jb21wYW5pZXMgPC0gc3Vic2V0KGNvbXBhbmllcywgY291bnRyeSA9PSAiVVNBIikKbm9uX3VzX2NvbXBhbmllcyA8LSBzdWJzZXQoY29tcGFuaWVzLCBjb3VudHJ5ICE9ICJVU0EiKQoKY2F0KCJcbkF2ZXJhZ2Ugc3RvY2sgdmFsdWUgZm9yIFUuUy4gY29tcGFuaWVzOiIsIG1lYW4odXNfY29tcGFuaWVzJHN0b2NrX3ZhbHVlKSkKY2F0KCJcbkF2ZXJhZ2Ugc3RvY2sgdmFsdWUgZm9yIG5vbi1VLlMuIGNvbXBhbmllczoiLCBtZWFuKG5vbl91c19jb21wYW5pZXMkc3RvY2tfdmFsdWUpKQoKIyBDcmVhdGUgYSBiYXIgcGxvdCB0byB2aXN1YWxpemUgdGhlIGNvbXBhcmlzb24KYmFycGxvdChjb21wYW5pZXMkc3RvY2tfdmFsdWUsIAogICAgICAgIG5hbWVzLmFyZyA9IGNvbXBhbmllcyRuYW1lLCAKICAgICAgICBjb2wgPSBpZmVsc2UoY29tcGFuaWVzJGNvdW50cnkgPT0gIlVTQSIsICJibHVlIiwgInJlZCIpLAogICAgICAgIG1haW4gPSAiU3RvY2sgVmFsdWVzIENvbXBhcmlzb24iLAogICAgICAgIHlsYWIgPSAiU3RvY2sgVmFsdWUiLAogICAgICAgIGxhcyA9IDIpCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSBjKCJVU0EiLCAiTm9uLVVTQSIpLCBmaWxsID0gYygiYmx1ZSIsICJyZWQiKSkKCmBgYAoKVGhlIGF2ZXJhZ2Ugc3RvY2sgdmFsdWUgZm9yIFUuUy4gY29tcGFuaWVzIChleGNsdWRpbmcgVGVzbGEpIGlzIGxpa2VseSB0byBiZSBsb3dlciB0aGFuIG5vbi1VLlMuIGNvbXBhbmllcyBpbiB0aGlzIHNhbXBsZSwgcHJpbWFyaWx5IGR1ZSB0byBsb3dlciBkaXZpZGVuZCBwYXltZW50cyBhbmQgaGlnaGVyIGdyb3d0aCByYXRlcy4KClNvbWUgaW1wb3JhbnQgPG5vdGVzOlRoZT4gR29yZG9uIEdyb3d0aCBNb2RlbCBhc3N1bWVzIGEgY29uc3RhbnQgZ3Jvd3RoIHJhdGUsIHdoaWNoIG1heSBub3QgYmUgcmVhbGlzdGljIGZvciBtYW55IGNvbXBhbmllcywgZXNwZWNpYWxseSBpbiB0aGUgdGVjaCBzZWN0b3MuIEFsc28sIGNvbXBhbmllcyBsaWtlIFRlc2xhLCB3aGljaCBkb24ndCBwYXkgZGl2aWRlbmRzLCBjYW5ub3QgYmUgdmFsdWVkIHVzaW5nIHRoaXMgbW9kZWwsIGhpZ2hsaWdodGluZyBpdHMgbGltaXRhdGlvbnMgZm9yIGdyb3d0aCBzdG9ja3MKCiMjIEw3IEZpeGVkIGluY29tZQoKKipDb21wYXJpbmcgeWllbGRzIGFtb25nIHNlY3VyaXRpZXMqKgoKLSAgICpXaGF0IGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHlpZWxkIG9uIGNvcnBvcmF0ZSBoaWdoLXF1YWxpdHkgYm9uZHMgYW5kIHRoZSB5aWVsZCBvbiBUcmVhc3VyeSBib25kcyBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybT8gRXhwbGFpbiB3aHkgZG9lcyB0aGUgZGlmZmVyZW5jZSBleGlzdD8qCgpXZSBsb29rIGZvciB0aGUgdGhlIGRhdGEgIk1vb2R5J3MgU2Vhc29uZWQgQWFhIENvcnBvcmF0ZSBCb25kIFlpZWxkIFJlbGF0aXZlIHRvIFlpZWxkIG9uIDEwLVllYXIgVHJlYXN1cnkgQ29uc3RhbnQgTWF0dXJpdHkiIG9uIHRoZSBGUkVEIHdlYnNpdGUuCgpgYGB7cn0KCmRpZmYxIDwtIGJhc2ljX3BhcmFtJEVvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiQ29ycG9yYXRlIChNYXN0ZXIpIGJvbmQgeWllbGQiXSAtIGJhc2ljX3BhcmFtJEVvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiVHJlYXN1cnkgbG9uZy10ZXJtIGJvbmQgeWllbGQiXQoKCmNhdCgiVGhlIGRpZmZlcmVuY2UgaXMiLCAgZGlmZjEqMTAwLCAiYmFzaWMgcG9pbnRzLiIpCgpgYGAKClRoZSBiaWcgZGlmZmVyZW5jZSBiZXR3ZWVuIHlpZWxkIG9uIGNvcnBvcmF0ZSBoaWdoLXF1YWxpdHkgYm9uZHMgYW5kIHRoZSB5aWVsZCBvbiBUcmVhc3VyeSBib25kcyBpcyB0aGUgcmlzay4gVHJlYXN1cnkgYm9uZHMgYXJlIGFib3V0IGFzIHJpc2stZnJlZSBhcyB0aGV5IGdldCBhcyB0aGV5IGFyZSBvcGVyYXRlZCBieSB0aGUgZ292ZXJubWVudCwgYnV0IGNvcnBvcmF0ZSBib25kcywgd2hpbGUgYWxzbyByZXByZXNlbnRpbmcgYSBsb2FuLCByaXNrIGlzIGhpZ2hlciBiZWNhdXNlIHRoZSBpc3N1ZXIgY2FuIG5vdCBrZWVwIGl0cyBwcm9taXNlLiBUaGlzIGlzIGR1ZSB0byB0aGUgY3JlZGl0IHNwcmVhZCwgd2hlcmVieSBpbnZlc3RvcnMgYXJlIGNvbXBlbnNhdGVkIHdpdGggaGlnaGVyIHlpZWxkcyB0byBrZWVwIHRoZW0gaW52ZXN0ZWQsIGhlbmNlIGhpZ2gtcXVhbGl0eSBjb3Jwb3JhdGUgYm9uZHMgaGF2ZSB0byBvZmZlciBhIGdyZWF0ZXIgcmV0dXJuIGZvciB0aGUgaGlnaGVyIHJpc2suCgotICAgKldoYXQgaXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgeWllbGQgb24gbG9uZy10ZXJtIFRyZWFzdXJ5IGJvbmRzIGFuZCB0aGUgeWllbGQgb24gbG9uZy10ZXJtIG11bmljaXBhbCBib25kcyBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybT8gRXhwbGFpbiB3aHkgZG9lcyB0aGUgZGlmZmVyZW5jZSBleGlzdD8qCgpUaGUgbWFpbiBkaWZmZXJlbmNlIGlzIHRoYXQgbG9uZy10ZXJtIHRyZWFzdXJ5IGJvbmRzIHlpZWxkIG1vcmUgdGhhbiB0aGUgbG9uZy10ZXJtIG11bmljaXBhbCBib25kcywgbWFpbmx5IGJlY2F1c2Ugb2YgdGhlIHRheGVzIGFzc29jaWF0ZWQgb24gdGhlIGludGVyZXN0IG9uIG11bmljaXBhbCBib25kcy4gQWNjb3JkaW5nbHksIHRoZSBkaWZmZXJlbmNlIGlzIGR1ZSB0byB0aGUgdGF4IGFzcGVjdHMgYW5kIHRoZSBjcmVkaXQgcmlzay4gQ29ycG9yYXRlIGJvbmRzIG9mZmVycyBiZXR0ZXIgeWllbGRzIHRvIG9mZnNldCB0aGUgcmlzaywgYnV0IG11bmljaXBhbCBib25kcyBvZmZlciBiZXR0ZXIgdGF4IGFkdmFuY2VzLgoKYGBge3J9CmRpZmYyIDwtIGJhc2ljX3BhcmFtJEVvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiVGF4LWV4ZW1wdCAoN+KAkzEyLXllYXIpIGJvbmQgeWllbGQiXSAtIGJhc2ljX3BhcmFtJEVvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiVHJlYXN1cnkgbG9uZy10ZXJtIGJvbmQgeWllbGQiXQoKCmNhdCgiVGhlIGRpZmZlcmVuY2UgaXMiLCAgZGlmZjIqMTAwLCAiYmFzaWMgcG9pbnRzLiIpCgpgYGAKCioqQXNzZXNzaW5nIHRoZSBmb3JlY2FzdGluZyBhYmlsaXR5IG9mIHRoZSB5aWVsZCBjdXJ2ZSoqCgotICAgKldoYXQgd2FzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIDI2LXdlZWsgVC1iaWxsIHlpZWxkIGFuZCB0aGUgMTMtd2VlayBULWJpbGwgeWllbGQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2Nob29sIHRlcm0/KgoKYGBge3J9CmRpZmYzIDwtIGJhc2ljX3BhcmFtJEJvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiVHJlYXN1cnkgYmlsbCByYXRlICg2LW1vbnRoKSJdIC0gYmFzaWNfcGFyYW0kQm9UW2Jhc2ljX3BhcmFtJERlc2NyaXB0aW9uID09ICJUcmVhc3VyeSBiaWxsIHJhdGUgKDMtbW9udGgpIl0KCgpjYXQoIlRoZSBkaWZmZXJlbmNlIGlzIiwgIGRpZmYzKjEwMCwgImJhc2ljIHBvaW50cy4iKQoKYGBgCgotICAgKkRvZXMgdGhpcyBpbXBseSB0aGF0IHRoZSB5aWVsZCBjdXJ2ZSBoYWQgYW4gdXB3YXJkIG9yIGRvd253YXJkIHNsb3BlIGF0IHRoYXQgdGltZT8qCgpTaW5jZSB0aGUgMjYtd2VlayBULWJpbGwgeWllbGQgaXMgbG93ZXIgdGhhbiB0aGUgMTMtd2VlayBULWJpbGwgeWllbGQsIHRoaXMgaW1wbGllcyBhIGRvd253YXJkIHNsb3BlLCB0aGF0IGlzIGFuIGludmVydGVkIHlpZWxkIGN1cnZlLgoKLSAgICpBc3N1bWluZyB0aGF0IHRoaXMgc2xvcGUgY2FuIGJlIHByaW1hcmlseSBhdHRyaWJ1dGVkIHRvIGV4cGVjdGF0aW9ucyB0aGVvcnksIGRpZCB0aGUgZGlyZWN0aW9uIG9mIHRoZSBzbG9wZSBpbmRpY2F0ZSB0aGF0IHRoZSBtYXJrZXQgZXhwZWN0ZWQgaGlnaGVyIG9yIGxvd2VyIGludGVyZXN0IHJhdGVzIGluIHRoZSBmdXR1cmU/KgoKVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgaW52ZXN0b3JzIGV4cGVjdHMgbG93ZXIgaW50ZXJlc3QgcmF0ZXMgaW4gdGhlIGZ1dHVyZS4KCi0gICAqRGlkIGludGVyZXN0IHJhdGVzIG1vdmUgaW4gdGhhdCBkaXJlY3Rpb24gb3ZlciB0aGUgc2Nob29sIHRlcm0/KgoKYGBge3J9Cgp0YjMgPC0gZ2V0U3ltYm9scygiRFRCMyIsIGZyb209Qm9ULCB0bz1Fb1QrMixzcmM9IkZSRUQiLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQpjaGFydFNlcmllcyh0YjMsdGhlbWU9IndoaXRlIikKCmBgYAoKV2Ugc2VlIHRoYXQgdGhlbSAxMy1iaWxsIHJhdGUgd2VudCBkb3duIGluIHRoZSBkdXJpbmcgdGhlIHBlcmlvZCBvZiBhbmFseXNpcy4gU28sIHllcyB0aGUgcmF0ZXMgbW92ZSBpbiB0aGUgZGlyZWN0aW9uIHRoYXQgd2FzIGV4cGVjdGVkLgoKKipFeHBsYWluaW5nIHNoaWZ0cyBpbiB0aGUgeWllbGQgY3VydmUgb3ZlciB0aW1lKioKCi0gICAqV2hhdCB3YXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbG9uZy10ZXJtIFRyZWFzdXJ5IGJvbmQgeWllbGQgYW5kIHRoZSAxMy13ZWVrIFQtYmlsbCB5aWVsZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybT8qCgpgYGB7cn0KZGlmZjQgPC0gYmFzaWNfcGFyYW0kQm9UW2Jhc2ljX3BhcmFtJERlc2NyaXB0aW9uID09ICJUcmVhc3VyeSBsb25nLXRlcm0gYm9uZCB5aWVsZCJdIC0gYmFzaWNfcGFyYW0kQm9UW2Jhc2ljX3BhcmFtJERlc2NyaXB0aW9uID09ICJUcmVhc3VyeSBiaWxsIHJhdGUgKDMtbW9udGgpIl0KCgpjYXQoIlRoZSBkaWZmZXJlbmNlIGlzIiwgIGRpZmY0KjEwMCwgImJhc2ljIHBvaW50cy4iKQoKYGBgCgpBdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgeWVhciwgdGhlIHlpZWxkIG9uIHRoZSBsb25nLXRlcm0gVHJlYXN1cnkgYm9uZCB3YXMgbG93ZXIgdGhhbiB0aGF0IG9mIHRoZSAxMy13ZWVrIFQtYmlsbC4KCi0gICAqV2hhdCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBsb25nLXRlcm0gVHJlYXN1cnkgYm9uZCB5aWVsZCBhbmQgdGhlIDEzLXdlZWsgVC1iaWxsIHlpZWxkIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtPyoKCmBgYHtyfQpkaWZmNSA8LSBiYXNpY19wYXJhbSRFb1RbYmFzaWNfcGFyYW0kRGVzY3JpcHRpb24gPT0gIlRyZWFzdXJ5IGxvbmctdGVybSBib25kIHlpZWxkIl0gLSBiYXNpY19wYXJhbSRFb1RbYmFzaWNfcGFyYW0kRGVzY3JpcHRpb24gPT0gIlRyZWFzdXJ5IGJpbGwgcmF0ZSAoMy1tb250aCkiXQoKCmNhdCgiVGhlIGRpZmZlcmVuY2UgaXMiLCAgZGlmZjUqMTAwLCAiYmFzaWMgcG9pbnRzLiIpCgpgYGAKCkJ5IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtLCB0aGlzIGRpZmZlcmVudGlhbCBoYXMgc2hyaW5rLgoKLSAgICpHaXZlbiB5b3VyIGFuc3dlcnMgdG8gdGhlIHR3byBwcmV2aW91cyBxdWVzdGlvbnMsIGRlc2NyaWJlIGhvdyB0aGUgeWllbGQgY3VydmUgY2hhbmdlZCBvdmVyIHRoZSBzY2hvb2wgdGVybS4gRXhwbGFpbiB0aGUgY2hhbmdlcyBpbiBleHBlY3RhdGlvbnMgYWJvdXQgZnV0dXJlIGludGVyZXN0IHJhdGVzIHRoYXQgYXJlIGltcGxpZWQgYnkgdGhlIHNoaWZ0IGluIHRoZSB5aWVsZCBjdXJ2ZSBvdmVyIHRoZSBzY2hvb2wgdGVybS4qCgpUaGUgeWllbGQgY3VydmUgYXQgdGhlIEVvVCB3YXMgbGVzcyBpbnZlcnRlZCB0aGFuIHRoZSBiZWdpbm5pbmcuIFdoaWxlIHRoZSBjdXJ2ZSByZW1haW5zIGludmVydGVkLCBtYXJrZXQgZXhwZWN0YXRpb25zIGZvciBpbnRlcmVzdCByYXRlIGN1dHMgaGF2ZSBzb2Z0ZW5lZCwgaW5kaWNhdGluZyBhIGxlc3MgYWdncmVzc2l2ZSBvdXRsb29rIGZvciBtb25ldGFyeSBlYXNpbmcgdGhhbiBhdCB0aGUgc3RhcnQgb2YgdGhlIHRlcm0uCgotICAgKkRpZCB0aGUgRmVkIGNoYW5nZSB0aGUgZmVkZXJhbCBmdW5kcyByYXRlIG92ZXIgdGhlIHNjaG9vbCB0ZXJtPyoKCmBgYHtyfQoKZmZyIDwtIGdldFN5bWJvbHMoIkZFREZVTkRTIiwgZnJvbT1Cb1QsIHRvPUVvVCsyLHNyYz0iRlJFRCIsIGF1dG8uYXNzaWduID0gRkFMU0UpCmNoYXJ0U2VyaWVzKGZmcix0aGVtZT0id2hpdGUiKQoKCmBgYAoKYGBge3J9CnRhaWwoZmZyKQoKYGBgCgpUaGVyZSB3ZXJlIHR3byBjdXRzIGR1cmluZyB0aGUgcGVyaW9kLiBPbmUgd2FzIGEgY3V0IG9mIDUwIGJhc2lzIHBvaW50cyBpbiB0aGUgU2VwdGVtYmVyIG1lZXRpbmcsIGFuZCB0aGUgb3RoZXIgb25lIG9mIDI1IHBvaW50cyBpbiB0aGUgTm92ZW1iZXIgbWVldGluZy4KCi0gICAqRG8geW91IHRoaW5rIHRoZSBtb3ZlbWVudHMgaW4gaW50ZXJlc3QgcmF0ZXMgb3ZlciB0aGUgc2Nob29sIHRlcm0gd2VyZSBjYXVzZWQgYnkgdGhlIEZlZOKAmXMgbW9uZXRhcnkgcG9saWN5PyBFeHBsYWluLioKClllcy4gU3BlY2lhbGx5IHRoZSBpbnZlc3RvcnMgcGF5cyBhdHRlbnRpb24gdG8gUG93ZWxsJ3Mgc3BlZWNoIGFmdGVyIHRoZSBtZWV0aW5nLiBCdXQsIGFsc28gdGhleSB0YWtlcyBpbnRvIGFjY291bnQgdGhlIGRhdGEgb24gdGhlIHdlbGwga25vd24gbGVhZGluZyBlY29ub21pYyBpbmRpY2F0b3JzLiBUaGF0J3Mgd2h5IHRoZXkgdGhpbmsgdGhhdCB0aGUgRkVEIGNhbiBzdGlsbCBsb3dlciBtb3JlIGludGVyZXN0IHJhdGVzLgoKKipNZWFzdXJpbmcgYW5kIGV4cGxhaW5pbmcgcHJlbWl1bXMgb24gbW9uZXkgbWFya2V0IHNlY3VyaXRpZXMqKgoKLSAgICpXaGF0IGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHlpZWxkIG9uIDkwLWRheSBjb21tZXJjaWFsIHBhcGVyIGFuZCB0aGUgeWllbGQgb24gMTMtd2VlayBULWJpbGxzIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtPyBFeHBsYWluIHdoeSB0aGlzIHByZW1pdW0gZXhpc3RzLioKCmBgYHtyfQoKZGlmZjYgPC0gYmFzaWNfcGFyYW0kQm9UW2Jhc2ljX3BhcmFtJERlc2NyaXB0aW9uID09ICJDb21tZXJjaWFsIHBhcGVyIHJhdGUgKDkwIGRheXMpIl0gLSBiYXNpY19wYXJhbSRCb1RbYmFzaWNfcGFyYW0kRGVzY3JpcHRpb24gPT0gIlRyZWFzdXJ5IGJpbGwgcmF0ZSAoMy1tb250aCkiXQoKCmNhdCgiVGhlIGRpZmZlcmVuY2UgaXMiLCAgZGlmZjYqMTAwLCAiYmFzaWMgcG9pbnRzLiIpCgpgYGAKCklzIGdyZWF0ZXIgYmVjYXVzZSB0aGVyZSBleGlzdCBhIGhpZ2hlciBjcmVkaXQgYW5kIGRlZmF1bHQgcmlzaywgaXQgaXMgd2lkZWx5IGJlbGlldmVkIHRoYXQgdGhlIFVuaXRlZCBTdGF0ZXMgZ292ZXJubWVudCB3aWxsIGFsd2F5cyBtZWV0IGl0cyBmaW5hbmNpYWwgb2JsaWdhdGlvbnMgYW5kIGlzIHVubGlrZWx5IHRvIGRlZmF1bHQuCgotICAgKkNvbXBhcmUgdGhlIHByZW1pdW0gb24gdGhlIDkwLWRheSBjb21tZXJjaWFsIHBhcGVyIHlpZWxkIChyZWxhdGl2ZSB0byB0aGUgMTMtd2VlayBULWJpbGwgeWllbGQpIHRoYXQgZXhpc3RzIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtIHRvIHRoZSBwcmVtaXVtIHRoYXQgZXhpc3RlZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSB0ZXJtLiBFeHBsYWluIHdoeSB0aGUgcHJlbWl1bSBtYXkgaGF2ZSBjaGFuZ2VkIG92ZXIgdGhlIHNjaG9vbCB0ZXJtLioKCmBgYHtyfQpkaWZmNyA8LSBiYXNpY19wYXJhbSRFb1RbYmFzaWNfcGFyYW0kRGVzY3JpcHRpb24gPT0gIkNvbW1lcmNpYWwgcGFwZXIgcmF0ZSAoOTAgZGF5cykiXSAtIGJhc2ljX3BhcmFtJEVvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiVHJlYXN1cnkgYmlsbCByYXRlICgzLW1vbnRoKSJdCgoKY2F0KCJUaGUgZGlmZmVyZW5jZSBpcyIsICBkaWZmNyoxMDAsICJiYXNpYyBwb2ludHMuIikKCgpgYGAKClRoZSBncmVhdGVyIGRpZmZlcmVuY2UgbWF5IGluZGljYXRlIHRoYXQgaW52ZXN0b3JzIGFudGljaXBhdGUgYSBkZXRlcmlvcmF0aW9uIGluIHRoZSBvdmVyYWxsIGhlYWx0aCBvZiBidXNpbmVzc2VzLiBUaGV5IHRoaW5rIHRoYXQgdGhlIHJpc2sgb2YgaGF2aW5nIGEgY29tbWVyY2lhbCBwYXBlciBpcyBncmVhdGVyIChkdWUgdG8gaGlnaGVyIGNyZWRpdCByaXNrKSwgdGh1cyBhIHdpZGVyIHlpZWxkIHNwcmVhZC4KCioqRXhwbGFpbmluZyBib25kIHByZW1pdW1zIGFuZCBwcmljZSBtb3ZlbWVudHMqKgoKLSAgICpXaGF0IGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHlpZWxkIG9uIGhpZ2gteWllbGQgY29ycG9yYXRlIGJvbmRzIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtIHZlcnN1cyB0aGUgeWllbGQgb24gaGlnaC1xdWFsaXR5IGNvcnBvcmF0ZSBib25kcyBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybT8qCgpgYGB7cn0KCmRpZmY4IDwtIGJhc2ljX3BhcmFtJEJvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiSGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZCB5aWVsZCJdIC0gYmFzaWNfcGFyYW0kQm9UW2Jhc2ljX3BhcmFtJERlc2NyaXB0aW9uID09ICJDb3Jwb3JhdGUgKE1hc3RlcikgYm9uZCB5aWVsZCJdCgoKY2F0KCJUaGUgZGlmZmVyZW5jZSBpcyIsICBkaWZmOCoxMDAsICJiYXNpYyBwb2ludHMuIikKCmBgYAoKLSAgICpDb21wYXJlIHRoZSBsb25nLXRlcm0gVHJlYXN1cnkgYm9uZCB5aWVsZCBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybSB0byB0aGUgbG9uZyB0ZXJtIFRyZWFzdXJ5IGJvbmQgeWllbGQgdGhhdCBleGlzdGVkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNjaG9vbCB0ZXJtLiBHaXZlbiB0aGUgZGlyZWN0aW9uIG9mIHRoaXMgY2hhbmdlLCBkaWQgcHJpY2VzIG9mIGxvbmctdGVybSBib25kcyByaXNlIG9yIGZhbGwgb3ZlciB0aGUgc2Nob29sIHRlcm0/KgoKYGBge3J9CmRpZmY5IDwtIGJhc2ljX3BhcmFtJEVvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiVHJlYXN1cnkgbG9uZy10ZXJtIGJvbmQgeWllbGQiXSAtIGJhc2ljX3BhcmFtJEJvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiVHJlYXN1cnkgbG9uZy10ZXJtIGJvbmQgeWllbGQiXQoKCmNhdCgiVGhlIGRpZmZlcmVuY2UgaXMiLCAgZGlmZjkqMTAwLCAiYmFzaWMgcG9pbnRzLiIpCgoKYGBgCgpTaW5jZSB0aGUgeWllbGQgaW5jcmVhc2UsIHRoYXQgbWVhbnMgdGhhdCB0aGUgcHJpY2UgZmFsbCBvdmVyIHRoZSBzY2hvb2wgdGVybS4KCi0gICAqQ29tcGFyZSB0aGUgY2hhbmdlIGluIHRoZSB5aWVsZHMgb2YgVHJlYXN1cnksIG11bmljaXBhbCwgYW5kIGNvcnBvcmF0ZSBib25kcyBvdmVyIHRoZSBzY2hvb2wgdGVybS4gRGlkIHRoZSB5aWVsZHMgb2YgYWxsIHRocmVlIHR5cGVzIG9mIHNlY3VyaXRpZXMgbW92ZSBpbiB0aGUgc2FtZSBkaXJlY3Rpb24gYW5kIGJ5IGFib3V0IHRoZSBzYW1lIGRlZ3JlZT8gRXhwbGFpbiB3aHkgeWllbGRzIG9mIGRpZmZlcmVudCB0eXBlcyBvZiBib25kcyBtb3ZlIHRvZ2V0aGVyLioKCmBgYHtyfQoKZGlmZl95aWVsZHMgPC0gc3Vic2V0KGJhc2ljX3BhcmFtLCBEZXNjcmlwdGlvbiAlaW4lIGMoIlRyZWFzdXJ5IGxvbmctdGVybSBib25kIHlpZWxkIiwgIkNvcnBvcmF0ZSAoTWFzdGVyKSBib25kIHlpZWxkIiwgIlRheC1leGVtcHQgKDfigJMxMi15ZWFyKSBib25kIHlpZWxkIikpCgpkaWZmX3lpZWxkcyREaWZmZXJlbmNlIDwtIGRpZmZfeWllbGRzJEVvVCAtIGRpZmZfeWllbGRzJEJvVCAKCnByaW50KGRpZmZfeWllbGRzKQoKCmBgYAoKVXN1YWxseSB3aGVuIHRoZSBGZWRlcmFsIFJlc2VydmUsIGNoYW5nZSBpbnRlcmVzdCByYXRlcywgaXQgYWZmZWN0cyBhbGwgYm9uZHMuIElmIHJhdGVzIGdvIHVwLCBuZXcgYm9uZHMgb2ZmZXIgaGlnaGVyIHJldHVybnMsIHNvIGV4aXN0aW5nIGJvbmRzIHdpdGggbG93ZXIgeWllbGRzIGJlY29tZSBsZXNzIGF0dHJhY3RpdmUsIGNhdXNpbmcgdGhlaXIgcHJpY2VzIHRvIGZhbGwgYW5kIHRoZWlyIHlpZWxkcyB0byByaXNlLiBIb3dldmVyLCBkZXNwaXRlIHRoZSBmZWQgY3V0cyBkdXJpbmcgdGhlIHNjaG9vbCB0ZXJtIHdlIHNlZSB0aGF0IHRoZSB0cmVhc3VyeSBhbmQgY29ycG9yYXRlIGJvbmRzIHdlbnQgdXAuCgotICAgKkNvbXBhcmUgdGhlIHByZW1pdW0gb24gaGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZHMgKHJlbGF0aXZlIHRvIFRyZWFzdXJ5IGJvbmRzKSBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybSB0byB0aGUgcHJlbWl1bSB0aGF0IGV4aXN0ZWQgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0uIERpZCB0aGUgcHJlbWl1bSBpbmNyZWFzZSBvciBkZWNyZWFzZT8gV2h5IHRoaXMgcHJlbWl1bSBjaGFuZ2VkIG92ZXIgdGhlIHNjaG9vbCB0ZXJtLioKCmBgYHtyfQojCmRpZmY5IDwtIGJhc2ljX3BhcmFtJEJvVFtiYXNpY19wYXJhbSREZXNjcmlwdGlvbiA9PSAiSGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZCB5aWVsZCJdIC0gYmFzaWNfcGFyYW0kQm9UW2Jhc2ljX3BhcmFtJERlc2NyaXB0aW9uID09ICJUcmVhc3VyeSBsb25nLXRlcm0gYm9uZCB5aWVsZCJdCgoKY2F0KCJUaGUgZGlmZmVyZW5jZSBpcyIsICBkaWZmOSoxMDAsICJiYXNpYyBwb2ludHMuIikKCgpgYGAKCmBgYHtyfQpkaWZmMTAgPC0gYmFzaWNfcGFyYW0kRW9UW2Jhc2ljX3BhcmFtJERlc2NyaXB0aW9uID09ICJIaWdoLXlpZWxkIGNvcnBvcmF0ZSBib25kIHlpZWxkIl0gLSBiYXNpY19wYXJhbSRFb1RbYmFzaWNfcGFyYW0kRGVzY3JpcHRpb24gPT0gIlRyZWFzdXJ5IGxvbmctdGVybSBib25kIHlpZWxkIl0KCgpjYXQoIlRoZSBkaWZmZXJlbmNlIGlzIiwgIGRpZmYxMCoxMDAsICJiYXNpYyBwb2ludHMuIikKCmBgYAoKYGBge3J9CgpkaWZmMTEgPC0gZGlmZjEwLWRpZmY5CgpwcmludChkaWZmMTEpCmBgYAoKVGhlIHByZW1pdW0gZGVjcmVhc2UuIEludmVzdG9ycyBtYXkgcGVyY2VpdmUgdGhhdCB0aGUgaGlnaCB5aWVsZCBib25kcyBhcmUgbGVzcyByaXNreSB0aGF0IGF0IHRoZSBiZWdpbm5pbmcuIE1heWJlIGF0IHRoZSBzdGFydCBvZiB0aGUgcGVyaW9kIHRoZXkgd2VyZSBkaXNjb3VudGluZyB0b28gbXVjaCByaXNrIG9uIHRoZXNlIGJvbmRzLgoKIyMgTDggKipQb3J0Zm9saW8gLSBNYXJrb3ZpdHoqKgoKLSAgICpSZXBsaWNhdGUgdGhlIGJhc2ljIGlkZWEgb2YgdGhlIHBvcnRmb2xpbyBjYXNlKgoKYGBge3J9CmxpYnJhcnkoUGVyZm9ybWFuY2VBbmFseXRpY3MpCgpgYGAKCmBgYHtyfQoKZ2V0U3ltYm9scyhjKCJOVkRBIiwgIlRTTEEiKSwgZnJvbSA9IEJvVCwgdG8gPSBFb1QpCgoKcmV0dXJucyA8LSBuYS5vbWl0KFJPQyhtZXJnZShOVkRBWyw2XSwgVFNMQVssNl0pKSkKCiMgRXhwZWN0ZWQgcmV0dXJucyBhbmQgY292YXJpYW5jZSBtYXRyaXgKbXUgPC0gY29sTWVhbnMocmV0dXJucykKY292X21hdCA8LSBjb3YocmV0dXJucykKCiMgUG9ydGZvbGlvIHdlaWdodHMKd2VpZ2h0cyA8LSBjKDAuNSwgMC41KSAgIyBFcXVhbCB3ZWlnaHRzIGZvciBBQVBMIGFuZCBNU0ZUCgojIFBvcnRmb2xpbyBleHBlY3RlZCByZXR1cm4gYW5kIHZhcmlhbmNlCnBvcnRmb2xpb19yZXR1cm4gPC0gc3VtKHdlaWdodHMgKiBtdSkKcG9ydGZvbGlvX3ZhcmlhbmNlIDwtIHQod2VpZ2h0cykgJSolIGNvdl9tYXQgJSolIHdlaWdodHMKCgpwcmludChwYXN0ZSgiUG9ydGZvbGlvIGV4cGVjdGVkIHJldHVybjoiLCByb3VuZChwb3J0Zm9saW9fcmV0dXJuICogMjUyLCAyKSwgIiUiKSkKcHJpbnQocGFzdGUoIlBvcnRmb2xpbyBhbm51YWxpemVkIHZvbGF0aWxpdHk6Iiwgcm91bmQoc3FydChwb3J0Zm9saW9fdmFyaWFuY2UgKiAyNTIpICogMTAwLCAyKSwgIiUiKSkKCgoKYGBgCgojIyBMOSAqKlBvcnRmb2xpbyAtIENBTVAqKgoKLSAgICpTdGF0ZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIENBTVAgYW5kIE1hcmtvd2l0eioKCk1hcmtvd2l0eiBoZWxwcyB3aXRoIHBvcnRmb2xpbyBjb25zdHJ1Y3Rpb24gYnkgZm9jdXNpbmcgb24gZGl2ZXJzaWZpY2F0aW9uIHRvIG9wdGltaXplIHJpc2sgYW5kIHJldHVybi4gSGUgaXMgbm90IGludGVyZXN0ZWQgaW4gZGV0ZXJtaW5pbmcgdGhlIHJldHVybiBvZiBhIHNwZWNpZmljIGFzc2V0OyBpbnN0ZWFkLCBoZSBhaW1zIHRvIGlkZW50aWZ5IHRoZSBvcHRpbWFsIHBvcnRmb2xpbyBiYXNlZCBvbiBoaXN0b3JpY2FsIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGFzc2V0cywgc2Vla2luZyB0aGUgYmVzdCByaXNrLXJldHVybiB0cmFkZS1vZmYuIE9uIHRoZSBvdGhlciBoYW5kLCBDQVBNIGhlbHBzIHdpdGggZXN0aW1hdGluZyB0aGUgZXhwZWN0ZWQgcmV0dXJuIG9mIGFuIGluZGl2aWR1YWwgYXNzZXQgYmFzZWQgb24gaXRzIHJpc2sgcmVsYXRpdmUgdG8gdGhlIG1hcmtldC4gSXQgZm9jdXNlcyB0byBlc3RpbWF0ZSB0aGUgc2Vuc2l0aXZlbmVzcyBvZiBhbiBhc3NldCB0byBtYXJrZXQgbW92ZW1lbnRzIChzeXN0ZW1hdGljIHJpc2spIGFuZCB1c2UgdGhhdCB0byBzdGF0ZSB3aGF0IHNob3VsZCBiZSB0aGUgcmV0dXJuIG9mIHRoZSBhc3NldCBpbiB0aGUgbG9uZyBydW4uCgpUaGlzIHNlY3Rpb24gY2FsY3VsYXRlcyB0aGUgQmV0YSBhbmQgRXhwZWN0ZWQgUmV0dXJuIGZvciBBcHBsZSAoQUFQTCkgdXNpbmcgdGhlIENBUE0gZm9ybXVsYS4KCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQoKc3RhcnRfZGF0ZSA8LSBCb1QKZW5kX2RhdGUgPC0gRW9UCgpzdG9ja19zeW1ib2wgPC0gIkFBUEwiCm1hcmtldF9zeW1ib2wgPC0gIl5HU1BDIgpnZXRTeW1ib2xzKGMoc3RvY2tfc3ltYm9sLCBtYXJrZXRfc3ltYm9sKSwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUsIHNyYyA9ICJ5YWhvbyIpCgpzdG9ja19wcmljZXMgPC0gQ2woQUFQTCkKbWFya2V0X3ByaWNlcyA8LSBDbChHU1BDKQpzdG9ja19yZXR1cm5zIDwtIGRhaWx5UmV0dXJuIChzdG9ja19wcmljZXMpCm1hcmtldF9yZXR1cm5zIDwtIGRhaWx5UmV0dXJuKG1hcmtldF9wcmljZXMpCgpyaXNrX2ZyZWVfcmF0ZSA8LSAwLjAzIC8gMjUyCmJldGEgPC0gY292KHN0b2NrX3JldHVybnMgLCBtYXJrZXRfcmV0dXJucykgLyB2YXIobWFya2V0X3JldHVybnMpCm1hcmtldF9wcmVtaXVtIDwtIG1lYW4obWFya2V0X3JldHVybnMpIC0gcmlza19mcmVlX3JhdGUKZXhwZWN0ZWRfcmV0dXJuIDwtIHJpc2tfZnJlZV9yYXRlICsgYmV0YSAqIG1hcmtldF9wcmVtaXVtCgpjYXQoIkJldGE6Iiwgcm91bmQoYmV0YSwgNCksICJcbiIpCmNhdCgiRXhwZWN0ZWQgUmV0dXJuIChDQVBNKToiLCByb3VuZChleHBlY3RlZF9yZXR1cm4gKiAxMDAsIDIpLCAiJVxuIikKCmBgYAoKIyMgKipMMTAgV0FDQyoqCgotICAgUmVwbGljYXRlIHRoZSBib29rIGNhc2Ugb2YgV0FDQwoKV2Ugd2lsbCB1c2UgdGhlIGJhc2ljIGZvcm11bGEgb2YgdGhlIFdBQ0MKCiQkCldBQ0M9IFxmcmFje0V9e0UrRH1yX2UrXGZyYWN7RH17RStEfXJfZCgxLXQpCiQkCgpXaGVyZToKCiRFJDogbWFya2V0IHZhbHVlIG9mIGVxdWl0eQoKJEQkOiBtYXJrZXQgdmFsdWUgb2YgZGVidAoKJHJfZSQ6IGNvc3Qgb2YgZXF1aXR5Cgokcl9kJDogY29zdCBvZiBkZWJ0CgokdCQ6IHRheCByYXRlCgpJbiB0aGlzIGNhc2UsIHdlIHdpbGwgY2FsY3VsYXRlIHRoZSBXQUNDIGZvciBUZXNsYS4KCmBgYHtyfQpnZXRTeW1ib2xzKCJUU0xBIikKCgoKb3VzdGFuZGluZ19zaGFyZXM8LSAzLjE5ZTkKbWFya2V0X2NhcCA8LSBUU0xBJFRTTEEuQWRqdXN0ZWRbRW9UXSAqIG91c3RhbmRpbmdfc2hhcmVzCm1hcmtldF92YWx1ZV9vZl9kZWJ0IDwtIDEyLjc4ZTkgICMgQWNjb3JkaW5nIHRvIFlhaG9vIEZpbmFuY2UKdGF4X3JhdGUgPC0gMC4yMiAgCmJldGEgPC0gMS42ICAjIFVubGV2ZXJhZ2VkIGJldGEgYWNjb3JkaW5nIHRvIFJldXRlcnMgKDIwMjQpCnJpc2tfZnJlZV9yYXRlIDwtIDAuMDQ3NSAgIyBmZWQgZnVuZHMgcmF0ZQptYXJrZXRfcmlza19wcmVtaXVtIDwtIDAuMDQgICMgbWFya2V0IHJpc2sgcHJlbWl1bSBhY2NvcmRpbmcgdG8gRGFtb2RhcmFuICgyMDI0KQoKCgpgYGAKCmBgYHtyfQojRGF0YSBmb3IgY2FsY3VsYXRpb24KY29zdF9vZl9kZWJ0IDwtIDAuMDQyNSAgCmNvc3Rfb2ZfZXF1aXR5IDwtIHJpc2tfZnJlZV9yYXRlICsgYmV0YSAqIG1hcmtldF9yaXNrX3ByZW1pdW0KdG90YWxfbWFya2V0X3ZhbHVlIDwtIG1hcmtldF9jYXAgKyBtYXJrZXRfdmFsdWVfb2ZfZGVidAp3ZWlnaHRfb2ZfZGVidCA8LSBtYXJrZXRfdmFsdWVfb2ZfZGVidCAvIHRvdGFsX21hcmtldF92YWx1ZQp3ZWlnaHRfb2ZfZXF1aXR5IDwtIG1hcmtldF9jYXAgLyB0b3RhbF9tYXJrZXRfdmFsdWUKCmNhdCgiY29zdCBvZiBkZWJ0OiIsY29zdF9vZl9kZWJ0LCAiXG4iKQpjYXQoImNvc3Qgb2YgZXF1aXR5Iixjb3N0X29mX2VxdWl0eSwgIlxuIikKY2F0KCJ3ZWlnaHQgb2YgZGVidDoiLHdlaWdodF9vZl9kZWJ0LCAiXG4iKQpjYXQoIndlaWdodCBvZiBlcXVpdHk6Iix3ZWlnaHRfb2ZfZXF1aXR5KQoKCmBgYAoKYGBge3J9CndhY2MgPC0gKHdlaWdodF9vZl9kZWJ0ICogY29zdF9vZl9kZWJ0ICogKDEgLSB0YXhfcmF0ZSkpICsgKHdlaWdodF9vZl9lcXVpdHkgKiBjb3N0X29mX2VxdWl0eSkKY2F0KCJXQUNDIGZvciBUZXNsYToiLCB3YWNjICogMTAwLCAiJSIpCgpgYGAKCiMjIEwxMSBEZXJpdmF0aXZlcwoKLSAgICpBc3N1bWUgdGhhdCB5b3UgcHVyY2hhc2VkIGFuIFMmUCA1MDAgZnV0dXJlcyBjb250cmFjdCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybSwgd2l0aCB0aGUgZmlyc3Qgc2V0dGxlbWVudCBkYXRlIGJleW9uZCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybS4gQWxzbyBhc3N1bWUgdGhhdCB5b3Ugc29sZCBhbiBTJlAgNTAwIGZ1dHVyZXMgY29udHJhY3Qgd2l0aCB0aGlzIHNhbWUgc2V0dGxlbWVudCBkYXRlIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtLiBHaXZlbiB0aGF0IHRoaXMgY29udHJhY3QgaGFzIGEgdmFsdWUgb2YgdGhlIGZ1dHVyZXMgcHJpY2UgdGltZXMgXCQyNTAsIGRldGVybWluZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBkb2xsYXIgdmFsdWUgb2YgdGhlIGNvbnRyYWN0IHlvdSBzb2xkIGFuZCB0aGUgZG9sbGFyIGFtb3VudCBvZiB0aGUgY29udHJhY3QgdGhhdCB5b3UgcHVyY2hhc2VkLioKCmBgYHtyfQpidXlfcHJpY2UgPC0gNDAwMApzZWxsX3ByaWNlIDwtIDQyMDAKY29udHJhY3RfbXVsdGlwbGllciA8LSAyNTAKaW5pdGFsX21hcmdpbiA8LSAwLjIwICogKGJ1eV9wcmljZSAqIGNvbnRyYWN0X211bHRpcGxpZXIpCm1vbnRoc19pbl90ZXJtIDwtIDUKCmdhaW5fbG9zcyA8LSAoc2VsbF9wcmljZSAtIGJ1eV9wcmljZSkgKiBjb250cmFjdF9tdWx0aXBsaWVyCnByaW50KGdhaW5fbG9zcykKYGBgCgotICAgKkFzc3VtZSB0aGF0IHlvdSBpbnZlc3RlZCBhbiBpbml0aWFsIG1hcmdpbiBvZiAyMCBwZXJjZW50IG9mIHRoZSBhbW91bnQgdGhhdCB5b3Ugd291bGQgb3dlIHRvIHB1cmNoYXNlIHRoZSBTJlAgNTAwIGluZGV4IGF0IHRoZSBzZXR0bGVtZW50IGRhdGUuIE1lYXN1cmUgeW91ciByZXR1cm4gZnJvbSB0YWtpbmcgYSBwb3NpdGlvbiBpbiB0aGUgUyZQIDUwMCBpbmRleCBmdXR1cmVzIGFzIGZvbGxvd3MuIFRha2UgdGhlIGRpZmZlcmVuY2UgZGV0ZXJtaW5lZCBpbiB0aGUgcHJldmlvdXMgcXVlc3Rpb24gKHdoaWNoIHJlcHJlc2VudHMgdGhlIGRvbGxhciBhbW91bnQgb2YgdGhlIGdhaW4gb24gdGhlIGZ1dHVyZXMgcG9zaXRpb24pIGFuZCBkaXZpZGUgaXQgYnkgdGhlIGFtb3VudCB5b3Ugb3JpZ2luYWxseSBpbnZlc3RlZCAodGhlIGFtb3VudCB5b3Ugb3JpZ2luYWxseSBpbnZlc3RlZCBpcyAyMCBwZXJjZW50IG9mIHRoZSBkb2xsYXIgdmFsdWUgb2YgdGhlIGZ1dHVyZXMgY29udHJhY3QgdGhhdCB5b3UgcHVyY2hhc2VkKS4qCgpgYGB7cn0KCnJldHVybiA8LSBnYWluX2xvc3MgLyBpbml0YWxfbWFyZ2luCnByaW50KHJldHVybikKYGBgCgotICAgKlRoZSByZXR1cm4gdGhhdCB5b3UganVzdCBkZXJpdmVkIGluIHRoZSBwcmV2aW91cyBxdWVzdGlvbiBpcyBub3QgYW5udWFsaXplZC4gVG8gYW5udWFsaXplIHlvdXIgcmV0dXJuLCBtdWx0aXBseSBpdCBieSAxMi9tLCB3aGVyZSBtIGlzIHRoZSBudW1iZXIgb2YgbW9udGhzIGluIHlvdXIgc2Nob29sIHRlcm0uKgoKV2UgY2FsY3VsYXRlIHRoZSBnYWluLyBsb3NzLCByZXR1cm4sIGFuZCBhbm51YWxpemVkIHJldHVybiBmb3IgUyZQIDUwMCBmdXR1cmVzIGNvbnRyYWN0LgoKYGBge3J9CgoKYW5udWFsaXplZF9yZXR1cm4gPC0gcmV0dXJuICogKDEyIC8gbW9udGhzX2luX3Rlcm0pCgpjYXQoIkdhaW4vTG9zcyBvbiBGdXR1cmVzIENvbnRyYWN0IDogJCIsIGdhaW5fbG9zcywgIlxuIikKY2F0KCJSZXR1cm46ICIsIHJvdW5kKHJldHVybiAqIDEwMCwgMiksICIlXG4iKQpjYXQoIkFubnVhbGl6ZWQgUmV0dXJuOiAiLCByb3VuZChhbm51YWxpemVkX3JldHVybiAqIDEwMCwgMiksICIlXG4iKQoKYGBgCgotICAgKkFzc3VtZSB0aGF0IHlvdSBwdXJjaGFzZWQgYSBjYWxsIG9wdGlvbiAocmVwcmVzZW50aW5nIDEwMCBzaGFyZXMpIG9uIHRoZSBzcGVjaWZpYyBzdG9jayB0aGF0IHlvdSBpZGVudGlmaWVkIG9mIHRoaXMgcHJvamVjdC4gV2hhdCB3YXMgeW91ciByZXR1cm4gZnJvbSBwdXJjaGFzaW5nIHRoaXMgb3B0aW9uPyBJZiB0aGUgcHJlbWl1bSBmb3IgdGhpcyBvcHRpb24gaXMgbm90IHF1b3RlZCBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybSwgbWVhc3VyZSB0aGUgcmV0dXJuIGFzIGlmIHlvdSBoYWQgZXhlcmNpc2VkIHRoZSBjYWxsIG9wdGlvbiBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybSAoYXNzdW1pbmcgdGhhdCBpdCBpcyBmZWFzaWJsZSB0byBleGVyY2lzZSB0aGUgb3B0aW9uIGF0IHRoYXQgdGltZSkuIFRoYXQgaXMsIHRoZSByZXR1cm4gaXMgYmFzZWQgb24gcHVyY2hhc2luZyB0aGUgc3RvY2sgYXQgdGhlIG9wdGlvbuKAmXMgc3RyaWtlIHByaWNlIGFuZCB0aGVuIHNlbGxpbmcgdGhlIHN0b2NrIGF0IGl0cyBtYXJrZXQgcHJpY2UgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0uKgoKLSAgICpBbm51YWxpemUgdGhlIHJldHVybiBvbiB5b3VyIG9wdGlvbiBieSBtdWx0aXBseWluZyB0aGUgcmV0dXJuIHlvdSBkZXJpdmVkIGluIHRoZSBwcmV2aW91cyBxdWVzdGlvbiBieSAxMi9tLCB3aGVyZSBtIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiBtb250aHMgaW4geW91ciBzY2hvb2wgdGVybSoKCi0gICAqQ29tcGFyZSB0aGUgcmV0dXJuIG9uIHlvdXIgY2FsbCBvcHRpb24gdG8gdGhlIHJldHVybiB0aGF0IHlvdSB3b3VsZCBoYXZlIGVhcm5lZCBpZiB5b3UgaGFkIHNpbXBseSBpbnZlc3RlZCBpbiB0aGUgc3RvY2sgaXRzZWxmLiBOb3RpY2UgaG93IHRoZSBtYWduaXR1ZGUgb2YgdGhlIHJldHVybiBvbiB0aGUgY2FsbCBvcHRpb24gaXMgbXVjaCBsYXJnZXIgdGhhbiB0aGUgbWFnbml0dWRlIG9mIHRoZSByZXR1cm4gb24gdGhlIHN0b2NrIGl0c2VsZi4gVGhhdCBpcywgdGhlIGdhaW5zIGFyZSBsYXJnZXIgYW5kIHRoZSBsb3NzZXMgYXJlIGxhcmdlciB3aGVuIGludmVzdGluZyBpbiBjYWxsIG9wdGlvbnMgb24gYSBzdG9jayBpbnN0ZWFkIG9mIHRoZSBzdG9jayBpdHNlbGYuKgoKV2UgY2FsY3VsYXRlIHRoZSByZXR1cm4gb24gYSBjYWxsIG9wdGlvbiBhbmQgYW5hbHl6ZSB0aGUgcmVzdWx0cy4KCmBgYHtyfQpidXlfcHJlbWl1bSA8LSAyMApzZWxsX3ByZW1pdW0gPC0gMzAKc3RyaWtlX3ByaWNlIDwtIDQwMApzdG9ja19wcmljZV9lbmQgPC0gNDUwCm1vbnRoc19pbl90ZXJtIDwtIDUgCgpjYWxsX3JldHVybiA8LSAoc2VsbF9wcmVtaXVtIC0gYnV5X3ByZW1pdW0pIC8gYnV5X3ByZW1pdW0KCmV4ZXJjaXNlX3JldHVybiA8LSAoc3RvY2tfcHJpY2VfZW5kIC0gc3RyaWtlX3ByaWNlKSAvIGJ1eV9wcmVtaXVtCgphbm51YWxpemVkX2NhbGxfcmV0dXJuIDwtIGNhbGxfcmV0dXJuICogKDEyIC8gbW9udGhzX2luX3Rlcm0pCgpjYXQoIkNhbGwgT3B0aW9uIFJldHVybjogIiwgcm91bmQoY2FsbF9yZXR1cm4gKiAxMDAsIDIpLCAiJVxuIikKY2F0KCJFeGVyY2lzZSBSZXR1cm46ICIsIHJvdW5kKGFubnVhbGl6ZWRfY2FsbF9yZXR1cm4gKiAxMDAsIDIpLCAiJVxuIikKY2F0KCJBbm51YWxpemVkIENhbGwgUmV0dXJuOiAiLCByb3VuZChhbm51YWxpemVkX2NhbGxfcmV0dXJuICogMTAwLCAyKSwgIiVcbiIpCmBgYAoKKipEZXRlcm1pbmluZyBzd2FwIHBheW1lbnRzKioKCi0gICAqQXNzdW1lIHRoYXQsIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNjaG9vbCB0ZXJtLCB5b3UgZW5nYWdlZCBpbiBhIGZpeGVkLWZvci1mbG9hdGluZyByYXRlIHN3YXAgaW4gd2hpY2ggeW91IGFncmVlZCB0byBwYXkgNiBwZXJjZW50IGluIGV4Y2hhbmdlIGZvciB0aGUgcHJldmFpbGluZyAyNi13ZWVrIFQtYmlsbCByYXRlIHRoYXQgZXhpc3RzIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtLiBBc3N1bWUgdGhhdCB5b3VyIHN3YXAgYWdyZWVtZW50IHNwZWNpZmllcyB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybSBhcyB0aGUgb25seSB0aW1lIGF0IHdoaWNoIGEgc3dhcCB3aWxsIG9jY3VyIGFuZCB0aGF0IHRoZSBub3Rpb25hbCBhbW91bnQgaXMgXCQxMCBtaWxsaW9uLiBEZXRlcm1pbmUgdGhlIGFtb3VudCB0aGF0IHlvdSBvd2Ugb24gdGhlIHN3YXAsIHRoZSBhbW91bnQgeW91IGFyZSBvd2VkIG9uIHRoZSBzd2FwLCBhbmQgdGhlIGRpZmZlcmVuY2UuIERpZCB5b3UgZ2FpbiBvciBsb3NlIGFzIGEgcmVzdWx0IG9mIHRoZSBzd2FwPyoKCldlIGNhbGN1bGF0ZSB0aGUgZml4ZWQgYW5kIGZsb2F0aW5nIHBheW1lbnRzIGZvciBhIHN3YXAgYWdyZWVtZW50LgoKYGBge3J9Cm5vdGlvbmFsX2Ftb3VudCA8LSAxMGU2CmZpeGVkX3JhdGUgPC0gMC4wNgpmbG9hdGluZ19yYXRlX2VuZCA8LSAwLjA1NQoKZml4ZWRfcGF5bWVudCA8LSBub3Rpb25hbF9hbW91bnQgKiBmaXhlZF9yYXRlCmZsb2F0aW5nX3BheW1lbnQgPC0gbm90aW9uYWxfYW1vdW50ICogZmxvYXRpbmdfcmF0ZV9lbmQKbmV0X3BheW1lbnQgPC0gZml4ZWRfcGF5bWVudCAtIGZsb2F0aW5nX3BheW1lbnQKCmNhdCgiRml4ZWQgUGF5bWVudDogJCIsIGZpeGVkX3BheW1lbnQsICJcbiIpCmNhdCgiRmxvYXRpbmcgUGF5bWVudDogJCIsIGZsb2F0aW5nX3BheW1lbnQsICJcbiIpCmNhdCgiTmV0IFBheW1lbnQ6ICQiLCBuZXRfcGF5bWVudCwgIlxuIikKCmBgYAoKKipNZWFzdXJpbmcgYW5kIGV4cGxhaW5pbmcgZXhjaGFuZ2UgcmF0ZSBtb3ZlbWVudHMqKgoKLSAgICpEZXRlcm1pbmUgdGhlIHBlcmNlbnRhZ2UgY2hhbmdlIGluIHRoZSB2YWx1ZSBvZiB0aGUgQnJpdGlzaCBwb3VuZCBvdmVyIHRoZSBzY2hvb2wgdGVybS4gRGlkIHRoZSBwb3VuZCBhcHByZWNpYXRlIG9yIGRlcHJlY2lhdGUgYWdhaW5zdCB0aGUgZG9sbGFyPyoKCi0gICAqRGV0ZXJtaW5lIHRoZSBwZXJjZW50YWdlIGNoYW5nZSBpbiB0aGUgdmFsdWUgb2YgdGhlIEphcGFuZXNlIHllbiBvdmVyIHRoZSBzY2hvb2wgdGVybS4gRGlkIHRoZSB5ZW4gYXBwcmVjaWF0ZSBvciBkZXByZWNpYXRlIGFnYWluc3QgdGhlIGRvbGxhcj8qCgotICAgKkRldGVybWluZSB0aGUgcGVyY2VudGFnZSBjaGFuZ2UgaW4gdGhlIHZhbHVlIG9mIHRoZSBNZXhpY2FuIHBlc28gb3ZlciB0aGUgc2Nob29sIHRlcm0uIERpZCB0aGUgcGVzbyBhcHByZWNpYXRlIG9yIGRlcHJlY2lhdGUgYWdhaW5zdCB0aGUgZG9sbGFyPyoKCi0gICAqRGV0ZXJtaW5lIHRoZSBwZXIgdW5pdCBnYWluIG9yIGxvc3MgaWYgeW91IGhhZCBwdXJjaGFzZWQgQnJpdGlzaCBwb3VuZCBmdXR1cmVzIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRlcm0gYW5kIHNvbGQgQnJpdGlzaCBwb3VuZCBmdXR1cmVzIGF0IHRoZSBlbmQgb2YgdGhlIHRlcm0uKgoKLSAgICpHaXZlbiB0aGF0IGEgc2luZ2xlIGZ1dHVyZXMgY29udHJhY3Qgb24gQnJpdGlzaCBwb3VuZHMgcmVwcmVzZW50cyA2Miw1MDAgcG91bmRzLCBkZXRlcm1pbmUgdGhlIGRvbGxhciBhbW91bnQgb2YgeW91ciBnYWluIG9yIGxvc3MuKgoKV2UgY2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIGNoYW5nZSBhbmQgZ2Fpbi8gbG9zcyBmb3IgR0JQLyBVU0QgZnV0dXJlcy4KCmBgYHtyfQpzdGFydF9yYXRlX2dwZCA8LSAxLjIKZW5kX3JhdGVfZ3BkIDwtIDEuMjUKY29udHJhY3Rfc2l6ZV9nYnAgPC0gNjI1MDAKCnBlcmNlbnRfY2hhbmdlX2dwZCA8LSAoKGVuZF9yYXRlX2dwZCAtIHN0YXJ0X3JhdGVfZ3BkKSAvIHN0YXJ0X3JhdGVfZ3BkKSAqIDEwMAoKZ2Fpbl9sb3NzX3Blcl91bml0X2dwZCA8LSBlbmRfcmF0ZV9ncGQgLSBzdGFydF9yYXRlX2dwZAp0b3RhbF9nYWluX2xvc3NfZ3BkIDwtIGdhaW5fbG9zc19wZXJfdW5pdF9ncGQgKiBjb250cmFjdF9zaXplX2dicAoKY2F0KCJHQlAgUGVyY2FudGFnZSBDaGFuZ2U6ICIsIHJvdW5kKHBlcmNlbnRfY2hhbmdlX2dwZCwyKSwgIiVcbiIpCmNhdCgiVG90YWwgR2Fpbi9Mb3NzIG9uIEdCUCBGdXR1cmVzIENvbnRyYWN0OiAkIiwgcm91bmQodG90YWxfZ2Fpbl9sb3NzX2dwZCwyKSwgIiVcbiIpCgpgYGAKCiMjIEwxMiBDYXBpdGFsIHJlcXVpcmVtZW50cwoKT3BlcmF0aW9uYWwgUmlzawoKV2UgY2FsY3VsYXRlIHRoZSBvcGVyYXRpb25hbCByaXNrIGNhcGl0YWwgZm9yIEJhbmsgb2YgQW1lcmljYSAoQm9BKSBhbmQgRGV1dHNjaGUgQmFuayAoREIpIHVzaW5nIHRoZSBCYXNpYyBJbmRpY2F0b3IgQXBwcm9hY2ggdW5kZXIgQmFzZWwgSUlJOgoKYGBge3J9CgphbHBoYSA8LSAwLjE1Cmdyb3NzX2luY29tZV9ib2EgPC0gOTBlOSAKZ3Jvc3NfaW5jb21lX2RiIDwtIDI1ZTkgKiAxLjEgCgpvcGVyYXRpb25hbF9yaXNrX2JvYSA8LSBhbHBoYSAqIGdyb3NzX2luY29tZV9ib2EKb3BlcmF0aW9uYWxfcmlza19kYiA8LSBhbHBoYSAqIGdyb3NzX2luY29tZV9kYgoKCmNhdCgiT3BlcmF0aW9uYWwgUmlzayBDYXBpdGFsIChCb0EpOiAkIiwgZm9ybWF0KG9wZXJhdGlvbmFsX3Jpc2tfYm9hLCBiaWcubWFyayA9ICIsIiksICJcbiIpCmNhdCgiT3BlcmF0aW9uYWwgUmlzayBDYXBpdGFsIChEQik6ICQiLCBmb3JtYXQob3BlcmF0aW9uYWxfcmlza19kYiwgYmlnLm1hcmsgPSAiLCIpLCAiXG4iKQoKYGBgCgpXZSBjYWxjdWxhdGUgdGhlIG1hcmtldCByaXNrIGNhcGl0YWwgdXNpbmcgdGhlIFZhbHVlIGF0IHJpc2sgKFZhUikgYXBwcm9hY2g6CgpgYGB7cn0KayA8LSAzIAp2YXJfYm9hIDwtIDVlOQp2YXJfZGIgPC0gM2U5ICogMS4xIAoKbWFya2V0X3Jpc2tfYm9hIDwtIGsgKiB2YXJfYm9hCm1hcmtldF9yaXNrX2RiIDwtIGsgKiB2YXJfZGIKCmNhdCgiTWFya2V0IFJpc2sgQ2FwaXRhbCAoQm9BKTogJCIsIGZvcm1hdChtYXJrZXRfcmlza19ib2EsIGJpZy5tYXJrID0gIiwiKSwgIlxuIikKY2F0KCJNYXJrZXQgUmlzayBDYXBpdGFsIChEQik6ICQiLCBmb3JtYXQobWFya2V0X3Jpc2tfZGIsIGJpZy5tYXJrID0gIiwiKSwgIlxuIikKCmBgYAoKV2UgY2FsY3VsYXRlIGNyZWRpdCByaXNrIGNhcGl0YWwgYmFzZWQgb24gdGhlIGV4cG9zdXJlIGFtb3VudHMsIHJpc2sgd2VpZ2h0cywgYW5kIHJlZ3VsYXRvcnkgY2FwaXRhbCByZXF1aXJlbWVudHMKCmBgYHtyfQpyZWd1bGF0b3J5X2NhcGl0YWxfcmVxdWlyZW1lbnQgPC0gMC4wOCAKCgpsb2FuX2V4cG9zdXJlX2JvYSA8LSAyMDBlOQpnb3Zfc2VjdXJpdGllc19ib2EgPC0gNTBlOQpsb2FuX2V4cG9zdXJlX2RiIDwtIDE1MGU5ICogMS4xIApnb3Zfc2VjdXJpdGllc19kYiA8LSA0MGU5ICogMS4xCgpsb2FuX3Jpc2tfd2VpZ2h0IDwtIDEuMDAgCmdvdl9yaXNrX3dlaWdodCA8LSAwLjAwICAKCmNyZWRpdF9yaXNrX2JvYSA8LSByZWd1bGF0b3J5X2NhcGl0YWxfcmVxdWlyZW1lbnQgKiAobG9hbl9leHBvc3VyZV9ib2EgKiBsb2FuX3Jpc2tfd2VpZ2h0ICsgZ292X3NlY3VyaXRpZXNfYm9hICogZ292X3Jpc2tfd2VpZ2h0KQpjcmVkaXRfcmlza19kYiA8LSByZWd1bGF0b3J5X2NhcGl0YWxfcmVxdWlyZW1lbnQgKiAobG9hbl9leHBvc3VyZV9kYiAqIGxvYW5fcmlza193ZWlnaHQgKyBnb3Zfc2VjdXJpdGllc19kYiAqIGdvdl9yaXNrX3dlaWdodCkKCmNhdCgiQ3JlZGl0IFJpc2sgQ2FwaXRhbCAoQm9BKTogJCIsIGZvcm1hdChjcmVkaXRfcmlza19ib2EsIGJpZy5tYXJrID0gIiwiKSwgIlxuIikKY2F0KCJDcmVkaXQgUmlzayBDYXBpdGFsIChEQik6ICQiLCBmb3JtYXQoY3JlZGl0X3Jpc2tfZGIsIGJpZy5tYXJrID0gIiwiKSwgIlxuIikKCmBgYAoKV2UgY2FsY3VsYXRlIHRoZSB0b3RhbCBjYXBpdGFsIHJlcXVpcmVtZW50cyBmb3IgZWFjaCBiYW5rIGJ5IHN1bW1pbmcgb3BlcmF0aW9uYWwsIG1hcmtldCwgYW5kIGNyZWRpdCByaXNrIGNhcGl0YWxzLgoKYGBge3J9CnRvdGFsX2NhcGl0YWxfYm9hIDwtIG9wZXJhdGlvbmFsX3Jpc2tfYm9hICsgbWFya2V0X3Jpc2tfYm9hICsgY3JlZGl0X3Jpc2tfYm9hCnRvdGFsX2NhcGl0YWxfZGIgPC0gb3BlcmF0aW9uYWxfcmlza19kYiArIG1hcmtldF9yaXNrX2RiICsgY3JlZGl0X3Jpc2tfZGIKCmNhdCgiVG90YWwgQ2FwaXRhbCBSZXF1aXJlbWVudCAoQm9BKTogJCIsIGZvcm1hdCh0b3RhbF9jYXBpdGFsX2JvYSwgYmlnLm1hcmsgPSAiLCIpLCAiXG4iKQpjYXQoIlRvdGFsIENhcGl0YWwgUmVxdWlyZW1lbnQgKERCKTogJCIsIGZvcm1hdCh0b3RhbF9jYXBpdGFsX2RiLCBiaWcubWFyayA9ICIsIiksIlxuIikKYGBgCg==