About the Data

The data is from Kenya National Bureau of Statistics Data Tables.

It is about the Population Distribution of Households by County according to the 2019 Kenya Population and Housing Census.

It contains the following fields;

Steps Taken

  1. Importing Necessary R Packages
  2. Loading Data to R
  3. Understanding the Data
  4. Data Cleaning and Preparation - Missing Values
  5. Exploratory Data Analysis - Visualizations
  6. Findings

Importing necessary packages

library(readxl) # To read excel data into R
library(tidyverse) # To tidy data
library(plotly) # To create interactive visualizations
library(knitr) # For report generation
library(kableExtra) # To display table
library(dplyr) # For data analysis

Load and Preview the Data

# Load data to a dataFrame
pop_data <- read_excel("C:/Users/KNBS/Documents/PROJECTS/Education Loans R Shiny/Population-households-density-by-county.xlsx", skip = 4)

# Preview the Data
head(pop_data)

Formatting Columns

Renaming column Headers

colnames(pop_data) <- c("County", "Total_Population", "Male_Population",
                        "Female_Population", "Intersex_Population",
                        "Total_Household", "Conventional_Household",
                        "Group_Quarters", "Land_Area_SqKm",
                        "Density_Persons_per_SqKm")
# Previewing the result
head(pop_data)

Understanding the structure of the Data

str(pop_data)
tibble [48 × 10] (S3: tbl_df/tbl/data.frame)
 $ County                  : chr [1:48] "MOMBASA" "KWALE" "KILIFI" "TANA RIVER" ...
 $ Total_Population        : num [1:48] 1208333 866820 1453787 315943 143920 ...
 $ Male_Population         : num [1:48] 610257 425121 704089 158550 76103 ...
 $ Female_Population       : num [1:48] 598046 441681 749673 157391 67813 ...
 $ Intersex_Population     : num [1:48] 30 18 25 2 4 7 34 49 37 18 ...
 $ Total_Household         : num [1:48] 378422 173176 298472 68242 37963 ...
 $ Conventional_Household  : num [1:48] 376295 172802 297990 66984 34231 ...
 $ Group_Quarters          : num [1:48] 2127 374 482 1258 3732 ...
 $ Land_Area_SqKm          : num [1:48] 220 8254 12553 37904 6283 ...
 $ Density_Persons_per_SqKm: num [1:48] 5495.01 105.02 115.81 8.34 22.91 ...
OBSERVATIONS:

Missing Values

Checking for rows with any null/Missing Values and viewing them

# Check for NAs in the entire pop_data data frame
na_rows <- pop_data[apply(is.na(pop_data), 1, any), ]

# View the rows with NAs in any column
print(na_rows)

OBSERVATION: Only one of the rows has missing values. It is the last row that isn’t related to the data, so will drop it.

pop_data <- na.omit(pop_data)

Previewing nulls again to confirm removal of the row

# Check for nulls in the entire pop_data data frame
na_rows <- pop_data[apply(is.na(pop_data), 1, any), ]

# View the rows with nulls in any column
print(na_rows)

OBSERVATION: - There’s no missing values left.

Getting Summary statistics of the data fields

# Summary statistics of the Data's columns
summary(pop_data)
    County          Total_Population  Male_Population   Female_Population Intersex_Population Total_Household   Conventional_Household Group_Quarters   
 Length:47          Min.   : 143920   Min.   :  76103   Min.   :  67813   Min.   :  2.00      Min.   :  37963   Min.   :  34231        Min.   :   77.0  
 Class :character   1st Qu.: 609505   1st Qu.: 303110   1st Qu.: 311291   1st Qu.: 18.00      1st Qu.: 141956   1st Qu.: 140409        1st Qu.:  610.5  
 Mode  :character   Median : 893681   Median : 450741   Median : 448868   Median : 25.00      Median : 204188   Median : 203576        Median : 1258.0  
                    Mean   :1012006   Mean   : 501023   Mean   : 510951   Mean   : 32.43      Mean   : 258381   Mean   : 256234        Mean   : 2146.7  
                    3rd Qu.:1156724   3rd Qu.: 569992   3rd Qu.: 589759   3rd Qu.: 34.00      3rd Qu.: 302844   3rd Qu.: 299550        3rd Qu.: 2681.0  
                    Max.   :4397073   Max.   :2192452   Max.   :2204376   Max.   :245.00      Max.   :1506888   Max.   :1494676        Max.   :17809.0  
 Land_Area_SqKm    Density_Persons_per_SqKm
 Min.   :  219.9   Min.   :   6.481        
 1st Qu.: 2526.2   1st Qu.:  52.826        
 Median : 3325.0   Median : 220.377        
 Mean   :12359.5   Mean   : 509.163        
 3rd Qu.:14852.6   3rd Qu.: 415.876        
 Max.   :70944.3   Max.   :6246.995        

Adding an extra column called Regions for better analysis

# Create 'Region' column based on 'County'
pop_data$Region <- ifelse(pop_data$County %in% c("MOMBASA", "KWALE", "KILIFI", "TANA RIVER", "LAMU", "TAITA/TAVETA"), "Coast",
                          ifelse(pop_data$County %in% "NAIROBI CITY", "Nairobi",
                          ifelse(pop_data$County %in% c("KIAMBU", "MURANG'A", "NYERI", "NYANDARUA", "KIRINYAGA"), "Central", 
                          ifelse(pop_data$County %in% c("MANDERA", "WAJIR", "GARISSA", "MARSABIT"), "North Eastern",
                          ifelse(pop_data$County %in% c("TURKANA", "UASIN GISHU", "ELGEYO/MARAKWET", "KERICHO", "WEST POKOT",
                                                        "SAMBURU", "TRANS NZOIA", "BARINGO", "NANDI", "LAIKIPIA", "NAKURU",
                                                        "NAROK", "KAJIADO"), "Rift Valley",
                          ifelse(pop_data$County %in% c("KAKAMEGA", "VIHIGA", "BUNGOMA", "BUSIA"), "Western",
                          ifelse(pop_data$County %in% c("KISII", "NYAMIRA", "HOMA BAY", "MIGORI", "KISUMU", "SIAYA"), "Nyanza",
                          ifelse(pop_data$County %in% c("THARAKA-NITHI", "EMBU", "KITUI", "MAKUENI", "MERU", "ISIOLO", "MACHAKOS"), "Eastern",
                          ifelse(pop_data$County %in% c("KAJIADO", "NAROK", "KERICHO", "BOMET", "NYERI"), "Rift Valley",
                          "Other")))))))))
# Reorder columns with 'Region' as the first column
pop_data <- pop_data %>%
  select(Region, everything())

