A/B Testing for ShoeFly.com

Our favorite online shoe store, ShoeFly.com is performing an A/B Test. They have two different versions of an ad, which they have placed in emails, as well as in banner ads on Facebook, Twitter, and Google. They want to know how the two ads are performing on each of the different platforms on each day of the week. Help them analyze the data using aggregate measures.

Analyzing Ad Souces

1.Inspect the first few rows of ad_clicks using head(). What variables are stored in the columns of the data frame?

Click the hint to see a description of the columns of ad_clicks.

# load packages
library(readr)
library(dplyr)
# load ad clicks data
ad_clicks <- read_csv("ad_clicks.csv")
# inspect ad_clicks here:
head(ad_clicks)
ad_clicks

2.Your manager wants to know which ad platform is getting the most views.

How many views (i.e., rows of the data frame) came from each utm_source? Group ad_clicks by utm_source and count the number of rows in each group. Save your result to views_by_utm, and view it.

# define views_by_utm here:
views_by_utm <- ad_clicks %>%
  group_by(utm_source) %>%
  summarize(count = n())

views_by_utm

3.We want to know the percentage of people who clicked on ads from each utm_source. Let’s start by finding the number of clicks per utm_source.

Group ad_clicks by utm_source and ad_clicked and count the number of rows in each group, naming the resulting column count. Save your answer to the variable clicks_by_utm, and view it.

*Hint:

To group together the rows of ad_clicks with the same value for utm_source and ad_clicked with group_by():

clicks_by_utm <- ad_clicks %>%

group_by(utm_source, ad_clicked)

To find the number of rows in each grouping by utm_source and ad_clicked, pipe the result from the grouping into summarize() and use n():

clicks_by_utm <- ad_clicks %>%

group_by(utm_source, ad_clicked) %>%

summarize(count = n())

# define clicks_by_utm here:
clicks_by_utm <- ad_clicks %>%
  group_by(utm_source, ad_clicked) %>%
  summarize(count = n())

clicks_by_utm

4.To find the percentage of people who clicked on ads from each utm_source, we need to add a new column to ad_clicks that stores the count of clicks (or the count of not clicking) divided by the total number of ad views.

Group clicks_by_utm by utm_source and pipe the result into mutate(), creating a new column percentage that is defined as count/sum(count).

Save your result to percentage_by_utm and view it. Open the hint for a description of the percentage_by_utm data frame.

*Hint:

To group together the rows of clicks_by_utm with the same value for utm_source with group_by():

percentage_by_utm <- clicks_by_utm %>%

group_by(utm_source) %>%

To add a column that stores the percentage of users who did or did not click on the ad, pipe the result from the grouping into mutate() and create a new column percentage defined as count/sum(count):

percentage_by_utm <- clicks_by_utm %>%

group_by(utm_source) %>%

mutate(percentage = count/sum(count))

1.count represents the number of users who did or did not click on an ad

2.sum(count) represents the total number of users who saw the ad

percentage_by_utm will now contain the click and non-click rates for each utm_source/ad_clicked

# define percentage_by_utm here:
percentage_by_utm <- clicks_by_utm %>%
  group_by(utm_source) %>%
  mutate(percentage = count/sum(count))

percentage_by_utm

5.Filter percentage_by_utm to remove all rows that do not describe clicked ads, and view it.

Was there a difference in click rates for each source?

*Hint

percentage_by_utm <-clicks_by_utm %>%
  group_by(utm_source) %>%
  mutate(percentage = count/sum(count)) %>%
  filter(ad_clicked == TRUE)

percentage_by_utm

Analyzing an A/B Test

6.The column experimental_group tells us whether the user was shown ad A or ad B.

Were approximately the same number of people shown both ads? Group ad_clicks by experimental_group and count the rows, saving your result to experiment_split.

View experiment_split to see how users were split across the experiment groups!

# define experiment_split here:
experiment_split <- ad_clicks %>%
  group_by(experimental_group) %>%
  summarize(count = n())

experiment_split

7.Using group_by() and the columns ad_clicked and experimental_group, check to see if a greater number of users clicked on ad A or ad B. Save your result to clicks_by_experiment, and view it.

