Description

In this assignment, you will be performing an analysis of a social network of bottle nose dolphins. The nodes in the network each represent a member of a bottle nose dolphin community living off Doubtful Sounds in New Zealand. An edge exists between two nodes if there is a frequent association between the dolphins represented by those nodes. The observations were gathered between 1994 and 2001.

Load Packages

Begin by loading the igraph, dplyr, and RColorBrewer packages.

rr require(igraph) require(dplyr) require(RColorBrewer)

Load Contents

The file nodes.txt contains the names of the dolphins, as well as a numerical code that has been assigned to each dolphin. The file edges.txt contains a list of edges.

Run the code below to read in and prepare the data for our analysis.

Perform the following steps in the cell below:

  1. Use the graph_from_data_frame() function to create an undirected graph from the edges.
  2. For the sake of reproducability, set the seed to 1 using set.seed().
  3. Plot the graph without vertex labels. Select an appropriate vertex size for your graph.

rr g <- graph_from_data_frame(edges,directed=FALSE) set.seed(1) plot(g, vertex.size = 4, vertex.label = NA)

Calculate Centrality Measures

Perform the following steps in the cell below:

  1. Calculate the degree centrality of the nodes in the graph. Store the results.
  2. Calculate the betweenness centrality of the nodes in the graph. Store the results.
  3. Calculate the closeness centrality of the nodes in the graph. Store the results.
  4. Create a data frame called nodes with five columns: Node (the number assigned to the dolphin), Name (the name of the dolphin), dCent (degree centrality), bCent (betweenness centrality), and cCent (closeness centrality).
  5. Print a summary of this data frame.

rr dC <- degree(g) bC <- betweenness(g) cC <- closeness(g) centDF <- data.frame(Node = names(dC), dCent = dC, bCent = bC, cCent = cC, stringsAsFactors = FALSE) nodes <- left_join(nodes, centDF, by=‘Node’) summary(nodes)

     Node               Name               dCent            bCent             cCent         
 Length:62          Length:62          Min.   : 1.000   Min.   :  0.000   Min.   :0.002924  
 Class :character   Class :character   1st Qu.: 3.000   1st Qu.:  5.641   1st Qu.:0.004288  
 Mode  :character   Mode  :character   Median : 5.000   Median : 39.583   Median :0.005181  
                                       Mean   : 5.129   Mean   : 71.887   Mean   :0.005037  
                                       3rd Qu.: 7.000   3rd Qu.:102.638   3rd Qu.:0.005556  
                                       Max.   :12.000   Max.   :454.274   Max.   :0.006849  

Print the contents of nodes in descending order of degree centrality.

rr arrange(nodes, desc(dCent))

Print the contents of nodes in descending order of betweenness centrality.

rr arrange(nodes, desc(bCent))

Print the contents of nodes in descending order of closeness centrality.

rr arrange(nodes, desc(cCent))

List any names of any dolphins that appear in the top 10 for all three centrality measures.

SN4, Kringel, and Beescratch.

Visualizing Centrality

In the cell below, complete the following steps: 1. Set the seed equal to 1. 2. Create a cut of the vector dC. Set the cuts to roughly correspond to the quartiles of the degree centrality (refer to the summary above). Set labels = FALSE. 3. Create a RColorBrewer palette with 4 colors. 4. Plot the graph with the size and color of the vertices each determined by degree centrality. Use the cut and palette you defined to set the color. Then set the size to be equal to 2 + the value of the cut. Do not display the labels.

In the cell below, complete the following steps: 1. Set the seed equal to 1. 2. Create a cut of the vector bC. Use the following cut levels: -1, 25, 75, 150, 450, and 500. Set labels = FALSE. 3. Create a RColorBrewer palette with 5 colors. 4. Plot the graph with the size and color of the vertices each determined by betweenness centrality. Use the cut and palette you defined to set the color. Then set the size to be equal to 2 + the value of the cut. Do not display the labels.

Community Detection

In the cell below, complete the following steps:

  1. Set the seed equal to 1.
  2. Use cluster_edge_betweenness() to detect communities within the graph.
  3. Plot the graph, displaying the communities that have been detected. Do not display the vertex labels.

