- Installing packages
install.packages("gridExtra")
trying URL 'https://cran.rstudio.com/bin/macosx/el-capitan/contrib/3.6/gridExtra_2.3.tgz'
Content type 'application/x-gzip' length 1103470 bytes (1.1 MB)
==================================================
downloaded 1.1 MB
The downloaded binary packages are in
/var/folders/_b/l95j9sls68zfzm9gpf99lh6h0000gp/T//RtmpUwp73V/downloaded_packages
# install.packages('devtools')
devtools::install_github("soodoku/tuber", build_vignettes = TRUE)
- Loading libraries
#loading libraries
library(tuber) # youtube API
library(magrittr)
library(tidyverse)
library(purrr)
library(stringr)
library(dplyr)
library(ggplot2)
library(wordcloud)
library(tm)
library(lubridate)
library(plyr)
library(gridExtra)
- Authentication
#authentication from account 1
client_id = "XXX"
client_secret = "XXX"
api_key = "XXX"
client_id = "XXX"
client_secret = "XXX"
# use the youtube oauth
yt_oauth(app_id = client_id,
app_secret = client_secret,
token = '')
4.Reading in scraped URLS
#read in scraped youtube urls
raw_urls = read_csv("/Users/yuyangwang 1/Desktop/OIDD 245/Data Project 2/youtube_urls.csv")
- Scraping data from YouTube API
#function to extract the video ID
getID = function(url) {
id = str_split(string = url,
pattern = "=",
n = 2,
simplify = TRUE)[ , 2]
return (id)
}
raw_urls$vid_id = sapply(raw_urls$URL, getID)
raw_urls = unique(raw_urls)
# function to scrape stats for all vids
get_all_stats = function(id) {
get_stats(video_id = id)
}
get_all_details = function(id) {
get_video_details(video_id = id)
}
#stats of all vids - ONLY RUN WHEN NEED (quota of queries per day)
video_all_stats = map_df(.x = raw_urls$vid_id, .f = get_all_stats)
#remove rows with null val
video_all_stats = na.omit(video_all_stats)
#join
merged_id = merge(x = raw_urls, y = video_all_stats, by.x = "vid_id", by.y = "id", all.y = TRUE)
#getting video details
videodets = lapply(as.character(merged_id$vid_id), function(x){
get_video_details(video_id = x, part="snippet")
})
#appending to data frame
for (i in 1 : 681) {
merged_id[i,]$publishedAt = videodets[[i]][["items"]][[1]][["snippet"]][["publishedAt"]]
merged_id[i,]$channelId = videodets[[i]][["items"]][[1]][["snippet"]][["channelId"]]
merged_id[i,]$description = videodets[[i]][["items"]][[1]][["snippet"]][["description"]]
merged_id[i,]$tags = paste(videodets[[i]][["items"]][[1]][["snippet"]][["tags"]], collapse = ' ')
}
#getting channel stats
channeldets = lapply(as.character(merged_id$channelId), function(x){
get_channel_stats(x)
})
#adding channel stats to main df
for (i in 1 : 681) {
merged_id[i,]$channel_views = as.numeric(channeldets[[i]][["statistics"]][["viewCount"]])
merged_id[i,]$channel_title = channeldets[[i]][["snippet"]][["title"]]
merged_id[i,]$channel_desc = channeldets[[i]][["snippet"]][["description"]]
merged_id[i,]$channel_subs = channeldets[[i]][["statistics"]][["subscriberCount"]]
}
- Manipulation to get some basic info on the videos scraped from homepage
head(worst_dislike_ratio, 15)
head(best_like_ratio, 15)
#creating histogram of data
hist(df_like_dislike_ratio$like_dislike_ratio, main="Histogram for Like/Dislike Ratio among 600+ YouTube Videos",
xlab="Like/Dislike Ratio",
border="white",
col="red",)

#finding the best/worst subs engagement
worst_subs_engagement = df_filtered[order(df_filtered$subs_engage), c("Link","channel_title","subs_engage")]
best_subs_engagement = df_filtered[order(-df_filtered$subs_engage), c("Link","channel_title","subs_engage")]
head(worst_subs_engagement, 10)
head(best_subs_engagement, 10)
#finding the best/worst comment ratio
worst_comment_ratio = df_filtered[order(df_filtered$comments_ratio), c("Link","channel_title","comments_ratio")]
best_comment_ratio = df_filtered[order(-df_filtered$comments_ratio), c("Link","channel_title","comments_ratio")]
head(worst_comment_ratio, 10)
head(best_comment_ratio, 10)
Generate wordcloud representing the videos shown
alldesc = ""
for (i in 1:100) {
alldesc = paste(alldesc, top100views[i, "description"], sep=" ")
}
#corpus
corpus = VCorpus(VectorSource(top100views$description))
#Step 1: cleaning
corp = tm_map(corpus, removePunctuation)
corp = tm_map(corp, removeNumbers)
corp = tm_map(corp, content_transformer(tolower) ,lazy=TRUE)
corp = tm_map(corp, content_transformer(removeWords), c("TIL") ,lazy=TRUE)
corp = tm_map(corp, content_transformer(removeWords), stopwords("english") ,lazy=TRUE)
corp = tm_map(corp, removeWords, c("the", "for", "is", "and"))
corp = tm_map(corp, stripWhitespace)
dtm = DocumentTermMatrix(corp)
dtms = removeSparseTerms(dtm, 0.983)
dim(dtm)
[1] 100 4869
dim(dtms)
[1] 100 1083
dtms_m = as.matrix(dtms)
# colSums adds up value over all of the Columns in a matrix
# rowSums(m) is the equivalent over rows
word.freq = colSums(dtms_m)
word.freq = sort(word.freq, decreasing=T)
d <- data.frame(word = names(word.freq),freq=word.freq)
#create wordcloud
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
max.words=100, random.order=FALSE, rot.per=0.35,
colors=brewer.pal(8, "Dark2"))

