Authors: “José Luis Suárez González (137576) and Jake Oliver Goddard (137633)”

Date: “02-12-2024”

Team participations:

José Luis Suárez: Code writing and analysis of results Jake Oliver Goddard: project structuring, revising and correcting mistakes of the outcome.

Authors’ statement of non-infrigement of others’ copyrights

We hereby declare that the work submitted is original and has been created solely by us. We confirm that we have not used or incorporated any material that infringes upon the copyrights of others. All sources and references used in the creation of this work have been properly acknowledged and cited in accordance with applicable guidelines.

Authors’ statement as to how the AI tool was used during the assignment.

Scope of Application:

The AI tool was utilized to generate structured explanations, analyze data trends, and refine language for clarity and coherence. It has also been utilized as tool for optimization and error-solving of the produced codes.

Quality Control Procedures:

Generated outputs were rigorously reviewed by the authors to ensure accuracy, relevance, and alignment with the assignment’s requirements. All final content underwent manual verification and edits.

Responsibility Statement:

We assume full responsibility for the content of this work, including accuracy, integrity, and originality.

L1 Intro

L1.1 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.

Starting quantmod

library(quantmod)

Function to get the symbols on the time period required

get_stock_info_by_date <- function(symbol, BoT_date, EoT_date){
     stock_data <- getSymbols(symbol, from = BoT_date, to = EoT_date, auto.assign = FALSE)
     start_price <- as.numeric(Cl(stock_data[BoT_date]))
     end_price <- as.numeric(Cl(stock_data[EoT_date]))
     if (is.null(end_price) || length(end_price) == 0 || is.na(as.numeric(end_price))) {
         end_price <- as.numeric(Cl(last(stock_data[paste0("/", EoT_date)])))} else {
  end_price <- as.numeric(end_price)}
     dividends <- getDividends(symbol, from = BoT_date, to = EoT_date, auto.assign = FALSE)
     start_dividend <- if (BoT_date %in% index(dividends)) {as.numeric(dividends[BoT_date])} else NA
     if (is.null(start_dividend) || length(start_dividend) == 0 || is.na(as.numeric(start_dividend))) {
         start_dividend <- as.numeric(last(dividends[paste0("/", EoT_date)]))} else {
         start_dividend <- as.numeric(start_dividend)}
     end_dividend <- if(EoT_date %in% index(dividends)) as.numeric(dividends[EoT_date])
     if (is.null(end_dividend) || length(end_dividend) == 0 || is.na(as.numeric(end_dividend))) {
         end_dividend <- as.numeric(last(dividends[paste0("/", EoT_date)]))} else {
         end_dividend <- as.numeric(end_dividend)}
     list(
         Start_Price= start_price,
         End_Price= end_price,
         Start_Dividend= start_dividend,
         End_Dividend= end_dividend
     )
 }

Determining the dates of beginning and end

BoT_date <- "2024-05-01"
EoT_date <- "2024-09-30"

Determining the stock symbols

nyse_stock <- "IBM"
nasdaq_stock <- "SBUX"

Retrieve information from each stock

nyse_info <- get_stock_info_by_date(nyse_stock, BoT_date, EoT_date)
nasdaq_info <- get_stock_info_by_date(nasdaq_stock, BoT_date, EoT_date)

Create a data frame to display the results

stock_data <- data.frame(
  Exchange = c("New York Stock Exchange", "Nasdaq Market"),
  Firm = c(nyse_stock, nasdaq_stock),
  BoT_Price = c(nyse_info$Start_Price, nasdaq_info$Start_Price),
  EoT_Price = c(nyse_info$End_Price, nasdaq_info$End_Price),
  BoT_Dividend = c(nyse_info$Start_Dividend, nasdaq_info$Start_Dividend),
  EoT_Dividend = c(nyse_info$End_Dividend, nasdaq_info$End_Dividend))
print(stock_data)

Analysis of results.

In this exercise we have obtained the stock prices and dividend of an stock from the New York Stock Exchange and another from the Nasdaq Market, both at the beginning of the school term date (BoT date) and the end of the school term date (EoT date) For the development of this exercise, we have designed a function which allows us to extract the stock price as well as the dividend, giving a solution to manage the lack of data at the EoT date, which is a non-trading day. In this solution, which we will have to further implement in the rest of exercises that involve obtaining data at EoT date, we have given an order to use the last available data when the date selected has no available data. Additionally, although it will probably not be needed, we have implemented an equivalent system for obtaining the data on BoT date, so that if we encounter a missing value, we will use the next available data. Regarding the results of the exercise, we can observe an increase in the price of the of both stocks during the school term. The increasing prices usually revolve around positive future expectancy of the companies as well as a favorable presentation of results at the end of each quarter. The dividends have not seen neither an increase nor a decrease, which indicates stability in their internal financial organization and gives a further sense of safeness to their stockholders.

L1.2 Use futures prices quotations to record the recent (“settle”) price of the following futures (select futures with first settlement date beyond the end of the school term)

Creating function to extract the values

get__futures_data_by_date <- function(symbol, from = BoT_date, to = EoT_date) {
     futures_data <- getSymbols(symbol, from = BoT_date, to = EoT_date, auto.assign = FALSE)
     if (is.null(futures_data) || nrow(futures_data) == 0) {
         warning(paste("No data found for symbol:", symbol))
         return(NA)
     }
    BoT_price <- as.numeric(Cl(futures_data[BoT_date]))
 EoT_data <- futures_data[paste0("/", EoT_date)]
 if(nrow(EoT_data) == 0) {
     warning(paste("No data available on or before EoT_date for symbol:", symbol))
     EoT_price <- NA
 } else {
     EoT_price <- as.numeric(last(Cl(EoT_data)))
 }
 return(list(
     Symbol = symbol,
     BoT_Price = BoT_price,
     EoT_Price = EoT_price
 ))
 }

use the function for each futures contract

treasury_bond <- get__futures_data_by_date("ZB=F", BoT_date, EoT_date)
  sp500_futures <- get__futures_data_by_date("ES=F", BoT_date, EoT_date)
  nasdaq <- get__futures_data_by_date("^IXIC", BoT_date, EoT_date)
 british_pound <- get__futures_data_by_date("6B=F", BoT_date, EoT_date)

build the data frame

future_prices <- data.frame(
  Asset = c(
    "Treasury Bond Futures Dec 2024",
    "S&P 500 Futures Dec 2024",
    "Nasdaq Composite Index",
    "British Pound Futures Dec 2024"
  ),
  Symbol = c(
    treasury_bond$Symbol,
    sp500_futures$Symbol,
    nasdaq$Symbol,
    british_pound$Symbol
  ),
  BoT_Price = c(
    treasury_bond$BoT_Price,
    sp500_futures$BoT_Price,
    nasdaq$BoT_Price,
    british_pound$BoT_Price
  ),
  EoT_Price = c(
    treasury_bond$EoT_Price,
    sp500_futures$EoT_Price,
    nasdaq$EoT_Price,
    british_pound$EoT_Price
  )
)

Print the data frame

print(future_prices)

Analysis of the results

In this case, we have created a function in order to retrieve the settle price of the different types of futures, with the first settlement date beyond the end of the school term. As done before, we have adjusted the function to manage non-trading days. In the data obtained we can observe an individual appreciation of each of their prices, which may indicate an overall growth in economy. However, some other factors that usually affect futures prices, such as interest rates, macroeconomic decisions, the market preferences and supply and demand can have a significant impact in the pricing of these assets.

L1.3 Use an options quotations table to select a call option on a firm whose stock price you expect to increase (select the option with the first expiration month beyond the end of the school term)

Install and load packages

# Load packages
library(quantmod)
library(tidyverse)
library(lubridate)
library(timeDate)
library(RQuantLib)

Define BoT and EoT dates

BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

Create function to adjust to non-trading dates and obtain stock information

#getting the symbols
get_stock_price <- function(symbol, date, use_next = FALSE)  {
    data <- getSymbols(
        Symbols = symbol,
        from = date - days(10),
        to = date + days(10),
        auto.assign = FALSE

    )
    #solving issues with non-trading days
    index(data) <- as.Date(index(data))
    if (use_next) {
        available_dates <- index(data)[index(data) >= date]
        if(length(available_dates) == 0) {
            warning(paste("No data available after", date, "for symbol:", symbol))
            return(NA)
        }
        date_used <- min(available_dates)
    } else {
        available_dates <- index(data)[index(data) <= date] 
        if (length(available_dates) == 0) {
            warning(paste("No data available before", date, "for symbol:", symbol))
            return(NA)
        }
        date_used <- max(available_dates)
    }
   #obtaining price
     price <- as.numeric(Cl(data[date_used]))
    return(list(
        Price = price, Date = as.Date(date_used)
    ))
}

Getting the data for our selected stock

BoT_stock <- get_stock_price("BABA", BoT_date, use_next = TRUE)
EoT_stock <- get_stock_price("BABA", EoT_date, use_next = FALSE)

Calculate Option Premiums on BoT and EoT. Option Type: Call Option Strike Price: Closest to the stock price at BoT_date Expiration Date: First Option expiration date beyond EoT_Date

# Load necessary packages
library(lubridate)
library(timeDate)

# Initialize expiration_dates as an empty vector of class Date
expiration_dates <- as.Date(character())

# Get the current date
current_date <- as.Date(Sys.Date())

# Define your EoT_date
EoT_date <- as.Date("2024-09-30")

# Define the corrected third_friday function
third_friday <- function(year, month) {
    # Get all days in the month
    dates <- seq(
        from = as.Date(paste0(year, "-", month, "-01")),
        to = as.Date(paste0(year, "-", month, "-", days_in_month(as.Date(paste0(year, "-", month, "-01"))))),
        by = "day"
    )
    
    # Get all Fridays using wday()
    fridays <- dates[wday(dates) == 6]  # 6 corresponds to Friday
    
    # Return the third Friday
    if (length(fridays) >= 3) {
        return(fridays[3])
    } else {
        return(NA)
    }
}

# Loop over the next 18 months
for (i in 0:17) {
    # Add i months to the current date
    date <- current_date %m+% months(i)
    
    # Extract the year and month
    yr <- year(date)
    mnth <- month(date)
    
    # Calculate the third Friday of the month
    exp_date <- third_friday(yr, mnth)
    
    if (!is.na(exp_date)) {
        expiration_dates <- c(expiration_dates, exp_date)
    }
}

# Filter expiration dates beyond EoT_date
expiration_dates <- expiration_dates[expiration_dates > EoT_date]

# Print the expiration dates
print(expiration_dates)
 [1] "2025-01-17" "2025-02-21" "2025-03-21"
 [4] "2025-04-18" "2025-05-16" "2025-06-20"
 [7] "2025-07-18" "2025-08-15" "2025-09-19"
[10] "2025-10-17" "2025-11-21" "2025-12-19"
[13] "2026-01-16" "2026-02-20" "2026-03-20"
[16] "2026-04-17" "2026-05-15" "2026-06-19"

Get strike price

strike_price <- round(BoT_stock$Price, digits = -1)  # Round to nearest 10

Estimate volatility

# Get historical stock prices for the past year before BoT_date
ticker <- "BABA"
vol_data <- getSymbols(
  Symbols = ticker,
  src = "yahoo",
  from = BoT_stock$Date - years(1),
  to = BoT_stock$Date,
  auto.assign = FALSE
)

# Calculate daily returns
returns <- dailyReturn(Cl(vol_data))

# Calculate annualized volatility
volatility <- sd(returns, na.rm = TRUE) * sqrt(252)  # 252 trading days in a year

Set risk-free Interest Rate and Dividend Yield

#Risk-free interest rate (e.g., 2% annualized)
risk_free_rate <- 0.02
#Dividend yield (from Yahoo Finance or set to 0.005 for 0.5%)
dividend_yield <- 0.05

Calculate Time to Expiration

# Assuming 'expiration_dates' is a vector of Date objects
expiration_dates <- expiration_dates[expiration_dates > EoT_date]

# Select the earliest expiration date beyond EoT_date
expiration_date <- expiration_dates[1]

# Time to expiration from BoT_date
time_to_expiration_BoT <- as.numeric(expiration_date - BoT_stock$Date) / 365

# Time to expiration from EoT_date
time_to_expiration_EoT <- as.numeric(expiration_date - EoT_stock$Date) / 365

Use Black-Scholes Model to calculate Option Premiums

#Function to calculate Option Premium
calculate_option_premium <- function(S, K, r, time_to_expiration, sigma, dividend_yield) {
  option <- EuropeanOption(
    type = "call",
    underlying = S,
    strike = K,
    dividendYield = dividend_yield,
    riskFreeRate = r,
    maturity = time_to_expiration,
    volatility = sigma
  )
  return(option$value)
}

Calculate Option Premiums

# Option premium on BoT_date
BoT_premium <- calculate_option_premium(
  S = BoT_stock$Price,
  K = strike_price,
  r = risk_free_rate,
  time_to_expiration = time_to_expiration_BoT,
  sigma = volatility,
  dividend_yield = dividend_yield
)

# Option premium on EoT_date
EoT_premium <- calculate_option_premium(
  S = EoT_stock$Price,
  K = strike_price,
  r = risk_free_rate,
  time_to_expiration = time_to_expiration_EoT,
  sigma = volatility,
  dividend_yield = dividend_yield
)

Create table for results

results <- data.frame(
    Stock = "BABA",
    BoT_Date = BoT_stock$Date,
    BoT_Price = BoT_stock$Price,
    BoT_Option_Premium = BoT_premium,
    EoT_Date = EoT_stock$Date,
    EoT_Price = EoT_stock$Price,
    EoT_Option_Premium = EoT_premium
)
print(results)

Analysis of results

In this exercise we must retrieve data of a call data from a stock we expect to increase. In these case, we have considered to take into account Alibaba (“BABA”), as we consider that is a company which is currently undervalued and has a huge potential of growth in terms of stock price. For the development of this exercise we have developed a new function to get our sstock data, but in this case we have lengthened our time bracket to obtain data both from before BoT date and after EoT date. We have also defined the expiration dates to the month’s third Friday, and we have set the expiration dates available to those after EoT date. Afterwards we have stablished the strike price and, with the use of a new function, we have calculated the volatility. As our last steps before applying the Black-Scholes model, we have calculated our time to expiration and we have established the risk-free rate and the dividend yield. Finally, we have defined our function for applying the Black-Scholes model and we have retrieved the option premiums at BoT date and EoT date.

The results obtained thanks to this code has led us to perceive a significant appreciation in the option premium, which we can attribute to an improvement of the underlying asset (“BABA”). Also, when we observe the change in price, it matches with the observation in the premiums, overall determining the great performance of the selected asset during the school term.

L1.4

Getting data for our selected stock

# Get stock prices on BoT and EoT dates
BoT_stock <- get_stock_price("ING", BoT_date, use_next = TRUE)
EoT_stock <- get_stock_price("ING", EoT_date, use_next = FALSE)

Calculate Option Premiums on BoT and EoT +Option type: put option +Strike Price: Closes to the Stock price at BoT_Date +Expiration Date: First option expiration date beyond EoT_date

Get Strike Price

#Round to the nearest 10
strike_price <- round(BoT_stock$Price, digits = -1) 

Estimate Volatility

# Get historical stock prices for the past year before BoT_date
ticker <- "ING"
vol_data <- getSymbols(
  Symbols = ticker,
  src = "yahoo",
  from = BoT_stock$Date - years(1),
  to = BoT_stock$Date,
  auto.assign = FALSE
)

# Calculate daily returns
returns <- dailyReturn(Cl(vol_data))

# Calculate annualized volatility
volatility <- sd(returns, na.rm = TRUE) * sqrt(252)  # 252 trading days in a year

Set Risk-Free Interest Rate and Dividend Yield

#Risk-free interest rate (2% annualized for example)
risk_free_rate <- 0.02

#Dividend Yield (most recent)
dividend_yield <- 0.0749

Calculate time to expiration

# Time to expiration from BoT_date
time_to_expiration_BoT <- as.numeric(expiration_date - BoT_stock$Date) / 365

# Time to expiration from EoT_date
time_to_expiration_EoT <- as.numeric(expiration_date - EoT_stock$Date) / 365

Calculate Option Premiums

# Option premium on BoT_date
BoT_premium <- calculate_option_premium(
  S = BoT_stock$Price,
  K = strike_price,
  r = risk_free_rate,
  time_to_expiration = time_to_expiration_BoT,
  sigma = volatility,
  dividend_yield = dividend_yield
)

# Option premium on EoT_date
EoT_premium <- calculate_option_premium(
  S = EoT_stock$Price,
  K = strike_price,
  r = risk_free_rate,
  time_to_expiration = time_to_expiration_EoT,
  sigma = volatility,
  dividend_yield = dividend_yield
)

Create table for Results

# Create a data frame with the obtained data
results <- data.frame(
    Stock = "ING",
    BoT_Date = BoT_stock$Date,
    BoT_Price = BoT_stock$Price,
    BoT_Option_Premium = BoT_premium,
    EoT_Date = EoT_stock$Date,
    EoT_Price = EoT_stock$Price,
    EoT_Option_Premium = EoT_premium
)

# Display the results
print(results)
NA

Analysis of results.

In this case, we have only had to apply the functions and process we had just applied for the call option. The Asset we have selected is Bank ING which we had expected to fall. However, in the results obtained we have noticed an appreciation in the stock value as well as the premiums. This means that the stock has out performed our expectations and has not fallen during the school term. Had we bought the put option in the beginning of term date, we would have had a negative action of our operation. However, we would like to note that in the recent times, ING has been hit with negative news and information regarding massive withdrawals. However, this information appears to have been debunked, although there has been observed recent negative stock movements.

L1.5

Define BoT and EoT dates

BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

Create a Function to Retrieve Exchange Rates with Non-Trading day Adjustment

get_exchange_rate <- function(symbol, date, use_next = FALSE, invert = FALSE) {
  # Retrieve exchange rate data from FRED
  data <- getSymbols(Symbols = symbol, src = "FRED", auto.assign = FALSE)
  
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Adjust for non-trading days
  if (use_next) {
    # For BoT_date, get the next available date after the date
    available_dates <- index(data)[index(data) >= date & !is.na(data[index(data)])]
    if(length(available_dates) == 0) {
      warning(paste("No data available after", date, "for symbol:", symbol))
      return(list(Rate = NA, Date = NA))
    }
    date_used <- min(available_dates)
  } else {
    # For EoT_date, get the last available date before the date
    available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
    if (length(available_dates) == 0) {
      warning(paste("No data available before", date, "for symbol:", symbol))
      return(list(Rate = NA, Date = NA))
    }
    date_used <- max(available_dates)
  }
  
  # Get the exchange rate
  rate <- as.numeric(data[date_used])
  
  # Invert the rate if needed (for currencies quoted as foreign currency per USD)
  if (invert) {
    rate <- 1 / rate
  }
  
  return(list(
    Rate = rate,
    Date = as.Date(date_used)
  ))
}

Retrieve Exchange Rates on BoT and EoT Dates Symbols in FRED: GPB/USD: DEXUSUK JPY/USD: DEXJPUS MXN/USD: DEXMXUS (FRED provides exchange rates in foreign currency units per U.S. dollar for JPY and MXN, so we’ll invert these rates to get USD per foreign currency unit)

# Retrieve exchange rates on BoT_date
GBP_BoT <- get_exchange_rate("DEXUSUK", BoT_date, use_next = TRUE)
JPY_BoT <- get_exchange_rate("DEXJPUS", BoT_date, use_next = TRUE, invert = TRUE)
MXN_BoT <- get_exchange_rate("DEXMXUS", BoT_date, use_next = TRUE, invert = TRUE)

# Retrieve exchange rates on EoT_date
GBP_EoT <- get_exchange_rate("DEXUSUK", EoT_date, use_next = FALSE)
JPY_EoT <- get_exchange_rate("DEXJPUS", EoT_date, use_next = FALSE, invert = TRUE)
MXN_EoT <- get_exchange_rate("DEXMXUS", EoT_date, use_next = FALSE, invert = TRUE)

Create a Data Frame to Display the Results

# Create data frame with the results
results <- data.frame(
  Currency = c("GBP/USD", "JPY/USD", "MXN/USD"),
  BoT_Date = c(GBP_BoT$Date, JPY_BoT$Date, MXN_BoT$Date),
  BoT_Rate = c(GBP_BoT$Rate, JPY_BoT$Rate, MXN_BoT$Rate),
  EoT_Date = c(GBP_EoT$Date, JPY_EoT$Date, MXN_EoT$Date),
  EoT_Rate = c(GBP_EoT$Rate, JPY_EoT$Rate, MXN_EoT$Rate)
)

# Display the results
print(results)

Analysis of results

In this exercise we have designed a new function to retrieve exchange rates, as always adjusting it to the non-trading days. We have retrieve the data of three different exchange rates both on BoT date and EoT date and we have portrayed the result in a data frame.

L1.6 Use currency options data (if available) to select a call option on a foreign currency that you expect will strengthen against the dollar (select the option with the first expiration month beyond the end of the school term)

Load packages

# Load packages
library(quantmod)
library(lubridate)
library(timeDate)
library(tidyverse)

Define BoT and EoT Dates

BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

Create a function to Adjust for Non-Trading Days and Obtain Exchange Rate Data

get_exchange_rate <- function(symbol, date, use_next = FALSE) {
  # Download data around the date
  data <- getSymbols(
    Symbols = symbol,
    src = "yahoo",
    from = date - days(10),
    to = date + days(10),
    auto.assign = FALSE
  )
  
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Handle non-trading days
  if (use_next) {
    # For BoT_date, get the next available date after the date
    available_dates <- index(data)[index(data) >= date]
    if(length(available_dates) == 0) {
      warning(paste("No data available after", date, "for symbol:", symbol))
      return(list(Rate = NA, Date = NA))
    }
    date_used <- min(available_dates)
  } else {
    # For EoT_date, get the last available date before the date
    available_dates <- index(data)[index(data) <= date]
    if (length(available_dates) == 0) {
      warning(paste("No data available before", date, "for symbol:", symbol))
      return(list(Rate = NA, Date = NA))
    }
    date_used <- max(available_dates)
  }
  
  # Get the exchange rate
  rate <- as.numeric(Cl(data[date_used]))
  
  return(list(
    Rate = rate,
    Date = as.Date(date_used)
  ))
}

Retrieve Exchabge Rates on BoT and EoT dates

# Get exchange rates for CNY/USD
# Note: On Yahoo Finance, the symbol for CNY/USD is "CNY=X"

CNY_BoT <- get_exchange_rate("CNY=X", BoT_date, use_next = TRUE)
CNY_EoT <- get_exchange_rate("CNY=X", EoT_date, use_next = FALSE)

Determine Option Details +Option type: Call option +Strike Price: Use the spot exchange rate at BoT_Date (At-The-Money) +Expiration Date: First option expiration date beyond EoT_Date

Generate Option Expiration Dates

# Function to get the third Friday of a month
third_friday <- function(year, month) {
  dates <- seq(
    from = as.Date(paste0(year, "-", month, "-01")),
    to = as.Date(paste0(year, "-", month, "-", days_in_month(as.Date(paste0(year, "-", month, "-01"))))),
    by = "day"
  )
  fridays <- dates[wday(dates) == 6]  # 6 corresponds to Friday
  if (length(fridays) >= 3) {
    return(fridays[3])
  } else {
    return(NA)
  }
}

# Generate expiration dates for the next 18 months
expiration_dates <- as.Date(character())
current_date <- as.Date(Sys.Date())

for (i in 0:17) {
  date <- current_date %m+% months(i)
  yr <- year(date)
  mnth <- month(date)
  exp_date <- third_friday(yr, mnth)
  if (!is.na(exp_date)) {
    expiration_dates <- c(expiration_dates, exp_date)
  }
}

# Filter expiration dates beyond EoT_date
expiration_dates <- expiration_dates[expiration_dates > EoT_date]

# Select the first expiration date beyond EoT_date
if (length(expiration_dates) == 0) {
  stop("No expiration dates found beyond EoT_date.")
}

expiration_date <- expiration_dates[1]
print(paste("Selected Option Expiration Date:", expiration_date))
[1] "Selected Option Expiration Date: 2025-01-17"

Calculate Time to expiration

# Time to expiration from BoT_date
time_to_expiration_BoT <- as.numeric(expiration_date - CNY_BoT$Date) / 365

# Time to expiration from EoT_date
time_to_expiration_EoT <- as.numeric(expiration_date - CNY_EoT$Date) / 365

Set the Strike Price

strike_price <- CNY_BoT$Rate  # At-The-Money option

Estimate Volatility

# Get historical exchange rate data for the past year before BoT_date
vol_data <- getSymbols(
  Symbols = "CNY=X",
  src = "yahoo",
  from = CNY_BoT$Date - years(1),
  to = CNY_BoT$Date,
  auto.assign = FALSE
)

# Calculate daily returns
returns <- dailyReturn(Cl(vol_data))

# Calculate annualized volatility
volatility <- sd(returns, na.rm = TRUE) * sqrt(252)  # 252 trading days in a year

Set Domestic and Foreign Risk-Free Interest Rates Domestic Risk-Free Rate (r_domestic): US risk-free rate Foreign Risk-Free Rate (r_foreign): Chinese risk-free rate

r_domestic <- 0.043
r_foreign <- 0.0209

Define the Garman-Kohlhagen Model Function

calculate_currency_option_premium <- function(S, K, r_domestic, r_foreign, time_to_expiration, sigma, option_type = "call") {
  d1 <- (log(S / K) + (r_domestic - r_foreign + 0.5 * sigma^2) * time_to_expiration) / (sigma * sqrt(time_to_expiration))
  d2 <- d1 - sigma * sqrt(time_to_expiration)
  
  if (option_type == "call") {
    premium <- S * exp(-r_foreign * time_to_expiration) * pnorm(d1) - K * exp(-r_domestic * time_to_expiration) * pnorm(d2)
  } else if (option_type == "put") {
    premium <- K * exp(-r_domestic * time_to_expiration) * pnorm(-d2) - S * exp(-r_foreign * time_to_expiration) * pnorm(-d1)
  } else {
    stop("Invalid option type. Use 'call' or 'put'.")
  }
  
  return(premium)
}

Calculate Option Premiums

# Option premium on BoT_date
BoT_premium <- calculate_currency_option_premium(
  S = CNY_BoT$Rate,
  K = strike_price,
  r_domestic = r_domestic,
  r_foreign = r_foreign,
  time_to_expiration = time_to_expiration_BoT,
  sigma = volatility,
  option_type = "call"
)

# Option premium on EoT_date
EoT_premium <- calculate_currency_option_premium(
  S = CNY_EoT$Rate,
  K = strike_price,
  r_domestic = r_domestic,
  r_foreign = r_foreign,
  time_to_expiration = time_to_expiration_EoT,
  sigma = volatility,
  option_type = "call"
)

Create Data Frame to Display Results

# Create data frame with the results
results <- data.frame(
  Currency = "CNY/USD",
  BoT_Date = CNY_BoT$Date,
  BoT_Rate = CNY_BoT$Rate,
  BoT_Option_Premium = BoT_premium,
  EoT_Date = CNY_EoT$Date,
  EoT_Rate = CNY_EoT$Rate,
  EoT_Option_Premium = EoT_premium
)

# Display the results
print(results)

Analysis of results

In this exercise we have performed a rather similar process than that of L1.4 and L1.5. However, in this case we are studying a call option on a currency that we think might appreciate in value during the school term. The currency we have selected has been the Chinese Yuan. The weakening of the US Treasury Interest is one of the main drivers of the weakening of the US Dollar and probably the main reason for the appreciation of the Chinese Yuan against it.
In this case, we have not used the Black-Scholes Model, but rather the Garman-Kohlhagen Model Function, which is often use to price currency options.

Regarding the results, in this case we have not been able to secure a favorable result in the call option, as the rate has depreciated, as well as the premium, at EoT. This results can be explained due to a great range of factors that include monetary policy of both countries, market movements, supply and demand, macroeconomic data, microeconomic details or even speculation from investors. Either way, the results depict an strengthen US Dollar against the Chinese Yuan and the exercise helps us to exemplify how a call option on a currency may be priced.

L1.7 Use currency options data (if available) to select a put option on a foreign currency that you expect will weaken against the dollar (select the option with the first expiration month beyond the end of the school term).

Retrieve Exchange Rates on BoT and EoT dates

# Get exchange rates for EUR/USD
# Note: On Yahoo Finance, the symbol for CNY/USD is "EURUSD=X"

EUR_BoT <- get_exchange_rate("EURUSD=X", BoT_date, use_next = TRUE)
EUR_EoT <- get_exchange_rate("EURUSD=X", EoT_date, use_next = FALSE)

Determine Option Details +Option type: Call option +Strike Price: Use the spot exchange rate at BoT_Date (At-The-Money) +Expiration Date: First option expiration date beyond EoT_Date

Calculate Time to expiration

# Time to expiration from BoT_date
time_to_expiration_BoT <- as.numeric(expiration_date - EUR_BoT$Date) / 365

# Time to expiration from EoT_date
time_to_expiration_EoT <- as.numeric(expiration_date - EUR_EoT$Date) / 365

Set the Strike Price

strike_price <- EUR_BoT$Rate  # At-The-Money option

Estimate Volatility

# Get historical exchange rate data for the past year before BoT_date
vol_data <- getSymbols(
  Symbols = "EURUSD=X",
  src = "yahoo",
  from = EUR_BoT$Date - years(1),
  to = EUR_BoT$Date,
  auto.assign = FALSE
)

# Calculate daily returns
returns <- dailyReturn(Cl(vol_data))

# Calculate annualized volatility
volatility <- sd(returns, na.rm = TRUE) * sqrt(252)  # 252 trading days in a year

Set Domestic and Foreign Risk-Free Interest Rates Domestic Risk-Free Rate (r_domestic): US risk-free rate Foreign Risk-Free Rate (r_foreign): European risk-free rate

r_domestic <- 0.043
r_foreign <- 0.0247

Calculate Option Premiums

# Option premium on BoT_date
BoT_premium <- calculate_currency_option_premium(
  S = EUR_BoT$Rate,
  K = strike_price,
  r_domestic = r_domestic,
  r_foreign = r_foreign,
  time_to_expiration = time_to_expiration_BoT,
  sigma = volatility,
  option_type = "put"
)

# Option premium on EoT_date
EoT_premium <- calculate_currency_option_premium(
  S = EUR_EoT$Rate,
  K = strike_price,
  r_domestic = r_domestic,
  r_foreign = r_foreign,
  time_to_expiration = time_to_expiration_EoT,
  sigma = volatility,
  option_type = "put"
)

Create Data Frame to Display Results

# Create data frame with the results
results <- data.frame(
  Currency = "EUR/USD",
  BoT_Date = EUR_BoT$Date,
  BoT_Rate = EUR_BoT$Rate,
  BoT_Option_Premium = BoT_premium,
  EoT_Date = EUR_EoT$Date,
  EoT_Rate = EUR_EoT$Rate,
  EoT_Option_Premium = EoT_premium
)

# Display the results
print(results)

Analysis of results

In this last exercise of the section we have retrieved the information of the Rate of Exchange EUR/USD and we had an initial expectation of a decrease in the value of the EUR over the school term. However, our initial thoughts have been proven wrong as we have obtained a higher rate at the EoT date and the Option Premium has fallen. In the case of having buyed this put option, the outcome would have resulted in a negative operation. This results depict an strengthened Euro against the Dollar. Even though our initial hypothesis of the movement of the Euro against the Dollar were wrong, we have developed an answer that explains how a put option on an currency exchange rate may be priced and how its premium can be calculated, using the Garman-Kohlhagen Model Function.

L2 Financial markets microstructure

Nasdaq and London Stock Exchange are two major global stock exchanges with significant influence no global financial markets. Historical Stock data for representative indices of both exchanges can be retrieved and analyzed using R. Qualitative information about ach exchange is available from reputable sources.

Hypotheses

There is a significant correlation between the performance of Nasdaq and the LSE indices over the specified period. Differences in market capitalization, liquidity, and types of instruments traded influence the statistical measures observed The time zone difference affects the trading patterns and liquidity of the two exchanges.

Data Retrieval and Preparation

Load required packages

# Install and load required packages
if (!require("quantmod")) {
  install.packages("quantmod")
}
if (!require("PerformanceAnalytics")) {
  install.packages("PerformanceAnalytics")
}
library(quantmod)
library(PerformanceAnalytics)

Retrieve Historical Data

# Define the date range
start_date <- as.Date("2008-01-03")
end_date <- as.Date("2023-01-05")

# Get historical data for Nasdaq Composite Index
getSymbols("^IXIC", src = "yahoo", from = start_date, to = end_date)
[1] "IXIC"
# Get historical data for FTSE 100 Index
getSymbols("^FTSE", src = "yahoo", from = start_date, to = end_date)
Aviso: ^FTSE contains missing values. Some functions will not work if objects contain missing values in the middle of the series. Consider using na.omit(), na.approx(), na.fill(), etc to remove or replace them.
[1] "FTSE"

Data Cleaning and Alignment

# Assign data to variables
nasdaq_data <- `IXIC`
ftse_data <- `FTSE`
# Check for missing values
sum(is.na(ftse_data))
[1] 12
# Handle missing values using linear interpolation
ftse_data <- na.approx(ftse_data)

# Merge the closing prices based on date
combined_data <- merge(Cl(nasdaq_data), Cl(ftse_data), all = FALSE)

# Rename columns for clarity
colnames(combined_data) <- c("Nasdaq_Close", "FTSE_Close")

Statistical Analysis

Calculate Basic Statistics

For Nasdaq

# Calculate basic statistics for Nasdaq
nasdaq_stats <- data.frame(
  Mean = mean(combined_data$Nasdaq_Close, na.rm = TRUE),
  Median = median(combined_data$Nasdaq_Close, na.rm = TRUE),
  StDev = sd(combined_data$Nasdaq_Close, na.rm = TRUE)
)
print(nasdaq_stats)

For FTSE

# Calculate basic statistics for FTSE
ftse_stats <- data.frame(
  Mean = mean(combined_data$FTSE_Close, na.rm = TRUE),
  Median = median(combined_data$FTSE_Close, na.rm = TRUE),
  StDev = sd(combined_data$FTSE_Close, na.rm = TRUE)
)
print(ftse_stats)

Calculate Correlation

# Calculate correlation between Nasdaq and FTSE closing prices
correlation <- cor(combined_data$Nasdaq_Close, combined_data$FTSE_Close, use = "complete.obs")

# Print the correlation coefficient
cat("Correlation between Nasdaq and FTSE:", round(correlation, 2), "\n")
Correlation between Nasdaq and FTSE: 0.65 

Display Results


# Combine statistics for comparison
stats_comparison <- rbind(Nasdaq = nasdaq_stats, FTSE = ftse_stats)

# Set column names
colnames(stats_comparison) <- c("Mean", "Median", "Standard Deviation")

# Print the statistics
print("Basic Statistics Comparison:")
[1] "Basic Statistics Comparison:"
print(round(stats_comparison, 2))

# Print the correlation coefficient
cat("Correlation between Nasdaq and FTSE:", round(correlation, 2), "\n")
Correlation between Nasdaq and FTSE: 0.65 

Analysis of the correlation

The correlation coefficient measures the strength and direction of the relation between two sets of data, or in this case, of two assets. The correlation coefficient can vary from -1 to 1, and with each value we obtain a representation of how interconnected are two assets. In the case of this exercise, we have obtained a correlation coefficient of 0.65, which constitutes a positive and strong correlation between the two indexes in study. In broader terms, this means that the tendencies of both indexes will be somewhat similar and will trend in the same direction.

Market Capitalization

Market capitalization represents the total value of all listed companies on an exchange. It’s a key indicator of the size and economic weight of a stock exchange. Although we do not have access to direct data, we will try to make the comparison using the top 5 companies from each exchange.

Hypothesis:

The Nasdaq has a larger market capitalization compared to LSE due to its concentration of large technology companies

Implementation:

Load packages


# Install and load required packages
if (!require("quantmod")) {
  install.packages("quantmod")
}
library(quantmod)
library(dplyr)

Define Top Companies. We will extract this companies from the indexes websites. LSE top 5 companies: Atrazeneca PLC, Shell PLC, HSBC HLDGS PLC, Unilever PLC, RELX PLC.
NASDAQ top 5 companies: Apple Inc, NVIDIA corp, Microsoft Corp, Amazon.com Inc, Broadcom Inc. 

nasdaq_symbols <- c("AAPL", "NVDA", "MSFT", "AMZN", "AVGO")
lse_symbols <- c("AZN.L", "SHEL.L", "HSBA.L", "ULVR.L", "REL.L")

Retrieve Market Capitalization Data


# Install and load tidyquant
if (!require("tidyquant")) {
  install.packages("tidyquant")
}
library(tidyquant)
library(dplyr)

Get Market Cap Data

# Function to get market cap data
get_market_cap <- function(symbols) {
  # Retrieve market capitalization data
  data <- getQuote(symbols, what = yahooQF("Market Capitalization"))
  
  # Convert rownames to a column
  data <- data %>%
    rownames_to_column(var = "symbol") %>%
    rename(market_cap = `Market Capitalization`) %>%
    select(symbol, market_cap)
  
  return(data)
}

# Get market cap data for Nasdaq companies
nasdaq_market_cap <- get_market_cap(nasdaq_symbols)
Error en getQuote.yahoo(Symbols = c("AAPL", "NVDA", "MSFT", "AMZN", "AVGO": 
  Unable to obtain yahoo crumb. If this is being called from a GDPR country, Yahoo requires GDPR consent, which cannot be scripted

Sum Market Caps

# Sum the market caps
nasdaq_total_market_cap <- sum(as.numeric(nasdaq_market_cap$market_cap), na.rm = TRUE)
Error: objeto 'nasdaq_market_cap' no encontrado

Handle Exchange Rates

# Get current GBP to USD exchange rate
getSymbols("GBPUSD=X", src = "yahoo", from = Sys.Date() - 1, to = Sys.Date())
[1] "GBPUSD=X"
exchange_rate <- as.numeric(Cl(`GBPUSD=X`)[1])

# Convert LSE market caps to USD
lse_market_cap$market_cap_usd <- as.numeric(lse_market_cap$market_cap) * exchange_rate
Error: objeto 'lse_market_cap' no encontrado

When trying to perform out analysis of the market capitalization we have encounter a problem two retrieve data from R, so we cannot perform the numerical demonstration. However, we will state that as far as the information we have been able to gather, the LSEG has a higher market capitalization than Nasdaq, Inc. This means that the LSE has a higher corporate market capitalization. However, if we take into account the aggregate market capitalization, the total market value of the assets traded in Nasdaq greatly surpass the value of those traded in the LSE.

A higher market capitalization may indicate higher economic influence, liquidity and overall international attractiveness. However, in this case Nasdaq’s thorough focus on technological companies narrows its representation of the economy while the LSE has a broader range of assets.

Liquidity.

It reflects how easily can assets be bought and sold in the market. Higher trading volumes indicate higher liquidity.

Hypothesis.

The Nasdaq has a higher average trading volumes compared to LSE due to its larger size and global investor base

We will retrieve the daily trading volume data from the indices and calculate the average daily volume over an specified period.

For the Volume Data we will be using their top companies as a proxy.

nasdaq_volumes <- list()
for (symbol in nasdaq_symbols) {
  data <- getSymbols(symbol, src = "yahoo", from = start_date, to = end_date, auto.assign = FALSE)
  nasdaq_volumes[[symbol]] <- Cl(data)
}

# Get volume data for top LSE companies
lse_volumes <- list()
for (symbol in lse_symbols) {
  data <- getSymbols(symbol, src = "yahoo", from = start_date, to = end_date, auto.assign = FALSE)
  volume_data <- Vo(data)
  
  # Handle missing values
  if (any(is.na(volume_data))) {
    cat("Handling missing values for", symbol, "\n")
    volume_data <- na.approx(volume_data)
  }
  
  # Store cleaned volume data
  lse_volumes[[symbol]] <- volume_data
}

# Merge and align LSE volumes
lse_volume_data <- do.call(merge, lse_volumes)

# Remove any remaining missing values
lse_volume_data <- na.omit(lse_volume_data)

We calculate Average Volume

# Calculate average volume for Nasdaq companies
nasdaq_avg_volumes <- sapply(nasdaq_symbols, function(symbol) {
  data <- getSymbols(symbol, src = "yahoo", from = start_date, to = end_date, auto.assign = FALSE)
  mean(Vo(data), na.rm = TRUE)
})

# Calculate average volume for LSE companies
lse_avg_volumes <- sapply(lse_volumes, function(volume_data) {
  mean(volume_data, na.rm = TRUE)
})

# Calculate the overall average volume
lse_avg_volume <- mean(lse_avg_volumes, na.rm = TRUE)

# Average volume across top companies
nasdaq_avg_volume <- mean(nasdaq_avg_volumes, na.rm = TRUE)
lse_avg_volume <- mean(lse_avg_volumes, na.rm = TRUE)

# Print results
cat("Average Daily Trading Volume for Nasdaq Top Companies:", formatC(nasdaq_avg_volume, format = "f", big.mark = ",", digits = 0), "\n")
Average Daily Trading Volume for Nasdaq Top Companies: 209,954,412 
cat("Average Daily Trading Volume for LSE Top Companies:", formatC(lse_avg_volume, format = "f", big.mark = ",", digits = 0), "shares\n")
Average Daily Trading Volume for LSE Top Companies: 9,923,258 shares

Analysis of results

We encounter some limitation regarding this comparison, as the volume units may differ between exchanges and the volume data for indices may not be directly comparable. However, it becomes noticeable that the average trading volume for Nasdaq’s Top companies is significantly higher than that of LSE. This indicates a more active market and is understandably explained by the constantly changing environment of the technological companies traded in the Nasdaq.

Number of IPOs

The number of Initial Public Offerings reflects the attractiveness of an exchange for companies looking to raise capital. Due to lack of possibility to retrieve such data, we will just mention that recent data signals a greater number of IPOs in Nasdaq compared to those of LSE, which indicates a much more attractive stock exchange both for investors and for companies who seek to raise capital, and gives a great example of how remarkable are sector trends in the manifestation of IPOs.

M&A Frequency

The frequency in mergers and acquisitions may indicate the dynamism of the market.

This data is yet again not available directly from R, but we may find it from other sources.

Nasdaq: active M&A environment in technology and biotech sectors.

LSE: regular M&A activity across sectors like finance, energy and mining.

Quality of information

Nasdaq: Regulated by the U.S. Securities and Exchange Commission (SEC). Strict reporting and disclosure requirements. Uses market makers and electronic communication networks (ECNs) as gatekeepers.

LSE: Regulated by the Financial Conduct Authority (FCA) in the UK. Emphasis on transparency and market integrity. Sponsors and nominated advisors (Nomads) act as gatekeepers for AIM.

Trading Costs

Nasdaq: Trading costs include brokerage fees, SEC fees, and potential exchange fees. Generally low due to high competition among brokers.

LSE: Trading costs may include brokerage fees, stamp duty (0.5% on purchases), and other transaction costs.

Trading Hours (time zone difference)

We may quantify the trading hours and calculate the overlap

# Nasdaq trading hours: 9:30 AM to 4:00 PM EST
# LSE trading hours: 8:00 AM to 4:30 PM GMT

# Convert trading hours to UTC
nasdaq_open_utc <- as.POSIXct("14:30", format = "%H:%M", tz = "UTC")  # 9:30 AM EST is 14:30 UTC
nasdaq_close_utc <- as.POSIXct("21:00", format = "%H:%M", tz = "UTC")  # 4:00 PM EST is 21:00 UTC

lse_open_utc <- as.POSIXct("08:00", format = "%H:%M", tz = "UTC")
lse_close_utc <- as.POSIXct("16:30", format = "%H:%M", tz = "UTC")

# Calculate overlap
overlap_start <- max(nasdaq_open_utc, lse_open_utc)
overlap_end <- min(nasdaq_close_utc, lse_close_utc)

if (overlap_start < overlap_end) {
  overlap_hours <- as.numeric(difftime(overlap_end, overlap_start, units = "hours"))
} else {
  overlap_hours <- 0
}

# Print results
cat("Overlap in Trading Hours: ", overlap_hours, " hours\n")
Overlap in Trading Hours:  2  hours

Here we have calculated the overlaping in trading hours. The low overlaping trading hours can have huge impacts on the trading strategies, as the information from one market will already be incorporated at the opening of the other. This causes shifts in volatility and investor’s behaviour, but can also be used as an strategic advantage for diversifying their investments.

L3 Instrument’s overview and valuation

L3.1 Compare the 13-week Treasury bill rate (which is a proxy for short-term interest rates) at the end of the school term to the rate that existed at the beginning of the school term. (note: 3-Month Treasury Bill Secondary Market Rate, Discount Basis (TB3MS))

load packages

library(quantmod)
library(lubridate)

define dates

# Define Beginning of Term (BoT) and End of Term (EoT) dates
BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

Retrieve data

# Retrieve TB3MS data from FRED
getSymbols("TB3MS", src = "FRED")
[1] "TB3MS"
# View the first few rows of data
head(TB3MS)
           TB3MS
1934-01-01  0.72
1934-02-01  0.62
1934-03-01  0.24
1934-04-01  0.15
1934-05-01  0.16
1934-06-01  0.15

Function to adjust to non-trading days

# Function to get the rate on a specific date, adjusting for non-trading days
get_rate_on_date <- function(data, date, use_next = FALSE) {
  # Convert index to Date format if not already
  index(data) <- as.Date(index(data))
  
  if (use_next) {
    # Get the next available date after the specified date
    available_dates <- index(data)[index(data) >= date & !is.na(data[index(data)])]
    if(length(available_dates) == 0) {
      warning(paste("No data available after", date))
      return(list(Rate = NA, Date = NA))
    }
    date_used <- min(available_dates)
  } else {
    # Get the last available date before or on the specified date
    available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
    if (length(available_dates) == 0) {
      warning(paste("No data available before", date))
      return(list(Rate = NA, Date = NA))
    }
    date_used <- max(available_dates)
  }
  
  # Get the rate
  rate <- as.numeric(data[date_used])
  
  return(list(
    Rate = rate,
    Date = as.Date(date_used)
  ))
}

Retrieve Rates on BoT_date and EoT_date

# Get rate on BoT_date
BoT_rate <- get_rate_on_date(TB3MS, BoT_date, use_next = TRUE)

# Get rate on EoT_date
EoT_rate <- get_rate_on_date(TB3MS, EoT_date, use_next = FALSE)

Create Data Frame to display results

# Create data frame with the results
results <- data.frame(
  Date = c(BoT_rate$Date, EoT_rate$Date),
  Rate = c(BoT_rate$Rate, EoT_rate$Rate),
  Period = c("Beginning of Term", "End of Term")
)

# Display the results
print(results)

Compare the Rates

rate_change<- EoT_rate$Rate - BoT_rate$Rate
print(paste("The 13-week Treasury bill rate changed by", round(rate_change, 2), "percentage points over the term."))
[1] "The 13-week Treasury bill rate changed by -0.53 percentage points over the term."

Analysis of results

In this exercise we have performed a comparison of the short-term interest rate at the beginning of the school and at the end. When we calculate the change, we find that there has been a depreciation of the rates, with a change of -0.53 points. A fall in the T-bill rate may be caused by several factors, such as a fall in interest rates, deceleration of economic growth or even recessions or economic uncertainty which leads to higher demand in T-bills. Another interesting factor may be a general desire for liquid instruments to store value in the short term with minimal risk. Any of these reasons can lead to a decrease in the T-bill rates, and we are inclined to believe that in this case it has been caused by the fall of interest rates and a foreseeable further cut in rates by the FED.

L3.2 Why interest rates change over time.

Interest rates fluctuation is a broad phenomenon influenced by a really wide range of factors. However, the most important aspects can summarized in supply, demand and government policy. High demand (or low supply) of credit will lead to higher interest rates in money lending from banks and other institutions, making it more expensive to borrow. Oppositely, a low demand (or high supply) will lead to a decrease in interest rates, making borrowing money cheaper. The government (cor central bank) also has an influence in the fluctuations as it sets the target interest rates at which then banks loan between each other. This change in target rates further affect the rates at which the commercial banks lend money to their customers. Central banks can also acquire government debt to push the economy (increase supply and lower the demand) or vice versa.

It is important to acknowledge that the Central Banks use their monetary policy to influence the interest rates in the SHORT-TERM, but their policies can contribute to shape the inflation targets in the long term.

L4 Efficiency of market and information

Check if on 26 October 2017 coca cola shares were hit by the advarse information realize on the market. (assume 26 is the information realese date)

Load packages

library(quantmod)

Define dates

event_date <- as.Date("2017-10-26")
start_date <- event_date - 7
end_date <- event_date + 7

Retrieve Coca-Cola Data

ticker <- "KO"
getSymbols(Symbols = ticker, scr = "yahoo", from = start_date, to = end_date)
[1] "KO"
head(KO)
           KO.Open KO.High KO.Low KO.Close
2017-10-19   46.37   46.79  46.32    46.59
2017-10-20   46.58   46.59  46.28    46.38
2017-10-23   46.38   46.65  46.23    46.32
2017-10-24   46.26   46.29  45.95    46.18
2017-10-25   46.37   46.76  45.93    46.05
2017-10-26   46.32   46.75  46.22    46.23
           KO.Volume KO.Adjusted
2017-10-19   7515500    37.07839
2017-10-20   9646800    36.91126
2017-10-23   7153600    36.86351
2017-10-24   9539500    36.75209
2017-10-25  11994200    36.64863
2017-10-26  10569100    36.79188

Plot Closing prices

dev.new()
chartSeries(KO, name = "Coca-Cola (KO) Stock Price")

Plot with Trading Volume

# Plot closing prices with volume
chartSeries(KO, name = "Coca-Cola (KO) Stock Price with Volume", theme = chartTheme("white"), TA = "addVo()")

Calculate Daily Returns

# Calculate daily returns
KO_returns <- dailyReturn(Cl(KO))

# View the returns
KO_returns
           daily.returns
2017-10-19   0.000000000
2017-10-20  -0.004507385
2017-10-23  -0.001293691
2017-10-24  -0.003022439
2017-10-25  -0.002815095
2017-10-26   0.003908801
2017-10-27  -0.003460953
2017-10-30  -0.004558261
2017-10-31   0.002616636
2017-11-01  -0.003914752

Analyze the Return on 26 October 2017

# Get the return on the event date
event_return <- KO_returns[event_date]

# Print the return
print(event_return)
           daily.returns
2017-10-26   0.003908801

Compare with Market Index (S&P 500)

Retrieve S&P 500

# Retrieve S&P 500 data
getSymbols("^GSPC", src = "yahoo", from = start_date, to = end_date)
[1] "GSPC"
# Calculate daily returns for S&P 500
SP500_returns <- dailyReturn(Cl(GSPC))

Merge and Compare Returns

# Merge the returns
combined_returns <- merge(KO_returns, SP500_returns, join = "inner")
colnames(combined_returns) <- c("KO_Return", "SP500_Return")

# View combined returns
print(combined_returns)
              KO_Return  SP500_Return
2017-10-19  0.000000000  0.0000000000
2017-10-20 -0.004507385  0.0051168427
2017-10-23 -0.001293691 -0.0039724840
2017-10-24 -0.003022439  0.0016179083
2017-10-25 -0.002815095 -0.0046630498
2017-10-26  0.003908801  0.0012709462
2017-10-27 -0.003460953  0.0080730225
2017-10-30 -0.004558261 -0.0031924706
2017-10-31  0.002616636  0.0009444587
2017-11-01 -0.003914752  0.0015921102

Plot the Returns

# Load ggplot2 for plotting
if (!require("ggplot2")) {
  install.packages("ggplot2")
}
library(ggplot2)

# Prepare data for plotting
returns_df <- data.frame(Date = index(combined_returns), coredata(combined_returns))

# Melt the data frame for ggplot2
if (!require("reshape2")) {
  install.packages("reshape2")
}
library(reshape2)
returns_melted <- melt(returns_df, id.vars = "Date")

# Plot the returns
ggplot(returns_melted, aes(x = Date, y = value, color = variable)) +
  geom_line(size = 1) +
  labs(title = "Daily Returns: Coca-Cola vs. S&P 500",
       x = "Date",
       y = "Daily Return",
       color = "Legend") +
  geom_vline(xintercept = as.numeric(event_date), linetype = "dashed", color = "red") +
  theme_minimal()

Statistical Analysis

Calculate Z-score for Event Date Return

# Calculate mean and standard deviation excluding event date
mean_return <- mean(KO_returns[-which(index(KO_returns) == event_date)])
sd_return <- sd(KO_returns[-which(index(KO_returns) == event_date)])

# Calculate z-score
z_score <- (as.numeric(event_return) - mean_return) / sd_return

# Print z-score
print(paste("Z-score on", event_date, ":", round(z_score, 2)))
[1] "Z-score on 2017-10-26 : 2.62"

Analysis of results.

In this exercise we have performed an study on the Coca Cola shares movements on an specified event. In order to unveil the abnormal returns, we have first obtained the Coca cola (KO) data and we have specifically obtained the return on the event date. Afterwards, we have obtained the equivalent data from the S&P500 in order to compare the returns obtained by the market in the event date so as to determine whether the returns are determined by the adverse information regarding Coca Cola or if it was rather a generalized movement of the market as a whole.

When observing the graphic comparison between the S&P500 and the Coca Cola shares, we observe that their tendency matches quite fairly, so our first intuition will be that the information had no relevant effect on the Coca Cola. We can also observe that the Coca Cola Shares have a clear peak in the event date that is followed by a drastic fall in the daily returns.

However, in order to better assess the event and its effects, we have performed an statistical analysis with the Z-Score. To analyze the results of this statistical study we must know that if our Z-score is greater than 2 (|Z-Score| > 2) we will be able to affirm that the return is significantly different with a significance level of 5%. Furthermore if the Z-Score is greater than 3, we will be able to affirm that the return is significantly different with a significance level of 1%. In the present case, the Z-Score we obtained has a value of 2.62, which lead us to conclude that with a significance level of 5% (or with a confidence level of 95%), the daily returns have been significantly different.

This ultimately leads us to affirm within our confidence level that the adverse information that hit the Coca-Cola Shares has had an impact in its price, which can be backed up with the observance of the graphic in the event date as well as the trend that follows inmidiately afterwards.

L5 Financial statements and fundamental analysis

L5.0 Download to R the financial statements of Microsoft 2018, show the code

# Load necessary libraries
library(quantmod)
library(tidyr)    # For data manipulation and cleaning
library(finreportr)
library(XBRL)

# Set up the authority to EDGAR
options(HTTPUserAgent = "js137576@students.sgh.waw.pl") 

# Microsoft's CIK is 0000789019

# Get the list of available annual reports for Microsoft
annual_reports <- AnnualReports("0000789019", foreign = FALSE)

# View the available reports
print(annual_reports)

# Specify the year for which you want the financial data
report_year <- 2018

# Retrieve the income statement
income_statement <- GetIncome("MSFT", report_year)
Aviso: downloaded length 0 != reported length 355Aviso: cannot open URL 'https://www.sec.gov/Archives/edgar/data/789019/000156459018019062/https://xbrl.sec.gov/dei/2018/dei-2018-01-31.xsd': HTTP status was '404 Not Found'Error en fileFromCache(file): 
  Error in download.file(file, cached.file, quiet = !verbose) : 
  no fue posible abrir la URL 'https://www.sec.gov/Archives/edgar/data/789019/000156459018019062/https://xbrl.sec.gov/dei/2018/dei-2018-01-31.xsd'

L5.1 Identify the types of deposits that the commercial bank uses to obtain most of its funds.

JPMorgan Chase relies on two main types of deposits:

Noninterest-Bearing Deposits:

U.S. offices: $643.75 billion in 2023.

Non-U.S. offices: $23.1 billion.

Interest-Bearing Deposits:

U.S. offices: $1.303 trillion in 2023.

Non-U.S. offices: $430.74 billion.

These deposits include savings, demand, and time deposits. The majority of funding comes from consumer and wholesale operating deposits, which are considered stable sources of liquidity.

L5.2 Identify the main uses of funds by the bank.

JPMorgan Chase primarily uses its funds for:

Loans:

Total loans in 2023 amounted to $1.324 trillion, including consumer and commercial loans.

Investments:

Funds are allocated to securities portfolios for income generation and liquidity management.

Liquidity:

Significant cash reserves and high-quality liquid assets are maintained to meet obligations.

Acquisitions:

Investments in businesses, such as the acquisition of First Republic, align with strategic goals.

L5.3 Does it appear that the bank is attempting to enter the securities industry by offering securities services?

Yes, JPMorgan Chase is deeply involved in the securities industry through:

Investment Banking:

Raising equity and debt capital, corporate strategy advisory.

Securities Services:

Custody, fund administration, and securities lending.

L5.4 Does it appear that the bank is attempting to enter the insurance industry by offering insurance services?

JPMorgan Chase is not significantly expanding into traditional insurance markets but offers products like credit derivatives, which overlap with some insurance-like risk management functions.

L5.5 Assess the bank’s balance sheet for the gap between rate-sensitive assets and liabilities.

JPMorgan actively manages interest rate risk by aligning rate-sensitive assets (loans, securities) and liabilities (deposits, borrowings). Based on available data, the bank seems to maintain a balanced or slightly positive gap.

L5.6-L5.12 Financial Ratios

R Code for Calculations

The following R code computes these metrics:

# Load necessary libraries
library(readxl)
library(dplyr)
library(ggplot2)

# Load data
file_path <- "C:/Users/USUARIO/OneDrive/Documentos/0000019617-24-000225.xlsx"
balance_sheet <- read_excel(file_path, sheet = "consolidated balance sheet")
New names:
income_sheet <- read_excel(file_path, sheet = "income")
New names:
# Extract data
total_assets <- balance_sheet %>%
  filter(grepl("Total assets", `Column 1`)) %>%
  select(`2023`) %>%
  pull()
Error in `filter()`:
ℹ In argument: `grepl("Total assets",
  `Column 1`)`.
Caused by error:
! objeto 'Column 1' no encontrado
Backtrace:
  1. ... %>% pull()
 11. base::grepl("Total assets", `Column 1`)
 12. base::is.factor(x)

Visual representation

ggplot(results, aes(x = Metric, y = Value)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  theme_minimal() +
  labs(
    title = "Financial Ratios (L5.6 - L5.12)",
    x = "Metric",
    y = "Value (%)"
  )

Explanation of Metrics:

L5.6 Interest Income as % of Assets: Measures the efficiency of assets in generating interest income.

L5.7 Interest Expenses as % of Assets: Shows the cost of funding relative to asset size.

L5.8 Net Interest Margin: Indicates profitability from core banking operations after funding costs.

L5.11 Return on Assets (ROA): Reflects how well the bank uses assets to generate profit.

L5.12 Return on Equity (ROE): Measures the returns generated on shareholder equity.

L5.13 Impact of Rising Interest Rates

Increase Interest Income: Loans with variable rates will yield higher interest.

Increase Interest Expense: Deposits and borrowings will cost more, potentially compressing net interest margin.

L5.14 Impact of Deteriorating Economic Conditions

Increase in Loan Loss Provisions: Higher defaults on loans would raise credit costs.

Reduce in Non-interest Income: Lower activity in investment banking and asset management could hurt fee income.

L5.15- L5.19

The mutual fund chosen will be Vanguard 500 Index Fund (VFIAX)

L5.15 What is the investment objective of this mutual fund? Do you consider this mutual fund to have low risk, moderate risk, or high risk?

The Vanguard 500 Index Fund aims to track the performance of the S&P 500 Index, which represents 500 of the largest U.S. companies. Its objective is to provide investors with exposure to the large-cap segment of the U.S. equity market, focusing on long-term growth of capital and income from dividends.

This mutual fund is considered to have moderate risk. It is still subject to market risk inherent in equity investing.

L5.16 What was the return on the mutual fund last year? What was the average annual return over the last three years?

As of the end of 2022:

Return last year (2022): Approximately -18%, reflecting a downturn in the U.S. stock market. Average annual return over the last three years (2020-2022): Approximately 7% per year

L5.17 What is a key economic factor that influences the return on this mutual fund?

It is the overall performance of the U.S. stock market. Factors such as its stock market conditions, US interest rates and macroeconomic indicators affect noticeably.

L5.18 Must any fees be paid when buying or selling this mutual fund?

The Vanguard 500 Index Fund does not charge any sales loads when buying or selling shares. However, investors shall be aware of expense ratios and accounting service fees.

L5.19 What was the expense ratio for this mutual fund over the last year? Does this ratio seem high to you?

The expense ratio for the Vanguard 500 Index Fund is approximately 0.04%.

This ratio is considered very law compare to other mutual funds.

L5.20 - L5.22 Securities Firms

Securities Firm Selected: Goldman Sachs Group, Inc.

L5.20 What are the main types of business conducted by the securities firm?

Goldman Sachs Operates in several business segments such as Investment Banking, Global Markets, Asset Management and Consumer & Wealth Management.

L5.21 Summarize any statements made by the securities firm in its annual report about how it may be affected by existing or potential regulations.

Regulatory Environment: The firm operates under extensive regulations that affect its operations, capital requirements, and profitability.

Compliance Costs:leads higher operational costs.

Potential Regulations: Future changes could impact business activities.

Risk Management: Importance of rigorous risk management systems to navigate the complex regulatory landscape.

Goldman Sachs acknowledges that regulatory changes could limit certain business practices and require certain adjustments.

L5.22 Describe the recent performance of the securities firm, and explain why the performance has been favorable or unfavorable.

Mixed financial results

Strengths: investment banking revenue and asset management growth

Challenges: Global Markets Division and regulatory costs

Reasons for performance

Economic recovery and market volatility as favorable factors Interest rate Changes and geopolitical risks as unfavorable factors.

L6. Equity

Event Study on Apple Inc. (AAPL)

Objective:

To conduct an event study on Apple Inc. (AAPL) to analyze the impact of a significant corporate event on its stock returns.

Event Selection:

We will focus on Apple’s Q4 2020 earnings announcement, which took place on October 29, 2020.

Hypothesis:

The earnings announcement has a measurable impact on Apple’s stock price, resulting in abnormal returns around the event date.

Methodology:

Calculate daily stock returns for AAPL.

Create an event dummy variable to isolate the event’s effect.

Perform a regression analysis to estimate the abnormal return on the event date.

Extend the analysis to an event window to capture any pre- or post-event effects.

Assess the statistical significance of the results.

R Code Implementation

# Load required libraries
library(quantmod)
library(dplyr)
library(ggplot2)

# Define the ticker symbol and date range
ticker <- "AAPL"
start_date <- "2020-10-15"
end_date <- "2020-11-12"

# Get stock data
getSymbols(ticker, from = start_date, to = end_date)
[1] "AAPL"
# Define the event date
event_date <- "2020-10-29"

# Calculate daily log returns
AAPL_returns <- diff(log(Ad(get(ticker))))

# Create event dummy variable
event_dummy <- ifelse(index(AAPL_returns) == event_date, 1, 0)

# Perform regression analysis
event_study <- lm(AAPL_returns ~ event_dummy)

# Summarize the regression results
summary(event_study)

Call:
lm(formula = AAPL_returns ~ event_dummy)

Residuals:
      Min        1Q    Median        3Q 
-0.055158 -0.009375  0.000000  0.015734 
      Max 
 0.042514 

Coefficients:
             Estimate Std. Error t value
(Intercept) -0.002490   0.006051  -0.411
event_dummy  0.038870   0.026374   1.474
            Pr(>|t|)
(Intercept)    0.686
event_dummy    0.159

Residual standard error: 0.02567 on 17 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:  0.1133,    Adjusted R-squared:  0.06114 
F-statistic: 2.172 on 1 and 17 DF,  p-value: 0.1588

Notes con code

Calculating Daily Log Returns:

Ad(get(ticker)): Extracts the adjusted closing prices.

diff(log(…)): Calculates the daily log returns.

Creating the Event Dummy Variable:

Assigns a value of 1 to the event date and 0 to all other dates.

This dummy variable isolates the effect of the event on the stock returns.

Performing Regression Analysis:

Regresses the daily returns on the event dummy variable.

The coefficient of event_dummy represents the abnormal return on the event date.

Interpreting the Regression Results

Coefficient of event_dummy:

Represents the abnormal return attributed to the event.

A significant positive coefficient suggests a favorable market reaction.

A significant negative coefficient indicates an unfavorable reaction.

Statistical Significance:

Check the p-value associated with the event_dummy coefficient.

A p-value less than 0.05 typically indicates statistical significance at the 5% level.

Conclusions.

As our p-value is 0.1588, we do not have sufficient data to conclude that there is statistical significance at a confidence level of 95% (or significance level of 5%). This means that we cannot determine that there has been an abnormal event at the event date.

Extended Event Window Analysis

To capture potential market reactions before and after the event, we extend the analysis to an event window.

# Define event window (e.g., -2 to +2 days around the event date)
event_window <- c(-2, 2)

# Get the numeric position of the event date in the returns index
event_pos <- match(as.Date(event_date), index(AAPL_returns))

# Define the start and end positions of the event window
w_beg <- event_pos + event_window[1]
w_end <- event_pos + event_window[2]

# Adjust event_dummy to mark the event window
event_dummy_window <- rep(0, length(AAPL_returns))
event_dummy_window[w_beg:w_end] <- 1

# Calculate cumulative abnormal returns (CAR)
CAR <- sum(AAPL_returns * event_dummy_window)

# Perform t-test to assess significance
# Calculate standard deviation of returns in the event window
event_window_returns <- AAPL_returns[w_beg:w_end]
std_dev <- sd(event_window_returns)

# Calculate t-statistic
t_stat <- CAR / (std_dev * sqrt(length(event_window_returns)))

# Degrees of freedom
df <- length(event_window_returns) - 1

# Calculate p-value
p_value <- 2 * pt(-abs(t_stat), df = df)

# Print results
cat("Cumulative Abnormal Return (CAR):", CAR, "\n")
Cumulative Abnormal Return (CAR): NA 
cat("t-statistic:", t_stat, "\n")
t-statistic: NA 
cat("p-value:", p_value, "\n")
p-value: NA 

Extended window analysis

Although we have followed the steps to perform the extended window analysis we have encountered a yet unknown mistake which had led us to not obtain any value. This extended window is supposed to analyse other market reactions that have happened within a range from the event window. Had we obtained any results, we could have derived that in some nearby dates there had been an event or that the event had been one that had extended over a series of dates.

Cumulative Abnormal Return

Represents the total abnormal return over the event window.

A positive CAR suggests that the event had a favorable impact on stock returns.

A negative CAR indicates an unfavorable impact.

As described before, the lack of results lead us to no further comments.

Interpretation:

The p-value is greater than 0.05:

We fail to reject the null hypothesis.

Conclude that there is no statistically significant evidence that the event affected the stock price.

Final Remarks

Earnings announcements

They often lead to increased volatility and can significantly impact stock prices depending on whether the results meet, exceed, or fall short of market expectations.

Limitations:

The analysis assumes that the market is efficient and that any abnormal returns are solely due to the event.

External factors (e.g., macroeconomic news, industry trends) could also influence stock returns during the event window.

Data Constraints: The analysis is based on historical data up to November 12, 2020. Results might differ with updated data.

Recommendations:

Include Control Variables: Incorporate market or industry returns to control for broader market movements.

Robust Statistical Tests: use more sophisticated models (e.g., Market Model) to estimate expected returns and abnormal returns.

L7.1 - L7.2. Comparing yields among securities

Explanations ahead

In this two exercises we will discuss securities’ yields. We will now explain what is a security.

Securities

A financial security is a category that englobes different a wide range of investments. There are three main types: equity, debt and hybrids. Securities can be traded both publicly and over-the-counter. When talking about securities we shall take into account concepts such as IPOs, which constitute the first sell of securities to the public. Securities can also be offered in private placements and ultimately in the secondary markets, OTC and private and direct negotiations.

Yields

Yields refer to the earnings generated by an investment, and it can take the form of dividends or interest. In the present case, when we talk about the Yield it will adopt the form of interest.

L7.1 What is the difference between the yield on corporate high-quality bonds and the yield on Treasury bonds at the end of the school term? Explain why does the difference exist?

R code for demonstration

load packages

library(quantmod)

Define EoT_date

# Define End of Term (EoT) date
EoT_date <- as.Date("2024-09-30")

Retrieve Treasury Bond Yield Data

# Retrieve 10-Year Treasury yield data
getSymbols("DGS10", src = "FRED", from = EoT_date - 7, to = EoT_date + 7)
[1] "DGS10"
# View the data
head(DGS10)
           DGS10
2024-09-23  3.75
2024-09-24  3.74
2024-09-25  3.79
2024-09-26  3.79
2024-09-27  3.75
2024-09-30  3.81

Retrieve Coporate High-Quality Bond Yield Data

# Retrieve Moody's Aaa Corporate Bond yield data
getSymbols("DAAA", src = "FRED", from = EoT_date - 7, to = EoT_date + 7)
[1] "DAAA"
# View the data
head(DAAA)
           DAAA
2024-09-23 4.66
2024-09-24 4.66
2024-09-25 4.72
2024-09-26 4.71
2024-09-27 4.69
2024-09-30 4.72

Adjust to Non-Trading Days

# Function to get yield on a specific date
get_yield_on_date <- function(data, date) {
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Get available dates on or before the specified date
  available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Yield = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  # Get the yield
  yield <- as.numeric(data[date_used])
  
  return(list(
    Yield = yield,
    Date = as.Date(date_used)
  ))
}

Retrieve Yields on EoT_date

# Get Treasury yield on EoT_date
treasury_yield <- get_yield_on_date(DGS10, EoT_date)

# Get Corporate Aaa yield on EoT_date
corporate_yield <- get_yield_on_date(DAAA, EoT_date)

Calculate the Difference

# Calculate the yield difference
yield_difference <- corporate_yield$Yield - treasury_yield$Yield

# Display the results
results_L71 <- data.frame(
  Date = treasury_yield$Date,
  Treasury_Yield = treasury_yield$Yield,
  Corporate_Yield = corporate_yield$Yield,
  Yield_Difference = yield_difference
)

print(results_L71)

Analysis of results

In this exercise we have obtained the Yields of two different Bonds with the help of our R code, in which we have retrieved the Yields from the 10-Year US Treasury bond and the Moody’s Seasoned Aaa Corporate Bond Yield. When we compare these two bonds, we shall foresee that the Corporate Bond Yield will most likely be higher than the Treasury Bond. Even though the corporate yield offers high quality and has a high rating, the treasury bonds are overall less risky and offer a much more stable option. When an investor decides to buy a corporate bond over a government bond (this is another way of naming the treasury bonds), they make an assessment of the risk level they will be open to tolerate and the returns they will obtain from it. As a general rule, the higher returns will be paired with higher volatility (risk).

L7.2 What is the difference between the yield on long-term Treasury bonds and the yield on long-term municipal bonds at the end of the school term? Explain why does the difference exist?

Municipal bonds are a type of security issued by local county and state governments. This is a debt security which is often used to finance local projects. However, data availability for these types of bonds are not easily available, and we cannot obtain the Data about their yields.

Given the lack of data, we cannot perform a real representation, but we may suppose that municipal bonds will have higher yields than long-term Treasury Bonds. Municipal Bonds are usually exent from taxation, which provides an absolute yield really attractive for investors. If we also analyze briefly the macroeconomic situation of the US, the cut in FED rate should produce an increase in yields for the longer duration bonds. Additionally, the current strength of the US economy with the recent win of Donald Trump has produced an spike in long-term yields. However, paying attention to recent news regarding municipal bonds, their main attractiveness which is their tax exemptions may be facing the risk of being suppressed. Were this to happen, municipal bonds may be greatly affected.

L7.3 - L7.6 Assessing the forecasting ability of the yield curve

L7.3 - L7.5

Load packages

library(quantmod)
library(lubridate)
library(ggplot2)

Define BoT_date

# Define Beginning of Term (BoT) date
BoT_date <- as.Date("2024-05-01")

Date Range

# Define the date range
start_date <- BoT_date - 7  # One week before
end_date <- BoT_date + 7    # One week after

Retrieve 13week and 26 week T-bill Yield Data 13-week tbill symbol: “DGS3MO” 26-week tbill symbol: “DGS6MO” We are using the daily yield data for the constant maturity rate, as no data was to be found and used otherwise

# Retrieve 13-week T-bill yield data
getSymbols("DGS3MO", src = "FRED", from = start_date, to = end_date)
[1] "DGS3MO"
# Retrieve 26-week T-bill yield data
getSymbols("DGS6MO", src = "FRED", from = start_date, to = end_date)
[1] "DGS6MO"

Merge Yields into one data frame and converting it to plot

# Merge the yields into one data frame
yields_data <- merge(DGS3MO, DGS6MO, join = "inner")
colnames(yields_data) <- c("Yield_13wk", "Yield_26wk")
# Convert to data frame for plotting
yields_df <- data.frame(Date = index(yields_data), coredata(yields_data))

# Remove rows with NA values
yields_df <- na.omit(yields_df)

#Plot Yields over time
# Plot the yields over time
ggplot(yields_df, aes(x = Date)) +
  geom_line(aes(y = Yield_13wk, color = "13-week T-bill")) +
  geom_line(aes(y = Yield_26wk, color = "26-week T-bill")) +
  geom_vline(xintercept = as.numeric(as.Date(BoT_date)), linetype = "dashed", color = "red") +
  labs(
    title = "13-week and 26-week T-bill Yields Around BoT_date",
    x = "Date",
    y = "Yield (%)",
    color = "T-bill Maturity"
  ) +
  theme_minimal()

Adjust to Non-Trading Days

get_yield_on_date <- function(data, date) {
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Get available dates on or before the specified date
  available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Yield = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  # Get the yield
  yield <- as.numeric(data[date_used])
  
  return(list(
    Yield = yield,
    Date = as.Date(date_used)
  ))
}

Retrieve Yields on BoT_date

# Get 13-week T-bill yield on BoT_date
yield_13wk <- get_yield_on_date(DGS3MO, BoT_date)

# Get 26-week T-bill yield on BoT_date
yield_26wk <- get_yield_on_date(DGS6MO, BoT_date)

Calculate the Difference

# Calculate the yield difference
yield_difference = yield_26wk$Yield - yield_13wk$Yield

# Create a data frame to display the results
results_L73 <- data.frame(
  Date = yield_13wk$Date,
  Yield_13wk = yield_13wk$Yield,
  Yield_26wk = yield_26wk$Yield,
  Yield_Difference = yield_difference
)

print(results_L73)
NA

Additionally, we can plot our results in order to have a visual representation

# Create a data frame for plotting the yield curve
yield_curve_df <- data.frame(
  Maturity = c(13/52, 26/52),  # Convert weeks to years
  Yield = c(yield_13wk$Yield, yield_26wk$Yield)
)

# Plot the yield curve between 13-week and 26-week T-bills
ggplot(yield_curve_df, aes(x = Maturity, y = Yield)) +
  geom_line(color = "blue") +
  geom_point(color = "red", size = 3) +
  labs(
    title = paste("Yield Curve between 13-week and 26-week T-bills on", BoT_date),
    x = "Maturity (Years)",
    y = "Yield (%)"
  ) +
  theme_minimal()

Analysis of results

In these 3 exercises we have calculated the difference in yields of the 26-week T-bill yield and the 13-week T-bill yield at the beginning of the school term. The difference between both yields gives us a total amount of -0.03, which reveals a higher yield in the 13-week T-bill.

Higher yields on lower maturity bonds is a rather unsual situation, but it can be explained due to several factors. This higher yield may be the result of market uncertainty, in which investors look for safer and long-term securities.

On the other hand, and answering to L7.5, this may be the result of the expectancy of a FED’s rate cut, which would lead to even lower yields. This reason would also explain the higher yields in the short term. The expectancy of lower interest rates matches the direction of the slope.

Some other reasons may be plausible, such as those regarding liquidity needs or technical market factors, but we will not further analyze those options.

L7.6 Did interest rates move in that direction over the school term?

Load packages

library(quantmod)
library(lubridate)
library(reshape2)
library(ggplot2)
library(xts)

Define End of Term Date

#Define BoT_date
BoT_date <- as.Date("2024-05-01")
# Define End of Term (EoT) date
EoT_date <- as.Date("2024-09-30")

Retrieve Yield Data Over the term

# Retrieve 13-week T-bill yield data over the term
getSymbols("TB3MS", src = "FRED", from = BoT_date, to = EoT_date)
[1] "TB3MS"
TB3MS_term <- TB3MS

# Retrieve 26-week T-bill yield data over the term
getSymbols("TB6MS", src = "FRED", from = BoT_date, to = EoT_date)
[1] "TB6MS"
TB6MS_term <- TB6MS

Adjust to Non-Trading Days

# Function to get yield on a specific date
get_yield_on_date <- function(data, date, use_next = FALSE) {
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  if (use_next) {
    # Get the next available date after the specified date
    available_dates <- index(data)[index(data) >= date & !is.na(data[index(data)])]
    if(length(available_dates) == 0) {
      warning(paste("No data available after", date))
      return(list(Yield = NA, Date = NA))
    }
    date_used <- min(available_dates)
  } else {
    # Get the last available date on or before the specified date
    available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
    if (length(available_dates) == 0) {
      warning(paste("No data available before", date))
      return(list(Yield = NA, Date = NA))
    }
    date_used <- max(available_dates)
  }
  
  # Get the yield
  yield <- as.numeric(data[date_used])
  
  return(list(
    Yield = yield,
    Date = as.Date(date_used)
  ))
}

Plot the yields over time

# Combine the yields into one data frame
yields_combined <- merge(TB3MS_term, TB6MS_term)
colnames(yields_combined) <- c("Yield_13wk", "Yield_26wk")

# Plot the yields over the term
yields_df <- data.frame(Date = index(yields_combined), coredata(yields_combined))
yields_df <- na.omit(yields_df)

# Melt the data for plotting
yields_melted <- melt(yields_df, id.vars = "Date")

# Plot
ggplot(yields_melted, aes(x = Date, y = value, color = variable)) +
  geom_line(linewidth = 1) +
  labs(title = "13-week and 26-week T-bill Yields Over the Term",
       x = "Date",
       y = "Yield (%)",
       color = "Yield") +
  theme_minimal()

Analyze the Movement of Interest Rates

#Get Yields at BoT_date
yield_13wk <- get_yield_on_date(TB3MS_term, BoT_date, use_next = FALSE)
yield_26wk <- get_yield_on_date(TB6MS_term, BoT_date, use_next = FALSE)

# Get yields at EoT_date
yield_13wk_EoT <- get_yield_on_date(TB3MS_term, EoT_date, use_next = FALSE)
yield_26wk_EoT <- get_yield_on_date(TB6MS_term, EoT_date, use_next = FALSE)

# Create a data frame to compare BoT and EoT yields
comparison_df <- data.frame(
  Date = c(yield_13wk$Date, yield_13wk_EoT$Date),
  Yield_13wk = c(yield_13wk$Yield, yield_13wk_EoT$Yield),
  Yield_26wk = c(yield_26wk$Yield, yield_26wk_EoT$Yield),
  Period = c("BoT", "EoT")
)

print(comparison_df)

Analysis of results

Interest rates, as we have represented graphically, yields over the term have fallen progressively. A decrease in yields indicates a downward movement in the interest rates. This movement matches the expectation we had extracted in the Beginning of Term, which was the decrease in yields/interest rates. Furthermore, yet again we have lower yields in the 13-week t-bill, which may indicate still further decreases in interest rates. This data matches with the FED rate cut in mid September, and the a positive forecast of further rate cuts.

L7.7 - L7.9 Explaining shifts in the yield curve over time

L7.7 Difference between the long-term Treasury bond yield and the 13-week T-bill yield at the beginning of the school term

Load Packages

library(quantmod)

Define Beginning of Term Date

# Define Beginning of Term (BoT) date
BoT_date <- as.Date("2024-05-01")

Retrieve the Yield Data

# Retrieve 3-Month T-bill yield data
getSymbols("DGS3MO", src = "FRED", from = BoT_date - 7, to = BoT_date + 7)
[1] "DGS3MO"
# Retrieve 10-Year Treasury yield data
getSymbols("DGS10", src = "FRED", from = BoT_date - 7, to = BoT_date + 7)
[1] "DGS10"

Adjust for Non-Trading Dates

# Function to get yield on a specific date
get_yield_on_date <- function(data, date) {
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Get available dates on or before the specified date
  available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Yield = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  # Get the yield
  yield <- as.numeric(data[date_used])
  
  return(list(
    Yield = yield,
    Date = as.Date(date_used)
  ))
}

Retrieve Yields on BoT_date

# Get 3-Month T-bill yield on BoT_date
yield_3mo_BoT <- get_yield_on_date(DGS3MO, BoT_date)

# Get 10-Year Treasury yield on BoT_date
yield_10yr_BoT <- get_yield_on_date(DGS10, BoT_date)

Calculate the Difference

# Calculate the yield difference
yield_difference_BoT <- yield_10yr_BoT$Yield - yield_3mo_BoT$Yield

# Create a data frame to display the results
results_L77 <- data.frame(
  Date = yield_3mo_BoT$Date,
  Yield_3mo = yield_3mo_BoT$Yield,
  Yield_10yr = yield_10yr_BoT$Yield,
  Yield_Difference = yield_difference_BoT
)

print(results_L77)

Analysis of results

The difference between the long-term Treasury Bond Yield and the 13-week treasury bond yield was a total of -0.83. A lower yield on the short term treasury bond

L7.8. Difference Between Long-Term Treasury Bond Yield and 13-week T-bill Yield at End of Term

Define End of Term Date

# Define End of Term (EoT) date
EoT_date <- as.Date("2024-09-30")

Retrieve the Yield Data

# Retrieve 3-Month T-bill yield data
getSymbols("DGS3MO", src = "FRED", from = EoT_date - 7, to = EoT_date + 7)
[1] "DGS3MO"
# Retrieve 10-Year Treasury yield data
getSymbols("DGS10", src = "FRED", from = EoT_date - 7, to = EoT_date + 7)
[1] "DGS10"

Adjust to Non-Trading Days

# Function to get yield on a specific date
get_yield_on_date <- function(data, date) {
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Get available dates on or before the specified date
  available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Yield = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  # Get the yield
  yield <- as.numeric(data[date_used])
  
  return(list(
    Yield = yield,
    Date = as.Date(date_used)
  ))
}

Retrieve the Yields on EoT_date

# Get 3-Month T-bill yield on EoT_date
yield_3mo_EoT <- get_yield_on_date(DGS3MO, EoT_date)

# Get 10-Year Treasury yield on EoT_date
yield_10yr_EoT <- get_yield_on_date(DGS10, EoT_date)

Calculate the Difference

# Calculate the yield difference
yield_difference_EoT <- yield_10yr_EoT$Yield - yield_3mo_EoT$Yield

# Create a data frame to display the results
results_L78 <- data.frame(
  Date = yield_3mo_EoT$Date,
  Yield_3mo = yield_3mo_EoT$Yield,
  Yield_10yr = yield_10yr_EoT$Yield,
  Yield_Difference = yield_difference_EoT
)

print(results_L78)

L7.9. Describe How the Yield Curve Changed Over the School Term

Comparison of Results

# Create a data frame to compare BoT and EoT yields
comparison_df <- data.frame(
  Date = c(yield_3mo_BoT$Date, yield_3mo_EoT$Date),
  Yield_3mo = c(yield_3mo_BoT$Yield, yield_3mo_EoT$Yield),
  Yield_10yr = c(yield_10yr_BoT$Yield, yield_10yr_EoT$Yield),
  Yield_Difference = c(yield_difference_BoT, yield_difference_EoT),
  Period = c("BoT", "EoT")
)

print(comparison_df)

Yield Difference

#Yield difference between the 10-year Treasury Bond and the 3-month T-bill in BoT_date
round(yield_difference_BoT, 2) #Difference in percentage points
[1] -0.83
#Yield difference between the 10-year Treasury Bond and the 3-month T-bill in EoT_date
round(yield_difference_EoT, 2)
[1] -0.92

Analysis of results

From the answers of L7.7 to L7.9 we have obtained that the difference in yields at the beginning of term was -0.83 and at the end of term was -0.92. In both cases, the higher yield in the shorter-term treasury bonds and the decreasing yields indicate an accordingly fall in the interest rates and an expectancy for further decreases in interest rates.

Monetary policies and market expectancy crucially alter the behaviour of the bond yields, as investors try to adapt to the market fluctuations and position themselves for the future situation. The interest rates, as we have explained, leads to the acceptance of lower yields in the long-term treasury bonds as they are expected to fall even more.

L7.10 - L7.11

L7.10 Did the Fed change the federal funds rate over the school term?

To determine if there was a change in federal funds rate over the school term we can analyze the data from he Federal Reserve Economic Data (FRED) database

library(quantmod)

# Define the start and end dates
start_date <- as.Date("2024-05-01")
end_date <- as.Date("2024-09-30")

# Get the Effective Federal Funds Rate (daily frequency) data from FRED
getSymbols("DFF", src = "FRED")
[1] "DFF"
# Subset the data for the specified period
fed_funds_daily <- window(DFF, start = start_date, end = end_date)

# Check if data is available for the end date
if (end_date %in% index(fed_funds_daily)) {
  print("Data is available for the end date.")
} else {
  print("Data is not available for the end date. Using the last available date.")
  actual_end_date <- tail(index(fed_funds_daily), 1)
  print(paste("Last available date in data:", actual_end_date))
}
[1] "Data is available for the end date."
# Plot the data with adjusted y-axis limits
min_rate <- min(fed_funds_daily, na.rm = TRUE)
max_rate <- max(fed_funds_daily, na.rm = TRUE)
y_min <- min_rate - 0.01  # Subtracting 0.01%
y_max <- max_rate + 0.01  # Adding 0.01%

plot(fed_funds_daily, type = "o", pch = 20, col = "blue",
     main = "Effective Federal Funds Rate (May 2023 - September 2023)",
     ylab = "Interest Rate (%)", ylim = c(y_min, y_max))
grid()

The Fed lowered the target rate in response to economic conditions that warranted a more accommodative monetary policy. This change was aimed at stimulating economic activity amid signs of slowing growth, declining inflation, or other financial challenges facing the economy during that period.

L7.11 Do you think the movements in interest rates over the school term were caused by the Fed’s monetary policy? Explain.

Yes, the movements in interest rates over the school term were significantly influenced by the Fed’s monetary policy actions. Here’s why:

Direct Impact of fed rates

Short-term rates reduced. Expansionary monetary policy.

Market expectations and Reactions

Transmission to Longer-Term Rates

Yield Curve Effects: A rate cut can lead to lower yields on medium and long-term securities as investors adjust their portfolios in response to the new rate environment.

Inflation Expectations: Lower interest rates can influence expectations of future inflation, which in turn affect long-term interest rates.

Economic Indicators

Stimulating Borrowing and Spending Declining industrial production and consumer spending

GLobal Economic Factors

Global economic slowdowns can prompt lower rates.

L7.12 - L7.13

L7.12 Difference Between 90-Day Commercial Paper Yield and 13-week T-bill Yield at End of Term

Load packages

library(quantmod)

Define the Beginning and End of Term Dates

# Define Beginning of Term (BoT) and End of Term (EoT) dates
BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

Retrieve Yield Data

# Retrieve 3-Month Commercial Paper yield data
getSymbols("CPF3M", src = "FRED", from = BoT_date - 7, to = EoT_date + 7)
[1] "CPF3M"
# Retrieve 3-Month Treasury Constant Maturity Rate data
getSymbols("DGS3MO", src = "FRED", from = BoT_date - 7, to = EoT_date + 7)
[1] "DGS3MO"

Adjust to Non-Trading Days

# Function to get yield on a specific date
get_yield_on_date <- function(data, date) {
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Get available dates on or before the specified date
  available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Yield = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  # Get the yield
  yield <- as.numeric(data[date_used])
  
  return(list(
    Yield = yield,
    Date = as.Date(date_used)
  ))
}

Retrieve Yields on EoT_date

# Get 90-Day Commercial Paper yield on EoT_date
yield_CP_EoT <- get_yield_on_date(CPF3M, EoT_date)

# Get 13-week T-bill yield on EoT_date
yield_TBill_EoT <- get_yield_on_date(DGS3MO, EoT_date)

Calculate the Premium at EoT

# Calculate the yield premium
premium_EoT <- yield_CP_EoT$Yield - yield_TBill_EoT$Yield

# Create a data frame to display the results
results_L712 <- data.frame(
  Date = yield_TBill_EoT$Date,
  Yield_Commercial_Paper = yield_CP_EoT$Yield,
  Yield_T_Bill = yield_TBill_EoT$Yield,
  Premium = premium_EoT
)

print(results_L712)

Analysis of results

In this exercise we are comparing the yields of a commercial paper against a T-bill. As we have already explained previous sections, the T-bills are issued by the US government and are considered risk-free. Given that the commercial papers do not offer such a safe risk profile, the higher risk must be compensated with higher yields. This premium may fluctuate given some economic factors related to stability and uncertainty.

L7.13 Compare the Premium at Beginning and End of Term

Retrieve the Yields on BoT_date

# Get 90-Day Commercial Paper yield on BoT_date
yield_CP_BoT <- get_yield_on_date(CPF3M, BoT_date)

# Get 13-week T-bill yield on BoT_date
yield_TBill_BoT <- get_yield_on_date(DGS3MO, BoT_date)

Calculate the Premium at BoT

# Calculate the yield premium at BoT
premium_BoT <- yield_CP_BoT$Yield - yield_TBill_BoT$Yield

# Create a data frame to display the results
results_L713 <- data.frame(
  Date = yield_TBill_BoT$Date,
  Yield_Commercial_Paper = yield_CP_BoT$Yield,
  Yield_T_Bill = yield_TBill_BoT$Yield,
  Premium = premium_BoT
)

print(results_L713)

Compare the Premiums

# Create a comparison data frame
comparison_premiums <- data.frame(
  Date = c(yield_TBill_BoT$Date, yield_TBill_EoT$Date),
  Period = c("BoT", "EoT"),
  Yield_Commercial_Paper = c(yield_CP_BoT$Yield, yield_CP_EoT$Yield),
  Yield_T_Bill = c(yield_TBill_BoT$Yield, yield_TBill_EoT$Yield),
  Premium = c(premium_BoT, premium_EoT)
)

print(comparison_premiums)

Change in Premium

#Premium increase/decrease in % points
premium_change <- round(premium_BoT, 2) - round(premium_EoT, 2)
print(premium_change)
[1] -0.26

Analysis of results

In this exercise we have taken the premiums at BoT and EoT and we have portrayed the comparison in a data.frame. From the results, we have observed that both yields have decreased over time. However, the corporate yield has decreased less than the T-bill, which has led to a final premium of 0.13 in favour for the commercial paper. These effects may have been caused by positive results and the already studied decrease in interest rates that caused the decrease of the t-bill yields. We must mention that the initial situation, in which the T-bill yield is higher than the commercial paper is abnormal, as usually t-bill yields contain a low risk profile and generally lower than the commercial yields, which offer higher yields and higher risk.

L7.14 to L7.17

Define Beginning and End of Term dates

# Define Beginning of Term (BoT) and End of Term (EoT) dates
BoT_date <- as.Date("2023-05-01")
EoT_date <- as.Date("2023-09-30")

L7.14. Difference Between Yields on High-Yield and High-Quality Corporate Bonds

Load packages

library(quantmod)

Retrieve Yield Data

# Retrieve Moody's Aaa Corporate Bond Yield (High-Quality)
getSymbols("DAAA", src = "FRED", from = BoT_date - 7, to = BoT_date + 7)
[1] "DAAA"
# Retrieve ICE BofA US High Yield Index Effective Yield (High-Yield)
getSymbols("BAMLH0A0HYM2EY", src = "FRED", from = EoT_date - 7, to = EoT_date + 7)
[1] "BAMLH0A0HYM2EY"

Define a Function to Get Yields on Specific Dates

# Function to get yield on a specific date
get_yield_on_date <- function(data, date) {
  # Convert index to Date format
  index(data) <- as.Date(index(data))
  
  # Get available dates on or before the specified date
  available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Yield = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  # Get the yield
  yield <- as.numeric(data[date_used])
  
  return(list(
    Yield = yield,
    Date = as.Date(date_used)
  ))
}

Retrieve Data on Specific Dates

# Get High-Quality Corporate Bond Yield on BoT_date
yield_HQ_BoT <- get_yield_on_date(DAAA, BoT_date)

# Get High-Yield Corporate Bond Yield on EoT_date
yield_HY_EoT <- get_yield_on_date(BAMLH0A0HYM2EY, EoT_date)

Calculate the Difference

Yield difference represents the change between the high-yield corporate bond yield at the end of the term and the high-quality corporate bond yield at the beginning of the term

A positive difference indicates that the high-yield bond yield at EoT is higher than the high-quality bond yield at BoT

# Calculate the yield difference
yield_difference_L714 <- yield_HY_EoT$Yield - yield_HQ_BoT$Yield

# Create a data frame to display the results
results_L714 <- data.frame(
  Description = c("High-Quality Corporate Bond Yield at BoT", "High-Yield Corporate Bond Yield at EoT"),
  Date = c(yield_HQ_BoT$Date, yield_HY_EoT$Date),
  Yield = c(yield_HQ_BoT$Yield, yield_HY_EoT$Yield)
)

print(results_L714)
cat("Yield Difference (High-Yield - High-Quality):", round(yield_difference_L714, 2), "%\n")
Yield Difference (High-Yield - High-Quality): 4.19 %

Analysis of results

We can observe a difference of 4.19 which reflects that the high-yield will result in higher returns compared to the high quality. This results are explained due to the already explained dynamics in which the riskier the investment, the higher its return will be. In the high-quality bonds we prioritize minimizing the risk at expense of a lower yield, whereas in the high-yield we will accept a higher risk for a higher expected return.

L7.15 Change in Long-Term Treasury Bond Yield and Impact on Bond Prices

Retrieve Yield Data

# Retrieve 10-Year Treasury Yield data
getSymbols("DGS10", src = "FRED", from = BoT_date - 7, to = EoT_date + 7)
[1] "DGS10"

Retrieve Yields on Specified Dates

# Get 10-Year Treasury Yield on BoT_date
yield_10yr_BoT <- get_yield_on_date(DGS10, BoT_date)

# Get 10-Year Treasury Yield on EoT_date
yield_10yr_EoT <- get_yield_on_date(DGS10, EoT_date)

Calculate the Change in Yield

# Calculate the change in yield
yield_change_L715 <- yield_10yr_EoT$Yield - yield_10yr_BoT$Yield

# Create a data frame to display the results
results_L715 <- data.frame(
  Date = c(yield_10yr_BoT$Date, yield_10yr_EoT$Date),
  Period = c("BoT", "EoT"),
  Yield_10yr_Treasury = c(yield_10yr_BoT$Yield, yield_10yr_EoT$Yield)
)

print(results_L715)
cat("Change in 10-Year Treasury Yield (EoT - BoT):", round(yield_change_L715, 2), "%\n")
Change in 10-Year Treasury Yield (EoT - BoT): 1 %

Analysis of results

The bond prices follow an inverse relationship with the bond yields. Therefore, as we have calculated an appreciation in the yield of a 1%, we may derive that the price has decreased over the term.

L7.16 Comparing Changes in Yields of Treasury, Municipal, and Corporate Bonds

Retrieve Yield Data

# Retrieve Treasury Yield data
getSymbols("DGS10", src = "FRED", from = BoT_date - 7, to = EoT_date + 7)
[1] "DGS10"
# Retrieve Corporate Bond Yield data
getSymbols("DAAA", src = "FRED", from = BoT_date - 7, to = EoT_date + 7)
[1] "DAAA"
# Attempt to Retrieve Municipal Bond Yield data
# Note: Municipal bond data is limited on FRED; we may need to use available proxies or acknowledge limitations.
#getSymbols("MUNI10Y", src = "FRED", from = BoT_date - 7, to = EoT_date + 7) #WE ARE NOT ABLE TO FIND ANY DATA ON MUNICIPAL BONDS

Analysis of results

As we have mentioned earlier, we have found certain issued to retrieve municipal bonds data. However, we can determine from what has been analyzed so far in previous answers that bond yields have fallen over the course of the school term, primarily due to the fall in interest rates and the expectancy of further rate cuts. Other factors such as inflation and overall economic conditions also affect this movements.

L7.17 Change in Premium on High-Yield Corporate Bonds Relative to Treasury Bonds

Retrieve High Yield Corporate Bond Yield on BoT_date

# Retrieve High-Yield Corporate Bond Yield data for BoT_date
getSymbols("BAMLH0A0HYM2EY", src = "FRED", from = BoT_date - 7, to = BoT_date + 7)
[1] "BAMLH0A0HYM2EY"
# Get High-Yield Corporate Bond Yield on BoT_date
yield_HY_BoT <- get_yield_on_date(BAMLH0A0HYM2EY, BoT_date)
#Get Yield on Treasury bond on BoT_date and EoT_date
yield_Treasury_BoT <- get_yield_on_date(DGS10, BoT_date)
yield_Treasury_EoT <- get_yield_on_date(DGS10, EoT_date)

Calculate Premiums

# Premium at BoT
premium_BoT <- yield_HY_BoT$Yield - yield_Treasury_BoT$Yield

# Premium at EoT
premium_EoT <- yield_HY_EoT$Yield - yield_Treasury_EoT$Yield

Compare Premiums

# Create a data frame to display the results
results_L717 <- data.frame(
  Date = c(yield_Treasury_BoT$Date, yield_Treasury_EoT$Date),
  Period = c("BoT", "EoT"),
  Yield_High_Yield_Corporate = c(yield_HY_BoT$Yield, yield_HY_EoT$Yield),
  Yield_Treasury = c(yield_Treasury_BoT$Yield, yield_Treasury_EoT$Yield),
  Premium = c(premium_BoT, premium_EoT)
)

print(results_L717)

Change in premiums

#Change in premium expressed in percentage points
change_in_premium <- round(premium_EoT, 2) - round(premium_BoT)
cat("change in premium:", change_in_premium)
change in premium: -0.79

Analysis of returns

In this last exercise of this section, we have calculated the premium of high yield corporate bonds against the treasury bond yields. As we know, high-yields will have higher risk and higher expected returns. The premium has fallen 0.79 points during the school term, which may indicate a reduction of credit risk and an overall improvement in the economy. This means that there is less risk of not getting non-payments, and as we know, with lower risks we shall obtain lower expected returns or yields. Investors necessities or preferences and their shifts may also have an impact on the premiums as the general risk tolerance fluctuate in the market.

L8 Portfolio - Markovitz

Replicate the basic idea of the portfolio case

Markowitz Portfolio Theory

Although it will be explained in further detail in the next question, we can introduce the Markowitz theory as a portfolio selection strategy that seeks to maximize the expected return for a given risk (or to find the minimum risk for a given return). This method considers total risk, that is systematic and specific risk.

R code for demonstration

Load Required Packages

# Install required packages if not already installed
if (!require("PerformanceAnalytics")) {
  install.packages("PerformanceAnalytics")
}
library(quantmod)
library(PerformanceAnalytics)

Retrieve Historical Stock Data

# Define stock symbols
symbols <- c("AMZN", "TSLA")

# Set the date range
start_date <- "2018-01-01"
end_date <- "2023-12-31"  # Adjust the end date if needed

# Get historical data for Amazon and Tesla
getSymbols(symbols, from = start_date, to = end_date, auto.assign = TRUE)
[1] "AMZN" "TSLA"
# Extract adjusted closing prices
prices <- merge(Ad(AMZN), Ad(TSLA))
colnames(prices) <- symbols

Calculate Daily Returns

# Calculate daily returns
returns <- na.omit(ROC(prices, type = "discrete"))

Calculate Expected Returns and Covariance Matrix

# Calculate expected daily returns (mean returns)
mu <- colMeans(returns)

# Calculate the covariance matrix
cov_mat <- cov(returns)

Set up Portfolio Weights

# Equal weights for AMZN and TSLA
weights <- c(0.5, 0.5)
names(weights) <- symbols

Calculate Portfolio Expected Return and Variance

# Calculate portfolio expected daily return
portfolio_return_daily <- sum(weights * mu)

# Calculate portfolio daily variance
portfolio_variance_daily <- t(weights) %*% cov_mat %*% weights

Annualize the Expected Return and Volatility

# Annualize expected return
portfolio_return_annual <- portfolio_return_daily * 252

# Annualize volatility (standard deviation)
portfolio_volatility_annual <- sqrt(portfolio_variance_daily * 252)

Print the results

# Print results
print(paste("Portfolio expected annual return:", round(portfolio_return_annual * 100, 2), "%"))
[1] "Portfolio expected annual return: 41.62 %"
print(paste("Portfolio annualized volatility:", round(portfolio_volatility_annual * 100, 2), "%"))
[1] "Portfolio annualized volatility: 42.5 %"

Analysis of results

In this example, we have created a portfolio which only contains two assets. Both assets have the same weight and we are only evaluating the expected annual return and the volatility. We may notice that the volatility is quite high in this case. Volatility, measured by the standard deviation, measures total risk. Therefore, the volatility portrayed in this example is considerably high for the investor, and presumably not a desired one. The main way to lessen this risk is by diversifying, this is, eliminating the unsystematic risk by mixing different types of assets and investments into the same portfolio.

Final Comments

In the following exercise we will dive further into the characteristics of the Markowitz Portfolio Theory and we will compare it to another model: CAPM.

L9 Portfolio - CAPM

Introduction

The Markowitz Portfolio Theory and the Capital Asset Pricing Model (CAPM) are two different approaches for portfolio selection and asset pricing. This two different methods have the scope of making investment decisions and optimize them, but each have their own assumptions, approaches and applications.

Markowitz Portfolio Theory

Overview

Developed by: Harry Markowitz in 1952.

Concept: Also known as Mean-Variance Optimization (MVO).

Objective: To build an optimal portfolio that offers the maximum expected return for a given level of risk, or equivalently, the minimum risk for a given level of expected return.

Main Elements

Expected Return: The weighted average of the expected returns of the assets in the portfolio.

Risk (Variance or Standard Deviation): The portfolio’s total risk is measured by the variance (or standard deviation) of its returns.

Covariance: Accounts for how assets move together; diversification benefits arise when asset returns are not perfectly correlated. Perfectly correlated assets will have a beta of 1 or -1, whereas the rest will have betas in-between those two values.

Assumptions

Investors are rational and risk-averse.

Returns are normally distributed.

Perfect Information in the market; Markets are efficient.

Investors consider only the mean and variance of returns.

No transaction costs or taxes.

Assets are infinitely divisible.

Efficient Frontier

The set of optimal portfolios that offer the highest expected return for a given level of risk.

Investors choose portfolios on the efficient frontier based on their risk preference.

Capital Asset Pricing Model (CAPM)

Overview

Developed by: William Sharpe, John Lintner, and Jan Mossin in the 1960s.

Concept: A model that describes the relationship between the expected return of an asset and its systematic risk, measured by beta (β).

Objective: To determine the expected return on an asset or portfolio, considering its risk relative to the market.

Key Components

Risk-Free Rate (Rf): The return of an investment with zero risk, typically government bonds. This investment has a β = 0

Market Return (Rm): The expected return of the market portfolio.

Beta (β): Measures the sensitivity of the asset’s returns to the returns of the market portfolio.

Expected Return Formula: E(Ri) = Rf + βi(E(Rm)-Rf) where: E(Ri) is the expected return of asset “i” βi is the beta of asset i E(Rm) is the expected market return

Assumptions

Investors hold diversified portfolios (market portfolio) that eliminate unsystematic risk.

Markets are efficient; all investors have the same information.

Investors can borrow and lend unlimited amounts at the risk-free rate (OR short selling shall be allowed)

No taxes or transaction costs.

Single-period investment horizon.

Security Market Line (SML)

A graphical representation of the CAPM, showing the relationship between expected return and beta. Assets plotted above the SML are undervalued; those below are overvalued. This can help us know (really approximately) whether an asset shall be bought or sell. In the case of an asset being overvalued, we should sell it as it will eventually drop to the security market line. If an asset is undervalued, we should buy it as its current price does not represent the market price it should have and it will eventually appreciate.

Differences Between CAPM and Markowitz Portfolio Theory

1. Purpose and Application

Markowitz Portfolio Theory:

Focuses on portfolio selection by optimizing the trade-off between expected return and risk. Helps investors construct an efficient portfolio based on their risk tolerance.

CAPM:

Focuses on asset pricing by relating expected return to systematic risk. Provides a way to price individual securities and determine expected returns based on market risk.

2. Risk Consideration

Markowitz:

Considers total risk (standard deviation or variance), including both systematic and unsystematic risk.

Emphasizes the importance of diversification to reduce unsystematic risk.

CAPM:

Considers only systematic risk (beta), assuming unsystematic risk is eliminated through diversification.

Beta measures the asset’s sensitivity to market movements.

3. Assumptions About Diversification

Markowitz:

Assumes investors can and should diversify their portfolios to optimize risk-return trade-offs.

Diversification reduces total risk.

CAPM:

Assumes investors already hold the market portfolio, which is fully diversified. Therefore, only systematic risk matters in pricing assets.

4. Output and Use

Markowitz:

Provides the efficient frontier of optimal portfolios.

Investors choose portfolios based on their risk preferences.

CAPM:

Provides the expected return of an asset given its beta.

Used to assess whether an asset is fairly priced.

5. Market Equilibrium

Markowitz:

Does not assume market equilibrium; it’s a normative model suggesting how investors should allocate assets.

CAPM:

Assumes market equilibrium where supply and demand are balanced.

Prices adjust so that expected returns are consistent with risk.

6. Practical Implementation

Markowitz:

Computationally intensive, especially with many assets due to the covariance matrix.

Requires estimates of expected returns, variances, and covariances.

CAPM:

Simpler to implement since it requires estimating beta and expected market return.

Beta can be estimated using regression analysis on historical data.

R Implementation Example

To illustrate the differences, we can use R to perform both a Markowitz portfolio optimization and a CAPM analysis.

Markowitz Portfolio Optimization

Load libraries

# Install and load required packages
if (!require("quantmod")) install.packages("quantmod")
if (!require("PortfolioAnalytics")) install.packages("PortfolioAnalytics")
if (!require("ROI")) install.packages("ROI")
if (!require("ROI.plugin.quadprog")) install.packages("ROI.plugin.quadprog")
if (!require("PerformanceAnalytics")) install.packages("PerformanceAnalytics")

library(quantmod)
library(PortfolioAnalytics)
library(ROI)
library(ROI.plugin.quadprog)
library(PerformanceAnalytics)

Retrieve data

# Define a set of assets
symbols <- c("AAPL", "MSFT", "GOOG", "AMZN")

# Get historical price data
getSymbols(symbols, from = "2020-01-01", to = "2023-01-01")
[1] "AAPL" "MSFT" "GOOG" "AMZN"

Merge Data and obtain returns (eliminating non-existing data)

# Merge adjusted closing prices
prices <- do.call(merge, lapply(symbols, function(x) Ad(get(x))))

# Calculate returns
returns <- na.omit(Return.calculate(prices))

Create portfolio specifications and optimize it

# Create portfolio specification
port_spec <- portfolio.spec(assets = symbols)
port_spec <- add.constraint(port_spec, type = "full_investment")
port_spec <- add.constraint(port_spec, type = "long_only")
port_spec <- add.objective(port_spec, type = "risk", name = "StdDev")
port_spec <- add.objective(port_spec, type = "return", name = "mean")

# Optimize portfolio to find the minimum variance portfolio
opt_port <- optimize.portfolio(R = returns, portfolio = port_spec, optimize_method = "ROI")

Create data frame and print results

markowitz_results <- data.frame(
  Stock = symbols,
  Weights = opt_port$weights
)
print(markowitz_results)

Construct final portfolio returns returns from the optimized weights

final_portfolio_returns <- Return.portfolio(R = returns, weights = opt_port$weights)

Compute annualized statistics (return, standard deviation, Sharpe ratio, etc.)

annual_stats <- table.AnnualizedReturns(final_portfolio_returns)
print(annual_stats)
Annualized Return (20.36%)

This implies that, if the daily returns observed during our historical sample period were to continue, the portfolio would earn roughly 20% per year. It is important to remember that this return is historically based and not a guaranteed future performance.

Annualized Standard Deviation (36.17%)

A standard deviation of 36% indicates a relatively high level of volatility. In practical terms, the portfolio’s value could fluctuate significantly around its average return. Investors need to decide if this level of risk aligns with their risk tolerance.

Annualized Sharpe Ratio (0.5629)

The Sharpe Ratio measures the portfolio’s risk-adjusted return. A ratio of 0.56 indicates that, historically, the portfolio’s return exceeded the risk-free rate by 0.56% for every 1% of volatility. While a Sharpe Ratio above 1.0 is often considered strong, a ratio around 0.5–0.7 can be viewed as acceptable or moderate, depending on the asset class.

CAPM Analysis

Load libraries and retrieve data

library(quantmod)
library(PerformanceAnalytics)

# Define the stock symbols
symbols <- c("AAPL", "MSFT", "GOOG", "AMZN")

# Get historical data for assets and market
getSymbols(c(symbols, "^GSPC"), from = "2018-01-01", to = "2023-12-31")
[1] "AAPL" "MSFT" "GOOG" "AMZN" "GSPC"

Define betas, expected returns, risk free rate and omit non-existent data in returns

# Initialize vectors to store betas and expected returns
betas <- numeric(length(symbols))
expected_returns <- numeric(length(symbols))

# Define the annual risk-free rate
risk_free_rate <- 0.03  # 3%

# Calculate daily market returns
market_returns <- na.omit(ROC(Ad(GSPC)))

Calculate betas and expected returns

# Loop over each symbol to calculate beta and expected return
for (i in 1:length(symbols)) {
  # Get stock returns
  stock_data <- get(symbols[i])
  stock_returns <- na.omit(ROC(Ad(stock_data)))
  
  # Align dates with market returns
  returns_data <- merge(stock_returns, market_returns, all = FALSE)
  
  # Calculate beta
  beta <- CAPM.beta(Ra = returns_data[,1], Rb = returns_data[,2])
  betas[i] <- beta

  # Calculate expected return using CAPM
  annual_market_return <- mean(returns_data[,2]) * 252  # Annualize market return
  expected_return <- risk_free_rate + beta * (annual_market_return - risk_free_rate)
  expected_returns[i] <- expected_return
  
  # Print results for each stock
  cat("Stock:", symbols[i], "\n")
  cat("Beta:", round(beta, 4), "\n")
  cat("Expected Return:", round(expected_return * 100, 2), "%\n\n")
}
Stock: AAPL 
Beta: 1.2176 
Expected Return: 10.96 %

Stock: MSFT 
Beta: 1.2089 
Expected Return: 10.9 %

Stock: GOOG 
Beta: 1.1552 
Expected Return: 10.55 %

Stock: AMZN 
Beta: 1.1256 
Expected Return: 10.36 %

Create data frame and print results

# Create a data frame with the results
capm_results <- data.frame(
  Stock = symbols,
  Beta = round(betas, 4),
  Expected_Return = round(expected_returns * 100, 2)
)

print(capm_results)

Conclusions

Markowitz Portfolio Theory focuses on constructing optimal portfolios by considering total risk and return, helping investors make decisions based on their risk tolerance. CAPM provides a method to price individual assets by relating expected returns to systematic risk, assuming investors hold diversified portfolios.

The main difference lies in their treatment of risk: Markowitz considers both systematic and unsystematic risk. CAPM considers only systematic risk, as unsystematic risk is assumed to be diversified away.

In the results we can see that the outcome of the Markowitz optimization is the weight of each asset in the portfolio, whereas our outcome from the CAPM is the betas and expected returns of the asset.

Implications for Investors

Portfolio Construction:

Use Markowitz’s framework to build a diversified portfolio that aligns with risk preferences.

Asset Pricing and Expected Returns:

Use CAPM to estimate the expected return of an asset based on its market risk and to assess whether it’s overvalued or undervalued.

Final comments.

We have observed thanks to our representations that even if both models have a similar objective, which is the optimization of the returns for the investors, each one does it in a whole different way, with different assumptions, different treatment of risk and with a different results scope.

L10 WACC

WACC replication

Load library

library(tidyverse)
library(quantmod)

Retrieve stock data

getSymbols("AAPL")
[1] "AAPL"

Define the Number of Outstanding Shares

outstanding_shares <- 16000000000  # 16 billion shares

Calculate Market Capitalization

market_cap <- last(AAPL$AAPL.Adjusted) * outstanding_shares

Define the Cost of Debt

cost_of_debt <- 0.02  # 2%

Define Tax Rate Applicable to Apple

tax_rate <- 0.21  # 21%

Obtain Beta for Apple’s Stock

beta <- 1.2  # Beta of 1.2 indicates higher volatility than the market

Define the Risk-Free Rate

risk_free_rate <- 0.015 

Define the Market Risk Premium

market_risk_premium <- 0.06

Calculate the Cost of Equity using CAPM Model

cost_of_equity <- risk_free_rate + beta * market_risk_premium

Define the Market Value of Debt

market_value_of_debt <- 100e9  # $100 billion

Calculate Total Market Value

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)

Display the WACC

cat("WACC for Apple Inc.:", round(wacc * 100, 2), "%")
WACC for Apple Inc.: 8.52 %

Analysis of results.

In this exercise we have replicated a basic example of WACC. WACC represents the minimum average return Apple must earn on its existing assets to satisfy its investors and creditors, which in this case must be 8.52%. The lower the WACC, the more projects the company can take on given they have positive net present values. WACC may use in its calculations the after-tax cost of debt, as interest is tax-deductible. A good assessment in the mix of debt and equity financing is crucial for the stability of a company and its capital structure.

The WACC approached may be used as a powerful tool to asses different kinds of situation that a company may face, such as project evaluation, corporate finance decisions (m&A and capital budgeting). It is also a useful tool used for investor analysis.

L11.1 - L11.6

Definitions

Futures Contract

A futures contract is a financial derivative upon someone agrees to buy or sell a determinate commodity asset or security at an predetermined price and an specific time in the future. The buyer agrees and becomes obliged to buy and receive the asset whereas the seller agrees to provide and make deliver of the asset.

Call Option

A call option is a type of financial contract where the buyer is given the right to buy a certain asset or instrument at an specified price and time. The seller on the other hand is obliged to sell the asset if the buyer exercises the call. The option is bought under a premium, so if the asset goes down in price and the buyer does not execute the option, the seller will profit from the premium. However, if the asset price increases and the buyer executes the option, the profit the buyer will have is the end value of the stock (payoff) minus the premium paid for the option. Call options have limited loses for the buyers (the premium is the maximum loss) but has no profit limit. Call options are divided into Long Call Options and Short Call Options(in the short call options, it is the seller the one who promises to sell an asset at a certain price in the date of expiration)

When using call options, it is often to implement an strategy called hedging, in which you also take the opposite position in order to mitigate potential losses. That is, that if we are using call options, we might also buy put options for the same asset so that we can reduce the losses in the case that the striking price is not reached at the date of expiration.

Load Packages

# Load required packages
library(quantmod)
library(lubridate)
library(PerformanceAnalytics)

Define Beginning and End of Term Dates

# Define Beginning of Term (BoT) and End of Term (EoT) dates
BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

L11.1 Calculating the Difference in the Dollar Value of the S&P 500 Futures Contract

-You purchased an S&P 500 futures contract at the beginning of the term.

-You sold the same futures contract at the end of the term.

-The contract value is futures price times $250.

Since getting historical futures prices can be challenging, we’ll use the S&P 500 index (^GSPC) as a proxy for the futures prices. ´

  1. Retrieve S&P500 index data
start_date <- BoT_date - 7
end_date <- EoT_date + 7

getSymbols("^GSPC", src = "yahoo", from = start_date, to = end_date)
[1] "GSPC"
  1. Define a Function to Get Prices on Specific Dates
# Function to get the adjusted closing price on a specific date
get_price_on_date <- function(data, date) {
  index(data) <- as.Date(index(data))
  
  available_dates <- index(data)[index(data) <= date]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Price = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  price <- as.numeric(Cl(data[date_used]))
  
  return(list(
    Price = price,
    Date = as.Date(date_used)
  ))
}

Get S&P500 prices at BoT and EoT

price_BoT <- get_price_on_date(`GSPC`, BoT_date)
price_EoT <- get_price_on_date(`GSPC`, EoT_date)

cat("S&P 500 Index Price at BoT (", price_BoT$Date, "): ", price_BoT$Price, "\n", sep = "")
S&P 500 Index Price at BoT (19844): 5018.39
cat("S&P 500 Index Price at EoT (", price_EoT$Date, "): ", price_EoT$Price, "\n", sep = "")
S&P 500 Index Price at EoT (19996): 5762.48

Calculate the Contract Values

contract_value_BoT <- price_BoT$Price * 250
contract_value_EoT <- price_EoT$Price * 250

Calculate the difference

difference <- contract_value_EoT - contract_value_BoT

cat("Difference in Contract Values: $", round(difference, 2), "\n", sep = "")
Difference in Contract Values: $186022.5

Analysis

The significant increase in the price of the S&P500 during the term has led to a final difference in the contract value of 186022.5 USD. In this example we can easily observe how the fluctuation of price can enormously affect the price of the contract, which makes hedging strategies much more attractive. Although they may reduce the total profit, a futures trader will overall benefit from them as loses will be greatly mitigated and the outcome of a bad operation will not be as catastrophic as it may be if there is no counterpart that backs it up.

L11.2 Calculating Your Return from the Futures Position

-You invested an initial margin of 20% of the futures contract value at BoT -Your return is the gain from the futures position divided by your initial investment

Calculate Initial Investment

initial_investment <- 0.20 * contract_value_BoT

cat("Initial Investment (20% Margin): $", round(initial_investment, 2), "\n", sep = "")
Initial Investment (20% Margin): $250919.5

Calculate Return on Investment

# Calculate the return
return_futures <- difference / initial_investment

# Print the return as a percentage
cat("Return on Futures Position: ", round(return_futures * 100, 2), "%\n", sep = "")
Return on Futures Position: 74.14%

Analysis

As a follow up from the previous exercise, we have the final return of the futures position that sums to a total of 74.14% in the duration of the school term. With such high returns, and as we have explained before, we shall bare in mind that equally high losses may be obtained. Therefore, deep knowledge of the underlying asset and a good trading strategy are extremely important in order to perform such operations.

L11.3 Annualizing Your Return

-The return calculated is for the duration of the school term (5 months) -To annualize the return, we multiply it by 12/m, where m ~ 5 months

Calculate the annualization

m <- as.numeric(difftime(EoT_date, BoT_date, units = "days")) / 30.44

annualized_return_futures <- return_futures * (12 / m)

cat("Annualized Return on Futures Position: ", round(annualized_return_futures * 100, 2), "%\n", sep = "")
Annualized Return on Futures Position: 178.16%

Comments

Previously, we had only obtained the difference in the futures contract price and the return obtained in the duration of the school term. Now, we have obtained the annualized return, which depicts the average rate of return per year. We annualize our returns to better compare them with other possible studied returns, as returns are usually presented as per year.

L11.4 Calculating the Return from Purchasing a Call Option on Apple Inc. (AAPL)

-Purchase of a call option representing 100 shares of AAPL at BoT -Determine the return based on the option premiums at BOT and EoT If the premium at EoT is unavailable, calculate the return based on exercising the option

We will estimate the option premiums using the Black-Scholes Model

Retrieve AAPL Stock Prices

getSymbols("AAPL", src = "yahoo", from = start_date, to = end_date)
[1] "AAPL"
price_AAPL_BoT <- get_price_on_date(AAPL, BoT_date)
price_AAPL_EoT <- get_price_on_date(AAPL, EoT_date)

cat("AAPL Stock Price at BoT (", price_AAPL_BoT$Date, "): $", round(price_AAPL_BoT$Price, 2), "\n", sep = "")
AAPL Stock Price at BoT (19844): $169.3
cat("AAPL Stock Price at EoT (", price_AAPL_EoT$Date, "): $", round(price_AAPL_EoT$Price, 2), "\n", sep = "")
AAPL Stock Price at EoT (19996): $233

Set the Strike Price

Strike_Price <- ceiling(price_AAPL_BoT$Price / 5) * 5

cat("Option Strike Price: $", Strike_Price, "\n", sep = "")
Option Strike Price: $170

Estimate Volatility

start_date_vol <- BoT_date - years(1)
getSymbols("AAPL", src = "yahoo", from = start_date_vol, to = BoT_date)
[1] "AAPL"
returns <- na.omit(dailyReturn(Cl(AAPL)))

volatility <- sd(returns) * sqrt(252)

cat("Estimated Annualized Volatility: ", round(volatility * 100, 2), "%\n", sep = "")
Estimated Annualized Volatility: 19.67%

Define the Black-Scholes Function

BlackScholesCall <- function(S, K, r, T, sigma) {
  d1 <- (log(S / K) + (r + sigma^2 / 2) * T) / (sigma * sqrt(T))
  d2 <- d1 - sigma * sqrt(T)
  C <- S * pnorm(d1) - K * exp(-r * T) * pnorm(d2)
  return(C)
}

Calculate Option Premiums at BoT and EoT

# Set risk-free rate (e.g., 2%)
risk_free_rate <- 0.02

# Time to expiration (assume option expires on next month's third Friday)
T_BoT <- as.numeric(difftime(as.Date("2024-11-15"), price_AAPL_BoT$Date, units = "days")) / 365
T_EoT <- as.numeric(difftime(as.Date("2024-11-15"), price_AAPL_EoT$Date, units = "days")) / 365 
C_BoT <- BlackScholesCall(S = price_AAPL_BoT$Price, K = Strike_Price, r = risk_free_rate, T = T_BoT, sigma = volatility)
C_EoT <- BlackScholesCall(S = price_AAPL_EoT$Price, K = Strike_Price, r = risk_free_rate, T = T_EoT, sigma = volatility)

cat("Option Premium at BoT: $", round(C_BoT, 2), "\n", sep = "")
Option Premium at BoT: $10.32
cat("Option Premium at EoT: $", round(C_EoT, 2), "\n", sep = "")
Option Premium at EoT: $63.43

Calculate the Return from the Option

# Calculate return based on selling the option at EoT
if (!is.na(C_EoT)) {
  return_option_sell <- (C_EoT - C_BoT) / C_BoT
  cat("Return from Selling the Call Option: ", round(return_option_sell * 100, 2), "%\n", sep = "")
} else {
  cat("Option premium at EoT is unavailable.\n")
}
Return from Selling the Call Option: 514.51%
# Calculate return based on exercising the option
if (price_AAPL_EoT$Price > Strike_Price) {
  profit_exercise <- (price_AAPL_EoT$Price - Strike_Price) - C_BoT
  return_option_exercise <- profit_exercise / C_BoT
  cat("Return from Exercising the Call Option: ", round(return_option_exercise * 100, 2), "%\n", sep = "")
} else {
  profit_exercise <- -C_BoT
  return_option_exercise <- profit_exercise / C_BoT
  cat("Option expired worthless. Return from Exercising the Call Option: ", round(return_option_exercise * 100, 2), "%\n", sep = "")
}
Return from Exercising the Call Option: 510.36%

Analysis

In this exercise, we have opted for calculating the premiums with the use of the Black Scholes Model. This decision has taken due to the inaccessibility of direct data about the premiums for the options. The Black-Scholes Model allows us to calculate the theoretical value of derivatives by taking into account 5 variables: strike price of the option, current stock price, time to expiration, risk-free rate and volatility. The estimation obtained with this model may derive from the real values. When using this model, we should also take into account that depending on our location, options could be exercised before the expiration date. However for this exercise we will not take that into account. We have also taken into account the two options that could happen when buying this call option: to exercise it or to buy it. When we sell the call option, the total non-annualized return will be 514.51%, whereas if we exercise it it is 510.36%. In the case of selling, the profit or return obtained will be calculated with the premiums. If the premium at the End of Term was unavailable or we decided to exercise the option, the profit obtained will be the price of the stock at the moment of exercise minus the strike price and the premium. Both returns are rather similar, although the return from selling the option is noticeably higher.

L11.5 Annualizing the Return on Your Option

# Annualize the Returns
annualized_return_option_sell <- (return_option_sell)*(12 / m)
annualized_return_option_exercise <- ((return_option_exercise)*(12 / m)) 

# Display the Annualized Returns
cat("\nAnnualized Return from Selling the Call Option: ", round(annualized_return_option_sell * 100, 2), "%\n", sep = "")

Annualized Return from Selling the Call Option: 1236.44%
cat("Annualized Return from Exercising the Call Option: ", round(annualized_return_option_exercise * 100, 2), "%\n", sep = "")
Annualized Return from Exercising the Call Option: 1226.47%

Comments

With the annualization of the results we obtain a return of 1236.44% and 1226.47% respectively. As we know, the annualization is usually done in order to better compare the returns with others.

L11.6 Comparing the Return on Your Call Option to Investing in the Stock

Calculate the Return from Investing in AAPL stock

return_stock <- (price_AAPL_EoT$Price - price_AAPL_BoT$Price) / price_AAPL_BoT$Price

annualized_return_stock <- return_stock * (12 / m)

cat("Return from Investing in AAPL Stock: ", round(return_stock * 100, 2), "%\n", sep = "")
Return from Investing in AAPL Stock: 37.63%
cat("Annualized Return on AAPL Stock: ", round(annualized_return_stock * 100, 2), "%\n", sep = "")
Annualized Return on AAPL Stock: 90.42%

Compare the returns

cat("\nComparison of Returns:\n")

Comparison of Returns:
cat("Annualized Return on Call Option: ", round(annualized_return_option_sell * 100, 2), "%\n", sep = "")
Annualized Return on Call Option: 1236.44%
cat("Annualized Return from Exercising the Call Option: ", round(annualized_return_option_exercise * 100, 2), "%\n", sep = "")
Annualized Return from Exercising the Call Option: 1226.47%
cat("Annualized Return on AAPL Stock: ", round(annualized_return_stock * 100, 2), "%\n", sep = "")
Annualized Return on AAPL Stock: 90.42%

Analysis

In this final exercise we compare the returns of the Return of the Stock with those of the call option, both when selling and when exercising it. As we can observe, the potential returns of the call options hugely outweigh those of the Stock itself. In the case of the call option, as we have mentioned, the potential loss for the buyer is limited to the premium that they shall pay when buying the option. However, for the seller of this option, the risk becomes extremely noticeable.

L11.7 Determining Swap Payments

Definitions

Swaps

Swaps are a kind of derivative contract in which the two parties involved exchange assets with their corresponding cash flows over an established period of time. One of the two cash flows involved will be fixed, whereas the other one will be variable and dependent on an index price, interest rate or currency exchange rate. The variable nature of one party against the fixed one of the other results in some swap contracts being very risky and they involve great specialization and a deep understanding of the underlying index/rate. This contracts are traded in the over-the-counter market (OTC) and are negotiated individually and privately. This characteristics may lead to thinking that this contracts are not particularly liquid but the reality in this case is quite counter-intuitive and there is great interest in the Swap Market.

R Code

Load packages

library(quantmod)
library(lubridate)

Define the Beginning and End of Term Dates

BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

Define Swap Terms

notional_amount <- 10000000

fixed_rate <- 0.06

Calculate the Time Period of the Swap

days_between <- as.numeric(difftime(EoT_date, BoT_date, units = "days"))

year_fraction <- days_between / 360

cat("Days between BoT and EoT:", days_between, "days\n")
Days between BoT and EoT: 152 days
cat("Year fraction (using Actual/360):", round(year_fraction, 6), "\n")
Year fraction (using Actual/360): 0.422222 

Calculate the Fixed-Rate Payment

fixed_payment <- notional_amount * fixed_rate * year_fraction

cat("Fixed-Rate Payment: $", round(fixed_payment, 2), "\n", sep = "")
Fixed-Rate Payment: $253333.3

Retrieve the 26-week Tbill Rate at Eot

Get the T-bill Rate Data

getSymbols("DTB6", src = "FRED", from = EoT_date - 7, to = EoT_date + 7)
[1] "DTB6"

Extract the Rate at EOT

get_rate_on_date <- function(data, date) {
  index(data) <- as.Date(index(data))
  
  available_dates <- index(data)[index(data) <= date & !is.na(data[index(data)])]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Rate = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  # Get the rate
  rate <- as.numeric(data[date_used]) / 100  # Convert percentage to decimal
  
  return(list(
    Rate = rate,
    Date = as.Date(date_used)
  ))
}

t_bill_rate_EoT <- get_rate_on_date(DTB6, EoT_date)

cat("26-week T-bill Rate at EoT (", t_bill_rate_EoT$Date, "): ", round(t_bill_rate_EoT$Rate * 100, 2), "%\n", sep = "")
26-week T-bill Rate at EoT (19996): 4.23%

Calculate the FLoating-Rate Payment

# Floating-rate payment calculation
floating_payment <- notional_amount * t_bill_rate_EoT$Rate * year_fraction

# Print the floating-rate payment
cat("Floating-Rate Payment: $", round(floating_payment, 2), "\n", sep = "")
Floating-Rate Payment: $178600

Compute the Net Payment

# Net payment
net_payment <- floating_payment - fixed_payment

# Determine if you gain or lose
if (net_payment > 0) {
  result <- "gain"
} else if (net_payment < 0) {
  result <- "lose"
} else {
  result <- "break even"
}

# Print the net payment and result
cat("Net Payment: $", round(net_payment, 2), "\n", sep = "")
Net Payment: $-74733.33
cat("You ", result, " on the swap.\n", sep = "")
You lose on the swap.

Analysis of results

This loss occurs because the floating rate you receive is lower than the fixed rate you pay. Interest Rate Movements: In this scenario, the 26-week T-bill rate at EoT was lower than the fixed rate agreed upon. This resulted in a net loss for you on the swap. Rate at EoT was 0.0423

Risk Management: Swaps are used to manage interest rate risk. By entering into this swap, you were speculating that the 26-week T-bill rate at EoT would be higher than 6%.

As we have mentioned in the beginning, a deep knowledge of the underlying asset/interest/index is crucial when entering a swap contract as the price risk will be determined by them. In this case, the lower-than-expected rate has led to a significant loss.

L11.8 - L11.12. Measuring and explaining exchange rate movements

Explanations Ahead

In this section we will be measuring and explaining exchange rate movements. In order to better understand this phenomena we will have to take into account certain concepts.

Currency fluctuation

When we talk about current fluctuation, we are referring to the change in the relative value of one against the other. In other words, is the change in the equivalencies of the value of the currencies.

Exchange Rates

Exchange Rates are the numerical representation of the currency fluctuation. That is the value of one currency against the other in an specific moment. Exchange Rates fluctuate and are great economical indicators. There are several reasons for the fluctuation of exchange rates, such as interest rates, general macroeconomic data of each country, political policies and stability, inflation rates, data and policy, and foreign investments. Another factor that creates fluctuation in exchange rates is the speculation.

Effects

The fluctuations in currency (and exchange rates) have an impact in several aspects of the economy. 1. International trade. A weak currency easily benefits from exports, while a strong one may reduce their export capability.
2. Inflation. A strong currency will have a lot of import capability and will be able to keep inflation stable. However, a weak currency will have higher import costs and will overall increase domestic inflation. 3. Investment. The stability or strengthen of a currency usually indicate an stable/strong economy and political situation. Therefore, it will be much more attractive to make an investment in those countries with a strong currency. Oppositely, a weak currency (or a constantly changing one) will indicate weakness and instability. 4. Economic stability and growth. Impacts in GDP, investment, inflation and international trade all contribute towards the economy of a country, whether making in stable and strong or weak a unstable.

Before the exercises

Load Packages

# Load required packages
library(quantmod)
library(lubridate)
library(PerformanceAnalytics)

Define Beginning and End of Term Dates

# Define Beginning of Term (BoT) and End of Term (EoT) dates
BoT_date <- as.Date("2024-05-01")
EoT_date <- as.Date("2024-09-30")

L11.8 Determining the Percentage Change in the Value of the British Pound

Retrieve GPB/USD Exchange Rate Data

# Get GBP/USD exchange rate data
getSymbols("GBPUSD=X", src = "yahoo", from = BoT_date - 7, to = EoT_date + 7, auto.assign = TRUE)
[1] "GBPUSD=X"
# Assign data to a variable
gbp_usd_data <- `GBPUSD=X`

Get exchange Rates at BoT and EoT

# Function to get the exchange rate on a specific date
get_rate_on_date <- function(data, date) {
  index(data) <- as.Date(index(data))
  
  available_dates <- index(data)[index(data) <= date]
  
  if (length(available_dates) == 0) {
    warning(paste("No data available on or before", date))
    return(list(Rate = NA, Date = NA))
  }
  
  date_used <- max(available_dates)
  
  rate <- as.numeric(Cl(data[date_used]))
  
  return(list(
    Rate = rate,
    Date = as.Date(date_used)
  ))
}

# Get rates at BoT and EoT
gbp_rate_BoT <- get_rate_on_date(gbp_usd_data, BoT_date)
gbp_rate_EoT <- get_rate_on_date(gbp_usd_data, EoT_date)

# Print the exchange rates
cat("GBP/USD Rate at BoT (", gbp_rate_BoT$Date, "): ", round(gbp_rate_BoT$Rate, 4), "\n", sep = "")
GBP/USD Rate at BoT (19844): 1.2539
cat("GBP/USD Rate at EoT (", gbp_rate_EoT$Date, "): ", round(gbp_rate_EoT$Rate, 4), "\n", sep = "")
GBP/USD Rate at EoT (19996): 1.3376

Calculate the Percentage Change

# Calculate the percentage change
gbp_percentage_change <- (gbp_rate_EoT$Rate - gbp_rate_BoT$Rate) / gbp_rate_BoT$Rate * 100

# Print the result
cat("Percentage Change in GBP/USD: ", round(gbp_percentage_change, 2), "%\n", sep = "")
Percentage Change in GBP/USD: 6.67%

Determine Appreciation or Depreciation

if (gbp_percentage_change > 0) {
  gbp_result <- "appreciated"
} else if (gbp_percentage_change < 0) {
  gbp_result <- "depreciated"
} else {
  gbp_result <- "remained the same"
}

cat("The British pound has ", gbp_result, " against the US dollar over the school term.\n", sep = "")
The British pound has appreciated against the US dollar over the school term.

Analysis

The appreciation of the British pound against the US dollar may indicate, as we have previously explained, an strengthening of UK’s economy against the US. Although we cannot be certain without much further analysis of what may have caused this notorious appreciation of the currency, we can presume is a mix of several factors that have been already explained. This could include favorable GDP data for the UK, an aggressive monetary policy from the Bank of England with higher interest rates, or the stabilization of certain aspects regarding Brexit. On the other side, the US may have become somewhat less attractive for investors who look for riskier opportunities, slow inflation with a less aggressive monetary policy or overall discontent with the political situation. The upcoming USA Presidential Elections may have risen certain concerns and created a sense of instability that has been portrayed in the exchange rate against the British Pound.

L11.9 Determining the Percentage Change in the Value of the Japanese Yen

Retrieve USD/JPY Exchange Rate Data

# Get USD/JPY exchange rate data
getSymbols("JPY=X", src = "yahoo", from = BoT_date - 7, to = EoT_date + 7, auto.assign = TRUE)
[1] "JPY=X"
# Assign data to a variable
usd_jpy_data <- `JPY=X`

Get Exchange Rates at BoT and EoT

# Get rates at BoT and EoT
jpy_rate_BoT <- get_rate_on_date(usd_jpy_data, BoT_date)
jpy_rate_EoT <- get_rate_on_date(usd_jpy_data, EoT_date)

# Print the exchange rates
cat("USD/JPY Rate at BoT (", jpy_rate_BoT$Date, "): ", round(jpy_rate_BoT$Rate, 4), "\n", sep = "")
USD/JPY Rate at BoT (19844): 155.704
cat("USD/JPY Rate at EoT (", jpy_rate_EoT$Date, "): ", round(jpy_rate_EoT$Rate, 4), "\n", sep = "")
USD/JPY Rate at EoT (19996): 143.71

Calculate the Percentage Rate

# Invert the rates to get JPY per USD
jpy_per_usd_BoT <- 1 / jpy_rate_BoT$Rate
jpy_per_usd_EoT <- 1 / jpy_rate_EoT$Rate

# Calculate the percentage change
jpy_percentage_change <- (jpy_per_usd_EoT - jpy_per_usd_BoT) / jpy_per_usd_BoT * 100

# Print the result
cat("Percentage Change in JPY/USD: ", round(jpy_percentage_change, 2), "%\n", sep = "")
Percentage Change in JPY/USD: 8.35%

Determine Appreciation or Depreciation

if (jpy_percentage_change > 0) {
  jpy_result <- "appreciated"
} else if (jpy_percentage_change < 0) {
  jpy_result <- "depreciated"
} else {
  jpy_result <- "remained the same"
}

cat("The Japanese yen has ", jpy_result, " against the US dollar over the school term.\n", sep = "")
The Japanese yen has appreciated against the US dollar over the school term.

Analysis

Just as we have explained in the previous question. the US may have faced a period of instability and slowness that could have caused a lower demand for US dollars. Conversely, the Bank of Japan, may have adopted a more strict regulation (in opposition with its traditional approach) due to high inflation or due to normalization strategies, which may have caused a reaction in the currency markets. Japan may have also had positive reports or a recovery in its trade balance.

L11.10 Determining the Percentage Change in the Value of the Mexican Peso

Retrieve USD/MXN Exchange Rate Data

# Get USD/MXN exchange rate data
getSymbols("MXN=X", src = "yahoo", from = BoT_date - 7, to = EoT_date + 7, auto.assign = TRUE)
[1] "MXN=X"
# Assign data to a variable
usd_mxn_data <- `MXN=X`

Get Exchange Rates at BoT and EoT

# Get rates at BoT and EoT
mxn_rate_BoT <- get_rate_on_date(usd_mxn_data, BoT_date)
mxn_rate_EoT <- get_rate_on_date(usd_mxn_data, EoT_date)

# Print the exchange rates
cat("USD/MXN Rate at BoT (", mxn_rate_BoT$Date, "): ", round(mxn_rate_BoT$Rate, 4), "\n", sep = "")
USD/MXN Rate at BoT (19844): 16.9286
cat("USD/MXN Rate at EoT (", mxn_rate_EoT$Date, "): ", round(mxn_rate_EoT$Rate, 4), "\n", sep = "")
USD/MXN Rate at EoT (19996): 19.6636

Calculate the Percentage Change

# Invert the rates to get MXN per USD
mxn_per_usd_BoT <- 1 / mxn_rate_BoT$Rate
mxn_per_usd_EoT <- 1 / mxn_rate_EoT$Rate

# Calculate the percentage change
mxn_percentage_change <- (mxn_per_usd_EoT - mxn_per_usd_BoT) / mxn_per_usd_BoT * 100

# Print the result
cat("Percentage Change in MXN/USD: ", round(mxn_percentage_change, 2), "%\n", sep = "")
Percentage Change in MXN/USD: -13.91%

Determine Appreciation or Depreciation

if (mxn_percentage_change > 0) {
  mxn_result <- "appreciated"
} else if (mxn_percentage_change < 0) {
  mxn_result <- "depreciated"
} else {
  mxn_result <- "remained the same"
}

cat("The Mexican peso has ", mxn_result, " against the US dollar over the school term.\n", sep = "")
The Mexican peso has depreciated against the US dollar over the school term.

Analysis

Have we not seen the previous results, we might have had the initial thought that these results are the manifestation of a strong US Dollar, which strengthens against the Mexican Peso. However, we already know that the USD had weakened against the other two currencies analyzed, so we may assume that this is not the outcome of an strong USA but rather a really worsened Mexico. If we take a look into Mexico’s politics during the Term Period, we will notice that Presidential Elections took place, with the victory of Claudia Sheinbaum. The difference in positions with the USA in several international matters may have pushed this drop in the Mexican Peso, which has not yet stopped as of today, although our End of Term Date only dates until September.

L11.11 Determining the Per Unit Gain or Loss for British Pound Futures

Determine the per unit gain or loss if you had purchased British pound futures at the beginning of the term and sold them at the end of the term. Use GPB/USD Exchange rates as Proxy.

Calculate the Per Unit Gain or Loss

# Calculate the per unit gain or loss
per_unit_gain_loss <- gbp_rate_EoT$Rate - gbp_rate_BoT$Rate

# Print the result
cat("Per Unit Gain/Loss for GBP Futures: $", round(per_unit_gain_loss, 4), " per GBP\n", sep = "")
Per Unit Gain/Loss for GBP Futures: $0.0837 per GBP

In this exercise we have determined the gain per GPB for the futures contract.

L11.12 Determining the Dollar Amount of Your Gain or Loss on the Futures Contract

Given that a single futures contract on British pounds represents 62,500 pounds, determine the dollar amount of your gain or loss.

# Number of pounds per futures contract
contract_size <- 62500

# Total gain or loss
total_gain_loss <- per_unit_gain_loss * contract_size

# Print the result
cat("Total Gain/Loss on Futures Contract: $", round(total_gain_loss, 2), "\n", sep = "")
Total Gain/Loss on Futures Contract: $5229.96

Determine if you Gained or Lost

if (total_gain_loss > 0) {
  futures_result <- "gained"
} else if (total_gain_loss < 0) {
  futures_result <- "lost"
} else {
  futures_result <- "broke even"
}

cat("You have ", futures_result, " $", abs(round(total_gain_loss, 2)), " on the futures contract.\n", sep = "")
You have gained $5229.96 on the futures contract.

With a gain per GPB of 0.0837 USD and an amount of 62500 pounds, we will have ended at the end of term with a total gain of 5229.96 USD. This has been possible, as we know, thanks to the appreciation of the GPB against the USD, which he have already analyzed previously.

L12 Capital requirements

L12.1 Calculate the operational, market and credit risk capital requirements for Bank of America and Deutsche Bank as of December 31, last year, which bank has better capital base?

Definitions

Operational Risk

We can define operational risk as a type of business risk derived from the daily activity of the company. That is the risk derived from within the company rather than external forces or events. This risk includes factors such as people, systems and internal procedures.

Market Risk

Market Risk, also known as systematic risk, comprises a series of factors that cannot be individualized but rather affect the market as a whole, without the chance of eliminating it through diversification. This risk is usually affected or made noticeable by changes or movements on the market price and the interest rates, so it has an strong link with politics and economic cycles.

Credit Risk

Credit risk measures the probability of not being payed back by a borrower. This is, the risk of not being able to recollect the principal and the interests, leading to a loss or at least an interruption and delay. This risk is usually assessed by carefully analyzing the borrower and taking into account all factors that could lead to non-payment. When talking about corporate bond issuers, there are credit-rating agencies which evaluate the credit risk in order to inform the investors of the probability of recieving back their investment. The higher the credit risk is, the greater the interest that the lender or investor will demand, as the credit risk must be counterbalanced with higher rewards.

Risk-Weighted Assets (RWA)

In the explanations that follow, we will be using RWA in order to refer to the assets that a bank must have to comply with their risk profile and minimize their risk of insolvency, within their desired limits and objectives.

Basel III

Basel III is an international regulation designed to assure the banking system’s stability by standardizing the minimum capital reserve requirements. This requirements are divided in common equity tiers (1 and 2), which shall add to a minimum of 8%. This 8% has stayed the same since the Basel I regulation. However, there has been an addition in this system with the implementation of buffers, which introduce new requirements for banks: Capital Conservation Buffer (CCB, 2.5%), Countercyclical Capital Buffer (CCyB, 0 to 2.5%), Global Systematically Important Bank (G-SIB, 1 to 3.5% of RWA). Other regulations in Leverage and Liquidity have also been introduced, although we will not dive into those.

Complete Analysis of Capital Requirements and Comparison

For this analysis, we have obtained the 10-k filing of Bank of America reporting for 2023 and the 20-F filing of Deutsche Bank reporting for 2023.

1. Bank of America (BOFA)

From the 10-K filing, BOFA’s risk-weighted assets (RWAs) as of December 31, 2023, are categorized as follows:

Credit Risk RWA: $1,395 billion.

Market Risk RWA: $119 billion.

Operational Risk RWA: $357 billion (BOFA 10k).

Using the Basel III minimum capital requirements (8%), the capital requirements for BOFA are:

Credit Risk Capital Requirement: $111.6 billion.

Market Risk Capital Requirement: $9.52 billion.

Operational Risk Capital Requirement: $28.56 billion.

2. Deutsche Bank

Based on the 20-F filing, Deutsche Bank’s RWAs as of December 31, 2023, are:

Credit Risk RWA: €265.79 billion.

Market Risk RWA: €21.51 billion.

Operational Risk RWA: €57.15 billion (20F Deutsche).

Applying the 8% Basel III requirement:

Credit Risk Capital Requirement: €21.26 billion.

Market Risk Capital Requirement: €1.72 billion.

Operational Risk Capital Requirement: €4.57 billion.

Comparison: BOFA vs. Deutsche Bank

1. Credit Risk Capital

BOFA: $111.6 billion.

Deutsche Bank: €21.26 billion (~$22.53 billion assuming €1 = $1.06).

Analysis: BOFA has a significantly higher credit risk capital requirement, reflecting a larger portfolio of loans and counterparty exposures.

2. Market Risk Capital

BOFA: $9.52 billion.

Deutsche Bank: €1.72 billion (~$1.82 billion).

Analysis: BOFA’s market risk exposure is much larger, likely due to extensive trading and investment activities in global markets.

3. Operational Risk Capital

BOFA: $28.56 billion.

Deutsche Bank: €4.57 billion (~$4.84 billion).

Analysis: BOFA’s operational risk capital is significantly higher, suggesting more complex operations or a larger geographic presence requiring higher reserves. As we know, operational risk includes people, systems and internal procedures, so the higher the amount of operations and the larger geographic extension, the riskier and more difficult to manage it gets.

Conclusion: Which Bank Has a Better Capital Base?

BOFA: Higher overall capital requirements reflect its vast operations, larger asset base, and significant global market presence. However, the higher operational and market risk capital requirements indicate greater risk exposure.

Deutsche Bank: Relatively lower capital requirements across all categories suggest a smaller global footprint or less complex operations. However, this could also reflect differences in risk appetite or operational scale.

Better Capital Base: BOFA holds a stronger capital base in absolute terms, given its higher capital allocations. However, Deutsche Bank’s lower risk exposures may translate into a more efficient capital structure. The choice depends on whether one prioritizes absolute strength (BOFA) or relative efficiency (Deutsche Bank).

LS0tDQp0aXRsZTogIkZpbmFuY2lhbCBNYXJrZXRzIFByb2plY3QiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KIyMgQXV0aG9yczogIkpvc8OpIEx1aXMgU3XDoXJleiBHb256w6FsZXogKDEzNzU3NikgYW5kIEpha2UgT2xpdmVyIEdvZGRhcmQgKDEzNzYzMykiDQojIyBEYXRlOiAiMDItMTItMjAyNCINCiMjIFRlYW0gcGFydGljaXBhdGlvbnM6DQpKb3PDqSBMdWlzIFN1w6FyZXo6IENvZGUgd3JpdGluZyBhbmQgYW5hbHlzaXMgb2YgcmVzdWx0cw0KSmFrZSBPbGl2ZXIgR29kZGFyZDogcHJvamVjdCBzdHJ1Y3R1cmluZywgcmV2aXNpbmcgYW5kIGNvcnJlY3RpbmcgbWlzdGFrZXMgb2YgdGhlIG91dGNvbWUuIA0KDQojIyBBdXRob3JzJyBzdGF0ZW1lbnQgb2Ygbm9uLWluZnJpZ2VtZW50IG9mIG90aGVycycgY29weXJpZ2h0cw0KV2UgaGVyZWJ5IGRlY2xhcmUgdGhhdCB0aGUgd29yayBzdWJtaXR0ZWQgaXMgb3JpZ2luYWwgYW5kIGhhcyBiZWVuIGNyZWF0ZWQgc29sZWx5IGJ5IHVzLiBXZSBjb25maXJtIHRoYXQgd2UgaGF2ZSBub3QgdXNlZCBvciBpbmNvcnBvcmF0ZWQgYW55IG1hdGVyaWFsIHRoYXQgaW5mcmluZ2VzIHVwb24gdGhlIGNvcHlyaWdodHMgb2Ygb3RoZXJzLiBBbGwgc291cmNlcyBhbmQgcmVmZXJlbmNlcyB1c2VkIGluIHRoZSBjcmVhdGlvbiBvZiB0aGlzIHdvcmsgaGF2ZSBiZWVuIHByb3Blcmx5IGFja25vd2xlZGdlZCBhbmQgY2l0ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIGFwcGxpY2FibGUgZ3VpZGVsaW5lcy4NCg0KIyMgIEF1dGhvcnPigJkgc3RhdGVtZW50IGFzIHRvIGhvdyB0aGUgQUkgdG9vbCB3YXMgdXNlZCBkdXJpbmcgdGhlIGFzc2lnbm1lbnQuDQojIyMgTmFtZXMgb2YgVG9vbHMgYW5kIExpbmtzOiANCk9wZW5BSSdzIENoYXRHUFQgKGh0dHBzOi8vb3BlbmFpLmNvbSkuIFZlcnNpb24gdXNlZDogQ2hhdEdQVCBvMS1wcmV2aWV3DQoNCiMjIyBTY29wZSBvZiBBcHBsaWNhdGlvbjogDQpUaGUgQUkgdG9vbCB3YXMgdXRpbGl6ZWQgdG8gZ2VuZXJhdGUgc3RydWN0dXJlZCBleHBsYW5hdGlvbnMsIGFuYWx5emUgZGF0YSB0cmVuZHMsIGFuZCByZWZpbmUgbGFuZ3VhZ2UgZm9yIGNsYXJpdHkgYW5kIGNvaGVyZW5jZS4gSXQgaGFzIGFsc28gYmVlbiB1dGlsaXplZCBhcyB0b29sIGZvciBvcHRpbWl6YXRpb24gYW5kIGVycm9yLXNvbHZpbmcgb2YgdGhlIHByb2R1Y2VkIGNvZGVzLiANCg0KIyMjIFF1YWxpdHkgQ29udHJvbCBQcm9jZWR1cmVzOiANCkdlbmVyYXRlZCBvdXRwdXRzIHdlcmUgcmlnb3JvdXNseSByZXZpZXdlZCBieSB0aGUgYXV0aG9ycyB0byBlbnN1cmUgYWNjdXJhY3ksIHJlbGV2YW5jZSwgYW5kIGFsaWdubWVudCB3aXRoIHRoZSBhc3NpZ25tZW50J3MgcmVxdWlyZW1lbnRzLiBBbGwgZmluYWwgY29udGVudCB1bmRlcndlbnQgbWFudWFsIHZlcmlmaWNhdGlvbiBhbmQgZWRpdHMuDQoNCiMjIyBSZXNwb25zaWJpbGl0eSBTdGF0ZW1lbnQ6IA0KV2UgYXNzdW1lIGZ1bGwgcmVzcG9uc2liaWxpdHkgZm9yIHRoZSBjb250ZW50IG9mIHRoaXMgd29yaywgaW5jbHVkaW5nIGFjY3VyYWN5LCBpbnRlZ3JpdHksIGFuZCBvcmlnaW5hbGl0eS4NCg0KDQoNCiMjIEwxIEludHJvDQoNCiMjIyBMMS4xIFVzZSBzdG9jayBleGNoYW5nZSBxdW90YXRpb25zIHRvIHJlY29yZCB0aGUgc3RvY2sgcHJpY2UgYW5kIGRpdmlkZW5kIG9mIG9uZSBzdG9jayBmcm9tIGVhY2ggc3RvY2sgZXhjaGFuZ2UgaW4gd2hpY2ggeW91IHdvdWxkIGxpa2UgdG8gaW52ZXN0Lg0KDQpTdGFydGluZyBxdWFudG1vZA0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpgYGANCg0KDQpGdW5jdGlvbiB0byBnZXQgdGhlIHN5bWJvbHMgb24gdGhlIHRpbWUgcGVyaW9kIHJlcXVpcmVkIA0KDQpgYGB7cn0NCmdldF9zdG9ja19pbmZvX2J5X2RhdGUgPC0gZnVuY3Rpb24oc3ltYm9sLCBCb1RfZGF0ZSwgRW9UX2RhdGUpew0KICAgICBzdG9ja19kYXRhIDwtIGdldFN5bWJvbHMoc3ltYm9sLCBmcm9tID0gQm9UX2RhdGUsIHRvID0gRW9UX2RhdGUsIGF1dG8uYXNzaWduID0gRkFMU0UpDQogICAgIHN0YXJ0X3ByaWNlIDwtIGFzLm51bWVyaWMoQ2woc3RvY2tfZGF0YVtCb1RfZGF0ZV0pKQ0KICAgICBlbmRfcHJpY2UgPC0gYXMubnVtZXJpYyhDbChzdG9ja19kYXRhW0VvVF9kYXRlXSkpDQogICAgIGlmIChpcy5udWxsKGVuZF9wcmljZSkgfHwgbGVuZ3RoKGVuZF9wcmljZSkgPT0gMCB8fCBpcy5uYShhcy5udW1lcmljKGVuZF9wcmljZSkpKSB7DQogICAgICAgICBlbmRfcHJpY2UgPC0gYXMubnVtZXJpYyhDbChsYXN0KHN0b2NrX2RhdGFbcGFzdGUwKCIvIiwgRW9UX2RhdGUpXSkpKX0gZWxzZSB7DQogIGVuZF9wcmljZSA8LSBhcy5udW1lcmljKGVuZF9wcmljZSl9DQogICAgIGRpdmlkZW5kcyA8LSBnZXREaXZpZGVuZHMoc3ltYm9sLCBmcm9tID0gQm9UX2RhdGUsIHRvID0gRW9UX2RhdGUsIGF1dG8uYXNzaWduID0gRkFMU0UpDQogICAgIHN0YXJ0X2RpdmlkZW5kIDwtIGlmIChCb1RfZGF0ZSAlaW4lIGluZGV4KGRpdmlkZW5kcykpIHthcy5udW1lcmljKGRpdmlkZW5kc1tCb1RfZGF0ZV0pfSBlbHNlIE5BDQogICAgIGlmIChpcy5udWxsKHN0YXJ0X2RpdmlkZW5kKSB8fCBsZW5ndGgoc3RhcnRfZGl2aWRlbmQpID09IDAgfHwgaXMubmEoYXMubnVtZXJpYyhzdGFydF9kaXZpZGVuZCkpKSB7DQogICAgICAgICBzdGFydF9kaXZpZGVuZCA8LSBhcy5udW1lcmljKGxhc3QoZGl2aWRlbmRzW3Bhc3RlMCgiLyIsIEVvVF9kYXRlKV0pKX0gZWxzZSB7DQogICAgICAgICBzdGFydF9kaXZpZGVuZCA8LSBhcy5udW1lcmljKHN0YXJ0X2RpdmlkZW5kKX0NCiAgICAgZW5kX2RpdmlkZW5kIDwtIGlmKEVvVF9kYXRlICVpbiUgaW5kZXgoZGl2aWRlbmRzKSkgYXMubnVtZXJpYyhkaXZpZGVuZHNbRW9UX2RhdGVdKQ0KICAgICBpZiAoaXMubnVsbChlbmRfZGl2aWRlbmQpIHx8IGxlbmd0aChlbmRfZGl2aWRlbmQpID09IDAgfHwgaXMubmEoYXMubnVtZXJpYyhlbmRfZGl2aWRlbmQpKSkgew0KICAgICAgICAgZW5kX2RpdmlkZW5kIDwtIGFzLm51bWVyaWMobGFzdChkaXZpZGVuZHNbcGFzdGUwKCIvIiwgRW9UX2RhdGUpXSkpfSBlbHNlIHsNCiAgICAgICAgIGVuZF9kaXZpZGVuZCA8LSBhcy5udW1lcmljKGVuZF9kaXZpZGVuZCl9DQogICAgIGxpc3QoDQogICAgICAgICBTdGFydF9QcmljZT0gc3RhcnRfcHJpY2UsDQogICAgICAgICBFbmRfUHJpY2U9IGVuZF9wcmljZSwNCiAgICAgICAgIFN0YXJ0X0RpdmlkZW5kPSBzdGFydF9kaXZpZGVuZCwNCiAgICAgICAgIEVuZF9EaXZpZGVuZD0gZW5kX2RpdmlkZW5kDQogICAgICkNCiB9DQoNCg0KYGBgDQoNCg0KRGV0ZXJtaW5pbmcgdGhlIGRhdGVzIG9mIGJlZ2lubmluZyBhbmQgZW5kDQoNCmBgYHtyfQ0KQm9UX2RhdGUgPC0gIjIwMjQtMDUtMDEiDQpFb1RfZGF0ZSA8LSAiMjAyNC0wOS0zMCINCmBgYA0KDQoNCkRldGVybWluaW5nIHRoZSBzdG9jayBzeW1ib2xzDQoNCmBgYHtyfQ0KbnlzZV9zdG9jayA8LSAiSUJNIg0KbmFzZGFxX3N0b2NrIDwtICJTQlVYIg0KYGBgDQoNCg0KUmV0cmlldmUgaW5mb3JtYXRpb24gZnJvbSBlYWNoIHN0b2NrDQoNCmBgYHtyfQ0KbnlzZV9pbmZvIDwtIGdldF9zdG9ja19pbmZvX2J5X2RhdGUobnlzZV9zdG9jaywgQm9UX2RhdGUsIEVvVF9kYXRlKQ0KbmFzZGFxX2luZm8gPC0gZ2V0X3N0b2NrX2luZm9fYnlfZGF0ZShuYXNkYXFfc3RvY2ssIEJvVF9kYXRlLCBFb1RfZGF0ZSkNCg0KYGBgDQoNCg0KQ3JlYXRlIGEgZGF0YSBmcmFtZSB0byBkaXNwbGF5IHRoZSByZXN1bHRzDQoNCmBgYHtyfQ0Kc3RvY2tfZGF0YSA8LSBkYXRhLmZyYW1lKA0KICBFeGNoYW5nZSA9IGMoIk5ldyBZb3JrIFN0b2NrIEV4Y2hhbmdlIiwgIk5hc2RhcSBNYXJrZXQiKSwNCiAgRmlybSA9IGMobnlzZV9zdG9jaywgbmFzZGFxX3N0b2NrKSwNCiAgQm9UX1ByaWNlID0gYyhueXNlX2luZm8kU3RhcnRfUHJpY2UsIG5hc2RhcV9pbmZvJFN0YXJ0X1ByaWNlKSwNCiAgRW9UX1ByaWNlID0gYyhueXNlX2luZm8kRW5kX1ByaWNlLCBuYXNkYXFfaW5mbyRFbmRfUHJpY2UpLA0KICBCb1RfRGl2aWRlbmQgPSBjKG55c2VfaW5mbyRTdGFydF9EaXZpZGVuZCwgbmFzZGFxX2luZm8kU3RhcnRfRGl2aWRlbmQpLA0KICBFb1RfRGl2aWRlbmQgPSBjKG55c2VfaW5mbyRFbmRfRGl2aWRlbmQsIG5hc2RhcV9pbmZvJEVuZF9EaXZpZGVuZCkpDQpwcmludChzdG9ja19kYXRhKQ0KYGBgDQoNCiMjIyMgQW5hbHlzaXMgb2YgcmVzdWx0cy4gDQpJbiB0aGlzIGV4ZXJjaXNlIHdlIGhhdmUgb2J0YWluZWQgdGhlIHN0b2NrIHByaWNlcyBhbmQgZGl2aWRlbmQgb2YgYW4gc3RvY2sgZnJvbSB0aGUgTmV3IFlvcmsgU3RvY2sgRXhjaGFuZ2UgYW5kIGFub3RoZXIgZnJvbSB0aGUgTmFzZGFxIE1hcmtldCwgYm90aCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybSBkYXRlIChCb1QgZGF0ZSkgYW5kIHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtIGRhdGUgKEVvVCBkYXRlKQ0KRm9yIHRoZSBkZXZlbG9wbWVudCBvZiB0aGlzIGV4ZXJjaXNlLCB3ZSBoYXZlIGRlc2lnbmVkIGEgZnVuY3Rpb24gd2hpY2ggYWxsb3dzIHVzIHRvIGV4dHJhY3QgdGhlIHN0b2NrIHByaWNlIGFzIHdlbGwgYXMgdGhlIGRpdmlkZW5kLCBnaXZpbmcgYSBzb2x1dGlvbiB0byBtYW5hZ2UgdGhlIGxhY2sgb2YgZGF0YSBhdCB0aGUgRW9UIGRhdGUsIHdoaWNoIGlzIGEgbm9uLXRyYWRpbmcgZGF5LiBJbiB0aGlzIHNvbHV0aW9uLCB3aGljaCB3ZSB3aWxsIGhhdmUgdG8gZnVydGhlciBpbXBsZW1lbnQgaW4gdGhlIHJlc3Qgb2YgZXhlcmNpc2VzIHRoYXQgaW52b2x2ZSBvYnRhaW5pbmcgZGF0YSBhdCBFb1QgZGF0ZSwgd2UgaGF2ZSBnaXZlbiBhbiBvcmRlciB0byB1c2UgdGhlIGxhc3QgYXZhaWxhYmxlIGRhdGEgd2hlbiB0aGUgZGF0ZSBzZWxlY3RlZCBoYXMgbm8gYXZhaWxhYmxlIGRhdGEuIEFkZGl0aW9uYWxseSwgYWx0aG91Z2ggaXQgd2lsbCBwcm9iYWJseSBub3QgYmUgbmVlZGVkLCB3ZSBoYXZlIGltcGxlbWVudGVkIGFuIGVxdWl2YWxlbnQgc3lzdGVtIGZvciBvYnRhaW5pbmcgdGhlIGRhdGEgb24gQm9UIGRhdGUsIHNvIHRoYXQgaWYgd2UgZW5jb3VudGVyIGEgbWlzc2luZyB2YWx1ZSwgd2Ugd2lsbCB1c2UgdGhlIG5leHQgYXZhaWxhYmxlIGRhdGEuIA0KUmVnYXJkaW5nIHRoZSByZXN1bHRzIG9mIHRoZSBleGVyY2lzZSwgd2UgY2FuIG9ic2VydmUgYW4gaW5jcmVhc2UgaW4gdGhlIHByaWNlIG9mIHRoZSBvZiBib3RoIHN0b2NrcyBkdXJpbmcgdGhlIHNjaG9vbCB0ZXJtLiBUaGUgaW5jcmVhc2luZyBwcmljZXMgdXN1YWxseSByZXZvbHZlIGFyb3VuZCBwb3NpdGl2ZSBmdXR1cmUgZXhwZWN0YW5jeSBvZiB0aGUgY29tcGFuaWVzIGFzIHdlbGwgYXMgYSBmYXZvcmFibGUgcHJlc2VudGF0aW9uIG9mIHJlc3VsdHMgYXQgdGhlIGVuZCBvZiBlYWNoIHF1YXJ0ZXIuIA0KVGhlIGRpdmlkZW5kcyBoYXZlIG5vdCBzZWVuIG5laXRoZXIgYW4gaW5jcmVhc2Ugbm9yIGEgZGVjcmVhc2UsIHdoaWNoIGluZGljYXRlcyBzdGFiaWxpdHkgaW4gdGhlaXIgaW50ZXJuYWwgZmluYW5jaWFsIG9yZ2FuaXphdGlvbiBhbmQgZ2l2ZXMgYSBmdXJ0aGVyIHNlbnNlIG9mIHNhZmVuZXNzIHRvIHRoZWlyIHN0b2NraG9sZGVycy4gDQoNCg0KDQojIyMgTDEuMiBVc2UgZnV0dXJlcyBwcmljZXMgcXVvdGF0aW9ucyB0byByZWNvcmQgdGhlIHJlY2VudCAo4oCcc2V0dGxl4oCdKSBwcmljZSBvZiB0aGUgZm9sbG93aW5nIGZ1dHVyZXMgKHNlbGVjdCBmdXR1cmVzIHdpdGggZmlyc3Qgc2V0dGxlbWVudCBkYXRlIGJleW9uZCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybSkgDQoNCkNyZWF0aW5nIGZ1bmN0aW9uIHRvIGV4dHJhY3QgdGhlIHZhbHVlcw0KDQpgYGB7cn0NCmdldF9fZnV0dXJlc19kYXRhX2J5X2RhdGUgPC0gZnVuY3Rpb24oc3ltYm9sLCBmcm9tID0gQm9UX2RhdGUsIHRvID0gRW9UX2RhdGUpIHsNCiAgICAgZnV0dXJlc19kYXRhIDwtIGdldFN5bWJvbHMoc3ltYm9sLCBmcm9tID0gQm9UX2RhdGUsIHRvID0gRW9UX2RhdGUsIGF1dG8uYXNzaWduID0gRkFMU0UpDQogICAgIGlmIChpcy5udWxsKGZ1dHVyZXNfZGF0YSkgfHwgbnJvdyhmdXR1cmVzX2RhdGEpID09IDApIHsNCiAgICAgICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgZm91bmQgZm9yIHN5bWJvbDoiLCBzeW1ib2wpKQ0KICAgICAgICAgcmV0dXJuKE5BKQ0KICAgICB9DQogICAgQm9UX3ByaWNlIDwtIGFzLm51bWVyaWMoQ2woZnV0dXJlc19kYXRhW0JvVF9kYXRlXSkpDQogRW9UX2RhdGEgPC0gZnV0dXJlc19kYXRhW3Bhc3RlMCgiLyIsIEVvVF9kYXRlKV0NCiBpZihucm93KEVvVF9kYXRhKSA9PSAwKSB7DQogICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIG9uIG9yIGJlZm9yZSBFb1RfZGF0ZSBmb3Igc3ltYm9sOiIsIHN5bWJvbCkpDQogICAgIEVvVF9wcmljZSA8LSBOQQ0KIH0gZWxzZSB7DQogICAgIEVvVF9wcmljZSA8LSBhcy5udW1lcmljKGxhc3QoQ2woRW9UX2RhdGEpKSkNCiB9DQogcmV0dXJuKGxpc3QoDQogICAgIFN5bWJvbCA9IHN5bWJvbCwNCiAgICAgQm9UX1ByaWNlID0gQm9UX3ByaWNlLA0KICAgICBFb1RfUHJpY2UgPSBFb1RfcHJpY2UNCiApKQ0KIH0NCmBgYA0KDQp1c2UgdGhlIGZ1bmN0aW9uIGZvciBlYWNoIGZ1dHVyZXMgY29udHJhY3QNCg0KYGBge3J9DQp0cmVhc3VyeV9ib25kIDwtIGdldF9fZnV0dXJlc19kYXRhX2J5X2RhdGUoIlpCPUYiLCBCb1RfZGF0ZSwgRW9UX2RhdGUpDQogIHNwNTAwX2Z1dHVyZXMgPC0gZ2V0X19mdXR1cmVzX2RhdGFfYnlfZGF0ZSgiRVM9RiIsIEJvVF9kYXRlLCBFb1RfZGF0ZSkNCiAgbmFzZGFxIDwtIGdldF9fZnV0dXJlc19kYXRhX2J5X2RhdGUoIl5JWElDIiwgQm9UX2RhdGUsIEVvVF9kYXRlKQ0KIGJyaXRpc2hfcG91bmQgPC0gZ2V0X19mdXR1cmVzX2RhdGFfYnlfZGF0ZSgiNkI9RiIsIEJvVF9kYXRlLCBFb1RfZGF0ZSkNCmBgYA0KDQoNCmJ1aWxkIHRoZSBkYXRhIGZyYW1lDQoNCmBgYHtyfQ0KZnV0dXJlX3ByaWNlcyA8LSBkYXRhLmZyYW1lKA0KICBBc3NldCA9IGMoDQogICAgIlRyZWFzdXJ5IEJvbmQgRnV0dXJlcyBEZWMgMjAyNCIsDQogICAgIlMmUCA1MDAgRnV0dXJlcyBEZWMgMjAyNCIsDQogICAgIk5hc2RhcSBDb21wb3NpdGUgSW5kZXgiLA0KICAgICJCcml0aXNoIFBvdW5kIEZ1dHVyZXMgRGVjIDIwMjQiDQogICksDQogIFN5bWJvbCA9IGMoDQogICAgdHJlYXN1cnlfYm9uZCRTeW1ib2wsDQogICAgc3A1MDBfZnV0dXJlcyRTeW1ib2wsDQogICAgbmFzZGFxJFN5bWJvbCwNCiAgICBicml0aXNoX3BvdW5kJFN5bWJvbA0KICApLA0KICBCb1RfUHJpY2UgPSBjKA0KICAgIHRyZWFzdXJ5X2JvbmQkQm9UX1ByaWNlLA0KICAgIHNwNTAwX2Z1dHVyZXMkQm9UX1ByaWNlLA0KICAgIG5hc2RhcSRCb1RfUHJpY2UsDQogICAgYnJpdGlzaF9wb3VuZCRCb1RfUHJpY2UNCiAgKSwNCiAgRW9UX1ByaWNlID0gYygNCiAgICB0cmVhc3VyeV9ib25kJEVvVF9QcmljZSwNCiAgICBzcDUwMF9mdXR1cmVzJEVvVF9QcmljZSwNCiAgICBuYXNkYXEkRW9UX1ByaWNlLA0KICAgIGJyaXRpc2hfcG91bmQkRW9UX1ByaWNlDQogICkNCikNCmBgYA0KDQpQcmludCB0aGUgZGF0YSBmcmFtZQ0KDQpgYGB7cn0NCnByaW50KGZ1dHVyZV9wcmljZXMpDQpgYGANCg0KIyMjIyBBbmFseXNpcyBvZiB0aGUgcmVzdWx0cw0KSW4gdGhpcyBjYXNlLCB3ZSBoYXZlIGNyZWF0ZWQgYSBmdW5jdGlvbiBpbiBvcmRlciB0byByZXRyaWV2ZSB0aGUgc2V0dGxlIHByaWNlIG9mIHRoZSBkaWZmZXJlbnQgdHlwZXMgb2YgZnV0dXJlcywgd2l0aCB0aGUgZmlyc3Qgc2V0dGxlbWVudCBkYXRlIGJleW9uZCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybS4gQXMgZG9uZSBiZWZvcmUsIHdlIGhhdmUgYWRqdXN0ZWQgdGhlIGZ1bmN0aW9uIHRvIG1hbmFnZSBub24tdHJhZGluZyBkYXlzLiANCkluIHRoZSBkYXRhIG9idGFpbmVkIHdlIGNhbiBvYnNlcnZlIGFuIGluZGl2aWR1YWwgYXBwcmVjaWF0aW9uIG9mIGVhY2ggb2YgdGhlaXIgcHJpY2VzLCB3aGljaCBtYXkgaW5kaWNhdGUgYW4gb3ZlcmFsbCBncm93dGggaW4gZWNvbm9teS4gSG93ZXZlciwgc29tZSBvdGhlciBmYWN0b3JzIHRoYXQgdXN1YWxseSBhZmZlY3QgZnV0dXJlcyBwcmljZXMsIHN1Y2ggYXMgaW50ZXJlc3QgcmF0ZXMsIG1hY3JvZWNvbm9taWMgZGVjaXNpb25zLCB0aGUgbWFya2V0IHByZWZlcmVuY2VzIGFuZCBzdXBwbHkgYW5kIGRlbWFuZCBjYW4gaGF2ZSBhIHNpZ25pZmljYW50IGltcGFjdCBpbiB0aGUgcHJpY2luZyBvZiB0aGVzZSBhc3NldHMuIA0KDQoNCg0KIyMjIEwxLjMgVXNlIGFuIG9wdGlvbnMgcXVvdGF0aW9ucyB0YWJsZSB0byBzZWxlY3QgYSBjYWxsIG9wdGlvbiBvbiBhIGZpcm0gd2hvc2Ugc3RvY2sgcHJpY2UgeW91IGV4cGVjdCB0byBpbmNyZWFzZSAoc2VsZWN0IHRoZSBvcHRpb24gd2l0aCB0aGUgZmlyc3QgZXhwaXJhdGlvbiBtb250aCBiZXlvbmQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0pDQoNCg0KSW5zdGFsbCBhbmQgbG9hZCBwYWNrYWdlcw0KYGBge3J9DQojIExvYWQgcGFja2FnZXMNCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh0aW1lRGF0ZSkNCmxpYnJhcnkoUlF1YW50TGliKQ0KDQpgYGANCg0KRGVmaW5lIEJvVCBhbmQgRW9UIGRhdGVzDQoNCmBgYHtyfQ0KQm9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNS0wMSIpDQpFb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCmBgYA0KDQoNCkNyZWF0ZSBmdW5jdGlvbiB0byBhZGp1c3QgdG8gbm9uLXRyYWRpbmcgZGF0ZXMgYW5kIG9idGFpbiBzdG9jayBpbmZvcm1hdGlvbg0KDQpgYGB7cn0NCiNnZXR0aW5nIHRoZSBzeW1ib2xzDQpnZXRfc3RvY2tfcHJpY2UgPC0gZnVuY3Rpb24oc3ltYm9sLCBkYXRlLCB1c2VfbmV4dCA9IEZBTFNFKSAgew0KICAgIGRhdGEgPC0gZ2V0U3ltYm9scygNCiAgICAgICAgU3ltYm9scyA9IHN5bWJvbCwNCiAgICAgICAgZnJvbSA9IGRhdGUgLSBkYXlzKDEwKSwNCiAgICAgICAgdG8gPSBkYXRlICsgZGF5cygxMCksDQogICAgICAgIGF1dG8uYXNzaWduID0gRkFMU0UNCg0KICAgICkNCiAgICAjc29sdmluZyBpc3N1ZXMgd2l0aCBub24tdHJhZGluZyBkYXlzDQogICAgaW5kZXgoZGF0YSkgPC0gYXMuRGF0ZShpbmRleChkYXRhKSkNCiAgICBpZiAodXNlX25leHQpIHsNCiAgICAgICAgYXZhaWxhYmxlX2RhdGVzIDwtIGluZGV4KGRhdGEpW2luZGV4KGRhdGEpID49IGRhdGVdDQogICAgICAgIGlmKGxlbmd0aChhdmFpbGFibGVfZGF0ZXMpID09IDApIHsNCiAgICAgICAgICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIGFmdGVyIiwgZGF0ZSwgImZvciBzeW1ib2w6Iiwgc3ltYm9sKSkNCiAgICAgICAgICAgIHJldHVybihOQSkNCiAgICAgICAgfQ0KICAgICAgICBkYXRlX3VzZWQgPC0gbWluKGF2YWlsYWJsZV9kYXRlcykNCiAgICB9IGVsc2Ugew0KICAgICAgICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPD0gZGF0ZV0gDQogICAgICAgIGlmIChsZW5ndGgoYXZhaWxhYmxlX2RhdGVzKSA9PSAwKSB7DQogICAgICAgICAgICB3YXJuaW5nKHBhc3RlKCJObyBkYXRhIGF2YWlsYWJsZSBiZWZvcmUiLCBkYXRlLCAiZm9yIHN5bWJvbDoiLCBzeW1ib2wpKQ0KICAgICAgICAgICAgcmV0dXJuKE5BKQ0KICAgICAgICB9DQogICAgICAgIGRhdGVfdXNlZCA8LSBtYXgoYXZhaWxhYmxlX2RhdGVzKQ0KICAgIH0NCiAgICNvYnRhaW5pbmcgcHJpY2UNCiAgICAgcHJpY2UgPC0gYXMubnVtZXJpYyhDbChkYXRhW2RhdGVfdXNlZF0pKQ0KICAgIHJldHVybihsaXN0KA0KICAgICAgICBQcmljZSA9IHByaWNlLCBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICAgKSkNCn0NCmBgYA0KDQoNCkdldHRpbmcgdGhlIGRhdGEgZm9yIG91ciBzZWxlY3RlZCBzdG9jaw0KDQpgYGB7cn0NCkJvVF9zdG9jayA8LSBnZXRfc3RvY2tfcHJpY2UoIkJBQkEiLCBCb1RfZGF0ZSwgdXNlX25leHQgPSBUUlVFKQ0KRW9UX3N0b2NrIDwtIGdldF9zdG9ja19wcmljZSgiQkFCQSIsIEVvVF9kYXRlLCB1c2VfbmV4dCA9IEZBTFNFKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIE9wdGlvbiBQcmVtaXVtcyBvbiBCb1QgYW5kIEVvVC4NCk9wdGlvbiBUeXBlOiBDYWxsIE9wdGlvbg0KU3RyaWtlIFByaWNlOiBDbG9zZXN0IHRvIHRoZSBzdG9jayBwcmljZSBhdCBCb1RfZGF0ZQ0KRXhwaXJhdGlvbiBEYXRlOiBGaXJzdCBPcHRpb24gZXhwaXJhdGlvbiBkYXRlIGJleW9uZCBFb1RfRGF0ZQ0KDQpgYGB7cn0NCiMgTG9hZCBuZWNlc3NhcnkgcGFja2FnZXMNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh0aW1lRGF0ZSkNCg0KIyBJbml0aWFsaXplIGV4cGlyYXRpb25fZGF0ZXMgYXMgYW4gZW1wdHkgdmVjdG9yIG9mIGNsYXNzIERhdGUNCmV4cGlyYXRpb25fZGF0ZXMgPC0gYXMuRGF0ZShjaGFyYWN0ZXIoKSkNCg0KIyBHZXQgdGhlIGN1cnJlbnQgZGF0ZQ0KY3VycmVudF9kYXRlIDwtIGFzLkRhdGUoU3lzLkRhdGUoKSkNCg0KIyBEZWZpbmUgeW91ciBFb1RfZGF0ZQ0KRW9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wOS0zMCIpDQoNCiMgRGVmaW5lIHRoZSBjb3JyZWN0ZWQgdGhpcmRfZnJpZGF5IGZ1bmN0aW9uDQp0aGlyZF9mcmlkYXkgPC0gZnVuY3Rpb24oeWVhciwgbW9udGgpIHsNCiAgICAjIEdldCBhbGwgZGF5cyBpbiB0aGUgbW9udGgNCiAgICBkYXRlcyA8LSBzZXEoDQogICAgICAgIGZyb20gPSBhcy5EYXRlKHBhc3RlMCh5ZWFyLCAiLSIsIG1vbnRoLCAiLTAxIikpLA0KICAgICAgICB0byA9IGFzLkRhdGUocGFzdGUwKHllYXIsICItIiwgbW9udGgsICItIiwgZGF5c19pbl9tb250aChhcy5EYXRlKHBhc3RlMCh5ZWFyLCAiLSIsIG1vbnRoLCAiLTAxIikpKSkpLA0KICAgICAgICBieSA9ICJkYXkiDQogICAgKQ0KICAgIA0KICAgICMgR2V0IGFsbCBGcmlkYXlzIHVzaW5nIHdkYXkoKQ0KICAgIGZyaWRheXMgPC0gZGF0ZXNbd2RheShkYXRlcykgPT0gNl0gICMgNiBjb3JyZXNwb25kcyB0byBGcmlkYXkNCiAgICANCiAgICAjIFJldHVybiB0aGUgdGhpcmQgRnJpZGF5DQogICAgaWYgKGxlbmd0aChmcmlkYXlzKSA+PSAzKSB7DQogICAgICAgIHJldHVybihmcmlkYXlzWzNdKQ0KICAgIH0gZWxzZSB7DQogICAgICAgIHJldHVybihOQSkNCiAgICB9DQp9DQoNCiMgTG9vcCBvdmVyIHRoZSBuZXh0IDE4IG1vbnRocw0KZm9yIChpIGluIDA6MTcpIHsNCiAgICAjIEFkZCBpIG1vbnRocyB0byB0aGUgY3VycmVudCBkYXRlDQogICAgZGF0ZSA8LSBjdXJyZW50X2RhdGUgJW0rJSBtb250aHMoaSkNCiAgICANCiAgICAjIEV4dHJhY3QgdGhlIHllYXIgYW5kIG1vbnRoDQogICAgeXIgPC0geWVhcihkYXRlKQ0KICAgIG1udGggPC0gbW9udGgoZGF0ZSkNCiAgICANCiAgICAjIENhbGN1bGF0ZSB0aGUgdGhpcmQgRnJpZGF5IG9mIHRoZSBtb250aA0KICAgIGV4cF9kYXRlIDwtIHRoaXJkX2ZyaWRheSh5ciwgbW50aCkNCiAgICANCiAgICBpZiAoIWlzLm5hKGV4cF9kYXRlKSkgew0KICAgICAgICBleHBpcmF0aW9uX2RhdGVzIDwtIGMoZXhwaXJhdGlvbl9kYXRlcywgZXhwX2RhdGUpDQogICAgfQ0KfQ0KDQojIEZpbHRlciBleHBpcmF0aW9uIGRhdGVzIGJleW9uZCBFb1RfZGF0ZQ0KZXhwaXJhdGlvbl9kYXRlcyA8LSBleHBpcmF0aW9uX2RhdGVzW2V4cGlyYXRpb25fZGF0ZXMgPiBFb1RfZGF0ZV0NCg0KIyBQcmludCB0aGUgZXhwaXJhdGlvbiBkYXRlcw0KcHJpbnQoZXhwaXJhdGlvbl9kYXRlcykNCg0KYGBgDQoNCg0KR2V0IHN0cmlrZSBwcmljZQ0KYGBge3J9DQpzdHJpa2VfcHJpY2UgPC0gcm91bmQoQm9UX3N0b2NrJFByaWNlLCBkaWdpdHMgPSAtMSkgICMgUm91bmQgdG8gbmVhcmVzdCAxMA0KDQpgYGANCg0KDQpFc3RpbWF0ZSB2b2xhdGlsaXR5DQpgYGB7cn0NCiMgR2V0IGhpc3RvcmljYWwgc3RvY2sgcHJpY2VzIGZvciB0aGUgcGFzdCB5ZWFyIGJlZm9yZSBCb1RfZGF0ZQ0KdGlja2VyIDwtICJCQUJBIg0Kdm9sX2RhdGEgPC0gZ2V0U3ltYm9scygNCiAgU3ltYm9scyA9IHRpY2tlciwNCiAgc3JjID0gInlhaG9vIiwNCiAgZnJvbSA9IEJvVF9zdG9jayREYXRlIC0geWVhcnMoMSksDQogIHRvID0gQm9UX3N0b2NrJERhdGUsDQogIGF1dG8uYXNzaWduID0gRkFMU0UNCikNCg0KIyBDYWxjdWxhdGUgZGFpbHkgcmV0dXJucw0KcmV0dXJucyA8LSBkYWlseVJldHVybihDbCh2b2xfZGF0YSkpDQoNCiMgQ2FsY3VsYXRlIGFubnVhbGl6ZWQgdm9sYXRpbGl0eQ0Kdm9sYXRpbGl0eSA8LSBzZChyZXR1cm5zLCBuYS5ybSA9IFRSVUUpICogc3FydCgyNTIpICAjIDI1MiB0cmFkaW5nIGRheXMgaW4gYSB5ZWFyDQoNCmBgYA0KDQoNClNldCByaXNrLWZyZWUgSW50ZXJlc3QgUmF0ZSBhbmQgRGl2aWRlbmQgWWllbGQNCg0KYGBge3J9DQojUmlzay1mcmVlIGludGVyZXN0IHJhdGUgKGUuZy4sIDIlIGFubnVhbGl6ZWQpDQpyaXNrX2ZyZWVfcmF0ZSA8LSAwLjAyDQojRGl2aWRlbmQgeWllbGQgKGZyb20gWWFob28gRmluYW5jZSBvciBzZXQgdG8gMC4wMDUgZm9yIDAuNSUpDQpkaXZpZGVuZF95aWVsZCA8LSAwLjA1DQpgYGANCg0KDQpDYWxjdWxhdGUgVGltZSB0byBFeHBpcmF0aW9uDQoNCmBgYHtyfQ0KIyBBc3N1bWluZyAnZXhwaXJhdGlvbl9kYXRlcycgaXMgYSB2ZWN0b3Igb2YgRGF0ZSBvYmplY3RzDQpleHBpcmF0aW9uX2RhdGVzIDwtIGV4cGlyYXRpb25fZGF0ZXNbZXhwaXJhdGlvbl9kYXRlcyA+IEVvVF9kYXRlXQ0KDQojIFNlbGVjdCB0aGUgZWFybGllc3QgZXhwaXJhdGlvbiBkYXRlIGJleW9uZCBFb1RfZGF0ZQ0KZXhwaXJhdGlvbl9kYXRlIDwtIGV4cGlyYXRpb25fZGF0ZXNbMV0NCg0KIyBUaW1lIHRvIGV4cGlyYXRpb24gZnJvbSBCb1RfZGF0ZQ0KdGltZV90b19leHBpcmF0aW9uX0JvVCA8LSBhcy5udW1lcmljKGV4cGlyYXRpb25fZGF0ZSAtIEJvVF9zdG9jayREYXRlKSAvIDM2NQ0KDQojIFRpbWUgdG8gZXhwaXJhdGlvbiBmcm9tIEVvVF9kYXRlDQp0aW1lX3RvX2V4cGlyYXRpb25fRW9UIDwtIGFzLm51bWVyaWMoZXhwaXJhdGlvbl9kYXRlIC0gRW9UX3N0b2NrJERhdGUpIC8gMzY1DQpgYGANCg0KDQpVc2UgQmxhY2stU2Nob2xlcyBNb2RlbCB0byBjYWxjdWxhdGUgT3B0aW9uIFByZW1pdW1zDQoNCmBgYHtyfQ0KI0Z1bmN0aW9uIHRvIGNhbGN1bGF0ZSBPcHRpb24gUHJlbWl1bQ0KY2FsY3VsYXRlX29wdGlvbl9wcmVtaXVtIDwtIGZ1bmN0aW9uKFMsIEssIHIsIHRpbWVfdG9fZXhwaXJhdGlvbiwgc2lnbWEsIGRpdmlkZW5kX3lpZWxkKSB7DQogIG9wdGlvbiA8LSBFdXJvcGVhbk9wdGlvbigNCiAgICB0eXBlID0gImNhbGwiLA0KICAgIHVuZGVybHlpbmcgPSBTLA0KICAgIHN0cmlrZSA9IEssDQogICAgZGl2aWRlbmRZaWVsZCA9IGRpdmlkZW5kX3lpZWxkLA0KICAgIHJpc2tGcmVlUmF0ZSA9IHIsDQogICAgbWF0dXJpdHkgPSB0aW1lX3RvX2V4cGlyYXRpb24sDQogICAgdm9sYXRpbGl0eSA9IHNpZ21hDQogICkNCiAgcmV0dXJuKG9wdGlvbiR2YWx1ZSkNCn0NCmBgYA0KDQoNCkNhbGN1bGF0ZSBPcHRpb24gUHJlbWl1bXMNCg0KYGBge3J9DQojIE9wdGlvbiBwcmVtaXVtIG9uIEJvVF9kYXRlDQpCb1RfcHJlbWl1bSA8LSBjYWxjdWxhdGVfb3B0aW9uX3ByZW1pdW0oDQogIFMgPSBCb1Rfc3RvY2skUHJpY2UsDQogIEsgPSBzdHJpa2VfcHJpY2UsDQogIHIgPSByaXNrX2ZyZWVfcmF0ZSwNCiAgdGltZV90b19leHBpcmF0aW9uID0gdGltZV90b19leHBpcmF0aW9uX0JvVCwNCiAgc2lnbWEgPSB2b2xhdGlsaXR5LA0KICBkaXZpZGVuZF95aWVsZCA9IGRpdmlkZW5kX3lpZWxkDQopDQoNCiMgT3B0aW9uIHByZW1pdW0gb24gRW9UX2RhdGUNCkVvVF9wcmVtaXVtIDwtIGNhbGN1bGF0ZV9vcHRpb25fcHJlbWl1bSgNCiAgUyA9IEVvVF9zdG9jayRQcmljZSwNCiAgSyA9IHN0cmlrZV9wcmljZSwNCiAgciA9IHJpc2tfZnJlZV9yYXRlLA0KICB0aW1lX3RvX2V4cGlyYXRpb24gPSB0aW1lX3RvX2V4cGlyYXRpb25fRW9ULA0KICBzaWdtYSA9IHZvbGF0aWxpdHksDQogIGRpdmlkZW5kX3lpZWxkID0gZGl2aWRlbmRfeWllbGQNCikNCmBgYA0KDQoNCkNyZWF0ZSB0YWJsZSBmb3IgcmVzdWx0cw0KYGBge3J9DQpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoDQogICAgU3RvY2sgPSAiQkFCQSIsDQogICAgQm9UX0RhdGUgPSBCb1Rfc3RvY2skRGF0ZSwNCiAgICBCb1RfUHJpY2UgPSBCb1Rfc3RvY2skUHJpY2UsDQogICAgQm9UX09wdGlvbl9QcmVtaXVtID0gQm9UX3ByZW1pdW0sDQogICAgRW9UX0RhdGUgPSBFb1Rfc3RvY2skRGF0ZSwNCiAgICBFb1RfUHJpY2UgPSBFb1Rfc3RvY2skUHJpY2UsDQogICAgRW9UX09wdGlvbl9QcmVtaXVtID0gRW9UX3ByZW1pdW0NCikNCnByaW50KHJlc3VsdHMpDQpgYGANCg0KDQojIyMjIEFuYWx5c2lzIG9mIHJlc3VsdHMNCkluIHRoaXMgZXhlcmNpc2Ugd2UgbXVzdCByZXRyaWV2ZSBkYXRhIG9mIGEgY2FsbCBkYXRhIGZyb20gYSBzdG9jayB3ZSBleHBlY3QgdG8gaW5jcmVhc2UuIEluIHRoZXNlIGNhc2UsIHdlIGhhdmUgY29uc2lkZXJlZCB0byB0YWtlIGludG8gYWNjb3VudCBBbGliYWJhICgiQkFCQSIpLCBhcyB3ZSBjb25zaWRlciB0aGF0IGlzIGEgY29tcGFueSB3aGljaCBpcyBjdXJyZW50bHkgdW5kZXJ2YWx1ZWQgYW5kIGhhcyBhIGh1Z2UgcG90ZW50aWFsIG9mIGdyb3d0aCBpbiB0ZXJtcyBvZiBzdG9jayBwcmljZS4gDQpGb3IgdGhlIGRldmVsb3BtZW50IG9mIHRoaXMgZXhlcmNpc2Ugd2UgaGF2ZSBkZXZlbG9wZWQgYSBuZXcgZnVuY3Rpb24gdG8gZ2V0IG91ciBzc3RvY2sgZGF0YSwgYnV0IGluIHRoaXMgY2FzZSB3ZSBoYXZlIGxlbmd0aGVuZWQgb3VyIHRpbWUgYnJhY2tldCB0byBvYnRhaW4gZGF0YSBib3RoIGZyb20gYmVmb3JlIEJvVCBkYXRlIGFuZCBhZnRlciBFb1QgZGF0ZS4gDQpXZSBoYXZlIGFsc28gZGVmaW5lZCB0aGUgZXhwaXJhdGlvbiBkYXRlcyB0byB0aGUgbW9udGgncyB0aGlyZCBGcmlkYXksIGFuZCB3ZSBoYXZlIHNldCB0aGUgZXhwaXJhdGlvbiBkYXRlcyBhdmFpbGFibGUgdG8gdGhvc2UgYWZ0ZXIgRW9UIGRhdGUuIEFmdGVyd2FyZHMgd2UgaGF2ZSBzdGFibGlzaGVkIHRoZSBzdHJpa2UgcHJpY2UgYW5kLCB3aXRoIHRoZSB1c2Ugb2YgYSBuZXcgZnVuY3Rpb24sIHdlIGhhdmUgY2FsY3VsYXRlZCB0aGUgdm9sYXRpbGl0eS4gQXMgb3VyIGxhc3Qgc3RlcHMgYmVmb3JlIGFwcGx5aW5nIHRoZSBCbGFjay1TY2hvbGVzIG1vZGVsLCB3ZSBoYXZlIGNhbGN1bGF0ZWQgb3VyIHRpbWUgdG8gZXhwaXJhdGlvbiBhbmQgd2UgaGF2ZSBlc3RhYmxpc2hlZCB0aGUgcmlzay1mcmVlIHJhdGUgYW5kIHRoZSBkaXZpZGVuZCB5aWVsZC4gDQpGaW5hbGx5LCB3ZSBoYXZlIGRlZmluZWQgb3VyIGZ1bmN0aW9uIGZvciBhcHBseWluZyB0aGUgQmxhY2stU2Nob2xlcyBtb2RlbCBhbmQgd2UgaGF2ZSByZXRyaWV2ZWQgdGhlIG9wdGlvbiBwcmVtaXVtcyBhdCBCb1QgZGF0ZSBhbmQgRW9UIGRhdGUuIA0KDQpUaGUgcmVzdWx0cyBvYnRhaW5lZCB0aGFua3MgdG8gdGhpcyBjb2RlIGhhcyBsZWQgdXMgdG8gcGVyY2VpdmUgYSBzaWduaWZpY2FudCBhcHByZWNpYXRpb24gaW4gdGhlIG9wdGlvbiBwcmVtaXVtLCB3aGljaCB3ZSBjYW4gYXR0cmlidXRlIHRvIGFuIGltcHJvdmVtZW50IG9mIHRoZSB1bmRlcmx5aW5nIGFzc2V0ICgiQkFCQSIpLiBBbHNvLCB3aGVuIHdlIG9ic2VydmUgdGhlIGNoYW5nZSBpbiBwcmljZSwgaXQgbWF0Y2hlcyB3aXRoIHRoZSBvYnNlcnZhdGlvbiBpbiB0aGUgcHJlbWl1bXMsIG92ZXJhbGwgZGV0ZXJtaW5pbmcgdGhlIGdyZWF0IHBlcmZvcm1hbmNlIG9mIHRoZSBzZWxlY3RlZCBhc3NldCBkdXJpbmcgdGhlIHNjaG9vbCB0ZXJtLiANCg0KDQoNCiMjIyBMMS40IA0KDQpHZXR0aW5nIGRhdGEgZm9yIG91ciBzZWxlY3RlZCBzdG9jaw0KDQpgYGB7cn0NCiMgR2V0IHN0b2NrIHByaWNlcyBvbiBCb1QgYW5kIEVvVCBkYXRlcw0KQm9UX3N0b2NrIDwtIGdldF9zdG9ja19wcmljZSgiSU5HIiwgQm9UX2RhdGUsIHVzZV9uZXh0ID0gVFJVRSkNCkVvVF9zdG9jayA8LSBnZXRfc3RvY2tfcHJpY2UoIklORyIsIEVvVF9kYXRlLCB1c2VfbmV4dCA9IEZBTFNFKQ0KYGBgDQoNCg0KDQpDYWxjdWxhdGUgT3B0aW9uIFByZW1pdW1zIG9uIEJvVCBhbmQgRW9UDQogICtPcHRpb24gdHlwZTogcHV0IG9wdGlvbg0KICArU3RyaWtlIFByaWNlOiBDbG9zZXMgdG8gdGhlIFN0b2NrIHByaWNlIGF0IEJvVF9EYXRlDQogICtFeHBpcmF0aW9uIERhdGU6IEZpcnN0IG9wdGlvbiBleHBpcmF0aW9uIGRhdGUgYmV5b25kIEVvVF9kYXRlDQoNCg0KR2V0IFN0cmlrZSBQcmljZQ0KDQpgYGB7cn0NCiNSb3VuZCB0byB0aGUgbmVhcmVzdCAxMA0Kc3RyaWtlX3ByaWNlIDwtIHJvdW5kKEJvVF9zdG9jayRQcmljZSwgZGlnaXRzID0gLTEpIA0KYGBgDQoNCg0KRXN0aW1hdGUgVm9sYXRpbGl0eQ0KDQpgYGB7cn0NCiMgR2V0IGhpc3RvcmljYWwgc3RvY2sgcHJpY2VzIGZvciB0aGUgcGFzdCB5ZWFyIGJlZm9yZSBCb1RfZGF0ZQ0KdGlja2VyIDwtICJJTkciDQp2b2xfZGF0YSA8LSBnZXRTeW1ib2xzKA0KICBTeW1ib2xzID0gdGlja2VyLA0KICBzcmMgPSAieWFob28iLA0KICBmcm9tID0gQm9UX3N0b2NrJERhdGUgLSB5ZWFycygxKSwNCiAgdG8gPSBCb1Rfc3RvY2skRGF0ZSwNCiAgYXV0by5hc3NpZ24gPSBGQUxTRQ0KKQ0KDQojIENhbGN1bGF0ZSBkYWlseSByZXR1cm5zDQpyZXR1cm5zIDwtIGRhaWx5UmV0dXJuKENsKHZvbF9kYXRhKSkNCg0KIyBDYWxjdWxhdGUgYW5udWFsaXplZCB2b2xhdGlsaXR5DQp2b2xhdGlsaXR5IDwtIHNkKHJldHVybnMsIG5hLnJtID0gVFJVRSkgKiBzcXJ0KDI1MikgICMgMjUyIHRyYWRpbmcgZGF5cyBpbiBhIHllYXINCmBgYA0KDQoNClNldCBSaXNrLUZyZWUgSW50ZXJlc3QgUmF0ZSBhbmQgRGl2aWRlbmQgWWllbGQNCg0KYGBge3J9DQojUmlzay1mcmVlIGludGVyZXN0IHJhdGUgKDIlIGFubnVhbGl6ZWQgZm9yIGV4YW1wbGUpDQpyaXNrX2ZyZWVfcmF0ZSA8LSAwLjAyDQoNCiNEaXZpZGVuZCBZaWVsZCAobW9zdCByZWNlbnQpDQpkaXZpZGVuZF95aWVsZCA8LSAwLjA3NDkNCmBgYA0KDQoNCkNhbGN1bGF0ZSB0aW1lIHRvIGV4cGlyYXRpb24NCg0KYGBge3J9DQojIFRpbWUgdG8gZXhwaXJhdGlvbiBmcm9tIEJvVF9kYXRlDQp0aW1lX3RvX2V4cGlyYXRpb25fQm9UIDwtIGFzLm51bWVyaWMoZXhwaXJhdGlvbl9kYXRlIC0gQm9UX3N0b2NrJERhdGUpIC8gMzY1DQoNCiMgVGltZSB0byBleHBpcmF0aW9uIGZyb20gRW9UX2RhdGUNCnRpbWVfdG9fZXhwaXJhdGlvbl9Fb1QgPC0gYXMubnVtZXJpYyhleHBpcmF0aW9uX2RhdGUgLSBFb1Rfc3RvY2skRGF0ZSkgLyAzNjUNCg0KYGBgDQoNCg0KQ2FsY3VsYXRlIE9wdGlvbiBQcmVtaXVtcw0KDQpgYGB7cn0NCiMgT3B0aW9uIHByZW1pdW0gb24gQm9UX2RhdGUNCkJvVF9wcmVtaXVtIDwtIGNhbGN1bGF0ZV9vcHRpb25fcHJlbWl1bSgNCiAgUyA9IEJvVF9zdG9jayRQcmljZSwNCiAgSyA9IHN0cmlrZV9wcmljZSwNCiAgciA9IHJpc2tfZnJlZV9yYXRlLA0KICB0aW1lX3RvX2V4cGlyYXRpb24gPSB0aW1lX3RvX2V4cGlyYXRpb25fQm9ULA0KICBzaWdtYSA9IHZvbGF0aWxpdHksDQogIGRpdmlkZW5kX3lpZWxkID0gZGl2aWRlbmRfeWllbGQNCikNCg0KIyBPcHRpb24gcHJlbWl1bSBvbiBFb1RfZGF0ZQ0KRW9UX3ByZW1pdW0gPC0gY2FsY3VsYXRlX29wdGlvbl9wcmVtaXVtKA0KICBTID0gRW9UX3N0b2NrJFByaWNlLA0KICBLID0gc3RyaWtlX3ByaWNlLA0KICByID0gcmlza19mcmVlX3JhdGUsDQogIHRpbWVfdG9fZXhwaXJhdGlvbiA9IHRpbWVfdG9fZXhwaXJhdGlvbl9Fb1QsDQogIHNpZ21hID0gdm9sYXRpbGl0eSwNCiAgZGl2aWRlbmRfeWllbGQgPSBkaXZpZGVuZF95aWVsZA0KKQ0KDQpgYGANCg0KDQpDcmVhdGUgdGFibGUgZm9yIFJlc3VsdHMgDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggdGhlIG9idGFpbmVkIGRhdGENCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgNCiAgICBTdG9jayA9ICJJTkciLA0KICAgIEJvVF9EYXRlID0gQm9UX3N0b2NrJERhdGUsDQogICAgQm9UX1ByaWNlID0gQm9UX3N0b2NrJFByaWNlLA0KICAgIEJvVF9PcHRpb25fUHJlbWl1bSA9IEJvVF9wcmVtaXVtLA0KICAgIEVvVF9EYXRlID0gRW9UX3N0b2NrJERhdGUsDQogICAgRW9UX1ByaWNlID0gRW9UX3N0b2NrJFByaWNlLA0KICAgIEVvVF9PcHRpb25fUHJlbWl1bSA9IEVvVF9wcmVtaXVtDQopDQoNCiMgRGlzcGxheSB0aGUgcmVzdWx0cw0KcHJpbnQocmVzdWx0cykNCg0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzLiANCkluIHRoaXMgY2FzZSwgd2UgaGF2ZSBvbmx5IGhhZCB0byBhcHBseSB0aGUgZnVuY3Rpb25zIGFuZCBwcm9jZXNzIHdlIGhhZCBqdXN0IGFwcGxpZWQgZm9yIHRoZSBjYWxsIG9wdGlvbi4gVGhlIEFzc2V0IHdlIGhhdmUgc2VsZWN0ZWQgaXMgQmFuayBJTkcgd2hpY2ggd2UgaGFkIGV4cGVjdGVkIHRvIGZhbGwuIEhvd2V2ZXIsIGluIHRoZSByZXN1bHRzIG9idGFpbmVkIHdlIGhhdmUgbm90aWNlZCBhbiBhcHByZWNpYXRpb24gaW4gdGhlIHN0b2NrIHZhbHVlIGFzIHdlbGwgYXMgdGhlIHByZW1pdW1zLiBUaGlzIG1lYW5zIHRoYXQgdGhlIHN0b2NrIGhhcyBvdXQgcGVyZm9ybWVkIG91ciBleHBlY3RhdGlvbnMgYW5kIGhhcyBub3QgZmFsbGVuIGR1cmluZyB0aGUgc2Nob29sIHRlcm0uIEhhZCB3ZSBib3VnaHQgdGhlIHB1dCBvcHRpb24gaW4gdGhlIGJlZ2lubmluZyBvZiB0ZXJtIGRhdGUsIHdlIHdvdWxkIGhhdmUgaGFkIGEgbmVnYXRpdmUgYWN0aW9uIG9mIG91ciBvcGVyYXRpb24uIEhvd2V2ZXIsIHdlIHdvdWxkIGxpa2UgdG8gbm90ZSB0aGF0IGluIHRoZSByZWNlbnQgdGltZXMsIElORyBoYXMgYmVlbiBoaXQgd2l0aCBuZWdhdGl2ZSBuZXdzIGFuZCBpbmZvcm1hdGlvbiByZWdhcmRpbmcgbWFzc2l2ZSB3aXRoZHJhd2Fscy4gSG93ZXZlciwgdGhpcyBpbmZvcm1hdGlvbiBhcHBlYXJzIHRvIGhhdmUgYmVlbiBkZWJ1bmtlZCwgYWx0aG91Z2ggdGhlcmUgaGFzIGJlZW4gb2JzZXJ2ZWQgcmVjZW50IG5lZ2F0aXZlIHN0b2NrIG1vdmVtZW50cy4gDQoNCg0KDQojIyMgTDEuNSANCg0KDQpEZWZpbmUgQm9UIGFuZCBFb1QgZGF0ZXMNCg0KYGBge3J9DQpCb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA1LTAxIikNCkVvVF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMDktMzAiKQ0KYGBgDQoNCg0KQ3JlYXRlIGEgRnVuY3Rpb24gdG8gUmV0cmlldmUgRXhjaGFuZ2UgUmF0ZXMgd2l0aCBOb24tVHJhZGluZyBkYXkgQWRqdXN0bWVudA0KDQpgYGB7cn0NCmdldF9leGNoYW5nZV9yYXRlIDwtIGZ1bmN0aW9uKHN5bWJvbCwgZGF0ZSwgdXNlX25leHQgPSBGQUxTRSwgaW52ZXJ0ID0gRkFMU0UpIHsNCiAgIyBSZXRyaWV2ZSBleGNoYW5nZSByYXRlIGRhdGEgZnJvbSBGUkVEDQogIGRhdGEgPC0gZ2V0U3ltYm9scyhTeW1ib2xzID0gc3ltYm9sLCBzcmMgPSAiRlJFRCIsIGF1dG8uYXNzaWduID0gRkFMU0UpDQogIA0KICAjIENvbnZlcnQgaW5kZXggdG8gRGF0ZSBmb3JtYXQNCiAgaW5kZXgoZGF0YSkgPC0gYXMuRGF0ZShpbmRleChkYXRhKSkNCiAgDQogICMgQWRqdXN0IGZvciBub24tdHJhZGluZyBkYXlzDQogIGlmICh1c2VfbmV4dCkgew0KICAgICMgRm9yIEJvVF9kYXRlLCBnZXQgdGhlIG5leHQgYXZhaWxhYmxlIGRhdGUgYWZ0ZXIgdGhlIGRhdGUNCiAgICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPj0gZGF0ZSAmICFpcy5uYShkYXRhW2luZGV4KGRhdGEpXSldDQogICAgaWYobGVuZ3RoKGF2YWlsYWJsZV9kYXRlcykgPT0gMCkgew0KICAgICAgd2FybmluZyhwYXN0ZSgiTm8gZGF0YSBhdmFpbGFibGUgYWZ0ZXIiLCBkYXRlLCAiZm9yIHN5bWJvbDoiLCBzeW1ib2wpKQ0KICAgICAgcmV0dXJuKGxpc3QoUmF0ZSA9IE5BLCBEYXRlID0gTkEpKQ0KICAgIH0NCiAgICBkYXRlX3VzZWQgPC0gbWluKGF2YWlsYWJsZV9kYXRlcykNCiAgfSBlbHNlIHsNCiAgICAjIEZvciBFb1RfZGF0ZSwgZ2V0IHRoZSBsYXN0IGF2YWlsYWJsZSBkYXRlIGJlZm9yZSB0aGUgZGF0ZQ0KICAgIGF2YWlsYWJsZV9kYXRlcyA8LSBpbmRleChkYXRhKVtpbmRleChkYXRhKSA8PSBkYXRlICYgIWlzLm5hKGRhdGFbaW5kZXgoZGF0YSldKV0NCiAgICBpZiAobGVuZ3RoKGF2YWlsYWJsZV9kYXRlcykgPT0gMCkgew0KICAgICAgd2FybmluZyhwYXN0ZSgiTm8gZGF0YSBhdmFpbGFibGUgYmVmb3JlIiwgZGF0ZSwgImZvciBzeW1ib2w6Iiwgc3ltYm9sKSkNCiAgICAgIHJldHVybihsaXN0KFJhdGUgPSBOQSwgRGF0ZSA9IE5BKSkNCiAgICB9DQogICAgZGF0ZV91c2VkIDwtIG1heChhdmFpbGFibGVfZGF0ZXMpDQogIH0NCiAgDQogICMgR2V0IHRoZSBleGNoYW5nZSByYXRlDQogIHJhdGUgPC0gYXMubnVtZXJpYyhkYXRhW2RhdGVfdXNlZF0pDQogIA0KICAjIEludmVydCB0aGUgcmF0ZSBpZiBuZWVkZWQgKGZvciBjdXJyZW5jaWVzIHF1b3RlZCBhcyBmb3JlaWduIGN1cnJlbmN5IHBlciBVU0QpDQogIGlmIChpbnZlcnQpIHsNCiAgICByYXRlIDwtIDEgLyByYXRlDQogIH0NCiAgDQogIHJldHVybihsaXN0KA0KICAgIFJhdGUgPSByYXRlLA0KICAgIERhdGUgPSBhcy5EYXRlKGRhdGVfdXNlZCkNCiAgKSkNCn0NCmBgYA0KDQoNClJldHJpZXZlIEV4Y2hhbmdlIFJhdGVzIG9uIEJvVCBhbmQgRW9UIERhdGVzDQpTeW1ib2xzIGluIEZSRUQ6DQpHUEIvVVNEOiBERVhVU1VLDQpKUFkvVVNEOiBERVhKUFVTDQpNWE4vVVNEOiBERVhNWFVTDQooRlJFRCBwcm92aWRlcyBleGNoYW5nZSByYXRlcyBpbiBmb3JlaWduIGN1cnJlbmN5IHVuaXRzIHBlciBVLlMuIGRvbGxhciBmb3IgSlBZIGFuZCBNWE4sIHNvIHdlJ2xsIGludmVydCB0aGVzZSByYXRlcyB0byBnZXQgVVNEIHBlciBmb3JlaWduIGN1cnJlbmN5IHVuaXQpDQoNCmBgYHtyfQ0KIyBSZXRyaWV2ZSBleGNoYW5nZSByYXRlcyBvbiBCb1RfZGF0ZQ0KR0JQX0JvVCA8LSBnZXRfZXhjaGFuZ2VfcmF0ZSgiREVYVVNVSyIsIEJvVF9kYXRlLCB1c2VfbmV4dCA9IFRSVUUpDQpKUFlfQm9UIDwtIGdldF9leGNoYW5nZV9yYXRlKCJERVhKUFVTIiwgQm9UX2RhdGUsIHVzZV9uZXh0ID0gVFJVRSwgaW52ZXJ0ID0gVFJVRSkNCk1YTl9Cb1QgPC0gZ2V0X2V4Y2hhbmdlX3JhdGUoIkRFWE1YVVMiLCBCb1RfZGF0ZSwgdXNlX25leHQgPSBUUlVFLCBpbnZlcnQgPSBUUlVFKQ0KDQojIFJldHJpZXZlIGV4Y2hhbmdlIHJhdGVzIG9uIEVvVF9kYXRlDQpHQlBfRW9UIDwtIGdldF9leGNoYW5nZV9yYXRlKCJERVhVU1VLIiwgRW9UX2RhdGUsIHVzZV9uZXh0ID0gRkFMU0UpDQpKUFlfRW9UIDwtIGdldF9leGNoYW5nZV9yYXRlKCJERVhKUFVTIiwgRW9UX2RhdGUsIHVzZV9uZXh0ID0gRkFMU0UsIGludmVydCA9IFRSVUUpDQpNWE5fRW9UIDwtIGdldF9leGNoYW5nZV9yYXRlKCJERVhNWFVTIiwgRW9UX2RhdGUsIHVzZV9uZXh0ID0gRkFMU0UsIGludmVydCA9IFRSVUUpDQpgYGANCg0KDQpDcmVhdGUgYSBEYXRhIEZyYW1lIHRvIERpc3BsYXkgdGhlIFJlc3VsdHMNCg0KYGBge3J9DQojIENyZWF0ZSBkYXRhIGZyYW1lIHdpdGggdGhlIHJlc3VsdHMNCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgNCiAgQ3VycmVuY3kgPSBjKCJHQlAvVVNEIiwgIkpQWS9VU0QiLCAiTVhOL1VTRCIpLA0KICBCb1RfRGF0ZSA9IGMoR0JQX0JvVCREYXRlLCBKUFlfQm9UJERhdGUsIE1YTl9Cb1QkRGF0ZSksDQogIEJvVF9SYXRlID0gYyhHQlBfQm9UJFJhdGUsIEpQWV9Cb1QkUmF0ZSwgTVhOX0JvVCRSYXRlKSwNCiAgRW9UX0RhdGUgPSBjKEdCUF9Fb1QkRGF0ZSwgSlBZX0VvVCREYXRlLCBNWE5fRW9UJERhdGUpLA0KICBFb1RfUmF0ZSA9IGMoR0JQX0VvVCRSYXRlLCBKUFlfRW9UJFJhdGUsIE1YTl9Fb1QkUmF0ZSkNCikNCg0KIyBEaXNwbGF5IHRoZSByZXN1bHRzDQpwcmludChyZXN1bHRzKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQpJbiB0aGlzIGV4ZXJjaXNlIHdlIGhhdmUgZGVzaWduZWQgYSBuZXcgZnVuY3Rpb24gdG8gcmV0cmlldmUgZXhjaGFuZ2UgcmF0ZXMsIGFzIGFsd2F5cyBhZGp1c3RpbmcgaXQgdG8gdGhlIG5vbi10cmFkaW5nIGRheXMuIFdlIGhhdmUgcmV0cmlldmUgdGhlIGRhdGEgb2YgdGhyZWUgZGlmZmVyZW50IGV4Y2hhbmdlIHJhdGVzIGJvdGggb24gQm9UIGRhdGUgYW5kIEVvVCBkYXRlIGFuZCB3ZSBoYXZlIHBvcnRyYXllZCB0aGUgcmVzdWx0IGluIGEgZGF0YSBmcmFtZS4gDQoNCg0KIyMjIEwxLjYgVXNlIGN1cnJlbmN5IG9wdGlvbnMgZGF0YSAoaWYgYXZhaWxhYmxlKSB0byBzZWxlY3QgYSBjYWxsIG9wdGlvbiBvbiBhIGZvcmVpZ24gY3VycmVuY3kgdGhhdCB5b3UgZXhwZWN0IHdpbGwgc3RyZW5ndGhlbiBhZ2FpbnN0IHRoZSBkb2xsYXIgKHNlbGVjdCB0aGUgb3B0aW9uIHdpdGggdGhlIGZpcnN0IGV4cGlyYXRpb24gbW9udGggYmV5b25kIHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtKQ0KDQoNCkxvYWQgcGFja2FnZXMNCg0KYGBge3J9DQojIExvYWQgcGFja2FnZXMNCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkodGltZURhdGUpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KYGBgDQoNCg0KRGVmaW5lIEJvVCBhbmQgRW9UIERhdGVzDQoNCmBgYHtyfQ0KQm9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNS0wMSIpDQpFb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCmBgYA0KDQoNCkNyZWF0ZSBhIGZ1bmN0aW9uIHRvIEFkanVzdCBmb3IgTm9uLVRyYWRpbmcgRGF5cyBhbmQgT2J0YWluIEV4Y2hhbmdlIFJhdGUgRGF0YQ0KDQpgYGB7cn0NCmdldF9leGNoYW5nZV9yYXRlIDwtIGZ1bmN0aW9uKHN5bWJvbCwgZGF0ZSwgdXNlX25leHQgPSBGQUxTRSkgew0KICAjIERvd25sb2FkIGRhdGEgYXJvdW5kIHRoZSBkYXRlDQogIGRhdGEgPC0gZ2V0U3ltYm9scygNCiAgICBTeW1ib2xzID0gc3ltYm9sLA0KICAgIHNyYyA9ICJ5YWhvbyIsDQogICAgZnJvbSA9IGRhdGUgLSBkYXlzKDEwKSwNCiAgICB0byA9IGRhdGUgKyBkYXlzKDEwKSwNCiAgICBhdXRvLmFzc2lnbiA9IEZBTFNFDQogICkNCiAgDQogICMgQ29udmVydCBpbmRleCB0byBEYXRlIGZvcm1hdA0KICBpbmRleChkYXRhKSA8LSBhcy5EYXRlKGluZGV4KGRhdGEpKQ0KICANCiAgIyBIYW5kbGUgbm9uLXRyYWRpbmcgZGF5cw0KICBpZiAodXNlX25leHQpIHsNCiAgICAjIEZvciBCb1RfZGF0ZSwgZ2V0IHRoZSBuZXh0IGF2YWlsYWJsZSBkYXRlIGFmdGVyIHRoZSBkYXRlDQogICAgYXZhaWxhYmxlX2RhdGVzIDwtIGluZGV4KGRhdGEpW2luZGV4KGRhdGEpID49IGRhdGVdDQogICAgaWYobGVuZ3RoKGF2YWlsYWJsZV9kYXRlcykgPT0gMCkgew0KICAgICAgd2FybmluZyhwYXN0ZSgiTm8gZGF0YSBhdmFpbGFibGUgYWZ0ZXIiLCBkYXRlLCAiZm9yIHN5bWJvbDoiLCBzeW1ib2wpKQ0KICAgICAgcmV0dXJuKGxpc3QoUmF0ZSA9IE5BLCBEYXRlID0gTkEpKQ0KICAgIH0NCiAgICBkYXRlX3VzZWQgPC0gbWluKGF2YWlsYWJsZV9kYXRlcykNCiAgfSBlbHNlIHsNCiAgICAjIEZvciBFb1RfZGF0ZSwgZ2V0IHRoZSBsYXN0IGF2YWlsYWJsZSBkYXRlIGJlZm9yZSB0aGUgZGF0ZQ0KICAgIGF2YWlsYWJsZV9kYXRlcyA8LSBpbmRleChkYXRhKVtpbmRleChkYXRhKSA8PSBkYXRlXQ0KICAgIGlmIChsZW5ndGgoYXZhaWxhYmxlX2RhdGVzKSA9PSAwKSB7DQogICAgICB3YXJuaW5nKHBhc3RlKCJObyBkYXRhIGF2YWlsYWJsZSBiZWZvcmUiLCBkYXRlLCAiZm9yIHN5bWJvbDoiLCBzeW1ib2wpKQ0KICAgICAgcmV0dXJuKGxpc3QoUmF0ZSA9IE5BLCBEYXRlID0gTkEpKQ0KICAgIH0NCiAgICBkYXRlX3VzZWQgPC0gbWF4KGF2YWlsYWJsZV9kYXRlcykNCiAgfQ0KICANCiAgIyBHZXQgdGhlIGV4Y2hhbmdlIHJhdGUNCiAgcmF0ZSA8LSBhcy5udW1lcmljKENsKGRhdGFbZGF0ZV91c2VkXSkpDQogIA0KICByZXR1cm4obGlzdCgNCiAgICBSYXRlID0gcmF0ZSwNCiAgICBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICkpDQp9DQpgYGANCg0KDQpSZXRyaWV2ZSBFeGNoYWJnZSBSYXRlcyBvbiBCb1QgYW5kIEVvVCBkYXRlcw0KDQpgYGB7cn0NCiMgR2V0IGV4Y2hhbmdlIHJhdGVzIGZvciBDTlkvVVNEDQojIE5vdGU6IE9uIFlhaG9vIEZpbmFuY2UsIHRoZSBzeW1ib2wgZm9yIENOWS9VU0QgaXMgIkNOWT1YIg0KDQpDTllfQm9UIDwtIGdldF9leGNoYW5nZV9yYXRlKCJDTlk9WCIsIEJvVF9kYXRlLCB1c2VfbmV4dCA9IFRSVUUpDQpDTllfRW9UIDwtIGdldF9leGNoYW5nZV9yYXRlKCJDTlk9WCIsIEVvVF9kYXRlLCB1c2VfbmV4dCA9IEZBTFNFKQ0KYGBgDQoNCg0KRGV0ZXJtaW5lIE9wdGlvbiBEZXRhaWxzDQorT3B0aW9uIHR5cGU6IENhbGwgb3B0aW9uDQorU3RyaWtlIFByaWNlOiBVc2UgdGhlIHNwb3QgZXhjaGFuZ2UgcmF0ZSBhdCBCb1RfRGF0ZSAoQXQtVGhlLU1vbmV5KQ0KK0V4cGlyYXRpb24gRGF0ZTogRmlyc3Qgb3B0aW9uIGV4cGlyYXRpb24gZGF0ZSBiZXlvbmQgRW9UX0RhdGUNCg0KDQpHZW5lcmF0ZSBPcHRpb24gRXhwaXJhdGlvbiBEYXRlcw0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gdG8gZ2V0IHRoZSB0aGlyZCBGcmlkYXkgb2YgYSBtb250aA0KdGhpcmRfZnJpZGF5IDwtIGZ1bmN0aW9uKHllYXIsIG1vbnRoKSB7DQogIGRhdGVzIDwtIHNlcSgNCiAgICBmcm9tID0gYXMuRGF0ZShwYXN0ZTAoeWVhciwgIi0iLCBtb250aCwgIi0wMSIpKSwNCiAgICB0byA9IGFzLkRhdGUocGFzdGUwKHllYXIsICItIiwgbW9udGgsICItIiwgZGF5c19pbl9tb250aChhcy5EYXRlKHBhc3RlMCh5ZWFyLCAiLSIsIG1vbnRoLCAiLTAxIikpKSkpLA0KICAgIGJ5ID0gImRheSINCiAgKQ0KICBmcmlkYXlzIDwtIGRhdGVzW3dkYXkoZGF0ZXMpID09IDZdICAjIDYgY29ycmVzcG9uZHMgdG8gRnJpZGF5DQogIGlmIChsZW5ndGgoZnJpZGF5cykgPj0gMykgew0KICAgIHJldHVybihmcmlkYXlzWzNdKQ0KICB9IGVsc2Ugew0KICAgIHJldHVybihOQSkNCiAgfQ0KfQ0KDQojIEdlbmVyYXRlIGV4cGlyYXRpb24gZGF0ZXMgZm9yIHRoZSBuZXh0IDE4IG1vbnRocw0KZXhwaXJhdGlvbl9kYXRlcyA8LSBhcy5EYXRlKGNoYXJhY3RlcigpKQ0KY3VycmVudF9kYXRlIDwtIGFzLkRhdGUoU3lzLkRhdGUoKSkNCg0KZm9yIChpIGluIDA6MTcpIHsNCiAgZGF0ZSA8LSBjdXJyZW50X2RhdGUgJW0rJSBtb250aHMoaSkNCiAgeXIgPC0geWVhcihkYXRlKQ0KICBtbnRoIDwtIG1vbnRoKGRhdGUpDQogIGV4cF9kYXRlIDwtIHRoaXJkX2ZyaWRheSh5ciwgbW50aCkNCiAgaWYgKCFpcy5uYShleHBfZGF0ZSkpIHsNCiAgICBleHBpcmF0aW9uX2RhdGVzIDwtIGMoZXhwaXJhdGlvbl9kYXRlcywgZXhwX2RhdGUpDQogIH0NCn0NCg0KIyBGaWx0ZXIgZXhwaXJhdGlvbiBkYXRlcyBiZXlvbmQgRW9UX2RhdGUNCmV4cGlyYXRpb25fZGF0ZXMgPC0gZXhwaXJhdGlvbl9kYXRlc1tleHBpcmF0aW9uX2RhdGVzID4gRW9UX2RhdGVdDQoNCiMgU2VsZWN0IHRoZSBmaXJzdCBleHBpcmF0aW9uIGRhdGUgYmV5b25kIEVvVF9kYXRlDQppZiAobGVuZ3RoKGV4cGlyYXRpb25fZGF0ZXMpID09IDApIHsNCiAgc3RvcCgiTm8gZXhwaXJhdGlvbiBkYXRlcyBmb3VuZCBiZXlvbmQgRW9UX2RhdGUuIikNCn0NCg0KZXhwaXJhdGlvbl9kYXRlIDwtIGV4cGlyYXRpb25fZGF0ZXNbMV0NCnByaW50KHBhc3RlKCJTZWxlY3RlZCBPcHRpb24gRXhwaXJhdGlvbiBEYXRlOiIsIGV4cGlyYXRpb25fZGF0ZSkpDQpgYGANCg0KDQpDYWxjdWxhdGUgVGltZSB0byBleHBpcmF0aW9uDQoNCmBgYHtyfQ0KIyBUaW1lIHRvIGV4cGlyYXRpb24gZnJvbSBCb1RfZGF0ZQ0KdGltZV90b19leHBpcmF0aW9uX0JvVCA8LSBhcy5udW1lcmljKGV4cGlyYXRpb25fZGF0ZSAtIENOWV9Cb1QkRGF0ZSkgLyAzNjUNCg0KIyBUaW1lIHRvIGV4cGlyYXRpb24gZnJvbSBFb1RfZGF0ZQ0KdGltZV90b19leHBpcmF0aW9uX0VvVCA8LSBhcy5udW1lcmljKGV4cGlyYXRpb25fZGF0ZSAtIENOWV9Fb1QkRGF0ZSkgLyAzNjUNCmBgYA0KDQoNClNldCB0aGUgU3RyaWtlIFByaWNlDQoNCmBgYHtyfQ0Kc3RyaWtlX3ByaWNlIDwtIENOWV9Cb1QkUmF0ZSAgIyBBdC1UaGUtTW9uZXkgb3B0aW9uDQpgYGANCg0KDQpFc3RpbWF0ZSBWb2xhdGlsaXR5DQoNCmBgYHtyfQ0KIyBHZXQgaGlzdG9yaWNhbCBleGNoYW5nZSByYXRlIGRhdGEgZm9yIHRoZSBwYXN0IHllYXIgYmVmb3JlIEJvVF9kYXRlDQp2b2xfZGF0YSA8LSBnZXRTeW1ib2xzKA0KICBTeW1ib2xzID0gIkNOWT1YIiwNCiAgc3JjID0gInlhaG9vIiwNCiAgZnJvbSA9IENOWV9Cb1QkRGF0ZSAtIHllYXJzKDEpLA0KICB0byA9IENOWV9Cb1QkRGF0ZSwNCiAgYXV0by5hc3NpZ24gPSBGQUxTRQ0KKQ0KDQojIENhbGN1bGF0ZSBkYWlseSByZXR1cm5zDQpyZXR1cm5zIDwtIGRhaWx5UmV0dXJuKENsKHZvbF9kYXRhKSkNCg0KIyBDYWxjdWxhdGUgYW5udWFsaXplZCB2b2xhdGlsaXR5DQp2b2xhdGlsaXR5IDwtIHNkKHJldHVybnMsIG5hLnJtID0gVFJVRSkgKiBzcXJ0KDI1MikgICMgMjUyIHRyYWRpbmcgZGF5cyBpbiBhIHllYXINCmBgYA0KDQoNClNldCBEb21lc3RpYyBhbmQgRm9yZWlnbiBSaXNrLUZyZWUgSW50ZXJlc3QgUmF0ZXMNCkRvbWVzdGljIFJpc2stRnJlZSBSYXRlIChyX2RvbWVzdGljKTogVVMgcmlzay1mcmVlIHJhdGUNCkZvcmVpZ24gUmlzay1GcmVlIFJhdGUgKHJfZm9yZWlnbik6IENoaW5lc2Ugcmlzay1mcmVlIHJhdGUNCg0KYGBge3J9DQpyX2RvbWVzdGljIDwtIDAuMDQzDQpyX2ZvcmVpZ24gPC0gMC4wMjA5DQpgYGANCg0KDQpEZWZpbmUgdGhlIEdhcm1hbi1Lb2hsaGFnZW4gTW9kZWwgRnVuY3Rpb24NCg0KYGBge3J9DQpjYWxjdWxhdGVfY3VycmVuY3lfb3B0aW9uX3ByZW1pdW0gPC0gZnVuY3Rpb24oUywgSywgcl9kb21lc3RpYywgcl9mb3JlaWduLCB0aW1lX3RvX2V4cGlyYXRpb24sIHNpZ21hLCBvcHRpb25fdHlwZSA9ICJjYWxsIikgew0KICBkMSA8LSAobG9nKFMgLyBLKSArIChyX2RvbWVzdGljIC0gcl9mb3JlaWduICsgMC41ICogc2lnbWFeMikgKiB0aW1lX3RvX2V4cGlyYXRpb24pIC8gKHNpZ21hICogc3FydCh0aW1lX3RvX2V4cGlyYXRpb24pKQ0KICBkMiA8LSBkMSAtIHNpZ21hICogc3FydCh0aW1lX3RvX2V4cGlyYXRpb24pDQogIA0KICBpZiAob3B0aW9uX3R5cGUgPT0gImNhbGwiKSB7DQogICAgcHJlbWl1bSA8LSBTICogZXhwKC1yX2ZvcmVpZ24gKiB0aW1lX3RvX2V4cGlyYXRpb24pICogcG5vcm0oZDEpIC0gSyAqIGV4cCgtcl9kb21lc3RpYyAqIHRpbWVfdG9fZXhwaXJhdGlvbikgKiBwbm9ybShkMikNCiAgfSBlbHNlIGlmIChvcHRpb25fdHlwZSA9PSAicHV0Iikgew0KICAgIHByZW1pdW0gPC0gSyAqIGV4cCgtcl9kb21lc3RpYyAqIHRpbWVfdG9fZXhwaXJhdGlvbikgKiBwbm9ybSgtZDIpIC0gUyAqIGV4cCgtcl9mb3JlaWduICogdGltZV90b19leHBpcmF0aW9uKSAqIHBub3JtKC1kMSkNCiAgfSBlbHNlIHsNCiAgICBzdG9wKCJJbnZhbGlkIG9wdGlvbiB0eXBlLiBVc2UgJ2NhbGwnIG9yICdwdXQnLiIpDQogIH0NCiAgDQogIHJldHVybihwcmVtaXVtKQ0KfQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIE9wdGlvbiBQcmVtaXVtcw0KDQpgYGB7cn0NCiMgT3B0aW9uIHByZW1pdW0gb24gQm9UX2RhdGUNCkJvVF9wcmVtaXVtIDwtIGNhbGN1bGF0ZV9jdXJyZW5jeV9vcHRpb25fcHJlbWl1bSgNCiAgUyA9IENOWV9Cb1QkUmF0ZSwNCiAgSyA9IHN0cmlrZV9wcmljZSwNCiAgcl9kb21lc3RpYyA9IHJfZG9tZXN0aWMsDQogIHJfZm9yZWlnbiA9IHJfZm9yZWlnbiwNCiAgdGltZV90b19leHBpcmF0aW9uID0gdGltZV90b19leHBpcmF0aW9uX0JvVCwNCiAgc2lnbWEgPSB2b2xhdGlsaXR5LA0KICBvcHRpb25fdHlwZSA9ICJjYWxsIg0KKQ0KDQojIE9wdGlvbiBwcmVtaXVtIG9uIEVvVF9kYXRlDQpFb1RfcHJlbWl1bSA8LSBjYWxjdWxhdGVfY3VycmVuY3lfb3B0aW9uX3ByZW1pdW0oDQogIFMgPSBDTllfRW9UJFJhdGUsDQogIEsgPSBzdHJpa2VfcHJpY2UsDQogIHJfZG9tZXN0aWMgPSByX2RvbWVzdGljLA0KICByX2ZvcmVpZ24gPSByX2ZvcmVpZ24sDQogIHRpbWVfdG9fZXhwaXJhdGlvbiA9IHRpbWVfdG9fZXhwaXJhdGlvbl9Fb1QsDQogIHNpZ21hID0gdm9sYXRpbGl0eSwNCiAgb3B0aW9uX3R5cGUgPSAiY2FsbCINCikNCmBgYA0KDQoNCkNyZWF0ZSBEYXRhIEZyYW1lIHRvIERpc3BsYXkgUmVzdWx0cw0KDQpgYGB7cn0NCiMgQ3JlYXRlIGRhdGEgZnJhbWUgd2l0aCB0aGUgcmVzdWx0cw0KcmVzdWx0cyA8LSBkYXRhLmZyYW1lKA0KICBDdXJyZW5jeSA9ICJDTlkvVVNEIiwNCiAgQm9UX0RhdGUgPSBDTllfQm9UJERhdGUsDQogIEJvVF9SYXRlID0gQ05ZX0JvVCRSYXRlLA0KICBCb1RfT3B0aW9uX1ByZW1pdW0gPSBCb1RfcHJlbWl1bSwNCiAgRW9UX0RhdGUgPSBDTllfRW9UJERhdGUsDQogIEVvVF9SYXRlID0gQ05ZX0VvVCRSYXRlLA0KICBFb1RfT3B0aW9uX1ByZW1pdW0gPSBFb1RfcHJlbWl1bQ0KKQ0KDQojIERpc3BsYXkgdGhlIHJlc3VsdHMNCnByaW50KHJlc3VsdHMpDQpgYGANCg0KDQojIyMjIEFuYWx5c2lzIG9mIHJlc3VsdHMNCg0KSW4gdGhpcyBleGVyY2lzZSB3ZSBoYXZlIHBlcmZvcm1lZCBhIHJhdGhlciBzaW1pbGFyIHByb2Nlc3MgdGhhbiB0aGF0IG9mIEwxLjQgYW5kIEwxLjUuIEhvd2V2ZXIsIGluIHRoaXMgY2FzZSB3ZSBhcmUgc3R1ZHlpbmcgYSBjYWxsIG9wdGlvbiBvbiBhIGN1cnJlbmN5IHRoYXQgd2UgdGhpbmsgbWlnaHQgYXBwcmVjaWF0ZSBpbiB2YWx1ZSBkdXJpbmcgdGhlIHNjaG9vbCB0ZXJtLiBUaGUgY3VycmVuY3kgd2UgaGF2ZSBzZWxlY3RlZCBoYXMgYmVlbiAgdGhlIENoaW5lc2UgWXVhbi4gVGhlIHdlYWtlbmluZyBvZiB0aGUgVVMgVHJlYXN1cnkgSW50ZXJlc3QgaXMgb25lIG9mIHRoZSBtYWluIGRyaXZlcnMgb2YgdGhlIHdlYWtlbmluZyBvZiB0aGUgVVMgRG9sbGFyIGFuZCBwcm9iYWJseSB0aGUgbWFpbiByZWFzb24gZm9yIHRoZSBhcHByZWNpYXRpb24gb2YgdGhlIENoaW5lc2UgWXVhbiBhZ2FpbnN0IGl0LiAgDQpJbiB0aGlzIGNhc2UsIHdlIGhhdmUgbm90IHVzZWQgdGhlIEJsYWNrLVNjaG9sZXMgTW9kZWwsIGJ1dCByYXRoZXIgdGhlIEdhcm1hbi1Lb2hsaGFnZW4gTW9kZWwgRnVuY3Rpb24sIHdoaWNoIGlzIG9mdGVuIHVzZSB0byBwcmljZSBjdXJyZW5jeSBvcHRpb25zLiANCg0KUmVnYXJkaW5nIHRoZSByZXN1bHRzLCBpbiB0aGlzIGNhc2Ugd2UgaGF2ZSBub3QgYmVlbiBhYmxlIHRvIHNlY3VyZSBhIGZhdm9yYWJsZSByZXN1bHQgaW4gdGhlIGNhbGwgb3B0aW9uLCBhcyB0aGUgcmF0ZSBoYXMgZGVwcmVjaWF0ZWQsIGFzIHdlbGwgYXMgdGhlIHByZW1pdW0sIGF0IEVvVC4gVGhpcyByZXN1bHRzIGNhbiBiZSBleHBsYWluZWQgZHVlIHRvIGEgZ3JlYXQgcmFuZ2Ugb2YgZmFjdG9ycyB0aGF0IGluY2x1ZGUgbW9uZXRhcnkgcG9saWN5IG9mIGJvdGggY291bnRyaWVzLCBtYXJrZXQgbW92ZW1lbnRzLCBzdXBwbHkgYW5kIGRlbWFuZCwgbWFjcm9lY29ub21pYyBkYXRhLCBtaWNyb2Vjb25vbWljIGRldGFpbHMgb3IgZXZlbiBzcGVjdWxhdGlvbiBmcm9tIGludmVzdG9ycy4gRWl0aGVyIHdheSwgdGhlIHJlc3VsdHMgZGVwaWN0IGFuIHN0cmVuZ3RoZW4gVVMgRG9sbGFyIGFnYWluc3QgdGhlIENoaW5lc2UgWXVhbiBhbmQgdGhlIGV4ZXJjaXNlIGhlbHBzIHVzIHRvIGV4ZW1wbGlmeSBob3cgYSBjYWxsIG9wdGlvbiBvbiBhIGN1cnJlbmN5IG1heSBiZSBwcmljZWQuIA0KDQoNCg0KIyMjIEwxLjcgVXNlIGN1cnJlbmN5IG9wdGlvbnMgZGF0YSAoaWYgYXZhaWxhYmxlKSB0byBzZWxlY3QgYSBwdXQgb3B0aW9uIG9uIGEgZm9yZWlnbiBjdXJyZW5jeSB0aGF0IHlvdSBleHBlY3Qgd2lsbCB3ZWFrZW4gYWdhaW5zdCB0aGUgZG9sbGFyIChzZWxlY3QgdGhlIG9wdGlvbiB3aXRoIHRoZSBmaXJzdCBleHBpcmF0aW9uIG1vbnRoIGJleW9uZCB0aGUgZW5kIG9mIHRoZSBzY2hvb2wgdGVybSkuDQoNClJldHJpZXZlIEV4Y2hhbmdlIFJhdGVzIG9uIEJvVCBhbmQgRW9UIGRhdGVzDQoNCmBgYHtyfQ0KIyBHZXQgZXhjaGFuZ2UgcmF0ZXMgZm9yIEVVUi9VU0QNCiMgTm90ZTogT24gWWFob28gRmluYW5jZSwgdGhlIHN5bWJvbCBmb3IgQ05ZL1VTRCBpcyAiRVVSVVNEPVgiDQoNCkVVUl9Cb1QgPC0gZ2V0X2V4Y2hhbmdlX3JhdGUoIkVVUlVTRD1YIiwgQm9UX2RhdGUsIHVzZV9uZXh0ID0gVFJVRSkNCkVVUl9Fb1QgPC0gZ2V0X2V4Y2hhbmdlX3JhdGUoIkVVUlVTRD1YIiwgRW9UX2RhdGUsIHVzZV9uZXh0ID0gRkFMU0UpDQpgYGANCg0KDQpEZXRlcm1pbmUgT3B0aW9uIERldGFpbHMNCitPcHRpb24gdHlwZTogQ2FsbCBvcHRpb24NCitTdHJpa2UgUHJpY2U6IFVzZSB0aGUgc3BvdCBleGNoYW5nZSByYXRlIGF0IEJvVF9EYXRlIChBdC1UaGUtTW9uZXkpDQorRXhwaXJhdGlvbiBEYXRlOiBGaXJzdCBvcHRpb24gZXhwaXJhdGlvbiBkYXRlIGJleW9uZCBFb1RfRGF0ZQ0KDQoNCkNhbGN1bGF0ZSBUaW1lIHRvIGV4cGlyYXRpb24NCg0KYGBge3J9DQojIFRpbWUgdG8gZXhwaXJhdGlvbiBmcm9tIEJvVF9kYXRlDQp0aW1lX3RvX2V4cGlyYXRpb25fQm9UIDwtIGFzLm51bWVyaWMoZXhwaXJhdGlvbl9kYXRlIC0gRVVSX0JvVCREYXRlKSAvIDM2NQ0KDQojIFRpbWUgdG8gZXhwaXJhdGlvbiBmcm9tIEVvVF9kYXRlDQp0aW1lX3RvX2V4cGlyYXRpb25fRW9UIDwtIGFzLm51bWVyaWMoZXhwaXJhdGlvbl9kYXRlIC0gRVVSX0VvVCREYXRlKSAvIDM2NQ0KYGBgDQoNCg0KU2V0IHRoZSBTdHJpa2UgUHJpY2UNCg0KYGBge3J9DQpzdHJpa2VfcHJpY2UgPC0gRVVSX0JvVCRSYXRlICAjIEF0LVRoZS1Nb25leSBvcHRpb24NCmBgYA0KDQoNCkVzdGltYXRlIFZvbGF0aWxpdHkNCg0KYGBge3J9DQojIEdldCBoaXN0b3JpY2FsIGV4Y2hhbmdlIHJhdGUgZGF0YSBmb3IgdGhlIHBhc3QgeWVhciBiZWZvcmUgQm9UX2RhdGUNCnZvbF9kYXRhIDwtIGdldFN5bWJvbHMoDQogIFN5bWJvbHMgPSAiRVVSVVNEPVgiLA0KICBzcmMgPSAieWFob28iLA0KICBmcm9tID0gRVVSX0JvVCREYXRlIC0geWVhcnMoMSksDQogIHRvID0gRVVSX0JvVCREYXRlLA0KICBhdXRvLmFzc2lnbiA9IEZBTFNFDQopDQoNCiMgQ2FsY3VsYXRlIGRhaWx5IHJldHVybnMNCnJldHVybnMgPC0gZGFpbHlSZXR1cm4oQ2wodm9sX2RhdGEpKQ0KDQojIENhbGN1bGF0ZSBhbm51YWxpemVkIHZvbGF0aWxpdHkNCnZvbGF0aWxpdHkgPC0gc2QocmV0dXJucywgbmEucm0gPSBUUlVFKSAqIHNxcnQoMjUyKSAgIyAyNTIgdHJhZGluZyBkYXlzIGluIGEgeWVhcg0KYGBgDQoNCg0KU2V0IERvbWVzdGljIGFuZCBGb3JlaWduIFJpc2stRnJlZSBJbnRlcmVzdCBSYXRlcw0KRG9tZXN0aWMgUmlzay1GcmVlIFJhdGUgKHJfZG9tZXN0aWMpOiBVUyByaXNrLWZyZWUgcmF0ZQ0KRm9yZWlnbiBSaXNrLUZyZWUgUmF0ZSAocl9mb3JlaWduKTogRXVyb3BlYW4gcmlzay1mcmVlIHJhdGUNCg0KYGBge3J9DQpyX2RvbWVzdGljIDwtIDAuMDQzDQpyX2ZvcmVpZ24gPC0gMC4wMjQ3DQpgYGANCg0KDQpDYWxjdWxhdGUgT3B0aW9uIFByZW1pdW1zDQoNCmBgYHtyfQ0KIyBPcHRpb24gcHJlbWl1bSBvbiBCb1RfZGF0ZQ0KQm9UX3ByZW1pdW0gPC0gY2FsY3VsYXRlX2N1cnJlbmN5X29wdGlvbl9wcmVtaXVtKA0KICBTID0gRVVSX0JvVCRSYXRlLA0KICBLID0gc3RyaWtlX3ByaWNlLA0KICByX2RvbWVzdGljID0gcl9kb21lc3RpYywNCiAgcl9mb3JlaWduID0gcl9mb3JlaWduLA0KICB0aW1lX3RvX2V4cGlyYXRpb24gPSB0aW1lX3RvX2V4cGlyYXRpb25fQm9ULA0KICBzaWdtYSA9IHZvbGF0aWxpdHksDQogIG9wdGlvbl90eXBlID0gInB1dCINCikNCg0KIyBPcHRpb24gcHJlbWl1bSBvbiBFb1RfZGF0ZQ0KRW9UX3ByZW1pdW0gPC0gY2FsY3VsYXRlX2N1cnJlbmN5X29wdGlvbl9wcmVtaXVtKA0KICBTID0gRVVSX0VvVCRSYXRlLA0KICBLID0gc3RyaWtlX3ByaWNlLA0KICByX2RvbWVzdGljID0gcl9kb21lc3RpYywNCiAgcl9mb3JlaWduID0gcl9mb3JlaWduLA0KICB0aW1lX3RvX2V4cGlyYXRpb24gPSB0aW1lX3RvX2V4cGlyYXRpb25fRW9ULA0KICBzaWdtYSA9IHZvbGF0aWxpdHksDQogIG9wdGlvbl90eXBlID0gInB1dCINCikNCmBgYA0KDQoNCkNyZWF0ZSBEYXRhIEZyYW1lIHRvIERpc3BsYXkgUmVzdWx0cw0KDQpgYGB7cn0NCiMgQ3JlYXRlIGRhdGEgZnJhbWUgd2l0aCB0aGUgcmVzdWx0cw0KcmVzdWx0cyA8LSBkYXRhLmZyYW1lKA0KICBDdXJyZW5jeSA9ICJFVVIvVVNEIiwNCiAgQm9UX0RhdGUgPSBFVVJfQm9UJERhdGUsDQogIEJvVF9SYXRlID0gRVVSX0JvVCRSYXRlLA0KICBCb1RfT3B0aW9uX1ByZW1pdW0gPSBCb1RfcHJlbWl1bSwNCiAgRW9UX0RhdGUgPSBFVVJfRW9UJERhdGUsDQogIEVvVF9SYXRlID0gRVVSX0VvVCRSYXRlLA0KICBFb1RfT3B0aW9uX1ByZW1pdW0gPSBFb1RfcHJlbWl1bQ0KKQ0KDQojIERpc3BsYXkgdGhlIHJlc3VsdHMNCnByaW50KHJlc3VsdHMpDQpgYGANCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQpJbiB0aGlzIGxhc3QgZXhlcmNpc2Ugb2YgdGhlIHNlY3Rpb24gd2UgaGF2ZSByZXRyaWV2ZWQgdGhlIGluZm9ybWF0aW9uIG9mIHRoZSBSYXRlIG9mIEV4Y2hhbmdlIEVVUi9VU0QgYW5kIHdlIGhhZCBhbiBpbml0aWFsIGV4cGVjdGF0aW9uIG9mIGEgZGVjcmVhc2UgaW4gdGhlIHZhbHVlIG9mIHRoZSBFVVIgb3ZlciB0aGUgc2Nob29sIHRlcm0uIEhvd2V2ZXIsIG91ciBpbml0aWFsIHRob3VnaHRzIGhhdmUgYmVlbiBwcm92ZW4gd3JvbmcgYXMgd2UgaGF2ZSBvYnRhaW5lZCBhIGhpZ2hlciByYXRlIGF0IHRoZSBFb1QgZGF0ZSBhbmQgdGhlIE9wdGlvbiBQcmVtaXVtIGhhcyBmYWxsZW4uIEluIHRoZSBjYXNlIG9mIGhhdmluZyBidXllZCB0aGlzIHB1dCBvcHRpb24sIHRoZSBvdXRjb21lIHdvdWxkIGhhdmUgcmVzdWx0ZWQgaW4gYSBuZWdhdGl2ZSBvcGVyYXRpb24uIA0KVGhpcyByZXN1bHRzIGRlcGljdCBhbiBzdHJlbmd0aGVuZWQgRXVybyBhZ2FpbnN0IHRoZSBEb2xsYXIuIA0KRXZlbiB0aG91Z2ggb3VyIGluaXRpYWwgaHlwb3RoZXNpcyBvZiB0aGUgbW92ZW1lbnQgb2YgdGhlIEV1cm8gYWdhaW5zdCB0aGUgRG9sbGFyIHdlcmUgd3JvbmcsIHdlIGhhdmUgZGV2ZWxvcGVkIGFuIGFuc3dlciB0aGF0IGV4cGxhaW5zIGhvdyBhIHB1dCBvcHRpb24gb24gYW4gY3VycmVuY3kgZXhjaGFuZ2UgcmF0ZSBtYXkgYmUgcHJpY2VkIGFuZCBob3cgaXRzIHByZW1pdW0gY2FuIGJlIGNhbGN1bGF0ZWQsIHVzaW5nIHRoZSBHYXJtYW4tS29obGhhZ2VuIE1vZGVsIEZ1bmN0aW9uLiANCg0KDQoNCg0KIyMgTDIgRmluYW5jaWFsIG1hcmtldHMgbWljcm9zdHJ1Y3R1cmUNCg0KDQpOYXNkYXEgYW5kIExvbmRvbiBTdG9jayBFeGNoYW5nZSBhcmUgdHdvIG1ham9yIGdsb2JhbCBzdG9jayBleGNoYW5nZXMgd2l0aCBzaWduaWZpY2FudCBpbmZsdWVuY2Ugbm8gZ2xvYmFsIGZpbmFuY2lhbCBtYXJrZXRzLiANCkhpc3RvcmljYWwgU3RvY2sgZGF0YSBmb3IgcmVwcmVzZW50YXRpdmUgaW5kaWNlcyBvZiBib3RoIGV4Y2hhbmdlcyBjYW4gYmUgcmV0cmlldmVkIGFuZCBhbmFseXplZCB1c2luZyBSLiBRdWFsaXRhdGl2ZSBpbmZvcm1hdGlvbiBhYm91dCBhY2ggZXhjaGFuZ2UgaXMgYXZhaWxhYmxlIGZyb20gcmVwdXRhYmxlIHNvdXJjZXMuIA0KDQoNCiMjIyBIeXBvdGhlc2VzDQpUaGVyZSBpcyBhIHNpZ25pZmljYW50IGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHBlcmZvcm1hbmNlIG9mIE5hc2RhcSBhbmQgdGhlIExTRSBpbmRpY2VzIG92ZXIgdGhlIHNwZWNpZmllZCBwZXJpb2QuIA0KRGlmZmVyZW5jZXMgaW4gbWFya2V0IGNhcGl0YWxpemF0aW9uLCBsaXF1aWRpdHksIGFuZCB0eXBlcyBvZiBpbnN0cnVtZW50cyB0cmFkZWQgaW5mbHVlbmNlIHRoZSBzdGF0aXN0aWNhbCBtZWFzdXJlcyBvYnNlcnZlZA0KVGhlIHRpbWUgem9uZSBkaWZmZXJlbmNlIGFmZmVjdHMgdGhlIHRyYWRpbmcgcGF0dGVybnMgYW5kIGxpcXVpZGl0eSBvZiB0aGUgdHdvIGV4Y2hhbmdlcy4gDQoNCg0KIyMjIERhdGEgUmV0cmlldmFsIGFuZCBQcmVwYXJhdGlvbg0KDQpMb2FkIHJlcXVpcmVkIHBhY2thZ2VzDQpgYGB7cn0NCiMgSW5zdGFsbCBhbmQgbG9hZCByZXF1aXJlZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJxdWFudG1vZCIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInF1YW50bW9kIikNCn0NCmlmICghcmVxdWlyZSgiUGVyZm9ybWFuY2VBbmFseXRpY3MiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJQZXJmb3JtYW5jZUFuYWx5dGljcyIpDQp9DQpsaWJyYXJ5KHF1YW50bW9kKQ0KbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcykNCmBgYA0KDQoNClJldHJpZXZlIEhpc3RvcmljYWwgRGF0YQ0KYGBge3J9DQojIERlZmluZSB0aGUgZGF0ZSByYW5nZQ0Kc3RhcnRfZGF0ZSA8LSBhcy5EYXRlKCIyMDA4LTAxLTAzIikNCmVuZF9kYXRlIDwtIGFzLkRhdGUoIjIwMjMtMDEtMDUiKQ0KDQojIEdldCBoaXN0b3JpY2FsIGRhdGEgZm9yIE5hc2RhcSBDb21wb3NpdGUgSW5kZXgNCmdldFN5bWJvbHMoIl5JWElDIiwgc3JjID0gInlhaG9vIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpDQoNCiMgR2V0IGhpc3RvcmljYWwgZGF0YSBmb3IgRlRTRSAxMDAgSW5kZXgNCmdldFN5bWJvbHMoIl5GVFNFIiwgc3JjID0gInlhaG9vIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpDQpgYGANCg0KDQpEYXRhIENsZWFuaW5nIGFuZCBBbGlnbm1lbnQNCmBgYHtyfQ0KIyBBc3NpZ24gZGF0YSB0byB2YXJpYWJsZXMNCm5hc2RhcV9kYXRhIDwtIGBJWElDYA0KZnRzZV9kYXRhIDwtIGBGVFNFYA0KIyBDaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMNCnN1bShpcy5uYShmdHNlX2RhdGEpKQ0KDQojIEhhbmRsZSBtaXNzaW5nIHZhbHVlcyB1c2luZyBsaW5lYXIgaW50ZXJwb2xhdGlvbg0KZnRzZV9kYXRhIDwtIG5hLmFwcHJveChmdHNlX2RhdGEpDQoNCiMgTWVyZ2UgdGhlIGNsb3NpbmcgcHJpY2VzIGJhc2VkIG9uIGRhdGUNCmNvbWJpbmVkX2RhdGEgPC0gbWVyZ2UoQ2wobmFzZGFxX2RhdGEpLCBDbChmdHNlX2RhdGEpLCBhbGwgPSBGQUxTRSkNCg0KIyBSZW5hbWUgY29sdW1ucyBmb3IgY2xhcml0eQ0KY29sbmFtZXMoY29tYmluZWRfZGF0YSkgPC0gYygiTmFzZGFxX0Nsb3NlIiwgIkZUU0VfQ2xvc2UiKQ0KYGBgDQoNCg0KIyMjIFN0YXRpc3RpY2FsIEFuYWx5c2lzDQoNCg0KIyMjIyBDYWxjdWxhdGUgQmFzaWMgU3RhdGlzdGljcw0KDQoNCkZvciBOYXNkYXENCmBgYHtyfQ0KIyBDYWxjdWxhdGUgYmFzaWMgc3RhdGlzdGljcyBmb3IgTmFzZGFxDQpuYXNkYXFfc3RhdHMgPC0gZGF0YS5mcmFtZSgNCiAgTWVhbiA9IG1lYW4oY29tYmluZWRfZGF0YSROYXNkYXFfQ2xvc2UsIG5hLnJtID0gVFJVRSksDQogIE1lZGlhbiA9IG1lZGlhbihjb21iaW5lZF9kYXRhJE5hc2RhcV9DbG9zZSwgbmEucm0gPSBUUlVFKSwNCiAgU3REZXYgPSBzZChjb21iaW5lZF9kYXRhJE5hc2RhcV9DbG9zZSwgbmEucm0gPSBUUlVFKQ0KKQ0KcHJpbnQobmFzZGFxX3N0YXRzKQ0KYGBgDQoNCg0KRm9yIEZUU0UNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgYmFzaWMgc3RhdGlzdGljcyBmb3IgRlRTRQ0KZnRzZV9zdGF0cyA8LSBkYXRhLmZyYW1lKA0KICBNZWFuID0gbWVhbihjb21iaW5lZF9kYXRhJEZUU0VfQ2xvc2UsIG5hLnJtID0gVFJVRSksDQogIE1lZGlhbiA9IG1lZGlhbihjb21iaW5lZF9kYXRhJEZUU0VfQ2xvc2UsIG5hLnJtID0gVFJVRSksDQogIFN0RGV2ID0gc2QoY29tYmluZWRfZGF0YSRGVFNFX0Nsb3NlLCBuYS5ybSA9IFRSVUUpDQopDQpwcmludChmdHNlX3N0YXRzKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIENvcnJlbGF0aW9uDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIGNvcnJlbGF0aW9uIGJldHdlZW4gTmFzZGFxIGFuZCBGVFNFIGNsb3NpbmcgcHJpY2VzDQpjb3JyZWxhdGlvbiA8LSBjb3IoY29tYmluZWRfZGF0YSROYXNkYXFfQ2xvc2UsIGNvbWJpbmVkX2RhdGEkRlRTRV9DbG9zZSwgdXNlID0gImNvbXBsZXRlLm9icyIpDQoNCiMgUHJpbnQgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50DQpjYXQoIkNvcnJlbGF0aW9uIGJldHdlZW4gTmFzZGFxIGFuZCBGVFNFOiIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSwgIlxuIikNCmBgYA0KDQoNCkRpc3BsYXkgUmVzdWx0cw0KYGBge3J9DQoNCiMgQ29tYmluZSBzdGF0aXN0aWNzIGZvciBjb21wYXJpc29uDQpzdGF0c19jb21wYXJpc29uIDwtIHJiaW5kKE5hc2RhcSA9IG5hc2RhcV9zdGF0cywgRlRTRSA9IGZ0c2Vfc3RhdHMpDQoNCiMgU2V0IGNvbHVtbiBuYW1lcw0KY29sbmFtZXMoc3RhdHNfY29tcGFyaXNvbikgPC0gYygiTWVhbiIsICJNZWRpYW4iLCAiU3RhbmRhcmQgRGV2aWF0aW9uIikNCg0KIyBQcmludCB0aGUgc3RhdGlzdGljcw0KcHJpbnQoIkJhc2ljIFN0YXRpc3RpY3MgQ29tcGFyaXNvbjoiKQ0KcHJpbnQocm91bmQoc3RhdHNfY29tcGFyaXNvbiwgMikpDQoNCiMgUHJpbnQgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50DQpjYXQoIkNvcnJlbGF0aW9uIGJldHdlZW4gTmFzZGFxIGFuZCBGVFNFOiIsIHJvdW5kKGNvcnJlbGF0aW9uLCAyKSwgIlxuIikNCmBgYA0KDQoNCiMjIyMgQW5hbHlzaXMgb2YgdGhlIGNvcnJlbGF0aW9uDQpUaGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgbWVhc3VyZXMgdGhlIHN0cmVuZ3RoIGFuZCBkaXJlY3Rpb24gb2YgdGhlIHJlbGF0aW9uIGJldHdlZW4gdHdvIHNldHMgb2YgZGF0YSwgb3IgaW4gdGhpcyBjYXNlLCBvZiB0d28gYXNzZXRzLiBUaGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgY2FuIHZhcnkgZnJvbSAtMSB0byAxLCBhbmQgd2l0aCBlYWNoIHZhbHVlIHdlIG9idGFpbiBhIHJlcHJlc2VudGF0aW9uIG9mIGhvdyBpbnRlcmNvbm5lY3RlZCBhcmUgdHdvIGFzc2V0cy4gSW4gdGhlIGNhc2Ugb2YgdGhpcyBleGVyY2lzZSwgd2UgaGF2ZSBvYnRhaW5lZCBhIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIDAuNjUsIHdoaWNoIGNvbnN0aXR1dGVzIGEgcG9zaXRpdmUgYW5kIHN0cm9uZyBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28gaW5kZXhlcyBpbiBzdHVkeS4gDQpJbiBicm9hZGVyIHRlcm1zLCB0aGlzIG1lYW5zIHRoYXQgdGhlIHRlbmRlbmNpZXMgb2YgYm90aCBpbmRleGVzIHdpbGwgYmUgc29tZXdoYXQgc2ltaWxhciAgYW5kIHdpbGwgdHJlbmQgaW4gdGhlIHNhbWUgZGlyZWN0aW9uLiANCg0KDQojIyMjIE1hcmtldCBDYXBpdGFsaXphdGlvbg0KDQpNYXJrZXQgY2FwaXRhbGl6YXRpb24gcmVwcmVzZW50cyB0aGUgdG90YWwgdmFsdWUgb2YgYWxsIGxpc3RlZCBjb21wYW5pZXMgb24gYW4gZXhjaGFuZ2UuIEl0J3MgYSBrZXkgaW5kaWNhdG9yIG9mIHRoZSBzaXplIGFuZCBlY29ub21pYyB3ZWlnaHQgb2YgYSBzdG9jayBleGNoYW5nZS4gDQpBbHRob3VnaCB3ZSBkbyBub3QgaGF2ZSBhY2Nlc3MgdG8gZGlyZWN0IGRhdGEsIHdlIHdpbGwgdHJ5IHRvIG1ha2UgdGhlIGNvbXBhcmlzb24gdXNpbmcgdGhlIHRvcCA1IGNvbXBhbmllcyBmcm9tIGVhY2ggZXhjaGFuZ2UuDQoNCg0KSHlwb3RoZXNpczoNCg0KVGhlIE5hc2RhcSBoYXMgYSBsYXJnZXIgbWFya2V0IGNhcGl0YWxpemF0aW9uIGNvbXBhcmVkIHRvIExTRSBkdWUgdG8gaXRzIGNvbmNlbnRyYXRpb24gb2YgbGFyZ2UgdGVjaG5vbG9neSBjb21wYW5pZXMNCg0KDQoNCkltcGxlbWVudGF0aW9uOg0KDQoNCkxvYWQgcGFja2FnZXMNCg0KYGBge3J9DQoNCiMgSW5zdGFsbCBhbmQgbG9hZCByZXF1aXJlZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJxdWFudG1vZCIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInF1YW50bW9kIikNCn0NCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCg0KRGVmaW5lIFRvcCBDb21wYW5pZXMuIFdlIHdpbGwgZXh0cmFjdCB0aGlzIGNvbXBhbmllcyBmcm9tIHRoZSBpbmRleGVzIHdlYnNpdGVzLiANCkxTRSB0b3AgNSBjb21wYW5pZXM6IEF0cmF6ZW5lY2EgUExDLCBTaGVsbCBQTEMsIEhTQkMgSExER1MgUExDLCBVbmlsZXZlciBQTEMsIFJFTFggUExDLiAgDQpOQVNEQVEgdG9wIDUgY29tcGFuaWVzOiBBcHBsZSBJbmMsIE5WSURJQSBjb3JwLCBNaWNyb3NvZnQgQ29ycCwgQW1hem9uLmNvbSBJbmMsIEJyb2FkY29tIEluYy4gDQoNCg0KYGBge3J9DQpuYXNkYXFfc3ltYm9scyA8LSBjKCJBQVBMIiwgIk5WREEiLCAiTVNGVCIsICJBTVpOIiwgIkFWR08iKQ0KbHNlX3N5bWJvbHMgPC0gYygiQVpOLkwiLCAiU0hFTC5MIiwgIkhTQkEuTCIsICJVTFZSLkwiLCAiUkVMLkwiKQ0KDQpgYGANCg0KDQpSZXRyaWV2ZSBNYXJrZXQgQ2FwaXRhbGl6YXRpb24gRGF0YQ0KDQpgYGB7cn0NCg0KIyBJbnN0YWxsIGFuZCBsb2FkIHRpZHlxdWFudA0KaWYgKCFyZXF1aXJlKCJ0aWR5cXVhbnQiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5cXVhbnQiKQ0KfQ0KbGlicmFyeSh0aWR5cXVhbnQpDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCg0KR2V0IE1hcmtldCBDYXAgRGF0YQ0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gdG8gZ2V0IG1hcmtldCBjYXAgZGF0YQ0KZ2V0X21hcmtldF9jYXAgPC0gZnVuY3Rpb24oc3ltYm9scykgew0KICAjIFJldHJpZXZlIG1hcmtldCBjYXBpdGFsaXphdGlvbiBkYXRhDQogIGRhdGEgPC0gZ2V0UXVvdGUoc3ltYm9scywgd2hhdCA9IHlhaG9vUUYoIk1hcmtldCBDYXBpdGFsaXphdGlvbiIpKQ0KICANCiAgIyBDb252ZXJ0IHJvd25hbWVzIHRvIGEgY29sdW1uDQogIGRhdGEgPC0gZGF0YSAlPiUNCiAgICByb3duYW1lc190b19jb2x1bW4odmFyID0gInN5bWJvbCIpICU+JQ0KICAgIHJlbmFtZShtYXJrZXRfY2FwID0gYE1hcmtldCBDYXBpdGFsaXphdGlvbmApICU+JQ0KICAgIHNlbGVjdChzeW1ib2wsIG1hcmtldF9jYXApDQogIA0KICByZXR1cm4oZGF0YSkNCn0NCg0KIyBHZXQgbWFya2V0IGNhcCBkYXRhIGZvciBOYXNkYXEgY29tcGFuaWVzDQpuYXNkYXFfbWFya2V0X2NhcCA8LSBnZXRfbWFya2V0X2NhcChuYXNkYXFfc3ltYm9scykNCg0KIyBHZXQgbWFya2V0IGNhcCBkYXRhIGZvciBMU0UgY29tcGFuaWVzDQpsc2VfbWFya2V0X2NhcCA8LSBnZXRfbWFya2V0X2NhcChsc2Vfc3ltYm9scykNCmBgYA0KDQoNClN1bSBNYXJrZXQgQ2Fwcw0KDQpgYGB7cn0NCiMgU3VtIHRoZSBtYXJrZXQgY2Fwcw0KbmFzZGFxX3RvdGFsX21hcmtldF9jYXAgPC0gc3VtKGFzLm51bWVyaWMobmFzZGFxX21hcmtldF9jYXAkbWFya2V0X2NhcCksIG5hLnJtID0gVFJVRSkNCmxzZV90b3RhbF9tYXJrZXRfY2FwIDwtIHN1bShhcy5udW1lcmljKGxzZV9tYXJrZXRfY2FwJG1hcmtldF9jYXApLCBuYS5ybSA9IFRSVUUpDQoNCiMgQ29udmVydCB0byB0cmlsbGlvbnMgZm9yIHJlYWRhYmlsaXR5DQpuYXNkYXFfdG90YWxfbWFya2V0X2NhcF90cmlsbGlvbiA8LSBuYXNkYXFfdG90YWxfbWFya2V0X2NhcCAvIDFlMTINCmxzZV90b3RhbF9tYXJrZXRfY2FwX3RyaWxsaW9uIDwtIGxzZV90b3RhbF9tYXJrZXRfY2FwIC8gMWUxMg0KDQojIFByaW50IHRoZSByZXN1bHRzDQpjYXQoIk5hc2RhcSBUb3AgQ29tcGFuaWVzIFRvdGFsIE1hcmtldCBDYXA6ICQiLCByb3VuZChuYXNkYXFfdG90YWxfbWFya2V0X2NhcF90cmlsbGlvbiwgMiksICIgdHJpbGxpb25cbiIpDQpjYXQoIkxTRSBUb3AgQ29tcGFuaWVzIFRvdGFsIE1hcmtldCBDYXA6ICQiLCByb3VuZChsc2VfdG90YWxfbWFya2V0X2NhcF90cmlsbGlvbiwgMiksICIgdHJpbGxpb25cbiIpDQpgYGANCg0KDQpIYW5kbGUgRXhjaGFuZ2UgUmF0ZXMNCg0KYGBge3J9DQojIEdldCBjdXJyZW50IEdCUCB0byBVU0QgZXhjaGFuZ2UgcmF0ZQ0KZ2V0U3ltYm9scygiR0JQVVNEPVgiLCBzcmMgPSAieWFob28iLCBmcm9tID0gU3lzLkRhdGUoKSAtIDEsIHRvID0gU3lzLkRhdGUoKSkNCmV4Y2hhbmdlX3JhdGUgPC0gYXMubnVtZXJpYyhDbChgR0JQVVNEPVhgKVsxXSkNCg0KIyBDb252ZXJ0IExTRSBtYXJrZXQgY2FwcyB0byBVU0QNCmxzZV9tYXJrZXRfY2FwJG1hcmtldF9jYXBfdXNkIDwtIGFzLm51bWVyaWMobHNlX21hcmtldF9jYXAkbWFya2V0X2NhcCkgKiBleGNoYW5nZV9yYXRlDQoNCiMgU3VtIHRoZSBjb252ZXJ0ZWQgbWFya2V0IGNhcHMNCmxzZV90b3RhbF9tYXJrZXRfY2FwX3VzZCA8LSBzdW0obHNlX21hcmtldF9jYXAkbWFya2V0X2NhcF91c2QsIG5hLnJtID0gVFJVRSkNCmxzZV90b3RhbF9tYXJrZXRfY2FwX3RyaWxsaW9uX3VzZCA8LSBsc2VfdG90YWxfbWFya2V0X2NhcF91c2QgLyAxZTEyDQoNCiMgVXBkYXRlIHRoZSBwcmludCBzdGF0ZW1lbnQNCmNhdCgiTFNFIFRvcCBDb21wYW5pZXMgVG90YWwgTWFya2V0IENhcDogJCIsIHJvdW5kKGxzZV90b3RhbF9tYXJrZXRfY2FwX3RyaWxsaW9uX3VzZCwgMiksICIgdHJpbGxpb24gKGNvbnZlcnRlZCB0byBVU0QpXG4iKQ0KYGBgDQoNCldoZW4gdHJ5aW5nIHRvIHBlcmZvcm0gb3V0IGFuYWx5c2lzIG9mIHRoZSBtYXJrZXQgY2FwaXRhbGl6YXRpb24gd2UgaGF2ZSBlbmNvdW50ZXIgYSBwcm9ibGVtIHR3byByZXRyaWV2ZSBkYXRhIGZyb20gUiwgc28gd2UgY2Fubm90IHBlcmZvcm0gdGhlIG51bWVyaWNhbCBkZW1vbnN0cmF0aW9uLiBIb3dldmVyLCB3ZSB3aWxsIHN0YXRlIHRoYXQgYXMgZmFyIGFzIHRoZSBpbmZvcm1hdGlvbiB3ZSBoYXZlIGJlZW4gYWJsZSB0byBnYXRoZXIsIHRoZSBMU0VHIGhhcyBhIGhpZ2hlciBtYXJrZXQgY2FwaXRhbGl6YXRpb24gdGhhbiBOYXNkYXEsIEluYy4gVGhpcyBtZWFucyB0aGF0IHRoZSBMU0UgaGFzIGEgaGlnaGVyIGNvcnBvcmF0ZSBtYXJrZXQgY2FwaXRhbGl6YXRpb24uIEhvd2V2ZXIsIGlmIHdlIHRha2UgaW50byBhY2NvdW50IHRoZSBhZ2dyZWdhdGUgbWFya2V0IGNhcGl0YWxpemF0aW9uLCB0aGUgdG90YWwgbWFya2V0IHZhbHVlIG9mIHRoZSBhc3NldHMgdHJhZGVkIGluIE5hc2RhcSBncmVhdGx5IHN1cnBhc3MgdGhlIHZhbHVlIG9mIHRob3NlIHRyYWRlZCBpbiB0aGUgTFNFLiANCg0KQSBoaWdoZXIgbWFya2V0IGNhcGl0YWxpemF0aW9uIG1heSBpbmRpY2F0ZSBoaWdoZXIgZWNvbm9taWMgaW5mbHVlbmNlLCBsaXF1aWRpdHkgYW5kIG92ZXJhbGwgaW50ZXJuYXRpb25hbCBhdHRyYWN0aXZlbmVzcy4gSG93ZXZlciwgaW4gdGhpcyBjYXNlIE5hc2RhcSdzIHRob3JvdWdoIGZvY3VzIG9uIHRlY2hub2xvZ2ljYWwgY29tcGFuaWVzIG5hcnJvd3MgaXRzIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBlY29ub215IHdoaWxlIHRoZSBMU0UgaGFzIGEgYnJvYWRlciByYW5nZSBvZiBhc3NldHMuDQoNCg0KIyMjIyBMaXF1aWRpdHkuIA0KDQpJdCByZWZsZWN0cyBob3cgZWFzaWx5IGNhbiBhc3NldHMgYmUgYm91Z2h0IGFuZCBzb2xkIGluIHRoZSBtYXJrZXQuIEhpZ2hlciB0cmFkaW5nIHZvbHVtZXMgaW5kaWNhdGUgaGlnaGVyIGxpcXVpZGl0eS4gDQoNCkh5cG90aGVzaXMuIA0KDQpUaGUgTmFzZGFxIGhhcyBhIGhpZ2hlciBhdmVyYWdlIHRyYWRpbmcgdm9sdW1lcyBjb21wYXJlZCB0byBMU0UgZHVlIHRvIGl0cyBsYXJnZXIgc2l6ZSBhbmQgZ2xvYmFsIGludmVzdG9yIGJhc2UNCg0KV2Ugd2lsbCByZXRyaWV2ZSB0aGUgZGFpbHkgdHJhZGluZyB2b2x1bWUgZGF0YSBmcm9tIHRoZSBpbmRpY2VzIGFuZCBjYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgZGFpbHkgdm9sdW1lIG92ZXIgYW4gc3BlY2lmaWVkIHBlcmlvZC4gDQoNCkZvciB0aGUgVm9sdW1lIERhdGEgd2Ugd2lsbCBiZSB1c2luZyB0aGVpciB0b3AgY29tcGFuaWVzIGFzIGEgcHJveHkuIA0KDQpgYGB7cn0NCm5hc2RhcV92b2x1bWVzIDwtIGxpc3QoKQ0KZm9yIChzeW1ib2wgaW4gbmFzZGFxX3N5bWJvbHMpIHsNCiAgZGF0YSA8LSBnZXRTeW1ib2xzKHN5bWJvbCwgc3JjID0gInlhaG9vIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUsIGF1dG8uYXNzaWduID0gRkFMU0UpDQogIG5hc2RhcV92b2x1bWVzW1tzeW1ib2xdXSA8LSBDbChkYXRhKQ0KfQ0KDQojIEdldCB2b2x1bWUgZGF0YSBmb3IgdG9wIExTRSBjb21wYW5pZXMNCmxzZV92b2x1bWVzIDwtIGxpc3QoKQ0KZm9yIChzeW1ib2wgaW4gbHNlX3N5bWJvbHMpIHsNCiAgZGF0YSA8LSBnZXRTeW1ib2xzKHN5bWJvbCwgc3JjID0gInlhaG9vIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUsIGF1dG8uYXNzaWduID0gRkFMU0UpDQogIHZvbHVtZV9kYXRhIDwtIFZvKGRhdGEpDQogIA0KICAjIEhhbmRsZSBtaXNzaW5nIHZhbHVlcw0KICBpZiAoYW55KGlzLm5hKHZvbHVtZV9kYXRhKSkpIHsNCiAgICBjYXQoIkhhbmRsaW5nIG1pc3NpbmcgdmFsdWVzIGZvciIsIHN5bWJvbCwgIlxuIikNCiAgICB2b2x1bWVfZGF0YSA8LSBuYS5hcHByb3godm9sdW1lX2RhdGEpDQogIH0NCiAgDQogICMgU3RvcmUgY2xlYW5lZCB2b2x1bWUgZGF0YQ0KICBsc2Vfdm9sdW1lc1tbc3ltYm9sXV0gPC0gdm9sdW1lX2RhdGENCn0NCg0KIyBNZXJnZSBhbmQgYWxpZ24gTFNFIHZvbHVtZXMNCmxzZV92b2x1bWVfZGF0YSA8LSBkby5jYWxsKG1lcmdlLCBsc2Vfdm9sdW1lcykNCg0KIyBSZW1vdmUgYW55IHJlbWFpbmluZyBtaXNzaW5nIHZhbHVlcw0KbHNlX3ZvbHVtZV9kYXRhIDwtIG5hLm9taXQobHNlX3ZvbHVtZV9kYXRhKQ0KYGBgDQoNCg0KV2UgY2FsY3VsYXRlIEF2ZXJhZ2UgVm9sdW1lDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgYXZlcmFnZSB2b2x1bWUgZm9yIE5hc2RhcSBjb21wYW5pZXMNCm5hc2RhcV9hdmdfdm9sdW1lcyA8LSBzYXBwbHkobmFzZGFxX3N5bWJvbHMsIGZ1bmN0aW9uKHN5bWJvbCkgew0KICBkYXRhIDwtIGdldFN5bWJvbHMoc3ltYm9sLCBzcmMgPSAieWFob28iLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSwgYXV0by5hc3NpZ24gPSBGQUxTRSkNCiAgbWVhbihWbyhkYXRhKSwgbmEucm0gPSBUUlVFKQ0KfSkNCg0KIyBDYWxjdWxhdGUgYXZlcmFnZSB2b2x1bWUgZm9yIExTRSBjb21wYW5pZXMNCmxzZV9hdmdfdm9sdW1lcyA8LSBzYXBwbHkobHNlX3ZvbHVtZXMsIGZ1bmN0aW9uKHZvbHVtZV9kYXRhKSB7DQogIG1lYW4odm9sdW1lX2RhdGEsIG5hLnJtID0gVFJVRSkNCn0pDQoNCiMgQ2FsY3VsYXRlIHRoZSBvdmVyYWxsIGF2ZXJhZ2Ugdm9sdW1lDQpsc2VfYXZnX3ZvbHVtZSA8LSBtZWFuKGxzZV9hdmdfdm9sdW1lcywgbmEucm0gPSBUUlVFKQ0KDQojIEF2ZXJhZ2Ugdm9sdW1lIGFjcm9zcyB0b3AgY29tcGFuaWVzDQpuYXNkYXFfYXZnX3ZvbHVtZSA8LSBtZWFuKG5hc2RhcV9hdmdfdm9sdW1lcywgbmEucm0gPSBUUlVFKQ0KbHNlX2F2Z192b2x1bWUgPC0gbWVhbihsc2VfYXZnX3ZvbHVtZXMsIG5hLnJtID0gVFJVRSkNCg0KIyBQcmludCByZXN1bHRzDQpjYXQoIkF2ZXJhZ2UgRGFpbHkgVHJhZGluZyBWb2x1bWUgZm9yIE5hc2RhcSBUb3AgQ29tcGFuaWVzOiIsIGZvcm1hdEMobmFzZGFxX2F2Z192b2x1bWUsIGZvcm1hdCA9ICJmIiwgYmlnLm1hcmsgPSAiLCIsIGRpZ2l0cyA9IDApLCAiXG4iKQ0KY2F0KCJBdmVyYWdlIERhaWx5IFRyYWRpbmcgVm9sdW1lIGZvciBMU0UgVG9wIENvbXBhbmllczoiLCBmb3JtYXRDKGxzZV9hdmdfdm9sdW1lLCBmb3JtYXQgPSAiZiIsIGJpZy5tYXJrID0gIiwiLCBkaWdpdHMgPSAwKSwgInNoYXJlc1xuIikNCmBgYA0KDQoNCiMjIyMgQW5hbHlzaXMgb2YgcmVzdWx0cw0KDQpXZSBlbmNvdW50ZXIgc29tZSBsaW1pdGF0aW9uIHJlZ2FyZGluZyB0aGlzIGNvbXBhcmlzb24sIGFzIHRoZSB2b2x1bWUgdW5pdHMgbWF5IGRpZmZlciBiZXR3ZWVuIGV4Y2hhbmdlcyBhbmQgdGhlIHZvbHVtZSBkYXRhIGZvciBpbmRpY2VzIG1heSBub3QgYmUgZGlyZWN0bHkgY29tcGFyYWJsZS4gSG93ZXZlciwgaXQgYmVjb21lcyBub3RpY2VhYmxlIHRoYXQgdGhlIGF2ZXJhZ2UgdHJhZGluZyB2b2x1bWUgZm9yIE5hc2RhcSdzIFRvcCBjb21wYW5pZXMgaXMgc2lnbmlmaWNhbnRseSBoaWdoZXIgdGhhbiB0aGF0IG9mIExTRS4gVGhpcyBpbmRpY2F0ZXMgYSBtb3JlIGFjdGl2ZSBtYXJrZXQgYW5kIGlzIHVuZGVyc3RhbmRhYmx5IGV4cGxhaW5lZCBieSB0aGUgY29uc3RhbnRseSBjaGFuZ2luZyBlbnZpcm9ubWVudCBvZiB0aGUgdGVjaG5vbG9naWNhbCBjb21wYW5pZXMgdHJhZGVkIGluIHRoZSBOYXNkYXEuDQoNCg0KDQojIyMgTnVtYmVyIG9mIElQT3MNCg0KVGhlIG51bWJlciBvZiBJbml0aWFsIFB1YmxpYyBPZmZlcmluZ3MgcmVmbGVjdHMgdGhlIGF0dHJhY3RpdmVuZXNzIG9mIGFuIGV4Y2hhbmdlIGZvciBjb21wYW5pZXMgbG9va2luZyB0byByYWlzZSBjYXBpdGFsLiBEdWUgdG8gbGFjayBvZiBwb3NzaWJpbGl0eSB0byByZXRyaWV2ZSBzdWNoIGRhdGEsIHdlIHdpbGwganVzdCBtZW50aW9uIHRoYXQgcmVjZW50IGRhdGEgc2lnbmFscyBhIGdyZWF0ZXIgbnVtYmVyIG9mIElQT3MgaW4gTmFzZGFxIGNvbXBhcmVkIHRvIHRob3NlIG9mIExTRSwgd2hpY2ggaW5kaWNhdGVzIGEgbXVjaCBtb3JlIGF0dHJhY3RpdmUgc3RvY2sgZXhjaGFuZ2UgYm90aCBmb3IgaW52ZXN0b3JzIGFuZCBmb3IgY29tcGFuaWVzIHdobyBzZWVrIHRvIHJhaXNlIGNhcGl0YWwsIGFuZCBnaXZlcyBhIGdyZWF0IGV4YW1wbGUgb2YgaG93IHJlbWFya2FibGUgYXJlIHNlY3RvciB0cmVuZHMgaW4gdGhlIG1hbmlmZXN0YXRpb24gb2YgSVBPcy4NCg0KDQojIyMgTSZBIEZyZXF1ZW5jeQ0KDQpUaGUgZnJlcXVlbmN5IGluIG1lcmdlcnMgYW5kIGFjcXVpc2l0aW9ucyBtYXkgaW5kaWNhdGUgdGhlIGR5bmFtaXNtIG9mIHRoZSBtYXJrZXQuIA0KDQpUaGlzIGRhdGEgaXMgeWV0IGFnYWluIG5vdCBhdmFpbGFibGUgZGlyZWN0bHkgZnJvbSBSLCBidXQgd2UgbWF5IGZpbmQgaXQgZnJvbSBvdGhlciBzb3VyY2VzLiANCg0KTmFzZGFxOiBhY3RpdmUgTSZBIGVudmlyb25tZW50IGluIHRlY2hub2xvZ3kgYW5kIGJpb3RlY2ggc2VjdG9ycy4NCg0KTFNFOiByZWd1bGFyIE0mQSBhY3Rpdml0eSBhY3Jvc3Mgc2VjdG9ycyBsaWtlIGZpbmFuY2UsIGVuZXJneSBhbmQgbWluaW5nLg0KDQoNCiMjIyBRdWFsaXR5IG9mIGluZm9ybWF0aW9uDQoNCk5hc2RhcToNClJlZ3VsYXRlZCBieSB0aGUgVS5TLiBTZWN1cml0aWVzIGFuZCBFeGNoYW5nZSBDb21taXNzaW9uIChTRUMpLg0KU3RyaWN0IHJlcG9ydGluZyBhbmQgZGlzY2xvc3VyZSByZXF1aXJlbWVudHMuDQpVc2VzIG1hcmtldCBtYWtlcnMgYW5kIGVsZWN0cm9uaWMgY29tbXVuaWNhdGlvbiBuZXR3b3JrcyAoRUNOcykgYXMgZ2F0ZWtlZXBlcnMuDQoNCkxTRToNClJlZ3VsYXRlZCBieSB0aGUgRmluYW5jaWFsIENvbmR1Y3QgQXV0aG9yaXR5IChGQ0EpIGluIHRoZSBVSy4NCkVtcGhhc2lzIG9uIHRyYW5zcGFyZW5jeSBhbmQgbWFya2V0IGludGVncml0eS4NClNwb25zb3JzIGFuZCBub21pbmF0ZWQgYWR2aXNvcnMgKE5vbWFkcykgYWN0IGFzIGdhdGVrZWVwZXJzIGZvciBBSU0uDQoNCg0KIyMjIFRyYWRpbmcgQ29zdHMNCg0KTmFzZGFxOiBUcmFkaW5nIGNvc3RzIGluY2x1ZGUgYnJva2VyYWdlIGZlZXMsIFNFQyBmZWVzLCBhbmQgcG90ZW50aWFsIGV4Y2hhbmdlIGZlZXMuDQpHZW5lcmFsbHkgbG93IGR1ZSB0byBoaWdoIGNvbXBldGl0aW9uIGFtb25nIGJyb2tlcnMuDQoNCkxTRTogVHJhZGluZyBjb3N0cyBtYXkgaW5jbHVkZSBicm9rZXJhZ2UgZmVlcywgc3RhbXAgZHV0eSAoMC41JSBvbiBwdXJjaGFzZXMpLCBhbmQgb3RoZXIgdHJhbnNhY3Rpb24gY29zdHMuDQoNCg0KIyMjIFRyYWRpbmcgSG91cnMgKHRpbWUgem9uZSBkaWZmZXJlbmNlKQ0KDQpXZSBtYXkgcXVhbnRpZnkgdGhlIHRyYWRpbmcgaG91cnMgYW5kIGNhbGN1bGF0ZSB0aGUgb3ZlcmxhcA0KYGBge3J9DQojIE5hc2RhcSB0cmFkaW5nIGhvdXJzOiA5OjMwIEFNIHRvIDQ6MDAgUE0gRVNUDQojIExTRSB0cmFkaW5nIGhvdXJzOiA4OjAwIEFNIHRvIDQ6MzAgUE0gR01UDQoNCiMgQ29udmVydCB0cmFkaW5nIGhvdXJzIHRvIFVUQw0KbmFzZGFxX29wZW5fdXRjIDwtIGFzLlBPU0lYY3QoIjE0OjMwIiwgZm9ybWF0ID0gIiVIOiVNIiwgdHogPSAiVVRDIikgICMgOTozMCBBTSBFU1QgaXMgMTQ6MzAgVVRDDQpuYXNkYXFfY2xvc2VfdXRjIDwtIGFzLlBPU0lYY3QoIjIxOjAwIiwgZm9ybWF0ID0gIiVIOiVNIiwgdHogPSAiVVRDIikgICMgNDowMCBQTSBFU1QgaXMgMjE6MDAgVVRDDQoNCmxzZV9vcGVuX3V0YyA8LSBhcy5QT1NJWGN0KCIwODowMCIsIGZvcm1hdCA9ICIlSDolTSIsIHR6ID0gIlVUQyIpDQpsc2VfY2xvc2VfdXRjIDwtIGFzLlBPU0lYY3QoIjE2OjMwIiwgZm9ybWF0ID0gIiVIOiVNIiwgdHogPSAiVVRDIikNCg0KIyBDYWxjdWxhdGUgb3ZlcmxhcA0Kb3ZlcmxhcF9zdGFydCA8LSBtYXgobmFzZGFxX29wZW5fdXRjLCBsc2Vfb3Blbl91dGMpDQpvdmVybGFwX2VuZCA8LSBtaW4obmFzZGFxX2Nsb3NlX3V0YywgbHNlX2Nsb3NlX3V0YykNCg0KaWYgKG92ZXJsYXBfc3RhcnQgPCBvdmVybGFwX2VuZCkgew0KICBvdmVybGFwX2hvdXJzIDwtIGFzLm51bWVyaWMoZGlmZnRpbWUob3ZlcmxhcF9lbmQsIG92ZXJsYXBfc3RhcnQsIHVuaXRzID0gImhvdXJzIikpDQp9IGVsc2Ugew0KICBvdmVybGFwX2hvdXJzIDwtIDANCn0NCg0KIyBQcmludCByZXN1bHRzDQpjYXQoIk92ZXJsYXAgaW4gVHJhZGluZyBIb3VyczogIiwgb3ZlcmxhcF9ob3VycywgIiBob3Vyc1xuIikNCmBgYA0KDQoNCkhlcmUgd2UgaGF2ZSBjYWxjdWxhdGVkIHRoZSBvdmVybGFwaW5nIGluIHRyYWRpbmcgaG91cnMuIFRoZSBsb3cgb3ZlcmxhcGluZyB0cmFkaW5nIGhvdXJzIGNhbiBoYXZlIGh1Z2UgaW1wYWN0cyBvbiB0aGUgdHJhZGluZyBzdHJhdGVnaWVzLCBhcyB0aGUgaW5mb3JtYXRpb24gZnJvbSBvbmUgbWFya2V0IHdpbGwgYWxyZWFkeSBiZSBpbmNvcnBvcmF0ZWQgYXQgdGhlIG9wZW5pbmcgb2YgdGhlIG90aGVyLiBUaGlzIGNhdXNlcyBzaGlmdHMgaW4gdm9sYXRpbGl0eSBhbmQgaW52ZXN0b3IncyBiZWhhdmlvdXIsIGJ1dCBjYW4gYWxzbyBiZSB1c2VkIGFzIGFuIHN0cmF0ZWdpYyBhZHZhbnRhZ2UgZm9yIGRpdmVyc2lmeWluZyB0aGVpciBpbnZlc3RtZW50cy4gDQoNCg0KDQojIyBMMyBJbnN0cnVtZW504oCZcyBvdmVydmlldyBhbmQgdmFsdWF0aW9uDQoNCg0KIyMjIEwzLjEgQ29tcGFyZSB0aGUgMTMtd2VlayBUcmVhc3VyeSBiaWxsIHJhdGUgKHdoaWNoIGlzIGEgcHJveHkgZm9yIHNob3J0LXRlcm0gaW50ZXJlc3QgcmF0ZXMpIGF0IHRoZSBlbmQgb2YgdGhlIHNjaG9vbCB0ZXJtIHRvIHRoZSByYXRlIHRoYXQgZXhpc3RlZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybS4gKG5vdGU6IDMtTW9udGggVHJlYXN1cnkgQmlsbCBTZWNvbmRhcnkgTWFya2V0IFJhdGUsIERpc2NvdW50IEJhc2lzIChUQjNNUykpDQoNCg0KbG9hZCBwYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmBgYA0KDQoNCmRlZmluZSBkYXRlcw0KDQpgYGB7cn0NCiMgRGVmaW5lIEJlZ2lubmluZyBvZiBUZXJtIChCb1QpIGFuZCBFbmQgb2YgVGVybSAoRW9UKSBkYXRlcw0KQm9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNS0wMSIpDQpFb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCmBgYA0KDQoNClJldHJpZXZlIGRhdGENCg0KYGBge3J9DQojIFJldHJpZXZlIFRCM01TIGRhdGEgZnJvbSBGUkVEDQpnZXRTeW1ib2xzKCJUQjNNUyIsIHNyYyA9ICJGUkVEIikNCg0KIyBWaWV3IHRoZSBmaXJzdCBmZXcgcm93cyBvZiBkYXRhDQpoZWFkKFRCM01TKQ0KYGBgDQoNCg0KRnVuY3Rpb24gdG8gYWRqdXN0IHRvIG5vbi10cmFkaW5nIGRheXMNCg0KYGBge3J9DQojIEZ1bmN0aW9uIHRvIGdldCB0aGUgcmF0ZSBvbiBhIHNwZWNpZmljIGRhdGUsIGFkanVzdGluZyBmb3Igbm9uLXRyYWRpbmcgZGF5cw0KZ2V0X3JhdGVfb25fZGF0ZSA8LSBmdW5jdGlvbihkYXRhLCBkYXRlLCB1c2VfbmV4dCA9IEZBTFNFKSB7DQogICMgQ29udmVydCBpbmRleCB0byBEYXRlIGZvcm1hdCBpZiBub3QgYWxyZWFkeQ0KICBpbmRleChkYXRhKSA8LSBhcy5EYXRlKGluZGV4KGRhdGEpKQ0KICANCiAgaWYgKHVzZV9uZXh0KSB7DQogICAgIyBHZXQgdGhlIG5leHQgYXZhaWxhYmxlIGRhdGUgYWZ0ZXIgdGhlIHNwZWNpZmllZCBkYXRlDQogICAgYXZhaWxhYmxlX2RhdGVzIDwtIGluZGV4KGRhdGEpW2luZGV4KGRhdGEpID49IGRhdGUgJiAhaXMubmEoZGF0YVtpbmRleChkYXRhKV0pXQ0KICAgIGlmKGxlbmd0aChhdmFpbGFibGVfZGF0ZXMpID09IDApIHsNCiAgICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIGFmdGVyIiwgZGF0ZSkpDQogICAgICByZXR1cm4obGlzdChSYXRlID0gTkEsIERhdGUgPSBOQSkpDQogICAgfQ0KICAgIGRhdGVfdXNlZCA8LSBtaW4oYXZhaWxhYmxlX2RhdGVzKQ0KICB9IGVsc2Ugew0KICAgICMgR2V0IHRoZSBsYXN0IGF2YWlsYWJsZSBkYXRlIGJlZm9yZSBvciBvbiB0aGUgc3BlY2lmaWVkIGRhdGUNCiAgICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPD0gZGF0ZSAmICFpcy5uYShkYXRhW2luZGV4KGRhdGEpXSldDQogICAgaWYgKGxlbmd0aChhdmFpbGFibGVfZGF0ZXMpID09IDApIHsNCiAgICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIGJlZm9yZSIsIGRhdGUpKQ0KICAgICAgcmV0dXJuKGxpc3QoUmF0ZSA9IE5BLCBEYXRlID0gTkEpKQ0KICAgIH0NCiAgICBkYXRlX3VzZWQgPC0gbWF4KGF2YWlsYWJsZV9kYXRlcykNCiAgfQ0KICANCiAgIyBHZXQgdGhlIHJhdGUNCiAgcmF0ZSA8LSBhcy5udW1lcmljKGRhdGFbZGF0ZV91c2VkXSkNCiAgDQogIHJldHVybihsaXN0KA0KICAgIFJhdGUgPSByYXRlLA0KICAgIERhdGUgPSBhcy5EYXRlKGRhdGVfdXNlZCkNCiAgKSkNCn0NCmBgYA0KDQoNClJldHJpZXZlIFJhdGVzIG9uIEJvVF9kYXRlIGFuZCBFb1RfZGF0ZQ0KDQpgYGB7cn0NCiMgR2V0IHJhdGUgb24gQm9UX2RhdGUNCkJvVF9yYXRlIDwtIGdldF9yYXRlX29uX2RhdGUoVEIzTVMsIEJvVF9kYXRlLCB1c2VfbmV4dCA9IFRSVUUpDQoNCiMgR2V0IHJhdGUgb24gRW9UX2RhdGUNCkVvVF9yYXRlIDwtIGdldF9yYXRlX29uX2RhdGUoVEIzTVMsIEVvVF9kYXRlLCB1c2VfbmV4dCA9IEZBTFNFKQ0KYGBgDQoNCg0KQ3JlYXRlIERhdGEgRnJhbWUgdG8gZGlzcGxheSByZXN1bHRzDQoNCmBgYHtyfQ0KIyBDcmVhdGUgZGF0YSBmcmFtZSB3aXRoIHRoZSByZXN1bHRzDQpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoDQogIERhdGUgPSBjKEJvVF9yYXRlJERhdGUsIEVvVF9yYXRlJERhdGUpLA0KICBSYXRlID0gYyhCb1RfcmF0ZSRSYXRlLCBFb1RfcmF0ZSRSYXRlKSwNCiAgUGVyaW9kID0gYygiQmVnaW5uaW5nIG9mIFRlcm0iLCAiRW5kIG9mIFRlcm0iKQ0KKQ0KDQojIERpc3BsYXkgdGhlIHJlc3VsdHMNCnByaW50KHJlc3VsdHMpDQpgYGANCg0KDQpDb21wYXJlIHRoZSBSYXRlcw0KDQpgYGB7cn0NCnJhdGVfY2hhbmdlPC0gRW9UX3JhdGUkUmF0ZSAtIEJvVF9yYXRlJFJhdGUNCnByaW50KHBhc3RlKCJUaGUgMTMtd2VlayBUcmVhc3VyeSBiaWxsIHJhdGUgY2hhbmdlZCBieSIsIHJvdW5kKHJhdGVfY2hhbmdlLCAyKSwgInBlcmNlbnRhZ2UgcG9pbnRzIG92ZXIgdGhlIHRlcm0uIikpDQoNCmBgYA0KDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQoNCkluIHRoaXMgZXhlcmNpc2Ugd2UgaGF2ZSBwZXJmb3JtZWQgYSBjb21wYXJpc29uIG9mIHRoZSBzaG9ydC10ZXJtIGludGVyZXN0IHJhdGUgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2Nob29sIGFuZCBhdCB0aGUgZW5kLiBXaGVuIHdlIGNhbGN1bGF0ZSB0aGUgY2hhbmdlLCB3ZSBmaW5kIHRoYXQgdGhlcmUgaGFzIGJlZW4gYSBkZXByZWNpYXRpb24gb2YgdGhlIHJhdGVzLCB3aXRoIGEgY2hhbmdlIG9mIC0wLjUzIHBvaW50cy4NCkEgZmFsbCBpbiB0aGUgVC1iaWxsIHJhdGUgbWF5IGJlIGNhdXNlZCBieSBzZXZlcmFsIGZhY3RvcnMsIHN1Y2ggYXMgYSBmYWxsIGluIGludGVyZXN0IHJhdGVzLCBkZWNlbGVyYXRpb24gb2YgZWNvbm9taWMgZ3Jvd3RoIG9yIGV2ZW4gcmVjZXNzaW9ucyBvciBlY29ub21pYyB1bmNlcnRhaW50eSB3aGljaCBsZWFkcyB0byBoaWdoZXIgZGVtYW5kIGluIFQtYmlsbHMuIEFub3RoZXIgaW50ZXJlc3RpbmcgZmFjdG9yIG1heSBiZSBhIGdlbmVyYWwgZGVzaXJlIGZvciBsaXF1aWQgaW5zdHJ1bWVudHMgdG8gc3RvcmUgdmFsdWUgaW4gdGhlIHNob3J0IHRlcm0gd2l0aCBtaW5pbWFsIHJpc2suIA0KQW55IG9mIHRoZXNlIHJlYXNvbnMgY2FuIGxlYWQgdG8gYSBkZWNyZWFzZSBpbiB0aGUgVC1iaWxsIHJhdGVzLCBhbmQgd2UgYXJlIGluY2xpbmVkIHRvIGJlbGlldmUgdGhhdCBpbiB0aGlzIGNhc2UgaXQgaGFzIGJlZW4gY2F1c2VkIGJ5IHRoZSBmYWxsIG9mIGludGVyZXN0IHJhdGVzIGFuZCBhIGZvcmVzZWVhYmxlIGZ1cnRoZXIgY3V0IGluIHJhdGVzIGJ5IHRoZSBGRUQuIA0KDQoNCg0KIyMjIEwzLjIgV2h5IGludGVyZXN0IHJhdGVzIGNoYW5nZSBvdmVyIHRpbWUuDQoNCkludGVyZXN0IHJhdGVzIGZsdWN0dWF0aW9uIGlzIGEgYnJvYWQgcGhlbm9tZW5vbiBpbmZsdWVuY2VkIGJ5IGEgcmVhbGx5IHdpZGUgcmFuZ2Ugb2YgZmFjdG9ycy4gSG93ZXZlciwgdGhlIG1vc3QgaW1wb3J0YW50IGFzcGVjdHMgY2FuIHN1bW1hcml6ZWQgaW4gc3VwcGx5LCBkZW1hbmQgYW5kIGdvdmVybm1lbnQgcG9saWN5LiANCkhpZ2ggZGVtYW5kIChvciBsb3cgc3VwcGx5KSBvZiBjcmVkaXQgd2lsbCBsZWFkIHRvIGhpZ2hlciBpbnRlcmVzdCByYXRlcyBpbiBtb25leSBsZW5kaW5nIGZyb20gYmFua3MgYW5kIG90aGVyIGluc3RpdHV0aW9ucywgbWFraW5nIGl0IG1vcmUgZXhwZW5zaXZlIHRvIGJvcnJvdy4gT3Bwb3NpdGVseSwgYSBsb3cgZGVtYW5kIChvciBoaWdoIHN1cHBseSkgd2lsbCBsZWFkIHRvIGEgZGVjcmVhc2UgaW4gaW50ZXJlc3QgcmF0ZXMsIG1ha2luZyBib3Jyb3dpbmcgbW9uZXkgY2hlYXBlci4gDQpUaGUgZ292ZXJubWVudCAoY29yIGNlbnRyYWwgYmFuaykgYWxzbyBoYXMgYW4gaW5mbHVlbmNlIGluIHRoZSBmbHVjdHVhdGlvbnMgYXMgaXQgc2V0cyB0aGUgdGFyZ2V0IGludGVyZXN0IHJhdGVzIGF0IHdoaWNoIHRoZW4gYmFua3MgbG9hbiBiZXR3ZWVuIGVhY2ggb3RoZXIuIFRoaXMgY2hhbmdlIGluIHRhcmdldCByYXRlcyBmdXJ0aGVyIGFmZmVjdCB0aGUgcmF0ZXMgYXQgd2hpY2ggdGhlIGNvbW1lcmNpYWwgYmFua3MgbGVuZCBtb25leSB0byB0aGVpciBjdXN0b21lcnMuIA0KQ2VudHJhbCBiYW5rcyBjYW4gYWxzbyBhY3F1aXJlIGdvdmVybm1lbnQgZGVidCB0byBwdXNoIHRoZSBlY29ub215IChpbmNyZWFzZSBzdXBwbHkgYW5kIGxvd2VyIHRoZSBkZW1hbmQpIG9yIHZpY2UgdmVyc2EuIA0KDQpJdCBpcyBpbXBvcnRhbnQgdG8gYWNrbm93bGVkZ2UgdGhhdCB0aGUgQ2VudHJhbCBCYW5rcyB1c2UgdGhlaXIgbW9uZXRhcnkgcG9saWN5IHRvIGluZmx1ZW5jZSB0aGUgaW50ZXJlc3QgcmF0ZXMgaW4gdGhlIFNIT1JULVRFUk0sIGJ1dCB0aGVpciBwb2xpY2llcyBjYW4gY29udHJpYnV0ZSB0byBzaGFwZSB0aGUgaW5mbGF0aW9uIHRhcmdldHMgaW4gdGhlIGxvbmcgdGVybS4gDQoNCg0KDQoNCiMjIEw0IEVmZmljaWVuY3kgb2YgbWFya2V0IGFuZCBpbmZvcm1hdGlvbg0KDQpDaGVjayBpZiBvbiAyNiBPY3RvYmVyIDIwMTcgY29jYSBjb2xhIHNoYXJlcyB3ZXJlIGhpdCBieSB0aGUgYWR2YXJzZSBpbmZvcm1hdGlvbiByZWFsaXplIG9uIHRoZSBtYXJrZXQuIChhc3N1bWUgMjYgaXMgdGhlIGluZm9ybWF0aW9uIHJlYWxlc2UgZGF0ZSkNCg0KDQpMb2FkIHBhY2thZ2VzDQoNCmBgYHtyfQ0KbGlicmFyeShxdWFudG1vZCkNCmBgYA0KDQoNCkRlZmluZSBkYXRlcw0KDQpgYGB7cn0NCmV2ZW50X2RhdGUgPC0gYXMuRGF0ZSgiMjAxNy0xMC0yNiIpDQpzdGFydF9kYXRlIDwtIGV2ZW50X2RhdGUgLSA3DQplbmRfZGF0ZSA8LSBldmVudF9kYXRlICsgNw0KYGBgDQoNCg0KUmV0cmlldmUgQ29jYS1Db2xhIERhdGENCg0KYGBge3J9DQp0aWNrZXIgPC0gIktPIg0KZ2V0U3ltYm9scyhTeW1ib2xzID0gdGlja2VyLCBzY3IgPSAieWFob28iLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSkNCmhlYWQoS08pDQpgYGANCg0KDQpQbG90IENsb3NpbmcgcHJpY2VzDQoNCmBgYHtyfQ0KZGV2Lm5ldygpDQpjaGFydFNlcmllcyhLTywgbmFtZSA9ICJDb2NhLUNvbGEgKEtPKSBTdG9jayBQcmljZSIpDQpgYGANCg0KDQpQbG90IHdpdGggVHJhZGluZyBWb2x1bWUNCmBgYHtyfQ0KIyBQbG90IGNsb3NpbmcgcHJpY2VzIHdpdGggdm9sdW1lDQpjaGFydFNlcmllcyhLTywgbmFtZSA9ICJDb2NhLUNvbGEgKEtPKSBTdG9jayBQcmljZSB3aXRoIFZvbHVtZSIsIHRoZW1lID0gY2hhcnRUaGVtZSgid2hpdGUiKSwgVEEgPSAiYWRkVm8oKSIpDQpgYGANCg0KDQpDYWxjdWxhdGUgRGFpbHkgUmV0dXJucw0KYGBge3J9DQojIENhbGN1bGF0ZSBkYWlseSByZXR1cm5zDQpLT19yZXR1cm5zIDwtIGRhaWx5UmV0dXJuKENsKEtPKSkNCg0KIyBWaWV3IHRoZSByZXR1cm5zDQpLT19yZXR1cm5zDQpgYGANCg0KDQpBbmFseXplIHRoZSBSZXR1cm4gb24gMjYgT2N0b2JlciAyMDE3DQpgYGB7cn0NCiMgR2V0IHRoZSByZXR1cm4gb24gdGhlIGV2ZW50IGRhdGUNCmV2ZW50X3JldHVybiA8LSBLT19yZXR1cm5zW2V2ZW50X2RhdGVdDQoNCiMgUHJpbnQgdGhlIHJldHVybg0KcHJpbnQoZXZlbnRfcmV0dXJuKQ0KYGBgDQoNCg0KIyMjIENvbXBhcmUgd2l0aCBNYXJrZXQgSW5kZXggKFMmUCA1MDApDQoNClJldHJpZXZlIFMmUCA1MDANCg0KYGBge3J9DQojIFJldHJpZXZlIFMmUCA1MDAgZGF0YQ0KZ2V0U3ltYm9scygiXkdTUEMiLCBzcmMgPSAieWFob28iLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSkNCg0KIyBDYWxjdWxhdGUgZGFpbHkgcmV0dXJucyBmb3IgUyZQIDUwMA0KU1A1MDBfcmV0dXJucyA8LSBkYWlseVJldHVybihDbChHU1BDKSkNCmBgYA0KDQoNCk1lcmdlIGFuZCBDb21wYXJlIFJldHVybnMNCg0KYGBge3J9DQojIE1lcmdlIHRoZSByZXR1cm5zDQpjb21iaW5lZF9yZXR1cm5zIDwtIG1lcmdlKEtPX3JldHVybnMsIFNQNTAwX3JldHVybnMsIGpvaW4gPSAiaW5uZXIiKQ0KY29sbmFtZXMoY29tYmluZWRfcmV0dXJucykgPC0gYygiS09fUmV0dXJuIiwgIlNQNTAwX1JldHVybiIpDQoNCiMgVmlldyBjb21iaW5lZCByZXR1cm5zDQpwcmludChjb21iaW5lZF9yZXR1cm5zKQ0KYGBgDQoNCg0KUGxvdCB0aGUgUmV0dXJucw0KDQpgYGB7cn0NCiMgTG9hZCBnZ3Bsb3QyIGZvciBwbG90dGluZw0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQp9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgUHJlcGFyZSBkYXRhIGZvciBwbG90dGluZw0KcmV0dXJuc19kZiA8LSBkYXRhLmZyYW1lKERhdGUgPSBpbmRleChjb21iaW5lZF9yZXR1cm5zKSwgY29yZWRhdGEoY29tYmluZWRfcmV0dXJucykpDQoNCiMgTWVsdCB0aGUgZGF0YSBmcmFtZSBmb3IgZ2dwbG90Mg0KaWYgKCFyZXF1aXJlKCJyZXNoYXBlMiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInJlc2hhcGUyIikNCn0NCmxpYnJhcnkocmVzaGFwZTIpDQpyZXR1cm5zX21lbHRlZCA8LSBtZWx0KHJldHVybnNfZGYsIGlkLnZhcnMgPSAiRGF0ZSIpDQoNCiMgUGxvdCB0aGUgcmV0dXJucw0KZ2dwbG90KHJldHVybnNfbWVsdGVkLCBhZXMoeCA9IERhdGUsIHkgPSB2YWx1ZSwgY29sb3IgPSB2YXJpYWJsZSkpICsNCiAgZ2VvbV9saW5lKHNpemUgPSAxKSArDQogIGxhYnModGl0bGUgPSAiRGFpbHkgUmV0dXJuczogQ29jYS1Db2xhIHZzLiBTJlAgNTAwIiwNCiAgICAgICB4ID0gIkRhdGUiLA0KICAgICAgIHkgPSAiRGFpbHkgUmV0dXJuIiwNCiAgICAgICBjb2xvciA9ICJMZWdlbmQiKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGFzLm51bWVyaWMoZXZlbnRfZGF0ZSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQoNCiMjIyBTdGF0aXN0aWNhbCBBbmFseXNpcw0KDQoNCkNhbGN1bGF0ZSBaLXNjb3JlIGZvciBFdmVudCBEYXRlIFJldHVybg0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBleGNsdWRpbmcgZXZlbnQgZGF0ZQ0KbWVhbl9yZXR1cm4gPC0gbWVhbihLT19yZXR1cm5zWy13aGljaChpbmRleChLT19yZXR1cm5zKSA9PSBldmVudF9kYXRlKV0pDQpzZF9yZXR1cm4gPC0gc2QoS09fcmV0dXJuc1std2hpY2goaW5kZXgoS09fcmV0dXJucykgPT0gZXZlbnRfZGF0ZSldKQ0KDQojIENhbGN1bGF0ZSB6LXNjb3JlDQp6X3Njb3JlIDwtIChhcy5udW1lcmljKGV2ZW50X3JldHVybikgLSBtZWFuX3JldHVybikgLyBzZF9yZXR1cm4NCg0KIyBQcmludCB6LXNjb3JlDQpwcmludChwYXN0ZSgiWi1zY29yZSBvbiIsIGV2ZW50X2RhdGUsICI6Iiwgcm91bmQoel9zY29yZSwgMikpKQ0KYGBgDQoNCg0KIyMjIEFuYWx5c2lzIG9mIHJlc3VsdHMuIA0KDQpJbiB0aGlzIGV4ZXJjaXNlIHdlIGhhdmUgcGVyZm9ybWVkIGFuIHN0dWR5IG9uIHRoZSBDb2NhIENvbGEgc2hhcmVzIG1vdmVtZW50cyBvbiBhbiBzcGVjaWZpZWQgZXZlbnQuIEluIG9yZGVyIHRvIHVudmVpbCB0aGUgYWJub3JtYWwgcmV0dXJucywgd2UgaGF2ZSBmaXJzdCBvYnRhaW5lZCB0aGUgQ29jYSBjb2xhIChLTykgZGF0YSBhbmQgd2UgaGF2ZSBzcGVjaWZpY2FsbHkgb2J0YWluZWQgdGhlIHJldHVybiBvbiB0aGUgZXZlbnQgZGF0ZS4gQWZ0ZXJ3YXJkcywgd2UgaGF2ZSBvYnRhaW5lZCB0aGUgZXF1aXZhbGVudCBkYXRhIGZyb20gdGhlIFMmUDUwMCBpbiBvcmRlciB0byBjb21wYXJlIHRoZSByZXR1cm5zIG9idGFpbmVkIGJ5IHRoZSBtYXJrZXQgaW4gdGhlIGV2ZW50IGRhdGUgc28gYXMgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIHJldHVybnMgYXJlIGRldGVybWluZWQgYnkgdGhlIGFkdmVyc2UgaW5mb3JtYXRpb24gcmVnYXJkaW5nIENvY2EgQ29sYSBvciBpZiBpdCB3YXMgcmF0aGVyIGEgZ2VuZXJhbGl6ZWQgbW92ZW1lbnQgb2YgdGhlIG1hcmtldCBhcyBhIHdob2xlLiANCg0KV2hlbiBvYnNlcnZpbmcgdGhlIGdyYXBoaWMgY29tcGFyaXNvbiBiZXR3ZWVuIHRoZSBTJlA1MDAgYW5kIHRoZSBDb2NhIENvbGEgc2hhcmVzLCB3ZSBvYnNlcnZlIHRoYXQgdGhlaXIgdGVuZGVuY3kgbWF0Y2hlcyBxdWl0ZSBmYWlybHksIHNvIG91ciBmaXJzdCBpbnR1aXRpb24gd2lsbCBiZSB0aGF0IHRoZSBpbmZvcm1hdGlvbiBoYWQgbm8gcmVsZXZhbnQgZWZmZWN0IG9uIHRoZSBDb2NhIENvbGEuIFdlIGNhbiBhbHNvIG9ic2VydmUgdGhhdCB0aGUgQ29jYSBDb2xhIFNoYXJlcyBoYXZlIGEgY2xlYXIgcGVhayBpbiB0aGUgZXZlbnQgZGF0ZSB0aGF0IGlzIGZvbGxvd2VkIGJ5IGEgZHJhc3RpYyBmYWxsIGluIHRoZSBkYWlseSByZXR1cm5zLiANCg0KSG93ZXZlciwgaW4gb3JkZXIgdG8gYmV0dGVyIGFzc2VzcyB0aGUgZXZlbnQgYW5kIGl0cyBlZmZlY3RzLCB3ZSBoYXZlIHBlcmZvcm1lZCBhbiBzdGF0aXN0aWNhbCBhbmFseXNpcyB3aXRoIHRoZSBaLVNjb3JlLiBUbyBhbmFseXplIHRoZSByZXN1bHRzIG9mIHRoaXMgc3RhdGlzdGljYWwgc3R1ZHkgd2UgbXVzdCBrbm93IHRoYXQgaWYgb3VyIFotc2NvcmUgaXMgZ3JlYXRlciB0aGFuIDIgKHxaLVNjb3JlfCA+IDIpIHdlIHdpbGwgYmUgYWJsZSB0byBhZmZpcm0gdGhhdCB0aGUgcmV0dXJuIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IHdpdGggYSBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgNSUuIEZ1cnRoZXJtb3JlIGlmIHRoZSBaLVNjb3JlIGlzIGdyZWF0ZXIgdGhhbiAzLCB3ZSB3aWxsIGJlIGFibGUgdG8gYWZmaXJtIHRoYXQgdGhlIHJldHVybiBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCB3aXRoIGEgc2lnbmlmaWNhbmNlIGxldmVsIG9mIDElLiANCkluIHRoZSBwcmVzZW50IGNhc2UsIHRoZSBaLVNjb3JlIHdlIG9idGFpbmVkIGhhcyBhIHZhbHVlIG9mIDIuNjIsIHdoaWNoIGxlYWQgdXMgdG8gY29uY2x1ZGUgdGhhdCB3aXRoIGEgc2lnbmlmaWNhbmNlIGxldmVsIG9mIDUlIChvciB3aXRoIGEgY29uZmlkZW5jZSBsZXZlbCBvZiA5NSUpLCB0aGUgZGFpbHkgcmV0dXJucyBoYXZlIGJlZW4gc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQuIA0KDQpUaGlzIHVsdGltYXRlbHkgbGVhZHMgdXMgdG8gYWZmaXJtIHdpdGhpbiBvdXIgY29uZmlkZW5jZSBsZXZlbCB0aGF0IHRoZSBhZHZlcnNlIGluZm9ybWF0aW9uIHRoYXQgaGl0IHRoZSBDb2NhLUNvbGEgU2hhcmVzIGhhcyBoYWQgYW4gaW1wYWN0IGluIGl0cyBwcmljZSwgd2hpY2ggY2FuIGJlIGJhY2tlZCB1cCB3aXRoIHRoZSBvYnNlcnZhbmNlIG9mIHRoZSBncmFwaGljIGluIHRoZSBldmVudCBkYXRlIGFzIHdlbGwgYXMgdGhlIHRyZW5kIHRoYXQgZm9sbG93cyBpbm1pZGlhdGVseSBhZnRlcndhcmRzLiANCg0KDQoNCiMjIEw1IEZpbmFuY2lhbCBzdGF0ZW1lbnRzIGFuZCBmdW5kYW1lbnRhbCBhbmFseXNpcw0KDQoNCiMjIyBMNS4wIERvd25sb2FkIHRvIFIgdGhlIGZpbmFuY2lhbCBzdGF0ZW1lbnRzIG9mIE1pY3Jvc29mdCAyMDE4LCBzaG93IHRoZSBjb2RlDQoNCmBgYHtyfQ0KIyBMb2FkIG5lY2Vzc2FyeSBsaWJyYXJpZXMNCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KHRpZHlyKSAgICAjIEZvciBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgY2xlYW5pbmcNCmxpYnJhcnkoZmlucmVwb3J0cikNCmxpYnJhcnkoWEJSTCkNCg0KIyBTZXQgdXAgdGhlIGF1dGhvcml0eSB0byBFREdBUg0Kb3B0aW9ucyhIVFRQVXNlckFnZW50ID0gImpzMTM3NTc2QHN0dWRlbnRzLnNnaC53YXcucGwiKSANCg0KIyBNaWNyb3NvZnQncyBDSUsgaXMgMDAwMDc4OTAxOQ0KDQojIEdldCB0aGUgbGlzdCBvZiBhdmFpbGFibGUgYW5udWFsIHJlcG9ydHMgZm9yIE1pY3Jvc29mdA0KYW5udWFsX3JlcG9ydHMgPC0gQW5udWFsUmVwb3J0cygiMDAwMDc4OTAxOSIsIGZvcmVpZ24gPSBGQUxTRSkNCg0KIyBWaWV3IHRoZSBhdmFpbGFibGUgcmVwb3J0cw0KcHJpbnQoYW5udWFsX3JlcG9ydHMpDQoNCiMgU3BlY2lmeSB0aGUgeWVhciBmb3Igd2hpY2ggeW91IHdhbnQgdGhlIGZpbmFuY2lhbCBkYXRhDQpyZXBvcnRfeWVhciA8LSAyMDE4DQoNCiMgUmV0cmlldmUgdGhlIGluY29tZSBzdGF0ZW1lbnQNCmluY29tZV9zdGF0ZW1lbnQgPC0gR2V0SW5jb21lKCJNU0ZUIiwgcmVwb3J0X3llYXIpDQoNCiMgVmlldyB0aGUgaW5jb21lIHN0YXRlbWVudA0KcHJpbnQoaW5jb21lX3N0YXRlbWVudCkNCg0KIyBSZXRyaWV2ZSB0aGUgYmFsYW5jZSBzaGVldA0KYmFsYW5jZV9zaGVldCA8LSBHZXRCYWxhbmNlU2hlZXQoIk1TRlQiLCByZXBvcnRfeWVhcikNCg0KIyBWaWV3IHRoZSBiYWxhbmNlIHNoZWV0DQpwcmludChiYWxhbmNlX3NoZWV0KQ0KDQojIFJldHJpZXZlIHRoZSBjYXNoIGZsb3cgc3RhdGVtZW50DQpjYXNoX2Zsb3cgPC0gR2V0Q2FzaEZsb3coIk1TRlQiLCByZXBvcnRfeWVhcikNCg0KIyBWaWV3IHRoZSBjYXNoIGZsb3cgc3RhdGVtZW50DQpwcmludChjYXNoX2Zsb3cpDQoNCmBgYA0KDQojIyMgTDUuMSBJZGVudGlmeSB0aGUgdHlwZXMgb2YgZGVwb3NpdHMgdGhhdCB0aGUgY29tbWVyY2lhbCBiYW5rIHVzZXMgdG8gb2J0YWluIG1vc3Qgb2YgaXRzIGZ1bmRzLg0KDQojIyMjIEpQTW9yZ2FuIENoYXNlIHJlbGllcyBvbiB0d28gbWFpbiB0eXBlcyBvZiBkZXBvc2l0czoNCg0KIyMjIyMgTm9uaW50ZXJlc3QtQmVhcmluZyBEZXBvc2l0czoNCg0KVS5TLiBvZmZpY2VzOiAkNjQzLjc1IGJpbGxpb24gaW4gMjAyMy4NCg0KTm9uLVUuUy4gb2ZmaWNlczogJDIzLjEgYmlsbGlvbi4NCg0KIyMjIyMgSW50ZXJlc3QtQmVhcmluZyBEZXBvc2l0czoNCg0KVS5TLiBvZmZpY2VzOiAkMS4zMDMgdHJpbGxpb24gaW4gMjAyMy4NCg0KTm9uLVUuUy4gb2ZmaWNlczogJDQzMC43NCBiaWxsaW9uLg0KDQpUaGVzZSBkZXBvc2l0cyBpbmNsdWRlIHNhdmluZ3MsIGRlbWFuZCwgYW5kIHRpbWUgZGVwb3NpdHMuIFRoZSBtYWpvcml0eSBvZiBmdW5kaW5nIGNvbWVzIGZyb20gY29uc3VtZXIgYW5kIHdob2xlc2FsZSBvcGVyYXRpbmcgZGVwb3NpdHMsIHdoaWNoIGFyZSBjb25zaWRlcmVkIHN0YWJsZSBzb3VyY2VzIG9mIGxpcXVpZGl0eS4NCg0KDQojIyMgTDUuMiBJZGVudGlmeSB0aGUgbWFpbiB1c2VzIG9mIGZ1bmRzIGJ5IHRoZSBiYW5rLg0KDQojIyMjIEpQTW9yZ2FuIENoYXNlIHByaW1hcmlseSB1c2VzIGl0cyBmdW5kcyBmb3I6DQoNCiMjIyMjIExvYW5zOg0KDQpUb3RhbCBsb2FucyBpbiAyMDIzIGFtb3VudGVkIHRvICQxLjMyNCB0cmlsbGlvbiwgaW5jbHVkaW5nIGNvbnN1bWVyIGFuZCBjb21tZXJjaWFsIGxvYW5zLg0KDQojIyMjIyBJbnZlc3RtZW50czoNCg0KRnVuZHMgYXJlIGFsbG9jYXRlZCB0byBzZWN1cml0aWVzIHBvcnRmb2xpb3MgZm9yIGluY29tZSBnZW5lcmF0aW9uIGFuZCBsaXF1aWRpdHkgbWFuYWdlbWVudC4NCg0KIyMjIyMgTGlxdWlkaXR5Og0KDQpTaWduaWZpY2FudCBjYXNoIHJlc2VydmVzIGFuZCBoaWdoLXF1YWxpdHkgbGlxdWlkIGFzc2V0cyBhcmUgbWFpbnRhaW5lZCB0byBtZWV0IG9ibGlnYXRpb25zLg0KDQojIyMjIyBBY3F1aXNpdGlvbnM6DQpJbnZlc3RtZW50cyBpbiBidXNpbmVzc2VzLCBzdWNoIGFzIHRoZSBhY3F1aXNpdGlvbiBvZiBGaXJzdCBSZXB1YmxpYywgYWxpZ24gd2l0aCBzdHJhdGVnaWMgZ29hbHMuDQoNCg0KIyMjIEw1LjMgRG9lcyBpdCBhcHBlYXIgdGhhdCB0aGUgYmFuayBpcyBhdHRlbXB0aW5nIHRvIGVudGVyIHRoZSBzZWN1cml0aWVzIGluZHVzdHJ5IGJ5IG9mZmVyaW5nIHNlY3VyaXRpZXMgc2VydmljZXM/DQoNClllcywgSlBNb3JnYW4gQ2hhc2UgaXMgZGVlcGx5IGludm9sdmVkIGluIHRoZSBzZWN1cml0aWVzIGluZHVzdHJ5IHRocm91Z2g6DQoNCiMjIyMjIEludmVzdG1lbnQgQmFua2luZzoNCg0KUmFpc2luZyBlcXVpdHkgYW5kIGRlYnQgY2FwaXRhbCwgY29ycG9yYXRlIHN0cmF0ZWd5IGFkdmlzb3J5Lg0KDQojIyMjIyBTZWN1cml0aWVzIFNlcnZpY2VzOg0KDQpDdXN0b2R5LCBmdW5kIGFkbWluaXN0cmF0aW9uLCBhbmQgc2VjdXJpdGllcyBsZW5kaW5nLg0KDQoNCiMjIyBMNS40IERvZXMgaXQgYXBwZWFyIHRoYXQgdGhlIGJhbmsgaXMgYXR0ZW1wdGluZyB0byBlbnRlciB0aGUgaW5zdXJhbmNlIGluZHVzdHJ5IGJ5IG9mZmVyaW5nIGluc3VyYW5jZSBzZXJ2aWNlcz8NCg0KSlBNb3JnYW4gQ2hhc2UgaXMgbm90IHNpZ25pZmljYW50bHkgZXhwYW5kaW5nIGludG8gdHJhZGl0aW9uYWwgaW5zdXJhbmNlIG1hcmtldHMgYnV0IG9mZmVycyBwcm9kdWN0cyBsaWtlIGNyZWRpdCBkZXJpdmF0aXZlcywgd2hpY2ggb3ZlcmxhcCB3aXRoIHNvbWUgaW5zdXJhbmNlLWxpa2UgcmlzayBtYW5hZ2VtZW50IGZ1bmN0aW9ucy4NCg0KDQojIyMgTDUuNSBBc3Nlc3MgdGhlIGJhbmvigJlzIGJhbGFuY2Ugc2hlZXQgZm9yIHRoZSBnYXAgYmV0d2VlbiByYXRlLXNlbnNpdGl2ZSBhc3NldHMgYW5kIGxpYWJpbGl0aWVzLg0KDQpKUE1vcmdhbiBhY3RpdmVseSBtYW5hZ2VzIGludGVyZXN0IHJhdGUgcmlzayBieSBhbGlnbmluZyByYXRlLXNlbnNpdGl2ZSBhc3NldHMgKGxvYW5zLCBzZWN1cml0aWVzKSBhbmQgbGlhYmlsaXRpZXMgKGRlcG9zaXRzLCBib3Jyb3dpbmdzKS4gQmFzZWQgb24gYXZhaWxhYmxlIGRhdGEsIHRoZSBiYW5rIHNlZW1zIHRvIG1haW50YWluIGEgYmFsYW5jZWQgb3Igc2xpZ2h0bHkgcG9zaXRpdmUgZ2FwLg0KDQoNCiMjIyBMNS42LUw1LjEyIEZpbmFuY2lhbCBSYXRpb3MNCg0KUiBDb2RlIGZvciBDYWxjdWxhdGlvbnMNCg0KVGhlIGZvbGxvd2luZyBSIGNvZGUgY29tcHV0ZXMgdGhlc2UgbWV0cmljczoNCg0KYGBge3J9DQojIExvYWQgbmVjZXNzYXJ5IGxpYnJhcmllcw0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIExvYWQgZGF0YQ0KZmlsZV9wYXRoIDwtICJDOi9Vc2Vycy9VU1VBUklPL09uZURyaXZlL0RvY3VtZW50b3MvMDAwMDAxOTYxNy0yNC0wMDAyMjUueGxzeCINCmJhbGFuY2Vfc2hlZXQgPC0gcmVhZF9leGNlbChmaWxlX3BhdGgsIHNoZWV0ID0gImNvbnNvbGlkYXRlZCBiYWxhbmNlIHNoZWV0IikNCmluY29tZV9zaGVldCA8LSByZWFkX2V4Y2VsKGZpbGVfcGF0aCwgc2hlZXQgPSAiaW5jb21lIikNCg0KIyBFeHRyYWN0IGRhdGENCnRvdGFsX2Fzc2V0cyA8LSBiYWxhbmNlX3NoZWV0ICU+JQ0KICBmaWx0ZXIoZ3JlcGwoIlRvdGFsIGFzc2V0cyIsIGBDb2x1bW4gMWApKSAlPiUNCiAgc2VsZWN0KGAyMDIzYCkgJT4lDQogIHB1bGwoKQ0KDQp0b3RhbF9lcXVpdHkgPC0gYmFsYW5jZV9zaGVldCAlPiUNCiAgZmlsdGVyKGdyZXBsKCJUb3RhbCBzdG9ja2hvbGRlcnMnIGVxdWl0eSIsIGBDb2x1bW4gMWApKSAlPiUNCiAgc2VsZWN0KGAyMDIzYCkgJT4lDQogIHB1bGwoKQ0KDQppbnRlcmVzdF9pbmNvbWUgPC0gaW5jb21lX3NoZWV0ICU+JQ0KICBmaWx0ZXIoZ3JlcGwoIk5ldCBpbnRlcmVzdCBpbmNvbWUiLCBgQ29sdW1uIDFgKSkgJT4lDQogIHNlbGVjdChgMjAyM2ApICU+JQ0KICBwdWxsKCkNCg0KaW50ZXJlc3RfZXhwZW5zZSA8LSBpbmNvbWVfc2hlZXQgJT4lDQogIGZpbHRlcihncmVwbCgiSW50ZXJlc3QgZXhwZW5zZSIsIGBDb2x1bW4gMWApKSAlPiUNCiAgc2VsZWN0KGAyMDIzYCkgJT4lDQogIHB1bGwoKQ0KDQpuZXRfaW5jb21lIDwtIGluY29tZV9zaGVldCAlPiUNCiAgZmlsdGVyKGdyZXBsKCJOZXQgaW5jb21lIiwgYENvbHVtbiAxYCkpICU+JQ0KICBzZWxlY3QoYDIwMjNgKSAlPiUNCiAgcHVsbCgpDQoNCiMgQ2FsY3VsYXRlIHJhdGlvcw0KaW50ZXJlc3RfaW5jb21lX3BlcmNlbnRfYXNzZXRzIDwtIChpbnRlcmVzdF9pbmNvbWUgLyB0b3RhbF9hc3NldHMpICogMTAwDQppbnRlcmVzdF9leHBlbnNlX3BlcmNlbnRfYXNzZXRzIDwtIChpbnRlcmVzdF9leHBlbnNlIC8gdG90YWxfYXNzZXRzKSAqIDEwMA0KbmV0X2ludGVyZXN0X21hcmdpbiA8LSAoaW50ZXJlc3RfaW5jb21lIC0gaW50ZXJlc3RfZXhwZW5zZSkgLyB0b3RhbF9hc3NldHMNCnJldHVybl9vbl9hc3NldHMgPC0gKG5ldF9pbmNvbWUgLyB0b3RhbF9hc3NldHMpICogMTAwDQpyZXR1cm5fb25fZXF1aXR5IDwtIChuZXRfaW5jb21lIC8gdG90YWxfZXF1aXR5KSAqIDEwMA0KDQojIERpc3BsYXkgcmVzdWx0cw0KcmVzdWx0cyA8LSBkYXRhLmZyYW1lKA0KICBNZXRyaWMgPSBjKA0KICAgICJJbnRlcmVzdCBJbmNvbWUgJSBvZiBUb3RhbCBBc3NldHMgKEw1LjYpIiwNCiAgICAiSW50ZXJlc3QgRXhwZW5zZXMgJSBvZiBUb3RhbCBBc3NldHMgKEw1LjcpIiwNCiAgICAiTmV0IEludGVyZXN0IE1hcmdpbiAoTDUuOCkiLA0KICAgICJSZXR1cm4gb24gQXNzZXRzIChMNS4xMSkiLA0KICAgICJSZXR1cm4gb24gRXF1aXR5IChMNS4xMikiDQogICksDQogIFZhbHVlID0gYygNCiAgICBpbnRlcmVzdF9pbmNvbWVfcGVyY2VudF9hc3NldHMsDQogICAgaW50ZXJlc3RfZXhwZW5zZV9wZXJjZW50X2Fzc2V0cywNCiAgICBuZXRfaW50ZXJlc3RfbWFyZ2luLA0KICAgIHJldHVybl9vbl9hc3NldHMsDQogICAgcmV0dXJuX29uX2VxdWl0eQ0KICApDQopDQoNCnByaW50KHJlc3VsdHMpDQoNCiMgT3B0aW9uYWw6IFZpc3VhbGl6YXRpb24NCmdncGxvdChyZXN1bHRzLCBhZXMoeCA9IE1ldHJpYywgeSA9IFZhbHVlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJzdGVlbGJsdWUiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRmluYW5jaWFsIFJhdGlvcyAoTDUuNiAtIEw1LjEyKSIsDQogICAgeCA9ICJNZXRyaWMiLA0KICAgIHkgPSAiVmFsdWUgKCUpIg0KICApDQpgYGANCg0KDQojIyMgVmlzdWFsIHJlcHJlc2VudGF0aW9uDQoNCmBgYHtyfQ0KZ2dwbG90KHJlc3VsdHMsIGFlcyh4ID0gTWV0cmljLCB5ID0gVmFsdWUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInN0ZWVsYmx1ZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJGaW5hbmNpYWwgUmF0aW9zIChMNS42IC0gTDUuMTIpIiwNCiAgICB4ID0gIk1ldHJpYyIsDQogICAgeSA9ICJWYWx1ZSAoJSkiDQogICkNCmBgYA0KDQoNCg0KIyMjIEV4cGxhbmF0aW9uIG9mIE1ldHJpY3M6DQoNCkw1LjYgSW50ZXJlc3QgSW5jb21lIGFzICUgb2YgQXNzZXRzOiBNZWFzdXJlcyB0aGUgZWZmaWNpZW5jeSBvZiBhc3NldHMgaW4gZ2VuZXJhdGluZyBpbnRlcmVzdCBpbmNvbWUuDQoNCkw1LjcgSW50ZXJlc3QgRXhwZW5zZXMgYXMgJSBvZiBBc3NldHM6IFNob3dzIHRoZSBjb3N0IG9mIGZ1bmRpbmcgcmVsYXRpdmUgdG8gYXNzZXQgc2l6ZS4NCg0KTDUuOCBOZXQgSW50ZXJlc3QgTWFyZ2luOiBJbmRpY2F0ZXMgcHJvZml0YWJpbGl0eSBmcm9tIGNvcmUgYmFua2luZyBvcGVyYXRpb25zIGFmdGVyIGZ1bmRpbmcgY29zdHMuDQoNCkw1LjExIFJldHVybiBvbiBBc3NldHMgKFJPQSk6IFJlZmxlY3RzIGhvdyB3ZWxsIHRoZSBiYW5rIHVzZXMgYXNzZXRzIHRvIGdlbmVyYXRlIHByb2ZpdC4NCg0KTDUuMTIgUmV0dXJuIG9uIEVxdWl0eSAoUk9FKTogTWVhc3VyZXMgdGhlIHJldHVybnMgZ2VuZXJhdGVkIG9uIHNoYXJlaG9sZGVyIGVxdWl0eS4NCg0KDQojIyMgTDUuMTMgSW1wYWN0IG9mIFJpc2luZyBJbnRlcmVzdCBSYXRlcw0KDQpJbmNyZWFzZSBJbnRlcmVzdCBJbmNvbWU6IExvYW5zIHdpdGggdmFyaWFibGUgcmF0ZXMgd2lsbCB5aWVsZCBoaWdoZXIgaW50ZXJlc3QuDQoNCkluY3JlYXNlIEludGVyZXN0IEV4cGVuc2U6IERlcG9zaXRzIGFuZCBib3Jyb3dpbmdzIHdpbGwgY29zdCBtb3JlLCBwb3RlbnRpYWxseSBjb21wcmVzc2luZyBuZXQgaW50ZXJlc3QgbWFyZ2luLg0KDQoNCiMjIyBMNS4xNCBJbXBhY3Qgb2YgRGV0ZXJpb3JhdGluZyBFY29ub21pYyBDb25kaXRpb25zDQoNCkluY3JlYXNlIGluIExvYW4gTG9zcyBQcm92aXNpb25zOiBIaWdoZXIgZGVmYXVsdHMgb24gbG9hbnMgd291bGQgcmFpc2UgY3JlZGl0IGNvc3RzLg0KDQpSZWR1Y2UgaW4gTm9uLWludGVyZXN0IEluY29tZTogTG93ZXIgYWN0aXZpdHkgaW4gaW52ZXN0bWVudCBiYW5raW5nIGFuZCBhc3NldCBtYW5hZ2VtZW50IGNvdWxkIGh1cnQgZmVlIGluY29tZS4NCg0KDQojIyBMNS4xNS0gTDUuMTkNClRoZSBtdXR1YWwgZnVuZCBjaG9zZW4gd2lsbCBiZSBWYW5ndWFyZCA1MDAgSW5kZXggRnVuZCAoVkZJQVgpDQoNCiMjIyBMNS4xNSBXaGF0IGlzIHRoZSBpbnZlc3RtZW50IG9iamVjdGl2ZSBvZiB0aGlzIG11dHVhbCBmdW5kPyBEbyB5b3UgY29uc2lkZXIgdGhpcyBtdXR1YWwgZnVuZCB0byBoYXZlIGxvdyByaXNrLCBtb2RlcmF0ZSByaXNrLCBvciBoaWdoIHJpc2s/DQpUaGUgVmFuZ3VhcmQgNTAwIEluZGV4IEZ1bmQgYWltcyB0byB0cmFjayB0aGUgcGVyZm9ybWFuY2Ugb2YgdGhlIFMmUCA1MDAgSW5kZXgsIHdoaWNoIHJlcHJlc2VudHMgNTAwIG9mIHRoZSBsYXJnZXN0IFUuUy4gY29tcGFuaWVzLiBJdHMgb2JqZWN0aXZlIGlzIHRvIHByb3ZpZGUgaW52ZXN0b3JzIHdpdGggZXhwb3N1cmUgdG8gdGhlIGxhcmdlLWNhcCBzZWdtZW50IG9mIHRoZSBVLlMuIGVxdWl0eSBtYXJrZXQsIGZvY3VzaW5nIG9uIGxvbmctdGVybSBncm93dGggb2YgY2FwaXRhbCBhbmQgaW5jb21lIGZyb20gZGl2aWRlbmRzLg0KDQpUaGlzIG11dHVhbCBmdW5kIGlzIGNvbnNpZGVyZWQgdG8gaGF2ZSBtb2RlcmF0ZSByaXNrLiBJdCBpcyBzdGlsbCBzdWJqZWN0IHRvIG1hcmtldCByaXNrIGluaGVyZW50IGluIGVxdWl0eSBpbnZlc3RpbmcuDQoNCiMjIyBMNS4xNiBXaGF0IHdhcyB0aGUgcmV0dXJuIG9uIHRoZSBtdXR1YWwgZnVuZCBsYXN0IHllYXI/IFdoYXQgd2FzIHRoZSBhdmVyYWdlIGFubnVhbCByZXR1cm4gb3ZlciB0aGUgbGFzdCB0aHJlZSB5ZWFycz8NCg0KQXMgb2YgdGhlIGVuZCBvZiAyMDIyOg0KDQpSZXR1cm4gbGFzdCB5ZWFyICgyMDIyKTogQXBwcm94aW1hdGVseSAtMTglLCByZWZsZWN0aW5nIGEgZG93bnR1cm4gaW4gdGhlIFUuUy4gc3RvY2sgbWFya2V0Lg0KQXZlcmFnZSBhbm51YWwgcmV0dXJuIG92ZXIgdGhlIGxhc3QgdGhyZWUgeWVhcnMgKDIwMjAtMjAyMik6IEFwcHJveGltYXRlbHkgNyUgcGVyIHllYXINCg0KIyMjIEw1LjE3IFdoYXQgaXMgYSBrZXkgZWNvbm9taWMgZmFjdG9yIHRoYXQgaW5mbHVlbmNlcyB0aGUgcmV0dXJuIG9uIHRoaXMgbXV0dWFsIGZ1bmQ/DQoNCkl0IGlzIHRoZSBvdmVyYWxsIHBlcmZvcm1hbmNlIG9mIHRoZSBVLlMuIHN0b2NrIG1hcmtldC4gRmFjdG9ycyBzdWNoIGFzIGl0cyBzdG9jayBtYXJrZXQgY29uZGl0aW9ucywgVVMgaW50ZXJlc3QgcmF0ZXMgYW5kIG1hY3JvZWNvbm9taWMgaW5kaWNhdG9ycyBhZmZlY3Qgbm90aWNlYWJseS4gDQoNCiMjIyBMNS4xOCBNdXN0IGFueSBmZWVzIGJlIHBhaWQgd2hlbiBidXlpbmcgb3Igc2VsbGluZyB0aGlzIG11dHVhbCBmdW5kPw0KDQpUaGUgVmFuZ3VhcmQgNTAwIEluZGV4IEZ1bmQgZG9lcyBub3QgY2hhcmdlIGFueSBzYWxlcyBsb2FkcyB3aGVuIGJ1eWluZyBvciBzZWxsaW5nIHNoYXJlcy4NCkhvd2V2ZXIsIGludmVzdG9ycyBzaGFsbCBiZSBhd2FyZSBvZiBleHBlbnNlIHJhdGlvcyBhbmQgYWNjb3VudGluZyBzZXJ2aWNlIGZlZXMuDQoNCiMjIyBMNS4xOSBXaGF0IHdhcyB0aGUgZXhwZW5zZSByYXRpbyBmb3IgdGhpcyBtdXR1YWwgZnVuZCBvdmVyIHRoZSBsYXN0IHllYXI/IERvZXMgdGhpcyByYXRpbyBzZWVtIGhpZ2ggdG8geW91Pw0KDQpUaGUgZXhwZW5zZSByYXRpbyBmb3IgdGhlIFZhbmd1YXJkIDUwMCBJbmRleCBGdW5kIGlzIGFwcHJveGltYXRlbHkgMC4wNCUuDQoNClRoaXMgcmF0aW8gaXMgY29uc2lkZXJlZCB2ZXJ5IGxhdyBjb21wYXJlIHRvIG90aGVyIG11dHVhbCBmdW5kcy4NCg0KDQojIyBMNS4yMCAtIEw1LjIyIFNlY3VyaXRpZXMgRmlybXMNClNlY3VyaXRpZXMgRmlybSBTZWxlY3RlZDogR29sZG1hbiBTYWNocyBHcm91cCwgSW5jLg0KDQojIyMgTDUuMjAgV2hhdCBhcmUgdGhlIG1haW4gdHlwZXMgb2YgYnVzaW5lc3MgY29uZHVjdGVkIGJ5IHRoZSBzZWN1cml0aWVzIGZpcm0/DQoNCkdvbGRtYW4gU2FjaHMgT3BlcmF0ZXMgaW4gc2V2ZXJhbCBidXNpbmVzcyBzZWdtZW50cyBzdWNoIGFzIEludmVzdG1lbnQgQmFua2luZywgR2xvYmFsIE1hcmtldHMsIEFzc2V0IE1hbmFnZW1lbnQgYW5kIENvbnN1bWVyICYgV2VhbHRoIE1hbmFnZW1lbnQuIA0KDQoNCiMjIyBMNS4yMSBTdW1tYXJpemUgYW55IHN0YXRlbWVudHMgbWFkZSBieSB0aGUgc2VjdXJpdGllcyBmaXJtIGluIGl0cyBhbm51YWwgcmVwb3J0IGFib3V0IGhvdyBpdCBtYXkgYmUgYWZmZWN0ZWQgYnkgZXhpc3Rpbmcgb3IgcG90ZW50aWFsIHJlZ3VsYXRpb25zLg0KDQpSZWd1bGF0b3J5IEVudmlyb25tZW50OiBUaGUgZmlybSBvcGVyYXRlcyB1bmRlciBleHRlbnNpdmUgcmVndWxhdGlvbnMgdGhhdCBhZmZlY3QgaXRzIG9wZXJhdGlvbnMsIGNhcGl0YWwgcmVxdWlyZW1lbnRzLCBhbmQgcHJvZml0YWJpbGl0eS4NCg0KQ29tcGxpYW5jZSBDb3N0czpsZWFkcyBoaWdoZXIgb3BlcmF0aW9uYWwgY29zdHMuDQoNClBvdGVudGlhbCBSZWd1bGF0aW9uczogRnV0dXJlIGNoYW5nZXMgY291bGQgaW1wYWN0IGJ1c2luZXNzIGFjdGl2aXRpZXMuDQoNClJpc2sgTWFuYWdlbWVudDogSW1wb3J0YW5jZSBvZiByaWdvcm91cyByaXNrIG1hbmFnZW1lbnQgc3lzdGVtcyB0byBuYXZpZ2F0ZSB0aGUgY29tcGxleCByZWd1bGF0b3J5IGxhbmRzY2FwZS4NCg0KR29sZG1hbiBTYWNocyBhY2tub3dsZWRnZXMgdGhhdCByZWd1bGF0b3J5IGNoYW5nZXMgY291bGQgbGltaXQgY2VydGFpbiBidXNpbmVzcyBwcmFjdGljZXMgYW5kIHJlcXVpcmUgY2VydGFpbiBhZGp1c3RtZW50cy4NCg0KDQojIyMgTDUuMjIgRGVzY3JpYmUgdGhlIHJlY2VudCBwZXJmb3JtYW5jZSBvZiB0aGUgc2VjdXJpdGllcyBmaXJtLCBhbmQgZXhwbGFpbiB3aHkgdGhlIHBlcmZvcm1hbmNlIGhhcyBiZWVuIGZhdm9yYWJsZSBvciB1bmZhdm9yYWJsZS4NCg0KIyMjIyBNaXhlZCBmaW5hbmNpYWwgcmVzdWx0cw0KDQpTdHJlbmd0aHM6IGludmVzdG1lbnQgYmFua2luZyByZXZlbnVlIGFuZCBhc3NldCBtYW5hZ2VtZW50IGdyb3d0aA0KDQpDaGFsbGVuZ2VzOiBHbG9iYWwgTWFya2V0cyBEaXZpc2lvbiBhbmQgcmVndWxhdG9yeSBjb3N0cw0KDQojIyMjIFJlYXNvbnMgZm9yIHBlcmZvcm1hbmNlDQpFY29ub21pYyByZWNvdmVyeSBhbmQgbWFya2V0IHZvbGF0aWxpdHkgYXMgZmF2b3JhYmxlIGZhY3RvcnMNCkludGVyZXN0IHJhdGUgQ2hhbmdlcyBhbmQgZ2VvcG9saXRpY2FsIHJpc2tzIGFzIHVuZmF2b3JhYmxlIGZhY3RvcnMuDQoNCg0KDQoNCiMjIEw2LiBFcXVpdHkNCg0KRXZlbnQgU3R1ZHkgb24gQXBwbGUgSW5jLiAoQUFQTCkNCg0KDQojIyMgT2JqZWN0aXZlOiANClRvIGNvbmR1Y3QgYW4gZXZlbnQgc3R1ZHkgb24gQXBwbGUgSW5jLiAoQUFQTCkgdG8gYW5hbHl6ZSB0aGUgaW1wYWN0IG9mIGEgc2lnbmlmaWNhbnQgY29ycG9yYXRlIGV2ZW50IG9uIGl0cyBzdG9jayByZXR1cm5zLg0KDQoNCiMjIyBFdmVudCBTZWxlY3Rpb246DQoNCldlIHdpbGwgZm9jdXMgb24gQXBwbGUncyBRNCAyMDIwIGVhcm5pbmdzIGFubm91bmNlbWVudCwgd2hpY2ggdG9vayBwbGFjZSBvbiBPY3RvYmVyIDI5LCAyMDIwLg0KDQoNCiMjIyBIeXBvdGhlc2lzOiANClRoZSBlYXJuaW5ncyBhbm5vdW5jZW1lbnQgaGFzIGEgbWVhc3VyYWJsZSBpbXBhY3Qgb24gQXBwbGUncyBzdG9jayBwcmljZSwgcmVzdWx0aW5nIGluIGFibm9ybWFsIHJldHVybnMgYXJvdW5kIHRoZSBldmVudCBkYXRlLg0KDQoNCiMjIyBNZXRob2RvbG9neToNCg0KQ2FsY3VsYXRlIGRhaWx5IHN0b2NrIHJldHVybnMgZm9yIEFBUEwuDQoNCkNyZWF0ZSBhbiBldmVudCBkdW1teSB2YXJpYWJsZSB0byBpc29sYXRlIHRoZSBldmVudCdzIGVmZmVjdC4NCg0KUGVyZm9ybSBhIHJlZ3Jlc3Npb24gYW5hbHlzaXMgdG8gZXN0aW1hdGUgdGhlIGFibm9ybWFsIHJldHVybiBvbiB0aGUgZXZlbnQgZGF0ZS4NCg0KRXh0ZW5kIHRoZSBhbmFseXNpcyB0byBhbiBldmVudCB3aW5kb3cgdG8gY2FwdHVyZSBhbnkgcHJlLSBvciBwb3N0LWV2ZW50IGVmZmVjdHMuDQoNCkFzc2VzcyB0aGUgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIG9mIHRoZSByZXN1bHRzLg0KDQoNCiMjIyBSIENvZGUgSW1wbGVtZW50YXRpb24NCg0KYGBge3J9DQojIExvYWQgcmVxdWlyZWQgbGlicmFyaWVzDQpsaWJyYXJ5KHF1YW50bW9kKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBEZWZpbmUgdGhlIHRpY2tlciBzeW1ib2wgYW5kIGRhdGUgcmFuZ2UNCnRpY2tlciA8LSAiQUFQTCINCnN0YXJ0X2RhdGUgPC0gIjIwMjAtMTAtMTUiDQplbmRfZGF0ZSA8LSAiMjAyMC0xMS0xMiINCg0KIyBHZXQgc3RvY2sgZGF0YQ0KZ2V0U3ltYm9scyh0aWNrZXIsIGZyb20gPSBzdGFydF9kYXRlLCB0byA9IGVuZF9kYXRlKQ0KDQojIERlZmluZSB0aGUgZXZlbnQgZGF0ZQ0KZXZlbnRfZGF0ZSA8LSAiMjAyMC0xMC0yOSINCg0KIyBDYWxjdWxhdGUgZGFpbHkgbG9nIHJldHVybnMNCkFBUExfcmV0dXJucyA8LSBkaWZmKGxvZyhBZChnZXQodGlja2VyKSkpKQ0KDQojIENyZWF0ZSBldmVudCBkdW1teSB2YXJpYWJsZQ0KZXZlbnRfZHVtbXkgPC0gaWZlbHNlKGluZGV4KEFBUExfcmV0dXJucykgPT0gZXZlbnRfZGF0ZSwgMSwgMCkNCg0KIyBQZXJmb3JtIHJlZ3Jlc3Npb24gYW5hbHlzaXMNCmV2ZW50X3N0dWR5IDwtIGxtKEFBUExfcmV0dXJucyB+IGV2ZW50X2R1bW15KQ0KDQojIFN1bW1hcml6ZSB0aGUgcmVncmVzc2lvbiByZXN1bHRzDQpzdW1tYXJ5KGV2ZW50X3N0dWR5KQ0KYGBgDQoNCg0KIyMjIE5vdGVzIGNvbiBjb2RlDQoNCg0KIyMjIyBDYWxjdWxhdGluZyBEYWlseSBMb2cgUmV0dXJuczoNCg0KQWQoZ2V0KHRpY2tlcikpOiBFeHRyYWN0cyB0aGUgYWRqdXN0ZWQgY2xvc2luZyBwcmljZXMuDQoNCmRpZmYobG9nKC4uLikpOiBDYWxjdWxhdGVzIHRoZSBkYWlseSBsb2cgcmV0dXJucy4NCg0KDQojIyMjIENyZWF0aW5nIHRoZSBFdmVudCBEdW1teSBWYXJpYWJsZToNCg0KQXNzaWducyBhIHZhbHVlIG9mIDEgdG8gdGhlIGV2ZW50IGRhdGUgYW5kIDAgdG8gYWxsIG90aGVyIGRhdGVzLg0KDQpUaGlzIGR1bW15IHZhcmlhYmxlIGlzb2xhdGVzIHRoZSBlZmZlY3Qgb2YgdGhlIGV2ZW50IG9uIHRoZSBzdG9jayByZXR1cm5zLg0KDQoNCiMjIyMgUGVyZm9ybWluZyBSZWdyZXNzaW9uIEFuYWx5c2lzOg0KDQpSZWdyZXNzZXMgdGhlIGRhaWx5IHJldHVybnMgb24gdGhlIGV2ZW50IGR1bW15IHZhcmlhYmxlLg0KDQpUaGUgY29lZmZpY2llbnQgb2YgZXZlbnRfZHVtbXkgcmVwcmVzZW50cyB0aGUgYWJub3JtYWwgcmV0dXJuIG9uIHRoZSBldmVudCBkYXRlLg0KDQoNCg0KIyMjIEludGVycHJldGluZyB0aGUgUmVncmVzc2lvbiBSZXN1bHRzDQoNCiMjIyMgQ29lZmZpY2llbnQgb2YgZXZlbnRfZHVtbXk6DQoNClJlcHJlc2VudHMgdGhlIGFibm9ybWFsIHJldHVybiBhdHRyaWJ1dGVkIHRvIHRoZSBldmVudC4NCg0KQSBzaWduaWZpY2FudCBwb3NpdGl2ZSBjb2VmZmljaWVudCBzdWdnZXN0cyBhIGZhdm9yYWJsZSBtYXJrZXQgcmVhY3Rpb24uDQoNCkEgc2lnbmlmaWNhbnQgbmVnYXRpdmUgY29lZmZpY2llbnQgaW5kaWNhdGVzIGFuIHVuZmF2b3JhYmxlIHJlYWN0aW9uLg0KDQoNCiMjIyMgU3RhdGlzdGljYWwgU2lnbmlmaWNhbmNlOg0KQ2hlY2sgdGhlIHAtdmFsdWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBldmVudF9kdW1teSBjb2VmZmljaWVudC4NCg0KQSBwLXZhbHVlIGxlc3MgdGhhbiAwLjA1IHR5cGljYWxseSBpbmRpY2F0ZXMgc3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIGF0IHRoZSA1JSBsZXZlbC4NCg0KDQojIyMgQ29uY2x1c2lvbnMuIA0KQXMgb3VyIHAtdmFsdWUgaXMgMC4xNTg4LCB3ZSBkbyBub3QgaGF2ZSBzdWZmaWNpZW50IGRhdGEgdG8gY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgYXQgYSBjb25maWRlbmNlIGxldmVsIG9mIDk1JSAob3Igc2lnbmlmaWNhbmNlIGxldmVsIG9mIDUlKS4gDQpUaGlzIG1lYW5zIHRoYXQgd2UgY2Fubm90IGRldGVybWluZSB0aGF0IHRoZXJlIGhhcyBiZWVuIGFuIGFibm9ybWFsIGV2ZW50IGF0IHRoZSBldmVudCBkYXRlLiANCg0KDQojIyMgRXh0ZW5kZWQgRXZlbnQgV2luZG93IEFuYWx5c2lzDQpUbyBjYXB0dXJlIHBvdGVudGlhbCBtYXJrZXQgcmVhY3Rpb25zIGJlZm9yZSBhbmQgYWZ0ZXIgdGhlIGV2ZW50LCB3ZSBleHRlbmQgdGhlIGFuYWx5c2lzIHRvIGFuIGV2ZW50IHdpbmRvdy4NCg0KYGBge3J9DQojIERlZmluZSBldmVudCB3aW5kb3cgKGUuZy4sIC0yIHRvICsyIGRheXMgYXJvdW5kIHRoZSBldmVudCBkYXRlKQ0KZXZlbnRfd2luZG93IDwtIGMoLTIsIDIpDQoNCiMgR2V0IHRoZSBudW1lcmljIHBvc2l0aW9uIG9mIHRoZSBldmVudCBkYXRlIGluIHRoZSByZXR1cm5zIGluZGV4DQpldmVudF9wb3MgPC0gbWF0Y2goYXMuRGF0ZShldmVudF9kYXRlKSwgaW5kZXgoQUFQTF9yZXR1cm5zKSkNCg0KIyBEZWZpbmUgdGhlIHN0YXJ0IGFuZCBlbmQgcG9zaXRpb25zIG9mIHRoZSBldmVudCB3aW5kb3cNCndfYmVnIDwtIGV2ZW50X3BvcyArIGV2ZW50X3dpbmRvd1sxXQ0Kd19lbmQgPC0gZXZlbnRfcG9zICsgZXZlbnRfd2luZG93WzJdDQoNCiMgQWRqdXN0IGV2ZW50X2R1bW15IHRvIG1hcmsgdGhlIGV2ZW50IHdpbmRvdw0KZXZlbnRfZHVtbXlfd2luZG93IDwtIHJlcCgwLCBsZW5ndGgoQUFQTF9yZXR1cm5zKSkNCmV2ZW50X2R1bW15X3dpbmRvd1t3X2JlZzp3X2VuZF0gPC0gMQ0KDQojIENhbGN1bGF0ZSBjdW11bGF0aXZlIGFibm9ybWFsIHJldHVybnMgKENBUikNCkNBUiA8LSBzdW0oQUFQTF9yZXR1cm5zICogZXZlbnRfZHVtbXlfd2luZG93KQ0KDQojIFBlcmZvcm0gdC10ZXN0IHRvIGFzc2VzcyBzaWduaWZpY2FuY2UNCiMgQ2FsY3VsYXRlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiByZXR1cm5zIGluIHRoZSBldmVudCB3aW5kb3cNCmV2ZW50X3dpbmRvd19yZXR1cm5zIDwtIEFBUExfcmV0dXJuc1t3X2JlZzp3X2VuZF0NCnN0ZF9kZXYgPC0gc2QoZXZlbnRfd2luZG93X3JldHVybnMpDQoNCiMgQ2FsY3VsYXRlIHQtc3RhdGlzdGljDQp0X3N0YXQgPC0gQ0FSIC8gKHN0ZF9kZXYgKiBzcXJ0KGxlbmd0aChldmVudF93aW5kb3dfcmV0dXJucykpKQ0KDQojIERlZ3JlZXMgb2YgZnJlZWRvbQ0KZGYgPC0gbGVuZ3RoKGV2ZW50X3dpbmRvd19yZXR1cm5zKSAtIDENCg0KIyBDYWxjdWxhdGUgcC12YWx1ZQ0KcF92YWx1ZSA8LSAyICogcHQoLWFicyh0X3N0YXQpLCBkZiA9IGRmKQ0KDQojIFByaW50IHJlc3VsdHMNCmNhdCgiQ3VtdWxhdGl2ZSBBYm5vcm1hbCBSZXR1cm4gKENBUik6IiwgQ0FSLCAiXG4iKQ0KY2F0KCJ0LXN0YXRpc3RpYzoiLCB0X3N0YXQsICJcbiIpDQpjYXQoInAtdmFsdWU6IiwgcF92YWx1ZSwgIlxuIikNCmBgYA0KDQoNCiMjIyMgRXh0ZW5kZWQgd2luZG93IGFuYWx5c2lzDQpBbHRob3VnaCB3ZSBoYXZlIGZvbGxvd2VkIHRoZSBzdGVwcyB0byBwZXJmb3JtIHRoZSBleHRlbmRlZCB3aW5kb3cgYW5hbHlzaXMgd2UgaGF2ZSBlbmNvdW50ZXJlZCBhIHlldCB1bmtub3duIG1pc3Rha2Ugd2hpY2ggaGFkIGxlZCB1cyB0byBub3Qgb2J0YWluIGFueSB2YWx1ZS4gVGhpcyBleHRlbmRlZCB3aW5kb3cgaXMgc3VwcG9zZWQgdG8gYW5hbHlzZSBvdGhlciBtYXJrZXQgcmVhY3Rpb25zIHRoYXQgaGF2ZSBoYXBwZW5lZCB3aXRoaW4gYSByYW5nZSBmcm9tIHRoZSBldmVudCB3aW5kb3cuIEhhZCB3ZSBvYnRhaW5lZCBhbnkgcmVzdWx0cywgd2UgY291bGQgaGF2ZSBkZXJpdmVkIHRoYXQgaW4gc29tZSBuZWFyYnkgZGF0ZXMgdGhlcmUgaGFkIGJlZW4gYW4gZXZlbnQgb3IgdGhhdCB0aGUgZXZlbnQgaGFkIGJlZW4gb25lIHRoYXQgaGFkIGV4dGVuZGVkIG92ZXIgYSBzZXJpZXMgb2YgZGF0ZXMuICANCg0KDQojIyMjIEN1bXVsYXRpdmUgQWJub3JtYWwgUmV0dXJuDQoNClJlcHJlc2VudHMgdGhlIHRvdGFsIGFibm9ybWFsIHJldHVybiBvdmVyIHRoZSBldmVudCB3aW5kb3cuDQoNCkEgcG9zaXRpdmUgQ0FSIHN1Z2dlc3RzIHRoYXQgdGhlIGV2ZW50IGhhZCBhIGZhdm9yYWJsZSBpbXBhY3Qgb24gc3RvY2sgcmV0dXJucy4NCg0KQSBuZWdhdGl2ZSBDQVIgaW5kaWNhdGVzIGFuIHVuZmF2b3JhYmxlIGltcGFjdC4NCg0KQXMgZGVzY3JpYmVkIGJlZm9yZSwgdGhlIGxhY2sgb2YgcmVzdWx0cyBsZWFkIHVzIHRvIG5vIGZ1cnRoZXIgY29tbWVudHMuIA0KDQoNCg0KDQojIyMgSW50ZXJwcmV0YXRpb246DQoNCiMjIyMgVGhlIHAtdmFsdWUgaXMgZ3JlYXRlciB0aGFuIDAuMDU6DQoNCldlIGZhaWwgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMuDQoNCkNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgbm8gc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBldmlkZW5jZSB0aGF0IHRoZSBldmVudCBhZmZlY3RlZCB0aGUgc3RvY2sgcHJpY2UuDQoNCg0KIyMjIEZpbmFsIFJlbWFya3MNCg0KIyMjIyBFYXJuaW5ncyBhbm5vdW5jZW1lbnRzIA0KVGhleSBvZnRlbiBsZWFkIHRvIGluY3JlYXNlZCB2b2xhdGlsaXR5IGFuZCBjYW4gc2lnbmlmaWNhbnRseSBpbXBhY3Qgc3RvY2sgcHJpY2VzIGRlcGVuZGluZyBvbiB3aGV0aGVyIHRoZSByZXN1bHRzIG1lZXQsIGV4Y2VlZCwgb3IgZmFsbCBzaG9ydCBvZiBtYXJrZXQgZXhwZWN0YXRpb25zLg0KDQoNCiMjIyMgTGltaXRhdGlvbnM6DQoNCg0KVGhlIGFuYWx5c2lzIGFzc3VtZXMgdGhhdCB0aGUgbWFya2V0IGlzIGVmZmljaWVudCBhbmQgdGhhdCBhbnkgYWJub3JtYWwgcmV0dXJucyBhcmUgc29sZWx5IGR1ZSB0byB0aGUgZXZlbnQuDQoNCkV4dGVybmFsIGZhY3RvcnMgKGUuZy4sIG1hY3JvZWNvbm9taWMgbmV3cywgaW5kdXN0cnkgdHJlbmRzKSBjb3VsZCBhbHNvIGluZmx1ZW5jZSBzdG9jayByZXR1cm5zIGR1cmluZyB0aGUgZXZlbnQgd2luZG93Lg0KDQpEYXRhIENvbnN0cmFpbnRzOiBUaGUgYW5hbHlzaXMgaXMgYmFzZWQgb24gaGlzdG9yaWNhbCBkYXRhIHVwIHRvIE5vdmVtYmVyIDEyLCAyMDIwLiBSZXN1bHRzIG1pZ2h0IGRpZmZlciB3aXRoIHVwZGF0ZWQgZGF0YS4NCg0KDQojIyMjIFJlY29tbWVuZGF0aW9uczoNCg0KSW5jbHVkZSBDb250cm9sIFZhcmlhYmxlczogSW5jb3Jwb3JhdGUgbWFya2V0IG9yIGluZHVzdHJ5IHJldHVybnMgdG8gY29udHJvbCBmb3IgYnJvYWRlciBtYXJrZXQgbW92ZW1lbnRzLg0KDQoNClJvYnVzdCBTdGF0aXN0aWNhbCBUZXN0czogdXNlIG1vcmUgc29waGlzdGljYXRlZCBtb2RlbHMgKGUuZy4sIE1hcmtldCBNb2RlbCkgdG8gZXN0aW1hdGUgZXhwZWN0ZWQgcmV0dXJucyBhbmQgYWJub3JtYWwgcmV0dXJucy4NCg0KDQoNCiMjIEw3LjEgLSBMNy4yLiBDb21wYXJpbmcgeWllbGRzIGFtb25nIHNlY3VyaXRpZXMNCg0KIyMjIEV4cGxhbmF0aW9ucyBhaGVhZA0KDQpJbiB0aGlzIHR3byBleGVyY2lzZXMgd2Ugd2lsbCBkaXNjdXNzIHNlY3VyaXRpZXMnIHlpZWxkcy4gV2Ugd2lsbCBub3cgZXhwbGFpbiB3aGF0IGlzIGEgc2VjdXJpdHkuDQoNCiMjIyMgU2VjdXJpdGllcw0KQSBmaW5hbmNpYWwgc2VjdXJpdHkgaXMgYSBjYXRlZ29yeSB0aGF0IGVuZ2xvYmVzIGRpZmZlcmVudCBhIHdpZGUgcmFuZ2Ugb2YgaW52ZXN0bWVudHMuIFRoZXJlIGFyZSB0aHJlZSBtYWluIHR5cGVzOiBlcXVpdHksIGRlYnQgYW5kIGh5YnJpZHMuIA0KU2VjdXJpdGllcyBjYW4gYmUgdHJhZGVkIGJvdGggcHVibGljbHkgYW5kIG92ZXItdGhlLWNvdW50ZXIuIA0KV2hlbiB0YWxraW5nIGFib3V0IHNlY3VyaXRpZXMgd2Ugc2hhbGwgdGFrZSBpbnRvIGFjY291bnQgY29uY2VwdHMgc3VjaCBhcyBJUE9zLCB3aGljaCBjb25zdGl0dXRlIHRoZSBmaXJzdCBzZWxsIG9mIHNlY3VyaXRpZXMgdG8gdGhlIHB1YmxpYy4gU2VjdXJpdGllcyBjYW4gYWxzbyBiZSBvZmZlcmVkIGluIHByaXZhdGUgcGxhY2VtZW50cyBhbmQgdWx0aW1hdGVseSBpbiB0aGUgc2Vjb25kYXJ5IG1hcmtldHMsIE9UQyBhbmQgcHJpdmF0ZSBhbmQgZGlyZWN0IG5lZ290aWF0aW9ucy4gDQoNCg0KIyMjIyBZaWVsZHMNCllpZWxkcyByZWZlciB0byB0aGUgZWFybmluZ3MgZ2VuZXJhdGVkIGJ5IGFuIGludmVzdG1lbnQsIGFuZCBpdCBjYW4gdGFrZSB0aGUgZm9ybSBvZiBkaXZpZGVuZHMgb3IgaW50ZXJlc3QuIEluIHRoZSBwcmVzZW50IGNhc2UsIHdoZW4gd2UgdGFsayBhYm91dCB0aGUgWWllbGQgaXQgd2lsbCBhZG9wdCB0aGUgZm9ybSBvZiBpbnRlcmVzdC4gDQoNCg0KIyMjIEw3LjEgV2hhdCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB5aWVsZCBvbiBjb3Jwb3JhdGUgaGlnaC1xdWFsaXR5IGJvbmRzIGFuZCB0aGUgeWllbGQgb24gVHJlYXN1cnkgYm9uZHMgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0/IEV4cGxhaW4gd2h5IGRvZXMgdGhlIGRpZmZlcmVuY2UgZXhpc3Q/DQoNCg0KIyMjIyBSIGNvZGUgZm9yIGRlbW9uc3RyYXRpb24NCg0KbG9hZCBwYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpgYGANCg0KDQpEZWZpbmUgRW9UX2RhdGUNCg0KYGBge3J9DQojIERlZmluZSBFbmQgb2YgVGVybSAoRW9UKSBkYXRlDQpFb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCmBgYA0KDQoNClJldHJpZXZlIFRyZWFzdXJ5IEJvbmQgWWllbGQgRGF0YQ0KDQpgYGB7cn0NCiMgUmV0cmlldmUgMTAtWWVhciBUcmVhc3VyeSB5aWVsZCBkYXRhDQpnZXRTeW1ib2xzKCJER1MxMCIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IEVvVF9kYXRlIC0gNywgdG8gPSBFb1RfZGF0ZSArIDcpDQoNCiMgVmlldyB0aGUgZGF0YQ0KaGVhZChER1MxMCkNCg0KYGBgDQoNCg0KUmV0cmlldmUgQ29wb3JhdGUgSGlnaC1RdWFsaXR5IEJvbmQgWWllbGQgRGF0YQ0KDQpgYGB7cn0NCiMgUmV0cmlldmUgTW9vZHkncyBBYWEgQ29ycG9yYXRlIEJvbmQgeWllbGQgZGF0YQ0KZ2V0U3ltYm9scygiREFBQSIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IEVvVF9kYXRlIC0gNywgdG8gPSBFb1RfZGF0ZSArIDcpDQoNCiMgVmlldyB0aGUgZGF0YQ0KaGVhZChEQUFBKQ0KYGBgDQoNCg0KQWRqdXN0IHRvIE5vbi1UcmFkaW5nIERheXMNCg0KYGBge3J9DQojIEZ1bmN0aW9uIHRvIGdldCB5aWVsZCBvbiBhIHNwZWNpZmljIGRhdGUNCmdldF95aWVsZF9vbl9kYXRlIDwtIGZ1bmN0aW9uKGRhdGEsIGRhdGUpIHsNCiAgIyBDb252ZXJ0IGluZGV4IHRvIERhdGUgZm9ybWF0DQogIGluZGV4KGRhdGEpIDwtIGFzLkRhdGUoaW5kZXgoZGF0YSkpDQogIA0KICAjIEdldCBhdmFpbGFibGUgZGF0ZXMgb24gb3IgYmVmb3JlIHRoZSBzcGVjaWZpZWQgZGF0ZQ0KICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPD0gZGF0ZSAmICFpcy5uYShkYXRhW2luZGV4KGRhdGEpXSldDQogIA0KICBpZiAobGVuZ3RoKGF2YWlsYWJsZV9kYXRlcykgPT0gMCkgew0KICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIG9uIG9yIGJlZm9yZSIsIGRhdGUpKQ0KICAgIHJldHVybihsaXN0KFlpZWxkID0gTkEsIERhdGUgPSBOQSkpDQogIH0NCiAgDQogIGRhdGVfdXNlZCA8LSBtYXgoYXZhaWxhYmxlX2RhdGVzKQ0KICANCiAgIyBHZXQgdGhlIHlpZWxkDQogIHlpZWxkIDwtIGFzLm51bWVyaWMoZGF0YVtkYXRlX3VzZWRdKQ0KICANCiAgcmV0dXJuKGxpc3QoDQogICAgWWllbGQgPSB5aWVsZCwNCiAgICBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICkpDQp9DQpgYGANCg0KDQpSZXRyaWV2ZSBZaWVsZHMgb24gRW9UX2RhdGUNCg0KYGBge3J9DQojIEdldCBUcmVhc3VyeSB5aWVsZCBvbiBFb1RfZGF0ZQ0KdHJlYXN1cnlfeWllbGQgPC0gZ2V0X3lpZWxkX29uX2RhdGUoREdTMTAsIEVvVF9kYXRlKQ0KDQojIEdldCBDb3Jwb3JhdGUgQWFhIHlpZWxkIG9uIEVvVF9kYXRlDQpjb3Jwb3JhdGVfeWllbGQgPC0gZ2V0X3lpZWxkX29uX2RhdGUoREFBQSwgRW9UX2RhdGUpDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIERpZmZlcmVuY2UNCg0KYGBge3J9DQojIENhbGN1bGF0ZSB0aGUgeWllbGQgZGlmZmVyZW5jZQ0KeWllbGRfZGlmZmVyZW5jZSA8LSBjb3Jwb3JhdGVfeWllbGQkWWllbGQgLSB0cmVhc3VyeV95aWVsZCRZaWVsZA0KDQojIERpc3BsYXkgdGhlIHJlc3VsdHMNCnJlc3VsdHNfTDcxIDwtIGRhdGEuZnJhbWUoDQogIERhdGUgPSB0cmVhc3VyeV95aWVsZCREYXRlLA0KICBUcmVhc3VyeV9ZaWVsZCA9IHRyZWFzdXJ5X3lpZWxkJFlpZWxkLA0KICBDb3Jwb3JhdGVfWWllbGQgPSBjb3Jwb3JhdGVfeWllbGQkWWllbGQsDQogIFlpZWxkX0RpZmZlcmVuY2UgPSB5aWVsZF9kaWZmZXJlbmNlDQopDQoNCnByaW50KHJlc3VsdHNfTDcxKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQoNCkluIHRoaXMgZXhlcmNpc2Ugd2UgaGF2ZSBvYnRhaW5lZCB0aGUgWWllbGRzIG9mIHR3byBkaWZmZXJlbnQgQm9uZHMgd2l0aCB0aGUgaGVscCBvZiBvdXIgUiBjb2RlLCBpbiB3aGljaCB3ZSBoYXZlIHJldHJpZXZlZCB0aGUgWWllbGRzIGZyb20gdGhlIDEwLVllYXIgVVMgVHJlYXN1cnkgYm9uZCBhbmQgdGhlIE1vb2R5J3MgU2Vhc29uZWQgQWFhIENvcnBvcmF0ZSBCb25kIFlpZWxkLiANCldoZW4gd2UgY29tcGFyZSB0aGVzZSB0d28gYm9uZHMsIHdlIHNoYWxsIGZvcmVzZWUgdGhhdCB0aGUgQ29ycG9yYXRlIEJvbmQgWWllbGQgd2lsbCBtb3N0IGxpa2VseSBiZSBoaWdoZXIgdGhhbiB0aGUgVHJlYXN1cnkgQm9uZC4gRXZlbiB0aG91Z2ggdGhlIGNvcnBvcmF0ZSB5aWVsZCBvZmZlcnMgaGlnaCBxdWFsaXR5IGFuZCBoYXMgYSBoaWdoIHJhdGluZywgdGhlIHRyZWFzdXJ5IGJvbmRzIGFyZSBvdmVyYWxsIGxlc3Mgcmlza3kgYW5kIG9mZmVyIGEgbXVjaCBtb3JlIHN0YWJsZSBvcHRpb24uIFdoZW4gYW4gaW52ZXN0b3IgZGVjaWRlcyB0byBidXkgYSBjb3Jwb3JhdGUgYm9uZCBvdmVyIGEgZ292ZXJubWVudCBib25kICh0aGlzIGlzIGFub3RoZXIgd2F5IG9mIG5hbWluZyB0aGUgdHJlYXN1cnkgYm9uZHMpLCB0aGV5IG1ha2UgYW4gYXNzZXNzbWVudCBvZiB0aGUgcmlzayBsZXZlbCB0aGV5IHdpbGwgYmUgb3BlbiB0byB0b2xlcmF0ZSBhbmQgdGhlIHJldHVybnMgdGhleSB3aWxsIG9idGFpbiBmcm9tIGl0LiBBcyBhIGdlbmVyYWwgcnVsZSwgdGhlIGhpZ2hlciByZXR1cm5zIHdpbGwgYmUgcGFpcmVkIHdpdGggaGlnaGVyIHZvbGF0aWxpdHkgKHJpc2spLiANCg0KDQojIyMgTDcuMiBXaGF0IGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHlpZWxkIG9uIGxvbmctdGVybSBUcmVhc3VyeSBib25kcyBhbmQgdGhlIHlpZWxkIG9uIGxvbmctdGVybSBtdW5pY2lwYWwgYm9uZHMgYXQgdGhlIGVuZCBvZiB0aGUgc2Nob29sIHRlcm0/IEV4cGxhaW4gd2h5IGRvZXMgdGhlIGRpZmZlcmVuY2UgZXhpc3Q/DQoNCk11bmljaXBhbCBib25kcyBhcmUgYSB0eXBlIG9mIHNlY3VyaXR5IGlzc3VlZCBieSBsb2NhbCBjb3VudHkgYW5kIHN0YXRlIGdvdmVybm1lbnRzLiBUaGlzIGlzIGEgZGVidCBzZWN1cml0eSB3aGljaCBpcyBvZnRlbiB1c2VkIHRvIGZpbmFuY2UgbG9jYWwgcHJvamVjdHMuIEhvd2V2ZXIsIGRhdGEgYXZhaWxhYmlsaXR5IGZvciB0aGVzZSB0eXBlcyBvZiBib25kcyBhcmUgbm90IGVhc2lseSBhdmFpbGFibGUsIGFuZCB3ZSBjYW5ub3Qgb2J0YWluIHRoZSBEYXRhIGFib3V0IHRoZWlyIHlpZWxkcy4gDQoNCkdpdmVuIHRoZSBsYWNrIG9mIGRhdGEsIHdlIGNhbm5vdCBwZXJmb3JtIGEgcmVhbCByZXByZXNlbnRhdGlvbiwgYnV0IHdlIG1heSBzdXBwb3NlIHRoYXQgbXVuaWNpcGFsIGJvbmRzIHdpbGwgaGF2ZSBoaWdoZXIgeWllbGRzIHRoYW4gbG9uZy10ZXJtIFRyZWFzdXJ5IEJvbmRzLiBNdW5pY2lwYWwgQm9uZHMgYXJlIHVzdWFsbHkgZXhlbnQgZnJvbSB0YXhhdGlvbiwgd2hpY2ggcHJvdmlkZXMgYW4gYWJzb2x1dGUgeWllbGQgcmVhbGx5IGF0dHJhY3RpdmUgZm9yIGludmVzdG9ycy4gDQpJZiB3ZSBhbHNvIGFuYWx5emUgYnJpZWZseSB0aGUgbWFjcm9lY29ub21pYyBzaXR1YXRpb24gb2YgdGhlIFVTLCB0aGUgY3V0IGluIEZFRCByYXRlIHNob3VsZCBwcm9kdWNlIGFuIGluY3JlYXNlIGluIHlpZWxkcyBmb3IgdGhlIGxvbmdlciBkdXJhdGlvbiBib25kcy4gQWRkaXRpb25hbGx5LCB0aGUgY3VycmVudCBzdHJlbmd0aCBvZiB0aGUgVVMgZWNvbm9teSB3aXRoIHRoZSByZWNlbnQgd2luIG9mIERvbmFsZCBUcnVtcCBoYXMgcHJvZHVjZWQgYW4gc3Bpa2UgaW4gbG9uZy10ZXJtIHlpZWxkcy4gDQpIb3dldmVyLCBwYXlpbmcgYXR0ZW50aW9uIHRvIHJlY2VudCBuZXdzIHJlZ2FyZGluZyBtdW5pY2lwYWwgYm9uZHMsIHRoZWlyIG1haW4gYXR0cmFjdGl2ZW5lc3Mgd2hpY2ggaXMgdGhlaXIgdGF4IGV4ZW1wdGlvbnMgbWF5IGJlIGZhY2luZyB0aGUgcmlzayBvZiBiZWluZyBzdXBwcmVzc2VkLiBXZXJlIHRoaXMgdG8gaGFwcGVuLCBtdW5pY2lwYWwgYm9uZHMgbWF5IGJlIGdyZWF0bHkgYWZmZWN0ZWQuIA0KDQoNCg0KIyMgTDcuMyAtIEw3LjYgQXNzZXNzaW5nIHRoZSBmb3JlY2FzdGluZyBhYmlsaXR5IG9mIHRoZSB5aWVsZCBjdXJ2ZQ0KDQojIyMgTDcuMyAtIEw3LjUNCg0KTG9hZCBwYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KDQoNCg0KRGVmaW5lIEJvVF9kYXRlDQoNCmBgYHtyfQ0KIyBEZWZpbmUgQmVnaW5uaW5nIG9mIFRlcm0gKEJvVCkgZGF0ZQ0KQm9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNS0wMSIpDQpgYGANCg0KDQpEYXRlIFJhbmdlDQoNCmBgYHtyfQ0KIyBEZWZpbmUgdGhlIGRhdGUgcmFuZ2UNCnN0YXJ0X2RhdGUgPC0gQm9UX2RhdGUgLSA3ICAjIE9uZSB3ZWVrIGJlZm9yZQ0KZW5kX2RhdGUgPC0gQm9UX2RhdGUgKyA3ICAgICMgT25lIHdlZWsgYWZ0ZXINCmBgYA0KDQoNCg0KUmV0cmlldmUgMTN3ZWVrIGFuZCAyNiB3ZWVrIFQtYmlsbCBZaWVsZCBEYXRhDQoxMy13ZWVrIHRiaWxsIHN5bWJvbDogIkRHUzNNTyINCjI2LXdlZWsgdGJpbGwgc3ltYm9sOiAiREdTNk1PIg0KV2UgYXJlIHVzaW5nIHRoZSBkYWlseSB5aWVsZCBkYXRhIGZvciB0aGUgY29uc3RhbnQgbWF0dXJpdHkgcmF0ZSwgYXMgbm8gZGF0YSB3YXMgdG8gYmUgZm91bmQgYW5kIHVzZWQgb3RoZXJ3aXNlDQoNCmBgYHtyfQ0KIyBSZXRyaWV2ZSAxMy13ZWVrIFQtYmlsbCB5aWVsZCBkYXRhDQpnZXRTeW1ib2xzKCJER1MzTU8iLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBzdGFydF9kYXRlLCB0byA9IGVuZF9kYXRlKQ0KDQojIFJldHJpZXZlIDI2LXdlZWsgVC1iaWxsIHlpZWxkIGRhdGENCmdldFN5bWJvbHMoIkRHUzZNTyIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpDQoNCmBgYA0KDQoNCk1lcmdlIFlpZWxkcyBpbnRvIG9uZSBkYXRhIGZyYW1lIGFuZCBjb252ZXJ0aW5nIGl0IHRvIHBsb3QNCg0KYGBge3J9DQojIE1lcmdlIHRoZSB5aWVsZHMgaW50byBvbmUgZGF0YSBmcmFtZQ0KeWllbGRzX2RhdGEgPC0gbWVyZ2UoREdTM01PLCBER1M2TU8sIGpvaW4gPSAiaW5uZXIiKQ0KY29sbmFtZXMoeWllbGRzX2RhdGEpIDwtIGMoIllpZWxkXzEzd2siLCAiWWllbGRfMjZ3ayIpDQojIENvbnZlcnQgdG8gZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcNCnlpZWxkc19kZiA8LSBkYXRhLmZyYW1lKERhdGUgPSBpbmRleCh5aWVsZHNfZGF0YSksIGNvcmVkYXRhKHlpZWxkc19kYXRhKSkNCg0KIyBSZW1vdmUgcm93cyB3aXRoIE5BIHZhbHVlcw0KeWllbGRzX2RmIDwtIG5hLm9taXQoeWllbGRzX2RmKQ0KDQojUGxvdCBZaWVsZHMgb3ZlciB0aW1lDQojIFBsb3QgdGhlIHlpZWxkcyBvdmVyIHRpbWUNCmdncGxvdCh5aWVsZHNfZGYsIGFlcyh4ID0gRGF0ZSkpICsNCiAgZ2VvbV9saW5lKGFlcyh5ID0gWWllbGRfMTN3aywgY29sb3IgPSAiMTMtd2VlayBULWJpbGwiKSkgKw0KICBnZW9tX2xpbmUoYWVzKHkgPSBZaWVsZF8yNndrLCBjb2xvciA9ICIyNi13ZWVrIFQtYmlsbCIpKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGFzLm51bWVyaWMoYXMuRGF0ZShCb1RfZGF0ZSkpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiMTMtd2VlayBhbmQgMjYtd2VlayBULWJpbGwgWWllbGRzIEFyb3VuZCBCb1RfZGF0ZSIsDQogICAgeCA9ICJEYXRlIiwNCiAgICB5ID0gIllpZWxkICglKSIsDQogICAgY29sb3IgPSAiVC1iaWxsIE1hdHVyaXR5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQpBZGp1c3QgdG8gTm9uLVRyYWRpbmcgRGF5cw0KDQpgYGB7cn0NCmdldF95aWVsZF9vbl9kYXRlIDwtIGZ1bmN0aW9uKGRhdGEsIGRhdGUpIHsNCiAgIyBDb252ZXJ0IGluZGV4IHRvIERhdGUgZm9ybWF0DQogIGluZGV4KGRhdGEpIDwtIGFzLkRhdGUoaW5kZXgoZGF0YSkpDQogIA0KICAjIEdldCBhdmFpbGFibGUgZGF0ZXMgb24gb3IgYmVmb3JlIHRoZSBzcGVjaWZpZWQgZGF0ZQ0KICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPD0gZGF0ZSAmICFpcy5uYShkYXRhW2luZGV4KGRhdGEpXSldDQogIA0KICBpZiAobGVuZ3RoKGF2YWlsYWJsZV9kYXRlcykgPT0gMCkgew0KICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIG9uIG9yIGJlZm9yZSIsIGRhdGUpKQ0KICAgIHJldHVybihsaXN0KFlpZWxkID0gTkEsIERhdGUgPSBOQSkpDQogIH0NCiAgDQogIGRhdGVfdXNlZCA8LSBtYXgoYXZhaWxhYmxlX2RhdGVzKQ0KICANCiAgIyBHZXQgdGhlIHlpZWxkDQogIHlpZWxkIDwtIGFzLm51bWVyaWMoZGF0YVtkYXRlX3VzZWRdKQ0KICANCiAgcmV0dXJuKGxpc3QoDQogICAgWWllbGQgPSB5aWVsZCwNCiAgICBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICkpDQp9DQpgYGANCg0KDQpSZXRyaWV2ZSBZaWVsZHMgb24gQm9UX2RhdGUNCg0KYGBge3J9DQojIEdldCAxMy13ZWVrIFQtYmlsbCB5aWVsZCBvbiBCb1RfZGF0ZQ0KeWllbGRfMTN3ayA8LSBnZXRfeWllbGRfb25fZGF0ZShER1MzTU8sIEJvVF9kYXRlKQ0KDQojIEdldCAyNi13ZWVrIFQtYmlsbCB5aWVsZCBvbiBCb1RfZGF0ZQ0KeWllbGRfMjZ3ayA8LSBnZXRfeWllbGRfb25fZGF0ZShER1M2TU8sIEJvVF9kYXRlKQ0KDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIERpZmZlcmVuY2UNCg0KYGBge3J9DQojIENhbGN1bGF0ZSB0aGUgeWllbGQgZGlmZmVyZW5jZQ0KeWllbGRfZGlmZmVyZW5jZSA9IHlpZWxkXzI2d2skWWllbGQgLSB5aWVsZF8xM3drJFlpZWxkDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSB0byBkaXNwbGF5IHRoZSByZXN1bHRzDQpyZXN1bHRzX0w3MyA8LSBkYXRhLmZyYW1lKA0KICBEYXRlID0geWllbGRfMTN3ayREYXRlLA0KICBZaWVsZF8xM3drID0geWllbGRfMTN3ayRZaWVsZCwNCiAgWWllbGRfMjZ3ayA9IHlpZWxkXzI2d2skWWllbGQsDQogIFlpZWxkX0RpZmZlcmVuY2UgPSB5aWVsZF9kaWZmZXJlbmNlDQopDQoNCnByaW50KHJlc3VsdHNfTDczKQ0KDQpgYGANCg0KQWRkaXRpb25hbGx5LCB3ZSBjYW4gcGxvdCBvdXIgcmVzdWx0cyBpbiBvcmRlciB0byBoYXZlIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBwbG90dGluZyB0aGUgeWllbGQgY3VydmUNCnlpZWxkX2N1cnZlX2RmIDwtIGRhdGEuZnJhbWUoDQogIE1hdHVyaXR5ID0gYygxMy81MiwgMjYvNTIpLCAgIyBDb252ZXJ0IHdlZWtzIHRvIHllYXJzDQogIFlpZWxkID0gYyh5aWVsZF8xM3drJFlpZWxkLCB5aWVsZF8yNndrJFlpZWxkKQ0KKQ0KDQojIFBsb3QgdGhlIHlpZWxkIGN1cnZlIGJldHdlZW4gMTMtd2VlayBhbmQgMjYtd2VlayBULWJpbGxzDQpnZ3Bsb3QoeWllbGRfY3VydmVfZGYsIGFlcyh4ID0gTWF0dXJpdHksIHkgPSBZaWVsZCkpICsNCiAgZ2VvbV9saW5lKGNvbG9yID0gImJsdWUiKSArDQogIGdlb21fcG9pbnQoY29sb3IgPSAicmVkIiwgc2l6ZSA9IDMpICsNCiAgbGFicygNCiAgICB0aXRsZSA9IHBhc3RlKCJZaWVsZCBDdXJ2ZSBiZXR3ZWVuIDEzLXdlZWsgYW5kIDI2LXdlZWsgVC1iaWxscyBvbiIsIEJvVF9kYXRlKSwNCiAgICB4ID0gIk1hdHVyaXR5IChZZWFycykiLA0KICAgIHkgPSAiWWllbGQgKCUpIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQojIyMjIEFuYWx5c2lzIG9mIHJlc3VsdHMNCg0KSW4gdGhlc2UgMyBleGVyY2lzZXMgd2UgaGF2ZSBjYWxjdWxhdGVkIHRoZSBkaWZmZXJlbmNlIGluIHlpZWxkcyBvZiB0aGUgMjYtd2VlayBULWJpbGwgeWllbGQgYW5kIHRoZSAxMy13ZWVrICBULWJpbGwgeWllbGQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgc2Nob29sIHRlcm0uIA0KVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBib3RoIHlpZWxkcyBnaXZlcyB1cyBhIHRvdGFsIGFtb3VudCBvZiAtMC4wMywgd2hpY2ggcmV2ZWFscyBhIGhpZ2hlciB5aWVsZCBpbiB0aGUgMTMtd2VlayBULWJpbGwuIA0KDQpIaWdoZXIgeWllbGRzIG9uIGxvd2VyIG1hdHVyaXR5IGJvbmRzIGlzIGEgcmF0aGVyIHVuc3VhbCBzaXR1YXRpb24sIGJ1dCBpdCBjYW4gYmUgZXhwbGFpbmVkIGR1ZSB0byBzZXZlcmFsIGZhY3RvcnMuIFRoaXMgaGlnaGVyIHlpZWxkIG1heSBiZSB0aGUgcmVzdWx0IG9mIG1hcmtldCB1bmNlcnRhaW50eSwgaW4gd2hpY2ggaW52ZXN0b3JzIGxvb2sgZm9yIHNhZmVyIGFuZCBsb25nLXRlcm0gc2VjdXJpdGllcy4gDQoNCk9uIHRoZSBvdGhlciBoYW5kLCBhbmQgYW5zd2VyaW5nIHRvIEw3LjUsIHRoaXMgbWF5IGJlIHRoZSByZXN1bHQgb2YgdGhlIGV4cGVjdGFuY3kgb2YgYSBGRUQncyByYXRlIGN1dCwgd2hpY2ggd291bGQgbGVhZCB0byBldmVuIGxvd2VyIHlpZWxkcy4gVGhpcyByZWFzb24gd291bGQgYWxzbyBleHBsYWluIHRoZSBoaWdoZXIgeWllbGRzIGluIHRoZSBzaG9ydCB0ZXJtLiBUaGUgZXhwZWN0YW5jeSBvZiBsb3dlciBpbnRlcmVzdCByYXRlcyBtYXRjaGVzIHRoZSBkaXJlY3Rpb24gb2YgdGhlIHNsb3BlLiANCg0KU29tZSBvdGhlciByZWFzb25zIG1heSBiZSBwbGF1c2libGUsIHN1Y2ggYXMgdGhvc2UgcmVnYXJkaW5nIGxpcXVpZGl0eSBuZWVkcyBvciB0ZWNobmljYWwgbWFya2V0IGZhY3RvcnMsIGJ1dCB3ZSB3aWxsIG5vdCBmdXJ0aGVyIGFuYWx5emUgdGhvc2Ugb3B0aW9ucy4gDQoNCg0KIyMjIEw3LjYgRGlkIGludGVyZXN0IHJhdGVzIG1vdmUgaW4gdGhhdCBkaXJlY3Rpb24gb3ZlciB0aGUgc2Nob29sIHRlcm0/DQoNCg0KTG9hZCBwYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHh0cykNCmBgYA0KDQoNCkRlZmluZSBFbmQgb2YgVGVybSBEYXRlDQoNCmBgYHtyfQ0KI0RlZmluZSBCb1RfZGF0ZQ0KQm9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNS0wMSIpDQojIERlZmluZSBFbmQgb2YgVGVybSAoRW9UKSBkYXRlDQpFb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCmBgYA0KDQoNClJldHJpZXZlIFlpZWxkIERhdGEgT3ZlciB0aGUgdGVybQ0KDQpgYGB7cn0NCiMgUmV0cmlldmUgMTMtd2VlayBULWJpbGwgeWllbGQgZGF0YSBvdmVyIHRoZSB0ZXJtDQpnZXRTeW1ib2xzKCJUQjNNUyIsIHNyYyA9ICJGUkVEIiwgZnJvbSA9IEJvVF9kYXRlLCB0byA9IEVvVF9kYXRlKQ0KVEIzTVNfdGVybSA8LSBUQjNNUw0KDQojIFJldHJpZXZlIDI2LXdlZWsgVC1iaWxsIHlpZWxkIGRhdGEgb3ZlciB0aGUgdGVybQ0KZ2V0U3ltYm9scygiVEI2TVMiLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSwgdG8gPSBFb1RfZGF0ZSkNClRCNk1TX3Rlcm0gPC0gVEI2TVMNCmBgYA0KDQoNCkFkanVzdCB0byBOb24tVHJhZGluZyBEYXlzDQoNCmBgYHtyfQ0KIyBGdW5jdGlvbiB0byBnZXQgeWllbGQgb24gYSBzcGVjaWZpYyBkYXRlDQpnZXRfeWllbGRfb25fZGF0ZSA8LSBmdW5jdGlvbihkYXRhLCBkYXRlLCB1c2VfbmV4dCA9IEZBTFNFKSB7DQogICMgQ29udmVydCBpbmRleCB0byBEYXRlIGZvcm1hdA0KICBpbmRleChkYXRhKSA8LSBhcy5EYXRlKGluZGV4KGRhdGEpKQ0KICANCiAgaWYgKHVzZV9uZXh0KSB7DQogICAgIyBHZXQgdGhlIG5leHQgYXZhaWxhYmxlIGRhdGUgYWZ0ZXIgdGhlIHNwZWNpZmllZCBkYXRlDQogICAgYXZhaWxhYmxlX2RhdGVzIDwtIGluZGV4KGRhdGEpW2luZGV4KGRhdGEpID49IGRhdGUgJiAhaXMubmEoZGF0YVtpbmRleChkYXRhKV0pXQ0KICAgIGlmKGxlbmd0aChhdmFpbGFibGVfZGF0ZXMpID09IDApIHsNCiAgICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIGFmdGVyIiwgZGF0ZSkpDQogICAgICByZXR1cm4obGlzdChZaWVsZCA9IE5BLCBEYXRlID0gTkEpKQ0KICAgIH0NCiAgICBkYXRlX3VzZWQgPC0gbWluKGF2YWlsYWJsZV9kYXRlcykNCiAgfSBlbHNlIHsNCiAgICAjIEdldCB0aGUgbGFzdCBhdmFpbGFibGUgZGF0ZSBvbiBvciBiZWZvcmUgdGhlIHNwZWNpZmllZCBkYXRlDQogICAgYXZhaWxhYmxlX2RhdGVzIDwtIGluZGV4KGRhdGEpW2luZGV4KGRhdGEpIDw9IGRhdGUgJiAhaXMubmEoZGF0YVtpbmRleChkYXRhKV0pXQ0KICAgIGlmIChsZW5ndGgoYXZhaWxhYmxlX2RhdGVzKSA9PSAwKSB7DQogICAgICB3YXJuaW5nKHBhc3RlKCJObyBkYXRhIGF2YWlsYWJsZSBiZWZvcmUiLCBkYXRlKSkNCiAgICAgIHJldHVybihsaXN0KFlpZWxkID0gTkEsIERhdGUgPSBOQSkpDQogICAgfQ0KICAgIGRhdGVfdXNlZCA8LSBtYXgoYXZhaWxhYmxlX2RhdGVzKQ0KICB9DQogIA0KICAjIEdldCB0aGUgeWllbGQNCiAgeWllbGQgPC0gYXMubnVtZXJpYyhkYXRhW2RhdGVfdXNlZF0pDQogIA0KICByZXR1cm4obGlzdCgNCiAgICBZaWVsZCA9IHlpZWxkLA0KICAgIERhdGUgPSBhcy5EYXRlKGRhdGVfdXNlZCkNCiAgKSkNCn0NCmBgYA0KDQoNClBsb3QgdGhlIHlpZWxkcyBvdmVyIHRpbWUNCg0KYGBge3J9DQojIENvbWJpbmUgdGhlIHlpZWxkcyBpbnRvIG9uZSBkYXRhIGZyYW1lDQp5aWVsZHNfY29tYmluZWQgPC0gbWVyZ2UoVEIzTVNfdGVybSwgVEI2TVNfdGVybSkNCmNvbG5hbWVzKHlpZWxkc19jb21iaW5lZCkgPC0gYygiWWllbGRfMTN3ayIsICJZaWVsZF8yNndrIikNCg0KIyBQbG90IHRoZSB5aWVsZHMgb3ZlciB0aGUgdGVybQ0KeWllbGRzX2RmIDwtIGRhdGEuZnJhbWUoRGF0ZSA9IGluZGV4KHlpZWxkc19jb21iaW5lZCksIGNvcmVkYXRhKHlpZWxkc19jb21iaW5lZCkpDQp5aWVsZHNfZGYgPC0gbmEub21pdCh5aWVsZHNfZGYpDQoNCiMgTWVsdCB0aGUgZGF0YSBmb3IgcGxvdHRpbmcNCnlpZWxkc19tZWx0ZWQgPC0gbWVsdCh5aWVsZHNfZGYsIGlkLnZhcnMgPSAiRGF0ZSIpDQoNCiMgUGxvdA0KZ2dwbG90KHlpZWxkc19tZWx0ZWQsIGFlcyh4ID0gRGF0ZSwgeSA9IHZhbHVlLCBjb2xvciA9IHZhcmlhYmxlKSkgKw0KICBnZW9tX2xpbmUobGluZXdpZHRoID0gMSkgKw0KICBsYWJzKHRpdGxlID0gIjEzLXdlZWsgYW5kIDI2LXdlZWsgVC1iaWxsIFlpZWxkcyBPdmVyIHRoZSBUZXJtIiwNCiAgICAgICB4ID0gIkRhdGUiLA0KICAgICAgIHkgPSAiWWllbGQgKCUpIiwNCiAgICAgICBjb2xvciA9ICJZaWVsZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KDQpBbmFseXplIHRoZSBNb3ZlbWVudCBvZiBJbnRlcmVzdCBSYXRlcw0KDQpgYGB7cn0NCiNHZXQgWWllbGRzIGF0IEJvVF9kYXRlDQp5aWVsZF8xM3drIDwtIGdldF95aWVsZF9vbl9kYXRlKFRCM01TX3Rlcm0sIEJvVF9kYXRlLCB1c2VfbmV4dCA9IEZBTFNFKQ0KeWllbGRfMjZ3ayA8LSBnZXRfeWllbGRfb25fZGF0ZShUQjZNU190ZXJtLCBCb1RfZGF0ZSwgdXNlX25leHQgPSBGQUxTRSkNCg0KIyBHZXQgeWllbGRzIGF0IEVvVF9kYXRlDQp5aWVsZF8xM3drX0VvVCA8LSBnZXRfeWllbGRfb25fZGF0ZShUQjNNU190ZXJtLCBFb1RfZGF0ZSwgdXNlX25leHQgPSBGQUxTRSkNCnlpZWxkXzI2d2tfRW9UIDwtIGdldF95aWVsZF9vbl9kYXRlKFRCNk1TX3Rlcm0sIEVvVF9kYXRlLCB1c2VfbmV4dCA9IEZBTFNFKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gY29tcGFyZSBCb1QgYW5kIEVvVCB5aWVsZHMNCmNvbXBhcmlzb25fZGYgPC0gZGF0YS5mcmFtZSgNCiAgRGF0ZSA9IGMoeWllbGRfMTN3ayREYXRlLCB5aWVsZF8xM3drX0VvVCREYXRlKSwNCiAgWWllbGRfMTN3ayA9IGMoeWllbGRfMTN3ayRZaWVsZCwgeWllbGRfMTN3a19Fb1QkWWllbGQpLA0KICBZaWVsZF8yNndrID0gYyh5aWVsZF8yNndrJFlpZWxkLCB5aWVsZF8yNndrX0VvVCRZaWVsZCksDQogIFBlcmlvZCA9IGMoIkJvVCIsICJFb1QiKQ0KKQ0KDQpwcmludChjb21wYXJpc29uX2RmKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQoNCkludGVyZXN0IHJhdGVzLCBhcyB3ZSBoYXZlIHJlcHJlc2VudGVkIGdyYXBoaWNhbGx5LCB5aWVsZHMgb3ZlciB0aGUgdGVybSBoYXZlIGZhbGxlbiBwcm9ncmVzc2l2ZWx5LiBBIGRlY3JlYXNlIGluIHlpZWxkcyBpbmRpY2F0ZXMgYSBkb3dud2FyZCBtb3ZlbWVudCBpbiB0aGUgaW50ZXJlc3QgcmF0ZXMuIFRoaXMgbW92ZW1lbnQgbWF0Y2hlcyB0aGUgZXhwZWN0YXRpb24gd2UgaGFkIGV4dHJhY3RlZCBpbiB0aGUgQmVnaW5uaW5nIG9mIFRlcm0sIHdoaWNoIHdhcyB0aGUgZGVjcmVhc2UgaW4geWllbGRzL2ludGVyZXN0IHJhdGVzLiANCkZ1cnRoZXJtb3JlLCB5ZXQgYWdhaW4gd2UgaGF2ZSBsb3dlciB5aWVsZHMgaW4gdGhlIDEzLXdlZWsgdC1iaWxsLCB3aGljaCBtYXkgaW5kaWNhdGUgc3RpbGwgZnVydGhlciBkZWNyZWFzZXMgaW4gaW50ZXJlc3QgcmF0ZXMuIFRoaXMgZGF0YSBtYXRjaGVzIHdpdGggdGhlIEZFRCByYXRlIGN1dCBpbiBtaWQgU2VwdGVtYmVyLCBhbmQgdGhlIGEgcG9zaXRpdmUgZm9yZWNhc3Qgb2YgZnVydGhlciByYXRlIGN1dHMuIA0KDQoNCg0KIyMgTDcuNyAtIEw3LjkgRXhwbGFpbmluZyBzaGlmdHMgaW4gdGhlIHlpZWxkIGN1cnZlIG92ZXIgdGltZQ0KDQoNCiMjIyBMNy43IERpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbG9uZy10ZXJtIFRyZWFzdXJ5IGJvbmQgeWllbGQgYW5kIHRoZSAxMy13ZWVrIFQtYmlsbCB5aWVsZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzY2hvb2wgdGVybQ0KDQoNCkxvYWQgUGFja2FnZXMNCg0KYGBge3J9DQpsaWJyYXJ5KHF1YW50bW9kKQ0KYGBgDQoNCg0KRGVmaW5lIEJlZ2lubmluZyBvZiBUZXJtIERhdGUNCg0KYGBge3J9DQojIERlZmluZSBCZWdpbm5pbmcgb2YgVGVybSAoQm9UKSBkYXRlDQpCb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA1LTAxIikNCmBgYA0KDQoNClJldHJpZXZlIHRoZSBZaWVsZCBEYXRhDQoNCmBgYHtyfQ0KIyBSZXRyaWV2ZSAzLU1vbnRoIFQtYmlsbCB5aWVsZCBkYXRhDQpnZXRTeW1ib2xzKCJER1MzTU8iLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSAtIDcsIHRvID0gQm9UX2RhdGUgKyA3KQ0KDQojIFJldHJpZXZlIDEwLVllYXIgVHJlYXN1cnkgeWllbGQgZGF0YQ0KZ2V0U3ltYm9scygiREdTMTAiLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSAtIDcsIHRvID0gQm9UX2RhdGUgKyA3KQ0KYGBgDQoNCg0KQWRqdXN0IGZvciBOb24tVHJhZGluZyBEYXRlcw0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gdG8gZ2V0IHlpZWxkIG9uIGEgc3BlY2lmaWMgZGF0ZQ0KZ2V0X3lpZWxkX29uX2RhdGUgPC0gZnVuY3Rpb24oZGF0YSwgZGF0ZSkgew0KICAjIENvbnZlcnQgaW5kZXggdG8gRGF0ZSBmb3JtYXQNCiAgaW5kZXgoZGF0YSkgPC0gYXMuRGF0ZShpbmRleChkYXRhKSkNCiAgDQogICMgR2V0IGF2YWlsYWJsZSBkYXRlcyBvbiBvciBiZWZvcmUgdGhlIHNwZWNpZmllZCBkYXRlDQogIGF2YWlsYWJsZV9kYXRlcyA8LSBpbmRleChkYXRhKVtpbmRleChkYXRhKSA8PSBkYXRlICYgIWlzLm5hKGRhdGFbaW5kZXgoZGF0YSldKV0NCiAgDQogIGlmIChsZW5ndGgoYXZhaWxhYmxlX2RhdGVzKSA9PSAwKSB7DQogICAgd2FybmluZyhwYXN0ZSgiTm8gZGF0YSBhdmFpbGFibGUgb24gb3IgYmVmb3JlIiwgZGF0ZSkpDQogICAgcmV0dXJuKGxpc3QoWWllbGQgPSBOQSwgRGF0ZSA9IE5BKSkNCiAgfQ0KICANCiAgZGF0ZV91c2VkIDwtIG1heChhdmFpbGFibGVfZGF0ZXMpDQogIA0KICAjIEdldCB0aGUgeWllbGQNCiAgeWllbGQgPC0gYXMubnVtZXJpYyhkYXRhW2RhdGVfdXNlZF0pDQogIA0KICByZXR1cm4obGlzdCgNCiAgICBZaWVsZCA9IHlpZWxkLA0KICAgIERhdGUgPSBhcy5EYXRlKGRhdGVfdXNlZCkNCiAgKSkNCn0NCmBgYA0KDQoNClJldHJpZXZlIFlpZWxkcyBvbiBCb1RfZGF0ZQ0KDQpgYGB7cn0NCiMgR2V0IDMtTW9udGggVC1iaWxsIHlpZWxkIG9uIEJvVF9kYXRlDQp5aWVsZF8zbW9fQm9UIDwtIGdldF95aWVsZF9vbl9kYXRlKERHUzNNTywgQm9UX2RhdGUpDQoNCiMgR2V0IDEwLVllYXIgVHJlYXN1cnkgeWllbGQgb24gQm9UX2RhdGUNCnlpZWxkXzEweXJfQm9UIDwtIGdldF95aWVsZF9vbl9kYXRlKERHUzEwLCBCb1RfZGF0ZSkNCmBgYA0KDQoNCkNhbGN1bGF0ZSB0aGUgRGlmZmVyZW5jZQ0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIHRoZSB5aWVsZCBkaWZmZXJlbmNlDQp5aWVsZF9kaWZmZXJlbmNlX0JvVCA8LSB5aWVsZF8xMHlyX0JvVCRZaWVsZCAtIHlpZWxkXzNtb19Cb1QkWWllbGQNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHRvIGRpc3BsYXkgdGhlIHJlc3VsdHMNCnJlc3VsdHNfTDc3IDwtIGRhdGEuZnJhbWUoDQogIERhdGUgPSB5aWVsZF8zbW9fQm9UJERhdGUsDQogIFlpZWxkXzNtbyA9IHlpZWxkXzNtb19Cb1QkWWllbGQsDQogIFlpZWxkXzEweXIgPSB5aWVsZF8xMHlyX0JvVCRZaWVsZCwNCiAgWWllbGRfRGlmZmVyZW5jZSA9IHlpZWxkX2RpZmZlcmVuY2VfQm9UDQopDQoNCnByaW50KHJlc3VsdHNfTDc3KQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQoNClRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGxvbmctdGVybSBUcmVhc3VyeSBCb25kIFlpZWxkIGFuZCB0aGUgMTMtd2VlayB0cmVhc3VyeSBib25kIHlpZWxkIHdhcyBhIHRvdGFsIG9mIC0wLjgzLiBBIGxvd2VyIHlpZWxkIG9uIHRoZSBzaG9ydCB0ZXJtIHRyZWFzdXJ5IGJvbmQgDQoNCg0KIyMjIEw3LjguIERpZmZlcmVuY2UgQmV0d2VlbiBMb25nLVRlcm0gVHJlYXN1cnkgQm9uZCBZaWVsZCBhbmQgMTMtd2VlayBULWJpbGwgWWllbGQgYXQgRW5kIG9mIFRlcm0gDQoNCg0KRGVmaW5lIEVuZCBvZiBUZXJtIERhdGUNCg0KYGBge3J9DQojIERlZmluZSBFbmQgb2YgVGVybSAoRW9UKSBkYXRlDQpFb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCmBgYA0KDQoNClJldHJpZXZlIHRoZSBZaWVsZCBEYXRhDQoNCmBgYHtyfQ0KIyBSZXRyaWV2ZSAzLU1vbnRoIFQtYmlsbCB5aWVsZCBkYXRhDQpnZXRTeW1ib2xzKCJER1MzTU8iLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBFb1RfZGF0ZSAtIDcsIHRvID0gRW9UX2RhdGUgKyA3KQ0KDQojIFJldHJpZXZlIDEwLVllYXIgVHJlYXN1cnkgeWllbGQgZGF0YQ0KZ2V0U3ltYm9scygiREdTMTAiLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBFb1RfZGF0ZSAtIDcsIHRvID0gRW9UX2RhdGUgKyA3KQ0KYGBgDQoNCg0KQWRqdXN0IHRvIE5vbi1UcmFkaW5nIERheXMNCg0KYGBge3J9DQojIEZ1bmN0aW9uIHRvIGdldCB5aWVsZCBvbiBhIHNwZWNpZmljIGRhdGUNCmdldF95aWVsZF9vbl9kYXRlIDwtIGZ1bmN0aW9uKGRhdGEsIGRhdGUpIHsNCiAgIyBDb252ZXJ0IGluZGV4IHRvIERhdGUgZm9ybWF0DQogIGluZGV4KGRhdGEpIDwtIGFzLkRhdGUoaW5kZXgoZGF0YSkpDQogIA0KICAjIEdldCBhdmFpbGFibGUgZGF0ZXMgb24gb3IgYmVmb3JlIHRoZSBzcGVjaWZpZWQgZGF0ZQ0KICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPD0gZGF0ZSAmICFpcy5uYShkYXRhW2luZGV4KGRhdGEpXSldDQogIA0KICBpZiAobGVuZ3RoKGF2YWlsYWJsZV9kYXRlcykgPT0gMCkgew0KICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIG9uIG9yIGJlZm9yZSIsIGRhdGUpKQ0KICAgIHJldHVybihsaXN0KFlpZWxkID0gTkEsIERhdGUgPSBOQSkpDQogIH0NCiAgDQogIGRhdGVfdXNlZCA8LSBtYXgoYXZhaWxhYmxlX2RhdGVzKQ0KICANCiAgIyBHZXQgdGhlIHlpZWxkDQogIHlpZWxkIDwtIGFzLm51bWVyaWMoZGF0YVtkYXRlX3VzZWRdKQ0KICANCiAgcmV0dXJuKGxpc3QoDQogICAgWWllbGQgPSB5aWVsZCwNCiAgICBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICkpDQp9DQpgYGANCg0KDQpSZXRyaWV2ZSB0aGUgWWllbGRzIG9uIEVvVF9kYXRlDQoNCmBgYHtyfQ0KIyBHZXQgMy1Nb250aCBULWJpbGwgeWllbGQgb24gRW9UX2RhdGUNCnlpZWxkXzNtb19Fb1QgPC0gZ2V0X3lpZWxkX29uX2RhdGUoREdTM01PLCBFb1RfZGF0ZSkNCg0KIyBHZXQgMTAtWWVhciBUcmVhc3VyeSB5aWVsZCBvbiBFb1RfZGF0ZQ0KeWllbGRfMTB5cl9Fb1QgPC0gZ2V0X3lpZWxkX29uX2RhdGUoREdTMTAsIEVvVF9kYXRlKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIHRoZSBEaWZmZXJlbmNlDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIHlpZWxkIGRpZmZlcmVuY2UNCnlpZWxkX2RpZmZlcmVuY2VfRW9UIDwtIHlpZWxkXzEweXJfRW9UJFlpZWxkIC0geWllbGRfM21vX0VvVCRZaWVsZA0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gZGlzcGxheSB0aGUgcmVzdWx0cw0KcmVzdWx0c19MNzggPC0gZGF0YS5mcmFtZSgNCiAgRGF0ZSA9IHlpZWxkXzNtb19Fb1QkRGF0ZSwNCiAgWWllbGRfM21vID0geWllbGRfM21vX0VvVCRZaWVsZCwNCiAgWWllbGRfMTB5ciA9IHlpZWxkXzEweXJfRW9UJFlpZWxkLA0KICBZaWVsZF9EaWZmZXJlbmNlID0geWllbGRfZGlmZmVyZW5jZV9Fb1QNCikNCg0KcHJpbnQocmVzdWx0c19MNzgpDQpgYGANCg0KDQojIyMgTDcuOS4gRGVzY3JpYmUgSG93IHRoZSBZaWVsZCBDdXJ2ZSBDaGFuZ2VkIE92ZXIgdGhlIFNjaG9vbCBUZXJtDQoNCg0KQ29tcGFyaXNvbiBvZiBSZXN1bHRzDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHRvIGNvbXBhcmUgQm9UIGFuZCBFb1QgeWllbGRzDQpjb21wYXJpc29uX2RmIDwtIGRhdGEuZnJhbWUoDQogIERhdGUgPSBjKHlpZWxkXzNtb19Cb1QkRGF0ZSwgeWllbGRfM21vX0VvVCREYXRlKSwNCiAgWWllbGRfM21vID0gYyh5aWVsZF8zbW9fQm9UJFlpZWxkLCB5aWVsZF8zbW9fRW9UJFlpZWxkKSwNCiAgWWllbGRfMTB5ciA9IGMoeWllbGRfMTB5cl9Cb1QkWWllbGQsIHlpZWxkXzEweXJfRW9UJFlpZWxkKSwNCiAgWWllbGRfRGlmZmVyZW5jZSA9IGMoeWllbGRfZGlmZmVyZW5jZV9Cb1QsIHlpZWxkX2RpZmZlcmVuY2VfRW9UKSwNCiAgUGVyaW9kID0gYygiQm9UIiwgIkVvVCIpDQopDQoNCnByaW50KGNvbXBhcmlzb25fZGYpDQpgYGANCg0KDQpZaWVsZCBEaWZmZXJlbmNlDQoNCmBgYHtyfQ0KI1lpZWxkIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgMTAteWVhciBUcmVhc3VyeSBCb25kIGFuZCB0aGUgMy1tb250aCBULWJpbGwgaW4gQm9UX2RhdGUNCnJvdW5kKHlpZWxkX2RpZmZlcmVuY2VfQm9ULCAyKSAjRGlmZmVyZW5jZSBpbiBwZXJjZW50YWdlIHBvaW50cw0KI1lpZWxkIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgMTAteWVhciBUcmVhc3VyeSBCb25kIGFuZCB0aGUgMy1tb250aCBULWJpbGwgaW4gRW9UX2RhdGUNCnJvdW5kKHlpZWxkX2RpZmZlcmVuY2VfRW9ULCAyKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQpGcm9tIHRoZSBhbnN3ZXJzIG9mIEw3LjcgdG8gTDcuOSB3ZSBoYXZlIG9idGFpbmVkIHRoYXQgdGhlIGRpZmZlcmVuY2UgaW4geWllbGRzIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGVybSB3YXMgLTAuODMgYW5kIGF0IHRoZSBlbmQgb2YgdGVybSB3YXMgLTAuOTIuIA0KSW4gYm90aCBjYXNlcywgdGhlIGhpZ2hlciB5aWVsZCBpbiB0aGUgc2hvcnRlci10ZXJtIHRyZWFzdXJ5IGJvbmRzIGFuZCB0aGUgZGVjcmVhc2luZyB5aWVsZHMgaW5kaWNhdGUgYW4gYWNjb3JkaW5nbHkgZmFsbCBpbiB0aGUgaW50ZXJlc3QgcmF0ZXMgYW5kIGFuIGV4cGVjdGFuY3kgZm9yIGZ1cnRoZXIgZGVjcmVhc2VzIGluIGludGVyZXN0IHJhdGVzLiANCg0KTW9uZXRhcnkgcG9saWNpZXMgYW5kIG1hcmtldCBleHBlY3RhbmN5IGNydWNpYWxseSBhbHRlciB0aGUgYmVoYXZpb3VyIG9mIHRoZSBib25kIHlpZWxkcywgYXMgaW52ZXN0b3JzIHRyeSB0byBhZGFwdCB0byB0aGUgbWFya2V0IGZsdWN0dWF0aW9ucyBhbmQgcG9zaXRpb24gdGhlbXNlbHZlcyBmb3IgdGhlIGZ1dHVyZSBzaXR1YXRpb24uIFRoZSBpbnRlcmVzdCByYXRlcywgYXMgd2UgaGF2ZSBleHBsYWluZWQsIGxlYWRzIHRvIHRoZSBhY2NlcHRhbmNlIG9mIGxvd2VyIHlpZWxkcyBpbiB0aGUgbG9uZy10ZXJtIHRyZWFzdXJ5IGJvbmRzIGFzIHRoZXkgYXJlIGV4cGVjdGVkIHRvIGZhbGwgZXZlbiBtb3JlLiANCg0KDQoNCiMjIEw3LjEwIC0gTDcuMTENCg0KDQojIyMgTDcuMTAgRGlkIHRoZSBGZWQgY2hhbmdlIHRoZSBmZWRlcmFsIGZ1bmRzIHJhdGUgb3ZlciB0aGUgc2Nob29sIHRlcm0/DQoNClRvIGRldGVybWluZSBpZiB0aGVyZSB3YXMgYSBjaGFuZ2UgaW4gZmVkZXJhbCBmdW5kcyByYXRlIG92ZXIgdGhlIHNjaG9vbCB0ZXJtIHdlIGNhbiBhbmFseXplIHRoZSBkYXRhIGZyb20gaGUgRmVkZXJhbCBSZXNlcnZlIEVjb25vbWljIERhdGEgKEZSRUQpIGRhdGFiYXNlDQoNCmBgYHtyfQ0KbGlicmFyeShxdWFudG1vZCkNCg0KIyBEZWZpbmUgdGhlIHN0YXJ0IGFuZCBlbmQgZGF0ZXMNCnN0YXJ0X2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNS0wMSIpDQplbmRfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCg0KIyBHZXQgdGhlIEVmZmVjdGl2ZSBGZWRlcmFsIEZ1bmRzIFJhdGUgKGRhaWx5IGZyZXF1ZW5jeSkgZGF0YSBmcm9tIEZSRUQNCmdldFN5bWJvbHMoIkRGRiIsIHNyYyA9ICJGUkVEIikNCg0KIyBTdWJzZXQgdGhlIGRhdGEgZm9yIHRoZSBzcGVjaWZpZWQgcGVyaW9kDQpmZWRfZnVuZHNfZGFpbHkgPC0gd2luZG93KERGRiwgc3RhcnQgPSBzdGFydF9kYXRlLCBlbmQgPSBlbmRfZGF0ZSkNCg0KIyBDaGVjayBpZiBkYXRhIGlzIGF2YWlsYWJsZSBmb3IgdGhlIGVuZCBkYXRlDQppZiAoZW5kX2RhdGUgJWluJSBpbmRleChmZWRfZnVuZHNfZGFpbHkpKSB7DQogIHByaW50KCJEYXRhIGlzIGF2YWlsYWJsZSBmb3IgdGhlIGVuZCBkYXRlLiIpDQp9IGVsc2Ugew0KICBwcmludCgiRGF0YSBpcyBub3QgYXZhaWxhYmxlIGZvciB0aGUgZW5kIGRhdGUuIFVzaW5nIHRoZSBsYXN0IGF2YWlsYWJsZSBkYXRlLiIpDQogIGFjdHVhbF9lbmRfZGF0ZSA8LSB0YWlsKGluZGV4KGZlZF9mdW5kc19kYWlseSksIDEpDQogIHByaW50KHBhc3RlKCJMYXN0IGF2YWlsYWJsZSBkYXRlIGluIGRhdGE6IiwgYWN0dWFsX2VuZF9kYXRlKSkNCn0NCg0KIyBQbG90IHRoZSBkYXRhIHdpdGggYWRqdXN0ZWQgeS1heGlzIGxpbWl0cw0KbWluX3JhdGUgPC0gbWluKGZlZF9mdW5kc19kYWlseSwgbmEucm0gPSBUUlVFKQ0KbWF4X3JhdGUgPC0gbWF4KGZlZF9mdW5kc19kYWlseSwgbmEucm0gPSBUUlVFKQ0KeV9taW4gPC0gbWluX3JhdGUgLSAwLjAxICAjIFN1YnRyYWN0aW5nIDAuMDElDQp5X21heCA8LSBtYXhfcmF0ZSArIDAuMDEgICMgQWRkaW5nIDAuMDElDQoNCnBsb3QoZmVkX2Z1bmRzX2RhaWx5LCB0eXBlID0gIm8iLCBwY2ggPSAyMCwgY29sID0gImJsdWUiLA0KICAgICBtYWluID0gIkVmZmVjdGl2ZSBGZWRlcmFsIEZ1bmRzIFJhdGUgKE1heSAyMDIzIC0gU2VwdGVtYmVyIDIwMjMpIiwNCiAgICAgeWxhYiA9ICJJbnRlcmVzdCBSYXRlICglKSIsIHlsaW0gPSBjKHlfbWluLCB5X21heCkpDQpncmlkKCkNCg0KYGBgDQoNCg0KVGhlIEZlZCBsb3dlcmVkIHRoZSB0YXJnZXQgcmF0ZSBpbiByZXNwb25zZSB0byBlY29ub21pYyBjb25kaXRpb25zIHRoYXQgd2FycmFudGVkIGEgbW9yZSBhY2NvbW1vZGF0aXZlIG1vbmV0YXJ5IHBvbGljeS4gVGhpcyBjaGFuZ2Ugd2FzIGFpbWVkIGF0IHN0aW11bGF0aW5nIGVjb25vbWljIGFjdGl2aXR5IGFtaWQgc2lnbnMgb2Ygc2xvd2luZyBncm93dGgsIGRlY2xpbmluZyBpbmZsYXRpb24sIG9yIG90aGVyIGZpbmFuY2lhbCBjaGFsbGVuZ2VzIGZhY2luZyB0aGUgZWNvbm9teSBkdXJpbmcgdGhhdCBwZXJpb2QuDQoNCg0KIyMjIEw3LjExIERvIHlvdSB0aGluayB0aGUgbW92ZW1lbnRzIGluIGludGVyZXN0IHJhdGVzIG92ZXIgdGhlIHNjaG9vbCB0ZXJtIHdlcmUgY2F1c2VkIGJ5IHRoZSBGZWTigJlzIG1vbmV0YXJ5IHBvbGljeT8gRXhwbGFpbi4NCg0KWWVzLCB0aGUgbW92ZW1lbnRzIGluIGludGVyZXN0IHJhdGVzIG92ZXIgdGhlIHNjaG9vbCB0ZXJtIHdlcmUgc2lnbmlmaWNhbnRseSBpbmZsdWVuY2VkIGJ5IHRoZSBGZWTigJlzIG1vbmV0YXJ5IHBvbGljeSBhY3Rpb25zLiBIZXJlJ3Mgd2h5Og0KDQojIyMjIERpcmVjdCBJbXBhY3Qgb2YgZmVkIHJhdGVzDQpTaG9ydC10ZXJtIHJhdGVzIHJlZHVjZWQuDQpFeHBhbnNpb25hcnkgbW9uZXRhcnkgcG9saWN5LiANCg0KIyMjIyBNYXJrZXQgZXhwZWN0YXRpb25zIGFuZCBSZWFjdGlvbnMNCg0KIyMjIyBUcmFuc21pc3Npb24gdG8gTG9uZ2VyLVRlcm0gUmF0ZXMNCg0KWWllbGQgQ3VydmUgRWZmZWN0czogQSByYXRlIGN1dCBjYW4gbGVhZCB0byBsb3dlciB5aWVsZHMgb24gbWVkaXVtIGFuZCBsb25nLXRlcm0gc2VjdXJpdGllcyBhcyBpbnZlc3RvcnMgYWRqdXN0IHRoZWlyIHBvcnRmb2xpb3MgaW4gcmVzcG9uc2UgdG8gdGhlIG5ldyByYXRlIGVudmlyb25tZW50Lg0KDQpJbmZsYXRpb24gRXhwZWN0YXRpb25zOiBMb3dlciBpbnRlcmVzdCByYXRlcyBjYW4gaW5mbHVlbmNlIGV4cGVjdGF0aW9ucyBvZiBmdXR1cmUgaW5mbGF0aW9uLCB3aGljaCBpbiB0dXJuIGFmZmVjdCBsb25nLXRlcm0gaW50ZXJlc3QgcmF0ZXMuDQoNCiMjIyMgRWNvbm9taWMgSW5kaWNhdG9ycw0KU3RpbXVsYXRpbmcgQm9ycm93aW5nIGFuZCBTcGVuZGluZw0KRGVjbGluaW5nIGluZHVzdHJpYWwgcHJvZHVjdGlvbiBhbmQgY29uc3VtZXIgc3BlbmRpbmcNCg0KIyMjIyBHTG9iYWwgRWNvbm9taWMgRmFjdG9ycw0KR2xvYmFsIGVjb25vbWljIHNsb3dkb3ducyBjYW4gcHJvbXB0IGxvd2VyIHJhdGVzLiANCg0KDQojIyBMNy4xMiAtIEw3LjEzDQoNCiMjIyBMNy4xMiBEaWZmZXJlbmNlIEJldHdlZW4gOTAtRGF5IENvbW1lcmNpYWwgUGFwZXIgWWllbGQgYW5kIDEzLXdlZWsgVC1iaWxsIFlpZWxkIGF0IEVuZCBvZiBUZXJtDQoNCg0KTG9hZCBwYWNrYWdlcw0KDQpgYGB7cn0NCmxpYnJhcnkocXVhbnRtb2QpDQpgYGANCg0KDQpEZWZpbmUgdGhlIEJlZ2lubmluZyBhbmQgRW5kIG9mIFRlcm0gRGF0ZXMNCg0KYGBge3J9DQojIERlZmluZSBCZWdpbm5pbmcgb2YgVGVybSAoQm9UKSBhbmQgRW5kIG9mIFRlcm0gKEVvVCkgZGF0ZXMNCkJvVF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMDUtMDEiKQ0KRW9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wOS0zMCIpDQpgYGANCg0KDQpSZXRyaWV2ZSBZaWVsZCBEYXRhDQoNCmBgYHtyfQ0KIyBSZXRyaWV2ZSAzLU1vbnRoIENvbW1lcmNpYWwgUGFwZXIgeWllbGQgZGF0YQ0KZ2V0U3ltYm9scygiQ1BGM00iLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSAtIDcsIHRvID0gRW9UX2RhdGUgKyA3KQ0KDQojIFJldHJpZXZlIDMtTW9udGggVHJlYXN1cnkgQ29uc3RhbnQgTWF0dXJpdHkgUmF0ZSBkYXRhDQpnZXRTeW1ib2xzKCJER1MzTU8iLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSAtIDcsIHRvID0gRW9UX2RhdGUgKyA3KQ0KDQpgYGANCg0KDQpBZGp1c3QgdG8gTm9uLVRyYWRpbmcgRGF5cw0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gdG8gZ2V0IHlpZWxkIG9uIGEgc3BlY2lmaWMgZGF0ZQ0KZ2V0X3lpZWxkX29uX2RhdGUgPC0gZnVuY3Rpb24oZGF0YSwgZGF0ZSkgew0KICAjIENvbnZlcnQgaW5kZXggdG8gRGF0ZSBmb3JtYXQNCiAgaW5kZXgoZGF0YSkgPC0gYXMuRGF0ZShpbmRleChkYXRhKSkNCiAgDQogICMgR2V0IGF2YWlsYWJsZSBkYXRlcyBvbiBvciBiZWZvcmUgdGhlIHNwZWNpZmllZCBkYXRlDQogIGF2YWlsYWJsZV9kYXRlcyA8LSBpbmRleChkYXRhKVtpbmRleChkYXRhKSA8PSBkYXRlICYgIWlzLm5hKGRhdGFbaW5kZXgoZGF0YSldKV0NCiAgDQogIGlmIChsZW5ndGgoYXZhaWxhYmxlX2RhdGVzKSA9PSAwKSB7DQogICAgd2FybmluZyhwYXN0ZSgiTm8gZGF0YSBhdmFpbGFibGUgb24gb3IgYmVmb3JlIiwgZGF0ZSkpDQogICAgcmV0dXJuKGxpc3QoWWllbGQgPSBOQSwgRGF0ZSA9IE5BKSkNCiAgfQ0KICANCiAgZGF0ZV91c2VkIDwtIG1heChhdmFpbGFibGVfZGF0ZXMpDQogIA0KICAjIEdldCB0aGUgeWllbGQNCiAgeWllbGQgPC0gYXMubnVtZXJpYyhkYXRhW2RhdGVfdXNlZF0pDQogIA0KICByZXR1cm4obGlzdCgNCiAgICBZaWVsZCA9IHlpZWxkLA0KICAgIERhdGUgPSBhcy5EYXRlKGRhdGVfdXNlZCkNCiAgKSkNCn0NCmBgYA0KDQoNClJldHJpZXZlIFlpZWxkcyBvbiBFb1RfZGF0ZQ0KDQpgYGB7cn0NCiMgR2V0IDkwLURheSBDb21tZXJjaWFsIFBhcGVyIHlpZWxkIG9uIEVvVF9kYXRlDQp5aWVsZF9DUF9Fb1QgPC0gZ2V0X3lpZWxkX29uX2RhdGUoQ1BGM00sIEVvVF9kYXRlKQ0KDQojIEdldCAxMy13ZWVrIFQtYmlsbCB5aWVsZCBvbiBFb1RfZGF0ZQ0KeWllbGRfVEJpbGxfRW9UIDwtIGdldF95aWVsZF9vbl9kYXRlKERHUzNNTywgRW9UX2RhdGUpDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIFByZW1pdW0gYXQgRW9UDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIHlpZWxkIHByZW1pdW0NCnByZW1pdW1fRW9UIDwtIHlpZWxkX0NQX0VvVCRZaWVsZCAtIHlpZWxkX1RCaWxsX0VvVCRZaWVsZA0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gZGlzcGxheSB0aGUgcmVzdWx0cw0KcmVzdWx0c19MNzEyIDwtIGRhdGEuZnJhbWUoDQogIERhdGUgPSB5aWVsZF9UQmlsbF9Fb1QkRGF0ZSwNCiAgWWllbGRfQ29tbWVyY2lhbF9QYXBlciA9IHlpZWxkX0NQX0VvVCRZaWVsZCwNCiAgWWllbGRfVF9CaWxsID0geWllbGRfVEJpbGxfRW9UJFlpZWxkLA0KICBQcmVtaXVtID0gcHJlbWl1bV9Fb1QNCikNCg0KcHJpbnQocmVzdWx0c19MNzEyKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQpJbiB0aGlzIGV4ZXJjaXNlIHdlIGFyZSBjb21wYXJpbmcgdGhlIHlpZWxkcyBvZiBhIGNvbW1lcmNpYWwgcGFwZXIgYWdhaW5zdCBhIFQtYmlsbC4gQXMgd2UgaGF2ZSBhbHJlYWR5IGV4cGxhaW5lZCBwcmV2aW91cyBzZWN0aW9ucywgdGhlIFQtYmlsbHMgYXJlIGlzc3VlZCBieSB0aGUgVVMgZ292ZXJubWVudCBhbmQgYXJlIGNvbnNpZGVyZWQgcmlzay1mcmVlLiBHaXZlbiB0aGF0IHRoZSBjb21tZXJjaWFsIHBhcGVycyBkbyBub3Qgb2ZmZXIgc3VjaCBhIHNhZmUgcmlzayBwcm9maWxlLCB0aGUgaGlnaGVyIHJpc2sgbXVzdCBiZSBjb21wZW5zYXRlZCB3aXRoIGhpZ2hlciB5aWVsZHMuIFRoaXMgcHJlbWl1bSBtYXkgZmx1Y3R1YXRlIGdpdmVuIHNvbWUgZWNvbm9taWMgZmFjdG9ycyByZWxhdGVkIHRvIHN0YWJpbGl0eSBhbmQgdW5jZXJ0YWludHkuIA0KDQoNCg0KIyMjIEw3LjEzIENvbXBhcmUgdGhlIFByZW1pdW0gYXQgQmVnaW5uaW5nIGFuZCBFbmQgb2YgVGVybQ0KDQoNClJldHJpZXZlIHRoZSBZaWVsZHMgb24gQm9UX2RhdGUNCg0KYGBge3J9DQojIEdldCA5MC1EYXkgQ29tbWVyY2lhbCBQYXBlciB5aWVsZCBvbiBCb1RfZGF0ZQ0KeWllbGRfQ1BfQm9UIDwtIGdldF95aWVsZF9vbl9kYXRlKENQRjNNLCBCb1RfZGF0ZSkNCg0KIyBHZXQgMTMtd2VlayBULWJpbGwgeWllbGQgb24gQm9UX2RhdGUNCnlpZWxkX1RCaWxsX0JvVCA8LSBnZXRfeWllbGRfb25fZGF0ZShER1MzTU8sIEJvVF9kYXRlKQ0KDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIFByZW1pdW0gYXQgQm9UDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIHlpZWxkIHByZW1pdW0gYXQgQm9UDQpwcmVtaXVtX0JvVCA8LSB5aWVsZF9DUF9Cb1QkWWllbGQgLSB5aWVsZF9UQmlsbF9Cb1QkWWllbGQNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHRvIGRpc3BsYXkgdGhlIHJlc3VsdHMNCnJlc3VsdHNfTDcxMyA8LSBkYXRhLmZyYW1lKA0KICBEYXRlID0geWllbGRfVEJpbGxfQm9UJERhdGUsDQogIFlpZWxkX0NvbW1lcmNpYWxfUGFwZXIgPSB5aWVsZF9DUF9Cb1QkWWllbGQsDQogIFlpZWxkX1RfQmlsbCA9IHlpZWxkX1RCaWxsX0JvVCRZaWVsZCwNCiAgUHJlbWl1bSA9IHByZW1pdW1fQm9UDQopDQoNCnByaW50KHJlc3VsdHNfTDcxMykNCmBgYA0KDQoNCkNvbXBhcmUgdGhlIFByZW1pdW1zDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBjb21wYXJpc29uIGRhdGEgZnJhbWUNCmNvbXBhcmlzb25fcHJlbWl1bXMgPC0gZGF0YS5mcmFtZSgNCiAgRGF0ZSA9IGMoeWllbGRfVEJpbGxfQm9UJERhdGUsIHlpZWxkX1RCaWxsX0VvVCREYXRlKSwNCiAgUGVyaW9kID0gYygiQm9UIiwgIkVvVCIpLA0KICBZaWVsZF9Db21tZXJjaWFsX1BhcGVyID0gYyh5aWVsZF9DUF9Cb1QkWWllbGQsIHlpZWxkX0NQX0VvVCRZaWVsZCksDQogIFlpZWxkX1RfQmlsbCA9IGMoeWllbGRfVEJpbGxfQm9UJFlpZWxkLCB5aWVsZF9UQmlsbF9Fb1QkWWllbGQpLA0KICBQcmVtaXVtID0gYyhwcmVtaXVtX0JvVCwgcHJlbWl1bV9Fb1QpDQopDQoNCnByaW50KGNvbXBhcmlzb25fcHJlbWl1bXMpDQpgYGANCg0KDQpDaGFuZ2UgaW4gUHJlbWl1bQ0KDQpgYGB7cn0NCiNQcmVtaXVtIGluY3JlYXNlL2RlY3JlYXNlIGluICUgcG9pbnRzDQpwcmVtaXVtX2NoYW5nZSA8LSByb3VuZChwcmVtaXVtX0JvVCwgMikgLSByb3VuZChwcmVtaXVtX0VvVCwgMikNCnByaW50KHByZW1pdW1fY2hhbmdlKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQoNCkluIHRoaXMgZXhlcmNpc2Ugd2UgaGF2ZSB0YWtlbiB0aGUgcHJlbWl1bXMgYXQgQm9UIGFuZCBFb1QgYW5kIHdlIGhhdmUgcG9ydHJheWVkIHRoZSBjb21wYXJpc29uIGluIGEgZGF0YS5mcmFtZS4gDQpGcm9tIHRoZSByZXN1bHRzLCB3ZSBoYXZlIG9ic2VydmVkIHRoYXQgYm90aCB5aWVsZHMgaGF2ZSBkZWNyZWFzZWQgb3ZlciB0aW1lLiBIb3dldmVyLCB0aGUgY29ycG9yYXRlIHlpZWxkIGhhcyBkZWNyZWFzZWQgbGVzcyB0aGFuIHRoZSBULWJpbGwsIHdoaWNoIGhhcyBsZWQgdG8gYSBmaW5hbCBwcmVtaXVtIG9mIDAuMTMgaW4gZmF2b3VyIGZvciB0aGUgY29tbWVyY2lhbCBwYXBlci4gVGhlc2UgZWZmZWN0cyBtYXkgaGF2ZSBiZWVuIGNhdXNlZCBieSBwb3NpdGl2ZSByZXN1bHRzIGFuZCB0aGUgYWxyZWFkeSBzdHVkaWVkIGRlY3JlYXNlIGluIGludGVyZXN0IHJhdGVzIHRoYXQgY2F1c2VkIHRoZSBkZWNyZWFzZSBvZiB0aGUgdC1iaWxsIHlpZWxkcy4gDQpXZSBtdXN0IG1lbnRpb24gdGhhdCB0aGUgaW5pdGlhbCBzaXR1YXRpb24sIGluIHdoaWNoIHRoZSBULWJpbGwgeWllbGQgaXMgaGlnaGVyIHRoYW4gdGhlIGNvbW1lcmNpYWwgcGFwZXIgaXMgYWJub3JtYWwsIGFzIHVzdWFsbHkgdC1iaWxsIHlpZWxkcyBjb250YWluIGEgbG93IHJpc2sgcHJvZmlsZSBhbmQgZ2VuZXJhbGx5IGxvd2VyIHRoYW4gdGhlIGNvbW1lcmNpYWwgeWllbGRzLCB3aGljaCBvZmZlciBoaWdoZXIgeWllbGRzIGFuZCBoaWdoZXIgcmlzay4gDQoNCg0KDQojIyBMNy4xNCB0byBMNy4xNw0KDQoNCkRlZmluZSBCZWdpbm5pbmcgYW5kIEVuZCBvZiBUZXJtIGRhdGVzDQoNCmBgYHtyfQ0KIyBEZWZpbmUgQmVnaW5uaW5nIG9mIFRlcm0gKEJvVCkgYW5kIEVuZCBvZiBUZXJtIChFb1QpIGRhdGVzDQpCb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDIzLTA1LTAxIikNCkVvVF9kYXRlIDwtIGFzLkRhdGUoIjIwMjMtMDktMzAiKQ0KYGBgDQoNCg0KIyMjIEw3LjE0LiBEaWZmZXJlbmNlIEJldHdlZW4gWWllbGRzIG9uIEhpZ2gtWWllbGQgYW5kIEhpZ2gtUXVhbGl0eSBDb3Jwb3JhdGUgQm9uZHMNCg0KDQpMb2FkIHBhY2thZ2VzDQoNCmBgYHtyfQ0KbGlicmFyeShxdWFudG1vZCkNCmBgYA0KDQoNClJldHJpZXZlIFlpZWxkIERhdGENCg0KYGBge3J9DQojIFJldHJpZXZlIE1vb2R5J3MgQWFhIENvcnBvcmF0ZSBCb25kIFlpZWxkIChIaWdoLVF1YWxpdHkpDQpnZXRTeW1ib2xzKCJEQUFBIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gQm9UX2RhdGUgLSA3LCB0byA9IEJvVF9kYXRlICsgNykNCg0KIyBSZXRyaWV2ZSBJQ0UgQm9mQSBVUyBIaWdoIFlpZWxkIEluZGV4IEVmZmVjdGl2ZSBZaWVsZCAoSGlnaC1ZaWVsZCkNCmdldFN5bWJvbHMoIkJBTUxIMEEwSFlNMkVZIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gRW9UX2RhdGUgLSA3LCB0byA9IEVvVF9kYXRlICsgNykNCmBgYA0KDQoNCkRlZmluZSBhIEZ1bmN0aW9uIHRvIEdldCBZaWVsZHMgb24gU3BlY2lmaWMgRGF0ZXMNCg0KYGBge3J9DQojIEZ1bmN0aW9uIHRvIGdldCB5aWVsZCBvbiBhIHNwZWNpZmljIGRhdGUNCmdldF95aWVsZF9vbl9kYXRlIDwtIGZ1bmN0aW9uKGRhdGEsIGRhdGUpIHsNCiAgIyBDb252ZXJ0IGluZGV4IHRvIERhdGUgZm9ybWF0DQogIGluZGV4KGRhdGEpIDwtIGFzLkRhdGUoaW5kZXgoZGF0YSkpDQogIA0KICAjIEdldCBhdmFpbGFibGUgZGF0ZXMgb24gb3IgYmVmb3JlIHRoZSBzcGVjaWZpZWQgZGF0ZQ0KICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPD0gZGF0ZSAmICFpcy5uYShkYXRhW2luZGV4KGRhdGEpXSldDQogIA0KICBpZiAobGVuZ3RoKGF2YWlsYWJsZV9kYXRlcykgPT0gMCkgew0KICAgIHdhcm5pbmcocGFzdGUoIk5vIGRhdGEgYXZhaWxhYmxlIG9uIG9yIGJlZm9yZSIsIGRhdGUpKQ0KICAgIHJldHVybihsaXN0KFlpZWxkID0gTkEsIERhdGUgPSBOQSkpDQogIH0NCiAgDQogIGRhdGVfdXNlZCA8LSBtYXgoYXZhaWxhYmxlX2RhdGVzKQ0KICANCiAgIyBHZXQgdGhlIHlpZWxkDQogIHlpZWxkIDwtIGFzLm51bWVyaWMoZGF0YVtkYXRlX3VzZWRdKQ0KICANCiAgcmV0dXJuKGxpc3QoDQogICAgWWllbGQgPSB5aWVsZCwNCiAgICBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICkpDQp9DQpgYGANCg0KDQpSZXRyaWV2ZSBEYXRhIG9uIFNwZWNpZmljIERhdGVzDQoNCmBgYHtyfQ0KIyBHZXQgSGlnaC1RdWFsaXR5IENvcnBvcmF0ZSBCb25kIFlpZWxkIG9uIEJvVF9kYXRlDQp5aWVsZF9IUV9Cb1QgPC0gZ2V0X3lpZWxkX29uX2RhdGUoREFBQSwgQm9UX2RhdGUpDQoNCiMgR2V0IEhpZ2gtWWllbGQgQ29ycG9yYXRlIEJvbmQgWWllbGQgb24gRW9UX2RhdGUNCnlpZWxkX0hZX0VvVCA8LSBnZXRfeWllbGRfb25fZGF0ZShCQU1MSDBBMEhZTTJFWSwgRW9UX2RhdGUpDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIERpZmZlcmVuY2UNCg0KWWllbGQgZGlmZmVyZW5jZSByZXByZXNlbnRzIHRoZSBjaGFuZ2UgYmV0d2VlbiB0aGUgaGlnaC15aWVsZCBjb3Jwb3JhdGUgYm9uZCB5aWVsZCBhdCB0aGUgZW5kIG9mIHRoZSB0ZXJtIGFuZCB0aGUgaGlnaC1xdWFsaXR5IGNvcnBvcmF0ZSBib25kIHlpZWxkIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIHRlcm0NCg0KQSBwb3NpdGl2ZSBkaWZmZXJlbmNlIGluZGljYXRlcyB0aGF0IHRoZSBoaWdoLXlpZWxkIGJvbmQgeWllbGQgYXQgRW9UIGlzIGhpZ2hlciB0aGFuIHRoZSBoaWdoLXF1YWxpdHkgYm9uZCB5aWVsZCBhdCBCb1QNCg0KYGBge3J9DQojIENhbGN1bGF0ZSB0aGUgeWllbGQgZGlmZmVyZW5jZQ0KeWllbGRfZGlmZmVyZW5jZV9MNzE0IDwtIHlpZWxkX0hZX0VvVCRZaWVsZCAtIHlpZWxkX0hRX0JvVCRZaWVsZA0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gZGlzcGxheSB0aGUgcmVzdWx0cw0KcmVzdWx0c19MNzE0IDwtIGRhdGEuZnJhbWUoDQogIERlc2NyaXB0aW9uID0gYygiSGlnaC1RdWFsaXR5IENvcnBvcmF0ZSBCb25kIFlpZWxkIGF0IEJvVCIsICJIaWdoLVlpZWxkIENvcnBvcmF0ZSBCb25kIFlpZWxkIGF0IEVvVCIpLA0KICBEYXRlID0gYyh5aWVsZF9IUV9Cb1QkRGF0ZSwgeWllbGRfSFlfRW9UJERhdGUpLA0KICBZaWVsZCA9IGMoeWllbGRfSFFfQm9UJFlpZWxkLCB5aWVsZF9IWV9Fb1QkWWllbGQpDQopDQoNCnByaW50KHJlc3VsdHNfTDcxNCkNCmNhdCgiWWllbGQgRGlmZmVyZW5jZSAoSGlnaC1ZaWVsZCAtIEhpZ2gtUXVhbGl0eSk6Iiwgcm91bmQoeWllbGRfZGlmZmVyZW5jZV9MNzE0LCAyKSwgIiVcbiIpDQpgYGANCg0KDQojIyMjIEFuYWx5c2lzIG9mIHJlc3VsdHMNCg0KV2UgY2FuIG9ic2VydmUgYSBkaWZmZXJlbmNlIG9mIDQuMTkgd2hpY2ggcmVmbGVjdHMgdGhhdCB0aGUgaGlnaC15aWVsZCB3aWxsIHJlc3VsdCBpbiBoaWdoZXIgcmV0dXJucyBjb21wYXJlZCB0byB0aGUgaGlnaCBxdWFsaXR5LiBUaGlzIHJlc3VsdHMgYXJlIGV4cGxhaW5lZCBkdWUgdG8gdGhlIGFscmVhZHkgZXhwbGFpbmVkIGR5bmFtaWNzIGluIHdoaWNoIHRoZSByaXNraWVyIHRoZSBpbnZlc3RtZW50LCB0aGUgaGlnaGVyIGl0cyByZXR1cm4gd2lsbCBiZS4gSW4gdGhlIGhpZ2gtcXVhbGl0eSBib25kcyB3ZSBwcmlvcml0aXplIG1pbmltaXppbmcgdGhlIHJpc2sgYXQgZXhwZW5zZSBvZiBhIGxvd2VyIHlpZWxkLCB3aGVyZWFzIGluIHRoZSBoaWdoLXlpZWxkIHdlIHdpbGwgYWNjZXB0IGEgaGlnaGVyIHJpc2sgZm9yIGEgaGlnaGVyIGV4cGVjdGVkIHJldHVybi4gDQoNCg0KDQojIyMgTDcuMTUgQ2hhbmdlIGluIExvbmctVGVybSBUcmVhc3VyeSBCb25kIFlpZWxkIGFuZCBJbXBhY3Qgb24gQm9uZCBQcmljZXMNCg0KDQpSZXRyaWV2ZSBZaWVsZCBEYXRhDQoNCmBgYHtyfQ0KIyBSZXRyaWV2ZSAxMC1ZZWFyIFRyZWFzdXJ5IFlpZWxkIGRhdGENCmdldFN5bWJvbHMoIkRHUzEwIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gQm9UX2RhdGUgLSA3LCB0byA9IEVvVF9kYXRlICsgNykNCmBgYA0KDQoNClJldHJpZXZlIFlpZWxkcyBvbiBTcGVjaWZpZWQgRGF0ZXMNCg0KYGBge3J9DQojIEdldCAxMC1ZZWFyIFRyZWFzdXJ5IFlpZWxkIG9uIEJvVF9kYXRlDQp5aWVsZF8xMHlyX0JvVCA8LSBnZXRfeWllbGRfb25fZGF0ZShER1MxMCwgQm9UX2RhdGUpDQoNCiMgR2V0IDEwLVllYXIgVHJlYXN1cnkgWWllbGQgb24gRW9UX2RhdGUNCnlpZWxkXzEweXJfRW9UIDwtIGdldF95aWVsZF9vbl9kYXRlKERHUzEwLCBFb1RfZGF0ZSkNCmBgYA0KDQoNCkNhbGN1bGF0ZSB0aGUgQ2hhbmdlIGluIFlpZWxkDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIGNoYW5nZSBpbiB5aWVsZA0KeWllbGRfY2hhbmdlX0w3MTUgPC0geWllbGRfMTB5cl9Fb1QkWWllbGQgLSB5aWVsZF8xMHlyX0JvVCRZaWVsZA0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgdG8gZGlzcGxheSB0aGUgcmVzdWx0cw0KcmVzdWx0c19MNzE1IDwtIGRhdGEuZnJhbWUoDQogIERhdGUgPSBjKHlpZWxkXzEweXJfQm9UJERhdGUsIHlpZWxkXzEweXJfRW9UJERhdGUpLA0KICBQZXJpb2QgPSBjKCJCb1QiLCAiRW9UIiksDQogIFlpZWxkXzEweXJfVHJlYXN1cnkgPSBjKHlpZWxkXzEweXJfQm9UJFlpZWxkLCB5aWVsZF8xMHlyX0VvVCRZaWVsZCkNCikNCg0KcHJpbnQocmVzdWx0c19MNzE1KQ0KY2F0KCJDaGFuZ2UgaW4gMTAtWWVhciBUcmVhc3VyeSBZaWVsZCAoRW9UIC0gQm9UKToiLCByb3VuZCh5aWVsZF9jaGFuZ2VfTDcxNSwgMiksICIlXG4iKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQoNClRoZSBib25kIHByaWNlcyBmb2xsb3cgYW4gaW52ZXJzZSByZWxhdGlvbnNoaXAgd2l0aCB0aGUgYm9uZCB5aWVsZHMuIFRoZXJlZm9yZSwgYXMgd2UgaGF2ZSBjYWxjdWxhdGVkIGFuIGFwcHJlY2lhdGlvbiBpbiB0aGUgeWllbGQgb2YgYSAxJSwgd2UgbWF5IGRlcml2ZSB0aGF0IHRoZSBwcmljZSBoYXMgZGVjcmVhc2VkIG92ZXIgdGhlIHRlcm0uICANCg0KIyMjIEw3LjE2IENvbXBhcmluZyBDaGFuZ2VzIGluIFlpZWxkcyBvZiBUcmVhc3VyeSwgTXVuaWNpcGFsLCBhbmQgQ29ycG9yYXRlIEJvbmRzDQoNCg0KUmV0cmlldmUgWWllbGQgRGF0YQ0KDQpgYGB7cn0NCiMgUmV0cmlldmUgVHJlYXN1cnkgWWllbGQgZGF0YQ0KZ2V0U3ltYm9scygiREdTMTAiLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSAtIDcsIHRvID0gRW9UX2RhdGUgKyA3KQ0KDQojIFJldHJpZXZlIENvcnBvcmF0ZSBCb25kIFlpZWxkIGRhdGENCmdldFN5bWJvbHMoIkRBQUEiLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSAtIDcsIHRvID0gRW9UX2RhdGUgKyA3KQ0KDQojIEF0dGVtcHQgdG8gUmV0cmlldmUgTXVuaWNpcGFsIEJvbmQgWWllbGQgZGF0YQ0KIyBOb3RlOiBNdW5pY2lwYWwgYm9uZCBkYXRhIGlzIGxpbWl0ZWQgb24gRlJFRDsgd2UgbWF5IG5lZWQgdG8gdXNlIGF2YWlsYWJsZSBwcm94aWVzIG9yIGFja25vd2xlZGdlIGxpbWl0YXRpb25zLg0KI2dldFN5bWJvbHMoIk1VTkkxMFkiLCBzcmMgPSAiRlJFRCIsIGZyb20gPSBCb1RfZGF0ZSAtIDcsIHRvID0gRW9UX2RhdGUgKyA3KSAjV0UgQVJFIE5PVCBBQkxFIFRPIEZJTkQgQU5ZIERBVEEgT04gTVVOSUNJUEFMIEJPTkRTDQoNCg0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcyBvZiByZXN1bHRzDQpBcyB3ZSBoYXZlIG1lbnRpb25lZCBlYXJsaWVyLCB3ZSBoYXZlIGZvdW5kIGNlcnRhaW4gaXNzdWVkIHRvIHJldHJpZXZlIG11bmljaXBhbCBib25kcyBkYXRhLiBIb3dldmVyLCB3ZSBjYW4gZGV0ZXJtaW5lIGZyb20gd2hhdCBoYXMgYmVlbiBhbmFseXplZCBzbyBmYXIgaW4gcHJldmlvdXMgYW5zd2VycyB0aGF0IGJvbmQgeWllbGRzIGhhdmUgZmFsbGVuIG92ZXIgdGhlIGNvdXJzZSBvZiB0aGUgc2Nob29sIHRlcm0sIHByaW1hcmlseSBkdWUgdG8gdGhlIGZhbGwgaW4gaW50ZXJlc3QgcmF0ZXMgYW5kIHRoZSBleHBlY3RhbmN5IG9mIGZ1cnRoZXIgcmF0ZSBjdXRzLiBPdGhlciBmYWN0b3JzIHN1Y2ggYXMgaW5mbGF0aW9uIGFuZCBvdmVyYWxsIGVjb25vbWljIGNvbmRpdGlvbnMgYWxzbyBhZmZlY3QgdGhpcyBtb3ZlbWVudHMuIA0KDQoNCiMjIyBMNy4xNyBDaGFuZ2UgaW4gUHJlbWl1bSBvbiBIaWdoLVlpZWxkIENvcnBvcmF0ZSBCb25kcyBSZWxhdGl2ZSB0byBUcmVhc3VyeSBCb25kcw0KDQoNClJldHJpZXZlIEhpZ2ggWWllbGQgQ29ycG9yYXRlIEJvbmQgWWllbGQgb24gQm9UX2RhdGUNCg0KYGBge3J9DQojIFJldHJpZXZlIEhpZ2gtWWllbGQgQ29ycG9yYXRlIEJvbmQgWWllbGQgZGF0YSBmb3IgQm9UX2RhdGUNCmdldFN5bWJvbHMoIkJBTUxIMEEwSFlNMkVZIiwgc3JjID0gIkZSRUQiLCBmcm9tID0gQm9UX2RhdGUgLSA3LCB0byA9IEJvVF9kYXRlICsgNykNCg0KIyBHZXQgSGlnaC1ZaWVsZCBDb3Jwb3JhdGUgQm9uZCBZaWVsZCBvbiBCb1RfZGF0ZQ0KeWllbGRfSFlfQm9UIDwtIGdldF95aWVsZF9vbl9kYXRlKEJBTUxIMEEwSFlNMkVZLCBCb1RfZGF0ZSkNCiNHZXQgWWllbGQgb24gVHJlYXN1cnkgYm9uZCBvbiBCb1RfZGF0ZSBhbmQgRW9UX2RhdGUNCnlpZWxkX1RyZWFzdXJ5X0JvVCA8LSBnZXRfeWllbGRfb25fZGF0ZShER1MxMCwgQm9UX2RhdGUpDQp5aWVsZF9UcmVhc3VyeV9Fb1QgPC0gZ2V0X3lpZWxkX29uX2RhdGUoREdTMTAsIEVvVF9kYXRlKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIFByZW1pdW1zDQoNCmBgYHtyfQ0KIyBQcmVtaXVtIGF0IEJvVA0KcHJlbWl1bV9Cb1QgPC0geWllbGRfSFlfQm9UJFlpZWxkIC0geWllbGRfVHJlYXN1cnlfQm9UJFlpZWxkDQoNCiMgUHJlbWl1bSBhdCBFb1QNCnByZW1pdW1fRW9UIDwtIHlpZWxkX0hZX0VvVCRZaWVsZCAtIHlpZWxkX1RyZWFzdXJ5X0VvVCRZaWVsZA0KYGBgDQoNCg0KQ29tcGFyZSBQcmVtaXVtcw0KDQpgYGB7cn0NCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSB0byBkaXNwbGF5IHRoZSByZXN1bHRzDQpyZXN1bHRzX0w3MTcgPC0gZGF0YS5mcmFtZSgNCiAgRGF0ZSA9IGMoeWllbGRfVHJlYXN1cnlfQm9UJERhdGUsIHlpZWxkX1RyZWFzdXJ5X0VvVCREYXRlKSwNCiAgUGVyaW9kID0gYygiQm9UIiwgIkVvVCIpLA0KICBZaWVsZF9IaWdoX1lpZWxkX0NvcnBvcmF0ZSA9IGMoeWllbGRfSFlfQm9UJFlpZWxkLCB5aWVsZF9IWV9Fb1QkWWllbGQpLA0KICBZaWVsZF9UcmVhc3VyeSA9IGMoeWllbGRfVHJlYXN1cnlfQm9UJFlpZWxkLCB5aWVsZF9UcmVhc3VyeV9Fb1QkWWllbGQpLA0KICBQcmVtaXVtID0gYyhwcmVtaXVtX0JvVCwgcHJlbWl1bV9Fb1QpDQopDQoNCnByaW50KHJlc3VsdHNfTDcxNykNCmBgYA0KDQoNCkNoYW5nZSBpbiBwcmVtaXVtcw0KDQpgYGB7cn0NCiNDaGFuZ2UgaW4gcHJlbWl1bSBleHByZXNzZWQgaW4gcGVyY2VudGFnZSBwb2ludHMNCmNoYW5nZV9pbl9wcmVtaXVtIDwtIHJvdW5kKHByZW1pdW1fRW9ULCAyKSAtIHJvdW5kKHByZW1pdW1fQm9UKQ0KY2F0KCJjaGFuZ2UgaW4gcHJlbWl1bToiLCBjaGFuZ2VfaW5fcHJlbWl1bSkNCmBgYA0KDQoNCiMjIyMgQW5hbHlzaXMgb2YgcmV0dXJucw0KSW4gdGhpcyBsYXN0IGV4ZXJjaXNlIG9mIHRoaXMgc2VjdGlvbiwgd2UgaGF2ZSBjYWxjdWxhdGVkIHRoZSBwcmVtaXVtIG9mIGhpZ2ggeWllbGQgY29ycG9yYXRlIGJvbmRzIGFnYWluc3QgdGhlIHRyZWFzdXJ5IGJvbmQgeWllbGRzLiBBcyB3ZSBrbm93LCBoaWdoLXlpZWxkcyB3aWxsIGhhdmUgaGlnaGVyIHJpc2sgYW5kIGhpZ2hlciBleHBlY3RlZCByZXR1cm5zLiBUaGUgcHJlbWl1bSBoYXMgZmFsbGVuIDAuNzkgcG9pbnRzIGR1cmluZyB0aGUgc2Nob29sIHRlcm0sIHdoaWNoIG1heSBpbmRpY2F0ZSBhIHJlZHVjdGlvbiBvZiBjcmVkaXQgcmlzayBhbmQgYW4gb3ZlcmFsbCBpbXByb3ZlbWVudCBpbiB0aGUgZWNvbm9teS4gVGhpcyBtZWFucyB0aGF0IHRoZXJlIGlzIGxlc3MgcmlzayBvZiBub3QgZ2V0dGluZyBub24tcGF5bWVudHMsIGFuZCBhcyB3ZSBrbm93LCB3aXRoIGxvd2VyIHJpc2tzIHdlIHNoYWxsIG9idGFpbiBsb3dlciBleHBlY3RlZCByZXR1cm5zIG9yIHlpZWxkcy4gDQpJbnZlc3RvcnMgbmVjZXNzaXRpZXMgb3IgcHJlZmVyZW5jZXMgYW5kIHRoZWlyIHNoaWZ0cyBtYXkgYWxzbyBoYXZlIGFuIGltcGFjdCBvbiB0aGUgcHJlbWl1bXMgYXMgdGhlIGdlbmVyYWwgcmlzayB0b2xlcmFuY2UgZmx1Y3R1YXRlIGluIHRoZSBtYXJrZXQuIA0KDQoNCg0KDQojIyBMOCBQb3J0Zm9saW8gLSBNYXJrb3ZpdHoNClJlcGxpY2F0ZSB0aGUgYmFzaWMgaWRlYSBvZiB0aGUgcG9ydGZvbGlvIGNhc2UNCg0KIyMjIE1hcmtvd2l0eiBQb3J0Zm9saW8gVGhlb3J5DQpBbHRob3VnaCBpdCB3aWxsIGJlIGV4cGxhaW5lZCBpbiBmdXJ0aGVyIGRldGFpbCBpbiB0aGUgbmV4dCBxdWVzdGlvbiwgd2UgY2FuIGludHJvZHVjZSB0aGUgTWFya293aXR6IHRoZW9yeSBhcyBhIHBvcnRmb2xpbyBzZWxlY3Rpb24gc3RyYXRlZ3kgdGhhdCBzZWVrcyB0byBtYXhpbWl6ZSB0aGUgZXhwZWN0ZWQgcmV0dXJuIGZvciBhIGdpdmVuIHJpc2sgKG9yIHRvIGZpbmQgdGhlIG1pbmltdW0gcmlzayBmb3IgYSBnaXZlbiByZXR1cm4pLiBUaGlzIG1ldGhvZCBjb25zaWRlcnMgdG90YWwgcmlzaywgdGhhdCBpcyBzeXN0ZW1hdGljIGFuZCBzcGVjaWZpYyByaXNrLiANCg0KIyMjIFIgY29kZSBmb3IgZGVtb25zdHJhdGlvbg0KDQpMb2FkIFJlcXVpcmVkIFBhY2thZ2VzDQoNCmBgYHtyfQ0KIyBJbnN0YWxsIHJlcXVpcmVkIHBhY2thZ2VzIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KaWYgKCFyZXF1aXJlKCJQZXJmb3JtYW5jZUFuYWx5dGljcyIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoIlBlcmZvcm1hbmNlQW5hbHl0aWNzIikNCn0NCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KDQpgYGANCg0KDQpSZXRyaWV2ZSBIaXN0b3JpY2FsIFN0b2NrIERhdGENCg0KYGBge3J9DQojIERlZmluZSBzdG9jayBzeW1ib2xzDQpzeW1ib2xzIDwtIGMoIkFNWk4iLCAiVFNMQSIpDQoNCiMgU2V0IHRoZSBkYXRlIHJhbmdlDQpzdGFydF9kYXRlIDwtICIyMDE4LTAxLTAxIg0KZW5kX2RhdGUgPC0gIjIwMjMtMTItMzEiICAjIEFkanVzdCB0aGUgZW5kIGRhdGUgaWYgbmVlZGVkDQoNCiMgR2V0IGhpc3RvcmljYWwgZGF0YSBmb3IgQW1hem9uIGFuZCBUZXNsYQ0KZ2V0U3ltYm9scyhzeW1ib2xzLCBmcm9tID0gc3RhcnRfZGF0ZSwgdG8gPSBlbmRfZGF0ZSwgYXV0by5hc3NpZ24gPSBUUlVFKQ0KDQojIEV4dHJhY3QgYWRqdXN0ZWQgY2xvc2luZyBwcmljZXMNCnByaWNlcyA8LSBtZXJnZShBZChBTVpOKSwgQWQoVFNMQSkpDQpjb2xuYW1lcyhwcmljZXMpIDwtIHN5bWJvbHMNCmBgYA0KDQoNCkNhbGN1bGF0ZSBEYWlseSBSZXR1cm5zDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgZGFpbHkgcmV0dXJucw0KcmV0dXJucyA8LSBuYS5vbWl0KFJPQyhwcmljZXMsIHR5cGUgPSAiZGlzY3JldGUiKSkNCmBgYA0KDQoNCkNhbGN1bGF0ZSBFeHBlY3RlZCBSZXR1cm5zIGFuZCBDb3ZhcmlhbmNlIE1hdHJpeA0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIGV4cGVjdGVkIGRhaWx5IHJldHVybnMgKG1lYW4gcmV0dXJucykNCm11IDwtIGNvbE1lYW5zKHJldHVybnMpDQoNCiMgQ2FsY3VsYXRlIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeA0KY292X21hdCA8LSBjb3YocmV0dXJucykNCmBgYA0KDQoNClNldCB1cCBQb3J0Zm9saW8gV2VpZ2h0cw0KDQpgYGB7cn0NCiMgRXF1YWwgd2VpZ2h0cyBmb3IgQU1aTiBhbmQgVFNMQQ0Kd2VpZ2h0cyA8LSBjKDAuNSwgMC41KQ0KbmFtZXMod2VpZ2h0cykgPC0gc3ltYm9scw0KDQpgYGANCg0KDQpDYWxjdWxhdGUgUG9ydGZvbGlvIEV4cGVjdGVkIFJldHVybiBhbmQgVmFyaWFuY2UNCg0KYGBge3J9DQojIENhbGN1bGF0ZSBwb3J0Zm9saW8gZXhwZWN0ZWQgZGFpbHkgcmV0dXJuDQpwb3J0Zm9saW9fcmV0dXJuX2RhaWx5IDwtIHN1bSh3ZWlnaHRzICogbXUpDQoNCiMgQ2FsY3VsYXRlIHBvcnRmb2xpbyBkYWlseSB2YXJpYW5jZQ0KcG9ydGZvbGlvX3ZhcmlhbmNlX2RhaWx5IDwtIHQod2VpZ2h0cykgJSolIGNvdl9tYXQgJSolIHdlaWdodHMNCmBgYA0KDQoNCg0KQW5udWFsaXplIHRoZSBFeHBlY3RlZCBSZXR1cm4gYW5kIFZvbGF0aWxpdHkNCg0KYGBge3J9DQojIEFubnVhbGl6ZSBleHBlY3RlZCByZXR1cm4NCnBvcnRmb2xpb19yZXR1cm5fYW5udWFsIDwtIHBvcnRmb2xpb19yZXR1cm5fZGFpbHkgKiAyNTINCg0KIyBBbm51YWxpemUgdm9sYXRpbGl0eSAoc3RhbmRhcmQgZGV2aWF0aW9uKQ0KcG9ydGZvbGlvX3ZvbGF0aWxpdHlfYW5udWFsIDwtIHNxcnQocG9ydGZvbGlvX3ZhcmlhbmNlX2RhaWx5ICogMjUyKQ0KYGBgDQoNCg0KUHJpbnQgdGhlIHJlc3VsdHMNCg0KYGBge3J9DQojIFByaW50IHJlc3VsdHMNCnByaW50KHBhc3RlKCJQb3J0Zm9saW8gZXhwZWN0ZWQgYW5udWFsIHJldHVybjoiLCByb3VuZChwb3J0Zm9saW9fcmV0dXJuX2FubnVhbCAqIDEwMCwgMiksICIlIikpDQpwcmludChwYXN0ZSgiUG9ydGZvbGlvIGFubnVhbGl6ZWQgdm9sYXRpbGl0eToiLCByb3VuZChwb3J0Zm9saW9fdm9sYXRpbGl0eV9hbm51YWwgKiAxMDAsIDIpLCAiJSIpKQ0KDQpgYGANCg0KDQojIyMgQW5hbHlzaXMgb2YgcmVzdWx0cw0KSW4gdGhpcyBleGFtcGxlLCB3ZSBoYXZlIGNyZWF0ZWQgYSBwb3J0Zm9saW8gd2hpY2ggb25seSBjb250YWlucyB0d28gYXNzZXRzLiBCb3RoIGFzc2V0cyBoYXZlIHRoZSBzYW1lIHdlaWdodCBhbmQgd2UgYXJlIG9ubHkgZXZhbHVhdGluZyB0aGUgZXhwZWN0ZWQgYW5udWFsIHJldHVybiBhbmQgdGhlIHZvbGF0aWxpdHkuIA0KV2UgbWF5IG5vdGljZSB0aGF0IHRoZSB2b2xhdGlsaXR5IGlzIHF1aXRlIGhpZ2ggaW4gdGhpcyBjYXNlLiBWb2xhdGlsaXR5LCBtZWFzdXJlZCBieSB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uLCBtZWFzdXJlcyB0b3RhbCByaXNrLiBUaGVyZWZvcmUsIHRoZSB2b2xhdGlsaXR5IHBvcnRyYXllZCBpbiB0aGlzIGV4YW1wbGUgaXMgY29uc2lkZXJhYmx5IGhpZ2ggZm9yIHRoZSBpbnZlc3RvciwgYW5kIHByZXN1bWFibHkgbm90IGEgZGVzaXJlZCBvbmUuIFRoZSBtYWluIHdheSB0byBsZXNzZW4gdGhpcyByaXNrIGlzIGJ5IGRpdmVyc2lmeWluZywgdGhpcyBpcywgZWxpbWluYXRpbmcgdGhlIHVuc3lzdGVtYXRpYyByaXNrIGJ5IG1peGluZyBkaWZmZXJlbnQgdHlwZXMgb2YgYXNzZXRzIGFuZCBpbnZlc3RtZW50cyBpbnRvIHRoZSBzYW1lIHBvcnRmb2xpby4gDQoNCg0KIyMjIEZpbmFsIENvbW1lbnRzDQpJbiB0aGUgZm9sbG93aW5nIGV4ZXJjaXNlIHdlIHdpbGwgZGl2ZSBmdXJ0aGVyIGludG8gdGhlIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgTWFya293aXR6IFBvcnRmb2xpbyBUaGVvcnkgYW5kIHdlIHdpbGwgY29tcGFyZSBpdCB0byBhbm90aGVyIG1vZGVsOiBDQVBNLiANCg0KDQoNCg0KIyMgTDkgUG9ydGZvbGlvIC0gQ0FQTQ0KDQoNCg0KIyMjIEludHJvZHVjdGlvbg0KVGhlIE1hcmtvd2l0eiBQb3J0Zm9saW8gVGhlb3J5IGFuZCB0aGUgQ2FwaXRhbCBBc3NldCBQcmljaW5nIE1vZGVsIChDQVBNKSBhcmUgdHdvIGRpZmZlcmVudCBhcHByb2FjaGVzIGZvciBwb3J0Zm9saW8gc2VsZWN0aW9uIGFuZCBhc3NldCBwcmljaW5nLiBUaGlzIHR3byBkaWZmZXJlbnQgbWV0aG9kcyBoYXZlIHRoZSBzY29wZSBvZiBtYWtpbmcgaW52ZXN0bWVudCBkZWNpc2lvbnMgYW5kIG9wdGltaXplIHRoZW0sIGJ1dCBlYWNoIGhhdmUgdGhlaXIgb3duIGFzc3VtcHRpb25zLCBhcHByb2FjaGVzIGFuZCBhcHBsaWNhdGlvbnMuIA0KDQoNCiMjIyBNYXJrb3dpdHogUG9ydGZvbGlvIFRoZW9yeQ0KDQojIyMjIE92ZXJ2aWV3DQoNCiAgRGV2ZWxvcGVkIGJ5OiBIYXJyeSBNYXJrb3dpdHogaW4gMTk1Mi4NCg0KICBDb25jZXB0OiBBbHNvIGtub3duIGFzIE1lYW4tVmFyaWFuY2UgT3B0aW1pemF0aW9uIChNVk8pLg0KDQogIE9iamVjdGl2ZTogVG8gYnVpbGQgYW4gb3B0aW1hbCBwb3J0Zm9saW8gdGhhdCBvZmZlcnMgdGhlIG1heGltdW0gZXhwZWN0ZWQgcmV0dXJuIGZvciBhIGdpdmVuIGxldmVsIG9mIHJpc2ssIG9yIGVxdWl2YWxlbnRseSwgdGhlIG1pbmltdW0gcmlzayBmb3IgYSBnaXZlbiBsZXZlbCBvZiBleHBlY3RlZCByZXR1cm4uDQoNCg0KIyMjIyBNYWluIEVsZW1lbnRzDQoNCiAgRXhwZWN0ZWQgUmV0dXJuOiBUaGUgd2VpZ2h0ZWQgYXZlcmFnZSBvZiB0aGUgZXhwZWN0ZWQgcmV0dXJucyBvZiB0aGUgYXNzZXRzIGluIHRoZSBwb3J0Zm9saW8uDQoNCiAgUmlzayAoVmFyaWFuY2Ugb3IgU3RhbmRhcmQgRGV2aWF0aW9uKTogVGhlIHBvcnRmb2xpbydzIHRvdGFsIHJpc2sgaXMgbWVhc3VyZWQgYnkgdGhlIHZhcmlhbmNlIChvciBzdGFuZGFyZCBkZXZpYXRpb24pIG9mIGl0cyByZXR1cm5zLg0KDQogIENvdmFyaWFuY2U6IEFjY291bnRzIGZvciBob3cgYXNzZXRzIG1vdmUgdG9nZXRoZXI7IGRpdmVyc2lmaWNhdGlvbiBiZW5lZml0cyBhcmlzZSB3aGVuIGFzc2V0IHJldHVybnMgYXJlIG5vdCBwZXJmZWN0bHkgY29ycmVsYXRlZC4NClBlcmZlY3RseSBjb3JyZWxhdGVkIGFzc2V0cyB3aWxsIGhhdmUgYSBiZXRhIG9mIDEgb3IgLTEsIHdoZXJlYXMgdGhlIHJlc3Qgd2lsbCBoYXZlIGJldGFzIGluLWJldHdlZW4gdGhvc2UgdHdvIHZhbHVlcy4gDQoNCg0KIyMjIyBBc3N1bXB0aW9ucw0KDQogIEludmVzdG9ycyBhcmUgcmF0aW9uYWwgYW5kIHJpc2stYXZlcnNlLg0KDQogIFJldHVybnMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLg0KDQogIFBlcmZlY3QgSW5mb3JtYXRpb24gaW4gdGhlIG1hcmtldDsgTWFya2V0cyBhcmUgZWZmaWNpZW50Lg0KDQogIEludmVzdG9ycyBjb25zaWRlciBvbmx5IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiByZXR1cm5zLg0KDQogIE5vIHRyYW5zYWN0aW9uIGNvc3RzIG9yIHRheGVzLg0KDQogIEFzc2V0cyBhcmUgaW5maW5pdGVseSBkaXZpc2libGUuDQoNCg0KIyMjIyBFZmZpY2llbnQgRnJvbnRpZXINCiAgVGhlIHNldCBvZiBvcHRpbWFsIHBvcnRmb2xpb3MgdGhhdCBvZmZlciB0aGUgaGlnaGVzdCBleHBlY3RlZCByZXR1cm4gZm9yIGEgZ2l2ZW4gbGV2ZWwgb2Ygcmlzay4NCg0KICBJbnZlc3RvcnMgY2hvb3NlIHBvcnRmb2xpb3Mgb24gdGhlIGVmZmljaWVudCBmcm9udGllciBiYXNlZCBvbiB0aGVpciByaXNrIHByZWZlcmVuY2UuDQoNCg0KDQojIyMgQ2FwaXRhbCBBc3NldCBQcmljaW5nIE1vZGVsIChDQVBNKQ0KDQoNCiMjIyMgT3ZlcnZpZXcNCiAgRGV2ZWxvcGVkIGJ5OiBXaWxsaWFtIFNoYXJwZSwgSm9obiBMaW50bmVyLCBhbmQgSmFuIE1vc3NpbiBpbiB0aGUgMTk2MHMuDQoNCiAgQ29uY2VwdDogQSBtb2RlbCB0aGF0IGRlc2NyaWJlcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGV4cGVjdGVkIHJldHVybiBvZiBhbiBhc3NldCBhbmQgaXRzIHN5c3RlbWF0aWMgcmlzaywgbWVhc3VyZWQgYnkgYmV0YSAozrIpLg0KDQogIE9iamVjdGl2ZTogVG8gZGV0ZXJtaW5lIHRoZSBleHBlY3RlZCByZXR1cm4gb24gYW4gYXNzZXQgb3IgcG9ydGZvbGlvLCBjb25zaWRlcmluZyBpdHMgcmlzayByZWxhdGl2ZSB0byB0aGUgbWFya2V0Lg0KDQoNCiMjIyMgS2V5IENvbXBvbmVudHMNCiAgUmlzay1GcmVlIFJhdGUgKFJmKTogVGhlIHJldHVybiBvZiBhbiBpbnZlc3RtZW50IHdpdGggemVybyByaXNrLCB0eXBpY2FsbHkgZ292ZXJubWVudCBib25kcy4gVGhpcyBpbnZlc3RtZW50IGhhcyBhIM6yID0gMA0KDQogIE1hcmtldCBSZXR1cm4gKFJtKTogVGhlIGV4cGVjdGVkIHJldHVybiBvZiB0aGUgbWFya2V0IHBvcnRmb2xpby4NCg0KICBCZXRhICjOsik6IE1lYXN1cmVzIHRoZSBzZW5zaXRpdml0eSBvZiB0aGUgYXNzZXQncyByZXR1cm5zIHRvIHRoZSByZXR1cm5zIG9mIHRoZSBtYXJrZXQgcG9ydGZvbGlvLg0KDQogIEV4cGVjdGVkIFJldHVybiBGb3JtdWxhOg0KRShSaSkgPSBSZiArIM6yaShFKFJtKS1SZikNCndoZXJlOg0KRShSaSkgaXMgdGhlIGV4cGVjdGVkIHJldHVybiBvZiBhc3NldCAiaSINCs6yaSBpcyB0aGUgYmV0YSBvZiBhc3NldCBpDQpFKFJtKSBpcyB0aGUgZXhwZWN0ZWQgbWFya2V0IHJldHVybg0KDQoNCiMjIyMgQXNzdW1wdGlvbnMNCg0KICBJbnZlc3RvcnMgaG9sZCBkaXZlcnNpZmllZCBwb3J0Zm9saW9zIChtYXJrZXQgcG9ydGZvbGlvKSB0aGF0IGVsaW1pbmF0ZSB1bnN5c3RlbWF0aWMgcmlzay4NCg0KICBNYXJrZXRzIGFyZSBlZmZpY2llbnQ7IGFsbCBpbnZlc3RvcnMgaGF2ZSB0aGUgc2FtZSBpbmZvcm1hdGlvbi4NCg0KICBJbnZlc3RvcnMgY2FuIGJvcnJvdyBhbmQgbGVuZCB1bmxpbWl0ZWQgYW1vdW50cyBhdCB0aGUgcmlzay1mcmVlIHJhdGUgKE9SIHNob3J0IHNlbGxpbmcgc2hhbGwgYmUgYWxsb3dlZCkNCg0KICBObyB0YXhlcyBvciB0cmFuc2FjdGlvbiBjb3N0cy4NCg0KICBTaW5nbGUtcGVyaW9kIGludmVzdG1lbnQgaG9yaXpvbi4NCg0KDQojIyMjIFNlY3VyaXR5IE1hcmtldCBMaW5lIChTTUwpDQpBIGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgQ0FQTSwgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZXhwZWN0ZWQgcmV0dXJuIGFuZCBiZXRhLg0KQXNzZXRzIHBsb3R0ZWQgYWJvdmUgdGhlIFNNTCBhcmUgdW5kZXJ2YWx1ZWQ7IHRob3NlIGJlbG93IGFyZSBvdmVydmFsdWVkLiBUaGlzIGNhbiBoZWxwIHVzIGtub3cgKHJlYWxseSBhcHByb3hpbWF0ZWx5KSB3aGV0aGVyIGFuIGFzc2V0IHNoYWxsIGJlIGJvdWdodCBvciBzZWxsLiBJbiB0aGUgY2FzZSBvZiBhbiBhc3NldCBiZWluZyBvdmVydmFsdWVkLCB3ZSBzaG91bGQgc2VsbCBpdCBhcyBpdCB3aWxsIGV2ZW50dWFsbHkgZHJvcCB0byB0aGUgc2VjdXJpdHkgbWFya2V0IGxpbmUuIElmIGFuIGFzc2V0IGlzIHVuZGVydmFsdWVkLCB3ZSBzaG91bGQgYnV5IGl0IGFzIGl0cyBjdXJyZW50IHByaWNlIGRvZXMgbm90IHJlcHJlc2VudCB0aGUgbWFya2V0IHByaWNlIGl0IHNob3VsZCBoYXZlIGFuZCBpdCB3aWxsIGV2ZW50dWFsbHkgYXBwcmVjaWF0ZS4gDQoNCg0KIyMjIERpZmZlcmVuY2VzIEJldHdlZW4gQ0FQTSBhbmQgTWFya293aXR6IFBvcnRmb2xpbyBUaGVvcnkNCg0KIyMjIyAxLiBQdXJwb3NlIGFuZCBBcHBsaWNhdGlvbg0KDQoNCiMjIyMjIE1hcmtvd2l0eiBQb3J0Zm9saW8gVGhlb3J5Og0KDQpGb2N1c2VzIG9uIHBvcnRmb2xpbyBzZWxlY3Rpb24gYnkgb3B0aW1pemluZyB0aGUgdHJhZGUtb2ZmIGJldHdlZW4gZXhwZWN0ZWQgcmV0dXJuIGFuZCByaXNrLg0KSGVscHMgaW52ZXN0b3JzIGNvbnN0cnVjdCBhbiBlZmZpY2llbnQgcG9ydGZvbGlvIGJhc2VkIG9uIHRoZWlyIHJpc2sgdG9sZXJhbmNlLg0KDQoNCiMjIyMjIENBUE06DQoNCkZvY3VzZXMgb24gYXNzZXQgcHJpY2luZyBieSByZWxhdGluZyBleHBlY3RlZCByZXR1cm4gdG8gc3lzdGVtYXRpYyByaXNrLg0KUHJvdmlkZXMgYSB3YXkgdG8gcHJpY2UgaW5kaXZpZHVhbCBzZWN1cml0aWVzIGFuZCBkZXRlcm1pbmUgZXhwZWN0ZWQgcmV0dXJucyBiYXNlZCBvbiBtYXJrZXQgcmlzay4NCg0KDQojIyMjIDIuIFJpc2sgQ29uc2lkZXJhdGlvbg0KDQojIyMjIyBNYXJrb3dpdHo6DQoNCiAgQ29uc2lkZXJzIHRvdGFsIHJpc2sgKHN0YW5kYXJkIGRldmlhdGlvbiBvciB2YXJpYW5jZSksIGluY2x1ZGluZyBib3RoIHN5c3RlbWF0aWMgYW5kIHVuc3lzdGVtYXRpYyByaXNrLg0KDQogIEVtcGhhc2l6ZXMgdGhlIGltcG9ydGFuY2Ugb2YgZGl2ZXJzaWZpY2F0aW9uIHRvIHJlZHVjZSB1bnN5c3RlbWF0aWMgcmlzay4NCg0KDQojIyMjIyBDQVBNOg0KDQogIENvbnNpZGVycyBvbmx5IHN5c3RlbWF0aWMgcmlzayAoYmV0YSksIGFzc3VtaW5nIHVuc3lzdGVtYXRpYyByaXNrIGlzIGVsaW1pbmF0ZWQgdGhyb3VnaCBkaXZlcnNpZmljYXRpb24uDQoNCiAgQmV0YSBtZWFzdXJlcyB0aGUgYXNzZXQncyBzZW5zaXRpdml0eSB0byBtYXJrZXQgbW92ZW1lbnRzLg0KDQoNCiMjIyMgMy4gQXNzdW1wdGlvbnMgQWJvdXQgRGl2ZXJzaWZpY2F0aW9uDQoNCiMjIyMjIE1hcmtvd2l0ejoNCg0KICBBc3N1bWVzIGludmVzdG9ycyBjYW4gYW5kIHNob3VsZCBkaXZlcnNpZnkgdGhlaXIgcG9ydGZvbGlvcyB0byBvcHRpbWl6ZSByaXNrLXJldHVybiB0cmFkZS1vZmZzLg0KDQogIERpdmVyc2lmaWNhdGlvbiByZWR1Y2VzIHRvdGFsIHJpc2suDQoNCg0KIyMjIyMgQ0FQTToNCg0KICBBc3N1bWVzIGludmVzdG9ycyBhbHJlYWR5IGhvbGQgdGhlIG1hcmtldCBwb3J0Zm9saW8sIHdoaWNoIGlzIGZ1bGx5IGRpdmVyc2lmaWVkLg0KICBUaGVyZWZvcmUsIG9ubHkgc3lzdGVtYXRpYyByaXNrIG1hdHRlcnMgaW4gcHJpY2luZyBhc3NldHMuDQoNCg0KIyMjIyA0LiBPdXRwdXQgYW5kIFVzZQ0KDQojIyMjIyBNYXJrb3dpdHo6DQoNCiAgUHJvdmlkZXMgdGhlIGVmZmljaWVudCBmcm9udGllciBvZiBvcHRpbWFsIHBvcnRmb2xpb3MuDQoNCiAgSW52ZXN0b3JzIGNob29zZSBwb3J0Zm9saW9zIGJhc2VkIG9uIHRoZWlyIHJpc2sgcHJlZmVyZW5jZXMuDQoNCg0KIyMjIyMgQ0FQTToNCg0KICBQcm92aWRlcyB0aGUgZXhwZWN0ZWQgcmV0dXJuIG9mIGFuIGFzc2V0IGdpdmVuIGl0cyBiZXRhLg0KDQogIFVzZWQgdG8gYXNzZXNzIHdoZXRoZXIgYW4gYXNzZXQgaXMgZmFpcmx5IHByaWNlZC4NCg0KDQojIyMjIDUuIE1hcmtldCBFcXVpbGlicml1bQ0KDQojIyMjIyBNYXJrb3dpdHo6DQoNCiAgRG9lcyBub3QgYXNzdW1lIG1hcmtldCBlcXVpbGlicml1bTsgaXQncyBhIG5vcm1hdGl2ZSBtb2RlbCBzdWdnZXN0aW5nIGhvdyBpbnZlc3RvcnMgc2hvdWxkIGFsbG9jYXRlIGFzc2V0cy4NCg0KDQojIyMjIyBDQVBNOg0KDQogIEFzc3VtZXMgbWFya2V0IGVxdWlsaWJyaXVtIHdoZXJlIHN1cHBseSBhbmQgZGVtYW5kIGFyZSBiYWxhbmNlZC4NCg0KICBQcmljZXMgYWRqdXN0IHNvIHRoYXQgZXhwZWN0ZWQgcmV0dXJucyBhcmUgY29uc2lzdGVudCB3aXRoIHJpc2suDQoNCg0KIyMjIyA2LiBQcmFjdGljYWwgSW1wbGVtZW50YXRpb24NCg0KIyMjIyMgTWFya293aXR6Og0KDQogIENvbXB1dGF0aW9uYWxseSBpbnRlbnNpdmUsIGVzcGVjaWFsbHkgd2l0aCBtYW55IGFzc2V0cyBkdWUgdG8gdGhlIGNvdmFyaWFuY2UgbWF0cml4Lg0KDQogIFJlcXVpcmVzIGVzdGltYXRlcyBvZiBleHBlY3RlZCByZXR1cm5zLCB2YXJpYW5jZXMsIGFuZCBjb3ZhcmlhbmNlcy4NCg0KDQojIyMjIyBDQVBNOg0KDQogIFNpbXBsZXIgdG8gaW1wbGVtZW50IHNpbmNlIGl0IHJlcXVpcmVzIGVzdGltYXRpbmcgYmV0YSBhbmQgZXhwZWN0ZWQgbWFya2V0IHJldHVybi4NCiAgDQogIEJldGEgY2FuIGJlIGVzdGltYXRlZCB1c2luZyByZWdyZXNzaW9uIGFuYWx5c2lzIG9uIGhpc3RvcmljYWwgZGF0YS4NCg0KDQojIyMgUiBJbXBsZW1lbnRhdGlvbiBFeGFtcGxlDQpUbyBpbGx1c3RyYXRlIHRoZSBkaWZmZXJlbmNlcywgd2UgY2FuIHVzZSBSIHRvIHBlcmZvcm0gYm90aCBhIE1hcmtvd2l0eiBwb3J0Zm9saW8gb3B0aW1pemF0aW9uIGFuZCBhIENBUE0gYW5hbHlzaXMuDQoNCiMjIyMgTWFya293aXR6IFBvcnRmb2xpbyBPcHRpbWl6YXRpb24NCg0KTG9hZCBsaWJyYXJpZXMNCg0KYGBge3J9DQojIEluc3RhbGwgYW5kIGxvYWQgcmVxdWlyZWQgcGFja2FnZXMNCmlmICghcmVxdWlyZSgicXVhbnRtb2QiKSkgaW5zdGFsbC5wYWNrYWdlcygicXVhbnRtb2QiKQ0KaWYgKCFyZXF1aXJlKCJQb3J0Zm9saW9BbmFseXRpY3MiKSkgaW5zdGFsbC5wYWNrYWdlcygiUG9ydGZvbGlvQW5hbHl0aWNzIikNCmlmICghcmVxdWlyZSgiUk9JIikpIGluc3RhbGwucGFja2FnZXMoIlJPSSIpDQppZiAoIXJlcXVpcmUoIlJPSS5wbHVnaW4ucXVhZHByb2ciKSkgaW5zdGFsbC5wYWNrYWdlcygiUk9JLnBsdWdpbi5xdWFkcHJvZyIpDQppZiAoIXJlcXVpcmUoIlBlcmZvcm1hbmNlQW5hbHl0aWNzIikpIGluc3RhbGwucGFja2FnZXMoIlBlcmZvcm1hbmNlQW5hbHl0aWNzIikNCg0KbGlicmFyeShxdWFudG1vZCkNCmxpYnJhcnkoUG9ydGZvbGlvQW5hbHl0aWNzKQ0KbGlicmFyeShST0kpDQpsaWJyYXJ5KFJPSS5wbHVnaW4ucXVhZHByb2cpDQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KYGBgDQoNCg0KUmV0cmlldmUgZGF0YQ0KDQpgYGB7cn0NCiMgRGVmaW5lIGEgc2V0IG9mIGFzc2V0cw0Kc3ltYm9scyA8LSBjKCJBQVBMIiwgIk1TRlQiLCAiR09PRyIsICJBTVpOIikNCg0KIyBHZXQgaGlzdG9yaWNhbCBwcmljZSBkYXRhDQpnZXRTeW1ib2xzKHN5bWJvbHMsIGZyb20gPSAiMjAyMC0wMS0wMSIsIHRvID0gIjIwMjMtMDEtMDEiKQ0KYGBgDQoNCg0KTWVyZ2UgRGF0YSBhbmQgb2J0YWluIHJldHVybnMgKGVsaW1pbmF0aW5nIG5vbi1leGlzdGluZyBkYXRhKQ0KDQpgYGB7cn0NCiMgTWVyZ2UgYWRqdXN0ZWQgY2xvc2luZyBwcmljZXMNCnByaWNlcyA8LSBkby5jYWxsKG1lcmdlLCBsYXBwbHkoc3ltYm9scywgZnVuY3Rpb24oeCkgQWQoZ2V0KHgpKSkpDQoNCiMgQ2FsY3VsYXRlIHJldHVybnMNCnJldHVybnMgPC0gbmEub21pdChSZXR1cm4uY2FsY3VsYXRlKHByaWNlcykpDQpgYGANCg0KDQpDcmVhdGUgcG9ydGZvbGlvIHNwZWNpZmljYXRpb25zIGFuZCBvcHRpbWl6ZSBpdA0KDQpgYGB7cn0NCiMgQ3JlYXRlIHBvcnRmb2xpbyBzcGVjaWZpY2F0aW9uDQpwb3J0X3NwZWMgPC0gcG9ydGZvbGlvLnNwZWMoYXNzZXRzID0gc3ltYm9scykNCnBvcnRfc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0X3NwZWMsIHR5cGUgPSAiZnVsbF9pbnZlc3RtZW50IikNCnBvcnRfc3BlYyA8LSBhZGQuY29uc3RyYWludChwb3J0X3NwZWMsIHR5cGUgPSAibG9uZ19vbmx5IikNCnBvcnRfc3BlYyA8LSBhZGQub2JqZWN0aXZlKHBvcnRfc3BlYywgdHlwZSA9ICJyaXNrIiwgbmFtZSA9ICJTdGREZXYiKQ0KcG9ydF9zcGVjIDwtIGFkZC5vYmplY3RpdmUocG9ydF9zcGVjLCB0eXBlID0gInJldHVybiIsIG5hbWUgPSAibWVhbiIpDQoNCiMgT3B0aW1pemUgcG9ydGZvbGlvIHRvIGZpbmQgdGhlIG1pbmltdW0gdmFyaWFuY2UgcG9ydGZvbGlvDQpvcHRfcG9ydCA8LSBvcHRpbWl6ZS5wb3J0Zm9saW8oUiA9IHJldHVybnMsIHBvcnRmb2xpbyA9IHBvcnRfc3BlYywgb3B0aW1pemVfbWV0aG9kID0gIlJPSSIpDQpgYGANCg0KDQpDcmVhdGUgZGF0YSBmcmFtZSBhbmQgcHJpbnQgcmVzdWx0cw0KDQpgYGB7cn0NCm1hcmtvd2l0el9yZXN1bHRzIDwtIGRhdGEuZnJhbWUoDQogIFN0b2NrID0gc3ltYm9scywNCiAgV2VpZ2h0cyA9IG9wdF9wb3J0JHdlaWdodHMNCikNCnByaW50KG1hcmtvd2l0el9yZXN1bHRzKQ0KYGBgDQoNCg0KQ29uc3RydWN0IGZpbmFsIHBvcnRmb2xpbyByZXR1cm5zIHJldHVybnMgZnJvbSB0aGUgb3B0aW1pemVkIHdlaWdodHMNCg0KYGBge3J9DQpmaW5hbF9wb3J0Zm9saW9fcmV0dXJucyA8LSBSZXR1cm4ucG9ydGZvbGlvKFIgPSByZXR1cm5zLCB3ZWlnaHRzID0gb3B0X3BvcnQkd2VpZ2h0cykNCmBgYA0KDQoNCkNvbXB1dGUgYW5udWFsaXplZCBzdGF0aXN0aWNzIChyZXR1cm4sIHN0YW5kYXJkIGRldmlhdGlvbiwgU2hhcnBlIHJhdGlvLCBldGMuKQ0KDQpgYGB7cn0NCmFubnVhbF9zdGF0cyA8LSB0YWJsZS5Bbm51YWxpemVkUmV0dXJucyhmaW5hbF9wb3J0Zm9saW9fcmV0dXJucykNCnByaW50KGFubnVhbF9zdGF0cykNCmBgYA0KDQojIyMjIyBBbm51YWxpemVkIFJldHVybiAoMjAuMzYlKQ0KDQpUaGlzIGltcGxpZXMgdGhhdCwgaWYgdGhlIGRhaWx5IHJldHVybnMgb2JzZXJ2ZWQgZHVyaW5nIG91ciBoaXN0b3JpY2FsIHNhbXBsZSBwZXJpb2Qgd2VyZSB0byBjb250aW51ZSwgdGhlIHBvcnRmb2xpbyB3b3VsZCBlYXJuIHJvdWdobHkgMjAlIHBlciB5ZWFyLiBJdCBpcyBpbXBvcnRhbnQgdG8gcmVtZW1iZXIgdGhhdCB0aGlzIHJldHVybiBpcyBoaXN0b3JpY2FsbHkgYmFzZWQgYW5kIG5vdCBhIGd1YXJhbnRlZWQgZnV0dXJlIHBlcmZvcm1hbmNlLg0KDQojIyMjIyBBbm51YWxpemVkIFN0YW5kYXJkIERldmlhdGlvbiAoMzYuMTclKQ0KDQpBIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAzNiUgaW5kaWNhdGVzIGEgcmVsYXRpdmVseSBoaWdoIGxldmVsIG9mIHZvbGF0aWxpdHkuIEluIHByYWN0aWNhbCB0ZXJtcywgdGhlIHBvcnRmb2xpb+KAmXMgdmFsdWUgY291bGQgZmx1Y3R1YXRlIHNpZ25pZmljYW50bHkgYXJvdW5kIGl0cyBhdmVyYWdlIHJldHVybi4gSW52ZXN0b3JzIG5lZWQgdG8gZGVjaWRlIGlmIHRoaXMgbGV2ZWwgb2YgcmlzayBhbGlnbnMgd2l0aCB0aGVpciByaXNrIHRvbGVyYW5jZS4NCg0KIyMjIyMgQW5udWFsaXplZCBTaGFycGUgUmF0aW8gKDAuNTYyOSkNCg0KVGhlIFNoYXJwZSBSYXRpbyBtZWFzdXJlcyB0aGUgcG9ydGZvbGlv4oCZcyByaXNrLWFkanVzdGVkIHJldHVybi4gQSByYXRpbyBvZiAwLjU2IGluZGljYXRlcyB0aGF0LCBoaXN0b3JpY2FsbHksIHRoZSBwb3J0Zm9saW/igJlzIHJldHVybiBleGNlZWRlZCB0aGUgcmlzay1mcmVlIHJhdGUgYnkgMC41NiUgZm9yIGV2ZXJ5IDElIG9mIHZvbGF0aWxpdHkuIFdoaWxlIGEgU2hhcnBlIFJhdGlvIGFib3ZlIDEuMCBpcyBvZnRlbiBjb25zaWRlcmVkIHN0cm9uZywgYSByYXRpbyBhcm91bmQgMC414oCTMC43IGNhbiBiZSB2aWV3ZWQgYXMgYWNjZXB0YWJsZSBvciBtb2RlcmF0ZSwgZGVwZW5kaW5nIG9uIHRoZSBhc3NldCBjbGFzcy4NCg0KDQojIyMjIENBUE0gQW5hbHlzaXMNCg0KTG9hZCBsaWJyYXJpZXMgYW5kIHJldHJpZXZlIGRhdGENCg0KYGBge3J9DQpsaWJyYXJ5KHF1YW50bW9kKQ0KbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcykNCg0KIyBEZWZpbmUgdGhlIHN0b2NrIHN5bWJvbHMNCnN5bWJvbHMgPC0gYygiQUFQTCIsICJNU0ZUIiwgIkdPT0ciLCAiQU1aTiIpDQoNCiMgR2V0IGhpc3RvcmljYWwgZGF0YSBmb3IgYXNzZXRzIGFuZCBtYXJrZXQNCmdldFN5bWJvbHMoYyhzeW1ib2xzLCAiXkdTUEMiKSwgZnJvbSA9ICIyMDE4LTAxLTAxIiwgdG8gPSAiMjAyMy0xMi0zMSIpDQpgYGANCg0KDQpEZWZpbmUgYmV0YXMsIGV4cGVjdGVkIHJldHVybnMsIHJpc2sgZnJlZSByYXRlIGFuZCBvbWl0IG5vbi1leGlzdGVudCBkYXRhIGluIHJldHVybnMNCg0KYGBgIHtyfQ0KIyBJbml0aWFsaXplIHZlY3RvcnMgdG8gc3RvcmUgYmV0YXMgYW5kIGV4cGVjdGVkIHJldHVybnMNCmJldGFzIDwtIG51bWVyaWMobGVuZ3RoKHN5bWJvbHMpKQ0KZXhwZWN0ZWRfcmV0dXJucyA8LSBudW1lcmljKGxlbmd0aChzeW1ib2xzKSkNCg0KIyBEZWZpbmUgdGhlIGFubnVhbCByaXNrLWZyZWUgcmF0ZQ0Kcmlza19mcmVlX3JhdGUgPC0gMC4wMyAgIyAzJQ0KDQojIENhbGN1bGF0ZSBkYWlseSBtYXJrZXQgcmV0dXJucw0KbWFya2V0X3JldHVybnMgPC0gbmEub21pdChST0MoQWQoR1NQQykpKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIGJldGFzIGFuZCBleHBlY3RlZCByZXR1cm5zDQoNCmBgYCB7cn0NCiMgTG9vcCBvdmVyIGVhY2ggc3ltYm9sIHRvIGNhbGN1bGF0ZSBiZXRhIGFuZCBleHBlY3RlZCByZXR1cm4NCmZvciAoaSBpbiAxOmxlbmd0aChzeW1ib2xzKSkgew0KICAjIEdldCBzdG9jayByZXR1cm5zDQogIHN0b2NrX2RhdGEgPC0gZ2V0KHN5bWJvbHNbaV0pDQogIHN0b2NrX3JldHVybnMgPC0gbmEub21pdChST0MoQWQoc3RvY2tfZGF0YSkpKQ0KICANCiAgIyBBbGlnbiBkYXRlcyB3aXRoIG1hcmtldCByZXR1cm5zDQogIHJldHVybnNfZGF0YSA8LSBtZXJnZShzdG9ja19yZXR1cm5zLCBtYXJrZXRfcmV0dXJucywgYWxsID0gRkFMU0UpDQogIA0KICAjIENhbGN1bGF0ZSBiZXRhDQogIGJldGEgPC0gQ0FQTS5iZXRhKFJhID0gcmV0dXJuc19kYXRhWywxXSwgUmIgPSByZXR1cm5zX2RhdGFbLDJdKQ0KICBiZXRhc1tpXSA8LSBiZXRhDQoNCiAgIyBDYWxjdWxhdGUgZXhwZWN0ZWQgcmV0dXJuIHVzaW5nIENBUE0NCiAgYW5udWFsX21hcmtldF9yZXR1cm4gPC0gbWVhbihyZXR1cm5zX2RhdGFbLDJdKSAqIDI1MiAgIyBBbm51YWxpemUgbWFya2V0IHJldHVybg0KICBleHBlY3RlZF9yZXR1cm4gPC0gcmlza19mcmVlX3JhdGUgKyBiZXRhICogKGFubnVhbF9tYXJrZXRfcmV0dXJuIC0gcmlza19mcmVlX3JhdGUpDQogIGV4cGVjdGVkX3JldHVybnNbaV0gPC0gZXhwZWN0ZWRfcmV0dXJuDQogIA0KICAjIFByaW50IHJlc3VsdHMgZm9yIGVhY2ggc3RvY2sNCiAgY2F0KCJTdG9jazoiLCBzeW1ib2xzW2ldLCAiXG4iKQ0KICBjYXQoIkJldGE6Iiwgcm91bmQoYmV0YSwgNCksICJcbiIpDQogIGNhdCgiRXhwZWN0ZWQgUmV0dXJuOiIsIHJvdW5kKGV4cGVjdGVkX3JldHVybiAqIDEwMCwgMiksICIlXG5cbiIpDQp9DQoNCmBgYA0KDQoNCkNyZWF0ZSBkYXRhIGZyYW1lIGFuZCBwcmludCByZXN1bHRzDQoNCmBgYHtyfQ0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIHdpdGggdGhlIHJlc3VsdHMNCmNhcG1fcmVzdWx0cyA8LSBkYXRhLmZyYW1lKA0KICBTdG9jayA9IHN5bWJvbHMsDQogIEJldGEgPSByb3VuZChiZXRhcywgNCksDQogIEV4cGVjdGVkX1JldHVybiA9IHJvdW5kKGV4cGVjdGVkX3JldHVybnMgKiAxMDAsIDIpDQopDQoNCnByaW50KGNhcG1fcmVzdWx0cykNCmBgYA0KDQoNCg0KIyMjIENvbmNsdXNpb25zDQoNCk1hcmtvd2l0eiBQb3J0Zm9saW8gVGhlb3J5IGZvY3VzZXMgb24gY29uc3RydWN0aW5nIG9wdGltYWwgcG9ydGZvbGlvcyBieSBjb25zaWRlcmluZyB0b3RhbCByaXNrIGFuZCByZXR1cm4sIGhlbHBpbmcgaW52ZXN0b3JzIG1ha2UgZGVjaXNpb25zIGJhc2VkIG9uIHRoZWlyIHJpc2sgdG9sZXJhbmNlLg0KQ0FQTSBwcm92aWRlcyBhIG1ldGhvZCB0byBwcmljZSBpbmRpdmlkdWFsIGFzc2V0cyBieSByZWxhdGluZyBleHBlY3RlZCByZXR1cm5zIHRvIHN5c3RlbWF0aWMgcmlzaywgYXNzdW1pbmcgaW52ZXN0b3JzIGhvbGQgZGl2ZXJzaWZpZWQgcG9ydGZvbGlvcy4NCg0KVGhlIG1haW4gZGlmZmVyZW5jZSBsaWVzIGluIHRoZWlyIHRyZWF0bWVudCBvZiByaXNrOg0KICBNYXJrb3dpdHogY29uc2lkZXJzIGJvdGggc3lzdGVtYXRpYyBhbmQgdW5zeXN0ZW1hdGljIHJpc2suDQogIENBUE0gY29uc2lkZXJzIG9ubHkgc3lzdGVtYXRpYyByaXNrLCBhcyB1bnN5c3RlbWF0aWMgcmlzayBpcyBhc3N1bWVkIHRvIGJlIGRpdmVyc2lmaWVkIGF3YXkuDQoNCkluIHRoZSByZXN1bHRzIHdlIGNhbiBzZWUgdGhhdCB0aGUgb3V0Y29tZSBvZiB0aGUgTWFya293aXR6IG9wdGltaXphdGlvbiBpcyB0aGUgd2VpZ2h0IG9mIGVhY2ggYXNzZXQgaW4gdGhlIHBvcnRmb2xpbywgd2hlcmVhcyBvdXIgb3V0Y29tZSBmcm9tIHRoZSBDQVBNIGlzIHRoZSBiZXRhcyBhbmQgZXhwZWN0ZWQgcmV0dXJucyBvZiB0aGUgYXNzZXQuIA0KDQoNCiMjIyBJbXBsaWNhdGlvbnMgZm9yIEludmVzdG9ycw0KDQojIyMjIFBvcnRmb2xpbyBDb25zdHJ1Y3Rpb246DQoNCiAgVXNlIE1hcmtvd2l0eidzIGZyYW1ld29yayB0byBidWlsZCBhIGRpdmVyc2lmaWVkIHBvcnRmb2xpbyB0aGF0IGFsaWducyB3aXRoIHJpc2sgcHJlZmVyZW5jZXMuDQoNCg0KIyMjIyBBc3NldCBQcmljaW5nIGFuZCBFeHBlY3RlZCBSZXR1cm5zOg0KDQogIFVzZSBDQVBNIHRvIGVzdGltYXRlIHRoZSBleHBlY3RlZCByZXR1cm4gb2YgYW4gYXNzZXQgYmFzZWQgb24gaXRzIG1hcmtldCByaXNrIGFuZCB0byBhc3Nlc3Mgd2hldGhlciBpdCdzIG92ZXJ2YWx1ZWQgb3IgdW5kZXJ2YWx1ZWQuDQoNCg0KIyMjIEZpbmFsIGNvbW1lbnRzLiANCg0KV2UgaGF2ZSBvYnNlcnZlZCB0aGFua3MgdG8gb3VyIHJlcHJlc2VudGF0aW9ucyB0aGF0IGV2ZW4gaWYgYm90aCBtb2RlbHMgaGF2ZSBhIHNpbWlsYXIgb2JqZWN0aXZlLCB3aGljaCBpcyB0aGUgb3B0aW1pemF0aW9uIG9mIHRoZSByZXR1cm5zIGZvciB0aGUgaW52ZXN0b3JzLCBlYWNoIG9uZSBkb2VzIGl0IGluIGEgd2hvbGUgZGlmZmVyZW50IHdheSwgd2l0aCBkaWZmZXJlbnQgYXNzdW1wdGlvbnMsIGRpZmZlcmVudCB0cmVhdG1lbnQgb2YgcmlzayBhbmQgd2l0aCBhIGRpZmZlcmVudCByZXN1bHRzIHNjb3BlLiANCg0KDQoNCiMjIEwxMCBXQUNDDQoNCiMjIyBXQUNDIHJlcGxpY2F0aW9uDQoNCkxvYWQgbGlicmFyeQ0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShxdWFudG1vZCkNCmBgYA0KDQoNClJldHJpZXZlIHN0b2NrIGRhdGENCg0KYGBge3J9DQpnZXRTeW1ib2xzKCJBQVBMIikNCmBgYA0KDQoNCkRlZmluZSB0aGUgTnVtYmVyIG9mIE91dHN0YW5kaW5nIFNoYXJlcw0KDQpgYGB7cn0NCm91dHN0YW5kaW5nX3NoYXJlcyA8LSAxNjAwMDAwMDAwMCAgIyAxNiBiaWxsaW9uIHNoYXJlcw0KYGBgDQoNCg0KQ2FsY3VsYXRlIE1hcmtldCBDYXBpdGFsaXphdGlvbg0KDQpgYGB7cn0NCm1hcmtldF9jYXAgPC0gbGFzdChBQVBMJEFBUEwuQWRqdXN0ZWQpICogb3V0c3RhbmRpbmdfc2hhcmVzDQpgYGANCg0KDQpEZWZpbmUgdGhlIENvc3Qgb2YgRGVidA0KDQpgYGB7cn0NCmNvc3Rfb2ZfZGVidCA8LSAwLjAyICAjIDIlDQpgYGANCg0KDQpEZWZpbmUgVGF4IFJhdGUgQXBwbGljYWJsZSB0byBBcHBsZQ0KDQpgYGB7cn0NCnRheF9yYXRlIDwtIDAuMjEgICMgMjElDQpgYGANCg0KDQpPYnRhaW4gQmV0YSBmb3IgQXBwbGUncyBTdG9jaw0KDQpgYGB7cn0NCmJldGEgPC0gMS4yICAjIEJldGEgb2YgMS4yIGluZGljYXRlcyBoaWdoZXIgdm9sYXRpbGl0eSB0aGFuIHRoZSBtYXJrZXQNCmBgYA0KDQoNCkRlZmluZSB0aGUgUmlzay1GcmVlIFJhdGUNCg0KYGBge3J9DQpyaXNrX2ZyZWVfcmF0ZSA8LSAwLjAxNSANCmBgYA0KDQoNCkRlZmluZSB0aGUgTWFya2V0IFJpc2sgUHJlbWl1bQ0KDQpgYGB7cn0NCm1hcmtldF9yaXNrX3ByZW1pdW0gPC0gMC4wNg0KYGBgDQoNCg0KQ2FsY3VsYXRlIHRoZSBDb3N0IG9mIEVxdWl0eSB1c2luZyBDQVBNIE1vZGVsDQoNCmBgYHtyfQ0KY29zdF9vZl9lcXVpdHkgPC0gcmlza19mcmVlX3JhdGUgKyBiZXRhICogbWFya2V0X3Jpc2tfcHJlbWl1bQ0KYGBgDQoNCg0KRGVmaW5lIHRoZSBNYXJrZXQgVmFsdWUgb2YgRGVidA0KDQpgYGB7cn0NCm1hcmtldF92YWx1ZV9vZl9kZWJ0IDwtIDEwMGU5ICAjICQxMDAgYmlsbGlvbg0KYGBgDQoNCg0KQ2FsY3VsYXRlIFRvdGFsIE1hcmtldCBWYWx1ZQ0KDQpgYGB7cn0NCnRvdGFsX21hcmtldF92YWx1ZSA8LSBtYXJrZXRfY2FwICsgbWFya2V0X3ZhbHVlX29mX2RlYnQNCmBgYA0KDQoNCkNhbGN1bGF0ZSBXZWlnaHRzIG9mIERlYnQgYW5kIEVxdWl0eQ0KDQpgYGB7cn0NCndlaWdodF9vZl9kZWJ0IDwtIG1hcmtldF92YWx1ZV9vZl9kZWJ0IC8gdG90YWxfbWFya2V0X3ZhbHVlDQp3ZWlnaHRfb2ZfZXF1aXR5IDwtIG1hcmtldF9jYXAgLyB0b3RhbF9tYXJrZXRfdmFsdWUNCmBgYA0KDQoNCkNhbGN1bGF0ZSBXQUNDDQoNCmBgYHtyfQ0Kd2FjYyA8LSAod2VpZ2h0X29mX2RlYnQgKiBjb3N0X29mX2RlYnQgKiAoMSAtIHRheF9yYXRlKSkgKyAod2VpZ2h0X29mX2VxdWl0eSAqIGNvc3Rfb2ZfZXF1aXR5KQ0KYGBgDQoNCg0KRGlzcGxheSB0aGUgV0FDQw0KDQpgYGB7cn0NCmNhdCgiV0FDQyBmb3IgQXBwbGUgSW5jLjoiLCByb3VuZCh3YWNjICogMTAwLCAyKSwgIiUiKQ0KYGBgDQoNCg0KIyMjIEFuYWx5c2lzIG9mIHJlc3VsdHMuDQoNCkluIHRoaXMgZXhlcmNpc2Ugd2UgaGF2ZSByZXBsaWNhdGVkIGEgYmFzaWMgZXhhbXBsZSBvZiBXQUNDLiANCldBQ0MgcmVwcmVzZW50cyB0aGUgbWluaW11bSBhdmVyYWdlIHJldHVybiBBcHBsZSBtdXN0IGVhcm4gb24gaXRzIGV4aXN0aW5nIGFzc2V0cyB0byBzYXRpc2Z5IGl0cyBpbnZlc3RvcnMgYW5kIGNyZWRpdG9ycywgd2hpY2ggaW4gdGhpcyBjYXNlIG11c3QgYmUgOC41MiUuDQpUaGUgbG93ZXIgdGhlIFdBQ0MsIHRoZSBtb3JlIHByb2plY3RzIHRoZSBjb21wYW55IGNhbiB0YWtlIG9uIGdpdmVuIHRoZXkgaGF2ZSBwb3NpdGl2ZSBuZXQgcHJlc2VudCB2YWx1ZXMuIA0KV0FDQyBtYXkgdXNlIGluIGl0cyBjYWxjdWxhdGlvbnMgdGhlIGFmdGVyLXRheCBjb3N0IG9mIGRlYnQsIGFzIGludGVyZXN0IGlzIHRheC1kZWR1Y3RpYmxlLg0KQSBnb29kIGFzc2Vzc21lbnQgaW4gdGhlIG1peCBvZiBkZWJ0IGFuZCBlcXVpdHkgZmluYW5jaW5nIGlzIGNydWNpYWwgZm9yIHRoZSBzdGFiaWxpdHkgb2YgYSBjb21wYW55IGFuZCBpdHMgY2FwaXRhbCBzdHJ1Y3R1cmUuIA0KDQpUaGUgV0FDQyBhcHByb2FjaGVkIG1heSBiZSB1c2VkIGFzIGEgcG93ZXJmdWwgdG9vbCB0byBhc3NlcyBkaWZmZXJlbnQga2luZHMgb2Ygc2l0dWF0aW9uIHRoYXQgYSBjb21wYW55IG1heSBmYWNlLCBzdWNoIGFzIHByb2plY3QgZXZhbHVhdGlvbiwgY29ycG9yYXRlIGZpbmFuY2UgZGVjaXNpb25zIChtJkEgYW5kIGNhcGl0YWwgYnVkZ2V0aW5nKS4gSXQgaXMgYWxzbyBhIHVzZWZ1bCB0b29sIHVzZWQgZm9yIGludmVzdG9yIGFuYWx5c2lzLiANCg0KDQoNCiMjIEwxMS4xIC0gTDExLjYNCg0KDQojIyMgRGVmaW5pdGlvbnMNCg0KIyMjIyBGdXR1cmVzIENvbnRyYWN0DQoNCkEgZnV0dXJlcyBjb250cmFjdCBpcyBhIGZpbmFuY2lhbCBkZXJpdmF0aXZlIHVwb24gc29tZW9uZSBhZ3JlZXMgdG8gYnV5IG9yIHNlbGwgYSBkZXRlcm1pbmF0ZSBjb21tb2RpdHkgYXNzZXQgb3Igc2VjdXJpdHkgYXQgYW4gcHJlZGV0ZXJtaW5lZCBwcmljZSBhbmQgYW4gc3BlY2lmaWMgdGltZSBpbiB0aGUgZnV0dXJlLiBUaGUgYnV5ZXIgYWdyZWVzIGFuZCBiZWNvbWVzIG9ibGlnZWQgdG8gYnV5IGFuZCByZWNlaXZlIHRoZSBhc3NldCB3aGVyZWFzIHRoZSBzZWxsZXIgYWdyZWVzIHRvIHByb3ZpZGUgYW5kIG1ha2UgZGVsaXZlciBvZiB0aGUgYXNzZXQuIA0KDQojIyMjIENhbGwgT3B0aW9uDQoNCkEgY2FsbCBvcHRpb24gaXMgYSB0eXBlIG9mIGZpbmFuY2lhbCBjb250cmFjdCB3aGVyZSB0aGUgYnV5ZXIgaXMgZ2l2ZW4gdGhlIHJpZ2h0IHRvIGJ1eSBhIGNlcnRhaW4gYXNzZXQgb3IgaW5zdHJ1bWVudCBhdCBhbiBzcGVjaWZpZWQgcHJpY2UgYW5kIHRpbWUuIFRoZSBzZWxsZXIgb24gdGhlIG90aGVyIGhhbmQgaXMgb2JsaWdlZCB0byBzZWxsIHRoZSBhc3NldCBpZiB0aGUgYnV5ZXIgZXhlcmNpc2VzIHRoZSBjYWxsLiANClRoZSBvcHRpb24gaXMgYm91Z2h0IHVuZGVyIGEgcHJlbWl1bSwgc28gaWYgdGhlIGFzc2V0IGdvZXMgZG93biBpbiBwcmljZSBhbmQgdGhlIGJ1eWVyIGRvZXMgbm90IGV4ZWN1dGUgdGhlIG9wdGlvbiwgdGhlIHNlbGxlciB3aWxsIHByb2ZpdCBmcm9tIHRoZSBwcmVtaXVtLiBIb3dldmVyLCBpZiB0aGUgYXNzZXQgcHJpY2UgaW5jcmVhc2VzIGFuZCB0aGUgYnV5ZXIgZXhlY3V0ZXMgdGhlIG9wdGlvbiwgdGhlIHByb2ZpdCB0aGUgYnV5ZXIgd2lsbCBoYXZlIGlzIHRoZSBlbmQgdmFsdWUgb2YgdGhlIHN0b2NrIChwYXlvZmYpIG1pbnVzIHRoZSBwcmVtaXVtIHBhaWQgZm9yIHRoZSBvcHRpb24uIA0KQ2FsbCBvcHRpb25zIGhhdmUgbGltaXRlZCBsb3NlcyBmb3IgdGhlIGJ1eWVycyAodGhlIHByZW1pdW0gaXMgdGhlIG1heGltdW0gbG9zcykgYnV0IGhhcyBubyBwcm9maXQgbGltaXQuIA0KQ2FsbCBvcHRpb25zIGFyZSBkaXZpZGVkIGludG8gTG9uZyBDYWxsIE9wdGlvbnMgYW5kIFNob3J0IENhbGwgT3B0aW9ucyhpbiB0aGUgc2hvcnQgY2FsbCBvcHRpb25zLCBpdCBpcyB0aGUgc2VsbGVyIHRoZSBvbmUgd2hvIHByb21pc2VzIHRvIHNlbGwgYW4gYXNzZXQgYXQgYSBjZXJ0YWluIHByaWNlIGluIHRoZSBkYXRlIG9mIGV4cGlyYXRpb24pDQoNCldoZW4gdXNpbmcgY2FsbCBvcHRpb25zLCBpdCBpcyBvZnRlbiB0byBpbXBsZW1lbnQgYW4gc3RyYXRlZ3kgY2FsbGVkIGhlZGdpbmcsIGluIHdoaWNoIHlvdSBhbHNvIHRha2UgdGhlIG9wcG9zaXRlIHBvc2l0aW9uIGluIG9yZGVyIHRvIG1pdGlnYXRlIHBvdGVudGlhbCBsb3NzZXMuIFRoYXQgaXMsIHRoYXQgaWYgd2UgYXJlIHVzaW5nIGNhbGwgb3B0aW9ucywgd2UgbWlnaHQgYWxzbyBidXkgcHV0IG9wdGlvbnMgZm9yIHRoZSBzYW1lIGFzc2V0IHNvIHRoYXQgd2UgY2FuIHJlZHVjZSB0aGUgbG9zc2VzIGluIHRoZSBjYXNlIHRoYXQgdGhlIHN0cmlraW5nIHByaWNlIGlzIG5vdCByZWFjaGVkIGF0IHRoZSBkYXRlIG9mIGV4cGlyYXRpb24uIA0KDQoNCkxvYWQgUGFja2FnZXMNCg0KYGBge3J9DQojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMNCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoUGVyZm9ybWFuY2VBbmFseXRpY3MpDQpgYGANCg0KDQpEZWZpbmUgQmVnaW5uaW5nIGFuZCBFbmQgb2YgVGVybSBEYXRlcw0KDQpgYGB7cn0NCiMgRGVmaW5lIEJlZ2lubmluZyBvZiBUZXJtIChCb1QpIGFuZCBFbmQgb2YgVGVybSAoRW9UKSBkYXRlcw0KQm9UX2RhdGUgPC0gYXMuRGF0ZSgiMjAyNC0wNS0wMSIpDQpFb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA5LTMwIikNCmBgYA0KDQoNCg0KIyMjIEwxMS4xIENhbGN1bGF0aW5nIHRoZSBEaWZmZXJlbmNlIGluIHRoZSBEb2xsYXIgVmFsdWUgb2YgdGhlIFMmUCA1MDAgRnV0dXJlcyBDb250cmFjdA0KIA0KICAtWW91IHB1cmNoYXNlZCBhbiBTJlAgNTAwIGZ1dHVyZXMgY29udHJhY3QgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgdGVybS4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIC1Zb3Ugc29sZCB0aGUgc2FtZSBmdXR1cmVzIGNvbnRyYWN0IGF0IHRoZSBlbmQgb2YgdGhlIHRlcm0uDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgLVRoZSBjb250cmFjdCB2YWx1ZSBpcyBmdXR1cmVzIHByaWNlIHRpbWVzICQyNTAuDQoNClNpbmNlIGdldHRpbmcgaGlzdG9yaWNhbCBmdXR1cmVzIHByaWNlcyBjYW4gYmUgY2hhbGxlbmdpbmcsIHdlJ2xsIHVzZSB0aGUgUyZQIDUwMCBpbmRleCAoXkdTUEMpIGFzIGEgcHJveHkgZm9yIHRoZSBmdXR1cmVzIHByaWNlcy4NCsK0DQoNCjEuIFJldHJpZXZlIFMmUDUwMCBpbmRleCBkYXRhDQoNCmBgYHtyfQ0Kc3RhcnRfZGF0ZSA8LSBCb1RfZGF0ZSAtIDcNCmVuZF9kYXRlIDwtIEVvVF9kYXRlICsgNw0KDQpnZXRTeW1ib2xzKCJeR1NQQyIsIHNyYyA9ICJ5YWhvbyIsIGZyb20gPSBzdGFydF9kYXRlLCB0byA9IGVuZF9kYXRlKQ0KDQpgYGANCg0KDQoyLiBEZWZpbmUgYSBGdW5jdGlvbiB0byBHZXQgUHJpY2VzIG9uIFNwZWNpZmljIERhdGVzDQoNCmBgYHtyfQ0KIyBGdW5jdGlvbiB0byBnZXQgdGhlIGFkanVzdGVkIGNsb3NpbmcgcHJpY2Ugb24gYSBzcGVjaWZpYyBkYXRlDQpnZXRfcHJpY2Vfb25fZGF0ZSA8LSBmdW5jdGlvbihkYXRhLCBkYXRlKSB7DQogIGluZGV4KGRhdGEpIDwtIGFzLkRhdGUoaW5kZXgoZGF0YSkpDQogIA0KICBhdmFpbGFibGVfZGF0ZXMgPC0gaW5kZXgoZGF0YSlbaW5kZXgoZGF0YSkgPD0gZGF0ZV0NCiAgDQogIGlmIChsZW5ndGgoYXZhaWxhYmxlX2RhdGVzKSA9PSAwKSB7DQogICAgd2FybmluZyhwYXN0ZSgiTm8gZGF0YSBhdmFpbGFibGUgb24gb3IgYmVmb3JlIiwgZGF0ZSkpDQogICAgcmV0dXJuKGxpc3QoUHJpY2UgPSBOQSwgRGF0ZSA9IE5BKSkNCiAgfQ0KICANCiAgZGF0ZV91c2VkIDwtIG1heChhdmFpbGFibGVfZGF0ZXMpDQogIA0KICBwcmljZSA8LSBhcy5udW1lcmljKENsKGRhdGFbZGF0ZV91c2VkXSkpDQogIA0KICByZXR1cm4obGlzdCgNCiAgICBQcmljZSA9IHByaWNlLA0KICAgIERhdGUgPSBhcy5EYXRlKGRhdGVfdXNlZCkNCiAgKSkNCn0NCmBgYA0KDQoNCkdldCBTJlA1MDAgcHJpY2VzIGF0IEJvVCBhbmQgRW9UDQoNCmBgYHtyfQ0KcHJpY2VfQm9UIDwtIGdldF9wcmljZV9vbl9kYXRlKGBHU1BDYCwgQm9UX2RhdGUpDQpwcmljZV9Fb1QgPC0gZ2V0X3ByaWNlX29uX2RhdGUoYEdTUENgLCBFb1RfZGF0ZSkNCg0KY2F0KCJTJlAgNTAwIEluZGV4IFByaWNlIGF0IEJvVCAoIiwgcHJpY2VfQm9UJERhdGUsICIpOiAiLCBwcmljZV9Cb1QkUHJpY2UsICJcbiIsIHNlcCA9ICIiKQ0KY2F0KCJTJlAgNTAwIEluZGV4IFByaWNlIGF0IEVvVCAoIiwgcHJpY2VfRW9UJERhdGUsICIpOiAiLCBwcmljZV9Fb1QkUHJpY2UsICJcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIHRoZSBDb250cmFjdCBWYWx1ZXMNCg0KYGBge3J9DQpjb250cmFjdF92YWx1ZV9Cb1QgPC0gcHJpY2VfQm9UJFByaWNlICogMjUwDQpjb250cmFjdF92YWx1ZV9Fb1QgPC0gcHJpY2VfRW9UJFByaWNlICogMjUwDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIGRpZmZlcmVuY2UNCg0KYGBge3J9DQpkaWZmZXJlbmNlIDwtIGNvbnRyYWN0X3ZhbHVlX0VvVCAtIGNvbnRyYWN0X3ZhbHVlX0JvVA0KDQpjYXQoIkRpZmZlcmVuY2UgaW4gQ29udHJhY3QgVmFsdWVzOiAkIiwgcm91bmQoZGlmZmVyZW5jZSwgMiksICJcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcw0KDQpUaGUgc2lnbmlmaWNhbnQgaW5jcmVhc2UgaW4gdGhlIHByaWNlIG9mIHRoZSBTJlA1MDAgZHVyaW5nIHRoZSB0ZXJtIGhhcyBsZWQgdG8gYSBmaW5hbCBkaWZmZXJlbmNlIGluIHRoZSBjb250cmFjdCB2YWx1ZSBvZiAxODYwMjIuNSBVU0QuIEluIHRoaXMgZXhhbXBsZSB3ZSBjYW4gZWFzaWx5IG9ic2VydmUgaG93IHRoZSBmbHVjdHVhdGlvbiBvZiBwcmljZSBjYW4gZW5vcm1vdXNseSBhZmZlY3QgdGhlIHByaWNlIG9mIHRoZSBjb250cmFjdCwgd2hpY2ggbWFrZXMgaGVkZ2luZyBzdHJhdGVnaWVzIG11Y2ggbW9yZSBhdHRyYWN0aXZlLiBBbHRob3VnaCB0aGV5IG1heSByZWR1Y2UgdGhlIHRvdGFsIHByb2ZpdCwgYSBmdXR1cmVzIHRyYWRlciB3aWxsIG92ZXJhbGwgYmVuZWZpdCBmcm9tIHRoZW0gYXMgbG9zZXMgd2lsbCBiZSBncmVhdGx5IG1pdGlnYXRlZCBhbmQgdGhlIG91dGNvbWUgb2YgYSBiYWQgb3BlcmF0aW9uIHdpbGwgbm90IGJlIGFzIGNhdGFzdHJvcGhpYyBhcyBpdCBtYXkgYmUgaWYgdGhlcmUgaXMgbm8gY291bnRlcnBhcnQgdGhhdCBiYWNrcyBpdCB1cC4gDQoNCg0KDQojIyMgTDExLjIgQ2FsY3VsYXRpbmcgWW91ciBSZXR1cm4gZnJvbSB0aGUgRnV0dXJlcyBQb3NpdGlvbg0KICAtWW91IGludmVzdGVkIGFuIGluaXRpYWwgbWFyZ2luIG9mIDIwJSBvZiB0aGUgZnV0dXJlcyBjb250cmFjdCB2YWx1ZSBhdCBCb1QNCiAgLVlvdXIgcmV0dXJuIGlzIHRoZSBnYWluIGZyb20gdGhlIGZ1dHVyZXMgcG9zaXRpb24gZGl2aWRlZCBieSB5b3VyIGluaXRpYWwgaW52ZXN0bWVudA0KDQoNCkNhbGN1bGF0ZSBJbml0aWFsIEludmVzdG1lbnQNCg0KYGBge3J9DQppbml0aWFsX2ludmVzdG1lbnQgPC0gMC4yMCAqIGNvbnRyYWN0X3ZhbHVlX0JvVA0KDQpjYXQoIkluaXRpYWwgSW52ZXN0bWVudCAoMjAlIE1hcmdpbik6ICQiLCByb3VuZChpbml0aWFsX2ludmVzdG1lbnQsIDIpLCAiXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCkNhbGN1bGF0ZSBSZXR1cm4gb24gSW52ZXN0bWVudA0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIHRoZSByZXR1cm4NCnJldHVybl9mdXR1cmVzIDwtIGRpZmZlcmVuY2UgLyBpbml0aWFsX2ludmVzdG1lbnQNCg0KIyBQcmludCB0aGUgcmV0dXJuIGFzIGEgcGVyY2VudGFnZQ0KY2F0KCJSZXR1cm4gb24gRnV0dXJlcyBQb3NpdGlvbjogIiwgcm91bmQocmV0dXJuX2Z1dHVyZXMgKiAxMDAsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQpgYGANCg0KDQojIyMjIEFuYWx5c2lzDQpBcyBhIGZvbGxvdyB1cCBmcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZSwgd2UgaGF2ZSB0aGUgZmluYWwgcmV0dXJuIG9mIHRoZSBmdXR1cmVzIHBvc2l0aW9uIHRoYXQgc3VtcyB0byBhIHRvdGFsIG9mIDc0LjE0JSBpbiB0aGUgZHVyYXRpb24gb2YgdGhlIHNjaG9vbCB0ZXJtLiBXaXRoIHN1Y2ggaGlnaCByZXR1cm5zLCBhbmQgYXMgd2UgaGF2ZSBleHBsYWluZWQgYmVmb3JlLCB3ZSBzaGFsbCBiYXJlIGluIG1pbmQgdGhhdCBlcXVhbGx5IGhpZ2ggbG9zc2VzIG1heSBiZSBvYnRhaW5lZC4gVGhlcmVmb3JlLCBkZWVwIGtub3dsZWRnZSBvZiB0aGUgdW5kZXJseWluZyBhc3NldCBhbmQgYSBnb29kIHRyYWRpbmcgc3RyYXRlZ3kgYXJlIGV4dHJlbWVseSBpbXBvcnRhbnQgaW4gb3JkZXIgdG8gcGVyZm9ybSBzdWNoIG9wZXJhdGlvbnMuIA0KDQoNCg0KIyMjIEwxMS4zIEFubnVhbGl6aW5nIFlvdXIgUmV0dXJuDQogIC1UaGUgcmV0dXJuIGNhbGN1bGF0ZWQgaXMgZm9yIHRoZSBkdXJhdGlvbiBvZiB0aGUgc2Nob29sIHRlcm0gKDUgbW9udGhzKQ0KICAtVG8gYW5udWFsaXplIHRoZSByZXR1cm4sIHdlIG11bHRpcGx5IGl0IGJ5IDEyL20sIHdoZXJlIG0gfiA1IG1vbnRocyANCg0KDQpDYWxjdWxhdGUgdGhlIGFubnVhbGl6YXRpb24NCg0KYGBge3J9DQptIDwtIGFzLm51bWVyaWMoZGlmZnRpbWUoRW9UX2RhdGUsIEJvVF9kYXRlLCB1bml0cyA9ICJkYXlzIikpIC8gMzAuNDQNCg0KYW5udWFsaXplZF9yZXR1cm5fZnV0dXJlcyA8LSByZXR1cm5fZnV0dXJlcyAqICgxMiAvIG0pDQoNCmNhdCgiQW5udWFsaXplZCBSZXR1cm4gb24gRnV0dXJlcyBQb3NpdGlvbjogIiwgcm91bmQoYW5udWFsaXplZF9yZXR1cm5fZnV0dXJlcyAqIDEwMCwgMiksICIlXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCiMjIyMgQ29tbWVudHMNClByZXZpb3VzbHksIHdlIGhhZCBvbmx5IG9idGFpbmVkIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBmdXR1cmVzIGNvbnRyYWN0IHByaWNlIGFuZCB0aGUgcmV0dXJuIG9idGFpbmVkIGluIHRoZSBkdXJhdGlvbiBvZiB0aGUgc2Nob29sIHRlcm0uIE5vdywgd2UgaGF2ZSBvYnRhaW5lZCB0aGUgYW5udWFsaXplZCByZXR1cm4sIHdoaWNoIGRlcGljdHMgdGhlIGF2ZXJhZ2UgcmF0ZSBvZiByZXR1cm4gcGVyIHllYXIuIFdlIGFubnVhbGl6ZSBvdXIgcmV0dXJucyB0byBiZXR0ZXIgY29tcGFyZSB0aGVtIHdpdGggb3RoZXIgcG9zc2libGUgc3R1ZGllZCByZXR1cm5zLCBhcyByZXR1cm5zIGFyZSB1c3VhbGx5IHByZXNlbnRlZCBhcyBwZXIgeWVhci4gDQoNCg0KIyMjIEwxMS40IENhbGN1bGF0aW5nIHRoZSBSZXR1cm4gZnJvbSBQdXJjaGFzaW5nIGEgQ2FsbCBPcHRpb24gb24gQXBwbGUgSW5jLiAoQUFQTCkNCiAgDQogIC1QdXJjaGFzZSBvZiBhIGNhbGwgb3B0aW9uIHJlcHJlc2VudGluZyAxMDAgc2hhcmVzIG9mIEFBUEwgYXQgQm9UDQogIC1EZXRlcm1pbmUgdGhlIHJldHVybiBiYXNlZCBvbiB0aGUgb3B0aW9uIHByZW1pdW1zIGF0IEJPVCBhbmQgRW9UDQogIElmIHRoZSBwcmVtaXVtIGF0IEVvVCBpcyB1bmF2YWlsYWJsZSwgY2FsY3VsYXRlIHRoZSByZXR1cm4gYmFzZWQgb24gZXhlcmNpc2luZyB0aGUgb3B0aW9uDQoNCldlIHdpbGwgZXN0aW1hdGUgdGhlIG9wdGlvbiBwcmVtaXVtcyB1c2luZyB0aGUgQmxhY2stU2Nob2xlcyBNb2RlbA0KDQoNCg0KUmV0cmlldmUgQUFQTCBTdG9jayBQcmljZXMNCg0KYGBge3J9DQpnZXRTeW1ib2xzKCJBQVBMIiwgc3JjID0gInlhaG9vIiwgZnJvbSA9IHN0YXJ0X2RhdGUsIHRvID0gZW5kX2RhdGUpDQoNCnByaWNlX0FBUExfQm9UIDwtIGdldF9wcmljZV9vbl9kYXRlKEFBUEwsIEJvVF9kYXRlKQ0KcHJpY2VfQUFQTF9Fb1QgPC0gZ2V0X3ByaWNlX29uX2RhdGUoQUFQTCwgRW9UX2RhdGUpDQoNCmNhdCgiQUFQTCBTdG9jayBQcmljZSBhdCBCb1QgKCIsIHByaWNlX0FBUExfQm9UJERhdGUsICIpOiAkIiwgcm91bmQocHJpY2VfQUFQTF9Cb1QkUHJpY2UsIDIpLCAiXG4iLCBzZXAgPSAiIikNCmNhdCgiQUFQTCBTdG9jayBQcmljZSBhdCBFb1QgKCIsIHByaWNlX0FBUExfRW9UJERhdGUsICIpOiAkIiwgcm91bmQocHJpY2VfQUFQTF9Fb1QkUHJpY2UsIDIpLCAiXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNClNldCB0aGUgU3RyaWtlIFByaWNlDQoNCmBgYHtyfQ0KU3RyaWtlX1ByaWNlIDwtIGNlaWxpbmcocHJpY2VfQUFQTF9Cb1QkUHJpY2UgLyA1KSAqIDUNCg0KY2F0KCJPcHRpb24gU3RyaWtlIFByaWNlOiAkIiwgU3RyaWtlX1ByaWNlLCAiXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCkVzdGltYXRlIFZvbGF0aWxpdHkNCg0KYGBge3J9DQpzdGFydF9kYXRlX3ZvbCA8LSBCb1RfZGF0ZSAtIHllYXJzKDEpDQpnZXRTeW1ib2xzKCJBQVBMIiwgc3JjID0gInlhaG9vIiwgZnJvbSA9IHN0YXJ0X2RhdGVfdm9sLCB0byA9IEJvVF9kYXRlKQ0KDQpyZXR1cm5zIDwtIG5hLm9taXQoZGFpbHlSZXR1cm4oQ2woQUFQTCkpKQ0KDQp2b2xhdGlsaXR5IDwtIHNkKHJldHVybnMpICogc3FydCgyNTIpDQoNCmNhdCgiRXN0aW1hdGVkIEFubnVhbGl6ZWQgVm9sYXRpbGl0eTogIiwgcm91bmQodm9sYXRpbGl0eSAqIDEwMCwgMiksICIlXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCkRlZmluZSB0aGUgQmxhY2stU2Nob2xlcyBGdW5jdGlvbg0KDQpgYGB7cn0NCkJsYWNrU2Nob2xlc0NhbGwgPC0gZnVuY3Rpb24oUywgSywgciwgVCwgc2lnbWEpIHsNCiAgZDEgPC0gKGxvZyhTIC8gSykgKyAociArIHNpZ21hXjIgLyAyKSAqIFQpIC8gKHNpZ21hICogc3FydChUKSkNCiAgZDIgPC0gZDEgLSBzaWdtYSAqIHNxcnQoVCkNCiAgQyA8LSBTICogcG5vcm0oZDEpIC0gSyAqIGV4cCgtciAqIFQpICogcG5vcm0oZDIpDQogIHJldHVybihDKQ0KfQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIE9wdGlvbiBQcmVtaXVtcyBhdCBCb1QgYW5kIEVvVA0KDQpgYGB7cn0NCiMgU2V0IHJpc2stZnJlZSByYXRlIChlLmcuLCAyJSkNCnJpc2tfZnJlZV9yYXRlIDwtIDAuMDINCg0KIyBUaW1lIHRvIGV4cGlyYXRpb24gKGFzc3VtZSBvcHRpb24gZXhwaXJlcyBvbiBuZXh0IG1vbnRoJ3MgdGhpcmQgRnJpZGF5KQ0KVF9Cb1QgPC0gYXMubnVtZXJpYyhkaWZmdGltZShhcy5EYXRlKCIyMDI0LTExLTE1IiksIHByaWNlX0FBUExfQm9UJERhdGUsIHVuaXRzID0gImRheXMiKSkgLyAzNjUNClRfRW9UIDwtIGFzLm51bWVyaWMoZGlmZnRpbWUoYXMuRGF0ZSgiMjAyNC0xMS0xNSIpLCBwcmljZV9BQVBMX0VvVCREYXRlLCB1bml0cyA9ICJkYXlzIikpIC8gMzY1IA0KQ19Cb1QgPC0gQmxhY2tTY2hvbGVzQ2FsbChTID0gcHJpY2VfQUFQTF9Cb1QkUHJpY2UsIEsgPSBTdHJpa2VfUHJpY2UsIHIgPSByaXNrX2ZyZWVfcmF0ZSwgVCA9IFRfQm9ULCBzaWdtYSA9IHZvbGF0aWxpdHkpDQpDX0VvVCA8LSBCbGFja1NjaG9sZXNDYWxsKFMgPSBwcmljZV9BQVBMX0VvVCRQcmljZSwgSyA9IFN0cmlrZV9QcmljZSwgciA9IHJpc2tfZnJlZV9yYXRlLCBUID0gVF9Fb1QsIHNpZ21hID0gdm9sYXRpbGl0eSkNCg0KY2F0KCJPcHRpb24gUHJlbWl1bSBhdCBCb1Q6ICQiLCByb3VuZChDX0JvVCwgMiksICJcbiIsIHNlcCA9ICIiKQ0KY2F0KCJPcHRpb24gUHJlbWl1bSBhdCBFb1Q6ICQiLCByb3VuZChDX0VvVCwgMiksICJcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIHRoZSBSZXR1cm4gZnJvbSB0aGUgT3B0aW9uDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgcmV0dXJuIGJhc2VkIG9uIHNlbGxpbmcgdGhlIG9wdGlvbiBhdCBFb1QNCmlmICghaXMubmEoQ19Fb1QpKSB7DQogIHJldHVybl9vcHRpb25fc2VsbCA8LSAoQ19Fb1QgLSBDX0JvVCkgLyBDX0JvVA0KICBjYXQoIlJldHVybiBmcm9tIFNlbGxpbmcgdGhlIENhbGwgT3B0aW9uOiAiLCByb3VuZChyZXR1cm5fb3B0aW9uX3NlbGwgKiAxMDAsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQp9IGVsc2Ugew0KICBjYXQoIk9wdGlvbiBwcmVtaXVtIGF0IEVvVCBpcyB1bmF2YWlsYWJsZS5cbiIpDQp9DQoNCiMgQ2FsY3VsYXRlIHJldHVybiBiYXNlZCBvbiBleGVyY2lzaW5nIHRoZSBvcHRpb24NCmlmIChwcmljZV9BQVBMX0VvVCRQcmljZSA+IFN0cmlrZV9QcmljZSkgew0KICBwcm9maXRfZXhlcmNpc2UgPC0gKHByaWNlX0FBUExfRW9UJFByaWNlIC0gU3RyaWtlX1ByaWNlKSAtIENfQm9UDQogIHJldHVybl9vcHRpb25fZXhlcmNpc2UgPC0gcHJvZml0X2V4ZXJjaXNlIC8gQ19Cb1QNCiAgY2F0KCJSZXR1cm4gZnJvbSBFeGVyY2lzaW5nIHRoZSBDYWxsIE9wdGlvbjogIiwgcm91bmQocmV0dXJuX29wdGlvbl9leGVyY2lzZSAqIDEwMCwgMiksICIlXG4iLCBzZXAgPSAiIikNCn0gZWxzZSB7DQogIHByb2ZpdF9leGVyY2lzZSA8LSAtQ19Cb1QNCiAgcmV0dXJuX29wdGlvbl9leGVyY2lzZSA8LSBwcm9maXRfZXhlcmNpc2UgLyBDX0JvVA0KICBjYXQoIk9wdGlvbiBleHBpcmVkIHdvcnRobGVzcy4gUmV0dXJuIGZyb20gRXhlcmNpc2luZyB0aGUgQ2FsbCBPcHRpb246ICIsIHJvdW5kKHJldHVybl9vcHRpb25fZXhlcmNpc2UgKiAxMDAsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQp9DQoNCmBgYA0KDQoNCiMjIyMgQW5hbHlzaXMNCg0KSW4gdGhpcyBleGVyY2lzZSwgd2UgaGF2ZSBvcHRlZCBmb3IgY2FsY3VsYXRpbmcgdGhlIHByZW1pdW1zIHdpdGggdGhlIHVzZSBvZiB0aGUgQmxhY2sgU2Nob2xlcyBNb2RlbC4gVGhpcyBkZWNpc2lvbiBoYXMgdGFrZW4gZHVlIHRvIHRoZSBpbmFjY2Vzc2liaWxpdHkgb2YgZGlyZWN0IGRhdGEgYWJvdXQgdGhlIHByZW1pdW1zIGZvciB0aGUgb3B0aW9ucy4gVGhlIEJsYWNrLVNjaG9sZXMgTW9kZWwgYWxsb3dzIHVzIHRvIGNhbGN1bGF0ZSB0aGUgdGhlb3JldGljYWwgdmFsdWUgb2YgZGVyaXZhdGl2ZXMgYnkgdGFraW5nIGludG8gYWNjb3VudCA1IHZhcmlhYmxlczogc3RyaWtlIHByaWNlIG9mIHRoZSBvcHRpb24sIGN1cnJlbnQgc3RvY2sgcHJpY2UsIHRpbWUgdG8gZXhwaXJhdGlvbiwgcmlzay1mcmVlIHJhdGUgYW5kIHZvbGF0aWxpdHkuIFRoZSBlc3RpbWF0aW9uIG9idGFpbmVkIHdpdGggdGhpcyBtb2RlbCBtYXkgZGVyaXZlIGZyb20gdGhlIHJlYWwgdmFsdWVzLiANCldoZW4gdXNpbmcgdGhpcyBtb2RlbCwgd2Ugc2hvdWxkIGFsc28gdGFrZSBpbnRvIGFjY291bnQgdGhhdCBkZXBlbmRpbmcgb24gb3VyIGxvY2F0aW9uLCBvcHRpb25zIGNvdWxkIGJlIGV4ZXJjaXNlZCBiZWZvcmUgdGhlIGV4cGlyYXRpb24gZGF0ZS4gSG93ZXZlciBmb3IgdGhpcyBleGVyY2lzZSB3ZSB3aWxsIG5vdCB0YWtlIHRoYXQgaW50byBhY2NvdW50LiANCldlIGhhdmUgYWxzbyB0YWtlbiBpbnRvIGFjY291bnQgdGhlIHR3byBvcHRpb25zIHRoYXQgY291bGQgaGFwcGVuIHdoZW4gYnV5aW5nIHRoaXMgY2FsbCBvcHRpb246IHRvIGV4ZXJjaXNlIGl0IG9yIHRvIGJ1eSBpdC4gDQpXaGVuIHdlIHNlbGwgdGhlIGNhbGwgb3B0aW9uLCB0aGUgdG90YWwgbm9uLWFubnVhbGl6ZWQgcmV0dXJuIHdpbGwgYmUgNTE0LjUxJSwgd2hlcmVhcyBpZiB3ZSBleGVyY2lzZSBpdCBpdCBpcyA1MTAuMzYlLiANCkluIHRoZSBjYXNlIG9mIHNlbGxpbmcsIHRoZSBwcm9maXQgb3IgcmV0dXJuIG9idGFpbmVkIHdpbGwgYmUgY2FsY3VsYXRlZCB3aXRoIHRoZSBwcmVtaXVtcy4gSWYgdGhlIHByZW1pdW0gYXQgdGhlIEVuZCBvZiBUZXJtIHdhcyB1bmF2YWlsYWJsZSBvciB3ZSBkZWNpZGVkIHRvIGV4ZXJjaXNlIHRoZSBvcHRpb24sIHRoZSBwcm9maXQgb2J0YWluZWQgd2lsbCBiZSB0aGUgcHJpY2Ugb2YgdGhlIHN0b2NrIGF0IHRoZSBtb21lbnQgb2YgZXhlcmNpc2UgbWludXMgdGhlIHN0cmlrZSBwcmljZSBhbmQgdGhlIHByZW1pdW0uIEJvdGggcmV0dXJucyBhcmUgcmF0aGVyIHNpbWlsYXIsIGFsdGhvdWdoIHRoZSByZXR1cm4gZnJvbSBzZWxsaW5nIHRoZSBvcHRpb24gaXMgbm90aWNlYWJseSBoaWdoZXIuIA0KDQojIyMgTDExLjUgQW5udWFsaXppbmcgdGhlIFJldHVybiBvbiBZb3VyIE9wdGlvbg0KDQpgYGB7cn0NCiMgQW5udWFsaXplIHRoZSBSZXR1cm5zDQphbm51YWxpemVkX3JldHVybl9vcHRpb25fc2VsbCA8LSAocmV0dXJuX29wdGlvbl9zZWxsKSooMTIgLyBtKQ0KYW5udWFsaXplZF9yZXR1cm5fb3B0aW9uX2V4ZXJjaXNlIDwtICgocmV0dXJuX29wdGlvbl9leGVyY2lzZSkqKDEyIC8gbSkpIA0KDQojIERpc3BsYXkgdGhlIEFubnVhbGl6ZWQgUmV0dXJucw0KY2F0KCJcbkFubnVhbGl6ZWQgUmV0dXJuIGZyb20gU2VsbGluZyB0aGUgQ2FsbCBPcHRpb246ICIsIHJvdW5kKGFubnVhbGl6ZWRfcmV0dXJuX29wdGlvbl9zZWxsICogMTAwLCAyKSwgIiVcbiIsIHNlcCA9ICIiKQ0KY2F0KCJBbm51YWxpemVkIFJldHVybiBmcm9tIEV4ZXJjaXNpbmcgdGhlIENhbGwgT3B0aW9uOiAiLCByb3VuZChhbm51YWxpemVkX3JldHVybl9vcHRpb25fZXhlcmNpc2UgKiAxMDAsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQpgYGANCg0KDQojIyMjIENvbW1lbnRzDQoNCldpdGggdGhlIGFubnVhbGl6YXRpb24gb2YgdGhlIHJlc3VsdHMgd2Ugb2J0YWluIGEgcmV0dXJuIG9mIDEyMzYuNDQlIGFuZCAxMjI2LjQ3JSByZXNwZWN0aXZlbHkuIEFzIHdlIGtub3csIHRoZSBhbm51YWxpemF0aW9uIGlzIHVzdWFsbHkgZG9uZSBpbiBvcmRlciB0byBiZXR0ZXIgY29tcGFyZSB0aGUgcmV0dXJucyB3aXRoIG90aGVycy4gDQoNCg0KDQojIyMgTDExLjYgQ29tcGFyaW5nIHRoZSBSZXR1cm4gb24gWW91ciBDYWxsIE9wdGlvbiB0byBJbnZlc3RpbmcgaW4gdGhlIFN0b2NrDQoNCg0KQ2FsY3VsYXRlIHRoZSBSZXR1cm4gZnJvbSBJbnZlc3RpbmcgaW4gQUFQTCBzdG9jaw0KDQpgYGB7cn0NCnJldHVybl9zdG9jayA8LSAocHJpY2VfQUFQTF9Fb1QkUHJpY2UgLSBwcmljZV9BQVBMX0JvVCRQcmljZSkgLyBwcmljZV9BQVBMX0JvVCRQcmljZQ0KDQphbm51YWxpemVkX3JldHVybl9zdG9jayA8LSByZXR1cm5fc3RvY2sgKiAoMTIgLyBtKQ0KDQpjYXQoIlJldHVybiBmcm9tIEludmVzdGluZyBpbiBBQVBMIFN0b2NrOiAiLCByb3VuZChyZXR1cm5fc3RvY2sgKiAxMDAsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQpjYXQoIkFubnVhbGl6ZWQgUmV0dXJuIG9uIEFBUEwgU3RvY2s6ICIsIHJvdW5kKGFubnVhbGl6ZWRfcmV0dXJuX3N0b2NrICogMTAwLCAyKSwgIiVcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KQ29tcGFyZSB0aGUgcmV0dXJucw0KDQpgYGB7cn0NCmNhdCgiXG5Db21wYXJpc29uIG9mIFJldHVybnM6XG4iKQ0KY2F0KCJBbm51YWxpemVkIFJldHVybiBvbiBDYWxsIE9wdGlvbjogIiwgcm91bmQoYW5udWFsaXplZF9yZXR1cm5fb3B0aW9uX3NlbGwgKiAxMDAsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQpjYXQoIkFubnVhbGl6ZWQgUmV0dXJuIGZyb20gRXhlcmNpc2luZyB0aGUgQ2FsbCBPcHRpb246ICIsIHJvdW5kKGFubnVhbGl6ZWRfcmV0dXJuX29wdGlvbl9leGVyY2lzZSAqIDEwMCwgMiksICIlXG4iLCBzZXAgPSAiIikNCmNhdCgiQW5udWFsaXplZCBSZXR1cm4gb24gQUFQTCBTdG9jazogIiwgcm91bmQoYW5udWFsaXplZF9yZXR1cm5fc3RvY2sgKiAxMDAsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQpgYGANCg0KDQojIyMjIEFuYWx5c2lzDQpJbiB0aGlzIGZpbmFsIGV4ZXJjaXNlIHdlIGNvbXBhcmUgdGhlIHJldHVybnMgb2YgdGhlIFJldHVybiBvZiB0aGUgU3RvY2sgd2l0aCB0aG9zZSBvZiB0aGUgY2FsbCBvcHRpb24sIGJvdGggd2hlbiBzZWxsaW5nIGFuZCB3aGVuIGV4ZXJjaXNpbmcgaXQuIEFzIHdlIGNhbiBvYnNlcnZlLCB0aGUgcG90ZW50aWFsIHJldHVybnMgb2YgdGhlIGNhbGwgb3B0aW9ucyBodWdlbHkgb3V0d2VpZ2ggdGhvc2Ugb2YgdGhlIFN0b2NrIGl0c2VsZi4gSW4gdGhlIGNhc2Ugb2YgdGhlIGNhbGwgb3B0aW9uLCBhcyB3ZSBoYXZlIG1lbnRpb25lZCwgdGhlIHBvdGVudGlhbCBsb3NzIGZvciB0aGUgYnV5ZXIgaXMgbGltaXRlZCB0byB0aGUgcHJlbWl1bSB0aGF0IHRoZXkgc2hhbGwgcGF5IHdoZW4gYnV5aW5nIHRoZSBvcHRpb24uIEhvd2V2ZXIsIGZvciB0aGUgc2VsbGVyIG9mIHRoaXMgb3B0aW9uLCB0aGUgcmlzayBiZWNvbWVzIGV4dHJlbWVseSBub3RpY2VhYmxlLiANCg0KDQoNCiMjIEwxMS43IERldGVybWluaW5nIFN3YXAgUGF5bWVudHMNCg0KDQojIyMgRGVmaW5pdGlvbnMNCg0KIyMjIyBTd2Fwcw0KU3dhcHMgYXJlIGEga2luZCBvZiBkZXJpdmF0aXZlIGNvbnRyYWN0IGluIHdoaWNoIHRoZSB0d28gcGFydGllcyBpbnZvbHZlZCBleGNoYW5nZSBhc3NldHMgd2l0aCB0aGVpciBjb3JyZXNwb25kaW5nIGNhc2ggZmxvd3Mgb3ZlciBhbiBlc3RhYmxpc2hlZCBwZXJpb2Qgb2YgdGltZS4gT25lIG9mIHRoZSB0d28gY2FzaCBmbG93cyBpbnZvbHZlZCB3aWxsIGJlIGZpeGVkLCB3aGVyZWFzIHRoZSBvdGhlciBvbmUgd2lsbCBiZSB2YXJpYWJsZSBhbmQgZGVwZW5kZW50IG9uIGFuIGluZGV4IHByaWNlLCBpbnRlcmVzdCByYXRlIG9yIGN1cnJlbmN5IGV4Y2hhbmdlIHJhdGUuIFRoZSB2YXJpYWJsZSBuYXR1cmUgb2Ygb25lIHBhcnR5IGFnYWluc3QgdGhlIGZpeGVkIG9uZSBvZiB0aGUgb3RoZXIgcmVzdWx0cyBpbiBzb21lIHN3YXAgY29udHJhY3RzIGJlaW5nIHZlcnkgcmlza3kgYW5kIHRoZXkgaW52b2x2ZSBncmVhdCBzcGVjaWFsaXphdGlvbiBhbmQgYSBkZWVwIHVuZGVyc3RhbmRpbmcgb2YgdGhlIHVuZGVybHlpbmcgaW5kZXgvcmF0ZS4gDQpUaGlzIGNvbnRyYWN0cyBhcmUgdHJhZGVkIGluIHRoZSBvdmVyLXRoZS1jb3VudGVyIG1hcmtldCAoT1RDKSBhbmQgYXJlIG5lZ290aWF0ZWQgaW5kaXZpZHVhbGx5IGFuZCBwcml2YXRlbHkuIFRoaXMgY2hhcmFjdGVyaXN0aWNzIG1heSBsZWFkIHRvIHRoaW5raW5nIHRoYXQgdGhpcyBjb250cmFjdHMgYXJlIG5vdCBwYXJ0aWN1bGFybHkgbGlxdWlkIGJ1dCB0aGUgcmVhbGl0eSBpbiB0aGlzIGNhc2UgaXMgcXVpdGUgY291bnRlci1pbnR1aXRpdmUgYW5kIHRoZXJlIGlzIGdyZWF0IGludGVyZXN0IGluIHRoZSBTd2FwIE1hcmtldC4gDQoNCg0KIyMjIFIgQ29kZQ0KDQoNCkxvYWQgcGFja2FnZXMNCg0KYGBge3J9DQpsaWJyYXJ5KHF1YW50bW9kKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpgYGANCg0KDQpEZWZpbmUgdGhlIEJlZ2lubmluZyBhbmQgRW5kIG9mIFRlcm0gRGF0ZXMNCg0KYGBge3J9DQpCb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA1LTAxIikNCkVvVF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMDktMzAiKQ0KDQpgYGANCg0KDQpEZWZpbmUgU3dhcCBUZXJtcw0KDQpgYGB7cn0NCm5vdGlvbmFsX2Ftb3VudCA8LSAxMDAwMDAwMA0KDQpmaXhlZF9yYXRlIDwtIDAuMDYNCmBgYA0KDQoNCkNhbGN1bGF0ZSB0aGUgVGltZSBQZXJpb2Qgb2YgdGhlIFN3YXANCg0KYGBge3J9DQpkYXlzX2JldHdlZW4gPC0gYXMubnVtZXJpYyhkaWZmdGltZShFb1RfZGF0ZSwgQm9UX2RhdGUsIHVuaXRzID0gImRheXMiKSkNCg0KeWVhcl9mcmFjdGlvbiA8LSBkYXlzX2JldHdlZW4gLyAzNjANCg0KY2F0KCJEYXlzIGJldHdlZW4gQm9UIGFuZCBFb1Q6IiwgZGF5c19iZXR3ZWVuLCAiZGF5c1xuIikNCmNhdCgiWWVhciBmcmFjdGlvbiAodXNpbmcgQWN0dWFsLzM2MCk6Iiwgcm91bmQoeWVhcl9mcmFjdGlvbiwgNiksICJcbiIpDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIEZpeGVkLVJhdGUgUGF5bWVudA0KDQpgYGB7cn0NCmZpeGVkX3BheW1lbnQgPC0gbm90aW9uYWxfYW1vdW50ICogZml4ZWRfcmF0ZSAqIHllYXJfZnJhY3Rpb24NCg0KY2F0KCJGaXhlZC1SYXRlIFBheW1lbnQ6ICQiLCByb3VuZChmaXhlZF9wYXltZW50LCAyKSwgIlxuIiwgc2VwID0gIiIpDQoNCmBgYA0KDQoNCg0KUmV0cmlldmUgdGhlIDI2LXdlZWsgVGJpbGwgUmF0ZSBhdCBFb3QNCg0KDQpHZXQgdGhlIFQtYmlsbCBSYXRlIERhdGENCg0KYGBge3J9DQpnZXRTeW1ib2xzKCJEVEI2Iiwgc3JjID0gIkZSRUQiLCBmcm9tID0gRW9UX2RhdGUgLSA3LCB0byA9IEVvVF9kYXRlICsgNykNCg0KYGBgDQoNCg0KRXh0cmFjdCB0aGUgUmF0ZSBhdCBFT1QNCg0KYGBge3J9DQpnZXRfcmF0ZV9vbl9kYXRlIDwtIGZ1bmN0aW9uKGRhdGEsIGRhdGUpIHsNCiAgaW5kZXgoZGF0YSkgPC0gYXMuRGF0ZShpbmRleChkYXRhKSkNCiAgDQogIGF2YWlsYWJsZV9kYXRlcyA8LSBpbmRleChkYXRhKVtpbmRleChkYXRhKSA8PSBkYXRlICYgIWlzLm5hKGRhdGFbaW5kZXgoZGF0YSldKV0NCiAgDQogIGlmIChsZW5ndGgoYXZhaWxhYmxlX2RhdGVzKSA9PSAwKSB7DQogICAgd2FybmluZyhwYXN0ZSgiTm8gZGF0YSBhdmFpbGFibGUgb24gb3IgYmVmb3JlIiwgZGF0ZSkpDQogICAgcmV0dXJuKGxpc3QoUmF0ZSA9IE5BLCBEYXRlID0gTkEpKQ0KICB9DQogIA0KICBkYXRlX3VzZWQgPC0gbWF4KGF2YWlsYWJsZV9kYXRlcykNCiAgDQogICMgR2V0IHRoZSByYXRlDQogIHJhdGUgPC0gYXMubnVtZXJpYyhkYXRhW2RhdGVfdXNlZF0pIC8gMTAwICAjIENvbnZlcnQgcGVyY2VudGFnZSB0byBkZWNpbWFsDQogIA0KICByZXR1cm4obGlzdCgNCiAgICBSYXRlID0gcmF0ZSwNCiAgICBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICkpDQp9DQoNCnRfYmlsbF9yYXRlX0VvVCA8LSBnZXRfcmF0ZV9vbl9kYXRlKERUQjYsIEVvVF9kYXRlKQ0KDQpjYXQoIjI2LXdlZWsgVC1iaWxsIFJhdGUgYXQgRW9UICgiLCB0X2JpbGxfcmF0ZV9Fb1QkRGF0ZSwgIik6ICIsIHJvdW5kKHRfYmlsbF9yYXRlX0VvVCRSYXRlICogMTAwLCAyKSwgIiVcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIHRoZSBGTG9hdGluZy1SYXRlIFBheW1lbnQNCg0KYGBge3J9DQojIEZsb2F0aW5nLXJhdGUgcGF5bWVudCBjYWxjdWxhdGlvbg0KZmxvYXRpbmdfcGF5bWVudCA8LSBub3Rpb25hbF9hbW91bnQgKiB0X2JpbGxfcmF0ZV9Fb1QkUmF0ZSAqIHllYXJfZnJhY3Rpb24NCg0KIyBQcmludCB0aGUgZmxvYXRpbmctcmF0ZSBwYXltZW50DQpjYXQoIkZsb2F0aW5nLVJhdGUgUGF5bWVudDogJCIsIHJvdW5kKGZsb2F0aW5nX3BheW1lbnQsIDIpLCAiXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCkNvbXB1dGUgdGhlIE5ldCBQYXltZW50DQoNCmBgYHtyfQ0KIyBOZXQgcGF5bWVudA0KbmV0X3BheW1lbnQgPC0gZmxvYXRpbmdfcGF5bWVudCAtIGZpeGVkX3BheW1lbnQNCg0KIyBEZXRlcm1pbmUgaWYgeW91IGdhaW4gb3IgbG9zZQ0KaWYgKG5ldF9wYXltZW50ID4gMCkgew0KICByZXN1bHQgPC0gImdhaW4iDQp9IGVsc2UgaWYgKG5ldF9wYXltZW50IDwgMCkgew0KICByZXN1bHQgPC0gImxvc2UiDQp9IGVsc2Ugew0KICByZXN1bHQgPC0gImJyZWFrIGV2ZW4iDQp9DQoNCiMgUHJpbnQgdGhlIG5ldCBwYXltZW50IGFuZCByZXN1bHQNCmNhdCgiTmV0IFBheW1lbnQ6ICQiLCByb3VuZChuZXRfcGF5bWVudCwgMiksICJcbiIsIHNlcCA9ICIiKQ0KY2F0KCJZb3UgIiwgcmVzdWx0LCAiIG9uIHRoZSBzd2FwLlxuIiwgc2VwID0gIiIpDQpgYGANCg0KDQojIyMgQW5hbHlzaXMgb2YgcmVzdWx0cw0KDQpUaGlzIGxvc3Mgb2NjdXJzIGJlY2F1c2UgdGhlIGZsb2F0aW5nIHJhdGUgeW91IHJlY2VpdmUgaXMgbG93ZXIgdGhhbiB0aGUgZml4ZWQgcmF0ZSB5b3UgcGF5Lg0KSW50ZXJlc3QgUmF0ZSBNb3ZlbWVudHM6IEluIHRoaXMgc2NlbmFyaW8sIHRoZSAyNi13ZWVrIFQtYmlsbCByYXRlIGF0IEVvVCB3YXMgbG93ZXIgdGhhbiB0aGUgZml4ZWQgcmF0ZSBhZ3JlZWQgdXBvbi4gVGhpcyByZXN1bHRlZCBpbiBhIG5ldCBsb3NzIGZvciB5b3Ugb24gdGhlIHN3YXAuDQpSYXRlIGF0IEVvVCB3YXMgMC4wNDIzDQoNClJpc2sgTWFuYWdlbWVudDogU3dhcHMgYXJlIHVzZWQgdG8gbWFuYWdlIGludGVyZXN0IHJhdGUgcmlzay4gQnkgZW50ZXJpbmcgaW50byB0aGlzIHN3YXAsIHlvdSB3ZXJlIHNwZWN1bGF0aW5nIHRoYXQgdGhlIDI2LXdlZWsgVC1iaWxsIHJhdGUgYXQgRW9UIHdvdWxkIGJlIGhpZ2hlciB0aGFuIDYlLg0KDQpBcyB3ZSBoYXZlIG1lbnRpb25lZCBpbiB0aGUgYmVnaW5uaW5nLCBhIGRlZXAga25vd2xlZGdlIG9mIHRoZSB1bmRlcmx5aW5nIGFzc2V0L2ludGVyZXN0L2luZGV4IGlzIGNydWNpYWwgd2hlbiBlbnRlcmluZyBhIHN3YXAgY29udHJhY3QgYXMgdGhlIHByaWNlIHJpc2sgd2lsbCBiZSBkZXRlcm1pbmVkIGJ5IHRoZW0uIEluIHRoaXMgY2FzZSwgdGhlIGxvd2VyLXRoYW4tZXhwZWN0ZWQgcmF0ZSBoYXMgbGVkIHRvIGEgc2lnbmlmaWNhbnQgbG9zcy4NCg0KDQoNCiMjIEwxMS44IC0gTDExLjEyLiBNZWFzdXJpbmcgYW5kIGV4cGxhaW5pbmcgZXhjaGFuZ2UgcmF0ZSBtb3ZlbWVudHMNCg0KIyMjIEV4cGxhbmF0aW9ucyBBaGVhZA0KDQpJbiB0aGlzIHNlY3Rpb24gd2Ugd2lsbCBiZSBtZWFzdXJpbmcgYW5kIGV4cGxhaW5pbmcgZXhjaGFuZ2UgcmF0ZSBtb3ZlbWVudHMuIEluIG9yZGVyIHRvIGJldHRlciB1bmRlcnN0YW5kIHRoaXMgcGhlbm9tZW5hIHdlIHdpbGwgaGF2ZSB0byB0YWtlIGludG8gYWNjb3VudCBjZXJ0YWluIGNvbmNlcHRzLiANCg0KDQojIyMjIEN1cnJlbmN5IGZsdWN0dWF0aW9uDQpXaGVuIHdlIHRhbGsgYWJvdXQgY3VycmVudCBmbHVjdHVhdGlvbiwgd2UgYXJlIHJlZmVycmluZyB0byB0aGUgY2hhbmdlIGluIHRoZSByZWxhdGl2ZSB2YWx1ZSBvZiBvbmUgYWdhaW5zdCB0aGUgb3RoZXIuIEluIG90aGVyIHdvcmRzLCBpcyB0aGUgY2hhbmdlIGluIHRoZSBlcXVpdmFsZW5jaWVzIG9mIHRoZSB2YWx1ZSBvZiB0aGUgY3VycmVuY2llcy4gDQoNCg0KIyMjIyBFeGNoYW5nZSBSYXRlcw0KRXhjaGFuZ2UgUmF0ZXMgYXJlIHRoZSBudW1lcmljYWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIGN1cnJlbmN5IGZsdWN0dWF0aW9uLiBUaGF0IGlzIHRoZSB2YWx1ZSBvZiBvbmUgY3VycmVuY3kgYWdhaW5zdCB0aGUgb3RoZXIgaW4gYW4gc3BlY2lmaWMgbW9tZW50LiBFeGNoYW5nZSBSYXRlcyBmbHVjdHVhdGUgYW5kIGFyZSBncmVhdCBlY29ub21pY2FsIGluZGljYXRvcnMuIFRoZXJlIGFyZSBzZXZlcmFsIHJlYXNvbnMgZm9yIHRoZSBmbHVjdHVhdGlvbiBvZiBleGNoYW5nZSByYXRlcywgc3VjaCBhcyBpbnRlcmVzdCByYXRlcywgZ2VuZXJhbCBtYWNyb2Vjb25vbWljIGRhdGEgb2YgZWFjaCBjb3VudHJ5LCBwb2xpdGljYWwgcG9saWNpZXMgYW5kIHN0YWJpbGl0eSwgaW5mbGF0aW9uIHJhdGVzLCBkYXRhIGFuZCBwb2xpY3ksIGFuZCBmb3JlaWduIGludmVzdG1lbnRzLiANCkFub3RoZXIgZmFjdG9yIHRoYXQgY3JlYXRlcyBmbHVjdHVhdGlvbiBpbiBleGNoYW5nZSByYXRlcyBpcyB0aGUgc3BlY3VsYXRpb24uIA0KDQoNCiMjIyMgRWZmZWN0cw0KVGhlIGZsdWN0dWF0aW9ucyBpbiBjdXJyZW5jeSAoYW5kIGV4Y2hhbmdlIHJhdGVzKSBoYXZlIGFuIGltcGFjdCBpbiBzZXZlcmFsIGFzcGVjdHMgb2YgdGhlIGVjb25vbXkuIA0KICAxLiBJbnRlcm5hdGlvbmFsIHRyYWRlLiBBIHdlYWsgY3VycmVuY3kgZWFzaWx5IGJlbmVmaXRzIGZyb20gZXhwb3J0cywgd2hpbGUgYSBzdHJvbmcgb25lIG1heSByZWR1Y2UgdGhlaXIgZXhwb3J0IGNhcGFiaWxpdHkuICANCiAgMi4gSW5mbGF0aW9uLiBBIHN0cm9uZyBjdXJyZW5jeSB3aWxsIGhhdmUgYSBsb3Qgb2YgaW1wb3J0IGNhcGFiaWxpdHkgYW5kIHdpbGwgYmUgYWJsZSB0byBrZWVwIGluZmxhdGlvbiBzdGFibGUuIEhvd2V2ZXIsIGEgd2VhayBjdXJyZW5jeSB3aWxsIGhhdmUgaGlnaGVyIGltcG9ydCBjb3N0cyBhbmQgd2lsbCBvdmVyYWxsIGluY3JlYXNlIGRvbWVzdGljIGluZmxhdGlvbi4gDQogIDMuIEludmVzdG1lbnQuIFRoZSBzdGFiaWxpdHkgb3Igc3RyZW5ndGhlbiBvZiBhIGN1cnJlbmN5IHVzdWFsbHkgaW5kaWNhdGUgYW4gc3RhYmxlL3N0cm9uZyBlY29ub215IGFuZCBwb2xpdGljYWwgc2l0dWF0aW9uLiBUaGVyZWZvcmUsIGl0IHdpbGwgYmUgbXVjaCBtb3JlIGF0dHJhY3RpdmUgdG8gbWFrZSBhbiBpbnZlc3RtZW50IGluIHRob3NlIGNvdW50cmllcyB3aXRoIGEgc3Ryb25nIGN1cnJlbmN5LiBPcHBvc2l0ZWx5LCBhIHdlYWsgY3VycmVuY3kgKG9yIGEgY29uc3RhbnRseSBjaGFuZ2luZyBvbmUpIHdpbGwgaW5kaWNhdGUgd2Vha25lc3MgYW5kIGluc3RhYmlsaXR5LiANCiAgNC4gRWNvbm9taWMgc3RhYmlsaXR5IGFuZCBncm93dGguIEltcGFjdHMgaW4gR0RQLCBpbnZlc3RtZW50LCBpbmZsYXRpb24gYW5kIGludGVybmF0aW9uYWwgdHJhZGUgYWxsIGNvbnRyaWJ1dGUgdG93YXJkcyB0aGUgZWNvbm9teSBvZiBhIGNvdW50cnksIHdoZXRoZXIgbWFraW5nIGluIHN0YWJsZSBhbmQgc3Ryb25nIG9yIHdlYWsgYSB1bnN0YWJsZS4gDQoNCg0KIyMjIEJlZm9yZSB0aGUgZXhlcmNpc2VzDQoNCkxvYWQgUGFja2FnZXMNCg0KYGBge3J9DQojIExvYWQgcmVxdWlyZWQgcGFja2FnZXMNCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoUGVyZm9ybWFuY2VBbmFseXRpY3MpDQoNCmBgYA0KDQoNCkRlZmluZSBCZWdpbm5pbmcgYW5kIEVuZCBvZiBUZXJtIERhdGVzDQoNCmBgYHtyfQ0KIyBEZWZpbmUgQmVnaW5uaW5nIG9mIFRlcm0gKEJvVCkgYW5kIEVuZCBvZiBUZXJtIChFb1QpIGRhdGVzDQpCb1RfZGF0ZSA8LSBhcy5EYXRlKCIyMDI0LTA1LTAxIikNCkVvVF9kYXRlIDwtIGFzLkRhdGUoIjIwMjQtMDktMzAiKQ0KDQpgYGANCg0KDQojIyMgTDExLjggRGV0ZXJtaW5pbmcgdGhlIFBlcmNlbnRhZ2UgQ2hhbmdlIGluIHRoZSBWYWx1ZSBvZiB0aGUgQnJpdGlzaCBQb3VuZA0KDQoNClJldHJpZXZlIEdQQi9VU0QgRXhjaGFuZ2UgUmF0ZSBEYXRhDQoNCmBgYHtyfQ0KIyBHZXQgR0JQL1VTRCBleGNoYW5nZSByYXRlIGRhdGENCmdldFN5bWJvbHMoIkdCUFVTRD1YIiwgc3JjID0gInlhaG9vIiwgZnJvbSA9IEJvVF9kYXRlIC0gNywgdG8gPSBFb1RfZGF0ZSArIDcsIGF1dG8uYXNzaWduID0gVFJVRSkNCg0KIyBBc3NpZ24gZGF0YSB0byBhIHZhcmlhYmxlDQpnYnBfdXNkX2RhdGEgPC0gYEdCUFVTRD1YYA0KYGBgDQoNCg0KR2V0IGV4Y2hhbmdlIFJhdGVzIGF0IEJvVCBhbmQgRW9UDQoNCmBgYHtyfQ0KIyBGdW5jdGlvbiB0byBnZXQgdGhlIGV4Y2hhbmdlIHJhdGUgb24gYSBzcGVjaWZpYyBkYXRlDQpnZXRfcmF0ZV9vbl9kYXRlIDwtIGZ1bmN0aW9uKGRhdGEsIGRhdGUpIHsNCiAgaW5kZXgoZGF0YSkgPC0gYXMuRGF0ZShpbmRleChkYXRhKSkNCiAgDQogIGF2YWlsYWJsZV9kYXRlcyA8LSBpbmRleChkYXRhKVtpbmRleChkYXRhKSA8PSBkYXRlXQ0KICANCiAgaWYgKGxlbmd0aChhdmFpbGFibGVfZGF0ZXMpID09IDApIHsNCiAgICB3YXJuaW5nKHBhc3RlKCJObyBkYXRhIGF2YWlsYWJsZSBvbiBvciBiZWZvcmUiLCBkYXRlKSkNCiAgICByZXR1cm4obGlzdChSYXRlID0gTkEsIERhdGUgPSBOQSkpDQogIH0NCiAgDQogIGRhdGVfdXNlZCA8LSBtYXgoYXZhaWxhYmxlX2RhdGVzKQ0KICANCiAgcmF0ZSA8LSBhcy5udW1lcmljKENsKGRhdGFbZGF0ZV91c2VkXSkpDQogIA0KICByZXR1cm4obGlzdCgNCiAgICBSYXRlID0gcmF0ZSwNCiAgICBEYXRlID0gYXMuRGF0ZShkYXRlX3VzZWQpDQogICkpDQp9DQoNCiMgR2V0IHJhdGVzIGF0IEJvVCBhbmQgRW9UDQpnYnBfcmF0ZV9Cb1QgPC0gZ2V0X3JhdGVfb25fZGF0ZShnYnBfdXNkX2RhdGEsIEJvVF9kYXRlKQ0KZ2JwX3JhdGVfRW9UIDwtIGdldF9yYXRlX29uX2RhdGUoZ2JwX3VzZF9kYXRhLCBFb1RfZGF0ZSkNCg0KIyBQcmludCB0aGUgZXhjaGFuZ2UgcmF0ZXMNCmNhdCgiR0JQL1VTRCBSYXRlIGF0IEJvVCAoIiwgZ2JwX3JhdGVfQm9UJERhdGUsICIpOiAiLCByb3VuZChnYnBfcmF0ZV9Cb1QkUmF0ZSwgNCksICJcbiIsIHNlcCA9ICIiKQ0KY2F0KCJHQlAvVVNEIFJhdGUgYXQgRW9UICgiLCBnYnBfcmF0ZV9Fb1QkRGF0ZSwgIik6ICIsIHJvdW5kKGdicF9yYXRlX0VvVCRSYXRlLCA0KSwgIlxuIiwgc2VwID0gIiIpDQpgYGANCg0KDQpDYWxjdWxhdGUgdGhlIFBlcmNlbnRhZ2UgQ2hhbmdlDQoNCmBgYHtyfQ0KIyBDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2UgY2hhbmdlDQpnYnBfcGVyY2VudGFnZV9jaGFuZ2UgPC0gKGdicF9yYXRlX0VvVCRSYXRlIC0gZ2JwX3JhdGVfQm9UJFJhdGUpIC8gZ2JwX3JhdGVfQm9UJFJhdGUgKiAxMDANCg0KIyBQcmludCB0aGUgcmVzdWx0DQpjYXQoIlBlcmNlbnRhZ2UgQ2hhbmdlIGluIEdCUC9VU0Q6ICIsIHJvdW5kKGdicF9wZXJjZW50YWdlX2NoYW5nZSwgMiksICIlXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCkRldGVybWluZSBBcHByZWNpYXRpb24gb3IgRGVwcmVjaWF0aW9uDQoNCmBgYHtyfQ0KaWYgKGdicF9wZXJjZW50YWdlX2NoYW5nZSA+IDApIHsNCiAgZ2JwX3Jlc3VsdCA8LSAiYXBwcmVjaWF0ZWQiDQp9IGVsc2UgaWYgKGdicF9wZXJjZW50YWdlX2NoYW5nZSA8IDApIHsNCiAgZ2JwX3Jlc3VsdCA8LSAiZGVwcmVjaWF0ZWQiDQp9IGVsc2Ugew0KICBnYnBfcmVzdWx0IDwtICJyZW1haW5lZCB0aGUgc2FtZSINCn0NCg0KY2F0KCJUaGUgQnJpdGlzaCBwb3VuZCBoYXMgIiwgZ2JwX3Jlc3VsdCwgIiBhZ2FpbnN0IHRoZSBVUyBkb2xsYXIgb3ZlciB0aGUgc2Nob29sIHRlcm0uXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCiMjIyMgQW5hbHlzaXMNClRoZSBhcHByZWNpYXRpb24gb2YgdGhlIEJyaXRpc2ggcG91bmQgYWdhaW5zdCB0aGUgVVMgZG9sbGFyIG1heSBpbmRpY2F0ZSwgYXMgd2UgaGF2ZSBwcmV2aW91c2x5IGV4cGxhaW5lZCwgYW4gc3RyZW5ndGhlbmluZyBvZiBVSydzIGVjb25vbXkgYWdhaW5zdCB0aGUgVVMuIEFsdGhvdWdoIHdlIGNhbm5vdCBiZSBjZXJ0YWluIHdpdGhvdXQgbXVjaCBmdXJ0aGVyIGFuYWx5c2lzIG9mIHdoYXQgbWF5IGhhdmUgY2F1c2VkIHRoaXMgbm90b3Jpb3VzIGFwcHJlY2lhdGlvbiBvZiB0aGUgY3VycmVuY3ksIHdlIGNhbiBwcmVzdW1lIGlzIGEgbWl4IG9mIHNldmVyYWwgZmFjdG9ycyB0aGF0IGhhdmUgYmVlbiBhbHJlYWR5IGV4cGxhaW5lZC4gVGhpcyBjb3VsZCBpbmNsdWRlIGZhdm9yYWJsZSBHRFAgZGF0YSBmb3IgdGhlIFVLLCBhbiBhZ2dyZXNzaXZlIG1vbmV0YXJ5IHBvbGljeSBmcm9tIHRoZSBCYW5rIG9mIEVuZ2xhbmQgd2l0aCBoaWdoZXIgaW50ZXJlc3QgcmF0ZXMsIG9yIHRoZSBzdGFiaWxpemF0aW9uIG9mIGNlcnRhaW4gYXNwZWN0cyByZWdhcmRpbmcgQnJleGl0LiBPbiB0aGUgb3RoZXIgc2lkZSwgdGhlIFVTIG1heSBoYXZlIGJlY29tZSBzb21ld2hhdCBsZXNzIGF0dHJhY3RpdmUgZm9yIGludmVzdG9ycyB3aG8gbG9vayBmb3Igcmlza2llciBvcHBvcnR1bml0aWVzLCBzbG93IGluZmxhdGlvbiB3aXRoIGEgbGVzcyBhZ2dyZXNzaXZlIG1vbmV0YXJ5IHBvbGljeSBvciBvdmVyYWxsIGRpc2NvbnRlbnQgd2l0aCB0aGUgcG9saXRpY2FsIHNpdHVhdGlvbi4gVGhlIHVwY29taW5nIFVTQSBQcmVzaWRlbnRpYWwgRWxlY3Rpb25zIG1heSBoYXZlIHJpc2VuIGNlcnRhaW4gY29uY2VybnMgYW5kIGNyZWF0ZWQgYSBzZW5zZSBvZiBpbnN0YWJpbGl0eSB0aGF0IGhhcyBiZWVuIHBvcnRyYXllZCBpbiB0aGUgZXhjaGFuZ2UgcmF0ZSBhZ2FpbnN0IHRoZSBCcml0aXNoIFBvdW5kLiANCg0KDQojIyMgTDExLjkgRGV0ZXJtaW5pbmcgdGhlIFBlcmNlbnRhZ2UgQ2hhbmdlIGluIHRoZSBWYWx1ZSBvZiB0aGUgSmFwYW5lc2UgWWVuDQoNCg0KUmV0cmlldmUgVVNEL0pQWSBFeGNoYW5nZSBSYXRlIERhdGENCg0KYGBge3J9DQojIEdldCBVU0QvSlBZIGV4Y2hhbmdlIHJhdGUgZGF0YQ0KZ2V0U3ltYm9scygiSlBZPVgiLCBzcmMgPSAieWFob28iLCBmcm9tID0gQm9UX2RhdGUgLSA3LCB0byA9IEVvVF9kYXRlICsgNywgYXV0by5hc3NpZ24gPSBUUlVFKQ0KDQojIEFzc2lnbiBkYXRhIHRvIGEgdmFyaWFibGUNCnVzZF9qcHlfZGF0YSA8LSBgSlBZPVhgDQpgYGANCg0KDQpHZXQgRXhjaGFuZ2UgUmF0ZXMgYXQgQm9UIGFuZCBFb1QNCg0KYGBge3J9DQojIEdldCByYXRlcyBhdCBCb1QgYW5kIEVvVA0KanB5X3JhdGVfQm9UIDwtIGdldF9yYXRlX29uX2RhdGUodXNkX2pweV9kYXRhLCBCb1RfZGF0ZSkNCmpweV9yYXRlX0VvVCA8LSBnZXRfcmF0ZV9vbl9kYXRlKHVzZF9qcHlfZGF0YSwgRW9UX2RhdGUpDQoNCiMgUHJpbnQgdGhlIGV4Y2hhbmdlIHJhdGVzDQpjYXQoIlVTRC9KUFkgUmF0ZSBhdCBCb1QgKCIsIGpweV9yYXRlX0JvVCREYXRlLCAiKTogIiwgcm91bmQoanB5X3JhdGVfQm9UJFJhdGUsIDQpLCAiXG4iLCBzZXAgPSAiIikNCmNhdCgiVVNEL0pQWSBSYXRlIGF0IEVvVCAoIiwganB5X3JhdGVfRW9UJERhdGUsICIpOiAiLCByb3VuZChqcHlfcmF0ZV9Fb1QkUmF0ZSwgNCksICJcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIHRoZSBQZXJjZW50YWdlIFJhdGUNCg0KYGBge3J9DQojIEludmVydCB0aGUgcmF0ZXMgdG8gZ2V0IEpQWSBwZXIgVVNEDQpqcHlfcGVyX3VzZF9Cb1QgPC0gMSAvIGpweV9yYXRlX0JvVCRSYXRlDQpqcHlfcGVyX3VzZF9Fb1QgPC0gMSAvIGpweV9yYXRlX0VvVCRSYXRlDQoNCiMgQ2FsY3VsYXRlIHRoZSBwZXJjZW50YWdlIGNoYW5nZQ0KanB5X3BlcmNlbnRhZ2VfY2hhbmdlIDwtIChqcHlfcGVyX3VzZF9Fb1QgLSBqcHlfcGVyX3VzZF9Cb1QpIC8ganB5X3Blcl91c2RfQm9UICogMTAwDQoNCiMgUHJpbnQgdGhlIHJlc3VsdA0KY2F0KCJQZXJjZW50YWdlIENoYW5nZSBpbiBKUFkvVVNEOiAiLCByb3VuZChqcHlfcGVyY2VudGFnZV9jaGFuZ2UsIDIpLCAiJVxuIiwgc2VwID0gIiIpDQpgYGANCg0KDQpEZXRlcm1pbmUgQXBwcmVjaWF0aW9uIG9yIERlcHJlY2lhdGlvbg0KDQpgYGB7cn0NCmlmIChqcHlfcGVyY2VudGFnZV9jaGFuZ2UgPiAwKSB7DQogIGpweV9yZXN1bHQgPC0gImFwcHJlY2lhdGVkIg0KfSBlbHNlIGlmIChqcHlfcGVyY2VudGFnZV9jaGFuZ2UgPCAwKSB7DQogIGpweV9yZXN1bHQgPC0gImRlcHJlY2lhdGVkIg0KfSBlbHNlIHsNCiAganB5X3Jlc3VsdCA8LSAicmVtYWluZWQgdGhlIHNhbWUiDQp9DQoNCmNhdCgiVGhlIEphcGFuZXNlIHllbiBoYXMgIiwganB5X3Jlc3VsdCwgIiBhZ2FpbnN0IHRoZSBVUyBkb2xsYXIgb3ZlciB0aGUgc2Nob29sIHRlcm0uXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCiMjIyMgQW5hbHlzaXMNCkp1c3QgYXMgd2UgaGF2ZSBleHBsYWluZWQgaW4gdGhlIHByZXZpb3VzIHF1ZXN0aW9uLiB0aGUgVVMgbWF5IGhhdmUgZmFjZWQgYSBwZXJpb2Qgb2YgaW5zdGFiaWxpdHkgYW5kIHNsb3duZXNzIHRoYXQgY291bGQgaGF2ZSBjYXVzZWQgYSBsb3dlciBkZW1hbmQgZm9yIFVTIGRvbGxhcnMuIENvbnZlcnNlbHksIHRoZSBCYW5rIG9mIEphcGFuLCBtYXkgaGF2ZSBhZG9wdGVkIGEgbW9yZSBzdHJpY3QgcmVndWxhdGlvbiAoaW4gb3Bwb3NpdGlvbiB3aXRoIGl0cyB0cmFkaXRpb25hbCBhcHByb2FjaCkgZHVlIHRvIGhpZ2ggaW5mbGF0aW9uIG9yIGR1ZSB0byBub3JtYWxpemF0aW9uIHN0cmF0ZWdpZXMsIHdoaWNoIG1heSBoYXZlIGNhdXNlZCBhIHJlYWN0aW9uIGluIHRoZSBjdXJyZW5jeSBtYXJrZXRzLiBKYXBhbiBtYXkgaGF2ZSBhbHNvIGhhZCBwb3NpdGl2ZSByZXBvcnRzIG9yIGEgcmVjb3ZlcnkgaW4gaXRzIHRyYWRlIGJhbGFuY2UuIA0KDQoNCiMjIyBMMTEuMTAgRGV0ZXJtaW5pbmcgdGhlIFBlcmNlbnRhZ2UgQ2hhbmdlIGluIHRoZSBWYWx1ZSBvZiB0aGUgTWV4aWNhbiBQZXNvDQoNCg0KUmV0cmlldmUgVVNEL01YTiBFeGNoYW5nZSBSYXRlIERhdGENCg0KYGBge3J9DQojIEdldCBVU0QvTVhOIGV4Y2hhbmdlIHJhdGUgZGF0YQ0KZ2V0U3ltYm9scygiTVhOPVgiLCBzcmMgPSAieWFob28iLCBmcm9tID0gQm9UX2RhdGUgLSA3LCB0byA9IEVvVF9kYXRlICsgNywgYXV0by5hc3NpZ24gPSBUUlVFKQ0KDQojIEFzc2lnbiBkYXRhIHRvIGEgdmFyaWFibGUNCnVzZF9teG5fZGF0YSA8LSBgTVhOPVhgDQpgYGANCg0KDQpHZXQgRXhjaGFuZ2UgUmF0ZXMgYXQgQm9UIGFuZCBFb1QNCg0KYGBge3J9DQojIEdldCByYXRlcyBhdCBCb1QgYW5kIEVvVA0KbXhuX3JhdGVfQm9UIDwtIGdldF9yYXRlX29uX2RhdGUodXNkX214bl9kYXRhLCBCb1RfZGF0ZSkNCm14bl9yYXRlX0VvVCA8LSBnZXRfcmF0ZV9vbl9kYXRlKHVzZF9teG5fZGF0YSwgRW9UX2RhdGUpDQoNCiMgUHJpbnQgdGhlIGV4Y2hhbmdlIHJhdGVzDQpjYXQoIlVTRC9NWE4gUmF0ZSBhdCBCb1QgKCIsIG14bl9yYXRlX0JvVCREYXRlLCAiKTogIiwgcm91bmQobXhuX3JhdGVfQm9UJFJhdGUsIDQpLCAiXG4iLCBzZXAgPSAiIikNCmNhdCgiVVNEL01YTiBSYXRlIGF0IEVvVCAoIiwgbXhuX3JhdGVfRW9UJERhdGUsICIpOiAiLCByb3VuZChteG5fcmF0ZV9Fb1QkUmF0ZSwgNCksICJcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KQ2FsY3VsYXRlIHRoZSBQZXJjZW50YWdlIENoYW5nZQ0KDQpgYGB7cn0NCiMgSW52ZXJ0IHRoZSByYXRlcyB0byBnZXQgTVhOIHBlciBVU0QNCm14bl9wZXJfdXNkX0JvVCA8LSAxIC8gbXhuX3JhdGVfQm9UJFJhdGUNCm14bl9wZXJfdXNkX0VvVCA8LSAxIC8gbXhuX3JhdGVfRW9UJFJhdGUNCg0KIyBDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2UgY2hhbmdlDQpteG5fcGVyY2VudGFnZV9jaGFuZ2UgPC0gKG14bl9wZXJfdXNkX0VvVCAtIG14bl9wZXJfdXNkX0JvVCkgLyBteG5fcGVyX3VzZF9Cb1QgKiAxMDANCg0KIyBQcmludCB0aGUgcmVzdWx0DQpjYXQoIlBlcmNlbnRhZ2UgQ2hhbmdlIGluIE1YTi9VU0Q6ICIsIHJvdW5kKG14bl9wZXJjZW50YWdlX2NoYW5nZSwgMiksICIlXG4iLCBzZXAgPSAiIikNCmBgYA0KDQoNCkRldGVybWluZSBBcHByZWNpYXRpb24gb3IgRGVwcmVjaWF0aW9uDQoNCmBgYHtyfQ0KaWYgKG14bl9wZXJjZW50YWdlX2NoYW5nZSA+IDApIHsNCiAgbXhuX3Jlc3VsdCA8LSAiYXBwcmVjaWF0ZWQiDQp9IGVsc2UgaWYgKG14bl9wZXJjZW50YWdlX2NoYW5nZSA8IDApIHsNCiAgbXhuX3Jlc3VsdCA8LSAiZGVwcmVjaWF0ZWQiDQp9IGVsc2Ugew0KICBteG5fcmVzdWx0IDwtICJyZW1haW5lZCB0aGUgc2FtZSINCn0NCg0KY2F0KCJUaGUgTWV4aWNhbiBwZXNvIGhhcyAiLCBteG5fcmVzdWx0LCAiIGFnYWluc3QgdGhlIFVTIGRvbGxhciBvdmVyIHRoZSBzY2hvb2wgdGVybS5cbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KIyMjIyBBbmFseXNpcw0KSGF2ZSB3ZSBub3Qgc2VlbiB0aGUgcHJldmlvdXMgcmVzdWx0cywgd2UgbWlnaHQgaGF2ZSBoYWQgdGhlIGluaXRpYWwgdGhvdWdodCB0aGF0IHRoZXNlIHJlc3VsdHMgYXJlIHRoZSBtYW5pZmVzdGF0aW9uIG9mIGEgc3Ryb25nIFVTIERvbGxhciwgd2hpY2ggc3RyZW5ndGhlbnMgYWdhaW5zdCB0aGUgTWV4aWNhbiBQZXNvLiBIb3dldmVyLCB3ZSBhbHJlYWR5IGtub3cgdGhhdCB0aGUgVVNEIGhhZCB3ZWFrZW5lZCBhZ2FpbnN0IHRoZSBvdGhlciB0d28gY3VycmVuY2llcyBhbmFseXplZCwgc28gd2UgbWF5IGFzc3VtZSB0aGF0IHRoaXMgaXMgbm90IHRoZSBvdXRjb21lIG9mIGFuIHN0cm9uZyBVU0EgYnV0IHJhdGhlciBhIHJlYWxseSB3b3JzZW5lZCBNZXhpY28uIA0KSWYgd2UgdGFrZSBhIGxvb2sgaW50byBNZXhpY28ncyBwb2xpdGljcyBkdXJpbmcgdGhlIFRlcm0gUGVyaW9kLCB3ZSB3aWxsIG5vdGljZSB0aGF0IFByZXNpZGVudGlhbCBFbGVjdGlvbnMgdG9vayBwbGFjZSwgd2l0aCB0aGUgdmljdG9yeSBvZiBDbGF1ZGlhIFNoZWluYmF1bS4gVGhlIGRpZmZlcmVuY2UgaW4gcG9zaXRpb25zIHdpdGggdGhlIFVTQSBpbiBzZXZlcmFsIGludGVybmF0aW9uYWwgbWF0dGVycyBtYXkgaGF2ZSBwdXNoZWQgdGhpcyBkcm9wIGluIHRoZSBNZXhpY2FuIFBlc28sIHdoaWNoIGhhcyBub3QgeWV0IHN0b3BwZWQgYXMgb2YgdG9kYXksIGFsdGhvdWdoIG91ciBFbmQgb2YgVGVybSBEYXRlIG9ubHkgZGF0ZXMgdW50aWwgU2VwdGVtYmVyLiANCg0KDQojIyMgTDExLjExIERldGVybWluaW5nIHRoZSBQZXIgVW5pdCBHYWluIG9yIExvc3MgZm9yIEJyaXRpc2ggUG91bmQgRnV0dXJlcw0KDQoNCkRldGVybWluZSB0aGUgcGVyIHVuaXQgZ2FpbiBvciBsb3NzIGlmIHlvdSBoYWQgcHVyY2hhc2VkIEJyaXRpc2ggcG91bmQgZnV0dXJlcyBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSB0ZXJtIGFuZCBzb2xkIHRoZW0gYXQgdGhlIGVuZCBvZiB0aGUgdGVybS4NClVzZSBHUEIvVVNEIEV4Y2hhbmdlIHJhdGVzIGFzIFByb3h5LiANCg0KDQpDYWxjdWxhdGUgdGhlIFBlciBVbml0IEdhaW4gb3IgTG9zcw0KDQpgYGB7cn0NCiMgQ2FsY3VsYXRlIHRoZSBwZXIgdW5pdCBnYWluIG9yIGxvc3MNCnBlcl91bml0X2dhaW5fbG9zcyA8LSBnYnBfcmF0ZV9Fb1QkUmF0ZSAtIGdicF9yYXRlX0JvVCRSYXRlDQoNCiMgUHJpbnQgdGhlIHJlc3VsdA0KY2F0KCJQZXIgVW5pdCBHYWluL0xvc3MgZm9yIEdCUCBGdXR1cmVzOiAkIiwgcm91bmQocGVyX3VuaXRfZ2Fpbl9sb3NzLCA0KSwgIiBwZXIgR0JQXG4iLCBzZXAgPSAiIikNCmBgYA0KDQpJbiB0aGlzIGV4ZXJjaXNlIHdlIGhhdmUgZGV0ZXJtaW5lZCB0aGUgZ2FpbiBwZXIgR1BCIGZvciB0aGUgZnV0dXJlcyBjb250cmFjdC4NCg0KDQojIyMgTDExLjEyIERldGVybWluaW5nIHRoZSBEb2xsYXIgQW1vdW50IG9mIFlvdXIgR2FpbiBvciBMb3NzIG9uIHRoZSBGdXR1cmVzIENvbnRyYWN0DQoNCkdpdmVuIHRoYXQgYSBzaW5nbGUgZnV0dXJlcyBjb250cmFjdCBvbiBCcml0aXNoIHBvdW5kcyByZXByZXNlbnRzIDYyLDUwMCBwb3VuZHMsIGRldGVybWluZSB0aGUgZG9sbGFyIGFtb3VudCBvZiB5b3VyIGdhaW4gb3IgbG9zcy4NCg0KYGBge3J9DQojIE51bWJlciBvZiBwb3VuZHMgcGVyIGZ1dHVyZXMgY29udHJhY3QNCmNvbnRyYWN0X3NpemUgPC0gNjI1MDANCg0KIyBUb3RhbCBnYWluIG9yIGxvc3MNCnRvdGFsX2dhaW5fbG9zcyA8LSBwZXJfdW5pdF9nYWluX2xvc3MgKiBjb250cmFjdF9zaXplDQoNCiMgUHJpbnQgdGhlIHJlc3VsdA0KY2F0KCJUb3RhbCBHYWluL0xvc3Mgb24gRnV0dXJlcyBDb250cmFjdDogJCIsIHJvdW5kKHRvdGFsX2dhaW5fbG9zcywgMiksICJcbiIsIHNlcCA9ICIiKQ0KYGBgDQoNCg0KRGV0ZXJtaW5lIGlmIHlvdSBHYWluZWQgb3IgTG9zdA0KDQpgYGB7cn0NCmlmICh0b3RhbF9nYWluX2xvc3MgPiAwKSB7DQogIGZ1dHVyZXNfcmVzdWx0IDwtICJnYWluZWQiDQp9IGVsc2UgaWYgKHRvdGFsX2dhaW5fbG9zcyA8IDApIHsNCiAgZnV0dXJlc19yZXN1bHQgPC0gImxvc3QiDQp9IGVsc2Ugew0KICBmdXR1cmVzX3Jlc3VsdCA8LSAiYnJva2UgZXZlbiINCn0NCg0KY2F0KCJZb3UgaGF2ZSAiLCBmdXR1cmVzX3Jlc3VsdCwgIiAkIiwgYWJzKHJvdW5kKHRvdGFsX2dhaW5fbG9zcywgMikpLCAiIG9uIHRoZSBmdXR1cmVzIGNvbnRyYWN0LlxuIiwgc2VwID0gIiIpDQpgYGANCg0KV2l0aCBhIGdhaW4gcGVyIEdQQiBvZiAwLjA4MzcgVVNEIGFuZCBhbiBhbW91bnQgb2YgNjI1MDAgcG91bmRzLCB3ZSB3aWxsIGhhdmUgZW5kZWQgYXQgdGhlIGVuZCBvZiB0ZXJtIHdpdGggYSB0b3RhbCBnYWluIG9mIDUyMjkuOTYgVVNELiBUaGlzIGhhcyBiZWVuIHBvc3NpYmxlLCBhcyB3ZSBrbm93LCB0aGFua3MgdG8gdGhlIGFwcHJlY2lhdGlvbiBvZiB0aGUgR1BCIGFnYWluc3QgdGhlIFVTRCwgd2hpY2ggaGUgaGF2ZSBhbHJlYWR5IGFuYWx5emVkIHByZXZpb3VzbHkuIA0KDQoNCg0KDQojIyBMMTIgQ2FwaXRhbCByZXF1aXJlbWVudHMNCkwxMi4xIENhbGN1bGF0ZSB0aGUgb3BlcmF0aW9uYWwsIG1hcmtldCBhbmQgY3JlZGl0IHJpc2sgY2FwaXRhbCByZXF1aXJlbWVudHMgZm9yIEJhbmsgb2YgQW1lcmljYSBhbmQgRGV1dHNjaGUgQmFuayBhcyBvZiBEZWNlbWJlciAzMSwgbGFzdCB5ZWFyLCB3aGljaCBiYW5rIGhhcyBiZXR0ZXIgY2FwaXRhbCBiYXNlPw0KDQoNCiMjIyBEZWZpbml0aW9ucw0KDQojIyMjIE9wZXJhdGlvbmFsIFJpc2sgDQoNCldlIGNhbiBkZWZpbmUgb3BlcmF0aW9uYWwgcmlzayBhcyBhIHR5cGUgb2YgYnVzaW5lc3MgcmlzayBkZXJpdmVkIGZyb20gdGhlIGRhaWx5IGFjdGl2aXR5IG9mIHRoZSBjb21wYW55LiBUaGF0IGlzIHRoZSByaXNrIGRlcml2ZWQgZnJvbSB3aXRoaW4gdGhlIGNvbXBhbnkgcmF0aGVyIHRoYW4gZXh0ZXJuYWwgZm9yY2VzIG9yIGV2ZW50cy4gVGhpcyByaXNrIGluY2x1ZGVzIGZhY3RvcnMgc3VjaCBhcyBwZW9wbGUsIHN5c3RlbXMgYW5kIGludGVybmFsIHByb2NlZHVyZXMuIA0KDQoNCiMjIyMgTWFya2V0IFJpc2sNCg0KTWFya2V0IFJpc2ssIGFsc28ga25vd24gYXMgc3lzdGVtYXRpYyByaXNrLCBjb21wcmlzZXMgYSBzZXJpZXMgb2YgZmFjdG9ycyB0aGF0IGNhbm5vdCBiZSBpbmRpdmlkdWFsaXplZCBidXQgcmF0aGVyIGFmZmVjdCB0aGUgbWFya2V0IGFzIGEgd2hvbGUsIHdpdGhvdXQgdGhlIGNoYW5jZSBvZiBlbGltaW5hdGluZyBpdCB0aHJvdWdoIGRpdmVyc2lmaWNhdGlvbi4gVGhpcyByaXNrIGlzIHVzdWFsbHkgYWZmZWN0ZWQgb3IgbWFkZSBub3RpY2VhYmxlIGJ5IGNoYW5nZXMgb3IgbW92ZW1lbnRzIG9uIHRoZSBtYXJrZXQgcHJpY2UgYW5kIHRoZSBpbnRlcmVzdCByYXRlcywgc28gaXQgaGFzIGFuIHN0cm9uZyBsaW5rIHdpdGggcG9saXRpY3MgYW5kIGVjb25vbWljIGN5Y2xlcy4gDQoNCg0KIyMjIyBDcmVkaXQgUmlzaw0KDQpDcmVkaXQgcmlzayBtZWFzdXJlcyB0aGUgcHJvYmFiaWxpdHkgb2Ygbm90IGJlaW5nIHBheWVkIGJhY2sgYnkgYSBib3Jyb3dlci4gVGhpcyBpcywgdGhlIHJpc2sgb2Ygbm90IGJlaW5nIGFibGUgdG8gcmVjb2xsZWN0IHRoZSBwcmluY2lwYWwgYW5kIHRoZSBpbnRlcmVzdHMsIGxlYWRpbmcgdG8gYSBsb3NzIG9yIGF0IGxlYXN0IGFuIGludGVycnVwdGlvbiBhbmQgZGVsYXkuIFRoaXMgcmlzayBpcyB1c3VhbGx5IGFzc2Vzc2VkIGJ5IGNhcmVmdWxseSBhbmFseXppbmcgdGhlIGJvcnJvd2VyIGFuZCB0YWtpbmcgaW50byBhY2NvdW50IGFsbCBmYWN0b3JzIHRoYXQgY291bGQgbGVhZCB0byBub24tcGF5bWVudC4gV2hlbiB0YWxraW5nIGFib3V0IGNvcnBvcmF0ZSBib25kIGlzc3VlcnMsIHRoZXJlIGFyZSBjcmVkaXQtcmF0aW5nIGFnZW5jaWVzIHdoaWNoIGV2YWx1YXRlIHRoZSBjcmVkaXQgcmlzayBpbiBvcmRlciB0byBpbmZvcm0gdGhlIGludmVzdG9ycyBvZiB0aGUgcHJvYmFiaWxpdHkgb2YgcmVjaWV2aW5nIGJhY2sgdGhlaXIgaW52ZXN0bWVudC4gDQpUaGUgaGlnaGVyIHRoZSBjcmVkaXQgcmlzayBpcywgdGhlIGdyZWF0ZXIgdGhlIGludGVyZXN0IHRoYXQgdGhlIGxlbmRlciBvciBpbnZlc3RvciB3aWxsIGRlbWFuZCwgYXMgdGhlIGNyZWRpdCByaXNrIG11c3QgYmUgY291bnRlcmJhbGFuY2VkIHdpdGggaGlnaGVyIHJld2FyZHMuIA0KDQoNCiMjIyMgUmlzay1XZWlnaHRlZCBBc3NldHMgKFJXQSkNCg0KSW4gdGhlIGV4cGxhbmF0aW9ucyB0aGF0IGZvbGxvdywgd2Ugd2lsbCBiZSB1c2luZyBSV0EgaW4gb3JkZXIgdG8gcmVmZXIgdG8gdGhlIGFzc2V0cyB0aGF0IGEgYmFuayBtdXN0IGhhdmUgdG8gY29tcGx5IHdpdGggdGhlaXIgcmlzayBwcm9maWxlIGFuZCBtaW5pbWl6ZSB0aGVpciByaXNrIG9mIGluc29sdmVuY3ksIHdpdGhpbiB0aGVpciBkZXNpcmVkIGxpbWl0cyBhbmQgb2JqZWN0aXZlcy4gDQoNCg0KIyMjIyBCYXNlbCBJSUkNCg0KQmFzZWwgSUlJIGlzIGFuIGludGVybmF0aW9uYWwgcmVndWxhdGlvbiBkZXNpZ25lZCB0byBhc3N1cmUgdGhlIGJhbmtpbmcgc3lzdGVtJ3Mgc3RhYmlsaXR5IGJ5IHN0YW5kYXJkaXppbmcgdGhlIG1pbmltdW0gY2FwaXRhbCByZXNlcnZlIHJlcXVpcmVtZW50cy4gDQpUaGlzIHJlcXVpcmVtZW50cyBhcmUgZGl2aWRlZCBpbiBjb21tb24gZXF1aXR5IHRpZXJzICgxIGFuZCAyKSwgd2hpY2ggc2hhbGwgYWRkIHRvIGEgbWluaW11bSBvZiA4JS4gVGhpcyA4JSBoYXMgc3RheWVkIHRoZSBzYW1lIHNpbmNlIHRoZSBCYXNlbCBJIHJlZ3VsYXRpb24uIEhvd2V2ZXIsIHRoZXJlIGhhcyBiZWVuIGFuIGFkZGl0aW9uIGluIHRoaXMgc3lzdGVtIHdpdGggdGhlIGltcGxlbWVudGF0aW9uIG9mIGJ1ZmZlcnMsIHdoaWNoIGludHJvZHVjZSBuZXcgcmVxdWlyZW1lbnRzIGZvciBiYW5rczogQ2FwaXRhbCBDb25zZXJ2YXRpb24gQnVmZmVyIChDQ0IsIDIuNSUpLCBDb3VudGVyY3ljbGljYWwgQ2FwaXRhbCBCdWZmZXIgKENDeUIsIDAgdG8gMi41JSksIEdsb2JhbCBTeXN0ZW1hdGljYWxseSBJbXBvcnRhbnQgQmFuayAoRy1TSUIsIDEgdG8gMy41JSBvZiBSV0EpLg0KT3RoZXIgcmVndWxhdGlvbnMgaW4gTGV2ZXJhZ2UgYW5kIExpcXVpZGl0eSBoYXZlIGFsc28gYmVlbiBpbnRyb2R1Y2VkLCBhbHRob3VnaCB3ZSB3aWxsIG5vdCBkaXZlIGludG8gdGhvc2UuIA0KDQoNCiMjIyBDb21wbGV0ZSBBbmFseXNpcyBvZiBDYXBpdGFsIFJlcXVpcmVtZW50cyBhbmQgQ29tcGFyaXNvbg0KDQpGb3IgdGhpcyBhbmFseXNpcywgd2UgaGF2ZSBvYnRhaW5lZCB0aGUgMTAtayBmaWxpbmcgb2YgQmFuayBvZiBBbWVyaWNhIHJlcG9ydGluZyBmb3IgMjAyMyBhbmQgdGhlIDIwLUYgZmlsaW5nIG9mIERldXRzY2hlIEJhbmsgcmVwb3J0aW5nIGZvciAyMDIzLg0KDQoNCiMjIyMgMS4gQmFuayBvZiBBbWVyaWNhIChCT0ZBKQ0KDQojIyMjIyBGcm9tIHRoZSAxMC1LIGZpbGluZywgQk9GQSdzIHJpc2std2VpZ2h0ZWQgYXNzZXRzIChSV0FzKSBhcyBvZiBEZWNlbWJlciAzMSwgMjAyMywgYXJlIGNhdGVnb3JpemVkIGFzIGZvbGxvd3M6DQoNCiAgQ3JlZGl0IFJpc2sgUldBOiAkMSwzOTUgYmlsbGlvbi4NCg0KICBNYXJrZXQgUmlzayBSV0E6ICQxMTkgYmlsbGlvbi4NCg0KICBPcGVyYXRpb25hbCBSaXNrIFJXQTogJDM1NyBiaWxsaW9uIChCT0ZBIDEwaykuDQoNCg0KIyMjIyMgVXNpbmcgdGhlIEJhc2VsIElJSSBtaW5pbXVtIGNhcGl0YWwgcmVxdWlyZW1lbnRzICg4JSksIHRoZSBjYXBpdGFsIHJlcXVpcmVtZW50cyBmb3IgQk9GQSBhcmU6DQoNCkNyZWRpdCBSaXNrIENhcGl0YWwgUmVxdWlyZW1lbnQ6ICQxMTEuNiBiaWxsaW9uLg0KDQpNYXJrZXQgUmlzayBDYXBpdGFsIFJlcXVpcmVtZW50OiAkOS41MiBiaWxsaW9uLg0KDQpPcGVyYXRpb25hbCBSaXNrIENhcGl0YWwgUmVxdWlyZW1lbnQ6ICQyOC41NiBiaWxsaW9uLg0KDQoNCiMjIyMgMi4gRGV1dHNjaGUgQmFuaw0KDQojIyMjIyBCYXNlZCBvbiB0aGUgMjAtRiBmaWxpbmcsIERldXRzY2hlIEJhbmsncyBSV0FzIGFzIG9mIERlY2VtYmVyIDMxLCAyMDIzLCBhcmU6DQoNCkNyZWRpdCBSaXNrIFJXQTog4oKsMjY1Ljc5IGJpbGxpb24uDQoNCk1hcmtldCBSaXNrIFJXQTog4oKsMjEuNTEgYmlsbGlvbi4NCg0KT3BlcmF0aW9uYWwgUmlzayBSV0E6IOKCrDU3LjE1IGJpbGxpb24gKDIwRiBEZXV0c2NoZSkuDQoNCg0KIyMjIyMgQXBwbHlpbmcgdGhlIDglIEJhc2VsIElJSSByZXF1aXJlbWVudDoNCg0KQ3JlZGl0IFJpc2sgQ2FwaXRhbCBSZXF1aXJlbWVudDog4oKsMjEuMjYgYmlsbGlvbi4NCg0KTWFya2V0IFJpc2sgQ2FwaXRhbCBSZXF1aXJlbWVudDog4oKsMS43MiBiaWxsaW9uLg0KDQpPcGVyYXRpb25hbCBSaXNrIENhcGl0YWwgUmVxdWlyZW1lbnQ6IOKCrDQuNTcgYmlsbGlvbi4NCg0KDQoNCiMjIyBDb21wYXJpc29uOiBCT0ZBIHZzLiBEZXV0c2NoZSBCYW5rDQoNCiMjIyMgMS4gQ3JlZGl0IFJpc2sgQ2FwaXRhbA0KDQpCT0ZBOiAkMTExLjYgYmlsbGlvbi4NCg0KRGV1dHNjaGUgQmFuazog4oKsMjEuMjYgYmlsbGlvbiAofiQyMi41MyBiaWxsaW9uIGFzc3VtaW5nIOKCrDEgPSAkMS4wNikuDQoNCkFuYWx5c2lzOiBCT0ZBIGhhcyBhIHNpZ25pZmljYW50bHkgaGlnaGVyIGNyZWRpdCByaXNrIGNhcGl0YWwgcmVxdWlyZW1lbnQsIHJlZmxlY3RpbmcgYSBsYXJnZXIgcG9ydGZvbGlvIG9mIGxvYW5zIGFuZCBjb3VudGVycGFydHkgZXhwb3N1cmVzLg0KDQoNCiMjIyMgMi4gTWFya2V0IFJpc2sgQ2FwaXRhbA0KDQpCT0ZBOiAkOS41MiBiaWxsaW9uLg0KDQpEZXV0c2NoZSBCYW5rOiDigqwxLjcyIGJpbGxpb24gKH4kMS44MiBiaWxsaW9uKS4NCg0KQW5hbHlzaXM6IEJPRkEncyBtYXJrZXQgcmlzayBleHBvc3VyZSBpcyBtdWNoIGxhcmdlciwgbGlrZWx5IGR1ZSB0byBleHRlbnNpdmUgdHJhZGluZyBhbmQgaW52ZXN0bWVudCBhY3Rpdml0aWVzIGluIGdsb2JhbCBtYXJrZXRzLiANCg0KDQojIyMjIDMuIE9wZXJhdGlvbmFsIFJpc2sgQ2FwaXRhbA0KDQpCT0ZBOiAkMjguNTYgYmlsbGlvbi4NCg0KRGV1dHNjaGUgQmFuazog4oKsNC41NyBiaWxsaW9uICh+JDQuODQgYmlsbGlvbikuDQoNCkFuYWx5c2lzOiBCT0ZBJ3Mgb3BlcmF0aW9uYWwgcmlzayBjYXBpdGFsIGlzIHNpZ25pZmljYW50bHkgaGlnaGVyLCBzdWdnZXN0aW5nIG1vcmUgY29tcGxleCBvcGVyYXRpb25zIG9yIGEgbGFyZ2VyIGdlb2dyYXBoaWMgcHJlc2VuY2UgcmVxdWlyaW5nIGhpZ2hlciByZXNlcnZlcy4gQXMgd2Uga25vdywgb3BlcmF0aW9uYWwgcmlzayBpbmNsdWRlcyBwZW9wbGUsIHN5c3RlbXMgYW5kIGludGVybmFsIHByb2NlZHVyZXMsIHNvIHRoZSBoaWdoZXIgdGhlIGFtb3VudCBvZiBvcGVyYXRpb25zIGFuZCB0aGUgbGFyZ2VyIGdlb2dyYXBoaWMgZXh0ZW5zaW9uLCB0aGUgcmlza2llciBhbmQgbW9yZSBkaWZmaWN1bHQgdG8gbWFuYWdlIGl0IGdldHMuIA0KDQoNCg0KIyMjIENvbmNsdXNpb246IFdoaWNoIEJhbmsgSGFzIGEgQmV0dGVyIENhcGl0YWwgQmFzZT8NCg0KQk9GQTogSGlnaGVyIG92ZXJhbGwgY2FwaXRhbCByZXF1aXJlbWVudHMgcmVmbGVjdCBpdHMgdmFzdCBvcGVyYXRpb25zLCBsYXJnZXIgYXNzZXQgYmFzZSwgYW5kIHNpZ25pZmljYW50IGdsb2JhbCBtYXJrZXQgcHJlc2VuY2UuIEhvd2V2ZXIsIHRoZSBoaWdoZXIgb3BlcmF0aW9uYWwgYW5kIG1hcmtldCByaXNrIGNhcGl0YWwgcmVxdWlyZW1lbnRzIGluZGljYXRlIGdyZWF0ZXIgcmlzayBleHBvc3VyZS4NCg0KRGV1dHNjaGUgQmFuazogUmVsYXRpdmVseSBsb3dlciBjYXBpdGFsIHJlcXVpcmVtZW50cyBhY3Jvc3MgYWxsIGNhdGVnb3JpZXMgc3VnZ2VzdCBhIHNtYWxsZXIgZ2xvYmFsIGZvb3RwcmludCBvciBsZXNzIGNvbXBsZXggb3BlcmF0aW9ucy4gSG93ZXZlciwgdGhpcyBjb3VsZCBhbHNvIHJlZmxlY3QgZGlmZmVyZW5jZXMgaW4gcmlzayBhcHBldGl0ZSBvciBvcGVyYXRpb25hbCBzY2FsZS4NCg0KQmV0dGVyIENhcGl0YWwgQmFzZTogQk9GQSBob2xkcyBhIHN0cm9uZ2VyIGNhcGl0YWwgYmFzZSBpbiBhYnNvbHV0ZSB0ZXJtcywgZ2l2ZW4gaXRzIGhpZ2hlciBjYXBpdGFsIGFsbG9jYXRpb25zLiBIb3dldmVyLCBEZXV0c2NoZSBCYW5rJ3MgbG93ZXIgcmlzayBleHBvc3VyZXMgbWF5IHRyYW5zbGF0ZSBpbnRvIGEgbW9yZSBlZmZpY2llbnQgY2FwaXRhbCBzdHJ1Y3R1cmUuIFRoZSBjaG9pY2UgZGVwZW5kcyBvbiB3aGV0aGVyIG9uZSBwcmlvcml0aXplcyBhYnNvbHV0ZSBzdHJlbmd0aCAoQk9GQSkgb3IgcmVsYXRpdmUgZWZmaWNpZW5jeSAoRGV1dHNjaGUgQmFuaykuDQo=