Deskripsi

Analysis Kepribadian Pelanggan adalah Analysis terperinci tentang pelanggan ideal di perusahaan. Ini membantu bisnis untuk lebih memahami pelanggannya dan memudahkan perusahaan untuk memodifikasi produk sesuai dengan kebutuhan, prilaku, dan perhatian khusus dari berbagai jenis pelanggan.

Pelanggan memiliki kepribadian yang berbeda dan tersebar di berbagai tahap saluran penjualan. Pelanggan menunjukkan kepribadian dan perilaku yang berbeda, jika perusahaan menangani berbagai jenis pelanggan dengan cara yang sama, jika perusahaan tidak mengelompokkan pelanggan secara strategis dan menaganinya dengan tepat, perusahaan pasti akan kehilangan banayak pelanggan setia dan akan mengakibatkan penghasilan perusahaan besar penjualan perusahaan. Dan penelitan menunjukkan bahwa 33% pelanggan meninggalkan merek perusahaan yang pelanggan tinggalkan hanya setelah satu pengalaman yang buruk!!.

Analysis Keperbadian Pelanggan membantu bisnis untuk memodifikasi produknya berdasarkan target pelanggan dari berbagai jenis segmen pelanggan. Misalnya alih-alih mengeluarkan uang untuk produk baru ke setiap pelanggan di database perusahaan, perusahaan dapat menganalysis segmen pelanggan mana yang paling mungkin produk dan memasarkan produk hanya pada segmen tertentu.

Data pada project ini bisa didownload : https://drive.google.com/file/d/1JAtY-zS9gLEQdq9FxrOmnEBKbciPknFm/view?usp=drivesdk

Deskripsi Kumpulan Data

Sebelum melangkah lebih jauh, saya perlu mengetahui informasi dasar dari data meliputi ukuran data, banyaknya data, dan nama-nama kolom atau variabel di dalam data.

glimpse(data)
Rows: 2,240
Columns: 29
$ ID                  <int> 5524, 2174, 4141, 6182, 5324, 7446, 965, 6177, 4855, 5899, 1994, 387, 212~
$ Year_Birth          <int> 1957, 1954, 1965, 1984, 1981, 1967, 1971, 1985, 1974, 1950, 1983, 1976, 1~
$ Education           <chr> "Graduation", "Graduation", "Graduation", "Graduation", "PhD", "Master", ~
$ Marital_Status      <chr> "Single", "Single", "Together", "Together", "Married", "Together", "Divor~
$ Income              <int> 58138, 46344, 71613, 26646, 58293, 62513, 55635, 33454, 30351, 5648, NA, ~
$ Kidhome             <int> 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0~
$ Teenhome            <int> 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1~
$ Dt_Customer         <chr> "04-09-2012", "08-03-2014", "21-08-2013", "10-02-2014", "19-01-2014", "09~
$ Recency             <int> 58, 38, 26, 26, 94, 16, 34, 32, 19, 68, 11, 59, 82, 53, 38, 23, 51, 20, 9~
$ MntWines            <int> 635, 11, 426, 11, 173, 520, 235, 76, 14, 28, 5, 6, 194, 233, 3, 1006, 53,~
$ MntFruits           <int> 88, 1, 49, 4, 43, 42, 65, 10, 0, 0, 5, 16, 61, 2, 14, 22, 5, 5, 80, 17, 2~
$ MntMeatProducts     <int> 546, 6, 127, 20, 118, 98, 164, 56, 24, 6, 6, 11, 480, 53, 17, 115, 19, 38~
$ MntFishProducts     <int> 172, 2, 111, 10, 46, 0, 50, 3, 3, 1, 0, 11, 225, 3, 6, 59, 2, 150, 0, 30,~
$ MntSweetProducts    <int> 88, 1, 21, 3, 27, 42, 49, 1, 3, 1, 2, 1, 112, 5, 1, 68, 13, 12, 16, 24, 3~
$ MntGoldProds        <int> 88, 6, 42, 5, 15, 14, 27, 23, 2, 13, 1, 16, 30, 14, 5, 45, 4, 28, 176, 39~
$ NumDealsPurchases   <int> 3, 2, 1, 2, 5, 2, 4, 2, 1, 1, 1, 1, 1, 3, 1, 1, 3, 2, 2, 2, 1, 15, 3, 3, ~
$ NumWebPurchases     <int> 8, 1, 8, 2, 5, 6, 7, 4, 3, 1, 1, 2, 3, 6, 1, 7, 3, 4, 11, 2, 4, 0, 2, 6, ~
$ NumCatalogPurchases <int> 10, 1, 2, 0, 3, 4, 3, 0, 0, 0, 0, 0, 4, 1, 0, 6, 0, 1, 4, 1, 2, 28, 3, 2,~
$ NumStorePurchases   <int> 4, 2, 10, 4, 6, 10, 7, 4, 2, 0, 2, 3, 8, 5, 3, 12, 3, 6, 9, 3, 5, 0, 9, 9~
$ NumWebVisitsMonth   <int> 7, 5, 4, 6, 5, 6, 6, 8, 9, 20, 7, 8, 2, 6, 8, 3, 8, 7, 5, 6, 8, 1, 8, 4, ~
$ AcceptedCmp3        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0~
$ AcceptedCmp4        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0~
$ AcceptedCmp5        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0~
$ AcceptedCmp1        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0~
$ AcceptedCmp2        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0~
$ Complain            <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0~
$ Z_CostContact       <int> 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3~
$ Z_Revenue           <int> 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 1~
$ Response            <int> 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0~

Tampaknya bahwa ada sebanyak 2240 baris pada data dengan variabel sebanyak 29 dan ada baiknya saya mengetahui apakah ada nilai yang kosong atau NA.

Berikut adalah Variabel singkat dari file deskripsi data

Pelanggan

Produk yang dijual Perusahaan

Promosi perusahaan kepada pelanggan

Tempat yang digunakan pelanggan

Data Clening

suatu proses mendeteksi dan memperbaiki (atau menghapus) data set, tabel, dan database yang korup atau tidak akurat. memeriksa nilai-nilai kosong yang hilang

colSums(is.na(data))
                 ID          Year_Birth           Education      Marital_Status              Income 
                  0                   0                   0                   0                  24 
            Kidhome            Teenhome         Dt_Customer             Recency            MntWines 
                  0                   0                   0                   0                   0 
          MntFruits     MntMeatProducts     MntFishProducts    MntSweetProducts        MntGoldProds 
                  0                   0                   0                   0                   0 
  NumDealsPurchases     NumWebPurchases NumCatalogPurchases   NumStorePurchases   NumWebVisitsMonth 
                  0                   0                   0                   0                   0 
       AcceptedCmp3        AcceptedCmp4        AcceptedCmp5        AcceptedCmp1        AcceptedCmp2 
                  0                   0                   0                   0                   0 
           Complain       Z_CostContact           Z_Revenue            Response 
                  0                   0                   0                   0 

Ternyata ada nilai kosong atau NA terdapat di variabel Income, untuk variabel income jika memiliki nilai yang hilang atau NA karena presenatasenya sangat kecil, maka saya harus menghapus nya atau jika nilai persentasenya sangat besar maka saya mengisi nilai yang kosong pada variabel income dengan mengisi nilai dengan imputation.

percentage.plot
Warning: Removed 28 rows containing missing values (position_stack).

Hasil dari plot diatas mengambarkan Ternayata Nilai presentasinya di variabel Income sangat kecil, maka saya harus menghapusnya.

Data Reduction

Pemilihan tentang bagian data mana yang dikode, mana yang dibuang, pola-pola mana yang diringkas sejumlah bagain tersebar data.

df1 <- na.omit(df)

Saya akan Membuat Varaibel Age untuk menghitung pelanggan dari tahun lahir pelanggan pelanggan. Ini akan lebih berguna untuk analysis saya.

df1['Age']= 2022-df1$Year_Birth
Error: object 'df1' not found

Membuat variabel Child untuk menggambungkan variabel Kidhome dan Teenhome. Untuk mengetahui Jumlah anak dan remaja didalam rumah tangga pelanggan.

print(max(df1$Dt_Customer))
[1] "31-12-2013"

Membuat Variabel total_spent untuk mengabungakan semua produk perusahaan untuk mengetahui total yang dibelanjakan pelanggan

df1['total_spent']=df1$MntMeatProducts+df1$MntFishProducts+df1$MntWines+df1$MntFruits+df1$MntSweetProducts+df1$MntGoldProds

Membuat Variabel accepted untuk mengabungakan semua kampanye perusahaan untuk mengetahui kamapanye mana yang diterima pelanggan.

names(df1)
 [1] "ID"                  "Year_Birth"          "Education"           "Marital_Status"     
 [5] "Income"              "Kidhome"             "Teenhome"            "Dt_Customer"        
 [9] "Recency"             "MntWines"            "MntFruits"           "MntMeatProducts"    
