The museum dataset is a list of museums and related organizations in the United States. The data file includes basic information about each organization (name, address, phone, website, and revenue) plus the museum type or discipline.
Data Cleaning and Preparation
In this stage the data is checked for accuracy and completeness prior to beginning the analysis. Some of the issues addressed are as follows:
- Remove extraneous data
- Check for in missing values
- Replace missing values
- Delete data that cannot be corrected/replaced
- Correct any data formatting issues
- Creating new features
- Identify errors revealed when new variables are created
Missing Values
#Identifying total number of missing values
sum(is.na(museum))
[1] 20893
There are a significant number of missing values. Let’s check which columns have missing values
#Identifying total number of missing values
summary(museum)
Museum.ID Legal.Name Museum.Type City..Administrative.Location. State..Administrative.Location.
Min. :8.400e+09 Length:33072 Length:33072 Length:33072 Length:33072
1st Qu.:8.402e+09 Class :character Class :character Class :character Class :character
Median :8.404e+09 Mode :character Mode :character Mode :character Mode :character
Mean :8.404e+09
3rd Qu.:8.405e+09
Max. :8.410e+09
Zip.Code..Administrative.Location. Income Revenue
Length:33072 Min. :-9.230e+02 Min. : -2127393
Class :character 1st Qu.: 0.000e+00 1st Qu.: 0
Mode :character Median : 8.781e+03 Median : 3307
Mean : 1.070e+08 Mean : 20976047
3rd Qu.: 2.164e+05 3rd Qu.: 167696
Max. : 8.318e+10 Max. :5840349457
NA's :10111 NA's :10782
As seen above the Income and Revenue Columns have missing values. These columns also seem to have negative values, which we have to correct. As we do not have a way to accurately replace the missing data we will be dropping the associated rows.
Dropping Rows with Missing Values
#Removing rows with missing data
#The complete.cases() function will examine a dataframe and return a result vector of the rows which contain missing values.
museum <- na.omit(museum)
#Checking for any remaining missing values
sum(is.na(museum))
[1] 0
There are no more missing values.
Duplicate Data
#Number of Museum/Institution Names in the dataframe
length(museum$Legal.Name)
[1] 22250
#Number of unique Museum/Institution Names in the dataframe
length(unique(museum$Legal.Name))
[1] 20276
As we see here, there are clearly some museum names that have been repeated. ### Removing Duplicates
#Keeping only rows with distinct Legal.Name values
museum <- museum %>% distinct(Legal.Name, .keep_all = TRUE)
Exploratory Data Analysis
In this stage, we will examine the data to identify any patterns, trends and relationships between the variables. It will help us analyze the data and extract insights that can be used to make decisions.
Data Visualization will give us a clear idea of what the data means by giving it visual context.
Statistics
To understand the museum data at a high level we can start be looking at income and revenue in more detail
#Calculating average income, total income, average revenue and total revenue
avg_inc = mean(museum$Income)
max_inc = max(museum$Income)
avg_rev = mean(museum$Revenue)
max_rev = max(museum$Revenue)
#Calculating number of museums with zero income and revenue
zero_inc_rev <- museum %>% filter((Income == 0) & (Revenue == 0))
cat('The average museum income:', avg_inc, ' and the highest museum income:', max_inc, '\nThe average museum revenue', avg_rev, ' and the highest revenue:', max_rev, '\nThe number of museums with no income and revenue are:', length(zero_inc_rev))
The average museum income: 18073371 and the highest museum income: 83181439574
The average museum revenue 8011790 and the highest revenue: 5840349457
The number of museums with no income and revenue are: 8
#Number of unique Museum Types, Cities and States
length(unique(museum$Museum.Type))
[1] 9
length(unique(museum$City..Administrative.Location.))
[1] 7236
length(unique(museum$State..Administrative.Location.))
[1] 51
We have museum data for museums of 9 Types, located in 7236 Cities across 51 States.
Grouping Museum Data by Type, City and State
We can create a few functions to help us aggregate the museum data and
#Creating a function to create a dataframe with aggregate data
museum_group <- function(col_name) {
#Grouping by col_name
group_name <- museum %>% group_by(.dots = col_name)
#Creating a data frame to store the summarized values of museums by col_name
#tally() gives us a count of how many museums belong to the category
museum_group_name <- group_name %>% tally()
#Renaming the columns
colnames(museum_group_name)[which(names(museum_group_name) == "n")] <- "Museum_Count"
#Summarizing by average income
group_name_average_income <- group_name %>% summarise(Income = mean(Income))
museum_group_name$Average_Income<- group_name_average_income$Income
#Summarizing by total income
group_name_total_income <- group_name %>% summarise(Income = sum(Income))
museum_group_name$Total_Income<- group_name_total_income$Income
#Summarizing by average revenue
group_name_average_revenue <- group_name %>% summarise(Revenue = mean(Revenue))
museum_group_name$Average_Revenue<- group_name_average_revenue$Revenue
#Summarizing by total revenue
group_name_total_revenue <- group_name %>% summarise(Revenue = sum(Revenue))
museum_group_name$Total_Revenue<- group_name_total_revenue$Revenue
#Returning a dataframe
return (museum_group_name)
}
#Creating a function to output maximum values from the dataframe with aggregate data
museum_group_max <- function(df,col_name) {
avg_inc_max <- df %>% filter(Average_Income == max(df$Average_Income))
tot_inc_max <- df %>% filter(Total_Income == max(df$Total_Income))
avg_rev_max <- df %>% filter(Average_Revenue == max(df$Average_Revenue))
tot_rev_max <- df %>% filter(Total_Revenue == max(df$Total_Revenue))
#Calculating the highest museum count and associated col_name value
count_max <- df %>% filter(Museum_Count == max(df$Museum_Count))
return (cat('Museum Types with highest average income:', avg_inc_max[[col_name]], ' highest total income:', tot_inc_max[[col_name]], '\nhighest average revenue', avg_rev_max[[col_name]], ' highest total revenue:',tot_rev_max[[col_name]], '\n\n', count_max[[col_name]], 'which has',count_max$Museum_Count, ' museums, has the most museums.'))
}
#Creating a function to output minimum values from the dataframe with aggregate data
museum_group_min <- function(df,col_name) {
avg_inc_min <- df %>% filter(Average_Income == min(df$Average_Income))
tot_inc_min <- df %>% filter(Total_Income == min(df$Total_Income))
avg_rev_min <- df %>% filter(Average_Revenue == min(df$Average_Revenue))
tot_rev_min <- df %>% filter(Total_Revenue == min(df$Total_Revenue))
#Calculating the lowest museum count and associated col_name value
count_min <- df %>% filter(Museum_Count == min(df$Museum_Count))
return (cat('\n\nMuseums with lowest average income:', avg_inc_min[[col_name]], ' lowest total income:', tot_inc_min[[col_name]], '\nlowest average revenue',avg_rev_min[[col_name]], ' lowest total revenue:', tot_rev_min[[col_name]],'\n\n', count_min[[col_name]], 'which has',count_min$Museum_Count, ' museums, has the least museums.'))
}
Type
To understand the museum data better we can group the data by Type and take a look at the average and total Income and Revenue.
#Grouping by type
museum_type <- museum_group('Museum.Type')
Warning: The `.dots` argument of `group_by()` is deprecated as of dplyr 1.0.0.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.
#Renaming the column
colnames(museum_type)[which(names(museum_type) == "Museum.Type")] <- "Type"
head(museum_type)
NA
museum_group_max(museum_type,'Type')
Museum Types with highest average income: SCIENCE & TECHNOLOGY MUSEUM OR PLANETARIUM highest total income: ART MUSEUM
highest average revenue ART MUSEUM highest total revenue: ART MUSEUM
HISTORIC PRESERVATION which has 11340 museums, has the most museums.
museum_group_min(museum_type,'Type')
Museums with lowest average income: HISTORIC PRESERVATION lowest total income: CHILDREN'S MUSEUM
lowest average revenue HISTORIC PRESERVATION lowest total revenue: CHILDREN'S MUSEUM
NATURAL HISTORY MUSEUM which has 205 museums, has the least museums.
- Science & Technology Museums/Planetariums have the highest average income.
- Art Museums have the highest total income, average revenue and total revenue.
- Historic Preservations have the lowest average income and average revenue, and this museum type has the most museums as well.
- Children’s Museums have the lowest total income and total revenue.
- Natural History Museums have the least museums among all museum types.
#plotting bar graph for museum type and number of Museums
ggplot(data=museum_type,aes(x=Type,y=Museum_Count, fill=Type)) + geom_bar(stat="identity") + labs(title="Number of Museums by Type")+ theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank())

