1 Objective

Membaca data dari file berupa JSON dengan R.

2 R and Data

Kemampuan R dalam mengolah data tentunya sudah tidak diragukan lagi. Banyak sekali source data yang dapat diintegrasikan dengan R, baik berupa file data maupun database.

R juga bisa membaca file berupa pdf dan gambar sebagai input data, tentunya dengan memanfaatkan berbagai package yang tersedia. Salah satu format data yang mampu dibaca oleh R yang akan dibahas pada tulisan ini adalah file JSON.

3 JSON

JSON adalah singkatan dari JavaScript Object Notation. Ya, JSON adalah sebuah format penyimpanan data dengan berdasarkan JavaScript. File JSON mirip seperti data pada text file biasa, hanya saja dengan berbagai aturan dan format yang sesuai dengan sintaksis pada JavaScript.

  • Data ditulis berpasangan nama dan nilainya (data aja berpasangan)
  • Data dipisahkan oleh tanda koma
  • Tanda kurung kurawal (curly braces) berisi sebuah object, {objects} \(\Rightarrow\) nilai dari data
  • Tanda kurung siku (square brackets) berisi arrays, [arrays] \(\Rightarrow\) list

Pada JSON, nilai yang ada harus berupa salah satu dari tipe data berikut.

  • String
{"name": "John"}
  • Numeric
{"age": 38}
  • JSON Object
{ 
  "employee": {"name": "John", "age": 30, "city": "New York"}
}
  • Array
{ 
  "employees": [ "John", "Anna", "Peter" ] 
}
  • Boolean (true/false)
{"male": true}
  • Null
{"midname": null}

Bagaimana dengan data berupa tanggal? JSON menyimpannya sebagai teks, kecuali untuk tanggal yang semuanya numerik. Misalnya 20190711 dan tanpa tanda kutip (") akan dibaca sebagai numerik.

4 Read JSON Data

Kita dapat dengan mudah membaca/import data dari file JSON dengan menggunakan package jsonlite.

library(jsonlite)

4.1 Format 1

json1 <- '{ 
  "ID": [1,2,3,4,5],
  "Name": ["Rick","Dan","Michelle","Ryan","Gary"],
  "Salary": [623.3,515.2,611,729,843.25],
  "StartDate": ["1/1/2012","9/23/2013","11/15/2014","5/11/2014","3/27/2015"],
  "Dept": ["IT","Operations","IT","HR","Finance"]
}'

x1 <- fromJSON(json1)
str(x1)
List of 5
 $ ID       : int [1:5] 1 2 3 4 5
 $ Name     : chr [1:5] "Rick" "Dan" "Michelle" "Ryan" ...
 $ Salary   : num [1:5] 623 515 611 729 843
 $ StartDate: chr [1:5] "1/1/2012" "9/23/2013" "11/15/2014" "5/11/2014" ...
 $ Dept     : chr [1:5] "IT" "Operations" "IT" "HR" ...

Jadikan data.frame!

x1 <- as.data.frame(x1, stringsAsFactors = FALSE)
str(x1)
'data.frame':   5 obs. of  5 variables:
 $ ID       : int  1 2 3 4 5
 $ Name     : chr  "Rick" "Dan" "Michelle" "Ryan" ...
 $ Salary   : num  623 515 611 729 843
 $ StartDate: chr  "1/1/2012" "9/23/2013" "11/15/2014" "5/11/2014" ...
 $ Dept     : chr  "IT" "Operations" "IT" "HR" ...

4.2 Format 2

json2 <- '[
  [1, "Rick", 623.3, "1/1/2012", "IT"],
  [2, "Dan", 515.2, "9/23/2013", "Operations"],
  [3, "Michelle", 611, "11/15/2014", "IT"],
  [4, "Ryan", 729, "5/11/2014", "HR"],
  [5, "Gary", 843.25, "3/27/2015", "Finance"]
]'
x2 <- fromJSON(json2)
str(x2)
 chr [1:5, 1:5] "1" "2" "3" "4" "5" "Rick" "Dan" "Michelle" "Ryan" "Gary" ...
