Justus Krupp, Germany

Author’s Statement on the Use of AI Tools and Platforms During the Assignment

To complete this assignment, I used a variety of tools and platforms to collect data, analyze it, and present my findings. Here’s a summary of what I used and how:

Tools and Platforms Used

ChatGPT (OpenAI): Assisted with drafting answers, explaining concepts, and creating code for analysis. Website: https://chat.openai.com

Gemini: Helped find solutions when I faced data issues or errors in my code. Website: https://gemini.google.com/app

Quantmod and FREDR: Provided financial data, such as stock market prices and interest rates. https://www.quantmod.com/ https://fred.stlouisfed.org/

Quandl: Used for additional economic and financial data. https://data.nasdaq.com/publishers/QDL

Posit Cloud (formerly RStudio Cloud): Used to write and run my R code online. Website: https://posit.cloud

RPubs: Used to share the report in a simple, easy-to-view format. Website: https://rpubs.com

How I Used These Tools:

Data Collection: I gathered data using Quantmod, FREDR, and Quandl.

Coding and Analysis: I wrote and tested R code in Posit Cloud to process and analyze the data.

Sharing: I used RPubs to share my report.

Challenges and Solutions: I faced some challenges like data being unavailable or API errors. For these, I used ChatGPT and Gemini to find solutions or alternative data sources. Posit Cloud made it easier to test and run my code, and RPubs allowed me to share my findings.

Ensuring Quality: I double-checked my data sources, reviewed my code and results to avoid mistakes, and made sure the report on RPubs was straightforward and easy to read.

Responsibility Statement: I take full responsibility for the accuracy of my work. While AI tools and platforms were helpful for data collection and analysis, all ideas, explanations, and the final report were created by me.

Public Access License Statement: This assignment has been shared under a public access license to ensure that others can view, use, and learn from the work

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)"))
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 (%)"))
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)
Stock Exchange Stock Ticker Latest Price Annualized Dividend
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)
Description Latest Price Sept 5, 2024 Price
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)
Description BoT (Beginning of Term) EoT (End of Term)
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)
Description BoT (September 5, 2024) EoT (Latest)
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)
Description BoT (Beginning of Term) EoT (End of Term)
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)
Description BoT (Beginning of Term) EoT (End of Term)
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

L2 Financial markets microstructure

# Load libraries
library(quantmod)
library(zoo)
library(knitr)

# Suppress warnings for missing values in FTSE
options(warn = -1)

# Download data for NASDAQ and FTSE 100
getSymbols("NDAQ", src = "yahoo", auto.assign = FALSE) -> NDAQ
getSymbols("^FTSE", src = "yahoo", auto.assign = FALSE) -> FTSE

# Restore warnings
options(warn = 0)

# Fill missing values for FTSE
FTSE <- na.approx(FTSE)

# Trim data to the comparison period
NDAQ <- subset(NDAQ, index(NDAQ) >= "2008-01-03" & index(NDAQ) <= "2023-01-05")
FTSE <- subset(FTSE, index(FTSE) >= "2008-01-03" & index(FTSE) <= "2023-01-05")

# Calculate basic statistics for NASDAQ
nasdaq_stats <- c(
  Mean = mean(NDAQ$NDAQ.Close, na.rm = TRUE),
  Median = median(NDAQ$NDAQ.Close, na.rm = TRUE),
  StDev = sd(NDAQ$NDAQ.Close, na.rm = TRUE)
)

# Calculate basic statistics for FTSE
lond_stats <- c(
  Mean = mean(FTSE$FTSE.Close, na.rm = TRUE),
  Median = median(FTSE$FTSE.Close, na.rm = TRUE),
  StDev = sd(FTSE$FTSE.Close, na.rm = TRUE)
)

# Calculate Coefficient of Variation (CV) for NASDAQ and FTSE
nasdaq_cv <- (nasdaq_stats["StDev"] / nasdaq_stats["Mean"]) * 100
ftse_cv <- (lond_stats["StDev"] / lond_stats["Mean"]) * 100

# Combine statistics into a table without market capitalization
stats_comparison <- rbind(
  NASDAQ = round(c(nasdaq_stats, CV = nasdaq_cv), 2),
  FTSE = round(c(lond_stats, CV = ftse_cv), 2)
)