# Check the resulting data frame
head(pop_data)
# Check unique values in the 'Region' column
unique(pop_data$Region)
[1] "Coast"         "North Eastern" "Eastern"       "Central"       "Rift Valley"   "Western"       "Nyanza"        "Nairobi"      
OBSERVATION

All records are represented in the 8 regions listed here

EXPLORATORY DATA ANALYSIS

VISUALIZATIONS

Total Population by Region

# Bar Plot of Total Population by Region
plot_ly(data = pop_data,
        x = ~Region,
        y = ~Total_Population,
        type = 'bar',
        name = 'Total Population',
        marker = list(color = 'blue')) %>%
  
  layout(title = 'Total Population by Region',
         xaxis = list(title = 'Region'),
         yaxis = list(title = 'Total Population'))
OBSERVATIONS:
  • Rift valley region has the Highest Population.
  • North Eastern region has the lowest Population.

Top 10 Highest County Populations

#Barplot of Top 10 Highest County Populations

# Order the data by Total_Population in descending order
Total_Population_desc <- pop_data[order(pop_data$Total_Population, decreasing = TRUE), ]

# Select the top N counties (e.g., top 10)
top_counties <- head(Total_Population_desc, n = 10)

plot_ly(data = top_counties,
        x = ~reorder(County, -Total_Population),
        y = ~Total_Population,
        type = 'bar',
        name = 'Total Population',
        marker = list(color = 'blue')) %>%
    layout(title = 'Top Highest County Populations',
         xaxis = list(title = 'County'),
         yaxis = list(title = 'Total Population'))
OBSERVATIONS=:
  • Nairobi County has the Highest Population compared to other counties, followed by Kiambu then Nakuru.

Bottom 10 (Low) County Populations

# Barplot of Bottom 10 County Populations

# Order the data by Total_Population in ascending order
pop_data_sorted <- pop_data[order(pop_data$Total_Population), ]

# Select the top N counties (e.g., bottom 10)
bottom_counties <- head(pop_data_sorted, n = 10)

# Create the plot with ordered bars in ascending order
plot_ly(data = bottom_counties,
        x = ~reorder(County, Total_Population),
        y = ~Total_Population,
        type = 'bar',
        name = 'Total Population',
        marker = list(color = 'blue')) %>%
  
  layout(title = 'Bottom Least County Populations',
         xaxis = list(title = 'County'),
         yaxis = list(title = 'Total Population'))
OBSERVATION:
  • Lamu County has the Lowest Population compared to other counties, followed by Isiolo then Samburu from the bottom.

Population by Gender

# Pie Chart of Male, Female and Intersex Population percentages
pop_data %>%
  plot_ly(labels = ~c("Male", "Female", "Intersex"),
          values = ~c(sum(pop_data$Male_Population), sum(pop_data$Female_Population), sum(pop_data$Intersex_Population)),
          type = 'pie',
          marker = list(colors = c("blue", "pink", "red"))) %>%
  layout(title = "Population Distribution by Gender")

Total Households by Region

# Bar Plot of Total Population by Region

plot_ly(data = pop_data,
        x = ~Region,
        y = ~Total_Household,
        type = 'bar',
        name = 'Total Households by Region',
        marker = list(color = 'blue')) %>%
    layout(title = 'Total Households by Region',
         xaxis = list(title = 'Region'),
         yaxis = list(title = 'Total Households for Region'))
OBSERVATION:
  • Rift Valley has the Highest number of Households while North Eastern has the least.

Comparison of Group Quarters and Conventional Household

# Pie Chart of Male, Female and Intersex Population percentages

pop_data %>%
  plot_ly(labels = ~c("Conventional_Household", "Group_Quarters"),
          values = ~c(sum(pop_data$Conventional_Household), sum(pop_data$Group_Quarters)),
          type = 'pie',
          marker = list(colors = c("blue", "red"))) %>%
  layout(title = "Comparison of Group Quarters and Conventional Household")
OBSERVATION:
  • Conventional households are more common than Group Quarters.

Comparison of Group Quarters and Conventional Household by Region

# Grouped Bar plot showing Comparison of Group Quarters and Conventional Household by Region

plot_ly(data = pop_data,
        x = ~Region,
        y = ~Group_Quarters,
        type = 'bar',
        name = 'Group Quarters',
        marker = list(color = 'red')) %>%
  
  add_trace(y = ~Conventional_Household,
            name = 'Conventional Household',
            marker = list(color = 'blue')) %>%
  
  layout(title = 'Comparison of Group Quarters and Conventional Household by Region',
         xaxis = list(title = 'Region'),
         yaxis = list(title = 'Count'),
         barmode = 'group')
OBSERVATIONS:
  • All Kenyan Regions have both Conventional Households and Group Quarters
  • Conventional Households are more common that Group Quarters
  • Rift Valley has the Highest Number of both Conventional Households and Group Quarters

Household vs. Land Area

# Scatter Plot of Household vs. Land Area

plot_ly(
  data = pop_data,
  x = ~Total_Household,
  y = ~Land_Area_SqKm,
  color = ~Region,  # Specify the variable for coloring
  type = 'scatter',
  mode = 'markers'
) %>%
  layout(
    title = 'Household vs. Land Area by Region',
    xaxis = list(title = 'Total Household'),
    yaxis = list(title = 'Land Area (Sq Km)')
  )
OBSERVATION:
  • Most parts of Kenya have low Land area and low Household numbers.

Population Density Distribution

# Histogram of Population Density
# Calculate density values
density_values <- density(pop_data$Density_Persons_per_SqKm)

# Create the combined plot
combined_plot <- plot_ly() %>%
  add_histogram(x = ~pop_data$Density_Persons_per_SqKm, nbinsx = 20, histnorm = 'probability density', marker = list(color = 'blue', line = list(color = 'black', width = 1))) %>%
  add_lines(x = density_values$x, y = density_values$y, type = 'scatter', mode = 'lines', line = list(color = 'red', width = 2)) %>%
  layout(title = 'Population Density Histogram with KDE',
         xaxis = list(title = 'Density (Persons per Sq Km)'),
         yaxis = list(title = 'Probability Density'))

# Display the combined plot
combined_plot
OBSERVATION:
  • Most Kenyan areas have relatively low population density with a few exceptions where population density is significantly high.

Narrowing down to comparison in different regions will help gather more insights.

Population Density by Region

# Box Plot
plot_ly(data = pop_data, x = ~Region, y = ~Density_Persons_per_SqKm, type = "box") %>%
  layout(title = "Population Density by Region",
         xaxis = list(title = "Region"),
         yaxis = list(title = "Density (Persons per Sq Km)"))
