Submitted to: Jon Spinney
Submitted by: Md Mahmudul Hasan

Problem 1



- Calculate the cumulative total price return for each of the 60 stocks as well as the TSX Composite Index from the beginning of the period to the end. - Calculate the daily standard deviation of returns for each of the 60 stocks as well as the TSX Composite Index (annualize this number using the √N rule). - Create a scatterplot in R plotting the standard deviation vs. the return for the year to date period for each of the 61 time series, with standard deviation on the x-axis.
Use a different point style for the TSX Composite Index to highlight the index vs. the individual stocks.


tsx_members <- read.csv("a1_tsx60memb.csv")
tsx_prices <- read.csv("a1_tsx60membpx.csv")
tsx_composite <- read.csv("a1_sptsxpx.csv")%>% 
  rename(Date = Dates, Price=S.P.TSX.Composite.Index.Level)

# Reshape the data to a long format
tsx_prices_long <- tsx_prices %>%
  pivot_longer(cols = -Date, names_to = "Ticker", values_to = "Price")

tsx_prices_long$Date <- as.Date(tsx_prices_long$Date)
tsx_composite$Date <- as.Date(tsx_composite$Date) 

# cumulative returns
cumulative_returns <- tsx_prices_long %>%
  group_by(Ticker) %>%
  summarize(cumulative_return = (last(Price) - first(Price)) / first(Price) * 100)

cumulative_returns %>%
  kbl(caption = "Cumulative Returns of S&P/TSX 60 Stocks") %>%
  kable_styling(full_width = F, position = "center", bootstrap_options = c("striped", "hover")) %>%
  scroll_box(height = "300px")  
Cumulative Returns of S&P/TSX 60 Stocks
Ticker cumulative_return
ABX -29.7738033
AEM -23.0848153
ARX -9.6542727
ATD.B -4.3185299
BAM.A 3.4700315
BB -7.5233023
BBD.B 45.6081081
BCE -10.9717344
BHC 10.6461087
BMO 6.5862894
BNS -7.3024055
CCL.B 9.6442274
CCO 11.9735756
CM -0.0898619
CNQ -2.5797989
CNR 11.3926480
CP 19.7182484
CPG -20.0598802
CSU 30.9432324
CTC.A -0.5663825
CVE -0.6568144
DOL -4.4839326
ECA 0.6406523
EMA -12.5026489
ENB -11.4228856
FM -9.3576966
FNV -16.0849009
FTS -6.1717549
G -14.5972138
GIB.A 25.4795724
GIL -4.8490846
HSE 16.7748918
IMO 3.0141844
IPL -8.2280903
K -30.3571429
L -1.5891529
MFC -8.5057471
MG -1.1748252
MRU 1.1636544
NA. 4.5964126
NTR 6.2898551
OTEX 17.4391923
POW -8.9068826
PPL -2.6678329
QSR -4.1858679
RCI.B 7.1632330
RY 0.6896552
SAP -10.9824014
SJR.B -7.8431373
SLF 0.7575758
SNC -7.5013207
SU 14.7127909
T 2.1101498
TD 6.7019400
TECK.B -12.7817319
TRI 6.0091324
TRP -9.9189627
WCN 18.2575931
WN -6.7694001
WPM -19.7991392
# daily returns and annualized standard deviation
daily_sd <- tsx_prices_long %>%
  arrange(Date) %>%
  group_by(Ticker) %>%
  mutate(daily_return = (Price - lag(Price)) / lag(Price)*100) %>%
  summarize(annualized_sd = sd(daily_return, na.rm = TRUE) * sqrt(252))

# Combine cumulative returns and standard deviations
tsx_data <- cumulative_returns %>%
  left_join(daily_sd, by = "Ticker")

# Now add the TSX Composite Index
tsx_composite_return <- (last(tsx_composite$Price) - first(tsx_composite$Price)) / first(tsx_composite$Price) * 100

# standard deviation for the TSX Composite Index
tsx_composite_sd <- tsx_composite %>%
  arrange(Date) %>%
  mutate(daily_return = (Price - lag(Price)) / lag(Price)*100) %>%
  summarize(annualized_sd = sd(daily_return, na.rm = TRUE) * sqrt(252))

# Combine stock data with the TSX Composite Index data
tsx_index_data <- data.frame(
  Ticker = "TSX Composite",
  cumulative_return = tsx_composite_return,
  annualized_sd = tsx_composite_sd$annualized_sd)
tsx_final_data <- bind_rows(tsx_data, tsx_index_data)

tsx_final_data %>%
  kbl(caption = "Combined Data of S&P/TSX Stocks and Index") %>%
  kable_styling(full_width = F, position = "center", bootstrap_options = c("striped", "hover")) %>%
  scroll_box(height = "300px")  
Combined Data of S&P/TSX Stocks and Index
Ticker cumulative_return annualized_sd
ABX -29.7738033 25.121116
AEM -23.0848153 26.099193
ARX -9.6542727 30.004314
ATD.B -4.3185299 21.953643
BAM.A 3.4700315 17.476855
BB -7.5233023 38.498023
BBD.B 45.6081081 40.012873
BCE -10.9717344 10.477512
BHC 10.6461087 45.848530
BMO 6.5862894 9.885924
BNS -7.3024055 10.987753
CCL.B 9.6442274 20.766257
CCO 11.9735756 31.718613
CM -0.0898619 10.088510
CNQ -2.5797989 26.151464
CNR 11.3926480 17.256581
CP 19.7182484 18.328382
CPG -20.0598802 41.040571
CSU 30.9432324 26.380750
CTC.A -0.5663825 20.694332
CVE -0.6568144 40.416859
DOL -4.4839326 21.565915
ECA 0.6406523 36.408975
EMA -12.5026489 15.861490
ENB -11.4228856 25.356114
FM -9.3576966 50.754969
FNV -16.0849009 20.653859
FTS -6.1717549 13.577737
G -14.5972138 28.475413
GIB.A 25.4795724 13.909277
GIL -4.8490846 33.880666
HSE 16.7748918 28.499753
IMO 3.0141844 21.492078
IPL -8.2280903 18.130873
K -30.3571429 37.514344
L -1.5891529 14.510301
MFC -8.5057471 15.259372
MG -1.1748252 28.181916
MRU 1.1636544 16.838633
NA. 4.5964126 11.118090
NTR 6.2898551 25.303495
OTEX 17.4391923 24.277977
POW -8.9068826 11.924285
PPL -2.6678329 19.165443
QSR -4.1858679 21.227851
RCI.B 7.1632330 14.668132
RY 0.6896552 10.718949
SAP -10.9824014 17.966009
SJR.B -7.8431373 18.132636
SLF 0.7575758 13.977093
SNC -7.5013207 16.997317
SU 14.7127909 21.693145
T 2.1101498 9.975501
TD 6.7019400 10.069219
TECK.B -12.7817319 34.493222
TRI 6.0091324 18.867391
TRP -9.9189627 20.351396
WCN 18.2575931 15.430204
WN -6.7694001 13.589204
WPM -19.7991392 22.626394
TSX Composite -0.2888414 12.893525
ggplot(tsx_final_data, aes(x = annualized_sd, y = cumulative_return, label = Ticker)) +
  geom_point(aes(shape = ifelse(Ticker == "TSX Composite", "Index", "Stock"), 
                 color = ifelse(Ticker == "TSX Composite", "Index", "Stock")), size = 3) +
  scale_shape_manual(values = c("Index" = 16, "Stock" = 17)) +  
  scale_color_manual(values = c("Index" = "#4584b6", "Stock" = "#ffde57")) +  
  labs(title = "Standard Deviation vs. Return for TSX Stocks and Composite Index",
       x = "Annualized Standard Deviation",
       y = "Cumulative Return (%)",
       color = "Legend",
       shape = "Legend") +
  theme_minimal(base_size = 15) +  
  geom_text(aes(label = Ticker), 
            hjust = 0.5, 
            vjust = -1,  
            size = 3, 
            check_overlap = TRUE) +  
  theme(legend.position = "top",  
        legend.box = "horizontal")  


Problem 2



In your a1_tsx60memb data frame, create a new column that assigns securities to a group based on market capitalization.
Create three groups - one for securities with less than $20B in market cap, one for securities with a market cap between $20B and $50B, and one for securities with a market cap above $50B. You may name the groups anything, but “Small”, “Mid”, and “Large” seems reasonable.
Use the aggregate() function in base R (or an equivalent function from the CRAN package data.table) to calculate the total weight of securities in each of your three market cap groups. Plot it in a bar chart.