# Display statistics using kable
kable(stats_comparison, 
      caption = "Comparison of NASDAQ and FTSE Statistics (Including Coefficient of Variation)")
Comparison of NASDAQ and FTSE Statistics (Including Coefficient of Variation)
Mean Median StDev CV.StDev
NASDAQ 23.06 17.01 17.16 74.41
FTSE 6380.16 6537.10 902.89 14.15

Index Calculation Process:

Company Selection: Index providers choose companies based on factors like market value, industry, and trading volume. Weight Assignment: Companies are assigned weights based on their market capitalization, with larger companies having more influence. Index Value Calculation: A formula is used to calculate the index value, considering price changes of each company and their weights. The value is updated continuously throughout the trading day. Mean and Median: The FTSE has higher average and median values compared to NASDAQ, indicating a higher typical index level. Standard Deviation (StDev):StDev may not be an ideal metric for comparing indices with different mean levels, as it does not account for the scale of these indices Coefficient of Variation (CV): NASDAQ’s high CV (74.41%) shows greater relative volatility, while FTSE’s lower CV (14.15%) implies more stability relative to its average.

L3 Instrument’s overview and valuation

library(quantmod)
library(knitr)

# Download the 3-Month Treasury Bill Rate (TB3MS) data from FRED
getSymbols("TB3MS", src = "FRED")
[1] "TB3MS"
# Define the start and end dates
start_date <- "2024-05-01"  # Start of term (set to May 2024)
end_date <- Sys.Date()      # Latest available date (dynamic)

# Subset the data to the period between start and latest data
tb_data <- window(TB3MS, start = start_date, end = end_date)

# Extract the start rate (the first available value for May 2024)
start_rate <- as.numeric(first(tb_data))  # Ensure it returns just one number

# Extract the end rate (the latest available value)
end_rate <- as.numeric(last(tb_data))    # Ensure it returns just one number

# Create a data frame for displaying the rates in a table
rate_data <- data.frame(
  "Period" = c("Start of Term (May 2024)", "End of Term (Latest Available)"),
  "Rate (%)" = c(round(start_rate, 2), round(end_rate, 2))
)

# Display the table using kable
kable(rate_data, caption = "Comparison of 3-Month Treasury Bill Rate (TB3MS)", col.names = c("Period", "Rate (%)"))
Comparison of 3-Month Treasury Bill Rate (TB3MS)
Period Rate (%)
Start of Term (May 2024) 5.25
End of Term (Latest Available) 4.51

Why Interest Rates Change Over Time

  1. Inflation Expectations:
    If inflation is expected to rise, interest rates usually increase to compensate for reduced purchasing power. In reverse, lower inflation can lead to lower rates.

  2. Central Bank Policies:
    Central banks adjust interest rates to control economic growth and inflation. Raising rates slows down borrowing, while lowering them stimulates spending and investment.

  3. Credit Supply and Demand:
    The balance of supply and demand for loans affects interest rates. Higher demand for loans tends to push rates up, while lower demand can reduce rates.

L4 Efficiency of market and information

# Load necessary library
library(quantmod)

# Download Coca-Cola stock data from Yahoo Finance
getSymbols("KO", src = "yahoo", from = "2017-10-20", to = "2017-10-31")
[1] "KO"
# Plotting Coca-Cola stock prices
chartSeries(KO, name = "Coca-Cola Stock Prices (October 20–31, 2017)", 
            theme = chartTheme("white"),
            type = "line")

Based on the graph, Coca-Cola’s share price does not show significant volatility or a sharp drop on October 26, 2017, which would be indicative of adverse market reactions to information release. Instead, the price appears relatively stable, with a small decline that is in line with normal fluctuations over the observed period. This suggests that either: The information released was anticipated or already priced in by the market. The market viewed the information as less impactful on Coca-Cola’s long-term fundamentals.

L5 Financial statements and fundamental analysis

library(quantmod)  # for basic financial data, stock quotes
library(finreportr) # for financial reports
library(edgar)  # for retrieving full text filings from EDGAR
library(XBRL)  # for handling XBRL data (financial reports)
library(dplyr)  # for data manipulation
library(tidyr)  # for data cleaning

# Set up the authority for Edgar (EDGAR requires your email)
options(HTTPUserAgent = "miky@xx.com")

