library(readr)
library(dplyr)
library(tidyr)
library(jsonlite)
library(lubridate)
library(ggplot2)
library(forecast)
library(zoo)
library(lmtest)

BTC Data

data is from CoinMarketCap

bitcoin_data <- read_delim(
  "/Users/joshuazhang/Desktop/Stats 429 Project/FinalProjectData/BTC.daily.csv",
  delim = ";", col_names = TRUE, trim_ws = TRUE, show_col_types = FALSE
)
bitcoin_data <- bitcoin_data %>%
  mutate(
    Date = as.Date(timeOpen)      # convert timestamp → Date
  ) %>%
  filter(Date >= as.Date("2025-01-01")) %>%   # keep only 2025+
  select(Date, Open = open) %>%               # keep date + open price
  arrange(Date)
plot(bitcoin_data, type = "l", col = "red",
     main = "BTC Opening Price",
     ylab = "USD")

par(mfrow = c(2, 2)) 

btc_ts <- ts(bitcoin_data$Open)
acf(btc_ts, main = "ACF of BTC Opening Price (2025)")
pacf(btc_ts, main = "PACF of BTC Opening Price (2025)")
ndiffs(btc_ts)        # differecing test; tells you how many differences needed
[1] 1
par(mfrow = c(1, 1)) 


btc_diff <- diff(btc_ts)
plot(btc_diff, type = "l", col = "red",
     main = "Differenced BTC Opening Price",
     ylab = "1st Difference")
par(mfrow = c(2, 2)) 

acf(btc_diff, main = "ACF of BTC Opening Price (2025); 1st diff")
pacf(btc_diff, main = "PACF of BTC Opening Price (2025); 1st diff")
par(mfrow = c(1, 1)) 

auto.arima(btc_ts)
Series: btc_ts 
ARIMA(0,1,0) 

sigma^2 = 4732593:  log likelihood = -3031.61
AIC=6065.22   AICc=6065.23   BIC=6069.02
forecast_data <- tail(bitcoin_data, 10)
forecast_data

ETH Data

data is from CoinMarketCap

eth_data <- read_delim(
  "/Users/joshuazhang/Desktop/Stats 429 Project/FinalProjectData/ETH_daily.csv",
  delim = ";", col_names = TRUE, trim_ws = TRUE, show_col_types = FALSE
)
eth_data <- eth_data %>%
  mutate(
    Date = as.Date(timeOpen)
  ) %>%
  filter(Date >= as.Date("2025-01-01")) %>%
  select(Date, Open = open) %>%
  arrange(Date)

plot(eth_data, type = "l", col = "red",
     main = "ETA Opening Price",
     ylab = "USD")

# ETH time series
eth_ts <- ts(eth_data$Open)

# ACF & PACF (original series)
par(mfrow = c(2, 2))

acf(eth_ts, main = "ACF of ETH Opening Price (2025)")
pacf(eth_ts, main = "PACF of ETH Opening Price (2025)")
ndiffs(eth_ts)
[1] 1
par(mfrow = c(1, 1))


#  First difference
eth_diff <- diff(eth_ts)
plot(
  eth_diff, type = "l", col = "red",
  main = "Differenced ETH Opening Price",
  ylab = "1st Difference"
)


# ACF & PACF of differenced series
par(mfrow = c(2, 2))

acf(eth_diff, main = "ACF of ETH Opening Price (2025); 1st diff")
pacf(eth_diff, main = "PACF of ETH Opening Price (2025); 1st diff")
par(mfrow = c(1, 1))


# Auto-ARIMA recommendation
auto.arima(eth_ts)
Series: eth_ts 
ARIMA(0,1,0) 

sigma^2 = 14896:  log likelihood = -2072.38
AIC=4146.75   AICc=4146.77   BIC=4150.56

S%P 500 Data

from investing.com

sp500_data <- read_delim(
  "/Users/joshuazhang/Desktop/Stats 429 Project/FinalProjectData/S&P500_daily.csv",
  delim = ",", col_names = TRUE, trim_ws = TRUE, show_col_types = FALSE
)

sp500_data <- sp500_data %>%
  mutate(
    Date = as.Date(Date, format = "%m/%d/%Y")   # convert character → Date
  ) %>%
  filter(Date >= as.Date("2025-01-01")) %>%     # keep only after 2025-01-01
  select(Date, Open) %>%                        # keep Date + Open
  arrange(Date)

sp500_ts <- ts(sp500_data$Open)

plot(sp500_data, type = "l", col = "red",
     main = "S&P500 Opening Price",
     ylab = "USD")

# 2. ACF & PACF (original series)
par(mfrow = c(2, 2))

acf(sp500_ts, main = "ACF of S&P500 Opening Price (2025)")
pacf(sp500_ts, main = "PACF of S&P500 Opening Price (2025)")
ndiffs(sp500_ts)
[1] 1
par(mfrow = c(1, 1))


# First difference
sp500_diff <- diff(sp500_ts)
plot(
  sp500_diff, type = "l", col = "red",
  main = "Differenced S&P500 Opening Price",
  ylab = "1st Difference"
)
par(mfrow = c(2, 2))

acf(sp500_diff, main = "ACF of S&P500 Opening Price (2025); 1st diff")
pacf(sp500_diff, main = "PACF of S&P500 Opening Price (2025); 1st diff")
par(mfrow = c(1, 1))


# Auto-ARIMA recommendation
auto.arima(sp500_ts)
Series: sp500_ts 
ARIMA(2,1,2) 

Coefficients:
          ar1      ar2     ma1     ma2
      -1.2117  -0.6758  1.0461  0.7085
s.e.   0.1784   0.1351  0.1616  0.1030

sigma^2 = 4453:  log likelihood = -1279.42
AIC=2568.83   AICc=2569.1   BIC=2585.98

Gold Data

from investing.com

gold_data <- read_delim(
  "/Users/joshuazhang/Desktop/Stats 429 Project/FinalProjectData/Gold_daily.csv",
  delim = ",", col_names = TRUE, trim_ws = TRUE, show_col_types = FALSE
)

gold_data <- gold_data %>%
  mutate(
    Date = as.Date(Date, format = "%m/%d/%Y")   # convert character → Date
  ) %>%
  filter(Date >= as.Date("2025-01-01")) %>%     # keep only after 2025-01-01
  select(Date, Open) %>%                        # keep Date + Open only
  arrange(Date)
gold_ts <- ts(gold_data$Open)
plot(gold_data, type = "l", col = "red",
     main = "Gold Opening Price",
     ylab = "USD")


# 2. ACF & PACF (original series)
par(mfrow = c(2, 2))

acf(gold_ts, main = "ACF of Gold Price (2025)")
pacf(gold_ts, main = "PACF of Gold Price (2025)")
ndiffs(gold_ts)
[1] 1
par(mfrow = c(1, 1))


# 3. First difference
gold_diff <- diff(gold_ts)
plot(
  gold_diff, type = "l", col = "red",
  main = "Differenced Gold Price",
  ylab = "1st Difference"
)

# ACF & PACF of differenced series
par(mfrow = c(2, 2))

acf(gold_diff, main = "ACF of Gold Price (2025); 1st diff")
pacf(gold_diff, main = "PACF of Gold Price (2025); 1st diff")
par(mfrow = c(1, 1))


# Auto-ARIMA recommendation
auto.arima(gold_ts)
Series: gold_ts 
ARIMA(0,1,0) with drift 

Coefficients:
       drift
      6.8200
s.e.  2.8546

sigma^2 = 1939:  log likelihood = -1232.85
AIC=2469.69   AICc=2469.75   BIC=2476.63

#VIX from investing.com

vix_data <- read_delim(
  "/Users/joshuazhang/Desktop/Stats 429 Project/FinalProjectData/VIX_daily.csv",
  delim = ",", col_names = TRUE, trim_ws = TRUE, show_col_types = FALSE
)

vix_data <- vix_data %>%
  mutate(
    Date = as.Date(Date, format = "%m/%d/%Y")   # convert to Date
  ) %>%
  filter(Date >= as.Date("2025-01-01")) %>%     # keep only after Jan 1st 2025
  select(Date, Open) %>%                        # keep Date + Open only
  arrange(Date)
vix_ts <- ts(vix_data$Open)
plot(vix_data, type = "l", col = "red",
     main = "VIX",
     ylab = "index")

# ACF & PACF (original series)
par(mfrow = c(2, 2))

acf(vix_ts, main = "ACF of VIX (2025)")
pacf(vix_ts, main = "PACF of VIX (2025)")
ndiffs(vix_ts)
[1] 1
par(mfrow = c(1, 1))


#  First difference
vix_diff <- diff(vix_ts)

plot(
  vix_diff, type = "l", col = "red",
  main = "Differenced VIX",
  ylab = "1st Difference"
)

