The materials in this R Markdown Notebook are licensed under a
Creative
Commons Attribution-NonCommercial-ShareAlike 4.0 International
License.
Pengantar
Materi pada R Markdown Notebook ini dibawakan pada R-Ladies
Jakarta 15th meetup (2 April 2022,
1400-1600 WIB) dengan tema Basic text manipulation with
stringr
(Rajeg
2022a). Jika materi ini digunakan kembali, menjadi dasar,
ataupun dikutip untuk keperluan lokakarya dan hal-hal lainnya, mohon
mengutip materi ini sebagai berikut:
Rajeg, Gede Primahadi Wijaya. 2022. Pengolahan teks dasar dengan R
menggunakan stringr. Open Science Framework (OSF). doi: 10.17605/OSF.IO/9ZHDJ.
https://osf.io/9zhdj/ (2
April, 2022).
Dan juga salindia pembuka sebelum pelaksanaan lokakarya (Rajeg 2022b):
Rajeg, Gede Primahadi Wijaya. 2022. Basic text manipulation with
stringr. OSF Preprints. doi: 10.31219/osf.io/q9yva.
https://osf.io/q9yva/
(2 April, 2022).
Pembaca disarankan mempelajari langsung dua sumber utama terkait
stringr
, yaitu (i) buku teks oleh Wickham dan Grolemund
(2017), utamanya Bab 14, dan (ii) cheatsheet
PDF untuk fungsi-fungsi kunci dalam stringr
. Bacaan lain
yang mungkin bisa dilihat adalah makalah kami (Rajeg, Denistia
& Rajeg 2018) yang salah satu bagiannya membahas
pengolahan teks dasar menggunakan sejumlah fungsi pengolahan teks dari
instalasi dasar R (bukan menggunakan stringr
) (kode sumber
makalah tersebut dapat diakses melalui tautan berikut atau
berikut).
Persiapan
# global option chunck
knitr::opts_chunk$set(echo = TRUE, include = TRUE, message = FALSE, warning = FALSE)
# install package stringr
install.packages("stringr")
Aktifkan modul/package stringr
.
# load the packages
library(stringr)
Muat data teks berupa kalimat dan kata-kata.
eng_sentence_all <- scan(file = "data/eng_stringr_sentences_all.txt", what = "char", sep = "\n", quiet = TRUE)
length(eng_sentence_all) # ada 720 elemen kalimat
[1] 720
sample(eng_sentence_all, size = 3) # tampilkan 3 kalimat acak saja
[1] "The beach is dry and shallow at low tide."
[2] "Leaves turn brown and yellow in the fall."
[3] "A whiff of it will cure the most stubborn cold."
words <- stringr::words # data kata (*words*) dari package stringr
sample(words, size = 3)
[1] "self" "example" "care"
fruits <- stringr::fruit # data kata-kata nama buah (*fruits*) dari package stringr
sample(fruits, size = 3)
[1] "satsuma" "breadfruit" "rock melon"
Pencarian dan
pendeteksian (rangkaian) karakter
Menguji pola
pencarian dan hasil yang ditangkap dengan
str_view_all()
Fungsi str_view_all()
memerlukan kita menginstall
package htmlwidgets
. Jika tidak, error akan muncul seperti
pada gambar di bawah ini.
# install htmlwidgets package
install.packages("htmlwidgets")
Kode berikut mencoba menampilkan keberadaan rangkaian karakater
"ze"
dalam vektor teks eng_sentence_all
.
str_view_all(string = eng_sentence_all, pattern = "ze", match = TRUE)
Registered S3 methods overwritten by 'htmltools':
method from
print.html tools:rstudio
print.shiny.tag tools:rstudio
print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Latihan
- Ubah parameter argumen
match = TRUE
menjadi
match = FALSE
, lalu jalankan kode sebelumnya dengan pola
pencarian "ze"
. Apa yang terjadi pada luarannya? Apa fungsi
dari match = FALSE
?
- Gunakan
str_view_all()
untuk menampilkan rangkaian
karakter "ly"
pada vektor teks
eng_sentence_all
.
- Bagaimana pola pencarian untuk menampilkan rangkaian karakter
"ly"
yang diikuti dengan spasi (whitespace)?
Mendeteksi keberadaan
pola rangkaian karakter dengan str_detect()
Fungsi str_detect()
menghasilkan luaran logis
TRUE
dan FALSE
yang menyatakan apakah
rangkaian karakter yang kita cari ditemukan (TRUE
) atau
tidak (FALSE
) pada suatu vektor teks/karakter.
# buat 50 sampel kalimat sederhana
eng_sentence_all_sample <- sample(x = eng_sentence_all, size = 50)
# apakah rangkaian karakter "ed" ditemukan dalam `eng_sentence_all_sample`?
str_detect(string = eng_sentence_all_sample, pattern = "ed")
[1] FALSE FALSE TRUE TRUE TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE
[14] TRUE FALSE FALSE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE FALSE FALSE
[27] FALSE FALSE TRUE TRUE TRUE FALSE TRUE TRUE FALSE TRUE FALSE TRUE FALSE
[40] FALSE FALSE TRUE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE
Latihan
- Gunakan
str_view_all()
untuk menampilkan rangkaian
karakter "ed"
pada vektor teks
eng_sentence_all_sample
.
- Apakah rangkaian karakter konsonan
"ck"
ditemukan dalam
nama-nama buah pada vektor teks fruits
?
- Jika ya, gunakan
str_view_all()
untuk menampilkan nama
buah apa yang mengandung rangkaian karakter konsonan "ck"
pada vektor teks fruits
.
Fungsi str_detect()
juga dapat digunakan untuk menyaring
observasi yang diinginkan dalam tabel (data frame) berdasarkan
rangkaian karakter tertentu. Ini dimungkinkan karena luaran
str_detect()
berupa struktur logis TRUE
dan
FALSE
yang menjadi landasan dalam menyaring observasi,
salah satunya dalam tabel.
# muat data tabel hanya kolom 4 - 7
verbs_idn <- read.table(file = "data/verb_semantics.txt", header = TRUE, sep = "\t")[4:7]
# lihat enam baris pertama
head(verbs_idn)
Kode berikut menyaring observasi (subset()
) dalam tabel
data verbs_idn
berdasarkan apakah kolom
example_target
mengandung teks (yaitu kata kerja
ber-) dengan rangkaian karakter "da"
(lihat Rajeg 2013 untuk makalah yang dilandasi atas
data tabel tersebut).
subset(verbs_idn, str_detect(string = example_target, pattern = "da"))
Latihan
- Ubah kode sebelumnya untuk menyaring/mendeteksi kata-kata dalam
kolom
example_source
yang mengandung
rangkaian karakter "ar"
.
Menyaring elemen
vektor teks yang mengandung rangkaian karakter tertentu dengan
str_subset()
Berbeda dengan str_detect()
, yang mengeluarkan
TRUE
dan FALSE
, str_subset()
(i)
mendeteksi dan (ii) mengeluarkan elemen dalam vektor teks yang
mengandung rangkaian karakter yang dicari.
str_subset(string = eng_sentence_all_sample, pattern = "ing")
[1] "Wood is best for making toys and blocks."
[2] "See the cat glaring at the scared mouse."
[3] "The map had an X that meant nothing."
[4] "The first part of the plan needs changing."
[5] "The source of the huge river is the clear spring."
[6] "Clothes and lodging are free to new men."
[7] "It takes heat to bring out the odor."
Tentu kita bisa simpan hasil penyaringan ini ke vektor lain.
# simpan luaran kode berikut ke vektor `ing_output`
ing_output <- str_subset(string = eng_sentence_all_sample, pattern = "ing")
ing_output
[1] "Wood is best for making toys and blocks."
[2] "See the cat glaring at the scared mouse."
[3] "The map had an X that meant nothing."
[4] "The first part of the plan needs changing."
[5] "The source of the huge river is the clear spring."
[6] "Clothes and lodging are free to new men."
[7] "It takes heat to bring out the odor."
Latihan
- Buah apa yang namanya mengandung karakter
"ck"
? Gunakan
str_subset()
pada vektor teks fruits
untuk
menjawab pertanyaan ini.
- Gunakan
str_subset()
untuk menyaring kalimat dalam
vektor eng_sentence_all
yang mengandung rangkaian karakter
"who"
. Apakah pola pencarian "who"
ini
mengeluarkan kalimat yang mengandung kata who ‘siapa’ dalam
bahasa Inggris?
Bandingkan luaran kedua baris kode berikut untuk pola pencarian
dengan dan tanpa RegEx pewatas kata ("\\b"
):
# tanpa regex pewatas kata "\\b" di kedua sisi karakter yang dicari
str_subset(string = eng_sentence_all, pattern = "who")
[1] "Thieves who rob friends deserve jail."
[2] "Find the twin who stole the pearl necklace."
[3] "He took the lead and kept it the whole distance."
[4] "The facts don\u0092t always show who is right."
# tanpa regex pewatas kata "\\b" di kedua sisi karakter yang dicari
str_view_all(string = eng_sentence_all, pattern = "who", match = TRUE)
# dengan regex pewatas kata "\\b" di kedua sisi karakter yang dicari
str_subset(string = eng_sentence_all, pattern = "\\bwho\\b")
[1] "Thieves who rob friends deserve jail."
[2] "Find the twin who stole the pearl necklace."
[3] "The facts don\u0092t always show who is right."
# dengan regex pewatas kata "\\b" di kedua sisi karakter yang dicari
str_view_all(string = eng_sentence_all, pattern = "\\bwho\\b", match = TRUE)
Latihan
- Gunakan RegEx pewatas kata (
"\\b"
) dengan
str_subset()
untuk menyaring kalimat dalam vektor
eng_sentence_all
yang mengandung kata-kata yang
diakhiri dengan rangkaian karakter "ing"
(misalnya, kata-kata seperti texting,
living, ring,
spring, dll.)
- Gunakan
str_subset()
dan pola pencarian dengan RegEx
pewatas kata ("\\b"
) untuk mengeluarkan kata-kata yang
diawali dengan karakter "ch"
(misalnya
chance, chap, dll.)
dalam vektor teks words
.
Perhatikan kode berikut sebagai contoh penggunaan RegEx pewatas awal
dan akhir rangkaian karakter (dikutip dari Wickham & Grolemund
2017:202):
# buat data sederhana
fruit_mini <- c("apple", "banana", "pear")
# menangkap karakter `"a"` yang muncul di akhir (`"$"`) rangkaian karakter nama buah pada vektor `fruit_mini`
str_view_all(string = fruit_mini, pattern = "a$")
str_subset(string = fruit_mini, pattern = "a$")
[1] "banana"
# menangkap karakter `"a"` yang muncul di akhir (`"$"`) rangkaian karakter nama buah pada vektor `fruit_mini`
str_view_all(string = fruit_mini, pattern = "^a")
str_subset(string = fruit_mini, pattern = "^a")
[1] "apple"
Kita bisa menggabungkan "^"
dan "$"
untuk
mempertegas bahwa kita hanya ingin menangkap rangkaian karakter secara
utuh. Bandingkan kedua kode berikut (dikutip dari
Wickham &
Grolemund 2017:202):
# buat data lain
fruit_cake <- c("apple pie", "apple", "apple cake")
# pencarian sederhana (tanpa RegEx) untuk menangkap rangkaian karakter `"apple"`
str_view_all(string = fruit_cake, pattern = "apple")
str_subset(string = fruit_cake, pattern = "apple")
[1] "apple pie" "apple" "apple cake"
# menangkap hanya rangkaian karakter utuh dari awal hingga akhir rangkaian karakter
str_view_all(string = fruit_cake, pattern = "^apple$")
str_subset(string = fruit_cake, pattern = "^apple$")
[1] "apple"
Latihan
Buah apa saja yang namanya diawali dengan
karakter konsonan "b"
? Gunakan str_subset()
untuk mengeluarkan dari vektor fruits
nama-nama buah yang
diawali dengan karakter "b"
.
Ada berapa buah yang namanya berakhir dengan
karakter vokal "o"
? Gunakan str_subset()
untuk
mengeluarkan dari vektor fruits
nama-nama buah yang diawali
dengan karakter "o"
.
Memecah teks menjadi
unit yang lebih kecil
Fungsi str_split()
digunakan untuk memecah teks
berdasarkan pada karakter mana teks tersebut dipecah. Contoh paling
sederhana adalah memecah kalimat menjadi kata dengan memecahnya pada
karakter spasi (yang merupakan pemisah kata untuk karakter Roman yang
dipahami oleh komputer).
# contoh sederhana pemecahan kalimat -> kata dengan dua kalimat
two_sentences <- eng_sentence_all_sample[1:2]
# pecah teks pada karakter spasi `" "`.
str_split(two_sentences, pattern = " ") # luarannya adalah List
[[1]]
[1] "The" "weight." "of" "the" "package" "was" "seen" "on"
[9] "the" "high" "scale."
[[2]]
[1] "Tear" "a" "thin" "sheet" "from" "the" "yellow" "pad."
Isunya adalah tanda baca seperti titik (.
) masih
menempel pada kata yang mengakhiri kalimat. Pada situasi inilah kekuatan
dari RegEx menjadi penting.
Kita perlu merancang pola pencarian RegEx yang menyatakan bahwa kita
ingin memisahkan/memecah teks pada kelompok karakter
selain kelompok karakter pembentuk kata, yaitu kelompok
karakter di luar karakter alfanumeris dan strip
"-"
. Dalam konteks bahasa Inggris, "-"
dipertahankan untuk menangkap kata seperti computer-readable
sebagai satu unit, bukannya menjadi dua unit computer dan
readable.
RegEx yang bisa digunakan adalah "[^a-zA-Z0-9-]+"
, yang
artinya: satu atau lebih ("+"
) kelompok karakter
("[...]"
) yang bukan ("^"
) (i) alfanumeris
kapital dan kecil ("a-zA-Z0-9"
) dan strip
("-"
).
# pecah teks pada karakter non-alfanumeris dan spasi `" "`.
str_split(two_sentences, pattern = "[^a-zA-Z0-9-]+")
[[1]]
[1] "The" "weight" "of" "the" "package" "was" "seen" "on"
[9] "the" "high" "scale" ""
[[2]]
[1] "Tear" "a" "thin" "sheet" "from" "the" "yellow" "pad" ""
Tentu luaran List ini bisa kita ubah menjadi vektor atomis:
split_sentence <- str_split(two_sentences, pattern = "[^a-zA-Z0-9-]+")
unlist(split_sentence)
[1] "The" "weight" "of" "the" "package" "was" "seen" "on"
[9] "the" "high" "scale" "" "Tear" "a" "thin" "sheet"
[17] "from" "the" "yellow" "pad" ""
Pemecahan teks dari kalimat menjadi kata ini dapat dilihat dari dua
perspektif:
memecah (yaitu memisahkan
dengan menghilangkan) karakter selain
alfanumeris dan strip, menggunakan str_split()
,
atau
menarik (yaitu
mengeluarkan/mengekstraksi) karakter
yang membangun suatu kata, yaitu karakter alfanumeris dan strip,
menggunakan str_extract_all()
.
Jika kita mengambil perspektif kedua (dengan
str_extract_all()
), maka RegEx yang digunakan sedikit
berbeda, yaitu dengan menghilangkan tanda negasi (‘bukan’)
"^"
dalam RegEx-nya. Perhatikan kode berikut dan bandingkan
dengan teliti luaran str_extract_all()
dengan luaran
str_split()
sebelumnya.
# perspektif kedua memecah kalimat menjadi kata
# dengan **mengkekstraksi** kata-kata
str_extract_all(two_sentences, pattern = "[a-zA-Z0-9-]+")
[[1]]
[1] "The" "weight" "of" "the" "package" "was" "seen" "on"
[9] "the" "high" "scale"
[[2]]
[1] "Tear" "a" "thin" "sheet" "from" "the" "yellow" "pad"
Yang membedakan luaran str_split()
dan
str_extract_all()
di atas, khususnya dalam konteks memecah
teks kalimat menjadi kata adalah:
luaran str_split()
menandai penghilangan/pemecahan
tanda baca, dalam hal ini titik, dengan karakter kosong (lihat karakter
""
setelah kata "ends"
dan
"enough"
).
luaran str_extract_all()
hanya akan
mengeluarkan/mengekstraksi karakter yang dinyatakan dalam pola
pencariannya, yaitu satu atau lebih karakter alfanumeris dan strip;
tidak ada karakter kosong yang mencerminkan dalam hal ini tanda
titik.
Kita yang menentukan fungsi dan luaran seperti apa yang
diinginkan.
Mengubah komponen
teks
Mengubah karakter
menjadi huruf besar atau kecil
Fungsi str_to_upper()
mengubah karakter menjadi huruf
kapital dan str_to_lower()
menjadi huruf kecil.
# mengubah nama warna sebelumnya menjadi huruf kapital
word_colour_caps <- str_to_upper(string = word_colour_vector)
word_colour_caps
[1] "BLUE" "BLUE" "BLUE" "YELLOW" "GREEN" "BLUE" "BLUE" "BLUE" "GREEN"
[10] "GREEN" "GREEN" "PURPLE" "GREEN" "BLUE" "BLUE" "GREEN" "GREEN" "GREEN"
[19] "YELLOW" "ORANGE"
# mengubah nama warna kapital menjadi huruf kecil
str_to_lower(string = word_colour_caps)
[1] "blue" "blue" "blue" "yellow" "green" "blue" "blue" "blue" "green"
[10] "green" "green" "purple" "green" "blue" "blue" "green" "green" "green"
[19] "yellow" "orange"
Latihan
- Lihat isi vektor
two_sentences
pada konsol dan
perhatikan bentuk rangkaian karakternya. Kemudian jalankan fungsi
str_to_title()
dengan input two_sentences
.
Perubahan apa yang terjadi dan apa yang dilakukan oleh
str_to_title()
?
Mengganti komponen
teks dengan karakter lain
Terkadang kita perlu mengubah komponen teks tertentu layaknya fungsi
find and replace pada peranti seperti MS Word. Dalam stringr,
kita bisa menggunakan str_replace()
dan
str_replace_all()
.
Varian dasar tanpa ..._all()
, yaitu
str_replace()
, hanya akan mengganti karakter yang
pertama kali ditangkap oleh pola pencariannya,
sedangkan karakter yang sama yang muncul setelahnya tidak akan ditangkap
dan diganti.
Perhatikan kode berikut yang mencoba mengganti karakter
"e"
pada vektor fruit_cake
.
# lihat kembali vektor `fruit_cake`
fruit_cake
[1] "apple pie" "apple" "apple cake"
# gunakan str_replace() untuk mengganti karakter `"e"` yang ditemukan pertama dengan strip `"-"`
str_replace(string = fruit_cake, pattern = "e", replacement = "-")
[1] "appl- pie" "appl-" "appl- cake"
# gunakan str_replace_all() untuk mengganti SEMUA karakter `"e"` dengan strip `"-"`
str_replace_all(string = fruit_cake, pattern = "e", replacement = "-")
[1] "appl- pi-" "appl-" "appl- cak-"
Latihan
- Ganti rangkaian karakter untuk kata
"apple"
pada vektor
fruit_cake
(yang berisi "apple pie"
,
"apple"
, dan "apple cake"
) dengan kata
"butter"
.
Menggabungkan vektor
rangkaian karakter
Untuk menggabungkan dua atau lebih rangkaian karakter, gunakan
str_c()
.
# menggabungkan dua rangkaian karakter: "ba" dan "li"
str_c("ba", "li")
[1] "bali"
karakter_1 <- c("b", "l", "k")
karakter_2 <- c("a", "i", "u")
# gabungkan tiga karakter dari dua vektor
str_c(karakter_1, karakter_2)
[1] "ba" "li" "ku"
# gabungkan dan apit tiga karakter dalam satu vektor dengan dua karakter lain yaitu "<m>"
str_c("<m>", karakter_1, "<m>")
[1] "<m>b<m>" "<m>l<m>" "<m>k<m>"
Jika salah satu dari dua vektor karakter yang akan digabung memiliki
jumlah elemen yang lebih sedikit, maka elemen pada vektor tersebut akan
digunakan ulang. Perhatikan contoh berikut.
two_word_fruit <- c("apple", "banana")
four_word_snack <- c("cake", "juice", "pie", "chocolate")
# gabungkan kedua vektor di atas
str_c(two_word_fruit, four_word_snack, sep = "_")
[1] "apple_cake" "banana_juice" "apple_pie" "banana_chocolate"
Gunakan argumen sep = ...
untuk mengatur pemisah di
antara rangkaian karakter yang digabungkan. Secara bawaan, argumen
sep = ...
telah diatur menjadi sep = ""
.
# atur pemisah di antara karakter yang digabungkan dengan `sep = ...`
str_c(karakter_1, karakter_2, sep = "_")
[1] "b_a" "l_i" "k_u"
Argumen collapse = ...
akan menyatukan sejumlah
rangkaian karakter menjadi satu rangkaian karakter.
Bandingkan kedua kode berikut yang menggunakan sep = ...
dan collapse = ...
:
# dengan sep = ..., penggabungan berikut menghasilkan tiga elemen rangkaian karakter
three_strings <- str_c("<m>", karakter_1, "<m>", sep = "_")
three_strings
[1] "<m>_b_<m>" "<m>_l_<m>" "<m>_k_<m>"
# Hitung jumlah elemen dalam vektor `three_strings`
length(three_strings)
[1] 3
# dengan collapse = ..., penggabungan berikut menghasilkan satu elemen rangkaian karakter
one_string <- str_c("<m>", karakter_1, "<m>", collapse = "_")
one_string
[1] "<m>b<m>_<m>l<m>_<m>k<m>"
# Hitung jumlah elemen dalam vektor `one_string`
length(one_string)
[1] 1
Menyimpan vektor
karakter ke dalam berkas teks (plain text)
Gunakan fungsi cat()
yang tersedia dari instalasi dasar
R untuk menyimpan vektor karakter ke dalam berkas teks sederhana
(plain text dengan ekstensi .txt
).
# simpan vektor nama warna ke berkas `"selected-colours.txt"`
# dalam direktori `results`
# yang masing-masing elemen vektornya dipisahkan dengan baris baru (`sep="\n"`)
cat(word_colour_vector, file = "results/selected-colours.txt", sep = "\n")
Session info
─ Session info ─────────────────────────────────────────────────────────────────────
setting value
version R version 4.1.3 (2022-03-10)
os macOS Monterey 12.1
system aarch64, darwin20
ui RStudio
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz Asia/Makassar
date 2022-04-02
rstudio 2022.02.0+443 Prairie Trillium (desktop)
pandoc NA
─ Packages ─────────────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
brio 1.1.3 2021-11-30 [1] CRAN (R 4.1.1)
cachem 1.0.6 2021-08-19 [1] CRAN (R 4.1.1)
callr 3.7.0 2021-04-20 [1] CRAN (R 4.1.0)
cli 3.2.0 2022-02-14 [1] CRAN (R 4.1.1)
crayon 1.5.0 2022-02-14 [1] CRAN (R 4.1.1)
desc 1.4.1 2022-03-06 [1] CRAN (R 4.1.1)
devtools 2.4.3 2021-11-30 [1] CRAN (R 4.1.1)
digest 0.6.29 2021-12-01 [1] CRAN (R 4.1.1)
ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.1.0)
fastmap 1.1.0 2021-01-25 [1] CRAN (R 4.1.0)
fs 1.5.2 2021-12-08 [1] CRAN (R 4.1.1)
glue 1.6.2 2022-02-24 [1] CRAN (R 4.1.1)
htmltools 0.5.2 2021-08-25 [1] CRAN (R 4.1.1)
htmlwidgets 1.5.4 2021-09-08 [1] CRAN (R 4.1.1)
jsonlite 1.8.0 2022-02-22 [1] CRAN (R 4.1.1)
knitr 1.37 2021-12-16 [1] CRAN (R 4.1.1)
lifecycle 1.0.1 2021-09-24 [1] CRAN (R 4.1.1)
magrittr 2.0.2 2022-01-26 [1] CRAN (R 4.1.1)
memoise 2.0.1 2021-11-26 [1] CRAN (R 4.1.1)
pkgbuild 1.3.1 2021-12-20 [1] CRAN (R 4.1.1)
pkgload 1.2.4 2021-11-30 [1] CRAN (R 4.1.1)
prettyunits 1.1.1 2020-01-24 [1] CRAN (R 4.1.0)
processx 3.5.2 2021-04-30 [1] CRAN (R 4.1.0)
ps 1.6.0 2021-02-28 [1] CRAN (R 4.1.0)
purrr 0.3.4 2020-04-17 [1] CRAN (R 4.1.0)
R6 2.5.1 2021-08-19 [1] CRAN (R 4.1.1)
remotes 2.4.2 2021-11-30 [1] CRAN (R 4.1.1)
rlang 1.0.2 2022-03-04 [1] CRAN (R 4.1.1)
rprojroot 2.0.2 2020-11-15 [1] CRAN (R 4.1.0)
sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.1.1)
stringi 1.7.6 2021-11-29 [1] CRAN (R 4.1.1)
stringr * 1.4.0 2019-02-10 [1] CRAN (R 4.1.1)
testthat 3.1.3 2022-03-29 [1] CRAN (R 4.1.1)
usethis 2.1.5 2021-12-09 [1] CRAN (R 4.1.1)
withr 2.5.0 2022-03-03 [1] CRAN (R 4.1.1)
xfun 0.30 2022-03-02 [1] CRAN (R 4.1.1)
yaml 2.3.5 2022-02-21 [1] CRAN (R 4.1.1)
[1] /Library/Frameworks/R.framework/Versions/4.1-arm64/Resources/library
────────────────────────────────────────────────────────────────────────────────────
Daftar acuan
Rajeg, Gede Primahadi Wijaya. 2013. Metonymy in
Indonesian
Prefixal Word-formation.
Lingual: Journal
of Language and Culture 1. 64–81. doi:
10.26180/5b6e403959120.
Rajeg, Gede Primahadi Wijaya. 2022a. Pengolahan teks dasar dengan
R menggunakan stringr.
Open Science Framework
(OSF). doi:
10.17605/OSF.IO/9ZHDJ.
https://osf.io/9zhdj/ (2 April,
2022).
Rajeg, Gede Primahadi Wijaya. 2022b.
Basic text manipulation with
stringr. OSF Preprints. doi:
10.31219/osf.io/q9yva.
https://osf.io/q9yva/ (2 April,
2022).
Rajeg, Gede Primahadi Wijaya, Karlina Denistia & I Made Rajeg. 2018.
Working with a linguistic corpus using
R:
An
introductory note with
Indonesian negating construction.
Linguistik Indonesia 36(1). 1–36. doi:
10.26499/li.v36i1.71.
Wickham, Hadley & Garrett Grolemund. 2017.
R for
Data Science. Canada: O’Reilly.
http://r4ds.had.co.nz/ (7 March,
2017).
LS0tCmF1dGhvcjogCi0gbmFtZTogJ1tHZWRlIFByaW1haGFkaSBXaWpheWEgUmFqZWddKGh0dHBzOi8vdWRheWFuYW5ldHdvcmtpbmcudW51ZC5hYy5pZC9sZWN0dXJlci84ODAtZ2VkZS1wcmltYWhhZGktd2lqYXlhLXJhamVnKSA8YSBpdGVtcHJvcD0ic2FtZUFzIiBjb250ZW50PSJodHRwczovL29yY2lkLm9yZy8wMDAwLTAwMDItMjA0Ny04NjIxIiBocmVmPSJodHRwczovL29yY2lkLm9yZy8wMDAwLTAwMDItMjA0Ny04NjIxIiB0YXJnZXQ9Im9yY2lkLndpZGdldCIgcmVsPSJub29wZW5lciBub3JlZmVycmVyIiBzdHlsZT0idmVydGljYWwtYWxpZ246dG9wOyI+PGltZyBzcmM9Imh0dHBzOi8vb3JjaWQub3JnL3NpdGVzL2RlZmF1bHQvZmlsZXMvaW1hZ2VzL29yY2lkXzE2eDE2LnBuZyIgc3R5bGU9IndpZHRoOjFlbTttYXJnaW4tcmlnaHQ6LjVlbTsiIGFsdD0iT1JDSUQgaUQgaWNvbiI+PC9hPicKICBhZmZpbGlhdGlvbjogIlByb2dyYW0gU3R1ZGkgW1Nhc3RyYSBJbmdncmlzXShodHRwczovL3R3aXR0ZXIuY29tL3Nhc2luZ3VudWQ/bGFuZz1lbikgICYgKkNlbnRyZSBmb3IgSW50ZXJkaXNjaXBsaW5hcnkgUmVzZWFyY2ggb24gdGhlIEh1bWFuaXRpZXMgYW5kIFNvY2lhbCBTY2llbmNlcyogKFtDSVJIU1NdKGh0dHA6Ly93d3cuY2lyaHNzLm9yZykpLCBbRmFrdWx0YXMgSWxtdSBCdWRheWFdKGh0dHBzOi8vZmliLnVudWQuYWMuaWQpLCBbVW5pdmVyc2l0YXMgVWRheWFuYV0oaHR0cHM6Ly93d3cudW51ZC5hYy5pZCkiCmRhdGU6ICIqQ3JlYXRlZCo6IDEgQXByaWwsIDIwMjI7ICpMYXN0IHVwZGF0ZSo6IGByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgp0aXRsZTogIlBlbmdvbGFoYW4gdGVrcyBkYXNhciBkZW5nYW4gW1JdKGh0dHBzOi8vd3d3LnItcHJvamVjdC5vcmcpIG1lbmdndW5ha2FuIFtzdHJpbmdyXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9pbmRleC5odG1sKSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBmaWdfd2lkdGg6IDYKICAgIHRoZW1lOiAidW5pdGVkIgogICAgaGlnaGxpZ2h0OiAicHlnbWVudCIKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICAgIGNvZGVfZm9sZGluZzogc2hvdwpsaW5rLWNpdGF0aW9uczogeWVzCmJpYmxpb2dyYXBoeTogInJlZmVyZW5jZXMuYmliIgpjc2w6IHVuaWZpZWRfc3R5bGVzaGVldF9saW5ndWlzdGljcy5jc2wKLS0tCgo8c3R5bGU+CgogIHAuY29tbWVudCB7CiAgYmFja2dyb3VuZC1jb2xvcjogI0U1RkZDQzsKICBwYWRkaW5nOiAxMHB4OwogIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOwogIG1hcmdpbi1sZWZ0OiAyNXB4OwogIGJvcmRlci1yYWRpdXM6IDVweDsKfQoKPC9zdHlsZT4KCgo8YSByZWw9ImxpY2Vuc2UiIGhyZWY9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMC8iPjxpbWcgYWx0PSJDcmVhdGl2ZSBDb21tb25zIExpY2Vuc2UiIHN0eWxlPSJib3JkZXItd2lkdGg6MCIgc3JjPSJodHRwczovL2kuY3JlYXRpdmVjb21tb25zLm9yZy9sL2J5LW5jLXNhLzQuMC84OHgzMS5wbmciIC8+PC9hPiBbIVtdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvZG9pLTEwLjE3NjA1L09TRi5JTy85WkhESi1saWdodGJsdWUuc3ZnKV0oaHR0cHM6Ly9kb2kub3JnLzEwLjE3NjA1L09TRi5JTy85WkhESikgPGJyIC8+PGk+VGhlIG1hdGVyaWFscyBpbiB0aGlzIFIgTWFya2Rvd24gTm90ZWJvb2sgYXJlIGxpY2Vuc2VkIHVuZGVyIGEgPGEgcmVsPSJsaWNlbnNlIiBocmVmPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1zYS80LjAvIj5DcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbkNvbW1lcmNpYWwtU2hhcmVBbGlrZSA0LjAgSW50ZXJuYXRpb25hbCBMaWNlbnNlPC9hPjwvaT4uCgojIFBlbmdhbnRhciB7LnVubnVtYmVyZWR9CgpNYXRlcmkgcGFkYSBSIE1hcmtkb3duIE5vdGVib29rIGluaSBkaWJhd2FrYW4gcGFkYSBbKlItTGFkaWVzIEpha2FydGEgMTUqXip0aCpeICptZWV0dXAqXShodHRwczovL3VkYXlhbmFuZXR3b3JraW5nLnVudWQuYWMuaWQvbGVjdHVyZXIvZ2FsbGVyeS9waG90by84ODAtZ2VkZS1wcmltYWhhZGktd2lqYXlhLXJhamVnLzEzMTgpICgyIEFwcmlsIDIwMjIsIDE0MDAtMTYwMCBXSUIpIGRlbmdhbiB0ZW1hICpCYXNpYyB0ZXh0IG1hbmlwdWxhdGlvbiB3aXRoIGBzdHJpbmdyYCogW0ByYWplZ19wZW5nb2xhaGFuXzIwMjJdLiBKaWthIG1hdGVyaSBpbmkgZGlndW5ha2FuIGtlbWJhbGksIG1lbmphZGkgZGFzYXIsIGF0YXVwdW4gZGlrdXRpcCB1bnR1ayBrZXBlcmx1YW4gbG9rYWthcnlhIGRhbiBoYWwtaGFsIGxhaW5ueWEsIG1vaG9uIG1lbmd1dGlwIG1hdGVyaSBpbmkgc2ViYWdhaSBiZXJpa3V0OgoKPiBSYWplZywgR2VkZSBQcmltYWhhZGkgV2lqYXlhLiAyMDIyLiBQZW5nb2xhaGFuIHRla3MgZGFzYXIgZGVuZ2FuIFIgbWVuZ2d1bmFrYW4gc3RyaW5nci4gKk9wZW4gU2NpZW5jZSBGcmFtZXdvcmsgKE9TRikqLiBkb2k6IFsxMC4xNzYwNS9PU0YuSU8vOVpIREpdKGh0dHBzOi8vZG9pLm9yZy8xMC4xNzYwNS9PU0YuSU8vOVpIREopLiBodHRwczovL29zZi5pby85emhkai8gKDIgQXByaWwsIDIwMjIpLgoKRGFuIGp1Z2Egc2FsaW5kaWEgcGVtYnVrYSBzZWJlbHVtIHBlbGFrc2FuYWFuIGxva2FrYXJ5YSBbQHJhamVnX2Jhc2ljXzIwMjJdOgoKPiBSYWplZywgR2VkZSBQcmltYWhhZGkgV2lqYXlhLiAyMDIyLiAqQmFzaWMgdGV4dCBtYW5pcHVsYXRpb24gd2l0aCBzdHJpbmdyKi4gT1NGIFByZXByaW50cy4gZG9pOiBbMTAuMzEyMTkvb3NmLmlvL3E5eXZhXShodHRwczovL2RvaS5vcmcvMTAuMzEyMTkvb3NmLmlvL3E5eXZhKS4gW2h0dHBzOi8vb3NmLmlvL3E5eXZhL10oaHR0cHM6Ly9kb2kub3JnLzEwLjMxMjE5L29zZi5pby9xOXl2YSkgKDIgQXByaWwsIDIwMjIpLgoKUGVtYmFjYSBkaXNhcmFua2FuIG1lbXBlbGFqYXJpIGxhbmdzdW5nIGR1YSBzdW1iZXIgdXRhbWEgdGVya2FpdCBgc3RyaW5ncmAsIHlhaXR1IChpKSBidWt1IHRla3Mgb2xlaCBXaWNraGFtIGRhbiBHcm9sZW11bmQgWy1Ad2lja2hhbV9yXzIwMTddLCB1dGFtYW55YSBbQmFiIDE0XShodHRwczovL3I0ZHMuaGFkLmNvLm56L3N0cmluZ3MuaHRtbCksIGRhbiAoaWkpIFsqY2hlYXRzaGVldCpdKGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL2NoZWF0c2hlZXRzL2Jsb2IvbWFpbi9zdHJpbmdzLnBkZikgUERGIHVudHVrIGZ1bmdzaS1mdW5nc2kga3VuY2kgZGFsYW0gYHN0cmluZ3JgLiBCYWNhYW4gbGFpbiB5YW5nIG11bmdraW4gYmlzYSBkaWxpaGF0IGFkYWxhaCBtYWthbGFoIGthbWkgW0ByYWplZ193b3JraW5nXzIwMThdIHlhbmcgc2FsYWggc2F0dSBiYWdpYW5ueWEgbWVtYmFoYXMgcGVuZ29sYWhhbiB0ZWtzIGRhc2FyIG1lbmdndW5ha2FuIHNlanVtbGFoIGZ1bmdzaSBwZW5nb2xhaGFuIHRla3MgZGFyaSBpbnN0YWxhc2kgZGFzYXIgUiAoYnVrYW4gbWVuZ2d1bmFrYW4gYHN0cmluZ3JgKSAoa29kZSBzdW1iZXIgbWFrYWxhaCB0ZXJzZWJ1dCBkYXBhdCBkaWFrc2VzIG1lbGFsdWkgW3RhdXRhbiBiZXJpa3V0XShodHRwczovL2RvaS5vcmcvMTAuNDIyNS8wMy81YTdlZTJhYzg0MzAzKSBhdGF1IFtiZXJpa3V0XShodHRwczovL29zZi5pby9zNmtoOC8pKS4KCiMgUGVyc2lhcGFuCgpgYGB7ciBzZXR1cH0KIyBnbG9iYWwgb3B0aW9uIGNodW5jawprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGluY2x1ZGUgPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKYGBgCgpgYGAKIyBpbnN0YWxsIHBhY2thZ2Ugc3RyaW5ncgppbnN0YWxsLnBhY2thZ2VzKCJzdHJpbmdyIikKYGBgCgpBa3RpZmthbiBtb2R1bC9wYWNrYWdlIGBzdHJpbmdyYC4KCmBgYHtyIGFrdGlma2FuLW1vZHVsLXN0cmluZ3J9CiMgbG9hZCB0aGUgcGFja2FnZXMKbGlicmFyeShzdHJpbmdyKQpgYGAKCk11YXQgZGF0YSB0ZWtzIGJlcnVwYSBrYWxpbWF0IGRhbiBrYXRhLWthdGEuCgpgYGB7ciBtdWF0LWRhdGEta2FsaW1hdC1zdHJpbmdyLXNlbXVhfQplbmdfc2VudGVuY2VfYWxsIDwtIHNjYW4oZmlsZSA9ICJkYXRhL2VuZ19zdHJpbmdyX3NlbnRlbmNlc19hbGwudHh0Iiwgd2hhdCA9ICJjaGFyIiwgc2VwID0gIlxuIiwgcXVpZXQgPSBUUlVFKQoKbGVuZ3RoKGVuZ19zZW50ZW5jZV9hbGwpICMgYWRhIDcyMCBlbGVtZW4ga2FsaW1hdAoKc2FtcGxlKGVuZ19zZW50ZW5jZV9hbGwsIHNpemUgPSAzKSAjIHRhbXBpbGthbiAzIGthbGltYXQgYWNhayBzYWphCmBgYAoKYGBge3IgbXVhdC1kYXRhLWx5LCBlY2hvID0gRkFMU0UsIGluY2x1ZGUgPSBGQUxTRSwgZXZhbCA9IEZBTFNFfQplbmdfc2VudGVuY2VfbHkgPC0gc2NhbihmaWxlID0gImRhdGEvZW5nX3NlbnRlbmNlc19seS50eHQiLCB3aGF0ID0gImNoYXIiLCBzZXAgPSAiXG4iLCBxdWlldCA9IFRSVUUpCgpzYW1wbGUoZW5nX3NlbnRlbmNlX2x5LCBzaXplID0gMykKYGBgCgpgYGB7ciBtdWF0LWRhdGEtemUsIGVjaG8gPSBGQUxTRSwgaW5jbHVkZSA9IEZBTFNFLCBldmFsID0gRkFMU0V9CmVuZ19zZW50ZW5jZV96ZSA8LSBzY2FuKGZpbGUgPSAiZGF0YS9lbmdfc2VudGVuY2VzX3plLnR4dCIsIHdoYXQgPSAiY2hhciIsIHNlcCA9ICJcbiIsIHF1aWV0ID0gVFJVRSkKCnNhbXBsZShlbmdfc2VudGVuY2VfemUsIHNpemUgPSAzKQpgYGAKCmBgYHtyIG11YXQtZGF0YS1rYXRhfQp3b3JkcyA8LSBzdHJpbmdyOjp3b3JkcyAjIGRhdGEga2F0YSAoKndvcmRzKikgZGFyaSBwYWNrYWdlIHN0cmluZ3IKc2FtcGxlKHdvcmRzLCBzaXplID0gMykKYGBgCgpgYGB7ciBtdWF0LWRhdGEtbmFtYS1idWFofQpmcnVpdHMgPC0gc3RyaW5ncjo6ZnJ1aXQgIyBkYXRhIGthdGEta2F0YSBuYW1hIGJ1YWggKCpmcnVpdHMqKSBkYXJpIHBhY2thZ2Ugc3RyaW5ncgpzYW1wbGUoZnJ1aXRzLCBzaXplID0gMykKYGBgCgojIFBlbmNhcmlhbiBkYW4gcGVuZGV0ZWtzaWFuIChyYW5na2FpYW4pIGthcmFrdGVyCgojIyBNZW5ndWppIHBvbGEgcGVuY2FyaWFuIGRhbiBoYXNpbCB5YW5nIGRpdGFuZ2thcCBkZW5nYW4gYHN0cl92aWV3X2FsbCgpYAoKRnVuZ3NpIGBzdHJfdmlld19hbGwoKWAgbWVtZXJsdWthbiBraXRhIG1lbmdpbnN0YWxsIHBhY2thZ2UgYGh0bWx3aWRnZXRzYC4gSmlrYSB0aWRhaywgZXJyb3IgYWthbiBtdW5jdWwgc2VwZXJ0aSBwYWRhIGdhbWJhciBkaSBiYXdhaCBpbmkuCgpgYGB7ciBlcnJvci1odG1sLXdpZGdldCwgZWNobyA9IEZBTFNFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHRtbHdpZGdldC1lcnJvci5wbmciKQpgYGAKCmBgYHtyIGluc3RhbGwtaHRtbHdpZGdldHMsIGV2YWwgPSBGQUxTRX0KIyBpbnN0YWxsIGh0bWx3aWRnZXRzIHBhY2thZ2UKaW5zdGFsbC5wYWNrYWdlcygiaHRtbHdpZGdldHMiKQpgYGAKCktvZGUgYmVyaWt1dCBtZW5jb2JhIG1lbmFtcGlsa2FuIGtlYmVyYWRhYW4gcmFuZ2thaWFuIGthcmFrYXRlciBgInplImAgZGFsYW0gdmVrdG9yIHRla3MgYGVuZ19zZW50ZW5jZV9hbGxgLgoKYGBge3IgbWVsaWhhdC1oYXNpbC1wZW5jYXJpYW4sIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQpzdHJfdmlld19hbGwoc3RyaW5nID0gZW5nX3NlbnRlbmNlX2FsbCwgcGF0dGVybiA9ICJ6ZSIsIG1hdGNoID0gVFJVRSkKYGBgCgojIyMgTGF0aWhhbiB7LnVubnVtYmVyZWR9CgoxLiAgVWJhaCBwYXJhbWV0ZXIgYXJndW1lbiBgbWF0Y2ggPSBUUlVFYCBtZW5qYWRpIGBtYXRjaCA9IEZBTFNFYCwgbGFsdSBqYWxhbmthbiBrb2RlIHNlYmVsdW1ueWEgZGVuZ2FuIHBvbGEgcGVuY2FyaWFuIGAiemUiYC4gQXBhIHlhbmcgdGVyamFkaSBwYWRhIGx1YXJhbm55YT8gQXBhIGZ1bmdzaSBkYXJpIGBtYXRjaCA9IEZBTFNFYD8KMi4gIEd1bmFrYW4gYHN0cl92aWV3X2FsbCgpYCB1bnR1ayBtZW5hbXBpbGthbiByYW5na2FpYW4ga2FyYWt0ZXIgYCJseSJgIHBhZGEgdmVrdG9yIHRla3MgYGVuZ19zZW50ZW5jZV9hbGxgLgozLiAgQmFnYWltYW5hIHBvbGEgcGVuY2FyaWFuIHVudHVrIG1lbmFtcGlsa2FuIHJhbmdrYWlhbiBrYXJha3RlciBgImx5ImAgeWFuZyBkaWlrdXRpIGRlbmdhbiBzcGFzaSAoKndoaXRlc3BhY2UqKT8KCiMjIE1lbmRldGVrc2kga2ViZXJhZGFhbiBwb2xhIHJhbmdrYWlhbiBrYXJha3RlciBkZW5nYW4gYHN0cl9kZXRlY3QoKWAKCkZ1bmdzaSBgc3RyX2RldGVjdCgpYCBtZW5naGFzaWxrYW4gbHVhcmFuIGxvZ2lzIGBUUlVFYCBkYW4gYEZBTFNFYCB5YW5nIG1lbnlhdGFrYW4gYXBha2FoIHJhbmdrYWlhbiBrYXJha3RlciB5YW5nIGtpdGEgY2FyaSBkaXRlbXVrYW4gKGBUUlVFYCkgYXRhdSB0aWRhayAoYEZBTFNFYCkgcGFkYSBzdWF0dSB2ZWt0b3IgdGVrcy9rYXJha3Rlci4KCmBgYHtyIGRldGVrc2ktcG9sYS1wZW5jYXJpYW59CiMgYnVhdCA1MCBzYW1wZWwga2FsaW1hdCBzZWRlcmhhbmEKZW5nX3NlbnRlbmNlX2FsbF9zYW1wbGUgPC0gc2FtcGxlKHggPSBlbmdfc2VudGVuY2VfYWxsLCBzaXplID0gNTApCgojIGFwYWthaCByYW5na2FpYW4ga2FyYWt0ZXIgImVkIiBkaXRlbXVrYW4gZGFsYW0gYGVuZ19zZW50ZW5jZV9hbGxfc2FtcGxlYD8Kc3RyX2RldGVjdChzdHJpbmcgPSBlbmdfc2VudGVuY2VfYWxsX3NhbXBsZSwgcGF0dGVybiA9ICJlZCIpCmBgYAoKIyMjIExhdGloYW4gey51bm51bWJlcmVkfQoKMS4gIEd1bmFrYW4gYHN0cl92aWV3X2FsbCgpYCB1bnR1ayBtZW5hbXBpbGthbiByYW5na2FpYW4ga2FyYWt0ZXIgYCJlZCJgIHBhZGEgdmVrdG9yIHRla3MgYGVuZ19zZW50ZW5jZV9hbGxfc2FtcGxlYC4KMi4gIEFwYWthaCByYW5na2FpYW4ga2FyYWt0ZXIga29uc29uYW4gYCJjayJgIGRpdGVtdWthbiBkYWxhbSBuYW1hLW5hbWEgYnVhaCBwYWRhIHZla3RvciB0ZWtzIGBmcnVpdHNgPwogICAgLSAgIEppa2EgeWEsIGd1bmFrYW4gYHN0cl92aWV3X2FsbCgpYCB1bnR1ayBtZW5hbXBpbGthbiBuYW1hIGJ1YWggYXBhIHlhbmcgbWVuZ2FuZHVuZyByYW5na2FpYW4ga2FyYWt0ZXIga29uc29uYW4gYCJjayJgIHBhZGEgdmVrdG9yIHRla3MgYGZydWl0c2AuCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCkZ1bmdzaSBgc3RyX2RldGVjdCgpYCBqdWdhIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW55YXJpbmcgb2JzZXJ2YXNpIHlhbmcgZGlpbmdpbmthbiBkYWxhbSB0YWJlbCAoKmRhdGEgZnJhbWUqKSBiZXJkYXNhcmthbiByYW5na2FpYW4ga2FyYWt0ZXIgdGVydGVudHUuIEluaSBkaW11bmdraW5rYW4ga2FyZW5hIGx1YXJhbiBgc3RyX2RldGVjdCgpYCBiZXJ1cGEgc3RydWt0dXIgbG9naXMgYFRSVUVgIGRhbiBgRkFMU0VgIHlhbmcgbWVuamFkaSBsYW5kYXNhbiBkYWxhbSBtZW55YXJpbmcgb2JzZXJ2YXNpLCBzYWxhaCBzYXR1bnlhIGRhbGFtIHRhYmVsLgoKYGBge3IgbXVhdC1kYXRhLXRhYmVsfQojIG11YXQgZGF0YSB0YWJlbCBoYW55YSBrb2xvbSA0IC0gNwp2ZXJic19pZG4gPC0gcmVhZC50YWJsZShmaWxlID0gImRhdGEvdmVyYl9zZW1hbnRpY3MudHh0IiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIlx0IilbNDo3XQoKIyBsaWhhdCBlbmFtIGJhcmlzIHBlcnRhbWEKaGVhZCh2ZXJic19pZG4pCmBgYAoKS29kZSBiZXJpa3V0IG1lbnlhcmluZyBvYnNlcnZhc2kgKGBzdWJzZXQoKWApIGRhbGFtIHRhYmVsIGRhdGEgYHZlcmJzX2lkbmAgYmVyZGFzYXJrYW4gYXBha2FoIGtvbG9tIGBleGFtcGxlX3RhcmdldGAgbWVuZ2FuZHVuZyB0ZWtzICh5YWl0dSBrYXRhIGtlcmphICpiZXItKikgZGVuZ2FuIHJhbmdrYWlhbiBrYXJha3RlciBgImRhImAgW2xpaGF0IEBwcmltYWhhZGlfbWV0b255bXlfMjAxMyB1bnR1ayBtYWthbGFoIHlhbmcgZGlsYW5kYXNpIGF0YXMgZGF0YSB0YWJlbCB0ZXJzZWJ1dF0uCgpgYGB7ciBzYXJpbmctb2JzZXJ2YXNpfQpzdWJzZXQodmVyYnNfaWRuLCBzdHJfZGV0ZWN0KHN0cmluZyA9IGV4YW1wbGVfdGFyZ2V0LCBwYXR0ZXJuID0gImRhIikpCmBgYAoKIyMjIExhdGloYW4gey51bm51bWJlcmVkfQoKMS4gIFViYWgga29kZSBzZWJlbHVtbnlhIHVudHVrIG1lbnlhcmluZy9tZW5kZXRla3NpIGthdGEta2F0YSBkYWxhbSBrb2xvbSAqKmBleGFtcGxlX3NvdXJjZWAqKiB5YW5nIG1lbmdhbmR1bmcgcmFuZ2thaWFuIGthcmFrdGVyIGAiYXIiYC4KCiMjIE1lbnlhcmluZyBlbGVtZW4gdmVrdG9yIHRla3MgeWFuZyBtZW5nYW5kdW5nIHJhbmdrYWlhbiBrYXJha3RlciB0ZXJ0ZW50dSBkZW5nYW4gYHN0cl9zdWJzZXQoKWAKCkJlcmJlZGEgZGVuZ2FuIGBzdHJfZGV0ZWN0KClgLCB5YW5nIG1lbmdlbHVhcmthbiBgVFJVRWAgZGFuIGBGQUxTRWAsIGBzdHJfc3Vic2V0KClgIChpKSBtZW5kZXRla3NpICpkYW4qIChpaSkgbWVuZ2VsdWFya2FuIGVsZW1lbiBkYWxhbSB2ZWt0b3IgdGVrcyB5YW5nIG1lbmdhbmR1bmcgcmFuZ2thaWFuIGthcmFrdGVyIHlhbmcgZGljYXJpLgoKYGBge3Igc2FyaW5nLWthbGltYXQtZGVuZ2FuLWthcmFrdGVyLWluZ30Kc3RyX3N1YnNldChzdHJpbmcgPSBlbmdfc2VudGVuY2VfYWxsX3NhbXBsZSwgcGF0dGVybiA9ICJpbmciKQpgYGAKVGVudHUga2l0YSBiaXNhIHNpbXBhbiBoYXNpbCBwZW55YXJpbmdhbiBpbmkga2UgdmVrdG9yIGxhaW4uCgpgYGB7ciBzYXJpbmcta2FsaW1hdC1kZW5nYW4ta2FyYWt0ZXItaW5nLXNpbXBhbn0KIyBzaW1wYW4gbHVhcmFuIGtvZGUgYmVyaWt1dCBrZSB2ZWt0b3IgYGluZ19vdXRwdXRgCmluZ19vdXRwdXQgPC0gc3RyX3N1YnNldChzdHJpbmcgPSBlbmdfc2VudGVuY2VfYWxsX3NhbXBsZSwgcGF0dGVybiA9ICJpbmciKQppbmdfb3V0cHV0CmBgYAoKCiMjIyBMYXRpaGFuIHsudW5udW1iZXJlZH0KCjEuIEJ1YWggYXBhIHlhbmcgbmFtYW55YSBtZW5nYW5kdW5nIGthcmFrdGVyIGAiY2siYD8gR3VuYWthbiBgc3RyX3N1YnNldCgpYCBwYWRhIHZla3RvciB0ZWtzIGBmcnVpdHNgIHVudHVrIG1lbmphd2FiIHBlcnRhbnlhYW4gaW5pLgoxLiBHdW5ha2FuIGBzdHJfc3Vic2V0KClgIHVudHVrIG1lbnlhcmluZyBrYWxpbWF0IGRhbGFtIHZla3RvciBgZW5nX3NlbnRlbmNlX2FsbGAgeWFuZyBtZW5nYW5kdW5nIHJhbmdrYWlhbiBrYXJha3RlciBgIndobyJgLiBBcGFrYWggcG9sYSBwZW5jYXJpYW4gYCJ3aG8iYCBpbmkgbWVuZ2VsdWFya2FuIGthbGltYXQgeWFuZyBtZW5nYW5kdW5nIGthdGEgKndobyogJ3NpYXBhJyBkYWxhbSBiYWhhc2EgSW5nZ3Jpcz8KCi0tLS0tLS0tLQoKPHAgY2xhc3M9ImNvbW1lbnQiPioqQ2F0YXRhbiB0ZW50YW5nIF9yZWd1bGFyIGV4cHJlc3Npb25zXyoqPGJyPjxici8+PGk+W1JlZ3VsYXIgZXhwcmVzc2lvbnNdKGh0dHBzOi8vd3d3LnJlZ3VsYXItZXhwcmVzc2lvbnMuaW5mby90dXRvcmlhbC5odG1sKTwvaT4gKFJlZ0V4KSBhZGFsYWggcG9sYSBwZW5jYXJpYW4ga2FyYWt0ZXIgeWFuZyBsZWJpaCBjYW5nZ2loIGRhbiBmbGVrc2liZWwgeWFuZyBwZXJsdSBkaXBlbGFqYXJpIHVudHVrIHBlbmdvbGFoYW4gZGFuIG1hbmlwdWxhc2kgdGVrcyB0aW5na2F0IGxhbmp1dCBbbGloYXQgQHdpY2toYW1fcl8yMDE3LCBzdWItYmFnaWFuIDE0LjMgdW50dWsgdWxhc2FuIGxlYmloIHJpbmNpXS48YnIvPjxici8+IFNhbGFoIHNhdHUgamVuaXMgUmVHZXggeWFuZyBwZW50aW5nIGRpa2V0YWh1aSBhZGFsYWggKipwZXdhdGFzIHJhbmdrYWlhbiBrYXJha3RlciB5YW5nIG1lbmNlcm1pbmthbiBrYXRhKiogKCp3b3JkIGJvdW5kYXJ5KikgKGAiXFxiImApLiBVbnR1ayBrYXN1cyBwZW5jYXJpYW4gcmFuZ2thaWFuIGthcmFrdGVyIGAid2hvImAgc2ViZWx1bW55YSwga2l0YSBtZWxha3VrYW4gcGVuY2FyaWFuIGRlbmdhbiByYW5na2FpYW4ga2FyYWt0ZXIgdGFucGEgUmVnRXgga2FyZW5hIGtpdGEgdGlkYWsgbWVtcGVyaW5jaSBiYWh3YSBrYXJha3RlciBgIndobyJgIHlhbmcga2l0YSBpbmdpbmthbiBhZGFsYWgga2F0YSBfd2hvXyBidWthbm55YSByYW5na2FpYW4ga2FyYWt0ZXIgYCJ3aG8iYCB5YW5nIGJpc2EgbXVuY3VsIGRhbGFtIGthdGEgXyoqd2hvKipsZV8sIF8qKndobyoqZXZlcl8sIGRsbC4gVW50dWsgaXR1LCBwb2xhIHBlbmNhcmlhbiBraXRhIHVudHVrICJrYXRhIiBfd2hvXyAoYnVrYW4gcmFuZ2thaWFuIGthcmFrdGVyIGAid2hvImApIGhhcnVzbGFoIGxlYmloIHNwZXNpZmlrIGRhbiBrYXJha3RlciBSZWdFeCBwZXdhdGFzIGthdGEgKGAiXFxiImApIGRhcGF0IG1lbWJhbnR1IGRhbGFtIGhhbCBpbmksIHlhaXR1IGAiXFxid2hvXFxiImAuPC9wPgoKQmFuZGluZ2thbiBsdWFyYW4ga2VkdWEgYmFyaXMga29kZSBiZXJpa3V0IHVudHVrIHBvbGEgcGVuY2FyaWFuIGRlbmdhbiBkYW4gdGFucGEgUmVnRXggcGV3YXRhcyBrYXRhIChgIlxcYiJgKToKCmBgYHtyIGxpdGVyYWwtc2VhcmNofQojIHRhbnBhIHJlZ2V4IHBld2F0YXMga2F0YSAiXFxiIiBkaSBrZWR1YSBzaXNpIGthcmFrdGVyIHlhbmcgZGljYXJpCnN0cl9zdWJzZXQoc3RyaW5nID0gZW5nX3NlbnRlbmNlX2FsbCwgcGF0dGVybiA9ICJ3aG8iKSAKCiMgdGFucGEgcmVnZXggcGV3YXRhcyBrYXRhICJcXGIiIGRpIGtlZHVhIHNpc2kga2FyYWt0ZXIgeWFuZyBkaWNhcmkKc3RyX3ZpZXdfYWxsKHN0cmluZyA9IGVuZ19zZW50ZW5jZV9hbGwsIHBhdHRlcm4gPSAid2hvIiwgbWF0Y2ggPSBUUlVFKQpgYGAKYGBge3Igd29yZC1ib3VuZGFyeS1zZWFyY2h9CiMgZGVuZ2FuIHJlZ2V4IHBld2F0YXMga2F0YSAiXFxiIiBkaSBrZWR1YSBzaXNpIGthcmFrdGVyIHlhbmcgZGljYXJpCnN0cl9zdWJzZXQoc3RyaW5nID0gZW5nX3NlbnRlbmNlX2FsbCwgcGF0dGVybiA9ICJcXGJ3aG9cXGIiKSAKCiMgZGVuZ2FuIHJlZ2V4IHBld2F0YXMga2F0YSAiXFxiIiBkaSBrZWR1YSBzaXNpIGthcmFrdGVyIHlhbmcgZGljYXJpCnN0cl92aWV3X2FsbChzdHJpbmcgPSBlbmdfc2VudGVuY2VfYWxsLCBwYXR0ZXJuID0gIlxcYndob1xcYiIsIG1hdGNoID0gVFJVRSkKYGBgCgoKIyMjIExhdGloYW4gey19CgoxLiBHdW5ha2FuIFJlZ0V4IHBld2F0YXMga2F0YSAoYCJcXGIiYCkgZGVuZ2FuIGBzdHJfc3Vic2V0KClgIHVudHVrIG1lbnlhcmluZyBrYWxpbWF0IGRhbGFtIHZla3RvciBgZW5nX3NlbnRlbmNlX2FsbGAgeWFuZyBtZW5nYW5kdW5nIGthdGEta2F0YSB5YW5nICoqZGlha2hpcmkqKiBkZW5nYW4gcmFuZ2thaWFuIGthcmFrdGVyIGAiaW5nImAgKG1pc2FsbnlhLCBrYXRhLWthdGEgc2VwZXJ0aSBfdGV4dCoqaW5nKipfLCBfbGl2KippbmcqKl8sIF9yKippbmcqKl8sIF9zcHIqKmluZyoqXywgZGxsLikKMS4gR3VuYWthbiBgc3RyX3N1YnNldCgpYCBkYW4gcG9sYSBwZW5jYXJpYW4gZGVuZ2FuIFJlZ0V4IHBld2F0YXMga2F0YSAoYCJcXGIiYCkgdW50dWsgbWVuZ2VsdWFya2FuIGthdGEta2F0YSB5YW5nICoqZGlhd2FsaSoqIGRlbmdhbiBrYXJha3RlciBgImNoImAgKG1pc2FsbnlhIF8qKmNoKiphbmNlXywgXyoqY2gqKmFwXywgZGxsLikgZGFsYW0gdmVrdG9yIHRla3MgYHdvcmRzYC4KCi0tLS0tLQoKPHAgY2xhc3M9ImNvbW1lbnQiPioqQ2F0YXRhbiB0ZW50YW5nIF9yZWd1bGFyIGV4cHJlc3Npb25zXyoqPGJyPjxici8+U2VsYWluIHBld2F0YXMgcmFuZ2thaWFuIGthcmFrdGVyIGJlcnVwYSBrYXRhLCB0ZXJkYXBhdCBkdWEgbGFnaSBSZUdleCBwZXdhdGFzIHJhbmdrYWlhbiBrYXJha3RlciB5YW5nIHBlbnRpbmcgZGlrZXRhaHVpLCB5YWl0dSAqKnBld2F0YXMgcmFuZ2thaWFuIGthcmFrdGVyKiogc2VjYXJhIHVtdW0gKCphbmNob3IgY2hhcmFjdGVyKik6IChpKSBwZXdhdGFzICoqcG9zaXNpIGF3YWwqKiByYW5na2FpYW4ga2FyYWt0ZXIgKGAiXiJgKSBkYW4gKGlpKSBwZXdhdGFzICoqcG9zaXNpIGFraGlyKiogcmFuZ2thaWFuIGthcmFrdGVyIChgIiQiYCkuPC9wPiAKClBlcmhhdGlrYW4ga29kZSBiZXJpa3V0IHNlYmFnYWkgY29udG9oIHBlbmdndW5hYW4gUmVnRXggcGV3YXRhcyBhd2FsIGRhbiBha2hpciByYW5na2FpYW4ga2FyYWt0ZXIgW2Rpa3V0aXAgZGFyaSBAd2lja2hhbV9yXzIwMTcsIDIwMl06CgpgYGB7ciBlbmQtb2Ytc3RyaW5nfQojIGJ1YXQgZGF0YSBzZWRlcmhhbmEKZnJ1aXRfbWluaSA8LSBjKCJhcHBsZSIsICJiYW5hbmEiLCAicGVhciIpCgojIG1lbmFuZ2thcCBrYXJha3RlciBgImEiYCB5YW5nIG11bmN1bCBkaSBha2hpciAoYCIkImApIHJhbmdrYWlhbiBrYXJha3RlciBuYW1hIGJ1YWggcGFkYSB2ZWt0b3IgYGZydWl0X21pbmlgCnN0cl92aWV3X2FsbChzdHJpbmcgPSBmcnVpdF9taW5pLCBwYXR0ZXJuID0gImEkIikKc3RyX3N1YnNldChzdHJpbmcgPSBmcnVpdF9taW5pLCBwYXR0ZXJuID0gImEkIikKYGBgCgoKYGBge3IgYmVnaW5uaW5nLW9mLXN0cmluZ30KIyBtZW5hbmdrYXAga2FyYWt0ZXIgYCJhImAgeWFuZyBtdW5jdWwgZGkgYWtoaXIgKGAiJCJgKSByYW5na2FpYW4ga2FyYWt0ZXIgbmFtYSBidWFoIHBhZGEgdmVrdG9yIGBmcnVpdF9taW5pYApzdHJfdmlld19hbGwoc3RyaW5nID0gZnJ1aXRfbWluaSwgcGF0dGVybiA9ICJeYSIpCnN0cl9zdWJzZXQoc3RyaW5nID0gZnJ1aXRfbWluaSwgcGF0dGVybiA9ICJeYSIpCmBgYAoKS2l0YSBiaXNhIG1lbmdnYWJ1bmdrYW4gYCJeImAgZGFuIGAiJCJgIHVudHVrIG1lbXBlcnRlZ2FzIGJhaHdhIGtpdGEgaGFueWEgaW5naW4gbWVuYW5na2FwIHJhbmdrYWlhbiBrYXJha3RlciBzZWNhcmEgdXR1aC4gQmFuZGluZ2thbiBrZWR1YSBrb2RlIGJlcmlrdXQgW2Rpa3V0aXAgZGFyaSBAd2lja2hhbV9yXzIwMTcsIDIwMl06CgpgYGB7ciBwYXJ0aWFsLW1hdGNofQojIGJ1YXQgZGF0YSBsYWluCmZydWl0X2Nha2UgPC0gYygiYXBwbGUgcGllIiwgImFwcGxlIiwgImFwcGxlIGNha2UiKQoKIyBwZW5jYXJpYW4gc2VkZXJoYW5hICh0YW5wYSBSZWdFeCkgdW50dWsgbWVuYW5na2FwIHJhbmdrYWlhbiBrYXJha3RlciBgImFwcGxlImAKc3RyX3ZpZXdfYWxsKHN0cmluZyA9IGZydWl0X2Nha2UsIHBhdHRlcm4gPSAiYXBwbGUiKQpzdHJfc3Vic2V0KHN0cmluZyA9IGZydWl0X2Nha2UsIHBhdHRlcm4gPSAiYXBwbGUiKQpgYGAKCmBgYHtyIGNvbXBsZXRlLW1hdGNofQojIG1lbmFuZ2thcCBoYW55YSByYW5na2FpYW4ga2FyYWt0ZXIgdXR1aCBkYXJpIGF3YWwgaGluZ2dhIGFraGlyIHJhbmdrYWlhbiBrYXJha3RlcgpzdHJfdmlld19hbGwoc3RyaW5nID0gZnJ1aXRfY2FrZSwgcGF0dGVybiA9ICJeYXBwbGUkIikKc3RyX3N1YnNldChzdHJpbmcgPSBmcnVpdF9jYWtlLCBwYXR0ZXJuID0gIl5hcHBsZSQiKQpgYGAKCiMjIyBMYXRpaGFuIHstfQoKMS4gQnVhaCBhcGEgc2FqYSB5YW5nIG5hbWFueWEgKipkaWF3YWxpKiogZGVuZ2FuIGthcmFrdGVyIGtvbnNvbmFuIGAiYiJgPyBHdW5ha2FuIGBzdHJfc3Vic2V0KClgIHVudHVrIG1lbmdlbHVhcmthbiBkYXJpIHZla3RvciBgZnJ1aXRzYCBuYW1hLW5hbWEgYnVhaCB5YW5nIGRpYXdhbGkgZGVuZ2FuIGthcmFrdGVyIGAiYiJgLgoKMS4gQWRhIGJlcmFwYSBidWFoIHlhbmcgbmFtYW55YSAqKmJlcmFraGlyKiogZGVuZ2FuIGthcmFrdGVyIHZva2FsIGAibyJgPyBHdW5ha2FuIGBzdHJfc3Vic2V0KClgIHVudHVrIG1lbmdlbHVhcmthbiBkYXJpIHZla3RvciBgZnJ1aXRzYCBuYW1hLW5hbWEgYnVhaCB5YW5nIGRpYXdhbGkgZGVuZ2FuIGthcmFrdGVyIGAibyJgLgoKCjxwIGNsYXNzPSJjb21tZW50Ij4qKlRpcHMqKjxicj48YnIvPmBzdHJpbmdyYCBqdWdhIG1lbWlsaWtpIGR1YSBmdW5nc2kga2h1c3VzIHVudHVrIG1lbmRldGVrc2kga2ViZXJhZGFhbiAocmFuZ2thaWFuKSBrYXJha3RlciB5YW5nIG11bmN1bCAoaSkgKipkaSBhd2FsKiogcmFuZ2thaWFuIGthcmFrdGVyLCB5YWl0dSBmdW5nc2kgW2BzdHJfc3RhcnRzKClgXShodHRwczovL3N0cmluZ3IudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2Uvc3RyX3N0YXJ0cy5odG1sKSwgZGFuIChpaSkgKipkaSBha2hpcioqIHJhbmdrYWlhbiBrYXJha3RlciwgeWFpdHUgZnVuZ3NpIFtgc3RyX2VuZHMoKWBdKGh0dHBzOi8vc3RyaW5nci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9zdHJfc3RhcnRzLmh0bWwpLiBMYXlha255YSBgc3RyX2RldGVjdCgpYCwga2VkdWEgZnVuZ3NpIGluaSBtZW5nZWx1YXJrYW4gdmVrdG9yIGxvZ2lzIGBUUlVFYCBkYW4gYEZBTFNFYC48YnIvPjxici8+TWlzYWxueWEsIGBzdHJfc3RhcnRzKGZydWl0X21pbmksICJwIilgIGFrYW4gbWVuZGV0ZWtzaSBhZGFrYWggZWxlbWVuIHRla3MgZGFsYW0gdmVrdG9yIGBmcnVpdF9taW5pYCB5YW5nIGRpYXdhbGkgZGVuZ2FuIGthcmFrdGVyIGAicCJgLCB0YW5wYSBwZXJsdSBtZW5nZ3VuYWthbiBSZWdFeCBwZXdhdGFzIGthcmFrdGVyIGF3YWwgYCJeImAuIFNlYmFsaWtueWEsIGBzdHJfZW5kcyhmcnVpdF9taW5pLCAicCIpYCBha2FuIG1lbmRldGVrc2kga2ViZXJhZGFhbiB0ZWtzIGRhbGFtIGBmcnVpdF9taW5pYCB5YW5nIGRpYWtoaXJpIGRlbmdhbiBrYXJha3RlciBgInAiYCwgdGFucGEgcGVybHUgbWVuZ2d1bmFrYW4gUmVnRXggcGV3YXRhcyBrYXJha3RlciBha2hpciBgIiQiYC48YnIvPjxici8+UmVnRXggdGV0YXAgZGlwZXJsdWthbiBqaWthIG1lbmdndW5ha2FuIGZ1bmdzaSBgc3RyX3N1YnNldCgpYCB1bnR1ayBtZW55YXJpbmcgdGVrcyB5YW5nIGRpYXdhbGkgYXRhdSBkaWFraGlyaSBkZW5nYW4gKHJhbmdrYWlhbikga2FyYWt0ZXIgdGVydGVudHUuPC9wPgoKLS0tLS0tCgojIE1lbmdlbHVhcmthbiAoKmV4dHJhY3QqKSBwb2xhIGthcmFrdGVyIGRhcmkgZGFsYW0gdGVrcwoKRnVuZ3NpIGBzdHJfZXh0cmFjdF9hbGwoKWAgZGlndW5ha2FuIHVudHVrICJtZW5nZWx1YXJrYW4iICgqZXh0cmFjdCopIHBvbGEgeWFuZyBkaXRhbmdrYXAgZGFyaSBwZW5jYXJpYW4ga2FyYWt0ZXIgeWFuZyBraXRhIHJhbmNhbmcuIFNlYmFnYWkgY29udG9oLCB2ZWt0b3Iga2FsaW1hdCBgZW5nX3NlbnRlbmNlX2FsbGAgdGVyZGFwYXQgc2VqdW1sYWggbmFtYS1uYW1hIHdhcm5hIGJhaGFzYSBJbmdncmlzIGRhbiBraXRhIGhhbnlhIGluZ2luIG1lbmdlbHVhcmthbiBrYXRhLWthdGEgeWFuZyBtZW5jZXJtaW5rYW4gbmFtYSB3YXJuYSB0ZXJzZWJ1dCAodGlkYWsga2F0YS1rYXRhIGxhaW5ueWEgZGFsYW0ga2FsaW1hdCkuIEtpdGEgbWVtZXJsdWthbiBrYXJha3RlciBSZWdFeCBiZXJuYW1hICJhbHRlcm5hdGlmIiAoYHxgKSB5YW5nIGJlcmFydGkgJ2F0YXUnLiBKaWthIGtpdGEgaW5naW4gbWVuY2FyaSB3YXJuYSBgIngiYCAqKmF0YXUqKiBgInkiYCAqKmF0YXUqKiBgInoiYCwgbWFrYSBwb2xhIHBlbmNhcmlhbiBraXRhIGFkYWxhaCBgIih4fHl8eikiYC4KClBlcnRhbWEga2l0YSByYW1waW5na2FuIGRhdGEga2FsaW1hdCBgZW5nX3NlbnRlbmNlX2FsbGAgZGVuZ2FuIG1lbnlhcmluZyBoYW55YSBrYWxpbWF0LWthbGltYXQgeWFuZyBtZW5nYW5kdW5nIG5hbWEtbmFtYSB3YXJuYS4KCmBgYHtyIGVrc3RyYWtzaXBlcnRhbWF9CiMgYnVhdCB2ZWt0b3Iga2FyYWt0ZXIgdW50dWsgcmVnZXggcGVuY2FyaWFuIGRlbmdhbiB0ZWtuaWsgImFsdGVybmF0aWYiCmNvbG91cl9wYXR0ZXJuIDwtICIoYmx1ZXxvcmFuZ2V8eWVsbG93fGdyZWVufHB1cnBsZSkiIAoKIyBkZXRla3NpIGRhbiBzYXJpbmcgdGVybGViaWggZGFodWx1IGhhbnlhIGthbGltYXQgeWFuZyBiZXJpc2kgbmFtYS1uYW1hIHdhcm5hICJiaXJ1IiwgIm9yYW55ZSIsICJrdW5pbmciLCAiaGlqYXUiLCBkYW4gInVuZ3UiLgpzZW50X2NvbG91ciA8LSBzdHJfc3Vic2V0KHN0cmluZyA9IGVuZ19zZW50ZW5jZV9hbGwsIHBhdHRlcm4gPSBjb2xvdXJfcGF0dGVybikKCiMgY2FyaSB0YWh1IGJlcmFwYSBrYWxpbWF0IHlhbmcgbWVuZ2FuZHVuZyBuYW1hLW5hbWEgd2FybmEKbGVuZ3RoKHNlbnRfY29sb3VyKSAjIDIwIGthbGltYXQgbWVuZ2FuZHVuZyBuYW1hLW5hbWEgd2FybmEgdGVyc2VidXQKYGBgCgpCYXJ1IGtpdGEga2VsdWFya2FuIGthdGEta2F0YSBuYW1hIHdhcm5hIGRhcmkgdmVrdG9yIGthcmFrdGVyIGBzZW50X2NvbG91cmAgZGFuIHNpbXBhbiBsdWFyYW5ueWEga2UgdmVrdG9yIGthcmFrdGVyIGxhaW5ueWEgZGVuZ2FuIG5hbWEgYHdvcmRfY29sb3VyYC4KCmBgYHtyIGVrc3RyYWtzaWtlZHVhfQojIGtlbHVhcmthbiBuYW1hLW5hbWEgd2FybmEgZGFyaSB2ZWt0b3IgYHNlbnRfY29sb3VyYCBkYW4gc2ltcGFuIGtlIHZla3RvciBgd29yZF9jb2xvdXJgCndvcmRfY29sb3VyIDwtIHN0cl9leHRyYWN0X2FsbChzdHJpbmcgPSBzZW50X2NvbG91ciwgcGF0dGVybiA9IGNvbG91cl9wYXR0ZXJuKSAKCiMgbGloYXQgZW5hbSBlbGVtZW4gcGVydGFtYQpoZWFkKHdvcmRfY29sb3VyKSAjIGx1YXJhbiBiZXJ1cGEgTGlzdCBidWthbiBWZWt0b3Iga2FyYWt0ZXIgKGF0b21pcykKYGBgCgpgYGB7ciBla3N0cmFrc2lrZXRpZ2F9CndvcmRfY29sb3VyX3ZlY3RvciA8LSB1bmxpc3Qod29yZF9jb2xvdXIpICMgdW5saXN0IG1lbmphZGkgdmVrdG9yIGthcmFrdGVyCndvcmRfY29sb3VyX3ZlY3RvcgpgYGAKCkd1bmFrYW4gYHN0cl9zb3J0KClgIHVudHVrIG1lbmd1cnV0a2FuIGthcmFrdGVyIHNlY2FyYSBhbGZhYmV0aXMuCgpgYGB7ciBtZW55b3J0aXItdGVrcy1zZWNhcmEtYWxmYWJldGlzfQpzdHJfc29ydCh3b3JkX2NvbG91cl92ZWN0b3IpCmBgYAoKS2l0YSBiaXNhIGd1bmFrYW4gYHRhYmxlKClgIHVudHVrIG1lbnRhYnVsYXNpIGthcmFrdGVyIHZla3RvciBuYW1hIHdhcm5hIHVudHVrIG1lbmdldGFodWkgZGlzdHJpYnVzaS9mcmVrdWVuc2kga2VtdW5jdWxhbiB3YXJuYSB0ZXJzZWJ1dC4KCmBgYHtyIHRhYnVsYXNpLXdhcm5hfQp0YWJsZSh3b3JkX2NvbG91cl92ZWN0b3IpCmBgYAoKYGBge3Igc29ydGlyLXRhYnVsYXNpfQojIHNvcnRpciBuYW1hIHdhcm5hIGRhcmkgZnJla3VlbnNpIHRlcnRpbmdnaSBrZSB0ZXJlbmRhaAp3b3JkX2NvbG91cl9jb3VudCA8LSB0YWJsZSh3b3JkX2NvbG91cl92ZWN0b3IpCndvcmRfY29sb3VyX2NvdW50IDwtIHNvcnQod29yZF9jb2xvdXJfY291bnQsIGRlY3JlYXNpbmcgPSBUUlVFKQp3b3JkX2NvbG91cl9jb3VudApgYGAKCiMgTWVtZWNhaCB0ZWtzIG1lbmphZGkgdW5pdCB5YW5nIGxlYmloIGtlY2lsCgpGdW5nc2kgYHN0cl9zcGxpdCgpYCBkaWd1bmFrYW4gdW50dWsgbWVtZWNhaCB0ZWtzIGJlcmRhc2Fya2FuIHBhZGEga2FyYWt0ZXIgbWFuYSB0ZWtzIHRlcnNlYnV0IGRpcGVjYWguIENvbnRvaCBwYWxpbmcgc2VkZXJoYW5hIGFkYWxhaCBtZW1lY2FoIGthbGltYXQgbWVuamFkaSBrYXRhIGRlbmdhbiBtZW1lY2FobnlhIHBhZGEga2FyYWt0ZXIgc3Bhc2kgKHlhbmcgbWVydXBha2FuIHBlbWlzYWgga2F0YSB1bnR1ayBrYXJha3RlciBSb21hbiB5YW5nIGRpcGFoYW1pIG9sZWgga29tcHV0ZXIpLgoKYGBge3IgcGVjYWgtdGVrc30KIyBjb250b2ggc2VkZXJoYW5hIHBlbWVjYWhhbiBrYWxpbWF0IC0+IGthdGEgZGVuZ2FuIGR1YSBrYWxpbWF0IAp0d29fc2VudGVuY2VzIDwtIGVuZ19zZW50ZW5jZV9hbGxfc2FtcGxlWzE6Ml0KCiMgcGVjYWggdGVrcyBwYWRhIGthcmFrdGVyIHNwYXNpIGAiICJgLgpzdHJfc3BsaXQodHdvX3NlbnRlbmNlcywgcGF0dGVybiA9ICIgIikgIyBsdWFyYW5ueWEgYWRhbGFoIExpc3QKYGBgCgpJc3VueWEgYWRhbGFoIHRhbmRhIGJhY2Egc2VwZXJ0aSB0aXRpayAoYC5gKSBtYXNpaCBtZW5lbXBlbCBwYWRhIGthdGEgeWFuZyBtZW5nYWtoaXJpIGthbGltYXQuIFBhZGEgc2l0dWFzaSBpbmlsYWgga2VrdWF0YW4gZGFyaSBSZWdFeCBtZW5qYWRpIHBlbnRpbmcuCgpLaXRhIHBlcmx1IG1lcmFuY2FuZyBwb2xhIHBlbmNhcmlhbiBSZWdFeCB5YW5nIG1lbnlhdGFrYW4gYmFod2Ega2l0YSBpbmdpbiBtZW1pc2Foa2FuL21lbWVjYWggdGVrcyBwYWRhIGtlbG9tcG9rIGthcmFrdGVyICoqc2VsYWluKioga2Vsb21wb2sga2FyYWt0ZXIgcGVtYmVudHVrIGthdGEsIHlhaXR1IGtlbG9tcG9rIGthcmFrdGVyICoqZGkgbHVhcioqIGthcmFrdGVyIGFsZmFudW1lcmlzIGRhbiBzdHJpcCBgIi0iYC4gRGFsYW0ga29udGVrcyBiYWhhc2EgSW5nZ3JpcywgYCItImAgZGlwZXJ0YWhhbmthbiB1bnR1ayBtZW5hbmdrYXAga2F0YSBzZXBlcnRpICpjb21wdXRlci1yZWFkYWJsZSogc2ViYWdhaSBzYXR1IHVuaXQsIGJ1a2FubnlhIG1lbmphZGkgZHVhIHVuaXQgKmNvbXB1dGVyKiBkYW4gKnJlYWRhYmxlKi4gCgpSZWdFeCB5YW5nIGJpc2EgZGlndW5ha2FuIGFkYWxhaCBgIlteYS16QS1aMC05LV0rImAsIHlhbmcgYXJ0aW55YTogc2F0dSBhdGF1IGxlYmloIChgIisiYCkga2Vsb21wb2sga2FyYWt0ZXIgKGAiWy4uLl0iYCkgeWFuZyBidWthbiAoYCJeImApIChpKSBhbGZhbnVtZXJpcyBrYXBpdGFsIGRhbiBrZWNpbCAoYCJhLXpBLVowLTkiYCkgZGFuIHN0cmlwIChgIi0iYCkuCgpgYGB7ciBwZWNhaC10ZWtzLXJlZ2V4fQojIHBlY2FoIHRla3MgcGFkYSBrYXJha3RlciBub24tYWxmYW51bWVyaXMgZGFuIHNwYXNpIGAiICJgLgpzdHJfc3BsaXQodHdvX3NlbnRlbmNlcywgcGF0dGVybiA9ICJbXmEtekEtWjAtOS1dKyIpCmBgYAoKVGVudHUgbHVhcmFuIExpc3QgaW5pIGJpc2Ega2l0YSB1YmFoIG1lbmphZGkgdmVrdG9yIGF0b21pczoKCmBgYHtyIHVubGlzdC1sdWFyYW4tc3RyLXNwbGl0fQpzcGxpdF9zZW50ZW5jZSA8LSBzdHJfc3BsaXQodHdvX3NlbnRlbmNlcywgcGF0dGVybiA9ICJbXmEtekEtWjAtOS1dKyIpCnVubGlzdChzcGxpdF9zZW50ZW5jZSkKYGBgCgpQZW1lY2FoYW4gdGVrcyBkYXJpIGthbGltYXQgbWVuamFkaSBrYXRhIGluaSBkYXBhdCBkaWxpaGF0IGRhcmkgZHVhIHBlcnNwZWt0aWY6CgppLiAqKm1lbWVjYWgqKiAoeWFpdHUgKiptZW1pc2Foa2FuKiogZGVuZ2FuICoqbWVuZ2hpbGFuZ2thbioqKSBrYXJha3RlciAqKnNlbGFpbioqIGFsZmFudW1lcmlzIGRhbiBzdHJpcCwgbWVuZ2d1bmFrYW4gYHN0cl9zcGxpdCgpYCwgYXRhdQoKaS4gKiptZW5hcmlrKiogKHlhaXR1ICoqbWVuZ2VsdWFya2FuKiovKiptZW5nZWtzdHJha3NpKiopIGthcmFrdGVyIHlhbmcgbWVtYmFuZ3VuIHN1YXR1IGthdGEsIHlhaXR1IGthcmFrdGVyIGFsZmFudW1lcmlzIGRhbiBzdHJpcCwgbWVuZ2d1bmFrYW4gYHN0cl9leHRyYWN0X2FsbCgpYC4KCkppa2Ega2l0YSBtZW5nYW1iaWwgcGVyc3Bla3RpZiBrZWR1YSAoZGVuZ2FuIGBzdHJfZXh0cmFjdF9hbGwoKWApLCBtYWthIFJlZ0V4IHlhbmcgZGlndW5ha2FuIHNlZGlraXQgYmVyYmVkYSwgeWFpdHUgZGVuZ2FuIG1lbmdoaWxhbmdrYW4gdGFuZGEgbmVnYXNpICgnYnVrYW4nKSBgIl4iYCBkYWxhbSBSZWdFeC1ueWEuIFBlcmhhdGlrYW4ga29kZSBiZXJpa3V0IGRhbiBiYW5kaW5na2FuIGRlbmdhbiB0ZWxpdGkgbHVhcmFuIGBzdHJfZXh0cmFjdF9hbGwoKWAgZGVuZ2FuIGx1YXJhbiBgc3RyX3NwbGl0KClgIHNlYmVsdW1ueWEuCgpgYGB7ciBla3N0cmFrLWthdGF9CiMgcGVyc3Bla3RpZiBrZWR1YSBtZW1lY2FoIGthbGltYXQgbWVuamFkaSBrYXRhCiMgZGVuZ2FuICoqbWVuZ2tla3N0cmFrc2kqKiBrYXRhLWthdGEKc3RyX2V4dHJhY3RfYWxsKHR3b19zZW50ZW5jZXMsIHBhdHRlcm4gPSAiW2EtekEtWjAtOS1dKyIpCmBgYAoKWWFuZyBtZW1iZWRha2FuIGx1YXJhbiBgc3RyX3NwbGl0KClgIGRhbiBgc3RyX2V4dHJhY3RfYWxsKClgIGRpIGF0YXMsIGtodXN1c255YSBkYWxhbSBrb250ZWtzIG1lbWVjYWggdGVrcyBrYWxpbWF0IG1lbmphZGkga2F0YSBhZGFsYWg6CgppLiBsdWFyYW4gYHN0cl9zcGxpdCgpYCBtZW5hbmRhaSBwZW5naGlsYW5nYW4vcGVtZWNhaGFuIHRhbmRhIGJhY2EsIGRhbGFtIGhhbCBpbmkgdGl0aWssIGRlbmdhbiBrYXJha3RlciBrb3NvbmcgKGxpaGF0IGthcmFrdGVyIGAiImAgc2V0ZWxhaCBrYXRhIGAiZW5kcyJgIGRhbiBgImVub3VnaCJgKS4KCmkuIGx1YXJhbiBgc3RyX2V4dHJhY3RfYWxsKClgIGhhbnlhIGFrYW4gbWVuZ2VsdWFya2FuL21lbmdla3N0cmFrc2kga2FyYWt0ZXIgeWFuZyBkaW55YXRha2FuIGRhbGFtIHBvbGEgcGVuY2FyaWFubnlhLCB5YWl0dSBzYXR1IGF0YXUgbGViaWgga2FyYWt0ZXIgYWxmYW51bWVyaXMgZGFuIHN0cmlwOyB0aWRhayBhZGEga2FyYWt0ZXIga29zb25nIHlhbmcgbWVuY2VybWlua2FuIGRhbGFtIGhhbCBpbmkgdGFuZGEgdGl0aWsuCgpLaXRhIHlhbmcgbWVuZW50dWthbiBmdW5nc2kgZGFuIGx1YXJhbiBzZXBlcnRpIGFwYSB5YW5nIGRpaW5naW5rYW4uCgoKIyBNZW5ndWJhaCBrb21wb25lbiB0ZWtzCgojIyBNZW5ndWJhaCBrYXJha3RlciBtZW5qYWRpIGh1cnVmIGJlc2FyIGF0YXUga2VjaWwKCkZ1bmdzaSBgc3RyX3RvX3VwcGVyKClgIG1lbmd1YmFoIGthcmFrdGVyIG1lbmphZGkgaHVydWYga2FwaXRhbCBkYW4gYHN0cl90b19sb3dlcigpYCBtZW5qYWRpIGh1cnVmIGtlY2lsLgoKYGBge3IgdXBwZXItY2FzZX0KIyBtZW5ndWJhaCBuYW1hIHdhcm5hIHNlYmVsdW1ueWEgbWVuamFkaSBodXJ1ZiBrYXBpdGFsCndvcmRfY29sb3VyX2NhcHMgPC0gc3RyX3RvX3VwcGVyKHN0cmluZyA9IHdvcmRfY29sb3VyX3ZlY3RvcikKd29yZF9jb2xvdXJfY2FwcwpgYGAKCmBgYHtyIGxvd2VyLWNhc2V9CiMgbWVuZ3ViYWggbmFtYSB3YXJuYSBrYXBpdGFsIG1lbmphZGkgaHVydWYga2VjaWwKc3RyX3RvX2xvd2VyKHN0cmluZyA9IHdvcmRfY29sb3VyX2NhcHMpCmBgYAoKIyMjIExhdGloYW4gey19CgoxLiBMaWhhdCBpc2kgdmVrdG9yIGB0d29fc2VudGVuY2VzYCBwYWRhIGtvbnNvbCBkYW4gcGVyaGF0aWthbiBiZW50dWsgcmFuZ2thaWFuIGthcmFrdGVybnlhLiBLZW11ZGlhbiBqYWxhbmthbiBmdW5nc2kgYHN0cl90b190aXRsZSgpYCBkZW5nYW4gaW5wdXQgYHR3b19zZW50ZW5jZXNgLiBQZXJ1YmFoYW4gYXBhIHlhbmcgdGVyamFkaSBkYW4gYXBhIHlhbmcgZGlsYWt1a2FuIG9sZWggYHN0cl90b190aXRsZSgpYD8KCiMjIE1lbmdnYW50aSBrb21wb25lbiB0ZWtzIGRlbmdhbiBrYXJha3RlciBsYWluCgpUZXJrYWRhbmcga2l0YSBwZXJsdSBtZW5ndWJhaCBrb21wb25lbiB0ZWtzIHRlcnRlbnR1IGxheWFrbnlhIGZ1bmdzaSAqZmluZCBhbmQgcmVwbGFjZSogcGFkYSBwZXJhbnRpIHNlcGVydGkgTVMgV29yZC4gRGFsYW0gc3RyaW5nciwga2l0YSBiaXNhIG1lbmdndW5ha2FuIGBzdHJfcmVwbGFjZSgpYCBkYW4gYHN0cl9yZXBsYWNlX2FsbCgpYC4gCgpWYXJpYW4gZGFzYXIgKip0YW5wYSoqIGAuLi5fYWxsKClgLCB5YWl0dSBgc3RyX3JlcGxhY2UoKWAsIGhhbnlhIGFrYW4gbWVuZ2dhbnRpIGthcmFrdGVyIHlhbmcgKipwZXJ0YW1hIGthbGkqKiBkaXRhbmdrYXAgb2xlaCBwb2xhIHBlbmNhcmlhbm55YSwgc2VkYW5na2FuIGthcmFrdGVyIHlhbmcgc2FtYSB5YW5nIG11bmN1bCBzZXRlbGFobnlhIHRpZGFrIGFrYW4gZGl0YW5na2FwIGRhbiBkaWdhbnRpLgoKUGVyaGF0aWthbiBrb2RlIGJlcmlrdXQgeWFuZyBtZW5jb2JhIG1lbmdnYW50aSBrYXJha3RlciBgImUiYCBwYWRhIHZla3RvciBgZnJ1aXRfY2FrZWAuCgpgYGB7cn0KIyBsaWhhdCBrZW1iYWxpIHZla3RvciBgZnJ1aXRfY2FrZWAKZnJ1aXRfY2FrZQpgYGAKCgpgYGB7ciBtZW5nZ2FudGktc2VkZXJoYW5hfQojIGd1bmFrYW4gc3RyX3JlcGxhY2UoKSB1bnR1ayBtZW5nZ2FudGkga2FyYWt0ZXIgYCJlImAgeWFuZyBkaXRlbXVrYW4gcGVydGFtYSBkZW5nYW4gc3RyaXAgYCItImAKc3RyX3JlcGxhY2Uoc3RyaW5nID0gZnJ1aXRfY2FrZSwgcGF0dGVybiA9ICJlIiwgcmVwbGFjZW1lbnQgPSAiLSIpCmBgYAoKYGBge3IgbWVuZ2dhbnRpLXNlbXVhfQojIGd1bmFrYW4gc3RyX3JlcGxhY2VfYWxsKCkgdW50dWsgbWVuZ2dhbnRpIFNFTVVBIGthcmFrdGVyIGAiZSJgIGRlbmdhbiBzdHJpcCBgIi0iYApzdHJfcmVwbGFjZV9hbGwoc3RyaW5nID0gZnJ1aXRfY2FrZSwgcGF0dGVybiA9ICJlIiwgcmVwbGFjZW1lbnQgPSAiLSIpCmBgYAoKIyMjIExhdGloYW4gey19CgoxLiBHYW50aSByYW5na2FpYW4ga2FyYWt0ZXIgdW50dWsga2F0YSBgImFwcGxlImAgcGFkYSB2ZWt0b3IgYGZydWl0X2Nha2VgICh5YW5nIGJlcmlzaSBgImFwcGxlIHBpZSJgLCBgImFwcGxlImAsIGRhbiBgImFwcGxlIGNha2UiYCkgZGVuZ2FuIGthdGEgYCJidXR0ZXIiYC4KCgojIE1lbmdnYWJ1bmdrYW4gdmVrdG9yIHJhbmdrYWlhbiBrYXJha3RlcgoKVW50dWsgbWVuZ2dhYnVuZ2thbiBkdWEgYXRhdSBsZWJpaCByYW5na2FpYW4ga2FyYWt0ZXIsIGd1bmFrYW4gYHN0cl9jKClgLgoKYGBge3IgZ2FidW5nLXNlZGVyaGFuYX0KIyBtZW5nZ2FidW5na2FuIGR1YSByYW5na2FpYW4ga2FyYWt0ZXI6ICJiYSIgZGFuICJsaSIKc3RyX2MoImJhIiwgImxpIikKYGBgCgpgYGB7ciBnYWJ1bmctc2VkZXJoYW5hLTF9CmthcmFrdGVyXzEgPC0gYygiYiIsICJsIiwgImsiKQprYXJha3Rlcl8yIDwtIGMoImEiLCAiaSIsICJ1IikKCiMgZ2FidW5na2FuIHRpZ2Ega2FyYWt0ZXIgZGFyaSBkdWEgdmVrdG9yCnN0cl9jKGthcmFrdGVyXzEsIGthcmFrdGVyXzIpCmBgYAoKYGBge3IgZ2FidW5nLXNlZGVyaGFuYS0yfQojIGdhYnVuZ2thbiBkYW4gYXBpdCB0aWdhIGthcmFrdGVyIGRhbGFtIHNhdHUgdmVrdG9yIGRlbmdhbiBkdWEga2FyYWt0ZXIgbGFpbiB5YWl0dSAiPG0+IgpzdHJfYygiPG0+Iiwga2FyYWt0ZXJfMSwgIjxtPiIpCmBgYAoKSmlrYSBzYWxhaCBzYXR1IGRhcmkgZHVhIHZla3RvciBrYXJha3RlciB5YW5nIGFrYW4gZGlnYWJ1bmcgbWVtaWxpa2kganVtbGFoIGVsZW1lbiB5YW5nIGxlYmloIHNlZGlraXQsIG1ha2EgZWxlbWVuIHBhZGEgdmVrdG9yIHRlcnNlYnV0IGFrYW4gZGlndW5ha2FuIHVsYW5nLiBQZXJoYXRpa2FuIGNvbnRvaCBiZXJpa3V0LgoKYGBge3IgZ2FidW5nLWJlZGEtdWt1cmFufQp0d29fd29yZF9mcnVpdCA8LSBjKCJhcHBsZSIsICJiYW5hbmEiKQpmb3VyX3dvcmRfc25hY2sgPC0gYygiY2FrZSIsICJqdWljZSIsICJwaWUiLCAiY2hvY29sYXRlIikKCiMgZ2FidW5na2FuIGtlZHVhIHZla3RvciBkaSBhdGFzCnN0cl9jKHR3b193b3JkX2ZydWl0LCBmb3VyX3dvcmRfc25hY2ssIHNlcCA9ICJfIikKYGBgCgpHdW5ha2FuIGFyZ3VtZW4gYHNlcCA9IC4uLmAgdW50dWsgbWVuZ2F0dXIgcGVtaXNhaCBkaSBhbnRhcmEgcmFuZ2thaWFuIGthcmFrdGVyIHlhbmcgZGlnYWJ1bmdrYW4uIFNlY2FyYSBiYXdhYW4sIGFyZ3VtZW4gYHNlcCA9IC4uLmAgdGVsYWggZGlhdHVyIG1lbmphZGkgYHNlcCA9ICIiYC4KCmBgYHtyIGdhYnVuZy1zZXBhcmF0b3J9CiMgYXR1ciBwZW1pc2FoIGRpIGFudGFyYSBrYXJha3RlciB5YW5nIGRpZ2FidW5na2FuIGRlbmdhbiBgc2VwID0gLi4uYApzdHJfYyhrYXJha3Rlcl8xLCBrYXJha3Rlcl8yLCBzZXAgPSAiXyIpCmBgYAoKQXJndW1lbiBgY29sbGFwc2UgPSAuLi5gIGFrYW4gbWVueWF0dWthbiBzZWp1bWxhaCByYW5na2FpYW4ga2FyYWt0ZXIgbWVuamFkaSAqKnNhdHUqKiByYW5na2FpYW4ga2FyYWt0ZXIuIEJhbmRpbmdrYW4ga2VkdWEga29kZSBiZXJpa3V0IHlhbmcgbWVuZ2d1bmFrYW4gYHNlcCA9IC4uLmAgZGFuIGBjb2xsYXBzZSA9IC4uLmA6CgpgYGB7ciBzZXBhcmF0ZWQtY29tYmluYXRpb259CiMgZGVuZ2FuIHNlcCA9IC4uLiwgcGVuZ2dhYnVuZ2FuIGJlcmlrdXQgbWVuZ2hhc2lsa2FuIHRpZ2EgZWxlbWVuIHJhbmdrYWlhbiBrYXJha3Rlcgp0aHJlZV9zdHJpbmdzIDwtIHN0cl9jKCI8bT4iLCBrYXJha3Rlcl8xLCAiPG0+Iiwgc2VwID0gIl8iKQp0aHJlZV9zdHJpbmdzCgojIEhpdHVuZyBqdW1sYWggZWxlbWVuIGRhbGFtIHZla3RvciBgdGhyZWVfc3RyaW5nc2AKbGVuZ3RoKHRocmVlX3N0cmluZ3MpCmBgYAoKYGBge3IgY29sbGFwc2V9CiMgZGVuZ2FuIGNvbGxhcHNlID0gLi4uLCBwZW5nZ2FidW5nYW4gYmVyaWt1dCBtZW5naGFzaWxrYW4gc2F0dSBlbGVtZW4gcmFuZ2thaWFuIGthcmFrdGVyCm9uZV9zdHJpbmcgPC0gc3RyX2MoIjxtPiIsIGthcmFrdGVyXzEsICI8bT4iLCBjb2xsYXBzZSA9ICJfIikKb25lX3N0cmluZwoKIyBIaXR1bmcganVtbGFoIGVsZW1lbiBkYWxhbSB2ZWt0b3IgYG9uZV9zdHJpbmdgCmxlbmd0aChvbmVfc3RyaW5nKQpgYGAKCiMgTWVueWltcGFuIHZla3RvciBrYXJha3RlciBrZSBkYWxhbSBiZXJrYXMgdGVrcyAoKnBsYWluIHRleHQqKQoKR3VuYWthbiBmdW5nc2kgYGNhdCgpYCB5YW5nIHRlcnNlZGlhIGRhcmkgaW5zdGFsYXNpIGRhc2FyIFIgdW50dWsgbWVueWltcGFuIHZla3RvciBrYXJha3RlciBrZSBkYWxhbSBiZXJrYXMgdGVrcyBzZWRlcmhhbmEgKCpwbGFpbiB0ZXh0KiBkZW5nYW4gZWtzdGVuc2kgYC50eHRgKS4KCmBgYHtyIHNhdmluZy1jaGFyYWN0ZXItdmVjdG9yfQojIHNpbXBhbiB2ZWt0b3IgbmFtYSB3YXJuYSBrZSBiZXJrYXMgYCJzZWxlY3RlZC1jb2xvdXJzLnR4dCJgCiMgZGFsYW0gZGlyZWt0b3JpIGByZXN1bHRzYAojIHlhbmcgbWFzaW5nLW1hc2luZyBlbGVtZW4gdmVrdG9ybnlhIGRpcGlzYWhrYW4gZGVuZ2FuIGJhcmlzIGJhcnUgKGBzZXA9IlxuImApCmNhdCh3b3JkX2NvbG91cl92ZWN0b3IsIGZpbGUgPSAicmVzdWx0cy9zZWxlY3RlZC1jb2xvdXJzLnR4dCIsIHNlcCA9ICJcbiIpCmBgYAoKCgojICpTZXNzaW9uIGluZm8qIHstfQoKYGBge3Igc2Vzc2luZm99CmRldnRvb2xzOjpzZXNzaW9uX2luZm8oKQpgYGAKCgojIERhZnRhciBhY3VhbiB7LX0K