knitr::opts_chunk$set(echo = TRUE)

Text mining merupakan pendekatan analitis yang digunakan untuk mengekstraksi informasi dan pola bermakna dari data teks tidak terstruktur, seperti percakapan daring, dokumen, maupun media sosial. Berbeda dengan data numerik yang memiliki struktur baku, data teks bersifat bebas, kaya konteks, dan mengandung variasi bahasa yang tinggi, sehingga memerlukan teknik khusus dalam pengolahannya. Melalui tahapan seperti pembersihan teks, tokenisasi, normalisasi, dan pembobotan kata, text mining memungkinkan teks diubah menjadi representasi terstruktur yang dapat dianalisis secara kuantitatif. Pendekatan ini semakin relevan seiring meningkatnya volume data tekstual dalam aktivitas komunikasi digital.

Tujuan utama text mining adalah untuk mengidentifikasi pola, kecenderungan, dan makna tersembunyi yang tidak mudah ditangkap melalui pembacaan manual, terutama pada data berskala besar. Dalam konteks analisis percakapan, text mining digunakan untuk memahami dinamika komunikasi, mengukur intensitas dan fokus pembahasan, serta mendeteksi indikasi sentimen atau isu tertentu yang muncul berulang. Dengan demikian, text mining tidak hanya berfungsi sebagai alat eksplorasi data, tetapi juga sebagai dasar pengambilan keputusan berbasis bukti, evaluasi kebijakan, dan pemahaman perilaku komunikasi secara sistematis dan objektif.

library(tidyverse)
library(tidytext)
library(rwhatsapp)
library(ggplot2)
library(lubridate)
library(wordcloud2)

1 Load Data

Data percakapan WhatsApp diperoleh dari file ekspor riwayat chat grup dalam format .txt. Data kemudian dibaca menggunakan fungsi rwa_read() dari paket rwhatsapp. Untuk menjaga relevansi analisis, data dibatasi hanya pada pesan yang dikirim mulai 1 Januari 2025, sehingga analisis merepresentasikan dinamika komunikasi sepanjang tahun berjalan.

Tahap awal eksplorasi data dilakukan dengan menampilkan beberapa baris pertama dan memeriksa struktur data menggunakan glimpse(). Pemeriksaan ini bertujuan untuk memastikan konsistensi variabel, khususnya kolom waktu (time), penulis pesan (author), dan isi pesan (text).

Analisis percakapan WhatsApp dilakukan menggunakan pendekatan text mining, yaitu serangkaian teknik untuk mengekstraksi informasi bermakna dari data teks tidak terstruktur. Pendekatan ini mencakup tahapan pembersihan teks, tokenisasi, pembobotan kata, serta analisis frekuensi dan kemiripan teks untuk mengidentifikasi pola komunikasi yang tersembunyi dalam data percakapan (Feldman & Sanger, 2007; Manning et al., 2008).

## # A tibble: 6 × 6
##   time                author       text                 source emoji  emoji_name
##   <dttm>              <fct>        <chr>                <chr>  <list> <list>    
## 1 2025-01-02 09:28:00 Ofi Ana Sari "Pak @⁨Raden Sinang…  Whats… <chr>  <chr [2]> 
## 2 2025-01-02 09:33:00 Raden Sinang "Tanggal 7 rencanan… Whats… <NULL> <NULL>    
## 3 2025-01-02 09:36:00 Mayang Sari  "tgl 2,3,6 masih fr… Whats… <NULL> <NULL>    
## 4 2025-01-02 09:38:00 Ofi Ana Sari "dah ngelupain kerj… Whats… <NULL> <NULL>    
## 5 2025-01-02 09:41:00 Raden Sinang "tunggu aja, siapa … Whats… <NULL> <NULL>    
## 6 2025-01-02 09:44:00 Budi Santoso "Ketua tim yg sdh y… Whats… <chr>  <chr [1]>

Pembersihan Data (Data Cleaning)

Salah satu isu yang ditemukan adalah adanya pesan tanpa identitas pengirim (nilai NA pada kolom author). Pesan-pesan tersebut umumnya merupakan notifikasi sistem atau pesan non-individual, sehingga dikeluarkan dari analisis. Setelah proses pembersihan ini, dataset hanya berisi pesan yang memiliki pengirim yang jelas.

Langkah ini penting untuk menjamin bahwa analisis frekuensi, partisipasi, dan sentimen benar-benar mencerminkan perilaku komunikasi antaranggota grup.

glimpse(history)
## Rows: 4,570
## Columns: 6
## $ time       <dttm> 2025-01-02 09:28:00, 2025-01-02 09:33:00, 2025-01-02 09:36…
## $ author     <fct> Ofi Ana Sari, Raden Sinang, Mayang Sari, Ofi Ana Sari, Rade…
## $ text       <chr> "Pak @⁨Raden Sinang⁩ pembagian tim 2025 belum ade kah?  dah…
## $ source     <chr> "WhatsApp Chat with Ngobrolin Roempian2025.txt", "WhatsApp …
## $ emoji      <list> <"😅", "😂">, <NULL>, <NULL>, <NULL>, <NULL>, "😂", <NULL>, <…
## $ emoji_name <list> <"grinning face with sweat", "face with tears of joy">, <N…
# Cek Jumlah NA pada Kolom Author
history %>% summarise(na_author = sum(is.na(author)))
## # A tibble: 1 × 1
##   na_author
##       <int>
## 1        23
# Tampilkan Baris dengan Author NA
history %>% filter(is.na(author)) %>% head(10)
## # A tibble: 10 × 6
##    time                author text                      source emoji  emoji_name
##    <dttm>              <fct>  <chr>                     <chr>  <list> <list>    
##  1 2025-01-11 09:48:00 <NA>   Amalia Noviani was added  Whats… <NULL> <NULL>    
##  2 2025-01-11 09:48:00 <NA>   Amalia Noviani left       Whats… <NULL> <NULL>    
##  3 2025-02-21 03:30:00 <NA>   Bu Ida Eridawaty added H… Whats… <NULL> <NULL>    
##  4 2025-02-21 03:40:00 <NA>   Bu Nona Iriana was added  Whats… <NULL> <NULL>    
##  5 2025-02-21 03:40:00 <NA>   Bu Nona Iriana joined us… Whats… <NULL> <NULL>    
##  6 2025-02-21 03:40:00 <NA>   Amiek Chamami joined usi… Whats… <NULL> <NULL>    
##  7 2025-04-09 09:37:00 <NA>   Raden Sinang added Ruth … Whats… <NULL> <NULL>    
##  8 2025-06-04 10:50:00 <NA>   Raden Sinang added Nathi… Whats… <NULL> <NULL>    
##  9 2025-07-04 10:44:00 <NA>   Mayang Sari removed Herl… Whats… <NULL> <NULL>    
## 10 2025-07-04 10:44:00 <NA>   Mayang Sari removed Dwi … Whats… <NULL> <NULL>
# Hapus Baris yang Tidak Memiliki Author
history <- history %>% drop_na(author)

2 Total Chat

Analisis deskriptif awal dilakukan dengan menghitung total jumlah pesan yang terkirim selama periode pengamatan. Selanjutnya, dilakukan penghitungan jumlah pesan berdasarkan pengirim (author) untuk mengidentifikasi anggota grup yang paling aktif.

history %>%
  summarise(total_chat = n())
## # A tibble: 1 × 1
##   total_chat
##        <int>
## 1       4547

Hasilnya divisualisasikan dalam bentuk diagram batang horizontal. Visualisasi ini memberikan gambaran yang jelas mengenai distribusi kontribusi pesan antaranggota, sekaligus membantu mengidentifikasi pola dominasi komunikasi dalam grup.

history %>%
  count(author, sort = TRUE) %>%
  ggplot(aes(x = n, y = reorder(author, n), fill = author)) +
  geom_col(alpha = 0.9, width = 0.7) +
  geom_text(aes(label = n), hjust = -0.1, size = 3) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.2))) +
  scale_fill_viridis_d("Nama") +
  theme_minimal() +
  theme(
    legend.position = "none",
    axis.title.y = element_blank(),
    plot.margin = margin(10, 40, 10, 10)
  ) +
  ggtitle("Jumlah Chat yang Dikirim (1 Jan – 31 Des 2025)")

Visualisasi Chat

Untuk menganalisis pola temporal, format waktu dikonversi ke dalam bahasa Indonesia dengan mengatur sistem lokal. Selanjutnya, dibuat variabel hari (day) berdasarkan tanggal pengiriman pesan.

Distribusi jumlah pesan per hari dianalisis dan divisualisasikan, sehingga dapat diketahui hari-hari tertentu dengan intensitas komunikasi yang lebih tinggi. Analisis ini berguna untuk memahami ritme aktivitas grup, misalnya apakah percakapan lebih aktif pada hari kerja atau akhir pekan.

Selain itu, waktu pesan juga diuraikan lebih detail menggunakan lubridate menjadi komponen tahun, bulan, tanggal, jam, menit, dan detik. Informasi ini membuka peluang analisis lanjutan terkait jam sibuk komunikasi atau tren musiman.

