0.1 Project Motivation

Being a nerdy kaggler, it was no brainer to pick 1 out of 54k+ public datasets. Totally didn’t have paradox of choice/existential crisis. It lead me to find something completely opposite to what I was feeling; a dataset of happiness levels around the globe.
The World Happiness Report 2021 focuses on the effects of COVID-19 and how people all over the world have fared. The reports review the state of happiness in the world today and show how the new science of happiness explains personal and national variations in happiness.
That’s how I decided to check out the pursuit of happi(y)ness.

0.1.1 Content

The happiness scores and rankings use data from the Gallup World Poll . The columns following the happiness score estimate the extent to which each of six factors – economic production, social support, life expectancy, freedom, absence of corruption, and generosity – contribute to making life evaluations higher in each country than they are in Dystopia, a hypothetical country that has values equal to the world’s lowest national averages for each of the six factors.

0.1.2 Data Source

  • For this analysis, the scope is just limited to the World Happiness 2021 and World Happiness (2005-2020) dataset.

  • The Happiness 2021 dataset was sourced from Kaggle.

  • Due to the sheer volume of data, the analysis focused specifically on 10 variables.The table below provides a description of the variables used during the analysis

  • Data Dictionary

Variable Datatype Explaination
country_name character Country name (141 countries)
year integer Year
ladder_score numeric Life evaluation score
regional_indicator numeric Region (10 Regions)
logged_GDP_per_capita numeric Extent to which GDP contributes to the calculation of the Ladder score
healthy_life_expectancy numeric Healthy life expectancies at birth based on the data extracted from the World Health Organisation (WHO) data repository
social_support numeric Defined as having someone to count on in times of trouble (ranked from 0 to 1)
freedom_to_make_life_choices numeric Defined as the national average of responses to the Gall-WorldPoll question (“Are you satisfied or dissatisfied with your freedom to choose what you do with your life?”)
generosity numeric National average of responses to the question - “Have you donated money to a charity in the past month?”
perception_of_corruption numeric National average of responses to the questions (“Is corruption widespread throughout the government or not” and “Is corruption widespread within businesses or not?” )
  • Details on the metadata of the dataset is provided under the References section.

Important steps-

  • To check my RPubs out click here

  • To check my github website click here

  • To check my GitHub repository out please click here

    • Clone my git repository
    • Open index.Rmd
    • Enter renv::restore()
    • Enter y

0.2 Research Questions

  • What is the effect of Covid19 on happiness levels in 2020 and 2021?
    • What are the top 10 happiest and saddest countries in 2021?
    • What is general trend of happiness in the world over last 3 years?
    • What factors contributed most to happiness scores?
    • Which regions showed change in happiness levels?

0.3 Data Preperation

0.3.1 Importing libraries and datasets

packages = c('tidyverse', # for easy handling of data
'heatmaply', # for visualizing data around plotly
'visdat', # for exploring missing data structure
'ggplot2', # for data visualization
'naniar', # for plotting missing values
'dplyr', # for data manipulation
'tidyr', # to create tidy data
'hrbrthemes', # to include additional themes for ggplot2
'ggchicklet', #stylize charts
'ggalt', # for statistical transformation
'corrplot', # for correlogram
'plotly', # for interactive and publication quality graphs
'cowplot', #add-on to ggplot
'patchwork', # to create layouts in ggplot
'RColorBrewer', # for ready to use color palettes
'ggbeeswarm', # to plot scatterplots
'scales', # for internal scaling
'kableExtra' # to build tables
)
for (p in packages){
  if(!require(p, character.only = T)){
    install.packages(p)
  }
  library(p,character.only = T)
}

#Reading the data
df_2021 <- read.csv("data/world-happiness-report-2021.csv")
df_all <- read.csv("data/world-happiness-report.csv")

0.4 Exploratory Data Analysis and cleaning

0.4.1 Full dataset (2005-2020)

Displaying dataset from 2005 t0 2020

df1<-head(df_all)
kable(df1) %>%
kable_styling(bootstrap_options = "condensed", font_size= 8, full_width = F)
ï..country_name year life_ladder log_GDP_per_capita social_support healthy_life_expectancy_at_birth freedom_to_make_life_choices generosity perceptions_of_corruption positive_affect negative_affect
Afghanistan 2008 3.724 7.370 0.451 50.80 0.718 0.168 0.882 0.518 0.258
Afghanistan 2009 4.402 7.540 0.552 51.20 0.679 0.190 0.850 0.584 0.237
Afghanistan 2010 4.758 7.647 0.539 51.60 0.600 0.121 0.707 0.618 0.275
Afghanistan 2011 3.832 7.620 0.521 51.92 0.496 0.162 0.731 0.611 0.267
Afghanistan 2012 3.783 7.705 0.521 52.24 0.531 0.236 0.776 0.710 0.268
Afghanistan 2013 3.572 7.725 0.484 52.56 0.578 0.061 0.823 0.621 0.273

0.4.2 Dataset 2021

Displaying dataset 2021

df2<-head(df_2021)
kable(df2) %>%
kable_styling(bootstrap_options = "condensed", font_size= 8, full_width = F)
ï..country_name regional_indicator ladder_score standard_error_of_ladder_score upperwhisker lowerwhisker logged_GDP_per_capita social_support healthy_life_expectancy freedom_to_make_life_choices generosity perceptions_of_corruption ladder_score_in_dystopia explained_by_Log_GDP_per_capita explained_by_social_support explained_by_healthy_life_expectancy explained_by_freedom_to_make_life_choices explained_by_generosity explained_by_perceptions_of_corruption dystopia_residual
Finland Western Europe 7.842 0.032 7.904 7.780 10.775 0.954 72.0 0.949 -0.098 0.186 2.43 1.446 1.106 0.741 0.691 0.124 0.481 3.253
Denmark Western Europe 7.620 0.035 7.687 7.552 10.933 0.954 72.7 0.946 0.030 0.179 2.43 1.502 1.108 0.763 0.686 0.208 0.485 2.868
Switzerland Western Europe 7.571 0.036 7.643 7.500 11.117 0.942 74.4 0.919 0.025 0.292 2.43 1.566 1.079 0.816 0.653 0.204 0.413 2.839
Iceland Western Europe 7.554 0.059 7.670 7.438 10.878 0.983 73.0 0.955 0.160 0.673 2.43 1.482 1.172 0.772 0.698 0.293 0.170 2.967
Netherlands Western Europe 7.464 0.027 7.518 7.410 10.932 0.942 72.4 0.913 0.175 0.338 2.43 1.501 1.079 0.753 0.647 0.302 0.384 2.798
Norway Western Europe 7.392 0.035 7.462 7.323 11.053 0.954 73.3 0.960 0.093 0.270 2.43 1.543 1.108 0.782 0.703 0.249 0.427 2.580

0.4.3 Exploring data

Visualizing datasets to check datatypes.

vis_data_1 <- vis_dat(df_2021)+ labs(x = "Datatypes for 2021 dataset")
vis_data_2 <- vis_dat(df_all)+ labs(x = "Datatypes for all dataset")
vis_data_1 + vis_data_2
Figure 1: Plots showing datatypes

Figure 1: Plots showing datatypes

Both datasets show numeric and character datatypes with few NA values.

0.4.4 Checking for missing values

Plotting missing values of both datasets.

miss_data_1 <- gg_miss_var(df_2021) + labs(y = "Checking for the missing ones in 2021")
miss_data_2 <- gg_miss_var(df_all) + labs(y = "Checking for the missing ones in full_data")
miss_data_1 + miss_data_2
Figure 2: Plots of missing values

Figure 2: Plots of missing values

df_2021 has no missing values whereas df_all has some columns with missing values.

0.4.5 Treating NA values

Imputing missing values with mean of the columns

df_all[sapply(df_all, is.numeric)] <- lapply(df_all[sapply(df_all, is.numeric)], function(x) ifelse(is.na(x), mean(x, na.rm = TRUE), x))  
df_all %>% summarise(across(everything(), ~ sum(is.na(.))))

0.4.6 Cleaned dataset

Checking for NA values in dataset.

gg_miss_var(df_all) + labs(y = "Checking for the missing ones in full_data")
Figure 3: Plot of NA for cleaned dataset

Figure 3: Plot of NA for cleaned dataset

Dataset has no missing values after treatment.

0.4.7 Summary of full dataset

summary(df_all)
##  ï..country_name         year       life_ladder    log_GDP_per_capita
##  Length:1949        Min.   :2005   Min.   :2.375   Min.   : 6.635    
##  Class :character   1st Qu.:2010   1st Qu.:4.640   1st Qu.: 8.478    
##  Mode  :character   Median :2013   Median :5.386   Median : 9.443    
##                     Mean   :2013   Mean   :5.467   Mean   : 9.368    
##                     3rd Qu.:2017   3rd Qu.:6.283   3rd Qu.:10.335    
##                     Max.   :2020   Max.   :8.019   Max.   :11.648    
##  social_support   healthy_life_expectancy_at_birth freedom_to_make_life_choices
##  Min.   :0.2900   Min.   :32.30                    Min.   :0.2580              
##  1st Qu.:0.7510   1st Qu.:58.90                    1st Qu.:0.6490              
##  Median :0.8340   Median :65.00                    Median :0.7590              
##  Mean   :0.8126   Mean   :63.36                    Mean   :0.7426              
##  3rd Qu.:0.9050   3rd Qu.:68.40                    3rd Qu.:0.8540              
##  Max.   :0.9870   Max.   :77.10                    Max.   :0.9850              
##    generosity         perceptions_of_corruption positive_affect
##  Min.   :-0.3350000   Min.   :0.0350            Min.   :0.322  
##  1st Qu.:-0.1060000   1st Qu.:0.6990            1st Qu.:0.627  
##  Median :-0.0160000   Median :0.7930            Median :0.718  
##  Mean   : 0.0001032   Mean   :0.7471            Mean   :0.710  
##  3rd Qu.: 0.0850000   3rd Qu.:0.8680            3rd Qu.:0.798  
##  Max.   : 0.6980000   Max.   :0.9830            Max.   :0.944  
##  negative_affect 
##  Min.   :0.0830  
##  1st Qu.:0.2070  
##  Median :0.2600  
##  Mean   :0.2685  
##  3rd Qu.:0.3190  
##  Max.   :0.7050

0.4.8 Summary of full dataset

summary(df_2021)
##  ï..country_name    regional_indicator  ladder_score  
##  Length:149         Length:149         Min.   :2.523  
##  Class :character   Class :character   1st Qu.:4.852  
##  Mode  :character   Mode  :character   Median :5.534  
##                                        Mean   :5.533  
##                                        3rd Qu.:6.255  
##                                        Max.   :7.842  
##  standard_error_of_ladder_score  upperwhisker    lowerwhisker  
##  Min.   :0.02600                Min.   :2.596   Min.   :2.449  
##  1st Qu.:0.04300                1st Qu.:4.991   1st Qu.:4.706  
##  Median :0.05400                Median :5.625   Median :5.413  
##  Mean   :0.05875                Mean   :5.648   Mean   :5.418  
##  3rd Qu.:0.07000                3rd Qu.:6.344   3rd Qu.:6.128  
##  Max.   :0.17300                Max.   :7.904   Max.   :7.780  
##  logged_GDP_per_capita social_support   healthy_life_expectancy
##  Min.   : 6.635        Min.   :0.4630   Min.   :48.48          
##  1st Qu.: 8.541        1st Qu.:0.7500   1st Qu.:59.80          
##  Median : 9.569        Median :0.8320   Median :66.60          
##  Mean   : 9.432        Mean   :0.8147   Mean   :64.99          
##  3rd Qu.:10.421        3rd Qu.:0.9050   3rd Qu.:69.60          
##  Max.   :11.647        Max.   :0.9830   Max.   :76.95          
##  freedom_to_make_life_choices   generosity       perceptions_of_corruption
##  Min.   :0.3820               Min.   :-0.28800   Min.   :0.0820           
##  1st Qu.:0.7180               1st Qu.:-0.12600   1st Qu.:0.6670           
##  Median :0.8040               Median :-0.03600   Median :0.7810           
##  Mean   :0.7916               Mean   :-0.01513   Mean   :0.7274           
##  3rd Qu.:0.8770               3rd Qu.: 0.07900   3rd Qu.:0.8450           
##  Max.   :0.9700               Max.   : 0.54200   Max.   :0.9390           
##  ladder_score_in_dystopia explained_by_Log_GDP_per_capita
##  Min.   :2.43             Min.   :0.0000                 
##  1st Qu.:2.43             1st Qu.:0.6660                 
##  Median :2.43             Median :1.0250                 
##  Mean   :2.43             Mean   :0.9772                 
##  3rd Qu.:2.43             3rd Qu.:1.3230                 
##  Max.   :2.43             Max.   :1.7510                 
##  explained_by_social_support explained_by_healthy_life_expectancy
##  Min.   :0.0000              Min.   :0.0000                      
##  1st Qu.:0.6470              1st Qu.:0.3570                      
##  Median :0.8320              Median :0.5710                      
##  Mean   :0.7933              Mean   :0.5202                      
##  3rd Qu.:0.9960              3rd Qu.:0.6650                      
##  Max.   :1.1720              Max.   :0.8970                      
##  explained_by_freedom_to_make_life_choices explained_by_generosity
##  Min.   :0.0000                            Min.   :0.000          
##  1st Qu.:0.4090                            1st Qu.:0.105          
##  Median :0.5140                            Median :0.164          
##  Mean   :0.4987                            Mean   :0.178          
##  3rd Qu.:0.6030                            3rd Qu.:0.239          
##  Max.   :0.7160                            Max.   :0.541          
##  explained_by_perceptions_of_corruption dystopia_residual
##  Min.   :0.0000                         Min.   :0.648    
##  1st Qu.:0.0600                         1st Qu.:2.138    
##  Median :0.1010                         Median :2.509    
##  Mean   :0.1351                         Mean   :2.430    
##  3rd Qu.:0.1740                         3rd Qu.:2.794    
##  Max.   :0.5470                         Max.   :3.482

