Materi ini akan membahas pengenalan meta-package tidyverse yang merupakan kumpulan dari 8 package inti, yaitu

  1. readr digunakan untuk membaca data tabular seperti csv,tsv dan fwf
  2. dplyr digunakan untuk memanipulasi data
  3. ggplot2 digunakan untuk visualisasi data berbasiskan Grammar of Graphics
  4. tidyr digunakan untuk merapihkan (tidying) data
  5. purrr digunakan untuk functional programming
  6. tibble digunakan sebagai alternatif data.frame yang lebih konsisten
  7. forcats digunakan untuk memanipulasi data berupa yang bertipe factor
  8. stringr digunakan untuk memanipulasi data bertipe string

Library dalam R

Library (atau package) dalam R adalah kumpulan fungsi, data, dan dokumentasi yang memperluas kemampuan dasar R. Library memungkinkan pengguna untuk menambahkan fungsi-fungsi spesifik tanpa harus menulis kode dari awal.

Instalasi Library

Pada penggunaan pertama, silahkan install terlebih dulu package yang akan digunakan dengan cara menuliskan code berikut:

#install.packages("nama_package") 
#install.packages("tidyverse")

Memanggil Package

#library(nama_package) 
library(tidyverse)

Menggunakan Fungsi dari Library

#nama_package::nama_fungsi()  
#dplyr::filter(data, kondisi)

Melihat Library yang Terinstall

#installed.packages() 
#search()

Update dan Hapus Library

#update.packages() 
#remove.packages("nama_package")

Data

Platform Source Data

Kaggle

Kaggle adalah platform komunitas data science yang sangat populer di kalangan praktisi ML dan analisis data. Platform ini tidak hanya menyediakan ribuan dataset publik yang mencakup berbagai domain mulai dari kesehatan, finansial, hingga data sosial, tetapi juga menyelenggarakan kompetisi data science berhadiah yang menarik para ahli dari seluruh dunia. Yang membedakan Kaggle adalah ekosistemnya yang lengkap - setiap dataset biasanya dilengkapi dengan notebook contoh (kernel), diskusi komunitas, dan voting system untuk menilai kualitas dataset. Untuk pengguna R, Kaggle menyediakan akses mudah melalui API resmi atau download manual file CSV/JSON yang kemudian dapat di-load ke dalam environment R.

UCI Machine Learning Repository

UCI Machine Learning Repository merupakan gudang dataset historis yang menjadi standar emas dalam penelitian akademis dan pengembangan algoritma machine learning. Dikelola oleh University of California, Irvine, repository ini menyediakan dataset-dataset yang sudah terkurasi dengan dokumentasi lengkap dan sering digunakan sebagai benchmark untuk paper penelitian. Dataset-dataset seperti Iris, Wine, dan Adult Census Income telah menjadi semacam “hello world” dalam komunitas ML. Untuk analis R, dataset dari UCI biasanya tersedia dalam format text file yang bersih dan mudah diimpor menggunakan fungsi dasar seperti read.csv() atau read.table().

Google Dataset Search

Google Dataset Search berfungsi sebagai mesin pencari meta yang mengindeks dataset dari berbagai sumber di seluruh web. Platform ini tidak menyimpan dataset secara langsung, melainkan mengumpulkan metadata dari publisher data seperti pemerintah, lembaga penelitian, dan organisasi lainnya. Keunggulan utamanya adalah kemampuannya untuk melakukan pencarian semantik across multiple sources dan menyediakan informasi tentang lisensi, tanggal update, serta format data. Bagi pengguna R, ini sangat membantu untuk menemukan dataset spesifik yang mungkin tersembunyi di berbagai website, kemudian mengimpornya melalui URL langsung atau download manual.

Government Open Data Portals

Portal data pemerintah seperti Data.go.id (Indonesia), data.gov (AS), dan data.gov.uk (UK) menyediakan data resmi yang dikumpulkan oleh instansi pemerintah. Data-data ini mencakup statistik demografi, indikator ekonomi, data geospasial, dan informasi publik lainnya yang dikumpulkan menggunakan anggaran negara. Keuntungan utama data pemerintah adalah otoritas sumbernya yang terpercaya, periodisitas yang teratur (bulanan/tahunan), dan cakupan nasional yang komprehensif. Untuk analis R, data ini biasanya tersedia dalam format CSV atau melalui API yang dapat diakses langsung menggunakan packages seperti httr atau jsonlite.

API-Based Platforms

Platform berbasis API seperti Yahoo Finance, Alpha Vantage, dan Twitter API menyediakan akses real-time atau near-real-time ke data dinamis. Platform finansial menawarkan data pasar saham, nilai tukar, dan indikator ekonomi dengan latensi rendah, sementara platform media sosial menyediakan akses ke data interaksi sosial terkini. Keunikan platform ini adalah sifat datanya yang selalu diperbarui dan kemampuan untuk mengambil data historis mendalam. Di R, developer telah membuat packages khusus seperti quantmod untuk data finansial dan rtweet untuk data Twitter yang menyederhanakan proses autentikasi dan query API.

Specialized Domain Platforms

Platform khusus domain seperti NOAA untuk klimatologi, NIH untuk kesehatan, dan NASA untuk data antariksa menyediakan dataset yang sangat spesifik dan teknis. Data dari platform ini biasanya dikumpulkan menggunakan instrumentasi khusus, melalui penelitian bertahun-tahun, atau dengan metodologi yang kompleks. Nilai utamanya terletak pada kedalaman dan akurasi data yang sulit ditemukan di platform umum. Untuk bekerja dengan data ini di R, seringkali diperlukan packages tambahan yang khusus dibuat untuk menangani format data niche seperti NetCDF untuk data iklim atau DICOM untuk data medis.

R Built-in Datasets dan Packages Data

R sendiri datang dengan puluhan dataset built-in yang siap digunakan untuk tujuan pembelajaran dan prototyping. Dataset seperti mtcars, iris, dan airquality telah menjadi bahan latihan bagi generasi analis data. Selain itu, ecosystem R memiliki packages yang khusus berisi dataset seperti nycflights13 (data penerbangan), gapminder (data perkembangan negara), dan palmerpenguins (data penguin). Kelebihan dataset ini adalah kesiapan pakainya - sudah dalam format yang bersih, terdokumentasi dengan baik, dan terintegrasi sempurna dengan tidyverse ecosystem, membuatnya ideal untuk demonstrasi teknik analisis dan visualisasi.

Load Data

Countries of the World

Dataset komprehensif ini menyediakan informasi mendalam tentang berbagai negara di seluruh dunia, yang mencakup beragam indikator sosio-ekonomi, demografis, dan geografis. Data ini meliputi statistik kependudukan, indikator ekonomi makro, faktor lingkungan, metrik kesehatan masyarakat, statistik pendidikan, serta struktur perekonomian nasional. Dengan cakupan 227 negara dari berbagai belahan dunia, dataset ini menawarkan perspektif global yang holistik tentang karakteristik masing-masing negara, memungkinkan analisis komparatif dan studi lintas sektor yang mendalam.

Country: Nama resmi negara

Region: Kelompok wilayah geografis negara

Population: Total jumlah penduduk negara

Area (sq. mi.): Luas wilayah dalam mil persegi

Pop. Density (per sq. mi.): Kepadatan penduduk per mil persegi

Coastline (coast/area ratio): Rasio panjang garis pantai terhadap luas wilayah

Net migration: Migrasi bersih per 1000 penduduk

Infant mortality (per 1000 births): Angka kematian bayi per 1000 kelahiran

GDP ($ per capita): Pendapatan per kapita dalam dollar AS

Literacy (%): Persentase penduduk melek huruf

Phones (per 1000): Jumlah telepon per 1000 penduduk

Arable (%): Persentase lahan cocok untuk pertanian

Crops (%): Persentase lahan untuk tanaman permanen

Other (%): Persentase lahan untuk penggunaan non-pertanian

Climate: Kode klasifikasi iklim (1-4)

Birthrate: Angka kelahiran per 1000 penduduk

Deathrate: Angka kematian per 1000 penduduk

Agriculture: Kontribusi sektor pertanian terhadap GDP (proporsi)

Industry: Kontribusi sektor industri terhadap GDP (proporsi)

Service: Kontribusi sektor jasa terhadap GDP (proporsi)

Data dapat diperoleh dengan mendownload link dibawah ini

Data

Import data

countries <- read_csv("C:\\Users\\Legion\\Documents\\Asisten Dosen\\Mandarel\\Data Wrangling di R\\countries of the world.csv",show_col_types = FALSE)

Fungsi Wrangling

Berikut materi lengkap untuk 20 fungsi tidyverse dengan contoh menggunakan dataset “Countries of the World”:

1. glimpse()

Fungsi: Menampilkan preview dataset dengan informasi struktur data, tipe variabel, dan beberapa nilai contoh. Sangat useful untuk eksplorasi data awal yang lebih readable dibanding str().

library(tidyverse) 
library(readr)  
# Melihat struktur data 
glimpse(countries)
## Rows: 227
## Columns: 20
## $ Country                              <chr> "Afghanistan", "Albania", "Algeri…
## $ Region                               <chr> "ASIA (EX. NEAR EAST)", "EASTERN …
## $ Population                           <dbl> 31056997, 3581655, 32930091, 5779…
## $ `Area (sq. mi.)`                     <dbl> 647500, 28748, 2381740, 199, 468,…
## $ `Pop. Density (per sq. mi.)`         <chr> "48,0", "124,6", "13,8", "290,4",…
## $ `Coastline (coast/area ratio)`       <chr> "0,00", "1,26", "0,04", "58,29", …
## $ `Net migration`                      <chr> "23,06", "-4,93", "-0,39", "-20,7…
## $ `Infant mortality (per 1000 births)` <dbl> 16307, 2152, 31, 927, 405, 19119,…
## $ `GDP ($ per capita)`                 <dbl> 700, 4500, 6000, 8000, 19000, 190…
## $ `Literacy (%)`                       <dbl> 360, 865, 700, 970, 1000, 420, 95…
## $ `Phones (per 1000)`                  <chr> "3,2", "71,2", "78,1", "259,5", "…
## $ `Arable (%)`                         <chr> "12,13", "21,09", "3,22", "10", "…
## $ `Crops (%)`                          <chr> "0,22", "4,42", "0,25", "15", "0"…
## $ `Other (%)`                          <dbl> 8765, 7449, 9653, 75, 9778, 9735,…
## $ Climate                              <dbl> 1, 3, 1, 2, 3, NA, 2, 2, 3, 4, 2,…
## $ Birthrate                            <dbl> 466, 1511, 1714, 2246, 871, 4511,…
## $ Deathrate                            <dbl> 2034, 522, 461, 327, 625, 242, 53…
## $ Agriculture                          <chr> "0,38", "0,232", "0,101", NA, NA,…
## $ Industry                             <chr> "0,24", "0,188", "0,6", NA, NA, "…
## $ Service                              <chr> "0,38", "0,579", "0,298", NA, NA,…

2. select()

Fungsi: Memilih kolom tertentu dari dataset berdasarkan nama atau kriteria tertentu. Dapat juga digunakan untuk merename kolom dan mengubah urutan kolom.

# Memilih kolom tertentu 
countries_selected <- countries %>%   
  select(Country, Population, `GDP ($ per capita)`, Region)  

countries_selected
# Memilih kolom dengan pattern 
countries_econ <- countries %>%   
  select(Country, contains("GDP"), contains("rate"))

countries_econ

3. %>% (Pipe Operator)

Fungsi: Operator pipe yang mentransform output dari fungsi sebelah kiri menjadi input pertama untuk fungsi sebelah kanan. Membuat kode lebih readable dan sequential.

# Tanpa pipe (nested function) 
result1 <- arrange(filter(countries, Population > 100000000), desc(`GDP ($ per capita)`))  

# Dengan pipe (lebih mudah dibaca) 
result2 <- countries %>%   
  filter(Population > 100000000) %>%   
  arrange(desc(`GDP ($ per capita)`))  
result1 
result2

4. filter()

Fungsi: Menyaring baris data berdasarkan kondisi logika tertentu. Dapat menggunakan multiple conditions dengan operator &, |, !.

# Filter negara dengan GDP tinggi dan populasi besar 
rich_countries <- countries %>%   
  filter(`GDP ($ per capita)` > 30000 & Population > 10000000)  