# Retrieve annual reports for Microsoft (CIK: 0000789019)
AnnualReports(0000789019, foreign = FALSE)

# Example: Get the balance sheet for Microsoft (MSFT ticker, for the year 2017)
Msft_2017 <- GetBalanceSheet('MSFT', 2017)

# View the balance sheet
View(Msft_2017)

2018 doesnt work The URL results in a 404 Not Found error, meaning that the file or resource is either unavailable, moved, or doesn’t exist at the given URL.

L5.1 Types of Deposits Used to Obtain Most of the Bank’s Funds (ING)

Customer Deposits

  • Savings accounts, current accounts, time deposits, and demand deposits.
  • Total deposits amounted to €650 billion in 2023.

Wholesale Funding

  • Includes borrowing via repurchase agreements, issuing bonds, and commercial papers.

L5.2 Main Uses of Funds

Primary Uses

  1. Lending: Loans to individuals and businesses, including mortgages, business loans, and consumer credit.
  2. Investments: Capital is invested in securities and financial instruments to earn returns and manage risks.
  3. Liquidity Management: Reserves maintained for regulatory and operational needs.

Regulatory Impacts

  • ING faces regulatory challenges like:
    • Compliance with sustainability standards (EU taxonomy, ESG disclosures).
    • Increased costs due to directives like the Corporate Sustainability Reporting Directive (CSRD).

L5.3 Entry into the Securities Industry

Yes, ING is expanding into securities services by: 1. Offering equity and debt issuance services to institutional clients. 2. Providing derivatives for hedging. 3. Engaging in securities underwriting via its Wholesale Banking division.


L5.4 Entry into the Insurance Industry

Yes, ING collaborates with insurance partners to offer: 1. Life and Non-Life Insurance Products: Includes health, car, travel, and home insurance. 2. In 2023, ING launched: - Pet insurance in Türkiye. - Car insurance in Spain.


L5.5 Gap Between Rate-Sensitive Assets and Liabilities

Balance Sheet Management

  • Interest rate risks are actively managed using hedging strategies (e.g., cap/floor contracts).
  • The report does not specify whether the gap is positive or negative but indicates strong management to minimize mismatches.

L5.6 Interest Income as a Percentage of Total Assets

\[ \text{Interest Income Percentage} = \frac{\text{Interest Income}}{\text{Total Assets}} \times 100 \]

\[ \text{Interest Income Percentage} = \frac{52,227}{975,583} \times 100 = 5.35\% \]


L5.7 Interest Expenses as a Percentage of Total Assets

\[ \text{Interest Expense Percentage} = \frac{\text{Interest Expenses}}{\text{Total Assets}} \times 100 \]

\[ \text{Interest Expense Percentage} = \frac{36,252}{975,583} \times 100 = 3.72\% \]


L5.8 Net Interest Margin

\[ \text{Net Interest Margin} = \frac{\text{Net Interest Income}}{\text{Total Assets}} \times 100 \]

\[ \text{Net Interest Margin} = \frac{15,976}{975,583} \times 100 = 1.64\% \]


L5.9 Noninterest Income and Expenses as a Percentage of Total Assets

Noninterest Income:

\[ \text{Noninterest Income Percentage} = \frac{\text{Noninterest Income}}{\text{Total Assets}} \times 100 \]

\[ \text{Noninterest Income Percentage} = \frac{5,109}{975,583} \times 100 = 0.52\% \]

Noninterest Expenses:

\[ \text{Noninterest Expense Percentage} = \frac{\text{Noninterest Expenses}}{\text{Total Assets}} \times 100 \]

\[ \text{Noninterest Expense Percentage} = \frac{1,514}{975,583} \times 100 = 0.16\% \]


L5.10 Addition to Loan Loss Reserves as a Percentage of Total Assets

\[ \text{Loan Loss Reserve Percentage} = \frac{\text{Loan Loss Reserves}}{\text{Total Assets}} \times 100 \]

\[ \text{Loan Loss Reserve Percentage} = \frac{520}{975,583} \times 100 = 0.05\% \]


L5.11 Return on Assets (ROA)

\[ \text{ROA} = \frac{\text{Net Income}}{\text{Total Assets}} \times 100 \]

