Load required packages

library(readxl)
library(dplyr)
library(psych) # describe()
library(skimr) # skim()
library(pastecs) # stat.desc()

Load and see the data

df <- read_excel("C:\\Users\\Dell\\OneDrive\\Desktop\\STATISTICS\\2nd Year\\R programming\\varsity\\Project_Distribution.xlsx")
describe(df)
View(df)
skim(df)
── Data Summary ────────────────────────
                           Values
Name                       df    
Number of rows             80    
Number of columns          5     
_______________________          
Column type frequency:           
  character                2     
  numeric                  3     
________________________         
Group variables            None  
glimpse(df)
Rows: 80
Columns: 5
$ ExamRoll        <dbl> 2316669, 2316632, 2316615, 2316643, 2316679, 2316667, 2316611, 2316607, 2316644, 2316650, 2316655, 23…
$ Sex             <chr> "F", "M", "M", "M", "F", "F", "M", "M", "M", "F", "F", "M", "M", "F", "F", "M", "F", "M", "F", "F", "…
$ CGPA            <dbl> 3.988, 3.953, 3.938, 3.938, 3.914, 3.910, 3.864, 3.857, 3.853, 3.841, 3.837, 3.830, 3.822, 3.818, 3.8…
$ Group           <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,…
$ AssignedTeacher <chr> "B", "O", "C", "FT", "MT", "T", "K", "I", "E", "G", "W", "S", "D", "R", "H", "Q", "J", "V", "P", "N",…
stat.desc(df)
summary(df) # Exam Roll numbers, Sex, CGPA, Group assignment, and Assigned Teacher
    ExamRoll           Sex                 CGPA           Group       AssignedTeacher   
 Min.   :2316601   Length:80          Min.   :2.053   Min.   :1.000   Length:80         
 1st Qu.:2316622   Class :character   1st Qu.:3.242   1st Qu.:1.000   Class :character  
 Median :2316643   Mode  :character   Median :3.484   Median :2.000   Mode  :character  
 Mean   :2316642                      Mean   :3.415   Mean   :2.275                     
 3rd Qu.:2316662                      3rd Qu.:3.769   3rd Qu.:3.000                     
 Max.   :2316682                      Max.   :3.988   Max.   :4.000                     
sum(is.na(df)) # no Missing values
[1] 0

Convert variable types

df$ExamRoll<-as.character(df$ExamRoll)
class(df$ExamRoll)
[1] "character"
df$Sex <- as.factor(df$Sex)
class(df$Sex)
[1] "factor"
df$Group <- as.factor(df$Group)
class(df$Group)
[1] "factor"
df$AssignedTeacher <- as.factor(df$AssignedTeacher)
class(df$AssignedTeacher)
[1] "factor"

See the data again

str(df)
tibble [80 × 5] (S3: tbl_df/tbl/data.frame)
 $ ExamRoll       : chr [1:80] "2316669" "2316632" "2316615" "2316643" ...
 $ Sex            : Factor w/ 2 levels "F","M": 1 2 2 2 1 1 2 2 2 1 ...
 $ CGPA           : num [1:80] 3.99 3.95 3.94 3.94 3.91 ...
 $ Group          : Factor w/ 4 levels "1","2","3","4": 1 1 1 1 1 1 1 1 1 1 ...
 $ AssignedTeacher: Factor w/ 23 levels "A","B","C","D",..: 2 15 3 6 13 20 11 9 5 7 ...
summary(df)
   ExamRoll         Sex         CGPA       Group  AssignedTeacher
 Length:80          F:30   Min.   :2.053   1:23   A      : 4     
 Class :character   M:50   1st Qu.:3.242   2:23   B      : 4     
 Mode  :character          Median :3.484   3:23   C      : 4     
                           Mean   :3.415   4:11   D      : 4     
                           3rd Qu.:3.769          E      : 4     
                           Max.   :3.988          FT     : 4     
                                                  (Other):56     

Descriptive Statistics

For CGPA (i) Mean (ii) Median (iii) Standard deviation

describe(df$CGPA)

Frequency Distributions (i) Sex (ii) Group (iii) AssignedTeacher

table(df$Sex)

 F  M 
30 50 
table(df$Group)

 1  2  3  4 
23 23 23 11 
table(df$AssignedTeacher)

 A  B  C  D  E FT  G  H  I  J  K  L MT  N  O  P  Q  R  S  T  U  V  W 
 4  4  4  4  4  4  4  4  4  4  4  3  3  3  3  3  3  3  3  3  3  3  3 
df %>%
  count(df$Sex) %>%  # Frequency
  mutate(
    percent = n / sum(n) * 100,
    cum_n = cumsum(n),
    cum_percent = cumsum(percent),
    relative_freq = n / sum(n),
    cum_relative = cumsum(relative_freq)
  ) %>%
  rename(Frequency = n)

df %>%
  count(df$Group) %>%  # Frequency
  mutate(
    percent = n / sum(n) * 100,
    cum_n = cumsum(n),
    cum_percent = cumsum(percent),
    relative_freq = n / sum(n),
    cum_relative = cumsum(relative_freq)
  ) %>%
  rename(Frequency = n)

df %>%
  count(df$AssignedTeacher) %>%  # Frequency
  mutate(
    percent = n / sum(n) * 100,
    cum_n = cumsum(n),
    cum_percent = cumsum(percent),
    relative_freq = n / sum(n),
    cum_relative = cumsum(relative_freq)
  ) %>%
  rename(Frequency = n)

Group Comparisons (i) CGPA by Sex (mean, SD, count) (ii) CGPA by Group (mean, SD, count)

# Using dplyr (recommended)
result <- df %>%
  group_by(Sex) %>%
  summarise(
    Count = n(),
    Mean_CGPA = round(mean(CGPA, na.rm = TRUE), 2),
    SD_CGPA = round(sd(CGPA, na.rm = TRUE), 2),
    .groups = 'drop'
  )
result
# knitr::kable(result, caption = "CGPA by Sex") # Display nicely

result <- df %>%
  group_by(Group) %>%
  summarise(
    Count = n(),
    Mean_CGPA = round(mean(CGPA, na.rm = TRUE), 2),
    SD_CGPA = round(sd(CGPA, na.rm = TRUE), 2),
    .groups = 'drop'
  )
