Rdatatable

https://github.com/Rdatatable

library(data.table)
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
data.table 1.12.2 using 2 threads (see ?getDTthreads).  Latest news: r-datatable.com

Introduction to data.table

https://cloud.r-project.org/web/packages/data.table/vignettes/datatable-intro.html

input <- if (file.exists("flights14.csv")) {
   "flights14.csv"
} else {
  "https://raw.githubusercontent.com/Rdatatable/data.table/master/vignettes/flights14.csv"
}
flights <- fread(input)

 [0%] Downloaded 1890 bytes...
 [0%] Downloaded 4649 bytes...
 [0%] Downloaded 7408 bytes...
 [0%] Downloaded 10167 bytes...
 [0%] Downloaded 12926 bytes...
 [0%] Downloaded 15515 bytes...
 [0%] Downloaded 18274 bytes...
 [0%] Downloaded 21033 bytes...
 [1%] Downloaded 23792 bytes...
 [1%] Downloaded 26551 bytes...
 [1%] Downloaded 29310 bytes...
 [1%] Downloaded 31899 bytes...
 [2%] Downloaded 48283 bytes...
 [2%] Downloaded 64667 bytes...
 [3%] Downloaded 81051 bytes...
 [4%] Downloaded 97435 bytes...
 [5%] Downloaded 113819 bytes...
 [5%] Downloaded 130203 bytes...
 [6%] Downloaded 146587 bytes...
 [7%] Downloaded 162971 bytes...
 [8%] Downloaded 179355 bytes...
 [8%] Downloaded 195739 bytes...
 [9%] Downloaded 212123 bytes...
 [10%] Downloaded 228507 bytes...
 [11%] Downloaded 244891 bytes...
 [11%] Downloaded 261275 bytes...
 [12%] Downloaded 277659 bytes...
 [13%] Downloaded 294043 bytes...
 [14%] Downloaded 310427 bytes...
 [14%] Downloaded 326811 bytes...
 [15%] Downloaded 343195 bytes...
 [16%] Downloaded 359579 bytes...
 [17%] Downloaded 375963 bytes...
 [17%] Downloaded 392347 bytes...
 [18%] Downloaded 401115 bytes...
 [19%] Downloaded 417499 bytes...
 [19%] Downloaded 433883 bytes...
 [20%] Downloaded 450267 bytes...
 [21%] Downloaded 466651 bytes...
 [22%] Downloaded 483035 bytes...
 [22%] Downloaded 499419 bytes...
 [23%] Downloaded 515803 bytes...
 [24%] Downloaded 532187 bytes...
 [25%] Downloaded 548571 bytes...
 [25%] Downloaded 564955 bytes...
 [26%] Downloaded 581339 bytes...
 [27%] Downloaded 597723 bytes...
 [27%] Downloaded 614107 bytes...
 [28%] Downloaded 630491 bytes...
 [29%] Downloaded 646875 bytes...
 [30%] Downloaded 663259 bytes...
 [30%] Downloaded 679643 bytes...
 [31%] Downloaded 696027 bytes...
 [32%] Downloaded 712411 bytes...
 [33%] Downloaded 728795 bytes...
 [33%] Downloaded 745179 bytes...
 [34%] Downloaded 761563 bytes...
 [35%] Downloaded 777947 bytes...
 [36%] Downloaded 794331 bytes...
 [36%] Downloaded 810715 bytes...
 [37%] Downloaded 827099 bytes...
 [38%] Downloaded 843483 bytes...
 [39%] Downloaded 859867 bytes...
 [39%] Downloaded 876251 bytes...
 [40%] Downloaded 892635 bytes...
 [41%] Downloaded 909019 bytes...
 [42%] Downloaded 925403 bytes...
 [42%] Downloaded 941787 bytes...
 [43%] Downloaded 958171 bytes...
 [44%] Downloaded 974555 bytes...
 [45%] Downloaded 990939 bytes...
 [45%] Downloaded 1007323 bytes...
 [46%] Downloaded 1023707 bytes...
 [47%] Downloaded 1040091 bytes...
 [48%] Downloaded 1056475 bytes...
 [48%] Downloaded 1072859 bytes...
 [49%] Downloaded 1089243 bytes...
 [50%] Downloaded 1105627 bytes...
 [51%] Downloaded 1122011 bytes...
 [51%] Downloaded 1138395 bytes...
 [52%] Downloaded 1154779 bytes...
 [53%] Downloaded 1171163 bytes...
 [54%] Downloaded 1187547 bytes...
 [54%] Downloaded 1203931 bytes...
 [55%] Downloaded 1220315 bytes...
 [56%] Downloaded 1236699 bytes...
 [57%] Downloaded 1253083 bytes...
 [57%] Downloaded 1269467 bytes...
 [58%] Downloaded 1285851 bytes...
 [59%] Downloaded 1302235 bytes...
 [60%] Downloaded 1318619 bytes...
 [60%] Downloaded 1335003 bytes...
 [61%] Downloaded 1351387 bytes...
 [62%] Downloaded 1367771 bytes...
 [63%] Downloaded 1384155 bytes...
 [63%] Downloaded 1400539 bytes...
 [64%] Downloaded 1416923 bytes...
 [65%] Downloaded 1433307 bytes...
 [66%] Downloaded 1449691 bytes...
 [66%] Downloaded 1466075 bytes...
 [67%] Downloaded 1482459 bytes...
 [68%] Downloaded 1498843 bytes...
 [69%] Downloaded 1515227 bytes...
 [69%] Downloaded 1531611 bytes...
 [70%] Downloaded 1547995 bytes...
 [71%] Downloaded 1564379 bytes...
 [72%] Downloaded 1580763 bytes...
 [72%] Downloaded 1597147 bytes...
 [73%] Downloaded 1613531 bytes...
 [74%] Downloaded 1629915 bytes...
 [75%] Downloaded 1646299 bytes...
 [75%] Downloaded 1662683 bytes...
 [76%] Downloaded 1679067 bytes...
 [77%] Downloaded 1695451 bytes...
 [78%] Downloaded 1711835 bytes...
 [78%] Downloaded 1728219 bytes...
 [79%] Downloaded 1744603 bytes...
 [80%] Downloaded 1760987 bytes...
 [81%] Downloaded 1777371 bytes...
 [81%] Downloaded 1793755 bytes...
 [82%] Downloaded 1810139 bytes...
 [83%] Downloaded 1826523 bytes...
 [84%] Downloaded 1842907 bytes...
 [84%] Downloaded 1859291 bytes...
 [85%] Downloaded 1875675 bytes...
 [86%] Downloaded 1892059 bytes...
 [86%] Downloaded 1908443 bytes...
 [87%] Downloaded 1924827 bytes...
 [88%] Downloaded 1941211 bytes...
 [89%] Downloaded 1957595 bytes...
 [89%] Downloaded 1973979 bytes...
 [90%] Downloaded 1990363 bytes...
 [91%] Downloaded 2006747 bytes...
 [92%] Downloaded 2023131 bytes...
 [92%] Downloaded 2039515 bytes...
 [93%] Downloaded 2055899 bytes...
 [94%] Downloaded 2072283 bytes...
 [95%] Downloaded 2088667 bytes...
 [95%] Downloaded 2105051 bytes...
 [96%] Downloaded 2121435 bytes...
 [97%] Downloaded 2137819 bytes...
 [98%] Downloaded 2154203 bytes...
 [98%] Downloaded 2170587 bytes...
 [99%] Downloaded 2186971 bytes...
 [100%] Downloaded 2193882 bytes...