Load in data from
top50gamers = read_csv("/Users/yuyangwang 1/Desktop/OIDD 245/Data Project 2/top100game.csv")
top50vloggers = read_csv("/Users/yuyangwang 1/Desktop/OIDD 245/Data Project 2/top100bloggers.csv")
top50comedians = read_csv("/Users/yuyangwang 1/Desktop/OIDD 245/Data Project 2/top100comedy.csv")
colnames(top50vloggers)[which(names(top50vloggers) == "user")] <- "username"
Edit the numbers


#plot of how subscriber counts compare in 3 categories
plot_subs = ggplot() +
geom_line(data=top50gamers, aes(x=rank, y=subs), color='green') +
geom_line(data=top50vloggers, aes(x=rank, y=subs), color='blue') +
geom_line(data=top50comedians, aes(x=rank, y=subs), color='red') + ggtitle("Number of Subscribers for Top 50 YouTubers of Each Category") +
xlab("Rank") + ylab("Number of Subscribers")
plot_subs
#plot of how total view counts compare in 3 categories
plot_views = ggplot() +
geom_line(data=top50gamers, aes(x=rank, y=totalviews), color='green') +
geom_line(data=top50vloggers, aes(x=rank, y=totalviews), color='blue') +
geom_line(data=top50comedians, aes(x=rank, y=totalviews), color='red') + ggtitle("Number of Views for Top 50 YouTubers of Each Category") +
xlab("Rank") + ylab("Total Views")
plot_views
#plot of how subscriber number of videos published compare in 3 categories
plot_vids = ggplot() +
geom_line(data=top50gamers, aes(x=rank, y=totalVids), color='green') +
geom_line(data=top50vloggers, aes(x=rank, y=totalVids), color='blue') +
geom_line(data=top50comedians, aes(x=rank, y=totalVids), color='red') + ggtitle("Number of Total Videos for Top 50 YouTubers of Each Category") +
xlab("Rank") + ylab("Total Videos")
plot_vids

#plot showing number of subscribers from when you joined
ggplot() +
geom_line(data=top50gamers, aes(x=join_date, y=subs), color='green') +
geom_line(data=top50vloggers, aes(x=join_date, y=subs), color='blue') +
geom_line(data=top50comedians, aes(x=join_date, y=subs), color='red') + ggtitle("Timeline of Join Dates of YouTubers and Number of Subscribers") +
xlab("Date") + ylab("Number of Subscribers") + labs(fill = "Categories")


