At-Taubah, surat ke-9 dalam Kitab Suci Al-Quran, merupakan satu-satunya surat yang tidak diawali dengan kata basmalah. Allah swt tentunya menciptakan ini bukan tanpa makna. Ayat pertama surat ini mungkin dapat memberikan gambaran mengapa Allah swt tidak menempatkan kata basmallah sebagai pengawal surat.
“(Inilah pernyataan) pemutusan hubungan dari Allah dan Rasul-Nya kepada orang-orang musyrik…”
Lalu bagaimanakah gambaran umum dari surat ini ditinjau dari pendekatan ‘text mining’? Kita akan coba melakukan text mining secara sederhana. Untuk melakukannya, diambil sumber berbahasa Inggris (agar sesuai dengan konteks software yang digunakan) dari https://www.helloquran.com/9
Library dan Laman Web
Untuk dapat melakukan text mining, diperlukan beberapa library sebagaimana berikut
pacman::p_load(rvest, dplyr, ggplot2, gridExtra, tidytext, tm, knitr,
kableExtra, formattable, tibble, wordcloud2, topicmodels,
tidyr, syuzhet)
Kemudian untuk memilih bagian mana dalam web yang secara spesifik akan diteliti, kita dapat menggunakan extension Chrome ‘SelectorGadget’. Dengan menggunakan ‘SelectorGadget’ tersebut kita dapat memilih bagian tertentu pada web yang nantinya akan secara otomatis mendeteksi informasi serupa dalam web. Kode yang diperoleh dari SelectorGadget tersebut (dihasilkan dari kotak di bawah webpage) kemudian dimasukkan ke dalam sytax sebagai berikut (dalam web ini misalnya, kode yang diperoleh adalah “.jss12”):
link <- "https://www.helloquran.com/9"
web <- read_html(link)
taubah <- web %>% html_nodes(".jss12") %>% html_text()
df.taubah <- data.frame(taubah, stringsAsFactors = FALSE)
Preprocessing
Tahapan selanjutnya dalam melakukan text processing yaitu ‘pembersihan’ atau text cleaning. Tujuan dari tahapan ini adalah untuk menghasilkan text utama tanpa ornamen seperti singkatan, spesial karakter, ataupun angka. Pertama kita ingin menyempurnakan kata apabila ada contraction seperti can’t -> can not; won’t -> will not, dan lain-lain:
slang <- function(doc) {
doc <- gsub("won't", "will not", doc)
doc <- gsub("can't", "can not", doc)
doc <- gsub("n't", " not", doc)
doc <- gsub("'ll", " will", doc)
doc <- gsub("'re", " are", doc)
doc <- gsub("'ve", " have", doc)
doc <- gsub("'m", " am", doc)
doc <- gsub("'d", " would", doc)
doc <- gsub("'s", "", doc)
return(doc)
}
df.taubah$taubah <- sapply(df.taubah$taubah, slang)
Kemudian kita perlu menghilangkan karakter khusus, mengubah semua huruf menjadi lowercase, dan menghilangkan nomor dalam kalimat.
karakterspesial <- function(x) gsub("[^a-zA-Z0-9 ]", " ", x)
df.taubah$taubah <- sapply(df.taubah$taubah, karakterspesial)
df.taubah$taubah <- sapply(df.taubah$taubah, tolower)
angka <- function(x) gsub("[0-9]+", " ", x)
df.taubah$taubah <- sapply(df.taubah$taubah, angka)
Proses text cleaning dirasa cukup karena sudah menghasilkan text utama yang mudah dicerna. Sebagai contoh misalkan kita ingin mengetahui Ayat ke-10 hasil preprocessing sebagai berikut:
str(df.taubah[10,], nchar.max = 300)
chr " towards a believer they respect neither kinship nor treaty these are the offenders "
Text Mining
Kita memasuki tahapan utama yaitu text mining. Pertama kita akan menghilangkan stopword bahasa inggris terlebih dahulu dan membatasi analisis kata dengan minimal terdiri dari 3 huruf (jadi kata-kata seperti ‘us’ tidak dilibatkan dalam analisis).
df.taubah$ayat <- 1:nrow(df.taubah)
filtrasi_kata <- df.taubah %>%
unnest_tokens(word, taubah) %>%
anti_join(stop_words) %>%
distinct() %>%
filter(nchar(word) > 2)
Joining, by = "word"
Selanjutnya, dari hasil tersebut kita dapat mendeteksi sebuah kata terdapat pada bagian (ayat) mana saja dalam surat. Misalnya kita ingin melihat kata “punishment” - azab, dalam surat At-Taubah itu terdapat pada ayat berapa saja
options(warn = -1)
filtrasi_kata %>%
filter(word == "punishment") %>%
select(word, ayat) %>%
arrange() %>%
top_n(10,ayat) %>%
mutate(ayat = color_tile("dodgerblue2","dodgerblue2")(ayat)) %>%
mutate(word = color_tile("seagreen3","seagreen3")(word)) %>%
kable("html", escape = FALSE, align = "c",
caption = "Kata 'Punishment' dalam Surat At-Taubah") %>%
kable_styling(bootstrap_options = c("striped", "condensed", "bordered"),
full_width = FALSE)
Kata 'Punishment' dalam Surat At-Taubah
| word |
ayat |
| punishment |
3 |
| punishment |
34 |
| punishment |
52 |
| punishment |
61 |
| punishment |
68 |
| punishment |
74 |
| punishment |
79 |
| punishment |
90 |
Kata ‘punishment’ atau azab ternyata diulang 8 kali dalam surat At-Taubah. Kita pun dapat mencari kata-kata lain sesuai dengan intensi.
Selanjutnya misalnya kita ingin mengetahui top-10 ayat dengan jumlah kata terbanyak dalam surat At-Taubah.
hitung_kata <- df.taubah %>%
unnest_tokens(word, taubah) %>%
group_by(ayat) %>%
summarise(num_words = n()) %>%
arrange(desc(num_words))
hitung_kata[1:10,] %>%
mutate(num_words = color_tile ("plum4","plum4")(num_words)) %>%
mutate(ayat = color_tile("lightseagreen","lightseagreen")(ayat)) %>%
kable("html", escape = FALSE, align = "c", caption = "Banyaknya Jumlah Kata dalam Ayat") %>%
kable_styling(bootstrap_options =
c("striped", "condensed", "bordered"),
full_width = FALSE)
Banyaknya Jumlah Kata dalam Ayat
| ayat |
num_words |
| 74 |
87 |
| 40 |
81 |
| 120 |
81 |
| 111 |
65 |
| 69 |
63 |
| 94 |
62 |
| 118 |
60 |
| 36 |
59 |
| 3 |
58 |
| 37 |
56 |
NA
Dari analisis tersebut, diperoleh ayat ke-74 memiliki jumlah kata (utama/inti) paling banyak sejumlah 87 kata diikuti oleh ayat ke-40 dengan 81 susunan kata.
Selain dari jumlah kata dalam satu ayat, kita juga dapat mengetahui kata top-20 ‘populer’ dalam surat At-Taubah
filtrasi_kata %>%
count(word, sort = TRUE) %>%
top_n(20) %>%
ungroup() %>%
mutate(word = reorder(word, n)) %>%
ggplot() + theme_bw() +
geom_col(aes(word, n), fill = "lightcoral") +
theme(legend.position = "none",
plot.title = element_text(hjust = 0.5),
panel.grid.major = element_blank()) +
xlab("") +
ylab("Jumlah Ayat") +
ggtitle("Top 20: Kata Paling Banyak Muncul dalam Surat At-Taubah") +
coord_flip()
Selecting by n

