Algoritma & Struktur Data

~ Visualisasi Data ~


Kontak : \(\downarrow\)
Email
Instagram https://www.instagram.com/fe_nw/
RPubs https://rpubs.com/ferdnw/

Visualisasi Data Visualisasi data merupakan suatu teknik mengubah informasi atau data yang ada menjadi bentuk visual yang lebih mudah untuk dilihat atau diproses seperti grafik atau chart. Dalam mempresentasikan data, akan lebih menarik untuk melihat visualized data daripada raw data. R merupakan salah satu software yang capable dalam melakukan hal tersebut.

Univariat (Single Variabel)

Visualisasi data dari satu variabel saja, bisa dalam bentuk Kategoris(Bukan angka, tidak dapat dihitung contohnya jenis kelamin, asal daerah) dan Numerik (Berupa Angka, dapat dihitung, seperti Umur, Salary)

Variabel Kategori

Variabel Non-Angka biasanya dipresentasikan dalam bentuk Bar Chart, Pie Chart, dan Pohon. Contoh visualisasi Data Marriage by dibawah

Bar Chart

Distribusi Marriage by Zodiacs dalam bentuk Daigram Batang

library(ggplot2)
MarriageZod = read.csv("https://raw.githubusercontent.com/Bakti-Siregar/dataset/master/Bookdown-Data-Science-for-Beginners/Marriage.csv")

ggplot(MarriageZod, aes(x=zodiacs))+
  geom_bar(fill='orchid', color='azure4')+
  theme_minimal()+
  labs(x="Zodiacs",
       y="Frequency",
       title = "Marriage Participants by Zodiac")

Dalam Bentuk Persentase

library(ggplot2)

ggplot(MarriageZod, 
       aes(x=zodiacs,
           y=..count.. / sum(..count..)))+
  geom_bar(fill=rainbow(12), color='azure4')+
  theme_light()+
  labs(x="Zodiacs",
       y="Frequency",
       title = "Marriage Participants by Zodiac in Percents") 

  scale_y_continuous(labels=scales::percent)
## <ScaleContinuousPosition>
##  Range:  
##  Limits:    0 --    1

Bisa Juga dalam bentuk Sorting from lowest to highest

library(dplyr)
library(ggplot2)
plotdata = MarriageZod%>%
  count(zodiacs)

ggplot(plotdata,
       aes(x=reorder(zodiacs,n), 
           y = n))+
  geom_bar(stat="identity", 
          fill=rainbow(12),
        color="azure4" )+
  theme_light()+  #theme yang berbeda dngan sblumnya
  labs(x="Zodiacs",
       y="Frequency",
       title = "Sorted Marriage Participants by Zodiacs")

Bar pada Chart dapat diberi label sesuai frekuensi atau persentase maisng-masing

library(dplyr)
library(ggplot2)
library(scales)

plotdata = MarriageZod%>%
  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_classic() + #theme yang lainnya
  scale_y_continuous(labels = percent) +
  labs(x = "Zodiacs",
       y = "Percentage",
       title = "Labeled Bars")

Label di bawah Tumpang tindih Bisa diatasi dengan memutar label pada sumbu x nya

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) +
  theme_minimal() + #theme yang lainnya
  scale_y_continuous(labels = percent) +
  labs(x = "Zodiacs",
       y = "Percentage",
       title = "Adjusted X and Labeled Bars")

theme(axis.text.x = element_text(angle = 45, hjust=1))
## List of 1
##  $ axis.text.x:List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : NULL
##   ..$ hjust        : num 1
##   ..$ vjust        : NULL
##   ..$ angle        : num 45
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi FALSE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi FALSE
##  - attr(*, "validate")= logi TRUE

Menukar Sumbu X dan Y (Memutar Grafik 90 derajat)

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 = "Percentage",
       title = "Rotated Bars")

coord_flip()
## <ggproto object: Class CoordFlip, CoordCartesian, Coord, gg>
##     aspect: function
##     backtransform_range: function
##     clip: on
##     default: FALSE
##     distance: function
##     expand: TRUE
##     is_free: function
##     is_linear: function
##     labels: function
##     limits: list
##     modify_scales: function
##     range: function
##     render_axis_h: function
##     render_axis_v: function
##     render_bg: function
##     render_fg: function
##     setup_data: function
##     setup_layout: function
##     setup_panel_guides: function
##     setup_panel_params: function
##     setup_params: function
##     train_panel_guides: function
##     transform: function
##     super:  <ggproto object: Class CoordFlip, CoordCartesian, Coord, gg>

Pie Chart

Variasi dari Bar Chart yang merupakan Grafik berbentuk Lingkaran

library(dplyr)
library(ggplot2)
library(scales)

plotdata = MarriageZod%>%
  count(race)%>%
  arrange(desc(race)) %>%
  mutate(prop=round(n*100/sum(n), 1), 
         lab.ypos = cumsum(prop)- 0.5*prop )

#Membuat Pie Chart

mycols = c("#0073C2FF", "#EFC000CF", "#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")

Variasi bentuk dari Pie chart adalah Donut Chart, hanya beda bolong di tengahnya

library(ggplot2)
library(scales)

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")

Menambahkan Labels pada Donut Chart

library(ggplot2)
library(scales)

plotdata$percent = paste0(plotdata$race, "\n",
                          round(plotdata$prop), "%")

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")

Peta Pohon

Biasanya digunakan terhadap Kategorikal data yang memiliki banyak tingkatan

library(ggplot2)
library(treemapify)
library(scales)

plotdata = MarriageZod %>%
  count(officialTitle)

ggplot(plotdata, aes(fill = officialTitle, area = n))+
  geom_treemap()+
  labs(title = " Marriage Participants by Officiate")

With Labels

library(ggplot2)
library(treemapify)
library(scales)

plotdata = MarriageZod %>%
  count(officialTitle)

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

Variabel Kontinu

Biasanya data Numerik atau Angka digambarkan dengan Histogram, Plot Densitas kernel, dan Diagram Titik

Histogram

library(ggplot2)
ggplot(MarriageZod, aes(x=age)) +
  geom_histogram(fill = "olivedrab4", color = "red", bins = 20) +
  theme_minimal() +
  labs(title = "Marriage Participants by Age (basic)", x="Age")

Cara mengubah Binwidth atau Range yang diwakili oleh satu batang histogram

library(ggplot2)
library(scales)

ggplot(MarriageZod, aes(x=age, y = ..count../sum(..count..))) +
  geom_histogram(fill = "deeppink3", color = "cyan1", binwidth = 5) +
  theme_minimal() +
  labs(title = "Marriage Participants by Age (Alternative Binds and bandwidths)", x="Age", 
       y = "Percent") +
scale_y_continuous(labels=percent)

Dengan percent sebagai pengganti jumlah frekuensi

library(ggplot2)
library(scales)

ggplot(MarriageZod, aes(x=age, y = ..count../sum(..count..))) +
  geom_histogram(fill = "lemonchiffon2", color = "orangered1", binwidth = 5) +
  theme_minimal() +
  labs(title = "Marriage Participants by Age (Alternative Binds and bandwidths)", x="Age", 
       y = "Percent") +
scale_y_continuous(labels=percent)

Plot Density Kernel

versi diperhalus dari Histogram

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

Cara Membacanya adalah dengan menghitung luas dibawah kurva dari range area yang di inginkan.

Parameter Penghalusan (Smoothing)

Nilai dibawah default dengan fungsi “bw.nrd0” menghasilkan penghalusan sedikit, dan nilai yang lebih besar dari default menghasilkan penghalusan lebih banyak

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

Diagram Titik (DotPlot)

Sebagai Alternatif dari Histogram

library(ggplot2)

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

Data Bivariat

Grafik yang dipengaruhi oleh dua variabel yang berhubungan

Kategorikal vs Kategorikal

Keduanya tidak dapat dihitung atau bukan numerik

Diagram batang Bertumpuk

Perbandingan antara Kelas Mobil dan penggeraknya (Front, rear, atau 4WD)

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")

Diagram Batang Dikelompokkan

Variabel kategori yang berbeda diletakkan di bar yang berbeda

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

Diagram batang segmentasi

Kurang lebihnya miirp dengan diagram batang bertumpuk

library(ggplot2)
library(dplyr)
library(scales)

#RIngkasan dataset
plotdata = mpg%>%
  group_by(class, drv) %>%
  dplyr::summarize (n= n()) %>%
  mutate(pct = n/sum(n),
         lbl = scales::percent(pct))

ggplot(plotdata, aes(x=factor(class),
                    y=pct, 
                    fill = factor(drv)))+
  geom_bar(stat="identity", position="fill")+
  scale_y_continuous(breaks = seq(0,1,0.2), label = percent)+
  geom_text(aes(label=lbl), size= 3, position = position_stack(vjust = 0.5)) +
  scale_fill_brewer (palette="Set2")+
  theme_minimal()+
  labs(y='Percent', fill = "Drivetrain", 
       x= "Class", title = "Automobile drives by class")+
  theme_minimal()

Mozaic Plot

Luas dari area menggambarkan proporsi jumlah kategorikal dengan kombinasi tertentu dengan warna ubin yang menunjukkan hubungan antar variabel. Contoh plot dengan data survival Titanic

tabel = xtabs(Freq ~ Survived + Class + Sex, Titanic)
ftable(tabel)
##                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
library(vcd)
mosaic(tabel, main = "Titanic data")

Dengan memberi warna pada ubin kita bisa tahu apakah nilainya sesuai dengan yang diharapkan jika berlaku tidak terikat

mosaic(tabel, shade = T, legens = T, 
       labelin_args = list(set_varnames = c(Sex= "Gender", Survives = "Survived", 
                                            Class = "PAssenger Class")),
       set.labels = list(Survived = c("No",'Yes'), 
                         Class = c("1st", "2nd", "3rd", "Crew"),
                         main = "Titanic Data"
       ))

Dilihat dari warna, lebih banyak Crew Laki-laki tewas dan Penumbang Wanita dari ketiga kelas yang selamat dan sebaliknya. Jauh lebih sedikit penumpang First class yang tidak selamat baik laki-laiki atau perempuan.

Kontinu vs Kontinu

Dua variable numerik biasanya digambarkan dengan grafik sebaran titik atau g aris

Scatter Plot

library(ggplot2)
library(hrbrthemes)

#Make a Dataframe
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))

don %>%
  ggplot(aes(x=x, y=y))+
  geom_point(color = "#69b3a2", alpha = 0.8)+
  theme_ipsum()+
  facet_wrap(~name, scale = 'free')

Contoh lain dengan Data Pengalaman Kerja dan Jumlah salary

library(carData)
library(ggplot2)
library(scales)
data(Salaries, package="carData")

