Libraries

library(tidyverse)
library(ggpubr)
library(gridExtra)
library(forecast)
library(scales)
library(fmsb)
# library(sn)
# library(modeest)
# library(fpp)

Intro to Descriptive Statistics

# Create vector classA and classB
classA <- c(102,128,131,98,140,93,110,115,109,89,106,119,97)
classB <- c(127,131,96,80,93,120,109,162,103,111,109,87,105)

# Calculate the mean for each class
mean(classA)
[1] 110.5385
mean(classB)
[1] 110.2308

Types of Data

Summarizing Data

Mean

# See-saw illustration
see_saw <- c(93,106,131)
mean(see_saw)
[1] 110

# Density plot
set.seed(123)
income <- rnorm(50, mean = 50, sd = 5)
p1 <- ggplot(data = data.frame(income), aes(income)) + 
        geom_density(fill = "red", alpha = 0.1) +
        geom_vline(xintercept = mean(income), 
                   linetype="dotted", 
                   color = "red", size=1.5)
p1

mean(income)
[1] 50.17202
# Outlier affects mean
income_outlier <- c(income,100,100,100,100,100,100)
p2 <- ggplot(data = data.frame(income = income_outlier), aes(income)) + 
      geom_density(fill = "red", alpha = 0.1) +
        geom_vline(xintercept = mean(income_outlier), linetype="dotted", 
                   color = "red", size=1.5)
p2

mean(income_outlier)
[1] 55.51073
# Normal data
set.seed(123)
sample_normal <- rnorm(n = 10000, mean = 0, sd = 1)

# Skew Normal data
set.seed(123)
sample_sn <- sn::rsn(n=10000, xi=0, omega=1, alpha=10, tau=0)

# Create density plots
p3 <- ggplot(data = data.frame(x = sample_normal), aes(x=x)) + 
        geom_density(fill = "red", alpha = 0.1) +
        geom_vline(xintercept = mean(sample_normal), linetype="dotted", 
                   color = "red", size=1) +
        ggtitle("Normal Distribution")
      
p4 <- ggplot(data = data.frame(x = sample_sn), aes(x=x)) + 
        geom_density(fill = "red", alpha = 0.1) +
        geom_vline(xintercept = mean(sample_sn), linetype="dotted", 
                   color = "red", size=1) +
        ggtitle("Skew Normal Distribution")

grid.arrange(p3,p4, ncol=1)

Median

grid.arrange(p1 + geom_vline(xintercept = median(income), linetype="dotted", 
                             color = "blue", size=1.5),
             p2 + geom_vline(xintercept = median(income_outlier), 
                             linetype="dotted", color = "blue", size=1.5))

summary(income)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  40.17   47.20   49.64   50.17   53.49   60.84 
summary(income_outlier)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  40.17   47.53   50.60   55.51   54.41  100.00 
grid.arrange(p3 + geom_vline(xintercept = median(sample_normal), 
                             linetype="dotted", color = "blue", size=1),
             p4 + geom_vline(xintercept = median(sample_sn), 
                             linetype="dotted", color = "blue", size=1))

summary(sample_normal)
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
-3.845320 -0.667969 -0.011089 -0.002372  0.673347  3.847768 
# Quartile examples
sample_quart <- quantile(sample_normal,probs = c(0.25, 0.5, 0.75))
sample_quart
        25%         50%         75% 
-0.66796903 -0.01108922  0.67334733 
# Percentile examples
sample_percent <- quantile(sample_normal,probs = seq(0.1,0.9,by=0.1))
sample_percent
        10%         20%         30%         40%         50%         60%         70%         80%         90% 
-1.27943893 -0.83997128 -0.51872750 -0.24831290 -0.01108922  0.24768364  0.51856015  0.84214001  1.26280398 
# Density plot with quartiles
p5 <- ggplot(data = data.frame(x = sample_normal), aes(x=x)) + 
        geom_density(fill = "red", alpha = 0.1) +
        geom_vline(xintercept = sample_quart, linetype="dotted", 
                   color = "red", size=1) +
        ggtitle("Normal Distribution")
p5

Mode

classAB <- c(classA, classB)
modeest::mfv(classAB)
[1] 109

Range

# Calculate range
range(classA)
[1]  89 140
range(classB)
[1]  80 162
range(classA)[2] - range(classA)[1]
[1] 51
range(classB)[2] - range(classB)[1]
[1] 82

Interquartile Range

# Calculate quartiles
income_outlier_quart <- quantile(income_outlier,probs = c(0.25, 0.5, 0.75),
                                 names = FALSE)

# Density plot with quartiles
p6 <- ggplot(data = data.frame(income = income_outlier), aes(income)) + 
      geom_density(fill = "red", alpha = 0.1) +
        geom_vline(xintercept = income_outlier_quart, linetype="dotted", 
                   color = "red", size=1)
p6

# Range of income_outlier
range(income_outlier)[2] - range(income_outlier)[1]
[1] 59.83309
# Interquartile range of income_outlier
income_outlier_quart[3] - income_outlier_quart[1]
[1] 6.879677

Variance and Standard Deviation

set.seed(123)
sample_multinormal <- data.frame(type = as.factor(c(rep(4:6,each=10000))),
                                 data = c(rnorm(10000,0,4),
                                          rnorm(10000,0,5),
                                          rnorm(10000,0,6)))

p7 <- ggplot(data = sample_multinormal, aes(x = data, fill = type, colour = type)) +
        geom_density(alpha = 0.2)