result

# For everyday use: dplyr (most readable and flexible)

# For quick analysis: psych::describeBy()

# For large datasets: data.table

# For publication: gtsummary

Data Visualization

Distribution Plots (i) Histogram of CGPA (ii) Density plot of CGPA

library(ggplot2)

# install.packages("esquisse")
# library(esquisse) # Creates ggplot2 code automatically
# esquisser(df) # Opens drag-and-drop interface
# Template for any plot
#ggplot(data = df, aes(x = x_variable, y = y_variable)) +
#  geom_*(aes(color/fill = grouping_variable)) +  # Choose geom
#  labs(title = "Title", x = "X Label", y = "Y Label") +
#  theme_minimal() +
#  scale_fill_brewer(palette = "Set2")  # Color palette


# Histogram of CGPA
ggplot(df, aes(x = CGPA)) +
  geom_histogram(bins = 30, fill = "steelblue", color = "white") +
  labs(title = "Histogram of CGPA", x = "CGPA", y = "Count") +
  theme_minimal()


# Density plot of CGPA
ggplot(df, aes(x = CGPA)) +
  geom_density(fill = "steelblue", alpha = 0.5, color = NA) +
  labs(title = "Density Plot of CGPA", x = "CGPA", y = "Density") +
  theme_minimal()

NA
NA

Categorical Data Plots: (i) Bar plot of Sex (ii) Bar plot of Group (iii) Bar plot of AssignedTeacher

# Bar plot of Sex
ggplot(df, aes(x = Sex, fill = Sex, group = Sex)) +
  geom_bar() +
  labs(title = "Bar Plot of Sex", x = "Sex", y = "Count") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set2")


# Bar plot of Group
ggplot(df, aes(x = Group, fill = Group, group = Group)) +
  geom_bar() +
  labs(title = "Bar Plot of Group", x = "Group", y = "Count") +
  theme_minimal() +
  scale_fill_brewer(palette = "Set1")


# Bar plot of Assigned Teacher 
ggplot(df, aes(x = AssignedTeacher, fill = AssignedTeacher, group = AssignedTeacher)) +
  geom_bar() +
  labs(title = "Bar Plot of Assigned Teacher",
       x = "Assigned Teacher", y = "Count") +
  theme_minimal() +
  scale_fill_viridis_d()        # many categories → no Brewer palette

Easier Way

# Bar plot of Sex
barplot(table(df$Sex), main = "Count by Sex", xlab = "Sex", ylab = "Count")

# Bar plot of Group
barplot(table(df$Group), main = "Count by Group", xlab = "Group", ylab = "Count")

# Bar plot of AssignedTeacher
barplot(table(df$AssignedTeacher), main = "Count by Assigned Teacher", 
        xlab = "Teacher", ylab = "Count", las = 2)

Comparative Plots: (i) Boxplot of CGPA by Sex (ii) Boxplot of CGPA by Group

library(ggplot2)

ggplot(df, aes(x = Sex, y = CGPA, fill = Sex)) +
  geom_boxplot(alpha = 0.8, outlier.color = "red") +
  stat_summary(fun = mean,
               geom = "point",
               shape = 23,
               size = 3,
               fill = "yellow") +
  labs(title = "Boxplot of CGPA by Sex",
       x = "Sex",
       y = "CGPA") +
  theme_minimal() 

  
ggplot(df, aes(x = Group, y = CGPA, fill = Group)) +
  geom_boxplot(alpha = 0.8, outlier.color = "red") +
  stat_summary(fun = mean,
               geom = "point",
               shape = 23,
               size = 3,
               fill = "yellow") +
  labs(title = "Boxplot of CGPA by Group",
       x = "Group",
       y = "CGPA") +
  theme_minimal() 

Easier way:

boxplot(CGPA ~ Sex, data = df, main = "CGPA by Sex", xlab = "Sex", ylab = "CGPA")

boxplot(CGPA ~ Group, data = df, main = "CGPA by Group", xlab = "Group", ylab = "CGPA")

Inferential Statistics

Mean Comparisons : 1) Independent samples t-test: CGPA by Sex 2) One-way ANOVA: CGPA by Group 3) One-way ANOVA: CGPA by AssignedTeacher

library(ggstatsplot)

# t-test with plot
gghistostats(
  data = df,
  x = CGPA,
  y = Sex,
  type = "parametric",  # t-test
  title = "CGPA by Sex with t-test"
)


# ANOVA with plot
ggbetweenstats(
  data = df,
  x = Group,
  y = CGPA,
  type = "parametric",  # ANOVA
  title = "CGPA by Group with ANOVA",
  pairwise.comparisons = TRUE,  # Shows post-hoc
  pairwise.display = "significant"
)

Easier Way:

# (i) t-test
t.test(CGPA ~ Sex, data = df, var.equal = TRUE)  # Equal variances

    Two Sample t-test

data:  CGPA by Sex
t = 1.6962, df = 78, p-value = 0.09384
alternative hypothesis: true difference in means between group F and group M is not equal to 0
95 percent confidence interval:
 -0.02967273  0.37124607
sample estimates:
mean in group F mean in group M 
       3.521967        3.351180 
t.test(CGPA ~ Sex, data = df, var.equal = FALSE) # Welch's t-test

    Welch Two Sample t-test

data:  CGPA by Sex
t = 1.7854, df = 70.874, p-value = 0.07848
alternative hypothesis: true difference in means between group F and group M is not equal to 0
95 percent confidence interval:
 -0.01995516  0.36152849
sample estimates:
mean in group F mean in group M 
       3.521967        3.351180 
# (ii) ANOVA
aov_result <- aov(CGPA ~ Group, data = df)
summary(aov_result)  # ANOVA table
            Df Sum Sq Mean Sq F value Pr(>F)    
Group        3 13.670   4.557   203.1 <2e-16 ***
Residuals   76  1.705   0.022                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# (iii) Another ANOVA
aov_teacher <- aov(CGPA ~ AssignedTeacher, data = df)
summary(aov_teacher)
                Df Sum Sq Mean Sq F value Pr(>F)
