Introduction
Our objective is to evaluate success factors and areas for growth in
Campaigns A, B, and C. This will allow us to understand if the
initiatives we are implementing are optimized to their fullest
potential.
We took 3 primary things into consideration during
our analysis; who we are serving, what we are serving, and where we are
serving it. These pillars provide a thorough analysis to understand each
campaign’s strengths and weaknesses. This analysis will provide
strategic recommendations to revise our campaigns for increased sales
for Regork.
Business Objective: Identify a potential growth area
where the company could invest future resources to increase revenue and
profit
Business Question 1: Which campaign types generated
most sales and what households are associated with that campaign
type?
Business Question 2: What further information can we
glean from this data about Campaign Types B and C that can be used to
develop a marketing strategy?
What are the total sales and number of products within each
campaign?
What are the income distributions among each campaigns
type?
What display locations lead to higher sales, and what locations
are common within each campaign type?
Answering the Questions
Initial Analysis on sales by campaign and household size
Based on the results of this exploratory graph, we discovered
differences between sales in Type A, Type B, and Type C. This was our
starting point for looking into campaigns.
# Creating a new table with summarized sales by campaign
sales_by_campaign <- campaign_descriptions %>%
inner_join(campaigns) %>%
inner_join(transactions) %>%
inner_join(demographics) %>%
group_by(campaign_id, campaign_type, household_comp) %>%
summarise(total_sales = sum(sales_value, na.rm = TRUE)) %>%
arrange(desc(total_sales))
# Graphing the sales by campaign with household information
sales_by_campaign %>%
ggplot(aes(x = campaign_type, y = total_sales, fill = household_comp)) +
geom_col(stat = "identity", position = "dodge") +
scale_y_continuous(labels = scales::dollar) +
labs(
title = "Total sales by campaign",
subtitle = "Campaign running from 2016 to 2017",
x = "Campaign type",
y = "Total sales",
fill = "Household size")

Product Count & Sales Amt Analysis
Next, we wanted to know how many products were involved in each
campaign type, and we wanted to validate that sales amounts differed by
campaign with a second graph.
It seems that campaign
C lacks in both product count and total sales value.
# Joining tables for further general analysis
df <-transactions %>%
left_join(products) %>%
left_join(demographics) %>%
full_join(campaigns) %>%
full_join(campaign_descriptions)
# This graph show how many products is applied for each type of campaign
#This is the reason why campaign A has the most sales value
#(df2 is the sales value of each campaign type)
df1 <- df %>%
group_by(campaign_type) %>%
count(n_distinct(product_id)) %>%
summarise(total_products= sum(n))
df1 %>% ggplot(aes(x= campaign_type,y=total_products)) +
geom_segment( aes(x= campaign_type,xend= campaign_type, y=0, yend= total_products, color= "Orange"), show.legend = FALSE)+
geom_point(color= 'Orange', size = 3, show.legend = FALSE) +
scale_y_continuous(trans= 'log2',name = "Number of products", labels = scales::comma) +
scale_x_discrete(name= "Campaign Type")+
labs( title = "Number of products in each campaign type",
subtitle = "This graph shows the number of products applied \n in each campaign type",
caption = "http://https://github.com/bradleyboehmke/completejourney")

# Creating a second data frame that looks at sales by campaign type without household information (more intuitive to understand)
df2<- df %>%
group_by(campaign_type) %>%
summarise(total_sales_campaign_type= sum(sales_value))
df2 %>%
ggplot(aes(x= campaign_type, y= total_sales_campaign_type, fill= campaign_type))+
geom_bar(stat = "identity", show.legend = FALSE)+
scale_fill_brewer(palette = "Oranges")+
scale_y_continuous( name = "Sales Value of each Campaign Type", labels = scales::dollar)+
scale_x_discrete(name= "Campaign Type")+
labs( title = "Total Sales Value of Each Campaign Type",
caption = "http://https://github.com/bradleyboehmke/completejourney")

An Analysis: Income Analysis
Additionally, we wanted to know what which household income factors
were attributed the most (percentage-wise) to each Campaign Type.
Based on the resulting stacked graph, middle-income families
are the target market of these campaigns.
# Without saving any variables, create the graph output of the count of households by income across campaign types.
demographics %>%
inner_join(transactions) %>%
inner_join(campaigns) %>%
inner_join(campaign_descriptions) %>%
filter(campaign_type %in% c("Type A","Type B", "Type C")) %>%
group_by(campaign_type) %>%
count(income, campaign_type) %>%
mutate(pct = n/sum(n)) %>%
ggplot(aes(reorder(income,n), y = n, fill = campaign_type)) +
geom_bar(stat = "identity") +
theme(axis.title.y = element_blank()) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_blank(),
axis.line = element_line(colour = "black"),
plot.caption = element_text(size = 8, margin = margin(t = 10), color = "grey70", hjust = 0)) +
scale_fill_brewer(palette = "Oranges") +
# Adding labels of percentages if wanted
# geom_text(aes(label = round(pct, 2)), hjust = -0.1,
# position = position_stack(vjust = 0.01),
# color = "black", check_overlap = TRUE) +
scale_y_continuous(labels = scales::number) +
coord_flip() +
labs(
title = "Income Distribution Among All Campaign Types",
x = "Income range",
y = "Count",
caption = "Source: R data package that provides access to data in the Complete Journey package \n provided by 84.51",
fill = "Campaign type")

