MASALAH BISNIS

Tujuan dari masalah bisnis ini adalah untuk lebih memahami atribut (fitur) apa yang membuat klien kami meningglakan kartu kredit. Selain itu, dalam masalah bisnis kami memiliki tiga tugas utama yang akan kami lakukan untuk menghasilkan solusi dan kesimpulan potensial:

Pendahuluan

Banyak perusahaan BANK akhirnya akan menghadapi situasi di mana pelanggan memutuskan untuk meninggalkan kartu kredit. Namun demikian, pertayaan muncul terutama ketika datang ke alasan pelanggan memutuskan untuk meninggalkan perusahaan bank. pasti ada alasan yang tidak sesuai dengan pelanggan yang lain yang telah meninggalkan kartu kredit tetapi bagaimana jika ada pola alasan pelanggan memutuskan untuk meninggalkan kartu kredit? jika perusahaan dapat mendeteksi alasan utama mengapa pelanggan meninggalkan perusahan bank, perusahaan bank akan dapat bereaksi dan mencegah pelanggan pergi. Selanjutnya, jika perusahaan bank mampu memahami dari masa lalu, perusaahan bank akan mampu mencegah gesekan pelanggan lebih lanjut di masa depan.

Catatan: Sebelum melangkah lebih jauh, mohon buku catatan proyek tersebut jika dirasa bermanfaat bagi masyarakat dan tentunya jika menyukainya. silahkan berkomentar jika ada kritik yang membangun di kolom komentar.

Definisi Fitur:

Saya akan menjaga fitur definsi fitur menjadi yang paling penting, namun jika saya melihat kebutuhan untuk menganalisis lebih lanjut fitur lain, saya akan menambahkannya ke daftar.

Impor Perupustakaan

Berikut adalah perpustakaan utama dan bagaimana mereka akan membantu kami memecahkan masalah bisnis ini.

  • GGplot: Pustaka visualisasi yang membantu kami mengidentifikasi pola melalui Analysis data eksporasi.
  • LIME: Bantu kami memahami bagaimana model ML kami membuat keputusan dan juga memahami fitur apa yang memiliki dampak terbesar pada pengambilan keputusan model kami.
  • H2o: Pustaka AoutoML yang akan kami gunakan untuk memutuskan model mana yang akan berkinerja terbaik saat mengantisipasi pelanggan mana yang akan memutuskan untuk meninggalkan kartu kredit di perusahaan bank.
# Libarary yang digunakan ----


# Core
library(tidyverse)



# Summarisation
library(skimr)


# Feature importance
install.packages("vip")
install.packages("skimr")
library(vip)
library(lime)

# Visualization
install.packages("ggsci")
install.packages("ggpubr")
install.packages("gghalves")
install.packages("ggridges")
install.packages("correlationfunnel")
install.packages("ggalluvial")
install.packages("tidymodels")
install.packages("cowplot")
install.packages("fmsb")
library(ggsci)
library(ggthemes)
library(ggpubr)
library(gghalves)
library(ggridges)
library(correlationfunnel)
library(ggalluvial)
library(tidymodels)
library(cowplot)
library(fmsb)

# AutoML
install.packages("h2o", type="source", repos=(c("http://h2o-release.s3.amazonaws.com/h2o/latest_stable_R")))
library(h2o)

Import data

df <- read_csv("BankChurners.csv")
Rows: 10127 Columns: 23
-- Column specification -------------------------------------------------------------------------
Delimiter: ","
chr  (6): Attrition_Flag, Gender, Education_Level, Marital_Status, Income_Category, Card_Cate...
dbl (17): CLIENTNUM, Customer_Age, Dependent_count, Months_on_book, Total_Relationship_Count,...

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.

Explorasi Data Analysis (EDA)

Buat parameter tema

Peringkasan

Kami akan menggunakan paket skimr untuk mengumpulkan beberapa informasi singkat tentang dataset ini.

  • Tidak ada nilai yang hilang: Tidak ada nilai yang hilang dalam dataset ini kami (beruntung, karena tidak ada metode imputasi yang harus diterapkan), yang kami gunakan ketika memili banyak nilai yang hilang.
  • Batas Kredit rata-rata: Batas Kredit rata-rata adalah 8.631.95 USD, sedangkan median adalah 4.594 USD yang dapat menunjukkan bahwa ada beberapa outlier dalam kumpulan dataset ini karena perbedaan yang lebar antara mean dan median.
  • Total Saldo Bergulir : Saldo bergulir tidak memiliki distribusi khusus dan rata-rata saldo bergulier terletak pada 1.000 USD.

Catatan:
Ada fitur lain untuk dijelajahi saya tetap memasukkanya ke dalam tiga fitur ini karena kami kan mengnalisisnya lebih lanjut nanti dibagina ekspolarsi data.

skim(df)
-- Data Summary ------------------------
                           Values
Name                       df    
Number of rows             10127 
Number of columns          20    
_______________________          
Column type frequency:           
  character                6     
  numeric                  14    
________________________         
Group variables            None  

-- Variable type: character ---------------------------------------------------------------------
# A tibble: 6 x 8
  skim_variable   n_missing complete_rate   min   max empty n_unique whitespace
* <chr>               <int>         <dbl> <int> <int> <int>    <int>      <int>
1 attrition_flag          0             1    17    17     0        2          0
2 gender                  0             1     1     1     0        2          0
3 education_level         0             1     7    13     0        7          0
4 marital_status          0             1     6     8     0        4          0
5 income_category         0             1     7    14     0        6          0
6 card_category           0             1     4     8     0        4          0

-- Variable type: numeric -----------------------------------------------------------------------
# A tibble: 14 x 11
   skim_variable            n_missing complete_rate     mean       sd    p0      p25      p50
 * <chr>                        <int>         <dbl>    <dbl>    <dbl> <dbl>    <dbl>    <dbl>
 1 customer_age                     0             1   46.3      8.02    26    41       46    
 2 dependent_count                  0             1    2.35     1.30     0     1        2    
 3 months_on_book                   0             1   35.9      7.99    13    31       36    
 4 total_relationship_count         0             1    3.81     1.55     1     3        4    
 5 months_inactive_12_mon           0             1    2.34     1.01     0     2        2    
 6 contacts_count_12_mon            0             1    2.46     1.11     0     2        2    
 7 credit_limit                     0             1 8632.    9089.    1438. 2555     4549    
 8 total_revolving_bal              0             1 1163.     815.       0   359     1276    
 9 avg_open_to_buy                  0             1 7469.    9091.       3  1324.    3474    
10 total_amt_chng_q4_q1             0             1    0.760    0.219    0     0.631    0.736
11 total_trans_amt                  0             1 4404.    3397.     510  2156.    3899    
12 total_trans_ct                   0             1   64.9     23.5     10    45       67    
13 total_ct_chng_q4_q1              0             1    0.712    0.238    0     0.582    0.702
14 avg_utilization_ratio            0             1    0.275    0.276    0     0.023    0.176
         p75      p100 hist 
 *     <dbl>     <dbl> <chr>
 1    52        73     ▂▆▇▃▁
 2     3         5     ▇▇▇▅▁
 3    40        56     ▁▃▇▃▂
 4     5         6     ▇▇▆▆▆
 5     3         6     ▅▇▇▁▁
 6     3         6     ▅▇▇▃▁
 7 11068.    34516     ▇▂▁▁▁
 8  1784      2517     ▇▅▇▇▅
 9  9859     34516     ▇▂▁▁▁
10     0.859     3.40  ▅▇▁▁▁
11  4741     18484     ▇▅▁▁▁
12    81       139     ▂▅▇▂▁
13     0.818     3.71  ▇▆▁▁▁
14     0.503     0.999 ▇▂▂▂▁

Kategori Pendapatan

Membadingkan Tingkat Atrisi

Ringkasan:

  • Tingkat Atrisi Tinggi dengan Kategor Pendapatan Tinggi? Kami melihat bahwa kategor pendpatan tertinggi memiliki % tinggkat atrisi yang tinggi (walapun tidak banyak), dibandingkan dengan kategori pendapatan lainya. Diikuti oleh kategori pendapatan terendah.

Pengaruh Tingkat Pendidikan

Ringkasan:

  • Basis Pelanggan Tertinggi: Cukup menarik kita melihat bahwa basis pelanggan utama memilliki program pascasarjana. Mungkin berarti bahwa basis pelanggan utama kami adalah klien di usia yang lebih muda.
  • Tingkat Atrisi Teringgi: Kami melihat bahwa kelompok Segmen Graduate dan Highshool memiliki tingkat atrisi tertinggi.

Saldo Bergulir VS Batas Kredit

Mari kita konfirmasi bahwa kita melihat bahwa group yang memiliki bendera tingkat atrisi tertinggi “kedua” adalah group kategori pendapatan Kurang dari 40K. Dalam hal ini saya ingin menelusuri kategori pendapatan terendah untuk melihat beberapa tingkat revolving balance pada grup ini.

Ringkasan:

  • Tingkat batas kredit rendah: Batas Kredit untuk kelempok berpenghasilan rendah, rendah untuk pelanggan yang tertarik.
  • Saldo Berputar Tinggi: Grup ini memiliki saldo bergulir yang tinggi, yang dapat menjadi alasan mengapa batas kredit untuk mereka rendah.
  • Tidak cukup batas Kredit untuk kelempok tertentu? Kami melilhat bahwa ada individu yang tertarik yang tidak memiliki saldo bergulir tetapi memiliki batas kredit yang rendah. Mungkinkah ini penjelasan untuk gesekan?
df %>% 
  filter(attrition_flag == "Attrited Customer") %>% 
  ggplot(aes(x=credit_limit, y=total_revolving_bal, color=income_category)) + geom_point(alpha = 0.3) +
  facet_wrap(~ income_category, scales = "free_x") + geom_smooth(method = "lm", color="red") + 
  custom_theme + scale_colour_nejm() + 
  labs(
    title = "Korelasi Credit Limit dan Revolving Balance",
    caption = str_glue("Korelasi kategori Pendapatan terendah: {lowest_income_cat_tbl}"),
    x = "Batas Kredit",
    y = "Total Saldo Bergulir"
  )
`geom_smooth()` using formula 'y ~ x'

Metrix Tingkat Aktivitas

Kategori Pendapatan yang lebih rendah memiliki rasio pemamfaatan yang sedikit lebih besar dibandingkan dengan kategori pendapatan lainya. Meskipun demikian, ini bukan jumlah yang signifikan tetapi dapat menunjukkan bahwa kategori berpenghasilan rendah memiliki tingkat aktivitas yang sedikit. Ini akan baik untuk dipahami terutama ketika kita masuk ke fase pentingya fitur untuk model kita. Rasio pemanfaatan juga memberi tahu kita tingkat aktivitas menerut kategori pendapatan, tetapi sekali lagi kita harus beralih ke fase kepentingan fitur untuk melihat apakah tingkat aktivitas merupakan indikator apakah pelaggan akan meninggalkan kartu kredit di Perusahaan bank.

Kategori Kartu

Tujuan menjelajahi kategori kartu adalah untuk melihat apakah klien kami puas dengan penawaran produk yang ditawarkan institusi. Apa saja jenis kartu kredit yang ditawarkan oleh lembaga kartu kredit?

  • Kartu Biru
  • Kartu Emas
  • Kartu Silver
  • Kartu Platinum

Tingkat Atrisi

  • Tingkat Atrisi: Tingkat persentasi atrisi tertinggi berasal darai pengguna kartu platinum dan emas.
  • Tingkat gesekan terendah: Tingkat gesekan terendah berasal dari kartu perak dan biru.

Total Transaksi

  • Total transkasi yang jauh lebih rendah untuk platinum: Ini dapat menunjukkan dua hal dari pelanggan yang keluar dari group ini, apakah mereka tidak memiliki batas kredit yag cukup atau mereka termasuk dalam kateogri berpenghasilan rendah. Anda dapat memeriksa bahwa median distribusi untuk Kategori Platinum untuk total transaksi jauh lebih rendah dari pada pelanggan yang menginap.
  • Grup kartu emas: Untuk grup kartu emas, kami tidak melihat perbedaan besar.
  • Kluster yang berbeda dalam distribusi kami: Perhatikan bahwa kami melihat cluster yang berbeda di beberapa distribusi grup kartu kami, ini dapat berarti bahwa ini adalah cluster tingkat pendapatan yang dapat dikorelasi dengan tingkat transaksi.
card_utilization_tbl %>% 
  ggplot(aes(x=card_category, y=total_trans_amt,fill=card_category)) + 
  geom_jitter(aes(color=card_category),
              alpha = 0.5,
              size=0.5,
              show.legend = FALSE) + 
  geom_half_violin(aes(fill=card_category),
                   side = "l",
                   alpha = 0.45,
                   show.legend = FALSE,
                   trim = FALSE) +
  geom_half_boxplot(aes(fill = card_category),
                    side = "r",
                    outlier.size = 1,
                    outlier.color = "red",
                    width = 0.4, 
                    alpha = 0.2,
                    show.legend = FALSE) + 
  stat_summary(fun = median, geom="line") + 
  facet_wrap(~ attrition_flag) + custom_theme + 
  scale_fill_manual(values = c("#1C366B", "#FCD16B", "#C7CEF6", "#D3DDDC")) + 
  scale_color_manual(values = c("#1C366B", "#FCD16B", "#C7CEF6", "#D3DDDC")) + 
  scale_y_continuous(labels = scales::dollar) +
  labs(
    title = "Distribusi Transaksi Berdasarkan Jenis Kartu",
    x = "Kategori Kartu",
    y = "Total Transaksi"
  )
geom_path: Each group consists of only one observation. Do you need to adjust the group
aesthetic?
geom_path: Each group consists of only one observation. Do you need to adjust the group
aesthetic?

Bendera Atrisi

Tingkat Aktivitas

Mari kita mengganalisis tingkat ketidakaktifan bagi pelanggan uang memutuskan atau yang akan meninggalkan Kartu Kredit di perusahaan bank dan pelanggan.

  • Pelanggan Yang Tertarik: Kami melihat bahwa tingkat iinteraktivitas memiliki median tiga bulan, 1 bulan lebih tinggi dari pada mereka yang masih bertahan di Kartu Kredit Perusahaan bank tersebit .
  • Memahimi distribusi ini : Ini dapat memberi kita indekasi bahwa ketika tingkat ketidakaktifan mulai “melampaui” ambang batas 2 bulan, maka ada kemungkinan lebih tinggi bahwa orang tersebut memutuskan untuk menginggalkan Kartu kredit di persuhaan tersebut .
  • Alternatif yang mungkin: Hubungi klien untuk melihat apakah mereka puas dengan layanan dan apa yang dapat dilakukan Kartu kredit di perusahaan bank untuk meningkatkan secara keseluruhan?
p1
Picking joint bandwidth of 0.151

Tingkat Saldo Bergulir

Kita dapat dengan jenis melihat bahwa pelanggan yang memiliki sado bergulir yang rendah adalah yang paling mungkin untuk pergi. Ini bisa menunjukkan bahwa pelanggan tersebut bisa saja pergi karena mereka menemukan suku bunga lain yang lebih rendah ke perusahaan lain yang menawarkan produk yang lebih baik dengan harga yang lebih rendah. Dalam kasus pelanggan yang sudah ada rata-rata mereka memilki saldo bergulir jauh lebih tinggi tetapi pelanggan dengan saldo bergulir yang lebih tinggi memiliki waktu yang jauh leibh sulit untuk mencari lembaga keuangan lain untuk menawarkan tarif yang lebih rendah karena resiko bahwa pelanggan tidak akan membayar sama sekali. Kiri dari sisa saldo. (Resiko Tinggi, tarif lebih tinggi)

Group Atrisi Pelangagan

Di bagian ini kita akan mengeksplorasi kemungkinan kombinasi kelempok orang yang meninggalkan Kartu kredit di perusahaan bank, kami dapat dengan cepat memvisualisasikan klater yang kemungkinan besar akan meninggalkan Kartu kredit di persuahaan bank.

  • Penjelasan Bagian: Bagian ini disebut diagram sanky, dan yang pada dasarnya memberitahu Anda adalah jumlah orang yang dialokasikan untuk setiap variabel kategori pelanggan yang tertarik.
  • Lulusan Wanita Berpenghasilan Rendah: Kelempok klaster ini terderi dari jumlah tertinggi orang yang tertarik pada pelanggan..

Analysis Korelasi

Sebelum masuk ke Auto ML, akan menarik untuk mengeksplorasi fitur man ayang berkorelasi dengan apakah pelanggan akan meninggalkan Kartu kredit di perusahaan bank. Untuk ini kami akan menggunakan apa yang di sebut funner “Korelasi” yang memungikinkan kami memahami fitur mana yang berkolerasi dnegna apakah seseorang akan meninggalkan kartu kredit di perusahaan bank. Catatan: Untuk variabel numerik, kami telah memutuskan mengabungkannya kedalam 4 kategori dan kemudian membuat variabel dummy berdasarkan fitur ini melalui satu pengokedan panas.

  • Saldo Bergulir Rendah: Orang biasanya membayar kartu kredit mereka tepat waktu lebih mungkin untuk meninggalkan Kartu kredit di perusahaan bank.
  • Tingkat Ketidakaktifan rendah: Jika jumlah transaksi kurang dari 0.582, kemungkinan besar pelanggan akan pergi. Sama untuk Jumlah total transaksi jika kurang dari 45 untuk klien tertentu maka klien lebih mungkin untuk meninggalkan kartu kredit di perusahaan bank
  • Jumlah transaksi rendah: Semakin rendah jumlah transaksi, semakin tinggi korealasinya dengan gesekan.

MOHON MAAFF DI SINI LAPTOP SAYA TIDAK BISA MENAMPILKAN PLOT NYA DI KARENAKAN ERROR

AutoML dengan H20

Pada bagian ini kita akan mulai mengimplementasikan H20, H20 adalah perpustakaan automi yang menyerderhanakan proses pemilihan model. Tidak hanya itu, tetapi juga mengurangi waktu yang kita habiskan untuk melakukan proses GridSearch (Penyetelan Hyperparameter.)

Berikut langkah-langkah untuk mengimplementasikan H2o:
  • Mengimpor H2o
  • Pisahkan dataframe
  • Pilih modelnya
  • Evaluasi metrik kinerja:

Mengimpor H2o

# Call H2o
h2o.init()

H2O is not running yet, starting it now...

Note:  In case of errors look at the following log files:
    C:\Users\Acer\AppData\Local\Temp\Rtmpesh0QO\file233c28001d6c/h2o_Acer_started_from_r.out
    C:\Users\Acer\AppData\Local\Temp\Rtmpesh0QO\file233c29b96f5b/h2o_Acer_started_from_r.err

java version "1.8.0_301"
Java(TM) SE Runtime Environment (build 1.8.0_301-b09)
Java HotSpot(TM) Client VM (build 25.301-b09, mixed mode)