Total Income by Museum Type
#Creating a Pie Chart
type_income = museum_type$Total_Income
type_labels = museum_type$Type
# Plot the chart.
pie(type_income, labels=type_labels, main = "Distribution of Total Income by Museum Type",col = rainbow(length(type_income)))

As seen above Art Museums make up the biggest portion of all museum income in the US, while Children’s Museums make up the smallest portion of all museum income in the US. We can check to see if a similar pattern is observed with revenue.
Total Revenue by Museum Type
#Creating a Pie Chart
type_revenue = museum_type$Total_Revenue
type_labels = museum_type$Type
# Plot the chart.
pie(type_revenue, labels=type_labels, main = "Distribution of Total Revenue by Museum Type",col = rainbow(length(type_revenue)))

Once again Art Museums make up the biggest portion of all museum revenue in the US, while Children’s Museums make up the smallest portion of all museum revenue in the US. For the museum data the revenue always lower than income so we could assume that the revenue is what the museum is left over with after deducting taxes and other expenses.
- It it noteworthy that the Art Museum’s revenue makes up a bigger portion of all museum revenue.
- The Art Museum’s is retaining a larger portion of its income as opposed to the other museum types.
- If this were not the case then we would expect the distribution to be similar to that of income.
City
We can group the data by City as well and take a look at the average and total Income and Revenue.
#Grouping by city
museum_city <- museum_group('City..Administrative.Location.')
#Renaming the column
colnames(museum_city)[which(names(museum_city) == "City..Administrative.Location.")] <- "City"
head(museum_city)
museum_group_max(museum_city,'City')
Museum Types with highest average income: AMADO highest total income: AMADO
highest average revenue AMADO highest total revenue: WASHINGTON
NEW YORK which has 172 museums, has the most museums.
- Amado has the highest average income, average revenue and total income.
- Washington has the highest total revenue.
- New York City has the most museums.
Number of Museums vs. Total Income
#plotting scatter plot for number of museums vs. total income from museums in each city
ggplot(data=museum_city,aes(x=Museum_Count,y=Total_Income)) + geom_point() + labs(title="City Level Data: Number of Museums vs. Total Income") + gghighlight(Total_Income > 10000000000)

As seen above the vast majority of cities make under 10 Billion in income from museums.
Number of Museums vs. Total Revenue
#plotting scatter plot for number of museums vs. total income from museums in each state
ggplot(data=museum_city,aes(x=Museum_Count,y=Total_Revenue)) + geom_point() + labs(title="City Level Data: Number of Museums vs. Total Revenue") + gghighlight(Total_Revenue > 2000000000)

As seen above the vast majority of cities make under 2 Billion in revenue from museums.
State
We can group the data by State as well and take a look at the average and total Income and Revenue.
#Grouping by state
museum_state <- museum_group('State..Administrative.Location.')
#Renaming the column
colnames(museum_state)[which(names(museum_state) == "State..Administrative.Location.")] <- "State"
head(museum_state)
museum_group_max(museum_state,'State')
Museum Types with highest average income: AZ highest total income: AZ
highest average revenue DC highest total revenue: CA
CA which has 1596 museums, has the most museums.
museum_group_min(museum_state,'State')
Museums with lowest average income: ND lowest total income: ND
lowest average revenue ND lowest total revenue: ND
UT which has 63 museums, has the least museums.
- Arizona (AZ) has the highest average and total income.
- Washington DC (DC) has the highest average revenue.
- California (CA) has the highest total revenue and and also the most museums.
- North Dakota (ND) has the lowest average and total income and revenue.
- Utah (UT) has the least museums.
Number of Museums vs. Total Income
#plotting scatter plot for number of museums vs. total income from museums in each state
ggplot(data=museum_state,aes(x=Museum_Count,y=Total_Income)) + geom_point() + labs(title="State Level Data: Number of Museums vs. Total Income") + gghighlight(Total_Income > 10000000000)

Similar to the city level data, the majority of states make under 10 Billion in income from museums.
Number of Museums vs. Total Revenue
#plotting scatter plot for number of museums vs. total income from museums in each state
ggplot(data=museum_state,aes(x=Museum_Count,y=Total_Revenue)) + geom_point() + labs(title="State Level Data: Number of Museums vs. Total Revenue") + gghighlight(Total_Revenue > 5000000000)

