Email             :
RPubs            : https://rpubs.com/Calvinriswandy/
Jurusan          : Statistika
Address         : ARA Center, Matana University Tower
                         Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.


1 Univariat(Satu Variabel)

Visualisasi data adalah teknik mengambil informasi dari data ke dalam konteks visual, seperti bagan, grafik, dan peta. Visualisasi data membuat data besar dan kecil lebih mudah dipahami oleh otak manusia, dan visualisasi juga membuatnya lebih andal untuk mendeteksi pola, tren, dan outlier dalam kelompok data.

Kategoris, seperti; jenis kelamin, ras, negara, kota, dll. Numerik, seperti; usia, berat badan, inflasi, suku bunga, dll.

2 Diagram Batang

Berikut ini adalah contoh yang menunjukkan frekuensi dari dataset Marriage, Saya mendapatkannya dari package mosaicData. Kita gunakan diagram batang untuk menampilkan distribusi peserta pernikahan berdasarkan Zodiak.

library(ggplot2)
setwd("C:/Users/5/Documents/Struktur Data")
library(ggplot2)                               
Marriage<- read.csv("https://raw.githubusercontent.com/Bakti-Siregar/dataset/master/Bookdown-Data-Science-for-Beginners/Marriage.csv")             # memauat data dari PC Anda`
ggplot(Marriage, aes(x = zodiacs)) +                 # memplot distribusi dari `Zodiacs` 
  geom_bar(fill = "cornflowerblue", 
           color= "azure4") +                        # Anda dapat mengganti warna 
  theme_minimal() +                                  # menggunakan tema minimal
  labs(x = "Zodiacs",                                # Anda dapat mengganti label dan judul plot
       y = "Frequency", 
       title = "Marriage Participants by Zodiacs")

Batang pada diagram batang dapat menggambarkan persentase dari jumlah.frequency terbanyak terdapat pada batang zodiak pisces, lalu untuk frequency yang paling dikit pada batang zodiak capricorn. Diagram batang biasanya diagram yang sering di pakai untuk menentukan frequency dari banyak sample. berikut bermacam-macam diagram batang:

library(ggplot2)                                     
ggplot(Marriage, 
   aes(x = zodiacs, 
       y = ..count.. / sum(..count..))) + 
  geom_bar(fill = rainbow(12), color= "azure4") +
  theme_minimal() +                                 
  labs(x = "Zodiacs", 
       y = "Percent", 
  title  = "Marriage Participants in Percent") +
  scale_y_continuous(labels = scales::percent)

library(dplyr)                                       # untuk manipulasi data
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)                                     # untuk visualisasi
plotdata <- Marriage %>%                             # memuat dataset
 count(zodiacs)                                      # jumlah peserta di setiap 'zodiacs'
# menyusun plot batang secara meningkat
ggplot(plotdata,                                     
       aes(x = reorder(zodiacs, n), 
           y = n)) + 
  geom_bar(stat = "identity",
           fill = rainbow(12), 
           color= "azure4") +
   theme_minimal() +                                  # menggunakan tema minimal
  labs(x = "Zodiacs", 
       y = "Frequency", 
  title  = "Sorting Categories")

library(dplyr)                                       
library(ggplot2)                                     
library(scales)                                       
plotdata <- Marriage %>%
  count(zodiacs) %>%
  mutate(pct = n / sum(n),
         pctlabel = paste0(round(pct*100), "%"))
ggplot(plotdata, 
       aes(x = reorder(zodiacs, -pct),
           y = pct)) + 
  geom_bar(stat = "identity", 
           fill = rainbow(12), 
          color = "azure4") +
  geom_text(aes(label = pctlabel), 
            vjust = -0.25) +
  theme_minimal() +                                
  scale_y_continuous(labels = percent) +
  labs(x = "Zodiacs", 
       y = "Percent", 
       title  = "Labeling Bars")

library(ggplot2)                                    
library(scales)                                      
ggplot(plotdata, 
       aes(x = reorder(zodiacs, -pct),
           y = pct)) + 
  geom_bar(stat = "identity", 
           fill = rainbow(12), 
           color = "azure4") +
  geom_text(aes(label = pctlabel), 
            vjust = -0.25) +
  scale_y_continuous(labels = percent) +
  theme_minimal() +                                
  labs(x = "Zodiacs", 
       y = "Percent", 
       title  = "Overlapping Labels")+
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

library(ggplot2)                                    
library(scales)                                      
ggplot(plotdata, 
       aes(x = reorder(zodiacs, -pct),
           y = pct)) + 
  geom_bar(stat = "identity", 
           fill = rainbow(12), 
           color = "azure4") +
  geom_text(aes(label = pctlabel), 
            hjust = -0.10) +
  scale_y_continuous(labels = percent) +
  theme_minimal() +                                  
  labs(x = "Zodiacs", 
       y = "Percent", 
       title  = "Overlapping Labels")+
  coord_flip()

3 Diagram Pai

Diagram pai bersifat kontroversial di statistik. Jika tujuan Anda adalah membandingkan frekuensi dari kategori, lebih baik Anda menggunakan diagram batang. Jika tujuan Anda untuk membandingkan setiap kategori secara keseluruhan, dan jumlah kategorinya kecil, maka diagram pai mungkin cocok untuk Anda. Biasanya diagram pai digunakan untuk menghitung frekuensi dengan sekala besar dan biasanya menggunakan persentase.

library(dplyr)                                      
library(ggplot2)                                     
library(scales)                                      
# Persiapan data
plotdata <- Marriage %>%
  count(race) %>%
  arrange(desc(race)) %>%
  mutate(prop = round(n*100/sum(n), 1),
         lab.ypos = cumsum(prop) - 0.5*prop)
# Membuat diagram pai
mycols <- c("#0073C2FF", "#EFC000FF", "#868686FF", "#CD534CFF")
ggplot(plotdata, aes(x = "", y = prop, fill = race)) +
  geom_bar(width = 1, stat = "identity", color = "white") +
  coord_polar("y", start = 0)+
  geom_text(aes(y = lab.ypos, label = prop), color = "white")+
  scale_fill_manual(values = mycols) +
  theme_void()+
  labs(title = "Marriage Participants by Race")

library(ggplot2)                                     # untuk visualisasi
library(scales)                                      # menentukan jeda atau label secara otomatis
# membuat diagram donat
ggplot(plotdata, aes(x = 2, y = prop, fill = race)) +
  geom_bar(stat = "identity", color = "white") +
  coord_polar(theta = "y", start = 0)+
  geom_text(aes(y = lab.ypos, label = prop), color = "white")+
  scale_fill_manual(values = mycols) +
  theme_void()+
  xlim(0.5, 2.5)+
  labs(title = "Marriage Participants by Race")

library(ggplot2)                        
library(scales)                                  
# tambahkan label persen
plotdata$percent <- paste0(plotdata$race, "\n",
                         round(plotdata$prop), "%")
# membuat diagram donat dalam persen
ggplot(plotdata, aes(x = 2, y = prop, fill = race)) +
  geom_bar(stat = "identity", color = "white") +
  coord_polar(theta = "y", start = 0)+
  geom_text(aes(y = lab.ypos, label = percent), color = "white")+
  scale_fill_manual(values = mycols) +
  theme_void()+
  xlim(0.5, 2.5)+
  labs(title = "Marriage Participants by Race")

3.1 Peta Pohon

Sebuah alternatif untuk diagram pai adalah peta phon. Tidak seperti diagram pai, peta pohon dapat menangani variabel kategorikal yang memiliki banyak tingkatan.

library(ggplot2)                                    
library(treemapify)                                 
## Warning: package 'treemapify' was built under R version 4.1.2
library(scales)                                     
plotdata <- Marriage %>%
  count(officialTitle)
ggplot(plotdata, 
       aes(fill = officialTitle, 
           area = n)) +
  geom_treemap() + 
  labs(title = "Marriage Participants by Officiate")

ggplot(plotdata, 
       aes(fill = officialTitle, 
           area = n, 
           label = officialTitle)) +
  geom_treemap() + 
  geom_treemap_text(colour = "white", 
                    place = "centre") +
  labs(title = "Marriage Participants by Officiate") +
  theme(legend.position = "none")

3.2 Variabel Kontinu

Distribusi variabel kuantitatif tunggal biasanya diplot dengan histogram, plot densitas kernel, atau plot titik.

3.3 Histogram

Menggunakan dataset Marriage, mari kita plot usia dari peserta pernikahan.

library(ggplot2)                                   
ggplot(Marriage, aes(x = age)) +
  geom_histogram(fill = "cornflowerblue", 
                 color = "white",bins = 20) + 
  theme_minimal() +                                  
  labs(title="Marriage Participants by age (Basic)",
       x = "Age")

Peserta tampaknya berusia 20-an tahun dengan kelompok lain berusia 40-an tahun, dan kelompok yang lebih kecil berusia 60-an dan 70-an tahun. Ini akan menjadi distribusi multimodal.

library(ggplot2)                                   
library(scales)                                     
ggplot(Marriage, 
       aes(x = age, 
           y= ..count.. / sum(..count..))) +
  geom_histogram(fill = "cornflowerblue", 
                 color = "white", 
                 binwidth = 5) +
  theme_minimal() +                               
  labs(title="Marriage Participants by age (Alternative Bins and bandwidths)", 
       y = "Percent",
       x = "Age") +
  scale_y_continuous(labels = percent)

pada diagram batang, sumbu y dapat mewakili jumlah atau persen dari total.

library(ggplot2)                               
library(scales)                                  
ggplot(Marriage, 
       aes(x = age, 
           y= ..count.. / sum(..count..))) +
  geom_histogram(fill = "cornflowerblue", 
                 color = "white", 
                 binwidth = 5) +
  theme_minimal() +                                 
  labs(title="Marriage Participants by age (Percent)", 
       y = "Percent",
       x = "Age") +
  scale_y_continuous(labels = percent)

3.4 Plot Densitas Kernel

Alternatif untuk histogram adalah plot densitas Kernel. Secara teknis, perkiraan densitas kernel adalah metode non-parametrik untuk memperkirakan fungsi densitas probabilitas dari variabel acak kontinu. (Apa??) Pada dasarnya, kita mencoba untuk menggambar histogram yang diperhalus, di mana area di bawah kurva sama dengan satu.

library(ggplot2)                                   
ggplot(Marriage, aes(x = age)) +
  geom_density(fill = "indianred3") +
  theme_minimal() +                                
  labs(title = "Marriage Participants by age")

Grafik menunjukkan distribusi dari nilai. Sebagai contoh, perbandingan kasus antara 20 dan 40 tahun akan diwakili oleh area di bawah kurva antara 20 dan 40 pada sumbu x. Seperti diagram sebelumnya, kita juga dapat menggunakan fill dan color untuk menentukan warna isian dan batasannya.

3.5 Parameter Penghalusan (Smoothing)

Tingkat kehalusan dikontrol oleh parameter bandwidth bw. Untuk menemukan nilai default untuk variabel tertentu, gunakan fungsi bw.nrd0. Nilai yang lebih besar akan menghasilkan penghalusan yang lebih banyak, sedangkan nilai yang lebih kecil akan menghasilkan penghalusan yang lebih sedikit.

library(ggplot2)                           
bw.nrd0(Marriage$age)                       
## [1] 5.181946
ggplot(Marriage, aes(x = age)) +
  geom_density(fill = "deepskyblue", 
               bw = 1) +
  theme_minimal() +                          
  labs(title = "Participants by age",
       subtitle = "bandwidth = 1")

Plot densitas kernel memungkinkan Anda dengan mudah melihat skor mana yang paling sering dan mana yang relatif jarang. Namun sulit untuk menjelaskan arti sumbu y kepada seorang non-ahli statistik.

4 Diagram Titik

Alternatif lain untuk histogram adalah diagram titik. Sekali lagi, variabel kuantitatif dibagi menjadi beberapa kelompok, tetapi bukan berbentuk batang, setiap pengamatan ditentukan oleh sebuah titik. Secara default, lebar dari sebuah titik sama dengan lebar bin, dan titik-titik bertumpuk, dengan setiap titik mewakili satu pengamatan. Ini bekerja dengan baik jika jumlah pengamatan kecil (katakanlah, kurang dari 150). Opsi fill dan color dapat digunakan untuk menentukan warna isian dan batasan masing-masing titik.

library(ggplot2)                                   
ggplot(Marriage, aes(x = age)) +
  geom_dotplot(fill = "gold", 
               color = "azure4",
               binwidth = 2) +
  theme_minimal() +                              
  labs(title = "Participants by age",
       y = "Proportion",
       x = "Age")

5 Data Bivariat

Grafik bivariat menunjukkan hubungan antara dua variabel. Jenis grafik akan tergantung pada tingkat pengukuran dari variabel (kategorikan atau kuantitatif).

5.1 Kategorikal vs. Kategorikal

5.1.1 Diagram Batang Bertumpuk

Mari kita plot hubungan antara kelas mobil dan jenis penggerak (roda depan, roda belakang, atau penggerak 4 roda) untuk mobil dalam dataset Fuel economy.

library(ggplot2)                                  
mpg$drv<-factor(mpg$drv, 
                levels = c("f", "r", "4"),
                labels = c("front-wheel", "rear-wheel", "4-wheel"))
# diagram batang bertumpuk
ggplot(mpg, 
       aes(x = class, 
           fill = drv)) + 
  geom_bar(position = "fill") +
  theme_minimal() +                               
  labs(y = "Proportion")

5.1.2 Diagram Batang yang Dikelompokkan

Tempat diagram batang yang dikelompokkan untuk variabel kategori kedua secara berdampingan.

Untuk membuat plot batang yang dikelompokkan, gunakan opsi position = “single”. Perhatikan bahwa opsi ini hanya tersedia di versi pengembangan terbaru ggplot2, tetapi akan segera tersedia secara umum.

library(ggplot2)                      
ggplot(mpg, aes(x = class, fill = drv)) +
  theme_minimal() +             
  geom_bar(position = position_dodge(preserve = "single"))

5.1.3 Diagram Batang Tersegmentasi

Plot batang yang tersegmentasi merupakan plot batang yang bertumpuk di mana setiap batang mewakili 100 persen. Anda dapat membuat diagram batang tersegmentasi menggunakan opsi position = “filled”. Jenis plot ini sangat berguna jika tujuannya adalah untuk membandingkan persentasi dari kategori dalam satu variabel di setiap tingkat variabel lain. Sebagai contoh, proporsi mobil dengan penggerak roda depan (front-wheel) meningkat saat Anda memindahkan dari mobil penumpang yang kecil, ke menengah, ke minivan.

library(dplyr)                                       
library(ggplot2)                                     
library(scales)                                      
# membuat ringkasan dataset (manipulasi data)
plotdata <- mpg %>%
  group_by(class, drv) %>%
  dplyr::summarize(n = n()) %>%
  mutate(pct = n/sum(n),
         lbl = scales::percent(pct))
## `summarise()` has grouped output by 'class'. You can override using the `.groups` argument.
# membuat diagram batang tersegmentasi
# menambahkan label untuk setiap segmen
ggplot(plotdata, 
       aes(x = factor(class),
           y = pct,
        fill = factor(drv))) +
  geom_bar(stat = "identity",
           position = "fill") +
  scale_y_continuous(breaks = seq(0, 1, .2), 
                     label = percent)+
  geom_text(aes(label = lbl),
            size = 3,
            position = position_stack(vjust = 0.5)) +
  scale_fill_brewer(palette = "Set2") +
  theme_minimal() +                                  # menggunakan tema minimal
  labs(y = "Percent",
       fill = "Drive Train",
       x = "Class",
       title = "Automobile Drive by Class") +
  theme_minimal()

5.1.4 Plot Mosaik

Diagram mosaik dapat menampilkan hubungan antara variabel kategorikal menggunakan persegi panjang yang luasnya mewakili proporsi kejadian untuk kombinasi level tertentu. Warna ubin juga dapat menunjukkan tingkat hubungan antar variabel.

Meskipun plot mosaik dapat dibuat dengan ggplot2 menggunakan package ggmosaic, saya merekomendasikan menggunakan package vcd sebagai gantinya. Meskipun tidak akan membuat grafik ggplot2, package tersebut memberikan pendekatan yang lebih komprehensif untuk memvisualisasikan data kategorikal.

Orang-orang terpesona dengan Titanic. Dalam bencana Titanic, peran apa yang dimainkan oleh sex dan class dalam survival? Kita dapat memvisualisasikan hubungan antara ketiga variabel kategorikal menggunakan kode berikut.

# membuat tabel
tbl <- xtabs(Freq ~ Survived + Class + Sex, Titanic)
ftable(tbl)
##                Sex Male Female
## Survived Class                
## No       1st        118      4
##          2nd        154     13
##          3rd        422    106
##          Crew       670      3
## Yes      1st         62    141
##          2nd         25     93
##          3rd         88     90
##          Crew       192     20
# membuat plot mosaik dari tabel
library(vcd)
## Warning: package 'vcd' was built under R version 4.1.2
## Loading required package: grid
mosaic(tbl, main = "Titanic data")

Ukuran ubin sebanding dengan persentase kasus dalam kombinasi tingkat tersebut. Jelas lebih banyak penumpang yang tewas daripada yang selamat. Mereka yang tewas adalah penumpang laki-laki kelas 3 dan kru laki-laki.

kita dapat memeriksa residual dari model dan memberi bayangan pada ubin agar sesuai. Pada grafik di bawah, biru gelap mewakilkan lebih banyak kasus dari yang diharapkan tidak terikat. Merah tua mewakili lebih sedikit kasus dari yang diharapkan jika berlaku tidak terikat.

mosaic(tbl, 
       shade = TRUE,
       legend = TRUE,
       labeling_args = list(set_varnames = c(Sex = "Gender",
                                             Survived = "Survived",
                                             Class = "Passenger Class")),
       set_labels = list(Survived = c("No", "Yes"),
                         Class = c("1st", "2nd", "3rd", "Crew"),
                         Sex = c("F", "M")),
       main = "Titanic data")

Kita dapat melihat jika class, gender, dan survival adalah tidak terikat, kita melihat lebih banyak kru laki-laki yang tewas, dan peremupan kelas 1, 2, dan 3 bertahan hidup daripada yang diharapkan. Sebaliknya, jauh lebih sedikit penumpang kelas 1 (laki-laki dan perempuan) yang meniggal daripada yang diperkirakan secara kebetulan. Dengan demikian asumsi tidak terikat ditolak.

5.1.5 Diskrit vs Kontinu

Hubungan antara dua variabel kuantitatif biasanya ditampilkan menggunakan plot sebaran dan grafik garis.

5.1.6 Plot Sebaran

Plot Sebaran dibuat untuk mempelajari hubungan antara 2 variabel. Sehingga sering disertai dengan perhitungan koefisien korelasi, yang biasanya mencoba untuk mengukur hubungan linear. Namun jenis hubungan lain dapat dideteksi menggunakan plot sebaran, dan tugas umum terdiri dari menyesuaikan model yang menjelaskan Y dalam fungsi X. Berikut adalah beberapa pola yang dapat Anda deteksi dengan melakukan plot sebaran.

