Loading in All Necessary Packages

library('tidyverse')
library('knitr')
library('sjPlot')
library('forcats')
library('caret')

Loading in Prior Deliverables

purl("deliverable1.Rmd", output = "deliv1.r")
source("deliv1.r")
purl("deliverable2.Rmd", output = "deliv2.r")
source("deliv2.r")

Introduction

Hi and welcome to my third and final deliverable for my portfolio analyzing app store analytics. At first when starting Deliverable 1, my focus was on microtransactions and in app purchases and their effect on analytics such as app price, total sales, and app rating. After finishing the first deliverable, the apple store dataset showed promise in a different type of analysis and the focus of the portfolio shifted to app ratings based on the content or age rating of the app. By the time Deliverable 2 came along, I introduced google play store data and made a model solely based on the google play data. In Deliverable 3, I would like to take the data from the apple app store and the google play store and combine them to make one comprehensive model and analyze both together.

Preparing the Apple Store Data to Merge with Google Play

First thing I want to do is prep the data from the first deliverable and put it in the format of the second data set in order to merge them for the model building. The first thing I have to do is take the variable cont_rating and duplicate it as a new variable so I can change it into the categories that match the google play store data without getting rid of the original data.

apps2 <- apps2 %>% mutate(content_cat = cont_rating)
apps2$content_cat <- as.character(apps2$content_cat)
apps2$content_cat[apps2$content_cat == "4+"] <- "Everyone"
apps2$content_cat[apps2$content_cat == "9+"] <- "Everyone 10+"
apps2$content_cat[apps2$content_cat == "12+"] <- "Teen"
apps2$content_cat[apps2$content_cat == "17+"] <- "Mature 17+"

Last deliverable I had an issue with my model due to singularities so this deliverable I want to integrate more variables into the model. To do this I am going to make more changes to the apple store data and also the google play data.

I am going to change the name of the variable rating_count_tot in apps2 to num_ratings for future joining.

apps2$num_ratings <- apps2$rating_count_tot

Now for the google play store data.

problem1$num_ratings <- problem1$Reviews

Moving onto another variable needed in the model, I am going to fix price for both data sets.

typeof(apps2$price)
[1] "double"

Since apps2 has price data stored as doubles, we can move forward without changing anything.

Looking at the google play store data, I need to change the way the data is stored since the data type is character with dollar signs. To fix this I will use gsub() to replace the $ with nothing and then convert it using as.numeric().

problem1$Price <- as.numeric(gsub("\\$", "", problem1$Price))
typeof(problem1$Price)
[1] "double"

Now it is successfully ready to be stored as doubles in both data frames.

Creating the Final Apple Store and Google Play Store Data Sets

I am going to use tibble() to select the variables wanted for both apple store and google play store.

apple_combine <- tibble(app_name = apps2$track_name,
                        app_rating = apps2$user_rating,
                        num_ratings = apps2$num_ratings,
                        app_price = apps2$price,
                        cont_rating = apps2$content_cat)

google_combine <- tibble(app_name = problem1$App,
                         app_rating = problem1$Rating,
                         num_ratings = problem1$Reviews,
                         app_price = problem1$Price,
                         cont_rating = problem1$`Content Rating`)

Combining Apple Store and Google Play

With the final two tibbles created, it is time to join the two tables into one. A dplyr join is not needed since all 6 variables in each data frame is identical. The final data frame is stored as apple_google and the variables included are:

app_name: The name of the app.

app_rating: The rating of the app on a scale from 0-5 stars.

num_ratings: The number of ratings the app has.

app_price: The price of the app in dollars.

cont_rating: The content rating of the app.

apple_google <- bind_rows(apple_combine,
                          google_combine)

After doing outside research, I found out it is impossible to rate an app 0 stars in both the apple app store and also the google play store. Knowing this information, I will remove all the values in apple_google in which the app rating is 0 to improve the model.

apple_google <- apple_google %>% filter(apple_google$app_rating != "0")
apple_google <- apple_google %>% filter(apple_google$app_rating != "NaN")

The last thing I need to do for apple_google is to make cont_rating a factor and then relevel it to where the age rating is in an order that makes sense for future graphs.

table(apple_google$cont_rating)

Adults only 18+        Everyone    Everyone 10+      Mature 17+            Teen 
              3           11357            1283             902            2088 
        Unrated 
              1 
