Tecnológico de Monterrey

Doctor Teófilo Ozuna

Alumna:

Avril Lobato Delgado A00833113

EDA de base de datos

Librerias

library(ggplot2)
library(dplyr)
library(tidyr)
library(lubridate)
library(purrr)
library(plotly)
library(forecast)
library(readxl)
library(DataExplorer)
library(dplyr)
library(ggplot2)
library(tm)
library(cluster)
library(factoextra) 
library(gridExtra)
library(purrr)
library(pROC)
library(rpart)
library(rpart.plot)
library(e1071)
library(ggpubr)
library(dlookr)
library(zoo)
library(caret)
library(stats)
library(tseries)
library(readr)
library(vars)
library(syuzhet)
library(kableExtra)
library(plotly)
library(scales)
library(knitr)
library(rmgarch)
library(devtools)
library(openxlsx)
library(relaimpo)
library(stargazer)
library(RColorBrewer)
library(PerformanceAnalytics)
library(ConnectednessApproach)
library(readr)
library(tseries)
library(forecast)
library(urca)
library(fGarch)
library(MTS)
library(MASS)
library(nortest)
library(outliers)
library(moments)
library(FinTS)
library(WeightedPortTest)

Carga de base de datos

# Lee el archivo CSV y selecciona las columnas relevantes
index_alt <- read_csv("C:/Users/AVRIL/Desktop/Spillovers/all_daily_index_returns.csv")
data_selected <- index_alt[, c("Date", "AI_INDEX", "Fintech_Index", "Blockchain_Index")]

Tests y EstadĆ­sticos de bd original

# Function for summary statistics
summary_stats <- function(data) {
  return(data.frame(
    Mean = mean(data, na.rm = TRUE),
    StdDev = sd(data, na.rm = TRUE),
    Min = min(data, na.rm = TRUE),
    P25 = quantile(data, 0.25, na.rm = TRUE),
    P50 = median(data, na.rm = TRUE),
    P75 = quantile(data, 0.75, na.rm = TRUE),
    Max = max(data, na.rm = TRUE),
    Skewness = skewness(data, na.rm = TRUE),
    Kurtosis = kurtosis(data, na.rm = TRUE)
  ))
}

# Calculate statistics and tests for each index
results <- data.frame(
  Test = c(
    "Mean", "Standard Deviation", "Minimum", "25th Percentile", "Median",
    "75th Percentile", "Maximum", "Skewness", "Kurtosis", "Jarque-Bera (p-value)",
    "ADF Test (p-value)", "KPSS Test (p-value)", "PP Test (p-value)", "ERS Test",
    "ARCH Test (p-value)", "Weighted Portmanteau Test (p-value)", "Q2(20) Test (p-value)",
    "Outlier detection (Chen and Liu)","Correlation Matrix and R-squared"
  ),
  AI_INDEX = NA, Fintech_Index = NA, Blockchain_Index = NA
)

# Populate the table with summary stats
stats_ai <- summary_stats(data_selected$AI_INDEX)
stats_fintech <- summary_stats(data_selected$Fintech_Index)
stats_blockchain <- summary_stats(data_selected$Blockchain_Index)
results$AI_INDEX[1:9] <- as.numeric(stats_ai)
results$Fintech_Index[1:9] <- as.numeric(stats_fintech)
results$Blockchain_Index[1:9] <- as.numeric(stats_blockchain)

# Normality and stationarity tests
results$AI_INDEX[10] <- jarque.bera.test(data_selected$AI_INDEX)$p.value
results$Fintech_Index[10] <- jarque.bera.test(data_selected$Fintech_Index)$p.value
results$Blockchain_Index[10] <- jarque.bera.test(data_selected$Blockchain_Index)$p.value

results$AI_INDEX[11] <- adf.test(data_selected$AI_INDEX)$p.value
results$Fintech_Index[11] <- adf.test(data_selected$Fintech_Index)$p.value
results$Blockchain_Index[11] <- adf.test(data_selected$Blockchain_Index)$p.value

results$AI_INDEX[12] <- kpss.test(data_selected$AI_INDEX)$p.value
results$Fintech_Index[12] <- kpss.test(data_selected$Fintech_Index)$p.value
results$Blockchain_Index[12] <- kpss.test(data_selected$Blockchain_Index)$p.value

results$AI_INDEX[13] <- pp.test(data_selected$AI_INDEX)$p.value
results$Fintech_Index[13] <- pp.test(data_selected$Fintech_Index)$p.value
results$Blockchain_Index[13] <- pp.test(data_selected$Blockchain_Index)$p.value

results$AI_INDEX[14] <- ur.ers(data_selected$AI_INDEX, type = "DF-GLS")@teststat
results$Fintech_Index[14] <- ur.ers(data_selected$Fintech_Index, type = "DF-GLS")@teststat
results$Blockchain_Index[14] <- ur.ers(data_selected$Blockchain_Index, type = "DF-GLS")@teststat

# ARCH test
results$AI_INDEX[15] <- ArchTest(data_selected$AI_INDEX)$p.value
results$Fintech_Index[15] <- ArchTest(data_selected$Fintech_Index)$p.value
results$Blockchain_Index[15] <- ArchTest(data_selected$Blockchain_Index)$p.value

# Portmanteau test
results$portmanteau_ai <- Weighted.Box.test(data_selected$AI_INDEX)$p.value
results$portmanteau_fintech <- Weighted.Box.test(data_selected$Fintech_Index)$p.value
results$portmanteau_blockchain <- Weighted.Box.test(data_selected$Blockchain_Index)$p.value

# Q2(20) test
results$AI_INDEX[17] <- Box.test(data_selected$AI_INDEX^2, lag = 20, type = "Ljung-Box")$p.value
results$Fintech_Index[17] <- Box.test(data_selected$Fintech_Index^2, lag = 20, type = "Ljung-Box")$p.value
results$Blockchain_Index[17] <- Box.test(data_selected$Blockchain_Index^2, lag = 20, type = "Ljung-Box")$p.value

# Outlier detection (Chen and Liu)
results$outliers_ai <- sum(scores(data_selected$AI_INDEX, type = "chisq", prob = 0.05) != 0)
results$outliers_fintech <- sum(scores(data_selected$Fintech_Index, type = "chisq", prob = 0.05) != 0)
results$outliers_blockchain <- sum(scores(data_selected$Blockchain_Index, type = "chisq", prob = 0.05) != 0)

# Correlation Matrix and R-squared
cor_matrix <- cor(data_selected[, -1], use = "complete.obs")
r_squared <- cor_matrix^2

print(results)
##                                   Test      AI_INDEX Fintech_Index
## 1                                 Mean  7.284978e-04  2.514532e-04
## 2                   Standard Deviation  5.997773e-03  1.886246e-03
## 3                              Minimum -1.803901e-02 -6.887190e-03
## 4                      25th Percentile -2.658939e-03 -9.810085e-04
## 5                               Median  1.024079e-03  2.999540e-04
## 6                      75th Percentile  5.001330e-03  1.530050e-03
## 7                              Maximum  1.653343e-02  5.406403e-03
## 8                             Skewness -3.676255e-01 -6.215113e-02
## 9                             Kurtosis  3.031592e+00  3.431835e+00
## 10               Jarque-Bera (p-value)  8.905365e-11  1.789472e-04
## 11                  ADF Test (p-value)  1.000000e-02  1.000000e-02
## 12                 KPSS Test (p-value)  1.000000e-01  1.000000e-01
## 13                   PP Test (p-value)  1.000000e-02  1.000000e-02
## 14                            ERS Test -8.226890e+00 -1.240032e+01
## 15                 ARCH Test (p-value)  0.000000e+00  0.000000e+00
## 16 Weighted Portmanteau Test (p-value)            NA            NA
## 17               Q2(20) Test (p-value)  0.000000e+00  0.000000e+00
## 18    Outlier detection (Chen and Liu)            NA            NA
## 19    Correlation Matrix and R-squared            NA            NA
##    Blockchain_Index portmanteau_ai portmanteau_fintech portmanteau_blockchain
## 1      4.414805e-04  2.791471e-321                   0                      0
## 2      5.269908e-03  2.791471e-321                   0                      0
## 3     -2.425996e-02  2.791471e-321                   0                      0
## 4     -2.095878e-03  2.791471e-321                   0                      0
## 5      7.566070e-04  2.791471e-321                   0                      0
## 6      3.584238e-03  2.791471e-321                   0                      0
## 7      2.091050e-02  2.791471e-321                   0                      0
## 8     -4.398032e-01  2.791471e-321                   0                      0
## 9      5.179150e+00  2.791471e-321                   0                      0
## 10     0.000000e+00  2.791471e-321                   0                      0
## 11     1.000000e-02  2.791471e-321                   0                      0
## 12     1.000000e-01  2.791471e-321                   0                      0
## 13     1.000000e-02  2.791471e-321                   0                      0
## 14    -1.321070e+01  2.791471e-321                   0                      0
## 15     0.000000e+00  2.791471e-321                   0                      0
## 16               NA  2.791471e-321                   0                      0
## 17     0.000000e+00  2.791471e-321                   0                      0
## 18               NA  2.791471e-321                   0                      0
## 19               NA  2.791471e-321                   0                      0
##    outliers_ai outliers_fintech outliers_blockchain
## 1         1890             1974                1904
## 2         1890             1974                1904
## 3         1890             1974                1904
## 4         1890             1974                1904
## 5         1890             1974                1904
## 6         1890             1974                1904
## 7         1890             1974                1904
## 8         1890             1974                1904
## 9         1890             1974                1904
## 10        1890             1974                1904
## 11        1890             1974                1904
## 12        1890             1974                1904
## 13        1890             1974                1904
## 14        1890             1974                1904
## 15        1890             1974                1904
## 16        1890             1974                1904
## 17        1890             1974                1904
## 18        1890             1974                1904
## 19        1890             1974                1904
# Convertir la columna `Date` a tipo Date si estĆ” en formato "dd/mm/yyyy"
index_alt$Date <- as.Date(index_alt$Date, format = "%d/%m/%Y")

# Mostrar estructura y resumen
str(index_alt)
## spc_tbl_ [2,051 Ɨ 12] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ Date                 : Date[1:2051], format: "2019-01-08" "2019-01-09" ...
##  $ AI_INDEX             : num [1:2051] 0.00865 0.00858 0.00851 0.00844 0.00836 ...
##  $ Cumulative return...3: num [1:2051] 101 102 103 103 104 ...
##  $ Fintech_Index        : num [1:2051] -0.000675 -0.000675 -0.000676 -0.000676 -0.000677 ...
##  $ Cumulative return...5: num [1:2051] 99.9 99.9 99.8 99.7 99.7 ...
##  $ Blockchain_Index     : num [1:2051] 0.00205 0.00204 0.00204 0.00203 0.00203 ...
##  $ Cumulative return...7: num [1:2051] 100 100 101 101 101 ...
##  $ Nasdaq Composite     : num [1:2051] 1005 1010 1015 1020 1025 ...
##  $ Dax 40               : num [1:2051] 1002 1003 1005 1006 1008 ...
##  $ Dow Jones Industrial : num [1:2051] 1003 1007 1010 1014 1017 ...
##  $ KFTX Index           : num [1:2051] 1012 1023 1029 1028 1027 ...
##  $ S&P Financials Index : num [1:2051] 1003 1005 1006 1008 1011 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   Date = col_character(),
##   ..   AI_INDEX = col_double(),
##   ..   `Cumulative return...3` = col_double(),
##   ..   Fintech_Index = col_double(),
##   ..   `Cumulative return...5` = col_double(),
##   ..   Blockchain_Index = col_double(),
##   ..   `Cumulative return...7` = col_double(),
##   ..   `Nasdaq Composite` = col_double(),
##   ..   `Dax 40` = col_double(),
##   ..   `Dow Jones Industrial` = col_double(),
##   ..   `KFTX Index` = col_double(),
##   ..   `S&P Financials Index` = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>
summary(index_alt)
##       Date               AI_INDEX          Cumulative return...3
##  Min.   :2019-01-08   Min.   :-0.0180390   Min.   :100.9        
##  1st Qu.:2020-06-03   1st Qu.:-0.0026589   1st Qu.:206.3        
##  Median :2021-10-29   Median : 0.0010241   Median :275.6        
##  Mean   :2021-10-29   Mean   : 0.0007285   Mean   :270.1        
##  3rd Qu.:2023-03-25   3rd Qu.: 0.0050013   3rd Qu.:332.3        
##  Max.   :2024-08-19   Max.   : 0.0165334   Max.   :439.8        
##  Fintech_Index        Cumulative return...5 Blockchain_Index    
##  Min.   :-0.0068872   Min.   : 91.42        Min.   :-0.0242600  
##  1st Qu.:-0.0009810   1st Qu.:105.21        1st Qu.:-0.0020959  
##  Median : 0.0003000   Median :116.09        Median : 0.0007566  
##  Mean   : 0.0002515   Mean   :120.99        Mean   : 0.0004415  
##  3rd Qu.: 0.0015300   3rd Qu.:127.90        3rd Qu.: 0.0035842  
##  Max.   : 0.0054064   Max.   :173.73        Max.   : 0.0209105  
##  Cumulative return...7 Nasdaq Composite     Dax 40       Dow Jones Industrial
##  Min.   : 95.04        Min.   :1005     Min.   : 829.2   Min.   : 818.2      
##  1st Qu.:136.66        1st Qu.:1435     1st Qu.:1184.8   1st Qu.:1186.1      
##  Median :168.18        Median :1810     Median :1320.5   Median :1409.5      
##  Mean   :176.21        Mean   :1798     Mean   :1329.6   Mean   :1357.7      
##  3rd Qu.:220.23        3rd Qu.:2098     3rd Qu.:1459.5   3rd Qu.:1482.5      
##  Max.   :276.64        Max.   :2723     Max.   :1743.4   Max.   :1757.1      
##    KFTX Index     S&P Financials Index
##  Min.   : 881.8   Min.   : 727.6      
##  1st Qu.:1289.6   1st Qu.:1153.5      
##  Median :1404.2   Median :1371.1      
##  Mean   :1466.7   Mean   :1348.0      
##  3rd Qu.:1680.7   3rd Qu.:1537.3      
##  Max.   :1925.3   Max.   :1811.6

Chatziantoniou, Gabauer & Gupta (2021): Integration and risk transmission in the market for crude oil: A time-varying parameter frequency connectedness approach

# Convertir a objeto zoo
data_selected <- index_alt[, c("Date","AI_INDEX", "Fintech_Index", "Blockchain_Index")]

data_matrix <- as.matrix(data_selected)

data_zoo <- zoo(data_selected[, -1], order.by = data_selected$Date)

# Instalar y cargar el paquete ConnectednessApproach, si no estĆ” ya instalado
if (!requireNamespace("ConnectednessApproach", quietly = TRUE)) {
  if (!requireNamespace("devtools", quietly = TRUE)) {
    install.packages("devtools")
  }
  devtools::install_github("GabauerDavid/ConnectednessApproach")
}
library(ConnectednessApproach)

# Configuración de parÔmetros para TVPVAR
nlag <- 2       # Orden del rezago
lambda <- c(0.99, 0.99)  # Valores de decaimiento para el filtro

# Crear la lista de configuración necesaria
config <- list(l = lambda, nlag = nlag)

# Estimar el modelo TVP-VAR con los parƔmetros especificados
tvpvar_model <- TVPVAR(data_zoo, configuration = config)

Table 2: Averaged Connectedness Table

partition = c(pi+0.00001, pi/5, 0)
dca = ConnectednessApproach(data_zoo, 
                            model="TVP-VAR",
                            connectedness="Frequency",
                            nlag=1,
                            nfore=100,
                            window.size=200,
                            VAR_config=list(TVPVAR=list(kappa1=0.99, kappa2=0.99, prior="BayesPrior")),
                            Connectedness_config = list(
                              FrequencyConnectedness=list(partition=partition, generalized=TRUE, scenario="ABS")
                            ))
kable(dca$TABLE)
AI_INDEX.Total Fintech_Index.Total Blockchain_Index.Total FROM.Total AI_INDEX.1-5 Fintech_Index.1-5 Blockchain_Index.1-5 FROM.1-5 AI_INDEX.5-Inf Fintech_Index.5-Inf Blockchain_Index.5-Inf FROM.5-Inf
AI_INDEX 79.76 6.87 13.37 20.24 10.44 0.87 1.13 2.00 69.32 6.00 12.24 18.24
Fintech_Index 8.56 84.40 7.04 15.60 0.75 10.89 0.53 1.28 7.81 73.51 6.51 14.32
Blockchain_Index 15.46 5.78 78.76 21.24 1.24 0.69 10.50 1.93 14.22 5.08 68.26 19.31
TO 24.02 12.64 20.41 57.07 1.99 1.56 1.65 5.20 22.03 11.08 18.76 51.87
Inc.Own 103.79 97.04 99.17 cTCI/TCI 12.43 12.44 12.15 cTCI/TCI 91.35 84.60 87.02 cTCI/TCI
Net 3.79 -2.96 -0.83 28.54/19.02 -0.01 0.28 -0.27 2.60/1.73 3.79 -3.24 -0.55 25.94/17.29
NPDC 2.00 0.00 1.00 1.00 2.00 0.00 2.00 0.00 1.00

Figure 4: Net Total Directional Connectedness

PlotNET(dca, ylim=c(-60,60))

Gabauer and Gupta (2018): On the transmission mechanism of country-specific and international economic uncertainty spillovers: Evidence from a TVP-VAR connectedness decomposition approach

data_zoo2 <- zoo(data_selected[, c("AI_INDEX", "Fintech_Index", "Blockchain_Index")], 
                 order.by = data_selected$Date)

# Configuración de parÔmetros para TVPVAR
nlag <- 2       # Orden del rezago
lambda <- c(0.99, 0.99)  # Valores de decaimiento para el filtro

# Crear la lista de configuración necesaria
config <- list(l = lambda, nlag = nlag)

# Estimar el modelo TVP-VAR con los parƔmetros especificados
tvpvar_model <- TVPVAR(data_zoo2, configuration = config)
dca = ConnectednessApproach(data_zoo2, 
                            nlag=1,
                            nfore=10,
                            model="TVP-VAR",
                            connectedness="Time",
                            window.size=200,
                            VAR_config=list(TVPVAR=list(kappa1=0.99, kappa2=0.99, prior="BayesPrior")))

Table 1: Connectedness table

kable(dca$TABLE)
AI_INDEX Fintech_Index Blockchain_Index FROM
AI_INDEX 81.70 6.65 11.65 18.30
Fintech_Index 7.31 86.71 5.98 13.29
Blockchain_Index 11.98 5.17 82.86 17.14
TO 19.29 11.82 17.63 48.73
Inc.Own 100.99 98.53 100.48 cTCI/TCI
NET 0.99 -1.47 0.48 24.37/16.24
NPT 2.00 0.00 1.00
# CONNECTEDNESS DECOMPOSITION
int = InternalConnectedness(dca, groups=list("Group1"=c(1), "Group2"=c(2), "Group3"=c(3)))
ext = ExternalConnectedness(dca, groups=list("Group1"=c(1), "Group2"=c(2), "Group3"=c(3)))
kable(int$TABLE)
AI_INDEX Fintech_Index Blockchain_Index FROM
AI_INDEX 81.70 0.00 0.00 0.00
Fintech_Index 0.00 86.71 0.00 0.00
Blockchain_Index 0.00 0.00 82.86 0.00
TO 0.00 0.00 0.00 0.00
Inc.Own 81.70 86.71 82.86 cTCI/TCI
NET 0.00 0.00 0.00 0.00/0.00
NPT 0.00 0.00 0.00
kable(ext$TABLE)
AI_INDEX Fintech_Index Blockchain_Index FROM
AI_INDEX 0.00 6.65 11.65 18.30
Fintech_Index 7.31 0.00 5.98 13.29
Blockchain_Index 11.98 5.17 0.00 17.14
TO 19.29 11.82 17.63 48.73
Inc.Own 19.29 11.82 17.63 cTCI/TCI
NET 0.99 -1.47 0.48 24.37/16.24
NPT 2.00 0.00 1.00
#Figure 3: Dynamic total connectedness
PlotTCI(dca, int, ylim=c(0, 40))

#Figure 4: Net total directional connectedness
PlotNET(dca, int, ylim=c(-10, 10))

#Figure 5: Total directional connectedness FROM others
PlotFROM(dca, int, ylim=c(0, 60))

#Figure 6: Total directional connectedness TO others
PlotTO(dca, int, ylim=c(0, 60))

#Figure 7: Internal net pairwise total directional connectedness
PlotNPDC(dca, int, ylim=c(-5, 5))

Cocca, Gabauer, and Pomberger (2024): Clean energy market connectedness and investment strategies: New evidence from DCC-GARCH R2 decomposed connectedness measures

# Convierte la columna 'Date' a formato Date
date <- as.Date(data_selected$Date, format="%d/%m/%Y")

# Crea la serie de tiempo (zoo) solo con las columnas seleccionadas
Y <- zoo(data_selected[, c("Fintech_Index", "AI_INDEX", "Blockchain_Index")], order.by = date)

# Asegúrate de que los datos sean numéricos y elimina valores NA
Y <- na.omit(zoo(data.frame(
  Fintech_Index_diff = as.numeric(data_selected$Fintech_Index),
  AI_INDEX_diff = as.numeric(data_selected$AI_INDEX),
  Blockchain_Index_diff = as.numeric(data_selected$Blockchain_Index)
), order.by = date))

# Reemplaza los valores NA restantes por 0
Y[is.na(Y)] <- 0

# Establece 'dimnames' de Y con nĆŗmeros como Ć­ndices (como en Y2) sin cambiar el Ć­ndice de fecha
dimnames(Y) <- list(as.character(1:nrow(Y)), colnames(Y))

NAMES = colnames(Y)
k = ncol(Y)
t = nrow(Y)

# Verifica la estructura de Y
str(Y)
## 'zoo' series from 2019-01-08 to 2024-08-19
##   Data: num [1:2051, 1:3] -0.000675 -0.000675 -0.000676 -0.000676 -0.000677 ...
##  - attr(*, "dimnames")=List of 2
##   ..$ : chr [1:2051] "1" "2" "3" "4" ...
##   ..$ : chr [1:3] "Fintech_Index_diff" "AI_INDEX_diff" "Blockchain_Index_diff"
##   Index:  Date[1:2051], format: "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" "2019-01-12" ...
kable(SummaryStatistics(Y, nlag=20))
Fintech_Index_diff AI_INDEX_diff Blockchain_Index_diff
Mean 0.000*** 0.001*** 0.000***
(0.000) (0.000) (0.000)
Variance 0 0 0
Skewness -0.062 -0.368*** -0.440***
(0.249) (0.000) (0.000)
Ex.Kurtosis 0.432*** 0.032 2.179***
(0.001) (0.712) (0.000)
JB 17.257*** 46.284*** 471.935***
(0.000) (0.000) (0.000)
ERS -12.400*** -8.227*** -13.211***
(0.000) (0.000) (0.000)
Q(20) 3870.587*** 3338.261*** 3939.808***
(0.000) (0.000) (0.000)
Q2(20) 3413.861*** 5253.401*** 4241.131***
(0.000) (0.000) (0.000)
kendall Fintech_Index_diff AI_INDEX_diff Blockchain_Index_diff
Fintech_Index_diff 1.000*** -0.062*** 0.016
AI_INDEX_diff -0.062*** 1.000*** 0.144***
Blockchain_Index_diff 0.016 0.144*** 1.000***

Figure 0: Percentage changes

par(mfcol = c(ceiling(k/2),2), oma = c(0, 1, 0, 0) + 0.5, mar = c(1, 1, 1, 1) + 0.5, mgp = c(1, 0.4, 0))
for (i in 1:k) {
  plot(date,Y[,i],type='l',las=1,xaxs='i',yaxs='i',ylim=c(-0.1,0.1),xlab='',ylab='',main=paste(NAMES[i]),tck=-.02,col='steelblue4')
  grid(NA,NULL)
  lines(date,Y[,i],col='steelblue4')
  abline(h=0,lty=3)
  box()
}

spec <- list()

# Itera sobre cada columna de Y
for (i in 1:k) {
  # Intenta seleccionar el mejor modelo GARCH para cada serie
  u <- tryCatch({
    GARCHselection(Y[, i],
                   distributions = c("norm", "std", "sstd", "ged", "sged"),
                   models = c("sGARCH", "gjrGARCH", "eGARCH", "iGARCH", "AVGARCH", "TGARCH"))
  }, error = function(e) {
    warning(paste("Error al seleccionar modelo GARCH para la variable", i, ":", e$message))
    NULL
  })
  
  # Si 'u' no es NULL y tiene un mejor modelo, agrega a 'spec'
  if (!is.null(u) && !is.null(u$best_ugarch)) {
    spec[[i]] <- u$best_ugarch
  } else {
    # Si no se seleccionó un modelo, asigna un modelo GARCH(1,1) por defecto
    warning(paste("No se seleccionó ningún modelo GARCH para", NAMES[i], ". Usando modelo GARCH(1,1) con distribución normal"))
    spec[[i]] <- ugarchspec(variance.model = list(model = "sGARCH", garchOrder = c(1, 1)),
                            mean.model = list(armaOrder = c(0, 0)),
                            distribution.model = "norm")
  }
}

# Verifica que 'spec' tenga modelos para cada serie en Y
if (length(spec) != k) {
  stop("spec no contiene modelos vƔlidos para todas las series de Y")
}

# Ejecuta el modelo DCC-GARCH si spec es vƔlida
fit <- BivariateDCCGARCH(Y, spec)
## [1] "DCC-GARCH estimation based on Fintech_Index_diff and AI_INDEX_diff"
## 
## *-------------------------------------------------*
## *                  Copula GARCH Fit               *
## *-------------------------------------------------*
## 
## Distribution     :  mvt
## DCC Order            :  1 1
## Asymmetric           :  FALSE
## No. of Parameters    :  19
## [VAR GARCH DCC UncQ]: [0+15+3+1]
## No. of Series        :  2
## No. of Observations  :  2051
## Log-Likelihood       :  21146.98
## Av.Log-Likelihood    :  10.311 
## 
## Optimal Parameters
## ---------------------------------------------------
##                              Estimate  Std. Error  t value Pr(>|t|)
## [Fintech_Index_diff].mu      0.000779          NA       NA       NA
## [Fintech_Index_diff].omega   0.000001          NA       NA       NA
## [Fintech_Index_diff].alpha1  1.000000          NA       NA       NA
## [Fintech_Index_diff].beta1   0.169934          NA       NA       NA
## [Fintech_Index_diff].eta11   0.076762          NA       NA       NA
## [Fintech_Index_diff].skew    2.447990          NA       NA       NA
## [Fintech_Index_diff].shape   3.327699          NA       NA       NA
## [AI_INDEX_diff].mu          -0.000120          NA       NA       NA
## [AI_INDEX_diff].omega        0.000000          NA       NA       NA
## [AI_INDEX_diff].alpha1       1.000000          NA       NA       NA
## [AI_INDEX_diff].beta1        0.000000          NA       NA       NA
## [AI_INDEX_diff].eta11       -0.122576          NA       NA       NA
## [AI_INDEX_diff].eta21       -0.000026          NA       NA       NA
## [AI_INDEX_diff].skew         0.379831          NA       NA       NA
## [AI_INDEX_diff].shape        4.157634          NA       NA       NA
## [Joint]dcca1                 0.999994          NA       NA       NA
## [Joint]dccb1                 0.000000          NA       NA       NA
## [Joint]mshape                4.003043          NA       NA       NA
## 
## Information Criteria
## ---------------------
##                     
## Akaike       -20.604
## Bayes        -20.554
## Shibata      -20.604
## Hannan-Quinn -20.585
## 
## 
## Elapsed time : 8.244778 
## 
## [1] "DCC-GARCH estimation based on Fintech_Index_diff and Blockchain_Index_diff"
## 
## *-------------------------------------------------*
## *                  Copula GARCH Fit               *
## *-------------------------------------------------*
## 
## Distribution     :  mvt
## DCC Order            :  1 1
## Asymmetric           :  FALSE
## No. of Parameters    :  18
## [VAR GARCH DCC UncQ]: [0+14+3+1]
## No. of Series        :  2
## No. of Observations  :  2051
## Log-Likelihood       :  20257.12
## Av.Log-Likelihood    :  9.877 
## 
## Optimal Parameters
## ---------------------------------------------------
##                                 Estimate  Std. Error  t value Pr(>|t|)
## [Fintech_Index_diff].mu         0.000779          NA       NA       NA
## [Fintech_Index_diff].omega      0.000001          NA       NA       NA
## [Fintech_Index_diff].alpha1     1.000000          NA       NA       NA
## [Fintech_Index_diff].beta1      0.169934          NA       NA       NA
## [Fintech_Index_diff].eta11      0.076762          NA       NA       NA
## [Fintech_Index_diff].skew       2.447990          NA       NA       NA
## [Fintech_Index_diff].shape      3.327699          NA       NA       NA
## [Blockchain_Index_diff].mu      0.000320          NA       NA       NA
## [Blockchain_Index_diff].omega  -2.080531          NA       NA       NA
## [Blockchain_Index_diff].alpha1  0.040246          NA       NA       NA
## [Blockchain_Index_diff].beta1   0.813364          NA       NA       NA
## [Blockchain_Index_diff].gamma1  1.329788          NA       NA       NA
## [Blockchain_Index_diff].skew    0.542386          NA       NA       NA
## [Blockchain_Index_diff].shape   3.532068          NA       NA       NA
## [Joint]dcca1                    0.923126          NA       NA       NA
## [Joint]dccb1                    0.000000          NA       NA       NA
## [Joint]mshape                   7.755774          NA       NA       NA
## 
## Information Criteria
## ---------------------
##                     
## Akaike       -19.737
## Bayes        -19.690
## Shibata      -19.737
## Hannan-Quinn -19.720
## 
## 
## Elapsed time : 5.123329 
## 
## [1] "DCC-GARCH estimation based on AI_INDEX_diff and Blockchain_Index_diff"
## 
## *-------------------------------------------------*
## *                  Copula GARCH Fit               *
## *-------------------------------------------------*
## 
## Distribution     :  mvt
## DCC Order            :  1 1
## Asymmetric           :  FALSE
## No. of Parameters    :  19
## [VAR GARCH DCC UncQ]: [0+15+3+1]
## No. of Series        :  2
## No. of Observations  :  2051
## Log-Likelihood       :  17917.44
## Av.Log-Likelihood    :  8.736 
## 
## Optimal Parameters
## ---------------------------------------------------
##                                 Estimate  Std. Error  t value Pr(>|t|)
## [AI_INDEX_diff].mu             -0.000120          NA       NA       NA
## [AI_INDEX_diff].omega           0.000000          NA       NA       NA
## [AI_INDEX_diff].alpha1          1.000000          NA       NA       NA
## [AI_INDEX_diff].beta1           0.000000          NA       NA       NA
## [AI_INDEX_diff].eta11          -0.122576          NA       NA       NA
## [AI_INDEX_diff].eta21          -0.000026          NA       NA       NA
## [AI_INDEX_diff].skew            0.379831          NA       NA       NA
## [AI_INDEX_diff].shape           4.157634          NA       NA       NA
## [Blockchain_Index_diff].mu      0.000320          NA       NA       NA
## [Blockchain_Index_diff].omega  -2.080531          NA       NA       NA
## [Blockchain_Index_diff].alpha1  0.040246          NA       NA       NA
## [Blockchain_Index_diff].beta1   0.813364          NA       NA       NA
## [Blockchain_Index_diff].gamma1  1.329788          NA       NA       NA
## [Blockchain_Index_diff].skew    0.542386          NA       NA       NA
## [Blockchain_Index_diff].shape   3.532068          NA       NA       NA
## [Joint]dcca1                    0.941613          NA       NA       NA
## [Joint]dccb1                    0.000000          NA       NA       NA
## [Joint]mshape                   7.839345          NA       NA       NA
## 
## Information Criteria
## ---------------------
##                     
## Akaike       -17.454
## Bayes        -17.405
## Shibata      -17.455
## Hannan-Quinn -17.436
## 
## 
## Elapsed time : 6.651648

Table 4: Evaluation of univariate GARCH performance

H = fit$H_t
R = fit$R_t

uGARCH_table = NULL
for (i in 1:k) {
  fit = ugarchfit(spec[[i]], Y[,i])
  gt = GARCHtests(fit, lag=20)
  uGARCH_table = rbind(uGARCH_table, gt$TABLE)
}

kable(uGARCH_table)
SignBias WARCH(20) VaR CVaR VaR Dur.
statistics 0.6230910 1.9437522 113.69976 -93.6559 0.1666667
pvalues 0.5332942 0.9997909 0.00000 0.1700 0.1755157
statistics 0.8620658 1.1073277 76.58490 -148.2286 0.2843137
pvalues 0.3887523 0.9999953 0.00000 0.0000 0.3464012
statistics 1.4127318 13.8866627 74.01928 -152.5048 0.2941176
pvalues 0.1578867 0.1760766 0.00000 0.2160 0.1284943

Figure 3: Dynamic conditional correlations

par(mfcol = c(ceiling(k/2),2), oma = c(0, 1, 0, 0) + 0.5, mar = c(1, 1, 1, 1) + 0.5, mgp = c(1, 0.4, 0))
for (j in 1:k) {
  plot(date,R[j,j,],type='l',las=1,xaxs='i',yaxs='i',xlab='',ylab='',main=paste(NAMES[j]),tck=-.02,col=j,ylim=c(-1.1,1.1))
  grid(NA,NULL)
  for (i in 1:k) {
    lines(date,R[j,i,],col=i)
    abline(h=0,lty=3)
    box()
  }
  legend("bottom",NAMES[-j],fill=c(1:k)[-j],bty="n",cex=0.75,ncol=k)
}

Table 5: Averaged connectedness measures