library(ggplot2)                                   
library(hrbrthemes)                                
## Warning: package 'hrbrthemes' was built under R version 4.1.2
## NOTE: Either Arial Narrow or Roboto Condensed fonts are required to use these themes.
##       Please use hrbrthemes::import_roboto_condensed() to install Roboto Condensed and
##       if Arial Narrow is not on your system, please see https://bit.ly/arialnarrow
# Membuat data
d1 <- data.frame(x=seq(1,100), 
                 y=rnorm(100), 
                 name="No trend")
d2 <- d1 %>% 
mutate(y=x*10 + rnorm(100,sd=60)) %>%
mutate(name="Linear relationship")
d3 <- d1 %>%
mutate(y=x^2 + rnorm(100,sd=140)) %>%
mutate(name="Square")
d4 <- data.frame( x=seq(1,10,0.1), 
                  y=sin(seq(1,10,0.1)) + 
                    rnorm(91,sd=0.6)) %>% 
mutate(name="Sin")
don <- do.call(rbind, list(d1, d2, d3, d4))
# Plot
don %>%
  ggplot(aes(x=x, y=y)) +
    geom_point(color="#69b3a2", alpha=0.8) +
    theme_ipsum() +
    facet_wrap(~name, scale="free")
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family not
## found in Windows font database
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family not
## found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family not
## found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

Tampilan yang paling sederhana dari 2 variabel kuantitatif adalah plot sebaran, dengan setiap variabel diwakilkan oleh sumbu. Contohnya, menggunakan dataset Salaries, kita dapat memplot pengalaman (yrs.since.phd) vs. gaji akademik (salary) dari Profesor perguruan tinggi.

library(ggplot2)                                  
library(scales)                                 
data(Salaries, package="carData")
# plot sebaran yang ditingkatkan
ggplot(Salaries, 
       aes(x = yrs.since.phd, 
           y = salary)) +
  geom_point(color="cornflowerblue", 
             size = 2, 
             alpha=.8) +
  scale_y_continuous(label = scales::dollar, 
                     limits = c(50000, 250000)) +
  scale_x_continuous(breaks = seq(0, 60, 10), 
                     limits=c(0, 60)) +
  theme_minimal() +                                  
  labs(x = "Years Since PhD",
       y = "",
       title = "Experience vs. Salary",
       subtitle = "9-month salary for 2008-2009")

5.1.7 Plot Sebaran Menyesuaikan Garis

Seringkali berguna untuk meringkas hubungan yang ditampilkan dalam plot sebaran, dengan menggunakan sebuah garis yang menyesuaikan. Banyak jenis garis yang didukung, termasuk linear, polinomial, dan nonparametrik (loess). Secara default, garis-garis ini ditamplikan dengan batas kepercayaan 95%.

library(ggplot2)                                
ggplot(Salaries,
       aes(x = yrs.since.phd, 
           y = salary)) +
  geom_point(color= "cornflowerblue") +
  geom_smooth(method = "lm", color = "brown1")+
  theme_minimal() +                                
  labs(x = "Years Since PhD",
       y = "",
       title = "Experience vs. Salary",
       subtitle = "9-month salary for 2008-2009")
## `geom_smooth()` using formula 'y ~ x'

Jelas bahwa gaji akan meningkat sesuai dengan pengalaman. Namun, tampaknya ada penurunan diujung kanan - profesor dengan pengalaman signifikan, mendapatkan gaji lebih rendah. Garis lurus tidak dapat merangkap efek non-linear ini. Garis dengan lengkungan akan lebih pas di sini.

Biasanya digunakan garis kuadrat (satu lengkungan), atau kubik (dua lengkungan). Penggunaan polinomial orde tinggi (>3) jarang diperlukan. menerapkan kesesuaian kuadrat ke data set gaji menghasilkan hasil sebagai berikut.

library(ggplot2)                         
ggplot(Salaries, 
       aes(x = yrs.since.phd, 
           y = salary)) +
  geom_point(color= "cornflowerblue") +
  geom_smooth(method = "lm", 
              formula = y ~ poly(x, 2), 
              color = "yellow")+
  theme_minimal() +                    
  labs(x = "Years Since PhD",
       y = "",
       title = "Experience vs. Salary",
       subtitle = "9-month salary for 2008-2009")

garis kesesuaian nonparametrik yang diperhalus sering kali dapat memberikan gambaran yang baik tentang hubungan tersebut. Default di ggplot2 adalah garis loess yang berarti penghalusan plot sebaran yang tertimbang secara lokal.

library(ggplot2)                                   
ggplot(Salaries, 
       aes(x = yrs.since.phd, 
           y = salary)) +
  geom_point(color="cornflowerblue", 
             size = 2, 
             alpha = 1) +
  geom_smooth(size = 1,
              color = "green") +
  scale_y_continuous(label = scales::dollar, 
                     limits = c(50000, 250000)) +
  scale_x_continuous(breaks = seq(0, 60, 10), 
                     limits = c(0, 60)) +
  theme_minimal() +                             
  labs(x = "Years Since PhD",
       y = "",
       title = "Experience vs. Salary",
       subtitle = "9-month salary for 2008-2009") +
  theme_minimal()
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

5.2 Kategorikal vs. Kontinu

Ketika memplot hubungan antara variabel kategorikal dan variabel kuantitatif, tersedia banyak jenis grafik. ini termasuk diagram batang yang menggunakan ringkasan statistik, plot densitas kernel yang dikelompokkan, plot kotak berdampingan, plot biola berdampingan, plot mean/sem, plot garis punggungan, dan plot Cleveland.

5.2.1 Diagram Batang (Ringkasan Statistik)

Di bagian sebelumnya, diagram batang digunakan untuk menampilkan jumlah kejadian berdasarkan kategori untuk variabel tunggal atau untuk dua variabel. Anda juga dapat menggunakan diagram batang untuk menampilkan ringkasan statistik lainnya (seperti mean atau median) pada variabel kuantitatif untuk setiap tingkatan dari variabel kategorikal.

Sebagai contoh, grafik berikut ini menampilkan gaji rata-rata untuk sampel profesor universitas berdasarkan jabatan akademik mereka.

library(dplyr)          
library(ggplot2)           
library(scales)                               
data(Salaries, package="carData")
# menghitung gaji rata-rata untuk setiap jabatan
plotdata <- Salaries %>%
  group_by(rank) %>%
  dplyr::summarize(mean_salary = mean(salary))
# plot gaji rata-rata dengan cara yang lebih menarik
mycols <- c("#CD534CFF", "#EFC000FF", "#0073C2FF")
ggplot(plotdata, 
       aes(x = factor(rank,
                      labels = c("Assistant\nProfessor",
                                 "Associate\nProfessor",
                                 "Full\nProfessor")), 
                      y = mean_salary)) +
  geom_bar(stat = "identity", 
           fill = mycols) +
  geom_text(aes(label = dollar(mean_salary)), 
            vjust = -0.25) +
  scale_y_continuous(breaks = seq(0, 130000, 20000), 
                     label = dollar) +
  theme_minimal() +                                  # menggunakan tema minimal
  labs(title = "Mean Salary by Rank", 
       subtitle = "9-month academic salary for 2008-2009",
       x = "",
       y = "")

Plot Densitas Kernel yang Dikelompokkan Seseorang dapat membandingkan kelompok pada variabel numerik dengan melapiskan plot densitas kernel dalam satu grafik. Mari kita plot distribusi gaji berdasarkan jabatan menggunakan plot densitas kernel.

ggplot(Salaries, 
       aes(x = salary, 
           fill = rank)) +
  geom_density(alpha = 0.4) +
  theme_minimal() +
  labs(title = "Salary distribution by rank")

Opsi alpha membuat plot densitas menjadi sebagian transparan sehingga kita dapat melihat apa yang terjadi di bagian yang tumpang tindih. Nilai alpha berkisar dari 0 (transparan) hingga 1 (buram). Grafik tersebut menjelaskan bahwa, secara umum, gaji akan meningkat sesuai jabatan. Namun, kisaran gaji untuk full profesor sangat luas.

5.2.2 Boxplot

Plot Kotak (Boxplot) menampilkan persentil ke-25, median, dan persentil ke-75 dari distribusi. Plot Kotak berdampingan sangat berguna untuk membandingkan kelompok pada variabel numerik. Mari kita plot distribusi gaji berdasarkan jabatan menggunakan plot kotak. Plot kotak bertakik memberikan metode perkiraan untuk visualisasi apakah kelompok berbeda. Meskipun bukan sebuah tes yang formal, jika takik dari kedua plot kotak tidak rumpang tindih, maka ada bukti kuat bahwa median dari kedua kelompok berbeda.

mycols <- c("#CD534CFF", "#EFC000FF", "#0073C2FF")
ggplot(Salaries, aes(x = rank, 
                     y = salary)) +
  geom_boxplot(notch = TRUE, 
               fill = mycols, 
               alpha = .7) +
  theme_minimal() +
  labs(title = "Salary Distribution by rank")

Dalam contoh di atas, ketiga kelompok itu tampak berbeda. Salah satu keuntungan dari plot kotak adalah lebarnya biasanya tidak berarti. Ini memungkinkan Anda untuk membandingkan distribusi dari banyak kelompok dalam satu grafik.

5.2.3 Plot Biola

Plot Biola mirip dengan plot densitas kernel tetapi dicerminkan dan diputar 900900. Mari kita plot distribusi gaji berdasarkan jabatan menggunakan plot biola.

ggplot(Salaries, 
       aes(x = rank, 
           y = salary)) +
  geom_violin(fill = "azure1") +
  geom_boxplot(width = .2, 
               fill = mycols,
               outlier.color = "red",
               outlier.size = 2) + 
  theme_minimal() +
  labs(title = "Salary distribution by rank")

5.2.4 Plot Garis Punggung

Plot garis punggung (juga disebut plot kegembiraan) menampilkan distribusi variabel kuantitatif untuk beberapa kelompok. Mereka mirip dengan plot densitas kernel dari segi (faceting) vertikal, tetapi memakan lebih sedikit ruang. Plot garis punggung dibuat dengan package ggridges.

Menggunakan data set Fuel economy, mari kita plot mil perjalanan kota per galon menurut kelas mobil.

library(dplyr)            
library(ggplot2)        
library(ggridges)                             
ggplot(mpg, 
       aes(x = cty, 
           y = class, 
           fill = class)) +
  geom_density_ridges(alpha = 0.7) + 
  theme_ridges() +
  labs("Highway mileage by auto class") +
  theme(legend.position = "none")
## Picking joint bandwidth of 0.929

Perhatikan kemungkinan tumpang tindih distribusi adalah diputuskan lebih kepada grafik mobil kompak. Anda dapat menambahkan transparansi jika tumpang tindihnya parah, dengan menggunakan geom_density_ridges(alpha = n), dimana n berkisar dari 0 (transparan) hingga 1 (buram). Lihat package vignette untuk lebih jelasnya.

5.2.5 Plot

Metode populer untuk membandingkan kelompok pada variabel numerik adalah plot rata-rata dengan batang kesalahan. Batang kesalahan dapat mewakilkan deviasi standar, kesalahan standar dari rata-rata, atau interval kepercayaan. Pada bagian ini, kita akan plot rata-rata dan kesalahan standar. Kita dapat menggunakan teknik yang sama untuk membandingkan gaji terhadap jabatan dan jenis kelamin.

library(dplyr)                                      
library(ggplot2)                                    
library(ggridges)                                   
# menghitung rata-rata, deviasi standar,
# kesalahan standar, dan 95% interval kepercayaan 
# berdasarkan jabatan
plotdata <- Salaries %>%
  group_by(rank, sex) %>%
  dplyr::summarize(n = n(),
            mean = mean(salary),
            sd = sd(salary),
            se = sd/sqrt(n),
            ci = qt(0.975, df = n - 1) * sd / sqrt(n))
## `summarise()` has grouped output by 'rank'. You can override using the `.groups` argument.
# meningkatkan plot rata-rata kesalahan atau standar kesalahan
pd <- position_dodge(0.2)
ggplot(plotdata, 
       aes(x = factor(rank, 
                      labels = c("Assistant\nProfessor",
                                 "Associate\nProfessor",
                                 "Full\nProfessor")), 
           y = mean, 
           group=sex, 
           color=sex)) +
  geom_point(position=pd, 
             size = 3) +
  geom_line(position = pd, 
            size = 1) +
  geom_errorbar(aes(ymin = mean - se, 
                    ymax = mean + se), 
                width = .1, 
                position = pd, 
                size = 1) +
  scale_y_continuous(label = scales::dollar) +
  scale_color_brewer(palette="Set1") +
  theme_minimal() +
  labs(title = "Mean salary by rank and sex",
       subtitle = "(mean +/- standard error)",
       x = "", 
       y = "",
       color = "Gender")

5.2.6 Plot Strip

Hubungan antara variabel pengelompokan dan variabel numerik dapat ditampilkan dengan plot sebaran. Contoh, plot distribusi gaji berdasarkan jabatan menggunakan plot strip. Plot sebar satu dimensi ini disebut sebagai plot strip. Sayangnya, pencetakan titik yang berlebihan membuat interpretasinya menjadi sulit.

library(ggplot2)          
library(scales)            
ggplot(Salaries, 
       aes(y = factor(rank,
                      labels = c("Assistant\nProfessor",
                                 "Associate\nProfessor",
                                 "Full\nProfessor")), 
           x = salary, 
           color = rank)) +
  geom_jitter(alpha = 0.7,
              size = 1.5) + 
  scale_x_continuous(label = dollar) +
  labs(title = "Academic Salary by Rank", 
       subtitle = "9-month salary for 2008-2009",
       x = "",
       y = "") +
  theme_minimal() +
  theme(legend.position = "none")

Opsi legend.position = “none” digunakan untuk menyembunyikan legend (yang tidak diperlukan di sini). Plot jitter bekerja dengan baik ketika jumlah dari titik-titik tidak terlalu besar.

5.2.7 Menggabungkan Jitter dan Plot Kotak

Mungkin lebih mudah untuk memvisualisasikan distribusi jika kita menambahkan plot kotak ke plot jitter. Beberapa pilihan ditambahkan untuk membuat plot ini.

library(ggplot2)         
library(scales)             
ggplot(Salaries, 
       aes(x = factor(rank,
                      labels = c("Assistant\nProfessor",
                                 "Associate\nProfessor",
                                 "Full\nProfessor")), 
           y = salary, 
           color = rank)) +
  geom_boxplot(size=1,
               outlier.shape = 1,
               outlier.color = "black",
               outlier.size  = 3) +
  geom_jitter(alpha = 0.5, 
              width=.2) + 
  scale_y_continuous(label = dollar) +
  labs(title = "Academic Salary by Rank", 
       subtitle = "9-month salary for 2008-2009",
       x = "",
       y = "") +
  theme_minimal() +
  theme(legend.position = "none") +
  coord_flip()

Sebelum melanjutkan, ada baiknya untuk memerhatikan fungsi geom_boxjitter yang disediakan dalam package ggpol. Ini membuat plot kotak hibrida - setengah plot kotak, setengan plot sebaran.

library(ggplot2)                                  
library(scales)                                   
library(ggpol)                                    
## Warning: package 'ggpol' was built under R version 4.1.2
ggplot(Salaries, 
       aes(x = factor(rank,
                      labels = c("Assistant\nProfessor",
                                 "Associate\nProfessor",
                                 "Full\nProfessor")), 
           y = salary, 
           fill=rank)) +
  geom_boxjitter(color="black",
                 jitter.color = "darkgrey",
                 errorbar.draw = TRUE) +
  scale_y_continuous(label = dollar) +
  labs(title = "Academic Salary by Rank", 
       subtitle = "9-month salary for 2008-2009",
       x = "",
       y = "") +
  theme_minimal() +
  theme(legend.position = "none")

5.2.8 Plot Kawanan Lebah

Plot kawanan lebah (juga disebut plot sebaran biola) mirip dengan plot sebaran jitter, di mana plot tersebut menampilkan distribusi dari variabel kuantitatif dengan memplot titik-titik dengan cara mengurangi tumpang tindih. Selain itu, mereka juga membantu menampilkan densitas dari data di setiap titik (dengan cara yang mirip dengan plot biola). Melanjutkan contoh sebelumnya.

library(ggplot2)                 
library(scales)                 
library(ggbeeswarm)              
## Warning: package 'ggbeeswarm' was built under R version 4.1.2
ggplot(Salaries, 
       aes(x = factor(rank,
                      labels = c("Assistant\nProfessor",
                                 "Associate\nProfessor",
                                 "Full\nProfessor")), 
           y = salary, 
           color = rank)) +
  geom_quasirandom(alpha = 0.7,
                   size = 1.5) + 
  scale_y_continuous(label = dollar) +
  labs(title = "Academic Salary by Rank", 
       subtitle = "9-month salary for 2008-2009",
       x = "",
       y = "") +
  theme_minimal() +
  theme(legend.position = "none")

Plot dibuat menggunakan fungsi geom_quasirandom. Plot ini dapat lebih mudah dibaca daripada plot strip jitter sederhana. Untuk mempelajari lebih lanjut mengenai plot ini, lihat Plot bergaya kawanan lebah dengan ggplot2.

5.2.9 Diagram Titik Cleveland

Plot Cleveland berguna ketika Anda ingin membandingkan statistik numerik untuk sejumlah besar kelompok. Misalnya, Anda ingin membandingkan harapan hidup tahun 2007 untuk negara Asia menggunakan data set gapminder.

library(dplyr)   
library(ggplot2)   
library(scales)          
library(ggbeeswarm)         
library(gapminder)           
## Warning: package 'gapminder' was built under R version 4.1.2
data(gapminder, package="gapminder")                 # memuat dataset `gapminder` 
# subset negara-negara Asian tahun 2007
library(dplyr)
plotdata <- gapminder %>%
  filter(continent == "Asia" & 
         year == 2007)
# Plot Cleveland yang menarik
ggplot(plotdata, 
       aes(x=lifeExp, 
           y=reorder(country, lifeExp))) +
  geom_point(color="blue", 
             size = 2) +
  geom_segment(aes(x = 40, 
               xend = lifeExp, 
               y = reorder(country, lifeExp), 
               yend = reorder(country, lifeExp)),
               color = "azure3") +
  labs (x = "Life Expectancy (years)",
        y = "",
        title = "Life Expectancy by Country",
        subtitle = "GapMinder data for Asia - 2007") +
  theme_minimal() + 
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())

Jepang jelas memiliki angka harapan hidup yang paling tinggi, sedangkan Afghanistan sejauh ini yang paling rendah. Plot terakhir ini disebut juga dengan grafik lolipop.

6 Data Multivariat

Grafik Multivariat menampilkan hubungan antara tiga variabel atau lebih. Ada dua metode umum untuk menampung variabel: pengelompokan dan faceting.

##Pengelompokan

Dalam pengelompokan, nilai dari dua variabel pertama dipetakan ke sumbu x dan y. Kemudian variabel tambahan dipetakan ke karakteristik visual lainnya seperti warna, bentuk, ukuran, jenis garis, dan transparansi. Pengelompokan memungkinkan Anda untuk memplot data untuk beberapa grup dalam satu grafik. Dengan menggunakan data set Salaries, mari kita tampilkan hubungan antara yrs.since.phd dan salary.