Reveal the hint to see which ad was more effective.

# define clicks_by_experiment here:
clicks_by_experiment <- ad_clicks %>%
  group_by(ad_clicked, experimental_group) %>%
  summarize(count = n())

clicks_by_experiment

8.The Product Manager for the A/B test thinks that the clicks might have changed by day of the week.

Start by creating two data frames: a_clicks and b_clicks, which contain only the results for A group and B group, respectively.

# define a_clicks here:
a_clicks <- ad_clicks %>%
  filter(experimental_group == 'A')

a_clicks

# define b_clicks here:
b_clicks <- ad_clicks %>%
  filter(experimental_group == 'B')

b_clicks

9.For each data frame (a_clicks and b_clicks), we want to find the number of users who clicked on the ad (and did not click on the ad) by day. Save the results to a_clicks_by_day and b_clicks_by_day, and view them.

# define a_clicks_by_day here:
a_clicks_by_day <- a_clicks %>%
  group_by(day, ad_clicked) %>%
  summarize(count = n())
a_clicks_by_day

# a_clicks_by_day <- a_clicks %>%
b_clicks_by_day <- b_clicks %>%
  group_by(day, ad_clicked) %>%
  summarize(count = n())

b_clicks_by_day

10.To find the percentage of people who clicked on the ads from each day, we need to add a new column to a_clicks_by_day and b_clicks_by_day that stores the count of clicks (or the count of not clicking) divided by the total number of ad views.

Group a_clicks_by_day and b_clicks_by_day by day and pipe the result into mutate(), creating a new column percentage that is defined as count/sum(count).

Save your result to a_percentage_by_day and b_percentage_by_day and view them. Open the hint for a description of these data frames.

# define a_percentage_by_day here:
a_percentage_by_day <- a_clicks_by_day %>%
  group_by(day) %>%
  mutate(percentage = count/sum(count))

a_percentage_by_day

# define b_percentage_by_day here:
b_percentage_by_day <- b_clicks_by_day %>%
  group_by(day) %>%
  mutate(percentage = count/sum(count))

b_percentage_by_day

11.Filter a_percentage_by_day and b_percentage_by_day to remove all rows that do not describe clicked ads, and view them.

Was there a difference in click rates for each day between the two ads? What happened over the course of the week?

Do you recommend that ShoeFly.com use ad A or ad B?

Reveal the hint for our analysis.

# define a_percentage_by_day here:
a_percentage_by_day <- a_clicks_by_day %>%
  group_by(day) %>%
  mutate(percentage = count/sum(count)) %>%
  filter(ad_clicked == TRUE)

a_percentage_by_day

# define b_percentage_by_day here:
b_percentage_by_day <- b_clicks_by_day %>%
  group_by(day) %>%
  mutate(percentage = count/sum(count)) %>%
  filter(ad_clicked == TRUE)

b_percentage_by_day

*Hint:

To filter a_percentage_by_day to only include rows where ads were clicked, pipe the result from the previous task into filter() with the additional argument ad_clicked == TRUE:

a_percentage_by_day <- a_clicks_by_day