rich_countries
# Filter negara dari region tertentu 
asian_countries <- countries %>%   
  filter(str_detect(Region, "ASIA"))  
asian_countries

5. arrange()

Fungsi: Mengurutkan baris data berdasarkan satu atau lebih kolom. Default ascending, gunakan desc() untuk descending.

# Urutkan berdasarkan GDP tertinggi 
countries_rich_first <- countries %>%   
  arrange(desc(`GDP ($ per capita)`))  
countries_rich_first
# Urutkan berdasarkan region lalu GDP 
countries_sorted <- countries %>%   
  arrange(Region, desc(`GDP ($ per capita)`))  
countries_sorted

6. mutate()

Fungsi: Membuat kolom baru atau memodifikasi kolom existing. Dapat menggunakan operasi aritmatika, fungsi, atau conditional logic.

{r} # Membuat kolom baru} countries_modified <- countries %>% mutate( GDP_total = Population * `GDP ($ per capita)`, development_level = ifelse(`GDP ($ per capita)` > 20000, "Developed", "Developing") ) countries_modified

7. summarize() / summarise()

Fungsi: Membuat summary statistics untuk satu atau lebih kolom. Biasanya dipakai dengan group_by().

# Summary statistics untuk seluruh dataset 
summary_stats <- countries %>%   
  summarise(     
    avg_gdp = mean(`GDP ($ per capita)`, na.rm = TRUE),     
    max_pop = max(Population, na.rm = TRUE),     
    total_countries = n()   
    ) 
summary_stats
economic_summary <- countries %>%   
  summarise(     
    total_population_world = sum(Population, na.rm = TRUE),     
    avg_gdp_per_capita = mean(`GDP ($ per capita)`, na.rm = TRUE),
    median_gdp_per_capita = median(`GDP ($ per capita)`, na.rm = TRUE),     
    sd_gdp = sd(`GDP ($ per capita)`, na.rm = TRUE),     
    min_gdp = min(`GDP ($ per capita)`, na.rm = TRUE),     
    max_gdp = max(`GDP ($ per capita)`, na.rm = TRUE),     
    total_countries = n(),     
    countries_with_high_gdp = sum(`GDP ($ per capita)` > 20000, na.rm = TRUE),     
    percentage_high_gdp = round(mean(`GDP ($ per capita)` > 20000, na.rm = TRUE) * 100, 1),     
    avg_literacy = mean(`Literacy (%)`, na.rm = TRUE),     
    avg_infant_mortality = mean(`Infant mortality (per 1000 births)`, na.rm = TRUE)   )  
economic_summary %>% print()
## # A tibble: 1 × 11
##   total_population_world avg_gdp_per_capita median_gdp_per_capita sd_gdp min_gdp
##                    <dbl>              <dbl>                 <dbl>  <dbl>   <dbl>
## 1             6524044551              9690.                  5550 10049.     500
## # ℹ 6 more variables: max_gdp <dbl>, total_countries <int>,
## #   countries_with_high_gdp <int>, percentage_high_gdp <dbl>,
## #   avg_literacy <dbl>, avg_infant_mortality <dbl>
countries_clean <- countries %>%   
  mutate(     
    `Phones (per 1000)` = as.numeric(str_replace(`Phones (per 1000)`, ",", ".")),
    `GDP ($ per capita)` = as.numeric(str_replace(`GDP ($ per capita)`, ",", ".")),
    `Literacy (%)` = as.numeric(str_replace(`Literacy (%)`, ",", ".")),     
    `Infant mortality (per 1000 births)` = as.numeric(str_replace(`Infant mortality (per 1000 births)`, ",", "."))   
  )

# Analisis dengan data yang sudah dibersihkan 
regional_analysis_clean <- countries_clean %>%   
  mutate(     
    gdp_category = case_when(       
      `GDP ($ per capita)` >= 25000 ~ "High Income",       
      `GDP ($ per capita)` >= 10000 ~ "Upper Middle Income",        
      `GDP ($ per capita)` >= 2500 ~ "Lower Middle Income",       
      `GDP ($ per capita)` < 2500 ~ "Low Income",       
      TRUE ~ "Unknown"     
    )   
  ) %>%   
  group_by(Region, gdp_category) %>%   
  summarise(     
    number_of_countries = n(),     
    total_population = sum(Population, na.rm = TRUE),    
    avg_gdp = mean(`GDP ($ per capita)`, na.rm = TRUE),     
    avg_literacy = mean(`Literacy (%)`, na.rm = TRUE),     
    avg_infant_mortality = mean(`Infant mortality (per 1000 births)`, na.rm = TRUE),     
    median_phones = median(`Phones (per 1000)`, na.rm = TRUE),     
    .groups = 'drop'   
  ) %>%  
  arrange(Region, desc(avg_gdp))

regional_analysis_clean %>% head(10)

8. group_by()

Fungsi: Mengelompokkan data berdasarkan satu atau lebih kolom kategorikal. Biasanya diikuti dengan summarize().

# Rata-rata GDP per region - nama chunk tanpa comment
gdp_by_region <- countries %>%   
  group_by(Region) %>%   
  summarise(
    avg_gdp = mean(`GDP ($ per capita)`, na.rm = TRUE),    
    count_countries = n()   
  ) %>%   
  arrange(desc(avg_gdp))  

gdp_by_region

9. count()

Fungsi: Menghitung frekuensi untuk kombinasi nilai dalam kolom. Shortcut untuk group_by() + summarise(n()).

region_count <- countries %>%   
  count(Region, sort = TRUE) 

region_count
# Count dengan multiple columns 
region_development <- countries %>%   
  mutate(development = ifelse(`GDP ($ per capita)` > 20000, "Developed", "Developing")) %>%   
  count(Region, development)  
region_count 
region_development

10. str_detect() dari package stringr

Fungsi: Mendeteksi pattern teks dalam string. Return logical vector yang sangat useful untuk filtering.

library(stringr)  
# Filter negara dengan nama mengandung "land" 
land_countries <- countries %>%   
  filter(str_detect(Country, "land"))  
land_countries
# Filter region Asia 
asian_region <- countries %>%   
  filter(str_detect(Region, "ASIA"))  

asian_region

11. case_when()

Fungsi: Membuat conditional statements kompleks dengan multiple conditions. Lebih powerful dari ifelse().

# Klasifikasi negara berdasarkan GDP 
countries_classified <- countries %>%   
  mutate(     
    income_group = case_when(       
      `GDP ($ per capita)` >= 30000 ~ "High Income",       
      `GDP ($ per capita)` >= 10000 ~ "Upper Middle",       
      `GDP ($ per capita)` >= 2500 ~ "Lower Middle",       
      `GDP ($ per capita)` < 2500 ~ "Low Income",       
      TRUE ~ "Unknown"     
      )   
    )

countries_classified

12. rename_with()

Fungsi: Rename kolom berdasarkan function atau pattern. Useful untuk cleaning nama kolom.

# Rename kolom ke lowercase 
countries_clean <- countries %>%   
  rename_with(tolower)  

countries_clean
# Rename menghapus spesial karakter 
countries_clean2 <- countries %>%   
  rename_with(~ str_remove_all(., "\\(|\\)|\\$| per capita"))  
countries_clean2

13. across() + where()

Fungsi: Melakukan operasi yang sama pada multiple columns yang memenuhi kondisi tertentu.

# Convert semua kolom numeric ke integer 
countries_int <- countries %>%   
  mutate(across(where(is.numeric), as.integer))  
countries_int
# Rata-rata untuk semua kolom numeric per region 
numeric_summary <- countries %>%   
  group_by(Region) %>%   
  summarise(across(where(is.numeric), mean, na.rm = TRUE))  

numeric_summary

14. distinct()

Fungsi: Mengambil unique rows berdasarkan kombinasi kolom. Useful untuk menghilangkan duplikat.

# Unique regions 
unique_regions <- countries %>%   
  distinct(Region) 
unique_regions
# Unique combinations 
unique_combinations <- countries %>%   
  distinct(Region, Climate)  
unique_combinations

15. slice()

Fungsi: Memilih baris tertentu berdasarkan posisi/index. Juga bisa slice_min/max/head/tail.

# 10 negara pertama 
first_10 <- countries %>%   
  slice(1:10) 
first_10  
# 5 negara dengan GDP tertinggi 
top5_gdp <- countries %>% 
  slice_max(`GDP ($ per capita)`, n = 5)  
top5_gdp 
# 10% negara dengan populasi terkecil 
bottom_10pct <- countries %>%   
  slice_min(Population, prop = 0.1) 
bottom_10pct

16. relocate()

Fungsi: Mengubah urutan kolom dalam dataset. Sangat useful untuk reorganisasi data.

# Pindah kolom Region ke depan 
countries_reordered <- countries %>%   
  relocate(Region, .before = Country)  
countries_reordered
# Pindah beberapa kolom ke depan 
countries_reordered2 <- countries %>%   
  relocate(where(is.character), .before = where(is.numeric))  
countries_reordered2

17. case_when() (dalam mutate)

Fungsi: Extended contoh case_when untuk multiple conditions dalam pembuatan variabel.

countries_complex <- countries %>%   
  mutate(     
    country_category = case_when(       
      `GDP ($ per capita)` > 30000 & `Literacy (%)` > 95 ~ "Developed High Literacy",
      `GDP ($ per capita)` > 30000 & `Literacy (%)` <= 95 ~ "Developed Medium Literacy",       
      `GDP ($ per capita)` <= 30000 & `Infant mortality (per 1000 births)` < 10 ~ "Developing Low Mortality",       
      TRUE ~ "Developing High Mortality"     
    )   
  )

countries_complex

18. bind_rows() & bind_cols()

Fungsi: Menggabungkan data frames secara vertikal (rows) atau horizontal (columns).

# Pisah data menjadi dua bagian 
asia_countries <- countries %>% filter(str_detect(Region, "ASIA")) 
europe_countries <- countries %>% filter(str_detect(Region, "EUROPE")) 

# Gabungkan kembali 
combined <- bind_rows(asia_countries, europe_countries)  
# Tambahkan kolom ID 
countries_with_id <- countries %>%   
  bind_cols(country_id = 1:nrow(.), .)

19. pivot_longer() & pivot_wider()

Fungsi pivot_longer digunakan untuk mentransformasi dataset yang berbentuk wide ke dataset yang berbentuk long. Sebaliknya pivot_wider digunakan untuk mentransformasi dataset yang berbentuk long ke dataset yang berbentuk wide. Kedua fungsi ini berasal dari package tidyr.

# Wide to long - pivot economic indicators 
countries_long <- countries %>%   
  select(Country, `GDP ($ per capita)`, `Literacy (%)`, `Infant mortality (per 1000 births)`) %>%   
  pivot_longer(     
    cols = c(`GDP ($ per capita)`, `Literacy (%)`, `Infant mortality (per 1000 births)`),     
    names_to = "indicator",     
    values_to = "value"   )  
countries_long 
# Long to wide kembali 
countries_wide <- countries_long %>%   
  pivot_wider(     
    names_from = indicator,     
    values_from = value   
    ) 
countries_wide

20. coalesce()

Fungsi: Mengambil nilai pertama yang tidak-NA dari sekumpulan vektor. Useful untuk handling missing values.

# Contoh dengan data yang dimodifikasi 
countries_with_na <- countries %>%   
  mutate(    
    GDP_alternative = ifelse(Country %in% c("Afghanistan", "Somalia"), NA, `GDP ($ per capita)`)   
    ) 
countries_with_na  
# Gunakan coalesce untuk prioritaskan GDP asli 
countries_fixed <- countries_with_na %>%   
  mutate(     
    GDP_final = coalesce(`GDP ($ per capita)`, GDP_alternative, 0)   
    )
countries_fixed 

Latihan Soal

Soal 1: Bersihkan dataset dengan melakukan beberapa operasi sekaligus: ubah koma menjadi titik pada kolom numeric, hapus spasi berlebih pada kolom teks, dan isi missing values dengan median untuk numeric atau modus untuk kategorikal. Tampilkan summary sebelum dan setelah cleaning.

Soal 2: Ubah dataset dari wide format menjadi long format dimana semua indikator ekonomi (GDP, Literacy, Infant Mortality) menjadi satu kolom “Indicator” dan nilainya di kolom “Value”. Kemudian kembalikan ke format semula tanpa kehilangan data.