Starting H2O JVM and connecting: .. Connection successful!

R is connected to the H2O cluster: 
    H2O cluster uptime:         19 seconds 273 milliseconds 
    H2O cluster timezone:       Asia/Bangkok 
    H2O data parsing timezone:  UTC 
    H2O cluster version:        3.34.0.7 
    H2O cluster version age:    7 days, 6 hours and 24 minutes  
    H2O cluster name:           H2O_started_from_R_Acer_act788 
    H2O cluster total nodes:    1 
    H2O cluster total memory:   0.97 GB 
    H2O cluster total cores:    2 
    H2O cluster allowed cores:  2 
    H2O cluster healthy:        TRUE 
    H2O Connection ip:          localhost 
    H2O Connection port:        54321 
    H2O Connection proxy:       NA 
    H2O Internal Security:      FALSE 
    H2O API Extensions:         Amazon S3, Algos, AutoML, Core V3, TargetEncoder, Core V4 
    R Version:                  R version 4.1.2 (2021-11-01) 

Pemisihaan H2o Dataframe

AutoML

Dibagian ini kita akan mengimplementasikan AutoML dari serangkaian model. AutoML adalah kerangka kerja yang membantukami menyerderhanakan penerapan model pembelajaran Mesin. langkah - langkah pemoresesan, penyetelan hyperparameter di antara aspek - aspek lain dari alur pembelajaran mesin. kami akan menerapakan langkah - langkah berikut

  • Menerapkan serangkaian model dan menentukan model mana yang terbaik untuk digunakan.
  • Evaluasi model dengan plot penarikan vs presisi dan plot ROC


Model teratas yang kami dapatkan semuanya adlaah model Gradient Boosting dengan parameter berbeda.

Metrik Kinerja

Precesion dan recail adalah metrix yang umum digunakan untuk masalah klafikasi. ini akan memungkinkan kami untuk mengevalusai kinerja model kami dengan lebih baik. Selajutnya dalam hal ini akan diguanakan model performasinya paling baik yaitu model GBM_3_AUTOML Namun di mungkinkan untuk mengevaluasi lebih dari satu model pada saat yang sama tetapi untuk menjaga semuanya tetap sederhana dalam proyek in i saya hanya menggunakan satu model.

  • Presisi: Ini adalah rasio positif sejati terhadap semua positif. Dalam hal ini, positif akan menjadi pelangan meninggalkan Kartu kredit di perusahaan. Benar positif akan menjadi prediksi yang benar oleh model kami bahwa pelanggan meninggalkan kartu kredit di perusahaan bank dan positif palsu akan model kami salah bahwa pelanggan akan pergi.
  • Penarikan Kembali: Adalah Metrix model kami yang mengidentifikasi dengan benar positif sejati (dengan kata lain pelanggan meningglakan kartu kredit di perusahaan bank.) Penarikan pada dasarnya adalah rasio berapa banyak pelanggan yang diprediksi model kami dengan benar dari total pelanggan di dalam perusahaan bank tersebut.
  • Reciver Operating Characteristic (ROC) dan Area Under Cover: ROC adalah kurva probalitas yang mengukur seberapa benar model ini dapat memprediksi hasil yang benar sementara AUC (Mendakati 1) semakin baik model.

Memahami Pentingnya FItur

Sekarang saatnya untuk lebih memahami model kita, Kami ingin memahami faktor apa yang mendorong model kami untuk membuat prediksi tertentu. Dalam hal ini faktor-faktor apa yang membuat model kita menentukan apakah seseorang pelanggan akan meninggalkan kartu kredit di perusahaan bank? Untuk itu , kita perlu memahami fitur mana yang penting untuk model kita.



  • Fitur Penting: Fitur ini model kami akan meninggalkan kartu kredit di perusahaan tertentu: Jumlah Total Transaksi Jumlah total transaksi dan total saldo bergulir.
  • Jumlah total transaksi: Ketika jumlah total transaksi lebih rendah dari 45 transaksi, kemungkinan besar pelanggan akan meninggalkan kartu kredit di perusahaan bank.





fi_plot <- vip(leader_model) + 
  custom_theme + geom_col(fill="#F24D29", color="black") + 
  labs(
    title = "Feature Imprtance",
    caption = "Which feature our model considers important"
  ) 




fi_plot

Fitur Apa yang paling Mempengaruhi Atrisi?

Dalam hal ini kami akan menggunakan paket Lime Yang membantu kami memahami fitur-fitur yang diangap penting oleh model kami. Namun kami akan mengeksplorasi pengamatan tunggal dimana pelanggan memutuskan untuk meninggalkan kartu kredit perusahaan di bank.

  • Jumlah Total Transaksi: Ketika jumlah total transaksi dari 45 kita melihat bahwa ada kemungkinan lebih besar bahwa individu akan meninggalkan kartu kredit di perusahaan bank.
  • Pelanggan yang berutang lebih sedikit kepada institusi: Pelanggan yang memiliki saldo bergulir leibh rendah memiliki peluang lebih besar untuk meninggalkan kartu kredit di perusahaan di bank. ini adalah sesuatu yang menarik karena yang ingin kita miliki adalah pelanggan yang berutan lebih dari sedikit kepada institusi.



Catatan Pengamatan ke -4 adalah prediksi yang salah disisi model kami. Sepertinya ini adalah pengeculian meskipun memiliki semua karekteristik yang menerut model kami penting untuk mempertimbangkan bahwa pelanggan akan meninggalkan kartu kredit di perusahaan bank.

Dalam plot ini kita dapat melihat bahwa tren berlanjut dengan empat pengamatan, jadi kita melihat bahwa untuk tiga tren pertama kita melihat ada konsistensi dan pola. kami juga dapat mencoba mengeksplorasi pengamatan yang berbeda dari pelanggan yang tertarik untuk melihat apakah pola ini berlanjut dengan ini anda menyimpulkan bahwa ini adalah fitur yang dipahami model kami yang penting dalam menentukan apakah pelanggan akan meninggalkan kartu kredit di perusahaan bank.

Menafsirkan Confusion Matrix

Pada bagian ini kami akan menjelaskan konsep yang diperlukan untuk mengintertasikan matrik dari masalah klasfikasi. Tujuanya adalah untuk memahami apakah model kita bisa mendapatkan
  • Negatif True: Ini bearti model kami memprediksi pelanggan kami akan tinggal dan tidak akan meninggalkan kartu kredit di perusahaan bank yang berarti ini adalah jumlah prediksi yang benar dari model kami.
  • Positif False: Model kami memprediksi bahwa pelanggan akan meninggalkan kartu kredit di perusahaan bank, namun pelanggan tetap tinggal.
  • Negatif False: Model kami memprediksi bahwa pelanggan akan tetap beraada di kartu kredit perusahaan bank, namun pelanggan meninggalkan kartu kredit di perusahaan bank. ini memiliki dampak negatif besar untuk kasus ini.
True Positif: Model kami memprediksi pelanggan akan meningglakan kartu kredit di perusahaan bank. Artinya model kami dapat dapat memprediksi dengan benar kapan model meninggalkan kartu kredit di perushaan bank.


Catatan: Anda juga harus melihat implikasi bisnis Positif False meiliki dampak yang rendah terhadap kartu kredit di perusahaan bank dibandingkan dnegna Negatif False

Ambang Batas

Konsep ambang batas penting ketika kita sampai pada masalah klafikasi. dalam hal ini kami menunjukkan kinerja ambang batas yang berada di berbagai tingaktan. Tarif Negatif Benar dan Tarif Positif False Serta tarif negatif False dan Tarif Positif True akan selalu bertambah menjadi 1. Saat ambang batas meningkat, semakin presisi model kami saat menentukan apakah pelanggan akan meninggalkan Kartu Kredit di perusahaan bank.

rates_by_threshold %>% 
  select(threshold, f1, tnr:tpr) %>% 
  gather(key = "key", value = "value", tnr:tpr, factor_key = TRUE) %>% 
  mutate(
    key = fct_reorder2(key, threshold, value)
  ) %>% 
  ggplot(aes(x=threshold, value, color=key)) + 
  geom_point() + 
  geom_smooth() + 
  custom_theme + 
  theme(legend.position = "right") + 
  labs(
    title = "Rates",
    y = "Value", 
    x = "Threshold"
  )
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

Startegi untuk Mengurangi Atrisi Pelanggan

  • Fokus pada kelompok berpenghasilan rendah: Meskipun daya beli tidak terlalu signifikan, sebagian besar pelanggan kami berasal dari kelompok rendah. Menerapkan Promosi untuk menguntungkan kelempok berpenghasilan rendah dapat menjadi alternatif yang baik untuk mengurangi churn pelanggan di antara kelompok klaster tersebut.
  • Bertindak saat tingkat aktivitas rendah: Kami melihat bahwa pelanggan yang memiliki tingat aktivitas lebih rendah (transaksi lebih rendah dari 45), Memiliki kemungkinan lebih tinggi untuk meninggalkan kartu kredit, Jika karyawan bank memanggil pelanggan dengan tingakt aktivitas yang lebih rendah untuk menawarkan produk baru untuk kebutuhan mereka atau untuk menayakan apakah pelanggan senang dengan layanan yang kami berikan dan jika ada sesuatu yang dapat kami lakukan untuk meningkatkan, kami mungkin unutk meningkatkan, kami mungkin akan mendapatkan wawasan yang lebih baik tentang apa dapat kita lakukan untuk meningkatkan tingkat aktivitas.
  • Tingkat batas kredit untuk mereka yang memiliki saldo bergulir lebih rendah? Menurut model kami, pelanggan dengan saldo bergulir yang lebih rendah leibh cenderung meinggalkan kartu kredit di perusahaan bank. Mungkin dengan menerapkan saldo kredit yang lebih tinggi kepada pelanggan tersebut., kemungkinan kelempok segmen tersebut untuk meninggalkan kartu kredit di perusahaan dapat di turunkan.

Dan hanya itu, saya harap anda menyukai proyek ini dan masih proses belajar.