x2 <- as.data.frame(x2, stringsAsFactors = F)
str(x2)
'data.frame':   5 obs. of  5 variables:
 $ V1: chr  "1" "2" "3" "4" ...
 $ V2: chr  "Rick" "Dan" "Michelle" "Ryan" ...
 $ V3: chr  "623.3" "515.2" "611" "729" ...
 $ V4: chr  "1/1/2012" "9/23/2013" "11/15/2014" "5/11/2014" ...
 $ V5: chr  "IT" "Operations" "IT" "HR" ...

4.3 Format 3

json3 <- '[
  {
  "ID":1, "Name":"Rick", "Salary":623.3, "StartDate":"1/1/2012", "Dept":"IT"
  },
  {
  "ID":2, "Name":"Dan", "Salary":515.2, "StartDate":"9/23/2013", "Dept":"Operations"
  },
  {
  "ID":3, "Name":"Michelle", "Salary":611, "StartDate":"11/15/2014", "Dept":"IT"
  },
  {
  "ID":4, "Name":"Ryan", "Salary":729, "StartDate":"5/11/2014", "Dept":"HR"
  },
  {
  "ID":5, "Name":"Gary", "Salary":843.25, "StartDate":"3/27/2015", "Dept":"Finance"
  }
]'
x3 <- fromJSON(json3)
str(x3)
'data.frame':   5 obs. of  5 variables:
 $ ID       : int  1 2 3 4 5
 $ Name     : chr  "Rick" "Dan" "Michelle" "Ryan" ...
 $ Salary   : num  623 515 611 729 843
 $ StartDate: chr  "1/1/2012" "9/23/2013" "11/15/2014" "5/11/2014" ...
 $ Dept     : chr  "IT" "Operations" "IT" "HR" ...

5 Read JSON From Website

# Read JSON data from website: infopemilu.kpu.go.id
dps2019 <- fromJSON("https://pemilu2019.kpu.go.id/static/json/hhcw/ppwp.json")
# View(dps2019)
head(dps2019$table)
$`1`
$`1`$`21`
[1] 399066

$`1`$`22`
[1] 2359989

$`1`$persen
[1] 98.64242


$`-99`
$`-99`$`21`
[1] 577637

$`-99`$`22`
[1] 223575

$`-99`$persen
[1] 98.64652


$`6728`
$`6728`$`21`
[1] 3917069

$`6728`$`22`
[1] 3577472

$`6728`$persen
[1] 99.86643


$`12920`
$`12920`$`21`
[1] 407638

$`12920`$`22`
[1] 2485265

$`12920`$persen
[1] 100


$`14086`
$`14086`$`21`
[1] 1246888

$`14086`$`22`
[1] 1973298

$`14086`$persen
[1] 100


$`15885`
$`15885`$`21`
[1] 858738

$`15885`$`22`
[1] 1200255

$`15885`$persen
[1] 100
dps2019 <- do.call(rbind.data.frame, dps2019$table)
str(dps2019)
'data.frame':   35 obs. of  3 variables:
 $ X21   : int  399066 577637 3917069 407638 1246888 858738 1915685 582845 2845798 495500 ...
 $ X22   : int  2359989 223575 3577472 2485265 1973298 1200255 2830633 585598 1951645 288097 ...
 $ persen: num  98.6 98.6 99.9 100 100 ...
head(dps2019)

6 Export Dataframe As JSON

write_json(dps2019, "dps2019.json", pretty = TRUE, dataframes = "rows")

7 Read Local JSON File