Create another bar chart but use the GICS Sectors as your grouping variable.


tsx_members <- tsx_members %>%
  mutate(market_cap_group = case_when(
    Market.Cap < 20000000000 ~ "Small", 
    Market.Cap >= 20000000000 & Market.Cap <= 50000000000 ~ "Mid",  
    Market.Cap > 50000000000 ~ "Large" 
  ))
# total weight for each market cap group
market_cap_weight <- aggregate(Weight ~ market_cap_group, data = tsx_members, sum)

# bar chart
p <- ggplot(market_cap_weight, aes(x = market_cap_group, y = Weight)) +
  geom_bar(stat = "identity", fill = "#4584b6") +
  labs(title = "Total Weight by Market Cap Group", x = "Market Cap Group", y = "Total Weight") +
  theme_minimal()+
  theme(axis.text.x = element_blank())
interactive_plot <- ggplotly(p)%>%
  layout(hoverlabel = list(bgcolor = "#ffde57", font = list(color = "black")))
interactive_plot
# total weight for each GICS Sector
sector_weight <- aggregate(Weight ~ GICS.Sector, data = tsx_members, sum)

# a bar chart for GICS sectors
p_weight <- ggplot(sector_weight, aes(x = GICS.Sector, y = Weight)) +
  geom_bar(stat = "identity", fill = "#ffde57") +
  labs(title = "Total Weight by GICS Sector", x = "GICS Sector", y = "Total Weight") +
  theme_minimal() +
  theme(axis.text.x = element_blank())
  interactive_plot_weight <- ggplotly(p_weight)%>%
  layout(hoverlabel = list(bgcolor = "#4584b6", font = list(color = "white")))
interactive_plot_weight



Problem 3



The beta of a security is a risk measure that gauges the degree of market sensitivity of that security (high beta stocks have higher market risk, and vice versa) and is generally the slope of a regression line for the returns of that security regressed on the returns on the benchmark index.
For the securities in this sample, calculate the market beta using the TSX Composite Index as the benchmark (you will need to run 60 linear regressions and extract the slope coefficient from each). Use either a loop or preferably an apply() function to accomplish this.
Plot a barplot of the betas of the 60 stocks in your sample over the sample period. Also plot the R-Squared of the 60 regressions in a separate barplot. How effective is a one-factor model such as this in describing the returns?



# daily returns for stocks 
tsx_prices_long <- tsx_prices_long %>%
  arrange(Date) %>%
  group_by(Ticker) %>%
  mutate(daily_return = (Price - lag(Price)) / lag(Price) * 100) %>%
  filter(!is.na(daily_return))  

# daily returns for TSX Composite Index
tsx_composite <- tsx_composite %>%
  arrange(Date) %>%
  mutate(daily_return = (Price - lag(Price)) / lag(Price) * 100) %>%
  filter(!is.na(daily_return))  

# A function to compute beta and R-squared for each stock
calculate_beta <- function(stock_returns, benchmark_returns) {
  model <- lm(stock_returns ~ benchmark_returns)
  beta <- coef(model)[2]  
  r_squared <- summary(model)$r.squared  
  return(c(beta = beta, r_squared = r_squared))}

# Data frame for beta and R-squared 
beta_results <- tsx_prices_long %>%
  group_by(Ticker) %>%
  summarize(
    beta_r_squared = list(calculate_beta(daily_return, tsx_composite$daily_return))
  ) %>%
  unnest_wider(beta_r_squared)

# Rename the columns for clarity
colnames(beta_results) <- c("Ticker", "Beta", "R_Squared")

# Plot the Betas
p_beta <- ggplot(beta_results, aes(x = reorder(Ticker, Beta), y = Beta)) +
  geom_bar(stat = "identity", fill = "#4584b6") +
  labs(title = "Betas of the 60 Stocks", x = "Stock Ticker", y = "Beta") +
  theme_minimal() +
  theme(axis.text.x = element_blank())

interactive_plot_beta <- ggplotly(p_beta)%>%
  layout(hoverlabel = list(bgcolor = "#ffde57", font = list(color = "black")))
interactive_plot_beta
# Plot the R-squared values
p_r_squared <- ggplot(beta_results, aes(x = reorder(Ticker, R_Squared), y = R_Squared)) +
  geom_bar(stat = "identity", fill = "#ffde57") +
  labs(title = "R-Squared of the 60 Regressions", x = "Stock Ticker", y = "R-Squared") +
  theme_minimal() +
  theme(axis.text.x = element_blank())
interactive_r_squared <- ggplotly(p_r_squared)%>%
  layout(hoverlabel = list(bgcolor = "#4584b6", font = list(color = "white")))
interactive_r_squared


Problem 4




Calculate the covariance matrix of the 60 securities in the TSX 60 Index, and use this data to estimate the volatility of:
• The equally weighted portfolio of all 60 securities, • The the TSX Weighted portfolio (use the weights provided in the a1_tsx60memb.csv file) • A portfolio of all 60 securities where the weight is inversely proportional to the beta you estimated in Problem 3 according to the following weight function: \[\omega_i=\dfrac{\dfrac{1}{\beta_i}}{\sum_{i=1}^{N}\dfrac{1}{\beta_i}}\] • An equally weighted portfolio containing only securities in the Financials GICS sector. • Equally weighted portfolios for each of your three market capitalization groups. Create a data frame containing the volatility for each of these 7 portfolios and plot them together in a barchart.


# a pivot table of daily returns
tsx_returns_wide <- tsx_prices_long %>%
  select(Date, Ticker, daily_return) %>%
  pivot_wider(names_from = Ticker, values_from = daily_return)

# covariance matrix for the stocks (excluding the Date)
cov_matrix <- cov(tsx_returns_wide[, -1], use = "pairwise.complete.obs")
# Equally weighted portfolio
equal_weights <- rep(1/60, 60)
equal_portfolio_variance <- t(equal_weights) %*% cov_matrix %*% equal_weights
equal_portfolio_sd <- sqrt(equal_portfolio_variance)
# Extract the weights from the members data
tsx_weights <- tsx_members$Weight / 100 
tsx_portfolio_variance <- t(tsx_weights) %*% cov_matrix %*% tsx_weights
tsx_portfolio_sd <- sqrt(tsx_portfolio_variance)  
# weights inversely proportional to beta
inverse_beta_weights <- 1 / beta_results$Beta
inverse_beta_weights <- inverse_beta_weights / sum(inverse_beta_weights)

# Inversely proportional to beta portfolio
inv_beta_portfolio_variance <- t(inverse_beta_weights) %*% cov_matrix %*% inverse_beta_weights
inv_beta_portfolio_sd <- sqrt(inv_beta_portfolio_variance)  
# Filter for Financials sector
financials_tickers <- tsx_members %>%
  filter(GICS.Sector == "Financials") %>%
  pull(Ticker)
financials_tickers <- na.omit(financials_tickers)

# Subset the covariance matrix for Financials tickers
financials_cov_matrix <- cov_matrix[financials_tickers, financials_tickers]

# Equal weights for Financials sector (after removing NA)
financials_weights <- rep(1/length(financials_tickers), length(financials_tickers))

# Financials portfolio variance
financials_portfolio_variance <- t(financials_weights) %*% financials_cov_matrix %*% financials_weights
financials_portfolio_sd <- sqrt(financials_portfolio_variance)
# Small Cap Portfolio
small_cap_tickers <- tsx_members %>%
  filter(market_cap_group == "Small") %>%
  pull(Ticker)

# Remove the invalid ticker from small_cap_tickers
small_cap_tickers <- small_cap_tickers[small_cap_tickers %in% rownames(cov_matrix)]

small_cap_weights <- rep(1/length(small_cap_tickers), length(small_cap_tickers))
small_cap_cov_matrix <- cov_matrix[small_cap_tickers, small_cap_tickers]
small_cap_portfolio_variance <- t(small_cap_weights) %*% small_cap_cov_matrix %*% small_cap_weights
small_cap_portfolio_sd <- sqrt(small_cap_portfolio_variance)

# Mid Cap Portfolio
mid_cap_tickers <- tsx_members %>%
  filter(market_cap_group == "Mid") %>%
  pull(Ticker)
