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=