flights

DT = data.table( ID = c(“b”,“b”,“b”,“a”,“a”,“c”), a = 1:6, b = 7:12, c = 13:18 ) DT

class(DT$ID)

getOption(“datatable.print.nrows”)

ans <- flights[origin == “JFK” & month == 6L] head(ans)

ans <- flights[1:2] ans

ans <- flights[origin == “JFK” & month == 6L][1:2] head(ans)

ans <- flights[order(origin, -dest)] head(ans)

ans <- flights[, arr_delay] head(ans)

ans <- flights[, arr_delay, dest] head(ans)

ans <- flights[, list(arr_delay)] head(ans)

ans <- flights[, .(arr_delay)] head(ans)

ans <- flights[, .(arr_delay, dep_delay)] head(ans)

ans <- flights[, .(delay_arr = arr_delay, delay_dep = dep_delay)] head(ans)

ans <- flights[, sum( (arr_delay + dep_delay) < 0 )] ans

ans <- flights[origin == “JFK” & month == 6L, .(m_arr = mean(arr_delay), m_dep = mean(dep_delay))] ans

ans <- flights[origin == “JFK” & month == 6L, length(dest)] ans

ans <- flights[origin == “JFK” & month == 6L, .N] ans

ans <- flights[, c(“arr_delay”, “dep_delay”)] head(ans)