The majority of states make under 5 Billion in revenue from museums.
LS0tCnRpdGxlOiAiTXVzZXVtcyBEYXRhIEFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCkFuYWx5c2lzIG9mIGEgcHVibGljIFVuaXRlZCBTdGF0ZXMgTXVzZXVtcyBkYXRhc2V0IGZyb20gS2FnZ2xlOiBodHRwczovL3d3dy5rYWdnbGUuY29tL2ltbHMvbXVzZXVtLWRpcmVjdG9yeQoKVGhlIG11c2V1bSBkYXRhc2V0IGlzIGEgbGlzdCBvZiBtdXNldW1zIGFuZCByZWxhdGVkIG9yZ2FuaXphdGlvbnMgaW4gdGhlIFVuaXRlZCBTdGF0ZXMuIFRoZSBkYXRhIGZpbGUgaW5jbHVkZXMgYmFzaWMgaW5mb3JtYXRpb24gYWJvdXQgZWFjaCBvcmdhbml6YXRpb24gKG5hbWUsIGFkZHJlc3MsIHBob25lLCB3ZWJzaXRlLCBhbmQgcmV2ZW51ZSkgcGx1cyB0aGUgbXVzZXVtIHR5cGUgb3IgZGlzY2lwbGluZS4gCgpXZSBhcmUgaW50ZXJlc3RlZCBpbiBleHRyYWN0aW5nIHNvbWUgaW5zaWdodHMgYWJvdXQgbXVzZXVtcyBpbiB0aGUgVVMsIHN1Y2ggYXMgCgotIFdoaWNoIGNpdHkgb3Igc3RhdGUgaGFzIHRoZSBtb3N0IG11c2V1bXMgcGVyIGNhcGl0YT8gCi0gSG93IG1hbnkgem9vcyBvciBhcXVhcml1bXMgZXhpc3QgaW4gdGhlIFVuaXRlZCBTdGF0ZXM/IAotIFdoYXQgbXVzZXVtIG9yIHJlbGF0ZWQgb3JnYW5pemF0aW9uIGhhZCB0aGUgaGlnaGVzdCByZXZlbnVlIGxhc3QgeWVhcj8KLSBIb3cgZG9lcyB0aGUgY29tcG9zaXRpb24gb2YgbXVzZXVtIHR5cGVzIGRpZmZlciBhY3Jvc3MgdGhlIGNvdW50cnk/CgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2doaWdobGlnaHQpCgojSW1wb3J0aW5nIHRoZSBjc3YgZmlsZSB0byBhIGJvb2tzIERhdGEgRnJhbWUKbXVzZXVtX2RhdGEgPC0gcmVhZC5jc3YoIm11c2V1bXMuY3N2IikKCiNWaWV3aW5nIHRoZSBEYXRhIEZyYW1lCmhlYWQobXVzZXVtX2RhdGEgKQpgYGAKIyBEYXRhIENsZWFuaW5nIGFuZCBQcmVwYXJhdGlvbgpJbiB0aGlzIHN0YWdlIHRoZSBkYXRhIGlzIGNoZWNrZWQgZm9yIGFjY3VyYWN5IGFuZCBjb21wbGV0ZW5lc3MgcHJpb3IgdG8gYmVnaW5uaW5nIHRoZSBhbmFseXNpcy4gU29tZSBvZiB0aGUgaXNzdWVzIGFkZHJlc3NlZCBhcmUgYXMgZm9sbG93czoKCi0gUmVtb3ZlIGV4dHJhbmVvdXMgZGF0YQotIENoZWNrIGZvciBpbiBtaXNzaW5nIHZhbHVlcwotIFJlcGxhY2UgbWlzc2luZyB2YWx1ZXMKLSBEZWxldGUgZGF0YSB0aGF0IGNhbm5vdCBiZSBjb3JyZWN0ZWQvcmVwbGFjZWQKLSBDb3JyZWN0IGFueSBkYXRhIGZvcm1hdHRpbmcgaXNzdWVzCi0gQ3JlYXRpbmcgbmV3IGZlYXR1cmVzCi0gSWRlbnRpZnkgZXJyb3JzIHJldmVhbGVkIHdoZW4gbmV3IHZhcmlhYmxlcyBhcmUgY3JlYXRlZAoKIyMgUmVtb3ZlIEV4dHJhbmVvdXMgRGF0YQoKYGBge3J9CiNJZGVudGlmeWluZyB0aGUgY29sdW1uIG5hbWVzCmNvbG5hbWVzKG11c2V1bV9kYXRhKQpgYGAKVGhlcmUgYXJlIGEgbG90IG9mIGNvbHVtbnMgaW4gdGhlIGRhdGFmcmFtZSwgaG93ZXZlciBub3QgYWxsIG9mIHRoZW0gYXJlIHVzZWZ1bC4gVGhlcmVmb3JlLCB3ZSB3aWxsIG9ubHkgc2VsZWN0IGEgc3Vic2V0IG9mIHRoZSBkYXRhZnJhbWUgY29udGFpbmluZyB0aGUgY29sdW1ucyB3ZSBhcmUgaW50ZXJlc3RlZCBpbi4KCmBgYHtyfQojQ3JlYXRpbmcgYSBjaGFyYWN0ZXIgdmVjdG9yIHdpdGggYWxsIHRoZSBjb2x1bW5zIG5hbWVzIHdlIGFyZSBpbnRlcmVzdGVkIGluCmtlZXBfY29sIDwtIGMoIk11c2V1bS5JRCIsIkxlZ2FsLk5hbWUiLCJNdXNldW0uVHlwZSIsIkNpdHkuLkFkbWluaXN0cmF0aXZlLkxvY2F0aW9uLiIsIlN0YXRlLi5BZG1pbmlzdHJhdGl2ZS5Mb2NhdGlvbi4iLCJaaXAuQ29kZS4uQWRtaW5pc3RyYXRpdmUuTG9jYXRpb24uIiwiSW5jb21lIiwiUmV2ZW51ZSIgICApCgptdXNldW0gPC1tdXNldW1fZGF0YVtrZWVwX2NvbF0KCmhlYWQobXVzZXVtKQpgYGAKCiMjIE1pc3NpbmcgVmFsdWVzCmBgYHtyfQojSWRlbnRpZnlpbmcgdG90YWwgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzCnN1bShpcy5uYShtdXNldW0pKQpgYGAKVGhlcmUgYXJlIGEgc2lnbmlmaWNhbnQgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzLiBMZXQncyBjaGVjayB3aGljaCBjb2x1bW5zIGhhdmUgbWlzc2luZyB2YWx1ZXMgCmBgYHtyfQojSWRlbnRpZnlpbmcgdG90YWwgbnVtYmVyIG9mIG1pc3NpbmcgdmFsdWVzCnN1bW1hcnkobXVzZXVtKQpgYGAKCkFzIHNlZW4gYWJvdmUgdGhlIEluY29tZSBhbmQgUmV2ZW51ZSBDb2x1bW5zIGhhdmUgbWlzc2luZyB2YWx1ZXMuIFRoZXNlIGNvbHVtbnMgYWxzbyBzZWVtIHRvIGhhdmUgbmVnYXRpdmUgdmFsdWVzLCB3aGljaCB3ZSBoYXZlIHRvIGNvcnJlY3QuIEFzIHdlIGRvIG5vdCBoYXZlIGEgd2F5IHRvIGFjY3VyYXRlbHkgcmVwbGFjZSB0aGUgbWlzc2luZyBkYXRhIHdlIHdpbGwgYmUgZHJvcHBpbmcgdGhlIGFzc29jaWF0ZWQgcm93cy4gCgojIyMgRHJvcHBpbmcgUm93cyB3aXRoIE1pc3NpbmcgVmFsdWVzCmBgYHtyfQojUmVtb3Zpbmcgcm93cyB3aXRoIG1pc3NpbmcgZGF0YQojVGhlIGNvbXBsZXRlLmNhc2VzKCkgZnVuY3Rpb24gd2lsbCBleGFtaW5lIGEgZGF0YWZyYW1lIGFuZCByZXR1cm4gYSByZXN1bHQgdmVjdG9yIG9mIHRoZSByb3dzIHdoaWNoIGNvbnRhaW4gbWlzc2luZyB2YWx1ZXMuCm11c2V1bSA8LSBuYS5vbWl0KG11c2V1bSkKCiNDaGVja2luZyBmb3IgYW55IHJlbWFpbmluZyBtaXNzaW5nIHZhbHVlcwpzdW0oaXMubmEobXVzZXVtKSkKYGBgClRoZXJlIGFyZSBubyBtb3JlIG1pc3NpbmcgdmFsdWVzLgoKIyMgQ29ycmVjdGluZyBGb3JtYXR0aW5nIElzc3VlcwpJbmNvbWUgYW5kIFJldmVudWUgQ29sdW1ucyBoYXZlIG5lZ2F0aXZlIHZhbHVlcy4gVGhlIG5lZ2F0aXZlIHZhbHVlcyBjb3VsZCByZXByZXNlbnQgdHdvIHNjZW5hcmlvczoKCi0gTXVzZXVtcyBhcmUgb3BlcmF0aW5nIGF0IGEgbG9zcywgd2hpY2ggYWNjb3VudHMgZm9yIHRoZSBuZWdhdGl2ZSBpbmNvbWUgYW5kIG5lZ2F0aXZlIHJldmVudWUuCi0gRXJyb3IgaW4gdGhlIGRhdGEgaW5wdXQgcHJvY2VzcyB3aGljaCByZXN1bHRlZCBpbiBhIG5lZ2F0aXZlIHZhbHVlIGJlaW5nIGVudGVyZWQuIAoKSW4gdGhlIGFic2VuY2Ugb2Ygc3BlY2lmaWMgY29udGV4dCwgd2UgZG8gbm90IGtub3cgaG93IG9yIGlmIHRoZXNlIHZhbHVlcyBuZWVkIHRvIGJlIGNvcnJlY3RlZC4gVGhlcmVmb3JlLCB3ZSB3aWxsIGFzc3VtZSB0aGF0IHRoZXNlIG5lZ2F0aXZlIHZhbHVlcyByZXByZXNlbnQgaW5hY2N1cmF0ZSBlbnRyaWVzIGFuZCB3ZSB3aWxsIGJlIGRyb3BwaW5nIHRoZXNlIHZhbHVlcy4gCgpgYGB7cn0KI1JlbW92aW5nIGFsbCByb3dzIHdpdGggaW5jb21lIGFuZCByZXZlbnVlIGxlc3MgdGhhbiAwCm11c2V1bSA8LSBtdXNldW0gJT4lIGZpbHRlcigoSW5jb21lID49IDApICYgKFJldmVudWUgPj0gMCkpCmBgYAoKCiMjIER1cGxpY2F0ZSBEYXRhIApgYGB7cn0KI051bWJlciBvZiBNdXNldW0vSW5zdGl0dXRpb24gTmFtZXMgaW4gdGhlIGRhdGFmcmFtZQpsZW5ndGgobXVzZXVtJExlZ2FsLk5hbWUpCiNOdW1iZXIgb2YgdW5pcXVlIE11c2V1bS9JbnN0aXR1dGlvbiBOYW1lcyBpbiB0aGUgZGF0YWZyYW1lCmxlbmd0aCh1bmlxdWUobXVzZXVtJExlZ2FsLk5hbWUpKQoKYGBgCgpBcyB3ZSBzZWUgaGVyZSwgdGhlcmUgYXJlIGNsZWFybHkgc29tZSBtdXNldW0gbmFtZXMgdGhhdCBoYXZlIGJlZW4gcmVwZWF0ZWQuCiMjIyBSZW1vdmluZyBEdXBsaWNhdGVzIApgYGB7cn0KI0tlZXBpbmcgb25seSByb3dzIHdpdGggZGlzdGluY3QgTGVnYWwuTmFtZSB2YWx1ZXMKbXVzZXVtIDwtIG11c2V1bSAlPiUgZGlzdGluY3QoTGVnYWwuTmFtZSwgLmtlZXBfYWxsID0gVFJVRSkKYGBgCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMKSW4gdGhpcyBzdGFnZSwgd2Ugd2lsbCBleGFtaW5lIHRoZSBkYXRhIHRvIGlkZW50aWZ5IGFueSBwYXR0ZXJucywgdHJlbmRzIGFuZCByZWxhdGlvbnNoaXBzIGJldHdlZW4gdGhlIHZhcmlhYmxlcy4gSXQgd2lsbCBoZWxwIHVzIGFuYWx5emUgdGhlIGRhdGEgYW5kIGV4dHJhY3QgaW5zaWdodHMgdGhhdCBjYW4gYmUgdXNlZCB0byBtYWtlIGRlY2lzaW9ucy4KCkRhdGEgVmlzdWFsaXphdGlvbiB3aWxsIGdpdmUgdXMgYSBjbGVhciBpZGVhIG9mIHdoYXQgdGhlIGRhdGEgbWVhbnMgYnkgZ2l2aW5nIGl0IHZpc3VhbCBjb250ZXh0LgoKIyMgU3RhdGlzdGljcwpUbyB1bmRlcnN0YW5kIHRoZSBtdXNldW0gZGF0YSBhdCBhIGhpZ2ggbGV2ZWwgd2UgY2FuIHN0YXJ0IGJlIGxvb2tpbmcgYXQgaW5jb21lIGFuZCByZXZlbnVlIGluIG1vcmUgZGV0YWlsCmBgYHtyfQojQ2FsY3VsYXRpbmcgYXZlcmFnZSBpbmNvbWUsIHRvdGFsIGluY29tZSwgYXZlcmFnZSByZXZlbnVlIGFuZCB0b3RhbCByZXZlbnVlCmF2Z19pbmMgPSBtZWFuKG11c2V1bSRJbmNvbWUpIAptYXhfaW5jID0gbWF4KG11c2V1bSRJbmNvbWUpIAphdmdfcmV2ID0gbWVhbihtdXNldW0kUmV2ZW51ZSkgCm1heF9yZXYgPSBtYXgobXVzZXVtJFJldmVudWUpIAoKI0NhbGN1bGF0aW5nIG51bWJlciBvZiBtdXNldW1zIHdpdGggemVybyBpbmNvbWUgYW5kIHJldmVudWUKemVyb19pbmNfcmV2IDwtIG11c2V1bSAlPiUgZmlsdGVyKChJbmNvbWUgPT0gMCkgJiAoUmV2ZW51ZSA9PSAwKSkKCmNhdCgnVGhlIGF2ZXJhZ2UgbXVzZXVtIGluY29tZTonLCBhdmdfaW5jLCAnIGFuZCB0aGUgaGlnaGVzdCBtdXNldW0gaW5jb21lOicsIG1heF9pbmMsICdcblRoZSBhdmVyYWdlIG11c2V1bSByZXZlbnVlJywgYXZnX3JldiwgJyBhbmQgdGhlIGhpZ2hlc3QgcmV2ZW51ZTonLCBtYXhfcmV2LCAnXG5UaGUgbnVtYmVyIG9mIG11c2V1bXMgd2l0aCBubyBpbmNvbWUgYW5kIHJldmVudWUgYXJlOicsIGxlbmd0aCh6ZXJvX2luY19yZXYpKQpgYGAKYGBge3J9CiNOdW1iZXIgb2YgdW5pcXVlIE11c2V1bSBUeXBlcywgQ2l0aWVzIGFuZCBTdGF0ZXMKbGVuZ3RoKHVuaXF1ZShtdXNldW0kTXVzZXVtLlR5cGUpKQpsZW5ndGgodW5pcXVlKG11c2V1bSRDaXR5Li5BZG1pbmlzdHJhdGl2ZS5Mb2NhdGlvbi4pKQpsZW5ndGgodW5pcXVlKG11c2V1bSRTdGF0ZS4uQWRtaW5pc3RyYXRpdmUuTG9jYXRpb24uKSkKYGBgCldlIGhhdmUgbXVzZXVtIGRhdGEgZm9yIG11c2V1bXMgb2YgPGI+OSBUeXBlczwvYj4sIGxvY2F0ZWQgaW4gPGI+NzIzNiBDaXRpZXM8L2I+IGFjcm9zcyA8Yj41MSBTdGF0ZXM8L2I+LgoKIyMjIEdyb3VwaW5nIE11c2V1bSBEYXRhIGJ5IFR5cGUsIENpdHkgYW5kIFN0YXRlCldlIGNhbiBjcmVhdGUgYSBmZXcgZnVuY3Rpb25zIHRvIGhlbHAgdXMgYWdncmVnYXRlIHRoZSBtdXNldW0gZGF0YSBhbmQgCmBgYHtyfQojQ3JlYXRpbmcgYSBmdW5jdGlvbiB0byBjcmVhdGUgYSBkYXRhZnJhbWUgd2l0aCBhZ2dyZWdhdGUgZGF0YQptdXNldW1fZ3JvdXAgPC0gZnVuY3Rpb24oY29sX25hbWUpIHsKICAKICAjR3JvdXBpbmcgYnkgY29sX25hbWUKICBncm91cF9uYW1lIDwtIG11c2V1bSAlPiUgZ3JvdXBfYnkoLmRvdHMgPSBjb2xfbmFtZSkKICAKICAjQ3JlYXRpbmcgYSBkYXRhIGZyYW1lIHRvIHN0b3JlIHRoZSBzdW1tYXJpemVkIHZhbHVlcyBvZiBtdXNldW1zIGJ5IGNvbF9uYW1lCiAgI3RhbGx5KCkgZ2l2ZXMgdXMgYSBjb3VudCBvZiBob3cgbWFueSBtdXNldW1zIGJlbG9uZyB0byB0aGUgY2F0ZWdvcnkKICBtdXNldW1fZ3JvdXBfbmFtZSA8LSBncm91cF9uYW1lICU+JSB0YWxseSgpCiAgCiAgI1JlbmFtaW5nIHRoZSBjb2x1bW5zCiAgY29sbmFtZXMobXVzZXVtX2dyb3VwX25hbWUpW3doaWNoKG5hbWVzKG11c2V1bV9ncm91cF9uYW1lKSA9PSAibiIpXSA8LSAiTXVzZXVtX0NvdW50IgogIAogICNTdW1tYXJpemluZyBieSBhdmVyYWdlIGluY29tZQogIGdyb3VwX25hbWVfYXZlcmFnZV9pbmNvbWUgPC0gZ3JvdXBfbmFtZSAlPiUgc3VtbWFyaXNlKEluY29tZSA9IG1lYW4oSW5jb21lKSkKICBtdXNldW1fZ3JvdXBfbmFtZSRBdmVyYWdlX0luY29tZTwtIGdyb3VwX25hbWVfYXZlcmFnZV9pbmNvbWUkSW5jb21lCiAgCiAgI1N1bW1hcml6aW5nIGJ5IHRvdGFsIGluY29tZQogIGdyb3VwX25hbWVfdG90YWxfaW5jb21lIDwtIGdyb3VwX25hbWUgJT4lIHN1bW1hcmlzZShJbmNvbWUgPSBzdW0oSW5jb21lKSkKICBtdXNldW1fZ3JvdXBfbmFtZSRUb3RhbF9JbmNvbWU8LSBncm91cF9uYW1lX3RvdGFsX2luY29tZSRJbmNvbWUKICAKICAjU3VtbWFyaXppbmcgYnkgYXZlcmFnZSByZXZlbnVlCiAgZ3JvdXBfbmFtZV9hdmVyYWdlX3JldmVudWUgPC0gZ3JvdXBfbmFtZSAlPiUgc3VtbWFyaXNlKFJldmVudWUgPSBtZWFuKFJldmVudWUpKQogIG11c2V1bV9ncm91cF9uYW1lJEF2ZXJhZ2VfUmV2ZW51ZTwtIGdyb3VwX25hbWVfYXZlcmFnZV9yZXZlbnVlJFJldmVudWUKICAKICAjU3VtbWFyaXppbmcgYnkgdG90YWwgcmV2ZW51ZQogIGdyb3VwX25hbWVfdG90YWxfcmV2ZW51ZSA8LSBncm91cF9uYW1lICU+JSBzdW1tYXJpc2UoUmV2ZW51ZSA9IHN1bShSZXZlbnVlKSkKICBtdXNldW1fZ3JvdXBfbmFtZSRUb3RhbF9SZXZlbnVlPC0gZ3JvdXBfbmFtZV90b3RhbF9yZXZlbnVlJFJldmVudWUKICAKICAjUmV0dXJuaW5nIGEgZGF0YWZyYW1lCiAgcmV0dXJuIChtdXNldW1fZ3JvdXBfbmFtZSkKfQoKI0NyZWF0aW5nIGEgZnVuY3Rpb24gdG8gb3V0cHV0IG1heGltdW0gdmFsdWVzIGZyb20gdGhlIGRhdGFmcmFtZSB3aXRoIGFnZ3JlZ2F0ZSBkYXRhCm11c2V1bV9ncm91cF9tYXggPC0gZnVuY3Rpb24oZGYsY29sX25hbWUpIHsKICAgIAogIGF2Z19pbmNfbWF4IDwtIGRmICU+JSBmaWx0ZXIoQXZlcmFnZV9JbmNvbWUgPT0gbWF4KGRmJEF2ZXJhZ2VfSW5jb21lKSkKICB0b3RfaW5jX21heCA8LSBkZiAlPiUgZmlsdGVyKFRvdGFsX0luY29tZSA9PSBtYXgoZGYkVG90YWxfSW5jb21lKSkKICBhdmdfcmV2X21heCA8LSBkZiAlPiUgZmlsdGVyKEF2ZXJhZ2VfUmV2ZW51ZSA9PSBtYXgoZGYkQXZlcmFnZV9SZXZlbnVlKSkKICB0b3RfcmV2X21heCA8LSBkZiAlPiUgZmlsdGVyKFRvdGFsX1JldmVudWUgPT0gbWF4KGRmJFRvdGFsX1JldmVudWUpKQogIAogICNDYWxjdWxhdGluZyB0aGUgaGlnaGVzdCBtdXNldW0gY291bnQgYW5kIGFzc29jaWF0ZWQgY29sX25hbWUgdmFsdWUKICBjb3VudF9tYXggPC0gZGYgJT4lIGZpbHRlcihNdXNldW1fQ291bnQgPT0gbWF4KGRmJE11c2V1bV9Db3VudCkpCiAgCiAgcmV0dXJuIChjYXQoJ011c2V1bSBUeXBlcyB3aXRoIGhpZ2hlc3QgYXZlcmFnZSBpbmNvbWU6JywgYXZnX2luY19tYXhbW2NvbF9uYW1lXV0sICcgaGlnaGVzdCB0b3RhbCBpbmNvbWU6JywgdG90X2luY19tYXhbW2NvbF9uYW1lXV0sICdcbmhpZ2hlc3QgYXZlcmFnZSByZXZlbnVlJywgYXZnX3Jldl9tYXhbW2NvbF9uYW1lXV0sICcgaGlnaGVzdCB0b3RhbCByZXZlbnVlOicsdG90X3Jldl9tYXhbW2NvbF9uYW1lXV0sICdcblxuJywgY291bnRfbWF4W1tjb2xfbmFtZV1dLCAnd2hpY2ggaGFzJyxjb3VudF9tYXgkTXVzZXVtX0NvdW50LCAnIG11c2V1bXMsIGhhcyB0aGUgbW9zdCBtdXNldW1zLicpKQp9CgojQ3JlYXRpbmcgYSBmdW5jdGlvbiB0byBvdXRwdXQgbWluaW11bSB2YWx1ZXMgZnJvbSB0aGUgZGF0YWZyYW1lIHdpdGggYWdncmVnYXRlIGRhdGEKbXVzZXVtX2dyb3VwX21pbiA8LSBmdW5jdGlvbihkZixjb2xfbmFtZSkgewoKICBhdmdfaW5jX21pbiA8LSBkZiAlPiUgZmlsdGVyKEF2ZXJhZ2VfSW5jb21lID09IG1pbihkZiRBdmVyYWdlX0luY29tZSkpCiAgdG90X2luY19taW4gPC0gZGYgJT4lIGZpbHRlcihUb3RhbF9JbmNvbWUgPT0gbWluKGRmJFRvdGFsX0luY29tZSkpCiAgYXZnX3Jldl9taW4gPC0gZGYgJT4lIGZpbHRlcihBdmVyYWdlX1JldmVudWUgPT0gbWluKGRmJEF2ZXJhZ2VfUmV2ZW51ZSkpCiAgdG90X3Jldl9taW4gPC0gZGYgJT4lIGZpbHRlcihUb3RhbF9SZXZlbnVlID09IG1pbihkZiRUb3RhbF9SZXZlbnVlKSkKCiAgI0NhbGN1bGF0aW5nIHRoZSBsb3dlc3QgbXVzZXVtIGNvdW50IGFuZCBhc3NvY2lhdGVkIGNvbF9uYW1lIHZhbHVlCiAgY291bnRfbWluIDwtIGRmICU+JSBmaWx0ZXIoTXVzZXVtX0NvdW50ID09IG1pbihkZiRNdXNldW1fQ291bnQpKQogIAogIHJldHVybiAoY2F0KCdcblxuTXVzZXVtcyB3aXRoIGxvd2VzdCBhdmVyYWdlIGluY29tZTonLCBhdmdfaW5jX21pbltbY29sX25hbWVdXSwgJyBsb3dlc3QgdG90YWwgaW5jb21lOicsIHRvdF9pbmNfbWluW1tjb2xfbmFtZV1dLCAnXG5sb3dlc3QgYXZlcmFnZSByZXZlbnVlJyxhdmdfcmV2X21pbltbY29sX25hbWVdXSwgJyBsb3dlc3QgdG90YWwgcmV2ZW51ZTonLCB0b3RfcmV2X21pbltbY29sX25hbWVdXSwnXG5cbicsIGNvdW50X21pbltbY29sX25hbWVdXSwgJ3doaWNoIGhhcycsY291bnRfbWluJE11c2V1bV9Db3VudCwgJyBtdXNldW1zLCBoYXMgdGhlIGxlYXN0IG11c2V1bXMuJykpCn0KYGBgCgojIyBUeXBlClRvIHVuZGVyc3RhbmQgdGhlIG11c2V1bSBkYXRhIGJldHRlciB3ZSBjYW4gZ3JvdXAgdGhlIGRhdGEgYnkgVHlwZSBhbmQgdGFrZSBhIGxvb2sgYXQgdGhlIGF2ZXJhZ2UgYW5kIHRvdGFsIEluY29tZSBhbmQgUmV2ZW51ZS4KYGBge3J9CiNHcm91cGluZyBieSB0eXBlCm11c2V1bV90eXBlIDwtIG11c2V1bV9ncm91cCgnTXVzZXVtLlR5cGUnKQoKI1JlbmFtaW5nIHRoZSBjb2x1bW4KY29sbmFtZXMobXVzZXVtX3R5cGUpW3doaWNoKG5hbWVzKG11c2V1bV90eXBlKSA9PSAiTXVzZXVtLlR5cGUiKV0gPC0gIlR5cGUiCgpoZWFkKG11c2V1bV90eXBlKQoKYGBgCmBgYHtyfQptdXNldW1fZ3JvdXBfbWF4KG11c2V1bV90eXBlLCdUeXBlJykKYGBgCmBgYHtyfQptdXNldW1fZ3JvdXBfbWluKG11c2V1bV90eXBlLCdUeXBlJykKYGBgCi0gU2NpZW5jZSAmIFRlY2hub2xvZ3kgTXVzZXVtcy9QbGFuZXRhcml1bXMgaGF2ZSB0aGUgaGlnaGVzdCBhdmVyYWdlIGluY29tZS4KLSBBcnQgTXVzZXVtcyBoYXZlIHRoZSBoaWdoZXN0IHRvdGFsIGluY29tZSwgYXZlcmFnZSByZXZlbnVlIGFuZCB0b3RhbCByZXZlbnVlLiAKLSBIaXN0b3JpYyBQcmVzZXJ2YXRpb25zIGhhdmUgdGhlIGxvd2VzdCBhdmVyYWdlIGluY29tZSBhbmQgYXZlcmFnZSByZXZlbnVlLCBhbmQgdGhpcyBtdXNldW0gdHlwZSBoYXMgdGhlIG1vc3QgbXVzZXVtcyBhcyB3ZWxsLgotIENoaWxkcmVuJ3MgTXVzZXVtcyBoYXZlIHRoZSBsb3dlc3QgdG90YWwgaW5jb21lIGFuZCB0b3RhbCByZXZlbnVlLgotIE5hdHVyYWwgSGlzdG9yeSBNdXNldW1zIGhhdmUgdGhlIGxlYXN0IG11c2V1bXMgYW1vbmcgYWxsIG11c2V1bSB0eXBlcy4KCmBgYHtyfQojcGxvdHRpbmcgYmFyIGdyYXBoIGZvciBtdXNldW0gdHlwZSBhbmQgbnVtYmVyIG9mIE11c2V1bXMKZ2dwbG90KGRhdGE9bXVzZXVtX3R5cGUsYWVzKHg9VHlwZSx5PU11c2V1bV9Db3VudCwgZmlsbD1UeXBlKSkgKyBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsgbGFicyh0aXRsZT0iTnVtYmVyIG9mIE11c2V1bXMgYnkgVHlwZSIpKyB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLCBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCkpCgpgYGAKCiMjIyBUb3RhbCBJbmNvbWUgYnkgTXVzZXVtIFR5cGUKYGBge3J9CiNDcmVhdGluZyBhIFBpZSBDaGFydCAKdHlwZV9pbmNvbWUgPSBtdXNldW1fdHlwZSRUb3RhbF9JbmNvbWUKdHlwZV9sYWJlbHMgPSBtdXNldW1fdHlwZSRUeXBlCgojIFBsb3QgdGhlIGNoYXJ0LgpwaWUodHlwZV9pbmNvbWUsIGxhYmVscz10eXBlX2xhYmVscywgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgVG90YWwgSW5jb21lIGJ5IE11c2V1bSBUeXBlIixjb2wgPSByYWluYm93KGxlbmd0aCh0eXBlX2luY29tZSkpKQpgYGAKQXMgc2VlbiBhYm92ZSBBcnQgTXVzZXVtcyBtYWtlIHVwIHRoZSBiaWdnZXN0IHBvcnRpb24gb2YgYWxsIG11c2V1bSBpbmNvbWUgaW4gdGhlIFVTLCB3aGlsZSBDaGlsZHJlbidzIE11c2V1bXMgbWFrZSB1cCB0aGUgc21hbGxlc3QgcG9ydGlvbiBvZiBhbGwgbXVzZXVtIGluY29tZSBpbiB0aGUgVVMuIFdlIGNhbiBjaGVjayB0byBzZWUgaWYgYSBzaW1pbGFyIHBhdHRlcm4gaXMgb2JzZXJ2ZWQgd2l0aCByZXZlbnVlLgoKIyMjIFRvdGFsIFJldmVudWUgYnkgTXVzZXVtIFR5cGUKYGBge3J9CiNDcmVhdGluZyBhIFBpZSBDaGFydCAKdHlwZV9yZXZlbnVlID0gbXVzZXVtX3R5cGUkVG90YWxfUmV2ZW51ZQp0eXBlX2xhYmVscyA9IG11c2V1bV90eXBlJFR5cGUKCiMgUGxvdCB0aGUgY2hhcnQuCnBpZSh0eXBlX3JldmVudWUsIGxhYmVscz10eXBlX2xhYmVscywgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgVG90YWwgUmV2ZW51ZSBieSBNdXNldW0gVHlwZSIsY29sID0gcmFpbmJvdyhsZW5ndGgodHlwZV9yZXZlbnVlKSkpCmBgYApPbmNlIGFnYWluIEFydCBNdXNldW1zIG1ha2UgdXAgdGhlIGJpZ2dlc3QgcG9ydGlvbiBvZiBhbGwgbXVzZXVtIHJldmVudWUgaW4gdGhlIFVTLCB3aGlsZSBDaGlsZHJlbidzIE11c2V1bXMgbWFrZSB1cCB0aGUgc21hbGxlc3QgcG9ydGlvbiBvZiBhbGwgbXVzZXVtIHJldmVudWUgaW4gdGhlIFVTLiBGb3IgdGhlIG11c2V1bSBkYXRhIHRoZSByZXZlbnVlIGFsd2F5cyBsb3dlciB0aGFuIGluY29tZSBzbyB3ZSBjb3VsZCBhc3N1bWUgdGhhdCB0aGUgcmV2ZW51ZSBpcyB3aGF0IHRoZSBtdXNldW0gaXMgbGVmdCBvdmVyIHdpdGggYWZ0ZXIgZGVkdWN0aW5nIHRheGVzIGFuZCBvdGhlciBleHBlbnNlcy4gCgotIEl0IGl0IG5vdGV3b3J0aHkgdGhhdCB0aGUgQXJ0IE11c2V1bSdzIHJldmVudWUgbWFrZXMgdXAgYSBiaWdnZXIgcG9ydGlvbiBvZiBhbGwgbXVzZXVtIHJldmVudWUuCi0gVGhlIEFydCBNdXNldW0ncyBpcyByZXRhaW5pbmcgYSBsYXJnZXIgcG9ydGlvbiBvZiBpdHMgaW5jb21lIGFzIG9wcG9zZWQgdG8gdGhlIG90aGVyIG11c2V1bSB0eXBlcy4KLSBJZiB0aGlzIHdlcmUgbm90IHRoZSBjYXNlIHRoZW4gd2Ugd291bGQgZXhwZWN0IHRoZSBkaXN0cmlidXRpb24gdG8gYmUgc2ltaWxhciB0byB0aGF0IG9mIGluY29tZS4KCiMjIENpdHkKV2UgY2FuIGdyb3VwIHRoZSBkYXRhIGJ5IENpdHkgYXMgd2VsbCBhbmQgdGFrZSBhIGxvb2sgYXQgdGhlIGF2ZXJhZ2UgYW5kIHRvdGFsIEluY29tZSBhbmQgUmV2ZW51ZS4KCmBgYHtyfQojR3JvdXBpbmcgYnkgY2l0eQptdXNldW1fY2l0eSA8LSBtdXNldW1fZ3JvdXAoJ0NpdHkuLkFkbWluaXN0cmF0aXZlLkxvY2F0aW9uLicpCgojUmVuYW1pbmcgdGhlIGNvbHVtbgpjb2xuYW1lcyhtdXNldW1fY2l0eSlbd2hpY2gobmFtZXMobXVzZXVtX2NpdHkpID09ICJDaXR5Li5BZG1pbmlzdHJhdGl2ZS5Mb2NhdGlvbi4iKV0gPC0gIkNpdHkiCgpoZWFkKG11c2V1bV9jaXR5KQpgYGAKYGBge3J9Cm11c2V1bV9ncm91cF9tYXgobXVzZXVtX2NpdHksJ0NpdHknKQpgYGAKLSBBbWFkbyBoYXMgdGhlIGhpZ2hlc3QgYXZlcmFnZSBpbmNvbWUsIGF2ZXJhZ2UgcmV2ZW51ZSBhbmQgdG90YWwgaW5jb21lLgotIFdhc2hpbmd0b24gaGFzIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUuIAotIE5ldyBZb3JrIENpdHkgaGFzIHRoZSBtb3N0IG11c2V1bXMuCgojIyMgTnVtYmVyIG9mIE11c2V1bXMgdnMuIFRvdGFsIEluY29tZQpgYGB7cn0KI3Bsb3R0aW5nIHNjYXR0ZXIgcGxvdCBmb3IgbnVtYmVyIG9mIG11c2V1bXMgdnMuIHRvdGFsIGluY29tZSBmcm9tIG11c2V1bXMgaW4gZWFjaCBjaXR5CmdncGxvdChkYXRhPW11c2V1bV9jaXR5LGFlcyh4PU11c2V1bV9Db3VudCx5PVRvdGFsX0luY29tZSkpICsgZ2VvbV9wb2ludCgpICsgbGFicyh0aXRsZT0iQ2l0eSBMZXZlbCBEYXRhOiBOdW1iZXIgb2YgTXVzZXVtcyB2cy4gVG90YWwgSW5jb21lIikgKyBnZ2hpZ2hsaWdodChUb3RhbF9JbmNvbWUgPiAxMDAwMDAwMDAwMCkKCmBgYApBcyBzZWVuIGFib3ZlIHRoZSB2YXN0IG1ham9yaXR5IG9mIGNpdGllcyBtYWtlIHVuZGVyIDEwIEJpbGxpb24gaW4gaW5jb21lIGZyb20gbXVzZXVtcy4gCgojIyMgTnVtYmVyIG9mIE11c2V1bXMgdnMuIFRvdGFsIFJldmVudWUKYGBge3J9CiNwbG90dGluZyBzY2F0dGVyIHBsb3QgZm9yIG51bWJlciBvZiBtdXNldW1zIHZzLiB0b3RhbCBpbmNvbWUgZnJvbSBtdXNldW1zIGluIGVhY2ggc3RhdGUKZ2dwbG90KGRhdGE9bXVzZXVtX2NpdHksYWVzKHg9TXVzZXVtX0NvdW50LHk9VG90YWxfUmV2ZW51ZSkpICsgZ2VvbV9wb2ludCgpICsgbGFicyh0aXRsZT0iQ2l0eSBMZXZlbCBEYXRhOiBOdW1iZXIgb2YgTXVzZXVtcyB2cy4gVG90YWwgUmV2ZW51ZSIpICsgZ2doaWdobGlnaHQoVG90YWxfUmV2ZW51ZSA+IDIwMDAwMDAwMDApCgpgYGAKQXMgc2VlbiBhYm92ZSB0aGUgdmFzdCBtYWpvcml0eSBvZiBjaXRpZXMgbWFrZSB1bmRlciAyIEJpbGxpb24gaW4gcmV2ZW51ZSBmcm9tIG11c2V1bXMuCgojIyBTdGF0ZQpXZSBjYW4gZ3JvdXAgdGhlIGRhdGEgYnkgU3RhdGUgYXMgd2VsbCBhbmQgdGFrZSBhIGxvb2sgYXQgdGhlIGF2ZXJhZ2UgYW5kIHRvdGFsIEluY29tZSBhbmQgUmV2ZW51ZS4KYGBge3J9CiNHcm91cGluZyBieSBzdGF0ZQptdXNldW1fc3RhdGUgPC0gbXVzZXVtX2dyb3VwKCdTdGF0ZS4uQWRtaW5pc3RyYXRpdmUuTG9jYXRpb24uJykKCiNSZW5hbWluZyB0aGUgY29sdW1uCmNvbG5hbWVzKG11c2V1bV9zdGF0ZSlbd2hpY2gobmFtZXMobXVzZXVtX3N0YXRlKSA9PSAiU3RhdGUuLkFkbWluaXN0cmF0aXZlLkxvY2F0aW9uLiIpXSA8LSAiU3RhdGUiCgpoZWFkKG11c2V1bV9zdGF0ZSkKYGBgCmBgYHtyfQptdXNldW1fZ3JvdXBfbWF4KG11c2V1bV9zdGF0ZSwnU3RhdGUnKQpgYGAKCmBgYHtyfQptdXNldW1fZ3JvdXBfbWluKG11c2V1bV9zdGF0ZSwnU3RhdGUnKQpgYGAKLSBBcml6b25hIChBWikgaGFzIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgYW5kIHRvdGFsIGluY29tZS4KLSBXYXNoaW5ndG9uIERDIChEQykgaGFzIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgcmV2ZW51ZS4KLSBDYWxpZm9ybmlhIChDQSkgaGFzIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUgYW5kIGFuZCBhbHNvIHRoZSBtb3N0IG11c2V1bXMuCi0gTm9ydGggRGFrb3RhIChORCkgaGFzIHRoZSBsb3dlc3QgYXZlcmFnZSBhbmQgdG90YWwgaW5jb21lIGFuZCByZXZlbnVlLgotIFV0YWggKFVUKSBoYXMgdGhlIGxlYXN0IG11c2V1bXMuCgojIyMgTnVtYmVyIG9mIE11c2V1bXMgdnMuIFRvdGFsIEluY29tZQpgYGB7cn0KI3Bsb3R0aW5nIHNjYXR0ZXIgcGxvdCBmb3IgbnVtYmVyIG9mIG11c2V1bXMgdnMuIHRvdGFsIGluY29tZSBmcm9tIG11c2V1bXMgaW4gZWFjaCBzdGF0ZQpnZ3Bsb3QoZGF0YT1tdXNldW1fc3RhdGUsYWVzKHg9TXVzZXVtX0NvdW50LHk9VG90YWxfSW5jb21lKSkgKyBnZW9tX3BvaW50KCkgKyBsYWJzKHRpdGxlPSJTdGF0ZSBMZXZlbCBEYXRhOiBOdW1iZXIgb2YgTXVzZXVtcyB2cy4gVG90YWwgSW5jb21lIikgKyBnZ2hpZ2hsaWdodChUb3RhbF9JbmNvbWUgPiAxMDAwMDAwMDAwMCkKCmBgYApTaW1pbGFyIHRvIHRoZSBjaXR5IGxldmVsIGRhdGEsIHRoZSBtYWpvcml0eSBvZiBzdGF0ZXMgbWFrZSB1bmRlciAxMCBCaWxsaW9uIGluIGluY29tZSBmcm9tIG11c2V1bXMuCgojIyMgTnVtYmVyIG9mIE11c2V1bXMgdnMuIFRvdGFsIFJldmVudWUKYGBge3J9CiNwbG90dGluZyBzY2F0dGVyIHBsb3QgZm9yIG51bWJlciBvZiBtdXNldW1zIHZzLiB0b3RhbCBpbmNvbWUgZnJvbSBtdXNldW1zIGluIGVhY2ggc3RhdGUKZ2dwbG90KGRhdGE9bXVzZXVtX3N0YXRlLGFlcyh4PU11c2V1bV9Db3VudCx5PVRvdGFsX1JldmVudWUpKSArIGdlb21fcG9pbnQoKSArIGxhYnModGl0bGU9IlN0YXRlIExldmVsIERhdGE6IE51bWJlciBvZiBNdXNldW1zIHZzLiBUb3RhbCBSZXZlbnVlIikgKyBnZ2hpZ2hsaWdodChUb3RhbF9SZXZlbnVlID4gNTAwMDAwMDAwMCkKCmBgYApUaGUgbWFqb3JpdHkgb2Ygc3RhdGVzIG1ha2UgdW5kZXIgNSBCaWxsaW9uIGluIHJldmVudWUgZnJvbSBtdXNldW1zLgoKIyBTdW1tYXJ5IG9mIERhdGEgQW5hbHlzaXMKCldlIGhhdmUgbXVzZXVtIGRhdGEgZm9yIG11c2V1bXMgb2YgPGI+OSBUeXBlczwvYj4sIGxvY2F0ZWQgaW4gPGI+NzIzNiBDaXRpZXM8L2I+IGFjcm9zcyA8Yj41MSBTdGF0ZXM8L2I+LgoKIyMgTXVzZXVtIFR5cGVzCgotIDxiPlNjaWVuY2UgJiBUZWNobm9sb2d5IE11c2V1bXMvUGxhbmV0YXJpdW1zPC9iPiBoYXZlIHRoZSBoaWdoZXN0IGF2ZXJhZ2UgaW5jb21lLgotIDxiPkFydCBNdXNldW1zPC9iPiBoYXZlIHRoZSBoaWdoZXN0IHRvdGFsIGluY29tZSwgYXZlcmFnZSByZXZlbnVlIGFuZCB0b3RhbCByZXZlbnVlLiAKLSA8Yj5IaXN0b3JpYyBQcmVzZXJ2YXRpb25zPC9iPiBoYXZlIHRoZSBsb3dlc3QgYXZlcmFnZSBpbmNvbWUgYW5kIGF2ZXJhZ2UgcmV2ZW51ZSwgYW5kIHRoaXMgbXVzZXVtIHR5cGUgaGFzIHRoZSBtb3N0IG11c2V1bXMgYXMgd2VsbC4KLSA8Yj5DaGlsZHJlbidzIE11c2V1bXM8L2I+IGhhdmUgdGhlIGxvd2VzdCB0b3RhbCBpbmNvbWUgYW5kIHRvdGFsIHJldmVudWUuCi0gPGI+TmF0dXJhbCBIaXN0b3J5IE11c2V1bXM8L2I+IGhhdmUgdGhlIGxlYXN0IG11c2V1bXMgYW1vbmcgYWxsIG11c2V1bSB0eXBlcy4KCiMjIyBBcnQgTXVzZXVtcwpBcnQgTXVzZXVtcyBtYWtlIHVwIHRoZSBiaWdnZXN0IHBvcnRpb24gb2YgYWxsIG11c2V1bSBpbmNvbWUgYW5kIHJldmVudWUgaW4gdGhlIFVTLCB3aGlsZSBDaGlsZHJlbidzIE11c2V1bXMgbWFrZSB1cCB0aGUgc21hbGxlc3QgcG9ydGlvbiBvZiBhbGwgbXVzZXVtIGluY29tZSBhbmQgcmV2ZW51ZSAgRm9yIHRoZSBtdXNldW0gZGF0YSB0aGUgcmV2ZW51ZSBhbHdheXMgbG93ZXIgdGhhbiBpbmNvbWUgc28gd2UgY291bGQgYXNzdW1lIHRoYXQgdGhlIHJldmVudWUgaXMgd2hhdCB0aGUgbXVzZXVtIGlzIGxlZnQgb3ZlciB3aXRoIGFmdGVyIGRlZHVjdGluZyB0YXhlcyBhbmQgb3RoZXIgZXhwZW5zZXMuIAoKLSBJdCBpcyBub3Rld29ydGh5IHRoYXQgdGhlIEFydCBNdXNldW1zIHJldmVudWUgbWFrZXMgdXAgYSBiaWdnZXIgcG9ydGlvbiBvZiBhbGwgbXVzZXVtIHJldmVudWUuCi0gVGhlIDx1PkFydCBNdXNldW1zIGFyZSByZXRhaW5pbmcgYSBsYXJnZXIgcG9ydGlvbiBvZiBpdHMgaW5jb21lPC91PiBhcyBvcHBvc2VkIHRvIHRoZSBvdGhlciBtdXNldW0gdHlwZXMuCi0gSWYgdGhpcyB3ZXJlIG5vdCB0aGUgY2FzZSB0aGVuIHdlIHdvdWxkIGV4cGVjdCB0aGUgZGlzdHJpYnV0aW9uIHRvIGJlIHNpbWlsYXIgdG8gdGhhdCBvZiBpbmNvbWUuCgojIyBDaXR5CgotIDxiPkFtYWRvPC9iPiBoYXMgdGhlIGhpZ2hlc3QgYXZlcmFnZSBpbmNvbWUsIGF2ZXJhZ2UgcmV2ZW51ZSBhbmQgdG90YWwgaW5jb21lLgotIDxiPldhc2hpbmd0b248L2I+IGhhcyB0aGUgaGlnaGVzdCB0b3RhbCByZXZlbnVlLiAKLSA8Yj5OZXcgWW9yayBDaXR5PC9iPiBoYXMgdGhlIG1vc3QgbXVzZXVtcy4KClRoZSB2YXN0IG1ham9yaXR5IG9mIGNpdGllcyBtYWtlIDxiPnVuZGVyIDEwIEJpbGxpb24gaW4gaW5jb21lPC9iPiBhbmQgPGI+dW5kZXIgMiBCaWxsaW9uIGluIHJldmVudWU8L2I+IGZyb20gbXVzZXVtcy4gCgojIyBTdGF0ZQoKLSA8Yj5Bcml6b25hIChBWik8L2I+IGhhcyB0aGUgaGlnaGVzdCBhdmVyYWdlIGFuZCB0b3RhbCBpbmNvbWUuCi0gPGI+V2FzaGluZ3RvbiBEQyAoREMpPC9iPmhhcyB0aGUgaGlnaGVzdCBhdmVyYWdlIHJldmVudWUuCi0gPGI+Q2FsaWZvcm5pYSAoQ0EpPC9iPiBoYXMgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZSBhbmQgYWxzbyB0aGUgbW9zdCBtdXNldW1zLgotIDxiPk5vcnRoIERha290YSAoTkQpPC9iPiBoYXMgdGhlIGxvd2VzdCBhdmVyYWdlIGFuZCB0b3RhbCBpbmNvbWUgYW5kIHJldmVudWUuCi0gPGI+VXRhaCAoVVQpPC9iPiBoYXMgdGhlIGxlYXN0IG11c2V1bXMuCgpUaGUgbWFqb3JpdHkgb2Ygc3RhdGVzIG1ha2UgdW5kZXIgMTAgQmlsbGlvbiBpbiBpbmNvbWUgYW5kIHVuZGVyIDUgQmlsbGlvbiBpbiByZXZlbnVlIGZyb20gbXVzZXVtcy4gSWYgd2UgdGFrZSBpbnRvIGNvbnRleHQgdGhlIGNpdHkgbGV2ZWwgZGF0YSwgaXQgYmVjb21lcyBjbGVhciB0aGF0IHRoZSBtYWpvcml0eSBvZiBpbmNvbWUgYW5kIHJldmVudWUgZ2VuZXJhdGVkIGZyb20gbXVzZXVtcyBpbiBlYWNoIHN0YXRlIGNvbWVzIGZyb20ganVzdCBhIGZldyBjaXRpZXMgaW4gdGhhdCBzdGF0ZS4gCg==