# ACF & PACF of differenced VIX
par(mfrow = c(2, 2))

acf(vix_diff, main = "ACF of VIX (1st diff)")
pacf(vix_diff, main = "PACF of VIX (1st diff)")
par(mfrow = c(1, 1))



# 5. Auto-ARIMA recommendation
auto.arima(vix_ts)
Series: vix_ts 
ARIMA(2,1,2) 

Coefficients:
          ar1      ar2     ma1     ma2
      -1.3088  -0.7008  1.0897  0.7362
s.e.   0.1053   0.1005  0.1029  0.0858

sigma^2 = 7.331:  log likelihood = -568.27
AIC=1146.55   AICc=1146.81   BIC=1163.87

Regression Model

Combined Data

library(ggplot2)
library(ggplot2)
library(zoo)
library(dplyr)

# Rename columns BEFORE joining (avoids suffix issues)
btc  <- bitcoin_data %>% rename(BTC = Open)
eth  <- eth_data     %>% rename(ETH = Open)
sp   <- sp500_data   %>% rename(SP500 = Open)
gold <- gold_data    %>% rename(GOLD = Open)
vix  <- vix_data     %>% rename(VIX = Open)

# Join all datasets by Date
combined <- btc %>%
  left_join(eth,  by = "Date") %>%
  left_join(sp,   by = "Date") %>%
  left_join(gold, by = "Date") %>%
  left_join(vix,  by = "Date")

# Drop rows where SP500, GOLD, or VIX are NA (market closed)
combined <- combined %>%
  drop_na()
combined
model_data <- combined %>%
  mutate(
    rBTC  = log(BTC)  - lag(log(BTC)),
    rETH  = log(ETH)  - lag(log(ETH)),
    rSP   = log(SP500) - lag(log(SP500)),
    rGOLD = log(GOLD) - lag(log(GOLD)),
    rVIX  = log(VIX)  - lag(log(VIX))
  ) %>%
  drop_na()
model_data

# Extract vectors
date  <- model_data$Date
rBTC  <- model_data$rBTC
rETH  <- model_data$rETH
rSP   <- model_data$rSP
rGOLD <- model_data$rGOLD
rVIX  <- model_data$rVIX

# Plot
plot(
  date, rBTC, type="l", col="blue",
  main="",
  xlab="Date", ylab="Log Returns",
  ylim=range(c(rBTC, rETH, rSP, rGOLD, rVIX), na.rm=TRUE)
)
lines(date, rETH,  col="red")
lines(date, rSP,   col="darkgreen")
lines(date, rGOLD, col="orange")
lines(date, rVIX,  col="purple")
legend(
  "topright",
  legend=c("BTC", "ETH", "SP500", "GOLD", "VIX"),
  col=c("blue", "red", "darkgreen", "orange", "purple"),
  lty=1, cex=0.8
)

date  <- combined$Date
BTC   <- combined$BTC
ETH   <- combined$ETH
SP500 <- combined$SP500
GOLD  <- combined$GOLD
VIX   <- combined$VIX

plot(
  date, BTC, type="l", col="blue",
  main="Raw Prices of All Variables",
  xlab="Date", ylab="Value",
  ylim = range(c(BTC, ETH, SP500, GOLD, VIX), na.rm = TRUE)
)

lines(date, ETH,  col="red")
lines(date, SP500, col="darkgreen")
lines(date, GOLD, col="orange")
lines(date, VIX,  col="purple")

legend("topright",
       legend=c("BTC","ETH","SP500","GOLD","VIX"),
       col=c("blue","red","darkgreen","orange","purple"),
       lty=1, cex=0.8)

Full Model

m1 <- lm(rBTC ~ rETH + rSP + rGOLD + rVIX, data=model_data)
summary(m1)

Call:
lm(formula = rBTC ~ rETH + rSP + rGOLD + rVIX, data = model_data)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.071285 -0.009311  0.000348  0.010019  0.065623 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.0004208  0.0010955  -0.384   0.7012    
rETH         0.4188940  0.0267214  15.676   <2e-16 ***
rSP          0.2897472  0.1563326   1.853   0.0652 .  
rGOLD        0.1390304  0.0857231   1.622   0.1063    
rVIX         0.0040839  0.0193357   0.211   0.8329    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01623 on 222 degrees of freedom
Multiple R-squared:  0.6457,    Adjusted R-squared:  0.6393 
F-statistic: 101.1 on 4 and 222 DF,  p-value: < 2.2e-16
# Residual ACF/PACF
par(mfrow=c(2,2))
acf(residuals(m1), main="ACF of Residuals (Model 1)")
pacf(residuals(m1), main="PACF of Residuals (Model 1)")
par(mfrow=c(1,1))


# box test
box_m1 <- Box.test(residuals(m1), lag = 10, type = "Ljung-Box")
box_m1

    Box-Ljung test

data:  residuals(m1)
X-squared = 13.933, df = 10, p-value = 0.1761

Model 2: reduced model

m2 <- lm(rBTC ~ rETH + rSP, data=model_data)
summary(m2)

Call:
lm(formula = rBTC ~ rETH + rSP, data = model_data)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.071889 -0.009141  0.000111  0.010297  0.064819 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.0001262  0.0010812  -0.117   0.9072    
rETH         0.4162239  0.0264277  15.750   <2e-16 ***
rSP          0.2712468  0.0998252   2.717   0.0071 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.01625 on 224 degrees of freedom
Multiple R-squared:  0.6414,    Adjusted R-squared:  0.6382 
F-statistic: 200.3 on 2 and 224 DF,  p-value: < 2.2e-16
par(mfrow=c(2,2))
acf(residuals(m2), main="ACF of Residuals (Model 2)")
pacf(residuals(m2), main="PACF of Residuals (Model 2)")
par(mfrow=c(1,1))


# Model 2 – Reduced Model
box_m2 <- Box.test(residuals(m2), lag = 10, type = "Ljung-Box")
box_m2

    Box-Ljung test

data:  residuals(m2)
X-squared = 13.507, df = 10, p-value = 0.1967

Model 3: lag model

lags <- 1:3   # possible lags

results <- data.frame(
  Model = character(),
  ETH_lag = integer(),
  SP_lag = integer(),
  VIX_lag = integer(),
  AIC = numeric(),
  AdjR2 = numeric(),
  stringsAsFactors = FALSE
)

models <- list()

# Loop through all combinations
for (e in lags) {
  for (s in lags) {
    for (v in lags) {
      
      # Create lagged data
      temp <- model_data %>%
        mutate(
          rETH_lag = lag(rETH, e),
          rSP_lag  = lag(rSP,  s),
          rVIX_lag = lag(rVIX, v)
        ) %>%
        drop_na()
      
      # Fit model
      m <- lm(rBTC ~ rETH_lag + rSP_lag + rGOLD + rVIX_lag, data=temp)
      
      # Model name
      model_name <- paste0("ETH", e, "_SP", s, "_VIX", v)
      
      # Store model
      models[[model_name]] <- m
      
      # Save results
      results <- rbind(
        results,
        data.frame(
          Model = model_name,
          ETH_lag = e,
          SP_lag = s,
          VIX_lag = v,
          AIC = AIC(m),
          AdjR2 = summary(m)$adj.r.squared
        )
      )
      
    }
  }
}

# Sort best models (lowest AIC)
results_sorted <- results[order(results$AIC), ]
results_sorted
# Identify best model (lowest AIC)
best_name <- results_sorted$Model[1]
cat("Best model:", best_name, "\n\n")
Best model: ETH2_SP1_VIX2 
# Extract the model object
best_model <- models[[best_name]]

# Model summary
summary(best_model)

Call:
lm(formula = rBTC ~ rETH_lag + rSP_lag + rGOLD + rVIX_lag, data = temp)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.109246 -0.013153 -0.000259  0.016136  0.097002 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)   
(Intercept) -0.0004082  0.0017924  -0.228   0.8201   
rETH_lag    -0.0840910  0.0428283  -1.963   0.0509 . 
rSP_lag     -0.1135312  0.1465738  -0.775   0.4394   
rGOLD        0.0763406  0.1403397   0.544   0.5870   
rVIX_lag    -0.0671813  0.0210187  -3.196   0.0016 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.0265 on 220 degrees of freedom
Multiple R-squared:  0.05874,   Adjusted R-squared:  0.04162 
F-statistic: 3.432 on 4 and 220 DF,  p-value: 0.009571
# Best Lag Model
best_model <- models[[best_name]]
summary(best_model)

Call:
lm(formula = rBTC ~ rETH_lag + rSP_lag + rGOLD + rVIX_lag, data = temp)

Residuals:
      Min        1Q    Median        3Q       Max 