AssignedTeacher 22   1.78 0.08091   0.339  0.997
Residuals       57  13.60 0.23850               
# Post-hoc tests
TukeyHSD(aov_result)  # Tukey's HSD
  Tukey multiple comparisons of means
    95% family-wise confidence level

Fit: aov(formula = CGPA ~ Group, data = df)

$Group
          diff        lwr        upr p adj
2-1 -0.2691304 -0.3851445 -0.1531164 3e-07
3-1 -0.5790000 -0.6950141 -0.4629859 0e+00
4-1 -1.2994664 -1.4436908 -1.1552420 0e+00
3-2 -0.3098696 -0.4258836 -0.1938555 0e+00
4-2 -1.0303360 -1.1745604 -0.8861116 0e+00
4-3 -0.7204664 -0.8646908 -0.5762420 0e+00
pairwise.t.test(df$CGPA, df$Group, p.adjust.method = "bonferroni")

    Pairwise comparisons using t tests with pooled SD 

data:  df$CGPA and df$Group 

  1       2       3      
2 2.5e-07 -       -      
3 < 2e-16 4.9e-09 -      
4 < 2e-16 < 2e-16 < 2e-16

P value adjustment method: bonferroni 

Association Tests : (i) Chi-square test: Sex vs Group (ii) Chi-square test: Sex vs AssignedTeacher

library(ggstatsplot)

# Sex vs Group with chi-square
ggbarstats(
  data = df,
  x = Sex,
  y = Group,
  title = "Association: Sex vs Group",
  results.subtitle = TRUE,
  label = "both",  # Show counts and percentages
  perc.k = 1       # Decimal places for percentages
)


# Sex vs AssignedTeacher
ggbarstats(
  data = df,
  x = Sex,
  y = AssignedTeacher,
  title = "Association: Sex vs AssignedTeacher"
)

Easier Way:

# Sex vs Group with chi-square
chisq.test(table(df$Sex, df$Group))

    Pearson's Chi-squared test

data:  table(df$Sex, df$Group)
X-squared = 4.0095, df = 3, p-value = 0.2604
# Sex vs AssignedTeacher
chisq.test(table(df$Sex, df$AssignedTeacher))

    Pearson's Chi-squared test

data:  table(df$Sex, df$AssignedTeacher)
X-squared = 25.244, df = 22, p-value = 0.2855

Regression Analysis

Simple Linear Regression : (i) Model 1: CGPA ~ Sex (ii) Model 2: CGPA ~ Group

summary(lm(CGPA ~ Sex, data = df))