library(carData)                                
library(ggplot2)                                 
data(Salaries, package="carData")
ggplot(Salaries, aes(x = yrs.since.phd, 
                     y = salary, 
                     color=rank)) +
  geom_point() +
  theme_minimal() +
  labs(title = "Academic salary by rank and years since degree")

Selanjutnya, tambahkan jenis kelamin profesor, menggunakan bentuk titik untuk menunjukkan jenis kelamin. Kita akan meningkatkan ukuran titik dan menambahkan transparansi untuk memperjelas titik individual.

library(carData)                       
library(ggplot2)                         
ggplot(Salaries, 
       aes(x = yrs.since.phd, 
           y = salary, 
           color = rank, 
           shape = sex)) +
  geom_point(size = 3, alpha = .6) +
  theme_minimal() +
  labs(title = "Academic salary by rank, sex, and years since degree")

Berikut adalah contoh yang lebih jelas. Kita akan membuat grafik hubungan antar tahun sejak Ph.D. dan gaji menggunakan ukuran dari titik untuk menunjukkan masa kerja. Ini disebut plot gelembung.

library(carData)  
library(ggplot2)  
ggplot(Salaries, 
       aes(x = yrs.since.phd, 
           y = salary, 
           color = rank, 
           size = yrs.service)) +
  geom_point(alpha = .8) +
  theme_minimal() +
  labs(title = "Academic salary by rank, years of service, and years since degree")

Jelas sekali ada hubungan positif yang kuat antara tahun-tahun sejak Ph.D. dan tahun layanan. Asisten Profesor ada dalam jangkauan 0-11 tahun sejak Ph.D. dan 0-10 tahun layanan. Kita tidak menemukan batasan waktu yang sama antara Associate dan Full Professors.

library(carData)                   
library(ggplot2)                   
ggplot(Salaries, 
       aes(x = yrs.since.phd, 
           y = salary, 
           color = sex)) +
  geom_point(alpha = .4, 
             size = 3) +
  geom_smooth(se=FALSE, 
              method = "lm", 
              formula = y~poly(x,2), 
              size = 1.5) +
  labs(x = "Years Since Ph.D.",
       title = "Academic Salary by Sex and Years Experience",
       subtitle = "9-month salary for 2008-2009",
       y = "",
       color = "Sex") +
  scale_y_continuous(label = scales::dollar) +
  scale_color_brewer(palette = "Set1") +
  theme_minimal()

6.1 Pembagian Faset (Faceting)

Pengelompokan memungkinkan Anda untuk memplot beberapa variabel dalam satu grafik, menggunakan karakteristik visual seperti, warna, bentuk, dan ukuran. Dalam pembagian faset, sebuah grafik terdiri dari beberapa plot-plot terpisah atau kelipatan kecil, satu untuk setiap tingkatan dari variabel ketiga, atau kombinasi variabel. Ini akan lebih mudah dipahami dengan sebuah contoh.

library(carData)          
library(ggplot2)         
ggplot(Salaries, aes(x = salary)) +
  geom_histogram(fill = "cornflowerblue",
                 color = "white") +
  facet_wrap(~rank, ncol = 1) +
  theme_minimal() +
  labs(title = "Salary histograms by rank")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Fungsi facet_wrap membuat grafik terpisah untuk setiap tingkat jabaran. Opsi ncol mengatur jumlah kolom. Dalam contoh berikutnya akan menggunakan dua variabel untuk mendefinisikan faset. Di sini, fungsi menetapkan jenis kelamin ke baris dan jabatan ke kolom, membuat matriks enam plot dalam satu grafik.

library(carData)      
library(ggplot2)           
ggplot(Salaries, aes(x = salary / 1000)) +
  geom_histogram(color = "white",
                 fill = "cornflowerblue") +
  facet_grid(sex ~ rank) +
  theme_minimal() +
  labs(title = "Salary histograms by sex and rank",
       x = "Salary ($1000)")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Kita juga dapat mengkombinasi pengelompokan dan pembagian faset. Kita akan menggunakan warna untuk membedakan jenis kelamin dan pembagian faset untuk membuat plot jabatan berdasarkan kombinasi disiplin ilmu.

library(carData)            
library(ggplot2)           
library(dplyr)              
# menghitung rata-rata dan kesalahan standar berdasarkan 
# jenis kelamin, jabatan, dan disiplin ilmu
plotdata <- Salaries %>%
  group_by(sex, rank, discipline) %>%
  dplyr::summarize(n = n(),
            mean = mean(salary),
            sd = sd(salary),
            se = sd / sqrt(n))
## `summarise()` has grouped output by 'sex', 'rank'. You can override using the `.groups` argument.
# membuat label yang lebih baik untuk disiplin ilmu
plotdata$discipline <- factor(plotdata$discipline,
                              labels = c("Theoretical",
                                         "Applied"))
# membuat plot
ggplot(plotdata, 
       aes(x = sex, 
           y = mean,
           color = sex)) +
  geom_point(size = 3) +
  geom_errorbar(aes(ymin = mean - se, 
                    ymax = mean + se),
                width = .1) +
  scale_y_continuous(breaks = seq(70000, 140000, 10000),
                     label = scales::dollar) +
  facet_grid(. ~ rank + discipline) +
  theme_bw() +
  theme(legend.position = "none",
        panel.grid.major.x = element_blank(),
        panel.grid.minor.y = element_blank()) +
  labs(x="", 
       y="", 
       title="Nine month academic salaries by gender, discipline, and rank",
       subtitle = "(Means and standard errors)") +
  scale_color_brewer(palette="Set1")

Pernyataan facet_grid(.~rank+dicipline) tidak menentukan variabel baris (.) dan kolom yang ditentukan oleh kombinasi jabatan dan disiplin ilmu.

Fungsi theme() membuat tema hitam dan putih dan menghilangkan garis grid vertikal dan garis grid horizontal minor. Fungsi scale_color_brewer() mengubah skema warna untuk titik dan batang-batang kesalahan.

Pada pandangan pertama, tampaknya mungkin ada perbedaan gender dalam gaji untuk Associate dan Full Professors di bidang teoritis.

Sebagai contoh terakhir, kita akan beralih ke dataset baru dan memplot perubahan dalam harapan hidup dari waktu ke waktu untuk negara-negara di “Asia”. Data tersebut berasal dari dataset gapminder dalam package gapminder. Setiap negara muncul dalam fasetnya sendiri. Fungsi tema digunakan untuk menyederhanakan warna latar belakang, memutar teks sumbu x, dan memperkecil ukuran tulisan.

library(gapminder)                                   # untuk dataset
library(ggplot2)                                     # untuk visualisasi
library(dplyr)                                       # manipulasi data
# memplot harapan hidup berdasarkan tahun secara terpisah
# untuk setiap negara di Asia
data(gapminder, package = "gapminder")
# Pilih data Asia
plotdata <- dplyr::filter(gapminder, 
                          continent == "Asia")
# memplot harapan hidup berdasarkan tahun, untuk setiap negara
ggplot(plotdata, aes(x=year, y = lifeExp)) +
  geom_line(color="grey") +
  geom_point(color="blue") +
  facet_wrap(~country) + 
  theme_minimal(base_size = 9) +
  theme(axis.text.x = element_text(angle = 45, 
                                   hjust = 1)) +
  labs(title = "Changes in Life Expectancy",
       x = "Year",
       y = "Life Expectancy") 