## [1] "id_ID.utf8"
history %>%
  count(day) %>%
  ggplot(aes(x = n, y = reorder(day, n), fill = day)) + 
  geom_col() +
  geom_text(aes(label = n), hjust = -0.1, size = 3.5) +
  scale_x_continuous(expand = expansion(mult = c(0, 0.2))) +
  scale_fill_viridis_d() +
  theme_minimal() +
  theme(
    legend.position = "none"
  ) +
  labs(
    y = "Hari",
    x = "Jumlah Chat",
    title = "Jumlah Chat per Hari"
  )

3 Wordcloud

Untuk memahami topik dan kosakata yang dominan dalam percakapan grup, dilakukan analisis teks menggunakan pendekatan bag-of-words. Pendekatan ini merepresentasikan dokumen sebagai kumpulan kata tanpa memperhatikan urutan, sehingga memungkinkan analisis frekuensi kemunculan kata secara sistematis (Manning et al., 2008).

Pesan yang berupa placeholder media dikeluarkan dari analisis, kemudian dilakukan tokenisasi untuk memecah teks menjadi kata tunggal. Angka, kata sangat pendek, serta stopwords Bahasa Indonesia dihapus guna meningkatkan kualitas representasi teks. Kata-kata yang tersisa dihitung frekuensinya dan divisualisasikan dalam bentuk wordcloud, yang mencerminkan kata-kata dominan dalam percakapan grup (Silge & Robinson, 2017).

stopwords <- read.csv("stopwordbahasa.csv")
colnames(stopwords) <- c("stopword")

Kata yang paling sering digunakan (tanpa Stopwords)

history %>%
  filter(text != "<Media tidak disertakan>") %>%
  unnest_tokens(kata, text) %>%
  filter(
    !str_detect(kata, "\\d"),        # buang angka
    nchar(kata) > 2                  # buang kata <= 2 huruf
  ) %>%
  anti_join(stopwords, by = c("kata" = "stopword")) %>%
  count(kata, sort = TRUE) %>%
  wordcloud2()

4 Frekuensi Frase Tertentu

Selain analisis kata tunggal, dilakukan pula analisis frasa tertentu yang secara substantif mencerminkan dinamika komunikasi, seperti ekspresi persetujuan, permintaan, atau kesopanan.

Sebelum penghitungan, dilakukan normalisasi teks untuk menyamakan variasi penulisan dengan makna yang sama (misalnya “ok”, “oke”, “okay”). Setelah itu, frekuensi kemunculan frasa-frasa tertentu dihitung menggunakan pencocokan berbasis pola kata (regular expression). Pendekatan ini memungkinkan analisis yang lebih semantik dibanding sekadar frekuensi kata.

Normalisasi teks dilakukan untuk menyamakan variasi penulisan kata atau frasa yang memiliki makna serupa, sehingga analisis tidak terdistorsi oleh perbedaan ejaan atau gaya bahasa. Pendekatan ini penting dalam text mining karena variasi linguistik yang tinggi pada data percakapan informal dapat memengaruhi hasil analisis frekuensi dan interpretasi makna (Feldman & Sanger, 2007).

hasil_frasa <- count_phrases(text_norm, frasa)
hasil_frasa
## # A tibble: 7 × 2
##   frasa        jumlah
##   <chr>         <int>
## 1 baik pak          6
## 2 siap pak          2
## 3 noted             7
## 4 ok               14
## 5 terima kasih    271
## 6 maaf             66
## 7 tolong           27

Frekuensi Chat

Frekuensi pesan per hari dianalisis dan divisualisasikan menggunakan heatmap kalender, di mana warna merepresentasikan tingkat kepadatan pesan. Visualisasi ini memudahkan identifikasi hari-hari dengan aktivitas komunikasi yang sangat tinggi atau sangat rendah.

Selanjutnya, dilakukan analisis hari teramai pada setiap bulan. Dengan mengelompokkan data berdasarkan bulan dan hari, kemudian memilih hari dengan jumlah pesan tertinggi, diperoleh gambaran pola aktivitas dominan pada setiap bulan. Hasilnya divisualisasikan kembali dalam bentuk heatmap dua dimensi (hari × bulan).

library(dplyr)
library(lubridate)

hasil_hari_terramai <- history %>%
  mutate(
    bulan = month(time, label = TRUE, abbr = FALSE),
    hari = weekdays(as.Date(time))
  ) %>%
  group_by(bulan, hari) %>%
  summarise(jumlah_chat = n(), .groups = "drop") %>%
  group_by(bulan) %>%
  slice_max(jumlah_chat, n = 1, with_ties = FALSE) %>%
  arrange(bulan)

hasil_hari_terramai
## # A tibble: 12 × 3
## # Groups:   bulan [12]
##    bulan     hari   jumlah_chat
##    <ord>     <chr>        <int>
##  1 Januari   Jumat           73
##  2 Februari  Kamis          120
##  3 Maret     Rabu           236
##  4 April     Rabu           112
##  5 Mei       Rabu            48
##  6 Juni      Selasa          70
##  7 Juli      Rabu            96
##  8 Agustus   Jumat          175
##  9 September Senin          168
## 10 Oktober   Rabu           112
## 11 November  Jumat           82
## 12 Desember  Selasa         186

Tabel menunjukkan distribusi jumlah chat selama satu tahun yang dikelompokkan berdasarkan bulan dan hari dominan terjadinya aktivitas chat pada bulan tersebut.

Secara umum, aktivitas chat tidak merata sepanjang tahun dan menunjukkan pola fluktuatif yang cukup jelas.

  1. Puncak aktivitas chat terjadi pada bulan Maret dengan total 236 chat, yang didominasi pada hari Rabu. Hal ini mengindikasikan adanya peningkatan intensitas komunikasi pada periode awal tahun, yang kemungkinan berkaitan dengan aktivitas koordinasi, perencanaan, atau dinamika kerja pasca-awal tahun.

  2. Aktivitas chat relatif tinggi juga terlihat pada Agustus (175 chat, Jumat) dan September (168 chat, Senin). Pola ini dapat mencerminkan meningkatnya kebutuhan komunikasi menjelang atau sesudah periode tertentu, seperti evaluasi tengah tahun atau penyesuaian program.

  3. Aktivitas terendah tercatat pada bulan Mei dengan hanya 48 chat, meskipun masih didominasi hari Rabu. Rendahnya intensitas ini dapat mengindikasikan periode aktivitas yang lebih stabil atau berkurangnya kebutuhan koordinasi.

  4. Dari sisi hari, Rabu muncul sebagai hari yang paling sering menjadi hari dominan (Maret, April, Mei, Juli, Oktober), menunjukkan bahwa pertengahan minggu merupakan waktu yang relatif aktif untuk komunikasi.

  5. Sementara itu, Jumat dan Selasa juga beberapa kali muncul sebagai hari dominan, tetapi dengan frekuensi yang lebih rendah, sedangkan Senin hanya dominan pada satu bulan, yaitu September.

history %>%
  mutate(
    bulan = month(time, label = TRUE, abbr = FALSE),
    hari = factor(
      weekdays(as.Date(time)),
      levels = c("Senin","Selasa","Rabu","Kamis","Jumat","Sabtu","Minggu")
    )
  ) %>%
  count(bulan, hari) %>%
  ggplot(aes(hari, bulan, fill = n)) +
  geom_tile(color = "white") +
  scale_fill_viridis_c() +
  theme_minimal() +
  labs(
    title = "Hari Teramai Chat per Bulan",
    x = "Hari",
    y = "Bulan",
    fill = "Jumlah Chat"
  )

5 Sentimen Negatif

Analisis sentimen dilakukan secara eksploratif dengan fokus pada identifikasi indikasi sentimen negatif dalam percakapan grup. Pendekatan yang digunakan bersifat lexicon-based, yaitu dengan memanfaatkan daftar kata negatif yang secara konseptual merepresentasikan ketidakpuasan, kesalahan, atau kendala dalam komunikasi (Liu, 2012).

Setiap pesan diberikan skor negatif berdasarkan jumlah kemunculan kata negatif. Pesan dengan skor lebih dari nol dianggap mengandung sentimen negatif dan dianalisis lebih lanjut.

Untuk menghindari duplikasi makna akibat variasi redaksi kalimat, diterapkan pendekatan Term Frequency–Inverse Document Frequency (TF-IDF) sebagai metode pembobotan kata. TF-IDF memberikan bobot lebih tinggi pada kata yang bersifat spesifik terhadap suatu pesan dan menurunkan pengaruh kata yang umum muncul di banyak pesan (Salton & Buckley, 1988).

Selanjutnya, tingkat kemiripan antar pesan diukur menggunakan cosine similarity berbasis vektor TF-IDF. Pendekatan ini memungkinkan identifikasi pesan-pesan yang secara semantik memiliki makna serupa meskipun berbeda secara struktur kalimat (Singhal, 2001).

pesan_makna_unik <- sentimen_chat %>%
  filter(!text_clean %in% similarity$item2) %>%
  arrange(desc(skor_negatif))

pesan_makna_unik %>%
  select(time, author, text, skor_negatif)