rr set.seed(1) ceb <- cluster_edge_betweenness(g) plot(ceb, g, vertex.label = NA, vertex.size = 4)

In the cell below, complete the following steps:

  1. Create a data frame called commDF with two columns: Node and Comm. The Comm column should indicate the community to each each dolphin has been assigned.
  2. Add the community information to the nodes data frame.
  3. Print a table with two columns: Comm and n. The Comm column should list the labels for the communities that have been detected. The n column should list the number of dolphins that have been assigned to each community. The table should be sorted in descending order by n.

rr mem <- membership(ceb) commDF <- data.frame(Node = names(mem), Comm = as.vector(unname(mem)), stringsAsFactors = FALSE) nodes <- left_join(nodes, commDF, by=‘Node’) nodes %>% group_by(Comm) %>% count() %>% arrange(desc(n))

Use induced.subgraph() to create a subgraph consisting of nodes associated with dolphins that have been assigned to the largest of the detected communities. Name the graph g2.

rr comm2 <- filter(nodes, Comm == 2) g2 <- induced.subgraph(g, vids = comm2$Node)

Run the cell below to plot the graph for the largest community with each node labeled by the name of the associated dolphin.

rr sel<- V(g2)\(name selDF <- data.frame(Node = sel, stringsAsFactors = FALSE) selDF <- left_join(selDF, nodes, by='Node') set.seed(1) plot(g2, vertex.label = selDF\)Name, vertex.label.cex = 1.5)

Clique Detection

Find the largest cliques in the network. Print a list of nodes contained in each clique.

rr lc <- largest_cliques(g) lc

[[1]]
+ 5/62 vertices, named, from d6c212d:
[1] 57 13 9  6  17

[[2]]
+ 5/62 vertices, named, from d6c212d:
[1] 51 45 18 29 24

[[3]]
+ 5/62 vertices, named, from d6c212d:
[1] 51 45 18 29 21

Print the names of the dolphins contained in each of the largest cliques. You will need a separate code chunk for each clique.

rr c1 <- lc[[1]]$name filter(nodes, Node %in% c1)

rr c2 <- lc[[2]]$name filter(nodes, Node %in% c2)

rr c3 <- lc[[3]]$name filter(nodes, Node %in% c3)

A larger clique could be created by adding a single edge between two dolphins. Which two dolphins are they?

MN83 and MN105.

