KELOMPOK 3

Scaling &
Normalization
Z-Score
Standardization
# Standardisasi Z-Score: mengubah data agar memiliki rata-rata 0 dan standar deviasi 1
financial_scaled <- financial_market %>%
mutate(
Stock_Price_Std = scale(Stock_Price),
Volume_Traded_Std = scale(Volume_Traded),
Market_Cap_Std = scale(Market_Cap),
PE_Ratio_Std = scale(PE_Ratio),
Dividend_Yield_Std = scale(Dividend_Yield),
Return_on_Equity_Std = scale(Return_on_Equity)
)
head(financial_scaled)
Penjelasan:
financial_market adalah data frame yang berisi data pasar
keuangan. Kolom-kolomnya mencakup variabel seperti harga saham
(Stock_Price), volume perdagangan (Volume_Traded), kapitalisasi pasar
(Market_Cap), rasio PE (PE_Ratio), dividen (Dividend_Yield), dan ROE
(Return_on_Equity).
Fungsi mutate() dari paket dplyr digunakan untuk menambahkan
kolom-kolom baru hasil transformasi dari kolom yang ada.
Z-Score Standardization adalah metode transformasi data yang
mengubah setiap nilai menjadi ukuran dalam satuan standar deviasi dari
rata-rata.
Fungsi scale() adalah fungsi bawaan R untuk melakukan Z-score
standardization, yaitu: \[ Z = \frac{X - \mu
} {\sigma} \]
Hasilnya adalah data baru yang:
- Kolom baru dengan akhiran _Std dibuat untuk setiap variabel,
seperti:
Stock_Price_Std
Volume_Traded_Std
Market_Cap_Std
PE_Ratio_Std
Dividend_Yield_Std
Return_on_Equity_Std
- head(financial_scaled) digunakan untuk menampilkan 6 baris pertama
dari data yang telah ditransformasi.
Contoh Perhitungan
Manual
Misalkan data Stock_Price: [100, 120, 150, 130, 110]
- Hitung Mean:
\[ \mu = \frac{100 + 120 + 150 + 130 + 110
} {5} = \frac{610}{5} = 122\]
- Hitung Standar Deviasi (σ):
\[ \sigma = \sqrt{\frac{(100 - 122)^2 +
(120 - 122)^2 + (150 - 122)^2 + (130 - 122)^2 + (110 - 122)^2 } {5}}
\]
\[ = \sqrt{\frac{484 + 4 + 784 + 64 +
144}{5}} = \sqrt{\frac{1480}{5}} = \sqrt{296} = 17.2 \]
- Z-Score untuk nilai 150:
\[ Z = \frac{150 - 122 } {17.2} =
\frac{28}{17.2} = 1.63 \]
Min-Max
Normalization
# Normalisasi Min-Max: mengubah skala data ke dalam rentang [0, 1]
financial_normalized <- financial_market %>%
mutate(
Stock_Price_Norm = (Stock_Price - min(Stock_Price)) / (max(Stock_Price) - min(Stock_Price)),
Volume_Traded_Norm = (Volume_Traded - min(Volume_Traded)) / (max(Volume_Traded) - min(Volume_Traded)),
Market_Cap_Norm = (Market_Cap - min(Market_Cap)) / (max(Market_Cap - min(Market_Cap))),
PE_Ratio_Norm = (PE_Ratio - min(PE_Ratio)) / (max(PE_Ratio) - min(PE_Ratio)),
Dividend_Yield_Norm = (Dividend_Yield - min(Dividend_Yield)) / (max(Dividend_Yield) - min(Dividend_Yield)),
Return_on_Equity_Norm = (Return_on_Equity - min(Return_on_Equity)) / (max(Return_on_Equity) - min(Return_on_Equity))
)
head(financial_normalized)
Penjelasan
financial_market adalah data frame yang berisi data pasar
keuangan. Kolom-kolomnya mencakup variabel seperti harga saham
(Stock_Price), volume perdagangan (Volume_Traded), kapitalisasi pasar
(Market_Cap), rasio PE (PE_Ratio), dividen (Dividend_Yield), dan ROE
(Return_on_Equity).
Fungsi mutate() dari paket dplyr digunakan untuk menambahkan
kolom-kolom baru hasil transformasi dari kolom yang ada.
Normalisasi Min-Max adalah metode penskalaan data ke dalam
rentang tetap, yaitu [0, 1], dengan menggunakan rumus berikut: \[ X_{norm} = \frac{X - X_{min} } {X_{max} -
X_{min}} \]
Hasilnya adalah data baru yang:
Memiliki nilai terendah = 0
Memiliki nilai tertinggi = 1
Tetap mempertahankan distribusi asli datanya (namun rentangnya
dipersempit)
- Kolom baru dengan akhiran _Norm dibuat untuk setiap variabel,
seperti:
Stock_Price_Norm
Volume_Traded_Norm
Market_Cap_Norm
PE_Ratio_Norm
Dividend_Yield_Norm
Return_on_Equity_Norm
- Fungsi head(financial_normalized) digunakan untuk menampilkan 6
baris pertama dari data yang telah dinormalisasi.
Contoh Perhitungan
Manual
Data Stock_Price:[100, 120, 150, 130, 110]
- Minimum dan Maksimum:
- Min-Max Normalization untuk nilai 130: \[
X_{norm} = \frac{130 - 100 } {150 - 100} =
\frac{30}{50} = 0.6\]
Categorical
Encoding
Di dalam data, kadang kita menemukan kolom yang isinya bukan angka,
tapi kata-kata atau kategori, misalnya:
Sector = “Finance”, “Retail”, “Technology”
Performance = “Positive”, “Negative”, “Stable”
library(readr)
library(dplyr)
# Baca file CSV-nya
financial_market <- read_csv("financial market.csv")
# Tampilkan 6 data teratas
head(financial_market)
Masalahnya, komputer hanya bisa membaca angka. Maka,
kita perlu mengubah kata-kata ini menjadi angka. Caranya disebut
Categorical Encoding.
One Hot Encoding
Gampangnya: Kita bikin kolom baru untuk setiap kategori,
lalu kita kasih angka 1 jika cocok, dan 0 kalau
tidak.
Kenapa Nggak Pakai Angka Biasa (1, 2, 3)?
Karena kalau kita kasih angka seperti:
Positive = 1
Negative = 2
Stable = 3
Komputer bisa salah paham dan mengira ada
urutan atau ranking, padahal nggak
ada.
Padahal kategori itu cuma label, bukan nilai.
Makanya kita pakai biner (0 dan 1), biar komputer
ngerti bahwa semua kategori itu setara, nggak ada yang
lebih tinggi atau lebih rendah.
berikut kodenya:
library(fastDummies)
# Ubah kolom Sector & Performance jadi bentuk angka biner (0/1)
one_hot <- dummy_cols(financial_market,
select_columns = c("Sector", "Performance"),
remove_first_dummy = FALSE,
remove_selected_columns = TRUE)
# Tampilkan 6 data hasil one hot encoding
head(one_hot)
Frequency
Encoding
Gampangnya: Kita hitung berapa kali setiap
kategori muncul, lalu setiap data diganti dengan angka
frekuensinya.
# Fungsi untuk menghitung frekuensi (berapa sering muncul)
freq_enc <- function(col) {
tab <- table(col)
return(as.numeric(tab[col]) / length(col))
}
# Tambahkan kolom frekuensi ke data
data_freq <- financial_market %>%
mutate(
Sector_freq = freq_enc(Sector),
Performance_freq = freq_enc(Performance)
)
# Tampilkan 6 data teratas
head(data_freq)
Hasilnya:
Akan muncul dua kolom baru:
Setiap baris akan berisi angka pecahan (misalnya 0.360, 0.336) yang
menunjukkan seberapa sering nilai tersebut muncul dalam
keseluruhan data.
Feature
Engineering
# Feature Engineering pada Financial_market
Feature_Eng <- financial_market %>%
mutate(
# 1. New Features from Raw Data
Price_Per_Volume = Stock_Price / (Volume_Traded + 1e-5), # Hindari pembagian dengan nol
# 2. Product of Features, Crossed Terms
PE_x_ROE = PE_Ratio * Return_on_Equity,
# 3. Price per Unit, Efficiency
Yield_to_PE = Dividend_Yield / (PE_Ratio + 1e-5), # Yield per PE
# 4. Ranking, Percentile
MarketCap_Rank = rank(-Market_Cap), # Rank market cap terbesar ke terkecil
ROE_Quartile = ntile(Return_on_Equity, 4), # Bagi ROE ke dalam 4 kuartil
# 5. From IDs: Prefix, Length, Pattern
Stock_ID_Prefix = substr(Stock_ID, 1, 3),
Stock_ID_Length = nchar(Stock_ID)
) %>%
# 6. Avg, Sum, Count by Group
group_by(Sector) %>%
mutate(
Avg_PE_Sector = mean(PE_Ratio, na.rm = TRUE),
Avg_ROE_Sector = mean(Return_on_Equity, na.rm = TRUE),
Total_Companies_Sector = n()
) %>%
ungroup()
head(Feature_Eng)
Penjelasan
- New Features from Raw Data
- Product of Features, Crossed Terms
Mengalikan Price to Earnings Ratio (P/E) dengan Return on Equity
(ROE) menghasilkan interaksi antar dua metrik penting:
Interaksi ini bisa memberi sinyal apakah saham undervalued atau
overvalued dengan memperhitungkan efisiensi.
- Price per Unit, Efficiency
- Ranking, Percentile
MarketCap_Rank: Memberi ranking terhadap perusahaan berdasarkan
kapitalisasi pasar dari terbesar (rank 1) ke terkecil.
ROE_Quartile: Mengelompokkan ROE ke dalam 4 kuartil. Tujuannya
untuk klasifikasi performa perusahaan berdasarkan ROE:
- From IDs: Prefix, Length, Pattern
Stock_ID_Prefix: Mengambil 3 karakter awal dari ID saham. Ini
bisa menunjukkan kode kategori, jenis saham, atau asal bursa.
Stock_ID_Length: Panjang dari ID saham. Bisa membantu deteksi
format ID yang tidak lazim.
- Avg, Sum, Count by Group
Interaction
Features
Financial_interaction <- financial_market %>%
mutate(
Impact_Score = Stock_Price * Return_on_Equity
)
head(Financial_interaction)
Ratio Features
Financial_ratio <- financial_market %>%
mutate(
Dividend_to_Price = Dividend_Yield / (Stock_Price + 1e-5)
)
head(Financial_ratio)
Group
Aggregation
Sector_summary <- financial_market %>%
group_by(Sector) %>%
summarise(
Avg_Market_Cap = mean(Market_Cap),
Max_Stock_Price = max(Stock_Price),
Company_Count = n()
)
Financial_merged <- left_join(financial_market, Sector_summary, by = "Sector")
head(Financial_merged)
Penjelasan
Sector_summary membuat ringkasan sektor:
Avg_Market_Cap: Kapitalisasi pasar rata-rata di sektor.
Max_Stock_Price: Harga saham tertinggi di sektor.
Company_Count: Jumlah perusahaan per sektor.
Lalu left_join dilakukan untuk menggabungkan informasi ini
kembali ke data utama, memungkinkan perbandingan antar perusahaan dalam
satu sektor.
Text Cleaning &
Feature Creation
Financial_text_feature <- financial_market %>%
mutate(
Stock_Num_Suffix = as.numeric(str_extract(Stock_ID, "\\d+"))
)
head(Financial_text_feature)
Cumulative
Features
Financial_cumulative <- financial_market %>%
arrange(Sector, Date) %>%
group_by(Sector) %>%
mutate(
Cumulative_Volume = cumsum(Volume_Traded)
) %>%
ungroup()
head(Financial_cumulative)
Kesimpulan Umum
Semua proses feature engineering ini bertujuan untuk:
Memperkaya data: Membuat fitur baru yang bisa menangkap
pola-pola tersembunyi di data mentah.
Mempermudah analisis eksploratif: Dengan agregasi,
ranking, dan transformasi, kita bisa lebih mudah melihat perusahaan
unggulan, tren sektor, dan perbandingan antar perusahaan.
Meningkatkan performa model machine learning atau
prediksi: Fitur yang informatif dan relevan dapat membantu model
mengenali hubungan antara variabel lebih baik.
Memberi insight bisnis dan investasi: Seperti
pemeringkatan saham, klasifikasi sektor, dan identifikasi saham dengan
performa keuangan baik.
Deteksi Outlier
Menggunakan Z-score dan IQR
library(dplyr)
# --- Z-score method for detecting outliers ---
data_outliers <- financial_market %>%
mutate(
z_scores_SP = scale(Stock_Price),
Outlier_Flag = ifelse(abs(z_scores_SP) > 3, "Outlier", "Normal")
)
# --- IQR method for detecting and removing outliers ---
Q1 <- quantile(financial_market$Total_Price, 0.25)
Q3 <- quantile(financial_market$Total_Price, 0.75)
IQR_val <- Q3 - Q1
data_outliers_iqr <- financial_market %>%
filter(
Stock_Price > (Q1 - 1.5 * IQR_val) &
Stock_Price < (Q3 + 1.5 * IQR_val)
)
head(data_outliers)
1. Deteksi Outlier dengan Metode Z-Score
- Anda menggunakan Z-score method untuk mendeteksi
outlier pada kolom Stock_Price.
- Z-score mengukur seberapa jauh suatu nilai dari
rata-rata dalam satuan standar deviasi.
- Rumus: Z = (x - mean) / sd
- Baris data yang memiliki nilai Z-score lebih dari 3 atau kurang dari
-3 dianggap outlier.
- Kolom baru Outlier_Flag ditambahkan, berisi label:
- Outlier jika nilai Z-score melebihi 3 atau kurang
dari -3,
- Normal jika masih dalam batas normal.
2. Pembersihan Outlier dengan Metode IQR
Metode kedua menggunakan Interquartile Range
(IQR) pada kolom Total_Price untuk mendeteksi
dan menghapus outlier.
Perhitungan:
- Q1 (kuartil 1) = nilai pada persentil ke-25,
- Q3 (kuartil 3) = nilai pada persentil ke-75,
- IQR = Q3 - Q1.
Data dianggap outlier jika berada di luar
rentang: \[
\left[ Q_1 - 1.5 \times \text{IQR},\; Q_3 + 1.5 \times \text{IQR}
\right]
\]
Baris yang berada di luar batas ini difilter dan dihapus dari
data dengan filter().
Z-score untuk mendeteksi outlier pada Stock_Price,
IQR untuk menghapus outlier pada Total_Price.
Metode ini penting untuk membersihkan data, sehingga analisis
atau model yang akan dibangun tidak bias oleh nilai ekstrem.
Discretization
(Binning)
library(dplyr)
# Baca data
financial_market <- financial_market
# Binning (Equal-frequency) dengan quantile
binned_data <- financial_market %>%
mutate(
Price_Level = cut(
Stock_Price,
breaks = quantile(Stock_Price, probs = c(0, 0.33, 0.66, 1), na.rm = TRUE),
labels = c("Low", "Medium", "High"),
include.lowest = TRUE
)
)
#Tampilkan hasil binning
head(binned_data)
1. Tujuan Binning
- Tujuannya adalah untuk mengelompokkan data numerik dari kolom
Stock_Price menjadi beberapa kategori
diskrit (dalam hal ini: Low, Medium, High).
- Ini disebut **equal-frequency binning*, karena setiap kelompok akan
memiliki jumlah data yang kurang lebih sama.
2. Proses yang Dillakukan
- quantile() digunakan untuk menentukan batas-batas
(breaks) berdasarkan persentil:
- 0% (minimum),
- 33% (sepertiga data),
- 66% (dua pertiga data),
- 100% (maksimum).
- Kemudian fungsi cut() membagi kolom Stock_Price ke dalam tiga
kelompok berdasarkan batas-batas tersebut, yaitu:
- Low: nilai dari kuantil ke-0 hingga ke-33,
- Medium: kuantil ke-33 hingga ke-66,
- High: kuantil ke-66 hingga ke-100.
- Kolom hasil kategorisasi tersebut dinamakan
Price_Level.
Seasonality
library(dplyr)
library(lubridate)
Seasonality <- financial_market %>%
mutate(
Date = as.Date(Date, format = "%m/%d/%Y"),
Year = year(Date),
DayOfYear = yday(Date),
DaysInYear = if_else(leap_year(Date), 366, 365),
sin_year = sin(2 * pi * DayOfYear / DaysInYear),
cos_year = cos(2 * pi * DayOfYear / DaysInYear)
)
head(Seasonality)
Kesimpulan yang Didukung oleh Data
- Musim Maret–Juni (sin_year tinggi):
2023-03-15 dan 2023-06-05 menunjukkan sin_year
sangat tinggi dan performa masing-masing adalah Stable dan
Positive.
Ini mendukung pola bahwa kuartal 2 (Q2) sering
menunjukkan performa kuat atau stabil.
- Akhir Tahun – November (sin_year negatif
tinggi):
2020-11-16 (sin_year = -0.6979) :
Stable
Tidak ekstrem negatif, tapi mendekati. Menunjukkan
kinerja yang tidak terlalu kuat, sesuai dengan dugaan
bahwa di akhir tahun bisa terjadi tekanan pasar (misalnya, aksi ambil
untung/take profit).
- Awal Tahun – Januari (sin dan cos mendekati ekstrem
positif):
2023-01-02 : sin_year ≈ 0, cos_year ≈ 1 :
Stable
Sesuai dengan interpretasi bahwa awal tahun cenderung netral atau
belum menunjukkan tren jelas.
- Pertengahan Tahun – Juli (sin_year mendekati nol, cos_year
negatif tinggi):
- 2021-07-14 : Positive meskipun sin_year = -0.2135 : berarti
ada potensi kinerja baik di pertengahan tahun, meskipun secara musiman
berada dalam transisiturun.
- Anomali:
- 2023-03-22 : sin_year sangat tinggi (0.9845) tapi
performa Negative. Ini menunjukkan bahwa meskipun sinyal musiman
mendukung pertumbuhan, faktor lain (mungkin eksternal atau sektor
tertentu) bisa memengaruhi negatif.
LS0tDQp0aXRsZTogIkRhdGEgVHJhbmZvcm1hdGlvbiINCnN1YnRpdGxlOiAiRGF0YSBTY2llbmNlIFByb2dyYW1taW5nIg0KYXV0aG9yOiANCiAgLSAiS0VMT01QT0sgMyINCiAgLSAiSm9hbnMgSGVua3kgU2VydmF0aXVzIFMgKDUyMjQwMDE3KSINCiAgLSAiTm92YSBTaXRvcnVzICg1MjI0MDAyMykiDQogIC0gIk9saXZpYSBNZWlsaW5kYSBEYXZ0aW4gUCAoNTIyNDAwMTEpIg0KICAtICJOYWJpbGEgQW5nZ2l0YSBQdXRyaSAoNTIyNDAwMDIpIg0KICAtICJSYWNoZWxpYSBCZXZpbmEgVGFtYmFqb25nICg1MjI0MDAyMSkiDQogIC0gIkR3aSBTcmkgWWFudGkgTWFudWxsYW5nICg1MjI0MDAzMCkiDQogIC0gIkNoZWxsbyBGcmhpbm8gTWlrZSBNICg1MjI0MDAzMSkiDQpkYXRlOiAgImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0Og0KICBybWRmb3JtYXRzOjpkb3duY3V0ZTogICAjIGh0dHBzOi8vZ2l0aHViLmNvbS9qdWJhL3JtZGZvcm1hdHMNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQ0KICAgIHRodW1ibmFpbHM6IHRydWUNCiAgICBsaWdodGJveDogdHJ1ZQ0KICAgIGdhbGxlcnk6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICBsaWJfZGlyOiBsaWJzDQogICAgZGZfcHJpbnQ6ICJwYWdlZCINCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93Ig0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIA0KLS0tDQoNCjxzdHlsZT4NCiAgYm9keSB7DQogICAgdGV4dC1hbGlnbjoganVzdGlmeTsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTsNCiAgICBvdmVyZmxvdy14OiBhdXRvOw0KICAgIGZvbnQtZmFtaWx5OiBzZXJpZjsNCiAgfQ0KPC9zdHlsZT4NCg0KKipLRUxPTVBPSyAzKioNCg0KPGltZyBpZD0ia2Vsb21wb2szIiBzcmM9IkM6L1VzZXJzL1VTRVIvRG9jdW1lbnRzL0RTUEtFTDMva2VsMy5qcGciIGFsdD0ia2VsIiBzdHlsZT0id2lkdGg6ODAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ij4NCg0KDQoNCg0KIyBUZW1wb3JhbCBUcmFuc2Zvcm1hdGlvbg0KDQoqKkZJTkFOQ0lBTCBNQVJLRVQqKg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoem9vKQ0KbGlicmFyeShEVCkNCmZpbmFuY2lhbF9tYXJrZXQgPC0gcmVhZF9jc3YoImZpbmFuY2lhbCBtYXJrZXQuY3N2IikNCmRhdGF0YWJsZShmaW5hbmNpYWxfbWFya2V0LCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkpDQpgYGANCg0KIyMgTGFnLERpZmYsUm9sbGluZw0KDQoxLiAqKkxhZyoqOiBNZW5nYW1iaWwgbmlsYWkgZGFyaSBwZXJpb2RlIHNlYmVsdW1ueWEuIEJlcmd1bmEgdW50dWsgbWVtYmFuZGluZ2thbiBkYXRhIHNla2FyYW5nIGRlbmdhbiBkYXRhIG1hc2EgbGFsdS4NCg0KMi4gKipEaWZmKio6IE1lbmdoaXR1bmcgc2VsaXNpaCBhbnRhciBlbGVtZW4gYmVydHVydXQtdHVydXQuLiBNZW1iYW50dSBtZW5ndWt1ciBwZXJ1YmFoYW4gYW50YXIgd2FrdHUuDQoNCjMuICoqUm9sbGluZyBNZWFuKio6IFJhdGEtcmF0YSBiZXJnZXJhayBkYXJpIGJlYmVyYXBhIG5pbGFpIHRlcmFraGlyIChtaXNhbG55YSA1IGhhcmkgdGVyYWtoaXIpLiBEaWd1bmFrYW4gdW50dWsgbWVsaWhhdCB0cmVuIGphbmdrYSBwZW5kZWsgZGVuZ2FuIG1lbmdoYWx1c2thbiBmbHVrdHVhc2kgZGF0YS4NCg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQoNCmZpbmFuY2lhbF9tYXJrZXQgPC0gcmVhZF9jc3YoImZpbmFuY2lhbCBtYXJrZXQuY3N2IikNCg0KIyBMYW5qdXRrYW4gdHJhbnNmb3JtYXNpDQpUZW1wcmFsIDwtIGZpbmFuY2lhbF9tYXJrZXQgJT4lDQogIG11dGF0ZShEYXRlID0geW1kKERhdGUpKSAgIyBnYW50aSAnRGF0ZScga2FsYXUgbmFtYSBrb2xvbW55YSBiZXJiZWRhDQoNCiMgSGl0dW5nIExhZywgRGlmZiwgUm9sbGluZyBNZWFuIHVudHVrIFN0b2NrX1ByaWNlLCBWb2x1bWVfVHJhZGVkLCBNYXJrZXRfQ2FwDQpMRFIgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgYXJyYW5nZShTZWN0b3IsIERhdGUpICU+JQ0KICBncm91cF9ieShTZWN0b3IpICU+JQ0KICBtdXRhdGUoDQogICAgIyBMYWcNCiAgICBMYWdfU3RvY2tfUHJpY2UgPSBsYWcoU3RvY2tfUHJpY2UpLA0KICAgIExhZ19Wb2x1bWUgPSBsYWcoVm9sdW1lX1RyYWRlZCksDQogICAgTGFnX01hcmtldF9DYXAgPSBsYWcoTWFya2V0X0NhcCksDQogICAgDQogICAgIyBEaWZmDQogICAgRGlmZl9TdG9ja19QcmljZSA9IHJvdW5kKFN0b2NrX1ByaWNlIC0gTGFnX1N0b2NrX1ByaWNlLCAyKSwNCiAgICBEaWZmX1ZvbHVtZSA9IFZvbHVtZV9UcmFkZWQgLSBMYWdfVm9sdW1lLA0KICAgIERpZmZfTWFya2V0X0NhcCA9IE1hcmtldF9DYXAgLSBMYWdfTWFya2V0X0NhcCwNCiAgICANCiAgICAjIFJvbGxpbmcgTWVhbiAoMyBoYXJpIHRlcmFraGlyKQ0KICAgIFJvbGxpbmdNZWFuX1N0b2NrX1ByaWNlXzMgPSByb3VuZCh6b286OnJvbGxhcHBseShTdG9ja19QcmljZSwgd2lkdGggPSAzLCBGVU4gPSBtZWFuLCBmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IiksIDIpLA0KICAgIFJvbGxpbmdNZWFuX1ZvbHVtZV8zID0gcm91bmQoem9vOjpyb2xsYXBwbHkoVm9sdW1lX1RyYWRlZCwgd2lkdGggPSAzLCBGVU4gPSBtZWFuLCBmaWxsID0gTkEsIGFsaWduID0gInJpZ2h0IikpLA0KICAgIFJvbGxpbmdNZWFuX01hcmtldF9DYXBfMyA9IHJvdW5kKHpvbzo6cm9sbGFwcGx5KE1hcmtldF9DYXAsIHdpZHRoID0gMywgRlVOID0gbWVhbiwgZmlsbCA9IE5BLCBhbGlnbiA9ICJyaWdodCIpKQ0KICApICU+JQ0KICB1bmdyb3VwKCkNCg0KIyBUYW1waWxrYW4gaGFzaWwNCmRhdGF0YWJsZShMRFIsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSkNCmBgYA0KMS4gKipTdG9ja19QcmljZSoqOiBIYXJnYSBzYWhhbSBzZXJpbmcgZGlhbmFsaXNpcyBiZXJkYXNhcmthbiBwZXJ1YmFoYW4gd2FrdHUgKG1pc2FsOiBuYWlrL3R1cnVuIGhhcmdhIGhhcmlhbikuRGktKmxhZyogdW50dWsgbWVsaWhhdCBoYXJnYSBzZWJlbHVtbnlhLCAqZGlmZiogdW50dWsgc2VsaXNpaCBoYXJpYW4sIGRhbiAqcm9sbGluZyBtZWFuKiB1bnR1ayB0cmVuIGphbmdrYSBwZW5kZWsuDQoNCjIuICoqVm9sdW1lX1RyYWRlZCoqOiBWb2x1bWUgdHJhbnNha3NpIGJpc2EgZmx1a3R1YXRpZiwgcGVybHUgZGlsaWhhdCBwZXJ1YmFoYW5ueWEgZGFuIHJhdGEtcmF0YSBkYWxhbSB3aW5kb3cgd2FrdHUuIERpLSpsYWcqIGRhbiAqZGlmZiogdW50dWsgZGV0ZWtzaSBsb25qYWthbiBha3Rpdml0YXMsICpyb2xsaW5nIG1lYW4qIHVudHVrIGtlc3RhYmlsYW4gdm9sdW1lLg0KDQozLiAqKk1hcmtldF9DYXAqKjogRGktKmRpZmYqIGRhbiAqcm9sbGluZyBtZWFuKiB1bnR1ayBtZW1hbnRhdSBwZXJ1YmFoYW4gbmlsYWkgcGFzYXIgc2FoYW0gc2VjYXJhIGJlcnRhaGFwLg0KDQoNCiMjIEV4dHJhY3QgRGF0ZQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoc3RyaW5ncikNCg0KRXh0cmFjdCA8LSBmaW5hbmNpYWxfbWFya2V0ICU+JQ0KICBtdXRhdGUoDQogICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIiksICAjIGtvbnZlcnNpIGRhcmkga2FyYWt0ZXIga2UgRGF0ZQ0KICAgIERheV9vZl9XZWVrID0gd2Vla2RheXMoRGF0ZSksDQogICAgTW9udGggPSBtb250aChEYXRlLCBsYWJlbCA9IFRSVUUpLA0KICAgIFllYXIgPSB5ZWFyKERhdGUpLA0KICAgIElzX1dlZWtlbmQgPSBpZmVsc2UoRGF5X29mX1dlZWsgJWluJSBjKCJTYXR1cmRheSIsICJTdW5kYXkiKSwgMSwgMCksDQogICAgU2VjdG9yID0gYXMuZmFjdG9yKFNlY3RvciksDQogICAgUGVyZm9ybWFuY2UgPSBhcy5mYWN0b3IoUGVyZm9ybWFuY2UpDQogICkgJT4lDQogIGJpbmRfY29scygNCiAgICBhcy5kYXRhLmZyYW1lKG1vZGVsLm1hdHJpeCh+IFNlY3RvciAtIDEsIGRhdGEgPSAuKSksDQogICAgYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgofiBQZXJmb3JtYW5jZSAtIDEsIGRhdGEgPSAuKSkNCiAgKQ0KDQojIExpaGF0IGJlYmVyYXBhIGJhcmlzIHBlcnRhbWENCmRhdGF0YWJsZShFeHRyYWN0LCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSkpDQoNCmBgYA0KS29udmVyc2kgVGFuZ2dhbDogVmFyaWFiZWwgRGF0ZSBkaWtvbnZlcnNpIGRhcmkgZm9ybWF0IGthcmFrdGVyIGtlIGZvcm1hdCBEYXRlIGFnYXIgZGFwYXQgZGlhbmFsaXNpcyBzZWNhcmEgdGVtcG9yYWwuDQoNCkVrc3RyYWtzaSBJbmZvcm1hc2kgV2FrdHU6IERhcmkgdGFuZ2dhbCB0ZXJzZWJ1dCwgZGl0YW1iYWhrYW4gYmViZXJhcGEgaW5mb3JtYXNpIHdha3R1Og0KDQpEYXlfb2ZfV2VlazogaGFyaSBkYWxhbSBtaW5nZ3UsDQoNCk1vbnRoOiBidWxhbiAoZGFsYW0gZm9ybWF0IGxhYmVsLCBtaXNhbG55YSBKYW4sIEZlYiksDQoNClllYXI6IHRhaHVuIHRyYW5zYWtzaSwNCg0KSXNfV2Vla2VuZDogaW5kaWthdG9yIGFwYWthaCBoYXJpIHRlcnNlYnV0IGFraGlyIHBla2FuIChTYWJ0dS9NaW5nZ3UpLg0KDQojIyBDdW11bGF0aXZlIFZhbHVlDQogDQpgYGB7cn0NClRlbXByYWwzIDwtIGZpbmFuY2lhbF9tYXJrZXQgJT4lDQogIGFycmFuZ2UoU3RvY2tfSUQsIERhdGUpICU+JQ0KICBncm91cF9ieShTdG9ja19JRCkgJT4lDQogIG11dGF0ZSgNCiAgICBDdW11bGF0aXZlX1ZvbHVtZSA9IGN1bXN1bShWb2x1bWVfVHJhZGVkKSwNCiAgICBDdW11bGF0aXZlX01hcmtldENhcCA9IGN1bXN1bShNYXJrZXRfQ2FwKSwNCiAgICBDdW11bGF0aXZlX0F2Z1ByaWNlID0gY3VtbWVhbihTdG9ja19QcmljZSkNCiAgKSAlPiUNCiAgdW5ncm91cCgpDQoNCmhlYWQoVGVtcHJhbDMpDQoNCmBgYA0KUG90b25nYW4ga29kZSBpbmkgZGlndW5ha2FuIHVudHVrIG1lbmdoaXR1bmcgYWt1bXVsYXNpIGRhdGEgcGFzYXIgc2FoYW0gc2VjYXJhIHRlbXBvcmFsIGJlcmRhc2Fya2FuIHNldGlhcCBgU3RvY2tfSURgLiBEYXRhIHBlcnRhbWEtdGFtYSBkaXVydXRrYW4gYmVyZGFzYXJrYW4gYFN0b2NrX0lEYCBkYW4gYERhdGVgIGFnYXIgYW5hbGlzaXMgYmVyc2lmYXQgdGltZS1zZXJpZXMuIEtlbXVkaWFuLCB1bnR1ayBzZXRpYXAgc3RvY2sgKGBncm91cF9ieShTdG9ja19JRClgKSwgZGlsYWt1a2FuIHRpZ2EgcGVyaGl0dW5nYW46IA0KDQoxLiAqKkN1bXVsYXRpdmVfVm9sdW1lKio6IHRvdGFsIHZvbHVtZSBwZXJkYWdhbmdhbiB5YW5nIHRlcnVzIGRpanVtbGFoa2FuIGRhcmkgd2FrdHUga2Ugd2FrdHUuDQoyLiAqKkN1bXVsYXRpdmVfTWFya2V0Q2FwKio6IGFrdW11bGFzaSBrYXBpdGFsaXNhc2kgcGFzYXIgaGluZ2dhIHRhbmdnYWwgdGVydGVudHUuDQozLiAqKkN1bXVsYXRpdmVfQXZnUHJpY2UqKjogcmF0YS1yYXRhIGhhcmdhIHNhaGFtIHNlY2FyYSBrdW11bGF0aWYgKGhpbmdnYSB0aXRpayB3YWt0dSB0ZXJzZWJ1dCkgbWVuZ2d1bmFrYW4gYGN1bW1lYW4oKWAuDQoNCkZ1bmdzaSBgdW5ncm91cCgpYCBkaWd1bmFrYW4gYWdhciBoYXNpbG55YSB0aWRhayBsYWdpIGJlcnNpZmF0IGtlbG9tcG9rLiBIYXNpbCBha2hpciBtZW1iZXJpIGdhbWJhcmFuIHBlcmtlbWJhbmdhbiBoaXN0b3JpcyBraW5lcmphIHNldGlhcCBzYWhhbSBkYXJpIHdha3R1IGtlIHdha3R1LiAgDQoNCg0KIyBEaXN0cmlidXRpb24gVHJhbnNmb3JtYXRpb24NCg0KIyMgTG9nIFRyYW5zZm9ybQ0KVmFyaWFiZWwgeWFuZyBkaXBpbGloIGFkYWxhaCBLYXBhc2l0YXMgcGFzYXIgYWxhc2FubnlhIGFkYWxhaCwga2FyZW5hIGthcGFzaXRhcyBwYXNhciBtZW1wdW55YWkgYW5na2EgeWFuZyBzYW5nYXQgYmVzYXIgZGFuIGRpc3RyaWJ1c2lueWEgc2FuZ2F0IG1pcmluZyBrZSBrYW5hbiAocmlnaHQtc2tld2VkKS4NCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQoNCm1pbl9wb3NpdGl2ZSA8LSBtaW4oZmluYW5jaWFsX21hcmtldCRNYXJrZXRfQ2FwW2ZpbmFuY2lhbF9tYXJrZXQkTWFya2V0X0NhcCA+IDBdKQ0KDQpMb2cgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIFNhZmVfTWFya2V0X0NhcCA9IGlmZWxzZShNYXJrZXRfQ2FwIDw9IDAsIG1pbl9wb3NpdGl2ZSwgTWFya2V0X0NhcCksDQogICAgTG9nX01hcmtldF9DYXAgPSBsb2cxcChTYWZlX01hcmtldF9DYXApDQogICkNCmhlYWQoTG9nKQ0KYGBgDQoNCipJbnRlcnByZXRhc2k6Kg0KDQpUcmFuc2Zvcm1hc2kgbG9nIGRpZ3VuYWthbiB1bnR1azoNCg0KLSBNZW5zdGFiaWxrYW4gdmFyaWFucyB5YW5nIG1lbmluZ2thdCBzZWlyaW5nIGRlbmdhbiBuaWxhaSB2YXJpYWJlbC4NCg0KLSBNZW5ndXJhbmdpIHNrZXduZXNzIChrZW1pcmluZ2FuIGRpc3RyaWJ1c2kpIHRlcnV0YW1hIHBhZGEgZGF0YSB5YW5nIHRlcmRpc3RyaWJ1c2kgc2tld2VkIGtlIGthbmFuIHNlcGVydGkgS2FwaXRhbGlzYXNpLlBhc2FyLg0KDQotIERhbGFtIGtvZGUsIG5pbGFpIG5vbCBhdGF1IG5lZ2F0aWYgZGlnYW50aSBkZW5nYW4gbmlsYWkgcG9zaXRpZiB0ZXJrZWNpbCBhZ2FyIGBsb2coKWAgdGlkYWsgZXJyb3IuDQoNCi0gRnVuZ3NpIGBsb2cxcCh4KWAgYCh5YWl0dSBsb2coeCArIDEpKWAgZGlndW5ha2FuIHNlYmFnYWkgYmVudHVrIGFtYW4gdW50dWsgZGF0YSBub2wuDQoNCipIYXNpbDoqIA0KDQpEaXN0cmlidXNpIG1lbmphZGkgbGViaWggc2ltZXRyaXMgZGFuIHZhcmlhbnMgYW50YXIgbGV2ZWwgZGF0YSBtZW5qYWRpIGxlYmloIHNlaW1iYW5nLCBzZWhpbmdnYSBsZWJpaCBjb2NvayB1bnR1ayBhbmFsaXNpcyByZWdyZXNpLg0KDQotIEJlcnRhbWJhaCAyIHZhcmlhYmVsLCB5YWl0dTogU2FmZV9LYXBpdGFsaXNhc2lfUGFzYXIgZGFuIExvZ19LYXBpdGFsaXNhc2lfUGFzYXINCg0KIyMgQm94LUNveA0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGJlc3ROb3JtYWxpemUpDQpmaW5hbmNpYWxfbWFya2V0IDwtIHJlYWQuY3N2KCJmaW5hbmNpYWwgbWFya2V0LmNzdiIpDQoNCkJveF9Db3ggPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIFllb0pfVm9sdW1lX1RyYWRlZCA9IGJlc3ROb3JtYWxpemUoVm9sdW1lX1RyYWRlZCkkeC50LA0KICAgIFllb0pfTWFya2V0X0NhcCA9IGJlc3ROb3JtYWxpemUoTWFya2V0X0NhcCkkeC50DQogICkNCmhlYWQoQm94X0NveCkNCmBgYA0KDQoqSW50ZXJwcmV0YXNpOioNCg0KLSBNZW5nZ3VuYWthbiBmdW5nc2kgYmVzdE5vcm1hbGl6ZSgpIHlhbmcgb3RvbWF0aXMgbWVtaWxpaCBtZXRvZGUgdHJhbnNmb3JtYXNpIHRlcmJhaWsgYWdhciBkYXRhIG1lbmRla2F0aSBkaXN0cmlidXNpIG5vcm1hbC4gIA0KDQotIFRyYW5zZm9ybWFzaSBkaWxha3VrYW4gcGFkYSBWb2x1bWVfRGlwZXJkYWdhbmdrYW4gZGFuIEthcGl0YWxpc2FzaS5QYXNhciwgZGFuIGhhc2lsbnlhIGRpc2ltcGFuIHNlYmFnYWkga29sb20gYmFydS4gIA0KDQotIFByYWt0aWsgaW5pIGlkZWFsIHVudHVrIHByZXByb2Nlc3Npbmcgc2ViZWx1bSBtb2RlbGluZywga2FyZW5hIG1lbWJhbnR1IG1lbmd1cmFuZ2kgc2tld25lc3MgZGFuIG1lbnN0YWJpbGthbiB2YXJpYW5zIGRhdGEuDQoNCiMjIFN0YWJpbGlzYXNpIFZhcmlhbnMNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KERUKQ0KDQpTdGFiaWxpemUgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIHNxcnRfVm9sdW1lX1RyYWRlZCA9IHNxcnQocG1heChWb2x1bWVfVHJhZGVkLCAwKSksDQogICAgc3FydF9NYXJrZXRfQ2FwID0gc3FydChwbWF4KE1hcmtldF9DYXAsIDApKQ0KICApJT4lDQogIHVuZ3JvdXAoKQ0KDQoNCmRhdGF0YWJsZShTdGFiaWxpemUsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA1KSkNCmBgYA0KIyMjIEludGVycHJldGFzaToNCg0KVHJhbnNmb3JtYXNpIGFrYXIga3VhZHJhdCAoc3FydCkgc2VyaW5nIGRpZ3VuYWthbiBkYWxhbSBhbmFsaXNpcyBkYXRhIGtldWFuZ2FuIGF0YXUgc3RhdGlzdGlrIHVudHVrOg0KDQoqICpNZW5zdGFiaWxrYW4gdmFyaWFucyo6IERhdGEgc2VwZXJ0aSBWb2x1bWVfVHJhZGVkIGRhbiBNYXJrZXRfQ2FwIGJpc2Egc2FuZ2F0IGJlcnZhcmlhc2kgYW50YXIgcGVydXNhaGFhbiAoYWRhIHlhbmcga2VjaWwsIGFkYSB5YW5nIHNhbmdhdCBiZXNhcikuIFRyYW5zZm9ybWFzaSBha2FyIG1lbWJhbnR1IG1lbmd1cmFuZ2kgZWZlayBla3N0cmVtIGluaS4NCg0KKiAqTWVuZ3VyYW5naSBza2V3bmVzcyo6IEJhbnlhayB2YXJpYWJlbCBrZXVhbmdhbiBiZXJzaWZhdCBzYW5nYXQgbWlyaW5nIGtlIGthbmFuIChyaWdodC1za2V3ZWQpLiBBa2FyIGt1YWRyYXQgbWVtYnVhdCBkaXN0cmlidXNpbnlhIGxlYmloIHNpbWV0cmlzIChkZWthdCBub3JtYWwpLCB5YW5nIHBlbnRpbmcgdW50dWsgYW5hbGlzaXMgcmVncmVzaSBhdGF1IG1hY2hpbmUgbGVhcm5pbmcuDQoNCiogKk1lbmdoaW5kYXJpIG1hc2FsYWggbmlsYWkgbmVnYXRpZio6IHBtYXgoLi4uLCAwKSBtZW1hc3Rpa2FuIG5pbGFpIG5lZ2F0aWYgZGl1YmFoIG1lbmphZGkgbm9sIHNlYmVsdW0gZGloaXR1bmcgYWthcm55YSwga2FyZW5hIGFrYXIgZGFyaSBiaWxhbmdhbiBuZWdhdGlmIHRpZGFrIHZhbGlkIGRhbGFtwqBrb250ZWtzwqByZWFsLg0KDQojIyMgQ29udG9oIEludGVycHJldGFzaSBLYXN1czoNCg0KTWlzYWxueWEsIGR1YSBwZXJ1c2FoYWFuOg0KDQotIFBlcnVzYWhhYW4gQTogTWFya2V0X0NhcCA9IDEuMDAwLjAwMCAgDQotIFBlcnVzYWhhYW4gQjogTWFya2V0X0NhcCA9IDEwLjAwMA0KDQpUYW5wYSB0cmFuc2Zvcm1hc2ksIFBlcnVzYWhhYW4gQSB0ZXJsaWhhdCAqMTAww5cgbGViaWggYmVzYXIqLiBTZXRlbGFoIGFrYXIga3VhZHJhdDoNCg0KLSBzcXJ0KDEuMDAwLjAwMCkgPSAxMDAwICANCi0gc3FydCgxMC4wMDApID0gMTAwICANCg0KU2VrYXJhbmcgUGVydXNhaGFhbiBBIGhhbnlhIHRlcmxpaGF0ICoxMMOXIGxlYmloIGJlc2FyKiwgbWVtYnVhdCBhbmFsaXNpcyBsZWJpaMKgcHJvcG9yc2lvbmFsLg0KDQojIFNjYWxpbmcgJiBOb3JtYWxpemF0aW9uDQoNCiMjIFotU2NvcmUgU3RhbmRhcmRpemF0aW9uDQoNCmBgYHtyfQ0KIyBTdGFuZGFyZGlzYXNpIFotU2NvcmU6IG1lbmd1YmFoIGRhdGEgYWdhciBtZW1pbGlraSByYXRhLXJhdGEgMCBkYW4gc3RhbmRhciBkZXZpYXNpIDENCmZpbmFuY2lhbF9zY2FsZWQgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIFN0b2NrX1ByaWNlX1N0ZCA9IHNjYWxlKFN0b2NrX1ByaWNlKSwNCiAgICBWb2x1bWVfVHJhZGVkX1N0ZCA9IHNjYWxlKFZvbHVtZV9UcmFkZWQpLA0KICAgIE1hcmtldF9DYXBfU3RkID0gc2NhbGUoTWFya2V0X0NhcCksDQogICAgUEVfUmF0aW9fU3RkID0gc2NhbGUoUEVfUmF0aW8pLA0KICAgIERpdmlkZW5kX1lpZWxkX1N0ZCA9IHNjYWxlKERpdmlkZW5kX1lpZWxkKSwNCiAgICBSZXR1cm5fb25fRXF1aXR5X1N0ZCA9IHNjYWxlKFJldHVybl9vbl9FcXVpdHkpDQogICkNCmhlYWQoZmluYW5jaWFsX3NjYWxlZCkNCmBgYA0KDQojIyMgUGVuamVsYXNhbjoNCg0KMS4gZmluYW5jaWFsX21hcmtldCBhZGFsYWggZGF0YSBmcmFtZSB5YW5nIGJlcmlzaSBkYXRhIHBhc2FyIGtldWFuZ2FuLiBLb2xvbS1rb2xvbW55YSBtZW5jYWt1cCB2YXJpYWJlbCBzZXBlcnRpIGhhcmdhIHNhaGFtIChTdG9ja19QcmljZSksIHZvbHVtZSBwZXJkYWdhbmdhbiAoVm9sdW1lX1RyYWRlZCksIGthcGl0YWxpc2FzaSBwYXNhciAoTWFya2V0X0NhcCksIHJhc2lvIFBFIChQRV9SYXRpbyksIGRpdmlkZW4gKERpdmlkZW5kX1lpZWxkKSwgZGFuIFJPRSAoUmV0dXJuX29uX0VxdWl0eSkuDQoNCjIuIEZ1bmdzaSBtdXRhdGUoKSBkYXJpIHBha2V0IGRwbHlyIGRpZ3VuYWthbiB1bnR1ayBtZW5hbWJhaGthbiBrb2xvbS1rb2xvbSBiYXJ1IGhhc2lsIHRyYW5zZm9ybWFzaSBkYXJpIGtvbG9tIHlhbmcgYWRhLg0KDQozLiBaLVNjb3JlIFN0YW5kYXJkaXphdGlvbiBhZGFsYWggbWV0b2RlIHRyYW5zZm9ybWFzaSBkYXRhIHlhbmcgbWVuZ3ViYWggc2V0aWFwIG5pbGFpIG1lbmphZGkgdWt1cmFuIGRhbGFtIHNhdHVhbiBzdGFuZGFyIGRldmlhc2kgZGFyaSByYXRhLXJhdGEuIA0KDQo0LiBGdW5nc2kgc2NhbGUoKSBhZGFsYWggZnVuZ3NpIGJhd2FhbiBSIHVudHVrIG1lbGFrdWthbiBaLXNjb3JlIHN0YW5kYXJkaXphdGlvbiwgeWFpdHU6DQokJCBaID0gXGZyYWN7WCAtIFxtdSB9IHtcc2lnbWF9ICQkDQoNCi0gWDogbmlsYWkgYXNsaQ0KDQotICRcbXUkIDogcmF0YS1yYXRhIGRhdGENCg0KLSAkXHNpZ21hJDogc3RhbmRhciBkZXZpYXNpIGRhdGENCg0KSGFzaWxueWEgYWRhbGFoIGRhdGEgYmFydSB5YW5nOg0KDQotIE1lbWlsaWtpIHJhdGEtcmF0YSA9IDANCg0KLSBNZW1pbGlraSBzdGFuZGFyIGRldmlhc2kgPSAxDQoNCjUuIEtvbG9tIGJhcnUgZGVuZ2FuIGFraGlyYW4gX1N0ZCBkaWJ1YXQgdW50dWsgc2V0aWFwIHZhcmlhYmVsLCBzZXBlcnRpOg0KDQotIFN0b2NrX1ByaWNlX1N0ZA0KDQotIFZvbHVtZV9UcmFkZWRfU3RkDQoNCi0gTWFya2V0X0NhcF9TdGQNCg0KLSBQRV9SYXRpb19TdGQNCg0KLSBEaXZpZGVuZF9ZaWVsZF9TdGQNCg0KLSBSZXR1cm5fb25fRXF1aXR5X1N0ZA0KDQo2LiBoZWFkKGZpbmFuY2lhbF9zY2FsZWQpIGRpZ3VuYWthbiB1bnR1ayBtZW5hbXBpbGthbiA2IGJhcmlzIHBlcnRhbWEgZGFyaSBkYXRhIHlhbmcgdGVsYWggZGl0cmFuc2Zvcm1hc2kuDQoNCiMjIyBDb250b2ggUGVyaGl0dW5nYW4gTWFudWFsDQoNCk1pc2Fsa2FuIGRhdGEgU3RvY2tfUHJpY2U6IFsxMDAsIDEyMCwgMTUwLCAxMzAsIDExMF0NCg0KMS4gSGl0dW5nIE1lYW46DQoNCiQkIFxtdSA9IFxmcmFjezEwMCArIDEyMCArIDE1MCArIDEzMCArIDExMCB9IHs1fSA9IFxmcmFjezYxMH17NX0gPSAxMjIkJA0KDQoyLiBIaXR1bmcgU3RhbmRhciBEZXZpYXNpICjPgyk6DQoNCiQkIFxzaWdtYSA9IFxzcXJ0e1xmcmFjeygxMDAgLSAxMjIpXjIgKyAoMTIwIC0gMTIyKV4yICsgKDE1MCAtIDEyMileMiArICgxMzAgLSAxMjIpXjIgKyAoMTEwIC0gMTIyKV4yIH0gezV9fSAkJA0KDQokJCA9IFxzcXJ0e1xmcmFjezQ4NCArIDQgKyA3ODQgKyA2NCArIDE0NH17NX19ID0gXHNxcnR7XGZyYWN7MTQ4MH17NX19ID0gXHNxcnR7Mjk2fSA9IDE3LjIgJCQNCg0KMy4gWi1TY29yZSB1bnR1ayBuaWxhaSAxNTA6DQoNCiQkIFogPSBcZnJhY3sxNTAgLSAxMjIgfSB7MTcuMn0gPSBcZnJhY3syOH17MTcuMn3CoD3CoDEuNjPCoCQkDQoNCiMjIE1pbi1NYXggTm9ybWFsaXphdGlvbg0KDQpgYGB7cn0NCiMgTm9ybWFsaXNhc2kgTWluLU1heDogbWVuZ3ViYWggc2thbGEgZGF0YSBrZSBkYWxhbSByZW50YW5nIFswLCAxXQ0KZmluYW5jaWFsX25vcm1hbGl6ZWQgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIFN0b2NrX1ByaWNlX05vcm0gPSAoU3RvY2tfUHJpY2UgLSBtaW4oU3RvY2tfUHJpY2UpKSAvIChtYXgoU3RvY2tfUHJpY2UpIC0gbWluKFN0b2NrX1ByaWNlKSksDQogICAgVm9sdW1lX1RyYWRlZF9Ob3JtID0gKFZvbHVtZV9UcmFkZWQgLSBtaW4oVm9sdW1lX1RyYWRlZCkpIC8gKG1heChWb2x1bWVfVHJhZGVkKSAtIG1pbihWb2x1bWVfVHJhZGVkKSksDQogICAgTWFya2V0X0NhcF9Ob3JtID0gKE1hcmtldF9DYXAgLSBtaW4oTWFya2V0X0NhcCkpIC8gKG1heChNYXJrZXRfQ2FwIC0gbWluKE1hcmtldF9DYXApKSksDQogICAgUEVfUmF0aW9fTm9ybSA9IChQRV9SYXRpbyAtIG1pbihQRV9SYXRpbykpIC8gKG1heChQRV9SYXRpbykgLSBtaW4oUEVfUmF0aW8pKSwNCiAgICBEaXZpZGVuZF9ZaWVsZF9Ob3JtID0gKERpdmlkZW5kX1lpZWxkIC0gbWluKERpdmlkZW5kX1lpZWxkKSkgLyAobWF4KERpdmlkZW5kX1lpZWxkKSAtIG1pbihEaXZpZGVuZF9ZaWVsZCkpLA0KICAgIFJldHVybl9vbl9FcXVpdHlfTm9ybSA9IChSZXR1cm5fb25fRXF1aXR5IC0gbWluKFJldHVybl9vbl9FcXVpdHkpKSAvIChtYXgoUmV0dXJuX29uX0VxdWl0eSkgLSBtaW4oUmV0dXJuX29uX0VxdWl0eSkpDQogICkNCmhlYWQoZmluYW5jaWFsX25vcm1hbGl6ZWQpDQpgYGANCiMjIyBQZW5qZWxhc2FuDQoNCjEuIGZpbmFuY2lhbF9tYXJrZXQgYWRhbGFoIGRhdGEgZnJhbWUgeWFuZyBiZXJpc2kgZGF0YSBwYXNhciBrZXVhbmdhbi4gS29sb20ta29sb21ueWEgbWVuY2FrdXAgdmFyaWFiZWwgc2VwZXJ0aSBoYXJnYSBzYWhhbSAoU3RvY2tfUHJpY2UpLCB2b2x1bWUgcGVyZGFnYW5nYW4gKFZvbHVtZV9UcmFkZWQpLCBrYXBpdGFsaXNhc2kgcGFzYXIgKE1hcmtldF9DYXApLCByYXNpbyBQRSAoUEVfUmF0aW8pLCBkaXZpZGVuIChEaXZpZGVuZF9ZaWVsZCksIGRhbiBST0UgKFJldHVybl9vbl9FcXVpdHkpLg0KDQoyLiBGdW5nc2kgbXV0YXRlKCkgZGFyaSBwYWtldCBkcGx5ciBkaWd1bmFrYW4gdW50dWsgbWVuYW1iYWhrYW4ga29sb20ta29sb20gYmFydSBoYXNpbCB0cmFuc2Zvcm1hc2kgZGFyaSBrb2xvbSB5YW5nIGFkYS4NCg0KMy4gTm9ybWFsaXNhc2kgTWluLU1heCBhZGFsYWggbWV0b2RlIHBlbnNrYWxhYW4gZGF0YSBrZSBkYWxhbSByZW50YW5nIHRldGFwLCB5YWl0dSBbMCwgMV0sIGRlbmdhbiBtZW5nZ3VuYWthbiBydW11cyBiZXJpa3V0Og0KJCQgWF97bm9ybX0gPSBcZnJhY3tYIC0gWF97bWlufSB9IHtYX3ttYXh9IC0gWF97bWlufX0gJCQNCg0KLSBYOiBuaWxhaSBhc2xpDQoNCi0gJFhfe21pbn0kIDogbmlsYWkgbWluaW11bSBkYXJpIGZpdHVyDQoNCi0gJFhfe21pbn0kIDogbmlsYWkgbWFrc2ltdW0gZGFyaSBmaXR1cg0KIA0KSGFzaWxueWEgYWRhbGFoIGRhdGEgYmFydSB5YW5nOg0KDQotIE1lbWlsaWtpIG5pbGFpIHRlcmVuZGFoID0gMA0KDQotIE1lbWlsaWtpIG5pbGFpIHRlcnRpbmdnaSA9IDENCg0KLSBUZXRhcCBtZW1wZXJ0YWhhbmthbiBkaXN0cmlidXNpIGFzbGkgZGF0YW55YSAobmFtdW4gcmVudGFuZ255YSBkaXBlcnNlbXBpdCkNCg0KNC4gS29sb20gYmFydSBkZW5nYW4gYWtoaXJhbiBfTm9ybSBkaWJ1YXQgdW50dWsgc2V0aWFwIHZhcmlhYmVsLCBzZXBlcnRpOg0KDQotIFN0b2NrX1ByaWNlX05vcm0NCg0KLSBWb2x1bWVfVHJhZGVkX05vcm0NCg0KLSBNYXJrZXRfQ2FwX05vcm0NCg0KLSBQRV9SYXRpb19Ob3JtDQoNCi0gRGl2aWRlbmRfWWllbGRfTm9ybQ0KDQotIFJldHVybl9vbl9FcXVpdHlfTm9ybQ0KDQo1LiBGdW5nc2kgaGVhZChmaW5hbmNpYWxfbm9ybWFsaXplZCkgZGlndW5ha2FuIHVudHVrIG1lbmFtcGlsa2FuIDYgYmFyaXMgcGVydGFtYSBkYXJpIGRhdGEgeWFuZyB0ZWxhaCBkaW5vcm1hbGlzYXNpLg0KDQojIyMgQ29udG9oIFBlcmhpdHVuZ2FuIE1hbnVhbA0KDQpEYXRhIFN0b2NrX1ByaWNlOlsxMDAsIDEyMCwgMTUwLCAxMzAsIDExMF0NCg0KMS4gTWluaW11bSBkYW4gTWFrc2ltdW06DQoNCi0gTWluOiAxMDANCg0KLSBNYXg6IDE1MA0KDQoyLiBNaW4tTWF4IE5vcm1hbGl6YXRpb24gdW50dWsgbmlsYWkgMTMwOg0KJCQgWF97bm9ybX0gPSBcZnJhY3sxMzAgLSAxMDAgfSB7MTUwIC0gMTAwfSA9IFxmcmFjezMwfXs1MH3CoD3CoDAuNiQkDQoNCiMgQ2F0ZWdvcmljYWwgRW5jb2RpbmcNCg0KRGkgZGFsYW0gZGF0YSwga2FkYW5nIGtpdGEgbWVuZW11a2FuIGtvbG9tIHlhbmcgaXNpbnlhIGJ1a2FuIGFuZ2thLCB0YXBpICprYXRhLWthdGEqIGF0YXUgKmthdGVnb3JpKiwgbWlzYWxueWE6DQogDQogDQotIFNlY3RvciA9IOKAnEZpbmFuY2XigJ0sIOKAnFJldGFpbOKAnSwg4oCcVGVjaG5vbG9neeKAnQ0KIA0KLSBQZXJmb3JtYW5jZSA9IOKAnFBvc2l0aXZl4oCdLCDigJxOZWdhdGl2ZeKAnSwg4oCcU3RhYmxl4oCdDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0NCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIEJhY2EgZmlsZSBDU1YtbnlhDQpmaW5hbmNpYWxfbWFya2V0IDwtIHJlYWRfY3N2KCJmaW5hbmNpYWwgbWFya2V0LmNzdiIpDQoNCiMgVGFtcGlsa2FuIDYgZGF0YSB0ZXJhdGFzDQpoZWFkKGZpbmFuY2lhbF9tYXJrZXQpDQpgYGANCg0KTWFzYWxhaG55YSwgKiprb21wdXRlcioqIGhhbnlhIGJpc2EgbWVtYmFjYSBhbmdrYS4gTWFrYSwga2l0YSBwZXJsdSBtZW5ndWJhaCBrYXRhLWthdGEgaW5pIG1lbmphZGkgYW5na2EuIENhcmFueWEgZGlzZWJ1dCAqKkNhdGVnb3JpY2FsIEVuY29kaW5nKiouDQogDQogIA0KIyMgT25lIEhvdCBFbmNvZGluZw0KIA0KKkdhbXBhbmdueWE6KiBLaXRhIGJpa2luIGtvbG9tIGJhcnUgdW50dWsgc2V0aWFwIGthdGVnb3JpLCBsYWx1IGtpdGEga2FzaWggKmFuZ2thIDEgamlrYSBjb2NvaywgZGFuIDAqICprYWxhdSB0aWRhayouDQoNCipLZW5hcGEgTmdnYWsgUGFrYWkgQW5na2EgQmlhc2EgKDEsIDIsIDMpPyoNCiANCkthcmVuYSBrYWxhdSBraXRhIGthc2loIGFuZ2thIHNlcGVydGk6DQogDQogDQotIFBvc2l0aXZlID0gMQ0KIA0KLSBOZWdhdGl2ZSA9IDINCiANCi0gU3RhYmxlID0gMw0KIA0KIA0KKipLb21wdXRlciBiaXNhIHNhbGFoIHBhaGFtKiogZGFuIG1lbmdpcmEgYWRhICoqdXJ1dGFuIGF0YXUgcmFua2luZyoqLCBwYWRhaGFsICoqbmdnYWsgYWRhKiouDQogDQpQYWRhaGFsIGthdGVnb3JpIGl0dSBjdW1hICoqbGFiZWwqKiwgYnVrYW4gbmlsYWkuDQogDQpNYWthbnlhIGtpdGEgcGFrYWkgKipiaW5lciAoMCBkYW4gMSkqKiwgYmlhciBrb21wdXRlciBuZ2VydGkgYmFod2Egc2VtdWEga2F0ZWdvcmkgaXR1ICoqc2V0YXJhKiosIG5nZ2FrIGFkYSB5YW5nIGxlYmloIHRpbmdnaSBhdGF1IGxlYmloIHJlbmRhaC4NCg0KYmVyaWt1dCBrb2RlbnlhOg0KIA0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShmYXN0RHVtbWllcykNCg0KIyBVYmFoIGtvbG9tIFNlY3RvciAmIFBlcmZvcm1hbmNlIGphZGkgYmVudHVrIGFuZ2thIGJpbmVyICgwLzEpDQpvbmVfaG90IDwtIGR1bW15X2NvbHMoZmluYW5jaWFsX21hcmtldCwgDQogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0X2NvbHVtbnMgPSBjKCJTZWN0b3IiLCAiUGVyZm9ybWFuY2UiKSwgDQogICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX2ZpcnN0X2R1bW15ID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZV9zZWxlY3RlZF9jb2x1bW5zID0gVFJVRSkNCg0KIyBUYW1waWxrYW4gNiBkYXRhIGhhc2lsIG9uZSBob3QgZW5jb2RpbmcNCmhlYWQob25lX2hvdCkNCmBgYA0KICANCiMjIEZyZXF1ZW5jeSBFbmNvZGluZw0KIA0KKkdhbXBhbmdueWE6KiBLaXRhIGhpdHVuZyAqKmJlcmFwYSBrYWxpKiogc2V0aWFwIGthdGVnb3JpIG11bmN1bCwgbGFsdSAqKnNldGlhcCBkYXRhIGRpZ2FudGkgZGVuZ2FuIGFuZ2thIGZyZWt1ZW5zaW55YSoqLg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQojIEZ1bmdzaSB1bnR1ayBtZW5naGl0dW5nIGZyZWt1ZW5zaSAoYmVyYXBhIHNlcmluZyBtdW5jdWwpDQpmcmVxX2VuYyA8LSBmdW5jdGlvbihjb2wpIHsNCiAgdGFiIDwtIHRhYmxlKGNvbCkNCiAgcmV0dXJuKGFzLm51bWVyaWModGFiW2NvbF0pIC8gbGVuZ3RoKGNvbCkpDQp9DQoNCiMgVGFtYmFoa2FuIGtvbG9tIGZyZWt1ZW5zaSBrZSBkYXRhDQpkYXRhX2ZyZXEgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIFNlY3Rvcl9mcmVxID0gZnJlcV9lbmMoU2VjdG9yKSwNCiAgICBQZXJmb3JtYW5jZV9mcmVxID0gZnJlcV9lbmMoUGVyZm9ybWFuY2UpDQogICkNCg0KIyBUYW1waWxrYW4gNiBkYXRhIHRlcmF0YXMNCmhlYWQoZGF0YV9mcmVxKQ0KYGBgDQoqSGFzaWxueWE6KiAgDQpBa2FuIG11bmN1bCBkdWEga29sb20gYmFydToNCg0KLSBTZWN0b3JfZnJlcTogYmVyaXNpIGFuZ2thIGZyZWt1ZW5zaSBkYXJpIG5pbGFpIGRpIGtvbG9tIFNlY3Rvcg0KDQotIFBlcmZvcm1hbmNlX2ZyZXE6IGZyZWt1ZW5zaSBkYXJpIGtvbG9tIFBlcmZvcm1hbmNlDQoNClNldGlhcCBiYXJpcyBha2FuIGJlcmlzaSBhbmdrYSBwZWNhaGFuIChtaXNhbG55YSAwLjM2MCwgMC4zMzYpIHlhbmcgbWVudW5qdWtrYW4gKipzZWJlcmFwYSBzZXJpbmcgbmlsYWkgdGVyc2VidXQgbXVuY3VsIGRhbGFtIGtlc2VsdXJ1aGFuIGRhdGEqKi4NCg0KDQojIEZlYXR1cmUgRW5naW5lZXJpbmcNCg0KYGBge3J9DQojIEZlYXR1cmUgRW5naW5lZXJpbmcgcGFkYSBGaW5hbmNpYWxfbWFya2V0DQoNCkZlYXR1cmVfRW5nIDwtIGZpbmFuY2lhbF9tYXJrZXQgJT4lDQogIG11dGF0ZSgNCiAgICAjIDEuIE5ldyBGZWF0dXJlcyBmcm9tIFJhdyBEYXRhDQogICAgUHJpY2VfUGVyX1ZvbHVtZSA9IFN0b2NrX1ByaWNlIC8gKFZvbHVtZV9UcmFkZWQgKyAxZS01KSwgICMgSGluZGFyaSBwZW1iYWdpYW4gZGVuZ2FuIG5vbA0KICAgIA0KICAgICMgMi4gUHJvZHVjdCBvZiBGZWF0dXJlcywgQ3Jvc3NlZCBUZXJtcw0KICAgIFBFX3hfUk9FID0gUEVfUmF0aW8gKiBSZXR1cm5fb25fRXF1aXR5LA0KICAgIA0KICAgICMgMy4gUHJpY2UgcGVyIFVuaXQsIEVmZmljaWVuY3kNCiAgICBZaWVsZF90b19QRSA9IERpdmlkZW5kX1lpZWxkIC8gKFBFX1JhdGlvICsgMWUtNSksICAjIFlpZWxkIHBlciBQRQ0KDQogICAgIyA0LiBSYW5raW5nLCBQZXJjZW50aWxlDQogICAgTWFya2V0Q2FwX1JhbmsgPSByYW5rKC1NYXJrZXRfQ2FwKSwgICMgUmFuayBtYXJrZXQgY2FwIHRlcmJlc2FyIGtlIHRlcmtlY2lsDQogICAgUk9FX1F1YXJ0aWxlID0gbnRpbGUoUmV0dXJuX29uX0VxdWl0eSwgNCksICAjIEJhZ2kgUk9FIGtlIGRhbGFtIDQga3VhcnRpbA0KICAgIA0KICAgICMgNS4gRnJvbSBJRHM6IFByZWZpeCwgTGVuZ3RoLCBQYXR0ZXJuDQogICAgU3RvY2tfSURfUHJlZml4ID0gc3Vic3RyKFN0b2NrX0lELCAxLCAzKSwNCiAgICBTdG9ja19JRF9MZW5ndGggPSBuY2hhcihTdG9ja19JRCkNCiAgKSAlPiUNCiAgDQogICMgNi4gQXZnLCBTdW0sIENvdW50IGJ5IEdyb3VwDQogIGdyb3VwX2J5KFNlY3RvcikgJT4lDQogIG11dGF0ZSgNCiAgICBBdmdfUEVfU2VjdG9yID0gbWVhbihQRV9SYXRpbywgbmEucm0gPSBUUlVFKSwNCiAgICBBdmdfUk9FX1NlY3RvciA9IG1lYW4oUmV0dXJuX29uX0VxdWl0eSwgbmEucm0gPSBUUlVFKSwNCiAgICBUb3RhbF9Db21wYW5pZXNfU2VjdG9yID0gbigpDQogICkgJT4lDQogIHVuZ3JvdXAoKQ0KDQpoZWFkKEZlYXR1cmVfRW5nKQ0KYGBgDQoNCiMjIyBQZW5qZWxhc2FuDQoxLiBOZXcgRmVhdHVyZXMgZnJvbSBSYXcgRGF0YQ0KDQotIFByaWNlX1Blcl9Wb2x1bWU6IE1lbmd1a3VyIHNlYmVyYXBhIGJlc2FyIGhhcmdhIHNhaGFtIGRpYmFuZGluZyB2b2x1bWUgcGVyZGFnYW5nYW5ueWEuIERpZ3VuYWthbiB1bnR1ayBtZWxpaGF0IGFwYWthaCBzYWhhbSBkaXBlcmRhZ2FuZ2thbiB0ZXJsYWx1IGJhbnlhayBhdGF1IHRlcmxhbHUgc2VkaWtpdCB0ZXJoYWRhcCBuaWxhaW55YS4NCg0KICAtIERpdGFtYmFoIDFlLTUgdW50dWsgbWVuY2VnYWggcGVtYmFnaWFuIG5vbC4NCg0KMi4gUHJvZHVjdCBvZiBGZWF0dXJlcywgQ3Jvc3NlZCBUZXJtcw0KDQotIE1lbmdhbGlrYW4gUHJpY2UgdG8gRWFybmluZ3MgUmF0aW8gKFAvRSkgZGVuZ2FuIFJldHVybiBvbiBFcXVpdHkgKFJPRSkgbWVuZ2hhc2lsa2FuIGludGVyYWtzaSBhbnRhciBkdWEgbWV0cmlrIHBlbnRpbmc6DQoNCiAgLSBQRSBSYXRpbyBtZW51bmp1a2thbiB2YWx1YXNpIHNhaGFtLg0KDQogIC0gUk9FIG1lbnVuanVra2FuIGVmaXNpZW5zaSBwZXJ1c2FoYWFuIG1lbmdoYXNpbGthbiBsYWJhIGRhcmkgbW9kYWwgc2VuZGlyaS4NCg0KLSBJbnRlcmFrc2kgaW5pIGJpc2EgbWVtYmVyaSBzaW55YWwgYXBha2FoIHNhaGFtIHVuZGVydmFsdWVkIGF0YXUgb3ZlcnZhbHVlZCBkZW5nYW4gbWVtcGVyaGl0dW5na2FuIGVmaXNpZW5zaS4NCg0KMy4gUHJpY2UgcGVyIFVuaXQsIEVmZmljaWVuY3kNCg0KLSBZaWVsZF90b19QRTogRWZpc2llbnNpIGhhc2lsIGRpdmlkZW4gdGVyaGFkYXAgbmlsYWkgdmFsdWFzaSBwZXJ1c2FoYWFuLg0KDQogIC0gU2FoYW0gZGVuZ2FuIHJhc2lvIHRpbmdnaSBkaWFuZ2dhcCBtZW1iZXJpa2FuIHJldHVybiBkaXZpZGVuIHlhbmcgYmVzYXIgZGVuZ2FuIHZhbHVhc2kgcmVuZGFoIChtZW5hcmlrIHVudHVrIGludmVzdG9yIGRpdmlkZW4pLg0KDQogIC0gTGFnaS1sYWdpIGRpdGFtYmFoIDFlLTUgdW50dWsgbWVuZ2hpbmRhcmkgcGVtYmFnaWFuIG5vbC4NCg0KNC4gUmFua2luZywgUGVyY2VudGlsZQ0KDQotIE1hcmtldENhcF9SYW5rOiBNZW1iZXJpIHJhbmtpbmcgdGVyaGFkYXAgcGVydXNhaGFhbiBiZXJkYXNhcmthbiBrYXBpdGFsaXNhc2kgcGFzYXIgZGFyaSB0ZXJiZXNhciAocmFuayAxKSBrZSB0ZXJrZWNpbC4NCg0KLSBST0VfUXVhcnRpbGU6IE1lbmdlbG9tcG9ra2FuIFJPRSBrZSBkYWxhbSA0IGt1YXJ0aWwuIFR1anVhbm55YSB1bnR1ayBrbGFzaWZpa2FzaSBwZXJmb3JtYSBwZXJ1c2FoYWFuIGJlcmRhc2Fya2FuIFJPRToNCg0KICAtIEt1YXJ0aWwgMTogUk9FIHJlbmRhaA0KDQogIC0gS3VhcnRpbCA0OiBST0UgdGluZ2dpIChwZXJ1c2FoYWFuIHNhbmdhdCBtZW5ndW50dW5na2FuKQ0KDQo1LiBGcm9tIElEczogUHJlZml4LCBMZW5ndGgsIFBhdHRlcm4NCg0KLSBTdG9ja19JRF9QcmVmaXg6IE1lbmdhbWJpbCAzIGthcmFrdGVyIGF3YWwgZGFyaSBJRCBzYWhhbS4gSW5pIGJpc2EgbWVudW5qdWtrYW4ga29kZSBrYXRlZ29yaSwgamVuaXMgc2FoYW0sIGF0YXUgYXNhbCBidXJzYS4NCg0KLSBTdG9ja19JRF9MZW5ndGg6IFBhbmphbmcgZGFyaSBJRCBzYWhhbS4gQmlzYSBtZW1iYW50dSBkZXRla3NpIGZvcm1hdCBJRCB5YW5nIHRpZGFrIGxhemltLg0KDQo2LiBBdmcsIFN1bSwgQ291bnQgYnkgR3JvdXANCi0gRml0dXIgaW5pIG1lbmdoaXR1bmcgc3RhdGlzdGlrIGFncmVnYXQgYmVyZGFzYXJrYW4gU2VjdG9yOg0KDQogIC0gQXZnX1BFX1NlY3RvcjogUmF0YS1yYXRhIFBFIHVudHVrIHNlbHVydWggcGVydXNhaGFhbiBkaSBzZWt0b3IgdGVyc2VidXQuDQoNCiAgLSBBdmdfUk9FX1NlY3RvcjogUmF0YS1yYXRhIFJPRS4NCg0KICAtIFRvdGFsX0NvbXBhbmllc19TZWN0b3I6IEp1bWxhaCBwZXJ1c2FoYWFuIGRhbGFtIHNla3Rvci4NCg0KLSBCZXJndW5hIHVudHVrIG1lbWJhbmRpbmdrYW4ga2luZXJqYSBwZXJ1c2FoYWFuIGRlbmdhbiByYXRhLXJhdGEgc2VrdG9ybnlhIChyZWxhdGl2ZSB2YWx1YXRpb24pLg0KDQojIyBJbnRlcmFjdGlvbiBGZWF0dXJlcyANCg0KYGBge3J9DQpGaW5hbmNpYWxfaW50ZXJhY3Rpb24gPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIEltcGFjdF9TY29yZSA9IFN0b2NrX1ByaWNlICogUmV0dXJuX29uX0VxdWl0eQ0KICApDQpoZWFkKEZpbmFuY2lhbF9pbnRlcmFjdGlvbikNCmBgYA0KDQojIyMgUGVuamVsYXNhbg0KLSBJbXBhY3RfU2NvcmU6IE1lbmNlcm1pbmthbiAia2VrdWF0YW4gcGFzYXIiIHN1YXR1IHNhaGFtIGJlcmRhc2Fya2FuIGhhcmdhIGRhbiByZXR1cm4gZWt1aXRhc255YS4NCg0KICAtIFNlbWFraW4gdGluZ2dpIG5pbGFpIGluaSwgc2VtYWtpbiBzaWduaWZpa2FuIHBlbmdhcnVoIHNhaGFtIHRlcmhhZGFwIHBhc2FyIGF0YXUgaW52ZXN0b3IuDQoNCiMjIFJhdGlvIEZlYXR1cmVzDQoNCmBgYHtyfQ0KRmluYW5jaWFsX3JhdGlvIDwtIGZpbmFuY2lhbF9tYXJrZXQgJT4lDQogIG11dGF0ZSgNCiAgICBEaXZpZGVuZF90b19QcmljZSA9IERpdmlkZW5kX1lpZWxkIC8gKFN0b2NrX1ByaWNlICsgMWUtNSkNCiAgKQ0KaGVhZChGaW5hbmNpYWxfcmF0aW8pDQpgYGANCg0KIyMjIFBlbmplbGFzYW4NCi0gRGl2aWRlbmRfdG9fUHJpY2U6IE1lbmd1a3VyIGltYmFsIGhhc2lsIGRpdmlkZW4gcmVsYXRpZiB0ZXJoYWRhcCBoYXJnYSBzYWhhbS4NCg0KICAtIFNhaGFtIGRlbmdhbiByYXNpbyB0aW5nZ2kgbWVtYmVyaWthbiBkaXZpZGVuIGJlc2FyIG1lc2tpcHVuIGhhcmdhbnlhIHJlbmRhaC4NCg0KICAtIENvY29rIHVudHVrIGlkZW50aWZpa2FzaSBzYWhhbSAiZGl2aWRlbiBtdXJhaCIuDQoNCiMjIEdyb3VwIEFnZ3JlZ2F0aW9uDQpgYGB7cn0NClNlY3Rvcl9zdW1tYXJ5IDwtIGZpbmFuY2lhbF9tYXJrZXQgJT4lDQogIGdyb3VwX2J5KFNlY3RvcikgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBBdmdfTWFya2V0X0NhcCA9IG1lYW4oTWFya2V0X0NhcCksDQogICAgTWF4X1N0b2NrX1ByaWNlID0gbWF4KFN0b2NrX1ByaWNlKSwNCiAgICBDb21wYW55X0NvdW50ID0gbigpDQogICkNCg0KRmluYW5jaWFsX21lcmdlZCA8LSBsZWZ0X2pvaW4oZmluYW5jaWFsX21hcmtldCwgU2VjdG9yX3N1bW1hcnksIGJ5ID0gIlNlY3RvciIpDQpoZWFkKEZpbmFuY2lhbF9tZXJnZWQpDQpgYGANCg0KIyMjIFBlbmplbGFzYW4NCi0gU2VjdG9yX3N1bW1hcnkgbWVtYnVhdCByaW5na2FzYW4gc2VrdG9yOg0KDQogIC0gQXZnX01hcmtldF9DYXA6IEthcGl0YWxpc2FzaSBwYXNhciByYXRhLXJhdGEgZGkgc2VrdG9yLg0KDQogIC0gTWF4X1N0b2NrX1ByaWNlOiBIYXJnYSBzYWhhbSB0ZXJ0aW5nZ2kgZGkgc2VrdG9yLg0KDQogIC0gQ29tcGFueV9Db3VudDogSnVtbGFoIHBlcnVzYWhhYW4gcGVyIHNla3Rvci4NCg0KLSBMYWx1IGxlZnRfam9pbiBkaWxha3VrYW4gdW50dWsgbWVuZ2dhYnVuZ2thbiBpbmZvcm1hc2kgaW5pIGtlbWJhbGkga2UgZGF0YSB1dGFtYSwgbWVtdW5na2lua2FuIHBlcmJhbmRpbmdhbiBhbnRhciBwZXJ1c2FoYWFuIGRhbGFtIHNhdHUgc2VrdG9yLg0KDQojIyBSYW5rIFRyYW5zZm9ybWF0aW9uDQpgYGB7cn0NCkZpbmFuY2lhbF9yYW5rX3RyYW5zZm9ybSA8LSBmaW5hbmNpYWxfbWFya2V0ICU+JQ0KICBtdXRhdGUoDQogICAgUk9FX1JhbmsgPSByYW5rKC1SZXR1cm5fb25fRXF1aXR5KQ0KICApDQpoZWFkKEZpbmFuY2lhbF9yYW5rX3RyYW5zZm9ybSkNCmBgYA0KDQojIyMgUGVuamVsYXNhbg0KLSBST0VfUmFuazogTWVtYmVyaSBwZXJpbmdrYXQgdGVyaGFkYXAgcGVydXNhaGFhbiBiZXJkYXNhcmthbiBST0UgdGVydGluZ2dpIGtlIHRlcmVuZGFoLg0KDQogIC0gRGFwYXQgZGlndW5ha2FuIHVudHVrIG1lbmd1cnV0a2FuIGRhbiBtZW1pbGloIHNhaGFtIHBhbGluZyBtZW5ndW50dW5na2FuLg0KDQojIyBUZXh0IENsZWFuaW5nICYgRmVhdHVyZSBDcmVhdGlvbg0KDQpgYGB7cn0NCkZpbmFuY2lhbF90ZXh0X2ZlYXR1cmUgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIFN0b2NrX051bV9TdWZmaXggPSBhcy5udW1lcmljKHN0cl9leHRyYWN0KFN0b2NrX0lELCAiXFxkKyIpKQ0KICApDQpoZWFkKEZpbmFuY2lhbF90ZXh0X2ZlYXR1cmUpDQpgYGANCg0KIyMjIFBlbmplbGFzYW4NCg0KLSBTdG9ja19OdW1fU3VmZml4OiBNZW5nZWtzdHJhayBhbmdrYSBkYXJpIElEIHNhaGFtLiBJbmkgYmVyZ3VuYSBqaWthIElEIHNhaGFtIG1lbmdhbmR1bmcgcG9sYSB5YW5nIG1lbnlpcmF0a2FuIGthdGVnb3JpLCBiYXRjaCwgYXRhdSBncnVwLg0KDQogIC0gQ29udG9oOiBJRCAiQUJDMTIzIiDihpIgc3VmZml4ID0gMTIzDQoNCiMjIEN1bXVsYXRpdmUgRmVhdHVyZXMNCg0KYGBge3J9DQpGaW5hbmNpYWxfY3VtdWxhdGl2ZSA8LSBmaW5hbmNpYWxfbWFya2V0ICU+JQ0KICBhcnJhbmdlKFNlY3RvciwgRGF0ZSkgJT4lDQogIGdyb3VwX2J5KFNlY3RvcikgJT4lDQogIG11dGF0ZSgNCiAgICBDdW11bGF0aXZlX1ZvbHVtZSA9IGN1bXN1bShWb2x1bWVfVHJhZGVkKQ0KICApICU+JQ0KICB1bmdyb3VwKCkNCmhlYWQoRmluYW5jaWFsX2N1bXVsYXRpdmUpDQpgYGANCg0KIyMjIFBlbmplbGFzYW4NCi0gQ3VtdWxhdGl2ZV9Wb2x1bWU6IE1lbmp1bWxhaGthbiB0b3RhbCB2b2x1bWUgcGVyZGFnYW5nYW4gZGFyaSB3YWt0dSBrZSB3YWt0dSB1bnR1ayBzZXRpYXAgc2VrdG9yLg0KDQogIC0gQ29jb2sgdW50dWsgbWVsaWhhdCB0cmVuIGt1bXVsYXRpZiBha3Rpdml0YXMgcGFzYXIgZGkgc2VrdG9yIHRlcnRlbnR1Lg0KDQogIC0gQmlzYSBkaWd1bmFrYW4gZGFsYW0gYW5hbGlzaXMgbW9tZW50dW0gYXRhdSB0cmVuIGphbmdrYSBwYW5qYW5nLg0KDQojIyBLZXNpbXB1bGFuIFVtdW0NClNlbXVhIHByb3NlcyBmZWF0dXJlIGVuZ2luZWVyaW5nIGluaSBiZXJ0dWp1YW4gdW50dWs6DQoNCjEuICpNZW1wZXJrYXlhIGRhdGEqOiBNZW1idWF0IGZpdHVyIGJhcnUgeWFuZyBiaXNhIG1lbmFuZ2thcCBwb2xhLXBvbGEgdGVyc2VtYnVueWkgZGkgZGF0YSBtZW50YWguDQoNCjIuICpNZW1wZXJtdWRhaCBhbmFsaXNpcyBla3NwbG9yYXRpZio6IERlbmdhbiBhZ3JlZ2FzaSwgcmFua2luZywgZGFuIHRyYW5zZm9ybWFzaSwga2l0YSBiaXNhIGxlYmloIG11ZGFoIG1lbGloYXQgcGVydXNhaGFhbiB1bmdndWxhbiwgdHJlbiBzZWt0b3IsIGRhbiBwZXJiYW5kaW5nYW4gYW50YXIgcGVydXNhaGFhbi4NCg0KMy4gKk1lbmluZ2thdGthbiBwZXJmb3JtYSBtb2RlbCBtYWNoaW5lIGxlYXJuaW5nIGF0YXUgcHJlZGlrc2kqOiBGaXR1ciB5YW5nIGluZm9ybWF0aWYgZGFuIHJlbGV2YW4gZGFwYXQgbWVtYmFudHUgbW9kZWwgbWVuZ2VuYWxpIGh1YnVuZ2FuIGFudGFyYSB2YXJpYWJlbCBsZWJpaCBiYWlrLg0KDQo0LiAqTWVtYmVyaSBpbnNpZ2h0IGJpc25pcyBkYW4gaW52ZXN0YXNpKjogU2VwZXJ0aSBwZW1lcmluZ2thdGFuIHNhaGFtLCBrbGFzaWZpa2FzaSBzZWt0b3IsIGRhbiBpZGVudGlmaWthc2kgc2FoYW0gZGVuZ2FuIHBlcmZvcm1hwqBrZXVhbmdhbsKgYmFpay4NCg0KDQoNCg0KIyAqKkRldGVrc2kgT3V0bGllciBNZW5nZ3VuYWthbiBaLXNjb3JlIGRhbiBJUVIqKg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQoNCiMgLS0tIFotc2NvcmUgbWV0aG9kIGZvciBkZXRlY3Rpbmcgb3V0bGllcnMgLS0tDQpkYXRhX291dGxpZXJzIDwtIGZpbmFuY2lhbF9tYXJrZXQgJT4lDQogIG11dGF0ZSgNCiAgICB6X3Njb3Jlc19TUCA9IHNjYWxlKFN0b2NrX1ByaWNlKSwNCiAgICBPdXRsaWVyX0ZsYWcgPSBpZmVsc2UoYWJzKHpfc2NvcmVzX1NQKSA+IDMsICJPdXRsaWVyIiwgIk5vcm1hbCIpDQogICkNCg0KIyAtLS0gSVFSIG1ldGhvZCBmb3IgZGV0ZWN0aW5nIGFuZCByZW1vdmluZyBvdXRsaWVycyAtLS0NClExIDwtIHF1YW50aWxlKGZpbmFuY2lhbF9tYXJrZXQkVG90YWxfUHJpY2UsIDAuMjUpDQpRMyA8LSBxdWFudGlsZShmaW5hbmNpYWxfbWFya2V0JFRvdGFsX1ByaWNlLCAwLjc1KQ0KSVFSX3ZhbCA8LSBRMyAtIFExDQoNCmRhdGFfb3V0bGllcnNfaXFyIDwtIGZpbmFuY2lhbF9tYXJrZXQgJT4lDQogIGZpbHRlcigNCiAgICBTdG9ja19QcmljZSA+IChRMSAtIDEuNSAqIElRUl92YWwpICYgDQogICAgU3RvY2tfUHJpY2UgPCAoUTMgKyAxLjUgKiBJUVJfdmFsKQ0KICApDQoNCmhlYWQoZGF0YV9vdXRsaWVycykNCg0KYGBgDQoqKjEuIERldGVrc2kgT3V0bGllciBkZW5nYW4gTWV0b2RlIFotU2NvcmUqKg0KDQotIEFuZGEgbWVuZ2d1bmFrYW4gKipaLXNjb3JlIG1ldGhvZCoqIHVudHVrIG1lbmRldGVrc2kgb3V0bGllciBwYWRhIGtvbG9tICoqU3RvY2tfUHJpY2UqKi4NCi0gKipaLXNjb3JlKiogbWVuZ3VrdXIgc2ViZXJhcGEgamF1aCBzdWF0dSBuaWxhaSBkYXJpIHJhdGEtcmF0YSBkYWxhbSBzYXR1YW4gc3RhbmRhciBkZXZpYXNpLg0KICAgIC0gUnVtdXM6ICoqWiA9ICh4IC0gbWVhbikgLyBzZCoqDQotIEJhcmlzIGRhdGEgeWFuZyBtZW1pbGlraSBuaWxhaSBaLXNjb3JlIGxlYmloIGRhcmkgMyBhdGF1IGt1cmFuZyBkYXJpIC0zIGRpYW5nZ2FwICoqb3V0bGllci4qKg0KLSBLb2xvbSBiYXJ1ICoqT3V0bGllcl9GbGFnKiogZGl0YW1iYWhrYW4sIGJlcmlzaSBsYWJlbDoNCiAgICAtICoqT3V0bGllcioqIGppa2EgbmlsYWkgWi1zY29yZSBtZWxlYmloaSAzIGF0YXUga3VyYW5nIGRhcmkgLTMsDQogICAgLSAqKk5vcm1hbCoqIGppa2EgbWFzaWggZGFsYW0gYmF0YXMgbm9ybWFsLg0KICAgIA0KKioyLiBQZW1iZXJzaWhhbiBPdXRsaWVyIGRlbmdhbiBNZXRvZGUgSVFSKioNCg0KLSBNZXRvZGUga2VkdWEgbWVuZ2d1bmFrYW4gKipJbnRlcnF1YXJ0aWxlIFJhbmdlIChJUVIpKiogcGFkYSBrb2xvbSAqKlRvdGFsX1ByaWNlKiogdW50dWsgbWVuZGV0ZWtzaSBkYW4gbWVuZ2hhcHVzIG91dGxpZXIuDQotIFBlcmhpdHVuZ2FuOg0KICAgIC0gKipRMSAoa3VhcnRpbCAxKSoqID0gbmlsYWkgcGFkYSBwZXJzZW50aWwga2UtMjUsDQogICAgLSAqKlEzIChrdWFydGlsIDMpKiogPSBuaWxhaSBwYWRhIHBlcnNlbnRpbCBrZS03NSwNCiAgICAtICoqSVFSKiogPSBRMyAtIFExLg0KICAgIA0KLSBEYXRhIGRpYW5nZ2FwICoqb3V0bGllcioqIGppa2EgYmVyYWRhIGRpIGx1YXIgcmVudGFuZzoNClxbDQpcbGVmdFsgUV8xIC0gMS41IFx0aW1lcyBcdGV4dHtJUVJ9LFw7IFFfMyArIDEuNSBcdGltZXMgXHRleHR7SVFSfSBccmlnaHRdDQpcXQ0KDQotIEJhcmlzIHlhbmcgYmVyYWRhIGRpIGx1YXIgYmF0YXMgaW5pIGRpZmlsdGVyIGRhbiBkaWhhcHVzIGRhcmkgZGF0YSBkZW5nYW4gKipmaWx0ZXIoKSoqLg0KDQotIFotc2NvcmUgdW50dWsgbWVuZGV0ZWtzaSBvdXRsaWVyIHBhZGEgU3RvY2tfUHJpY2UsDQotIElRUiB1bnR1ayBtZW5naGFwdXMgb3V0bGllciBwYWRhIFRvdGFsX1ByaWNlLg0KLSBNZXRvZGUgaW5pIHBlbnRpbmcgdW50dWsgbWVtYmVyc2loa2FuIGRhdGEsIHNlaGluZ2dhIGFuYWxpc2lzIGF0YXUgbW9kZWwgeWFuZyBha2FuIGRpYmFuZ3VuIHRpZGFrIGJpYXMgb2xlaCBuaWxhaSBla3N0cmVtLg0KDQoNCg0KDQoNCiMgKipEaXNjcmV0aXphdGlvbiAoQmlubmluZykqKg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQoNCiMgQmFjYSBkYXRhDQpmaW5hbmNpYWxfbWFya2V0IDwtIGZpbmFuY2lhbF9tYXJrZXQNCg0KIyBCaW5uaW5nIChFcXVhbC1mcmVxdWVuY3kpIGRlbmdhbiBxdWFudGlsZQ0KYmlubmVkX2RhdGEgPC0gZmluYW5jaWFsX21hcmtldCAlPiUNCiAgbXV0YXRlKA0KICAgIFByaWNlX0xldmVsID0gY3V0KA0KICAgICAgU3RvY2tfUHJpY2UsDQogICAgICBicmVha3MgPSBxdWFudGlsZShTdG9ja19QcmljZSwgcHJvYnMgPSBjKDAsIDAuMzMsIDAuNjYsIDEpLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgbGFiZWxzID0gYygiTG93IiwgIk1lZGl1bSIsICJIaWdoIiksDQogICAgICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUNCiAgICApDQogICkNCg0KI1RhbXBpbGthbiBoYXNpbCBiaW5uaW5nDQpoZWFkKGJpbm5lZF9kYXRhKQ0KYGBgDQoNCioqMS4gVHVqdWFuIEJpbm5pbmcqKg0KDQotIFR1anVhbm55YSBhZGFsYWggdW50dWsgbWVuZ2Vsb21wb2trYW4gZGF0YSBudW1lcmlrIGRhcmkga29sb20gKipTdG9ja19QcmljZSoqIG1lbmphZGkgYmViZXJhcGEgKiprYXRlZ29yaSBkaXNrcml0KiogKGRhbGFtIGhhbCBpbmk6IExvdywgTWVkaXVtLCBIaWdoKS4NCi0gSW5pIGRpc2VidXQgKiplcXVhbC1mcmVxdWVuY3kgYmlubmluZyosIGthcmVuYSBzZXRpYXAga2Vsb21wb2sgYWthbiBtZW1pbGlraSBqdW1sYWggZGF0YSB5YW5nIGt1cmFuZyBsZWJpaCBzYW1hLg0KDQoqKjIuIFByb3NlcyB5YW5nIERpbGxha3VrYW4qKg0KDQotICoqcXVhbnRpbGUoKSoqIGRpZ3VuYWthbiB1bnR1ayBtZW5lbnR1a2FuIGJhdGFzLWJhdGFzIChicmVha3MpIGJlcmRhc2Fya2FuICoqcGVyc2VudGlsKio6DQogICAgLSAwJSAobWluaW11bSksDQogICAgLSAzMyUgKHNlcGVydGlnYSBkYXRhKSwNCiAgICAtIDY2JSAoZHVhIHBlcnRpZ2EgZGF0YSksDQogICAgLSAxMDAlIChtYWtzaW11bSkuDQogICAgDQotIEtlbXVkaWFuIGZ1bmdzaSBjdXQoKSBtZW1iYWdpIGtvbG9tIFN0b2NrX1ByaWNlIGtlIGRhbGFtIHRpZ2Ega2Vsb21wb2sgYmVyZGFzYXJrYW4gYmF0YXMtYmF0YXMgdGVyc2VidXQsIHlhaXR1Og0KICAgIC0gKipMb3cqKjogbmlsYWkgZGFyaSBrdWFudGlsIGtlLTAgaGluZ2dhIGtlLTMzLA0KICAgIC0gKipNZWRpdW0qKjoga3VhbnRpbCBrZS0zMyBoaW5nZ2Ega2UtNjYsDQogICAgLSAqKkhpZ2gqKjoga3VhbnRpbCBrZS02NiBoaW5nZ2Ega2UtMTAwLg0KDQotIEtvbG9tIGhhc2lsIGthdGVnb3Jpc2FzaSB0ZXJzZWJ1dCBkaW5hbWFrYW4gKipQcmljZV9MZXZlbCoqLg0KDQoNCiMgU2Vhc29uYWxpdHkNCg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkobHVicmlkYXRlKQ0KDQpTZWFzb25hbGl0eSA8LSBmaW5hbmNpYWxfbWFya2V0ICU+JQ0KICBtdXRhdGUoDQogICAgRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZIiksDQogICAgWWVhciA9IHllYXIoRGF0ZSksDQogICAgRGF5T2ZZZWFyID0geWRheShEYXRlKSwNCiAgICBEYXlzSW5ZZWFyID0gaWZfZWxzZShsZWFwX3llYXIoRGF0ZSksIDM2NiwgMzY1KSwNCiAgICBzaW5feWVhciA9IHNpbigyICogcGkgKiBEYXlPZlllYXIgLyBEYXlzSW5ZZWFyKSwNCiAgICBjb3NfeWVhciA9IGNvcygyICogcGkgKiBEYXlPZlllYXIgLyBEYXlzSW5ZZWFyKQ0KICApDQoNCmhlYWQoU2Vhc29uYWxpdHkpDQoNCmBgYA0KDQoqKktlc2ltcHVsYW4geWFuZyBEaWR1a3VuZyBvbGVoIERhdGEqKg0KDQoxLiAqKk11c2ltIE1hcmV04oCTSnVuaSAoc2luX3llYXIgdGluZ2dpKSoqOg0KDQotIDIwMjMtMDMtMTUgZGFuIDIwMjMtMDYtMDUgbWVudW5qdWtrYW4gKipzaW5feWVhcioqIHNhbmdhdCB0aW5nZ2kgZGFuIHBlcmZvcm1hIG1hc2luZy1tYXNpbmcgYWRhbGFoICpTdGFibGUgZGFuIFBvc2l0aXZlKi4NCg0KLSBJbmkgbWVuZHVrdW5nIHBvbGEgYmFod2EgKiprdWFydGFsIDIgKFEyKSoqIHNlcmluZyBtZW51bmp1a2thbiBwZXJmb3JtYSAqKmt1YXQgYXRhdSBzdGFiaWwqKi4NCg0KDQoyLiAqKkFraGlyIFRhaHVuIOKAkyBOb3ZlbWJlciAoc2luX3llYXIgbmVnYXRpZiB0aW5nZ2kpKio6DQoNCi0gMjAyMC0xMS0xNiAoKnNpbl95ZWFyID0gLTAuNjk3OSopIDogKipTdGFibGUqKg0KDQotIFRpZGFrIGVrc3RyZW0gbmVnYXRpZiwgdGFwaSBtZW5kZWthdGkuIE1lbnVuanVra2FuICoqa2luZXJqYSB5YW5nIHRpZGFrIHRlcmxhbHUga3VhdCoqLCBzZXN1YWkgZGVuZ2FuIGR1Z2FhbiBiYWh3YSBkaSBha2hpciB0YWh1biBiaXNhIHRlcmphZGkgdGVrYW5hbiBwYXNhciAobWlzYWxueWEsIGFrc2kgYW1iaWwgdW50dW5nL3Rha2UgcHJvZml0KS4NCg0KDQozLiAqKkF3YWwgVGFodW4g4oCTIEphbnVhcmkgKHNpbiBkYW4gY29zIG1lbmRla2F0aSBla3N0cmVtIHBvc2l0aWYpKio6DQoNCi0gMjAyMy0wMS0wMiA6IHNpbl95ZWFyIOKJiCAwLCBjb3NfeWVhciDiiYggMSA6ICoqU3RhYmxlKioNCg0KLSBTZXN1YWkgZGVuZ2FuIGludGVycHJldGFzaSBiYWh3YSBhd2FsIHRhaHVuIGNlbmRlcnVuZyBuZXRyYWwgYXRhdSBiZWx1bSBtZW51bmp1a2thbiB0cmVuIGplbGFzLg0KDQoNCjQuICoqUGVydGVuZ2FoYW4gVGFodW4g4oCTIEp1bGkgKHNpbl95ZWFyIG1lbmRla2F0aSBub2wsIGNvc195ZWFyIG5lZ2F0aWYgdGluZ2dpKSoqOg0KDQotIDIwMjEtMDctMTQgOiAqUG9zaXRpdmUqIG1lc2tpcHVuIHNpbl95ZWFyID0gLTAuMjEzNSA6IGJlcmFydGkgYWRhIHBvdGVuc2kga2luZXJqYSBiYWlrIGRpIHBlcnRlbmdhaGFuIHRhaHVuLCBtZXNraXB1biBzZWNhcmEgbXVzaW1hbiBiZXJhZGEgZGFsYW0gdHJhbnNpc2l0dXJ1bi4NCg0KNS4gKipBbm9tYWxpKio6DQoNCi0gMjAyMy0wMy0yMiA6ICoqc2luX3llYXIqKiBzYW5nYXQgdGluZ2dpICgwLjk4NDUpIHRhcGkgcGVyZm9ybWEgTmVnYXRpdmUuIEluaSBtZW51bmp1a2thbiBiYWh3YSBtZXNraXB1biBzaW55YWwgbXVzaW1hbiBtZW5kdWt1bmcgcGVydHVtYnVoYW4sIGZha3RvciBsYWluIChtdW5na2luIGVrc3Rlcm5hbCBhdGF1IHNla3RvciB0ZXJ0ZW50dSkgYmlzYSBtZW1lbmdhcnVoaSBuZWdhdGlmLg0KDQo=