[13] "MntFishProducts"     "MntSweetProducts"    "MntGoldProds"        "NumDealsPurchases"  
[17] "NumWebPurchases"     "NumCatalogPurchases" "NumStorePurchases"   "NumWebVisitsMonth"  
[21] "AcceptedCmp3"        "AcceptedCmp4"        "AcceptedCmp5"        "AcceptedCmp1"       
[25] "AcceptedCmp2"        "Complain"            "Z_CostContact"       "Z_Revenue"          
[29] "Response"            "Age"                 "Child"               "total_spent"        
[33] "accepted"           

dari hasil diatas dapat dilihat variabel baru yaitu age, child, total_spent dan accepeted dari hasil pegabungan data variabel.

Menghapus Variabel asli Karena sekarang data ini beriisi fitur gabungan baru.

Sekarang sudah menjadi kumpulan data berisi fitur gabungan baru

Temuan Utama dalam Analysis Desriptive

Analysis desriptive dapat di kategorikan menjadi empat jenis yaitu ukuran frekunesi, tendesi sentral, despersi atau variasi, dan ukuran posisi. untuk projeck ini saya menggunakan analyis desikriptif ukuran posisi nilai tunggal atau responsny adalam kaitanya dengan nilai lain. Menggunakan deskriptive Bivariat atau Multivariat untuk mempelajari apakah ada hubungan diantara keduanya.

Anlysis Desriptive Income Customers

Hasi plot diatas mengambarkan bawa rata-rata pendapatan rata-rata Pelanggan sekitar 50000

dari plot diatas mengambarkan pendapatan pelanggan yang dibelanjakan semua produk perusahaan untuk mengetahui total yang dibelanjakan pelanggan.

Anlysis Descriptive Age Customers

Dari plot diatas mengambarkan rata-rata Age Customers 50 tahun.

Analysis Descriptive Total Spent

dari gambar diatas total_spent customers rata-rata nya sekitar 475

Data Visualisasi

eduplot
Warning: Removed 1 rows containing non-finite values (stat_boxplot).

Dari visualisasis hasil diatas bahwa pelanggan Basic tingkat pendidikan dasar memiliki pendapatan yang lebih kecil dibadingkan dengan yang lain.

mplot
Warning: Removed 1 rows containing non-finite values (stat_boxplot).
notch went outside hinges. Try setting notch=FALSE.
notch went outside hinges. Try setting notch=FALSE.

Dari visualisasis hasil diatas bahwa Martial Status Alone dan YOLO memiliki pendapatan yang lebih kecil dibadingkan dengan yang lain.

Variable Dummy

Variabel yang digunakan untuk mengkuantitatifkan variabel yang bersifat kualitatif.

Membuat variabel dummy

glimpse(dfc)
Rows: 2,216
Columns: 14
$ Marital_StatusMarried <dbl> 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0,~
$ Marital_StatusSingle  <dbl> 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,~
$ Recency               <dbl> 58, 38, 26, 26, 94, 16, 34, 32, 19, 68, 59, 82, 53, 38, 23, 51, 20, 91,~
$ NumDealsPurchases     <dbl> 3, 2, 1, 2, 5, 2, 4, 2, 1, 1, 1, 1, 3, 1, 1, 3, 2, 2, 2, 1, 15, 3, 3, 7~
$ NumWebPurchases       <dbl> 8, 1, 8, 2, 5, 6, 7, 4, 3, 1, 2, 3, 6, 1, 7, 3, 4, 11, 2, 4, 0, 2, 6, 7~
$ NumCatalogPurchases   <dbl> 10, 1, 2, 0, 3, 4, 3, 0, 0, 0, 0, 4, 1, 0, 6, 0, 1, 4, 1, 2, 28, 3, 2, ~
$ NumStorePurchases     <dbl> 4, 2, 10, 4, 6, 10, 7, 4, 2, 0, 3, 8, 5, 3, 12, 3, 6, 9, 3, 5, 0, 9, 9,~
$ NumWebVisitsMonth     <dbl> 7, 5, 4, 6, 5, 6, 6, 8, 9, 20, 8, 2, 6, 8, 3, 8, 7, 5, 6, 8, 1, 8, 4, 8~
$ Complain              <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,~
$ Response              <dbl> 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,~
$ Age                   <dbl> 65, 68, 57, 38, 41, 55, 51, 37, 48, 72, 46, 63, 70, 35, 76, 42, 76, 73,~
$ Child                 <dbl> 0, 2, 0, 1, 1, 1, 1, 1, 1, 2, 0, 0, 2, 0, 0, 2, 0, 1, 1, 0, 1, 1, 1, 1,~
$ total_spent           <dbl> 1617, 27, 776, 53, 422, 716, 590, 169, 46, 49, 61, 1102, 310, 46, 1315,~
$ accepted              <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 1, 0, 0, 0, 1, 0, 0,~

Disini saya menghapus variabel Pendapatan (Income), pertama saya melakukan pengelempokan mengguanakan variabel itu tetapi tidak membantu untuk mendapatkan pemisahan yang jelas. dan juga dalam masalah ini saya tertarik dengan jumlah yang dibelanjakan pelanggan dari pada Penghasilanya

K-Means Clustering

Clustering adalah proses pembagian objek-objek ke dalam beberapa kelompok (cluster) berdasarkan tingkat kemiripan antara satu objek dengan yang lain.

Beberapa contoh clustering:

Banyak algoritma telah dikembangkan untuk melakukan clustering secara otomatis, salah satu yang sangat populer adalah K-Means.

K-means adalah algoritma yang membagi data menjadi sejumlah partisi dengan cara sederhana: mencari kedekatan dari tiap titik pada suatu cluster dengan sejumlah nilai rata-rata atau mean.

Ada dua konsep kunci yang juga menjadi nama asal k-means:

Fungsi kmeans memerlukan minimal 2 parameter, yaitu:

Mean atau nilai rata-rata disini sering disebut juga dengan centroid pada berbagai literatur data science.

Dan fungsi kmeans ini biasanya disertai dengan pemanggilan function seet.seed(). Ini berguna agar dapat “menyeragamkan” daftar nilai acak yang sama dari kmeans sehingga mendapatkan output yang sama.

print(km.res$centers)
  Marital_StatusMarried Marital_StatusSingle  Recency NumDealsPurchases NumWebPurchases
1             0.3933121            0.2165605 48.62898          2.340764        2.719745
2             0.3793677            0.1863561 48.80865          2.728785        6.093178
3             0.3760446            0.2423398 50.69638          1.584958        5.501393
  NumCatalogPurchases NumStorePurchases NumWebVisitsMonth    Complain  Response      Age     Child
1           0.8073248          3.730892          6.314490 0.011146497 0.1011146 51.77150 1.2300955
2           4.3777038          8.660566          4.379368 0.009983361 0.1264559 55.68220 0.7504160
3           6.3342618          8.256267          3.409471 0.002785515 0.3621170 53.91643 0.2869081
  total_spent  accepted
1    152.6863 0.1058917
2    921.4676 0.3061564
3   1670.4819 0.9582173
print(km.res$size)
[1] 1256  601  359
print(km.res$betweenss/km.res$totss)
[1] 0.8976368

Saya dapat meliahat pemisahan yang jelas dalam total pengeluaran di antara 3 Cluster. ini akan memabantu untuk memberi nama cluster

numcatplot
notch went outside hinges. Try setting notch=FALSE.

numcatplot
notch went outside hinges. Try setting notch=FALSE.

Kesimpulan

Semua fitur yang diplot di atas memiliki pemisahan yang jelas antar Cluster. Menurut Analysis ini saya dapat memberi nama ketiga Klaster ini. Cluster 1 memiliki pembelanjaan rendah, cluster 2 Memiliki pembelanjaan rata-rata, dan Claster 3 memiliki pembelanjaan tinggi.

Penampilan atau peselancar adalah pelanggan yang hanya menelusuri layanan perusahaan anda dan mungkin juga melihat melalui pesaing Anda. Mereka telah melanjutkan minat, tetapi mereka belum memutuskan apa pun.

Bagaimana menghadapi mereka ?

Pelanggan implusif belum benar-benar berencana untuk membeli produk Anda, atau produk apapun dalam hal ini, calon pelanggan membeli keputusan pembelian secara mendadak.

Bagaimana menghadapi mereka ?

Pelanggan setia adalah jenis pelanggan terbaik untuk bisnis Anda. Jenis pelanggan berulang terus kembali kepada Anda untuk produk dan layanan yang berbeda dan mereka tampaknya terkesan dengan merek Anda.

Bagaimana Menghadapi mereka ?

Perlu diingat kesimpulan cluster 1, cluster 2 dan cluster 3 saya mengambil kesimpulan diatas di 16 jenis pelanggan yang berbeda dan cara mendakatinya

https://www.revechat.com/blog/types-of-customers/amp/