LS0tDQp0aXRsZTogIlR1Z2FzIDYiDQpzdWJ0aXRsZTogIkFsZ29yaXRtYSBkYW4gc3RydWt0dXIgZGF0YSINCmF1dGhvcjogIkNhbHZpbiBSaXN3YW5kaSAoMjAyMTQ5MjAwMDMpIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgaHRtbF9kb2N1bWVudDogbnVsbA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRoZW1lOiBzYW5kc3RvbmUNCiAgICBjc3M6IHN0eWxlMS5jc3MNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCi0tLQ0KDQoNCjxpbWcgc3R5bGU9ImZsb2F0OiByaWdodDsgbWFyZ2luOiAwcHggMTAwcHggMHB4IDBweDsgd2lkdGg6MjUlIiBzcmM9ImZvdG8ucG5nIi8+IA0KDQpgYGB7ciBsb2dvLCBlY2hvPUZBTFNFLGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoID0gJzMwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiTG9nby5wbmciKQ0KYGBgDQoNCkVtYWlsICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyZuYnNwOzogIGNhbHZpbi5yaXN3YW5kaUBzdHVkZW50Lm1hdGFuYXVuaXZlcnNpdHkuYWMuaWQgPGJyPg0KUlB1YnMgICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOzogaHR0cHM6Ly9ycHVicy5jb20vQ2Fsdmlucmlzd2FuZHkvIDxicj4NCkp1cnVzYW4gJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOzogW1N0YXRpc3Rpa2FdKGh0dHBzOi8vbWF0YW5hdW5pdmVyc2l0eS5hYy5pZC8/bHk9YWNhZGVtaWMmYz1zYikgPGJyPg0KQWRkcmVzcyAgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7IDogQVJBIENlbnRlciwgTWF0YW5hIFVuaXZlcnNpdHkgVG93ZXIgPGJyPg0KJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsmbmJzcDsgSmwuIENCRCBCYXJhdCBLYXYsIFJULjEsIEN1cnVnIFNhbmdlcmVuZywgS2VsYXBhIER1YSwgVGFuZ2VyYW5nLCBCYW50ZW4gMTU4MTAuDQoNCioqKioNCg0KIyBVbml2YXJpYXQoU2F0dSBWYXJpYWJlbCkNCg0KVmlzdWFsaXNhc2kgZGF0YSBhZGFsYWggdGVrbmlrIG1lbmdhbWJpbCBpbmZvcm1hc2kgZGFyaSBkYXRhIGtlIGRhbGFtIGtvbnRla3MgdmlzdWFsLCBzZXBlcnRpIGJhZ2FuLCBncmFmaWssIGRhbiBwZXRhLiBWaXN1YWxpc2FzaSBkYXRhIG1lbWJ1YXQgZGF0YSBiZXNhciBkYW4ga2VjaWwgbGViaWggbXVkYWggZGlwYWhhbWkgb2xlaCBvdGFrIG1hbnVzaWEsIGRhbiB2aXN1YWxpc2FzaSBqdWdhIG1lbWJ1YXRueWEgbGViaWggYW5kYWwgdW50dWsgbWVuZGV0ZWtzaSBwb2xhLCB0cmVuLCBkYW4gb3V0bGllciBkYWxhbSBrZWxvbXBvayBkYXRhLg0KDQpLYXRlZ29yaXMsIHNlcGVydGk7IGplbmlzIGtlbGFtaW4sIHJhcywgbmVnYXJhLCBrb3RhLCBkbGwuDQpOdW1lcmlrLCBzZXBlcnRpOyB1c2lhLCBiZXJhdCBiYWRhbiwgaW5mbGFzaSwgc3VrdSBidW5nYSwgZGxsLg0KDQojIERpYWdyYW0gQmF0YW5nDQoNCkJlcmlrdXQgaW5pIGFkYWxhaCBjb250b2ggeWFuZyBtZW51bmp1a2thbiBmcmVrdWVuc2kgZGFyaSBkYXRhc2V0IE1hcnJpYWdlLCBTYXlhIG1lbmRhcGF0a2FubnlhIGRhcmkgcGFja2FnZSBtb3NhaWNEYXRhLiBLaXRhIGd1bmFrYW4gZGlhZ3JhbSBiYXRhbmcgdW50dWsgbWVuYW1waWxrYW4gZGlzdHJpYnVzaSBwZXNlcnRhIHBlcm5pa2FoYW4gYmVyZGFzYXJrYW4gWm9kaWFrLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCnNldHdkKCJDOi9Vc2Vycy81L0RvY3VtZW50cy9TdHJ1a3R1ciBEYXRhIikNCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpNYXJyaWFnZTwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQmFrdGktU2lyZWdhci9kYXRhc2V0L21hc3Rlci9Cb29rZG93bi1EYXRhLVNjaWVuY2UtZm9yLUJlZ2lubmVycy9NYXJyaWFnZS5jc3YiKSAgICAgICAgICAgICAjIG1lbWF1YXQgZGF0YSBkYXJpIFBDIEFuZGFgDQpnZ3Bsb3QoTWFycmlhZ2UsIGFlcyh4ID0gem9kaWFjcykpICsgICAgICAgICAgICAgICAgICMgbWVtcGxvdCBkaXN0cmlidXNpIGRhcmkgYFpvZGlhY3NgIA0KICBnZW9tX2JhcihmaWxsID0gImNvcm5mbG93ZXJibHVlIiwgDQogICAgICAgICAgIGNvbG9yPSAiYXp1cmU0IikgKyAgICAgICAgICAgICAgICAgICAgICAgICMgQW5kYSBkYXBhdCBtZW5nZ2FudGkgd2FybmEgDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWVuZ2d1bmFrYW4gdGVtYSBtaW5pbWFsDQogIGxhYnMoeCA9ICJab2RpYWNzIiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQW5kYSBkYXBhdCBtZW5nZ2FudGkgbGFiZWwgZGFuIGp1ZHVsIHBsb3QNCiAgICAgICB5ID0gIkZyZXF1ZW5jeSIsIA0KICAgICAgIHRpdGxlID0gIk1hcnJpYWdlIFBhcnRpY2lwYW50cyBieSBab2RpYWNzIikNCmBgYA0KDQpCYXRhbmcgcGFkYSBkaWFncmFtIGJhdGFuZyBkYXBhdCBtZW5nZ2FtYmFya2FuIHBlcnNlbnRhc2UgZGFyaSBqdW1sYWguZnJlcXVlbmN5IHRlcmJhbnlhayB0ZXJkYXBhdCBwYWRhIGJhdGFuZyB6b2RpYWsgcGlzY2VzLCBsYWx1IHVudHVrIGZyZXF1ZW5jeSB5YW5nIHBhbGluZyBkaWtpdCBwYWRhIGJhdGFuZyB6b2RpYWsgY2Fwcmljb3JuLiBEaWFncmFtIGJhdGFuZyBiaWFzYW55YSBkaWFncmFtIHlhbmcgc2VyaW5nIGRpIHBha2FpIHVudHVrIG1lbmVudHVrYW4gZnJlcXVlbmN5IGRhcmkgYmFueWFrIHNhbXBsZS4gYmVyaWt1dCBiZXJtYWNhbS1tYWNhbSBkaWFncmFtIGJhdGFuZzoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZ2dwbG90KE1hcnJpYWdlLCANCiAgIGFlcyh4ID0gem9kaWFjcywgDQogICAgICAgeSA9IC4uY291bnQuLiAvIHN1bSguLmNvdW50Li4pKSkgKyANCiAgZ2VvbV9iYXIoZmlsbCA9IHJhaW5ib3coMTIpLCBjb2xvcj0gImF6dXJlNCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbGFicyh4ID0gIlpvZGlhY3MiLCANCiAgICAgICB5ID0gIlBlcmNlbnQiLCANCiAgdGl0bGUgID0gIk1hcnJpYWdlIFBhcnRpY2lwYW50cyBpbiBQZXJjZW50IikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVudHVrIG1hbmlwdWxhc2kgZGF0YQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVudHVrIHZpc3VhbGlzYXNpDQpwbG90ZGF0YSA8LSBNYXJyaWFnZSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWVtdWF0IGRhdGFzZXQNCiBjb3VudCh6b2RpYWNzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBqdW1sYWggcGVzZXJ0YSBkaSBzZXRpYXAgJ3pvZGlhY3MnDQojIG1lbnl1c3VuIHBsb3QgYmF0YW5nIHNlY2FyYSBtZW5pbmdrYXQNCmdncGxvdChwbG90ZGF0YSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogICAgICAgYWVzKHggPSByZW9yZGVyKHpvZGlhY3MsIG4pLCANCiAgICAgICAgICAgeSA9IG4pKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwNCiAgICAgICAgICAgZmlsbCA9IHJhaW5ib3coMTIpLCANCiAgICAgICAgICAgY29sb3I9ICJhenVyZTQiKSArDQogICB0aGVtZV9taW5pbWFsKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1lbmdndW5ha2FuIHRlbWEgbWluaW1hbA0KICBsYWJzKHggPSAiWm9kaWFjcyIsIA0KICAgICAgIHkgPSAiRnJlcXVlbmN5IiwgDQogIHRpdGxlICA9ICJTb3J0aW5nIENhdGVnb3JpZXMiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCnBsb3RkYXRhIDwtIE1hcnJpYWdlICU+JQ0KICBjb3VudCh6b2RpYWNzKSAlPiUNCiAgbXV0YXRlKHBjdCA9IG4gLyBzdW0obiksDQogICAgICAgICBwY3RsYWJlbCA9IHBhc3RlMChyb3VuZChwY3QqMTAwKSwgIiUiKSkNCmdncGxvdChwbG90ZGF0YSwgDQogICAgICAgYWVzKHggPSByZW9yZGVyKHpvZGlhY3MsIC1wY3QpLA0KICAgICAgICAgICB5ID0gcGN0KSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIA0KICAgICAgICAgICBmaWxsID0gcmFpbmJvdygxMiksIA0KICAgICAgICAgIGNvbG9yID0gImF6dXJlNCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBjdGxhYmVsKSwgDQogICAgICAgICAgICB2anVzdCA9IC0wLjI1KSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsNCiAgbGFicyh4ID0gIlpvZGlhY3MiLCANCiAgICAgICB5ID0gIlBlcmNlbnQiLCANCiAgICAgICB0aXRsZSAgPSAiTGFiZWxpbmcgQmFycyIpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZ2dwbG90KHBsb3RkYXRhLCANCiAgICAgICBhZXMoeCA9IHJlb3JkZXIoem9kaWFjcywgLXBjdCksDQogICAgICAgICAgIHkgPSBwY3QpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgDQogICAgICAgICAgIGZpbGwgPSByYWluYm93KDEyKSwgDQogICAgICAgICAgIGNvbG9yID0gImF6dXJlNCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBjdGxhYmVsKSwgDQogICAgICAgICAgICB2anVzdCA9IC0wLjI1KSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbGFicyh4ID0gIlpvZGlhY3MiLCANCiAgICAgICB5ID0gIlBlcmNlbnQiLCANCiAgICAgICB0aXRsZSAgPSAiT3ZlcmxhcHBpbmcgTGFiZWxzIikrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZ2dwbG90KHBsb3RkYXRhLCANCiAgICAgICBhZXMoeCA9IHJlb3JkZXIoem9kaWFjcywgLXBjdCksDQogICAgICAgICAgIHkgPSBwY3QpKSArIA0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgDQogICAgICAgICAgIGZpbGwgPSByYWluYm93KDEyKSwgDQogICAgICAgICAgIGNvbG9yID0gImF6dXJlNCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBjdGxhYmVsKSwgDQogICAgICAgICAgICBoanVzdCA9IC0wLjEwKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBsYWJzKHggPSAiWm9kaWFjcyIsIA0KICAgICAgIHkgPSAiUGVyY2VudCIsIA0KICAgICAgIHRpdGxlICA9ICJPdmVybGFwcGluZyBMYWJlbHMiKSsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KIyBEaWFncmFtIFBhaQ0KDQpEaWFncmFtIHBhaSBiZXJzaWZhdCBrb250cm92ZXJzaWFsIGRpIHN0YXRpc3Rpay4gSmlrYSB0dWp1YW4gQW5kYSBhZGFsYWggbWVtYmFuZGluZ2thbiBmcmVrdWVuc2kgZGFyaSBrYXRlZ29yaSwgbGViaWggYmFpayBBbmRhIG1lbmdndW5ha2FuIGRpYWdyYW0gYmF0YW5nLiBKaWthIHR1anVhbiBBbmRhIHVudHVrIG1lbWJhbmRpbmdrYW4gc2V0aWFwIGthdGVnb3JpIHNlY2FyYSBrZXNlbHVydWhhbiwgZGFuIGp1bWxhaCBrYXRlZ29yaW55YSBrZWNpbCwgbWFrYSBkaWFncmFtIHBhaSBtdW5na2luIGNvY29rIHVudHVrIEFuZGEuIEJpYXNhbnlhIGRpYWdyYW0gcGFpIGRpZ3VuYWthbiB1bnR1ayBtZW5naGl0dW5nIGZyZWt1ZW5zaSBkZW5nYW4gc2VrYWxhIGJlc2FyIGRhbiBiaWFzYW55YSBtZW5nZ3VuYWthbiBwZXJzZW50YXNlLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyBQZXJzaWFwYW4gZGF0YQ0KcGxvdGRhdGEgPC0gTWFycmlhZ2UgJT4lDQogIGNvdW50KHJhY2UpICU+JQ0KICBhcnJhbmdlKGRlc2MocmFjZSkpICU+JQ0KICBtdXRhdGUocHJvcCA9IHJvdW5kKG4qMTAwL3N1bShuKSwgMSksDQogICAgICAgICBsYWIueXBvcyA9IGN1bXN1bShwcm9wKSAtIDAuNSpwcm9wKQ0KIyBNZW1idWF0IGRpYWdyYW0gcGFpDQpteWNvbHMgPC0gYygiIzAwNzNDMkZGIiwgIiNFRkMwMDBGRiIsICIjODY4Njg2RkYiLCAiI0NENTM0Q0ZGIikNCmdncGxvdChwbG90ZGF0YSwgYWVzKHggPSAiIiwgeSA9IHByb3AsIGZpbGwgPSByYWNlKSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApKw0KICBnZW9tX3RleHQoYWVzKHkgPSBsYWIueXBvcywgbGFiZWwgPSBwcm9wKSwgY29sb3IgPSAid2hpdGUiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbXljb2xzKSArDQogIHRoZW1lX3ZvaWQoKSsNCiAgbGFicyh0aXRsZSA9ICJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgUmFjZSIpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdW50dWsgdmlzdWFsaXNhc2kNCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtZW5lbnR1a2FuIGplZGEgYXRhdSBsYWJlbCBzZWNhcmEgb3RvbWF0aXMNCiMgbWVtYnVhdCBkaWFncmFtIGRvbmF0DQpnZ3Bsb3QocGxvdGRhdGEsIGFlcyh4ID0gMiwgeSA9IHByb3AsIGZpbGwgPSByYWNlKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAid2hpdGUiKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiLCBzdGFydCA9IDApKw0KICBnZW9tX3RleHQoYWVzKHkgPSBsYWIueXBvcywgbGFiZWwgPSBwcm9wKSwgY29sb3IgPSAid2hpdGUiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbXljb2xzKSArDQogIHRoZW1lX3ZvaWQoKSsNCiAgeGxpbSgwLjUsIDIuNSkrDQogIGxhYnModGl0bGUgPSAiTWFycmlhZ2UgUGFydGljaXBhbnRzIGJ5IFJhY2UiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgIA0KbGlicmFyeShzY2FsZXMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyB0YW1iYWhrYW4gbGFiZWwgcGVyc2VuDQpwbG90ZGF0YSRwZXJjZW50IDwtIHBhc3RlMChwbG90ZGF0YSRyYWNlLCAiXG4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHBsb3RkYXRhJHByb3ApLCAiJSIpDQojIG1lbWJ1YXQgZGlhZ3JhbSBkb25hdCBkYWxhbSBwZXJzZW4NCmdncGxvdChwbG90ZGF0YSwgYWVzKHggPSAyLCB5ID0gcHJvcCwgZmlsbCA9IHJhY2UpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIsIHN0YXJ0ID0gMCkrDQogIGdlb21fdGV4dChhZXMoeSA9IGxhYi55cG9zLCBsYWJlbCA9IHBlcmNlbnQpLCBjb2xvciA9ICJ3aGl0ZSIpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBteWNvbHMpICsNCiAgdGhlbWVfdm9pZCgpKw0KICB4bGltKDAuNSwgMi41KSsNCiAgbGFicyh0aXRsZSA9ICJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgUmFjZSIpDQpgYGANCg0KIyMgUGV0YSBQb2hvbg0KU2VidWFoIGFsdGVybmF0aWYgdW50dWsgZGlhZ3JhbSBwYWkgYWRhbGFoIHBldGEgcGhvbi4gVGlkYWsgc2VwZXJ0aSBkaWFncmFtIHBhaSwgcGV0YSBwb2hvbiBkYXBhdCBtZW5hbmdhbmkgdmFyaWFiZWwga2F0ZWdvcmlrYWwgeWFuZyBtZW1pbGlraSBiYW55YWsgdGluZ2thdGFuLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkodHJlZW1hcGlmeSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCnBsb3RkYXRhIDwtIE1hcnJpYWdlICU+JQ0KICBjb3VudChvZmZpY2lhbFRpdGxlKQ0KZ2dwbG90KHBsb3RkYXRhLCANCiAgICAgICBhZXMoZmlsbCA9IG9mZmljaWFsVGl0bGUsIA0KICAgICAgICAgICBhcmVhID0gbikpICsNCiAgZ2VvbV90cmVlbWFwKCkgKyANCiAgbGFicyh0aXRsZSA9ICJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgT2ZmaWNpYXRlIikNCg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KHBsb3RkYXRhLCANCiAgICAgICBhZXMoZmlsbCA9IG9mZmljaWFsVGl0bGUsIA0KICAgICAgICAgICBhcmVhID0gbiwgDQogICAgICAgICAgIGxhYmVsID0gb2ZmaWNpYWxUaXRsZSkpICsNCiAgZ2VvbV90cmVlbWFwKCkgKyANCiAgZ2VvbV90cmVlbWFwX3RleHQoY29sb3VyID0gIndoaXRlIiwgDQogICAgICAgICAgICAgICAgICAgIHBsYWNlID0gImNlbnRyZSIpICsNCiAgbGFicyh0aXRsZSA9ICJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgT2ZmaWNpYXRlIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpgYGANCg0KIyMgVmFyaWFiZWwgS29udGludQ0KRGlzdHJpYnVzaSB2YXJpYWJlbCBrdWFudGl0YXRpZiB0dW5nZ2FsIGJpYXNhbnlhIGRpcGxvdCBkZW5nYW4gaGlzdG9ncmFtLCBwbG90IGRlbnNpdGFzIGtlcm5lbCwgYXRhdSBwbG90IHRpdGlrLg0KDQojIyBIaXN0b2dyYW0NCk1lbmdndW5ha2FuIGRhdGFzZXQgTWFycmlhZ2UsIG1hcmkga2l0YSBwbG90IHVzaWEgZGFyaSBwZXNlcnRhIHBlcm5pa2FoYW4uDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpnZ3Bsb3QoTWFycmlhZ2UsIGFlcyh4ID0gYWdlKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gImNvcm5mbG93ZXJibHVlIiwgDQogICAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIixiaW5zID0gMjApICsgDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBsYWJzKHRpdGxlPSJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgYWdlIChCYXNpYykiLA0KICAgICAgIHggPSAiQWdlIikNCmBgYA0KDQpQZXNlcnRhIHRhbXBha255YSBiZXJ1c2lhIDIwLWFuIHRhaHVuIGRlbmdhbiBrZWxvbXBvayBsYWluIGJlcnVzaWEgNDAtYW4gdGFodW4sIGRhbiBrZWxvbXBvayB5YW5nIGxlYmloIGtlY2lsIGJlcnVzaWEgNjAtYW4gZGFuIDcwLWFuIHRhaHVuLiBJbmkgYWthbiBtZW5qYWRpIGRpc3RyaWJ1c2kgbXVsdGltb2RhbC4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmdncGxvdChNYXJyaWFnZSwgDQogICAgICAgYWVzKHggPSBhZ2UsIA0KICAgICAgICAgICB5PSAuLmNvdW50Li4gLyBzdW0oLi5jb3VudC4uKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIsIA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIsIA0KICAgICAgICAgICAgICAgICBiaW53aWR0aCA9IDUpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGxhYnModGl0bGU9Ik1hcnJpYWdlIFBhcnRpY2lwYW50cyBieSBhZ2UgKEFsdGVybmF0aXZlIEJpbnMgYW5kIGJhbmR3aWR0aHMpIiwgDQogICAgICAgeSA9ICJQZXJjZW50IiwNCiAgICAgICB4ID0gIkFnZSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpDQpgYGANCg0KcGFkYSBkaWFncmFtIGJhdGFuZywgc3VtYnUgeSBkYXBhdCBtZXdha2lsaSBqdW1sYWggYXRhdSBwZXJzZW4gZGFyaSB0b3RhbC4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KbGlicmFyeShzY2FsZXMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZ2dwbG90KE1hcnJpYWdlLCANCiAgICAgICBhZXMoeCA9IGFnZSwgDQogICAgICAgICAgIHk9IC4uY291bnQuLiAvIHN1bSguLmNvdW50Li4pKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gImNvcm5mbG93ZXJibHVlIiwgDQogICAgICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwgDQogICAgICAgICAgICAgICAgIGJpbndpZHRoID0gNSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBsYWJzKHRpdGxlPSJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgYWdlIChQZXJjZW50KSIsIA0KICAgICAgIHkgPSAiUGVyY2VudCIsDQogICAgICAgeCA9ICJBZ2UiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KQ0KYGBgDQoNCiMjIFBsb3QgRGVuc2l0YXMgS2VybmVsDQoNCkFsdGVybmF0aWYgdW50dWsgaGlzdG9ncmFtIGFkYWxhaCBwbG90IGRlbnNpdGFzIEtlcm5lbC4gU2VjYXJhIHRla25pcywgcGVya2lyYWFuIGRlbnNpdGFzIGtlcm5lbCBhZGFsYWggbWV0b2RlIG5vbi1wYXJhbWV0cmlrIHVudHVrIG1lbXBlcmtpcmFrYW4gZnVuZ3NpIGRlbnNpdGFzIHByb2JhYmlsaXRhcyBkYXJpIHZhcmlhYmVsIGFjYWsga29udGludS4gKEFwYT8/KSBQYWRhIGRhc2FybnlhLCBraXRhIG1lbmNvYmEgdW50dWsgbWVuZ2dhbWJhciBoaXN0b2dyYW0geWFuZyBkaXBlcmhhbHVzLCBkaSBtYW5hIGFyZWEgZGkgYmF3YWgga3VydmEgc2FtYSBkZW5nYW4gc2F0dS4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmdncGxvdChNYXJyaWFnZSwgYWVzKHggPSBhZ2UpKSArDQogIGdlb21fZGVuc2l0eShmaWxsID0gImluZGlhbnJlZDMiKSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbGFicyh0aXRsZSA9ICJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgYWdlIikNCmBgYA0KDQpHcmFmaWsgbWVudW5qdWtrYW4gZGlzdHJpYnVzaSBkYXJpIG5pbGFpLiBTZWJhZ2FpIGNvbnRvaCwgcGVyYmFuZGluZ2FuIGthc3VzIGFudGFyYSAyMCBkYW4gNDAgdGFodW4gYWthbiBkaXdha2lsaSBvbGVoIGFyZWEgZGkgYmF3YWgga3VydmEgYW50YXJhIDIwIGRhbiA0MCBwYWRhIHN1bWJ1IHguIFNlcGVydGkgZGlhZ3JhbSBzZWJlbHVtbnlhLCBraXRhIGp1Z2EgZGFwYXQgbWVuZ2d1bmFrYW4gZmlsbCBkYW4gY29sb3IgdW50dWsgbWVuZW50dWthbiB3YXJuYSBpc2lhbiBkYW4gYmF0YXNhbm55YS4NCg0KIyMgUGFyYW1ldGVyIFBlbmdoYWx1c2FuIChTbW9vdGhpbmcpDQoNClRpbmdrYXQga2VoYWx1c2FuIGRpa29udHJvbCBvbGVoIHBhcmFtZXRlciBiYW5kd2lkdGggYncuIFVudHVrIG1lbmVtdWthbiBuaWxhaSBkZWZhdWx0IHVudHVrIHZhcmlhYmVsIHRlcnRlbnR1LCBndW5ha2FuIGZ1bmdzaSBidy5ucmQwLiBOaWxhaSB5YW5nIGxlYmloIGJlc2FyIGFrYW4gbWVuZ2hhc2lsa2FuIHBlbmdoYWx1c2FuIHlhbmcgbGViaWggYmFueWFrLCBzZWRhbmdrYW4gbmlsYWkgeWFuZyBsZWJpaCBrZWNpbCBha2FuIG1lbmdoYXNpbGthbiBwZW5naGFsdXNhbiB5YW5nIGxlYmloIHNlZGlraXQuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KYncubnJkMChNYXJyaWFnZSRhZ2UpICAgICAgICAgICAgICAgICAgICAgICANCmdncGxvdChNYXJyaWFnZSwgYWVzKHggPSBhZ2UpKSArDQogIGdlb21fZGVuc2l0eShmaWxsID0gImRlZXBza3libHVlIiwgDQogICAgICAgICAgICAgICBidyA9IDEpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBsYWJzKHRpdGxlID0gIlBhcnRpY2lwYW50cyBieSBhZ2UiLA0KICAgICAgIHN1YnRpdGxlID0gImJhbmR3aWR0aCA9IDEiKQ0KYGBgDQoNClBsb3QgZGVuc2l0YXMga2VybmVsIG1lbXVuZ2tpbmthbiBBbmRhIGRlbmdhbiBtdWRhaCBtZWxpaGF0IHNrb3IgbWFuYSB5YW5nIHBhbGluZyBzZXJpbmcgZGFuIG1hbmEgeWFuZyByZWxhdGlmIGphcmFuZy4gTmFtdW4gc3VsaXQgdW50dWsgbWVuamVsYXNrYW4gYXJ0aSBzdW1idSB5IGtlcGFkYSBzZW9yYW5nIG5vbi1haGxpIHN0YXRpc3Rpay4NCg0KIyBEaWFncmFtIFRpdGlrDQoNCkFsdGVybmF0aWYgbGFpbiB1bnR1ayBoaXN0b2dyYW0gYWRhbGFoIGRpYWdyYW0gdGl0aWsuIFNla2FsaSBsYWdpLCB2YXJpYWJlbCBrdWFudGl0YXRpZiBkaWJhZ2kgbWVuamFkaSBiZWJlcmFwYSBrZWxvbXBvaywgdGV0YXBpIGJ1a2FuIGJlcmJlbnR1ayBiYXRhbmcsIHNldGlhcCBwZW5nYW1hdGFuIGRpdGVudHVrYW4gb2xlaCBzZWJ1YWggdGl0aWsuIFNlY2FyYSBkZWZhdWx0LCBsZWJhciBkYXJpIHNlYnVhaCB0aXRpayBzYW1hIGRlbmdhbiBsZWJhciBiaW4sIGRhbiB0aXRpay10aXRpayBiZXJ0dW1wdWssIGRlbmdhbiBzZXRpYXAgdGl0aWsgbWV3YWtpbGkgc2F0dSBwZW5nYW1hdGFuLiBJbmkgYmVrZXJqYSBkZW5nYW4gYmFpayBqaWthIGp1bWxhaCBwZW5nYW1hdGFuIGtlY2lsIChrYXRha2FubGFoLCBrdXJhbmcgZGFyaSAxNTApLiBPcHNpIGZpbGwgZGFuIGNvbG9yIGRhcGF0IGRpZ3VuYWthbiB1bnR1ayBtZW5lbnR1a2FuIHdhcm5hIGlzaWFuIGRhbiBiYXRhc2FuIG1hc2luZy1tYXNpbmcgdGl0aWsuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpnZ3Bsb3QoTWFycmlhZ2UsIGFlcyh4ID0gYWdlKSkgKw0KICBnZW9tX2RvdHBsb3QoZmlsbCA9ICJnb2xkIiwgDQogICAgICAgICAgICAgICBjb2xvciA9ICJhenVyZTQiLA0KICAgICAgICAgICAgICAgYmlud2lkdGggPSAyKSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQogIGxhYnModGl0bGUgPSAiUGFydGljaXBhbnRzIGJ5IGFnZSIsDQogICAgICAgeSA9ICJQcm9wb3J0aW9uIiwNCiAgICAgICB4ID0gIkFnZSIpDQpgYGANCg0KIyBEYXRhIEJpdmFyaWF0DQoNCkdyYWZpayBiaXZhcmlhdCBtZW51bmp1a2thbiBodWJ1bmdhbiBhbnRhcmEgZHVhIHZhcmlhYmVsLiBKZW5pcyBncmFmaWsgYWthbiB0ZXJnYW50dW5nIHBhZGEgdGluZ2thdCBwZW5ndWt1cmFuIGRhcmkgdmFyaWFiZWwgKGthdGVnb3Jpa2FuIGF0YXUga3VhbnRpdGF0aWYpLg0KDQojIyBLYXRlZ29yaWthbCB2cy4gS2F0ZWdvcmlrYWwNCg0KIyMjIERpYWdyYW0gQmF0YW5nIEJlcnR1bXB1aw0KDQpNYXJpIGtpdGEgcGxvdCBodWJ1bmdhbiBhbnRhcmEga2VsYXMgbW9iaWwgZGFuIGplbmlzIHBlbmdnZXJhayAocm9kYSBkZXBhbiwgcm9kYSBiZWxha2FuZywgYXRhdSBwZW5nZ2VyYWsgNCByb2RhKSB1bnR1ayBtb2JpbCBkYWxhbSBkYXRhc2V0IEZ1ZWwgZWNvbm9teS4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KbXBnJGRydjwtZmFjdG9yKG1wZyRkcnYsIA0KICAgICAgICAgICAgICAgIGxldmVscyA9IGMoImYiLCAiciIsICI0IiksDQogICAgICAgICAgICAgICAgbGFiZWxzID0gYygiZnJvbnQtd2hlZWwiLCAicmVhci13aGVlbCIsICI0LXdoZWVsIikpDQojIGRpYWdyYW0gYmF0YW5nIGJlcnR1bXB1aw0KZ2dwbG90KG1wZywgDQogICAgICAgYWVzKHggPSBjbGFzcywgDQogICAgICAgICAgIGZpbGwgPSBkcnYpKSArIA0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbGFicyh5ID0gIlByb3BvcnRpb24iKQ0KYGBgDQoNCiMjIyBEaWFncmFtIEJhdGFuZyB5YW5nIERpa2Vsb21wb2trYW4NCg0KVGVtcGF0IGRpYWdyYW0gYmF0YW5nIHlhbmcgZGlrZWxvbXBva2thbiB1bnR1ayB2YXJpYWJlbCBrYXRlZ29yaSBrZWR1YSBzZWNhcmEgYmVyZGFtcGluZ2FuLiANCg0KVW50dWsgbWVtYnVhdCBwbG90IGJhdGFuZyB5YW5nIGRpa2Vsb21wb2trYW4sIGd1bmFrYW4gb3BzaSBwb3NpdGlvbiA9ICJzaW5nbGUiLiBQZXJoYXRpa2FuIGJhaHdhIG9wc2kgaW5pIGhhbnlhIHRlcnNlZGlhIGRpIHZlcnNpIHBlbmdlbWJhbmdhbiB0ZXJiYXJ1IGdncGxvdDIsIHRldGFwaSBha2FuIHNlZ2VyYSB0ZXJzZWRpYSBzZWNhcmEgdW11bS4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgIA0KZ2dwbG90KG1wZywgYWVzKHggPSBjbGFzcywgZmlsbCA9IGRydikpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgICAgICAgICAgICAgDQogIGdlb21fYmFyKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UocHJlc2VydmUgPSAic2luZ2xlIikpDQpgYGANCg0KIyMjIERpYWdyYW0gQmF0YW5nIFRlcnNlZ21lbnRhc2kNCg0KUGxvdCBiYXRhbmcgeWFuZyB0ZXJzZWdtZW50YXNpIG1lcnVwYWthbiBwbG90IGJhdGFuZyB5YW5nIGJlcnR1bXB1ayBkaSBtYW5hIHNldGlhcCBiYXRhbmcgbWV3YWtpbGkgMTAwIHBlcnNlbi4gQW5kYSBkYXBhdCBtZW1idWF0IGRpYWdyYW0gYmF0YW5nIHRlcnNlZ21lbnRhc2kgbWVuZ2d1bmFrYW4gb3BzaSBwb3NpdGlvbiA9ICJmaWxsZWQiLiBKZW5pcyBwbG90IGluaSBzYW5nYXQgYmVyZ3VuYSBqaWthIHR1anVhbm55YSBhZGFsYWggdW50dWsgbWVtYmFuZGluZ2thbiBwZXJzZW50YXNpIGRhcmkga2F0ZWdvcmkgZGFsYW0gc2F0dSB2YXJpYWJlbCBkaSBzZXRpYXAgdGluZ2thdCB2YXJpYWJlbCBsYWluLiBTZWJhZ2FpIGNvbnRvaCwgcHJvcG9yc2kgbW9iaWwgZGVuZ2FuIHBlbmdnZXJhayByb2RhIGRlcGFuIChmcm9udC13aGVlbCkgbWVuaW5na2F0IHNhYXQgQW5kYSBtZW1pbmRhaGthbiBkYXJpIG1vYmlsIHBlbnVtcGFuZyB5YW5nIGtlY2lsLCBrZSBtZW5lbmdhaCwga2UgbWluaXZhbi4NCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQojIG1lbWJ1YXQgcmluZ2thc2FuIGRhdGFzZXQgKG1hbmlwdWxhc2kgZGF0YSkNCnBsb3RkYXRhIDwtIG1wZyAlPiUNCiAgZ3JvdXBfYnkoY2xhc3MsIGRydikgJT4lDQogIGRwbHlyOjpzdW1tYXJpemUobiA9IG4oKSkgJT4lDQogIG11dGF0ZShwY3QgPSBuL3N1bShuKSwNCiAgICAgICAgIGxibCA9IHNjYWxlczo6cGVyY2VudChwY3QpKQ0KIyBtZW1idWF0IGRpYWdyYW0gYmF0YW5nIHRlcnNlZ21lbnRhc2kNCiMgbWVuYW1iYWhrYW4gbGFiZWwgdW50dWsgc2V0aWFwIHNlZ21lbg0KZ2dwbG90KHBsb3RkYXRhLCANCiAgICAgICBhZXMoeCA9IGZhY3RvcihjbGFzcyksDQogICAgICAgICAgIHkgPSBwY3QsDQogICAgICAgIGZpbGwgPSBmYWN0b3IoZHJ2KSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsDQogICAgICAgICAgIHBvc2l0aW9uID0gImZpbGwiKSArDQogIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgLjIpLCANCiAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGVyY2VudCkrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBsYmwpLA0KICAgICAgICAgICAgc2l6ZSA9IDMsDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDIiKSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWVuZ2d1bmFrYW4gdGVtYSBtaW5pbWFsDQogIGxhYnMoeSA9ICJQZXJjZW50IiwNCiAgICAgICBmaWxsID0gIkRyaXZlIFRyYWluIiwNCiAgICAgICB4ID0gIkNsYXNzIiwNCiAgICAgICB0aXRsZSA9ICJBdXRvbW9iaWxlIERyaXZlIGJ5IENsYXNzIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyMgUGxvdCBNb3NhaWsNCkRpYWdyYW0gbW9zYWlrIGRhcGF0IG1lbmFtcGlsa2FuIGh1YnVuZ2FuIGFudGFyYSB2YXJpYWJlbCBrYXRlZ29yaWthbCBtZW5nZ3VuYWthbiBwZXJzZWdpIHBhbmphbmcgeWFuZyBsdWFzbnlhIG1ld2FraWxpIHByb3BvcnNpIGtlamFkaWFuIHVudHVrIGtvbWJpbmFzaSBsZXZlbCB0ZXJ0ZW50dS4gV2FybmEgdWJpbiBqdWdhIGRhcGF0IG1lbnVuanVra2FuIHRpbmdrYXQgaHVidW5nYW4gYW50YXIgdmFyaWFiZWwuDQoNCk1lc2tpcHVuIHBsb3QgbW9zYWlrIGRhcGF0IGRpYnVhdCBkZW5nYW4gZ2dwbG90MiBtZW5nZ3VuYWthbiBwYWNrYWdlIGdnbW9zYWljLCBzYXlhIG1lcmVrb21lbmRhc2lrYW4gbWVuZ2d1bmFrYW4gcGFja2FnZSB2Y2Qgc2ViYWdhaSBnYW50aW55YS4gTWVza2lwdW4gdGlkYWsgYWthbiBtZW1idWF0IGdyYWZpayBnZ3Bsb3QyLCBwYWNrYWdlIHRlcnNlYnV0IG1lbWJlcmlrYW4gcGVuZGVrYXRhbiB5YW5nIGxlYmloIGtvbXByZWhlbnNpZiB1bnR1ayBtZW12aXN1YWxpc2FzaWthbiBkYXRhIGthdGVnb3Jpa2FsLg0KDQpPcmFuZy1vcmFuZyB0ZXJwZXNvbmEgZGVuZ2FuIFRpdGFuaWMuIERhbGFtIGJlbmNhbmEgVGl0YW5pYywgcGVyYW4gYXBhIHlhbmcgZGltYWlua2FuIG9sZWggc2V4IGRhbiBjbGFzcyBkYWxhbSBzdXJ2aXZhbD8gS2l0YSBkYXBhdCBtZW12aXN1YWxpc2FzaWthbiBodWJ1bmdhbiBhbnRhcmEga2V0aWdhIHZhcmlhYmVsIGthdGVnb3Jpa2FsIG1lbmdndW5ha2FuIGtvZGUgYmVyaWt1dC4NCg0KYGBge3J9DQojIG1lbWJ1YXQgdGFiZWwNCnRibCA8LSB4dGFicyhGcmVxIH4gU3Vydml2ZWQgKyBDbGFzcyArIFNleCwgVGl0YW5pYykNCmZ0YWJsZSh0YmwpDQojIG1lbWJ1YXQgcGxvdCBtb3NhaWsgZGFyaSB0YWJlbA0KbGlicmFyeSh2Y2QpDQptb3NhaWModGJsLCBtYWluID0gIlRpdGFuaWMgZGF0YSIpDQpgYGANCg0KVWt1cmFuIHViaW4gc2ViYW5kaW5nIGRlbmdhbiBwZXJzZW50YXNlIGthc3VzIGRhbGFtIGtvbWJpbmFzaSB0aW5na2F0IHRlcnNlYnV0LiBKZWxhcyBsZWJpaCBiYW55YWsgcGVudW1wYW5nIHlhbmcgdGV3YXMgZGFyaXBhZGEgeWFuZyBzZWxhbWF0LiBNZXJla2EgeWFuZyB0ZXdhcyBhZGFsYWggcGVudW1wYW5nIGxha2ktbGFraSBrZWxhcyAzIGRhbiBrcnUgbGFraS1sYWtpLg0KDQoga2l0YSBkYXBhdCBtZW1lcmlrc2EgcmVzaWR1YWwgZGFyaSBtb2RlbCBkYW4gbWVtYmVyaSBiYXlhbmdhbiBwYWRhIHViaW4gYWdhciBzZXN1YWkuIFBhZGEgZ3JhZmlrIGRpIGJhd2FoLCBiaXJ1IGdlbGFwIG1ld2FraWxrYW4gbGViaWggYmFueWFrIGthc3VzIGRhcmkgeWFuZyBkaWhhcmFwa2FuIHRpZGFrIHRlcmlrYXQuIE1lcmFoIHR1YSBtZXdha2lsaSBsZWJpaCBzZWRpa2l0IGthc3VzIGRhcmkgeWFuZyBkaWhhcmFwa2FuIGppa2EgYmVybGFrdSB0aWRhayB0ZXJpa2F0Lg0KDQpgYGB7cn0NCm1vc2FpYyh0YmwsIA0KICAgICAgIHNoYWRlID0gVFJVRSwNCiAgICAgICBsZWdlbmQgPSBUUlVFLA0KICAgICAgIGxhYmVsaW5nX2FyZ3MgPSBsaXN0KHNldF92YXJuYW1lcyA9IGMoU2V4ID0gIkdlbmRlciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdXJ2aXZlZCA9ICJTdXJ2aXZlZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDbGFzcyA9ICJQYXNzZW5nZXIgQ2xhc3MiKSksDQogICAgICAgc2V0X2xhYmVscyA9IGxpc3QoU3Vydml2ZWQgPSBjKCJObyIsICJZZXMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBDbGFzcyA9IGMoIjFzdCIsICIybmQiLCAiM3JkIiwgIkNyZXciKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBTZXggPSBjKCJGIiwgIk0iKSksDQogICAgICAgbWFpbiA9ICJUaXRhbmljIGRhdGEiKQ0KYGBgDQoNCktpdGEgZGFwYXQgbWVsaWhhdCBqaWthIGNsYXNzLCBnZW5kZXIsIGRhbiBzdXJ2aXZhbCBhZGFsYWggdGlkYWsgdGVyaWthdCwga2l0YSBtZWxpaGF0IGxlYmloIGJhbnlhayBrcnUgbGFraS1sYWtpIHlhbmcgdGV3YXMsIGRhbiBwZXJlbXVwYW4ga2VsYXMgMSwgMiwgZGFuIDMgYmVydGFoYW4gaGlkdXAgZGFyaXBhZGEgeWFuZyBkaWhhcmFwa2FuLiBTZWJhbGlrbnlhLCBqYXVoIGxlYmloIHNlZGlraXQgcGVudW1wYW5nIGtlbGFzIDEgKGxha2ktbGFraSBkYW4gcGVyZW1wdWFuKSB5YW5nIG1lbmlnZ2FsIGRhcmlwYWRhIHlhbmcgZGlwZXJraXJha2FuIHNlY2FyYSBrZWJldHVsYW4uIERlbmdhbiBkZW1pa2lhbiBhc3Vtc2kgdGlkYWsgdGVyaWthdCBkaXRvbGFrLg0KDQojIyMgRGlza3JpdCB2cyBLb250aW51DQpIdWJ1bmdhbiBhbnRhcmEgZHVhIHZhcmlhYmVsIGt1YW50aXRhdGlmIGJpYXNhbnlhIGRpdGFtcGlsa2FuIG1lbmdndW5ha2FuIHBsb3Qgc2ViYXJhbiBkYW4gZ3JhZmlrIGdhcmlzLg0KDQojIyMgUGxvdCBTZWJhcmFuDQpQbG90IFNlYmFyYW4gZGlidWF0IHVudHVrIG1lbXBlbGFqYXJpIGh1YnVuZ2FuIGFudGFyYSAyIHZhcmlhYmVsLiBTZWhpbmdnYSBzZXJpbmcgZGlzZXJ0YWkgZGVuZ2FuIHBlcmhpdHVuZ2FuIGtvZWZpc2llbiBrb3JlbGFzaSwgeWFuZyBiaWFzYW55YSBtZW5jb2JhIHVudHVrIG1lbmd1a3VyIGh1YnVuZ2FuIGxpbmVhci4gTmFtdW4gamVuaXMgaHVidW5nYW4gbGFpbiBkYXBhdCBkaWRldGVrc2kgbWVuZ2d1bmFrYW4gcGxvdCBzZWJhcmFuLCBkYW4gdHVnYXMgdW11bSB0ZXJkaXJpIGRhcmkgbWVueWVzdWFpa2FuIG1vZGVsIHlhbmcgbWVuamVsYXNrYW4gWSBkYWxhbSBmdW5nc2kgWC4gQmVyaWt1dCBhZGFsYWggYmViZXJhcGEgcG9sYSB5YW5nIGRhcGF0IEFuZGEgZGV0ZWtzaSBkZW5nYW4gbWVsYWt1a2FuIHBsb3Qgc2ViYXJhbi4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoaHJicnRoZW1lcykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KIyBNZW1idWF0IGRhdGENCmQxIDwtIGRhdGEuZnJhbWUoeD1zZXEoMSwxMDApLCANCiAgICAgICAgICAgICAgICAgeT1ybm9ybSgxMDApLCANCiAgICAgICAgICAgICAgICAgbmFtZT0iTm8gdHJlbmQiKQ0KZDIgPC0gZDEgJT4lIA0KbXV0YXRlKHk9eCoxMCArIHJub3JtKDEwMCxzZD02MCkpICU+JQ0KbXV0YXRlKG5hbWU9IkxpbmVhciByZWxhdGlvbnNoaXAiKQ0KZDMgPC0gZDEgJT4lDQptdXRhdGUoeT14XjIgKyBybm9ybSgxMDAsc2Q9MTQwKSkgJT4lDQptdXRhdGUobmFtZT0iU3F1YXJlIikNCmQ0IDwtIGRhdGEuZnJhbWUoIHg9c2VxKDEsMTAsMC4xKSwgDQogICAgICAgICAgICAgICAgICB5PXNpbihzZXEoMSwxMCwwLjEpKSArIA0KICAgICAgICAgICAgICAgICAgICBybm9ybSg5MSxzZD0wLjYpKSAlPiUgDQptdXRhdGUobmFtZT0iU2luIikNCmRvbiA8LSBkby5jYWxsKHJiaW5kLCBsaXN0KGQxLCBkMiwgZDMsIGQ0KSkNCiMgUGxvdA0KZG9uICU+JQ0KICBnZ3Bsb3QoYWVzKHg9eCwgeT15KSkgKw0KICAgIGdlb21fcG9pbnQoY29sb3I9IiM2OWIzYTIiLCBhbHBoYT0wLjgpICsNCiAgICB0aGVtZV9pcHN1bSgpICsNCiAgICBmYWNldF93cmFwKH5uYW1lLCBzY2FsZT0iZnJlZSIpDQpgYGANCg0KVGFtcGlsYW4geWFuZyBwYWxpbmcgc2VkZXJoYW5hIGRhcmkgMiB2YXJpYWJlbCBrdWFudGl0YXRpZiBhZGFsYWggcGxvdCBzZWJhcmFuLCBkZW5nYW4gc2V0aWFwIHZhcmlhYmVsIGRpd2FraWxrYW4gb2xlaCBzdW1idS4gQ29udG9obnlhLCBtZW5nZ3VuYWthbiBkYXRhc2V0IFNhbGFyaWVzLCBraXRhIGRhcGF0IG1lbXBsb3QgcGVuZ2FsYW1hbiAoeXJzLnNpbmNlLnBoZCkgdnMuIGdhamkgYWthZGVtaWsgKHNhbGFyeSkgZGFyaSBQcm9mZXNvciBwZXJndXJ1YW4gdGluZ2dpLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmRhdGEoU2FsYXJpZXMsIHBhY2thZ2U9ImNhckRhdGEiKQ0KIyBwbG90IHNlYmFyYW4geWFuZyBkaXRpbmdrYXRrYW4NCmdncGxvdChTYWxhcmllcywgDQogICAgICAgYWVzKHggPSB5cnMuc2luY2UucGhkLCANCiAgICAgICAgICAgeSA9IHNhbGFyeSkpICsNCiAgZ2VvbV9wb2ludChjb2xvcj0iY29ybmZsb3dlcmJsdWUiLCANCiAgICAgICAgICAgICBzaXplID0gMiwgDQogICAgICAgICAgICAgYWxwaGE9LjgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVsID0gc2NhbGVzOjpkb2xsYXIsIA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyg1MDAwMCwgMjUwMDAwKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDYwLCAxMCksIA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoMCwgNjApKSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICBsYWJzKHggPSAiWWVhcnMgU2luY2UgUGhEIiwNCiAgICAgICB5ID0gIiIsDQogICAgICAgdGl0bGUgPSAiRXhwZXJpZW5jZSB2cy4gU2FsYXJ5IiwNCiAgICAgICBzdWJ0aXRsZSA9ICI5LW1vbnRoIHNhbGFyeSBmb3IgMjAwOC0yMDA5IikNCmBgYA0KDQojIyMgUGxvdCBTZWJhcmFuIE1lbnllc3VhaWthbiBHYXJpcw0KU2VyaW5na2FsaSBiZXJndW5hIHVudHVrIG1lcmluZ2thcyBodWJ1bmdhbiB5YW5nIGRpdGFtcGlsa2FuIGRhbGFtIHBsb3Qgc2ViYXJhbiwgZGVuZ2FuIG1lbmdndW5ha2FuIHNlYnVhaCBnYXJpcyB5YW5nIG1lbnllc3VhaWthbi4gQmFueWFrIGplbmlzIGdhcmlzIHlhbmcgZGlkdWt1bmcsIHRlcm1hc3VrIGxpbmVhciwgcG9saW5vbWlhbCwgZGFuIG5vbnBhcmFtZXRyaWsgKGxvZXNzKS4gU2VjYXJhIGRlZmF1bHQsIGdhcmlzLWdhcmlzIGluaSBkaXRhbXBsaWthbiBkZW5nYW4gYmF0YXMga2VwZXJjYXlhYW4gOTUlLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZ2dwbG90KFNhbGFyaWVzLA0KICAgICAgIGFlcyh4ID0geXJzLnNpbmNlLnBoZCwgDQogICAgICAgICAgIHkgPSBzYWxhcnkpKSArDQogIGdlb21fcG9pbnQoY29sb3I9ICJjb3JuZmxvd2VyYmx1ZSIpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiYnJvd24xIikrDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbGFicyh4ID0gIlllYXJzIFNpbmNlIFBoRCIsDQogICAgICAgeSA9ICIiLA0KICAgICAgIHRpdGxlID0gIkV4cGVyaWVuY2UgdnMuIFNhbGFyeSIsDQogICAgICAgc3VidGl0bGUgPSAiOS1tb250aCBzYWxhcnkgZm9yIDIwMDgtMjAwOSIpDQpgYGANCg0KSmVsYXMgYmFod2EgZ2FqaSBha2FuIG1lbmluZ2thdCBzZXN1YWkgZGVuZ2FuIHBlbmdhbGFtYW4uIE5hbXVuLCB0YW1wYWtueWEgYWRhIHBlbnVydW5hbiBkaXVqdW5nIGthbmFuIC0gcHJvZmVzb3IgZGVuZ2FuIHBlbmdhbGFtYW4gc2lnbmlmaWthbiwgbWVuZGFwYXRrYW4gZ2FqaSBsZWJpaCByZW5kYWguIEdhcmlzIGx1cnVzIHRpZGFrIGRhcGF0IG1lcmFuZ2thcCBlZmVrIG5vbi1saW5lYXIgaW5pLiBHYXJpcyBkZW5nYW4gbGVuZ2t1bmdhbiBha2FuIGxlYmloIHBhcyBkaSBzaW5pLg0KDQpCaWFzYW55YSBkaWd1bmFrYW4gZ2FyaXMga3VhZHJhdCAoc2F0dSBsZW5na3VuZ2FuKSwgYXRhdSBrdWJpayAoZHVhIGxlbmdrdW5nYW4pLiBQZW5nZ3VuYWFuIHBvbGlub21pYWwgb3JkZSB0aW5nZ2kgKD4zKSBqYXJhbmcgZGlwZXJsdWthbi4gbWVuZXJhcGthbiBrZXNlc3VhaWFuIGt1YWRyYXQga2UgZGF0YSBzZXQgZ2FqaSBtZW5naGFzaWxrYW4gaGFzaWwgc2ViYWdhaSBiZXJpa3V0Lg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgDQpnZ3Bsb3QoU2FsYXJpZXMsIA0KICAgICAgIGFlcyh4ID0geXJzLnNpbmNlLnBoZCwgDQogICAgICAgICAgIHkgPSBzYWxhcnkpKSArDQogIGdlb21fcG9pbnQoY29sb3I9ICJjb3JuZmxvd2VyYmx1ZSIpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgDQogICAgICAgICAgICAgIGZvcm11bGEgPSB5IH4gcG9seSh4LCAyKSwgDQogICAgICAgICAgICAgIGNvbG9yID0gInllbGxvdyIpKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgICAgICAgICAgICAgICAgICAgDQogIGxhYnMoeCA9ICJZZWFycyBTaW5jZSBQaEQiLA0KICAgICAgIHkgPSAiIiwNCiAgICAgICB0aXRsZSA9ICJFeHBlcmllbmNlIHZzLiBTYWxhcnkiLA0KICAgICAgIHN1YnRpdGxlID0gIjktbW9udGggc2FsYXJ5IGZvciAyMDA4LTIwMDkiKQ0KYGBgDQoNCmdhcmlzIGtlc2VzdWFpYW4gbm9ucGFyYW1ldHJpayB5YW5nIGRpcGVyaGFsdXMgc2VyaW5nIGthbGkgZGFwYXQgbWVtYmVyaWthbiBnYW1iYXJhbiB5YW5nIGJhaWsgdGVudGFuZyBodWJ1bmdhbiB0ZXJzZWJ1dC4gRGVmYXVsdCBkaSBnZ3Bsb3QyIGFkYWxhaCBnYXJpcyBsb2VzcyB5YW5nIGJlcmFydGkgcGVuZ2hhbHVzYW4gcGxvdCBzZWJhcmFuIHlhbmcgdGVydGltYmFuZyBzZWNhcmEgbG9rYWwuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpnZ3Bsb3QoU2FsYXJpZXMsIA0KICAgICAgIGFlcyh4ID0geXJzLnNpbmNlLnBoZCwgDQogICAgICAgICAgIHkgPSBzYWxhcnkpKSArDQogIGdlb21fcG9pbnQoY29sb3I9ImNvcm5mbG93ZXJibHVlIiwgDQogICAgICAgICAgICAgc2l6ZSA9IDIsIA0KICAgICAgICAgICAgIGFscGhhID0gMSkgKw0KICBnZW9tX3Ntb290aChzaXplID0gMSwNCiAgICAgICAgICAgICAgY29sb3IgPSAiZ3JlZW4iKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbCA9IHNjYWxlczo6ZG9sbGFyLCANCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoNTAwMDAsIDI1MDAwMCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA2MCwgMTApLCANCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoMCwgNjApKSArDQogIHRoZW1lX21pbmltYWwoKSArICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiAgbGFicyh4ID0gIlllYXJzIFNpbmNlIFBoRCIsDQogICAgICAgeSA9ICIiLA0KICAgICAgIHRpdGxlID0gIkV4cGVyaWVuY2UgdnMuIFNhbGFyeSIsDQogICAgICAgc3VidGl0bGUgPSAiOS1tb250aCBzYWxhcnkgZm9yIDIwMDgtMjAwOSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMgS2F0ZWdvcmlrYWwgdnMuIEtvbnRpbnUNCg0KS2V0aWthIG1lbXBsb3QgaHVidW5nYW4gYW50YXJhIHZhcmlhYmVsIGthdGVnb3Jpa2FsIGRhbiB2YXJpYWJlbCBrdWFudGl0YXRpZiwgdGVyc2VkaWEgYmFueWFrIGplbmlzIGdyYWZpay4gaW5pIHRlcm1hc3VrIGRpYWdyYW0gYmF0YW5nIHlhbmcgbWVuZ2d1bmFrYW4gcmluZ2thc2FuIHN0YXRpc3RpaywgcGxvdCBkZW5zaXRhcyBrZXJuZWwgeWFuZyBkaWtlbG9tcG9ra2FuLCBwbG90IGtvdGFrIGJlcmRhbXBpbmdhbiwgcGxvdCBiaW9sYSBiZXJkYW1waW5nYW4sIHBsb3QgbWVhbi9zZW0sIHBsb3QgZ2FyaXMgcHVuZ2d1bmdhbiwgZGFuIHBsb3QgQ2xldmVsYW5kLg0KDQojIyMgRGlhZ3JhbSBCYXRhbmcgKFJpbmdrYXNhbiBTdGF0aXN0aWspDQoNCkRpIGJhZ2lhbiBzZWJlbHVtbnlhLCBkaWFncmFtIGJhdGFuZyBkaWd1bmFrYW4gdW50dWsgbWVuYW1waWxrYW4ganVtbGFoIGtlamFkaWFuIGJlcmRhc2Fya2FuIGthdGVnb3JpIHVudHVrIHZhcmlhYmVsIHR1bmdnYWwgYXRhdSB1bnR1ayBkdWEgdmFyaWFiZWwuIEFuZGEganVnYSBkYXBhdCBtZW5nZ3VuYWthbiBkaWFncmFtIGJhdGFuZyB1bnR1ayBtZW5hbXBpbGthbiByaW5na2FzYW4gc3RhdGlzdGlrIGxhaW5ueWEgKHNlcGVydGkgbWVhbiBhdGF1IG1lZGlhbikgcGFkYSB2YXJpYWJlbCBrdWFudGl0YXRpZiB1bnR1ayBzZXRpYXAgdGluZ2thdGFuIGRhcmkgdmFyaWFiZWwga2F0ZWdvcmlrYWwuDQoNClNlYmFnYWkgY29udG9oLCBncmFmaWsgYmVyaWt1dCBpbmkgbWVuYW1waWxrYW4gZ2FqaSByYXRhLXJhdGEgdW50dWsgc2FtcGVsIHByb2Zlc29yIHVuaXZlcnNpdGFzIGJlcmRhc2Fya2FuIGphYmF0YW4gYWthZGVtaWsgbWVyZWthLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpICAgICAgICAgIA0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpkYXRhKFNhbGFyaWVzLCBwYWNrYWdlPSJjYXJEYXRhIikNCiMgbWVuZ2hpdHVuZyBnYWppIHJhdGEtcmF0YSB1bnR1ayBzZXRpYXAgamFiYXRhbg0KcGxvdGRhdGEgPC0gU2FsYXJpZXMgJT4lDQogIGdyb3VwX2J5KHJhbmspICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKG1lYW5fc2FsYXJ5ID0gbWVhbihzYWxhcnkpKQ0KIyBwbG90IGdhamkgcmF0YS1yYXRhIGRlbmdhbiBjYXJhIHlhbmcgbGViaWggbWVuYXJpaw0KbXljb2xzIDwtIGMoIiNDRDUzNENGRiIsICIjRUZDMDAwRkYiLCAiIzAwNzNDMkZGIikNCmdncGxvdChwbG90ZGF0YSwgDQogICAgICAgYWVzKHggPSBmYWN0b3IocmFuaywNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBc3Npc3RhbnRcblByb2Zlc3NvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNzb2NpYXRlXG5Qcm9mZXNzb3IiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZ1bGxcblByb2Zlc3NvciIpKSwgDQogICAgICAgICAgICAgICAgICAgICAgeSA9IG1lYW5fc2FsYXJ5KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgDQogICAgICAgICAgIGZpbGwgPSBteWNvbHMpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGRvbGxhcihtZWFuX3NhbGFyeSkpLCANCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMjUpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxMzAwMDAsIDIwMDAwKSwgDQogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGRvbGxhcikgKw0KICB0aGVtZV9taW5pbWFsKCkgKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1lbmdndW5ha2FuIHRlbWEgbWluaW1hbA0KICBsYWJzKHRpdGxlID0gIk1lYW4gU2FsYXJ5IGJ5IFJhbmsiLCANCiAgICAgICBzdWJ0aXRsZSA9ICI5LW1vbnRoIGFjYWRlbWljIHNhbGFyeSBmb3IgMjAwOC0yMDA5IiwNCiAgICAgICB4ID0gIiIsDQogICAgICAgeSA9ICIiKQ0KYGBgDQoNClBsb3QgRGVuc2l0YXMgS2VybmVsIHlhbmcgRGlrZWxvbXBva2thbg0KU2VzZW9yYW5nIGRhcGF0IG1lbWJhbmRpbmdrYW4ga2Vsb21wb2sgcGFkYSB2YXJpYWJlbCBudW1lcmlrIGRlbmdhbiBtZWxhcGlza2FuIHBsb3QgZGVuc2l0YXMga2VybmVsIGRhbGFtIHNhdHUgZ3JhZmlrLiBNYXJpIGtpdGEgcGxvdCBkaXN0cmlidXNpIGdhamkgYmVyZGFzYXJrYW4gamFiYXRhbiBtZW5nZ3VuYWthbiBwbG90IGRlbnNpdGFzIGtlcm5lbC4NCg0KYGBge3J9DQpnZ3Bsb3QoU2FsYXJpZXMsIA0KICAgICAgIGFlcyh4ID0gc2FsYXJ5LCANCiAgICAgICAgICAgZmlsbCA9IHJhbmspKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlNhbGFyeSBkaXN0cmlidXRpb24gYnkgcmFuayIpDQpgYGANCg0KT3BzaSBhbHBoYSBtZW1idWF0IHBsb3QgZGVuc2l0YXMgbWVuamFkaSBzZWJhZ2lhbiB0cmFuc3BhcmFuIHNlaGluZ2dhIGtpdGEgZGFwYXQgbWVsaWhhdCBhcGEgeWFuZyB0ZXJqYWRpIGRpIGJhZ2lhbiB5YW5nIHR1bXBhbmcgdGluZGloLiBOaWxhaSBhbHBoYSBiZXJraXNhciBkYXJpIDAgKHRyYW5zcGFyYW4pIGhpbmdnYSAxIChidXJhbSkuIEdyYWZpayB0ZXJzZWJ1dCBtZW5qZWxhc2thbiBiYWh3YSwgc2VjYXJhIHVtdW0sIGdhamkgYWthbiBtZW5pbmdrYXQgc2VzdWFpIGphYmF0YW4uIE5hbXVuLCBraXNhcmFuIGdhamkgdW50dWsgZnVsbCBwcm9mZXNvciBzYW5nYXQgbHVhcy4NCg0KIyMjIEJveHBsb3QgDQoNClBsb3QgS290YWsgKEJveHBsb3QpIG1lbmFtcGlsa2FuIHBlcnNlbnRpbCBrZS0yNSwgbWVkaWFuLCBkYW4gcGVyc2VudGlsIGtlLTc1IGRhcmkgZGlzdHJpYnVzaS4gUGxvdCBLb3RhayBiZXJkYW1waW5nYW4gc2FuZ2F0IGJlcmd1bmEgdW50dWsgbWVtYmFuZGluZ2thbiBrZWxvbXBvayBwYWRhIHZhcmlhYmVsIG51bWVyaWsuIE1hcmkga2l0YSBwbG90IGRpc3RyaWJ1c2kgZ2FqaSBiZXJkYXNhcmthbiBqYWJhdGFuIG1lbmdndW5ha2FuIHBsb3Qga290YWsuIFBsb3Qga290YWsgYmVydGFraWsgbWVtYmVyaWthbiBtZXRvZGUgcGVya2lyYWFuIHVudHVrIHZpc3VhbGlzYXNpIGFwYWthaCBrZWxvbXBvayBiZXJiZWRhLiBNZXNraXB1biBidWthbiBzZWJ1YWggdGVzIHlhbmcgZm9ybWFsLCBqaWthIHRha2lrIGRhcmkga2VkdWEgcGxvdCBrb3RhayB0aWRhayBydW1wYW5nIHRpbmRpaCwgbWFrYSBhZGEgYnVrdGkga3VhdCBiYWh3YSBtZWRpYW4gZGFyaSBrZWR1YSBrZWxvbXBvayBiZXJiZWRhLg0KDQpgYGB7cn0NCm15Y29scyA8LSBjKCIjQ0Q1MzRDRkYiLCAiI0VGQzAwMEZGIiwgIiMwMDczQzJGRiIpDQpnZ3Bsb3QoU2FsYXJpZXMsIGFlcyh4ID0gcmFuaywgDQogICAgICAgICAgICAgICAgICAgICB5ID0gc2FsYXJ5KSkgKw0KICBnZW9tX2JveHBsb3Qobm90Y2ggPSBUUlVFLCANCiAgICAgICAgICAgICAgIGZpbGwgPSBteWNvbHMsIA0KICAgICAgICAgICAgICAgYWxwaGEgPSAuNykgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlNhbGFyeSBEaXN0cmlidXRpb24gYnkgcmFuayIpDQpgYGANCkRhbGFtIGNvbnRvaCBkaSBhdGFzLCBrZXRpZ2Ega2Vsb21wb2sgaXR1IHRhbXBhayBiZXJiZWRhLiBTYWxhaCBzYXR1IGtldW50dW5nYW4gZGFyaSBwbG90IGtvdGFrIGFkYWxhaCBsZWJhcm55YSBiaWFzYW55YSB0aWRhayBiZXJhcnRpLiBJbmkgbWVtdW5na2lua2FuIEFuZGEgdW50dWsgbWVtYmFuZGluZ2thbiBkaXN0cmlidXNpIGRhcmkgYmFueWFrIGtlbG9tcG9rIGRhbGFtIHNhdHUgZ3JhZmlrLg0KDQoNCiMjIyBQbG90IEJpb2xhDQoNClBsb3QgQmlvbGEgbWlyaXAgZGVuZ2FuIHBsb3QgZGVuc2l0YXMga2VybmVsIHRldGFwaSBkaWNlcm1pbmthbiBkYW4gZGlwdXRhciA5MDA5MDAuIE1hcmkga2l0YSBwbG90IGRpc3RyaWJ1c2kgZ2FqaSBiZXJkYXNhcmthbiBqYWJhdGFuIG1lbmdndW5ha2FuIHBsb3QgYmlvbGEuDQoNCmBgYHtyfQ0KZ2dwbG90KFNhbGFyaWVzLCANCiAgICAgICBhZXMoeCA9IHJhbmssIA0KICAgICAgICAgICB5ID0gc2FsYXJ5KSkgKw0KICBnZW9tX3Zpb2xpbihmaWxsID0gImF6dXJlMSIpICsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoID0gLjIsIA0KICAgICAgICAgICAgICAgZmlsbCA9IG15Y29scywNCiAgICAgICAgICAgICAgIG91dGxpZXIuY29sb3IgPSAicmVkIiwNCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZSA9IDIpICsgDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiU2FsYXJ5IGRpc3RyaWJ1dGlvbiBieSByYW5rIikNCg0KYGBgDQoNCiMjIyBQbG90IEdhcmlzIFB1bmdndW5nDQoNClBsb3QgZ2FyaXMgcHVuZ2d1bmcgKGp1Z2EgZGlzZWJ1dCBwbG90IGtlZ2VtYmlyYWFuKSBtZW5hbXBpbGthbiBkaXN0cmlidXNpIHZhcmlhYmVsIGt1YW50aXRhdGlmIHVudHVrIGJlYmVyYXBhIGtlbG9tcG9rLiBNZXJla2EgbWlyaXAgZGVuZ2FuIHBsb3QgZGVuc2l0YXMga2VybmVsIGRhcmkgc2VnaSAoZmFjZXRpbmcpIHZlcnRpa2FsLCB0ZXRhcGkgbWVtYWthbiBsZWJpaCBzZWRpa2l0IHJ1YW5nLiBQbG90IGdhcmlzIHB1bmdndW5nIGRpYnVhdCBkZW5nYW4gcGFja2FnZSBnZ3JpZGdlcy4NCg0KTWVuZ2d1bmFrYW4gZGF0YSBzZXQgRnVlbCBlY29ub215LCBtYXJpIGtpdGEgcGxvdCBtaWwgcGVyamFsYW5hbiBrb3RhIHBlciBnYWxvbiBtZW51cnV0IGtlbGFzIG1vYmlsLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpICAgICAgICAgICAgDQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICANCmxpYnJhcnkoZ2dyaWRnZXMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmdncGxvdChtcGcsIA0KICAgICAgIGFlcyh4ID0gY3R5LCANCiAgICAgICAgICAgeSA9IGNsYXNzLCANCiAgICAgICAgICAgZmlsbCA9IGNsYXNzKSkgKw0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFscGhhID0gMC43KSArIA0KICB0aGVtZV9yaWRnZXMoKSArDQogIGxhYnMoIkhpZ2h3YXkgbWlsZWFnZSBieSBhdXRvIGNsYXNzIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCmBgYA0KDQpQZXJoYXRpa2FuIGtlbXVuZ2tpbmFuIHR1bXBhbmcgdGluZGloIGRpc3RyaWJ1c2kgYWRhbGFoIGRpcHV0dXNrYW4gbGViaWgga2VwYWRhIGdyYWZpayBtb2JpbCBrb21wYWsuIEFuZGEgZGFwYXQgbWVuYW1iYWhrYW4gdHJhbnNwYXJhbnNpIGppa2EgdHVtcGFuZyB0aW5kaWhueWEgcGFyYWgsIGRlbmdhbiBtZW5nZ3VuYWthbiBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFscGhhID0gbiksIGRpbWFuYSBuIGJlcmtpc2FyIGRhcmkgMCAodHJhbnNwYXJhbikgaGluZ2dhIDEgKGJ1cmFtKS4gTGloYXQgcGFja2FnZSB2aWduZXR0ZSB1bnR1ayBsZWJpaCBqZWxhc255YS4NCg0KIyMjIFBsb3QgDQoNCk1ldG9kZSBwb3B1bGVyIHVudHVrIG1lbWJhbmRpbmdrYW4ga2Vsb21wb2sgcGFkYSB2YXJpYWJlbCBudW1lcmlrIGFkYWxhaCBwbG90IHJhdGEtcmF0YSBkZW5nYW4gYmF0YW5nIGtlc2FsYWhhbi4gQmF0YW5nIGtlc2FsYWhhbiBkYXBhdCBtZXdha2lsa2FuIGRldmlhc2kgc3RhbmRhciwga2VzYWxhaGFuIHN0YW5kYXIgZGFyaSByYXRhLXJhdGEsIGF0YXUgaW50ZXJ2YWwga2VwZXJjYXlhYW4uIFBhZGEgYmFnaWFuIGluaSwga2l0YSBha2FuIHBsb3QgcmF0YS1yYXRhIGRhbiBrZXNhbGFoYW4gc3RhbmRhci4gS2l0YSBkYXBhdCBtZW5nZ3VuYWthbiB0ZWtuaWsgeWFuZyBzYW1hIHVudHVrIG1lbWJhbmRpbmdrYW4gZ2FqaSB0ZXJoYWRhcCBqYWJhdGFuIGRhbiBqZW5pcyBrZWxhbWluLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoZ2dyaWRnZXMpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCiMgbWVuZ2hpdHVuZyByYXRhLXJhdGEsIGRldmlhc2kgc3RhbmRhciwNCiMga2VzYWxhaGFuIHN0YW5kYXIsIGRhbiA5NSUgaW50ZXJ2YWwga2VwZXJjYXlhYW4gDQojIGJlcmRhc2Fya2FuIGphYmF0YW4NCnBsb3RkYXRhIDwtIFNhbGFyaWVzICU+JQ0KICBncm91cF9ieShyYW5rLCBzZXgpICU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKG4gPSBuKCksDQogICAgICAgICAgICBtZWFuID0gbWVhbihzYWxhcnkpLA0KICAgICAgICAgICAgc2QgPSBzZChzYWxhcnkpLA0KICAgICAgICAgICAgc2UgPSBzZC9zcXJ0KG4pLA0KICAgICAgICAgICAgY2kgPSBxdCgwLjk3NSwgZGYgPSBuIC0gMSkgKiBzZCAvIHNxcnQobikpDQojIG1lbmluZ2thdGthbiBwbG90IHJhdGEtcmF0YSBrZXNhbGFoYW4gYXRhdSBzdGFuZGFyIGtlc2FsYWhhbg0KcGQgPC0gcG9zaXRpb25fZG9kZ2UoMC4yKQ0KZ2dwbG90KHBsb3RkYXRhLCANCiAgICAgICBhZXMoeCA9IGZhY3RvcihyYW5rLCANCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBc3Npc3RhbnRcblByb2Zlc3NvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNzb2NpYXRlXG5Qcm9mZXNzb3IiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZ1bGxcblByb2Zlc3NvciIpKSwgDQogICAgICAgICAgIHkgPSBtZWFuLCANCiAgICAgICAgICAgZ3JvdXA9c2V4LCANCiAgICAgICAgICAgY29sb3I9c2V4KSkgKw0KICBnZW9tX3BvaW50KHBvc2l0aW9uPXBkLCANCiAgICAgICAgICAgICBzaXplID0gMykgKw0KICBnZW9tX2xpbmUocG9zaXRpb24gPSBwZCwgDQogICAgICAgICAgICBzaXplID0gMSkgKw0KICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbWVhbiAtIHNlLCANCiAgICAgICAgICAgICAgICAgICAgeW1heCA9IG1lYW4gKyBzZSksIA0KICAgICAgICAgICAgICAgIHdpZHRoID0gLjEsIA0KICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcGQsIA0KICAgICAgICAgICAgICAgIHNpemUgPSAxKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbCA9IHNjYWxlczo6ZG9sbGFyKSArDQogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJTZXQxIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIk1lYW4gc2FsYXJ5IGJ5IHJhbmsgYW5kIHNleCIsDQogICAgICAgc3VidGl0bGUgPSAiKG1lYW4gKy8tIHN0YW5kYXJkIGVycm9yKSIsDQogICAgICAgeCA9ICIiLCANCiAgICAgICB5ID0gIiIsDQogICAgICAgY29sb3IgPSAiR2VuZGVyIikNCg0KYGBgDQoNCiMjIyBQbG90IFN0cmlwDQoNCkh1YnVuZ2FuIGFudGFyYSB2YXJpYWJlbCBwZW5nZWxvbXBva2FuIGRhbiB2YXJpYWJlbCBudW1lcmlrIGRhcGF0IGRpdGFtcGlsa2FuIGRlbmdhbiBwbG90IHNlYmFyYW4uIENvbnRvaCwgcGxvdCBkaXN0cmlidXNpIGdhamkgYmVyZGFzYXJrYW4gamFiYXRhbiBtZW5nZ3VuYWthbiBwbG90IHN0cmlwLiBQbG90IHNlYmFyIHNhdHUgZGltZW5zaSBpbmkgZGlzZWJ1dCBzZWJhZ2FpIHBsb3Qgc3RyaXAuIFNheWFuZ255YSwgcGVuY2V0YWthbiB0aXRpayB5YW5nIGJlcmxlYmloYW4gbWVtYnVhdCBpbnRlcnByZXRhc2lueWEgbWVuamFkaSBzdWxpdC4gDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICANCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgICAgIA0KZ2dwbG90KFNhbGFyaWVzLCANCiAgICAgICBhZXMoeSA9IGZhY3RvcihyYW5rLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFzc2lzdGFudFxuUHJvZmVzc29yIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc3NvY2lhdGVcblByb2Zlc3NvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRnVsbFxuUHJvZmVzc29yIikpLCANCiAgICAgICAgICAgeCA9IHNhbGFyeSwgDQogICAgICAgICAgIGNvbG9yID0gcmFuaykpICsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjcsDQogICAgICAgICAgICAgIHNpemUgPSAxLjUpICsgDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbCA9IGRvbGxhcikgKw0KICBsYWJzKHRpdGxlID0gIkFjYWRlbWljIFNhbGFyeSBieSBSYW5rIiwgDQogICAgICAgc3VidGl0bGUgPSAiOS1tb250aCBzYWxhcnkgZm9yIDIwMDgtMjAwOSIsDQogICAgICAgeCA9ICIiLA0KICAgICAgIHkgPSAiIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpgYGANCk9wc2kgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiIGRpZ3VuYWthbiB1bnR1ayBtZW55ZW1idW55aWthbiBsZWdlbmQgKHlhbmcgdGlkYWsgZGlwZXJsdWthbiBkaSBzaW5pKS4gUGxvdCBqaXR0ZXIgYmVrZXJqYSBkZW5nYW4gYmFpayBrZXRpa2EganVtbGFoIGRhcmkgdGl0aWstdGl0aWsgdGlkYWsgdGVybGFsdSBiZXNhci4NCg0KIyMjIE1lbmdnYWJ1bmdrYW4gSml0dGVyIGRhbiBQbG90IEtvdGFrDQoNCk11bmdraW4gbGViaWggbXVkYWggdW50dWsgbWVtdmlzdWFsaXNhc2lrYW4gZGlzdHJpYnVzaSBqaWthIGtpdGEgbWVuYW1iYWhrYW4gcGxvdCBrb3RhayBrZSBwbG90IGppdHRlci4gQmViZXJhcGEgcGlsaWhhbiBkaXRhbWJhaGthbiB1bnR1ayBtZW1idWF0IHBsb3QgaW5pLg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICANCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgICAgICANCmdncGxvdChTYWxhcmllcywgDQogICAgICAgYWVzKHggPSBmYWN0b3IocmFuaywNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBc3Npc3RhbnRcblByb2Zlc3NvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXNzb2NpYXRlXG5Qcm9mZXNzb3IiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZ1bGxcblByb2Zlc3NvciIpKSwgDQogICAgICAgICAgIHkgPSBzYWxhcnksIA0KICAgICAgICAgICBjb2xvciA9IHJhbmspKSArDQogIGdlb21fYm94cGxvdChzaXplPTEsDQogICAgICAgICAgICAgICBvdXRsaWVyLnNoYXBlID0gMSwNCiAgICAgICAgICAgICAgIG91dGxpZXIuY29sb3IgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgb3V0bGllci5zaXplICA9IDMpICsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjUsIA0KICAgICAgICAgICAgICB3aWR0aD0uMikgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVsID0gZG9sbGFyKSArDQogIGxhYnModGl0bGUgPSAiQWNhZGVtaWMgU2FsYXJ5IGJ5IFJhbmsiLCANCiAgICAgICBzdWJ0aXRsZSA9ICI5LW1vbnRoIHNhbGFyeSBmb3IgMjAwOC0yMDA5IiwNCiAgICAgICB4ID0gIiIsDQogICAgICAgeSA9ICIiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQpTZWJlbHVtIG1lbGFuanV0a2FuLCBhZGEgYmFpa255YSB1bnR1ayBtZW1lcmhhdGlrYW4gZnVuZ3NpIGdlb21fYm94aml0dGVyIHlhbmcgZGlzZWRpYWthbiBkYWxhbSBwYWNrYWdlIGdncG9sLiBJbmkgbWVtYnVhdCBwbG90IGtvdGFrIGhpYnJpZGEgLSBzZXRlbmdhaCBwbG90IGtvdGFrLCBzZXRlbmdhbiBwbG90IHNlYmFyYW4uDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoc2NhbGVzKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgDQpsaWJyYXJ5KGdncG9sKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZ2dwbG90KFNhbGFyaWVzLCANCiAgICAgICBhZXMoeCA9IGZhY3RvcihyYW5rLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFzc2lzdGFudFxuUHJvZmVzc29yIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBc3NvY2lhdGVcblByb2Zlc3NvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRnVsbFxuUHJvZmVzc29yIikpLCANCiAgICAgICAgICAgeSA9IHNhbGFyeSwgDQogICAgICAgICAgIGZpbGw9cmFuaykpICsNCiAgZ2VvbV9ib3hqaXR0ZXIoY29sb3I9ImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgaml0dGVyLmNvbG9yID0gImRhcmtncmV5IiwNCiAgICAgICAgICAgICAgICAgZXJyb3JiYXIuZHJhdyA9IFRSVUUpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVsID0gZG9sbGFyKSArDQogIGxhYnModGl0bGUgPSAiQWNhZGVtaWMgU2FsYXJ5IGJ5IFJhbmsiLCANCiAgICAgICBzdWJ0aXRsZSA9ICI5LW1vbnRoIHNhbGFyeSBmb3IgMjAwOC0yMDA5IiwNCiAgICAgICB4ID0gIiIsDQogICAgICAgeSA9ICIiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQoNCiMjIyBQbG90IEthd2FuYW4gTGViYWgNCg0KUGxvdCBrYXdhbmFuIGxlYmFoIChqdWdhIGRpc2VidXQgcGxvdCBzZWJhcmFuIGJpb2xhKSBtaXJpcCBkZW5nYW4gcGxvdCBzZWJhcmFuIGppdHRlciwgZGkgbWFuYSBwbG90IHRlcnNlYnV0IG1lbmFtcGlsa2FuIGRpc3RyaWJ1c2kgZGFyaSB2YXJpYWJlbCBrdWFudGl0YXRpZiBkZW5nYW4gbWVtcGxvdCB0aXRpay10aXRpayBkZW5nYW4gY2FyYSBtZW5ndXJhbmdpIHR1bXBhbmcgdGluZGloLiBTZWxhaW4gaXR1LCBtZXJla2EganVnYSBtZW1iYW50dSBtZW5hbXBpbGthbiBkZW5zaXRhcyBkYXJpIGRhdGEgZGkgc2V0aWFwIHRpdGlrIChkZW5nYW4gY2FyYSB5YW5nIG1pcmlwIGRlbmdhbiBwbG90IGJpb2xhKS4gTWVsYW5qdXRrYW4gY29udG9oIHNlYmVsdW1ueWEuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICAgICAgICAgIA0KbGlicmFyeShnZ2JlZXN3YXJtKSAgICAgICAgICAgICAgDQpnZ3Bsb3QoU2FsYXJpZXMsIA0KICAgICAgIGFlcyh4ID0gZmFjdG9yKHJhbmssDQogICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQXNzaXN0YW50XG5Qcm9mZXNzb3IiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFzc29jaWF0ZVxuUHJvZmVzc29yIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGdWxsXG5Qcm9mZXNzb3IiKSksIA0KICAgICAgICAgICB5ID0gc2FsYXJ5LCANCiAgICAgICAgICAgY29sb3IgPSByYW5rKSkgKw0KICBnZW9tX3F1YXNpcmFuZG9tKGFscGhhID0gMC43LA0KICAgICAgICAgICAgICAgICAgIHNpemUgPSAxLjUpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbCA9IGRvbGxhcikgKw0KICBsYWJzKHRpdGxlID0gIkFjYWRlbWljIFNhbGFyeSBieSBSYW5rIiwgDQogICAgICAgc3VidGl0bGUgPSAiOS1tb250aCBzYWxhcnkgZm9yIDIwMDgtMjAwOSIsDQogICAgICAgeCA9ICIiLA0KICAgICAgIHkgPSAiIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCmBgYA0KDQpQbG90IGRpYnVhdCBtZW5nZ3VuYWthbiBmdW5nc2kgZ2VvbV9xdWFzaXJhbmRvbS4gUGxvdCBpbmkgZGFwYXQgbGViaWggbXVkYWggZGliYWNhIGRhcmlwYWRhIHBsb3Qgc3RyaXAgaml0dGVyIHNlZGVyaGFuYS4gVW50dWsgbWVtcGVsYWphcmkgbGViaWggbGFuanV0IG1lbmdlbmFpIHBsb3QgaW5pLCBsaWhhdCBQbG90IGJlcmdheWEga2F3YW5hbiBsZWJhaCBkZW5nYW4gZ2dwbG90Mi4NCg0KIyMjIERpYWdyYW0gVGl0aWsgQ2xldmVsYW5kIA0KDQpQbG90IENsZXZlbGFuZCBiZXJndW5hIGtldGlrYSBBbmRhIGluZ2luIG1lbWJhbmRpbmdrYW4gc3RhdGlzdGlrIG51bWVyaWsgdW50dWsgc2VqdW1sYWggYmVzYXIga2Vsb21wb2suIE1pc2FsbnlhLCBBbmRhIGluZ2luIG1lbWJhbmRpbmdrYW4gaGFyYXBhbiBoaWR1cCB0YWh1biAyMDA3IHVudHVrIG5lZ2FyYSBBc2lhIG1lbmdndW5ha2FuIGRhdGEgc2V0IGdhcG1pbmRlci4NCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKSAgIA0KbGlicmFyeShnZ3Bsb3QyKSAgIA0KbGlicmFyeShzY2FsZXMpICAgICAgICAgIA0KbGlicmFyeShnZ2JlZXN3YXJtKSAgICAgICAgIA0KbGlicmFyeShnYXBtaW5kZXIpICAgICAgICAgICANCmRhdGEoZ2FwbWluZGVyLCBwYWNrYWdlPSJnYXBtaW5kZXIiKSAgICAgICAgICAgICAgICAgIyBtZW11YXQgZGF0YXNldCBgZ2FwbWluZGVyYCANCiMgc3Vic2V0IG5lZ2FyYS1uZWdhcmEgQXNpYW4gdGFodW4gMjAwNw0KbGlicmFyeShkcGx5cikNCnBsb3RkYXRhIDwtIGdhcG1pbmRlciAlPiUNCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAiQXNpYSIgJiANCiAgICAgICAgIHllYXIgPT0gMjAwNykNCiMgUGxvdCBDbGV2ZWxhbmQgeWFuZyBtZW5hcmlrDQpnZ3Bsb3QocGxvdGRhdGEsIA0KICAgICAgIGFlcyh4PWxpZmVFeHAsIA0KICAgICAgICAgICB5PXJlb3JkZXIoY291bnRyeSwgbGlmZUV4cCkpKSArDQogIGdlb21fcG9pbnQoY29sb3I9ImJsdWUiLCANCiAgICAgICAgICAgICBzaXplID0gMikgKw0KICBnZW9tX3NlZ21lbnQoYWVzKHggPSA0MCwgDQogICAgICAgICAgICAgICB4ZW5kID0gbGlmZUV4cCwgDQogICAgICAgICAgICAgICB5ID0gcmVvcmRlcihjb3VudHJ5LCBsaWZlRXhwKSwgDQogICAgICAgICAgICAgICB5ZW5kID0gcmVvcmRlcihjb3VudHJ5LCBsaWZlRXhwKSksDQogICAgICAgICAgICAgICBjb2xvciA9ICJhenVyZTMiKSArDQogIGxhYnMgKHggPSAiTGlmZSBFeHBlY3RhbmN5ICh5ZWFycykiLA0KICAgICAgICB5ID0gIiIsDQogICAgICAgIHRpdGxlID0gIkxpZmUgRXhwZWN0YW5jeSBieSBDb3VudHJ5IiwNCiAgICAgICAgc3VidGl0bGUgPSAiR2FwTWluZGVyIGRhdGEgZm9yIEFzaWEgLSAyMDA3IikgKw0KICB0aGVtZV9taW5pbWFsKCkgKyANCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQpKZXBhbmcgamVsYXMgbWVtaWxpa2kgYW5na2EgaGFyYXBhbiBoaWR1cCB5YW5nIHBhbGluZyB0aW5nZ2ksIHNlZGFuZ2thbiBBZmdoYW5pc3RhbiBzZWphdWggaW5pIHlhbmcgcGFsaW5nIHJlbmRhaC4gUGxvdCB0ZXJha2hpciBpbmkgZGlzZWJ1dCBqdWdhIGRlbmdhbiBncmFmaWsgbG9saXBvcC4NCg0KIyBEYXRhIE11bHRpdmFyaWF0DQoNCkdyYWZpayBNdWx0aXZhcmlhdCBtZW5hbXBpbGthbiBodWJ1bmdhbiBhbnRhcmEgdGlnYSB2YXJpYWJlbCBhdGF1IGxlYmloLiBBZGEgZHVhIG1ldG9kZSB1bXVtIHVudHVrIG1lbmFtcHVuZyB2YXJpYWJlbDogcGVuZ2Vsb21wb2thbiBkYW4gZmFjZXRpbmcuDQoNCiMjUGVuZ2Vsb21wb2thbg0KDQpEYWxhbSBwZW5nZWxvbXBva2FuLCBuaWxhaSBkYXJpIGR1YSB2YXJpYWJlbCBwZXJ0YW1hIGRpcGV0YWthbiBrZSBzdW1idSB4IGRhbiB5LiBLZW11ZGlhbiB2YXJpYWJlbCB0YW1iYWhhbiBkaXBldGFrYW4ga2Uga2FyYWt0ZXJpc3RpayB2aXN1YWwgbGFpbm55YSBzZXBlcnRpIHdhcm5hLCBiZW50dWssIHVrdXJhbiwgamVuaXMgZ2FyaXMsIGRhbiB0cmFuc3BhcmFuc2kuIFBlbmdlbG9tcG9rYW4gbWVtdW5na2lua2FuIEFuZGEgdW50dWsgbWVtcGxvdCBkYXRhIHVudHVrIGJlYmVyYXBhIGdydXAgZGFsYW0gc2F0dSBncmFmaWsuIERlbmdhbiBtZW5nZ3VuYWthbiBkYXRhIHNldCBTYWxhcmllcywgbWFyaSBraXRhIHRhbXBpbGthbiBodWJ1bmdhbiBhbnRhcmEgeXJzLnNpbmNlLnBoZCBkYW4gc2FsYXJ5Lg0KDQpgYGB7cn0NCmxpYnJhcnkoY2FyRGF0YSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KZGF0YShTYWxhcmllcywgcGFja2FnZT0iY2FyRGF0YSIpDQpnZ3Bsb3QoU2FsYXJpZXMsIGFlcyh4ID0geXJzLnNpbmNlLnBoZCwgDQogICAgICAgICAgICAgICAgICAgICB5ID0gc2FsYXJ5LCANCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yPXJhbmspKSArDQogIGdlb21fcG9pbnQoKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiQWNhZGVtaWMgc2FsYXJ5IGJ5IHJhbmsgYW5kIHllYXJzIHNpbmNlIGRlZ3JlZSIpDQpgYGANCg0KU2VsYW5qdXRueWEsIHRhbWJhaGthbiBqZW5pcyBrZWxhbWluIHByb2Zlc29yLCBtZW5nZ3VuYWthbiBiZW50dWsgdGl0aWsgdW50dWsgbWVudW5qdWtrYW4gamVuaXMga2VsYW1pbi4gS2l0YSBha2FuIG1lbmluZ2thdGthbiB1a3VyYW4gdGl0aWsgZGFuIG1lbmFtYmFoa2FuIHRyYW5zcGFyYW5zaSB1bnR1ayBtZW1wZXJqZWxhcyB0aXRpayBpbmRpdmlkdWFsLg0KDQpgYGB7cn0NCmxpYnJhcnkoY2FyRGF0YSkgICAgICAgICAgICAgICAgICAgICAgIA0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICANCmdncGxvdChTYWxhcmllcywgDQogICAgICAgYWVzKHggPSB5cnMuc2luY2UucGhkLCANCiAgICAgICAgICAgeSA9IHNhbGFyeSwgDQogICAgICAgICAgIGNvbG9yID0gcmFuaywgDQogICAgICAgICAgIHNoYXBlID0gc2V4KSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzLCBhbHBoYSA9IC42KSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiQWNhZGVtaWMgc2FsYXJ5IGJ5IHJhbmssIHNleCwgYW5kIHllYXJzIHNpbmNlIGRlZ3JlZSIpDQpgYGANCg0KQmVyaWt1dCBhZGFsYWggY29udG9oIHlhbmcgbGViaWggamVsYXMuIEtpdGEgYWthbiBtZW1idWF0IGdyYWZpayBodWJ1bmdhbiBhbnRhciB0YWh1biBzZWphayBQaC5ELiBkYW4gZ2FqaSBtZW5nZ3VuYWthbiB1a3VyYW4gZGFyaSB0aXRpayB1bnR1ayBtZW51bmp1a2thbiBtYXNhIGtlcmphLiBJbmkgZGlzZWJ1dCBwbG90IGdlbGVtYnVuZy4NCg0KYGBge3J9DQpsaWJyYXJ5KGNhckRhdGEpICANCmxpYnJhcnkoZ2dwbG90MikgIA0KZ2dwbG90KFNhbGFyaWVzLCANCiAgICAgICBhZXMoeCA9IHlycy5zaW5jZS5waGQsIA0KICAgICAgICAgICB5ID0gc2FsYXJ5LCANCiAgICAgICAgICAgY29sb3IgPSByYW5rLCANCiAgICAgICAgICAgc2l6ZSA9IHlycy5zZXJ2aWNlKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gLjgpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJBY2FkZW1pYyBzYWxhcnkgYnkgcmFuaywgeWVhcnMgb2Ygc2VydmljZSwgYW5kIHllYXJzIHNpbmNlIGRlZ3JlZSIpDQpgYGANCg0KSmVsYXMgc2VrYWxpIGFkYSBodWJ1bmdhbiBwb3NpdGlmIHlhbmcga3VhdCBhbnRhcmEgdGFodW4tdGFodW4gc2VqYWsgUGguRC4gZGFuIHRhaHVuIGxheWFuYW4uIEFzaXN0ZW4gUHJvZmVzb3IgYWRhIGRhbGFtIGphbmdrYXVhbiAwLTExIHRhaHVuIHNlamFrIFBoLkQuIGRhbiAwLTEwIHRhaHVuIGxheWFuYW4uIEtpdGEgdGlkYWsgbWVuZW11a2FuIGJhdGFzYW4gd2FrdHUgeWFuZyBzYW1hIGFudGFyYSBBc3NvY2lhdGUgZGFuIEZ1bGwgUHJvZmVzc29ycy4gDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKSAgICAgICAgICAgICAgICAgICANCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgICAgICAgICAgDQpnZ3Bsb3QoU2FsYXJpZXMsIA0KICAgICAgIGFlcyh4ID0geXJzLnNpbmNlLnBoZCwgDQogICAgICAgICAgIHkgPSBzYWxhcnksIA0KICAgICAgICAgICBjb2xvciA9IHNleCkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IC40LCANCiAgICAgICAgICAgICBzaXplID0gMykgKw0KICBnZW9tX3Ntb290aChzZT1GQUxTRSwgDQogICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIsIA0KICAgICAgICAgICAgICBmb3JtdWxhID0geX5wb2x5KHgsMiksIA0KICAgICAgICAgICAgICBzaXplID0gMS41KSArDQogIGxhYnMoeCA9ICJZZWFycyBTaW5jZSBQaC5ELiIsDQogICAgICAgdGl0bGUgPSAiQWNhZGVtaWMgU2FsYXJ5IGJ5IFNleCBhbmQgWWVhcnMgRXhwZXJpZW5jZSIsDQogICAgICAgc3VidGl0bGUgPSAiOS1tb250aCBzYWxhcnkgZm9yIDIwMDgtMjAwOSIsDQogICAgICAgeSA9ICIiLA0KICAgICAgIGNvbG9yID0gIlNleCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVsID0gc2NhbGVzOjpkb2xsYXIpICsNCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMgUGVtYmFnaWFuIEZhc2V0IChGYWNldGluZykNCg0KUGVuZ2Vsb21wb2thbiBtZW11bmdraW5rYW4gQW5kYSB1bnR1ayBtZW1wbG90IGJlYmVyYXBhIHZhcmlhYmVsIGRhbGFtIHNhdHUgZ3JhZmlrLCBtZW5nZ3VuYWthbiBrYXJha3RlcmlzdGlrIHZpc3VhbCBzZXBlcnRpLCB3YXJuYSwgYmVudHVrLCBkYW4gdWt1cmFuLiBEYWxhbSBwZW1iYWdpYW4gZmFzZXQsIHNlYnVhaCBncmFmaWsgdGVyZGlyaSBkYXJpIGJlYmVyYXBhIHBsb3QtcGxvdCB0ZXJwaXNhaCBhdGF1IGtlbGlwYXRhbiBrZWNpbCwgc2F0dSB1bnR1ayBzZXRpYXAgdGluZ2thdGFuIGRhcmkgdmFyaWFiZWwga2V0aWdhLCBhdGF1IGtvbWJpbmFzaSB2YXJpYWJlbC4gSW5pIGFrYW4gbGViaWggbXVkYWggZGlwYWhhbWkgZGVuZ2FuIHNlYnVhaCBjb250b2guDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKSAgICAgICAgICANCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICANCmdncGxvdChTYWxhcmllcywgYWVzKHggPSBzYWxhcnkpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAiY29ybmZsb3dlcmJsdWUiLA0KICAgICAgICAgICAgICAgICBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgZmFjZXRfd3JhcCh+cmFuaywgbmNvbCA9IDEpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJTYWxhcnkgaGlzdG9ncmFtcyBieSByYW5rIikNCmBgYA0KDQpGdW5nc2kgZmFjZXRfd3JhcCBtZW1idWF0IGdyYWZpayB0ZXJwaXNhaCB1bnR1ayBzZXRpYXAgdGluZ2thdCBqYWJhcmFuLiBPcHNpIG5jb2wgbWVuZ2F0dXIganVtbGFoIGtvbG9tLiBEYWxhbSBjb250b2ggYmVyaWt1dG55YSBha2FuIG1lbmdndW5ha2FuIGR1YSB2YXJpYWJlbCB1bnR1ayBtZW5kZWZpbmlzaWthbiBmYXNldC4gRGkgc2luaSwgZnVuZ3NpIG1lbmV0YXBrYW4gamVuaXMga2VsYW1pbiBrZSBiYXJpcyBkYW4gamFiYXRhbiBrZSBrb2xvbSwgbWVtYnVhdCBtYXRyaWtzIGVuYW0gcGxvdCBkYWxhbSBzYXR1IGdyYWZpay4NCg0KYGBge3J9DQpsaWJyYXJ5KGNhckRhdGEpICAgICAgDQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICANCmdncGxvdChTYWxhcmllcywgYWVzKHggPSBzYWxhcnkgLyAxMDAwKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShjb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgICAgICAgIGZpbGwgPSAiY29ybmZsb3dlcmJsdWUiKSArDQogIGZhY2V0X2dyaWQoc2V4IH4gcmFuaykgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlNhbGFyeSBoaXN0b2dyYW1zIGJ5IHNleCBhbmQgcmFuayIsDQogICAgICAgeCA9ICJTYWxhcnkgKCQxMDAwKSIpDQpgYGANCg0KS2l0YSBqdWdhIGRhcGF0IG1lbmdrb21iaW5hc2kgcGVuZ2Vsb21wb2thbiBkYW4gcGVtYmFnaWFuIGZhc2V0LiAgS2l0YSBha2FuIG1lbmdndW5ha2FuIHdhcm5hIHVudHVrIG1lbWJlZGFrYW4gamVuaXMga2VsYW1pbiBkYW4gcGVtYmFnaWFuIGZhc2V0IHVudHVrIG1lbWJ1YXQgcGxvdCBqYWJhdGFuIGJlcmRhc2Fya2FuIGtvbWJpbmFzaSBkaXNpcGxpbiBpbG11Lg0KDQpgYGB7cn0NCmxpYnJhcnkoY2FyRGF0YSkgICAgICAgICAgICANCmxpYnJhcnkoZ2dwbG90MikgICAgICAgICAgIA0KbGlicmFyeShkcGx5cikgICAgICAgICAgICAgIA0KIyBtZW5naGl0dW5nIHJhdGEtcmF0YSBkYW4ga2VzYWxhaGFuIHN0YW5kYXIgYmVyZGFzYXJrYW4gDQojIGplbmlzIGtlbGFtaW4sIGphYmF0YW4sIGRhbiBkaXNpcGxpbiBpbG11DQpwbG90ZGF0YSA8LSBTYWxhcmllcyAlPiUNCiAgZ3JvdXBfYnkoc2V4LCByYW5rLCBkaXNjaXBsaW5lKSAlPiUNCiAgZHBseXI6OnN1bW1hcml6ZShuID0gbigpLA0KICAgICAgICAgICAgbWVhbiA9IG1lYW4oc2FsYXJ5KSwNCiAgICAgICAgICAgIHNkID0gc2Qoc2FsYXJ5KSwNCiAgICAgICAgICAgIHNlID0gc2QgLyBzcXJ0KG4pKQ0KIyBtZW1idWF0IGxhYmVsIHlhbmcgbGViaWggYmFpayB1bnR1ayBkaXNpcGxpbiBpbG11DQpwbG90ZGF0YSRkaXNjaXBsaW5lIDwtIGZhY3RvcihwbG90ZGF0YSRkaXNjaXBsaW5lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiVGhlb3JldGljYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQXBwbGllZCIpKQ0KIyBtZW1idWF0IHBsb3QNCmdncGxvdChwbG90ZGF0YSwgDQogICAgICAgYWVzKHggPSBzZXgsIA0KICAgICAgICAgICB5ID0gbWVhbiwNCiAgICAgICAgICAgY29sb3IgPSBzZXgpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsNCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IG1lYW4gLSBzZSwgDQogICAgICAgICAgICAgICAgICAgIHltYXggPSBtZWFuICsgc2UpLA0KICAgICAgICAgICAgICAgIHdpZHRoID0gLjEpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSg3MDAwMCwgMTQwMDAwLCAxMDAwMCksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHNjYWxlczo6ZG9sbGFyKSArDQogIGZhY2V0X2dyaWQoLiB+IHJhbmsgKyBkaXNjaXBsaW5lKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeD0iIiwgDQogICAgICAgeT0iIiwgDQogICAgICAgdGl0bGU9Ik5pbmUgbW9udGggYWNhZGVtaWMgc2FsYXJpZXMgYnkgZ2VuZGVyLCBkaXNjaXBsaW5lLCBhbmQgcmFuayIsDQogICAgICAgc3VidGl0bGUgPSAiKE1lYW5zIGFuZCBzdGFuZGFyZCBlcnJvcnMpIikgKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIpDQpgYGANCg0KUGVybnlhdGFhbiBmYWNldF9ncmlkKC5+cmFuaytkaWNpcGxpbmUpIHRpZGFrIG1lbmVudHVrYW4gdmFyaWFiZWwgYmFyaXMgKC4pIGRhbiBrb2xvbSB5YW5nIGRpdGVudHVrYW4gb2xlaCBrb21iaW5hc2kgamFiYXRhbiBkYW4gZGlzaXBsaW4gaWxtdS4NCg0KRnVuZ3NpIHRoZW1lKCkgbWVtYnVhdCB0ZW1hIGhpdGFtIGRhbiBwdXRpaCBkYW4gbWVuZ2hpbGFuZ2thbiBnYXJpcyBncmlkIHZlcnRpa2FsIGRhbiBnYXJpcyBncmlkIGhvcml6b250YWwgbWlub3IuIEZ1bmdzaSBzY2FsZV9jb2xvcl9icmV3ZXIoKSBtZW5ndWJhaCBza2VtYSB3YXJuYSB1bnR1ayB0aXRpayBkYW4gYmF0YW5nLWJhdGFuZyBrZXNhbGFoYW4uDQoNClBhZGEgcGFuZGFuZ2FuIHBlcnRhbWEsIHRhbXBha255YSBtdW5na2luIGFkYSBwZXJiZWRhYW4gZ2VuZGVyIGRhbGFtIGdhamkgdW50dWsgQXNzb2NpYXRlIGRhbiBGdWxsIFByb2Zlc3NvcnMgZGkgYmlkYW5nIHRlb3JpdGlzLg0KDQpTZWJhZ2FpIGNvbnRvaCB0ZXJha2hpciwga2l0YSBha2FuIGJlcmFsaWgga2UgZGF0YXNldCBiYXJ1IGRhbiBtZW1wbG90IHBlcnViYWhhbiBkYWxhbSBoYXJhcGFuIGhpZHVwIGRhcmkgd2FrdHUga2Ugd2FrdHUgdW50dWsgbmVnYXJhLW5lZ2FyYSBkaSDigJxBc2lh4oCdLiBEYXRhIHRlcnNlYnV0IGJlcmFzYWwgZGFyaSBkYXRhc2V0IGdhcG1pbmRlciBkYWxhbSBwYWNrYWdlIGdhcG1pbmRlci4gU2V0aWFwIG5lZ2FyYSBtdW5jdWwgZGFsYW0gZmFzZXRueWEgc2VuZGlyaS4gRnVuZ3NpIHRlbWEgZGlndW5ha2FuIHVudHVrIG1lbnllZGVyaGFuYWthbiB3YXJuYSBsYXRhciBiZWxha2FuZywgbWVtdXRhciB0ZWtzIHN1bWJ1IHgsIGRhbiBtZW1wZXJrZWNpbCB1a3VyYW4gdHVsaXNhbi4NCg0KYGBge3J9DQpsaWJyYXJ5KGdhcG1pbmRlcikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdW50dWsgZGF0YXNldA0KbGlicmFyeShnZ3Bsb3QyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHVudHVrIHZpc3VhbGlzYXNpDQpsaWJyYXJ5KGRwbHlyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbWFuaXB1bGFzaSBkYXRhDQojIG1lbXBsb3QgaGFyYXBhbiBoaWR1cCBiZXJkYXNhcmthbiB0YWh1biBzZWNhcmEgdGVycGlzYWgNCiMgdW50dWsgc2V0aWFwIG5lZ2FyYSBkaSBBc2lhDQpkYXRhKGdhcG1pbmRlciwgcGFja2FnZSA9ICJnYXBtaW5kZXIiKQ0KIyBQaWxpaCBkYXRhIEFzaWENCnBsb3RkYXRhIDwtIGRwbHlyOjpmaWx0ZXIoZ2FwbWluZGVyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGluZW50ID09ICJBc2lhIikNCiMgbWVtcGxvdCBoYXJhcGFuIGhpZHVwIGJlcmRhc2Fya2FuIHRhaHVuLCB1bnR1ayBzZXRpYXAgbmVnYXJhDQpnZ3Bsb3QocGxvdGRhdGEsIGFlcyh4PXllYXIsIHkgPSBsaWZlRXhwKSkgKw0KICBnZW9tX2xpbmUoY29sb3I9ImdyZXkiKSArDQogIGdlb21fcG9pbnQoY29sb3I9ImJsdWUiKSArDQogIGZhY2V0X3dyYXAofmNvdW50cnkpICsgDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gOSkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxKSkgKw0KICBsYWJzKHRpdGxlID0gIkNoYW5nZXMgaW4gTGlmZSBFeHBlY3RhbmN5IiwNCiAgICAgICB4ID0gIlllYXIiLA0KICAgICAgIHkgPSAiTGlmZSBFeHBlY3RhbmN5IikgDQpgYGANCg0KIyBSZWZlcmVuc2kNCg0KaHR0cHM6Ly9ib29rZG93bi5vcmcvQmFrdGlTaXJlZ2FyL2RhdGEtc2NpZW5jZS1mb3ItYmVnaW5uZXJzL1Zpc3VhbGl6YXRpb24uaHRtbA0KDQpodHRwczovL3d3dy5nZWVrc2ZvcmdlZWtzLm9yZy9zZWFib3JuLXNvcnQtYmFycy1pbi1iYXJwbG90Lw0KDQpodHRwczovL3BhbmRhcy5weWRhdGEub3JnLw0KDQpodHRwczovL21hdHBsb3RsaWIub3JnLw0KDQpodHRwczovL3NlYWJvcm4ucHlkYXRhLm9yZy8NCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=