1. Delete products that are not books from “products” and “copurchase” files. Note: In social network analysis, it important to define the boundary of your work; in other words, the boundary of the network.
setwd("/Users/brichew/Desktop/UCI MSBA/Fall/BANA 277/Social Networks HW/")
copurchase <- read.csv(file.choose(), header = TRUE)
products <- read.csv(file.choose(), header = TRUE)

products <- filter(products, group == "Book" &
                     products$salesrank <= 150000 &
                     products$salesrank != -1)

copurchase <- filter(copurchase, copurchase$Source %in% products$id & 
                        copurchase$Target %in% products$id)
  1. Create a variable named in-degree, to show how many “Source” products people who buy “Target” products buy; i.e. how many edges are to the focal product in “co-purchase” network.
library(igraph)

colnames(copurchase)[1] <- "id"
combined <- merge(x= products, y= copurchase, by="id", all.x = TRUE) 
head(combined)

#clean data
combined$Target <- as.numeric(combined$Target)
colnames(combined)[3] <- "group1"
combined1<- sqldf("SELECT id, Target, title, group1, salesrank, review_cnt, downloads, rating FROM combined Where Target !=0")
head(combined1)
g <- graph.data.frame(combined1, directed = T)

in_degree <- degree(g, mode = 'in')
class(in_degree)

The number of adjacent vertices, or sources, are going into the node or in our cause the Target.

  1. Create a variable named out-degree, to show how many “Target” products people who buy “Source” product also buy; i.e., how many edges are from the focal product in “co-purchase” network.
out_degree <- degree(g, mode = 'out')

The number of vertices that are from the Nodes, or Target products, that are leaving the Node.

  1. Pick up one of the products (in case there are multiple) with highest degree (in-degree + out-degree), and find its subcomponent, i.e., all the products that are connected to this focal product. From this point on, you will work only on this subcomponent.
#show how many degrees are connected to nodes
all_degree <- degree(g, mode = 'total')
#what is the max numb of degrees for all the nodes
max(all_degree)
all_degree[all_degree==53]
sub <- subcomponent(g, "33",'all') 
sub
sub

We ran the degree function to determine how many degrees are connected to the nodes. Then, we asked R to spit out the maximum number of in and out degrees for all the nodes, to which we got 53. From there, we needed to figure out which of the nodes had 53 degrees or in other words, are connected to this particular focal product. We found out that node 4429 and node 33 both have 53 degrees. As for our subcomponent, we decided to use the node 33.

  1. Visualize the subcomponent using iGraph, trying out different colors, node and edge sizes and layouts, so that the result is most appealing. Find the diameter, and color the nodes along the diameter. Provide your insights from the visualizations.
graph <- induced_subgraph(g, sub)

V(graph)
E(graph)

V(graph)$label <- V(graph)$name
V(graph)$degree <- degree(graph)

plot(graph,
     vertex.color='pink',
     vertex.size= V(graph)$degree*0.2,
     edge.arrow.size=0.01,
     vertex.label.cex=0.01,
     layout=layout.kamada.kawai)
diameter(graph, directed = T, weights = NA)
d <- get_diameter(graph, weights = NULL)

Diameter is the longest distance between two vertices, and we found the diameter to be 9. In the graph, the 10 red nodes are the vertices that on the longest path, and they are 37895, 27936, 21584, 10889, 11080, 14111, 4429, 2501, 3588, 6676.

V(graph)$color<-"yellow"
V(graph)$color[d]<-"red"

#testing different colors
plot(graph,
     vertex.color=V(graph)$color,
     vertex.size= V(graph)$degree*0.2,
     edge.arrow.size=0.01,
     vertex.label.cex=0.01,
     layout=layout.kamada.kawai)

The graph demonstrates 904 vertices. These 904 vertices are the book ids that connected to the book whose id = 33, directly and indirectly. Size of the vertices represents the number of vertices that connected to a vertice; the bigger of the vertice, the more vertices link to it. The distance between each vertice represents how strong the vertices connect to each other; the longer the ties, the weaker the relationship. Therefore, some vertices look like clusters in the middle with short edges, which means these books have strong connections. Some vertices are nodes on the edges, which means weaker connections.

  1. Compute various statistics about this network (i.e., subcomponent), including degree distribution, density, and centrality (degree centrality, closeness centrality and between centrality), hub/authority scores, etc. Interpret your results.
deg_dist<- degree.distribution(graph,cumulative = T, mode="all")
plot(x=0:max(all_degree), y=1-deg_dist, pch=19, cex=1.2, col="orange", xlab="Degree", ylab="Cumulative Frequency")


dd_all<-degree_distribution(graph,cumulative=T)
plot(dd_all, xlab="Degree")

dd_in<-degree_distribution(graph,cumulative=T,mode="in")
plot(dd_in, xlab="Degree")

dd_out<-degree_distribution(graph,cumulative=T,mode="out")
plot(dd_out, xlab="Degree")

Degree means the number of ties.

#density
edge_density(graph, loops=F)

Density is the proportion of present edges from all possible edges in the network. The density of our graph is 5.250029e-05, which is small; therefore, the networking is pretty dense.

#centrality
centr_degree(graph)

Centrality calculates the centrality of all the 904 nodes, our results vary from 0 to 53, and 53 is the highest centrality.

closeness <- closeness(graph, mode='all', weights=NA)

Closeness calculates the centrality based on distance to other nodes.