\[ \text{ROA} = \frac{7,521}{975,583} \times 100 = 0.77\% \]


L5.12 Return on Equity (ROE)

\[ \text{ROE} = \frac{\text{Net Income}}{\text{Total Equity}} \times 100 \]

\[ \text{ROE} = \frac{7,521}{52,184} \times 100 = 14.42\% \]


L5.13 Items Affected by Rising Interest Rates

Affected Items

  1. Interest Income: Likely to increase as loan yields rise.
  2. Interest Expenses: Likely to rise significantly if deposit rates or funding costs increase.

L5.14 Items Affected by Economic Deterioration

Affected Items

  1. Loan Loss Reserves: Likely to increase due to higher default rates.
  2. Noninterest Income: May decline as demand for investment and financial services decreases.
  3. Net Income: Overall reduction due to lower lending and fee-based activity.

L5.15 Investment Objective and Risk Level

Investment Objective

The Vanguard 500 Index Fund seeks to track the performance of the Standard & Poor’s 500 Index, which measures the investment return of large-capitalization U.S. stocks.

Risk Level

  • Moderate Risk:
    • The fund is exposed to market risks due to its focus on equities and the S&P 500.
    • It has sector risks, particularly in the information technology sector, which constitutes a significant portion of its portfolio.

L5.16 Fund Performance

Return Last Year

\[ \text{Return Last Year} = 26.24\% \]

Average Annual Return Over the Last Three Years

\[ \text{Average Annual Return (3 Years)} = 15.65\% \]


L5.17 Key Economic Factor Influencing Returns

Key Economic Factor

  • The return of the fund is primarily influenced by:
    • U.S. Stock Market Conditions: As the fund tracks the S&P 500, its performance closely mirrors the overall U.S. stock market trends.
    • Additional influences include U.S. interest rates and sector-specific trends, especially in the information technology sector.

L5.18 Fees for Buying or Selling the Mutual Fund

Fees

  • No Sales Charges:
    • No fees are imposed for purchases, reinvested dividends, or redemptions.

L5.19 Expense Ratio

Expense Ratio

\[ \text{Expense Ratio (Last Year)} = 0.04\% \]

Assessment

  • The expense ratio is extremely low compared to industry averages, making the fund highly cost-efficient for investors.

L5.20 Main Types of Business Conducted

Charles Schwab’s Business Operations

  1. Brokerage Services:
    • Trade execution and clearing for equities, ETFs, options, fixed income, and other securities.
  2. Wealth Management:
    • Personalized financial planning, portfolio management, and advisory services.
  3. Banking Services:
    • FDIC-insured deposit accounts and lending services.
  4. Mutual Fund and ETF Management:
    • Management of proprietary Schwab Funds and ETFs, along with third-party fund investments.
  5. Technology Solutions for Advisors:
    • Digital platforms designed for Registered Investment Advisors (RIAs).

L5.21 Regulatory Impacts

Existing and Potential Regulatory Challenges

  1. Capital Requirements:
    • Schwab may face stricter leverage ratios due to the integration of accumulated other comprehensive income (AOCI) into regulatory capital calculations.
  2. Regulatory Compliance:
    • Schwab places a strong emphasis on compliance and safeguarding client trust, highlighting the role of integrity in its operations.

L5.22 Recent Performance

Performance Summary

  1. Net Revenues: Declined by 9% in 2023 to $18.8 billion.
  2. Net Income: Dropped by 30% to $4.65 billion.
  3. Earnings Per Share: Fell by 27% to $2.54.

Reasons for Unfavorable Performance

  1. Interest Rate Increases:
    • Rapid rate hikes reduced client cash balances held by Schwab, impacting the net interest margin.
  2. Client Behavior:
    • Many clients moved their funds to higher-yielding alternatives, a trend Schwab supported to maintain long-term trust despite short-term revenue impacts.
  3. Market Volatility:
    • Geopolitical and economic uncertainty contributed to reduced trading activity and diminished investor sentiment.

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
Metric Value
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
Metric Value
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
Date DGS30 DTB3 DGS30.1
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
Date DCPF3M DTB3 DCPF3M.1
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
Description BoT (04/01/2024) EoT (10/30/2024) Change (%) Direction
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
Risk Type RWA (Billion) CET1 Ratio CET1 Requirement (Billion) 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