LS0tDQp0aXRsZTogTUVOR0FOVElTSVBBU0kgUEVOR1VSQU5HQU4gUEVMQU5HR0FOIHx8IEFVVE9NTCBVTlRVSyBNRU5ZRUxBTUFUS0FOIEtBUlRVDQogIEtSRURJVCENCmF1dGhvcjogIkpBTUFMTFVESU4iDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB5ZXMNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIGZpZ193aWR0aDogNw0KICAgIGZpZ19oZWlnaHQ6IDUNCiAgICB0aGVtZTogY29zbW8NCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgICBlY2hvID0gVFJVRSwNCiAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgd2FybmluZyA9IEZBTFNFLA0KICAgIGVycm9yID0gRkFMU0UNCikNCg0KYGBgDQoNCg0KPGNlbnRlcj4NCg0KPGltZyBoZWlnaHQ9IDQwMCBzcmM9Imh0dHBzOi8vZG9jcy5oMm8uYWkvaDJvL2xhdGVzdC1zdGFibGUvaDJvLWRvY3MvX2ltYWdlcy9oMm8tYXV0b21sLWxvZ28uanBnIj4NCg0KDQo8L2NlbnRlcj4NCg0KIyBNQVNBTEFIIEJJU05JUyANCg0KVHVqdWFuIGRhcmkgbWFzYWxhaCBiaXNuaXMgaW5pIGFkYWxhaCB1bnR1ayBsZWJpaCBtZW1haGFtaSBhdHJpYnV0IChmaXR1cikgYXBhIHlhbmcgbWVtYnVhdCBrbGllbiBrYW1pIG1lbmluZ2dsYWthbiBrYXJ0dSBrcmVkaXQuIFNlbGFpbiBpdHUsIGRhbGFtIG1hc2FsYWggYmlzbmlzIGthbWkgbWVtaWxpa2kgdGlnYSB0dWdhcyB1dGFtYSB5YW5nIGFrYW4ga2FtaSBsYWt1a2FuIHVudHVrIG1lbmdoYXNpbGthbiBzb2x1c2kgZGFuIGtlc2ltcHVsYW4gcG90ZW5zaWFsOiA8YnI+DQoNCjx1bD4NCjxsaT4qKkplbGFqYWhpIGRhdGEga2FtaToqKiBJbmkgYWthbiBtZW1iYW50dSBrYW1pIG1lbmFyaWsgYmViZXJhcGEgd2F3YXNhbiB1bnR1ayBtZW1pbGlraSBnYW1iYXJhbiB1bXVtIGFwYSB5YW5nIGJpc2EgbWVuamFkaSBmaXR1ciBwb3RlbnNpYWwgeWFuZyBtZW55ZWJhYmthbiBrbGllbiBtZW5pbmdnYWxrYW4ga2FydHUga3JlZGl0LiA8L2xpPg0KPGxpPioqUGVudGluZ255YSBGaXR1cjoqKiBGSXR1ciBhcGEgeWFuZyBtZW1pbGlraSBkYW1wYWsgdGVydGluZ2dpIGJhZ2kgcGVsYW5nZ2FuIGthbWkgdW50dWsgbWVuaW5nZ2Fsa2FuIGthcnR1IGNyZWRpdD8gPC9saT4NCjxsaT4qKkltcGxlbWVudGF0aW9uIG9mIEF1dG9NTDogKiogSW5pIGFrYW4gbWVtYmFudHUga2FtaSBtZW1pbGloIG1vZGVsIG1hbmEgeWFuZyB0ZXJiYWlrIHVudHVrIG1lbmFnYW5pIG1hc2FsYWgga2xhc2lmaWthc2kgdGlkYWsgc2VpbWJhbmcgaW5pLiA8L2xpPg0KDQo8L3VsPg0KDQoNCg0KDQojIFBlbmRhaHVsdWFuDQoNCg0KQmFueWFrIHBlcnVzYWhhYW4gQkFOSyBha2hpcm55YSBha2FuIG1lbmdoYWRhcGkgc2l0dWFzaSBkaSBtYW5hIHBlbGFuZ2dhbiBtZW11dHVza2FuIHVudHVrIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQuIE5hbXVuIGRlbWlraWFuLCBwZXJ0YXlhYW4gbXVuY3VsIHRlcnV0YW1hIGtldGlrYSBkYXRhbmcga2UgYWxhc2FuIHBlbGFuZ2dhbiBtZW11dHVza2FuIHVudHVrIG1lbmluZ2dhbGthbiBwZXJ1c2FoYWFuIGJhbmsuIHBhc3RpIGFkYSBhbGFzYW4geWFuZyB0aWRhayBzZXN1YWkgZGVuZ2FuIHBlbGFuZ2dhbiB5YW5nIGxhaW4geWFuZyB0ZWxhaCBtZW5pbmdnYWxrYW4ga2FydHUga3JlZGl0IHRldGFwaSBiYWdhaW1hbmEgamlrYSBhZGEgcG9sYSBhbGFzYW4gcGVsYW5nZ2FuIG1lbXV0dXNrYW4gdW50dWsgbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdD8gamlrYSBwZXJ1c2FoYWFuIGRhcGF0IG1lbmRldGVrc2kgYWxhc2FuIHV0YW1hIG1lbmdhcGEgcGVsYW5nZ2FuIG1lbmluZ2dhbGthbiBwZXJ1c2FoYW4gYmFuaywgcGVydXNhaGFhbiBiYW5rIGFrYW4gZGFwYXQgYmVyZWFrc2kgZGFuIG1lbmNlZ2FoIHBlbGFuZ2dhbiBwZXJnaS4gU2VsYW5qdXRueWEsIGppa2EgcGVydXNhaGFhbiBiYW5rIG1hbXB1IG1lbWFoYW1pIGRhcmkgbWFzYSBsYWx1LCBwZXJ1c2FhaGFuIGJhbmsgYWthbiBtYW1wdSBtZW5jZWdhaCBnZXNla2FuIHBlbGFuZ2dhbiBsZWJpaCBsYW5qdXQgZGkgbWFzYSBkZXBhbi4NCg0KDQo8c3BhbiBzdHlsZT0iYmFja2dyb3VuZDojZmVkNTZmOyBmb250LXdlaWdodDpib2xkOyBjb2xvcjpibGFjayI+IENhdGF0YW46IDwvc3Bhbj4gIFNlYmVsdW0gbWVsYW5na2FoIGxlYmloIGphdWgsIG1vaG9uIGJ1a3UgY2F0YXRhbiBwcm95ZWsgdGVyc2VidXQgamlrYSBkaXJhc2EgYmVybWFuZmFhdCBiYWdpIG1hc3lhcmFrYXQgZGFuIHRlbnR1bnlhIGppa2EgbWVueXVrYWlueWEuIHNpbGFoa2FuIGJlcmtvbWVudGFyIGppa2EgYWRhIGtyaXRpayB5YW5nIG1lbWJhbmd1biBkaSBrb2xvbSBrb21lbnRhci4gDQoNCg0KPGg0PjxzcGFuIHN0eWxlPSJiYWNrZ3JvdW5kOiNDN0NFRjY7IGZvbnQtd2VpZ2h0OmJvbGQ7IGNvbG9yOmJsYWNrIj4gRGVmaW5pc2kgRml0dXI6IDwvc3Bhbj48L2g0Pg0KDQpTYXlhIGFrYW4gbWVuamFnYSBmaXR1ciBkZWZpbnNpIGZpdHVyIG1lbmphZGkgeWFuZyBwYWxpbmcgcGVudGluZywgbmFtdW4gamlrYSBzYXlhIG1lbGloYXQga2VidXR1aGFuIHVudHVrIG1lbmdhbmFsaXNpcyBsZWJpaCBsYW5qdXQgZml0dXIgbGFpbiwgc2F5YSBha2FuIG1lbmFtYmFoa2FubnlhIGtlIGRhZnRhci4NCg0KPHVsPg0KPGxpPioqQXR0cml0aW9uIEZsYWc6KiogSW5pIGFkYWxhaCB2YXJpYWJlbCB0YXJnZXQga2FtaSwgYmVhcnRpIGFwYWthaCBwZWxhbmdnYW4ga2FtaSBtZW11dHVza2FuIHVudHVrIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rIGF0YXUgYWRhIGtlbXVuZ2tpbmFuIGJlc2FyIHBlbGFuZ2dhbiBha2FuIHBlcmdpIGtlIHBlcnVzYWhhYW4gYmFuayB5YW5nIGxhaW4geWFuZyBzYW1hIGRlbmdhbiBrYXJ0dSBrcmVkaXQuIDwvbGk+DQo8bGk+KipHZW5kZXI6ICoqIFByaWEgYXRhdSBXYW5pdGEgPC9saT4NCjxsaT4qKkN1c3RvbWVyIGFnZToqKiBVc2lhIFBlbGFuZ2dhbjwvbGk+DQo8bGk+KipJbmNvbWUgY2F0ZWdvcnk6ICoqIEtlIGRhbGFtIGthdGVnb3JpIG1hbmEgcGVsYW5nZ2FuIHRlcm1hc3VrLiAgPC9saT4NCjxsaT4qKkNhcmQgY2F0ZWdvcnk6KiogS2FydHUgYXBhIHlhbmcgZGltaWxpa2kgcGVsYW5nZ2FuPyA8L2xpPg0KPGxpPioqTW9udGhzIEluYWN0aXZlOioqIEp1bWxhaCB5YW5nIHRpZGFrIGFrdGlmIHNhYXQgbWVuZ2d1bmFrYW4ga2FydHUga3JlZGl0LiA8L2xpPg0KPGxpPioqQ3JlZGl0IExpbWl0OioqIEtyZWRpdCB5YW5nIGRpbWlsaWtpIHBlbGFuZ2dhbiBzYWF0IGluaS4gPC9saT4NCjxsaT4qKlRvdGFsIFJldm9sdmluZyBCYWxhbmNlOioqIEJhZ2lhbiB5YW5nIGJlbHVtIGRpYmF5YXIgeWFuZyBkaWJhd2Ega2UgYnVsYW4gYmVyaWt1dG55YSBrZXRpa2EgcGVsYW5nZ2FuIHRpZGFrIG1lbWJheWFyLiA8L2xpPg0KPGxpPioqQXZlcmFnZSBVdGlsaXphdGlvbiBSYXRpbzoqKiBNZW5ndWt1ciBiZXJhcGEgYmFueWFrIGtyZWRpdCB5YW5nIHBlbGFuZ2dhbiBndW5ha2FuIGRpYmFuZGluZ2thbiBkZW5nYW4gYmVyYXBhIGJhbnlhayB5YW5nIHBlbGFuZ2dhbiBtaWxpa2kuIDwvbGk+DQo8bGk+KipPcGVuIHRvIGJ1eToqKiBKdW1sYWgga3JlZGl0IHlhbmcgYmVyc2lkaWEgcGFkYSB3YWt0dSB0ZXJ0ZW50dSBkaSBha3VuIHBlbWVnYW5nIGthcnR1IGtyZWRpdC4gamFkaSwgcmF0YS1yYXRhIHRlcmJ1a2EgdW50dWsgbWVtYmVsaSBhZGFsYWgga3JlZGl0IHJhdGEtcmF0YSB5YW5nIHRlcnNlZGlhIHlhbmcgZGlhbG9rYXNpa2FuIHVudHVrIHBlbGFuZ2dhbiB0ZXJ0ZW50dS4gPC9saT4NCg0KDQo8L3VsPg0KDQojIyBJbXBvciBQZXJ1cHVzdGFrYWFuDQoNCkJlcmlrdXQgYWRhbGFoIHBlcnB1c3Rha2FhbiB1dGFtYSBkYW4gYmFnYWltYW5hIG1lcmVrYSBha2FuIG1lbWJhbnR1IGthbWkgbWVtZWNhaGthbiBtYXNhbGFoIGJpc25pcyBpbmkuDQoNCjx1bD4NCjxsaT4qKkdHcGxvdDoqKiBQdXN0YWthIHZpc3VhbGlzYXNpIHlhbmcgbWVtYmFudHUga2FtaSBtZW5naWRlbnRpZmlrYXNpIHBvbGEgbWVsYWx1aSBBbmFseXNpcyBkYXRhIGVrc3BvcmFzaS4gPC9saT4NCjxsaT4qKkxJTUU6ICoqIEJhbnR1IGthbWkgbWVtYWhhbWkgYmFnYWltYW5hIG1vZGVsIE1MIGthbWkgbWVtYnVhdCBrZXB1dHVzYW4gZGFuIGp1Z2EgbWVtYWhhbWkgZml0dXIgYXBhIHlhbmcgbWVtaWxpa2kgZGFtcGFrIHRlcmJlc2FyIHBhZGEgcGVuZ2FtYmlsYW4ga2VwdXR1c2FuIG1vZGVsIGthbWkuIDwvbGk+DQo8bGk+KipIMm86KiogUHVzdGFrYSBBb3V0b01MIHlhbmcgYWthbiBrYW1pIGd1bmFrYW4gdW50dWsgbWVtdXR1c2thbiBtb2RlbCBtYW5hIHlhbmcgYWthbiBiZXJraW5lcmphIHRlcmJhaWsgc2FhdCBtZW5nYW50aXNpcGFzaSBwZWxhbmdnYW4gbWFuYSB5YW5nIGFrYW4gbWVtdXR1c2thbiB1bnR1ayBtZW5pbmdnYWxrYW4ga2FydHUga3JlZGl0IGRpIHBlcnVzYWhhYW4gYmFuay4gPC9saT4NCg0KPC91bD4NCg0KYGBge3IgbGlicmFyaWVzfQ0KIyBMaWJhcmFyeSB5YW5nIGRpZ3VuYWthbiAtLS0tDQoNCg0KIyBDb3JlDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KDQoNCiMgU3VtbWFyaXNhdGlvbg0KbGlicmFyeShza2ltcikNCg0KDQojIEZlYXR1cmUgaW1wb3J0YW5jZQ0KaW5zdGFsbC5wYWNrYWdlcygidmlwIikNCmluc3RhbGwucGFja2FnZXMoInNraW1yIikNCmxpYnJhcnkodmlwKQ0KbGlicmFyeShsaW1lKQ0KDQojIFZpc3VhbGl6YXRpb24NCmluc3RhbGwucGFja2FnZXMoImdnc2NpIikNCmluc3RhbGwucGFja2FnZXMoImdncHViciIpDQppbnN0YWxsLnBhY2thZ2VzKCJnZ2hhbHZlcyIpDQppbnN0YWxsLnBhY2thZ2VzKCJnZ3JpZGdlcyIpDQppbnN0YWxsLnBhY2thZ2VzKCJjb3JyZWxhdGlvbmZ1bm5lbCIpDQppbnN0YWxsLnBhY2thZ2VzKCJnZ2FsbHV2aWFsIikNCmluc3RhbGwucGFja2FnZXMoInRpZHltb2RlbHMiKQ0KaW5zdGFsbC5wYWNrYWdlcygiY293cGxvdCIpDQppbnN0YWxsLnBhY2thZ2VzKCJmbXNiIikNCmxpYnJhcnkoZ2dzY2kpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KGdnaGFsdmVzKQ0KbGlicmFyeShnZ3JpZGdlcykNCmxpYnJhcnkoY29ycmVsYXRpb25mdW5uZWwpDQpsaWJyYXJ5KGdnYWxsdXZpYWwpDQpsaWJyYXJ5KHRpZHltb2RlbHMpDQpsaWJyYXJ5KGNvd3Bsb3QpDQpsaWJyYXJ5KGZtc2IpDQoNCiMgQXV0b01MDQppbnN0YWxsLnBhY2thZ2VzKCJoMm8iLCB0eXBlPSJzb3VyY2UiLCByZXBvcz0oYygiaHR0cDovL2gyby1yZWxlYXNlLnMzLmFtYXpvbmF3cy5jb20vaDJvL2xhdGVzdF9zdGFibGVfUiIpKSkNCmxpYnJhcnkoaDJvKQ0KDQoNCmBgYA0KDQoNCg0KIyMgSW1wb3J0IGRhdGENCg0KYGBge3IgaW1wb3J0X2RhdGF9DQojIEltcG9ydCB0aGUgZGF0YSAtLS0tDQoNCg0KZGYgPC0gcmVhZF9jc3YoIkJhbmtDaHVybmVycy5jc3YiKQ0KDQojIE1lbmdoYXB1cyBub21vciBwZWxhbmdnYW4NCg0KZGYgPC0gZGYgJT4lIA0KICBzZWxlY3QoLWMoQ0xJRU5UTlVNLCANCiAgICAgICAgICAgIE5haXZlX0JheWVzX0NsYXNzaWZpZXJfQXR0cml0aW9uX0ZsYWdfQ2FyZF9DYXRlZ29yeV9Db250YWN0c19Db3VudF8xMl9tb25fRGVwZW5kZW50X2NvdW50X0VkdWNhdGlvbl9MZXZlbF9Nb250aHNfSW5hY3RpdmVfMTJfbW9uXzEsDQogICAgICAgICAgICBOYWl2ZV9CYXllc19DbGFzc2lmaWVyX0F0dHJpdGlvbl9GbGFnX0NhcmRfQ2F0ZWdvcnlfQ29udGFjdHNfQ291bnRfMTJfbW9uX0RlcGVuZGVudF9jb3VudF9FZHVjYXRpb25fTGV2ZWxfTW9udGhzX0luYWN0aXZlXzEyX21vbl8yKSkgJT4lIA0KICBzZXRfbmFtZXMobmFtZXMoLikgJT4lIHN0cl90b19sb3dlcigpKQ0KDQoNCg0KYGBgDQoNCg0KDQojIEV4cGxvcmFzaSBEYXRhIEFuYWx5c2lzIChFREEpDQoNCg0KDQojIyBCdWF0IHBhcmFtZXRlciB0ZW1hDQoNCmBgYHtyIGN1c3RvbV90aGVtZX0NCg0KY3VzdG9tX3RoZW1lIDwtIHRoZW1lX2J3KCkgKyANCiAgICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgY29sb3IgPSAiYmxhY2siLCBzaXplPTE0KSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZT0xMiksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9ZWxlbWVudF9yZWN0KGZpbGw9IiM2NjY2NjYiKSwgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvcj0id2hpdGUiLCBmYWNlPSJib2xkIiksDQogICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIpKQ0KICANCg0KYGBgDQoNCg0KDQoNCiMjIFBlcmluZ2thc2FuDQoNCkthbWkgYWthbiBtZW5nZ3VuYWthbiBwYWtldCBza2ltciB1bnR1ayBtZW5ndW1wdWxrYW4gYmViZXJhcGEgaW5mb3JtYXNpIHNpbmdrYXQgdGVudGFuZyBkYXRhc2V0IGluaS4NCg0KPHVsPg0KPGxpPioqVGlkYWsgYWRhIG5pbGFpIHlhbmcgaGlsYW5nOioqIFRpZGFrIGFkYSBuaWxhaSB5YW5nIGhpbGFuZyBkYWxhbSBkYXRhc2V0IGluaSBrYW1pIChiZXJ1bnR1bmcsIGthcmVuYSB0aWRhayBhZGEgbWV0b2RlIGltcHV0YXNpIHlhbmcgaGFydXMgZGl0ZXJhcGthbiksIHlhbmcga2FtaSBndW5ha2FuIGtldGlrYSBtZW1pbGkgYmFueWFrIG5pbGFpIHlhbmcgaGlsYW5nLiA8L2xpPg0KPGxpPioqQmF0YXMgS3JlZGl0IHJhdGEtcmF0YToqKiBCYXRhcyBLcmVkaXQgcmF0YS1yYXRhIGFkYWxhaCA4LjYzMS45NSBVU0QsIHNlZGFuZ2thbiBtZWRpYW4gYWRhbGFoIDQuNTk0IFVTRCB5YW5nIGRhcGF0IG1lbnVuanVra2FuIGJhaHdhIGFkYSBiZWJlcmFwYSBvdXRsaWVyIGRhbGFtIGt1bXB1bGFuIGRhdGFzZXQgaW5pIGthcmVuYSBwZXJiZWRhYW4geWFuZyBsZWJhciBhbnRhcmEgbWVhbiBkYW4gbWVkaWFuLiAgIDwvbGk+DQo8bGk+KipUb3RhbCBTYWxkbyBCZXJndWxpciA6KiogU2FsZG8gYmVyZ3VsaXIgdGlkYWsgbWVtaWxpa2kgZGlzdHJpYnVzaSBraHVzdXMgZGFuIHJhdGEtcmF0YSBzYWxkbyBiZXJndWxpZXIgdGVybGV0YWsgcGFkYSAxLjAwMCBVU0QuIDwvbGk+DQoNCjwvdWw+DQoNCioqQ2F0YXRhbjoqKjxicj4NCkFkYSBmaXR1ciBsYWluIHVudHVrIGRpamVsYWphaGkgc2F5YSB0ZXRhcCBtZW1hc3Vra2FueWEga2UgZGFsYW0gdGlnYSBmaXR1ciBpbmkga2FyZW5hIGthbWkga2FuIG1lbmduYWxpc2lzbnlhIGxlYmloIGxhbmp1dCBuYW50aSBkaWJhZ2luYSBla3Nwb2xhcnNpIGRhdGEuDQoNCg0KDQoNCmBgYHtyIHN1bW1hcml6YXRpb259DQoNCiMgQmViZXJhcGEgZml0dXIgZGFwYXQgZGkga2F0ZWdvcmlrYW4NCg0Kc2tpbShkZikNCg0KDQojIDE2JSBQZWxhbmdnYW4gbWVtaWxpa2kgQXR0cml0ZWQgKGthbWkgYmVydXJ1c2FuIGRhdGEgc2V0IHlhbmcgdGlkYWsgc2VpbWJhbmcpDQoNCiMgVW50dWsgbWVtZXJpa3NhIHByb3BvcnNpIGRhdGENCg0KIyBkZiAlPiUgDQojICAgc2VsZWN0X2lmKGlzLmNoYXJhY3RlcikgJT4lIA0KIyAgIG1hcCggfiB0YWJsZSguKSAlPiUgcHJvcC50YWJsZSgpKQ0KDQoNCmBgYA0KDQoNCg0KDQoNCiMjIEthdGVnb3JpIFBlbmRhcGF0YW4NCg0KDQojIyMgTWVtYmFkaW5na2FuIFRpbmdrYXQgQXRyaXNpIA0KDQoqKlJpbmdrYXNhbjoqKg0KDQo8dWw+DQo8bGk+KipUaW5na2F0IEF0cmlzaSBUaW5nZ2kgZGVuZ2FuIEthdGVnb3IgUGVuZGFwYXRhbiBUaW5nZ2k/KiogS2FtaSBtZWxpaGF0IGJhaHdhIGthdGVnb3IgcGVuZHBhdGFuIHRlcnRpbmdnaSBtZW1pbGlraSAlIHRpbmdna2F0IGF0cmlzaSB5YW5nIHRpbmdnaSAod2FsYXB1biB0aWRhayBiYW55YWspLCBkaWJhbmRpbmdrYW4gZGVuZ2FuIGthdGVnb3JpIHBlbmRhcGF0YW4gbGFpbnlhLiBEaWlrdXRpIG9sZWgga2F0ZWdvcmkgcGVuZGFwYXRhbiB0ZXJlbmRhaC4gPC9saT4NCg0KPC91bD4NCg0KDQpgYGB7ciBpbmNvbWVfYXR0cml0aW9uX2xldmVsc30NCg0KIyBTdGVwIDI6IEluY29tZSBDYXRlZ29yeSAgLS0tLQ0KDQojIEFzc2lnbiB0aGUgbGV2ZWwgb3JkZXINCmxldmVsX29yZGVyIDwtIGMoIiQxMjBLICsiLCAiTGVzcyB0aGFuICQ0MEsiLCAiJDQwSyAtICQ2MEsiLCAiJDgwSyAtICQxMjBLIiwgIiQ0MEsgLSAkNjBLIiwgIiQ2MEsgLSAkODBLIiwgIlVua25vd24iKQ0KDQojIGEuIEZpbmQgJSBvZiBjdXN0b21lcnMgd2hvIGFyZSBhYm91dCB0byBsZWF2ZQ0KDQppbmNvbWVfdGJsIDwtIGRmICU+JSANCiAgc2VsZWN0KGF0dHJpdGlvbl9mbGFnLCBpbmNvbWVfY2F0ZWdvcnkpICU+JSANCiAgY291bnQoYXR0cml0aW9uX2ZsYWcsIGluY29tZV9jYXRlZ29yeSkgJT4lIA0KICBncm91cF9ieShpbmNvbWVfY2F0ZWdvcnkpICU+JSANCiAgbXV0YXRlKHBjdCA9IG4gLyBzdW0obikpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgYXJyYW5nZShkZXNjKHBjdCkpICU+JSANCiAgbXV0YXRlKA0KICAgIHBjdF90eHQgPSBzY2FsZXM6OnBlcmNlbnQocGN0KSwNCiAgICBpbmNvbWVfY2F0ZWdvcnkgPSBpbmNvbWVfY2F0ZWdvcnkgJT4lIGZhY3RvcihsZXZlbHMgPSBjKCIkMTIwSyArIiwgIkxlc3MgdGhhbiAkNDBLIiwgIiQ0MEsgLSAkNjBLIiwgIiQ4MEsgLSAkMTIwSyIsICIkNjBLIC0gJDgwSyIsICJVbmtub3duIikpICU+JSBmY3RfcmV2KCksDQogICAgaW5jb21lX2NhdGVnb3J5ID0gaW5jb21lX2NhdGVnb3J5ICU+JSBhc19mYWN0b3IoKSAlPiUgZmN0X3Jlb3JkZXIocGN0KSwNCiAgICBhdHRyaXRpb25fZmxhZyA9IGF0dHJpdGlvbl9mbGFnICU+JSBhc19mYWN0b3IoKSAlPiUgZmN0X3JldigpDQogICkgDQoNCg0KIyBQbG90IFZpc3VhbGl6YXRpb24NCg0KaW5jb21lX3RibCAlPiUgDQogIGdncGxvdChhZXMoeD1pbmNvbWVfY2F0ZWdvcnksIHk9cGN0LCBjb2xvcj0gYXR0cml0aW9uX2ZsYWcpKSArIA0KICBnZW9tX3NlZ21lbnQoYWVzKHllbmQgPSAwLCB4ZW5kID0gaW5jb21lX2NhdGVnb3J5KSwgc2l6ZSA9IDEpICsgDQogIGdlb21fcG9pbnQoKSArIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gcGN0X3R4dCksIGhqdXN0ID0gImlud2FyZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDMpICsgY29vcmRfZmxpcCgpICsNCiAgZmFjZXRfd3JhcCh+IGF0dHJpdGlvbl9mbGFnKSAgKyBjdXN0b21fdGhlbWUgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIA0KICBzY2FsZV9jb2xvdXJfbmVqbSgpICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiVGluZ2thdCBHZXNla2FuIiwNCiAgICBzdWJ0aXRsZSA9ICJNZW51cnV0IEthdGVnb3JpIFBlbmRhcGF0YW4iLA0KICAgIHggPSAiS2F0ZWdvcmkgUGVuZGFwYXRhbiIsDQogICAgeSA9ICJQZXJzZW50YXNpIEdlc2VrYW4iDQogICkNCg0KDQpgYGANCg0KDQojIyMgUGVuZ2FydWggVGluZ2thdCBQZW5kaWRpa2FuDQoNCioqUmluZ2thc2FuOioqDQoNCjx1bD4NCjxsaT4qKkJhc2lzIFBlbGFuZ2dhbiBUZXJ0aW5nZ2k6ICoqIEN1a3VwIG1lbmFyaWsga2l0YSBtZWxpaGF0IGJhaHdhIGJhc2lzIHBlbGFuZ2dhbiB1dGFtYSBtZW1pbGxpa2kgcHJvZ3JhbSBwYXNjYXNhcmphbmEuIE11bmdraW4gYmVyYXJ0aSBiYWh3YSBiYXNpcyBwZWxhbmdnYW4gdXRhbWEga2FtaSBhZGFsYWgga2xpZW4gZGkgdXNpYSB5YW5nIGxlYmloIG11ZGEuIDwvbGk+DQo8bGk+KipUaW5na2F0IEF0cmlzaSBUZXJpbmdnaTogKiogS2FtaSBtZWxpaGF0IGJhaHdhIGtlbG9tcG9rIFNlZ21lbiBHcmFkdWF0ZSBkYW4gSGlnaHNob29sIG1lbWlsaWtpIHRpbmdrYXQgYXRyaXNpIHRlcnRpbmdnaS4gPC9saT4NCg0KPC91bD4NCg0KDQpgYGB7ciBpbmNvbWVfZWR1Y2F0aW9uX2xldmVsfQ0KDQojIEZ1bmdzaSByZWZlcmVuc2k6IFN0YWNrb3ZlcmZsb3cNCnNwZWNpZnlfZGVjaW1hbCA8LSBmdW5jdGlvbih4LCBrKSB0cmltd3MoZm9ybWF0KHJvdW5kKHgsIGspLCBuc21hbGw9aykpDQoNCg0KIyBEYXJpIGthdGVnb3JpIHBlbmRhcGF0YW4gZGFuIHBlbmRpZGlrYW4gbWFuYSBwZWxhbmdnYW4geWFuZyBwYWxpbmcgdGVydGFyaWsgYmVyYXNhbD8NCg0KIyBCYWRpbmdrYW4gdGluZ2thdCBnZXNla2FuIG1lbnVydXQgS2F0ZWdvcmlfcGVuZGFwYXRhbiBkYW4gdGluZ2thdCBwZW5kaWRpa2FuDQppbmNvbWVfZWR1Y2F0aW9uX3BjdF90YmwgPC0gZGYgJT4lIA0KICBjb3VudChhdHRyaXRpb25fZmxhZywgaW5jb21lX2NhdGVnb3J5LCBlZHVjYXRpb25fbGV2ZWwpICU+JSANCiAgZ3JvdXBfYnkoYXR0cml0aW9uX2ZsYWcsIGluY29tZV9jYXRlZ29yeSwgZWR1Y2F0aW9uX2xldmVsKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShuKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBncm91cF9ieShpbmNvbWVfY2F0ZWdvcnkpICU+JSANCiAgbXV0YXRlKA0KICAgIHBjdCA9IHRvdGFsIC8gc3VtKHRvdGFsKQ0KICApICU+JSB1bmdyb3VwKCkgJT4lIA0KICBtdXRhdGUoDQogICAgaW5jb21lX2NhdGVnb3J5ID0gaW5jb21lX2NhdGVnb3J5ICU+JSBmYWN0b3IobGV2ZWxzID0gYygiJDEyMEsgKyIsICJMZXNzIHRoYW4gJDQwSyIsICIkNDBLIC0gJDYwSyIsICIkODBLIC0gJDEyMEsiLCAiJDYwSyAtICQ4MEsiLCAiVW5rbm93biIpKSAlPiUgZmN0X3JldigpDQogICkgJT4lIA0KICBtdXRhdGUoDQogICAgcGN0ID0gYXMubnVtZXJpYyhzcGVjaWZ5X2RlY2ltYWwocGN0LDQpKSwNCiAgICBwY3RfdHh0ID0gc3RyX2dsdWUoIntwY3QqMTAwfSUiKQ0KICApDQogIA0KDQoNCg0KIyBQbG90DQoNCmluY29tZV9lZHVjYXRpb25fcGN0X3RibCAlPiUgDQogIGdncGxvdChhZXMoeD1lZHVjYXRpb25fbGV2ZWwsIHkgPSBpbmNvbWVfY2F0ZWdvcnkpKSArIA0KICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBwY3QpKSArIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICIjNkY5OUFERkYiLCBtaWQgPSAid2hpdGUiLCBoaWdoID0gIiNCQzNDMjlGRiIpICsgZmFjZXRfd3JhcCh+IGF0dHJpdGlvbl9mbGFnLCBzY2FsZXMgPSAiZnJlZV94IikgKyBjdXN0b21fdGhlbWUgKyANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoZmFjZSA9ICJpdGFsaWMiKSkgKyANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBjdF90eHQpLCBzaXplPTIuNSkgKyANCiAgbGFicygNCiAgICB0aXRsZSA9ICJBdHJpc2kgUGVsYW5nZ2FuIFBldGEgUGFuYXMiLA0KICAgIGNhcHRpb24gPSAiQmVycGluZGlkaWthbiB0aW5nZ2kgZGFuIGJlcnBlbmdoYXNpbGFuIG1lbmVuZ2FoIGtlIGF0YXMgbWVtaWxpa2kgJSBBdHJpc2kgeWFuZyBiZXNhciIsDQogICAgeCA9ICJUaW5na2F0IFBlbmRpZGlrYW4iLCANCiAgICB5ID0gIkthdGVnb3JpIFBlbmRhcGF0YW4iDQogICkNCg0KYGBgDQoNCg0KDQoNCiMjIyBTYWxkbyBCZXJndWxpciBWUyBCYXRhcyBLcmVkaXQNCg0KTWFyaSBraXRhIGtvbmZpcm1hc2kgYmFod2Ega2l0YSBtZWxpaGF0IGJhaHdhIGdyb3VwIHlhbmcgbWVtaWxpa2kgYmVuZGVyYSB0aW5na2F0IGF0cmlzaSB0ZXJ0aW5nZ2kgImtlZHVhIiBhZGFsYWggPHNwYW4gc3R5bGU9ImJhY2tncm91bmQ6I2ZlZDU2ZjsgZm9udC13ZWlnaHQ6Ym9sZDsgY29sb3I6YmxhY2siPiBncm91cCBrYXRlZ29yaSBwZW5kYXBhdGFuIEt1cmFuZyBkYXJpIDQwSy4gPC9zcGFuPiBEYWxhbSBoYWwgaW5pIHNheWEgaW5naW4gbWVuZWx1c3VyaSBrYXRlZ29yaSBwZW5kYXBhdGFuIHRlcmVuZGFoIHVudHVrIG1lbGloYXQgYmViZXJhcGEgdGluZ2thdCByZXZvbHZpbmcgYmFsYW5jZSBwYWRhIGdydXAgaW5pLiANCg0KDQoqKlJpbmdrYXNhbjoqKg0KDQo8dWw+DQo8bGk+KipUaW5na2F0IGJhdGFzIGtyZWRpdCByZW5kYWg6KiogQmF0YXMgS3JlZGl0IHVudHVrIGtlbGVtcG9rIGJlcnBlbmdoYXNpbGFuIHJlbmRhaCwgcmVuZGFoIHVudHVrIHBlbGFuZ2dhbiB5YW5nIHRlcnRhcmlrLiA8L2xpPg0KPGxpPioqU2FsZG8gQmVycHV0YXIgVGluZ2dpOioqIEdydXAgaW5pIG1lbWlsaWtpIHNhbGRvIGJlcmd1bGlyIHlhbmcgdGluZ2dpLCB5YW5nIGRhcGF0IG1lbmphZGkgYWxhc2FuIG1lbmdhcGEgYmF0YXMga3JlZGl0IHVudHVrIG1lcmVrYSByZW5kYWguIDwvbGk+DQo8bGk+KipUaWRhayBjdWt1cCBiYXRhcyBLcmVkaXQgdW50dWsga2VsZW1wb2sgdGVydGVudHU/KiogS2FtaSBtZWxpbGhhdCBiYWh3YSBhZGEgaW5kaXZpZHUgeWFuZyB0ZXJ0YXJpayB5YW5nIHRpZGFrIG1lbWlsaWtpIHNhbGRvIGJlcmd1bGlyIHRldGFwaSBtZW1pbGlraSBiYXRhcyBrcmVkaXQgeWFuZyByZW5kYWguIE11bmdraW5rYWggaW5pIHBlbmplbGFzYW4gdW50dWsgZ2VzZWthbj8gIDwvbGk+DQo8L3VsPg0KDQoNCmBgYHtyIHJldm9sdmluZ19iYWxhbmNlfQ0KDQoNCiMgU2FsZG8gYmVyZ3VsaXIgYmVyZGFzYXJrYW4gcGVuZGFwYXRhbg0KIyBQZXJraXJhYW4gR3JhZmlrLg0KDQojIEtvcmVsYXNpIGRhbGFtIGNyZWRpdF9saW1pdCBkYW4gcmV2b2x2aW5nX2JhbGFuY2UNCmxvd2VzdF9pbmNvbWVfY2F0X3RibCA8LSBkZiAlPiUgDQogIGZpbHRlcihpbmNvbWVfY2F0ZWdvcnkgPT0gIkxlc3MgdGhhbiAkNDBLIiAmIGF0dHJpdGlvbl9mbGFnID09ICJBdHRyaXRlZCBDdXN0b21lciIpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGNvcnJlbGF0aW9uID0gc2NhbGVzOjpwZXJjZW50KGNvcihjcmVkaXRfbGltaXQsIHRvdGFsX3Jldm9sdmluZ19iYWwpKQ0KICApDQoNCg0KZGYgJT4lIA0KICBmaWx0ZXIoYXR0cml0aW9uX2ZsYWcgPT0gIkF0dHJpdGVkIEN1c3RvbWVyIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9Y3JlZGl0X2xpbWl0LCB5PXRvdGFsX3Jldm9sdmluZ19iYWwsIGNvbG9yPWluY29tZV9jYXRlZ29yeSkpICsgZ2VvbV9wb2ludChhbHBoYSA9IDAuMykgKw0KICBmYWNldF93cmFwKH4gaW5jb21lX2NhdGVnb3J5LCBzY2FsZXMgPSAiZnJlZV94IikgKyBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvcj0icmVkIikgKyANCiAgY3VzdG9tX3RoZW1lICsgc2NhbGVfY29sb3VyX25lam0oKSArIA0KICBsYWJzKA0KICAgIHRpdGxlID0gIktvcmVsYXNpIENyZWRpdCBMaW1pdCBkYW4gUmV2b2x2aW5nIEJhbGFuY2UiLA0KICAgIGNhcHRpb24gPSBzdHJfZ2x1ZSgiS29yZWxhc2kga2F0ZWdvcmkgUGVuZGFwYXRhbiB0ZXJlbmRhaDoge2xvd2VzdF9pbmNvbWVfY2F0X3RibH0iKSwNCiAgICB4ID0gIkJhdGFzIEtyZWRpdCIsDQogICAgeSA9ICJUb3RhbCBTYWxkbyBCZXJndWxpciINCiAgKQ0KDQoNCg0KYGBgDQoNCg0KIyMjIE1ldHJpeCBUaW5na2F0IEFrdGl2aXRhcw0KDQpLYXRlZ29yaSBQZW5kYXBhdGFuIHlhbmcgbGViaWggcmVuZGFoIG1lbWlsaWtpIHJhc2lvIHBlbWFtZmFhdGFuIHlhbmcgc2VkaWtpdCBsZWJpaCBiZXNhciBkaWJhbmRpbmdrYW4gZGVuZ2FuIGthdGVnb3JpIHBlbmRhcGF0YW4gbGFpbnlhLiBNZXNraXB1biBkZW1pa2lhbiwgaW5pIGJ1a2FuIGp1bWxhaCB5YW5nIHNpZ25pZmlrYW4gdGV0YXBpIGRhcGF0IG1lbnVuanVra2FuIGJhaHdhIGthdGVnb3JpIGJlcnBlbmdoYXNpbGFuIHJlbmRhaCBtZW1pbGlraSB0aW5na2F0IGFrdGl2aXRhcyB5YW5nIHNlZGlraXQuIEluaSBha2FuIGJhaWsgdW50dWsgZGlwYWhhbWkgdGVydXRhbWEga2V0aWthIGtpdGEgbWFzdWsga2UgZmFzZSBwZW50aW5neWEgZml0dXIgdW50dWsgbW9kZWwga2l0YS4gUmFzaW8gcGVtYW5mYWF0YW4ganVnYSBtZW1iZXJpIHRhaHUga2l0YSB0aW5na2F0IGFrdGl2aXRhcyBtZW5lcnV0IGthdGVnb3JpIHBlbmRhcGF0YW4sIHRldGFwaSBzZWthbGkgbGFnaSBraXRhIGhhcnVzIGJlcmFsaWgga2UgZmFzZSBrZXBlbnRpbmdhbiBmaXR1ciB1bnR1ayBtZWxpaGF0IGFwYWthaCB0aW5na2F0IGFrdGl2aXRhcyBtZXJ1cGFrYW4gaW5kaWthdG9yIGFwYWthaCBwZWxhZ2dhbiBha2FuIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgUGVydXNhaGFhbiBiYW5rLiANCg0KYGBge3IgYWN0aXZpdHlfbGV2ZWxzX2luY29tZX0NCg0KaW5jb21lX21ldHJpY3MgPC0gZGYgJT4lIA0KICBzZWxlY3QoaW5jb21lX2NhdGVnb3J5LCB0b3RhbF90cmFuc19jdCwgYXZnX3V0aWxpemF0aW9uX3JhdGlvLCB0b3RhbF90cmFuc19hbXQpICU+JSANCiAgZ3JvdXBfYnkoaW5jb21lX2NhdGVnb3J5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBhdmdfdHJhbnNfY3QgPSByb3VuZChtZWFuKHRvdGFsX3RyYW5zX2N0LCBuYS5ybSA9IFRSVUUpLDIpLA0KICAgIGF2Z191dGlsaXphdGlvbl9yYXRpbyA9IHJvdW5kKG1lYW4oYXZnX3V0aWxpemF0aW9uX3JhdGlvLCBuYS5ybSA9IFRSVUUpLDIpDQogICkgJT4lIA0KICB1bmdyb3VwKCkNCg0KDQojIExha3VrYW4gZ3JhZmlrIHJhZGFyDQojIE11bmdraW4gbWVtYnVhdCBiZWJlcmFwYSBtZXRyaXgNCnByZXBfdGJsIDwtIGluY29tZV9tZXRyaWNzICU+JSANCiAgcGl2b3RfbG9uZ2VyKDI6MykgJT4lIA0KICBtdXRhdGUoDQogICAgaW5jb21lX2NhdGVnb3J5ID0gYXMuZmFjdG9yKGluY29tZV9jYXRlZ29yeSkgJT4lIGZjdF9yZW9yZGVyKHZhbHVlKQ0KICApDQoNCnByZXBfdGJsICU+JSANCiAgZ2dwbG90KGFlcyh4PWluY29tZV9jYXRlZ29yeSwgeT12YWx1ZSwgZmlsbD1uYW1lKSkgKyANCiAgZ2VvbV9jb2woY29sb3I9ImJsYWNrIikgKw0KICBmYWNldF93cmFwKH5uYW1lLCBzY2FsZXMgPSAiZnJlZV94IikgKyANCiAgY29vcmRfZmxpcCgpICsgY3VzdG9tX3RoZW1lICsgc2NhbGVfZmlsbF9uZWptKCkgKyANCiAgZ2VvbV9sYWJlbChhZXMobGFiZWw9dmFsdWUpLCBjb2xvcj0id2hpdGUiLCBoanVzdD0xLjIpICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTWV0cmlrIG1lbnVydXQgS2F0ZWdvcmkgUGVuZGFwYXRhbiIsDQogICAgc3VidGl0bGUgPSAiU2VtYWtpbiBkYWxhbSBrZSB0aW5na2F0IGFrdGl2aXRhcyIsDQogICAgeCA9ICJOaWxhaSIsDQogICAgeSA9ICJLYXRlZ29yaSBQZW5kYXBhdGFuIg0KICApDQoNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KIyMgS2F0ZWdvcmkgS2FydHUNClR1anVhbiBtZW5qZWxhamFoaSBrYXRlZ29yaSBrYXJ0dSBhZGFsYWggdW50dWsgbWVsaWhhdCBhcGFrYWgga2xpZW4ga2FtaSBwdWFzIGRlbmdhbiBwZW5hd2FyYW4gcHJvZHVrIHlhbmcgZGl0YXdhcmthbiBpbnN0aXR1c2kuIEFwYSBzYWphIGplbmlzIGthcnR1IGtyZWRpdCB5YW5nIGRpdGF3YXJrYW4gb2xlaCBsZW1iYWdhIGthcnR1IGtyZWRpdD8NCg0KPHVsPg0KPGxpPioqS2FydHUgQmlydSoqIDwvbGk+DQo8bGk+KipLYXJ0dSBFbWFzKiogPC9saT4NCjxsaT4qKkthcnR1IFNpbHZlcioqIDwvbGk+DQo8bGk+KipLYXJ0dSBQbGF0aW51bSoqIDwvbGk+DQoNCjwvdWw+DQoNCg0KIyMjIFRpbmdrYXQgQXRyaXNpDQoNCjx1bD4NCjxsaT4qKlRpbmdrYXQgQXRyaXNpOioqIFRpbmdrYXQgcGVyc2VudGFzaSBhdHJpc2kgdGVydGluZ2dpIGJlcmFzYWwgZGFyYWkgcGVuZ2d1bmEga2FydHUgcGxhdGludW0gZGFuIGVtYXMuIDwvbGk+DQo8bGk+KipUaW5na2F0IGdlc2VrYW4gdGVyZW5kYWg6IFRpbmdrYXQgZ2VzZWthbioqIHRlcmVuZGFoIGJlcmFzYWwgZGFyaSBrYXJ0dSBwZXJhayBkYW4gYmlydS4gPC9saT4NCg0KPC91bD4NCg0KDQoNCmBgYHtyIGNhcmRfZ3JvdXBfYXR0cml0aW9ufQ0KY2FyZF9jYXRlZ29yeV9hdHRyaXRpb25fdGJsIDwtIGRmICU+JSANCiAgc2VsZWN0KGF0dHJpdGlvbl9mbGFnLCBjYXJkX2NhdGVnb3J5KSAlPiUgDQogIGNvdW50KGF0dHJpdGlvbl9mbGFnLCBjYXJkX2NhdGVnb3J5KSAlPiUgDQogIGdyb3VwX2J5KGNhcmRfY2F0ZWdvcnkpICU+JSANCiAgbXV0YXRlKHBjdCA9IG4gLyBzdW0obikpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgYXJyYW5nZShkZXNjKHBjdCkpICU+JSANCiAgICBtdXRhdGUoDQogICAgcGN0X3R4dCA9IHNjYWxlczo6cGVyY2VudChwY3QpLA0KICAgIGNhcmRfY2F0ZWdvcnkgPSBjYXJkX2NhdGVnb3J5ICU+JSBhc19mYWN0b3IoKSAlPiUgZmN0X3Jlb3JkZXIocGN0KQ0KICAgICkNCg0KDQoNCmNhcmRfY2F0ZWdvcnlfYXR0cml0aW9uX3RibCAlPiUgDQogIGdncGxvdChhZXMoeCA9IHBjdCwgeSA9IGNhcmRfY2F0ZWdvcnksICBmaWxsID0gYXR0cml0aW9uX2ZsYWcpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIiwgd2lkdGggPSAwLjUsIGNvbG9yID0gImJsYWNrIikgKw0KICBmYWNldF93cmFwKH4gYXR0cml0aW9uX2ZsYWcsIHNjYWxlcyA9ICJmcmVlX3giKSArIGN1c3RvbV90aGVtZSArIA0KICBzY2FsZV9maWxsX25lam0oKSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsgDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gcGN0X3R4dCksIGhqdXN0ID0gImlud2FyZCIsIGNvbG9yID0gIndoaXRlIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlN0YXR1cyBQZWxhbmdnYW4gTWVudXJ1dCBLYXRlb2dvcmkgUGVuZGFwYXRhbiIsDQogICAgeCA9ICJUaW5na2F0IEdlc2VrYW4iLA0KICAgIHkgPSAiS2F0ZWdvcmkgS2FydHUiLA0KICAgIGNhcHRpb24gPSAiS2FydHUgUGxhdGludW0gbWVtaWxpa2kgdGluZ2thdCBnZXNla2FuIHRlcnRpbmdnaSINCiAgKQ0KDQoNCmBgYA0KDQoNCg0KDQojIyMgVG90YWwgVHJhbnNha3NpIA0KDQoNCjx1bD4gDQo8bGk+KipUb3RhbCB0cmFuc2thc2kgeWFuZyBqYXVoIGxlYmloIHJlbmRhaCB1bnR1ayBwbGF0aW51bToqKiBJbmkgZGFwYXQgbWVudW5qdWtrYW4gZHVhIGhhbCBkYXJpIHBlbGFuZ2dhbiB5YW5nIGtlbHVhciBkYXJpIGdyb3VwIGluaSwgYXBha2FoIG1lcmVrYSB0aWRhayBtZW1pbGlraSBiYXRhcyBrcmVkaXQgeWFnIGN1a3VwIGF0YXUgbWVyZWthIHRlcm1hc3VrIGRhbGFtIGthdGVvZ3JpIGJlcnBlbmdoYXNpbGFuIHJlbmRhaC4gQW5kYSBkYXBhdCBtZW1lcmlrc2EgYmFod2EgbWVkaWFuIGRpc3RyaWJ1c2kgdW50dWsgS2F0ZWdvcmkgUGxhdGludW0gdW50dWsgdG90YWwgdHJhbnNha3NpIGphdWggbGViaWggcmVuZGFoIGRhcmkgcGFkYSBwZWxhbmdnYW4geWFuZyBtZW5naW5hcC4gIDwvbGk+DQo8bGk+KipHcnVwIGthcnR1IGVtYXM6ICoqVW50dWsgZ3J1cCBrYXJ0dSBlbWFzLCBrYW1pIHRpZGFrIG1lbGloYXQgcGVyYmVkYWFuIGJlc2FyLjwvbGk+DQo8bGk+KipLbHVzdGVyIHlhbmcgYmVyYmVkYSBkYWxhbSBkaXN0cmlidXNpIGthbWk6KiogUGVyaGF0aWthbiBiYWh3YSBrYW1pIG1lbGloYXQgY2x1c3RlciB5YW5nIGJlcmJlZGEgZGkgYmViZXJhcGEgZGlzdHJpYnVzaSBncnVwIGthcnR1IGthbWksIGluaSBkYXBhdCBiZXJhcnRpIGJhaHdhIGluaSBhZGFsYWggY2x1c3RlciB0aW5na2F0IHBlbmRhcGF0YW4geWFuZyBkYXBhdCBkaWtvcmVsYXNpIGRlbmdhbiB0aW5na2F0IHRyYW5zYWtzaS4gPC9saT4NCjwvdWw+DQoNCg0KYGBge3IgdG90YWxfdHJhbnNhY3Rpb25zfQ0KDQojIERpc3RyaWJ1c2kgcmFzaW8gVmlzdWFsaXNhc2kgYmVyZGFzYXJrYW4gamVuaXMga2FydHUNCg0KY2FyZF91dGlsaXphdGlvbl90YmwgPC0gZGYgJT4lIA0KICBzZWxlY3QoYXR0cml0aW9uX2ZsYWcsIGNhcmRfY2F0ZWdvcnksIGF2Z191dGlsaXphdGlvbl9yYXRpbywgdG90YWxfdHJhbnNfYW10KQ0KDQoNCmNhcmRfdXRpbGl6YXRpb25fdGJsICU+JSANCiAgZ2dwbG90KGFlcyh4PWNhcmRfY2F0ZWdvcnksIHk9dG90YWxfdHJhbnNfYW10LGZpbGw9Y2FyZF9jYXRlZ29yeSkpICsgDQogIGdlb21faml0dGVyKGFlcyhjb2xvcj1jYXJkX2NhdGVnb3J5KSwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjUsDQogICAgICAgICAgICAgIHNpemU9MC41LA0KICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIA0KICBnZW9tX2hhbGZfdmlvbGluKGFlcyhmaWxsPWNhcmRfY2F0ZWdvcnkpLA0KICAgICAgICAgICAgICAgICAgIHNpZGUgPSAibCIsDQogICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjQ1LA0KICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgdHJpbSA9IEZBTFNFKSArDQogIGdlb21faGFsZl9ib3hwbG90KGFlcyhmaWxsID0gY2FyZF9jYXRlZ29yeSksDQogICAgICAgICAgICAgICAgICAgIHNpZGUgPSAiciIsDQogICAgICAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZSA9IDEsDQogICAgICAgICAgICAgICAgICAgIG91dGxpZXIuY29sb3IgPSAicmVkIiwNCiAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAwLjQsIA0KICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMiwNCiAgICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyANCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lZGlhbiwgZ2VvbT0ibGluZSIpICsgDQogIGZhY2V0X3dyYXAofiBhdHRyaXRpb25fZmxhZykgKyBjdXN0b21fdGhlbWUgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzFDMzY2QiIsICIjRkNEMTZCIiwgIiNDN0NFRjYiLCAiI0QzREREQyIpKSArIA0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzFDMzY2QiIsICIjRkNEMTZCIiwgIiNDN0NFRjYiLCAiI0QzREREQyIpKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpkb2xsYXIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXNpIFRyYW5zYWtzaSBCZXJkYXNhcmthbiBKZW5pcyBLYXJ0dSIsDQogICAgeCA9ICJLYXRlZ29yaSBLYXJ0dSIsDQogICAgeSA9ICJUb3RhbCBUcmFuc2Frc2kiDQogICkNCg0KDQpgYGANCg0KDQoNCiMjIEJlbmRlcmEgQXRyaXNpDQoNCg0KIyMjIFRpbmdrYXQgQWt0aXZpdGFzDQoNCk1hcmkga2l0YSBtZW5nZ2FuYWxpc2lzIHRpbmdrYXQga2V0aWRha2FrdGlmYW4gYmFnaSBwZWxhbmdnYW4gdWFuZyBtZW11dHVza2FuIGF0YXUgeWFuZyBha2FuIG1lbmluZ2dhbGthbiBLYXJ0dSBLcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rIGRhbiBwZWxhbmdnYW4uDQoNCjx1bD4NCjxsaT4qKlBlbGFuZ2dhbiBZYW5nIFRlcnRhcmlrOiAqKiBLYW1pIG1lbGloYXQgYmFod2EgdGluZ2thdCBpaW50ZXJha3Rpdml0YXMgbWVtaWxpa2kgbWVkaWFuIHRpZ2EgYnVsYW4sIDEgYnVsYW4gbGViaWggdGluZ2dpIGRhcmkgcGFkYSBtZXJla2EgeWFuZyBtYXNpaCBiZXJ0YWhhbiBkaSBLYXJ0dSBLcmVkaXQgUGVydXNhaGFhbiBiYW5rIHRlcnNlYml0ICAuPC9saT4NCjxsaT4qKk1lbWFoaW1pIGRpc3RyaWJ1c2kgaW5pIDogKiogSW5pIGRhcGF0IG1lbWJlcmkga2l0YSBpbmRla2FzaSBiYWh3YSBrZXRpa2EgdGluZ2thdCBrZXRpZGFrYWt0aWZhbiBtdWxhaSAibWVsYW1wYXVpIiBhbWJhbmcgYmF0YXMgMiBidWxhbiwgbWFrYSBhZGEga2VtdW5na2luYW4gbGViaWggdGluZ2dpIGJhaHdhIG9yYW5nIHRlcnNlYnV0IG1lbXV0dXNrYW4gdW50dWsgbWVuZ2luZ2dhbGthbiBLYXJ0dSBrcmVkaXQgZGkgcGVyc3VoYWFuIHRlcnNlYnV0ICAuPC9saT4NCjxsaT4qKkFsdGVybmF0aWYgeWFuZyBtdW5na2luOioqIEh1YnVuZ2kga2xpZW4gdW50dWsgbWVsaWhhdCBhcGFrYWggbWVyZWthIHB1YXMgZGVuZ2FuIGxheWFuYW4gZGFuIGFwYSB5YW5nIGRhcGF0IGRpbGFrdWthbiBLYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rIHVudHVrIG1lbmluZ2thdGthbiBzZWNhcmEga2VzZWx1cnVoYW4/IDwvbGk+DQo8L3VsPg0KDQpgYGB7cn0NCg0KYXR0cml0aW9uX3RibCA8LSBkZiAlPiUgDQogIHNlbGVjdChhdHRyaXRpb25fZmxhZywgbW9udGhzX2luYWN0aXZlXzEyX21vbiwgdG90YWxfcmV2b2x2aW5nX2JhbCwgdG90YWxfdHJhbnNfYW10LCBjcmVkaXRfbGltaXQpDQoNCg0KIyBUaW5na2F0IEtldGlkYWtha3RpZmFuIG1lbnVydXQgYmVuZGVyYSBnZXNla2FuDQpwMSA8LSBhdHRyaXRpb25fdGJsICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gbW9udGhzX2luYWN0aXZlXzEyX21vbiwgeSA9IGF0dHJpdGlvbl9mbGFnLCBmaWxsID0gYXR0cml0aW9uX2ZsYWcpKSArIA0KICBzdGF0X2RlbnNpdHlfcmlkZ2VzKHF1YW50aWxlX2xpbmVzID0gVFJVRSwgcXVhbnRpbGVzID0gMiwgYWxwaGEgPSAwLjQpICsgDQogIHNjYWxlX2ZpbGxfbmVqbSgpICsgY3VzdG9tX3RoZW1lICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiVEluZ2thdCBLZXRpZGFrYWt0aWZhbiIsDQogICAgeCA9ICJCdWxhbiBUaWRhayBBa3RpZiIsIA0KICAgIHkgPSAiQmVuZGVyZWEgQXRyaXNpIiwNCiAgICBjYXB0aW9uID0gIkF0cmlzaSBQZWxhbmdnYW4gbWVtaWxpa2kgdGluZ2thdCBLZXRpZGFrYWt0aWZhbiB5YW5nIGxlYmloIHRpbmdnaSAoMyBidWxhbiB2cyBNZWRpYW4gMiBidWxhbikiDQogICkNCg0KDQpwMQ0KYGBgDQoNCg0KDQoNCiMjIyBUaW5na2F0IFNhbGRvIEJlcmd1bGlyDQoNCktpdGEgZGFwYXQgZGVuZ2FuIGplbmlzIG1lbGloYXQgYmFod2EgcGVsYW5nZ2FuIHlhbmcgbWVtaWxpa2kgc2FkbyBiZXJndWxpciB5YW5nIHJlbmRhaCBhZGFsYWggeWFuZyBwYWxpbmcgbXVuZ2tpbiB1bnR1ayBwZXJnaS4gSW5pIGJpc2EgbWVudW5qdWtrYW4gYmFod2EgcGVsYW5nZ2FuIHRlcnNlYnV0IGJpc2Egc2FqYSBwZXJnaSBrYXJlbmEgbWVyZWthIG1lbmVtdWthbiBzdWt1IGJ1bmdhIGxhaW4geWFuZyBsZWJpaCByZW5kYWgga2UgcGVydXNhaGFhbiBsYWluIHlhbmcgbWVuYXdhcmthbiBwcm9kdWsgeWFuZyBsZWJpaCBiYWlrIGRlbmdhbiBoYXJnYSB5YW5nIGxlYmloIHJlbmRhaC4gRGFsYW0ga2FzdXMgcGVsYW5nZ2FuIHlhbmcgc3VkYWggYWRhIHJhdGEtcmF0YSBtZXJla2EgbWVtaWxraSBzYWxkbyBiZXJndWxpciBqYXVoIGxlYmloIHRpbmdnaSB0ZXRhcGkgcGVsYW5nZ2FuIGRlbmdhbiBzYWxkbyBiZXJndWxpciB5YW5nIGxlYmloIHRpbmdnaSBtZW1pbGlraSB3YWt0dSB5YW5nIGphdWggbGVpYmggc3VsaXQgdW50dWsgbWVuY2FyaSBsZW1iYWdhIGtldWFuZ2FuIGxhaW4gdW50dWsgbWVuYXdhcmthbiB0YXJpZiB5YW5nIGxlYmloIHJlbmRhaCBrYXJlbmEgcmVzaWtvIGJhaHdhIHBlbGFuZ2dhbiB0aWRhayBha2FuIG1lbWJheWFyIHNhbWEgc2VrYWxpLiBLaXJpIGRhcmkgc2lzYSBzYWxkby4gKFJlc2lrbyBUaW5nZ2ksIHRhcmlmIGxlYmloIHRpbmdnaSkNCg0KYGBge3IgcmFkYXJfY2hhcnR9DQoNCiMgQmFnYWluIFJhZGFyIHVudHVrIHBlbGFuZ2dhbiB5YW5nIHRlcnRhcmlrDQoNCm1heF92YWwgPC0gZGYgJT4lIA0KICBzZWxlY3QoYXR0cml0aW9uX2ZsYWcsIGluY29tZV9jYXRlZ29yeSwgdG90YWxfcmV2b2x2aW5nX2JhbCkgJT4lIA0KICBmaWx0ZXIoYXR0cml0aW9uX2ZsYWcgPT0gIkF0dHJpdGVkIEN1c3RvbWVyIikgJT4lIA0KICBncm91cF9ieShpbmNvbWVfY2F0ZWdvcnkpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIG1heF92YWwgPSAxMDAwDQogICkgJT4lIHVuZ3JvdXAoKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbmNvbWVfY2F0ZWdvcnksIHZhbHVlc19mcm9tID0gYyhtYXhfdmFsKSkNCg0KDQptaW5fdmFsIDwtIGRmICU+JSANCiAgc2VsZWN0KGF0dHJpdGlvbl9mbGFnLCBpbmNvbWVfY2F0ZWdvcnksIHRvdGFsX3Jldm9sdmluZ19iYWwpICU+JSANCiAgZmlsdGVyKGF0dHJpdGlvbl9mbGFnID09ICJBdHRyaXRlZCBDdXN0b21lciIpICU+JSANCiAgZ3JvdXBfYnkoaW5jb21lX2NhdGVnb3J5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBtaW5fdmFsID0gbWluKHRvdGFsX3Jldm9sdmluZ19iYWwpDQogICkgJT4lIHVuZ3JvdXAoKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbmNvbWVfY2F0ZWdvcnksIHZhbHVlc19mcm9tID0gYyhtaW5fdmFsKSkNCg0KDQoNCnJldm9fZGYgPC0gZGYgJT4lIA0KICBzZWxlY3QoYXR0cml0aW9uX2ZsYWcsIGluY29tZV9jYXRlZ29yeSwgdG90YWxfcmV2b2x2aW5nX2JhbCkgJT4lIA0KICBmaWx0ZXIoYXR0cml0aW9uX2ZsYWcgPT0gIkF0dHJpdGVkIEN1c3RvbWVyIikgJT4lIA0KICBncm91cF9ieShpbmNvbWVfY2F0ZWdvcnkpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIGF2Z19yZXYgPSBtZWFuKHRvdGFsX3Jldm9sdmluZ19iYWwsIG5hLnJtID0gVFJVRSkNCiAgKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBpbmNvbWVfY2F0ZWdvcnksIHZhbHVlc19mcm9tID0gYyhhdmdfcmV2KSkNCg0KDQoNCmNvbWJpbmVkX2RmX2F0dHJpdGVkIDwtIG1heF92YWwgJT4lIA0KICByYmluZChtaW5fdmFsKSAlPiUgDQogIHJiaW5kKHJldm9fZGYpDQoNCg0Kcm93bmFtZXMoY29tYmluZWRfZGZfYXR0cml0ZWQpIDwtIDE6bnJvdyhjb21iaW5lZF9kZl9hdHRyaXRlZCkgDQoNCg0KDQpyZXZvX2RmIDwtIGRmICU+JSANCiAgc2VsZWN0KGF0dHJpdGlvbl9mbGFnLCBpbmNvbWVfY2F0ZWdvcnksIHRvdGFsX3Jldm9sdmluZ19iYWwpICU+JSANCiAgZmlsdGVyKGF0dHJpdGlvbl9mbGFnID09ICJBdHRyaXRlZCBDdXN0b21lciIpICU+JSANCiAgZ3JvdXBfYnkoaW5jb21lX2NhdGVnb3J5KSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBhdmdfcmV2ID0gbWVhbih0b3RhbF9yZXZvbHZpbmdfYmFsLCBuYS5ybSA9IFRSVUUpDQogICkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gaW5jb21lX2NhdGVnb3J5LCB2YWx1ZXNfZnJvbSA9IGMoYXZnX3JldikpDQoNCg0KDQojIFBlbGFuZ2dhbiB5YW5nIHRlcnNpc2ENCg0KbWF4X3ZhbF9leGlzdGluZyA8LSBkZiAlPiUgDQogIHNlbGVjdChhdHRyaXRpb25fZmxhZywgaW5jb21lX2NhdGVnb3J5LCB0b3RhbF9yZXZvbHZpbmdfYmFsKSAlPiUgDQogIGZpbHRlcihhdHRyaXRpb25fZmxhZyA9PSAiQXR0cml0ZWQgQ3VzdG9tZXIiKSAlPiUgDQogIGdyb3VwX2J5KGluY29tZV9jYXRlZ29yeSkgJT4lIA0KICBzdW1tYXJpc2UoDQogICAgbWF4X3ZhbCA9IDE3MDANCiAgKSAlPiUgdW5ncm91cCgpICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGluY29tZV9jYXRlZ29yeSwgdmFsdWVzX2Zyb20gPSBjKG1heF92YWwpKQ0KDQoNCm1pbl92YWxfZXhpc3RpbmcgPC0gZGYgJT4lIA0KICBzZWxlY3QoYXR0cml0aW9uX2ZsYWcsIGluY29tZV9jYXRlZ29yeSwgdG90YWxfcmV2b2x2aW5nX2JhbCkgJT4lIA0KICBmaWx0ZXIoYXR0cml0aW9uX2ZsYWcgPT0gIkV4aXN0aW5nIEN1c3RvbWVyIikgJT4lIA0KICBncm91cF9ieShpbmNvbWVfY2F0ZWdvcnkpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIG1pbl92YWwgPSBtaW4odG90YWxfcmV2b2x2aW5nX2JhbCkNCiAgKSAlPiUgdW5ncm91cCgpICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGluY29tZV9jYXRlZ29yeSwgdmFsdWVzX2Zyb20gPSBjKG1pbl92YWwpKQ0KDQoNCg0KcmV2b19kZl9leGlzdGluZyA8LSBkZiAlPiUgDQogIHNlbGVjdChhdHRyaXRpb25fZmxhZywgaW5jb21lX2NhdGVnb3J5LCB0b3RhbF9yZXZvbHZpbmdfYmFsKSAlPiUgDQogIGZpbHRlcihhdHRyaXRpb25fZmxhZyA9PSAiRXhpc3RpbmcgQ3VzdG9tZXIiKSAlPiUgDQogIGdyb3VwX2J5KGluY29tZV9jYXRlZ29yeSkgJT4lIA0KICBzdW1tYXJpc2UoDQogICAgYXZnX3JldiA9IG1lYW4odG90YWxfcmV2b2x2aW5nX2JhbCwgbmEucm0gPSBUUlVFKQ0KICApICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGluY29tZV9jYXRlZ29yeSwgdmFsdWVzX2Zyb20gPSBjKGF2Z19yZXYpKQ0KDQoNCmNvbWJpbmVkX2RmX2V4aXN0aW5nIDwtIG1heF92YWxfZXhpc3RpbmcgJT4lIA0KICByYmluZChtaW5fdmFsX2V4aXN0aW5nKSAlPiUgDQogIHJiaW5kKHJldm9fZGZfZXhpc3RpbmcpDQoNCg0KY29tYmluZWRfZGZfYXR0cml0ZWQgPC0gbWF4X3ZhbCAlPiUgDQogIHJiaW5kKG1pbl92YWwpICU+JSANCiAgcmJpbmQocmV2b19kZikNCg0KDQpyb3duYW1lcyhjb21iaW5lZF9kZl9hdHRyaXRlZCkgPC0gMTpucm93KGNvbWJpbmVkX2RmX2F0dHJpdGVkKSANCg0KDQpjcmVhdGVfYmVhdXRpZnVsX3JhZGFyY2hhcnQgPC0gZnVuY3Rpb24oZGF0YSwgY29sb3IgPSAiIzAwQUZCQiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZsYWJlbHMgPSBjb2xuYW1lcyhkYXRhKSwgdmxjZXggPSAwLjcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2F4aXNsYWJlbHMgPSBOVUxMLCB0aXRsZSA9IE5VTEwsIC4uLil7DQogIHJhZGFyY2hhcnQoDQogICAgZGF0YSwgYXhpc3R5cGUgPSAxLA0KICAgICMgQ3VzdG9taXplIHRoZSBwb2x5Z29uDQogICAgcGNvbCA9IGNvbG9yLCBwZmNvbCA9IHNjYWxlczo6YWxwaGEoY29sb3IsIDAuNSksIHBsd2QgPSAyLCBwbHR5ID0gMSwNCiAgICAjIEN1c3RvbWl6ZSB0aGUgZ3JpZA0KICAgIGNnbGNvbCA9ICJncmV5IiwgY2dsdHkgPSAxLCBjZ2x3ZCA9IDAuOCwNCiAgICAjIEN1c3RvbWl6ZSB0aGUgYXhpcw0KICAgIGF4aXNsYWJjb2wgPSAiZ3JleSIsIA0KICAgICMgVmFyaWFibGUgbGFiZWxzDQogICAgdmxjZXggPSB2bGNleCwgdmxhYmVscyA9IHZsYWJlbHMsDQogICAgY2F4aXNsYWJlbHMgPSBjYXhpc2xhYmVscywgdGl0bGUgPSB0aXRsZSwgLi4uDQogICkNCn0NCg0KDQoNCg0Kb3AgPC0gcGFyKG1hciA9IGMoMSwgMiwgMiwgMSkpDQphdHRyaXRlZF9wbG90IDwtIGNyZWF0ZV9iZWF1dGlmdWxfcmFkYXJjaGFydChjb21iaW5lZF9kZl9hdHRyaXRlZCwgY2F4aXNsYWJlbHMgPSBjKDAsMzAwICwgNjAwLCA5MDAsIDEyMDApLCB0aXRsZSA9ICJBdHRyaXRlZCBDdXN0b21lciIsIGNvbG9yPSIjRjkyOTIzIikNCg0KDQpleGlzdGluZ19wbG90IDwtIGNyZWF0ZV9iZWF1dGlmdWxfcmFkYXJjaGFydChjb21iaW5lZF9kZl9leGlzdGluZywgY2F4aXNsYWJlbHMgPSBjKDAsIDQwMCwgODAwLCAxMjAwLCAxNjAwKSwgdGl0bGUgPSAiRXhpc3RpbmcgQ3VzdG9tZXIiLCBjb2xvcj0iIzIzRjk5MyIpDQoNCg0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCiMjIyBHcm91cCBBdHJpc2kgUGVsYW5nYWdhbiANCg0KRGkgYmFnaWFuIGluaSBraXRhIGFrYW4gbWVuZ2Vrc3Bsb3Jhc2kga2VtdW5na2luYW4ga29tYmluYXNpIGtlbGVtcG9rIG9yYW5nIHlhbmcgbWVuaW5nZ2Fsa2FuIEthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmssIGthbWkgZGFwYXQgZGVuZ2FuIGNlcGF0IG1lbXZpc3VhbGlzYXNpa2FuIGtsYXRlciB5YW5nIGtlbXVuZ2tpbmFuIGJlc2FyIGFrYW4gbWVuaW5nZ2Fsa2FuIEthcnR1IGtyZWRpdCBkaSBwZXJzdWFoYWFuIGJhbmsuDQoNCjx1bD4NCjxsaT4qKlBlbmplbGFzYW4gQmFnaWFuOioqIEJhZ2lhbiBpbmkgZGlzZWJ1dCBkaWFncmFtIHNhbmt5LCBkYW4geWFuZyBwYWRhIGRhc2FybnlhIG1lbWJlcml0YWh1IEFuZGEgYWRhbGFoIGp1bWxhaCBvcmFuZyB5YW5nIGRpYWxva2FzaWthbiB1bnR1ayBzZXRpYXAgdmFyaWFiZWwga2F0ZWdvcmkgcGVsYW5nZ2FuIHlhbmcgdGVydGFyaWsuIDwvbGk+DQo8bGk+KipMdWx1c2FuIFdhbml0YSBCZXJwZW5naGFzaWxhbiBSZW5kYWg6KiogS2VsZW1wb2sga2xhc3RlciBpbmkgdGVyZGVyaSBkYXJpIGp1bWxhaCB0ZXJ0aW5nZ2kgb3JhbmcgeWFuZyB0ZXJ0YXJpayBwYWRhIHBlbGFuZ2dhbi4uIDwvbGk+DQoNCjwvdWw+DQoNCg0KYGBge3Igc2Fua3lfZGlhZ3JhbSwgZmlnLmhlaWdodD01LjV9DQoNCnNhbXBsZV9kYXRhIDwtIGRmICU+JSANCiAgc2VsZWN0KGF0dHJpdGlvbl9mbGFnLCBlZHVjYXRpb25fbGV2ZWwsIGdlbmRlciwgaW5jb21lX2NhdGVnb3J5KSAlPiUgDQogIGZpbHRlcihhdHRyaXRpb25fZmxhZyA9PSAiQXR0cml0ZWQgQ3VzdG9tZXIiKSAlPiUgDQogIGNvdW50KGF0dHJpdGlvbl9mbGFnLCBlZHVjYXRpb25fbGV2ZWwsIGdlbmRlciwgaW5jb21lX2NhdGVnb3J5KSAlPiUgDQogIG11dGF0ZSgNCiAgICBpbnRlcmVzdGluZ19ncm91cCA9IGlmZWxzZShnZW5kZXIgPT0gIkYiICYgZWR1Y2F0aW9uX2xldmVsID09ICJHcmFkdWF0ZSIgJg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5jb21lX2NhdGVnb3J5ID09ICJMZXNzIHRoYW4gJDQwSyIsICJJbnRlcmVzdGluZyIsICJOb3QgSW50ZXJlc3RpbmciKQ0KICApDQoNCg0KDQoNCg0Kc2FtcGxlX2RhdGEgJT4lIA0KICBnZ3Bsb3QoYWVzKHkgPSBuLA0KICAgICAgICAgICAgIGF4aXMxID0gZ2VuZGVyLCBheGlzMiA9IGVkdWNhdGlvbl9sZXZlbCwgYXhpczMgPSBpbmNvbWVfY2F0ZWdvcnkpKSArDQogIGdlb21fYWxsdXZpdW0oYWVzKGZpbGwgPSBpbnRlcmVzdGluZ19ncm91cCksIGFscGhhID0gMC40LCAgYWJzb2x1dGUgPSBGQUxTRSkgKyANCiAgZ2VvbV9zdHJhdHVtKGFic29sdXRlID0gRkFMU0UsIHdpZHRoID0gMC40NSkgKyANCiAgICBnZW9tX3RleHQoc3RhdCA9ICJzdHJhdHVtIiwgYWVzKGxhYmVsID0gYWZ0ZXJfc3RhdChzdHJhdHVtKSksDQogICAgICAgICAgICBhYnNvbHV0ZSA9IEZBTFNFKSArIA0KICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIkluY29tZSBDYXRlZ29yeSIsICJFZHVjYXRpb24gTGV2ZWwiLCAiR2VuZGVyIiksIGV4cGFuZCA9IGMoLjEsIC4wNSkpICsgDQogIGN1c3RvbV90aGVtZSArIHNjYWxlX2ZpbGxfbmVqbSgpICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiR3J1cCBCZXJiZWRhIGRhbGFtIEF0cmlzaSBQZWxhbmdnYW4iLA0KICAgIHN1YnRpdGxlID0gIlBvcHVsYXNpIHNhbXBlbCBQZWxhbmdnYW4geWFuZyBUZXJ0YXJpayIsDQogICAgeSA9ICJKdW1sYWgiLA0KICAgIGNhcHRpb24gPSAiTHVsdXNhbiBXYW5pdGEgZGFsYW0ga2F0ZWdvcmkgYmVycGVuZ2hhc2lsYW4gcmVuZGFoIG1lbWJ1YXQgc2ViYWdpYW4gYmVzYXIgUGVsYW5nZ2FuIFRlcnRhcmlrIg0KICApDQogIA0KDQoNCg0KYGBgDQoNCg0KDQojIyBBbmFseXNpcyBLb3JlbGFzaSANCg0KU2ViZWx1bSBtYXN1ayBrZSBBdXRvIE1MLCBha2FuIG1lbmFyaWsgdW50dWsgbWVuZ2Vrc3Bsb3Jhc2kgZml0dXIgbWFuIGF5YW5nIGJlcmtvcmVsYXNpIGRlbmdhbiBhcGFrYWggcGVsYW5nZ2FuIGFrYW4gbWVuaW5nZ2Fsa2FuIEthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmsuIFVudHVrIGluaSBrYW1pIGFrYW4gbWVuZ2d1bmFrYW4gYXBhIHlhbmcgZGkgc2VidXQgZnVubmVyICJLb3JlbGFzaSIgeWFuZyBtZW11bmdpa2lua2FuIGthbWkgbWVtYWhhbWkgZml0dXIgbWFuYSB5YW5nIGJlcmtvbGVyYXNpIGRuZWduYSBhcGFrYWggc2VzZW9yYW5nIGFrYW4gbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmsuIENhdGF0YW46IFVudHVrIHZhcmlhYmVsIG51bWVyaWssIGthbWkgdGVsYWggbWVtdXR1c2thbiBtZW5nYWJ1bmdrYW5ueWEga2VkYWxhbSA0IGthdGVnb3JpIGRhbiBrZW11ZGlhbiBtZW1idWF0IHZhcmlhYmVsIGR1bW15IGJlcmRhc2Fya2FuIGZpdHVyIGluaSBtZWxhbHVpIHNhdHUgcGVuZ29rZWRhbiBwYW5hcy4NCg0KPHVsPg0KPGxpPioqU2FsZG8gQmVyZ3VsaXIgUmVuZGFoOioqIE9yYW5nIGJpYXNhbnlhIG1lbWJheWFyIGthcnR1IGtyZWRpdCBtZXJla2EgdGVwYXQgd2FrdHUgbGViaWggbXVuZ2tpbiB1bnR1ayBtZW5pbmdnYWxrYW4gS2FydHUga3JlZGl0IGRpIHBlcnVzYWhhYW4gYmFuay4gPC9saT4NCjxsaT4qKlRpbmdrYXQgS2V0aWRha2FrdGlmYW4gcmVuZGFoOiAqKiBKaWthIGp1bWxhaCB0cmFuc2Frc2kga3VyYW5nIGRhcmkgMC41ODIsIGtlbXVuZ2tpbmFuIGJlc2FyIHBlbGFuZ2dhbiBha2FuIHBlcmdpLiBTYW1hIHVudHVrIEp1bWxhaCB0b3RhbCB0cmFuc2Frc2kgamlrYSBrdXJhbmcgZGFyaSA0NSB1bnR1ayBrbGllbiB0ZXJ0ZW50dSBtYWthIGtsaWVuIGxlYmloIG11bmdraW4gdW50dWsgbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbms8L2xpPg0KPGxpPioqSnVtbGFoIHRyYW5zYWtzaSByZW5kYWg6KiogU2VtYWtpbiByZW5kYWgganVtbGFoIHRyYW5zYWtzaSwgc2VtYWtpbiB0aW5nZ2kga29yZWFsYXNpbnlhIGRlbmdhbiBnZXNla2FuLiAgPC9saT4NCjwvdWw+DQoNCk1PSE9OIE1BQUZGIERJIFNJTkkgTEFQVE9QIFNBWUEgVElEQUsgQklTQSBNRU5BTVBJTEtBTiBQTE9UIE5ZQSBESSBLQVJFTkFLQU4gRVJST1INCg0KYGBge3IgZmlnLmhlaWdodCA9IDd9DQpjb3JlbGF0aW9uX3ByZXBhcmVkX3RibCA8LSBkZiAlPiUgYmluYXJpemUoKQ0KDQoNCiMgUGxvdCBjb3JyZWxhdGlvbiBmdW5uZWwNCmNvcmVsYXRpb25fcHJlcGFyZWRfdGJsICU+JSANCiAgY29ycmVsYXRlKHRhcmdldCA9IGF0dHJpdGlvbl9mbGFnX19BdHRyaXRlZF9DdXN0b21lcikgJT4lIA0KICBwbG90X2NvcnJlbGF0aW9uX2Z1bm5lbChpbnRlcmFjdGl2ZSA9IEZBTFNFKSArIGN1c3RvbV90aGVtZSANCg0KYGBgDQoNCg0KDQoNCiMjIEF1dG9NTCBkZW5nYW4gSDIwIA0KDQoNClBhZGEgYmFnaWFuIGluaSBraXRhIGFrYW4gbXVsYWkgbWVuZ2ltcGxlbWVudGFzaWthbiBIMjAsIEgyMCBhZGFsYWggcGVycHVzdGFrYWFuIGF1dG9taSB5YW5nIG1lbnllcmRlcmhhbmFrYW4gcHJvc2VzIHBlbWlsaWhhbiBtb2RlbC4gVGlkYWsgaGFueWEgaXR1LCB0ZXRhcGkganVnYSBtZW5ndXJhbmdpIHdha3R1IHlhbmcga2l0YSBoYWJpc2thbiB1bnR1ayBtZWxha3VrYW4gcHJvc2VzIEdyaWRTZWFyY2ggKFBlbnlldGVsYW4gSHlwZXJwYXJhbWV0ZXIuKQ0KDQoNCkJlcmlrdXQgbGFuZ2thaC1sYW5na2FoIHVudHVrIG1lbmdpbXBsZW1lbnRhc2lrYW4gIEgybzoNCjx1bD4NCjxsaT4qKk1lbmdpbXBvciBIMm8qKiA8L2xpPg0KPGxpPioqUGlzYWhrYW4gZGF0YWZyYW1lICoqIDwvbGk+DQo8bGk+KipQaWxpaCBtb2RlbG55YSAqKiA8L2xpPg0KPGxpPioqRXZhbHVhc2kgbWV0cmlrIGtpbmVyamE6KiogPC9saT4NCjwvdWw+DQoNCiMjIyBNZW5naW1wb3IgSDJvDQoNCmBgYHtyfQ0KDQojIENhbGwgSDJvDQpoMm8uaW5pdCgpDQoNCg0KYGBgDQoNCg0KIyMjICBQZW1pc2loYWFuIEgybyBEYXRhZnJhbWUgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCg0Kc2V0LnNlZWQoMTIzNCkNCg0KZGYgPC0gZGYgJT4lIA0KICBtdXRhdGUoDQogICAgYXR0cml0aW9uX2ZsYWcgPSBhdHRyaXRpb25fZmxhZyAlPiUgYXNfZmFjdG9yKCkNCiAgKQ0KDQoNCg0KIyBTcGxpdCBvZiB0aGUgZGF0YWZyYW1lDQpzcGxpdHMgPC0gaW5pdGlhbF9zcGxpdCgNCiAgZGF0YSA9IGRmLA0KICBwcm9wID0gMC44MA0KKQ0KDQoNCnRyYWluX3RibCA8LSB0cmFpbmluZyhzcGxpdHMpDQp0ZXN0X3RibCA8LSB0ZXN0aW5nKHNwbGl0cykNCg0KDQpyZWNpcGVfYmFzZSA8LSByZWNpcGUoYXR0cml0aW9uX2ZsYWcgfiAuLCBkYXRhID0gdHJhaW5fdGJsKSAlPiUgDQogIHN0ZXBfenYoYWxsX3ByZWRpY3RvcnMoKSkgJT4lIA0KICBwcmVwKCkNCg0KDQpzcGxpdF9oMm9fZnJhbWUgPC0gaDJvLnNwbGl0RnJhbWUoYXMuaDJvKHRyYWluX3RibCksIHJhdGlvcyA9IGMoMC44KSwgc2VlZD0xMjM0KQ0KDQp0cmFpbl9oMm8gPC0gc3BsaXRfaDJvX2ZyYW1lW1sxXV0NCnZhbF9oMm8gPC0gc3BsaXRfaDJvX2ZyYW1lW1syXV0NCnRlc3RfaDJvIDwtIGFzLmgybyh0ZXN0X3RibCkNCg0KDQp5IDwtICJhdHRyaXRpb25fZmxhZyINCnggPC0gc2V0ZGlmZihuYW1lcyh0cmFpbl9oMm8pLCB5KQ0KDQoNCmBgYA0KDQoNCg0KIyMjIEF1dG9NTA0KDQpEaWJhZ2lhbiBpbmkga2l0YSBha2FuIG1lbmdpbXBsZW1lbnRhc2lrYW4gQXV0b01MIGRhcmkgc2VyYW5na2FpYW4gbW9kZWwuIEF1dG9NTCBhZGFsYWgga2VyYW5na2Ega2VyamEgeWFuZyBtZW1iYW50dWthbWkgbWVueWVyZGVyaGFuYWthbiBwZW5lcmFwYW4gbW9kZWwgcGVtYmVsYWphcmFuIE1lc2luLiBsYW5na2FoIC0gbGFuZ2thaCBwZW1vcmVzZXNhbiwgcGVueWV0ZWxhbiBoeXBlcnBhcmFtZXRlciBkaSBhbnRhcmEgYXNwZWsgLSBhc3BlayBsYWluIGRhcmkgYWx1ciBwZW1iZWxhamFyYW4gbWVzaW4uIGthbWkgYWthbiBtZW5lcmFwYWthbiBsYW5na2FoIC0gbGFuZ2thaCBiZXJpa3V0IDxicj4NCg0KPHVsPiANCjxsaT4qKk1lbmVyYXBrYW4gc2VyYW5na2FpYW4gbW9kZWwgZGFuIG1lbmVudHVrYW4gbW9kZWwgbWFuYSB5YW5nIHRlcmJhaWsgdW50dWsgZGlndW5ha2FuLioqIDwvbGk+DQo8bGk+KipFdmFsdWFzaSBtb2RlbCBkZW5nYW4gcGxvdCBwZW5hcmlrYW4gdnMgcHJlc2lzaSBkYW4gcGxvdCBST0MqKiA8L2xpPg0KPC91bD4NCg0KPGJyPg0KDQoNCg0KDQoqKk1vZGVsIHRlcmF0YXMgeWFuZyBrYW1pIGRhcGF0a2FuIHNlbXVhbnlhIGFkbGFhaCBtb2RlbCBHcmFkaWVudCBCb29zdGluZyBkZW5nYW4gcGFyYW1ldGVyIGJlcmJlZGEuKioNCg0KDQoNCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCg0KDQphdXRvbWxfbW9kZWxzX2gybyA8LSBoMm8uYXV0b21sKA0KICB4ID0geCwNCiAgeSA9IHksDQogIHRyYWluaW5nX2ZyYW1lID0gdHJhaW5faDJvLCANCiAgdmFsaWRhdGlvbl9mcmFtZSA9IHZhbF9oMm8sDQogIGxlYWRlcmJvYXJkX2ZyYW1lID0gdGVzdF9oMm8sDQogIG1heF9tb2RlbHMgPSAxMCwNCiAgYmFsYW5jZV9jbGFzc2VzID0gVFJVRSwNCiAgbmZvbGRzID0gNSwNCiAgc2VlZCA9IDEyMzQsDQogIGV4Y2x1ZGVfYWxnb3MgPSBjKCJEZWVwTGVhcm5pbmciKQ0KKQ0KDQoNCg0KYGBgDQoNCg0KDQpgYGB7ciB2aXN1YWxpemVfbGVhZGVyYm9hcmR9DQoNCmxlYWRlcmJvYXJkX2RhdGEgPC0gYXV0b21sX21vZGVsc19oMm9AbGVhZGVyYm9hcmQgJT4lIA0KICBhc190aWJibGUoKSAlPiUgDQogIG11dGF0ZSgNCiAgICAjIFRha2VzIHRoZSBmaXJzdCBwYXJ0IGJlZm9yZSB0aGUgdW5kZXJzY29yZQ0KICAgIG1vZGVsX3R5cGUgPSBzdHJfc3BsaXQobW9kZWxfaWQsICJfIiwgc2ltcGxpZnkgPSBUKVssMV0NCiAgKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKCkgJT4lIA0KICBtdXRhdGUoDQogICAgbW9kZWxfaWQgPSBtb2RlbF9pZCAlPiUgYXNfZmFjdG9yKCkgJT4lIGZjdF9yZW9yZGVyKGF1YyksDQogICAgbW9kZWxfdHlwZSA9IG1vZGVsX3R5cGUgJT4lIGFzX2ZhY3RvcigpDQogICkgJT4lIA0KICBzZWxlY3Qocm93bmFtZSwgbW9kZWxfaWQsIG1vZGVsX3R5cGUsIGV2ZXJ5dGhpbmcoKSkgJT4lIA0KICBwaXZvdF9sb25nZXIoNDo5KSAlPiUgDQogIG11dGF0ZSgNCiAgICBtb2RlbF9pZCA9IHBhc3RlMChyb3duYW1lLCAiLiAiLCBtb2RlbF9pZCkgJT4lIGFzX2ZhY3RvcigpICU+JSBmY3RfcmV2KCkNCiAgKSAlPiUgDQogIGZpbHRlcihuYW1lICVpbiUgYygiYXVjIiwgImxvZ2xvc3MiKSkNCg0KDQoNCmxlYWRlcmJvYXJkX2RhdGEgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9dmFsdWUsIHk9bW9kZWxfaWQsIGNvbG9yID0gbW9kZWxfdHlwZSkpICsgDQogIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSBtb2RlbF9pZCwgeGVuZCA9IHZhbHVlLCB5ZW5kID0gbW9kZWxfaWQpLCBjb2xvciA9ICJncmV5NTAiKSArDQogIGdlb21fcG9pbnQoc2l6ZT0zKSArIGZhY2V0X3dyYXAofiBuYW1lLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICBzY2FsZV9jb2xvcl9uZWptKCkgKyBjdXN0b21fdGhlbWUgKyANCiAgZ2VvbV9sYWJlbChhZXMobGFiZWwgPSByb3VuZCh2YWx1ZSwgMiksIGhqdXN0ID0gImlud2FyZCIpLCBzaXplID0gMykgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBhcGFuIFBlcmlua2F0IE1vZGVsIiwNCiAgICBzdWJ0aXRsZSA9IHBhc3RlMCgiRGkgdXJ1dGthbiBvbGVoOiBhdWMiKQ0KICApDQoNCmBgYA0KDQoNCiMjIyBNZXRyaWsgS2luZXJqYSANCg0KUHJlY2VzaW9uIGRhbiByZWNhaWwgYWRhbGFoIG1ldHJpeCB5YW5nIHVtdW0gZGlndW5ha2FuIHVudHVrIG1hc2FsYWgga2xhZmlrYXNpLiBpbmkgYWthbiBtZW11bmdraW5rYW4ga2FtaSB1bnR1ayBtZW5nZXZhbHVzYWkga2luZXJqYSBtb2RlbCBrYW1pIGRlbmdhbiBsZWJpaCBiYWlrLiBTZWxhanV0bnlhIGRhbGFtIGhhbCBpbmkgYWthbiBkaWd1YW5ha2FuIG1vZGVsIHBlcmZvcm1hc2lueWEgcGFsaW5nIGJhaWsgeWFpdHUgbW9kZWwgKipHQk1fM19BVVRPTUwqKiBOYW11biBkaSBtdW5na2lua2FuIHVudHVrIG1lbmdldmFsdWFzaSBsZWJpaCBkYXJpIHNhdHUgbW9kZWwgcGFkYSBzYWF0IHlhbmcgc2FtYSB0ZXRhcGkgdW50dWsgbWVuamFnYSBzZW11YW55YSB0ZXRhcCBzZWRlcmhhbmEgZGFsYW0gcHJveWVrIGluIGkgc2F5YSBoYW55YSBtZW5nZ3VuYWthbiBzYXR1IG1vZGVsLg0KDQoNCg0KPHVsPg0KPGxpPioqUHJlc2lzaToqKiBJbmkgYWRhbGFoIHJhc2lvIHBvc2l0aWYgc2VqYXRpIHRlcmhhZGFwIHNlbXVhIHBvc2l0aWYuIERhbGFtIGhhbCBpbmksIHBvc2l0aWYgYWthbiBtZW5qYWRpIHBlbGFuZ2FuIG1lbmluZ2dhbGthbiBLYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbi4gQmVuYXIgcG9zaXRpZiBha2FuIG1lbmphZGkgcHJlZGlrc2kgeWFuZyBiZW5hciBvbGVoIG1vZGVsIGthbWkgYmFod2EgcGVsYW5nZ2FuIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rIGRhbiBwb3NpdGlmIHBhbHN1IGFrYW4gbW9kZWwga2FtaSBzYWxhaCBiYWh3YSBwZWxhbmdnYW4gYWthbiBwZXJnaS4gICA8L2xpPg0KPGxpPioqUGVuYXJpa2FuIEtlbWJhbGk6KiogQWRhbGFoIE1ldHJpeCBtb2RlbCBrYW1pIHlhbmcgbWVuZ2lkZW50aWZpa2FzaSBkZW5nYW4gYmVuYXIgcG9zaXRpZiBzZWphdGkgKGRlbmdhbiBrYXRhIGxhaW4gcGVsYW5nZ2FuIG1lbmluZ2dsYWthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rLikgUGVuYXJpa2FuIHBhZGEgZGFzYXJueWEgYWRhbGFoIHJhc2lvIGJlcmFwYSBiYW55YWsgcGVsYW5nZ2FuIHlhbmcgZGlwcmVkaWtzaSBtb2RlbCBrYW1pIGRlbmdhbiBiZW5hciBkYXJpIHRvdGFsIHBlbGFuZ2dhbiBkaSBkYWxhbSBwZXJ1c2FoYWFuIGJhbmsgdGVyc2VidXQuIDwvbGk+DQo8bGk+KipSZWNpdmVyIE9wZXJhdGluZyBDaGFyYWN0ZXJpc3RpYyAoUk9DKSBkYW4gQXJlYSBVbmRlciBDb3ZlcjogKiogUk9DIGFkYWxhaCBrdXJ2YSBwcm9iYWxpdGFzIHlhbmcgbWVuZ3VrdXIgc2ViZXJhcGEgYmVuYXIgbW9kZWwgaW5pIGRhcGF0IG1lbXByZWRpa3NpIGhhc2lsIHlhbmcgYmVuYXIgc2VtZW50YXJhIEFVQyAoTWVuZGFrYXRpIDEpIHNlbWFraW4gYmFpayBtb2RlbC4gIDwvbGk+DQo8L3VsPg0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpsZWFkZXJfbW9kZWwgPC0gYXV0b21sX21vZGVsc19oMm9AbGVhZGVyDQoNCg0KIyBLYW1pIGFrYW4gbWVuZ2FuYWxpc2lzIG1vZGVsIGluaSB5YW5nIG1lcnVwYWthbiBtb2RlbCBwZW1pbXBpbi4NCnBlcmZvcm1hbmNlX2gybyA8LSBoMm8ucGVyZm9ybWFuY2UobGVhZGVyX21vZGVsLCBuZXdkYXRhID0gYXMuaDJvKHRlc3RfdGJsKSkNCg0KYGBgDQoNCg0KDQoNCmBgYHtyIHBlcmZvcm1hbmNlX21ldHJpY3N9DQoNCg0KDQoNCm1ldHJpY3NfdGJsIDwtIHBlcmZvcm1hbmNlX2gybyAlPiUgDQogIGgyby5tZXRyaWMoKSAlPiUgDQogIGFzX3RpYmJsZSgpDQoNCg0KDQoNCnByX3Bsb3QgPC0gbWV0cmljc190YmwgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9dGhyZXNob2xkKSkgKyANCiAgZ2VvbV9saW5lKGFlcyh5PXByZWNpc2lvbiksIGNvbG9yID0gIiNGMjREMjkiLCBzaXplPTEpICsgDQogIGdlb21fbGluZShhZXMoeT1yZWNhbGwpLCBjb2xvciA9ICIjMURBQ0U4Iiwgc2l6ZT0xKSArIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBoMm8uZmluZF90aHJlc2hvbGRfYnlfbWF4X21ldHJpYyhwZXJmb3JtYW5jZV9oMm8sICJmMSIpLA0KICAgICAgICAgICAgIGx0eT0iZGFzaGVkIikgKyANCiAgY3VzdG9tX3RoZW1lICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUHJlc2lzaSBEaWJhbmRpbmdrYW4gTWVuaWdnYXQgS2VtYmFsaSINCiAgKQ0KDQoNCmBgYA0KDQoNCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTR9DQoNCnJvY190YmwgPC0gcGVyZm9ybWFuY2VfaDJvICU+JSANCiAgaDJvLm1ldHJpYygpICU+JSANCiAgYXNfdGliYmxlKCkgJT4lIA0KICBtdXRhdGUoDQogIGF1YyA9IGgyby5hdWMocGVyZm9ybWFuY2VfaDJvKQ0KICApICU+JSANCiAgc2VsZWN0KHRwciwgZnByLCBhdWMpDQoNCg0Kcm9jX3Bsb3QgPC0gcm9jX3RibCAlPiUgDQogIGdncGxvdChhZXMoZnByLCB0cHIpKSArIA0KICBnZW9tX2xpbmUoY29sb3IgPSAiI0YyNEQyOSIsIHNpemU9MSkgKw0KICBnZW9tX2FibGluZSgpICsNCiAgY3VzdG9tX3RoZW1lICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUk9DIFBsb3QiDQogICkNCg0KcGxvdF9ncmlkKHByX3Bsb3QsIHJvY19wbG90LCBuY29sID0gMikNCg0KYGBgDQoNCg0KDQojIyBNZW1haGFtaSBQZW50aW5nbnlhIEZJdHVyIA0KDQpTZWthcmFuZyBzYWF0bnlhIHVudHVrIGxlYmloIG1lbWFoYW1pIG1vZGVsIGtpdGEsIEthbWkgaW5naW4gbWVtYWhhbWkgZmFrdG9yIGFwYSB5YW5nIG1lbmRvcm9uZyBtb2RlbCBrYW1pIHVudHVrIG1lbWJ1YXQgcHJlZGlrc2kgdGVydGVudHUuIERhbGFtIGhhbCBpbmkgZmFrdG9yLWZha3RvciBhcGEgeWFuZyBtZW1idWF0IG1vZGVsIGtpdGEgbWVuZW50dWthbiBhcGFrYWggc2VzZW9yYW5nIHBlbGFuZ2dhbiBha2FuIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rPyBVbnR1ayBpdHUgLCBraXRhIHBlcmx1IG1lbWFoYW1pIGZpdHVyIG1hbmEgeWFuZyBwZW50aW5nIHVudHVrIG1vZGVsIGtpdGEuIA0KDQo8YnI+PGJyPg0KDQo8dWw+DQo8bGk+KipGaXR1ciBQZW50aW5nOioqIEZpdHVyIGluaSBtb2RlbCBrYW1pIGFrYW4gbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIHRlcnRlbnR1OiAqKkp1bWxhaCBUb3RhbCBUcmFuc2Frc2kgSnVtbGFoIHRvdGFsIHRyYW5zYWtzaSBkYW4gdG90YWwgc2FsZG8gYmVyZ3VsaXIuKiogPC9saT4NCjxsaT4qKkp1bWxhaCB0b3RhbCB0cmFuc2Frc2k6ICoqIEtldGlrYSBqdW1sYWggdG90YWwgdHJhbnNha3NpIGxlYmloIHJlbmRhaCBkYXJpIDQ1IHRyYW5zYWtzaSwga2VtdW5na2luYW4gYmVzYXIgcGVsYW5nZ2FuIGFrYW4gbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmsuIDwvbGk+DQoNCjwvdWw+DQoNCg0KDQpgYGB7ciBsaW1lX2ltcGxlbWVudGF0aW9ufQ0KDQoNCg0KDQoNCmZpX3Bsb3QgPC0gdmlwKGxlYWRlcl9tb2RlbCkgKyANCiAgY3VzdG9tX3RoZW1lICsgZ2VvbV9jb2woZmlsbD0iI0YyNEQyOSIsIGNvbG9yPSJibGFjayIpICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRmVhdHVyZSBJbXBydGFuY2UiLA0KICAgIGNhcHRpb24gPSAiV2hpY2ggZmVhdHVyZSBvdXIgbW9kZWwgY29uc2lkZXJzIGltcG9ydGFudCINCiAgKSANCg0KDQoNCg0KZmlfcGxvdA0KDQoNCg0KYGBgDQoNCg0KYGBge3J9DQoNCmgyby5ub19wcm9ncmVzcygpDQoNCnRvdGFsX3RyYW5zX3Bsb3QgPC0gaDJvLnBhcnRpYWxQbG90KGxlYWRlcl9tb2RlbCwgZGF0YSA9IGFzLmgybyh0cmFpbl90YmwpLCBjb2xzID0gInRvdGFsX3RyYW5zX2N0IikNCg0KDQpgYGANCg0KDQoNCg0KDQojIyMgRml0dXIgQXBhIHlhbmcgcGFsaW5nIE1lbXBlbmdhcnVoaSBBdHJpc2k/DQoNCkRhbGFtIGhhbCBpbmkga2FtaSBha2FuIG1lbmdndW5ha2FuIHBha2V0ICoqTGltZSoqIFlhbmcgbWVtYmFudHUga2FtaSBtZW1haGFtaSBmaXR1ci1maXR1ciB5YW5nIGRpYW5nYXAgcGVudGluZyBvbGVoIG1vZGVsIGthbWkuIE5hbXVuIGthbWkgYWthbiBtZW5nZWtzcGxvcmFzaSBwZW5nYW1hdGFuIHR1bmdnYWwgZGltYW5hIHBlbGFuZ2dhbiBtZW11dHVza2FuIHVudHVrIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgcGVydXNhaGFhbiBkaSBiYW5rLiA8YnI+PGJyPg0KDQo8dWw+DQo8bGk+KipKdW1sYWggVG90YWwgVHJhbnNha3NpOioqIEtldGlrYSBqdW1sYWggdG90YWwgdHJhbnNha3NpIGRhcmkgNDUga2l0YSBtZWxpaGF0IGJhaHdhIGFkYSBrZW11bmdraW5hbiBsZWJpaCBiZXNhciBiYWh3YSBpbmRpdmlkdSBha2FuIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rLiA8L2xpPg0KPGxpPioqUGVsYW5nZ2FuIHlhbmcgYmVydXRhbmcgbGViaWggc2VkaWtpdCBrZXBhZGEgaW5zdGl0dXNpOioqIFBlbGFuZ2dhbiB5YW5nIG1lbWlsaWtpIHNhbGRvIGJlcmd1bGlyIGxlaWJoIHJlbmRhaCBtZW1pbGlraSBwZWx1YW5nIGxlYmloIGJlc2FyIHVudHVrIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBkaSBiYW5rLiBpbmkgYWRhbGFoIHNlc3VhdHUgeWFuZyBtZW5hcmlrIGthcmVuYSB5YW5nIGluZ2luIGtpdGEgbWlsaWtpIGFkYWxhaCBwZWxhbmdnYW4geWFuZyBiZXJ1dGFuIGxlYmloIGRhcmkgc2VkaWtpdCBrZXBhZGEgaW5zdGl0dXNpLiA8L2xpPg0KDQo8L3VsPg0KDQo8YnI+PGJyPg0KDQoqKkNhdGF0YW4qKiBQZW5nYW1hdGFuIGtlIC00IGFkYWxhaCBwcmVkaWtzaSB5YW5nIHNhbGFoIGRpc2lzaSBtb2RlbCBrYW1pLiBTZXBlcnRpbnlhIGluaSBhZGFsYWggcGVuZ2VjdWxpYW4gbWVza2lwdW4gbWVtaWxpa2kgc2VtdWEga2FyZWt0ZXJpc3RpayB5YW5nIG1lbmVydXQgbW9kZWwga2FtaSBwZW50aW5nIHVudHVrIG1lbXBlcnRpbWJhbmdrYW4gYmFod2EgcGVsYW5nZ2FuIGFrYW4gbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmsuDQoNCmBgYHtyIGZpZy5oZWlnaHQ9Nn0NCg0KaDJvLm5vX3Byb2dyZXNzKCkNCg0KZXhwbGFpbmVyIDwtIHRyYWluX3RibCAlPiUNCiAgICBzZWxlY3QoLWF0dHJpdGlvbl9mbGFnKSAlPiUNCiAgICBsaW1lKA0KICAgICAgICBtb2RlbCAgICAgICAgICAgPSBsZWFkZXJfbW9kZWwsDQogICAgICAgIGJpbl9jb250aW51b3VzICA9IFRSVUUsDQogICAgICAgIG5fYmlucyAgICAgICAgICA9IDQsDQogICAgICAgIHF1YW50aWxlX2JpbnMgICA9IFRSVUUNCiAgICApDQoNCg0KIyBGaXR1ciBub21vciA0IGFkYWxhaCBwcmVkaWtzaSB5YW5nIHNhbGFoIQ0KDQpleHBsYW5hdGlvbiA8LSB0ZXN0X3RibCAlPiUNCiAgICBmaWx0ZXIoYXR0cml0aW9uX2ZsYWcgPT0gIkF0dHJpdGVkIEN1c3RvbWVyIikgJT4lDQogIHNsaWNlKDE6NCkgJT4lIA0KICAgIHNlbGVjdCgtYXR0cml0aW9uX2ZsYWcpICU+JQ0KICAgIGxpbWU6OmV4cGxhaW4oDQogICAgICAgIGV4cGxhaW5lciA9IGV4cGxhaW5lciwNCiAgICAgICAgbl9sYWJlbHMgICA9IDEsDQogICAgICAgIG5fZmVhdHVyZXMgPSA4LA0KICAgICAgICBuX3Blcm11dGF0aW9ucyA9IDUwMDAsDQogICAgICAgIGtlcm5lbF93aWR0aCAgID0gMQ0KICAgICkNCg0KDQpwbG90X2ZlYXR1cmVzKGV4cGxhbmF0aW9uID0gZXhwbGFuYXRpb24pDQoNCg0KDQpgYGANCg0KDQpEYWxhbSBwbG90IGluaSBraXRhIGRhcGF0IG1lbGloYXQgYmFod2EgdHJlbiBiZXJsYW5qdXQgZGVuZ2FuIGVtcGF0IHBlbmdhbWF0YW4sIGphZGkga2l0YSBtZWxpaGF0IGJhaHdhIHVudHVrIHRpZ2EgdHJlbiBwZXJ0YW1hIGtpdGEgbWVsaWhhdCBhZGEga29uc2lzdGVuc2kgZGFuIHBvbGEuIGthbWkganVnYSBkYXBhdCBtZW5jb2JhIG1lbmdla3NwbG9yYXNpIHBlbmdhbWF0YW4geWFuZyBiZXJiZWRhIGRhcmkgcGVsYW5nZ2FuIHlhbmcgdGVydGFyaWsgdW50dWsgbWVsaWhhdCBhcGFrYWggcG9sYSBpbmkgYmVybGFuanV0IGRlbmdhbiBpbmkgYW5kYSBtZW55aW1wdWxrYW4gYmFod2EgaW5pIGFkYWxhaCBmaXR1ciB5YW5nIGRpcGFoYW1pIG1vZGVsIGthbWkgeWFuZyBwZW50aW5nIGRhbGFtIG1lbmVudHVrYW4gYXBha2FoIHBlbGFuZ2dhbiBha2FuIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rLiANCg0KDQoNCg0KYGBge3J9DQoNCnBsb3RfZXhwbGFuYXRpb25zKGV4cGxhbmF0aW9uID0gZXhwbGFuYXRpb24pDQoNCmBgYA0KDQoNCg0KIyMjIE1lbmFmc2lya2FuIENvbmZ1c2lvbiBNYXRyaXgNCg0KDQoNClBhZGEgYmFnaWFuIGluaSBrYW1pIGFrYW4gbWVuamVsYXNrYW4ga29uc2VwIHlhbmcgZGlwZXJsdWthbiB1bnR1ayBtZW5naW50ZXJ0YXNpa2FuIG1hdHJpayBkYXJpIG1hc2FsYWgga2xhc2Zpa2FzaS4gVHVqdWFueWEgYWRhbGFoIHVudHVrIG1lbWFoYW1pIGFwYWthaCBtb2RlbCBraXRhIGJpc2EgbWVuZGFwYXRrYW4NCjx1bD4NCjxsaT4qKk5lZ2F0aWYgVHJ1ZToqKiBJbmkgYmVhcnRpICoqbW9kZWwqKiBrYW1pIG1lbXByZWRpa3NpIHBlbGFuZ2dhbiBrYW1pIGFrYW4gdGluZ2dhbCBkYW4gdGlkYWsgYWthbiBtZW5pbmdnYWxrYW4ga2FydHUga3JlZGl0IGRpIHBlcnVzYWhhYW4gYmFuayB5YW5nIGJlcmFydGkgaW5pIGFkYWxhaCBqdW1sYWggcHJlZGlrc2kgeWFuZyBiZW5hciBkYXJpIG1vZGVsIGthbWkuICA8L2xpPg0KPGxpPioqUG9zaXRpZiBGYWxzZTogKiogTW9kZWwga2FtaSBtZW1wcmVkaWtzaSBiYWh3YSBwZWxhbmdnYW4gYWthbiBtZW5pbmdnYWxrYW4ga2FydHUga3JlZGl0IGRpIHBlcnVzYWhhYW4gYmFuaywgbmFtdW4gcGVsYW5nZ2FuIHRldGFwIHRpbmdnYWwuIDwvbGk+DQo8bGk+KipOZWdhdGlmIEZhbHNlOioqIE1vZGVsIGthbWkgbWVtcHJlZGlrc2kgYmFod2EgcGVsYW5nZ2FuIGFrYW4gdGV0YXAgYmVyYWFkYSBkaSBrYXJ0dSBrcmVkaXQgcGVydXNhaGFhbiBiYW5rLCBuYW11biBwZWxhbmdnYW4gbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmsuIGluaSBtZW1pbGlraSBkYW1wYWsgbmVnYXRpZiBiZXNhciB1bnR1ayBrYXN1cyBpbmkuIDwvbGk+DQo8L3VsPioqVHJ1ZSBQb3NpdGlmOioqIE1vZGVsIGthbWkgbWVtcHJlZGlrc2kgcGVsYW5nZ2FuIGFrYW4gbWVuaW5nZ2xha2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmsuIEFydGlueWEgbW9kZWwga2FtaSBkYXBhdCBkYXBhdCBtZW1wcmVkaWtzaSBkZW5nYW4gYmVuYXIga2FwYW4gbW9kZWwgbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2hhYW4gYmFuay4gPC9saT4NCg0KDQo8YnI+DQoqKkNhdGF0YW46KiogQW5kYSBqdWdhIGhhcnVzIG1lbGloYXQgaW1wbGlrYXNpIGJpc25pcyBQb3NpdGlmIEZhbHNlIG1laWxpa2kgZGFtcGFrIHlhbmcgcmVuZGFoIHRlcmhhZGFwIGthcnR1IGtyZWRpdCBkaSBwZXJ1c2FoYWFuIGJhbmsgZGliYW5kaW5na2FuIGRuZWduYSBOZWdhdGlmIEZhbHNlIA0KDQoNCg0KDQoNCmBgYHtyfQ0KDQptZXRyaWNzX2gybyA8LSBsZWFkZXJfbW9kZWwgJT4lIA0KICBoMm8ucGVyZm9ybWFuY2UobmV3ZGF0YSA9IHRlc3RfaDJvKQ0KDQoNCnByZWRpY3Rpb25zX3RibCA8LSBsZWFkZXJfbW9kZWwgJT4lIA0KICBoMm8ucHJlZGljdChuZXdkYXRhID0gdGVzdF9oMm8pICU+JQ0KICBhc190aWJibGUoKSAlPiUgDQogIGJpbmRfY29scyh0ZXN0X2gybyAlPiUgYXNfdGliYmxlKCkpDQoNCg0KDQpwcmVkaWN0aW9uc190YmwgJT4lIA0KICBzZWxlY3QoMTo0KSAlPiUgDQogIGNvbmZfbWF0KGF0dHJpdGlvbl9mbGFnLCBwcmVkaWN0KSAlPiUgDQogIHBsdWNrKDEpICU+JSANCiAgYXNfdGliYmxlKCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9UHJlZGljdGlvbiwgeT1UcnV0aCwgZmlsbD1uKSkgKw0KICBnZW9tX3RpbGUoc2hvdy5sZWdlbmQgPSBGLCBhbHBoYT0wLjUpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1uKSwgY29sb3I9ImJsYWNrIiwgYWxwaGE9MSwgc2l6ZT04KSArIA0KICBzY2FsZV9maWxsX2dzZWEoKSsgDQogIGN1c3RvbV90aGVtZSArIA0KICBsYWJzKA0KICAgIHRpdGxlID0gIkNvbmZ1c2lvbiBNYXRyaXgiDQogICkNCg0KDQpgYGANCg0KDQojIyMgQW1iYW5nIEJhdGFzDQoNCktvbnNlcCBhbWJhbmcgYmF0YXMgcGVudGluZyBrZXRpa2Ega2l0YSBzYW1wYWkgcGFkYSBtYXNhbGFoIGtsYWZpa2FzaS4gZGFsYW0gaGFsIGluaSBrYW1pIG1lbnVuanVra2FuIGtpbmVyamEgYW1iYW5nIGJhdGFzIHlhbmcgYmVyYWRhIGRpIGJlcmJhZ2FpIHRpbmdha3Rhbi4gKipUYXJpZiBOZWdhdGlmIEJlbmFyIGRhbiBUYXJpZiBQb3NpdGlmIEZhbHNlIFNlcnRhIHRhcmlmIG5lZ2F0aWYgRmFsc2UgZGFuIFRhcmlmIFBvc2l0aWYgVHJ1ZSBha2FuIHNlbGFsdSBiZXJ0YW1iYWggbWVuamFkaSAxKiouIFNhYXQgYW1iYW5nIGJhdGFzIG1lbmluZ2thdCwgc2VtYWtpbiBwcmVzaXNpIG1vZGVsIGthbWkgc2FhdCBtZW5lbnR1a2FuIGFwYWthaCBwZWxhbmdnYW4gYWthbiBtZW5pbmdnYWxrYW4gS2FydHUgS3JlZGl0IGRpIHBlcnVzYWhhYW4gYmFuay4gDQoNCg0KDQpgYGB7cn0NCg0KDQpuZXdfcGVyZm9ybWFuY2VfaDJvIDwtIGxlYWRlcl9tb2RlbCAlPiUgDQogIGgyby5wZXJmb3JtYW5jZShuZXdkYXRhID0gdGVzdF9oMm8pDQoNCg0KcmF0ZXNfYnlfdGhyZXNob2xkIDwtIG5ld19wZXJmb3JtYW5jZV9oMm8gJT4lIA0KICBoMm8ubWV0cmljKCkgJT4lIA0KICBhc190aWJibGUoKQ0KDQoNCg0KDQpyYXRlc19ieV90aHJlc2hvbGQgJT4lIA0KICBzZWxlY3QodGhyZXNob2xkLCBmMSwgdG5yOnRwcikgJT4lIA0KICBnYXRoZXIoa2V5ID0gImtleSIsIHZhbHVlID0gInZhbHVlIiwgdG5yOnRwciwgZmFjdG9yX2tleSA9IFRSVUUpICU+JSANCiAgbXV0YXRlKA0KICAgIGtleSA9IGZjdF9yZW9yZGVyMihrZXksIHRocmVzaG9sZCwgdmFsdWUpDQogICkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9dGhyZXNob2xkLCB2YWx1ZSwgY29sb3I9a2V5KSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKCkgKyANCiAgY3VzdG9tX3RoZW1lICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpICsgDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUmF0ZXMiLA0KICAgIHkgPSAiVmFsdWUiLCANCiAgICB4ID0gIlRocmVzaG9sZCINCiAgKQ0KDQoNCg0KDQpgYGANCg0KDQojIyBTdGFydGVnaSB1bnR1ayBNZW5ndXJhbmdpIEF0cmlzaSBQZWxhbmdnYW4gDQoNCg0KDQoNCjxpbWcgc3JjPSJodHRwczovL3d3dy5wb2ludGlsbGlzdC5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTcvMTEvUnVubmluZy00LXRoZS1FeGl0LTItODQ0eDQyMi5wbmciPg0KDQoNCjx1bD4NCjxsaT4qKkZva3VzIHBhZGEga2Vsb21wb2sgYmVycGVuZ2hhc2lsYW4gcmVuZGFoOioqIE1lc2tpcHVuIGRheWEgYmVsaSB0aWRhayB0ZXJsYWx1IHNpZ25pZmlrYW4sIHNlYmFnaWFuIGJlc2FyIHBlbGFuZ2dhbiBrYW1pIGJlcmFzYWwgZGFyaSBrZWxvbXBvayByZW5kYWguIA0KTWVuZXJhcGthbiBQcm9tb3NpIHVudHVrIG1lbmd1bnR1bmdrYW4ga2VsZW1wb2sgYmVycGVuZ2hhc2lsYW4gcmVuZGFoIGRhcGF0IG1lbmphZGkgYWx0ZXJuYXRpZiB5YW5nIGJhaWsgdW50dWsgbWVuZ3VyYW5naSBjaHVybiBwZWxhbmdnYW4gZGkgYW50YXJhIGtlbG9tcG9rIGtsYXN0ZXIgdGVyc2VidXQuIDwvbGk+DQo8bGk+KipCZXJ0aW5kYWsgc2FhdCB0aW5na2F0IGFrdGl2aXRhcyByZW5kYWg6KiogS2FtaSBtZWxpaGF0IGJhaHdhIHBlbGFuZ2dhbiB5YW5nIG1lbWlsaWtpIHRpbmdhdCBha3Rpdml0YXMgbGViaWggcmVuZGFoICh0cmFuc2Frc2kgbGViaWggcmVuZGFoIGRhcmkgNDUpLCBNZW1pbGlraSBrZW11bmdraW5hbiBsZWJpaCB0aW5nZ2kgdW50dWsgbWVuaW5nZ2Fsa2FuIGthcnR1IGtyZWRpdCwgSmlrYSBrYXJ5YXdhbiBiYW5rIG1lbWFuZ2dpbCBwZWxhbmdnYW4gZGVuZ2FuIHRpbmdha3QgYWt0aXZpdGFzIHlhbmcgbGViaWggcmVuZGFoIHVudHVrIG1lbmF3YXJrYW4gcHJvZHVrIGJhcnUgdW50dWsga2VidXR1aGFuIG1lcmVrYSBhdGF1IHVudHVrIG1lbmF5YWthbiBhcGFrYWggcGVsYW5nZ2FuIHNlbmFuZyBkZW5nYW4gbGF5YW5hbiB5YW5nIGthbWkgYmVyaWthbiBkYW4gamlrYSBhZGEgc2VzdWF0dSB5YW5nIGRhcGF0IGthbWkgbGFrdWthbiB1bnR1ayBtZW5pbmdrYXRrYW4sIGthbWkgbXVuZ2tpbiB1bnV0ayBtZW5pbmdrYXRrYW4sIGthbWkgbXVuZ2tpbiBha2FuIG1lbmRhcGF0a2FuIHdhd2FzYW4geWFuZyBsZWJpaCBiYWlrIHRlbnRhbmcgYXBhIGRhcGF0IGtpdGEgbGFrdWthbiB1bnR1ayBtZW5pbmdrYXRrYW4gdGluZ2thdCBha3Rpdml0YXMuIDwvbGk+DQo8bGk+KipUaW5na2F0IGJhdGFzIGtyZWRpdCB1bnR1ayBtZXJla2EgeWFuZyBtZW1pbGlraSBzYWxkbyBiZXJndWxpciBsZWJpaCByZW5kYWg/KiogTWVudXJ1dCBtb2RlbCBrYW1pLCBwZWxhbmdnYW4gZGVuZ2FuIHNhbGRvIGJlcmd1bGlyIHlhbmcgbGViaWggcmVuZGFoIGxlaWJoIGNlbmRlcnVuZyBtZWluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBiYW5rLiBNdW5na2luIGRlbmdhbiBtZW5lcmFwa2FuIHNhbGRvIGtyZWRpdCB5YW5nIGxlYmloIHRpbmdnaSBrZXBhZGEgcGVsYW5nZ2FuIHRlcnNlYnV0Liwga2VtdW5na2luYW4ga2VsZW1wb2sgc2VnbWVuIHRlcnNlYnV0IHVudHVrIG1lbmluZ2dhbGthbiBrYXJ0dSBrcmVkaXQgZGkgcGVydXNhaGFhbiBkYXBhdCBkaSB0dXJ1bmthbi48L2xpPg0KDQo8L3VsPg0KDQoNCkRhbiBoYW55YSBpdHUsIHNheWEgaGFyYXAgYW5kYSBtZW55dWthaSBwcm95ZWsgaW5pIGRhbiBtYXNpaCBwcm9zZXMgYmVsYWphci4gDQoNCg0K