Call:
lm(formula = CGPA ~ Sex, data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.29818 -0.22513  0.09743  0.28478  0.60182 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   3.5220     0.0796  44.244   <2e-16 ***
SexM         -0.1708     0.1007  -1.696   0.0938 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.436 on 78 degrees of freedom
Multiple R-squared:  0.03557,   Adjusted R-squared:  0.02321 
F-statistic: 2.877 on 1 and 78 DF,  p-value: 0.09384
summary(lm(CGPA ~ Group, data = df))

Call:
lm(formula = CGPA ~ Group, data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.48527 -0.07246  0.00333  0.10026  0.44173 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  3.83774    0.03123 122.887  < 2e-16 ***
Group2      -0.26913    0.04417  -6.094 4.23e-08 ***
Group3      -0.57900    0.04417 -13.110  < 2e-16 ***
Group4      -1.29947    0.05491 -23.668  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1498 on 76 degrees of freedom
Multiple R-squared:  0.8891,    Adjusted R-squared:  0.8847 
F-statistic: 203.1 on 3 and 76 DF,  p-value: < 2.2e-16

Multiple Regression : Full model: CGPA ~ Sex + Group + AssignedTeacher


# Full model
full_model <- lm(CGPA ~ Sex + Group + AssignedTeacher, data = df)
summary(full_model)

Call:
lm(formula = CGPA ~ Sex + Group + AssignedTeacher, data = df)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.37629 -0.07189  0.01049  0.06907  0.29031 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)        3.697292   0.079024  46.787  < 2e-16 ***
SexM               0.053618   0.042178   1.271   0.2092    
Group2            -0.278455   0.043500  -6.401 4.14e-08 ***
Group3            -0.588325   0.043500 -13.525  < 2e-16 ***
Group4            -1.321622   0.058344 -22.652  < 2e-16 ***
AssignedTeacherB   0.225250   0.102817   2.191   0.0329 *  
AssignedTeacherC   0.183846   0.103356   1.779   0.0810 .  
AssignedTeacherD   0.066154   0.103356   0.640   0.5249    
AssignedTeacherE   0.093191   0.104957   0.888   0.3786    
AssignedTeacherFT  0.033096   0.103356   0.320   0.7501    
AssignedTeacherG   0.041346   0.103356   0.400   0.6907    
AssignedTeacherH   0.130846   0.103356   1.266   0.2111    
AssignedTeacherI   0.007691   0.104957   0.073   0.9419    
AssignedTeacherJ   0.260404   0.103356   2.519   0.0148 *  
AssignedTeacherK   0.264250   0.102817   2.570   0.0130 *  
AssignedTeacherL   0.005017   0.114247   0.044   0.9651    
AssignedTeacherMT  0.202096   0.111863   1.807   0.0765 .  
AssignedTeacherN  -0.007777   0.112184  -0.069   0.9450    
AssignedTeacherO   0.175557   0.112184   1.565   0.1236    
AssignedTeacherP   0.143302   0.113299   1.265   0.2115    
AssignedTeacherQ   0.021557   0.112184   0.192   0.8484    
AssignedTeacherR   0.193096   0.111863   1.726   0.0901 .  
AssignedTeacherS   0.087351   0.114247   0.765   0.4479    
AssignedTeacherT   0.113557   0.112184   1.012   0.3160    
AssignedTeacherU   0.023890   0.112184   0.213   0.8322    
AssignedTeacherV   0.165351   0.114247   1.447   0.1537    
AssignedTeacherW   0.211429   0.111863   1.890   0.0642 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1454 on 53 degrees of freedom
Multiple R-squared:  0.9271,    Adjusted R-squared:  0.8914 
F-statistic: 25.93 on 26 and 53 DF,  p-value: < 2.2e-16
library(performance)
check_model(full_model)  # All diagnostic plots

Outlier Detection

  1. Detect outliers in CGPA using the IQR rule
  2. Visualize outliers using boxplots
# Detect outliers using IQR rule
Q1 <- quantile(df$CGPA, 0.25)
Q3 <- quantile(df$CGPA, 0.75)
IQR_val <- Q3 - Q1
lower <- Q1 - 1.5 * IQR_val
upper <- Q3 + 1.5 * IQR_val

outliers <- df[df$CGPA < lower | df$CGPA > upper, ]
cat("\nOutliers detected:", nrow(outliers), "\n")

Outliers detected: 4 
# Boxplot in one line
boxplot(df$CGPA, col = "lightblue", main = "CGPA Distribution with Outliers", 
        ylab = "CGPA", outline = TRUE)

Regression Diagnostics

For the multiple regression model (CGPA ~ Sex + Group + AssignedTeacher), check:

  1. Linearity
  2. Normality
  3. Homoscedasticity
  4. Multicollinearity
# Fit the model
full_model <- lm(CGPA ~ Sex + Group + AssignedTeacher, data = df)

# 1. Diagnostic plots (Linearity, Homoscedasticity, Normality of residuals)
par(mfrow = c(2, 2))   # 2x2 layout
plot(full_model)        # Generates:
                        # 1. Residuals vs Fitted → checks linearity
                        # 2. Normal Q-Q → checks residual normality
                        # 3. Scale-Location → checks homoscedasticity
                        # 4. Residuals vs Leverage → checks influential points
par(mfrow = c(1, 1))   # Reset layout


# 2. Normality test of residuals
cat("\nShapiro-Wilk Test on Residuals:\n")

Shapiro-Wilk Test on Residuals:
shapiro.test(residuals(full_model))

    Shapiro-Wilk normality test

data:  residuals(full_model)
W = 0.97797, p-value = 0.1824
# 3. Multicollinearity (VIF)
library(car)
cat("\nVariance Inflation Factors (VIF):\n")

Variance Inflation Factors (VIF):
vif(full_model)
                    GVIF Df GVIF^(1/(2*Df))
Sex             1.577656  1        1.256048
Group           1.241791  3        1.036752
AssignedTeacher 1.723375 22        1.012447
LS0tDQp0aXRsZTogJycNCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBodG1sX2RvY3VtZW50Og0KICAgIGRmX3ByaW50OiBwYWdlZA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KTG9hZCByZXF1aXJlZCBwYWNrYWdlcw0KYGBge3J9DQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHBzeWNoKSAjIGRlc2NyaWJlKCkNCmxpYnJhcnkoc2tpbXIpICMgc2tpbSgpDQpsaWJyYXJ5KHBhc3RlY3MpICMgc3RhdC5kZXNjKCkNCmBgYA0KTG9hZCBhbmQgc2VlIHRoZSBkYXRhDQpgYGB7cn0NCmRmIDwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcRGVsbFxcT25lRHJpdmVcXERlc2t0b3BcXFNUQVRJU1RJQ1NcXDJuZCBZZWFyXFxSIHByb2dyYW1taW5nXFx2YXJzaXR5XFxQcm9qZWN0X0Rpc3RyaWJ1dGlvbi54bHN4IikNCmRlc2NyaWJlKGRmKQ0KVmlldyhkZikNCnNraW0oZGYpDQpnbGltcHNlKGRmKQ0Kc3RhdC5kZXNjKGRmKQ0Kc3VtbWFyeShkZikgIyBFeGFtIFJvbGwgbnVtYmVycywgU2V4LCBDR1BBLCBHcm91cCBhc3NpZ25tZW50LCBhbmQgQXNzaWduZWQgVGVhY2hlcg0Kc3VtKGlzLm5hKGRmKSkgIyBubyBNaXNzaW5nIHZhbHVlcw0KYGBgDQpDb252ZXJ0IHZhcmlhYmxlIHR5cGVzDQpgYGB7cn0NCmRmJEV4YW1Sb2xsPC1hcy5jaGFyYWN0ZXIoZGYkRXhhbVJvbGwpDQpjbGFzcyhkZiRFeGFtUm9sbCkNCmRmJFNleCA8LSBhcy5mYWN0b3IoZGYkU2V4KQ0KY2xhc3MoZGYkU2V4KQ0KZGYkR3JvdXAgPC0gYXMuZmFjdG9yKGRmJEdyb3VwKQ0KY2xhc3MoZGYkR3JvdXApDQpkZiRBc3NpZ25lZFRlYWNoZXIgPC0gYXMuZmFjdG9yKGRmJEFzc2lnbmVkVGVhY2hlcikNCmNsYXNzKGRmJEFzc2lnbmVkVGVhY2hlcikNCmBgYA0KU2VlIHRoZSBkYXRhIGFnYWluDQpgYGB7cn0NCnN0cihkZikNCnN1bW1hcnkoZGYpDQpgYGANCiMgRGVzY3JpcHRpdmUgU3RhdGlzdGljcw0KRm9yIENHUEENCihpKSBNZWFuDQooaWkpIE1lZGlhbg0KKGlpaSkgU3RhbmRhcmQgZGV2aWF0aW9uDQpgYGB7cn0NCmRlc2NyaWJlKGRmJENHUEEpDQpgYGANCkZyZXF1ZW5jeSBEaXN0cmlidXRpb25zDQooaSkgU2V4DQooaWkpIEdyb3VwDQooaWlpKSBBc3NpZ25lZFRlYWNoZXINCmBgYHtyfQ0KdGFibGUoZGYkU2V4KQ0KdGFibGUoZGYkR3JvdXApDQp0YWJsZShkZiRBc3NpZ25lZFRlYWNoZXIpDQoNCmRmICU+JQ0KICBjb3VudChkZiRTZXgpICU+JSAgIyBGcmVxdWVuY3kNCiAgbXV0YXRlKA0KICAgIHBlcmNlbnQgPSBuIC8gc3VtKG4pICogMTAwLA0KICAgIGN1bV9uID0gY3Vtc3VtKG4pLA0KICAgIGN1bV9wZXJjZW50ID0gY3Vtc3VtKHBlcmNlbnQpLA0KICAgIHJlbGF0aXZlX2ZyZXEgPSBuIC8gc3VtKG4pLA0KICAgIGN1bV9yZWxhdGl2ZSA9IGN1bXN1bShyZWxhdGl2ZV9mcmVxKQ0KICApICU+JQ0KICByZW5hbWUoRnJlcXVlbmN5ID0gbikNCg0KZGYgJT4lDQogIGNvdW50KGRmJEdyb3VwKSAlPiUgICMgRnJlcXVlbmN5DQogIG11dGF0ZSgNCiAgICBwZXJjZW50ID0gbiAvIHN1bShuKSAqIDEwMCwNCiAgICBjdW1fbiA9IGN1bXN1bShuKSwNCiAgICBjdW1fcGVyY2VudCA9IGN1bXN1bShwZXJjZW50KSwNCiAgICByZWxhdGl2ZV9mcmVxID0gbiAvIHN1bShuKSwNCiAgICBjdW1fcmVsYXRpdmUgPSBjdW1zdW0ocmVsYXRpdmVfZnJlcSkNCiAgKSAlPiUNCiAgcmVuYW1lKEZyZXF1ZW5jeSA9IG4pDQoNCmRmICU+JQ0KICBjb3VudChkZiRBc3NpZ25lZFRlYWNoZXIpICU+JSAgIyBGcmVxdWVuY3kNCiAgbXV0YXRlKA0KICAgIHBlcmNlbnQgPSBuIC8gc3VtKG4pICogMTAwLA0KICAgIGN1bV9uID0gY3Vtc3VtKG4pLA0KICAgIGN1bV9wZXJjZW50ID0gY3Vtc3VtKHBlcmNlbnQpLA0KICAgIHJlbGF0aXZlX2ZyZXEgPSBuIC8gc3VtKG4pLA0KICAgIGN1bV9yZWxhdGl2ZSA9IGN1bXN1bShyZWxhdGl2ZV9mcmVxKQ0KICApICU+JQ0KICByZW5hbWUoRnJlcXVlbmN5ID0gbikNCmBgYA0KR3JvdXAgQ29tcGFyaXNvbnMNCihpKSBDR1BBIGJ5IFNleCAobWVhbiwgU0QsIGNvdW50KQ0KKGlpKSBDR1BBIGJ5IEdyb3VwIChtZWFuLCBTRCwgY291bnQpDQpgYGB7cn0NCiMgVXNpbmcgZHBseXIgKHJlY29tbWVuZGVkKQ0KcmVzdWx0IDwtIGRmICU+JQ0KICBncm91cF9ieShTZXgpICU+JQ0KICBzdW1tYXJpc2UoDQogICAgQ291bnQgPSBuKCksDQogICAgTWVhbl9DR1BBID0gcm91bmQobWVhbihDR1BBLCBuYS5ybSA9IFRSVUUpLCAyKSwNCiAgICBTRF9DR1BBID0gcm91bmQoc2QoQ0dQQSwgbmEucm0gPSBUUlVFKSwgMiksDQogICAgLmdyb3VwcyA9ICdkcm9wJw0KICApDQpyZXN1bHQNCiMga25pdHI6OmthYmxlKHJlc3VsdCwgY2FwdGlvbiA9ICJDR1BBIGJ5IFNleCIpICMgRGlzcGxheSBuaWNlbHkNCg0KcmVzdWx0IDwtIGRmICU+JQ0KICBncm91cF9ieShHcm91cCkgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBDb3VudCA9IG4oKSwNCiAgICBNZWFuX0NHUEEgPSByb3VuZChtZWFuKENHUEEsIG5hLnJtID0gVFJVRSksIDIpLA0KICAgIFNEX0NHUEEgPSByb3VuZChzZChDR1BBLCBuYS5ybSA9IFRSVUUpLCAyKSwNCiAgICAuZ3JvdXBzID0gJ2Ryb3AnDQogICkNCnJlc3VsdA0KDQojIEZvciBldmVyeWRheSB1c2U6IGRwbHlyIChtb3N0IHJlYWRhYmxlIGFuZCBmbGV4aWJsZSkNCg0KIyBGb3IgcXVpY2sgYW5hbHlzaXM6IHBzeWNoOjpkZXNjcmliZUJ5KCkNCg0KIyBGb3IgbGFyZ2UgZGF0YXNldHM6IGRhdGEudGFibGUNCg0KIyBGb3IgcHVibGljYXRpb246IGd0c3VtbWFyeQ0KYGBgDQojIERhdGEgVmlzdWFsaXphdGlvbg0KDQpEaXN0cmlidXRpb24gUGxvdHMgDQooaSkgSGlzdG9ncmFtIG9mIENHUEENCihpaSkgRGVuc2l0eSBwbG90IG9mIENHUEENCg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJlc3F1aXNzZSIpDQojIGxpYnJhcnkoZXNxdWlzc2UpICMgQ3JlYXRlcyBnZ3Bsb3QyIGNvZGUgYXV0b21hdGljYWxseQ0KIyBlc3F1aXNzZXIoZGYpICMgT3BlbnMgZHJhZy1hbmQtZHJvcCBpbnRlcmZhY2UNCmBgYA0KYGBge3J9DQojIFRlbXBsYXRlIGZvciBhbnkgcGxvdA0KI2dncGxvdChkYXRhID0gZGYsIGFlcyh4ID0geF92YXJpYWJsZSwgeSA9IHlfdmFyaWFibGUpKSArDQojICBnZW9tXyooYWVzKGNvbG9yL2ZpbGwgPSBncm91cGluZ192YXJpYWJsZSkpICsgICMgQ2hvb3NlIGdlb20NCiMgIGxhYnModGl0bGUgPSAiVGl0bGUiLCB4ID0gIlggTGFiZWwiLCB5ID0gIlkgTGFiZWwiKSArDQojICB0aGVtZV9taW5pbWFsKCkgKw0KIyAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgICMgQ29sb3IgcGFsZXR0ZQ0KDQoNCiMgSGlzdG9ncmFtIG9mIENHUEENCmdncGxvdChkZiwgYWVzKHggPSBDR1BBKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzAsIGZpbGwgPSAic3RlZWxibHVlIiwgY29sb3IgPSAid2hpdGUiKSArDQogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIG9mIENHUEEiLCB4ID0gIkNHUEEiLCB5ID0gIkNvdW50IikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBEZW5zaXR5IHBsb3Qgb2YgQ0dQQQ0KZ2dwbG90KGRmLCBhZXMoeCA9IENHUEEpKSArDQogIGdlb21fZGVuc2l0eShmaWxsID0gInN0ZWVsYmx1ZSIsIGFscGhhID0gMC41LCBjb2xvciA9IE5BKSArDQogIGxhYnModGl0bGUgPSAiRGVuc2l0eSBQbG90IG9mIENHUEEiLCB4ID0gIkNHUEEiLCB5ID0gIkRlbnNpdHkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQoNCmBgYA0KQ2F0ZWdvcmljYWwgRGF0YSBQbG90czoNCihpKSBCYXIgcGxvdCBvZiBTZXgNCihpaSkgQmFyIHBsb3Qgb2YgR3JvdXANCihpaWkpIEJhciBwbG90IG9mIEFzc2lnbmVkVGVhY2hlcg0KYGBge3J9DQojIEJhciBwbG90IG9mIFNleA0KZ2dwbG90KGRmLCBhZXMoeCA9IFNleCwgZmlsbCA9IFNleCwgZ3JvdXAgPSBTZXgpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIkJhciBQbG90IG9mIFNleCIsIHggPSAiU2V4IiwgeSA9ICJDb3VudCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikNCg0KIyBCYXIgcGxvdCBvZiBHcm91cA0KZ2dwbG90KGRmLCBhZXMoeCA9IEdyb3VwLCBmaWxsID0gR3JvdXAsIGdyb3VwID0gR3JvdXApKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIkJhciBQbG90IG9mIEdyb3VwIiwgeCA9ICJHcm91cCIsIHkgPSAiQ291bnQiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpDQoNCiMgQmFyIHBsb3Qgb2YgQXNzaWduZWQgVGVhY2hlciANCmdncGxvdChkZiwgYWVzKHggPSBBc3NpZ25lZFRlYWNoZXIsIGZpbGwgPSBBc3NpZ25lZFRlYWNoZXIsIGdyb3VwID0gQXNzaWduZWRUZWFjaGVyKSkgKw0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJCYXIgUGxvdCBvZiBBc3NpZ25lZCBUZWFjaGVyIiwNCiAgICAgICB4ID0gIkFzc2lnbmVkIFRlYWNoZXIiLCB5ID0gIkNvdW50IikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgpICAgICAgICAjIG1hbnkgY2F0ZWdvcmllcyDihpIgbm8gQnJld2VyIHBhbGV0dGUNCg0KYGBgDQpFYXNpZXIgV2F5DQpgYGB7cn0NCiMgQmFyIHBsb3Qgb2YgU2V4DQpiYXJwbG90KHRhYmxlKGRmJFNleCksIG1haW4gPSAiQ291bnQgYnkgU2V4IiwgeGxhYiA9ICJTZXgiLCB5bGFiID0gIkNvdW50IikNCiMgQmFyIHBsb3Qgb2YgR3JvdXANCmJhcnBsb3QodGFibGUoZGYkR3JvdXApLCBtYWluID0gIkNvdW50IGJ5IEdyb3VwIiwgeGxhYiA9ICJHcm91cCIsIHlsYWIgPSAiQ291bnQiKQ0KIyBCYXIgcGxvdCBvZiBBc3NpZ25lZFRlYWNoZXINCmJhcnBsb3QodGFibGUoZGYkQXNzaWduZWRUZWFjaGVyKSwgbWFpbiA9ICJDb3VudCBieSBBc3NpZ25lZCBUZWFjaGVyIiwgDQogICAgICAgIHhsYWIgPSAiVGVhY2hlciIsIHlsYWIgPSAiQ291bnQiLCBsYXMgPSAyKQ0KYGBgDQpDb21wYXJhdGl2ZSBQbG90czoNCihpKSBCb3hwbG90IG9mIENHUEEgYnkgU2V4DQooaWkpIEJveHBsb3Qgb2YgQ0dQQSBieSBHcm91cA0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCmdncGxvdChkZiwgYWVzKHggPSBTZXgsIHkgPSBDR1BBLCBmaWxsID0gU2V4KSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjgsIG91dGxpZXIuY29sb3IgPSAicmVkIikgKw0KICBzdGF0X3N1bW1hcnkoZnVuID0gbWVhbiwNCiAgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLA0KICAgICAgICAgICAgICAgc2hhcGUgPSAyMywNCiAgICAgICAgICAgICAgIHNpemUgPSAzLA0KICAgICAgICAgICAgICAgZmlsbCA9ICJ5ZWxsb3ciKSArDQogIGxhYnModGl0bGUgPSAiQm94cGxvdCBvZiBDR1BBIGJ5IFNleCIsDQogICAgICAgeCA9ICJTZXgiLA0KICAgICAgIHkgPSAiQ0dQQSIpICsNCiAgdGhlbWVfbWluaW1hbCgpIA0KICANCmdncGxvdChkZiwgYWVzKHggPSBHcm91cCwgeSA9IENHUEEsIGZpbGwgPSBHcm91cCkpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC44LCBvdXRsaWVyLmNvbG9yID0gInJlZCIpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sDQogICAgICAgICAgICAgICBnZW9tID0gInBvaW50IiwNCiAgICAgICAgICAgICAgIHNoYXBlID0gMjMsDQogICAgICAgICAgICAgICBzaXplID0gMywNCiAgICAgICAgICAgICAgIGZpbGwgPSAieWVsbG93IikgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3Qgb2YgQ0dQQSBieSBHcm91cCIsDQogICAgICAgeCA9ICJHcm91cCIsDQogICAgICAgeSA9ICJDR1BBIikgKw0KICB0aGVtZV9taW5pbWFsKCkgDQoNCmBgYA0KRWFzaWVyIHdheToNCmBgYHtyfQ0KYm94cGxvdChDR1BBIH4gU2V4LCBkYXRhID0gZGYsIG1haW4gPSAiQ0dQQSBieSBTZXgiLCB4bGFiID0gIlNleCIsIHlsYWIgPSAiQ0dQQSIpDQpib3hwbG90KENHUEEgfiBHcm91cCwgZGF0YSA9IGRmLCBtYWluID0gIkNHUEEgYnkgR3JvdXAiLCB4bGFiID0gIkdyb3VwIiwgeWxhYiA9ICJDR1BBIikNCg0KYGBgDQojIEluZmVyZW50aWFsIFN0YXRpc3RpY3MNCg0KTWVhbiBDb21wYXJpc29ucyA6DQoxKSBJbmRlcGVuZGVudCBzYW1wbGVzIHQtdGVzdDogQ0dQQSBieSBTZXgNCjIpIE9uZS13YXkgQU5PVkE6IENHUEEgYnkgR3JvdXANCjMpIE9uZS13YXkgQU5PVkE6IENHUEEgYnkgQXNzaWduZWRUZWFjaGVyDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3N0YXRzcGxvdCkNCg0KIyB0LXRlc3Qgd2l0aCBwbG90DQpnZ2hpc3Rvc3RhdHMoDQogIGRhdGEgPSBkZiwNCiAgeCA9IENHUEEsDQogIHkgPSBTZXgsDQogIHR5cGUgPSAicGFyYW1ldHJpYyIsICAjIHQtdGVzdA0KICB0aXRsZSA9ICJDR1BBIGJ5IFNleCB3aXRoIHQtdGVzdCINCikNCg0KIyBBTk9WQSB3aXRoIHBsb3QNCmdnYmV0d2VlbnN0YXRzKA0KICBkYXRhID0gZGYsDQogIHggPSBHcm91cCwNCiAgeSA9IENHUEEsDQogIHR5cGUgPSAicGFyYW1ldHJpYyIsICAjIEFOT1ZBDQogIHRpdGxlID0gIkNHUEEgYnkgR3JvdXAgd2l0aCBBTk9WQSIsDQogIHBhaXJ3aXNlLmNvbXBhcmlzb25zID0gVFJVRSwgICMgU2hvd3MgcG9zdC1ob2MNCiAgcGFpcndpc2UuZGlzcGxheSA9ICJzaWduaWZpY2FudCINCikNCmBgYA0KRWFzaWVyIFdheToNCmBgYHtyfQ0KIyAoaSkgdC10ZXN0DQp0LnRlc3QoQ0dQQSB+IFNleCwgZGF0YSA9IGRmLCB2YXIuZXF1YWwgPSBUUlVFKSAgIyBFcXVhbCB2YXJpYW5jZXMNCnQudGVzdChDR1BBIH4gU2V4LCBkYXRhID0gZGYsIHZhci5lcXVhbCA9IEZBTFNFKSAjIFdlbGNoJ3MgdC10ZXN0DQoNCiMgKGlpKSBBTk9WQQ0KYW92X3Jlc3VsdCA8LSBhb3YoQ0dQQSB+IEdyb3VwLCBkYXRhID0gZGYpDQpzdW1tYXJ5KGFvdl9yZXN1bHQpICAjIEFOT1ZBIHRhYmxlDQoNCiMgKGlpaSkgQW5vdGhlciBBTk9WQQ0KYW92X3RlYWNoZXIgPC0gYW92KENHUEEgfiBBc3NpZ25lZFRlYWNoZXIsIGRhdGEgPSBkZikNCnN1bW1hcnkoYW92X3RlYWNoZXIpDQoNCiMgUG9zdC1ob2MgdGVzdHMNClR1a2V5SFNEKGFvdl9yZXN1bHQpICAjIFR1a2V5J3MgSFNEDQpwYWlyd2lzZS50LnRlc3QoZGYkQ0dQQSwgZGYkR3JvdXAsIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIikNCmBgYA0KQXNzb2NpYXRpb24gVGVzdHMgOg0KKGkpIENoaS1zcXVhcmUgdGVzdDogU2V4IHZzIEdyb3VwDQooaWkpIENoaS1zcXVhcmUgdGVzdDogU2V4IHZzIEFzc2lnbmVkVGVhY2hlcg0KYGBge3J9DQpsaWJyYXJ5KGdnc3RhdHNwbG90KQ0KDQojIFNleCB2cyBHcm91cCB3aXRoIGNoaS1zcXVhcmUNCmdnYmFyc3RhdHMoDQogIGRhdGEgPSBkZiwNCiAgeCA9IFNleCwNCiAgeSA9IEdyb3VwLA0KICB0aXRsZSA9ICJBc3NvY2lhdGlvbjogU2V4IHZzIEdyb3VwIiwNCiAgcmVzdWx0cy5zdWJ0aXRsZSA9IFRSVUUsDQogIGxhYmVsID0gImJvdGgiLCAgIyBTaG93IGNvdW50cyBhbmQgcGVyY2VudGFnZXMNCiAgcGVyYy5rID0gMSAgICAgICAjIERlY2ltYWwgcGxhY2VzIGZvciBwZXJjZW50YWdlcw0KKQ0KDQojIFNleCB2cyBBc3NpZ25lZFRlYWNoZXINCmdnYmFyc3RhdHMoDQogIGRhdGEgPSBkZiwNCiAgeCA9IFNleCwNCiAgeSA9IEFzc2lnbmVkVGVhY2hlciwNCiAgdGl0bGUgPSAiQXNzb2NpYXRpb246IFNleCB2cyBBc3NpZ25lZFRlYWNoZXIiDQopDQpgYGANCkVhc2llciBXYXk6DQpgYGB7cn0NCiMgU2V4IHZzIEdyb3VwIHdpdGggY2hpLXNxdWFyZQ0KY2hpc3EudGVzdCh0YWJsZShkZiRTZXgsIGRmJEdyb3VwKSkNCiMgU2V4IHZzIEFzc2lnbmVkVGVhY2hlcg0KY2hpc3EudGVzdCh0YWJsZShkZiRTZXgsIGRmJEFzc2lnbmVkVGVhY2hlcikpDQoNCmBgYA0KIyBSZWdyZXNzaW9uIEFuYWx5c2lzDQoNClNpbXBsZSBMaW5lYXIgUmVncmVzc2lvbiA6DQooaSkgTW9kZWwgMTogQ0dQQSB+IFNleA0KKGlpKSBNb2RlbCAyOiBDR1BBIH4gR3JvdXANCmBgYHtyfQ0Kc3VtbWFyeShsbShDR1BBIH4gU2V4LCBkYXRhID0gZGYpKQ0Kc3VtbWFyeShsbShDR1BBIH4gR3JvdXAsIGRhdGEgPSBkZikpDQpgYGANCk11bHRpcGxlIFJlZ3Jlc3Npb24gOg0KRnVsbCBtb2RlbDogQ0dQQSB+IFNleCArIEdyb3VwICsgQXNzaWduZWRUZWFjaGVyDQpgYGB7cn0NCg0KIyBGdWxsIG1vZGVsDQpmdWxsX21vZGVsIDwtIGxtKENHUEEgfiBTZXggKyBHcm91cCArIEFzc2lnbmVkVGVhY2hlciwgZGF0YSA9IGRmKQ0Kc3VtbWFyeShmdWxsX21vZGVsKQ0KDQojIEFsbCBkaWFnbm9zdGljIHBsb3RzDQpsaWJyYXJ5KHBlcmZvcm1hbmNlKQ0KY2hlY2tfbW9kZWwoZnVsbF9tb2RlbCkgIA0KYGBgDQojICBPdXRsaWVyIERldGVjdGlvbg0KDQooaSkgRGV0ZWN0IG91dGxpZXJzIGluIENHUEEgdXNpbmcgdGhlIElRUiBydWxlDQooaWkpIFZpc3VhbGl6ZSBvdXRsaWVycyB1c2luZyBib3hwbG90cw0KYGBge3J9DQojIERldGVjdCBvdXRsaWVycyB1c2luZyBJUVIgcnVsZQ0KUTEgPC0gcXVhbnRpbGUoZGYkQ0dQQSwgMC4yNSkNClEzIDwtIHF1YW50aWxlKGRmJENHUEEsIDAuNzUpDQpJUVJfdmFsIDwtIFEzIC0gUTENCmxvd2VyIDwtIFExIC0gMS41ICogSVFSX3ZhbA0KdXBwZXIgPC0gUTMgKyAxLjUgKiBJUVJfdmFsDQoNCm91dGxpZXJzIDwtIGRmW2RmJENHUEEgPCBsb3dlciB8IGRmJENHUEEgPiB1cHBlciwgXQ0KY2F0KCJcbk91dGxpZXJzIGRldGVjdGVkOiIsIG5yb3cob3V0bGllcnMpLCAiXG4iKQ0KYGBgDQpgYGB7cn0NCiMgQm94cGxvdCBpbiBvbmUgbGluZQ0KYm94cGxvdChkZiRDR1BBLCBjb2wgPSAibGlnaHRibHVlIiwgbWFpbiA9ICJDR1BBIERpc3RyaWJ1dGlvbiB3aXRoIE91dGxpZXJzIiwgDQogICAgICAgIHlsYWIgPSAiQ0dQQSIsIG91dGxpbmUgPSBUUlVFKQ0KYGBgDQojIFJlZ3Jlc3Npb24gRGlhZ25vc3RpY3MNCg0KRm9yIHRoZSBtdWx0aXBsZSByZWdyZXNzaW9uIG1vZGVsIChDR1BBIH4gU2V4ICsgR3JvdXAgKyBBc3NpZ25lZFRlYWNoZXIpLCBjaGVjazoNCg0KaSkgTGluZWFyaXR5DQppaSkgTm9ybWFsaXR5DQppaWkpIEhvbW9zY2VkYXN0aWNpdHkNCml2KSBNdWx0aWNvbGxpbmVhcml0eQ0KYGBge3J9DQojIEZpdCB0aGUgbW9kZWwNCmZ1bGxfbW9kZWwgPC0gbG0oQ0dQQSB+IFNleCArIEdyb3VwICsgQXNzaWduZWRUZWFjaGVyLCBkYXRhID0gZGYpDQoNCiMgMS4gRGlhZ25vc3RpYyBwbG90cyAoTGluZWFyaXR5LCBIb21vc2NlZGFzdGljaXR5LCBOb3JtYWxpdHkgb2YgcmVzaWR1YWxzKQ0KcGFyKG1mcm93ID0gYygyLCAyKSkgICAjIDJ4MiBsYXlvdXQNCnBsb3QoZnVsbF9tb2RlbCkgICAgICAgICMgR2VuZXJhdGVzOg0KICAgICAgICAgICAgICAgICAgICAgICAgIyAxLiBSZXNpZHVhbHMgdnMgRml0dGVkIOKGkiBjaGVja3MgbGluZWFyaXR5DQogICAgICAgICAgICAgICAgICAgICAgICAjIDIuIE5vcm1hbCBRLVEg4oaSIGNoZWNrcyByZXNpZHVhbCBub3JtYWxpdHkNCiAgICAgICAgICAgICAgICAgICAgICAgICMgMy4gU2NhbGUtTG9jYXRpb24g4oaSIGNoZWNrcyBob21vc2NlZGFzdGljaXR5DQogICAgICAgICAgICAgICAgICAgICAgICAjIDQuIFJlc2lkdWFscyB2cyBMZXZlcmFnZSDihpIgY2hlY2tzIGluZmx1ZW50aWFsIHBvaW50cw0KcGFyKG1mcm93ID0gYygxLCAxKSkgICAjIFJlc2V0IGxheW91dA0KDQojIDIuIE5vcm1hbGl0eSB0ZXN0IG9mIHJlc2lkdWFscw0KY2F0KCJcblNoYXBpcm8tV2lsayBUZXN0IG9uIFJlc2lkdWFsczpcbiIpDQpzaGFwaXJvLnRlc3QocmVzaWR1YWxzKGZ1bGxfbW9kZWwpKQ0KDQojIDMuIE11bHRpY29sbGluZWFyaXR5IChWSUYpDQpsaWJyYXJ5KGNhcikNCmNhdCgiXG5WYXJpYW5jZSBJbmZsYXRpb24gRmFjdG9ycyAoVklGKTpcbiIpDQp2aWYoZnVsbF9tb2RlbCkNCg0KYGBgDQoNCg==