L1 Intro
library(quantmod)
library(fredr)
library(knitr)
# Set your FRED API key
fredr_set_key("bf734a754ddb42bfd91f06e0224ac7da")
# Function to fetch stock index data from Yahoo Finance for specific dates
get_prices <- function(symbol, date1, date2) {
data <- tryCatch(
getSymbols(symbol, src = "yahoo", auto.assign = FALSE, from = Sys.Date() - 365, to = Sys.Date()),
error = function(e) NULL
)
if (!is.null(data)) {
# Convert to a time index to find the nearest available dates
available_dates <- index(data)
beginning_date <- as.Date(date1)
ending_date <- as.Date(date2)
# Find the closest available dates
beginning_index <- which.min(abs(available_dates - beginning_date))
ending_index <- which.min(abs(available_dates - ending_date))
beginning_price <- as.numeric(Cl(data)[beginning_index])
ending_price <- as.numeric(Cl(data)[ending_index])
return(c(beginning_price, ending_price))
} else {
return(c(NA, NA))
}
}
# Function to fetch data from FRED for the specific dates and find the closest available data
get_fred_rate <- function(series_id, date1, date2) {
data <- tryCatch(
fredr(series_id = series_id, observation_start = Sys.Date() - 365, observation_end = Sys.Date()),
error = function(e) NA
)
# Ensure data is a data frame and find the closest dates if necessary
if (!is.null(data) && is.data.frame(data)) {
available_dates <- as.Date(data$date)
beginning_date <- as.Date(date1)
ending_date <- as.Date(date2)
# Find the closest available dates
beginning_index <- which.min(abs(available_dates - beginning_date))
ending_index <- which.min(abs(available_dates - ending_date))
beginning_rate <- data$value[beginning_index]
ending_rate <- data$value[ending_index]
return(c(beginning_rate, ending_rate))
} else {
return(c(NA, NA))
}
}
# Initialize data for the table with column names
table_data <- data.frame(
Category = character(),
BoT = numeric(),
EoT = numeric(),
stringsAsFactors = FALSE
)
# Function to add rows to the table
add_row <- function(category, data) {
table_data <<- rbind(table_data, data.frame(
Category = category,
BoT = data[1],
EoT = data[2],
stringsAsFactors = FALSE
))
}
# Dates to use (04/01/2024 and 10/30/2024)
date1 <- "2024-04-01"
date2 <- "2024-10-30"
# Add stock market data
add_row("S&P 500 (stock) index level:", get_prices("^GSPC", date1, date2))
add_row("Nasdaq Composite (stock) index level:", get_prices("^IXIC", date1, date2))
# Add interest rates (via FRED)
add_row("Prime rate:", get_fred_rate("MPRIME", date1, date2))
add_row("Federal funds rate:", get_fred_rate("DFF", date1, date2))
add_row("Commercial paper rate (90 days):", get_fred_rate("CP3M", date1, date2))
add_row("Certificate of deposit rate (3-month):", get_fred_rate("CD3M", date1, date2))
add_row("Treasury bill rate (13 weeks):", get_fred_rate("TB3MS", date1, date2))
add_row("Treasury bill rate (26 weeks):", get_fred_rate("TB6MS", date1, date2))
# Add bond yields (via FRED)
add_row("Treasury long-term bond yield:", get_fred_rate("GS10", date1, date2))
add_row("Corporate (Master) bond yield:", get_fred_rate("BAA", date1, date2))
add_row("High-yield corporate bond yield:", get_fred_rate("BAMLH0A0HYM2EY", date1, date2))
add_row("Tax-exempt (7–12-year) bond yield:", get_fred_rate("MUNIMM", date1, date2))
# Display the table
knitr::kable(table_data, col.names = c("Category", "BoT (04/01/2024)", "EoT (10/30/2024)"))
| S&P 500 (stock) index level: |
5243.77 |
5813.67 |
| Nasdaq Composite (stock) index level: |
16396.83 |
18607.93 |
| Prime rate: |
8.50 |
7.81 |
| Federal funds rate: |
5.33 |
4.83 |
| Commercial paper rate (90 days): |
NA |
NA |
| Certificate of deposit rate (3-month): |
NA |
NA |
| Treasury bill rate (13 weeks): |
5.24 |
4.42 |
| Treasury bill rate (26 weeks): |
5.15 |
4.31 |
| Treasury long-term bond yield: |
4.54 |
4.36 |
| Corporate (Master) bond yield: |
6.00 |
5.78 |
| High-yield corporate bond yield: |
7.58 |
6.93 |
| Tax-exempt (7–12-year) bond yield: |
NA |
NA |
Like you said in the lecture, some financial data may be unavailable
due to gaps in historical records or limited coverage. ETFs serve as
good substitutes because they provide consistent, reliable data and
represent a broader market, making them ideal for filling in missing
data points for analysis.While ETFs provide useful approximations for
missing data, they don’t represent exact percentages or values of
specific indices or assets. Instead, they show general differences and
changes, which can still be valuable for analysis.
library(quantmod)
library(knitr)
# Function to fetch ETF data from Yahoo Finance
get_etf_prices <- function(symbol, date1, date2) {
data <- tryCatch(
getSymbols(symbol, src = "yahoo", auto.assign = FALSE, from = "2023-01-01", to = Sys.Date()),
error = function(e) NULL
)
if (!is.null(data)) {
# Filter data for the specific dates
data_filtered <- data[date1 <= index(data) & index(data) <= date2]
if (nrow(data_filtered) > 0) {
beginning_price <- as.numeric(first(Cl(data_filtered)))
ending_price <- as.numeric(last(Cl(data_filtered)))
# Calculate percentage change
percent_change <- ((ending_price - beginning_price) / beginning_price) * 100
return(c(beginning_price, ending_price, percent_change))
} else {
return(c(NA, NA, NA))
}
} else {
return(c(NA, NA, NA))
}
}
# Initialize data for the table
table_data <- data.frame(
BoT = character(),
EoT = character(),
Change_Percentage = character()
)
# Function to add rows to the table
add_row <- function(category, data) {
table_data <<- rbind(table_data, data.frame(
BoT = category,
EoT = paste(data[1:2], collapse = ", "),
Change_Percentage = round(data[3], 2)
))
}
# Add ETF data for missing rates
# Commercial paper rate (90 days) -> Use a short-term bond ETF like SHV (iShares Short Treasury Bond ETF)
add_row("Commercial paper rate (90 days):", get_etf_prices("SHV", "2024-04-01", "2024-10-30"))
# Certificate of deposit rate (3-month) -> Use a short-term bond ETF like BSV (Vanguard Short-Term Bond ETF)
add_row("Certificate of deposit rate (3-month):", get_etf_prices("BSV", "2024-04-01", "2024-10-30"))
# Tax-exempt (7–12-year) bond yield -> Use a municipal bond ETF like MUB (iShares National Muni Bond ETF)
add_row("Tax-exempt (7–12-year) bond yield:", get_etf_prices("MUB", "2024-04-01", "2024-10-30"))
# Display the table
knitr::kable(table_data, col.names = c("Category", "BoT (04/01/2024), EoT (10/30/2024)", "Change (%)"))
| Commercial paper rate (90 days): |
110.069999694824, 110.550003051758 |
0.44 |
| Certificate of deposit rate (3-month): |
76.3099975585938, 77.6699981689453 |
1.78 |
| Tax-exempt (7–12-year) bond yield: |
107.019996643066, 107.019996643066 |
0.00 |
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.
library(quantmod)
library(knitr)
# Define the stocks
stocks <- c("KO", "NVDA") # Coca-Cola (KO) and NVIDIA (NVDA)
# Initialize a dataframe to store results
results <- data.frame(
Exchange = c("NYSE", "Nasdaq"),
Stock = stocks,
Latest_Price = NA,
Latest_Annual_Dividend = NA
)
# Fetch data for each stock
for (i in 1:length(stocks)) {
stock <- stocks[i]
# Fetch stock data
getSymbols(stock, src = "yahoo", auto.assign = TRUE)
# Get the latest closing price
stock_data <- get(stock)
results$Latest_Price[i] <- as.numeric(Cl(stock_data[nrow(stock_data)]))
# Fetch dividend data
dividend_data <- getDividends(stock, auto.assign = FALSE)
if (nrow(dividend_data) > 0) {
# Get the most recent dividend payment
latest_dividend <- as.numeric(tail(dividend_data, 1))
# Assume quarterly dividends and calculate the annualized dividend
results$Latest_Annual_Dividend[i] <- latest_dividend * 4
} else {
results$Latest_Annual_Dividend[i] <- 0
}
}
# Display the table with knitr::kable()
kable(
results,
col.names = c("Stock Exchange", "Stock Ticker", "Latest Price", "Annualized Dividend"),
caption = "Stock Prices and Dividends for Coca-Cola (NYSE) and NVIDIA (Nasdaq)"
)
Stock Prices and Dividends for Coca-Cola (NYSE) and NVIDIA
(Nasdaq)
| NYSE |
KO |
64.08 |
1.94 |
| Nasdaq |
NVDA |
138.25 |
0.04 |
library(quantmod)
library(knitr)
# Define ETFs as proxies for futures
# TLT: Treasury Bonds, SPY: S&P 500, QQQ: Nasdaq, FXB: British Pound
symbols <- c("TLT", "SPY", "QQQ", "FXB")
# Initialize a dataframe to store results
results <- data.frame(
Description = c("Treasury Bond Futures", "S&P 500 Index Futures", "Nasdaq Market", "British Pound Futures"),
Latest_Price = NA,
Sept_5_2024_Price = NA
)
# Define the specific date to fetch (September 5th, 2024)
specific_date <- "2024-09-05"
# Fetch data for each symbol
for (i in 1:length(symbols)) {
symbol <- symbols[i]
# Fetch data (entire year for safety)
getSymbols(symbol, src = "yahoo", from = "2023-01-01", to = Sys.Date(), auto.assign = TRUE)
# Extract stock data
stock_data <- get(symbol)
# Get the latest closing price
results$Latest_Price[i] <- as.numeric(Cl(stock_data[nrow(stock_data)]))
# Get the price on the specific date
if (specific_date %in% index(stock_data)) {
results$Sept_5_2024_Price[i] <- as.numeric(Cl(stock_data[specific_date]))
} else {
results$Sept_5_2024_Price[i] <- NA # If market data is unavailable
}
}
# Display the table with knitr::kable
kable(
results,
col.names = c("Description", "Latest Price", "Sept 5, 2024 Price"),
caption = "Stock Prices for Futures Proxies (Latest and Sept 5, 2024)"
)
Stock Prices for Futures Proxies (Latest and Sept 5,
2024)
| Treasury Bond Futures |
93.97 |
99.57 |
| S&P 500 Index Futures |
602.55 |
549.61 |
| Nasdaq Market |
509.74 |
461.04 |
| British Pound Futures |
122.47 |
126.55 |
library(quantmod)
library(knitr)
# Fetch Tesla stock data without outputting symbol information
tesla_data <- getSymbols("TSLA", src = "yahoo", from = "2023-01-01", to = Sys.Date(), auto.assign = FALSE)
# Latest closing price
latest_price <- as.numeric(last(Cl(tesla_data)))
# Price on September 5, 2024
specific_date <- "2024-09-05"
sept_5_price <- if (specific_date %in% index(tesla_data)) as.numeric(Cl(tesla_data[specific_date]))
# Option details
expiration_month <- "December 2024"
strike_price <- 250
option_premium_bot <- 20 # Beginning of Term
option_premium_eot <- 94 # End of Term
# Create table
results <- data.frame(
Description = c("Tesla (TSLA) Stock", "Option Expiration Month", "Option Strike Price", "Option Premium"),
BoT = c(sept_5_price, expiration_month, strike_price, option_premium_bot),
EoT = c(latest_price, expiration_month, strike_price, option_premium_eot)
)
# Display table
kable(
results,
col.names = c("Description", "BoT (Beginning of Term)", "EoT (End of Term)"),
caption = "Tesla (TSLA) Stock Price and Option Details (Latest and September 5, 2024)"
)
Tesla (TSLA) Stock Price and Option Details (Latest and
September 5, 2024)
| Tesla (TSLA) Stock |
230.169998168945 |
345.160003662109 |
| Option Expiration Month |
December 2024 |
December 2024 |
| Option Strike Price |
250 |
250 |
| Option Premium |
20 |
94 |
library(quantmod)
library(knitr)
# Define the currency pairs
currencies <- c("GBP/USD", "JPY/USD", "MXN/USD")
# Initialize a dataframe to store results
results <- data.frame(
Description = c(
"Exchange rate of the British pound (in $):",
"Exchange rate of the Japanese yen (in $):",
"Exchange rate of the Mexican peso (in $):"
),
BoT = NA,
EoT = NA
)
# Define the specific date (September 5th, 2024)
specific_date <- "2024-09-05"
# Fetch exchange rate data
for (i in 1:length(currencies)) {
currency <- currencies[i]
# Convert format for Yahoo Finance (e.g., GBP/USD -> GBPUSD=X)
yahoo_symbol <- gsub("/", "", currency) %>% paste0("=X")
# Fetch data from Yahoo Finance
currency_data <- getSymbols(yahoo_symbol, src = "yahoo", from = "2023-01-01", to = Sys.Date(), auto.assign = FALSE)
# Get the latest closing rate (EoT)
results$EoT[i] <- as.numeric(last(Cl(currency_data)))
# Get the rate on September 5th, 2024 (BoT)
if (specific_date %in% index(currency_data)) {
results$BoT[i] <- as.numeric(Cl(currency_data[specific_date]))
} else {
results$BoT[i] <- NA # If data is unavailable
}
}
# Display the table
kable(
results,
col.names = c("Description", "BoT (September 5, 2024)", "EoT (Latest)"),
caption = "Currency Exchange Rates (British Pound, Japanese Yen, and Mexican Peso)"
)
Currency Exchange Rates (British Pound, Japanese Yen, and
Mexican Peso)
| Exchange rate of the British pound (in $): |
1.3177488 |
1.2696800 |
| Exchange rate of the Japanese yen (in $): |
0.0069738 |
0.0066787 |
| Exchange rate of the Mexican peso (in $): |
0.0502983 |
0.0491183 |
# Load necessary libraries
library(quantmod)
library(knitr)
# Fetch CHF/USD exchange rate data from Yahoo Finance
currency_symbol <- "CHFUSD=X" # CHF/USD symbol on Yahoo Finance
# Fetch data from Yahoo Finance
currency_data <- getSymbols(currency_symbol, src = "yahoo", from = "2023-01-01", to = Sys.Date(), auto.assign = FALSE)
# Latest value of the CHF/USD currency pair
latest_value <- as.numeric(last(Cl(currency_data)))
# Price on September 5, 2024 (BoT)
specific_date <- "2024-09-05"
sept_5_value <- if (specific_date %in% index(currency_data)) as.numeric(Cl(currency_data[specific_date])) else NA
# Estimate the strike price for the option (5% above the current value) since CHF is strengthening
strike_price <- latest_value * 1.05 # Assume 5% above the current value
# Estimating the option premium
# We will use a simple method assuming a 10% volatility for CHF/USD, with a time to expiration of about 2 months (Oct 2024)
implied_volatility <- 0.1 # Assumed volatility for currency options (10%)
time_to_expiration <- 2 / 12 # 2 months to expiration (October 2024)
# Using a simplified Black-Scholes-like model to estimate the option premium (not precise but gives an idea)
# Formula: Option Premium = Spot Price * N(d1) - Strike Price * exp(-r*t) * N(d2)
# Here we'll skip the risk-free rate and assume it's a call option for simplicity
# Black-Scholes components
d1 <- (log(latest_value / strike_price) + (0.5 * implied_volatility^2) * time_to_expiration) / (implied_volatility * sqrt(time_to_expiration))
d2 <- d1 - implied_volatility * sqrt(time_to_expiration)
# Normal distribution function (N(d1) and N(d2))
N <- function(x) { pnorm(x) }
# Estimate option premium (simplified for a currency call option)
option_premium <- latest_value * N(d1) - strike_price * exp(-0.02 * time_to_expiration) * N(d2)
# Display estimated option premium for BoT (September 5, 2024) and EoT (latest)
# For simplicity, let's assume the premium at September 5, 2024 is slightly lower due to time decay
option_premium_bot <- option_premium * 0.95 # Assuming the premium was slightly lower on September 5, 2024 due to time decay
option_premium_eot <- option_premium # Latest (EoT) premium is our estimated premium
# Create the results table
results <- data.frame(
Description = c("Currency (CHF/USD)", "Option Expiration Month", "Option Strike Price", "Option Premium"),
BoT = c(sept_5_value, "Dezember 2024", strike_price, option_premium_bot),
EoT = c(latest_value, "Dezember 2024", strike_price, option_premium_eot)
)
# Display the table using knitr::kable
kable(
results,
col.names = c("Description", "BoT (Beginning of Term)", "EoT (End of Term)"),
caption = "Currency Option Details (CHF/USD) - Beginning of Term (Sept 5, 2024) vs End of Term (Latest)"
)
Currency Option Details (CHF/USD) - Beginning of Term (Sept 5,
2024) vs End of Term (Latest)
| Currency (CHF/USD) |
1.18510091304779 |
1.12059879302979 |
| Option Expiration Month |
Dezember 2024 |
Dezember 2024 |
| Option Strike Price |
1.17662873268127 |
1.17662873268127 |
| Option Premium |
0.00294020779195862 |
0.00309495557048275 |
# Load necessary libraries
library(quantmod)
library(knitr)
# Fetch AUD/USD exchange rate data from Yahoo Finance
currency_symbol <- "AUDUSD=X" # AUD/USD symbol on Yahoo Finance
# Fetch data from Yahoo Finance
currency_data <- getSymbols(currency_symbol, src = "yahoo", from = "2023-01-01", to = Sys.Date(), auto.assign = FALSE)
# Latest value of the AUD/USD currency pair
latest_value <- as.numeric(last(Cl(currency_data)))
# Price on September 5, 2024 (BoT)
specific_date <- "2024-09-05"
sept_5_value <- if (specific_date %in% index(currency_data)) as.numeric(Cl(currency_data[specific_date])) else NA
# Estimate the strike price for the option (5% below the current value) since AUD is expected to weaken
strike_price <- latest_value * 0.95 # Assume 5% below the current value for a put option
# Estimating the option premium
# We will use the same method as above, assuming a 10% volatility for AUD/USD, with a time to expiration of about 2 months (Oct 2024)
implied_volatility <- 0.1 # Assumed volatility for currency options (10%)
time_to_expiration <- 2 / 12 # 2 months to expiration (October 2024)
# Using a simplified Black-Scholes-like model to estimate the option premium (not precise but gives an idea)
# Formula: Option Premium = Spot Price * N(d1) - Strike Price * exp(-r*t) * N(d2)
# Here we'll skip the risk-free rate and assume it's a put option for simplicity
# Black-Scholes components
d1 <- (log(latest_value / strike_price) + (0.5 * implied_volatility^2) * time_to_expiration) / (implied_volatility * sqrt(time_to_expiration))
d2 <- d1 - implied_volatility * sqrt(time_to_expiration)
# Normal distribution function (N(d1) and N(d2))
N <- function(x) { pnorm(x) }
# Estimate option premium (simplified for a currency put option)
option_premium <- strike_price * exp(-0.02 * time_to_expiration) * N(-d2) - latest_value * N(-d1)
# Display estimated option premium for BoT (September 5, 2024) and EoT (latest)
# For simplicity, let's assume the premium at September 5, 2024 is slightly lower due to time decay
option_premium_bot <- option_premium * 0.95 # Assuming the premium was slightly lower on September 5, 2024 due to time decay
option_premium_eot <- option_premium # Latest (EoT) premium is our estimated premium
# Create the results table
results <- data.frame(
Description = c("Currency (AUD/USD)", "Option Expiration Month", "Option Strike Price", "Option Premium"),
BoT = c(sept_5_value, "Dezember 2024", strike_price, option_premium_bot),
EoT = c(latest_value, "Dezember 2024", strike_price, option_premium_eot)
)
# Display the table using knitr::kable
kable(
results,
col.names = c("Description", "BoT (Beginning of Term)", "EoT (End of Term)"),
caption = "Currency Option Details (AUD/USD) - Beginning of Term (Sept 5, 2024) vs End of Term (Latest)"
)
Currency Option Details (AUD/USD) - Beginning of Term (Sept 5,
2024) vs End of Term (Latest)
| Currency (AUD/USD) |
0.674050211906433 |
0.650728166103363 |
| Option Expiration Month |
Dezember 2024 |
Dezember 2024 |
| Option Strike Price |
0.618191757798195 |
0.618191757798195 |
| Option Premium |
0.00101607248069769 |
0.00106954997968178 |
L5.22 Recent Performance
L7.1 Comparing Yields Among Securities
Difference between yields on corporate high-quality bonds and
Treasury bonds:
library(quantmod)
library(knitr)
# Define the start and end dates of the school term
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30") # Updated end date
# Download data for 10-year Treasury bond yield and AAA-rated corporate bond yield
tryCatch({
getSymbols("DGS10", src = "FRED", from = start_date, to = end_date) # 10-year Treasury bond yield
getSymbols("BAMLC0A1CAAAEY", src = "FRED", from = start_date, to = end_date) # AAA-rated corporate bond yield
# Extract yields at the end of the school term
treasury_yield <- na.omit(DGS10[end_date] / 100) # Convert to percentage
corporate_yield <- na.omit(BAMLC0A1CAAAEY[end_date] / 100) # Convert to percentage
# Verify that the data is extracted correctly for the given date
if (length(treasury_yield) == 0 || length(corporate_yield) == 0) {
stop("Data for the specified end date is not available.")
}
# Calculate the yield difference (spread)
yield_difference <- first(corporate_yield) - first(treasury_yield)
# Create a data frame to display the results
results <- data.frame(
Metric = c("10-Year Treasury Bond Yield", "Corporate High-Quality Bond Yield", "Yield Premium (Corporate - Treasury)"),
Value = c(
paste0(round(first(treasury_yield) * 100, 2), "%"),
paste0(round(first(corporate_yield) * 100, 2), "%"),
paste0(round(yield_difference * 100, 2), "%")
)
)
# Display the results in a table format using knitr::kable()
print(kable(results, caption = paste("Bond Yields and Premiums on", format(end_date, "%Y-%m-%d"))))
}, error = function(e) {
cat("Error retrieving data:", e$message, "\n")
})
Bond Yields and Premiums on 2024-10-30
| 10-Year Treasury Bond Yield |
4.29% |
| Corporate High-Quality Bond Yield |
4.69% |
| Yield Premium (Corporate - Treasury) |
0.4% |
Corporate high-quality bonds generally have higher yields than
Treasury bonds. This difference, known as the spread, exists because
corporate bonds carry credit risk (the risk that the issuer may
default), while Treasury bonds are considered virtually risk-free as
they are backed by the U.S. government. The size of the spread varies
depending on market conditions, such as investor risk appetite and
economic outlook.
L7.2 Comparing Yields on Long-term Bonds
Difference between yields on long-term Treasury bonds and long-term
municipal bonds:
Municipal bonds often have lower yields than Treasury bonds for
investors in high tax brackets because the interest earned on municipal
bonds is typically exempt from federal taxes (and sometimes state and
local taxes). This tax-exempt status makes municipal bonds more
attractive on an after-tax basis, reducing their yields compared to
taxable Treasury bonds. The difference reflects the tax advantage and
the credit quality of the municipal issuers.
library(quantmod)
library(knitr)
# Define the start and end dates of the school term
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30")
# Download data for 26-week and 13-week T-bill yields
tryCatch({
getSymbols("DTB6", src = "FRED", from = start_date, to = end_date) # 26-week T-bill yield
getSymbols("DTB3", src = "FRED", from = start_date, to = end_date) # 13-week T-bill yield
# Extract yields at the start of the school term
t_bill_26_start <- na.omit(DTB6[start_date] / 100) # Convert to percentage
t_bill_13_start <- na.omit(DTB3[start_date] / 100) # Convert to percentage
# Extract yields at the end of the school term
t_bill_26_end <- na.omit(DTB6[end_date] / 100) # Convert to percentage
t_bill_13_end <- na.omit(DTB3[end_date] / 100) # Convert to percentage
# Calculate the yield difference (spread) at the start of the term
yield_difference_start <- first(t_bill_26_start) - first(t_bill_13_start)
# Create a data frame to display results
results <- data.frame(
Metric = c("26-week T-bill yield at start", "13-week T-bill yield at start", "Yield Difference (26-week - 13-week) at start",
"Curve Slope at start", "Market Expectation at start",
"26-week T-bill yield at end", "13-week T-bill yield at end"),
Value = c(
paste(round(first(t_bill_26_start) * 100, 2), "%"),
paste(round(first(t_bill_13_start) * 100, 2), "%"),
paste(round(yield_difference_start * 100, 2), "%"),
if (yield_difference_start > 0) "Upward Slope" else if (yield_difference_start < 0) "Downward Slope" else "Flat",
if (yield_difference_start > 0) "Higher rates expected" else if (yield_difference_start < 0) "Lower rates expected" else "No clear expectation",
paste(round(first(t_bill_26_end) * 100, 2), "%"),
paste(round(first(t_bill_13_end) * 100, 2), "%")
)
)
# Display the results using kable for better formatting
kable(results, caption = "Analysis of T-Bill Yield and Expectations Over the Term")
}, error = function(e) {
cat("Error retrieving data:", e$message, "\n")
})
Analysis of T-Bill Yield and Expectations Over the
Term
| 26-week T-bill yield at start |
5.13 % |
| 13-week T-bill yield at start |
5.23 % |
| Yield Difference (26-week - 13-week) at start |
-0.1 % |
| Curve Slope at start |
Downward Slope |
| Market Expectation at start |
Lower rates expected |
| 26-week T-bill yield at end |
4.32 % |
| 13-week T-bill yield at end |
4.47 % |
L7.6 Did interest rates move in that direction over the school
term?
Yes, the market expectation is right.
L7.7 and 7.8
# Install and load necessary packages
if (!require(quantmod)) install.packages("quantmod")
if (!require(knitr)) install.packages("knitr")
library(quantmod)
library(knitr)
# Initialize a data frame to store the results
results <- data.frame(
Date = character(),
`30-Year Treasury Bond Yield (%)` = numeric(),
`13-Week T-Bill Yield (%)` = numeric(),
`Yield Difference (30-Year - 13-Week) (%)` = numeric(),
stringsAsFactors = FALSE
)
# Part 7.7: Analyze the yield difference at the beginning of the school term
start_date <- as.Date("2024-04-01")
tryCatch({
# Download data for the period covering the start of the school term
getSymbols("DGS30", src = "FRED", from = "2024-03-01", to = "2024-04-15") # 30-year Treasury bond
getSymbols("DTB3", src = "FRED", from = "2024-03-01", to = "2024-04-15") # 13-week T-bill
# Extract yields at the start of the school term
long_term_yield <- na.omit(DGS30[start_date] / 100) # Convert to percentage
short_term_yield <- na.omit(DTB3[start_date] / 100) # Convert to percentage
# Calculate the difference
yield_difference <- first(long_term_yield) - first(short_term_yield)
# Store results in the data frame
results <- rbind(results, data.frame(
Date = format(start_date, "%B %d, %Y"),
`30-Year Treasury Bond Yield (%)` = round(first(long_term_yield) * 100, 2),
`13-Week T-Bill Yield (%)` = round(first(short_term_yield) * 100, 2),
`Yield Difference (30-Year - 13-Week) (%)` = round(yield_difference * 100, 2)
))
}, error = function(e) {
cat("Error retrieving data:", e$message, "\n")
})
# Part 7.8: Analyze the yield difference at the end of the school term
end_date <- as.Date("2024-10-30")
tryCatch({
# Download data for the period covering the end of the school term
getSymbols("DGS30", src = "FRED", from = "2024-09-01", to = "2024-11-01") # 30-year Treasury bond
getSymbols("DTB3", src = "FRED", from = "2024-09-01", to = "2024-11-01") # 13-week T-bill
# Extract yields at the end of the school term
long_term_yield <- na.omit(DGS30[end_date] / 100) # Convert to percentage
short_term_yield <- na.omit(DTB3[end_date] / 100) # Convert to percentage
# Calculate the difference
yield_difference <- first(long_term_yield) - first(short_term_yield)
# Store results in the data frame
results <- rbind(results, data.frame(
Date = format(end_date, "%B %d, %Y"),
`30-Year Treasury Bond Yield (%)` = round(first(long_term_yield) * 100, 2),
`13-Week T-Bill Yield (%)` = round(first(short_term_yield) * 100, 2),
`Yield Difference (30-Year - 13-Week) (%)` = round(yield_difference * 100, 2)
))
}, error = function(e) {
cat("Error retrieving data:", e$message, "\n")
})
# Display the results as a kable table
kable(results, caption = "Comparison of Treasury Bond and T-Bill Yields")
Comparison of Treasury Bond and T-Bill Yields
| 2024-04-01 |
April 01, 2024 |
4.47 |
5.23 |
-0.76 |
| 2024-10-30 |
October 30, 2024 |
4.49 |
4.47 |
0.02 |
L7.9
At the beginning of the school term (April 1, 2024), the yield curve
was inverted, with the 13-week T-bill yield (5.23%) higher than the
30-year Treasury bond yield (4.47%), indicating concerns about a
potential economic slowdown and a preference for longer-term bonds due
to anticipated lower future interest rates. By the end of the term
(October 30, 2024), the yield curve became slightly upward-sloping, with
the 30-year yield (4.49%) slightly higher than the 13-week yield
(4.47%). This shift suggests an improvement in market sentiment and
expectations for economic growth, signaling that investors expected
interest rates to rise and the economy to remain stable.
L7.10
# Load the necessary package
library(quantmod)
# Get the federal funds rate from FRED
getSymbols("FEDFUNDS", src = "FRED")
[1] "FEDFUNDS"
# Filter data for the relevant dates
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30")
federal_funds_filtered <- FEDFUNDS[paste(start_date, end_date, sep = "/")]
# Plot the filtered federal funds rate data
plot(federal_funds_filtered,
main = "Federal Funds Rate from April 1, 2024 to October 30, 2024",
col = "blue",
lwd = 2,
xlab = "Date",
ylab = "Federal Funds Rate (%)")
L7.11
The movements in interest rates during the school term were likely
influenced by the Fed’s monetary policy, as changes in the federal funds
rate are a primary tool for managing economic conditions. If the federal
funds rate was adjusted during this period, it suggests the Fed was
actively responding to economic indicators and influencing market
interest rates. However, if no significant changes were made to the
federal funds rate, other factors, such as market expectations, economic
growth, or global economic conditions, might have contributed to the
observed movements in interest rates.
It’s important to note that these factors can interact and influence
each other. For example, a change in the federal funds rate can impact
market expectations, which in turn can affect other interest rates.
L7.12
library(quantmod)
library(knitr)
# Define the start and end dates for the school term
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30")
# Retrieve data from FRED
tryCatch({
getSymbols("DCPF3M", src = "FRED", from = start_date, to = end_date) # 90-day commercial paper yield
getSymbols("DTB3", src = "FRED", from = start_date, to = end_date) # 13-week Treasury bills
# Extract yields at the end of the school term
commercial_paper_yield <- na.omit(DCPF3M[end_date] / 100) # Convert to percentage
t_bill_yield <- na.omit(DTB3[end_date] / 100) # Convert to percentage
# Calculate the yield difference (premium)
yield_difference <- first(commercial_paper_yield) - first(t_bill_yield)
# Create a data frame for displaying results
result <- data.frame(
Date = as.character(end_date),
`90-day Commercial Paper Yield (%)` = round(first(commercial_paper_yield) * 100, 2),
`13-week T-Bill Yield (%)` = round(first(t_bill_yield) * 100, 2),
`Yield Premium (%)` = round(yield_difference * 100, 2)
)
# Display results using kable
kable(result, caption = "Results for the End of the School Term")
}, error = function(e) {
# Error handling
cat("Error retrieving data:", e$message, "\n")
})
Results for the End of the School Term
| 2024-10-30 |
2024-10-30 |
4.65 |
4.47 |
0.18 |
The difference between the yield on 90-day commercial paper and
13-week T-bills is the premium associated with the increased risk of
holding commercial paper. This premium compensates investors for the
higher credit and liquidity risks relative to government securities.
L7.13
Even after attempting to find the closest available date to the
requested period, there was still no data for the 90-day commercial
paper yield and the 13-week T-bill yield for April 2024 or some similiar
date. This reinforces the conclusion that data for these specific dates
might not be reported or accessible in the FRED database or other
sources.
The premium difference between the 90-day commercial paper yield and
the 13-week T-bill yield reflects market conditions, including risk
perception, liquidity, and supply and demand. Typically, commercial
paper yields tend to be higher than T-bill yields due to the higher
credit risk associated with corporate issuers compared to the U.S.
government. This premium can change due to shifts in economic conditions
or policy changes, such as adjustments by the Federal Reserve to
interest rates or market liquidity crises.
L7.14
library(quantmod)
# Define the start and end dates for the school term
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30")
# Download high-quality corporate bond data (example: AAA-rated corporate bonds)
tryCatch({
getSymbols("BAMLC0A1CAAAEY", src = "FRED", from = "2024-03-30", to = "2024-05-15", auto.assign = TRUE)
high_quality_yield <- na.omit(BAMLC0A1CAAAEY) # Get the data and remove NAs
# Find the closest available data point at the start date
closest_date_start <- index(high_quality_yield)[which.min(abs(index(high_quality_yield) - start_date))]
high_quality_yield_on_start <- high_quality_yield[closest_date_start]
cat("High-quality corporate bond yield data downloaded successfully.\n")
}, error = function(e) {
cat("Error downloading high-quality corporate bond data:", e$message, "\n")
high_quality_yield_on_start <- NA
})
High-quality corporate bond yield data downloaded successfully.
# Download high-yield corporate bond data (example: junk bonds)
tryCatch({
getSymbols("BAMLH0A0HYM2EY", src = "FRED", from = "2024-09-01", to = "2024-10-31", auto.assign = TRUE)
high_yield_bond <- na.omit(BAMLH0A0HYM2EY) # Get the data and remove NAs
# Find the closest available data point at the end date
closest_date_end <- index(high_yield_bond)[which.min(abs(index(high_yield_bond) - end_date))]
high_yield_bond_on_end <- high_yield_bond[closest_date_end]
cat("High-yield corporate bond yield data downloaded successfully.\n")
}, error = function(e) {
cat("Error downloading high-yield corporate bond data:", e$message, "\n")
high_yield_bond_on_end <- NA
})
High-yield corporate bond yield data downloaded successfully.
# Display the results if the data is available
if (!is.na(high_quality_yield_on_start) && !is.na(high_yield_bond_on_end)) {
# Display the results
cat("\nHigh-quality corporate bond yield on April 1, 2024 (closest available):",
round(high_quality_yield_on_start, 4), "\n")
cat("High-yield corporate bond yield on October 30, 2024 (closest available):",
round(high_yield_bond_on_end, 4), "\n")
} else {
cat("Insufficient data to display the yields.\n")
}
High-quality corporate bond yield on April 1, 2024 (closest available): 4.9
High-yield corporate bond yield on October 30, 2024 (closest available): 6.93
The 2.03% difference between the yields on high-quality and
high-yield corporate bonds suggests that investors in October 2024 were
more cautious about taking on risk compared to April 2024. The higher
yield on high-yield bonds is compensation for the increased risk, which
could be driven by factors like economic uncertainty, changes in
interest rates, or shifts in investor sentiment.
L7.15
# Install and load necessary packages if not already installed
if (!require(quantmod)) install.packages("quantmod")
library(quantmod)
# Define dates for the beginning and end of the school term
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30")
# Download long-term Treasury bond yield data (e.g., 10-year Treasury yield)
tryCatch({
getSymbols("GS10", src = "FRED", from = start_date, to = end_date, auto.assign = TRUE)
long_term_treasury_yield <- na.omit(GS10) # Clean data by removing NAs
cat("Long-term Treasury bond yield data downloaded successfully.\n")
}, error = function(e) {
cat("Error downloading long-term Treasury bond yield data:", e$message, "\n")
})
Long-term Treasury bond yield data downloaded successfully.
# Ensure data is available and not empty
if (exists("long_term_treasury_yield") && nrow(long_term_treasury_yield) > 0) {
# Find the closest available date to the start and end dates
start_index <- which.min(abs(index(long_term_treasury_yield) - start_date))
end_index <- which.min(abs(index(long_term_treasury_yield) - end_date))
yield_start <- long_term_treasury_yield[start_index]
yield_end <- long_term_treasury_yield[end_index]
# Display the yields
cat("Long-term Treasury bond yield on the closest available date in April 2024:", round(yield_start, 2), "%\n")
cat("Long-term Treasury bond yield on the closest available date in October 2024:", round(yield_end, 2), "%\n")
} else {
cat("Data for long-term Treasury bond yields is not available.\n")
}
Long-term Treasury bond yield on the closest available date in April 2024: 4.54 %
Long-term Treasury bond yield on the closest available date in October 2024: 4.1 %
The yield on long-term Treasury bonds decreased from 4.54% in April
2024 to 4.1% in October 2024. This suggests that the interest rates for
newly issued bonds fell during the school term.
L7.16
# Install and load necessary packages if not already installed
if (!require(quantmod)) install.packages("quantmod")
library(quantmod)
# Define start and end dates for the school term
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30")
# Fetch Treasury bond yield data
treasury_yield <- tryCatch({
getSymbols("DGS10", src = "FRED", from = start_date - 30, to = end_date + 30, auto.assign = FALSE)
na.omit(DGS10)
}, error = function(e) {
cat("Error downloading Treasury bond yield data:", e$message, "\n")
NULL
})
# Fetch Corporate bond yield data
corporate_yield <- tryCatch({
getSymbols("BAMLC0A1CAAAEY", src = "FRED", from = start_date - 30, to = end_date + 30, auto.assign = FALSE)
na.omit(BAMLC0A1CAAAEY)
}, error = function(e) {
cat("Error downloading Corporate bond yield data:", e$message, "\n")
NULL
})
# Find closest dates for the start and end of the school term
if (!is.null(treasury_yield) && !is.null(corporate_yield)) {
treasury_start <- treasury_yield[index(treasury_yield) == max(index(treasury_yield[index(treasury_yield) <= start_date]))]
treasury_end <- treasury_yield[index(treasury_yield) == min(index(treasury_yield[index(treasury_yield) >= end_date]))]
corporate_start <- corporate_yield[index(corporate_yield) == max(index(corporate_yield[index(corporate_yield) <= start_date]))]
corporate_end <- corporate_yield[index(corporate_yield) == min(index(corporate_yield[index(corporate_yield) >= end_date]))]
# Display results
cat("Treasury bond yield at the beginning of the school term (closest available):", treasury_start, "%\n")
cat("Treasury bond yield at the end of the school term (closest available):", treasury_end, "%\n")
cat("Corporate bond yield at the beginning of the school term (closest available):", corporate_start, "%\n")
cat("Corporate bond yield at the end of the school term (closest available):", corporate_end, "%\n")
} else {
cat("Insufficient data for analysis.\n")
}
Treasury bond yield at the beginning of the school term (closest available): 4.33 %
Treasury bond yield at the end of the school term (closest available): 4.29 %
Corporate bond yield at the beginning of the school term (closest available): 4.9 %
Corporate bond yield at the end of the school term (closest available): 4.69 %
Treasury bond yields experienced a slight decline, driven by stable
inflation expectations and increased demand for safe-haven assets.
Corporate bond yields declined more significantly, reflecting improved
economic sentiment and reduced credit risk. Municipal bond yields likely
followed a trend closer to corporate bonds due to their tax-exempt
status and lower perceived credit risk.
L7.17
library(quantmod)
# Define start and end dates
start_date <- as.Date("2024-04-01")
end_date <- as.Date("2024-10-30")
# Fetch Treasury bond yields
tryCatch({
getSymbols("DGS10", src = "FRED", from = "2024-03-01", to = "2024-11-01")
treasury_yield_start <- last(na.omit(DGS10["2024-04-01"])) / 100
treasury_yield_end <- last(na.omit(DGS10["2024-10-30"])) / 100
cat("Treasury bond yields fetched successfully.\n")
}, error = function(e) {
cat("Error fetching Treasury bond yields:", e$message, "\n")
treasury_yield_start <- NA
treasury_yield_end <- NA
})
Treasury bond yields fetched successfully.
# Fetch High-Yield Corporate Bond yields
tryCatch({
getSymbols("BAMLH0A0HYM2EY", src = "FRED", from = "2024-03-01", to = "2024-11-01")
high_yield_start <- last(na.omit(BAMLH0A0HYM2EY["2024-04-01"])) / 100
high_yield_end <- last(na.omit(BAMLH0A0HYM2EY["2024-10-30"])) / 100
cat("High-yield corporate bond yields fetched successfully.\n")
}, error = function(e) {
cat("Error fetching High-Yield Corporate Bond yields:", e$message, "\n")
high_yield_start <- NA
high_yield_end <- NA
})
High-yield corporate bond yields fetched successfully.
# Calculate the premium on high-yield corporate bonds relative to Treasury bonds
if (!is.na(treasury_yield_start) && !is.na(high_yield_start)) {
premium_start <- high_yield_start - treasury_yield_start
} else {
premium_start <- NA
}
if (!is.na(treasury_yield_end) && !is.na(high_yield_end)) {
premium_end <- high_yield_end - treasury_yield_end
} else {
premium_end <- NA
}
# Display the data
cat("Treasury bond yield at the beginning of the school term:", round(treasury_yield_start, 4), "\n")
Treasury bond yield at the beginning of the school term: 0.0433
cat("High-yield corporate bond yield at the beginning of the school term:", round(high_yield_start, 4), "\n")
High-yield corporate bond yield at the beginning of the school term: 0.0758
cat("Premium on high-yield corporate bonds at the beginning of the school term:", round(premium_start, 4), "\n\n")
Premium on high-yield corporate bonds at the beginning of the school term: 0.0325
cat("Treasury bond yield at the end of the school term:", round(treasury_yield_end, 4), "\n")
Treasury bond yield at the end of the school term: 0.0429
cat("High-yield corporate bond yield at the end of the school term:", round(high_yield_end, 4), "\n")
High-yield corporate bond yield at the end of the school term: 0.0693
cat("Premium on high-yield corporate bonds at the end of the school term:", round(premium_end, 4), "\n")
Premium on high-yield corporate bonds at the end of the school term: 0.0264
the decrease in the premium highlights a shift in investor sentiment
and market dynamics over the school term, likely driven by improved
economic conditions and reduced credit risk perception. This change
emphasizes the interconnectedness of different segments of the bond
market.
L8 Portfolio - Markovitz
# Install and load necessary packages
if (!require(quantmod)) install.packages("quantmod")
if (!require(PerformanceAnalytics)) install.packages("PerformanceAnalytics")
if (!require(quadprog)) install.packages("quadprog")
library(quantmod)
library(PerformanceAnalytics)
library(quadprog)
# Step 1: Get historical data for selected assets
symbols <- c("AAPL", "MSFT", "GOOG") # Example tickers
start_date <- "2020-01-01"
end_date <- "2023-01-01"
getSymbols(symbols, from = start_date, to = end_date)
[1] "AAPL" "MSFT" "GOOG"
# Use adjusted closing prices
prices <- do.call(cbind, lapply(symbols, function(x) Ad(get(x))))
# Step 2: Calculate daily returns
returns <- na.omit(ROC(prices, type = "discrete"))
# Step 3: Calculate mean returns and covariance matrix
mean_returns <- colMeans(returns)
cov_matrix <- cov(returns)
# Step 4: Define the optimization problem
num_assets <- ncol(returns)
# Constraints: weights must sum to 1
Amat <- cbind(rep(1, num_assets), diag(num_assets)) # Equality and non-negativity
bvec <- c(1, rep(0, num_assets)) # Sum weights to 1, no short-selling
# Set risk-return trade-off (target expected return)
target_return <- mean(mean_returns)
# Minimize portfolio variance
opt_result <- solve.QP(Dmat = cov_matrix,
dvec = rep(0, num_assets),
Amat = Amat,
bvec = bvec,
meq = 1)
# Step 5: Extract optimal weights
optimal_weights <- opt_result$solution
# Step 6: Calculate portfolio expected return and variance
portfolio_return <- sum(optimal_weights * mean_returns)
portfolio_variance <- t(optimal_weights) %*% cov_matrix %*% optimal_weights
# Step 7: Display results
cat("Optimal Portfolio Weights:\n")
Optimal Portfolio Weights:
names(optimal_weights) <- symbols
print(optimal_weights)
AAPL MSFT GOOG
0.2396667 0.2882664 0.4720669
cat("\nPortfolio Expected Return:", round(portfolio_return, 4))
Portfolio Expected Return: 8e-04
cat("\nPortfolio Variance:", round(portfolio_variance, 4))
Portfolio Variance: 4e-04
cat("\nPortfolio Standard Deviation:", round(sqrt(portfolio_variance), 4))
Portfolio Standard Deviation: 0.0205
L9 Portfolio - CAMP
# Load necessary packages
library(quantmod)
library(PerformanceAnalytics)
# Get historical data for a stock and a market index (e.g., S&P 500)
getSymbols(c("AAPL", "^GSPC"), from = "2018-01-01", to = "2023-12-31")
[1] "AAPL" "GSPC"
# Calculate daily returns
stock_returns <- na.omit(ROC(AAPL[, 6]))
market_returns <- na.omit(ROC(GSPC[, 6]))
# Calculate beta (systematic risk)
beta <- CAPM.beta(Ra = stock_returns, Rb = market_returns)
# Assume a risk-free rate (e.g., 3-month Treasury bill rate)
risk_free_rate <- 0.03
# Calculate the expected return using CAPM
expected_return <- risk_free_rate + beta * (mean(market_returns) - risk_free_rate)
# Print the results
cat("Beta:", beta, "\n")
Beta: 1.217628
cat("Expected Return:", expected_return * 100, "%")
Expected Return: -0.606811 %
CAPM is focused on understanding the expected return of a single
asset in the context of the market and its risk, helping with asset
valuation and risk-adjusted return analysis. Markowitz’s Mean-Variance
Optimization is used to create an investment portfolio that balances
risk and return, helping investors determine the optimal combination of
assets to hold. The CAPM is more about determining how much return
should be expected given the market’s risk, while Markowitz’s model is
more about constructing a portfolio that optimizes return and minimizes
risk based on historical data. An equilibrium market provides the
foundation for understanding how assets should be priced, which is key
for CAPM, Markowitz’s portfolio theory, and multi-factor models. It
suggests that in an efficient and balanced market, investors cannot
achieve superior returns without bearing greater risk, and the
relationship between risk and return should be consistent with these
models.
L10 WACC
library(tidyverse)
library(quantmod)
library(TTR)
# Get Microsoft's stock data
getSymbols("MSFT")
[1] "MSFT"
# Market value of equity (market capitalization)
oustanding_shares <- 30000000 # Replace with actual value
market_cap <- last(MSFT$MSFT.Adjusted) * oustanding_shares
# Assumptions
cost_of_debt <- 0.03 # 3%
tax_rate <- 0.25 # 25% tax rate
beta <- 1.1 # Beta of Microsoft's stock
risk_free_rate <- 0.02 # 2% risk-free rate
market_risk_premium <- 0.06 # 6% market risk premium
# Calculate cost of equity using CAPM
cost_of_equity <- risk_free_rate + beta * market_risk_premium
# Assumed market value of debt
market_value_of_debt <- 100e9 # $100 billion
# Calculate total market value of capital
total_market_value <- market_cap + market_value_of_debt
# Calculate weights of debt and equity
weight_of_debt <- market_value_of_debt / total_market_value
weight_of_equity <- market_cap / total_market_value
# Calculate WACC
wacc <- (weight_of_debt * cost_of_debt * (1 - tax_rate)) + (weight_of_equity * cost_of_equity)
# Print the WACC
cat("WACC for Microsoft:", wacc * 100, "%")
WACC for Microsoft: 2.977346 %
L11 Derivatives
library(quantmod)
# Get S&P 500 data for the period, allowing for nearest available data
getSymbols("^GSPC", from = "2024-04-01", to = "2024-10-30")
[1] "GSPC"
# Find the closest available dates if exact dates are missing
start_date <- index(GSPC)[which.min(abs(index(GSPC) - as.Date("2024-04-01")))]
end_date <- index(GSPC)[which.min(abs(index(GSPC) - as.Date("2024-10-30")))]
# Extract adjusted closing prices for those dates
start_price <- as.numeric(Cl(GSPC[start_date]))
end_price <- as.numeric(Cl(GSPC[end_date]))
# Calculate contract value per point: $250
contract_value_start <- start_price * 250
contract_value_end <- end_price * 250
# Difference in dollar value
difference <- contract_value_end - contract_value_start
cat("Difference in dollar value:", difference)
Difference in dollar value: 147287.5
L11.2
# Initial margin invested (20% of contract value)
initial_investment <- 0.20 * contract_value_start
# Calculate return as a percentage
return_futures <- (difference / initial_investment) * 100 # Expressed as a percentage
cat("Return on futures position:", return_futures, "%")
Return on futures position: 56.17618 %
L11.3
# Number of months in the school term (e.g., 7 months from April 1 to October 30)
m <- 7
# Annualized return
annualized_return_futures <- return_futures * (12 / m)
cat("Annualized return on futures position:", annualized_return_futures, "%")
Annualized return on futures position: 96.30202 %
L11.4
# Example stock and option data for the specific dates
getSymbols("AAPL", from = "2024-04-01", to = "2024-10-30")
[1] "AAPL"
# Find the closest available dates if exact dates are missing
start_date_option <- index(AAPL)[which.min(abs(index(AAPL) - as.Date("2024-04-01")))]
end_date_option <- index(AAPL)[which.min(abs(index(AAPL) - as.Date("2024-10-30")))]
# Extract adjusted closing prices for the option dates
stock_start_price <- as.numeric(Cl(AAPL[start_date_option]))
stock_end_price <- as.numeric(Cl(AAPL[end_date_option]))
# Assume strike price and premium values (update with real data)
strike_price <- 150
premium_start <- 5 # Premium at the start
premium_end <- 10 # Premium at the end
# Return on the option if sold at the end
option_return <- ((premium_end - premium_start) / premium_start) * 100
cat("Return on the call option:", option_return, "%")
Return on the call option: 100 %
L11.5
# Annualize the return
annualized_return_option <- option_return * (12 / m)
cat("Annualized return on the call option:", annualized_return_option, "%")
Annualized return on the call option: 171.4286 %
L11.6
# Calculate stock return over the term
stock_return <- ((stock_end_price - stock_start_price) / stock_start_price) * 100
cat("Return on the stock:", stock_return, "%")
Return on the stock: 37.42869 %
L11.7
# Fixed rate agreed at the beginning
fixed_rate <- 0.06
# Floating rate at the end (e.g., T-bill rate)
floating_rate <- 0.05 # Example value
# Notional amount
notional_amount <- 10e6 # $10 million
# Amount owed and amount received
amount_owed <- fixed_rate * notional_amount
amount_received <- floating_rate * notional_amount
# Net result
net_result <- amount_received - amount_owed
cat("Net result from swap:", net_result)
L 11.8- 11.12 Measuring and explaining exchange rate movements
library(quantmod)
library(knitr)
# Define the currency pairs
currencies <- c("GBP/USD", "JPY/USD", "MXN/USD")
# Initialize a dataframe to store results
results <- data.frame(
Description = c(
"Exchange rate of the British pound (in $):",
"Exchange rate of the Japanese yen (in $):",
"Exchange rate of the Mexican peso (in $):"
),
BoT = NA,
EoT = NA,
Change = NA,
Direction = NA
)
# Define the specific dates for the school term
start_date <- "2024-04-01"
end_date <- "2024-10-30"
# Fetch exchange rate data
for (i in 1:length(currencies)) {
currency <- currencies[i]
# Convert format for Yahoo Finance (e.g., GBP/USD -> GBPUSD=X)
yahoo_symbol <- gsub("/", "", currency) %>% paste0("=X")
# Fetch data from Yahoo Finance
currency_data <- getSymbols(yahoo_symbol, src = "yahoo", from = "2024-01-01", to = Sys.Date(), auto.assign = FALSE)
# Get the rate closest to the start date
start_price <- Cl(currency_data)[which.min(abs(index(currency_data) - as.Date(start_date)))]
results$BoT[i] <- as.numeric(start_price)
# Get the rate closest to the end date
end_price <- Cl(currency_data)[which.min(abs(index(currency_data) - as.Date(end_date)))]
results$EoT[i] <- as.numeric(end_price)
# Calculate percentage change
results$Change[i] <- ((results$EoT[i] - results$BoT[i]) / results$BoT[i]) * 100
# Determine direction
results$Direction[i] <- ifelse(results$Change[i] > 0, "Appreciated", "Depreciated")
}
# Calculate per unit gain/loss for British Pound futures
gbp_futures_gain_per_unit <- results$EoT[1] - results$BoT[1]
# Given a single futures contract represents 62,500 pounds
gbp_futures_total_gain <- gbp_futures_gain_per_unit * 62500
# Add futures results to the table
futures_results <- data.frame(
Description = c("Per Unit Gain/Loss for GBP Futures:", "Total Dollar Gain/Loss for GBP Futures:"),
BoT = c(gbp_futures_gain_per_unit, gbp_futures_total_gain),
EoT = c(NA, NA),
Change = c(NA, NA),
Direction = c(NA, NA)
)
# Combine results for display
final_results <- rbind(results, futures_results)
# Display the table
kable(
final_results,
col.names = c("Description", "BoT (04/01/2024)", "EoT (10/30/2024)", "Change (%)", "Direction"),
caption = "Currency Exchange Rates and GBP Futures"
)
Currency Exchange Rates and GBP Futures
| Exchange rate of the British pound (in $): |
1.2545477 |
1.3014055 |
3.735038 |
Appreciated |
| Exchange rate of the Japanese yen (in $): |
0.0065971 |
0.0065243 |
-1.104563 |
Depreciated |
| Exchange rate of the Mexican peso (in $): |
0.0602090 |
0.0498659 |
-17.178700 |
Depreciated |
| Per Unit Gain/Loss for GBP Futures: |
0.0468578 |
NA |
NA |
NA |
| Total Dollar Gain/Loss for GBP Futures: |
2928.6146164 |
NA |
NA |
NA |
L12 Capital requirements
library(tidyverse)
library(knitr) # For creating tables
# Input data: RWAs (in billions)
rwa_boa <- data.frame(
Risk = c("Credit", "Market", "Operational"),
RWA = c(1580, 71, 361)
)
rwa_db <- data.frame(
Risk = c("Credit", "Market", "Operational"),
RWA = c(265.8, 21.5, 57.2)
)
# Define CET1 ratios
cet1_ratio_boa <- 0.135 # Bank of America
cet1_ratio_db <- 0.137 # Deutsche Bank
# Calculate CET1 capital requirements
rwa_boa <- rwa_boa %>%
mutate(CET1_Ratio = cet1_ratio_boa,
CET1_Requirement = RWA * cet1_ratio_boa)
rwa_db <- rwa_db %>%
mutate(CET1_Ratio = cet1_ratio_db,
CET1_Requirement = RWA * cet1_ratio_db)
# Combine results
combined_results <- bind_rows(
rwa_boa %>% mutate(Bank = "Bank of America"),
rwa_db %>% mutate(Bank = "Deutsche Bank")
)
# Format table
kable(
combined_results,
col.names = c("Risk Type", "RWA (Billion)", "CET1 Ratio", "CET1 Requirement (Billion)", "Bank"),
caption = "CET1 Capital Requirements and Ratios for Bank of America and Deutsche Bank"
)
CET1 Capital Requirements and Ratios for Bank of America and
Deutsche Bank
| Credit |
1580.0 |
0.135 |
213.3000 |
Bank of America |
| Market |
71.0 |
0.135 |
9.5850 |
Bank of America |
| Operational |
361.0 |
0.135 |
48.7350 |
Bank of America |
| Credit |
265.8 |
0.137 |
36.4146 |
Deutsche Bank |
| Market |
21.5 |
0.137 |
2.9455 |
Deutsche Bank |
| Operational |
57.2 |
0.137 |
7.8364 |
Deutsche Bank |
Bank of America has significantly larger RWAs for credit and
operational risks compared to Deutsche Bank, reflecting its larger
global footprint. BoA’s CET1 ratio (13.5%) is comparable to Deutsche
Bank’s (13.7%), but the absolute amount of required capital is higher
for BoA due to its larger scale. Deutsche Bank has a more efficient use
of its capital relative to risk exposure, with a robust CET1 ratio
exceeding regulatory requirements.
LS0tCnRpdGxlOiAiT2JsaWdhdG9yeSBleGVyc2lzZSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKSnVzdHVzIEtydXBwLCBHZXJtYW55CgojIyBBdXRob3LigJlzIFN0YXRlbWVudCBvbiB0aGUgVXNlIG9mIEFJIFRvb2xzIGFuZCBQbGF0Zm9ybXMgRHVyaW5nIHRoZSBBc3NpZ25tZW50CgoKVG8gY29tcGxldGUgdGhpcyBhc3NpZ25tZW50LCBJIHVzZWQgYSB2YXJpZXR5IG9mIHRvb2xzIGFuZCBwbGF0Zm9ybXMgdG8gY29sbGVjdCBkYXRhLCBhbmFseXplIGl0LCBhbmQgcHJlc2VudCBteSBmaW5kaW5ncy4gSGVyZeKAmXMgYSBzdW1tYXJ5IG9mIHdoYXQgSSB1c2VkIGFuZCBob3c6CgpUb29scyBhbmQgUGxhdGZvcm1zIFVzZWQKCkNoYXRHUFQgKE9wZW5BSSk6IEFzc2lzdGVkIHdpdGggZHJhZnRpbmcgYW5zd2VycywgZXhwbGFpbmluZyBjb25jZXB0cywgYW5kIGNyZWF0aW5nIGNvZGUgZm9yIGFuYWx5c2lzLiBXZWJzaXRlOiBodHRwczovL2NoYXQub3BlbmFpLmNvbQoKR2VtaW5pOiBIZWxwZWQgZmluZCBzb2x1dGlvbnMgd2hlbiBJIGZhY2VkIGRhdGEgaXNzdWVzIG9yIGVycm9ycyBpbiBteSBjb2RlLiBXZWJzaXRlOiBodHRwczovL2dlbWluaS5nb29nbGUuY29tL2FwcAoKUXVhbnRtb2QgYW5kIEZSRURSOiBQcm92aWRlZCBmaW5hbmNpYWwgZGF0YSwgc3VjaCBhcyBzdG9jayBtYXJrZXQgcHJpY2VzIGFuZCBpbnRlcmVzdCByYXRlcy4gaHR0cHM6Ly93d3cucXVhbnRtb2QuY29tLyAgaHR0cHM6Ly9mcmVkLnN0bG91aXNmZWQub3JnLwoKUXVhbmRsOiBVc2VkIGZvciBhZGRpdGlvbmFsIGVjb25vbWljIGFuZCBmaW5hbmNpYWwgZGF0YS4KaHR0cHM6Ly9kYXRhLm5hc2RhcS5jb20vcHVibGlzaGVycy9RREwKClBvc2l0IENsb3VkIChmb3JtZXJseSBSU3R1ZGlvIENsb3VkKTogVXNlZCB0byB3cml0ZSBhbmQgcnVuIG15IFIgY29kZSBvbmxpbmUuIFdlYnNpdGU6IGh0dHBzOi8vcG9zaXQuY2xvdWQKClJQdWJzOiBVc2VkIHRvIHNoYXJlIHRoZSByZXBvcnQgaW4gYSBzaW1wbGUsIGVhc3ktdG8tdmlldyBmb3JtYXQuIFdlYnNpdGU6IGh0dHBzOi8vcnB1YnMuY29tCgpIb3cgSSBVc2VkIFRoZXNlIFRvb2xzOgoKRGF0YSBDb2xsZWN0aW9uOiBJIGdhdGhlcmVkIGRhdGEgdXNpbmcgUXVhbnRtb2QsIEZSRURSLCBhbmQgUXVhbmRsLgoKQ29kaW5nIGFuZCBBbmFseXNpczogSSB3cm90ZSBhbmQgdGVzdGVkIFIgY29kZSBpbiBQb3NpdCBDbG91ZCB0byBwcm9jZXNzIGFuZCBhbmFseXplIHRoZSBkYXRhLgoKU2hhcmluZzogSSB1c2VkIFJQdWJzIHRvIHNoYXJlIG15IHJlcG9ydC4KCkNoYWxsZW5nZXMgYW5kIFNvbHV0aW9uczoKSSBmYWNlZCBzb21lIGNoYWxsZW5nZXMgbGlrZSBkYXRhIGJlaW5nIHVuYXZhaWxhYmxlIG9yIEFQSSBlcnJvcnMuIEZvciB0aGVzZSwgSSB1c2VkIENoYXRHUFQgYW5kIEdlbWluaSB0byBmaW5kIHNvbHV0aW9ucyBvciBhbHRlcm5hdGl2ZSBkYXRhIHNvdXJjZXMuIFBvc2l0IENsb3VkIG1hZGUgaXQgZWFzaWVyIHRvIHRlc3QgYW5kIHJ1biBteSBjb2RlLCBhbmQgUlB1YnMgYWxsb3dlZCBtZSB0byBzaGFyZSBteSBmaW5kaW5ncy4KCkVuc3VyaW5nIFF1YWxpdHk6CkkgZG91YmxlLWNoZWNrZWQgbXkgZGF0YSBzb3VyY2VzLCByZXZpZXdlZCBteSBjb2RlIGFuZCByZXN1bHRzIHRvIGF2b2lkIG1pc3Rha2VzLCBhbmQgbWFkZSBzdXJlIHRoZSByZXBvcnQgb24gUlB1YnMgd2FzIHN0cmFpZ2h0Zm9yd2FyZCBhbmQgZWFzeSB0byByZWFkLgoKUmVzcG9uc2liaWxpdHkgU3RhdGVtZW50OgpJIHRha2UgZnVsbCByZXNwb25zaWJpbGl0eSBmb3IgdGhlIGFjY3VyYWN5IG9mIG15IHdvcmsuIFdoaWxlIEFJIHRvb2xzIGFuZCBwbGF0Zm9ybXMgd2VyZSBoZWxwZnVsIGZvciBkYXRhIGNvbGxlY3Rpb24gYW5kIGFuYWx5c2lzLCBhbGwgaWRlYXMsIGV4cGxhbmF0aW9ucywgYW5kIHRoZSBmaW5hbCByZXBvcnQgd2VyZSBjcmVhdGVkIGJ5IG1lLgoKUHVibGljIEFjY2VzcyBMaWNlbnNlIFN0YXRlbWVudDoKVGhpcyBhc3NpZ25tZW50IGhhcyBiZWVuIHNoYXJlZCB1bmRlciBhIHB1YmxpYyBhY2Nlc3MgbGljZW5zZSB0byBlbnN1cmUgdGhhdCBvdGhlcnMgY2FuIHZpZXcsIHVzZSwgYW5kIGxlYXJuIGZyb20gdGhlIHdvcmsKCgoKCiMjIEwxIEludHJvCgpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShmcmVkcikKbGlicmFyeShrbml0cikKCiMgU2V0IHlvdXIgRlJFRCBBUEkga2V5CmZyZWRyX3NldF9rZXkoImJmNzM0YTc1NGRkYjQyYmZkOTFmMDZlMDIyNGFjN2RhIikKCiMgRnVuY3Rpb24gdG8gZmV0Y2ggc3RvY2sgaW5kZXggZGF0YSBmcm9tIFlhaG9vIEZpbmFuY2UgZm9yIHNwZWNpZmljIGRhdGVzCmdldF9wcmljZXMgPC0gZnVuY3Rpb24oc3ltYm9sLCBkYXRlMSwgZGF0ZTIpIHsKICBkYXRhIDwtIHRyeUNhdGNoKAogICAgZ2V0U3ltYm9scyhzeW1ib2wsIHNyYyA9ICJ5YWhvbyIsIGF1dG8uYXNzaWduID0gRkFMU0UsIGZyb20gPSBTeXMuRGF0ZSgpIC0gMzY1LCB0byA9IFN5cy5EYXRlKCkpLAogICAgZXJyb3IgPSBmdW5jdGlvbihlKSBOVUxMCiAgKQogIGlmICghaXMubnVsbChkYXRhKSkgewogICAgIyBDb252ZXJ0IHRvIGEgdGltZSBpbmRleCB0byBmaW5kIHRoZSBuZWFyZXN0IGF2YWlsYWJsZSBkYXRlcwogICAgYXZhaWxhYmxlX2RhdGVzIDwtIGluZGV4KGRhdGEpCiAgICBiZWdpbm5pbmdfZGF0ZSA8LSBhcy5EYXRlKGRhdGUxKQogICAgZW5kaW5nX2RhdGUgPC0gYXMuRGF0ZShkYXRlMikKICAgIAogICAgIyBGaW5kIHRoZSBjbG9zZXN0IGF2YWlsYWJsZSBkYXRlcwogICAgYmVnaW5uaW5nX2luZGV4IDwtIHdoaWNoLm1pbihhYnMoYXZhaWxhYmxlX2RhdGVzIC0gYmVnaW5uaW5nX2RhdGUpKQogICAgZW5kaW5nX2luZGV4IDwtIHdoaWNoLm1pbihhYnMoYXZhaWxhYmxlX2RhdGVzIC0gZW5kaW5nX2RhdGUpKQogICAgCiAgICBiZWdpbm5pbmdfcHJpY2UgPC0gYXMubnVtZXJpYyhDbChkYXRhKVtiZWdpbm5pbmdfaW5kZXhdKQogICAgZW5kaW5nX3ByaWNlIDwtIGFzLm51bWVyaWMoQ2woZGF0YSlbZW5kaW5nX2luZGV4XSkKICAgIAogICAgcmV0dXJuKGMoYmVnaW5uaW5nX3ByaWNlLCBlbmRpbmdfcHJpY2UpKQogIH0gZWxzZSB7CiAgICByZXR1cm4oYyhOQSwgTkEpKQogIH0KfQoKIyBGdW5jdGlvbiB0byBmZXRjaCBkYXRhIGZyb20gRlJFRCBmb3IgdGhlIHNwZWNpZmljIGRhdGVzIGFuZCBmaW5kIHRoZSBjbG9zZXN0IGF2YWlsYWJsZSBkYXRhCmdldF9mcmVkX3JhdGUgPC0gZnVuY3Rpb24oc2VyaWVzX2lkLCBkYXRlMSwgZGF0ZTIpIHsKICBkYXRhIDwtIHRyeUNhdGNoKAogICAgZnJlZHIoc2VyaWVzX2lkID0gc2VyaWVzX2lkLCBvYnNlcnZhdGlvbl9zdGFydCA9IFN5cy5EYXRlKCkgLSAzNjUsIG9ic2VydmF0aW9uX2VuZCA9IFN5cy5EYXRlKCkpLAogICAgZXJyb3IgPSBmdW5jdGlvbihlKSBOQQogICkKICAKICAjIEVuc3VyZSBkYXRhIGlzIGEgZGF0YSBmcmFtZSBhbmQgZmluZCB0aGUgY2xvc2VzdCBkYXRlcyBpZiBuZWNlc3NhcnkKICBpZiAoIWlzLm51bGwoZGF0YSkgJiYgaXMuZGF0YS5mcmFtZShkYXRhKSkgewogICAgYXZhaWxhYmxlX2RhdGVzIDwtIGFzLkRhdGUoZGF0YSRkYXRlKQogICAgYmVnaW5uaW5nX2RhdGUgPC0gYXMuRGF0ZShkYXRlMSkKICAgIGVuZGluZ19kYXRlIDwtIGFzLkRhdGUoZGF0ZTIpCiAgICAKICAgICMgRmluZCB0aGUgY2xvc2VzdCBhdmFpbGFibGUgZGF0ZXMKICAgIGJlZ2lubmluZ19pbmRleCA8LSB3aGljaC5taW4oYWJzKGF2YWlsYWJsZV9kYXRlcyAtIGJlZ2lubmluZ19kYXRlKSkKICAgIGVuZGluZ19pbmRleCA8LSB3aGljaC5taW4oYWJzKGF2YWlsYWJsZV9kYXRlcyAtIGVuZGluZ19kYXRlKSkKICAgIAogICAgYmVnaW5uaW5nX3JhdGUgPC0gZGF0YSR2YWx1ZVtiZWdpbm5pbmdfaW5kZXhdCiAgICBlbmRpbmdfcmF0ZSA8LSBkYXRhJHZhbHVlW2VuZGluZ19pbmRleF0KICAgIAogICAgcmV0dXJuKGMoYmVnaW5uaW5nX3JhdGUsIGVuZGluZ19yYXRlKSkKICB9IGVsc2UgewogICAgcmV0dXJuKGMoTkEsIE5BKSkKICB9Cn0KCiMgSW5pdGlhbGl6ZSBkYXRhIGZvciB0aGUgdGFibGUgd2l0aCBjb2x1bW4gbmFtZXMKdGFibGVfZGF0YSA8LSBkYXRhLmZyYW1lKAogIENhdGVnb3J5ID0gY2hhcmFjdGVyKCksCiAgQm9UID0gbnVtZXJpYygpLAogIEVvVCA9IG51bWVyaWMoKSwKICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKKQoKIyBGdW5jdGlvbiB0byBhZGQgcm93cyB0byB0aGUgdGFibGUKYWRkX3JvdyA8LSBmdW5jdGlvbihjYXRlZ29yeSwgZGF0YSkgewogIHRhYmxlX2RhdGEgPDwtIHJiaW5kKHRhYmxlX2RhdGEsIGRhdGEuZnJhbWUoCiAgICBDYXRlZ29yeSA9IGNhdGVnb3J5LAogICAgQm9UID0gZGF0YVsxXSwKICAgIEVvVCA9IGRhdGFbMl0sCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UKICApKQp9CgojIERhdGVzIHRvIHVzZSAoMDQvMDEvMjAyNCBhbmQgMTAvMzAvMjAyNCkKZGF0ZTEgPC0gIjIwMjQtMDQtMDEiCmRhdGUyIDwtICIyMDI0LTEwLTMwIgoKIyBBZGQgc3RvY2sgbWFya2V0IGRhdGEKYWRkX3JvdygiUyZQIDUwMCAoc3RvY2spIGluZGV4IGxldmVsOiIsIGdldF9wcmljZXMoIl5HU1BDIiwgZGF0ZTEsIGRhdGUyKSkKYWRkX3JvdygiTmFzZGFxIENvbXBvc2l0ZSAoc3RvY2spIGluZGV4IGxldmVsOiIsIGdldF9wcmljZXMoIl5JWElDIiwgZGF0ZTEsIGRhdGUyKSkKCiMgQWRkIGludGVyZXN0IHJhdGVzICh2aWEgRlJFRCkKYWRkX3JvdygiUHJpbWUgcmF0ZToiLCBnZXRfZnJlZF9yYXRlKCJNUFJJTUUiLCBkYXRlMSwgZGF0ZTIpKQphZGRfcm93KCJGZWRlcmFsIGZ1bmRzIHJhdGU6IiwgZ2V0X2ZyZWRfcmF0ZSgiREZGIiwgZGF0ZTEsIGRhdGUyKSkKYWRkX3JvdygiQ29tbWVyY2lhbCBwYXBlciByYXRlICg5MCBkYXlzKToiLCBnZXRfZnJlZF9yYXRlKCJDUDNNIiwgZGF0ZTEsIGRhdGUyKSkKYWRkX3JvdygiQ2VydGlmaWNhdGUgb2YgZGVwb3NpdCByYXRlICgzLW1vbnRoKToiLCBnZXRfZnJlZF9yYXRlKCJDRDNNIiwgZGF0ZTEsIGRhdGUyKSkKYWRkX3JvdygiVHJlYXN1cnkgYmlsbCByYXRlICgxMyB3ZWVrcyk6IiwgZ2V0X2ZyZWRfcmF0ZSgiVEIzTVMiLCBkYXRlMSwgZGF0ZTIpKQphZGRfcm93KCJUcmVhc3VyeSBiaWxsIHJhdGUgKDI2IHdlZWtzKToiLCBnZXRfZnJlZF9yYXRlKCJUQjZNUyIsIGRhdGUxLCBkYXRlMikpCgojIEFkZCBib25kIHlpZWxkcyAodmlhIEZSRUQpCmFkZF9yb3coIlRyZWFzdXJ5IGxvbmctdGVybSBib25kIHlpZWxkOiIsIGdldF9mcmVkX3JhdGUoIkdTMTAiLCBkYXRlMSwgZGF0ZTIpKQphZGRfcm93KCJDb3Jwb3JhdGUgKE1hc3RlcikgYm9uZCB5aWVsZDoiLCBnZXRfZnJlZF9yYXRlKCJCQUEiLCBkYXRlMSwgZGF0ZTIpKQphZGRfcm93KCJIaWdoLXlpZWxkIGNvcnBvcmF0ZSBib25kIHlpZWxkOiIsIGdldF9mcmVkX3JhdGUoIkJBTUxIMEEwSFlNMkVZIiwgZGF0ZTEsIGRhdGUyKSkKYWRkX3JvdygiVGF4LWV4ZW1wdCAoN+KAkzEyLXllYXIpIGJvbmQgeWllbGQ6IiwgZ2V0X2ZyZWRfcmF0ZSgiTVVOSU1NIiwgZGF0ZTEsIGRhdGUyKSkKCiMgRGlzcGxheSB0aGUgdGFibGUKa25pdHI6OmthYmxlKHRhYmxlX2RhdGEsIGNvbC5uYW1lcyA9IGMoIkNhdGVnb3J5IiwgIkJvVCAoMDQvMDEvMjAyNCkiLCAiRW9UICgxMC8zMC8yMDI0KSIpKQpgYGAKCgpMaWtlIHlvdSBzYWlkIGluIHRoZSBsZWN0dXJlLCBzb21lIGZpbmFuY2lhbCBkYXRhIG1heSBiZSB1bmF2YWlsYWJsZSBkdWUgdG8gZ2FwcyBpbiBoaXN0b3JpY2FsIHJlY29yZHMgb3IgbGltaXRlZCBjb3ZlcmFnZS4gRVRGcyBzZXJ2ZSBhcyBnb29kIHN1YnN0aXR1dGVzIGJlY2F1c2UgdGhleSBwcm92aWRlIGNvbnNpc3RlbnQsIHJlbGlhYmxlIGRhdGEgYW5kIHJlcHJlc2VudCBhIGJyb2FkZXIgbWFya2V0LCBtYWtpbmcgdGhlbSBpZGVhbCBmb3IgZmlsbGluZyBpbiBtaXNzaW5nIGRhdGEgcG9pbnRzIGZvciBhbmFseXNpcy5XaGlsZSBFVEZzIHByb3ZpZGUgdXNlZnVsIGFwcHJveGltYXRpb25zIGZvciBtaXNzaW5nIGRhdGEsIHRoZXkgZG9uJ3QgcmVwcmVzZW50IGV4YWN0IHBlcmNlbnRhZ2VzIG9yIHZhbHVlcyBvZiBzcGVjaWZpYyBpbmRpY2VzIG9yIGFzc2V0cy4gSW5zdGVhZCwgdGhleSBzaG93IGdlbmVyYWwgZGlmZmVyZW5jZXMgYW5kIGNoYW5nZXMsIHdoaWNoIGNhbiBzdGlsbCBiZSB2YWx1YWJsZSBmb3IgYW5hbHlzaXMuIAoKYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkoa25pdHIpCgojIEZ1bmN0aW9uIHRvIGZldGNoIEVURiBkYXRhIGZyb20gWWFob28gRmluYW5jZQpnZXRfZXRmX3ByaWNlcyA8LSBmdW5jdGlvbihzeW1ib2wsIGRhdGUxLCBkYXRlMikgewogIGRhdGEgPC0gdHJ5Q2F0Y2goCiAgICBnZXRTeW1ib2xzKHN5bWJvbCwgc3JjID0gInlhaG9vIiwgYXV0by5hc3NpZ24gPSBGQUxTRSwgZnJvbSA9ICIyMDIzLTAxLTAxIiwgdG8gPSBTeXMuRGF0ZSgpKSwKICAgIGVycm9yID0gZnVuY3Rpb24oZSkgTlVMTAogICkKICBpZiAoIWlzLm51bGwoZGF0YSkpIHsKICAgICMgRmlsdGVyIGRhdGEgZm9yIHRoZSBzcGVjaWZpYyBkYXRlcwogICAgZGF0YV9maWx0ZXJlZCA8LSBkYXRhW2RhdGUxIDw9IGluZGV4KGRhdGEpICYgaW5kZXgoZGF0YSkgPD0gZGF0ZTJdCiAgICBpZiAobnJvdyhkYXRhX2ZpbHRlcmVkKSA+IDApIHsKICAgICAgYmVnaW5uaW5nX3ByaWNlIDwtIGFzLm51bWVyaWMoZmlyc3QoQ2woZGF0YV9maWx0ZXJlZCkpKQogICAgICBlbmRpbmdfcHJpY2UgPC0gYXMubnVtZXJpYyhsYXN0KENsKGRhdGFfZmlsdGVyZWQpKSkKICAgICAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBjaGFuZ2UKICAgICAgcGVyY2VudF9jaGFuZ2UgPC0gKChlbmRpbmdfcHJpY2UgLSBiZWdpbm5pbmdfcHJpY2UpIC8gYmVnaW5uaW5nX3ByaWNlKSAqIDEwMAogICAgICByZXR1cm4oYyhiZWdpbm5pbmdfcHJpY2UsIGVuZGluZ19wcmljZSwgcGVyY2VudF9jaGFuZ2UpKQogICAgfSBlbHNlIHsKICAgICAgcmV0dXJuKGMoTkEsIE5BLCBOQSkpCiAgICB9CiAgfSBlbHNlIHsKICAgIHJldHVybihjKE5BLCBOQSwgTkEpKQogIH0KfQoKIyBJbml0aWFsaXplIGRhdGEgZm9yIHRoZSB0YWJsZQp0YWJsZV9kYXRhIDwtIGRhdGEuZnJhbWUoCiAgQm9UID0gY2hhcmFjdGVyKCksCiAgRW9UID0gY2hhcmFjdGVyKCksCiAgQ2hhbmdlX1BlcmNlbnRhZ2UgPSBjaGFyYWN0ZXIoKQopCgojIEZ1bmN0aW9uIHRvIGFkZCByb3dzIHRvIHRoZSB0YWJsZQphZGRfcm93IDwtIGZ1bmN0aW9uKGNhdGVnb3J5LCBkYXRhKSB7CiAgdGFibGVfZGF0YSA8PC0gcmJpbmQodGFibGVfZGF0YSwgZGF0YS5mcmFtZSgKICAgIEJvVCA9IGNhdGVnb3J5LAogICAgRW9UID0gcGFzdGUoZGF0YVsxOjJdLCBjb2xsYXBzZSA9ICIsICIpLAogICAgQ2hhbmdlX1BlcmNlbnRhZ2UgPSByb3VuZChkYXRhWzNdLCAyKQogICkpCn0KCiMgQWRkIEVURiBkYXRhIGZvciBtaXNzaW5nIHJhdGVzCiMgQ29tbWVyY2lhbCBwYXBlciByYXRlICg5MCBkYXlzKSAtPiBVc2UgYSBzaG9ydC10ZXJtIGJvbmQgRVRGIGxpa2UgU0hWIChpU2hhcmVzIFNob3J0IFRyZWFzdXJ5IEJvbmQgRVRGKQphZGRfcm93KCJDb21tZXJjaWFsIHBhcGVyIHJhdGUgKDkwIGRheXMpOiIsIGdldF9ldGZfcHJpY2VzKCJTSFYiLCAiMjAyNC0wNC0wMSIsICIyMDI0LTEwLTMwIikpCgojIENlcnRpZmljYXRlIG9mIGRlcG9zaXQgcmF0ZSAoMy1tb250aCkgLT4gVXNlIGEgc2hvcnQtdGVybSBib25kIEVURiBsaWtlIEJTViAoVmFuZ3VhcmQgU2hvcnQtVGVybSBCb25kIEVURikKYWRkX3JvdygiQ2VydGlmaWNhdGUgb2YgZGVwb3NpdCByYXRlICgzLW1vbnRoKToiLCBnZXRfZXRmX3ByaWNlcygiQlNWIiwgIjIwMjQtMDQtMDEiLCAiMjAyNC0xMC0zMCIpKQoKIyBUYXgtZXhlbXB0ICg34oCTMTIteWVhcikgYm9uZCB5aWVsZCAtPiBVc2UgYSBtdW5pY2lwYWwgYm9uZCBFVEYgbGlrZSBNVUIgKGlTaGFyZXMgTmF0aW9uYWwgTXVuaSBCb25kIEVURikKYWRkX3JvdygiVGF4LWV4ZW1wdCAoN+KAkzEyLXllYXIpIGJvbmQgeWllbGQ6IiwgZ2V0X2V0Zl9wcmljZXMoIk1VQiIsICIyMDI0LTA0LTAxIiwgIjIwMjQtMTAtMzAiKSkKCiMgRGlzcGxheSB0aGUgdGFibGUKa25pdHI6OmthYmxlKHRhYmxlX2RhdGEsIGNvbC5uYW1lcyA9IGMoIkNhdGVnb3J5IiwgIkJvVCAoMDQvMDEvMjAyNCksIEVvVCAoMTAvMzAvMjAyNCkiLCAiQ2hhbmdlICglKSIpKQpgYGAKCiMjIFVzZSBzdG9jayBleGNoYW5nZSBxdW90YXRpb25zIHRvIHJlY29yZCB0aGUgc3RvY2sgcHJpY2UgYW5kIGRpdmlkZW5kIG9mIG9uZSBzdG9jayBmcm9tIGVhY2ggc3RvY2sgZXhjaGFuZ2UgaW4gd2hpY2ggeW91IHdvdWxkIGxpa2UgdG8gaW52ZXN0LgoKYGBge3J9CgpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBEZWZpbmUgdGhlIHN0b2NrcwpzdG9ja3MgPC0gYygiS08iLCAiTlZEQSIpICMgQ29jYS1Db2xhIChLTykgYW5kIE5WSURJQSAoTlZEQSkKCiMgSW5pdGlhbGl6ZSBhIGRhdGFmcmFtZSB0byBzdG9yZSByZXN1bHRzCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBFeGNoYW5nZSA9IGMoIk5ZU0UiLCAiTmFzZGFxIiksCiAgU3RvY2sgPSBzdG9ja3MsCiAgTGF0ZXN0X1ByaWNlID0gTkEsCiAgTGF0ZXN0X0FubnVhbF9EaXZpZGVuZCA9IE5BCikKCiMgRmV0Y2ggZGF0YSBmb3IgZWFjaCBzdG9jawpmb3IgKGkgaW4gMTpsZW5ndGgoc3RvY2tzKSkgewogIHN0b2NrIDwtIHN0b2Nrc1tpXQogIAogICMgRmV0Y2ggc3RvY2sgZGF0YQogIGdldFN5bWJvbHMoc3RvY2ssIHNyYyA9ICJ5YWhvbyIsIGF1dG8uYXNzaWduID0gVFJVRSkKICAKICAjIEdldCB0aGUgbGF0ZXN0IGNsb3NpbmcgcHJpY2UKICBzdG9ja19kYXRhIDwtIGdldChzdG9jaykKICByZXN1bHRzJExhdGVzdF9QcmljZVtpXSA8LSBhcy5udW1lcmljKENsKHN0b2NrX2RhdGFbbnJvdyhzdG9ja19kYXRhKV0pKQogIAogICMgRmV0Y2ggZGl2aWRlbmQgZGF0YQogIGRpdmlkZW5kX2RhdGEgPC0gZ2V0RGl2aWRlbmRzKHN0b2NrLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQogIAogIGlmIChucm93KGRpdmlkZW5kX2RhdGEpID4gMCkgewogICAgIyBHZXQgdGhlIG1vc3QgcmVjZW50IGRpdmlkZW5kIHBheW1lbnQKICAgIGxhdGVzdF9kaXZpZGVuZCA8LSBhcy5udW1lcmljKHRhaWwoZGl2aWRlbmRfZGF0YSwgMSkpCiAgICAKICAgICMgQXNzdW1lIHF1YXJ0ZXJseSBkaXZpZGVuZHMgYW5kIGNhbGN1bGF0ZSB0aGUgYW5udWFsaXplZCBkaXZpZGVuZAogICAgcmVzdWx0cyRMYXRlc3RfQW5udWFsX0RpdmlkZW5kW2ldIDwtIGxhdGVzdF9kaXZpZGVuZCAqIDQKICB9IGVsc2UgewogICAgcmVzdWx0cyRMYXRlc3RfQW5udWFsX0RpdmlkZW5kW2ldIDwtIDAKICB9Cn0KCiMgRGlzcGxheSB0aGUgdGFibGUgd2l0aCBrbml0cjo6a2FibGUoKQprYWJsZSgKICByZXN1bHRzLAogIGNvbC5uYW1lcyA9IGMoIlN0b2NrIEV4Y2hhbmdlIiwgIlN0b2NrIFRpY2tlciIsICJMYXRlc3QgUHJpY2UiLCAiQW5udWFsaXplZCBEaXZpZGVuZCIpLAogIGNhcHRpb24gPSAiU3RvY2sgUHJpY2VzIGFuZCBEaXZpZGVuZHMgZm9yIENvY2EtQ29sYSAoTllTRSkgYW5kIE5WSURJQSAoTmFzZGFxKSIKKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBEZWZpbmUgRVRGcyBhcyBwcm94aWVzIGZvciBmdXR1cmVzCiMgVExUOiBUcmVhc3VyeSBCb25kcywgU1BZOiBTJlAgNTAwLCBRUVE6IE5hc2RhcSwgRlhCOiBCcml0aXNoIFBvdW5kCnN5bWJvbHMgPC0gYygiVExUIiwgIlNQWSIsICJRUVEiLCAiRlhCIikgCgojIEluaXRpYWxpemUgYSBkYXRhZnJhbWUgdG8gc3RvcmUgcmVzdWx0cwpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjKCJUcmVhc3VyeSBCb25kIEZ1dHVyZXMiLCAiUyZQIDUwMCBJbmRleCBGdXR1cmVzIiwgIk5hc2RhcSBNYXJrZXQiLCAiQnJpdGlzaCBQb3VuZCBGdXR1cmVzIiksCiAgTGF0ZXN0X1ByaWNlID0gTkEsCiAgU2VwdF81XzIwMjRfUHJpY2UgPSBOQQopCgojIERlZmluZSB0aGUgc3BlY2lmaWMgZGF0ZSB0byBmZXRjaCAoU2VwdGVtYmVyIDV0aCwgMjAyNCkKc3BlY2lmaWNfZGF0ZSA8LSAiMjAyNC0wOS0wNSIKCiMgRmV0Y2ggZGF0YSBmb3IgZWFjaCBzeW1ib2wKZm9yIChpIGluIDE6bGVuZ3RoKHN5bWJvbHMpKSB7CiAgc3ltYm9sIDwtIHN5bWJvbHNbaV0KICAKICAjIEZldGNoIGRhdGEgKGVudGlyZSB5ZWFyIGZvciBzYWZldHkpCiAgZ2V0U3ltYm9scyhzeW1ib2wsIHNyYyA9ICJ5YWhvbyIsIGZyb20gPSAiMjAyMy0wMS0wMSIsIHRvID0gU3lzLkRhdGUoKSwgYXV0by5hc3NpZ24gPSBUUlVFKQogIAogICMgRXh0cmFjdCBzdG9jayBkYXRhCiAgc3RvY2tfZGF0YSA8LSBnZXQoc3ltYm9sKQogIAogICMgR2V0IHRoZSBsYXRlc3QgY2xvc2luZyBwcmljZQogIHJlc3VsdHMkTGF0ZXN0X1ByaWNlW2ldIDwtIGFzLm51bWVyaWMoQ2woc3RvY2tfZGF0YVtucm93KHN0b2NrX2RhdGEpXSkpCiAgCiAgIyBHZXQgdGhlIHByaWNlIG9uIHRoZSBzcGVjaWZpYyBkYXRlCiAgaWYgKHNwZWNpZmljX2RhdGUgJWluJSBpbmRleChzdG9ja19kYXRhKSkgewogICAgcmVzdWx0cyRTZXB0XzVfMjAyNF9QcmljZVtpXSA8LSBhcy5udW1lcmljKENsKHN0b2NrX2RhdGFbc3BlY2lmaWNfZGF0ZV0pKQogIH0gZWxzZSB7CiAgICByZXN1bHRzJFNlcHRfNV8yMDI0X1ByaWNlW2ldIDwtIE5BICAjIElmIG1hcmtldCBkYXRhIGlzIHVuYXZhaWxhYmxlCiAgfQp9CgojIERpc3BsYXkgdGhlIHRhYmxlIHdpdGgga25pdHI6OmthYmxlCmthYmxlKAogIHJlc3VsdHMsCiAgY29sLm5hbWVzID0gYygiRGVzY3JpcHRpb24iLCAiTGF0ZXN0IFByaWNlIiwgIlNlcHQgNSwgMjAyNCBQcmljZSIpLAogIGNhcHRpb24gPSAiU3RvY2sgUHJpY2VzIGZvciBGdXR1cmVzIFByb3hpZXMgKExhdGVzdCBhbmQgU2VwdCA1LCAyMDI0KSIKKQpgYGAKCgpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShrbml0cikKCiMgRmV0Y2ggVGVzbGEgc3RvY2sgZGF0YSB3aXRob3V0IG91dHB1dHRpbmcgc3ltYm9sIGluZm9ybWF0aW9uCnRlc2xhX2RhdGEgPC0gZ2V0U3ltYm9scygiVFNMQSIsIHNyYyA9ICJ5YWhvbyIsIGZyb20gPSAiMjAyMy0wMS0wMSIsIHRvID0gU3lzLkRhdGUoKSwgYXV0by5hc3NpZ24gPSBGQUxTRSkKCiMgTGF0ZXN0IGNsb3NpbmcgcHJpY2UKbGF0ZXN0X3ByaWNlIDwtIGFzLm51bWVyaWMobGFzdChDbCh0ZXNsYV9kYXRhKSkpCgojIFByaWNlIG9uIFNlcHRlbWJlciA1LCAyMDI0CnNwZWNpZmljX2RhdGUgPC0gIjIwMjQtMDktMDUiCnNlcHRfNV9wcmljZSA8LSBpZiAoc3BlY2lmaWNfZGF0ZSAlaW4lIGluZGV4KHRlc2xhX2RhdGEpKSBhcy5udW1lcmljKENsKHRlc2xhX2RhdGFbc3BlY2lmaWNfZGF0ZV0pKSAKIyBPcHRpb24gZGV0YWlscwpleHBpcmF0aW9uX21vbnRoIDwtICJEZWNlbWJlciAyMDI0IgpzdHJpa2VfcHJpY2UgPC0gMjUwCm9wdGlvbl9wcmVtaXVtX2JvdCA8LSAyMCAgIyBCZWdpbm5pbmcgb2YgVGVybQpvcHRpb25fcHJlbWl1bV9lb3QgPC0gOTQgICMgRW5kIG9mIFRlcm0KCiMgQ3JlYXRlIHRhYmxlCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBEZXNjcmlwdGlvbiA9IGMoIlRlc2xhIChUU0xBKSBTdG9jayIsICJPcHRpb24gRXhwaXJhdGlvbiBNb250aCIsICJPcHRpb24gU3RyaWtlIFByaWNlIiwgIk9wdGlvbiBQcmVtaXVtIiksCiAgQm9UID0gYyhzZXB0XzVfcHJpY2UsIGV4cGlyYXRpb25fbW9udGgsIHN0cmlrZV9wcmljZSwgb3B0aW9uX3ByZW1pdW1fYm90KSwKICBFb1QgPSBjKGxhdGVzdF9wcmljZSwgZXhwaXJhdGlvbl9tb250aCwgc3RyaWtlX3ByaWNlLCBvcHRpb25fcHJlbWl1bV9lb3QpCikKCiMgRGlzcGxheSB0YWJsZQprYWJsZSgKICByZXN1bHRzLAogIGNvbC5uYW1lcyA9IGMoIkRlc2NyaXB0aW9uIiwgIkJvVCAoQmVnaW5uaW5nIG9mIFRlcm0pIiwgIkVvVCAoRW5kIG9mIFRlcm0pIiksCiAgY2FwdGlvbiA9ICJUZXNsYSAoVFNMQSkgU3RvY2sgUHJpY2UgYW5kIE9wdGlvbiBEZXRhaWxzIChMYXRlc3QgYW5kIFNlcHRlbWJlciA1LCAyMDI0KSIKKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBEZWZpbmUgdGhlIGN1cnJlbmN5IHBhaXJzCmN1cnJlbmNpZXMgPC0gYygiR0JQL1VTRCIsICJKUFkvVVNEIiwgIk1YTi9VU0QiKQoKIyBJbml0aWFsaXplIGEgZGF0YWZyYW1lIHRvIHN0b3JlIHJlc3VsdHMKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIERlc2NyaXB0aW9uID0gYygKICAgICJFeGNoYW5nZSByYXRlIG9mIHRoZSBCcml0aXNoIHBvdW5kIChpbiAkKToiLAogICAgIkV4Y2hhbmdlIHJhdGUgb2YgdGhlIEphcGFuZXNlIHllbiAoaW4gJCk6IiwKICAgICJFeGNoYW5nZSByYXRlIG9mIHRoZSBNZXhpY2FuIHBlc28gKGluICQpOiIKICApLAogIEJvVCA9IE5BLAogIEVvVCA9IE5BCikKCiMgRGVmaW5lIHRoZSBzcGVjaWZpYyBkYXRlIChTZXB0ZW1iZXIgNXRoLCAyMDI0KQpzcGVjaWZpY19kYXRlIDwtICIyMDI0LTA5LTA1IgoKIyBGZXRjaCBleGNoYW5nZSByYXRlIGRhdGEKZm9yIChpIGluIDE6bGVuZ3RoKGN1cnJlbmNpZXMpKSB7CiAgY3VycmVuY3kgPC0gY3VycmVuY2llc1tpXQogIAogICMgQ29udmVydCBmb3JtYXQgZm9yIFlhaG9vIEZpbmFuY2UgKGUuZy4sIEdCUC9VU0QgLT4gR0JQVVNEPVgpCiAgeWFob29fc3ltYm9sIDwtIGdzdWIoIi8iLCAiIiwgY3VycmVuY3kpICU+JSBwYXN0ZTAoIj1YIikKICAKICAjIEZldGNoIGRhdGEgZnJvbSBZYWhvbyBGaW5hbmNlCiAgY3VycmVuY3lfZGF0YSA8LSBnZXRTeW1ib2xzKHlhaG9vX3N5bWJvbCwgc3JjID0gInlhaG9vIiwgZnJvbSA9ICIyMDIzLTAxLTAxIiwgdG8gPSBTeXMuRGF0ZSgpLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQogIAogICMgR2V0IHRoZSBsYXRlc3QgY2xvc2luZyByYXRlIChFb1QpCiAgcmVzdWx0cyRFb1RbaV0gPC0gYXMubnVtZXJpYyhsYXN0KENsKGN1cnJlbmN5X2RhdGEpKSkKICAKICAjIEdldCB0aGUgcmF0ZSBvbiBTZXB0ZW1iZXIgNXRoLCAyMDI0IChCb1QpCiAgaWYgKHNwZWNpZmljX2RhdGUgJWluJSBpbmRleChjdXJyZW5jeV9kYXRhKSkgewogICAgcmVzdWx0cyRCb1RbaV0gPC0gYXMubnVtZXJpYyhDbChjdXJyZW5jeV9kYXRhW3NwZWNpZmljX2RhdGVdKSkKICB9IGVsc2UgewogICAgcmVzdWx0cyRCb1RbaV0gPC0gTkEgICMgSWYgZGF0YSBpcyB1bmF2YWlsYWJsZQogIH0KfQoKIyBEaXNwbGF5IHRoZSB0YWJsZQprYWJsZSgKICByZXN1bHRzLAogIGNvbC5uYW1lcyA9IGMoIkRlc2NyaXB0aW9uIiwgIkJvVCAoU2VwdGVtYmVyIDUsIDIwMjQpIiwgIkVvVCAoTGF0ZXN0KSIpLAogIGNhcHRpb24gPSAiQ3VycmVuY3kgRXhjaGFuZ2UgUmF0ZXMgKEJyaXRpc2ggUG91bmQsIEphcGFuZXNlIFllbiwgYW5kIE1leGljYW4gUGVzbykiCikKYGBgCgpgYGB7cn0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMKbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShrbml0cikKCiMgRmV0Y2ggQ0hGL1VTRCBleGNoYW5nZSByYXRlIGRhdGEgZnJvbSBZYWhvbyBGaW5hbmNlCmN1cnJlbmN5X3N5bWJvbCA8LSAiQ0hGVVNEPVgiICAjIENIRi9VU0Qgc3ltYm9sIG9uIFlhaG9vIEZpbmFuY2UKCiMgRmV0Y2ggZGF0YSBmcm9tIFlhaG9vIEZpbmFuY2UKY3VycmVuY3lfZGF0YSA8LSBnZXRTeW1ib2xzKGN1cnJlbmN5X3N5bWJvbCwgc3JjID0gInlhaG9vIiwgZnJvbSA9ICIyMDIzLTAxLTAxIiwgdG8gPSBTeXMuRGF0ZSgpLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQoKIyBMYXRlc3QgdmFsdWUgb2YgdGhlIENIRi9VU0QgY3VycmVuY3kgcGFpcgpsYXRlc3RfdmFsdWUgPC0gYXMubnVtZXJpYyhsYXN0KENsKGN1cnJlbmN5X2RhdGEpKSkKCiMgUHJpY2Ugb24gU2VwdGVtYmVyIDUsIDIwMjQgKEJvVCkKc3BlY2lmaWNfZGF0ZSA8LSAiMjAyNC0wOS0wNSIKc2VwdF81X3ZhbHVlIDwtIGlmIChzcGVjaWZpY19kYXRlICVpbiUgaW5kZXgoY3VycmVuY3lfZGF0YSkpIGFzLm51bWVyaWMoQ2woY3VycmVuY3lfZGF0YVtzcGVjaWZpY19kYXRlXSkpIGVsc2UgTkEKCiMgRXN0aW1hdGUgdGhlIHN0cmlrZSBwcmljZSBmb3IgdGhlIG9wdGlvbiAoNSUgYWJvdmUgdGhlIGN1cnJlbnQgdmFsdWUpIHNpbmNlIENIRiBpcyBzdHJlbmd0aGVuaW5nCnN0cmlrZV9wcmljZSA8LSBsYXRlc3RfdmFsdWUgKiAxLjA1ICAjIEFzc3VtZSA1JSBhYm92ZSB0aGUgY3VycmVudCB2YWx1ZQoKIyBFc3RpbWF0aW5nIHRoZSBvcHRpb24gcHJlbWl1bQojIFdlIHdpbGwgdXNlIGEgc2ltcGxlIG1ldGhvZCBhc3N1bWluZyBhIDEwJSB2b2xhdGlsaXR5IGZvciBDSEYvVVNELCB3aXRoIGEgdGltZSB0byBleHBpcmF0aW9uIG9mIGFib3V0IDIgbW9udGhzIChPY3QgMjAyNCkKaW1wbGllZF92b2xhdGlsaXR5IDwtIDAuMSAgIyBBc3N1bWVkIHZvbGF0aWxpdHkgZm9yIGN1cnJlbmN5IG9wdGlvbnMgKDEwJSkKdGltZV90b19leHBpcmF0aW9uIDwtIDIgLyAxMiAgIyAyIG1vbnRocyB0byBleHBpcmF0aW9uIChPY3RvYmVyIDIwMjQpCgojIFVzaW5nIGEgc2ltcGxpZmllZCBCbGFjay1TY2hvbGVzLWxpa2UgbW9kZWwgdG8gZXN0aW1hdGUgdGhlIG9wdGlvbiBwcmVtaXVtIChub3QgcHJlY2lzZSBidXQgZ2l2ZXMgYW4gaWRlYSkKIyBGb3JtdWxhOiBPcHRpb24gUHJlbWl1bSA9IFNwb3QgUHJpY2UgKiBOKGQxKSAtIFN0cmlrZSBQcmljZSAqIGV4cCgtcip0KSAqIE4oZDIpCiMgSGVyZSB3ZSdsbCBza2lwIHRoZSByaXNrLWZyZWUgcmF0ZSBhbmQgYXNzdW1lIGl0J3MgYSBjYWxsIG9wdGlvbiBmb3Igc2ltcGxpY2l0eQoKIyBCbGFjay1TY2hvbGVzIGNvbXBvbmVudHMKZDEgPC0gKGxvZyhsYXRlc3RfdmFsdWUgLyBzdHJpa2VfcHJpY2UpICsgKDAuNSAqIGltcGxpZWRfdm9sYXRpbGl0eV4yKSAqIHRpbWVfdG9fZXhwaXJhdGlvbikgLyAoaW1wbGllZF92b2xhdGlsaXR5ICogc3FydCh0aW1lX3RvX2V4cGlyYXRpb24pKQpkMiA8LSBkMSAtIGltcGxpZWRfdm9sYXRpbGl0eSAqIHNxcnQodGltZV90b19leHBpcmF0aW9uKQoKIyBOb3JtYWwgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChOKGQxKSBhbmQgTihkMikpCk4gPC0gZnVuY3Rpb24oeCkgeyBwbm9ybSh4KSB9CgojIEVzdGltYXRlIG9wdGlvbiBwcmVtaXVtIChzaW1wbGlmaWVkIGZvciBhIGN1cnJlbmN5IGNhbGwgb3B0aW9uKQpvcHRpb25fcHJlbWl1bSA8LSBsYXRlc3RfdmFsdWUgKiBOKGQxKSAtIHN0cmlrZV9wcmljZSAqIGV4cCgtMC4wMiAqIHRpbWVfdG9fZXhwaXJhdGlvbikgKiBOKGQyKQoKIyBEaXNwbGF5IGVzdGltYXRlZCBvcHRpb24gcHJlbWl1bSBmb3IgQm9UIChTZXB0ZW1iZXIgNSwgMjAyNCkgYW5kIEVvVCAobGF0ZXN0KQojIEZvciBzaW1wbGljaXR5LCBsZXQncyBhc3N1bWUgdGhlIHByZW1pdW0gYXQgU2VwdGVtYmVyIDUsIDIwMjQgaXMgc2xpZ2h0bHkgbG93ZXIgZHVlIHRvIHRpbWUgZGVjYXkKCm9wdGlvbl9wcmVtaXVtX2JvdCA8LSBvcHRpb25fcHJlbWl1bSAqIDAuOTUgICMgQXNzdW1pbmcgdGhlIHByZW1pdW0gd2FzIHNsaWdodGx5IGxvd2VyIG9uIFNlcHRlbWJlciA1LCAyMDI0IGR1ZSB0byB0aW1lIGRlY2F5Cm9wdGlvbl9wcmVtaXVtX2VvdCA8LSBvcHRpb25fcHJlbWl1bSAgIyBMYXRlc3QgKEVvVCkgcHJlbWl1bSBpcyBvdXIgZXN0aW1hdGVkIHByZW1pdW0KCiMgQ3JlYXRlIHRoZSByZXN1bHRzIHRhYmxlCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBEZXNjcmlwdGlvbiA9IGMoIkN1cnJlbmN5IChDSEYvVVNEKSIsICJPcHRpb24gRXhwaXJhdGlvbiBNb250aCIsICJPcHRpb24gU3RyaWtlIFByaWNlIiwgIk9wdGlvbiBQcmVtaXVtIiksCiAgQm9UID0gYyhzZXB0XzVfdmFsdWUsICJEZXplbWJlciAyMDI0Iiwgc3RyaWtlX3ByaWNlLCBvcHRpb25fcHJlbWl1bV9ib3QpLAogIEVvVCA9IGMobGF0ZXN0X3ZhbHVlLCAiRGV6ZW1iZXIgMjAyNCIsIHN0cmlrZV9wcmljZSwgb3B0aW9uX3ByZW1pdW1fZW90KQopCgojIERpc3BsYXkgdGhlIHRhYmxlIHVzaW5nIGtuaXRyOjprYWJsZQprYWJsZSgKICByZXN1bHRzLAogIGNvbC5uYW1lcyA9IGMoIkRlc2NyaXB0aW9uIiwgIkJvVCAoQmVnaW5uaW5nIG9mIFRlcm0pIiwgIkVvVCAoRW5kIG9mIFRlcm0pIiksCiAgY2FwdGlvbiA9ICJDdXJyZW5jeSBPcHRpb24gRGV0YWlscyAoQ0hGL1VTRCkgLSBCZWdpbm5pbmcgb2YgVGVybSAoU2VwdCA1LCAyMDI0KSB2cyBFbmQgb2YgVGVybSAoTGF0ZXN0KSIKKQpgYGAKCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcwpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBGZXRjaCBBVUQvVVNEIGV4Y2hhbmdlIHJhdGUgZGF0YSBmcm9tIFlhaG9vIEZpbmFuY2UKY3VycmVuY3lfc3ltYm9sIDwtICJBVURVU0Q9WCIgICMgQVVEL1VTRCBzeW1ib2wgb24gWWFob28gRmluYW5jZQoKIyBGZXRjaCBkYXRhIGZyb20gWWFob28gRmluYW5jZQpjdXJyZW5jeV9kYXRhIDwtIGdldFN5bWJvbHMoY3VycmVuY3lfc3ltYm9sLCBzcmMgPSAieWFob28iLCBmcm9tID0gIjIwMjMtMDEtMDEiLCB0byA9IFN5cy5EYXRlKCksIGF1dG8uYXNzaWduID0gRkFMU0UpCgojIExhdGVzdCB2YWx1ZSBvZiB0aGUgQVVEL1VTRCBjdXJyZW5jeSBwYWlyCmxhdGVzdF92YWx1ZSA8LSBhcy5udW1lcmljKGxhc3QoQ2woY3VycmVuY3lfZGF0YSkpKQoKIyBQcmljZSBvbiBTZXB0ZW1iZXIgNSwgMjAyNCAoQm9UKQpzcGVjaWZpY19kYXRlIDwtICIyMDI0LTA5LTA1IgpzZXB0XzVfdmFsdWUgPC0gaWYgKHNwZWNpZmljX2RhdGUgJWluJSBpbmRleChjdXJyZW5jeV9kYXRhKSkgYXMubnVtZXJpYyhDbChjdXJyZW5jeV9kYXRhW3NwZWNpZmljX2RhdGVdKSkgZWxzZSBOQQoKIyBFc3RpbWF0ZSB0aGUgc3RyaWtlIHByaWNlIGZvciB0aGUgb3B0aW9uICg1JSBiZWxvdyB0aGUgY3VycmVudCB2YWx1ZSkgc2luY2UgQVVEIGlzIGV4cGVjdGVkIHRvIHdlYWtlbgpzdHJpa2VfcHJpY2UgPC0gbGF0ZXN0X3ZhbHVlICogMC45NSAgIyBBc3N1bWUgNSUgYmVsb3cgdGhlIGN1cnJlbnQgdmFsdWUgZm9yIGEgcHV0IG9wdGlvbgoKIyBFc3RpbWF0aW5nIHRoZSBvcHRpb24gcHJlbWl1bQojIFdlIHdpbGwgdXNlIHRoZSBzYW1lIG1ldGhvZCBhcyBhYm92ZSwgYXNzdW1pbmcgYSAxMCUgdm9sYXRpbGl0eSBmb3IgQVVEL1VTRCwgd2l0aCBhIHRpbWUgdG8gZXhwaXJhdGlvbiBvZiBhYm91dCAyIG1vbnRocyAoT2N0IDIwMjQpCmltcGxpZWRfdm9sYXRpbGl0eSA8LSAwLjEgICMgQXNzdW1lZCB2b2xhdGlsaXR5IGZvciBjdXJyZW5jeSBvcHRpb25zICgxMCUpCnRpbWVfdG9fZXhwaXJhdGlvbiA8LSAyIC8gMTIgICMgMiBtb250aHMgdG8gZXhwaXJhdGlvbiAoT2N0b2JlciAyMDI0KQoKIyBVc2luZyBhIHNpbXBsaWZpZWQgQmxhY2stU2Nob2xlcy1saWtlIG1vZGVsIHRvIGVzdGltYXRlIHRoZSBvcHRpb24gcHJlbWl1bSAobm90IHByZWNpc2UgYnV0IGdpdmVzIGFuIGlkZWEpCiMgRm9ybXVsYTogT3B0aW9uIFByZW1pdW0gPSBTcG90IFByaWNlICogTihkMSkgLSBTdHJpa2UgUHJpY2UgKiBleHAoLXIqdCkgKiBOKGQyKQojIEhlcmUgd2UnbGwgc2tpcCB0aGUgcmlzay1mcmVlIHJhdGUgYW5kIGFzc3VtZSBpdCdzIGEgcHV0IG9wdGlvbiBmb3Igc2ltcGxpY2l0eQoKIyBCbGFjay1TY2hvbGVzIGNvbXBvbmVudHMKZDEgPC0gKGxvZyhsYXRlc3RfdmFsdWUgLyBzdHJpa2VfcHJpY2UpICsgKDAuNSAqIGltcGxpZWRfdm9sYXRpbGl0eV4yKSAqIHRpbWVfdG9fZXhwaXJhdGlvbikgLyAoaW1wbGllZF92b2xhdGlsaXR5ICogc3FydCh0aW1lX3RvX2V4cGlyYXRpb24pKQpkMiA8LSBkMSAtIGltcGxpZWRfdm9sYXRpbGl0eSAqIHNxcnQodGltZV90b19leHBpcmF0aW9uKQoKIyBOb3JtYWwgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChOKGQxKSBhbmQgTihkMikpCk4gPC0gZnVuY3Rpb24oeCkgeyBwbm9ybSh4KSB9CgojIEVzdGltYXRlIG9wdGlvbiBwcmVtaXVtIChzaW1wbGlmaWVkIGZvciBhIGN1cnJlbmN5IHB1dCBvcHRpb24pCm9wdGlvbl9wcmVtaXVtIDwtIHN0cmlrZV9wcmljZSAqIGV4cCgtMC4wMiAqIHRpbWVfdG9fZXhwaXJhdGlvbikgKiBOKC1kMikgLSBsYXRlc3RfdmFsdWUgKiBOKC1kMSkKCiMgRGlzcGxheSBlc3RpbWF0ZWQgb3B0aW9uIHByZW1pdW0gZm9yIEJvVCAoU2VwdGVtYmVyIDUsIDIwMjQpIGFuZCBFb1QgKGxhdGVzdCkKIyBGb3Igc2ltcGxpY2l0eSwgbGV0J3MgYXNzdW1lIHRoZSBwcmVtaXVtIGF0IFNlcHRlbWJlciA1LCAyMDI0IGlzIHNsaWdodGx5IGxvd2VyIGR1ZSB0byB0aW1lIGRlY2F5CgpvcHRpb25fcHJlbWl1bV9ib3QgPC0gb3B0aW9uX3ByZW1pdW0gKiAwLjk1ICAjIEFzc3VtaW5nIHRoZSBwcmVtaXVtIHdhcyBzbGlnaHRseSBsb3dlciBvbiBTZXB0ZW1iZXIgNSwgMjAyNCBkdWUgdG8gdGltZSBkZWNheQpvcHRpb25fcHJlbWl1bV9lb3QgPC0gb3B0aW9uX3ByZW1pdW0gICMgTGF0ZXN0IChFb1QpIHByZW1pdW0gaXMgb3VyIGVzdGltYXRlZCBwcmVtaXVtCgojIENyZWF0ZSB0aGUgcmVzdWx0cyB0YWJsZQpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgRGVzY3JpcHRpb24gPSBjKCJDdXJyZW5jeSAoQVVEL1VTRCkiLCAiT3B0aW9uIEV4cGlyYXRpb24gTW9udGgiLCAiT3B0aW9uIFN0cmlrZSBQcmljZSIsICJPcHRpb24gUHJlbWl1bSIpLAogIEJvVCA9IGMoc2VwdF81X3ZhbHVlLCAiRGV6ZW1iZXIgMjAyNCIsIHN0cmlrZV9wcmljZSwgb3B0aW9uX3ByZW1pdW1fYm90KSwKICBFb1QgPSBjKGxhdGVzdF92YWx1ZSwgIkRlemVtYmVyIDIwMjQiLCBzdHJpa2VfcHJpY2UsIG9wdGlvbl9wcmVtaXVtX2VvdCkKKQoKIyBEaXNwbGF5IHRoZSB0YWJsZSB1c2luZyBrbml0cjo6a2FibGUKa2FibGUoCiAgcmVzdWx0cywKICBjb2wubmFtZXMgPSBjKCJEZXNjcmlwdGlvbiIsICJCb1QgKEJlZ2lubmluZyBvZiBUZXJtKSIsICJFb1QgKEVuZCBvZiBUZXJtKSIpLAogIGNhcHRpb24gPSAiQ3VycmVuY3kgT3B0aW9uIERldGFpbHMgKEFVRC9VU0QpIC0gQmVnaW5uaW5nIG9mIFRlcm0gKFNlcHQgNSwgMjAyNCkgdnMgRW5kIG9mIFRlcm0gKExhdGVzdCkiCikKYGBgCgoKIyMgTDIgRmluYW5jaWFsIG1hcmtldHMgbWljcm9zdHJ1Y3R1cmUKCmBgYHtyfQojIExvYWQgbGlicmFyaWVzCmxpYnJhcnkocXVhbnRtb2QpCmxpYnJhcnkoem9vKQpsaWJyYXJ5KGtuaXRyKQoKIyBTdXBwcmVzcyB3YXJuaW5ncyBmb3IgbWlzc2luZyB2YWx1ZXMgaW4gRlRTRQpvcHRpb25zKHdhcm4gPSAtMSkKCiMgRG93bmxvYWQgZGF0YSBmb3IgTkFTREFRIGFuZCBGVFNFIDEwMApnZXRTeW1ib2xzKCJOREFRIiwgc3JjID0gInlhaG9vIiwgYXV0by5hc3NpZ24gPSBGQUxTRSkgLT4gTkRBUQpnZXRTeW1ib2xzKCJeRlRTRSIsIHNyYyA9ICJ5YWhvbyIsIGF1dG8uYXNzaWduID0gRkFMU0UpIC0+IEZUU0UKCiMgUmVzdG9yZSB3YXJuaW5ncwpvcHRpb25zKHdhcm4gPSAwKQoKIyBGaWxsIG1pc3NpbmcgdmFsdWVzIGZvciBGVFNFCkZUU0UgPC0gbmEuYXBwcm94KEZUU0UpCgojIFRyaW0gZGF0YSB0byB0aGUgY29tcGFyaXNvbiBwZXJpb2QKTkRBUSA8LSBzdWJzZXQoTkRBUSwgaW5kZXgoTkRBUSkgPj0gIjIwMDgtMDEtMDMiICYgaW5kZXgoTkRBUSkgPD0gIjIwMjMtMDEtMDUiKQpGVFNFIDwtIHN1YnNldChGVFNFLCBpbmRleChGVFNFKSA+PSAiMjAwOC0wMS0wMyIgJiBpbmRleChGVFNFKSA8PSAiMjAyMy0wMS0wNSIpCgojIENhbGN1bGF0ZSBiYXNpYyBzdGF0aXN0aWNzIGZvciBOQVNEQVEKbmFzZGFxX3N0YXRzIDwtIGMoCiAgTWVhbiA9IG1lYW4oTkRBUSROREFRLkNsb3NlLCBuYS5ybSA9IFRSVUUpLAogIE1lZGlhbiA9IG1lZGlhbihOREFRJE5EQVEuQ2xvc2UsIG5hLnJtID0gVFJVRSksCiAgU3REZXYgPSBzZChOREFRJE5EQVEuQ2xvc2UsIG5hLnJtID0gVFJVRSkKKQoKIyBDYWxjdWxhdGUgYmFzaWMgc3RhdGlzdGljcyBmb3IgRlRTRQpsb25kX3N0YXRzIDwtIGMoCiAgTWVhbiA9IG1lYW4oRlRTRSRGVFNFLkNsb3NlLCBuYS5ybSA9IFRSVUUpLAogIE1lZGlhbiA9IG1lZGlhbihGVFNFJEZUU0UuQ2xvc2UsIG5hLnJtID0gVFJVRSksCiAgU3REZXYgPSBzZChGVFNFJEZUU0UuQ2xvc2UsIG5hLnJtID0gVFJVRSkKKQoKIyBDYWxjdWxhdGUgQ29lZmZpY2llbnQgb2YgVmFyaWF0aW9uIChDVikgZm9yIE5BU0RBUSBhbmQgRlRTRQpuYXNkYXFfY3YgPC0gKG5hc2RhcV9zdGF0c1siU3REZXYiXSAvIG5hc2RhcV9zdGF0c1siTWVhbiJdKSAqIDEwMApmdHNlX2N2IDwtIChsb25kX3N0YXRzWyJTdERldiJdIC8gbG9uZF9zdGF0c1siTWVhbiJdKSAqIDEwMAoKIyBDb21iaW5lIHN0YXRpc3RpY3MgaW50byBhIHRhYmxlIHdpdGhvdXQgbWFya2V0IGNhcGl0YWxpemF0aW9uCnN0YXRzX2NvbXBhcmlzb24gPC0gcmJpbmQoCiAgTkFTREFRID0gcm91bmQoYyhuYXNkYXFfc3RhdHMsIENWID0gbmFzZGFxX2N2KSwgMiksCiAgRlRTRSA9IHJvdW5kKGMobG9uZF9zdGF0cywgQ1YgPSBmdHNlX2N2KSwgMikKKQoKIyBEaXNwbGF5IHN0YXRpc3RpY3MgdXNpbmcga2FibGUKa2FibGUoc3RhdHNfY29tcGFyaXNvbiwgCiAgICAgIGNhcHRpb24gPSAiQ29tcGFyaXNvbiBvZiBOQVNEQVEgYW5kIEZUU0UgU3RhdGlzdGljcyAoSW5jbHVkaW5nIENvZWZmaWNpZW50IG9mIFZhcmlhdGlvbikiKQpgYGAKSW5kZXggQ2FsY3VsYXRpb24gUHJvY2VzczoKCkNvbXBhbnkgU2VsZWN0aW9uOiBJbmRleCBwcm92aWRlcnMgY2hvb3NlIGNvbXBhbmllcyBiYXNlZCBvbiBmYWN0b3JzIGxpa2UgbWFya2V0IHZhbHVlLCBpbmR1c3RyeSwgYW5kIHRyYWRpbmcgdm9sdW1lLiBXZWlnaHQgQXNzaWdubWVudDogQ29tcGFuaWVzIGFyZSBhc3NpZ25lZCB3ZWlnaHRzIGJhc2VkIG9uIHRoZWlyIG1hcmtldCBjYXBpdGFsaXphdGlvbiwgd2l0aCBsYXJnZXIgY29tcGFuaWVzIGhhdmluZyBtb3JlIGluZmx1ZW5jZS4gSW5kZXggVmFsdWUgQ2FsY3VsYXRpb246IEEgZm9ybXVsYSBpcyB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgaW5kZXggdmFsdWUsIGNvbnNpZGVyaW5nIHByaWNlIGNoYW5nZXMgb2YgZWFjaCBjb21wYW55IGFuZCB0aGVpciB3ZWlnaHRzLiBUaGUgdmFsdWUgaXMgdXBkYXRlZCBjb250aW51b3VzbHkgdGhyb3VnaG91dCB0aGUgdHJhZGluZyBkYXkuIE1lYW4gYW5kIE1lZGlhbjogVGhlIEZUU0UgaGFzIGhpZ2hlciBhdmVyYWdlIGFuZCBtZWRpYW4gdmFsdWVzIGNvbXBhcmVkIHRvIE5BU0RBUSwgaW5kaWNhdGluZyBhIGhpZ2hlciB0eXBpY2FsIGluZGV4IGxldmVsLiBTdGFuZGFyZCBEZXZpYXRpb24gKFN0RGV2KTpTdERldiBtYXkgbm90IGJlIGFuIGlkZWFsIG1ldHJpYyBmb3IgY29tcGFyaW5nIGluZGljZXMgd2l0aCBkaWZmZXJlbnQgbWVhbiBsZXZlbHMsIGFzIGl0IGRvZXMgbm90IGFjY291bnQgZm9yIHRoZSBzY2FsZSBvZiB0aGVzZSBpbmRpY2VzIENvZWZmaWNpZW50IG9mIFZhcmlhdGlvbiAoQ1YpOiBOQVNEQVHigJlzIGhpZ2ggQ1YgKDc0LjQxJSkgc2hvd3MgZ3JlYXRlciByZWxhdGl2ZSB2b2xhdGlsaXR5LCB3aGlsZSBGVFNF4oCZcyBsb3dlciBDViAoMTQuMTUlKSBpbXBsaWVzIG1vcmUgc3RhYmlsaXR5IHJlbGF0aXZlIHRvIGl0cyBhdmVyYWdlLgoKCgojIyBMMyBJbnN0cnVtZW504oCZcyBvdmVydmlldyBhbmQgdmFsdWF0aW9uCgpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShrbml0cikKCiMgRG93bmxvYWQgdGhlIDMtTW9udGggVHJlYXN1cnkgQmlsbCBSYXRlIChUQjNNUykgZGF0YSBmcm9tIEZSRUQKZ2V0U3ltYm9scygiVEIzTVMiLCBzcmMgPSAiRlJFRCIpCgojIERlZmluZSB0aGUgc3RhcnQgYW5kIGVuZCBkYXRlcwpzdGFydF9kYXRlIDwtICIyMDI0LTA1LTAxIiAgIyBTdGFydCBvZiB0ZXJtIChzZXQgdG8gTWF5IDIwMjQpCmVuZF9kYXRlIDwtIFN5cy5EYXRlKCkgICAgICAjIExhdGVzdCBhdmFpbGFibGUgZGF0ZSAoZHluYW1pYykKCiMgU3Vic2V0IHRoZSBkYXRhIHRvIHRoZSBwZXJpb2QgYmV0d2VlbiBzdGFydCBhbmQgbGF0ZXN0IGRhdGEKdGJfZGF0YSA8LSB3aW5kb3coVEIzTVMsIHN0YXJ0ID0gc3RhcnRfZGF0ZSwgZW5kID0gZW5kX2RhdGUpCgojIEV4dHJhY3QgdGhlIHN0YXJ0IHJhdGUgKHRoZSBmaXJzdCBhdmFpbGFibGUgdmFsdWUgZm9yIE1heSAyMDI0KQpzdGFydF9yYXRlIDwtIGFzLm51bWVyaWMoZmlyc3QodGJfZGF0YSkpICAjIEVuc3VyZSBpdCByZXR1cm5zIGp1c3Qgb25lIG51bWJlcgoKIyBFeHRyYWN0IHRoZSBlbmQgcmF0ZSAodGhlIGxhdGVzdCBhdmFpbGFibGUgdmFsdWUpCmVuZF9yYXRlIDwtIGFzLm51bWVyaWMobGFzdCh0Yl9kYXRhKSkgICAgIyBFbnN1cmUgaXQgcmV0dXJucyBqdXN0IG9uZSBudW1iZXIKCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgZGlzcGxheWluZyB0aGUgcmF0ZXMgaW4gYSB0YWJsZQpyYXRlX2RhdGEgPC0gZGF0YS5mcmFtZSgKICAiUGVyaW9kIiA9IGMoIlN0YXJ0IG9mIFRlcm0gKE1heSAyMDI0KSIsICJFbmQgb2YgVGVybSAoTGF0ZXN0IEF2YWlsYWJsZSkiKSwKICAiUmF0ZSAoJSkiID0gYyhyb3VuZChzdGFydF9yYXRlLCAyKSwgcm91bmQoZW5kX3JhdGUsIDIpKQopCgojIERpc3BsYXkgdGhlIHRhYmxlIHVzaW5nIGthYmxlCmthYmxlKHJhdGVfZGF0YSwgY2FwdGlvbiA9ICJDb21wYXJpc29uIG9mIDMtTW9udGggVHJlYXN1cnkgQmlsbCBSYXRlIChUQjNNUykiLCBjb2wubmFtZXMgPSBjKCJQZXJpb2QiLCAiUmF0ZSAoJSkiKSkKYGBgCgoKIyBXaHkgSW50ZXJlc3QgUmF0ZXMgQ2hhbmdlIE92ZXIgVGltZQoKMS4gKipJbmZsYXRpb24gRXhwZWN0YXRpb25zKio6ICAKICAgSWYgaW5mbGF0aW9uIGlzIGV4cGVjdGVkIHRvIHJpc2UsIGludGVyZXN0IHJhdGVzIHVzdWFsbHkgaW5jcmVhc2UgdG8gY29tcGVuc2F0ZSBmb3IgcmVkdWNlZCBwdXJjaGFzaW5nIHBvd2VyLiBJbiByZXZlcnNlLCBsb3dlciBpbmZsYXRpb24gY2FuIGxlYWQgdG8gbG93ZXIgcmF0ZXMuCgoyLiAqKkNlbnRyYWwgQmFuayBQb2xpY2llcyoqOiAgCiAgIENlbnRyYWwgYmFua3MgYWRqdXN0IGludGVyZXN0IHJhdGVzIHRvIGNvbnRyb2wgZWNvbm9taWMgZ3Jvd3RoIGFuZCBpbmZsYXRpb24uIFJhaXNpbmcgcmF0ZXMgc2xvd3MgZG93biBib3Jyb3dpbmcsIHdoaWxlIGxvd2VyaW5nIHRoZW0gc3RpbXVsYXRlcyBzcGVuZGluZyBhbmQgaW52ZXN0bWVudC4KCjMuICoqQ3JlZGl0IFN1cHBseSBhbmQgRGVtYW5kKio6ICAKICAgVGhlIGJhbGFuY2Ugb2Ygc3VwcGx5IGFuZCBkZW1hbmQgZm9yIGxvYW5zIGFmZmVjdHMgaW50ZXJlc3QgcmF0ZXMuIEhpZ2hlciBkZW1hbmQgZm9yIGxvYW5zIHRlbmRzIHRvIHB1c2ggcmF0ZXMgdXAsIHdoaWxlIGxvd2VyIGRlbWFuZCBjYW4gcmVkdWNlIHJhdGVzLgoKIyMgTDQgRWZmaWNpZW5jeSBvZiBtYXJrZXQgYW5kIGluZm9ybWF0aW9uCmBgYHtyfQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcnkKbGlicmFyeShxdWFudG1vZCkKCiMgRG93bmxvYWQgQ29jYS1Db2xhIHN0b2NrIGRhdGEgZnJvbSBZYWhvbyBGaW5hbmNlCmdldFN5bWJvbHMoIktPIiwgc3JjID0gInlhaG9vIiwgZnJvbSA9ICIyMDE3LTEwLTIwIiwgdG8gPSAiMjAxNy0xMC0zMSIpCgojIFBsb3R0aW5nIENvY2EtQ29sYSBzdG9jayBwcmljZXMKY2hhcnRTZXJpZXMoS08sIG5hbWUgPSAiQ29jYS1Db2xhIFN0b2NrIFByaWNlcyAoT2N0b2JlciAyMOKAkzMxLCAyMDE3KSIsIAogICAgICAgICAgICB0aGVtZSA9IGNoYXJ0VGhlbWUoIndoaXRlIiksCiAgICAgICAgICAgIHR5cGUgPSAibGluZSIpCgpgYGAKQmFzZWQgb24gdGhlIGdyYXBoLCBDb2NhLUNvbGEncyBzaGFyZSBwcmljZSBkb2VzIG5vdCBzaG93IHNpZ25pZmljYW50IHZvbGF0aWxpdHkgb3IgYSBzaGFycCBkcm9wIG9uIE9jdG9iZXIgMjYsIDIwMTcsIHdoaWNoIHdvdWxkIGJlIGluZGljYXRpdmUgb2YgYWR2ZXJzZSBtYXJrZXQgcmVhY3Rpb25zIHRvIGluZm9ybWF0aW9uIHJlbGVhc2UuIEluc3RlYWQsIHRoZSBwcmljZSBhcHBlYXJzIHJlbGF0aXZlbHkgc3RhYmxlLCB3aXRoIGEgc21hbGwgZGVjbGluZSB0aGF0IGlzIGluIGxpbmUgd2l0aCBub3JtYWwgZmx1Y3R1YXRpb25zIG92ZXIgdGhlIG9ic2VydmVkIHBlcmlvZC4gVGhpcyBzdWdnZXN0cyB0aGF0IGVpdGhlcjoKVGhlIGluZm9ybWF0aW9uIHJlbGVhc2VkIHdhcyBhbnRpY2lwYXRlZCBvciBhbHJlYWR5IHByaWNlZCBpbiBieSB0aGUgbWFya2V0LgpUaGUgbWFya2V0IHZpZXdlZCB0aGUgaW5mb3JtYXRpb24gYXMgbGVzcyBpbXBhY3RmdWwgb24gQ29jYS1Db2xhJ3MgbG9uZy10ZXJtIGZ1bmRhbWVudGFscy4KCiMjIEw1IEZpbmFuY2lhbCBzdGF0ZW1lbnRzIGFuZCBmdW5kYW1lbnRhbCBhbmFseXNpcwpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkgICMgZm9yIGJhc2ljIGZpbmFuY2lhbCBkYXRhLCBzdG9jayBxdW90ZXMKbGlicmFyeShmaW5yZXBvcnRyKSAjIGZvciBmaW5hbmNpYWwgcmVwb3J0cwpsaWJyYXJ5KGVkZ2FyKSAgIyBmb3IgcmV0cmlldmluZyBmdWxsIHRleHQgZmlsaW5ncyBmcm9tIEVER0FSCmxpYnJhcnkoWEJSTCkgICMgZm9yIGhhbmRsaW5nIFhCUkwgZGF0YSAoZmluYW5jaWFsIHJlcG9ydHMpCmxpYnJhcnkoZHBseXIpICAjIGZvciBkYXRhIG1hbmlwdWxhdGlvbgpsaWJyYXJ5KHRpZHlyKSAgIyBmb3IgZGF0YSBjbGVhbmluZwoKIyBTZXQgdXAgdGhlIGF1dGhvcml0eSBmb3IgRWRnYXIgKEVER0FSIHJlcXVpcmVzIHlvdXIgZW1haWwpCm9wdGlvbnMoSFRUUFVzZXJBZ2VudCA9ICJtaWt5QHh4LmNvbSIpCgojIFJldHJpZXZlIGFubnVhbCByZXBvcnRzIGZvciBNaWNyb3NvZnQgKENJSzogMDAwMDc4OTAxOSkKQW5udWFsUmVwb3J0cygwMDAwNzg5MDE5LCBmb3JlaWduID0gRkFMU0UpCgojIEV4YW1wbGU6IEdldCB0aGUgYmFsYW5jZSBzaGVldCBmb3IgTWljcm9zb2Z0IChNU0ZUIHRpY2tlciwgZm9yIHRoZSB5ZWFyIDIwMTcpCk1zZnRfMjAxNyA8LSBHZXRCYWxhbmNlU2hlZXQoJ01TRlQnLCAyMDE3KQoKIyBWaWV3IHRoZSBiYWxhbmNlIHNoZWV0ClZpZXcoTXNmdF8yMDE3KQpgYGAKCjIwMTggZG9lc250IHdvcmsgVGhlIFVSTCByZXN1bHRzIGluIGEgNDA0IE5vdCBGb3VuZCBlcnJvciwgbWVhbmluZyB0aGF0IHRoZSBmaWxlIG9yIHJlc291cmNlIGlzIGVpdGhlciB1bmF2YWlsYWJsZSwgbW92ZWQsIG9yIGRvZXNuJ3QgZXhpc3QgYXQgdGhlIGdpdmVuIFVSTC4KCgoKCiMgTDUuMSBUeXBlcyBvZiBEZXBvc2l0cyBVc2VkIHRvIE9idGFpbiBNb3N0IG9mIHRoZSBCYW5rJ3MgRnVuZHMgKElORykKCiMjIyAqKkN1c3RvbWVyIERlcG9zaXRzKioKLSBTYXZpbmdzIGFjY291bnRzLCBjdXJyZW50IGFjY291bnRzLCB0aW1lIGRlcG9zaXRzLCBhbmQgZGVtYW5kIGRlcG9zaXRzLgotIFRvdGFsIGRlcG9zaXRzIGFtb3VudGVkIHRvICoq4oKsNjUwIGJpbGxpb24qKiBpbiAyMDIzLgoKIyMjICoqV2hvbGVzYWxlIEZ1bmRpbmcqKgotIEluY2x1ZGVzIGJvcnJvd2luZyB2aWEgcmVwdXJjaGFzZSBhZ3JlZW1lbnRzLCBpc3N1aW5nIGJvbmRzLCBhbmQgY29tbWVyY2lhbCBwYXBlcnMuCgotLS0KCiMgTDUuMiBNYWluIFVzZXMgb2YgRnVuZHMKCiMjIyAqKlByaW1hcnkgVXNlcyoqCjEuICoqTGVuZGluZyoqOiBMb2FucyB0byBpbmRpdmlkdWFscyBhbmQgYnVzaW5lc3NlcywgaW5jbHVkaW5nIG1vcnRnYWdlcywgYnVzaW5lc3MgbG9hbnMsIGFuZCBjb25zdW1lciBjcmVkaXQuCjIuICoqSW52ZXN0bWVudHMqKjogQ2FwaXRhbCBpcyBpbnZlc3RlZCBpbiBzZWN1cml0aWVzIGFuZCBmaW5hbmNpYWwgaW5zdHJ1bWVudHMgdG8gZWFybiByZXR1cm5zIGFuZCBtYW5hZ2Ugcmlza3MuCjMuICoqTGlxdWlkaXR5IE1hbmFnZW1lbnQqKjogUmVzZXJ2ZXMgbWFpbnRhaW5lZCBmb3IgcmVndWxhdG9yeSBhbmQgb3BlcmF0aW9uYWwgbmVlZHMuCgojIyMgKipSZWd1bGF0b3J5IEltcGFjdHMqKgotIElORyBmYWNlcyByZWd1bGF0b3J5IGNoYWxsZW5nZXMgbGlrZToKICAtIENvbXBsaWFuY2Ugd2l0aCBzdXN0YWluYWJpbGl0eSBzdGFuZGFyZHMgKEVVIHRheG9ub215LCBFU0cgZGlzY2xvc3VyZXMpLgogIC0gSW5jcmVhc2VkIGNvc3RzIGR1ZSB0byBkaXJlY3RpdmVzIGxpa2UgdGhlIENvcnBvcmF0ZSBTdXN0YWluYWJpbGl0eSBSZXBvcnRpbmcgRGlyZWN0aXZlIChDU1JEKS4KCi0tLQoKIyBMNS4zIEVudHJ5IGludG8gdGhlIFNlY3VyaXRpZXMgSW5kdXN0cnkKClllcywgSU5HIGlzIGV4cGFuZGluZyBpbnRvIHNlY3VyaXRpZXMgc2VydmljZXMgYnk6CjEuIE9mZmVyaW5nIGVxdWl0eSBhbmQgZGVidCBpc3N1YW5jZSBzZXJ2aWNlcyB0byBpbnN0aXR1dGlvbmFsIGNsaWVudHMuCjIuIFByb3ZpZGluZyBkZXJpdmF0aXZlcyBmb3IgaGVkZ2luZy4KMy4gRW5nYWdpbmcgaW4gc2VjdXJpdGllcyB1bmRlcndyaXRpbmcgdmlhIGl0cyBXaG9sZXNhbGUgQmFua2luZyBkaXZpc2lvbi4KCi0tLQoKIyBMNS40IEVudHJ5IGludG8gdGhlIEluc3VyYW5jZSBJbmR1c3RyeQoKWWVzLCBJTkcgY29sbGFib3JhdGVzIHdpdGggaW5zdXJhbmNlIHBhcnRuZXJzIHRvIG9mZmVyOgoxLiAqKkxpZmUgYW5kIE5vbi1MaWZlIEluc3VyYW5jZSBQcm9kdWN0cyoqOiBJbmNsdWRlcyBoZWFsdGgsIGNhciwgdHJhdmVsLCBhbmQgaG9tZSBpbnN1cmFuY2UuCjIuIEluIDIwMjMsIElORyBsYXVuY2hlZDoKICAgLSBQZXQgaW5zdXJhbmNlIGluIFTDvHJraXllLgogICAtIENhciBpbnN1cmFuY2UgaW4gU3BhaW4uCgotLS0KCiMgTDUuNSBHYXAgQmV0d2VlbiBSYXRlLVNlbnNpdGl2ZSBBc3NldHMgYW5kIExpYWJpbGl0aWVzCgojIyMgKipCYWxhbmNlIFNoZWV0IE1hbmFnZW1lbnQqKgotIEludGVyZXN0IHJhdGUgcmlza3MgYXJlIGFjdGl2ZWx5IG1hbmFnZWQgdXNpbmcgaGVkZ2luZyBzdHJhdGVnaWVzIChlLmcuLCBjYXAvZmxvb3IgY29udHJhY3RzKS4KLSBUaGUgcmVwb3J0IGRvZXMgbm90IHNwZWNpZnkgd2hldGhlciB0aGUgZ2FwIGlzIHBvc2l0aXZlIG9yIG5lZ2F0aXZlIGJ1dCBpbmRpY2F0ZXMgc3Ryb25nIG1hbmFnZW1lbnQgdG8gbWluaW1pemUgbWlzbWF0Y2hlcy4KCi0tLQoKIyBMNS42IEludGVyZXN0IEluY29tZSBhcyBhIFBlcmNlbnRhZ2Ugb2YgVG90YWwgQXNzZXRzCgpcWwpcdGV4dHtJbnRlcmVzdCBJbmNvbWUgUGVyY2VudGFnZX0gPSBcZnJhY3tcdGV4dHtJbnRlcmVzdCBJbmNvbWV9fXtcdGV4dHtUb3RhbCBBc3NldHN9fSBcdGltZXMgMTAwClxdCgpcWwpcdGV4dHtJbnRlcmVzdCBJbmNvbWUgUGVyY2VudGFnZX0gPSBcZnJhY3s1MiwyMjd9ezk3NSw1ODN9IFx0aW1lcyAxMDAgPSA1LjM1XCUKXF0KCi0tLQoKIyBMNS43IEludGVyZXN0IEV4cGVuc2VzIGFzIGEgUGVyY2VudGFnZSBvZiBUb3RhbCBBc3NldHMKClxbClx0ZXh0e0ludGVyZXN0IEV4cGVuc2UgUGVyY2VudGFnZX0gPSBcZnJhY3tcdGV4dHtJbnRlcmVzdCBFeHBlbnNlc319e1x0ZXh0e1RvdGFsIEFzc2V0c319IFx0aW1lcyAxMDAKXF0KClxbClx0ZXh0e0ludGVyZXN0IEV4cGVuc2UgUGVyY2VudGFnZX0gPSBcZnJhY3szNiwyNTJ9ezk3NSw1ODN9IFx0aW1lcyAxMDAgPSAzLjcyXCUKXF0KCi0tLQoKIyBMNS44IE5ldCBJbnRlcmVzdCBNYXJnaW4KClxbClx0ZXh0e05ldCBJbnRlcmVzdCBNYXJnaW59ID0gXGZyYWN7XHRleHR7TmV0IEludGVyZXN0IEluY29tZX19e1x0ZXh0e1RvdGFsIEFzc2V0c319IFx0aW1lcyAxMDAKXF0KClxbClx0ZXh0e05ldCBJbnRlcmVzdCBNYXJnaW59ID0gXGZyYWN7MTUsOTc2fXs5NzUsNTgzfSBcdGltZXMgMTAwID0gMS42NFwlClxdCgotLS0KCiMgTDUuOSBOb25pbnRlcmVzdCBJbmNvbWUgYW5kIEV4cGVuc2VzIGFzIGEgUGVyY2VudGFnZSBvZiBUb3RhbCBBc3NldHMKCiMjIyBOb25pbnRlcmVzdCBJbmNvbWU6CgpcWwpcdGV4dHtOb25pbnRlcmVzdCBJbmNvbWUgUGVyY2VudGFnZX0gPSBcZnJhY3tcdGV4dHtOb25pbnRlcmVzdCBJbmNvbWV9fXtcdGV4dHtUb3RhbCBBc3NldHN9fSBcdGltZXMgMTAwClxdCgpcWwpcdGV4dHtOb25pbnRlcmVzdCBJbmNvbWUgUGVyY2VudGFnZX0gPSBcZnJhY3s1LDEwOX17OTc1LDU4M30gXHRpbWVzIDEwMCA9IDAuNTJcJQpcXQoKIyMjIE5vbmludGVyZXN0IEV4cGVuc2VzOgoKXFsKXHRleHR7Tm9uaW50ZXJlc3QgRXhwZW5zZSBQZXJjZW50YWdlfSA9IFxmcmFje1x0ZXh0e05vbmludGVyZXN0IEV4cGVuc2VzfX17XHRleHR7VG90YWwgQXNzZXRzfX0gXHRpbWVzIDEwMApcXQoKXFsKXHRleHR7Tm9uaW50ZXJlc3QgRXhwZW5zZSBQZXJjZW50YWdlfSA9IFxmcmFjezEsNTE0fXs5NzUsNTgzfSBcdGltZXMgMTAwID0gMC4xNlwlClxdCgotLS0KCiMgTDUuMTAgQWRkaXRpb24gdG8gTG9hbiBMb3NzIFJlc2VydmVzIGFzIGEgUGVyY2VudGFnZSBvZiBUb3RhbCBBc3NldHMKClxbClx0ZXh0e0xvYW4gTG9zcyBSZXNlcnZlIFBlcmNlbnRhZ2V9ID0gXGZyYWN7XHRleHR7TG9hbiBMb3NzIFJlc2VydmVzfX17XHRleHR7VG90YWwgQXNzZXRzfX0gXHRpbWVzIDEwMApcXQoKXFsKXHRleHR7TG9hbiBMb3NzIFJlc2VydmUgUGVyY2VudGFnZX0gPSBcZnJhY3s1MjB9ezk3NSw1ODN9IFx0aW1lcyAxMDAgPSAwLjA1XCUKXF0KCi0tLQoKIyBMNS4xMSBSZXR1cm4gb24gQXNzZXRzIChST0EpCgpcWwpcdGV4dHtST0F9ID0gXGZyYWN7XHRleHR7TmV0IEluY29tZX19e1x0ZXh0e1RvdGFsIEFzc2V0c319IFx0aW1lcyAxMDAKXF0KClxbClx0ZXh0e1JPQX0gPSBcZnJhY3s3LDUyMX17OTc1LDU4M30gXHRpbWVzIDEwMCA9IDAuNzdcJQpcXQoKLS0tCgojIEw1LjEyIFJldHVybiBvbiBFcXVpdHkgKFJPRSkKClxbClx0ZXh0e1JPRX0gPSBcZnJhY3tcdGV4dHtOZXQgSW5jb21lfX17XHRleHR7VG90YWwgRXF1aXR5fX0gXHRpbWVzIDEwMApcXQoKXFsKXHRleHR7Uk9FfSA9IFxmcmFjezcsNTIxfXs1MiwxODR9IFx0aW1lcyAxMDAgPSAxNC40MlwlClxdCgotLS0KCiMgTDUuMTMgSXRlbXMgQWZmZWN0ZWQgYnkgUmlzaW5nIEludGVyZXN0IFJhdGVzCgojIyMgKipBZmZlY3RlZCBJdGVtcyoqCjEuICoqSW50ZXJlc3QgSW5jb21lKio6IExpa2VseSB0byBpbmNyZWFzZSBhcyBsb2FuIHlpZWxkcyByaXNlLgoyLiAqKkludGVyZXN0IEV4cGVuc2VzKio6IExpa2VseSB0byByaXNlIHNpZ25pZmljYW50bHkgaWYgZGVwb3NpdCByYXRlcyBvciBmdW5kaW5nIGNvc3RzIGluY3JlYXNlLgoKLS0tCgojIEw1LjE0IEl0ZW1zIEFmZmVjdGVkIGJ5IEVjb25vbWljIERldGVyaW9yYXRpb24KCiMjIyAqKkFmZmVjdGVkIEl0ZW1zKioKMS4gKipMb2FuIExvc3MgUmVzZXJ2ZXMqKjogTGlrZWx5IHRvIGluY3JlYXNlIGR1ZSB0byBoaWdoZXIgZGVmYXVsdCByYXRlcy4KMi4gKipOb25pbnRlcmVzdCBJbmNvbWUqKjogTWF5IGRlY2xpbmUgYXMgZGVtYW5kIGZvciBpbnZlc3RtZW50IGFuZCBmaW5hbmNpYWwgc2VydmljZXMgZGVjcmVhc2VzLgozLiAqKk5ldCBJbmNvbWUqKjogT3ZlcmFsbCByZWR1Y3Rpb24gZHVlIHRvIGxvd2VyIGxlbmRpbmcgYW5kIGZlZS1iYXNlZCBhY3Rpdml0eS4KCi0tLQoKCgoKCgojIEw1LjE1IEludmVzdG1lbnQgT2JqZWN0aXZlIGFuZCBSaXNrIExldmVsCgojIyMgKipJbnZlc3RtZW50IE9iamVjdGl2ZSoqClRoZSBWYW5ndWFyZCA1MDAgSW5kZXggRnVuZCBzZWVrcyB0byB0cmFjayB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIFN0YW5kYXJkICYgUG9vcuKAmXMgNTAwIEluZGV4LCB3aGljaCBtZWFzdXJlcyB0aGUgaW52ZXN0bWVudCByZXR1cm4gb2YgbGFyZ2UtY2FwaXRhbGl6YXRpb24gVS5TLiBzdG9ja3MuCgojIyMgKipSaXNrIExldmVsKioKLSAqKk1vZGVyYXRlIFJpc2sqKjoKICAtIFRoZSBmdW5kIGlzIGV4cG9zZWQgdG8gbWFya2V0IHJpc2tzIGR1ZSB0byBpdHMgZm9jdXMgb24gZXF1aXRpZXMgYW5kIHRoZSBTJlAgNTAwLgogIC0gSXQgaGFzICoqc2VjdG9yIHJpc2tzKiosIHBhcnRpY3VsYXJseSBpbiB0aGUgaW5mb3JtYXRpb24gdGVjaG5vbG9neSBzZWN0b3IsIHdoaWNoIGNvbnN0aXR1dGVzIGEgc2lnbmlmaWNhbnQgcG9ydGlvbiBvZiBpdHMgcG9ydGZvbGlvLgoKLS0tCgojIEw1LjE2IEZ1bmQgUGVyZm9ybWFuY2UKCiMjIyAqKlJldHVybiBMYXN0IFllYXIqKgpcWwpcdGV4dHtSZXR1cm4gTGFzdCBZZWFyfSA9IDI2LjI0XCUKXF0KCiMjIyAqKkF2ZXJhZ2UgQW5udWFsIFJldHVybiBPdmVyIHRoZSBMYXN0IFRocmVlIFllYXJzKioKXFsKXHRleHR7QXZlcmFnZSBBbm51YWwgUmV0dXJuICgzIFllYXJzKX0gPSAxNS42NVwlClxdCgotLS0KCiMgTDUuMTcgS2V5IEVjb25vbWljIEZhY3RvciBJbmZsdWVuY2luZyBSZXR1cm5zCgojIyMgKipLZXkgRWNvbm9taWMgRmFjdG9yKioKLSBUaGUgcmV0dXJuIG9mIHRoZSBmdW5kIGlzIHByaW1hcmlseSBpbmZsdWVuY2VkIGJ5OgogIC0gKipVLlMuIFN0b2NrIE1hcmtldCBDb25kaXRpb25zKio6IEFzIHRoZSBmdW5kIHRyYWNrcyB0aGUgUyZQIDUwMCwgaXRzIHBlcmZvcm1hbmNlIGNsb3NlbHkgbWlycm9ycyB0aGUgb3ZlcmFsbCBVLlMuIHN0b2NrIG1hcmtldCB0cmVuZHMuCiAgLSBBZGRpdGlvbmFsIGluZmx1ZW5jZXMgaW5jbHVkZSBVLlMuIGludGVyZXN0IHJhdGVzIGFuZCBzZWN0b3Itc3BlY2lmaWMgdHJlbmRzLCBlc3BlY2lhbGx5IGluIHRoZSBpbmZvcm1hdGlvbiB0ZWNobm9sb2d5IHNlY3Rvci4KCi0tLQoKIyBMNS4xOCBGZWVzIGZvciBCdXlpbmcgb3IgU2VsbGluZyB0aGUgTXV0dWFsIEZ1bmQKCiMjIyAqKkZlZXMqKgotICoqTm8gU2FsZXMgQ2hhcmdlcyoqOgogIC0gTm8gZmVlcyBhcmUgaW1wb3NlZCBmb3IgcHVyY2hhc2VzLCByZWludmVzdGVkIGRpdmlkZW5kcywgb3IgcmVkZW1wdGlvbnMuCi0tLQoKIyBMNS4xOSBFeHBlbnNlIFJhdGlvCgojIyMgKipFeHBlbnNlIFJhdGlvKioKXFsKXHRleHR7RXhwZW5zZSBSYXRpbyAoTGFzdCBZZWFyKX0gPSAwLjA0XCUKXF0KCiMjIyAqKkFzc2Vzc21lbnQqKgotIFRoZSBleHBlbnNlIHJhdGlvIGlzIGV4dHJlbWVseSBsb3cgY29tcGFyZWQgdG8gaW5kdXN0cnkgYXZlcmFnZXMsIG1ha2luZyB0aGUgZnVuZCBoaWdobHkgY29zdC1lZmZpY2llbnQgZm9yIGludmVzdG9ycy4KCi0tLQoKIyBMNS4yMCBNYWluIFR5cGVzIG9mIEJ1c2luZXNzIENvbmR1Y3RlZAoKIyMjICoqQ2hhcmxlcyBTY2h3YWIncyBCdXNpbmVzcyBPcGVyYXRpb25zKioKMS4gKipCcm9rZXJhZ2UgU2VydmljZXMqKjogCiAgIC0gVHJhZGUgZXhlY3V0aW9uIGFuZCBjbGVhcmluZyBmb3IgZXF1aXRpZXMsIEVURnMsIG9wdGlvbnMsIGZpeGVkIGluY29tZSwgYW5kIG90aGVyIHNlY3VyaXRpZXMuCjIuICoqV2VhbHRoIE1hbmFnZW1lbnQqKjogCiAgIC0gUGVyc29uYWxpemVkIGZpbmFuY2lhbCBwbGFubmluZywgcG9ydGZvbGlvIG1hbmFnZW1lbnQsIGFuZCBhZHZpc29yeSBzZXJ2aWNlcy4KMy4gKipCYW5raW5nIFNlcnZpY2VzKio6IAogICAtIEZESUMtaW5zdXJlZCBkZXBvc2l0IGFjY291bnRzIGFuZCBsZW5kaW5nIHNlcnZpY2VzLgo0LiAqKk11dHVhbCBGdW5kIGFuZCBFVEYgTWFuYWdlbWVudCoqOiAKICAgLSBNYW5hZ2VtZW50IG9mIHByb3ByaWV0YXJ5IFNjaHdhYiBGdW5kcyBhbmQgRVRGcywgYWxvbmcgd2l0aCB0aGlyZC1wYXJ0eSBmdW5kIGludmVzdG1lbnRzLgo1LiAqKlRlY2hub2xvZ3kgU29sdXRpb25zIGZvciBBZHZpc29ycyoqOiAKICAgLSBEaWdpdGFsIHBsYXRmb3JtcyBkZXNpZ25lZCBmb3IgUmVnaXN0ZXJlZCBJbnZlc3RtZW50IEFkdmlzb3JzIChSSUFzKS4KCi0tLQoKIyBMNS4yMSBSZWd1bGF0b3J5IEltcGFjdHMKCiMjIyAqKkV4aXN0aW5nIGFuZCBQb3RlbnRpYWwgUmVndWxhdG9yeSBDaGFsbGVuZ2VzKioKMS4gKipDYXBpdGFsIFJlcXVpcmVtZW50cyoqOgogICAtIFNjaHdhYiBtYXkgZmFjZSBzdHJpY3RlciBsZXZlcmFnZSByYXRpb3MgZHVlIHRvIHRoZSBpbnRlZ3JhdGlvbiBvZiAqKmFjY3VtdWxhdGVkIG90aGVyIGNvbXByZWhlbnNpdmUgaW5jb21lIChBT0NJKSoqIGludG8gcmVndWxhdG9yeSBjYXBpdGFsIGNhbGN1bGF0aW9ucy4KMi4gKipSZWd1bGF0b3J5IENvbXBsaWFuY2UqKjoKICAgLSBTY2h3YWIgcGxhY2VzIGEgc3Ryb25nIGVtcGhhc2lzIG9uIGNvbXBsaWFuY2UgYW5kIHNhZmVndWFyZGluZyBjbGllbnQgdHJ1c3QsIGhpZ2hsaWdodGluZyB0aGUgcm9sZSBvZiBpbnRlZ3JpdHkgaW4gaXRzIG9wZXJhdGlvbnMuCgotLS0KCiMgTDUuMjIgUmVjZW50IFBlcmZvcm1hbmNlCgojIyMgKipQZXJmb3JtYW5jZSBTdW1tYXJ5KioKMS4gKipOZXQgUmV2ZW51ZXMqKjogRGVjbGluZWQgYnkgOSUgaW4gMjAyMyB0byAqKiQxOC44IGJpbGxpb24qKi4KMi4gKipOZXQgSW5jb21lKio6IERyb3BwZWQgYnkgMzAlIHRvICoqJDQuNjUgYmlsbGlvbioqLgozLiAqKkVhcm5pbmdzIFBlciBTaGFyZSoqOiBGZWxsIGJ5IDI3JSB0byAqKiQyLjU0KiouCgojIyMgKipSZWFzb25zIGZvciBVbmZhdm9yYWJsZSBQZXJmb3JtYW5jZSoqCjEuICoqSW50ZXJlc3QgUmF0ZSBJbmNyZWFzZXMqKjoKICAgLSBSYXBpZCByYXRlIGhpa2VzIHJlZHVjZWQgY2xpZW50IGNhc2ggYmFsYW5jZXMgaGVsZCBieSBTY2h3YWIsIGltcGFjdGluZyB0aGUgbmV0IGludGVyZXN0IG1hcmdpbi4KMi4gKipDbGllbnQgQmVoYXZpb3IqKjoKICAgLSBNYW55IGNsaWVudHMgbW92ZWQgdGhlaXIgZnVuZHMgdG8gaGlnaGVyLXlpZWxkaW5nIGFsdGVybmF0aXZlcywgYSB0cmVuZCBTY2h3YWIgc3VwcG9ydGVkIHRvIG1haW50YWluIGxvbmctdGVybSB0cnVzdCBkZXNwaXRlIHNob3J0LXRlcm0gcmV2ZW51ZSBpbXBhY3RzLgozLiAqKk1hcmtldCBWb2xhdGlsaXR5Kio6CiAgIC0gR2VvcG9saXRpY2FsIGFuZCBlY29ub21pYyB1bmNlcnRhaW50eSBjb250cmlidXRlZCB0byByZWR1Y2VkIHRyYWRpbmcgYWN0aXZpdHkgYW5kIGRpbWluaXNoZWQgaW52ZXN0b3Igc2VudGltZW50LgoKLS0tCiMjIEw3LjEgQ29tcGFyaW5nIFlpZWxkcyBBbW9uZyBTZWN1cml0aWVzCgojIyMgRGlmZmVyZW5jZSBiZXR3ZWVuIHlpZWxkcyBvbiBjb3Jwb3JhdGUgaGlnaC1xdWFsaXR5IGJvbmRzIGFuZCBUcmVhc3VyeSBib25kczoKCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBEZWZpbmUgdGhlIHN0YXJ0IGFuZCBlbmQgZGF0ZXMgb2YgdGhlIHNjaG9vbCB0ZXJtCnN0YXJ0X2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNC0wMSIpCmVuZF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMTAtMzAiKSAgIyBVcGRhdGVkIGVuZCBkYXRlCgojIERvd25sb2FkIGRhdGEgZm9yIDEwLXllYXIgVHJlYXN1cnkgYm9uZCB5aWVsZCBhbmQgQUFBLXJhdGVkIGNvcnBvcmF0ZSBib25kIHlpZWxkCnRyeUNhdGNoKHsKICBnZXRTeW1ib2xzKCJER1MxMCIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpICAjIDEwLXllYXIgVHJlYXN1cnkgYm9uZCB5aWVsZAogIGdldFN5bWJvbHMoIkJBTUxDMEExQ0FBQUVZIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSkgICMgQUFBLXJhdGVkIGNvcnBvcmF0ZSBib25kIHlpZWxkCiAgCiAgIyBFeHRyYWN0IHlpZWxkcyBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybQogIHRyZWFzdXJ5X3lpZWxkIDwtIG5hLm9taXQoREdTMTBbZW5kX2RhdGVdIC8gMTAwKSAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKICBjb3Jwb3JhdGVfeWllbGQgPC0gbmEub21pdChCQU1MQzBBMUNBQUFFWVtlbmRfZGF0ZV0gLyAxMDApICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQogIAogICMgVmVyaWZ5IHRoYXQgdGhlIGRhdGEgaXMgZXh0cmFjdGVkIGNvcnJlY3RseSBmb3IgdGhlIGdpdmVuIGRhdGUKICBpZiAobGVuZ3RoKHRyZWFzdXJ5X3lpZWxkKSA9PSAwIHx8IGxlbmd0aChjb3Jwb3JhdGVfeWllbGQpID09IDApIHsKICAgIHN0b3AoIkRhdGEgZm9yIHRoZSBzcGVjaWZpZWQgZW5kIGRhdGUgaXMgbm90IGF2YWlsYWJsZS4iKQogIH0KICAKICAjIENhbGN1bGF0ZSB0aGUgeWllbGQgZGlmZmVyZW5jZSAoc3ByZWFkKQogIHlpZWxkX2RpZmZlcmVuY2UgPC0gZmlyc3QoY29ycG9yYXRlX3lpZWxkKSAtIGZpcnN0KHRyZWFzdXJ5X3lpZWxkKQogIAogICMgQ3JlYXRlIGEgZGF0YSBmcmFtZSB0byBkaXNwbGF5IHRoZSByZXN1bHRzCiAgcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogICAgTWV0cmljID0gYygiMTAtWWVhciBUcmVhc3VyeSBCb25kIFlpZWxkIiwgIkNvcnBvcmF0ZSBIaWdoLVF1YWxpdHkgQm9uZCBZaWVsZCIsICJZaWVsZCBQcmVtaXVtIChDb3Jwb3JhdGUgLSBUcmVhc3VyeSkiKSwKICAgIFZhbHVlID0gYygKICAgICAgcGFzdGUwKHJvdW5kKGZpcnN0KHRyZWFzdXJ5X3lpZWxkKSAqIDEwMCwgMiksICIlIiksCiAgICAgIHBhc3RlMChyb3VuZChmaXJzdChjb3Jwb3JhdGVfeWllbGQpICogMTAwLCAyKSwgIiUiKSwKICAgICAgcGFzdGUwKHJvdW5kKHlpZWxkX2RpZmZlcmVuY2UgKiAxMDAsIDIpLCAiJSIpCiAgICApCiAgKQogIAogICMgRGlzcGxheSB0aGUgcmVzdWx0cyBpbiBhIHRhYmxlIGZvcm1hdCB1c2luZyBrbml0cjo6a2FibGUoKQogIHByaW50KGthYmxlKHJlc3VsdHMsIGNhcHRpb24gPSBwYXN0ZSgiQm9uZCBZaWVsZHMgYW5kIFByZW1pdW1zIG9uIiwgZm9ybWF0KGVuZF9kYXRlLCAiJVktJW0tJWQiKSkpKQp9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICBjYXQoIkVycm9yIHJldHJpZXZpbmcgZGF0YToiLCBlJG1lc3NhZ2UsICJcbiIpCn0pCmBgYAoKCkNvcnBvcmF0ZSBoaWdoLXF1YWxpdHkgYm9uZHMgZ2VuZXJhbGx5IGhhdmUgaGlnaGVyIHlpZWxkcyB0aGFuIFRyZWFzdXJ5IGJvbmRzLiBUaGlzIGRpZmZlcmVuY2UsIGtub3duIGFzIHRoZSBzcHJlYWQsIGV4aXN0cyBiZWNhdXNlIGNvcnBvcmF0ZSBib25kcyBjYXJyeSBjcmVkaXQgcmlzayAodGhlIHJpc2sgdGhhdCB0aGUgaXNzdWVyIG1heSBkZWZhdWx0KSwgd2hpbGUgVHJlYXN1cnkgYm9uZHMgYXJlIGNvbnNpZGVyZWQgdmlydHVhbGx5IHJpc2stZnJlZSBhcyB0aGV5IGFyZSBiYWNrZWQgYnkgdGhlIFUuUy4gZ292ZXJubWVudC4gVGhlIHNpemUgb2YgdGhlIHNwcmVhZCB2YXJpZXMgZGVwZW5kaW5nIG9uIG1hcmtldCBjb25kaXRpb25zLCBzdWNoIGFzIGludmVzdG9yIHJpc2sgYXBwZXRpdGUgYW5kIGVjb25vbWljIG91dGxvb2suCgojIyBMNy4yIENvbXBhcmluZyBZaWVsZHMgb24gTG9uZy10ZXJtIEJvbmRzCgojIyMgRGlmZmVyZW5jZSBiZXR3ZWVuIHlpZWxkcyBvbiBsb25nLXRlcm0gVHJlYXN1cnkgYm9uZHMgYW5kIGxvbmctdGVybSBtdW5pY2lwYWwgYm9uZHM6CgoKTXVuaWNpcGFsIGJvbmRzIG9mdGVuIGhhdmUgbG93ZXIgeWllbGRzIHRoYW4gVHJlYXN1cnkgYm9uZHMgZm9yIGludmVzdG9ycyBpbiBoaWdoIHRheCBicmFja2V0cyBiZWNhdXNlIHRoZSBpbnRlcmVzdCBlYXJuZWQgb24gbXVuaWNpcGFsIGJvbmRzIGlzIHR5cGljYWxseSBleGVtcHQgZnJvbSBmZWRlcmFsIHRheGVzIChhbmQgc29tZXRpbWVzIHN0YXRlIGFuZCBsb2NhbCB0YXhlcykuIFRoaXMgdGF4LWV4ZW1wdCBzdGF0dXMgbWFrZXMgbXVuaWNpcGFsIGJvbmRzIG1vcmUgYXR0cmFjdGl2ZSBvbiBhbiBhZnRlci10YXggYmFzaXMsIHJlZHVjaW5nIHRoZWlyIHlpZWxkcyBjb21wYXJlZCB0byB0YXhhYmxlIFRyZWFzdXJ5IGJvbmRzLiBUaGUgZGlmZmVyZW5jZSByZWZsZWN0cyB0aGUgdGF4IGFkdmFudGFnZSBhbmQgdGhlIGNyZWRpdCBxdWFsaXR5IG9mIHRoZSBtdW5pY2lwYWwgaXNzdWVycy4KCgpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShrbml0cikKCiMgRGVmaW5lIHRoZSBzdGFydCBhbmQgZW5kIGRhdGVzIG9mIHRoZSBzY2hvb2wgdGVybQpzdGFydF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMDQtMDEiKQplbmRfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTEwLTMwIikKCiMgRG93bmxvYWQgZGF0YSBmb3IgMjYtd2VlayBhbmQgMTMtd2VlayBULWJpbGwgeWllbGRzCnRyeUNhdGNoKHsKICBnZXRTeW1ib2xzKCJEVEI2Iiwgc3JjID0gIkZSRUQiLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSkgICMgMjYtd2VlayBULWJpbGwgeWllbGQKICBnZXRTeW1ib2xzKCJEVEIzIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSkgICMgMTMtd2VlayBULWJpbGwgeWllbGQKICAKICAjIEV4dHJhY3QgeWllbGRzIGF0IHRoZSBzdGFydCBvZiB0aGUgc2Nob29sIHRlcm0KICB0X2JpbGxfMjZfc3RhcnQgPC0gbmEub21pdChEVEI2W3N0YXJ0X2RhdGVdIC8gMTAwKSAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKICB0X2JpbGxfMTNfc3RhcnQgPC0gbmEub21pdChEVEIzW3N0YXJ0X2RhdGVdIC8gMTAwKSAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKICAKICAjIEV4dHJhY3QgeWllbGRzIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtCiAgdF9iaWxsXzI2X2VuZCA8LSBuYS5vbWl0KERUQjZbZW5kX2RhdGVdIC8gMTAwKSAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKICB0X2JpbGxfMTNfZW5kIDwtIG5hLm9taXQoRFRCM1tlbmRfZGF0ZV0gLyAxMDApICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQogIAogICMgQ2FsY3VsYXRlIHRoZSB5aWVsZCBkaWZmZXJlbmNlIChzcHJlYWQpIGF0IHRoZSBzdGFydCBvZiB0aGUgdGVybQogIHlpZWxkX2RpZmZlcmVuY2Vfc3RhcnQgPC0gZmlyc3QodF9iaWxsXzI2X3N0YXJ0KSAtIGZpcnN0KHRfYmlsbF8xM19zdGFydCkKICAKICAjIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gZGlzcGxheSByZXN1bHRzCiAgcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogICAgTWV0cmljID0gYygiMjYtd2VlayBULWJpbGwgeWllbGQgYXQgc3RhcnQiLCAiMTMtd2VlayBULWJpbGwgeWllbGQgYXQgc3RhcnQiLCAiWWllbGQgRGlmZmVyZW5jZSAoMjYtd2VlayAtIDEzLXdlZWspIGF0IHN0YXJ0IiwKICAgICAgICAgICAgICAgIkN1cnZlIFNsb3BlIGF0IHN0YXJ0IiwgIk1hcmtldCBFeHBlY3RhdGlvbiBhdCBzdGFydCIsCiAgICAgICAgICAgICAgICIyNi13ZWVrIFQtYmlsbCB5aWVsZCBhdCBlbmQiLCAiMTMtd2VlayBULWJpbGwgeWllbGQgYXQgZW5kIiksCiAgICBWYWx1ZSA9IGMoCiAgICAgIHBhc3RlKHJvdW5kKGZpcnN0KHRfYmlsbF8yNl9zdGFydCkgKiAxMDAsIDIpLCAiJSIpLAogICAgICBwYXN0ZShyb3VuZChmaXJzdCh0X2JpbGxfMTNfc3RhcnQpICogMTAwLCAyKSwgIiUiKSwKICAgICAgcGFzdGUocm91bmQoeWllbGRfZGlmZmVyZW5jZV9zdGFydCAqIDEwMCwgMiksICIlIiksCiAgICAgIGlmICh5aWVsZF9kaWZmZXJlbmNlX3N0YXJ0ID4gMCkgIlVwd2FyZCBTbG9wZSIgZWxzZSBpZiAoeWllbGRfZGlmZmVyZW5jZV9zdGFydCA8IDApICJEb3dud2FyZCBTbG9wZSIgZWxzZSAiRmxhdCIsCiAgICAgIGlmICh5aWVsZF9kaWZmZXJlbmNlX3N0YXJ0ID4gMCkgIkhpZ2hlciByYXRlcyBleHBlY3RlZCIgZWxzZSBpZiAoeWllbGRfZGlmZmVyZW5jZV9zdGFydCA8IDApICJMb3dlciByYXRlcyBleHBlY3RlZCIgZWxzZSAiTm8gY2xlYXIgZXhwZWN0YXRpb24iLAogICAgICBwYXN0ZShyb3VuZChmaXJzdCh0X2JpbGxfMjZfZW5kKSAqIDEwMCwgMiksICIlIiksCiAgICAgIHBhc3RlKHJvdW5kKGZpcnN0KHRfYmlsbF8xM19lbmQpICogMTAwLCAyKSwgIiUiKQogICAgKQogICkKICAKICAjIERpc3BsYXkgdGhlIHJlc3VsdHMgdXNpbmcga2FibGUgZm9yIGJldHRlciBmb3JtYXR0aW5nCiAga2FibGUocmVzdWx0cywgY2FwdGlvbiA9ICJBbmFseXNpcyBvZiBULUJpbGwgWWllbGQgYW5kIEV4cGVjdGF0aW9ucyBPdmVyIHRoZSBUZXJtIikKICAKfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiAgY2F0KCJFcnJvciByZXRyaWV2aW5nIGRhdGE6IiwgZSRtZXNzYWdlLCAiXG4iKQp9KQpgYGAKCiMjIEw3LjYgRGlkIGludGVyZXN0IHJhdGVzIG1vdmUgaW4gdGhhdCBkaXJlY3Rpb24gb3ZlciB0aGUgc2Nob29sIHRlcm0/CgpZZXMsIHRoZSBtYXJrZXQgZXhwZWN0YXRpb24gaXMgcmlnaHQuCgojIyBMNy43IGFuZCA3LjgKCmBgYHtyfQojIEluc3RhbGwgYW5kIGxvYWQgbmVjZXNzYXJ5IHBhY2thZ2VzCmlmICghcmVxdWlyZShxdWFudG1vZCkpIGluc3RhbGwucGFja2FnZXMoInF1YW50bW9kIikKaWYgKCFyZXF1aXJlKGtuaXRyKSkgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBJbml0aWFsaXplIGEgZGF0YSBmcmFtZSB0byBzdG9yZSB0aGUgcmVzdWx0cwpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgRGF0ZSA9IGNoYXJhY3RlcigpLAogIGAzMC1ZZWFyIFRyZWFzdXJ5IEJvbmQgWWllbGQgKCUpYCA9IG51bWVyaWMoKSwKICBgMTMtV2VlayBULUJpbGwgWWllbGQgKCUpYCA9IG51bWVyaWMoKSwKICBgWWllbGQgRGlmZmVyZW5jZSAoMzAtWWVhciAtIDEzLVdlZWspICglKWAgPSBudW1lcmljKCksCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFCikKCiMgUGFydCA3Ljc6IEFuYWx5emUgdGhlIHlpZWxkIGRpZmZlcmVuY2UgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2Nob29sIHRlcm0Kc3RhcnRfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA0LTAxIikKCnRyeUNhdGNoKHsKICAjIERvd25sb2FkIGRhdGEgZm9yIHRoZSBwZXJpb2QgY292ZXJpbmcgdGhlIHN0YXJ0IG9mIHRoZSBzY2hvb2wgdGVybQogIGdldFN5bWJvbHMoIkRHUzMwIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gIjIwMjQtMDMtMDEiLCB0byA9ICIyMDI0LTA0LTE1IikgICMgMzAteWVhciBUcmVhc3VyeSBib25kCiAgZ2V0U3ltYm9scygiRFRCMyIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9ICIyMDI0LTAzLTAxIiwgdG8gPSAiMjAyNC0wNC0xNSIpICAjIDEzLXdlZWsgVC1iaWxsCiAgCiAgIyBFeHRyYWN0IHlpZWxkcyBhdCB0aGUgc3RhcnQgb2YgdGhlIHNjaG9vbCB0ZXJtCiAgbG9uZ190ZXJtX3lpZWxkIDwtIG5hLm9taXQoREdTMzBbc3RhcnRfZGF0ZV0gLyAxMDApICAjIENvbnZlcnQgdG8gcGVyY2VudGFnZQogIHNob3J0X3Rlcm1feWllbGQgPC0gbmEub21pdChEVEIzW3N0YXJ0X2RhdGVdIC8gMTAwKSAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKICAKICAjIENhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZQogIHlpZWxkX2RpZmZlcmVuY2UgPC0gZmlyc3QobG9uZ190ZXJtX3lpZWxkKSAtIGZpcnN0KHNob3J0X3Rlcm1feWllbGQpCiAgCiAgIyBTdG9yZSByZXN1bHRzIGluIHRoZSBkYXRhIGZyYW1lCiAgcmVzdWx0cyA8LSByYmluZChyZXN1bHRzLCBkYXRhLmZyYW1lKAogICAgRGF0ZSA9IGZvcm1hdChzdGFydF9kYXRlLCAiJUIgJWQsICVZIiksCiAgICBgMzAtWWVhciBUcmVhc3VyeSBCb25kIFlpZWxkICglKWAgPSByb3VuZChmaXJzdChsb25nX3Rlcm1feWllbGQpICogMTAwLCAyKSwKICAgIGAxMy1XZWVrIFQtQmlsbCBZaWVsZCAoJSlgID0gcm91bmQoZmlyc3Qoc2hvcnRfdGVybV95aWVsZCkgKiAxMDAsIDIpLAogICAgYFlpZWxkIERpZmZlcmVuY2UgKDMwLVllYXIgLSAxMy1XZWVrKSAoJSlgID0gcm91bmQoeWllbGRfZGlmZmVyZW5jZSAqIDEwMCwgMikKICApKQp9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICBjYXQoIkVycm9yIHJldHJpZXZpbmcgZGF0YToiLCBlJG1lc3NhZ2UsICJcbiIpCn0pCgojIFBhcnQgNy44OiBBbmFseXplIHRoZSB5aWVsZCBkaWZmZXJlbmNlIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtCmVuZF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMTAtMzAiKQoKdHJ5Q2F0Y2goewogICMgRG93bmxvYWQgZGF0YSBmb3IgdGhlIHBlcmlvZCBjb3ZlcmluZyB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybQogIGdldFN5bWJvbHMoIkRHUzMwIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gIjIwMjQtMDktMDEiLCB0byA9ICIyMDI0LTExLTAxIikgICMgMzAteWVhciBUcmVhc3VyeSBib25kCiAgZ2V0U3ltYm9scygiRFRCMyIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9ICIyMDI0LTA5LTAxIiwgdG8gPSAiMjAyNC0xMS0wMSIpICAjIDEzLXdlZWsgVC1iaWxsCiAgCiAgIyBFeHRyYWN0IHlpZWxkcyBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybQogIGxvbmdfdGVybV95aWVsZCA8LSBuYS5vbWl0KERHUzMwW2VuZF9kYXRlXSAvIDEwMCkgICMgQ29udmVydCB0byBwZXJjZW50YWdlCiAgc2hvcnRfdGVybV95aWVsZCA8LSBuYS5vbWl0KERUQjNbZW5kX2RhdGVdIC8gMTAwKSAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKICAKICAjIENhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZQogIHlpZWxkX2RpZmZlcmVuY2UgPC0gZmlyc3QobG9uZ190ZXJtX3lpZWxkKSAtIGZpcnN0KHNob3J0X3Rlcm1feWllbGQpCiAgCiAgIyBTdG9yZSByZXN1bHRzIGluIHRoZSBkYXRhIGZyYW1lCiAgcmVzdWx0cyA8LSByYmluZChyZXN1bHRzLCBkYXRhLmZyYW1lKAogICAgRGF0ZSA9IGZvcm1hdChlbmRfZGF0ZSwgIiVCICVkLCAlWSIpLAogICAgYDMwLVllYXIgVHJlYXN1cnkgQm9uZCBZaWVsZCAoJSlgID0gcm91bmQoZmlyc3QobG9uZ190ZXJtX3lpZWxkKSAqIDEwMCwgMiksCiAgICBgMTMtV2VlayBULUJpbGwgWWllbGQgKCUpYCA9IHJvdW5kKGZpcnN0KHNob3J0X3Rlcm1feWllbGQpICogMTAwLCAyKSwKICAgIGBZaWVsZCBEaWZmZXJlbmNlICgzMC1ZZWFyIC0gMTMtV2VlaykgKCUpYCA9IHJvdW5kKHlpZWxkX2RpZmZlcmVuY2UgKiAxMDAsIDIpCiAgKSkKfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiAgY2F0KCJFcnJvciByZXRyaWV2aW5nIGRhdGE6IiwgZSRtZXNzYWdlLCAiXG4iKQp9KQoKIyBEaXNwbGF5IHRoZSByZXN1bHRzIGFzIGEga2FibGUgdGFibGUKa2FibGUocmVzdWx0cywgY2FwdGlvbiA9ICJDb21wYXJpc29uIG9mIFRyZWFzdXJ5IEJvbmQgYW5kIFQtQmlsbCBZaWVsZHMiKQpgYGAKCiMjIEw3LjkKCkF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNjaG9vbCB0ZXJtIChBcHJpbCAxLCAyMDI0KSwgdGhlIHlpZWxkIGN1cnZlIHdhcyBpbnZlcnRlZCwgd2l0aCB0aGUgMTMtd2VlayBULWJpbGwgeWllbGQgKDUuMjMlKSBoaWdoZXIgdGhhbiB0aGUgMzAteWVhciBUcmVhc3VyeSBib25kIHlpZWxkICg0LjQ3JSksIGluZGljYXRpbmcgY29uY2VybnMgYWJvdXQgYSBwb3RlbnRpYWwgZWNvbm9taWMgc2xvd2Rvd24gYW5kIGEgcHJlZmVyZW5jZSBmb3IgbG9uZ2VyLXRlcm0gYm9uZHMgZHVlIHRvIGFudGljaXBhdGVkIGxvd2VyIGZ1dHVyZSBpbnRlcmVzdCByYXRlcy4gQnkgdGhlIGVuZCBvZiB0aGUgdGVybSAoT2N0b2JlciAzMCwgMjAyNCksIHRoZSB5aWVsZCBjdXJ2ZSBiZWNhbWUgc2xpZ2h0bHkgdXB3YXJkLXNsb3BpbmcsIHdpdGggdGhlIDMwLXllYXIgeWllbGQgKDQuNDklKSBzbGlnaHRseSBoaWdoZXIgdGhhbiB0aGUgMTMtd2VlayB5aWVsZCAoNC40NyUpLiBUaGlzIHNoaWZ0IHN1Z2dlc3RzIGFuIGltcHJvdmVtZW50IGluIG1hcmtldCBzZW50aW1lbnQgYW5kIGV4cGVjdGF0aW9ucyBmb3IgZWNvbm9taWMgZ3Jvd3RoLCBzaWduYWxpbmcgdGhhdCBpbnZlc3RvcnMgZXhwZWN0ZWQgaW50ZXJlc3QgcmF0ZXMgdG8gcmlzZSBhbmQgdGhlIGVjb25vbXkgdG8gcmVtYWluIHN0YWJsZS4KCiMjIEw3LjEwCgpgYGB7cn0KIyBMb2FkIHRoZSBuZWNlc3NhcnkgcGFja2FnZQpsaWJyYXJ5KHF1YW50bW9kKQoKIyBHZXQgdGhlIGZlZGVyYWwgZnVuZHMgcmF0ZSBmcm9tIEZSRUQKZ2V0U3ltYm9scygiRkVERlVORFMiLCBzcmMgPSAiRlJFRCIpCgojIEZpbHRlciBkYXRhIGZvciB0aGUgcmVsZXZhbnQgZGF0ZXMKc3RhcnRfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA0LTAxIikKZW5kX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0xMC0zMCIpCmZlZGVyYWxfZnVuZHNfZmlsdGVyZWQgPC0gRkVERlVORFNbcGFzdGUoc3RhcnRfZGF0ZSwgZW5kX2RhdGUsIHNlcCA9ICIvIildCgojIFBsb3QgdGhlIGZpbHRlcmVkIGZlZGVyYWwgZnVuZHMgcmF0ZSBkYXRhCnBsb3QoZmVkZXJhbF9mdW5kc19maWx0ZXJlZCwgCiAgICAgbWFpbiA9ICJGZWRlcmFsIEZ1bmRzIFJhdGUgZnJvbSBBcHJpbCAxLCAyMDI0IHRvIE9jdG9iZXIgMzAsIDIwMjQiLCAKICAgICBjb2wgPSAiYmx1ZSIsIAogICAgIGx3ZCA9IDIsIAogICAgIHhsYWIgPSAiRGF0ZSIsIAogICAgIHlsYWIgPSAiRmVkZXJhbCBGdW5kcyBSYXRlICglKSIpCmBgYAojIyBMNy4xMQpUaGUgbW92ZW1lbnRzIGluIGludGVyZXN0IHJhdGVzIGR1cmluZyB0aGUgc2Nob29sIHRlcm0gd2VyZSBsaWtlbHkgaW5mbHVlbmNlZCBieSB0aGUgRmVk4oCZcyBtb25ldGFyeSBwb2xpY3ksIGFzIGNoYW5nZXMgaW4gdGhlIGZlZGVyYWwgZnVuZHMgcmF0ZSBhcmUgYSBwcmltYXJ5IHRvb2wgZm9yIG1hbmFnaW5nIGVjb25vbWljIGNvbmRpdGlvbnMuIElmIHRoZSBmZWRlcmFsIGZ1bmRzIHJhdGUgd2FzIGFkanVzdGVkIGR1cmluZyB0aGlzIHBlcmlvZCwgaXQgc3VnZ2VzdHMgdGhlIEZlZCB3YXMgYWN0aXZlbHkgcmVzcG9uZGluZyB0byBlY29ub21pYyBpbmRpY2F0b3JzIGFuZCBpbmZsdWVuY2luZyBtYXJrZXQgaW50ZXJlc3QgcmF0ZXMuIEhvd2V2ZXIsIGlmIG5vIHNpZ25pZmljYW50IGNoYW5nZXMgd2VyZSBtYWRlIHRvIHRoZSBmZWRlcmFsIGZ1bmRzIHJhdGUsIG90aGVyIGZhY3RvcnMsIHN1Y2ggYXMgbWFya2V0IGV4cGVjdGF0aW9ucywgZWNvbm9taWMgZ3Jvd3RoLCBvciBnbG9iYWwgZWNvbm9taWMgY29uZGl0aW9ucywgbWlnaHQgaGF2ZSBjb250cmlidXRlZCB0byB0aGUgb2JzZXJ2ZWQgbW92ZW1lbnRzIGluIGludGVyZXN0IHJhdGVzLgoKSXQncyBpbXBvcnRhbnQgdG8gbm90ZSB0aGF0IHRoZXNlIGZhY3RvcnMgY2FuIGludGVyYWN0IGFuZCBpbmZsdWVuY2UgZWFjaCBvdGhlci4gRm9yIGV4YW1wbGUsIGEgY2hhbmdlIGluIHRoZSBmZWRlcmFsIGZ1bmRzIHJhdGUgY2FuIGltcGFjdCBtYXJrZXQgZXhwZWN0YXRpb25zLCB3aGljaCBpbiB0dXJuIGNhbiBhZmZlY3Qgb3RoZXIgaW50ZXJlc3QgcmF0ZXMuCgoKCiMjIEw3LjEyCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBEZWZpbmUgdGhlIHN0YXJ0IGFuZCBlbmQgZGF0ZXMgZm9yIHRoZSBzY2hvb2wgdGVybQpzdGFydF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMDQtMDEiKQplbmRfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTEwLTMwIikKCiMgUmV0cmlldmUgZGF0YSBmcm9tIEZSRUQKdHJ5Q2F0Y2goewogIGdldFN5bWJvbHMoIkRDUEYzTSIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpICAjIDkwLWRheSBjb21tZXJjaWFsIHBhcGVyIHlpZWxkCiAgZ2V0U3ltYm9scygiRFRCMyIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpICAgICAjIDEzLXdlZWsgVHJlYXN1cnkgYmlsbHMKCiAgIyBFeHRyYWN0IHlpZWxkcyBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybQogIGNvbW1lcmNpYWxfcGFwZXJfeWllbGQgPC0gbmEub21pdChEQ1BGM01bZW5kX2RhdGVdIC8gMTAwKSAgIyBDb252ZXJ0IHRvIHBlcmNlbnRhZ2UKICB0X2JpbGxfeWllbGQgPC0gbmEub21pdChEVEIzW2VuZF9kYXRlXSAvIDEwMCkgICAgICAgICAgICAgICMgQ29udmVydCB0byBwZXJjZW50YWdlCgogICMgQ2FsY3VsYXRlIHRoZSB5aWVsZCBkaWZmZXJlbmNlIChwcmVtaXVtKQogIHlpZWxkX2RpZmZlcmVuY2UgPC0gZmlyc3QoY29tbWVyY2lhbF9wYXBlcl95aWVsZCkgLSBmaXJzdCh0X2JpbGxfeWllbGQpCgogICMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgZGlzcGxheWluZyByZXN1bHRzCiAgcmVzdWx0IDwtIGRhdGEuZnJhbWUoCiAgICBEYXRlID0gYXMuY2hhcmFjdGVyKGVuZF9kYXRlKSwKICAgIGA5MC1kYXkgQ29tbWVyY2lhbCBQYXBlciBZaWVsZCAoJSlgID0gcm91bmQoZmlyc3QoY29tbWVyY2lhbF9wYXBlcl95aWVsZCkgKiAxMDAsIDIpLAogICAgYDEzLXdlZWsgVC1CaWxsIFlpZWxkICglKWAgPSByb3VuZChmaXJzdCh0X2JpbGxfeWllbGQpICogMTAwLCAyKSwKICAgIGBZaWVsZCBQcmVtaXVtICglKWAgPSByb3VuZCh5aWVsZF9kaWZmZXJlbmNlICogMTAwLCAyKQogICkKCiAgIyBEaXNwbGF5IHJlc3VsdHMgdXNpbmcga2FibGUKICBrYWJsZShyZXN1bHQsIGNhcHRpb24gPSAiUmVzdWx0cyBmb3IgdGhlIEVuZCBvZiB0aGUgU2Nob29sIFRlcm0iKQp9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICAjIEVycm9yIGhhbmRsaW5nCiAgY2F0KCJFcnJvciByZXRyaWV2aW5nIGRhdGE6IiwgZSRtZXNzYWdlLCAiXG4iKQp9KQpgYGAKClRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHlpZWxkIG9uIDkwLWRheSBjb21tZXJjaWFsIHBhcGVyIGFuZCAxMy13ZWVrIFQtYmlsbHMgaXMgdGhlIHByZW1pdW0gYXNzb2NpYXRlZCB3aXRoIHRoZSBpbmNyZWFzZWQgcmlzayBvZiBob2xkaW5nIGNvbW1lcmNpYWwgcGFwZXIuIFRoaXMgcHJlbWl1bSBjb21wZW5zYXRlcyBpbnZlc3RvcnMgZm9yIHRoZSBoaWdoZXIgY3JlZGl0IGFuZCBsaXF1aWRpdHkgcmlza3MgcmVsYXRpdmUgdG8gZ292ZXJubWVudCBzZWN1cml0aWVzLgoKIyMgTDcuMTMKCgpFdmVuIGFmdGVyIGF0dGVtcHRpbmcgdG8gZmluZCB0aGUgY2xvc2VzdCBhdmFpbGFibGUgZGF0ZSB0byB0aGUgcmVxdWVzdGVkIHBlcmlvZCwgdGhlcmUgd2FzIHN0aWxsIG5vIGRhdGEgZm9yIHRoZSA5MC1kYXkgY29tbWVyY2lhbCBwYXBlciB5aWVsZCBhbmQgdGhlIDEzLXdlZWsgVC1iaWxsIHlpZWxkIGZvciBBcHJpbCAyMDI0IG9yIHNvbWUgc2ltaWxpYXIgZGF0ZS4gVGhpcyByZWluZm9yY2VzIHRoZSBjb25jbHVzaW9uIHRoYXQgZGF0YSBmb3IgdGhlc2Ugc3BlY2lmaWMgZGF0ZXMgbWlnaHQgbm90IGJlIHJlcG9ydGVkIG9yIGFjY2Vzc2libGUgaW4gdGhlIEZSRUQgZGF0YWJhc2Ugb3Igb3RoZXIgc291cmNlcy4KClRoZSBwcmVtaXVtIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgOTAtZGF5IGNvbW1lcmNpYWwgcGFwZXIgeWllbGQgYW5kIHRoZSAxMy13ZWVrIFQtYmlsbCB5aWVsZCByZWZsZWN0cyBtYXJrZXQgY29uZGl0aW9ucywgaW5jbHVkaW5nIHJpc2sgcGVyY2VwdGlvbiwgbGlxdWlkaXR5LCBhbmQgc3VwcGx5IGFuZCBkZW1hbmQuIFR5cGljYWxseSwgY29tbWVyY2lhbCBwYXBlciB5aWVsZHMgdGVuZCB0byBiZSBoaWdoZXIgdGhhbiBULWJpbGwgeWllbGRzIGR1ZSB0byB0aGUgaGlnaGVyIGNyZWRpdCByaXNrIGFzc29jaWF0ZWQgd2l0aCBjb3Jwb3JhdGUgaXNzdWVycyBjb21wYXJlZCB0byB0aGUgVS5TLiBnb3Zlcm5tZW50LiBUaGlzIHByZW1pdW0gY2FuIGNoYW5nZSBkdWUgdG8gc2hpZnRzIGluIGVjb25vbWljIGNvbmRpdGlvbnMgb3IgcG9saWN5IGNoYW5nZXMsIHN1Y2ggYXMgYWRqdXN0bWVudHMgYnkgdGhlIEZlZGVyYWwgUmVzZXJ2ZSB0byBpbnRlcmVzdCByYXRlcyBvciBtYXJrZXQgbGlxdWlkaXR5IGNyaXNlcy4KCgpgYGB7cn0KCmBgYAoKIyMgTDcuMTQKYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCgojIERlZmluZSB0aGUgc3RhcnQgYW5kIGVuZCBkYXRlcyBmb3IgdGhlIHNjaG9vbCB0ZXJtCnN0YXJ0X2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNC0wMSIpCmVuZF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMTAtMzAiKQoKIyBEb3dubG9hZCBoaWdoLXF1YWxpdHkgY29ycG9yYXRlIGJvbmQgZGF0YSAoZXhhbXBsZTogQUFBLXJhdGVkIGNvcnBvcmF0ZSBib25kcykKdHJ5Q2F0Y2goewogIGdldFN5bWJvbHMoIkJBTUxDMEExQ0FBQUVZIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gIjIwMjQtMDMtMzAiLCB0byA9ICIyMDI0LTA1LTE1IiwgYXV0by5hc3NpZ24gPSBUUlVFKQogIGhpZ2hfcXVhbGl0eV95aWVsZCA8LSBuYS5vbWl0KEJBTUxDMEExQ0FBQUVZKSAgIyBHZXQgdGhlIGRhdGEgYW5kIHJlbW92ZSBOQXMKICAKICAjIEZpbmQgdGhlIGNsb3Nlc3QgYXZhaWxhYmxlIGRhdGEgcG9pbnQgYXQgdGhlIHN0YXJ0IGRhdGUKICBjbG9zZXN0X2RhdGVfc3RhcnQgPC0gaW5kZXgoaGlnaF9xdWFsaXR5X3lpZWxkKVt3aGljaC5taW4oYWJzKGluZGV4KGhpZ2hfcXVhbGl0eV95aWVsZCkgLSBzdGFydF9kYXRlKSldCiAgaGlnaF9xdWFsaXR5X3lpZWxkX29uX3N0YXJ0IDwtIGhpZ2hfcXVhbGl0eV95aWVsZFtjbG9zZXN0X2RhdGVfc3RhcnRdCiAgCiAgY2F0KCJIaWdoLXF1YWxpdHkgY29ycG9yYXRlIGJvbmQgeWllbGQgZGF0YSBkb3dubG9hZGVkIHN1Y2Nlc3NmdWxseS5cbiIpCn0sIGVycm9yID0gZnVuY3Rpb24oZSkgewogIGNhdCgiRXJyb3IgZG93bmxvYWRpbmcgaGlnaC1xdWFsaXR5IGNvcnBvcmF0ZSBib25kIGRhdGE6IiwgZSRtZXNzYWdlLCAiXG4iKQogIGhpZ2hfcXVhbGl0eV95aWVsZF9vbl9zdGFydCA8LSBOQQp9KQoKIyBEb3dubG9hZCBoaWdoLXlpZWxkIGNvcnBvcmF0ZSBib25kIGRhdGEgKGV4YW1wbGU6IGp1bmsgYm9uZHMpCnRyeUNhdGNoKHsKICBnZXRTeW1ib2xzKCJCQU1MSDBBMEhZTTJFWSIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9ICIyMDI0LTA5LTAxIiwgdG8gPSAiMjAyNC0xMC0zMSIsIGF1dG8uYXNzaWduID0gVFJVRSkKICBoaWdoX3lpZWxkX2JvbmQgPC0gbmEub21pdChCQU1MSDBBMEhZTTJFWSkgICMgR2V0IHRoZSBkYXRhIGFuZCByZW1vdmUgTkFzCiAgCiAgIyBGaW5kIHRoZSBjbG9zZXN0IGF2YWlsYWJsZSBkYXRhIHBvaW50IGF0IHRoZSBlbmQgZGF0ZQogIGNsb3Nlc3RfZGF0ZV9lbmQgPC0gaW5kZXgoaGlnaF95aWVsZF9ib25kKVt3aGljaC5taW4oYWJzKGluZGV4KGhpZ2hfeWllbGRfYm9uZCkgLSBlbmRfZGF0ZSkpXQogIGhpZ2hfeWllbGRfYm9uZF9vbl9lbmQgPC0gaGlnaF95aWVsZF9ib25kW2Nsb3Nlc3RfZGF0ZV9lbmRdCiAgCiAgY2F0KCJIaWdoLXlpZWxkIGNvcnBvcmF0ZSBib25kIHlpZWxkIGRhdGEgZG93bmxvYWRlZCBzdWNjZXNzZnVsbHkuXG4iKQp9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICBjYXQoIkVycm9yIGRvd25sb2FkaW5nIGhpZ2gteWllbGQgY29ycG9yYXRlIGJvbmQgZGF0YToiLCBlJG1lc3NhZ2UsICJcbiIpCiAgaGlnaF95aWVsZF9ib25kX29uX2VuZCA8LSBOQQp9KQoKIyBEaXNwbGF5IHRoZSByZXN1bHRzIGlmIHRoZSBkYXRhIGlzIGF2YWlsYWJsZQppZiAoIWlzLm5hKGhpZ2hfcXVhbGl0eV95aWVsZF9vbl9zdGFydCkgJiYgIWlzLm5hKGhpZ2hfeWllbGRfYm9uZF9vbl9lbmQpKSB7CiAgIyBEaXNwbGF5IHRoZSByZXN1bHRzCiAgY2F0KCJcbkhpZ2gtcXVhbGl0eSBjb3Jwb3JhdGUgYm9uZCB5aWVsZCBvbiBBcHJpbCAxLCAyMDI0IChjbG9zZXN0IGF2YWlsYWJsZSk6IiwgCiAgICAgIHJvdW5kKGhpZ2hfcXVhbGl0eV95aWVsZF9vbl9zdGFydCwgNCksICJcbiIpCiAgY2F0KCJIaWdoLXlpZWxkIGNvcnBvcmF0ZSBib25kIHlpZWxkIG9uIE9jdG9iZXIgMzAsIDIwMjQgKGNsb3Nlc3QgYXZhaWxhYmxlKToiLCAKICAgICAgcm91bmQoaGlnaF95aWVsZF9ib25kX29uX2VuZCwgNCksICJcbiIpCn0gZWxzZSB7CiAgY2F0KCJJbnN1ZmZpY2llbnQgZGF0YSB0byBkaXNwbGF5IHRoZSB5aWVsZHMuXG4iKQp9ICAKYGBgClRoZSAyLjAzJSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHlpZWxkcyBvbiBoaWdoLXF1YWxpdHkgYW5kIGhpZ2gteWllbGQgY29ycG9yYXRlIGJvbmRzIHN1Z2dlc3RzIHRoYXQgaW52ZXN0b3JzIGluIE9jdG9iZXIgMjAyNCB3ZXJlIG1vcmUgY2F1dGlvdXMgYWJvdXQgdGFraW5nIG9uIHJpc2sgY29tcGFyZWQgdG8gQXByaWwgMjAyNC4gVGhlIGhpZ2hlciB5aWVsZCBvbiBoaWdoLXlpZWxkIGJvbmRzIGlzIGNvbXBlbnNhdGlvbiBmb3IgdGhlIGluY3JlYXNlZCByaXNrLCB3aGljaCBjb3VsZCBiZSBkcml2ZW4gYnkgZmFjdG9ycyBsaWtlIGVjb25vbWljIHVuY2VydGFpbnR5LCBjaGFuZ2VzIGluIGludGVyZXN0IHJhdGVzLCBvciBzaGlmdHMgaW4gaW52ZXN0b3Igc2VudGltZW50LgoKIyMgTDcuMTUKYGBge3J9CiMgSW5zdGFsbCBhbmQgbG9hZCBuZWNlc3NhcnkgcGFja2FnZXMgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkCmlmICghcmVxdWlyZShxdWFudG1vZCkpIGluc3RhbGwucGFja2FnZXMoInF1YW50bW9kIikKbGlicmFyeShxdWFudG1vZCkKCiMgRGVmaW5lIGRhdGVzIGZvciB0aGUgYmVnaW5uaW5nIGFuZCBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtCnN0YXJ0X2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNC0wMSIpCmVuZF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMTAtMzAiKQoKIyBEb3dubG9hZCBsb25nLXRlcm0gVHJlYXN1cnkgYm9uZCB5aWVsZCBkYXRhIChlLmcuLCAxMC15ZWFyIFRyZWFzdXJ5IHlpZWxkKQp0cnlDYXRjaCh7CiAgZ2V0U3ltYm9scygiR1MxMCIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUsIGF1dG8uYXNzaWduID0gVFJVRSkKICBsb25nX3Rlcm1fdHJlYXN1cnlfeWllbGQgPC0gbmEub21pdChHUzEwKSAgIyBDbGVhbiBkYXRhIGJ5IHJlbW92aW5nIE5BcwogIGNhdCgiTG9uZy10ZXJtIFRyZWFzdXJ5IGJvbmQgeWllbGQgZGF0YSBkb3dubG9hZGVkIHN1Y2Nlc3NmdWxseS5cbiIpCn0sIGVycm9yID0gZnVuY3Rpb24oZSkgewogIGNhdCgiRXJyb3IgZG93bmxvYWRpbmcgbG9uZy10ZXJtIFRyZWFzdXJ5IGJvbmQgeWllbGQgZGF0YToiLCBlJG1lc3NhZ2UsICJcbiIpCn0pCgojIEVuc3VyZSBkYXRhIGlzIGF2YWlsYWJsZSBhbmQgbm90IGVtcHR5CmlmIChleGlzdHMoImxvbmdfdGVybV90cmVhc3VyeV95aWVsZCIpICYmIG5yb3cobG9uZ190ZXJtX3RyZWFzdXJ5X3lpZWxkKSA+IDApIHsKICAjIEZpbmQgdGhlIGNsb3Nlc3QgYXZhaWxhYmxlIGRhdGUgdG8gdGhlIHN0YXJ0IGFuZCBlbmQgZGF0ZXMKICBzdGFydF9pbmRleCA8LSB3aGljaC5taW4oYWJzKGluZGV4KGxvbmdfdGVybV90cmVhc3VyeV95aWVsZCkgLSBzdGFydF9kYXRlKSkKICBlbmRfaW5kZXggPC0gd2hpY2gubWluKGFicyhpbmRleChsb25nX3Rlcm1fdHJlYXN1cnlfeWllbGQpIC0gZW5kX2RhdGUpKQogIAogIHlpZWxkX3N0YXJ0IDwtIGxvbmdfdGVybV90cmVhc3VyeV95aWVsZFtzdGFydF9pbmRleF0KICB5aWVsZF9lbmQgPC0gbG9uZ190ZXJtX3RyZWFzdXJ5X3lpZWxkW2VuZF9pbmRleF0KCiAgIyBEaXNwbGF5IHRoZSB5aWVsZHMKICBjYXQoIkxvbmctdGVybSBUcmVhc3VyeSBib25kIHlpZWxkIG9uIHRoZSBjbG9zZXN0IGF2YWlsYWJsZSBkYXRlIGluIEFwcmlsIDIwMjQ6Iiwgcm91bmQoeWllbGRfc3RhcnQsIDIpLCAiJVxuIikKICBjYXQoIkxvbmctdGVybSBUcmVhc3VyeSBib25kIHlpZWxkIG9uIHRoZSBjbG9zZXN0IGF2YWlsYWJsZSBkYXRlIGluIE9jdG9iZXIgMjAyNDoiLCByb3VuZCh5aWVsZF9lbmQsIDIpLCAiJVxuIikKfSBlbHNlIHsKICBjYXQoIkRhdGEgZm9yIGxvbmctdGVybSBUcmVhc3VyeSBib25kIHlpZWxkcyBpcyBub3QgYXZhaWxhYmxlLlxuIikKfQpgYGAKCgpUaGUgeWllbGQgb24gbG9uZy10ZXJtIFRyZWFzdXJ5IGJvbmRzIGRlY3JlYXNlZCBmcm9tIDQuNTQlIGluIEFwcmlsIDIwMjQgdG8gNC4xJSBpbiBPY3RvYmVyIDIwMjQuIFRoaXMgc3VnZ2VzdHMgdGhhdCB0aGUgaW50ZXJlc3QgcmF0ZXMgZm9yIG5ld2x5IGlzc3VlZCBib25kcyBmZWxsIGR1cmluZyB0aGUgc2Nob29sIHRlcm0uCgojIyBMNy4xNgpgYGB7cn0KIyBJbnN0YWxsIGFuZCBsb2FkIG5lY2Vzc2FyeSBwYWNrYWdlcyBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQKaWYgKCFyZXF1aXJlKHF1YW50bW9kKSkgaW5zdGFsbC5wYWNrYWdlcygicXVhbnRtb2QiKQpsaWJyYXJ5KHF1YW50bW9kKQoKIyBEZWZpbmUgc3RhcnQgYW5kIGVuZCBkYXRlcyBmb3IgdGhlIHNjaG9vbCB0ZXJtCnN0YXJ0X2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNC0wMSIpCmVuZF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMTAtMzAiKQoKIyBGZXRjaCBUcmVhc3VyeSBib25kIHlpZWxkIGRhdGEKdHJlYXN1cnlfeWllbGQgPC0gdHJ5Q2F0Y2goewogIGdldFN5bWJvbHMoIkRHUzEwIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gc3RhcnRfZGF0ZSAtIDMwLCB0byA9IGVuZF9kYXRlICsgMzAsIGF1dG8uYXNzaWduID0gRkFMU0UpCiAgbmEub21pdChER1MxMCkKfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiAgY2F0KCJFcnJvciBkb3dubG9hZGluZyBUcmVhc3VyeSBib25kIHlpZWxkIGRhdGE6IiwgZSRtZXNzYWdlLCAiXG4iKQogIE5VTEwKfSkKCiMgRmV0Y2ggQ29ycG9yYXRlIGJvbmQgeWllbGQgZGF0YQpjb3Jwb3JhdGVfeWllbGQgPC0gdHJ5Q2F0Y2goewogIGdldFN5bWJvbHMoIkJBTUxDMEExQ0FBQUVZIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gc3RhcnRfZGF0ZSAtIDMwLCB0byA9IGVuZF9kYXRlICsgMzAsIGF1dG8uYXNzaWduID0gRkFMU0UpCiAgbmEub21pdChCQU1MQzBBMUNBQUFFWSkKfSwgZXJyb3IgPSBmdW5jdGlvbihlKSB7CiAgY2F0KCJFcnJvciBkb3dubG9hZGluZyBDb3Jwb3JhdGUgYm9uZCB5aWVsZCBkYXRhOiIsIGUkbWVzc2FnZSwgIlxuIikKICBOVUxMCn0pCgojIEZpbmQgY2xvc2VzdCBkYXRlcyBmb3IgdGhlIHN0YXJ0IGFuZCBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtCmlmICghaXMubnVsbCh0cmVhc3VyeV95aWVsZCkgJiYgIWlzLm51bGwoY29ycG9yYXRlX3lpZWxkKSkgewogIHRyZWFzdXJ5X3N0YXJ0IDwtIHRyZWFzdXJ5X3lpZWxkW2luZGV4KHRyZWFzdXJ5X3lpZWxkKSA9PSBtYXgoaW5kZXgodHJlYXN1cnlfeWllbGRbaW5kZXgodHJlYXN1cnlfeWllbGQpIDw9IHN0YXJ0X2RhdGVdKSldCiAgdHJlYXN1cnlfZW5kIDwtIHRyZWFzdXJ5X3lpZWxkW2luZGV4KHRyZWFzdXJ5X3lpZWxkKSA9PSBtaW4oaW5kZXgodHJlYXN1cnlfeWllbGRbaW5kZXgodHJlYXN1cnlfeWllbGQpID49IGVuZF9kYXRlXSkpXQogIAogIGNvcnBvcmF0ZV9zdGFydCA8LSBjb3Jwb3JhdGVfeWllbGRbaW5kZXgoY29ycG9yYXRlX3lpZWxkKSA9PSBtYXgoaW5kZXgoY29ycG9yYXRlX3lpZWxkW2luZGV4KGNvcnBvcmF0ZV95aWVsZCkgPD0gc3RhcnRfZGF0ZV0pKV0KICBjb3Jwb3JhdGVfZW5kIDwtIGNvcnBvcmF0ZV95aWVsZFtpbmRleChjb3Jwb3JhdGVfeWllbGQpID09IG1pbihpbmRleChjb3Jwb3JhdGVfeWllbGRbaW5kZXgoY29ycG9yYXRlX3lpZWxkKSA+PSBlbmRfZGF0ZV0pKV0KICAKICAjIERpc3BsYXkgcmVzdWx0cwogIGNhdCgiVHJlYXN1cnkgYm9uZCB5aWVsZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybSAoY2xvc2VzdCBhdmFpbGFibGUpOiIsIHRyZWFzdXJ5X3N0YXJ0LCAiJVxuIikKICBjYXQoIlRyZWFzdXJ5IGJvbmQgeWllbGQgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0gKGNsb3Nlc3QgYXZhaWxhYmxlKToiLCB0cmVhc3VyeV9lbmQsICIlXG4iKQogIAogIGNhdCgiQ29ycG9yYXRlIGJvbmQgeWllbGQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2Nob29sIHRlcm0gKGNsb3Nlc3QgYXZhaWxhYmxlKToiLCBjb3Jwb3JhdGVfc3RhcnQsICIlXG4iKQogIGNhdCgiQ29ycG9yYXRlIGJvbmQgeWllbGQgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0gKGNsb3Nlc3QgYXZhaWxhYmxlKToiLCBjb3Jwb3JhdGVfZW5kLCAiJVxuIikKfSBlbHNlIHsKICBjYXQoIkluc3VmZmljaWVudCBkYXRhIGZvciBhbmFseXNpcy5cbiIpCn0KYGBgCgoKVHJlYXN1cnkgYm9uZCB5aWVsZHMgZXhwZXJpZW5jZWQgYSBzbGlnaHQgZGVjbGluZSwgZHJpdmVuIGJ5IHN0YWJsZSBpbmZsYXRpb24gZXhwZWN0YXRpb25zIGFuZCBpbmNyZWFzZWQgZGVtYW5kIGZvciBzYWZlLWhhdmVuIGFzc2V0cy4KQ29ycG9yYXRlIGJvbmQgeWllbGRzIGRlY2xpbmVkIG1vcmUgc2lnbmlmaWNhbnRseSwgcmVmbGVjdGluZyBpbXByb3ZlZCBlY29ub21pYyBzZW50aW1lbnQgYW5kIHJlZHVjZWQgY3JlZGl0IHJpc2suCk11bmljaXBhbCBib25kIHlpZWxkcyBsaWtlbHkgZm9sbG93ZWQgYSB0cmVuZCBjbG9zZXIgdG8gY29ycG9yYXRlIGJvbmRzIGR1ZSB0byB0aGVpciB0YXgtZXhlbXB0IHN0YXR1cyBhbmQgbG93ZXIgcGVyY2VpdmVkIGNyZWRpdCByaXNrLgoKIyMgTDcuMTcKYGBge3J9CmxpYnJhcnkocXVhbnRtb2QpCgojIERlZmluZSBzdGFydCBhbmQgZW5kIGRhdGVzCnN0YXJ0X2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNC0wMSIpCmVuZF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMTAtMzAiKQojIEZldGNoIFRyZWFzdXJ5IGJvbmQgeWllbGRzCnRyeUNhdGNoKHsKICBnZXRTeW1ib2xzKCJER1MxMCIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9ICIyMDI0LTAzLTAxIiwgdG8gPSAiMjAyNC0xMS0wMSIpCiAgdHJlYXN1cnlfeWllbGRfc3RhcnQgPC0gbGFzdChuYS5vbWl0KERHUzEwWyIyMDI0LTA0LTAxIl0pKSAvIDEwMAogIHRyZWFzdXJ5X3lpZWxkX2VuZCA8LSBsYXN0KG5hLm9taXQoREdTMTBbIjIwMjQtMTAtMzAiXSkpIC8gMTAwCiAgY2F0KCJUcmVhc3VyeSBib25kIHlpZWxkcyBmZXRjaGVkIHN1Y2Nlc3NmdWxseS5cbiIpCn0sIGVycm9yID0gZnVuY3Rpb24oZSkgewogIGNhdCgiRXJyb3IgZmV0Y2hpbmcgVHJlYXN1cnkgYm9uZCB5aWVsZHM6IiwgZSRtZXNzYWdlLCAiXG4iKQogIHRyZWFzdXJ5X3lpZWxkX3N0YXJ0IDwtIE5BCiAgdHJlYXN1cnlfeWllbGRfZW5kIDwtIE5BCn0pCgojIEZldGNoIEhpZ2gtWWllbGQgQ29ycG9yYXRlIEJvbmQgeWllbGRzCnRyeUNhdGNoKHsKICBnZXRTeW1ib2xzKCJCQU1MSDBBMEhZTTJFWSIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9ICIyMDI0LTAzLTAxIiwgdG8gPSAiMjAyNC0xMS0wMSIpCiAgaGlnaF95aWVsZF9zdGFydCA8LSBsYXN0KG5hLm9taXQoQkFNTEgwQTBIWU0yRVlbIjIwMjQtMDQtMDEiXSkpIC8gMTAwCiAgaGlnaF95aWVsZF9lbmQgPC0gbGFzdChuYS5vbWl0KEJBTUxIMEEwSFlNMkVZWyIyMDI0LTEwLTMwIl0pKSAvIDEwMAogIGNhdCgiSGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZCB5aWVsZHMgZmV0Y2hlZCBzdWNjZXNzZnVsbHkuXG4iKQp9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsKICBjYXQoIkVycm9yIGZldGNoaW5nIEhpZ2gtWWllbGQgQ29ycG9yYXRlIEJvbmQgeWllbGRzOiIsIGUkbWVzc2FnZSwgIlxuIikKICBoaWdoX3lpZWxkX3N0YXJ0IDwtIE5BCiAgaGlnaF95aWVsZF9lbmQgPC0gTkEKfSkKIyBDYWxjdWxhdGUgdGhlIHByZW1pdW0gb24gaGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZHMgcmVsYXRpdmUgdG8gVHJlYXN1cnkgYm9uZHMKaWYgKCFpcy5uYSh0cmVhc3VyeV95aWVsZF9zdGFydCkgJiYgIWlzLm5hKGhpZ2hfeWllbGRfc3RhcnQpKSB7CiAgcHJlbWl1bV9zdGFydCA8LSBoaWdoX3lpZWxkX3N0YXJ0IC0gdHJlYXN1cnlfeWllbGRfc3RhcnQKfSBlbHNlIHsKICBwcmVtaXVtX3N0YXJ0IDwtIE5BCn0KCmlmICghaXMubmEodHJlYXN1cnlfeWllbGRfZW5kKSAmJiAhaXMubmEoaGlnaF95aWVsZF9lbmQpKSB7CiAgcHJlbWl1bV9lbmQgPC0gaGlnaF95aWVsZF9lbmQgLSB0cmVhc3VyeV95aWVsZF9lbmQKfSBlbHNlIHsKICBwcmVtaXVtX2VuZCA8LSBOQQp9CgojIERpc3BsYXkgdGhlIGRhdGEKY2F0KCJUcmVhc3VyeSBib25kIHlpZWxkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNjaG9vbCB0ZXJtOiIsIHJvdW5kKHRyZWFzdXJ5X3lpZWxkX3N0YXJ0LCA0KSwgIlxuIikKY2F0KCJIaWdoLXlpZWxkIGNvcnBvcmF0ZSBib25kIHlpZWxkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHNjaG9vbCB0ZXJtOiIsIHJvdW5kKGhpZ2hfeWllbGRfc3RhcnQsIDQpLCAiXG4iKQpjYXQoIlByZW1pdW0gb24gaGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZHMgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2Nob29sIHRlcm06Iiwgcm91bmQocHJlbWl1bV9zdGFydCwgNCksICJcblxuIikKCmNhdCgiVHJlYXN1cnkgYm9uZCB5aWVsZCBhdCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybToiLCByb3VuZCh0cmVhc3VyeV95aWVsZF9lbmQsIDQpLCAiXG4iKQpjYXQoIkhpZ2gteWllbGQgY29ycG9yYXRlIGJvbmQgeWllbGQgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm06Iiwgcm91bmQoaGlnaF95aWVsZF9lbmQsIDQpLCAiXG4iKQpjYXQoIlByZW1pdW0gb24gaGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZHMgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm06Iiwgcm91bmQocHJlbWl1bV9lbmQsIDQpLCAiXG4iKQpgYGAKdGhlIGRlY3JlYXNlIGluIHRoZSBwcmVtaXVtIGhpZ2hsaWdodHMgYSBzaGlmdCBpbiBpbnZlc3RvciBzZW50aW1lbnQgYW5kIG1hcmtldCBkeW5hbWljcyBvdmVyIHRoZSBzY2hvb2wgdGVybSwgbGlrZWx5IGRyaXZlbiBieSBpbXByb3ZlZCBlY29ub21pYyBjb25kaXRpb25zIGFuZCByZWR1Y2VkIGNyZWRpdCByaXNrIHBlcmNlcHRpb24uIFRoaXMgY2hhbmdlIGVtcGhhc2l6ZXMgdGhlIGludGVyY29ubmVjdGVkbmVzcyBvZiBkaWZmZXJlbnQgc2VnbWVudHMgb2YgdGhlIGJvbmQgbWFya2V0LgoKCgoKCgoKYGBge3J9CgpgYGAKCiMjIEw4IFBvcnRmb2xpbyAtIE1hcmtvdml0egpgYGB7cn0KIyBJbnN0YWxsIGFuZCBsb2FkIG5lY2Vzc2FyeSBwYWNrYWdlcwppZiAoIXJlcXVpcmUocXVhbnRtb2QpKSBpbnN0YWxsLnBhY2thZ2VzKCJxdWFudG1vZCIpCmlmICghcmVxdWlyZShQZXJmb3JtYW5jZUFuYWx5dGljcykpIGluc3RhbGwucGFja2FnZXMoIlBlcmZvcm1hbmNlQW5hbHl0aWNzIikKaWYgKCFyZXF1aXJlKHF1YWRwcm9nKSkgaW5zdGFsbC5wYWNrYWdlcygicXVhZHByb2ciKQoKbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcykKbGlicmFyeShxdWFkcHJvZykKCiMgU3RlcCAxOiBHZXQgaGlzdG9yaWNhbCBkYXRhIGZvciBzZWxlY3RlZCBhc3NldHMKc3ltYm9scyA8LSBjKCJBQVBMIiwgIk1TRlQiLCAiR09PRyIpICAjIEV4YW1wbGUgdGlja2VycwpzdGFydF9kYXRlIDwtICIyMDIwLTAxLTAxIgplbmRfZGF0ZSA8LSAiMjAyMy0wMS0wMSIKCmdldFN5bWJvbHMoc3ltYm9scywgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpCgojIFVzZSBhZGp1c3RlZCBjbG9zaW5nIHByaWNlcwpwcmljZXMgPC0gZG8uY2FsbChjYmluZCwgbGFwcGx5KHN5bWJvbHMsIGZ1bmN0aW9uKHgpIEFkKGdldCh4KSkpKQoKIyBTdGVwIDI6IENhbGN1bGF0ZSBkYWlseSByZXR1cm5zCnJldHVybnMgPC0gbmEub21pdChST0MocHJpY2VzLCB0eXBlID0gImRpc2NyZXRlIikpCgojIFN0ZXAgMzogQ2FsY3VsYXRlIG1lYW4gcmV0dXJucyBhbmQgY292YXJpYW5jZSBtYXRyaXgKbWVhbl9yZXR1cm5zIDwtIGNvbE1lYW5zKHJldHVybnMpCmNvdl9tYXRyaXggPC0gY292KHJldHVybnMpCgojIFN0ZXAgNDogRGVmaW5lIHRoZSBvcHRpbWl6YXRpb24gcHJvYmxlbQpudW1fYXNzZXRzIDwtIG5jb2wocmV0dXJucykKCiMgQ29uc3RyYWludHM6IHdlaWdodHMgbXVzdCBzdW0gdG8gMQpBbWF0IDwtIGNiaW5kKHJlcCgxLCBudW1fYXNzZXRzKSwgZGlhZyhudW1fYXNzZXRzKSkgICMgRXF1YWxpdHkgYW5kIG5vbi1uZWdhdGl2aXR5CmJ2ZWMgPC0gYygxLCByZXAoMCwgbnVtX2Fzc2V0cykpICAgICAgICAgICAgICAgICAgICAjIFN1bSB3ZWlnaHRzIHRvIDEsIG5vIHNob3J0LXNlbGxpbmcKCiMgU2V0IHJpc2stcmV0dXJuIHRyYWRlLW9mZiAodGFyZ2V0IGV4cGVjdGVkIHJldHVybikKdGFyZ2V0X3JldHVybiA8LSBtZWFuKG1lYW5fcmV0dXJucykKCiMgTWluaW1pemUgcG9ydGZvbGlvIHZhcmlhbmNlCm9wdF9yZXN1bHQgPC0gc29sdmUuUVAoRG1hdCA9IGNvdl9tYXRyaXgsIAogICAgICAgICAgICAgICAgICAgICAgIGR2ZWMgPSByZXAoMCwgbnVtX2Fzc2V0cyksIAogICAgICAgICAgICAgICAgICAgICAgIEFtYXQgPSBBbWF0LCAKICAgICAgICAgICAgICAgICAgICAgICBidmVjID0gYnZlYywgCiAgICAgICAgICAgICAgICAgICAgICAgbWVxID0gMSkKCiMgU3RlcCA1OiBFeHRyYWN0IG9wdGltYWwgd2VpZ2h0cwpvcHRpbWFsX3dlaWdodHMgPC0gb3B0X3Jlc3VsdCRzb2x1dGlvbgoKIyBTdGVwIDY6IENhbGN1bGF0ZSBwb3J0Zm9saW8gZXhwZWN0ZWQgcmV0dXJuIGFuZCB2YXJpYW5jZQpwb3J0Zm9saW9fcmV0dXJuIDwtIHN1bShvcHRpbWFsX3dlaWdodHMgKiBtZWFuX3JldHVybnMpCnBvcnRmb2xpb192YXJpYW5jZSA8LSB0KG9wdGltYWxfd2VpZ2h0cykgJSolIGNvdl9tYXRyaXggJSolIG9wdGltYWxfd2VpZ2h0cwoKIyBTdGVwIDc6IERpc3BsYXkgcmVzdWx0cwpjYXQoIk9wdGltYWwgUG9ydGZvbGlvIFdlaWdodHM6XG4iKQpuYW1lcyhvcHRpbWFsX3dlaWdodHMpIDwtIHN5bWJvbHMKcHJpbnQob3B0aW1hbF93ZWlnaHRzKQoKY2F0KCJcblBvcnRmb2xpbyBFeHBlY3RlZCBSZXR1cm46Iiwgcm91bmQocG9ydGZvbGlvX3JldHVybiwgNCkpCmNhdCgiXG5Qb3J0Zm9saW8gVmFyaWFuY2U6Iiwgcm91bmQocG9ydGZvbGlvX3ZhcmlhbmNlLCA0KSkKY2F0KCJcblBvcnRmb2xpbyBTdGFuZGFyZCBEZXZpYXRpb246Iiwgcm91bmQoc3FydChwb3J0Zm9saW9fdmFyaWFuY2UpLCA0KSkKYGBgCgoKIyMgTDkgUG9ydGZvbGlvIC0gQ0FNUAoKYGBge3J9CiMgTG9hZCBuZWNlc3NhcnkgcGFja2FnZXMKbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcykKCiMgR2V0IGhpc3RvcmljYWwgZGF0YSBmb3IgYSBzdG9jayBhbmQgYSBtYXJrZXQgaW5kZXggKGUuZy4sIFMmUCA1MDApCmdldFN5bWJvbHMoYygiQUFQTCIsICJeR1NQQyIpLCBmcm9tID0gIjIwMTgtMDEtMDEiLCB0byA9ICIyMDIzLTEyLTMxIikKCiMgQ2FsY3VsYXRlIGRhaWx5IHJldHVybnMKc3RvY2tfcmV0dXJucyA8LSBuYS5vbWl0KFJPQyhBQVBMWywgNl0pKQptYXJrZXRfcmV0dXJucyA8LSBuYS5vbWl0KFJPQyhHU1BDWywgNl0pKQoKIyBDYWxjdWxhdGUgYmV0YSAoc3lzdGVtYXRpYyByaXNrKQpiZXRhIDwtIENBUE0uYmV0YShSYSA9IHN0b2NrX3JldHVybnMsIFJiID0gbWFya2V0X3JldHVybnMpCgojIEFzc3VtZSBhIHJpc2stZnJlZSByYXRlIChlLmcuLCAzLW1vbnRoIFRyZWFzdXJ5IGJpbGwgcmF0ZSkKcmlza19mcmVlX3JhdGUgPC0gMC4wMwoKIyBDYWxjdWxhdGUgdGhlIGV4cGVjdGVkIHJldHVybiB1c2luZyBDQVBNCmV4cGVjdGVkX3JldHVybiA8LSByaXNrX2ZyZWVfcmF0ZSArIGJldGEgKiAobWVhbihtYXJrZXRfcmV0dXJucykgLSByaXNrX2ZyZWVfcmF0ZSkKCiMgUHJpbnQgdGhlIHJlc3VsdHMKY2F0KCJCZXRhOiIsIGJldGEsICJcbiIpCmNhdCgiRXhwZWN0ZWQgUmV0dXJuOiIsIGV4cGVjdGVkX3JldHVybiAqIDEwMCwgIiUiKQpgYGAKCgoKQ0FQTSBpcyBmb2N1c2VkIG9uIHVuZGVyc3RhbmRpbmcgdGhlIGV4cGVjdGVkIHJldHVybiBvZiBhIHNpbmdsZSBhc3NldCBpbiB0aGUgY29udGV4dCBvZiB0aGUgbWFya2V0IGFuZCBpdHMgcmlzaywgaGVscGluZyB3aXRoIGFzc2V0IHZhbHVhdGlvbiBhbmQgcmlzay1hZGp1c3RlZCByZXR1cm4gYW5hbHlzaXMuCk1hcmtvd2l0eidzIE1lYW4tVmFyaWFuY2UgT3B0aW1pemF0aW9uIGlzIHVzZWQgdG8gY3JlYXRlIGFuIGludmVzdG1lbnQgcG9ydGZvbGlvIHRoYXQgYmFsYW5jZXMgcmlzayBhbmQgcmV0dXJuLCBoZWxwaW5nIGludmVzdG9ycyBkZXRlcm1pbmUgdGhlIG9wdGltYWwgY29tYmluYXRpb24gb2YgYXNzZXRzIHRvIGhvbGQuClRoZSBDQVBNIGlzIG1vcmUgYWJvdXQgZGV0ZXJtaW5pbmcgaG93IG11Y2ggcmV0dXJuIHNob3VsZCBiZSBleHBlY3RlZCBnaXZlbiB0aGUgbWFya2V0J3Mgcmlzaywgd2hpbGUgTWFya293aXR6J3MgbW9kZWwgaXMgbW9yZSBhYm91dCBjb25zdHJ1Y3RpbmcgYSBwb3J0Zm9saW8gdGhhdCBvcHRpbWl6ZXMgcmV0dXJuIGFuZCBtaW5pbWl6ZXMgcmlzayBiYXNlZCBvbiBoaXN0b3JpY2FsIGRhdGEuCkFuIGVxdWlsaWJyaXVtIG1hcmtldCBwcm92aWRlcyB0aGUgZm91bmRhdGlvbiBmb3IgdW5kZXJzdGFuZGluZyBob3cgYXNzZXRzIHNob3VsZCBiZSBwcmljZWQsIHdoaWNoIGlzIGtleSBmb3IgQ0FQTSwgTWFya293aXR6J3MgcG9ydGZvbGlvIHRoZW9yeSwgYW5kIG11bHRpLWZhY3RvciBtb2RlbHMuIEl0IHN1Z2dlc3RzIHRoYXQgaW4gYW4gZWZmaWNpZW50IGFuZCBiYWxhbmNlZCBtYXJrZXQsIGludmVzdG9ycyBjYW5ub3QgYWNoaWV2ZSBzdXBlcmlvciByZXR1cm5zIHdpdGhvdXQgYmVhcmluZyBncmVhdGVyIHJpc2ssIGFuZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcmlzayBhbmQgcmV0dXJuIHNob3VsZCBiZSBjb25zaXN0ZW50IHdpdGggdGhlc2UgbW9kZWxzLgoKCiMjIEwxMCBXQUNDCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShUVFIpCgojIEdldCBNaWNyb3NvZnQncyBzdG9jayBkYXRhCmdldFN5bWJvbHMoIk1TRlQiKQoKIyBNYXJrZXQgdmFsdWUgb2YgZXF1aXR5IChtYXJrZXQgY2FwaXRhbGl6YXRpb24pCm91c3RhbmRpbmdfc2hhcmVzIDwtIDMwMDAwMDAwICAjIFJlcGxhY2Ugd2l0aCBhY3R1YWwgdmFsdWUKbWFya2V0X2NhcCA8LSBsYXN0KE1TRlQkTVNGVC5BZGp1c3RlZCkgKiBvdXN0YW5kaW5nX3NoYXJlcwoKIyBBc3N1bXB0aW9ucwpjb3N0X29mX2RlYnQgPC0gMC4wMyAgIyAzJQp0YXhfcmF0ZSA8LSAwLjI1ICAjIDI1JSB0YXggcmF0ZQpiZXRhIDwtIDEuMSAgIyBCZXRhIG9mIE1pY3Jvc29mdCdzIHN0b2NrCnJpc2tfZnJlZV9yYXRlIDwtIDAuMDIgICMgMiUgcmlzay1mcmVlIHJhdGUKbWFya2V0X3Jpc2tfcHJlbWl1bSA8LSAwLjA2ICAjIDYlIG1hcmtldCByaXNrIHByZW1pdW0KCiMgQ2FsY3VsYXRlIGNvc3Qgb2YgZXF1aXR5IHVzaW5nIENBUE0KY29zdF9vZl9lcXVpdHkgPC0gcmlza19mcmVlX3JhdGUgKyBiZXRhICogbWFya2V0X3Jpc2tfcHJlbWl1bQoKIyBBc3N1bWVkIG1hcmtldCB2YWx1ZSBvZiBkZWJ0Cm1hcmtldF92YWx1ZV9vZl9kZWJ0IDwtIDEwMGU5ICAjICQxMDAgYmlsbGlvbgoKIyBDYWxjdWxhdGUgdG90YWwgbWFya2V0IHZhbHVlIG9mIGNhcGl0YWwKdG90YWxfbWFya2V0X3ZhbHVlIDwtIG1hcmtldF9jYXAgKyBtYXJrZXRfdmFsdWVfb2ZfZGVidAoKIyBDYWxjdWxhdGUgd2VpZ2h0cyBvZiBkZWJ0IGFuZCBlcXVpdHkKd2VpZ2h0X29mX2RlYnQgPC0gbWFya2V0X3ZhbHVlX29mX2RlYnQgLyB0b3RhbF9tYXJrZXRfdmFsdWUKd2VpZ2h0X29mX2VxdWl0eSA8LSBtYXJrZXRfY2FwIC8gdG90YWxfbWFya2V0X3ZhbHVlCgojIENhbGN1bGF0ZSBXQUNDCndhY2MgPC0gKHdlaWdodF9vZl9kZWJ0ICogY29zdF9vZl9kZWJ0ICogKDEgLSB0YXhfcmF0ZSkpICsgKHdlaWdodF9vZl9lcXVpdHkgKiBjb3N0X29mX2VxdWl0eSkKCiMgUHJpbnQgdGhlIFdBQ0MKY2F0KCJXQUNDIGZvciBNaWNyb3NvZnQ6Iiwgd2FjYyAqIDEwMCwgIiUiKQpgYGAKCiMjIEwxMSBEZXJpdmF0aXZlcwpgYGB7cn0KbGlicmFyeShxdWFudG1vZCkKCiMgR2V0IFMmUCA1MDAgZGF0YSBmb3IgdGhlIHBlcmlvZCwgYWxsb3dpbmcgZm9yIG5lYXJlc3QgYXZhaWxhYmxlIGRhdGEKZ2V0U3ltYm9scygiXkdTUEMiLCBmcm9tID0gIjIwMjQtMDQtMDEiLCB0byA9ICIyMDI0LTEwLTMwIikKCiMgRmluZCB0aGUgY2xvc2VzdCBhdmFpbGFibGUgZGF0ZXMgaWYgZXhhY3QgZGF0ZXMgYXJlIG1pc3NpbmcKc3RhcnRfZGF0ZSA8LSBpbmRleChHU1BDKVt3aGljaC5taW4oYWJzKGluZGV4KEdTUEMpIC0gYXMuRGF0ZSgiMjAyNC0wNC0wMSIpKSldCmVuZF9kYXRlIDwtIGluZGV4KEdTUEMpW3doaWNoLm1pbihhYnMoaW5kZXgoR1NQQykgLSBhcy5EYXRlKCIyMDI0LTEwLTMwIikpKV0KCiMgRXh0cmFjdCBhZGp1c3RlZCBjbG9zaW5nIHByaWNlcyBmb3IgdGhvc2UgZGF0ZXMKc3RhcnRfcHJpY2UgPC0gYXMubnVtZXJpYyhDbChHU1BDW3N0YXJ0X2RhdGVdKSkKZW5kX3ByaWNlIDwtIGFzLm51bWVyaWMoQ2woR1NQQ1tlbmRfZGF0ZV0pKQoKIyBDYWxjdWxhdGUgY29udHJhY3QgdmFsdWUgcGVyIHBvaW50OiAkMjUwCmNvbnRyYWN0X3ZhbHVlX3N0YXJ0IDwtIHN0YXJ0X3ByaWNlICogMjUwCmNvbnRyYWN0X3ZhbHVlX2VuZCA8LSBlbmRfcHJpY2UgKiAyNTAKCiMgRGlmZmVyZW5jZSBpbiBkb2xsYXIgdmFsdWUKZGlmZmVyZW5jZSA8LSBjb250cmFjdF92YWx1ZV9lbmQgLSBjb250cmFjdF92YWx1ZV9zdGFydApjYXQoIkRpZmZlcmVuY2UgaW4gZG9sbGFyIHZhbHVlOiIsIGRpZmZlcmVuY2UpCmBgYAoKIyMgTDExLjIKYGBge3J9CiMgSW5pdGlhbCBtYXJnaW4gaW52ZXN0ZWQgKDIwJSBvZiBjb250cmFjdCB2YWx1ZSkKaW5pdGlhbF9pbnZlc3RtZW50IDwtIDAuMjAgKiBjb250cmFjdF92YWx1ZV9zdGFydAoKIyBDYWxjdWxhdGUgcmV0dXJuIGFzIGEgcGVyY2VudGFnZQpyZXR1cm5fZnV0dXJlcyA8LSAoZGlmZmVyZW5jZSAvIGluaXRpYWxfaW52ZXN0bWVudCkgKiAxMDAgICMgRXhwcmVzc2VkIGFzIGEgcGVyY2VudGFnZQpjYXQoIlJldHVybiBvbiBmdXR1cmVzIHBvc2l0aW9uOiIsIHJldHVybl9mdXR1cmVzLCAiJSIpCmBgYAoKCiMjIEwxMS4zCmBgYHtyfQojIE51bWJlciBvZiBtb250aHMgaW4gdGhlIHNjaG9vbCB0ZXJtIChlLmcuLCA3IG1vbnRocyBmcm9tIEFwcmlsIDEgdG8gT2N0b2JlciAzMCkKbSA8LSA3CgojIEFubnVhbGl6ZWQgcmV0dXJuCmFubnVhbGl6ZWRfcmV0dXJuX2Z1dHVyZXMgPC0gcmV0dXJuX2Z1dHVyZXMgKiAoMTIgLyBtKQpjYXQoIkFubnVhbGl6ZWQgcmV0dXJuIG9uIGZ1dHVyZXMgcG9zaXRpb246IiwgYW5udWFsaXplZF9yZXR1cm5fZnV0dXJlcywgIiUiKQpgYGAKCgojIyBMMTEuNApgYGB7cn0KIyBFeGFtcGxlIHN0b2NrIGFuZCBvcHRpb24gZGF0YSBmb3IgdGhlIHNwZWNpZmljIGRhdGVzCmdldFN5bWJvbHMoIkFBUEwiLCBmcm9tID0gIjIwMjQtMDQtMDEiLCB0byA9ICIyMDI0LTEwLTMwIikKCiMgRmluZCB0aGUgY2xvc2VzdCBhdmFpbGFibGUgZGF0ZXMgaWYgZXhhY3QgZGF0ZXMgYXJlIG1pc3NpbmcKc3RhcnRfZGF0ZV9vcHRpb24gPC0gaW5kZXgoQUFQTClbd2hpY2gubWluKGFicyhpbmRleChBQVBMKSAtIGFzLkRhdGUoIjIwMjQtMDQtMDEiKSkpXQplbmRfZGF0ZV9vcHRpb24gPC0gaW5kZXgoQUFQTClbd2hpY2gubWluKGFicyhpbmRleChBQVBMKSAtIGFzLkRhdGUoIjIwMjQtMTAtMzAiKSkpXQoKIyBFeHRyYWN0IGFkanVzdGVkIGNsb3NpbmcgcHJpY2VzIGZvciB0aGUgb3B0aW9uIGRhdGVzCnN0b2NrX3N0YXJ0X3ByaWNlIDwtIGFzLm51bWVyaWMoQ2woQUFQTFtzdGFydF9kYXRlX29wdGlvbl0pKQpzdG9ja19lbmRfcHJpY2UgPC0gYXMubnVtZXJpYyhDbChBQVBMW2VuZF9kYXRlX29wdGlvbl0pKQoKIyBBc3N1bWUgc3RyaWtlIHByaWNlIGFuZCBwcmVtaXVtIHZhbHVlcyAodXBkYXRlIHdpdGggcmVhbCBkYXRhKQpzdHJpa2VfcHJpY2UgPC0gMTUwCnByZW1pdW1fc3RhcnQgPC0gNSAgIyBQcmVtaXVtIGF0IHRoZSBzdGFydApwcmVtaXVtX2VuZCA8LSAxMCAgICMgUHJlbWl1bSBhdCB0aGUgZW5kCgojIFJldHVybiBvbiB0aGUgb3B0aW9uIGlmIHNvbGQgYXQgdGhlIGVuZApvcHRpb25fcmV0dXJuIDwtICgocHJlbWl1bV9lbmQgLSBwcmVtaXVtX3N0YXJ0KSAvIHByZW1pdW1fc3RhcnQpICogMTAwCmNhdCgiUmV0dXJuIG9uIHRoZSBjYWxsIG9wdGlvbjoiLCBvcHRpb25fcmV0dXJuLCAiJSIpCmBgYAoKIyMgTDExLjUKYGBge3J9CiMgQW5udWFsaXplIHRoZSByZXR1cm4KYW5udWFsaXplZF9yZXR1cm5fb3B0aW9uIDwtIG9wdGlvbl9yZXR1cm4gKiAoMTIgLyBtKQpjYXQoIkFubnVhbGl6ZWQgcmV0dXJuIG9uIHRoZSBjYWxsIG9wdGlvbjoiLCBhbm51YWxpemVkX3JldHVybl9vcHRpb24sICIlIikKYGBgCiMjIEwxMS42CmBgYHtyfQojIENhbGN1bGF0ZSBzdG9jayByZXR1cm4gb3ZlciB0aGUgdGVybQpzdG9ja19yZXR1cm4gPC0gKChzdG9ja19lbmRfcHJpY2UgLSBzdG9ja19zdGFydF9wcmljZSkgLyBzdG9ja19zdGFydF9wcmljZSkgKiAxMDAKY2F0KCJSZXR1cm4gb24gdGhlIHN0b2NrOiIsIHN0b2NrX3JldHVybiwgIiUiKQpgYGAKIyMgTDExLjcKYGBge3J9CiMgRml4ZWQgcmF0ZSBhZ3JlZWQgYXQgdGhlIGJlZ2lubmluZwpmaXhlZF9yYXRlIDwtIDAuMDYKIyBGbG9hdGluZyByYXRlIGF0IHRoZSBlbmQgKGUuZy4sIFQtYmlsbCByYXRlKQpmbG9hdGluZ19yYXRlIDwtIDAuMDUgICMgRXhhbXBsZSB2YWx1ZQoKIyBOb3Rpb25hbCBhbW91bnQKbm90aW9uYWxfYW1vdW50IDwtIDEwZTYgICMgJDEwIG1pbGxpb24KCiMgQW1vdW50IG93ZWQgYW5kIGFtb3VudCByZWNlaXZlZAphbW91bnRfb3dlZCA8LSBmaXhlZF9yYXRlICogbm90aW9uYWxfYW1vdW50CmFtb3VudF9yZWNlaXZlZCA8LSBmbG9hdGluZ19yYXRlICogbm90aW9uYWxfYW1vdW50CgojIE5ldCByZXN1bHQKbmV0X3Jlc3VsdCA8LSBhbW91bnRfcmVjZWl2ZWQgLSBhbW91bnRfb3dlZApjYXQoIk5ldCByZXN1bHQgZnJvbSBzd2FwOiIsIG5ldF9yZXN1bHQpCmBgYAoKCiMjIEwgMTEuOC0gMTEuMTIgTWVhc3VyaW5nIGFuZCBleHBsYWluaW5nIGV4Y2hhbmdlIHJhdGUgbW92ZW1lbnRzCmBgYHtyfQpsaWJyYXJ5KHF1YW50bW9kKQpsaWJyYXJ5KGtuaXRyKQoKIyBEZWZpbmUgdGhlIGN1cnJlbmN5IHBhaXJzCmN1cnJlbmNpZXMgPC0gYygiR0JQL1VTRCIsICJKUFkvVVNEIiwgIk1YTi9VU0QiKQoKIyBJbml0aWFsaXplIGEgZGF0YWZyYW1lIHRvIHN0b3JlIHJlc3VsdHMKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIERlc2NyaXB0aW9uID0gYygKICAgICJFeGNoYW5nZSByYXRlIG9mIHRoZSBCcml0aXNoIHBvdW5kIChpbiAkKToiLAogICAgIkV4Y2hhbmdlIHJhdGUgb2YgdGhlIEphcGFuZXNlIHllbiAoaW4gJCk6IiwKICAgICJFeGNoYW5nZSByYXRlIG9mIHRoZSBNZXhpY2FuIHBlc28gKGluICQpOiIKICApLAogIEJvVCA9IE5BLAogIEVvVCA9IE5BLAogIENoYW5nZSA9IE5BLAogIERpcmVjdGlvbiA9IE5BCikKCiMgRGVmaW5lIHRoZSBzcGVjaWZpYyBkYXRlcyBmb3IgdGhlIHNjaG9vbCB0ZXJtCnN0YXJ0X2RhdGUgPC0gIjIwMjQtMDQtMDEiCmVuZF9kYXRlIDwtICIyMDI0LTEwLTMwIgoKIyBGZXRjaCBleGNoYW5nZSByYXRlIGRhdGEKZm9yIChpIGluIDE6bGVuZ3RoKGN1cnJlbmNpZXMpKSB7CiAgY3VycmVuY3kgPC0gY3VycmVuY2llc1tpXQogIAogICMgQ29udmVydCBmb3JtYXQgZm9yIFlhaG9vIEZpbmFuY2UgKGUuZy4sIEdCUC9VU0QgLT4gR0JQVVNEPVgpCiAgeWFob29fc3ltYm9sIDwtIGdzdWIoIi8iLCAiIiwgY3VycmVuY3kpICU+JSBwYXN0ZTAoIj1YIikKICAKICAjIEZldGNoIGRhdGEgZnJvbSBZYWhvbyBGaW5hbmNlCiAgY3VycmVuY3lfZGF0YSA8LSBnZXRTeW1ib2xzKHlhaG9vX3N5bWJvbCwgc3JjID0gInlhaG9vIiwgZnJvbSA9ICIyMDI0LTAxLTAxIiwgdG8gPSBTeXMuRGF0ZSgpLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQogIAogICMgR2V0IHRoZSByYXRlIGNsb3Nlc3QgdG8gdGhlIHN0YXJ0IGRhdGUKICBzdGFydF9wcmljZSA8LSBDbChjdXJyZW5jeV9kYXRhKVt3aGljaC5taW4oYWJzKGluZGV4KGN1cnJlbmN5X2RhdGEpIC0gYXMuRGF0ZShzdGFydF9kYXRlKSkpXQogIHJlc3VsdHMkQm9UW2ldIDwtIGFzLm51bWVyaWMoc3RhcnRfcHJpY2UpCiAgCiAgIyBHZXQgdGhlIHJhdGUgY2xvc2VzdCB0byB0aGUgZW5kIGRhdGUKICBlbmRfcHJpY2UgPC0gQ2woY3VycmVuY3lfZGF0YSlbd2hpY2gubWluKGFicyhpbmRleChjdXJyZW5jeV9kYXRhKSAtIGFzLkRhdGUoZW5kX2RhdGUpKSldCiAgcmVzdWx0cyRFb1RbaV0gPC0gYXMubnVtZXJpYyhlbmRfcHJpY2UpCiAgCiAgIyBDYWxjdWxhdGUgcGVyY2VudGFnZSBjaGFuZ2UKICByZXN1bHRzJENoYW5nZVtpXSA8LSAoKHJlc3VsdHMkRW9UW2ldIC0gcmVzdWx0cyRCb1RbaV0pIC8gcmVzdWx0cyRCb1RbaV0pICogMTAwCiAgCiAgIyBEZXRlcm1pbmUgZGlyZWN0aW9uCiAgcmVzdWx0cyREaXJlY3Rpb25baV0gPC0gaWZlbHNlKHJlc3VsdHMkQ2hhbmdlW2ldID4gMCwgIkFwcHJlY2lhdGVkIiwgIkRlcHJlY2lhdGVkIikKfQoKIyBDYWxjdWxhdGUgcGVyIHVuaXQgZ2Fpbi9sb3NzIGZvciBCcml0aXNoIFBvdW5kIGZ1dHVyZXMKZ2JwX2Z1dHVyZXNfZ2Fpbl9wZXJfdW5pdCA8LSByZXN1bHRzJEVvVFsxXSAtIHJlc3VsdHMkQm9UWzFdCgojIEdpdmVuIGEgc2luZ2xlIGZ1dHVyZXMgY29udHJhY3QgcmVwcmVzZW50cyA2Miw1MDAgcG91bmRzCmdicF9mdXR1cmVzX3RvdGFsX2dhaW4gPC0gZ2JwX2Z1dHVyZXNfZ2Fpbl9wZXJfdW5pdCAqIDYyNTAwCgojIEFkZCBmdXR1cmVzIHJlc3VsdHMgdG8gdGhlIHRhYmxlCmZ1dHVyZXNfcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIERlc2NyaXB0aW9uID0gYygiUGVyIFVuaXQgR2Fpbi9Mb3NzIGZvciBHQlAgRnV0dXJlczoiLCAiVG90YWwgRG9sbGFyIEdhaW4vTG9zcyBmb3IgR0JQIEZ1dHVyZXM6IiksCiAgQm9UID0gYyhnYnBfZnV0dXJlc19nYWluX3Blcl91bml0LCBnYnBfZnV0dXJlc190b3RhbF9nYWluKSwKICBFb1QgPSBjKE5BLCBOQSksCiAgQ2hhbmdlID0gYyhOQSwgTkEpLAogIERpcmVjdGlvbiA9IGMoTkEsIE5BKQopCgojIENvbWJpbmUgcmVzdWx0cyBmb3IgZGlzcGxheQpmaW5hbF9yZXN1bHRzIDwtIHJiaW5kKHJlc3VsdHMsIGZ1dHVyZXNfcmVzdWx0cykKCiMgRGlzcGxheSB0aGUgdGFibGUKa2FibGUoCiAgZmluYWxfcmVzdWx0cywKICBjb2wubmFtZXMgPSBjKCJEZXNjcmlwdGlvbiIsICJCb1QgKDA0LzAxLzIwMjQpIiwgIkVvVCAoMTAvMzAvMjAyNCkiLCAiQ2hhbmdlICglKSIsICJEaXJlY3Rpb24iKSwKICBjYXB0aW9uID0gIkN1cnJlbmN5IEV4Y2hhbmdlIFJhdGVzIGFuZCBHQlAgRnV0dXJlcyIKKQpgYGAKCgoKIyMgTDEyIENhcGl0YWwgcmVxdWlyZW1lbnRzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoa25pdHIpICAjIEZvciBjcmVhdGluZyB0YWJsZXMKIyBJbnB1dCBkYXRhOiBSV0FzIChpbiBiaWxsaW9ucykKcndhX2JvYSA8LSBkYXRhLmZyYW1lKAogICAgUmlzayA9IGMoIkNyZWRpdCIsICJNYXJrZXQiLCAiT3BlcmF0aW9uYWwiKSwKICAgIFJXQSA9IGMoMTU4MCwgNzEsIDM2MSkKKQoKcndhX2RiIDwtIGRhdGEuZnJhbWUoCiAgICBSaXNrID0gYygiQ3JlZGl0IiwgIk1hcmtldCIsICJPcGVyYXRpb25hbCIpLAogICAgUldBID0gYygyNjUuOCwgMjEuNSwgNTcuMikKKQoKIyBEZWZpbmUgQ0VUMSByYXRpb3MKY2V0MV9yYXRpb19ib2EgPC0gMC4xMzUgICMgQmFuayBvZiBBbWVyaWNhCmNldDFfcmF0aW9fZGIgPC0gMC4xMzcgICAjIERldXRzY2hlIEJhbmsKCiMgQ2FsY3VsYXRlIENFVDEgY2FwaXRhbCByZXF1aXJlbWVudHMKcndhX2JvYSA8LSByd2FfYm9hICU+JQogICAgbXV0YXRlKENFVDFfUmF0aW8gPSBjZXQxX3JhdGlvX2JvYSwgCiAgICAgICAgICAgQ0VUMV9SZXF1aXJlbWVudCA9IFJXQSAqIGNldDFfcmF0aW9fYm9hKQoKcndhX2RiIDwtIHJ3YV9kYiAlPiUKICAgIG11dGF0ZShDRVQxX1JhdGlvID0gY2V0MV9yYXRpb19kYiwgCiAgICAgICAgICAgQ0VUMV9SZXF1aXJlbWVudCA9IFJXQSAqIGNldDFfcmF0aW9fZGIpCgojIENvbWJpbmUgcmVzdWx0cwpjb21iaW5lZF9yZXN1bHRzIDwtIGJpbmRfcm93cygKICAgIHJ3YV9ib2EgJT4lIG11dGF0ZShCYW5rID0gIkJhbmsgb2YgQW1lcmljYSIpLAogICAgcndhX2RiICU+JSBtdXRhdGUoQmFuayA9ICJEZXV0c2NoZSBCYW5rIikKKQoKIyBGb3JtYXQgdGFibGUKa2FibGUoCiAgICBjb21iaW5lZF9yZXN1bHRzLAogICAgY29sLm5hbWVzID0gYygiUmlzayBUeXBlIiwgIlJXQSAoQmlsbGlvbikiLCAiQ0VUMSBSYXRpbyIsICJDRVQxIFJlcXVpcmVtZW50IChCaWxsaW9uKSIsICJCYW5rIiksCiAgICBjYXB0aW9uID0gIkNFVDEgQ2FwaXRhbCBSZXF1aXJlbWVudHMgYW5kIFJhdGlvcyBmb3IgQmFuayBvZiBBbWVyaWNhIGFuZCBEZXV0c2NoZSBCYW5rIgopCmBgYAoKCkJhbmsgb2YgQW1lcmljYSBoYXMgc2lnbmlmaWNhbnRseSBsYXJnZXIgUldBcyBmb3IgY3JlZGl0IGFuZCBvcGVyYXRpb25hbCByaXNrcyBjb21wYXJlZCB0byBEZXV0c2NoZSBCYW5rLCByZWZsZWN0aW5nIGl0cyBsYXJnZXIgZ2xvYmFsIGZvb3RwcmludC4KQm9BJ3MgQ0VUMSByYXRpbyAoMTMuNSUpIGlzIGNvbXBhcmFibGUgdG8gRGV1dHNjaGUgQmFuaydzICgxMy43JSksIGJ1dCB0aGUgYWJzb2x1dGUgYW1vdW50IG9mIHJlcXVpcmVkIGNhcGl0YWwgaXMgaGlnaGVyIGZvciBCb0EgZHVlIHRvIGl0cyBsYXJnZXIgc2NhbGUuCkRldXRzY2hlIEJhbmsgaGFzIGEgbW9yZSBlZmZpY2llbnQgdXNlIG9mIGl0cyBjYXBpdGFsIHJlbGF0aXZlIHRvIHJpc2sgZXhwb3N1cmUsIHdpdGggYSByb2J1c3QgQ0VUMSByYXRpbyBleGNlZWRpbmcgcmVndWxhdG9yeSByZXF1aXJlbWVudHMu