0.5 Visualization 1 -Top 10 happiest and saddest countries in 2021

0.5.1 Getting top and bottom 10 countries.

Mapping countries by region and filtering countries by ladder_score i.e. happiness level.

# Subsetting dimensions
dimensions <- c('ladder_score',
                'logged_GDP_per_capita',
                'social_support',
                'healthy_life_expectancy',
                'freedom_to_make_life_choices',
                'generosity',
                'perceptions_of_corruption')

# Mapping country to regions
country_region_dict = df_2021 %>% 
  select(country = ï..country_name, region = regional_indicator) %>% unique()

df_2021_long <- df_2021 %>% 
  select(country = ï..country_name, all_of(dimensions)) %>%
  mutate(absence_of_corruption = 1- perceptions_of_corruption) %>%
  pivot_longer(cols = c(all_of(dimensions),'absence_of_corruption'),
               names_to = 'dimension', values_to = 'score') %>%
  filter(dimension != "perceptions_of_corruption")

# Calculating score using min max values
df_2021_tranformed <- df_2021_long %>%
  group_by(dimension) %>%
  mutate(min_value = min(score),
         max_value = max(score)) %>%
  mutate(score_pct = (score-min_value)/(max_value-min_value)) %>%
  ungroup()

# Getting top 10 countries
df_2021_top10 <- df_2021_tranformed %>%
  filter(dimension == "ladder_score") %>%
  slice_max(score, n = 10) %>%
  mutate(cat = 'top_10', 
         country_rank = rank(-score),
         country_label = paste0(country, ' (', country_rank, ')'))

# Getting bottom 10 countries
df_2021_bottom10 <- df_2021_tranformed %>%
  filter(dimension == "ladder_score") %>%
  mutate(country_rank = rank(score),
         country_label = paste0(country, ' (', country_rank, ')')) %>%
  slice_min(score, n = 10) %>%
  mutate(cat = 'bottom_10')

0.5.2 Plotting top and bottom 10 countries

# Plotting top 10 happiest countries 
top_10 <- ggplot(df_2021_top10, aes(x = reorder(country_label, score))) + 
  geom_chicklet(aes(y = 10, fill = 4.9), width = 0.5, radius = grid::unit(5, "pt")) +
  geom_chicklet(aes(y = score, fill = score), width = 0.5, radius = grid::unit(5, "pt")) +
  geom_text(aes(y = score), label = round(df_2021_top10$score,2), nudge_y = 0.4, size = 3) + 
  scale_y_continuous(expand = c(0, 0.1), position = "right", limits = c(0, 10)) +
  scale_fill_gradient2(low = 'black', high = '#818aeb', mid = 'white', midpoint = 5) + 
  coord_flip() +
  labs(y="Best possible life = 10", x = '',
       title="Top 10 Happiest Countries in 2021",
       subtitle="9 of the happiest countries present in Europe",
       caption="Source: The World Happiness Report 2021") + 
  theme_ipsum(grid = '')  +
  theme(plot.title = element_text(size=15),
        plot.subtitle = element_text(size = 12),
        plot.caption = element_text(size = 10),
        axis.title.x = element_text(size= 10, color = '#555955'),
        axis.text.y = element_text(size = 10, color = 'black'),
        axis.text.x = element_blank(),
        legend.position = 'None')

# Plotting 10 saddest countries
bottom_10 <- ggplot(df_2021_bottom10, aes(x = reorder(country_label, score))) + 
  geom_chicklet(aes(y = 10, fill = 4.9), width = 0.5, radius = grid::unit(5, "pt")) +
  geom_chicklet(aes(y = score, fill = score), width = 0.5, radius = grid::unit(5, "pt")) +
  geom_text(aes(y = score), label = round(df_2021_bottom10$score,2), nudge_y = 0.4, size = 3) + 
  scale_y_continuous(expand = c(0, 0.1), position = "right", limits = c(0, 10)) +
  scale_fill_gradient2(low = '#074040', high = '#4cc2c2', mid = 'white', midpoint = 5) + 
  coord_flip() +
  labs(y="Best possible life = 10", x = '',
       title="Top 10 Saddest Countries in 2021",
       subtitle="Mostly struck by poverty",
       caption="Source: The World Happiness Report 2021") + 
  theme_ipsum(grid = '') +
  theme(plot.title = element_text(size=15),
        plot.subtitle = element_text(size = 12),
        plot.caption = element_text(size = 10),
        axis.title.x = element_text(size= 10, color = '#555955'),
        axis.text.y = element_text(size = 10, color = 'black'),
        axis.text.x = element_blank(),
        legend.position = 'None')

# Displaying plots side by side
top_10 + bottom_10
Figure 4: Plot of 10 happiest and saddest countries in the world

Figure 4: Plot of 10 happiest and saddest countries in the world

Most of the happiest countries comprise in Europe. Most saddest seem to be under financial crisis


0.6 Visualization 2 -Happiness trend in 2019, 2020 and 2021 (insights w.r.t. covid19)

0.6.1 Extracting relevant columns for analysis

Subsetting country, region, ladder_score for the years 2019 and 2020.

# Filtering coloums required to evaluate trends in years 2019 and above
df_2019_2020 <- df_all %>% 
  filter(year >= 2019) %>%
  left_join(country_region_dict, by = c('ï..country_name' = 'country')) %>%
  select(country = ï..country_name, region, year, ladder = life_ladder)  %>%
  pivot_wider(names_from = 'year', names_prefix = 'year', values_from = 'ladder') %>%
  filter(!is.na(year2019) & !is.na(year2020)) %>%
  group_by(region) %>%
  summarize(happiness_2019 = mean(year2019, na.rm = TRUE),
            happiness_2020 = mean(year2020, na.rm = TRUE)) %>%
  mutate(diff = happiness_2020-happiness_2019) %>%
  arrange(diff) %>%
  mutate(region = factor(region, levels = region))

0.6.2 Plotting happiness levels during covid19

# Visualizing difference between happiness scores in 2019 and 2020
plot_2020 <- ggplot() + 
  geom_dumbbell(data = df_2019_2020 %>% filter(diff >0),
                aes(y=region, x=happiness_2019, xend=happiness_2020),
                size=1.5, color="#7FB185", 
                colour_xend = "#7FB185", colour_x = "#7FB185",
                size_x = 2.5, size_xend = 5,
                dot_guide=TRUE, dot_guide_size=0.5) +
  geom_dumbbell(data = df_2019_2020 %>% filter(diff <0),
                aes(y=region, x=happiness_2019, xend=happiness_2020),
                size=1.5, color="#edae52", 
                colour_xend = "#edae52", colour_x = "#edae52",
                size_x = 2.5, size_xend = 5,
                dot_guide=TRUE, dot_guide_size=0.5) +
  scale_y_discrete(limits = levels(df_2019_2020$region), expand=c(0.075,1)) +
  labs(x='', y=NULL,
       title="Happiness in pre to amidst Covid",
       subtitle = 'Regions see increases in happiness, despite Covid',
       caption= 'Source: World Happiness Report (2021)') +
  geom_rect(data=df_2019_2020,
            aes(xmin=7.35, xmax=7.65, ymin=-Inf, ymax=Inf),
            fill="#e3e2e1") +
  geom_text(data=df_2019_2020 %>% filter(region == 'South Asia'),
            aes(x=happiness_2020, y=region, label= "2020"),
            color="gray15", size=3, vjust=-1.5) +
  geom_text(data=df_2019_2020 %>% filter(region == 'South Asia'),
            aes(x=happiness_2019, y=region, label= "2019"),
            color="gray15", size=3, vjust=-1.5) +
  geom_text(data=df_2019_2020 %>% filter(diff>0),
            aes(x=happiness_2020 , y=region, label=round(happiness_2020,2)),
            size=4, hjust=-0.5) +
  geom_text(data=df_2019_2020 %>% filter(diff>0),
            aes(x=happiness_2019 , y=region, label=round(happiness_2019,2)),
            color="gray15", size=4, hjust=1.3) +
  geom_text(data=df_2019_2020 %>% filter(diff<0),
            aes(x=happiness_2020 , y=region,
                label=round(happiness_2020,2)),size=4, hjust=1.5) +
  geom_text(data=df_2019_2020 %>% filter(diff<0),
            aes(x=happiness_2019 , y=region,
                label=round(happiness_2019,2)),
            color="gray15", size=4, hjust=-0.3) +
  geom_text(data=df_2019_2020 %>%
              filter(region == 'South Asia'),
            aes(x=7.5, y=region, label="DIFF"),
            size=4.5, vjust=-1.5, fontface="bold") +
  geom_text(data=df_2019_2020, aes(label=round(diff,2),
                                   y=region, x=7.5), size=3) + 
  theme_ipsum(grid="") +
  theme(plot.title = element_text(size=20),
        plot.subtitle = element_text(size = 15),
        plot.caption = element_text(size = 12),
        axis.title.x = element_text(size= 12, color = '#3a403a'),
        axis.text.y = element_text(size = 15, color = 'black'),
        axis.text.x = element_blank(),
        legend.position = 'left')

0.6.3 Creating new dataframe to compare happiness levels amidst Covid to 2021 level

Combining dimentions from both datasets to form new dataset with country, region, year and ladder_score.

# Adding year column to 2021 dataset
df_2021$year <- rep(2021,nrow(df_2021)) 

# Renaming 2021 `ladder_score` as `happiness_2021`
df_2021_new <- cbind(df_2021)
names(df_2021_new)[names(df_2021_new) == 'ladder_score'] <- 'happiness_2021'

# Joining 2020 and 2021 dataset
df_yr_score<-full_join(df_2019_2020, df_2021_new,
                       by=c("region"="regional_indicator"))

0.6.4 Creating new dataframe with region, country and ladder_score columns for year 2019,2020 and 2021

# Merging country regions with countries 
df_all_region <- df_all %>% 
  left_join(country_region_dict, by = c('ï..country_name' = 'country')) %>%
  select(country = ï..country_name, region, year, ladder = life_ladder) 

# Renaming region, ladder score in data_all dataset
names(df_all_region)[names(df_all_region) == 'region'] <- 'regional_indicator'
names(df_all_region)[names(df_all_region) == 'ladder'] <- 'ladder_score'


# Subsetting df_2021 dataset
df_2021_region<- df_2021 %>%
  select(country = ï..country_name, regional_indicator, year, ladder_score)

# Binding all the regions in `df_final` dataset
df_final <-rbind(df_all_region,df_2021_region) %>%
  filter(!is.na(year) & !is.na(regional_indicator)) 

# Making dataset of last 3 years
df_final_19_20_21 <- df_final %>% 
  filter(year >= 2019)

0.8 Visualization 3- Factors correlating to happiness

Plotting correlation among factors related to happiness in 2021 dataset.

# Subsetting numerical colums 
df_cor <- df_2021 %>% 
  select(corruption = perceptions_of_corruption,
         generosity = generosity,
         freedom = freedom_to_make_life_choices, 
         life_expectancy = healthy_life_expectancy, 
         social_support = social_support,
         GDP_per_capita = logged_GDP_per_capita, 
         happiness = ladder_score
  )
# Displaying heatmap of correlation
corr <- cor(df_cor)
plot_ly(colors = "RdBu") %>%
  add_heatmap(x = rownames(corr), y = colnames(corr), z = corr) %>%
  colorbar(limits = c(-1, 1))

Figure 7: Correlation Matrix