Dari bar chart tersebut dapat dilihat bahwa kata God menjadi kata paling banyak disebut (tentunya). Selanjutnya adalah kata ‘mesenger’ atau rasul/nabi, kemudian ‘people’ atau manusia, dan ‘believers’ atau orang-orang beriman. Yang menarik adalah terdapat kata ‘fight’ dalam top-10 kata paling banyak disebut. Apabila melihat pada terjemahan Indonesia, kata ‘fight’ diartikan sebagai perang. Seperti misalkan potongan dalam ayat ke-14 yang berbunyi “Perangilah mereka…”
Banyak munculnya kata ‘perang’ ini mungkin menjadi salah satu alasan mengapa permulaan At-Taubah tidak diawali dengan kata Basmalah.
Visualisasi Hasil
Tahapan selanjutnya, agar lebih menarik kita bisa membuat bentuk wordcloud dari kata-kata yang sering muncul dalam surat At-Taubah sebagai berikut:
wordcloud_taubah <- filtrasi_kata %>%
count(word, sort = TRUE)
wordcloud2(wordcloud_taubah[1:661,], size = 1, color = "random-light",
shape = "circle", backgroundColor = "gray32")
Selanjutnya, kita ingin melihat diversity dari leksikal/vocabulary yang ada dalam surat ini berdasarkan ayat.
leksikal <- df.taubah %>%
unnest_tokens(word, taubah) %>%
group_by(ayat) %>%
summarise(lex_diversity = n_distinct(word)) %>%
arrange(desc(lex_diversity))
diversity_plot <- leksikal %>%
ggplot(aes(ayat, lex_diversity)) +
geom_point(color = "sienna1",
alpha = .6,
size = 4,
position = "jitter") +
stat_smooth(color = "turquoise1", se = FALSE, method = "lm") +
geom_smooth(aes(x = ayat, y = lex_diversity), se = FALSE,
color = "olivedrab1", lwd = 1) +
ggtitle("Keragaman Kosakata") +
xlab("Ayat") +
ylab("Keragaman") +
theme_dark()
diversity_plot
`geom_smooth()` using formula 'y ~ x'
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Dari gambar tersebut dapat dilihat bahwa keragaman leksikal yang digunakan stabil dari ayat pertama sampai dengan terakhir.
Topic Modelling
Untuk melengkapi proses text mining, analisis selanjutnya kita ingin melakukan topic modelling (pengelompokkan kata-kata berdasarkan topik tertentu secara otomatis).
text_taubah <- VCorpus(VectorSource(filtrasi_kata$word))
text_taubah <- DocumentTermMatrix(text_taubah)
text_taubah
<<DocumentTermMatrix (documents: 1281, terms: 661)>>
Non-/sparse entries: 1281/845460
Sparsity : 100%
Maximal term length: 13
Weighting : term frequency (tf)
Misalnya kita ingin mengetahui kata yang muncul minimal 10 kali dalam surat At-Taubah
findFreqTerms(text_taubah, lowfreq = 10)
[1] "believers" "day" "fight" "god" "hearts" "messenger"
[7] "people" "wealth"
Kemudian kita ingin melakukan pengelompokkan topik dengan enam kategori:
lda_taubah <- LDA(text_taubah, k = 4, method = "Gibbs",
control = list(seed = 1407))
taubah_topics <- tidy(lda_taubah, matrix = "beta")
taubah_top_terms <- taubah_topics %>%
group_by(topic) %>%
slice_max(beta, n = 6) %>%
ungroup() %>%
arrange(topic, -beta)
taubah_top_terms %>%
mutate(term = reorder_within(term, beta, topic)) %>%
ggplot(aes(beta, term, fill = factor(topic))) +
geom_col(show.legend = FALSE) +
facet_wrap(~ topic, scales = "free") + scale_y_reordered()