dca = R2Correlations(R)
##   |                                                                              |                                                                      |   0%  |                                                                              |                                                                      |   1%  |                                                                              |=                                                                     |   1%  |                                                                              |=                                                                     |   2%  |                                                                              |==                                                                    |   2%  |                                                                              |==                                                                    |   3%  |                                                                              |==                                                                    |   4%  |                                                                              |===                                                                   |   4%  |                                                                              |===                                                                   |   5%  |                                                                              |====                                                                  |   5%  |                                                                              |====                                                                  |   6%  |                                                                              |=====                                                                 |   6%  |                                                                              |=====                                                                 |   7%  |                                                                              |=====                                                                 |   8%  |                                                                              |======                                                                |   8%  |                                                                              |======                                                                |   9%  |                                                                              |=======                                                               |   9%  |                                                                              |=======                                                               |  10%  |                                                                              |=======                                                               |  11%  |                                                                              |========                                                              |  11%  |                                                                              |========                                                              |  12%  |                                                                              |=========                                                             |  12%  |                                                                              |=========                                                             |  13%  |                                                                              |=========                                                             |  14%  |                                                                              |==========                                                            |  14%  |                                                                              |==========                                                            |  15%  |                                                                              |===========                                                           |  15%  |                                                                              |===========                                                           |  16%  |                                                                              |============                                                          |  16%  |                                                                              |============                                                          |  17%  |                                                                              |============                                                          |  18%  |                                                                              |=============                                                         |  18%  |                                                                              |=============                                                         |  19%  |                                                                              |==============                                                        |  19%  |                                                                              |==============                                                        |  20%  |                                                                              |==============                                                        |  21%  |                                                                              |===============                                                       |  21%  |                                                                              |===============                                                       |  22%  |                                                                              |================                                                      |  22%  |                                                                              |================                                                      |  23%  |                                                                              |================                                                      |  24%  |                                                                              |=================                                                     |  24%  |                                                                              |=================                                                     |  25%  |                                                                              |==================                                                    |  25%  |                                                                              |==================                                                    |  26%  |                                                                              |===================                                                   |  26%  |                                                                              |===================                                                   |  27%  |                                                                              |===================                                                   |  28%  |                                                                              |====================                                                  |  28%  |                                                                              |====================                                                  |  29%  |                                                                              |=====================                                                 |  29%  |                                                                              |=====================                                                 |  30%  |                                                                              |=====================                                                 |  31%  |                                                                              |======================                                                |  31%  |                                                                              |======================                                                |  32%  |                                                                              |=======================                                               |  32%  |                                                                              |=======================                                               |  33%  |                                                                              |=======================                                               |  34%  |                                                                              |========================                                              |  34%  |                                                                              |========================                                              |  35%  |                                                                              |=========================                                             |  35%  |                                                                              |=========================                                             |  36%  |                                                                              |==========================                                            |  36%  |                                                                              |==========================                                            |  37%  |                                                                              |==========================                                            |  38%  |                                                                              |===========================                                           |  38%  |                                                                              |===========================                                           |  39%  |                                                                              |============================                                          |  39%  |                                                                              |============================                                          |  40%  |                                                                              |============================                                          |  41%  |                                                                              |=============================                                         |  41%  |                                                                              |=============================                                         |  42%  |                                                                              |==============================                                        |  42%  |                                                                              |==============================                                        |  43%  |                                                                              |==============================                                        |  44%  |                                                                              |===============================                                       |  44%  |                                                                              |===============================                                       |  45%  |                                                                              |================================                                      |  45%  |                                                                              |================================                                      |  46%  |                                                                              |=================================                                     |  46%  |                                                                              |=================================                                     |  47%  |                                                                              |=================================                                     |  48%  |                                                                              |==================================                                    |  48%  |                                                                              |==================================                                    |  49%  |                                                                              |===================================                                   |  49%  |                                                                              |===================================                                   |  50%  |                                                                              |===================================                                   |  51%  |                                                                              |====================================                                  |  51%  |                                                                              |====================================                                  |  52%  |                                                                              |=====================================                                 |  52%  |                                                                              |=====================================                                 |  53%  |                                                                              |=====================================                                 |  54%  |                                                                              |======================================                                |  54%  |                                                                              |======================================                                |  55%  |                                                                              |=======================================                               |  55%  |                                                                              |=======================================                               |  56%  |                                                                              |========================================                              |  56%  |                                                                              |========================================                              |  57%  |                                                                              |========================================                              |  58%  |                                                                              |=========================================                             |  58%  |                                                                              |=========================================                             |  59%  |                                                                              |==========================================                            |  59%  |                                                                              |==========================================                            |  60%  |                                                                              |==========================================                            |  61%  |                                                                              |===========================================                           |  61%  |                                                                              |===========================================                           |  62%  |                                                                              |============================================                          |  62%  |                                                                              |============================================                          |  63%  |                                                                              |============================================                          |  64%  |                                                                              |=============================================                         |  64%  |                                                                              |=============================================                         |  65%  |                                                                              |==============================================                        |  65%  |                                                                              |==============================================                        |  66%  |                                                                              |===============================================                       |  66%  |                                                                              |===============================================                       |  67%  |                                                                              |===============================================                       |  68%  |                                                                              |================================================                      |  68%  |                                                                              |================================================                      |  69%  |                                                                              |=================================================                     |  69%  |                                                                              |=================================================                     |  70%  |                                                                              |=================================================                     |  71%  |                                                                              |==================================================                    |  71%  |                                                                              |==================================================                    |  72%  |                                                                              |===================================================                   |  72%  |                                                                              |===================================================                   |  73%  |                                                                              |===================================================                   |  74%  |                                                                              |====================================================                  |  74%  |                                                                              |====================================================                  |  75%  |                                                                              |=====================================================                 |  75%  |                                                                              |=====================================================                 |  76%  |                                                                              |======================================================                |  76%  |                                                                              |======================================================                |  77%  |                                                                              |======================================================                |  78%  |                                                                              |=======================================================               |  78%  |                                                                              |=======================================================               |  79%  |                                                                              |========================================================              |  79%  |                                                                              |========================================================              |  80%  |                                                                              |========================================================              |  81%  |                                                                              |=========================================================             |  81%  |                                                                              |=========================================================             |  82%  |                                                                              |==========================================================            |  82%  |                                                                              |==========================================================            |  83%  |                                                                              |==========================================================            |  84%  |                                                                              |===========================================================           |  84%  |                                                                              |===========================================================           |  85%  |                                                                              |============================================================          |  85%  |                                                                              |============================================================          |  86%  |                                                                              |=============================================================         |  86%  |                                                                              |=============================================================         |  87%  |                                                                              |=============================================================         |  88%  |                                                                              |==============================================================        |  88%  |                                                                              |==============================================================        |  89%  |                                                                              |===============================================================       |  89%  |                                                                              |===============================================================       |  90%  |                                                                              |===============================================================       |  91%  |                                                                              |================================================================      |  91%  |                                                                              |================================================================      |  92%  |                                                                              |=================================================================     |  92%  |                                                                              |=================================================================     |  93%  |                                                                              |=================================================================     |  94%  |                                                                              |==================================================================    |  94%  |                                                                              |==================================================================    |  95%  |                                                                              |===================================================================   |  95%  |                                                                              |===================================================================   |  96%  |                                                                              |====================================================================  |  96%  |                                                                              |====================================================================  |  97%  |                                                                              |====================================================================  |  98%  |                                                                              |===================================================================== |  98%  |                                                                              |===================================================================== |  99%  |                                                                              |======================================================================|  99%  |                                                                              |======================================================================| 100%
kable(dca$TABLE)
Fintech_Index_diff AI_INDEX_diff Blockchain_Index_diff FROM
Fintech_Index_diff 100.00 62.16 22.18 84.34
AI_INDEX_diff 62.45 100.00 20.89 83.33
Blockchain_Index_diff 24.17 22.58 100.00 46.75
TO 86.62 84.74 43.07 214.42
Inc.Own 186.62 184.74 143.07 cTCI/TCI
NET 2.28 1.40 -3.68 107.21/71.47
NPT 2.00 1.00 0.00

Figure 4: Dynamic conditional R2 decomposed measures

r2c = apply(dca$CT,c(1,3),sum)-1
par(mfcol = c(ceiling(k/2),2), oma = c(0, 1, 0, 0) + 0.5, mar = c(1, 1, 1, 1) + 0.5, mgp = c(1, 0.4, 0))
for (j in 1:k) {
  r2dd = matrix(0,ncol=k,nrow=t)
  for (i in 1:t) {
    ded = rep(0,k)
    ded[j] = 1
    r2dd[i,] = cumsum(dca$CT[j,,i]-ded)
  }
  plot(date,100*r2c[j,]*NA,type="l",las=1,xlab="",ylab="",ylim=c(0,100),xaxs="i",tck=-0.01,yaxs="i",main=NAMES[j])
  grid(NA,NULL)
  for (i in k:1) {
    polygon(c(date, rev(date)), c(c(rep(0, t)), rev(100*r2dd[,i])), col=i, border=i)
  }
  box()
  legend("topleft",NAMES[-j],fill=c(1:k)[-j],bty="n",cex=0.75,ncol=1)
}

Figure 5: Dynamic total connectedness

par(mfcol = c(1,1), oma = c(0, 1, 0, 0) + 0.5, mar = c(1, 1, 1, 1) + 0.5, mgp = c(1, 0.4, 0))
plot(date,dca$TCI*NA,type='l',las=1,xaxs='i',yaxs='i',xlab='',ylab='',main='',tck=-.01, ylim=c(0,110))#c(max(c(0,min(TCI)-10)),max(TCI)+10))
grid(NA,NULL)
polygon(c(date, rev(date)), c(c(rep(0, t)), rev(dca$TCI)), col=1, border=1)
box()

Figure 6: Net total directional connectedness

par(mfcol = c(ceiling(k/2),2), oma = c(0, 0, 0, 0) + 0.5, mar = c(1, 1, 1, 1) + 0.5, mgp = c(1, 0.4, 0))
for (i in 1:k) {
  plot(date,dca$NET[,i]*NA,type='l',las=1,xaxs='i',yaxs='i',ylim=c(-20,20),xlab='',ylab='',main=paste("NET",NAMES[i]),tck=-.025)
  grid(NA,NULL)
  polygon(c(date, rev(date)), c(c(rep(0, t)), rev(dca$NET[,i])), col=1, border=1)
  abline(h=0,lty=3)
  box()
}

Table 7: Hedge ratios

method = "cumsum"
statistics = "Fisher"
metric = "StdDev"
hr = HedgeRatio(Y/100, H, statistics=statistics, method=method, metric=metric, digit=3)
kable(hr$TABLE)
Mean Std.Dev. 5% 95% HE p-value Return Std.Dev SR
Fintech_Index_diff/AI_INDEX_diff -4.933 118.289 -2.128 3.001 -10177.249 0.000 0.013 0.030 0.444
Fintech_Index_diff/Blockchain_Index_diff 0.043 0.600 -0.716 0.846 0.040 0.000 0.001 0.000 4.142
AI_INDEX_diff/Fintech_Index_diff 3.522 64.710 -15.822 17.286 -76.120 0.350 -0.003 0.008 -0.403
AI_INDEX_diff/Blockchain_Index_diff 0.145 1.356 -1.659 2.154 0.277 0.000 0.001 0.001 1.398
Blockchain_Index_diff/Fintech_Index_diff -3.450 72.603 -17.189 8.992 -126.712 0.350 0.008 0.009 0.862
Blockchain_Index_diff/AI_INDEX_diff 2.433 393.141 -3.044 5.405 -47175.052 0.000 -0.097 0.182 -0.533

Table 8: Multivariate hedging portfolios

mhp = MultivariateHedgingPortfolio(Y/100, H, statistics=statistics, method=method, digit=3)
kable(mhp$TABLE)
Mean Std.Dev. 5% 95% HE p-value Return Risk SR
Fintech_Index_diff/AI_INDEX_diff -4.015 95.488 -2.036 2.679 -6472.673 0.000 0.011 0.024 0.456
Fintech_Index_diff/Blockchain_Index_diff 0.015 0.356 -0.160 0.233 -6472.673 0.000 0.011 0.024 0.456
AI_INDEX_diff/Fintech_Index_diff 3.093 58.466 -15.276 16.505 -63.903 0.000 -0.003 0.008 -0.431
AI_INDEX_diff/Blockchain_Index_diff 0.072 0.760 -0.144 0.593 -63.903 0.000 -0.003 0.008 -0.431
Blockchain_Index_diff/Fintech_Index_diff -9.665 448.013 -19.850 13.359 -35347.965 0.000 0.088 0.157 0.562
Blockchain_Index_diff/AI_INDEX_diff 12.806 207.019 -1.457 7.665 -35347.965 0.000 0.088 0.157 0.562

Figure 3: Dynamic conditional betas

par(mfcol = c(ceiling(k/2),2), oma = c(0, 1, 0, 0) + 0.5, mar = c(1, 1, 1, 1) + 0.5, mgp = c(1, 0.4, 0))
for (j in 1:k) {
  plot(date,mhp$Beta[j,j,]*NA,type='l',las=1,xaxs='i',yaxs='i',xlab='',ylab='',
       main=paste(NAMES[j]),tck=-.02,col=j,ylim=c(-0.5,70))
  grid(NA,NULL)
  coefs = lm(Y[,j]~Y[,-j])$coefficients[-1]
  for (i in 1:k) {
    if (i!=j) {
      lines(date,mhp$Beta[j,i,],col=i)
      abline(h=0,lty=3)
      box()
    }
  }
  col = 1:k
  col = col[-j]
  abline(h=coefs,lty=3,col=col)
  legend("bottom",NAMES[-j],fill=c(1:k)[-j],bty="n",cex=0.6,ncol=k)
}

Table 9: Optimal bivariate portfolio weights

bpw = BivariatePortfolio(Y/100, H, statistics=statistics, method=method, metric=metric, digit=3)
## The optimal bivariate portfolios are computed according to:
##  Kroner, K. F., & Ng, V. K. (1998). Modeling asymmetric comovements of asset returns. The Review of Financial Studies, 11(4), 817-844.
## 
##           Hedging effectiveness is calculated according to:
##  Ederington, L. H. (1979). The hedging performance of the new futures markets. The Journal of Finance, 34(1), 157-170.
## 
##           Statistics of the hedging effectiveness measure are implemented according to:
##  Antonakakis, N., Cunado, J., Filis, G., Gabauer, D., & de Gracia, F. P. (2020). Oil and asset classes implied volatilities: Investment strategies and hedging effectiveness. Energy Economics, 91, 104762.
kable(bpw$TABLE)
Mean Std.Dev. 5% 95% HE p-value SR
Fintech_Index_diff/AI_INDEX_diff 0.708 0.341 0.000 1.000 0.350 0.000 4.412
Fintech_Index_diff/Blockchain_Index_diff 0.789 0.279 0.101 1.000 0.408 0.000 4.959
AI_INDEX_diff/Fintech_Index_diff 0.292 0.341 0.000 1.000 0.936 0.000 4.412
AI_INDEX_diff/Blockchain_Index_diff 0.536 0.386 0.000 1.000 0.640 0.000 1.295
Blockchain_Index_diff/Fintech_Index_diff 0.211 0.279 0.000 0.899 0.924 0.000 4.959
Blockchain_Index_diff/AI_INDEX_diff 0.464 0.386 0.000 1.000 0.533 0.000 1.295

Table 10: Multivariate portfolio analysis

PCIc = dca$PCI
PCIg = dca$CT
for (l in 1:dim(dca$CT)[3]) {
  for (i in 1:k) {
    for (j in 1:k) {
      PCIg[i,j,l] = (2*R[i,j,l]^2)/(1+R[i,j,l]^2)
    }
  }
}
mvp = MinimumConnectednessPortfolio(Y/100, H, statistics=statistics, method=method, metric=metric, digit=3)
## The minimum connectedness portfolio is implemented according to:
##  Broadstock, D. C., Chatziantoniou, I., & Gabauer, D. (2022). Minimum connectedness portfolios and the market for green bonds: Advocating socially responsible investment (SRI) activity. In Applications in Energy Finance (pp. 217-253). Palgrave Macmillan, Cham.
## 
##           Hedging effectiveness is calculated according to:
##  Ederington, L. H. (1979). The hedging performance of the new futures markets. The Journal of Finance, 34(1), 157-170.
## 
##           Statistics of the hedging effectiveness measure are implemented according to:
##  Antonakakis, N., Cunado, J., Filis, G., Gabauer, D., & de Gracia, F. P. (2020). Oil and asset classes implied volatilities: Investment strategies and hedging effectiveness. Energy Economics, 91, 104762.
mcp = MinimumConnectednessPortfolio(Y/100, R, statistics=statistics, method=method, metric=metric, digit=3)
## The minimum connectedness portfolio is implemented according to:
##  Broadstock, D. C., Chatziantoniou, I., & Gabauer, D. (2022). Minimum connectedness portfolios and the market for green bonds: Advocating socially responsible investment (SRI) activity. In Applications in Energy Finance (pp. 217-253). Palgrave Macmillan, Cham.
## 
##           Hedging effectiveness is calculated according to:
##  Ederington, L. H. (1979). The hedging performance of the new futures markets. The Journal of Finance, 34(1), 157-170.
## 
##           Statistics of the hedging effectiveness measure are implemented according to:
##  Antonakakis, N., Cunado, J., Filis, G., Gabauer, D., & de Gracia, F. P. (2020). Oil and asset classes implied volatilities: Investment strategies and hedging effectiveness. Energy Economics, 91, 104762.
mpc = MinimumConnectednessPortfolio(Y/100, PCIc, statistics=statistics, method=method, metric=metric, digit=3)
## The minimum connectedness portfolio is implemented according to:
##  Broadstock, D. C., Chatziantoniou, I., & Gabauer, D. (2022). Minimum connectedness portfolios and the market for green bonds: Advocating socially responsible investment (SRI) activity. In Applications in Energy Finance (pp. 217-253). Palgrave Macmillan, Cham.
## 
##           Hedging effectiveness is calculated according to:
##  Ederington, L. H. (1979). The hedging performance of the new futures markets. The Journal of Finance, 34(1), 157-170.
## 
##           Statistics of the hedging effectiveness measure are implemented according to:
##  Antonakakis, N., Cunado, J., Filis, G., Gabauer, D., & de Gracia, F. P. (2020). Oil and asset classes implied volatilities: Investment strategies and hedging effectiveness. Energy Economics, 91, 104762.
mpg = MinimumConnectednessPortfolio(Y/100, PCIg, statistics=statistics, method=method, metric=metric, digit=3)
## The minimum connectedness portfolio is implemented according to:
##  Broadstock, D. C., Chatziantoniou, I., & Gabauer, D. (2022). Minimum connectedness portfolios and the market for green bonds: Advocating socially responsible investment (SRI) activity. In Applications in Energy Finance (pp. 217-253). Palgrave Macmillan, Cham.
## 
##           Hedging effectiveness is calculated according to:
##  Ederington, L. H. (1979). The hedging performance of the new futures markets. The Journal of Finance, 34(1), 157-170.
## 
##           Statistics of the hedging effectiveness measure are implemented according to:
##  Antonakakis, N., Cunado, J., Filis, G., Gabauer, D., & de Gracia, F. P. (2020). Oil and asset classes implied volatilities: Investment strategies and hedging effectiveness. Energy Economics, 91, 104762.
mrp = MinimumConnectednessPortfolio(Y/100, dca$CT, statistics=statistics, method=method, metric=metric, digit=3)
## The minimum connectedness portfolio is implemented according to:
##  Broadstock, D. C., Chatziantoniou, I., & Gabauer, D. (2022). Minimum connectedness portfolios and the market for green bonds: Advocating socially responsible investment (SRI) activity. In Applications in Energy Finance (pp. 217-253). Palgrave Macmillan, Cham.
## 
##           Hedging effectiveness is calculated according to:
##  Ederington, L. H. (1979). The hedging performance of the new futures markets. The Journal of Finance, 34(1), 157-170.
## 
##           Statistics of the hedging effectiveness measure are implemented according to:
##  Antonakakis, N., Cunado, J., Filis, G., Gabauer, D., & de Gracia, F. P. (2020). Oil and asset classes implied volatilities: Investment strategies and hedging effectiveness. Energy Economics, 91, 104762.
MVA = rbind(mvp$TABLE, mcp$TABLE, mpc$TABLE, mpg$TABLE, mrp$TABLE)
kable(MVA)
Mean Std.Dev. 5% 95% HE p-value SR
Fintech_Index_diff 0.668 0.328 0.000 1.000 0.376 0.000 4.722
AI_INDEX_diff 0.265 0.318 0.000 1.000 0.938 0.000 4.722
Blockchain_Index_diff 0.067 0.126 0.000 0.330 0.920 0.000 4.722
Fintech_Index_diff 0.418 0.131 0.141 0.518 -1.512 0.000 2.477
AI_INDEX_diff 0.347 0.188 0.000 0.520 0.752 0.000 2.477
Blockchain_Index_diff 0.235 0.217 0.000 0.498 0.678 0.000 2.477
Fintech_Index_diff 0.271 0.098 0.148 0.475 -1.901 0.000 2.427
AI_INDEX_diff 0.277 0.100 0.032 0.401 0.713 0.000 2.427
Blockchain_Index_diff 0.452 0.030 0.436 0.492 0.628 0.000 2.427
Fintech_Index_diff 0.237 0.189 0.000 0.538 -2.503 0.000 2.483
AI_INDEX_diff 0.311 0.210 0.000 0.550 0.654 0.000 2.483
Blockchain_Index_diff 0.452 0.105 0.287 0.499 0.551 0.000 2.483
Fintech_Index_diff 0.286 0.021 0.257 0.329 -1.791 0.000 2.407
AI_INDEX_diff 0.291 0.028 0.249 0.332 0.724 0.000 2.407
Blockchain_Index_diff 0.423 0.029 0.361 0.469 0.642 0.000 2.407

Table 11: Portfolio performance

library(PerformanceAnalytics)
library(xts)
port.mat = data.frame(
                     MVP=mvp$portfolio_return,
                     MCP=mcp$portfolio_return,
                     MPC=mpc$portfolio_return,
                     MPG=mpg$portfolio_return,
                     MRP=mrp$portfolio_return
                     )
port.xts = xts(port.mat, order.by=date)

Rb <- xts(Y[,1]/100, order.by = index(Y))
colnames(Rb) <- "Benchmark"

ir <- matrix(NA, nrow = 1, ncol = ncol(port.xts))
colnames(ir) <- colnames(port.xts)
rownames(ir) <- "GRE"

for (i in 1:ncol(port.xts)) {
  ir[, i] <- InformationRatio(Ra = port.xts[, i], Rb = Rb)
}

k = ncol(port.xts)
table = matrix(NA, ncol=k, nrow=5)
for (i in 1:k) {
  table[,i] = c(
  # Retorno anualizado
  Return.annualized(port.xts[,i]),
  
  # Desviación estÔndar anualizada
  StdDev.annualized(port.xts[,i]),
  
  # Ratio de Sharpe anualizado
  SharpeRatio.annualized(port.xts[,i]),
  
  # Valor en Riesgo (VaR) con distribución normal y percentil del 95%
  VaR(as.numeric(port.xts[,i]), p=0.95, method="gaussian"),
  
  # Expectativa de Pérdida (ES) con distribución normal y percentil del 95%
  ES(as.numeric(port.xts[,i]), p=0.95, method="gaussian")
)
}
colnames(table) = colnames(port.xts)
rownames(table) = c("Return","StdDev","Sharpe Ratio (StdDev)","Sharpe Ratio (VaR)","Sharpe Ratio (CVaR)")
kable(rbind(table, ir))
MVP MCP MPC MPG MRP
Return 0.0011168 0.0011754 0.0012379 0.0013915 0.0012041
StdDev 0.0002365 0.0004746 0.0005100 0.0005605 0.0005003
Sharpe Ratio (StdDev) 4.7215607 2.4767543 2.4269769 2.4828300 2.4068835
Sharpe Ratio (VaR) -0.0000236 -0.0000497 -0.0000513 -0.0000555 -0.0000495
Sharpe Ratio (CVaR) -0.0000026 -0.0000015 -0.0000016 -0.0000016 -0.0000016
GRE 1.6028835 1.0169457 1.0795859 1.2355510 1.0451553

Henriques(2025): Connectedness and systemic risk between FinTech and traditional financial stocks: Implications for portfolio diversification

pkgs <- c("readr","zoo","xts","ConnectednessApproach","PerformanceAnalytics",
          "riskParityPortfolio","quadprog","rugarch","rmgarch","tseries",
          "urca","FinTS","robustbase","corrplot","matrixStats","psych","vars")

install_if_missing <- function(p) if (!requireNamespace(p, quietly = TRUE)) install.packages(p)
invisible(lapply(pkgs, install_if_missing))
library(readr); library(zoo); library(xts); library(ConnectednessApproach)
library(PerformanceAnalytics); library(riskParityPortfolio); library(quadprog)
## Warning: package 'riskParityPortfolio' was built under R version 4.5.1
library(corrplot); library(vars)
## corrplot 0.95 loaded
# --- 1) Cargar datos --------------------------------------------------------
data_path <- "C:/Users/AVRIL/Desktop/Spillovers/all_daily_index_returns.csv"
index_alt <- read_csv(data_path, show_col_types = FALSE)
## New names:
## • `Cumulative return` -> `Cumulative return...3`
## • `Cumulative return` -> `Cumulative return...5`
## • `Cumulative return` -> `Cumulative return...7`
if(!("Date" %in% colnames(index_alt))) stop("No se encontró la columna 'Date'.")
index_alt$Date <- as.Date(index_alt$Date, format = "%d/%m/%Y")
if(any(is.na(index_alt$Date))) index_alt$Date <- as.Date(index_alt$Date, format = "%Y-%m-%d")

data_selected <- index_alt[, c("Date", "AI_INDEX", "Fintech_Index", "Blockchain_Index")]
colnames(data_selected) <- c("Date","AI_INDEX","Fintech","Blockchain")
data_selected <- data_selected[!is.na(data_selected$Date), ]

Detectar si los valores son precios o retornos y preparar series

# HeurĆ­stica: si hay valores mayores que 1.5 -> tratamos como precios, sino como retornos
is_price_like <- function(x) median(abs(x), na.rm=TRUE) > 1.5
mat <- as.data.frame(data_selected[, -1])

if(any(sapply(mat, is_price_like))) {
  message("Detectado dato tipo precios -> calculando retornos logarĆ­tmicos.")
  prices_xts <- xts(mat, order.by = data_selected$Date)
  y.r <- na.omit(diff(log(prices_xts)))
} else {
  message("Detectado dato tipo retornos -> usaremos directamente los retornos.")
  y.r <- xts(mat, order.by = data_selected$Date)
  if(all(abs(coredata(y.r)) > 1)) {
    message("Retornos parecen en porcentaje. Se convierten a decimales (/100).")
    y.r <- y.r / 100
  }
  y.r <- na.omit(y.r)
}
## Detectado dato tipo retornos -> usaremos directamente los retornos.
symbols <- colnames(y.r)
cat("Series preparadas:", paste(symbols, collapse=", "), " (n=", nrow(y.r), ")\n")
## Series preparadas: AI_INDEX, Fintech, Blockchain  (n= 2051 )
p1 <-plot.xts(y.r, auto.legend = TRUE, main="",legend.loc = "topleft")
p1

EstadĆ­sticos y correlaciones

cat("\n--- EstadĆ­sticos descriptivos ---\n")
## 
## --- EstadĆ­sticos descriptivos ---
sum_stats <- data.frame(t(psych::describe(as.data.frame(100 * y.r))))
print(sum_stats)
##               AI_INDEX       Fintech    Blockchain
## vars        1.00000000  2.000000e+00    3.00000000
## n        2051.00000000  2.051000e+03 2051.00000000
## mean        0.07284978  2.514532e-02    0.04414805
## sd          0.59977731  1.886246e-01    0.52699084
## median      0.10240790  2.999540e-02    0.07566070
## trimmed     0.09878005  2.391826e-02    0.06405141
## mad         0.57087483  1.879322e-01    0.42218102
## min        -1.80390090 -6.887190e-01   -2.42599600
## max         1.65334260  5.406403e-01    2.09105040
## range       3.45724350  1.229359e+00    4.51704640
## skew       -0.36735670 -6.210568e-02   -0.43948156
## kurtosis    0.02863654  4.284896e-01    2.17410101
## se          0.01324363  4.165005e-03    0.01163644
cat("\n--- Matriz de correlaciones ---\n")
## 
## --- Matriz de correlaciones ---
cor_mat <- cor(y.r, use="complete.obs")
print(round(cor_mat,3))
##            AI_INDEX Fintech Blockchain
## AI_INDEX      1.000  -0.088       0.26
## Fintech      -0.088   1.000       0.03
## Blockchain    0.260   0.030       1.00
corrplot(cor_mat, type="upper", order="hclust", tl.col="black", tl.srt=45)

vars::VARselect(y.r)
## $selection
## AIC(n)  HQ(n)  SC(n) FPE(n) 
##      8      8      8      8 
## 
## $criteria
##                    1             2             3             4             5
## AIC(n) -3.733363e+01 -3.734514e+01 -3.736101e+01 -3.738291e+01 -3.741355e+01
## HQ(n)  -3.732150e+01 -3.732393e+01 -3.733071e+01 -3.734352e+01 -3.736506e+01
## SC(n)  -3.730058e+01 -3.728731e+01 -3.727839e+01 -3.727550e+01 -3.728135e+01
## FPE(n)  6.112400e-17  6.042404e-17  5.947280e-17  5.818446e-17  5.642912e-17
##                    6             7             8             9            10
## AIC(n) -3.745772e+01 -3.752502e+01 -3.830092e+01 -3.829888e+01 -3.829762e+01
## HQ(n)  -3.740014e+01 -3.745834e+01 -3.822515e+01 -3.821402e+01 -3.820367e+01
## SC(n)  -3.730073e+01 -3.734325e+01 -3.809435e+01 -3.806754e+01 -3.804149e+01
## FPE(n)  5.399074e-17  5.047683e-17  2.323408e-17  2.328139e-17  2.331083e-17
# standard dy approach
dca = ConnectednessApproach(y.r,
                            nlag=1,
                            nfore=20,
                            window.size=200)
## Estimating model
## Computing connectedness measures
## The (generalized) VAR connectedness approach is implemented according to:
##  Diebold, F. X., & Yilmaz, K. (2012). Better to give than to receive: Predictive directional measurement of volatility spillovers. International Journal of Forecasting.
(dca$TABLE)
##            AI_INDEX Fintech  Blockchain FROM         
## AI_INDEX   "84.13"  " 5.16"  "10.71"    "15.87"      
## Fintech    " 4.46"  "92.53"  " 3.02"    " 7.47"      
## Blockchain "12.66"  " 4.00"  "83.33"    "16.67"      
## TO         "17.12"  " 9.17"  "13.72"    "40.01"      
## Inc.Own    "101.25" "101.69" " 97.06"   "cTCI/TCI"   
## NET        " 1.25"  " 1.69"  "-2.94"    "20.00/13.34"
## NPT        "1.00"   "2.00"   "0.00"     ""
PlotTCI(dca, ylim=c(0,100))

# tvp-var
dca = ConnectednessApproach(y.r,
                            nlag=1,
                            nfore=20,
                            #window.size=200,
                            corrected = FALSE,
                            model="TVP-VAR")
## Estimating model
## Computing connectedness measures
## The TVP-VAR connectedness approach is implemented according to:
##  Antonakakis, N., Chatziantoniou, I., & Gabauer, D. (2020). Refined measures of dynamic connectedness based on time-varying parameter vector autoregressions. Journal of Risk and Financial Management.
(dca$TABLE)
##            AI_INDEX Fintech  Blockchain FROM         
## AI_INDEX   "84.66"  " 4.79"  "10.55"    "15.34"      
## Fintech    " 4.24"  "92.18"  " 3.58"    " 7.82"      
## Blockchain "12.72"  " 3.43"  "83.85"    "16.15"      
## TO         "16.96"  " 8.22"  "14.13"    "39.32"      
## Inc.Own    "101.62" "100.40" " 97.98"   "cTCI/TCI"   
## NET        " 1.62"  " 0.40"  "-2.02"    "19.66/13.11"
## NPT        "1.00"   "1.00"   "1.00"     ""
PlotTCI(dca, ylim=c(0,100))