select_cols = c(“arr_delay”, “dep_delay”) flights[ , ..select_cols]

flights[ , select_cols, with = FALSE]

ans <- flights[, !c(“arr_delay”, “dep_delay”)]

ans <- flights[, -c(“arr_delay”, “dep_delay”)]

ans <- flights[, year:day]

ans <- flights[, day:year]

ans <- flights[, -(year:day)] ans <- flights[, !(year:day)]

ans <- flights[, .(.N), by = .(origin)] ans

ans <- flights[, .(.N), by = “origin”] ans

ans <- flights[, .N, by = origin] ans

ans <- flights[carrier == “AA”, .N, by = origin] ans

ans <- flights[carrier == “AA”, .N, by = .(origin, dest)] head(ans)

ans <- flights[carrier == “AA”, .N, by = c(“origin”, “dest”)] ans

ans <- flights[carrier == “AA”, .(mean(arr_delay), mean(dep_delay)), by = .(origin, dest, month)] ans

ans <- flights[carrier == “AA”, .(mean(arr_delay), mean(dep_delay)), keyby = .(origin, dest, month)] ans

ans <- flights[carrier == “AA”, .N, by = .(origin, dest)] ans

ans <- flights[carrier == “AA”, .N, by = .(origin, dest)][order(origin, -dest)] head(ans, 10)

ans <- flights[, .N, .(dep_delay>0, arr_delay>0)] ans

flights[, .N, .(dep_delayed = dep_delay>0, arr_delayed = arr_delay>0)]

cheat sheet

https://www.datacamp.com/community/tutorials/data-table-cheat-sheet

https://s3.amazonaws.com/assets.datacamp.com/blog_assets/datatable_Cheat_Sheet_R.pdf

library(data.table)

http://r-datatable.com

https://github.com/Rdatatable/data.table/wiki

set.seed(45L)
DT <- data.table(V1 = c(1L,2L),
                 V2 = LETTERS[1:3],
                 V3 = round(rnorm(4),4),
                 V4 = 1:12)
DT
typeof(DT)
class(DT)

Subsetting Rows Using i

DT[3:5,]
DT[3:5]
DT[V2=="A"]
DT[V2 %in% c("A","C")]

Manipulating on Columns in j

sonuç vektör olarak alınacaksa sadece sütun ismi yazılıyor

DT[,V2]

sonuç data.frame olarak alınacaksa sütun ismi önünde . yazılıyor

DT[,.(V2)]
DT[,.(V2,V3)]

tek sütun üzerinden özet alma

DT[,sum(V1)]

birden fazla sütun üzerinden özet alma

DT[,.(sum(V1),sd(V3))]
DT[,.(Aggregate = sum(V1),
      Sd.V3 = sd(V3))]
DT[,.(V1,Sd.V3=sd(V3))]
DT[,.(print(V2),
      plot(V3),
      NULL)]

Doing j by Group

DT[,.(V4.Sum = sum(V4)),by = V1]
DT[,.(V4.Sum = sum(V4)),
   by = .(V1,V2)]
DT[,.(V4.Sum = sum(V4)),
   by = sign(V1-1)]
DT[,.(V4.Sum = sum(V4)),
   by = .(V1.01 = sign(V1 - 1))]
DT[1:5,.(V4.Sum = sum(V4)), 
   by = V1]
DT[,.N,by = V1]

Adding/Updating Columns By Reference in j Using :=

DT[,V1:=round(exp(V1),2)]
DT
DT[,V5:=round(exp(V1),2)]
DT
DT[,c("V1","V2"):=list(round(exp(V1),2),
                       LETTERS[4:6])]
DT
DT[,':='(V1=round(exp(V1),2),
         V2=LETTERS[4:6])][]
DT[,V1:=NULL]
DT
DT[,c("V1","V2"):=NULL][]
Cols.chosen = c("A", "B")
DT[,Cols.Chosen:=NULL]
Cols.chosen = c("A", "B")
DT[,(Cols.Chosen):=NULL]

Indexing And Keys

setkey(DT,V2)
DT["A"]
DT[c("A","C")]
DT["A",mult="first"]
DT["A",mult="last"]
DT[c("A","D")]
DT[c("A","D"),nomatch=0]
DT[c("A","C"),sum(V4)]
DT[c("A","C"),
   sum(V4),
   by=.EACHI]