apple_google$cont_rating <- as.factor(apple_google$cont_rating)
apple_google$cont_rating <- fct_relevel(apple_google$cont_rating, levels = 
                                          c('Everyone', 'Everyone 10+', 'Teen', 'Mature 17+', 'Adults only 18+', 'Unrated'))
Outer names are only allowed for unnamed scalar atomic inputs
levels(apple_google$cont_rating)
[1] "Everyone"        "Everyone 10+"    "Teen"            "Mature 17+"      "Adults only 18+"
[6] "Unrated"        

Performing Multiple Linear Regression for Model Building

First, I need to create a partition of the data based on app_rating in order to split that up into the train and test data. The partition I named sample_partition splits the data into two groups with 70% of the data in one group and 30% in the other. I will then make the 70% into the train data to create the model and then use 30% of the data to predict values using the model.

sample_partition <- createDataPartition(apple_google$app_rating, p=0.70, list = FALSE)
combtrain <- apple_google[sample_selection,]
combtest <- apple_google[-sample_selection,]

One of the main issues with deliverable 2 was that the model was lacking explanatory variables. In this deliverable I will integrate more variables. Now that the train and test data has been made, I will create a model named comb_model that will use content rating, app price, and the number of ratings to predict app rating.

comb_model <- lm(app_rating ~ cont_rating + app_price, + num_ratings , data = combtrain)
summary(comb_model)

Call:
lm(formula = app_rating ~ cont_rating + app_price, data = combtrain, 
    subset = +num_ratings)

Residuals:
     Min       1Q   Median       3Q      Max 
-2.99759 -0.49096  0.00904  0.50507  1.33770 

Coefficients:
                          Estimate Std. Error t value Pr(>|t|)    
(Intercept)              3.9909616  0.0116017 343.998   <2e-16 ***
cont_ratingEveryone 10+  0.0742945  0.0337233   2.203   0.0276 *  
cont_ratingTeen         -0.0366973  0.0270578  -1.356   0.1751    
cont_ratingMature 17+   -0.3286588  0.0363389  -9.044   <2e-16 ***
app_price                0.0013287  0.0008043   1.652   0.0986 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.6099 on 4178 degrees of freedom
  (2375 observations deleted due to missingness)
Multiple R-squared:  0.0226,    Adjusted R-squared:  0.02166 
F-statistic: 24.15 on 4 and 4178 DF,  p-value: < 2.2e-16
apple_google %>% ggplot(aes(x=cont_rating, y = app_rating)) + geom_boxplot() +
  stat_summary(fun.y="mean", geom="point", size=5, pch=17,color="red") + theme_bw()

Final Conclusions and Summary

Over this semester I have enjoyed looking into app store data for many reasons. I first assumed that all apps were made for monetary gain in which I would obviously find a correlation between sales and in app purchases, but after diving into multiple data sets, I noticed that there are much more variables to the process and changed focus. That is what Data Science is all about. The Data Science cycle is all about data preparation, research into the data, drawing conclusions from it and repeating.

When discussing the social implications and some of the drawbacks, it is important to focus on the reasons behind a review in the app store. Like all optional review systems, people only review if they are on the polar ends of the spectrum of satisfaction with the product. Like I discussed in Deliverable 2, people only review an app if they absolutely love it or absolutely hate it. This causes a skew in the reviews. No one will take their time to express that they are moderately pleased with an app and give it 3 stars. This causes the variation of data points for average app rating to be very low. Most apps in my model based on content rating had a very similar average app rating. Another problem when looking into this data could be the possible effects of the Cobra effect which is when a possible solution for a problem actually has the opposite effect and introduces a negative reaction in the population. A possible example of the cobra effect in app research is that if the results come back as a certain age group provides higher ratings for apps such as 18+ or even teens, more apps in the future could be aimed at that age group which takes away from a large population of the users in the app store, the kids under 13.

When all is done, diving into app analytics while demonstrating the data science cycle was enriching and I hope to continue my research in this topic in the future.