-0.109246 -0.013153 -0.000259  0.016136  0.097002 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)   
(Intercept) -0.0004082  0.0017924  -0.228   0.8201   
rETH_lag    -0.0840910  0.0428283  -1.963   0.0509 . 
rSP_lag     -0.1135312  0.1465738  -0.775   0.4394   
rGOLD        0.0763406  0.1403397   0.544   0.5870   
rVIX_lag    -0.0671813  0.0210187  -3.196   0.0016 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.0265 on 220 degrees of freedom
Multiple R-squared:  0.05874,   Adjusted R-squared:  0.04162 
F-statistic: 3.432 on 4 and 220 DF,  p-value: 0.009571
# Residual ACF/PACF for the lag model
par(mfrow=c(2,2))
acf(residuals(best_model), main=paste("ACF of Residuals (", best_name, ")"))
pacf(residuals(best_model), main=paste("PACF of Residuals (", best_name, ")"))
par(mfrow=c(1,1))



# Model 3 – Lag Model (best model)
box_m3 <- Box.test(residuals(best_model), lag = 10, type = "Ljung-Box")
box_m3

    Box-Ljung test

data:  residuals(best_model)
X-squared = 6.4267, df = 10, p-value = 0.7782
# --- AIC, BIC, R-square extractor function ---
extract_metrics <- function(model) {
  s <- summary(model)
  data.frame(
    AIC  = AIC(model),
    BIC  = BIC(model),
    R2   = s$r.squared,
    AdjR2 = s$adj.r.squared
  )
}

# --- Apply to all three models ---
metrics_m1 <- extract_metrics(m1)
metrics_m2 <- extract_metrics(m2)
metrics_m3 <- extract_metrics(best_model)

# Combine into one table
model_comparison <- rbind(
  cbind(Model = "Full Model (m1)", metrics_m1),
  cbind(Model = "Reduced Model (m2)", metrics_m2),
  cbind(Model = "Best Lag Model (m3)", metrics_m3)
)

model_comparison
NA
### ============================================================
### 1. Fit individual regressions
### ============================================================

m_eth  <- lm(rBTC ~ rETH,  data = model_data)
m_sp   <- lm(rBTC ~ rSP,   data = model_data)
m_gold <- lm(rBTC ~ rGOLD, data = model_data)
m_vix  <- lm(rBTC ~ rVIX,  data = model_data)

### Helper function to extract stats
get_stats <- function(model){
  s <- summary(model)
  coef_val <- s$coefficients[2, 1]      # slope coefficient
  p_val    <- s$coefficients[2, 4]      # p-value of predictor
  aic_val  <- AIC(model)
  adj_r2   <- s$adj.r.squared
  
  return(c(coef_val, p_val, aic_val, adj_r2))
}

### ============================================================
### 2. Build results table
### ============================================================

results_individual <- data.frame(
  Predictor = c("ETH", "SP500", "GOLD", "VIX"),
  Coefficient = c(
    get_stats(m_eth)[1],
    get_stats(m_sp)[1],
    get_stats(m_gold)[1],
    get_stats(m_vix)[1]
  ),
  P_value = c(
    get_stats(m_eth)[2],
    get_stats(m_sp)[2],
    get_stats(m_gold)[2],
    get_stats(m_vix)[2]
  ),
  AIC = c(
    get_stats(m_eth)[3],
    get_stats(m_sp)[3],
    get_stats(m_gold)[3],
    get_stats(m_vix)[3]
  ),
  Adj_R2 = c(
    get_stats(m_eth)[4],
    get_stats(m_sp)[4],
    get_stats(m_gold)[4],
    get_stats(m_vix)[4]
  )
)

print(results_individual)
NA
NA

Forecasting

### Define the best-model lags
lag_e <- 1   # rETH lag
lag_s <- 2   # rSP lag
lag_v <- 2   # rVIX lag

### Select last k days
k <- 5
compare_raw <- tail(model_data, k + max(lag_e, lag_s, lag_v))


### Recreate lag variables needed by best_model
compare_data <- compare_raw %>%
  mutate(
    rETH_lag = lag(rETH, lag_e),
    rSP_lag  = lag(rSP,  lag_s),
    rVIX_lag = lag(rVIX, lag_v)
  ) %>%
  drop_na() %>%       # remove rows where lag data not available
  tail(k)             # keep last k rows only


### Get the price BEFORE the comparison window
last_price_before_window <- tail(model_data$BTC, k+1)[1]

###  Helper function: returns → prices
predict_price <- function(model, data_window, last_price){
  pred_r <- predict(model, newdata = data_window)

  pred_price <- numeric(length(pred_r))
  pred_price[1] <- last_price * exp(pred_r[1])

  for(i in 2:length(pred_r)){
    pred_price[i] <- pred_price[i-1] * exp(pred_r[i])
  }
  return(pred_price)
}

### Predict using all 3 models

# Full model (m1)
pred_m1 <- predict_price(m1, compare_data, last_price_before_window)

# Reduced model (m2)
pred_m2 <- predict_price(m2, compare_data, last_price_before_window)

# Best lag model (m3)
pred_m3 <- predict_price(best_model, compare_data, last_price_before_window)


###  Build comparison table
comparison_table <- data.frame(
  Date = compare_data$Date,
  Actual = compare_data$BTC,
  Full_Model = pred_m1,
  Reduced_Model = pred_m2,
  Best_Lag_Model = pred_m3
)
print(comparison_table)


### Plot all three models vs actual
matplot(
  comparison_table$Date,
  comparison_table[, 2:5],
  type="l", lwd=2,
  col=c("black","red","blue","darkgreen"),
  xlab="Date", ylab="BTC Price (USD)",
  main="Actual vs Predicted BTC Price"
)

legend(
  "topleft",
  legend=c("Actual","Full Model","Reduced Model","Best Lag Model"),
  col=c("black","red","blue","darkgreen"),
  lwd=2
)



### 8. Compute RMSE + MAE
RMSE <- function(actual, predicted) sqrt(mean((actual - predicted)^2))
MAE  <- function(actual, predicted) mean(abs(actual - predicted))

error_table <- data.frame(
  Model = c("Full Model","Reduced Model","Best Lag Model"),
  RMSE = c(
    RMSE(comparison_table$Actual, comparison_table$Full_Model),
    RMSE(comparison_table$Actual, comparison_table$Reduced_Model),
    RMSE(comparison_table$Actual, comparison_table$Best_Lag_Model)
  ),
  MAE = c(
    MAE(comparison_table$Actual, comparison_table$Full_Model),
    MAE(comparison_table$Actual, comparison_table$Reduced_Model),
    MAE(comparison_table$Actual, comparison_table$Best_Lag_Model)
  )
)