betweeness <- betweenness(graph, directed='T', weights=NA)

Betweenness (centrality based on a broker position connecting others)

#hub/authority scores
#hub centraility eigenvector
hub_score1 <- hub.score(graph)$vector

#authority centraility eiganvector
authority_score1 <- authority.score(graph)$vector
  1. Create a group of variables containing the information of neighbors that “point to” focal products. The variables include:
  1. Neighbors’ mean rating (nghb_mn_rating),
  2. Neighbors’ mean salesrank (nghb_mn_salesrank),
  3. Neighbors’ mean number of reviews (nghb_mn_review_cnt), Note: you may recall the functions in “dplyr” such as group_by, inner_join, summarize, mean, etc.
rating<-copurchase %>%
  group_by(Target) %>%
  inner_join(products, by=c('id'='id'))%>%
  transmute(nghb_mn_rating=mean(rating))

rank<-copurchase %>%
  group_by(Target) %>%
  inner_join(products,by=c('id'='id'))%>%
  transmute(nghb_mn_salesrank=mean(salesrank))


reviews<-copurchase %>%
  group_by(Target) %>%
  inner_join(products,by=c('id'='id'))%>%
  transmute(nghb_mn_review_cnt=mean(review_cnt))

products$id <- as.vector(products$id)
sub_id <- as_ids(sub)
products_sub <- products[products$id %in% sub_id,]

mean <- copurchase %>% 
  group_by(Target) %>% 
  inner_join(products_sub, by = c('id' = 'id')) %>%
  summarise(nghb_mn_rating=mean(rating),
            nghb_mn_salesrank=mean(salesrank),
            nghb_mn_review_cnt=mean(review_cnt))
  1. Include the variables (taking logs where necessary) created in Parts 2-6 above into the “products” information and fit a Poisson regression to predict salesrank of all the books in this subcomponent using products’ own information and their neighbor’s information. Provide an interpretation of your results. Note: Lower salesrank means higher sales. Data points in the network are related. The performance of one node is influenced by the performance of its neighbors. Also, it’s not necessary that all variables matter.
#conver to data frames
in_degree1 <- as.data.frame(in_degree)
in_degree1 <- cbind(newColName = rownames(in_degree1), in_degree1)
rownames(in_degree1) <- 1:nrow(in_degree1)
colnames(in_degree1) <- c("Nodes", "in_degree")

out_degree1 <- as.data.frame(out_degree)
out_degree1 <- cbind(newColName = rownames(out_degree1), out_degree1)
rownames(out_degree1) <- 1:nrow(out_degree1)
colnames(out_degree1) <- c("Nodes", "out_degree")

closeness1 <- as.data.frame(closeness)
closeness1 <- cbind(newColName = rownames(closeness1), closeness1)
rownames(closeness1) <- 1:nrow(closeness1)
colnames(closeness1) <- c("Nodes", "closeness")

betweeness1 <- as.data.frame(betweeness)
betweeness1 <- cbind(newColName = rownames(betweeness1), betweeness1)
rownames(betweeness1) <- 1:nrow(betweeness1)
colnames(betweeness1) <- c("Nodes", "betweeness")

hub_score2 <- as.data.frame(hub_score1)
hub_score2 <- cbind(newColName = rownames(hub_score2), hub_score2)
rownames(hub_score2) <- 1:nrow(hub_score2)
colnames(hub_score2) <- c("Nodes", "hub_score")

authority_score2 <- as.data.frame(authority_score1)
authority_score2 <- cbind(newColName = rownames(authority_score2), authority_score2)
rownames(authority_score2) <- 1:nrow(authority_score2)
colnames(authority_score2) <- c("Nodes", "authority_score")