## # A tibble: 259 × 4
##    time                author                   text                skor_negatif
##    <dttm>              <fct>                    <chr>                      <int>
##  1 2025-04-14 10:43:00 Karunia Ramadhani        "Selamat pagi Bapa…            9
##  2 2025-06-18 08:09:00 Mayang Sari              "Info kemarin dr J…            6
##  3 2025-12-30 03:31:00 Karunia Ramadhani        "Sehubungan dengan…            5
##  4 2025-03-26 09:15:00 Ofi Ana Sari             "disni sy bukan *p…            4
##  5 2025-03-26 09:16:00 Freshy Windy             "Bukan mbaaakkk ka…            4
##  6 2025-04-16 06:12:00 Asy-Syaja'ul Haqqul Amin "Assalamu'alaikum …            4
##  7 2025-04-21 10:23:00 Raden Sinang             "Usul saya, inisia…            4
##  8 2025-10-15 08:56:00 Karunia Ramadhani        "Untuk konfirmasi …            4
##  9 2025-09-25 02:10:00 Raden Sinang             "Yth.Teman2, menin…            3
## 10 2025-01-02 04:49:00 Ketut Krisna             "Bapak/Ibu mohon u…            2
## # ℹ 249 more rows

6 Penutup

Secara keseluruhan, analisis ini mengombinasikan pendekatan deskriptif dan text mining untuk menggambarkan dinamika komunikasi dalam grup WhatsApp. Melalui analisis frekuensi, visualisasi temporal, eksplorasi kosakata, serta reduksi semantik pesan negatif, penelitian ini menunjukkan bagaimana data percakapan digital dapat dimanfaatkan untuk memahami pola interaksi sosial secara lebih sistematis. Pendekatan ini sejalan dengan praktik analisis teks modern yang menekankan integrasi metode statistik dan linguistik dalam pengolahan data tidak terstruktur (Manning et al., 2008; Silge & Robinson, 2017).

7 Referensi

[1] Feldman, R., & Sanger, J. (2007). The text mining handbook: Advanced approaches in analyzing unstructured data. Cambridge University Press.

[2] Liu, B. (2012). Sentiment analysis and opinion mining. Morgan & Claypool Publishers. https://doi.org/10.2200/S00416ED1V01Y201204HLT016

[3] Manning, C. D., Raghavan, P., & Schütze, H. (2008). Introduction to information retrieval. Cambridge University Press.

[4] Salton, G., & Buckley, C. (1988). Term-weighting approaches in automatic text retrieval. Information Processing & Management, 24(5), 513–523. https://doi.org/10.1016/0306-4573(88)90021-0

[5] Silge, J., & Robinson, D. (2017). Text mining with R: A tidy approach. O’Reilly Media.

[6] Singhal, A. (2001). Modern information retrieval: A brief overview. IEEE Data Engineering Bulletin, 24(4), 35–43.


Direktorat Statistik Kesejahteraan Rakyat, BPS,