Campaign-Location Analysis
Finally, we wanted to know which promotional display locations
contributed to each campaign type by counting the # of unique proucts
that were placed in each location during the campaign. (For the sake of
options, we made 2 graphs for each type).
Locations 0 and 7 are the top two for Types A and B, while locations
5 and 0 are common for type C (which has lower performance).
#Defining variables to analyze locations in each campaign. This uses large data frames.
plot_data <- promotions %>%
group_by(display_location, product_id) %>%
select(display_location, product_id) %>%
inner_join(products, by = "product_id") %>%
inner_join(coupons, by = "product_id") %>%
inner_join(campaign_descriptions, by = "campaign_id") %>%
select(campaign_type, display_location, product_id) %>%
group_by(campaign_type, display_location) %>%
summarize(distinct = n_distinct(product_id)) %>%
arrange(campaign_type, desc(distinct))
location_plot1 <- NA
location_plot2 <- NA
# This function intakes the campaign type (ex: 'Type A') and outputs two ranked graphs regarding location counts by distinct product id
campaign_locations <- function(campaign_tp, messages = TRUE){
location_plot1 <<- plot_data %>%
filter(campaign_type == campaign_tp) %>%
ggplot(aes(x = reorder(display_location, -distinct),
y = distinct,
fill = reorder(display_location, -distinct))) +
geom_bar(stat = "identity", show.legend = FALSE) +
scale_y_continuous(labels = scales::comma) +
scale_fill_grey() +
xlab("Display Locations") +
ylab("Distinct Product Count") +
labs( title = paste("# of unique products per display location"),
subtitle = paste("For", campaign_tp))
location_plot2 <<- plot_data %>%
filter(campaign_type == campaign_tp) %>%
ggplot(aes(x = distinct,
y = reorder(display_location, distinct),
col = -distinct)) +
geom_point(show.legend = FALSE, size = 5) +
scale_fill_distiller(type = "seq", palette = "Blues") +
xlab("Distinct Product Count") +
ylab("Display Location") +
scale_x_continuous(labels = scales::comma) +
labs( title = paste("# of unique products per display location"),
subtitle = paste("For", campaign_tp))
message("Function complete")
}
# Running the 'campgain_locations()' function and displaying outputs
cmpgns <- c("Type A","Type B","Type C")
for(i in cmpgns){
campaign_locations(i)
print(location_plot1)
print(location_plot2)
rm(location_plot1)
rm(location_plot2)
}
Function complete