p7

# Comparing MLE variance (denominator n) and and unbiased variance (denominator n-1)

# n = 10
set.seed(123)
sample1 <- rnorm(10, mean = 0, sd = 2)

# Unbiased variance
sd(sample1)^2
[1] 3.638816
# MLE variance
sd(sample1)^2 * (length(sample1)-1)/length(sample1)
[1] 3.274934
# n = 30
set.seed(123)
sample2 <- rnorm(30, mean = 0, sd = 2)

# Unbiased variance
sd(sample2)^2
[1] 3.849685
# MLE variance
sd(sample2)^2 * (length(sample2)-1)/length(sample2)
[1] 3.721362
# n = 100
set.seed(123)
sample3 <- rnorm(100, mean = 0, sd = 2)

# Unbiased variance
sd(sample3)^2
[1] 3.332931
# MLE variance
sd(sample3)^2 * (length(sample3)-1)/length(sample3)
[1] 3.299602
# n = 1000
set.seed(123)
sample4 <- rnorm(1000, mean = 0, sd = 2)

# Unbiased variance
sd(sample4)^2
[1] 3.933836
# MLE variance
sd(sample4)^2 * (length(sample4)-1)/length(sample4)
[1] 3.929902

Graphs

Pie chart

df_pie <- data.frame(
            group = c("Male", "Female", "Child"),
            value = c(20, 30, 50)
            )
df_pie
pie <- ggplot(df_pie, aes(x="", y=value, fill=group)) +
        geom_bar(width = 1, stat = "identity") + 
        coord_polar("y", start=0) +
        # scale_fill_brewer(palette="Blues") + 
        theme_minimal() +
        theme(
        axis.title.x = element_blank(),
        axis.title.y = element_blank(),
        panel.border = element_blank(),
        panel.grid=element_blank(),
        axis.ticks = element_blank(),
        plot.title=element_text(size=14, face="bold")
        ) +
        theme(axis.text.x=element_blank()) +
        geom_text(aes(y = value/3 + c(0, cumsum(value)[-length(value)]), 
                      label = scales::percent(value/100)), size=5)
pie

Bar chart

df_vehicles <- data.frame(kendaraan=c("Sepeda Motor", "Mobil", "Bus"),
                          jumlah=c(30, 10, 5))
df_vehicles
bar <- ggplot(data=df_vehicles, aes(x=kendaraan, y=jumlah)) + 
        geom_bar(stat="identity", fill="steelblue") +
        geom_text(aes(label=jumlah), vjust=1.6, color="white", size=5)
bar

Line chart

tourist <- fpp::austourists
autoplot(tourist, color = 'black', linetype = 'solid') + geom_point() +
      ggtitle("Quarterly visitor nights spent by International Tourists to Australia")

Histogram

histogram <- ggplot(data = data.frame(x = sample_normal), aes(x=x)) + 
              geom_histogram(bins=30, color="darkblue", fill="lightblue") +
              ggtitle("Normal Distribution")
histogram

# Bimodal distribution
sample_bimodal <- c(rnorm(n = 10000, mean = 0, sd = 1), 
                    rnorm(n = 10000, mean = 4, sd = 1.2))
histogram2 <- ggplot(data = data.frame(x = sample_bimodal), aes(x=x)) + 
              geom_histogram(bins=30, color="black", fill="white") +
              ggtitle("Bimodal Distribution")
histogram2

Radar chart

# Demo data
exam_scores <- data.frame(
    row.names = c("Student 1", "Student 2", "Student 3"),
      Biology = c(7.9, 3.9, 9.4),
      Physics = c(10, 20, 0),
        Maths = c(3.7, 11.5, 2.5),
        Sport = c(8.7, 20, 4),
      English = c(7.9, 7.2, 12.4),
    Geography = c(6.4, 10.5, 6.5),
          Art = c(2.4, 0.2, 9.8),
  Programming = c(0, 0, 20),
        Music = c(20, 20, 20)
)

# Define the variable ranges: maximum and minimum
max_min <- data.frame(
  Biology = c(20, 0), Physics = c(20, 0), Maths = c(20, 0),
  Sport = c(20, 0), English = c(20, 0), Geography = c(20, 0),
  Art = c(20, 0), Programming = c(20, 0), Music = c(20, 0)
)
rownames(max_min) <- c("Max", "Min")

# Bind the variable ranges to the data
df_exam <- rbind(max_min, exam_scores)
df_exam
student1_data <- df_exam[c("Max", "Min", "Student 1"), ]
radarchart(student1_data)

create_beautiful_radarchart <- function(data, color = "#00AFBB", 
                                        vlabels = colnames(data), vlcex = 0.7,
                                        caxislabels = NULL, title = NULL, ...){
  radarchart(
    data, axistype = 1,
    # Customize the polygon
    pcol = color, pfcol = scales::alpha(color, 0.5), plwd = 2, plty = 1,
    # Customize the grid
    cglcol = "grey", cglty = 1, cglwd = 0.8,
    # Customize the axis
    axislabcol = "grey", 
    # Variable labels
    vlcex = vlcex, vlabels = vlabels,
    caxislabels = caxislabels, title = title, ...
  )
}
# Define colors and titles
colors <- c("#00AFBB", "#E7B800", "#FC4E07")
titles <- c("Student 1", "Student 2", "Student 3")

# Reduce plot margin using par()
# Split the screen in 3 parts
par(mfrow = c(1,3))