LS0tDQp0aXRsZTogIkFuYWxpc2lzIFBlcmNha2FwYW4gV2hhdHNBcHAgPGJyPiBkZW5nYW4gUGVuZGVrYXRhbiBUZXh0IE1pbmluZyINCnN1YnRpdGxlOiAiQWt0aXZpdGFzIFdoYXRzQXBwIEdydXAgKEFrdXNpc2kgZGF0YTogMSBKYW51YXJpIDIwMjUpIg0KYXV0aG9yOiAiU2FwdGEgSGFzdGhvIFBvbmNvIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IGpvdXJuYWwNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGU+DQpib2R5ew0KdGV4dC1hbGlnbjoganVzdGlmeX0NCjwvc3R5bGU+DQpgYGANCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1UUlVFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCl9UZXh0IG1pbmluZ18gbWVydXBha2FuIHBlbmRla2F0YW4gYW5hbGl0aXMgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuZ2Vrc3RyYWtzaSBpbmZvcm1hc2kgZGFuIHBvbGEgYmVybWFrbmEgZGFyaSBkYXRhIHRla3MgdGlkYWsgdGVyc3RydWt0dXIsIHNlcGVydGkgcGVyY2FrYXBhbiBkYXJpbmcsIGRva3VtZW4sIG1hdXB1biBtZWRpYSBzb3NpYWwuIEJlcmJlZGEgZGVuZ2FuIGRhdGEgbnVtZXJpayB5YW5nIG1lbWlsaWtpIHN0cnVrdHVyIGJha3UsIGRhdGEgdGVrcyBiZXJzaWZhdCBiZWJhcywga2F5YSBrb250ZWtzLCBkYW4gbWVuZ2FuZHVuZyB2YXJpYXNpIGJhaGFzYSB5YW5nIHRpbmdnaSwgc2VoaW5nZ2EgbWVtZXJsdWthbiB0ZWtuaWsga2h1c3VzIGRhbGFtIHBlbmdvbGFoYW5ueWEuIE1lbGFsdWkgdGFoYXBhbiBzZXBlcnRpIHBlbWJlcnNpaGFuIHRla3MsIHRva2VuaXNhc2ksIG5vcm1hbGlzYXNpLCBkYW4gcGVtYm9ib3RhbiBrYXRhLCBfdGV4dCBtaW5pbmdfIG1lbXVuZ2tpbmthbiB0ZWtzIGRpdWJhaCBtZW5qYWRpIHJlcHJlc2VudGFzaSB0ZXJzdHJ1a3R1ciB5YW5nIGRhcGF0IGRpYW5hbGlzaXMgc2VjYXJhIGt1YW50aXRhdGlmLiBQZW5kZWthdGFuIGluaSBzZW1ha2luIHJlbGV2YW4gc2VpcmluZyBtZW5pbmdrYXRueWEgdm9sdW1lIGRhdGEgdGVrc3R1YWwgZGFsYW0gYWt0aXZpdGFzIGtvbXVuaWthc2kgZGlnaXRhbC4NCg0KVHVqdWFuIHV0YW1hIF90ZXh0IG1pbmluZ18gYWRhbGFoIHVudHVrIG1lbmdpZGVudGlmaWthc2kgcG9sYSwga2VjZW5kZXJ1bmdhbiwgZGFuIG1ha25hIHRlcnNlbWJ1bnlpIHlhbmcgdGlkYWsgbXVkYWggZGl0YW5na2FwIG1lbGFsdWkgcGVtYmFjYWFuIG1hbnVhbCwgdGVydXRhbWEgcGFkYSBkYXRhIGJlcnNrYWxhIGJlc2FyLiBEYWxhbSBrb250ZWtzIGFuYWxpc2lzIHBlcmNha2FwYW4sIF90ZXh0IG1pbmluZ18gZGlndW5ha2FuIHVudHVrIG1lbWFoYW1pIGRpbmFtaWthIGtvbXVuaWthc2ksIG1lbmd1a3VyIGludGVuc2l0YXMgZGFuIGZva3VzIHBlbWJhaGFzYW4sIHNlcnRhIG1lbmRldGVrc2kgaW5kaWthc2kgc2VudGltZW4gYXRhdSBpc3UgdGVydGVudHUgeWFuZyBtdW5jdWwgYmVydWxhbmcuIERlbmdhbiBkZW1pa2lhbiwgX3RleHQgbWluaW5nXyB0aWRhayBoYW55YSBiZXJmdW5nc2kgc2ViYWdhaSBhbGF0IGVrc3Bsb3Jhc2kgZGF0YSwgdGV0YXBpIGp1Z2Egc2ViYWdhaSBkYXNhciBwZW5nYW1iaWxhbiBrZXB1dHVzYW4gYmVyYmFzaXMgYnVrdGksIGV2YWx1YXNpIGtlYmlqYWthbiwgZGFuIHBlbWFoYW1hbiBwZXJpbGFrdSBrb211bmlrYXNpIHNlY2FyYSBzaXN0ZW1hdGlzIGRhbiBvYmpla3RpZi4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodGlkeXRleHQpDQpsaWJyYXJ5KHJ3aGF0c2FwcCkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh3b3JkY2xvdWQyKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0Kc2V0d2QoIkQ6XFwyLiBQZW5nZW1iYW5nYW4gZGlyaVxcMSBFeGVyY2lzZSBCYWd1c1xcVGV4dCBhbmQgU2NyYXBwaW5nXFwiKQ0KYGBgDQoNCiMgTG9hZCBEYXRhDQoNCkRhdGEgcGVyY2FrYXBhbiBXaGF0c0FwcCBkaXBlcm9sZWggZGFyaSBmaWxlIGVrc3BvciByaXdheWF0IGNoYXQgZ3J1cCBkYWxhbSBmb3JtYXQgLnR4dC4gRGF0YSBrZW11ZGlhbiBkaWJhY2EgbWVuZ2d1bmFrYW4gZnVuZ3NpIGByd2FfcmVhZCgpYCBkYXJpIHBha2V0IGByd2hhdHNhcHBgLiBVbnR1ayBtZW5qYWdhIHJlbGV2YW5zaSBhbmFsaXNpcywgZGF0YSBkaWJhdGFzaSBoYW55YSBwYWRhIHBlc2FuIHlhbmcgZGlraXJpbSBtdWxhaSAxIEphbnVhcmkgMjAyNSwgc2VoaW5nZ2EgYW5hbGlzaXMgbWVyZXByZXNlbnRhc2lrYW4gZGluYW1pa2Ega29tdW5pa2FzaSBzZXBhbmphbmcgdGFodW4gYmVyamFsYW4uDQoNClRhaGFwIGF3YWwgZWtzcGxvcmFzaSBkYXRhIGRpbGFrdWthbiBkZW5nYW4gbWVuYW1waWxrYW4gYmViZXJhcGEgYmFyaXMgcGVydGFtYSBkYW4gbWVtZXJpa3NhIHN0cnVrdHVyIGRhdGEgbWVuZ2d1bmFrYW4gYGdsaW1wc2UoKWAuIFBlbWVyaWtzYWFuIGluaSBiZXJ0dWp1YW4gdW50dWsgbWVtYXN0aWthbiBrb25zaXN0ZW5zaSB2YXJpYWJlbCwga2h1c3VzbnlhIGtvbG9tIHdha3R1IChgdGltZWApLCBwZW51bGlzIHBlc2FuIChgYXV0aG9yYCksIGRhbiBpc2kgcGVzYW4gKGB0ZXh0YCkuDQoNCkFuYWxpc2lzIHBlcmNha2FwYW4gV2hhdHNBcHAgZGlsYWt1a2FuIG1lbmdndW5ha2FuIHBlbmRla2F0YW4gX3RleHQgbWluaW5nXywgeWFpdHUgc2VyYW5na2FpYW4gdGVrbmlrIHVudHVrIG1lbmdla3N0cmFrc2kgaW5mb3JtYXNpIGJlcm1ha25hIGRhcmkgZGF0YSB0ZWtzIHRpZGFrIHRlcnN0cnVrdHVyLiBQZW5kZWthdGFuIGluaSBtZW5jYWt1cCB0YWhhcGFuIHBlbWJlcnNpaGFuIHRla3MsIHRva2VuaXNhc2ksIHBlbWJvYm90YW4ga2F0YSwgc2VydGEgYW5hbGlzaXMgZnJla3VlbnNpIGRhbiBrZW1pcmlwYW4gdGVrcyB1bnR1ayBtZW5naWRlbnRpZmlrYXNpIHBvbGEga29tdW5pa2FzaSB5YW5nIHRlcnNlbWJ1bnlpIGRhbGFtIGRhdGEgcGVyY2FrYXBhbiAoRmVsZG1hbiAmIFNhbmdlciwgMjAwNzsgTWFubmluZyBldCBhbC4sIDIwMDgpLg0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmhpc3RvcnkgPC0gcndhX3JlYWQoIldoYXRzQXBwIENoYXQgd2l0aCBOZ29icm9saW4gUm9lbXBpYW4yMDI1LnR4dCIpICU+JQ0KICBmaWx0ZXIoYXMuRGF0ZSh0aW1lKSA+PSBhcy5EYXRlKCIyMDI1LTAxLTAxIikpDQpoZWFkKGhpc3RvcnkpDQpgYGANCg0KKipQZW1iZXJzaWhhbiBEYXRhIChEYXRhIENsZWFuaW5nKSoqDQoNClNhbGFoIHNhdHUgaXN1IHlhbmcgZGl0ZW11a2FuIGFkYWxhaCBhZGFueWEgcGVzYW4gdGFucGEgaWRlbnRpdGFzIHBlbmdpcmltIChuaWxhaSBOQSBwYWRhIGtvbG9tIGF1dGhvcikuIFBlc2FuLXBlc2FuIHRlcnNlYnV0IHVtdW1ueWEgbWVydXBha2FuIG5vdGlmaWthc2kgc2lzdGVtIGF0YXUgcGVzYW4gbm9uLWluZGl2aWR1YWwsIHNlaGluZ2dhIGRpa2VsdWFya2FuIGRhcmkgYW5hbGlzaXMuIFNldGVsYWggcHJvc2VzIHBlbWJlcnNpaGFuIGluaSwgZGF0YXNldCBoYW55YSBiZXJpc2kgcGVzYW4geWFuZyBtZW1pbGlraSBwZW5naXJpbSB5YW5nIGplbGFzLg0KDQpMYW5na2FoIGluaSBwZW50aW5nIHVudHVrIG1lbmphbWluIGJhaHdhIGFuYWxpc2lzIGZyZWt1ZW5zaSwgcGFydGlzaXBhc2ksIGRhbiBzZW50aW1lbiBiZW5hci1iZW5hciBtZW5jZXJtaW5rYW4gcGVyaWxha3Uga29tdW5pa2FzaSBhbnRhcmFuZ2dvdGEgZ3J1cC4NCg0KYGBge3J9DQpnbGltcHNlKGhpc3RvcnkpDQoNCiMgQ2VrIEp1bWxhaCBOQSBwYWRhIEtvbG9tIEF1dGhvcg0KaGlzdG9yeSAlPiUgc3VtbWFyaXNlKG5hX2F1dGhvciA9IHN1bShpcy5uYShhdXRob3IpKSkNCg0KIyBUYW1waWxrYW4gQmFyaXMgZGVuZ2FuIEF1dGhvciBOQQ0KaGlzdG9yeSAlPiUgZmlsdGVyKGlzLm5hKGF1dGhvcikpICU+JSBoZWFkKDEwKQ0KDQojIEhhcHVzIEJhcmlzIHlhbmcgVGlkYWsgTWVtaWxpa2kgQXV0aG9yDQpoaXN0b3J5IDwtIGhpc3RvcnkgJT4lIGRyb3BfbmEoYXV0aG9yKQ0KYGBgDQoNCiMgVG90YWwgQ2hhdA0KDQpBbmFsaXNpcyBkZXNrcmlwdGlmIGF3YWwgZGlsYWt1a2FuIGRlbmdhbiBtZW5naGl0dW5nIHRvdGFsIGp1bWxhaCBwZXNhbiB5YW5nIHRlcmtpcmltIHNlbGFtYSBwZXJpb2RlIHBlbmdhbWF0YW4uIFNlbGFuanV0bnlhLCBkaWxha3VrYW4gcGVuZ2hpdHVuZ2FuIGp1bWxhaCBwZXNhbiBiZXJkYXNhcmthbiBwZW5naXJpbSAoYXV0aG9yKSB1bnR1ayBtZW5naWRlbnRpZmlrYXNpIGFuZ2dvdGEgZ3J1cCB5YW5nIHBhbGluZyBha3RpZi4NCg0KYGBge3J9DQpoaXN0b3J5ICU+JQ0KICBzdW1tYXJpc2UodG90YWxfY2hhdCA9IG4oKSkNCmBgYA0KDQpIYXNpbG55YSBkaXZpc3VhbGlzYXNpa2FuIGRhbGFtIGJlbnR1ayBkaWFncmFtIGJhdGFuZyBob3Jpem9udGFsLiBWaXN1YWxpc2FzaSBpbmkgbWVtYmVyaWthbiBnYW1iYXJhbiB5YW5nIGplbGFzIG1lbmdlbmFpIGRpc3RyaWJ1c2kga29udHJpYnVzaSBwZXNhbiBhbnRhcmFuZ2dvdGEsIHNla2FsaWd1cyBtZW1iYW50dSBtZW5naWRlbnRpZmlrYXNpIHBvbGEgZG9taW5hc2kga29tdW5pa2FzaSBkYWxhbSBncnVwLg0KDQpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9DQpoaXN0b3J5ICU+JQ0KICBjb3VudChhdXRob3IsIHNvcnQgPSBUUlVFKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHJlb3JkZXIoYXV0aG9yLCBuKSwgZmlsbCA9IGF1dGhvcikpICsNCiAgZ2VvbV9jb2woYWxwaGEgPSAwLjksIHdpZHRoID0gMC43KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgaGp1c3QgPSAtMC4xLCBzaXplID0gMykgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMikpKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKCJOYW1hIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDEwLCA0MCwgMTAsIDEwKQ0KICApICsNCiAgZ2d0aXRsZSgiSnVtbGFoIENoYXQgeWFuZyBEaWtpcmltICgxIEphbiDigJMgMzEgRGVzIDIwMjUpIikNCg0KYGBgDQoNCioqVmlzdWFsaXNhc2kgQ2hhdCoqDQoNCg0KVW50dWsgbWVuZ2FuYWxpc2lzIHBvbGEgdGVtcG9yYWwsIGZvcm1hdCB3YWt0dSBkaWtvbnZlcnNpIGtlIGRhbGFtIGJhaGFzYSBJbmRvbmVzaWEgZGVuZ2FuIG1lbmdhdHVyIHNpc3RlbSBsb2thbC4gU2VsYW5qdXRueWEsIGRpYnVhdCB2YXJpYWJlbCBoYXJpIChfZGF5XykgYmVyZGFzYXJrYW4gdGFuZ2dhbCBwZW5naXJpbWFuIHBlc2FuLg0KDQpEaXN0cmlidXNpIGp1bWxhaCBwZXNhbiBwZXIgaGFyaSBkaWFuYWxpc2lzIGRhbiBkaXZpc3VhbGlzYXNpa2FuLCBzZWhpbmdnYSBkYXBhdCBkaWtldGFodWkgaGFyaS1oYXJpIHRlcnRlbnR1IGRlbmdhbiBpbnRlbnNpdGFzIGtvbXVuaWthc2kgeWFuZyBsZWJpaCB0aW5nZ2kuIEFuYWxpc2lzIGluaSBiZXJndW5hIHVudHVrIG1lbWFoYW1pIHJpdG1lIGFrdGl2aXRhcyBncnVwLCBtaXNhbG55YSBhcGFrYWggcGVyY2FrYXBhbiBsZWJpaCBha3RpZiBwYWRhIGhhcmkga2VyamEgYXRhdSBha2hpciBwZWthbi4NCg0KU2VsYWluIGl0dSwgd2FrdHUgcGVzYW4ganVnYSBkaXVyYWlrYW4gbGViaWggZGV0YWlsIG1lbmdndW5ha2FuIGBsdWJyaWRhdGVgIG1lbmphZGkga29tcG9uZW4gdGFodW4sIGJ1bGFuLCB0YW5nZ2FsLCBqYW0sIG1lbml0LCBkYW4gZGV0aWsuIEluZm9ybWFzaSBpbmkgbWVtYnVrYSBwZWx1YW5nIGFuYWxpc2lzIGxhbmp1dGFuIHRlcmthaXQgamFtIHNpYnVrIGtvbXVuaWthc2kgYXRhdSB0cmVuIG11c2ltYW4uDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBNZW5nYXR1ciBGb3JtYXQgSGFyaSBkYWxhbSBCYWhhc2EgSW5kb25lc2lhDQpTeXMuc2V0bG9jYWxlKCJMQ19USU1FIiwgImlkX0lELnV0ZjgiKQ0KDQojIE1lbmFtYmFoa2FuIEtvbG9tIEhhcmkNCmhpc3RvcnkgPC0gaGlzdG9yeSAlPiUNCiAgbXV0YXRlKGRheSA9IHdlZWtkYXlzKGFzLkRhdGUodGltZSkpKQ0KDQojIEtvbnZlcnNpIEZha3RvciBIYXJpDQpoYXJpIDwtIGMoIlNlbmluIiwgIlNlbGFzYSIsICJSYWJ1IiwgIkthbWlzIiwgIkp1bWF0IiwgIlNhYnR1IiwgIk1pbmdndSIpDQpoaXN0b3J5JGRheSA8LSBmYWN0b3IoaGlzdG9yeSRkYXksIGxldmVscyA9IGhhcmkpDQpgYGANCg0KYGBge3J9DQpoaXN0b3J5ICU+JQ0KICBjb3VudChkYXkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gcmVvcmRlcihkYXksIG4pLCBmaWxsID0gZGF5KSkgKyANCiAgZ2VvbV9jb2woKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBuKSwgaGp1c3QgPSAtMC4xLCBzaXplID0gMy41KSArDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgMC4yKSkpICsNCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApICsNCiAgbGFicygNCiAgICB5ID0gIkhhcmkiLA0KICAgIHggPSAiSnVtbGFoIENoYXQiLA0KICAgIHRpdGxlID0gIkp1bWxhaCBDaGF0IHBlciBIYXJpIg0KICApDQpgYGANCg0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KI0Vrc3RyYWtzaSBUYW5nZ2FsIGRhbiBXYWt0dQ0KaGlzdG9yeSA8LSBoaXN0b3J5ICU+JQ0KICBtdXRhdGUoDQogICAgdGltZSA9IHltZF9obXModGltZSksDQogICAgdGFodW4gPSB5ZWFyKHRpbWUpLA0KICAgIGJ1bGFuID0gbW9udGgodGltZSwgbGFiZWwgPSBUUlVFLCBhYmJyID0gRkFMU0UpLA0KICAgIHRhbmdnYWwgPSBkYXkodGltZSksDQogICAgamFtID0gaG91cih0aW1lKSwNCiAgICBtZW5pdCA9IG1pbnV0ZSh0aW1lKSwNCiAgICBkZXRpayA9IHNlY29uZCh0aW1lKQ0KICApDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBlY2hvPUZBTFNFfQ0KbGlicmFyeShEVCkNCkRUOjpkYXRhdGFibGUoaGlzdG9yeSkNCmBgYA0KDQojIFdvcmRjbG91ZA0KDQpVbnR1ayBtZW1haGFtaSB0b3BpayBkYW4ga29zYWthdGEgeWFuZyBkb21pbmFuIGRhbGFtIHBlcmNha2FwYW4gZ3J1cCwgZGlsYWt1a2FuIGFuYWxpc2lzIHRla3MgbWVuZ2d1bmFrYW4gcGVuZGVrYXRhbiBfYmFnLW9mLXdvcmRzXy4gUGVuZGVrYXRhbiBpbmkgbWVyZXByZXNlbnRhc2lrYW4gZG9rdW1lbiBzZWJhZ2FpIGt1bXB1bGFuIGthdGEgdGFucGEgbWVtcGVyaGF0aWthbiB1cnV0YW4sIHNlaGluZ2dhIG1lbXVuZ2tpbmthbiBhbmFsaXNpcyBmcmVrdWVuc2kga2VtdW5jdWxhbiBrYXRhIHNlY2FyYSBzaXN0ZW1hdGlzIChNYW5uaW5nIGV0IGFsLiwgMjAwOCkuDQoNClBlc2FuIHlhbmcgYmVydXBhIF9wbGFjZWhvbGRlcl8gbWVkaWEgZGlrZWx1YXJrYW4gZGFyaSBhbmFsaXNpcywga2VtdWRpYW4gZGlsYWt1a2FuIHRva2VuaXNhc2kgdW50dWsgbWVtZWNhaCB0ZWtzIG1lbmphZGkga2F0YSB0dW5nZ2FsLiBBbmdrYSwga2F0YSBzYW5nYXQgcGVuZGVrLCBzZXJ0YSBfc3RvcHdvcmRzXyBCYWhhc2EgSW5kb25lc2lhIGRpaGFwdXMgZ3VuYSBtZW5pbmdrYXRrYW4ga3VhbGl0YXMgcmVwcmVzZW50YXNpIHRla3MuIEthdGEta2F0YSB5YW5nIHRlcnNpc2EgZGloaXR1bmcgZnJla3VlbnNpbnlhIGRhbiBkaXZpc3VhbGlzYXNpa2FuIGRhbGFtIGJlbnR1ayB3b3JkY2xvdWQsIHlhbmcgbWVuY2VybWlua2FuIGthdGEta2F0YSBkb21pbmFuIGRhbGFtIHBlcmNha2FwYW4gZ3J1cCAoU2lsZ2UgJiBSb2JpbnNvbiwgMjAxNykuDQoNCmBgYHtyfQ0Kc3RvcHdvcmRzIDwtIHJlYWQuY3N2KCJzdG9wd29yZGJhaGFzYS5jc3YiKQ0KY29sbmFtZXMoc3RvcHdvcmRzKSA8LSBjKCJzdG9wd29yZCIpDQpgYGANCg0KS2F0YSB5YW5nIHBhbGluZyBzZXJpbmcgZGlndW5ha2FuICh0YW5wYSBTdG9wd29yZHMpDQoNCmBgYHtyfQ0KaGlzdG9yeSAlPiUNCiAgZmlsdGVyKHRleHQgIT0gIjxNZWRpYSB0aWRhayBkaXNlcnRha2FuPiIpICU+JQ0KICB1bm5lc3RfdG9rZW5zKGthdGEsIHRleHQpICU+JQ0KICBmaWx0ZXIoDQogICAgIXN0cl9kZXRlY3Qoa2F0YSwgIlxcZCIpLCAgICAgICAgIyBidWFuZyBhbmdrYQ0KICAgIG5jaGFyKGthdGEpID4gMiAgICAgICAgICAgICAgICAgICMgYnVhbmcga2F0YSA8PSAyIGh1cnVmDQogICkgJT4lDQogIGFudGlfam9pbihzdG9wd29yZHMsIGJ5ID0gYygia2F0YSIgPSAic3RvcHdvcmQiKSkgJT4lDQogIGNvdW50KGthdGEsIHNvcnQgPSBUUlVFKSAlPiUNCiAgd29yZGNsb3VkMigpDQpgYGANCg0KIyBGcmVrdWVuc2kgRnJhc2UgVGVydGVudHUNCg0KU2VsYWluIGFuYWxpc2lzIGthdGEgdHVuZ2dhbCwgZGlsYWt1a2FuIHB1bGEgYW5hbGlzaXMgZnJhc2EgdGVydGVudHUgeWFuZyBzZWNhcmEgc3Vic3RhbnRpZiBtZW5jZXJtaW5rYW4gZGluYW1pa2Ega29tdW5pa2FzaSwgc2VwZXJ0aSBla3NwcmVzaSBwZXJzZXR1anVhbiwgcGVybWludGFhbiwgYXRhdSBrZXNvcGFuYW4uDQoNClNlYmVsdW0gcGVuZ2hpdHVuZ2FuLCBkaWxha3VrYW4gbm9ybWFsaXNhc2kgdGVrcyB1bnR1ayBtZW55YW1ha2FuIHZhcmlhc2kgcGVudWxpc2FuIGRlbmdhbiBtYWtuYSB5YW5nIHNhbWEgKG1pc2FsbnlhIOKAnG9r4oCdLCDigJxva2XigJ0sIOKAnG9rYXnigJ0pLiBTZXRlbGFoIGl0dSwgZnJla3VlbnNpIGtlbXVuY3VsYW4gZnJhc2EtZnJhc2EgdGVydGVudHUgZGloaXR1bmcgbWVuZ2d1bmFrYW4gcGVuY29jb2thbiBiZXJiYXNpcyBwb2xhIGthdGEgKF9yZWd1bGFyIGV4cHJlc3Npb25fKS4gUGVuZGVrYXRhbiBpbmkgbWVtdW5na2lua2FuIGFuYWxpc2lzIHlhbmcgbGViaWggc2VtYW50aWsgZGliYW5kaW5nIHNla2FkYXIgZnJla3VlbnNpIGthdGEuDQoNCk5vcm1hbGlzYXNpIHRla3MgZGlsYWt1a2FuIHVudHVrIG1lbnlhbWFrYW4gdmFyaWFzaSBwZW51bGlzYW4ga2F0YSBhdGF1IGZyYXNhIHlhbmcgbWVtaWxpa2kgbWFrbmEgc2VydXBhLCBzZWhpbmdnYSBhbmFsaXNpcyB0aWRhayB0ZXJkaXN0b3JzaSBvbGVoIHBlcmJlZGFhbiBlamFhbiBhdGF1IGdheWEgYmFoYXNhLiBQZW5kZWthdGFuIGluaSBwZW50aW5nIGRhbGFtIF90ZXh0IG1pbmluZ18ga2FyZW5hIHZhcmlhc2kgbGluZ3Vpc3RpayB5YW5nIHRpbmdnaSBwYWRhIGRhdGEgcGVyY2FrYXBhbiBpbmZvcm1hbCBkYXBhdCBtZW1lbmdhcnVoaSBoYXNpbCBhbmFsaXNpcyBmcmVrdWVuc2kgZGFuIGludGVycHJldGFzaSBtYWtuYSAoRmVsZG1hbiAmIFNhbmdlciwgMjAwNykuDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHB1cnJyKQ0KbGlicmFyeSh0aWJibGUpDQoNCiMgTm9ybWFsaXNhc2kgdGVrcyAobWFrbmEgZGlzYW1ha2FuKQ0Kbm9ybWFsaXplX3RleHQgPC0gZnVuY3Rpb24odGV4dCkgew0KICB0ZXh0ICU+JQ0KICAgIHN0cl90b19sb3dlcigpICU+JQ0KICAgIHN0cl9yZXBsYWNlX2FsbCgiXFxiKG9rZXxva2F5fG9rZXl8b2spXGIiLCAib2siKSAlPiUNCiAgICBzdHJfcmVwbGFjZV9hbGwoIlxcYihtYWthc2lofG1ha2FzaXx0aGFua3N8dGh4KVxiIiwgInRlcmltYSBrYXNpaCIpICU+JQ0KICAgIHN0cl9yZXBsYWNlX2FsbCgiXFxiKHNpYXB8c2lhcCBQYWt8c2lhcCwgUGFrfHNpYXAgcGFrKVxiIiwgInNpYXAgcGFrIikgJT4lDQogICAgc3RyX3JlcGxhY2VfYWxsKCJcXHMrIiwgIiAiKSAlPiUNCiAgICBzdHJfdHJpbSgpDQp9DQoNCiMgSGl0dW5nIGZyZWt1ZW5zaSBmcmFzYQ0KY291bnRfcGhyYXNlcyA8LSBmdW5jdGlvbih0ZXh0LCBwaHJhc2VzKSB7DQogIG1hcF9kZihwaHJhc2VzLCBmdW5jdGlvbihwKSB7DQogICAgdGliYmxlKA0KICAgICAgZnJhc2EgPSBwLA0KICAgICAganVtbGFoID0gc3VtKA0KICAgICAgICBzdHJfZGV0ZWN0KHRleHQsIHBhc3RlMCgiXFxiIiwgcCwgIlxcYiIpKSwNCiAgICAgICAgbmEucm0gPSBUUlVFDQogICAgICApDQogICAgKQ0KICB9KQ0KfQ0KDQojIE5vcm1hbGlzYXNpIHNlbHVydWggY2hhdA0KdGV4dF9ub3JtIDwtIG5vcm1hbGl6ZV90ZXh0KGhpc3RvcnkkdGV4dCkNCg0KIyBEYWZ0YXIgZnJhc2EgeWFuZyBpbmdpbiBkaWhpdHVuZw0KZnJhc2EgPC0gYygNCiAgImJhaWsgcGFrIiwNCiAgInNpYXAgcGFrIiwNCiAgIm5vdGVkIiwNCiAgIm9rIiwNCiAgInRlcmltYSBrYXNpaCIsDQogICJtYWFmIiwNCiAgInRvbG9uZyINCikNCmBgYA0KDQpgYGB7cn0NCmhhc2lsX2ZyYXNhIDwtIGNvdW50X3BocmFzZXModGV4dF9ub3JtLCBmcmFzYSkNCmhhc2lsX2ZyYXNhDQpgYGANCg0KKipGcmVrdWVuc2kgQ2hhdCoqDQoNCkZyZWt1ZW5zaSBwZXNhbiBwZXIgaGFyaSBkaWFuYWxpc2lzIGRhbiBkaXZpc3VhbGlzYXNpa2FuIG1lbmdndW5ha2FuIGhlYXRtYXAga2FsZW5kZXIsIGRpIG1hbmEgd2FybmEgbWVyZXByZXNlbnRhc2lrYW4gdGluZ2thdCBrZXBhZGF0YW4gcGVzYW4uIFZpc3VhbGlzYXNpIGluaSBtZW11ZGFoa2FuIGlkZW50aWZpa2FzaSBoYXJpLWhhcmkgZGVuZ2FuIGFrdGl2aXRhcyBrb211bmlrYXNpIHlhbmcgc2FuZ2F0IHRpbmdnaSBhdGF1IHNhbmdhdCByZW5kYWguDQoNClNlbGFuanV0bnlhLCBkaWxha3VrYW4gYW5hbGlzaXMgaGFyaSB0ZXJhbWFpIHBhZGEgc2V0aWFwIGJ1bGFuLiBEZW5nYW4gbWVuZ2Vsb21wb2trYW4gZGF0YSBiZXJkYXNhcmthbiBidWxhbiBkYW4gaGFyaSwga2VtdWRpYW4gbWVtaWxpaCBoYXJpIGRlbmdhbiBqdW1sYWggcGVzYW4gdGVydGluZ2dpLCBkaXBlcm9sZWggZ2FtYmFyYW4gcG9sYSBha3Rpdml0YXMgZG9taW5hbiBwYWRhIHNldGlhcCBidWxhbi4gSGFzaWxueWEgZGl2aXN1YWxpc2FzaWthbiBrZW1iYWxpIGRhbGFtIGJlbnR1ayBoZWF0bWFwIGR1YSBkaW1lbnNpIChoYXJpIMOXIGJ1bGFuKS4NCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KYWFhIDwtIGhpc3RvcnkgJT4lDQogIG11dGF0ZSh0YW5nZ2FsID0gYXMuRGF0ZSh0aW1lKSkgJT4lDQogIGNvdW50KHRhbmdnYWwpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB0YW5nZ2FsLCB5ID0gMSwgZmlsbCA9IG4pKSArDQogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiZ3JlZW4iLCBoaWdoID0gInJlZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHRpdGxlID0gIkZyZWt1ZW5zaSBQZXNhbiBwZXIgSGFyaSIsIHggPSAiVGFuZ2dhbCIsIHkgPSBOVUxMLCBmaWxsID0gIkp1bWxhaCBQZXNhbiIpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCg0KaGFzaWxfaGFyaV90ZXJyYW1haSA8LSBoaXN0b3J5ICU+JQ0KICBtdXRhdGUoDQogICAgYnVsYW4gPSBtb250aCh0aW1lLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBGQUxTRSksDQogICAgaGFyaSA9IHdlZWtkYXlzKGFzLkRhdGUodGltZSkpDQogICkgJT4lDQogIGdyb3VwX2J5KGJ1bGFuLCBoYXJpKSAlPiUNCiAgc3VtbWFyaXNlKGp1bWxhaF9jaGF0ID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUNCiAgZ3JvdXBfYnkoYnVsYW4pICU+JQ0KICBzbGljZV9tYXgoanVtbGFoX2NoYXQsIG4gPSAxLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lDQogIGFycmFuZ2UoYnVsYW4pDQoNCmhhc2lsX2hhcmlfdGVycmFtYWkNCmBgYA0KDQpUYWJlbCBtZW51bmp1a2thbiBkaXN0cmlidXNpIGp1bWxhaCBjaGF0IHNlbGFtYSBzYXR1IHRhaHVuIHlhbmcgZGlrZWxvbXBva2thbiBiZXJkYXNhcmthbiBidWxhbiBkYW4gaGFyaSBkb21pbmFuIHRlcmphZGlueWEgYWt0aXZpdGFzIGNoYXQgcGFkYSBidWxhbiB0ZXJzZWJ1dC4NCg0KU2VjYXJhIHVtdW0sIGFrdGl2aXRhcyBjaGF0IHRpZGFrIG1lcmF0YSBzZXBhbmphbmcgdGFodW4gZGFuIG1lbnVuanVra2FuIHBvbGEgZmx1a3R1YXRpZiB5YW5nIGN1a3VwIGplbGFzLg0KDQoxLiAgUHVuY2FrIGFrdGl2aXRhcyBjaGF0IHRlcmphZGkgcGFkYSBidWxhbiBNYXJldCBkZW5nYW4gdG90YWwgMjM2IGNoYXQsIHlhbmcgZGlkb21pbmFzaSBwYWRhIGhhcmkgUmFidS4gSGFsIGluaSBtZW5naW5kaWthc2lrYW4gYWRhbnlhIHBlbmluZ2thdGFuIGludGVuc2l0YXMga29tdW5pa2FzaSBwYWRhIHBlcmlvZGUgYXdhbCB0YWh1biwgeWFuZyBrZW11bmdraW5hbiBiZXJrYWl0YW4gZGVuZ2FuIGFrdGl2aXRhcyBrb29yZGluYXNpLCBwZXJlbmNhbmFhbiwgYXRhdSBkaW5hbWlrYSBrZXJqYSBwYXNjYS1hd2FsIHRhaHVuLg0KDQoyLiAgQWt0aXZpdGFzIGNoYXQgcmVsYXRpZiB0aW5nZ2kganVnYSB0ZXJsaWhhdCBwYWRhIEFndXN0dXMgKDE3NSBjaGF0LCBKdW1hdCkgZGFuIFNlcHRlbWJlciAoMTY4IGNoYXQsIFNlbmluKS4gUG9sYSBpbmkgZGFwYXQgbWVuY2VybWlua2FuIG1lbmluZ2thdG55YSBrZWJ1dHVoYW4ga29tdW5pa2FzaSBtZW5qZWxhbmcgYXRhdSBzZXN1ZGFoIHBlcmlvZGUgdGVydGVudHUsIHNlcGVydGkgZXZhbHVhc2kgdGVuZ2FoIHRhaHVuIGF0YXUgcGVueWVzdWFpYW4gcHJvZ3JhbS4NCg0KMy4gIEFrdGl2aXRhcyB0ZXJlbmRhaCB0ZXJjYXRhdCBwYWRhIGJ1bGFuIE1laSBkZW5nYW4gaGFueWEgNDggY2hhdCwgbWVza2lwdW4gbWFzaWggZGlkb21pbmFzaSBoYXJpIFJhYnUuIFJlbmRhaG55YSBpbnRlbnNpdGFzIGluaSBkYXBhdCBtZW5naW5kaWthc2lrYW4gcGVyaW9kZSBha3Rpdml0YXMgeWFuZyBsZWJpaCBzdGFiaWwgYXRhdSBiZXJrdXJhbmdueWEga2VidXR1aGFuIGtvb3JkaW5hc2kuDQoNCjQuICBEYXJpIHNpc2kgaGFyaSwgUmFidSBtdW5jdWwgc2ViYWdhaSBoYXJpIHlhbmcgcGFsaW5nIHNlcmluZyBtZW5qYWRpIGhhcmkgZG9taW5hbiAoTWFyZXQsIEFwcmlsLCBNZWksIEp1bGksIE9rdG9iZXIpLCBtZW51bmp1a2thbiBiYWh3YSBwZXJ0ZW5nYWhhbiBtaW5nZ3UgbWVydXBha2FuIHdha3R1IHlhbmcgcmVsYXRpZiBha3RpZiB1bnR1ayBrb211bmlrYXNpLg0KDQo1LiAgU2VtZW50YXJhIGl0dSwgSnVtYXQgZGFuIFNlbGFzYSBqdWdhIGJlYmVyYXBhIGthbGkgbXVuY3VsIHNlYmFnYWkgaGFyaSBkb21pbmFuLCB0ZXRhcGkgZGVuZ2FuIGZyZWt1ZW5zaSB5YW5nIGxlYmloIHJlbmRhaCwgc2VkYW5na2FuIFNlbmluIGhhbnlhIGRvbWluYW4gcGFkYSBzYXR1IGJ1bGFuLCB5YWl0dSBTZXB0ZW1iZXIuDQoNCg0KDQpgYGB7cn0NCmhpc3RvcnkgJT4lDQogIG11dGF0ZSgNCiAgICBidWxhbiA9IG1vbnRoKHRpbWUsIGxhYmVsID0gVFJVRSwgYWJiciA9IEZBTFNFKSwNCiAgICBoYXJpID0gZmFjdG9yKA0KICAgICAgd2Vla2RheXMoYXMuRGF0ZSh0aW1lKSksDQogICAgICBsZXZlbHMgPSBjKCJTZW5pbiIsIlNlbGFzYSIsIlJhYnUiLCJLYW1pcyIsIkp1bWF0IiwiU2FidHUiLCJNaW5nZ3UiKQ0KICAgICkNCiAgKSAlPiUNCiAgY291bnQoYnVsYW4sIGhhcmkpICU+JQ0KICBnZ3Bsb3QoYWVzKGhhcmksIGJ1bGFuLCBmaWxsID0gbikpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJIYXJpIFRlcmFtYWkgQ2hhdCBwZXIgQnVsYW4iLA0KICAgIHggPSAiSGFyaSIsDQogICAgeSA9ICJCdWxhbiIsDQogICAgZmlsbCA9ICJKdW1sYWggQ2hhdCINCiAgKQ0KYGBgDQoNCg0KIyBTZW50aW1lbiBOZWdhdGlmDQoNCkFuYWxpc2lzIHNlbnRpbWVuIGRpbGFrdWthbiBzZWNhcmEgZWtzcGxvcmF0aWYgZGVuZ2FuIGZva3VzIHBhZGEgaWRlbnRpZmlrYXNpIGluZGlrYXNpIHNlbnRpbWVuIG5lZ2F0aWYgZGFsYW0gcGVyY2FrYXBhbiBncnVwLiBQZW5kZWthdGFuIHlhbmcgZGlndW5ha2FuIGJlcnNpZmF0IF9sZXhpY29uLWJhc2VkXywgeWFpdHUgZGVuZ2FuIG1lbWFuZmFhdGthbiBkYWZ0YXIga2F0YSBuZWdhdGlmIHlhbmcgc2VjYXJhIGtvbnNlcHR1YWwgbWVyZXByZXNlbnRhc2lrYW4ga2V0aWRha3B1YXNhbiwga2VzYWxhaGFuLCBhdGF1IGtlbmRhbGEgZGFsYW0ga29tdW5pa2FzaSAoTGl1LCAyMDEyKS4NCg0KU2V0aWFwIHBlc2FuIGRpYmVyaWthbiBza29yIG5lZ2F0aWYgYmVyZGFzYXJrYW4ganVtbGFoIGtlbXVuY3VsYW4ga2F0YSBuZWdhdGlmLiBQZXNhbiBkZW5nYW4gc2tvciBsZWJpaCBkYXJpIG5vbCBkaWFuZ2dhcCBtZW5nYW5kdW5nIHNlbnRpbWVuIG5lZ2F0aWYgZGFuIGRpYW5hbGlzaXMgbGViaWggbGFuanV0Lg0KDQpVbnR1ayBtZW5naGluZGFyaSBkdXBsaWthc2kgbWFrbmEgYWtpYmF0IHZhcmlhc2kgcmVkYWtzaSBrYWxpbWF0LCBkaXRlcmFwa2FuIHBlbmRla2F0YW4gX1Rlcm0gRnJlcXVlbmN54oCTSW52ZXJzZSBEb2N1bWVudCBGcmVxdWVuY3lfIChURi1JREYpIHNlYmFnYWkgbWV0b2RlIHBlbWJvYm90YW4ga2F0YS4gVEYtSURGIG1lbWJlcmlrYW4gYm9ib3QgbGViaWggdGluZ2dpIHBhZGEga2F0YSB5YW5nIGJlcnNpZmF0IHNwZXNpZmlrIHRlcmhhZGFwIHN1YXR1IHBlc2FuIGRhbiBtZW51cnVua2FuIHBlbmdhcnVoIGthdGEgeWFuZyB1bXVtIG11bmN1bCBkaSBiYW55YWsgcGVzYW4gKFNhbHRvbiAmIEJ1Y2tsZXksIDE5ODgpLg0KDQpTZWxhbmp1dG55YSwgdGluZ2thdCBrZW1pcmlwYW4gYW50YXIgcGVzYW4gZGl1a3VyIG1lbmdndW5ha2FuIF9jb3NpbmUgc2ltaWxhcml0eV8gYmVyYmFzaXMgdmVrdG9yIFRGLUlERi4gUGVuZGVrYXRhbiBpbmkgbWVtdW5na2lua2FuIGlkZW50aWZpa2FzaSBwZXNhbi1wZXNhbiB5YW5nIHNlY2FyYSBzZW1hbnRpayBtZW1pbGlraSBtYWtuYSBzZXJ1cGEgbWVza2lwdW4gYmVyYmVkYSBzZWNhcmEgc3RydWt0dXIga2FsaW1hdCAoU2luZ2hhbCwgMjAwMSkuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLGVjaG89RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXRleHQpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHdpZHlyKQ0KDQpzZW50aW1lbl9uZWdhdGlmIDwtIGMoDQogICJ0aWRhayIsImJ1a2FuIiwiYmVsdW0iLCJzYWxhaCIsImt1cmFuZyIsDQogICJsYW1iYXQiLCJ0ZWxhdCIsIm1hc2FsYWgiLCJlcnJvciIsImdhZ2FsIiwNCiAgInJpYmV0Iiwic3VzYWgiLCJrZWNld2EiLCJwYXJhaCIsICJwcm90ZXMiDQopDQoNCiMgQ0xFQU5JTkcgVEVLUw0KY2hhdF9jbGVhbiA8LSBoaXN0b3J5ICU+JQ0KICBmaWx0ZXIodGV4dCAhPSAiPE1lZGlhIHRpZGFrIGRpc2VydGFrYW4+IikgJT4lDQogIG11dGF0ZSgNCiAgICB0ZXh0X2NsZWFuID0gdGV4dCAlPiUNCiAgICAgIHN0cl90b19sb3dlcigpICU+JQ0KICAgICAgc3RyX3JlcGxhY2VfYWxsKCJbXmEtelxcc10iLCAiICIpICU+JQ0KICAgICAgc3RyX3NxdWlzaCgpDQogICkNCg0KIyBISVRVTkcgU0tPUiBORUdBVElGDQpzZW50aW1lbl9jaGF0IDwtIGNoYXRfY2xlYW4gJT4lDQogIHVubmVzdF90b2tlbnMoa2F0YSwgdGV4dF9jbGVhbiwgdG9rZW4gPSAid29yZHMiKSAlPiUNCiAgbXV0YXRlKG5lZ2F0aWYgPSBrYXRhICVpbiUgc2VudGltZW5fbmVnYXRpZikgJT4lDQogIGdyb3VwX2J5KHRpbWUsIGF1dGhvciwgdGV4dCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBza29yX25lZ2F0aWYgPSBzdW0obmVnYXRpZiksDQogICAgLmdyb3VwcyA9ICJkcm9wIg0KICApICU+JQ0KICBmaWx0ZXIoc2tvcl9uZWdhdGlmID4gMCkgJT4lDQogIGxlZnRfam9pbigNCiAgICBjaGF0X2NsZWFuICU+JSBzZWxlY3QodGltZSwgdGV4dCwgdGV4dF9jbGVhbiksDQogICAgYnkgPSBjKCJ0aW1lIiwgInRleHQiKQ0KICApDQoNCiMgVE9LRU5JU0FTSQ0KdGZpZGZfZGF0YSA8LSBzZW50aW1lbl9jaGF0ICU+JQ0KICB1bm5lc3RfdG9rZW5zKGthdGEsIHRleHRfY2xlYW4sIHRva2VuID0gIndvcmRzIiwgZHJvcCA9IEZBTFNFKQ0KDQojIFRGLUlERg0KdGZpZGYgPC0gdGZpZGZfZGF0YSAlPiUNCiAgY291bnQodGV4dF9jbGVhbiwga2F0YSkgJT4lDQogIGJpbmRfdGZfaWRmKGthdGEsIHRleHRfY2xlYW4sIG4pDQoNCiMgQ09TSU5FIFNJTUlMQVJJVFkNCnNpbWlsYXJpdHkgPC0gdGZpZGYgJT4lDQogIHBhaXJ3aXNlX3NpbWlsYXJpdHkoDQogICAgaXRlbSA9IHRleHRfY2xlYW4sDQogICAgZmVhdHVyZSA9IGthdGEsDQogICAgdmFsdWUgPSB0Zl9pZGYNCiAgKSAlPiUNCiAgZmlsdGVyKHNpbWlsYXJpdHkgPiAwLjg1KQ0KYGBgDQoNCmBgYHtyfQ0KcGVzYW5fbWFrbmFfdW5payA8LSBzZW50aW1lbl9jaGF0ICU+JQ0KICBmaWx0ZXIoIXRleHRfY2xlYW4gJWluJSBzaW1pbGFyaXR5JGl0ZW0yKSAlPiUNCiAgYXJyYW5nZShkZXNjKHNrb3JfbmVnYXRpZikpDQoNCnBlc2FuX21ha25hX3VuaWsgJT4lDQogIHNlbGVjdCh0aW1lLCBhdXRob3IsIHRleHQsIHNrb3JfbmVnYXRpZikNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgcmVzdWx0cz0naGlkZScsIGVjaG89RkFMU0V9DQpsaWJyYXJ5KERUKQ0KRFQ6OmRhdGF0YWJsZSgNCiAgcGVzYW5fbWFrbmFfdW5paywNCiAgb3B0aW9ucyA9IGxpc3QoDQogICAgcGFnZUxlbmd0aCA9IDEwLA0KICAgIGF1dG9XaWR0aCA9IFRSVUUNCiAgKQ0KKQ0KYGBgDQoNCiMgUGVudXR1cA0KDQpTZWNhcmEga2VzZWx1cnVoYW4sIGFuYWxpc2lzIGluaSBtZW5nb21iaW5hc2lrYW4gcGVuZGVrYXRhbiBkZXNrcmlwdGlmIGRhbiBfdGV4dCBtaW5pbmdfIHVudHVrIG1lbmdnYW1iYXJrYW4gZGluYW1pa2Ega29tdW5pa2FzaSBkYWxhbSBncnVwIFdoYXRzQXBwLiBNZWxhbHVpIGFuYWxpc2lzIGZyZWt1ZW5zaSwgdmlzdWFsaXNhc2kgdGVtcG9yYWwsIGVrc3Bsb3Jhc2kga29zYWthdGEsIHNlcnRhIHJlZHVrc2kgc2VtYW50aWsgcGVzYW4gbmVnYXRpZiwgcGVuZWxpdGlhbiBpbmkgbWVudW5qdWtrYW4gYmFnYWltYW5hIGRhdGEgcGVyY2FrYXBhbiBkaWdpdGFsIGRhcGF0IGRpbWFuZmFhdGthbiB1bnR1ayBtZW1haGFtaSBwb2xhIGludGVyYWtzaSBzb3NpYWwgc2VjYXJhIGxlYmloIHNpc3RlbWF0aXMuIFBlbmRla2F0YW4gaW5pIHNlamFsYW4gZGVuZ2FuIHByYWt0aWsgYW5hbGlzaXMgdGVrcyBtb2Rlcm4geWFuZyBtZW5la2Fua2FuIGludGVncmFzaSBtZXRvZGUgc3RhdGlzdGlrIGRhbiBsaW5ndWlzdGlrIGRhbGFtIHBlbmdvbGFoYW4gZGF0YSB0aWRhayB0ZXJzdHJ1a3R1ciAoTWFubmluZyBldCBhbC4sIDIwMDg7IFNpbGdlICYgUm9iaW5zb24sIDIwMTcpLg0KDQojIFJlZmVyZW5zaQ0KDQpbMV0gRmVsZG1hbiwgUi4sICYgU2FuZ2VyLCBKLiAoMjAwNykuIF9UaGUgdGV4dCBtaW5pbmcgaGFuZGJvb2s6IEFkdmFuY2VkIGFwcHJvYWNoZXMgaW4gYW5hbHl6aW5nIHVuc3RydWN0dXJlZCBkYXRhXy4gQ2FtYnJpZGdlIFVuaXZlcnNpdHkgUHJlc3MuDQoNClsyXSBMaXUsIEIuICgyMDEyKS4gX1NlbnRpbWVudCBhbmFseXNpcyBhbmQgb3BpbmlvbiBtaW5pbmcuIE1vcmdhbiAmIENsYXlwb29sIFB1Ymxpc2hlcnNfLiBodHRwczovL2RvaS5vcmcvMTAuMjIwMC9TMDA0MTZFRDFWMDFZMjAxMjA0SExUMDE2DQoNClszXSBNYW5uaW5nLCBDLiBELiwgUmFnaGF2YW4sIFAuLCAmIFNjaMO8dHplLCBILiAoMjAwOCkuIF9JbnRyb2R1Y3Rpb24gdG8gaW5mb3JtYXRpb24gcmV0cmlldmFsXy4gQ2FtYnJpZGdlIFVuaXZlcnNpdHkgUHJlc3MuDQoNCls0XSBTYWx0b24sIEcuLCAmIEJ1Y2tsZXksIEMuICgxOTg4KS4gX1Rlcm0td2VpZ2h0aW5nIGFwcHJvYWNoZXMgaW4gYXV0b21hdGljIHRleHQgcmV0cmlldmFsLiBJbmZvcm1hdGlvbiBQcm9jZXNzaW5nICYgTWFuYWdlbWVudF8sIDI0KDUpLCA1MTPigJM1MjMuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDE2LzAzMDYtNDU3Myg4OCk5MDAyMS0wDQoNCls1XSBTaWxnZSwgSi4sICYgUm9iaW5zb24sIEQuICgyMDE3KS4gX1RleHQgbWluaW5nIHdpdGggUjogQSB0aWR5IGFwcHJvYWNoXy4gT+KAmVJlaWxseSBNZWRpYS4NCg0KWzZdIFNpbmdoYWwsIEEuICgyMDAxKS4gX01vZGVybiBpbmZvcm1hdGlvbiByZXRyaWV2YWw6IEEgYnJpZWYgb3ZlcnZpZXdfLiBJRUVFIERhdGEgRW5naW5lZXJpbmcgQnVsbGV0aW4sIDI0KDQpLCAzNeKAkzQzLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KPiBEaXJla3RvcmF0IFN0YXRpc3RpayBLZXNlamFodGVyYWFuIFJha3lhdCwgQlBTLCBzYXB0YWhhc0BicHMuZ28uaWQNCg0KDQoNCg0K