# Read JSON data from local .json file
dps2018 <- fromJSON('dps2018.json', simplifyDataFrame = TRUE)
str(dps2018)
'data.frame':   10 obs. of  20 variables:
 $ namaPropinsi             : chr  "JAWA BARAT" "JAWA BARAT" "JAWA BARAT" "JAWA BARAT" ...
 $ namaKabKota              : chr  "BOGOR" "BOGOR" "BOGOR" "BOGOR" ...
 $ namaKecamatan            : chr  "DRAMAGA" "DRAMAGA" "DRAMAGA" "DRAMAGA" ...
 $ namaKelurahan            : chr  "BABAKAN" "CIHERANG" "CIKARAWANG" "DRAMAGA" ...
 $ jmlTps                   : int  14 26 15 23 14 22 11 12 12 12
 $ jmlPemilihLaki           : int  2546 5333 3350 4522 3371 4972 2570 3293 3070 2933
 $ jmlPemilihPerempuan      : int  2582 5195 3171 4328 3202 4590 2514 3135 2826 2745
 $ jmlPemilihKosong         : int  0 0 0 0 0 0 0 0 0 0
 $ totalPemilih             : int  5128 10528 6521 8850 6573 9562 5084 6428 5896 5678
 $ jmlPemilihPemulaLaki     : int  5 16 105 38 7 9 6 18 8 3
 $ jmlPemilihPemulaPerempuan: int  1 11 90 53 10 5 6 22 13 4
 $ totalPemilihPemula       : int  6 27 195 91 17 14 12 40 21 7
 $ persenPemilihPemula      : num  0.12 0.26 2.99 1.03 0.26 0.15 0.24 0.62 0.36 0.12
 $ jmlDifabel1              : int  0 2 0 3 0 0 1 2 3 3
 $ jmlDifabel2              : int  0 0 0 0 0 0 0 1 4 0
 $ jmlDifabel3              : int  1 0 0 6 0 0 0 0 2 1
 $ jmlDifabel4              : int  0 0 0 1 0 0 1 0 5 0
 $ jmlDifabel5              : int  0 2 0 0 0 1 5 0 4 1
 $ totalDifabel             : int  1 4 0 10 0 1 7 3 18 5
 $ persenDifabel            : num  0.02 0.04 0 0.11 0 0.01 0.14 0.05 0.31 0.09
head(dps2018)

7.1 Explore

library(dplyr)
# How many 'Kelurahan' in Dramaga?
dps2018 %>% 
  distinct(namaKelurahan) %>% 
  count() 

# What 5 'Kelurahan' have the largest number of TPS?
dps2018 %>% 
  arrange(desc(jmlTps)) %>% 
  select(namaKelurahan, jmlTps) %>% 
  head(n = 5)
NA

8 Use ggplot2 package

library(ggplot2)

dps2018 %>% 
  ggplot(aes(x = reorder(namaKelurahan, jmlTps), y = jmlTps)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = jmlTps)) +
  labs(title = "Number of TPS by Kelurahan",
       y = "Number of TPS",
       x = "Kelurahan") +
  coord_flip() +
  theme_minimal()

