4. Modelo Bayesiano train.
4.1 Run: Fit bayesian model (train)
# Run Fit Bayesian Model
# file path for actual model
file_path <- "~/Documents/bayes_soccer/output/models/bayes_ucl_20260418.rds"
start <- Sys.time()
if (file.exists(file_path)) {
# Load the object if the file exists
bayes_ucl_20260418 <- readRDS(file_path)
} else {
# Create the object
bayes_ucl_20260418 <- fit_bayesian_model(train)
# Save it for future use
saveRDS(bayes_ucl_20260418, file = file_path)
}
end <- Sys.time()
print(end - start)
Time difference of 0.3158648 secs
Length Class Mode
1 character character
4.3 Run: Evaluate model full (test)
- Using Bayesian model_ucl & test data
# Run: Evaluate model using train data
# file path for actual model
file_path <- "~/Documents/bayes_soccer/output/models/eval_bayes_ucl_20260418.rds"
start <- Sys.time()
if (file.exists(file_path)) {
# Load the object if the file exists
eval_bayes_ucl_20260418 <- readRDS(file_path)
} else {
# Create the object
eval_bayes_ucl_20260418 <-
evaluate_model_full(bayes_ucl_20260418, # actual model ucl
test,
test_size=0.2)
# Save it for future use
saveRDS(eval_bayes_ucl_20260418, file = file_path)
}
end <- Sys.time()
print(end - start)
Time difference of 0.4185491 secs
summary("eval_bayes_ucl_20260418")
Length Class Mode
1 character character
4.4 Check calibration results (test)
# check calibration results
calibration_results <- cbind(
eval_bayes_ucl_20260418$calibration_data, test) %>%
select(cup:goals_away,pH:actual, correct) %>%
mutate_if(is.numeric, round, 2)
glimpse(calibration_results)
Rows: 36
Columns: 13
$ cup <chr> "ucl2526", "ucl2526", "ucl2526…
$ date <date> 2026-02-17, 2026-02-17, 2026-…
$ competition <fct> UCL, UCL, UCL, UCL, UCL, UCL, …
$ season <fct> 2025_2026, 2025_2026, 2025_202…
$ home_team <fct> Benfica, Galatasaray, Monaco, …
$ away_team <fct> Real Madrid, Juventus, PSG, At…
$ goals_home <dbl> 0, 5, 2, 2, 3, 3, 1, 0, 4, 3, …
$ goals_away <dbl> 1, 2, 3, 0, 1, 3, 6, 2, 1, 2, …
$ pH <dbl> 0.48, 0.57, 0.55, 0.55, 0.47, …
$ pD <dbl> 0.08, 0.10, 0.09, 0.10, 0.10, …
$ pA <dbl> 0.43, 0.33, 0.35, 0.35, 0.43, …
$ actual <chr> "A", "H", "A", "H", "H", "D", …
$ correct <lgl> FALSE, TRUE, FALSE, TRUE, TRUE…
4.5 Check metrics (logloss, brier, etc.).
- logloss, brier, accuracy & baseline_log_loss.
# metrics
eval_bayes_ucl_20260418$metrics
$log_loss
[1] 1.002739
$brier_score
[1] 0.2000082
$accuracy
[1] 0.4722222
$baseline_log_loss
[1] 0.9730874
5. Prediccion futura (test).
5.1 check test data
Rows: 36
Columns: 14
$ cup <chr> "ucl2526", "ucl2526", "ucl2526…
$ date <date> 2026-02-17, 2026-02-17, 2026-…
$ competition <fct> UCL, UCL, UCL, UCL, UCL, UCL, …
$ season <fct> 2025_2026, 2025_2026, 2025_202…
$ home_team <fct> Benfica, Galatasaray, Monaco, …
$ away_team <fct> Real Madrid, Juventus, PSG, At…
$ goals_home <int> 0, 5, 2, 2, 3, 3, 1, 0, 4, 3, …
$ goals_away <int> 1, 2, 3, 0, 1, 3, 6, 2, 1, 2, …
$ rest_home <dbl> 20, 20, 20, 20, 21, 21, 21, 21…
$ rest_away <dbl> 20, 20, 20, 20, 21, 21, 21, 21…
$ goal_diff <int> -1, 3, -1, 2, 2, 0, -5, -2, 3,…
$ form_home <dbl> 0.8, 1.4, 1.4, 1.2, 1.0, 1.2, …
$ form_away <dbl> -0.8, -1.4, -1.4, -1.2, -1.0, …
$ matchweek <int> 145, 146, 147, 148, 149, 150, …
5.2 build_features (test)
# build_features
df_test <- build_features(test)
glimpse(df_test)
Rows: 36
Columns: 14
$ cup <chr> "ucl2526", "ucl2526", "ucl2526…
$ date <date> 2026-02-17, 2026-02-17, 2026-…
$ competition <fct> UCL, UCL, UCL, UCL, UCL, UCL, …
$ season <fct> 2025_2026, 2025_2026, 2025_202…
$ home_team <fct> Benfica, Galatasaray, Monaco, …
$ away_team <fct> Real Madrid, Juventus, PSG, At…
$ goals_home <int> 0, 5, 2, 2, 3, 3, 1, 0, 4, 3, …
$ goals_away <int> 1, 2, 3, 0, 1, 3, 6, 2, 1, 2, …
$ rest_home <dbl> 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, …
$ rest_away <dbl> 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, …
$ goal_diff <int> -1, 3, -1, 2, 2, 0, -5, -2, 3,…
$ form_home <dbl> 0.0, 0.0, 0.0, 0.0, 1.0, 1.2, …
$ form_away <dbl> 0.0, 0.0, 0.0, 0.0, -1.0, -1.2…
$ matchweek <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,…
5.3 Fit Bayesian Model (test)
Time difference of 0.673301 secs
Length Class Mode
1 character character
5.4 Crear partidos futuros
# crear partidos futuros
new_matches <- data.frame(
home_team=c("Bayern Munich","Liverpool",
"Atletico Madrid","Arsenal"),
away_team=c("Real Madrid","PSG",
"Barcelona","Sporting"),
competition=c("UCL"),
season=c("2025_2026"),
form_home=c(0.6,0.7),
form_away=c(0.5,0.65),
rest_home=c(5,4),
rest_away=c(4,3)
)
glimpse(new_matches)
Rows: 4
Columns: 8
$ home_team <chr> "Bayern Munich", "Liverpool", …
$ away_team <chr> "Real Madrid", "PSG", "Barcelo…
$ competition <chr> "UCL", "UCL", "UCL", "UCL"
$ season <chr> "2025_2026", "2025_2026", "202…
$ form_home <dbl> 0.6, 0.7, 0.6, 0.7
$ form_away <dbl> 0.50, 0.65, 0.50, 0.65
$ rest_home <dbl> 5, 4, 5, 4
$ rest_away <dbl> 4, 3, 4, 3
5.5 Predecir probabilidades
# Predecir probabilidades
preds <- lapply(1:nrow(new_matches), function(i){
predict_match_probabilities(bayes_ucl_test_20260418,
new_matches[i,])
})
head(preds,3)
[[1]]
[[1]]$prob_1X2
Home Draw Away
0.54400 0.17025 0.28575
[[1]]$score_distribution
[,1] [,2] [,3] [,4] [,5]
[1,] 0.01950 0.02400 0.02350 0.01125 0.00825
[2,] 0.03575 0.05300 0.04225 0.03050 0.01850
[3,] 0.04225 0.06300 0.05400 0.03175 0.01850
[4,] 0.03275 0.04875 0.04050 0.02675 0.01375
[5,] 0.02625 0.03625 0.02750 0.02000 0.01100
[6,] 0.01500 0.02150 0.01775 0.01575 0.00875
[7,] 0.00875 0.01425 0.01175 0.00775 0.00325
[,6] [,7]
[1,] 0.00275 0.00175
[2,] 0.00825 0.00475
[3,] 0.00700 0.00450
[4,] 0.00900 0.00300
[5,] 0.00625 0.00200
[6,] 0.00450 0.00075
[7,] 0.00125 0.00100
[[1]]$simulations
[[2]]
[[2]]$prob_1X2
Home Draw Away
0.4775 0.1745 0.3480
[[2]]$score_distribution
[,1] [,2] [,3] [,4] [,5]
[1,] 0.01550 0.02225 0.02575 0.01850 0.01125
[2,] 0.03075 0.05275 0.05175 0.03750 0.01750
[3,] 0.03150 0.05775 0.05650 0.04300 0.02100
[4,] 0.02825 0.04600 0.04550 0.03025 0.02000
[5,] 0.01675 0.03825 0.02975 0.02150 0.01300
[6,] 0.00875 0.01825 0.01700 0.01275 0.00650
[7,] 0.00400 0.01100 0.01125 0.00650 0.00450
[,6] [,7]
[1,] 0.00325 0.00200
[2,] 0.01050 0.00450
[3,] 0.01000 0.00450
[4,] 0.00725 0.00400
[5,] 0.00750 0.00325
[6,] 0.00600 0.00325
[7,] 0.00150 0.00050
[[2]]$simulations
[[3]]
[[3]]$prob_1X2
Home Draw Away
0.50425 0.17000 0.32575
[[3]]$score_distribution
[,1] [,2] [,3] [,4] [,5]
[1,] 0.01625 0.02550 0.02075 0.01575 0.00850
[2,] 0.03175 0.05250 0.04525 0.03525 0.01875
[3,] 0.03550 0.05825 0.05550 0.03125 0.01825
[4,] 0.02775 0.04800 0.04025 0.03050 0.01950
[5,] 0.01775 0.03025 0.02900 0.02125 0.01075
[6,] 0.01475 0.02025 0.01575 0.01850 0.00600
[7,] 0.00725 0.00850 0.01275 0.00600 0.00500
[,6] [,7]
[1,] 0.00550 0.00150
[2,] 0.00925 0.00425
[3,] 0.01200 0.00500
[4,] 0.00775 0.00500
[5,] 0.00850 0.00325
[6,] 0.00300 0.00100
[7,] 0.00300 0.00150
[[3]]$simulations
NANA
5.5.1 preds[[1]]$prob_1X2
Home Draw Away
0.54400 0.17025 0.28575
5.5.2 preds[[1]]$score_distribution
row col
[1,] 3 2
5.5.3 pred$score_distribution
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.01950 0.024 0.02350 0.01125 0.00825 0.00275
[2,] 0.03575 0.053 0.04225 0.03050 0.01850 0.00825
[,7]
[1,] 0.00175
[2,] 0.00475
LS0tCnRpdGxlOiAiMjAyNjA0MTlfd29ya2Zsb3dfdjEiCmF1dGhvcjogIkFuZHJlcyBQRU5BIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGNlcnVsZWFuICAjIE9wY2lvbmVzOiBkZWZhdWx0LCBjZXJ1bGVhbiwgam91cm5hbCwgZmxhdGx5LCBkYXJrbHksIHJlYWRhYmxlLCBldGMuCiAgICBoaWdobGlnaHQ6IHRhbmdvICMgUmVzYWx0YWRvIGRlIGPDs2RpZ28KICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICBkZl9wcmludDogcGFnZWQKLS0tCgojIFBlbmRpbmcgCgojIFJlc3VsdHMgCgogICAgMSkgQ29tcGV0aXRpb246IFVDTCAtIEVVUk8gLSBGV0MuIAogICAgMikgcGFydGl0aW9uIGRhdGE6IHRyYWluIC0gdGVzdC4gIAogICAgMikgTWF0aCBtb2RlbHMgOiBCYXllc2lhbiAtIE1vbnRlIENhcmxvLiAgCiAgICAzKSBQcm9jY2VzczogRXN0aW1hdGlvbiAtIEZvcmVjYXN0LiAgCiAgICAKIyBXb3JrZmxvdwogIAogICAgICAxKSBMb2FkIG1hdGNoZXMgZGF0YS4gIAogICAgICAgIDEuMSkgU2VsZWN0IGRhdGEgdG8gcnVuIG1vZGVscy4gIAogICAgICAKICAgICAgMikgQnVpbGQgZmVhdHVyZXMgKGZvcm1hICsgZmF0aWdhKS4gICAKICAgICAgCiAgICAgIDMpIFNwbGl0IHRlbXBvcmFsICh0cmFpbiAvIHRlc3QpLiAKICAgICAgCiAgICAgIDQpIE1vZGVsbyBCYXllc2lhbm8gdXNpbmcgdHJhaW4uICAgIAogICAgICAgIDQuMSkgUnVuOiBmaXRfYmF5ZXNpYW5fbW9kZWwgKHRyYWluKS4gCiAgICAgICAgNC4yKSBNb2RlbCBldmFsdWF0aW9uICh0cmFpbikuCiAgICAgICAgNC4zKSBSdW46IEV2YWx1YXRlIG1vZGVsIGZ1bGwgKHRlc3QpLiAgCiAgICAgICAgNC40KSBDaGVjayBjYWxpYnJhdGlvbiByZXN1bHRzICh0ZXN0KS4gCiAgICAgICAgNC41KSBDaGVjayBtZXRyaWNzCiAgICAgICAgCiAgICAgIDUpIFByZWRpY2Npb24gZnV0dXJhICsgTW9udGUgQ2FybG8gKHRlc3QpICAgCiAgICAgICAgNS4xKSBDaGVjayB0ZXN0IGRhdGEuIAogICAgICAgIDUuMikgQnVpbGQgZmVhdHVyZXMgKHRlc3QpCiAgICAgICAgNS4zKSBSdW4gZml0X2JheWVzaWFuX21vZGVsICh0ZXN0KS4gCiAgICAgICAgNS40KSBDcmVhciBwYXJ0aWRvcyBmdXR1cm9zLiAKICAgICAgICA1LjUpIFByZWRlY2lyIHByb2JhYmlsaWRhZGVzLiAKICAgICAgICAKICAgICAgNikgU2ltdWxhdGUgTW9udGUgQ2FybG8gKHRlc3QpIAogICAgICAgIDYuMSkgRnVuOiBzaW11bGF0ZV9zZWFzb25fbW9udGVjYXJsby4gCiAgICAgICAgNi4yKSBDcmVhdGUgbmV3X21hdGNoZXMuMS4gCiAgICAgICAgNi4zKSBSdW46IHNpbXVsYXRlX3NlYXNvbl9tb250ZWNhcmxvLiAKICAgICAgICA2LjQpIE1lYW5zIHNpbXVsYXRpb24gcmVzdWx0cy4gIAogICAgICAgIDYuNSkgU2ltdWxhdGUgcGFydGlhbCByZXN1bHRzIC4gCiAgICAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyAxLiBMb2FkIGxpYnJhcmllcwoKIyBjbGVhciB3b3Jrc3BhY2UgCnJtKGxpc3QgPSBscygpKQoKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgUEFDS0FHRVMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgpwYWNrYWdlcyA8LSBjKCJ0aWR5dmVyc2UiLCAiYnJtcyIsICJwb3N0ZXJpb3IiLCJ0aWR5YmF5ZXMiLCJzbGlkZXIiLCAicnN0YW4iLCJsdWJyaWRhdGUiLCAic3RyaW5naSIsImRwbHlyIiwidGlkeXIiLCJEVCIsInBsb3RseSIsICJwYXRjaHdvcmsiKQoKIyBMb2FkIGFsbCBwYWNrYWdlcyBpbiB0aGUgdmVjdG9yCmxhcHBseShwYWNrYWdlcywgbGlicmFyeSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKQoKIyBsb2FkIGFsbCBSIGZ1bmN0aW9uIAoKIyBEZWZpbmUgdGhlIGZvbGRlciBwYXRoCmZvbGRlcl9wYXRoIDwtICJ+L0RvY3VtZW50cy9iYXllc19zb2NjZXIvUiIKCiMgTGlzdCBhbGwgLlIgZmlsZXMgd2l0aCBmdWxsIHBhdGhzCnJfZmlsZXMgPC0gbGlzdC5maWxlcyhwYXRoID0gZm9sZGVyX3BhdGgsIHBhdHRlcm4gPSAiXFwuW1JyXSQiLCBmdWxsLm5hbWVzID0gVFJVRSkKCiMgU291cmNlIGVhY2ggZmlsZQpzYXBwbHkocl9maWxlcywgc291cmNlKQpgYGAKCiMgMS4gTWF0Y2hlcyBkYXRhIAoKYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMgTG9hZCBtYXRjaGVzIGRhdGEgCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKbG9hZCgifi9Eb2N1bWVudHMvYmF5ZXNfc29jY2VyL2RhdGEvcHJvY2Vzc2VkLzIwMjYwNDE3X2V1cm9fdWNsX2Z3Y19tYXRjaGVzLnJkYSIpCgojIHByaW50IG1hdGNoZXMgZGF0YQptYXRjaGVzICU+JSAKICBncm91cF9ieShzZWFzb24sIGNvbXBldGl0aW9uLCBjdXApICU+JSAKICBzdW1tYXJpc2UoZ2FtZXMgPSBuKCksIAogICAgICAgICAgICBzZWFzb24gPXVuaXF1ZShzZWFzb24pKSAlPiUKICB0aWJibGUoKQpgYGAKCiMjIDEuMSBTZWxlY3QgZGF0YSB0byBydW4gbW9kZWxzIAoKLSBjb21wZXRpdGlvbiA9PSAiVUNMIiwgCi0gc2Vhc29uID09ICIyMDI1XzIwMjYiCgpgYGB7cn0KbWF0Y2hlcyA8LSBtYXRjaGVzICU+JSAKICBmaWx0ZXIoY29tcGV0aXRpb24gPT0gIlVDTCIsIAogICAgICAgICBzZWFzb24gPT0gIjIwMjVfMjAyNiIpICU+JSAKICBkcm9wX25hKGdvYWxzX2hvbWUpCgojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyBWQUxJREFSIENPTFVNTkFTIFJFUVVFUklEQVMKIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgogIHJlcXVpcmVkX2NvbHMgPC0gYygiZGF0ZSIsImNvbXBldGl0aW9uIiwic2Vhc29uIiwiaG9tZV90ZWFtIiwiYXdheV90ZWFtIiwiZ29hbHNfaG9tZSIsImdvYWxzX2F3YXkiCiAgKQoKICBtaXNzaW5nX2NvbHMgPC0gc2V0ZGlmZihyZXF1aXJlZF9jb2xzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyhtYXRjaGVzKSkKCiAgaWYobGVuZ3RoKG1pc3NpbmdfY29scykgPiAwKXsKICAgIHN0b3AocGFzdGUoIkZhbHRhbiBjb2x1bW5hczoiLCBwYXN0ZShtaXNzaW5nX2NvbHMsIGNvbGxhcHNlPSIsICIpKSkKICB9CgogICMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICMgQ09OVkVSU0lPTkVTIERFIFRJUE8KICAjID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KICBtYXRjaGVzIDwtIG1hdGNoZXMgJT4lCiAgICBtdXRhdGUoCiAgICAgIGNvbXBldGl0aW9uID0gZmFjdG9yKGNvbXBldGl0aW9uKSwKICAgICAgc2Vhc29uID0gZmFjdG9yKHNlYXNvbiksCiAgICAgIGhvbWVfdGVhbSA9IGZhY3Rvcihob21lX3RlYW0pLAogICAgICBhd2F5X3RlYW0gPSBmYWN0b3IoYXdheV90ZWFtKSwKICAgICAgZ29hbHNfaG9tZSA9IGFzLmludGVnZXIoZ29hbHNfaG9tZSksCiAgICAgIGdvYWxzX2F3YXkgPSBhcy5pbnRlZ2VyKGdvYWxzX2F3YXkpCiAgICApCgogICMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQogICMgVkFMSURBQ0lPTkVTIElNUE9SVEFOVEVTCiAgIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CiAgaWYoYW55KGlzLm5hKG1hdGNoZXMkZ29hbHNfaG9tZSkpIHwgYW55KGlzLm5hKG1hdGNoZXMkZ29hbHNfYXdheSkpKXsKICAgIHN0b3AoIkV4aXN0ZW4gZ29sZXMgTkEg4oCUIHJldmlzYXIgZGF0b3MuIikKICB9CgogIGlmKGFueShtYXRjaGVzJGdvYWxzX2hvbWUgPCAwIHwgbWF0Y2hlcyRnb2Fsc19hd2F5IDwgMCkpewogICAgc3RvcCgiTG9zIGdvbGVzIG5vIHB1ZWRlbiBzZXIgbmVnYXRpdm9zLiIpCiAgfQoKICAjIG9yZGVuYXIgdGVtcG9yYWxtZW50ZQogIG1hdGNoZXMgPC0gbWF0Y2hlcyAlPiUgYXJyYW5nZShkYXRlKQoKZ2xpbXBzZShtYXRjaGVzKQpgYGAKCiMgMi4gQnVpbGQgZmVhdHVyZXMgKGZvcm1hICsgZmF0aWdhKQoKIyMgMi4xIFJ1biBidWlsZF9mZWF0dXJlcwoKYGBge3J9CiMgUnVuIGJ1aWxkX2ZlYXR1cmVzCgpkZiA8LSBtYXRjaGVzCgptYXRjaGVzIDwtIGJ1aWxkX2ZlYXR1cmVzKG1hdGNoZXMpCgpnbGltcHNlKG1hdGNoZXMpCmBgYAoKIyAzLiBTcGxpdCB0ZW1wb3JhbCAodHJhaW4gLyB0ZXN0KSAgIAoKYGBge3J9CiMgU3BsaXQgdGVtcG9yYWwKCiAgIyA9PT09PT09PT09PT09PT09PT09PT09PT09PQogICMgMS4gU1BMSVQgVEVNUE9SQUwKICAjID09PT09PT09PT09PT09PT09PT09PT09PT09CiAgCiAgbWF0Y2hlcyA8LSBtYXRjaGVzICU+JSBhcnJhbmdlKGRhdGUpCiAgdGVzdF9zaXplID0gMC4yCiAgCiAgc3BsaXRfaW5kZXggPC0gZmxvb3IoKDEgLSB0ZXN0X3NpemUpICogbnJvdyhtYXRjaGVzKSkKICAKICB0cmFpbiA8LSBtYXRjaGVzWzE6c3BsaXRfaW5kZXgsIF0KICB0ZXN0ICA8LSBtYXRjaGVzWyhzcGxpdF9pbmRleCsxKTpucm93KG1hdGNoZXMpLCBdCiAgCiAgbWVzc2FnZSgiVHJhaW4gc2l6ZToiLCBucm93KHRyYWluKSkKICBtZXNzYWdlKCJUZXN0IHNpemU6IiwgbnJvdyh0ZXN0KSkKYGBgCgojIDQuIE1vZGVsbyBCYXllc2lhbm8gdHJhaW4uCgojIyA0LjEgUnVuOiBGaXQgYmF5ZXNpYW4gbW9kZWwgKHRyYWluKSAgCgotIGNyZWF0ZSB1Y2xfMjAyNjA0MTggCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFJ1biBGaXQgQmF5ZXNpYW4gTW9kZWwKCiMgZmlsZSBwYXRoIGZvciBhY3R1YWwgbW9kZWwKCmZpbGVfcGF0aCA8LSAifi9Eb2N1bWVudHMvYmF5ZXNfc29jY2VyL291dHB1dC9tb2RlbHMvYmF5ZXNfdWNsXzIwMjYwNDE4LnJkcyIKCnN0YXJ0IDwtIFN5cy50aW1lKCkKICAKICBpZiAoZmlsZS5leGlzdHMoZmlsZV9wYXRoKSkgewogICAgIyBMb2FkIHRoZSBvYmplY3QgaWYgdGhlIGZpbGUgZXhpc3RzCiAgICBiYXllc191Y2xfMjAyNjA0MTggPC0gcmVhZFJEUyhmaWxlX3BhdGgpCiAgfSBlbHNlIHsKICAgICMgQ3JlYXRlIHRoZSBvYmplY3QKICAgIGJheWVzX3VjbF8yMDI2MDQxOCA8LSBmaXRfYmF5ZXNpYW5fbW9kZWwodHJhaW4pCiAgICAKICAgICMgU2F2ZSBpdCBmb3IgZnV0dXJlIHVzZQogICAgc2F2ZVJEUyhiYXllc191Y2xfMjAyNjA0MTgsIGZpbGUgPSBmaWxlX3BhdGgpCiAgfQoKZW5kIDwtIFN5cy50aW1lKCkKCnByaW50KGVuZCAtIHN0YXJ0KQoKc3VtbWFyeSgidWNsXzIwMjYwNDE4IikKYGBgCgojIyA0LjMgUnVuOiBFdmFsdWF0ZSBtb2RlbCBmdWxsICh0ZXN0KQoKLSBVc2luZyBCYXllc2lhbiBtb2RlbF91Y2wgJiB0ZXN0IGRhdGEKCmBgYHtyfQojIFJ1bjogRXZhbHVhdGUgbW9kZWwgdXNpbmcgdHJhaW4gZGF0YQoKIyBmaWxlIHBhdGggZm9yIGFjdHVhbCBtb2RlbAoKZmlsZV9wYXRoIDwtICJ+L0RvY3VtZW50cy9iYXllc19zb2NjZXIvb3V0cHV0L21vZGVscy9ldmFsX2JheWVzX3VjbF8yMDI2MDQxOC5yZHMiCgpzdGFydCA8LSBTeXMudGltZSgpCiAgCiAgaWYgKGZpbGUuZXhpc3RzKGZpbGVfcGF0aCkpIHsKICAgICMgTG9hZCB0aGUgb2JqZWN0IGlmIHRoZSBmaWxlIGV4aXN0cwogICAgZXZhbF9iYXllc191Y2xfMjAyNjA0MTggPC0gcmVhZFJEUyhmaWxlX3BhdGgpCiAgfSBlbHNlIHsKICAgICMgQ3JlYXRlIHRoZSBvYmplY3QKICAgIGV2YWxfYmF5ZXNfdWNsXzIwMjYwNDE4IDwtCiAgICAgIGV2YWx1YXRlX21vZGVsX2Z1bGwoYmF5ZXNfdWNsXzIwMjYwNDE4LCAjIGFjdHVhbCBtb2RlbCB1Y2wKICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgIHRlc3Rfc2l6ZT0wLjIpCiAgICAKICAgICMgU2F2ZSBpdCBmb3IgZnV0dXJlIHVzZQogICAgc2F2ZVJEUyhldmFsX2JheWVzX3VjbF8yMDI2MDQxOCwgZmlsZSA9IGZpbGVfcGF0aCkKICB9CmVuZCA8LSBTeXMudGltZSgpCgpwcmludChlbmQgLSBzdGFydCkKCnN1bW1hcnkoImV2YWxfYmF5ZXNfdWNsXzIwMjYwNDE4IikKYGBgCgojIyA0LjQgQ2hlY2sgY2FsaWJyYXRpb24gcmVzdWx0cyAodGVzdCkKCi0gdXNpbmcgdGVzdCBkYXRhCgpgYGB7cn0KIyBjaGVjayBjYWxpYnJhdGlvbiByZXN1bHRzCgpjYWxpYnJhdGlvbl9yZXN1bHRzIDwtIGNiaW5kKAogIGV2YWxfYmF5ZXNfdWNsXzIwMjYwNDE4JGNhbGlicmF0aW9uX2RhdGEsIHRlc3QpICU+JQogIHNlbGVjdChjdXA6Z29hbHNfYXdheSxwSDphY3R1YWwsIGNvcnJlY3QpICU+JQogIG11dGF0ZV9pZihpcy5udW1lcmljLCByb3VuZCwgMikKCmdsaW1wc2UoY2FsaWJyYXRpb25fcmVzdWx0cykKYGBgCgojIyA0LjUgQ2hlY2sgbWV0cmljcyAobG9nbG9zcywgYnJpZXIsIGV0Yy4pLiAgIAoKLSBsb2dsb3NzLCBicmllciwgYWNjdXJhY3kgJiBiYXNlbGluZV9sb2dfbG9zcy4KCmBgYHtyfQojIG1ldHJpY3MKCmV2YWxfYmF5ZXNfdWNsXzIwMjYwNDE4JG1ldHJpY3MKYGBgCgojIDUuIFByZWRpY2Npb24gZnV0dXJhICh0ZXN0KS4gCgotIHVzYW5kbyB0ZXN0IGRhdGEgCgojIyA1LjEgY2hlY2sgdGVzdCBkYXRhCgpgYGB7ciBlY2hvPUZBTFNFfQojIGNoZWNrIHRlc3QgZGF0YQoKZ2xpbXBzZSh0ZXN0KQpgYGAKCiMjIDUuMiBidWlsZF9mZWF0dXJlcyAodGVzdCkgCgpgYGB7cn0KIyBidWlsZF9mZWF0dXJlcwoKZGZfdGVzdCA8LSBidWlsZF9mZWF0dXJlcyh0ZXN0KQpnbGltcHNlKGRmX3Rlc3QpCmBgYAoKIyMgNS4zIEZpdCBCYXllc2lhbiBNb2RlbCAodGVzdCkgCgpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0V9CiMgUnVuIEZpdCBCYXllc2lhbiBNb2RlbAoKIyBmaWxlIHBhdGggZm9yIGFjdHVhbCBtb2RlbAoKZmlsZV9wYXRoIDwtICJ+L0RvY3VtZW50cy9iYXllc19zb2NjZXIvb3V0cHV0L21vZGVscy9iYXllc191Y2xfdGVzdF8yMDI2MDQxOC5yZHMiCgpzdGFydCA8LSBTeXMudGltZSgpCiAgCiAgaWYgKGZpbGUuZXhpc3RzKGZpbGVfcGF0aCkpIHsKICAgICMgTG9hZCB0aGUgb2JqZWN0IGlmIHRoZSBmaWxlIGV4aXN0cwogICAgYmF5ZXNfdWNsX3Rlc3RfMjAyNjA0MTggPC0gcmVhZFJEUyhmaWxlX3BhdGgpCiAgfSBlbHNlIHsKICAgICMgQ3JlYXRlIHRoZSBvYmplY3QKICAgIGJheWVzX3VjbF90ZXN0XzIwMjYwNDE4IDwtIGZpdF9iYXllc2lhbl9tb2RlbCh0cmFpbikKICAgIAogICAgIyBTYXZlIGl0IGZvciBmdXR1cmUgdXNlCiAgICBzYXZlUkRTKGJheWVzX3VjbF90ZXN0XzIwMjYwNDE4LCBmaWxlID0gZmlsZV9wYXRoKQogIH0KCmVuZCA8LSBTeXMudGltZSgpCgpwcmludChlbmQgLSBzdGFydCkKYGBgCgojIyA1LjQgQ3JlYXIgcGFydGlkb3MgZnV0dXJvcyAKCmBgYHtyfQojIGNyZWFyIHBhcnRpZG9zIGZ1dHVyb3MKCm5ld19tYXRjaGVzIDwtIGRhdGEuZnJhbWUoCiAgaG9tZV90ZWFtPWMoIkJheWVybiBNdW5pY2giLCJMaXZlcnBvb2wiLAogICAgICAgICAgICAgICJBdGxldGljbyBNYWRyaWQiLCJBcnNlbmFsIiksCiAgYXdheV90ZWFtPWMoIlJlYWwgTWFkcmlkIiwiUFNHIiwKICAgICAgICAgICAgICAiQmFyY2Vsb25hIiwiU3BvcnRpbmciKSwKICBjb21wZXRpdGlvbj1jKCJVQ0wiKSwKICBzZWFzb249YygiMjAyNV8yMDI2IiksCiAgZm9ybV9ob21lPWMoMC42LDAuNyksIAogIGZvcm1fYXdheT1jKDAuNSwwLjY1KSwKICByZXN0X2hvbWU9Yyg1LDQpLAogIHJlc3RfYXdheT1jKDQsMykKICAgIAopCgpnbGltcHNlKG5ld19tYXRjaGVzKQpgYGAKCiMjIDUuNSBQcmVkZWNpciBwcm9iYWJpbGlkYWRlcwoKYGBge3J9CiMgUHJlZGVjaXIgcHJvYmFiaWxpZGFkZXMKCnByZWRzIDwtIGxhcHBseSgxOm5yb3cobmV3X21hdGNoZXMpLCBmdW5jdGlvbihpKXsKICBwcmVkaWN0X21hdGNoX3Byb2JhYmlsaXRpZXMoYmF5ZXNfdWNsX3Rlc3RfMjAyNjA0MTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld19tYXRjaGVzW2ksXSkKfSkKCmhlYWQocHJlZHMsMykKYGBgCgojIyMgNS41LjEgcHJlZHNbWzFdXSRwcm9iXzFYMgoKYGBge3IgZWNobz1GQUxTRX0KIyBwcmVkc1tbMV1dJHByb2JfMVgyIAoKcHJlZHNbWzFdXSRwcm9iXzFYMgpgYGAKCiMjIyA1LjUuMiBwcmVkc1tbMV1dJHNjb3JlX2Rpc3RyaWJ1dGlvbgoKYGBge3IgZWNobz1GQUxTRX0KIyBwcmVkc1tbMV1dJHNjb3JlX2Rpc3RyaWJ1dGlvbgoKd2hpY2gocHJlZHNbWzFdXSRzY29yZV9kaXN0cmlidXRpb249PQogICAgICAgIG1heChwcmVkc1tbMV1dJHNjb3JlX2Rpc3RyaWJ1dGlvbiksIAogICAgICBhcnIuaW5kID0gVFJVRSkKYGBgCgojIyMgNS41LjMgcHJlZCRzY29yZV9kaXN0cmlidXRpb24KCmBgYHtyIGVjaG89RkFMU0V9CiMgcHJlZHNbWzFdXSRzY29yZV9kaXN0cmlidXRpb24KCmhlYWQocHJlZHNbWzFdXSRzY29yZV9kaXN0cmlidXRpb24sMikKYGBgCgojIDYuIFNpbXVsYXRlIE1vbnRlIENhcmxvLiAKCiMjIDYuMSBEZWZpbmUgZGF0YSB0byBiZSB1c2VkLiAKCmBgYHtyfQojIGNyZWFyIHBhcnRpZG9zIGZ1dHVyb3MKCm5ld19tYXRjaGVzLjEgPC0gZGF0YS5mcmFtZSgKICBob21lX3RlYW09YygiQmF5ZXJuIE11bmljaCIsIkxpdmVycG9vbCIsIkF0bGV0aWNvIE1hZHJpZCIsIkFyc2VuYWwiKSwKICBhd2F5X3RlYW09YygiUmVhbCBNYWRyaWQiLCJQU0ciLCJCYXJjZWxvbmEiLCJTcG9ydGluZyIpLAogIGNvbXBldGl0aW9uPWMoIlVDTCIpLAogIHNlYXNvbj1jKCIyMDI1XzIwMjYiKSwKICBmb3JtX2hvbWU9YygwLjYsMC43KSwgCiAgZm9ybV9hd2F5PWMoMC41LDAuNjUpLAogIHJlc3RfaG9tZT1jKDUsNCksCiAgcmVzdF9hd2F5PWMoNCwzKQogICAgCikKCmdsaW1wc2UobmV3X21hdGNoZXMuMSkKYGBgCgojIyA2LjIgUnVuOiBzaW11bGF0ZV9zZWFzb25fbW9udGVjYXJsbwoKLSBVc2luZyBkYXRhOiBuZXdfbWF0Y2hlcy4yLiAgCi0gbW9kZWwgb2JqZWN0OiBtY191Y2xfdGVzdF8yMDI2MDQxOAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZmlsZV9wYXRoIDwtICJ+L0RvY3VtZW50cy9iYXllc19zb2NjZXIvb3V0cHV0L21vZGVscy9tY191Y2xfdGVzdF8yMDI2MDQxOC5yZHMiCgpzdGFydCA8LSBTeXMudGltZSgpCiAgCiAgaWYgKGZpbGUuZXhpc3RzKGZpbGVfcGF0aCkpIHsKICAgICMgTG9hZCB0aGUgb2JqZWN0IGlmIHRoZSBmaWxlIGV4aXN0cwogICAgbWNfdWNsX3Rlc3RfMjAyNjA0MTggPC0gcmVhZFJEUyhmaWxlX3BhdGgpCiAgfSBlbHNlIHsKICAgICMgQ3JlYXRlIHRoZSBvYmplY3QKICAgIG1jX3VjbF90ZXN0XzIwMjYwNDE4ID0KICAgICAgc2ltdWxhdGVfc2Vhc29uX21vbnRlY2FybG8oCiAgICAgICAgYmF5ZXNfdWNsX3Rlc3RfMjAyNjA0MTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdfbWF0Y2hlcy4xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5zaW09MTAwMCkKICAgIAogICAgIyBTYXZlIGl0IGZvciBmdXR1cmUgdXNlCiAgICBzYXZlUkRTKG1jX3VjbF90ZXN0XzIwMjYwNDE4LCBmaWxlID0gZmlsZV9wYXRoKQogIH0KCmVuZCA8LSBTeXMudGltZSgpCgpwcmludChlbmQgLSBzdGFydCkKYGBgCgojIyA2LjMgTWVhbnMgc2ltdWxhdGlvbiByZXN1bHRzICAKCmBgYHtyfQptY191Y2xfdGVzdF8yMDI2MDQxOCRzaW11bGF0aW9uX3Jlc3VsdHMgJT4lIAogIGdyb3VwX2J5KHRlYW0pICU+JSAKICBzdW1tYXJpc2UocG9pbnQgPSBtZWFuKHBvaW50cyksIAogICAgICAgICAgICBnb2Fsc19mb3IgPSBtZWFuKGdvYWxzX2ZvciksCiAgICAgICAgICAgIGdvYWxzX2FnYWluc3QgPSBtZWFuKGdvYWxzX2FnYWluc3QpLAogICAgICAgICAgICBwb3NpdGlvbiA9IG1lYW4ocG9zaXRpb24pKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCAyKSAlPiUKICBhcnJhbmdlKHBvc2l0aW9uKQpgYGAKCiMjIDYuNCBTaW11bGF0ZSBwYXJ0aWFsIHJlc3VsdHMgIAoKLSBFeHBvcnQgcmVzdWx0cyB1c2luZyAqKm1hdGNoZXMuMSoqIGRhdGEgYXMgYSBpbnB1dC4gIAoKYGBge3J9CiMgRXhwb3J0YXIgcmVzdWx0YWRvcwoKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIG1hdGNoID0gcGFzdGUoCiAgICBuZXdfbWF0Y2hlcy4xJGhvbWVfdGVhbSwgInZzIixuZXdfbWF0Y2hlcy4xJGF3YXlfdGVhbSksCiAgcF9ob21lPXNhcHBseShwcmVkcywgZnVuY3Rpb24oeCkgeCRwcm9iXzFYMlsiSG9tZSJdKSwKICBwX2RyYXc9c2FwcGx5KHByZWRzLCBmdW5jdGlvbih4KSB4JHByb2JfMVgyWyJEcmF3Il0pLAogIHBfYXdheT1zYXBwbHkocHJlZHMsIGZ1bmN0aW9uKHgpIHgkcHJvYl8xWDJbIkF3YXkiXSkKKQoKcmVzdWx0cyAlPiUgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCAzKQpgYGAKCiMgNy4gU2ltdWxhdGUgTW9udGUgQ2FybG8uIAoKIyMgNy4xIERlZmluZSBkYXRhIHRvIGJlIHVzZWQuIAoKYGBge3J9CiMgY3JlYXIgcGFydGlkb3MgZnV0dXJvcwoKbmV3X21hdGNoZXMuMiA8LSBkYXRhLmZyYW1lKAogIGhvbWVfdGVhbT1jKCJQU0ciLCJBdGxldGljbyBNYWRyaWQiLCAKICAgICAgICAgICAgICAiQmF5ZXJuIE11bmljaCIsIkFyc2VuYWwiKSwKICBhd2F5X3RlYW09YygiQmF5ZXJuIE11bmljaCIsIkFyc2VuYWwiLCAKICAgICAgICAgICAgICAiUFNHIiwiQXRsZXRpY28gTWFkcmlkIiksCiAgY29tcGV0aXRpb249YygiVUNMIiksCiAgc2Vhc29uPWMoIjIwMjVfMjAyNiIpLAogIGZvcm1faG9tZT1jKDAuNiwwLjcpLCAKICBmb3JtX2F3YXk9YygwLjUsMC42NSksCiAgcmVzdF9ob21lPWMoNSw0KSwKICByZXN0X2F3YXk9Yyg0LDMpCiAgICAKKQoKZ2xpbXBzZShuZXdfbWF0Y2hlcy4yKQpgYGAKCiMjIDcuMiBSdW46IHNpbXVsYXRlX3NlYXNvbl9tb250ZWNhcmxvCgotIFVzaW5nIGRhdGE6IG5ld19tYXRjaGVzLjIuICAKLSBtb2RlbCBvYmplY3Q6IG1jX3VjbF90ZXN0XzIwMjYwNDE4X3YyIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZmlsZV9wYXRoIDwtICJ+L0RvY3VtZW50cy9iYXllc19zb2NjZXIvb3V0cHV0L21vZGVscy9tY191Y2xfdGVzdF8yMDI2MDQxOF92Mi5yZHMiCgpzdGFydCA8LSBTeXMudGltZSgpCiAgCiAgaWYgKGZpbGUuZXhpc3RzKGZpbGVfcGF0aCkpIHsKICAgICMgTG9hZCB0aGUgb2JqZWN0IGlmIHRoZSBmaWxlIGV4aXN0cwogICAgbWNfdWNsX3Rlc3RfMjAyNjA0MThfdjIgPC0gcmVhZFJEUyhmaWxlX3BhdGgpCiAgfSBlbHNlIHsKICAgICMgQ3JlYXRlIHRoZSBvYmplY3QKICAgIG1jX3VjbF90ZXN0XzIwMjYwNDE4X3YyID0KICAgICAgc2ltdWxhdGVfc2Vhc29uX21vbnRlY2FybG8oCiAgICAgICAgYmF5ZXNfdWNsX3Rlc3RfMjAyNjA0MTgsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXdfbWF0Y2hlcy4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5zaW09MTAwMCkKICAgIAogICAgIyBTYXZlIGl0IGZvciBmdXR1cmUgdXNlCiAgICBzYXZlUkRTKG1jX3VjbF90ZXN0XzIwMjYwNDE4X3YyLCBmaWxlID0gZmlsZV9wYXRoKQogIH0KCmVuZCA8LSBTeXMudGltZSgpCgpwcmludChlbmQgLSBzdGFydCkKYGBgCgojIyA3LjMgTWVhbnMgc2ltdWxhdGlvbiByZXN1bHRzICAKCmBgYHtyfQptY191Y2xfdGVzdF8yMDI2MDQxOF92MiRzaW11bGF0aW9uX3Jlc3VsdHMgJT4lIAogIGdyb3VwX2J5KHRlYW0pICU+JSAKICBzdW1tYXJpc2UocG9pbnQgPSBtZWFuKHBvaW50cyksIAogICAgICAgICAgICBnb2Fsc19mb3IgPSBtZWFuKGdvYWxzX2ZvciksCiAgICAgICAgICAgIGdvYWxzX2FnYWluc3QgPSBtZWFuKGdvYWxzX2FnYWluc3QpLAogICAgICAgICAgICBwb3NpdGlvbiA9IG1lYW4ocG9zaXRpb24pKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCAyKSAlPiUKICBhcnJhbmdlKHBvc2l0aW9uKQpgYGAKCiMjIDcuNCBTaW11bGF0ZSBwYXJ0aWFsIHJlc3VsdHMgIAoKLSBFeHBvcnQgcmVzdWx0cyB1c2luZyAqKm1hdGNoZXMuMioqIGRhdGEgYXMgYSBpbnB1dC4gIAoKYGBge3J9CiMgRXhwb3J0YXIgcmVzdWx0YWRvcwoKcmVzdWx0cy4yIDwtIGRhdGEuZnJhbWUoCiAgbWF0Y2ggPSBwYXN0ZSgKICAgIG5ld19tYXRjaGVzLjIkaG9tZV90ZWFtLCAidnMiLG5ld19tYXRjaGVzLjIkYXdheV90ZWFtKSwKICBwX2hvbWU9c2FwcGx5KHByZWRzLCBmdW5jdGlvbih4KSB4JHByb2JfMVgyWyJIb21lIl0pLAogIHBfZHJhdz1zYXBwbHkocHJlZHMsIGZ1bmN0aW9uKHgpIHgkcHJvYl8xWDJbIkRyYXciXSksCiAgcF9hd2F5PXNhcHBseShwcmVkcywgZnVuY3Rpb24oeCkgeCRwcm9iXzFYMlsiQXdheSJdKQopCgpyZXN1bHRzLjIgJT4lIG11dGF0ZV9pZihpcy5udW1lcmljLCByb3VuZCwgMykKYGBg