rm(cmpgns)
rm(i)
rm(plot_data)
Summary
Problem Statement:
Which campaign types generated most sales and what households are
associated with that campaign type? Additionally, what further
information can be gleaned from this data about Campaign Types A, B, and
C that can be used to develop a marketing strategy?
Analysis Methodology
Addressing the strategy required to properly invest in all three
campaigns required a multi-metric approach, so the analysis was divided
into major categories of:
Basic sales metrics by campaign type
Household income distributions
Location popularity distributions
Once broken into the above-stated parts, each analysis used dplyr to
join, mutate, and filter (and more) multiple data tables from the
completejourney data. Then, the created data frames were visualized
utilizing ggplot2 and RColorBrewer.
Strategic Insights
From a marketing perspective, we wanted to address the 4 P’s
(pricing, product, placement, & promotion) to fully understand the
consumer. We recognized that the most popular income range for all 3
campaigns was 50-74K. This is a great insight to understand the
consumers that are reacting positively to our campaigns. It will also
allow us to implement a strategic pricing and promotion initiative in
place.
Although that is great, we also have some missed
opportunities in the other income ranges. This would be a chance for
Regork to investigate why that may be and innovate solutions to address
that in future campaigns.
Next, we also found that the higher
the number of products offered, the higher the sales value for the
campaign. This product variety seems to attract consumers and positively
impact their buying habits.
Finally, we discovered that
campaigns A & B were very successful using display locations 0 and
7. Grocery stores are very strategic in their product placement to
increase sales. We wanted to be sensitive to this and understand how
this influences campaign sales.
Implications on the Customer
Based on the findings listed above, our recommendations are
to:
Continue to target the 50-74K income range
Increase the number of products per campaign (particularly
C)
Rotate the campaigns among display locations 0 and 7
This will not only drive already-profitable growth in the 50-74k
income range, but also shift Campaign C’s low-quality strategy into the
same, highly successful strategies as A and B.
Analysis Limitations
After conducting out analysis, we discovered 4 primary limitations;
unknown locations, overlapping campaigns, campaign budget, and unknown
product categories.
One of our recommendations was to rotate the
campaigns between display locations 0 and 7. Although that is good in
theory, this poses some potential road blocks. First, we do not have any
information on these locations other than their designated number. This
is crucial information especially in a grocery store setting. Is it an
end cap? Is it refrigerated? How much space is available? All of these
things would be necessary information to implement the recommendation.
Next, since we recommended rotating the campaigns this means no
campaigns can overlap in timelines which could cause an issue. Another
limitation is campaign budget. One of our recommendations was to add
more products to Campaign C. However, more products require more capital
which may not be available in the budget.
Lastly, the data set
did not provide product categories. This information would’ve been
instrumental in creating more specific and successful campaigns.
LS0tDQp0aXRsZTogIkdyb3VwIDExIFByb2plY3QiDQpkYXRlOiAnIGByIFN5cy5EYXRlKClgJw0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCk1hcmtldGluZyBTdHJhdGVnaWVzIFJlZ2FyZGluZyBDYW1wYWlnbnMgPGJyPg0KQ2xhc3M6IERhdGEgTWluaW5nICg0MDgwLTAwMSkgPGJyPg0KQXV0aG9yczogQW4gTmd1eWVuLCBBdm5lZXQgRGhhcm5pLCBPYW5oIERhbmcsIFJvYW4gWmFwcGFudGksIFRhdHVtIEFyZXkgDQo8YnI+PGJyPg0KICANCiMjIFByZXJlcXVpdGllcw0KTm90ZTogUkNvbG9yQnJld2VyIHByb3ZpZGVzIGNvbG9yIHNjaGVtZXMgZm9yIGdyYXBocw0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShjb21wbGV0ZWpvdXJuZXkpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikNCmxpYnJhcnkoZHBseXIpDQoNCg0KYyhwcm9tb3Rpb25zLCB0cmFuc2FjdGlvbnMpICU8LSUgZ2V0X2RhdGEod2hpY2ggPSAnYm90aCcsIHZlcmJvc2UgPSBGQUxTRSkNCmBgYA0KIyMgSW50cm9kdWN0aW9uICANCg0KT3VyIG9iamVjdGl2ZSBpcyB0byBldmFsdWF0ZSBzdWNjZXNzIGZhY3RvcnMgYW5kIGFyZWFzIGZvciBncm93dGggaW4gQ2FtcGFpZ25zIEEsIEIsIGFuZCBDLiBUaGlzIHdpbGwgYWxsb3cgdXMgdG8gdW5kZXJzdGFuZCBpZiB0aGUgaW5pdGlhdGl2ZXMgd2UgYXJlIGltcGxlbWVudGluZyBhcmUgb3B0aW1pemVkIHRvIHRoZWlyIGZ1bGxlc3QgcG90ZW50aWFsLiA8YnI+IDxicj5XZSB0b29rIDMgcHJpbWFyeSB0aGluZ3MgaW50byBjb25zaWRlcmF0aW9uIGR1cmluZyBvdXIgYW5hbHlzaXM7IHdobyB3ZSBhcmUgc2VydmluZywgd2hhdCB3ZSBhcmUgc2VydmluZywgYW5kIHdoZXJlIHdlIGFyZSBzZXJ2aW5nIGl0LiBUaGVzZSBwaWxsYXJzIHByb3ZpZGUgYSB0aG9yb3VnaCBhbmFseXNpcyB0byB1bmRlcnN0YW5kIGVhY2ggY2FtcGFpZ24ncyBzdHJlbmd0aHMgYW5kIHdlYWtuZXNzZXMuIFRoaXMgYW5hbHlzaXMgd2lsbCBwcm92aWRlIHN0cmF0ZWdpYyByZWNvbW1lbmRhdGlvbnMgdG8gcmV2aXNlIG91ciBjYW1wYWlnbnMgZm9yIGluY3JlYXNlZCBzYWxlcyBmb3IgUmVnb3JrLg0KDQoqKkJ1c2luZXNzIE9iamVjdGl2ZSoqOiBJZGVudGlmeSBhIHBvdGVudGlhbCBncm93dGggYXJlYSB3aGVyZSB0aGUgY29tcGFueSBjb3VsZCBpbnZlc3QgZnV0dXJlIHJlc291cmNlcyB0byBpbmNyZWFzZSByZXZlbnVlIGFuZCBwcm9maXQNCg0KKipCdXNpbmVzcyBRdWVzdGlvbiAxKio6IFdoaWNoIGNhbXBhaWduIHR5cGVzIGdlbmVyYXRlZCBtb3N0IHNhbGVzIGFuZCB3aGF0IGhvdXNlaG9sZHMgYXJlIGFzc29jaWF0ZWQgd2l0aCB0aGF0IGNhbXBhaWduIHR5cGU/DQoNCioqQnVzaW5lc3MgUXVlc3Rpb24gMjoqKiBXaGF0IGZ1cnRoZXIgaW5mb3JtYXRpb24gY2FuIHdlIGdsZWFuIGZyb20gdGhpcyBkYXRhIGFib3V0IENhbXBhaWduIFR5cGVzIEIgYW5kIEMgdGhhdCBjYW4gYmUgdXNlZCB0byBkZXZlbG9wIGEgbWFya2V0aW5nIHN0cmF0ZWd5PyAgPGJyPjxicj4NCg0KLSBXaGF0IGFyZSB0aGUgdG90YWwgc2FsZXMgYW5kIG51bWJlciBvZiBwcm9kdWN0cyB3aXRoaW4gZWFjaCBjYW1wYWlnbj8NCg0KLSAgV2hhdCBhcmUgdGhlIGluY29tZSBkaXN0cmlidXRpb25zIGFtb25nIGVhY2ggY2FtcGFpZ25zIHR5cGU/ICANCg0KLSBXaGF0IGRpc3BsYXkgbG9jYXRpb25zIGxlYWQgdG8gaGlnaGVyIHNhbGVzLCBhbmQgd2hhdCBsb2NhdGlvbnMgYXJlIGNvbW1vbiB3aXRoaW4gZWFjaCBjYW1wYWlnbiB0eXBlPyANCjxicj48YnI+DQoNCg0KIyMgQW5zd2VyaW5nIHRoZSBRdWVzdGlvbnMNCg0KPGJyPg0KDQojIyMjIEluaXRpYWwgQW5hbHlzaXMgb24gc2FsZXMgYnkgY2FtcGFpZ24gYW5kIGhvdXNlaG9sZCBzaXplDQoNCkJhc2VkIG9uIHRoZSByZXN1bHRzIG9mIHRoaXMgZXhwbG9yYXRvcnkgZ3JhcGgsIHdlIGRpc2NvdmVyZWQgZGlmZmVyZW5jZXMgYmV0d2VlbiBzYWxlcyBpbiBUeXBlIEEsIFR5cGUgQiwgYW5kIFR5cGUgQy4gVGhpcyB3YXMgb3VyIHN0YXJ0aW5nIHBvaW50IGZvciBsb29raW5nIGludG8gY2FtcGFpZ25zLg0KYGBge3IsIG1lc3NhZ2U9IEZBTFNFLCBpbmNsdWRlPSBUUlVFLCBlY2hvPSBUUlVFfSANCg0KIyBDcmVhdGluZyBhIG5ldyB0YWJsZSB3aXRoIHN1bW1hcml6ZWQgc2FsZXMgYnkgY2FtcGFpZ24NCnNhbGVzX2J5X2NhbXBhaWduIDwtIGNhbXBhaWduX2Rlc2NyaXB0aW9ucyAlPiUNCiAgaW5uZXJfam9pbihjYW1wYWlnbnMpICU+JQ0KICBpbm5lcl9qb2luKHRyYW5zYWN0aW9ucykgJT4lDQogIGlubmVyX2pvaW4oZGVtb2dyYXBoaWNzKSAlPiUNCiAgZ3JvdXBfYnkoY2FtcGFpZ25faWQsIGNhbXBhaWduX3R5cGUsIGhvdXNlaG9sZF9jb21wKSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsX3NhbGVzID0gc3VtKHNhbGVzX3ZhbHVlLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsX3NhbGVzKSkNCmBgYA0KDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIyBHcmFwaGluZyB0aGUgc2FsZXMgYnkgY2FtcGFpZ24gd2l0aCBob3VzZWhvbGQgaW5mb3JtYXRpb24NCnNhbGVzX2J5X2NhbXBhaWduICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBjYW1wYWlnbl90eXBlLCB5ID0gdG90YWxfc2FsZXMsIGZpbGwgPSBob3VzZWhvbGRfY29tcCkpICsNCiAgZ2VvbV9jb2woc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpkb2xsYXIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJUb3RhbCBzYWxlcyBieSBjYW1wYWlnbiIsDQogICAgc3VidGl0bGUgPSAiQ2FtcGFpZ24gcnVubmluZyBmcm9tIDIwMTYgdG8gMjAxNyIsDQogICAgeCA9ICJDYW1wYWlnbiB0eXBlIiwNCiAgICB5ID0gIlRvdGFsIHNhbGVzIiwNCiAgICBmaWxsID0gIkhvdXNlaG9sZCBzaXplIikNCmBgYA0KPGJyPg0KDQojIyMjIFByb2R1Y3QgQ291bnQgJiBTYWxlcyBBbXQgQW5hbHlzaXMNCk5leHQsIHdlIHdhbnRlZCB0byBrbm93IGhvdyBtYW55IHByb2R1Y3RzIHdlcmUgaW52b2x2ZWQgaW4gZWFjaCBjYW1wYWlnbiB0eXBlLCBhbmQgd2Ugd2FudGVkIHRvIHZhbGlkYXRlIHRoYXQgc2FsZXMgYW1vdW50cyBkaWZmZXJlZCBieSBjYW1wYWlnbiB3aXRoIGEgc2Vjb25kIGdyYXBoLiANCjxicj48YnI+DQpJdCBzZWVtcyB0aGF0ICoqY2FtcGFpZ24gQyoqIGxhY2tzIGluIGJvdGggcHJvZHVjdCBjb3VudCBhbmQgdG90YWwgc2FsZXMgdmFsdWUuDQoNCmBgYHtyIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCiMgSm9pbmluZyB0YWJsZXMgZm9yIGZ1cnRoZXIgZ2VuZXJhbCBhbmFseXNpcw0KZGYgPC10cmFuc2FjdGlvbnMgJT4lDQogIGxlZnRfam9pbihwcm9kdWN0cykgJT4lDQogIGxlZnRfam9pbihkZW1vZ3JhcGhpY3MpICU+JQ0KICBmdWxsX2pvaW4oY2FtcGFpZ25zKSAlPiUNCiAgZnVsbF9qb2luKGNhbXBhaWduX2Rlc2NyaXB0aW9ucykNCg0KICANCiMgVGhpcyBncmFwaCBzaG93IGhvdyBtYW55IHByb2R1Y3RzIGlzIGFwcGxpZWQgZm9yIGVhY2ggdHlwZSBvZiBjYW1wYWlnbg0KI1RoaXMgaXMgdGhlIHJlYXNvbiB3aHkgY2FtcGFpZ24gQSBoYXMgdGhlIG1vc3Qgc2FsZXMgdmFsdWUgDQojKGRmMiBpcyB0aGUgc2FsZXMgdmFsdWUgb2YgZWFjaCBjYW1wYWlnbiB0eXBlKQ0KZGYxIDwtIGRmICU+JQ0KICBncm91cF9ieShjYW1wYWlnbl90eXBlKSAlPiUNCiAgY291bnQobl9kaXN0aW5jdChwcm9kdWN0X2lkKSkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9wcm9kdWN0cz0gc3VtKG4pKQ0KDQpkZjEgJT4lIGdncGxvdChhZXMoeD0gY2FtcGFpZ25fdHlwZSx5PXRvdGFsX3Byb2R1Y3RzKSkgKw0KICBnZW9tX3NlZ21lbnQoIGFlcyh4PSBjYW1wYWlnbl90eXBlLHhlbmQ9IGNhbXBhaWduX3R5cGUsIHk9MCwgeWVuZD0gdG90YWxfcHJvZHVjdHMsIGNvbG9yPSAiT3JhbmdlIiksIHNob3cubGVnZW5kID0gRkFMU0UpKw0KICBnZW9tX3BvaW50KGNvbG9yPSAnT3JhbmdlJywgc2l6ZSA9IDMsIHNob3cubGVnZW5kID0gRkFMU0UpICsgDQogIHNjYWxlX3lfY29udGludW91cyh0cmFucz0gJ2xvZzInLG5hbWUgPSAiTnVtYmVyIG9mIHByb2R1Y3RzIiwgbGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICBzY2FsZV94X2Rpc2NyZXRlKG5hbWU9ICJDYW1wYWlnbiBUeXBlIikrDQogIGxhYnMoIHRpdGxlID0gIk51bWJlciBvZiBwcm9kdWN0cyBpbiBlYWNoIGNhbXBhaWduIHR5cGUiLA0KICAgICAgICBzdWJ0aXRsZSA9ICJUaGlzIGdyYXBoIHNob3dzIHRoZSBudW1iZXIgb2YgcHJvZHVjdHMgYXBwbGllZCBcbiBpbiBlYWNoIGNhbXBhaWduIHR5cGUiLA0KICAgICAgIGNhcHRpb24gPSAiaHR0cDovL2h0dHBzOi8vZ2l0aHViLmNvbS9icmFkbGV5Ym9laG1rZS9jb21wbGV0ZWpvdXJuZXkiKQ0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT0gRkFMU0V9DQojIENyZWF0aW5nIGEgc2Vjb25kIGRhdGEgZnJhbWUgdGhhdCBsb29rcyBhdCBzYWxlcyBieSBjYW1wYWlnbiB0eXBlIHdpdGhvdXQgaG91c2Vob2xkIGluZm9ybWF0aW9uIChtb3JlIGludHVpdGl2ZSB0byB1bmRlcnN0YW5kKQ0KZGYyPC0gZGYgJT4lDQogIGdyb3VwX2J5KGNhbXBhaWduX3R5cGUpICU+JQ0Kc3VtbWFyaXNlKHRvdGFsX3NhbGVzX2NhbXBhaWduX3R5cGU9IHN1bShzYWxlc192YWx1ZSkpDQoNCmRmMiAlPiUgDQogIGdncGxvdChhZXMoeD0gY2FtcGFpZ25fdHlwZSwgeT0gdG90YWxfc2FsZXNfY2FtcGFpZ25fdHlwZSwgZmlsbD0gY2FtcGFpZ25fdHlwZSkpKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkrDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiT3JhbmdlcyIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoIG5hbWUgPSAiU2FsZXMgVmFsdWUgb2YgZWFjaCBDYW1wYWlnbiBUeXBlIiwgbGFiZWxzID0gc2NhbGVzOjpkb2xsYXIpKw0KICBzY2FsZV94X2Rpc2NyZXRlKG5hbWU9ICJDYW1wYWlnbiBUeXBlIikrDQogIGxhYnMoIHRpdGxlID0gIlRvdGFsIFNhbGVzIFZhbHVlIG9mIEVhY2ggQ2FtcGFpZ24gVHlwZSIsDQogICAgICAgY2FwdGlvbiA9ICJodHRwOi8vaHR0cHM6Ly9naXRodWIuY29tL2JyYWRsZXlib2VobWtlL2NvbXBsZXRlam91cm5leSIpDQpgYGANCjxicj4NCg0KIyMjIyBBbiBBbmFseXNpczogSW5jb21lIEFuYWx5c2lzDQoNCkFkZGl0aW9uYWxseSwgd2Ugd2FudGVkIHRvIGtub3cgd2hhdCB3aGljaCBob3VzZWhvbGQgaW5jb21lIGZhY3RvcnMgd2VyZSBhdHRyaWJ1dGVkIHRoZSBtb3N0IChwZXJjZW50YWdlLXdpc2UpIHRvIGVhY2ggQ2FtcGFpZ24gVHlwZS4NCjxicj48YnI+DQpCYXNlZCBvbiB0aGUgcmVzdWx0aW5nIHN0YWNrZWQgZ3JhcGgsIG1pZGRsZS1pbmNvbWUgZmFtaWxpZXMgYXJlIHRoZSB0YXJnZXQgbWFya2V0IG9mIHRoZXNlIGNhbXBhaWducy4NCmBgYHtyIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCg0KIyBXaXRob3V0IHNhdmluZyBhbnkgdmFyaWFibGVzLCBjcmVhdGUgdGhlIGdyYXBoIG91dHB1dCBvZiB0aGUgY291bnQgb2YgaG91c2Vob2xkcyBieSBpbmNvbWUgYWNyb3NzIGNhbXBhaWduIHR5cGVzLg0KZGVtb2dyYXBoaWNzICU+JQ0KICBpbm5lcl9qb2luKHRyYW5zYWN0aW9ucykgJT4lDQogIGlubmVyX2pvaW4oY2FtcGFpZ25zKSAlPiUNCiAgaW5uZXJfam9pbihjYW1wYWlnbl9kZXNjcmlwdGlvbnMpICU+JQ0KICBmaWx0ZXIoY2FtcGFpZ25fdHlwZSAlaW4lIGMoIlR5cGUgQSIsIlR5cGUgQiIsICJUeXBlIEMiKSkgJT4lDQogIGdyb3VwX2J5KGNhbXBhaWduX3R5cGUpICU+JQ0KICBjb3VudChpbmNvbWUsIGNhbXBhaWduX3R5cGUpICU+JQ0KICBtdXRhdGUocGN0ID0gbi9zdW0obikpICU+JQ0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIoaW5jb21lLG4pLCB5ID0gbiwgZmlsbCA9IGNhbXBhaWduX3R5cGUpKSArDQogICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCANCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJibGFjayIpLA0KICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgsIG1hcmdpbiA9IG1hcmdpbih0ID0gMTApLCBjb2xvciA9ICJncmV5NzAiLCBoanVzdCA9IDApKSArDQogICAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJPcmFuZ2VzIikgKw0KICAgICMgQWRkaW5nIGxhYmVscyBvZiBwZXJjZW50YWdlcyBpZiB3YW50ZWQNCiAgICAjIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChwY3QsIDIpKSwgaGp1c3QgPSAtMC4xLA0KICAgICMgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuMDEpLA0KICAgICMgY29sb3IgPSAiYmxhY2siLCBjaGVja19vdmVybGFwID0gVFJVRSkgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6Om51bWJlcikgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiSW5jb21lIERpc3RyaWJ1dGlvbiBBbW9uZyBBbGwgQ2FtcGFpZ24gVHlwZXMiLA0KICAgIHggPSAiSW5jb21lIHJhbmdlIiwNCiAgICB5ID0gIkNvdW50IiwNCiAgICBjYXB0aW9uID0gIlNvdXJjZTogUiBkYXRhIHBhY2thZ2UgdGhhdCBwcm92aWRlcyBhY2Nlc3MgdG8gZGF0YSBpbiB0aGUgQ29tcGxldGUgSm91cm5leSBwYWNrYWdlIFxuIHByb3ZpZGVkIGJ5IDg0LjUxIiwNCiAgICBmaWxsID0gIkNhbXBhaWduIHR5cGUiKQ0KYGBgDQoNCjxicj4NCg0KIyMjIyBDYW1wYWlnbi1Mb2NhdGlvbiBBbmFseXNpcw0KDQpGaW5hbGx5LCB3ZSB3YW50ZWQgdG8ga25vdyB3aGljaCBwcm9tb3Rpb25hbCBkaXNwbGF5IGxvY2F0aW9ucyBjb250cmlidXRlZCB0byBlYWNoIGNhbXBhaWduIHR5cGUgYnkgY291bnRpbmcgdGhlICMgb2YgdW5pcXVlIHByb3VjdHMgdGhhdCB3ZXJlIHBsYWNlZCBpbiBlYWNoIGxvY2F0aW9uIGR1cmluZyB0aGUgY2FtcGFpZ24uDQooRm9yIHRoZSBzYWtlIG9mIG9wdGlvbnMsIHdlIG1hZGUgMiBncmFwaHMgZm9yIGVhY2ggdHlwZSkuDQoNCkxvY2F0aW9ucyAwIGFuZCA3IGFyZSB0aGUgdG9wIHR3byBmb3IgVHlwZXMgQSBhbmQgQiwgd2hpbGUgbG9jYXRpb25zIDUgYW5kIDAgYXJlIGNvbW1vbiBmb3IgdHlwZSBDICh3aGljaCBoYXMgbG93ZXIgcGVyZm9ybWFuY2UpLg0KDQpgYGB7ciBEZWZpbmluZyBEYXRhICYgVmFyaWFibGVzLCBlY2hvID0gVFJVRSwgbWVzc2FnZT0gRkFMU0V9DQojRGVmaW5pbmcgdmFyaWFibGVzIHRvIGFuYWx5emUgbG9jYXRpb25zIGluIGVhY2ggY2FtcGFpZ24uIFRoaXMgdXNlcyBsYXJnZSBkYXRhIGZyYW1lcy4NCnBsb3RfZGF0YSA8LSBwcm9tb3Rpb25zICU+JSANCiAgICBncm91cF9ieShkaXNwbGF5X2xvY2F0aW9uLCBwcm9kdWN0X2lkKSAlPiUgDQogICAgc2VsZWN0KGRpc3BsYXlfbG9jYXRpb24sIHByb2R1Y3RfaWQpICU+JSANCiAgICBpbm5lcl9qb2luKHByb2R1Y3RzLCBieSA9ICJwcm9kdWN0X2lkIikgJT4lIA0KICAgIGlubmVyX2pvaW4oY291cG9ucywgYnkgPSAicHJvZHVjdF9pZCIpICU+JSANCiAgICBpbm5lcl9qb2luKGNhbXBhaWduX2Rlc2NyaXB0aW9ucywgYnkgPSAiY2FtcGFpZ25faWQiKSAlPiUNCiAgICBzZWxlY3QoY2FtcGFpZ25fdHlwZSwgZGlzcGxheV9sb2NhdGlvbiwgcHJvZHVjdF9pZCkgJT4lIA0KICAgIGdyb3VwX2J5KGNhbXBhaWduX3R5cGUsIGRpc3BsYXlfbG9jYXRpb24pICU+JSANCiAgICBzdW1tYXJpemUoZGlzdGluY3QgPSBuX2Rpc3RpbmN0KHByb2R1Y3RfaWQpKSAlPiUNCiAgICBhcnJhbmdlKGNhbXBhaWduX3R5cGUsIGRlc2MoZGlzdGluY3QpKQ0KDQpsb2NhdGlvbl9wbG90MSA8LSBOQQ0KbG9jYXRpb25fcGxvdDIgPC0gTkENCmBgYA0KDQpgYGB7ciBDcmVhdGUgdGhlIEZ1bmN0aW9uLCBlY2hvID0gVFJVRX0NCiMgVGhpcyBmdW5jdGlvbiBpbnRha2VzIHRoZSBjYW1wYWlnbiB0eXBlIChleDogJ1R5cGUgQScpIGFuZCBvdXRwdXRzIHR3byByYW5rZWQgZ3JhcGhzIHJlZ2FyZGluZyBsb2NhdGlvbiBjb3VudHMgYnkgZGlzdGluY3QgcHJvZHVjdCBpZA0KDQpjYW1wYWlnbl9sb2NhdGlvbnMgPC0gZnVuY3Rpb24oY2FtcGFpZ25fdHAsIG1lc3NhZ2VzID0gVFJVRSl7DQogIA0KICAgIA0KICBsb2NhdGlvbl9wbG90MSA8PC0gcGxvdF9kYXRhICU+JQ0KICAgIGZpbHRlcihjYW1wYWlnbl90eXBlID09IGNhbXBhaWduX3RwKSAlPiUgDQogICAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihkaXNwbGF5X2xvY2F0aW9uLCAtZGlzdGluY3QpLCANCiAgICAgICAgICAgICAgICB5ID0gZGlzdGluY3QsDQogICAgICAgICAgICAgICBmaWxsID0gcmVvcmRlcihkaXNwbGF5X2xvY2F0aW9uLCAtZGlzdGluY3QpKSkgKyANCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICAgICAgc2NhbGVfZmlsbF9ncmV5KCkgKw0KICAgICAgeGxhYigiRGlzcGxheSBMb2NhdGlvbnMiKSArDQogICAgICB5bGFiKCJEaXN0aW5jdCBQcm9kdWN0IENvdW50IikgKw0KICAgICAgbGFicyggdGl0bGUgPSBwYXN0ZSgiIyBvZiB1bmlxdWUgcHJvZHVjdHMgcGVyIGRpc3BsYXkgbG9jYXRpb24iKSwNCiAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIkZvciIsIGNhbXBhaWduX3RwKSkNCiAgICANCiAgbG9jYXRpb25fcGxvdDIgPDwtIHBsb3RfZGF0YSAlPiUgDQogICAgZmlsdGVyKGNhbXBhaWduX3R5cGUgPT0gY2FtcGFpZ25fdHApICU+JSANCiAgICBnZ3Bsb3QoYWVzKHggPSBkaXN0aW5jdCwgDQogICAgICAgICAgICAgICB5ID0gcmVvcmRlcihkaXNwbGF5X2xvY2F0aW9uLCBkaXN0aW5jdCksDQogICAgICAgICAgICAgICBjb2wgPSAtZGlzdGluY3QpKSArIA0KICAgICAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEZBTFNFLCBzaXplID0gNSkgKw0KICAgICAgc2NhbGVfZmlsbF9kaXN0aWxsZXIodHlwZSA9ICJzZXEiLCBwYWxldHRlID0gIkJsdWVzIikgKyAgICAgIA0KICAgICAgeGxhYigiRGlzdGluY3QgUHJvZHVjdCBDb3VudCIpICsNCiAgICAgIHlsYWIoIkRpc3BsYXkgTG9jYXRpb24iKSArDQogICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICAgICAgbGFicyggdGl0bGUgPSBwYXN0ZSgiIyBvZiB1bmlxdWUgcHJvZHVjdHMgcGVyIGRpc3BsYXkgbG9jYXRpb24iKSwNCiAgICAgICAgICAgIHN1YnRpdGxlID0gcGFzdGUoIkZvciIsIGNhbXBhaWduX3RwKSkNCiAgDQogIG1lc3NhZ2UoIkZ1bmN0aW9uIGNvbXBsZXRlIikNCn0gIA0KDQpgYGANCg0KYGBge3IgUnVuIHRoZSBGdW5jdGlvbiwgbWVzc2FnZXMgPSBGQUxTRX0NCiMgUnVubmluZyB0aGUgJ2NhbXBnYWluX2xvY2F0aW9ucygpJyBmdW5jdGlvbiBhbmQgZGlzcGxheWluZyBvdXRwdXRzDQpjbXBnbnMgPC0gYygiVHlwZSBBIiwiVHlwZSBCIiwiVHlwZSBDIikNCmZvcihpIGluIGNtcGducyl7DQogIGNhbXBhaWduX2xvY2F0aW9ucyhpKQ0KICBwcmludChsb2NhdGlvbl9wbG90MSkNCiAgcHJpbnQobG9jYXRpb25fcGxvdDIpDQogIHJtKGxvY2F0aW9uX3Bsb3QxKQ0KICBybShsb2NhdGlvbl9wbG90MikNCn0NCg0Kcm0oY21wZ25zKQ0Kcm0oaSkNCnJtKHBsb3RfZGF0YSkNCmBgYA0KPGJyPg0KDQojIyBTdW1tYXJ5DQoNCiMjIyBQcm9ibGVtIFN0YXRlbWVudDoNCldoaWNoIGNhbXBhaWduIHR5cGVzIGdlbmVyYXRlZCBtb3N0IHNhbGVzIGFuZCB3aGF0IGhvdXNlaG9sZHMgYXJlIGFzc29jaWF0ZWQgd2l0aCB0aGF0IGNhbXBhaWduIHR5cGU/IEFkZGl0aW9uYWxseSwgd2hhdCBmdXJ0aGVyIGluZm9ybWF0aW9uIGNhbiBiZSBnbGVhbmVkIGZyb20gdGhpcyBkYXRhIGFib3V0IENhbXBhaWduIFR5cGVzIEEsIEIsIGFuZCBDIHRoYXQgY2FuIGJlIHVzZWQgdG8gZGV2ZWxvcCBhIG1hcmtldGluZyBzdHJhdGVneT8gPGJyPjxicj4NCg0KIyMjIEFuYWx5c2lzIE1ldGhvZG9sb2d5DQpBZGRyZXNzaW5nIHRoZSBzdHJhdGVneSByZXF1aXJlZCB0byBwcm9wZXJseSBpbnZlc3QgaW4gYWxsIHRocmVlIGNhbXBhaWducyByZXF1aXJlZCBhIG11bHRpLW1ldHJpYyBhcHByb2FjaCwgc28gdGhlIGFuYWx5c2lzIHdhcyBkaXZpZGVkIGludG8gbWFqb3IgY2F0ZWdvcmllcyBvZjogPGJyPg0KDQotIEJhc2ljIHNhbGVzIG1ldHJpY3MgYnkgY2FtcGFpZ24gdHlwZQ0KDQotIEhvdXNlaG9sZCBpbmNvbWUgZGlzdHJpYnV0aW9ucyAgDQoNCi0gTG9jYXRpb24gcG9wdWxhcml0eSBkaXN0cmlidXRpb25zIA0KDQpPbmNlIGJyb2tlbiBpbnRvIHRoZSBhYm92ZS1zdGF0ZWQgcGFydHMsIGVhY2ggYW5hbHlzaXMgdXNlZCBkcGx5ciB0byBqb2luLCBtdXRhdGUsIGFuZCBmaWx0ZXIgKGFuZCBtb3JlKSBtdWx0aXBsZSBkYXRhIHRhYmxlcyBmcm9tIHRoZSBjb21wbGV0ZWpvdXJuZXkgZGF0YS4gVGhlbiwgdGhlIGNyZWF0ZWQgZGF0YSBmcmFtZXMgd2VyZSB2aXN1YWxpemVkIHV0aWxpemluZyBnZ3Bsb3QyIGFuZCBSQ29sb3JCcmV3ZXIuPGJyPjxicj4NCg0KIyMjIFN0cmF0ZWdpYyBJbnNpZ2h0cw0KRnJvbSBhIG1hcmtldGluZyBwZXJzcGVjdGl2ZSwgd2Ugd2FudGVkIHRvIGFkZHJlc3MgdGhlIDQgUCdzIChwcmljaW5nLCBwcm9kdWN0LCBwbGFjZW1lbnQsICYgcHJvbW90aW9uKSB0byBmdWxseSB1bmRlcnN0YW5kIHRoZSBjb25zdW1lci4gDQpXZSByZWNvZ25pemVkIHRoYXQgdGhlIG1vc3QgcG9wdWxhciBpbmNvbWUgcmFuZ2UgZm9yIGFsbCAzIGNhbXBhaWducyB3YXMgNTAtNzRLLiBUaGlzIGlzIGEgZ3JlYXQgaW5zaWdodCB0byB1bmRlcnN0YW5kIHRoZSBjb25zdW1lcnMgdGhhdCBhcmUgcmVhY3RpbmcgcG9zaXRpdmVseSB0byBvdXIgY2FtcGFpZ25zLiBJdCB3aWxsIGFsc28gYWxsb3cgdXMgdG8gaW1wbGVtZW50IGEgc3RyYXRlZ2ljIHByaWNpbmcgYW5kIHByb21vdGlvbiBpbml0aWF0aXZlIGluIHBsYWNlLiA8YnI+PGJyPkFsdGhvdWdoIHRoYXQgaXMgZ3JlYXQsIHdlIGFsc28gaGF2ZSBzb21lIG1pc3NlZCBvcHBvcnR1bml0aWVzIGluIHRoZSBvdGhlciBpbmNvbWUgcmFuZ2VzLiBUaGlzIHdvdWxkIGJlIGEgY2hhbmNlIGZvciBSZWdvcmsgdG8gaW52ZXN0aWdhdGUgd2h5IHRoYXQgbWF5IGJlIGFuZCBpbm5vdmF0ZSBzb2x1dGlvbnMgdG8gYWRkcmVzcyB0aGF0IGluIGZ1dHVyZSBjYW1wYWlnbnMuIDxicj48YnI+TmV4dCwgd2UgYWxzbyBmb3VuZCB0aGF0IHRoZSBoaWdoZXIgdGhlIG51bWJlciBvZiBwcm9kdWN0cyBvZmZlcmVkLCB0aGUgaGlnaGVyIHRoZSBzYWxlcyB2YWx1ZSBmb3IgdGhlIGNhbXBhaWduLiBUaGlzIHByb2R1Y3QgdmFyaWV0eSBzZWVtcyB0byBhdHRyYWN0IGNvbnN1bWVycyBhbmQgcG9zaXRpdmVseSBpbXBhY3QgdGhlaXIgYnV5aW5nIGhhYml0cy4gPGJyPjxicj5GaW5hbGx5LCB3ZSBkaXNjb3ZlcmVkIHRoYXQgY2FtcGFpZ25zIEEgJiBCIHdlcmUgdmVyeSBzdWNjZXNzZnVsIHVzaW5nIGRpc3BsYXkgbG9jYXRpb25zIDAgYW5kIDcuIEdyb2Nlcnkgc3RvcmVzIGFyZSB2ZXJ5IHN0cmF0ZWdpYyBpbiB0aGVpciBwcm9kdWN0IHBsYWNlbWVudCB0byBpbmNyZWFzZSBzYWxlcy4gV2Ugd2FudGVkIHRvIGJlIHNlbnNpdGl2ZSB0byB0aGlzIGFuZCB1bmRlcnN0YW5kIGhvdyB0aGlzIGluZmx1ZW5jZXMgY2FtcGFpZ24gc2FsZXMuPGJyPjxicj4NCg0KIyMjIEltcGxpY2F0aW9ucyBvbiB0aGUgQ3VzdG9tZXINCkJhc2VkIG9uIHRoZSBmaW5kaW5ncyBsaXN0ZWQgYWJvdmUsIG91ciByZWNvbW1lbmRhdGlvbnMgYXJlIHRvOjxicj4NCg0KMS4gQ29udGludWUgdG8gdGFyZ2V0IHRoZSA1MC03NEsgaW5jb21lIHJhbmdlIA0KDQoyLiBJbmNyZWFzZSB0aGUgbnVtYmVyIG9mIHByb2R1Y3RzIHBlciBjYW1wYWlnbiAocGFydGljdWxhcmx5IEMpIA0KDQozLiBSb3RhdGUgdGhlIGNhbXBhaWducyBhbW9uZyBkaXNwbGF5IGxvY2F0aW9ucyAwIGFuZCA3DQoNClRoaXMgd2lsbCBub3Qgb25seSBkcml2ZSBhbHJlYWR5LXByb2ZpdGFibGUgZ3Jvd3RoIGluIHRoZSA1MC03NGsgaW5jb21lIHJhbmdlLCBidXQgYWxzbyBzaGlmdCBDYW1wYWlnbiBDJ3MgbG93LXF1YWxpdHkgc3RyYXRlZ3kgaW50byB0aGUgc2FtZSwgaGlnaGx5IHN1Y2Nlc3NmdWwgc3RyYXRlZ2llcyBhcyBBIGFuZCBCLiA8YnI+PGJyPg0KDQojIyMgQW5hbHlzaXMgTGltaXRhdGlvbnMNCkFmdGVyIGNvbmR1Y3Rpbmcgb3V0IGFuYWx5c2lzLCB3ZSBkaXNjb3ZlcmVkIDQgcHJpbWFyeSBsaW1pdGF0aW9uczsgdW5rbm93biBsb2NhdGlvbnMsIG92ZXJsYXBwaW5nIGNhbXBhaWducywgY2FtcGFpZ24gYnVkZ2V0LCBhbmQgdW5rbm93biBwcm9kdWN0IGNhdGVnb3JpZXMuIDxicj48YnI+T25lIG9mIG91ciByZWNvbW1lbmRhdGlvbnMgd2FzIHRvIHJvdGF0ZSB0aGUgY2FtcGFpZ25zIGJldHdlZW4gZGlzcGxheSBsb2NhdGlvbnMgMCBhbmQgNy4gQWx0aG91Z2ggdGhhdCBpcyBnb29kIGluIHRoZW9yeSwgdGhpcyBwb3NlcyBzb21lIHBvdGVudGlhbCByb2FkIGJsb2Nrcy4gRmlyc3QsIHdlIGRvIG5vdCBoYXZlIGFueSBpbmZvcm1hdGlvbiBvbiB0aGVzZSBsb2NhdGlvbnMgb3RoZXIgdGhhbiB0aGVpciBkZXNpZ25hdGVkIG51bWJlci4gVGhpcyBpcyBjcnVjaWFsIGluZm9ybWF0aW9uIGVzcGVjaWFsbHkgaW4gYSBncm9jZXJ5IHN0b3JlIHNldHRpbmcuIElzIGl0IGFuIGVuZCBjYXA/IElzIGl0IHJlZnJpZ2VyYXRlZD8gSG93IG11Y2ggc3BhY2UgaXMgYXZhaWxhYmxlPyBBbGwgb2YgdGhlc2UgdGhpbmdzIHdvdWxkIGJlIG5lY2Vzc2FyeSBpbmZvcm1hdGlvbiB0byBpbXBsZW1lbnQgdGhlIHJlY29tbWVuZGF0aW9uLiA8YnI+PGJyPk5leHQsIHNpbmNlIHdlIHJlY29tbWVuZGVkIHJvdGF0aW5nIHRoZSBjYW1wYWlnbnMgdGhpcyBtZWFucyBubyBjYW1wYWlnbnMgY2FuIG92ZXJsYXAgaW4gdGltZWxpbmVzIHdoaWNoIGNvdWxkIGNhdXNlIGFuIGlzc3VlLiBBbm90aGVyIGxpbWl0YXRpb24gaXMgY2FtcGFpZ24gYnVkZ2V0LiBPbmUgb2Ygb3VyIHJlY29tbWVuZGF0aW9ucyB3YXMgdG8gYWRkIG1vcmUgcHJvZHVjdHMgdG8gQ2FtcGFpZ24gQy4gSG93ZXZlciwgbW9yZSBwcm9kdWN0cyByZXF1aXJlIG1vcmUgY2FwaXRhbCB3aGljaCBtYXkgbm90IGJlIGF2YWlsYWJsZSBpbiB0aGUgYnVkZ2V0LiA8YnI+PGJyPkxhc3RseSwgdGhlIGRhdGEgc2V0IGRpZCBub3QgcHJvdmlkZSBwcm9kdWN0IGNhdGVnb3JpZXMuIFRoaXMgaW5mb3JtYXRpb24gd291bGQndmUgYmVlbiBpbnN0cnVtZW50YWwgaW4gY3JlYXRpbmcgbW9yZSBzcGVjaWZpYyBhbmQgc3VjY2Vzc2Z1bCBjYW1wYWlnbnMuDQoNCg0K