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.2 Syntaxe

dt[group1 == "A", mean(value), by = group2]
   group2           V1
1:      C 0.0008501418
2:      D 0.0539426361

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=