setkey(DT,V1,V2)
DT[.(2,"C")]
DT[.(2,c("A","C"))]

Advanced Data Table Operations

.SD & .SDcols

Chaining

set()-Family

set()

setnames()


DataCamp Data Analysis in R, the data.table Way

https://www.datacamp.com/courses/data-table-data-manipulation-r-tutorial

LS0tCnRpdGxlOiAiZGF0YS50YWJsZSBwYWNrYWdlIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKIyBSZGF0YXRhYmxlCgpodHRwczovL2dpdGh1Yi5jb20vUmRhdGF0YWJsZQoKYGBge3J9CmxpYnJhcnkoZGF0YS50YWJsZSkKYGBgCgoKIyMgSW50cm9kdWN0aW9uIHRvIGRhdGEudGFibGUKCgpodHRwczovL2Nsb3VkLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2RhdGEudGFibGUvdmlnbmV0dGVzL2RhdGF0YWJsZS1pbnRyby5odG1sCgoKYGBge3J9CmlucHV0IDwtIGlmIChmaWxlLmV4aXN0cygiZmxpZ2h0czE0LmNzdiIpKSB7CiAgICJmbGlnaHRzMTQuY3N2Igp9IGVsc2UgewogICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vUmRhdGF0YWJsZS9kYXRhLnRhYmxlL21hc3Rlci92aWduZXR0ZXMvZmxpZ2h0czE0LmNzdiIKfQpmbGlnaHRzIDwtIGZyZWFkKGlucHV0KQpmbGlnaHRzCmBgYAoKCmBgYHtyfQo/ZnJlYWQKYGBgCgoKRFQgPSBkYXRhLnRhYmxlKAogIElEID0gYygiYiIsImIiLCJiIiwiYSIsImEiLCJjIiksCiAgYSA9IDE6NiwKICBiID0gNzoxMiwKICBjID0gMTM6MTgKKQpEVAoKCmNsYXNzKERUJElEKQoKCmdldE9wdGlvbigiZGF0YXRhYmxlLnByaW50Lm5yb3dzIikKCgoKYW5zIDwtIGZsaWdodHNbb3JpZ2luID09ICJKRksiICYgbW9udGggPT0gNkxdCmhlYWQoYW5zKQoKCmFucyA8LSBmbGlnaHRzWzE6Ml0KYW5zCgphbnMgPC0gZmxpZ2h0c1tvcmlnaW4gPT0gIkpGSyIgJiBtb250aCA9PSA2TF1bMToyXQpoZWFkKGFucykKCgphbnMgPC0gZmxpZ2h0c1tvcmRlcihvcmlnaW4sIC1kZXN0KV0KaGVhZChhbnMpCgoKYW5zIDwtIGZsaWdodHNbLCBhcnJfZGVsYXldCmhlYWQoYW5zKQoKCgphbnMgPC0gZmxpZ2h0c1ssIGFycl9kZWxheSwgZGVzdF0KaGVhZChhbnMpCgphbnMgPC0gZmxpZ2h0c1ssIGxpc3QoYXJyX2RlbGF5KV0KaGVhZChhbnMpCgoKYW5zIDwtIGZsaWdodHNbLCAuKGFycl9kZWxheSldCmhlYWQoYW5zKQoKYW5zIDwtIGZsaWdodHNbLCAuKGFycl9kZWxheSwgZGVwX2RlbGF5KV0KaGVhZChhbnMpCgoKYW5zIDwtIGZsaWdodHNbLCAuKGRlbGF5X2FyciA9IGFycl9kZWxheSwgZGVsYXlfZGVwID0gZGVwX2RlbGF5KV0KaGVhZChhbnMpCgoKYW5zIDwtIGZsaWdodHNbLCBzdW0oIChhcnJfZGVsYXkgKyBkZXBfZGVsYXkpIDwgMCApXQphbnMKCmFucyA8LSBmbGlnaHRzW29yaWdpbiA9PSAiSkZLIiAmIG1vbnRoID09IDZMLAogICAgICAgICAgICAgICAuKG1fYXJyID0gbWVhbihhcnJfZGVsYXkpLCBtX2RlcCA9IG1lYW4oZGVwX2RlbGF5KSldCmFucwoKYW5zIDwtIGZsaWdodHNbb3JpZ2luID09ICJKRksiICYgbW9udGggPT0gNkwsIGxlbmd0aChkZXN0KV0KYW5zCgphbnMgPC0gZmxpZ2h0c1tvcmlnaW4gPT0gIkpGSyIgJiBtb250aCA9PSA2TCwgLk5dCmFucwoKYW5zIDwtIGZsaWdodHNbLCBjKCJhcnJfZGVsYXkiLCAiZGVwX2RlbGF5IildCmhlYWQoYW5zKQoKc2VsZWN0X2NvbHMgPSBjKCJhcnJfZGVsYXkiLCAiZGVwX2RlbGF5IikKZmxpZ2h0c1sgLCAuLnNlbGVjdF9jb2xzXQoKCmZsaWdodHNbICwgc2VsZWN0X2NvbHMsIHdpdGggPSBGQUxTRV0KCmFucyA8LSBmbGlnaHRzWywgIWMoImFycl9kZWxheSIsICJkZXBfZGVsYXkiKV0KCmFucyA8LSBmbGlnaHRzWywgLWMoImFycl9kZWxheSIsICJkZXBfZGVsYXkiKV0KCmFucyA8LSBmbGlnaHRzWywgeWVhcjpkYXldCgphbnMgPC0gZmxpZ2h0c1ssIGRheTp5ZWFyXQoKYW5zIDwtIGZsaWdodHNbLCAtKHllYXI6ZGF5KV0KYW5zIDwtIGZsaWdodHNbLCAhKHllYXI6ZGF5KV0KCgphbnMgPC0gZmxpZ2h0c1ssIC4oLk4pLCBieSA9IC4ob3JpZ2luKV0KYW5zCgoKYW5zIDwtIGZsaWdodHNbLCAuKC5OKSwgYnkgPSAib3JpZ2luIl0KYW5zCgphbnMgPC0gZmxpZ2h0c1ssIC5OLCBieSA9IG9yaWdpbl0KYW5zCgoKYW5zIDwtIGZsaWdodHNbY2FycmllciA9PSAiQUEiLCAuTiwgYnkgPSBvcmlnaW5dCmFucwoKCmFucyA8LSBmbGlnaHRzW2NhcnJpZXIgPT0gIkFBIiwgLk4sIGJ5ID0gLihvcmlnaW4sIGRlc3QpXQpoZWFkKGFucykKCgphbnMgPC0gZmxpZ2h0c1tjYXJyaWVyID09ICJBQSIsIC5OLCBieSA9IGMoIm9yaWdpbiIsICJkZXN0IildCmFucwoKCmFucyA8LSBmbGlnaHRzW2NhcnJpZXIgPT0gIkFBIiwKICAgICAgICAuKG1lYW4oYXJyX2RlbGF5KSwgbWVhbihkZXBfZGVsYXkpKSwKICAgICAgICBieSA9IC4ob3JpZ2luLCBkZXN0LCBtb250aCldCmFucwoKCmFucyA8LSBmbGlnaHRzW2NhcnJpZXIgPT0gIkFBIiwKICAgICAgICAuKG1lYW4oYXJyX2RlbGF5KSwgbWVhbihkZXBfZGVsYXkpKSwKICAgICAgICBrZXlieSA9IC4ob3JpZ2luLCBkZXN0LCBtb250aCldCmFucwoKCmFucyA8LSBmbGlnaHRzW2NhcnJpZXIgPT0gIkFBIiwgLk4sIGJ5ID0gLihvcmlnaW4sIGRlc3QpXQphbnMKCgphbnMgPC0gZmxpZ2h0c1tjYXJyaWVyID09ICJBQSIsIC5OLCBieSA9IC4ob3JpZ2luLCBkZXN0KV1bb3JkZXIob3JpZ2luLCAtZGVzdCldCmhlYWQoYW5zLCAxMCkKCgphbnMgPC0gZmxpZ2h0c1ssIC5OLCAuKGRlcF9kZWxheT4wLCBhcnJfZGVsYXk+MCldCmFucwoKZmxpZ2h0c1ssIC5OLCAuKGRlcF9kZWxheWVkID0gZGVwX2RlbGF5PjAsIGFycl9kZWxheWVkID0gYXJyX2RlbGF5PjApXQoKCgoKIwoKCgoKCiMgY2hlYXQgc2hlZXQKCgoKaHR0cHM6Ly93d3cuZGF0YWNhbXAuY29tL2NvbW11bml0eS90dXRvcmlhbHMvZGF0YS10YWJsZS1jaGVhdC1zaGVldAoKaHR0cHM6Ly9zMy5hbWF6b25hd3MuY29tL2Fzc2V0cy5kYXRhY2FtcC5jb20vYmxvZ19hc3NldHMvZGF0YXRhYmxlX0NoZWF0X1NoZWV0X1IucGRmCgoKYGBge3J9CmxpYnJhcnkoZGF0YS50YWJsZSkKYGBgCmh0dHA6Ly9yLWRhdGF0YWJsZS5jb20KCmh0dHBzOi8vZ2l0aHViLmNvbS9SZGF0YXRhYmxlL2RhdGEudGFibGUvd2lraQoKWyFbXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vd2lraS9SZGF0YXRhYmxlL2RhdGEudGFibGUvcGljdHVyZXMvc3ludGF4MS5qcGcpXShodHRwczovL2dpdGh1Yi5jb20vUmRhdGF0YWJsZS9kYXRhLnRhYmxlL3dpa2kvdGFsa3MvQXJ1blNyaW5pdmFzYW5TYXRSZGF5c0J1ZGFwZXN0MjAxNi5wZGYpCgoKYGBge3J9CnNldC5zZWVkKDQ1TCkKRFQgPC0gZGF0YS50YWJsZShWMSA9IGMoMUwsMkwpLAogICAgICAgICAgICAgICAgIFYyID0gTEVUVEVSU1sxOjNdLAogICAgICAgICAgICAgICAgIFYzID0gcm91bmQocm5vcm0oNCksNCksCiAgICAgICAgICAgICAgICAgVjQgPSAxOjEyKQpgYGAKCgpgYGB7cn0KRFQKYGBgCgoKCmBgYHtyfQp0eXBlb2YoRFQpCmBgYAoKYGBge3J9CmNsYXNzKERUKQpgYGAKCgoKCgojIyBTdWJzZXR0aW5nIFJvd3MgVXNpbmcgaQoKYGBge3J9CkRUWzM6NSxdCmBgYAoKCgpgYGB7cn0KRFRbMzo1XQpgYGAKCmBgYHtyfQpEVFtWMj09IkEiXQpgYGAKCgpgYGB7cn0KRFRbVjIgJWluJSBjKCJBIiwiQyIpXQpgYGAKCgojIyBNYW5pcHVsYXRpbmcgb24gQ29sdW1ucyBpbiBqCgpzb251w6cgdmVrdMO2ciBvbGFyYWsgYWzEsW5hY2Frc2Egc2FkZWNlIHPDvHR1biBpc21pIHlhesSxbMSxeW9yCgpgYGB7cn0KRFRbLFYyXQpgYGAKCnNvbnXDpyBkYXRhLmZyYW1lIG9sYXJhayBhbMSxbmFjYWtzYSBzw7x0dW4gaXNtaSDDtm7DvG5kZSBgLmAgeWF6xLFsxLF5b3IKCmBgYHtyfQpEVFssLihWMildCmBgYAoKCgpgYGB7cn0KRFRbLC4oVjIsVjMpXQpgYGAKCnRlayBzw7x0dW4gw7x6ZXJpbmRlbiDDtnpldCBhbG1hCgpgYGB7cn0KRFRbLHN1bShWMSldCmBgYAoKYmlyZGVuIGZhemxhIHPDvHR1biDDvHplcmluZGVuIMO2emV0IGFsbWEKCmBgYHtyfQpEVFssLihzdW0oVjEpLHNkKFYzKSldCmBgYAoKYGBge3J9CkRUWywuKEFnZ3JlZ2F0ZSA9IHN1bShWMSksCiAgICAgIFNkLlYzID0gc2QoVjMpKV0KYGBgCgpgYGB7cn0KRFRbLC4oVjEsU2QuVjM9c2QoVjMpKV0KYGBgCgpgYGB7cn0KRFRbLC4ocHJpbnQoVjIpLAogICAgICBwbG90KFYzKSwKICAgICAgTlVMTCldCmBgYAoKCiMjIERvaW5nIGogYnkgR3JvdXAKCmBgYHtyfQpEVFssLihWNC5TdW0gPSBzdW0oVjQpKSxieSA9IFYxXQpgYGAKCgpgYGB7cn0KRFRbLC4oVjQuU3VtID0gc3VtKFY0KSksCiAgIGJ5ID0gLihWMSxWMildCmBgYAoKCgoKYGBge3J9CkRUWywuKFY0LlN1bSA9IHN1bShWNCkpLAogICBieSA9IHNpZ24oVjEtMSldCmBgYAoKCgpgYGB7cn0KRFRbLC4oVjQuU3VtID0gc3VtKFY0KSksCiAgIGJ5ID0gLihWMS4wMSA9IHNpZ24oVjEgLSAxKSldCmBgYAoKCmBgYHtyfQpEVFsxOjUsLihWNC5TdW0gPSBzdW0oVjQpKSwgCiAgIGJ5ID0gVjFdCmBgYAoKYGBge3J9CkRUWywuTixieSA9IFYxXQpgYGAKCiMjIEFkZGluZy9VcGRhdGluZyBDb2x1bW5zIEJ5IFJlZmVyZW5jZSBpbiBqIFVzaW5nIDo9CgpgYGB7cn0KRFRbLFYxOj1yb3VuZChleHAoVjEpLDIpXQpEVApgYGAKCgpgYGB7cn0KRFRbLFY1Oj1yb3VuZChleHAoVjEpLDIpXQpEVApgYGAKCgpgYGB7cn0KRFRbLGMoIlYxIiwiVjIiKTo9bGlzdChyb3VuZChleHAoVjEpLDIpLAogICAgICAgICAgICAgICAgICAgICAgIExFVFRFUlNbNDo2XSldCkRUCmBgYAoKCgpgYGB7cn0KRFRbLCc6PScoVjE9cm91bmQoZXhwKFYxKSwyKSwKICAgICAgICAgVjI9TEVUVEVSU1s0OjZdKV1bXQpgYGAKCgpgYGB7cn0KRFRbLFYxOj1OVUxMXQpEVApgYGAKCmBgYHtyfQpEVFssYygiVjEiLCJWMiIpOj1OVUxMXVtdCmBgYAoKCmBgYHtyfQpDb2xzLmNob3NlbiA9IGMoIkEiLCAiQiIpCkRUWyxDb2xzLkNob3Nlbjo9TlVMTF0KYGBgCgpgYGB7cn0KQ29scy5jaG9zZW4gPSBjKCJBIiwgIkIiKQpEVFssKENvbHMuQ2hvc2VuKTo9TlVMTF0KYGBgCgoKIyMgSW5kZXhpbmcgQW5kIEtleXMKCgpgYGB7cn0Kc2V0a2V5KERULFYyKQpgYGAKCgpgYGB7cn0KRFRbIkEiXQpgYGAKCgpgYGB7cn0KRFRbYygiQSIsIkMiKV0KYGBgCgoKCmBgYHtyfQpEVFsiQSIsbXVsdD0iZmlyc3QiXQpgYGAKCgpgYGB7cn0KRFRbIkEiLG11bHQ9Imxhc3QiXQpgYGAKCgpgYGB7cn0KRFRbYygiQSIsIkQiKV0KYGBgCgoKYGBge3J9CkRUW2MoIkEiLCJEIiksbm9tYXRjaD0wXQpgYGAKCgpgYGB7cn0KRFRbYygiQSIsIkMiKSxzdW0oVjQpXQpgYGAKCgpgYGB7cn0KRFRbYygiQSIsIkMiKSwKICAgc3VtKFY0KSwKICAgYnk9LkVBQ0hJXQpgYGAKCgpgYGB7cn0Kc2V0a2V5KERULFYxLFYyKQpgYGAKCgpgYGB7cn0KRFRbLigyLCJDIildCmBgYAoKCmBgYHtyfQpEVFsuKDIsYygiQSIsIkMiKSldCmBgYAoKCiMjIEFkdmFuY2VkIERhdGEgVGFibGUgT3BlcmF0aW9ucwoKCgojIyAuU0QgJiAuU0Rjb2xzCgoKIyMgQ2hhaW5pbmcKCgojIyBzZXQoKS1GYW1pbHkKCiMjIyBzZXQoKQoKIyMjIHNldG5hbWVzKCkKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgotLS0KCiMgRGF0YUNhbXAgRGF0YSBBbmFseXNpcyBpbiBSLCB0aGUgZGF0YS50YWJsZSBXYXkKCmh0dHBzOi8vd3d3LmRhdGFjYW1wLmNvbS9jb3Vyc2VzL2RhdGEtdGFibGUtZGF0YS1tYW5pcHVsYXRpb24tci10dXRvcmlhbAoK