poisson_data <- sqldf("SELECT hub_score2.Nodes, hub_score, betweeness, authority_score, closeness, in_degree, out_degree, nghb_mn_rating, nghb_mn_salesrank, nghb_mn_review_cnt, products.id, products.review_cnt, products.rating, products.salesrank
                      FROM hub_score2, betweeness1, authority_score2, closeness1, in_degree1,            out_degree1, mean, products
                      WHERE hub_score2.Nodes = betweeness1.Nodes 
                      and hub_score2.Nodes = authority_score2.Nodes
                      and hub_score2.Nodes = closeness1.Nodes
                      and hub_score2.Nodes = in_degree1.Nodes
                      and hub_score2.Nodes = out_degree1.Nodes
                      and hub_score2.Nodes = mean.Target
                      and hub_score2.Nodes = products.id")

#run poisson regression
summary(salesrating_prediction<- glm(salesrank ~ review_cnt + rating + hub_score + betweeness + 
authority_score + closeness + in_degree + out_degree + nghb_mn_rating+ nghb_mn_salesrank + nghb_mn_review_cnt, family="poisson", data=poisson_data))

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tCnRpdGxlOiAiU29jaWFsIE5ldHdvcmsgVGVhbSBBc3NpZ25tZW50IgphdXRob3I6ICJUZWFtIDE0IgpkYXRlOiAiMTEtMDktMjAxOCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoxLiAJRGVsZXRlIHByb2R1Y3RzIHRoYXQgYXJlIG5vdCBib29rcyBmcm9tIOKAnHByb2R1Y3Rz4oCdIGFuZCDigJxjb3B1cmNoYXNl4oCdIGZpbGVzLgpOb3RlOiBJbiBzb2NpYWwgbmV0d29yayBhbmFseXNpcywgaXQgaW1wb3J0YW50IHRvIGRlZmluZSB0aGUgYm91bmRhcnkgb2YgeW91ciB3b3JrOyBpbiBvdGhlciB3b3JkcywgdGhlIGJvdW5kYXJ5IG9mIHRoZSBuZXR3b3JrLgoKYGBge3J9CnNldHdkKCIvVXNlcnMvYnJpY2hldy9EZXNrdG9wL1VDSSBNU0JBL0ZhbGwvQkFOQSAyNzcvU29jaWFsIE5ldHdvcmtzIEhXLyIpCmNvcHVyY2hhc2UgPC0gcmVhZC5jc3YoZmlsZS5jaG9vc2UoKSwgaGVhZGVyID0gVFJVRSkKcHJvZHVjdHMgPC0gcmVhZC5jc3YoZmlsZS5jaG9vc2UoKSwgaGVhZGVyID0gVFJVRSkKCnByb2R1Y3RzIDwtIGZpbHRlcihwcm9kdWN0cywgZ3JvdXAgPT0gIkJvb2siICYKICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdHMkc2FsZXNyYW5rIDw9IDE1MDAwMCAmCiAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RzJHNhbGVzcmFuayAhPSAtMSkKCmNvcHVyY2hhc2UgPC0gZmlsdGVyKGNvcHVyY2hhc2UsIGNvcHVyY2hhc2UkU291cmNlICVpbiUgcHJvZHVjdHMkaWQgJiAKICAgICAgICAgICAgICAgICAgICAgICAgY29wdXJjaGFzZSRUYXJnZXQgJWluJSBwcm9kdWN0cyRpZCkKCmBgYAoKMi4gCUNyZWF0ZSBhIHZhcmlhYmxlIG5hbWVkIGluLWRlZ3JlZSwgdG8gc2hvdyBob3cgbWFueSDigJxTb3VyY2XigJ0gcHJvZHVjdHMgcGVvcGxlIHdobyBidXkg4oCcVGFyZ2V04oCdIHByb2R1Y3RzIGJ1eTsgaS5lLiBob3cgbWFueSBlZGdlcyBhcmUgdG8gdGhlIGZvY2FsIHByb2R1Y3QgaW4g4oCcY28tcHVyY2hhc2XigJ0gbmV0d29yay4KCmBgYHtyfQpsaWJyYXJ5KGlncmFwaCkKCmNvbG5hbWVzKGNvcHVyY2hhc2UpWzFdIDwtICJpZCIKY29tYmluZWQgPC0gbWVyZ2UoeD0gcHJvZHVjdHMsIHk9IGNvcHVyY2hhc2UsIGJ5PSJpZCIsIGFsbC54ID0gVFJVRSkgCmhlYWQoY29tYmluZWQpCgojY2xlYW4gZGF0YQpjb21iaW5lZCRUYXJnZXQgPC0gYXMubnVtZXJpYyhjb21iaW5lZCRUYXJnZXQpCmNvbG5hbWVzKGNvbWJpbmVkKVszXSA8LSAiZ3JvdXAxIgpjb21iaW5lZDE8LSBzcWxkZigiU0VMRUNUIGlkLCBUYXJnZXQsIHRpdGxlLCBncm91cDEsIHNhbGVzcmFuaywgcmV2aWV3X2NudCwgZG93bmxvYWRzLCByYXRpbmcgRlJPTSBjb21iaW5lZCBXaGVyZSBUYXJnZXQgIT0wIikKaGVhZChjb21iaW5lZDEpCmcgPC0gZ3JhcGguZGF0YS5mcmFtZShjb21iaW5lZDEsIGRpcmVjdGVkID0gVCkKCmluX2RlZ3JlZSA8LSBkZWdyZWUoZywgbW9kZSA9ICdpbicpCmNsYXNzKGluX2RlZ3JlZSkKYGBgCgpUaGUgbnVtYmVyIG9mIGFkamFjZW50IHZlcnRpY2VzLCBvciBzb3VyY2VzLCBhcmUgZ29pbmcgaW50byB0aGUgbm9kZSBvciBpbiBvdXIgY2F1c2UgdGhlIFRhcmdldC4KCgozLiAJQ3JlYXRlIGEgdmFyaWFibGUgbmFtZWQgb3V0LWRlZ3JlZSwgdG8gc2hvdyBob3cgbWFueSDigJxUYXJnZXTigJ0gcHJvZHVjdHMgcGVvcGxlIHdobyBidXkg4oCcU291cmNl4oCdIHByb2R1Y3QgYWxzbyBidXk7IGkuZS4sIGhvdyBtYW55IGVkZ2VzIGFyZSBmcm9tIHRoZSBmb2NhbCBwcm9kdWN0IGluIOKAnGNvLXB1cmNoYXNl4oCdIG5ldHdvcmsuCgpgYGB7cn0Kb3V0X2RlZ3JlZSA8LSBkZWdyZWUoZywgbW9kZSA9ICdvdXQnKQpgYGAKVGhlIG51bWJlciBvZiB2ZXJ0aWNlcyB0aGF0IGFyZSBmcm9tIHRoZSBOb2Rlcywgb3IgVGFyZ2V0IHByb2R1Y3RzLCB0aGF0IGFyZSBsZWF2aW5nIHRoZSBOb2RlLiAKCgo0LiAJUGljayB1cCBvbmUgb2YgdGhlIHByb2R1Y3RzIChpbiBjYXNlIHRoZXJlIGFyZSBtdWx0aXBsZSkgd2l0aCBoaWdoZXN0IGRlZ3JlZSAoaW4tZGVncmVlICsgb3V0LWRlZ3JlZSksIGFuZCBmaW5kIGl0cyBzdWJjb21wb25lbnQsIGkuZS4sIGFsbCB0aGUgcHJvZHVjdHMgdGhhdCBhcmUgY29ubmVjdGVkIHRvIHRoaXMgZm9jYWwgcHJvZHVjdC4gRnJvbSB0aGlzIHBvaW50IG9uLCB5b3Ugd2lsbCB3b3JrIG9ubHkgb24gdGhpcyBzdWJjb21wb25lbnQuCmBgYHtyfQojc2hvdyBob3cgbWFueSBkZWdyZWVzIGFyZSBjb25uZWN0ZWQgdG8gbm9kZXMKYWxsX2RlZ3JlZSA8LSBkZWdyZWUoZywgbW9kZSA9ICd0b3RhbCcpCiN3aGF0IGlzIHRoZSBtYXggbnVtYiBvZiBkZWdyZWVzIGZvciBhbGwgdGhlIG5vZGVzCm1heChhbGxfZGVncmVlKQphbGxfZGVncmVlW2FsbF9kZWdyZWU9PTUzXQpzdWIgPC0gc3ViY29tcG9uZW50KGcsICIzMyIsJ2FsbCcpIApzdWIKc3ViCmBgYAoKV2UgcmFuIHRoZSBkZWdyZWUgZnVuY3Rpb24gdG8gZGV0ZXJtaW5lIGhvdyBtYW55IGRlZ3JlZXMgYXJlIGNvbm5lY3RlZCB0byB0aGUgbm9kZXMuIFRoZW4sIHdlIGFza2VkIFIgdG8gc3BpdCBvdXQgdGhlIG1heGltdW0gbnVtYmVyIG9mIGluIGFuZCBvdXQgZGVncmVlcyBmb3IgYWxsIHRoZSBub2RlcywgdG8gd2hpY2ggd2UgZ290IDUzLiBGcm9tIHRoZXJlLCB3ZSBuZWVkZWQgdG8gZmlndXJlIG91dCB3aGljaCBvZiB0aGUgbm9kZXMgaGFkIDUzIGRlZ3JlZXMgb3IgaW4gb3RoZXIgd29yZHMsIGFyZSBjb25uZWN0ZWQgdG8gdGhpcyBwYXJ0aWN1bGFyIGZvY2FsIHByb2R1Y3QuIFdlIGZvdW5kIG91dCB0aGF0IG5vZGUgNDQyOSBhbmQgbm9kZSAzMyBib3RoIGhhdmUgNTMgZGVncmVlcy4gQXMgZm9yIG91ciBzdWJjb21wb25lbnQsIHdlIGRlY2lkZWQgdG8gdXNlIHRoZSBub2RlIDMzLiAKCjUuIAlWaXN1YWxpemUgdGhlIHN1YmNvbXBvbmVudCB1c2luZyBpR3JhcGgsIHRyeWluZyBvdXQgZGlmZmVyZW50IGNvbG9ycywgbm9kZSBhbmQgZWRnZSBzaXplcyBhbmQgbGF5b3V0cywgc28gdGhhdCB0aGUgcmVzdWx0IGlzIG1vc3QgYXBwZWFsaW5nLiBGaW5kIHRoZSBkaWFtZXRlciwgYW5kIGNvbG9yIHRoZSBub2RlcyBhbG9uZyB0aGUgZGlhbWV0ZXIuIFByb3ZpZGUgeW91ciBpbnNpZ2h0cyBmcm9tIHRoZSB2aXN1YWxpemF0aW9ucy4KYGBge3J9CmdyYXBoIDwtIGluZHVjZWRfc3ViZ3JhcGgoZywgc3ViKQoKVihncmFwaCkKRShncmFwaCkKClYoZ3JhcGgpJGxhYmVsIDwtIFYoZ3JhcGgpJG5hbWUKVihncmFwaCkkZGVncmVlIDwtIGRlZ3JlZShncmFwaCkKCnBsb3QoZ3JhcGgsCiAgICAgdmVydGV4LmNvbG9yPSdwaW5rJywKICAgICB2ZXJ0ZXguc2l6ZT0gVihncmFwaCkkZGVncmVlKjAuMiwKICAgICBlZGdlLmFycm93LnNpemU9MC4wMSwKICAgICB2ZXJ0ZXgubGFiZWwuY2V4PTAuMDEsCiAgICAgbGF5b3V0PWxheW91dC5rYW1hZGEua2F3YWkpCgpgYGAKCmBgYHtyfQpkaWFtZXRlcihncmFwaCwgZGlyZWN0ZWQgPSBULCB3ZWlnaHRzID0gTkEpCmQgPC0gZ2V0X2RpYW1ldGVyKGdyYXBoLCB3ZWlnaHRzID0gTlVMTCkKCmBgYApEaWFtZXRlciBpcyB0aGUgbG9uZ2VzdCBkaXN0YW5jZSBiZXR3ZWVuIHR3byB2ZXJ0aWNlcywgYW5kIHdlIGZvdW5kIHRoZSBkaWFtZXRlciB0byBiZSA5LiBJbiB0aGUgZ3JhcGgsIHRoZSAxMCByZWQgbm9kZXMgYXJlIHRoZSB2ZXJ0aWNlcyB0aGF0IG9uIHRoZSBsb25nZXN0IHBhdGgsIGFuZCB0aGV5IGFyZSAzNzg5NSwgMjc5MzYsIDIxNTg0LCAxMDg4OSwgMTEwODAsIDE0MTExLCA0NDI5LCAyNTAxLCAzNTg4LCA2Njc2LgpgYGB7cn0KVihncmFwaCkkY29sb3I8LSJ5ZWxsb3ciClYoZ3JhcGgpJGNvbG9yW2RdPC0icmVkIgoKI3Rlc3RpbmcgZGlmZmVyZW50IGNvbG9ycwpwbG90KGdyYXBoLAogICAgIHZlcnRleC5jb2xvcj1WKGdyYXBoKSRjb2xvciwKICAgICB2ZXJ0ZXguc2l6ZT0gVihncmFwaCkkZGVncmVlKjAuMiwKICAgICBlZGdlLmFycm93LnNpemU9MC4wMSwKICAgICB2ZXJ0ZXgubGFiZWwuY2V4PTAuMDEsCiAgICAgbGF5b3V0PWxheW91dC5rYW1hZGEua2F3YWkpCmBgYApUaGUgZ3JhcGggZGVtb25zdHJhdGVzIDkwNCB2ZXJ0aWNlcy4gVGhlc2UgOTA0IHZlcnRpY2VzIGFyZSB0aGUgYm9vayBpZHMgdGhhdCBjb25uZWN0ZWQgdG8gdGhlIGJvb2sgd2hvc2UgaWQgPSAzMywgZGlyZWN0bHkgYW5kIGluZGlyZWN0bHkuIFNpemUgb2YgdGhlIHZlcnRpY2VzIHJlcHJlc2VudHMgdGhlIG51bWJlciBvZiB2ZXJ0aWNlcyB0aGF0IGNvbm5lY3RlZCB0byBhIHZlcnRpY2U7IHRoZSBiaWdnZXIgb2YgdGhlIHZlcnRpY2UsIHRoZSBtb3JlIHZlcnRpY2VzIGxpbmsgdG8gaXQuIFRoZSBkaXN0YW5jZSBiZXR3ZWVuIGVhY2ggdmVydGljZSByZXByZXNlbnRzIGhvdyBzdHJvbmcgdGhlIHZlcnRpY2VzIGNvbm5lY3QgdG8gZWFjaCBvdGhlcjsgdGhlIGxvbmdlciB0aGUgdGllcywgdGhlIHdlYWtlciB0aGUgcmVsYXRpb25zaGlwLiBUaGVyZWZvcmUsIHNvbWUgdmVydGljZXMgbG9vayBsaWtlIGNsdXN0ZXJzIGluIHRoZSBtaWRkbGUgd2l0aCBzaG9ydCBlZGdlcywgd2hpY2ggbWVhbnMgdGhlc2UgYm9va3MgaGF2ZSBzdHJvbmcgY29ubmVjdGlvbnMuIFNvbWUgdmVydGljZXMgYXJlIG5vZGVzIG9uIHRoZSBlZGdlcywgd2hpY2ggbWVhbnMgd2Vha2VyIGNvbm5lY3Rpb25zLgoKCgo2LiAJQ29tcHV0ZSB2YXJpb3VzIHN0YXRpc3RpY3MgYWJvdXQgdGhpcyBuZXR3b3JrIChpLmUuLCBzdWJjb21wb25lbnQpLCBpbmNsdWRpbmcgZGVncmVlIGRpc3RyaWJ1dGlvbiwgZGVuc2l0eSwgYW5kIGNlbnRyYWxpdHkgKGRlZ3JlZSBjZW50cmFsaXR5LCBjbG9zZW5lc3MgY2VudHJhbGl0eSBhbmQgYmV0d2VlbiBjZW50cmFsaXR5KSwgaHViL2F1dGhvcml0eSBzY29yZXMsIGV0Yy4gSW50ZXJwcmV0IHlvdXIgcmVzdWx0cy4KYGBge3J9CmRlZ19kaXN0PC0gZGVncmVlLmRpc3RyaWJ1dGlvbihncmFwaCxjdW11bGF0aXZlID0gVCwgbW9kZT0iYWxsIikKcGxvdCh4PTA6bWF4KGFsbF9kZWdyZWUpLCB5PTEtZGVnX2Rpc3QsIHBjaD0xOSwgY2V4PTEuMiwgY29sPSJvcmFuZ2UiLCB4bGFiPSJEZWdyZWUiLCB5bGFiPSJDdW11bGF0aXZlIEZyZXF1ZW5jeSIpCgoKZGRfYWxsPC1kZWdyZWVfZGlzdHJpYnV0aW9uKGdyYXBoLGN1bXVsYXRpdmU9VCkKcGxvdChkZF9hbGwsIHhsYWI9IkRlZ3JlZSIpCgpkZF9pbjwtZGVncmVlX2Rpc3RyaWJ1dGlvbihncmFwaCxjdW11bGF0aXZlPVQsbW9kZT0iaW4iKQpwbG90KGRkX2luLCB4bGFiPSJEZWdyZWUiKQoKZGRfb3V0PC1kZWdyZWVfZGlzdHJpYnV0aW9uKGdyYXBoLGN1bXVsYXRpdmU9VCxtb2RlPSJvdXQiKQpwbG90KGRkX291dCwgeGxhYj0iRGVncmVlIikKCmBgYApEZWdyZWUgbWVhbnMgdGhlIG51bWJlciBvZiB0aWVzLiAKCmBgYHtyfQojZGVuc2l0eQplZGdlX2RlbnNpdHkoZ3JhcGgsIGxvb3BzPUYpCgpgYGAKRGVuc2l0eSBpcyB0aGUgcHJvcG9ydGlvbiBvZiBwcmVzZW50IGVkZ2VzIGZyb20gYWxsIHBvc3NpYmxlIGVkZ2VzIGluIHRoZSBuZXR3b3JrLiBUaGUgZGVuc2l0eSBvZiBvdXIgZ3JhcGggaXMgNS4yNTAwMjllLTA1LCB3aGljaCBpcyBzbWFsbDsgdGhlcmVmb3JlLCB0aGUgbmV0d29ya2luZyBpcyBwcmV0dHkgZGVuc2UuIApgYGB7cn0KI2NlbnRyYWxpdHkKY2VudHJfZGVncmVlKGdyYXBoKQpgYGAKCkNlbnRyYWxpdHkgY2FsY3VsYXRlcyB0aGUgY2VudHJhbGl0eSBvZiBhbGwgdGhlIDkwNCBub2Rlcywgb3VyIHJlc3VsdHMgdmFyeSBmcm9tIDAgdG8gNTMsIGFuZCA1MyBpcyB0aGUgaGlnaGVzdCBjZW50cmFsaXR5LiAKCmBgYHtyfQpjbG9zZW5lc3MgPC0gY2xvc2VuZXNzKGdyYXBoLCBtb2RlPSdhbGwnLCB3ZWlnaHRzPU5BKQpgYGAKQ2xvc2VuZXNzIGNhbGN1bGF0ZXMgdGhlIGNlbnRyYWxpdHkgYmFzZWQgb24gZGlzdGFuY2UgdG8gb3RoZXIgbm9kZXMuIAoKYGBge3J9CmJldHdlZW5lc3MgPC0gYmV0d2Vlbm5lc3MoZ3JhcGgsIGRpcmVjdGVkPSdUJywgd2VpZ2h0cz1OQSkKYGBgCkJldHdlZW5uZXNzIChjZW50cmFsaXR5IGJhc2VkIG9uIGEgYnJva2VyIHBvc2l0aW9uIGNvbm5lY3Rpbmcgb3RoZXJzKQpgYGB7cn0KI2h1Yi9hdXRob3JpdHkgc2NvcmVzCiNodWIgY2VudHJhaWxpdHkgZWlnZW52ZWN0b3IKaHViX3Njb3JlMSA8LSBodWIuc2NvcmUoZ3JhcGgpJHZlY3RvcgoKI2F1dGhvcml0eSBjZW50cmFpbGl0eSBlaWdhbnZlY3RvcgphdXRob3JpdHlfc2NvcmUxIDwtIGF1dGhvcml0eS5zY29yZShncmFwaCkkdmVjdG9yCmBgYAo3LiAJQ3JlYXRlIGEgZ3JvdXAgb2YgdmFyaWFibGVzIGNvbnRhaW5pbmcgdGhlIGluZm9ybWF0aW9uIG9mIG5laWdoYm9ycyB0aGF0IOKAnHBvaW50IHRv4oCdIGZvY2FsIHByb2R1Y3RzLiBUaGUgdmFyaWFibGVzIGluY2x1ZGU6CmEuICAgICBOZWlnaGJvcnPigJkgbWVhbiByYXRpbmcgKG5naGJfbW5fcmF0aW5nKSwKYi4gICAgIE5laWdoYm9yc+KAmSBtZWFuIHNhbGVzcmFuayAobmdoYl9tbl9zYWxlc3JhbmspLApjLiAgICAgTmVpZ2hib3Jz4oCZIG1lYW4gbnVtYmVyIG9mIHJldmlld3MgKG5naGJfbW5fcmV2aWV3X2NudCksCk5vdGU6IHlvdSBtYXkgcmVjYWxsIHRoZSBmdW5jdGlvbnMgaW4g4oCcZHBseXLigJ0gc3VjaCBhcyBncm91cF9ieSwgaW5uZXJfam9pbiwgc3VtbWFyaXplLCBtZWFuLCBldGMuCmBgYHtyfQpyYXRpbmc8LWNvcHVyY2hhc2UgJT4lCiAgZ3JvdXBfYnkoVGFyZ2V0KSAlPiUKICBpbm5lcl9qb2luKHByb2R1Y3RzLCBieT1jKCdpZCc9J2lkJykpJT4lCiAgdHJhbnNtdXRlKG5naGJfbW5fcmF0aW5nPW1lYW4ocmF0aW5nKSkKCnJhbms8LWNvcHVyY2hhc2UgJT4lCiAgZ3JvdXBfYnkoVGFyZ2V0KSAlPiUKICBpbm5lcl9qb2luKHByb2R1Y3RzLGJ5PWMoJ2lkJz0naWQnKSklPiUKICB0cmFuc211dGUobmdoYl9tbl9zYWxlc3Jhbms9bWVhbihzYWxlc3JhbmspKQoKCnJldmlld3M8LWNvcHVyY2hhc2UgJT4lCiAgZ3JvdXBfYnkoVGFyZ2V0KSAlPiUKICBpbm5lcl9qb2luKHByb2R1Y3RzLGJ5PWMoJ2lkJz0naWQnKSklPiUKICB0cmFuc211dGUobmdoYl9tbl9yZXZpZXdfY250PW1lYW4ocmV2aWV3X2NudCkpCgpwcm9kdWN0cyRpZCA8LSBhcy52ZWN0b3IocHJvZHVjdHMkaWQpCnN1Yl9pZCA8LSBhc19pZHMoc3ViKQpwcm9kdWN0c19zdWIgPC0gcHJvZHVjdHNbcHJvZHVjdHMkaWQgJWluJSBzdWJfaWQsXQoKbWVhbiA8LSBjb3B1cmNoYXNlICU+JSAKICBncm91cF9ieShUYXJnZXQpICU+JSAKICBpbm5lcl9qb2luKHByb2R1Y3RzX3N1YiwgYnkgPSBjKCdpZCcgPSAnaWQnKSkgJT4lCiAgc3VtbWFyaXNlKG5naGJfbW5fcmF0aW5nPW1lYW4ocmF0aW5nKSwKICAgICAgICAgICAgbmdoYl9tbl9zYWxlc3Jhbms9bWVhbihzYWxlc3JhbmspLAogICAgICAgICAgICBuZ2hiX21uX3Jldmlld19jbnQ9bWVhbihyZXZpZXdfY250KSkKYGBgCjguIAlJbmNsdWRlIHRoZSB2YXJpYWJsZXMgKHRha2luZyBsb2dzIHdoZXJlIG5lY2Vzc2FyeSkgY3JlYXRlZCBpbiBQYXJ0cyAyLTYgYWJvdmUgaW50byB0aGUg4oCccHJvZHVjdHPigJ0gaW5mb3JtYXRpb24gYW5kIGZpdCBhIFBvaXNzb24gcmVncmVzc2lvbiB0byBwcmVkaWN0IHNhbGVzcmFuayBvZiBhbGwgdGhlIGJvb2tzIGluIHRoaXMgc3ViY29tcG9uZW50IHVzaW5nIHByb2R1Y3Rz4oCZIG93biBpbmZvcm1hdGlvbiBhbmQgdGhlaXIgbmVpZ2hib3LigJlzIGluZm9ybWF0aW9uLiBQcm92aWRlIGFuIGludGVycHJldGF0aW9uIG9mIHlvdXIgcmVzdWx0cy4KTm90ZTogTG93ZXIgc2FsZXNyYW5rIG1lYW5zIGhpZ2hlciBzYWxlcy4gRGF0YSBwb2ludHMgaW4gdGhlIG5ldHdvcmsgYXJlIHJlbGF0ZWQuIFRoZSBwZXJmb3JtYW5jZSBvZiBvbmUgbm9kZSBpcyBpbmZsdWVuY2VkIGJ5IHRoZSBwZXJmb3JtYW5jZSBvZiBpdHMgbmVpZ2hib3JzLiBBbHNvLCBpdOKAmXMgbm90IG5lY2Vzc2FyeSB0aGF0IGFsbCB2YXJpYWJsZXMgbWF0dGVyLgpgYGB7cn0KI2NvbnZlciB0byBkYXRhIGZyYW1lcwppbl9kZWdyZWUxIDwtIGFzLmRhdGEuZnJhbWUoaW5fZGVncmVlKQppbl9kZWdyZWUxIDwtIGNiaW5kKG5ld0NvbE5hbWUgPSByb3duYW1lcyhpbl9kZWdyZWUxKSwgaW5fZGVncmVlMSkKcm93bmFtZXMoaW5fZGVncmVlMSkgPC0gMTpucm93KGluX2RlZ3JlZTEpCmNvbG5hbWVzKGluX2RlZ3JlZTEpIDwtIGMoIk5vZGVzIiwgImluX2RlZ3JlZSIpCgpvdXRfZGVncmVlMSA8LSBhcy5kYXRhLmZyYW1lKG91dF9kZWdyZWUpCm91dF9kZWdyZWUxIDwtIGNiaW5kKG5ld0NvbE5hbWUgPSByb3duYW1lcyhvdXRfZGVncmVlMSksIG91dF9kZWdyZWUxKQpyb3duYW1lcyhvdXRfZGVncmVlMSkgPC0gMTpucm93KG91dF9kZWdyZWUxKQpjb2xuYW1lcyhvdXRfZGVncmVlMSkgPC0gYygiTm9kZXMiLCAib3V0X2RlZ3JlZSIpCgpjbG9zZW5lc3MxIDwtIGFzLmRhdGEuZnJhbWUoY2xvc2VuZXNzKQpjbG9zZW5lc3MxIDwtIGNiaW5kKG5ld0NvbE5hbWUgPSByb3duYW1lcyhjbG9zZW5lc3MxKSwgY2xvc2VuZXNzMSkKcm93bmFtZXMoY2xvc2VuZXNzMSkgPC0gMTpucm93KGNsb3NlbmVzczEpCmNvbG5hbWVzKGNsb3NlbmVzczEpIDwtIGMoIk5vZGVzIiwgImNsb3NlbmVzcyIpCgpiZXR3ZWVuZXNzMSA8LSBhcy5kYXRhLmZyYW1lKGJldHdlZW5lc3MpCmJldHdlZW5lc3MxIDwtIGNiaW5kKG5ld0NvbE5hbWUgPSByb3duYW1lcyhiZXR3ZWVuZXNzMSksIGJldHdlZW5lc3MxKQpyb3duYW1lcyhiZXR3ZWVuZXNzMSkgPC0gMTpucm93KGJldHdlZW5lc3MxKQpjb2xuYW1lcyhiZXR3ZWVuZXNzMSkgPC0gYygiTm9kZXMiLCAiYmV0d2VlbmVzcyIpCgpodWJfc2NvcmUyIDwtIGFzLmRhdGEuZnJhbWUoaHViX3Njb3JlMSkKaHViX3Njb3JlMiA8LSBjYmluZChuZXdDb2xOYW1lID0gcm93bmFtZXMoaHViX3Njb3JlMiksIGh1Yl9zY29yZTIpCnJvd25hbWVzKGh1Yl9zY29yZTIpIDwtIDE6bnJvdyhodWJfc2NvcmUyKQpjb2xuYW1lcyhodWJfc2NvcmUyKSA8LSBjKCJOb2RlcyIsICJodWJfc2NvcmUiKQoKYXV0aG9yaXR5X3Njb3JlMiA8LSBhcy5kYXRhLmZyYW1lKGF1dGhvcml0eV9zY29yZTEpCmF1dGhvcml0eV9zY29yZTIgPC0gY2JpbmQobmV3Q29sTmFtZSA9IHJvd25hbWVzKGF1dGhvcml0eV9zY29yZTIpLCBhdXRob3JpdHlfc2NvcmUyKQpyb3duYW1lcyhhdXRob3JpdHlfc2NvcmUyKSA8LSAxOm5yb3coYXV0aG9yaXR5X3Njb3JlMikKY29sbmFtZXMoYXV0aG9yaXR5X3Njb3JlMikgPC0gYygiTm9kZXMiLCAiYXV0aG9yaXR5X3Njb3JlIikKCnBvaXNzb25fZGF0YSA8LSBzcWxkZigiU0VMRUNUIGh1Yl9zY29yZTIuTm9kZXMsIGh1Yl9zY29yZSwgYmV0d2VlbmVzcywgYXV0aG9yaXR5X3Njb3JlLCBjbG9zZW5lc3MsIGluX2RlZ3JlZSwgb3V0X2RlZ3JlZSwgbmdoYl9tbl9yYXRpbmcsIG5naGJfbW5fc2FsZXNyYW5rLCBuZ2hiX21uX3Jldmlld19jbnQsIHByb2R1Y3RzLmlkLCBwcm9kdWN0cy5yZXZpZXdfY250LCBwcm9kdWN0cy5yYXRpbmcsIHByb2R1Y3RzLnNhbGVzcmFuawogICAgICAgICAgICAgICAgICAgICAgRlJPTSBodWJfc2NvcmUyLCBiZXR3ZWVuZXNzMSwgYXV0aG9yaXR5X3Njb3JlMiwgY2xvc2VuZXNzMSwgaW5fZGVncmVlMSwgICAgICAgICAgICBvdXRfZGVncmVlMSwgbWVhbiwgcHJvZHVjdHMKICAgICAgICAgICAgICAgICAgICAgIFdIRVJFIGh1Yl9zY29yZTIuTm9kZXMgPSBiZXR3ZWVuZXNzMS5Ob2RlcyAKICAgICAgICAgICAgICAgICAgICAgIGFuZCBodWJfc2NvcmUyLk5vZGVzID0gYXV0aG9yaXR5X3Njb3JlMi5Ob2RlcwogICAgICAgICAgICAgICAgICAgICAgYW5kIGh1Yl9zY29yZTIuTm9kZXMgPSBjbG9zZW5lc3MxLk5vZGVzCiAgICAgICAgICAgICAgICAgICAgICBhbmQgaHViX3Njb3JlMi5Ob2RlcyA9IGluX2RlZ3JlZTEuTm9kZXMKICAgICAgICAgICAgICAgICAgICAgIGFuZCBodWJfc2NvcmUyLk5vZGVzID0gb3V0X2RlZ3JlZTEuTm9kZXMKICAgICAgICAgICAgICAgICAgICAgIGFuZCBodWJfc2NvcmUyLk5vZGVzID0gbWVhbi5UYXJnZXQKICAgICAgICAgICAgICAgICAgICAgIGFuZCBodWJfc2NvcmUyLk5vZGVzID0gcHJvZHVjdHMuaWQiKQoKI3J1biBwb2lzc29uIHJlZ3Jlc3Npb24Kc3VtbWFyeShzYWxlc3JhdGluZ19wcmVkaWN0aW9uPC0gZ2xtKHNhbGVzcmFuayB+IHJldmlld19jbnQgKyByYXRpbmcgKyBodWJfc2NvcmUgKyBiZXR3ZWVuZXNzICsgCmF1dGhvcml0eV9zY29yZSArIGNsb3NlbmVzcyArIGluX2RlZ3JlZSArIG91dF9kZWdyZWUgKyBuZ2hiX21uX3JhdGluZysgbmdoYl9tbl9zYWxlc3JhbmsgKyBuZ2hiX21uX3Jldmlld19jbnQsIGZhbWlseT0icG9pc3NvbiIsIGRhdGE9cG9pc3Nvbl9kYXRhKSkKCgpgYGAKIAoKCgoKCgoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLiAKClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4KCg==