LS0tDQp0aXRsZTogIkhXIDA3OiBEb2xwaGluIFNvY2lhbCBOZXR3b3JrIEFuYWx5c2lzIg0Kb3V0cHV0OiANCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICB0aGVtZTogZmxhdGx5DQogICAgICAgIHRvYzogdHJ1ZQ0KICAgICAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KDQojIyMgRGVzY3JpcHRpb24NCg0KSW4gdGhpcyBhc3NpZ25tZW50LCB5b3Ugd2lsbCBiZSBwZXJmb3JtaW5nIGFuIGFuYWx5c2lzIG9mIGEgc29jaWFsIG5ldHdvcmsgb2YgYm90dGxlIG5vc2UgZG9scGhpbnMuIFRoZSBub2RlcyBpbiB0aGUgbmV0d29yayBlYWNoIHJlcHJlc2VudCBhIG1lbWJlciBvZiBhIGJvdHRsZSBub3NlIGRvbHBoaW4gY29tbXVuaXR5IGxpdmluZyBvZmYgRG91YnRmdWwgU291bmRzIGluIE5ldyBaZWFsYW5kLiBBbiBlZGdlIGV4aXN0cyBiZXR3ZWVuIHR3byBub2RlcyBpZiB0aGVyZSBpcyBhIGZyZXF1ZW50IGFzc29jaWF0aW9uIGJldHdlZW4gdGhlIGRvbHBoaW5zIHJlcHJlc2VudGVkIGJ5IHRob3NlIG5vZGVzLiBUaGUgb2JzZXJ2YXRpb25zIHdlcmUgZ2F0aGVyZWQgYmV0d2VlbiAxOTk0IGFuZCAyMDAxLiANCg0KIyMjIExvYWQgUGFja2FnZXMNCg0KQmVnaW4gYnkgbG9hZGluZyB0aGUgaWdyYXBoLCBkcGx5ciwgYW5kIFJDb2xvckJyZXdlciBwYWNrYWdlcy4gDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KcmVxdWlyZShpZ3JhcGgpDQpyZXF1aXJlKGRwbHlyKQ0KcmVxdWlyZShSQ29sb3JCcmV3ZXIpDQpgYGANCg0KIyMjIExvYWQgQ29udGVudHMNCg0KVGhlIGZpbGUgYG5vZGVzLnR4dGAgY29udGFpbnMgdGhlIG5hbWVzIG9mIHRoZSBkb2xwaGlucywgYXMgd2VsbCBhcyBhIG51bWVyaWNhbCBjb2RlIHRoYXQgaGFzIGJlZW4gYXNzaWduZWQgdG8gZWFjaCBkb2xwaGluLiBUaGUgZmlsZSBgZWRnZXMudHh0YCBjb250YWlucyBhIGxpc3Qgb2YgZWRnZXMuIA0KDQpSdW4gdGhlIGNvZGUgYmVsb3cgdG8gcmVhZCBpbiBhbmQgcHJlcGFyZSB0aGUgZGF0YSBmb3Igb3VyIGFuYWx5c2lzLg0KDQpgYGB7cn0NCm5vZGVzIDwtIHJlYWQudGFibGUoIm5vZGVzLnR4dCIsIHNlcD0iXHQiLCBoZWFkZXIgPSBUUlVFLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQplZGdlcyA8LSByZWFkLnRhYmxlKCJlZGdlcy50eHQiLCBzZXA9Ilx0IiwgaGVhZGVyID0gVFJVRSkNCm5vZGVzJE5vZGUgPC0gYXMuY2hhcmFjdGVyKG5vZGVzJE5vZGUpDQpgYGANCg0KUGVyZm9ybSB0aGUgZm9sbG93aW5nIHN0ZXBzIGluIHRoZSBjZWxsIGJlbG93Og0KDQoxLiBVc2UgdGhlIGBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGFuIHVuZGlyZWN0ZWQgZ3JhcGggZnJvbSB0aGUgZWRnZXMuIA0KMi4gRm9yIHRoZSBzYWtlIG9mIHJlcHJvZHVjYWJpbGl0eSwgc2V0IHRoZSBzZWVkIHRvIDEgdXNpbmcgYHNldC5zZWVkKClgLiANCjMuIFBsb3QgdGhlIGdyYXBoIHdpdGhvdXQgdmVydGV4IGxhYmVscy4gU2VsZWN0IGFuIGFwcHJvcHJpYXRlIHZlcnRleCBzaXplIGZvciB5b3VyIGdyYXBoLiANCg0KYGBge3IsIGZpZy53aWR0aCA9IDIwfQ0KDQpnIDwtIGdyYXBoX2Zyb21fZGF0YV9mcmFtZShlZGdlcyxkaXJlY3RlZD1GQUxTRSkNCnNldC5zZWVkKDEpDQpwbG90KGcsIHZlcnRleC5zaXplID0gNCwgdmVydGV4LmxhYmVsID0gTkEpDQpgYGANCg0KIyMjIENhbGN1bGF0ZSBDZW50cmFsaXR5IE1lYXN1cmVzDQoNClBlcmZvcm0gdGhlIGZvbGxvd2luZyBzdGVwcyBpbiB0aGUgY2VsbCBiZWxvdzoNCg0KMS4gQ2FsY3VsYXRlIHRoZSBkZWdyZWUgY2VudHJhbGl0eSBvZiB0aGUgbm9kZXMgaW4gdGhlIGdyYXBoLiBTdG9yZSB0aGUgcmVzdWx0cy4gDQoyLiBDYWxjdWxhdGUgdGhlIGJldHdlZW5uZXNzIGNlbnRyYWxpdHkgb2YgdGhlIG5vZGVzIGluIHRoZSBncmFwaC4gU3RvcmUgdGhlIHJlc3VsdHMuIA0KMy4gQ2FsY3VsYXRlIHRoZSBjbG9zZW5lc3MgY2VudHJhbGl0eSBvZiB0aGUgbm9kZXMgaW4gdGhlIGdyYXBoLiBTdG9yZSB0aGUgcmVzdWx0cy4gDQo0LiBDcmVhdGUgYSBkYXRhIGZyYW1lIGNhbGxlZCBgbm9kZXNgIHdpdGggZml2ZSBjb2x1bW5zOiBOb2RlICh0aGUgbnVtYmVyIGFzc2lnbmVkIHRvIHRoZSBkb2xwaGluKSwgTmFtZSAodGhlIG5hbWUgb2YgdGhlIGRvbHBoaW4pLCBkQ2VudCAoZGVncmVlIGNlbnRyYWxpdHkpLCBiQ2VudCAoYmV0d2Vlbm5lc3MgY2VudHJhbGl0eSksIGFuZCBjQ2VudCAoY2xvc2VuZXNzIGNlbnRyYWxpdHkpLg0KNS4gUHJpbnQgYSBzdW1tYXJ5IG9mIHRoaXMgZGF0YSBmcmFtZS4gDQoNCmBgYHtyfQ0KZEMgPC0gZGVncmVlKGcpDQpiQyA8LSBiZXR3ZWVubmVzcyhnKQ0KY0MgPC0gY2xvc2VuZXNzKGcpDQoNCmNlbnRERiA8LSBkYXRhLmZyYW1lKE5vZGUgPSBuYW1lcyhkQyksIGRDZW50ID0gZEMsIGJDZW50ID0gYkMsIGNDZW50ID0gY0MsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCg0Kbm9kZXMgPC0gbGVmdF9qb2luKG5vZGVzLCBjZW50REYsIGJ5PSdOb2RlJykNCnN1bW1hcnkobm9kZXMpDQpgYGANCg0KUHJpbnQgdGhlIGNvbnRlbnRzIG9mIGBub2Rlc2AgaW4gZGVzY2VuZGluZyBvcmRlciBvZiBkZWdyZWUgY2VudHJhbGl0eS4gDQoNCmBgYHtyfQ0KYXJyYW5nZShub2RlcywgZGVzYyhkQ2VudCkpDQpgYGANCg0KUHJpbnQgdGhlIGNvbnRlbnRzIG9mIGBub2Rlc2AgaW4gZGVzY2VuZGluZyBvcmRlciBvZiBiZXR3ZWVubmVzcyBjZW50cmFsaXR5LiANCg0KYGBge3J9DQphcnJhbmdlKG5vZGVzLCBkZXNjKGJDZW50KSkNCmBgYA0KDQpQcmludCB0aGUgY29udGVudHMgb2YgYG5vZGVzYCBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIGNsb3NlbmVzcyBjZW50cmFsaXR5LiANCg0KYGBge3J9DQphcnJhbmdlKG5vZGVzLCBkZXNjKGNDZW50KSkNCmBgYA0KDQpMaXN0IGFueSBuYW1lcyBvZiBhbnkgZG9scGhpbnMgdGhhdCBhcHBlYXIgaW4gdGhlIHRvcCAxMCBmb3IgYWxsIHRocmVlIGNlbnRyYWxpdHkgbWVhc3VyZXMuIA0KDQoqKlNONCwgS3JpbmdlbCwgYW5kIEJlZXNjcmF0Y2guKioNCg0KDQojIyMgVmlzdWFsaXppbmcgQ2VudHJhbGl0eQ0KDQpJbiB0aGUgY2VsbCBiZWxvdywgY29tcGxldGUgdGhlIGZvbGxvd2luZyBzdGVwczoNCjEuIFNldCB0aGUgc2VlZCBlcXVhbCB0byAxLiANCjIuIENyZWF0ZSBhIGN1dCBvZiB0aGUgdmVjdG9yIGBkQ2AuIFNldCB0aGUgY3V0cyB0byByb3VnaGx5IGNvcnJlc3BvbmQgdG8gdGhlIHF1YXJ0aWxlcyBvZiB0aGUgZGVncmVlIGNlbnRyYWxpdHkgKHJlZmVyIHRvIHRoZSBzdW1tYXJ5IGFib3ZlKS4gU2V0IGBsYWJlbHMgPSBGQUxTRWAuIA0KMy4gQ3JlYXRlIGEgYFJDb2xvckJyZXdlcmAgcGFsZXR0ZSB3aXRoIDQgY29sb3JzLiANCjQuIFBsb3QgdGhlIGdyYXBoIHdpdGggdGhlIHNpemUgYW5kIGNvbG9yIG9mIHRoZSB2ZXJ0aWNlcyBlYWNoIGRldGVybWluZWQgYnkgZGVncmVlIGNlbnRyYWxpdHkuIFVzZSB0aGUgY3V0IGFuZCBwYWxldHRlIHlvdSBkZWZpbmVkIHRvIHNldCB0aGUgY29sb3IuIFRoZW4gc2V0IHRoZSBzaXplIHRvIGJlIGVxdWFsIHRvIDIgKyB0aGUgdmFsdWUgb2YgdGhlIGN1dC4gRG8gbm90IGRpc3BsYXkgdGhlIGxhYmVscy4gDQoNCg0KYGBge3IsIGZpZy53aWR0aCA9IDIwfQ0Kc2V0LnNlZWQoMSkNCmN0IDwtIGN1dChkQywgYygtMSwgMywgNSwgNywgMTMpLCBsYWJlbHM9RkFMU0UpDQpteVBhbCA8LSBicmV3ZXIucGFsKDQsICJSZFB1IikNCnBsb3QoZywgdmVydGV4LmxhYmVsID0gTkEsIHZlcnRleC5zaXplID0gMiArIGN0LCB2ZXJ0ZXguY29sb3IgPSBteVBhbFtjdF0pDQpgYGANCg0KSW4gdGhlIGNlbGwgYmVsb3csIGNvbXBsZXRlIHRoZSBmb2xsb3dpbmcgc3RlcHM6DQoxLiBTZXQgdGhlIHNlZWQgZXF1YWwgdG8gMS4gDQoyLiBDcmVhdGUgYSBjdXQgb2YgdGhlIHZlY3RvciBgYkNgLiBVc2UgdGhlIGZvbGxvd2luZyBjdXQgbGV2ZWxzOiAtMSwgMjUsIDc1LCAxNTAsIDQ1MCwgYW5kIDUwMC4gU2V0IGBsYWJlbHMgPSBGQUxTRWAuIA0KMy4gQ3JlYXRlIGEgYFJDb2xvckJyZXdlcmAgcGFsZXR0ZSB3aXRoIDUgY29sb3JzLiANCjQuIFBsb3QgdGhlIGdyYXBoIHdpdGggdGhlIHNpemUgYW5kIGNvbG9yIG9mIHRoZSB2ZXJ0aWNlcyBlYWNoIGRldGVybWluZWQgYnkgYmV0d2Vlbm5lc3MgY2VudHJhbGl0eS4gVXNlIHRoZSBjdXQgYW5kIHBhbGV0dGUgeW91IGRlZmluZWQgdG8gc2V0IHRoZSBjb2xvci4gVGhlbiBzZXQgdGhlIHNpemUgdG8gYmUgZXF1YWwgdG8gMiArIHRoZSB2YWx1ZSBvZiB0aGUgY3V0LiBEbyBub3QgZGlzcGxheSB0aGUgbGFiZWxzLiANCg0KYGBge3IsIGZpZy53aWR0aCA9IDIwfQ0Kc2V0LnNlZWQoMSkNCmN0IDwtIGN1dChiQywgYygtMSwgMjUsIDc1LCAxNTAsIDQ1MCwgNTAwKSwgbGFiZWxzPUZBTFNFKQ0KbXlQYWwgPC0gYnJld2VyLnBhbCg1LCAiUmRQdSIpDQpwbG90KGcsIHZlcnRleC5sYWJlbCA9IE5BLCB2ZXJ0ZXguc2l6ZSA9IDIgKyBjdCwgdmVydGV4LmNvbG9yID0gbXlQYWxbY3RdKQ0KYGBgDQoNCiMjIyBDb21tdW5pdHkgRGV0ZWN0aW9uDQoNCkluIHRoZSBjZWxsIGJlbG93LCBjb21wbGV0ZSB0aGUgZm9sbG93aW5nIHN0ZXBzOg0KDQoxLiBTZXQgdGhlIHNlZWQgZXF1YWwgdG8gMS4NCjIuIFVzZSBgY2x1c3Rlcl9lZGdlX2JldHdlZW5uZXNzKClgIHRvIGRldGVjdCBjb21tdW5pdGllcyB3aXRoaW4gdGhlIGdyYXBoLiANCjMuIFBsb3QgdGhlIGdyYXBoLCBkaXNwbGF5aW5nIHRoZSBjb21tdW5pdGllcyB0aGF0IGhhdmUgYmVlbiBkZXRlY3RlZC4gRG8gbm90IGRpc3BsYXkgdGhlIHZlcnRleCBsYWJlbHMuIA0KDQoNCg0KYGBge3IsIGZpZy53aWR0aCA9IDIwfQ0Kc2V0LnNlZWQoMSkNCmNlYiA8LSBjbHVzdGVyX2VkZ2VfYmV0d2Vlbm5lc3MoZykNCnBsb3QoY2ViLCBnLCB2ZXJ0ZXgubGFiZWwgPSBOQSwgdmVydGV4LnNpemUgPSA0KQ0KYGBgDQoNCkluIHRoZSBjZWxsIGJlbG93LCBjb21wbGV0ZSB0aGUgZm9sbG93aW5nIHN0ZXBzOg0KDQoxLiBDcmVhdGUgYSBkYXRhIGZyYW1lIGNhbGxlZCBgY29tbURGYCB3aXRoIHR3byBjb2x1bW5zOiBOb2RlIGFuZCBDb21tLiBUaGUgQ29tbSBjb2x1bW4gc2hvdWxkIGluZGljYXRlIHRoZSBjb21tdW5pdHkgdG8gZWFjaCBlYWNoIGRvbHBoaW4gaGFzIGJlZW4gYXNzaWduZWQuIA0KMi4gQWRkIHRoZSBjb21tdW5pdHkgaW5mb3JtYXRpb24gdG8gdGhlIGBub2Rlc2AgZGF0YSBmcmFtZS4gDQozLiBQcmludCBhIHRhYmxlIHdpdGggdHdvIGNvbHVtbnM6IENvbW0gYW5kIG4uIFRoZSBDb21tIGNvbHVtbiBzaG91bGQgbGlzdCB0aGUgbGFiZWxzIGZvciB0aGUgY29tbXVuaXRpZXMgdGhhdCBoYXZlIGJlZW4gZGV0ZWN0ZWQuIFRoZSBuIGNvbHVtbiBzaG91bGQgbGlzdCB0aGUgbnVtYmVyIG9mIGRvbHBoaW5zIHRoYXQgaGF2ZSBiZWVuIGFzc2lnbmVkIHRvIGVhY2ggY29tbXVuaXR5LiBUaGUgdGFibGUgc2hvdWxkIGJlIHNvcnRlZCBpbiBkZXNjZW5kaW5nIG9yZGVyIGJ5IG4uIA0KDQpgYGB7cn0NCm1lbSA8LSBtZW1iZXJzaGlwKGNlYikNCmNvbW1ERiA8LSBkYXRhLmZyYW1lKE5vZGUgPSBuYW1lcyhtZW0pLCBDb21tID0gYXMudmVjdG9yKHVubmFtZShtZW0pKSwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQpub2RlcyA8LSBsZWZ0X2pvaW4obm9kZXMsIGNvbW1ERiwgYnk9J05vZGUnKQ0KDQpub2RlcyAlPiUgZ3JvdXBfYnkoQ29tbSkgJT4lIGNvdW50KCkgJT4lIGFycmFuZ2UoZGVzYyhuKSkNCg0KYGBgDQoNClVzZSBgaW5kdWNlZC5zdWJncmFwaCgpYCB0byBjcmVhdGUgYSBzdWJncmFwaCBjb25zaXN0aW5nIG9mIG5vZGVzIGFzc29jaWF0ZWQgd2l0aCBkb2xwaGlucyB0aGF0IGhhdmUgYmVlbiBhc3NpZ25lZCB0byB0aGUgbGFyZ2VzdCBvZiB0aGUgZGV0ZWN0ZWQgY29tbXVuaXRpZXMuIE5hbWUgdGhlIGdyYXBoIGBnMmAuIA0KDQpgYGB7cn0NCmNvbW0yIDwtIGZpbHRlcihub2RlcywgQ29tbSA9PSAyKQ0KZzIgPC0gaW5kdWNlZC5zdWJncmFwaChnLCB2aWRzID0gY29tbTIkTm9kZSkgDQpgYGANCg0KUnVuIHRoZSBjZWxsIGJlbG93IHRvIHBsb3QgdGhlIGdyYXBoIGZvciB0aGUgbGFyZ2VzdCBjb21tdW5pdHkgd2l0aCBlYWNoIG5vZGUgbGFiZWxlZCBieSB0aGUgbmFtZSBvZiB0aGUgYXNzb2NpYXRlZCBkb2xwaGluLiANCg0KDQpgYGB7ciwgZmlnLndpZHRoID0gMjB9DQpzZWw8LSBWKGcyKSRuYW1lDQoNCnNlbERGIDwtIGRhdGEuZnJhbWUoTm9kZSA9IHNlbCwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0Kc2VsREYgPC0gbGVmdF9qb2luKHNlbERGLCBub2RlcywgYnk9J05vZGUnKQ0KDQpzZXQuc2VlZCgxKQ0KcGxvdChnMiwgdmVydGV4LmxhYmVsID0gc2VsREYkTmFtZSwgdmVydGV4LmxhYmVsLmNleCA9IDEuNSkNCg0KYGBgDQoNCiMjIyBDbGlxdWUgRGV0ZWN0aW9uDQoNCkZpbmQgdGhlIGxhcmdlc3QgY2xpcXVlcyBpbiB0aGUgbmV0d29yay4gUHJpbnQgYSBsaXN0IG9mIG5vZGVzIGNvbnRhaW5lZCBpbiBlYWNoIGNsaXF1ZS4gDQoNCmBgYHtyfQ0KbGMgPC0gbGFyZ2VzdF9jbGlxdWVzKGcpDQpsYw0KYGBgDQoNClByaW50IHRoZSBuYW1lcyBvZiB0aGUgZG9scGhpbnMgY29udGFpbmVkIGluIGVhY2ggb2YgdGhlIGxhcmdlc3QgY2xpcXVlcy4gWW91IHdpbGwgbmVlZCBhIHNlcGFyYXRlIGNvZGUgY2h1bmsgZm9yIGVhY2ggY2xpcXVlLiANCg0KYGBge3J9DQpjMSA8LSBsY1tbMV1dJG5hbWUNCmZpbHRlcihub2RlcywgTm9kZSAlaW4lIGMxKQ0KYGBgDQoNCmBgYHtyfQ0KYzIgPC0gbGNbWzJdXSRuYW1lDQpmaWx0ZXIobm9kZXMsIE5vZGUgJWluJSBjMikNCmBgYA0KDQpgYGB7cn0NCmMzIDwtIGxjW1szXV0kbmFtZQ0KZmlsdGVyKG5vZGVzLCBOb2RlICVpbiUgYzMpDQpgYGANCg0KQSBsYXJnZXIgY2xpcXVlIGNvdWxkIGJlIGNyZWF0ZWQgYnkgYWRkaW5nIGEgc2luZ2xlIGVkZ2UgYmV0d2VlbiB0d28gZG9scGhpbnMuIFdoaWNoIHR3byBkb2xwaGlucyBhcmUgdGhleT8NCg0KKipNTjgzIGFuZCBNTjEwNSoqLiANCg0KDQoNCg==