
Pendahuluan
Transformasi data adalah teknik dalam pemrosesan data yang bertujuan
untuk mengubah format, struktur, atau nilai data agar lebih sesuai untuk
analisis, eksplorasi, dan pemodelan. Beberapa alasan utama transformasi
data adalah:
- Menstabilkan Variansi – Data dengan skala yang
sangat berbeda dapat menyebabkan model menjadi tidak stabil atau sulit
dipahami. Dengan transformasi, distribusi data dapat disesuaikan agar
lebih seragam.
- Mengurangi Skewness – Data sering kali memiliki
distribusi yang miring (skewed), yang dapat mempengaruhi performa model
statistik. Transformasi dapat membantu mendekatkan distribusi ke bentuk
normal.
- Menangani Outlier – Outlier atau nilai ekstrem
dapat mendistorsi hasil analisis dan pemodelan. Teknik transformasi
dapat membantu mengurangi pengaruhnya.
- Mengubah Data Kategorikal – Data kategorikal tidak
dapat langsung digunakan dalam banyak algoritma machine learning,
sehingga perlu diubah menjadi bentuk numerik.
- Mendeteksi Pola Musiman dan Tren – Dalam analisis
deret waktu, transformasi membantu mengidentifikasi pola musiman dan
tren dengan lebih jelas.
- Mengurangi Dimensi Data – Ketika dataset memiliki
terlalu banyak variabel, analisis menjadi sulit dan memakan waktu.
Teknik seperti Principal Component Analysis (PCA) membantu
menyederhanakan struktur data tanpa kehilangan informasi penting.
Laporan ini akan membahas berbagai teknik transformasi data.
Transformasi Data
3. Scaling & Normalization
3.1 Standardization (Z-score)
Proses mengubah variabel numerik yang memiliki skala berbeda menjadi
skala yang sama dengan rata-rata 0 dan deviasi standar 1.
# Z-score Normalization
Z_score <- health_data %>%
mutate(
Age_Z = scale(age),
BMI_Z = scale(bmi),
Blood_Pressure_Z = scale(blood_pressure),
Cholesterol_Z = scale(cholesterol),
Glucose_Z = scale(glucose)
)
Penjelasan Kode
| scale(Age) |
Menstandarkan usia agar berada dalam skala satuan. |
| scale(BMI) |
Menstandarkan nilai indeks massa tubuh (IMT). |
| scale(Blood_Pressure) |
Menstandarkan tekanan darah agar tidak dominan karena skalanya
besar. |
| scale(Cholesterol) |
Menstandarkan kolesterol agar setara dengan fitur lain. |
| scale(Glucose) |
Menstandarkan glukosa agar adil dalam model prediksi. |
| scale(Heart_Rate) |
Menstandarkan detak jantung agar memiliki skala yang sama. |
Interpretasi Kesehatan
| Age_std |
Membantu melihat pengaruh usia tanpa dipengaruhi oleh rentang besar
pada data usia. |
| BMI_Std |
Membantu mendeteksi pasien dengan risiko obesitas yang memengaruhi
tekanan darah. |
| bloodpreasure_Std |
Membuat tekanan darah menjadi fitur yang sebanding untuk prediksi
atau klasifikasi. |
| kolestrol_std |
Menyetarakan pengaruh kolesterol dalam model prediksi
hipertensi. |
| Glukosa_std |
Memungkinkan pengaruh glukosa diamati secara proporsional tanpa bias
skala. |
| Heartrate_std |
Mempermudah analisis tren detak jantung terhadap kondisi lain secara
setara. |
Kesimpulan
Variabel-variabel seperti Age, BMI, Blood Pressure, Cholesterol,
Glucose, dan Heart Rate yang sebelumnya memiliki rentang skala yang
sangat berbeda sekarang ada di skala yang sama. Penskalaan ini bisa
membantu model machine learning untuk tidak cenderung menganggap satu
fitur lebih penting daripada yang lain hanya karena memiliki rentang
yang lebih besar.
Dalam mendeteksi pasien yang memiliki faktor risiko dalam
mempengaruhi tekanan darah yang akan mengakibatkan hipertensi bisa
diliat dari nilai BMI, kolestrol dan glukosa. ketiga fitur itu memiliki
rentang skala yang berbeda beda ada yang di puluhan ataupun ratusan.
Model mechine learning akan memberi bobot pada fitur kolestrol karena
memiliki rentang yang besar. Setelah di skala ketiga fitur itu ada di
skala satuan. Disini model bisa menilai dari ketiga fitur tersebut
apakah bisa mempengaruhi tekanan darah tinggi atau tidak yang akan
mengakibatkan hipertensi.
Kekurangan Skala ini masih terpengaruh terhadap outlier dibandingkan
dengan Robust Scaler.
3.2 Robust Scaler
Proses merubah variabel numerik yang memiliki skala berbeda menjadi
skala yang sama dalam dataset dan tahan terhadap outlier. Namun, masih
terpengaruhi oleh nilai yang sangat ekstrim. Penskalaan ini diperkuat
dengan median dan IQR dari tiap fitur.
# RobustScaler
Robust <- health_data %>%
mutate(
Age_robust = (age - median(age)) / IQR(age),
BMI_robust = (bmi - median(bmi)) / IQR(bmi),
BloodPressure_robust = (blood_pressure - median(blood_pressure)) / IQR(blood_pressure),
Cholesterol_robust = (cholesterol - median(cholesterol)) / IQR(cholesterol),
Glucose_robust = (glucose - median(glucose)) / IQR(glucose),
HeartRate_robust = (heart_rate - median(heart_rate)) / IQR(heart_rate)
)
Penjelasan Kode
| (age - median(age)) / IQR(age) |
Menstandarkan usia berdasarkan median dan IQR agar tidak dipengaruhi
outlier. |
| (bmi - median(bmi)) / IQR(bmi) |
Menyesuaikan nilai BMI ke skala yang lebih netral terhadap nilai
ekstrem. |
| (blood_pressure - median(…)) / IQR(…) |
Mengubah tekanan darah ke skala yang stabil dan tahan terhadap
lonjakan nilai. |
| (cholesterol - median(…)) / IQR(…) |
Mengatur kolesterol agar setara skalanya dengan fitur lain meskipun
outlier ada. |
| (glucose - median(…)) / IQR(…) |
Menormalkan kadar gula darah agar tidak didominasi oleh nilai
ekstrem. |
| (heart_rate - median(…)) / IQR(…) |
Menstabilkan nilai detak jantung untuk analisis komparatif antar
pasien. |
Interpretasi Kesehatan
| Age_robust |
Usia pasien kini distandarisasi tanpa dipengaruhi ekstrem umur yang
terlalu muda atau tua. Berguna untuk model prediktif yang sensitif
terhadap variasi usia. |
| BMI_robust |
Menilai risiko kelebihan berat badan terhadap hipertensi secara adil
dan netral. |
| BloodPressure_robust |
Memberi gambaran tekanan darah yang adil saat dibandingkan antar
pasien dengan data bervariasi. |
| Cholesterol_robust |
Menghindari bias model terhadap pasien dengan kadar kolesterol
sangat tinggi. |
| Glucose_robust |
Memastikan model melihat pola kadar glukosa tanpa tertipu nilai yang
terlalu ekstrem. |
| HeartRate_robust |
Menjadikan detak jantung setara secara skala dengan fitur lain untuk
analisis prediksi kesehatan jantung. |
Kesimpulan
Sama hal nya dengan Skala Standarisasi, Robust scaler memiliki skala
yang lebih kecil dibanding dengan Skala (standarisasi) karena median dan
IQR tidak dipengaruhi oleh nilai ekstrem yang jauh dari distribusi data
lainnya. Ini menjadikannya lebih stabil saat data memiliki outlier.
Ini membuat model mampu mengevaluasi pengaruh BMI, kolesterol, dan
glukosa secara adil terhadap tekanan darah, baik sistolik maupun
diastolik. Akhirnya, ini mendukung proses deteksi risiko hipertensi
dengan pendekatan statistik yang lebih akurat dan tidak bias.
3.3 Normalization
Proses merubah skala dalam rentang tertentu umumnya 0-1 dengan
menggunakan nilai minimum dan maksimum yang menghasilkan keseimbangan
data. Normalisasi ini akan sangat terpengaruh oleh nilai ekstrem.
# Min-Max Normalization
Min_Max <- health_data %>%
mutate(
Age_Norm = (Age - min(Age, na.rm = TRUE)) / (max(Age, na.rm = TRUE) - min(Age, na.rm = TRUE)),
BMI_Norm = (BMI - min(BMI, na.rm = TRUE)) / (max(BMI, na.rm = TRUE) - min(BMI, na.rm = TRUE)),
Blood_Pressure_Norm = (Blood_Pressure - min(Blood_Pressure, na.rm = TRUE)) / (max(Blood_Pressure, na.rm = TRUE) - min(Blood_Pressure, na.rm = TRUE)),
Cholesterol_Norm = (Cholesterol - min(Cholesterol, na.rm = TRUE)) / (max(Cholesterol, na.rm = TRUE) - min(Cholesterol, na.rm = TRUE)),
Glucose_Norm = (Glucose - min(Glucose, na.rm = TRUE)) / (max(Glucose, na.rm = TRUE) - min(Glucose, na.rm = TRUE))
)
Penjelasan Kode
| (x - min(x)) / (max(x) - min(x)) |
Mengubah skala data agar berada dalam rentang 0 hingga 1, tanpa
mengubah bentuk distribusi aslinya. Berguna untuk algoritma machine
learning yang sensitif terhadap skala, seperti KNN dan SVM. |
| na.rm = TRUE |
Mengabaikan nilai missing agar proses normalisasi tetap berjalan
tanpa error. |
Interpretasi Kesehatan
| Age_Norm |
Mengonversi umur pasien ke skala 0–1 untuk memastikan model tidak
bias terhadap rentang usia yang luas. |
| BMI_Norm |
Memastikan nilai indeks massa tubuh dibandingkan secara adil dengan
fitur lain. |
| Blood_Pressure_Norm |
Menstandarkan tekanan darah agar bisa dibandingkan langsung dengan
variabel lain dalam model prediktif. |
| Cholesterol_Norm |
Membuat kadar kolesterol dapat diinterpretasikan dalam skala
seragam. |
| Glucose_Norm |
Membantu dalam menyeimbangkan fitur glukosa dengan fitur lainnya
tanpa memperbesar bobotnya. |
Kesimpulan
Sama hal nya dengan Scaling, normalisasi ini untuk merubah rentang
agar model bisa menganggap data di setiap fitur nya memiliki bobot yang
sama. Hanya saja jika normalisasi dalam rentang diantara 0 sampai 1.
Sedangkan, skala masih ada nilai yang rentang diatas nilai 1.
Kelebihan dalam normalisasi yaitu menjaga data dalam rentang yang
seragam tanpa dipengaruhi outlier secara ekstrem. dan Kelemahannya yaitu
sangat sensitif terhadap outlier, karena min() dan max() bisa
terpengaruh nilai ekstrem.
4. Kategorial Encoding
4.1 One-Hot Encoding
One-hot encoding adalah metode transformasi variabel kategorik
menjadi bentuk numerik biner (0/1) agar bisa digunakan dalam analisis
statistik atau machine learning.
Kelebihan:
- Menghilangkan makna ordinal dari kategori (tidak mengasumsikan
urutan).
- Cocok untuk algoritma yang tidak bisa menangani data kategorik
secara langsung.
Kekurangan:
- Menambah jumlah fitur secara signifikan (terutama jika kategori
banyak).
- Bisa menyebabkan curse of dimensionality.
Contoh Penggunaan dalam R:
categorical_cols <- names(health_data)[sapply(health_data, function(x) is.factor(x) || is.character(x))]
one_hot <- dummy_cols(
health_data,
select_columns = categorical_cols,
remove_first_dummy = TRUE,
remove_selected_columns = TRUE
)
Penjelasan Fungsi
| dummy_cols() |
Membuat kolom dummy dari data kategorik. |
| remove_first_dummy = TRUE |
Menghindari dummy variable trap (multikolinearitas) dengan menghapus
satu kategori. |
| remove_selected_columns = TRUE |
Menghapus kolom kategorik asli dari dataset. |
Interpretasi Kesehatan:
| Location_Bandung = 1 |
Pasien berasal dari Bandung. |
| Health_Condition_Diabetes = 1 |
Pasien memiliki kondisi diabetes. |
Kesimpulan:
Transformasi ini mempermudah penggunaan data kategorik dalam
model prediksi dan analisis statistik.
Menghindari kesalahan interpretasi urutan pada variabel
kategorik.
Cocok digunakan bersama metode statistik dan machine learning
modern.
4.2 Frequency Encoding
Frequency encoding adalah metode pengkodean data kategorik dengan
mengganti setiap kategori dengan frekuensinya dalam data. Artinya, nilai
kategori yang lebih sering muncul akan mendapatkan nilai numerik yang
lebih tinggi.
Kelebihan:
Tidak menambah dimensi seperti one-hot encoding.
Menyimpan informasi distribusi kategori.
Efisien untuk dataset dengan banyak kategori unik.
Kekurangan:
Contoh Penggunaan dalam R:
# Fungsi frequency encoding
freq_enc <- function(col) {
tab <- table(col)
return(as.numeric(tab[col]) / length(col))
}
# Pastikan kolom lowercase
colnames(health_data) <- tolower(colnames(health_data))
# Kolom yang ingin di-encode
target_cols <- c("year", "location", "health_condition")
available_cols <- intersect(target_cols, colnames(health_data))
# Encoding frekuensi
Frequency <- health_data %>%
mutate(across(all_of(available_cols), ~ freq_enc(.), .names = "{.col}_freq"))
Penjelasan Fungsi
| table(col) |
Menghitung jumlah kemunculan tiap kategori. |
| as.numeric(tab[col]) / length(col) |
Mengubah nilai kategori menjadi proporsi kemunculannya. |
| across(…, .names = “{.col}_freq”) |
Menambahkan nama kolom hasil encoding. |
Interpretasi Kesehatan:
| location_freq = 0.30 |
Lokasi tersebut muncul sebanyak 30% dari total data. |
| health_condition_freq = 0.10 |
Kondisi kesehatan tersebut hanya muncul di 10% data. |
Kesimpulan:
Frequency encoding memberikan bobot proporsional terhadap
kemunculan kategori.
Lebih ringan secara komputasi dibanding one-hot encoding, namun
tetap menyimpan makna statistik dari data kategorik.
Cocok digunakan dalam model linear dan tree-based seperti Random
Forest dan XGBoost.
5. Feature Engineering
Feature engineering adalah proses menciptakan fitur-fitur baru dari
data yang ada untuk meningkatkan performa model machine learning. Salah
satu teknik yang sering digunakan adalah interaction features,
yaitu menggabungkan dua atau lebih fitur untuk membentuk fitur baru yang
bisa menangkap hubungan nonlinier antar variabel.
5.1 Interaction Features
Interaction features dibuat dengan mengalikan atau menggabungkan dua
fitur untuk merepresentasikan hubungan antara keduanya. Dalam kasus ini,
dibuat fitur interaksi antara umur (age) dan BMI (Body Mass
Index) untuk melihat dampak gabungan usia dan berat badan terhadap
kesehatan.
Contoh Kode R:
# Simpan nama kolom BMI ke variabel
bmi_col <- grep("bmi|imt", colnames(health_data), value = TRUE)[1]
# Buat interaksi antara age dan BMI
data_interaction <- health_data %>%
mutate(
Age_BMI_Impact = age * .data[[bmi_col]]
)
Penjelasan Fungsi
| grep(“bmi |
imt”, …) |
| age * .data[[bmi_col]] |
Mengalikan umur dan BMI untuk membuat fitur baru
Age_BMI_Impact. |
| mutate() |
Menambahkan fitur baru ke dalam data. |
Kesimpulan:
- Fitur interaksi berguna untuk mengungkap relasi tersembunyi antar
variabel.
- Dalam kasus data kesehatan, interaksi antara usia dan BMI bisa
menjadi indikator penting terhadap risiko penyakit kronis.
5.2 Ratio Features
Ratio features adalah fitur yang dibentuk dari perbandingan dua
variabel numerik. Teknik ini sering digunakan untuk menormalkan data,
menyoroti ketidakseimbangan, atau menangkap hubungan proporsional antar
variabel.
Contoh Kasus:
Dalam data kesehatan, membandingkan kadar kolesterol terhadap kadar
glukosa dapat memberikan insight tambahan tentang profil metabolik
seseorang. Maka dibuat fitur baru: Cholesterol to Glucose
Ratio.
Contoh Kode R:
data_ratio <- health_data %>%
mutate(
Cholesterol_Glucose_Ratio = cholesterol / (glucose + 1e-5)
)
Penjelasan Fungsi
| cholesterol / (glucose + 1e-5) |
Rasio antara kolesterol dan glukosa; penambahan 1e-5 mencegah
pembagian dengan nol. |
| mutate() |
Menambahkan fitur rasio baru ke dalam data. |
Kesimpulan:
- Ratio features memperkaya dataset dengan informasi
proporsional.
- Dalam konteks medis, rasio ini membantu dalam mendeteksi
ketidakseimbangan biokimia yang tidak terlihat dari nilai absolut
saja.
5.3 Group Aggregation
Group aggregation adalah teknik untuk menghitung ringkasan statistik
berdasarkan kelompok tertentu dalam data, misalnya berdasarkan ID
pasien, lokasi, atau waktu. Teknik ini berguna untuk menciptakan fitur
baru yang merangkum informasi historis atau berulang.
Contoh Kasus:
Pada dataset kesehatan, satu pasien bisa memiliki beberapa entri
kunjungan. Maka kita bisa menghitung rata-rata dan maksimum kadar
glukosa untuk tiap patient_id, serta jumlah kunjungan sebagai
fitur tambahan.
Contoh Kode R:
# Aggregate by patient
patient_glucose <- health_data %>%
group_by(patient_id) %>%
summarise(
Avg_Glucose = mean(glucose, na.rm = TRUE),
Max_Glucose = max(glucose, na.rm = TRUE),
Visits = n(),
.groups = "drop"
)
# Join with original data
health_data_joined <- left_join(health_data, patient_glucose, by = "patient_id")
| group_by(patient_id) |
Mengelompokkan data berdasarkan ID pasien. |
| summarise() |
Menghitung nilai rata-rata, maksimum, dan jumlah kunjungan. |
| left_join() |
Menggabungkan hasil agregasi kembali ke data utama. |
Manfaat dalam Konteks Medis:
Kesimpulan:
- Group aggregation menghasilkan fitur yang memperkaya data dengan
informasi ringkasan per entitas.
- Cocok untuk data yang bersifat longitudinal, seperti rekam medis
atau transaksi pelanggan.
5.5 Text Cleaning & Feature Creation
Text cleaning dan pembuatan fitur dari teks adalah langkah penting
dalam proses pembersihan data, khususnya ketika kita bekerja dengan data
yang mengandung informasi dalam format teks yang tidak terstruktur.
Salah satu langkah penting adalah mengekstraksi informasi relevan dari
teks, seperti angka atau kata-kata kunci, untuk digunakan dalam analisis
lebih lanjut.
Contoh Kasus:
Dalam dataset kesehatan, kolom patient_id mungkin mengandung angka
dan karakter lain, yang mana kita bisa mengekstraksi angka saja untuk
membuat fitur baru.
Contoh Kode R:
data_text <- health_data %>%
mutate(
Patient_Num = as.numeric(gsub("[^0-9]", "", patient_id))
)
Penjelasan Fungsi
| gsub(“[^0-9]”, ““, patient_id) |
Menggunakan fungsi gsub untuk menghapus karakter non-angka dan
mengekstraksi hanya angka dari kolom patient_id. |
| as.numeric() |
Mengonversi hasil ekstraksi menjadi format numerik. |
Manfaat dalam Konteks Medis:
- Patient_Num memberikan nomor pasien dalam format numerik
yang bisa digunakan untuk analisis lebih lanjut, seperti pengelompokan
atau identifikasi pasien berdasarkan ID numerik.
Kesimpulan:
Langkah pembersihan teks ini membantu mengubah ID pasien yang
mengandung karakter menjadi format yang lebih mudah untuk dianalisis,
terutama saat ID pasien diperlukan dalam analisis statistik atau
pembelajaran mesin.
5.6 Cumulative Features
Cumulative features mengacu pada fitur yang dihitung secara berurutan
berdasarkan data yang terurut, seperti akumulasi nilai dari variabel
tertentu sepanjang waktu. Cumulative features sering digunakan dalam
analisis time series atau data yang bersifat kronologis, seperti
penghitungan jumlah kumulatif dari suatu parameter kesehatan.
Contoh Kasus:
Dalam dataset kesehatan, kita dapat menghitung jumlah kumulatif kadar
glukosa dari waktu ke waktu untuk setiap pasien, yang memberikan
gambaran tentang perubahan tingkat glukosa sepanjang waktu.
Contoh Kode R:
data_cumulative <- health_data %>%
arrange(patient_id, date) %>%
group_by(patient_id) %>%
mutate(
Cumulative_Glucose = cumsum(glucose)
) %>%
ungroup()
Penjelasan Fungsi
| arrange(patient_id, date) |
Mengurutkan data berdasarkan ID pasien dan tanggal untuk memastikan
bahwa penghitungan kumulatif dilakukan berdasarkan urutan waktu. |
| group_by(patient_id) |
Mengelompokkan data berdasarkan ID pasien agar perhitungan kumulatif
dilakukan per pasien. |
| cumsum(glucose) |
Menghitung jumlah kumulatif kadar glukosa untuk setiap pasien dari
waktu ke waktu. |
Manfaat dalam Konteks Medis:
- Cumulative_Glucose memberikan informasi mengenai akumulasi
kadar glukosa pasien sepanjang waktu, yang bisa digunakan untuk memahami
perubahan pola glukosa, mengidentifikasi tren, dan mendeteksi
kemungkinan masalah kesehatan.
Kesimpulan:
Penghitungan fitur kumulatif seperti Cumulative_Glucose
memungkinkan pemahaman yang lebih dalam mengenai perjalanan kesehatan
pasien dari waktu ke waktu dan dapat membantu dalam pemodelan prediktif,
seperti deteksi risiko diabetes atau komplikasi terkait glukosa.
6. Outlier Handling
Dalam analisis data, outlier atau data yang menyimpang jauh dari pola
umum dapat mempengaruhi hasil analisis dan model. Oleh karena itu,
penting untuk mendeteksi dan menangani outlier dengan tepat. Beberapa
metode yang umum digunakan untuk mendeteksi outlier antara lain Z-score
dan Interquartile Range (IQR).
Contoh Kasus:
Pada dataset kesehatan ini, kita akan menggunakan dua metode untuk
mendeteksi dan menangani outlier:
Z-score untuk mendeteksi outlier pada kadar
glukosa.
IQR untuk mendeteksi outlier pada indeks massa tubuh
(BMI).
Contoh Kode R:
# Ensure all column names are lowercase
colnames(health_data) <- tolower(colnames(health_data))
# Get the exact name of glucose and BMI columns
glucose_col <- grep("glukosa|glucose", colnames(health_data), value = TRUE)[1]
bmi_col <- grep("imt|bmi", colnames(health_data), value = TRUE)[1]
# Z-score method for outlier detection (using Glucose)
z_scores <- scale(health_data[[glucose_col]])
data_outliers <- health_data %>%
mutate(
Outlier_Flag = ifelse(abs(z_scores) > 3, "Outlier", "Normal")
)
# IQR method for outlier removal (using BMI)
Q1 <- quantile(health_data[[bmi_col]], 0.25, na.rm = TRUE)
Q3 <- quantile(health_data[[bmi_col]], 0.75, na.rm = TRUE)
IQR_val <- Q3 - Q1
data_outliers_IQR <- health_data %>%
filter(
.data[[bmi_col]] > (Q1 - 1.5 * IQR_val) &
.data[[bmi_col]] < (Q3 + 1.5 * IQR_val)
)
Metode Z-Score untuk Deteksi Outlier:
Z-score digunakan untuk mendeteksi seberapa jauh suatu nilai dari
rata-rata dalam satuan deviasi standar. Dalam kasus ini, kita menghitung
Z-score untuk kadar glukosa, dan jika Z-score lebih besar dari 3 atau
lebih kecil dari -3, nilai tersebut dianggap sebagai outlier.
| scale(health_data[[glucose_col]]) |
Menghitung Z-score untuk kadar glukosa. |
| ifelse(abs(z_scores) > 3, “Outlier”, “Normal”) |
Menandai nilai yang memiliki Z-score lebih dari 3 atau kurang dari
-3 sebagai outlier. |
Metode IQR untuk Penghapusan Outlier:
Metode IQR menghitung rentang interkuartil (IQR) yang merupakan
selisih antara kuartil ketiga (Q3) dan kuartil pertama (Q1). Nilai yang
berada di luar rentang [Q1 - 1.5 IQR, Q3 + 1.5 IQR] dianggap
sebagai outlier.
| quantile(health_data[[bmi_col]], 0.25) |
Menghitung kuartil pertama (Q1) dari data BMI. |
| quantile(health_data[[bmi_col]], 0.75) |
Menghitung kuartil ketiga (Q3) dari data BMI. |
| filter(.data[[bmi_col]] > (Q1 - 1.5 * IQR_val) &
.data[[bmi_col]] < (Q3 + 1.5 * IQR_val)) |
Menyaring data BMI untuk menghapus nilai-nilai outlier di luar
rentang IQR. |
Manfaat Mengelola Outlier:
- Deteksi Dini: Mengidentifikasi outlier dengan metode yang
tepat memungkinkan pemahaman yang lebih baik tentang data dan membantu
mendeteksi masalah dalam pengukuran atau kondisi yang tidak biasa.
- Modeling: Menghapus atau menangani outlier dapat
meningkatkan kinerja model prediktif dengan menghindari distorsi yang
dapat disebabkan oleh data yang ekstrem.
Kesimpulan:
- Dengan menggunakan metode Z-score dan IQR, kita
dapat mendeteksi dan menangani outlier pada data kesehatan untuk
memastikan bahwa analisis dan model yang dibangun lebih akurat dan
representatif terhadap data asli.
7. Discretization
Discretization adalah proses mengubah variabel kontinu menjadi
kategori atau interval. Hal ini sering dilakukan untuk meningkatkan
pemahaman atau interpretasi data, serta memudahkan penerapan model
klasifikasi. Salah satu contoh yang umum adalah mengubah usia menjadi
kategori seperti “Muda”, “Paruh Baya”, dan “Tua”.
Contoh Kasus:
Pada dataset kesehatan ini, kita akan mendiskretisasikan kolom
usia menjadi tiga kategori: 1. Young (Muda) 2.
Middle-aged (Paruh Baya) 3. Old (Tua)
Kategori ini akan didasarkan pada pembagian kuantil data usia.
Contoh Kode R:
# Make sure column names are lowercase
colnames(health_data) <- tolower(colnames(health_data))
# Convert 'age' to numeric (if not already)
health_data <- health_data %>%
mutate(usia = as.numeric(age))
# Binning 'age' into age categories
binning <- health_data %>%
mutate(
age_level = cut(
age,
breaks = quantile(age, probs = c(0, 0.33, 0.66, 1), na.rm = TRUE),
labels = c("Young", "Middle-aged", "Old"),
include.lowest = TRUE
)
)
Penjelasan:
cut(age, breaks = quantile(age, probs = c(0, 0.33, 0.66, 1),
na.rm = TRUE)) digunakan untuk membagi usia berdasarkan kuantil.
0-33% usia pertama akan digolongkan ke dalam kategori
“Young” (Muda).
34-66% usia kedua akan digolongkan ke dalam kategori
“Middle-aged” (Paruh Baya).
67-100% usia ketiga akan digolongkan ke dalam kategori
“Old” (Tua).
Fungsi cut() ini juga memberikan label pada setiap kategori,
sehingga memudahkan interpretasi data.
Manfaat Discretization:
- Penyederhanaan Model: Dengan mengubah variabel kontinu
menjadi kategori, kita dapat mengurangi kompleksitas model dan
memudahkan interpretasi.
- Memperbaiki Model Klasifikasi: Kategorisasi dapat
meningkatkan kinerja model klasifikasi, terutama jika data kontinu
memiliki distribusi yang sangat miring atau tidak normal.
Kesimpulan:
Discretization dapat bermanfaat untuk mempermudah pemahaman dan
analisis data, terutama dalam kasus di mana hubungan antara variabel
kontinu dan hasil yang diinginkan tidak linier atau sulit untuk
dimodelkan secara langsung.
8. Seasonality
Seasonality atau musiman adalah pola yang muncul secara periodik
dalam data yang terkait dengan waktu, seperti pola tahunan, bulanan,
atau mingguan. Fitur seasonality sangat penting dalam analisis data time
series untuk memahami fluktuasi yang terkait dengan perubahan musiman
dalam tahun.
Pada dataset ini, kita akan membuat fitur musiman berdasarkan
informasi tanggal untuk menangkap pola tahunan.
Contoh:
- Fourier Transform untuk ekstraksi frekuensi.
- Deteksi Musiman dalam data bulanan/tahunan.
Contoh Kasus:
Untuk memodelkan seasonality dalam dataset kesehatan ini, kita akan
menambahkan fitur-fitur berikut: - Tahun (Year)
Contoh Kode R:
# Ensure lowercase column names
colnames(health_data) <- tolower(colnames(health_data))
# Try to find the column that represents the date
date_col <- grep("tanggal|date", colnames(health_data), value = TRUE)[1]
# Convert the column to Date type if not already
health_data[[date_col]] <- as.Date(health_data[[date_col]])
# Create seasonality features
seasonality <- health_data %>%
mutate(
year = year(.data[[date_col]]),
day_of_year = yday(.data[[date_col]]),
days_in_year = if_else(leap_year(.data[[date_col]]), 366, 365),
sin_year = sin(2 * pi * day_of_year / days_in_year),
cos_year = cos(2 * pi * day_of_year / days_in_year)
)
Penjelasan:
Tahun (Year): Menyimpan informasi tahun dari kolom
tanggal.
Hari dalam Tahun (Day of Year): Menghitung hari
ke-berapa dalam tahun tersebut.
Sinus dan Cosinus (sin_year dan cos_year): Mengonversi
hari dalam tahun menjadi nilai sinus dan cosinus untuk menangkap sifat
musiman dalam bentuk numerik. Ini adalah teknik umum untuk menghindari
masalah dengan model yang tidak dapat menangani data musiman yang
bersifat siklis.
Manfaat Seasonality:
- Memahami Pola Musiman: Fitur musiman dapat membantu dalam
memprediksi pola yang berulang, seperti fluktuasi kesehatan pada periode
tertentu dalam setahun.
- Peningkatan Akurasi Model: Dengan memasukkan informasi musiman dalam
model, kita dapat meningkatkan kemampuan prediksi terutama untuk data
time series.
Kesimpulan:
Fitur seasonality sangat berguna dalam dataset dengan komponen waktu
yang mempengaruhi hasil, seperti kesehatan yang dapat dipengaruhi oleh
perubahan musiman. Dengan menggunakan fitur-fitur musiman, model dapat
lebih efektif dalam menangkap pola yang terkait dengan perubahan musiman
dan meningkatkan akurasi prediksi.
Penutup
Transformasi data adalah tahap penting yang menentukan kualitas
analisis dan pemodelan. Teknik-teknik yang telah dibahas seperti
transformasi temporal, distribusi, scaling, encoding, feature
engineering, hingga handling outlier, semuanya bertujuan untuk membuat
data lebih “bersahabat” dengan algoritma analisis. Dengan pemilihan
metode yang tepat, kita dapat meningkatkan akurasi model dan membuat
interpretasi data menjadi lebih baik.
LS0tICANCnRpdGxlOiAiUEVNUk9HUkFNQU4gU0FJTlMgREFUQSAxIiAgDQpzdWJ0aXRsZTogIkVYQU0gMSBTTVQgMiIgIA0KYXV0aG9yOiAiRGFkYW4gUmFtZGFuIEhpZGF5YXQgKDUyMjQwMDI4KSIgIA0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIiAgDQpvdXRwdXQ6ICANCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUgIA0KICAgIHRodW1ibmFpbHM6IHRydWUgIA0KICAgIGxpZ2h0Ym94OiB0cnVlICANCiAgICBnYWxsZXJ5OiB0cnVlICANCiAgICBsaWJfZGlyOiBsaWJzICANCiAgICBkZl9wcmludDogInBhZ2VkIiAgDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyIgIA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgIA0KICAgIGNzczogInN0eWxlLmNzcyIgIA0KLS0tICANCg0KPGltZyBzcmM9IkZPVE8gVEVSQkFSVV8xMXpvbi5qcGciIGFsdD0iTG9nbyIgc3R5bGU9IndpZHRoOjIwMHB4OyBkaXNwbGF5OiBibG9jazsgbWFyZ2luOiBhdXRvOyI+DQoNCiMgKipQZW5kYWh1bHVhbioqICANClRyYW5zZm9ybWFzaSBkYXRhIGFkYWxhaCB0ZWtuaWsgZGFsYW0gcGVtcm9zZXNhbiBkYXRhIHlhbmcgYmVydHVqdWFuIHVudHVrIG1lbmd1YmFoIGZvcm1hdCwgc3RydWt0dXIsIGF0YXUgbmlsYWkgZGF0YSBhZ2FyIGxlYmloIHNlc3VhaSB1bnR1ayBhbmFsaXNpcywgZWtzcGxvcmFzaSwgZGFuIHBlbW9kZWxhbi4gQmViZXJhcGEgYWxhc2FuIHV0YW1hIHRyYW5zZm9ybWFzaSBkYXRhIGFkYWxhaDogIA0KDQotICoqTWVuc3RhYmlsa2FuIFZhcmlhbnNpKiog4oCTIERhdGEgZGVuZ2FuIHNrYWxhIHlhbmcgc2FuZ2F0IGJlcmJlZGEgZGFwYXQgbWVueWViYWJrYW4gbW9kZWwgbWVuamFkaSB0aWRhayBzdGFiaWwgYXRhdSBzdWxpdCBkaXBhaGFtaS4gRGVuZ2FuIHRyYW5zZm9ybWFzaSwgZGlzdHJpYnVzaSBkYXRhIGRhcGF0IGRpc2VzdWFpa2FuIGFnYXIgbGViaWggc2VyYWdhbS4NCi0gKipNZW5ndXJhbmdpIFNrZXduZXNzKiog4oCTIERhdGEgc2VyaW5nIGthbGkgbWVtaWxpa2kgZGlzdHJpYnVzaSB5YW5nIG1pcmluZyAoc2tld2VkKSwgeWFuZyBkYXBhdCBtZW1wZW5nYXJ1aGkgcGVyZm9ybWEgbW9kZWwgc3RhdGlzdGlrLiBUcmFuc2Zvcm1hc2kgZGFwYXQgbWVtYmFudHUgbWVuZGVrYXRrYW4gZGlzdHJpYnVzaSBrZSBiZW50dWsgbm9ybWFsLg0KLSAqKk1lbmFuZ2FuaSBPdXRsaWVyKiog4oCTIE91dGxpZXIgYXRhdSBuaWxhaSBla3N0cmVtIGRhcGF0IG1lbmRpc3RvcnNpIGhhc2lsIGFuYWxpc2lzIGRhbiBwZW1vZGVsYW4uIFRla25payB0cmFuc2Zvcm1hc2kgZGFwYXQgbWVtYmFudHUgbWVuZ3VyYW5naSBwZW5nYXJ1aG55YS4NCi0gKipNZW5ndWJhaCBEYXRhIEthdGVnb3Jpa2FsKiog4oCTIERhdGEga2F0ZWdvcmlrYWwgdGlkYWsgZGFwYXQgbGFuZ3N1bmcgZGlndW5ha2FuIGRhbGFtIGJhbnlhayBhbGdvcml0bWEgbWFjaGluZSBsZWFybmluZywgc2VoaW5nZ2EgcGVybHUgZGl1YmFoIG1lbmphZGkgYmVudHVrIG51bWVyaWsuDQotICoqTWVuZGV0ZWtzaSBQb2xhIE11c2ltYW4gZGFuIFRyZW4qKiDigJMgRGFsYW0gYW5hbGlzaXMgZGVyZXQgd2FrdHUsIHRyYW5zZm9ybWFzaSBtZW1iYW50dSBtZW5naWRlbnRpZmlrYXNpIHBvbGEgbXVzaW1hbiBkYW4gdHJlbiBkZW5nYW4gbGViaWggamVsYXMuDQotICoqTWVuZ3VyYW5naSBEaW1lbnNpIERhdGEqKiDigJMgS2V0aWthIGRhdGFzZXQgbWVtaWxpa2kgdGVybGFsdSBiYW55YWsgdmFyaWFiZWwsIGFuYWxpc2lzIG1lbmphZGkgc3VsaXQgZGFuIG1lbWFrYW4gd2FrdHUuIFRla25payBzZXBlcnRpIFByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMgKFBDQSkgbWVtYmFudHUgbWVueWVkZXJoYW5ha2FuIHN0cnVrdHVyIGRhdGEgdGFucGEga2VoaWxhbmdhbiBpbmZvcm1hc2kgcGVudGluZy4NCg0KTGFwb3JhbiBpbmkgYWthbiBtZW1iYWhhcyBiZXJiYWdhaSB0ZWtuaWsgdHJhbnNmb3JtYXNpIGRhdGEuDQoNCi0tLQ0KDQpgYGB7ciwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgRW5zdXJlIGFsbCByZXF1aXJlZCBwYWNrYWdlcyBhcmUgaW5zdGFsbGVkDQpwYWNrYWdlcyA8LSBjKCJkcGx5ciIsICJzdHJpbmdpIiwgImx1YnJpZGF0ZSIsICJEVCIpDQpuZXdfcGFja2FnZXMgPC0gcGFja2FnZXNbIShwYWNrYWdlcyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpWywgIlBhY2thZ2UiXSldDQppZihsZW5ndGgobmV3X3BhY2thZ2VzKSkgaW5zdGFsbC5wYWNrYWdlcyhuZXdfcGFja2FnZXMpDQoNCiMgTG9hZCBsaWJyYXJpZXMNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHN0cmluZ2kpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoRFQpDQoNCiMgQ3JlYXRlIGEgY29tcGxleCBkdW1teSBoZWFsdGggZGF0YXNldCBmb3IgZGF0YSB0cmFuc2Zvcm1hdGlvbg0Kc2V0LnNlZWQoNDIpDQpuIDwtIDUwMA0KDQpkYXRlcyA8LSBzZXEuRGF0ZShmcm9tID0gYXMuRGF0ZSgiMjAyMC0wMS0wMSIpLCB0byA9IGFzLkRhdGUoIjIwMjQtMTItMzEiKSwgYnkgPSAiZGF5IikNCnNhbXBsZV9kYXRlcyA8LSBzYW1wbGUoZGF0ZXMsIG4sIHJlcGxhY2UgPSBUUlVFKQ0KDQojIFNpbXVsYXRlIGhlYWx0aCBwYXJhbWV0ZXJzDQphZ2UgPC0gc2FtcGxlKDE4OjgwLCBuLCByZXBsYWNlID0gVFJVRSkNCmJtaSA8LSByb3VuZChybm9ybShuLCBtZWFuID0gMjUsIHNkID0gNCksIDEpICAjIEJNSSAoQm9keSBNYXNzIEluZGV4KQ0KYmxvb2RfcHJlc3N1cmUgPC0gcm91bmQocm5vcm0obiwgbWVhbiA9IDEyMCwgc2QgPSAxNSksIDEpICAjIFN5c3RvbGljIEJQDQpjaG9sZXN0ZXJvbCA8LSByb3VuZChybm9ybShuLCBtZWFuID0gMjAwLCBzZCA9IDQwKSwgMSkgICMgQ2hvbGVzdGVyb2wgKG1nL2RMKQ0KZ2x1Y29zZSA8LSByb3VuZChybm9ybShuLCBtZWFuID0gOTAsIHNkID0gMjApLCAxKSAgIyBHbHVjb3NlIChtZy9kTCkNCmhlYXJ0X3JhdGUgPC0gcm91bmQocm5vcm0obiwgbWVhbiA9IDc1LCBzZCA9IDEwKSwgMSkgICMgSGVhcnQgUmF0ZSAoYnBtKQ0KDQojIFNpbXVsYXRlIGxvY2F0aW9uIGFuZCBoZWFsdGggY29uZGl0aW9uDQpsb2NhdGlvbiA8LSBzYW1wbGUoYygiSmFrYXJ0YSIsICJCYW5kdW5nIiwgIlN1cmFiYXlhIiwgIk1lZGFuIiwgIk1ha2Fzc2FyIiksIG4sIHJlcGxhY2UgPSBUUlVFKQ0KaGVhbHRoX2NvbmRpdGlvbiA8LSBzYW1wbGUoYygiSGVhbHRoeSIsICJIeXBlcnRlbnNpb24iLCAiRGlhYmV0ZXMiLCAiT2Jlc2l0eSIsICJDYXJkaW92YXNjdWxhciBEaXNlYXNlIiksIG4sIHJlcGxhY2UgPSBUUlVFKQ0KDQojIFNpbXVsYXRlIHNlYXNvbmFsIGltcGFjdCBvbiBoZWFsdGgNCnNlYXNvbiA8LSBjYXNlX3doZW4oDQogIG1vbnRoKHNhbXBsZV9kYXRlcykgJWluJSBjKDExLCAxMiwgMSwgMikgfiAiUmFpbnkgU2Vhc29uIiwNCiAgbW9udGgoc2FtcGxlX2RhdGVzKSAlaW4lIGMoNiwgNywgOCwgOSkgfiAiRHJ5IFNlYXNvbiIsDQogIFRSVUUgfiAiVHJhbnNpdGlvbmFsIFNlYXNvbiINCikNCg0KIyBDcmVhdGUgdGhlIGhlYWx0aCBkYXRhc2V0DQpoZWFsdGhfZGF0YSA8LSB0aWJibGUoDQogIFBhdGllbnRfSUQgPSBzdHJpX3JhbmRfc3RyaW5ncyhuLCAxMiksDQogIERhdGUgPSBzYW1wbGVfZGF0ZXMsDQogIEFnZSA9IGFnZSwNCiAgQk1JID0gYm1pLA0KICBCbG9vZF9QcmVzc3VyZSA9IGJsb29kX3ByZXNzdXJlLA0KICBDaG9sZXN0ZXJvbCA9IGNob2xlc3Rlcm9sLA0KICBHbHVjb3NlID0gZ2x1Y29zZSwNCiAgSGVhcnRfUmF0ZSA9IGhlYXJ0X3JhdGUsDQogIExvY2F0aW9uID0gbG9jYXRpb24sDQogIEhlYWx0aF9Db25kaXRpb24gPSBoZWFsdGhfY29uZGl0aW9uLA0KICBTZWFzb24gPSBzZWFzb24NCikNCg0KIyBTaG93IGludGVyYWN0aXZlIHRhYmxlIHdpdGggZG93bmxvYWQgYnV0dG9ucw0KZGF0YXRhYmxlKA0KICBoZWFsdGhfZGF0YSwNCiAgZXh0ZW5zaW9ucyA9ICdCdXR0b25zJywNCiAgb3B0aW9ucyA9IGxpc3QoDQogICAgZG9tID0gJ0JmcnRpcCcsDQogICAgYnV0dG9ucyA9IGMoJ2NvcHknLCAnY3N2JywgJ2V4Y2VsJywgJ3BkZicsICdwcmludCcpLA0KICAgIHNjcm9sbFkgPSAiNDAwcHgiLA0KICAgIHNjcm9sbENvbGxhcHNlID0gVFJVRSwNCiAgICBwYWdpbmcgPSBGQUxTRQ0KICApLA0KICBjYXB0aW9uID0gaHRtbHRvb2xzOjp0YWdzJGNhcHRpb24oDQogICAgc3R5bGUgPSAnY2FwdGlvbi1zaWRlOiB0b3A7IHRleHQtYWxpZ246IGxlZnQ7IA0KICAgICAgICAgICAgIGZvbnQtc2l6ZTogMThweDsgZm9udC13ZWlnaHQ6IGJvbGQ7Jw0KICApLA0KICBjbGFzcyA9ICdzdHJpcGUgaG92ZXIgY29tcGFjdCcNCikNCmBgYA0KDQojIFRyYW5zZm9ybWFzaSBEYXRhDQoNCiMgMS5UZW1wb3JhbCBUcmFuc2Zvcm1hdGlvbg0KDQojIyAxLjEgTGFnLCBkaWZmLCByb2xsaW5nDQoNCkxhZ2dpbmcgYWRhbGFoIHRla25payB5YW5nIGRpZ3VuYWthbiB1bnR1ayBtZW5nZ2VzZXIgZGF0YSBrZSBiZWxha2FuZyBkYWxhbSBzYXR1YW4gd2FrdHUgdGVydGVudHUuIEluaSBzYW5nYXQgYmVyZ3VuYSBkYWxhbSBhbmFsaXNpcyBkZXJldCB3YWt0dSB1bnR1ayBtZW1haGFtaSBrZXRlcmthaXRhbiBhbnRhcmEgbmlsYWkgc2FhdCBpbmkgZGFuIG1hc2EgbGFsdS4NCg0KVGVrbmlrIGluaSBzZXJpbmcgZGlndW5ha2FuIGRhbGFtIG1vZGVsIHByZWRpa3RpZiBzZXBlcnRpIEFSSU1BIGRhbiByZWdyZXNpIGRlcmV0IHdha3R1LiBEZW5nYW4gbWVuZXJhcGthbiBsYWdnaW5nLCBraXRhIGRhcGF0IG1lbGloYXQgcG9sYSBwZXJnZXJha2FuIHN1YXR1IHZhcmlhYmVsIHRlcmhhZGFwIHdha3R1LCB5YW5nIG1lbXVuZ2tpbmthbiBhbmFsaXNpcyB5YW5nIGxlYmloIG1lbmRhbGFtLg0KDQojIyMgS2VsZWJpaGFuOiAgDQotIE1lbWJhbnR1IG1lbWFoYW1pIGh1YnVuZ2FuIHRlbXBvcmFsIGFudGFyYSB2YXJpYWJlbC4NCi0gQmVyZ3VuYSBkYWxhbSBwZW1vZGVsYW4gcHJlZGlrdGlmIGJlcmJhc2lzIGRlcmV0IHdha3R1Lg0KLSBNZW1iYW50dSBkYWxhbSBwZW1idWF0YW4gZml0dXIgYmFydSB1bnR1ayBtb2RlbCBtYWNoaW5lIGxlYXJuaW5nIGJlcmJhc2lzIGRlcmV0IHdha3R1Lg0KDQojIyMgS2VrdXJhbmdhbjoNCi0gRGFwYXQgbWVueWViYWJrYW4ga2VoaWxhbmdhbiBkYXRhIHBhZGEgYXdhbCBwZXJpb2RlLg0KLSBKaWthIGxhZyB0ZXJsYWx1IGJlc2FyLCBpbmZvcm1hc2kgeWFuZyByZWxldmFuIGJpc2EgaGlsYW5nLg0KLSBUaWRhayBzZWxhbHUgZWZla3RpZiBqaWthIHBvbGEgaHVidW5nYW4gYW50YXJ3YWt0dSB0aWRhayBrb25zaXN0ZW4uDQoNCg0KKkNvbnRvaCBQZW5nZ3VuYWFuOioNCg0KLSBEYWxhbSBrZXVhbmdhbiwgaGFyZ2Egc2FoYW0gaGFyaSBpbmkgYmlzYSBkaXBlbmdhcnVoaSBvbGVoIGhhcmdhIHNlYmVsdW1ueWEuDQotIERhbGFtIG1ldGVvcm9sb2dpLCBzdWh1IGhhcmkgaW5pIG11bmdraW4gYmVyZ2FudHVuZyBwYWRhIHN1aHUgYmViZXJhcGEgaGFyaSB5YW5nIGxhbHUuDQoNCmBgYHt9DQoNClRlbXBvcmFsIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBhcnJhbmdlKFBhdGllbnRfSUQsIERhdGUpICU+JQ0KICBncm91cF9ieShQYXRpZW50X0lEKSAlPiUNCiAgbXV0YXRlKA0KICAgIExhZ19CUCA9IGxhZyhCbG9vZF9QcmVzc3VyZSksDQogICAgRGlmZl9CUCA9IEJsb29kX1ByZXNzdXJlIC0gbGFnKEJsb29kX1ByZXNzdXJlKSwNCiAgICBSb2xsaW5nTWVhbl9CUF8zID0gem9vOjpyb2xsYXBwbHkoQmxvb2RfUHJlc3N1cmUsIHdpZHRoID0gMywgRlVOID0gbWVhbiwgZmlsbCA9IE5BLCBhbGlnbiA9ICJyaWdodCIpDQogICkgJT4lDQogIHVuZ3JvdXAoKQ0KYGBgICANCg0KDQojIyMgUGVuamVsYXNhbiBGdW5nc2kgDQoNCnwgRnVuZ3NpIHwgVHVqdWFuIHwNCnwtLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS18DQp8IGFycmFuZ2UoUGF0aWVudF9JRCwgRGF0ZSkgfCBNZW5ndXJ1dGthbiBkYXRhIGJlcmRhc2Fya2FuIHBhc2llbiBkYW4gdGFuZ2dhbCB1bnR1ayBtZW1hc3Rpa2FuIGtyb25vbG9naS4gfA0KfCBncm91cF9ieShQYXRpZW50X0lEKSB8IEFnYXIgdHJhbnNmb3JtYXNpIGRpbGFrdWthbiBwZXIgaW5kaXZpZHUsIGJ1a2FuIHNlbHVydWggZGF0YXNldC4gfA0KfCBsYWcoQmxvb2RfUHJlc3N1cmUpIHwgTWVuZ2FtYmlsIHRla2FuYW4gZGFyYWggc2ViZWx1bW55YSB1bnR1ayBtYXNpbmctbWFzaW5nIHBhc2llbi4gfA0KfCBEaWZmX0JQIHwgU2VsaXNpaCBhbnRhcmEgbmlsYWkgc2VrYXJhbmcgZGFuIG5pbGFpIHNlYmVsdW1ueWEg4oCUIGRpZ3VuYWthbiB1bnR1ayBtZW5kZXRla3NpIHRyZW4gbmFpay90dXJ1bi4gfA0KfCByb2xsYXBwbHkoLi4uLCB3aWR0aCA9IDMpIHwgUmF0YS1yYXRhIGRhcmkgMyBuaWxhaSB0ZXJha2hpciB1bnR1ayBtZW1iYW50dSBtZWxpaGF0IHRyZW4geWFuZyBsZWJpaCBzdGFiaWwgKHJvbGxpbmcgbWVhbikuIHwNCg0KDQojIyMgSW50ZXJwcmV0YXNpIEtlc2VoYXRhbg0KDQp8IEZpdHVyIFRyYW5zZm9ybWFzaSB8IEFydGkgJiBNYW5mYWF0IHwNCnwtLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgTGFnX0JQICAgICAgICAgICAgICAgfCBNZWxpaGF0IGVmZWsgbWFzYSBsYWx1IHRlcmhhZGFwIGtvbmRpc2kgc2FhdCBpbmkuIFBlbnRpbmcgdW50dWsgbW9kZWwgcHJlZGlrc2kuIHwNCnwgRGlmZl9CUCAgICAgICAgICAgICAgfCBNZW5naW5kaWthc2lrYW4gcGVuaW5na2F0YW4gYXRhdSBwZW51cnVuYW4gdGVrYW5hbiBkYXJhaC4gQmlzYSBtZW5hbmRha2FuIGtvbmRpc2kgc3RhYmlsIGF0YXUgbWVtYnVydWsuIHwNCnwgUm9sbGluZ01lYW5fQlBfMyAgICAgfCBNZW1iYW50dSBtZW1maWx0ZXIgZmx1a3R1YXNpIGphbmdrYSBwZW5kZWsuIEppa2EgbmlsYWkgc2FhdCBpbmkgamF1aCBkaSBhdGFzIHJhdGEtcmF0YSwgYmlzYSBqYWRpIGFsYXJtIGFub21hbGkuIHwNCg0KDQojIyMgSGFzaWwgVHJhbnNmb3JtYXNpIA0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoYmVzdE5vcm1hbGl6ZSkNCmxpYnJhcnkoRFQpDQoNClRlbXBvcmFsIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBhcnJhbmdlKFBhdGllbnRfSUQsIERhdGUpICU+JQ0KICBncm91cF9ieShQYXRpZW50X0lEKSAlPiUNCiAgbXV0YXRlKA0KICAgIExhZ19CUCA9IGxhZyhCbG9vZF9QcmVzc3VyZSksDQogICAgRGlmZl9CUCA9IEJsb29kX1ByZXNzdXJlIC0gbGFnKEJsb29kX1ByZXNzdXJlKSwNCiAgICBSb2xsaW5nTWVhbl9CUF8zID0gem9vOjpyb2xsYXBwbHkoQmxvb2RfUHJlc3N1cmUsIHdpZHRoID0gMywgRlVOID0gbWVhbiwgZmlsbCA9IE5BLCBhbGlnbiA9ICJyaWdodCIpDQogICkgJT4lDQogIHVuZ3JvdXAoKQ0KDQpEVDo6ZGF0YXRhYmxlKFRlbXBvcmFsLCBjYXB0aW9uID0gIkxhZywgRGlmZiwgUm9sbGluZyAtIEJsb29kIFByZXNzdXJlIikNCmBgYA0KDQoNCg0KDQpTZW11YSBuaWxhaSAqTGFnX0JQLCBEaWZmX0JQLCBkYW4gUm9sbGluZ01lYW5fQlBfMyogYmVybmlsYWkgTkEga2FyZW5hIGluaSBhZGFsYWggYmFyaXMgcGVydGFtYSB1bnR1ayBtYXNpbmctbWFzaW5nIHBhc2llbi4gVGFucGEgb2JzZXJ2YXNpIHNlYmVsdW1ueWEsIHRpZGFrIG11bmdraW4gbWVuZ2hpdHVuZyBuaWxhaSBsYWcsIHNlbGlzaWgsIGF0YXUgcmF0YS1yYXRhIGJlcmd1bGlyLg0KDQoNCiMjIDEuMiBFeHRyYWN0IEhvdXIsIERheSwgTW9udGgsIFllYXINCg0KRWtzdHJha3NpIHdha3R1IGFkYWxhaCBwcm9zZXMgbWVuZ2FtYmlsIGJhZ2lhbiBzcGVzaWZpayBkYXJpIHRpbWVzdGFtcCwgc2VwZXJ0aSBqYW0sIGhhcmksIGJ1bGFuLCBhdGF1IHRhaHVuLiAgDQpJbmkgYmVyZ3VuYSB1bnR1ayBhbmFsaXNpcyBtdXNpbWFuIGF0YXUgcG9sYSBwZXJpbGFrdSBwZW5nZ3VuYSBiZXJkYXNhcmthbiB3YWt0dS4NCg0KIyMjIEtlbGViaWhhbjoNCi0gTWVtYmFudHUgbWVuZW11a2FuIHBvbGEgYmVyZGFzYXJrYW4gd2FrdHUgKGNvbnRvaDogcGVtYmVsaWFuIGxlYmloIGJhbnlhayBkaSBha2hpciBwZWthbikuDQotIE1lbXVuZ2tpbmthbiBwZW1idWF0YW4gZml0dXIgYmFydSBkYXJpIGRhdGEgd2FrdHUuDQoNCiMjIyBLZWt1cmFuZ2FuOg0KLSBKaWthIHRpZGFrIHJlbGV2YW4gZGVuZ2FuIGFuYWxpc2lzLCBmaXR1ciBpbmkgYmlzYSBtZW5qYWRpIG5vaXNlLg0KLSBNZW1idXR1aGthbiBmb3JtYXQgdGFuZ2dhbC93YWt0dSB5YW5nIGJlbmFyLg0KDQpgYGB7fQ0KDQpFeHRyYWN0IDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgRGF5X29mX1dlZWsgPSB3ZWVrZGF5cyhEYXRlKSwNCiAgICBNb250aCA9IG1vbnRoKERhdGUsIGxhYmVsID0gVFJVRSksDQogICAgWWVhciA9IHllYXIoRGF0ZSksDQogICAgSXNfV2Vla2VuZCA9IGlmZWxzZShEYXlfb2ZfV2VlayAlaW4lIGMoIlNhdHVyZGF5IiwgIlN1bmRheSIpLCAxLCAwKSwNCiAgICBMb2NhdGlvbiA9IGFzLmZhY3RvcihMb2NhdGlvbiksDQogICAgSGVhbHRoX0NvbmRpdGlvbiA9IGFzLmZhY3RvcihIZWFsdGhfQ29uZGl0aW9uKQ0KICApICU+JQ0KICBiaW5kX2NvbHMoDQogICAgYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgofiBMb2NhdGlvbiAtIDEsIGRhdGEgPSAuKSksDQogICAgYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgofiBIZWFsdGhfQ29uZGl0aW9uIC0gMSwgZGF0YSA9IC4pKQ0KICApDQpgYGAgDQoNCg0KDQojIyMgUGVuamVsYXNhbiBGdW5nc2kgDQoNCnwgRnVuZ3NpIHwgVHVqdWFuIHwNCnwtLS0tLS0tLXwtLS0tLS0tLXwNCnwgd2Vla2RheXMoRGF0ZSkgfCBNZW5lbnR1a2FuIG5hbWEgaGFyaSBiZXJkYXNhcmthbiB0YW5nZ2FsIChtaXNhbG55YSBTZW5pbiwgU2VsYXNhLCBkbGwuKS4gfA0KfCBtb250aChEYXRlLCBsYWJlbCA9IFRSVUUpIHwgTWVuZ2FtYmlsIGJ1bGFuIGRhcmkgdGFuZ2dhbCBkYW4gbWVtYmVyaSBsYWJlbCAoY29udG9oOiBKYW4sIEZlYiwgZHN0LikuIHwNCnwgeWVhcihEYXRlKSB8IE1lbmdhbWJpbCB0YWh1biBkYXJpIHRhbmdnYWwgdW50dWsgYW5hbGlzaXMgbXVzaW1hbiBhdGF1IHRhaHVuYW4uIHwNCnwgaWZlbHNlKERheV9vZl9XZWVrICVpbiUgYygiU2F0dXJkYXkiLCAiU3VuZGF5IiksIDEsIDApIHwgTWVuZW50dWthbiBhcGFrYWggdGFuZ2dhbCB0ZXJzZWJ1dCBqYXR1aCBwYWRhIGFraGlyIHBla2FuIChTYWJ0dS9NaW5nZ3UpLiB8DQp8IGFzLmZhY3RvcihMb2NhdGlvbikgfCBNZW5ndWJhaCBsb2thc2kgbWVuamFkaSB2YXJpYWJlbCBrYXRlZ29yaS4gfA0KfCBhcy5mYWN0b3IoSGVhbHRoX0NvbmRpdGlvbikgfCBNZW5ndWJhaCBrb25kaXNpIGtlc2VoYXRhbiBtZW5qYWRpIHZhcmlhYmVsIGthdGVnb3JpLiB8DQp8IG1vZGVsLm1hdHJpeCh+IExvY2F0aW9uIC0gMSkgfCBNZW5nZ3VuYWthbiBvbmUtaG90IGVuY29kaW5nIHVudHVrIG1lbmdvbnZlcnNpIGxva2FzaSBtZW5qYWRpIGtvbG9tLWtvbG9tIGJpbmVyLiB8DQp8IG1vZGVsLm1hdHJpeCh+IEhlYWx0aF9Db25kaXRpb24gLSAxKSB8IE1lbmdndW5ha2FuIG9uZS1ob3QgZW5jb2RpbmcgdW50dWsgbWVuZ29udmVyc2kga29uZGlzaSBrZXNlaGF0YW4gbWVuamFkaSBrb2xvbS1rb2xvbSBiaW5lci4gfA0KDQoNCg0KIyMjICBJbnRlcnByZXRhc2kgS2VzZWhhdGFuOg0KDQp8IEZpdHVyIFRyYW5zZm9ybWFzaSB8IEFydGkgJiBNYW5mYWF0IHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBEYXlfb2ZfV2VlayAgICAgICAgICB8IE1lbnllZGlha2FuIGluZm9ybWFzaSBoYXJpIGRhbGFtIG1pbmdndS4gQmVyZ3VuYSB1bnR1ayBtZW5kZXRla3NpIHBvbGEgaGFyaWFuLCBtaXNhbG55YSBhcGFrYWggYWRhIGxlYmloIGJhbnlhayBrdW5qdW5nYW4gcnVtYWggc2FraXQgZGkgYWtoaXIgcGVrYW4uIHwNCnwgTW9udGggICAgICAgICAgICAgICAgfCBNZW55ZWRpYWthbiBpbmZvcm1hc2kgdGVudGFuZyBidWxhbi4gRGFwYXQgZGlndW5ha2FuIHVudHVrIG1lbmRldGVrc2kgcG9sYSBtdXNpbWFuIGRhbGFtIGRhdGEsIHNlcGVydGkgcGVuaW5na2F0YW4ga2FzdXMgcGVueWFraXQgdGVydGVudHUgZGkgYnVsYW4gdGVydGVudHUuIHwNCnwgWWVhciAgICAgICAgICAgICAgICAgfCBNZW1iZXJpa2FuIGluZm9ybWFzaSB0YWh1bmFuLiBCZXJndW5hIHVudHVrIGFuYWxpc2lzIGphbmdrYSBwYW5qYW5nIGRhbiB0cmVuIHRhaHVuYW4sIHNlcGVydGkgcGVuaW5na2F0YW4gYXRhdSBwZW51cnVuYW4ga2VzZWhhdGFuIG1hc3lhcmFrYXQgZGFyaSB0YWh1biBrZSB0YWh1bi4gfA0KfCBJc19XZWVrZW5kICAgICAgICAgICB8IE1lbnVuanVra2FuIGFwYWthaCBkYXRhIGJlcmFzYWwgZGFyaSBha2hpciBwZWthbiBhdGF1IHRpZGFrLiBCaXNhIG1lbmphZGkgZml0dXIgdW50dWsgbWVsaWhhdCBwZXJpbGFrdSBhdGF1IHBvbGEgeWFuZyB0ZXJqYWRpIHBhZGEgaGFyaS1oYXJpIHRlcnRlbnR1LiB8DQp8IExvY2F0aW9uIChPbmUtaG90KSAgIHwgTWVuZ29udmVyc2kgbG9rYXNpIG1lbmphZGkgdmFyaWFiZWwgYmluZXIuIERhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW5nYW5hbGlzaXMgYXBha2FoIGxva2FzaSB0ZXJ0ZW50dSBiZXJodWJ1bmdhbiBkZW5nYW4ga29uZGlzaSBrZXNlaGF0YW4gdGVydGVudHUuIHwNCnwgSGVhbHRoX0NvbmRpdGlvbiAoT25lLWhvdCkgfCBNZW5nb252ZXJzaSBrb25kaXNpIGtlc2VoYXRhbiBtZW5qYWRpIHZhcmlhYmVsIGJpbmVyLiBNZW1iYW50dSBkYWxhbSBhbmFsaXNpcyB0ZXJrYWl0IGRlbmdhbiBqZW5pcyBrb25kaXNpIGtlc2VoYXRhbiBkYW4gcGVuZ2FydWhueWEgdGVyaGFkYXAgdmFyaWFiZWwgbGFpbm55YS4gfA0KDQoNCg0KIyMjIEhhc2lsIFRyYW5zZm9ybWFzaSANCg0KRGFyaSBoYXNpbCB0cmFuc2Zvcm1hc2kgZGF0YSB5YW5nIG1lbGliYXRrYW4gZWtzdHJha3NpIGluZm9ybWFzaSB3YWt0dSBkYW4gZW5jb2RpbmcgdW50dWsgbG9rYXNpIHNlcnRhIGtvbmRpc2kga2VzZWhhdGFuIHBhc2llbiwgYmVyaWt1dCBhZGFsYWggY29udG9oIHRhbXBpbGFuIGRhdGEgeWFuZyBkaXBlcm9sZWg6DQoNCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCg0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh6b28pDQpsaWJyYXJ5KGJlc3ROb3JtYWxpemUpDQpsaWJyYXJ5KERUKQ0KDQpFeHRyYWN0IDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgRGF5X29mX1dlZWsgPSB3ZWVrZGF5cyhEYXRlKSwNCiAgICBNb250aCA9IG1vbnRoKERhdGUsIGxhYmVsID0gVFJVRSksDQogICAgWWVhciA9IHllYXIoRGF0ZSksDQogICAgSXNfV2Vla2VuZCA9IGlmZWxzZShEYXlfb2ZfV2VlayAlaW4lIGMoIlNhdHVyZGF5IiwgIlN1bmRheSIpLCAxLCAwKSwNCiAgICBMb2NhdGlvbiA9IGFzLmZhY3RvcihMb2NhdGlvbiksDQogICAgSGVhbHRoX0NvbmRpdGlvbiA9IGFzLmZhY3RvcihIZWFsdGhfQ29uZGl0aW9uKQ0KICApICU+JQ0KICBiaW5kX2NvbHMoDQogICAgYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgofiBMb2NhdGlvbiAtIDEsIGRhdGEgPSAuKSksDQogICAgYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgofiBIZWFsdGhfQ29uZGl0aW9uIC0gMSwgZGF0YSA9IC4pKQ0KICApDQoNCkRUOjpkYXRhdGFibGUoRXh0cmFjdCwgY2FwdGlvbiA9ICJFeHRyYWN0IERhdGUgQ29tcG9uZW50cyIpDQpgYGANCg0KDQoNCiMjIyBLZXNpbXB1bGFuDQoNCi0gKkVrc3RyYWtzaSBXYWt0dToqIERhdGEgYmVyaGFzaWwgZGl1YmFoIGRlbmdhbiBtZW5nZWtzdHJha3NpIGVsZW1lbi1lbGVtZW4gd2FrdHUgc2VwZXJ0aSAqSGFyaSBkYWxhbSBNaW5nZ3UsIEJ1bGFuLCBkYW4gVGFodW4qLCB5YW5nIG1lbXVuZ2tpbmthbiBhbmFsaXNpcyBsZWJpaCBsYW5qdXQgdGVya2FpdCBkZW5nYW4gcG9sYSBtdXNpbWFuIGRhbiBwZXJpbGFrdSBiZXJkYXNhcmthbiB3YWt0dS4NCiAgLSBJc19XZWVrZW5kIGRpaGFzaWxrYW4gZGVuZ2FuIG1lbWJlcmlrYW4gbmlsYWkgMSBqaWthIGhhcmkgdGVyc2VidXQgYWRhbGFoIGFraGlyIHBla2FuIChTYWJ0dSBhdGF1IE1pbmdndSkgZGFuIDAgdW50dWsgaGFyaSBsYWlubnlhLCBtZW11bmdraW5rYW4gaWRlbnRpZmlrYXNpIHRyZW4gYmVyZGFzYXJrYW4gYWtoaXIgcGVrYW4gYXRhdSBoYXJpIGtlcmphLg0KICANCi0gKkxvY2F0aW9uICYgSGVhbHRoIENvbmRpdGlvbiBFbmNvZGluZzoqIExva2FzaSBkYW4ga29uZGlzaSBrZXNlaGF0YW4gcGFzaWVuIHRlbGFoIGRpdWJhaCBtZW5qYWRpICp2YXJpYWJlbCBiaW5lciB1bnR1ayBtZW11ZGFoa2FuIGFuYWxpc2lzIHN0YXRpc3RpayBkYW4gcGVtb2RlbGFuIHByZWRpa3RpZi4NCiAgLSBWYXJpYWJlbCBsb2thc2kgc2VwZXJ0aSAqTG9jYXRpb25fSmFrYXJ0YSwgTG9jYXRpb25fQmFuZHVuZywgZGFuIExvY2F0aW9uX1N1cmFiYXlhKiBkaXViYWggbWVuamFkaSBpbmRpa2F0b3IgYmluZXIgdW50dWsgc2V0aWFwIGxva2FzaS4NCiAgLSBLb25kaXNpIGtlc2VoYXRhbiBwYXNpZW4sIHNlcGVydGkgKkhlYWx0aF9Db25kaXRpb25fSGVhbHRoeSwgSGVhbHRoX0NvbmRpdGlvbl9IeXBlcnRlbnNpb24sIGRhbiBIZWFsdGhfQ29uZGl0aW9uX0RpYWJldGVzKiwganVnYSBkaXBldGFrYW4gZGFsYW0gYmVudHVrIHZhcmlhYmVsIGJpbmVyIHlhbmcgbWVuZ2dhbWJhcmthbiBrb25kaXNpIG1lZGlzIHNldGlhcCBpbmRpdmlkdS4NCg0KDQojIyAxLjMgQ3VtdWxhdGl2ZSBTdW0vTWVhbi9Db3VudA0KDQpUZWtuaWsga3VtdWxhdGlmIG1lbmdoaXR1bmcgdG90YWwgYmVyamFsYW4gKHJ1bm5pbmcgdG90YWwpLCBqdW1sYWgga2VtdW5jdWxhbiwgYXRhdSByYXRhLXJhdGEga3VtdWxhdGlmIGRhcmkgZGF0YSBiZXJkYXNhcmthbiB3YWt0dS4NCg0KIyMjIEtlbGViaWhhbjoNCi0gU2FuZ2F0IGJlcmd1bmEgdW50dWsgbWVsaWhhdCBwZXJ0dW1idWhhbiBha3VtdWxhdGlmLg0KLSBNZW1iYW50dSBkYWxhbSBtZW1vZGVsa2FuIHBlcmlsYWt1IGphbmdrYSBwYW5qYW5nLg0KDQojIyMgS2VrdXJhbmdhbjoNCg0KLSBIYXNpbCBrdW11bGF0aWYgYmlzYSBtZW5nYWJ1cmthbiBwZXJ1YmFoYW4gbG9rYWwga2VjaWwuDQoNCi0gQmlzYSBtZW1wZW5nYXJ1aGkgZGlzdHJpYnVzaSBkYXRhIG1lbmphZGkgbGViaWggc21vb3RoICh0ZXJsYWx1IGhhbHVzKS4NCg0KKkNvbnRvaCBQZW5nZ3VuYWFuIGRhbGFtIFI6Kg0KDQpgYGB7fQ0KDQpUZW1wb3JhbDMgPC0gaGVhbHRoX2RhdGEgJT4lDQogIGdyb3VwX2J5KFBhdGllbnRfSUQpICU+JQ0KICBtdXRhdGUoDQogICAgQ3VtdWxhdGl2ZV9CUCA9IGN1bXN1bShCbG9vZF9QcmVzc3VyZSksDQogICAgQ3VtdWxhdGl2ZV9HbHVjb3NlID0gY3Vtc3VtKEdsdWNvc2UpLA0KICAgIEN1bXVsYXRpdmVfQXZnSFIgPSBjdW1tZWFuKEhlYXJ0X1JhdGUpDQogICkgJT4lDQogIHVuZ3JvdXAoKQ0KYGBgIA0KDQoNCg0KIyMjIFBlbmplbGFzYW4gRnVuZ3NpIA0KDQp8IEZ1bmdzaSB8IFR1anVhbiB8DQp8LS0tLS0tLS18LS0tLS0tLS18DQp8IGN1bXN1bShCbG9vZF9QcmVzc3VyZSkgfCBNZW5naGl0dW5nIGp1bWxhaCBrdW11bGF0aWYgdGVrYW5hbiBkYXJhaCBzZXBhbmphbmcgd2FrdHUuIHwNCnwgY3Vtc3VtKEdsdWNvc2UpIHwgTWVuZ2hpdHVuZyBqdW1sYWgga3VtdWxhdGlmIGthZGFyIGdsdWtvc2Egc2VwYW5qYW5nIHdha3R1LiB8DQp8IGN1bW1lYW4oSGVhcnRfUmF0ZSkgfCBNZW5naGl0dW5nIHJhdGEtcmF0YSBrdW11bGF0aWYgZGV0YWsgamFudHVuZyBzZXBhbmphbmcgd2FrdHUuIHwNCg0KDQojIyMgSW50ZXJwcmV0YXNpIEtlc2VoYXRhbjoNCg0KfCBGaXR1ciBUcmFuc2Zvcm1hc2kgfCBBcnRpICYgTWFuZmFhdCB8DQp8LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgQ3VtdWxhdGl2ZV9CUCAgICAgICAgIHwgTWVueWVkaWFrYW4gdG90YWwga3VtdWxhdGlmIGRhcmkgdGVrYW5hbiBkYXJhaCBwYXNpZW4gc2VwYW5qYW5nIHdha3R1LiBJbmkgYmlzYSBtZW1iZXJpa2FuIGdhbWJhcmFuIG1lbmdlbmFpIHBlbmluZ2thdGFuIGF0YXUgcGVudXJ1bmFuIGtvbmRpc2kga2VzZWhhdGFuIHNlY2FyYSBrZXNlbHVydWhhbiwgbWlzYWxueWEgZGFsYW0ga2FzdXMgaGlwZXJ0ZW5zaS4gfA0KfCBDdW11bGF0aXZlX0dsdWNvc2UgICAgfCBNZW55ZWRpYWthbiB0b3RhbCBrdW11bGF0aWYga2FkYXIgZ2x1a29zYSBwYXNpZW4uIEluaSBkYXBhdCBtZW1iYW50dSBtZW1hbnRhdSBmbHVrdHVhc2kga2FkYXIgZ2x1a29zYSBzZXBhbmphbmcgd2FrdHUgZGFuIG1lbWJlcmlrYW4gZ2FtYmFyYW4gdGVudGFuZyBrZXN0YWJpbGFuIGtvbmRpc2kgcGFzaWVuIGRlbmdhbiBkaWFiZXRlcy4gfA0KfCBDdW11bGF0aXZlX0F2Z0hSICAgICAgfCBNZW55ZWRpYWthbiByYXRhLXJhdGEga3VtdWxhdGlmIGRldGFrIGphbnR1bmcgcGFzaWVuLiBJbmkgZGFwYXQgbWVtYmFudHUgbWVsaWhhdCB0cmVuIGRldGFrIGphbnR1bmcgcGFzaWVuIGRhcmkgd2FrdHUga2Ugd2FrdHUsIGFwYWthaCB0ZXJqYWRpIHBlbmluZ2thdGFuIGF0YXUgcGVudXJ1bmFuIHlhbmcgc2lnbmlmaWthbi4gfA0KDQoNCiMjIyBIYXNpbCBUcmFuc2Zvcm1hc2kNCg0KYGBge3IgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCg0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh6b28pDQpsaWJyYXJ5KGJlc3ROb3JtYWxpemUpDQpsaWJyYXJ5KERUKQ0KDQpUZW1wb3JhbDMgPC0gaGVhbHRoX2RhdGEgJT4lDQogIGdyb3VwX2J5KFBhdGllbnRfSUQpICU+JQ0KICBtdXRhdGUoDQogICAgQ3VtdWxhdGl2ZV9CUCA9IGN1bXN1bShCbG9vZF9QcmVzc3VyZSksDQogICAgQ3VtdWxhdGl2ZV9HbHVjb3NlID0gY3Vtc3VtKEdsdWNvc2UpLA0KICAgIEN1bXVsYXRpdmVfQXZnSFIgPSBjdW1tZWFuKEhlYXJ0X1JhdGUpDQogICkgJT4lDQogIHVuZ3JvdXAoKQ0KDQpEVDo6ZGF0YXRhYmxlKFRlbXBvcmFsMywgY2FwdGlvbiA9ICJDdW11bGF0aXZlIFZhbHVlcyIpDQpgYGANCg0KIyMjIEtlc2ltcHVsYW46DQoNCi0gKkN1bXVsYXRpdmUgU3VtIChjdW1zdW0pKiBkaWd1bmFrYW4gdW50dWsgbWVuZ3VrdXIgdG90YWwga3VtdWxhdGlmIGRhcmkgdmFyaWFiZWwgdGVydGVudHUgKHNlcGVydGkgdGVrYW5hbiBkYXJhaCBhdGF1IGthZGFyIGdsdWtvc2EpIGRhcmkgd2FrdHUga2Ugd2FrdHUuIFRla25payBpbmkgc2FuZ2F0IGJlcmd1bmEgdW50dWsgbWVtYWhhbWkgYmFnYWltYW5hIHN1YXR1IGtvbmRpc2kgYmVya2VtYmFuZyBkYWxhbSBqYW5na2EgcGFuamFuZy4NCg0KLSAqQ3VtdWxhdGl2ZSBNZWFuIChjdW1tZWFuKSogZGlndW5ha2FuIHVudHVrIG1lbGloYXQgdHJlbiByYXRhLXJhdGEgamFuZ2thIHBhbmphbmcsIHNlcGVydGkgZGV0YWsgamFudHVuZy4gSW5pIGRhcGF0IG1lbWJhbnR1IGRhbGFtIG1lbWFudGF1IGtlc3RhYmlsYW4ga29uZGlzaSBrZXNlaGF0YW4gcGFzaWVuLg0KDQotICpLZWxlbWFoYW4gdGVrbmlrIGt1bXVsYXRpZio6IEhhc2lsIGt1bXVsYXRpZiBiaXNhIG1lbXBlbmdhcnVoaSBkaXN0cmlidXNpIGRhdGEsIG1lbWJ1YXQgZGF0YSB0ZXJsaWhhdCBsZWJpaCBzbW9vdGggZGFuIGRhcGF0IG1lbmdhYnVya2FuIHBlcnViYWhhbiBsb2thbCBrZWNpbCB5YW5nIG11bmdraW4gc2lnbmlmaWthbi4gT2xlaCBrYXJlbmEgaXR1LCBoYXJ1cyBkaWd1bmFrYW4gZGVuZ2FuIGhhdGktaGF0aSB0ZXJnYW50dW5nIHBhZGEgdHVqdWFuwqBhbmFsaXNpcy4NCg0KLS0tDQoNCiMgMi5UcmFuc2Zvcm1hc2kgRGlzdHJpYnVzaQ0KDQojIyAyLjEgTG9nIFRyYW5zZm9ybQ0KDQpgYGB7fQ0KDQptaW5fcG9zaXRpdmUgPC0gbWluKGhlYWx0aF9kYXRhJEdsdWNvc2VbaGVhbHRoX2RhdGEkR2x1Y29zZSA+IDBdKQ0KDQpMb2cgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBTYWZlX0dsdWNvc2UgPSBpZmVsc2UoR2x1Y29zZSA8PSAwLCBtaW5fcG9zaXRpdmUsIEdsdWNvc2UpLA0KICAgIExvZ19HbHVjb3NlID0gbG9nMXAoU2FmZV9HbHVjb3NlKQ0KICApDQpgYGANCg0KDQojIyMgUGVuamVsYXNhbiBGdW5nc2kNCg0KfCBGdW5nc2kgfCBUdWp1YW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tfA0KfCBtaW4oaGVhbHRoX2RhdGEkR2x1Y29zZVtoZWFsdGhfZGF0YSRHbHVjb3NlID4gMF0pIHwgTWVuY2FyaSBuaWxhaSBnbHVrb3NhIHBvc2l0aWYgdGVya2VjaWwsIHVudHVrIG1lbmdnYW50aWthbiBuaWxhaSBub2wgYXRhdSBuZWdhdGlmLiB8DQp8IGlmZWxzZShHbHVjb3NlIDw9IDAsIG1pbl9wb3NpdGl2ZSwgR2x1Y29zZSkgfCBNZW5nZ2FudGkgbmlsYWkgZ2x1a29zYSBub2wgYXRhdSBuZWdhdGlmIGRlbmdhbiBuaWxhaSBnbHVrb3NhIHBvc2l0aWYgdGVya2VjaWwgYWdhciBhbWFuIHVudHVrIHRyYW5zZm9ybWFzaSBsb2dhcml0bWEuIHwNCnwgbG9nMXAoU2FmZV9HbHVjb3NlKSB8IE1lbmdoaXR1bmcgbG9nYXJpdG1hIG5hdHVyYWwgZGFyaSAoZ2x1a29zYSArIDEpLCBhZ2FyIGRpc3RyaWJ1c2kgZGF0YSBsZWJpaCBub3JtYWwgZGFuIG1lbmdoaW5kYXJpIGxvZygwKS4gfA0KDQotLS0NCg0KIyMjIEludGVycHJldGFzaSBLZXNlaGF0YW4gDQoNCnwgRml0dXIgVHJhbnNmb3JtYXNpIHwgQXJ0aSAmIE1hbmZhYXQgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IFNhZmVfR2x1Y29zZSAgICAgICAgIHwgTWVuamFtaW4gc2VtdWEgbmlsYWkgZ2x1a29zYSBiZXJuaWxhaSBwb3NpdGlmIHNlYmVsdW0gdHJhbnNmb3JtYXNpIGxvZ2FyaXRtYS4gSW5pIHBlbnRpbmcga2FyZW5hIGxvZygwKSB0aWRhayB0ZXJkZWZpbmlzaSwgZGFuIG5pbGFpIG5vbCBiaXNhIG11bmN1bCBha2liYXQga2VzYWxhaGFuIHBlbmNhdGF0YW4gYXRhdSBhbGF0IG1lZGlzLiB8DQp8IExvZ19HbHVjb3NlICAgICAgICAgIHwgVHJhbnNmb3JtYXNpIGxvZ2FyaXRtYSBtZW1idWF0IGRpc3RyaWJ1c2kgZ2x1a29zYSB5YW5nIGF3YWxueWEgbWlyaW5nIChza2V3ZWQpIG1lbmphZGkgbGViaWggbm9ybWFsLiBJbmkgbWVtYmFudHUgbWVuaW5na2F0a2FuIHBlcmZvcm1hIG1vZGVsIHByZWRpa3RpZiBkYW4gYW5hbGlzaXMgc3RhdGlzdGlrLiB8DQoNCi0tLQ0KDQojIyMgSGFzaWwgVHJhbnNmb3J0YXNpIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCg0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh6b28pDQpsaWJyYXJ5KGJlc3ROb3JtYWxpemUpDQpsaWJyYXJ5KERUKQ0KDQptaW5fcG9zaXRpdmUgPC0gbWluKGhlYWx0aF9kYXRhJEdsdWNvc2VbaGVhbHRoX2RhdGEkR2x1Y29zZSA+IDBdKQ0KDQpMb2cgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBTYWZlX0dsdWNvc2UgPSBpZmVsc2UoR2x1Y29zZSA8PSAwLCBtaW5fcG9zaXRpdmUsIEdsdWNvc2UpLA0KICAgIExvZ19HbHVjb3NlID0gbG9nMXAoU2FmZV9HbHVjb3NlKQ0KICApDQoNCkRUOjpkYXRhdGFibGUoTG9nLCBjYXB0aW9uID0gIkxvZyBUcmFuc2Zvcm0gb24gR2x1Y29zZSIpDQpgYGANCg0KDQoNCiMjIyBLZXNpbXB1bGFuIA0KDQotIFRyYW5zZm9ybWFzaSBsb2cxcCgpIChsb2coeCArIDEpKSBiZXJndW5hIHVudHVrIG1lbmFuZ2FuaSBkYXRhIHNrZXdlZCBkYW4gbmlsYWkgbm9sLCB0ZXJ1dGFtYSBkYWxhbSBkYXRhIGtlc2VoYXRhbiBzZXBlcnRpIGdsdWtvc2EuDQotIE1lbmdnYW50aSBuaWxhaSAwIGF0YXUgbmVnYXRpZiBkZW5nYW4gbmlsYWkgbWluaW11bSBwb3NpdGlmIGFkYWxhaCBzdHJhdGVnaSByb2J1c3QgdW50dWsgbWVuZ2hpbmRhcmkgZXJyb3IgbWF0ZW1hdGlzLg0KLSBUZWtuaWsgaW5pIHNlcmluZyBkaWd1bmFrYW4gc2ViZWx1bSBwZW1vZGVsYW4gc3RhdGlzdGlrIGF0YXUgbWFjaGluZSBsZWFybmluZywgYWdhciBoYXNpbCBhbmFsaXNpcyBtZW5qYWRpIGxlYmloIGFrdXJhdCBkYW4gc3RhYmlsLg0KDQotLS0NCg0KIyMgMi4yIEJveC1Db3gNCg0KDQpgYGB7fQ0KDQoNCkJveF9Db3ggPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBZZW9KX0JQID0gYmVzdE5vcm1hbGl6ZShCbG9vZF9QcmVzc3VyZSkkeC50LA0KICAgIFllb0pfQ2hvbCA9IGJlc3ROb3JtYWxpemUoQ2hvbGVzdGVyb2wpJHgudA0KICApDQogIA0KYGBgDQoNCiMjIyBQZW5qZWxhc2FuIEZ1bmdzaSANCg0KfCBGdW5nc2kgfCBUdWp1YW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tfA0KfCBiZXN0Tm9ybWFsaXplKEJsb29kX1ByZXNzdXJlKSR4LnQgfCBNZW5lcmFwa2FuIHRyYW5zZm9ybWFzaSBub3JtYWxpc2FzaSB0ZXJiYWlrIChzZXBlcnRpIFllby1Kb2huc29uKSBrZSB2YXJpYWJlbCB0ZWthbmFuIGRhcmFoIHVudHVrIG1lbWJ1YXQgZGlzdHJpYnVzaW55YSBsZWJpaCBtZW5kZWthdGkgbm9ybWFsLiB8DQp8IGJlc3ROb3JtYWxpemUoQ2hvbGVzdGVyb2wpJHgudCB8IE1lbmVyYXBrYW4gdHJhbnNmb3JtYXNpIG5vcm1hbGlzYXNpIHRlcmJhaWsga2UgdmFyaWFiZWwga29sZXN0ZXJvbCBhZ2FyIGRpc3RyaWJ1c2lueWEgbGViaWggc2ltZXRyaXMgZGFuIGNvY29rIHVudHVrIGFuYWxpc2lzIHN0YXRpc3RpayBhdGF1IG1hY2hpbmUgbGVhcm5pbmcuIHwNCg0KLS0tDQoNCiMjIyBJbnRlcnByZXRhc2kgS2VzZWhhdGFuIA0KDQp8IEZpdHVyIFRyYW5zZm9ybWFzaSB8IEFydGkgJiBNYW5mYWF0IHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBZZW9KX0JQIHwgTWVuZ2hhc2lsa2FuIHZlcnNpIHRyYW5zZm9ybWFzaSBkYXJpIEJsb29kX1ByZXNzdXJlIHlhbmcgc3VkYWggZGlub3JtYWxpc2FzaSBtZW5nZ3VuYWthbiBtZXRvZGUgWWVvLUpvaG5zb24gYXRhdSBtZXRvZGUgdGVyYmFpayBsYWlubnlhLiBJbmkgcGVudGluZyB1bnR1ayBhbmFsaXNpcyBzdGF0aXN0aWsgeWFuZyBtZW5nYXN1bXNpa2FuIGRpc3RyaWJ1c2kgbm9ybWFsLCBzZXBlcnRpIHJlZ3Jlc2kgbGluaWVyLiB8DQp8IFllb0pfQ2hvbCB8IE1lbmdoYXNpbGthbiB2ZXJzaSB0cmFuc2Zvcm1hc2kgZGFyaSBDaG9sZXN0ZXJvbCB5YW5nIHRlbGFoIGRpbm9ybWFsaXNhc2kuIEluaSBiZXJndW5hIHVudHVrIG1lbmd1cmFuZ2kgcGVuZ2FydWggb3V0bGllciBkYW4gbWVtYnVhdCBkYXRhIGxlYmloIGNvY29rIHVudHVrIHBlbW9kZWxhbi4gfA0KDQotLS0NCg0KIyMjIEhhc2lsIFRyYW5zZm9ybWFzaQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0NCg0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeSh6b28pDQpsaWJyYXJ5KGJlc3ROb3JtYWxpemUpDQpsaWJyYXJ5KERUKQ0KDQpCb3hfQ294IDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgWWVvSl9CUCA9IGJlc3ROb3JtYWxpemUoQmxvb2RfUHJlc3N1cmUpJHgudCwNCiAgICBZZW9KX0Nob2wgPSBiZXN0Tm9ybWFsaXplKENob2xlc3Rlcm9sKSR4LnQNCiAgKQ0KDQpEVDo6ZGF0YXRhYmxlKEJveF9Db3gsIGNhcHRpb24gPSAiQm94LUNveCAvIFllby1Kb2huc29uIFRyYW5zZm9ybSIpDQpgYGANCg0KDQojIyMgS2VzaW1wdWxhbiANCg0KLSBGdW5nc2kgYmVzdE5vcm1hbGl6ZSgpIHNlY2FyYSBvdG9tYXRpcyBtZW1pbGloIHRyYW5zZm9ybWFzaSB0ZXJiYWlrIChtaXNhbG55YSBZZW8tSm9obnNvbiwgQm94LUNveCwgbG9nLCBhdGF1IGxhaW5ueWEpIHVudHVrIG1lbWJ1YXQgZGlzdHJpYnVzaSBkYXRhIGxlYmloIG1lbmRla2F0aSBub3JtYWwuDQotIFRyYW5zZm9ybWFzaSBpbmkgc2FuZ2F0IGJlcm1hbmZhYXQga2V0aWthIHZhcmlhYmVsIGlucHV0IG1lbWlsaWtpIGRpc3RyaWJ1c2kgc2tld2VkIGF0YXUgbWVuZ2FuZHVuZyBvdXRsaWVyIHlhbmcgZGFwYXQgbWVtcGVuZ2FydWhpIGhhc2lsIGFuYWxpc2lzLg0KLSBQZW5nZ3VuYWFuIG5vcm1hbGlzYXNpIHNlcGVydGkgaW5pIHNlcmluZyBkaXRlcmFwa2FuIHNlYmVsdW0gcmVncmVzaSwga2xhc2lmaWthc2ksIGF0YXUgY2x1c3RlcmluZyBhZ2FyIG1vZGVsIGxlYmloIGFrdXJhdCBkYW4gc3RhYmlsLg0KDQotLS0NCg0KIyMgMi4zIFZhcmlhbmNlIFN0YWJpbGl6YXRpb24NCg0KYGBge30NCg0KVmFyaWFuY2VfU3RhYiA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKA0KICAgIFNxcnRfQ2hvbGVzdGVyb2wgPSBzcXJ0KENob2xlc3Rlcm9sKSwNCiAgICBTcXJ0X0JNSSA9IHNxcnQoQk1JKQ0KICApDQpgYGAgIA0KDQoNCg0KDQojIyMgUGVuamVsYXNhbiBGdW5nc2kgDQoNCnwgRnVuZ3NpICAgICAgICAgICAgICAgICAgICAgICAgIHwgVHVqdWFuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBzcXJ0KENob2xlc3Rlcm9sKSAgICAgICAgICAgIHwgTWVudHJhbnNmb3JtYXNpIGtvbGVzdGVyb2wgZGVuZ2FuIGFrYXIga3VhZHJhdCB1bnR1ayBtZW5zdGFiaWxrYW4gdmFyaWFuc2kuIHwNCnwgc3FydChCTUkpICAgICAgICAgICAgICAgICAgICB8IE1lbnRyYW5zZm9ybWFzaSBpbmRla3MgbWFzc2EgdHVidWggKEJNSSkgZGVuZ2FuIGFrYXIga3VhZHJhdCBhZ2FyIGRpc3RyaWJ1c2lueWEgbGViaWggbm9ybWFsIGRhbiBtZW5ndXJhbmdpIGVmZWsgb3V0bGllci4gfA0KDQotLS0NCg0KIyMjIEludGVycHJldGFzaSBLZXNlaGF0YW4gDQoNCnwgRml0dXIgVHJhbnNmb3JtYXNpIHwgQXJ0aSAmIE1hbmZhYXQgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgU3FydF9DaG9sZXN0ZXJvbCAgIHwgTWVuZ3VyYW5naSBzZWJhcmFuIGVrc3RyZW0gcGFkYSBuaWxhaSBrb2xlc3Rlcm9sIHRpbmdnaS4gSW5pIG1lbWJhbnR1IGRhbGFtIGFuYWxpc2lzIHJlZ3Jlc2kgYXRhdSBtYWNoaW5lIGxlYXJuaW5nIGFnYXIgbW9kZWwgdGlkYWsgdGVybGFsdSBkaXBlbmdhcnVoaSBvbGVoIG91dGxpZXIuIHwNCnwgU3FydF9CTUkgICAgICAgICAgIHwgTWVtYmFudHUgbWVuc3RhYmlsa2FuIHZhcmlhbnMgQk1JIGRhbiBtZW5kZWthdGthbiBkaXN0cmlidXNpIGtlIGJlbnR1ayBub3JtYWwuIEluaSBwZW50aW5nIGppa2EgZGF0YSBha2FuIGRpZ3VuYWthbiBkYWxhbSBtb2RlbCBzdGF0aXN0aWsgeWFuZyBtZW5nYXN1bXNpa2FuIGRpc3RyaWJ1c2kgbm9ybWFsLiB8DQoNCi0tLQ0KDQojIyMgSGFzaWwgSW50ZXJwcmV0YXNpIA0KDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoYmVzdE5vcm1hbGl6ZSkNCmxpYnJhcnkoRFQpDQoNClZhcmlhbmNlX1N0YWIgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBTcXJ0X0Nob2xlc3Rlcm9sID0gc3FydChDaG9sZXN0ZXJvbCksDQogICAgU3FydF9CTUkgPSBzcXJ0KEJNSSkNCiAgKQ0KDQpEVDo6ZGF0YXRhYmxlKFZhcmlhbmNlX1N0YWIsIGNhcHRpb24gPSAiVmFyaWFuY2UgU3RhYmlsaXphdGlvbiB1c2luZyBzcXJ0KCkiKQ0KYGBgDQoNCg0KIyMjIEtlc2ltcHVsYW4gDQoNCi0gVHJhbnNmb3JtYXNpIGFrYXIga3VhZHJhdCAoc3FydCkgYWRhbGFoIG1ldG9kZSBzZWRlcmhhbmEgZGFuIGVmZWt0aWYgdW50dWsgbWVuc3RhYmlsa2FuIHZhcmlhbnNpIHBhZGEgZGF0YSB5YW5nIHBvc2l0aWYgc2tld2VkIChjb25kb25nIGtlIGthbmFuKS4NCi0gSW5pIHBlbnRpbmcgZGFsYW0gYW5hbGlzaXMgZGF0YSBtZWRpcyBrYXJlbmEgYmFueWFrIG5pbGFpIGJpb21ldHJpayAoc2VwZXJ0aSBrb2xlc3Rlcm9sIGRhbiBCTUkpIHRpZGFrIHRlcmRpc3RyaWJ1c2kgbm9ybWFsIGRhbiBiaXNhIG1lbWlsaWtpIG91dGxpZXIuDQotIFRla25payBpbmkgZGFwYXQgbWVuaW5na2F0a2FuIHBlcmZvcm1hIGRhbiBpbnRlcnByZXRhYmlsaXRhcyBtb2RlbCBzdGF0aXN0aWsgeWFuZyBzZW5zaXRpZiB0ZXJoYWRhcCBiZW50dWsgZGlzdHJpYnVzaSBkYXRhLg0KDQoNCi0tLQ0KDQoNCiMgMy4gU2NhbGluZyAmIE5vcm1hbGl6YXRpb24gDQoNCiMjIDMuMSBTdGFuZGFyZGl6YXRpb24gKFotc2NvcmUpDQoNClByb3NlcyBtZW5ndWJhaCB2YXJpYWJlbCBudW1lcmlrIHlhbmcgbWVtaWxpa2kgc2thbGEgYmVyYmVkYSBtZW5qYWRpIHNrYWxhIHlhbmcgc2FtYSBkZW5nYW4gcmF0YS1yYXRhIDAgZGFuIGRldmlhc2kgc3RhbmRhciAxLg0KDQpgYGB7fQ0KDQojIFotc2NvcmUgTm9ybWFsaXphdGlvbg0KWl9zY29yZSA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKA0KICAgIEFnZV9aID0gc2NhbGUoYWdlKSwNCiAgICBCTUlfWiA9IHNjYWxlKGJtaSksDQogICAgQmxvb2RfUHJlc3N1cmVfWiA9IHNjYWxlKGJsb29kX3ByZXNzdXJlKSwNCiAgICBDaG9sZXN0ZXJvbF9aID0gc2NhbGUoY2hvbGVzdGVyb2wpLA0KICAgIEdsdWNvc2VfWiA9IHNjYWxlKGdsdWNvc2UpDQogICkNCmBgYCAgDQoNCg0KDQojIyMgUGVuamVsYXNhbiBLb2RlIA0KDQp8IEZ1bmdzaSAgICAgICAgICAgICAgICAgICAgICAgICAgfCBUdWp1YW4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IHNjYWxlKEFnZSkgICAgICAgICAgICAgICAgICAgfCBNZW5zdGFuZGFya2FuIHVzaWEgYWdhciBiZXJhZGEgZGFsYW0gc2thbGEgc2F0dWFuLiAgICAgICAgICAgICAgICAgICAgfA0KfCBzY2FsZShCTUkpICAgICAgICAgICAgICAgICAgIHwgTWVuc3RhbmRhcmthbiBuaWxhaSBpbmRla3MgbWFzc2EgdHVidWggKElNVCkuICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwgc2NhbGUoQmxvb2RfUHJlc3N1cmUpICAgICAgICB8IE1lbnN0YW5kYXJrYW4gdGVrYW5hbiBkYXJhaCBhZ2FyIHRpZGFrIGRvbWluYW4ga2FyZW5hIHNrYWxhbnlhIGJlc2FyLiB8DQp8IHNjYWxlKENob2xlc3Rlcm9sKSAgICAgICAgICAgfCBNZW5zdGFuZGFya2FuIGtvbGVzdGVyb2wgYWdhciBzZXRhcmEgZGVuZ2FuIGZpdHVyIGxhaW4uICAgICAgICAgICAgICAgfA0KfCBzY2FsZShHbHVjb3NlKSAgICAgICAgICAgICAgIHwgTWVuc3RhbmRhcmthbiBnbHVrb3NhIGFnYXIgYWRpbCBkYWxhbSBtb2RlbCBwcmVkaWtzaS4gICAgICAgICAgICAgICAgIHwNCnwgc2NhbGUoSGVhcnRfUmF0ZSkgICAgICAgICAgICB8IE1lbnN0YW5kYXJrYW4gZGV0YWsgamFudHVuZyBhZ2FyIG1lbWlsaWtpIHNrYWxhIHlhbmcgc2FtYS4gICAgICAgICAgICB8DQoNCg0KIyMjICBJbnRlcnByZXRhc2kgS2VzZWhhdGFuDQoNCnwgRml0dXIgVHJhbnNmb3JtYXNpIHwgQXJ0aSAmIE1hbmZhYXQgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBBZ2Vfc3RkICAgICAgICAgICAgfCBNZW1iYW50dSBtZWxpaGF0IHBlbmdhcnVoIHVzaWEgdGFucGEgZGlwZW5nYXJ1aGkgb2xlaCByZW50YW5nIGJlc2FyIHBhZGEgZGF0YSB1c2lhLiB8DQp8IEJNSV9TdGQgICAgICAgICAgICB8IE1lbWJhbnR1IG1lbmRldGVrc2kgcGFzaWVuIGRlbmdhbiByaXNpa28gb2Jlc2l0YXMgeWFuZyBtZW1lbmdhcnVoaSB0ZWthbmFuIGRhcmFoLiB8DQp8IGJsb29kcHJlYXN1cmVfU3RkICB8IE1lbWJ1YXQgdGVrYW5hbiBkYXJhaCBtZW5qYWRpIGZpdHVyIHlhbmcgc2ViYW5kaW5nIHVudHVrIHByZWRpa3NpIGF0YXUga2xhc2lmaWthc2kuIHwNCnwga29sZXN0cm9sX3N0ZCAgICAgIHwgTWVueWV0YXJha2FuIHBlbmdhcnVoIGtvbGVzdGVyb2wgZGFsYW0gbW9kZWwgcHJlZGlrc2kgaGlwZXJ0ZW5zaS4gfA0KfCBHbHVrb3NhX3N0ZCAgICAgICAgfCBNZW11bmdraW5rYW4gcGVuZ2FydWggZ2x1a29zYSBkaWFtYXRpIHNlY2FyYSBwcm9wb3JzaW9uYWwgdGFucGEgYmlhcyBza2FsYS4gfA0KfCBIZWFydHJhdGVfc3RkICAgICAgfCBNZW1wZXJtdWRhaCBhbmFsaXNpcyB0cmVuIGRldGFrIGphbnR1bmcgdGVyaGFkYXAga29uZGlzaSBsYWluIHNlY2FyYSBzZXRhcmEuIHwNCg0KDQojIyMgSGFzaWwgVHJhbnNmb3JtYXNpDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCg0KIyBaLVNjb3JlIFN0YW5kYXJkaXphdGlvbg0KDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoYmVzdE5vcm1hbGl6ZSkNCmxpYnJhcnkoRFQpDQoNCiMgWi1zY29yZSBOb3JtYWxpemF0aW9uDQpaX3Njb3JlIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgQWdlX1ogPSBzY2FsZShhZ2UpLA0KICAgIEJNSV9aID0gc2NhbGUoYm1pKSwNCiAgICBCbG9vZF9QcmVzc3VyZV9aID0gc2NhbGUoYmxvb2RfcHJlc3N1cmUpLA0KICAgIENob2xlc3Rlcm9sX1ogPSBzY2FsZShjaG9sZXN0ZXJvbCksDQogICAgR2x1Y29zZV9aID0gc2NhbGUoZ2x1Y29zZSkNCiAgKQ0KDQojIExpaGF0IGhhc2lsIGF3YWwNCkRUOjpkYXRhdGFibGUoWl9zY29yZSwgY2FwdGlvbiA9ICJaX3Njb3JlKCkiKQ0KDQpgYGANCg0KDQoNCg0KIyMjIEtlc2ltcHVsYW4NCg0KVmFyaWFiZWwtdmFyaWFiZWwgc2VwZXJ0aSBBZ2UsIEJNSSwgQmxvb2QgUHJlc3N1cmUsIENob2xlc3Rlcm9sLCBHbHVjb3NlLCBkYW4gSGVhcnQgUmF0ZSB5YW5nIHNlYmVsdW1ueWEgbWVtaWxpa2kgcmVudGFuZyBza2FsYSB5YW5nIHNhbmdhdCBiZXJiZWRhIHNla2FyYW5nIGFkYSBkaSBza2FsYSB5YW5nIHNhbWEuIFBlbnNrYWxhYW4gaW5pIGJpc2EgbWVtYmFudHUgbW9kZWwgbWFjaGluZSBsZWFybmluZyB1bnR1ayB0aWRhayBjZW5kZXJ1bmcgbWVuZ2FuZ2dhcCBzYXR1IGZpdHVyIGxlYmloIHBlbnRpbmcgZGFyaXBhZGEgeWFuZyBsYWluIGhhbnlhIGthcmVuYSBtZW1pbGlraSByZW50YW5nIHlhbmcgbGViaWggYmVzYXIuDQoNCkRhbGFtIG1lbmRldGVrc2kgcGFzaWVuIHlhbmcgbWVtaWxpa2kgZmFrdG9yIHJpc2lrbyBkYWxhbSBtZW1wZW5nYXJ1aGkgdGVrYW5hbiBkYXJhaCB5YW5nIGFrYW4gbWVuZ2FraWJhdGthbiAgaGlwZXJ0ZW5zaSBiaXNhIGRpbGlhdCBkYXJpIG5pbGFpIEJNSSwga29sZXN0cm9sIGRhbiBnbHVrb3NhLiBrZXRpZ2EgZml0dXIgaXR1IG1lbWlsaWtpIHJlbnRhbmcgc2thbGEgeWFuZyBiZXJiZWRhIGJlZGEgYWRhIHlhbmcgZGkgcHVsdWhhbiBhdGF1cHVuIHJhdHVzYW4uIE1vZGVsIG1lY2hpbmUgbGVhcm5pbmcgYWthbiBtZW1iZXJpIGJvYm90IHBhZGEgZml0dXIga29sZXN0cm9sIGthcmVuYSBtZW1pbGlraSByZW50YW5nIHlhbmcgYmVzYXIuIFNldGVsYWggZGkgc2thbGEga2V0aWdhIGZpdHVyIGl0dSBhZGEgZGkgc2thbGEgc2F0dWFuLiBEaXNpbmkgbW9kZWwgYmlzYSBtZW5pbGFpIGRhcmkga2V0aWdhIGZpdHVyIHRlcnNlYnV0IGFwYWthaCBiaXNhIG1lbXBlbmdhcnVoaSB0ZWthbmFuIGRhcmFoIHRpbmdnaSBhdGF1IHRpZGFrIHlhbmcgYWthbiBtZW5nYWtpYmF0a2FuIGhpcGVydGVuc2kuIA0KDQpLZWt1cmFuZ2FuIFNrYWxhIGluaSBtYXNpaCB0ZXJwZW5nYXJ1aCB0ZXJoYWRhcCBvdXRsaWVyIGRpYmFuZGluZ2thbiBkZW5nYW4gUm9idXN0IFNjYWxlci4gDQoNCg0KIyMgMy4yIFJvYnVzdCBTY2FsZXIgDQoNClByb3NlcyBtZXJ1YmFoIHZhcmlhYmVsIG51bWVyaWsgeWFuZyBtZW1pbGlraSBza2FsYSBiZXJiZWRhIG1lbmphZGkgc2thbGEgeWFuZyBzYW1hIGRhbGFtIGRhdGFzZXQgZGFuIHRhaGFuIHRlcmhhZGFwIG91dGxpZXIuIE5hbXVuLCBtYXNpaCB0ZXJwZW5nYXJ1aGkgb2xlaCBuaWxhaSB5YW5nIHNhbmdhdCBla3N0cmltLiBQZW5za2FsYWFuIGluaSBkaXBlcmt1YXQgZGVuZ2FuIG1lZGlhbiBkYW4gSVFSIGRhcmkgdGlhcCBmaXR1ci4gDQoNCmBgYHt9DQoNCiMgUm9idXN0U2NhbGVyDQoNClJvYnVzdCA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKA0KICAgIEFnZV9yb2J1c3QgPSAoYWdlIC0gbWVkaWFuKGFnZSkpIC8gSVFSKGFnZSksDQogICAgQk1JX3JvYnVzdCA9IChibWkgLSBtZWRpYW4oYm1pKSkgLyBJUVIoYm1pKSwNCiAgICBCbG9vZFByZXNzdXJlX3JvYnVzdCA9IChibG9vZF9wcmVzc3VyZSAtIG1lZGlhbihibG9vZF9wcmVzc3VyZSkpIC8gSVFSKGJsb29kX3ByZXNzdXJlKSwNCiAgICBDaG9sZXN0ZXJvbF9yb2J1c3QgPSAoY2hvbGVzdGVyb2wgLSBtZWRpYW4oY2hvbGVzdGVyb2wpKSAvIElRUihjaG9sZXN0ZXJvbCksDQogICAgR2x1Y29zZV9yb2J1c3QgPSAoZ2x1Y29zZSAtIG1lZGlhbihnbHVjb3NlKSkgLyBJUVIoZ2x1Y29zZSksDQogICAgSGVhcnRSYXRlX3JvYnVzdCA9IChoZWFydF9yYXRlIC0gbWVkaWFuKGhlYXJ0X3JhdGUpKSAvIElRUihoZWFydF9yYXRlKQ0KICApDQpgYGAgIA0KDQoNCg0KIyMjIFBlbmplbGFzYW4gS29kZSANCg0KfCBGdW5nc2kgVHJhbnNmb3JtYXNpICAgICAgICAgICAgICAgICAgICAgICAgfCBUdWp1YW4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgKGFnZSAtIG1lZGlhbihhZ2UpKSAvIElRUihhZ2UpICAgICAgICAgIHwgTWVuc3RhbmRhcmthbiB1c2lhIGJlcmRhc2Fya2FuIG1lZGlhbiBkYW4gSVFSIGFnYXIgdGlkYWsgZGlwZW5nYXJ1aGkgb3V0bGllci4gfA0KfCAoYm1pIC0gbWVkaWFuKGJtaSkpIC8gSVFSKGJtaSkgICAgICAgICAgfCBNZW55ZXN1YWlrYW4gbmlsYWkgQk1JIGtlIHNrYWxhIHlhbmcgbGViaWggbmV0cmFsIHRlcmhhZGFwIG5pbGFpIGVrc3RyZW0uICAgICB8DQp8IChibG9vZF9wcmVzc3VyZSAtIG1lZGlhbiguLi4pKSAvIElRUiguLi4pIHwgTWVuZ3ViYWggdGVrYW5hbiBkYXJhaCBrZSBza2FsYSB5YW5nIHN0YWJpbCBkYW4gdGFoYW4gdGVyaGFkYXAgbG9uamFrYW4gbmlsYWkuIHwNCnwgKGNob2xlc3Rlcm9sIC0gbWVkaWFuKC4uLikpIC8gSVFSKC4uLikgIHwgTWVuZ2F0dXIga29sZXN0ZXJvbCBhZ2FyIHNldGFyYSBza2FsYW55YSBkZW5nYW4gZml0dXIgbGFpbiBtZXNraXB1biBvdXRsaWVyIGFkYS4gfA0KfCAoZ2x1Y29zZSAtIG1lZGlhbiguLi4pKSAvIElRUiguLi4pICAgICAgfCBNZW5vcm1hbGthbiBrYWRhciBndWxhIGRhcmFoIGFnYXIgdGlkYWsgZGlkb21pbmFzaSBvbGVoIG5pbGFpIGVrc3RyZW0uICAgICAgIHwNCnwgKGhlYXJ0X3JhdGUgLSBtZWRpYW4oLi4uKSkgLyBJUVIoLi4uKSAgIHwgTWVuc3RhYmlsa2FuIG5pbGFpIGRldGFrIGphbnR1bmcgdW50dWsgYW5hbGlzaXMga29tcGFyYXRpZiBhbnRhciBwYXNpZW4uICAgICB8DQoNCg0KIyMjIEludGVycHJldGFzaSBLZXNlaGF0YW4NCg0KfCBGaXR1ciBUcmFuc2Zvcm1hc2kgICAgICB8IEFydGkgJiBNYW5mYWF0IHwNCnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBBZ2Vfcm9idXN0ICAgICAgICAgICAgICAgIHwgVXNpYSBwYXNpZW4ga2luaSBkaXN0YW5kYXJpc2FzaSB0YW5wYSBkaXBlbmdhcnVoaSBla3N0cmVtIHVtdXIgeWFuZyB0ZXJsYWx1IG11ZGEgYXRhdSB0dWEuIEJlcmd1bmEgdW50dWsgbW9kZWwgcHJlZGlrdGlmIHlhbmcgc2Vuc2l0aWYgdGVyaGFkYXAgdmFyaWFzaSB1c2lhLiB8DQp8IEJNSV9yb2J1c3QgICAgICAgICAgICAgICAgfCBNZW5pbGFpIHJpc2lrbyBrZWxlYmloYW4gYmVyYXQgYmFkYW4gdGVyaGFkYXAgaGlwZXJ0ZW5zaSBzZWNhcmEgYWRpbCBkYW4gbmV0cmFsLiB8DQp8IEJsb29kUHJlc3N1cmVfcm9idXN0ICAgICAgfCBNZW1iZXJpIGdhbWJhcmFuIHRla2FuYW4gZGFyYWggeWFuZyBhZGlsIHNhYXQgZGliYW5kaW5na2FuIGFudGFyIHBhc2llbiBkZW5nYW4gZGF0YSBiZXJ2YXJpYXNpLiB8DQp8IENob2xlc3Rlcm9sX3JvYnVzdCAgICAgICAgfCBNZW5naGluZGFyaSBiaWFzIG1vZGVsIHRlcmhhZGFwIHBhc2llbiBkZW5nYW4ga2FkYXIga29sZXN0ZXJvbCBzYW5nYXQgdGluZ2dpLiB8DQp8IEdsdWNvc2Vfcm9idXN0ICAgICAgICAgICAgfCBNZW1hc3Rpa2FuIG1vZGVsIG1lbGloYXQgcG9sYSBrYWRhciBnbHVrb3NhIHRhbnBhIHRlcnRpcHUgbmlsYWkgeWFuZyB0ZXJsYWx1IGVrc3RyZW0uIHwNCnwgSGVhcnRSYXRlX3JvYnVzdCAgICAgICAgICB8IE1lbmphZGlrYW4gZGV0YWsgamFudHVuZyBzZXRhcmEgc2VjYXJhIHNrYWxhIGRlbmdhbiBmaXR1ciBsYWluIHVudHVrIGFuYWxpc2lzIHByZWRpa3NpIGtlc2VoYXRhbiBqYW50dW5nLiB8DQoNCg0KIyMjIEhhc2lsIFRyYW5zZm9ybWFzaQ0KDQpgYGB7ciBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQoNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoem9vKQ0KbGlicmFyeShiZXN0Tm9ybWFsaXplKQ0KbGlicmFyeShEVCkNCg0KIyBSb2J1c3RTY2FsZXINCg0KUm9idXN0IDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgQWdlX3JvYnVzdCA9IChhZ2UgLSBtZWRpYW4oYWdlKSkgLyBJUVIoYWdlKSwNCiAgICBCTUlfcm9idXN0ID0gKGJtaSAtIG1lZGlhbihibWkpKSAvIElRUihibWkpLA0KICAgIEJsb29kUHJlc3N1cmVfcm9idXN0ID0gKGJsb29kX3ByZXNzdXJlIC0gbWVkaWFuKGJsb29kX3ByZXNzdXJlKSkgLyBJUVIoYmxvb2RfcHJlc3N1cmUpLA0KICAgIENob2xlc3Rlcm9sX3JvYnVzdCA9IChjaG9sZXN0ZXJvbCAtIG1lZGlhbihjaG9sZXN0ZXJvbCkpIC8gSVFSKGNob2xlc3Rlcm9sKSwNCiAgICBHbHVjb3NlX3JvYnVzdCA9IChnbHVjb3NlIC0gbWVkaWFuKGdsdWNvc2UpKSAvIElRUihnbHVjb3NlKSwNCiAgICBIZWFydFJhdGVfcm9idXN0ID0gKGhlYXJ0X3JhdGUgLSBtZWRpYW4oaGVhcnRfcmF0ZSkpIC8gSVFSKGhlYXJ0X3JhdGUpDQogICkNCg0KIyBMaWhhdCBoYXNpbCBhd2FsDQpEVDo6ZGF0YXRhYmxlKFJvYnVzdCwgY2FwdGlvbiA9ICJSb2J1c3QgU2NhbGVyKCkiKQ0KYGBgDQoNCg0KDQojIyMgS2VzaW1wdWxhbiANCg0KU2FtYSBoYWwgbnlhIGRlbmdhbiBTa2FsYSBTdGFuZGFyaXNhc2ksIFJvYnVzdCBzY2FsZXIgbWVtaWxpa2kgc2thbGEgeWFuZyBsZWJpaCBrZWNpbCBkaWJhbmRpbmcgZGVuZ2FuIFNrYWxhIChzdGFuZGFyaXNhc2kpIGthcmVuYSBtZWRpYW4gZGFuIElRUiB0aWRhayBkaXBlbmdhcnVoaSBvbGVoIG5pbGFpIGVrc3RyZW0geWFuZyBqYXVoIGRhcmkgZGlzdHJpYnVzaSBkYXRhIGxhaW5ueWEuIEluaSBtZW5qYWRpa2FubnlhIGxlYmloIHN0YWJpbCBzYWF0IGRhdGEgbWVtaWxpa2kgb3V0bGllci4NCg0KSW5pIG1lbWJ1YXQgbW9kZWwgbWFtcHUgbWVuZ2V2YWx1YXNpIHBlbmdhcnVoIEJNSSwga29sZXN0ZXJvbCwgZGFuIGdsdWtvc2Egc2VjYXJhIGFkaWwgdGVyaGFkYXAgdGVrYW5hbiBkYXJhaCwgYmFpayBzaXN0b2xpayBtYXVwdW4gZGlhc3RvbGlrLiBBa2hpcm55YSwgaW5pIG1lbmR1a3VuZyBwcm9zZXMgZGV0ZWtzaSByaXNpa28gaGlwZXJ0ZW5zaSBkZW5nYW4gcGVuZGVrYXRhbiBzdGF0aXN0aWsgeWFuZyBsZWJpaCBha3VyYXQgZGFuIHRpZGFrIGJpYXMuDQoNCiMjIDMuMyBOb3JtYWxpemF0aW9uIA0KDQpQcm9zZXMgbWVydWJhaCBza2FsYSBkYWxhbSByZW50YW5nIHRlcnRlbnR1IHVtdW1ueWEgMC0xIGRlbmdhbiBtZW5nZ3VuYWthbiBuaWxhaSBtaW5pbXVtIGRhbiBtYWtzaW11bSB5YW5nIG1lbmdoYXNpbGthbiBrZXNlaW1iYW5nYW4gZGF0YS4gTm9ybWFsaXNhc2kgaW5pIGFrYW4gc2FuZ2F0IHRlcnBlbmdhcnVoIG9sZWggbmlsYWkgZWtzdHJlbS4NCg0KYGBge30NCg0KIyBNaW4tTWF4IE5vcm1hbGl6YXRpb24NCk1pbl9NYXggPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBBZ2VfTm9ybSA9IChBZ2UgLSBtaW4oQWdlLCBuYS5ybSA9IFRSVUUpKSAvIChtYXgoQWdlLCBuYS5ybSA9IFRSVUUpIC0gbWluKEFnZSwgbmEucm0gPSBUUlVFKSksDQogICAgQk1JX05vcm0gPSAoQk1JIC0gbWluKEJNSSwgbmEucm0gPSBUUlVFKSkgLyAobWF4KEJNSSwgbmEucm0gPSBUUlVFKSAtIG1pbihCTUksIG5hLnJtID0gVFJVRSkpLA0KICAgIEJsb29kX1ByZXNzdXJlX05vcm0gPSAoQmxvb2RfUHJlc3N1cmUgLSBtaW4oQmxvb2RfUHJlc3N1cmUsIG5hLnJtID0gVFJVRSkpIC8gKG1heChCbG9vZF9QcmVzc3VyZSwgbmEucm0gPSBUUlVFKSAtIG1pbihCbG9vZF9QcmVzc3VyZSwgbmEucm0gPSBUUlVFKSksDQogICAgQ2hvbGVzdGVyb2xfTm9ybSA9IChDaG9sZXN0ZXJvbCAtIG1pbihDaG9sZXN0ZXJvbCwgbmEucm0gPSBUUlVFKSkgLyAobWF4KENob2xlc3Rlcm9sLCBuYS5ybSA9IFRSVUUpIC0gbWluKENob2xlc3Rlcm9sLCBuYS5ybSA9IFRSVUUpKSwNCiAgICBHbHVjb3NlX05vcm0gPSAoR2x1Y29zZSAtIG1pbihHbHVjb3NlLCBuYS5ybSA9IFRSVUUpKSAvIChtYXgoR2x1Y29zZSwgbmEucm0gPSBUUlVFKSAtIG1pbihHbHVjb3NlLCBuYS5ybSA9IFRSVUUpKQ0KICApDQpgYGAgIA0KDQoNCg0KIyMjIFBlbmplbGFzYW4gS29kZSANCg0KfCBGdW5nc2kgfCBUdWp1YW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tfA0KfCAoeCAtIG1pbih4KSkgLyAobWF4KHgpIC0gbWluKHgpKSB8IE1lbmd1YmFoIHNrYWxhIGRhdGEgYWdhciBiZXJhZGEgZGFsYW0gcmVudGFuZyAwIGhpbmdnYSAxLCB0YW5wYSBtZW5ndWJhaCBiZW50dWsgZGlzdHJpYnVzaSBhc2xpbnlhLiBCZXJndW5hIHVudHVrIGFsZ29yaXRtYSBtYWNoaW5lIGxlYXJuaW5nIHlhbmcgc2Vuc2l0aWYgdGVyaGFkYXAgc2thbGEsIHNlcGVydGkgS05OIGRhbiBTVk0uIHwNCnwgbmEucm0gPSBUUlVFIHwgTWVuZ2FiYWlrYW4gbmlsYWkgbWlzc2luZyBhZ2FyIHByb3NlcyBub3JtYWxpc2FzaSB0ZXRhcCBiZXJqYWxhbiB0YW5wYSBlcnJvci4gfA0KDQoNCiMjIyBJbnRlcnByZXRhc2kgS2VzZWhhdGFuDQoNCnwgRml0dXIgVGVybm9ybWFsaXNhc2kgfCBBcnRpICYgTWFuZmFhdCB8DQp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgQWdlX05vcm0gICAgICAgICAgICAgICB8IE1lbmdvbnZlcnNpIHVtdXIgcGFzaWVuIGtlIHNrYWxhIDDigJMxIHVudHVrIG1lbWFzdGlrYW4gbW9kZWwgdGlkYWsgYmlhcyB0ZXJoYWRhcCByZW50YW5nIHVzaWEgeWFuZyBsdWFzLiB8DQp8IEJNSV9Ob3JtICAgICAgICAgICAgICAgfCBNZW1hc3Rpa2FuIG5pbGFpIGluZGVrcyBtYXNzYSB0dWJ1aCBkaWJhbmRpbmdrYW4gc2VjYXJhIGFkaWwgZGVuZ2FuIGZpdHVyIGxhaW4uIHwNCnwgQmxvb2RfUHJlc3N1cmVfTm9ybSAgICB8IE1lbnN0YW5kYXJrYW4gdGVrYW5hbiBkYXJhaCBhZ2FyIGJpc2EgZGliYW5kaW5na2FuIGxhbmdzdW5nIGRlbmdhbiB2YXJpYWJlbCBsYWluIGRhbGFtIG1vZGVsIHByZWRpa3RpZi4gfA0KfCBDaG9sZXN0ZXJvbF9Ob3JtICAgICAgIHwgTWVtYnVhdCBrYWRhciBrb2xlc3Rlcm9sIGRhcGF0IGRpaW50ZXJwcmV0YXNpa2FuIGRhbGFtIHNrYWxhIHNlcmFnYW0uIHwNCnwgR2x1Y29zZV9Ob3JtICAgICAgICAgICB8IE1lbWJhbnR1IGRhbGFtIG1lbnllaW1iYW5na2FuIGZpdHVyIGdsdWtvc2EgZGVuZ2FuIGZpdHVyIGxhaW5ueWEgdGFucGEgbWVtcGVyYmVzYXIgYm9ib3RueWEuIHwNCg0KDQojIyMgSGFzaWwgVHJhbnNmb3JtYXNpDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoYmVzdE5vcm1hbGl6ZSkNCmxpYnJhcnkoRFQpDQoNCiMgUGFzdGlrYW4gbmFtYSBrb2xvbSBzdWRhaCBiZXJzaWgNCmNvbG5hbWVzKGhlYWx0aF9kYXRhKSA8LSBtYWtlLm5hbWVzKG5hbWVzKGhlYWx0aF9kYXRhKSkNCg0KDQojIE1pbi1NYXggTm9ybWFsaXphdGlvbg0KTWluX01heCA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKA0KICAgIEFnZV9Ob3JtID0gKEFnZSAtIG1pbihBZ2UsIG5hLnJtID0gVFJVRSkpIC8gKG1heChBZ2UsIG5hLnJtID0gVFJVRSkgLSBtaW4oQWdlLCBuYS5ybSA9IFRSVUUpKSwNCiAgICBCTUlfTm9ybSA9IChCTUkgLSBtaW4oQk1JLCBuYS5ybSA9IFRSVUUpKSAvIChtYXgoQk1JLCBuYS5ybSA9IFRSVUUpIC0gbWluKEJNSSwgbmEucm0gPSBUUlVFKSksDQogICAgQmxvb2RfUHJlc3N1cmVfTm9ybSA9IChCbG9vZF9QcmVzc3VyZSAtIG1pbihCbG9vZF9QcmVzc3VyZSwgbmEucm0gPSBUUlVFKSkgLyAobWF4KEJsb29kX1ByZXNzdXJlLCBuYS5ybSA9IFRSVUUpIC0gbWluKEJsb29kX1ByZXNzdXJlLCBuYS5ybSA9IFRSVUUpKSwNCiAgICBDaG9sZXN0ZXJvbF9Ob3JtID0gKENob2xlc3Rlcm9sIC0gbWluKENob2xlc3Rlcm9sLCBuYS5ybSA9IFRSVUUpKSAvIChtYXgoQ2hvbGVzdGVyb2wsIG5hLnJtID0gVFJVRSkgLSBtaW4oQ2hvbGVzdGVyb2wsIG5hLnJtID0gVFJVRSkpLA0KICAgIEdsdWNvc2VfTm9ybSA9IChHbHVjb3NlIC0gbWluKEdsdWNvc2UsIG5hLnJtID0gVFJVRSkpIC8gKG1heChHbHVjb3NlLCBuYS5ybSA9IFRSVUUpIC0gbWluKEdsdWNvc2UsIG5hLnJtID0gVFJVRSkpDQogICkNCg0KIyBUYW1waWxrYW4gdGFiZWwgaW50ZXJha3RpZiBoYXNpbCBub3JtYWxpc2FzaQ0KRFQ6OmRhdGF0YWJsZShNaW5fTWF4LCBjYXB0aW9uID0gIk1pbi1NYXggTm9ybWFsaXphdGlvbiBvZiBIZWFsdGggRGF0YSIpDQpgYGANCg0KDQoNCiMjIyBLZXNpbXB1bGFuIA0KDQpTYW1hIGhhbCBueWEgZGVuZ2FuIFNjYWxpbmcsIG5vcm1hbGlzYXNpIGluaSB1bnR1ayBtZXJ1YmFoIHJlbnRhbmcgYWdhciBtb2RlbCBiaXNhIG1lbmdhbmdnYXAgZGF0YSBkaSBzZXRpYXAgZml0dXIgbnlhIG1lbWlsaWtpIGJvYm90IHlhbmcgc2FtYS4gSGFueWEgc2FqYSBqaWthIG5vcm1hbGlzYXNpIGRhbGFtIHJlbnRhbmcgZGlhbnRhcmEgMCBzYW1wYWkgMS4gU2VkYW5na2FuLCBza2FsYSBtYXNpaCBhZGEgbmlsYWkgeWFuZyByZW50YW5nIGRpYXRhcyBuaWxhaSAxLiANCg0KS2VsZWJpaGFuIGRhbGFtIG5vcm1hbGlzYXNpIHlhaXR1IG1lbmphZ2EgZGF0YSBkYWxhbSByZW50YW5nIHlhbmcgc2VyYWdhbSB0YW5wYSBkaXBlbmdhcnVoaSBvdXRsaWVyIHNlY2FyYSBla3N0cmVtLiBkYW4gS2VsZW1haGFubnlhIHlhaXR1IHNhbmdhdCBzZW5zaXRpZiB0ZXJoYWRhcCBvdXRsaWVyLCBrYXJlbmEgbWluKCkgZGFuIG1heCgpIGJpc2EgdGVycGVuZ2FydWggbmlsYWkgZWtzdHJlbS4NCg0KDQoNCiMgNC4gS2F0ZWdvcmlhbCBFbmNvZGluZyANCg0KIyMgNC4xIE9uZS1Ib3QgRW5jb2RpbmcNCg0KT25lLWhvdCBlbmNvZGluZyBhZGFsYWggbWV0b2RlIHRyYW5zZm9ybWFzaSB2YXJpYWJlbCBrYXRlZ29yaWsgbWVuamFkaSBiZW50dWsgbnVtZXJpayBiaW5lciAoMC8xKSBhZ2FyIGJpc2EgZGlndW5ha2FuIGRhbGFtIGFuYWxpc2lzIHN0YXRpc3RpayBhdGF1IG1hY2hpbmUgbGVhcm5pbmcuDQoNCiMjIyBLZWxlYmloYW46DQotIE1lbmdoaWxhbmdrYW4gbWFrbmEgb3JkaW5hbCBkYXJpIGthdGVnb3JpICh0aWRhayBtZW5nYXN1bXNpa2FuIHVydXRhbikuDQotIENvY29rIHVudHVrIGFsZ29yaXRtYSB5YW5nIHRpZGFrIGJpc2EgbWVuYW5nYW5pIGRhdGEga2F0ZWdvcmlrIHNlY2FyYSBsYW5nc3VuZy4NCg0KIyMjIEtla3VyYW5nYW46DQotIE1lbmFtYmFoIGp1bWxhaCBmaXR1ciBzZWNhcmEgc2lnbmlmaWthbiAodGVydXRhbWEgamlrYSBrYXRlZ29yaSBiYW55YWspLg0KLSBCaXNhIG1lbnllYmFia2FuIGN1cnNlIG9mIGRpbWVuc2lvbmFsaXR5Lg0KDQoqQ29udG9oIFBlbmdndW5hYW4gZGFsYW0gUjoqDQoNCmBgYHt9DQoNCmNhdGVnb3JpY2FsX2NvbHMgPC0gbmFtZXMoaGVhbHRoX2RhdGEpW3NhcHBseShoZWFsdGhfZGF0YSwgZnVuY3Rpb24oeCkgaXMuZmFjdG9yKHgpIHx8IGlzLmNoYXJhY3Rlcih4KSldDQpvbmVfaG90IDwtIGR1bW15X2NvbHMoDQogIGhlYWx0aF9kYXRhLA0KICBzZWxlY3RfY29sdW1ucyA9IGNhdGVnb3JpY2FsX2NvbHMsDQogIHJlbW92ZV9maXJzdF9kdW1teSA9IFRSVUUsDQogIHJlbW92ZV9zZWxlY3RlZF9jb2x1bW5zID0gVFJVRQ0KKQ0KYGBgDQoNCg0KDQojIyMgUGVuamVsYXNhbiBGdW5nc2kgDQoNCnwgRnVuZ3NpIHwgVHVqdWFuIHwNCnwtLS0tLS0tLXwtLS0tLS0tLXwNCnwgZHVtbXlfY29scygpIHwgTWVtYnVhdCBrb2xvbSBkdW1teSBkYXJpIGRhdGEga2F0ZWdvcmlrLiB8DQp8IHJlbW92ZV9maXJzdF9kdW1teSA9IFRSVUUgfCBNZW5naGluZGFyaSBkdW1teSB2YXJpYWJsZSB0cmFwIChtdWx0aWtvbGluZWFyaXRhcykgZGVuZ2FuIG1lbmdoYXB1cyBzYXR1IGthdGVnb3JpLiB8DQp8IHJlbW92ZV9zZWxlY3RlZF9jb2x1bW5zID0gVFJVRSB8IE1lbmdoYXB1cyBrb2xvbSBrYXRlZ29yaWsgYXNsaSBkYXJpIGRhdGFzZXQuIHwNCg0KDQojIyMgSW50ZXJwcmV0YXNpIEtlc2VoYXRhbjoNCg0KfCBGaXR1ciBPbmUtSG90IHwgTWFrbmEgfA0KfC0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS18DQp8IExvY2F0aW9uX0JhbmR1bmcgPSAxIHwgUGFzaWVuIGJlcmFzYWwgZGFyaSBCYW5kdW5nLiB8DQp8IEhlYWx0aF9Db25kaXRpb25fRGlhYmV0ZXMgPSAxIHwgUGFzaWVuIG1lbWlsaWtpIGtvbmRpc2kgZGlhYmV0ZXMuIHwNCg0KDQojIyMgSGFzaWwgVHJhbnNmb3JtYXNpDQoNCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGZhc3REdW1taWVzKQ0KbGlicmFyeShEVCkNCg0KY2F0ZWdvcmljYWxfY29scyA8LSBuYW1lcyhoZWFsdGhfZGF0YSlbc2FwcGx5KGhlYWx0aF9kYXRhLCBmdW5jdGlvbih4KSBpcy5mYWN0b3IoeCkgfHwgaXMuY2hhcmFjdGVyKHgpKV0NCm9uZV9ob3QgPC0gZHVtbXlfY29scygNCiAgaGVhbHRoX2RhdGEsDQogIHNlbGVjdF9jb2x1bW5zID0gY2F0ZWdvcmljYWxfY29scywNCiAgcmVtb3ZlX2ZpcnN0X2R1bW15ID0gVFJVRSwNCiAgcmVtb3ZlX3NlbGVjdGVkX2NvbHVtbnMgPSBUUlVFDQopDQoNCkRUOjpkYXRhdGFibGUob25lX2hvdCwgY2FwdGlvbiA9ICJIYXNpbCBPbmUtSG90IEVuY29kaW5nIChUYW5wYSBLb2xvbSBQZXJ0YW1hIGRhbiBBc2xpKSIpDQpgYGANCg0KDQoNCiMjIyBLZXNpbXB1bGFuOg0KDQotIFRyYW5zZm9ybWFzaSBpbmkgbWVtcGVybXVkYWggcGVuZ2d1bmFhbiBkYXRhIGthdGVnb3JpayBkYWxhbSBtb2RlbCBwcmVkaWtzaSBkYW4gYW5hbGlzaXMgc3RhdGlzdGlrLg0KDQotIE1lbmdoaW5kYXJpIGtlc2FsYWhhbiBpbnRlcnByZXRhc2kgdXJ1dGFuIHBhZGEgdmFyaWFiZWwga2F0ZWdvcmlrLg0KDQotIENvY29rIGRpZ3VuYWthbiBiZXJzYW1hIG1ldG9kZSBzdGF0aXN0aWsgZGFuIG1hY2hpbmUgbGVhcm5pbmcgbW9kZXJuLg0KDQoNCiMjIDQuMiBGcmVxdWVuY3kgRW5jb2RpbmcNCg0KRnJlcXVlbmN5IGVuY29kaW5nIGFkYWxhaCBtZXRvZGUgcGVuZ2tvZGVhbiBkYXRhIGthdGVnb3JpayBkZW5nYW4gbWVuZ2dhbnRpIHNldGlhcCBrYXRlZ29yaSBkZW5nYW4gZnJla3VlbnNpbnlhIGRhbGFtIGRhdGEuIEFydGlueWEsIG5pbGFpIGthdGVnb3JpIHlhbmcgbGViaWggc2VyaW5nIG11bmN1bCBha2FuIG1lbmRhcGF0a2FuIG5pbGFpIG51bWVyaWsgeWFuZyBsZWJpaCB0aW5nZ2kuDQoNCiMjIyBLZWxlYmloYW46DQotIFRpZGFrIG1lbmFtYmFoIGRpbWVuc2kgc2VwZXJ0aSBvbmUtaG90IGVuY29kaW5nLg0KDQotIE1lbnlpbXBhbiBpbmZvcm1hc2kgZGlzdHJpYnVzaSBrYXRlZ29yaS4NCg0KLSBFZmlzaWVuIHVudHVrIGRhdGFzZXQgZGVuZ2FuIGJhbnlhayBrYXRlZ29yaSB1bmlrLg0KDQojIyMgS2VrdXJhbmdhbjoNCi0gVGlkYWsgY29jb2sgamlrYSBrYXRlZ29yaSBkZW5nYW4gZnJla3VlbnNpIHlhbmcgc2FtYSBtZW1pbGlraSBtYWtuYSBiZXJiZWRhLg0KDQotIEJpc2EgbWVtdW5jdWxrYW4gZGF0YSBsZWFrYWdlIGppa2EgdGlkYWsgZGlsYWt1a2FuIGRlbmdhbiBoYXRpLWhhdGkgKG1pc2FsbnlhIHNhYXQgZGlndW5ha2FuIHNlYmVsdW0gZGF0YSBzcGxpdCkuDQoNCipDb250b2ggUGVuZ2d1bmFhbiBkYWxhbSBSOioNCg0KYGBge30NCg0KIyBGdW5nc2kgZnJlcXVlbmN5IGVuY29kaW5nDQpmcmVxX2VuYyA8LSBmdW5jdGlvbihjb2wpIHsNCiAgdGFiIDwtIHRhYmxlKGNvbCkNCiAgcmV0dXJuKGFzLm51bWVyaWModGFiW2NvbF0pIC8gbGVuZ3RoKGNvbCkpDQp9DQoNCiMgUGFzdGlrYW4ga29sb20gbG93ZXJjYXNlDQpjb2xuYW1lcyhoZWFsdGhfZGF0YSkgPC0gdG9sb3dlcihjb2xuYW1lcyhoZWFsdGhfZGF0YSkpDQoNCiMgS29sb20geWFuZyBpbmdpbiBkaS1lbmNvZGUNCnRhcmdldF9jb2xzIDwtIGMoInllYXIiLCAibG9jYXRpb24iLCAiaGVhbHRoX2NvbmRpdGlvbiIpDQphdmFpbGFibGVfY29scyA8LSBpbnRlcnNlY3QodGFyZ2V0X2NvbHMsIGNvbG5hbWVzKGhlYWx0aF9kYXRhKSkNCg0KIyBFbmNvZGluZyBmcmVrdWVuc2kNCkZyZXF1ZW5jeSA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKGFjcm9zcyhhbGxfb2YoYXZhaWxhYmxlX2NvbHMpLCB+IGZyZXFfZW5jKC4pLCAubmFtZXMgPSAiey5jb2x9X2ZyZXEiKSkNCmBgYA0KDQoNCg0KIyMjIFBlbmplbGFzYW4gRnVuZ3NpIA0KDQoNCnwgRnVuZ3NpIHwgVHVqdWFuIHwNCnwtLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCB0YWJsZShjb2wpIHwgTWVuZ2hpdHVuZyBqdW1sYWgga2VtdW5jdWxhbiB0aWFwIGthdGVnb3JpLiB8DQp8IGFzLm51bWVyaWModGFiW2NvbF0pIC8gbGVuZ3RoKGNvbCkgfCBNZW5ndWJhaCBuaWxhaSBrYXRlZ29yaSBtZW5qYWRpIHByb3BvcnNpIGtlbXVuY3VsYW5ueWEuIHwNCnwgYWNyb3NzKC4uLiwgLm5hbWVzID0gInsuY29sfV9mcmVxIikgfCBNZW5hbWJhaGthbiBuYW1hIGtvbG9tIGhhc2lsIGVuY29kaW5nLiB8DQoNCg0KIyMjIEludGVycHJldGFzaSBLZXNlaGF0YW46DQoNCnwgRml0dXIgRW5jb2RlZCB8IE1ha25hIHwNCnwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnwgbG9jYXRpb25fZnJlcSA9IDAuMzAgfCBMb2thc2kgdGVyc2VidXQgbXVuY3VsIHNlYmFueWFrIDMwJSBkYXJpIHRvdGFsIGRhdGEuIHwNCnwgaGVhbHRoX2NvbmRpdGlvbl9mcmVxID0gMC4xMCB8IEtvbmRpc2kga2VzZWhhdGFuIHRlcnNlYnV0IGhhbnlhIG11bmN1bCBkaSAxMCUgZGF0YS4gfA0KDQoNCiMjIyBIYXNpbCBUcmFuc2Zvcm1hc2kNCg0KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShEVCkNCg0KIyBGdW5nc2kgZnJlcXVlbmN5IGVuY29kaW5nDQpmcmVxX2VuYyA8LSBmdW5jdGlvbihjb2wpIHsNCiAgdGFiIDwtIHRhYmxlKGNvbCkNCiAgcmV0dXJuKGFzLm51bWVyaWModGFiW2NvbF0pIC8gbGVuZ3RoKGNvbCkpDQp9DQoNCiMgUGFzdGlrYW4ga29sb20gbG93ZXJjYXNlDQpjb2xuYW1lcyhoZWFsdGhfZGF0YSkgPC0gdG9sb3dlcihjb2xuYW1lcyhoZWFsdGhfZGF0YSkpDQoNCiMgS29sb20geWFuZyBpbmdpbiBkaS1lbmNvZGUNCnRhcmdldF9jb2xzIDwtIGMoInllYXIiLCAibG9jYXRpb24iLCAiaGVhbHRoX2NvbmRpdGlvbiIpDQphdmFpbGFibGVfY29scyA8LSBpbnRlcnNlY3QodGFyZ2V0X2NvbHMsIGNvbG5hbWVzKGhlYWx0aF9kYXRhKSkNCg0KIyBFbmNvZGluZyBmcmVrdWVuc2kNCkZyZXF1ZW5jeSA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKGFjcm9zcyhhbGxfb2YoYXZhaWxhYmxlX2NvbHMpLCB+IGZyZXFfZW5jKC4pLCAubmFtZXMgPSAiey5jb2x9X2ZyZXEiKSkNCg0KIyBUYW1waWxrYW4gaGFzaWwNCkRUOjpkYXRhdGFibGUoRnJlcXVlbmN5LCBjYXB0aW9uID0gIkZyZXF1ZW5jeSBFbmNvZGluZyIpDQpgYGANCg0KDQoNCiMjIyBLZXNpbXB1bGFuOg0KDQotIEZyZXF1ZW5jeSBlbmNvZGluZyBtZW1iZXJpa2FuIGJvYm90IHByb3BvcnNpb25hbCB0ZXJoYWRhcCBrZW11bmN1bGFuIGthdGVnb3JpLg0KDQotIExlYmloIHJpbmdhbiBzZWNhcmEga29tcHV0YXNpIGRpYmFuZGluZyBvbmUtaG90IGVuY29kaW5nLCBuYW11biB0ZXRhcCBtZW55aW1wYW4gbWFrbmEgc3RhdGlzdGlrIGRhcmkgZGF0YSBrYXRlZ29yaWsuDQoNCi0gQ29jb2sgZGlndW5ha2FuIGRhbGFtIG1vZGVsIGxpbmVhciBkYW4gdHJlZS1iYXNlZCBzZXBlcnRpIFJhbmRvbSBGb3Jlc3QgZGFuIFhHQm9vc3QuDQoNCg0KIyA1LiBGZWF0dXJlIEVuZ2luZWVyaW5nDQoNCkZlYXR1cmUgZW5naW5lZXJpbmcgYWRhbGFoIHByb3NlcyBtZW5jaXB0YWthbiBmaXR1ci1maXR1ciBiYXJ1IGRhcmkgZGF0YSB5YW5nIGFkYSB1bnR1ayBtZW5pbmdrYXRrYW4gcGVyZm9ybWEgbW9kZWwgbWFjaGluZSBsZWFybmluZy4gU2FsYWggc2F0dSB0ZWtuaWsgeWFuZyBzZXJpbmcgZGlndW5ha2FuIGFkYWxhaCAqaW50ZXJhY3Rpb24gZmVhdHVyZXMqLCB5YWl0dSBtZW5nZ2FidW5na2FuIGR1YSBhdGF1IGxlYmloIGZpdHVyIHVudHVrIG1lbWJlbnR1ayBmaXR1ciBiYXJ1IHlhbmcgYmlzYSBtZW5hbmdrYXAgaHVidW5nYW4gbm9ubGluaWVyIGFudGFyIHZhcmlhYmVsLg0KDQoNCiMjIDUuMSBJbnRlcmFjdGlvbiBGZWF0dXJlcw0KDQpJbnRlcmFjdGlvbiBmZWF0dXJlcyBkaWJ1YXQgZGVuZ2FuIG1lbmdhbGlrYW4gYXRhdSBtZW5nZ2FidW5na2FuIGR1YSBmaXR1ciB1bnR1ayBtZXJlcHJlc2VudGFzaWthbiBodWJ1bmdhbiBhbnRhcmEga2VkdWFueWEuIERhbGFtIGthc3VzIGluaSwgZGlidWF0IGZpdHVyIGludGVyYWtzaSBhbnRhcmEgKnVtdXIgKGFnZSkqIGRhbiAqQk1JIChCb2R5IE1hc3MgSW5kZXgpKiB1bnR1ayBtZWxpaGF0IGRhbXBhayBnYWJ1bmdhbiB1c2lhIGRhbiBiZXJhdCBiYWRhbiB0ZXJoYWRhcCBrZXNlaGF0YW4uDQoNCiMjIyBLZWd1bmFhbjoNCg0KLSBNZW1iYW50dSBtb2RlbCBtZW5hbmdrYXAgZWZlayBnYWJ1bmdhbiBhbnRhciANCg0KLSBCZXJndW5hIGRhbGFtIG1vZGVsIGxpbmVhciB5YW5nIHRpZGFrIHNlY2FyYSBla3NwbGlzaXQgbWVuYW5na2FwIGludGVyYWtzaSBhbnRhciBmaXR1ci4NCg0KIyMjIENvbnRvaCBLb2RlIFI6DQoNCmBgYHt9DQoNCiMgU2ltcGFuIG5hbWEga29sb20gQk1JIGtlIHZhcmlhYmVsDQpibWlfY29sIDwtIGdyZXAoImJtaXxpbXQiLCBjb2xuYW1lcyhoZWFsdGhfZGF0YSksIHZhbHVlID0gVFJVRSlbMV0NCg0KIyBCdWF0IGludGVyYWtzaSBhbnRhcmEgYWdlIGRhbiBCTUkNCmRhdGFfaW50ZXJhY3Rpb24gPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBBZ2VfQk1JX0ltcGFjdCA9IGFnZSAqIC5kYXRhW1tibWlfY29sXV0NCiAgKQ0KYGBgDQoNCg0KDQojIyMgUGVuamVsYXNhbiBGdW5nc2kNCg0KfCBMYW5na2FoIHwgUGVuamVsYXNhbiB8DQp8LS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IGdyZXAoImJtaXxpbXQiLCAuLi4pIHwgU2VjYXJhIG90b21hdGlzIG1lbmRldGVrc2kgbmFtYSBrb2xvbSBCTUkgKGJpc2EgImJtaSIsICJpbXQiLCBkc2IpLiB8DQp8IGFnZSAqIC5kYXRhW1tibWlfY29sXV0gfCBNZW5nYWxpa2FuIHVtdXIgZGFuIEJNSSB1bnR1ayBtZW1idWF0IGZpdHVyIGJhcnUgQWdlX0JNSV9JbXBhY3QuIHwNCnwgbXV0YXRlKCkgfCBNZW5hbWJhaGthbiBmaXR1ciBiYXJ1IGtlIGRhbGFtIGRhdGEuIHwNCg0KDQojIyMgSW50ZXJwcmV0YXNpIEtlc2VoYXRhbjoNCg0KLSBGaXR1ciBBZ2VfQk1JX0ltcGFjdCBha2FuIGJlcm5pbGFpIHRpbmdnaSBqaWthIHNlc2VvcmFuZyBtZW1pbGlraSB1c2lhIGRhbiBCTUkgeWFuZyBzYW1hLXNhbWEgdGluZ2dpLg0KDQotIERhcGF0IG1lbnVuanVra2FuIHJpc2lrbyBrZXNlaGF0YW4gZ2FidW5nYW4gYWtpYmF0IHVzaWEgbGFuanV0IGRhbiBiZXJhdCBiYWRhbiBiZXJsZWJpaC4NCg0KDQojIyMgSGFzaWwgVHJhbnNmb3JtYXNpIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KERUKQ0KDQojIFNpbXBhbiBuYW1hIGtvbG9tIEJNSSBrZSB2YXJpYWJlbA0KYm1pX2NvbCA8LSBncmVwKCJibWl8aW10IiwgY29sbmFtZXMoaGVhbHRoX2RhdGEpLCB2YWx1ZSA9IFRSVUUpWzFdDQoNCiMgQnVhdCBpbnRlcmFrc2kgYW50YXJhIGFnZSBkYW4gQk1JDQpkYXRhX2ludGVyYWN0aW9uIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgQWdlX0JNSV9JbXBhY3QgPSBhZ2UgKiAuZGF0YVtbYm1pX2NvbF1dDQogICkNCg0KIyBUYW1waWxrYW4gaGFzaWwNCkRUOjpkYXRhdGFibGUoaGVhZChkYXRhX2ludGVyYWN0aW9uKSwgY2FwdGlvbiA9ICJJbnRlcmFjdGlvbiBiZXR3ZWVuIEFnZSBhbmQgQk1JIikNCmBgYA0KDQoNCg0KIyMjIEtlc2ltcHVsYW46DQoNCi0gRml0dXIgaW50ZXJha3NpIGJlcmd1bmEgdW50dWsgbWVuZ3VuZ2thcCByZWxhc2kgdGVyc2VtYnVueWkgYW50YXIgdmFyaWFiZWwuDQotIERhbGFtIGthc3VzIGRhdGEga2VzZWhhdGFuLCBpbnRlcmFrc2kgYW50YXJhIHVzaWEgZGFuIEJNSSBiaXNhIG1lbmphZGkgaW5kaWthdG9yIHBlbnRpbmcgdGVyaGFkYXAgcmlzaWtvIHBlbnlha2l0IGtyb25pcy4NCg0KDQojIyA1LjIgUmF0aW8gRmVhdHVyZXMNCg0KUmF0aW8gZmVhdHVyZXMgYWRhbGFoIGZpdHVyIHlhbmcgZGliZW50dWsgZGFyaSBwZXJiYW5kaW5nYW4gZHVhIHZhcmlhYmVsIG51bWVyaWsuIFRla25payBpbmkgc2VyaW5nIGRpZ3VuYWthbiB1bnR1ayBtZW5vcm1hbGthbiBkYXRhLCBtZW55b3JvdGkga2V0aWRha3NlaW1iYW5nYW4sIGF0YXUgbWVuYW5na2FwIGh1YnVuZ2FuIHByb3BvcnNpb25hbCBhbnRhciB2YXJpYWJlbC4NCg0KDQojIyMgQ29udG9oIEthc3VzOg0KDQpEYWxhbSBkYXRhIGtlc2VoYXRhbiwgbWVtYmFuZGluZ2thbiBrYWRhciBrb2xlc3Rlcm9sIHRlcmhhZGFwIGthZGFyIGdsdWtvc2EgZGFwYXQgbWVtYmVyaWthbiBpbnNpZ2h0IHRhbWJhaGFuIHRlbnRhbmcgcHJvZmlsIG1ldGFib2xpayBzZXNlb3JhbmcuIE1ha2EgZGlidWF0IGZpdHVyIGJhcnU6ICpDaG9sZXN0ZXJvbCB0byBHbHVjb3NlIFJhdGlvKi4NCg0KIyMjIENvbnRvaCBLb2RlIFI6DQoNCmBgYHt9DQoNCmRhdGFfcmF0aW8gPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBDaG9sZXN0ZXJvbF9HbHVjb3NlX1JhdGlvID0gY2hvbGVzdGVyb2wgLyAoZ2x1Y29zZSArIDFlLTUpDQogICkNCmBgYA0KDQoNCg0KIyMjIFBlbmplbGFzYW4gRnVuZ3NpDQoNCnwgTGFuZ2thaCB8IFBlbmplbGFzYW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tLS0tLXwNCnwgY2hvbGVzdGVyb2wgLyAoZ2x1Y29zZSArIDFlLTUpIHwgUmFzaW8gYW50YXJhIGtvbGVzdGVyb2wgZGFuIGdsdWtvc2E7IHBlbmFtYmFoYW4gMWUtNSBtZW5jZWdhaCBwZW1iYWdpYW4gZGVuZ2FuIG5vbC4gfA0KfCBtdXRhdGUoKSB8IE1lbmFtYmFoa2FuIGZpdHVyIHJhc2lvIGJhcnUga2UgZGFsYW0gZGF0YS4gfA0KDQoNCg0KIyMjIEludGVycHJldGFzaSBLZXNlaGF0YW46DQoNCi0gUmFzaW8geWFuZyB0aW5nZ2kgYmlzYSBtZW51bmp1a2thbiBwb3RlbnNpIHJpc2lrbyBnYW5nZ3VhbiBtZXRhYm9saWsuDQoNCi0gQmVyZ3VuYSB1bnR1ayBtZW55YXJpbmcgaW5kaXZpZHUgZGVuZ2FuIGtvbGVzdGVyb2wgdGluZ2dpIHRldGFwaSBrYWRhciBnbHVrb3NhIG5vcm1hbCBhdGF1IHNlYmFsaWtueWEuDQoNCg0KIyMjIEhhc2lsIFRyYW5zZm9ybWFzaQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoRFQpDQoNCmRhdGFfcmF0aW8gPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBDaG9sZXN0ZXJvbF9HbHVjb3NlX1JhdGlvID0gY2hvbGVzdGVyb2wgLyAoZ2x1Y29zZSArIDFlLTUpDQogICkNCg0KRFQ6OmRhdGF0YWJsZShoZWFkKGRhdGFfcmF0aW8pLCBjYXB0aW9uID0gIkNob2xlc3Rlcm9sIHRvIEdsdWNvc2UgUmF0aW8iKQ0KYGBgDQoNCg0KDQojIyMgS2VzaW1wdWxhbjoNCg0KLSBSYXRpbyBmZWF0dXJlcyBtZW1wZXJrYXlhIGRhdGFzZXQgZGVuZ2FuIGluZm9ybWFzaSBwcm9wb3JzaW9uYWwuDQotIERhbGFtIGtvbnRla3MgbWVkaXMsIHJhc2lvIGluaSBtZW1iYW50dSBkYWxhbSBtZW5kZXRla3NpIGtldGlkYWtzZWltYmFuZ2FuIGJpb2tpbWlhIHlhbmcgdGlkYWsgdGVybGloYXQgZGFyaSBuaWxhaSBhYnNvbHV0IHNhamEuDQoNCg0KDQojIyA1LjMgR3JvdXAgQWdncmVnYXRpb24NCg0KR3JvdXAgYWdncmVnYXRpb24gYWRhbGFoIHRla25payB1bnR1ayBtZW5naGl0dW5nIHJpbmdrYXNhbiBzdGF0aXN0aWsgYmVyZGFzYXJrYW4ga2Vsb21wb2sgdGVydGVudHUgZGFsYW0gZGF0YSwgbWlzYWxueWEgYmVyZGFzYXJrYW4gSUQgcGFzaWVuLCBsb2thc2ksIGF0YXUgd2FrdHUuIFRla25payBpbmkgYmVyZ3VuYSB1bnR1ayBtZW5jaXB0YWthbiBmaXR1ciBiYXJ1IHlhbmcgbWVyYW5na3VtIGluZm9ybWFzaSBoaXN0b3JpcyBhdGF1IGJlcnVsYW5nLg0KDQoNCiMjIyBDb250b2ggS2FzdXM6DQoNClBhZGEgZGF0YXNldCBrZXNlaGF0YW4sIHNhdHUgcGFzaWVuIGJpc2EgbWVtaWxpa2kgYmViZXJhcGEgZW50cmkga3VuanVuZ2FuLiBNYWthIGtpdGEgYmlzYSBtZW5naGl0dW5nIHJhdGEtcmF0YSBkYW4gbWFrc2ltdW0ga2FkYXIgZ2x1a29zYSB1bnR1ayB0aWFwICpwYXRpZW50X2lkKiwgc2VydGEganVtbGFoIGt1bmp1bmdhbiBzZWJhZ2FpIGZpdHVyIHRhbWJhaGFuLg0KDQojIyMgQ29udG9oIEtvZGUgUjoNCg0KYGBge30NCg0KIyBBZ2dyZWdhdGUgYnkgcGF0aWVudA0KcGF0aWVudF9nbHVjb3NlIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBncm91cF9ieShwYXRpZW50X2lkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIEF2Z19HbHVjb3NlID0gbWVhbihnbHVjb3NlLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1heF9HbHVjb3NlID0gbWF4KGdsdWNvc2UsIG5hLnJtID0gVFJVRSksDQogICAgVmlzaXRzID0gbigpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQojIEpvaW4gd2l0aCBvcmlnaW5hbCBkYXRhDQpoZWFsdGhfZGF0YV9qb2luZWQgPC0gbGVmdF9qb2luKGhlYWx0aF9kYXRhLCBwYXRpZW50X2dsdWNvc2UsIGJ5ID0gInBhdGllbnRfaWQiKQ0KYGBgDQoNCg0KfCBMYW5na2FoIHwgUGVuamVsYXNhbiB8DQp8LS0tLS0tLS18LS0tLS0tLS0tLS0tfA0KfCBncm91cF9ieShwYXRpZW50X2lkKSB8IE1lbmdlbG9tcG9ra2FuIGRhdGEgYmVyZGFzYXJrYW4gSUQgcGFzaWVuLiB8DQp8IHN1bW1hcmlzZSgpIHwgTWVuZ2hpdHVuZyBuaWxhaSByYXRhLXJhdGEsIG1ha3NpbXVtLCBkYW4ganVtbGFoIGt1bmp1bmdhbi4gfA0KfCBsZWZ0X2pvaW4oKSB8IE1lbmdnYWJ1bmdrYW4gaGFzaWwgYWdyZWdhc2kga2VtYmFsaSBrZSBkYXRhIHV0YW1hLiB8DQoNCg0KIyMjICBNYW5mYWF0IGRhbGFtIEtvbnRla3MgTWVkaXM6DQoNCi0gKkF2Z19HbHVjb3NlKiBkYW4gKk1heF9HbHVjb3NlKiBtZW5jZXJtaW5rYW4ga29udHJvbCBndWxhIGRhcmFoIHBhc2llbiBzZWNhcmEgbG9uZ2l0dWRpbmFsLg0KDQotICpWaXNpdHMqIGRhcGF0IG1lbnVuanVra2FuIGZyZWt1ZW5zaSBrb250cm9sIGF0YXUga2VwYXJhaGFuIGtvbmRpc2kgcGFzaWVuLg0KDQoNCiMjIyBIYXNpbCBUcmFuc2Zvcm1hc2kNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShEVCkNCg0KIyBBZ2dyZWdhdGUgYnkgcGF0aWVudA0KcGF0aWVudF9nbHVjb3NlIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBncm91cF9ieShwYXRpZW50X2lkKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIEF2Z19HbHVjb3NlID0gbWVhbihnbHVjb3NlLCBuYS5ybSA9IFRSVUUpLA0KICAgIE1heF9HbHVjb3NlID0gbWF4KGdsdWNvc2UsIG5hLnJtID0gVFJVRSksDQogICAgVmlzaXRzID0gbigpLA0KICAgIC5ncm91cHMgPSAiZHJvcCINCiAgKQ0KDQojIEpvaW4gd2l0aCBvcmlnaW5hbCBkYXRhDQpoZWFsdGhfZGF0YV9qb2luZWQgPC0gbGVmdF9qb2luKGhlYWx0aF9kYXRhLCBwYXRpZW50X2dsdWNvc2UsIGJ5ID0gInBhdGllbnRfaWQiKQ0KDQpEVDo6ZGF0YXRhYmxlKGhlYWQoaGVhbHRoX2RhdGFfam9pbmVkKSwgY2FwdGlvbiA9ICJHbHVjb3NlIEFnZ3JlZ2F0aW9uIHBlciBQYXRpZW50IikNCmBgYA0KDQoNCg0KIyMjICBLZXNpbXB1bGFuOg0KDQotIEdyb3VwIGFnZ3JlZ2F0aW9uIG1lbmdoYXNpbGthbiBmaXR1ciB5YW5nIG1lbXBlcmtheWEgZGF0YSBkZW5nYW4gaW5mb3JtYXNpIHJpbmdrYXNhbiBwZXIgZW50aXRhcy4NCi0gQ29jb2sgdW50dWsgZGF0YSB5YW5nIGJlcnNpZmF0IGxvbmdpdHVkaW5hbCwgc2VwZXJ0aSByZWthbSBtZWRpcyBhdGF1IHRyYW5zYWtzaSBwZWxhbmdnYW4uDQoNCg0KIyMgNS40IFJhbmsgVHJhbnNmb3JtYXRpb24NCg0KUmFuayB0cmFuc2Zvcm1hdGlvbiBhZGFsYWggdGVrbmlrIHVudHVrIG1lbmd1YmFoIG5pbGFpIG51bWVyaWsgbWVuamFkaSB1cnV0YW4gYmVyZGFzYXJrYW4gcG9zaXNpIHJlbGF0aWZueWEgZGFsYW0gZGF0YXNldC4gSW5pIGJlcmd1bmEgdW50dWsgbWVuZ2lkZW50aWZpa2FzaSBwb3Npc2kgYXRhdSBwZXJpbmdrYXQgc3VhdHUgZW50aXRhcyBiZXJkYXNhcmthbiB2YXJpYWJlbCB0ZXJ0ZW50dSB0YW5wYSBtZW1lcmx1a2FuIGRpc3RyaWJ1c2kgZGF0YSB5YW5nIHNwZXNpZmlrLg0KDQoNCiMjIyBDb250b2ggS2FzdXM6DQoNCkRhbGFtIGRhdGFzZXQga2VzZWhhdGFuLCBraXRhIGRhcGF0IG1lbmd1cnV0a2FuIGthZGFyIGdsdWtvc2EgcGFzaWVuIGRhbiBtZW1iZXJpIHBlcmluZ2thdCBrZXBhZGEgbWVyZWthIGJlcmRhc2Fya2FuIGxldmVsIGdsdWtvc2EsIGRlbmdhbiBwYXNpZW4geWFuZyBtZW1pbGlraSBrYWRhciBnbHVrb3NhIHRlcnRpbmdnaSBtZW5kYXBhdCBwZXJpbmdrYXQgdGVyYXRhcy4NCg0KIyMjIENvbnRvaCBLb2RlIFI6DQoNCmBgYHt9DQoNCmRhdGFfcmFua2VkIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgR2x1Y29zZV9SYW5rID0gcmFuaygtZ2x1Y29zZSkNCiAgKQ0KDQpgYGANCg0KIyMjIFBlbmplbGFzYW4gRnVuZ3NpIA0KDQoNCnwgTGFuZ2thaCB8IFBlbmplbGFzYW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tLS0tLXwNCnwgcmFuaygtZ2x1Y29zZSkgfCBNZW5naGl0dW5nIHBlcmluZ2thdCBiZXJkYXNhcmthbiBrYWRhciBnbHVrb3NhLCBkZW5nYW4gdGFuZGEgbWludXMgLSB1bnR1ayBtZW1iZXJpa2FuIHBlcmluZ2thdCB0ZXJ0aW5nZ2kgcGFkYSBuaWxhaSB0ZXJiZXNhci4gfA0KDQoNCiMjIyAgTWFuZmFhdCBkYWxhbSBLb250ZWtzIE1lZGlzOg0KDQotICpHbHVjb3NlX1JhbmsqIG1lbWJlcmlrYW4gZ2FtYmFyYW4gdGVudGFuZyBwb3Npc2kgcmVsYXRpZiBwYXNpZW4gYmVyZGFzYXJrYW4ga2FkYXIgZ2x1a29zYSBtZXJla2EuIEluaSBiZXJndW5hIHVudHVrIG1lbWFoYW1pIHNpYXBhIHlhbmcgYmVyYWRhIGRhbGFtIGtlbG9tcG9rIGRlbmdhbiBrYWRhciBnbHVrb3NhIHRlcnRpbmdnaSBhdGF1IHRlcmVuZGFoLg0KDQoNCiMjIyBIYXNpbCBUcmFuc2Zvcm1hc2kNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShEVCkNCg0KZGF0YV9yYW5rZWQgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBHbHVjb3NlX1JhbmsgPSByYW5rKC1nbHVjb3NlKQ0KICApDQoNCkRUOjpkYXRhdGFibGUoaGVhZChkYXRhX3JhbmtlZCksIGNhcHRpb24gPSAiUmFua2luZyBieSBHbHVjb3NlIExldmVsIikNCmBgYA0KDQoNCg0KIyMjICBLZXNpbXB1bGFuOg0KDQpSYW5rIHRyYW5zZm9ybWF0aW9uIGNvY29rIHVudHVrIGFuYWxpc2lzIHlhbmcgbWVuZ3V0YW1ha2FuIHVydXRhbiBkYXJpcGFkYSBuaWxhaSBhYnNvbHV0LCBzZXBlcnRpIGlkZW50aWZpa2FzaSBwYXNpZW4gZGVuZ2FuIGtvbmRpc2kgcGFsaW5nIGtyaXRpcyBiZXJkYXNhcmthbiBwZXJpbmdrYXQuDQoNCg0KIyMgNS41IFRleHQgQ2xlYW5pbmcgJiBGZWF0dXJlIENyZWF0aW9uDQoNClRleHQgY2xlYW5pbmcgZGFuIHBlbWJ1YXRhbiBmaXR1ciBkYXJpIHRla3MgYWRhbGFoIGxhbmdrYWggcGVudGluZyBkYWxhbSBwcm9zZXMgcGVtYmVyc2loYW4gZGF0YSwga2h1c3VzbnlhIGtldGlrYSBraXRhIGJla2VyamEgZGVuZ2FuIGRhdGEgeWFuZyBtZW5nYW5kdW5nIGluZm9ybWFzaSBkYWxhbSBmb3JtYXQgdGVrcyB5YW5nIHRpZGFrIHRlcnN0cnVrdHVyLiBTYWxhaCBzYXR1IGxhbmdrYWggcGVudGluZyBhZGFsYWggbWVuZ2Vrc3RyYWtzaSBpbmZvcm1hc2kgcmVsZXZhbiBkYXJpIHRla3MsIHNlcGVydGkgYW5na2EgYXRhdSBrYXRhLWthdGEga3VuY2ksIHVudHVrIGRpZ3VuYWthbiBkYWxhbSBhbmFsaXNpcyBsZWJpaCBsYW5qdXQuDQoNCg0KIyMjIENvbnRvaCBLYXN1czoNCg0KRGFsYW0gZGF0YXNldCBrZXNlaGF0YW4sIGtvbG9tIHBhdGllbnRfaWQgbXVuZ2tpbiBtZW5nYW5kdW5nIGFuZ2thIGRhbiBrYXJha3RlciBsYWluLCB5YW5nIG1hbmEga2l0YSBiaXNhIG1lbmdla3N0cmFrc2kgYW5na2Egc2FqYSB1bnR1ayBtZW1idWF0IGZpdHVyIGJhcnUuDQoNCiMjIyBDb250b2ggS29kZSBSOg0KDQpgYGB7fQ0KDQpkYXRhX3RleHQgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBQYXRpZW50X051bSA9IGFzLm51bWVyaWMoZ3N1YigiW14wLTldIiwgIiIsIHBhdGllbnRfaWQpKQ0KICApDQpgYGAgIA0KDQoNCiMjIyBQZW5qZWxhc2FuIEZ1bmdzaSANCg0KfCBMYW5na2FoIHwgUGVuamVsYXNhbiB8DQp8LS0tLS0tLS18LS0tLS0tLS0tLS0tfA0KfCBnc3ViKCJbXjAtOV0iLCAiIiwgcGF0aWVudF9pZCkgfCBNZW5nZ3VuYWthbiBmdW5nc2kgZ3N1YiB1bnR1ayBtZW5naGFwdXMga2FyYWt0ZXIgbm9uLWFuZ2thIGRhbiBtZW5nZWtzdHJha3NpIGhhbnlhIGFuZ2thIGRhcmkga29sb20gcGF0aWVudF9pZC4gfA0KfCBhcy5udW1lcmljKCkgfCBNZW5nb252ZXJzaSBoYXNpbCBla3N0cmFrc2kgbWVuamFkaSBmb3JtYXQgbnVtZXJpay4gfA0KDQoNCiMjIyAgTWFuZmFhdCBkYWxhbSBLb250ZWtzIE1lZGlzOg0KDQotICpQYXRpZW50X051bSogbWVtYmVyaWthbiBub21vciBwYXNpZW4gZGFsYW0gZm9ybWF0IG51bWVyaWsgeWFuZyBiaXNhIGRpZ3VuYWthbiB1bnR1ayBhbmFsaXNpcyBsZWJpaCBsYW5qdXQsIHNlcGVydGkgcGVuZ2Vsb21wb2thbiBhdGF1IGlkZW50aWZpa2FzaSBwYXNpZW4gYmVyZGFzYXJrYW4gSUQgbnVtZXJpay4NCg0KDQojIyMgSGFzaWwgVHJhbnNmb3JtYXNpDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoRFQpDQoNCmRhdGFfdGV4dCA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKA0KICAgIFBhdGllbnRfTnVtID0gYXMubnVtZXJpYyhnc3ViKCJbXjAtOV0iLCAiIiwgcGF0aWVudF9pZCkpDQogICkNCg0KRFQ6OmRhdGF0YWJsZShoZWFkKGRhdGFfdGV4dCksIGNhcHRpb24gPSAiRXh0cmFjdCBOdW1iZXJzIGZyb20gUGF0aWVudCBJRCIpDQpgYGANCg0KDQoNCiMjIyAgS2VzaW1wdWxhbjoNCg0KTGFuZ2thaCBwZW1iZXJzaWhhbiB0ZWtzIGluaSBtZW1iYW50dSBtZW5ndWJhaCBJRCBwYXNpZW4geWFuZyBtZW5nYW5kdW5nIGthcmFrdGVyIG1lbmphZGkgZm9ybWF0IHlhbmcgbGViaWggbXVkYWggdW50dWsgZGlhbmFsaXNpcywgdGVydXRhbWEgc2FhdCBJRCBwYXNpZW4gZGlwZXJsdWthbiBkYWxhbSBhbmFsaXNpcyBzdGF0aXN0aWsgYXRhdSBwZW1iZWxhamFyYW4gbWVzaW4uDQoNCg0KIyMgNS42IEN1bXVsYXRpdmUgRmVhdHVyZXMNCg0KQ3VtdWxhdGl2ZSBmZWF0dXJlcyBtZW5nYWN1IHBhZGEgZml0dXIgeWFuZyBkaWhpdHVuZyBzZWNhcmEgYmVydXJ1dGFuIGJlcmRhc2Fya2FuIGRhdGEgeWFuZyB0ZXJ1cnV0LCBzZXBlcnRpIGFrdW11bGFzaSBuaWxhaSBkYXJpIHZhcmlhYmVsIHRlcnRlbnR1IHNlcGFuamFuZyB3YWt0dS4gQ3VtdWxhdGl2ZSBmZWF0dXJlcyBzZXJpbmcgZGlndW5ha2FuIGRhbGFtIGFuYWxpc2lzIHRpbWUgc2VyaWVzIGF0YXUgZGF0YSB5YW5nIGJlcnNpZmF0IGtyb25vbG9naXMsIHNlcGVydGkgcGVuZ2hpdHVuZ2FuIGp1bWxhaCBrdW11bGF0aWYgZGFyaSBzdWF0dSBwYXJhbWV0ZXIga2VzZWhhdGFuLg0KDQoNCiMjIyBDb250b2ggS2FzdXM6DQoNCkRhbGFtIGRhdGFzZXQga2VzZWhhdGFuLCBraXRhIGRhcGF0IG1lbmdoaXR1bmcganVtbGFoIGt1bXVsYXRpZiBrYWRhciBnbHVrb3NhIGRhcmkgd2FrdHUga2Ugd2FrdHUgdW50dWsgc2V0aWFwIHBhc2llbiwgeWFuZyBtZW1iZXJpa2FuIGdhbWJhcmFuIHRlbnRhbmcgcGVydWJhaGFuIHRpbmdrYXQgZ2x1a29zYSBzZXBhbmphbmcgd2FrdHUuDQoNCiMjIyBDb250b2ggS29kZSBSOg0KDQpgYGB7fQ0KDQpkYXRhX2N1bXVsYXRpdmUgPC0gaGVhbHRoX2RhdGEgJT4lDQogIGFycmFuZ2UocGF0aWVudF9pZCwgZGF0ZSkgJT4lDQogIGdyb3VwX2J5KHBhdGllbnRfaWQpICU+JQ0KICBtdXRhdGUoDQogICAgQ3VtdWxhdGl2ZV9HbHVjb3NlID0gY3Vtc3VtKGdsdWNvc2UpDQogICkgJT4lDQogIHVuZ3JvdXAoKQ0KYGBgICANCg0KDQojIyMgUGVuamVsYXNhbiBGdW5nc2kgDQoNCnwgTGFuZ2thaCB8IFBlbmplbGFzYW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tLS0tLXwNCnwgYXJyYW5nZShwYXRpZW50X2lkLCBkYXRlKSB8IE1lbmd1cnV0a2FuIGRhdGEgYmVyZGFzYXJrYW4gSUQgcGFzaWVuIGRhbiB0YW5nZ2FsIHVudHVrIG1lbWFzdGlrYW4gYmFod2EgcGVuZ2hpdHVuZ2FuIGt1bXVsYXRpZiBkaWxha3VrYW4gYmVyZGFzYXJrYW4gdXJ1dGFuIHdha3R1LiB8DQp8IGdyb3VwX2J5KHBhdGllbnRfaWQpIHwgTWVuZ2Vsb21wb2trYW4gZGF0YSBiZXJkYXNhcmthbiBJRCBwYXNpZW4gYWdhciBwZXJoaXR1bmdhbiBrdW11bGF0aWYgZGlsYWt1a2FuIHBlciBwYXNpZW4uIHwNCnwgY3Vtc3VtKGdsdWNvc2UpIHwgTWVuZ2hpdHVuZyBqdW1sYWgga3VtdWxhdGlmIGthZGFyIGdsdWtvc2EgdW50dWsgc2V0aWFwIHBhc2llbiBkYXJpIHdha3R1IGtlIHdha3R1LiB8DQoNCg0KIyMjIE1hbmZhYXQgZGFsYW0gS29udGVrcyBNZWRpczoNCg0KLSAqQ3VtdWxhdGl2ZV9HbHVjb3NlKiBtZW1iZXJpa2FuIGluZm9ybWFzaSBtZW5nZW5haSBha3VtdWxhc2kga2FkYXIgZ2x1a29zYSBwYXNpZW4gc2VwYW5qYW5nIHdha3R1LCB5YW5nIGJpc2EgZGlndW5ha2FuIHVudHVrIG1lbWFoYW1pIHBlcnViYWhhbiBwb2xhIGdsdWtvc2EsIG1lbmdpZGVudGlmaWthc2kgdHJlbiwgZGFuIG1lbmRldGVrc2kga2VtdW5na2luYW4gbWFzYWxhaCBrZXNlaGF0YW4uDQoNCg0KIyMjIEhhc2lsIFRyYW5zZm9ybWFzaSANCg0KYGBge3IsIG1hc3NhZ2U9RkFMU0UsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShEVCkNCg0KZGF0YV9jdW11bGF0aXZlIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBhcnJhbmdlKHBhdGllbnRfaWQsIGRhdGUpICU+JQ0KICBncm91cF9ieShwYXRpZW50X2lkKSAlPiUNCiAgbXV0YXRlKA0KICAgIEN1bXVsYXRpdmVfR2x1Y29zZSA9IGN1bXN1bShnbHVjb3NlKQ0KICApICU+JQ0KICB1bmdyb3VwKCkNCg0KRFQ6OmRhdGF0YWJsZShoZWFkKGRhdGFfY3VtdWxhdGl2ZSksIGNhcHRpb24gPSAiQ3VtdWxhdGl2ZSBHbHVjb3NlIHBlciBQYXRpZW50IikNCmBgYA0KDQoNCg0KIyMjIEtlc2ltcHVsYW46DQoNClBlbmdoaXR1bmdhbiBmaXR1ciBrdW11bGF0aWYgc2VwZXJ0aSAqQ3VtdWxhdGl2ZV9HbHVjb3NlKiBtZW11bmdraW5rYW4gcGVtYWhhbWFuIHlhbmcgbGViaWggZGFsYW0gbWVuZ2VuYWkgcGVyamFsYW5hbiBrZXNlaGF0YW4gcGFzaWVuIGRhcmkgd2FrdHUga2Ugd2FrdHUgZGFuIGRhcGF0IG1lbWJhbnR1IGRhbGFtIHBlbW9kZWxhbiBwcmVkaWt0aWYsIHNlcGVydGkgZGV0ZWtzaSByaXNpa28gZGlhYmV0ZXMgYXRhdSBrb21wbGlrYXNpIHRlcmthaXQgZ2x1a29zYS4NCg0KDQojIDYuIE91dGxpZXIgSGFuZGxpbmcNCg0KRGFsYW0gYW5hbGlzaXMgZGF0YSwgb3V0bGllciBhdGF1IGRhdGEgeWFuZyBtZW55aW1wYW5nIGphdWggZGFyaSBwb2xhIHVtdW0gZGFwYXQgbWVtcGVuZ2FydWhpIGhhc2lsIGFuYWxpc2lzIGRhbiBtb2RlbC4gT2xlaCBrYXJlbmEgaXR1LCBwZW50aW5nIHVudHVrIG1lbmRldGVrc2kgZGFuIG1lbmFuZ2FuaSBvdXRsaWVyIGRlbmdhbiB0ZXBhdC4gQmViZXJhcGEgbWV0b2RlIHlhbmcgdW11bSBkaWd1bmFrYW4gdW50dWsgbWVuZGV0ZWtzaSBvdXRsaWVyIGFudGFyYSBsYWluIFotc2NvcmUgZGFuIEludGVycXVhcnRpbGUgUmFuZ2UgKElRUikuDQoNCg0KIyMjIENvbnRvaCBLYXN1czoNCg0KUGFkYSBkYXRhc2V0IGtlc2VoYXRhbiBpbmksIGtpdGEgYWthbiBtZW5nZ3VuYWthbiBkdWEgbWV0b2RlIHVudHVrIG1lbmRldGVrc2kgZGFuIG1lbmFuZ2FuaSBvdXRsaWVyOg0KDQoxLiAqWi1zY29yZSogdW50dWsgbWVuZGV0ZWtzaSBvdXRsaWVyIHBhZGEga2FkYXIgZ2x1a29zYS4NCg0KMi4gKklRUiogdW50dWsgbWVuZGV0ZWtzaSBvdXRsaWVyIHBhZGEgaW5kZWtzIG1hc3NhIHR1YnVoIChCTUkpLg0KDQojIyMgQ29udG9oIEtvZGUgUjoNCg0KDQpgYGB7fQ0KDQojIEVuc3VyZSBhbGwgY29sdW1uIG5hbWVzIGFyZSBsb3dlcmNhc2UNCmNvbG5hbWVzKGhlYWx0aF9kYXRhKSA8LSB0b2xvd2VyKGNvbG5hbWVzKGhlYWx0aF9kYXRhKSkNCg0KIyBHZXQgdGhlIGV4YWN0IG5hbWUgb2YgZ2x1Y29zZSBhbmQgQk1JIGNvbHVtbnMNCmdsdWNvc2VfY29sIDwtIGdyZXAoImdsdWtvc2F8Z2x1Y29zZSIsIGNvbG5hbWVzKGhlYWx0aF9kYXRhKSwgdmFsdWUgPSBUUlVFKVsxXQ0KYm1pX2NvbCA8LSBncmVwKCJpbXR8Ym1pIiwgY29sbmFtZXMoaGVhbHRoX2RhdGEpLCB2YWx1ZSA9IFRSVUUpWzFdDQoNCiMgWi1zY29yZSBtZXRob2QgZm9yIG91dGxpZXIgZGV0ZWN0aW9uICh1c2luZyBHbHVjb3NlKQ0Kel9zY29yZXMgPC0gc2NhbGUoaGVhbHRoX2RhdGFbW2dsdWNvc2VfY29sXV0pDQoNCmRhdGFfb3V0bGllcnMgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBPdXRsaWVyX0ZsYWcgPSBpZmVsc2UoYWJzKHpfc2NvcmVzKSA+IDMsICJPdXRsaWVyIiwgIk5vcm1hbCIpDQogICkNCg0KIyBJUVIgbWV0aG9kIGZvciBvdXRsaWVyIHJlbW92YWwgKHVzaW5nIEJNSSkNClExIDwtIHF1YW50aWxlKGhlYWx0aF9kYXRhW1tibWlfY29sXV0sIDAuMjUsIG5hLnJtID0gVFJVRSkNClEzIDwtIHF1YW50aWxlKGhlYWx0aF9kYXRhW1tibWlfY29sXV0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCklRUl92YWwgPC0gUTMgLSBRMQ0KDQpkYXRhX291dGxpZXJzX0lRUiA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgZmlsdGVyKA0KICAgIC5kYXRhW1tibWlfY29sXV0gPiAoUTEgLSAxLjUgKiBJUVJfdmFsKSAmDQogICAgLmRhdGFbW2JtaV9jb2xdXSA8IChRMyArIDEuNSAqIElRUl92YWwpDQogICkNCg0KYGBgDQoNCg0KIyMjIE1ldG9kZSBaLVNjb3JlIHVudHVrIERldGVrc2kgT3V0bGllcjoNCg0KWi1zY29yZSBkaWd1bmFrYW4gdW50dWsgbWVuZGV0ZWtzaSBzZWJlcmFwYSBqYXVoIHN1YXR1IG5pbGFpIGRhcmkgcmF0YS1yYXRhIGRhbGFtIHNhdHVhbiBkZXZpYXNpIHN0YW5kYXIuIERhbGFtIGthc3VzIGluaSwga2l0YSBtZW5naGl0dW5nIFotc2NvcmUgdW50dWsga2FkYXIgZ2x1a29zYSwgZGFuIGppa2EgWi1zY29yZSBsZWJpaCBiZXNhciBkYXJpIDMgYXRhdSBsZWJpaCBrZWNpbCBkYXJpIC0zLCBuaWxhaSB0ZXJzZWJ1dCBkaWFuZ2dhcCBzZWJhZ2FpIG91dGxpZXIuDQoNCnwgTGFuZ2thaCB8IFBlbmplbGFzYW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tLS0tLXwNCnwgc2NhbGUoaGVhbHRoX2RhdGFbW2dsdWNvc2VfY29sXV0pIHwgTWVuZ2hpdHVuZyBaLXNjb3JlIHVudHVrIGthZGFyIGdsdWtvc2EuIHwNCnwgaWZlbHNlKGFicyh6X3Njb3JlcykgPiAzLCAiT3V0bGllciIsICJOb3JtYWwiKSB8IE1lbmFuZGFpIG5pbGFpIHlhbmcgbWVtaWxpa2kgWi1zY29yZSBsZWJpaCBkYXJpIDMgYXRhdSBrdXJhbmcgZGFyaSAtMyBzZWJhZ2FpIG91dGxpZXIuIHwNCg0KDQojIyMgTWV0b2RlIElRUiB1bnR1ayBQZW5naGFwdXNhbiBPdXRsaWVyOg0KDQpNZXRvZGUgSVFSIG1lbmdoaXR1bmcgcmVudGFuZyBpbnRlcmt1YXJ0aWwgKElRUikgeWFuZyBtZXJ1cGFrYW4gc2VsaXNpaCBhbnRhcmEga3VhcnRpbCBrZXRpZ2EgKFEzKSBkYW4ga3VhcnRpbCBwZXJ0YW1hIChRMSkuIE5pbGFpIHlhbmcgYmVyYWRhIGRpIGx1YXIgcmVudGFuZyAqW1ExIC0gMS41ICBJUVIsIFEzICsgMS41ICBJUVJdKiBkaWFuZ2dhcCBzZWJhZ2FpIG91dGxpZXIuDQoNCnwgTGFuZ2thaCB8IFBlbmplbGFzYW4gfA0KfC0tLS0tLS0tfC0tLS0tLS0tLS0tLXwNCnwgcXVhbnRpbGUoaGVhbHRoX2RhdGFbW2JtaV9jb2xdXSwgMC4yNSkgfCBNZW5naGl0dW5nIGt1YXJ0aWwgcGVydGFtYSAoUTEpIGRhcmkgZGF0YSBCTUkuIHwNCnwgcXVhbnRpbGUoaGVhbHRoX2RhdGFbW2JtaV9jb2xdXSwgMC43NSkgfCBNZW5naGl0dW5nIGt1YXJ0aWwga2V0aWdhIChRMykgZGFyaSBkYXRhIEJNSS4gfA0KfCBmaWx0ZXIoLmRhdGFbW2JtaV9jb2xdXSA+IChRMSAtIDEuNSAqIElRUl92YWwpICYgLmRhdGFbW2JtaV9jb2xdXSA8IChRMyArIDEuNSAqIElRUl92YWwpKSB8IE1lbnlhcmluZyBkYXRhIEJNSSB1bnR1ayBtZW5naGFwdXMgbmlsYWktbmlsYWkgb3V0bGllciBkaSBsdWFyIHJlbnRhbmcgSVFSLiB8DQoNCg0KIyMjIE1hbmZhYXQgTWVuZ2Vsb2xhIE91dGxpZXI6DQoNCi0gKkRldGVrc2kgRGluaToqIE1lbmdpZGVudGlmaWthc2kgb3V0bGllciBkZW5nYW4gbWV0b2RlIHlhbmcgdGVwYXQgbWVtdW5na2lua2FuIHBlbWFoYW1hbiB5YW5nIGxlYmloIGJhaWsgdGVudGFuZyBkYXRhIGRhbiBtZW1iYW50dSBtZW5kZXRla3NpIG1hc2FsYWggZGFsYW0gcGVuZ3VrdXJhbiBhdGF1IGtvbmRpc2kgeWFuZyB0aWRhayBiaWFzYS4NCi0gKk1vZGVsaW5nOiogTWVuZ2hhcHVzIGF0YXUgbWVuYW5nYW5pIG91dGxpZXIgZGFwYXQgbWVuaW5na2F0a2FuIGtpbmVyamEgbW9kZWwgcHJlZGlrdGlmIGRlbmdhbiBtZW5naGluZGFyaSBkaXN0b3JzaSB5YW5nIGRhcGF0IGRpc2ViYWJrYW4gb2xlaCBkYXRhIHlhbmcgZWtzdHJlbS4NCg0KDQojIyMgSGFzaWwgVHJhbnNmb3JtYXNpIA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KERUKQ0KDQojIEVuc3VyZSBhbGwgY29sdW1uIG5hbWVzIGFyZSBsb3dlcmNhc2UNCmNvbG5hbWVzKGhlYWx0aF9kYXRhKSA8LSB0b2xvd2VyKGNvbG5hbWVzKGhlYWx0aF9kYXRhKSkNCg0KIyBHZXQgdGhlIGV4YWN0IG5hbWUgb2YgZ2x1Y29zZSBhbmQgQk1JIGNvbHVtbnMNCmdsdWNvc2VfY29sIDwtIGdyZXAoImdsdWtvc2F8Z2x1Y29zZSIsIGNvbG5hbWVzKGhlYWx0aF9kYXRhKSwgdmFsdWUgPSBUUlVFKVsxXQ0KYm1pX2NvbCA8LSBncmVwKCJpbXR8Ym1pIiwgY29sbmFtZXMoaGVhbHRoX2RhdGEpLCB2YWx1ZSA9IFRSVUUpWzFdDQoNCiMgWi1zY29yZSBtZXRob2QgZm9yIG91dGxpZXIgZGV0ZWN0aW9uICh1c2luZyBHbHVjb3NlKQ0Kel9zY29yZXMgPC0gc2NhbGUoaGVhbHRoX2RhdGFbW2dsdWNvc2VfY29sXV0pDQoNCmRhdGFfb3V0bGllcnMgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBPdXRsaWVyX0ZsYWcgPSBpZmVsc2UoYWJzKHpfc2NvcmVzKSA+IDMsICJPdXRsaWVyIiwgIk5vcm1hbCIpDQogICkNCg0KIyBJUVIgbWV0aG9kIGZvciBvdXRsaWVyIHJlbW92YWwgKHVzaW5nIEJNSSkNClExIDwtIHF1YW50aWxlKGhlYWx0aF9kYXRhW1tibWlfY29sXV0sIDAuMjUsIG5hLnJtID0gVFJVRSkNClEzIDwtIHF1YW50aWxlKGhlYWx0aF9kYXRhW1tibWlfY29sXV0sIDAuNzUsIG5hLnJtID0gVFJVRSkNCklRUl92YWwgPC0gUTMgLSBRMQ0KDQpkYXRhX291dGxpZXJzX0lRUiA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgZmlsdGVyKA0KICAgIC5kYXRhW1tibWlfY29sXV0gPiAoUTEgLSAxLjUgKiBJUVJfdmFsKSAmDQogICAgLmRhdGFbW2JtaV9jb2xdXSA8IChRMyArIDEuNSAqIElRUl92YWwpDQogICkNCg0KIyBEaXNwbGF5IHJlc3VsdHMNCkRUOjpkYXRhdGFibGUoaGVhZChkYXRhX291dGxpZXJzKSwgY2FwdGlvbiA9ICJPdXRsaWVyIERldGVjdGlvbiBVc2luZyBaLVNjb3JlIChHbHVjb3NlKSIpDQpEVDo6ZGF0YXRhYmxlKGhlYWQoZGF0YV9vdXRsaWVyc19JUVIpLCBjYXB0aW9uID0gIkZpbHRlcmVkIERhdGEgVXNpbmcgSVFSIE1ldGhvZCAoQk1JKSIpDQpgYGANCg0KDQoNCiMjIyAgS2VzaW1wdWxhbjoNCg0KLSBEZW5nYW4gbWVuZ2d1bmFrYW4gbWV0b2RlICpaLXNjb3JlKiBkYW4gKklRUiosIGtpdGEgZGFwYXQgbWVuZGV0ZWtzaSBkYW4gbWVuYW5nYW5pIG91dGxpZXIgcGFkYSBkYXRhIGtlc2VoYXRhbiB1bnR1ayBtZW1hc3Rpa2FuIGJhaHdhIGFuYWxpc2lzIGRhbiBtb2RlbCB5YW5nIGRpYmFuZ3VuIGxlYmloIGFrdXJhdCBkYW4gcmVwcmVzZW50YXRpZiB0ZXJoYWRhcCBkYXRhIGFzbGkuDQoNCg0KIyA3LiBEaXNjcmV0aXphdGlvbg0KDQpEaXNjcmV0aXphdGlvbiBhZGFsYWggcHJvc2VzIG1lbmd1YmFoIHZhcmlhYmVsIGtvbnRpbnUgbWVuamFkaSBrYXRlZ29yaSBhdGF1IGludGVydmFsLiBIYWwgaW5pIHNlcmluZyBkaWxha3VrYW4gdW50dWsgbWVuaW5na2F0a2FuIHBlbWFoYW1hbiBhdGF1IGludGVycHJldGFzaSBkYXRhLCBzZXJ0YSBtZW11ZGFoa2FuIHBlbmVyYXBhbiBtb2RlbCBrbGFzaWZpa2FzaS4gU2FsYWggc2F0dSBjb250b2ggeWFuZyB1bXVtIGFkYWxhaCBtZW5ndWJhaCB1c2lhIG1lbmphZGkga2F0ZWdvcmkgc2VwZXJ0aSAiTXVkYSIsICJQYXJ1aCBCYXlhIiwgZGFuICJUdWEiLg0KDQoNCiMjIyBDb250b2ggS2FzdXM6DQoNClBhZGEgZGF0YXNldCBrZXNlaGF0YW4gaW5pLCBraXRhIGFrYW4gbWVuZGlza3JldGlzYXNpa2FuIGtvbG9tICp1c2lhKiBtZW5qYWRpIHRpZ2Ega2F0ZWdvcmk6DQoxLiAqWW91bmcqIChNdWRhKQ0KMi4gKk1pZGRsZS1hZ2VkKiAoUGFydWggQmF5YSkNCjMuICpPbGQqIChUdWEpDQoNCkthdGVnb3JpIGluaSBha2FuIGRpZGFzYXJrYW4gcGFkYSBwZW1iYWdpYW4ga3VhbnRpbCBkYXRhIHVzaWEuDQoNCiMjIyBDb250b2ggS29kZSBSOg0KDQpgYGB7fQ0KDQoNCiMgTWFrZSBzdXJlIGNvbHVtbiBuYW1lcyBhcmUgbG93ZXJjYXNlDQpjb2xuYW1lcyhoZWFsdGhfZGF0YSkgPC0gdG9sb3dlcihjb2xuYW1lcyhoZWFsdGhfZGF0YSkpDQoNCiMgQ29udmVydCAnYWdlJyB0byBudW1lcmljIChpZiBub3QgYWxyZWFkeSkNCmhlYWx0aF9kYXRhIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUodXNpYSA9IGFzLm51bWVyaWMoYWdlKSkNCg0KIyBCaW5uaW5nICdhZ2UnIGludG8gYWdlIGNhdGVnb3JpZXMNCmJpbm5pbmcgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICBhZ2VfbGV2ZWwgPSBjdXQoDQogICAgICBhZ2UsDQogICAgICBicmVha3MgPSBxdWFudGlsZShhZ2UsIHByb2JzID0gYygwLCAwLjMzLCAwLjY2LCAxKSwgbmEucm0gPSBUUlVFKSwNCiAgICAgIGxhYmVscyA9IGMoIllvdW5nIiwgIk1pZGRsZS1hZ2VkIiwgIk9sZCIpLA0KICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUUlVFDQogICAgKQ0KICApDQpgYGANCg0KDQojIyMgUGVuamVsYXNhbjoNCg0KLSBjdXQoYWdlLCBicmVha3MgPSBxdWFudGlsZShhZ2UsIHByb2JzID0gYygwLCAwLjMzLCAwLjY2LCAxKSwgbmEucm0gPSBUUlVFKSkgZGlndW5ha2FuIHVudHVrIG1lbWJhZ2kgdXNpYSBiZXJkYXNhcmthbiBrdWFudGlsLiANCg0KICAtICowLTMzJSogdXNpYSBwZXJ0YW1hIGFrYW4gZGlnb2xvbmdrYW4ga2UgZGFsYW0ga2F0ZWdvcmkgIllvdW5nIiAoTXVkYSkuDQogIA0KICAtICozNC02NiUqIHVzaWEga2VkdWEgYWthbiBkaWdvbG9uZ2thbiBrZSBkYWxhbSBrYXRlZ29yaSAiTWlkZGxlLWFnZWQiIChQYXJ1aCBCYXlhKS4NCiAgDQogIC0gKjY3LTEwMCUqIHVzaWEga2V0aWdhIGFrYW4gZGlnb2xvbmdrYW4ga2UgZGFsYW0ga2F0ZWdvcmkgIk9sZCIgKFR1YSkuDQogIA0KLSBGdW5nc2kgY3V0KCkgaW5pIGp1Z2EgbWVtYmVyaWthbiBsYWJlbCBwYWRhIHNldGlhcCBrYXRlZ29yaSwgc2VoaW5nZ2EgbWVtdWRhaGthbiBpbnRlcnByZXRhc2kgZGF0YS4NCg0KDQojIyMgTWFuZmFhdCBEaXNjcmV0aXphdGlvbjoNCi0gKlBlbnllZGVyaGFuYWFuIE1vZGVsOiogRGVuZ2FuIG1lbmd1YmFoIHZhcmlhYmVsIGtvbnRpbnUgbWVuamFkaSBrYXRlZ29yaSwga2l0YSBkYXBhdCBtZW5ndXJhbmdpIGtvbXBsZWtzaXRhcyBtb2RlbCBkYW4gbWVtdWRhaGthbiBpbnRlcnByZXRhc2kuDQotICpNZW1wZXJiYWlraSBNb2RlbCBLbGFzaWZpa2FzaToqIEthdGVnb3Jpc2FzaSBkYXBhdCBtZW5pbmdrYXRrYW4ga2luZXJqYSBtb2RlbCBrbGFzaWZpa2FzaSwgdGVydXRhbWEgamlrYSBkYXRhIGtvbnRpbnUgbWVtaWxpa2kgZGlzdHJpYnVzaSB5YW5nIHNhbmdhdCBtaXJpbmcgYXRhdSB0aWRhayBub3JtYWwuDQoNCg0KIyMjIEhhc2lsIFRyYW5zZm9ybWFzaQ0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KERUKQ0KDQojIE1ha2Ugc3VyZSBjb2x1bW4gbmFtZXMgYXJlIGxvd2VyY2FzZQ0KY29sbmFtZXMoaGVhbHRoX2RhdGEpIDwtIHRvbG93ZXIoY29sbmFtZXMoaGVhbHRoX2RhdGEpKQ0KDQojIENvbnZlcnQgJ2FnZScgdG8gbnVtZXJpYyAoaWYgbm90IGFscmVhZHkpDQpoZWFsdGhfZGF0YSA8LSBoZWFsdGhfZGF0YSAlPiUNCiAgbXV0YXRlKHVzaWEgPSBhcy5udW1lcmljKGFnZSkpDQoNCiMgQmlubmluZyAnYWdlJyBpbnRvIGFnZSBjYXRlZ29yaWVzDQpiaW5uaW5nIDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgYWdlX2xldmVsID0gY3V0KA0KICAgICAgYWdlLA0KICAgICAgYnJlYWtzID0gcXVhbnRpbGUoYWdlLCBwcm9icyA9IGMoMCwgMC4zMywgMC42NiwgMSksIG5hLnJtID0gVFJVRSksDQogICAgICBsYWJlbHMgPSBjKCJZb3VuZyIsICJNaWRkbGUtYWdlZCIsICJPbGQiKSwNCiAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRQ0KICAgICkNCiAgKQ0KDQojIFNob3cgcmVzdWx0cyBpbiBhIGRhdGF0YWJsZQ0KRFQ6OmRhdGF0YWJsZShoZWFkKGJpbm5pbmcpLCBjYXB0aW9uID0gIkJpbm5pbmcgQWdlIGludG8gQ2F0ZWdvcmllcyIpDQpgYGANCg0KDQoNCiMjIyBLZXNpbXB1bGFuOg0KRGlzY3JldGl6YXRpb24gZGFwYXQgYmVybWFuZmFhdCB1bnR1ayBtZW1wZXJtdWRhaCBwZW1haGFtYW4gZGFuIGFuYWxpc2lzIGRhdGEsIHRlcnV0YW1hIGRhbGFtIGthc3VzIGRpIG1hbmEgaHVidW5nYW4gYW50YXJhIHZhcmlhYmVsIGtvbnRpbnUgZGFuIGhhc2lsIHlhbmcgZGlpbmdpbmthbiB0aWRhayBsaW5pZXIgYXRhdSBzdWxpdCB1bnR1ayBkaW1vZGVsa2FuIHNlY2FyYSBsYW5nc3VuZy4NCg0KDQojIDguIFNlYXNvbmFsaXR5DQoNClNlYXNvbmFsaXR5IGF0YXUgbXVzaW1hbiBhZGFsYWggcG9sYSB5YW5nIG11bmN1bCBzZWNhcmEgcGVyaW9kaWsgZGFsYW0gZGF0YSB5YW5nIHRlcmthaXQgZGVuZ2FuIHdha3R1LCBzZXBlcnRpIHBvbGEgdGFodW5hbiwgYnVsYW5hbiwgYXRhdSBtaW5nZ3Vhbi4gRml0dXIgc2Vhc29uYWxpdHkgc2FuZ2F0IHBlbnRpbmcgZGFsYW0gYW5hbGlzaXMgZGF0YSB0aW1lIHNlcmllcyB1bnR1ayBtZW1haGFtaSBmbHVrdHVhc2kgeWFuZyB0ZXJrYWl0IGRlbmdhbiBwZXJ1YmFoYW4gbXVzaW1hbiBkYWxhbSB0YWh1bi4NCg0KUGFkYSBkYXRhc2V0IGluaSwga2l0YSBha2FuIG1lbWJ1YXQgZml0dXIgbXVzaW1hbiBiZXJkYXNhcmthbiBpbmZvcm1hc2kgdGFuZ2dhbCB1bnR1ayBtZW5hbmdrYXAgcG9sYSB0YWh1bmFuLg0KDQojIyAqKkNvbnRvaDoqKiAgDQotICoqRm91cmllciBUcmFuc2Zvcm0qKiB1bnR1ayBla3N0cmFrc2kgZnJla3VlbnNpLg0KLSAqKkRldGVrc2kgTXVzaW1hbioqIGRhbGFtIGRhdGEgYnVsYW5hbi90YWh1bmFuLg0KDQojIyMgQ29udG9oIEthc3VzOg0KDQpVbnR1ayBtZW1vZGVsa2FuIHNlYXNvbmFsaXR5IGRhbGFtIGRhdGFzZXQga2VzZWhhdGFuIGluaSwga2l0YSBha2FuIG1lbmFtYmFoa2FuIGZpdHVyLWZpdHVyIGJlcmlrdXQ6DQotICpUYWh1biogKFllYXIpDQoNCi0gKkhhcmkgZGFsYW0gVGFodW4qIChEYXkgb2YgWWVhcikNCg0KLSAqRnVuZ3NpIFNpbnVzIGRhbiBDb3NpbnVzKiB1bnR1ayBtZW5ndWJhaCBkYXRhIG11c2ltYW4ga2UgZGFsYW0gZm9ybWF0IG51bWVyaWsgeWFuZyBkYXBhdCBkaWd1bmFrYW4gb2xlaCBtb2RlbCBtYWNoaW5lIGxlYXJuaW5nLg0KDQojIyMgQ29udG9oIEtvZGUgUjoNCg0KYGBge30NCg0KIyBFbnN1cmUgbG93ZXJjYXNlIGNvbHVtbiBuYW1lcw0KY29sbmFtZXMoaGVhbHRoX2RhdGEpIDwtIHRvbG93ZXIoY29sbmFtZXMoaGVhbHRoX2RhdGEpKQ0KDQojIFRyeSB0byBmaW5kIHRoZSBjb2x1bW4gdGhhdCByZXByZXNlbnRzIHRoZSBkYXRlDQpkYXRlX2NvbCA8LSBncmVwKCJ0YW5nZ2FsfGRhdGUiLCBjb2xuYW1lcyhoZWFsdGhfZGF0YSksIHZhbHVlID0gVFJVRSlbMV0NCg0KIyBDb252ZXJ0IHRoZSBjb2x1bW4gdG8gRGF0ZSB0eXBlIGlmIG5vdCBhbHJlYWR5DQpoZWFsdGhfZGF0YVtbZGF0ZV9jb2xdXSA8LSBhcy5EYXRlKGhlYWx0aF9kYXRhW1tkYXRlX2NvbF1dKQ0KDQojIENyZWF0ZSBzZWFzb25hbGl0eSBmZWF0dXJlcw0Kc2Vhc29uYWxpdHkgPC0gaGVhbHRoX2RhdGEgJT4lDQogIG11dGF0ZSgNCiAgICB5ZWFyID0geWVhciguZGF0YVtbZGF0ZV9jb2xdXSksDQogICAgZGF5X29mX3llYXIgPSB5ZGF5KC5kYXRhW1tkYXRlX2NvbF1dKSwNCiAgICBkYXlzX2luX3llYXIgPSBpZl9lbHNlKGxlYXBfeWVhciguZGF0YVtbZGF0ZV9jb2xdXSksIDM2NiwgMzY1KSwNCiAgICBzaW5feWVhciA9IHNpbigyICogcGkgKiBkYXlfb2ZfeWVhciAvIGRheXNfaW5feWVhciksDQogICAgY29zX3llYXIgPSBjb3MoMiAqIHBpICogZGF5X29mX3llYXIgLyBkYXlzX2luX3llYXIpDQogICkNCmBgYCAgDQoNCg0KDQojIyMgUGVuamVsYXNhbjoNCg0KLSAqVGFodW4gKFllYXIpOiogTWVueWltcGFuIGluZm9ybWFzaSB0YWh1biBkYXJpIGtvbG9tIHRhbmdnYWwuDQoNCi0gKkhhcmkgZGFsYW0gVGFodW4gKERheSBvZiBZZWFyKToqIE1lbmdoaXR1bmcgaGFyaSBrZS1iZXJhcGEgZGFsYW0gdGFodW4gdGVyc2VidXQuDQoNCi0gKlNpbnVzIGRhbiBDb3NpbnVzIChzaW5feWVhciBkYW4gY29zX3llYXIpOiogTWVuZ29udmVyc2kgaGFyaSBkYWxhbSB0YWh1biBtZW5qYWRpIG5pbGFpIHNpbnVzIGRhbiBjb3NpbnVzIHVudHVrIG1lbmFuZ2thcCBzaWZhdCBtdXNpbWFuIGRhbGFtIGJlbnR1ayBudW1lcmlrLiBJbmkgYWRhbGFoIHRla25payB1bXVtIHVudHVrIG1lbmdoaW5kYXJpIG1hc2FsYWggZGVuZ2FuIG1vZGVsIHlhbmcgdGlkYWsgZGFwYXQgbWVuYW5nYW5pIGRhdGEgbXVzaW1hbiB5YW5nIGJlcnNpZmF0IHNpa2xpcy4NCg0KDQoNCiMjIyBNYW5mYWF0IFNlYXNvbmFsaXR5Og0KLSBNZW1haGFtaSBQb2xhIE11c2ltYW46IEZpdHVyIG11c2ltYW4gZGFwYXQgbWVtYmFudHUgZGFsYW0gbWVtcHJlZGlrc2kgcG9sYSB5YW5nIGJlcnVsYW5nLCBzZXBlcnRpIGZsdWt0dWFzaSBrZXNlaGF0YW4gcGFkYSBwZXJpb2RlIHRlcnRlbnR1IGRhbGFtIHNldGFodW4uDQotIFBlbmluZ2thdGFuIEFrdXJhc2kgTW9kZWw6IERlbmdhbiBtZW1hc3Vra2FuIGluZm9ybWFzaSBtdXNpbWFuIGRhbGFtIG1vZGVsLCBraXRhIGRhcGF0IG1lbmluZ2thdGthbiBrZW1hbXB1YW4gcHJlZGlrc2kgdGVydXRhbWEgdW50dWsgZGF0YSB0aW1lIHNlcmllcy4NCg0KDQoNCiMjIyBIYXNpbCBUcmFuc2Zvcm1hc2kgDQoNCg0KYGBge3IsbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoRFQpDQoNCiMgRW5zdXJlIGxvd2VyY2FzZSBjb2x1bW4gbmFtZXMNCmNvbG5hbWVzKGhlYWx0aF9kYXRhKSA8LSB0b2xvd2VyKGNvbG5hbWVzKGhlYWx0aF9kYXRhKSkNCg0KIyBUcnkgdG8gZmluZCB0aGUgY29sdW1uIHRoYXQgcmVwcmVzZW50cyB0aGUgZGF0ZQ0KZGF0ZV9jb2wgPC0gZ3JlcCgidGFuZ2dhbHxkYXRlIiwgY29sbmFtZXMoaGVhbHRoX2RhdGEpLCB2YWx1ZSA9IFRSVUUpWzFdDQoNCiMgQ29udmVydCB0aGUgY29sdW1uIHRvIERhdGUgdHlwZSBpZiBub3QgYWxyZWFkeQ0KaGVhbHRoX2RhdGFbW2RhdGVfY29sXV0gPC0gYXMuRGF0ZShoZWFsdGhfZGF0YVtbZGF0ZV9jb2xdXSkNCg0KIyBDcmVhdGUgc2Vhc29uYWxpdHkgZmVhdHVyZXMNCnNlYXNvbmFsaXR5IDwtIGhlYWx0aF9kYXRhICU+JQ0KICBtdXRhdGUoDQogICAgeWVhciA9IHllYXIoLmRhdGFbW2RhdGVfY29sXV0pLA0KICAgIGRheV9vZl95ZWFyID0geWRheSguZGF0YVtbZGF0ZV9jb2xdXSksDQogICAgZGF5c19pbl95ZWFyID0gaWZfZWxzZShsZWFwX3llYXIoLmRhdGFbW2RhdGVfY29sXV0pLCAzNjYsIDM2NSksDQogICAgc2luX3llYXIgPSBzaW4oMiAqIHBpICogZGF5X29mX3llYXIgLyBkYXlzX2luX3llYXIpLA0KICAgIGNvc195ZWFyID0gY29zKDIgKiBwaSAqIGRheV9vZl95ZWFyIC8gZGF5c19pbl95ZWFyKQ0KICApDQoNCiMgRGlzcGxheSB0aGUgcmVzdWx0DQpEVDo6ZGF0YXRhYmxlKGhlYWQoc2Vhc29uYWxpdHkpLCBjYXB0aW9uID0gIlNlYXNvbmFsaXR5IEZlYXR1cmVzIEJhc2VkIG9uIERhdGUiKQ0KYGBgDQoNCg0KIyMjICBLZXNpbXB1bGFuOg0KRml0dXIgc2Vhc29uYWxpdHkgc2FuZ2F0IGJlcmd1bmEgZGFsYW0gZGF0YXNldCBkZW5nYW4ga29tcG9uZW4gd2FrdHUgeWFuZyBtZW1wZW5nYXJ1aGkgaGFzaWwsIHNlcGVydGkga2VzZWhhdGFuIHlhbmcgZGFwYXQgZGlwZW5nYXJ1aGkgb2xlaCBwZXJ1YmFoYW4gbXVzaW1hbi4gRGVuZ2FuIG1lbmdndW5ha2FuIGZpdHVyLWZpdHVyIG11c2ltYW4sIG1vZGVsIGRhcGF0IGxlYmloIGVmZWt0aWYgZGFsYW0gbWVuYW5na2FwIHBvbGEgeWFuZyB0ZXJrYWl0IGRlbmdhbiBwZXJ1YmFoYW4gbXVzaW1hbiBkYW4gbWVuaW5na2F0a2FuIGFrdXJhc2kgcHJlZGlrc2kuDQoNCiMgKipQZW51dHVwKiogIA0KDQpUcmFuc2Zvcm1hc2kgZGF0YSBhZGFsYWggdGFoYXAgcGVudGluZyB5YW5nIG1lbmVudHVrYW4ga3VhbGl0YXMgYW5hbGlzaXMgZGFuIHBlbW9kZWxhbi4gVGVrbmlrLXRla25payB5YW5nIHRlbGFoIGRpYmFoYXMgc2VwZXJ0aSB0cmFuc2Zvcm1hc2kgdGVtcG9yYWwsIGRpc3RyaWJ1c2ksIHNjYWxpbmcsIGVuY29kaW5nLCBmZWF0dXJlIGVuZ2luZWVyaW5nLCBoaW5nZ2EgaGFuZGxpbmcgb3V0bGllciwgc2VtdWFueWEgYmVydHVqdWFuIHVudHVrIG1lbWJ1YXQgZGF0YSBsZWJpaCAiYmVyc2FoYWJhdCIgZGVuZ2FuIGFsZ29yaXRtYSBhbmFsaXNpcy4gRGVuZ2FuIHBlbWlsaWhhbiBtZXRvZGUgeWFuZyB0ZXBhdCwga2l0YSBkYXBhdCBtZW5pbmdrYXRrYW4gYWt1cmFzaSBtb2RlbCBkYW4gbWVtYnVhdCBpbnRlcnByZXRhc2kgZGF0YSBtZW5qYWRpIGxlYmloIGJhaWsuDQoNCg0KIyAqKlJlZmVyZW5zaSoqDQoNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcvZHNjaWVuY2VsYWJzL2RhdGFfc2NpZW5jZV9wcm9ncmFtbWluZy8wNC1EYXRhX0NvbGxlY3Rpb24uaHRtbA0KDQpodHRwczovL3d3dy5zdGF0aXN0aWtpYW4uY29tLzIwMTMvMDEvdHJhbnNmb3JtYXNpLWRhdGEuaHRtbA0KDQpodHRwczovL2V4c2lnaHQuaWQvYmxvZy8yMDIzLzA1LzE0L3RyYW5zZm9ybWFzaS1kYXRhLXBhcnQtMS8NCg0KaHR0cHM6Ly9wYXRyYXN0YXRpc3Rpa2EuY29tL3RyYW5zZm9ybWFzaS1kYXRhLw0KDQpodHRwczovL3d3dy5yZXZvdS5jby9rb3Nha2F0YS9kYXRhLXRyYW5zZm9ybWF0aW9uDQo=