str(dca)
## List of 11
##  $ TABLE    : chr [1:7, 1:4] "84.66" " 4.24" "12.72" "16.96" ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:7] "AI_INDEX" "Fintech" "Blockchain" "TO" ...
##   .. ..$ : chr [1:4] "AI_INDEX" "Fintech" "Blockchain" "FROM"
##  $ CT       : num [1:3, 1:3, 1:2051] 0.9723 0.0115 0.0944 0.0201 0.986 ...
##   ..- attr(*, "dimnames")=List of 3
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##  $ TCI      : num [1:2051, 1] 4.6 15.6 15.8 15.7 15.6 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##   .. ..$ : chr "TCI"
##  $ TO       : num [1:2051, 1:3] 10.6 35.5 35.8 35.5 34.7 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##  $ FROM     : num [1:2051, 1:3] 2.77 10.35 10.51 10.69 10.97 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##  $ NET      : num [1:2051, 1:3] 7.82 25.2 25.3 24.82 23.73 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##  $ NPT      : num [1:2051, 1:3] 1 2 2 2 2 2 2 2 1 1 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##  $ NPDC     : num [1:3, 1:3, 1:2051] 0 -0.854 8.673 0.854 0 ...
##   ..- attr(*, "dimnames")=List of 3
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##  $ PCI      : num [1:3, 1:3, 1:2051] 100 3.17 10.32 3.17 100 ...
##   ..- attr(*, "dimnames")=List of 3
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##  $ INFLUENCE: num [1:3, 1:3, 1:2051] 0 27 85 27 0 ...
##   ..- attr(*, "dimnames")=List of 3
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:3] "AI_INDEX" "Fintech" "Blockchain"
##   .. ..$ : chr [1:2051] "2019-01-08" "2019-01-09" "2019-01-10" "2019-01-11" ...
##  $ config   :List of 4
##   ..$ nfore      : num 20
##   ..$ approach   : chr "Time"
##   ..$ generalized: logi TRUE
##   ..$ corrected  : logi FALSE
(dca$TABLE)
##            AI_INDEX Fintech  Blockchain FROM         
## AI_INDEX   "84.66"  " 4.79"  "10.55"    "15.34"      
## Fintech    " 4.24"  "92.18"  " 3.58"    " 7.82"      
## Blockchain "12.72"  " 3.43"  "83.85"    "16.15"      
## TO         "16.96"  " 8.22"  "14.13"    "39.32"      
## Inc.Own    "101.62" "100.40" " 97.98"   "cTCI/TCI"   
## NET        " 1.62"  " 0.40"  "-2.02"    "19.66/13.11"
## NPT        "1.00"   "1.00"   "1.00"     ""
gfevd = dca$CT
dim(gfevd)
## [1]    3    3 2051
(ConnectednessTable(gfevd))
## $FEVD
##             AI_INDEX   Fintech Blockchain
## AI_INDEX   84.656676  4.789393  10.553931
## Fintech     4.240865 92.179328   3.579807
## Blockchain 12.724088  3.428141  83.847771
## 
## $TCI
## [1] 13.10541
## 
## $cTCI
## [1] 19.65811
## 
## $PCI
##            [,1]       [,2]       [,3]
## [1,] 100.000000   9.716942  24.275440
## [2,]   9.716942 100.000000   7.657494
## [3,]  24.275440   7.657494 100.000000
## 
## $TO
##   AI_INDEX    Fintech Blockchain 
##  16.964953   8.217535  14.133738 
## 
## $FROM
##   AI_INDEX    Fintech Blockchain 
##  15.343324   7.820672  16.152229 
## 
## $NET
##   AI_INDEX    Fintech Blockchain 
##  1.6216283  0.3968625 -2.0184907 
## 
## $NPDC
##              AI_INDEX    Fintech Blockchain
## AI_INDEX    0.0000000  0.5485286 -2.1701569
## Fintech    -0.5485286  0.0000000  0.1516661
## Blockchain  2.1701569 -0.1516661  0.0000000
## 
## $TABLE
##            AI_INDEX Fintech  Blockchain FROM         
## AI_INDEX   "84.66"  " 4.79"  "10.55"    "15.34"      
## Fintech    " 4.24"  "92.18"  " 3.58"    " 7.82"      
## Blockchain "12.72"  " 3.43"  "83.85"    "16.15"      
## TO         "16.96"  " 8.22"  "14.13"    "39.32"      
## Inc.Own    "101.62" "100.40" " 97.98"   "cTCI/TCI"   
## NET        " 1.62"  " 0.40"  "-2.02"    "19.66/13.11"
## NPT        "1.00"   "1.00"   "1.00"     ""           
## 
## $NPT
##   AI_INDEX    Fintech Blockchain 
##          1          1          1 
## 
## $INFLUENCE
##            AI_INDEX  Fintech Blockchain
## AI_INDEX   0.000000 6.074340   9.322773
## Fintech    6.074340 0.000000   2.164201
## Blockchain 9.322773 2.164201   0.000000
(ConnectednessTable(gfevd)$PCI)
##            [,1]       [,2]       [,3]
## [1,] 100.000000   9.716942  24.275440
## [2,]   9.716942 100.000000   7.657494
## [3,]  24.275440   7.657494 100.000000
# png("plots/plot_tci.png",  width = 600, height = 480 , pointsize=14)
PlotTCI(dca, ylim=c(0,100))
View (dca$TCI)
max(dca$TCI)
## [1] 32.41053
min(dca$TCI)
## [1] 2.462622
mean(dca$TCI)
## [1] 13.10541
PlotTO(dca, ylim=c(0,100))

PlotFROM(dca, ylim=c(0,100))

PlotNET(dca, ylim=c(-20,20))

PlotNPDC(dca, ylim=c(-15,15))

PlotNetwork(dca)

# portfolio weights
mcp = MinimumConnectednessPortfolio(as.zoo(y.r), dca$PCI, statistics="Fisher")
mcp$TABLE
##            Mean    Std.Dev. 5%      95%     HE      p-value SR     
## AI_INDEX   " 0.31" " 0.03"  " 0.27" " 0.36" " 0.78" " 0.00" " 2.67"
## Fintech    " 0.37" " 0.04"  " 0.31" " 0.46" "-1.20" " 0.00" " 2.67"
## Blockchain " 0.32" " 0.03"  " 0.26" " 0.38" " 0.72" " 0.00" " 2.67"
w.mcp <- mcp$portfolio_weights 
apply(w.mcp,2, mean)
##   AI_INDEX    Fintech Blockchain 
##  0.3127304  0.3663442  0.3209254
rpp = RiskParityPortfolio(as.zoo(y.r), dca$PCI, statistics="Fisher")
rpp$TABLE
##            Mean    Std.Dev. 5%      95%     HE      p-value SR     
## AI_INDEX   " 0.32" " 0.01"  " 0.30" " 0.34" " 0.76" " 0.00" " 2.63"
## Fintech    " 0.35" " 0.02"  " 0.32" " 0.39" "-1.40" " 0.00" " 2.63"
## Blockchain " 0.33" " 0.01"  " 0.30" " 0.35" " 0.69" " 0.00" " 2.63"
w.rpp <- rpp$portfolio_weights 
apply(w.rpp,2, mean)
##   AI_INDEX    Fintech Blockchain 
##  0.3244395  0.3480463  0.3275142
head(w.rpp)
##       AI_INDEX   Fintech Blockchain
## [1,] 0.3265071 0.3423964  0.3310965
## [2,] 0.3097279 0.3328982  0.3573739
## [3,] 0.3095399 0.3329365  0.3575236
## [4,] 0.3096072 0.3330941  0.3572987
## [5,] 0.3099208 0.3333798  0.3566995
## [6,] 0.3105212 0.3337755  0.3557033
tail(w.rpp)
##          AI_INDEX   Fintech Blockchain
## [2046,] 0.3346011 0.3464380  0.3189609
## [2047,] 0.3348527 0.3459465  0.3192008
## [2048,] 0.3350871 0.3454904  0.3194226
## [2049,] 0.3353060 0.3450661  0.3196278
## [2050,] 0.3355112 0.3446707  0.3198181
## [2051,] 0.3357040 0.3443012  0.3199947
dim(w.rpp)
## [1] 2051    3
dim(y.r)
## [1] 2051    3
dim(w.mcp)
## [1] 2051    3
head (w.rpp*y.r)
##               AI_INDEX       Fintech   Blockchain
## 2019-01-08 0.002825686 -0.0002310878 0.0006773096
## 2019-01-09 0.002657475 -0.0002248291 0.0007295717
## 2019-01-10 0.002633269 -0.0002250068 0.0007283904
## 2019-01-11 0.002611624 -0.0002252656 0.0007264518
## 2019-01-12 0.002592402 -0.0002256114 0.0007237621
## 2019-01-13 0.002575878 -0.0002260321 0.0007202793
w.rpp[1,1] * y.r[1,1]
##               AI_INDEX
## 2019-01-08 0.002825686
w.mcp_temp <-  cbind(y.r[,1], w.mcp)
head(w.mcp_temp)
##               AI_INDEX AI_INDEX.1   Fintech Blockchain
## 2019-01-08 0.008654286  0.3186217 0.3521304  0.3292479
## 2019-01-09 0.008580032  0.2657578 0.3436517  0.3905905
## 2019-01-10 0.008507041  0.2649176 0.3439984  0.3910839
## 2019-01-11 0.008435282  0.2650959 0.3442598  0.3906443
## 2019-01-12 0.008364723  0.2662147 0.3444827  0.3893026
## 2019-01-13 0.008295335  0.2683736 0.3446199  0.3870065
w.mcp_temp <- w.mcp_temp[,-1]
head(w.mcp_temp)
##            AI_INDEX.1   Fintech Blockchain
## 2019-01-08  0.3186217 0.3521304  0.3292479
## 2019-01-09  0.2657578 0.3436517  0.3905905
## 2019-01-10  0.2649176 0.3439984  0.3910839
## 2019-01-11  0.2650959 0.3442598  0.3906443
## 2019-01-12  0.2662147 0.3444827  0.3893026
## 2019-01-13  0.2683736 0.3446199  0.3870065
w.rpp_temp <-  cbind(y.r[,1], w.rpp)
head(w.rpp_temp)
##               AI_INDEX AI_INDEX.1   Fintech Blockchain
## 2019-01-08 0.008654286  0.3265071 0.3423964  0.3310965
## 2019-01-09 0.008580032  0.3097279 0.3328982  0.3573739
## 2019-01-10 0.008507041  0.3095399 0.3329365  0.3575236
## 2019-01-11 0.008435282  0.3096072 0.3330941  0.3572987
## 2019-01-12 0.008364723  0.3099208 0.3333798  0.3566995
## 2019-01-13 0.008295335  0.3105212 0.3337755  0.3557033
w.rpp_temp <- w.rpp_temp[,-1]
head(w.rpp_temp)
##            AI_INDEX.1   Fintech Blockchain
## 2019-01-08  0.3265071 0.3423964  0.3310965
## 2019-01-09  0.3097279 0.3328982  0.3573739
## 2019-01-10  0.3095399 0.3329365  0.3575236
## 2019-01-11  0.3096072 0.3330941  0.3572987
## 2019-01-12  0.3099208 0.3333798  0.3566995
## 2019-01-13  0.3105212 0.3337755  0.3557033
################################################################
# portfolios
################################################################

# choice of portfolios; mcp, rpp, ew, rp
# https://cran.r-project.org/web/packages/riskParityPortfolio/vignettes/RiskParityPortfolio.html#a-pratical-example-using-faang-price-data
# for backtesting
# https://cran.r-project.org/web/packages/portfolioBacktest/vignettes/PortfolioBacktest.html#defining-portfolios

y.r_c <- exp(y.r)-1

w.eq <- rep(1/ncol(y.r_c), ncol(y.r_c))
w.rp <- riskParityPortfolio(cov(y.r_c))$w

# https://bookdown.org/compfinezbook/introcompfinr/Efficient-portfolios-of.html
max_sharpe_ratio <- function(dataset) {
  prices <- dataset
  
  # 1. Eliminar columnas o filas con NAs
  prices <- na.omit(prices)
  if (nrow(prices) < 2) return(rep(NA, ncol(prices)))
  
  # 2. Calcular retornos logarĆ­tmicos de forma segura
  log_returns <- suppressWarnings(diff(log(prices)))
  log_returns <- na.omit(exp(log_returns) - 1)
  
  if (nrow(log_returns) < 2) return(rep(NA, ncol(prices)))
  
  # 3. Estadƭsticos bƔsicos
  Sigma <- cov(log_returns, use = "pairwise.complete.obs")
  mu <- colMeans(log_returns, na.rm = TRUE)
  
  # 4. Validación de inputs
  if (any(is.na(mu)) || any(is.na(Sigma))) return(rep(NA, ncol(prices)))
  if (all(mu <= 1e-8, na.rm = TRUE)) return(rep(0, ncol(prices)))
  
  # 5. Optimización clÔsica de portafolio mÔximo Sharpe
  Dmat <- 2 * Sigma
  Amat <- cbind(mu, diag(ncol(prices)))
  bvec <- c(1, rep(0, ncol(prices)))
  dvec <- rep(0, ncol(prices))
  
  res <- try(solve.QP(Dmat = Dmat, dvec = dvec, Amat = Amat, bvec = bvec, meq = 1), silent = TRUE)
  
  if (inherits(res, "try-error")) {
    return(rep(NA, ncol(prices)))
  } else {
    w <- res$solution
    return(w / sum(w))
  }
}



# rolling portfolio weights
wl <- 252
roll_rp =  na.omit (rollapply(y.r_c, wl ,function(x) riskParityPortfolio(cov(x))$w, by.column=FALSE,align="right"))
head(roll_rp)
##             AI_INDEX   Fintech Blockchain
## 2019-09-16 0.2297251 0.5320311  0.2382438
## 2019-09-17 0.2307445 0.5310811  0.2381744
## 2019-09-18 0.2317617 0.5301275  0.2381108
## 2019-09-19 0.2327769 0.5291704  0.2380527
## 2019-09-20 0.2337901 0.5282097  0.2380002
## 2019-09-21 0.2348015 0.5272453  0.2379531
tail(roll_rp)
##             AI_INDEX   Fintech Blockchain
## 2024-08-14 0.1987962 0.5399731  0.2612307
## 2024-08-15 0.1992887 0.5411880  0.2595233
## 2024-08-16 0.1997582 0.5423454  0.2578964
## 2024-08-17 0.2002060 0.5434493  0.2563446
## 2024-08-18 0.2006332 0.5445035  0.2548632
## 2024-08-19 0.2010408 0.5455113  0.2534479
roll_ms =  na.omit (rollapply(y.r_c, wl ,function(x) max_sharpe_ratio(x), by.column=FALSE,align="right"))
colnames(roll_ms) <- colnames(roll_rp)
head(roll_ms)
##            AI_INDEX Fintech    Blockchain
## 2019-09-16        0       1 -1.179115e-13
## 2019-09-17        0       1 -1.179115e-13
## 2019-09-18        0       1 -1.179115e-13
## 2019-09-19        0       1 -1.179115e-13
## 2019-09-20        0       1 -1.179115e-13
## 2019-09-21        0       1 -1.179115e-13
tail(roll_ms)
##            AI_INDEX Fintech Blockchain
## 2024-08-14        0       0          0
## 2024-08-15        0       0          0
## 2024-08-16        0       0          0
## 2024-08-17        0       0          0
## 2024-08-18        0       0          0
## 2024-08-19        0       0          0
###########################3