ggplot(Salaries, aes(x=yrs.since.phd, y = salary))+
  geom_point(color = "aquamarine2", size = 2, alpha = .8) +
  scale_y_continuous (labels = 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-Months Salary for 2008-2009")

Plot Sebaran Menyesuaikan Garis

Plot ini digunakan dengan batas kepercayaan mencapai 95%

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

Benar bahwa gaji akan meningkat sejalan pengalaman , namun ada penurunan juga, garis lurus kurang pas lebih cocok garis melengkung. Biasanya garis melengkunf kuadrat atau pangkat tiga (kubik). garis polinomial lebih dari kubik jarang digunakan

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

Penghalusan Plot Sebaran

library(ggplot2)
ggplot(Salaries, aes(x=yrs.since.phd, y=salary))+
  geom_point(color="magenta", size = 2, alpha = 1)+
  geom_smooth(size = 1, color="deepskyblue1")+
  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-Months Salary for 2008-2009")

Kategorikal vs Kontinu

Diagram Batang

library(dplyr)
library(ggplot2)
library(scales)
data(Salaries, package = "carData")

plotdata = Salaries %>%
  group_by(rank)%>%
  dplyr ::summarize(mean_salary = mean(salary))

mycols = c("#CD534CFF", "#EFC000FF", "#0073C2FF")
ggplot(plotdata, aes(x=factor(rank, labels = c("Assistanst \n Professor", "Associate \n Professor", "Full \n Professor")),
                     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()+
  labs(title = "Mean Salary by Rank",
       subtitle = "9-Month academic salary for 2008-2009",
       x="", y="")

Plot DEnsitas Kernel yang dikelompokkan

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

Box Plot

Boxplot memberikan kita Five-Number Summary dari suatu data

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

Violin Plot

Mirip dengan Densitas Kernel, yang diputar 90 derajat dan diMirror

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

Plot Garis Punggung

Mirip dengan Plot Densitas Kernel, menampilkan distribusi kuantitas dari beberapa kelompok. dibuat dengan Library ggridges.Contoh penggunaaan dengan data Fuel Economy

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")

Apabila Data terlalu tumpang tindih, bisa mengecilkan oppacity atau transparansi dengan mengecilkan nilai Alpha

Plot Garis

Gabungan dari Boxplot dan Line chart yang menghubungkan antar rata-rata (Titik Tengah Boxplot)

library(dplyr)
library(ggplot2)
library(ggridges)

#Menghitung Mean, StaDev, dan 95% Nilai 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))

pd = position_dodge(0.2)
ggplot(plotdata, aes(x=factor(rank,
                              labels = c("Assistanst \n Professor", "Associate \n Professor", "Full \n Professor")), 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")

Strip Plot

Scatter Plot yang dikelompokkan, agak susah dilihat apabila titiknya goyah

library(ggplot2)
library(scales)

ggplot(Salaries, aes(y=factor(rank,
                              labels = c("Assistanst \n Professor", "Associate \n Professor", "Full \n Professor")), x= salary, color= rank))+
  geom_jitter(alpha = 0.7, size = 1.5)+
  scale_x_continuous(label=dollar)+
    theme_minimal()+
  labs(title = "Academic Salary by Rank ",
       subtitle= "9 Months Salary for 20008-2009 ",
       x= "", y="")

theme(legend.position = "none")
## List of 1
##  $ legend.position: chr "none"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi FALSE
##  - attr(*, "validate")= logi TRUE

Gabungan Jitter dan Plot Kotak

Menambahkan plot kotak ke plot Jitter memudahkan presentasi distribusi

library(ggplot2)
library(scales)
ggplot(Salaries, aes(x= factor(rank,
                              labels = c("Assistanst \n Professor", "Associate \n Professor", "Full \n Professor")), 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)+
    theme_minimal()+
  labs(title = "Academic Salary by Rank ",
       subtitle= "9 Months Salary for 2008-2009 ",
       x= "", y="")+
theme(legend.position = "none")+
  coord_flip()

Dalam geo_boxjitter kita bisa membuat plot hybrid kotak dan sebaran dalam library ggpol

library(ggplot2)
library(scales)
library(ggpol)

ggplot(Salaries, aes(x= factor(rank,
                              labels = c("Assistanst \n Professor", "Associate \n Professor", "Full \n Professor")), y = salary ,fill = rank))+
  geom_boxjitter(color = 'black', 
                 jitter.color = "darkgrey",
                 errorbar.draw = T)+
  scale_y_continuous(label=dollar)+
  labs(title = "Academic Salary by Rank ",
       subtitle= "9 Months Salary for 2008-2009 ",
       x= "", y="")+
    theme_minimal()+
theme(legend.position = "none")

Plot Kawanan Lebah

Mirip dengan Plot Biola dan Plot Jitter. Menunjukkan distribusi variabel kuantitatif dan densitas tiap titik

library(ggplot2)
library(scales)
library(ggbeeswarm) #mengurangi tumpang tindih 

ggplot(Salaries, aes(x= factor(rank,
                              labels = c("Assistanst \n Professor", "Associate \n Professor", "Full \n Professor")), 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 Months Salary for 2008-2009 ",
       x= "", y="")+
    theme_minimal()+
theme(legend.position = "none")

Diagram Titik Cleveland

Digunakan ketika membandingkan statistik numerik sejumlah kelompok. Disebut juga Lolipop Graph. Contohnya data dari gapminder tentang harapan hidup di Asia

library(ggplot2)
library(dplyr)
library(scales)
library(ggbeeswarm)
library(gapminder)
data(gapminder, package = "gapminder")

#Subset hanya data Region Asia
library(dplyr)
plotdata = gapminder%>%
  filter(continent == 'Asia' & year == 2007)

#Plot Cleveland
ggplot(plotdata, aes(x=lifeExp, y=reorder(country, lifeExp)))+
  geom_point(color='navy', 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 Countries",
        subtitle = "GapMinder data for Asia - 2007")+
  theme_minimal()+
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank())

Data Multivariat

Grafik Multivariat mempresentasikan hubungan antara lebih dari dua variabel, seperti membandingkan lebih dari dua grafik . Pada Multivariat ini, terdapat dua metode umum yaitu pengelompokan dan faceting.

Pengelompokan

Nilai dari dua variabel pertama dipetakan ke sumbu x dan y variabel tambahan juga digambarkan sesauai karakteristik visualnya, seperti warna, bentuk, ukuran, jenis garis, dan transparansi. Pengelompokan juga memplot lebih dari dua data ke dalam suatu grafik. Contohnya adalah dengan kita ingin memplot data 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 yang berbeda untuk menunjukkan jenis kelamin. Lalu meningkatkan ukuran titik dan menambahkan transparansi untuk memperjelas masing-masing titik .

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")

Grafik sepertinya terlalu ramai, FAceting akan lebih cocok. Pemetaan variabel ada dalam fungsi aes dan nilai konstanta lain di luarnya. Berikut Plot Gelembung dengan besar gelembung menentukan lama nya pengalaman kerja.

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, sex, and years since degree")

Dari grafik di atas, menjelaskan bahwa lama setelah menyandang Ph.D dan jabatan berkorelasi positif. Sebagai contoh terakhir, presentasi data yrs.since.phd vs. salary dan tambahkan jenis kelamin menggunakan warna dan garis kuadrat yang paling cocok.

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()

Faceting atau pembagian faset

Membandingkan grafik satu dengan yang lainnya dengan x dan y atau x dan y dengan jangkauan yang sama

library(carData)
library(ggplot2)

ggplot(Salaries,
aes(x = salary)) + 
  geom_histogram(fill = "khaki3", color = 'white')+
  facet_wrap(~rank, ncol=1) + 
  theme_minimal()+
  labs(title = "Salary Histograms by rank")

Facet_wrap berfungsi sebagai pemisah grafik dan opsi ncol sebagai pengatur jumlah kolom. Di COntoh kedua menggunakan 2 variabel sebagai facet yaitu jenis kelamin dan jabatan.

library(carData)
library(ggplot2)

ggplot(Salaries,
aes(x = salary/1000)) + 
  geom_histogram(fill = "mediumpurple3", color = 'white')+
  facet_grid(sex~rank) + 
  theme_minimal()+
  labs(title = "Salary Histograms by Sex and rank",
       x = "Salary($1000)")

Contohnya menggunakan Plot Mean/SE dan pembagian faset untuk membandingkan gajigaji dari profesor pria dan wanita, dalam jabatan dan disiplin ilmu. Kita akan menggunakan warna untuk membedakan jenis kelamin dan pembagian faset untuk membuat plotjabatan berdasarkan kombinasi disiplin ilmu.

library(carData) 
library(ggplot2)
library (dplyr)

#Menghitung Rata-rata dan Kesalahan Standar
plotdata <- Salaries %>%
group_by (sex, rank, discipline) %>% 
dplyr :: summarize (n = n(),
mean = mean(salary), 
sd = sd(salary), 
se = sd / sqrt(n))

#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")

  1. facet_grid(~rank+dicipline) tidak menentukan variabel baris kombinasi jabatan dan disiplin ilmu.
  2. theme() -> membuat tema hitam dan putih, menghilangkan garis grid vertikal, dan garis grid horizontal minor.
  3. scale_color_brewer() -> mengubah skema warna untuk titik dan batang batang kesalahan.

Kalau dilihat, adanya perbedaan antara gender dan gaji Associate dan Full Professors di bidang teoritis. ini bisa terjadi karena kita tidak melihat secara langsung mengapa ada perbedaan tersebut. Mungkin diperlukan percobaan secara langsung agar kita mengetahui .

Contoh terakhir, kita coba menggunakan 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 akan muncul dalam fasetnya sendiri.

Fungsi tema -> menyederhanakan warna latar belakang, memutar teks sumbu x, dan memperkecil ukuran tulisan

library(gapminder)
library(ggplot2)
library (dplyr)


# 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")

DQotLS0NCnRpdGxlOiAiQWxnb3JpdG1hICYgU3RydWt0dXIgRGF0YSINCnN1YnRpdGxlOiAifiBWaXN1YWxpc2FzaSBEYXRhIH4iDQphdXRob3I6ICJGZXJkaW5hbmQgTmF0aGFuaWVsIFdpZGpheWEgKDIwMjE0OTIwMDA2KSINCmRhdGU6ICAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6DQogIHJtZGZvcm1hdHM6OnJvYm9ib29rOiAgICMgaHR0cHM6Ly9naXRodWIuY29tL2p1YmEvcm1kZm9ybWF0cw0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlDQogICAgdGh1bWJuYWlsczogdHJ1ZQ0KICAgIGxpZ2h0Ym94OiB0cnVlDQogICAgZ2FsbGVyeTogdHJ1ZQ0KICAgIGxpYl9kaXI6IGxpYnMNCiAgICBkZl9wcmludDogInBhZ2VkIg0KICAgIGNvZGVfZm9sZGluZzogInNob3ciDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY3NzOiAic3R5bGUuY3NzIg0KDQotLS0NCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChjbGFzcy5zb3VyY2UgPSAibm9jb3B5IiwNCiAgICAgICAgICAgICAgICAgICAgICBjbGFzcy5vdXRwdXQgPSAibm9jb3B5IiwNCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRiwNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRikNCg0KbGlicmFyeShyZXRpY3VsYXRlKQ0KbGlicmFyeShSY3BwKQ0KDQpgYGANCg0KPGJyPg0KDQo8aW1nIHN0eWxlPSJmbG9hdDogcmlnaHQ7IG1hcmdpbjogLTUwcHggNTBweCAwcHggNTBweDsgd2lkdGg6MzAlIiBzcmM9ImZvdG8uanBnIi8+IA0KDQp8DQo6LS0tLSB8Oi0tLS0NCioqS29udGFrKip8ICoqOiAkXGRvd25hcnJvdyQqKg0KRW1haWx8IGZlcmRpbmFuZC53aWRqYXlhQHN0dWRlbnQubWF0YW5hdW5pdmVyc2l0eS5hYy5pZA0KSW5zdGFncmFtIHwgaHR0cHM6Ly93d3cuaW5zdGFncmFtLmNvbS9mZV9udy8gDQpSUHVicyAgfCBodHRwczovL3JwdWJzLmNvbS9mZXJkbncvIA0KDQoqKioNCg0KKipWaXN1YWxpc2FzaSBEYXRhKioNClZpc3VhbGlzYXNpIGRhdGEgbWVydXBha2FuIHN1YXR1IHRla25payBtZW5ndWJhaCBpbmZvcm1hc2kgYXRhdSBkYXRhIHlhbmcgYWRhIG1lbmphZGkgYmVudHVrIHZpc3VhbCB5YW5nIGxlYmloIG11ZGFoIHVudHVrIGRpbGloYXQgYXRhdSBkaXByb3NlcyBzZXBlcnRpIGdyYWZpayBhdGF1IGNoYXJ0LiBEYWxhbSBtZW1wcmVzZW50YXNpa2FuIGRhdGEsIGFrYW4gbGViaWggbWVuYXJpayB1bnR1ayBtZWxpaGF0IHZpc3VhbGl6ZWQgZGF0YSAgZGFyaXBhZGEgcmF3IGRhdGEuIFIgbWVydXBha2FuIHNhbGFoIHNhdHUgc29mdHdhcmUgeWFuZyBjYXBhYmxlIGRhbGFtIG1lbGFrdWthbiBoYWwgdGVyc2VidXQuIA0KDQojIFVuaXZhcmlhdCAoU2luZ2xlIFZhcmlhYmVsKQ0KVmlzdWFsaXNhc2kgZGF0YSBkYXJpIHNhdHUgdmFyaWFiZWwgc2FqYSwgYmlzYSBkYWxhbSBiZW50dWsgS2F0ZWdvcmlzKEJ1a2FuIGFuZ2thLCB0aWRhayBkYXBhdCBkaWhpdHVuZyBjb250b2hueWEgamVuaXMga2VsYW1pbiwgYXNhbCBkYWVyYWgpIGRhbiBOdW1lcmlrIChCZXJ1cGEgQW5na2EsIGRhcGF0IGRpaGl0dW5nLCBzZXBlcnRpIFVtdXIsIFNhbGFyeSkNCg0KIyMgVmFyaWFiZWwgS2F0ZWdvcmkgey50YWJzZXQgLnRhYnNldC1waWxsc30NClZhcmlhYmVsIE5vbi1BbmdrYSBiaWFzYW55YSBkaXByZXNlbnRhc2lrYW4gZGFsYW0gYmVudHVrIEJhciBDaGFydCwgUGllIENoYXJ0LCBkYW4gUG9ob24uIENvbnRvaCB2aXN1YWxpc2FzaSBEYXRhIE1hcnJpYWdlIGJ5IGRpYmF3YWgNCg0KIyMjIEJhciBDaGFydA0KRGlzdHJpYnVzaSBNYXJyaWFnZSBieSBab2RpYWNzIGRhbGFtIGJlbnR1ayBEYWlncmFtIEJhdGFuZw0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpNYXJyaWFnZVpvZCA9IHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQmFrdGktU2lyZWdhci9kYXRhc2V0L21hc3Rlci9Cb29rZG93bi1EYXRhLVNjaWVuY2UtZm9yLUJlZ2lubmVycy9NYXJyaWFnZS5jc3YiKQ0KDQpnZ3Bsb3QoTWFycmlhZ2Vab2QsIGFlcyh4PXpvZGlhY3MpKSsNCiAgZ2VvbV9iYXIoZmlsbD0nb3JjaGlkJywgY29sb3I9J2F6dXJlNCcpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnMoeD0iWm9kaWFjcyIsDQogICAgICAgeT0iRnJlcXVlbmN5IiwNCiAgICAgICB0aXRsZSA9ICJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgWm9kaWFjIikNCmBgYA0KRGFsYW0gQmVudHVrIFBlcnNlbnRhc2UNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpnZ3Bsb3QoTWFycmlhZ2Vab2QsIA0KICAgICAgIGFlcyh4PXpvZGlhY3MsDQogICAgICAgICAgIHk9Li5jb3VudC4uIC8gc3VtKC4uY291bnQuLikpKSsNCiAgZ2VvbV9iYXIoZmlsbD1yYWluYm93KDEyKSwgY29sb3I9J2F6dXJlNCcpKw0KICB0aGVtZV9saWdodCgpKw0KICBsYWJzKHg9IlpvZGlhY3MiLA0KICAgICAgIHk9IkZyZXF1ZW5jeSIsDQogICAgICAgdGl0bGUgPSAiTWFycmlhZ2UgUGFydGljaXBhbnRzIGJ5IFpvZGlhYyBpbiBQZXJjZW50cyIpIA0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlczo6cGVyY2VudCkNCg0KYGBgDQoNCg0KDQoNCkJpc2EgSnVnYSBkYWxhbSBiZW50dWsgU29ydGluZyBmcm9tIGxvd2VzdCB0byBoaWdoZXN0DQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpwbG90ZGF0YSA9IE1hcnJpYWdlWm9kJT4lDQogIGNvdW50KHpvZGlhY3MpDQoNCmdncGxvdChwbG90ZGF0YSwNCiAgICAgICBhZXMoeD1yZW9yZGVyKHpvZGlhY3MsbiksIA0KICAgICAgICAgICB5ID0gbikpKw0KICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIA0KICAgICAgICAgIGZpbGw9cmFpbmJvdygxMiksDQogICAgICAgIGNvbG9yPSJhenVyZTQiICkrDQogIHRoZW1lX2xpZ2h0KCkrICAjdGhlbWUgeWFuZyBiZXJiZWRhIGRuZ2FuIHNibHVtbnlhDQogIGxhYnMoeD0iWm9kaWFjcyIsDQogICAgICAgeT0iRnJlcXVlbmN5IiwNCiAgICAgICB0aXRsZSA9ICJTb3J0ZWQgTWFycmlhZ2UgUGFydGljaXBhbnRzIGJ5IFpvZGlhY3MiKQ0KYGBgDQoNCkJhciBwYWRhIENoYXJ0IGRhcGF0IGRpYmVyaSBsYWJlbCBzZXN1YWkgZnJla3VlbnNpIGF0YXUgcGVyc2VudGFzZSAgbWFpc25nLW1hc2luZw0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQoNCnBsb3RkYXRhID0gTWFycmlhZ2Vab2QlPiUNCiAgY291bnQoem9kaWFjcyklPiUNCiAgbXV0YXRlKHBjdD1uIC8gc3VtKG4pLA0KICAgICAgICAgcGN0bGFiZWwgPSBwYXN0ZTAocm91bmQocGN0KjEwMCksICIlIikpDQpnZ3Bsb3QocGxvdGRhdGEsDQogICAgICAgYWVzKHg9IHJlb3JkZXIoem9kaWFjcywgLXBjdCksDQogICAgICAgICAgIHk9cGN0KSkgKw0KICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGwgPSByYWluYm93KDEyKSwgY29sb3I9ImF6dXJlNCIpICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBjdGxhYmVsKSwgdmp1c3Q9IC0wLjI1KSArDQogIHRoZW1lX2NsYXNzaWMoKSArICN0aGVtZSB5YW5nIGxhaW5ueWENCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsNCiAgbGFicyh4ID0gIlpvZGlhY3MiLA0KICAgICAgIHkgPSAiUGVyY2VudGFnZSIsDQogICAgICAgdGl0bGUgPSAiTGFiZWxlZCBCYXJzIikNCg0KDQpgYGANCkxhYmVsIGRpIGJhd2FoIFR1bXBhbmcgdGluZGloICBCaXNhIGRpYXRhc2kgZGVuZ2FuIG1lbXV0YXIgbGFiZWwgcGFkYSBzdW1idSB4IG55YSANCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQoNCmdncGxvdChwbG90ZGF0YSwNCiAgICAgICBhZXMoeD0gcmVvcmRlcih6b2RpYWNzLCAtcGN0KSwNCiAgICAgICAgICAgeT1wY3QpKSArDQogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbCA9IHJhaW5ib3coMTIpLCBjb2xvcj0iYXp1cmU0IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGN0bGFiZWwpLCB2anVzdD0gLTAuMjUpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgI3RoZW1lIHlhbmcgbGFpbm55YQ0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKw0KICBsYWJzKHggPSAiWm9kaWFjcyIsDQogICAgICAgeSA9ICJQZXJjZW50YWdlIiwNCiAgICAgICB0aXRsZSA9ICJBZGp1c3RlZCBYIGFuZCBMYWJlbGVkIEJhcnMiKQ0KdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSkpDQogICAgDQpgYGANCiBNZW51a2FyIFN1bWJ1IFggZGFuIFkgKE1lbXV0YXIgR3JhZmlrIDkwIGRlcmFqYXQpDQpgYGB7cn0NCmdncGxvdChwbG90ZGF0YSwNCiAgICAgICBhZXMoeD0gcmVvcmRlcih6b2RpYWNzLCAtcGN0KSwNCiAgICAgICAgICAgeT1wY3QpKSArDQogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbCA9IHJhaW5ib3coMTIpLCBjb2xvcj0iYXp1cmU0IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGN0bGFiZWwpLCB2anVzdD0gLTAuMjUpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArDQogIGxhYnMoeCA9ICJab2RpYWNzIiwNCiAgICAgICB5ID0gIlBlcmNlbnRhZ2UiLA0KICAgICAgIHRpdGxlID0gIlJvdGF0ZWQgQmFycyIpDQpjb29yZF9mbGlwKCkNCmBgYA0KDQojIyMgUGllIENoYXJ0DQpWYXJpYXNpIGRhcmkgQmFyIENoYXJ0IHlhbmcgbWVydXBha2FuIEdyYWZpayBiZXJiZW50dWsgTGluZ2thcmFuDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc2NhbGVzKQ0KDQpwbG90ZGF0YSA9IE1hcnJpYWdlWm9kJT4lDQogIGNvdW50KHJhY2UpJT4lDQogIGFycmFuZ2UoZGVzYyhyYWNlKSkgJT4lDQogIG11dGF0ZShwcm9wPXJvdW5kKG4qMTAwL3N1bShuKSwgMSksIA0KICAgICAgICAgbGFiLnlwb3MgPSBjdW1zdW0ocHJvcCktIDAuNSpwcm9wICkNCg0KI01lbWJ1YXQgUGllIENoYXJ0DQoNCm15Y29scyA9IGMoIiMwMDczQzJGRiIsICIjRUZDMDAwQ0YiLCAiIzg2ODY4NkZGIiwgIiNDRDUzNENGRiIpDQoNCmdncGxvdChwbG90ZGF0YSwgYWVzKHg9IiIsIHkgPSBwcm9wLCBmaWxsID0gcmFjZSApKSArDQogIGdlb21fYmFyKHdpZHRoPTEsIHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgY29vcmRfcG9sYXIgKCJ5Iiwgc3RhcnQgPSAwICkgKw0KICBnZW9tX3RleHQgKGFlcyh5PWxhYi55cG9zLCBsYWJlbCA9IHByb3ApLCBjb2xvciA9ICJ3aGl0ZSIpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9bXljb2xzKSArDQogIHRoZW1lX3ZvaWQoKSArIA0KICBsYWJzICh0aXRsZSA9ICJNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgUmFjZSIpDQpgYGANCg0KIFZhcmlhc2kgYmVudHVrIGRhcmkgUGllIGNoYXJ0IGFkYWxhaCBEb251dCBDaGFydCwgaGFueWEgYmVkYSBib2xvbmcgZGkgdGVuZ2FobnlhDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQoNCmdncGxvdChwbG90ZGF0YSwgYWVzKHg9MiwgeSA9IHByb3AsIGZpbGwgPSByYWNlICkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gIndoaXRlIikgKw0KICBjb29yZF9wb2xhciAodGhldGEgPSAieSIsIHN0YXJ0ID0gMCApICsNCiAgZ2VvbV90ZXh0KGFlcyh5PWxhYi55cG9zLCBsYWJlbCA9IHByb3ApLCBjb2xvciA9ICJ3aGl0ZSIpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9bXljb2xzKSArDQogIHRoZW1lX3ZvaWQoKSArIA0KICB4bGltKDAuNSwgMi41KSsNCiAgbGFicyAodGl0bGUgPSAiTWFycmlhZ2UgUGFydGljaXBhbnRzIGJ5IFJhY2UiKQ0KYGBgDQoNCiBNZW5hbWJhaGthbiBMYWJlbHMgcGFkYSBEb251dCBDaGFydA0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHNjYWxlcykNCg0KcGxvdGRhdGEkcGVyY2VudCA9IHBhc3RlMChwbG90ZGF0YSRyYWNlLCAiXG4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZChwbG90ZGF0YSRwcm9wKSwgIiUiKQ0KDQpnZ3Bsb3QocGxvdGRhdGEsIGFlcyh4PTIsIHkgPSBwcm9wLCBmaWxsID0gcmFjZSApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJ3aGl0ZSIpICsNCiAgY29vcmRfcG9sYXIgKHRoZXRhID0gInkiLCBzdGFydCA9IDAgKSArDQogIGdlb21fdGV4dChhZXMoeT1sYWIueXBvcywgbGFiZWwgPSBwcm9wKSwgY29sb3IgPSAid2hpdGUiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPW15Y29scykgKw0KICB0aGVtZV92b2lkKCkgKyANCiAgeGxpbSgwLjUsIDIuNSkrDQogIGxhYnMgKHRpdGxlID0gIk1hcnJpYWdlIFBhcnRpY2lwYW50cyBieSBSYWNlIikNCmBgYA0KIA0KIyMjIFBldGEgUG9ob24NCkJpYXNhbnlhIGRpZ3VuYWthbiB0ZXJoYWRhcCBLYXRlZ29yaWthbCBkYXRhIHlhbmcgbWVtaWxpa2kgYmFueWFrIHRpbmdrYXRhbg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRyZWVtYXBpZnkpDQpsaWJyYXJ5KHNjYWxlcykNCg0KcGxvdGRhdGEgPSBNYXJyaWFnZVpvZCAlPiUNCiAgY291bnQob2ZmaWNpYWxUaXRsZSkNCg0KZ2dwbG90KHBsb3RkYXRhLCBhZXMoZmlsbCA9IG9mZmljaWFsVGl0bGUsIGFyZWEgPSBuKSkrDQogIGdlb21fdHJlZW1hcCgpKw0KICBsYWJzKHRpdGxlID0gIiBNYXJyaWFnZSBQYXJ0aWNpcGFudHMgYnkgT2ZmaWNpYXRlIikNCmBgYA0KV2l0aCBMYWJlbHMNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0cmVlbWFwaWZ5KQ0KbGlicmFyeShzY2FsZXMpDQoNCnBsb3RkYXRhID0gTWFycmlhZ2Vab2QgJT4lDQogIGNvdW50KG9mZmljaWFsVGl0bGUpDQoNCmdncGxvdChwbG90ZGF0YSwgYWVzKGZpbGwgPSBvZmZpY2lhbFRpdGxlLCBhcmVhID0gbiwgbGFiZWwgPSBvZmZpY2lhbFRpdGxlKSkrDQogIGdlb21fdHJlZW1hcCgpKw0KICBnZW9tX3RyZWVtYXBfdGV4dChjb2xvcj0id2hpdGUiLCBwbGFjZSA9ICJjZW50cmUiKSsNCiAgbGFicyh0aXRsZSA9ICIgTWFycmlhZ2UgUGFydGljaXBhbnRzIGJ5IE9mZmljaWF0ZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQ0KYGBgDQoNCiMjIFZhcmlhYmVsIEtvbnRpbnUgIHsudGFic2V0IC50YWJzZXQtcGlsbHN9DQpCaWFzYW55YSBkYXRhIE51bWVyaWsgYXRhdSBBbmdrYSBkaWdhbWJhcmthbiBkZW5nYW4gSGlzdG9ncmFtLCBQbG90IERlbnNpdGFzIGtlcm5lbCwgZGFuIERpYWdyYW0gVGl0aWsgDQoNCiMjIyBIaXN0b2dyYW0gDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KE1hcnJpYWdlWm9kLCBhZXMoeD1hZ2UpKSArDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAib2xpdmVkcmFiNCIsIGNvbG9yID0gInJlZCIsIGJpbnMgPSAyMCkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIk1hcnJpYWdlIFBhcnRpY2lwYW50cyBieSBBZ2UgKGJhc2ljKSIsIHg9IkFnZSIpDQpgYGANCg0KQ2FyYSBtZW5ndWJhaCBCaW53aWR0aCBhdGF1IFJhbmdlIHlhbmcgZGl3YWtpbGkgb2xlaCBzYXR1IGJhdGFuZyBoaXN0b2dyYW0NCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQoNCmdncGxvdChNYXJyaWFnZVpvZCwgYWVzKHg9YWdlLCB5ID0gLi5jb3VudC4uL3N1bSguLmNvdW50Li4pKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gImRlZXBwaW5rMyIsIGNvbG9yID0gImN5YW4xIiwgYmlud2lkdGggPSA1KSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiTWFycmlhZ2UgUGFydGljaXBhbnRzIGJ5IEFnZSAoQWx0ZXJuYXRpdmUgQmluZHMgYW5kIGJhbmR3aWR0aHMpIiwgeD0iQWdlIiwgDQogICAgICAgeSA9ICJQZXJjZW50IikgKw0Kc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1wZXJjZW50KQ0KYGBgDQpEZW5nYW4gcGVyY2VudCBzZWJhZ2FpIHBlbmdnYW50aSBqdW1sYWggZnJla3VlbnNpDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc2NhbGVzKQ0KDQpnZ3Bsb3QoTWFycmlhZ2Vab2QsIGFlcyh4PWFnZSwgeSA9IC4uY291bnQuLi9zdW0oLi5jb3VudC4uKSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbCA9ICJsZW1vbmNoaWZmb24yIiwgY29sb3IgPSAib3JhbmdlcmVkMSIsIGJpbndpZHRoID0gNSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIk1hcnJpYWdlIFBhcnRpY2lwYW50cyBieSBBZ2UgKEFsdGVybmF0aXZlIEJpbmRzIGFuZCBiYW5kd2lkdGhzKSIsIHg9IkFnZSIsIA0KICAgICAgIHkgPSAiUGVyY2VudCIpICsNCnNjYWxlX3lfY29udGludW91cyhsYWJlbHM9cGVyY2VudCkNCmBgYA0KDQojIyMgUGxvdCBEZW5zaXR5IEtlcm5lbCANCg0KdmVyc2kgZGlwZXJoYWx1cyBkYXJpIEhpc3RvZ3JhbSANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpnZ3Bsb3QoTWFycmlhZ2Vab2QsIGFlcyh4PWFnZSkpICsNCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAicGx1bTMiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnModGl0bGUgPSAiTWFycmlhZ2UgUGFydGljaXBhbnRzIGJ5IEFnZSIpDQpgYGANCg0KQ2FyYSBNZW1iYWNhbnlhIGFkYWxhaCBkZW5nYW4gbWVuZ2hpdHVuZyBsdWFzIGRpYmF3YWgga3VydmEgZGFyaSByYW5nZSBhcmVhIHlhbmcgZGkgaW5naW5rYW4uDQoNCiMjIyBQYXJhbWV0ZXIgUGVuZ2hhbHVzYW4gKFNtb290aGluZykNCg0KTmlsYWkgZGliYXdhaCBkZWZhdWx0IGRlbmdhbiBmdW5nc2kgImJ3Lm5yZDAiIG1lbmdoYXNpbGthbiBwZW5naGFsdXNhbiBzZWRpa2l0LCBkYW4gbmlsYWkgeWFuZyBsZWJpaCBiZXNhciBkYXJpIGRlZmF1bHQgbWVuZ2hhc2lsa2FuIHBlbmdoYWx1c2FuIGxlYmloIGJhbnlhaw0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpidy5ucmQwKE1hcnJpYWdlWm9kJGFnZSkNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoTWFycmlhZ2Vab2QsIGFlcyh4PWFnZSkpICsNCiAgZ2VvbV9kZW5zaXR5IChmaWxsID0gImxpZ2h0cGluayIsIGJ3PTEpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyAodGl0bGUgPSAiUGFydGljaXBhbnRzIGJ5IEFnZSIsIHN1YnRpdGxlID0gIkJhbmR3aWR0aCA9IDEgIikNCmBgYA0KDQojIyMgRGlhZ3JhbSBUaXRpayAoRG90UGxvdCkNCg0KU2ViYWdhaSBBbHRlcm5hdGlmIGRhcmkgSGlzdG9ncmFtDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpnZ3Bsb3QoTWFycmlhZ2Vab2QsIGFlcyh4PWFnZSkpICsNCiAgZ2VvbV9kb3RwbG90KGZpbGwgPSAicGFsZXZpb2xldHJlZDMiLCBjb2xvciA9ICJhenVyZTQiLCBiaW53aWR0aD0yKSsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICBsYWJzICh0aXRsZSA9ICJQYXJ0aWNpcGFudHMgYnkgQWdlIiwgeCA9ICJBZ2UiICwgeT0iUHJvcG9ydGlvbiIgKQ0KDQpgYGANCg0KIyBEYXRhIEJpdmFyaWF0DQoNCkdyYWZpayB5YW5nIGRpcGVuZ2FydWhpIG9sZWggZHVhIHZhcmlhYmVsIHlhbmcgYmVyaHVidW5nYW4NCg0KIyMgS2F0ZWdvcmlrYWwgdnMgS2F0ZWdvcmlrYWwgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KS2VkdWFueWEgdGlkYWsgZGFwYXQgZGloaXR1bmcgYXRhdSBidWthbiBudW1lcmlrDQoNCiMjIyBEaWFncmFtIGJhdGFuZyBCZXJ0dW1wdWsgDQoNClBlcmJhbmRpbmdhbiBhbnRhcmEgS2VsYXMgTW9iaWwgZGFuIHBlbmdnZXJha255YSAoRnJvbnQsIHJlYXIsIGF0YXUgNFdEKQ0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCm1wZyRkcnYgPSBmYWN0b3IobXBnJGRydiwNCiAgICAgICAgICAgICAgICAgbGV2ZWxzPSBjKCJmIiwgInIiLCAiNCIpLA0KICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJGcm9udC13aGVlbCIsICJSZWFyLXdoZWVsIiwgIjQtd2hlZWwiKSkNCg0KIyBEaWFncmFtIEJhdGFuZyBCZXJ0dW1wdWsNCg0KZ2dwbG90KG1wZywgYWVzKHg9IGNsYXNzLCBmaWxsID0gZHJ2KSkrDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIGxhYnMoeT0iUHJvcG9ydGlvbiIpDQpgYGANCg0KIyMjIERpYWdyYW0gQmF0YW5nIERpa2Vsb21wb2trYW4gDQoNClZhcmlhYmVsIGthdGVnb3JpIHlhbmcgYmVyYmVkYSBkaWxldGFra2FuIGRpIGJhciB5YW5nIGJlcmJlZGENCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpnZ3Bsb3QobXBnLCBhZXMoeD1jbGFzcywgZmlsbCA9IGRydikpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgZ2VvbV9iYXIocG9zaXRpb249cG9zaXRpb25fZG9kZ2UocHJlc2VydmUgPSAic2luZ2xlIikpDQogIA0KYGBgDQoNCiMjIyBEaWFncmFtIGJhdGFuZyBzZWdtZW50YXNpDQoNCkt1cmFuZyBsZWJpaG55YSBtaWlycCBkZW5nYW4gZGlhZ3JhbSBiYXRhbmcgIGJlcnR1bXB1ayANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShzY2FsZXMpDQoNCiNSSW5na2FzYW4gZGF0YXNldA0KcGxvdGRhdGEgPSBtcGclPiUNCiAgZ3JvdXBfYnkoY2xhc3MsIGRydikgJT4lDQogIGRwbHlyOjpzdW1tYXJpemUgKG49IG4oKSkgJT4lDQogIG11dGF0ZShwY3QgPSBuL3N1bShuKSwNCiAgICAgICAgIGxibCA9IHNjYWxlczo6cGVyY2VudChwY3QpKQ0KDQpnZ3Bsb3QocGxvdGRhdGEsIGFlcyh4PWZhY3RvcihjbGFzcyksDQogICAgICAgICAgICAgICAgICAgIHk9cGN0LCANCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGZhY3RvcihkcnYpKSkrDQogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgcG9zaXRpb249ImZpbGwiKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDEsMC4yKSwgbGFiZWwgPSBwZXJjZW50KSsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1sYmwpLCBzaXplPSAzLCBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSkgKw0KICBzY2FsZV9maWxsX2JyZXdlciAocGFsZXR0ZT0iU2V0MiIpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnMoeT0nUGVyY2VudCcsIGZpbGwgPSAiRHJpdmV0cmFpbiIsIA0KICAgICAgIHg9ICJDbGFzcyIsIHRpdGxlID0gIkF1dG9tb2JpbGUgZHJpdmVzIGJ5IGNsYXNzIikrDQogIHRoZW1lX21pbmltYWwoKQ0KICANCmBgYA0KDQojIyMgTW96YWljIFBsb3QNCg0KTHVhcyBkYXJpIGFyZWEgbWVuZ2dhbWJhcmthbiBwcm9wb3JzaSBqdW1sYWgga2F0ZWdvcmlrYWwgZGVuZ2FuICBrb21iaW5hc2kgdGVydGVudHUgZGVuZ2FuIHdhcm5hIHViaW4geWFuZyBtZW51bmp1a2thbiBodWJ1bmdhbiBhbnRhciB2YXJpYWJlbC4gQ29udG9oIHBsb3QgZGVuZ2FuIGRhdGEgc3Vydml2YWwgVGl0YW5pYw0KDQpgYGB7cn0NCnRhYmVsID0geHRhYnMoRnJlcSB+IFN1cnZpdmVkICsgQ2xhc3MgKyBTZXgsIFRpdGFuaWMpDQpmdGFibGUodGFiZWwpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHZjZCkNCm1vc2FpYyh0YWJlbCwgbWFpbiA9ICJUaXRhbmljIGRhdGEiKQ0KYGBgDQoNCkRlbmdhbiBtZW1iZXJpIHdhcm5hIHBhZGEgdWJpbiBraXRhIGJpc2EgdGFodSBhcGFrYWggbmlsYWlueWEgc2VzdWFpIGRlbmdhbiB5YW5nIGRpaGFyYXBrYW4gamlrYSBiZXJsYWt1IHRpZGFrIHRlcmlrYXQNCg0KYGBge3J9DQptb3NhaWModGFiZWwsIHNoYWRlID0gVCwgbGVnZW5zID0gVCwgDQogICAgICAgbGFiZWxpbl9hcmdzID0gbGlzdChzZXRfdmFybmFtZXMgPSBjKFNleD0gIkdlbmRlciIsIFN1cnZpdmVzID0gIlN1cnZpdmVkIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENsYXNzID0gIlBBc3NlbmdlciBDbGFzcyIpKSwNCiAgICAgICBzZXQubGFiZWxzID0gbGlzdChTdXJ2aXZlZCA9IGMoIk5vIiwnWWVzJyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgIENsYXNzID0gYygiMXN0IiwgIjJuZCIsICIzcmQiLCAiQ3JldyIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIG1haW4gPSAiVGl0YW5pYyBEYXRhIg0KICAgICAgICkpDQpgYGANCg0KRGlsaWhhdCBkYXJpIHdhcm5hLCBsZWJpaCBiYW55YWsgQ3JldyBMYWtpLWxha2kgdGV3YXMgZGFuIFBlbnVtYmFuZyBXYW5pdGEgZGFyaSBrZXRpZ2Ega2VsYXMgeWFuZyBzZWxhbWF0IGRhbiBzZWJhbGlrbnlhLiBKYXVoIGxlYmloIHNlZGlraXQgcGVudW1wYW5nIEZpcnN0IGNsYXNzIHlhbmcgdGlkYWsgc2VsYW1hdCAgYmFpayBsYWtpLWxhaWtpIGF0YXUgcGVyZW1wdWFuLg0KDQojIyBLb250aW51IHZzIEtvbnRpbnUgey50YWJzZXQgLnRhYnNldC1waWxsc30NCg0KRHVhIHZhcmlhYmxlIG51bWVyaWsgYmlhc2FueWEgZGlnYW1iYXJrYW4gZGVuZ2FuIGdyYWZpayBzZWJhcmFuIHRpdGlrIGF0YXUgZyBhcmlzDQoNCiMjIyBTY2F0dGVyIFBsb3QNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGhyYnJ0aGVtZXMpDQoNCiNNYWtlIGEgRGF0YWZyYW1lDQpkMSA9IGRhdGEuZnJhbWUoeD1zZXEoMSwxMDApLA0KICAgICAgICAgICAgICAgIHk9cm5vcm0oMTAwKSwNCiAgICAgICAgICAgICAgICBuYW1lID0gIk5vIHRyZW5kIikNCg0KZDIgPSBkMSAlPiUNCm11dGF0ZSAoeSA9IHgqMTAgKyBybm9ybSAoMTAwLCBzZD02MCkpICU+JQ0KbXV0YXRlIChuYW1lID0gIkxpbmVhciByZWxhdGlvbnNoaXAgIikNCg0KZDMgPSBkMSAlPiUNCm11dGF0ZSh5PXheMiArIHJub3JtKDEwMCwgc2Q9MTQwKSkgJT4lDQptdXRhdGUgKG5hbWUgPSAiU3F1YXJlIikNCg0KZDQgPSBkYXRhLmZyYW1lKHg9c2VxKDEsMTAsIDAuMSksDQogICAgICAgICAgICAgICAgeT1zaW4oc2VxKDEsMTAsMC4xKSkrDQogICAgICAgICAgICAgICAgcm5vcm0oOTEsIHNkPSAwLjYpKSU+JQ0KbXV0YXRlKG5hbWUgPSAiU2luIikNCmRvbiA8LSBkby5jYWxsKHJiaW5kLCBsaXN0KGQxLCBkMiAsZDMsIGQ0KSkNCg0KZG9uICU+JQ0KICBnZ3Bsb3QoYWVzKHg9eCwgeT15KSkrDQogIGdlb21fcG9pbnQoY29sb3IgPSAiIzY5YjNhMiIsIGFscGhhID0gMC44KSsNCiAgdGhlbWVfaXBzdW0oKSsNCiAgZmFjZXRfd3JhcCh+bmFtZSwgc2NhbGUgPSAnZnJlZScpDQoNCmBgYA0KDQpDb250b2ggbGFpbiBkZW5nYW4gRGF0YSBQZW5nYWxhbWFuIEtlcmphIGRhbiBKdW1sYWggc2FsYXJ5DQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQpkYXRhKFNhbGFyaWVzLCBwYWNrYWdlPSJjYXJEYXRhIikNCg0KZ2dwbG90KFNhbGFyaWVzLCBhZXMoeD15cnMuc2luY2UucGhkLCB5ID0gc2FsYXJ5KSkrDQogIGdlb21fcG9pbnQoY29sb3IgPSAiYXF1YW1hcmluZTIiLCBzaXplID0gMiwgYWxwaGEgPSAuOCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMgKGxhYmVscyA9IHNjYWxlcyA6OmRvbGxhciwgbGltaXRzID0gYyg1MDAwMCwgMjUwMDAwKSkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzIChicmVha3MgPSBzZXEoMCw2MCwxMCksDQogICAgICAgICAgICAgICAgICAgICAgbGltaXRzPWMoMCw2MCkpKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzICh4ID0gIlllYXJzIHNpbmNlIFBoRCIsIA0KICAgICAgICB5ID0gIiIsDQogICAgICAgIHRpdGxlID0gICdFeHBlcmllbmNlIHZzIFNhbGFyeScsDQogICAgICAgIHN1YnRpdGxlID0gIjktTW9udGhzIFNhbGFyeSBmb3IgMjAwOC0yMDA5IikNCmBgYA0KDQojIyMgUGxvdCBTZWJhcmFuIE1lbnllc3VhaWthbiBHYXJpcyANCg0KUGxvdCBpbmkgZGlndW5ha2FuIGRlbmdhbiBiYXRhcyBrZXBlcmNheWFhbiBtZW5jYXBhaSA5NSUNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpnZ3Bsb3QoU2FsYXJpZXMsIGFlcyh4PXlycy5zaW5jZS5waGQsIHk9c2FsYXJ5KSkrDQogIGdlb21fcG9pbnQoY29sb3I9Im1hZ2VudGEiKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIGNvbG9yPSJicm93bjEiKSsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICBsYWJzKHg9IlllYXJzIFNpbmNlIFBoRCIsIHkgPSAiIiwgDQogICAgICAgIHRpdGxlID0gICdFeHBlcmllbmNlIHZzIFNhbGFyeScsDQogICAgICAgIHN1YnRpdGxlID0gIjktTW9udGhzIFNhbGFyeSBmb3IgMjAwOC0yMDA5IikNCmBgYA0KDQpCZW5hciBiYWh3YSBnYWppIGFrYW4gbWVuaW5na2F0IHNlamFsYW4gcGVuZ2FsYW1hbiAsIG5hbXVuIGFkYSBwZW51cnVuYW4ganVnYSwgZ2FyaXMgbHVydXMga3VyYW5nIHBhcyBsZWJpaCBjb2NvayBnYXJpcyBtZWxlbmdrdW5nLiBCaWFzYW55YSBnYXJpcyBtZWxlbmdrdW5mIGt1YWRyYXQgYXRhdSBwYW5na2F0IHRpZ2EgKGt1YmlrKS4gZ2FyaXMgcG9saW5vbWlhbCBsZWJpaCBkYXJpIGt1YmlrIGphcmFuZyBkaWd1bmFrYW4NCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpnZ3Bsb3QoU2FsYXJpZXMsIGFlcyh4PXlycy5zaW5jZS5waGQsIHk9c2FsYXJ5KSkrDQogIGdlb21fcG9pbnQoY29sb3I9Im1hZ2VudGEiKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsIA0KICAgICAgICAgICAgICBmb3JtdWxhID0geX5wb2x5KHgsMiksDQogICAgICAgICAgICAgIGNvbG9yPSJkYXJrb2xpdmVncmVlbjEiKSsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICBsYWJzKHg9IlllYXJzIFNpbmNlIFBoRCIsIHkgPSAiIiwgDQogICAgICAgIHRpdGxlID0gICdFeHBlcmllbmNlIHZzIFNhbGFyeScsDQogICAgICAgIHN1YnRpdGxlID0gIjktTW9udGhzIFNhbGFyeSBmb3IgMjAwOC0yMDA5IikNCmBgYA0KDQoNCg0KUGVuZ2hhbHVzYW4gUGxvdCBTZWJhcmFuDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdChTYWxhcmllcywgYWVzKHg9eXJzLnNpbmNlLnBoZCwgeT1zYWxhcnkpKSsNCiAgZ2VvbV9wb2ludChjb2xvcj0ibWFnZW50YSIsIHNpemUgPSAyLCBhbHBoYSA9IDEpKw0KICBnZW9tX3Ntb290aChzaXplID0gMSwgY29sb3I9ImRlZXBza3libHVlMSIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWwgPSBzY2FsZXMgOjogZG9sbGFyICwgDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDUwMDAwLCAyNTAwMDApKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLDYwLDEwKSwgDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsNjApKSsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICBsYWJzKHg9IlllYXJzIFNpbmNlIFBoRCIsIHkgPSAiIiwgDQogICAgICAgIHRpdGxlID0gICdFeHBlcmllbmNlIHZzIFNhbGFyeScsDQogICAgICAgIHN1YnRpdGxlID0gIjktTW9udGhzIFNhbGFyeSBmb3IgMjAwOC0yMDA5IikNCmBgYA0KDQoNCg0KIyMgS2F0ZWdvcmlrYWwgdnMgS29udGludSB7LnRhYnNldCAudGFic2V0LXBpbGxzfQ0KDQojIyMgRGlhZ3JhbSBCYXRhbmcgDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHNjYWxlcykNCmRhdGEoU2FsYXJpZXMsIHBhY2thZ2UgPSAiY2FyRGF0YSIpDQoNCnBsb3RkYXRhID0gU2FsYXJpZXMgJT4lDQogIGdyb3VwX2J5KHJhbmspJT4lDQogIGRwbHlyIDo6c3VtbWFyaXplKG1lYW5fc2FsYXJ5ID0gbWVhbihzYWxhcnkpKQ0KDQpteWNvbHMgPSBjKCIjQ0Q1MzRDRkYiLCAiI0VGQzAwMEZGIiwgIiMwMDczQzJGRiIpDQpnZ3Bsb3QocGxvdGRhdGEsIGFlcyh4PWZhY3RvcihyYW5rLCBsYWJlbHMgPSBjKCJBc3Npc3RhbnN0IFxuIFByb2Zlc3NvciIsICJBc3NvY2lhdGUgXG4gUHJvZmVzc29yIiwgIkZ1bGwgXG4gUHJvZmVzc29yIikpLA0KICAgICAgICAgICAgICAgICAgICAgeSA9IG1lYW5fc2FsYXJ5KSkrDQpnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGwgPSBteWNvbHMpICsNCmdlb21fdGV4dChhZXMobGFiZWwgPSBkb2xsYXIobWVhbl9zYWxhcnkpKSwgdmp1c3QgPSAtMC4yNSkrDQpzY2FsZV95X2NvbnRpbnVvdXMgKGJyZWFrcyA9IHNlcSgwLDEzMDAwMCwgMjAwMDApLCBsYWJlbCA9IGRvbGxhcikgKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnModGl0bGUgPSAiTWVhbiBTYWxhcnkgYnkgUmFuayIsDQogICAgICAgc3VidGl0bGUgPSAiOS1Nb250aCBhY2FkZW1pYyBzYWxhcnkgZm9yIDIwMDgtMjAwOSIsDQogICAgICAgeD0iIiwgeT0iIikNCg0KYGBgDQoNCiMjIyBQbG90IERFbnNpdGFzIEtlcm5lbCB5YW5nIGRpa2Vsb21wb2trYW4NCg0KYGBge3J9DQpnZ3Bsb3QoU2FsYXJpZXMsIGFlcyh4PXNhbGFyeSwgZmlsbCA9IHJhbmsgKSkrDQogIGdlb21fZGVuc2l0eShhbHBoYT0wLjQpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnModGl0bGUgPSAiU2FsYXJ5IERpc3RyaWJ1dGlvbnMgYnkgUmFuayIpDQpgYGANCg0KIyMjIEJveCBQbG90DQoNCkJveHBsb3QgbWVtYmVyaWthbiBraXRhIEZpdmUtTnVtYmVyIFN1bW1hcnkgZGFyaSBzdWF0dSBkYXRhDQoNCmBgYHtyfQ0KbXljb2xzID0gYygiI0NENTM0Q0ZGIiwgIiNFRkMwMDBGRiIsICIjMDA3M0MyRkYiKQ0KZ2dwbG90KFNhbGFyaWVzLCBhZXMoeD1yYW5rLCB5PXNhbGFyeSkpKw0KICBnZW9tX2JveHBsb3Qobm90Y2ggPSBULCBmaWxsID0gbXljb2xzLCBhbHBoYSA9IC43KSsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICBsYWJzKHRpdGxlID0gIlNhbGFyeSBEaXN0cmlidXRpb24gYnkgUmFuayIpDQogIA0KYGBgDQoNCiMjIyBWaW9saW4gUGxvdA0KTWlyaXAgZGVuZ2FuIERlbnNpdGFzIEtlcm5lbCwgeWFuZyBkaXB1dGFyIDkwIGRlcmFqYXQgZGFuIGRpTWlycm9yDQoNCmBgYHtyfQ0KZ2dwbG90KFNhbGFyaWVzLCBhZXMoeD1yYW5rLCB5ID0gc2FsYXJ5KSkrDQogIGdlb21fdmlvbGluKGZpbGwgPSAiYXp1cmUxIikrDQogIGdlb21fYm94cGxvdCh3aWR0aCA9IDAuMiwgDQogICAgICAgICAgICAgICBmaWxsID0gbXljb2xzLA0KICAgICAgICAgICAgICAgb3V0bGllci5jb2xvciA9ICJyZWQiLA0KICAgICAgICAgICAgICAgb3V0bGllci5zaXplPTIpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnModGl0bGUgPSAiU2FsYXJ5IERpc3RyaWJ1dGlvbiBieSBSYW5rIikNCmBgYA0KDQojIyMgUGxvdCBHYXJpcyBQdW5nZ3VuZyANCg0KTWlyaXAgZGVuZ2FuIFBsb3QgRGVuc2l0YXMgS2VybmVsLCBtZW5hbXBpbGthbiBkaXN0cmlidXNpIGt1YW50aXRhcyBkYXJpIGJlYmVyYXBhIGtlbG9tcG9rLiBkaWJ1YXQgZGVuZ2FuIExpYnJhcnkgZ2dyaWRnZXMuQ29udG9oIHBlbmdndW5hYWFuIGRlbmdhbiBkYXRhIEZ1ZWwgRWNvbm9teSANCg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdncmlkZ2VzKQ0KDQpnZ3Bsb3QobXBnLCBhZXMoeD1jdHksIHk9Y2xhc3MsDQogICAgICAgICAgICAgICAgZmlsbCA9IGNsYXNzKSkrDQogIGdlb21fZGVuc2l0eV9yaWRnZXMoYWxwaGE9MC43KSsNCiAgdGhlbWVfcmlkZ2VzKCkrDQogIGxhYnMoIkhpZ2h3YXkgTWlsZWFnZSBieSBBdXRvIENsYXNzIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCiAgDQpgYGANCg0KQXBhYmlsYSBEYXRhIHRlcmxhbHUgdHVtcGFuZyB0aW5kaWgsIGJpc2EgbWVuZ2VjaWxrYW4gb3BwYWNpdHkgYXRhdSB0cmFuc3BhcmFuc2kgZGVuZ2FuIG1lbmdlY2lsa2FuIG5pbGFpIEFscGhhDQoNCiMjIyBQbG90IEdhcmlzDQoNCkdhYnVuZ2FuIGRhcmkgQm94cGxvdCBkYW4gTGluZSBjaGFydCB5YW5nIG1lbmdodWJ1bmdrYW4gYW50YXIgcmF0YS1yYXRhIChUaXRpayBUZW5nYWggQm94cGxvdCkNCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ3JpZGdlcykNCg0KI01lbmdoaXR1bmcgTWVhbiwgU3RhRGV2LCBkYW4gOTUlIE5pbGFpIEtlcGVyY2F5YWFuIGJlcmRhc2Fya2FuIGphYmF0YW4NCg0KcGxvdGRhdGEgPSBTYWxhcmllcyAlPiUNCiAgZ3JvdXBfYnkocmFuaywgc2V4KSU+JQ0KICBkcGx5cjo6c3VtbWFyaXplKG49bigpLA0KICAgICAgICAgICAgICAgICAgIG1lYW4gPSBtZWFuKHNhbGFyeSksDQogICAgICAgICAgICAgICAgICAgc2Q9IHNkKHNhbGFyeSksIA0KICAgICAgICAgICAgICAgICAgIHNlID0gc2Qvc3FydChuKSwNCiAgICAgICAgICAgICAgICAgICBjaSA9IHF0KDAuOTc1LCBkZiA9IG4tMSkgKiBzZC9zcXJ0KG4pKQ0KDQpwZCA9IHBvc2l0aW9uX2RvZGdlKDAuMikNCmdncGxvdChwbG90ZGF0YSwgYWVzKHg9ZmFjdG9yKHJhbmssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBc3Npc3RhbnN0IFxuIFByb2Zlc3NvciIsICJBc3NvY2lhdGUgXG4gUHJvZmVzc29yIiwgIkZ1bGwgXG4gUHJvZmVzc29yIikpLCB5ID0gbWVhbiwgZ3JvdXAgPSBzZXgsIGNvbG9yID0gc2V4KSkrDQogIA0KICBnZW9tX3BvaW50KHBvc2l0aW9uID0gcGQsIHNpemUgPSAzKSArDQogIGdlb21fbGluZShwb3NpdGlvbiA9IHBkLCBzaXplID0gMSkrDQogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1zZSwgeW1heCA9IG1lYW4gKyBzZSksDQogICAgICAgICAgICAgICAgd2lkdGggPSAuMSAsIHBvc2l0aW9uID0gcGQsIHNpemUgPSAxKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVsID0gc2NhbGVzOjpkb2xsYXIpKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgbGFicyh0aXRsZSA9ICJNZWFuICBTYWxhcnkgYnkgUmFuayBhbmQgU2V4IiwNCiAgICAgICBzdWJ0aXRsZT0gIihtZWFuKy8tIHN0YW5kYXJkIGVycm9yKSIsDQogICAgICAgeD0gIiIsIHk9IiIsIGNvbG9yID0gIkdlbmRlciIpDQpgYGANCg0KIyMjIFN0cmlwIFBsb3QNCg0KU2NhdHRlciBQbG90IHlhbmcgZGlrZWxvbXBva2thbiwgYWdhayBzdXNhaCBkaWxpaGF0IGFwYWJpbGEgdGl0aWtueWEgZ295YWgNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHNjYWxlcykNCg0KZ2dwbG90KFNhbGFyaWVzLCBhZXMoeT1mYWN0b3IocmFuaywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFzc2lzdGFuc3QgXG4gUHJvZmVzc29yIiwgIkFzc29jaWF0ZSBcbiBQcm9mZXNzb3IiLCAiRnVsbCBcbiBQcm9mZXNzb3IiKSksIHg9IHNhbGFyeSwgY29sb3I9IHJhbmspKSsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjcsIHNpemUgPSAxLjUpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWw9ZG9sbGFyKSsNCiAgICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnModGl0bGUgPSAiQWNhZGVtaWMgU2FsYXJ5IGJ5IFJhbmsgIiwNCiAgICAgICBzdWJ0aXRsZT0gIjkgTW9udGhzIFNhbGFyeSBmb3IgMjAwMDgtMjAwOSAiLA0KICAgICAgIHg9ICIiLCB5PSIiKQ0KdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KICANCmBgYA0KDQojIyMgR2FidW5nYW4gSml0dGVyIGRhbiBQbG90IEtvdGFrIA0KDQpNZW5hbWJhaGthbiBwbG90IGtvdGFrIGtlIHBsb3QgSml0dGVyIG1lbXVkYWhrYW4gcHJlc2VudGFzaSBkaXN0cmlidXNpDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQpnZ3Bsb3QoU2FsYXJpZXMsIGFlcyh4PSBmYWN0b3IocmFuaywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFzc2lzdGFuc3QgXG4gUHJvZmVzc29yIiwgIkFzc29jaWF0ZSBcbiBQcm9mZXNzb3IiLCAiRnVsbCBcbiBQcm9mZXNzb3IiKSksIHkgPSBzYWxhcnkgLCBjb2xvciA9IHJhbmspKSsNCiAgZ2VvbV9ib3hwbG90KHNpemUgPSAxLCANCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSAxLA0KICAgICAgICAgICAgICAgb3V0bGllci5jb2xvciA9ICdibGFjaycsDQogICAgICAgICAgICAgICBvdXRsaWVyLnNpemUgPSAzKSsNCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjUsIA0KICAgICAgICAgICAgICB3aWR0aD0uMikrDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbD1kb2xsYXIpKw0KICAgIHRoZW1lX21pbmltYWwoKSsNCiAgbGFicyh0aXRsZSA9ICJBY2FkZW1pYyBTYWxhcnkgYnkgUmFuayAiLA0KICAgICAgIHN1YnRpdGxlPSAiOSBNb250aHMgU2FsYXJ5IGZvciAyMDA4LTIwMDkgIiwNCiAgICAgICB4PSAiIiwgeT0iIikrDQp0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKw0KICBjb29yZF9mbGlwKCkNCiAgDQpgYGANCg0KRGFsYW0gZ2VvX2JveGppdHRlciBraXRhIGJpc2EgbWVtYnVhdCBwbG90IGh5YnJpZCBrb3RhayBkYW4gc2ViYXJhbiBkYWxhbSBsaWJyYXJ5IGdncG9sDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGdncG9sKQ0KDQpnZ3Bsb3QoU2FsYXJpZXMsIGFlcyh4PSBmYWN0b3IocmFuaywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkFzc2lzdGFuc3QgXG4gUHJvZmVzc29yIiwgIkFzc29jaWF0ZSBcbiBQcm9mZXNzb3IiLCAiRnVsbCBcbiBQcm9mZXNzb3IiKSksIHkgPSBzYWxhcnkgLGZpbGwgPSByYW5rKSkrDQogIGdlb21fYm94aml0dGVyKGNvbG9yID0gJ2JsYWNrJywgDQogICAgICAgICAgICAgICAgIGppdHRlci5jb2xvciA9ICJkYXJrZ3JleSIsDQogICAgICAgICAgICAgICAgIGVycm9yYmFyLmRyYXcgPSBUKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVsPWRvbGxhcikrDQogIGxhYnModGl0bGUgPSAiQWNhZGVtaWMgU2FsYXJ5IGJ5IFJhbmsgIiwNCiAgICAgICBzdWJ0aXRsZT0gIjkgTW9udGhzIFNhbGFyeSBmb3IgMjAwOC0yMDA5ICIsDQogICAgICAgeD0gIiIsIHk9IiIpKw0KICAgIHRoZW1lX21pbmltYWwoKSsNCnRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQojIyMgUGxvdCBLYXdhbmFuIExlYmFoDQoNCk1pcmlwIGRlbmdhbiBQbG90IEJpb2xhIGRhbiBQbG90IEppdHRlci4gTWVudW5qdWtrYW4gZGlzdHJpYnVzaSB2YXJpYWJlbCBrdWFudGl0YXRpZiBkYW4gZGVuc2l0YXMgdGlhcCB0aXRpaw0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeShnZ2JlZXN3YXJtKSAjbWVuZ3VyYW5naSB0dW1wYW5nIHRpbmRpaCANCg0KZ2dwbG90KFNhbGFyaWVzLCBhZXMoeD0gZmFjdG9yKHJhbmssDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJBc3Npc3RhbnN0IFxuIFByb2Zlc3NvciIsICJBc3NvY2lhdGUgXG4gUHJvZmVzc29yIiwgIkZ1bGwgXG4gUHJvZmVzc29yIikpLCB5ID0gc2FsYXJ5ICxjb2xvciA9IHJhbmspKSsNCmdlb21fcXVhc2lyYW5kb20oYWxwaGEgPSAwLjcsIHNpemUgPSAxLjUpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWw9ZG9sbGFyKSsNCiAgbGFicyh0aXRsZSA9ICJBY2FkZW1pYyBTYWxhcnkgYnkgUmFuayAiLA0KICAgICAgIHN1YnRpdGxlPSAiOSBNb250aHMgU2FsYXJ5IGZvciAyMDA4LTIwMDkgIiwNCiAgICAgICB4PSAiIiwgeT0iIikrDQogICAgdGhlbWVfbWluaW1hbCgpKw0KdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCiMjIyBEaWFncmFtIFRpdGlrIENsZXZlbGFuZA0KDQpEaWd1bmFrYW4ga2V0aWthIG1lbWJhbmRpbmdrYW4gc3RhdGlzdGlrIG51bWVyaWsgc2VqdW1sYWgga2Vsb21wb2suIERpc2VidXQganVnYSBMb2xpcG9wIEdyYXBoLiBDb250b2hueWEgZGF0YSBkYXJpIGdhcG1pbmRlciB0ZW50YW5nIGhhcmFwYW4gaGlkdXAgZGkgQXNpYQ0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkoZ2diZWVzd2FybSkNCmxpYnJhcnkoZ2FwbWluZGVyKQ0KZGF0YShnYXBtaW5kZXIsIHBhY2thZ2UgPSAiZ2FwbWluZGVyIikNCg0KI1N1YnNldCBoYW55YSBkYXRhIFJlZ2lvbiBBc2lhDQpsaWJyYXJ5KGRwbHlyKQ0KcGxvdGRhdGEgPSBnYXBtaW5kZXIlPiUNCiAgZmlsdGVyKGNvbnRpbmVudCA9PSAnQXNpYScgJiB5ZWFyID09IDIwMDcpDQoNCiNQbG90IENsZXZlbGFuZA0KZ2dwbG90KHBsb3RkYXRhLCBhZXMoeD1saWZlRXhwLCB5PXJlb3JkZXIoY291bnRyeSwgbGlmZUV4cCkpKSsNCiAgZ2VvbV9wb2ludChjb2xvcj0nbmF2eScsIHNpemU9MikrDQogIGdlb21fc2VnbWVudChhZXMoeD00MCwNCiAgICAgICAgICAgICAgICAgIHhlbmQgPSBsaWZlRXhwLA0KICAgICAgICAgICAgICAgICAgeT1yZW9yZGVyKGNvdW50cnksIGxpZmVFeHApLA0KICAgICAgICAgICAgICAgICAgeWVuZD1yZW9yZGVyKGNvdW50cnksIGxpZmVFeHApKSwgY29sb3IgPSAnYXp1cmUzJykgKw0KICBsYWJzICh4ID0gIkxpZmUgRXhwZWN0YW5jeSAoeWVhcnMpIiwNCiAgICAgICAgeSA9ICIiLA0KICAgICAgICB0aXRsZSA9ICJMaWZlIEV4cGVjdGFuY3kgYnkgQ291bnRyaWVzIiwNCiAgICAgICAgc3VidGl0bGUgPSAiR2FwTWluZGVyIGRhdGEgZm9yIEFzaWEgLSAyMDA3IikrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSkNCg0KYGBgDQoNCiMgRGF0YSBNdWx0aXZhcmlhdA0KR3JhZmlrIE11bHRpdmFyaWF0IG1lbXByZXNlbnRhc2lrYW4gIGh1YnVuZ2FuIGFudGFyYSBsZWJpaCBkYXJpIGR1YSB2YXJpYWJlbCwgc2VwZXJ0aSBtZW1iYW5kaW5na2FuIGxlYmloIGRhcmkgZHVhIGdyYWZpayAuIFBhZGEgTXVsdGl2YXJpYXQgaW5pLCB0ZXJkYXBhdCBkdWEgbWV0b2RlIHVtdW0geWFpdHUgcGVuZ2Vsb21wb2thbiBkYW4gZmFjZXRpbmcuDQoNCiMjIFBlbmdlbG9tcG9rYW4NCk5pbGFpIGRhcmkgZHVhIHZhcmlhYmVsIHBlcnRhbWEgZGlwZXRha2FuIGtlIHN1bWJ1IHggZGFuIHkgdmFyaWFiZWwgdGFtYmFoYW4ganVnYSBkaWdhbWJhcmthbiBzZXNhdWFpIGthcmFrdGVyaXN0aWsgdmlzdWFsbnlhLCBzZXBlcnRpIHdhcm5hLCBiZW50dWssIHVrdXJhbiwgamVuaXMgZ2FyaXMsIGRhbiB0cmFuc3BhcmFuc2kuIFBlbmdlbG9tcG9rYW4ganVnYSBtZW1wbG90IGxlYmloIGRhcmkgZHVhIGRhdGEga2UgZGFsYW0gc3VhdHUgZ3JhZmlrLg0KQ29udG9obnlhIGFkYWxhaCBkZW5nYW4ga2l0YSBpbmdpbiBtZW1wbG90IGRhdGEgbWVuZ2d1bmFrYW4gZGF0YSBzZXQgU2FsYXJpZXMsIG1hcmkga2l0YSB0YW1waWxrYW4gaHVidW5nYW4gYW50YXJhIHlycy5zaW5jZS5waGQgZGFuIHNhbGFyeS4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoY2FyRGF0YSkNCmxpYnJhcnkgKGdncGxvdDIpDQpkYXRhKFNhbGFyaWVzLCBwYWNrYWdlPSJjYXJEYXRhIikgDQoNCmdncGxvdChTYWxhcmllcywgYWVzKHggPSB5cnMuc2luY2UucGhkLA0KeSA9IHNhbGFyeSwNCmNvbG9yPXJhbmspKSArDQogIGdlb21fcG9pbnQoKSArDQogIHRoZW1lX21pbmltYWwoKSArIA0KICBsYWJzKHRpdGxlID0gIkFjYWRlbWljIHNhbGFyeSBieSByYW5rIGFuZCB5ZWFycyBzaW5jZSBkZWdyZWUiKQ0KYGBgDQoNClNlbGFuanV0bnlhLCB0YW1iYWhrYW4gamVuaXMga2VsYW1pbiBwcm9mZXNvciwgbWVuZ2d1bmFrYW4gYmVudHVrIHRpdGlrIHlhbmcgYmVyYmVkYSAgdW50dWsgbWVudW5qdWtrYW4gamVuaXMga2VsYW1pbi4gTGFsdSAgbWVuaW5na2F0a2FuIHVrdXJhbiB0aXRpayBkYW4gbWVuYW1iYWhrYW4gdHJhbnNwYXJhbnNpIHVudHVrIG1lbXBlcmplbGFzIG1hc2luZy1tYXNpbmcgdGl0aWsgLg0KDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KFNhbGFyaWVzLCBhZXMoeCA9IHlycy5zaW5jZS5waGQsDQp5ID0gc2FsYXJ5LCANCmNvbG9yID0gcmFuaywNCnNoYXBlID0gc2V4KSkgKyANCmdlb21fcG9pbnQgKHNpemUgPSAzLCBhbHBoYSA9IC42KSArIA0KdGhlbWVfbWluaW1hbCgpICsgDQpsYWJzKHRpdGxlID0gIkFjYWRlbWljIHNhbGFyeSBieSByYW5rLCBzZXgsIGFuZCB5ZWFycyBzaW5jZSBkZWdyZWUiKQ0KYGBgDQoNCkdyYWZpayBzZXBlcnRpbnlhIHRlcmxhbHUgcmFtYWksIEZBY2V0aW5nIGFrYW4gbGViaWggY29jb2suIFBlbWV0YWFuIHZhcmlhYmVsIGFkYSBkYWxhbSBmdW5nc2kgYWVzIGRhbiBuaWxhaSBrb25zdGFudGEgbGFpbiBkaSBsdWFybnlhLiANCkJlcmlrdXQgUGxvdCBHZWxlbWJ1bmcgZGVuZ2FuIGJlc2FyIGdlbGVtYnVuZyBtZW5lbnR1a2FuIGxhbWEgbnlhIHBlbmdhbGFtYW4ga2VyamEuDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KFNhbGFyaWVzLCBhZXMoeCA9IHlycy5zaW5jZS5waGQsDQp5ID0gc2FsYXJ5LCANCmNvbG9yID0gcmFuaywNCnNpemUgPSB5cnMuc2VydmljZSkpICsgDQpnZW9tX3BvaW50IChhbHBoYSA9IC44KSArIA0KdGhlbWVfbWluaW1hbCgpICsgDQpsYWJzKHRpdGxlID0gIkFjYWRlbWljIHNhbGFyeSBieSByYW5rLCBzZXgsIGFuZCB5ZWFycyBzaW5jZSBkZWdyZWUiKQ0KYGBgDQoNCkRhcmkgZ3JhZmlrIGRpIGF0YXMsICBtZW5qZWxhc2thbiBiYWh3YSBsYW1hICBzZXRlbGFoIG1lbnlhbmRhbmcgIFBoLkQgZGFuIGphYmF0YW4gYmVya29yZWxhc2kgcG9zaXRpZi4NClNlYmFnYWkgY29udG9oIHRlcmFraGlyLCBwcmVzZW50YXNpIGRhdGEgIHlycy5zaW5jZS5waGQgdnMuIHNhbGFyeSBkYW4gdGFtYmFoa2FuIGplbmlzIGtlbGFtaW4gbWVuZ2d1bmFrYW4gd2FybmEgZGFuIGdhcmlzIGt1YWRyYXQgeWFuZyBwYWxpbmcgY29jb2suDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpnZ3Bsb3QoU2FsYXJpZXMsDQphZXMoeCA9IHlycy5zaW5jZS5waGQsDQp5ID0gc2FsYXJ5LA0KY29sb3IgPSBzZXgpKSArIA0KICANCmdlb21fcG9pbnQoYWxwaGEgPSAuNCwNCnNpemUgPSAzKSArDQogIA0KIGdlb21fc21vb3RoKHNlPUZBTFNFLA0KbWV0aG9kID0gImxtIiwgDQpmb3JtdWxhID0geX5wb2x5KHgsMiksDQpzaXplID0gMS41KSArIA0KbGFicyh4ID0gIlllYXJzIFNpbmNlIFBoLkQuIiwNCnRpdGxlID0gIkFjYWRlbWljIFNhbGFyeSBieSBTZXggYW5kIFllYXJzIEV4cGVyaWVuY2UiLCANCnN1YnRpdGxlID0gIjktbW9udGggc2FsYXJ5IGZvciAyMDA4LTIwMDkiLA0KIHkgPSAiICIsDQpjb2xvciA9ICJTZXgiKSArDQogc2NhbGVfeV9jb250aW51b3VzKGxhYmVsID0gc2NhbGVzOjpkb2xsYXIpICsgDQogIHNjYWxlX2NvbG9yX2JyZXdlciAocGFsZXR0ZSA9ICJTZXQxIikgKw0KIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiMjIEZhY2V0aW5nIGF0YXUgcGVtYmFnaWFuIGZhc2V0DQoNCk1lbWJhbmRpbmdrYW4gZ3JhZmlrIHNhdHUgZGVuZ2FuIHlhbmcgbGFpbm55YSBkZW5nYW4geCBkYW4geSBhdGF1IHggZGFuIHkgZGVuZ2FuIGphbmdrYXVhbiB5YW5nIHNhbWEgDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQpnZ3Bsb3QoU2FsYXJpZXMsDQphZXMoeCA9IHNhbGFyeSkpICsgDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAia2hha2kzIiwgY29sb3IgPSAnd2hpdGUnKSsNCiAgZmFjZXRfd3JhcCh+cmFuaywgbmNvbD0xKSArIA0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnModGl0bGUgPSAiU2FsYXJ5IEhpc3RvZ3JhbXMgYnkgcmFuayIpDQpgYGANCg0KIEZhY2V0X3dyYXAgYmVyZnVuZ3NpIHNlYmFnYWkgcGVtaXNhaCBncmFmaWsgZGFuIG9wc2kgbmNvbCBzZWJhZ2FpIHBlbmdhdHVyIGp1bWxhaCBrb2xvbS4NCiBEaSBDT250b2gga2VkdWEgbWVuZ2d1bmFrYW4gMiB2YXJpYWJlbCBzZWJhZ2FpIGZhY2V0IHlhaXR1IGplbmlzIGtlbGFtaW4gZGFuIGphYmF0YW4uDQogDQpgYGB7cn0NCmxpYnJhcnkoY2FyRGF0YSkNCmxpYnJhcnkoZ2dwbG90MikNCg0KZ2dwbG90KFNhbGFyaWVzLA0KYWVzKHggPSBzYWxhcnkvMTAwMCkpICsgDQogIGdlb21faGlzdG9ncmFtKGZpbGwgPSAibWVkaXVtcHVycGxlMyIsIGNvbG9yID0gJ3doaXRlJykrDQogIGZhY2V0X2dyaWQoc2V4fnJhbmspICsgDQogIHRoZW1lX21pbmltYWwoKSsNCiAgbGFicyh0aXRsZSA9ICJTYWxhcnkgSGlzdG9ncmFtcyBieSBTZXggYW5kIHJhbmsiLA0KICAgICAgIHggPSAiU2FsYXJ5KCQxMDAwKSIpDQpgYGANCiANCiANCkNvbnRvaG55YSAgbWVuZ2d1bmFrYW4gUGxvdCBNZWFuL1NFIGRhbiBwZW1iYWdpYW4gZmFzZXQgdW50dWsgbWVtYmFuZGluZ2thbiBnYWppZ2FqaSBkYXJpIHByb2Zlc29yIHByaWEgZGFuIHdhbml0YSwgZGFsYW0gamFiYXRhbiBkYW4gZGlzaXBsaW4gaWxtdS4gS2l0YSBha2FuIG1lbmdndW5ha2FuIHdhcm5hIHVudHVrIG1lbWJlZGFrYW4gamVuaXMga2VsYW1pbiBkYW4gcGVtYmFnaWFuIGZhc2V0IHVudHVrIG1lbWJ1YXQgcGxvdGphYmF0YW4gYmVyZGFzYXJrYW4ga29tYmluYXNpIGRpc2lwbGluIGlsbXUuDQoNCmBgYHtyfQ0KbGlicmFyeShjYXJEYXRhKSANCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkgKGRwbHlyKQ0KDQojTWVuZ2hpdHVuZyBSYXRhLXJhdGEgZGFuIEtlc2FsYWhhbiBTdGFuZGFyDQpwbG90ZGF0YSA8LSBTYWxhcmllcyAlPiUNCmdyb3VwX2J5IChzZXgsIHJhbmssIGRpc2NpcGxpbmUpICU+JSANCmRwbHlyIDo6IHN1bW1hcml6ZSAobiA9IG4oKSwNCm1lYW4gPSBtZWFuKHNhbGFyeSksIA0Kc2QgPSBzZChzYWxhcnkpLCANCnNlID0gc2QgLyBzcXJ0KG4pKQ0KDQojTWVtYnVhdCBsYWJlbCB5YW5nIGxlYmloIGJhaWsgdW50dWsgZGlzaXBsaW4gaWxtdSANCiBwbG90ZGF0YSRkaXNjaXBsaW5lIDwtIGZhY3RvcihwbG90ZGF0YSRkaXNjaXBsaW5lLA0KbGFiZWxzID0gYygiVGhlb3JldGljYWwiLA0KIkFwcGxpZWQiKSkgDQoNCiAjTWVtYnVhdCBQbG90DQogDQpnZ3Bsb3QocGxvdGRhdGEsDQphZXMoeCA9IHNleCwNCnkgPSBtZWFuLA0KY29sb3IgPSBzZXgpKSArIA0KZ2VvbV9wb2ludChzaXplID0gMykgKyANCmdlb21fZXJyb3JiYXIoYWVzICh5bWluID0gbWVhbiAtIHNlLA0KeW1heCA9IG1lYW4gKyBzZSksDQp3aWR0aCA9IC4xKSArIA0Kc2NhbGVfeV9jb250aW51b3VzIChicmVha3MgPSBzZXEoNzAwMDAsIDE0MDAwMCwgMTAwMDApLA0KbGFiZWwgPSBzY2FsZXM6OmRvbGxhcikgKyANCiAgDQpmYWNldF9ncmlkKC5+IHJhbmsgKyBkaXNjaXBsaW5lKSArIA0KdGhlbWVfYncoKSArIA0KdGhlbWUgKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCnBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwNCnBhbmVsLmdyaWQubWlub3IueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgbGFicyh4PSIiLA0KeT0iIiwgDQp0aXRsZT0iTmluZSBtb250aCBhY2FkZW1pYyBzYWxhcmllcyBieSBnZW5kZXIsIGRpc2NpcGxpbmUsIGFuZCByYW5rIiwNCnN1YnRpdGxlID0gIihNZWFucyBhbmQgc3RhbmRhcmQgZXJyb3JzKSIpICsgc2NhbGVfY29sb3JfYnJld2VyIChwYWxldHRlPSJTZXQxIikNCiANCmBgYA0KDQoxLiBmYWNldF9ncmlkKH5yYW5rK2RpY2lwbGluZSkgdGlkYWsgbWVuZW50dWthbiB2YXJpYWJlbCBiYXJpcyBrb21iaW5hc2kgamFiYXRhbiBkYW4gZGlzaXBsaW4gaWxtdS4NCjIuIHRoZW1lKCkgLT4gbWVtYnVhdCB0ZW1hIGhpdGFtIGRhbiBwdXRpaCwgbWVuZ2hpbGFuZ2thbiBnYXJpcyBncmlkIHZlcnRpa2FsLCBkYW4gZ2FyaXMgZ3JpZA0KaG9yaXpvbnRhbCBtaW5vci4NCjMuIHNjYWxlX2NvbG9yX2JyZXdlcigpIC0+IG1lbmd1YmFoIHNrZW1hIHdhcm5hIHVudHVrIHRpdGlrIGRhbiBiYXRhbmcgYmF0YW5nIGtlc2FsYWhhbi4NCg0KS2FsYXUgZGlsaWhhdCwgYWRhbnlhIHBlcmJlZGFhbiBhbnRhcmEgZ2VuZGVyIGRhbiBnYWppIEFzc29jaWF0ZSBkYW4gRnVsbCBQcm9mZXNzb3JzIGRpIGJpZGFuZyB0ZW9yaXRpcy4gaW5pIGJpc2EgdGVyamFkaSBrYXJlbmEga2l0YSB0aWRhayBtZWxpaGF0ICBzZWNhcmEgbGFuZ3N1bmcgbWVuZ2FwYSBhZGEgcGVyYmVkYWFuIHRlcnNlYnV0LiBNdW5na2luIGRpcGVybHVrYW4gcGVyY29iYWFuIHNlY2FyYSBsYW5nc3VuZyBhZ2FyIGtpdGEgbWVuZ2V0YWh1aSAuDQoNCkNvbnRvaCB0ZXJha2hpciwga2l0YSBjb2JhIG1lbmdndW5ha2FuIGRhdGFzZXQgYmFydSBkYW4gbWVtcGxvdCBwZXJ1YmFoYW4gZGFsYW0gaGFyYXBhbiBoaWR1cCBkYXJpIHdha3R1IGtlIHdha3R1IHVudHVrIG5lZ2FyYS1uZWdhcmEgZGkgQXNpYS4gRGF0YSB0ZXJzZWJ1dCBiZXJhc2FsIGRhcmkgZGF0YXNldCBnYXBtaW5kZXIgZGFsYW0gcGFja2FnZSBnYXBtaW5kZXIuIFNldGlhcCBuZWdhcmEgYWthbiBtdW5jdWwgZGFsYW0gZmFzZXRueWEgc2VuZGlyaS4NCg0KRnVuZ3NpIHRlbWEgLT4gbWVueWVkZXJoYW5ha2FuIHdhcm5hIGxhdGFyIGJlbGFrYW5nLCBtZW11dGFyIHRla3Mgc3VtYnUgeCwgZGFuIG1lbXBlcmtlY2lsIHVrdXJhbiB0dWxpc2FuDQoNCmBgYHtyfQ0KbGlicmFyeShnYXBtaW5kZXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5IChkcGx5cikNCg0KDQojIG1lbXBsb3QgaGFyYXBhbiBoaWR1cCBiZXJkYXNhcmthbiB0YWh1biBzZWNhcmEgdGVycGlzYWggIHVudHVrIHNldGlhcCBuZWdhcmEgZGkgQXNpYSANCmRhdGEoZ2FwbWluZGVyLCBwYWNrYWdlID0gImdhcG1pbmRlciIpDQoNCiAjIFBpbGloIGRhdGEgQXNpYSANCnBsb3RkYXRhIDwtIGRwbHlyOjpmaWx0ZXIgKGdhcG1pbmRlciwNCmNvbnRpbmVudCA9PSAiQXNpYSIpIA0KIyBtZW1wbG90IGhhcmFwYW4gaGlkdXAgYmVyZGFzYXJrYW4gdGFodW4sIHVudHVrIHNldGlhcCBuZWdhcmEgDQpnZ3Bsb3QocGxvdGRhdGEsIGFlcyAoeD15ZWFyLCB5ID0gbGlmZUV4cCkpICsNCmdlb21fbGluZSAoY29sb3I9ImdyZXkiKSArIA0KICBnZW9tX3BvaW50KGNvbG9yPSJibHVlIikgKyANCmZhY2V0X3dyYXAofmNvdW50cnkpICsgDQp0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDkpICsgDQp0aGVtZSAoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwNCmhqdXN0ID0gMSkpICsNCiBsYWJzICh0aXRsZSA9ICJDaGFuZ2VzIGluIExpZmUgRXhwZWN0YW5jeSIsDQp4ID0gIlllYXIiLCB5ID0gIkxpZmUgRXhwZWN0YW5jeSIpDQpgYGANCg0KIyBSZWZlcmVuc2kgDQoxKS4gIGh0dHBzOi8vd3d3LnJwdWJzLmNvbS9kc2NpZW5jZWxhYnMvYXNkMTM=