# Create the radar chart
for(i in 1:3){
  create_beautiful_radarchart(
    data = df_exam[c(1, 2, i+2), ], caxislabels = c(0, 5, 10, 15, 20),
    color = colors[i], title = titles[i]
    )
}

Bubble chart

See https://www.gapminder.org/tools/#$chart-type=bubbles&url=v1

# Load data
df_cars <- mtcars

# Convert cyl as a grouping variable
df_cars$cyl <- as.factor(df_cars$cyl)

# Bubble cart
plot_cars <- ggplot(df_cars, aes(x = wt, y = mpg)) + 
              geom_point(aes(color = cyl, size = qsec), alpha = 0.5) +
              scale_color_manual(values = c("#00AFBB", "#E7B800", "#FC4E07")) +
              scale_size(range = c(0.5, 12))  # Adjust the range of points size

plot_cars

Scatter plot

# Scatter plot
plot_cars2 <- ggplot(df_cars, aes(x = hp, y = mpg)) + 
              geom_point(size = 2)

plot_cars2

Dot plot

homework <- data.frame(hour = seq(0,10),
                       freq = c(1,5,4,3,4,2,3,0,2,1,0))

hours_spent <- rep(homework$hour[1],homework$freq[1])
for (i in 2:11){
  hours_spent <- c(hours_spent, rep(homework$hour[i],homework$freq[i]))
}
hours_spent
 [1] 0 1 1 1 1 1 2 2 2 2 3 3 3 4 4 4 4 5 5 6 6 6 8 8 9
plot_hour <- ggplot(data = data.frame(hour = hours_spent), aes(x=hour)) +
              geom_dotplot(binwidth = 1, dotsize=0.4) +
              scale_x_continuous(breaks=seq(0,10))
plot_hour

Boxplot

df_plant <- PlantGrowth

box1 <- ggboxplot(df_plant, x = "group", y = "weight", color = "group",
          ylab = "Weight", xlab = "Treatment")

box2 <- ggline(df_plant, x = "group", y = "weight", 
          add = c("mean_se", "jitter"), 
          order = c("ctrl", "trt1", "trt2"),
          ylab = "Weight", xlab = "Treatment")

grid.arrange(box1, box2, ncol=2)

