5.1.1 Importation avec fread
library(data.table)
set.seed(1234)
dt <- data.table(group1 = c("A", "B"),
group2 = rep(c("C", "D"), each = 5000),
value = rnorm(10000),
weight = sample(1:10, 10000, replace = TRUE))
dt
group1 group2 value weight
1: A C -1.20706575 1
2: B C 0.27742924 9
3: A C 1.08444118 8
4: B C -2.34569770 7
5: A C 0.42912469 7
---
9996: B D 0.01973902 2
9997: A D -2.12674529 10
9998: B D -0.05022201 4
9999: A D -0.23817408 6
10000: B D 0.77640531 8
write.table(dt,"dt.csv",sep=",",row.names=FALSE,quote=FALSE)
cat("File size (MB):", round(file.info("dt.csv")$size/1024^2),"\n")
File size (MB): 0
system.time(df <- read.table("dt.csv",sep=",",header=T,stringsAsFactors=F))
utilisateur système écoulé
0.01 0.00 0.04
system.time(dt <- fread("dt.csv"))
utilisateur système écoulé
0.00 0.00 0.02
all.equal(as.data.table(df),dt)
[1] TRUE
set.seed(1234)
n <- 1e6
dt2 <- data.table(a=sample(1:1000,n,replace=TRUE),
b=runif(n),
c=rnorm(n),
d=sample(c("A","B","C","D"),n,replace=TRUE))
write.table(dt2,"dt2.csv",sep=",",row.names=FALSE,quote=FALSE)
cat("Taille en (MB):", round(file.info("dt2.csv")$size/1024^2),"\n")
Taille en (MB): 28
system.time(df2 <- read.table("dt2.csv", sep=",", header=TRUE, stringsAsFactors=FALSE))
utilisateur système écoulé
2.28 0.06 2.36
system.time(dt2 <- fread("dt2.csv"))
utilisateur système écoulé
0.10 0.03 0.06
5.1.3 Sélection
dt[1:2, ]
group1 group2 value weight
1: A C -1.2070657 1
2: B C 0.2774292 9
dt[c(1,5)] # virgule optionnelle
group1 group2 value weight
1: A C -1.2070657 1
2: A C 0.4291247 7
dt[order(value), ]
group1 group2 value weight
1: B C -3.396064 6
2: B D -3.335108 8
3: A C -3.233152 9
4: A D -3.200732 7
5: B D -3.185662 6
---
9996: B D 3.357021 4
9997: B D 3.456972 3
9998: A D 3.560775 6
9999: B D 3.606510 6
10000: B D 3.618107 10
dt[weight > 9, ] # pas besoin de guillemets
group1 group2 value weight
1: A C -0.5644520 10
2: B C -0.9111954 10
3: B C 0.4595894 10
4: A C 0.6565885 10
5: A C -1.3907009 10
---
1007: B D 0.2090612 10
1008: A D 0.5321609 10
1009: B D 1.0577233 10
1010: A D 1.1622009 10
1011: A D -2.1267453 10
dt[weight > 9 & group2 == "C", ]
group1 group2 value weight
1: A C -0.5644520 10
2: B C -0.9111954 10
3: B C 0.4595894 10
4: A C 0.6565885 10
5: A C -1.3907009 10
---
524: B C 0.5206022 10
525: B C -0.8170175 10
526: A C -1.2598663 10
527: A C 2.6986404 10
528: B C -0.2878009 10
dt[, 1]
group1
1: A
2: B
3: A
4: B
5: A
---
9996: B
9997: A
9998: B
9999: A
10000: B
dt[, c(1,3)]
group1 value
1: A -1.20706575
2: B 0.27742924
3: A 1.08444118
4: B -2.34569770
5: A 0.42912469
---
9996: B 0.01973902
9997: A -2.12674529
9998: B -0.05022201
9999: A -0.23817408
10000: B 0.77640531
dt[, "group1"]
group1
1: A
2: B
3: A
4: B
5: A
---
9996: B
9997: A
9998: B
9999: A
10000: B
dt[, c("group1", "value")]
group1 value
1: A -1.20706575
2: B 0.27742924
3: A 1.08444118
4: B -2.34569770
5: A 0.42912469
---
9996: B 0.01973902
9997: A -2.12674529
9998: B -0.05022201
9999: A -0.23817408
10000: B 0.77640531
dt[, list(group1)]
group1
1: A
2: B
3: A
4: B
5: A
---
9996: B
9997: A
9998: B
9999: A
10000: B
dt[, list(group1, value)]
group1 value
1: A -1.20706575
2: B 0.27742924
3: A 1.08444118
4: B -2.34569770
5: A 0.42912469
---
9996: B 0.01973902
9997: A -2.12674529
9998: B -0.05022201
9999: A -0.23817408
10000: B 0.77640531
dt[, .(group1, value)]
group1 value
1: A -1.20706575
2: B 0.27742924
3: A 1.08444118
4: B -2.34569770
5: A 0.42912469
---
9996: B 0.01973902
9997: A -2.12674529
9998: B -0.05022201
9999: A -0.23817408
10000: B 0.77640531
dt[, list(mygroup = group1, myvalue = value)][1:2]
mygroup myvalue
1: A -1.2070657
2: B 0.2774292
dt$value
dt[["value"]]
5.1.4 Manipulation
dt[, tval := trunc(value)][1:2]
group1 group2 value weight tval
1: A C -1.2070657 1 -1
2: B C 0.2774292 9 0
dt[, c("tvalue", "rvalue") := list(trunc(value), round(value, 2))]
dt[, ':=' (tvalue = trunc(value), rvalue = round(value ,2))]
dt[, tvalue := tvalue + 10] # modification
dt[, rvalue := NULL] # suppression
dt[ group1 %in% "A", weight := weight * 10L][1:2]
group1 group2 value weight tval tvalue
1: A C -1.2070657 10 -1 9
2: B C 0.2774292 9 0 10
dt[is.na(value), value := mean(value, na.rm = TRUE)]
dt[, sum(value)] # un vecteur
[1] 61.15893
dt[, list(sum(value))] # un data-table
V1
1: 61.15893
dt[, list(somme = sum(value), moyenne = mean(value))]
somme moyenne
1: 61.15893 0.006115893
dt[group1 == "B" & group2 == "C", list(sum(value), mean(value))]
V1 V2
1: -33.89884 -0.01355953
dt[, sum(value), by = group1]
group1 V1
1: A 136.98194
2: B -75.82302
dt[, sum(value), by = "group1"]
group1 V1
1: A 136.98194
2: B -75.82302
dt[, list(somme = sum(value)), by = list(group1, group2)]
group1 group2 somme
1: A C 2.125355
2: B C -33.898836
3: A D 134.856590
4: B D -41.924180
dt[, list(somme = sum(value)), by = .(group1, group2)]
group1 group2 somme
1: A C 2.125355
2: B C -33.898836
3: A D 134.856590
4: B D -41.924180
dt[, list(somme = sum(value)), by = c("group1", "group2")]
group1 group2 somme
1: A C 2.125355
2: B C -33.898836
3: A D 134.856590
4: B D -41.924180
dt[, list(somme = sum(value)), by = list(pop = group1, poids = weight > 5)]
pop poids somme
1: A TRUE 136.98194
2: B TRUE -58.17120
3: B FALSE -17.65182
dt[, mean_group1 := mean(value), by = list(group1)][1:3]
group1 group2 value weight tval tvalue mean_group1
1: A C -1.2070657 10 -1 9 0.02739639
2: B C 0.2774292 9 0 10 -0.01516460
3: A C 1.0844412 80 1 11 0.02739639
dt[weight > 5, .N, by = list(group1, group2)][order(-N)]
group1 group2 N
1: A C 2500
2: A D 2500
3: B C 1305
4: B D 1268
dt[, list(mean(value), mean(weight)), by = list(group1, group2)]
group1 group2 V1 V2
1: A C 0.0008501418 55.4920
2: B C -0.0135595342 5.6124
3: A D 0.0539426361 54.7880
4: B D -0.0167696718 5.5424
dt[, lapply(.SD, mean), by = list(group1, group2)]
group1 group2 value weight tval tvalue mean_group1
1: A C 0.0008501418 55.4920 -0.0040 9.9960 0.02739639
2: B C -0.0135595342 5.6124 -0.0080 9.9920 -0.01516460
3: A D 0.0539426361 54.7880 0.0348 10.0348 0.02739639
4: B D -0.0167696718 5.5424 -0.0160 9.9840 -0.01516460
dt[, lapply(.SD, mean), by = group1, .SDcols = c("value", "weight")]
group1 value weight
1: A 0.02739639 55.1400
2: B -0.01516460 5.5774
dt[, lapply(.SD, mean), by = group1, .SDcols = -c("group2")]
group1 value weight tval tvalue mean_group1
1: A 0.02739639 55.1400 0.0154 10.0154 0.02739639
2: B -0.01516460 5.5774 -0.0120 9.9880 -0.01516460
sd_col <- c("value", "weight")
new_col <- c("t_value", "t_weight")
dt[,c(new_col) := lapply(.SD, trunc), .SDcols = sd_col]
tables()
NAME NROW NCOL MB COLS KEY
1: dt 10,000 9 1 group1,group2,value,weight,tval,tvalue,...
2: dt2 1,000,000 4 27 a,b,c,d
Total: 28MB
shift(1:10, type="lag", fill = NA, n=2L) # "lag" ou "lead"
[1] NA NA 1 2 3 4 5 6 7 8
setkeyv(dt, "group1")
key(dt)
[1] "group1"
dt["A"] # une valeur
group1 group2 value weight tval tvalue mean_group1 t_value t_weight
1: A C -1.2070657 10 -1 9 0.02739639 -1 10
2: A C 1.0844412 80 1 11 0.02739639 1 80
3: A C 0.4291247 70 0 10 0.02739639 0 70
4: A C -0.5747400 60 0 10 0.02739639 0 60
5: A C -0.5644520 100 0 10 0.02739639 0 100
---
4996: A D 1.1622009 100 1 11 0.02739639 1 100
4997: A D 0.1132464 20 0 10 0.02739639 0 20
4998: A D 1.2048600 80 1 11 0.02739639 1 80
4999: A D -2.1267453 100 -2 8 0.02739639 -2 100
5000: A D -0.2381741 60 0 10 0.02739639 0 60
dt[c("A", "B")] # plusieurs valeurs
group1 group2 value weight tval tvalue mean_group1 t_value t_weight
1: A C -1.20706575 10 -1 9 0.02739639 -1 10
2: A C 1.08444118 80 1 11 0.02739639 1 80
3: A C 0.42912469 70 0 10 0.02739639 0 70
4: A C -0.57473996 60 0 10 0.02739639 0 60
5: A C -0.56445200 100 0 10 0.02739639 0 100
---
9996: B D -1.34092741 7 -1 9 -0.01516460 -1 7
9997: B D -1.83042103 4 -1 9 -0.01516460 -1 4
9998: B D 0.01973902 2 0 10 -0.01516460 0 2
9999: B D -0.05022201 4 0 10 -0.01516460 0 4
10000: B D 0.77640531 8 0 10 -0.01516460 0 8
# clés multiples
setkey(dt, group1, group2)
dt["A"]
group1 group2 value weight tval tvalue mean_group1 t_value t_weight
1: A C -1.2070657 10 -1 9 0.02739639 -1 10
2: A C 1.0844412 80 1 11 0.02739639 1 80
3: A C 0.4291247 70 0 10 0.02739639 0 70
4: A C -0.5747400 60 0 10 0.02739639 0 60
5: A C -0.5644520 100 0 10 0.02739639 0 100
---
4996: A D 1.1622009 100 1 11 0.02739639 1 100
4997: A D 0.1132464 20 0 10 0.02739639 0 20
4998: A D 1.2048600 80 1 11 0.02739639 1 80
4999: A D -2.1267453 100 -2 8 0.02739639 -2 100
5000: A D -0.2381741 60 0 10 0.02739639 0 60
dt[list("A", c("C", "D"))]
group1 group2 value weight tval tvalue mean_group1 t_value t_weight
1: A C -1.2070657 10 -1 9 0.02739639 -1 10
2: A C 1.0844412 80 1 11 0.02739639 1 80
3: A C 0.4291247 70 0 10 0.02739639 0 70
4: A C -0.5747400 60 0 10 0.02739639 0 60
5: A C -0.5644520 100 0 10 0.02739639 0 100
---
4996: A D 1.1622009 100 1 11 0.02739639 1 100
4997: A D 0.1132464 20 0 10 0.02739639 0 20
4998: A D 1.2048600 80 1 11 0.02739639 1 80
4999: A D -2.1267453 100 -2 8 0.02739639 -2 100
5000: A D -0.2381741 60 0 10 0.02739639 0 60
# supressions des clés
setkeyv(dt, NULL)
dt <- data.table(x = 1, y = 1)
dt2 <- dt # nouvelle affectation
dt2[, y := 2] # modification de y
dt
x y
1: 1 2
dt2
x y
1: 1 2
dt <- data.table(x = 1, y = 1)
new_dt <- copy(dt)
new_dt[, y := 2] # modification de y
dt
x y
1: 1 1
df <- data.frame(x = 1, y = 1)
df2 <- df # nouvelle affectation
df2$y <- 2 # modification de y
df
x y
1 1 1
LS0tDQp0aXRsZTogIkxlIHBhY2thZ2UgZGF0YS50YWJsZSINCmF1dGhvcjogIkh1c3NvbiBldCBhbC4iDQpkYXRlOiAiMDkvMDkvMjAxOCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDogeWVzDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6ICczJw0KICAgIHRvY19mbG9hdDogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGNhY2hlID0gVFJVRSkNCmBgYA0KDQojIDUuMS4xIEltcG9ydGF0aW9uIGF2ZWMgZnJlYWQNCg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkYXRhLnRhYmxlKQ0Kc2V0LnNlZWQoMTIzNCkNCmR0IDwtIGRhdGEudGFibGUoZ3JvdXAxID0gYygiQSIsICJCIiksDQogICAgICAgICAgICAgICAgIGdyb3VwMiA9IHJlcChjKCJDIiwgIkQiKSwgZWFjaCA9IDUwMDApLA0KICAgICAgICAgICAgICAgICB2YWx1ZSA9IHJub3JtKDEwMDAwKSwNCiAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gc2FtcGxlKDE6MTAsIDEwMDAwLCByZXBsYWNlID0gVFJVRSkpDQpkdA0KYGBgDQoNCmBgYHtyfQ0Kd3JpdGUudGFibGUoZHQsImR0LmNzdiIsc2VwPSIsIixyb3cubmFtZXM9RkFMU0UscXVvdGU9RkFMU0UpDQpjYXQoIkZpbGUgc2l6ZSAoTUIpOiIsIHJvdW5kKGZpbGUuaW5mbygiZHQuY3N2Iikkc2l6ZS8xMDI0XjIpLCJcbiIpDQpgYGANCg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0Kc3lzdGVtLnRpbWUoZGYgPC0gcmVhZC50YWJsZSgiZHQuY3N2IixzZXA9IiwiLGhlYWRlcj1ULHN0cmluZ3NBc0ZhY3RvcnM9RikpDQpzeXN0ZW0udGltZShkdCA8LSBmcmVhZCgiZHQuY3N2IikpDQphbGwuZXF1YWwoYXMuZGF0YS50YWJsZShkZiksZHQpDQpgYGANCg0KYGBge3J9DQpzZXQuc2VlZCgxMjM0KQ0KbiA8LSAxZTYNCmR0MiA8LSBkYXRhLnRhYmxlKGE9c2FtcGxlKDE6MTAwMCxuLHJlcGxhY2U9VFJVRSksDQogICAgICAgICAgICAgICAgICAgIGI9cnVuaWYobiksDQogICAgICAgICAgICAgICAgICAgIGM9cm5vcm0obiksDQogICAgICAgICAgICAgICAgICAgIGQ9c2FtcGxlKGMoIkEiLCJCIiwiQyIsIkQiKSxuLHJlcGxhY2U9VFJVRSkpDQp3cml0ZS50YWJsZShkdDIsImR0Mi5jc3YiLHNlcD0iLCIscm93Lm5hbWVzPUZBTFNFLHF1b3RlPUZBTFNFKQ0KY2F0KCJUYWlsbGUgZW4gKE1CKToiLCByb3VuZChmaWxlLmluZm8oImR0Mi5jc3YiKSRzaXplLzEwMjReMiksIlxuIikNCnN5c3RlbS50aW1lKGRmMiA8LSByZWFkLnRhYmxlKCJkdDIuY3N2Iiwgc2VwPSIsIiwgaGVhZGVyPVRSVUUsIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpKQ0Kc3lzdGVtLnRpbWUoZHQyIDwtIGZyZWFkKCJkdDIuY3N2IikpDQpgYGANCg0KIyA1LjEuMiBTeW50YXhlDQoNCmBgYHtyfQ0KZHRbZ3JvdXAxID09ICJBIiwgbWVhbih2YWx1ZSksIGJ5ID0gZ3JvdXAyXQ0KYGBgDQoNCiMgNS4xLjMgU8OpbGVjdGlvbg0KDQpgYGB7cn0NCmR0WzE6MiwgXQ0KZHRbYygxLDUpXSAjIHZpcmd1bGUgb3B0aW9ubmVsbGUNCmR0W29yZGVyKHZhbHVlKSwgXQ0KYGBgDQoNCmBgYHtyfQ0KZHRbd2VpZ2h0ID4gOSwgXSAjIHBhcyBiZXNvaW4gZGUgZ3VpbGxlbWV0cw0KZHRbd2VpZ2h0ID4gOSAmIGdyb3VwMiA9PSAiQyIsIF0NCmBgYA0KDQpgYGB7cn0NCmR0WywgMV0NCmR0WywgYygxLDMpXQ0KYGBgDQoNCmBgYHtyfQ0KZHRbLCAiZ3JvdXAxIl0NCmR0WywgYygiZ3JvdXAxIiwgInZhbHVlIildDQpgYGANCg0KYGBge3J9DQpkdFssIGxpc3QoZ3JvdXAxKV0NCmR0WywgbGlzdChncm91cDEsIHZhbHVlKV0NCmR0WywgLihncm91cDEsIHZhbHVlKV0NCmR0WywgbGlzdChteWdyb3VwID0gZ3JvdXAxLCBteXZhbHVlID0gdmFsdWUpXVsxOjJdDQpgYGANCg0KYGBge3IscmVzdWx0cz1GQUxTRX0NCmR0JHZhbHVlDQpkdFtbInZhbHVlIl1dDQpgYGANCiMgNS4xLjQgTWFuaXB1bGF0aW9uDQoNCmBgYHtyfQ0KZHRbLCB0dmFsIDo9IHRydW5jKHZhbHVlKV1bMToyXQ0KYGBgDQpgYGB7cn0NCmR0WywgYygidHZhbHVlIiwgInJ2YWx1ZSIpIDo9IGxpc3QodHJ1bmModmFsdWUpLCByb3VuZCh2YWx1ZSwgMikpXQ0KZHRbLCAnOj0nICh0dmFsdWUgPSB0cnVuYyh2YWx1ZSksIHJ2YWx1ZSA9IHJvdW5kKHZhbHVlICwyKSldDQpgYGANCmBgYHtyfQ0KZHRbLCB0dmFsdWUgOj0gdHZhbHVlICsgMTBdICMgbW9kaWZpY2F0aW9uDQpkdFssIHJ2YWx1ZSA6PSBOVUxMXSAjIHN1cHByZXNzaW9uDQpgYGANCmBgYHtyfQ0KZHRbIGdyb3VwMSAlaW4lICJBIiwgd2VpZ2h0IDo9IHdlaWdodCAqIDEwTF1bMToyXQ0KYGBgDQpgYGB7cn0NCmR0W2lzLm5hKHZhbHVlKSwgdmFsdWUgOj0gbWVhbih2YWx1ZSwgbmEucm0gPSBUUlVFKV0NCmBgYA0KYGBge3J9DQpkdFssIHN1bSh2YWx1ZSldICMgdW4gdmVjdGV1cg0KZHRbLCBsaXN0KHN1bSh2YWx1ZSkpXSAjIHVuIGRhdGEtdGFibGUNCmR0WywgbGlzdChzb21tZSA9IHN1bSh2YWx1ZSksIG1veWVubmUgPSBtZWFuKHZhbHVlKSldDQpgYGANCmBgYHtyfQ0KZHRbZ3JvdXAxID09ICJCIiAmIGdyb3VwMiA9PSAiQyIsIGxpc3Qoc3VtKHZhbHVlKSwgbWVhbih2YWx1ZSkpXQ0KYGBgDQpgYGB7cn0NCmR0Wywgc3VtKHZhbHVlKSwgYnkgPSBncm91cDFdDQpkdFssIHN1bSh2YWx1ZSksIGJ5ID0gImdyb3VwMSJdDQpgYGANCmBgYHtyfQ0KZHRbLCBsaXN0KHNvbW1lID0gc3VtKHZhbHVlKSksIGJ5ID0gbGlzdChncm91cDEsIGdyb3VwMildDQpkdFssIGxpc3Qoc29tbWUgPSBzdW0odmFsdWUpKSwgYnkgPSAuKGdyb3VwMSwgZ3JvdXAyKV0NCmR0WywgbGlzdChzb21tZSA9IHN1bSh2YWx1ZSkpLCBieSA9IGMoImdyb3VwMSIsICJncm91cDIiKV0NCmBgYA0KDQpgYGB7cn0NCmR0WywgbGlzdChzb21tZSA9IHN1bSh2YWx1ZSkpLCBieSA9IGxpc3QocG9wID0gZ3JvdXAxLCBwb2lkcyA9IHdlaWdodCA+IDUpXQ0KYGBgDQpgYGB7cn0NCmR0WywgbWVhbl9ncm91cDEgOj0gbWVhbih2YWx1ZSksIGJ5ID0gbGlzdChncm91cDEpXVsxOjNdDQpgYGANCmBgYHtyfQ0KZHRbd2VpZ2h0ID4gNSwgLk4sIGJ5ID0gbGlzdChncm91cDEsIGdyb3VwMildW29yZGVyKC1OKV0NCmBgYA0KYGBge3J9DQpkdFssIGxpc3QobWVhbih2YWx1ZSksIG1lYW4od2VpZ2h0KSksIGJ5ID0gbGlzdChncm91cDEsIGdyb3VwMildDQpgYGANCmBgYHtyfQ0KZHRbLCBsYXBwbHkoLlNELCBtZWFuKSwgYnkgPSBsaXN0KGdyb3VwMSwgZ3JvdXAyKV0NCmBgYA0KYGBge3J9DQpkdFssIGxhcHBseSguU0QsIG1lYW4pLCBieSA9IGdyb3VwMSwgLlNEY29scyA9IGMoInZhbHVlIiwgIndlaWdodCIpXQ0KYGBgDQpgYGB7cn0NCmR0WywgbGFwcGx5KC5TRCwgbWVhbiksIGJ5ID0gZ3JvdXAxLCAuU0Rjb2xzID0gLWMoImdyb3VwMiIpXQ0KYGBgDQpgYGB7cn0NCnNkX2NvbCA8LSBjKCJ2YWx1ZSIsICJ3ZWlnaHQiKQ0KbmV3X2NvbCA8LSBjKCJ0X3ZhbHVlIiwgInRfd2VpZ2h0IikNCmR0WyxjKG5ld19jb2wpIDo9IGxhcHBseSguU0QsIHRydW5jKSwgLlNEY29scyA9IHNkX2NvbF0NCmBgYA0KYGBge3J9DQp0YWJsZXMoKQ0KYGBgDQpgYGB7cn0NCnNoaWZ0KDE6MTAsIHR5cGU9ImxhZyIsIGZpbGwgPSBOQSwgbj0yTCkgIyAibGFnIiBvdSAibGVhZCINCmBgYA0KYGBge3J9DQpzZXRrZXl2KGR0LCAiZ3JvdXAxIikNCmtleShkdCkNCmR0WyJBIl0gIyB1bmUgdmFsZXVyDQpkdFtjKCJBIiwgIkIiKV0gIyBwbHVzaWV1cnMgdmFsZXVycw0KIyBjbMOpcyBtdWx0aXBsZXMNCnNldGtleShkdCwgZ3JvdXAxLCBncm91cDIpDQpkdFsiQSJdDQpkdFtsaXN0KCJBIiwgYygiQyIsICJEIikpXQ0KIyBzdXByZXNzaW9ucyBkZXMgY2zDqXMNCnNldGtleXYoZHQsIE5VTEwpDQpgYGANCg0KYGBge3J9DQpkdCA8LSBkYXRhLnRhYmxlKHggPSAxLCB5ID0gMSkNCmR0MiA8LSBkdCAjIG5vdXZlbGxlIGFmZmVjdGF0aW9uDQpkdDJbLCB5IDo9IDJdICMgbW9kaWZpY2F0aW9uIGRlIHkNCmR0DQpkdDINCmBgYA0KYGBge3J9DQpkdCA8LSBkYXRhLnRhYmxlKHggPSAxLCB5ID0gMSkNCm5ld19kdCA8LSBjb3B5KGR0KQ0KbmV3X2R0WywgeSA6PSAyXSAjIG1vZGlmaWNhdGlvbiBkZSB5DQpkdA0KYGBgDQpgYGB7cn0NCmRmIDwtIGRhdGEuZnJhbWUoeCA9IDEsIHkgPSAxKQ0KZGYyIDwtIGRmICMgbm91dmVsbGUgYWZmZWN0YXRpb24NCmRmMiR5IDwtIDIgIyBtb2RpZmljYXRpb24gZGUgeQ0KZGYNCmBgYA0KDQo=