mid_cap_weights <- rep(1/length(mid_cap_tickers), length(mid_cap_tickers))

# Remove the invalid tickers from mid_cap_tickers
mid_cap_tickers <- mid_cap_tickers[mid_cap_tickers %in% rownames(cov_matrix)]
mid_cap_cov_matrix <- cov_matrix[mid_cap_tickers, mid_cap_tickers]
mid_cap_weights <- rep(1 / length(mid_cap_tickers), length(mid_cap_tickers))
mid_cap_portfolio_variance <- t(mid_cap_weights) %*% mid_cap_cov_matrix %*% mid_cap_weights
mid_cap_portfolio_sd <- sqrt(mid_cap_portfolio_variance)

# Large Cap Portfolio
large_cap_tickers <- tsx_members %>%
  filter(market_cap_group == "Large") %>%
  pull(Ticker)
large_cap_weights <- rep(1/length(large_cap_tickers), length(large_cap_tickers))
large_cap_cov_matrix <- cov_matrix[large_cap_tickers, large_cap_tickers]
large_cap_portfolio_variance <- t(large_cap_weights) %*% large_cap_cov_matrix %*% large_cap_weights
large_cap_portfolio_sd <- sqrt(large_cap_portfolio_variance)
# a data frame with the volatilities
volatility_data <- data.frame(
  Portfolio = c("Equally Weighted", "TSX Weighted", "Inverse Beta Weighted", 
                "Financials Sector", "Small Cap", "Mid Cap", "Large Cap"),
  Volatility = c(equal_portfolio_sd, tsx_portfolio_sd, inv_beta_portfolio_sd, 
                 financials_portfolio_sd, small_cap_portfolio_sd, mid_cap_portfolio_sd, large_cap_portfolio_sd))
# ggplot bar chart
p <- ggplot(volatility_data, aes(x = Portfolio, y = Volatility)) +
  geom_bar(stat = "identity", fill = "#4584b6") +
  labs(title = "Volatility of Different Portfolios", x = "Portfolio", y = "Volatility (Standard Deviation)") +
  theme_minimal() +
  theme(axis.text.x = element_blank())
interactive_plot <- ggplotly(p) %>%
  layout(hoverlabel = list(bgcolor = "#ffde57", font = list(color = "black")))  
interactive_plot

Problem 5




Install the package quantmod and download prices of the S&P 500 using the function getSymbols() (ticker“ˆGSPC”). Calculate the daily returns and compare against a normal distribution using a qqnorm() and qqline() plot.



# Download prices of the S&P 500 using getSymbols()
getSymbols("^GSPC", src = "yahoo", from = "2010-01-01", to = Sys.Date())
## [1] "GSPC"
# daily returns- Using Adjusted Close prices to account for dividends and stock splits
sp500_prices <- Ad(GSPC)  
daily_returns <- diff(log(sp500_prices))  
daily_returns <- na.omit(daily_returns)  

# a Q-Q plot to compare against a normal distribution
qqnorm(daily_returns, main = "Q-Q Plot of Daily Returns of S&P 500")
qqline(daily_returns, col = "red")  




Md Mahmudul Hasan
MQIM 3760573
Faculty of Management
University of New Brunswick
mahmudul.hasan@unb.ca


