Hi, please find final thoughts at the end of analysis.
install.packages("tidyverse")
library(tidyverse)
Installing necessary packages (In this case, tidyverse should do the
trick)
hornet <- read.csv("abc_test_data.csv")
view(hornet)
glimpse(hornet)
Load the dataset into the R environment, quick overview to check if
it has loaded properly and what data types the fields are coded as.
hornet <- hornet %>% rename(date = DATE)
hornet <- hornet %>% rename(amt = Total_purchased_amount)
hornet <- hornet %>% rename(nr_purchased = Purchases)
Rename variables for easier usage throughout script (not a fan of
capitals)
hornet2 <- hornet
Create a duplicate dataset as a test before applying changes to main
dataset.
hornet$date <- as.Date(hornet$date, format = "%Y/%m/%d")
hornet$amt <- gsub(",", ".", hornet$amt)
hornet$amt <- as.numeric(hornet$amt)
glimpse(hornet)
sum(is.na(hornet$amt))
Converting to correct data types, and confirming it has pulled
through correctly.
Now, on to answering the questions.
Q3a.i: Is there a difference between the different versions regarding
daily revenue brought in by the feature?
daily_revenue <- hornet %>%
group_by(date, variant) %>%
summarise(total_revenue = sum(amt, na.rm = TRUE))
summary(daily_revenue)
Create table showing total revenue per day, split by each version
ggplot(daily_revenue, aes(x = date, y = total_revenue, color = as.factor(variant))) +
geom_line() +
labs(title = "Daily Revenue by Version", x = "Date", y = "Total Revenue") +
theme_minimal()
Line graph showing Daily Revenue, split by each version. Similar
trend line for all versions, no notable differences. Version 3 appears
to be the only one with purchases on last day (May 17th), but appears to
be statistically insignificant (On further inspection in Excel, total
amounted to approximately 670).
ggplot(daily_revenue, aes(x = as.factor(variant), y = total_revenue, fill = as.factor(variant))) +
geom_boxplot() +
labs(title = "Daily Revenue By Version", x = "Variant", y = "Total Revenue") +
theme_minimal()
Box Plot showing Daily Revenue, split by each version. Version 1 has
highest variability, but median very similar across all versions.
Version 2 has lowest outlier revenue.
anova_q3ai <- aov(total_revenue ~ as.factor(variant), data = daily_revenue)
summary(anova_q3ai)
ANOVA test shows that there is no statistically significant
difference between the 3 versions daily revenue.
User behavior difference between the different versions
Q3aii1: Is there a difference in single purchase values?
Null Hypothesis: There is no statistically significant difference in
single purchase values between the different versions.
Alternative Hypothesis: There is a statistically significant
difference in single purchase values in at least one version.
hornet$avg_single_purchase_value <- hornet$amt / hornet$nr_purchased
Create average single purchase value column
single_purchase_summary <- hornet %>%
group_by(variant) %>%
summarise(
mean_purchase_value = mean(avg_single_purchase_value, na.rm = TRUE),
median_purchase_value = median(avg_single_purchase_value, na.rm = TRUE)
) %>%
pivot_longer(cols = c(mean_purchase_value, median_purchase_value),
names_to = "Metric", values_to = "Value")
Create summary table, showing mean & median single purchase
values. Pivot longer to be able to plot grouped bar graph.
ggplot(single_purchase_summary, aes(x = as.factor(variant), y = Value, fill = Metric)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Mean & Median Single Purchase Value by Version",
x = "Version",
y = "Purchase Value") +
theme_minimal()
Bar graph showing mean & median single purchase values by
version. Version 3 has highest mean appearing to be a couple cents
higher than v1 and v2. Median appears similar across all versions,
supporting previous graphs findings of differing distributions across
versions.
anova_q3aii1 <- aov(avg_single_purchase_value ~ as.factor(variant), data = hornet)
summary(anova_q3aii1)
ANOVA shows P-value not statistically significant - fail to reject
null hypothesis and conclude that there is no evidence that single
purchase values differ significantly.
Q3aii2: Is there a difference in number of purchases?
Null Hypothesis: There is no statistically significant difference in
number of purchases between the different versions.
Alternative Hypothesis: There is a statistically significant
difference in number of purchases in at least one version.
num_purchases_summary <- hornet %>%
group_by(variant) %>%
summarise(mean_nr_purchases = mean(nr_purchased, na.rm = TRUE),
median_nr_purchases = median(nr_purchased, na.rm = TRUE)
) %>% pivot_longer(cols = c(mean_nr_purchases, median_nr_purchases),
names_to = "Metric", values_to = "Value")
Creating summary table showing mean & median nr of purchases by
version.
ggplot(num_purchases_summary, aes(x = as.factor(variant), y = Value, fill = Metric)) +
geom_bar(stat = "identity", position = "dodge") +
labs(title = "Mean & Median Number of Purchases by Version",
x = "Version",
y = "Nr Purchases") +
theme_minimal()
Create bar graph showing mean & median nr of purchases by
version. Fewest purchases in version 2. v1 & v3 appear to have a
similar nr of purchases.
anova_q3aii2 <- aov(nr_purchased ~ as.factor(variant), data = hornet)
summary(anova_q3aii2)
ANOVA test shows extremely strong evidence that number of purchases
is statistically significantly different (p-value < 0.0001).
Therefore, reject null hypothesis and conclude that there is a
statistically significant difference in number of purchases in at least
one version.
tukey_test <- TukeyHSD(anova_q3aii2)
print(tukey_test)
Use Tukey Test to confirm that version 1 & 3 perform similarly in
nr of purchases, and both perform better than version 2.
Q3iii: Retention Rates
Null Hypothesis: There is no statistically significant difference in
retention rates between the different versions.
Alternative Hypothesis: There is a statistically significant
difference in retention rates in at least one version.
first_purchase <- hornet %>%
group_by(userid) %>%
summarise(first_purchase_date = min(date))
Create table showing each userid’s 1st purchase by version.
hornet <- hornet %>%
left_join(first_purchase, by = "userid")
Left Join onto original table using key userid, to add the
first_purchase as a column
hornet$retained <- hornet$date > hornet$first_purchase_date
Create a binary retained column, to indicate whether a user had an
additional purchase after the 1st purchase
retention_summary <- hornet %>%
group_by(variant) %>%
summarise(
total_users = n_distinct(userid),
retained_users = sum(retained, na.rm = TRUE),
retention_rate = retained_users / total_users
)
print(retention_summary)
Summary table showing total users by version, retained users by
version, and then each version’s retention rate. Version 3 having
highest retention rate (58.7%), followed by version 1 (55.0%) and
version 2 (53.7%)
n_distinct(hornet$userid)
user_variant_counts <- hornet %>%
group_by(userid) %>%
summarise(variant_count = n_distinct(variant))
Check: Some userid’s appear in multiple versions, explains why sum of
total distinct users split by versions (52 281) > than sum of total
distinct users (50 397)
retention_table <- table(hornet$variant, hornet$retained)
print(retention_table)
Create retention table to be able to use in bar graph.
ggplot(retention_summary, aes(x = as.factor(variant), y = retention_rate, fill = as.factor(variant))) +
geom_bar(stat = "identity") +
labs(title = "Retention Rate by Variant",
x = "Variant",
y = "Retention Rate") +
theme_minimal()
Bar graph showing retention rates by version (1 being 100%).
chisq_result <- chisq.test(retention_table)
print(chisq_result)
Chi Square test shows extremely statistically significant evidence
that there is difference in retention rates (p-value < 0.0001)
between the different versions. Therefore, reject null hypothesis and
conclude that there is a statistically significant difference in at
least one version. Version 3 has the highest retention rate.
Final thoughts:
Is there a difference between the different versions regarding daily
revenue brought in by the feature? No
Is there a difference in single purchase values? No
Is there a difference in number of purchases? Yes
Is there a difference in Retention Rates? Yes
There is no strong evidence that there is a difference between
versions in terms of daily revenue and single purchase values. However,
in number of purchases, there is very strong evidence that v1 & v3
outperform v2. And in retention rates, there is very strong evidence
that v3 outperforms both v2 & v1.
Further analysis needs to be done to conclusively say that v3 should
be rolled out to users, and depends on what metrics Hornet is attempting
to drive. But provisional analysis indicates that v3 performs the
best.
LS0tCnRpdGxlOiAiSG9ybmV0IEFzc2Vzc21lbnQiCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KCgpIaSwgcGxlYXNlIGZpbmQgZmluYWwgdGhvdWdodHMgYXQgdGhlIGVuZCBvZiBhbmFseXNpcy4KCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQoKbGlicmFyeSh0aWR5dmVyc2UpCmBgYApJbnN0YWxsaW5nIG5lY2Vzc2FyeSBwYWNrYWdlcyAoSW4gdGhpcyBjYXNlLCB0aWR5dmVyc2Ugc2hvdWxkIGRvIHRoZSB0cmljaykKCgpgYGB7cn0KaG9ybmV0IDwtIHJlYWQuY3N2KCJhYmNfdGVzdF9kYXRhLmNzdiIpCgp2aWV3KGhvcm5ldCkKZ2xpbXBzZShob3JuZXQpCmBgYApMb2FkIHRoZSBkYXRhc2V0IGludG8gdGhlIFIgZW52aXJvbm1lbnQsIHF1aWNrIG92ZXJ2aWV3IHRvIGNoZWNrIGlmIGl0IGhhcyBsb2FkZWQgcHJvcGVybHkgYW5kIHdoYXQgZGF0YSB0eXBlcyB0aGUgZmllbGRzIGFyZSBjb2RlZCBhcy4gCgoKYGBge3J9Cmhvcm5ldCA8LSBob3JuZXQgJT4lIHJlbmFtZShkYXRlID0gREFURSkKaG9ybmV0IDwtIGhvcm5ldCAlPiUgcmVuYW1lKGFtdCA9IFRvdGFsX3B1cmNoYXNlZF9hbW91bnQpCmhvcm5ldCA8LSBob3JuZXQgJT4lIHJlbmFtZShucl9wdXJjaGFzZWQgPSBQdXJjaGFzZXMpCmBgYApSZW5hbWUgdmFyaWFibGVzIGZvciBlYXNpZXIgdXNhZ2UgdGhyb3VnaG91dCBzY3JpcHQgKG5vdCBhIGZhbiBvZiBjYXBpdGFscykKCgpgYGB7cn0KaG9ybmV0MiA8LSBob3JuZXQKYGBgCkNyZWF0ZSBhIGR1cGxpY2F0ZSBkYXRhc2V0IGFzIGEgdGVzdCBiZWZvcmUgYXBwbHlpbmcgY2hhbmdlcyB0byBtYWluIGRhdGFzZXQuCgoKYGBge3J9Cgpob3JuZXQkZGF0ZSA8LSBhcy5EYXRlKGhvcm5ldCRkYXRlLCBmb3JtYXQgPSAiJVkvJW0vJWQiKQoKaG9ybmV0JGFtdCA8LSBnc3ViKCIsIiwgIi4iLCBob3JuZXQkYW10KQoKaG9ybmV0JGFtdCA8LSBhcy5udW1lcmljKGhvcm5ldCRhbXQpCgpnbGltcHNlKGhvcm5ldCkKICAgIApzdW0oaXMubmEoaG9ybmV0JGFtdCkpCmBgYApDb252ZXJ0aW5nIHRvIGNvcnJlY3QgZGF0YSB0eXBlcywgYW5kIGNvbmZpcm1pbmcgaXQgaGFzIHB1bGxlZCB0aHJvdWdoIGNvcnJlY3RseS4KCgpOb3csIG9uIHRvIGFuc3dlcmluZyB0aGUgcXVlc3Rpb25zLgoKCgpRM2EuaTogSXMgdGhlcmUgYSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGRpZmZlcmVudCB2ZXJzaW9ucyByZWdhcmRpbmcgZGFpbHkKcmV2ZW51ZSBicm91Z2h0IGluIGJ5IHRoZSBmZWF0dXJlPwoKCmBgYHtyfQoKZGFpbHlfcmV2ZW51ZSA8LSBob3JuZXQgJT4lCiAgZ3JvdXBfYnkoZGF0ZSwgdmFyaWFudCkgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX3JldmVudWUgPSBzdW0oYW10LCBuYS5ybSA9IFRSVUUpKQoKc3VtbWFyeShkYWlseV9yZXZlbnVlKQpgYGAKQ3JlYXRlIHRhYmxlIHNob3dpbmcgdG90YWwgcmV2ZW51ZSBwZXIgZGF5LCBzcGxpdCBieSBlYWNoIHZlcnNpb24KCgoKCmBgYHtyfQpnZ3Bsb3QoZGFpbHlfcmV2ZW51ZSwgYWVzKHggPSBkYXRlLCB5ID0gdG90YWxfcmV2ZW51ZSwgY29sb3IgPSBhcy5mYWN0b3IodmFyaWFudCkpKSArCiAgZ2VvbV9saW5lKCkgKwogIGxhYnModGl0bGUgPSAiRGFpbHkgUmV2ZW51ZSBieSBWZXJzaW9uIiwgeCA9ICJEYXRlIiwgeSA9ICJUb3RhbCBSZXZlbnVlIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKTGluZSBncmFwaCBzaG93aW5nIERhaWx5IFJldmVudWUsIHNwbGl0IGJ5IGVhY2ggdmVyc2lvbi4gU2ltaWxhciB0cmVuZCBsaW5lIGZvciBhbGwgdmVyc2lvbnMsIG5vIG5vdGFibGUgZGlmZmVyZW5jZXMuIFZlcnNpb24gMyBhcHBlYXJzIHRvIGJlIHRoZSBvbmx5IG9uZSB3aXRoIHB1cmNoYXNlcyBvbiBsYXN0IGRheSAoTWF5IDE3dGgpLCBidXQgYXBwZWFycyB0byBiZSBzdGF0aXN0aWNhbGx5IGluc2lnbmlmaWNhbnQgKE9uIGZ1cnRoZXIgaW5zcGVjdGlvbiBpbiBFeGNlbCwgdG90YWwgYW1vdW50ZWQgdG8gYXBwcm94aW1hdGVseSA2NzApLgoKCmBgYHtyfQpnZ3Bsb3QoZGFpbHlfcmV2ZW51ZSwgYWVzKHggPSBhcy5mYWN0b3IodmFyaWFudCksIHkgPSB0b3RhbF9yZXZlbnVlLCBmaWxsID0gYXMuZmFjdG9yKHZhcmlhbnQpKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKHRpdGxlID0gIkRhaWx5IFJldmVudWUgQnkgVmVyc2lvbiIsIHggPSAiVmFyaWFudCIsIHkgPSAiVG90YWwgUmV2ZW51ZSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCkJveCBQbG90IHNob3dpbmcgRGFpbHkgUmV2ZW51ZSwgc3BsaXQgYnkgZWFjaCB2ZXJzaW9uLiBWZXJzaW9uIDEgaGFzIGhpZ2hlc3QgdmFyaWFiaWxpdHksIGJ1dCBtZWRpYW4gdmVyeSBzaW1pbGFyIGFjcm9zcyBhbGwgdmVyc2lvbnMuIFZlcnNpb24gMiBoYXMgbG93ZXN0IG91dGxpZXIgcmV2ZW51ZS4KCgoKCmBgYHtyfQphbm92YV9xM2FpIDwtIGFvdih0b3RhbF9yZXZlbnVlIH4gYXMuZmFjdG9yKHZhcmlhbnQpLCBkYXRhID0gZGFpbHlfcmV2ZW51ZSkKc3VtbWFyeShhbm92YV9xM2FpKQpgYGAKQU5PVkEgdGVzdCBzaG93cyB0aGF0IHRoZXJlIGlzIG5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSAzIHZlcnNpb25zIGRhaWx5IHJldmVudWUuCgoKClVzZXIgYmVoYXZpb3IgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgdmVyc2lvbnMKCgpRM2FpaTE6IElzIHRoZXJlIGEgZGlmZmVyZW5jZSBpbiBzaW5nbGUgcHVyY2hhc2UgdmFsdWVzPwoKTnVsbCBIeXBvdGhlc2lzOiBUaGVyZSBpcyBubyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGRpZmZlcmVuY2UgaW4gc2luZ2xlIHB1cmNoYXNlIHZhbHVlcyBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgdmVyc2lvbnMuCgpBbHRlcm5hdGl2ZSBIeXBvdGhlc2lzOiBUaGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBzaW5nbGUgcHVyY2hhc2UgdmFsdWVzIGluIGF0IGxlYXN0IG9uZSB2ZXJzaW9uLgoKCgpgYGB7cn0KaG9ybmV0JGF2Z19zaW5nbGVfcHVyY2hhc2VfdmFsdWUgPC0gaG9ybmV0JGFtdCAvIGhvcm5ldCRucl9wdXJjaGFzZWQKYGBgCkNyZWF0ZSBhdmVyYWdlIHNpbmdsZSBwdXJjaGFzZSB2YWx1ZSBjb2x1bW4KCgpgYGB7cn0Kc2luZ2xlX3B1cmNoYXNlX3N1bW1hcnkgPC0gaG9ybmV0ICU+JQogIGdyb3VwX2J5KHZhcmlhbnQpICU+JQogIHN1bW1hcmlzZSgKICAgIG1lYW5fcHVyY2hhc2VfdmFsdWUgPSBtZWFuKGF2Z19zaW5nbGVfcHVyY2hhc2VfdmFsdWUsIG5hLnJtID0gVFJVRSksCiAgICBtZWRpYW5fcHVyY2hhc2VfdmFsdWUgPSBtZWRpYW4oYXZnX3NpbmdsZV9wdXJjaGFzZV92YWx1ZSwgbmEucm0gPSBUUlVFKQogICkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKG1lYW5fcHVyY2hhc2VfdmFsdWUsIG1lZGlhbl9wdXJjaGFzZV92YWx1ZSksIAogICAgICAgICAgICAgICBuYW1lc190byA9ICJNZXRyaWMiLCB2YWx1ZXNfdG8gPSAiVmFsdWUiKQpgYGAKQ3JlYXRlIHN1bW1hcnkgdGFibGUsIHNob3dpbmcgbWVhbiAmIG1lZGlhbiBzaW5nbGUgcHVyY2hhc2UgdmFsdWVzLiBQaXZvdCBsb25nZXIgdG8gYmUgYWJsZSB0byBwbG90IGdyb3VwZWQgYmFyIGdyYXBoLgoKCmBgYHtyfQpnZ3Bsb3Qoc2luZ2xlX3B1cmNoYXNlX3N1bW1hcnksIGFlcyh4ID0gYXMuZmFjdG9yKHZhcmlhbnQpLCB5ID0gVmFsdWUsIGZpbGwgPSBNZXRyaWMpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnModGl0bGUgPSAiTWVhbiAmIE1lZGlhbiBTaW5nbGUgUHVyY2hhc2UgVmFsdWUgYnkgVmVyc2lvbiIsCiAgICAgICB4ID0gIlZlcnNpb24iLAogICAgICAgeSA9ICJQdXJjaGFzZSBWYWx1ZSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCkJhciBncmFwaCBzaG93aW5nIG1lYW4gJiBtZWRpYW4gc2luZ2xlIHB1cmNoYXNlIHZhbHVlcyBieSB2ZXJzaW9uLiBWZXJzaW9uIDMgaGFzIGhpZ2hlc3QgbWVhbiBhcHBlYXJpbmcgdG8gYmUgYSBjb3VwbGUgY2VudHMgaGlnaGVyIHRoYW4gdjEgYW5kIHYyLiBNZWRpYW4gYXBwZWFycyBzaW1pbGFyIGFjcm9zcyBhbGwgdmVyc2lvbnMsIHN1cHBvcnRpbmcgcHJldmlvdXMgZ3JhcGhzIGZpbmRpbmdzIG9mIGRpZmZlcmluZyBkaXN0cmlidXRpb25zIGFjcm9zcyB2ZXJzaW9ucy4KCgoKCmBgYHtyfQphbm92YV9xM2FpaTEgPC0gYW92KGF2Z19zaW5nbGVfcHVyY2hhc2VfdmFsdWUgfiBhcy5mYWN0b3IodmFyaWFudCksIGRhdGEgPSBob3JuZXQpCnN1bW1hcnkoYW5vdmFfcTNhaWkxKQpgYGAKQU5PVkEgc2hvd3MgUC12YWx1ZSBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCAtIGZhaWwgdG8gcmVqZWN0IG51bGwgaHlwb3RoZXNpcyBhbmQgY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBubyBldmlkZW5jZSB0aGF0IHNpbmdsZSBwdXJjaGFzZSB2YWx1ZXMgZGlmZmVyIHNpZ25pZmljYW50bHkuCgoKClEzYWlpMjogSXMgdGhlcmUgYSBkaWZmZXJlbmNlIGluIG51bWJlciBvZiBwdXJjaGFzZXM/CgpOdWxsIEh5cG90aGVzaXM6IFRoZXJlIGlzIG5vIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiBudW1iZXIgb2YgcHVyY2hhc2VzIGJldHdlZW4gdGhlIGRpZmZlcmVudCB2ZXJzaW9ucy4KCkFsdGVybmF0aXZlIEh5cG90aGVzaXM6IFRoZXJlIGlzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIG51bWJlciBvZiBwdXJjaGFzZXMgaW4gYXQgbGVhc3Qgb25lIHZlcnNpb24uCgoKYGBge3J9Cm51bV9wdXJjaGFzZXNfc3VtbWFyeSA8LSBob3JuZXQgJT4lIAogIGdyb3VwX2J5KHZhcmlhbnQpICU+JSAKICBzdW1tYXJpc2UobWVhbl9ucl9wdXJjaGFzZXMgPSBtZWFuKG5yX3B1cmNoYXNlZCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVkaWFuX25yX3B1cmNoYXNlcyA9IG1lZGlhbihucl9wdXJjaGFzZWQsIG5hLnJtID0gVFJVRSkKICApICU+JSBwaXZvdF9sb25nZXIoY29scyA9IGMobWVhbl9ucl9wdXJjaGFzZXMsIG1lZGlhbl9ucl9wdXJjaGFzZXMpLCAKICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiTWV0cmljIiwgdmFsdWVzX3RvID0gIlZhbHVlIikKYGBgCkNyZWF0aW5nIHN1bW1hcnkgdGFibGUgc2hvd2luZyBtZWFuICYgbWVkaWFuIG5yIG9mIHB1cmNoYXNlcyBieSB2ZXJzaW9uLgoKCmBgYHtyfQpnZ3Bsb3QobnVtX3B1cmNoYXNlc19zdW1tYXJ5LCBhZXMoeCA9IGFzLmZhY3Rvcih2YXJpYW50KSwgeSA9IFZhbHVlLCBmaWxsID0gTWV0cmljKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBsYWJzKHRpdGxlID0gIk1lYW4gJiBNZWRpYW4gTnVtYmVyIG9mIFB1cmNoYXNlcyBieSBWZXJzaW9uIiwKICAgICAgIHggPSAiVmVyc2lvbiIsCiAgICAgICB5ID0gIk5yIFB1cmNoYXNlcyIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCkNyZWF0ZSBiYXIgZ3JhcGggc2hvd2luZyBtZWFuICYgbWVkaWFuIG5yIG9mIHB1cmNoYXNlcyBieSB2ZXJzaW9uLiBGZXdlc3QgcHVyY2hhc2VzIGluIHZlcnNpb24gMi4gdjEgJiB2MyBhcHBlYXIgdG8gaGF2ZSBhIHNpbWlsYXIgbnIgb2YgcHVyY2hhc2VzLgoKCgoKCgpgYGB7cn0KYW5vdmFfcTNhaWkyIDwtIGFvdihucl9wdXJjaGFzZWQgfiBhcy5mYWN0b3IodmFyaWFudCksIGRhdGEgPSBob3JuZXQpCnN1bW1hcnkoYW5vdmFfcTNhaWkyKQpgYGAKQU5PVkEgdGVzdCBzaG93cyBleHRyZW1lbHkgc3Ryb25nIGV2aWRlbmNlIHRoYXQgbnVtYmVyIG9mIHB1cmNoYXNlcyBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50bHkgZGlmZmVyZW50IChwLXZhbHVlIDwgMC4wMDAxKS4gVGhlcmVmb3JlLCByZWplY3QgbnVsbCBoeXBvdGhlc2lzIGFuZCBjb25jbHVkZSB0aGF0IHRoZXJlIGlzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIG51bWJlciBvZiBwdXJjaGFzZXMgaW4gYXQgbGVhc3Qgb25lIHZlcnNpb24uCgoKCmBgYHtyfQp0dWtleV90ZXN0IDwtIFR1a2V5SFNEKGFub3ZhX3EzYWlpMikKcHJpbnQodHVrZXlfdGVzdCkKYGBgClVzZSBUdWtleSBUZXN0IHRvIGNvbmZpcm0gdGhhdCB2ZXJzaW9uIDEgJiAzIHBlcmZvcm0gc2ltaWxhcmx5IGluIG5yIG9mIHB1cmNoYXNlcywgYW5kIGJvdGggcGVyZm9ybSBiZXR0ZXIgdGhhbiB2ZXJzaW9uIDIuIAoKClEzaWlpOiBSZXRlbnRpb24gUmF0ZXMKCk51bGwgSHlwb3RoZXNpczogVGhlcmUgaXMgbm8gc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIHJldGVudGlvbiByYXRlcyBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgdmVyc2lvbnMuCgpBbHRlcm5hdGl2ZSBIeXBvdGhlc2lzOiBUaGVyZSBpcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBpbiByZXRlbnRpb24gcmF0ZXMgaW4gYXQgbGVhc3Qgb25lIHZlcnNpb24uCgoKCmBgYHtyfQpmaXJzdF9wdXJjaGFzZSA8LSBob3JuZXQgJT4lIAogIGdyb3VwX2J5KHVzZXJpZCkgJT4lIAogIHN1bW1hcmlzZShmaXJzdF9wdXJjaGFzZV9kYXRlID0gbWluKGRhdGUpKQoKYGBgCkNyZWF0ZSB0YWJsZSBzaG93aW5nIGVhY2ggdXNlcmlkJ3MgMXN0IHB1cmNoYXNlIGJ5IHZlcnNpb24uCgoKYGBge3J9Cmhvcm5ldCA8LSBob3JuZXQgJT4lIAogIGxlZnRfam9pbihmaXJzdF9wdXJjaGFzZSwgYnkgPSAidXNlcmlkIikKYGBgCkxlZnQgSm9pbiBvbnRvIG9yaWdpbmFsIHRhYmxlIHVzaW5nIGtleSB1c2VyaWQsIHRvIGFkZCB0aGUgZmlyc3RfcHVyY2hhc2UgYXMgYSBjb2x1bW4KCgpgYGB7cn0KaG9ybmV0JHJldGFpbmVkIDwtIGhvcm5ldCRkYXRlID4gaG9ybmV0JGZpcnN0X3B1cmNoYXNlX2RhdGUKYGBgCkNyZWF0ZSBhIGJpbmFyeSByZXRhaW5lZCBjb2x1bW4sIHRvIGluZGljYXRlIHdoZXRoZXIgYSB1c2VyIGhhZCBhbiBhZGRpdGlvbmFsIHB1cmNoYXNlIGFmdGVyIHRoZSAxc3QgcHVyY2hhc2UKCgpgYGB7cn0KcmV0ZW50aW9uX3N1bW1hcnkgPC0gaG9ybmV0ICU+JSAKICBncm91cF9ieSh2YXJpYW50KSAlPiUgCiAgc3VtbWFyaXNlKAogICAgdG90YWxfdXNlcnMgPSBuX2Rpc3RpbmN0KHVzZXJpZCksCiAgICByZXRhaW5lZF91c2VycyA9IHN1bShyZXRhaW5lZCwgbmEucm0gPSBUUlVFKSwKICAgIHJldGVudGlvbl9yYXRlID0gcmV0YWluZWRfdXNlcnMgLyB0b3RhbF91c2VycwogICkKcHJpbnQocmV0ZW50aW9uX3N1bW1hcnkpCmBgYApTdW1tYXJ5IHRhYmxlIHNob3dpbmcgdG90YWwgdXNlcnMgYnkgdmVyc2lvbiwgcmV0YWluZWQgdXNlcnMgYnkgdmVyc2lvbiwgYW5kIHRoZW4gZWFjaCB2ZXJzaW9uJ3MgcmV0ZW50aW9uIHJhdGUuIFZlcnNpb24gMyBoYXZpbmcgaGlnaGVzdCByZXRlbnRpb24gcmF0ZSAoNTguNyUpLCBmb2xsb3dlZCBieSB2ZXJzaW9uIDEgKDU1LjAlKSBhbmQgdmVyc2lvbiAyICg1My43JSkKCgoKCgoKYGBge3J9Cm5fZGlzdGluY3QoaG9ybmV0JHVzZXJpZCkKCnVzZXJfdmFyaWFudF9jb3VudHMgPC0gaG9ybmV0ICU+JQogIGdyb3VwX2J5KHVzZXJpZCkgJT4lCiAgc3VtbWFyaXNlKHZhcmlhbnRfY291bnQgPSBuX2Rpc3RpbmN0KHZhcmlhbnQpKQoKYGBgCkNoZWNrOiBTb21lIHVzZXJpZCdzIGFwcGVhciBpbiBtdWx0aXBsZSB2ZXJzaW9ucywgZXhwbGFpbnMgd2h5IHN1bSBvZiB0b3RhbCBkaXN0aW5jdCB1c2VycyBzcGxpdCBieSB2ZXJzaW9ucyAoNTIgMjgxKSA+IHRoYW4gc3VtIG9mIHRvdGFsIGRpc3RpbmN0IHVzZXJzICg1MCAzOTcpCgoKYGBge3J9CnJldGVudGlvbl90YWJsZSA8LSB0YWJsZShob3JuZXQkdmFyaWFudCwgaG9ybmV0JHJldGFpbmVkKQoKcHJpbnQocmV0ZW50aW9uX3RhYmxlKQpgYGAKQ3JlYXRlIHJldGVudGlvbiB0YWJsZSB0byBiZSBhYmxlIHRvIHVzZSBpbiBiYXIgZ3JhcGguCgoKYGBge3J9CmdncGxvdChyZXRlbnRpb25fc3VtbWFyeSwgYWVzKHggPSBhcy5mYWN0b3IodmFyaWFudCksIHkgPSByZXRlbnRpb25fcmF0ZSwgZmlsbCA9IGFzLmZhY3Rvcih2YXJpYW50KSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGxhYnModGl0bGUgPSAiUmV0ZW50aW9uIFJhdGUgYnkgVmFyaWFudCIsCiAgICAgICB4ID0gIlZhcmlhbnQiLAogICAgICAgeSA9ICJSZXRlbnRpb24gUmF0ZSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCkJhciBncmFwaCBzaG93aW5nIHJldGVudGlvbiByYXRlcyBieSB2ZXJzaW9uICgxIGJlaW5nIDEwMCUpLgoKCgoKYGBge3J9CmNoaXNxX3Jlc3VsdCA8LSBjaGlzcS50ZXN0KHJldGVudGlvbl90YWJsZSkKcHJpbnQoY2hpc3FfcmVzdWx0KQpgYGAKQ2hpIFNxdWFyZSB0ZXN0IHNob3dzIGV4dHJlbWVseSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGV2aWRlbmNlIHRoYXQgdGhlcmUgaXMgZGlmZmVyZW5jZSBpbiByZXRlbnRpb24gcmF0ZXMgKHAtdmFsdWUgPCAwLjAwMDEpIGJldHdlZW4gdGhlIGRpZmZlcmVudCB2ZXJzaW9ucy4gVGhlcmVmb3JlLCByZWplY3QgbnVsbCBoeXBvdGhlc2lzIGFuZCBjb25jbHVkZSB0aGF0IHRoZXJlIGlzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGluIGF0IGxlYXN0IG9uZSB2ZXJzaW9uLiBWZXJzaW9uIDMgaGFzIHRoZSBoaWdoZXN0IHJldGVudGlvbiByYXRlLgoKRmluYWwgdGhvdWdodHM6CgpJcyB0aGVyZSBhIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZGlmZmVyZW50IHZlcnNpb25zIHJlZ2FyZGluZyBkYWlseQpyZXZlbnVlIGJyb3VnaHQgaW4gYnkgdGhlIGZlYXR1cmU/IE5vCgpJcyB0aGVyZSBhIGRpZmZlcmVuY2UgaW4gc2luZ2xlIHB1cmNoYXNlIHZhbHVlcz8gTm8KCklzIHRoZXJlIGEgZGlmZmVyZW5jZSBpbiBudW1iZXIgb2YgcHVyY2hhc2VzPyBZZXMKCklzIHRoZXJlIGEgZGlmZmVyZW5jZSBpbiBSZXRlbnRpb24gUmF0ZXM/IFllcwoKVGhlcmUgaXMgbm8gc3Ryb25nIGV2aWRlbmNlIHRoYXQgdGhlcmUgaXMgYSBkaWZmZXJlbmNlIGJldHdlZW4gdmVyc2lvbnMgaW4gdGVybXMgb2YgZGFpbHkgcmV2ZW51ZSBhbmQgc2luZ2xlIHB1cmNoYXNlIHZhbHVlcy4gCkhvd2V2ZXIsIGluIG51bWJlciBvZiBwdXJjaGFzZXMsIHRoZXJlIGlzIHZlcnkgc3Ryb25nIGV2aWRlbmNlIHRoYXQgdjEgJiB2MyBvdXRwZXJmb3JtIHYyLiAKQW5kIGluIHJldGVudGlvbiByYXRlcywgdGhlcmUgaXMgdmVyeSBzdHJvbmcgZXZpZGVuY2UgdGhhdCB2MyBvdXRwZXJmb3JtcyBib3RoIHYyICYgdjEuIAoKRnVydGhlciBhbmFseXNpcyBuZWVkcyB0byBiZSBkb25lIHRvIGNvbmNsdXNpdmVseSBzYXkgdGhhdCB2MyBzaG91bGQgYmUgcm9sbGVkIG91dCB0byB1c2VycywgYW5kIGRlcGVuZHMgb24gd2hhdCBtZXRyaWNzIEhvcm5ldCBpcyBhdHRlbXB0aW5nIHRvIGRyaXZlLiBCdXQgcHJvdmlzaW9uYWwgYW5hbHlzaXMgaW5kaWNhdGVzIHRoYXQgdjMgcGVyZm9ybXMgdGhlIGJlc3QuCgo=