# plotly is used to make an interactive plots. If the mouse is hovered over figure, datapoints will be visible.

Top 3 contributors of happiness from the 2021 dataset are:

  1. Life Expectancy
  2. Social Support
  3. GDP per capita

0.9 Visualization 4- General trend of happiness levels over the regions.

0.9.1 Plotting overall trend of happiness scores across all regions.

# Mapping regions to happiness scores.
region_level <- ggplot(df_final, aes( x = regional_indicator, y = ladder_score, fill = regional_indicator, text = country)) + geom_beeswarm(aes(color = regional_indicator, alpha=1) )

region_level4 <- region_level   +  geom_boxplot(aes(alpha=2 )) +
            ggtitle("Country-wise happiness trends in regions")+
            #theme_classic() + 
            theme(legend.position = "none", axis.text.x=element_text( angle = 0,hjust=1, size=8)) +  
            scale_x_discrete(labels = wrap_format(10))+  
            scale_fill_brewer(palette = "Spectral") + 
            scale_color_brewer(palette = "Spectral")
        ggplotly(region_level4, tooltip = c("country","ladder_score"))

Figure 8: Happiness trend plot across regions

# plotly is used to make an interactive plots. If the mouse is hovered over figure, datapoints will be visible.

Top happiest regions in the world are Western Europe and North America & ANZ.


0.10 Summary

Happiness across the globe has taken a blow. None of the regions in the world show rise in happiness in 2021 as compared to 2020 (amidst covid).

Countries having good healthy lifestyle, social support, and high good per capita income have high happiness index. Western Europe and Northern America further confirm the pattern with high happiness scores.

0.10.1 What I learned?

Definitely got what the fuss is all about for R. Despite being a python enthusiast I have grown to love R. Learned how R handles reproducibility and version control issues, share my project without the hassle of handling dependencies and new packages like packrat, vizdat, nainar etc. Learned a lot about automation in RMarkdown and publication on RPubs.

0.10.2 What I would do next?

There were several variables untouched due to time constraint and scope of the project. Further I would see how the six factors contribute to happiness scores and look at the time series analysis of the most influential factors. Futhermore, make an interactive dashboard to display regression and cluster analysis of important features.