coord_flip()
<ggproto object: Class CoordFlip, CoordCartesian, Coord, gg>
aspect: function
backtransform_range: function
clip: on
default: FALSE
distance: function
expand: TRUE
is_free: function
is_linear: function
labels: function
limits: list
modify_scales: function
range: function
render_axis_h: function
render_axis_v: function
render_bg: function
render_fg: function
setup_data: function
setup_layout: function
setup_panel_guides: function
setup_panel_params: function
setup_params: function
train_panel_guides: function
transform: function
super: <ggproto object: Class CoordFlip, CoordCartesian, Coord, gg>
Sentiment Analysis
Terakhir, kita ingin melihat/membentuk analisis sentimen dari kata-kata yang ada dalam surat At-Taubah sebagai berikut
taubah_sentimen <- iconv(df.taubah$taubah, to = "utf-8")
taubah_sentimen <- get_nrc_sentiment(taubah_sentimen)
barplot(colSums(taubah_sentimen),
las = 2,
col = rainbow(10),
ylab = 'Frekuensi',
main = 'Sentimen')

Apabila dilihat pada bar chart tersebut, sentimen paling dominan adalah tone positif, trust, dan fear. Menarik melihat ada sentimen ‘fear’ yang cukup dominan disini. Sentimen ini jelas bukan menunjukkan kondisi yang sebenarnya, hanya sebuah pendekatan dari sistem murni berdasarkan kata tanpa melihat konteks maupun struktur kata secara utuh.
End
LS0tDQp0aXRsZTogIlJlcGVudGFuY2U6IFNpbXBsZSBUZXh0IE1pbmluZyB3aXRoIFIiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpBdC1UYXViYWgsIHN1cmF0IGtlLTkgZGFsYW0gS2l0YWIgU3VjaSBBbC1RdXJhbiwgbWVydXBha2FuIHNhdHUtc2F0dW55YSBzdXJhdCB5YW5nIHRpZGFrIGRpYXdhbGkgZGVuZ2FuIGthdGEgYmFzbWFsYWguIEFsbGFoIHN3dCB0ZW50dW55YSBtZW5jaXB0YWthbiBpbmkgYnVrYW4gdGFucGEgbWFrbmEuIEF5YXQgcGVydGFtYSBzdXJhdCBpbmkgbXVuZ2tpbiBkYXBhdCBtZW1iZXJpa2FuIGdhbWJhcmFuIG1lbmdhcGEgQWxsYWggc3d0IHRpZGFrIG1lbmVtcGF0a2FuIGthdGEgYmFzbWFsbGFoIHNlYmFnYWkgcGVuZ2F3YWwgc3VyYXQuIA0KDQpfIihJbmlsYWggcGVybnlhdGFhbikgcGVtdXR1c2FuIGh1YnVuZ2FuIGRhcmkgQWxsYWggZGFuIFJhc3VsLU55YSBrZXBhZGEgb3Jhbmctb3JhbmcgbXVzeXJpay4uLiJfDQoNCkxhbHUgYmFnYWltYW5ha2FoIGdhbWJhcmFuIHVtdW0gZGFyaSBzdXJhdCBpbmkgZGl0aW5qYXUgZGFyaSBwZW5kZWthdGFuICd0ZXh0IG1pbmluZyc/IEtpdGEgYWthbiBjb2JhIG1lbGFrdWthbiB0ZXh0IG1pbmluZyBzZWNhcmEgc2VkZXJoYW5hLiBVbnR1ayBtZWxha3VrYW5ueWEsIGRpYW1iaWwgc3VtYmVyIGJlcmJhaGFzYSBJbmdncmlzIChhZ2FyIHNlc3VhaSBkZW5nYW4ga29udGVrcyBzb2Z0d2FyZSB5YW5nIGRpZ3VuYWthbikgZGFyaSBodHRwczovL3d3dy5oZWxsb3F1cmFuLmNvbS85IA0KDQotLS0tLS0tDQoNCiMjIyBMaWJyYXJ5IGRhbiBMYW1hbiBXZWINCg0KVW50dWsgZGFwYXQgbWVsYWt1a2FuIHRleHQgbWluaW5nLCBkaXBlcmx1a2FuIGJlYmVyYXBhIGxpYnJhcnkgc2ViYWdhaW1hbmEgYmVyaWt1dA0KDQpgYGB7cn0NCnBhY21hbjo6cF9sb2FkKHJ2ZXN0LCBkcGx5ciwgZ2dwbG90MiwgZ3JpZEV4dHJhLCB0aWR5dGV4dCwgdG0sIGtuaXRyLA0KICAgICAgICAgICAgICAga2FibGVFeHRyYSwgZm9ybWF0dGFibGUsIHRpYmJsZSwgd29yZGNsb3VkMiwgdG9waWNtb2RlbHMsDQogICAgICAgICAgICAgICB0aWR5ciwgc3l1emhldCkNCmBgYA0KDQpLZW11ZGlhbiB1bnR1ayBtZW1pbGloIGJhZ2lhbiBtYW5hIGRhbGFtIHdlYiB5YW5nIHNlY2FyYSBzcGVzaWZpayBha2FuIGRpdGVsaXRpLCBraXRhIGRhcGF0IG1lbmdndW5ha2FuIGV4dGVuc2lvbiBDaHJvbWUgJ1NlbGVjdG9yR2FkZ2V0Jy4gRGVuZ2FuIG1lbmdndW5ha2FuICdTZWxlY3RvckdhZGdldCcgdGVyc2VidXQga2l0YSBkYXBhdCBtZW1pbGloIGJhZ2lhbiB0ZXJ0ZW50dSBwYWRhIHdlYiB5YW5nIG5hbnRpbnlhIGFrYW4gc2VjYXJhIG90b21hdGlzIG1lbmRldGVrc2kgaW5mb3JtYXNpIHNlcnVwYSBkYWxhbSB3ZWIuIEtvZGUgeWFuZyBkaXBlcm9sZWggZGFyaSBTZWxlY3RvckdhZGdldCB0ZXJzZWJ1dCAoZGloYXNpbGthbiBkYXJpIGtvdGFrIGRpIGJhd2FoIHdlYnBhZ2UpIGtlbXVkaWFuIGRpbWFzdWtrYW4ga2UgZGFsYW0gc3l0YXggc2ViYWdhaSBiZXJpa3V0IChkYWxhbSB3ZWIgaW5pIG1pc2FsbnlhLCBrb2RlIHlhbmcgZGlwZXJvbGVoIGFkYWxhaCAqKiIuanNzMTIiKiopOg0KDQoNCmBgYHtyfQ0KbGluayA8LSAiaHR0cHM6Ly93d3cuaGVsbG9xdXJhbi5jb20vOSINCndlYiA8LSByZWFkX2h0bWwobGluaykNCnRhdWJhaCA8LSB3ZWIgJT4lIGh0bWxfbm9kZXMoIi5qc3MxMiIpICU+JSBodG1sX3RleHQoKQ0KZGYudGF1YmFoIDwtIGRhdGEuZnJhbWUodGF1YmFoLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQpgYGANCg0KDQotLS0tLS0tLQ0KDQojIyMgUHJlcHJvY2Vzc2luZw0KDQpUYWhhcGFuIHNlbGFuanV0bnlhIGRhbGFtIG1lbGFrdWthbiB0ZXh0IHByb2Nlc3NpbmcgeWFpdHUgJ3BlbWJlcnNpaGFuJyBhdGF1IHRleHQgY2xlYW5pbmcuIFR1anVhbiBkYXJpIHRhaGFwYW4gaW5pIGFkYWxhaCB1bnR1ayBtZW5naGFzaWxrYW4gdGV4dCB1dGFtYSB0YW5wYSBvcm5hbWVuIHNlcGVydGkgc2luZ2thdGFuLCBzcGVzaWFsIGthcmFrdGVyLCBhdGF1cHVuIGFuZ2thLiBQZXJ0YW1hIGtpdGEgaW5naW4gbWVueWVtcHVybmFrYW4ga2F0YSBhcGFiaWxhIGFkYSBjb250cmFjdGlvbiBzZXBlcnRpIGNhbid0IC0+IGNhbiBub3Q7IHdvbid0IC0+IHdpbGwgbm90LCBkYW4gbGFpbi1sYWluOg0KDQpgYGB7cn0NCnNsYW5nIDwtIGZ1bmN0aW9uKGRvYykgew0KICBkb2MgPC0gZ3N1Yigid29uJ3QiLCAid2lsbCBub3QiLCBkb2MpDQogIGRvYyA8LSBnc3ViKCJjYW4ndCIsICJjYW4gbm90IiwgZG9jKQ0KICBkb2MgPC0gZ3N1Yigibid0IiwgIiBub3QiLCBkb2MpDQogIGRvYyA8LSBnc3ViKCInbGwiLCAiIHdpbGwiLCBkb2MpDQogIGRvYyA8LSBnc3ViKCIncmUiLCAiIGFyZSIsIGRvYykNCiAgZG9jIDwtIGdzdWIoIid2ZSIsICIgaGF2ZSIsIGRvYykNCiAgZG9jIDwtIGdzdWIoIidtIiwgIiBhbSIsIGRvYykNCiAgZG9jIDwtIGdzdWIoIidkIiwgIiB3b3VsZCIsIGRvYykNCiAgZG9jIDwtIGdzdWIoIidzIiwgIiIsIGRvYykNCiAgcmV0dXJuKGRvYykNCn0NCg0KZGYudGF1YmFoJHRhdWJhaCA8LSBzYXBwbHkoZGYudGF1YmFoJHRhdWJhaCwgc2xhbmcpDQpgYGANCg0KDQpLZW11ZGlhbiBraXRhIHBlcmx1IG1lbmdoaWxhbmdrYW4ga2FyYWt0ZXIga2h1c3VzLCBtZW5ndWJhaCBzZW11YSBodXJ1ZiBtZW5qYWRpIGxvd2VyY2FzZSwgZGFuIG1lbmdoaWxhbmdrYW4gbm9tb3IgZGFsYW0ga2FsaW1hdC4NCg0KDQpgYGB7cn0NCmthcmFrdGVyc3Blc2lhbCA8LSBmdW5jdGlvbih4KSBnc3ViKCJbXmEtekEtWjAtOSBdIiwgIiAiLCB4KQ0KDQpkZi50YXViYWgkdGF1YmFoIDwtIHNhcHBseShkZi50YXViYWgkdGF1YmFoLCBrYXJha3RlcnNwZXNpYWwpDQpkZi50YXViYWgkdGF1YmFoIDwtIHNhcHBseShkZi50YXViYWgkdGF1YmFoLCB0b2xvd2VyKQ0KDQphbmdrYSA8LSBmdW5jdGlvbih4KSBnc3ViKCJbMC05XSsiLCAiICIsIHgpDQpkZi50YXViYWgkdGF1YmFoIDwtIHNhcHBseShkZi50YXViYWgkdGF1YmFoLCBhbmdrYSkNCg0KYGBgDQoNCg0KUHJvc2VzIHRleHQgY2xlYW5pbmcgZGlyYXNhIGN1a3VwIGthcmVuYSBzdWRhaCBtZW5naGFzaWxrYW4gdGV4dCB1dGFtYSB5YW5nIG11ZGFoIGRpY2VybmEuIFNlYmFnYWkgY29udG9oIG1pc2Fsa2FuIGtpdGEgaW5naW4gbWVuZ2V0YWh1aSBBeWF0IGtlLTEwIGhhc2lsIHByZXByb2Nlc3Npbmcgc2ViYWdhaSBiZXJpa3V0Og0KDQoNCmBgYHtyfQ0Kc3RyKGRmLnRhdWJhaFsxMCxdLCBuY2hhci5tYXggPSAzMDApDQpgYGANCg0KDQotLS0tLS0tLQ0KDQojIyMgVGV4dCBNaW5pbmcNCg0KDQpLaXRhIG1lbWFzdWtpIHRhaGFwYW4gdXRhbWEgeWFpdHUgdGV4dCBtaW5pbmcuIFBlcnRhbWEga2l0YSBha2FuIG1lbmdoaWxhbmdrYW4gc3RvcHdvcmQgYmFoYXNhIGluZ2dyaXMgdGVybGViaWggZGFodWx1IGRhbiBtZW1iYXRhc2kgYW5hbGlzaXMga2F0YSBkZW5nYW4gbWluaW1hbCB0ZXJkaXJpIGRhcmkgMyBodXJ1ZiAoamFkaSBrYXRhLWthdGEgc2VwZXJ0aSAndXMnIHRpZGFrIGRpbGliYXRrYW4gZGFsYW0gYW5hbGlzaXMpLg0KDQoNCmBgYHtyfQ0KZGYudGF1YmFoJGF5YXQgPC0gMTpucm93KGRmLnRhdWJhaCkNCg0KZmlsdHJhc2lfa2F0YSA8LSBkZi50YXViYWggJT4lDQogIHVubmVzdF90b2tlbnMod29yZCwgdGF1YmFoKSAlPiUNCiAgYW50aV9qb2luKHN0b3Bfd29yZHMpICU+JQ0KICBkaXN0aW5jdCgpICU+JQ0KICBmaWx0ZXIobmNoYXIod29yZCkgPiAyKQ0KYGBgDQoNClNlbGFuanV0bnlhLCBkYXJpIGhhc2lsIHRlcnNlYnV0IGtpdGEgZGFwYXQgbWVuZGV0ZWtzaSBzZWJ1YWgga2F0YSB0ZXJkYXBhdCBwYWRhIGJhZ2lhbiAoYXlhdCkgbWFuYSBzYWphIGRhbGFtIHN1cmF0LiBNaXNhbG55YSBraXRhIGluZ2luIG1lbGloYXQga2F0YSAqKiJwdW5pc2htZW50IiAtIGF6YWIqKiwgZGFsYW0gc3VyYXQgQXQtVGF1YmFoIGl0dSB0ZXJkYXBhdCBwYWRhIGF5YXQgYmVyYXBhIHNhamENCg0KYGBge3J9DQoNCm9wdGlvbnMod2FybiA9IC0xKQ0KDQpmaWx0cmFzaV9rYXRhICU+JSANCiAgZmlsdGVyKHdvcmQgPT0gInB1bmlzaG1lbnQiKSAlPiUNCiAgc2VsZWN0KHdvcmQsIGF5YXQpICU+JQ0KICBhcnJhbmdlKCkgJT4lDQogIHRvcF9uKDEwLGF5YXQpICU+JQ0KICBtdXRhdGUoYXlhdCA9IGNvbG9yX3RpbGUoImRvZGdlcmJsdWUyIiwiZG9kZ2VyYmx1ZTIiKShheWF0KSkgJT4lDQogIG11dGF0ZSh3b3JkID0gY29sb3JfdGlsZSgic2VhZ3JlZW4zIiwic2VhZ3JlZW4zIikod29yZCkpICU+JQ0KICBrYWJsZSgiaHRtbCIsIGVzY2FwZSA9IEZBTFNFLCBhbGlnbiA9ICJjIiwNCiAgICAgICAgY2FwdGlvbiA9ICJLYXRhICdQdW5pc2htZW50JyBkYWxhbSBTdXJhdCBBdC1UYXViYWgiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiY29uZGVuc2VkIiwgImJvcmRlcmVkIiksIA0KICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBGQUxTRSkNCmBgYA0KDQpLYXRhICdwdW5pc2htZW50JyBhdGF1IGF6YWIgdGVybnlhdGEgZGl1bGFuZyA4IGthbGkgZGFsYW0gc3VyYXQgQXQtVGF1YmFoLiBLaXRhIHB1biBkYXBhdCBtZW5jYXJpIGthdGEta2F0YSBsYWluIHNlc3VhaSBkZW5nYW4gaW50ZW5zaS4NCg0KDQpTZWxhbmp1dG55YSBtaXNhbG55YSBraXRhIGluZ2luIG1lbmdldGFodWkgdG9wLTEwIGF5YXQgZGVuZ2FuIGp1bWxhaCBrYXRhIHRlcmJhbnlhayBkYWxhbSBzdXJhdCBBdC1UYXViYWguDQoNCmBgYHtyfQ0KDQpoaXR1bmdfa2F0YSA8LSBkZi50YXViYWggJT4lDQogIHVubmVzdF90b2tlbnMod29yZCwgdGF1YmFoKSAlPiUNCiAgZ3JvdXBfYnkoYXlhdCkgJT4lDQogIHN1bW1hcmlzZShudW1fd29yZHMgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MobnVtX3dvcmRzKSkgDQoNCg0KaGl0dW5nX2thdGFbMToxMCxdICU+JQ0KICBtdXRhdGUobnVtX3dvcmRzID0gY29sb3JfdGlsZSAoInBsdW00IiwicGx1bTQiKShudW1fd29yZHMpKSAlPiUNCiAgbXV0YXRlKGF5YXQgPSBjb2xvcl90aWxlKCJsaWdodHNlYWdyZWVuIiwibGlnaHRzZWFncmVlbiIpKGF5YXQpKSAlPiUNCiAga2FibGUoImh0bWwiLCBlc2NhcGUgPSBGQUxTRSwgYWxpZ24gPSAiYyIsIGNhcHRpb24gPSAiQmFueWFrbnlhIEp1bWxhaCBLYXRhIGRhbGFtIEF5YXQiKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IA0KICAgICAgICAgICAgICAgICAgYygic3RyaXBlZCIsICJjb25kZW5zZWQiLCAiYm9yZGVyZWQiKSwgDQogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEZBTFNFKQ0KDQpgYGANCg0KRGFyaSBhbmFsaXNpcyB0ZXJzZWJ1dCwgZGlwZXJvbGVoIGF5YXQga2UtNzQgbWVtaWxpa2kganVtbGFoIGthdGEgKHV0YW1hL2ludGkpIHBhbGluZyBiYW55YWsgc2VqdW1sYWggODcga2F0YSBkaWlrdXRpIG9sZWggYXlhdCBrZS00MCBkZW5nYW4gODEgc3VzdW5hbiBrYXRhLg0KDQpTZWxhaW4gZGFyaSBqdW1sYWgga2F0YSBkYWxhbSBzYXR1IGF5YXQsIGtpdGEganVnYSBkYXBhdCBtZW5nZXRhaHVpIGthdGEgdG9wLTIwICAncG9wdWxlcicgZGFsYW0gc3VyYXQgQXQtVGF1YmFoDQoNCmBgYHtyfQ0KZmlsdHJhc2lfa2F0YSAlPiUNCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpICU+JQ0KICB0b3BfbigyMCkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUNCiAgZ2dwbG90KCkgKyB0aGVtZV9idygpICsNCiAgZ2VvbV9jb2woYWVzKHdvcmQsIG4pLCBmaWxsID0gImxpZ2h0Y29yYWwiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSArDQogIHhsYWIoIiIpICsgDQogIHlsYWIoIkp1bWxhaCBBeWF0IikgKw0KICBnZ3RpdGxlKCJUb3AgMjA6IEthdGEgUGFsaW5nIEJhbnlhayBNdW5jdWwgZGFsYW0gU3VyYXQgQXQtVGF1YmFoIikgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQpEYXJpIGJhciBjaGFydCB0ZXJzZWJ1dCBkYXBhdCBkaWxpaGF0IGJhaHdhIGthdGEgR29kIG1lbmphZGkga2F0YSBwYWxpbmcgYmFueWFrIGRpc2VidXQgKHRlbnR1bnlhKS4gU2VsYW5qdXRueWEgYWRhbGFoIGthdGEgJ21lc2VuZ2VyJyBhdGF1IHJhc3VsL25hYmksIGtlbXVkaWFuICdwZW9wbGUnIGF0YXUgbWFudXNpYSwgZGFuICdiZWxpZXZlcnMnIGF0YXUgb3Jhbmctb3JhbmcgYmVyaW1hbi4gWWFuZyBtZW5hcmlrIGFkYWxhaCB0ZXJkYXBhdCBrYXRhICdmaWdodCcgZGFsYW0gdG9wLTEwIGthdGEgcGFsaW5nIGJhbnlhayBkaXNlYnV0LiBBcGFiaWxhIG1lbGloYXQgcGFkYSB0ZXJqZW1haGFuIEluZG9uZXNpYSwga2F0YSAnZmlnaHQnIGRpYXJ0aWthbiBzZWJhZ2FpIHBlcmFuZy4gU2VwZXJ0aSBtaXNhbGthbiBwb3RvbmdhbiBkYWxhbSBheWF0IGtlLTE0IHlhbmcgYmVyYnVueWkgXyJQZXJhbmdpbGFoIG1lcmVrYS4uLiJfDQoNCj4gQmFueWFrIG11bmN1bG55YSBrYXRhICdwZXJhbmcnIGluaSBtdW5na2luIG1lbmphZGkgc2FsYWggc2F0dSBhbGFzYW4gbWVuZ2FwYSBwZXJtdWxhYW4gQXQtVGF1YmFoIHRpZGFrIGRpYXdhbGkgZGVuZ2FuIGthdGEgQmFzbWFsYWguDQoNCi0tLS0tLQ0KDQojIyMgVmlzdWFsaXNhc2kgSGFzaWwNCg0KVGFoYXBhbiBzZWxhbmp1dG55YSwgYWdhciBsZWJpaCBtZW5hcmlrIGtpdGEgYmlzYSBtZW1idWF0IGJlbnR1ayB3b3JkY2xvdWQgZGFyaSBrYXRhLWthdGEgeWFuZyBzZXJpbmcgbXVuY3VsIGRhbGFtIHN1cmF0IEF0LVRhdWJhaCBzZWJhZ2FpIGJlcmlrdXQ6DQoNCmBgYHtyfQ0KDQp3b3JkY2xvdWRfdGF1YmFoIDwtIGZpbHRyYXNpX2thdGEgJT4lDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSANCg0Kd29yZGNsb3VkMih3b3JkY2xvdWRfdGF1YmFoWzE6NjYxLF0sIHNpemUgPSAxLCAgY29sb3IgPSAicmFuZG9tLWxpZ2h0IiwgDQogICAgICAgICAgIHNoYXBlID0gImNpcmNsZSIsIGJhY2tncm91bmRDb2xvciA9ICJncmF5MzIiKQ0KYGBgDQoNCg0KU2VsYW5qdXRueWEsIGtpdGEgaW5naW4gbWVsaWhhdCBkaXZlcnNpdHkgZGFyaSBsZWtzaWthbC92b2NhYnVsYXJ5IHlhbmcgYWRhIGRhbGFtIHN1cmF0IGluaSBiZXJkYXNhcmthbiBheWF0Lg0KDQpgYGB7cn0NCg0KbGVrc2lrYWwgPC0gZGYudGF1YmFoICU+JQ0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRhdWJhaCkgJT4lDQogIGdyb3VwX2J5KGF5YXQpICU+JQ0KICBzdW1tYXJpc2UobGV4X2RpdmVyc2l0eSA9IG5fZGlzdGluY3Qod29yZCkpICU+JQ0KICBhcnJhbmdlKGRlc2MobGV4X2RpdmVyc2l0eSkpIA0KDQpkaXZlcnNpdHlfcGxvdCA8LSBsZWtzaWthbCAlPiUNCiAgZ2dwbG90KGFlcyhheWF0LCBsZXhfZGl2ZXJzaXR5KSkgKw0KICBnZW9tX3BvaW50KGNvbG9yID0gInNpZW5uYTEiLA0KICAgICAgICAgICAgIGFscGhhID0gLjYsIA0KICAgICAgICAgICAgIHNpemUgPSA0LCANCiAgICAgICAgICAgICBwb3NpdGlvbiA9ICJqaXR0ZXIiKSArIA0KICBzdGF0X3Ntb290aChjb2xvciA9ICJ0dXJxdW9pc2UxIiwgc2UgPSBGQUxTRSwgbWV0aG9kID0gImxtIikgKw0KICBnZW9tX3Ntb290aChhZXMoeCA9IGF5YXQsIHkgPSBsZXhfZGl2ZXJzaXR5KSwgc2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgY29sb3IgPSAib2xpdmVkcmFiMSIsIGx3ZCA9IDEpICsNCiAgZ2d0aXRsZSgiS2VyYWdhbWFuIEtvc2FrYXRhIikgKw0KICB4bGFiKCJBeWF0IikgKyANCiAgeWxhYigiS2VyYWdhbWFuIikgKw0KICB0aGVtZV9kYXJrKCkNCg0KZGl2ZXJzaXR5X3Bsb3QNCg0KYGBgDQoNCg0KRGFyaSBnYW1iYXIgdGVyc2VidXQgZGFwYXQgZGlsaWhhdCBiYWh3YSBrZXJhZ2FtYW4gbGVrc2lrYWwgeWFuZyBkaWd1bmFrYW4gc3RhYmlsIGRhcmkgYXlhdCBwZXJ0YW1hIHNhbXBhaSBkZW5nYW4gdGVyYWtoaXIuDQoNCg0KLS0tLS0tLQ0KDQojIyMgVG9waWMgTW9kZWxsaW5nDQoNClVudHVrIG1lbGVuZ2thcGkgcHJvc2VzIHRleHQgbWluaW5nLCBhbmFsaXNpcyBzZWxhbmp1dG55YSBraXRhIGluZ2luIG1lbGFrdWthbiB0b3BpYyBtb2RlbGxpbmcgKHBlbmdlbG9tcG9ra2FuIGthdGEta2F0YSBiZXJkYXNhcmthbiB0b3BpayB0ZXJ0ZW50dSBzZWNhcmEgb3RvbWF0aXMpLiANCg0KYGBge3J9DQp0ZXh0X3RhdWJhaCA8LSBWQ29ycHVzKFZlY3RvclNvdXJjZShmaWx0cmFzaV9rYXRhJHdvcmQpKQ0KdGV4dF90YXViYWggPC0gRG9jdW1lbnRUZXJtTWF0cml4KHRleHRfdGF1YmFoKQ0KdGV4dF90YXViYWgNCmBgYA0KDQpNaXNhbG55YSBraXRhIGluZ2luIG1lbmdldGFodWkga2F0YSB5YW5nIG11bmN1bCBtaW5pbWFsIDEwIGthbGkgZGFsYW0gc3VyYXQgQXQtVGF1YmFoDQoNCmBgYHtyfQ0KZmluZEZyZXFUZXJtcyh0ZXh0X3RhdWJhaCwgbG93ZnJlcSA9IDEwKQ0KYGBgDQoNCktlbXVkaWFuIGtpdGEgaW5naW4gbWVsYWt1a2FuIHBlbmdlbG9tcG9ra2FuIHRvcGlrIGRlbmdhbiBlbmFtIGthdGVnb3JpOg0KDQoNCmBgYHtyfQ0KbGRhX3RhdWJhaCA8LSBMREEodGV4dF90YXViYWgsIGsgPSA0LCBtZXRob2QgPSAiR2liYnMiLA0KICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3Qoc2VlZCA9IDE0MDcpKQ0KdGF1YmFoX3RvcGljcyA8LSB0aWR5KGxkYV90YXViYWgsIG1hdHJpeCA9ICJiZXRhIikNCg0KdGF1YmFoX3RvcF90ZXJtcyA8LSB0YXViYWhfdG9waWNzICU+JQ0KICBncm91cF9ieSh0b3BpYykgJT4lDQogIHNsaWNlX21heChiZXRhLCBuID0gNikgJT4lIA0KICB1bmdyb3VwKCkgJT4lDQogIGFycmFuZ2UodG9waWMsIC1iZXRhKQ0KDQp0YXViYWhfdG9wX3Rlcm1zICU+JQ0KICBtdXRhdGUodGVybSA9IHJlb3JkZXJfd2l0aGluKHRlcm0sIGJldGEsIHRvcGljKSkgJT4lDQogIGdncGxvdChhZXMoYmV0YSwgdGVybSwgZmlsbCA9IGZhY3Rvcih0b3BpYykpKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsNCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBzY2FsZXMgPSAiZnJlZSIpICsgc2NhbGVfeV9yZW9yZGVyZWQoKQ0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQoNCi0tLS0tLQ0KDQojIyMgU2VudGltZW50IEFuYWx5c2lzDQoNClRlcmFraGlyLCBraXRhIGluZ2luIG1lbGloYXQvbWVtYmVudHVrIGFuYWxpc2lzIHNlbnRpbWVuIGRhcmkga2F0YS1rYXRhIHlhbmcgYWRhIGRhbGFtIHN1cmF0IEF0LVRhdWJhaCBzZWJhZ2FpIGJlcmlrdXQNCg0KYGBge3J9DQp0YXViYWhfc2VudGltZW4gPC0gaWNvbnYoZGYudGF1YmFoJHRhdWJhaCwgdG8gPSAidXRmLTgiKQ0KdGF1YmFoX3NlbnRpbWVuIDwtIGdldF9ucmNfc2VudGltZW50KHRhdWJhaF9zZW50aW1lbikNCg0KYmFycGxvdChjb2xTdW1zKHRhdWJhaF9zZW50aW1lbiksDQogICAgICAgIGxhcyA9IDIsDQogICAgICAgIGNvbCA9IHJhaW5ib3coMTApLA0KICAgICAgICB5bGFiID0gJ0ZyZWt1ZW5zaScsDQogICAgICAgIG1haW4gPSAnU2VudGltZW4nKQ0KYGBgDQoNCkFwYWJpbGEgZGlsaWhhdCBwYWRhIGJhciBjaGFydCB0ZXJzZWJ1dCwgc2VudGltZW4gcGFsaW5nIGRvbWluYW4gYWRhbGFoIHRvbmUgcG9zaXRpZiwgdHJ1c3QsIGRhbiBmZWFyLiBNZW5hcmlrIG1lbGloYXQgYWRhIHNlbnRpbWVuICdmZWFyJyB5YW5nIGN1a3VwIGRvbWluYW4gZGlzaW5pLiBTZW50aW1lbiBpbmkgamVsYXMgYnVrYW4gbWVudW5qdWtrYW4ga29uZGlzaSB5YW5nIHNlYmVuYXJueWEsIGhhbnlhIHNlYnVhaCBwZW5kZWthdGFuIGRhcmkgc2lzdGVtIG11cm5pIGJlcmRhc2Fya2FuIGthdGEgdGFucGEgbWVsaWhhdCBrb250ZWtzIG1hdXB1biBzdHJ1a3R1ciBrYXRhIHNlY2FyYSB1dHVoLg0KDQotLS0tLS0tDQoNCiMjIyBFbmQNCg0K