LS0tCnRpdGxlOiAiRGVzY3JpcHRpdmUgU3RhdGlzdGljcyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgdG9jX2NvbGxhcHNlZDogdHJ1ZQotLS0KCiMjIExpYnJhcmllcwpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShmb3JlY2FzdCkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoZm1zYikKIyBsaWJyYXJ5KHNuKQojIGxpYnJhcnkobW9kZWVzdCkKIyBsaWJyYXJ5KGZwcCkKYGBgCgoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8wMS5wbmcpCgohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzAyLnBuZykKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8wMy5wbmcpCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMDQucG5nKQoKIyMgSW50cm8gdG8gRGVzY3JpcHRpdmUgU3RhdGlzdGljcwoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8wNS5wbmcpCgohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzA2LnBuZykKCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMDcucG5nKQoKYGBge3J9CiMgQ3JlYXRlIHZlY3RvciBjbGFzc0EgYW5kIGNsYXNzQgpjbGFzc0EgPC0gYygxMDIsMTI4LDEzMSw5OCwxNDAsOTMsMTEwLDExNSwxMDksODksMTA2LDExOSw5NykKY2xhc3NCIDwtIGMoMTI3LDEzMSw5Niw4MCw5MywxMjAsMTA5LDE2MiwxMDMsMTExLDEwOSw4NywxMDUpCgojIENhbGN1bGF0ZSB0aGUgbWVhbiBmb3IgZWFjaCBjbGFzcwptZWFuKGNsYXNzQSkKbWVhbihjbGFzc0IpCmBgYAoKIyMgVHlwZXMgb2YgRGF0YQoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8wOC5wbmcpCgohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzA5LnBuZykKCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMTAucG5nKQoKIyMgU3VtbWFyaXppbmcgRGF0YQoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8xMS5wbmcpCgojIyMgTWVhbgoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8xMi5wbmcpCgohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzEzLnBuZykKCmBgYHtyfQojIFNlZS1zYXcgaWxsdXN0cmF0aW9uCnNlZV9zYXcgPC0gYyg5MywxMDYsMTMxKQptZWFuKHNlZV9zYXcpCmBgYAoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8xNC5wbmcpCgpgYGB7cn0KIyBEZW5zaXR5IHBsb3QKc2V0LnNlZWQoMTIzKQppbmNvbWUgPC0gcm5vcm0oNTAsIG1lYW4gPSA1MCwgc2QgPSA1KQpwMSA8LSBnZ3Bsb3QoZGF0YSA9IGRhdGEuZnJhbWUoaW5jb21lKSwgYWVzKGluY29tZSkpICsgCiAgICAgICAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAicmVkIiwgYWxwaGEgPSAwLjEpICsKICAgICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKGluY29tZSksIAogICAgICAgICAgICAgICAgICAgbGluZXR5cGU9ImRvdHRlZCIsIAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgc2l6ZT0xLjUpCnAxCmBgYAoKYGBge3J9Cm1lYW4oaW5jb21lKQpgYGAKCgpgYGB7cn0KIyBPdXRsaWVyIGFmZmVjdHMgbWVhbgppbmNvbWVfb3V0bGllciA8LSBjKGluY29tZSwxMDAsMTAwLDEwMCwxMDAsMTAwLDEwMCkKcDIgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKGluY29tZSA9IGluY29tZV9vdXRsaWVyKSwgYWVzKGluY29tZSkpICsgCiAgICAgIGdlb21fZGVuc2l0eShmaWxsID0gInJlZCIsIGFscGhhID0gMC4xKSArCiAgICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbihpbmNvbWVfb3V0bGllciksIGxpbmV0eXBlPSJkb3R0ZWQiLCAKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIHNpemU9MS41KQpwMgpgYGAKCmBgYHtyfQptZWFuKGluY29tZV9vdXRsaWVyKQpgYGAKCmBgYHtyfQojIE5vcm1hbCBkYXRhCnNldC5zZWVkKDEyMykKc2FtcGxlX25vcm1hbCA8LSBybm9ybShuID0gMTAwMDAsIG1lYW4gPSAwLCBzZCA9IDEpCgojIFNrZXcgTm9ybWFsIGRhdGEKc2V0LnNlZWQoMTIzKQpzYW1wbGVfc24gPC0gc246OnJzbihuPTEwMDAwLCB4aT0wLCBvbWVnYT0xLCBhbHBoYT0xMCwgdGF1PTApCgojIENyZWF0ZSBkZW5zaXR5IHBsb3RzCnAzIDwtIGdncGxvdChkYXRhID0gZGF0YS5mcmFtZSh4ID0gc2FtcGxlX25vcm1hbCksIGFlcyh4PXgpKSArIAogICAgICAgIGdlb21fZGVuc2l0eShmaWxsID0gInJlZCIsIGFscGhhID0gMC4xKSArCiAgICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbihzYW1wbGVfbm9ybWFsKSwgbGluZXR5cGU9ImRvdHRlZCIsIAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwgc2l6ZT0xKSArCiAgICAgICAgZ2d0aXRsZSgiTm9ybWFsIERpc3RyaWJ1dGlvbiIpCiAgICAgIApwNCA8LSBnZ3Bsb3QoZGF0YSA9IGRhdGEuZnJhbWUoeCA9IHNhbXBsZV9zbiksIGFlcyh4PXgpKSArIAogICAgICAgIGdlb21fZGVuc2l0eShmaWxsID0gInJlZCIsIGFscGhhID0gMC4xKSArCiAgICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbihzYW1wbGVfc24pLCBsaW5ldHlwZT0iZG90dGVkIiwgCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJyZWQiLCBzaXplPTEpICsKICAgICAgICBnZ3RpdGxlKCJTa2V3IE5vcm1hbCBEaXN0cmlidXRpb24iKQoKZ3JpZC5hcnJhbmdlKHAzLHA0LCBuY29sPTEpCmBgYAojIyMgTWVkaWFuCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMTUucG5nKQoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8xNi5wbmcpCgohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzE3LnBuZykKCmBgYHtyfQpncmlkLmFycmFuZ2UocDEgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWRpYW4oaW5jb21lKSwgbGluZXR5cGU9ImRvdHRlZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsdWUiLCBzaXplPTEuNSksCiAgICAgICAgICAgICBwMiArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbihpbmNvbWVfb3V0bGllciksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV0eXBlPSJkb3R0ZWQiLCBjb2xvciA9ICJibHVlIiwgc2l6ZT0xLjUpKQpgYGAKCmBgYHtyfQpzdW1tYXJ5KGluY29tZSkKc3VtbWFyeShpbmNvbWVfb3V0bGllcikKYGBgCgpgYGB7cn0KZ3JpZC5hcnJhbmdlKHAzICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuKHNhbXBsZV9ub3JtYWwpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0iZG90dGVkIiwgY29sb3IgPSAiYmx1ZSIsIHNpemU9MSksCiAgICAgICAgICAgICBwNCArIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lZGlhbihzYW1wbGVfc24pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZT0iZG90dGVkIiwgY29sb3IgPSAiYmx1ZSIsIHNpemU9MSkpCmBgYAoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8xOC5wbmcpCgohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzE5LnBuZykKCmBgYHtyfQpzdW1tYXJ5KHNhbXBsZV9ub3JtYWwpCmBgYAoKYGBge3J9CiMgUXVhcnRpbGUgZXhhbXBsZXMKc2FtcGxlX3F1YXJ0IDwtIHF1YW50aWxlKHNhbXBsZV9ub3JtYWwscHJvYnMgPSBjKDAuMjUsIDAuNSwgMC43NSkpCnNhbXBsZV9xdWFydAoKIyBQZXJjZW50aWxlIGV4YW1wbGVzCnNhbXBsZV9wZXJjZW50IDwtIHF1YW50aWxlKHNhbXBsZV9ub3JtYWwscHJvYnMgPSBzZXEoMC4xLDAuOSxieT0wLjEpKQpzYW1wbGVfcGVyY2VudApgYGAKCgpgYGB7cn0KIyBEZW5zaXR5IHBsb3Qgd2l0aCBxdWFydGlsZXMKcDUgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKHggPSBzYW1wbGVfbm9ybWFsKSwgYWVzKHg9eCkpICsgCiAgICAgICAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAicmVkIiwgYWxwaGEgPSAwLjEpICsKICAgICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBzYW1wbGVfcXVhcnQsIGxpbmV0eXBlPSJkb3R0ZWQiLCAKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIHNpemU9MSkgKwogICAgICAgIGdndGl0bGUoIk5vcm1hbCBEaXN0cmlidXRpb24iKQpwNQpgYGAKCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMTkucG5nKQoKIyMjIE1vZGUKCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMjAucG5nKQoKYGBge3J9CmNsYXNzQUIgPC0gYyhjbGFzc0EsIGNsYXNzQikKbW9kZWVzdDo6bWZ2KGNsYXNzQUIpCmBgYAoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8yMS5wbmcpCgojIyMgUmFuZ2UKCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMjIucG5nKQoKYGBge3J9CiMgQ2FsY3VsYXRlIHJhbmdlCnJhbmdlKGNsYXNzQSkKcmFuZ2UoY2xhc3NCKQpgYGAKCmBgYHtyfQpyYW5nZShjbGFzc0EpWzJdIC0gcmFuZ2UoY2xhc3NBKVsxXQpyYW5nZShjbGFzc0IpWzJdIC0gcmFuZ2UoY2xhc3NCKVsxXQpgYGAKCgojIyMgSW50ZXJxdWFydGlsZSBSYW5nZQoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8yMy5wbmcpCgpgYGB7cn0KIyBDYWxjdWxhdGUgcXVhcnRpbGVzCmluY29tZV9vdXRsaWVyX3F1YXJ0IDwtIHF1YW50aWxlKGluY29tZV9vdXRsaWVyLHByb2JzID0gYygwLjI1LCAwLjUsIDAuNzUpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lcyA9IEZBTFNFKQoKIyBEZW5zaXR5IHBsb3Qgd2l0aCBxdWFydGlsZXMKcDYgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKGluY29tZSA9IGluY29tZV9vdXRsaWVyKSwgYWVzKGluY29tZSkpICsgCiAgICAgIGdlb21fZGVuc2l0eShmaWxsID0gInJlZCIsIGFscGhhID0gMC4xKSArCiAgICAgICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gaW5jb21lX291dGxpZXJfcXVhcnQsIGxpbmV0eXBlPSJkb3R0ZWQiLCAKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsIHNpemU9MSkKcDYKYGBgCgpgYGB7cn0KIyBSYW5nZSBvZiBpbmNvbWVfb3V0bGllcgpyYW5nZShpbmNvbWVfb3V0bGllcilbMl0gLSByYW5nZShpbmNvbWVfb3V0bGllcilbMV0KYGBgCgpgYGB7cn0KIyBJbnRlcnF1YXJ0aWxlIHJhbmdlIG9mIGluY29tZV9vdXRsaWVyCmluY29tZV9vdXRsaWVyX3F1YXJ0WzNdIC0gaW5jb21lX291dGxpZXJfcXVhcnRbMV0KYGBgCgoKIyMjIFZhcmlhbmNlIGFuZCBTdGFuZGFyZCBEZXZpYXRpb24KCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMjQucG5nKQoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8yNS5wbmcpCgohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzI2LnBuZykKCmBgYHtyfQojIEdlbmVyYXRlIG5vcm1hbCBzYW1wbGVzIHdpdGggZGlmZmVyZW50IHZhcmlhbmNlcwpzZXQuc2VlZCgxMjMpCnNhbXBsZV9tdWx0aW5vcm1hbCA8LSBkYXRhLmZyYW1lKHR5cGUgPSBhcy5mYWN0b3IoYyhyZXAoNDo2LGVhY2g9MTAwMDApKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBjKHJub3JtKDEwMDAwLDAsNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJub3JtKDEwMDAwLDAsNSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJub3JtKDEwMDAwLDAsNikpKQoKcDcgPC0gZ2dwbG90KGRhdGEgPSBzYW1wbGVfbXVsdGlub3JtYWwsIGFlcyh4ID0gZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IHR5cGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHR5cGUpKSArCiAgICAgICAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4yKQpwNwpgYGAKCmBgYHtyfQojIENvbXBhcmluZyBNTEUgdmFyaWFuY2UgKGRlbm9taW5hdG9yIG4pIGFuZCBhbmQgdW5iaWFzZWQgdmFyaWFuY2UgKGRlbm9taW5hdG9yIG4tMSkKCiMgbiA9IDEwCnNldC5zZWVkKDEyMykKc2FtcGxlMSA8LSBybm9ybSgxMCwgbWVhbiA9IDAsIHNkID0gMikKCiMgVW5iaWFzZWQgdmFyaWFuY2UKc2Qoc2FtcGxlMSleMgoKIyBNTEUgdmFyaWFuY2UKc2Qoc2FtcGxlMSleMiAqIChsZW5ndGgoc2FtcGxlMSktMSkvbGVuZ3RoKHNhbXBsZTEpCmBgYAoKYGBge3J9CiMgbiA9IDMwCnNldC5zZWVkKDEyMykKc2FtcGxlMiA8LSBybm9ybSgzMCwgbWVhbiA9IDAsIHNkID0gMikKCiMgVW5iaWFzZWQgdmFyaWFuY2UKc2Qoc2FtcGxlMileMgoKIyBNTEUgdmFyaWFuY2UKc2Qoc2FtcGxlMileMiAqIChsZW5ndGgoc2FtcGxlMiktMSkvbGVuZ3RoKHNhbXBsZTIpCmBgYAoKYGBge3J9CiMgbiA9IDEwMApzZXQuc2VlZCgxMjMpCnNhbXBsZTMgPC0gcm5vcm0oMTAwLCBtZWFuID0gMCwgc2QgPSAyKQoKIyBVbmJpYXNlZCB2YXJpYW5jZQpzZChzYW1wbGUzKV4yCgojIE1MRSB2YXJpYW5jZQpzZChzYW1wbGUzKV4yICogKGxlbmd0aChzYW1wbGUzKS0xKS9sZW5ndGgoc2FtcGxlMykKYGBgCgpgYGB7cn0KIyBuID0gMTAwMApzZXQuc2VlZCgxMjMpCnNhbXBsZTQgPC0gcm5vcm0oMTAwMCwgbWVhbiA9IDAsIHNkID0gMikKCiMgVW5iaWFzZWQgdmFyaWFuY2UKc2Qoc2FtcGxlNCleMgoKIyBNTEUgdmFyaWFuY2UKc2Qoc2FtcGxlNCleMiAqIChsZW5ndGgoc2FtcGxlNCktMSkvbGVuZ3RoKHNhbXBsZTQpCmBgYAoKIAohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzI3LnBuZykKCiMjIEdyYXBocwoKIyMjIFBpZSBjaGFydAoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8yOC5wbmcpCgpgYGB7cn0KZGZfcGllIDwtIGRhdGEuZnJhbWUoCiAgICAgICAgICAgIGdyb3VwID0gYygiTWFsZSIsICJGZW1hbGUiLCAiQ2hpbGQiKSwKICAgICAgICAgICAgdmFsdWUgPSBjKDIwLCAzMCwgNTApCiAgICAgICAgICAgICkKZGZfcGllCmBgYAoKYGBge3J9CnBpZSA8LSBnZ3Bsb3QoZGZfcGllLCBhZXMoeD0iIiwgeT12YWx1ZSwgZmlsbD1ncm91cCkpICsKICAgICAgICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiKSArIAogICAgICAgIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkgKwogICAgICAgICMgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0iQmx1ZXMiKSArIAogICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICAgdGhlbWUoCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTE0LCBmYWNlPSJib2xkIikKICAgICAgICApICsKICAgICAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCkpICsKICAgICAgICBnZW9tX3RleHQoYWVzKHkgPSB2YWx1ZS8zICsgYygwLCBjdW1zdW0odmFsdWUpWy1sZW5ndGgodmFsdWUpXSksIAogICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQodmFsdWUvMTAwKSksIHNpemU9NSkKcGllCmBgYAoKIyMjIEJhciBjaGFydAoKIVtdKFNsaWRlIGltYWdlcy8wMSAtIERlc2NyaXB0aXZlIFN0YXRpc3RpY3NfUGFnZV8yOS5wbmcpCgpgYGB7cn0KZGZfdmVoaWNsZXMgPC0gZGF0YS5mcmFtZShrZW5kYXJhYW49YygiU2VwZWRhIE1vdG9yIiwgIk1vYmlsIiwgIkJ1cyIpLAogICAgICAgICAgICAgICAgICAgICAgICAgIGp1bWxhaD1jKDMwLCAxMCwgNSkpCmRmX3ZlaGljbGVzCmBgYAoKYGBge3J9CmJhciA8LSBnZ3Bsb3QoZGF0YT1kZl92ZWhpY2xlcywgYWVzKHg9a2VuZGFyYWFuLCB5PWp1bWxhaCkpICsgCiAgICAgICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBmaWxsPSJzdGVlbGJsdWUiKSArCiAgICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1qdW1sYWgpLCB2anVzdD0xLjYsIGNvbG9yPSJ3aGl0ZSIsIHNpemU9NSkKYmFyCmBgYAoKIyMjIExpbmUgY2hhcnQKCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMzAucG5nKQoKYGBge3J9CnRvdXJpc3QgPC0gZnBwOjphdXN0b3VyaXN0cwphdXRvcGxvdCh0b3VyaXN0LCBjb2xvciA9ICdibGFjaycsIGxpbmV0eXBlID0gJ3NvbGlkJykgKyBnZW9tX3BvaW50KCkgKwogICAgICBnZ3RpdGxlKCJRdWFydGVybHkgdmlzaXRvciBuaWdodHMgc3BlbnQgYnkgSW50ZXJuYXRpb25hbCBUb3VyaXN0cyB0byBBdXN0cmFsaWEiKQpgYGAKCiMjIyBIaXN0b2dyYW0KCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMzEucG5nKQoKYGBge3J9Cmhpc3RvZ3JhbSA8LSBnZ3Bsb3QoZGF0YSA9IGRhdGEuZnJhbWUoeCA9IHNhbXBsZV9ub3JtYWwpLCBhZXMoeD14KSkgKyAKICAgICAgICAgICAgICBnZW9tX2hpc3RvZ3JhbShiaW5zPTMwLCBjb2xvcj0iZGFya2JsdWUiLCBmaWxsPSJsaWdodGJsdWUiKSArCiAgICAgICAgICAgICAgZ2d0aXRsZSgiTm9ybWFsIERpc3RyaWJ1dGlvbiIpCmhpc3RvZ3JhbQpgYGAKCmBgYHtyfQojIEJpbW9kYWwgZGlzdHJpYnV0aW9uCnNhbXBsZV9iaW1vZGFsIDwtIGMocm5vcm0obiA9IDEwMDAwLCBtZWFuID0gMCwgc2QgPSAxKSwgCiAgICAgICAgICAgICAgICAgICAgcm5vcm0obiA9IDEwMDAwLCBtZWFuID0gNCwgc2QgPSAxLjIpKQpoaXN0b2dyYW0yIDwtIGdncGxvdChkYXRhID0gZGF0YS5mcmFtZSh4ID0gc2FtcGxlX2JpbW9kYWwpLCBhZXMoeD14KSkgKyAKICAgICAgICAgICAgICBnZW9tX2hpc3RvZ3JhbShiaW5zPTMwLCBjb2xvcj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIpICsKICAgICAgICAgICAgICBnZ3RpdGxlKCJCaW1vZGFsIERpc3RyaWJ1dGlvbiIpCmhpc3RvZ3JhbTIKYGBgCgojIyMgUmFkYXIgY2hhcnQKCiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMzIucG5nKQoKCmBgYHtyfQojIERlbW8gZGF0YQpleGFtX3Njb3JlcyA8LSBkYXRhLmZyYW1lKAogICAgcm93Lm5hbWVzID0gYygiU3R1ZGVudCAxIiwgIlN0dWRlbnQgMiIsICJTdHVkZW50IDMiKSwKICAgICAgQmlvbG9neSA9IGMoNy45LCAzLjksIDkuNCksCiAgICAgIFBoeXNpY3MgPSBjKDEwLCAyMCwgMCksCiAgICAgICAgTWF0aHMgPSBjKDMuNywgMTEuNSwgMi41KSwKICAgICAgICBTcG9ydCA9IGMoOC43LCAyMCwgNCksCiAgICAgIEVuZ2xpc2ggPSBjKDcuOSwgNy4yLCAxMi40KSwKICAgIEdlb2dyYXBoeSA9IGMoNi40LCAxMC41LCA2LjUpLAogICAgICAgICAgQXJ0ID0gYygyLjQsIDAuMiwgOS44KSwKICBQcm9ncmFtbWluZyA9IGMoMCwgMCwgMjApLAogICAgICAgIE11c2ljID0gYygyMCwgMjAsIDIwKQopCgojIERlZmluZSB0aGUgdmFyaWFibGUgcmFuZ2VzOiBtYXhpbXVtIGFuZCBtaW5pbXVtCm1heF9taW4gPC0gZGF0YS5mcmFtZSgKICBCaW9sb2d5ID0gYygyMCwgMCksIFBoeXNpY3MgPSBjKDIwLCAwKSwgTWF0aHMgPSBjKDIwLCAwKSwKICBTcG9ydCA9IGMoMjAsIDApLCBFbmdsaXNoID0gYygyMCwgMCksIEdlb2dyYXBoeSA9IGMoMjAsIDApLAogIEFydCA9IGMoMjAsIDApLCBQcm9ncmFtbWluZyA9IGMoMjAsIDApLCBNdXNpYyA9IGMoMjAsIDApCikKcm93bmFtZXMobWF4X21pbikgPC0gYygiTWF4IiwgIk1pbiIpCgojIEJpbmQgdGhlIHZhcmlhYmxlIHJhbmdlcyB0byB0aGUgZGF0YQpkZl9leGFtIDwtIHJiaW5kKG1heF9taW4sIGV4YW1fc2NvcmVzKQpkZl9leGFtCmBgYAoKYGBge3J9CnN0dWRlbnQxX2RhdGEgPC0gZGZfZXhhbVtjKCJNYXgiLCAiTWluIiwgIlN0dWRlbnQgMSIpLCBdCnJhZGFyY2hhcnQoc3R1ZGVudDFfZGF0YSkKYGBgCgoKYGBge3J9CmNyZWF0ZV9iZWF1dGlmdWxfcmFkYXJjaGFydCA8LSBmdW5jdGlvbihkYXRhLCBjb2xvciA9ICIjMDBBRkJCIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2bGFiZWxzID0gY29sbmFtZXMoZGF0YSksIHZsY2V4ID0gMC43LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2F4aXNsYWJlbHMgPSBOVUxMLCB0aXRsZSA9IE5VTEwsIC4uLil7CiAgcmFkYXJjaGFydCgKICAgIGRhdGEsIGF4aXN0eXBlID0gMSwKICAgICMgQ3VzdG9taXplIHRoZSBwb2x5Z29uCiAgICBwY29sID0gY29sb3IsIHBmY29sID0gc2NhbGVzOjphbHBoYShjb2xvciwgMC41KSwgcGx3ZCA9IDIsIHBsdHkgPSAxLAogICAgIyBDdXN0b21pemUgdGhlIGdyaWQKICAgIGNnbGNvbCA9ICJncmV5IiwgY2dsdHkgPSAxLCBjZ2x3ZCA9IDAuOCwKICAgICMgQ3VzdG9taXplIHRoZSBheGlzCiAgICBheGlzbGFiY29sID0gImdyZXkiLCAKICAgICMgVmFyaWFibGUgbGFiZWxzCiAgICB2bGNleCA9IHZsY2V4LCB2bGFiZWxzID0gdmxhYmVscywKICAgIGNheGlzbGFiZWxzID0gY2F4aXNsYWJlbHMsIHRpdGxlID0gdGl0bGUsIC4uLgogICkKfQpgYGAKCgpgYGB7cn0KIyBEZWZpbmUgY29sb3JzIGFuZCB0aXRsZXMKY29sb3JzIDwtIGMoIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IikKdGl0bGVzIDwtIGMoIlN0dWRlbnQgMSIsICJTdHVkZW50IDIiLCAiU3R1ZGVudCAzIikKCiMgUmVkdWNlIHBsb3QgbWFyZ2luIHVzaW5nIHBhcigpCiMgU3BsaXQgdGhlIHNjcmVlbiBpbiAzIHBhcnRzCnBhcihtZnJvdyA9IGMoMSwzKSkKCiMgQ3JlYXRlIHRoZSByYWRhciBjaGFydApmb3IoaSBpbiAxOjMpewogIGNyZWF0ZV9iZWF1dGlmdWxfcmFkYXJjaGFydCgKICAgIGRhdGEgPSBkZl9leGFtW2MoMSwgMiwgaSsyKSwgXSwgY2F4aXNsYWJlbHMgPSBjKDAsIDUsIDEwLCAxNSwgMjApLAogICAgY29sb3IgPSBjb2xvcnNbaV0sIHRpdGxlID0gdGl0bGVzW2ldCiAgICApCn0KYGBgCgojIyMgQnViYmxlIGNoYXJ0CiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMzMucG5nKQoKU2VlIGh0dHBzOi8vd3d3LmdhcG1pbmRlci5vcmcvdG9vbHMvIyRjaGFydC10eXBlPWJ1YmJsZXMmdXJsPXYxCgpgYGB7cn0KIyBMb2FkIGRhdGEKZGZfY2FycyA8LSBtdGNhcnMKCiMgQ29udmVydCBjeWwgYXMgYSBncm91cGluZyB2YXJpYWJsZQpkZl9jYXJzJGN5bCA8LSBhcy5mYWN0b3IoZGZfY2FycyRjeWwpCgojIEJ1YmJsZSBjYXJ0CnBsb3RfY2FycyA8LSBnZ3Bsb3QoZGZfY2FycywgYWVzKHggPSB3dCwgeSA9IG1wZykpICsgCiAgICAgICAgICAgICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjeWwsIHNpemUgPSBxc2VjKSwgYWxwaGEgPSAwLjUpICsKICAgICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiIzAwQUZCQiIsICIjRTdCODAwIiwgIiNGQzRFMDciKSkgKwogICAgICAgICAgICAgIHNjYWxlX3NpemUocmFuZ2UgPSBjKDAuNSwgMTIpKSAgIyBBZGp1c3QgdGhlIHJhbmdlIG9mIHBvaW50cyBzaXplCgpwbG90X2NhcnMKYGBgCgojIyMgU2NhdHRlciBwbG90CiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMzQucG5nKQoKYGBge3J9CiMgU2NhdHRlciBwbG90CnBsb3RfY2FyczIgPC0gZ2dwbG90KGRmX2NhcnMsIGFlcyh4ID0gaHAsIHkgPSBtcGcpKSArIAogICAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDIpCgpwbG90X2NhcnMyCmBgYAoKIyMjIERvdCBwbG90CiFbXShTbGlkZSBpbWFnZXMvMDEgLSBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzX1BhZ2VfMzUucG5nKQoKCmBgYHtyfQpob21ld29yayA8LSBkYXRhLmZyYW1lKGhvdXIgPSBzZXEoMCwxMCksCiAgICAgICAgICAgICAgICAgICAgICAgZnJlcSA9IGMoMSw1LDQsMyw0LDIsMywwLDIsMSwwKSkKCmhvdXJzX3NwZW50IDwtIHJlcChob21ld29yayRob3VyWzFdLGhvbWV3b3JrJGZyZXFbMV0pCmZvciAoaSBpbiAyOjExKXsKICBob3Vyc19zcGVudCA8LSBjKGhvdXJzX3NwZW50LCByZXAoaG9tZXdvcmskaG91cltpXSxob21ld29yayRmcmVxW2ldKSkKfQpgYGAKCmBgYHtyfQpob3Vyc19zcGVudApgYGAKCmBgYHtyfQpwbG90X2hvdXIgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKGhvdXIgPSBob3Vyc19zcGVudCksIGFlcyh4PWhvdXIpKSArCiAgICAgICAgICAgICAgZ2VvbV9kb3RwbG90KGJpbndpZHRoID0gMSwgZG90c2l6ZT0wLjQpICsKICAgICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDEwKSkKcGxvdF9ob3VyCmBgYAoKCgojIyMgQm94cGxvdAohW10oU2xpZGUgaW1hZ2VzLzAxIC0gRGVzY3JpcHRpdmUgU3RhdGlzdGljc19QYWdlXzM2LnBuZykKCgpgYGB7cn0KZGZfcGxhbnQgPC0gUGxhbnRHcm93dGgKCmJveDEgPC0gZ2dib3hwbG90KGRmX3BsYW50LCB4ID0gImdyb3VwIiwgeSA9ICJ3ZWlnaHQiLCBjb2xvciA9ICJncm91cCIsCiAgICAgICAgICB5bGFiID0gIldlaWdodCIsIHhsYWIgPSAiVHJlYXRtZW50IikKCmJveDIgPC0gZ2dsaW5lKGRmX3BsYW50LCB4ID0gImdyb3VwIiwgeSA9ICJ3ZWlnaHQiLCAKICAgICAgICAgIGFkZCA9IGMoIm1lYW5fc2UiLCAiaml0dGVyIiksIAogICAgICAgICAgb3JkZXIgPSBjKCJjdHJsIiwgInRydDEiLCAidHJ0MiIpLAogICAgICAgICAgeWxhYiA9ICJXZWlnaHQiLCB4bGFiID0gIlRyZWF0bWVudCIpCgpncmlkLmFycmFuZ2UoYm94MSwgYm94MiwgbmNvbD0yKQpgYGAKCgoK