LS0tDQp0aXRsZTogIlRoZSBXb3JsZCBIYXBwaW5lc3MgUmVwb3J0IDIwMjEiDQphdXRob3I6ICJGYXJ6YW5hIFBhdGVsIg0KZGF0ZTogIjE2LzA1LzIwMjEiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGRlZmF1bHQNCiAgICB0b2M6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgaGlnaGxpZ2h0OiB0YW5nbyANCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cgDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgZmlnX2NhcHRpb246IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgDQogIHhhcmluZ2FuOjptb29uX3JlYWRlcjoNCiAgICBjc3M6IFtkZWZhdWx0LCBtZXRyb3BvbGlzLCBtZXRyb3BvbGlzLWZvbnRzXQ0KICBwcmV0dHlkb2M6Omh0bWxfcHJldHR5Og0KICAgIHRoZW1lOiBsZW9uaWRzDQogICAgaGlnaGxpZ2h0OiBnaXRodWINCiAgcGRmX2RvY3VtZW50OiANCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgIA0KICANCi0tLQ0KDQojIyBQcm9qZWN0IE1vdGl2YXRpb24NCg0KQmVpbmcgYSBuZXJkeSBrYWdnbGVyLCBpdCB3YXMgbm8gYnJhaW5lciB0byBwaWNrIDEgb3V0IG9mIDU0aysgcHVibGljIGRhdGFzZXRzLiBUb3RhbGx5IGRpZG4ndCBoYXZlIHBhcmFkb3ggb2YgY2hvaWNlL2V4aXN0ZW50aWFsIGNyaXNpcy4gSXQgbGVhZCBtZSB0byBmaW5kIHNvbWV0aGluZyBjb21wbGV0ZWx5IG9wcG9zaXRlIHRvIHdoYXQgSSB3YXMgZmVlbGluZzsgYSBkYXRhc2V0IG9mIGhhcHBpbmVzcyBsZXZlbHMgYXJvdW5kIHRoZSBnbG9iZS4gIA0KVGhlIFdvcmxkIEhhcHBpbmVzcyBSZXBvcnQgMjAyMSBmb2N1c2VzIG9uIHRoZSBlZmZlY3RzIG9mIENPVklELTE5IGFuZCBob3cgcGVvcGxlIGFsbCBvdmVyIHRoZSB3b3JsZCBoYXZlIGZhcmVkLiBUaGUgcmVwb3J0cyByZXZpZXcgdGhlIHN0YXRlIG9mIGhhcHBpbmVzcyBpbiB0aGUgd29ybGQgdG9kYXkgYW5kIHNob3cgaG93IHRoZSBuZXcgc2NpZW5jZSBvZiBoYXBwaW5lc3MgZXhwbGFpbnMgcGVyc29uYWwgYW5kIG5hdGlvbmFsIHZhcmlhdGlvbnMgaW4gaGFwcGluZXNzLiAgDQpUaGF0J3MgaG93IEkgZGVjaWRlZCB0byBjaGVjayBvdXQgdGhlIHB1cnN1aXQgb2YgaGFwcGkoeSluZXNzLg0KDQojIyMgQ29udGVudA0KVGhlIGhhcHBpbmVzcyBzY29yZXMgYW5kIHJhbmtpbmdzIHVzZSBkYXRhIGZyb20gdGhlIEdhbGx1cCBXb3JsZCBQb2xsIC4gVGhlIGNvbHVtbnMgZm9sbG93aW5nIHRoZSBoYXBwaW5lc3Mgc2NvcmUgZXN0aW1hdGUgdGhlIGV4dGVudCB0byB3aGljaCBlYWNoIG9mIHNpeCBmYWN0b3JzIOKAkyBlY29ub21pYyBwcm9kdWN0aW9uLCBzb2NpYWwgc3VwcG9ydCwgbGlmZSBleHBlY3RhbmN5LCBmcmVlZG9tLCBhYnNlbmNlIG9mIGNvcnJ1cHRpb24sIGFuZCBnZW5lcm9zaXR5IOKAkyBjb250cmlidXRlIHRvIG1ha2luZyBsaWZlIGV2YWx1YXRpb25zIGhpZ2hlciBpbiBlYWNoIGNvdW50cnkgdGhhbiB0aGV5IGFyZSBpbiBEeXN0b3BpYSwgYSBoeXBvdGhldGljYWwgY291bnRyeSB0aGF0IGhhcyB2YWx1ZXMgZXF1YWwgdG8gdGhlIHdvcmxk4oCZcyBsb3dlc3QgbmF0aW9uYWwgYXZlcmFnZXMgZm9yIGVhY2ggb2YgdGhlIHNpeCBmYWN0b3JzLiANCg0KIyMjIERhdGEgU291cmNlDQotIEZvciB0aGlzIGFuYWx5c2lzLCB0aGUgc2NvcGUgaXMganVzdCBsaW1pdGVkIHRvIHRoZSBXb3JsZCBIYXBwaW5lc3MgMjAyMSBhbmQgV29ybGQgSGFwcGluZXNzICgyMDA1LTIwMjApIGRhdGFzZXQuIA0KLSBUaGUgW0hhcHBpbmVzcyAyMDIxIGRhdGFzZXRdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vYWpheXBhbHNpbmdobG8vd29ybGQtaGFwcGluZXNzLXJlcG9ydC0yMDIxKSB3YXMgc291cmNlZCBmcm9tIFtLYWdnbGVdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20pLg0KDQotIER1ZSB0byB0aGUgc2hlZXIgdm9sdW1lIG9mIGRhdGEsIHRoZSBhbmFseXNpcyBmb2N1c2VkIHNwZWNpZmljYWxseSBvbiAxMCB2YXJpYWJsZXMuVGhlIHRhYmxlIGJlbG93IHByb3ZpZGVzIGEgZGVzY3JpcHRpb24gb2YgdGhlIHZhcmlhYmxlcyB1c2VkICBkdXJpbmcgdGhlIGFuYWx5c2lzDQoNCi0gKipEYXRhIERpY3Rpb25hcnkqKg0KDQp8IFZhcmlhYmxlIHwgRGF0YXR5cGUgfCBFeHBsYWluYXRpb24gDQp8LS0tLS0tOnw6LS0tLS18LS0tLS0tLS0tfDotLS0tLS0NCnwgY291bnRyeV9uYW1lIHwgY2hhcmFjdGVyIHwgQ291bnRyeSBuYW1lICgxNDEgY291bnRyaWVzKQ0KfCB5ZWFyIHwgaW50ZWdlciB8IFllYXIgfCANCnwgbGFkZGVyX3Njb3JlIHwgbnVtZXJpYyB8IExpZmUgZXZhbHVhdGlvbiBzY29yZSANCnwgcmVnaW9uYWxfaW5kaWNhdG9yIHwgbnVtZXJpYyB8IFJlZ2lvbiAoMTAgUmVnaW9ucykgIA0KfCBsb2dnZWRfR0RQX3Blcl9jYXBpdGF8IG51bWVyaWMgfCBFeHRlbnQgdG8gd2hpY2ggR0RQIGNvbnRyaWJ1dGVzIHRvIHRoZSBjYWxjdWxhdGlvbiBvZiB0aGUgTGFkZGVyIHNjb3JlICAgDQp8IGhlYWx0aHlfbGlmZV9leHBlY3RhbmN5fCBudW1lcmljIHwgIEhlYWx0aHkgbGlmZSBleHBlY3RhbmNpZXMgYXQgYmlydGggYmFzZWQgb24gdGhlIGRhdGEgZXh0cmFjdGVkIGZyb20gdGhlIFdvcmxkIEhlYWx0aCBPcmdhbmlzYXRpb24gKFdITykgZGF0YSByZXBvc2l0b3J5ICAgDQp8IHNvY2lhbF9zdXBwb3J0fCBudW1lcmljIHwgRGVmaW5lZCBhcyBoYXZpbmcgc29tZW9uZSB0byBjb3VudCBvbiBpbiB0aW1lcyBvZiB0cm91YmxlIChyYW5rZWQgZnJvbSAwIHRvIDEpICANCnwgZnJlZWRvbV90b19tYWtlX2xpZmVfY2hvaWNlc3wgbnVtZXJpYyB8IERlZmluZWQgYXMgdGhlIG5hdGlvbmFsIGF2ZXJhZ2Ugb2YgcmVzcG9uc2VzIHRvIHRoZSBHYWxsLVdvcmxkUG9sbCBxdWVzdGlvbiAo4oCcQXJlIHlvdSBzYXRpc2ZpZWQgb3IgZGlzc2F0aXNmaWVkIHdpdGggeW91ciBmcmVlZG9tIHRvIGNob29zZSB3aGF0IHlvdSBkbyB3aXRoIHlvdXIgbGlmZT/igJ0pICAgDQp8IGdlbmVyb3NpdHl8IG51bWVyaWMgfCBOYXRpb25hbCBhdmVyYWdlIG9mIHJlc3BvbnNlcyB0byB0aGUgcXVlc3Rpb24gLSDigJxIYXZlIHlvdSBkb25hdGVkIG1vbmV5IHRvIGEgY2hhcml0eSBpbiB0aGUgcGFzdCBtb250aD/igJ0gIA0KfCBwZXJjZXB0aW9uX29mX2NvcnJ1cHRpb258IG51bWVyaWMgfCBOYXRpb25hbCBhdmVyYWdlIG9mIHJlc3BvbnNlcyB0byB0aGUgcXVlc3Rpb25zICjigJxJcyBjb3JydXB0aW9uIHdpZGVzcHJlYWQgdGhyb3VnaG91dCB0aGUgZ292ZXJubWVudCBvciBub3TigJ0gYW5kIOKAnElzIGNvcnJ1cHRpb24gd2lkZXNwcmVhZCB3aXRoaW4gYnVzaW5lc3NlcyBvciBub3Q/4oCdICkgDQoNCi0gRGV0YWlscyBvbiB0aGUgbWV0YWRhdGEgb2YgdGhlIGRhdGFzZXQgaXMgcHJvdmlkZWQgdW5kZXIgdGhlIFJlZmVyZW5jZXMgc2VjdGlvbi4NCg0KDQoqKioNCg0KKipJbXBvcnRhbnQgc3RlcHMtKioNCg0KLSBUbyBjaGVjayBteSBSUHVicyBvdXQgY2xpY2sgW2hlcmVdKGh0dHBzOi8vcnB1YnMuY29tL0ZhcnphbmFQYXRlbC9wc3k2NDIyX0hhcHBpbmVzc1JlcG9ydDIwMjEpDQotIFRvIGNoZWNrIG15IGdpdGh1YiB3ZWJzaXRlIGNsaWNrIFtoZXJlXShodHRwczovL2ZhcnoxMzEzLmdpdGh1Yi5pby9mYXJ6YW5hX3BhdGVsX3BzeTY0MjIvKQ0KLSBUbyBjaGVjayBteSBHaXRIdWIgcmVwb3NpdG9yeSBvdXQgcGxlYXNlIGNsaWNrIFtoZXJlXShodHRwczovL2dpdGh1Yi5jb20vZmFyejEzMTMvZmFyemFuYV9wYXRlbF9wc3k2NDIyKSANCg0KICAqIENsb25lIG15IGdpdCByZXBvc2l0b3J5ICANCiAgKiBPcGVuIGluZGV4LlJtZCAgDQogICogRW50ZXIgcmVudjo6cmVzdG9yZSgpICANCiAgKiBFbnRlciB5ICANCg0KKioqDQoNCiMjIFJlc2VhcmNoIFF1ZXN0aW9ucw0KLSAqKldoYXQgaXMgdGhlIGVmZmVjdCBvZiBDb3ZpZDE5IG9uIGhhcHBpbmVzcyBsZXZlbHMgaW4gMjAyMCBhbmQgMjAyMT8qKg0KICAgLSBXaGF0IGFyZSB0aGUgdG9wIDEwIGhhcHBpZXN0IGFuZCBzYWRkZXN0IGNvdW50cmllcyBpbiAyMDIxPw0KICAgLSBXaGF0IGlzIGdlbmVyYWwgdHJlbmQgb2YgaGFwcGluZXNzIGluIHRoZSB3b3JsZCBvdmVyIGxhc3QgMyB5ZWFycz8NCiAgIC0gV2hhdCBmYWN0b3JzIGNvbnRyaWJ1dGVkIG1vc3QgdG8gaGFwcGluZXNzIHNjb3Jlcz8NCiAgIC0gV2hpY2ggcmVnaW9ucyBzaG93ZWQgY2hhbmdlIGluIGhhcHBpbmVzcyBsZXZlbHM/DQoNCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ24gPSAnbGVmdCcsIGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwKQ0Kb3B0aW9ucyhrbml0ci5kdXBsaWNhdGUubGFiZWwgPSAiYWxsb3ciKQ0KYGBgDQoqKioNCiMjIERhdGEgUHJlcGVyYXRpb24NCiMjIyBJbXBvcnRpbmcgbGlicmFyaWVzIGFuZCBkYXRhc2V0cw0KDQpgYGB7ciBkYXRhLCBpbmNsdWRlID0gVFJVRSwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCnBhY2thZ2VzID0gYygndGlkeXZlcnNlJywgIyBmb3IgZWFzeSBoYW5kbGluZyBvZiBkYXRhDQonaGVhdG1hcGx5JywgIyBmb3IgdmlzdWFsaXppbmcgZGF0YSBhcm91bmQgcGxvdGx5DQondmlzZGF0JywgIyBmb3IgZXhwbG9yaW5nIG1pc3NpbmcgZGF0YSBzdHJ1Y3R1cmUNCidnZ3Bsb3QyJywgIyBmb3IgZGF0YSB2aXN1YWxpemF0aW9uDQonbmFuaWFyJywgIyBmb3IgcGxvdHRpbmcgbWlzc2luZyB2YWx1ZXMNCidkcGx5cicsICMgZm9yIGRhdGEgbWFuaXB1bGF0aW9uDQondGlkeXInLCAjIHRvIGNyZWF0ZSB0aWR5IGRhdGENCidocmJydGhlbWVzJywgIyB0byBpbmNsdWRlIGFkZGl0aW9uYWwgdGhlbWVzIGZvciBnZ3Bsb3QyDQonZ2djaGlja2xldCcsICNzdHlsaXplIGNoYXJ0cw0KJ2dnYWx0JywgIyBmb3Igc3RhdGlzdGljYWwgdHJhbnNmb3JtYXRpb24NCidjb3JycGxvdCcsICMgZm9yIGNvcnJlbG9ncmFtDQoncGxvdGx5JywgIyBmb3IgaW50ZXJhY3RpdmUgYW5kIHB1YmxpY2F0aW9uIHF1YWxpdHkgZ3JhcGhzDQonY293cGxvdCcsICNhZGQtb24gdG8gZ2dwbG90DQoncGF0Y2h3b3JrJywgIyB0byBjcmVhdGUgbGF5b3V0cyBpbiBnZ3Bsb3QNCidSQ29sb3JCcmV3ZXInLCAjIGZvciByZWFkeSB0byB1c2UgY29sb3IgcGFsZXR0ZXMNCidnZ2JlZXN3YXJtJywgIyB0byBwbG90IHNjYXR0ZXJwbG90cw0KJ3NjYWxlcycsICMgZm9yIGludGVybmFsIHNjYWxpbmcNCidrYWJsZUV4dHJhJyAjIHRvIGJ1aWxkIHRhYmxlcw0KKQ0KZm9yIChwIGluIHBhY2thZ2VzKXsNCiAgaWYoIXJlcXVpcmUocCwgY2hhcmFjdGVyLm9ubHkgPSBUKSl7DQogICAgaW5zdGFsbC5wYWNrYWdlcyhwKQ0KICB9DQogIGxpYnJhcnkocCxjaGFyYWN0ZXIub25seSA9IFQpDQp9DQoNCiNSZWFkaW5nIHRoZSBkYXRhDQpkZl8yMDIxIDwtIHJlYWQuY3N2KCJkYXRhL3dvcmxkLWhhcHBpbmVzcy1yZXBvcnQtMjAyMS5jc3YiKQ0KZGZfYWxsIDwtIHJlYWQuY3N2KCJkYXRhL3dvcmxkLWhhcHBpbmVzcy1yZXBvcnQuY3N2IikNCg0KYGBgDQoNCioqKg0KDQojIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIGFuZCBjbGVhbmluZyB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxscyB9DQojIyMgRnVsbCBkYXRhc2V0ICgyMDA1LTIwMjApDQpEaXNwbGF5aW5nIGRhdGFzZXQgZnJvbSAyMDA1IHQwIDIwMjANCmBgYHtyfQ0KZGYxPC1oZWFkKGRmX2FsbCkNCmthYmxlKGRmMSkgJT4lDQprYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gImNvbmRlbnNlZCIsIGZvbnRfc2l6ZT0gOCwgZnVsbF93aWR0aCA9IEYpDQpgYGANCiMjIyBEYXRhc2V0IDIwMjENCkRpc3BsYXlpbmcgZGF0YXNldCAyMDIxDQpgYGB7cn0NCmRmMjwtaGVhZChkZl8yMDIxKQ0Ka2FibGUoZGYyKSAlPiUNCmthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAiY29uZGVuc2VkIiwgZm9udF9zaXplPSA4LCBmdWxsX3dpZHRoID0gRikNCmBgYA0KDQojIyMgRXhwbG9yaW5nIGRhdGENClZpc3VhbGl6aW5nIGRhdGFzZXRzIHRvIGNoZWNrIGRhdGF0eXBlcy4NCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gMTAsIGZpZy5jYXA9IkZpZ3VyZSAxOiBQbG90cyBzaG93aW5nIGRhdGF0eXBlcyJ9IA0KdmlzX2RhdGFfMSA8LSB2aXNfZGF0KGRmXzIwMjEpKyBsYWJzKHggPSAiRGF0YXR5cGVzIGZvciAyMDIxIGRhdGFzZXQiKQ0KdmlzX2RhdGFfMiA8LSB2aXNfZGF0KGRmX2FsbCkrIGxhYnMoeCA9ICJEYXRhdHlwZXMgZm9yIGFsbCBkYXRhc2V0IikNCnZpc19kYXRhXzEgKyB2aXNfZGF0YV8yDQpgYGANCg0KPkJvdGggZGF0YXNldHMgc2hvdyBudW1lcmljIGFuZCBjaGFyYWN0ZXIgZGF0YXR5cGVzIHdpdGggZmV3IE5BIHZhbHVlcy4gDQoNCiMjIyBDaGVja2luZyBmb3IgbWlzc2luZyB2YWx1ZXMNClBsb3R0aW5nIG1pc3NpbmcgdmFsdWVzIG9mIGJvdGggZGF0YXNldHMuDQpgYGB7ciwgZmlnLmhlaWdodCA9IDMsIGZpZy53aWR0aCA9IDExLCBmaWcuY2FwPSJGaWd1cmUgMjogUGxvdHMgb2YgbWlzc2luZyB2YWx1ZXMifSANCm1pc3NfZGF0YV8xIDwtIGdnX21pc3NfdmFyKGRmXzIwMjEpICsgbGFicyh5ID0gIkNoZWNraW5nIGZvciB0aGUgbWlzc2luZyBvbmVzIGluIDIwMjEiKQ0KbWlzc19kYXRhXzIgPC0gZ2dfbWlzc192YXIoZGZfYWxsKSArIGxhYnMoeSA9ICJDaGVja2luZyBmb3IgdGhlIG1pc3Npbmcgb25lcyBpbiBmdWxsX2RhdGEiKQ0KbWlzc19kYXRhXzEgKyBtaXNzX2RhdGFfMg0KYGBgDQoNCj5gZGZfMjAyMWAgaGFzIG5vIG1pc3NpbmcgdmFsdWVzIHdoZXJlYXMgYGRmX2FsbGAgaGFzIHNvbWUgY29sdW1ucyB3aXRoIG1pc3NpbmcgdmFsdWVzLg0KDQojIyMgVHJlYXRpbmcgYE5BYCB2YWx1ZXMNCkltcHV0aW5nIG1pc3NpbmcgdmFsdWVzIHdpdGggbWVhbiBvZiB0aGUgY29sdW1ucw0KYGBge3IsIHJlc3VsdHM9J2hpZGUnfQ0KZGZfYWxsW3NhcHBseShkZl9hbGwsIGlzLm51bWVyaWMpXSA8LSBsYXBwbHkoZGZfYWxsW3NhcHBseShkZl9hbGwsIGlzLm51bWVyaWMpXSwgZnVuY3Rpb24oeCkgaWZlbHNlKGlzLm5hKHgpLCBtZWFuKHgsIG5hLnJtID0gVFJVRSksIHgpKSAgDQpkZl9hbGwgJT4lIHN1bW1hcmlzZShhY3Jvc3MoZXZlcnl0aGluZygpLCB+IHN1bShpcy5uYSguKSkpKQ0KYGBgDQoNCiMjIyBDbGVhbmVkIGRhdGFzZXQNCkNoZWNraW5nIGZvciBgTkFgIHZhbHVlcyBpbiBkYXRhc2V0Lg0KYGBge3IsZmlnLmhlaWdodCA9IDIsIGZpZy53aWR0aCA9IDUsIGZpZy5jYXA9IkZpZ3VyZSAzOiBQbG90IG9mIE5BIGZvciBjbGVhbmVkIGRhdGFzZXQifQ0KZ2dfbWlzc192YXIoZGZfYWxsKSArIGxhYnMoeSA9ICJDaGVja2luZyBmb3IgdGhlIG1pc3Npbmcgb25lcyBpbiBmdWxsX2RhdGEiKQ0KYGBgDQoNCj4gRGF0YXNldCBoYXMgbm8gbWlzc2luZyB2YWx1ZXMgYWZ0ZXIgdHJlYXRtZW50Lg0KDQojIyMgU3VtbWFyeSBvZiBmdWxsIGRhdGFzZXQNCmBgYHtyLCBjb2xzLnByaW50PTQsIHJvd3MucHJpbnQ9NX0NCnN1bW1hcnkoZGZfYWxsKQ0KYGBgDQoNCiMjIyBTdW1tYXJ5IG9mIGZ1bGwgZGF0YXNldA0KYGBge3IsIGNvbHMucHJpbnQ9NCwgcm93cy5wcmludD01fQ0Kc3VtbWFyeShkZl8yMDIxKQ0KYGBgDQoNCioqKg0KDQoNCiMjIFZpc3VhbGl6YXRpb24gMSAtVG9wIDEwIGhhcHBpZXN0IGFuZCBzYWRkZXN0IGNvdW50cmllcyBpbiAyMDIxDQoNCiMjIyBHZXR0aW5nIHRvcCBhbmQgYm90dG9tIDEwIGNvdW50cmllcy4NCk1hcHBpbmcgY291bnRyaWVzIGJ5IHJlZ2lvbiBhbmQgZmlsdGVyaW5nIGNvdW50cmllcyBieSBgbGFkZGVyX3Njb3JlYCBpLmUuIGhhcHBpbmVzcyBsZXZlbC4NCmBgYHtyfQ0KIyBTdWJzZXR0aW5nIGRpbWVuc2lvbnMNCmRpbWVuc2lvbnMgPC0gYygnbGFkZGVyX3Njb3JlJywNCiAgICAgICAgICAgICAgICAnbG9nZ2VkX0dEUF9wZXJfY2FwaXRhJywNCiAgICAgICAgICAgICAgICAnc29jaWFsX3N1cHBvcnQnLA0KICAgICAgICAgICAgICAgICdoZWFsdGh5X2xpZmVfZXhwZWN0YW5jeScsDQogICAgICAgICAgICAgICAgJ2ZyZWVkb21fdG9fbWFrZV9saWZlX2Nob2ljZXMnLA0KICAgICAgICAgICAgICAgICdnZW5lcm9zaXR5JywNCiAgICAgICAgICAgICAgICAncGVyY2VwdGlvbnNfb2ZfY29ycnVwdGlvbicpDQoNCiMgTWFwcGluZyBjb3VudHJ5IHRvIHJlZ2lvbnMNCmNvdW50cnlfcmVnaW9uX2RpY3QgPSBkZl8yMDIxICU+JSANCiAgc2VsZWN0KGNvdW50cnkgPSDDry4uY291bnRyeV9uYW1lLCByZWdpb24gPSByZWdpb25hbF9pbmRpY2F0b3IpICU+JSB1bmlxdWUoKQ0KDQpkZl8yMDIxX2xvbmcgPC0gZGZfMjAyMSAlPiUgDQogIHNlbGVjdChjb3VudHJ5ID0gw68uLmNvdW50cnlfbmFtZSwgYWxsX29mKGRpbWVuc2lvbnMpKSAlPiUNCiAgbXV0YXRlKGFic2VuY2Vfb2ZfY29ycnVwdGlvbiA9IDEtIHBlcmNlcHRpb25zX29mX2NvcnJ1cHRpb24pICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoYWxsX29mKGRpbWVuc2lvbnMpLCdhYnNlbmNlX29mX2NvcnJ1cHRpb24nKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gJ2RpbWVuc2lvbicsIHZhbHVlc190byA9ICdzY29yZScpICU+JQ0KICBmaWx0ZXIoZGltZW5zaW9uICE9ICJwZXJjZXB0aW9uc19vZl9jb3JydXB0aW9uIikNCg0KIyBDYWxjdWxhdGluZyBzY29yZSB1c2luZyBtaW4gbWF4IHZhbHVlcw0KZGZfMjAyMV90cmFuZm9ybWVkIDwtIGRmXzIwMjFfbG9uZyAlPiUNCiAgZ3JvdXBfYnkoZGltZW5zaW9uKSAlPiUNCiAgbXV0YXRlKG1pbl92YWx1ZSA9IG1pbihzY29yZSksDQogICAgICAgICBtYXhfdmFsdWUgPSBtYXgoc2NvcmUpKSAlPiUNCiAgbXV0YXRlKHNjb3JlX3BjdCA9IChzY29yZS1taW5fdmFsdWUpLyhtYXhfdmFsdWUtbWluX3ZhbHVlKSkgJT4lDQogIHVuZ3JvdXAoKQ0KDQojIEdldHRpbmcgdG9wIDEwIGNvdW50cmllcw0KZGZfMjAyMV90b3AxMCA8LSBkZl8yMDIxX3RyYW5mb3JtZWQgJT4lDQogIGZpbHRlcihkaW1lbnNpb24gPT0gImxhZGRlcl9zY29yZSIpICU+JQ0KICBzbGljZV9tYXgoc2NvcmUsIG4gPSAxMCkgJT4lDQogIG11dGF0ZShjYXQgPSAndG9wXzEwJywgDQogICAgICAgICBjb3VudHJ5X3JhbmsgPSByYW5rKC1zY29yZSksDQogICAgICAgICBjb3VudHJ5X2xhYmVsID0gcGFzdGUwKGNvdW50cnksICcgKCcsIGNvdW50cnlfcmFuaywgJyknKSkNCg0KIyBHZXR0aW5nIGJvdHRvbSAxMCBjb3VudHJpZXMNCmRmXzIwMjFfYm90dG9tMTAgPC0gZGZfMjAyMV90cmFuZm9ybWVkICU+JQ0KICBmaWx0ZXIoZGltZW5zaW9uID09ICJsYWRkZXJfc2NvcmUiKSAlPiUNCiAgbXV0YXRlKGNvdW50cnlfcmFuayA9IHJhbmsoc2NvcmUpLA0KICAgICAgICAgY291bnRyeV9sYWJlbCA9IHBhc3RlMChjb3VudHJ5LCAnICgnLCBjb3VudHJ5X3JhbmssICcpJykpICU+JQ0KICBzbGljZV9taW4oc2NvcmUsIG4gPSAxMCkgJT4lDQogIG11dGF0ZShjYXQgPSAnYm90dG9tXzEwJykNCg0KYGBgDQojIyMgUGxvdHRpbmcgdG9wIGFuZCBib3R0b20gMTAgY291bnRyaWVzDQpgYGB7ciwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDEwLCBmaWcuY2FwPSJGaWd1cmUgNDogUGxvdCBvZiAxMCBoYXBwaWVzdCBhbmQgc2FkZGVzdCBjb3VudHJpZXMgaW4gdGhlIHdvcmxkIn0NCiMgUGxvdHRpbmcgdG9wIDEwIGhhcHBpZXN0IGNvdW50cmllcyANCnRvcF8xMCA8LSBnZ3Bsb3QoZGZfMjAyMV90b3AxMCwgYWVzKHggPSByZW9yZGVyKGNvdW50cnlfbGFiZWwsIHNjb3JlKSkpICsgDQogIGdlb21fY2hpY2tsZXQoYWVzKHkgPSAxMCwgZmlsbCA9IDQuOSksIHdpZHRoID0gMC41LCByYWRpdXMgPSBncmlkOjp1bml0KDUsICJwdCIpKSArDQogIGdlb21fY2hpY2tsZXQoYWVzKHkgPSBzY29yZSwgZmlsbCA9IHNjb3JlKSwgd2lkdGggPSAwLjUsIHJhZGl1cyA9IGdyaWQ6OnVuaXQoNSwgInB0IikpICsNCiAgZ2VvbV90ZXh0KGFlcyh5ID0gc2NvcmUpLCBsYWJlbCA9IHJvdW5kKGRmXzIwMjFfdG9wMTAkc2NvcmUsMiksIG51ZGdlX3kgPSAwLjQsIHNpemUgPSAzKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwLjEpLCBwb3NpdGlvbiA9ICJyaWdodCIsIGxpbWl0cyA9IGMoMCwgMTApKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICdibGFjaycsIGhpZ2ggPSAnIzgxOGFlYicsIG1pZCA9ICd3aGl0ZScsIG1pZHBvaW50ID0gNSkgKyANCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh5PSJCZXN0IHBvc3NpYmxlIGxpZmUgPSAxMCIsIHggPSAnJywNCiAgICAgICB0aXRsZT0iVG9wIDEwIEhhcHBpZXN0IENvdW50cmllcyBpbiAyMDIxIiwNCiAgICAgICBzdWJ0aXRsZT0iOSBvZiB0aGUgaGFwcGllc3QgY291bnRyaWVzIHByZXNlbnQgaW4gRXVyb3BlIiwNCiAgICAgICBjYXB0aW9uPSJTb3VyY2U6IFRoZSBXb3JsZCBIYXBwaW5lc3MgUmVwb3J0IDIwMjEiKSArIA0KICB0aGVtZV9pcHN1bShncmlkID0gJycpICArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPSAxMCwgY29sb3IgPSAnIzU1NTk1NScpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gJ2JsYWNrJyksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnTm9uZScpDQoNCiMgUGxvdHRpbmcgMTAgc2FkZGVzdCBjb3VudHJpZXMNCmJvdHRvbV8xMCA8LSBnZ3Bsb3QoZGZfMjAyMV9ib3R0b20xMCwgYWVzKHggPSByZW9yZGVyKGNvdW50cnlfbGFiZWwsIHNjb3JlKSkpICsgDQogIGdlb21fY2hpY2tsZXQoYWVzKHkgPSAxMCwgZmlsbCA9IDQuOSksIHdpZHRoID0gMC41LCByYWRpdXMgPSBncmlkOjp1bml0KDUsICJwdCIpKSArDQogIGdlb21fY2hpY2tsZXQoYWVzKHkgPSBzY29yZSwgZmlsbCA9IHNjb3JlKSwgd2lkdGggPSAwLjUsIHJhZGl1cyA9IGdyaWQ6OnVuaXQoNSwgInB0IikpICsNCiAgZ2VvbV90ZXh0KGFlcyh5ID0gc2NvcmUpLCBsYWJlbCA9IHJvdW5kKGRmXzIwMjFfYm90dG9tMTAkc2NvcmUsMiksIG51ZGdlX3kgPSAwLjQsIHNpemUgPSAzKSArIA0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLCAwLjEpLCBwb3NpdGlvbiA9ICJyaWdodCIsIGxpbWl0cyA9IGMoMCwgMTApKSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICcjMDc0MDQwJywgaGlnaCA9ICcjNGNjMmMyJywgbWlkID0gJ3doaXRlJywgbWlkcG9pbnQgPSA1KSArIA0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHk9IkJlc3QgcG9zc2libGUgbGlmZSA9IDEwIiwgeCA9ICcnLA0KICAgICAgIHRpdGxlPSJUb3AgMTAgU2FkZGVzdCBDb3VudHJpZXMgaW4gMjAyMSIsDQogICAgICAgc3VidGl0bGU9Ik1vc3RseSBzdHJ1Y2sgYnkgcG92ZXJ0eSIsDQogICAgICAgY2FwdGlvbj0iU291cmNlOiBUaGUgV29ybGQgSGFwcGluZXNzIFJlcG9ydCAyMDIxIikgKyANCiAgdGhlbWVfaXBzdW0oZ3JpZCA9ICcnKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPSAxMCwgY29sb3IgPSAnIzU1NTk1NScpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gJ2JsYWNrJyksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnTm9uZScpDQoNCiMgRGlzcGxheWluZyBwbG90cyBzaWRlIGJ5IHNpZGUNCnRvcF8xMCArIGJvdHRvbV8xMA0KYGBgDQoNCj5Nb3N0IG9mIHRoZSBoYXBwaWVzdCBjb3VudHJpZXMgY29tcHJpc2UgaW4gRXVyb3BlLiBNb3N0IHNhZGRlc3Qgc2VlbSB0byBiZSB1bmRlciBmaW5hbmNpYWwgY3Jpc2lzDQoNCioqKg0KDQojIyBWaXN1YWxpemF0aW9uIDIgLUhhcHBpbmVzcyB0cmVuZCBpbiAyMDE5LCAyMDIwIGFuZCAyMDIxIChpbnNpZ2h0cyB3LnIudC4gY292aWQxOSkNCg0KIyMjIEV4dHJhY3RpbmcgcmVsZXZhbnQgY29sdW1ucyBmb3IgYW5hbHlzaXMNClN1YnNldHRpbmcgYGNvdW50cnlgLCBgcmVnaW9uYCwgYGxhZGRlcl9zY29yZWAgZm9yIHRoZSB5ZWFycyAyMDE5IGFuZCAyMDIwLg0KYGBge3J9DQojIEZpbHRlcmluZyBjb2xvdW1zIHJlcXVpcmVkIHRvIGV2YWx1YXRlIHRyZW5kcyBpbiB5ZWFycyAyMDE5IGFuZCBhYm92ZQ0KZGZfMjAxOV8yMDIwIDwtIGRmX2FsbCAlPiUgDQogIGZpbHRlcih5ZWFyID49IDIwMTkpICU+JQ0KICBsZWZ0X2pvaW4oY291bnRyeV9yZWdpb25fZGljdCwgYnkgPSBjKCfDry4uY291bnRyeV9uYW1lJyA9ICdjb3VudHJ5JykpICU+JQ0KICBzZWxlY3QoY291bnRyeSA9IMOvLi5jb3VudHJ5X25hbWUsIHJlZ2lvbiwgeWVhciwgbGFkZGVyID0gbGlmZV9sYWRkZXIpICAlPiUNCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICd5ZWFyJywgbmFtZXNfcHJlZml4ID0gJ3llYXInLCB2YWx1ZXNfZnJvbSA9ICdsYWRkZXInKSAlPiUNCiAgZmlsdGVyKCFpcy5uYSh5ZWFyMjAxOSkgJiAhaXMubmEoeWVhcjIwMjApKSAlPiUNCiAgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiAgc3VtbWFyaXplKGhhcHBpbmVzc18yMDE5ID0gbWVhbih5ZWFyMjAxOSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIGhhcHBpbmVzc18yMDIwID0gbWVhbih5ZWFyMjAyMCwgbmEucm0gPSBUUlVFKSkgJT4lDQogIG11dGF0ZShkaWZmID0gaGFwcGluZXNzXzIwMjAtaGFwcGluZXNzXzIwMTkpICU+JQ0KICBhcnJhbmdlKGRpZmYpICU+JQ0KICBtdXRhdGUocmVnaW9uID0gZmFjdG9yKHJlZ2lvbiwgbGV2ZWxzID0gcmVnaW9uKSkNCg0KYGBgDQojIyMgUGxvdHRpbmcgaGFwcGluZXNzIGxldmVscyBkdXJpbmcgY292aWQxOQ0KYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMCwgZmlnLmFsaWduID0gImNlbnRlciJ9DQojIFZpc3VhbGl6aW5nIGRpZmZlcmVuY2UgYmV0d2VlbiBoYXBwaW5lc3Mgc2NvcmVzIGluIDIwMTkgYW5kIDIwMjANCnBsb3RfMjAyMCA8LSBnZ3Bsb3QoKSArIA0KICBnZW9tX2R1bWJiZWxsKGRhdGEgPSBkZl8yMDE5XzIwMjAgJT4lIGZpbHRlcihkaWZmID4wKSwNCiAgICAgICAgICAgICAgICBhZXMoeT1yZWdpb24sIHg9aGFwcGluZXNzXzIwMTksIHhlbmQ9aGFwcGluZXNzXzIwMjApLA0KICAgICAgICAgICAgICAgIHNpemU9MS41LCBjb2xvcj0iIzdGQjE4NSIsIA0KICAgICAgICAgICAgICAgIGNvbG91cl94ZW5kID0gIiM3RkIxODUiLCBjb2xvdXJfeCA9ICIjN0ZCMTg1IiwNCiAgICAgICAgICAgICAgICBzaXplX3ggPSAyLjUsIHNpemVfeGVuZCA9IDUsDQogICAgICAgICAgICAgICAgZG90X2d1aWRlPVRSVUUsIGRvdF9ndWlkZV9zaXplPTAuNSkgKw0KICBnZW9tX2R1bWJiZWxsKGRhdGEgPSBkZl8yMDE5XzIwMjAgJT4lIGZpbHRlcihkaWZmIDwwKSwNCiAgICAgICAgICAgICAgICBhZXMoeT1yZWdpb24sIHg9aGFwcGluZXNzXzIwMTksIHhlbmQ9aGFwcGluZXNzXzIwMjApLA0KICAgICAgICAgICAgICAgIHNpemU9MS41LCBjb2xvcj0iI2VkYWU1MiIsIA0KICAgICAgICAgICAgICAgIGNvbG91cl94ZW5kID0gIiNlZGFlNTIiLCBjb2xvdXJfeCA9ICIjZWRhZTUyIiwNCiAgICAgICAgICAgICAgICBzaXplX3ggPSAyLjUsIHNpemVfeGVuZCA9IDUsDQogICAgICAgICAgICAgICAgZG90X2d1aWRlPVRSVUUsIGRvdF9ndWlkZV9zaXplPTAuNSkgKw0KICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cyA9IGxldmVscyhkZl8yMDE5XzIwMjAkcmVnaW9uKSwgZXhwYW5kPWMoMC4wNzUsMSkpICsNCiAgbGFicyh4PScnLCB5PU5VTEwsDQogICAgICAgdGl0bGU9IkhhcHBpbmVzcyBpbiBwcmUgdG8gYW1pZHN0IENvdmlkIiwNCiAgICAgICBzdWJ0aXRsZSA9ICdSZWdpb25zIHNlZSBpbmNyZWFzZXMgaW4gaGFwcGluZXNzLCBkZXNwaXRlIENvdmlkJywNCiAgICAgICBjYXB0aW9uPSAnU291cmNlOiBXb3JsZCBIYXBwaW5lc3MgUmVwb3J0ICgyMDIxKScpICsNCiAgZ2VvbV9yZWN0KGRhdGE9ZGZfMjAxOV8yMDIwLA0KICAgICAgICAgICAgYWVzKHhtaW49Ny4zNSwgeG1heD03LjY1LCB5bWluPS1JbmYsIHltYXg9SW5mKSwNCiAgICAgICAgICAgIGZpbGw9IiNlM2UyZTEiKSArDQogIGdlb21fdGV4dChkYXRhPWRmXzIwMTlfMjAyMCAlPiUgZmlsdGVyKHJlZ2lvbiA9PSAnU291dGggQXNpYScpLA0KICAgICAgICAgICAgYWVzKHg9aGFwcGluZXNzXzIwMjAsIHk9cmVnaW9uLCBsYWJlbD0gIjIwMjAiKSwNCiAgICAgICAgICAgIGNvbG9yPSJncmF5MTUiLCBzaXplPTMsIHZqdXN0PS0xLjUpICsNCiAgZ2VvbV90ZXh0KGRhdGE9ZGZfMjAxOV8yMDIwICU+JSBmaWx0ZXIocmVnaW9uID09ICdTb3V0aCBBc2lhJyksDQogICAgICAgICAgICBhZXMoeD1oYXBwaW5lc3NfMjAxOSwgeT1yZWdpb24sIGxhYmVsPSAiMjAxOSIpLA0KICAgICAgICAgICAgY29sb3I9ImdyYXkxNSIsIHNpemU9Mywgdmp1c3Q9LTEuNSkgKw0KICBnZW9tX3RleHQoZGF0YT1kZl8yMDE5XzIwMjAgJT4lIGZpbHRlcihkaWZmPjApLA0KICAgICAgICAgICAgYWVzKHg9aGFwcGluZXNzXzIwMjAgLCB5PXJlZ2lvbiwgbGFiZWw9cm91bmQoaGFwcGluZXNzXzIwMjAsMikpLA0KICAgICAgICAgICAgc2l6ZT00LCBoanVzdD0tMC41KSArDQogIGdlb21fdGV4dChkYXRhPWRmXzIwMTlfMjAyMCAlPiUgZmlsdGVyKGRpZmY+MCksDQogICAgICAgICAgICBhZXMoeD1oYXBwaW5lc3NfMjAxOSAsIHk9cmVnaW9uLCBsYWJlbD1yb3VuZChoYXBwaW5lc3NfMjAxOSwyKSksDQogICAgICAgICAgICBjb2xvcj0iZ3JheTE1Iiwgc2l6ZT00LCBoanVzdD0xLjMpICsNCiAgZ2VvbV90ZXh0KGRhdGE9ZGZfMjAxOV8yMDIwICU+JSBmaWx0ZXIoZGlmZjwwKSwNCiAgICAgICAgICAgIGFlcyh4PWhhcHBpbmVzc18yMDIwICwgeT1yZWdpb24sDQogICAgICAgICAgICAgICAgbGFiZWw9cm91bmQoaGFwcGluZXNzXzIwMjAsMikpLHNpemU9NCwgaGp1c3Q9MS41KSArDQogIGdlb21fdGV4dChkYXRhPWRmXzIwMTlfMjAyMCAlPiUgZmlsdGVyKGRpZmY8MCksDQogICAgICAgICAgICBhZXMoeD1oYXBwaW5lc3NfMjAxOSAsIHk9cmVnaW9uLA0KICAgICAgICAgICAgICAgIGxhYmVsPXJvdW5kKGhhcHBpbmVzc18yMDE5LDIpKSwNCiAgICAgICAgICAgIGNvbG9yPSJncmF5MTUiLCBzaXplPTQsIGhqdXN0PS0wLjMpICsNCiAgZ2VvbV90ZXh0KGRhdGE9ZGZfMjAxOV8yMDIwICU+JQ0KICAgICAgICAgICAgICBmaWx0ZXIocmVnaW9uID09ICdTb3V0aCBBc2lhJyksDQogICAgICAgICAgICBhZXMoeD03LjUsIHk9cmVnaW9uLCBsYWJlbD0iRElGRiIpLA0KICAgICAgICAgICAgc2l6ZT00LjUsIHZqdXN0PS0xLjUsIGZvbnRmYWNlPSJib2xkIikgKw0KICBnZW9tX3RleHQoZGF0YT1kZl8yMDE5XzIwMjAsIGFlcyhsYWJlbD1yb3VuZChkaWZmLDIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PXJlZ2lvbiwgeD03LjUpLCBzaXplPTMpICsgDQogIHRoZW1lX2lwc3VtKGdyaWQ9IiIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLA0KICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9IDEyLCBjb2xvciA9ICcjM2E0MDNhJyksDQogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSwgY29sb3IgPSAnYmxhY2snKSwNCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdsZWZ0JykNCg0KYGBgDQojIyMgQ3JlYXRpbmcgbmV3IGRhdGFmcmFtZSB0byBjb21wYXJlIGhhcHBpbmVzcyBsZXZlbHMgYW1pZHN0IENvdmlkIHRvIDIwMjEgbGV2ZWwNCkNvbWJpbmluZyBkaW1lbnRpb25zIGZyb20gYm90aCBkYXRhc2V0cyB0byBmb3JtIG5ldyBkYXRhc2V0IHdpdGggYGNvdW50cnlgLCBgcmVnaW9uYCwgYHllYXJgIGFuZCBgbGFkZGVyX3Njb3JlYC4NCmBgYHtyfQ0KIyBBZGRpbmcgeWVhciBjb2x1bW4gdG8gMjAyMSBkYXRhc2V0DQpkZl8yMDIxJHllYXIgPC0gcmVwKDIwMjEsbnJvdyhkZl8yMDIxKSkgDQoNCiMgUmVuYW1pbmcgMjAyMSBgbGFkZGVyX3Njb3JlYCBhcyBgaGFwcGluZXNzXzIwMjFgDQpkZl8yMDIxX25ldyA8LSBjYmluZChkZl8yMDIxKQ0KbmFtZXMoZGZfMjAyMV9uZXcpW25hbWVzKGRmXzIwMjFfbmV3KSA9PSAnbGFkZGVyX3Njb3JlJ10gPC0gJ2hhcHBpbmVzc18yMDIxJw0KDQojIEpvaW5pbmcgMjAyMCBhbmQgMjAyMSBkYXRhc2V0DQpkZl95cl9zY29yZTwtZnVsbF9qb2luKGRmXzIwMTlfMjAyMCwgZGZfMjAyMV9uZXcsDQogICAgICAgICAgICAgICAgICAgICAgIGJ5PWMoInJlZ2lvbiI9InJlZ2lvbmFsX2luZGljYXRvciIpKQ0KYGBgDQojIyMgQ3JlYXRpbmcgbmV3IGRhdGFmcmFtZSB3aXRoIGByZWdpb25gLCBgY291bnRyeWAgYW5kIGBsYWRkZXJfc2NvcmVgIGNvbHVtbnMgZm9yIHllYXIgMjAxOSwyMDIwIGFuZCAyMDIxDQpgYGB7cn0NCiMgTWVyZ2luZyBjb3VudHJ5IHJlZ2lvbnMgd2l0aCBjb3VudHJpZXMgDQpkZl9hbGxfcmVnaW9uIDwtIGRmX2FsbCAlPiUgDQogIGxlZnRfam9pbihjb3VudHJ5X3JlZ2lvbl9kaWN0LCBieSA9IGMoJ8OvLi5jb3VudHJ5X25hbWUnID0gJ2NvdW50cnknKSkgJT4lDQogIHNlbGVjdChjb3VudHJ5ID0gw68uLmNvdW50cnlfbmFtZSwgcmVnaW9uLCB5ZWFyLCBsYWRkZXIgPSBsaWZlX2xhZGRlcikgDQoNCiMgUmVuYW1pbmcgcmVnaW9uLCBsYWRkZXIgc2NvcmUgaW4gZGF0YV9hbGwgZGF0YXNldA0KbmFtZXMoZGZfYWxsX3JlZ2lvbilbbmFtZXMoZGZfYWxsX3JlZ2lvbikgPT0gJ3JlZ2lvbiddIDwtICdyZWdpb25hbF9pbmRpY2F0b3InDQpuYW1lcyhkZl9hbGxfcmVnaW9uKVtuYW1lcyhkZl9hbGxfcmVnaW9uKSA9PSAnbGFkZGVyJ10gPC0gJ2xhZGRlcl9zY29yZScNCg0KDQojIFN1YnNldHRpbmcgZGZfMjAyMSBkYXRhc2V0DQpkZl8yMDIxX3JlZ2lvbjwtIGRmXzIwMjEgJT4lDQogIHNlbGVjdChjb3VudHJ5ID0gw68uLmNvdW50cnlfbmFtZSwgcmVnaW9uYWxfaW5kaWNhdG9yLCB5ZWFyLCBsYWRkZXJfc2NvcmUpDQoNCiMgQmluZGluZyBhbGwgdGhlIHJlZ2lvbnMgaW4gYGRmX2ZpbmFsYCBkYXRhc2V0DQpkZl9maW5hbCA8LXJiaW5kKGRmX2FsbF9yZWdpb24sZGZfMjAyMV9yZWdpb24pICU+JQ0KICBmaWx0ZXIoIWlzLm5hKHllYXIpICYgIWlzLm5hKHJlZ2lvbmFsX2luZGljYXRvcikpIA0KDQojIE1ha2luZyBkYXRhc2V0IG9mIGxhc3QgMyB5ZWFycw0KZGZfZmluYWxfMTlfMjBfMjEgPC0gZGZfZmluYWwgJT4lIA0KICBmaWx0ZXIoeWVhciA+PSAyMDE5KQ0KYGBgDQoNCiMjIyBQbG90dGluZyB0cmVuZHMgZnJvbSAyMDIwIHRvIDIwMjENCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTAsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KIyBGaWx0ZXJpbmcgcmVnaW9ucyBmb3IgbGFkZGVyIHNjb3JlIHllYXJzIDIwMTksIDIwMjAgYW5kIDIwMjEgIA0KZGZfMjBfMjEgPC0gZGZfZmluYWxfMTlfMjBfMjEgJT4lIA0KICBmaWx0ZXIoeWVhciA+PSAyMDIwKSAlPiUNCiAgc2VsZWN0KGNvdW50cnksIHJlZ2lvbmFsX2luZGljYXRvciwgeWVhciwgbGFkZGVyX3Njb3JlKSAgJT4lDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSAneWVhcicsIG5hbWVzX3ByZWZpeCA9ICd5ZWFyJywgdmFsdWVzX2Zyb20gPSAnbGFkZGVyX3Njb3JlJykgJT4lDQogIGdyb3VwX2J5KHJlZ2lvbmFsX2luZGljYXRvcikgJT4lDQogIHN1bW1hcml6ZShoYXBwaW5lc3NfMjAyMCA9IG1lYW4oeWVhcjIwMjAsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBoYXBwaW5lc3NfMjAyMSA9IG1lYW4oeWVhcjIwMjEsIG5hLnJtID0gVFJVRSkpICU+JQ0KICBtdXRhdGUoZGlmZiA9IGhhcHBpbmVzc18yMDIxLWhhcHBpbmVzc18yMDIwKSAlPiUNCiAgYXJyYW5nZShkaWZmKSAlPiUNCiAgbXV0YXRlKHJlZ2lvbmFsX2luZGljYXRvciA9IGZhY3RvcihyZWdpb25hbF9pbmRpY2F0b3IsIGxldmVscyA9IHJlZ2lvbmFsX2luZGljYXRvcikpDQpgYGANCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gMTAsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KIyBWaXN1YWxpemluZyBkaWZmZXJlbmNlIGluIGhhcHBpbmVzcyBzY29yZSBpbiAyMDIwIHRvIDIwMjENCnBsb3RfMjAyMSA8LSBnZ3Bsb3QoKSArIA0KICBnZW9tX2R1bWJiZWxsKGRhdGEgPSBkZl8yMF8yMSAlPiUgZmlsdGVyKGRpZmYgPjApLA0KICAgICAgICAgICAgICAgIGFlcyh5PXJlZ2lvbmFsX2luZGljYXRvciwgeD1oYXBwaW5lc3NfMjAyMCwgeGVuZD1oYXBwaW5lc3NfMjAyMSksDQogICAgICAgICAgICAgICAgc2l6ZT0xLjUsIGNvbG9yPSIjN0ZCMTg1IiwgDQogICAgICAgICAgICAgICAgY29sb3VyX3hlbmQgPSAiIzdGQjE4NSIsIGNvbG91cl94ID0gIiM3RkIxODUiLA0KICAgICAgICAgICAgICAgIHNpemVfeCA9IDIuNSwgc2l6ZV94ZW5kID0gNSwNCiAgICAgICAgICAgICAgICBkb3RfZ3VpZGU9VFJVRSwgZG90X2d1aWRlX3NpemU9MC41KSArDQogIGdlb21fZHVtYmJlbGwoZGF0YSA9IGRmXzIwXzIxICU+JSBmaWx0ZXIoZGlmZiA8MCksDQogICAgICAgICAgICAgICAgYWVzKHk9cmVnaW9uYWxfaW5kaWNhdG9yLCB4PWhhcHBpbmVzc18yMDIwLCB4ZW5kPWhhcHBpbmVzc18yMDIxKSwNCiAgICAgICAgICAgICAgICBzaXplPTEuNSwgY29sb3I9IiNlZGFlNTIiLCANCiAgICAgICAgICAgICAgICBjb2xvdXJfeGVuZCA9ICIjZWRhZTUyIiwgY29sb3VyX3ggPSAiI2VkYWU1MiIsDQogICAgICAgICAgICAgICAgc2l6ZV94ID0gMi41LCBzaXplX3hlbmQgPSA1LA0KICAgICAgICAgICAgICAgIGRvdF9ndWlkZT1UUlVFLCBkb3RfZ3VpZGVfc2l6ZT0wLjUpICsNCiAgc2NhbGVfeV9kaXNjcmV0ZShsaW1pdHMgPSBsZXZlbHMoZGZfMjAxOV8yMDIwJHJlZ2lvbmFsX2luZGljYXRvciksIGV4cGFuZD1jKDAuMDc1LDEpKSArDQogIGxhYnMoeD0nJywgeT1OVUxMLA0KICAgICAgIHRpdGxlPSJIYXBwaW5lc3MgYW1kaXN0IENvdmlkIHRvIDIwMjEiLA0KICAgICAgIHN1YnRpdGxlID0gJ01vc3QgcmVnaW9ucyBzZWUgZGVjcmVhc2VzIGluIGhhcHBpbmVzcy4nLA0KICAgICAgIGNhcHRpb249ICdTb3VyY2U6IFdvcmxkIEhhcHBpbmVzcyBSZXBvcnQgKDIwMjEpJykgKw0KICBnZW9tX3JlY3QoZGF0YT1kZl8yMF8yMSwNCiAgICAgICAgICAgIGFlcyh4bWluPTcuMzUsIHhtYXg9Ny42NSwgeW1pbj0tSW5mLCB5bWF4PUluZiksDQogICAgICAgICAgICBmaWxsPSIjZTNlMmUxIikgKw0KICBnZW9tX3RleHQoZGF0YT1kZl8yMF8yMSAlPiUgZmlsdGVyKHJlZ2lvbmFsX2luZGljYXRvciA9PSAnV2VzdGVybiBFdXJvcGUnKSwNCiAgICAgICAgICAgIGFlcyh4PWhhcHBpbmVzc18yMDIxLCB5PXJlZ2lvbmFsX2luZGljYXRvciwgbGFiZWw9ICIyMDIxIiksDQogICAgICAgICAgICBjb2xvcj0iZ3JheTE1Iiwgc2l6ZT0zLCBoanVzdD0tMS41KSArDQogIGdlb21fdGV4dChkYXRhPWRmXzIwXzIxICU+JSBmaWx0ZXIocmVnaW9uYWxfaW5kaWNhdG9yID09ICdXZXN0ZXJuIEV1cm9wZScpLA0KICAgICAgICAgICAgYWVzKHg9aGFwcGluZXNzXzIwMjAsIHk9cmVnaW9uYWxfaW5kaWNhdG9yLCBsYWJlbD0gIjIwMjAiKSwNCiAgICAgICAgICAgIGNvbG9yPSJncmF5MTUiLCBzaXplPTMsIGhqdXN0PTMuMCkgKw0KICBnZW9tX3RleHQoZGF0YT1kZl8yMF8yMSAlPiUgZmlsdGVyKGRpZmY+MCksDQogICAgICAgICAgICBhZXMoeD1oYXBwaW5lc3NfMjAyMSAsIHk9cmVnaW9uYWxfaW5kaWNhdG9yLCBsYWJlbD1yb3VuZChoYXBwaW5lc3NfMjAyMCwyKSksDQogICAgICAgICAgICBzaXplPTQsIGhqdXN0PS0wLjUpICsNCiAgZ2VvbV90ZXh0KGRhdGE9ZGZfMjBfMjEgJT4lIGZpbHRlcihkaWZmPjApLA0KICAgICAgICAgICAgYWVzKHg9aGFwcGluZXNzXzIwMjEgLCB5PXJlZ2lvbmFsX2luZGljYXRvciwgbGFiZWw9cm91bmQoaGFwcGluZXNzXzIwMjAsMikpLA0KICAgICAgICAgICAgY29sb3I9ImdyYXkxNSIsIHNpemU9NCwgaGp1c3Q9MS4zKSArDQogIGdlb21fdGV4dChkYXRhPWRmXzIwXzIxICU+JSBmaWx0ZXIoZGlmZjwwKSwNCiAgICAgICAgICAgIGFlcyh4PWhhcHBpbmVzc18yMDIxICwgeT1yZWdpb25hbF9pbmRpY2F0b3IsDQogICAgICAgICAgICAgICAgbGFiZWw9cm91bmQoaGFwcGluZXNzXzIwMjEsMikpLHNpemU9NCwgaGp1c3Q9MS41KSArDQogIGdlb21fdGV4dChkYXRhPWRmXzIwXzIxICU+JSBmaWx0ZXIoZGlmZjwwKSwNCiAgICAgICAgICAgIGFlcyh4PWhhcHBpbmVzc18yMDIwICwgeT1yZWdpb25hbF9pbmRpY2F0b3IsDQogICAgICAgICAgICAgICAgbGFiZWw9cm91bmQoaGFwcGluZXNzXzIwMjAsMikpLA0KICAgICAgICAgICAgY29sb3I9ImdyYXkxNSIsIHNpemU9NCwgaGp1c3Q9LTAuMykgKw0KICBnZW9tX3RleHQoZGF0YT1kZl8yMF8yMSAlPiUNCiAgICAgICAgICAgICAgZmlsdGVyKHJlZ2lvbmFsX2luZGljYXRvciA9PSAnV2VzdGVybiBFdXJvcGUnKSwNCiAgICAgICAgICAgIGFlcyh4PTcuNSwgeT1yZWdpb25hbF9pbmRpY2F0b3IsIGxhYmVsPSJESUZGIiksDQogICAgICAgICAgICBzaXplPTQuNSwgdmp1c3Q9LTEuNSwgZm9udGZhY2U9ImJvbGQiKSArDQogIGdlb21fdGV4dChkYXRhPWRmXzIwXzIxLCBhZXMobGFiZWw9cm91bmQoZGlmZiwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1yZWdpb25hbF9pbmRpY2F0b3IsIHg9Ny41KSwgc2l6ZT0zKSArIA0KICB0aGVtZV9pcHN1bShncmlkPSIiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplPSAxMiwgY29sb3IgPSAnIzNhNDAzYScpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGNvbG9yID0gJ2JsYWNrJyksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAnbGVmdCcpDQpgYGANCiMjIEhhcHBpbmVzcyB0cmVuZHMgVmlzdWFsaXphdGlvbnMgZm9yIGxhc3QgdGhyZWUgeWVhcnMgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHMgfQ0KIyMjIER1bWJlbGwgY29tcGFyaXNvbi4NClBsb3R0aW5nIHRyZW5kcyBhZG1pc3QgY292aWQgYW5kIDIwMjEgbGV2ZWxzLg0KYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAyMCwgZmlnLmNhcD0iRmlndXJlIDU6IFRyZW5kIHBsb3RzIHRvIGNvbXBhcmUgaGFwcGluZXNzIGxldmVscyBpbiBwcmUsIGFkbWlzdCBjb3ZpZCBhbmQgMjAyMSJ9DQojIERpc3BsYXlpbmcgY29tcGFyaXNvbiBwbG90cw0KcGxvdF8yMDIwICsgcGxvdF8yMDIxDQpgYGANCiMjIyBCb3hwbG90IGNvbXBhcmlzb24gDQpQbG90dGluZyBib3hwbG90IGZvciBlbmhhbmNlZCBjbGFyaXR5IG9mIHRyZW5kcyBhY3Jvc3MgcmVnaW9ucy4NCmBgYHtyLGZpZy5oZWlnaHQ9NiwgZmlnLmNhcD0gIkZpZ3VyZSA2OiBCb3hwbG90IGFuYWx5c2lzIG9mIGhhcHBpbmVzcyBzY29yZXMifQ0KICAjIFBsb3R0aW5nIGhhcHBpbmVzcyBpbmRleCB0byBjb21wYXJlIGxldmVscyBpbiBsYXN0IHRocmVlIHllYXJzDQogIGdncGxvdChkZl9maW5hbF8xOV8yMF8yMSwgYWVzKHg9ZmFjdG9yKHllYXIpLCB5PWxhZGRlcl9zY29yZSxmaWxsPXJlZ2lvbmFsX2luZGljYXRvcikpKw0KICAgIGdlb21fYm94cGxvdCgpKw0KICAgIGdndGl0bGUoIkhhcHBpbmVzcyBpbmRleCBhY3Jvc3MgcmVnaW9ucyBmb3IgeWVhciAyMDE5LDIwMjAgYW5kIDIwMjEiKSsNCiAgICBmYWNldF9ncmlkKC5+cmVnaW9uYWxfaW5kaWNhdG9yKSsNCiAgICBsYWJzKHg9IlllYXIiKSsNCiAgICBmYWNldF93cmFwKC5+cmVnaW9uYWxfaW5kaWNhdG9yLG5yb3cgPSAyLHN0cmlwLnBvc2l0aW9uID0gInJpZ2h0IiApKw0KICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT0tOTAsIHZqdXN0PTAuNCxoanVzdD0xKSkrDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCj5EZXNwaXRlIENvdmlkLTE5LCBhYm91dCBoYWxmIG9mIHRoZSBjb3VudHJpZXMgaW4gdGhlIHdvcmxkIHN0aWxsIHNlZSBhbiBpbmNyZWFzZSBpbiBoYXBwaW5lc3MgZnJvbSAyMDE5IHRvIDIwMjAgYnkgc21hbGwgaW5jcmVtZW50LiBXaGVyZWFzLCBtYWpvcml0eSBvZiBjb3VudHJpZXMgc2VlIGEgZGlwIGluIGhhcHBpbmVzcyBmcm9tIDIwMjAgdG8gMjAyMS4NCg0KDQoqKioNCg0KIyMgVmlzdWFsaXphdGlvbiAzLSBGYWN0b3JzIGNvcnJlbGF0aW5nIHRvIGhhcHBpbmVzcw0KUGxvdHRpbmcgY29ycmVsYXRpb24gYW1vbmcgZmFjdG9ycyByZWxhdGVkIHRvIGhhcHBpbmVzcyBpbiAyMDIxIGRhdGFzZXQuDQpgYGB7cixjb3JyLCBmaWcuaGVpZ2h0ID0gMywgZmlnLndpZHRoID0gNSwgZmlnLmFsaWduID0gImxlZnQiLCBmaWcuY2FwPSJGaWd1cmUgNzogQ29ycmVsYXRpb24gTWF0cml4In0NCiMgU3Vic2V0dGluZyBudW1lcmljYWwgY29sdW1zIA0KZGZfY29yIDwtIGRmXzIwMjEgJT4lIA0KICBzZWxlY3QoY29ycnVwdGlvbiA9IHBlcmNlcHRpb25zX29mX2NvcnJ1cHRpb24sDQogICAgICAgICBnZW5lcm9zaXR5ID0gZ2VuZXJvc2l0eSwNCiAgICAgICAgIGZyZWVkb20gPSBmcmVlZG9tX3RvX21ha2VfbGlmZV9jaG9pY2VzLCANCiAgICAgICAgIGxpZmVfZXhwZWN0YW5jeSA9IGhlYWx0aHlfbGlmZV9leHBlY3RhbmN5LCANCiAgICAgICAgIHNvY2lhbF9zdXBwb3J0ID0gc29jaWFsX3N1cHBvcnQsDQogICAgICAgICBHRFBfcGVyX2NhcGl0YSA9IGxvZ2dlZF9HRFBfcGVyX2NhcGl0YSwgDQogICAgICAgICBoYXBwaW5lc3MgPSBsYWRkZXJfc2NvcmUNCiAgKQ0KIyBEaXNwbGF5aW5nIGhlYXRtYXAgb2YgY29ycmVsYXRpb24NCmNvcnIgPC0gY29yKGRmX2NvcikNCnBsb3RfbHkoY29sb3JzID0gIlJkQnUiKSAlPiUNCiAgYWRkX2hlYXRtYXAoeCA9IHJvd25hbWVzKGNvcnIpLCB5ID0gY29sbmFtZXMoY29yciksIHogPSBjb3JyKSAlPiUNCiAgY29sb3JiYXIobGltaXRzID0gYygtMSwgMSkpDQpgYGANCmBgYHtyfQ0KIyBwbG90bHkgaXMgdXNlZCB0byBtYWtlIGFuIGludGVyYWN0aXZlIHBsb3RzLiBJZiB0aGUgbW91c2UgaXMgaG92ZXJlZCBvdmVyIGZpZ3VyZSwgZGF0YXBvaW50cyB3aWxsIGJlIHZpc2libGUuDQpgYGANCg0KPlRvcCAzIGNvbnRyaWJ1dG9ycyBvZiBoYXBwaW5lc3MgZnJvbSB0aGUgMjAyMSBkYXRhc2V0IGFyZToNCg0KPjEuIExpZmUgRXhwZWN0YW5jeQ0KPjIuIFNvY2lhbCBTdXBwb3J0DQo+My4gR0RQIHBlciBjYXBpdGEgDQoNCioqKg0KDQojIyBWaXN1YWxpemF0aW9uIDQtIEdlbmVyYWwgdHJlbmQgb2YgaGFwcGluZXNzIGxldmVscyBvdmVyIHRoZSByZWdpb25zLg0KIyMjIFBsb3R0aW5nIG92ZXJhbGwgdHJlbmQgb2YgaGFwcGluZXNzIHNjb3JlcyBhY3Jvc3MgYWxsIHJlZ2lvbnMuDQpgYGB7ciwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDksIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuY2FwPSJGaWd1cmUgODogSGFwcGluZXNzIHRyZW5kIHBsb3QgYWNyb3NzIHJlZ2lvbnMifQ0KIyBNYXBwaW5nIHJlZ2lvbnMgdG8gaGFwcGluZXNzIHNjb3Jlcy4NCnJlZ2lvbl9sZXZlbCA8LSBnZ3Bsb3QoZGZfZmluYWwsIGFlcyggeCA9IHJlZ2lvbmFsX2luZGljYXRvciwgeSA9IGxhZGRlcl9zY29yZSwgZmlsbCA9IHJlZ2lvbmFsX2luZGljYXRvciwgdGV4dCA9IGNvdW50cnkpKSArIGdlb21fYmVlc3dhcm0oYWVzKGNvbG9yID0gcmVnaW9uYWxfaW5kaWNhdG9yLCBhbHBoYT0xKSApDQoNCnJlZ2lvbl9sZXZlbDQgPC0gcmVnaW9uX2xldmVsICAgKyAgZ2VvbV9ib3hwbG90KGFlcyhhbHBoYT0yICkpICsNCiAgICAgICAgICAgIGdndGl0bGUoIkNvdW50cnktd2lzZSBoYXBwaW5lc3MgdHJlbmRzIGluIHJlZ2lvbnMiKSsNCiAgICAgICAgICAgICN0aGVtZV9jbGFzc2ljKCkgKyANCiAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KCBhbmdsZSA9IDAsaGp1c3Q9MSwgc2l6ZT04KSkgKyAgDQogICAgICAgICAgICBzY2FsZV94X2Rpc2NyZXRlKGxhYmVscyA9IHdyYXBfZm9ybWF0KDEwKSkrICANCiAgICAgICAgICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKSArIA0KICAgICAgICAgICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKQ0KICAgICAgICBnZ3Bsb3RseShyZWdpb25fbGV2ZWw0LCB0b29sdGlwID0gYygiY291bnRyeSIsImxhZGRlcl9zY29yZSIpKQ0KYGBgDQpgYGB7cn0NCiMgcGxvdGx5IGlzIHVzZWQgdG8gbWFrZSBhbiBpbnRlcmFjdGl2ZSBwbG90cy4gSWYgdGhlIG1vdXNlIGlzIGhvdmVyZWQgb3ZlciBmaWd1cmUsIGRhdGFwb2ludHMgd2lsbCBiZSB2aXNpYmxlLg0KYGBgDQoNCj5Ub3AgaGFwcGllc3QgcmVnaW9ucyBpbiB0aGUgd29ybGQgYXJlIFdlc3Rlcm4gRXVyb3BlIGFuZCBOb3J0aCBBbWVyaWNhICYgQU5aLg0KDQoNCg0KDQoqKioNCg0KIyMgU3VtbWFyeQ0KSGFwcGluZXNzIGFjcm9zcyB0aGUgZ2xvYmUgaGFzIHRha2VuIGEgYmxvdy4gTm9uZSBvZiB0aGUgcmVnaW9ucyBpbiB0aGUgd29ybGQgc2hvdyByaXNlIGluIGhhcHBpbmVzcyBpbiAyMDIxIGFzIGNvbXBhcmVkIHRvIDIwMjAgKGFtaWRzdCBjb3ZpZCkuICANCg0KQ291bnRyaWVzIGhhdmluZyBnb29kIGhlYWx0aHkgbGlmZXN0eWxlLCBzb2NpYWwgc3VwcG9ydCwgYW5kIGhpZ2ggZ29vZCBwZXIgY2FwaXRhIGluY29tZSBoYXZlIGhpZ2ggaGFwcGluZXNzIGluZGV4LiBXZXN0ZXJuIEV1cm9wZSBhbmQgTm9ydGhlcm4gQW1lcmljYSBmdXJ0aGVyIGNvbmZpcm0gdGhlIHBhdHRlcm4gd2l0aCBoaWdoIGhhcHBpbmVzcyBzY29yZXMuDQoNCiMjIyBXaGF0IEkgbGVhcm5lZD8NCkRlZmluaXRlbHkgZ290IHdoYXQgdGhlIGZ1c3MgaXMgYWxsIGFib3V0IGZvciBSLiBEZXNwaXRlIGJlaW5nIGEgcHl0aG9uIGVudGh1c2lhc3QgSSBoYXZlIGdyb3duIHRvIGxvdmUgUi4gTGVhcm5lZCBob3cgUiBoYW5kbGVzIHJlcHJvZHVjaWJpbGl0eSBhbmQgdmVyc2lvbiBjb250cm9sIGlzc3Vlcywgc2hhcmUgbXkgcHJvamVjdCB3aXRob3V0IHRoZSBoYXNzbGUgb2YgaGFuZGxpbmcgZGVwZW5kZW5jaWVzIGFuZCBuZXcgcGFja2FnZXMgbGlrZSBwYWNrcmF0LCB2aXpkYXQsIG5haW5hciBldGMuIA0KTGVhcm5lZCBhIGxvdCBhYm91dCBhdXRvbWF0aW9uIGluIFJNYXJrZG93biBhbmQgcHVibGljYXRpb24gb24gUlB1YnMuDQoNCiMjIyBXaGF0IEkgd291bGQgZG8gbmV4dD8NClRoZXJlIHdlcmUgc2V2ZXJhbCB2YXJpYWJsZXMgdW50b3VjaGVkIGR1ZSB0byB0aW1lIGNvbnN0cmFpbnQgYW5kIHNjb3BlIG9mIHRoZSBwcm9qZWN0LiBGdXJ0aGVyIEkgd291bGQgc2VlIGhvdyB0aGUgc2l4IGZhY3RvcnMgY29udHJpYnV0ZSB0byBoYXBwaW5lc3Mgc2NvcmVzIGFuZCBsb29rIGF0IHRoZSB0aW1lIHNlcmllcyBhbmFseXNpcyBvZiB0aGUgbW9zdCBpbmZsdWVudGlhbCBmYWN0b3JzLiBGdXRoZXJtb3JlLCBtYWtlIGFuIGludGVyYWN0aXZlIGRhc2hib2FyZCB0byBkaXNwbGF5IHJlZ3Jlc3Npb24gYW5kIGNsdXN0ZXIgYW5hbHlzaXMgb2YgaW1wb3J0YW50IGZlYXR1cmVzLiANCg0KKioqDQoNCiMjIFJlZmVyZW5jZXMNCiogV29ybGQgSGFwcGluZXNzIFJlcG9ydCAyMDIxLSAgPGh0dHBzOi8vd29ybGRoYXBwaW5lc3MucmVwb3J0Pg0KKiBEYXRhc2V0LSA8aHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9hamF5cGFsc2luZ2hsby93b3JsZC1oYXBwaW5lc3MtcmVwb3J0LTIwMjE+DQoqIE1ldGFkYXRhLSA8aHR0cHM6Ly9oYXBwaW5lc3MtcmVwb3J0LnMzLmFtYXpvbmF3cy5jb20vMjAyMS9BcHBlbmRpeDFXSFIyMDIxQzIucGRmPg==