Soal 3: Bandingkan negara-negara dalam region yang sama dengan membuat kolom baru yang menunjukkan peringkat GDP per kapita dalam regionnya, selisih GDP dari rata-rata region, dan status apakah GDP negara tersebut di atas atau di bawah median region.

Soal 4: Pisahkan region utama dan sub-region (jika ada), normalisasi penulisan (kapitalisasi yang konsisten), dan hitung frekuensi setiap kombinasi region-subregion.

Soal 5: Kelompokkan negara berdasarkan multiple conditions: “High Income-Low Population” (GDP > $15,000 & Population < 10 juta), “Low Income-High Population” (GDP < $5,000 & Population > 50 juta), dan “Medium All”. Hitung statistik deskriptif untuk setiap kelompok.

Soal 6:Identifikasi dan perbaiki data yang tidak konsisten: nilai GDP yang tidak masuk akal (misal: $0 atau > $100,000), persentase yang melebihi 100%, dan kombinasi Agriculture+Industry+Service yang tidak sama dengan 1.

Soal 7: Group oleh Region dan Climate, kemudian hitung: rata-rata GDP, jumlah negara, negara dengan GDP tertinggi & terendah, dan range GDP untuk setiap kombinasi group.

Soal 8: Cari negara-negara yang memenuhi minimal 3 dari 4 kriteria: Literacy > 90%, Infant Mortality < 10, Phones > 500, dan Net Migration positif. Tampilkan dalam bentuk ranked list.

Soal 9:Dalam satu pipeline berurutan: seleksi kolom, filter baris, buat 3 kolom baru (log transformation untuk Population, kategori untuk Density, flag untuk Coastal countries), dan group summary statistics.

Soal 10: Asumsikan ada dataset tambahan berisi ibukota dan bahasa resmi setiap negara. Gabungkan dengan dataset existing, handle missing matches, dan buat analisis perbandingan antara negara dengan dan tanpa data lengkap.