LS0tDQp0aXRsZTogIkFubHlzaXMgS2VwcmliYWRpYW4gUGVsYW5nZ2FuIE9ubGluZSINCmF1dGhvcjogIlxVMDAwMUY1RTMgSmFtYWxsdWRpbiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICBodG1sX2RvY3VtZW50Og0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDgNCiAgICBmaWdfaGVpZ2h0OiA2LjUNCiAgICB0aGVtZTogcmVhZGFibGUNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KDQohW10oQWxsaWFudF9EYXRhSHViX0xlZnQtMS5naWYpDQoNCg0KDQojIERlc2tyaXBzaSANCg0KDQoNCkFuYWx5c2lzIEtlcHJpYmFkaWFuIFBlbGFuZ2dhbiBhZGFsYWggQW5hbHlzaXMgdGVycGVyaW5jaSB0ZW50YW5nIHBlbGFuZ2dhbiBpZGVhbCBkaSBwZXJ1c2FoYWFuLiBJbmkgbWVtYmFudHUgYmlzbmlzIHVudHVrIGxlYmloIG1lbWFoYW1pIHBlbGFuZ2dhbm55YSBkYW4gbWVtdWRhaGthbiBwZXJ1c2FoYWFuIHVudHVrIG1lbW9kaWZpa2FzaSBwcm9kdWsgc2VzdWFpIGRlbmdhbiBrZWJ1dHVoYW4sIHByaWxha3UsIGRhbiBwZXJoYXRpYW4ga2h1c3VzIGRhcmkgYmVyYmFnYWkgamVuaXMgcGVsYW5nZ2FuLiANCg0KUGVsYW5nZ2FuIG1lbWlsaWtpIGtlcHJpYmFkaWFuIHlhbmcgYmVyYmVkYSBkYW4gdGVyc2ViYXIgZGkgYmVyYmFnYWkgdGFoYXAgc2FsdXJhbiBwZW5qdWFsYW4uIFBlbGFuZ2dhbiBtZW51bmp1a2thbiBrZXByaWJhZGlhbiBkYW4gcGVyaWxha3UgeWFuZyBiZXJiZWRhLCBqaWthIHBlcnVzYWhhYW4gbWVuYW5nYW5pIGJlcmJhZ2FpIGplbmlzIHBlbGFuZ2dhbiBkZW5nYW4gY2FyYSB5YW5nIHNhbWEsIGppa2EgcGVydXNhaGFhbiB0aWRhayBtZW5nZWxvbXBva2thbiBwZWxhbmdnYW4gc2VjYXJhIHN0cmF0ZWdpcyBkYW4gbWVuYWdhbmlueWEgZGVuZ2FuIHRlcGF0LCBwZXJ1c2FoYWFuIHBhc3RpIGFrYW4ga2VoaWxhbmdhbiBiYW5heWFrIHBlbGFuZ2dhbiBzZXRpYSBkYW4gYWthbiBtZW5nYWtpYmF0a2FuIHBlbmdoYXNpbGFuIHBlcnVzYWhhYW4gYmVzYXIgcGVuanVhbGFuIHBlcnVzYWhhYW4uDQpEYW4gcGVuZWxpdGFuIG1lbnVuanVra2FuIGJhaHdhIDMzJSBwZWxhbmdnYW4gbWVuaW5nZ2Fsa2FuIG1lcmVrIHBlcnVzYWhhYW4geWFuZyBwZWxhbmdnYW4gdGluZ2dhbGthbiBoYW55YSBzZXRlbGFoIHNhdHUgcGVuZ2FsYW1hbiB5YW5nIGJ1cnVrISEuDQoNCkFuYWx5c2lzIEtlcGVyYmFkaWFuIFBlbGFuZ2dhbiBtZW1iYW50dSBiaXNuaXMgdW50dWsgbWVtb2RpZmlrYXNpIHByb2R1a255YSBiZXJkYXNhcmthbiB0YXJnZXQgcGVsYW5nZ2FuIGRhcmkgYmVyYmFnYWkgamVuaXMgc2VnbWVuIHBlbGFuZ2dhbi4gTWlzYWxueWEgYWxpaC1hbGloIG1lbmdlbHVhcmthbiB1YW5nIHVudHVrIHByb2R1ayBiYXJ1IGtlIHNldGlhcCBwZWxhbmdnYW4gZGkgZGF0YWJhc2UgcGVydXNhaGFhbiwgcGVydXNhaGFhbiBkYXBhdCBtZW5nYW5hbHlzaXMgc2VnbWVuIHBlbGFuZ2dhbiBtYW5hIHlhbmcgcGFsaW5nIG11bmdraW4gcHJvZHVrIGRhbiBtZW1hc2Fya2FuIHByb2R1ayBoYW55YSBwYWRhIHNlZ21lbiB0ZXJ0ZW50dS4gDQoNCg0KRGF0YSBwYWRhIHByb2plY3QgaW5pIGJpc2EgZGlkb3dubG9hZCA6IGh0dHBzOi8vZHJpdmUuZ29vZ2xlLmNvbS9maWxlL2QvMUpBdFktelM5Z0xFUWRxOUZ4ck9tbkVCS2JjaVBrbkZtL3ZpZXc/dXNwPWRyaXZlc2RrDQoNCg0KDQojIERlc2tyaXBzaSBLdW1wdWxhbiBEYXRhDQoNCg0KU2ViZWx1bSBtZWxhbmdrYWggbGViaWggamF1aCwgc2F5YSBwZXJsdSBtZW5nZXRhaHVpIGluZm9ybWFzaSBkYXNhciBkYXJpIGRhdGEgbWVsaXB1dGkgdWt1cmFuIGRhdGEsIGJhbnlha255YSBkYXRhLCBkYW4gbmFtYS1uYW1hIGtvbG9tIGF0YXUgdmFyaWFiZWwgZGkgZGFsYW0gZGF0YS4NCg0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KZGF0YSA9IHJlYWQuY3N2KCJkYXRhX3BlbGFuZ2dhbi5jc3YiKQ0KDQpkYXRhID0gcmVhZC50YWJsZSgiZGF0YV9wZWxhbmdnYW4uY3N2Iiwgc2VwID0gIlx0IiwNCiAgICAgICAgICAgICAgICAgIGhlYWRlciA9IFQpDQpvcHRpb25zKHdhcm4gPSAtMSkNCmRmID0gZGF0YS5mcmFtZShkYXRhKQ0KaGVhZChkYXRhKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpnbGltcHNlKGRhdGEpDQpgYGANCg0KDQpUYW1wYWtueWEgYmFod2EgYWRhIHNlYmFueWFrIDIyNDAgYmFyaXMgcGFkYSBkYXRhIGRlbmdhbiB2YXJpYWJlbCBzZWJhbnlhayAyOSBkYW4gYWRhIGJhaWtueWEgc2F5YSBtZW5nZXRhaHVpIGFwYWthaCBhZGEgbmlsYWkgeWFuZyBrb3NvbmcgYXRhdSBOQS4NCg0KDQpCZXJpa3V0IGFkYWxhaCBWYXJpYWJlbCBzaW5na2F0IGRhcmkgZmlsZSBkZXNrcmlwc2kgZGF0YQ0KDQoNCioqUGVsYW5nZ2FuKioNCg0KDQotICoqSUQqKiA6IFBlbmdpZGVudGlmaWthc2kgdW5payBwZWxhbmdnYW4gDQoNCi0gKipZZWFyX0JpcnRoKiogOiBUYWh1biBMYWhpciBQZWxhbmdnYW4gDQoNCi0gKipFZHVjYXRvbioqIDogVGluZ2thdCBwZW5kaWRpa2FuIHBlbGFuZ2dhbiANCg0KLSAqKk1hcnRpYWxfU3RhdHVzKiogOiBTdGF0dXMgcGVybmlrYWhhbiBwZWxhbmdnYW4gDQoNCi0gKipJbmNvbWUqKiA6IFBlbmRhcGF0YW4gcnVtYWggdGFuZ2dhIHBlbGFuZ2dhbiBwZXJ0YWh1bg0KDQotICoqS2lkaG9tZSoqIDogSnVtbGFoIGFuYWsgZGFsYW0gcnVtYWggdGFuZ2dhIHBlbGFuZ2dhbiANCg0KLSAqKlRlZW5ob21lKiogOiBKdW1sYWggcmVtYWphIGRhbGFtIHJ1bWFoIHRhbmdnYSBwZWxhbmdnYW4NCg0KLSAqKkR0X0N1c3RvbWVyKiogOiBUYW5nZ2FsIFBlbmRhZnRhcmFuIHBlbGFuZ2dhbiBkZW5nYW4gcGVydXNhaGFhbiANCg0KLSAqKlJlY2VuY3kqKiA6IEp1bWxhaCBoYXJpIHNlamFrIHBlbWJlbGlhbiB0ZXJha2hpciBwZWxhbmdnYW4gDQoNCi0gKipDb21wbGFpbioqIDogMSBqaWthIHBlbGFuZ2dhbiBtZW5nZWx1aCBkYWxhbSAyIHRhaHVuIHRlcmFrYWhpciwgMCBzZWJhbGlrbnlhIA0KDQoNCioqUHJvZHVrIHlhbmcgZGlqdWFsIFBlcnVzYWhhYW4qKg0KDQoNCi0gKipNbnRXaW5lcyoqIDogSnVtbGFoIHlhbmcgZGloYWJpc2thbiB1bnR1ayBkYWdpbmcgZGFsYW0gMiB0YWh1biB0ZXJha2hpciAgDQoNCi0gKipNbnRGcnVpdHMqKiA6IEp1bWxhaCB5YW5nIGRpaGFiaXNrYW4gdW50dWsgYnVhaC1idWFoYW4gZGFsYW0gMiB0YWh1biB0ZXJha2hpciANCg0KLSAqKk1udE1lYXRQcm9kdWN0cyoqIDogSnVtbGFoIHlhbmcgZGloYWJpc2thbiB1bnR1ayBtZW1iZWxpIGRhZ2luZyBkYWxhbSAyIHRhaHVuIHRlcmFraGlyICAgDQoNCi0gKipNbnRGaXNoUHJvZHVjdCoqIDogIEp1bWxhaCB5YW5nIGRpaGFiaXNrYW4gdW50dWsgbWVtYmVsaSBpa2FuIGRhbGFtIDIgdGFodW4gdGVyYWtoaXIgDQoNCi0gKipNbnRTd2VldFByb2R1Y3QqKiA6IEp1bWxhaCB5YW5nIGRpaGFiaXNrYW4gdW50dWsgcGVybWVuIGRhbGFtIDIgdGFodW4gdGVyYWtoaXIgDQoNCi0gKipNbnRHb2xkUHJvZHMqKiA6IEp1bWxhaCB5YW5nIGRpaGFiaXNrYW4gdW50dWsgZW1hcyBkYWxhbSAyIHRhaHVuIHRlcmFraGlyICANCg0KDQoqKlByb21vc2kgcGVydXNhaGFhbiBrZXBhZGEgcGVsYW5nZ2FuKioNCg0KDQotICoqTnVtRGVscyBQdXJjaGFzZXMqKiA6IEp1bWxhaCBQZW1iZWxpYW4geWFuZyBkaWxha3VrYW4gZGVuZ2FuIGRpc2tvbg0KDQotICoqQWNjZXB0ZWRDbXAxKiogOiAxIGppa2EgcGVsYW5nZ2FuIG1lbmVyaW1hIHBlbmF3YXJhbiBkaSBrYW1wYW55ZSBwZXJ0YW1hLCAwIHNlYmFsaWtueWENCg0KLSAqKkFjY2VwdGVkY21wMioqIDogMSBKaWthIHBlbGFuZ2dhbiBtZW5lcmltYSBwZW5hd2FyYW4gZGkga2FtYXBhbnllIGtlLTIsIDAgc2ViYWxpa255YQ0KDQotICoqQWNjZXB0ZWRjbXAzKiogOiAxIEppa2EgcGVsYW5nZ2FuIG1lbmVyaW1hIHBlbmF3YXJhbiBkaSBrYW1wYW55ZSBrZS0zICwgMCBzZWJhbGlrbnlhIA0KDQotICoqQWNjZXB0ZWRjbXA0KiogOiAxIEppa2EgcGVsYW5nZ2FuIG1lbmVyaW1hIHBlbmF3YXJhbiBkaSBrYW1wYW55ZSBrZS00LCAwIHNlYmFsaWtueWEgDQoNCi0gKipBY2NlcHRlZGNtcDUqKiA6IDEgSmlrYSBwZWxhbmdnYW4gbWVuZXJpbWEgcGVuYXdhcmFuIGRpIGthbXBhbnllIGtlLTUsIDAgc2ViYWxpa255YQ0KDQotICoqUmVzcG9uc2UqKiA6IDEgSmlrYSBwZWxhbmdnYW4gbWVuZXJpbWEgdGF3YXJhbiBkaSBrYW1wYW55ZSB0ZXJha2hpciwgMCBzZWJhbGlrbnlhIA0KDQoNCg0KKipUZW1wYXQgeWFuZyBkaWd1bmFrYW4gcGVsYW5nZ2FuKioNCg0KDQotICoqTnVtV2ViUHVyY2hhc2VzKiogOiBKdW1sYWggcGVtYmVsaWFuIHlhbmcgZGlsYWt1a2FuIG1lbGFsdWkgc2l0dXMgd2ViIHBlcnVzYWhhYW4gDQoNCi0gKipOdW1DYXRhbG9nUHVyY2hhc2VzKiogOiBKdW1sYWggcGVtYmVpbGFuIHlhbmcgZGlsYWt1a2FuIG1lbmd1YW5ha2FuIGthdGFsb2cgIA0KDQotICoqTnVtU3RvcmVQdXJjaGFzZXMqKiA6IEp1bWxhaCBwZW1iZWlsYW4geWFuZyBkaWxha3VrYW4gbGFuZ3N1bmcgZGkgdG9rbyAgDQoNCi0gKipOdW1XZWJWaXNpdHNNb250aCoqIDogSnVtbGFoIEt1bmp1bmdhbiBrZSBzaXR1cyB3ZWIgcGVydXNhaGFhbiBkYWxhbSBzZWJ1bGFuIHRlcmFraGlyDQoNCg0KDQojIERhdGEgQ2xlbmluZw0KDQoNCg0Kc3VhdHUgcHJvc2VzIG1lbmRldGVrc2kgZGFuIG1lbXBlcmJhaWtpIChhdGF1IG1lbmdoYXB1cykgZGF0YSBzZXQsIHRhYmVsLCBkYW4gZGF0YWJhc2UgeWFuZyBrb3J1cCBhdGF1IHRpZGFrIGFrdXJhdC4NCm1lbWVyaWtzYSBuaWxhaS1uaWxhaSBrb3NvbmcgeWFuZyBoaWxhbmcNCg0KDQpgYGB7cn0NCmNvbFN1bXMoaXMubmEoZGF0YSkpDQpgYGANCg0KDQpUZXJueWF0YSBhZGEgbmlsYWkga29zb25nIGF0YXUgTkEgdGVyZGFwYXQgZGkgdmFyaWFiZWwgKipJbmNvbWUqKiwgdW50dWsgdmFyaWFiZWwgaW5jb21lIGppa2EgbWVtaWxpa2kgbmlsYWkgeWFuZyBoaWxhbmcgYXRhdSBOQSBrYXJlbmEgcHJlc2VuYXRhc2VueWEgc2FuZ2F0IGtlY2lsLCBtYWthIHNheWEgaGFydXMgbWVuZ2hhcHVzIG55YSBhdGF1IGppa2EgbmlsYWkgcGVyc2VudGFzZW55YSBzYW5nYXQgYmVzYXIgbWFrYSBzYXlhIG1lbmdpc2kgbmlsYWkgeWFuZyBrb3NvbmcgcGFkYSB2YXJpYWJlbCBpbmNvbWUgZGVuZ2FuIG1lbmdpc2kgbmlsYWkgZGVuZ2FuIGltcHV0YXRpb24uIA0KDQoNCg0KYGBge3J9DQptaXNzaW5nLnZhbHVlcyA8LSBkZiAlPiUNCiAgZ2F0aGVyKGtleSA9ICJrZXkiLCB2YWx1ZSA9ICJ2YWwiKSAlPiUNCiAgbXV0YXRlKGlzbmEgPSBpcy5uYSh2YWwpKSAlPiUNCiAgZ3JvdXBfYnkoa2V5KSAlPiUNCiAgbXV0YXRlKHRvdGFsID0gbigpKSAlPiUNCiAgZ3JvdXBfYnkoa2V5LCB0b3RhbCwgaXNuYSkgJT4lDQogIHN1bW1hcmlzZShudW0uaXNuYSA9IG4oKSkgJT4lDQogIG11dGF0ZShwY3QgPSBudW0uaXNuYSAvIHRvdGFsICogMTAwKQ0KDQoNCmxldmVscyA9KG1pc3NpbmcudmFsdWVzICAlPiUgZmlsdGVyKGlzbmEgPT0gVCkgJT4lIGFycmFuZ2UoZGVzYyhwY3QpKSkka2V5DQoNCnBlcmNlbnRhZ2UucGxvdCA9IG1pc3NpbmcudmFsdWVzICU+JQ0KICAgICAgZ2dwbG90KCkgKw0KICAgICAgICBnZW9tX2JhcihhZXMoeCA9IHJlb3JkZXIoa2V5LCBkZXNjKHBjdCkpLCANCiAgICAgICAgICAgICAgICAgICAgIHkgPSBwY3QsIGZpbGw9aXNuYSksIA0KICAgICAgICAgICAgICAgICBzdGF0ID0gJ2lkZW50aXR5JywgYWxwaGE9MC44KSArDQogICAgICBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGxldmVscykgKw0KICAgICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICIiLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IGMoJyNhZGNhZTYnLCAncmVkJyksIGxhYmVscyA9IGMoIlByZXNlbnQiLCAiTWlzc2luZyIpKSArDQogICAgICBjb29yZF9mbGlwKCkgKw0KICAgICAgbGFicyh0aXRsZSA9ICJQZXJzZW50YXNpIE5pbGFpIFlhbmcgSGlsYW5nIiwgeCA9J1ZhcmlhYmxlJywgeSA9ICIlIE5pbGFpIFlhbmcgSGlsYW5nIikNCg0KcGVyY2VudGFnZS5wbG90DQpgYGANCg0KDQoNCkhhc2lsIGRhcmkgcGxvdCBkaWF0YXMgbWVuZ2FtYmFya2FuIFRlcm5heWF0YSBOaWxhaSBwcmVzZW50YXNpbnlhIGRpIHZhcmlhYmVsICoqSW5jb21lKiogc2FuZ2F0IGtlY2lsLCBtYWthIHNheWEgaGFydXMgbWVuZ2hhcHVzbnlhLiANCg0KDQojIERhdGEgUmVkdWN0aW9uIA0KDQoNClBlbWlsaWhhbiB0ZW50YW5nIGJhZ2lhbiBkYXRhIG1hbmEgeWFuZyBkaWtvZGUsIG1hbmEgeWFuZyBkaWJ1YW5nLCBwb2xhLXBvbGEgbWFuYSB5YW5nIGRpcmluZ2thcyBzZWp1bWxhaCBiYWdhaW4gdGVyc2ViYXIgZGF0YS4NCg0KDQpgYGB7cn0NCmRmMSA8LSBuYS5vbWl0KGRmKQ0KYGBgDQoNCg0KDQpTYXlhIGFrYW4gTWVtYnVhdCBWYXJhaWJlbCAqKkFnZSoqIHVudHVrIG1lbmdoaXR1bmcgcGVsYW5nZ2FuIGRhcmkgdGFodW4gbGFoaXIgcGVsYW5nZ2FuIHBlbGFuZ2dhbi4gDQpJbmkgYWthbiBsZWJpaCBiZXJndW5hIHVudHVrIGFuYWx5c2lzIHNheWEuIA0KDQoNCmBgYHtyfQ0KZGYxWydBZ2UnXT0gMjAyMi1kZjEkWWVhcl9CaXJ0aA0KYGBgDQoNCg0KTWVtYnVhdCB2YXJpYWJlbCAqKkNoaWxkKiogdW50dWsgbWVuZ2dhbWJ1bmdrYW4gdmFyaWFiZWwgKipLaWRob21lKiogZGFuICoqVGVlbmhvbWUqKi4NClVudHVrIG1lbmdldGFodWkgSnVtbGFoIGFuYWsgZGFuIHJlbWFqYSBkaWRhbGFtIHJ1bWFoIHRhbmdnYSBwZWxhbmdnYW4uDQoNCg0KYGBge3J9DQpkZjFbJ0NoaWxkJ109ZGYxJEtpZGhvbWUrZGYxJFRlZW5ob21lDQoNCnByaW50KG1pbihkZjEkRHRfQ3VzdG9tZXIpKQ0KcHJpbnQobWF4KGRmMSREdF9DdXN0b21lcikpDQpgYGANCg0KDQpNZW1idWF0IFZhcmlhYmVsICoqdG90YWxfc3BlbnQqKiB1bnR1ayBtZW5nYWJ1bmdha2FuIHNlbXVhIHByb2R1ayBwZXJ1c2FoYWFuIHVudHVrIG1lbmdldGFodWkgdG90YWwgeWFuZyBkaWJlbGFuamFrYW4gcGVsYW5nZ2FuIA0KDQoNCmBgYHtyfQ0KZGYxWyd0b3RhbF9zcGVudCddPWRmMSRNbnRNZWF0UHJvZHVjdHMrZGYxJE1udEZpc2hQcm9kdWN0cytkZjEkTW50V2luZXMrZGYxJE1udEZydWl0cytkZjEkTW50U3dlZXRQcm9kdWN0cytkZjEkTW50R29sZFByb2RzDQpgYGANCg0KDQpNZW1idWF0IFZhcmlhYmVsICoqYWNjZXB0ZWQqKiB1bnR1ayBtZW5nYWJ1bmdha2FuIHNlbXVhIGthbXBhbnllIHBlcnVzYWhhYW4gdW50dWsgbWVuZ2V0YWh1aSBrYW1hcGFueWUgbWFuYSB5YW5nIGRpdGVyaW1hIHBlbGFuZ2dhbi4NCg0KDQpgYGB7cn0NCmRmMVsnYWNjZXB0ZWQnXT1kZjEkQWNjZXB0ZWRDbXAxK2RmMSRBY2NlcHRlZENtcDIrZGYxJEFjY2VwdGVkQ21wMytkZjEkQWNjZXB0ZWRDbXA0K2RmMSRBY2NlcHRlZENtcDUNCg0KaGVhZChkZjEpDQpgYGANCg0KDQoNCmBgYHtyfQ0KbmFtZXMoZGYxKQ0KYGBgDQoNCmRhcmkgaGFzaWwgZGlhdGFzIGRhcGF0IGRpbGloYXQgdmFyaWFiZWwgYmFydSB5YWl0dSAqKmFnZSoqLCAqKmNoaWxkKiosICoqdG90YWxfc3BlbnQqKiBkYW4gKiphY2NlcGV0ZWQqKiBkYXJpIGhhc2lsIHBlZ2FidW5nYW4gZGF0YSB2YXJpYWJlbC4gDQoNCg0KKipNZW5naGFwdXMgVmFyaWFiZWwgYXNsaSoqIEthcmVuYSBzZWthcmFuZyBkYXRhIGluaSBiZXJpaXNpIGZpdHVyIGdhYnVuZ2FuIGJhcnUuIA0KDQoNCmBgYHtyfQ0KZGYxPWRmMVtjKC0xLC0yLC02LC03LC04LC0xMCwtMTEsLTEyLC0xMywtMTQsLTE1LC0yMSwtMjIsLTIzLC0yNCwtMjUsLTI3LC0yOCldDQoNCmhlYWQoZGYxKQ0KYGBgDQoNCg0KU2VrYXJhbmcgc3VkYWggbWVuamFkaSBrdW1wdWxhbiBkYXRhIGJlcmlzaSAqKmZpdHVyIGdhYnVuZ2FuIGJhcnUqKg0KDQoNCiMgVGVtdWFuIFV0YW1hIGRhbGFtIEFuYWx5c2lzIERlc3JpcHRpdmUNCg0KQW5hbHlzaXMgZGVzcmlwdGl2ZSBkYXBhdCBkaSBrYXRlZ29yaWthbiBtZW5qYWRpIGVtcGF0IGplbmlzIHlhaXR1IHVrdXJhbiBmcmVrdW5lc2ksIHRlbmRlc2kgc2VudHJhbCwgZGVzcGVyc2kgYXRhdSB2YXJpYXNpLCBkYW4gdWt1cmFuIHBvc2lzaS4gdW50dWsgcHJvamVjayBpbmkgc2F5YSBtZW5nZ3VuYWthbiBhbmFseWlzIGRlc2lrcmlwdGlmIHVrdXJhbiBwb3Npc2kgbmlsYWkgdHVuZ2dhbCBhdGF1IHJlc3BvbnNueSBhZGFsYW0ga2FpdGFueWEgZGVuZ2FuIG5pbGFpIGxhaW4uIE1lbmdndW5ha2FuIGRlc2tyaXB0aXZlIEJpdmFyaWF0IGF0YXUgTXVsdGl2YXJpYXQgdW50dWsgbWVtcGVsYWphcmkgYXBha2FoIGFkYSBodWJ1bmdhbiBkaWFudGFyYSBrZWR1YW55YS4NCg0KDQojIyBBbmx5c2lzIERlc3JpcHRpdmUgSW5jb21lIEN1c3RvbWVycw0KDQoNCmBgYHtyfQ0KaGlzdChkZjEkSW5jb21lLDQwLGNvbD0iI2FkY2FlNiIpDQpgYGANCg0KDQoNCg0KYGBge3J9DQppbmNvbWU9ZGYxJEluY29tZVtkZjEkSW5jb21lPDE4MDAwMF0NCmJveHBsb3QoaW5jb21lLA0KbWFpbiA9ICJDdXN0b21lciBpbmNvbWUiLA0KeGxhYiA9ICJJbmNvbWUiLA0KeWxhYiA9ICIiLA0KY29sID0gIiNhZGNhZTYiLA0KYm9yZGVyID0gImJsdWUiLA0KaG9yaXpvbnRhbCA9IFRSVUUsDQpub3RjaCA9IFRSVUUNCikNCmBgYA0KDQoNCkhhc2kgcGxvdCBkaWF0YXMgbWVuZ2FtYmFya2FuIGJhd2EgcmF0YS1yYXRhIHBlbmRhcGF0YW4gcmF0YS1yYXRhIFBlbGFuZ2dhbiBzZWtpdGFyICoqNTAwMDAqKg0KDQoNCg0KYGBge3J9DQpwbG90KGRmMSRJbmNvbWUsZGYxJHRvdGFsX3NwZW50LGNvbD0nI2FkY2FlNicNCiAgICAgLHhsYWI9J0luY29tZScseWxhYj0nc3BlbnQnKQ0KYGBgDQoNCmRhcmkgcGxvdCBkaWF0YXMgbWVuZ2FtYmFya2FuIHBlbmRhcGF0YW4gcGVsYW5nZ2FuIHlhbmcgZGliZWxhbmpha2FuIHNlbXVhIHByb2R1ayBwZXJ1c2FoYWFuIHVudHVrIG1lbmdldGFodWkgdG90YWwgeWFuZyBkaWJlbGFuamFrYW4gcGVsYW5nZ2FuLg0KDQoNCg0KIyMgQW5seXNpcyBEZXNjcmlwdGl2ZSAgQWdlIEN1c3RvbWVycyANCg0KDQoNCmBgYHtyfQ0KaGlzdChkZjEkQWdlLDUwLGNvbD0iI2FkY2FlNiIpDQpgYGANCg0KDQoNCmBgYHtyfQ0KYm94cGxvdChkZjEkQWdlLA0KbWFpbiA9ICJBZ2UgQ3VzdG9tZXJzIiwNCnhsYWIgPSAiQWdlIiwNCnlsYWIgPSAiIiwNCmNvbCA9ICIjYWRjYWU2IiwNCmJvcmRlciA9ICJibHVlIiwNCmhvcml6b250YWwgPSBUUlVFLA0Kbm90Y2ggPSBUUlVFDQopDQpgYGANCg0KDQpEYXJpIHBsb3QgZGlhdGFzIG1lbmdhbWJhcmthbiByYXRhLXJhdGEgQWdlIEN1c3RvbWVycyAqKjUwKiogdGFodW4uDQoNCg0KDQojIyBBbmFseXNpcyBEZXNjcmlwdGl2ZSBUb3RhbCBTcGVudA0KDQoNCmBgYHtyfQ0KaGlzdChkZjEkdG90YWxfc3BlbnQsNTAsY29sPSIjYWRjYWU2IikNCmBgYA0KDQoNCmBgYHtyfQ0KYm94cGxvdChkZjEkdG90YWxfc3BlbnQsDQptYWluID0gIlRvdGFsIHNwZW50IGJ5IHRoZSBjdXN0b21lcnMiLA0KeGxhYiA9ICJUb3RhbCIsDQp5bGFiID0gIiIsDQpjb2wgPSAiI2FkY2FlNiIsDQpib3JkZXIgPSAiYmx1ZSIsDQpob3Jpem9udGFsID0gVFJVRSwNCm5vdGNoID0gVFJVRQ0KKQ0KYGBgDQoNCg0KZGFyaSBnYW1iYXIgZGlhdGFzICoqdG90YWxfc3BlbnQqKiBjdXN0b21lcnMgcmF0YS1yYXRhIG55YSBzZWtpdGFyICoqNDc1KioNCg0KDQoNCiMgRGF0YSBWaXN1YWxpc2FzaQ0KDQoNCmBgYHtyfQ0KZWR1cGxvdCA9IGdncGxvdChkZjEsIGFlcyh4PUVkdWNhdGlvbix5PUluY29tZSxmaWxsPUVkdWNhdGlvbikpK3lsaW0oMCwxODAwMDApK2dlb21fYm94cGxvdChvdXRsaWVyLmNvbG91cj0iYmxhY2siLCBvdXRsaWVyLnNoYXBlPTE2LG91dGxpZXIuc2l6ZT0yLCBub3RjaD1UKQ0KZWR1cGxvdA0KYGBgDQoNCg0KRGFyaSB2aXN1YWxpc2FzaXMgaGFzaWwgZGlhdGFzIGJhaHdhIHBlbGFuZ2dhbiAqKkJhc2ljKiogdGluZ2thdCBwZW5kaWRpa2FuIGRhc2FyIG1lbWlsaWtpIHBlbmRhcGF0YW4geWFuZyBsZWJpaCBrZWNpbCBkaWJhZGluZ2thbiBkZW5nYW4geWFuZyBsYWluLg0KDQoNCmBgYHtyfQ0KbXBsb3QgPSBnZ3Bsb3QoZGYxLCBhZXMoeD1NYXJpdGFsX1N0YXR1cyx5PUluY29tZSxmaWxsPU1hcml0YWxfU3RhdHVzKSkreWxpbSgwLDE4MDAwMCkrZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJibGFjayIsIG91dGxpZXIuc2hhcGU9MTYsb3V0bGllci5zaXplPTIsIG5vdGNoPVQpDQoNCm1wbG90DQpgYGANCg0KDQpEYXJpIHZpc3VhbGlzYXNpcyBoYXNpbCBkaWF0YXMgYmFod2EgTWFydGlhbCBTdGF0dXMgKipBbG9uZSoqIGRhbiAqKllPTE8qKiBtZW1pbGlraSBwZW5kYXBhdGFuIHlhbmcgbGViaWgga2VjaWwgZGliYWRpbmdrYW4gZGVuZ2FuIHlhbmcgbGFpbi4NCg0KDQoNCiMgVmFyaWFibGUgRHVtbXkgDQoNCg0KVmFyaWFiZWwgeWFuZyBkaWd1bmFrYW4gdW50dWsgbWVuZ2t1YW50aXRhdGlma2FuIHZhcmlhYmVsIHlhbmcgYmVyc2lmYXQga3VhbGl0YXRpZi4NCg0KTWVtYnVhdCB2YXJpYWJlbCBkdW1teQ0KDQpgYGB7cn0NCmxpYnJhcnkoY2FyZXQpDQoNCmRteSA8LSBkdW1teVZhcnMoIiB+IC4iLCBkYXRhID0gZGYxLCBmdWxsUmFuayA9IFQpDQpkYXRfdHJhbnNmb3JtZWQgPC0gZGF0YS5mcmFtZShwcmVkaWN0KGRteSwgbmV3ZGF0YSA9IGRmMSkpDQoNCmRmYz1kYXRfdHJhbnNmb3JtZWRbYyg3LDgsMTMsMTQsMTUsMTYsMTcsMTgsMTksMjAsMjEsMjIsMjMsMjQpXQ0KDQpnbGltcHNlKGRmYykNCmBgYA0KDQoNCkRpc2luaSBzYXlhIG1lbmdoYXB1cyB2YXJpYWJlbCBQZW5kYXBhdGFuICoqKEluY29tZSkqKiwgcGVydGFtYSBzYXlhIG1lbGFrdWthbiBwZW5nZWxlbXBva2FuIG1lbmdndWFuYWthbiB2YXJpYWJlbCBpdHUgdGV0YXBpIHRpZGFrIG1lbWJhbnR1IHVudHVrIG1lbmRhcGF0a2FuIHBlbWlzYWhhbiB5YW5nIGplbGFzLiBkYW4ganVnYSBkYWxhbSBtYXNhbGFoIGluaSBzYXlhIHRlcnRhcmlrIGRlbmdhbiBqdW1sYWggeWFuZyBkaWJlbGFuamFrYW4gcGVsYW5nZ2FuIGRhcmkgcGFkYSBQZW5naGFzaWxhbnlhDQoNCg0KDQojIEstTWVhbnMgQ2x1c3RlcmluZw0KDQoNCkNsdXN0ZXJpbmcgYWRhbGFoIHByb3NlcyBwZW1iYWdpYW4gb2JqZWstb2JqZWsga2UgZGFsYW0gYmViZXJhcGEga2Vsb21wb2sgKGNsdXN0ZXIpIGJlcmRhc2Fya2FuIHRpbmdrYXQga2VtaXJpcGFuIGFudGFyYSBzYXR1IG9iamVrIGRlbmdhbiB5YW5nIGxhaW4uDQoNCkJlYmVyYXBhIGNvbnRvaCBjbHVzdGVyaW5nOg0KDQotIFBlbmdlbG9tcG9rYW4gbWFudXNpYSBiZXJkYXNhcmthbiB1bXVyOiBiYXlpLCBiYWxpdGEsIGFuYWssIHJlbWFqYSwgZGV3YXNhLCB0dWEuDQoNCi0gUGVuZ2Vsb21wb2thbiBjdXN0b21lciBiZXJkYXNhcmthbiBkYXlhIGJlbGlueWE6IHJlZ3VsYXIgZGFuIHByZW1pdW0uDQoNCi0gUGVuZ2Vsb21wb2thbiBtYWthbmFuIGJlcmRhc2Fya2FuIGthbmR1bmdhbiBnaXppbnlhOiBiaWppLWJpamlhbiwgc2F5dXJhbiwgYnVhaC1idWFoYW4sIG1pbnlhaywgcHJvdGVpbiwgZGFuIGxhaW4tbGFpbi4NCg0KQmFueWFrIGFsZ29yaXRtYSB0ZWxhaCBkaWtlbWJhbmdrYW4gdW50dWsgbWVsYWt1a2FuIGNsdXN0ZXJpbmcgc2VjYXJhIG90b21hdGlzLCBzYWxhaCBzYXR1IHlhbmcgc2FuZ2F0IHBvcHVsZXIgYWRhbGFoIEstTWVhbnMuDQoNCkstbWVhbnMgYWRhbGFoIGFsZ29yaXRtYSB5YW5nIG1lbWJhZ2kgZGF0YSBtZW5qYWRpIHNlanVtbGFoIHBhcnRpc2kgZGVuZ2FuIGNhcmEgc2VkZXJoYW5hOiBtZW5jYXJpIGtlZGVrYXRhbiBkYXJpIHRpYXAgdGl0aWsgcGFkYSBzdWF0dSBjbHVzdGVyIGRlbmdhbiBzZWp1bWxhaCBuaWxhaSByYXRhLXJhdGEgYXRhdSBtZWFuLg0KDQpBZGEgZHVhIGtvbnNlcCBrdW5jaSB5YW5nIGp1Z2EgbWVuamFkaSBuYW1hIGFzYWwgay1tZWFuczoNCg0KLSBKdW1sYWggcGFydGlzaSB5YW5nIGRpaW5naW5rYW4sIGRpd2FraWxpIG9sZWggaHVydWYgaw0KDQotIE1lbmNhcmkg4oCcamFyYWvigJ0ga2VkZWthdGFuIHRpYXAgdGl0aWsga2Ugc2VqdW1sYWggbmlsYWkgcmF0YS1yYXRhIGNsdXN0ZXIgeWFuZyBkaWFtYXRpLCBkaXdha2lsaSBvbGVoIG1lYW5zLiBJbmkgYmlhc2EganVnYSBkaXNlYnV0IGNlbnRyb2lkIGRpbGFtYmFuZyBvbGVoIHNpbWJvbCBzZWdpdGlnYS4NCg0KRnVuZ3NpIGttZWFucyBtZW1lcmx1a2FuIG1pbmltYWwgMiBwYXJhbWV0ZXIsIHlhaXR1Og0KDQotIHg6IGRhdGEgeWFuZyBkaWd1bmFrYW4sIGRpbWFuYSBzZW11YSBpc2kgZGF0YW55YSBoYXJ1cyBiZXJ1cGEgbnVtZXJpay4NCg0KLSBjZW50ZXJzOiBqdW1sYWggY2x1c3RlciB5YW5nIGRpaW5naW5rYW4uDQoNCk1lYW4gYXRhdSBuaWxhaSByYXRhLXJhdGEgZGlzaW5pIHNlcmluZyBkaXNlYnV0IGp1Z2EgZGVuZ2FuIGNlbnRyb2lkIHBhZGEgYmVyYmFnYWkgbGl0ZXJhdHVyIGRhdGEgc2NpZW5jZS4NCg0KRGFuIGZ1bmdzaSBrbWVhbnMgaW5pIGJpYXNhbnlhIGRpc2VydGFpIGRlbmdhbiBwZW1hbmdnaWxhbiBmdW5jdGlvbiBzZWV0LnNlZWQoKS4gSW5pIGJlcmd1bmEgYWdhciBkYXBhdCDigJxtZW55ZXJhZ2Fta2Fu4oCdIGRhZnRhciBuaWxhaSBhY2FrIHlhbmcgc2FtYSBkYXJpIGttZWFucyBzZWhpbmdnYSBtZW5kYXBhdGthbiBvdXRwdXQgeWFuZyBzYW1hLg0KDQoNCg0KDQoNCmBgYHtyfQ0KbGlicmFyeShmYWN0b2V4dHJhKQ0KDQpmdml6X25iY2x1c3QoZGZjLGttZWFucyxtZXRob2Q9IndzcyIpK2dlb21fdmxpbmUoeGludGVyY2VwdD0zLGxpbmV0eXBlPTIpDQpgYGANCg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCmttLnJlcyA8LSBrbWVhbnMoZGZjLCAzLCBuc3RhcnQgPSAxMCkNCg0KcHJpbnQoa20ucmVzJGNlbnRlcnMpDQpgYGANCg0KDQpgYGB7cn0NCnByaW50KGttLnJlcyRzaXplKQ0KYGBgDQoNCmBgYHtyfQ0KcHJpbnQoa20ucmVzJGJldHdlZW5zcy9rbS5yZXMkdG90c3MpDQpgYGANCg0KYGBge3J9DQpmdml6X2NsdXN0ZXIoa20ucmVzLCBkZmMsIGdlb20gPSAicG9pbnQiLGVsbGlwc2UudHlwZSA9ICJub3JtIixyZXBlbCA9IFRSVUUpDQpgYGANCg0KDQpgYGB7cn0NCmRmY1snY2x1c3RlciddPWFzLmZhY3RvcihrbS5yZXMkY2x1c3RlcikNCg0KaGVhZChkZmMpDQpgYGANCg0KDQpgYGB7cn0NCmF0dGFjaChkZmMpDQoNCnNwZW50cGxvdCA9IGdncGxvdChkZmMsIGFlcyh4PWNsdXN0ZXIseT10b3RhbF9zcGVudCxmaWxsPWNsdXN0ZXIpKStnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9ImJsYWNrIiwgb3V0bGllci5zaGFwZT0xNixvdXRsaWVyLnNpemU9Miwgbm90Y2g9VCkNCg0Kc3BlbnRwbG90DQpgYGANCg0KU2F5YSBkYXBhdCBtZWxpYWhhdCBwZW1pc2FoYW4geWFuZyBqZWxhcyBkYWxhbSB0b3RhbCBwZW5nZWx1YXJhbiBkaSBhbnRhcmEgMyBDbHVzdGVyLiBpbmkgYWthbiBtZW1hYmFudHUgdW50dWsgbWVtYmVyaSBuYW1hIGNsdXN0ZXINCg0KDQpgYGB7cn0NCnNwZW50cGxvdCA9IGdncGxvdChkZmMsIGFlcyh4PWNsdXN0ZXIseT1BZ2UsZmlsbD1jbHVzdGVyKSkrZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJibGFjayIsIG91dGxpZXIuc2hhcGU9MTYsb3V0bGllci5zaXplPTIsIG5vdGNoPVQpDQoNCnNwZW50cGxvdA0KYGBgDQoNCg0KYGBge3J9DQpudW1kZWFscGxvdCA9IGdncGxvdChkZmMsIGFlcyh4PWNsdXN0ZXIseT1OdW1EZWFsc1B1cmNoYXNlcyxmaWxsPWNsdXN0ZXIpKStnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9ImJsYWNrIiwgb3V0bGllci5zaGFwZT0xNixvdXRsaWVyLnNpemU9Miwgbm90Y2g9VCkNCg0KbnVtZGVhbHBsb3QNCmBgYA0KDQoNCg0KYGBge3J9DQpudW13ZWJwbG90ID0gZ2dwbG90KGRmYywgYWVzKHg9Y2x1c3Rlcix5PU51bVdlYlB1cmNoYXNlcyxmaWxsPWNsdXN0ZXIpKStnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9ImJsYWNrIiwgb3V0bGllci5zaGFwZT0xNixvdXRsaWVyLnNpemU9Miwgbm90Y2g9VCkNCg0KbnVtd2VicGxvdA0KYGBgDQoNCg0KYGBge3J9DQpudW1jYXRwbG90ID0gZ2dwbG90KGRmYywgYWVzKHg9Y2x1c3Rlcix5PU51bUNhdGFsb2dQdXJjaGFzZXMsZmlsbD1jbHVzdGVyKSkrZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJibGFjayIsIG91dGxpZXIuc2hhcGU9MTYsb3V0bGllci5zaXplPTIsIG5vdGNoPVQpDQoNCm51bWNhdHBsb3QNCmBgYA0KDQoNCg0KYGBge3J9DQpudW1jYXRwbG90ID0gZ2dwbG90KGRmYywgYWVzKHg9Y2x1c3Rlcix5PU51bUNhdGFsb2dQdXJjaGFzZXMsZmlsbD1jbHVzdGVyKSkrZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJibGFjayIsIG91dGxpZXIuc2hhcGU9MTYsb3V0bGllci5zaXplPTIsIG5vdGNoPVQpDQoNCm51bWNhdHBsb3QNCmBgYA0KDQoNCmBgYHtyfQ0KbnVtY2F0cGxvdCA9IGdncGxvdChkZmMsIGFlcyh4PWNsdXN0ZXIseT0gTnVtV2ViVmlzaXRzTW9udGgsZmlsbD1jbHVzdGVyKSkrZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJibGFjayIsIG91dGxpZXIuc2hhcGU9MTYsb3V0bGllci5zaXplPTIsIG5vdGNoPVQpDQoNCm51bWNhdHBsb3QNCmBgYA0KDQoNCiMgS2VzaW1wdWxhbg0KDQoNClNlbXVhIGZpdHVyIHlhbmcgZGlwbG90IGRpIGF0YXMgbWVtaWxpa2kgcGVtaXNhaGFuIHlhbmcgamVsYXMgYW50YXIgQ2x1c3Rlci4gIE1lbnVydXQgQW5hbHlzaXMgaW5pIHNheWEgZGFwYXQgbWVtYmVyaSBuYW1hIGtldGlnYSBLbGFzdGVyIGluaS4gKipDbHVzdGVyIDEqKiBtZW1pbGlraSBwZW1iZWxhbmphYW4gcmVuZGFoLCAqKmNsdXN0ZXIgMioqIE1lbWlsaWtpIHBlbWJlbGFuamFhbiByYXRhLXJhdGEsIGRhbiAqKkNsYXN0ZXIgMyoqIG1lbWlsaWtpIHBlbWJlbGFuamFhbiB0aW5nZ2kuIA0KDQoNCg0KLSBDbHVzdGVyIDENCg0KDQpQZW5hbXBpbGFuIGF0YXUgcGVzZWxhbmNhciBhZGFsYWggcGVsYW5nZ2FuIHlhbmcgaGFueWEgbWVuZWx1c3VyaSBsYXlhbmFuIHBlcnVzYWhhYW4gYW5kYSBkYW4gbXVuZ2tpbiBqdWdhIG1lbGloYXQgbWVsYWx1aSBwZXNhaW5nIEFuZGEuIE1lcmVrYSB0ZWxhaCBtZWxhbmp1dGthbiBtaW5hdCwgdGV0YXBpIG1lcmVrYSBiZWx1bSBtZW11dHVza2FuIGFwYSBwdW4uDQoNCg0KKipCYWdhaW1hbmEgbWVuZ2hhZGFwaSBtZXJla2EgPyoqDQoNCi0gSmFkaWthbiBzaXR1cyB3ZWIgQW5kYSB0ZXJsaWhhdCBtZW5hcmlrIHNlcGVydGkgdHVsaXNhbiBzYWxpbmFuIHlhbmcgbWVuYXJpayBkaSBoYWxhbWFuIHdlYiBBbmRhIGRhbiBwZXJ0YWhhbmthbiBkZXNhaW55YSB0ZXRhcCBpbm92YXRpZi4gUGFzdGlrYW4gQW5kYSBtZW5nYXJhaCBwZXJoYXRpYW4gY2Fsb24gcGVsYW5nZ2FuIGtlIHRlbXBhdCB5YW5nIHRlcGF0IGRlbmdhbiBtZXJhbmNhbmFrYW4gc3RyYXRlZ2kga2V0ZXJsaWJhdGFuIHNpdHVzIHdlYiB5YW5nIHRlcGF0LiANCg0KDQotIEhpbGFuZ2thbiBoYW1iYXRhbiBhdGF1IGtlYmVyYXRhbiBwYWRhIHRhaGFwIGF3YWwgaW5pIGRhbiBmb2t1c2xhaCBwYWRhIHBlbmdhbGFtYW4gY2Fsb24gcGVsYW5nZ2FuIHNhYXQgbWVuZ3VuanVuZ2kgc2l0dXMgd2ViIGFuZGEgc2VoaW5nZ2EgbWVuY2lwYXRha2FuIHBlbmdhbGFtYW4geWFuZyBiYWlrLiBCYWhrYW4gZWxlbWVuIHBvcC11cCB5YW5nIG1lbmdnYW5nZ3Ugc2VwZXJ0aSBpa2xhbiB5YW5nIG1lbmdnYW5nZ3UsICBrZXN1bGl0YW4gbWVuYXZpZ2FzaSwgYXRhdSBrdXJhbmdueWEgZHVrdW5nYW4gcGVsYW5nZ2FuIHlhbmcgY2VwYXQgZGFwYXQgZGFwYXQgbWVuZ3ViYWhueWEuDQoNCg0KDQotIENsdXN0ZXIgMg0KDQoNClBlbGFuZ2dhbiBpbXBsdXNpZiBiZWx1bSBiZW5hci1iZW5hciBiZXJlbmNhbmEgdW50dWsgbWVtYmVsaSBwcm9kdWsgQW5kYSwgYXRhdSBwcm9kdWsgYXBhcHVuIGRhbGFtIGhhbCBpbmksIGNhbG9uIHBlbGFuZ2dhbiBtZW1iZWxpIGtlcHV0dXNhbiBwZW1iZWxpYW4gc2VjYXJhIG1lbmRhZGFrLg0KDQoNCioqQmFnYWltYW5hIG1lbmdoYWRhcGkgbWVyZWthID8qKg0KDQoNCi0gQmVyaWthbiBtZXJla2EgcGVuZ2FsYW1hbiB5YW5nIG11bHVzIGRpIHNlbHVydWggY29yb25nLiBzaW5na2lya2FuIHJpbnRhbmdhbiBzZWtlY2lsIGFwYSBwdW4gZGFuIGJ1YXQgc2VsdXJ1aCBwZXJqYWxhbmFuIHBlbWJlbGlhbiBtZW5qYWRpIHNlbHVuY3VyIHlhbmcgbGljaW4uIA0KDQoNCi0gUGVuYXdhcmFuIGFraGlyIHBla2FuIHBhbGluZyBiYWlrIGRlbmdhbiBqZW5pcyBjYWxvbiBwZWxhbmdnYW4gaW5pLiBKYWRpLCB0YXdhcmthbiBtZXJla2Ega2VzZXBha2F0YW4gbWVyZWthIHRlcmlrYXQgd2F0a3UgeWFuZyBtZW5jaXBhdGFrYW4gdXJnZW5zaS4gDQoNCg0KLSBCdWF0bGFoIHNhbGluYW4gc2l0dXMgd2ViIEFuZGEgdGV0YXAgdGFqYW0gZGFuIG1lbmFyaWsuIEtlbXVkaWFuIHBlbmdndW5hIGFrYW4gbWVtYnVhdCBrZXB1dHVzYW4gcGVtYmVsaWFuIGltcGx1c2lmIHlhbmcgbWVuZ3VudHVuZ2thbiBBbmRhLg0KDQoNCg0KLSBDbHVzdGVyIDMNCg0KDQpQZWxhbmdnYW4gc2V0aWEgYWRhbGFoIGplbmlzIHBlbGFuZ2dhbiB0ZXJiYWlrIHVudHVrIGJpc25pcyBBbmRhLiBKZW5pcyBwZWxhbmdnYW4gYmVydWxhbmcgdGVydXMga2VtYmFsaSBrZXBhZGEgQW5kYSB1bnR1ayBwcm9kdWsgZGFuIGxheWFuYW4geWFuZyBiZXJiZWRhIGRhbiBtZXJla2EgdGFtcGFrbnlhIHRlcmtlc2FuIGRlbmdhbiBtZXJlayBBbmRhLiANCg0KDQoNCioqQmFnYWltYW5hIE1lbmdoYWRhcGkgbWVyZWthID8qKg0KDQoNCi0gUGVydGFtYSBUYW1waWxhbiBwZWxhbmdnYW4gc2V0aWEgQW5kYSBwYWRhIHN0dWRpIGthc3VzIEFuZGEgYXRhdSBkYXBhdGthbiB0ZXN0aW1vbmlhbCBtZXJla2EuIGluaSBha2FuIG1lbWJ1YXQgbWVyZWthIG1lcmFzYSBsZWJpaCBiZXJoYXJnYSwgZGFuIEFuZGEgbWVuZGFwYXRrYW4gbGViaWggYmFueWFrIGJ1a3RpIHNvc2lhbCB1bnR1ayBkaXRhbWJhaGthbiBrZSBzaXR1cyB3ZWIgQW5kYS4NCg0KDQotIEtlZHVhIFRlcmh1YnVuZyBkZW5nYW4gbWVyZWthIGRhbiBwYWhhbWkga2lzYWggc3Vrc2VzIG1lcmVrYS4gUGFoYW1pIGFwYSB5YW5nIG1lcmVrYSBzdWthaSBkYXJpIG1lcmVrIEFuZGEgZGFuIGFwYSB5YW5nIG1lbWJ1YXQgbWVyZWthIG1lbmphZGkgcGVsYW5nZ2FuIHNldGlhIEFuZGEuIEd1bmFrYW4gcGVuZ2FsYW1hbiBtZXJla2EgZGFuIGNvYmEgdGlydSBoYWwgeWFuZyBzYW1hIHVudHVrIHNlbXVhIHBlbGFuZ2dhbiBBbmRhIHlhbmcgbGFpbi4NCg0KDQoNCioqUGVybHUgZGlpbmdhdCBrZXNpbXB1bGFuIGNsdXN0ZXIgMSwgY2x1c3RlciAyIGRhbiBjbHVzdGVyIDMgc2F5YSBtZW5nYW1iaWwga2VzaW1wdWxhbiBkaWF0YXMgZGkgMTYgamVuaXMgcGVsYW5nZ2FuIHlhbmcgYmVyYmVkYSBkYW4gY2FyYSBtZW5kYWthdGlueWEqKg0KDQpodHRwczovL3d3dy5yZXZlY2hhdC5jb20vYmxvZy90eXBlcy1vZi1jdXN0b21lcnMvYW1wLw0KDQoNCg==