group_by(day

mutate(percentage = count/sum(count)) %>%

filter(ad_clicked == TRUE)

LS0tDQp0aXRsZTogIkEvQiBUZXN0aW5nIGZvciBTaG9lRmx5LmNvbSINCmF1dGhvcjogIkFubmFiZWwgS3VvIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJVktJW0tJWQgJUg6JU0nKWAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIEEvQiBUZXN0aW5nIGZvciBTaG9lRmx5LmNvbQ0KT3VyIGZhdm9yaXRlIG9ubGluZSBzaG9lIHN0b3JlLCBTaG9lRmx5LmNvbSBpcyBwZXJmb3JtaW5nIGFuIEEvQiBUZXN0LiBUaGV5IGhhdmUgdHdvIGRpZmZlcmVudCB2ZXJzaW9ucyBvZiBhbiBhZCwgd2hpY2ggdGhleSBoYXZlIHBsYWNlZCBpbiBlbWFpbHMsIGFzIHdlbGwgYXMgaW4gYmFubmVyIGFkcyBvbiBGYWNlYm9vaywgVHdpdHRlciwgYW5kIEdvb2dsZS4gVGhleSB3YW50IHRvIGtub3cgaG93IHRoZSB0d28gYWRzIGFyZSBwZXJmb3JtaW5nIG9uIGVhY2ggb2YgdGhlIGRpZmZlcmVudCBwbGF0Zm9ybXMgb24gZWFjaCBkYXkgb2YgdGhlIHdlZWsuIEhlbHAgdGhlbSBhbmFseXplIHRoZSBkYXRhIHVzaW5nIGFnZ3JlZ2F0ZSBtZWFzdXJlcy4NCg0KIyBBbmFseXppbmcgQWQgU291Y2VzDQoxLkluc3BlY3QgdGhlIGZpcnN0IGZldyByb3dzIG9mIGFkX2NsaWNrcyB1c2luZyBoZWFkKCkuIFdoYXQgdmFyaWFibGVzIGFyZSBzdG9yZWQgaW4gdGhlIGNvbHVtbnMgb2YgdGhlIGRhdGEgZnJhbWU/DQoNCkNsaWNrIHRoZSBoaW50IHRvIHNlZSBhIGRlc2NyaXB0aW9uIG9mIHRoZSBjb2x1bW5zIG9mIGFkX2NsaWNrcy4NCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCBlcnJvcj1UUlVFfQ0KIyBsb2FkIHBhY2thZ2VzDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmBgYA0KDQpgYGB7ciBtZXNzYWdlID0gRkFMU0UsIGVycm9yPVRSVUV9DQojIGxvYWQgYWQgY2xpY2tzIGRhdGENCmFkX2NsaWNrcyA8LSByZWFkX2NzdigiYWRfY2xpY2tzLmNzdiIpDQpgYGANCg0KYGBge3IgZXJyb3I9VFJVRX0NCiMgaW5zcGVjdCBhZF9jbGlja3MgaGVyZToNCmhlYWQoYWRfY2xpY2tzKQ0KYWRfY2xpY2tzDQpgYGANCg0KMi5Zb3VyIG1hbmFnZXIgd2FudHMgdG8ga25vdyB3aGljaCBhZCBwbGF0Zm9ybSBpcyBnZXR0aW5nIHRoZSBtb3N0IHZpZXdzLg0KDQpIb3cgbWFueSB2aWV3cyAoaS5lLiwgcm93cyBvZiB0aGUgZGF0YSBmcmFtZSkgY2FtZSBmcm9tIGVhY2ggdXRtX3NvdXJjZT8gR3JvdXAgYWRfY2xpY2tzIGJ5IHV0bV9zb3VyY2UgYW5kIGNvdW50IHRoZSBudW1iZXIgb2Ygcm93cyBpbiBlYWNoIGdyb3VwLiBTYXZlIHlvdXIgcmVzdWx0IHRvIHZpZXdzX2J5X3V0bSwgYW5kIHZpZXcgaXQuDQoNCmBgYHtyIGVycm9yPVRSVUV9DQojIGRlZmluZSB2aWV3c19ieV91dG0gaGVyZToNCnZpZXdzX2J5X3V0bSA8LSBhZF9jbGlja3MgJT4lDQogIGdyb3VwX2J5KHV0bV9zb3VyY2UpICU+JQ0KICBzdW1tYXJpemUoY291bnQgPSBuKCkpDQoNCnZpZXdzX2J5X3V0bQ0KYGBgDQoNCg0KMy5XZSB3YW50IHRvIGtub3cgdGhlIHBlcmNlbnRhZ2Ugb2YgcGVvcGxlIHdobyBjbGlja2VkIG9uIGFkcyBmcm9tIGVhY2ggdXRtX3NvdXJjZS4gTGV04oCZcyBzdGFydCBieSBmaW5kaW5nIHRoZSBudW1iZXIgb2YgY2xpY2tzIHBlciB1dG1fc291cmNlLg0KDQpHcm91cCBhZF9jbGlja3MgYnkgdXRtX3NvdXJjZSBhbmQgYWRfY2xpY2tlZCBhbmQgY291bnQgdGhlIG51bWJlciBvZiByb3dzIGluIGVhY2ggZ3JvdXAsIG5hbWluZyB0aGUgcmVzdWx0aW5nIGNvbHVtbiBjb3VudC4gU2F2ZSB5b3VyIGFuc3dlciB0byB0aGUgdmFyaWFibGUgY2xpY2tzX2J5X3V0bSwgYW5kIHZpZXcgaXQuDQoNCipIaW50Og0KDQpUbyBncm91cCB0b2dldGhlciB0aGUgcm93cyBvZiBhZF9jbGlja3Mgd2l0aCB0aGUgc2FtZSB2YWx1ZSBmb3IgdXRtX3NvdXJjZSBhbmQgYWRfY2xpY2tlZCB3aXRoIGdyb3VwX2J5KCk6DQoNCiINCg0KY2xpY2tzX2J5X3V0bSA8LSBhZF9jbGlja3MgJT4lDQoNCiAgZ3JvdXBfYnkodXRtX3NvdXJjZSwgYWRfY2xpY2tlZCkNCg0KIg0KDQpUbyBmaW5kIHRoZSBudW1iZXIgb2Ygcm93cyBpbiBlYWNoIGdyb3VwaW5nIGJ5IHV0bV9zb3VyY2UgYW5kIGFkX2NsaWNrZWQsIHBpcGUgdGhlIHJlc3VsdCBmcm9tIHRoZSBncm91cGluZyBpbnRvIHN1bW1hcml6ZSgpIGFuZCB1c2UgbigpOg0KDQoiDQoNCmNsaWNrc19ieV91dG0gPC0gYWRfY2xpY2tzICU+JQ0KDQogIGdyb3VwX2J5KHV0bV9zb3VyY2UsIGFkX2NsaWNrZWQpICU+JQ0KICANCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKQ0KDQoiDQoNCg0KDQpgYGB7ciBlcnJvcj1UUlVFfQ0KIyBkZWZpbmUgY2xpY2tzX2J5X3V0bSBoZXJlOg0KY2xpY2tzX2J5X3V0bSA8LSBhZF9jbGlja3MgJT4lDQogIGdyb3VwX2J5KHV0bV9zb3VyY2UsIGFkX2NsaWNrZWQpICU+JQ0KICBzdW1tYXJpemUoY291bnQgPSBuKCkpDQoNCmNsaWNrc19ieV91dG0NCmBgYA0KDQo0LlRvIGZpbmQgdGhlIHBlcmNlbnRhZ2Ugb2YgcGVvcGxlIHdobyBjbGlja2VkIG9uIGFkcyBmcm9tIGVhY2ggdXRtX3NvdXJjZSwgd2UgbmVlZCB0byBhZGQgYSBuZXcgY29sdW1uIHRvIGFkX2NsaWNrcyB0aGF0IHN0b3JlcyB0aGUgY291bnQgb2YgY2xpY2tzIChvciB0aGUgY291bnQgb2Ygbm90IGNsaWNraW5nKSBkaXZpZGVkIGJ5IHRoZSB0b3RhbCBudW1iZXIgb2YgYWQgdmlld3MuDQoNCkdyb3VwIGNsaWNrc19ieV91dG0gYnkgdXRtX3NvdXJjZSBhbmQgcGlwZSB0aGUgcmVzdWx0IGludG8gbXV0YXRlKCksIGNyZWF0aW5nIGEgbmV3IGNvbHVtbiBwZXJjZW50YWdlIHRoYXQgaXMgZGVmaW5lZCBhcyBjb3VudC9zdW0oY291bnQpLg0KDQpTYXZlIHlvdXIgcmVzdWx0IHRvIHBlcmNlbnRhZ2VfYnlfdXRtIGFuZCB2aWV3IGl0LiBPcGVuIHRoZSBoaW50IGZvciBhIGRlc2NyaXB0aW9uIG9mIHRoZSBwZXJjZW50YWdlX2J5X3V0bSBkYXRhIGZyYW1lLg0KDQoqSGludDogDQoNClRvIGdyb3VwIHRvZ2V0aGVyIHRoZSByb3dzIG9mIGNsaWNrc19ieV91dG0gd2l0aCB0aGUgc2FtZSB2YWx1ZSBmb3IgdXRtX3NvdXJjZSB3aXRoIGdyb3VwX2J5KCk6DQoNCiINCg0KcGVyY2VudGFnZV9ieV91dG0gPC0gY2xpY2tzX2J5X3V0bSAlPiUNCg0KICBncm91cF9ieSh1dG1fc291cmNlKSAlPiUNCiAgDQoiDQoNClRvIGFkZCBhIGNvbHVtbiB0aGF0IHN0b3JlcyB0aGUgcGVyY2VudGFnZSBvZiB1c2VycyB3aG8gZGlkIG9yIGRpZCBub3QgY2xpY2sgb24gdGhlIGFkLCBwaXBlIHRoZSByZXN1bHQgZnJvbSB0aGUgZ3JvdXBpbmcgaW50byBtdXRhdGUoKSBhbmQgY3JlYXRlIGEgbmV3IGNvbHVtbiBwZXJjZW50YWdlIGRlZmluZWQgYXMgY291bnQvc3VtKGNvdW50KToNCg0KIg0KDQpwZXJjZW50YWdlX2J5X3V0bSA8LSBjbGlja3NfYnlfdXRtICU+JQ0KDQogIGdyb3VwX2J5KHV0bV9zb3VyY2UpICU+JQ0KICANCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBjb3VudC9zdW0oY291bnQpKQ0KDQoiDQoNCjEuY291bnQgcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIHVzZXJzIHdobyBkaWQgb3IgZGlkIG5vdCBjbGljayBvbiBhbiBhZA0KDQoyLnN1bShjb3VudCkgcmVwcmVzZW50cyB0aGUgdG90YWwgbnVtYmVyIG9mIHVzZXJzIHdobyBzYXcgdGhlIGFkDQoNCnBlcmNlbnRhZ2VfYnlfdXRtIHdpbGwgbm93IGNvbnRhaW4gdGhlIGNsaWNrIGFuZCBub24tY2xpY2sgcmF0ZXMgZm9yIGVhY2ggdXRtX3NvdXJjZS9hZF9jbGlja2VkIA0KDQpgYGB7ciBlcnJvcj1UUlVFfQ0KIyBkZWZpbmUgcGVyY2VudGFnZV9ieV91dG0gaGVyZToNCnBlcmNlbnRhZ2VfYnlfdXRtIDwtIGNsaWNrc19ieV91dG0gJT4lDQogIGdyb3VwX2J5KHV0bV9zb3VyY2UpICU+JQ0KICBtdXRhdGUocGVyY2VudGFnZSA9IGNvdW50L3N1bShjb3VudCkpDQoNCnBlcmNlbnRhZ2VfYnlfdXRtDQpgYGANCg0KNS5GaWx0ZXIgcGVyY2VudGFnZV9ieV91dG0gdG8gcmVtb3ZlIGFsbCByb3dzIHRoYXQgZG8gbm90IGRlc2NyaWJlIGNsaWNrZWQgYWRzLCBhbmQgdmlldyBpdC4NCg0KV2FzIHRoZXJlIGEgZGlmZmVyZW5jZSBpbiBjbGljayByYXRlcyBmb3IgZWFjaCBzb3VyY2U/DQoNCipIaW50DQpgYGB7cn0NCnBlcmNlbnRhZ2VfYnlfdXRtIDwtY2xpY2tzX2J5X3V0bSAlPiUNCiAgZ3JvdXBfYnkodXRtX3NvdXJjZSkgJT4lDQogIG11dGF0ZShwZXJjZW50YWdlID0gY291bnQvc3VtKGNvdW50KSkgJT4lDQogIGZpbHRlcihhZF9jbGlja2VkID09IFRSVUUpDQoNCnBlcmNlbnRhZ2VfYnlfdXRtDQpgYGANCg0KIyBBbmFseXppbmcgYW4gQS9CIFRlc3QNCg0KNi5UaGUgY29sdW1uIGV4cGVyaW1lbnRhbF9ncm91cCB0ZWxscyB1cyB3aGV0aGVyIHRoZSB1c2VyIHdhcyBzaG93biBhZCBBIG9yIGFkIEIuDQoNCldlcmUgYXBwcm94aW1hdGVseSB0aGUgc2FtZSBudW1iZXIgb2YgcGVvcGxlIHNob3duIGJvdGggYWRzPyBHcm91cCBhZF9jbGlja3MgYnkgZXhwZXJpbWVudGFsX2dyb3VwIGFuZCBjb3VudCB0aGUgcm93cywgc2F2aW5nIHlvdXIgcmVzdWx0IHRvIGV4cGVyaW1lbnRfc3BsaXQuDQoNClZpZXcgZXhwZXJpbWVudF9zcGxpdCB0byBzZWUgaG93IHVzZXJzIHdlcmUgc3BsaXQgYWNyb3NzIHRoZSBleHBlcmltZW50IGdyb3VwcyENCg0KYGBge3IgZXJyb3I9VFJVRX0NCiMgZGVmaW5lIGV4cGVyaW1lbnRfc3BsaXQgaGVyZToNCmV4cGVyaW1lbnRfc3BsaXQgPC0gYWRfY2xpY2tzICU+JQ0KICBncm91cF9ieShleHBlcmltZW50YWxfZ3JvdXApICU+JQ0KICBzdW1tYXJpemUoY291bnQgPSBuKCkpDQoNCmV4cGVyaW1lbnRfc3BsaXQNCmBgYA0KDQo3LlVzaW5nIGdyb3VwX2J5KCkgYW5kIHRoZSBjb2x1bW5zIGFkX2NsaWNrZWQgYW5kIGV4cGVyaW1lbnRhbF9ncm91cCwgY2hlY2sgdG8gc2VlIGlmIGEgZ3JlYXRlciBudW1iZXIgb2YgdXNlcnMgY2xpY2tlZCBvbiBhZCBBIG9yIGFkIEIuIFNhdmUgeW91ciByZXN1bHQgdG8gY2xpY2tzX2J5X2V4cGVyaW1lbnQsIGFuZCB2aWV3IGl0Lg0KDQpSZXZlYWwgdGhlIGhpbnQgdG8gc2VlIHdoaWNoIGFkIHdhcyBtb3JlIGVmZmVjdGl2ZS4NCg0KYGBge3IgZXJyb3I9VFJVRX0NCiMgZGVmaW5lIGNsaWNrc19ieV9leHBlcmltZW50IGhlcmU6DQpjbGlja3NfYnlfZXhwZXJpbWVudCA8LSBhZF9jbGlja3MgJT4lDQogIGdyb3VwX2J5KGFkX2NsaWNrZWQsIGV4cGVyaW1lbnRhbF9ncm91cCkgJT4lDQogIHN1bW1hcml6ZShjb3VudCA9IG4oKSkNCg0KY2xpY2tzX2J5X2V4cGVyaW1lbnQNCmBgYA0KDQo4LlRoZSBQcm9kdWN0IE1hbmFnZXIgZm9yIHRoZSBBL0IgdGVzdCB0aGlua3MgdGhhdCB0aGUgY2xpY2tzIG1pZ2h0IGhhdmUgY2hhbmdlZCBieSBkYXkgb2YgdGhlIHdlZWsuDQoNClN0YXJ0IGJ5IGNyZWF0aW5nIHR3byBkYXRhIGZyYW1lczogYV9jbGlja3MgYW5kIGJfY2xpY2tzLCB3aGljaCBjb250YWluIG9ubHkgdGhlIHJlc3VsdHMgZm9yIEEgZ3JvdXAgYW5kIEIgZ3JvdXAsIHJlc3BlY3RpdmVseS4NCg0KYGBge3IgZXJyb3I9VFJVRX0NCiMgZGVmaW5lIGFfY2xpY2tzIGhlcmU6DQphX2NsaWNrcyA8LSBhZF9jbGlja3MgJT4lDQogIGZpbHRlcihleHBlcmltZW50YWxfZ3JvdXAgPT0gJ0EnKQ0KDQphX2NsaWNrcw0KDQojIGRlZmluZSBiX2NsaWNrcyBoZXJlOg0KYl9jbGlja3MgPC0gYWRfY2xpY2tzICU+JQ0KICBmaWx0ZXIoZXhwZXJpbWVudGFsX2dyb3VwID09ICdCJykNCg0KYl9jbGlja3MNCmBgYA0KDQo5LkZvciBlYWNoIGRhdGEgZnJhbWUgKGFfY2xpY2tzIGFuZCBiX2NsaWNrcyksIHdlIHdhbnQgdG8gZmluZCB0aGUgbnVtYmVyIG9mIHVzZXJzIHdobyBjbGlja2VkIG9uIHRoZSBhZCAoYW5kIGRpZCBub3QgY2xpY2sgb24gdGhlIGFkKSBieSBkYXkuIFNhdmUgdGhlIHJlc3VsdHMgdG8gYV9jbGlja3NfYnlfZGF5IGFuZCBiX2NsaWNrc19ieV9kYXksIGFuZCB2aWV3IHRoZW0uDQoNCmBgYHtyIGVycm9yPVRSVUV9DQojIGRlZmluZSBhX2NsaWNrc19ieV9kYXkgaGVyZToNCmFfY2xpY2tzX2J5X2RheSA8LSBhX2NsaWNrcyAlPiUNCiAgZ3JvdXBfYnkoZGF5LCBhZF9jbGlja2VkKSAlPiUNCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKQ0KYV9jbGlja3NfYnlfZGF5DQoNCiMgYV9jbGlja3NfYnlfZGF5IDwtIGFfY2xpY2tzICU+JQ0KYl9jbGlja3NfYnlfZGF5IDwtIGJfY2xpY2tzICU+JQ0KICBncm91cF9ieShkYXksIGFkX2NsaWNrZWQpICU+JQ0KICBzdW1tYXJpemUoY291bnQgPSBuKCkpDQoNCmJfY2xpY2tzX2J5X2RheQ0KYGBgDQoNCg0KMTAuVG8gZmluZCB0aGUgcGVyY2VudGFnZSBvZiBwZW9wbGUgd2hvIGNsaWNrZWQgb24gdGhlIGFkcyBmcm9tIGVhY2ggZGF5LCB3ZSBuZWVkIHRvIGFkZCBhIG5ldyBjb2x1bW4gdG8gYV9jbGlja3NfYnlfZGF5IGFuZCBiX2NsaWNrc19ieV9kYXkgdGhhdCBzdG9yZXMgdGhlIGNvdW50IG9mIGNsaWNrcyAob3IgdGhlIGNvdW50IG9mIG5vdCBjbGlja2luZykgZGl2aWRlZCBieSB0aGUgdG90YWwgbnVtYmVyIG9mIGFkIHZpZXdzLg0KDQpHcm91cCBhX2NsaWNrc19ieV9kYXkgYW5kIGJfY2xpY2tzX2J5X2RheSBieSBkYXkgYW5kIHBpcGUgdGhlIHJlc3VsdCBpbnRvIG11dGF0ZSgpLCBjcmVhdGluZyBhIG5ldyBjb2x1bW4gcGVyY2VudGFnZSB0aGF0IGlzIGRlZmluZWQgYXMgY291bnQvc3VtKGNvdW50KS4NCg0KU2F2ZSB5b3VyIHJlc3VsdCB0byBhX3BlcmNlbnRhZ2VfYnlfZGF5IGFuZCBiX3BlcmNlbnRhZ2VfYnlfZGF5IGFuZCB2aWV3IHRoZW0uIE9wZW4gdGhlIGhpbnQgZm9yIGEgZGVzY3JpcHRpb24gb2YgdGhlc2UgZGF0YSBmcmFtZXMuDQoNCmBgYHtyIGVycm9yPVRSVUV9DQojIGRlZmluZSBhX3BlcmNlbnRhZ2VfYnlfZGF5IGhlcmU6DQphX3BlcmNlbnRhZ2VfYnlfZGF5IDwtIGFfY2xpY2tzX2J5X2RheSAlPiUNCiAgZ3JvdXBfYnkoZGF5KSAlPiUNCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBjb3VudC9zdW0oY291bnQpKQ0KDQphX3BlcmNlbnRhZ2VfYnlfZGF5DQoNCiMgZGVmaW5lIGJfcGVyY2VudGFnZV9ieV9kYXkgaGVyZToNCmJfcGVyY2VudGFnZV9ieV9kYXkgPC0gYl9jbGlja3NfYnlfZGF5ICU+JQ0KICBncm91cF9ieShkYXkpICU+JQ0KICBtdXRhdGUocGVyY2VudGFnZSA9IGNvdW50L3N1bShjb3VudCkpDQoNCmJfcGVyY2VudGFnZV9ieV9kYXkNCmBgYA0KDQoxMS5GaWx0ZXIgYV9wZXJjZW50YWdlX2J5X2RheSBhbmQgYl9wZXJjZW50YWdlX2J5X2RheSB0byByZW1vdmUgYWxsIHJvd3MgdGhhdCBkbyBub3QgZGVzY3JpYmUgY2xpY2tlZCBhZHMsIGFuZCB2aWV3IHRoZW0uDQoNCldhcyB0aGVyZSBhIGRpZmZlcmVuY2UgaW4gY2xpY2sgcmF0ZXMgZm9yIGVhY2ggZGF5IGJldHdlZW4gdGhlIHR3byBhZHM/IFdoYXQgaGFwcGVuZWQgb3ZlciB0aGUgY291cnNlIG9mIHRoZSB3ZWVrPw0KDQpEbyB5b3UgcmVjb21tZW5kIHRoYXQgU2hvZUZseS5jb20gdXNlIGFkIEEgb3IgYWQgQj8NCg0KUmV2ZWFsIHRoZSBoaW50IGZvciBvdXIgYW5hbHlzaXMuDQoNCmBgYHtyfQ0KIyBkZWZpbmUgYV9wZXJjZW50YWdlX2J5X2RheSBoZXJlOg0KYV9wZXJjZW50YWdlX2J5X2RheSA8LSBhX2NsaWNrc19ieV9kYXkgJT4lDQogIGdyb3VwX2J5KGRheSkgJT4lDQogIG11dGF0ZShwZXJjZW50YWdlID0gY291bnQvc3VtKGNvdW50KSkgJT4lDQogIGZpbHRlcihhZF9jbGlja2VkID09IFRSVUUpDQoNCmFfcGVyY2VudGFnZV9ieV9kYXkNCg0KIyBkZWZpbmUgYl9wZXJjZW50YWdlX2J5X2RheSBoZXJlOg0KYl9wZXJjZW50YWdlX2J5X2RheSA8LSBiX2NsaWNrc19ieV9kYXkgJT4lDQogIGdyb3VwX2J5KGRheSkgJT4lDQogIG11dGF0ZShwZXJjZW50YWdlID0gY291bnQvc3VtKGNvdW50KSkgJT4lDQogIGZpbHRlcihhZF9jbGlja2VkID09IFRSVUUpDQoNCmJfcGVyY2VudGFnZV9ieV9kYXkNCmBgYA0KDQoqSGludDoNCg0KVG8gZmlsdGVyIGFfcGVyY2VudGFnZV9ieV9kYXkgdG8gb25seSBpbmNsdWRlIHJvd3Mgd2hlcmUgYWRzIHdlcmUgY2xpY2tlZCwgcGlwZSB0aGUgcmVzdWx0IGZyb20gdGhlIHByZXZpb3VzIHRhc2sgaW50byBmaWx0ZXIoKSB3aXRoIHRoZSBhZGRpdGlvbmFsIGFyZ3VtZW50IGFkX2NsaWNrZWQgPT0gVFJVRToNCg0KIg0KDQphX3BlcmNlbnRhZ2VfYnlfZGF5IDwtIGFfY2xpY2tzX2J5X2RheQ0KDQogIGdyb3VwX2J5KGRheQ0KICANCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSBjb3VudC9zdW0oY291bnQpKSAlPiUNCiAgDQogIGZpbHRlcihhZF9jbGlja2VkID09IFRSVUUpDQoNCiI=