LS0tDQp0aXRsZTogIkRhdGEgV3JhbmdsaW5nIGluIFIiDQphdXRob3I6ICJOZ3VyYWggU2VudGFuYSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVkICVCICVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB0cnVlDQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGZpZ193aWR0aDogOA0KICAgIGZpZ19oZWlnaHQ6IDUNCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgZWNobyA9IFRSVUUsDQogIHdhcm5pbmcgPSBGQUxTRSwNCiAgbWVzc2FnZSA9IEZBTFNFLA0KICBlcnJvciA9IEZBTFNFLA0KICBjYWNoZSA9IFRSVUUsDQogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLA0KICBmaWcucG9zID0gIkgiLA0KICBvdXQuZXh0cmEgPSAiIg0KKQ0KYGBgDQoNCk1hdGVyaSBpbmkgYWthbiBtZW1iYWhhcyBwZW5nZW5hbGFuIG1ldGEtcGFja2FnZSBgdGlkeXZlcnNlYCB5YW5nIG1lcnVwYWthbiBrdW1wdWxhbiBkYXJpIDggcGFja2FnZSBpbnRpLCB5YWl0dQ0KDQoxLiAgYHJlYWRyYCBkaWd1bmFrYW4gdW50dWsgbWVtYmFjYSBkYXRhIHRhYnVsYXIgc2VwZXJ0aSBjc3YsdHN2IGRhbiBmd2YNCjIuICBgZHBseXJgIGRpZ3VuYWthbiB1bnR1ayBtZW1hbmlwdWxhc2kgZGF0YQ0KMy4gIGBnZ3Bsb3QyYCBkaWd1bmFrYW4gdW50dWsgdmlzdWFsaXNhc2kgZGF0YSBiZXJiYXNpc2thbiBHcmFtbWFyIG9mIEdyYXBoaWNzDQo0LiAgYHRpZHlyYCBkaWd1bmFrYW4gdW50dWsgbWVyYXBpaGthbiAodGlkeWluZykgZGF0YQ0KNS4gIGBwdXJycmAgZGlndW5ha2FuIHVudHVrIGZ1bmN0aW9uYWwgcHJvZ3JhbW1pbmcNCjYuICBgdGliYmxlYCBkaWd1bmFrYW4gc2ViYWdhaSBhbHRlcm5hdGlmIGBkYXRhLmZyYW1lYCB5YW5nIGxlYmloIGtvbnNpc3Rlbg0KNy4gIGBmb3JjYXRzYCBkaWd1bmFrYW4gdW50dWsgbWVtYW5pcHVsYXNpIGRhdGEgYmVydXBhIHlhbmcgYmVydGlwZSBgZmFjdG9yYA0KOC4gIGBzdHJpbmdyYCBkaWd1bmFrYW4gdW50dWsgbWVtYW5pcHVsYXNpIGRhdGEgYmVydGlwZSBgc3RyaW5nYA0KDQohW10oZGF0YS1zY2llbmNlLnBuZykNCg0KIyMgTGlicmFyeSBkYWxhbSBSDQoNCioqTGlicmFyeSoqIChhdGF1ICoqcGFja2FnZSoqKSBkYWxhbSBSIGFkYWxhaCBrdW1wdWxhbiBmdW5nc2ksIGRhdGEsIGRhbiBkb2t1bWVudGFzaSB5YW5nIG1lbXBlcmx1YXMga2VtYW1wdWFuIGRhc2FyIFIuIExpYnJhcnkgbWVtdW5na2lua2FuIHBlbmdndW5hIHVudHVrIG1lbmFtYmFoa2FuIGZ1bmdzaS1mdW5nc2kgc3Blc2lmaWsgdGFucGEgaGFydXMgbWVudWxpcyBrb2RlIGRhcmkgYXdhbC4NCg0KIyMjICoqSW5zdGFsYXNpIExpYnJhcnkqKg0KDQpQYWRhIHBlbmdndW5hYW4gcGVydGFtYSwgc2lsYWhrYW4gaW5zdGFsbCB0ZXJsZWJpaCBkdWx1IHBhY2thZ2UgeWFuZyBha2FuIGRpZ3VuYWthbiBkZW5nYW4gY2FyYSBtZW51bGlza2FuIGNvZGUgYmVyaWt1dDoNCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygibmFtYV9wYWNrYWdlIikgDQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmBgYA0KDQojIyMgKipNZW1hbmdnaWwgUGFja2FnZSoqDQoNCmBgYHtyfQ0KI2xpYnJhcnkobmFtYV9wYWNrYWdlKSANCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCiMjIyAqKk1lbmdndW5ha2FuIEZ1bmdzaSBkYXJpIExpYnJhcnkqKg0KDQpgYGB7cn0NCiNuYW1hX3BhY2thZ2U6Om5hbWFfZnVuZ3NpKCkgIA0KI2RwbHlyOjpmaWx0ZXIoZGF0YSwga29uZGlzaSkNCmBgYA0KDQojIyMgKipNZWxpaGF0IExpYnJhcnkgeWFuZyBUZXJpbnN0YWxsKioNCg0KYGBge3J9DQojaW5zdGFsbGVkLnBhY2thZ2VzKCkgDQojc2VhcmNoKCkNCmBgYA0KDQojIyMgKipVcGRhdGUgZGFuIEhhcHVzIExpYnJhcnkqKg0KDQpgYGB7cn0NCiN1cGRhdGUucGFja2FnZXMoKSANCiNyZW1vdmUucGFja2FnZXMoIm5hbWFfcGFja2FnZSIpDQpgYGANCg0KIyMgRGF0YQ0KDQojIyMgUGxhdGZvcm0gU291cmNlIERhdGENCg0KKipLYWdnbGUqKg0KDQpLYWdnbGUgYWRhbGFoIHBsYXRmb3JtIGtvbXVuaXRhcyBkYXRhIHNjaWVuY2UgeWFuZyBzYW5nYXQgcG9wdWxlciBkaSBrYWxhbmdhbiBwcmFrdGlzaSBNTCBkYW4gYW5hbGlzaXMgZGF0YS4gUGxhdGZvcm0gaW5pIHRpZGFrIGhhbnlhIG1lbnllZGlha2FuIHJpYnVhbiBkYXRhc2V0IHB1YmxpayB5YW5nIG1lbmNha3VwIGJlcmJhZ2FpIGRvbWFpbiBtdWxhaSBkYXJpIGtlc2VoYXRhbiwgZmluYW5zaWFsLCBoaW5nZ2EgZGF0YSBzb3NpYWwsIHRldGFwaSBqdWdhIG1lbnllbGVuZ2dhcmFrYW4ga29tcGV0aXNpIGRhdGEgc2NpZW5jZSBiZXJoYWRpYWggeWFuZyBtZW5hcmlrIHBhcmEgYWhsaSBkYXJpIHNlbHVydWggZHVuaWEuIFlhbmcgbWVtYmVkYWthbiBLYWdnbGUgYWRhbGFoIGVrb3Npc3RlbW55YSB5YW5nIGxlbmdrYXAgLSBzZXRpYXAgZGF0YXNldCBiaWFzYW55YSBkaWxlbmdrYXBpIGRlbmdhbiBub3RlYm9vayBjb250b2ggKGtlcm5lbCksIGRpc2t1c2kga29tdW5pdGFzLCBkYW4gdm90aW5nIHN5c3RlbSB1bnR1ayBtZW5pbGFpIGt1YWxpdGFzIGRhdGFzZXQuIFVudHVrIHBlbmdndW5hIFIsIEthZ2dsZSBtZW55ZWRpYWthbiBha3NlcyBtdWRhaCBtZWxhbHVpIEFQSSByZXNtaSBhdGF1IGRvd25sb2FkIG1hbnVhbCBmaWxlIENTVi9KU09OIHlhbmcga2VtdWRpYW4gZGFwYXQgZGktbG9hZCBrZSBkYWxhbSBlbnZpcm9ubWVudCBSLg0KDQoqKlVDSSBNYWNoaW5lIExlYXJuaW5nIFJlcG9zaXRvcnkqKg0KDQpVQ0kgTWFjaGluZSBMZWFybmluZyBSZXBvc2l0b3J5IG1lcnVwYWthbiBndWRhbmcgZGF0YXNldCBoaXN0b3JpcyB5YW5nIG1lbmphZGkgc3RhbmRhciBlbWFzIGRhbGFtIHBlbmVsaXRpYW4gYWthZGVtaXMgZGFuIHBlbmdlbWJhbmdhbiBhbGdvcml0bWEgbWFjaGluZSBsZWFybmluZy4gRGlrZWxvbGEgb2xlaCBVbml2ZXJzaXR5IG9mIENhbGlmb3JuaWEsIElydmluZSwgcmVwb3NpdG9yeSBpbmkgbWVueWVkaWFrYW4gZGF0YXNldC1kYXRhc2V0IHlhbmcgc3VkYWggdGVya3VyYXNpIGRlbmdhbiBkb2t1bWVudGFzaSBsZW5na2FwIGRhbiBzZXJpbmcgZGlndW5ha2FuIHNlYmFnYWkgYmVuY2htYXJrIHVudHVrIHBhcGVyIHBlbmVsaXRpYW4uIERhdGFzZXQtZGF0YXNldCBzZXBlcnRpIElyaXMsIFdpbmUsIGRhbiBBZHVsdCBDZW5zdXMgSW5jb21lIHRlbGFoIG1lbmphZGkgc2VtYWNhbSAiaGVsbG8gd29ybGQiIGRhbGFtIGtvbXVuaXRhcyBNTC4gVW50dWsgYW5hbGlzIFIsIGRhdGFzZXQgZGFyaSBVQ0kgYmlhc2FueWEgdGVyc2VkaWEgZGFsYW0gZm9ybWF0IHRleHQgZmlsZSB5YW5nIGJlcnNpaCBkYW4gbXVkYWggZGlpbXBvciBtZW5nZ3VuYWthbiBmdW5nc2kgZGFzYXIgc2VwZXJ0aSByZWFkLmNzdigpIGF0YXUgcmVhZC50YWJsZSgpLg0KDQoqKkdvb2dsZSBEYXRhc2V0IFNlYXJjaCoqDQoNCkdvb2dsZSBEYXRhc2V0IFNlYXJjaCBiZXJmdW5nc2kgc2ViYWdhaSBtZXNpbiBwZW5jYXJpIG1ldGEgeWFuZyBtZW5naW5kZWtzIGRhdGFzZXQgZGFyaSBiZXJiYWdhaSBzdW1iZXIgZGkgc2VsdXJ1aCB3ZWIuIFBsYXRmb3JtIGluaSB0aWRhayBtZW55aW1wYW4gZGF0YXNldCBzZWNhcmEgbGFuZ3N1bmcsIG1lbGFpbmthbiBtZW5ndW1wdWxrYW4gbWV0YWRhdGEgZGFyaSBwdWJsaXNoZXIgZGF0YSBzZXBlcnRpIHBlbWVyaW50YWgsIGxlbWJhZ2EgcGVuZWxpdGlhbiwgZGFuIG9yZ2FuaXNhc2kgbGFpbm55YS4gS2V1bmdndWxhbiB1dGFtYW55YSBhZGFsYWgga2VtYW1wdWFubnlhIHVudHVrIG1lbGFrdWthbiBwZW5jYXJpYW4gc2VtYW50aWsgYWNyb3NzIG11bHRpcGxlIHNvdXJjZXMgZGFuIG1lbnllZGlha2FuIGluZm9ybWFzaSB0ZW50YW5nIGxpc2Vuc2ksIHRhbmdnYWwgdXBkYXRlLCBzZXJ0YSBmb3JtYXQgZGF0YS4gQmFnaSBwZW5nZ3VuYSBSLCBpbmkgc2FuZ2F0IG1lbWJhbnR1IHVudHVrIG1lbmVtdWthbiBkYXRhc2V0IHNwZXNpZmlrIHlhbmcgbXVuZ2tpbiB0ZXJzZW1idW55aSBkaSBiZXJiYWdhaSB3ZWJzaXRlLCBrZW11ZGlhbiBtZW5naW1wb3JueWEgbWVsYWx1aSBVUkwgbGFuZ3N1bmcgYXRhdSBkb3dubG9hZCBtYW51YWwuDQoNCioqR292ZXJubWVudCBPcGVuIERhdGEgUG9ydGFscyoqDQoNClBvcnRhbCBkYXRhIHBlbWVyaW50YWggc2VwZXJ0aSBEYXRhLmdvLmlkIChJbmRvbmVzaWEpLCBkYXRhLmdvdiAoQVMpLCBkYW4gZGF0YS5nb3YudWsgKFVLKSBtZW55ZWRpYWthbiBkYXRhIHJlc21pIHlhbmcgZGlrdW1wdWxrYW4gb2xlaCBpbnN0YW5zaSBwZW1lcmludGFoLiBEYXRhLWRhdGEgaW5pIG1lbmNha3VwIHN0YXRpc3RpayBkZW1vZ3JhZmksIGluZGlrYXRvciBla29ub21pLCBkYXRhIGdlb3NwYXNpYWwsIGRhbiBpbmZvcm1hc2kgcHVibGlrIGxhaW5ueWEgeWFuZyBkaWt1bXB1bGthbiBtZW5nZ3VuYWthbiBhbmdnYXJhbiBuZWdhcmEuIEtldW50dW5nYW4gdXRhbWEgZGF0YSBwZW1lcmludGFoIGFkYWxhaCBvdG9yaXRhcyBzdW1iZXJueWEgeWFuZyB0ZXJwZXJjYXlhLCBwZXJpb2Rpc2l0YXMgeWFuZyB0ZXJhdHVyIChidWxhbmFuL3RhaHVuYW4pLCBkYW4gY2FrdXBhbiBuYXNpb25hbCB5YW5nIGtvbXByZWhlbnNpZi4gVW50dWsgYW5hbGlzIFIsIGRhdGEgaW5pIGJpYXNhbnlhIHRlcnNlZGlhIGRhbGFtIGZvcm1hdCBDU1YgYXRhdSBtZWxhbHVpIEFQSSB5YW5nIGRhcGF0IGRpYWtzZXMgbGFuZ3N1bmcgbWVuZ2d1bmFrYW4gcGFja2FnZXMgc2VwZXJ0aSBodHRyIGF0YXUganNvbmxpdGUuDQoNCioqQVBJLUJhc2VkIFBsYXRmb3JtcyoqDQoNClBsYXRmb3JtIGJlcmJhc2lzIEFQSSBzZXBlcnRpIFlhaG9vIEZpbmFuY2UsIEFscGhhIFZhbnRhZ2UsIGRhbiBUd2l0dGVyIEFQSSBtZW55ZWRpYWthbiBha3NlcyByZWFsLXRpbWUgYXRhdSBuZWFyLXJlYWwtdGltZSBrZSBkYXRhIGRpbmFtaXMuIFBsYXRmb3JtIGZpbmFuc2lhbCBtZW5hd2Fya2FuIGRhdGEgcGFzYXIgc2FoYW0sIG5pbGFpIHR1a2FyLCBkYW4gaW5kaWthdG9yIGVrb25vbWkgZGVuZ2FuIGxhdGVuc2kgcmVuZGFoLCBzZW1lbnRhcmEgcGxhdGZvcm0gbWVkaWEgc29zaWFsIG1lbnllZGlha2FuIGFrc2VzIGtlIGRhdGEgaW50ZXJha3NpIHNvc2lhbCB0ZXJraW5pLiBLZXVuaWthbiBwbGF0Zm9ybSBpbmkgYWRhbGFoIHNpZmF0IGRhdGFueWEgeWFuZyBzZWxhbHUgZGlwZXJiYXJ1aSBkYW4ga2VtYW1wdWFuIHVudHVrIG1lbmdhbWJpbCBkYXRhIGhpc3RvcmlzIG1lbmRhbGFtLiBEaSBSLCBkZXZlbG9wZXIgdGVsYWggbWVtYnVhdCBwYWNrYWdlcyBraHVzdXMgc2VwZXJ0aSBxdWFudG1vZCB1bnR1ayBkYXRhIGZpbmFuc2lhbCBkYW4gcnR3ZWV0IHVudHVrIGRhdGEgVHdpdHRlciB5YW5nIG1lbnllZGVyaGFuYWthbiBwcm9zZXMgYXV0ZW50aWthc2kgZGFuIHF1ZXJ5IEFQSS4NCg0KKipTcGVjaWFsaXplZCBEb21haW4gUGxhdGZvcm1zKioNCg0KUGxhdGZvcm0ga2h1c3VzIGRvbWFpbiBzZXBlcnRpIE5PQUEgdW50dWsga2xpbWF0b2xvZ2ksIE5JSCB1bnR1ayBrZXNlaGF0YW4sIGRhbiBOQVNBIHVudHVrIGRhdGEgYW50YXJpa3NhIG1lbnllZGlha2FuIGRhdGFzZXQgeWFuZyBzYW5nYXQgc3Blc2lmaWsgZGFuIHRla25pcy4gRGF0YSBkYXJpIHBsYXRmb3JtIGluaSBiaWFzYW55YSBkaWt1bXB1bGthbiBtZW5nZ3VuYWthbiBpbnN0cnVtZW50YXNpIGtodXN1cywgbWVsYWx1aSBwZW5lbGl0aWFuIGJlcnRhaHVuLXRhaHVuLCBhdGF1IGRlbmdhbiBtZXRvZG9sb2dpIHlhbmcga29tcGxla3MuIE5pbGFpIHV0YW1hbnlhIHRlcmxldGFrIHBhZGEga2VkYWxhbWFuIGRhbiBha3VyYXNpIGRhdGEgeWFuZyBzdWxpdCBkaXRlbXVrYW4gZGkgcGxhdGZvcm0gdW11bS4gVW50dWsgYmVrZXJqYSBkZW5nYW4gZGF0YSBpbmkgZGkgUiwgc2VyaW5na2FsaSBkaXBlcmx1a2FuIHBhY2thZ2VzIHRhbWJhaGFuIHlhbmcga2h1c3VzIGRpYnVhdCB1bnR1ayBtZW5hbmdhbmkgZm9ybWF0IGRhdGEgbmljaGUgc2VwZXJ0aSBOZXRDREYgdW50dWsgZGF0YSBpa2xpbSBhdGF1IERJQ09NIHVudHVrIGRhdGEgbWVkaXMuDQoNCioqUiBCdWlsdC1pbiBEYXRhc2V0cyBkYW4gUGFja2FnZXMgRGF0YSoqDQoNClIgc2VuZGlyaSBkYXRhbmcgZGVuZ2FuIHB1bHVoYW4gZGF0YXNldCBidWlsdC1pbiB5YW5nIHNpYXAgZGlndW5ha2FuIHVudHVrIHR1anVhbiBwZW1iZWxhamFyYW4gZGFuIHByb3RvdHlwaW5nLiBEYXRhc2V0IHNlcGVydGkgbXRjYXJzLCBpcmlzLCBkYW4gYWlycXVhbGl0eSB0ZWxhaCBtZW5qYWRpIGJhaGFuIGxhdGloYW4gYmFnaSBnZW5lcmFzaSBhbmFsaXMgZGF0YS4gU2VsYWluIGl0dSwgZWNvc3lzdGVtIFIgbWVtaWxpa2kgcGFja2FnZXMgeWFuZyBraHVzdXMgYmVyaXNpIGRhdGFzZXQgc2VwZXJ0aSBueWNmbGlnaHRzMTMgKGRhdGEgcGVuZXJiYW5nYW4pLCBnYXBtaW5kZXIgKGRhdGEgcGVya2VtYmFuZ2FuIG5lZ2FyYSksIGRhbiBwYWxtZXJwZW5ndWlucyAoZGF0YSBwZW5ndWluKS4gS2VsZWJpaGFuIGRhdGFzZXQgaW5pIGFkYWxhaCBrZXNpYXBhbiBwYWthaW55YSAtIHN1ZGFoIGRhbGFtIGZvcm1hdCB5YW5nIGJlcnNpaCwgdGVyZG9rdW1lbnRhc2kgZGVuZ2FuIGJhaWssIGRhbiB0ZXJpbnRlZ3Jhc2kgc2VtcHVybmEgZGVuZ2FuIHRpZHl2ZXJzZSBlY29zeXN0ZW0sIG1lbWJ1YXRueWEgaWRlYWwgdW50dWsgZGVtb25zdHJhc2kgdGVrbmlrIGFuYWxpc2lzIGRhbiB2aXN1YWxpc2FzaS4NCg0KIyMgTG9hZCBEYXRhDQoNCiMjIyAqKkNvdW50cmllcyBvZiB0aGUgV29ybGQqKg0KDQpEYXRhc2V0IGtvbXByZWhlbnNpZiBpbmkgbWVueWVkaWFrYW4gaW5mb3JtYXNpIG1lbmRhbGFtIHRlbnRhbmcgYmVyYmFnYWkgbmVnYXJhIGRpIHNlbHVydWggZHVuaWEsIHlhbmcgbWVuY2FrdXAgYmVyYWdhbSBpbmRpa2F0b3Igc29zaW8tZWtvbm9taSwgZGVtb2dyYWZpcywgZGFuIGdlb2dyYWZpcy4gRGF0YSBpbmkgbWVsaXB1dGkgc3RhdGlzdGlrIGtlcGVuZHVkdWthbiwgaW5kaWthdG9yIGVrb25vbWkgbWFrcm8sIGZha3RvciBsaW5na3VuZ2FuLCBtZXRyaWsga2VzZWhhdGFuIG1hc3lhcmFrYXQsIHN0YXRpc3RpayBwZW5kaWRpa2FuLCBzZXJ0YSBzdHJ1a3R1ciBwZXJla29ub21pYW4gbmFzaW9uYWwuIERlbmdhbiBjYWt1cGFuIDIyNyBuZWdhcmEgZGFyaSBiZXJiYWdhaSBiZWxhaGFuIGR1bmlhLCBkYXRhc2V0IGluaSBtZW5hd2Fya2FuIHBlcnNwZWt0aWYgZ2xvYmFsIHlhbmcgaG9saXN0aWsgdGVudGFuZyBrYXJha3RlcmlzdGlrIG1hc2luZy1tYXNpbmcgbmVnYXJhLCBtZW11bmdraW5rYW4gYW5hbGlzaXMga29tcGFyYXRpZiBkYW4gc3R1ZGkgbGludGFzIHNla3RvciB5YW5nIG1lbmRhbGFtLg0KDQoqKkNvdW50cnkqKjogTmFtYSByZXNtaSBuZWdhcmENCg0KKipSZWdpb24qKjogS2Vsb21wb2sgd2lsYXlhaCBnZW9ncmFmaXMgbmVnYXJhDQoNCioqUG9wdWxhdGlvbioqOiBUb3RhbCBqdW1sYWggcGVuZHVkdWsgbmVnYXJhDQoNCioqQXJlYSAoc3EuIG1pLikqKjogTHVhcyB3aWxheWFoIGRhbGFtIG1pbCBwZXJzZWdpDQoNCioqUG9wLiBEZW5zaXR5IChwZXIgc3EuIG1pLikqKjogS2VwYWRhdGFuIHBlbmR1ZHVrIHBlciBtaWwgcGVyc2VnaQ0KDQoqKkNvYXN0bGluZSAoY29hc3QvYXJlYSByYXRpbykqKjogUmFzaW8gcGFuamFuZyBnYXJpcyBwYW50YWkgdGVyaGFkYXAgbHVhcyB3aWxheWFoDQoNCioqTmV0IG1pZ3JhdGlvbioqOiBNaWdyYXNpIGJlcnNpaCBwZXIgMTAwMCBwZW5kdWR1aw0KDQoqKkluZmFudCBtb3J0YWxpdHkgKHBlciAxMDAwIGJpcnRocykqKjogQW5na2Ega2VtYXRpYW4gYmF5aSBwZXIgMTAwMCBrZWxhaGlyYW4NCg0KKipHRFAgKFwkIHBlciBjYXBpdGEpKio6IFBlbmRhcGF0YW4gcGVyIGthcGl0YSBkYWxhbSBkb2xsYXIgQVMNCg0KKipMaXRlcmFjeSAoJSkqKjogUGVyc2VudGFzZSBwZW5kdWR1ayBtZWxlayBodXJ1Zg0KDQoqKlBob25lcyAocGVyIDEwMDApKio6IEp1bWxhaCB0ZWxlcG9uIHBlciAxMDAwIHBlbmR1ZHVrDQoNCioqQXJhYmxlICglKSoqOiBQZXJzZW50YXNlIGxhaGFuIGNvY29rIHVudHVrIHBlcnRhbmlhbg0KDQoqKkNyb3BzICglKSoqOiBQZXJzZW50YXNlIGxhaGFuIHVudHVrIHRhbmFtYW4gcGVybWFuZW4NCg0KKipPdGhlciAoJSkqKjogUGVyc2VudGFzZSBsYWhhbiB1bnR1ayBwZW5nZ3VuYWFuIG5vbi1wZXJ0YW5pYW4NCg0KKipDbGltYXRlKio6IEtvZGUga2xhc2lmaWthc2kgaWtsaW0gKDEtNCkNCg0KKipCaXJ0aHJhdGUqKjogQW5na2Ega2VsYWhpcmFuIHBlciAxMDAwIHBlbmR1ZHVrDQoNCioqRGVhdGhyYXRlKio6IEFuZ2thIGtlbWF0aWFuIHBlciAxMDAwIHBlbmR1ZHVrDQoNCioqQWdyaWN1bHR1cmUqKjogS29udHJpYnVzaSBzZWt0b3IgcGVydGFuaWFuIHRlcmhhZGFwIEdEUCAocHJvcG9yc2kpDQoNCioqSW5kdXN0cnkqKjogS29udHJpYnVzaSBzZWt0b3IgaW5kdXN0cmkgdGVyaGFkYXAgR0RQIChwcm9wb3JzaSkNCg0KKipTZXJ2aWNlKio6IEtvbnRyaWJ1c2kgc2VrdG9yIGphc2EgdGVyaGFkYXAgR0RQIChwcm9wb3JzaSkNCg0KRGF0YSBkYXBhdCBkaXBlcm9sZWggZGVuZ2FuIG1lbmRvd25sb2FkIGxpbmsgZGliYXdhaCBpbmkNCg0KW0RhdGFdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvZmVybmFuZG9sL2NvdW50cmllcy1vZi10aGUtd29ybGQpDQoNCiMjIEltcG9ydCBkYXRhDQoNCmBgYHtyfQ0KY291bnRyaWVzIDwtIHJlYWRfY3N2KCJDOlxcVXNlcnNcXExlZ2lvblxcRG9jdW1lbnRzXFxBc2lzdGVuIERvc2VuXFxNYW5kYXJlbFxcRGF0YSBXcmFuZ2xpbmcgZGkgUlxcY291bnRyaWVzIG9mIHRoZSB3b3JsZC5jc3YiLHNob3dfY29sX3R5cGVzID0gRkFMU0UpDQpgYGANCg0KIyMgRnVuZ3NpIFdyYW5nbGluZw0KDQpCZXJpa3V0IG1hdGVyaSBsZW5na2FwIHVudHVrIDIwIGZ1bmdzaSAqKnRpZHl2ZXJzZSoqIGRlbmdhbiBjb250b2ggbWVuZ2d1bmFrYW4gZGF0YXNldCAiQ291bnRyaWVzIG9mIHRoZSBXb3JsZCI6DQoNCiMjIyAqKjEuIGdsaW1wc2UoKSoqDQoNCioqRnVuZ3NpKio6IE1lbmFtcGlsa2FuIHByZXZpZXcgZGF0YXNldCBkZW5nYW4gaW5mb3JtYXNpIHN0cnVrdHVyIGRhdGEsIHRpcGUgdmFyaWFiZWwsIGRhbiBiZWJlcmFwYSBuaWxhaSBjb250b2guIFNhbmdhdCB1c2VmdWwgdW50dWsgZWtzcGxvcmFzaSBkYXRhIGF3YWwgeWFuZyBsZWJpaCByZWFkYWJsZSBkaWJhbmRpbmcgc3RyKCkuDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpIA0KbGlicmFyeShyZWFkcikgIA0KIyBNZWxpaGF0IHN0cnVrdHVyIGRhdGEgDQpnbGltcHNlKGNvdW50cmllcykNCmBgYA0KDQojIyMgKioyLiBzZWxlY3QoKSoqDQoNCioqRnVuZ3NpKio6IE1lbWlsaWgga29sb20gdGVydGVudHUgZGFyaSBkYXRhc2V0IGJlcmRhc2Fya2FuIG5hbWEgYXRhdSBrcml0ZXJpYSB0ZXJ0ZW50dS4gRGFwYXQganVnYSBkaWd1bmFrYW4gdW50dWsgbWVyZW5hbWUga29sb20gZGFuIG1lbmd1YmFoIHVydXRhbiBrb2xvbS4NCg0KYGBge3J9DQojIE1lbWlsaWgga29sb20gdGVydGVudHUgDQpjb3VudHJpZXNfc2VsZWN0ZWQgPC0gY291bnRyaWVzICU+JSAgIA0KICBzZWxlY3QoQ291bnRyeSwgUG9wdWxhdGlvbiwgYEdEUCAoJCBwZXIgY2FwaXRhKWAsIFJlZ2lvbikgIA0KDQpjb3VudHJpZXNfc2VsZWN0ZWQNCmBgYA0KDQpgYGB7cn0NCiMgTWVtaWxpaCBrb2xvbSBkZW5nYW4gcGF0dGVybiANCmNvdW50cmllc19lY29uIDwtIGNvdW50cmllcyAlPiUgICANCiAgc2VsZWN0KENvdW50cnksIGNvbnRhaW5zKCJHRFAiKSwgY29udGFpbnMoInJhdGUiKSkNCg0KY291bnRyaWVzX2Vjb24NCmBgYA0KDQojIyMgKiozLiAlXD4lIChQaXBlIE9wZXJhdG9yKSoqDQoNCioqRnVuZ3NpKio6IE9wZXJhdG9yIHBpcGUgeWFuZyBtZW50cmFuc2Zvcm0gb3V0cHV0IGRhcmkgZnVuZ3NpIHNlYmVsYWgga2lyaSBtZW5qYWRpIGlucHV0IHBlcnRhbWEgdW50dWsgZnVuZ3NpIHNlYmVsYWgga2FuYW4uIE1lbWJ1YXQga29kZSBsZWJpaCByZWFkYWJsZSBkYW4gc2VxdWVudGlhbC4NCg0KYGBge3J9DQojIFRhbnBhIHBpcGUgKG5lc3RlZCBmdW5jdGlvbikgDQpyZXN1bHQxIDwtIGFycmFuZ2UoZmlsdGVyKGNvdW50cmllcywgUG9wdWxhdGlvbiA+IDEwMDAwMDAwMCksIGRlc2MoYEdEUCAoJCBwZXIgY2FwaXRhKWApKSAgDQoNCiMgRGVuZ2FuIHBpcGUgKGxlYmloIG11ZGFoIGRpYmFjYSkgDQpyZXN1bHQyIDwtIGNvdW50cmllcyAlPiUgICANCiAgZmlsdGVyKFBvcHVsYXRpb24gPiAxMDAwMDAwMDApICU+JSAgIA0KICBhcnJhbmdlKGRlc2MoYEdEUCAoJCBwZXIgY2FwaXRhKWApKSAgDQpyZXN1bHQxIA0KcmVzdWx0Mg0KYGBgDQoNCiMjIyAqKjQuIGZpbHRlcigpKioNCg0KKipGdW5nc2kqKjogTWVueWFyaW5nIGJhcmlzIGRhdGEgYmVyZGFzYXJrYW4ga29uZGlzaSBsb2dpa2EgdGVydGVudHUuIERhcGF0IG1lbmdndW5ha2FuIG11bHRpcGxlIGNvbmRpdGlvbnMgZGVuZ2FuIG9wZXJhdG9yICYsIFx8LCAhLg0KDQpgYGB7cn0NCiMgRmlsdGVyIG5lZ2FyYSBkZW5nYW4gR0RQIHRpbmdnaSBkYW4gcG9wdWxhc2kgYmVzYXIgDQpyaWNoX2NvdW50cmllcyA8LSBjb3VudHJpZXMgJT4lICAgDQogIGZpbHRlcihgR0RQICgkIHBlciBjYXBpdGEpYCA+IDMwMDAwICYgUG9wdWxhdGlvbiA+IDEwMDAwMDAwKSAgDQpyaWNoX2NvdW50cmllcw0KYGBgDQoNCmBgYHtyfQ0KIyBGaWx0ZXIgbmVnYXJhIGRhcmkgcmVnaW9uIHRlcnRlbnR1IA0KYXNpYW5fY291bnRyaWVzIDwtIGNvdW50cmllcyAlPiUgICANCiAgZmlsdGVyKHN0cl9kZXRlY3QoUmVnaW9uLCAiQVNJQSIpKSAgDQphc2lhbl9jb3VudHJpZXMNCmBgYA0KDQojIyMgKio1LiBhcnJhbmdlKCkqKg0KDQoqKkZ1bmdzaSoqOiBNZW5ndXJ1dGthbiBiYXJpcyBkYXRhIGJlcmRhc2Fya2FuIHNhdHUgYXRhdSBsZWJpaCBrb2xvbS4gRGVmYXVsdCBhc2NlbmRpbmcsIGd1bmFrYW4gZGVzYygpIHVudHVrIGRlc2NlbmRpbmcuDQoNCmBgYHtyfQ0KIyBVcnV0a2FuIGJlcmRhc2Fya2FuIEdEUCB0ZXJ0aW5nZ2kgDQpjb3VudHJpZXNfcmljaF9maXJzdCA8LSBjb3VudHJpZXMgJT4lICAgDQogIGFycmFuZ2UoZGVzYyhgR0RQICgkIHBlciBjYXBpdGEpYCkpICANCmNvdW50cmllc19yaWNoX2ZpcnN0DQpgYGANCg0KYGBge3J9DQojIFVydXRrYW4gYmVyZGFzYXJrYW4gcmVnaW9uIGxhbHUgR0RQIA0KY291bnRyaWVzX3NvcnRlZCA8LSBjb3VudHJpZXMgJT4lICAgDQogIGFycmFuZ2UoUmVnaW9uLCBkZXNjKGBHRFAgKCQgcGVyIGNhcGl0YSlgKSkgIA0KY291bnRyaWVzX3NvcnRlZA0KYGBgDQoNCiMjIyAqKjYuIG11dGF0ZSgpKioNCg0KKipGdW5nc2kqKjogTWVtYnVhdCBrb2xvbSBiYXJ1IGF0YXUgbWVtb2RpZmlrYXNpIGtvbG9tIGV4aXN0aW5nLiBEYXBhdCBtZW5nZ3VuYWthbiBvcGVyYXNpIGFyaXRtYXRpa2EsIGZ1bmdzaSwgYXRhdSBjb25kaXRpb25hbCBsb2dpYy4NCg0KYGAge3J9ICMgTWVtYnVhdCBrb2xvbSBiYXJ1fSBjb3VudHJpZXNfbW9kaWZpZWQgPC0gY291bnRyaWVzICU+JSAgICAgIG11dGF0ZSggICAgICAgICAgR0RQX3RvdGFsID0gUG9wdWxhdGlvbiAqIGBHRFAgKCQgcGVyIGNhcGl0YSlgLCAgICAgICAgICBkZXZlbG9wbWVudF9sZXZlbCA9IGlmZWxzZShgR0RQICgkIHBlciBjYXBpdGEpYCA+IDIwMDAwLCAiRGV2ZWxvcGVkIiwgIkRldmVsb3BpbmciKSAgICkgICBjb3VudHJpZXNfbW9kaWZpZWQgYGANCg0KIyMjICoqNy4gc3VtbWFyaXplKCkgLyBzdW1tYXJpc2UoKSoqDQoNCioqRnVuZ3NpKio6IE1lbWJ1YXQgc3VtbWFyeSBzdGF0aXN0aWNzIHVudHVrIHNhdHUgYXRhdSBsZWJpaCBrb2xvbS4gQmlhc2FueWEgZGlwYWthaSBkZW5nYW4gZ3JvdXBfYnkoKS4NCg0KYGBge3J9DQojIFN1bW1hcnkgc3RhdGlzdGljcyB1bnR1ayBzZWx1cnVoIGRhdGFzZXQgDQpzdW1tYXJ5X3N0YXRzIDwtIGNvdW50cmllcyAlPiUgICANCiAgc3VtbWFyaXNlKCAgICAgDQogICAgYXZnX2dkcCA9IG1lYW4oYEdEUCAoJCBwZXIgY2FwaXRhKWAsIG5hLnJtID0gVFJVRSksICAgICANCiAgICBtYXhfcG9wID0gbWF4KFBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksICAgICANCiAgICB0b3RhbF9jb3VudHJpZXMgPSBuKCkgICANCiAgICApIA0Kc3VtbWFyeV9zdGF0cw0KYGBgDQoNCmBgYHtyfQ0KZWNvbm9taWNfc3VtbWFyeSA8LSBjb3VudHJpZXMgJT4lICAgDQogIHN1bW1hcmlzZSggICAgIA0KICAgIHRvdGFsX3BvcHVsYXRpb25fd29ybGQgPSBzdW0oUG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSwgICAgIA0KICAgIGF2Z19nZHBfcGVyX2NhcGl0YSA9IG1lYW4oYEdEUCAoJCBwZXIgY2FwaXRhKWAsIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuX2dkcF9wZXJfY2FwaXRhID0gbWVkaWFuKGBHRFAgKCQgcGVyIGNhcGl0YSlgLCBuYS5ybSA9IFRSVUUpLCAgICAgDQogICAgc2RfZ2RwID0gc2QoYEdEUCAoJCBwZXIgY2FwaXRhKWAsIG5hLnJtID0gVFJVRSksICAgICANCiAgICBtaW5fZ2RwID0gbWluKGBHRFAgKCQgcGVyIGNhcGl0YSlgLCBuYS5ybSA9IFRSVUUpLCAgICAgDQogICAgbWF4X2dkcCA9IG1heChgR0RQICgkIHBlciBjYXBpdGEpYCwgbmEucm0gPSBUUlVFKSwgICAgIA0KICAgIHRvdGFsX2NvdW50cmllcyA9IG4oKSwgICAgIA0KICAgIGNvdW50cmllc193aXRoX2hpZ2hfZ2RwID0gc3VtKGBHRFAgKCQgcGVyIGNhcGl0YSlgID4gMjAwMDAsIG5hLnJtID0gVFJVRSksICAgICANCiAgICBwZXJjZW50YWdlX2hpZ2hfZ2RwID0gcm91bmQobWVhbihgR0RQICgkIHBlciBjYXBpdGEpYCA+IDIwMDAwLCBuYS5ybSA9IFRSVUUpICogMTAwLCAxKSwgICAgIA0KICAgIGF2Z19saXRlcmFjeSA9IG1lYW4oYExpdGVyYWN5ICglKWAsIG5hLnJtID0gVFJVRSksICAgICANCiAgICBhdmdfaW5mYW50X21vcnRhbGl0eSA9IG1lYW4oYEluZmFudCBtb3J0YWxpdHkgKHBlciAxMDAwIGJpcnRocylgLCBuYS5ybSA9IFRSVUUpICAgKSAgDQplY29ub21pY19zdW1tYXJ5ICU+JSBwcmludCgpDQpgYGANCg0KYGBge3J9DQpjb3VudHJpZXNfY2xlYW4gPC0gY291bnRyaWVzICU+JSAgIA0KICBtdXRhdGUoICAgICANCiAgICBgUGhvbmVzIChwZXIgMTAwMClgID0gYXMubnVtZXJpYyhzdHJfcmVwbGFjZShgUGhvbmVzIChwZXIgMTAwMClgLCAiLCIsICIuIikpLA0KICAgIGBHRFAgKCQgcGVyIGNhcGl0YSlgID0gYXMubnVtZXJpYyhzdHJfcmVwbGFjZShgR0RQICgkIHBlciBjYXBpdGEpYCwgIiwiLCAiLiIpKSwNCiAgICBgTGl0ZXJhY3kgKCUpYCA9IGFzLm51bWVyaWMoc3RyX3JlcGxhY2UoYExpdGVyYWN5ICglKWAsICIsIiwgIi4iKSksICAgICANCiAgICBgSW5mYW50IG1vcnRhbGl0eSAocGVyIDEwMDAgYmlydGhzKWAgPSBhcy5udW1lcmljKHN0cl9yZXBsYWNlKGBJbmZhbnQgbW9ydGFsaXR5IChwZXIgMTAwMCBiaXJ0aHMpYCwgIiwiLCAiLiIpKSAgIA0KICApDQoNCiMgQW5hbGlzaXMgZGVuZ2FuIGRhdGEgeWFuZyBzdWRhaCBkaWJlcnNpaGthbiANCnJlZ2lvbmFsX2FuYWx5c2lzX2NsZWFuIDwtIGNvdW50cmllc19jbGVhbiAlPiUgICANCiAgbXV0YXRlKCAgICAgDQogICAgZ2RwX2NhdGVnb3J5ID0gY2FzZV93aGVuKCAgICAgICANCiAgICAgIGBHRFAgKCQgcGVyIGNhcGl0YSlgID49IDI1MDAwIH4gIkhpZ2ggSW5jb21lIiwgICAgICAgDQogICAgICBgR0RQICgkIHBlciBjYXBpdGEpYCA+PSAxMDAwMCB+ICJVcHBlciBNaWRkbGUgSW5jb21lIiwgICAgICAgIA0KICAgICAgYEdEUCAoJCBwZXIgY2FwaXRhKWAgPj0gMjUwMCB+ICJMb3dlciBNaWRkbGUgSW5jb21lIiwgICAgICAgDQogICAgICBgR0RQICgkIHBlciBjYXBpdGEpYCA8IDI1MDAgfiAiTG93IEluY29tZSIsICAgICAgIA0KICAgICAgVFJVRSB+ICJVbmtub3duIiAgICAgDQogICAgKSAgIA0KICApICU+JSAgIA0KICBncm91cF9ieShSZWdpb24sIGdkcF9jYXRlZ29yeSkgJT4lICAgDQogIHN1bW1hcmlzZSggICAgIA0KICAgIG51bWJlcl9vZl9jb3VudHJpZXMgPSBuKCksICAgICANCiAgICB0b3RhbF9wb3B1bGF0aW9uID0gc3VtKFBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksICAgIA0KICAgIGF2Z19nZHAgPSBtZWFuKGBHRFAgKCQgcGVyIGNhcGl0YSlgLCBuYS5ybSA9IFRSVUUpLCAgICAgDQogICAgYXZnX2xpdGVyYWN5ID0gbWVhbihgTGl0ZXJhY3kgKCUpYCwgbmEucm0gPSBUUlVFKSwgICAgIA0KICAgIGF2Z19pbmZhbnRfbW9ydGFsaXR5ID0gbWVhbihgSW5mYW50IG1vcnRhbGl0eSAocGVyIDEwMDAgYmlydGhzKWAsIG5hLnJtID0gVFJVRSksICAgICANCiAgICBtZWRpYW5fcGhvbmVzID0gbWVkaWFuKGBQaG9uZXMgKHBlciAxMDAwKWAsIG5hLnJtID0gVFJVRSksICAgICANCiAgICAuZ3JvdXBzID0gJ2Ryb3AnICAgDQogICkgJT4lICANCiAgYXJyYW5nZShSZWdpb24sIGRlc2MoYXZnX2dkcCkpDQoNCnJlZ2lvbmFsX2FuYWx5c2lzX2NsZWFuICU+JSBoZWFkKDEwKQ0KYGBgDQoNCiMjIyAqKjguIGdyb3VwX2J5KCkqKg0KDQoqKkZ1bmdzaSoqOiBNZW5nZWxvbXBva2thbiBkYXRhIGJlcmRhc2Fya2FuIHNhdHUgYXRhdSBsZWJpaCBrb2xvbSBrYXRlZ29yaWthbC4gQmlhc2FueWEgZGlpa3V0aSBkZW5nYW4gc3VtbWFyaXplKCkuDQoNCmBgYHtyfQ0KIyBSYXRhLXJhdGEgR0RQIHBlciByZWdpb24gLSBuYW1hIGNodW5rIHRhbnBhIGNvbW1lbnQNCmdkcF9ieV9yZWdpb24gPC0gY291bnRyaWVzICU+JSAgIA0KICBncm91cF9ieShSZWdpb24pICU+JSAgIA0KICBzdW1tYXJpc2UoDQogICAgYXZnX2dkcCA9IG1lYW4oYEdEUCAoJCBwZXIgY2FwaXRhKWAsIG5hLnJtID0gVFJVRSksICAgIA0KICAgIGNvdW50X2NvdW50cmllcyA9IG4oKSAgIA0KICApICU+JSAgIA0KICBhcnJhbmdlKGRlc2MoYXZnX2dkcCkpICANCg0KZ2RwX2J5X3JlZ2lvbg0KYGBgDQoNCiMjIyAqKjkuIGNvdW50KCkqKg0KDQoqKkZ1bmdzaSoqOiBNZW5naGl0dW5nIGZyZWt1ZW5zaSB1bnR1ayBrb21iaW5hc2kgbmlsYWkgZGFsYW0ga29sb20uIFNob3J0Y3V0IHVudHVrIGdyb3VwX2J5KCkgKyBzdW1tYXJpc2UobigpKS4NCg0KYGBge3J9DQpyZWdpb25fY291bnQgPC0gY291bnRyaWVzICU+JSAgIA0KICBjb3VudChSZWdpb24sIHNvcnQgPSBUUlVFKSANCg0KcmVnaW9uX2NvdW50DQoNCiMgQ291bnQgZGVuZ2FuIG11bHRpcGxlIGNvbHVtbnMgDQpyZWdpb25fZGV2ZWxvcG1lbnQgPC0gY291bnRyaWVzICU+JSAgIA0KICBtdXRhdGUoZGV2ZWxvcG1lbnQgPSBpZmVsc2UoYEdEUCAoJCBwZXIgY2FwaXRhKWAgPiAyMDAwMCwgIkRldmVsb3BlZCIsICJEZXZlbG9waW5nIikpICU+JSAgIA0KICBjb3VudChSZWdpb24sIGRldmVsb3BtZW50KSAgDQpyZWdpb25fY291bnQgDQpyZWdpb25fZGV2ZWxvcG1lbnQNCmBgYA0KDQojIyMgKioxMC4gc3RyX2RldGVjdCgpIGRhcmkgcGFja2FnZSBzdHJpbmdyKioNCg0KKipGdW5nc2kqKjogTWVuZGV0ZWtzaSBwYXR0ZXJuIHRla3MgZGFsYW0gc3RyaW5nLiBSZXR1cm4gbG9naWNhbCB2ZWN0b3IgeWFuZyBzYW5nYXQgdXNlZnVsIHVudHVrIGZpbHRlcmluZy4NCg0KYGBge3J9DQpsaWJyYXJ5KHN0cmluZ3IpICANCiMgRmlsdGVyIG5lZ2FyYSBkZW5nYW4gbmFtYSBtZW5nYW5kdW5nICJsYW5kIiANCmxhbmRfY291bnRyaWVzIDwtIGNvdW50cmllcyAlPiUgICANCiAgZmlsdGVyKHN0cl9kZXRlY3QoQ291bnRyeSwgImxhbmQiKSkgIA0KbGFuZF9jb3VudHJpZXMNCmBgYA0KDQpgYGB7cn0NCiMgRmlsdGVyIHJlZ2lvbiBBc2lhIA0KYXNpYW5fcmVnaW9uIDwtIGNvdW50cmllcyAlPiUgICANCiAgZmlsdGVyKHN0cl9kZXRlY3QoUmVnaW9uLCAiQVNJQSIpKSAgDQoNCmFzaWFuX3JlZ2lvbg0KYGBgDQoNCiMjIyAqKjExLiBjYXNlX3doZW4oKSoqDQoNCioqRnVuZ3NpKio6IE1lbWJ1YXQgY29uZGl0aW9uYWwgc3RhdGVtZW50cyBrb21wbGVrcyBkZW5nYW4gbXVsdGlwbGUgY29uZGl0aW9ucy4gTGViaWggcG93ZXJmdWwgZGFyaSBpZmVsc2UoKS4NCg0KYGBge3J9DQojIEtsYXNpZmlrYXNpIG5lZ2FyYSBiZXJkYXNhcmthbiBHRFAgDQpjb3VudHJpZXNfY2xhc3NpZmllZCA8LSBjb3VudHJpZXMgJT4lICAgDQogIG11dGF0ZSggICAgIA0KICAgIGluY29tZV9ncm91cCA9IGNhc2Vfd2hlbiggICAgICAgDQogICAgICBgR0RQICgkIHBlciBjYXBpdGEpYCA+PSAzMDAwMCB+ICJIaWdoIEluY29tZSIsICAgICAgIA0KICAgICAgYEdEUCAoJCBwZXIgY2FwaXRhKWAgPj0gMTAwMDAgfiAiVXBwZXIgTWlkZGxlIiwgICAgICAgDQogICAgICBgR0RQICgkIHBlciBjYXBpdGEpYCA+PSAyNTAwIH4gIkxvd2VyIE1pZGRsZSIsICAgICAgIA0KICAgICAgYEdEUCAoJCBwZXIgY2FwaXRhKWAgPCAyNTAwIH4gIkxvdyBJbmNvbWUiLCAgICAgICANCiAgICAgIFRSVUUgfiAiVW5rbm93biIgICAgIA0KICAgICAgKSAgIA0KICAgICkNCg0KY291bnRyaWVzX2NsYXNzaWZpZWQNCmBgYA0KDQojIyMgKioxMi4gcmVuYW1lX3dpdGgoKSoqDQoNCioqRnVuZ3NpKio6IFJlbmFtZSBrb2xvbSBiZXJkYXNhcmthbiBmdW5jdGlvbiBhdGF1IHBhdHRlcm4uIFVzZWZ1bCB1bnR1ayBjbGVhbmluZyBuYW1hIGtvbG9tLg0KDQpgYGB7cn0NCiMgUmVuYW1lIGtvbG9tIGtlIGxvd2VyY2FzZSANCmNvdW50cmllc19jbGVhbiA8LSBjb3VudHJpZXMgJT4lICAgDQogIHJlbmFtZV93aXRoKHRvbG93ZXIpICANCg0KY291bnRyaWVzX2NsZWFuDQpgYGANCg0KYGBge3J9DQojIFJlbmFtZSBtZW5naGFwdXMgc3Blc2lhbCBrYXJha3RlciANCmNvdW50cmllc19jbGVhbjIgPC0gY291bnRyaWVzICU+JSAgIA0KICByZW5hbWVfd2l0aCh+IHN0cl9yZW1vdmVfYWxsKC4sICJcXCh8XFwpfFxcJHwgcGVyIGNhcGl0YSIpKSAgDQpjb3VudHJpZXNfY2xlYW4yDQpgYGANCg0KIyMjICoqMTMuIGFjcm9zcygpICsgd2hlcmUoKSoqDQoNCioqRnVuZ3NpKio6IE1lbGFrdWthbiBvcGVyYXNpIHlhbmcgc2FtYSBwYWRhIG11bHRpcGxlIGNvbHVtbnMgeWFuZyBtZW1lbnVoaSBrb25kaXNpIHRlcnRlbnR1Lg0KDQpgYGB7cn0NCiMgQ29udmVydCBzZW11YSBrb2xvbSBudW1lcmljIGtlIGludGVnZXIgDQpjb3VudHJpZXNfaW50IDwtIGNvdW50cmllcyAlPiUgICANCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgYXMuaW50ZWdlcikpICANCmNvdW50cmllc19pbnQNCmBgYA0KDQpgYGB7cn0NCiMgUmF0YS1yYXRhIHVudHVrIHNlbXVhIGtvbG9tIG51bWVyaWMgcGVyIHJlZ2lvbiANCm51bWVyaWNfc3VtbWFyeSA8LSBjb3VudHJpZXMgJT4lICAgDQogIGdyb3VwX2J5KFJlZ2lvbikgJT4lICAgDQogIHN1bW1hcmlzZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYyksIG1lYW4sIG5hLnJtID0gVFJVRSkpICANCg0KbnVtZXJpY19zdW1tYXJ5DQpgYGANCg0KIyMjICoqMTQuIGRpc3RpbmN0KCkqKg0KDQoqKkZ1bmdzaSoqOiBNZW5nYW1iaWwgdW5pcXVlIHJvd3MgYmVyZGFzYXJrYW4ga29tYmluYXNpIGtvbG9tLiBVc2VmdWwgdW50dWsgbWVuZ2hpbGFuZ2thbiBkdXBsaWthdC4NCg0KYGBge3J9DQojIFVuaXF1ZSByZWdpb25zIA0KdW5pcXVlX3JlZ2lvbnMgPC0gY291bnRyaWVzICU+JSAgIA0KICBkaXN0aW5jdChSZWdpb24pIA0KdW5pcXVlX3JlZ2lvbnMNCmBgYA0KDQpgYGB7cn0NCiMgVW5pcXVlIGNvbWJpbmF0aW9ucyANCnVuaXF1ZV9jb21iaW5hdGlvbnMgPC0gY291bnRyaWVzICU+JSAgIA0KICBkaXN0aW5jdChSZWdpb24sIENsaW1hdGUpICANCnVuaXF1ZV9jb21iaW5hdGlvbnMNCmBgYA0KDQojIyMgKioxNS4gc2xpY2UoKSoqDQoNCioqRnVuZ3NpKio6IE1lbWlsaWggYmFyaXMgdGVydGVudHUgYmVyZGFzYXJrYW4gcG9zaXNpL2luZGV4LiBKdWdhIGJpc2Egc2xpY2VfbWluL21heC9oZWFkL3RhaWwuDQoNCmBgYHtyfQ0KIyAxMCBuZWdhcmEgcGVydGFtYSANCmZpcnN0XzEwIDwtIGNvdW50cmllcyAlPiUgICANCiAgc2xpY2UoMToxMCkgDQpmaXJzdF8xMCAgDQojIDUgbmVnYXJhIGRlbmdhbiBHRFAgdGVydGluZ2dpIA0KdG9wNV9nZHAgPC0gY291bnRyaWVzICU+JSANCiAgc2xpY2VfbWF4KGBHRFAgKCQgcGVyIGNhcGl0YSlgLCBuID0gNSkgIA0KdG9wNV9nZHAgDQojIDEwJSBuZWdhcmEgZGVuZ2FuIHBvcHVsYXNpIHRlcmtlY2lsIA0KYm90dG9tXzEwcGN0IDwtIGNvdW50cmllcyAlPiUgICANCiAgc2xpY2VfbWluKFBvcHVsYXRpb24sIHByb3AgPSAwLjEpIA0KYm90dG9tXzEwcGN0DQpgYGANCg0KIyMjICoqMTYuIHJlbG9jYXRlKCkqKg0KDQoqKkZ1bmdzaSoqOiBNZW5ndWJhaCB1cnV0YW4ga29sb20gZGFsYW0gZGF0YXNldC4gU2FuZ2F0IHVzZWZ1bCB1bnR1ayByZW9yZ2FuaXNhc2kgZGF0YS4NCg0KYGBge3J9DQojIFBpbmRhaCBrb2xvbSBSZWdpb24ga2UgZGVwYW4gDQpjb3VudHJpZXNfcmVvcmRlcmVkIDwtIGNvdW50cmllcyAlPiUgICANCiAgcmVsb2NhdGUoUmVnaW9uLCAuYmVmb3JlID0gQ291bnRyeSkgIA0KY291bnRyaWVzX3Jlb3JkZXJlZA0KYGBgDQoNCmBgYHtyfQ0KIyBQaW5kYWggYmViZXJhcGEga29sb20ga2UgZGVwYW4gDQpjb3VudHJpZXNfcmVvcmRlcmVkMiA8LSBjb3VudHJpZXMgJT4lICAgDQogIHJlbG9jYXRlKHdoZXJlKGlzLmNoYXJhY3RlciksIC5iZWZvcmUgPSB3aGVyZShpcy5udW1lcmljKSkgIA0KY291bnRyaWVzX3Jlb3JkZXJlZDINCmBgYA0KDQojIyMgKioxNy4gY2FzZV93aGVuKCkgKGRhbGFtIG11dGF0ZSkqKg0KDQoqKkZ1bmdzaSoqOiBFeHRlbmRlZCBjb250b2ggY2FzZV93aGVuIHVudHVrIG11bHRpcGxlIGNvbmRpdGlvbnMgZGFsYW0gcGVtYnVhdGFuIHZhcmlhYmVsLg0KDQpgYGB7cn0NCmNvdW50cmllc19jb21wbGV4IDwtIGNvdW50cmllcyAlPiUgICANCiAgbXV0YXRlKCAgICAgDQogICAgY291bnRyeV9jYXRlZ29yeSA9IGNhc2Vfd2hlbiggICAgICAgDQogICAgICBgR0RQICgkIHBlciBjYXBpdGEpYCA+IDMwMDAwICYgYExpdGVyYWN5ICglKWAgPiA5NSB+ICJEZXZlbG9wZWQgSGlnaCBMaXRlcmFjeSIsDQogICAgICBgR0RQICgkIHBlciBjYXBpdGEpYCA+IDMwMDAwICYgYExpdGVyYWN5ICglKWAgPD0gOTUgfiAiRGV2ZWxvcGVkIE1lZGl1bSBMaXRlcmFjeSIsICAgICAgIA0KICAgICAgYEdEUCAoJCBwZXIgY2FwaXRhKWAgPD0gMzAwMDAgJiBgSW5mYW50IG1vcnRhbGl0eSAocGVyIDEwMDAgYmlydGhzKWAgPCAxMCB+ICJEZXZlbG9waW5nIExvdyBNb3J0YWxpdHkiLCAgICAgICANCiAgICAgIFRSVUUgfiAiRGV2ZWxvcGluZyBIaWdoIE1vcnRhbGl0eSIgICAgIA0KICAgICkgICANCiAgKQ0KDQpjb3VudHJpZXNfY29tcGxleA0KYGBgDQoNCiMjIyAqKjE4LiBiaW5kX3Jvd3MoKSAmIGJpbmRfY29scygpKioNCg0KKipGdW5nc2kqKjogTWVuZ2dhYnVuZ2thbiBkYXRhIGZyYW1lcyBzZWNhcmEgdmVydGlrYWwgKHJvd3MpIGF0YXUgaG9yaXpvbnRhbCAoY29sdW1ucykuDQoNCmBgYHtyfQ0KIyBQaXNhaCBkYXRhIG1lbmphZGkgZHVhIGJhZ2lhbiANCmFzaWFfY291bnRyaWVzIDwtIGNvdW50cmllcyAlPiUgZmlsdGVyKHN0cl9kZXRlY3QoUmVnaW9uLCAiQVNJQSIpKSANCmV1cm9wZV9jb3VudHJpZXMgPC0gY291bnRyaWVzICU+JSBmaWx0ZXIoc3RyX2RldGVjdChSZWdpb24sICJFVVJPUEUiKSkgDQoNCiMgR2FidW5na2FuIGtlbWJhbGkgDQpjb21iaW5lZCA8LSBiaW5kX3Jvd3MoYXNpYV9jb3VudHJpZXMsIGV1cm9wZV9jb3VudHJpZXMpICANCiMgVGFtYmFoa2FuIGtvbG9tIElEIA0KY291bnRyaWVzX3dpdGhfaWQgPC0gY291bnRyaWVzICU+JSAgIA0KICBiaW5kX2NvbHMoY291bnRyeV9pZCA9IDE6bnJvdyguKSwgLikNCmBgYA0KDQojIyMgKioxOS4gcGl2b3RfbG9uZ2VyKCkgJiBwaXZvdF93aWRlcigpKioNCg0KRnVuZ3NpIGBwaXZvdF9sb25nZXJgIGRpZ3VuYWthbiB1bnR1ayBtZW50cmFuc2Zvcm1hc2kgZGF0YXNldCB5YW5nIGJlcmJlbnR1ayB3aWRlIGtlIGRhdGFzZXQgeWFuZyBiZXJiZW50dWsgbG9uZy4gU2ViYWxpa255YSBgcGl2b3Rfd2lkZXJgIGRpZ3VuYWthbiB1bnR1ayBtZW50cmFuc2Zvcm1hc2kgZGF0YXNldCB5YW5nIGJlcmJlbnR1ayBsb25nIGtlIGRhdGFzZXQgeWFuZyBiZXJiZW50dWsgd2lkZS4gS2VkdWEgZnVuZ3NpIGluaSBiZXJhc2FsIGRhcmkgcGFja2FnZSBgdGlkeXJgLg0KDQohW10od2lkZUxvbmdkYXRhLnBuZykNCg0KYGBge3J9DQojIFdpZGUgdG8gbG9uZyAtIHBpdm90IGVjb25vbWljIGluZGljYXRvcnMgDQpjb3VudHJpZXNfbG9uZyA8LSBjb3VudHJpZXMgJT4lICAgDQogIHNlbGVjdChDb3VudHJ5LCBgR0RQICgkIHBlciBjYXBpdGEpYCwgYExpdGVyYWN5ICglKWAsIGBJbmZhbnQgbW9ydGFsaXR5IChwZXIgMTAwMCBiaXJ0aHMpYCkgJT4lICAgDQogIHBpdm90X2xvbmdlciggICAgIA0KICAgIGNvbHMgPSBjKGBHRFAgKCQgcGVyIGNhcGl0YSlgLCBgTGl0ZXJhY3kgKCUpYCwgYEluZmFudCBtb3J0YWxpdHkgKHBlciAxMDAwIGJpcnRocylgKSwgICAgIA0KICAgIG5hbWVzX3RvID0gImluZGljYXRvciIsICAgICANCiAgICB2YWx1ZXNfdG8gPSAidmFsdWUiICAgKSAgDQpjb3VudHJpZXNfbG9uZyANCg0KIyBMb25nIHRvIHdpZGUga2VtYmFsaSANCmNvdW50cmllc193aWRlIDwtIGNvdW50cmllc19sb25nICU+JSAgIA0KICBwaXZvdF93aWRlciggICAgIA0KICAgIG5hbWVzX2Zyb20gPSBpbmRpY2F0b3IsICAgICANCiAgICB2YWx1ZXNfZnJvbSA9IHZhbHVlICAgDQogICAgKSANCmNvdW50cmllc193aWRlDQpgYGANCg0KIyMjICoqMjAuIGNvYWxlc2NlKCkqKg0KDQoqKkZ1bmdzaSoqOiBNZW5nYW1iaWwgbmlsYWkgcGVydGFtYSB5YW5nIHRpZGFrLU5BIGRhcmkgc2VrdW1wdWxhbiB2ZWt0b3IuIFVzZWZ1bCB1bnR1ayBoYW5kbGluZyBtaXNzaW5nIHZhbHVlcy4NCg0KYGBge3J9DQojIENvbnRvaCBkZW5nYW4gZGF0YSB5YW5nIGRpbW9kaWZpa2FzaSANCmNvdW50cmllc193aXRoX25hIDwtIGNvdW50cmllcyAlPiUgICANCiAgbXV0YXRlKCAgICANCiAgICBHRFBfYWx0ZXJuYXRpdmUgPSBpZmVsc2UoQ291bnRyeSAlaW4lIGMoIkFmZ2hhbmlzdGFuIiwgIlNvbWFsaWEiKSwgTkEsIGBHRFAgKCQgcGVyIGNhcGl0YSlgKSAgIA0KICAgICkgDQpjb3VudHJpZXNfd2l0aF9uYSAgDQoNCiMgR3VuYWthbiBjb2FsZXNjZSB1bnR1ayBwcmlvcml0YXNrYW4gR0RQIGFzbGkgDQpjb3VudHJpZXNfZml4ZWQgPC0gY291bnRyaWVzX3dpdGhfbmEgJT4lICAgDQogIG11dGF0ZSggICAgIA0KICAgIEdEUF9maW5hbCA9IGNvYWxlc2NlKGBHRFAgKCQgcGVyIGNhcGl0YSlgLCBHRFBfYWx0ZXJuYXRpdmUsIDApICAgDQogICAgKQ0KY291bnRyaWVzX2ZpeGVkIA0KYGBgDQoNCiMjIExhdGloYW4gU29hbA0KDQoqKlNvYWwgMToqKiBCZXJzaWhrYW4gZGF0YXNldCBkZW5nYW4gbWVsYWt1a2FuIGJlYmVyYXBhIG9wZXJhc2kgc2VrYWxpZ3VzOiB1YmFoIGtvbWEgbWVuamFkaSB0aXRpayBwYWRhIGtvbG9tIG51bWVyaWMsIGhhcHVzIHNwYXNpIGJlcmxlYmloIHBhZGEga29sb20gdGVrcywgZGFuIGlzaSBtaXNzaW5nIHZhbHVlcyBkZW5nYW4gbWVkaWFuIHVudHVrIG51bWVyaWMgYXRhdSBtb2R1cyB1bnR1ayBrYXRlZ29yaWthbC4gVGFtcGlsa2FuIHN1bW1hcnkgc2ViZWx1bSBkYW4gc2V0ZWxhaCBjbGVhbmluZy4NCg0KKipTb2FsIDI6KiogVWJhaCBkYXRhc2V0IGRhcmkgd2lkZSBmb3JtYXQgbWVuamFkaSBsb25nIGZvcm1hdCBkaW1hbmEgc2VtdWEgaW5kaWthdG9yIGVrb25vbWkgKEdEUCwgTGl0ZXJhY3ksIEluZmFudCBNb3J0YWxpdHkpIG1lbmphZGkgc2F0dSBrb2xvbSAiSW5kaWNhdG9yIiBkYW4gbmlsYWlueWEgZGkga29sb20gIlZhbHVlIi4gS2VtdWRpYW4ga2VtYmFsaWthbiBrZSBmb3JtYXQgc2VtdWxhIHRhbnBhIGtlaGlsYW5nYW4gZGF0YS4NCg0KKipTb2FsIDM6KiogQmFuZGluZ2thbiBuZWdhcmEtbmVnYXJhIGRhbGFtIHJlZ2lvbiB5YW5nIHNhbWEgZGVuZ2FuIG1lbWJ1YXQga29sb20gYmFydSB5YW5nIG1lbnVuanVra2FuIHBlcmluZ2thdCBHRFAgcGVyIGthcGl0YSBkYWxhbSByZWdpb25ueWEsIHNlbGlzaWggR0RQIGRhcmkgcmF0YS1yYXRhIHJlZ2lvbiwgZGFuIHN0YXR1cyBhcGFrYWggR0RQIG5lZ2FyYSB0ZXJzZWJ1dCBkaSBhdGFzIGF0YXUgZGkgYmF3YWggbWVkaWFuIHJlZ2lvbi4NCg0KKipTb2FsIDQ6KiogUGlzYWhrYW4gcmVnaW9uIHV0YW1hIGRhbiBzdWItcmVnaW9uIChqaWthIGFkYSksIG5vcm1hbGlzYXNpIHBlbnVsaXNhbiAoa2FwaXRhbGlzYXNpIHlhbmcga29uc2lzdGVuKSwgZGFuIGhpdHVuZyBmcmVrdWVuc2kgc2V0aWFwIGtvbWJpbmFzaSByZWdpb24tc3VicmVnaW9uLg0KDQoqKlNvYWwgNToqKiBLZWxvbXBva2thbiBuZWdhcmEgYmVyZGFzYXJrYW4gbXVsdGlwbGUgY29uZGl0aW9uczogIkhpZ2ggSW5jb21lLUxvdyBQb3B1bGF0aW9uIiAoR0RQIFw+IFwkMTUsMDAwICYgUG9wdWxhdGlvbiBcPCAxMCBqdXRhKSwgIkxvdyBJbmNvbWUtSGlnaCBQb3B1bGF0aW9uIiAoR0RQIFw8IFwkNSwwMDAgJiBQb3B1bGF0aW9uIFw+IDUwIGp1dGEpLCBkYW4gIk1lZGl1bSBBbGwiLiBIaXR1bmcgc3RhdGlzdGlrIGRlc2tyaXB0aWYgdW50dWsgc2V0aWFwIGtlbG9tcG9rLg0KDQoqKlNvYWwgNjoqKklkZW50aWZpa2FzaSBkYW4gcGVyYmFpa2kgZGF0YSB5YW5nIHRpZGFrIGtvbnNpc3RlbjogbmlsYWkgR0RQIHlhbmcgdGlkYWsgbWFzdWsgYWthbCAobWlzYWw6IFwkMCBhdGF1IFw+IFwkMTAwLDAwMCksIHBlcnNlbnRhc2UgeWFuZyBtZWxlYmloaSAxMDAlLCBkYW4ga29tYmluYXNpIEFncmljdWx0dXJlK0luZHVzdHJ5K1NlcnZpY2UgeWFuZyB0aWRhayBzYW1hIGRlbmdhbiAxLg0KDQoqKlNvYWwgNzoqKiBHcm91cCBvbGVoIFJlZ2lvbiBkYW4gQ2xpbWF0ZSwga2VtdWRpYW4gaGl0dW5nOiByYXRhLXJhdGEgR0RQLCBqdW1sYWggbmVnYXJhLCBuZWdhcmEgZGVuZ2FuIEdEUCB0ZXJ0aW5nZ2kgJiB0ZXJlbmRhaCwgZGFuIHJhbmdlIEdEUCB1bnR1ayBzZXRpYXAga29tYmluYXNpIGdyb3VwLg0KDQoqKlNvYWwgODoqKiBDYXJpIG5lZ2FyYS1uZWdhcmEgeWFuZyBtZW1lbnVoaSBtaW5pbWFsIDMgZGFyaSA0IGtyaXRlcmlhOiBMaXRlcmFjeSBcPiA5MCUsIEluZmFudCBNb3J0YWxpdHkgXDwgMTAsIFBob25lcyBcPiA1MDAsIGRhbiBOZXQgTWlncmF0aW9uIHBvc2l0aWYuIFRhbXBpbGthbiBkYWxhbSBiZW50dWsgcmFua2VkIGxpc3QuDQoNCioqU29hbCA5OioqRGFsYW0gc2F0dSBwaXBlbGluZSBiZXJ1cnV0YW46IHNlbGVrc2kga29sb20sIGZpbHRlciBiYXJpcywgYnVhdCAzIGtvbG9tIGJhcnUgKGxvZyB0cmFuc2Zvcm1hdGlvbiB1bnR1ayBQb3B1bGF0aW9uLCBrYXRlZ29yaSB1bnR1ayBEZW5zaXR5LCBmbGFnIHVudHVrIENvYXN0YWwgY291bnRyaWVzKSwgZGFuIGdyb3VwIHN1bW1hcnkgc3RhdGlzdGljcy4NCg0KKipTb2FsIDEwOioqIEFzdW1zaWthbiBhZGEgZGF0YXNldCB0YW1iYWhhbiBiZXJpc2kgaWJ1a290YSBkYW4gYmFoYXNhIHJlc21pIHNldGlhcCBuZWdhcmEuIEdhYnVuZ2thbiBkZW5nYW4gZGF0YXNldCBleGlzdGluZywgaGFuZGxlIG1pc3NpbmcgbWF0Y2hlcywgZGFuIGJ1YXQgYW5hbGlzaXMgcGVyYmFuZGluZ2FuIGFudGFyYSBuZWdhcmEgZGVuZ2FuIGRhbiB0YW5wYSBkYXRhIGxlbmdrYXAuDQo=