LS0tDQp0aXRsZTogIkJhc2ljIERlYWxpbmcgV2l0aCBKU09OIERhdGEgVXNpbmcgUiINCmF1dGhvcjogIkJ5IEFlcCBIaWRheWF0dWxvaCINCmRhdGU6ICJMYXN0IFVwZGF0ZTogYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZCAlQiAlWScpYCINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogc3BhY2VsYWINCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQpib2R5eyAvKiBOb3JtYWwgICovDQogICAgICBmb250LXNpemU6IDE0cHg7DQogIH0NCnRkIHsgIC8qIFRhYmxlICAqLw0KICBmb250LXNpemU6IDEycHg7DQp9DQpoMS50aXRsZSB7DQogIGZvbnQtc2l6ZTogMzhweDsNCiAgY29sb3I6IGxpZ2h0Ymx1ZTsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQp9DQpoMSB7IC8qIEhlYWRlciAxICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgY29sb3I6IERhcmtCbHVlOw0KfQ0KaDIgeyAvKiBIZWFkZXIgMiAqLw0KICBmb250LXNpemU6IDIwcHg7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmgzIHsgLyogSGVhZGVyIDMgKi8NCiAgZm9udC1zaXplOiAxNnB4Ow0KIyAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCn0NCmg0IHsgLyogSGVhZGVyIDQgKi8NCiAgZm9udC1zaXplOiAxNHB4Ow0KICBjb2xvcjogRGFya0JsdWU7DQp9DQpjb2RlLnJ7IC8qIENvZGUgYmxvY2sgKi8NCiAgICBmb250LXNpemU6IDEycHg7DQp9DQpwcmUgeyAvKiBDb2RlIGJsb2NrIC0gZGV0ZXJtaW5lcyBjb2RlIHNwYWNpbmcgYmV0d2VlbiBsaW5lcyAqLw0KICAgIGZvbnQtc2l6ZTogMTJweDsNCn0NCjwvc3R5bGU+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQoja25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcud2lkdGggPSA2LjUsIHJlc3VsdHMgPSAnaG9sZCcsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLnNob3cgPSAnaG9sZCcsIG1lc3NhZ2UgPSBGQUxTRSkgDQpvcHRpb25zKHNjaXBlbiA9IDk5KQ0KYGBgDQoNCg0KPHAgYWxpZ249ImNlbnRlciI+DQo8aW1nIHNyYz0ianNvbl9sb2dvLnBuZyIgd2lkdGg9IjQwMHB4Ij4NCjwvcD4NCg0KDQoNCiMgT2JqZWN0aXZlDQoNCk1lbWJhY2EgZGF0YSBkYXJpIGZpbGUgYmVydXBhIEpTT04gZGVuZ2FuIFIuDQoNCiMgUiBhbmQgRGF0YQ0KDQpLZW1hbXB1YW4gUiBkYWxhbSBtZW5nb2xhaCBkYXRhIHRlbnR1bnlhIHN1ZGFoIHRpZGFrIGRpcmFndWthbiBsYWdpLiBCYW55YWsgc2VrYWxpIHNvdXJjZSBkYXRhIHlhbmcgZGFwYXQgZGlpbnRlZ3Jhc2lrYW4gZGVuZ2FuIFIsIGJhaWsgYmVydXBhIGZpbGUgZGF0YSBtYXVwdW4gZGF0YWJhc2UuDQoNCjxwIGFsaWduPSJjZW50ZXIiPg0KPGltZyBzcmM9ImRhdGFfUi5wbmciIHdpZHRoPSI0MDBweCI+DQo8cCBhbGlnbj0iY2VudGVyIj48bGFiZWw+UiBhbmQgRGF0YTwvbGFiZWw+PC9wPg0KPC9wPg0KDQpSIGp1Z2EgYmlzYSBtZW1iYWNhIGZpbGUgYmVydXBhIHBkZiBkYW4gZ2FtYmFyIHNlYmFnYWkgaW5wdXQgZGF0YSwgdGVudHVueWEgZGVuZ2FuIG1lbWFuZmFhdGthbiBiZXJiYWdhaSBwYWNrYWdlIHlhbmcgdGVyc2VkaWEuIFNhbGFoIHNhdHUgZm9ybWF0IGRhdGEgeWFuZyBtYW1wdSBkaWJhY2Egb2xlaCBSIHlhbmcgYWthbiBkaWJhaGFzIHBhZGEgdHVsaXNhbiBpbmkgYWRhbGFoIGZpbGUgKipKU09OKiouDQoNCiMgSlNPTg0KDQpKU09OIGFkYWxhaCBzaW5na2F0YW4gZGFyaSAqKkphdmFTY3JpcHQgT2JqZWN0IE5vdGF0aW9uKiouIFlhLCBKU09OIGFkYWxhaCBzZWJ1YWggZm9ybWF0IHBlbnlpbXBhbmFuIGRhdGEgZGVuZ2FuIGJlcmRhc2Fya2FuIEphdmFTY3JpcHQuIEZpbGUgSlNPTiBtaXJpcCBzZXBlcnRpIGRhdGEgcGFkYSB0ZXh0IGZpbGUgYmlhc2EsIGhhbnlhIHNhamEgZGVuZ2FuIGJlcmJhZ2FpIGF0dXJhbiBkYW4gZm9ybWF0IHlhbmcgc2VzdWFpIGRlbmdhbiBzaW50YWtzaXMgcGFkYSBKYXZhU2NyaXB0Lg0KDQoqIERhdGEgZGl0dWxpcyBiZXJwYXNhbmdhbiBuYW1hIGRhbiBuaWxhaW55YSAoZGF0YSBhamEgYmVycGFzYW5nYW4pDQoqIERhdGEgZGlwaXNhaGthbiBvbGVoIHRhbmRhIGtvbWENCiogVGFuZGEga3VydW5nIGt1cmF3YWwgKGN1cmx5IGJyYWNlcykgYmVyaXNpIHNlYnVhaCBvYmplY3QsIHtvYmplY3RzfSAkXFJpZ2h0YXJyb3ckIG5pbGFpIGRhcmkgZGF0YQ0KKiBUYW5kYSBrdXJ1bmcgc2lrdSAoc3F1YXJlIGJyYWNrZXRzKSBiZXJpc2kgYXJyYXlzLCBbYXJyYXlzXSAkXFJpZ2h0YXJyb3ckIGxpc3QNCg0KPHAgYWxpZ249ImNlbnRlciI+DQo8aW1nIHNyYz0ianNvbl9mb3JtLnBuZyIgd2lkdGg9IjQwMHB4Ij4NCjxwIGFsaWduPSJjZW50ZXIiPjxsYWJlbD5KU09OIG5hbWU6dmFsdWUgcGFpcnM8L2xhYmVsPjwvcD4NCjwvcD4NCg0KUGFkYSBKU09OLCBuaWxhaSB5YW5nIGFkYSBoYXJ1cyBiZXJ1cGEgc2FsYWggc2F0dSBkYXJpIHRpcGUgZGF0YSBiZXJpa3V0Lg0KDQoqIFN0cmluZyANCmBgYHtyIGVjaG89RkFMU0V9DQpjYXQoJ3sibmFtZSI6ICJKb2huIn0nKQ0KYGBgDQoqIE51bWVyaWMNCmBgYHtyIGVjaG89RkFMU0V9DQpjYXQoJ3siYWdlIjogMzh9JykNCmBgYA0KKiBKU09OIE9iamVjdCANCmBgYHtyIGVjaG89RkFMU0V9DQpjYXQoJ3sgDQogICJlbXBsb3llZSI6IHsibmFtZSI6ICJKb2huIiwgImFnZSI6IDMwLCAiY2l0eSI6ICJOZXcgWW9yayJ9DQp9JykNCmBgYA0KKiBBcnJheSANCmBgYHtyIGVjaG89RkFMU0V9DQpjYXQoJ3sgDQogICJlbXBsb3llZXMiOiBbICJKb2huIiwgIkFubmEiLCAiUGV0ZXIiIF0gDQp9JykNCmBgYA0KKiBCb29sZWFuICgqdHJ1ZSovKmZhbHNlKikgDQpgYGB7ciBlY2hvPUZBTFNFfQ0KY2F0KCd7Im1hbGUiOiB0cnVlfScpDQpgYGANCiogKk51bGwqIA0KYGBge3IgZWNobz1GQUxTRX0NCmNhdCgneyJtaWRuYW1lIjogbnVsbH0nKQ0KYGBgDQoNCkJhZ2FpbWFuYSBkZW5nYW4gZGF0YSBiZXJ1cGEgdGFuZ2dhbD8gSlNPTiBtZW55aW1wYW5ueWEgc2ViYWdhaSB0ZWtzLCBrZWN1YWxpIHVudHVrIHRhbmdnYWwgeWFuZyBzZW11YW55YSBudW1lcmlrLiBNaXNhbG55YSBgMjAxOTA3MTFgIGRhbiB0YW5wYSB0YW5kYSBrdXRpcCAoIikgYWthbiBkaWJhY2Egc2ViYWdhaSBudW1lcmlrLg0KDQojIFJlYWQgSlNPTiBEYXRhDQoNCktpdGEgZGFwYXQgZGVuZ2FuIG11ZGFoIG1lbWJhY2EvaW1wb3J0IGRhdGEgZGFyaSBmaWxlIEpTT04gZGVuZ2FuIG1lbmdndW5ha2FuIHBhY2thZ2UgW2Bqc29ubGl0ZWBdKGh0dHBzOi8vZ2l0aHViLmNvbS9qZXJvZW4vanNvbmxpdGUpLg0KDQpgYGB7cn0NCmxpYnJhcnkoanNvbmxpdGUpDQpgYGANCg0KIyMgRm9ybWF0IDENCmBgYHtyfQ0KanNvbjEgPC0gJ3sgDQogICJJRCI6IFsxLDIsMyw0LDVdLA0KICAiTmFtZSI6IFsiUmljayIsIkRhbiIsIk1pY2hlbGxlIiwiUnlhbiIsIkdhcnkiXSwNCiAgIlNhbGFyeSI6IFs2MjMuMyw1MTUuMiw2MTEsNzI5LDg0My4yNV0sDQogICJTdGFydERhdGUiOiBbIjEvMS8yMDEyIiwiOS8yMy8yMDEzIiwiMTEvMTUvMjAxNCIsIjUvMTEvMjAxNCIsIjMvMjcvMjAxNSJdLA0KICAiRGVwdCI6IFsiSVQiLCJPcGVyYXRpb25zIiwiSVQiLCJIUiIsIkZpbmFuY2UiXQ0KfScNCg0KeDEgPC0gZnJvbUpTT04oanNvbjEpDQpzdHIoeDEpDQpgYGANCg0KSmFkaWthbiBgZGF0YS5mcmFtZWAhDQoNCmBgYHtyfQ0KeDEgPC0gYXMuZGF0YS5mcmFtZSh4MSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc3RyKHgxKQ0KYGBgDQoNCiMjIEZvcm1hdCAyDQoNCmBgYHtyfQ0KanNvbjIgPC0gJ1sNCiAgWzEsICJSaWNrIiwgNjIzLjMsICIxLzEvMjAxMiIsICJJVCJdLA0KICBbMiwgIkRhbiIsIDUxNS4yLCAiOS8yMy8yMDEzIiwgIk9wZXJhdGlvbnMiXSwNCiAgWzMsICJNaWNoZWxsZSIsIDYxMSwgIjExLzE1LzIwMTQiLCAiSVQiXSwNCiAgWzQsICJSeWFuIiwgNzI5LCAiNS8xMS8yMDE0IiwgIkhSIl0sDQogIFs1LCAiR2FyeSIsIDg0My4yNSwgIjMvMjcvMjAxNSIsICJGaW5hbmNlIl0NCl0nDQp4MiA8LSBmcm9tSlNPTihqc29uMikNCnN0cih4MikNCmBgYA0KDQpgYGB7cn0NCngyIDwtIGFzLmRhdGEuZnJhbWUoeDIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQ0Kc3RyKHgyKQ0KDQpgYGANCg0KIyMgRm9ybWF0IDMNCmBgYHtyfQ0KanNvbjMgPC0gJ1sNCiAgew0KICAiSUQiOjEsICJOYW1lIjoiUmljayIsICJTYWxhcnkiOjYyMy4zLCAiU3RhcnREYXRlIjoiMS8xLzIwMTIiLCAiRGVwdCI6IklUIg0KICB9LA0KICB7DQogICJJRCI6MiwgIk5hbWUiOiJEYW4iLCAiU2FsYXJ5Ijo1MTUuMiwgIlN0YXJ0RGF0ZSI6IjkvMjMvMjAxMyIsICJEZXB0IjoiT3BlcmF0aW9ucyINCiAgfSwNCiAgew0KICAiSUQiOjMsICJOYW1lIjoiTWljaGVsbGUiLCAiU2FsYXJ5Ijo2MTEsICJTdGFydERhdGUiOiIxMS8xNS8yMDE0IiwgIkRlcHQiOiJJVCINCiAgfSwNCiAgew0KICAiSUQiOjQsICJOYW1lIjoiUnlhbiIsICJTYWxhcnkiOjcyOSwgIlN0YXJ0RGF0ZSI6IjUvMTEvMjAxNCIsICJEZXB0IjoiSFIiDQogIH0sDQogIHsNCiAgIklEIjo1LCAiTmFtZSI6IkdhcnkiLCAiU2FsYXJ5Ijo4NDMuMjUsICJTdGFydERhdGUiOiIzLzI3LzIwMTUiLCAiRGVwdCI6IkZpbmFuY2UiDQogIH0NCl0nDQp4MyA8LSBmcm9tSlNPTihqc29uMykNCnN0cih4MykNCg0KYGBgDQoNCiMgUmVhZCBKU09OIEZyb20gV2Vic2l0ZQ0KDQpgYGB7cn0NCiMgUmVhZCBKU09OIGRhdGEgZnJvbSB3ZWJzaXRlOiBpbmZvcGVtaWx1LmtwdS5nby5pZA0KZHBzMjAxOSA8LSBmcm9tSlNPTigiaHR0cHM6Ly9wZW1pbHUyMDE5LmtwdS5nby5pZC9zdGF0aWMvanNvbi9oaGN3L3Bwd3AuanNvbiIpDQojIFZpZXcoZHBzMjAxOSkNCmhlYWQoZHBzMjAxOSR0YWJsZSkNCmBgYA0KDQpgYGB7cn0NCmRwczIwMTkgPC0gZG8uY2FsbChyYmluZC5kYXRhLmZyYW1lLCBkcHMyMDE5JHRhYmxlKQ0Kc3RyKGRwczIwMTkpDQpoZWFkKGRwczIwMTkpDQpgYGANCg0KIyBFeHBvcnQgRGF0YWZyYW1lIEFzIEpTT04NCg0KYGBge3J9DQp3cml0ZV9qc29uKGRwczIwMTksICJkcHMyMDE5Lmpzb24iLCBwcmV0dHkgPSBUUlVFLCBkYXRhZnJhbWVzID0gInJvd3MiKQ0KYGBgDQoNCiMgUmVhZCBMb2NhbCBKU09OIEZpbGUNCg0KYGBge3J9DQojIFJlYWQgSlNPTiBkYXRhIGZyb20gbG9jYWwgLmpzb24gZmlsZQ0KZHBzMjAxOCA8LSBmcm9tSlNPTignZHBzMjAxOC5qc29uJywgc2ltcGxpZnlEYXRhRnJhbWUgPSBUUlVFKQ0Kc3RyKGRwczIwMTgpDQpoZWFkKGRwczIwMTgpDQpgYGANCg0KIyMgRXhwbG9yZQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQojIEhvdyBtYW55ICdLZWx1cmFoYW4nIGluIERyYW1hZ2E/DQpkcHMyMDE4ICU+JSANCiAgZGlzdGluY3QobmFtYUtlbHVyYWhhbikgJT4lIA0KICBjb3VudCgpIA0KDQojIFdoYXQgNSAnS2VsdXJhaGFuJyBoYXZlIHRoZSBsYXJnZXN0IG51bWJlciBvZiBUUFM/DQpkcHMyMDE4ICU+JSANCiAgYXJyYW5nZShkZXNjKGptbFRwcykpICU+JSANCiAgc2VsZWN0KG5hbWFLZWx1cmFoYW4sIGptbFRwcykgJT4lIA0KICBoZWFkKG4gPSA1KQ0KDQpgYGANCg0KIyBVc2UgZ2dwbG90MiBwYWNrYWdlDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KZHBzMjAxOCAlPiUgDQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIobmFtYUtlbHVyYWhhbiwgam1sVHBzKSwgeSA9IGptbFRwcykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGptbFRwcykpICsNCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgVFBTIGJ5IEtlbHVyYWhhbiIsDQogICAgICAgeSA9ICJOdW1iZXIgb2YgVFBTIiwNCiAgICAgICB4ID0gIktlbHVyYWhhbiIpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0K