#get pewdiepie
#pewd = get_channel_stats("UC-lHJZR3Gqxm24_Vd_AJ5Yw")
#get all of his videos
#videos = yt_search(term="", type="video", channel_id = "UC-lHJZR3Gqxm24_Vd_AJ5Yw")
#get all their stats
#videostats = lapply(as.character(videos$video_id), function(x){
# get_stats(video_id = x)
#})
LS0tCnRpdGxlOiAiWW91VHViZSBBbmFseXNpcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKMS4gSW5zdGFsbGluZyBwYWNrYWdlcwpgYGB7cn0KI2luc3RhbGxpbmcgcGFja2FnZXMKaW5zdGFsbC5wYWNrYWdlcygidHViZXIiKQppbnN0YWxsLnBhY2thZ2VzKCJncmlkRXh0cmEiKQpgYGAKYGBge3J9CiMgaW5zdGFsbC5wYWNrYWdlcygnZGV2dG9vbHMnKQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoInNvb2Rva3UvdHViZXIiLCBidWlsZF92aWduZXR0ZXMgPSBUUlVFKQpgYGAKCjIuIExvYWRpbmcgbGlicmFyaWVzCmBgYHtyfQojbG9hZGluZyBsaWJyYXJpZXMKbGlicmFyeSh0dWJlcikgIyB5b3V0dWJlIEFQSQpsaWJyYXJ5KG1hZ3JpdHRyKSAKbGlicmFyeSh0aWR5dmVyc2UpIApsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkodG0pCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHBseXIpCmxpYnJhcnkoZ3JpZEV4dHJhKQoKYGBgCgozLiBBdXRoZW50aWNhdGlvbgpgYGB7cn0KI2F1dGhlbnRpY2F0aW9uIGZyb20gYWNjb3VudCAxCmNsaWVudF9pZCA9ICJYWFgiCmNsaWVudF9zZWNyZXQgPSAiWFhYIgphcGlfa2V5ID0gIlhYWCIKYGBgCgpgYGB7cn0KY2xpZW50X2lkID0gIlhYWCIKY2xpZW50X3NlY3JldCA9ICJYWFgiCmBgYAoKYGBge3J9CiMgdXNlIHRoZSB5b3V0dWJlIG9hdXRoIAp5dF9vYXV0aChhcHBfaWQgPSBjbGllbnRfaWQsCiAgICAgICAgIGFwcF9zZWNyZXQgPSBjbGllbnRfc2VjcmV0LAogICAgICAgICB0b2tlbiA9ICcnKQpgYGAKCjQuUmVhZGluZyBpbiBzY3JhcGVkIFVSTFMKYGBge3J9CiNyZWFkIGluIHNjcmFwZWQgeW91dHViZSB1cmxzCnJhd191cmxzID0gcmVhZF9jc3YoIi9Vc2Vycy95dXlhbmd3YW5nIDEvRGVza3RvcC9PSUREIDI0NS9EYXRhIFByb2plY3QgMi95b3V0dWJlX3VybHMuY3N2IikKYGBgCgo1LiBTY3JhcGluZyBkYXRhIGZyb20gWW91VHViZSBBUEkKYGBge3J9CiNmdW5jdGlvbiB0byBleHRyYWN0IHRoZSB2aWRlbyBJRApnZXRJRCA9IGZ1bmN0aW9uKHVybCkgewogIGlkID0gc3RyX3NwbGl0KHN0cmluZyA9IHVybCwgCiAgICBwYXR0ZXJuID0gIj0iLCAKICAgIG4gPSAyLAogICAgc2ltcGxpZnkgPSBUUlVFKVsgLCAyXQogIHJldHVybiAoaWQpCn0KcmF3X3VybHMkdmlkX2lkID0gc2FwcGx5KHJhd191cmxzJFVSTCwgZ2V0SUQpCnJhd191cmxzID0gdW5pcXVlKHJhd191cmxzKQoKIyBmdW5jdGlvbiB0byBzY3JhcGUgc3RhdHMgZm9yIGFsbCB2aWRzCmdldF9hbGxfc3RhdHMgPSBmdW5jdGlvbihpZCkgewogIGdldF9zdGF0cyh2aWRlb19pZCA9IGlkKQp9IAoKZ2V0X2FsbF9kZXRhaWxzID0gZnVuY3Rpb24oaWQpIHsKICBnZXRfdmlkZW9fZGV0YWlscyh2aWRlb19pZCA9IGlkKQp9Cgojc3RhdHMgb2YgYWxsIHZpZHMgLSBPTkxZIFJVTiBXSEVOIE5FRUQgKHF1b3RhIG9mIHF1ZXJpZXMgcGVyIGRheSkKdmlkZW9fYWxsX3N0YXRzID0gbWFwX2RmKC54ID0gcmF3X3VybHMkdmlkX2lkLCAuZiA9IGdldF9hbGxfc3RhdHMpCgojcmVtb3ZlIHJvd3Mgd2l0aCBudWxsIHZhbAp2aWRlb19hbGxfc3RhdHMgPSBuYS5vbWl0KHZpZGVvX2FsbF9zdGF0cykKCiNqb2luCm1lcmdlZF9pZCA9IG1lcmdlKHggPSByYXdfdXJscywgeSA9IHZpZGVvX2FsbF9zdGF0cywgYnkueCA9ICJ2aWRfaWQiLCBieS55ID0gImlkIiwgYWxsLnkgPSBUUlVFKQoKI2dldHRpbmcgdmlkZW8gZGV0YWlscwp2aWRlb2RldHMgPSBsYXBwbHkoYXMuY2hhcmFjdGVyKG1lcmdlZF9pZCR2aWRfaWQpLCBmdW5jdGlvbih4KXsKICBnZXRfdmlkZW9fZGV0YWlscyh2aWRlb19pZCA9IHgsIHBhcnQ9InNuaXBwZXQiKQp9KQoKI2FwcGVuZGluZyB0byBkYXRhIGZyYW1lCmZvciAoaSBpbiAxIDogNjgxKSB7CiAgbWVyZ2VkX2lkW2ksXSRwdWJsaXNoZWRBdCA9IHZpZGVvZGV0c1tbaV1dW1siaXRlbXMiXV1bWzFdXVtbInNuaXBwZXQiXV1bWyJwdWJsaXNoZWRBdCJdXQogIG1lcmdlZF9pZFtpLF0kY2hhbm5lbElkID0gdmlkZW9kZXRzW1tpXV1bWyJpdGVtcyJdXVtbMV1dW1sic25pcHBldCJdXVtbImNoYW5uZWxJZCJdXQogIG1lcmdlZF9pZFtpLF0kZGVzY3JpcHRpb24gPSB2aWRlb2RldHNbW2ldXVtbIml0ZW1zIl1dW1sxXV1bWyJzbmlwcGV0Il1dW1siZGVzY3JpcHRpb24iXV0KICBtZXJnZWRfaWRbaSxdJHRhZ3MgPSBwYXN0ZSh2aWRlb2RldHNbW2ldXVtbIml0ZW1zIl1dW1sxXV1bWyJzbmlwcGV0Il1dW1sidGFncyJdXSwgY29sbGFwc2UgPSAnICcpCn0KCiNnZXR0aW5nIGNoYW5uZWwgc3RhdHMKY2hhbm5lbGRldHMgPSBsYXBwbHkoYXMuY2hhcmFjdGVyKG1lcmdlZF9pZCRjaGFubmVsSWQpLCBmdW5jdGlvbih4KXsKICBnZXRfY2hhbm5lbF9zdGF0cyh4KQp9KQoKI2FkZGluZyBjaGFubmVsIHN0YXRzIHRvIG1haW4gZGYKZm9yIChpIGluIDEgOiA2ODEpIHsKICBtZXJnZWRfaWRbaSxdJGNoYW5uZWxfdmlld3MgPSBhcy5udW1lcmljKGNoYW5uZWxkZXRzW1tpXV1bWyJzdGF0aXN0aWNzIl1dW1sidmlld0NvdW50Il1dKQogIG1lcmdlZF9pZFtpLF0kY2hhbm5lbF90aXRsZSA9IGNoYW5uZWxkZXRzW1tpXV1bWyJzbmlwcGV0Il1dW1sidGl0bGUiXV0KICBtZXJnZWRfaWRbaSxdJGNoYW5uZWxfZGVzYyA9IGNoYW5uZWxkZXRzW1tpXV1bWyJzbmlwcGV0Il1dW1siZGVzY3JpcHRpb24iXV0KICBtZXJnZWRfaWRbaSxdJGNoYW5uZWxfc3VicyA9IGNoYW5uZWxkZXRzW1tpXV1bWyJzdGF0aXN0aWNzIl1dW1sic3Vic2NyaWJlckNvdW50Il1dCn0KYGBgCgo2LiBNYW5pcHVsYXRpb24gdG8gZ2V0IHNvbWUgYmFzaWMgaW5mbyBvbiB0aGUgdmlkZW9zIHNjcmFwZWQgZnJvbSBob21lcGFnZQpgYGB7cn0KI2NvbnZlcnQgYWxsIHRvIG51bWVyaWNzCm1lcmdlZF9pZCRsaWtlQ291bnQgPSBhcy5udW1lcmljKG1lcmdlZF9pZCRsaWtlQ291bnQpCm1lcmdlZF9pZCRkaXNsaWtlQ291bnQgPSBhcy5udW1lcmljKG1lcmdlZF9pZCRkaXNsaWtlQ291bnQpCm1lcmdlZF9pZCR2aWV3Q291bnQgPSBhcy5udW1lcmljKG1lcmdlZF9pZCR2aWV3Q291bnQpCm1lcmdlZF9pZCRjaGFubmVsX3N1YnMgPSBhcy5udW1lcmljKG1lcmdlZF9pZCRjaGFubmVsX3N1YnMpCm1lcmdlZF9pZCRjb21tZW50Q291bnQgPSBhcy5udW1lcmljKG1lcmdlZF9pZCRjb21tZW50Q291bnQpCgojd2hhdCBpcyB0aGUgbWVkaWFuIG9mIHZpZXdzL2xpa2VzL2Rpc2xpa2VzL3N1YnMgdGhhdCBZb3VUdWJlIHJlY29tbWVuZHMgdG8gYSBuZXcgdXNlcgptZWRpYW5fdmlkX3ZpZXdzID0gbWVkaWFuKG1lcmdlZF9pZCR2aWV3Q291bnQpCm1lZGlhbl92aWRfbGlrZXMgPSBtZWRpYW4obWVyZ2VkX2lkJGxpa2VDb3VudCkKbWVkaWFuX3ZpZF9kaXNsaWtlcyA9IG1lZGlhbihtZXJnZWRfaWQkZGlzbGlrZUNvdW50KQptZWRpYW5fY2hhbm5lbF9zdWJzID0gbWVkaWFuKG1lcmdlZF9pZCRjaGFubmVsX3N1YnMpCgojbGlrZSB0byBkaXNsaWtlIHJhdGlvCm1lcmdlZF9pZCRsaWtlX2Rpc2xpa2VfcmF0aW8gPSBtZXJnZWRfaWQkbGlrZUNvdW50IC8gbWVyZ2VkX2lkJGRpc2xpa2VDb3VudAoKI3N1YnNjcmliZXIgZW5nYWdlbWVudAptZXJnZWRfaWQkc3Vic19lbmdhZ2UgPSBtZXJnZWRfaWQkdmlld0NvdW50IC8gbWVyZ2VkX2lkJGNoYW5uZWxfc3VicwoKI2NvbW1lbnRzIHBlciB2aWV3Cm1lcmdlZF9pZCRjb21tZW50c19yYXRpbyA9IG1lcmdlZF9pZCR2aWV3Q291bnQgLyBtZXJnZWRfaWQkY29tbWVudENvdW50CgojZmluZGluZyB0aGUgYmVzdC93b3JzdCBkaXNsaWtlIHJhdGlvcwpkZl9maWx0ZXJlZCA9IG1lcmdlZF9pZCAlPiUgZmlsdGVyKGxpa2VDb3VudCA+IDEwMCAmIGNoYW5uZWxfc3VicyA+IDEwMCkgJT4lIG5hLm9taXQoKQp3b3JzdF9kaXNsaWtlX3JhdGlvID0gZGZfZmlsdGVyZWRbb3JkZXIoZGZfZmlsdGVyZWQkbGlrZV9kaXNsaWtlX3JhdGlvKSwgYygiTGluayIsImNoYW5uZWxfdGl0bGUiLCJsaWtlX2Rpc2xpa2VfcmF0aW8iKV0KYmVzdF9saWtlX3JhdGlvID0gZGZfZmlsdGVyZWRbb3JkZXIoLWRmX2ZpbHRlcmVkJGxpa2VfZGlzbGlrZV9yYXRpbyksIGMoIkxpbmsiLCJjaGFubmVsX3RpdGxlIiwibGlrZV9kaXNsaWtlX3JhdGlvIildCmhlYWQod29yc3RfZGlzbGlrZV9yYXRpbywgMTUpCmhlYWQoYmVzdF9saWtlX3JhdGlvLCAxNSkKCiNjcmVhdGluZyBoaXN0b2dyYW0gb2YgZGF0YQpoaXN0KGRmX2xpa2VfZGlzbGlrZV9yYXRpbyRsaWtlX2Rpc2xpa2VfcmF0aW8sIG1haW49Ikhpc3RvZ3JhbSBmb3IgTGlrZS9EaXNsaWtlIFJhdGlvIGFtb25nIDYwMCsgWW91VHViZSBWaWRlb3MiLCAKICAgICB4bGFiPSJMaWtlL0Rpc2xpa2UgUmF0aW8iLCAKICAgICBib3JkZXI9IndoaXRlIiwgCiAgICAgY29sPSJyZWQiLCkKCiNmaW5kaW5nIHRoZSBiZXN0L3dvcnN0IHN1YnMgZW5nYWdlbWVudAp3b3JzdF9zdWJzX2VuZ2FnZW1lbnQgPSBkZl9maWx0ZXJlZFtvcmRlcihkZl9maWx0ZXJlZCRzdWJzX2VuZ2FnZSksIGMoIkxpbmsiLCJjaGFubmVsX3RpdGxlIiwic3Vic19lbmdhZ2UiKV0KYmVzdF9zdWJzX2VuZ2FnZW1lbnQgPSBkZl9maWx0ZXJlZFtvcmRlcigtZGZfZmlsdGVyZWQkc3Vic19lbmdhZ2UpLCBjKCJMaW5rIiwiY2hhbm5lbF90aXRsZSIsInN1YnNfZW5nYWdlIildCmhlYWQod29yc3Rfc3Vic19lbmdhZ2VtZW50LCAxMCkKaGVhZChiZXN0X3N1YnNfZW5nYWdlbWVudCwgMTApCgojZmluZGluZyB0aGUgYmVzdC93b3JzdCBjb21tZW50IHJhdGlvCndvcnN0X2NvbW1lbnRfcmF0aW8gPSBkZl9maWx0ZXJlZFtvcmRlcihkZl9maWx0ZXJlZCRjb21tZW50c19yYXRpbyksIGMoIkxpbmsiLCJjaGFubmVsX3RpdGxlIiwiY29tbWVudHNfcmF0aW8iKV0KYmVzdF9jb21tZW50X3JhdGlvID0gZGZfZmlsdGVyZWRbb3JkZXIoLWRmX2ZpbHRlcmVkJGNvbW1lbnRzX3JhdGlvKSwgYygiTGluayIsImNoYW5uZWxfdGl0bGUiLCJjb21tZW50c19yYXRpbyIpXQpoZWFkKHdvcnN0X2NvbW1lbnRfcmF0aW8sIDEwKQpoZWFkKGJlc3RfY29tbWVudF9yYXRpbywgMTApCmBgYAoKR2VuZXJhdGUgd29yZGNsb3VkIHJlcHJlc2VudGluZyB0aGUgdmlkZW9zIHNob3duCmBgYHtyfQojZ2VuZXJhdGluZyB3b3JkIGNsb3VkIGZyb20gdG9wIDEwMCB2aWRzIHNjcmFwZWQKdG9wMTAwdmlld3MgPSBtZXJnZWRfaWQgJT4lIGZpbHRlcihsaWtlQ291bnQgPiAxMDAgJiBjaGFubmVsX3N1YnMgPiAxMDApICU+JSBuYS5vbWl0KCkKdG9wMTAwdmlld3MgPSB0b3AxMDB2aWV3c1tvcmRlcigtdG9wMTAwdmlld3Mkdmlld0NvdW50KSxdCnRvcDEwMHZpZXdzID0gaGVhZCh0b3AxMDB2aWV3cywgMTAwKQoKYWxsZGVzYyA9ICIiCgpmb3IgKGkgaW4gMToxMDApIHsKICBhbGxkZXNjID0gcGFzdGUoYWxsZGVzYywgdG9wMTAwdmlld3NbaSwgImRlc2NyaXB0aW9uIl0sIHNlcD0iICIpCn0KCiNjb3JwdXMKY29ycHVzID0gVkNvcnB1cyhWZWN0b3JTb3VyY2UodG9wMTAwdmlld3MkZGVzY3JpcHRpb24pKQoKI1N0ZXAgMTogY2xlYW5pbmcKY29ycCA9IHRtX21hcChjb3JwdXMsIHJlbW92ZVB1bmN0dWF0aW9uKSAKY29ycCA9IHRtX21hcChjb3JwLCByZW1vdmVOdW1iZXJzKSAKY29ycCA9IHRtX21hcChjb3JwLCBjb250ZW50X3RyYW5zZm9ybWVyKHRvbG93ZXIpICxsYXp5PVRSVUUpIApjb3JwID0gdG1fbWFwKGNvcnAsIGNvbnRlbnRfdHJhbnNmb3JtZXIocmVtb3ZlV29yZHMpLCBjKCJUSUwiKSAsbGF6eT1UUlVFKQpjb3JwID0gdG1fbWFwKGNvcnAsIGNvbnRlbnRfdHJhbnNmb3JtZXIocmVtb3ZlV29yZHMpLCBzdG9wd29yZHMoImVuZ2xpc2giKSAsbGF6eT1UUlVFKQpjb3JwID0gdG1fbWFwKGNvcnAsIHJlbW92ZVdvcmRzLCBjKCJ0aGUiLCAiZm9yIiwgImlzIiwgImFuZCIpKSAKY29ycCA9IHRtX21hcChjb3JwLCBzdHJpcFdoaXRlc3BhY2UpCgpkdG0gPSBEb2N1bWVudFRlcm1NYXRyaXgoY29ycCkKZHRtcyA9IHJlbW92ZVNwYXJzZVRlcm1zKGR0bSwgMC45ODMpCmRpbShkdG0pCmRpbShkdG1zKQpkdG1zX20gPSBhcy5tYXRyaXgoZHRtcykKCiMgY29sU3VtcyBhZGRzIHVwIHZhbHVlIG92ZXIgYWxsIG9mIHRoZSBDb2x1bW5zIGluIGEgbWF0cml4CiMgcm93U3VtcyhtKSBpcyB0aGUgZXF1aXZhbGVudCBvdmVyIHJvd3MKd29yZC5mcmVxID0gY29sU3VtcyhkdG1zX20pCndvcmQuZnJlcSA9IHNvcnQod29yZC5mcmVxLCBkZWNyZWFzaW5nPVQpCmQgPC0gZGF0YS5mcmFtZSh3b3JkID0gbmFtZXMod29yZC5mcmVxKSxmcmVxPXdvcmQuZnJlcSkKCiNjcmVhdGUgd29yZGNsb3VkCndvcmRjbG91ZCh3b3JkcyA9IGQkd29yZCwgZnJlcSA9IGQkZnJlcSwgbWluLmZyZXEgPSAxLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwgcmFuZG9tLm9yZGVyPUZBTFNFLCByb3QucGVyPTAuMzUsIAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOCwgIkRhcmsyIikpCmBgYAoKTG9hZCBpbiBkYXRhIGZyb20gCmBgYHtyfQp0b3A1MGdhbWVycyA9IHJlYWRfY3N2KCIvVXNlcnMveXV5YW5nd2FuZyAxL0Rlc2t0b3AvT0lERCAyNDUvRGF0YSBQcm9qZWN0IDIvdG9wMTAwZ2FtZS5jc3YiKQp0b3A1MHZsb2dnZXJzID0gcmVhZF9jc3YoIi9Vc2Vycy95dXlhbmd3YW5nIDEvRGVza3RvcC9PSUREIDI0NS9EYXRhIFByb2plY3QgMi90b3AxMDBibG9nZ2Vycy5jc3YiKQp0b3A1MGNvbWVkaWFucyA9IHJlYWRfY3N2KCIvVXNlcnMveXV5YW5nd2FuZyAxL0Rlc2t0b3AvT0lERCAyNDUvRGF0YSBQcm9qZWN0IDIvdG9wMTAwY29tZWR5LmNzdiIpCmNvbG5hbWVzKHRvcDUwdmxvZ2dlcnMpW3doaWNoKG5hbWVzKHRvcDUwdmxvZ2dlcnMpID09ICJ1c2VyIildIDwtICJ1c2VybmFtZSIKCmBgYAoKRWRpdCB0aGUgbnVtYmVycwpgYGB7cn0KCiNmdW5jdGlvbiB0aGF0IGNvbnZlcnN0IHRoZSBzdHJpbmdzIHRvIG51bWJlcnMKY29udmVydCA9IGZ1bmN0aW9uKG51bWJlcikgewogIGlmIChncmVwbCgiQiIsIG51bWJlcikpIHsKICAgIGFzLm51bWVyaWMoc3Ryc3BsaXQobnVtYmVyLCAiQiIpW1sxXV0pICogMTAwMDAwMDAwMAogIH0gZWxzZSBpZiAoZ3JlcGwoIk0iLCBudW1iZXIpKSB7CiAgICBhcy5udW1lcmljKHN0cnNwbGl0KG51bWJlciwgIk0iKVtbMV1dKSAqIDEwMDAwMDAKICB9IGVsc2UgaWYgKGdyZXBsKCJLIiwgbnVtYmVyKSkgewogICAgYXMubnVtZXJpYyhzdHJzcGxpdChudW1iZXIsICJLIilbWzFdXSkgKiAxMDAwCiAgfSBlbHNlIHsKICAgIGFzLm51bWVyaWMobnVtYmVyKQogIH0KfQoKY29udmVydERhdGUgPSBmdW5jdGlvbihkYXRlKSB7CiAgYXMuRGF0ZShkYXRlLCAiJVktJW0tJWQiKQp9CgojY29udmVydCBmb3IgZWFjaCBvZiB0aGUgMyBjYXRlZ29yaWVzCnRvcDUwZ2FtZXJzJHRvdGFsdmlld3MgPSBzYXBwbHkodG9wNTBnYW1lcnMkdG90YWx2aWV3cywgY29udmVydCkKdG9wNTBnYW1lcnMkc3VicyA9IHNhcHBseSh0b3A1MGdhbWVycyRzdWJzLCBjb252ZXJ0KQp0b3A1MGdhbWVycyR0b3RhbFZpZHMgPSBzYXBwbHkodG9wNTBnYW1lcnMkdG90YWxWaWRzLCBjb252ZXJ0KQp0b3A1MGdhbWVycyRkYXRlID0gc2FwcGx5KHRvcDUwZ2FtZXJzJGpvaW5fZGF0ZSwgY29udmVydERhdGUpCgp0b3A1MHZsb2dnZXJzJHRvdGFsdmlld3MgPSBzYXBwbHkodG9wNTB2bG9nZ2VycyR0b3RhbHZpZXdzLCBjb252ZXJ0KQp0b3A1MHZsb2dnZXJzJHN1YnMgPSBzYXBwbHkodG9wNTB2bG9nZ2VycyRzdWJzLCBjb252ZXJ0KQp0b3A1MHZsb2dnZXJzJHRvdGFsVmlkcyA9IHNhcHBseSh0b3A1MHZsb2dnZXJzJHRvdGFsVmlkcywgY29udmVydCkKdG9wNTB2bG9nZ2VycyRkYXRlID0gc2FwcGx5KHRvcDUwdmxvZ2dlcnMkam9pbl9kYXRlLCBjb252ZXJ0RGF0ZSkKCnRvcDUwY29tZWRpYW5zJHRvdGFsdmlld3MgPSBzYXBwbHkodG9wNTBjb21lZGlhbnMkdG90YWx2aWV3cywgY29udmVydCkKdG9wNTBjb21lZGlhbnMkc3VicyA9IHNhcHBseSh0b3A1MGNvbWVkaWFucyRzdWJzLCBjb252ZXJ0KQp0b3A1MGNvbWVkaWFucyR0b3RhbFZpZHMgPSBzYXBwbHkodG9wNTBjb21lZGlhbnMkdG90YWxWaWRzLCBjb252ZXJ0KQp0b3A1MGNvbWVkaWFucyRkYXRlID0gc2FwcGx5KHRvcDUwY29tZWRpYW5zJGpvaW5fZGF0ZSwgY29udmVydERhdGUpCgojc29ydCB0aGVtIGJ5IHN1YnMKdG9wNTBjb21lZGlhbnMgPSB0b3A1MGNvbWVkaWFuc1tvcmRlcigtdG9wNTBjb21lZGlhbnMkc3VicyksXQp0b3A1MHZsb2dnZXJzID0gdG9wNTB2bG9nZ2Vyc1tvcmRlcigtdG9wNTB2bG9nZ2VycyRzdWJzKSxdCnRvcDUwZ2FtZXJzID0gdG9wNTBnYW1lcnNbb3JkZXIoLXRvcDUwZ2FtZXJzJHN1YnMpLF0KCiNhcHBlbmQgdGhlaXIgInJhbmtzIiBiYXNlZCBvbiBzdWJzY3JpYmVyIGNvdW50CnJhbmsgPSBjKDE6NTApCnRvcDUwZ2FtZXJzID0gY2JpbmQodG9wNTBnYW1lcnMsIGRhdGEuZnJhbWUocmFuaykpCnRvcDUwdmxvZ2dlcnMgPSBjYmluZCh0b3A1MHZsb2dnZXJzLCBkYXRhLmZyYW1lKHJhbmspKQp0b3A1MGNvbWVkaWFucyA9IGNiaW5kKHRvcDUwY29tZWRpYW5zLCBkYXRhLmZyYW1lKHJhbmspKQoKI3Bsb3Qgb2YgaG93IHN1YnNjcmliZXIgY291bnRzIGNvbXBhcmUgaW4gMyBjYXRlZ29yaWVzCnBsb3Rfc3VicyA9IGdncGxvdCgpICsgCmdlb21fbGluZShkYXRhPXRvcDUwZ2FtZXJzLCBhZXMoeD1yYW5rLCB5PXN1YnMpLCBjb2xvcj0nZ3JlZW4nKSArIApnZW9tX2xpbmUoZGF0YT10b3A1MHZsb2dnZXJzLCBhZXMoeD1yYW5rLCB5PXN1YnMpLCBjb2xvcj0nYmx1ZScpICsgCmdlb21fbGluZShkYXRhPXRvcDUwY29tZWRpYW5zLCBhZXMoeD1yYW5rLCB5PXN1YnMpLCBjb2xvcj0ncmVkJykgKyBnZ3RpdGxlKCJOdW1iZXIgb2YgU3Vic2NyaWJlcnMgZm9yIFRvcCA1MCBZb3VUdWJlcnMgb2YgRWFjaCBDYXRlZ29yeSIpICsKICB4bGFiKCJSYW5rIikgKyB5bGFiKCJOdW1iZXIgb2YgU3Vic2NyaWJlcnMiKQoKcGxvdF9zdWJzCgojcGxvdCBvZiBob3cgdG90YWwgdmlldyBjb3VudHMgY29tcGFyZSBpbiAzIGNhdGVnb3JpZXMKcGxvdF92aWV3cyA9IGdncGxvdCgpICsgCmdlb21fbGluZShkYXRhPXRvcDUwZ2FtZXJzLCBhZXMoeD1yYW5rLCB5PXRvdGFsdmlld3MpLCBjb2xvcj0nZ3JlZW4nKSArIApnZW9tX2xpbmUoZGF0YT10b3A1MHZsb2dnZXJzLCBhZXMoeD1yYW5rLCB5PXRvdGFsdmlld3MpLCBjb2xvcj0nYmx1ZScpICsgCmdlb21fbGluZShkYXRhPXRvcDUwY29tZWRpYW5zLCBhZXMoeD1yYW5rLCB5PXRvdGFsdmlld3MpLCBjb2xvcj0ncmVkJykgKyBnZ3RpdGxlKCJOdW1iZXIgb2YgVmlld3MgZm9yIFRvcCA1MCBZb3VUdWJlcnMgb2YgRWFjaCBDYXRlZ29yeSIpICsKeGxhYigiUmFuayIpICsgeWxhYigiVG90YWwgVmlld3MiKQoKcGxvdF92aWV3cwoKI3Bsb3Qgb2YgaG93IHN1YnNjcmliZXIgbnVtYmVyIG9mIHZpZGVvcyBwdWJsaXNoZWQgY29tcGFyZSBpbiAzIGNhdGVnb3JpZXMKcGxvdF92aWRzID0gZ2dwbG90KCkgKyAKZ2VvbV9saW5lKGRhdGE9dG9wNTBnYW1lcnMsIGFlcyh4PXJhbmssIHk9dG90YWxWaWRzKSwgY29sb3I9J2dyZWVuJykgKyAKZ2VvbV9saW5lKGRhdGE9dG9wNTB2bG9nZ2VycywgYWVzKHg9cmFuaywgeT10b3RhbFZpZHMpLCBjb2xvcj0nYmx1ZScpICsgCmdlb21fbGluZShkYXRhPXRvcDUwY29tZWRpYW5zLCBhZXMoeD1yYW5rLCB5PXRvdGFsVmlkcyksIGNvbG9yPSdyZWQnKSArIGdndGl0bGUoIk51bWJlciBvZiBUb3RhbCBWaWRlb3MgZm9yIFRvcCA1MCBZb3VUdWJlcnMgb2YgRWFjaCBDYXRlZ29yeSIpICsKeGxhYigiUmFuayIpICsgeWxhYigiVG90YWwgVmlkZW9zIikKCnBsb3RfdmlkcwoKI3Bsb3Qgc2hvd2luZyBudW1iZXIgb2Ygc3Vic2NyaWJlcnMgZnJvbSB3aGVuIHlvdSBqb2luZWQKZ2dwbG90KCkgKyAKZ2VvbV9saW5lKGRhdGE9dG9wNTBnYW1lcnMsIGFlcyh4PWpvaW5fZGF0ZSwgeT1zdWJzKSwgY29sb3I9J2dyZWVuJykgKyAKZ2VvbV9saW5lKGRhdGE9dG9wNTB2bG9nZ2VycywgYWVzKHg9am9pbl9kYXRlLCB5PXN1YnMpLCBjb2xvcj0nYmx1ZScpICsgCmdlb21fbGluZShkYXRhPXRvcDUwY29tZWRpYW5zLCBhZXMoeD1qb2luX2RhdGUsIHk9c3VicyksIGNvbG9yPSdyZWQnKSAgKyBnZ3RpdGxlKCJUaW1lbGluZSBvZiBKb2luIERhdGVzIG9mIFlvdVR1YmVycyBhbmQgTnVtYmVyIG9mIFN1YnNjcmliZXJzIikgKwp4bGFiKCJEYXRlIikgKyB5bGFiKCJOdW1iZXIgb2YgU3Vic2NyaWJlcnMiKSArIGxhYnMoZmlsbCA9ICJDYXRlZ29yaWVzIikKCmBgYAoKYGBge3J9CiNjcmVhdGUgY29sdW1uIGZvciBzdWJzY3JpYmVycyBwZXIgdmlkCnRvcDUwZ2FtZXJzJHN1YnNfcGVyX3ZpZCA9IHRvcDUwZ2FtZXJzJHN1YnMgLyB0b3A1MGdhbWVycyR0b3RhbFZpZHMKdG9wNTB2bG9nZ2VycyRzdWJzX3Blcl92aWQgPSB0b3A1MHZsb2dnZXJzJHN1YnMgLyB0b3A1MHZsb2dnZXJzJHRvdGFsVmlkcwp0b3A1MGNvbWVkaWFucyRzdWJzX3Blcl92aWQgPSB0b3A1MGNvbWVkaWFucyRzdWJzIC8gdG9wNTBjb21lZGlhbnMkdG90YWxWaWRzCgojYWRkIGNvbHVtbiBmb3IgdGhlaXIgY2F0ZWdvcnkKdG9wNTBnYW1lcnMkY2F0ZWdvcnkgPSAiR2FtZSIKdG9wNTB2bG9nZ2VycyRjYXRlZ29yeSA9ICJWbG9nIgp0b3A1MGNvbWVkaWFucyRjYXRlZ29yeSA9ICJDb21lZHkiCgphbGxfdG9wXzE1MCA9IHJiaW5kLmZpbGwobGlzdCh0b3A1MGdhbWVycywgdG9wNTB2bG9nZ2VycywgdG9wNTBjb21lZGlhbnMpKQoKdG9wX3N1YnNfcGVyX3ZpZCA9IGhlYWQoYWxsX3RvcF8xNTBbb3JkZXIoLWFsbF90b3BfMTUwJHN1YnNfcGVyX3ZpZCksIGMoInVzZXJuYW1lIiwgInN1YnNfcGVyX3ZpZCIsICJjYXRlZ29yeSIpXSwgNTApCgojY3JlYXRpbmcgcGllIGNoYXJ0CnRhbGx5X3N1YnNfcGVyX3ZpZCA9IHRvcF9zdWJzX3Blcl92aWQgJT4lIGdyb3VwX2J5KGNhdGVnb3J5KSAlPiUgdGFsbHkoKQp0YWxseV9zdWJzX3Blcl92aWQkcGN0ID0gcm91bmQodGFsbHlfc3Vic19wZXJfdmlkJG4vc3VtKHRhbGx5X3N1YnNfcGVyX3ZpZCRuKSoxMDApCm5hbWVzKHRhbGx5X3N1YnNfcGVyX3ZpZCkgPC0gYygiQ2F0ZWdvcnkiLCAiVG90YWwiLCAiUGVyY2VudGFnZSIpCmJwPC0gZ2dwbG90KHRhbGx5X3N1YnNfcGVyX3ZpZCwgYWVzKHg9IiIsIHk9UGVyY2VudGFnZSwgZmlsbD1DYXRlZ29yeSkpKwpnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiKQpwaWUgPC0gYnAgKyBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApICsgZ2d0aXRsZSgiQ2F0ZWdvcmllcyBvZiBUb3AgNTAgWW91VHViZXJzIGJ5IFN1YnNjcmliZXJzIHBlciBWaWRlbyIpCnBpZQpgYGAKCgoKYGBge3J9CiNnZXQgcGV3ZGllcGllCiNwZXdkID0gZ2V0X2NoYW5uZWxfc3RhdHMoIlVDLWxISlpSM0dxeG0yNF9WZF9BSjVZdyIpCgojZ2V0IGFsbCBvZiBoaXMgdmlkZW9zCiN2aWRlb3MgPSB5dF9zZWFyY2godGVybT0iIiwgdHlwZT0idmlkZW8iLCBjaGFubmVsX2lkID0gIlVDLWxISlpSM0dxeG0yNF9WZF9BSjVZdyIpCgojZ2V0IGFsbCB0aGVpciBzdGF0cwojdmlkZW9zdGF0cyA9IGxhcHBseShhcy5jaGFyYWN0ZXIodmlkZW9zJHZpZGVvX2lkKSwgZnVuY3Rpb24oeCl7CiAjIGdldF9zdGF0cyh2aWRlb19pZCA9IHgpCiN9KQpgYGAKCgoKCg==