LS0tDQp0aXRsZTogIjxzcGFuIHN0eWxlPSdmb250LXNpemU6MjVweDsnPkFzc2lnbm1lbnQgb24gLSBRdWFudGl0YXRpdmUgU3R1ZGVudCBJbnZlc3RtZW50IEZ1bmQ8L3NwYW4+Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgaGlnaGxpZ2h0OiBlc3ByZXNzbw0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQojIyMjIyMgKipTdWJtaXR0ZWQgdG86KiogKipKb24gU3Bpbm5leSoqDQojIyMjIyMgKipTdWJtaXR0ZWQgYnk6KiogTWQgTWFobXVkdWwgSGFzYW4NCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+IGJvZHksIHRkIHtmb250LXNpemU6IDE0cHg7fSBjb2RlLnJ7Zm9udC1zaXplOiAxMnB4O30gcHJlIHtmb250LXNpemU6IDE0cHh9IDwvc3R5bGU+DQo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9jb2RlLmpxdWVyeS5jb20vanF1ZXJ5LTMuNy4xLnNsaW0ubWluLmpzIj48L3NjcmlwdD4NCjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4NCiAgJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24oKSB7DQogICQoJ2EnKS5hdHRyKCd0YXJnZXQnLCAnX2JsYW5rJyk7DQogIH0pOw0KPC9zY3JpcHQ+DQo8c3R5bGU+DQouYm94ZWQgew0KICBiYWNrZ3JvdW5kOiAjMjMyMDIzOw0KICBjb2xvcjogd2hpdGU7DQogIGJvcmRlcjogMHB4IHNvbGlkICM1MzUzNTM7DQogIG1hcmdpbjogMHB4IGF1dG87DQogIHdpZHRoOiBhdXRvOw0KICBwYWRkaW5nOiAxMHB4Ow0KICBib3JkZXItcmFkaXVzOiAwcHg7DQp9DQo8L3N0eWxlPg0KDQojICB7LnRhYnNldH0NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCglmaWcuYWxpZ24gPSAiY2VudGVyIiwNCgltZXNzYWdlID0gRkFMU0UsDQoJd2FybmluZyA9IEZBTFNFDQopDQpsaWJyYXJ5KGZwcDIpDQpsaWJyYXJ5KHRpZHlxdWFudCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkoY3VybCkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShjb3dwbG90KQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmVzaGFwZTIpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeShndEV4dHJhcykNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGdnZm9ydGlmeSkNCmxpYnJhcnkobW9tZW50cykNCmxpYnJhcnkoc2tpbXIpDQpsaWJyYXJ5KHBzeWNoKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShmb3JlY2FzdCkNCmxpYnJhcnkodHNlcmllcykNCmxpYnJhcnkodGliYmxlKQ0KYGBgDQoNCiMjIFByb2JsZW0gMQ0KPGJyPg0KPGRpdiBjbGFzcz0iYm94ZWQiPg0KPGJyPg0KLSBDYWxjdWxhdGUgdGhlIGN1bXVsYXRpdmUgdG90YWwgcHJpY2UgcmV0dXJuIGZvciBlYWNoIG9mIHRoZSA2MCBzdG9ja3MgYXMgd2VsbCBhcyB0aGUgVFNYIENvbXBvc2l0ZSBJbmRleCBmcm9tIHRoZSBiZWdpbm5pbmcgb2YgdGhlIHBlcmlvZCB0byB0aGUgZW5kLg0KLSBDYWxjdWxhdGUgdGhlIGRhaWx5IHN0YW5kYXJkIGRldmlhdGlvbiBvZiByZXR1cm5zIGZvciBlYWNoIG9mIHRoZSA2MCBzdG9ja3MgYXMgd2VsbCBhcyB0aGUgVFNYIENvbXBvc2l0ZSBJbmRleCAoYW5udWFsaXplIHRoaXMgbnVtYmVyIHVzaW5nIHRoZSDiiJpOIHJ1bGUpLg0KLSBDcmVhdGUgYSBzY2F0dGVycGxvdCBpbiBSIHBsb3R0aW5nIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gdnMuIHRoZSByZXR1cm4gZm9yIHRoZSB5ZWFyIHRvIGRhdGUgcGVyaW9kIGZvciBlYWNoIG9mIHRoZSA2MSB0aW1lIHNlcmllcywgd2l0aCBzdGFuZGFyZCBkZXZpYXRpb24gb24gdGhlIHgtYXhpcy4gDQo8YnI+DQpVc2UgYSBkaWZmZXJlbnQgcG9pbnQgc3R5bGUgZm9yIHRoZSBUU1ggQ29tcG9zaXRlIEluZGV4IHRvIGhpZ2hsaWdodCB0aGUgaW5kZXggdnMuIHRoZSBpbmRpdmlkdWFsIHN0b2Nrcy4NCjxicj4NCjwvZGl2Pg0KPGJyPg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KdHN4X21lbWJlcnMgPC0gcmVhZC5jc3YoImExX3RzeDYwbWVtYi5jc3YiKQ0KdHN4X3ByaWNlcyA8LSByZWFkLmNzdigiYTFfdHN4NjBtZW1icHguY3N2IikNCnRzeF9jb21wb3NpdGUgPC0gcmVhZC5jc3YoImExX3NwdHN4cHguY3N2IiklPiUgDQogIHJlbmFtZShEYXRlID0gRGF0ZXMsIFByaWNlPVMuUC5UU1guQ29tcG9zaXRlLkluZGV4LkxldmVsKQ0KDQojIFJlc2hhcGUgdGhlIGRhdGEgdG8gYSBsb25nIGZvcm1hdA0KdHN4X3ByaWNlc19sb25nIDwtIHRzeF9wcmljZXMgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gLURhdGUsIG5hbWVzX3RvID0gIlRpY2tlciIsIHZhbHVlc190byA9ICJQcmljZSIpDQoNCnRzeF9wcmljZXNfbG9uZyREYXRlIDwtIGFzLkRhdGUodHN4X3ByaWNlc19sb25nJERhdGUpDQp0c3hfY29tcG9zaXRlJERhdGUgPC0gYXMuRGF0ZSh0c3hfY29tcG9zaXRlJERhdGUpIA0KDQojIGN1bXVsYXRpdmUgcmV0dXJucw0KY3VtdWxhdGl2ZV9yZXR1cm5zIDwtIHRzeF9wcmljZXNfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoVGlja2VyKSAlPiUNCiAgc3VtbWFyaXplKGN1bXVsYXRpdmVfcmV0dXJuID0gKGxhc3QoUHJpY2UpIC0gZmlyc3QoUHJpY2UpKSAvIGZpcnN0KFByaWNlKSAqIDEwMCkNCg0KY3VtdWxhdGl2ZV9yZXR1cm5zICU+JQ0KICBrYmwoY2FwdGlvbiA9ICJDdW11bGF0aXZlIFJldHVybnMgb2YgUyZQL1RTWCA2MCBTdG9ja3MiKSAlPiUNCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRiwgcG9zaXRpb24gPSAiY2VudGVyIiwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpICU+JQ0KICBzY3JvbGxfYm94KGhlaWdodCA9ICIzMDBweCIpICANCg0KYGBgDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBkYWlseSByZXR1cm5zIGFuZCBhbm51YWxpemVkIHN0YW5kYXJkIGRldmlhdGlvbg0KZGFpbHlfc2QgPC0gdHN4X3ByaWNlc19sb25nICU+JQ0KICBhcnJhbmdlKERhdGUpICU+JQ0KICBncm91cF9ieShUaWNrZXIpICU+JQ0KICBtdXRhdGUoZGFpbHlfcmV0dXJuID0gKFByaWNlIC0gbGFnKFByaWNlKSkgLyBsYWcoUHJpY2UpKjEwMCkgJT4lDQogIHN1bW1hcml6ZShhbm51YWxpemVkX3NkID0gc2QoZGFpbHlfcmV0dXJuLCBuYS5ybSA9IFRSVUUpICogc3FydCgyNTIpKQ0KDQojIENvbWJpbmUgY3VtdWxhdGl2ZSByZXR1cm5zIGFuZCBzdGFuZGFyZCBkZXZpYXRpb25zDQp0c3hfZGF0YSA8LSBjdW11bGF0aXZlX3JldHVybnMgJT4lDQogIGxlZnRfam9pbihkYWlseV9zZCwgYnkgPSAiVGlja2VyIikNCg0KIyBOb3cgYWRkIHRoZSBUU1ggQ29tcG9zaXRlIEluZGV4DQp0c3hfY29tcG9zaXRlX3JldHVybiA8LSAobGFzdCh0c3hfY29tcG9zaXRlJFByaWNlKSAtIGZpcnN0KHRzeF9jb21wb3NpdGUkUHJpY2UpKSAvIGZpcnN0KHRzeF9jb21wb3NpdGUkUHJpY2UpICogMTAwDQoNCiMgc3RhbmRhcmQgZGV2aWF0aW9uIGZvciB0aGUgVFNYIENvbXBvc2l0ZSBJbmRleA0KdHN4X2NvbXBvc2l0ZV9zZCA8LSB0c3hfY29tcG9zaXRlICU+JQ0KICBhcnJhbmdlKERhdGUpICU+JQ0KICBtdXRhdGUoZGFpbHlfcmV0dXJuID0gKFByaWNlIC0gbGFnKFByaWNlKSkgLyBsYWcoUHJpY2UpKjEwMCkgJT4lDQogIHN1bW1hcml6ZShhbm51YWxpemVkX3NkID0gc2QoZGFpbHlfcmV0dXJuLCBuYS5ybSA9IFRSVUUpICogc3FydCgyNTIpKQ0KDQojIENvbWJpbmUgc3RvY2sgZGF0YSB3aXRoIHRoZSBUU1ggQ29tcG9zaXRlIEluZGV4IGRhdGENCnRzeF9pbmRleF9kYXRhIDwtIGRhdGEuZnJhbWUoDQogIFRpY2tlciA9ICJUU1ggQ29tcG9zaXRlIiwNCiAgY3VtdWxhdGl2ZV9yZXR1cm4gPSB0c3hfY29tcG9zaXRlX3JldHVybiwNCiAgYW5udWFsaXplZF9zZCA9IHRzeF9jb21wb3NpdGVfc2QkYW5udWFsaXplZF9zZCkNCnRzeF9maW5hbF9kYXRhIDwtIGJpbmRfcm93cyh0c3hfZGF0YSwgdHN4X2luZGV4X2RhdGEpDQoNCnRzeF9maW5hbF9kYXRhICU+JQ0KICBrYmwoY2FwdGlvbiA9ICJDb21iaW5lZCBEYXRhIG9mIFMmUC9UU1ggU3RvY2tzIGFuZCBJbmRleCIpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGLCBwb3NpdGlvbiA9ICJjZW50ZXIiLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkgJT4lDQogIHNjcm9sbF9ib3goaGVpZ2h0ID0gIjMwMHB4IikgIA0KDQpnZ3Bsb3QodHN4X2ZpbmFsX2RhdGEsIGFlcyh4ID0gYW5udWFsaXplZF9zZCwgeSA9IGN1bXVsYXRpdmVfcmV0dXJuLCBsYWJlbCA9IFRpY2tlcikpICsNCiAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBpZmVsc2UoVGlja2VyID09ICJUU1ggQ29tcG9zaXRlIiwgIkluZGV4IiwgIlN0b2NrIiksIA0KICAgICAgICAgICAgICAgICBjb2xvciA9IGlmZWxzZShUaWNrZXIgPT0gIlRTWCBDb21wb3NpdGUiLCAiSW5kZXgiLCAiU3RvY2siKSksIHNpemUgPSAzKSArDQogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJJbmRleCIgPSAxNiwgIlN0b2NrIiA9IDE3KSkgKyAgDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJJbmRleCIgPSAiIzQ1ODRiNiIsICJTdG9jayIgPSAiI2ZmZGU1NyIpKSArICANCiAgbGFicyh0aXRsZSA9ICJTdGFuZGFyZCBEZXZpYXRpb24gdnMuIFJldHVybiBmb3IgVFNYIFN0b2NrcyBhbmQgQ29tcG9zaXRlIEluZGV4IiwNCiAgICAgICB4ID0gIkFubnVhbGl6ZWQgU3RhbmRhcmQgRGV2aWF0aW9uIiwNCiAgICAgICB5ID0gIkN1bXVsYXRpdmUgUmV0dXJuICglKSIsDQogICAgICAgY29sb3IgPSAiTGVnZW5kIiwNCiAgICAgICBzaGFwZSA9ICJMZWdlbmQiKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTUpICsgIA0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gVGlja2VyKSwgDQogICAgICAgICAgICBoanVzdCA9IDAuNSwgDQogICAgICAgICAgICB2anVzdCA9IC0xLCAgDQogICAgICAgICAgICBzaXplID0gMywgDQogICAgICAgICAgICBjaGVja19vdmVybGFwID0gVFJVRSkgKyAgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLCAgDQogICAgICAgIGxlZ2VuZC5ib3ggPSAiaG9yaXpvbnRhbCIpICANCmBgYA0KPGJyPg0KDQojIyBQcm9ibGVtIDINCjxicj4NCjxkaXYgY2xhc3M9ImJveGVkIj4NCjxicj4NCkluIHlvdXIgKmExX3RzeDYwbWVtYiogZGF0YSBmcmFtZSwgY3JlYXRlIGEgbmV3IGNvbHVtbiB0aGF0IGFzc2lnbnMgc2VjdXJpdGllcyB0byBhIGdyb3VwIGJhc2VkIG9uIG1hcmtldCBjYXBpdGFsaXphdGlvbi4gDQo8YnI+DQpDcmVhdGUgdGhyZWUgZ3JvdXBzIC0gb25lIGZvciBzZWN1cml0aWVzIHdpdGggbGVzcyB0aGFuIFwkMjBCIGluIG1hcmtldCBjYXAsIG9uZSBmb3Igc2VjdXJpdGllcyB3aXRoIGEgbWFya2V0IGNhcCBiZXR3ZWVuIFwkMjBCIGFuZCBcJDUwQiwgYW5kIG9uZSBmb3Igc2VjdXJpdGllcyB3aXRoIGEgbWFya2V0IGNhcCBhYm92ZSAkNTBCLiBZb3UgbWF5IG5hbWUgdGhlIGdyb3VwcyBhbnl0aGluZywgYnV0IOKAnFNtYWxs4oCdLCDigJxNaWTigJ0sIGFuZCDigJxMYXJnZeKAnSBzZWVtcyByZWFzb25hYmxlLg0KPGJyPg0KVXNlIHRoZSAqYWdncmVnYXRlKCkqIGZ1bmN0aW9uIGluIGJhc2UgUiAob3IgYW4gZXF1aXZhbGVudCBmdW5jdGlvbiBmcm9tIHRoZSBDUkFOIHBhY2thZ2UgZGF0YS50YWJsZSkgdG8gY2FsY3VsYXRlIHRoZSB0b3RhbCB3ZWlnaHQgb2Ygc2VjdXJpdGllcyBpbiBlYWNoIG9mIHlvdXIgdGhyZWUgbWFya2V0IGNhcCBncm91cHMuIFBsb3QgaXQgaW4gYSBiYXIgY2hhcnQuXA0KPGJyPg0KQ3JlYXRlIGFub3RoZXIgYmFyIGNoYXJ0IGJ1dCB1c2UgdGhlIEdJQ1MgU2VjdG9ycyBhcyB5b3VyIGdyb3VwaW5nIHZhcmlhYmxlLg0KPGJyPg0KPC9kaXY+DQo8YnI+DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0c3hfbWVtYmVycyA8LSB0c3hfbWVtYmVycyAlPiUNCiAgbXV0YXRlKG1hcmtldF9jYXBfZ3JvdXAgPSBjYXNlX3doZW4oDQogICAgTWFya2V0LkNhcCA8IDIwMDAwMDAwMDAwIH4gIlNtYWxsIiwgDQogICAgTWFya2V0LkNhcCA+PSAyMDAwMDAwMDAwMCAmIE1hcmtldC5DYXAgPD0gNTAwMDAwMDAwMDAgfiAiTWlkIiwgIA0KICAgIE1hcmtldC5DYXAgPiA1MDAwMDAwMDAwMCB+ICJMYXJnZSIgDQogICkpDQojIHRvdGFsIHdlaWdodCBmb3IgZWFjaCBtYXJrZXQgY2FwIGdyb3VwDQptYXJrZXRfY2FwX3dlaWdodCA8LSBhZ2dyZWdhdGUoV2VpZ2h0IH4gbWFya2V0X2NhcF9ncm91cCwgZGF0YSA9IHRzeF9tZW1iZXJzLCBzdW0pDQoNCiMgYmFyIGNoYXJ0DQpwIDwtIGdncGxvdChtYXJrZXRfY2FwX3dlaWdodCwgYWVzKHggPSBtYXJrZXRfY2FwX2dyb3VwLCB5ID0gV2VpZ2h0KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDU4NGI2IikgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIFdlaWdodCBieSBNYXJrZXQgQ2FwIEdyb3VwIiwgeCA9ICJNYXJrZXQgQ2FwIEdyb3VwIiwgeSA9ICJUb3RhbCBXZWlnaHQiKSArDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpDQppbnRlcmFjdGl2ZV9wbG90IDwtIGdncGxvdGx5KHApJT4lDQogIGxheW91dChob3ZlcmxhYmVsID0gbGlzdChiZ2NvbG9yID0gIiNmZmRlNTciLCBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIpKSkNCmludGVyYWN0aXZlX3Bsb3QNCg0KIyB0b3RhbCB3ZWlnaHQgZm9yIGVhY2ggR0lDUyBTZWN0b3INCnNlY3Rvcl93ZWlnaHQgPC0gYWdncmVnYXRlKFdlaWdodCB+IEdJQ1MuU2VjdG9yLCBkYXRhID0gdHN4X21lbWJlcnMsIHN1bSkNCg0KIyBhIGJhciBjaGFydCBmb3IgR0lDUyBzZWN0b3JzDQpwX3dlaWdodCA8LSBnZ3Bsb3Qoc2VjdG9yX3dlaWdodCwgYWVzKHggPSBHSUNTLlNlY3RvciwgeSA9IFdlaWdodCkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiI2ZmZGU1NyIpICsNCiAgbGFicyh0aXRsZSA9ICJUb3RhbCBXZWlnaHQgYnkgR0lDUyBTZWN0b3IiLCB4ID0gIkdJQ1MgU2VjdG9yIiwgeSA9ICJUb3RhbCBXZWlnaHQiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQ0KICBpbnRlcmFjdGl2ZV9wbG90X3dlaWdodCA8LSBnZ3Bsb3RseShwX3dlaWdodCklPiUNCiAgbGF5b3V0KGhvdmVybGFiZWwgPSBsaXN0KGJnY29sb3IgPSAiIzQ1ODRiNiIsIGZvbnQgPSBsaXN0KGNvbG9yID0gIndoaXRlIikpKQ0KaW50ZXJhY3RpdmVfcGxvdF93ZWlnaHQNCmBgYA0KPGJyPg0KPGJyPg0KDQoNCg0KIyMgUHJvYmxlbSAzDQo8YnI+DQo8ZGl2IGNsYXNzPSJib3hlZCI+DQo8YnI+DQpUaGUgYmV0YSBvZiBhIHNlY3VyaXR5IGlzIGEgcmlzayBtZWFzdXJlIHRoYXQgZ2F1Z2VzIHRoZSBkZWdyZWUgb2YgbWFya2V0IHNlbnNpdGl2aXR5IG9mIHRoYXQgc2VjdXJpdHkgKGhpZ2ggYmV0YSBzdG9ja3MgaGF2ZSBoaWdoZXIgbWFya2V0IHJpc2ssIGFuZCB2aWNlIHZlcnNhKSBhbmQgaXMgZ2VuZXJhbGx5IHRoZSBzbG9wZSBvZiBhIHJlZ3Jlc3Npb24gbGluZSBmb3IgdGhlIHJldHVybnMgb2YgdGhhdCBzZWN1cml0eSByZWdyZXNzZWQgb24gdGhlIHJldHVybnMgb24gdGhlIGJlbmNobWFyayBpbmRleC4NCjxicj4NCkZvciB0aGUgc2VjdXJpdGllcyBpbiB0aGlzIHNhbXBsZSwgY2FsY3VsYXRlIHRoZSBtYXJrZXQgYmV0YSB1c2luZyB0aGUgVFNYIENvbXBvc2l0ZSBJbmRleCBhcyB0aGUgYmVuY2htYXJrICh5b3Ugd2lsbCBuZWVkIHRvIHJ1biA2MCBsaW5lYXIgcmVncmVzc2lvbnMgYW5kIGV4dHJhY3QgdGhlIHNsb3BlIGNvZWZmaWNpZW50IGZyb20gZWFjaCkuIFVzZSBlaXRoZXIgYSBsb29wIG9yIHByZWZlcmFibHkgYW4gYXBwbHkoKSBmdW5jdGlvbiB0byBhY2NvbXBsaXNoIHRoaXMuDQo8YnI+DQpQbG90IGEgYmFycGxvdCBvZiB0aGUgYmV0YXMgb2YgdGhlIDYwIHN0b2NrcyBpbiB5b3VyIHNhbXBsZSBvdmVyIHRoZSBzYW1wbGUgcGVyaW9kLiBBbHNvIHBsb3QgdGhlIFItU3F1YXJlZCBvZiB0aGUgNjAgcmVncmVzc2lvbnMgaW4gYSBzZXBhcmF0ZSBiYXJwbG90LiBIb3cgZWZmZWN0aXZlIGlzIGEgb25lLWZhY3RvciBtb2RlbCBzdWNoIGFzIHRoaXMgaW4gZGVzY3JpYmluZyB0aGUgcmV0dXJucz8NCjxicj4NCjwvZGl2Pg0KPGJyPg0KPGJyPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgZGFpbHkgcmV0dXJucyBmb3Igc3RvY2tzIA0KdHN4X3ByaWNlc19sb25nIDwtIHRzeF9wcmljZXNfbG9uZyAlPiUNCiAgYXJyYW5nZShEYXRlKSAlPiUNCiAgZ3JvdXBfYnkoVGlja2VyKSAlPiUNCiAgbXV0YXRlKGRhaWx5X3JldHVybiA9IChQcmljZSAtIGxhZyhQcmljZSkpIC8gbGFnKFByaWNlKSAqIDEwMCkgJT4lDQogIGZpbHRlcighaXMubmEoZGFpbHlfcmV0dXJuKSkgIA0KDQojIGRhaWx5IHJldHVybnMgZm9yIFRTWCBDb21wb3NpdGUgSW5kZXgNCnRzeF9jb21wb3NpdGUgPC0gdHN4X2NvbXBvc2l0ZSAlPiUNCiAgYXJyYW5nZShEYXRlKSAlPiUNCiAgbXV0YXRlKGRhaWx5X3JldHVybiA9IChQcmljZSAtIGxhZyhQcmljZSkpIC8gbGFnKFByaWNlKSAqIDEwMCkgJT4lDQogIGZpbHRlcighaXMubmEoZGFpbHlfcmV0dXJuKSkgIA0KDQojIEEgZnVuY3Rpb24gdG8gY29tcHV0ZSBiZXRhIGFuZCBSLXNxdWFyZWQgZm9yIGVhY2ggc3RvY2sNCmNhbGN1bGF0ZV9iZXRhIDwtIGZ1bmN0aW9uKHN0b2NrX3JldHVybnMsIGJlbmNobWFya19yZXR1cm5zKSB7DQogIG1vZGVsIDwtIGxtKHN0b2NrX3JldHVybnMgfiBiZW5jaG1hcmtfcmV0dXJucykNCiAgYmV0YSA8LSBjb2VmKG1vZGVsKVsyXSAgDQogIHJfc3F1YXJlZCA8LSBzdW1tYXJ5KG1vZGVsKSRyLnNxdWFyZWQgIA0KICByZXR1cm4oYyhiZXRhID0gYmV0YSwgcl9zcXVhcmVkID0gcl9zcXVhcmVkKSl9DQoNCiMgRGF0YSBmcmFtZSBmb3IgYmV0YSBhbmQgUi1zcXVhcmVkIA0KYmV0YV9yZXN1bHRzIDwtIHRzeF9wcmljZXNfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoVGlja2VyKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGJldGFfcl9zcXVhcmVkID0gbGlzdChjYWxjdWxhdGVfYmV0YShkYWlseV9yZXR1cm4sIHRzeF9jb21wb3NpdGUkZGFpbHlfcmV0dXJuKSkNCiAgKSAlPiUNCiAgdW5uZXN0X3dpZGVyKGJldGFfcl9zcXVhcmVkKQ0KDQojIFJlbmFtZSB0aGUgY29sdW1ucyBmb3IgY2xhcml0eQ0KY29sbmFtZXMoYmV0YV9yZXN1bHRzKSA8LSBjKCJUaWNrZXIiLCAiQmV0YSIsICJSX1NxdWFyZWQiKQ0KDQojIFBsb3QgdGhlIEJldGFzDQpwX2JldGEgPC0gZ2dwbG90KGJldGFfcmVzdWx0cywgYWVzKHggPSByZW9yZGVyKFRpY2tlciwgQmV0YSksIHkgPSBCZXRhKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjNDU4NGI2IikgKw0KICBsYWJzKHRpdGxlID0gIkJldGFzIG9mIHRoZSA2MCBTdG9ja3MiLCB4ID0gIlN0b2NrIFRpY2tlciIsIHkgPSAiQmV0YSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpDQoNCmludGVyYWN0aXZlX3Bsb3RfYmV0YSA8LSBnZ3Bsb3RseShwX2JldGEpJT4lDQogIGxheW91dChob3ZlcmxhYmVsID0gbGlzdChiZ2NvbG9yID0gIiNmZmRlNTciLCBmb250ID0gbGlzdChjb2xvciA9ICJibGFjayIpKSkNCmludGVyYWN0aXZlX3Bsb3RfYmV0YQ0KDQojIFBsb3QgdGhlIFItc3F1YXJlZCB2YWx1ZXMNCnBfcl9zcXVhcmVkIDwtIGdncGxvdChiZXRhX3Jlc3VsdHMsIGFlcyh4ID0gcmVvcmRlcihUaWNrZXIsIFJfU3F1YXJlZCksIHkgPSBSX1NxdWFyZWQpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiNmZmRlNTciKSArDQogIGxhYnModGl0bGUgPSAiUi1TcXVhcmVkIG9mIHRoZSA2MCBSZWdyZXNzaW9ucyIsIHggPSAiU3RvY2sgVGlja2VyIiwgeSA9ICJSLVNxdWFyZWQiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQ0KaW50ZXJhY3RpdmVfcl9zcXVhcmVkIDwtIGdncGxvdGx5KHBfcl9zcXVhcmVkKSU+JQ0KICBsYXlvdXQoaG92ZXJsYWJlbCA9IGxpc3QoYmdjb2xvciA9ICIjNDU4NGI2IiwgZm9udCA9IGxpc3QoY29sb3IgPSAid2hpdGUiKSkpDQppbnRlcmFjdGl2ZV9yX3NxdWFyZWQNCmBgYA0KPGJyPg0KDQojIyBQcm9ibGVtIDQNCjxicj4NCjxkaXYgY2xhc3M9ImJveGVkIj4NCjxicj4NCjxicj4NCkNhbGN1bGF0ZSB0aGUgY292YXJpYW5jZSBtYXRyaXggb2YgdGhlIDYwIHNlY3VyaXRpZXMgaW4gdGhlIFRTWCA2MCBJbmRleCwgYW5kIHVzZSB0aGlzIGRhdGEgdG8gZXN0aW1hdGUgdGhlIHZvbGF0aWxpdHkgb2Y6DQo8YnI+DQrigKIgVGhlIGVxdWFsbHkgd2VpZ2h0ZWQgcG9ydGZvbGlvIG9mIGFsbCA2MCBzZWN1cml0aWVzLA0K4oCiIFRoZSB0aGUgVFNYIFdlaWdodGVkIHBvcnRmb2xpbyAodXNlIHRoZSB3ZWlnaHRzIHByb3ZpZGVkIGluIHRoZSBhMV90c3g2MG1lbWIuY3N2IGZpbGUpDQrigKIgQSBwb3J0Zm9saW8gb2YgYWxsIDYwIHNlY3VyaXRpZXMgd2hlcmUgdGhlIHdlaWdodCBpcyBpbnZlcnNlbHkgcHJvcG9ydGlvbmFsIHRvIHRoZSBiZXRhIHlvdSBlc3RpbWF0ZWQgaW4gUHJvYmxlbSAzIGFjY29yZGluZyB0byB0aGUgZm9sbG93aW5nIHdlaWdodCBmdW5jdGlvbjoNCiQkXG9tZWdhX2k9XGRmcmFje1xkZnJhY3sxfXtcYmV0YV9pfX17XHN1bV97aT0xfV57Tn1cZGZyYWN7MX17XGJldGFfaX19JCQNCuKAoiBBbiBlcXVhbGx5IHdlaWdodGVkIHBvcnRmb2xpbyBjb250YWluaW5nIG9ubHkgc2VjdXJpdGllcyBpbiB0aGUgRmluYW5jaWFscyBHSUNTIHNlY3Rvci4NCuKAoiBFcXVhbGx5IHdlaWdodGVkIHBvcnRmb2xpb3MgZm9yIGVhY2ggb2YgeW91ciB0aHJlZSBtYXJrZXQgY2FwaXRhbGl6YXRpb24gZ3JvdXBzLg0KQ3JlYXRlIGEgZGF0YSBmcmFtZSBjb250YWluaW5nIHRoZSB2b2xhdGlsaXR5IGZvciBlYWNoIG9mIHRoZXNlIDcgcG9ydGZvbGlvcyBhbmQgcGxvdCB0aGVtIHRvZ2V0aGVyIGluIGEgYmFyY2hhcnQuDQo8YnI+DQo8YnI+DQo8L2Rpdj4NCg0KDQo8YnI+DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGEgcGl2b3QgdGFibGUgb2YgZGFpbHkgcmV0dXJucw0KdHN4X3JldHVybnNfd2lkZSA8LSB0c3hfcHJpY2VzX2xvbmcgJT4lDQogIHNlbGVjdChEYXRlLCBUaWNrZXIsIGRhaWx5X3JldHVybikgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBUaWNrZXIsIHZhbHVlc19mcm9tID0gZGFpbHlfcmV0dXJuKQ0KDQojIGNvdmFyaWFuY2UgbWF0cml4IGZvciB0aGUgc3RvY2tzIChleGNsdWRpbmcgdGhlIERhdGUpDQpjb3ZfbWF0cml4IDwtIGNvdih0c3hfcmV0dXJuc193aWRlWywgLTFdLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEVxdWFsbHkgd2VpZ2h0ZWQgcG9ydGZvbGlvDQplcXVhbF93ZWlnaHRzIDwtIHJlcCgxLzYwLCA2MCkNCmVxdWFsX3BvcnRmb2xpb192YXJpYW5jZSA8LSB0KGVxdWFsX3dlaWdodHMpICUqJSBjb3ZfbWF0cml4ICUqJSBlcXVhbF93ZWlnaHRzDQplcXVhbF9wb3J0Zm9saW9fc2QgPC0gc3FydChlcXVhbF9wb3J0Zm9saW9fdmFyaWFuY2UpDQoNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEV4dHJhY3QgdGhlIHdlaWdodHMgZnJvbSB0aGUgbWVtYmVycyBkYXRhDQp0c3hfd2VpZ2h0cyA8LSB0c3hfbWVtYmVycyRXZWlnaHQgLyAxMDAgDQp0c3hfcG9ydGZvbGlvX3ZhcmlhbmNlIDwtIHQodHN4X3dlaWdodHMpICUqJSBjb3ZfbWF0cml4ICUqJSB0c3hfd2VpZ2h0cw0KdHN4X3BvcnRmb2xpb19zZCA8LSBzcXJ0KHRzeF9wb3J0Zm9saW9fdmFyaWFuY2UpICANCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIHdlaWdodHMgaW52ZXJzZWx5IHByb3BvcnRpb25hbCB0byBiZXRhDQppbnZlcnNlX2JldGFfd2VpZ2h0cyA8LSAxIC8gYmV0YV9yZXN1bHRzJEJldGENCmludmVyc2VfYmV0YV93ZWlnaHRzIDwtIGludmVyc2VfYmV0YV93ZWlnaHRzIC8gc3VtKGludmVyc2VfYmV0YV93ZWlnaHRzKQ0KDQojIEludmVyc2VseSBwcm9wb3J0aW9uYWwgdG8gYmV0YSBwb3J0Zm9saW8NCmludl9iZXRhX3BvcnRmb2xpb192YXJpYW5jZSA8LSB0KGludmVyc2VfYmV0YV93ZWlnaHRzKSAlKiUgY292X21hdHJpeCAlKiUgaW52ZXJzZV9iZXRhX3dlaWdodHMNCmludl9iZXRhX3BvcnRmb2xpb19zZCA8LSBzcXJ0KGludl9iZXRhX3BvcnRmb2xpb192YXJpYW5jZSkgIA0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRmlsdGVyIGZvciBGaW5hbmNpYWxzIHNlY3Rvcg0KZmluYW5jaWFsc190aWNrZXJzIDwtIHRzeF9tZW1iZXJzICU+JQ0KICBmaWx0ZXIoR0lDUy5TZWN0b3IgPT0gIkZpbmFuY2lhbHMiKSAlPiUNCiAgcHVsbChUaWNrZXIpDQpmaW5hbmNpYWxzX3RpY2tlcnMgPC0gbmEub21pdChmaW5hbmNpYWxzX3RpY2tlcnMpDQoNCiMgU3Vic2V0IHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCBmb3IgRmluYW5jaWFscyB0aWNrZXJzDQpmaW5hbmNpYWxzX2Nvdl9tYXRyaXggPC0gY292X21hdHJpeFtmaW5hbmNpYWxzX3RpY2tlcnMsIGZpbmFuY2lhbHNfdGlja2Vyc10NCg0KIyBFcXVhbCB3ZWlnaHRzIGZvciBGaW5hbmNpYWxzIHNlY3RvciAoYWZ0ZXIgcmVtb3ZpbmcgTkEpDQpmaW5hbmNpYWxzX3dlaWdodHMgPC0gcmVwKDEvbGVuZ3RoKGZpbmFuY2lhbHNfdGlja2VycyksIGxlbmd0aChmaW5hbmNpYWxzX3RpY2tlcnMpKQ0KDQojIEZpbmFuY2lhbHMgcG9ydGZvbGlvIHZhcmlhbmNlDQpmaW5hbmNpYWxzX3BvcnRmb2xpb192YXJpYW5jZSA8LSB0KGZpbmFuY2lhbHNfd2VpZ2h0cykgJSolIGZpbmFuY2lhbHNfY292X21hdHJpeCAlKiUgZmluYW5jaWFsc193ZWlnaHRzDQpmaW5hbmNpYWxzX3BvcnRmb2xpb19zZCA8LSBzcXJ0KGZpbmFuY2lhbHNfcG9ydGZvbGlvX3ZhcmlhbmNlKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgU21hbGwgQ2FwIFBvcnRmb2xpbw0Kc21hbGxfY2FwX3RpY2tlcnMgPC0gdHN4X21lbWJlcnMgJT4lDQogIGZpbHRlcihtYXJrZXRfY2FwX2dyb3VwID09ICJTbWFsbCIpICU+JQ0KICBwdWxsKFRpY2tlcikNCg0KIyBSZW1vdmUgdGhlIGludmFsaWQgdGlja2VyIGZyb20gc21hbGxfY2FwX3RpY2tlcnMNCnNtYWxsX2NhcF90aWNrZXJzIDwtIHNtYWxsX2NhcF90aWNrZXJzW3NtYWxsX2NhcF90aWNrZXJzICVpbiUgcm93bmFtZXMoY292X21hdHJpeCldDQoNCnNtYWxsX2NhcF93ZWlnaHRzIDwtIHJlcCgxL2xlbmd0aChzbWFsbF9jYXBfdGlja2VycyksIGxlbmd0aChzbWFsbF9jYXBfdGlja2VycykpDQpzbWFsbF9jYXBfY292X21hdHJpeCA8LSBjb3ZfbWF0cml4W3NtYWxsX2NhcF90aWNrZXJzLCBzbWFsbF9jYXBfdGlja2Vyc10NCnNtYWxsX2NhcF9wb3J0Zm9saW9fdmFyaWFuY2UgPC0gdChzbWFsbF9jYXBfd2VpZ2h0cykgJSolIHNtYWxsX2NhcF9jb3ZfbWF0cml4ICUqJSBzbWFsbF9jYXBfd2VpZ2h0cw0Kc21hbGxfY2FwX3BvcnRmb2xpb19zZCA8LSBzcXJ0KHNtYWxsX2NhcF9wb3J0Zm9saW9fdmFyaWFuY2UpDQoNCiMgTWlkIENhcCBQb3J0Zm9saW8NCm1pZF9jYXBfdGlja2VycyA8LSB0c3hfbWVtYmVycyAlPiUNCiAgZmlsdGVyKG1hcmtldF9jYXBfZ3JvdXAgPT0gIk1pZCIpICU+JQ0KICBwdWxsKFRpY2tlcikNCm1pZF9jYXBfd2VpZ2h0cyA8LSByZXAoMS9sZW5ndGgobWlkX2NhcF90aWNrZXJzKSwgbGVuZ3RoKG1pZF9jYXBfdGlja2VycykpDQoNCiMgUmVtb3ZlIHRoZSBpbnZhbGlkIHRpY2tlcnMgZnJvbSBtaWRfY2FwX3RpY2tlcnMNCm1pZF9jYXBfdGlja2VycyA8LSBtaWRfY2FwX3RpY2tlcnNbbWlkX2NhcF90aWNrZXJzICVpbiUgcm93bmFtZXMoY292X21hdHJpeCldDQptaWRfY2FwX2Nvdl9tYXRyaXggPC0gY292X21hdHJpeFttaWRfY2FwX3RpY2tlcnMsIG1pZF9jYXBfdGlja2Vyc10NCm1pZF9jYXBfd2VpZ2h0cyA8LSByZXAoMSAvIGxlbmd0aChtaWRfY2FwX3RpY2tlcnMpLCBsZW5ndGgobWlkX2NhcF90aWNrZXJzKSkNCm1pZF9jYXBfcG9ydGZvbGlvX3ZhcmlhbmNlIDwtIHQobWlkX2NhcF93ZWlnaHRzKSAlKiUgbWlkX2NhcF9jb3ZfbWF0cml4ICUqJSBtaWRfY2FwX3dlaWdodHMNCm1pZF9jYXBfcG9ydGZvbGlvX3NkIDwtIHNxcnQobWlkX2NhcF9wb3J0Zm9saW9fdmFyaWFuY2UpDQoNCiMgTGFyZ2UgQ2FwIFBvcnRmb2xpbw0KbGFyZ2VfY2FwX3RpY2tlcnMgPC0gdHN4X21lbWJlcnMgJT4lDQogIGZpbHRlcihtYXJrZXRfY2FwX2dyb3VwID09ICJMYXJnZSIpICU+JQ0KICBwdWxsKFRpY2tlcikNCmxhcmdlX2NhcF93ZWlnaHRzIDwtIHJlcCgxL2xlbmd0aChsYXJnZV9jYXBfdGlja2VycyksIGxlbmd0aChsYXJnZV9jYXBfdGlja2VycykpDQpsYXJnZV9jYXBfY292X21hdHJpeCA8LSBjb3ZfbWF0cml4W2xhcmdlX2NhcF90aWNrZXJzLCBsYXJnZV9jYXBfdGlja2Vyc10NCmxhcmdlX2NhcF9wb3J0Zm9saW9fdmFyaWFuY2UgPC0gdChsYXJnZV9jYXBfd2VpZ2h0cykgJSolIGxhcmdlX2NhcF9jb3ZfbWF0cml4ICUqJSBsYXJnZV9jYXBfd2VpZ2h0cw0KbGFyZ2VfY2FwX3BvcnRmb2xpb19zZCA8LSBzcXJ0KGxhcmdlX2NhcF9wb3J0Zm9saW9fdmFyaWFuY2UpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBhIGRhdGEgZnJhbWUgd2l0aCB0aGUgdm9sYXRpbGl0aWVzDQp2b2xhdGlsaXR5X2RhdGEgPC0gZGF0YS5mcmFtZSgNCiAgUG9ydGZvbGlvID0gYygiRXF1YWxseSBXZWlnaHRlZCIsICJUU1ggV2VpZ2h0ZWQiLCAiSW52ZXJzZSBCZXRhIFdlaWdodGVkIiwgDQogICAgICAgICAgICAgICAgIkZpbmFuY2lhbHMgU2VjdG9yIiwgIlNtYWxsIENhcCIsICJNaWQgQ2FwIiwgIkxhcmdlIENhcCIpLA0KICBWb2xhdGlsaXR5ID0gYyhlcXVhbF9wb3J0Zm9saW9fc2QsIHRzeF9wb3J0Zm9saW9fc2QsIGludl9iZXRhX3BvcnRmb2xpb19zZCwgDQogICAgICAgICAgICAgICAgIGZpbmFuY2lhbHNfcG9ydGZvbGlvX3NkLCBzbWFsbF9jYXBfcG9ydGZvbGlvX3NkLCBtaWRfY2FwX3BvcnRmb2xpb19zZCwgbGFyZ2VfY2FwX3BvcnRmb2xpb19zZCkpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBnZ3Bsb3QgYmFyIGNoYXJ0DQpwIDwtIGdncGxvdCh2b2xhdGlsaXR5X2RhdGEsIGFlcyh4ID0gUG9ydGZvbGlvLCB5ID0gVm9sYXRpbGl0eSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzQ1ODRiNiIpICsNCiAgbGFicyh0aXRsZSA9ICJWb2xhdGlsaXR5IG9mIERpZmZlcmVudCBQb3J0Zm9saW9zIiwgeCA9ICJQb3J0Zm9saW8iLCB5ID0gIlZvbGF0aWxpdHkgKFN0YW5kYXJkIERldmlhdGlvbikiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKQ0KaW50ZXJhY3RpdmVfcGxvdCA8LSBnZ3Bsb3RseShwKSAlPiUNCiAgbGF5b3V0KGhvdmVybGFiZWwgPSBsaXN0KGJnY29sb3IgPSAiI2ZmZGU1NyIsIGZvbnQgPSBsaXN0KGNvbG9yID0gImJsYWNrIikpKSAgDQppbnRlcmFjdGl2ZV9wbG90DQpgYGANCg0KDQojIyBQcm9ibGVtIDUNCjxicj4NCjxkaXYgY2xhc3M9ImJveGVkIj4NCjxicj4NCjxicj4NCkluc3RhbGwgdGhlIHBhY2thZ2UgcXVhbnRtb2QgYW5kIGRvd25sb2FkIHByaWNlcyBvZiB0aGUgUyZQIDUwMCB1c2luZyB0aGUgZnVuY3Rpb24gKmdldFN5bWJvbHMoKSogKHRpY2tlcuKAnMuGR1NQQ+KAnSkuIENhbGN1bGF0ZSB0aGUgZGFpbHkgcmV0dXJucyBhbmQgY29tcGFyZSBhZ2FpbnN0IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiB1c2luZyBhICpxcW5vcm0oKSogYW5kICpxcWxpbmUoKSogcGxvdC4NCjxicj4NCjxicj4NCjwvZGl2Pg0KPGJyPg0KPGJyPg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRG93bmxvYWQgcHJpY2VzIG9mIHRoZSBTJlAgNTAwIHVzaW5nIGdldFN5bWJvbHMoKQ0KZ2V0U3ltYm9scygiXkdTUEMiLCBzcmMgPSAieWFob28iLCBmcm9tID0gIjIwMTAtMDEtMDEiLCB0byA9IFN5cy5EYXRlKCkpDQoNCiMgZGFpbHkgcmV0dXJucy0gVXNpbmcgQWRqdXN0ZWQgQ2xvc2UgcHJpY2VzIHRvIGFjY291bnQgZm9yIGRpdmlkZW5kcyBhbmQgc3RvY2sgc3BsaXRzDQpzcDUwMF9wcmljZXMgPC0gQWQoR1NQQykgIA0KZGFpbHlfcmV0dXJucyA8LSBkaWZmKGxvZyhzcDUwMF9wcmljZXMpKSAgDQpkYWlseV9yZXR1cm5zIDwtIG5hLm9taXQoZGFpbHlfcmV0dXJucykgIA0KDQojIGEgUS1RIHBsb3QgdG8gY29tcGFyZSBhZ2FpbnN0IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbg0KcXFub3JtKGRhaWx5X3JldHVybnMsIG1haW4gPSAiUS1RIFBsb3Qgb2YgRGFpbHkgUmV0dXJucyBvZiBTJlAgNTAwIikNCnFxbGluZShkYWlseV9yZXR1cm5zLCBjb2wgPSAicmVkIikgIA0KYGBgDQoNCjxicj4NCg0KPGJyPg0KDQoNCjxicj4NCg0KPHNwYW4+ICA8c3BhbiBzdHlsZT0iY29sb3I6IFN0ZWVsYmx1ZTsiPioqTWQgTWFobXVkdWwgSGFzYW4qKjwvc3Bhbj4gXA0KTVFJTSAzNzYwNTczXA0KRmFjdWx0eSBvZiBNYW5hZ2VtZW50IFwNClVuaXZlcnNpdHkgb2YgTmV3IEJydW5zd2ljayBcDQptYWhtdWR1bC5oYXNhblxAdW5iLmNhIFwNCg0KPGJyPg==