print(error_table)
NA
LS0tCnRpdGxlOiAiU3RhdHMgNDI5IEZpbmFsIFByb2plY3QoY29kZSkiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGpzb25saXRlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGZvcmVjYXN0KQpsaWJyYXJ5KHpvbykKbGlicmFyeShsbXRlc3QpCmBgYAoKIyMgQlRDIERhdGEKZGF0YSBpcyBmcm9tIENvaW5NYXJrZXRDYXAKYGBge3J9CmJpdGNvaW5fZGF0YSA8LSByZWFkX2RlbGltKAogICIvVXNlcnMvam9zaHVhemhhbmcvRGVza3RvcC9TdGF0cyA0MjkgUHJvamVjdC9GaW5hbFByb2plY3REYXRhL0JUQy5kYWlseS5jc3YiLAogIGRlbGltID0gIjsiLCBjb2xfbmFtZXMgPSBUUlVFLCB0cmltX3dzID0gVFJVRSwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRQopCmJpdGNvaW5fZGF0YSA8LSBiaXRjb2luX2RhdGEgJT4lCiAgbXV0YXRlKAogICAgRGF0ZSA9IGFzLkRhdGUodGltZU9wZW4pICAgICAgIyBjb252ZXJ0IHRpbWVzdGFtcCDihpIgRGF0ZQogICkgJT4lCiAgZmlsdGVyKERhdGUgPj0gYXMuRGF0ZSgiMjAyNS0wMS0wMSIpKSAlPiUgICAjIGtlZXAgb25seSAyMDI1KwogIHNlbGVjdChEYXRlLCBPcGVuID0gb3BlbikgJT4lICAgICAgICAgICAgICAgIyBrZWVwIGRhdGUgKyBvcGVuIHByaWNlCiAgYXJyYW5nZShEYXRlKQpwbG90KGJpdGNvaW5fZGF0YSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsCiAgICAgbWFpbiA9ICJCVEMgT3BlbmluZyBQcmljZSIsCiAgICAgeWxhYiA9ICJVU0QiKQoKcGFyKG1mcm93ID0gYygyLCAyKSkgCmJ0Y190cyA8LSB0cyhiaXRjb2luX2RhdGEkT3BlbikKYWNmKGJ0Y190cywgbWFpbiA9ICJBQ0Ygb2YgQlRDIE9wZW5pbmcgUHJpY2UgKDIwMjUpIikKcGFjZihidGNfdHMsIG1haW4gPSAiUEFDRiBvZiBCVEMgT3BlbmluZyBQcmljZSAoMjAyNSkiKQpuZGlmZnMoYnRjX3RzKSAgICAgICAgIyBkaWZmZXJlY2luZyB0ZXN0OyB0ZWxscyB5b3UgaG93IG1hbnkgZGlmZmVyZW5jZXMgbmVlZGVkCnBhcihtZnJvdyA9IGMoMSwgMSkpIAoKYnRjX2RpZmYgPC0gZGlmZihidGNfdHMpCnBsb3QoYnRjX2RpZmYsIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLAogICAgIG1haW4gPSAiRGlmZmVyZW5jZWQgQlRDIE9wZW5pbmcgUHJpY2UiLAogICAgIHlsYWIgPSAiMXN0IERpZmZlcmVuY2UiKQpwYXIobWZyb3cgPSBjKDIsIDIpKSAKYWNmKGJ0Y19kaWZmLCBtYWluID0gIkFDRiBvZiBCVEMgT3BlbmluZyBQcmljZSAoMjAyNSk7IDFzdCBkaWZmIikKcGFjZihidGNfZGlmZiwgbWFpbiA9ICJQQUNGIG9mIEJUQyBPcGVuaW5nIFByaWNlICgyMDI1KTsgMXN0IGRpZmYiKQpwYXIobWZyb3cgPSBjKDEsIDEpKSAKYXV0by5hcmltYShidGNfdHMpCgoKZm9yZWNhc3RfZGF0YSA8LSB0YWlsKGJpdGNvaW5fZGF0YSwgMTApCmZvcmVjYXN0X2RhdGEKYGBgCgojIyBFVEggRGF0YQpkYXRhIGlzIGZyb20gQ29pbk1hcmtldENhcApgYGB7cn0KZXRoX2RhdGEgPC0gcmVhZF9kZWxpbSgKICAiL1VzZXJzL2pvc2h1YXpoYW5nL0Rlc2t0b3AvU3RhdHMgNDI5IFByb2plY3QvRmluYWxQcm9qZWN0RGF0YS9FVEhfZGFpbHkuY3N2IiwKICBkZWxpbSA9ICI7IiwgY29sX25hbWVzID0gVFJVRSwgdHJpbV93cyA9IFRSVUUsIHNob3dfY29sX3R5cGVzID0gRkFMU0UKKQpldGhfZGF0YSA8LSBldGhfZGF0YSAlPiUKICBtdXRhdGUoCiAgICBEYXRlID0gYXMuRGF0ZSh0aW1lT3BlbikKICApICU+JQogIGZpbHRlcihEYXRlID49IGFzLkRhdGUoIjIwMjUtMDEtMDEiKSkgJT4lCiAgc2VsZWN0KERhdGUsIE9wZW4gPSBvcGVuKSAlPiUKICBhcnJhbmdlKERhdGUpCgpwbG90KGV0aF9kYXRhLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwKICAgICBtYWluID0gIkVUQSBPcGVuaW5nIFByaWNlIiwKICAgICB5bGFiID0gIlVTRCIpCgojIEVUSCB0aW1lIHNlcmllcwpldGhfdHMgPC0gdHMoZXRoX2RhdGEkT3BlbikKCiMgQUNGICYgUEFDRiAob3JpZ2luYWwgc2VyaWVzKQpwYXIobWZyb3cgPSBjKDIsIDIpKQphY2YoZXRoX3RzLCBtYWluID0gIkFDRiBvZiBFVEggT3BlbmluZyBQcmljZSAoMjAyNSkiKQpwYWNmKGV0aF90cywgbWFpbiA9ICJQQUNGIG9mIEVUSCBPcGVuaW5nIFByaWNlICgyMDI1KSIpCm5kaWZmcyhldGhfdHMpCnBhcihtZnJvdyA9IGMoMSwgMSkpCgojICBGaXJzdCBkaWZmZXJlbmNlCmV0aF9kaWZmIDwtIGRpZmYoZXRoX3RzKQpwbG90KAogIGV0aF9kaWZmLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwKICBtYWluID0gIkRpZmZlcmVuY2VkIEVUSCBPcGVuaW5nIFByaWNlIiwKICB5bGFiID0gIjFzdCBEaWZmZXJlbmNlIgopCgoKIyBBQ0YgJiBQQUNGIG9mIGRpZmZlcmVuY2VkIHNlcmllcwpwYXIobWZyb3cgPSBjKDIsIDIpKQphY2YoZXRoX2RpZmYsIG1haW4gPSAiQUNGIG9mIEVUSCBPcGVuaW5nIFByaWNlICgyMDI1KTsgMXN0IGRpZmYiKQpwYWNmKGV0aF9kaWZmLCBtYWluID0gIlBBQ0Ygb2YgRVRIIE9wZW5pbmcgUHJpY2UgKDIwMjUpOyAxc3QgZGlmZiIpCnBhcihtZnJvdyA9IGMoMSwgMSkpCgojIEF1dG8tQVJJTUEgcmVjb21tZW5kYXRpb24KYXV0by5hcmltYShldGhfdHMpCgpgYGAKCiMjIFMlUCA1MDAgRGF0YSAKZnJvbSBpbnZlc3RpbmcuY29tCmBgYHtyfQpzcDUwMF9kYXRhIDwtIHJlYWRfZGVsaW0oCiAgIi9Vc2Vycy9qb3NodWF6aGFuZy9EZXNrdG9wL1N0YXRzIDQyOSBQcm9qZWN0L0ZpbmFsUHJvamVjdERhdGEvUyZQNTAwX2RhaWx5LmNzdiIsCiAgZGVsaW0gPSAiLCIsIGNvbF9uYW1lcyA9IFRSVUUsIHRyaW1fd3MgPSBUUlVFLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFCikKCnNwNTAwX2RhdGEgPC0gc3A1MDBfZGF0YSAlPiUKICBtdXRhdGUoCiAgICBEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkiKSAgICMgY29udmVydCBjaGFyYWN0ZXIg4oaSIERhdGUKICApICU+JQogIGZpbHRlcihEYXRlID49IGFzLkRhdGUoIjIwMjUtMDEtMDEiKSkgJT4lICAgICAjIGtlZXAgb25seSBhZnRlciAyMDI1LTAxLTAxCiAgc2VsZWN0KERhdGUsIE9wZW4pICU+JSAgICAgICAgICAgICAgICAgICAgICAgICMga2VlcCBEYXRlICsgT3BlbgogIGFycmFuZ2UoRGF0ZSkKCnNwNTAwX3RzIDwtIHRzKHNwNTAwX2RhdGEkT3BlbikKCnBsb3Qoc3A1MDBfZGF0YSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsCiAgICAgbWFpbiA9ICJTJlA1MDAgT3BlbmluZyBQcmljZSIsCiAgICAgeWxhYiA9ICJVU0QiKQoKIyAyLiBBQ0YgJiBQQUNGIChvcmlnaW5hbCBzZXJpZXMpCnBhcihtZnJvdyA9IGMoMiwgMikpCmFjZihzcDUwMF90cywgbWFpbiA9ICJBQ0Ygb2YgUyZQNTAwIE9wZW5pbmcgUHJpY2UgKDIwMjUpIikKcGFjZihzcDUwMF90cywgbWFpbiA9ICJQQUNGIG9mIFMmUDUwMCBPcGVuaW5nIFByaWNlICgyMDI1KSIpCm5kaWZmcyhzcDUwMF90cykKcGFyKG1mcm93ID0gYygxLCAxKSkKCiMgRmlyc3QgZGlmZmVyZW5jZQpzcDUwMF9kaWZmIDwtIGRpZmYoc3A1MDBfdHMpCnBsb3QoCiAgc3A1MDBfZGlmZiwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsCiAgbWFpbiA9ICJEaWZmZXJlbmNlZCBTJlA1MDAgT3BlbmluZyBQcmljZSIsCiAgeWxhYiA9ICIxc3QgRGlmZmVyZW5jZSIKKQpwYXIobWZyb3cgPSBjKDIsIDIpKQphY2Yoc3A1MDBfZGlmZiwgbWFpbiA9ICJBQ0Ygb2YgUyZQNTAwIE9wZW5pbmcgUHJpY2UgKDIwMjUpOyAxc3QgZGlmZiIpCnBhY2Yoc3A1MDBfZGlmZiwgbWFpbiA9ICJQQUNGIG9mIFMmUDUwMCBPcGVuaW5nIFByaWNlICgyMDI1KTsgMXN0IGRpZmYiKQpwYXIobWZyb3cgPSBjKDEsIDEpKQoKIyBBdXRvLUFSSU1BIHJlY29tbWVuZGF0aW9uCmF1dG8uYXJpbWEoc3A1MDBfdHMpCmBgYAoKIyMgR29sZCBEYXRhIApmcm9tIGludmVzdGluZy5jb20KYGBge3J9CmdvbGRfZGF0YSA8LSByZWFkX2RlbGltKAogICIvVXNlcnMvam9zaHVhemhhbmcvRGVza3RvcC9TdGF0cyA0MjkgUHJvamVjdC9GaW5hbFByb2plY3REYXRhL0dvbGRfZGFpbHkuY3N2IiwKICBkZWxpbSA9ICIsIiwgY29sX25hbWVzID0gVFJVRSwgdHJpbV93cyA9IFRSVUUsIHNob3dfY29sX3R5cGVzID0gRkFMU0UKKQoKZ29sZF9kYXRhIDwtIGdvbGRfZGF0YSAlPiUKICBtdXRhdGUoCiAgICBEYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAiJW0vJWQvJVkiKSAgICMgY29udmVydCBjaGFyYWN0ZXIg4oaSIERhdGUKICApICU+JQogIGZpbHRlcihEYXRlID49IGFzLkRhdGUoIjIwMjUtMDEtMDEiKSkgJT4lICAgICAjIGtlZXAgb25seSBhZnRlciAyMDI1LTAxLTAxCiAgc2VsZWN0KERhdGUsIE9wZW4pICU+JSAgICAgICAgICAgICAgICAgICAgICAgICMga2VlcCBEYXRlICsgT3BlbiBvbmx5CiAgYXJyYW5nZShEYXRlKQpnb2xkX3RzIDwtIHRzKGdvbGRfZGF0YSRPcGVuKQpwbG90KGdvbGRfZGF0YSwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsCiAgICAgbWFpbiA9ICJHb2xkIE9wZW5pbmcgUHJpY2UiLAogICAgIHlsYWIgPSAiVVNEIikKCgojIDIuIEFDRiAmIFBBQ0YgKG9yaWdpbmFsIHNlcmllcykKcGFyKG1mcm93ID0gYygyLCAyKSkKYWNmKGdvbGRfdHMsIG1haW4gPSAiQUNGIG9mIEdvbGQgUHJpY2UgKDIwMjUpIikKcGFjZihnb2xkX3RzLCBtYWluID0gIlBBQ0Ygb2YgR29sZCBQcmljZSAoMjAyNSkiKQpuZGlmZnMoZ29sZF90cykKcGFyKG1mcm93ID0gYygxLCAxKSkKCiMgMy4gRmlyc3QgZGlmZmVyZW5jZQpnb2xkX2RpZmYgPC0gZGlmZihnb2xkX3RzKQpwbG90KAogIGdvbGRfZGlmZiwgdHlwZSA9ICJsIiwgY29sID0gInJlZCIsCiAgbWFpbiA9ICJEaWZmZXJlbmNlZCBHb2xkIFByaWNlIiwKICB5bGFiID0gIjFzdCBEaWZmZXJlbmNlIgopCgojIEFDRiAmIFBBQ0Ygb2YgZGlmZmVyZW5jZWQgc2VyaWVzCnBhcihtZnJvdyA9IGMoMiwgMikpCmFjZihnb2xkX2RpZmYsIG1haW4gPSAiQUNGIG9mIEdvbGQgUHJpY2UgKDIwMjUpOyAxc3QgZGlmZiIpCnBhY2YoZ29sZF9kaWZmLCBtYWluID0gIlBBQ0Ygb2YgR29sZCBQcmljZSAoMjAyNSk7IDFzdCBkaWZmIikKcGFyKG1mcm93ID0gYygxLCAxKSkKCiMgQXV0by1BUklNQSByZWNvbW1lbmRhdGlvbgphdXRvLmFyaW1hKGdvbGRfdHMpCgpgYGAKCiNWSVggCmZyb20gaW52ZXN0aW5nLmNvbQpgYGB7cn0Kdml4X2RhdGEgPC0gcmVhZF9kZWxpbSgKICAiL1VzZXJzL2pvc2h1YXpoYW5nL0Rlc2t0b3AvU3RhdHMgNDI5IFByb2plY3QvRmluYWxQcm9qZWN0RGF0YS9WSVhfZGFpbHkuY3N2IiwKICBkZWxpbSA9ICIsIiwgY29sX25hbWVzID0gVFJVRSwgdHJpbV93cyA9IFRSVUUsIHNob3dfY29sX3R5cGVzID0gRkFMU0UKKQoKdml4X2RhdGEgPC0gdml4X2RhdGEgJT4lCiAgbXV0YXRlKAogICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIikgICAjIGNvbnZlcnQgdG8gRGF0ZQogICkgJT4lCiAgZmlsdGVyKERhdGUgPj0gYXMuRGF0ZSgiMjAyNS0wMS0wMSIpKSAlPiUgICAgICMga2VlcCBvbmx5IGFmdGVyIEphbiAxc3QgMjAyNQogIHNlbGVjdChEYXRlLCBPcGVuKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAjIGtlZXAgRGF0ZSArIE9wZW4gb25seQogIGFycmFuZ2UoRGF0ZSkKdml4X3RzIDwtIHRzKHZpeF9kYXRhJE9wZW4pCnBsb3Qodml4X2RhdGEsIHR5cGUgPSAibCIsIGNvbCA9ICJyZWQiLAogICAgIG1haW4gPSAiVklYIiwKICAgICB5bGFiID0gImluZGV4IikKCiMgQUNGICYgUEFDRiAob3JpZ2luYWwgc2VyaWVzKQpwYXIobWZyb3cgPSBjKDIsIDIpKQphY2Yodml4X3RzLCBtYWluID0gIkFDRiBvZiBWSVggKDIwMjUpIikKcGFjZih2aXhfdHMsIG1haW4gPSAiUEFDRiBvZiBWSVggKDIwMjUpIikKbmRpZmZzKHZpeF90cykKcGFyKG1mcm93ID0gYygxLCAxKSkKCiMgIEZpcnN0IGRpZmZlcmVuY2UKdml4X2RpZmYgPC0gZGlmZih2aXhfdHMpCgpwbG90KAogIHZpeF9kaWZmLCB0eXBlID0gImwiLCBjb2wgPSAicmVkIiwKICBtYWluID0gIkRpZmZlcmVuY2VkIFZJWCIsCiAgeWxhYiA9ICIxc3QgRGlmZmVyZW5jZSIKKQoKIyBBQ0YgJiBQQUNGIG9mIGRpZmZlcmVuY2VkIFZJWApwYXIobWZyb3cgPSBjKDIsIDIpKQphY2Yodml4X2RpZmYsIG1haW4gPSAiQUNGIG9mIFZJWCAoMXN0IGRpZmYpIikKcGFjZih2aXhfZGlmZiwgbWFpbiA9ICJQQUNGIG9mIFZJWCAoMXN0IGRpZmYpIikKcGFyKG1mcm93ID0gYygxLCAxKSkKCgojIDUuIEF1dG8tQVJJTUEgcmVjb21tZW5kYXRpb24KYXV0by5hcmltYSh2aXhfdHMpCgpgYGAKCgojIyBSZWdyZXNzaW9uIE1vZGVsCgojIENvbWJpbmVkIERhdGEgCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh6b28pCmxpYnJhcnkoZHBseXIpCgojIFJlbmFtZSBjb2x1bW5zIEJFRk9SRSBqb2luaW5nIChhdm9pZHMgc3VmZml4IGlzc3VlcykKYnRjICA8LSBiaXRjb2luX2RhdGEgJT4lIHJlbmFtZShCVEMgPSBPcGVuKQpldGggIDwtIGV0aF9kYXRhICAgICAlPiUgcmVuYW1lKEVUSCA9IE9wZW4pCnNwICAgPC0gc3A1MDBfZGF0YSAgICU+JSByZW5hbWUoU1A1MDAgPSBPcGVuKQpnb2xkIDwtIGdvbGRfZGF0YSAgICAlPiUgcmVuYW1lKEdPTEQgPSBPcGVuKQp2aXggIDwtIHZpeF9kYXRhICAgICAlPiUgcmVuYW1lKFZJWCA9IE9wZW4pCgojIEpvaW4gYWxsIGRhdGFzZXRzIGJ5IERhdGUKY29tYmluZWQgPC0gYnRjICU+JQogIGxlZnRfam9pbihldGgsICBieSA9ICJEYXRlIikgJT4lCiAgbGVmdF9qb2luKHNwLCAgIGJ5ID0gIkRhdGUiKSAlPiUKICBsZWZ0X2pvaW4oZ29sZCwgYnkgPSAiRGF0ZSIpICU+JQogIGxlZnRfam9pbih2aXgsICBieSA9ICJEYXRlIikKCiMgRHJvcCByb3dzIHdoZXJlIFNQNTAwLCBHT0xELCBvciBWSVggYXJlIE5BIChtYXJrZXQgY2xvc2VkKQpjb21iaW5lZCA8LSBjb21iaW5lZCAlPiUKICBkcm9wX25hKCkKY29tYmluZWQKYGBgCgpgYGB7cn0KbW9kZWxfZGF0YSA8LSBjb21iaW5lZCAlPiUKICBtdXRhdGUoCiAgICByQlRDICA9IGxvZyhCVEMpICAtIGxhZyhsb2coQlRDKSksCiAgICByRVRIICA9IGxvZyhFVEgpICAtIGxhZyhsb2coRVRIKSksCiAgICByU1AgICA9IGxvZyhTUDUwMCkgLSBsYWcobG9nKFNQNTAwKSksCiAgICByR09MRCA9IGxvZyhHT0xEKSAtIGxhZyhsb2coR09MRCkpLAogICAgclZJWCAgPSBsb2coVklYKSAgLSBsYWcobG9nKFZJWCkpCiAgKSAlPiUKICBkcm9wX25hKCkKbW9kZWxfZGF0YQoKIyBFeHRyYWN0IHZlY3RvcnMKZGF0ZSAgPC0gbW9kZWxfZGF0YSREYXRlCnJCVEMgIDwtIG1vZGVsX2RhdGEkckJUQwpyRVRIICA8LSBtb2RlbF9kYXRhJHJFVEgKclNQICAgPC0gbW9kZWxfZGF0YSRyU1AKckdPTEQgPC0gbW9kZWxfZGF0YSRyR09MRApyVklYICA8LSBtb2RlbF9kYXRhJHJWSVgKCiMgUGxvdApwbG90KAogIGRhdGUsIHJCVEMsIHR5cGU9ImwiLCBjb2w9ImJsdWUiLAogIG1haW49IiIsCiAgeGxhYj0iRGF0ZSIsIHlsYWI9IkxvZyBSZXR1cm5zIiwKICB5bGltPXJhbmdlKGMockJUQywgckVUSCwgclNQLCByR09MRCwgclZJWCksIG5hLnJtPVRSVUUpCikKbGluZXMoZGF0ZSwgckVUSCwgIGNvbD0icmVkIikKbGluZXMoZGF0ZSwgclNQLCAgIGNvbD0iZGFya2dyZWVuIikKbGluZXMoZGF0ZSwgckdPTEQsIGNvbD0ib3JhbmdlIikKbGluZXMoZGF0ZSwgclZJWCwgIGNvbD0icHVycGxlIikKbGVnZW5kKAogICJ0b3ByaWdodCIsCiAgbGVnZW5kPWMoIkJUQyIsICJFVEgiLCAiU1A1MDAiLCAiR09MRCIsICJWSVgiKSwKICBjb2w9YygiYmx1ZSIsICJyZWQiLCAiZGFya2dyZWVuIiwgIm9yYW5nZSIsICJwdXJwbGUiKSwKICBsdHk9MSwgY2V4PTAuOAopCgpgYGAKYGBge3J9CmRhdGUgIDwtIGNvbWJpbmVkJERhdGUKQlRDICAgPC0gY29tYmluZWQkQlRDCkVUSCAgIDwtIGNvbWJpbmVkJEVUSApTUDUwMCA8LSBjb21iaW5lZCRTUDUwMApHT0xEICA8LSBjb21iaW5lZCRHT0xEClZJWCAgIDwtIGNvbWJpbmVkJFZJWAoKcGxvdCgKICBkYXRlLCBCVEMsIHR5cGU9ImwiLCBjb2w9ImJsdWUiLAogIG1haW49IlJhdyBQcmljZXMgb2YgQWxsIFZhcmlhYmxlcyIsCiAgeGxhYj0iRGF0ZSIsIHlsYWI9IlZhbHVlIiwKICB5bGltID0gcmFuZ2UoYyhCVEMsIEVUSCwgU1A1MDAsIEdPTEQsIFZJWCksIG5hLnJtID0gVFJVRSkKKQoKbGluZXMoZGF0ZSwgRVRILCAgY29sPSJyZWQiKQpsaW5lcyhkYXRlLCBTUDUwMCwgY29sPSJkYXJrZ3JlZW4iKQpsaW5lcyhkYXRlLCBHT0xELCBjb2w9Im9yYW5nZSIpCmxpbmVzKGRhdGUsIFZJWCwgIGNvbD0icHVycGxlIikKCmxlZ2VuZCgidG9wcmlnaHQiLAogICAgICAgbGVnZW5kPWMoIkJUQyIsIkVUSCIsIlNQNTAwIiwiR09MRCIsIlZJWCIpLAogICAgICAgY29sPWMoImJsdWUiLCJyZWQiLCJkYXJrZ3JlZW4iLCJvcmFuZ2UiLCJwdXJwbGUiKSwKICAgICAgIGx0eT0xLCBjZXg9MC44KQoKYGBgCgoKIyMgRnVsbCBNb2RlbApgYGB7cn0KbTEgPC0gbG0ockJUQyB+IHJFVEggKyByU1AgKyByR09MRCArIHJWSVgsIGRhdGE9bW9kZWxfZGF0YSkKc3VtbWFyeShtMSkKIyBSZXNpZHVhbCBBQ0YvUEFDRgpwYXIobWZyb3c9YygyLDIpKQphY2YocmVzaWR1YWxzKG0xKSwgbWFpbj0iQUNGIG9mIFJlc2lkdWFscyAoTW9kZWwgMSkiKQpwYWNmKHJlc2lkdWFscyhtMSksIG1haW49IlBBQ0Ygb2YgUmVzaWR1YWxzIChNb2RlbCAxKSIpCnBhcihtZnJvdz1jKDEsMSkpCgojIGJveCB0ZXN0CmJveF9tMSA8LSBCb3gudGVzdChyZXNpZHVhbHMobTEpLCBsYWcgPSAxMCwgdHlwZSA9ICJManVuZy1Cb3giKQpib3hfbTEKYGBgCgojIyBNb2RlbCAyOiByZWR1Y2VkIG1vZGVsCmBgYHtyfQptMiA8LSBsbShyQlRDIH4gckVUSCArIHJTUCwgZGF0YT1tb2RlbF9kYXRhKQpzdW1tYXJ5KG0yKQpwYXIobWZyb3c9YygyLDIpKQphY2YocmVzaWR1YWxzKG0yKSwgbWFpbj0iQUNGIG9mIFJlc2lkdWFscyAoTW9kZWwgMikiKQpwYWNmKHJlc2lkdWFscyhtMiksIG1haW49IlBBQ0Ygb2YgUmVzaWR1YWxzIChNb2RlbCAyKSIpCnBhcihtZnJvdz1jKDEsMSkpCgojIE1vZGVsIDIg4oCTIFJlZHVjZWQgTW9kZWwKYm94X20yIDwtIEJveC50ZXN0KHJlc2lkdWFscyhtMiksIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nLUJveCIpCmJveF9tMgpgYGAKCiMjIE1vZGVsIDM6IGxhZyBtb2RlbApgYGB7cn0KbGFncyA8LSAxOjMgICAjIHBvc3NpYmxlIGxhZ3MKCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgKICBNb2RlbCA9IGNoYXJhY3RlcigpLAogIEVUSF9sYWcgPSBpbnRlZ2VyKCksCiAgU1BfbGFnID0gaW50ZWdlcigpLAogIFZJWF9sYWcgPSBpbnRlZ2VyKCksCiAgQUlDID0gbnVtZXJpYygpLAogIEFkalIyID0gbnVtZXJpYygpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQopCgptb2RlbHMgPC0gbGlzdCgpCgojIExvb3AgdGhyb3VnaCBhbGwgY29tYmluYXRpb25zCmZvciAoZSBpbiBsYWdzKSB7CiAgZm9yIChzIGluIGxhZ3MpIHsKICAgIGZvciAodiBpbiBsYWdzKSB7CiAgICAgIAogICAgICAjIENyZWF0ZSBsYWdnZWQgZGF0YQogICAgICB0ZW1wIDwtIG1vZGVsX2RhdGEgJT4lCiAgICAgICAgbXV0YXRlKAogICAgICAgICAgckVUSF9sYWcgPSBsYWcockVUSCwgZSksCiAgICAgICAgICByU1BfbGFnICA9IGxhZyhyU1AsICBzKSwKICAgICAgICAgIHJWSVhfbGFnID0gbGFnKHJWSVgsIHYpCiAgICAgICAgKSAlPiUKICAgICAgICBkcm9wX25hKCkKICAgICAgCiAgICAgICMgRml0IG1vZGVsCiAgICAgIG0gPC0gbG0ockJUQyB+IHJFVEhfbGFnICsgclNQX2xhZyArIHJHT0xEICsgclZJWF9sYWcsIGRhdGE9dGVtcCkKICAgICAgCiAgICAgICMgTW9kZWwgbmFtZQogICAgICBtb2RlbF9uYW1lIDwtIHBhc3RlMCgiRVRIIiwgZSwgIl9TUCIsIHMsICJfVklYIiwgdikKICAgICAgCiAgICAgICMgU3RvcmUgbW9kZWwKICAgICAgbW9kZWxzW1ttb2RlbF9uYW1lXV0gPC0gbQogICAgICAKICAgICAgIyBTYXZlIHJlc3VsdHMKICAgICAgcmVzdWx0cyA8LSByYmluZCgKICAgICAgICByZXN1bHRzLAogICAgICAgIGRhdGEuZnJhbWUoCiAgICAgICAgICBNb2RlbCA9IG1vZGVsX25hbWUsCiAgICAgICAgICBFVEhfbGFnID0gZSwKICAgICAgICAgIFNQX2xhZyA9IHMsCiAgICAgICAgICBWSVhfbGFnID0gdiwKICAgICAgICAgIEFJQyA9IEFJQyhtKSwKICAgICAgICAgIEFkalIyID0gc3VtbWFyeShtKSRhZGouci5zcXVhcmVkCiAgICAgICAgKQogICAgICApCiAgICAgIAogICAgfQogIH0KfQoKIyBTb3J0IGJlc3QgbW9kZWxzIChsb3dlc3QgQUlDKQpyZXN1bHRzX3NvcnRlZCA8LSByZXN1bHRzW29yZGVyKHJlc3VsdHMkQUlDKSwgXQpyZXN1bHRzX3NvcnRlZAojIElkZW50aWZ5IGJlc3QgbW9kZWwgKGxvd2VzdCBBSUMpCmJlc3RfbmFtZSA8LSByZXN1bHRzX3NvcnRlZCRNb2RlbFsxXQpjYXQoIkJlc3QgbW9kZWw6IiwgYmVzdF9uYW1lLCAiXG5cbiIpCgojIEV4dHJhY3QgdGhlIG1vZGVsIG9iamVjdApiZXN0X21vZGVsIDwtIG1vZGVsc1tbYmVzdF9uYW1lXV0KCiMgTW9kZWwgc3VtbWFyeQpzdW1tYXJ5KGJlc3RfbW9kZWwpCgojIEJlc3QgTGFnIE1vZGVsCmJlc3RfbW9kZWwgPC0gbW9kZWxzW1tiZXN0X25hbWVdXQpzdW1tYXJ5KGJlc3RfbW9kZWwpCgojIFJlc2lkdWFsIEFDRi9QQUNGIGZvciB0aGUgbGFnIG1vZGVsCnBhcihtZnJvdz1jKDIsMikpCmFjZihyZXNpZHVhbHMoYmVzdF9tb2RlbCksIG1haW49cGFzdGUoIkFDRiBvZiBSZXNpZHVhbHMgKCIsIGJlc3RfbmFtZSwgIikiKSkKcGFjZihyZXNpZHVhbHMoYmVzdF9tb2RlbCksIG1haW49cGFzdGUoIlBBQ0Ygb2YgUmVzaWR1YWxzICgiLCBiZXN0X25hbWUsICIpIikpCnBhcihtZnJvdz1jKDEsMSkpCgoKIyBNb2RlbCAzIOKAkyBMYWcgTW9kZWwgKGJlc3QgbW9kZWwpCmJveF9tMyA8LSBCb3gudGVzdChyZXNpZHVhbHMoYmVzdF9tb2RlbCksIGxhZyA9IDEwLCB0eXBlID0gIkxqdW5nLUJveCIpCmJveF9tMwoKYGBgCgoKYGBge3J9CiMgLS0tIEFJQywgQklDLCBSLXNxdWFyZSBleHRyYWN0b3IgZnVuY3Rpb24gLS0tCmV4dHJhY3RfbWV0cmljcyA8LSBmdW5jdGlvbihtb2RlbCkgewogIHMgPC0gc3VtbWFyeShtb2RlbCkKICBkYXRhLmZyYW1lKAogICAgQUlDICA9IEFJQyhtb2RlbCksCiAgICBCSUMgID0gQklDKG1vZGVsKSwKICAgIFIyICAgPSBzJHIuc3F1YXJlZCwKICAgIEFkalIyID0gcyRhZGouci5zcXVhcmVkCiAgKQp9CgojIC0tLSBBcHBseSB0byBhbGwgdGhyZWUgbW9kZWxzIC0tLQptZXRyaWNzX20xIDwtIGV4dHJhY3RfbWV0cmljcyhtMSkKbWV0cmljc19tMiA8LSBleHRyYWN0X21ldHJpY3MobTIpCm1ldHJpY3NfbTMgPC0gZXh0cmFjdF9tZXRyaWNzKGJlc3RfbW9kZWwpCgojIENvbWJpbmUgaW50byBvbmUgdGFibGUKbW9kZWxfY29tcGFyaXNvbiA8LSByYmluZCgKICBjYmluZChNb2RlbCA9ICJGdWxsIE1vZGVsIChtMSkiLCBtZXRyaWNzX20xKSwKICBjYmluZChNb2RlbCA9ICJSZWR1Y2VkIE1vZGVsIChtMikiLCBtZXRyaWNzX20yKSwKICBjYmluZChNb2RlbCA9ICJCZXN0IExhZyBNb2RlbCAobTMpIiwgbWV0cmljc19tMykKKQoKbW9kZWxfY29tcGFyaXNvbgoKYGBgCgoKYGBge3J9CiMjIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyMjIDEuIEZpdCBpbmRpdmlkdWFsIHJlZ3Jlc3Npb25zCiMjIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCm1fZXRoICA8LSBsbShyQlRDIH4gckVUSCwgIGRhdGEgPSBtb2RlbF9kYXRhKQptX3NwICAgPC0gbG0ockJUQyB+IHJTUCwgICBkYXRhID0gbW9kZWxfZGF0YSkKbV9nb2xkIDwtIGxtKHJCVEMgfiByR09MRCwgZGF0YSA9IG1vZGVsX2RhdGEpCm1fdml4ICA8LSBsbShyQlRDIH4gclZJWCwgIGRhdGEgPSBtb2RlbF9kYXRhKQoKIyMjIEhlbHBlciBmdW5jdGlvbiB0byBleHRyYWN0IHN0YXRzCmdldF9zdGF0cyA8LSBmdW5jdGlvbihtb2RlbCl7CiAgcyA8LSBzdW1tYXJ5KG1vZGVsKQogIGNvZWZfdmFsIDwtIHMkY29lZmZpY2llbnRzWzIsIDFdICAgICAgIyBzbG9wZSBjb2VmZmljaWVudAogIHBfdmFsICAgIDwtIHMkY29lZmZpY2llbnRzWzIsIDRdICAgICAgIyBwLXZhbHVlIG9mIHByZWRpY3RvcgogIGFpY192YWwgIDwtIEFJQyhtb2RlbCkKICBhZGpfcjIgICA8LSBzJGFkai5yLnNxdWFyZWQKICAKICByZXR1cm4oYyhjb2VmX3ZhbCwgcF92YWwsIGFpY192YWwsIGFkal9yMikpCn0KCiMjIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyMjIDIuIEJ1aWxkIHJlc3VsdHMgdGFibGUKIyMjID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKcmVzdWx0c19pbmRpdmlkdWFsIDwtIGRhdGEuZnJhbWUoCiAgUHJlZGljdG9yID0gYygiRVRIIiwgIlNQNTAwIiwgIkdPTEQiLCAiVklYIiksCiAgQ29lZmZpY2llbnQgPSBjKAogICAgZ2V0X3N0YXRzKG1fZXRoKVsxXSwKICAgIGdldF9zdGF0cyhtX3NwKVsxXSwKICAgIGdldF9zdGF0cyhtX2dvbGQpWzFdLAogICAgZ2V0X3N0YXRzKG1fdml4KVsxXQogICksCiAgUF92YWx1ZSA9IGMoCiAgICBnZXRfc3RhdHMobV9ldGgpWzJdLAogICAgZ2V0X3N0YXRzKG1fc3ApWzJdLAogICAgZ2V0X3N0YXRzKG1fZ29sZClbMl0sCiAgICBnZXRfc3RhdHMobV92aXgpWzJdCiAgKSwKICBBSUMgPSBjKAogICAgZ2V0X3N0YXRzKG1fZXRoKVszXSwKICAgIGdldF9zdGF0cyhtX3NwKVszXSwKICAgIGdldF9zdGF0cyhtX2dvbGQpWzNdLAogICAgZ2V0X3N0YXRzKG1fdml4KVszXQogICksCiAgQWRqX1IyID0gYygKICAgIGdldF9zdGF0cyhtX2V0aClbNF0sCiAgICBnZXRfc3RhdHMobV9zcClbNF0sCiAgICBnZXRfc3RhdHMobV9nb2xkKVs0XSwKICAgIGdldF9zdGF0cyhtX3ZpeClbNF0KICApCikKCnByaW50KHJlc3VsdHNfaW5kaXZpZHVhbCkKCgpgYGAKCiMjIEZvcmVjYXN0aW5nCmBgYHtyfQojIyMgRGVmaW5lIHRoZSBiZXN0LW1vZGVsIGxhZ3MKbGFnX2UgPC0gMSAgICMgckVUSCBsYWcKbGFnX3MgPC0gMiAgICMgclNQIGxhZwpsYWdfdiA8LSAyICAgIyByVklYIGxhZwoKIyMjIFNlbGVjdCBsYXN0IGsgZGF5cwprIDwtIDUKY29tcGFyZV9yYXcgPC0gdGFpbChtb2RlbF9kYXRhLCBrICsgbWF4KGxhZ19lLCBsYWdfcywgbGFnX3YpKQoKCiMjIyBSZWNyZWF0ZSBsYWcgdmFyaWFibGVzIG5lZWRlZCBieSBiZXN0X21vZGVsCmNvbXBhcmVfZGF0YSA8LSBjb21wYXJlX3JhdyAlPiUKICBtdXRhdGUoCiAgICByRVRIX2xhZyA9IGxhZyhyRVRILCBsYWdfZSksCiAgICByU1BfbGFnICA9IGxhZyhyU1AsICBsYWdfcyksCiAgICByVklYX2xhZyA9IGxhZyhyVklYLCBsYWdfdikKICApICU+JQogIGRyb3BfbmEoKSAlPiUgICAgICAgIyByZW1vdmUgcm93cyB3aGVyZSBsYWcgZGF0YSBub3QgYXZhaWxhYmxlCiAgdGFpbChrKSAgICAgICAgICAgICAjIGtlZXAgbGFzdCBrIHJvd3Mgb25seQoKCiMjIyBHZXQgdGhlIHByaWNlIEJFRk9SRSB0aGUgY29tcGFyaXNvbiB3aW5kb3cKbGFzdF9wcmljZV9iZWZvcmVfd2luZG93IDwtIHRhaWwobW9kZWxfZGF0YSRCVEMsIGsrMSlbMV0KCiMjIyAgSGVscGVyIGZ1bmN0aW9uOiByZXR1cm5zIOKGkiBwcmljZXMKcHJlZGljdF9wcmljZSA8LSBmdW5jdGlvbihtb2RlbCwgZGF0YV93aW5kb3csIGxhc3RfcHJpY2UpewogIHByZWRfciA8LSBwcmVkaWN0KG1vZGVsLCBuZXdkYXRhID0gZGF0YV93aW5kb3cpCgogIHByZWRfcHJpY2UgPC0gbnVtZXJpYyhsZW5ndGgocHJlZF9yKSkKICBwcmVkX3ByaWNlWzFdIDwtIGxhc3RfcHJpY2UgKiBleHAocHJlZF9yWzFdKQoKICBmb3IoaSBpbiAyOmxlbmd0aChwcmVkX3IpKXsKICAgIHByZWRfcHJpY2VbaV0gPC0gcHJlZF9wcmljZVtpLTFdICogZXhwKHByZWRfcltpXSkKICB9CiAgcmV0dXJuKHByZWRfcHJpY2UpCn0KCiMjIyBQcmVkaWN0IHVzaW5nIGFsbCAzIG1vZGVscwoKIyBGdWxsIG1vZGVsIChtMSkKcHJlZF9tMSA8LSBwcmVkaWN0X3ByaWNlKG0xLCBjb21wYXJlX2RhdGEsIGxhc3RfcHJpY2VfYmVmb3JlX3dpbmRvdykKCiMgUmVkdWNlZCBtb2RlbCAobTIpCnByZWRfbTIgPC0gcHJlZGljdF9wcmljZShtMiwgY29tcGFyZV9kYXRhLCBsYXN0X3ByaWNlX2JlZm9yZV93aW5kb3cpCgojIEJlc3QgbGFnIG1vZGVsIChtMykKcHJlZF9tMyA8LSBwcmVkaWN0X3ByaWNlKGJlc3RfbW9kZWwsIGNvbXBhcmVfZGF0YSwgbGFzdF9wcmljZV9iZWZvcmVfd2luZG93KQoKCiMjIyAgQnVpbGQgY29tcGFyaXNvbiB0YWJsZQpjb21wYXJpc29uX3RhYmxlIDwtIGRhdGEuZnJhbWUoCiAgRGF0ZSA9IGNvbXBhcmVfZGF0YSREYXRlLAogIEFjdHVhbCA9IGNvbXBhcmVfZGF0YSRCVEMsCiAgRnVsbF9Nb2RlbCA9IHByZWRfbTEsCiAgUmVkdWNlZF9Nb2RlbCA9IHByZWRfbTIsCiAgQmVzdF9MYWdfTW9kZWwgPSBwcmVkX20zCikKcHJpbnQoY29tcGFyaXNvbl90YWJsZSkKCgojIyMgUGxvdCBhbGwgdGhyZWUgbW9kZWxzIHZzIGFjdHVhbAptYXRwbG90KAogIGNvbXBhcmlzb25fdGFibGUkRGF0ZSwKICBjb21wYXJpc29uX3RhYmxlWywgMjo1XSwKICB0eXBlPSJsIiwgbHdkPTIsCiAgY29sPWMoImJsYWNrIiwicmVkIiwiYmx1ZSIsImRhcmtncmVlbiIpLAogIHhsYWI9IkRhdGUiLCB5bGFiPSJCVEMgUHJpY2UgKFVTRCkiLAogIG1haW49IkFjdHVhbCB2cyBQcmVkaWN0ZWQgQlRDIFByaWNlIgopCgpsZWdlbmQoCiAgInRvcGxlZnQiLAogIGxlZ2VuZD1jKCJBY3R1YWwiLCJGdWxsIE1vZGVsIiwiUmVkdWNlZCBNb2RlbCIsIkJlc3QgTGFnIE1vZGVsIiksCiAgY29sPWMoImJsYWNrIiwicmVkIiwiYmx1ZSIsImRhcmtncmVlbiIpLAogIGx3ZD0yCikKCgojIyMgOC4gQ29tcHV0ZSBSTVNFICsgTUFFClJNU0UgPC0gZnVuY3Rpb24oYWN0dWFsLCBwcmVkaWN0ZWQpIHNxcnQobWVhbigoYWN0dWFsIC0gcHJlZGljdGVkKV4yKSkKTUFFICA8LSBmdW5jdGlvbihhY3R1YWwsIHByZWRpY3RlZCkgbWVhbihhYnMoYWN0dWFsIC0gcHJlZGljdGVkKSkKCmVycm9yX3RhYmxlIDwtIGRhdGEuZnJhbWUoCiAgTW9kZWwgPSBjKCJGdWxsIE1vZGVsIiwiUmVkdWNlZCBNb2RlbCIsIkJlc3QgTGFnIE1vZGVsIiksCiAgUk1TRSA9IGMoCiAgICBSTVNFKGNvbXBhcmlzb25fdGFibGUkQWN0dWFsLCBjb21wYXJpc29uX3RhYmxlJEZ1bGxfTW9kZWwpLAogICAgUk1TRShjb21wYXJpc29uX3RhYmxlJEFjdHVhbCwgY29tcGFyaXNvbl90YWJsZSRSZWR1Y2VkX01vZGVsKSwKICAgIFJNU0UoY29tcGFyaXNvbl90YWJsZSRBY3R1YWwsIGNvbXBhcmlzb25fdGFibGUkQmVzdF9MYWdfTW9kZWwpCiAgKSwKICBNQUUgPSBjKAogICAgTUFFKGNvbXBhcmlzb25fdGFibGUkQWN0dWFsLCBjb21wYXJpc29uX3RhYmxlJEZ1bGxfTW9kZWwpLAogICAgTUFFKGNvbXBhcmlzb25fdGFibGUkQWN0dWFsLCBjb21wYXJpc29uX3RhYmxlJFJlZHVjZWRfTW9kZWwpLAogICAgTUFFKGNvbXBhcmlzb25fdGFibGUkQWN0dWFsLCBjb21wYXJpc29uX3RhYmxlJEJlc3RfTGFnX01vZGVsKQogICkKKQoKcHJpbnQoZXJyb3JfdGFibGUpCgpgYGAKCgo=