LS0tCnRpdGxlOiAiRGVsaXZlcmFibGUgMyIKYXV0aG9yOiAiQnJhbmRvbiBMZWZmIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIExvYWRpbmcgaW4gQWxsIE5lY2Vzc2FyeSBQYWNrYWdlcwoKYGBge3J9CmxpYnJhcnkoJ3RpZHl2ZXJzZScpCmxpYnJhcnkoJ2tuaXRyJykKbGlicmFyeSgnc2pQbG90JykKbGlicmFyeSgnZm9yY2F0cycpCmxpYnJhcnkoJ2NhcmV0JykKYGBgCgojIExvYWRpbmcgaW4gUHJpb3IgRGVsaXZlcmFibGVzCgpgYGB7cn0KcHVybCgiZGVsaXZlcmFibGUxLlJtZCIsIG91dHB1dCA9ICJkZWxpdjEuciIpCnNvdXJjZSgiZGVsaXYxLnIiKQpwdXJsKCJkZWxpdmVyYWJsZTIuUm1kIiwgb3V0cHV0ID0gImRlbGl2Mi5yIikKc291cmNlKCJkZWxpdjIuciIpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCkhpIGFuZCB3ZWxjb21lIHRvIG15IHRoaXJkIGFuZCBmaW5hbCBkZWxpdmVyYWJsZSBmb3IgbXkgcG9ydGZvbGlvIGFuYWx5emluZyBhcHAgc3RvcmUgYW5hbHl0aWNzLiBBdCBmaXJzdCB3aGVuIHN0YXJ0aW5nIERlbGl2ZXJhYmxlIDEsIG15IGZvY3VzIHdhcyBvbiBtaWNyb3RyYW5zYWN0aW9ucyBhbmQgaW4gYXBwIHB1cmNoYXNlcyBhbmQgdGhlaXIgZWZmZWN0IG9uIGFuYWx5dGljcyBzdWNoIGFzIGFwcCBwcmljZSwgdG90YWwgc2FsZXMsIGFuZCBhcHAgcmF0aW5nLiBBZnRlciBmaW5pc2hpbmcgdGhlIGZpcnN0IGRlbGl2ZXJhYmxlLCB0aGUgYXBwbGUgc3RvcmUgZGF0YXNldCBzaG93ZWQgcHJvbWlzZSBpbiBhIGRpZmZlcmVudCB0eXBlIG9mIGFuYWx5c2lzIGFuZCB0aGUgZm9jdXMgb2YgdGhlIHBvcnRmb2xpbyBzaGlmdGVkIHRvIGFwcCByYXRpbmdzIGJhc2VkIG9uIHRoZSBjb250ZW50IG9yIGFnZSByYXRpbmcgb2YgdGhlIGFwcC4gQnkgdGhlIHRpbWUgRGVsaXZlcmFibGUgMiBjYW1lIGFsb25nLCBJIGludHJvZHVjZWQgZ29vZ2xlIHBsYXkgc3RvcmUgZGF0YSBhbmQgbWFkZSBhIG1vZGVsIHNvbGVseSBiYXNlZCBvbiB0aGUgZ29vZ2xlIHBsYXkgZGF0YS4gSW4gRGVsaXZlcmFibGUgMywgSSB3b3VsZCBsaWtlIHRvIHRha2UgdGhlIGRhdGEgZnJvbSB0aGUgYXBwbGUgYXBwIHN0b3JlIGFuZCB0aGUgZ29vZ2xlIHBsYXkgc3RvcmUgYW5kIGNvbWJpbmUgdGhlbSB0byBtYWtlIG9uZSBjb21wcmVoZW5zaXZlIG1vZGVsIGFuZCBhbmFseXplIGJvdGggdG9nZXRoZXIuCgojIFByZXBhcmluZyB0aGUgQXBwbGUgU3RvcmUgRGF0YSB0byBNZXJnZSB3aXRoIEdvb2dsZSBQbGF5CgpGaXJzdCB0aGluZyBJIHdhbnQgdG8gZG8gaXMgcHJlcCB0aGUgZGF0YSBmcm9tIHRoZSBmaXJzdCBkZWxpdmVyYWJsZSBhbmQgcHV0IGl0IGluIHRoZSBmb3JtYXQgb2YgdGhlIHNlY29uZCBkYXRhIHNldCBpbiBvcmRlciB0byBtZXJnZSB0aGVtIGZvciB0aGUgbW9kZWwgYnVpbGRpbmcuIFRoZSBmaXJzdCB0aGluZyBJIGhhdmUgdG8gZG8gaXMgdGFrZSB0aGUgdmFyaWFibGUgYGNvbnRfcmF0aW5nYCBhbmQgZHVwbGljYXRlIGl0IGFzIGEgbmV3IHZhcmlhYmxlIHNvIEkgY2FuIGNoYW5nZSBpdCBpbnRvIHRoZSBjYXRlZ29yaWVzIHRoYXQgbWF0Y2ggdGhlIGdvb2dsZSBwbGF5IHN0b3JlIGRhdGEgd2l0aG91dCBnZXR0aW5nIHJpZCBvZiB0aGUgb3JpZ2luYWwgZGF0YS4KCmBgYHtyfQphcHBzMiA8LSBhcHBzMiAlPiUgbXV0YXRlKGNvbnRlbnRfY2F0ID0gY29udF9yYXRpbmcpCmFwcHMyJGNvbnRlbnRfY2F0IDwtIGFzLmNoYXJhY3RlcihhcHBzMiRjb250ZW50X2NhdCkKYXBwczIkY29udGVudF9jYXRbYXBwczIkY29udGVudF9jYXQgPT0gIjQrIl0gPC0gIkV2ZXJ5b25lIgphcHBzMiRjb250ZW50X2NhdFthcHBzMiRjb250ZW50X2NhdCA9PSAiOSsiXSA8LSAiRXZlcnlvbmUgMTArIgphcHBzMiRjb250ZW50X2NhdFthcHBzMiRjb250ZW50X2NhdCA9PSAiMTIrIl0gPC0gIlRlZW4iCmFwcHMyJGNvbnRlbnRfY2F0W2FwcHMyJGNvbnRlbnRfY2F0ID09ICIxNysiXSA8LSAiTWF0dXJlIDE3KyIKYGBgCgpMYXN0IGRlbGl2ZXJhYmxlIEkgaGFkIGFuIGlzc3VlIHdpdGggbXkgbW9kZWwgZHVlIHRvIHNpbmd1bGFyaXRpZXMgc28gdGhpcyBkZWxpdmVyYWJsZSBJIHdhbnQgdG8gaW50ZWdyYXRlIG1vcmUgdmFyaWFibGVzIGludG8gdGhlIG1vZGVsLiBUbyBkbyB0aGlzIEkgYW0gZ29pbmcgdG8gbWFrZSBtb3JlIGNoYW5nZXMgdG8gdGhlIGFwcGxlIHN0b3JlIGRhdGEgYW5kIGFsc28gdGhlIGdvb2dsZSBwbGF5IGRhdGEuCgpJIGFtIGdvaW5nIHRvIGNoYW5nZSB0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUgYHJhdGluZ19jb3VudF90b3RgIGluIGFwcHMyIHRvIGBudW1fcmF0aW5nc2AgZm9yIGZ1dHVyZSBqb2luaW5nLgoKYGBge3J9CmFwcHMyJG51bV9yYXRpbmdzIDwtIGFwcHMyJHJhdGluZ19jb3VudF90b3QKYGBgCgpOb3cgZm9yIHRoZSBnb29nbGUgcGxheSBzdG9yZSBkYXRhLgoKYGBge3J9CnByb2JsZW0xJG51bV9yYXRpbmdzIDwtIHByb2JsZW0xJFJldmlld3MKYGBgCgpNb3Zpbmcgb250byBhbm90aGVyIHZhcmlhYmxlIG5lZWRlZCBpbiB0aGUgbW9kZWwsIEkgYW0gZ29pbmcgdG8gZml4IHByaWNlIGZvciBib3RoIGRhdGEgc2V0cy4KCmBgYHtyfQp0eXBlb2YoYXBwczIkcHJpY2UpCmBgYApTaW5jZSBhcHBzMiBoYXMgcHJpY2UgZGF0YSBzdG9yZWQgYXMgZG91Ymxlcywgd2UgY2FuIG1vdmUgZm9yd2FyZCB3aXRob3V0IGNoYW5naW5nIGFueXRoaW5nLgoKTG9va2luZyBhdCB0aGUgZ29vZ2xlIHBsYXkgc3RvcmUgZGF0YSwgSSBuZWVkIHRvIGNoYW5nZSB0aGUgd2F5IHRoZSBkYXRhIGlzIHN0b3JlZCBzaW5jZSB0aGUgZGF0YSB0eXBlIGlzIGNoYXJhY3RlciB3aXRoIGRvbGxhciBzaWducy4gVG8gZml4IHRoaXMgSSB3aWxsIHVzZSBgZ3N1YigpYCB0byByZXBsYWNlIHRoZSAkIHdpdGggbm90aGluZyBhbmQgdGhlbiBjb252ZXJ0IGl0IHVzaW5nIGBhcy5udW1lcmljKClgLgoKYGBge3J9CnByb2JsZW0xJFByaWNlIDwtIGFzLm51bWVyaWMoZ3N1YigiXFwkIiwgIiIsIHByb2JsZW0xJFByaWNlKSkKYGBgCgpgYGB7cn0KdHlwZW9mKHByb2JsZW0xJFByaWNlKQpgYGAKCk5vdyBpdCBpcyBzdWNjZXNzZnVsbHkgcmVhZHkgdG8gYmUgc3RvcmVkIGFzIGRvdWJsZXMgaW4gYm90aCBkYXRhIGZyYW1lcy4KCiMgQ3JlYXRpbmcgdGhlIEZpbmFsIEFwcGxlIFN0b3JlIGFuZCBHb29nbGUgUGxheSBTdG9yZSBEYXRhIFNldHMKCkkgYW0gZ29pbmcgdG8gdXNlIGB0aWJibGUoKWAgdG8gc2VsZWN0IHRoZSB2YXJpYWJsZXMgd2FudGVkIGZvciBib3RoIGFwcGxlIHN0b3JlIGFuZCBnb29nbGUgcGxheSBzdG9yZS4KCmBgYHtyfQphcHBsZV9jb21iaW5lIDwtIHRpYmJsZShhcHBfbmFtZSA9IGFwcHMyJHRyYWNrX25hbWUsCiAgICAgICAgICAgICAgICAgICAgICAgIGFwcF9yYXRpbmcgPSBhcHBzMiR1c2VyX3JhdGluZywKICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3JhdGluZ3MgPSBhcHBzMiRudW1fcmF0aW5ncywKICAgICAgICAgICAgICAgICAgICAgICAgYXBwX3ByaWNlID0gYXBwczIkcHJpY2UsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRfcmF0aW5nID0gYXBwczIkY29udGVudF9jYXQpCgpnb29nbGVfY29tYmluZSA8LSB0aWJibGUoYXBwX25hbWUgPSBwcm9ibGVtMSRBcHAsCiAgICAgICAgICAgICAgICAgICAgICAgICBhcHBfcmF0aW5nID0gcHJvYmxlbTEkUmF0aW5nLAogICAgICAgICAgICAgICAgICAgICAgICAgbnVtX3JhdGluZ3MgPSBwcm9ibGVtMSRSZXZpZXdzLAogICAgICAgICAgICAgICAgICAgICAgICAgYXBwX3ByaWNlID0gcHJvYmxlbTEkUHJpY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICBjb250X3JhdGluZyA9IHByb2JsZW0xJGBDb250ZW50IFJhdGluZ2ApCmBgYAoKIyBDb21iaW5pbmcgQXBwbGUgU3RvcmUgYW5kIEdvb2dsZSBQbGF5CgpXaXRoIHRoZSBmaW5hbCB0d28gdGliYmxlcyBjcmVhdGVkLCBpdCBpcyB0aW1lIHRvIGpvaW4gdGhlIHR3byB0YWJsZXMgaW50byBvbmUuIEEgZHBseXIgam9pbiBpcyBub3QgbmVlZGVkIHNpbmNlIGFsbCA2IHZhcmlhYmxlcyBpbiBlYWNoIGRhdGEgZnJhbWUgaXMgaWRlbnRpY2FsLiBUaGUgZmluYWwgZGF0YSBmcmFtZSBpcyBzdG9yZWQgYXMgYGFwcGxlX2dvb2dsZWAgYW5kIHRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgYXJlOgoKYGFwcF9uYW1lYDogVGhlIG5hbWUgb2YgdGhlIGFwcC4KCmBhcHBfcmF0aW5nYDogVGhlIHJhdGluZyBvZiB0aGUgYXBwIG9uIGEgc2NhbGUgZnJvbSAwLTUgc3RhcnMuCgpgbnVtX3JhdGluZ3NgOiBUaGUgbnVtYmVyIG9mIHJhdGluZ3MgdGhlIGFwcCBoYXMuCgpgYXBwX3ByaWNlYDogVGhlIHByaWNlIG9mIHRoZSBhcHAgaW4gZG9sbGFycy4KCmBjb250X3JhdGluZ2A6IFRoZSBjb250ZW50IHJhdGluZyBvZiB0aGUgYXBwLgoKYGBge3J9CmFwcGxlX2dvb2dsZSA8LSBiaW5kX3Jvd3MoYXBwbGVfY29tYmluZSwKICAgICAgICAgICAgICAgICAgICAgICAgICBnb29nbGVfY29tYmluZSkKYGBgCgpBZnRlciBkb2luZyBvdXRzaWRlIHJlc2VhcmNoLCBJIGZvdW5kIG91dCBpdCBpcyBpbXBvc3NpYmxlIHRvIHJhdGUgYW4gYXBwIDAgc3RhcnMgaW4gYm90aCB0aGUgYXBwbGUgYXBwIHN0b3JlIGFuZCBhbHNvIHRoZSBnb29nbGUgcGxheSBzdG9yZS4gS25vd2luZyB0aGlzIGluZm9ybWF0aW9uLCBJIHdpbGwgcmVtb3ZlIGFsbCB0aGUgdmFsdWVzIGluIGBhcHBsZV9nb29nbGVgIGluIHdoaWNoIHRoZSBhcHAgcmF0aW5nIGlzIDAgdG8gaW1wcm92ZSB0aGUgbW9kZWwuCgpgYGB7cn0KYXBwbGVfZ29vZ2xlIDwtIGFwcGxlX2dvb2dsZSAlPiUgZmlsdGVyKGFwcGxlX2dvb2dsZSRhcHBfcmF0aW5nICE9ICIwIikKYXBwbGVfZ29vZ2xlIDwtIGFwcGxlX2dvb2dsZSAlPiUgZmlsdGVyKGFwcGxlX2dvb2dsZSRhcHBfcmF0aW5nICE9ICJOYU4iKQpgYGAKClRoZSBsYXN0IHRoaW5nIEkgbmVlZCB0byBkbyBmb3IgYGFwcGxlX2dvb2dsZWAgaXMgdG8gbWFrZSBgY29udF9yYXRpbmdgIGEgZmFjdG9yIGFuZCB0aGVuIHJlbGV2ZWwgaXQgdG8gd2hlcmUgdGhlIGFnZSByYXRpbmcgaXMgaW4gYW4gb3JkZXIgdGhhdCBtYWtlcyBzZW5zZSBmb3IgZnV0dXJlIGdyYXBocy4KCmBgYHtyfQp0YWJsZShhcHBsZV9nb29nbGUkY29udF9yYXRpbmcpCmBgYAoKCmBgYHtyfQphcHBsZV9nb29nbGUkY29udF9yYXRpbmcgPC0gYXMuZmFjdG9yKGFwcGxlX2dvb2dsZSRjb250X3JhdGluZykKYXBwbGVfZ29vZ2xlJGNvbnRfcmF0aW5nIDwtIGZjdF9yZWxldmVsKGFwcGxlX2dvb2dsZSRjb250X3JhdGluZywgbGV2ZWxzID0gCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoJ0V2ZXJ5b25lJywgJ0V2ZXJ5b25lIDEwKycsICdUZWVuJywgJ01hdHVyZSAxNysnLCAnQWR1bHRzIG9ubHkgMTgrJywgJ1VucmF0ZWQnKSkKbGV2ZWxzKGFwcGxlX2dvb2dsZSRjb250X3JhdGluZykKYGBgCgojIFBlcmZvcm1pbmcgTXVsdGlwbGUgTGluZWFyIFJlZ3Jlc3Npb24gZm9yIE1vZGVsIEJ1aWxkaW5nCgpGaXJzdCwgSSBuZWVkIHRvIGNyZWF0ZSBhIHBhcnRpdGlvbiBvZiB0aGUgZGF0YSBiYXNlZCBvbiBgYXBwX3JhdGluZ2AgaW4gb3JkZXIgdG8gc3BsaXQgdGhhdCB1cCBpbnRvIHRoZSB0cmFpbiBhbmQgdGVzdCBkYXRhLiBUaGUgcGFydGl0aW9uIEkgbmFtZWQgYHNhbXBsZV9wYXJ0aXRpb25gIHNwbGl0cyB0aGUgZGF0YSBpbnRvIHR3byBncm91cHMgd2l0aCA3MCUgb2YgdGhlIGRhdGEgaW4gb25lIGdyb3VwIGFuZCAzMCUgaW4gdGhlIG90aGVyLiBJIHdpbGwgdGhlbiBtYWtlIHRoZSA3MCUgaW50byB0aGUgdHJhaW4gZGF0YSB0byBjcmVhdGUgdGhlIG1vZGVsIGFuZCB0aGVuIHVzZSAzMCUgb2YgdGhlIGRhdGEgdG8gcHJlZGljdCB2YWx1ZXMgdXNpbmcgdGhlIG1vZGVsLgoKYGBge3J9CnNhbXBsZV9wYXJ0aXRpb24gPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihhcHBsZV9nb29nbGUkYXBwX3JhdGluZywgcD0wLjcwLCBsaXN0ID0gRkFMU0UpCmNvbWJ0cmFpbiA8LSBhcHBsZV9nb29nbGVbc2FtcGxlX3NlbGVjdGlvbixdCmNvbWJ0ZXN0IDwtIGFwcGxlX2dvb2dsZVstc2FtcGxlX3NlbGVjdGlvbixdCmBgYAoKT25lIG9mIHRoZSBtYWluIGlzc3VlcyB3aXRoIGRlbGl2ZXJhYmxlIDIgd2FzIHRoYXQgdGhlIG1vZGVsIHdhcyBsYWNraW5nIGV4cGxhbmF0b3J5IHZhcmlhYmxlcy4gSW4gdGhpcyBkZWxpdmVyYWJsZSBJIHdpbGwgaW50ZWdyYXRlIG1vcmUgdmFyaWFibGVzLiBOb3cgdGhhdCB0aGUgdHJhaW4gYW5kIHRlc3QgZGF0YSBoYXMgYmVlbiBtYWRlLCBJIHdpbGwgY3JlYXRlIGEgbW9kZWwgbmFtZWQgYGNvbWJfbW9kZWxgIHRoYXQgd2lsbCB1c2UgY29udGVudCByYXRpbmcsIGFwcCBwcmljZSwgYW5kIHRoZSBudW1iZXIgb2YgcmF0aW5ncyB0byBwcmVkaWN0IGFwcCByYXRpbmcuCgpgYGB7cn0KY29tYl9tb2RlbCA8LSBsbShhcHBfcmF0aW5nIH4gY29udF9yYXRpbmcgKyBhcHBfcHJpY2UsICsgbnVtX3JhdGluZ3MgLCBkYXRhID0gY29tYnRyYWluKQpzdW1tYXJ5KGNvbWJfbW9kZWwpCmBgYAoKYGBge3J9CmFwcGxlX2dvb2dsZSAlPiUgZ2dwbG90KGFlcyh4PWNvbnRfcmF0aW5nLCB5ID0gYXBwX3JhdGluZykpICsgZ2VvbV9ib3hwbG90KCkgKwogIHN0YXRfc3VtbWFyeShmdW4ueT0ibWVhbiIsIGdlb209InBvaW50Iiwgc2l6ZT01LCBwY2g9MTcsY29sb3I9InJlZCIpICsgdGhlbWVfYncoKQpgYGAKCiMgRmluYWwgQ29uY2x1c2lvbnMgYW5kIFN1bW1hcnkKCk92ZXIgdGhpcyBzZW1lc3RlciBJIGhhdmUgZW5qb3llZCBsb29raW5nIGludG8gYXBwIHN0b3JlIGRhdGEgZm9yIG1hbnkgcmVhc29ucy4gSSBmaXJzdCBhc3N1bWVkIHRoYXQgYWxsIGFwcHMgd2VyZSBtYWRlIGZvciBtb25ldGFyeSBnYWluIGluIHdoaWNoIEkgd291bGQgb2J2aW91c2x5IGZpbmQgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHNhbGVzIGFuZCBpbiBhcHAgcHVyY2hhc2VzLCBidXQgYWZ0ZXIgZGl2aW5nIGludG8gbXVsdGlwbGUgZGF0YSBzZXRzLCBJIG5vdGljZWQgdGhhdCB0aGVyZSBhcmUgbXVjaCBtb3JlIHZhcmlhYmxlcyB0byB0aGUgcHJvY2VzcyBhbmQgY2hhbmdlZCBmb2N1cy4gVGhhdCBpcyB3aGF0IERhdGEgU2NpZW5jZSBpcyBhbGwgYWJvdXQuIFRoZSBEYXRhIFNjaWVuY2UgY3ljbGUgaXMgYWxsIGFib3V0IGRhdGEgcHJlcGFyYXRpb24sIHJlc2VhcmNoIGludG8gdGhlIGRhdGEsIGRyYXdpbmcgY29uY2x1c2lvbnMgZnJvbSBpdCBhbmQgcmVwZWF0aW5nLiAKCldoZW4gZGlzY3Vzc2luZyB0aGUgc29jaWFsIGltcGxpY2F0aW9ucyBhbmQgc29tZSBvZiB0aGUgZHJhd2JhY2tzLCBpdCBpcyBpbXBvcnRhbnQgdG8gZm9jdXMgb24gdGhlIHJlYXNvbnMgYmVoaW5kIGEgcmV2aWV3IGluIHRoZSBhcHAgc3RvcmUuIExpa2UgYWxsIG9wdGlvbmFsIHJldmlldyBzeXN0ZW1zLCBwZW9wbGUgb25seSByZXZpZXcgaWYgdGhleSBhcmUgb24gdGhlIHBvbGFyIGVuZHMgb2YgdGhlIHNwZWN0cnVtIG9mIHNhdGlzZmFjdGlvbiB3aXRoIHRoZSBwcm9kdWN0LiBMaWtlIEkgZGlzY3Vzc2VkIGluIERlbGl2ZXJhYmxlIDIsIHBlb3BsZSBvbmx5IHJldmlldyBhbiBhcHAgaWYgdGhleSBhYnNvbHV0ZWx5IGxvdmUgaXQgb3IgYWJzb2x1dGVseSBoYXRlIGl0LiBUaGlzIGNhdXNlcyBhIHNrZXcgaW4gdGhlIHJldmlld3MuIE5vIG9uZSB3aWxsIHRha2UgdGhlaXIgdGltZSB0byBleHByZXNzIHRoYXQgdGhleSBhcmUgbW9kZXJhdGVseSBwbGVhc2VkIHdpdGggYW4gYXBwIGFuZCBnaXZlIGl0IDMgc3RhcnMuIFRoaXMgY2F1c2VzIHRoZSB2YXJpYXRpb24gb2YgZGF0YSBwb2ludHMgZm9yIGF2ZXJhZ2UgYXBwIHJhdGluZyB0byBiZSB2ZXJ5IGxvdy4gTW9zdCBhcHBzIGluIG15IG1vZGVsIGJhc2VkIG9uIGNvbnRlbnQgcmF0aW5nIGhhZCBhIHZlcnkgc2ltaWxhciBhdmVyYWdlIGFwcCByYXRpbmcuIEFub3RoZXIgcHJvYmxlbSB3aGVuIGxvb2tpbmcgaW50byB0aGlzIGRhdGEgY291bGQgYmUgdGhlIHBvc3NpYmxlIGVmZmVjdHMgb2YgdGhlIENvYnJhIGVmZmVjdCB3aGljaCBpcyB3aGVuIGEgcG9zc2libGUgc29sdXRpb24gZm9yIGEgcHJvYmxlbSBhY3R1YWxseSBoYXMgdGhlIG9wcG9zaXRlIGVmZmVjdCBhbmQgaW50cm9kdWNlcyBhIG5lZ2F0aXZlIHJlYWN0aW9uIGluIHRoZSBwb3B1bGF0aW9uLiBBIHBvc3NpYmxlIGV4YW1wbGUgb2YgdGhlIGNvYnJhIGVmZmVjdCBpbiBhcHAgcmVzZWFyY2ggaXMgdGhhdCBpZiB0aGUgcmVzdWx0cyBjb21lIGJhY2sgYXMgYSBjZXJ0YWluIGFnZSBncm91cCBwcm92aWRlcyBoaWdoZXIgcmF0aW5ncyBmb3IgYXBwcyBzdWNoIGFzIDE4KyBvciBldmVuIHRlZW5zLCBtb3JlIGFwcHMgaW4gdGhlIGZ1dHVyZSBjb3VsZCBiZSBhaW1lZCBhdCB0aGF0IGFnZSBncm91cCB3aGljaCB0YWtlcyBhd2F5IGZyb20gYSBsYXJnZSBwb3B1bGF0aW9uIG9mIHRoZSB1c2VycyBpbiB0aGUgYXBwIHN0b3JlLCB0aGUga2lkcyB1bmRlciAxMy4KCldoZW4gYWxsIGlzIGRvbmUsIGRpdmluZyBpbnRvIGFwcCBhbmFseXRpY3Mgd2hpbGUgZGVtb25zdHJhdGluZyB0aGUgZGF0YSBzY2llbmNlIGN5Y2xlIHdhcyBlbnJpY2hpbmcgYW5kIEkgaG9wZSB0byBjb250aW51ZSBteSByZXNlYXJjaCBpbiB0aGlzIHRvcGljIGluIHRoZSBmdXR1cmUu