# port_eqw  <- Return.portfolio(y.r, weights=w.eq ,   verbose=TRUE, geometric = FALSE)
port_eqw  <- Return.portfolio( y.r_c,   verbose=TRUE,  rebalance_on = "days")
head (port_eqw$BOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-08 0.3333333 0.3333333  0.3333333
## 2019-01-09 0.3333333 0.3333333  0.3333333
## 2019-01-10 0.3333333 0.3333333  0.3333333
## 2019-01-11 0.3333333 0.3333333  0.3333333
## 2019-01-12 0.3333333 0.3333333  0.3333333
## 2019-01-13 0.3333333 0.3333333  0.3333333
## 2019-01-14 0.3333333 0.3333333  0.3333333
## 2019-01-15 0.3333333 0.3333333  0.3333333
## 2019-01-16 0.3333333 0.3333333  0.3333333
## 2019-01-17 0.3333333 0.3333333  0.3333333
## 2019-01-18 0.3333333 0.3333333  0.3333333
## 2019-01-19 0.3333333 0.3333333  0.3333333
## 2019-01-20 0.3333333 0.3333333  0.3333333
## 2019-01-21 0.3333333 0.3333333  0.3333333
## 2019-01-22 0.3333333 0.3333333  0.3333333
## 2019-01-23 0.3333333 0.3333333  0.3333333
## 2019-01-24 0.3333333 0.3333333  0.3333333
## 2019-01-25 0.3333333 0.3333333  0.3333333
## 2019-01-26 0.3333333 0.3333333  0.3333333
## 2019-01-27 0.3333333 0.3333333  0.3333333
## 2019-01-28 0.3333333 0.3333333  0.3333333
## 2019-01-29 0.3333333 0.3333333  0.3333333
head (port_eqw$EOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-08 0.3351063 0.3319946  0.3328991
## 2019-01-09 0.3350903 0.3320032  0.3329065
## 2019-01-10 0.3350746 0.3320117  0.3329137
## 2019-01-11 0.3350591 0.3320200  0.3329209
## 2019-01-12 0.3350439 0.3320283  0.3329279
## 2019-01-13 0.3350289 0.3320363  0.3329347
## 2019-01-14 0.3350142 0.3320443  0.3329415
## 2019-01-15 0.3336926 0.3320248  0.3342827
## 2019-01-16 0.3336931 0.3320291  0.3342778
## 2019-01-17 0.3336935 0.3320334  0.3342730
## 2019-01-18 0.3336940 0.3320377  0.3342683
## 2019-01-19 0.3336945 0.3320419  0.3342637
## 2019-01-20 0.3336949 0.3320460  0.3342590
## 2019-01-21 0.3336954 0.3320501  0.3342545
## 2019-01-22 0.3343278 0.3326513  0.3330208
## 2019-01-23 0.3343218 0.3326547  0.3330235
## 2019-01-24 0.3343158 0.3326580  0.3330262
## 2019-01-25 0.3343098 0.3326613  0.3330289
## 2019-01-26 0.3343040 0.3326645  0.3330315
## 2019-01-27 0.3342982 0.3326677  0.3330341
## 2019-01-28 0.3342924 0.3326709  0.3330366
## 2019-01-29 0.3344755 0.3329409  0.3325836
# port_rp   <- Return.portfolio(y.r, weights=w.rp,verbose=TRUE)
port_rp   <- Return.portfolio( y.r_c, weights=roll_rp,   verbose=TRUE)
port_mcp  <- Return.portfolio( y.r_c, weights=w.mcp_temp,verbose=TRUE)
port_rpp  <- Return.portfolio( y.r_c, weights=w.rpp_temp,verbose=TRUE)
port_ms   <- Return.portfolio( y.r_c, weights=roll_ms,   verbose=TRUE)
## Warning in Return.portfolio.geometric(R = R, weights = weights, wealth.index =
## wealth.index, : The weights for one or more periods do not sum up to 1:
## assuming a return of 0 for the residual weights
str(port_eqw)
## List of 6
##  $ returns     :An xts object on 2019-01-08 / 2024-08-19 containing: 
##   Data:    double [2051, 1]
##   Columns: portfolio.returns
##   Index:   Date [2051] (TZ: "UTC")
##  $ contribution:An xts object on 2019-01-08 / 2024-08-19 containing: 
##   Data:    double [2051, 3]
##   Columns: AI_INDEX, Fintech, Blockchain
##   Index:   Date [2051] (TZ: "UTC")
##  $ BOP.Weight  :An xts object on 2019-01-08 / 2024-08-19 containing: 
##   Data:    double [2051, 3]
##   Columns: AI_INDEX, Fintech, Blockchain
##   Index:   Date [2051] (TZ: "UTC")
##  $ EOP.Weight  :An xts object on 2019-01-08 / 2024-08-19 containing: 
##   Data:    double [2051, 3]
##   Columns: AI_INDEX, Fintech, Blockchain
##   Index:   Date [2051] (TZ: "UTC")
##  $ BOP.Value   :An xts object on 2019-01-08 / 2024-08-19 containing: 
##   Data:    double [2051, 3]
##   Columns: AI_INDEX, Fintech, Blockchain
##   Index:   Date [2051] (TZ: "UTC")
##  $ EOP.Value   :An xts object on 2019-01-08 / 2024-08-19 containing: 
##   Data:    double [2051, 3]
##   Columns: AI_INDEX, Fintech, Blockchain
##   Index:   Date [2051] (TZ: "UTC")
################################################################
# some checks on the eqw
head(port_eqw$returns)
##            portfolio.returns
## 2019-01-08       0.003354969
## 2019-01-09       0.003328457
## 2019-01-10       0.003302377
## 2019-01-11       0.003276717
## 2019-01-12       0.003251469
## 2019-01-13       0.003226621
w.eq *y.r[1:5,]
##               AI_INDEX       Fintech   Blockchain
## 2019-01-08 0.002884762 -0.0002249710 0.0006818853
## 2019-01-09 0.002860011 -0.0002251230 0.0006804933
## 2019-01-10 0.002835680 -0.0002252750 0.0006791070
## 2019-01-11 0.002811761 -0.0002254273 0.0006777260
## 2019-01-12 0.002788241 -0.0002255800 0.0006763510
apply(w.eq *y.r[1:5,],1, sum)
##  2019-01-08  2019-01-09  2019-01-10  2019-01-11  2019-01-12 
## 0.003341676 0.003315381 0.003289512 0.003264059 0.003239012
head(port_rp$returns)
##            portfolio.returns
## 2019-09-17      0.0007909495
## 2019-09-18      0.0007901827
## 2019-09-19      0.0007893914
## 2019-09-20      0.0007885755
## 2019-09-21      0.0007877354
## 2019-09-22      0.0007868719
tail(port_rp$returns)
##            portfolio.returns
## 2024-08-14       0.003434350
## 2024-08-15       0.003391413
## 2024-08-16       0.003350085
## 2024-08-17       0.003310266
## 2024-08-18       0.003271866
## 2024-08-19       0.003234802
table.AnnualizedReturns(apply(w.eq *y.r_c["2017-09-14/"],1,sum), scale=252, Rf=(.01/252))
##                                 
## Annualized Return         0.1287
## Annualized Std Dev        0.0480
## Annualized Sharpe (Rf=1%) 2.4488
# in sample eqw
summary(y.r_c["2017-09-14/"])
##      Index               AI_INDEX             Fintech          
##  Min.   :2019-01-08   Min.   :-0.0178773   Min.   :-0.0068635  
##  1st Qu.:2020-06-03   1st Qu.:-0.0026554   1st Qu.:-0.0009805  
##  Median :2021-10-29   Median : 0.0010246   Median : 0.0003000  
##  Mean   :2021-10-29   Mean   : 0.0007467   Mean   : 0.0002533  
##  3rd Qu.:2023-03-25   3rd Qu.: 0.0050139   3rd Qu.: 0.0015312  
##  Max.   :2024-08-19   Max.   : 0.0166709   Max.   : 0.0054210  
##    Blockchain        
##  Min.   :-0.0239681  
##  1st Qu.:-0.0020937  
##  Median : 0.0007569  
##  Mean   : 0.0004555  
##  3rd Qu.: 0.0035907  
##  Max.   : 0.0211307
    w.eq *apply(y.r_c["2017-09-14/"], 2, mean)
##     AI_INDEX      Fintech   Blockchain 
## 2.489137e-04 8.442111e-05 1.518176e-04
sum(w.eq *apply(y.r_c["2017-09-14/"], 2, mean))*252
## [1] 0.1222584
# 0.06297518
################################################################


port_ret <- cbind(port_eqw$returns, port_rp$returns, port_rpp$returns, port_ms$returns )
colnames(port_ret) <- c("EQW", "RP", "RPC", "MS")
# all portfolios start at same time period
port_ret <- na.omit( port_ret)
head(port_ret)
##                     EQW           RP          RPC           MS
## 2019-09-17 0.0008288824 0.0007909495 0.0008167320 0.0007733999
## 2019-09-18 0.0008239991 0.0007901827 0.0008228203 0.0007728015
## 2019-09-19 0.0008191387 0.0007893914 0.0008180661 0.0007722050
## 2019-09-20 0.0008143003 0.0007885755 0.0008133313 0.0007716095
## 2019-09-21 0.0008094841 0.0007877354 0.0008086159 0.0007710141
## 2019-09-22 0.0008046894 0.0007868719 0.0008039194 0.0007704206
# portfolio summary statistics
# puedes fijar una fecha o usar el inicio automƔtico de tus datos
start_date <- start(y.r_c)  
cat("Fecha inicial de los datos:", start_date, "\n")
## Fecha inicial de los datos: 17904
# Filtrar desde start_date
roll_rp_sub  <- roll_rp[paste0(start_date, "/")]
roll_ms_sub  <- roll_ms[paste0(start_date, "/")]
w_rpp_sub    <- w.rpp_temp[paste0(start_date, "/")]

# promedios de pesos
aw1 <- apply(roll_rp_sub, 2, mean, na.rm = TRUE)
aw2 <- apply(roll_ms_sub, 2, mean, na.rm = TRUE)
aw3 <- apply(w_rpp_sub,   2, mean, na.rm = TRUE)

# estadĆ­sticas resumen
summary(roll_rp_sub)
##      Index               AI_INDEX         Fintech         Blockchain    
##  Min.   :2019-09-16   Min.   :0.1271   Min.   :0.4993   Min.   :0.1290  
##  1st Qu.:2020-12-08   1st Qu.:0.1421   1st Qu.:0.5492   1st Qu.:0.1492  
##  Median :2022-03-03   Median :0.1848   Median :0.5963   Median :0.2121  
##  Mean   :2022-03-03   Mean   :0.1829   Mean   :0.6190   Mean   :0.1981  
##  3rd Qu.:2023-05-27   3rd Qu.:0.2182   3rd Qu.:0.7092   3rd Qu.:0.2312  
##  Max.   :2024-08-19   Max.   :0.2663   Max.   :0.7410   Max.   :0.2943
summary(roll_ms_sub)
##      Index               AI_INDEX         Fintech         Blockchain    
##  Min.   :2019-09-16   Min.   :0.0000   Min.   :0.0000   Min.   :0.0000  
##  1st Qu.:2020-12-08   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.0000  
##  Median :2022-03-03   Median :0.0000   Median :0.0000   Median :0.0000  
##  Mean   :2022-03-03   Mean   :0.1067   Mean   :0.2150   Mean   :0.2255  
##  3rd Qu.:2023-05-27   3rd Qu.:0.0000   3rd Qu.:0.5079   3rd Qu.:0.4800  
##  Max.   :2024-08-19   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000
summary(w_rpp_sub)
##      Index              AI_INDEX.1        Fintech         Blockchain    
##  Min.   :2019-01-08   Min.   :0.3017   Min.   :0.3102   Min.   :0.2995  
##  1st Qu.:2020-06-03   1st Qu.:0.3153   1st Qu.:0.3358   1st Qu.:0.3203  
##  Median :2021-10-29   Median :0.3263   Median :0.3437   Median :0.3280  
##  Mean   :2021-10-29   Mean   :0.3244   Mean   :0.3480   Mean   :0.3275  
##  3rd Qu.:2023-03-25   3rd Qu.:0.3316   3rd Qu.:0.3531   3rd Qu.:0.3330  
##  Max.   :2024-08-19   Max.   :0.3702   Max.   :0.3987   Max.   :0.3654
# grƔficas de pesos
plot(roll_rp_sub, main = "Pesos Rolling Risk Parity (RP)", auto.legend = TRUE, legend.loc = "topleft")

plot(roll_ms_sub, main = "Pesos Rolling Max Sharpe (MS)", auto.legend = TRUE, legend.loc = "topleft")

plot(w_rpp_sub,   main = "Pesos Rolling Risk Parity Connectedness (RPC)", auto.legend = TRUE, legend.loc = "topleft")

# medidas agregadas: media, sd, cv, min, max
aw1_2 <- rbind(
  Mean = apply(roll_rp_sub, 2, mean, na.rm = TRUE),
  SD   = apply(roll_rp_sub, 2, sd, na.rm = TRUE),
  CV   = apply(roll_rp_sub, 2, sd, na.rm = TRUE) / apply(roll_rp_sub, 2, mean, na.rm = TRUE),
  Min  = apply(roll_rp_sub, 2, min, na.rm = TRUE),
  Max  = apply(roll_rp_sub, 2, max, na.rm = TRUE)
)

aw2_2 <- rbind(
  Mean = apply(roll_ms_sub, 2, mean, na.rm = TRUE),
  SD   = apply(roll_ms_sub, 2, sd, na.rm = TRUE),
  CV   = apply(roll_ms_sub, 2, sd, na.rm = TRUE) / apply(roll_ms_sub, 2, mean, na.rm = TRUE),
  Min  = apply(roll_ms_sub, 2, min, na.rm = TRUE),
  Max  = apply(roll_ms_sub, 2, max, na.rm = TRUE)
)

aw3_2 <- rbind(
  Mean = apply(w_rpp_sub, 2, mean, na.rm = TRUE),
  SD   = apply(w_rpp_sub, 2, sd, na.rm = TRUE),
  CV   = apply(w_rpp_sub, 2, sd, na.rm = TRUE) / apply(w_rpp_sub, 2, mean, na.rm = TRUE),
  Min  = apply(w_rpp_sub, 2, min, na.rm = TRUE),
  Max  = apply(w_rpp_sub, 2, max, na.rm = TRUE)
)

# combinar en un solo marco de datos
portfolio_weights_summary <- rbind(
  cbind(Type = "RP",  Stat = rownames(aw1_2), round(aw1_2, 4)),
  cbind(Type = "MS",  Stat = rownames(aw2_2), round(aw2_2, 4)),
  cbind(Type = "RPC", Stat = rownames(aw3_2), round(aw3_2, 4))
)

print(portfolio_weights_summary)
##      Type  Stat   AI_INDEX Fintech  Blockchain
## Mean "RP"  "Mean" "0.1829" "0.619"  "0.1981"  
## SD   "RP"  "SD"   "0.0375" "0.0769" "0.044"   
## CV   "RP"  "CV"   "0.2051" "0.1243" "0.2221"  
## Min  "RP"  "Min"  "0.1271" "0.4993" "0.129"   
## Max  "RP"  "Max"  "0.2663" "0.741"  "0.2943"  
## Mean "MS"  "Mean" "0.1067" "0.215"  "0.2255"  
## SD   "MS"  "SD"   "0.2527" "0.3701" "0.3509"  
## CV   "MS"  "CV"   "2.368"  "1.7211" "1.5564"  
## Min  "MS"  "Min"  "0"      "0"      "0"       
## Max  "MS"  "Max"  "1"      "1"      "1"       
## Mean "RPC" "Mean" "0.3244" "0.348"  "0.3275"  
## SD   "RPC" "SD"   "0.0117" "0.0187" "0.0129"  
## CV   "RPC" "CV"   "0.0361" "0.0538" "0.0393"  
## Min  "RPC" "Min"  "0.3017" "0.3102" "0.2995"  
## Max  "RPC" "Max"  "0.3702" "0.3987" "0.3654"
# opcional: guardar resultados
# write.csv(portfolio_weights_summary, "tables_portfolio_weights_summary.csv", row.names = FALSE)

# Curvas acumuladas
chart.CumReturns(port_ret, main = "Equity Curves (EQW, RP, RPC, MS)",
                 ylab = "", geometric = TRUE, wealth.index = TRUE,
                 legend.loc = "topleft")

# dev.off()

# experimenting with colors
#chart.CumReturns(port_ret,  main = "Equity curves", ylab="", geometric = FALSE, wealth.index = TRUE, 
#                 colorset=tim6equal, legend.loc = "topleft", )

#chart.CumReturns(port_ret,  main = "Equity curves", ylab="", geometric = FALSE, wealth.index = TRUE, 
#                 colorset=rich6equal, legend.loc = "topleft", )

# set risk free rate ; from yahoo finance ^IRX
(rfr <- (0.9556624/100)/252)
## [1] 3.792311e-05
ta1 <- table.AnnualizedReturns(port_ret, scale=252, geometric = TRUE,  Rf=rfr)

ta2 <- table.DownsideRisk(port_ret, scale=252,  Rf=rfr, MAR =.00, p=.95)
ta3 <- Omega(port_ret, Rf=rfr)
SortinoRatio(port_ret)
##                                EQW        RP       RPC        MS
## Sortino Ratio (MAR = 0%) 0.2158486 0.2879532 0.2165428 0.3092285
rbind(ta1, ta2, ta3)
##                                     EQW       RP      RPC        MS
## Annualized Return              0.120900  0.10050  0.11730  0.108900
## Annualized Std Dev             0.049500  0.03220  0.04780  0.037000
## Annualized Sharpe (Rf=0.96%)   2.225500  2.79650  2.22940  2.660300
## Semi Deviation                 0.002300  0.00150  0.00230  0.001500
## Gain Deviation                 0.001700  0.00120  0.00170  0.002100
## Loss Deviation                 0.002200  0.00140  0.00210  0.001900
## Downside Deviation (MAR=0%)    0.002100  0.00130  0.00210  0.001300
## Downside Deviation (Rf=0.96%)  0.002100  0.00130  0.00210  0.001300
## Downside Deviation (0%)        0.002100  0.00130  0.00210  0.001300
## Maximum Drawdown               0.306100  0.14570  0.29840  0.111700
## Historical VaR (95%)          -0.005100 -0.00330 -0.00500 -0.002600
## Historical ES (95%)           -0.006900 -0.00430 -0.00670 -0.005000
## Modified VaR (95%)            -0.005000 -0.00320 -0.00490 -0.003000
## Modified ES (95%)             -0.007300 -0.00430 -0.00690 -0.003800
## Omega (L = 0%)                 1.451807  1.60503  1.45131  1.877081
#################################################################
# weekly re-balancing
#################################################################

rbp <- c("days")
# rbp <- c("weeks")
# rbp <- c("months")


port_eqw  <- Return.portfolio( y.r_c,   verbose=TRUE,  rebalance_on = rbp)
head (port_eqw$BOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-08 0.3333333 0.3333333  0.3333333
## 2019-01-09 0.3333333 0.3333333  0.3333333
## 2019-01-10 0.3333333 0.3333333  0.3333333
## 2019-01-11 0.3333333 0.3333333  0.3333333
## 2019-01-12 0.3333333 0.3333333  0.3333333
## 2019-01-13 0.3333333 0.3333333  0.3333333
## 2019-01-14 0.3333333 0.3333333  0.3333333
## 2019-01-15 0.3333333 0.3333333  0.3333333
## 2019-01-16 0.3333333 0.3333333  0.3333333
## 2019-01-17 0.3333333 0.3333333  0.3333333
## 2019-01-18 0.3333333 0.3333333  0.3333333
## 2019-01-19 0.3333333 0.3333333  0.3333333
## 2019-01-20 0.3333333 0.3333333  0.3333333
## 2019-01-21 0.3333333 0.3333333  0.3333333
## 2019-01-22 0.3333333 0.3333333  0.3333333
## 2019-01-23 0.3333333 0.3333333  0.3333333
## 2019-01-24 0.3333333 0.3333333  0.3333333
## 2019-01-25 0.3333333 0.3333333  0.3333333
## 2019-01-26 0.3333333 0.3333333  0.3333333
## 2019-01-27 0.3333333 0.3333333  0.3333333
## 2019-01-28 0.3333333 0.3333333  0.3333333
## 2019-01-29 0.3333333 0.3333333  0.3333333
head (port_eqw$EOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-08 0.3351063 0.3319946  0.3328991
## 2019-01-09 0.3350903 0.3320032  0.3329065
## 2019-01-10 0.3350746 0.3320117  0.3329137
## 2019-01-11 0.3350591 0.3320200  0.3329209
## 2019-01-12 0.3350439 0.3320283  0.3329279
## 2019-01-13 0.3350289 0.3320363  0.3329347
## 2019-01-14 0.3350142 0.3320443  0.3329415
## 2019-01-15 0.3336926 0.3320248  0.3342827
## 2019-01-16 0.3336931 0.3320291  0.3342778
## 2019-01-17 0.3336935 0.3320334  0.3342730
## 2019-01-18 0.3336940 0.3320377  0.3342683
## 2019-01-19 0.3336945 0.3320419  0.3342637
## 2019-01-20 0.3336949 0.3320460  0.3342590
## 2019-01-21 0.3336954 0.3320501  0.3342545
## 2019-01-22 0.3343278 0.3326513  0.3330208
## 2019-01-23 0.3343218 0.3326547  0.3330235
## 2019-01-24 0.3343158 0.3326580  0.3330262
## 2019-01-25 0.3343098 0.3326613  0.3330289
## 2019-01-26 0.3343040 0.3326645  0.3330315
## 2019-01-27 0.3342982 0.3326677  0.3330341
## 2019-01-28 0.3342924 0.3326709  0.3330366
## 2019-01-29 0.3344755 0.3329409  0.3325836
tail (port_eqw$BOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2024-07-29 0.3333333 0.3333333  0.3333333
## 2024-07-30 0.3333333 0.3333333  0.3333333
## 2024-07-31 0.3333333 0.3333333  0.3333333
## 2024-08-01 0.3333333 0.3333333  0.3333333
## 2024-08-02 0.3333333 0.3333333  0.3333333
## 2024-08-03 0.3333333 0.3333333  0.3333333
## 2024-08-04 0.3333333 0.3333333  0.3333333
## 2024-08-05 0.3333333 0.3333333  0.3333333
## 2024-08-06 0.3333333 0.3333333  0.3333333
## 2024-08-07 0.3333333 0.3333333  0.3333333
## 2024-08-08 0.3333333 0.3333333  0.3333333
## 2024-08-09 0.3333333 0.3333333  0.3333333
## 2024-08-10 0.3333333 0.3333333  0.3333333
## 2024-08-11 0.3333333 0.3333333  0.3333333
## 2024-08-12 0.3333333 0.3333333  0.3333333
## 2024-08-13 0.3333333 0.3333333  0.3333333
## 2024-08-14 0.3333333 0.3333333  0.3333333
## 2024-08-15 0.3333333 0.3333333  0.3333333
## 2024-08-16 0.3333333 0.3333333  0.3333333
## 2024-08-17 0.3333333 0.3333333  0.3333333
## 2024-08-18 0.3333333 0.3333333  0.3333333
## 2024-08-19 0.3333333 0.3333333  0.3333333
tail (port_eqw$EOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2024-07-29 0.3315546 0.3346011  0.3338443
## 2024-07-30 0.3372767 0.3333147  0.3294086
## 2024-07-31 0.3372732 0.3333457  0.3293812
## 2024-08-01 0.3372706 0.3333770  0.3293524
## 2024-08-02 0.3372691 0.3334086  0.3293223
## 2024-08-03 0.3372686 0.3334405  0.3292909
## 2024-08-04 0.3372692 0.3334729  0.3292579
## 2024-08-05 0.3372708 0.3335056  0.3292236
## 2024-08-06 0.3342365 0.3319810  0.3337825
## 2024-08-07 0.3342302 0.3319884  0.3337814
## 2024-08-08 0.3342240 0.3319957  0.3337803
## 2024-08-09 0.3342179 0.3320030  0.3337792
## 2024-08-10 0.3342118 0.3320102  0.3337780
## 2024-08-11 0.3342058 0.3320172  0.3337769
## 2024-08-12 0.3341999 0.3320242  0.3337758
## 2024-08-13 0.3325669 0.3321661  0.3352670
## 2024-08-14 0.3325773 0.3321775  0.3352452
## 2024-08-15 0.3325875 0.3321888  0.3352238
## 2024-08-16 0.3325974 0.3321998  0.3352028
## 2024-08-17 0.3326071 0.3322106  0.3351823
## 2024-08-18 0.3326167 0.3322212  0.3351622
## 2024-08-19 0.3326260 0.3322316  0.3351424
# port_rp   <- Return.portfolio(y.r, weights=w.rp,verbose=TRUE)
ep <- endpoints(roll_rp, on = rbp)
port_rp   <- Return.portfolio( y.r_c, weights= roll_rp[ep,] ,   verbose=TRUE)
head(roll_rp[ep,],22)
##             AI_INDEX   Fintech Blockchain
## 2019-09-16 0.2297251 0.5320311  0.2382438
## 2019-09-17 0.2307445 0.5310811  0.2381744
## 2019-09-18 0.2317617 0.5301275  0.2381108
## 2019-09-19 0.2327769 0.5291704  0.2380527
## 2019-09-20 0.2337901 0.5282097  0.2380002
## 2019-09-21 0.2348015 0.5272453  0.2379531
## 2019-09-22 0.2358112 0.5262774  0.2379115
## 2019-09-23 0.2368191 0.5253058  0.2378751
## 2019-09-24 0.2351257 0.5258355  0.2390388
## 2019-09-25 0.2334720 0.5263306  0.2401975
## 2019-09-26 0.2318561 0.5267919  0.2413520
## 2019-09-27 0.2302765 0.5272202  0.2425032
## 2019-09-28 0.2287318 0.5276162  0.2436520
## 2019-09-29 0.2272204 0.5279806  0.2447990
## 2019-09-30 0.2257410 0.5283140  0.2459450
## 2019-10-01 0.2262891 0.5280190  0.2456919
## 2019-10-02 0.2268315 0.5277291  0.2454394
## 2019-10-03 0.2273682 0.5274443  0.2451875
## 2019-10-04 0.2278993 0.5271645  0.2449362
## 2019-10-05 0.2284248 0.5268898  0.2446854
## 2019-10-06 0.2289448 0.5266200  0.2444352
## 2019-10-07 0.2294592 0.5263553  0.2441855
head (port_rp$BOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-09-17 0.2297251 0.5320311  0.2382438
## 2019-09-18 0.2307445 0.5310811  0.2381744
## 2019-09-19 0.2317617 0.5301275  0.2381108
## 2019-09-20 0.2327769 0.5291704  0.2380527
## 2019-09-21 0.2337901 0.5282097  0.2380002
## 2019-09-22 0.2348015 0.5272453  0.2379531
## 2019-09-23 0.2358112 0.5262774  0.2379115
## 2019-09-24 0.2368191 0.5253058  0.2378751
## 2019-09-25 0.2351257 0.5258355  0.2390388
## 2019-09-26 0.2334720 0.5263306  0.2401975
## 2019-09-27 0.2318561 0.5267919  0.2413520
## 2019-09-28 0.2302765 0.5272202  0.2425032
## 2019-09-29 0.2287318 0.5276162  0.2436520
## 2019-09-30 0.2272204 0.5279806  0.2447990
## 2019-10-01 0.2257410 0.5283140  0.2459450
## 2019-10-02 0.2262891 0.5280190  0.2456919
## 2019-10-03 0.2268315 0.5277291  0.2454394
## 2019-10-04 0.2273682 0.5274443  0.2451875
## 2019-10-05 0.2278993 0.5271645  0.2449362
## 2019-10-06 0.2284248 0.5268898  0.2446854
## 2019-10-07 0.2289448 0.5266200  0.2444352
## 2019-10-08 0.2294592 0.5263553  0.2441855
head (port_rp$EOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-09-17 0.2303167 0.5320218  0.2376615
## 2019-09-18 0.2313363 0.5310719  0.2375918
## 2019-09-19 0.2323537 0.5301184  0.2375279
## 2019-09-20 0.2333691 0.5291614  0.2374695
## 2019-09-21 0.2343825 0.5282008  0.2374166
## 2019-09-22 0.2353941 0.5272367  0.2373692
## 2019-09-23 0.2364039 0.5262689  0.2373272
## 2019-09-24 0.2357207 0.5262990  0.2379803
## 2019-09-25 0.2340244 0.5268312  0.2391444
## 2019-09-26 0.2323675 0.5273289  0.2403035
## 2019-09-27 0.2307485 0.5277929  0.2414586
## 2019-09-28 0.2291656 0.5282240  0.2426104
## 2019-09-29 0.2276175 0.5286228  0.2437597
## 2019-09-30 0.2261025 0.5289901  0.2449074
## 2019-10-01 0.2270032 0.5272784  0.2457184
## 2019-10-02 0.2275485 0.5269848  0.2454666
## 2019-10-03 0.2280882 0.5266963  0.2452155
## 2019-10-04 0.2286222 0.5264129  0.2449649
## 2019-10-05 0.2291506 0.5261344  0.2447150
## 2019-10-06 0.2296735 0.5258610  0.2444655
## 2019-10-07 0.2301908 0.5255925  0.2442166
## 2019-10-08 0.2295617 0.5257297  0.2447086
tail(roll_rp[ep,],22)
##             AI_INDEX   Fintech Blockchain
## 2024-07-29 0.1845341 0.5211630  0.2943029
## 2024-07-30 0.1880571 0.5220880  0.2898549
## 2024-07-31 0.1914323 0.5229209  0.2856468
## 2024-08-01 0.1946748 0.5236746  0.2816506
## 2024-08-02 0.1977975 0.5243599  0.2778427
## 2024-08-03 0.2008115 0.5249860  0.2742026
## 2024-08-04 0.2037266 0.5255607  0.2707127
## 2024-08-05 0.2065516 0.5260909  0.2673576
## 2024-08-06 0.2052349 0.5277786  0.2669865
## 2024-08-07 0.2039387 0.5294381  0.2666231
## 2024-08-08 0.2026622 0.5310707  0.2662671
## 2024-08-09 0.2014045 0.5326774  0.2659180
## 2024-08-10 0.2001649 0.5342593  0.2655758
## 2024-08-11 0.1989426 0.5358173  0.2652400
## 2024-08-12 0.1977369 0.5373525  0.2649105
## 2024-08-13 0.1982794 0.5386962  0.2630243
## 2024-08-14 0.1987962 0.5399731  0.2612307
## 2024-08-15 0.1992887 0.5411880  0.2595233
## 2024-08-16 0.1997582 0.5423454  0.2578964
## 2024-08-17 0.2002060 0.5434493  0.2563446
## 2024-08-18 0.2006332 0.5445035  0.2548632
## 2024-08-19 0.2010408 0.5455113  0.2534479
tail (port_rp$BOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2024-07-29 0.1856793 0.5203533  0.2939673
## 2024-07-30 0.1845341 0.5211630  0.2943029
## 2024-07-31 0.1880571 0.5220880  0.2898549
## 2024-08-01 0.1914323 0.5229209  0.2856468
## 2024-08-02 0.1946748 0.5236746  0.2816506
## 2024-08-03 0.1977975 0.5243599  0.2778427
## 2024-08-04 0.2008115 0.5249860  0.2742026
## 2024-08-05 0.2037266 0.5255607  0.2707127
## 2024-08-06 0.2065516 0.5260909  0.2673576
## 2024-08-07 0.2052349 0.5277786  0.2669865
## 2024-08-08 0.2039387 0.5294381  0.2666231
## 2024-08-09 0.2026622 0.5310707  0.2662671
## 2024-08-10 0.2014045 0.5326774  0.2659180
## 2024-08-11 0.2001649 0.5342593  0.2655758
## 2024-08-12 0.1989426 0.5358173  0.2652400
## 2024-08-13 0.1977369 0.5373525  0.2649105
## 2024-08-14 0.1982794 0.5386962  0.2630243
## 2024-08-15 0.1987962 0.5399731  0.2612307
## 2024-08-16 0.1992887 0.5411880  0.2595233
## 2024-08-17 0.1997582 0.5423454  0.2578964
## 2024-08-18 0.2002060 0.5434493  0.2563446
## 2024-08-19 0.2006332 0.5445035  0.2548632
tail (port_rp$EOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2024-07-29 0.1844231 0.5215819  0.2939950
## 2024-07-30 0.1869623 0.5218181  0.2912196
## 2024-07-31 0.1905074 0.5227318  0.2867608
## 2024-08-01 0.1939033 0.5235557  0.2825410
## 2024-08-02 0.1971651 0.5243026  0.2785323
## 2024-08-03 0.2003061 0.5249830  0.2747110
## 2024-08-04 0.2033374 0.5256060  0.2710566
## 2024-08-05 0.2062692 0.5261794  0.2675514
## 2024-08-06 0.2073631 0.5245936  0.2680433
## 2024-08-07 0.2060381 0.5262903  0.2676715
## 2024-08-08 0.2047338 0.5279588  0.2673073
## 2024-08-09 0.2034493 0.5296003  0.2669504
## 2024-08-10 0.2021838 0.5312158  0.2666004
## 2024-08-11 0.2009364 0.5328063  0.2662572
## 2024-08-12 0.1997065 0.5343730  0.2659205
## 2024-08-13 0.1974402 0.5358993  0.2666605
## 2024-08-14 0.1979899 0.5372630  0.2647471
## 2024-08-15 0.1985136 0.5385592  0.2629272
## 2024-08-16 0.1990129 0.5397928  0.2611943
## 2024-08-17 0.1994889 0.5409684  0.2595427
## 2024-08-18 0.1999430 0.5420900  0.2579670
## 2024-08-19 0.2003762 0.5431613  0.2564625
ep <- endpoints(w.mcp_temp, on = rbp)
port_mcp  <- Return.portfolio( y.r_c, weights= w.mcp_temp[ep,]  ,verbose=TRUE)

ep <- endpoints(w.rpp_temp, on = rbp)
port_rpp  <- Return.portfolio( y.r_c, weights= w.rpp_temp[ep,],verbose=TRUE)
head(w.rpp_temp[ep,],22)
##            AI_INDEX.1   Fintech Blockchain
## 2019-01-08  0.3265071 0.3423964  0.3310965
## 2019-01-09  0.3097279 0.3328982  0.3573739
## 2019-01-10  0.3095399 0.3329365  0.3575236
## 2019-01-11  0.3096072 0.3330941  0.3572987
## 2019-01-12  0.3099208 0.3333798  0.3566995
## 2019-01-13  0.3105212 0.3337755  0.3557033
## 2019-01-14  0.3114297 0.3342215  0.3543487
## 2019-01-15  0.3123933 0.3337710  0.3538357
## 2019-01-16  0.3693964 0.3101953  0.3204083
## 2019-01-17  0.3696746 0.3101726  0.3201528
## 2019-01-18  0.3696835 0.3102277  0.3200888
## 2019-01-19  0.3694967 0.3103686  0.3201347
## 2019-01-20  0.3691072 0.3106073  0.3202855
## 2019-01-21  0.3685150 0.3109457  0.3205393
## 2019-01-22  0.3702358 0.3106228  0.3191414
## 2019-01-23  0.3258050 0.3354621  0.3387329
## 2019-01-24  0.3206552 0.3359615  0.3433833
## 2019-01-25  0.3188437 0.3360249  0.3451314
## 2019-01-26  0.3179339 0.3360335  0.3460325
## 2019-01-27  0.3173917 0.3360312  0.3465771
## 2019-01-28  0.3170341 0.3360267  0.3469392
## 2019-01-29  0.3152786 0.3348212  0.3499001
head (port_rpp$BOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-09 0.3265071 0.3423964  0.3310965
## 2019-01-10 0.3097279 0.3328982  0.3573739
## 2019-01-11 0.3095399 0.3329365  0.3575236
## 2019-01-12 0.3096072 0.3330941  0.3572987
## 2019-01-13 0.3099208 0.3333798  0.3566995
## 2019-01-14 0.3105212 0.3337755  0.3557033
## 2019-01-15 0.3114297 0.3342215  0.3543487
## 2019-01-16 0.3123933 0.3337710  0.3538357
## 2019-01-17 0.3693964 0.3101953  0.3204083
## 2019-01-18 0.3696746 0.3101726  0.3201528
## 2019-01-19 0.3696835 0.3102277  0.3200888
## 2019-01-20 0.3694967 0.3103686  0.3201347
## 2019-01-21 0.3691072 0.3106073  0.3202855
## 2019-01-22 0.3685150 0.3109457  0.3205393
## 2019-01-23 0.3702358 0.3106228  0.3191414
## 2019-01-24 0.3258050 0.3354621  0.3387329
## 2019-01-25 0.3206552 0.3359615  0.3433833
## 2019-01-26 0.3188437 0.3360249  0.3451314
## 2019-01-27 0.3179339 0.3360335  0.3460325
## 2019-01-28 0.3173917 0.3360312  0.3465771
## 2019-01-29 0.3170341 0.3360267  0.3469392
## 2019-01-30 0.3152786 0.3348212  0.3499001
head (port_rpp$EOP.Weight,22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-09 0.3282508 0.3410537  0.3306954
## 2019-01-10 0.3113931 0.3316286  0.3569783
## 2019-01-11 0.3111896 0.3316750  0.3571354
## 2019-01-12 0.3112426 0.3318398  0.3569176
## 2019-01-13 0.3115432 0.3321315  0.3563254
## 2019-01-14 0.3121318 0.3325322  0.3553360
## 2019-01-15 0.3117551 0.3328986  0.3553463
## 2019-01-16 0.3127198 0.3324538  0.3548263
## 2019-01-17 0.3697613 0.3089570  0.3212818
## 2019-01-18 0.3700404 0.3089384  0.3210212
## 2019-01-19 0.3700500 0.3089974  0.3209526
## 2019-01-20 0.3698638 0.3091417  0.3209945
## 2019-01-21 0.3694747 0.3093837  0.3211416
## 2019-01-22 0.3695544 0.3102590  0.3201866
## 2019-01-23 0.3712710 0.3099381  0.3187909
## 2019-01-24 0.3267756 0.3347930  0.3384314
## 2019-01-25 0.3216112 0.3353015  0.3430874
## 2019-01-26 0.3197908 0.3353702  0.3448390
## 2019-01-27 0.3188738 0.3353831  0.3457431
## 2019-01-28 0.3183250 0.3353846  0.3462905
## 2019-01-29 0.3181490 0.3356612  0.3461898
## 2019-01-30 0.3163789 0.3344656  0.3491555
ep <- endpoints(roll_ms, on = rbp)
port_ms   <- Return.portfolio( y.r_c, weights= roll_ms[ep,],   verbose=TRUE)
## Warning in Return.portfolio.geometric(R = R, weights = weights, wealth.index =
## wealth.index, : The weights for one or more periods do not sum up to 1:
## assuming a return of 0 for the residual weights
port_ret <- cbind(port_eqw$returns, port_rp$returns, port_rpp$returns, port_ms$returns )
colnames(port_ret) <- c("EQW", "RP", "RPC", "MS")
# all portfolios start at same time period
port_ret <- na.omit( port_ret)
head(port_ret)
##                     EQW           RP          RPC           MS
## 2019-09-17 0.0008288824 0.0007909495 0.0008167320 0.0007733999
## 2019-09-18 0.0008239991 0.0007901827 0.0008228203 0.0007728015
## 2019-09-19 0.0008191387 0.0007893914 0.0008180661 0.0007722050
## 2019-09-20 0.0008143003 0.0007885755 0.0008133313 0.0007716095
## 2019-09-21 0.0008094841 0.0007877354 0.0008086159 0.0007710141
## 2019-09-22 0.0008046894 0.0007868719 0.0008039194 0.0007704206
ta1 <- table.AnnualizedReturns(port_ret, scale=252, geometric = TRUE,  Rf=rfr)
ta2 <- table.DownsideRisk(port_ret, scale=252,  Rf=rfr, MAR =.00, p=.95)
ta3 <- Omega(port_ret, Rf=rfr)
SortinoRatio(port_ret)
##                                EQW        RP       RPC        MS
## Sortino Ratio (MAR = 0%) 0.2158486 0.2879532 0.2165428 0.3092285
rbind(ta1, ta2, ta3)
##                                     EQW       RP      RPC        MS
## Annualized Return              0.120900  0.10050  0.11730  0.108900
## Annualized Std Dev             0.049500  0.03220  0.04780  0.037000
## Annualized Sharpe (Rf=0.96%)   2.225500  2.79650  2.22940  2.660300
## Semi Deviation                 0.002300  0.00150  0.00230  0.001500
## Gain Deviation                 0.001700  0.00120  0.00170  0.002100
## Loss Deviation                 0.002200  0.00140  0.00210  0.001900
## Downside Deviation (MAR=0%)    0.002100  0.00130  0.00210  0.001300
## Downside Deviation (Rf=0.96%)  0.002100  0.00130  0.00210  0.001300
## Downside Deviation (0%)        0.002100  0.00130  0.00210  0.001300
## Maximum Drawdown               0.306100  0.14570  0.29840  0.111700
## Historical VaR (95%)          -0.005100 -0.00330 -0.00500 -0.002600
## Historical ES (95%)           -0.006900 -0.00430 -0.00670 -0.005000
## Modified VaR (95%)            -0.005000 -0.00320 -0.00490 -0.003000
## Modified ES (95%)             -0.007300 -0.00430 -0.00690 -0.003800
## Omega (L = 0%)                 1.451807  1.60503  1.45131  1.877081
#################################################################
# Portfolio summary statistics (rebalance monthly)
#################################################################

rbp <- c("months")  # <<< cambio clave respecto al bloque semanal

# Portafolio Equal Weight (EQW)
port_eqw_m  <- Return.portfolio(y.r_c, verbose = TRUE, rebalance_on = rbp)
head(port_eqw_m$BOP.Weight, 22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-08 0.3333333 0.3333333  0.3333333
## 2019-01-09 0.3351063 0.3319946  0.3328991
## 2019-01-10 0.3368675 0.3306648  0.3324677
## 2019-01-11 0.3386170 0.3293438  0.3320391
## 2019-01-12 0.3403549 0.3280316  0.3316135
## 2019-01-13 0.3420814 0.3267280  0.3311906
## 2019-01-14 0.3437965 0.3254331  0.3307705
## 2019-01-15 0.3455003 0.3241466  0.3303531
## 2019-01-16 0.3458586 0.3228609  0.3312805
## 2019-01-17 0.3462150 0.3215820  0.3322030
## 2019-01-18 0.3465695 0.3203098  0.3331207
## 2019-01-19 0.3469222 0.3190442  0.3340336
## 2019-01-20 0.3472730 0.3177852  0.3349417
## 2019-01-21 0.3476221 0.3165328  0.3358452
## 2019-01-22 0.3479693 0.3152868  0.3367439
## 2019-01-23 0.3489805 0.3146174  0.3364022
## 2019-01-24 0.3499867 0.3139512  0.3360621
## 2019-01-25 0.3509881 0.3132882  0.3357236
## 2019-01-26 0.3519847 0.3126285  0.3353868
## 2019-01-27 0.3529765 0.3119719  0.3350516
## 2019-01-28 0.3539635 0.3113185  0.3347180
## 2019-01-29 0.3549458 0.3106682  0.3343860
head(port_eqw_m$EOP.Weight, 22)
##             AI_INDEX   Fintech Blockchain
## 2019-01-08 0.3351063 0.3319946  0.3328991
## 2019-01-09 0.3368675 0.3306648  0.3324677
## 2019-01-10 0.3386170 0.3293438  0.3320391
## 2019-01-11 0.3403549 0.3280316  0.3316135
## 2019-01-12 0.3420814 0.3267280  0.3311906
## 2019-01-13 0.3437965 0.3254331  0.3307705
## 2019-01-14 0.3455003 0.3241466  0.3303531
## 2019-01-15 0.3458586 0.3228609  0.3312805
## 2019-01-16 0.3462150 0.3215820  0.3322030
## 2019-01-17 0.3465695 0.3203098  0.3331207
## 2019-01-18 0.3469222 0.3190442  0.3340336
## 2019-01-19 0.3472730 0.3177852  0.3349417
## 2019-01-20 0.3476221 0.3165328  0.3358452
## 2019-01-21 0.3479693 0.3152868  0.3367439
## 2019-01-22 0.3489805 0.3146174  0.3364022
## 2019-01-23 0.3499867 0.3139512  0.3360621
## 2019-01-24 0.3509881 0.3132882  0.3357236
## 2019-01-25 0.3519847 0.3126285  0.3353868
## 2019-01-26 0.3529765 0.3119719  0.3350516
## 2019-01-27 0.3539635 0.3113185  0.3347180
## 2019-01-28 0.3549458 0.3106682  0.3343860
## 2019-01-29 0.3561270 0.3102719  0.3336011
# Portafolio Risk Parity (RP)
ep_m <- endpoints(roll_rp, on = rbp)
port_rp_m <- Return.portfolio(y.r_c, weights = roll_rp[ep_m, ], verbose = TRUE)
head(roll_rp[ep_m, ], 22)
##             AI_INDEX   Fintech Blockchain
## 2019-09-30 0.2257410 0.5283140  0.2459450
## 2019-10-31 0.2435732 0.5127518  0.2436751
## 2019-11-30 0.2428329 0.5015914  0.2555756
## 2019-12-31 0.2209365 0.5235653  0.2554982
## 2020-01-31 0.2253063 0.5120199  0.2626738
## 2020-02-29 0.2112113 0.5237991  0.2649895
## 2020-03-31 0.1624413 0.6914295  0.1461292
## 2020-04-30 0.1402904 0.7127473  0.1469623
## 2020-05-31 0.1364577 0.7164528  0.1470895
## 2020-06-30 0.1440367 0.7097323  0.1462311
## 2020-07-31 0.1350736 0.7251373  0.1397891
## 2020-08-31 0.1382792 0.7231423  0.1385785
## 2020-09-30 0.1297673 0.7322973  0.1379354
## 2020-10-31 0.1423560 0.7082562  0.1493878
## 2020-11-30 0.1580203 0.6554109  0.1865688
## 2020-12-31 0.1870742 0.5941062  0.2188196
## 2021-01-31 0.1993651 0.5799397  0.2206951
## 2021-02-28 0.1560658 0.6152398  0.2286944
## 2021-03-31 0.1961157 0.5912551  0.2126292
## 2021-04-30 0.1952150 0.5885829  0.2162021
## 2021-05-31 0.1902963 0.5971289  0.2125748
## 2021-06-30 0.1869404 0.5974275  0.2156321
head(port_rp_m$BOP.Weight, 22)
##             AI_INDEX   Fintech Blockchain
## 2019-10-01 0.2257410 0.5283140  0.2459450
## 2019-10-02 0.2270032 0.5272784  0.2457184
## 2019-10-03 0.2282654 0.5262429  0.2454917
## 2019-10-04 0.2295276 0.5252073  0.2452651
## 2019-10-05 0.2307897 0.5241717  0.2450385
## 2019-10-06 0.2320519 0.5231362  0.2448119
## 2019-10-07 0.2333141 0.5221006  0.2445853
## 2019-10-08 0.2345763 0.5210650  0.2443587
## 2019-10-09 0.2346790 0.5204410  0.2448800
## 2019-10-10 0.2347816 0.5198175  0.2454009
## 2019-10-11 0.2348840 0.5191946  0.2459214
## 2019-10-12 0.2349864 0.5185722  0.2464414
## 2019-10-13 0.2350887 0.5179503  0.2469610
## 2019-10-14 0.2351910 0.5173289  0.2474801
## 2019-10-15 0.2352931 0.5167081  0.2479988
## 2019-10-16 0.2335041 0.5176499  0.2488460
## 2019-10-17 0.2317134 0.5185927  0.2496939
## 2019-10-18 0.2299209 0.5195363  0.2505427
## 2019-10-19 0.2281267 0.5204809  0.2513924
## 2019-10-20 0.2263306 0.5214265  0.2522429
## 2019-10-21 0.2245329 0.5223729  0.2530942
## 2019-10-22 0.2227333 0.5233203  0.2539464
head(port_rp_m$EOP.Weight, 22)
##             AI_INDEX   Fintech Blockchain
## 2019-10-01 0.2270032 0.5272784  0.2457184
## 2019-10-02 0.2282654 0.5262429  0.2454917
## 2019-10-03 0.2295276 0.5252073  0.2452651
## 2019-10-04 0.2307897 0.5241717  0.2450385
## 2019-10-05 0.2320519 0.5231362  0.2448119
## 2019-10-06 0.2333141 0.5221006  0.2445853
## 2019-10-07 0.2345763 0.5210650  0.2443587
## 2019-10-08 0.2346790 0.5204410  0.2448800
## 2019-10-09 0.2347816 0.5198175  0.2454009
## 2019-10-10 0.2348840 0.5191946  0.2459214
## 2019-10-11 0.2349864 0.5185722  0.2464414
## 2019-10-12 0.2350887 0.5179503  0.2469610
## 2019-10-13 0.2351910 0.5173289  0.2474801
## 2019-10-14 0.2352931 0.5167081  0.2479988
## 2019-10-15 0.2335041 0.5176499  0.2488460
## 2019-10-16 0.2317134 0.5185927  0.2496939
## 2019-10-17 0.2299209 0.5195363  0.2505427
## 2019-10-18 0.2281267 0.5204809  0.2513924
## 2019-10-19 0.2263306 0.5214265  0.2522429
## 2019-10-20 0.2245329 0.5223729  0.2530942
## 2019-10-21 0.2227333 0.5233203  0.2539464
## 2019-10-22 0.2224410 0.5239432  0.2536158
# Portafolio Minimum Connectedness (MCP)
ep_m <- endpoints(w.mcp_temp, on = rbp)
port_mcp_m <- Return.portfolio(y.r_c, weights = w.mcp_temp[ep_m, ], verbose = TRUE)

# Portafolio Risk Parity Connectedness (RPC)
ep_m <- endpoints(w.rpp_temp, on = rbp)
port_rpp_m <- Return.portfolio(y.r_c, weights = w.rpp_temp[ep_m, ], verbose = TRUE)
head(w.rpp_temp[ep_m, ], 22)
##            AI_INDEX.1   Fintech Blockchain
## 2019-01-31  0.3289811 0.3341430  0.3368759
## 2019-02-28  0.3363116 0.3492580  0.3144304
## 2019-03-31  0.3308702 0.3393929  0.3297369
## 2019-04-30  0.3449267 0.3272312  0.3278422
## 2019-05-31  0.3320275 0.3420041  0.3259684
## 2019-06-30  0.3168507 0.3506587  0.3324906
## 2019-07-31  0.3134723 0.3612394  0.3252882
## 2019-08-31  0.3181933 0.3617609  0.3200458
## 2019-09-30  0.3257037 0.3514502  0.3228461
## 2019-10-31  0.3371312 0.3367531  0.3261157
## 2019-11-30  0.3375601 0.3363697  0.3260702
## 2019-12-31  0.3315039 0.3364480  0.3320481
## 2020-01-31  0.3282430 0.3464434  0.3253136
## 2020-02-29  0.3136865 0.3723297  0.3139838
## 2020-03-31  0.3018515 0.3986544  0.2994941
## 2020-04-30  0.3043240 0.3937593  0.3019166
## 2020-05-31  0.3032735 0.3948967  0.3018298
## 2020-06-30  0.3065739 0.3916484  0.3017777
## 2020-07-31  0.3039566 0.3880528  0.3079906
## 2020-08-31  0.3121820 0.3738214  0.3139966
## 2020-09-30  0.3093644 0.3722504  0.3183853
## 2020-10-31  0.3078739 0.3777330  0.3143930
head(port_rpp_m$BOP.Weight, 22)
##             AI_INDEX   Fintech Blockchain
## 2019-02-01 0.3289811 0.3341430  0.3368759
## 2019-02-02 0.3300801 0.3337725  0.3361474
## 2019-02-03 0.3311693 0.3334053  0.3354254
## 2019-02-04 0.3322487 0.3330414  0.3347099
## 2019-02-05 0.3333185 0.3326807  0.3340008
## 2019-02-06 0.3341147 0.3326916  0.3331937
## 2019-02-07 0.3349093 0.3327025  0.3323882
## 2019-02-08 0.3357023 0.3327134  0.3315843
## 2019-02-09 0.3364938 0.3327242  0.3307820
## 2019-02-10 0.3372836 0.3327350  0.3299813
## 2019-02-11 0.3380719 0.3327458  0.3291822
## 2019-02-12 0.3388587 0.3327566  0.3283847
## 2019-02-13 0.3397594 0.3312211  0.3290195
## 2019-02-14 0.3406556 0.3296932  0.3296512
## 2019-02-15 0.3415475 0.3281727  0.3302798
## 2019-02-16 0.3424349 0.3266598  0.3309053
## 2019-02-17 0.3433181 0.3251542  0.3315277
## 2019-02-18 0.3441969 0.3236559  0.3321472
## 2019-02-19 0.3450715 0.3221649  0.3327636
## 2019-02-20 0.3455115 0.3212615  0.3332270
## 2019-02-21 0.3459494 0.3203624  0.3336883
## 2019-02-22 0.3463852 0.3194674  0.3341474
head(port_rpp_m$EOP.Weight, 22)
##             AI_INDEX   Fintech Blockchain
## 2019-02-01 0.3300801 0.3337725  0.3361474
## 2019-02-02 0.3311693 0.3334053  0.3354254
## 2019-02-03 0.3322487 0.3330414  0.3347099
## 2019-02-04 0.3333185 0.3326807  0.3340008
## 2019-02-05 0.3341147 0.3326916  0.3331937
## 2019-02-06 0.3349093 0.3327025  0.3323882
## 2019-02-07 0.3357023 0.3327134  0.3315843
## 2019-02-08 0.3364938 0.3327242  0.3307820
## 2019-02-09 0.3372836 0.3327350  0.3299813
## 2019-02-10 0.3380719 0.3327458  0.3291822
## 2019-02-11 0.3388587 0.3327566  0.3283847
## 2019-02-12 0.3397594 0.3312211  0.3290195
## 2019-02-13 0.3406556 0.3296932  0.3296512
## 2019-02-14 0.3415475 0.3281727  0.3302798
## 2019-02-15 0.3424349 0.3266598  0.3309053
## 2019-02-16 0.3433181 0.3251542  0.3315277
## 2019-02-17 0.3441969 0.3236559  0.3321472
## 2019-02-18 0.3450715 0.3221649  0.3327636
## 2019-02-19 0.3455115 0.3212615  0.3332270
## 2019-02-20 0.3459494 0.3203624  0.3336883
## 2019-02-21 0.3463852 0.3194674  0.3341474
## 2019-02-22 0.3468190 0.3185766  0.3346044
# Portafolio MƔximo Sharpe (MS)
ep_m <- endpoints(roll_ms, on = rbp)
port_ms_m <- Return.portfolio(y.r_c, weights = roll_ms[ep_m, ], verbose = TRUE)
## Warning in Return.portfolio.geometric(R = R, weights = weights, wealth.index =
## wealth.index, : The weights for one or more periods do not sum up to 1:
## assuming a return of 0 for the residual weights
# Combinar retornos de todos los portafolios
port_ret_m <- cbind(
  port_eqw_m$returns,
  port_rp_m$returns,
  port_rpp_m$returns,
  port_ms_m$returns
)
colnames(port_ret_m) <- c("EQW", "RP", "RPC", "MS")
port_ret_m <- na.omit(port_ret_m)
head(port_ret_m)
##                     EQW            RP          RPC           MS
## 2019-10-01 0.0009009216 -2.314959e-06 0.0008324144 -0.001962428
## 2019-10-02 0.0009001104 -2.315402e-06 0.0008317218 -0.001966287
## 2019-10-03 0.0008993010 -2.315164e-06 0.0008310307 -0.001970161
## 2019-10-04 0.0008984931 -2.315130e-06 0.0008303408 -0.001974050
## 2019-10-05 0.0008976862 -2.315594e-06 0.0008296515 -0.001977955
## 2019-10-06 0.0008968814 -2.315136e-06 0.0008289641 -0.001981874
# EstadĆ­sticas anuales y de riesgo
ta1_m <- table.AnnualizedReturns(port_ret_m, scale = 252, geometric = TRUE, Rf = rfr)
ta2_m <- table.DownsideRisk(port_ret_m, scale = 252, Rf = rfr, MAR = 0.00, p = 0.95)
ta3_m <- Omega(port_ret_m, Rf = rfr)
sr_m  <- SortinoRatio(port_ret_m)

# Consolidar tabla resumen mensual
summary_monthly <- rbind(ta1_m, ta2_m, ta3_m, sr_m)
print(summary_monthly)
##                                      EQW         RP        RPC        MS
## Annualized Return              0.1330000  0.1101000  0.1290000  0.103200
## Annualized Std Dev             0.0490000  0.0331000  0.0475000  0.037000
## Annualized Sharpe (Rf=0.96%)   2.4926000  3.0119000  2.4924000  2.505600
## Semi Deviation                 0.0023000  0.0016000  0.0023000  0.001600
## Gain Deviation                 0.0017000  0.0012000  0.0016000  0.002100
## Loss Deviation                 0.0021000  0.0014000  0.0021000  0.002100
## Downside Deviation (MAR=0%)    0.0021000  0.0013000  0.0020000  0.001400
## Downside Deviation (Rf=0.96%)  0.0021000  0.0014000  0.0020000  0.001400
## Downside Deviation (0%)        0.0021000  0.0013000  0.0020000  0.001400
## Maximum Drawdown               0.2986000  0.1486000  0.2923000  0.090000
## Historical VaR (95%)          -0.0051000 -0.0033000 -0.0049000 -0.002600
## Historical ES (95%)           -0.0067000 -0.0044000 -0.0065000 -0.005100
## Modified VaR (95%)            -0.0049000 -0.0032000 -0.0048000 -0.003100
## Modified ES (95%)             -0.0070000 -0.0046000 -0.0066000 -0.004500
## Omega (L = 0%)                 1.5048524  1.6605752  1.5036860  1.836729
## Sortino Ratio (MAR = 0%)       0.2415943  0.3091108  0.2419175  0.282443
# Curva de rendimiento acumulado mensual
chart.CumReturns(
  port_ret_m,
  main = "Equity Curves (Monthly Rebalance)",
  ylab = "",
  geometric = TRUE,
  wealth.index = TRUE,
  legend.loc = "topleft"
)

Connectedness: TVP-VAR

Extraer medidas clave (GFEVD, TCI, TO, FROM, NET, PCI)

Portafolios: EQW, RiskParity, MinimumConnectednessPortfolio, MS

Performance summary and relación con TCI

LS0tDQp0aXRsZTogIlJldHVybiBhbmQgVm9sYXRpbGl0eSBTcGlsbG92ZXJzIEJldHdlZW4gRmluVGVjaCwgQmxvY2tjaGFpbiBhbmQgQUkgRmlybXMiDQpzdWJ0aXRsZTogIkVzdGFuY2lhIGRlIEludmVzdGlnYWNpw7NuIg0KYXV0aG9yOiAiQXZyaWwgTG9iYXRvIERlbGdhZG8iDQpkYXRlOiAiMjAyNC0xMS0wMSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KLS0tDQoNCiFbXShodHRwczovL2NpdHJpcy11Yy5vcmcvd3AtY29udGVudC91cGxvYWRzLzIwMTkvMTAvVGVjLWRlLU1vbnRlcnJleS1sb2dvLWhvcml6b250YWwtYmx1ZS5wbmcpDQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlciI+DQogIDxwPjxzdHJvbmc+VGVjbm9sw7NnaWNvIGRlIE1vbnRlcnJleTwvc3Ryb25nPjwvcD4NCiAgPHA+PHN0cm9uZz5Eb2N0b3IgVGXDs2ZpbG8gT3p1bmE8L3N0cm9uZz48L3A+DQo8L2Rpdj4NCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyIj4NCiAgPHA+PHN0cm9uZz5BbHVtbmE6PC9zdHJvbmc+PC9wPg0KDQogIEF2cmlsIExvYmF0byBEZWxnYWRvIEEwMDgzMzExMw0KIA0KPC9kaXY+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQppZiAocGFja2FnZVZlcnNpb24oInhmdW4iKSA8ICIwLjQ0Iikgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ4ZnVuIikNCn0NCg0KIyBDYXJnYSBlbCBwYXF1ZXRlIGFjdHVhbGl6YWRvDQpsaWJyYXJ5KHhmdW4pDQoNCiMgQ29uZmlndXJhY2nDs24gZGUgbG9zIGNodW5rcyBkZSBrbml0cg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KCWVjaG8gPSBUUlVFLA0KCW1lc3NhZ2UgPSBUUlVFLA0KCXdhcm5pbmcgPSBUUlVFDQopDQpgYGANCg0KIyBFREEgZGUgYmFzZSBkZSBkYXRvcw0KDQpMaWJyZXJpYXMNCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHB1cnJyKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KERhdGFFeHBsb3JlcikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRtKQ0KbGlicmFyeShjbHVzdGVyKQ0KbGlicmFyeShmYWN0b2V4dHJhKSANCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KbGlicmFyeShwdXJycikNCmxpYnJhcnkocFJPQykNCmxpYnJhcnkocnBhcnQpDQpsaWJyYXJ5KHJwYXJ0LnBsb3QpDQpsaWJyYXJ5KGUxMDcxKQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KGRsb29rcikNCmxpYnJhcnkoem9vKQ0KbGlicmFyeShjYXJldCkNCmxpYnJhcnkoc3RhdHMpDQpsaWJyYXJ5KHRzZXJpZXMpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeSh2YXJzKQ0KbGlicmFyeShzeXV6aGV0KQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHJtZ2FyY2gpDQpsaWJyYXJ5KGRldnRvb2xzKQ0KbGlicmFyeShvcGVueGxzeCkNCmxpYnJhcnkocmVsYWltcG8pDQpsaWJyYXJ5KHN0YXJnYXplcikNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcykNCmxpYnJhcnkoQ29ubmVjdGVkbmVzc0FwcHJvYWNoKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkodHNlcmllcykNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KHVyY2EpDQpsaWJyYXJ5KGZHYXJjaCkNCmxpYnJhcnkoTVRTKQ0KbGlicmFyeShNQVNTKQ0KbGlicmFyeShub3J0ZXN0KQ0KbGlicmFyeShvdXRsaWVycykNCmxpYnJhcnkobW9tZW50cykNCmxpYnJhcnkoRmluVFMpDQpsaWJyYXJ5KFdlaWdodGVkUG9ydFRlc3QpDQpgYGANCg0KIyMgQ2FyZ2EgZGUgYmFzZSBkZSBkYXRvcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgTGVlIGVsIGFyY2hpdm8gQ1NWIHkgc2VsZWNjaW9uYSBsYXMgY29sdW1uYXMgcmVsZXZhbnRlcw0KaW5kZXhfYWx0IDwtIHJlYWRfY3N2KCJDOi9Vc2Vycy9BVlJJTC9EZXNrdG9wL1NwaWxsb3ZlcnMvYWxsX2RhaWx5X2luZGV4X3JldHVybnMuY3N2IikNCmRhdGFfc2VsZWN0ZWQgPC0gaW5kZXhfYWx0WywgYygiRGF0ZSIsICJBSV9JTkRFWCIsICJGaW50ZWNoX0luZGV4IiwgIkJsb2NrY2hhaW5fSW5kZXgiKV0NCmBgYA0KDQojIyBUZXN0cyB5IEVzdGFkw61zdGljb3MgZGUgYmQgb3JpZ2luYWwNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEZ1bmN0aW9uIGZvciBzdW1tYXJ5IHN0YXRpc3RpY3MNCnN1bW1hcnlfc3RhdHMgPC0gZnVuY3Rpb24oZGF0YSkgew0KICByZXR1cm4oZGF0YS5mcmFtZSgNCiAgICBNZWFuID0gbWVhbihkYXRhLCBuYS5ybSA9IFRSVUUpLA0KICAgIFN0ZERldiA9IHNkKGRhdGEsIG5hLnJtID0gVFJVRSksDQogICAgTWluID0gbWluKGRhdGEsIG5hLnJtID0gVFJVRSksDQogICAgUDI1ID0gcXVhbnRpbGUoZGF0YSwgMC4yNSwgbmEucm0gPSBUUlVFKSwNCiAgICBQNTAgPSBtZWRpYW4oZGF0YSwgbmEucm0gPSBUUlVFKSwNCiAgICBQNzUgPSBxdWFudGlsZShkYXRhLCAwLjc1LCBuYS5ybSA9IFRSVUUpLA0KICAgIE1heCA9IG1heChkYXRhLCBuYS5ybSA9IFRSVUUpLA0KICAgIFNrZXduZXNzID0gc2tld25lc3MoZGF0YSwgbmEucm0gPSBUUlVFKSwNCiAgICBLdXJ0b3NpcyA9IGt1cnRvc2lzKGRhdGEsIG5hLnJtID0gVFJVRSkNCiAgKSkNCn0NCg0KIyBDYWxjdWxhdGUgc3RhdGlzdGljcyBhbmQgdGVzdHMgZm9yIGVhY2ggaW5kZXgNCnJlc3VsdHMgPC0gZGF0YS5mcmFtZSgNCiAgVGVzdCA9IGMoDQogICAgIk1lYW4iLCAiU3RhbmRhcmQgRGV2aWF0aW9uIiwgIk1pbmltdW0iLCAiMjV0aCBQZXJjZW50aWxlIiwgIk1lZGlhbiIsDQogICAgIjc1dGggUGVyY2VudGlsZSIsICJNYXhpbXVtIiwgIlNrZXduZXNzIiwgIkt1cnRvc2lzIiwgIkphcnF1ZS1CZXJhIChwLXZhbHVlKSIsDQogICAgIkFERiBUZXN0IChwLXZhbHVlKSIsICJLUFNTIFRlc3QgKHAtdmFsdWUpIiwgIlBQIFRlc3QgKHAtdmFsdWUpIiwgIkVSUyBUZXN0IiwNCiAgICAiQVJDSCBUZXN0IChwLXZhbHVlKSIsICJXZWlnaHRlZCBQb3J0bWFudGVhdSBUZXN0IChwLXZhbHVlKSIsICJRMigyMCkgVGVzdCAocC12YWx1ZSkiLA0KICAgICJPdXRsaWVyIGRldGVjdGlvbiAoQ2hlbiBhbmQgTGl1KSIsIkNvcnJlbGF0aW9uIE1hdHJpeCBhbmQgUi1zcXVhcmVkIg0KICApLA0KICBBSV9JTkRFWCA9IE5BLCBGaW50ZWNoX0luZGV4ID0gTkEsIEJsb2NrY2hhaW5fSW5kZXggPSBOQQ0KKQ0KDQojIFBvcHVsYXRlIHRoZSB0YWJsZSB3aXRoIHN1bW1hcnkgc3RhdHMNCnN0YXRzX2FpIDwtIHN1bW1hcnlfc3RhdHMoZGF0YV9zZWxlY3RlZCRBSV9JTkRFWCkNCnN0YXRzX2ZpbnRlY2ggPC0gc3VtbWFyeV9zdGF0cyhkYXRhX3NlbGVjdGVkJEZpbnRlY2hfSW5kZXgpDQpzdGF0c19ibG9ja2NoYWluIDwtIHN1bW1hcnlfc3RhdHMoZGF0YV9zZWxlY3RlZCRCbG9ja2NoYWluX0luZGV4KQ0KcmVzdWx0cyRBSV9JTkRFWFsxOjldIDwtIGFzLm51bWVyaWMoc3RhdHNfYWkpDQpyZXN1bHRzJEZpbnRlY2hfSW5kZXhbMTo5XSA8LSBhcy5udW1lcmljKHN0YXRzX2ZpbnRlY2gpDQpyZXN1bHRzJEJsb2NrY2hhaW5fSW5kZXhbMTo5XSA8LSBhcy5udW1lcmljKHN0YXRzX2Jsb2NrY2hhaW4pDQoNCiMgTm9ybWFsaXR5IGFuZCBzdGF0aW9uYXJpdHkgdGVzdHMNCnJlc3VsdHMkQUlfSU5ERVhbMTBdIDwtIGphcnF1ZS5iZXJhLnRlc3QoZGF0YV9zZWxlY3RlZCRBSV9JTkRFWCkkcC52YWx1ZQ0KcmVzdWx0cyRGaW50ZWNoX0luZGV4WzEwXSA8LSBqYXJxdWUuYmVyYS50ZXN0KGRhdGFfc2VsZWN0ZWQkRmludGVjaF9JbmRleCkkcC52YWx1ZQ0KcmVzdWx0cyRCbG9ja2NoYWluX0luZGV4WzEwXSA8LSBqYXJxdWUuYmVyYS50ZXN0KGRhdGFfc2VsZWN0ZWQkQmxvY2tjaGFpbl9JbmRleCkkcC52YWx1ZQ0KDQpyZXN1bHRzJEFJX0lOREVYWzExXSA8LSBhZGYudGVzdChkYXRhX3NlbGVjdGVkJEFJX0lOREVYKSRwLnZhbHVlDQpyZXN1bHRzJEZpbnRlY2hfSW5kZXhbMTFdIDwtIGFkZi50ZXN0KGRhdGFfc2VsZWN0ZWQkRmludGVjaF9JbmRleCkkcC52YWx1ZQ0KcmVzdWx0cyRCbG9ja2NoYWluX0luZGV4WzExXSA8LSBhZGYudGVzdChkYXRhX3NlbGVjdGVkJEJsb2NrY2hhaW5fSW5kZXgpJHAudmFsdWUNCg0KcmVzdWx0cyRBSV9JTkRFWFsxMl0gPC0ga3Bzcy50ZXN0KGRhdGFfc2VsZWN0ZWQkQUlfSU5ERVgpJHAudmFsdWUNCnJlc3VsdHMkRmludGVjaF9JbmRleFsxMl0gPC0ga3Bzcy50ZXN0KGRhdGFfc2VsZWN0ZWQkRmludGVjaF9JbmRleCkkcC52YWx1ZQ0KcmVzdWx0cyRCbG9ja2NoYWluX0luZGV4WzEyXSA8LSBrcHNzLnRlc3QoZGF0YV9zZWxlY3RlZCRCbG9ja2NoYWluX0luZGV4KSRwLnZhbHVlDQoNCnJlc3VsdHMkQUlfSU5ERVhbMTNdIDwtIHBwLnRlc3QoZGF0YV9zZWxlY3RlZCRBSV9JTkRFWCkkcC52YWx1ZQ0KcmVzdWx0cyRGaW50ZWNoX0luZGV4WzEzXSA8LSBwcC50ZXN0KGRhdGFfc2VsZWN0ZWQkRmludGVjaF9JbmRleCkkcC52YWx1ZQ0KcmVzdWx0cyRCbG9ja2NoYWluX0luZGV4WzEzXSA8LSBwcC50ZXN0KGRhdGFfc2VsZWN0ZWQkQmxvY2tjaGFpbl9JbmRleCkkcC52YWx1ZQ0KDQpyZXN1bHRzJEFJX0lOREVYWzE0XSA8LSB1ci5lcnMoZGF0YV9zZWxlY3RlZCRBSV9JTkRFWCwgdHlwZSA9ICJERi1HTFMiKUB0ZXN0c3RhdA0KcmVzdWx0cyRGaW50ZWNoX0luZGV4WzE0XSA8LSB1ci5lcnMoZGF0YV9zZWxlY3RlZCRGaW50ZWNoX0luZGV4LCB0eXBlID0gIkRGLUdMUyIpQHRlc3RzdGF0DQpyZXN1bHRzJEJsb2NrY2hhaW5fSW5kZXhbMTRdIDwtIHVyLmVycyhkYXRhX3NlbGVjdGVkJEJsb2NrY2hhaW5fSW5kZXgsIHR5cGUgPSAiREYtR0xTIilAdGVzdHN0YXQNCg0KIyBBUkNIIHRlc3QNCnJlc3VsdHMkQUlfSU5ERVhbMTVdIDwtIEFyY2hUZXN0KGRhdGFfc2VsZWN0ZWQkQUlfSU5ERVgpJHAudmFsdWUNCnJlc3VsdHMkRmludGVjaF9JbmRleFsxNV0gPC0gQXJjaFRlc3QoZGF0YV9zZWxlY3RlZCRGaW50ZWNoX0luZGV4KSRwLnZhbHVlDQpyZXN1bHRzJEJsb2NrY2hhaW5fSW5kZXhbMTVdIDwtIEFyY2hUZXN0KGRhdGFfc2VsZWN0ZWQkQmxvY2tjaGFpbl9JbmRleCkkcC52YWx1ZQ0KDQojIFBvcnRtYW50ZWF1IHRlc3QNCnJlc3VsdHMkcG9ydG1hbnRlYXVfYWkgPC0gV2VpZ2h0ZWQuQm94LnRlc3QoZGF0YV9zZWxlY3RlZCRBSV9JTkRFWCkkcC52YWx1ZQ0KcmVzdWx0cyRwb3J0bWFudGVhdV9maW50ZWNoIDwtIFdlaWdodGVkLkJveC50ZXN0KGRhdGFfc2VsZWN0ZWQkRmludGVjaF9JbmRleCkkcC52YWx1ZQ0KcmVzdWx0cyRwb3J0bWFudGVhdV9ibG9ja2NoYWluIDwtIFdlaWdodGVkLkJveC50ZXN0KGRhdGFfc2VsZWN0ZWQkQmxvY2tjaGFpbl9JbmRleCkkcC52YWx1ZQ0KDQojIFEyKDIwKSB0ZXN0DQpyZXN1bHRzJEFJX0lOREVYWzE3XSA8LSBCb3gudGVzdChkYXRhX3NlbGVjdGVkJEFJX0lOREVYXjIsIGxhZyA9IDIwLCB0eXBlID0gIkxqdW5nLUJveCIpJHAudmFsdWUNCnJlc3VsdHMkRmludGVjaF9JbmRleFsxN10gPC0gQm94LnRlc3QoZGF0YV9zZWxlY3RlZCRGaW50ZWNoX0luZGV4XjIsIGxhZyA9IDIwLCB0eXBlID0gIkxqdW5nLUJveCIpJHAudmFsdWUNCnJlc3VsdHMkQmxvY2tjaGFpbl9JbmRleFsxN10gPC0gQm94LnRlc3QoZGF0YV9zZWxlY3RlZCRCbG9ja2NoYWluX0luZGV4XjIsIGxhZyA9IDIwLCB0eXBlID0gIkxqdW5nLUJveCIpJHAudmFsdWUNCg0KIyBPdXRsaWVyIGRldGVjdGlvbiAoQ2hlbiBhbmQgTGl1KQ0KcmVzdWx0cyRvdXRsaWVyc19haSA8LSBzdW0oc2NvcmVzKGRhdGFfc2VsZWN0ZWQkQUlfSU5ERVgsIHR5cGUgPSAiY2hpc3EiLCBwcm9iID0gMC4wNSkgIT0gMCkNCnJlc3VsdHMkb3V0bGllcnNfZmludGVjaCA8LSBzdW0oc2NvcmVzKGRhdGFfc2VsZWN0ZWQkRmludGVjaF9JbmRleCwgdHlwZSA9ICJjaGlzcSIsIHByb2IgPSAwLjA1KSAhPSAwKQ0KcmVzdWx0cyRvdXRsaWVyc19ibG9ja2NoYWluIDwtIHN1bShzY29yZXMoZGF0YV9zZWxlY3RlZCRCbG9ja2NoYWluX0luZGV4LCB0eXBlID0gImNoaXNxIiwgcHJvYiA9IDAuMDUpICE9IDApDQoNCiMgQ29ycmVsYXRpb24gTWF0cml4IGFuZCBSLXNxdWFyZWQNCmNvcl9tYXRyaXggPC0gY29yKGRhdGFfc2VsZWN0ZWRbLCAtMV0sIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0Kcl9zcXVhcmVkIDwtIGNvcl9tYXRyaXheMg0KDQpwcmludChyZXN1bHRzKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDb252ZXJ0aXIgbGEgY29sdW1uYSBgRGF0ZWAgYSB0aXBvIERhdGUgc2kgZXN0w6EgZW4gZm9ybWF0byAiZGQvbW0veXl5eSINCmluZGV4X2FsdCREYXRlIDwtIGFzLkRhdGUoaW5kZXhfYWx0JERhdGUsIGZvcm1hdCA9ICIlZC8lbS8lWSIpDQoNCiMgTW9zdHJhciBlc3RydWN0dXJhIHkgcmVzdW1lbg0Kc3RyKGluZGV4X2FsdCkNCnN1bW1hcnkoaW5kZXhfYWx0KQ0KYGBgDQoNCiMgKipDaGF0emlhbnRvbmlvdSwgR2FiYXVlciAmIEd1cHRhICgyMDIxKToqKiBJbnRlZ3JhdGlvbiBhbmQgcmlzayB0cmFuc21pc3Npb24gaW4gdGhlIG1hcmtldCBmb3IgY3J1ZGUgb2lsOiBBIHRpbWUtdmFyeWluZyBwYXJhbWV0ZXIgZnJlcXVlbmN5IGNvbm5lY3RlZG5lc3MgYXBwcm9hY2gNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIENvbnZlcnRpciBhIG9iamV0byB6b28NCmRhdGFfc2VsZWN0ZWQgPC0gaW5kZXhfYWx0WywgYygiRGF0ZSIsIkFJX0lOREVYIiwgIkZpbnRlY2hfSW5kZXgiLCAiQmxvY2tjaGFpbl9JbmRleCIpXQ0KDQpkYXRhX21hdHJpeCA8LSBhcy5tYXRyaXgoZGF0YV9zZWxlY3RlZCkNCg0KZGF0YV96b28gPC0gem9vKGRhdGFfc2VsZWN0ZWRbLCAtMV0sIG9yZGVyLmJ5ID0gZGF0YV9zZWxlY3RlZCREYXRlKQ0KDQojIEluc3RhbGFyIHkgY2FyZ2FyIGVsIHBhcXVldGUgQ29ubmVjdGVkbmVzc0FwcHJvYWNoLCBzaSBubyBlc3TDoSB5YSBpbnN0YWxhZG8NCmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQ29ubmVjdGVkbmVzc0FwcHJvYWNoIiwgcXVpZXRseSA9IFRSVUUpKSB7DQogIGlmICghcmVxdWlyZU5hbWVzcGFjZSgiZGV2dG9vbHMiLCBxdWlldGx5ID0gVFJVRSkpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpDQogIH0NCiAgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJHYWJhdWVyRGF2aWQvQ29ubmVjdGVkbmVzc0FwcHJvYWNoIikNCn0NCmxpYnJhcnkoQ29ubmVjdGVkbmVzc0FwcHJvYWNoKQ0KDQojIENvbmZpZ3VyYWNpw7NuIGRlIHBhcsOhbWV0cm9zIHBhcmEgVFZQVkFSDQpubGFnIDwtIDIgICAgICAgIyBPcmRlbiBkZWwgcmV6YWdvDQpsYW1iZGEgPC0gYygwLjk5LCAwLjk5KSAgIyBWYWxvcmVzIGRlIGRlY2FpbWllbnRvIHBhcmEgZWwgZmlsdHJvDQoNCiMgQ3JlYXIgbGEgbGlzdGEgZGUgY29uZmlndXJhY2nDs24gbmVjZXNhcmlhDQpjb25maWcgPC0gbGlzdChsID0gbGFtYmRhLCBubGFnID0gbmxhZykNCg0KIyBFc3RpbWFyIGVsIG1vZGVsbyBUVlAtVkFSIGNvbiBsb3MgcGFyw6FtZXRyb3MgZXNwZWNpZmljYWRvcw0KdHZwdmFyX21vZGVsIDwtIFRWUFZBUihkYXRhX3pvbywgY29uZmlndXJhdGlvbiA9IGNvbmZpZykNCmBgYA0KDQojIyBUYWJsZSAyOiBBdmVyYWdlZCBDb25uZWN0ZWRuZXNzIFRhYmxlDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGFydGl0aW9uID0gYyhwaSswLjAwMDAxLCBwaS81LCAwKQ0KZGNhID0gQ29ubmVjdGVkbmVzc0FwcHJvYWNoKGRhdGFfem9vLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbD0iVFZQLVZBUiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGVkbmVzcz0iRnJlcXVlbmN5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGFnPTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmZvcmU9MTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zaXplPTIwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWQVJfY29uZmlnPWxpc3QoVFZQVkFSPWxpc3Qoa2FwcGExPTAuOTksIGthcHBhMj0wLjk5LCBwcmlvcj0iQmF5ZXNQcmlvciIpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBDb25uZWN0ZWRuZXNzX2NvbmZpZyA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGcmVxdWVuY3lDb25uZWN0ZWRuZXNzPWxpc3QocGFydGl0aW9uPXBhcnRpdGlvbiwgZ2VuZXJhbGl6ZWQ9VFJVRSwgc2NlbmFyaW89IkFCUyIpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgKSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Ka2FibGUoZGNhJFRBQkxFKQ0KYGBgDQoNCiMjIEZpZ3VyZSA0OiBOZXQgVG90YWwgRGlyZWN0aW9uYWwgQ29ubmVjdGVkbmVzcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NClBsb3RORVQoZGNhLCB5bGltPWMoLTYwLDYwKSkNCmBgYA0KDQoNCg0KIyAqKkdhYmF1ZXIgYW5kIEd1cHRhICgyMDE4KTogKiogT24gdGhlIHRyYW5zbWlzc2lvbiBtZWNoYW5pc20gb2YgY291bnRyeS1zcGVjaWZpYyBhbmQgaW50ZXJuYXRpb25hbCBlY29ub21pYyB1bmNlcnRhaW50eSBzcGlsbG92ZXJzOiBFdmlkZW5jZSBmcm9tIGEgVFZQLVZBUiBjb25uZWN0ZWRuZXNzIGRlY29tcG9zaXRpb24gYXBwcm9hY2gNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRhdGFfem9vMiA8LSB6b28oZGF0YV9zZWxlY3RlZFssIGMoIkFJX0lOREVYIiwgIkZpbnRlY2hfSW5kZXgiLCAiQmxvY2tjaGFpbl9JbmRleCIpXSwgDQogICAgICAgICAgICAgICAgIG9yZGVyLmJ5ID0gZGF0YV9zZWxlY3RlZCREYXRlKQ0KDQojIENvbmZpZ3VyYWNpw7NuIGRlIHBhcsOhbWV0cm9zIHBhcmEgVFZQVkFSDQpubGFnIDwtIDIgICAgICAgIyBPcmRlbiBkZWwgcmV6YWdvDQpsYW1iZGEgPC0gYygwLjk5LCAwLjk5KSAgIyBWYWxvcmVzIGRlIGRlY2FpbWllbnRvIHBhcmEgZWwgZmlsdHJvDQoNCiMgQ3JlYXIgbGEgbGlzdGEgZGUgY29uZmlndXJhY2nDs24gbmVjZXNhcmlhDQpjb25maWcgPC0gbGlzdChsID0gbGFtYmRhLCBubGFnID0gbmxhZykNCg0KIyBFc3RpbWFyIGVsIG1vZGVsbyBUVlAtVkFSIGNvbiBsb3MgcGFyw6FtZXRyb3MgZXNwZWNpZmljYWRvcw0KdHZwdmFyX21vZGVsIDwtIFRWUFZBUihkYXRhX3pvbzIsIGNvbmZpZ3VyYXRpb24gPSBjb25maWcpDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRjYSA9IENvbm5lY3RlZG5lc3NBcHByb2FjaChkYXRhX3pvbzIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5sYWc9MSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZm9yZT0xMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbD0iVFZQLVZBUiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ubmVjdGVkbmVzcz0iVGltZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93LnNpemU9MjAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZBUl9jb25maWc9bGlzdChUVlBWQVI9bGlzdChrYXBwYTE9MC45OSwga2FwcGEyPTAuOTksIHByaW9yPSJCYXllc1ByaW9yIikpKQ0KYGBgDQoNCiMjIFRhYmxlIDE6IENvbm5lY3RlZG5lc3MgdGFibGUNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQprYWJsZShkY2EkVEFCTEUpDQojIENPTk5FQ1RFRE5FU1MgREVDT01QT1NJVElPTg0KaW50ID0gSW50ZXJuYWxDb25uZWN0ZWRuZXNzKGRjYSwgZ3JvdXBzPWxpc3QoIkdyb3VwMSI9YygxKSwgIkdyb3VwMiI9YygyKSwgIkdyb3VwMyI9YygzKSkpDQpleHQgPSBFeHRlcm5hbENvbm5lY3RlZG5lc3MoZGNhLCBncm91cHM9bGlzdCgiR3JvdXAxIj1jKDEpLCAiR3JvdXAyIj1jKDIpLCAiR3JvdXAzIj1jKDMpKSkNCmthYmxlKGludCRUQUJMRSkNCmthYmxlKGV4dCRUQUJMRSkNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojRmlndXJlIDM6IER5bmFtaWMgdG90YWwgY29ubmVjdGVkbmVzcw0KUGxvdFRDSShkY2EsIGludCwgeWxpbT1jKDAsIDQwKSkNCg0KI0ZpZ3VyZSA0OiBOZXQgdG90YWwgZGlyZWN0aW9uYWwgY29ubmVjdGVkbmVzcw0KUGxvdE5FVChkY2EsIGludCwgeWxpbT1jKC0xMCwgMTApKQ0KDQojRmlndXJlIDU6IFRvdGFsIGRpcmVjdGlvbmFsIGNvbm5lY3RlZG5lc3MgRlJPTSBvdGhlcnMNClBsb3RGUk9NKGRjYSwgaW50LCB5bGltPWMoMCwgNjApKQ0KDQojRmlndXJlIDY6IFRvdGFsIGRpcmVjdGlvbmFsIGNvbm5lY3RlZG5lc3MgVE8gb3RoZXJzDQpQbG90VE8oZGNhLCBpbnQsIHlsaW09YygwLCA2MCkpDQoNCiNGaWd1cmUgNzogSW50ZXJuYWwgbmV0IHBhaXJ3aXNlIHRvdGFsIGRpcmVjdGlvbmFsIGNvbm5lY3RlZG5lc3MNClBsb3ROUERDKGRjYSwgaW50LCB5bGltPWMoLTUsIDUpKQ0KYGBgDQoNCiMgKipDb2NjYSwgR2FiYXVlciwgYW5kIFBvbWJlcmdlciAoMjAyNCk6KiogQ2xlYW4gZW5lcmd5IG1hcmtldCBjb25uZWN0ZWRuZXNzIGFuZCBpbnZlc3RtZW50IHN0cmF0ZWdpZXM6IE5ldyBldmlkZW5jZSBmcm9tIERDQy1HQVJDSCBSMiBkZWNvbXBvc2VkIGNvbm5lY3RlZG5lc3MgbWVhc3VyZXMNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIENvbnZpZXJ0ZSBsYSBjb2x1bW5hICdEYXRlJyBhIGZvcm1hdG8gRGF0ZQ0KZGF0ZSA8LSBhcy5EYXRlKGRhdGFfc2VsZWN0ZWQkRGF0ZSwgZm9ybWF0PSIlZC8lbS8lWSIpDQoNCiMgQ3JlYSBsYSBzZXJpZSBkZSB0aWVtcG8gKHpvbykgc29sbyBjb24gbGFzIGNvbHVtbmFzIHNlbGVjY2lvbmFkYXMNClkgPC0gem9vKGRhdGFfc2VsZWN0ZWRbLCBjKCJGaW50ZWNoX0luZGV4IiwgIkFJX0lOREVYIiwgIkJsb2NrY2hhaW5fSW5kZXgiKV0sIG9yZGVyLmJ5ID0gZGF0ZSkNCg0KIyBBc2Vnw7pyYXRlIGRlIHF1ZSBsb3MgZGF0b3Mgc2VhbiBudW3DqXJpY29zIHkgZWxpbWluYSB2YWxvcmVzIE5BDQpZIDwtIG5hLm9taXQoem9vKGRhdGEuZnJhbWUoDQogIEZpbnRlY2hfSW5kZXhfZGlmZiA9IGFzLm51bWVyaWMoZGF0YV9zZWxlY3RlZCRGaW50ZWNoX0luZGV4KSwNCiAgQUlfSU5ERVhfZGlmZiA9IGFzLm51bWVyaWMoZGF0YV9zZWxlY3RlZCRBSV9JTkRFWCksDQogIEJsb2NrY2hhaW5fSW5kZXhfZGlmZiA9IGFzLm51bWVyaWMoZGF0YV9zZWxlY3RlZCRCbG9ja2NoYWluX0luZGV4KQ0KKSwgb3JkZXIuYnkgPSBkYXRlKSkNCg0KIyBSZWVtcGxhemEgbG9zIHZhbG9yZXMgTkEgcmVzdGFudGVzIHBvciAwDQpZW2lzLm5hKFkpXSA8LSAwDQoNCiMgRXN0YWJsZWNlICdkaW1uYW1lcycgZGUgWSBjb24gbsO6bWVyb3MgY29tbyDDrW5kaWNlcyAoY29tbyBlbiBZMikgc2luIGNhbWJpYXIgZWwgw61uZGljZSBkZSBmZWNoYQ0KZGltbmFtZXMoWSkgPC0gbGlzdChhcy5jaGFyYWN0ZXIoMTpucm93KFkpKSwgY29sbmFtZXMoWSkpDQoNCk5BTUVTID0gY29sbmFtZXMoWSkNCmsgPSBuY29sKFkpDQp0ID0gbnJvdyhZKQ0KDQojIFZlcmlmaWNhIGxhIGVzdHJ1Y3R1cmEgZGUgWQ0Kc3RyKFkpDQoNCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Ka2FibGUoU3VtbWFyeVN0YXRpc3RpY3MoWSwgbmxhZz0yMCkpDQpgYGANCg0KIyMgRmlndXJlIDA6IFBlcmNlbnRhZ2UgY2hhbmdlcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBhcihtZmNvbCA9IGMoY2VpbGluZyhrLzIpLDIpLCBvbWEgPSBjKDAsIDEsIDAsIDApICsgMC41LCBtYXIgPSBjKDEsIDEsIDEsIDEpICsgMC41LCBtZ3AgPSBjKDEsIDAuNCwgMCkpDQpmb3IgKGkgaW4gMTprKSB7DQogIHBsb3QoZGF0ZSxZWyxpXSx0eXBlPSdsJyxsYXM9MSx4YXhzPSdpJyx5YXhzPSdpJyx5bGltPWMoLTAuMSwwLjEpLHhsYWI9JycseWxhYj0nJyxtYWluPXBhc3RlKE5BTUVTW2ldKSx0Y2s9LS4wMixjb2w9J3N0ZWVsYmx1ZTQnKQ0KICBncmlkKE5BLE5VTEwpDQogIGxpbmVzKGRhdGUsWVssaV0sY29sPSdzdGVlbGJsdWU0JykNCiAgYWJsaW5lKGg9MCxsdHk9MykNCiAgYm94KCkNCn0NCmBgYA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc3BlYyA8LSBsaXN0KCkNCg0KIyBJdGVyYSBzb2JyZSBjYWRhIGNvbHVtbmEgZGUgWQ0KZm9yIChpIGluIDE6aykgew0KICAjIEludGVudGEgc2VsZWNjaW9uYXIgZWwgbWVqb3IgbW9kZWxvIEdBUkNIIHBhcmEgY2FkYSBzZXJpZQ0KICB1IDwtIHRyeUNhdGNoKHsNCiAgICBHQVJDSHNlbGVjdGlvbihZWywgaV0sDQogICAgICAgICAgICAgICAgICAgZGlzdHJpYnV0aW9ucyA9IGMoIm5vcm0iLCAic3RkIiwgInNzdGQiLCAiZ2VkIiwgInNnZWQiKSwNCiAgICAgICAgICAgICAgICAgICBtb2RlbHMgPSBjKCJzR0FSQ0giLCAiZ2pyR0FSQ0giLCAiZUdBUkNIIiwgImlHQVJDSCIsICJBVkdBUkNIIiwgIlRHQVJDSCIpKQ0KICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsNCiAgICB3YXJuaW5nKHBhc3RlKCJFcnJvciBhbCBzZWxlY2Npb25hciBtb2RlbG8gR0FSQ0ggcGFyYSBsYSB2YXJpYWJsZSIsIGksICI6IiwgZSRtZXNzYWdlKSkNCiAgICBOVUxMDQogIH0pDQogIA0KICAjIFNpICd1JyBubyBlcyBOVUxMIHkgdGllbmUgdW4gbWVqb3IgbW9kZWxvLCBhZ3JlZ2EgYSAnc3BlYycNCiAgaWYgKCFpcy5udWxsKHUpICYmICFpcy5udWxsKHUkYmVzdF91Z2FyY2gpKSB7DQogICAgc3BlY1tbaV1dIDwtIHUkYmVzdF91Z2FyY2gNCiAgfSBlbHNlIHsNCiAgICAjIFNpIG5vIHNlIHNlbGVjY2lvbsOzIHVuIG1vZGVsbywgYXNpZ25hIHVuIG1vZGVsbyBHQVJDSCgxLDEpIHBvciBkZWZlY3RvDQogICAgd2FybmluZyhwYXN0ZSgiTm8gc2Ugc2VsZWNjaW9uw7MgbmluZ8O6biBtb2RlbG8gR0FSQ0ggcGFyYSIsIE5BTUVTW2ldLCAiLiBVc2FuZG8gbW9kZWxvIEdBUkNIKDEsMSkgY29uIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIikpDQogICAgc3BlY1tbaV1dIDwtIHVnYXJjaHNwZWModmFyaWFuY2UubW9kZWwgPSBsaXN0KG1vZGVsID0gInNHQVJDSCIsIGdhcmNoT3JkZXIgPSBjKDEsIDEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuLm1vZGVsID0gbGlzdChhcm1hT3JkZXIgPSBjKDAsIDApKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXN0cmlidXRpb24ubW9kZWwgPSAibm9ybSIpDQogIH0NCn0NCg0KIyBWZXJpZmljYSBxdWUgJ3NwZWMnIHRlbmdhIG1vZGVsb3MgcGFyYSBjYWRhIHNlcmllIGVuIFkNCmlmIChsZW5ndGgoc3BlYykgIT0gaykgew0KICBzdG9wKCJzcGVjIG5vIGNvbnRpZW5lIG1vZGVsb3MgdsOhbGlkb3MgcGFyYSB0b2RhcyBsYXMgc2VyaWVzIGRlIFkiKQ0KfQ0KDQojIEVqZWN1dGEgZWwgbW9kZWxvIERDQy1HQVJDSCBzaSBzcGVjIGVzIHbDoWxpZGENCmZpdCA8LSBCaXZhcmlhdGVEQ0NHQVJDSChZLCBzcGVjKQ0KYGBgDQoNCiMjIFRhYmxlIDQ6IEV2YWx1YXRpb24gb2YgdW5pdmFyaWF0ZSBHQVJDSCBwZXJmb3JtYW5jZQ0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkggPSBmaXQkSF90DQpSID0gZml0JFJfdA0KDQp1R0FSQ0hfdGFibGUgPSBOVUxMDQpmb3IgKGkgaW4gMTprKSB7DQogIGZpdCA9IHVnYXJjaGZpdChzcGVjW1tpXV0sIFlbLGldKQ0KICBndCA9IEdBUkNIdGVzdHMoZml0LCBsYWc9MjApDQogIHVHQVJDSF90YWJsZSA9IHJiaW5kKHVHQVJDSF90YWJsZSwgZ3QkVEFCTEUpDQp9DQoNCmthYmxlKHVHQVJDSF90YWJsZSkNCmBgYA0KDQoNCiMjIEZpZ3VyZSAzOiBEeW5hbWljIGNvbmRpdGlvbmFsIGNvcnJlbGF0aW9ucw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBhcihtZmNvbCA9IGMoY2VpbGluZyhrLzIpLDIpLCBvbWEgPSBjKDAsIDEsIDAsIDApICsgMC41LCBtYXIgPSBjKDEsIDEsIDEsIDEpICsgMC41LCBtZ3AgPSBjKDEsIDAuNCwgMCkpDQpmb3IgKGogaW4gMTprKSB7DQogIHBsb3QoZGF0ZSxSW2osaixdLHR5cGU9J2wnLGxhcz0xLHhheHM9J2knLHlheHM9J2knLHhsYWI9JycseWxhYj0nJyxtYWluPXBhc3RlKE5BTUVTW2pdKSx0Y2s9LS4wMixjb2w9aix5bGltPWMoLTEuMSwxLjEpKQ0KICBncmlkKE5BLE5VTEwpDQogIGZvciAoaSBpbiAxOmspIHsNCiAgICBsaW5lcyhkYXRlLFJbaixpLF0sY29sPWkpDQogICAgYWJsaW5lKGg9MCxsdHk9MykNCiAgICBib3goKQ0KICB9DQogIGxlZ2VuZCgiYm90dG9tIixOQU1FU1stal0sZmlsbD1jKDE6aylbLWpdLGJ0eT0ibiIsY2V4PTAuNzUsbmNvbD1rKQ0KfQ0KYGBgDQoNCg0KIyMgVGFibGUgNTogQXZlcmFnZWQgY29ubmVjdGVkbmVzcyBtZWFzdXJlcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRjYSA9IFIyQ29ycmVsYXRpb25zKFIpDQprYWJsZShkY2EkVEFCTEUpDQpgYGANCg0KIyMgRmlndXJlIDQ6IER5bmFtaWMgY29uZGl0aW9uYWwgUjIgZGVjb21wb3NlZCBtZWFzdXJlcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnIyYyA9IGFwcGx5KGRjYSRDVCxjKDEsMyksc3VtKS0xDQpwYXIobWZjb2wgPSBjKGNlaWxpbmcoay8yKSwyKSwgb21hID0gYygwLCAxLCAwLCAwKSArIDAuNSwgbWFyID0gYygxLCAxLCAxLCAxKSArIDAuNSwgbWdwID0gYygxLCAwLjQsIDApKQ0KZm9yIChqIGluIDE6aykgew0KICByMmRkID0gbWF0cml4KDAsbmNvbD1rLG5yb3c9dCkNCiAgZm9yIChpIGluIDE6dCkgew0KICAgIGRlZCA9IHJlcCgwLGspDQogICAgZGVkW2pdID0gMQ0KICAgIHIyZGRbaSxdID0gY3Vtc3VtKGRjYSRDVFtqLCxpXS1kZWQpDQogIH0NCiAgcGxvdChkYXRlLDEwMCpyMmNbaixdKk5BLHR5cGU9ImwiLGxhcz0xLHhsYWI9IiIseWxhYj0iIix5bGltPWMoMCwxMDApLHhheHM9ImkiLHRjaz0tMC4wMSx5YXhzPSJpIixtYWluPU5BTUVTW2pdKQ0KICBncmlkKE5BLE5VTEwpDQogIGZvciAoaSBpbiBrOjEpIHsNCiAgICBwb2x5Z29uKGMoZGF0ZSwgcmV2KGRhdGUpKSwgYyhjKHJlcCgwLCB0KSksIHJldigxMDAqcjJkZFssaV0pKSwgY29sPWksIGJvcmRlcj1pKQ0KICB9DQogIGJveCgpDQogIGxlZ2VuZCgidG9wbGVmdCIsTkFNRVNbLWpdLGZpbGw9YygxOmspWy1qXSxidHk9Im4iLGNleD0wLjc1LG5jb2w9MSkNCn0NCmBgYA0KDQojIyBGaWd1cmUgNTogRHluYW1pYyB0b3RhbCBjb25uZWN0ZWRuZXNzDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGFyKG1mY29sID0gYygxLDEpLCBvbWEgPSBjKDAsIDEsIDAsIDApICsgMC41LCBtYXIgPSBjKDEsIDEsIDEsIDEpICsgMC41LCBtZ3AgPSBjKDEsIDAuNCwgMCkpDQpwbG90KGRhdGUsZGNhJFRDSSpOQSx0eXBlPSdsJyxsYXM9MSx4YXhzPSdpJyx5YXhzPSdpJyx4bGFiPScnLHlsYWI9JycsbWFpbj0nJyx0Y2s9LS4wMSwgeWxpbT1jKDAsMTEwKSkjYyhtYXgoYygwLG1pbihUQ0kpLTEwKSksbWF4KFRDSSkrMTApKQ0KZ3JpZChOQSxOVUxMKQ0KcG9seWdvbihjKGRhdGUsIHJldihkYXRlKSksIGMoYyhyZXAoMCwgdCkpLCByZXYoZGNhJFRDSSkpLCBjb2w9MSwgYm9yZGVyPTEpDQpib3goKQ0KYGBgDQoNCiMjIEZpZ3VyZSA2OiBOZXQgdG90YWwgZGlyZWN0aW9uYWwgY29ubmVjdGVkbmVzcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBhcihtZmNvbCA9IGMoY2VpbGluZyhrLzIpLDIpLCBvbWEgPSBjKDAsIDAsIDAsIDApICsgMC41LCBtYXIgPSBjKDEsIDEsIDEsIDEpICsgMC41LCBtZ3AgPSBjKDEsIDAuNCwgMCkpDQpmb3IgKGkgaW4gMTprKSB7DQogIHBsb3QoZGF0ZSxkY2EkTkVUWyxpXSpOQSx0eXBlPSdsJyxsYXM9MSx4YXhzPSdpJyx5YXhzPSdpJyx5bGltPWMoLTIwLDIwKSx4bGFiPScnLHlsYWI9JycsbWFpbj1wYXN0ZSgiTkVUIixOQU1FU1tpXSksdGNrPS0uMDI1KQ0KICBncmlkKE5BLE5VTEwpDQogIHBvbHlnb24oYyhkYXRlLCByZXYoZGF0ZSkpLCBjKGMocmVwKDAsIHQpKSwgcmV2KGRjYSRORVRbLGldKSksIGNvbD0xLCBib3JkZXI9MSkNCiAgYWJsaW5lKGg9MCxsdHk9MykNCiAgYm94KCkNCn0NCmBgYA0KDQoNCiMjIFRhYmxlIDc6IEhlZGdlIHJhdGlvcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCm1ldGhvZCA9ICJjdW1zdW0iDQpzdGF0aXN0aWNzID0gIkZpc2hlciINCm1ldHJpYyA9ICJTdGREZXYiDQpociA9IEhlZGdlUmF0aW8oWS8xMDAsIEgsIHN0YXRpc3RpY3M9c3RhdGlzdGljcywgbWV0aG9kPW1ldGhvZCwgbWV0cmljPW1ldHJpYywgZGlnaXQ9MykNCmthYmxlKGhyJFRBQkxFKQ0KYGBgDQoNCiMjIFRhYmxlIDg6IE11bHRpdmFyaWF0ZSBoZWRnaW5nIHBvcnRmb2xpb3MNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQptaHAgPSBNdWx0aXZhcmlhdGVIZWRnaW5nUG9ydGZvbGlvKFkvMTAwLCBILCBzdGF0aXN0aWNzPXN0YXRpc3RpY3MsIG1ldGhvZD1tZXRob2QsIGRpZ2l0PTMpDQprYWJsZShtaHAkVEFCTEUpDQpgYGANCg0KIyMgRmlndXJlIDM6IER5bmFtaWMgY29uZGl0aW9uYWwgYmV0YXMNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYXIobWZjb2wgPSBjKGNlaWxpbmcoay8yKSwyKSwgb21hID0gYygwLCAxLCAwLCAwKSArIDAuNSwgbWFyID0gYygxLCAxLCAxLCAxKSArIDAuNSwgbWdwID0gYygxLCAwLjQsIDApKQ0KZm9yIChqIGluIDE6aykgew0KICBwbG90KGRhdGUsbWhwJEJldGFbaixqLF0qTkEsdHlwZT0nbCcsbGFzPTEseGF4cz0naScseWF4cz0naScseGxhYj0nJyx5bGFiPScnLA0KICAgICAgIG1haW49cGFzdGUoTkFNRVNbal0pLHRjaz0tLjAyLGNvbD1qLHlsaW09YygtMC41LDcwKSkNCiAgZ3JpZChOQSxOVUxMKQ0KICBjb2VmcyA9IGxtKFlbLGpdfllbLC1qXSkkY29lZmZpY2llbnRzWy0xXQ0KICBmb3IgKGkgaW4gMTprKSB7DQogICAgaWYgKGkhPWopIHsNCiAgICAgIGxpbmVzKGRhdGUsbWhwJEJldGFbaixpLF0sY29sPWkpDQogICAgICBhYmxpbmUoaD0wLGx0eT0zKQ0KICAgICAgYm94KCkNCiAgICB9DQogIH0NCiAgY29sID0gMTprDQogIGNvbCA9IGNvbFstal0NCiAgYWJsaW5lKGg9Y29lZnMsbHR5PTMsY29sPWNvbCkNCiAgbGVnZW5kKCJib3R0b20iLE5BTUVTWy1qXSxmaWxsPWMoMTprKVstal0sYnR5PSJuIixjZXg9MC42LG5jb2w9aykNCn0NCmBgYA0KDQojIyBUYWJsZSA5OiBPcHRpbWFsIGJpdmFyaWF0ZSBwb3J0Zm9saW8gd2VpZ2h0cw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmJwdyA9IEJpdmFyaWF0ZVBvcnRmb2xpbyhZLzEwMCwgSCwgc3RhdGlzdGljcz1zdGF0aXN0aWNzLCBtZXRob2Q9bWV0aG9kLCBtZXRyaWM9bWV0cmljLCBkaWdpdD0zKQ0KIyMgVGhlIG9wdGltYWwgYml2YXJpYXRlIHBvcnRmb2xpb3MgYXJlIGNvbXB1dGVkIGFjY29yZGluZyB0bzoNCiMjICBLcm9uZXIsIEsuIEYuLCAmIE5nLCBWLiBLLiAoMTk5OCkuIE1vZGVsaW5nIGFzeW1tZXRyaWMgY29tb3ZlbWVudHMgb2YgYXNzZXQgcmV0dXJucy4gVGhlIFJldmlldyBvZiBGaW5hbmNpYWwgU3R1ZGllcywgMTEoNCksIDgxNy04NDQuDQojIyANCiMjICAgICAgICAgICBIZWRnaW5nIGVmZmVjdGl2ZW5lc3MgaXMgY2FsY3VsYXRlZCBhY2NvcmRpbmcgdG86DQojIyAgRWRlcmluZ3RvbiwgTC4gSC4gKDE5NzkpLiBUaGUgaGVkZ2luZyBwZXJmb3JtYW5jZSBvZiB0aGUgbmV3IGZ1dHVyZXMgbWFya2V0cy4gVGhlIEpvdXJuYWwgb2YgRmluYW5jZSwgMzQoMSksIDE1Ny0xNzAuDQojIyANCiMjICAgICAgICAgICBTdGF0aXN0aWNzIG9mIHRoZSBoZWRnaW5nIGVmZmVjdGl2ZW5lc3MgbWVhc3VyZSBhcmUgaW1wbGVtZW50ZWQgYWNjb3JkaW5nIHRvOg0KIyMgIEFudG9uYWtha2lzLCBOLiwgQ3VuYWRvLCBKLiwgRmlsaXMsIEcuLCBHYWJhdWVyLCBELiwgJiBkZSBHcmFjaWEsIEYuIFAuICgyMDIwKS4gT2lsIGFuZCBhc3NldCBjbGFzc2VzIGltcGxpZWQgdm9sYXRpbGl0aWVzOiBJbnZlc3RtZW50IHN0cmF0ZWdpZXMgYW5kIGhlZGdpbmcgZWZmZWN0aXZlbmVzcy4gRW5lcmd5IEVjb25vbWljcywgOTEsIDEwNDc2Mi4NCmthYmxlKGJwdyRUQUJMRSkNCmBgYA0KDQojIyBUYWJsZSAxMDogTXVsdGl2YXJpYXRlIHBvcnRmb2xpbyBhbmFseXNpcw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NClBDSWMgPSBkY2EkUENJDQpQQ0lnID0gZGNhJENUDQpmb3IgKGwgaW4gMTpkaW0oZGNhJENUKVszXSkgew0KICBmb3IgKGkgaW4gMTprKSB7DQogICAgZm9yIChqIGluIDE6aykgew0KICAgICAgUENJZ1tpLGosbF0gPSAoMipSW2ksaixsXV4yKS8oMStSW2ksaixsXV4yKQ0KICAgIH0NCiAgfQ0KfQ0KbXZwID0gTWluaW11bUNvbm5lY3RlZG5lc3NQb3J0Zm9saW8oWS8xMDAsIEgsIHN0YXRpc3RpY3M9c3RhdGlzdGljcywgbWV0aG9kPW1ldGhvZCwgbWV0cmljPW1ldHJpYywgZGlnaXQ9MykNCiMjIFRoZSBtaW5pbXVtIGNvbm5lY3RlZG5lc3MgcG9ydGZvbGlvIGlzIGltcGxlbWVudGVkIGFjY29yZGluZyB0bzoNCiMjICBCcm9hZHN0b2NrLCBELiBDLiwgQ2hhdHppYW50b25pb3UsIEkuLCAmIEdhYmF1ZXIsIEQuICgyMDIyKS4gTWluaW11bSBjb25uZWN0ZWRuZXNzIHBvcnRmb2xpb3MgYW5kIHRoZSBtYXJrZXQgZm9yIGdyZWVuIGJvbmRzOiBBZHZvY2F0aW5nIHNvY2lhbGx5IHJlc3BvbnNpYmxlIGludmVzdG1lbnQgKFNSSSkgYWN0aXZpdHkuIEluIEFwcGxpY2F0aW9ucyBpbiBFbmVyZ3kgRmluYW5jZSAocHAuIDIxNy0yNTMpLiBQYWxncmF2ZSBNYWNtaWxsYW4sIENoYW0uDQojIyANCiMjICAgICAgICAgICBIZWRnaW5nIGVmZmVjdGl2ZW5lc3MgaXMgY2FsY3VsYXRlZCBhY2NvcmRpbmcgdG86DQojIyAgRWRlcmluZ3RvbiwgTC4gSC4gKDE5NzkpLiBUaGUgaGVkZ2luZyBwZXJmb3JtYW5jZSBvZiB0aGUgbmV3IGZ1dHVyZXMgbWFya2V0cy4gVGhlIEpvdXJuYWwgb2YgRmluYW5jZSwgMzQoMSksIDE1Ny0xNzAuDQojIyANCiMjICAgICAgICAgICBTdGF0aXN0aWNzIG9mIHRoZSBoZWRnaW5nIGVmZmVjdGl2ZW5lc3MgbWVhc3VyZSBhcmUgaW1wbGVtZW50ZWQgYWNjb3JkaW5nIHRvOg0KIyMgIEFudG9uYWtha2lzLCBOLiwgQ3VuYWRvLCBKLiwgRmlsaXMsIEcuLCBHYWJhdWVyLCBELiwgJiBkZSBHcmFjaWEsIEYuIFAuICgyMDIwKS4gT2lsIGFuZCBhc3NldCBjbGFzc2VzIGltcGxpZWQgdm9sYXRpbGl0aWVzOiBJbnZlc3RtZW50IHN0cmF0ZWdpZXMgYW5kIGhlZGdpbmcgZWZmZWN0aXZlbmVzcy4gRW5lcmd5IEVjb25vbWljcywgOTEsIDEwNDc2Mi4NCm1jcCA9IE1pbmltdW1Db25uZWN0ZWRuZXNzUG9ydGZvbGlvKFkvMTAwLCBSLCBzdGF0aXN0aWNzPXN0YXRpc3RpY3MsIG1ldGhvZD1tZXRob2QsIG1ldHJpYz1tZXRyaWMsIGRpZ2l0PTMpDQojIyBUaGUgbWluaW11bSBjb25uZWN0ZWRuZXNzIHBvcnRmb2xpbyBpcyBpbXBsZW1lbnRlZCBhY2NvcmRpbmcgdG86DQojIyAgQnJvYWRzdG9jaywgRC4gQy4sIENoYXR6aWFudG9uaW91LCBJLiwgJiBHYWJhdWVyLCBELiAoMjAyMikuIE1pbmltdW0gY29ubmVjdGVkbmVzcyBwb3J0Zm9saW9zIGFuZCB0aGUgbWFya2V0IGZvciBncmVlbiBib25kczogQWR2b2NhdGluZyBzb2NpYWxseSByZXNwb25zaWJsZSBpbnZlc3RtZW50IChTUkkpIGFjdGl2aXR5LiBJbiBBcHBsaWNhdGlvbnMgaW4gRW5lcmd5IEZpbmFuY2UgKHBwLiAyMTctMjUzKS4gUGFsZ3JhdmUgTWFjbWlsbGFuLCBDaGFtLg0KIyMgDQojIyAgICAgICAgICAgSGVkZ2luZyBlZmZlY3RpdmVuZXNzIGlzIGNhbGN1bGF0ZWQgYWNjb3JkaW5nIHRvOg0KIyMgIEVkZXJpbmd0b24sIEwuIEguICgxOTc5KS4gVGhlIGhlZGdpbmcgcGVyZm9ybWFuY2Ugb2YgdGhlIG5ldyBmdXR1cmVzIG1hcmtldHMuIFRoZSBKb3VybmFsIG9mIEZpbmFuY2UsIDM0KDEpLCAxNTctMTcwLg0KIyMgDQojIyAgICAgICAgICAgU3RhdGlzdGljcyBvZiB0aGUgaGVkZ2luZyBlZmZlY3RpdmVuZXNzIG1lYXN1cmUgYXJlIGltcGxlbWVudGVkIGFjY29yZGluZyB0bzoNCiMjICBBbnRvbmFrYWtpcywgTi4sIEN1bmFkbywgSi4sIEZpbGlzLCBHLiwgR2FiYXVlciwgRC4sICYgZGUgR3JhY2lhLCBGLiBQLiAoMjAyMCkuIE9pbCBhbmQgYXNzZXQgY2xhc3NlcyBpbXBsaWVkIHZvbGF0aWxpdGllczogSW52ZXN0bWVudCBzdHJhdGVnaWVzIGFuZCBoZWRnaW5nIGVmZmVjdGl2ZW5lc3MuIEVuZXJneSBFY29ub21pY3MsIDkxLCAxMDQ3NjIuDQptcGMgPSBNaW5pbXVtQ29ubmVjdGVkbmVzc1BvcnRmb2xpbyhZLzEwMCwgUENJYywgc3RhdGlzdGljcz1zdGF0aXN0aWNzLCBtZXRob2Q9bWV0aG9kLCBtZXRyaWM9bWV0cmljLCBkaWdpdD0zKQ0KIyMgVGhlIG1pbmltdW0gY29ubmVjdGVkbmVzcyBwb3J0Zm9saW8gaXMgaW1wbGVtZW50ZWQgYWNjb3JkaW5nIHRvOg0KIyMgIEJyb2Fkc3RvY2ssIEQuIEMuLCBDaGF0emlhbnRvbmlvdSwgSS4sICYgR2FiYXVlciwgRC4gKDIwMjIpLiBNaW5pbXVtIGNvbm5lY3RlZG5lc3MgcG9ydGZvbGlvcyBhbmQgdGhlIG1hcmtldCBmb3IgZ3JlZW4gYm9uZHM6IEFkdm9jYXRpbmcgc29jaWFsbHkgcmVzcG9uc2libGUgaW52ZXN0bWVudCAoU1JJKSBhY3Rpdml0eS4gSW4gQXBwbGljYXRpb25zIGluIEVuZXJneSBGaW5hbmNlIChwcC4gMjE3LTI1MykuIFBhbGdyYXZlIE1hY21pbGxhbiwgQ2hhbS4NCiMjIA0KIyMgICAgICAgICAgIEhlZGdpbmcgZWZmZWN0aXZlbmVzcyBpcyBjYWxjdWxhdGVkIGFjY29yZGluZyB0bzoNCiMjICBFZGVyaW5ndG9uLCBMLiBILiAoMTk3OSkuIFRoZSBoZWRnaW5nIHBlcmZvcm1hbmNlIG9mIHRoZSBuZXcgZnV0dXJlcyBtYXJrZXRzLiBUaGUgSm91cm5hbCBvZiBGaW5hbmNlLCAzNCgxKSwgMTU3LTE3MC4NCiMjIA0KIyMgICAgICAgICAgIFN0YXRpc3RpY3Mgb2YgdGhlIGhlZGdpbmcgZWZmZWN0aXZlbmVzcyBtZWFzdXJlIGFyZSBpbXBsZW1lbnRlZCBhY2NvcmRpbmcgdG86DQojIyAgQW50b25ha2FraXMsIE4uLCBDdW5hZG8sIEouLCBGaWxpcywgRy4sIEdhYmF1ZXIsIEQuLCAmIGRlIEdyYWNpYSwgRi4gUC4gKDIwMjApLiBPaWwgYW5kIGFzc2V0IGNsYXNzZXMgaW1wbGllZCB2b2xhdGlsaXRpZXM6IEludmVzdG1lbnQgc3RyYXRlZ2llcyBhbmQgaGVkZ2luZyBlZmZlY3RpdmVuZXNzLiBFbmVyZ3kgRWNvbm9taWNzLCA5MSwgMTA0NzYyLg0KbXBnID0gTWluaW11bUNvbm5lY3RlZG5lc3NQb3J0Zm9saW8oWS8xMDAsIFBDSWcsIHN0YXRpc3RpY3M9c3RhdGlzdGljcywgbWV0aG9kPW1ldGhvZCwgbWV0cmljPW1ldHJpYywgZGlnaXQ9MykNCiMjIFRoZSBtaW5pbXVtIGNvbm5lY3RlZG5lc3MgcG9ydGZvbGlvIGlzIGltcGxlbWVudGVkIGFjY29yZGluZyB0bzoNCiMjICBCcm9hZHN0b2NrLCBELiBDLiwgQ2hhdHppYW50b25pb3UsIEkuLCAmIEdhYmF1ZXIsIEQuICgyMDIyKS4gTWluaW11bSBjb25uZWN0ZWRuZXNzIHBvcnRmb2xpb3MgYW5kIHRoZSBtYXJrZXQgZm9yIGdyZWVuIGJvbmRzOiBBZHZvY2F0aW5nIHNvY2lhbGx5IHJlc3BvbnNpYmxlIGludmVzdG1lbnQgKFNSSSkgYWN0aXZpdHkuIEluIEFwcGxpY2F0aW9ucyBpbiBFbmVyZ3kgRmluYW5jZSAocHAuIDIxNy0yNTMpLiBQYWxncmF2ZSBNYWNtaWxsYW4sIENoYW0uDQojIyANCiMjICAgICAgICAgICBIZWRnaW5nIGVmZmVjdGl2ZW5lc3MgaXMgY2FsY3VsYXRlZCBhY2NvcmRpbmcgdG86DQojIyAgRWRlcmluZ3RvbiwgTC4gSC4gKDE5NzkpLiBUaGUgaGVkZ2luZyBwZXJmb3JtYW5jZSBvZiB0aGUgbmV3IGZ1dHVyZXMgbWFya2V0cy4gVGhlIEpvdXJuYWwgb2YgRmluYW5jZSwgMzQoMSksIDE1Ny0xNzAuDQojIyANCiMjICAgICAgICAgICBTdGF0aXN0aWNzIG9mIHRoZSBoZWRnaW5nIGVmZmVjdGl2ZW5lc3MgbWVhc3VyZSBhcmUgaW1wbGVtZW50ZWQgYWNjb3JkaW5nIHRvOg0KIyMgIEFudG9uYWtha2lzLCBOLiwgQ3VuYWRvLCBKLiwgRmlsaXMsIEcuLCBHYWJhdWVyLCBELiwgJiBkZSBHcmFjaWEsIEYuIFAuICgyMDIwKS4gT2lsIGFuZCBhc3NldCBjbGFzc2VzIGltcGxpZWQgdm9sYXRpbGl0aWVzOiBJbnZlc3RtZW50IHN0cmF0ZWdpZXMgYW5kIGhlZGdpbmcgZWZmZWN0aXZlbmVzcy4gRW5lcmd5IEVjb25vbWljcywgOTEsIDEwNDc2Mi4NCm1ycCA9IE1pbmltdW1Db25uZWN0ZWRuZXNzUG9ydGZvbGlvKFkvMTAwLCBkY2EkQ1QsIHN0YXRpc3RpY3M9c3RhdGlzdGljcywgbWV0aG9kPW1ldGhvZCwgbWV0cmljPW1ldHJpYywgZGlnaXQ9MykNCiMjIFRoZSBtaW5pbXVtIGNvbm5lY3RlZG5lc3MgcG9ydGZvbGlvIGlzIGltcGxlbWVudGVkIGFjY29yZGluZyB0bzoNCiMjICBCcm9hZHN0b2NrLCBELiBDLiwgQ2hhdHppYW50b25pb3UsIEkuLCAmIEdhYmF1ZXIsIEQuICgyMDIyKS4gTWluaW11bSBjb25uZWN0ZWRuZXNzIHBvcnRmb2xpb3MgYW5kIHRoZSBtYXJrZXQgZm9yIGdyZWVuIGJvbmRzOiBBZHZvY2F0aW5nIHNvY2lhbGx5IHJlc3BvbnNpYmxlIGludmVzdG1lbnQgKFNSSSkgYWN0aXZpdHkuIEluIEFwcGxpY2F0aW9ucyBpbiBFbmVyZ3kgRmluYW5jZSAocHAuIDIxNy0yNTMpLiBQYWxncmF2ZSBNYWNtaWxsYW4sIENoYW0uDQojIyANCiMjICAgICAgICAgICBIZWRnaW5nIGVmZmVjdGl2ZW5lc3MgaXMgY2FsY3VsYXRlZCBhY2NvcmRpbmcgdG86DQojIyAgRWRlcmluZ3RvbiwgTC4gSC4gKDE5NzkpLiBUaGUgaGVkZ2luZyBwZXJmb3JtYW5jZSBvZiB0aGUgbmV3IGZ1dHVyZXMgbWFya2V0cy4gVGhlIEpvdXJuYWwgb2YgRmluYW5jZSwgMzQoMSksIDE1Ny0xNzAuDQojIyANCiMjICAgICAgICAgICBTdGF0aXN0aWNzIG9mIHRoZSBoZWRnaW5nIGVmZmVjdGl2ZW5lc3MgbWVhc3VyZSBhcmUgaW1wbGVtZW50ZWQgYWNjb3JkaW5nIHRvOg0KIyMgIEFudG9uYWtha2lzLCBOLiwgQ3VuYWRvLCBKLiwgRmlsaXMsIEcuLCBHYWJhdWVyLCBELiwgJiBkZSBHcmFjaWEsIEYuIFAuICgyMDIwKS4gT2lsIGFuZCBhc3NldCBjbGFzc2VzIGltcGxpZWQgdm9sYXRpbGl0aWVzOiBJbnZlc3RtZW50IHN0cmF0ZWdpZXMgYW5kIGhlZGdpbmcgZWZmZWN0aXZlbmVzcy4gRW5lcmd5IEVjb25vbWljcywgOTEsIDEwNDc2Mi4NCk1WQSA9IHJiaW5kKG12cCRUQUJMRSwgbWNwJFRBQkxFLCBtcGMkVEFCTEUsIG1wZyRUQUJMRSwgbXJwJFRBQkxFKQ0Ka2FibGUoTVZBKQ0KYGBgDQoNCiMjIFRhYmxlIDExOiBQb3J0Zm9saW8gcGVyZm9ybWFuY2UNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KFBlcmZvcm1hbmNlQW5hbHl0aWNzKQ0KbGlicmFyeSh4dHMpDQpwb3J0Lm1hdCA9IGRhdGEuZnJhbWUoDQogICAgICAgICAgICAgICAgICAgICBNVlA9bXZwJHBvcnRmb2xpb19yZXR1cm4sDQogICAgICAgICAgICAgICAgICAgICBNQ1A9bWNwJHBvcnRmb2xpb19yZXR1cm4sDQogICAgICAgICAgICAgICAgICAgICBNUEM9bXBjJHBvcnRmb2xpb19yZXR1cm4sDQogICAgICAgICAgICAgICAgICAgICBNUEc9bXBnJHBvcnRmb2xpb19yZXR1cm4sDQogICAgICAgICAgICAgICAgICAgICBNUlA9bXJwJHBvcnRmb2xpb19yZXR1cm4NCiAgICAgICAgICAgICAgICAgICAgICkNCnBvcnQueHRzID0geHRzKHBvcnQubWF0LCBvcmRlci5ieT1kYXRlKQ0KDQpSYiA8LSB4dHMoWVssMV0vMTAwLCBvcmRlci5ieSA9IGluZGV4KFkpKQ0KY29sbmFtZXMoUmIpIDwtICJCZW5jaG1hcmsiDQoNCmlyIDwtIG1hdHJpeChOQSwgbnJvdyA9IDEsIG5jb2wgPSBuY29sKHBvcnQueHRzKSkNCmNvbG5hbWVzKGlyKSA8LSBjb2xuYW1lcyhwb3J0Lnh0cykNCnJvd25hbWVzKGlyKSA8LSAiR1JFIg0KDQpmb3IgKGkgaW4gMTpuY29sKHBvcnQueHRzKSkgew0KICBpclssIGldIDwtIEluZm9ybWF0aW9uUmF0aW8oUmEgPSBwb3J0Lnh0c1ssIGldLCBSYiA9IFJiKQ0KfQ0KDQprID0gbmNvbChwb3J0Lnh0cykNCnRhYmxlID0gbWF0cml4KE5BLCBuY29sPWssIG5yb3c9NSkNCmZvciAoaSBpbiAxOmspIHsNCiAgdGFibGVbLGldID0gYygNCiAgIyBSZXRvcm5vIGFudWFsaXphZG8NCiAgUmV0dXJuLmFubnVhbGl6ZWQocG9ydC54dHNbLGldKSwNCiAgDQogICMgRGVzdmlhY2nDs24gZXN0w6FuZGFyIGFudWFsaXphZGENCiAgU3RkRGV2LmFubnVhbGl6ZWQocG9ydC54dHNbLGldKSwNCiAgDQogICMgUmF0aW8gZGUgU2hhcnBlIGFudWFsaXphZG8NCiAgU2hhcnBlUmF0aW8uYW5udWFsaXplZChwb3J0Lnh0c1ssaV0pLA0KICANCiAgIyBWYWxvciBlbiBSaWVzZ28gKFZhUikgY29uIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIHkgcGVyY2VudGlsIGRlbCA5NSUNCiAgVmFSKGFzLm51bWVyaWMocG9ydC54dHNbLGldKSwgcD0wLjk1LCBtZXRob2Q9ImdhdXNzaWFuIiksDQogIA0KICAjIEV4cGVjdGF0aXZhIGRlIFDDqXJkaWRhIChFUykgY29uIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIHkgcGVyY2VudGlsIGRlbCA5NSUNCiAgRVMoYXMubnVtZXJpYyhwb3J0Lnh0c1ssaV0pLCBwPTAuOTUsIG1ldGhvZD0iZ2F1c3NpYW4iKQ0KKQ0KfQ0KY29sbmFtZXModGFibGUpID0gY29sbmFtZXMocG9ydC54dHMpDQpyb3duYW1lcyh0YWJsZSkgPSBjKCJSZXR1cm4iLCJTdGREZXYiLCJTaGFycGUgUmF0aW8gKFN0ZERldikiLCJTaGFycGUgUmF0aW8gKFZhUikiLCJTaGFycGUgUmF0aW8gKENWYVIpIikNCmthYmxlKHJiaW5kKHRhYmxlLCBpcikpDQpgYGANCg0KDQojICoqSGVucmlxdWVzKDIwMjUpOioqIENvbm5lY3RlZG5lc3MgYW5kIHN5c3RlbWljIHJpc2sgYmV0d2VlbiBGaW5UZWNoIGFuZCB0cmFkaXRpb25hbCBmaW5hbmNpYWwgc3RvY2tzOiBJbXBsaWNhdGlvbnMgZm9yIHBvcnRmb2xpbyBkaXZlcnNpZmljYXRpb24NCg0KYGBge3J9DQpwa2dzIDwtIGMoInJlYWRyIiwiem9vIiwieHRzIiwiQ29ubmVjdGVkbmVzc0FwcHJvYWNoIiwiUGVyZm9ybWFuY2VBbmFseXRpY3MiLA0KICAgICAgICAgICJyaXNrUGFyaXR5UG9ydGZvbGlvIiwicXVhZHByb2ciLCJydWdhcmNoIiwicm1nYXJjaCIsInRzZXJpZXMiLA0KICAgICAgICAgICJ1cmNhIiwiRmluVFMiLCJyb2J1c3RiYXNlIiwiY29ycnBsb3QiLCJtYXRyaXhTdGF0cyIsInBzeWNoIiwidmFycyIpDQoNCmluc3RhbGxfaWZfbWlzc2luZyA8LSBmdW5jdGlvbihwKSBpZiAoIXJlcXVpcmVOYW1lc3BhY2UocCwgcXVpZXRseSA9IFRSVUUpKSBpbnN0YWxsLnBhY2thZ2VzKHApDQppbnZpc2libGUobGFwcGx5KHBrZ3MsIGluc3RhbGxfaWZfbWlzc2luZykpDQpsaWJyYXJ5KHJlYWRyKTsgbGlicmFyeSh6b28pOyBsaWJyYXJ5KHh0cyk7IGxpYnJhcnkoQ29ubmVjdGVkbmVzc0FwcHJvYWNoKQ0KbGlicmFyeShQZXJmb3JtYW5jZUFuYWx5dGljcyk7IGxpYnJhcnkocmlza1Bhcml0eVBvcnRmb2xpbyk7IGxpYnJhcnkocXVhZHByb2cpDQpsaWJyYXJ5KGNvcnJwbG90KTsgbGlicmFyeSh2YXJzKQ0KDQojIC0tLSAxKSBDYXJnYXIgZGF0b3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmRhdGFfcGF0aCA8LSAiQzovVXNlcnMvQVZSSUwvRGVza3RvcC9TcGlsbG92ZXJzL2FsbF9kYWlseV9pbmRleF9yZXR1cm5zLmNzdiINCmluZGV4X2FsdCA8LSByZWFkX2NzdihkYXRhX3BhdGgsIHNob3dfY29sX3R5cGVzID0gRkFMU0UpDQoNCmlmKCEoIkRhdGUiICVpbiUgY29sbmFtZXMoaW5kZXhfYWx0KSkpIHN0b3AoIk5vIHNlIGVuY29udHLDsyBsYSBjb2x1bW5hICdEYXRlJy4iKQ0KaW5kZXhfYWx0JERhdGUgPC0gYXMuRGF0ZShpbmRleF9hbHQkRGF0ZSwgZm9ybWF0ID0gIiVkLyVtLyVZIikNCmlmKGFueShpcy5uYShpbmRleF9hbHQkRGF0ZSkpKSBpbmRleF9hbHQkRGF0ZSA8LSBhcy5EYXRlKGluZGV4X2FsdCREYXRlLCBmb3JtYXQgPSAiJVktJW0tJWQiKQ0KDQpkYXRhX3NlbGVjdGVkIDwtIGluZGV4X2FsdFssIGMoIkRhdGUiLCAiQUlfSU5ERVgiLCAiRmludGVjaF9JbmRleCIsICJCbG9ja2NoYWluX0luZGV4IildDQpjb2xuYW1lcyhkYXRhX3NlbGVjdGVkKSA8LSBjKCJEYXRlIiwiQUlfSU5ERVgiLCJGaW50ZWNoIiwiQmxvY2tjaGFpbiIpDQpkYXRhX3NlbGVjdGVkIDwtIGRhdGFfc2VsZWN0ZWRbIWlzLm5hKGRhdGFfc2VsZWN0ZWQkRGF0ZSksIF0NCg0KYGBgDQoNCiMjIERldGVjdGFyIHNpIGxvcyB2YWxvcmVzIHNvbiBwcmVjaW9zIG8gcmV0b3Jub3MgeSBwcmVwYXJhciBzZXJpZXMgDQpgYGB7cn0NCiMgSGV1csOtc3RpY2E6IHNpIGhheSB2YWxvcmVzIG1heW9yZXMgcXVlIDEuNSAtPiB0cmF0YW1vcyBjb21vIHByZWNpb3MsIHNpbm8gY29tbyByZXRvcm5vcw0KaXNfcHJpY2VfbGlrZSA8LSBmdW5jdGlvbih4KSBtZWRpYW4oYWJzKHgpLCBuYS5ybT1UUlVFKSA+IDEuNQ0KbWF0IDwtIGFzLmRhdGEuZnJhbWUoZGF0YV9zZWxlY3RlZFssIC0xXSkNCg0KaWYoYW55KHNhcHBseShtYXQsIGlzX3ByaWNlX2xpa2UpKSkgew0KICBtZXNzYWdlKCJEZXRlY3RhZG8gZGF0byB0aXBvIHByZWNpb3MgLT4gY2FsY3VsYW5kbyByZXRvcm5vcyBsb2dhcsOtdG1pY29zLiIpDQogIHByaWNlc194dHMgPC0geHRzKG1hdCwgb3JkZXIuYnkgPSBkYXRhX3NlbGVjdGVkJERhdGUpDQogIHkuciA8LSBuYS5vbWl0KGRpZmYobG9nKHByaWNlc194dHMpKSkNCn0gZWxzZSB7DQogIG1lc3NhZ2UoIkRldGVjdGFkbyBkYXRvIHRpcG8gcmV0b3Jub3MgLT4gdXNhcmVtb3MgZGlyZWN0YW1lbnRlIGxvcyByZXRvcm5vcy4iKQ0KICB5LnIgPC0geHRzKG1hdCwgb3JkZXIuYnkgPSBkYXRhX3NlbGVjdGVkJERhdGUpDQogIGlmKGFsbChhYnMoY29yZWRhdGEoeS5yKSkgPiAxKSkgew0KICAgIG1lc3NhZ2UoIlJldG9ybm9zIHBhcmVjZW4gZW4gcG9yY2VudGFqZS4gU2UgY29udmllcnRlbiBhIGRlY2ltYWxlcyAoLzEwMCkuIikNCiAgICB5LnIgPC0geS5yIC8gMTAwDQogIH0NCiAgeS5yIDwtIG5hLm9taXQoeS5yKQ0KfQ0KDQpzeW1ib2xzIDwtIGNvbG5hbWVzKHkucikNCmNhdCgiU2VyaWVzIHByZXBhcmFkYXM6IiwgcGFzdGUoc3ltYm9scywgY29sbGFwc2U9IiwgIiksICIgKG49IiwgbnJvdyh5LnIpLCAiKVxuIikNCmBgYA0KDQpgYGB7cn0NCnAxIDwtcGxvdC54dHMoeS5yLCBhdXRvLmxlZ2VuZCA9IFRSVUUsIG1haW49IiIsbGVnZW5kLmxvYyA9ICJ0b3BsZWZ0IikNCnAxDQpgYGANCg0KDQoNCiMjIEVzdGFkw61zdGljb3MgeSBjb3JyZWxhY2lvbmVzDQpgYGB7cn0NCmNhdCgiXG4tLS0gRXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MgLS0tXG4iKQ0Kc3VtX3N0YXRzIDwtIGRhdGEuZnJhbWUodChwc3ljaDo6ZGVzY3JpYmUoYXMuZGF0YS5mcmFtZSgxMDAgKiB5LnIpKSkpDQpwcmludChzdW1fc3RhdHMpDQoNCmNhdCgiXG4tLS0gTWF0cml6IGRlIGNvcnJlbGFjaW9uZXMgLS0tXG4iKQ0KY29yX21hdCA8LSBjb3IoeS5yLCB1c2U9ImNvbXBsZXRlLm9icyIpDQpwcmludChyb3VuZChjb3JfbWF0LDMpKQ0KY29ycnBsb3QoY29yX21hdCwgdHlwZT0idXBwZXIiLCBvcmRlcj0iaGNsdXN0IiwgdGwuY29sPSJibGFjayIsIHRsLnNydD00NSkNCmBgYA0KDQoNCmBgYHtyfQ0KdmFyczo6VkFSc2VsZWN0KHkucikNCiMgc3RhbmRhcmQgZHkgYXBwcm9hY2gNCmRjYSA9IENvbm5lY3RlZG5lc3NBcHByb2FjaCh5LnIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmxhZz0xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5mb3JlPTIwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zaXplPTIwMCkNCg0KKGRjYSRUQUJMRSkNClBsb3RUQ0koZGNhLCB5bGltPWMoMCwxMDApKQ0KDQojIHR2cC12YXINCmRjYSA9IENvbm5lY3RlZG5lc3NBcHByb2FjaCh5LnIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbmxhZz0xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5mb3JlPTIwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICN3aW5kb3cuc2l6ZT0yMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29ycmVjdGVkID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWw9IlRWUC1WQVIiKQ0KKGRjYSRUQUJMRSkNClBsb3RUQ0koZGNhLCB5bGltPWMoMCwxMDApKQ0KDQpzdHIoZGNhKQ0KKGRjYSRUQUJMRSkNCmdmZXZkID0gZGNhJENUDQpkaW0oZ2ZldmQpDQoNCihDb25uZWN0ZWRuZXNzVGFibGUoZ2ZldmQpKQ0KKENvbm5lY3RlZG5lc3NUYWJsZShnZmV2ZCkkUENJKQ0KDQojIHBuZygicGxvdHMvcGxvdF90Y2kucG5nIiwgIHdpZHRoID0gNjAwLCBoZWlnaHQgPSA0ODAgLCBwb2ludHNpemU9MTQpDQpQbG90VENJKGRjYSwgeWxpbT1jKDAsMTAwKSkNClZpZXcgKGRjYSRUQ0kpDQptYXgoZGNhJFRDSSkNCm1pbihkY2EkVENJKQ0KbWVhbihkY2EkVENJKQ0KUGxvdFRPKGRjYSwgeWxpbT1jKDAsMTAwKSkNClBsb3RGUk9NKGRjYSwgeWxpbT1jKDAsMTAwKSkNClBsb3RORVQoZGNhLCB5bGltPWMoLTIwLDIwKSkNClBsb3ROUERDKGRjYSwgeWxpbT1jKC0xNSwxNSkpDQpQbG90TmV0d29yayhkY2EpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyBwb3J0Zm9saW8gd2VpZ2h0cw0KbWNwID0gTWluaW11bUNvbm5lY3RlZG5lc3NQb3J0Zm9saW8oYXMuem9vKHkuciksIGRjYSRQQ0ksIHN0YXRpc3RpY3M9IkZpc2hlciIpDQptY3AkVEFCTEUNCg0Kdy5tY3AgPC0gbWNwJHBvcnRmb2xpb193ZWlnaHRzIA0KYXBwbHkody5tY3AsMiwgbWVhbikNCg0KcnBwID0gUmlza1Bhcml0eVBvcnRmb2xpbyhhcy56b28oeS5yKSwgZGNhJFBDSSwgc3RhdGlzdGljcz0iRmlzaGVyIikNCnJwcCRUQUJMRQ0KDQp3LnJwcCA8LSBycHAkcG9ydGZvbGlvX3dlaWdodHMgDQphcHBseSh3LnJwcCwyLCBtZWFuKQ0KaGVhZCh3LnJwcCkNCnRhaWwody5ycHApDQpkaW0ody5ycHApDQpkaW0oeS5yKQ0KZGltKHcubWNwKQ0KDQpoZWFkICh3LnJwcCp5LnIpDQp3LnJwcFsxLDFdICogeS5yWzEsMV0NCg0Kdy5tY3BfdGVtcCA8LSAgY2JpbmQoeS5yWywxXSwgdy5tY3ApDQpoZWFkKHcubWNwX3RlbXApDQp3Lm1jcF90ZW1wIDwtIHcubWNwX3RlbXBbLC0xXQ0KaGVhZCh3Lm1jcF90ZW1wKQ0KDQp3LnJwcF90ZW1wIDwtICBjYmluZCh5LnJbLDFdLCB3LnJwcCkNCmhlYWQody5ycHBfdGVtcCkNCncucnBwX3RlbXAgPC0gdy5ycHBfdGVtcFssLTFdDQpoZWFkKHcucnBwX3RlbXApDQoNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBwb3J0Zm9saW9zDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCiMgY2hvaWNlIG9mIHBvcnRmb2xpb3M7IG1jcCwgcnBwLCBldywgcnANCiMgaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3Jpc2tQYXJpdHlQb3J0Zm9saW8vdmlnbmV0dGVzL1Jpc2tQYXJpdHlQb3J0Zm9saW8uaHRtbCNhLXByYXRpY2FsLWV4YW1wbGUtdXNpbmctZmFhbmctcHJpY2UtZGF0YQ0KIyBmb3IgYmFja3Rlc3RpbmcNCiMgaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3BvcnRmb2xpb0JhY2t0ZXN0L3ZpZ25ldHRlcy9Qb3J0Zm9saW9CYWNrdGVzdC5odG1sI2RlZmluaW5nLXBvcnRmb2xpb3MNCg0KeS5yX2MgPC0gZXhwKHkuciktMQ0KDQp3LmVxIDwtIHJlcCgxL25jb2woeS5yX2MpLCBuY29sKHkucl9jKSkNCncucnAgPC0gcmlza1Bhcml0eVBvcnRmb2xpbyhjb3YoeS5yX2MpKSR3DQoNCiMgaHR0cHM6Ly9ib29rZG93bi5vcmcvY29tcGZpbmV6Ym9vay9pbnRyb2NvbXBmaW5yL0VmZmljaWVudC1wb3J0Zm9saW9zLW9mLmh0bWwNCm1heF9zaGFycGVfcmF0aW8gPC0gZnVuY3Rpb24oZGF0YXNldCkgew0KICBwcmljZXMgPC0gZGF0YXNldA0KICANCiAgIyAxLiBFbGltaW5hciBjb2x1bW5hcyBvIGZpbGFzIGNvbiBOQXMNCiAgcHJpY2VzIDwtIG5hLm9taXQocHJpY2VzKQ0KICBpZiAobnJvdyhwcmljZXMpIDwgMikgcmV0dXJuKHJlcChOQSwgbmNvbChwcmljZXMpKSkNCiAgDQogICMgMi4gQ2FsY3VsYXIgcmV0b3Jub3MgbG9nYXLDrXRtaWNvcyBkZSBmb3JtYSBzZWd1cmENCiAgbG9nX3JldHVybnMgPC0gc3VwcHJlc3NXYXJuaW5ncyhkaWZmKGxvZyhwcmljZXMpKSkNCiAgbG9nX3JldHVybnMgPC0gbmEub21pdChleHAobG9nX3JldHVybnMpIC0gMSkNCiAgDQogIGlmIChucm93KGxvZ19yZXR1cm5zKSA8IDIpIHJldHVybihyZXAoTkEsIG5jb2wocHJpY2VzKSkpDQogIA0KICAjIDMuIEVzdGFkw61zdGljb3MgYsOhc2ljb3MNCiAgU2lnbWEgPC0gY292KGxvZ19yZXR1cm5zLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIikNCiAgbXUgPC0gY29sTWVhbnMobG9nX3JldHVybnMsIG5hLnJtID0gVFJVRSkNCiAgDQogICMgNC4gVmFsaWRhY2nDs24gZGUgaW5wdXRzDQogIGlmIChhbnkoaXMubmEobXUpKSB8fCBhbnkoaXMubmEoU2lnbWEpKSkgcmV0dXJuKHJlcChOQSwgbmNvbChwcmljZXMpKSkNCiAgaWYgKGFsbChtdSA8PSAxZS04LCBuYS5ybSA9IFRSVUUpKSByZXR1cm4ocmVwKDAsIG5jb2wocHJpY2VzKSkpDQogIA0KICAjIDUuIE9wdGltaXphY2nDs24gY2zDoXNpY2EgZGUgcG9ydGFmb2xpbyBtw6F4aW1vIFNoYXJwZQ0KICBEbWF0IDwtIDIgKiBTaWdtYQ0KICBBbWF0IDwtIGNiaW5kKG11LCBkaWFnKG5jb2wocHJpY2VzKSkpDQogIGJ2ZWMgPC0gYygxLCByZXAoMCwgbmNvbChwcmljZXMpKSkNCiAgZHZlYyA8LSByZXAoMCwgbmNvbChwcmljZXMpKQ0KICANCiAgcmVzIDwtIHRyeShzb2x2ZS5RUChEbWF0ID0gRG1hdCwgZHZlYyA9IGR2ZWMsIEFtYXQgPSBBbWF0LCBidmVjID0gYnZlYywgbWVxID0gMSksIHNpbGVudCA9IFRSVUUpDQogIA0KICBpZiAoaW5oZXJpdHMocmVzLCAidHJ5LWVycm9yIikpIHsNCiAgICByZXR1cm4ocmVwKE5BLCBuY29sKHByaWNlcykpKQ0KICB9IGVsc2Ugew0KICAgIHcgPC0gcmVzJHNvbHV0aW9uDQogICAgcmV0dXJuKHcgLyBzdW0odykpDQogIH0NCn0NCg0KDQoNCiMgcm9sbGluZyBwb3J0Zm9saW8gd2VpZ2h0cw0Kd2wgPC0gMjUyDQpyb2xsX3JwID0gIG5hLm9taXQgKHJvbGxhcHBseSh5LnJfYywgd2wgLGZ1bmN0aW9uKHgpIHJpc2tQYXJpdHlQb3J0Zm9saW8oY292KHgpKSR3LCBieS5jb2x1bW49RkFMU0UsYWxpZ249InJpZ2h0IikpDQpoZWFkKHJvbGxfcnApDQp0YWlsKHJvbGxfcnApDQoNCnJvbGxfbXMgPSAgbmEub21pdCAocm9sbGFwcGx5KHkucl9jLCB3bCAsZnVuY3Rpb24oeCkgbWF4X3NoYXJwZV9yYXRpbyh4KSwgYnkuY29sdW1uPUZBTFNFLGFsaWduPSJyaWdodCIpKQ0KY29sbmFtZXMocm9sbF9tcykgPC0gY29sbmFtZXMocm9sbF9ycCkNCmhlYWQocm9sbF9tcykNCnRhaWwocm9sbF9tcykNCg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMzDQoNCiMgcG9ydF9lcXcgIDwtIFJldHVybi5wb3J0Zm9saW8oeS5yLCB3ZWlnaHRzPXcuZXEgLCAgIHZlcmJvc2U9VFJVRSwgZ2VvbWV0cmljID0gRkFMU0UpDQpwb3J0X2VxdyAgPC0gUmV0dXJuLnBvcnRmb2xpbyggeS5yX2MsICAgdmVyYm9zZT1UUlVFLCAgcmViYWxhbmNlX29uID0gImRheXMiKQ0KaGVhZCAocG9ydF9lcXckQk9QLldlaWdodCwyMikNCmhlYWQgKHBvcnRfZXF3JEVPUC5XZWlnaHQsMjIpDQoNCiMgcG9ydF9ycCAgIDwtIFJldHVybi5wb3J0Zm9saW8oeS5yLCB3ZWlnaHRzPXcucnAsdmVyYm9zZT1UUlVFKQ0KcG9ydF9ycCAgIDwtIFJldHVybi5wb3J0Zm9saW8oIHkucl9jLCB3ZWlnaHRzPXJvbGxfcnAsICAgdmVyYm9zZT1UUlVFKQ0KcG9ydF9tY3AgIDwtIFJldHVybi5wb3J0Zm9saW8oIHkucl9jLCB3ZWlnaHRzPXcubWNwX3RlbXAsdmVyYm9zZT1UUlVFKQ0KcG9ydF9ycHAgIDwtIFJldHVybi5wb3J0Zm9saW8oIHkucl9jLCB3ZWlnaHRzPXcucnBwX3RlbXAsdmVyYm9zZT1UUlVFKQ0KcG9ydF9tcyAgIDwtIFJldHVybi5wb3J0Zm9saW8oIHkucl9jLCB3ZWlnaHRzPXJvbGxfbXMsICAgdmVyYm9zZT1UUlVFKQ0KDQoNCnN0cihwb3J0X2VxdykNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBzb21lIGNoZWNrcyBvbiB0aGUgZXF3DQpoZWFkKHBvcnRfZXF3JHJldHVybnMpDQp3LmVxICp5LnJbMTo1LF0NCmFwcGx5KHcuZXEgKnkuclsxOjUsXSwxLCBzdW0pDQpoZWFkKHBvcnRfcnAkcmV0dXJucykNCnRhaWwocG9ydF9ycCRyZXR1cm5zKQ0KDQp0YWJsZS5Bbm51YWxpemVkUmV0dXJucyhhcHBseSh3LmVxICp5LnJfY1siMjAxNy0wOS0xNC8iXSwxLHN1bSksIHNjYWxlPTI1MiwgUmY9KC4wMS8yNTIpKQ0KDQojIGluIHNhbXBsZSBlcXcNCnN1bW1hcnkoeS5yX2NbIjIwMTctMDktMTQvIl0pDQogICAgdy5lcSAqYXBwbHkoeS5yX2NbIjIwMTctMDktMTQvIl0sIDIsIG1lYW4pDQpzdW0ody5lcSAqYXBwbHkoeS5yX2NbIjIwMTctMDktMTQvIl0sIDIsIG1lYW4pKSoyNTINCiMgMC4wNjI5NzUxOA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCnBvcnRfcmV0IDwtIGNiaW5kKHBvcnRfZXF3JHJldHVybnMsIHBvcnRfcnAkcmV0dXJucywgcG9ydF9ycHAkcmV0dXJucywgcG9ydF9tcyRyZXR1cm5zICkNCmNvbG5hbWVzKHBvcnRfcmV0KSA8LSBjKCJFUVciLCAiUlAiLCAiUlBDIiwgIk1TIikNCiMgYWxsIHBvcnRmb2xpb3Mgc3RhcnQgYXQgc2FtZSB0aW1lIHBlcmlvZA0KcG9ydF9yZXQgPC0gbmEub21pdCggcG9ydF9yZXQpDQpoZWFkKHBvcnRfcmV0KQ0KYGBgDQoNCg0KYGBge3J9DQojIHBvcnRmb2xpbyBzdW1tYXJ5IHN0YXRpc3RpY3MNCiMgcHVlZGVzIGZpamFyIHVuYSBmZWNoYSBvIHVzYXIgZWwgaW5pY2lvIGF1dG9tw6F0aWNvIGRlIHR1cyBkYXRvcw0Kc3RhcnRfZGF0ZSA8LSBzdGFydCh5LnJfYykgIA0KY2F0KCJGZWNoYSBpbmljaWFsIGRlIGxvcyBkYXRvczoiLCBzdGFydF9kYXRlLCAiXG4iKQ0KDQojIEZpbHRyYXIgZGVzZGUgc3RhcnRfZGF0ZQ0Kcm9sbF9ycF9zdWIgIDwtIHJvbGxfcnBbcGFzdGUwKHN0YXJ0X2RhdGUsICIvIildDQpyb2xsX21zX3N1YiAgPC0gcm9sbF9tc1twYXN0ZTAoc3RhcnRfZGF0ZSwgIi8iKV0NCndfcnBwX3N1YiAgICA8LSB3LnJwcF90ZW1wW3Bhc3RlMChzdGFydF9kYXRlLCAiLyIpXQ0KDQojIHByb21lZGlvcyBkZSBwZXNvcw0KYXcxIDwtIGFwcGx5KHJvbGxfcnBfc3ViLCAyLCBtZWFuLCBuYS5ybSA9IFRSVUUpDQphdzIgPC0gYXBwbHkocm9sbF9tc19zdWIsIDIsIG1lYW4sIG5hLnJtID0gVFJVRSkNCmF3MyA8LSBhcHBseSh3X3JwcF9zdWIsICAgMiwgbWVhbiwgbmEucm0gPSBUUlVFKQ0KDQojIGVzdGFkw61zdGljYXMgcmVzdW1lbg0Kc3VtbWFyeShyb2xsX3JwX3N1YikNCnN1bW1hcnkocm9sbF9tc19zdWIpDQpzdW1tYXJ5KHdfcnBwX3N1YikNCg0KIyBncsOhZmljYXMgZGUgcGVzb3MNCnBsb3Qocm9sbF9ycF9zdWIsIG1haW4gPSAiUGVzb3MgUm9sbGluZyBSaXNrIFBhcml0eSAoUlApIiwgYXV0by5sZWdlbmQgPSBUUlVFLCBsZWdlbmQubG9jID0gInRvcGxlZnQiKQ0KcGxvdChyb2xsX21zX3N1YiwgbWFpbiA9ICJQZXNvcyBSb2xsaW5nIE1heCBTaGFycGUgKE1TKSIsIGF1dG8ubGVnZW5kID0gVFJVRSwgbGVnZW5kLmxvYyA9ICJ0b3BsZWZ0IikNCnBsb3Qod19ycHBfc3ViLCAgIG1haW4gPSAiUGVzb3MgUm9sbGluZyBSaXNrIFBhcml0eSBDb25uZWN0ZWRuZXNzIChSUEMpIiwgYXV0by5sZWdlbmQgPSBUUlVFLCBsZWdlbmQubG9jID0gInRvcGxlZnQiKQ0KDQojIG1lZGlkYXMgYWdyZWdhZGFzOiBtZWRpYSwgc2QsIGN2LCBtaW4sIG1heA0KYXcxXzIgPC0gcmJpbmQoDQogIE1lYW4gPSBhcHBseShyb2xsX3JwX3N1YiwgMiwgbWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgU0QgICA9IGFwcGx5KHJvbGxfcnBfc3ViLCAyLCBzZCwgbmEucm0gPSBUUlVFKSwNCiAgQ1YgICA9IGFwcGx5KHJvbGxfcnBfc3ViLCAyLCBzZCwgbmEucm0gPSBUUlVFKSAvIGFwcGx5KHJvbGxfcnBfc3ViLCAyLCBtZWFuLCBuYS5ybSA9IFRSVUUpLA0KICBNaW4gID0gYXBwbHkocm9sbF9ycF9zdWIsIDIsIG1pbiwgbmEucm0gPSBUUlVFKSwNCiAgTWF4ICA9IGFwcGx5KHJvbGxfcnBfc3ViLCAyLCBtYXgsIG5hLnJtID0gVFJVRSkNCikNCg0KYXcyXzIgPC0gcmJpbmQoDQogIE1lYW4gPSBhcHBseShyb2xsX21zX3N1YiwgMiwgbWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgU0QgICA9IGFwcGx5KHJvbGxfbXNfc3ViLCAyLCBzZCwgbmEucm0gPSBUUlVFKSwNCiAgQ1YgICA9IGFwcGx5KHJvbGxfbXNfc3ViLCAyLCBzZCwgbmEucm0gPSBUUlVFKSAvIGFwcGx5KHJvbGxfbXNfc3ViLCAyLCBtZWFuLCBuYS5ybSA9IFRSVUUpLA0KICBNaW4gID0gYXBwbHkocm9sbF9tc19zdWIsIDIsIG1pbiwgbmEucm0gPSBUUlVFKSwNCiAgTWF4ICA9IGFwcGx5KHJvbGxfbXNfc3ViLCAyLCBtYXgsIG5hLnJtID0gVFJVRSkNCikNCg0KYXczXzIgPC0gcmJpbmQoDQogIE1lYW4gPSBhcHBseSh3X3JwcF9zdWIsIDIsIG1lYW4sIG5hLnJtID0gVFJVRSksDQogIFNEICAgPSBhcHBseSh3X3JwcF9zdWIsIDIsIHNkLCBuYS5ybSA9IFRSVUUpLA0KICBDViAgID0gYXBwbHkod19ycHBfc3ViLCAyLCBzZCwgbmEucm0gPSBUUlVFKSAvIGFwcGx5KHdfcnBwX3N1YiwgMiwgbWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgTWluICA9IGFwcGx5KHdfcnBwX3N1YiwgMiwgbWluLCBuYS5ybSA9IFRSVUUpLA0KICBNYXggID0gYXBwbHkod19ycHBfc3ViLCAyLCBtYXgsIG5hLnJtID0gVFJVRSkNCikNCg0KIyBjb21iaW5hciBlbiB1biBzb2xvIG1hcmNvIGRlIGRhdG9zDQpwb3J0Zm9saW9fd2VpZ2h0c19zdW1tYXJ5IDwtIHJiaW5kKA0KICBjYmluZChUeXBlID0gIlJQIiwgIFN0YXQgPSByb3duYW1lcyhhdzFfMiksIHJvdW5kKGF3MV8yLCA0KSksDQogIGNiaW5kKFR5cGUgPSAiTVMiLCAgU3RhdCA9IHJvd25hbWVzKGF3Ml8yKSwgcm91bmQoYXcyXzIsIDQpKSwNCiAgY2JpbmQoVHlwZSA9ICJSUEMiLCBTdGF0ID0gcm93bmFtZXMoYXczXzIpLCByb3VuZChhdzNfMiwgNCkpDQopDQoNCnByaW50KHBvcnRmb2xpb193ZWlnaHRzX3N1bW1hcnkpDQoNCiMgb3BjaW9uYWw6IGd1YXJkYXIgcmVzdWx0YWRvcw0KIyB3cml0ZS5jc3YocG9ydGZvbGlvX3dlaWdodHNfc3VtbWFyeSwgInRhYmxlc19wb3J0Zm9saW9fd2VpZ2h0c19zdW1tYXJ5LmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KDQojIEN1cnZhcyBhY3VtdWxhZGFzDQpjaGFydC5DdW1SZXR1cm5zKHBvcnRfcmV0LCBtYWluID0gIkVxdWl0eSBDdXJ2ZXMgKEVRVywgUlAsIFJQQywgTVMpIiwNCiAgICAgICAgICAgICAgICAgeWxhYiA9ICIiLCBnZW9tZXRyaWMgPSBUUlVFLCB3ZWFsdGguaW5kZXggPSBUUlVFLA0KICAgICAgICAgICAgICAgICBsZWdlbmQubG9jID0gInRvcGxlZnQiKQ0KDQojIGRldi5vZmYoKQ0KDQojIGV4cGVyaW1lbnRpbmcgd2l0aCBjb2xvcnMNCiNjaGFydC5DdW1SZXR1cm5zKHBvcnRfcmV0LCAgbWFpbiA9ICJFcXVpdHkgY3VydmVzIiwgeWxhYj0iIiwgZ2VvbWV0cmljID0gRkFMU0UsIHdlYWx0aC5pbmRleCA9IFRSVUUsIA0KIyAgICAgICAgICAgICAgICAgY29sb3JzZXQ9dGltNmVxdWFsLCBsZWdlbmQubG9jID0gInRvcGxlZnQiLCApDQoNCiNjaGFydC5DdW1SZXR1cm5zKHBvcnRfcmV0LCAgbWFpbiA9ICJFcXVpdHkgY3VydmVzIiwgeWxhYj0iIiwgZ2VvbWV0cmljID0gRkFMU0UsIHdlYWx0aC5pbmRleCA9IFRSVUUsIA0KIyAgICAgICAgICAgICAgICAgY29sb3JzZXQ9cmljaDZlcXVhbCwgbGVnZW5kLmxvYyA9ICJ0b3BsZWZ0IiwgKQ0KDQojIHNldCByaXNrIGZyZWUgcmF0ZSA7IGZyb20geWFob28gZmluYW5jZSBeSVJYDQoocmZyIDwtICgwLjk1NTY2MjQvMTAwKS8yNTIpDQoNCnRhMSA8LSB0YWJsZS5Bbm51YWxpemVkUmV0dXJucyhwb3J0X3JldCwgc2NhbGU9MjUyLCBnZW9tZXRyaWMgPSBUUlVFLCAgUmY9cmZyKQ0KDQp0YTIgPC0gdGFibGUuRG93bnNpZGVSaXNrKHBvcnRfcmV0LCBzY2FsZT0yNTIsICBSZj1yZnIsIE1BUiA9LjAwLCBwPS45NSkNCnRhMyA8LSBPbWVnYShwb3J0X3JldCwgUmY9cmZyKQ0KU29ydGlub1JhdGlvKHBvcnRfcmV0KQ0KDQpyYmluZCh0YTEsIHRhMiwgdGEzKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyB3ZWVrbHkgcmUtYmFsYW5jaW5nDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQpyYnAgPC0gYygiZGF5cyIpDQojIHJicCA8LSBjKCJ3ZWVrcyIpDQojIHJicCA8LSBjKCJtb250aHMiKQ0KDQoNCnBvcnRfZXF3ICA8LSBSZXR1cm4ucG9ydGZvbGlvKCB5LnJfYywgICB2ZXJib3NlPVRSVUUsICByZWJhbGFuY2Vfb24gPSByYnApDQpoZWFkIChwb3J0X2VxdyRCT1AuV2VpZ2h0LDIyKQ0KaGVhZCAocG9ydF9lcXckRU9QLldlaWdodCwyMikNCnRhaWwgKHBvcnRfZXF3JEJPUC5XZWlnaHQsMjIpDQp0YWlsIChwb3J0X2VxdyRFT1AuV2VpZ2h0LDIyKQ0KDQoNCg0KIyBwb3J0X3JwICAgPC0gUmV0dXJuLnBvcnRmb2xpbyh5LnIsIHdlaWdodHM9dy5ycCx2ZXJib3NlPVRSVUUpDQplcCA8LSBlbmRwb2ludHMocm9sbF9ycCwgb24gPSByYnApDQpwb3J0X3JwICAgPC0gUmV0dXJuLnBvcnRmb2xpbyggeS5yX2MsIHdlaWdodHM9IHJvbGxfcnBbZXAsXSAsICAgdmVyYm9zZT1UUlVFKQ0KaGVhZChyb2xsX3JwW2VwLF0sMjIpDQpoZWFkIChwb3J0X3JwJEJPUC5XZWlnaHQsMjIpDQpoZWFkIChwb3J0X3JwJEVPUC5XZWlnaHQsMjIpDQp0YWlsKHJvbGxfcnBbZXAsXSwyMikNCnRhaWwgKHBvcnRfcnAkQk9QLldlaWdodCwyMikNCnRhaWwgKHBvcnRfcnAkRU9QLldlaWdodCwyMikNCg0KDQplcCA8LSBlbmRwb2ludHMody5tY3BfdGVtcCwgb24gPSByYnApDQpwb3J0X21jcCAgPC0gUmV0dXJuLnBvcnRmb2xpbyggeS5yX2MsIHdlaWdodHM9IHcubWNwX3RlbXBbZXAsXSAgLHZlcmJvc2U9VFJVRSkNCg0KZXAgPC0gZW5kcG9pbnRzKHcucnBwX3RlbXAsIG9uID0gcmJwKQ0KcG9ydF9ycHAgIDwtIFJldHVybi5wb3J0Zm9saW8oIHkucl9jLCB3ZWlnaHRzPSB3LnJwcF90ZW1wW2VwLF0sdmVyYm9zZT1UUlVFKQ0KaGVhZCh3LnJwcF90ZW1wW2VwLF0sMjIpDQpoZWFkIChwb3J0X3JwcCRCT1AuV2VpZ2h0LDIyKQ0KaGVhZCAocG9ydF9ycHAkRU9QLldlaWdodCwyMikNCg0KDQplcCA8LSBlbmRwb2ludHMocm9sbF9tcywgb24gPSByYnApDQpwb3J0X21zICAgPC0gUmV0dXJuLnBvcnRmb2xpbyggeS5yX2MsIHdlaWdodHM9IHJvbGxfbXNbZXAsXSwgICB2ZXJib3NlPVRSVUUpDQoNCnBvcnRfcmV0IDwtIGNiaW5kKHBvcnRfZXF3JHJldHVybnMsIHBvcnRfcnAkcmV0dXJucywgcG9ydF9ycHAkcmV0dXJucywgcG9ydF9tcyRyZXR1cm5zICkNCmNvbG5hbWVzKHBvcnRfcmV0KSA8LSBjKCJFUVciLCAiUlAiLCAiUlBDIiwgIk1TIikNCiMgYWxsIHBvcnRmb2xpb3Mgc3RhcnQgYXQgc2FtZSB0aW1lIHBlcmlvZA0KcG9ydF9yZXQgPC0gbmEub21pdCggcG9ydF9yZXQpDQpoZWFkKHBvcnRfcmV0KQ0KDQp0YTEgPC0gdGFibGUuQW5udWFsaXplZFJldHVybnMocG9ydF9yZXQsIHNjYWxlPTI1MiwgZ2VvbWV0cmljID0gVFJVRSwgIFJmPXJmcikNCnRhMiA8LSB0YWJsZS5Eb3duc2lkZVJpc2socG9ydF9yZXQsIHNjYWxlPTI1MiwgIFJmPXJmciwgTUFSID0uMDAsIHA9Ljk1KQ0KdGEzIDwtIE9tZWdhKHBvcnRfcmV0LCBSZj1yZnIpDQpTb3J0aW5vUmF0aW8ocG9ydF9yZXQpDQoNCnJiaW5kKHRhMSwgdGEyLCB0YTMpDQpgYGANCg0KYGBge3J9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBQb3J0Zm9saW8gc3VtbWFyeSBzdGF0aXN0aWNzIChyZWJhbGFuY2UgbW9udGhseSkNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCnJicCA8LSBjKCJtb250aHMiKSAgIyA8PDwgY2FtYmlvIGNsYXZlIHJlc3BlY3RvIGFsIGJsb3F1ZSBzZW1hbmFsDQoNCiMgUG9ydGFmb2xpbyBFcXVhbCBXZWlnaHQgKEVRVykNCnBvcnRfZXF3X20gIDwtIFJldHVybi5wb3J0Zm9saW8oeS5yX2MsIHZlcmJvc2UgPSBUUlVFLCByZWJhbGFuY2Vfb24gPSByYnApDQpoZWFkKHBvcnRfZXF3X20kQk9QLldlaWdodCwgMjIpDQpoZWFkKHBvcnRfZXF3X20kRU9QLldlaWdodCwgMjIpDQoNCiMgUG9ydGFmb2xpbyBSaXNrIFBhcml0eSAoUlApDQplcF9tIDwtIGVuZHBvaW50cyhyb2xsX3JwLCBvbiA9IHJicCkNCnBvcnRfcnBfbSA8LSBSZXR1cm4ucG9ydGZvbGlvKHkucl9jLCB3ZWlnaHRzID0gcm9sbF9ycFtlcF9tLCBdLCB2ZXJib3NlID0gVFJVRSkNCmhlYWQocm9sbF9ycFtlcF9tLCBdLCAyMikNCmhlYWQocG9ydF9ycF9tJEJPUC5XZWlnaHQsIDIyKQ0KaGVhZChwb3J0X3JwX20kRU9QLldlaWdodCwgMjIpDQoNCiMgUG9ydGFmb2xpbyBNaW5pbXVtIENvbm5lY3RlZG5lc3MgKE1DUCkNCmVwX20gPC0gZW5kcG9pbnRzKHcubWNwX3RlbXAsIG9uID0gcmJwKQ0KcG9ydF9tY3BfbSA8LSBSZXR1cm4ucG9ydGZvbGlvKHkucl9jLCB3ZWlnaHRzID0gdy5tY3BfdGVtcFtlcF9tLCBdLCB2ZXJib3NlID0gVFJVRSkNCg0KIyBQb3J0YWZvbGlvIFJpc2sgUGFyaXR5IENvbm5lY3RlZG5lc3MgKFJQQykNCmVwX20gPC0gZW5kcG9pbnRzKHcucnBwX3RlbXAsIG9uID0gcmJwKQ0KcG9ydF9ycHBfbSA8LSBSZXR1cm4ucG9ydGZvbGlvKHkucl9jLCB3ZWlnaHRzID0gdy5ycHBfdGVtcFtlcF9tLCBdLCB2ZXJib3NlID0gVFJVRSkNCmhlYWQody5ycHBfdGVtcFtlcF9tLCBdLCAyMikNCmhlYWQocG9ydF9ycHBfbSRCT1AuV2VpZ2h0LCAyMikNCmhlYWQocG9ydF9ycHBfbSRFT1AuV2VpZ2h0LCAyMikNCg0KIyBQb3J0YWZvbGlvIE3DoXhpbW8gU2hhcnBlIChNUykNCmVwX20gPC0gZW5kcG9pbnRzKHJvbGxfbXMsIG9uID0gcmJwKQ0KcG9ydF9tc19tIDwtIFJldHVybi5wb3J0Zm9saW8oeS5yX2MsIHdlaWdodHMgPSByb2xsX21zW2VwX20sIF0sIHZlcmJvc2UgPSBUUlVFKQ0KDQojIENvbWJpbmFyIHJldG9ybm9zIGRlIHRvZG9zIGxvcyBwb3J0YWZvbGlvcw0KcG9ydF9yZXRfbSA8LSBjYmluZCgNCiAgcG9ydF9lcXdfbSRyZXR1cm5zLA0KICBwb3J0X3JwX20kcmV0dXJucywNCiAgcG9ydF9ycHBfbSRyZXR1cm5zLA0KICBwb3J0X21zX20kcmV0dXJucw0KKQ0KY29sbmFtZXMocG9ydF9yZXRfbSkgPC0gYygiRVFXIiwgIlJQIiwgIlJQQyIsICJNUyIpDQpwb3J0X3JldF9tIDwtIG5hLm9taXQocG9ydF9yZXRfbSkNCmhlYWQocG9ydF9yZXRfbSkNCg0KIyBFc3RhZMOtc3RpY2FzIGFudWFsZXMgeSBkZSByaWVzZ28NCnRhMV9tIDwtIHRhYmxlLkFubnVhbGl6ZWRSZXR1cm5zKHBvcnRfcmV0X20sIHNjYWxlID0gMjUyLCBnZW9tZXRyaWMgPSBUUlVFLCBSZiA9IHJmcikNCnRhMl9tIDwtIHRhYmxlLkRvd25zaWRlUmlzayhwb3J0X3JldF9tLCBzY2FsZSA9IDI1MiwgUmYgPSByZnIsIE1BUiA9IDAuMDAsIHAgPSAwLjk1KQ0KdGEzX20gPC0gT21lZ2EocG9ydF9yZXRfbSwgUmYgPSByZnIpDQpzcl9tICA8LSBTb3J0aW5vUmF0aW8ocG9ydF9yZXRfbSkNCg0KIyBDb25zb2xpZGFyIHRhYmxhIHJlc3VtZW4gbWVuc3VhbA0Kc3VtbWFyeV9tb250aGx5IDwtIHJiaW5kKHRhMV9tLCB0YTJfbSwgdGEzX20sIHNyX20pDQpwcmludChzdW1tYXJ5X21vbnRobHkpDQoNCiMgQ3VydmEgZGUgcmVuZGltaWVudG8gYWN1bXVsYWRvIG1lbnN1YWwNCmNoYXJ0LkN1bVJldHVybnMoDQogIHBvcnRfcmV0X20sDQogIG1haW4gPSAiRXF1aXR5IEN1cnZlcyAoTW9udGhseSBSZWJhbGFuY2UpIiwNCiAgeWxhYiA9ICIiLA0KICBnZW9tZXRyaWMgPSBUUlVFLA0KICB3ZWFsdGguaW5kZXggPSBUUlVFLA0KICBsZWdlbmQubG9jID0gInRvcGxlZnQiDQopDQoNCmBgYA0KDQoNCg0KDQojIyBDb25uZWN0ZWRuZXNzOiBUVlAtVkFSDQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQ0KY2F0KCJcbkVzdGltYW5kbyBUVlAtVkFSIENvbm5lY3RlZG5lc3MuLi5cbiIpDQpubGFnIDwtIDE7IG5mb3JlIDwtIDIwOyB3aW5kb3cuc2l6ZSA8LSAyMDANCmRjYSA8LSBDb25uZWN0ZWRuZXNzQXBwcm9hY2goeS5yLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBubGFnPW5sYWcsIG5mb3JlPW5mb3JlLCBtb2RlbD0iVFZQLVZBUiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zaXplPXdpbmRvdy5zaXplLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWQVJfY29uZmlnPWxpc3QoVFZQVkFSPWxpc3Qoa2FwcGExPTAuOTksIGthcHBhMj0wLjk5LCBwcmlvcj0iQmF5ZXNQcmlvciIpKSkNCg0KY2F0KCJcbi0tLSBSZXN1bHRhZG9zIENvbm5lY3RlZG5lc3MgLS0tXG4iKQ0KZ2ZldmRfYXJyYXkgPC0gZGNhJENUDQpnZmV2ZF9hdmcgPC0gYXBwbHkoZ2ZldmRfYXJyYXksIGMoMSwyKSwgbWVhbiwgbmEucm09VFJVRSkNCmNvbG5hbWVzKGdmZXZkX2F2ZykgPC0gcm93bmFtZXMoZ2ZldmRfYXZnKSA8LSBzeW1ib2xzDQpwcmludChyb3VuZChnZmV2ZF9hdmcsMykpDQoNClRDSV9zZXJpZXMgPC0gZGNhJFRDSQ0KVENJX21lYW4gPC0gbWVhbihUQ0lfc2VyaWVzLCBuYS5ybT1UUlVFKQ0KY2F0KCJcblByb21lZGlvIFRDSToiLCByb3VuZChUQ0lfbWVhbiwyKSwgIlxuIikNCnBsb3QoaW5kZXgoVENJX3NlcmllcyksIGNvcmVkYXRhKFRDSV9zZXJpZXMpLCB0eXBlPSJsIiwNCiAgICAgbWFpbj0iVG90YWwgQ29ubmVjdGVkbmVzcyBJbmRleCAoVENJKSIsIHhsYWI9IkZlY2hhIiwgeWxhYj0iVENJIikNCmFibGluZShoPVRDSV9tZWFuLCBjb2w9InJlZCIsIGx0eT0yKQ0KDQpUT19zZXJpZXMgPC0gZGNhJFRPOyBGUk9NX3NlcmllcyA8LSBkY2EkRlJPTTsgTkVUX3NlcmllcyA8LSBkY2EkTkVUDQpUT19hdmcgPC0gY29sTWVhbnMoVE9fc2VyaWVzLCBuYS5ybT1UUlVFKQ0KRlJPTV9hdmcgPC0gY29sTWVhbnMoRlJPTV9zZXJpZXMsIG5hLnJtPVRSVUUpDQpORVRfYXZnIDwtIGNvbE1lYW5zKE5FVF9zZXJpZXMsIG5hLnJtPVRSVUUpDQpkaXJfc3VtbWFyeSA8LSBkYXRhLmZyYW1lKFZhcmlhYmxlPXN5bWJvbHMsIFRPX2F2ZywgRlJPTV9hdmcsIE5FVF9hdmcpDQpjYXQoIlxuLS0tIERpcmVjY2nDs24gcHJvbWVkaW8gKFRPL0ZST00vTkVUKSAtLS1cbiIpDQpsaWJyYXJ5KGRwbHlyKQ0KZGlyX3N1bW1hcnkgJT4lDQogIG11dGF0ZV9pZihpcy5udW1lcmljLCB+cm91bmQoLiwgMykpICU+JQ0KICBwcmludCgpDQoNCnBjaV9vYmogPC0gdHJ5Q2F0Y2goeyBDb25uZWN0ZWRuZXNzVGFibGUoZ2ZldmRfYXJyYXkpJFBDSSB9LCBlcnJvcj1mdW5jdGlvbihlKSBnZmV2ZF9hdmcpDQpjYXQoIlxuLS0tIFBhaXJ3aXNlIENvbm5lY3RlZG5lc3MgSW5kZXggKFBDSSkgcHJvbWVkaW8gLS0tXG4iKQ0KcHJpbnQocm91bmQocGNpX29iaiwzKSkNCg0KbWF0cGxvdChpbmRleChORVRfc2VyaWVzKSwgTkVUX3NlcmllcywgdHlwZT0nbCcsIGx0eT0xLA0KICAgICAgICBtYWluPSJORVQgZHluYW1pYyAoVE8gLSBGUk9NKSIsIHhsYWI9IkRhdGUiLCB5bGFiPSJORVQiKQ0KbGVnZW5kKCJ0b3ByaWdodCIsIGxlZ2VuZD1zeW1ib2xzLCBjb2w9MTpsZW5ndGgoc3ltYm9scyksIGx0eT0xLCBjZXg9MC44KQ0KDQpgYGANCg0KIyMgRXh0cmFlciBtZWRpZGFzIGNsYXZlIChHRkVWRCwgVENJLCBUTywgRlJPTSwgTkVULCBQQ0kpIA0KYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCnlfcl96b28gPC0gYXMuem9vKHkucikNCndfZXEgPC0gcmVwKDEvbmNvbCh5LnIpLCBuY29sKHkucikpOyBuYW1lcyh3X2VxKSA8LSBzeW1ib2xzDQpjb3ZfbWF0IDwtIGNvdihjb3JlZGF0YSh5LnIpLCB1c2U9ImNvbXBsZXRlLm9icyIpDQoNCndfcnAgPC0gdHJ5Q2F0Y2goeyByaXNrUGFyaXR5UG9ydGZvbGlvKGNvdl9tYXQpJHcgfSwNCiAgICAgICAgICAgICAgICAgZXJyb3I9ZnVuY3Rpb24oZSl7IG1lc3NhZ2UoIkVycm9yIFJpc2tQYXJpdHlQb3J0Zm9saW8gLT4gRVFXIHVzYWRvLiIpOyB3X2VxIH0pDQpuYW1lcyh3X3JwKSA8LSBzeW1ib2xzDQoNCmNhdCgiXG5QZXNvcyBFUVc6XG4iKTsgcHJpbnQocm91bmQod19lcSwzKSkNCmNhdCgiXG5QZXNvcyBSaXNrIFBhcml0eTpcbiIpOyBwcmludChyb3VuZCh3X3JwLDMpKQ0KDQptY3AgPC0gdHJ5Q2F0Y2goew0KICBNaW5pbXVtQ29ubmVjdGVkbmVzc1BvcnRmb2xpbyhhcy56b28oeS5yKSwgcGNpX29iaiwgc3RhdGlzdGljcz0iRmlzaGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kPSJjdW1zdW0iLCBtZXRyaWM9IlN0ZERldiIpDQp9LCBlcnJvcj1mdW5jdGlvbihlKXsgbWVzc2FnZSgiRXJyb3IgTUNQOiAiLCBlJG1lc3NhZ2UpOyBOVUxMIH0pDQoNCmlmKCFpcy5udWxsKG1jcCkpIHsNCiAgY2F0KCJcblBlc29zIE1pbmltdW0gQ29ubmVjdGVkbmVzcyBQb3J0Zm9saW8gKE1DUCk6XG4iKQ0KICBwcmludChyb3VuZChtY3AkcG9ydGZvbGlvX3dlaWdodHMsMykpDQp9DQoNCnJwcCA8LSB0cnlDYXRjaCh7DQogIFJpc2tQYXJpdHlQb3J0Zm9saW8oYXMuem9vKHkuciksIHBjaV9vYmosIHN0YXRpc3RpY3M9IkZpc2hlciIpDQp9LCBlcnJvcj1mdW5jdGlvbihlKXsgbWVzc2FnZSgiRXJyb3IgUlBDOiAiLCBlJG1lc3NhZ2UpOyBOVUxMIH0pDQoNCmlmKCFpcy5udWxsKHJwcCkpIHsNCiAgY2F0KCJcblBlc29zIFJpc2stUGFyaXR5IFBvcnRmb2xpbyAoUlBDKTpcbiIpDQogIHByaW50KHJvdW5kKHJwcCRwb3J0Zm9saW9fd2VpZ2h0cywzKSkNCn0NCmBgYA0KDQojIyBQb3J0YWZvbGlvczogRVFXLCBSaXNrUGFyaXR5LCBNaW5pbXVtQ29ubmVjdGVkbmVzc1BvcnRmb2xpbywgTVMgDQoNCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQptYXhfc2hhcnBlX3cgPC0gZnVuY3Rpb24ocHJpY2VzX3dpbmRvdykgew0KICB0cnlDYXRjaCh7DQogICAgcmV0IDwtIGFzLm1hdHJpeChwcmljZXNfd2luZG93KQ0KICAgIG11IDwtIGNvbE1lYW5zKHJldCwgbmEucm0gPSBUUlVFKQ0KICAgIFNpZ21hIDwtIGNvdihyZXQsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0KICAgIE4gPC0gbGVuZ3RoKG11KQ0KICAgIERtYXQgPC0gMiAqIFNpZ21hOyBkdmVjIDwtIHJlcCgwLCBOKQ0KICAgIEFtYXQgPC0gY2JpbmQocmVwKDEsIE4pLCBtdSkNCiAgICBidmVjIDwtIGMoMSwgMCkNCiAgICByZXMgPC0gc29sdmUuUVAoRG1hdCwgZHZlYywgQW1hdCwgYnZlYz1idmVjLCBtZXE9MSkNCiAgICB3IDwtIHBtYXgocmVzJHNvbHV0aW9uLCAwKQ0KICAgIHcgLyBzdW0odykNCiAgfSwgZXJyb3I9ZnVuY3Rpb24oZSkgcmVwKDEvbmNvbChwcmljZXNfd2luZG93KSwgbmNvbChwcmljZXNfd2luZG93KSkpDQp9DQoNCmNhdCgiXG5DYWxjdWxhbmRvIHBvcnRhZm9saW8gTWF4LVNoYXJwZSByb2xsaW5nLi4uXG4iKQ0Kd2wgPC0gbWluKDI1MiwgbnJvdyh5LnIpKQ0Kcm9sbF9tcyA8LSByb2xsYXBwbHkoYXMubWF0cml4KHkuciksIHdpZHRoPXdsLCBGVU49ZnVuY3Rpb24oeCkgbWF4X3NoYXJwZV93KHgpLA0KICAgICAgICAgICAgICAgICAgICAgYnkuY29sdW1uPUZBTFNFLCBhbGlnbj0icmlnaHQiKQ0KY2F0KCJSb2xsaW5nIE1lYW4tU2hhcnBlIGxpc3RvLlxuIikNCg0KcG9ydF9yZXQgPC0gUmV0dXJuLnBvcnRmb2xpbyh5LnIsIHdlaWdodHM9d19lcSkNCmNoYXJ0LkN1bVJldHVybnMocG9ydF9yZXQsIG1haW49IkN1cnZhIGFjdW11bGFkYSBFUVciLCBsZWdlbmQubG9jPSJ0b3BsZWZ0Iiwgd2VhbHRoLmluZGV4PVRSVUUpDQoNClRDSV9kYXRlcyA8LSBhcy5EYXRlKHJvd25hbWVzKFRDSV9zZXJpZXMpKQ0KVENJX3h0cyA8LSB4dHMoYXMubnVtZXJpYyhUQ0lfc2VyaWVzKSwgb3JkZXIuYnk9VENJX2RhdGVzKQ0KY29tbW9uX2lkeCA8LSBpbnRlcnNlY3QoaW5kZXgoVENJX3h0cyksIGluZGV4KHBvcnRfcmV0KSkNCnBhcihtZnJvdz1jKDEsMikpDQpwbG90KGluZGV4KFRDSV94dHNbY29tbW9uX2lkeF0pLCBjb3JlZGF0YShUQ0lfeHRzW2NvbW1vbl9pZHhdKSwgdHlwZT0ibCIsIG1haW49IlRDSSIsIHlsYWI9IlRDSSIsIHhsYWI9IkRhdGUiKQ0KcGxvdChpbmRleChwb3J0X3JldFtjb21tb25faWR4LF0pLCBjb3JlZGF0YShwb3J0X3JldFtjb21tb25faWR4LCJwb3J0Zm9saW8ucmV0dXJucyJdKSwNCiAgICAgdHlwZT0ibCIsIG1haW49IkVRVyBSZXR1cm5zIiwgeWxhYj0iUmV0dXJuIiwgeGxhYj0iRGF0ZSIpDQoNCmBgYA0KDQojIyBQZXJmb3JtYW5jZSBzdW1tYXJ5IGFuZCByZWxhY2nDs24gY29uIFRDSQ0KYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCnJmcl9kYWlseSA8LSAwICAjIHRhc2EgbGlicmUgZGUgcmllc2dvIGRpYXJpYQ0KY2F0KCJcbi0tLSBJbmRpY2Fkb3JlcyBkZSBkZXNlbXBlw7FvIC0tLVxuIikNCg0KIyBNw6l0cmljYXMgY2zDoXNpY2FzDQp0YTEgPC0gdGFibGUuQW5udWFsaXplZFJldHVybnMocG9ydF9yZXQsIHNjYWxlID0gMjUyLCBSZiA9IHJmcl9kYWlseSkNCnRhMiA8LSB0YWJsZS5Eb3duc2lkZVJpc2socG9ydF9yZXQsIHNjYWxlID0gMjUyLCBSZiA9IHJmcl9kYWlseSwgTUFSID0gMCwgcCA9IC45NSkNCnRhMyA8LSBPbWVnYShwb3J0X3JldCwgUmYgPSByZnJfZGFpbHkpDQoNCiMgVW5pciBlbiB1bmEgdGFibGENCnBlcmZfYWxsIDwtIHJiaW5kKHRhMSwgdGEyLCB0YTMpDQpwcmludChyb3VuZChwZXJmX2FsbCwgNCkpDQoNCiMgLS0tIENvcnJlbGFjacOzbiBlbnRyZSBUQ0kgeSByZXRvcm5vcyBkZWwgcG9ydGFmb2xpbyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NClRDSV9kYXRlcyA8LSBhcy5EYXRlKHJvd25hbWVzKFRDSV9zZXJpZXMpKQ0KVENJX3h0cyA8LSB4dHMoYXMubnVtZXJpYyhUQ0lfc2VyaWVzKSwgb3JkZXIuYnkgPSBUQ0lfZGF0ZXMpDQpjb21tb25faWR4IDwtIGludGVyc2VjdChpbmRleChUQ0lfeHRzKSwgaW5kZXgocG9ydF9yZXQpKQ0KDQppZiAobGVuZ3RoKGNvbW1vbl9pZHgpID4gMTApIHsNCiAgY29ycyA8LSBjb3IoY29yZWRhdGEoVENJX3h0c1tjb21tb25faWR4XSksDQogICAgICAgICAgICAgIGNvcmVkYXRhKHBvcnRfcmV0W2NvbW1vbl9pZHgsXSksDQogICAgICAgICAgICAgIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0KICBjYXQoIlxuLS0tIENvcnJlbGFjacOzbiBlbnRyZSBUQ0kgeSBwb3J0YWZvbGlvKHMpIC0tLVxuIikNCiAgcHJpbnQocm91bmQoY29ycywgNCkpDQp9DQoNCiMgLS0tIEdyw6FmaWNvcyBkZSBkZXNlbXBlw7FvIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQpjYXQoIlxuTW9zdHJhbmRvIGN1cnZhcyBhY3VtdWxhZGFzIGRlIHBvcnRhZm9saW8ocykuLi5cbiIpDQpjaGFydC5DdW1SZXR1cm5zKHBvcnRfcmV0LCBtYWluPSJFcXVpdHkgQ3VydmVzIChQb3J0YWZvbGlvcykiLA0KICAgICAgICAgICAgICAgICBsZWdlbmQubG9jPSJ0b3BsZWZ0Iiwgd2VhbHRoLmluZGV4PVRSVUUpDQoNCiMgLS0tIEdyw6FmaWNvIFRDSSB2cyBSZXRvcm5vcyBkZSBwb3J0YWZvbGlvIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KY2F0KCJcbk1vc3RyYW5kbyBUQ0kgdnMgRVFXIHJldHVybnMuLi5cbiIpDQpwYXIobWZyb3c9YygxLDIpKQ0KcGxvdChpbmRleChUQ0lfeHRzW2NvbW1vbl9pZHhdKSwgY29yZWRhdGEoVENJX3h0c1tjb21tb25faWR4XSksIHR5cGU9ImwiLA0KICAgICBtYWluPSJUQ0kiLCB5bGFiPSJUQ0kiLCB4bGFiPSJEYXRlIikNCnBsb3QoaW5kZXgocG9ydF9yZXRbY29tbW9uX2lkeCxdKSwgY29yZWRhdGEocG9ydF9yZXRbY29tbW9uX2lkeCwicG9ydGZvbGlvLnJldHVybnMiXSksDQogICAgIHR5cGU9ImwiLCBtYWluPSJFUVcgUmV0dXJucyIsIHlsYWI9IlJldHVybiIsIHhsYWI9IkRhdGUiKQ0KYGBgDQoNCmBgYHtyIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpnZmV2ZF9hcnJheSA8LSBkY2EkQ1QNCmdmZXZkX2F2ZyA8LSBhcHBseShnZmV2ZF9hcnJheSwgYygxLDIpLCBtZWFuLCBuYS5ybT1UUlVFKQ0KY29sbmFtZXMoZ2ZldmRfYXZnKSA8LSByb3duYW1lcyhnZmV2ZF9hdmcpIDwtIHN5bWJvbHMNCnByaW50KHJvdW5kKGdmZXZkX2F2ZywzKSkNCg0KDQpUQ0lfc2VyaWVzIDwtIGRjYSRUQ0kNClRDSV9tZWFuIDwtIG1lYW4oVENJX3NlcmllcywgbmEucm09VFJVRSkNCmNhdCgiXG5Qcm9tZWRpbyBUQ0k6Iiwgcm91bmQoVENJX21lYW4sMiksICJcbiIpDQojcGxvdChpbmRleChUQ0lfc2VyaWVzKSwgY29yZWRhdGEoVENJX3NlcmllcyksIHR5cGU9ImwiLCAuLi4pDQoNCiMgUENJIChQYWlyd2lzZSBDb25uZWN0ZWRuZXNzIEluZGV4KQ0KcGNpX29iaiA8LSB0cnlDYXRjaCh7DQogIENvbm5lY3RlZG5lc3NUYWJsZShnZmV2ZF9hcnJheSkkUENJDQp9LCBlcnJvcj1mdW5jdGlvbihlKSBnZmV2ZF9hdmcpDQpwcmludChyb3VuZChwY2lfb2JqLDMpKQ0KYGBgDQoNCg==