OBSERVATION:
  • Most regions have relatively low density ranging from 0 to slightly above 1000000 persons per square Km but the entire Nairobi Region has very high density. Coast Region has an outlier that has very high population density of 5495008 persons per Sq Km.
  • In most regions, the median is closer to the lower values. This means that most values are in the lower range. This emphasizes the low population density in most parts of Kenya.

A table showing density for each county in coast region will help understand the outlier in the region better.

# filter coast data only
coast_data <- pop_data[pop_data$Region == "Coast", ]

# Assuming your data frame is named 'pop_data'
coast_data <- pop_data[pop_data$Region == "Coast", ]

# Create a table of density values
coast_density_table <- coast_data %>%
  select(County, Density_Persons_per_SqKm) %>%
  kable("html", caption = "Density Values for Counties in the Coast Region") %>%
  kable_styling()

# Display the table
coast_density_table
Density Values for Counties in the Coast Region
County Density_Persons_per_SqKm
MOMBASA 5495.00838
KWALE 105.02256
KILIFI 115.80947
TANA RIVER 8.33543
LAMU 22.90616
TAITA/TAVETA 19.86188
OBSERVATION:
  • From the coast Region, Mombasa is the outlier with very high density compared to the other areas.

FINDINGS

LS0tDQp0aXRsZTogIktlbnlhbiBQb3B1bGF0aW9uIERpc3RyaWJ1dGlvbiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIyBBYm91dCB0aGUgRGF0YQ0KVGhlIGRhdGEgaXMgZnJvbSBbS2VueWEgTmF0aW9uYWwgQnVyZWF1IG9mIFN0YXRpc3RpY3MgRGF0YSBUYWJsZXNdKGh0dHBzOi8vd3d3LmtuYnMub3Iua2UvZG93bmxvYWQvcG9wdWxhdGlvbi1ob3VzZWhvbGRzLWRlbnNpdHktYnktY291bnR5LykuDQo8cD5JdCBpcyBhYm91dCB0aGUgUG9wdWxhdGlvbiBEaXN0cmlidXRpb24gb2YgSG91c2Vob2xkcyBieSBDb3VudHkgYWNjb3JkaW5nIHRvIHRoZSAyMDE5IEtlbnlhIFBvcHVsYXRpb24gYW5kIEhvdXNpbmcgQ2Vuc3VzLjwvcD4NCkl0IGNvbnRhaW5zIHRoZSBmb2xsb3dpbmcgZmllbGRzOw0KPHVsPg0KICA8bGk+IENvdW50eQ0KICA8bGk+IFRvdGFsX1BvcHVsYXRpb24NCiAgPGxpPiBNYWxlX1BvcHVsYXRpb24NCiAgPGxpPiBGZW1hbGVfUG9wdWxhdGlvbg0KICA8bGk+IEludGVyc2V4X1BvcHVsYXRpb24NCiAgPGxpPiBUb3RhbF9Ib3VzZWhvbGQNCiAgPGxpPiBDb252ZW50aW9uYWxfSG91c2Vob2xkDQogIDxsaT4gR3JvdXBfUXVhcnRlcnMNCiAgPGxpPiBMYW5kX0FyZWFfU3FLbQ0KICA8bGk+IERlbnNpdHlfUGVyc29uc19wZXJfU3FLbQ0KPC91bD4NCg0KIyMjIFN0ZXBzIFRha2VuDQo8b2w+DQogIDxsaT4gSW1wb3J0aW5nIE5lY2Vzc2FyeSBSIFBhY2thZ2VzDQogIDxsaT4gTG9hZGluZyBEYXRhIHRvIFINCiAgPGxpPiBVbmRlcnN0YW5kaW5nIHRoZSBEYXRhDQogIDxsaT4gRGF0YSBDbGVhbmluZyBhbmQgUHJlcGFyYXRpb24gLSBNaXNzaW5nIFZhbHVlcw0KICA8bGk+IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgLSBWaXN1YWxpemF0aW9ucw0KICA8bGk+IEZpbmRpbmdzDQo8L29sPg0KDQojIyMgSW1wb3J0aW5nIG5lY2Vzc2FyeSBwYWNrYWdlcw0KYGBge3J9DQpsaWJyYXJ5KHJlYWR4bCkgIyBUbyByZWFkIGV4Y2VsIGRhdGEgaW50byBSDQpsaWJyYXJ5KHRpZHl2ZXJzZSkgIyBUbyB0aWR5IGRhdGENCmxpYnJhcnkocGxvdGx5KSAjIFRvIGNyZWF0ZSBpbnRlcmFjdGl2ZSB2aXN1YWxpemF0aW9ucw0KbGlicmFyeShrbml0cikgIyBGb3IgcmVwb3J0IGdlbmVyYXRpb24NCmxpYnJhcnkoa2FibGVFeHRyYSkgIyBUbyBkaXNwbGF5IHRhYmxlDQpsaWJyYXJ5KGRwbHlyKSAjIEZvciBkYXRhIGFuYWx5c2lzDQpgYGANCg0KIyMjIExvYWQgYW5kIFByZXZpZXcgdGhlIERhdGENCmBgYHtyfQ0KIyBMb2FkIGRhdGEgdG8gYSBkYXRhRnJhbWUNCnBvcF9kYXRhIDwtIHJlYWRfZXhjZWwoIkM6L1VzZXJzL0tOQlMvRG9jdW1lbnRzL1BST0pFQ1RTL0VkdWNhdGlvbiBMb2FucyBSIFNoaW55L1BvcHVsYXRpb24taG91c2Vob2xkcy1kZW5zaXR5LWJ5LWNvdW50eS54bHN4Iiwgc2tpcCA9IDQpDQoNCiMgUHJldmlldyB0aGUgRGF0YQ0KaGVhZChwb3BfZGF0YSkNCmBgYA0KDQojIyMgRm9ybWF0dGluZyBDb2x1bW5zDQpSZW5hbWluZyBjb2x1bW4gSGVhZGVycw0KYGBge3J9DQpjb2xuYW1lcyhwb3BfZGF0YSkgPC0gYygiQ291bnR5IiwgIlRvdGFsX1BvcHVsYXRpb24iLCAiTWFsZV9Qb3B1bGF0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJGZW1hbGVfUG9wdWxhdGlvbiIsICJJbnRlcnNleF9Qb3B1bGF0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbF9Ib3VzZWhvbGQiLCAiQ29udmVudGlvbmFsX0hvdXNlaG9sZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAiR3JvdXBfUXVhcnRlcnMiLCAiTGFuZF9BcmVhX1NxS20iLA0KICAgICAgICAgICAgICAgICAgICAgICAgIkRlbnNpdHlfUGVyc29uc19wZXJfU3FLbSIpDQojIFByZXZpZXdpbmcgdGhlIHJlc3VsdA0KaGVhZChwb3BfZGF0YSkNCmBgYA0KIyMjIFVuZGVyc3RhbmRpbmcgdGhlIHN0cnVjdHVyZSBvZiB0aGUgRGF0YQ0KYGBge3J9DQpzdHIocG9wX2RhdGEpDQpgYGANCioqT0JTRVJWQVRJT05TOioqDQo8dWw+DQo8bGk+VGhlcmUgYXJlIDEwIGNvbHVtbnMgYXMgbGlzdGVkLCBhbGwgaW4gdGhlIGNvcnJlY3QgRGF0YSBUeXBlcy4NCjxsaT5UaGUgZGF0YSBoYXMgNDggcmVjb3Jkcy4NCjx1bD4NCg0KIyMjIE1pc3NpbmcgVmFsdWVzDQpDaGVja2luZyBmb3Igcm93cyB3aXRoIGFueSBudWxsL01pc3NpbmcgVmFsdWVzIGFuZCB2aWV3aW5nIHRoZW0NCmBgYHtyfQ0KIyBDaGVjayBmb3IgTkFzIGluIHRoZSBlbnRpcmUgcG9wX2RhdGEgZGF0YSBmcmFtZQ0KbmFfcm93cyA8LSBwb3BfZGF0YVthcHBseShpcy5uYShwb3BfZGF0YSksIDEsIGFueSksIF0NCg0KIyBWaWV3IHRoZSByb3dzIHdpdGggTkFzIGluIGFueSBjb2x1bW4NCnByaW50KG5hX3Jvd3MpDQpgYGANCioqT0JTRVJWQVRJT046KioNCk9ubHkgb25lIG9mIHRoZSByb3dzIGhhcyBtaXNzaW5nIHZhbHVlcy4gSXQgaXMgdGhlIGxhc3Qgcm93IHRoYXQgaXNuJ3QgcmVsYXRlZCB0byB0aGUgZGF0YSwgc28gd2lsbCBkcm9wIGl0Lg0KYGBge3J9DQpwb3BfZGF0YSA8LSBuYS5vbWl0KHBvcF9kYXRhKQ0KYGBgDQoNClByZXZpZXdpbmcgbnVsbHMgYWdhaW4gdG8gY29uZmlybSByZW1vdmFsIG9mIHRoZSByb3cNCmBgYHtyfQ0KIyBDaGVjayBmb3IgbnVsbHMgaW4gdGhlIGVudGlyZSBwb3BfZGF0YSBkYXRhIGZyYW1lDQpuYV9yb3dzIDwtIHBvcF9kYXRhW2FwcGx5KGlzLm5hKHBvcF9kYXRhKSwgMSwgYW55KSwgXQ0KDQojIFZpZXcgdGhlIHJvd3Mgd2l0aCBudWxscyBpbiBhbnkgY29sdW1uDQpwcmludChuYV9yb3dzKQ0KYGBgDQoqKk9CU0VSVkFUSU9OOioqDQotIFRoZXJlJ3Mgbm8gbWlzc2luZyB2YWx1ZXMgbGVmdC4NCg0KIyMjIEdldHRpbmcgU3VtbWFyeSBzdGF0aXN0aWNzIG9mIHRoZSBkYXRhIGZpZWxkcw0KYGBge3J9DQojIFN1bW1hcnkgc3RhdGlzdGljcyBvZiB0aGUgRGF0YSdzIGNvbHVtbnMNCnN1bW1hcnkocG9wX2RhdGEpDQpgYGANCg0KIyMjIEFkZGluZyBhbiBleHRyYSBjb2x1bW4gY2FsbGVkIFJlZ2lvbnMgZm9yIGJldHRlciBhbmFseXNpcw0KYGBge3J9DQojIENyZWF0ZSAnUmVnaW9uJyBjb2x1bW4gYmFzZWQgb24gJ0NvdW50eScNCnBvcF9kYXRhJFJlZ2lvbiA8LSBpZmVsc2UocG9wX2RhdGEkQ291bnR5ICVpbiUgYygiTU9NQkFTQSIsICJLV0FMRSIsICJLSUxJRkkiLCAiVEFOQSBSSVZFUiIsICJMQU1VIiwgIlRBSVRBL1RBVkVUQSIpLCAiQ29hc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocG9wX2RhdGEkQ291bnR5ICVpbiUgIk5BSVJPQkkgQ0lUWSIsICJOYWlyb2JpIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHBvcF9kYXRhJENvdW50eSAlaW4lIGMoIktJQU1CVSIsICJNVVJBTkcnQSIsICJOWUVSSSIsICJOWUFOREFSVUEiLCAiS0lSSU5ZQUdBIiksICJDZW50cmFsIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShwb3BfZGF0YSRDb3VudHkgJWluJSBjKCJNQU5ERVJBIiwgIldBSklSIiwgIkdBUklTU0EiLCAiTUFSU0FCSVQiKSwgIk5vcnRoIEVhc3Rlcm4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocG9wX2RhdGEkQ291bnR5ICVpbiUgYygiVFVSS0FOQSIsICJVQVNJTiBHSVNIVSIsICJFTEdFWU8vTUFSQUtXRVQiLCAiS0VSSUNITyIsICJXRVNUIFBPS09UIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNBTUJVUlUiLCAiVFJBTlMgTlpPSUEiLCAiQkFSSU5HTyIsICJOQU5ESSIsICJMQUlLSVBJQSIsICJOQUtVUlUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTkFST0siLCAiS0FKSUFETyIpLCAiUmlmdCBWYWxsZXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocG9wX2RhdGEkQ291bnR5ICVpbiUgYygiS0FLQU1FR0EiLCAiVklISUdBIiwgIkJVTkdPTUEiLCAiQlVTSUEiKSwgIldlc3Rlcm4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocG9wX2RhdGEkQ291bnR5ICVpbiUgYygiS0lTSUkiLCAiTllBTUlSQSIsICJIT01BIEJBWSIsICJNSUdPUkkiLCAiS0lTVU1VIiwgIlNJQVlBIiksICJOeWFuemEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocG9wX2RhdGEkQ291bnR5ICVpbiUgYygiVEhBUkFLQS1OSVRISSIsICJFTUJVIiwgIktJVFVJIiwgIk1BS1VFTkkiLCAiTUVSVSIsICJJU0lPTE8iLCAiTUFDSEFLT1MiKSwgIkVhc3Rlcm4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocG9wX2RhdGEkQ291bnR5ICVpbiUgYygiS0FKSUFETyIsICJOQVJPSyIsICJLRVJJQ0hPIiwgIkJPTUVUIiwgIk5ZRVJJIiksICJSaWZ0IFZhbGxleSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciIpKSkpKSkpKSkNCiMgUmVvcmRlciBjb2x1bW5zIHdpdGggJ1JlZ2lvbicgYXMgdGhlIGZpcnN0IGNvbHVtbg0KcG9wX2RhdGEgPC0gcG9wX2RhdGEgJT4lDQogIHNlbGVjdChSZWdpb24sIGV2ZXJ5dGhpbmcoKSkNCg0KIyBDaGVjayB0aGUgcmVzdWx0aW5nIGRhdGEgZnJhbWUNCmhlYWQocG9wX2RhdGEpDQpgYGANCg0KYGBge3J9DQojIENoZWNrIHVuaXF1ZSB2YWx1ZXMgaW4gdGhlICdSZWdpb24nIGNvbHVtbg0KdW5pcXVlKHBvcF9kYXRhJFJlZ2lvbikNCmBgYA0KKipPQlNFUlZBVElPTioqDQo8cD5BbGwgcmVjb3JkcyBhcmUgcmVwcmVzZW50ZWQgaW4gdGhlIDggcmVnaW9ucyBsaXN0ZWQgaGVyZTwvcD4NCg0KIyBFWFBMT1JBVE9SWSBEQVRBIEFOQUxZU0lTDQpWSVNVQUxJWkFUSU9OUw0KDQojIyMgVG90YWwgUG9wdWxhdGlvbiBieSBSZWdpb24NCmBgYHtyfQ0KIyBCYXIgUGxvdCBvZiBUb3RhbCBQb3B1bGF0aW9uIGJ5IFJlZ2lvbg0KcGxvdF9seShkYXRhID0gcG9wX2RhdGEsDQogICAgICAgIHggPSB+UmVnaW9uLA0KICAgICAgICB5ID0gflRvdGFsX1BvcHVsYXRpb24sDQogICAgICAgIHR5cGUgPSAnYmFyJywNCiAgICAgICAgbmFtZSA9ICdUb3RhbCBQb3B1bGF0aW9uJywNCiAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICdibHVlJykpICU+JQ0KICANCiAgbGF5b3V0KHRpdGxlID0gJ1RvdGFsIFBvcHVsYXRpb24gYnkgUmVnaW9uJywNCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdSZWdpb24nKSwNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdUb3RhbCBQb3B1bGF0aW9uJykpDQpgYGANCioqT0JTRVJWQVRJT05TOioqDQo8dWw+DQo8bGk+IFJpZnQgdmFsbGV5IHJlZ2lvbiBoYXMgdGhlIEhpZ2hlc3QgUG9wdWxhdGlvbi4NCjxsaT4gTm9ydGggRWFzdGVybiByZWdpb24gaGFzIHRoZSBsb3dlc3QgUG9wdWxhdGlvbi4NCjwvdWw+DQoNCiMjIyBUb3AgMTAgSGlnaGVzdCBDb3VudHkgUG9wdWxhdGlvbnMNCmBgYHtyfQ0KI0JhcnBsb3Qgb2YgVG9wIDEwIEhpZ2hlc3QgQ291bnR5IFBvcHVsYXRpb25zDQoNCiMgT3JkZXIgdGhlIGRhdGEgYnkgVG90YWxfUG9wdWxhdGlvbiBpbiBkZXNjZW5kaW5nIG9yZGVyDQpUb3RhbF9Qb3B1bGF0aW9uX2Rlc2MgPC0gcG9wX2RhdGFbb3JkZXIocG9wX2RhdGEkVG90YWxfUG9wdWxhdGlvbiwgZGVjcmVhc2luZyA9IFRSVUUpLCBdDQoNCiMgU2VsZWN0IHRoZSB0b3AgTiBjb3VudGllcyAoZS5nLiwgdG9wIDEwKQ0KdG9wX2NvdW50aWVzIDwtIGhlYWQoVG90YWxfUG9wdWxhdGlvbl9kZXNjLCBuID0gMTApDQoNCnBsb3RfbHkoZGF0YSA9IHRvcF9jb3VudGllcywNCiAgICAgICAgeCA9IH5yZW9yZGVyKENvdW50eSwgLVRvdGFsX1BvcHVsYXRpb24pLA0KICAgICAgICB5ID0gflRvdGFsX1BvcHVsYXRpb24sDQogICAgICAgIHR5cGUgPSAnYmFyJywNCiAgICAgICAgbmFtZSA9ICdUb3RhbCBQb3B1bGF0aW9uJywNCiAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICdibHVlJykpICU+JQ0KICAgIGxheW91dCh0aXRsZSA9ICdUb3AgSGlnaGVzdCBDb3VudHkgUG9wdWxhdGlvbnMnLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0NvdW50eScpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ1RvdGFsIFBvcHVsYXRpb24nKSkNCmBgYA0KKipPQlNFUlZBVElPTlM9OioqDQo8dWw+DQo8bGk+IE5haXJvYmkgQ291bnR5IGhhcyB0aGUgSGlnaGVzdCBQb3B1bGF0aW9uIGNvbXBhcmVkIHRvIG90aGVyIGNvdW50aWVzLCBmb2xsb3dlZCBieSBLaWFtYnUgdGhlbiBOYWt1cnUuDQo8L3VsPg0KDQojIyMgQm90dG9tIDEwIChMb3cpIENvdW50eSBQb3B1bGF0aW9ucw0KYGBge3J9DQojIEJhcnBsb3Qgb2YgQm90dG9tIDEwIENvdW50eSBQb3B1bGF0aW9ucw0KDQojIE9yZGVyIHRoZSBkYXRhIGJ5IFRvdGFsX1BvcHVsYXRpb24gaW4gYXNjZW5kaW5nIG9yZGVyDQpwb3BfZGF0YV9zb3J0ZWQgPC0gcG9wX2RhdGFbb3JkZXIocG9wX2RhdGEkVG90YWxfUG9wdWxhdGlvbiksIF0NCg0KIyBTZWxlY3QgdGhlIHRvcCBOIGNvdW50aWVzIChlLmcuLCBib3R0b20gMTApDQpib3R0b21fY291bnRpZXMgPC0gaGVhZChwb3BfZGF0YV9zb3J0ZWQsIG4gPSAxMCkNCg0KIyBDcmVhdGUgdGhlIHBsb3Qgd2l0aCBvcmRlcmVkIGJhcnMgaW4gYXNjZW5kaW5nIG9yZGVyDQpwbG90X2x5KGRhdGEgPSBib3R0b21fY291bnRpZXMsDQogICAgICAgIHggPSB+cmVvcmRlcihDb3VudHksIFRvdGFsX1BvcHVsYXRpb24pLA0KICAgICAgICB5ID0gflRvdGFsX1BvcHVsYXRpb24sDQogICAgICAgIHR5cGUgPSAnYmFyJywNCiAgICAgICAgbmFtZSA9ICdUb3RhbCBQb3B1bGF0aW9uJywNCiAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICdibHVlJykpICU+JQ0KICANCiAgbGF5b3V0KHRpdGxlID0gJ0JvdHRvbSBMZWFzdCBDb3VudHkgUG9wdWxhdGlvbnMnLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ0NvdW50eScpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ1RvdGFsIFBvcHVsYXRpb24nKSkNCmBgYA0KKipPQlNFUlZBVElPTjoqKg0KPHVsPg0KPGxpPiBMYW11IENvdW50eSBoYXMgdGhlIExvd2VzdCBQb3B1bGF0aW9uIGNvbXBhcmVkIHRvIG90aGVyIGNvdW50aWVzLCBmb2xsb3dlZCBieSBJc2lvbG8gdGhlbiBTYW1idXJ1IGZyb20gdGhlIGJvdHRvbS4NCjwvdWw+DQoNCiMjIyBQb3B1bGF0aW9uIGJ5IEdlbmRlcg0KYGBge3J9DQojIFBpZSBDaGFydCBvZiBNYWxlLCBGZW1hbGUgYW5kIEludGVyc2V4IFBvcHVsYXRpb24gcGVyY2VudGFnZXMNCnBvcF9kYXRhICU+JQ0KICBwbG90X2x5KGxhYmVscyA9IH5jKCJNYWxlIiwgIkZlbWFsZSIsICJJbnRlcnNleCIpLA0KICAgICAgICAgIHZhbHVlcyA9IH5jKHN1bShwb3BfZGF0YSRNYWxlX1BvcHVsYXRpb24pLCBzdW0ocG9wX2RhdGEkRmVtYWxlX1BvcHVsYXRpb24pLCBzdW0ocG9wX2RhdGEkSW50ZXJzZXhfUG9wdWxhdGlvbikpLA0KICAgICAgICAgIHR5cGUgPSAncGllJywNCiAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9ycyA9IGMoImJsdWUiLCAicGluayIsICJyZWQiKSkpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAiUG9wdWxhdGlvbiBEaXN0cmlidXRpb24gYnkgR2VuZGVyIikNCmBgYA0KIyMjIyBUb3RhbCBIb3VzZWhvbGRzIGJ5IFJlZ2lvbg0KYGBge3J9DQojIEJhciBQbG90IG9mIFRvdGFsIFBvcHVsYXRpb24gYnkgUmVnaW9uDQoNCnBsb3RfbHkoZGF0YSA9IHBvcF9kYXRhLA0KICAgICAgICB4ID0gflJlZ2lvbiwNCiAgICAgICAgeSA9IH5Ub3RhbF9Ib3VzZWhvbGQsDQogICAgICAgIHR5cGUgPSAnYmFyJywNCiAgICAgICAgbmFtZSA9ICdUb3RhbCBIb3VzZWhvbGRzIGJ5IFJlZ2lvbicsDQogICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAnYmx1ZScpKSAlPiUNCiAgICBsYXlvdXQodGl0bGUgPSAnVG90YWwgSG91c2Vob2xkcyBieSBSZWdpb24nLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gJ1JlZ2lvbicpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ1RvdGFsIEhvdXNlaG9sZHMgZm9yIFJlZ2lvbicpKQ0KYGBgDQoqKk9CU0VSVkFUSU9OOioqDQo8dWw+DQo8bGk+IFJpZnQgVmFsbGV5IGhhcyB0aGUgSGlnaGVzdCBudW1iZXIgb2YgSG91c2Vob2xkcyB3aGlsZSBOb3J0aCBFYXN0ZXJuIGhhcyB0aGUgbGVhc3QuDQo8L3VsPg0KDQoNCiMjIyBDb21wYXJpc29uIG9mIEdyb3VwIFF1YXJ0ZXJzIGFuZCBDb252ZW50aW9uYWwgSG91c2Vob2xkDQpgYGB7cn0NCiMgUGllIENoYXJ0IG9mIE1hbGUsIEZlbWFsZSBhbmQgSW50ZXJzZXggUG9wdWxhdGlvbiBwZXJjZW50YWdlcw0KDQpwb3BfZGF0YSAlPiUNCiAgcGxvdF9seShsYWJlbHMgPSB+YygiQ29udmVudGlvbmFsX0hvdXNlaG9sZCIsICJHcm91cF9RdWFydGVycyIpLA0KICAgICAgICAgIHZhbHVlcyA9IH5jKHN1bShwb3BfZGF0YSRDb252ZW50aW9uYWxfSG91c2Vob2xkKSwgc3VtKHBvcF9kYXRhJEdyb3VwX1F1YXJ0ZXJzKSksDQogICAgICAgICAgdHlwZSA9ICdwaWUnLA0KICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3JzID0gYygiYmx1ZSIsICJyZWQiKSkpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAiQ29tcGFyaXNvbiBvZiBHcm91cCBRdWFydGVycyBhbmQgQ29udmVudGlvbmFsIEhvdXNlaG9sZCIpDQpgYGANCioqT0JTRVJWQVRJT046KioNCjx1bD4NCjxsaT4gQ29udmVudGlvbmFsIGhvdXNlaG9sZHMgYXJlIG1vcmUgY29tbW9uIHRoYW4gR3JvdXAgUXVhcnRlcnMuDQo8L3VsPg0KDQojIyMgQ29tcGFyaXNvbiBvZiBHcm91cCBRdWFydGVycyBhbmQgQ29udmVudGlvbmFsIEhvdXNlaG9sZCBieSBSZWdpb24NCmBgYHtyfQ0KIyBHcm91cGVkIEJhciBwbG90IHNob3dpbmcgQ29tcGFyaXNvbiBvZiBHcm91cCBRdWFydGVycyBhbmQgQ29udmVudGlvbmFsIEhvdXNlaG9sZCBieSBSZWdpb24NCg0KcGxvdF9seShkYXRhID0gcG9wX2RhdGEsDQogICAgICAgIHggPSB+UmVnaW9uLA0KICAgICAgICB5ID0gfkdyb3VwX1F1YXJ0ZXJzLA0KICAgICAgICB0eXBlID0gJ2JhcicsDQogICAgICAgIG5hbWUgPSAnR3JvdXAgUXVhcnRlcnMnLA0KICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gJ3JlZCcpKSAlPiUNCiAgDQogIGFkZF90cmFjZSh5ID0gfkNvbnZlbnRpb25hbF9Ib3VzZWhvbGQsDQogICAgICAgICAgICBuYW1lID0gJ0NvbnZlbnRpb25hbCBIb3VzZWhvbGQnLA0KICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9ICdibHVlJykpICU+JQ0KICANCiAgbGF5b3V0KHRpdGxlID0gJ0NvbXBhcmlzb24gb2YgR3JvdXAgUXVhcnRlcnMgYW5kIENvbnZlbnRpb25hbCBIb3VzZWhvbGQgYnkgUmVnaW9uJywNCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdSZWdpb24nKSwNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdDb3VudCcpLA0KICAgICAgICAgYmFybW9kZSA9ICdncm91cCcpDQpgYGANCioqT0JTRVJWQVRJT05TOioqDQo8dWw+DQo8bGk+IEFsbCBLZW55YW4gUmVnaW9ucyBoYXZlIGJvdGggQ29udmVudGlvbmFsIEhvdXNlaG9sZHMgYW5kIEdyb3VwIFF1YXJ0ZXJzDQo8bGk+IENvbnZlbnRpb25hbCBIb3VzZWhvbGRzIGFyZSBtb3JlIGNvbW1vbiB0aGF0IEdyb3VwIFF1YXJ0ZXJzDQo8bGk+IFJpZnQgVmFsbGV5IGhhcyB0aGUgSGlnaGVzdCBOdW1iZXIgb2YgYm90aCBDb252ZW50aW9uYWwgSG91c2Vob2xkcyBhbmQgR3JvdXAgUXVhcnRlcnMNCjwvdWw+DQoNCiMjIyBIb3VzZWhvbGQgdnMuIExhbmQgQXJlYQ0KYGBge3J9DQojIFNjYXR0ZXIgUGxvdCBvZiBIb3VzZWhvbGQgdnMuIExhbmQgQXJlYQ0KDQpwbG90X2x5KA0KICBkYXRhID0gcG9wX2RhdGEsDQogIHggPSB+VG90YWxfSG91c2Vob2xkLA0KICB5ID0gfkxhbmRfQXJlYV9TcUttLA0KICBjb2xvciA9IH5SZWdpb24sICAjIFNwZWNpZnkgdGhlIHZhcmlhYmxlIGZvciBjb2xvcmluZw0KICB0eXBlID0gJ3NjYXR0ZXInLA0KICBtb2RlID0gJ21hcmtlcnMnDQopICU+JQ0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAnSG91c2Vob2xkIHZzLiBMYW5kIEFyZWEgYnkgUmVnaW9uJywNCiAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAnVG90YWwgSG91c2Vob2xkJyksDQogICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ0xhbmQgQXJlYSAoU3EgS20pJykNCiAgKQ0KYGBgDQoqKk9CU0VSVkFUSU9OOioqDQo8dWw+DQo8bGk+IE1vc3QgcGFydHMgb2YgS2VueWEgaGF2ZSBsb3cgTGFuZCBhcmVhIGFuZCBsb3cgSG91c2Vob2xkIG51bWJlcnMuDQo8L3VsPg0KDQojIyMgUG9wdWxhdGlvbiBEZW5zaXR5IERpc3RyaWJ1dGlvbg0KYGBge3J9DQojIEhpc3RvZ3JhbSBvZiBQb3B1bGF0aW9uIERlbnNpdHkNCiMgQ2FsY3VsYXRlIGRlbnNpdHkgdmFsdWVzDQpkZW5zaXR5X3ZhbHVlcyA8LSBkZW5zaXR5KHBvcF9kYXRhJERlbnNpdHlfUGVyc29uc19wZXJfU3FLbSkNCg0KIyBDcmVhdGUgdGhlIGNvbWJpbmVkIHBsb3QNCmNvbWJpbmVkX3Bsb3QgPC0gcGxvdF9seSgpICU+JQ0KICBhZGRfaGlzdG9ncmFtKHggPSB+cG9wX2RhdGEkRGVuc2l0eV9QZXJzb25zX3Blcl9TcUttLCBuYmluc3ggPSAyMCwgaGlzdG5vcm0gPSAncHJvYmFiaWxpdHkgZGVuc2l0eScsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAnYmx1ZScsIGxpbmUgPSBsaXN0KGNvbG9yID0gJ2JsYWNrJywgd2lkdGggPSAxKSkpICU+JQ0KICBhZGRfbGluZXMoeCA9IGRlbnNpdHlfdmFsdWVzJHgsIHkgPSBkZW5zaXR5X3ZhbHVlcyR5LCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3IgPSAncmVkJywgd2lkdGggPSAyKSkgJT4lDQogIGxheW91dCh0aXRsZSA9ICdQb3B1bGF0aW9uIERlbnNpdHkgSGlzdG9ncmFtIHdpdGggS0RFJywNCiAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdEZW5zaXR5IChQZXJzb25zIHBlciBTcSBLbSknKSwNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdQcm9iYWJpbGl0eSBEZW5zaXR5JykpDQoNCiMgRGlzcGxheSB0aGUgY29tYmluZWQgcGxvdA0KY29tYmluZWRfcGxvdA0KYGBgDQoqKk9CU0VSVkFUSU9OOioqDQo8dWw+DQo8bGk+TW9zdCBLZW55YW4gYXJlYXMgaGF2ZSByZWxhdGl2ZWx5IGxvdyBwb3B1bGF0aW9uIGRlbnNpdHkgd2l0aCBhIGZldyBleGNlcHRpb25zIHdoZXJlIHBvcHVsYXRpb24gZGVuc2l0eSBpcyBzaWduaWZpY2FudGx5IGhpZ2guDQo8L3VsPg0KDQo8cD48L3A+DQoNCk5hcnJvd2luZyBkb3duIHRvIGNvbXBhcmlzb24gaW4gZGlmZmVyZW50IHJlZ2lvbnMgd2lsbCBoZWxwIGdhdGhlciBtb3JlIGluc2lnaHRzLg0KDQojIyMgUG9wdWxhdGlvbiBEZW5zaXR5IGJ5IFJlZ2lvbg0KYGBge3J9DQojIEJveCBQbG90DQpwbG90X2x5KGRhdGEgPSBwb3BfZGF0YSwgeCA9IH5SZWdpb24sIHkgPSB+RGVuc2l0eV9QZXJzb25zX3Blcl9TcUttLCB0eXBlID0gImJveCIpICU+JQ0KICBsYXlvdXQodGl0bGUgPSAiUG9wdWxhdGlvbiBEZW5zaXR5IGJ5IFJlZ2lvbiIsDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiUmVnaW9uIiksDQogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiRGVuc2l0eSAoUGVyc29ucyBwZXIgU3EgS20pIikpDQpgYGANCioqT0JTRVJWQVRJT046KioNCjx1bD4NCjxsaT5Nb3N0IHJlZ2lvbnMgaGF2ZSByZWxhdGl2ZWx5IGxvdyBkZW5zaXR5IHJhbmdpbmcgZnJvbSAwIHRvIHNsaWdodGx5IGFib3ZlIDEwMDAwMDAgcGVyc29ucyBwZXIgc3F1YXJlIEttIGJ1dCB0aGUgZW50aXJlIE5haXJvYmkgUmVnaW9uIGhhcyB2ZXJ5IGhpZ2ggZGVuc2l0eS4gQ29hc3QgUmVnaW9uIGhhcyBhbiBvdXRsaWVyIHRoYXQgaGFzIHZlcnkgaGlnaCBwb3B1bGF0aW9uIGRlbnNpdHkgb2YgNTQ5NTAwOCBwZXJzb25zIHBlciBTcSBLbS4NCjxMST5JbiBtb3N0IHJlZ2lvbnMsIHRoZSBtZWRpYW4gaXMgY2xvc2VyIHRvIHRoZSBsb3dlciB2YWx1ZXMuIFRoaXMgbWVhbnMgdGhhdCBtb3N0IHZhbHVlcyBhcmUgaW4gdGhlIGxvd2VyIHJhbmdlLiBUaGlzIGVtcGhhc2l6ZXMgdGhlICpsb3cgcG9wdWxhdGlvbiBkZW5zaXR5IGluIG1vc3QgcGFydHMgb2YgS2VueWEuKg0KPC91bD4NCg0KQSB0YWJsZSBzaG93aW5nIGRlbnNpdHkgZm9yIGVhY2ggY291bnR5IGluIGNvYXN0IHJlZ2lvbiB3aWxsIGhlbHAgdW5kZXJzdGFuZCB0aGUgb3V0bGllciBpbiB0aGUgcmVnaW9uIGJldHRlci4NCmBgYHtyfQ0KIyBmaWx0ZXIgY29hc3QgZGF0YSBvbmx5DQpjb2FzdF9kYXRhIDwtIHBvcF9kYXRhW3BvcF9kYXRhJFJlZ2lvbiA9PSAiQ29hc3QiLCBdDQoNCiMgQXNzdW1pbmcgeW91ciBkYXRhIGZyYW1lIGlzIG5hbWVkICdwb3BfZGF0YScNCmNvYXN0X2RhdGEgPC0gcG9wX2RhdGFbcG9wX2RhdGEkUmVnaW9uID09ICJDb2FzdCIsIF0NCg0KIyBDcmVhdGUgYSB0YWJsZSBvZiBkZW5zaXR5IHZhbHVlcw0KY29hc3RfZGVuc2l0eV90YWJsZSA8LSBjb2FzdF9kYXRhICU+JQ0KICBzZWxlY3QoQ291bnR5LCBEZW5zaXR5X1BlcnNvbnNfcGVyX1NxS20pICU+JQ0KICBrYWJsZSgiaHRtbCIsIGNhcHRpb24gPSAiRGVuc2l0eSBWYWx1ZXMgZm9yIENvdW50aWVzIGluIHRoZSBDb2FzdCBSZWdpb24iKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQoNCiMgRGlzcGxheSB0aGUgdGFibGUNCmNvYXN0X2RlbnNpdHlfdGFibGUNCmBgYA0KKipPQlNFUlZBVElPTjoqKg0KPHVsPg0KPGxpPiBGcm9tIHRoZSBjb2FzdCBSZWdpb24sIE1vbWJhc2EgaXMgdGhlIG91dGxpZXIgd2l0aCB2ZXJ5IGhpZ2ggZGVuc2l0eSBjb21wYXJlZCB0byB0aGUgb3RoZXIgYXJlYXMuDQo8L3VsPg0KDQojIEZJTkRJTkdTDQo8dWw+DQo8bGk+IFJpZnQgdmFsbGV5IHJlZ2lvbiBoYXMgdGhlIEhpZ2hlc3QgUG9wdWxhdGlvbiBhbmQgaGlnaGVzdCBudW1iZXIgb2YgSG91c2Vob2xkcy4NCjxwPjwvcD4NCjxsaT4gTm9ydGggRWFzdGVybiByZWdpb24gaGFzIHRoZSBsb3dlc3QgUG9wdWxhdGlvbiBhbmQgbG93ZXN0IG51bWJlciBvZiBIb3VzZWhvbGRzLg0KPHA+PC9wPg0KPGxpPiBNb3N0IEtlbnlhbnMgaWRlbnRpZnkgYXMgbWFsZSBvciBmZW1hbGUuIFdpdGggc2xpZ2h0bHkgbW9yZSBmZW1hbGVzIHRoYW4gbWFsZXMuIEEgdmVyeSBzbWFsbCBwZXJjZW50YWdlKDAuMDAzMiUpIGlkZW50aWZ5IGFzIGludGVyc2V4Lg0KPHA+PC9wPg0KPGxpPiBOYWlyb2JpIENvdW50eSBoYXMgdGhlIEhpZ2hlc3QgUG9wdWxhdGlvbiBjb21wYXJlZCB0byBvdGhlciBjb3VudGllcywgZm9sbG93ZWQgYnkgS2lhbWJ1IHRoZW4gTmFrdXJ1Lg0KPHA+PC9wPg0KPGxpPiBMYW11IENvdW50eSBoYXMgdGhlIExvd2VzdCBQb3B1bGF0aW9uIGNvbXBhcmVkIHRvIG90aGVyIGNvdW50aWVzLCBmb2xsb3dlZCBieSBJc2lvbG8gdGhlbiBTYW1idXJ1IGZyb20gdGhlIGJvdHRvbS4NCjxwPjwvcD4NCjxsaT4gQWxsIEtlbnlhbiBSZWdpb25zIGhhdmUgYm90aCBDb252ZW50aW9uYWwgSG91c2Vob2xkcyBhbmQgR3JvdXAgUXVhcnRlcnMgYnV0IENvbnZlbnRpb25hbCBIb3VzZWhvbGRzIGFyZSBtb3JlIGNvbW1vbiB0aGF0IEdyb3VwIFF1YXJ0ZXJzLg0KPHA+PC9wPg0KPGxpPiBNb3N0IEtlbnlhbiBjb3VudGllcyBoYXZlIHJlbGF0aXZlbHkgbG93IFBvcHVsYXRpb24gRGVuc2l0eSB3aXRoIGFuIGV4Y2VwdGlvbiBvZiBNb21iYXNhIGFuZCBOYWlyb2JpIHdoaWNoIGhhdmUgdmVyeSBIaWdoIFBvcHVsYXRpb24gRGVuc2l0eShQZXJzb25zIHBlciBTcXVhcmUgS2lsb21ldGVyKSBjb21wYXJlZCB0byB0aGUgb3RoZXIgY291bnRpZXMuDQo8L3VsPg0KDQoNCg==