Setup

To run a “chunk” - the code between the back ticks - click on the green arrow to the right. For more options see Run at the top of the source editor window (this window).

In this tutorial we are going to work with the igraph package. Run this command:

If and only if you get an error saying that the package is unkown run the chunk above called Package_Installation. Then, or otherwise, continue with the next line.

The best source of information on igraph is the online documentation.

Prelude: Minimal R

R is not a command language - e.g., just a bunch of commands for statistics operations - but a full programming language. This provides great flexilibity, but also means that one has to understand a little bit about programming. Really, just a little bit. Therefore, Occasionally, we need to learn - or remind ourselves of - something about R. It’ll always be short and to the point. Two elementary things today: assignments and the list constructor c().

Assignment

You can assign a value to an object using assign(), “<-”, or “=”:

x <- 3         # Assignment
x              # Evaluate the expression and print result
[1] 3

Now you: Assign y to 4 and evaluate.

y = 4
y
[1] 4

Next, what do you expect as result when you run this chunk:

y + 5
[1] 9
y
[1] 4

Why did the value of y not change?

Because is was not assigned to a new value; it was only used in evaluations.

We can chain objects together, like in algebra:

z =  x + 5*y    # Assignment
z             # Evaluation
[1] 23

Not only can you create objects, you can also destroy them:

rm(z)          # Remove z: deletes the object.
z              # Error!
Error: object 'z' not found

Lists and vectors.

Lists are basic to R: this is a list: (apple, pear, banana, cherry).These kind of simple list–all elements have the same type (characters, numbers), not embedding of lists in lists–are called vectors in R. The vector, not and individual value (atom), is the basic data type in R. One way to construct vectors is with c().

fruit
[1] "apple"  "pear"   "banana" "cherry"

Now you: Make a vector - a simple list - of numbers 1-4. Assign it to numVec

numVec <- c(1, 2, 3, 4)
numVec
[1] 1 2 3 4

R is all about vectors, so math is done on vectors if they contain numbers:

numVec + 1
[1] 2 3 4 5
numVec * numVec
[1]  1  4  9 16

(Those of you who have done a bit of coding will see immediately what this means: Much less need for looping!)

If you want to pick an element, or a set of elements, you can use the index:

numVec[2]
[1] 2
c("Eins", "zwei", "drei")[1]
[1] "Eins"

When we assign different kinds of atoms to a vector, they will be transformed automatically to be of one type - a process called coercion. Like so:

c(1, 2, 3, "four")
[1] "1"    "2"    "3"    "four"

Better not to try arithmetic on this vector.

Now the difference to a list can be demonstrated, using the list() operator to create, you guessed it, a list.

list(1, "apple", 5, "pear")
[[1]]
[1] 1

[[2]]
[1] "apple"

[[3]]
[1] 5

[[4]]
[1] "pear"

You see, because vectors are R’s ‘primitive’ data structure, a list is a list of vectors, even when these vector have length 1.

MixedBag <- list(fruit, numVec)
MixedBag
[[1]]
[1] "apple"  "pear"   "banana" "cherry"

[[2]]
[1] 1 2 3 4

As you see, lists can contain multiple vectors - and, indeed, multiple lists - and these vectors can contain data of different types (strings and numbers in this case)

This ends the Prelude.

Create networks

Example network: undirected

Usually we would read network data from files, but for an initial understanding - and for small networks - we can create them “manually”. For instance, an undirected graph with 3 edges:

g1 <- make_graph(edges=c(1,2, 2,3, 3,1), directed=FALSE)
  • g1 is a variable (in a programming sense)
  • <- is an assignment operator: “Assign to what is left of the operator the value of that what is to the right of the operator”. It’s meant to look like an arrow.
  • c() concatinates what is between the brackets into a list.
  • The numbers are interpreted as vertex IDs, so the edges are 1–2, 2–3, 3–1.
  • The graph is undirected (the default of directed=TRUE is overwritten)

A simple plot of g1:

plot(g1)

And some information about g1:

g1
IGRAPH 094b0d4 U--- 3 3 -- 
+ edges from 094b0d4:
[1] 1--2 2--3 1--3

The first line is a bit cryptic, but informative. The description of an igraph object starts with four letters:

  • IGRAPH 094b0d4: Class and and internal identifier for the graph object- we can safely ignore this
  • D or U, for a directed or undirected graph
  • N for a named graph (where nodes have a name attribute), else -.
  • W for a weighted graph (where edges have a weight attribute), else -.
  • B for a bipartite (two-mode) graph (where nodes have a type attribute), else -.
  • number of vertices (nodes)
  • number of edges (links, ties)
  • followed by two dashes -- that have no meaning other than “end of first line”.

The lines after the first contain the network connections.

Question: What does it tell you that the listing of edges (links) is preceeded by [1]?

It means that the links are stored in a vector, but it’s not quite clear to me how because the links are not represented as strings:

c("1--2", "2--3", "1--3")
[1] "1--2" "2--3" "1--3"

I presume igraph defined a new data type that makes a tie such as 1--2 or 1->2 a ‘primitive’.

Example network: directed

g2 <- graph( edges=c(1,2, 2,3, 3,1), n=10 )
g2
IGRAPH 90fe0b9 D--- 10 3 -- 
+ edges from 90fe0b9:
[1] 1->2 2->3 3->1

This yields a network with n=10 vertices, not all of which are connected.

plot(g2)

Example network: named vertices

g3 <- graph( c("John", "Jim", "Jim", "Jill", "Jill", "John"))
plot(g3)

g3
IGRAPH 013dfe5 DN-- 3 3 -- 
+ attr: name (v/c)
+ edges from 013dfe5 (vertex names):
[1] John->Jim  Jim ->Jill Jill->John

You can see in line 1 that this is Directed and Named graph. The description also lists node & edge attributes.In this case the name (v/c) string means “vertex level attribute name with data type character”. In general:

  • (g/c) - graph-level character attribute
  • (v/c) - vertex-level character attribute
  • (e/n) - edge-level numeric attribute

Example network: named vertices and with named isolates

g4 <- graph( c("John", "Jim", "Jim", "Jack", "Jim", "Jack", "John", "John"), 
             isolates=c("Jesse", "Janis", "Jennifer", "Justin"))
plot(g4, edge.arrow.size=.5, vertex.color="gold", vertex.size=15, 
     vertex.frame.color="gray", vertex.label.color="black", 
     vertex.label.cex=0.8, vertex.label.dist=2, edge.curved=0.2)

This example shows how to label isolates in addition to connected vertices, and demonstrates some of ways one can use the plot() function to control display features.

Feel free to explore the plot function a bit more. For instance, try to change the vertex colour to red or green instead of gold. Remember, you can add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

(insert one or more chunks here, as you like.)

Exercise

Create a network object (and plot) that satisfies this IGRAPH signature:

DN-- 7 4 --

I copy Adrienne’s solution as an example (correct and first submitted):

g5 <- graph( c("Chris", "Adrienne", "Adrienne", "Kate", "Kate", "Jesse", "Jesse", "Chris"),
              isolates=c("Mary", "Ado", "Kuzma"))
g5
IGRAPH 35058c0 DN-- 7 4 -- 
+ attr: name (v/c)
+ edges from 35058c0 (vertex names):
[1] Chris   ->Adrienne Adrienne->Kate     Kate    ->Jesse    Jesse   ->Chris   
LS0tCnRpdGxlOiAiTmV0d29yayBWaXN1YWxpc2F0aW9uIHdpdGggaWdyYXBoIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyMjIFNldHVwIAoKYGBge3IgUGFja2FnZV9JbnN0YWxsYXRpb24sIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMgcnVuIHRoaXMgb25seSBpZiB5b3Uga25vdyB3aGF0IHlvdSBkby4gV2lsbCBub3QgcnVuIGF1dG9tYXRpY2FsbHkuIAojIE9ubHkgbmVlZGVkIHRoZSBmaXJzdCB0aW1lIG9uIGFueSBzcGVjaWZpYyBtYWNoaW5lLiAKaW5zdGFsbC5wYWNrYWdlcygiaWdyYXBoIikgCiMgaW5zdGFsbC5wYWNrYWdlcygibmV0d29yayIpIAojIGluc3RhbGwucGFja2FnZXMoInNuYSIpCiMgaW5zdGFsbC5wYWNrYWdlcygidmlzTmV0d29yayIpCiMgaW5zdGFsbC5wYWNrYWdlcygidGhyZWVqcyIpCiMgaW5zdGFsbC5wYWNrYWdlcygibmR0diIpCmBgYAoKVG8gcnVuIGEgImNodW5rIiAtIHRoZSBjb2RlIGJldHdlZW4gdGhlIGJhY2sgdGlja3MgLSBjbGljayBvbiB0aGUgZ3JlZW4gYXJyb3cgdG8gIHRoZSByaWdodC4gRm9yIG1vcmUgb3B0aW9ucyBzZWUgYFJ1bmAgYXQgdGhlIHRvcCBvZiB0aGUgc291cmNlIGVkaXRvciB3aW5kb3cgKHRoaXMgd2luZG93KS4gCgoKYGBge3IgaW5jbHVkZT1GQUxTRX0KIyBUaGlzIGp1c3QgY2xlYW5zIHRoZSBlbnZpcm9ubWVudCAtIG5vIHZhcmlhYmxlIGV0YyBkZWNsYXJlZApybShsaXN0ID0gbHMoKSkgCmBgYAoKSW4gdGhpcyB0dXRvcmlhbCB3ZSBhcmUgZ29pbmcgdG8gd29yayB3aXRoIHRoZSBpZ3JhcGggcGFja2FnZS4gUnVuIHRoaXMgY29tbWFuZDoKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoImlncmFwaCIpCmBgYAoKSWYgYW5kIG9ubHkgaWYgeW91IGdldCBhbiBlcnJvciBzYXlpbmcgdGhhdCB0aGUgcGFja2FnZSBpcyB1bmtvd24gcnVuIHRoZSBjaHVuayBhYm92ZSBjYWxsZWQgYFBhY2thZ2VfSW5zdGFsbGF0aW9uYC4gVGhlbiwgb3Igb3RoZXJ3aXNlLCBjb250aW51ZSB3aXRoIHRoZSBuZXh0IGxpbmUuIAoKVGhlIGJlc3Qgc291cmNlIG9mIGluZm9ybWF0aW9uIG9uIGlncmFwaCBpcyB0aGUgW29ubGluZSBkb2N1bWVudGF0aW9uXShodHRwczovL2lncmFwaC5vcmcvci9kb2MvKS4gCgoKIyBQcmVsdWRlOiBNaW5pbWFsIFIKClIgaXMgbm90IGEgY29tbWFuZCBsYW5ndWFnZSAtIGUuZy4sIGp1c3QgYSBidW5jaCBvZiBjb21tYW5kcyBmb3Igc3RhdGlzdGljcyBvcGVyYXRpb25zIC0gYnV0IGEgZnVsbCBwcm9ncmFtbWluZyBsYW5ndWFnZS4gVGhpcyBwcm92aWRlcyBncmVhdCBmbGV4aWxpYml0eSwgYnV0IGFsc28gbWVhbnMgdGhhdCBvbmUgaGFzIHRvIHVuZGVyc3RhbmQgYSBsaXR0bGUgYml0IGFib3V0IHByb2dyYW1taW5nLiBSZWFsbHksIGp1c3QgYSBsaXR0bGUgYml0LiAKVGhlcmVmb3JlLCBPY2Nhc2lvbmFsbHksIHdlIG5lZWQgdG8gbGVhcm4gLSBvciByZW1pbmQgb3Vyc2VsdmVzIG9mIC0gc29tZXRoaW5nIGFib3V0IFIuIEl0J2xsIGFsd2F5cyBiZSBzaG9ydCBhbmQgdG8gdGhlIHBvaW50LiBUd28gZWxlbWVudGFyeSB0aGluZ3MgdG9kYXk6IGFzc2lnbm1lbnRzIGFuZCB0aGUgbGlzdCBjb25zdHJ1Y3RvciBgYygpYC4gCgojIyBBc3NpZ25tZW50CgpZb3UgY2FuIGFzc2lnbiBhIHZhbHVlIHRvIGFuIG9iamVjdCB1c2luZyBhc3NpZ24oKSwgICI8LSIsIG9yICI9IjogCgpgYGB7cn0KeCA8LSAzICAgICAgICAgIyBBc3NpZ25tZW50CnggICAgICAgICAgICAgICMgRXZhbHVhdGUgdGhlIGV4cHJlc3Npb24gYW5kIHByaW50IHJlc3VsdApgYGAKCk5vdyB5b3U6IEFzc2lnbiB5IHRvIDQgYW5kIGV2YWx1YXRlLiAKCmBgYHtyfQp5ID0gNAp5CmBgYAoKTmV4dCwgd2hhdCBkbyB5b3UgZXhwZWN0IGFzIHJlc3VsdCB3aGVuIHlvdSBydW4gdGhpcyBjaHVuazogCgpgYGB7cn0KeSArIDUKeQpgYGAKCldoeSBkaWQgdGhlIHZhbHVlIG9mIHkgbm90IGNoYW5nZT8gCgpCZWNhdXNlIGlzIHdhcyBub3QgYXNzaWduZWQgdG8gYSBuZXcgdmFsdWU7IGl0IHdhcyBvbmx5IHVzZWQgaW4gZXZhbHVhdGlvbnMuIAoKV2UgY2FuIGNoYWluIG9iamVjdHMgdG9nZXRoZXIsIGxpa2UgaW4gYWxnZWJyYTogCgpgYGB7cn0KeiA9ICB4ICsgNSp5ICAgICMgQXNzaWdubWVudAp6ICAgICAgICAgICAgICMgRXZhbHVhdGlvbgpgYGAKCk5vdCBvbmx5IGNhbiB5b3UgY3JlYXRlIG9iamVjdHMsIHlvdSBjYW4gYWxzbyBkZXN0cm95IHRoZW06CgpgYGB7cn0Kcm0oeikgICAgICAgICAgIyBSZW1vdmUgejogZGVsZXRlcyB0aGUgb2JqZWN0Lgp6ICAgICAgICAgICAgICAjIEVycm9yIQpgYGAKCiMjIExpc3RzIGFuZCB2ZWN0b3JzLgoKTGlzdHMgYXJlIGJhc2ljIHRvIFI6IHRoaXMgaXMgYSBsaXN0OiBgKGFwcGxlLCBwZWFyLCBiYW5hbmEsIGNoZXJyeSlgLlRoZXNlIGtpbmQgb2Ygc2ltcGxlIGxpc3QtLWFsbCBlbGVtZW50cyBoYXZlIHRoZSBzYW1lIHR5cGUgKGNoYXJhY3RlcnMsIG51bWJlcnMpLCBub3QgZW1iZWRkaW5nIG9mIGxpc3RzIGluIGxpc3RzLS1hcmUgY2FsbGVkIGB2ZWN0b3JzYCBpbiBSLiBUaGUgdmVjdG9yLCBub3QgYW5kIGluZGl2aWR1YWwgdmFsdWUgKGF0b20pLCBpcyB0aGUgYmFzaWMgZGF0YSB0eXBlIGluIFIuIE9uZSB3YXkgdG8gY29uc3RydWN0IHZlY3RvcnMgaXMgd2l0aCBgYygpYC4gCgpgYGB7cn0KZnJ1aXQgPC0gYygiYXBwbGUiLCAicGVhciIsICJiYW5hbmEiLCAiY2hlcnJ5IikKZnJ1aXQKYGBgCgpOb3cgeW91OiBNYWtlIGEgdmVjdG9yIC0gYSBzaW1wbGUgbGlzdCAtIG9mIG51bWJlcnMgMS00LiBBc3NpZ24gaXQgdG8gbnVtVmVjCgpgYGB7cn0KbnVtVmVjIDwtIGMoMSwgMiwgMywgNCkKbnVtVmVjCmBgYAoKUiBpcyBhbGwgYWJvdXQgdmVjdG9ycywgc28gbWF0aCBpcyBkb25lIG9uIHZlY3RvcnMgaWYgdGhleSBjb250YWluIG51bWJlcnM6CgpgYGB7cn0KbnVtVmVjICsgMQpudW1WZWMgKiBudW1WZWMKYGBgCihUaG9zZSBvZiB5b3Ugd2hvIGhhdmUgZG9uZSBhIGJpdCBvZiBjb2Rpbmcgd2lsbCBzZWUgaW1tZWRpYXRlbHkgd2hhdCB0aGlzIG1lYW5zOiBNdWNoIGxlc3MgbmVlZCBmb3IgbG9vcGluZyEpCgpJZiB5b3Ugd2FudCB0byBwaWNrIGFuIGVsZW1lbnQsIG9yIGEgc2V0IG9mIGVsZW1lbnRzLCB5b3UgY2FuIHVzZSB0aGUgaW5kZXg6IAoKYGBge3J9Cm51bVZlY1syXQpjKCJFaW5zIiwgInp3ZWkiLCAiZHJlaSIpWzFdCmBgYAoKCldoZW4gd2UgYXNzaWduIGRpZmZlcmVudCBraW5kcyBvZiBhdG9tcyB0byBhIHZlY3RvciwgdGhleSB3aWxsIGJlIHRyYW5zZm9ybWVkIGF1dG9tYXRpY2FsbHkgdG8gYmUgb2Ygb25lIHR5cGUgLSBhIHByb2Nlc3MgY2FsbGVkIGNvZXJjaW9uLiBMaWtlIHNvOgoKYGBge3J9CmMoMSwgMiwgMywgImZvdXIiKQpgYGAKQmV0dGVyIG5vdCB0byB0cnkgYXJpdGhtZXRpYyBvbiB0aGlzIHZlY3Rvci4gCgoKTm93IHRoZSBkaWZmZXJlbmNlIHRvIGEgbGlzdCBjYW4gYmUgZGVtb25zdHJhdGVkLCB1c2luZyB0aGUgYGxpc3QoKWAgb3BlcmF0b3IgdG8gY3JlYXRlLCB5b3UgZ3Vlc3NlZCBpdCwgYSBsaXN0LiAKCmBgYHtyfQpsaXN0KDEsICJhcHBsZSIsIDUsICJwZWFyIikKYGBgCllvdSBzZWUsIGJlY2F1c2UgdmVjdG9ycyBhcmUgUidzICdwcmltaXRpdmUnIGRhdGEgc3RydWN0dXJlLCBhIGxpc3QgaXMgYSBsaXN0IG9mIHZlY3RvcnMsIGV2ZW4gd2hlbiB0aGVzZSB2ZWN0b3IgaGF2ZSBsZW5ndGggMS4gCgpgYGB7cn0KTWl4ZWRCYWcgPC0gbGlzdChmcnVpdCwgbnVtVmVjKQpNaXhlZEJhZwpgYGAKQXMgeW91IHNlZSwgbGlzdHMgY2FuIGNvbnRhaW4gbXVsdGlwbGUgdmVjdG9ycyAtIGFuZCwgaW5kZWVkLCBtdWx0aXBsZSBsaXN0cyAtIGFuZCB0aGVzZSB2ZWN0b3JzIGNhbiBjb250YWluIGRhdGEgb2YgZGlmZmVyZW50IHR5cGVzIChzdHJpbmdzIGFuZCBudW1iZXJzIGluIHRoaXMgY2FzZSkKClRoaXMgZW5kcyB0aGUgUHJlbHVkZS4gCgoKIyAgQ3JlYXRlIG5ldHdvcmtzCgojIyBFeGFtcGxlIG5ldHdvcms6IHVuZGlyZWN0ZWQKClVzdWFsbHkgd2Ugd291bGQgcmVhZCBuZXR3b3JrIGRhdGEgZnJvbSBmaWxlcywgYnV0IGZvciBhbiBpbml0aWFsIHVuZGVyc3RhbmRpbmcgLSBhbmQgZm9yIHNtYWxsIG5ldHdvcmtzIC0gIHdlIGNhbiBjcmVhdGUgdGhlbSAibWFudWFsbHkiLiBGb3IgaW5zdGFuY2UsIGFuIHVuZGlyZWN0ZWQgZ3JhcGggd2l0aCAzIGVkZ2VzOiAKCmBgYHtyfQpnMSA8LSBtYWtlX2dyYXBoKGVkZ2VzPWMoMSwyLCAyLDMsIDMsMSksIGRpcmVjdGVkPUZBTFNFKQpgYGAKKiBnMSBpcyBhIHZhcmlhYmxlIChpbiBhIHByb2dyYW1taW5nIHNlbnNlKQoqIGA8LWAgaXMgYW4gYXNzaWdubWVudCBvcGVyYXRvcjogIkFzc2lnbiB0byB3aGF0IGlzIGxlZnQgb2YgdGhlIG9wZXJhdG9yIHRoZSB2YWx1ZSBvZiB0aGF0IHdoYXQgaXMgdG8gdGhlIHJpZ2h0IG9mIHRoZSBvcGVyYXRvciIuIEl0J3MgbWVhbnQgdG8gbG9vayBsaWtlIGFuIGFycm93LiAKKiBgYygpYCBjb25jYXRpbmF0ZXMgd2hhdCBpcyBiZXR3ZWVuIHRoZSBicmFja2V0cyBpbnRvIGEgbGlzdC4gCiogVGhlIG51bWJlcnMgYXJlIGludGVycHJldGVkIGFzIHZlcnRleCBJRHMsIHNvIHRoZSBlZGdlcyBhcmUgMS0tMiwgMi0tMywgMy0tMS4KKiBUaGUgZ3JhcGggaXMgdW5kaXJlY3RlZCAodGhlIGRlZmF1bHQgb2YgYGRpcmVjdGVkPVRSVUVgIGlzIG92ZXJ3cml0dGVuKQogCgpBIHNpbXBsZSBwbG90IG9mIGcxOiAKCmBgYHtyfQpwbG90KGcxKQpgYGAKQW5kIHNvbWUgaW5mb3JtYXRpb24gYWJvdXQgZzE6IAoKYGBge3J9CmcxCmBgYApUaGUgZmlyc3QgbGluZSAgaXMgYSBiaXQgY3J5cHRpYywgYnV0IGluZm9ybWF0aXZlLiBUaGUgZGVzY3JpcHRpb24gb2YgYW4gaWdyYXBoIG9iamVjdCBzdGFydHMgd2l0aCBmb3VyIGxldHRlcnM6CgoqIGBJR1JBUEggMDk0YjBkNGA6IENsYXNzIGFuZCBhbmQgaW50ZXJuYWwgaWRlbnRpZmllciBmb3IgdGhlIGdyYXBoIG9iamVjdC0gd2UgY2FuIHNhZmVseSBpZ25vcmUgdGhpcyAKKiBEIG9yIFUsIGZvciBhIGRpcmVjdGVkIG9yIHVuZGlyZWN0ZWQgZ3JhcGgKKiBOIGZvciBhIG5hbWVkIGdyYXBoICh3aGVyZSBub2RlcyBoYXZlIGEgbmFtZSBhdHRyaWJ1dGUpLCBlbHNlIGAtYC4gCiogVyBmb3IgYSB3ZWlnaHRlZCBncmFwaCAod2hlcmUgZWRnZXMgaGF2ZSBhIHdlaWdodCBhdHRyaWJ1dGUpLCBlbHNlIGAtYC4gCiogQiBmb3IgYSBiaXBhcnRpdGUgKHR3by1tb2RlKSBncmFwaCAod2hlcmUgbm9kZXMgaGF2ZSBhIHR5cGUgYXR0cmlidXRlKSwgZWxzZSBgLWAuCiogbnVtYmVyIG9mIHZlcnRpY2VzIChub2RlcykKKiBudW1iZXIgb2YgZWRnZXMgKGxpbmtzLCB0aWVzKQoqIGZvbGxvd2VkICBieSB0d28gZGFzaGVzIGAtLWAgdGhhdCBoYXZlIG5vIG1lYW5pbmcgb3RoZXIgdGhhbiAiZW5kIG9mIGZpcnN0IGxpbmUiLiAKClRoZSBsaW5lcyBhZnRlciB0aGUgZmlyc3QgIGNvbnRhaW4gdGhlIG5ldHdvcmsgY29ubmVjdGlvbnMuIAoKKipRdWVzdGlvbjoqKiBXaGF0IGRvZXMgaXQgdGVsbCB5b3UgdGhhdCB0aGUgbGlzdGluZyBvZiBlZGdlcyAobGlua3MpIGlzIHByZWNlZWRlZCBieSBgWzFdYD8gCgpJdCBtZWFucyB0aGF0IHRoZSBsaW5rcyBhcmUgc3RvcmVkIGluIGEgdmVjdG9yLCBidXQgaXQncyBub3QgcXVpdGUgY2xlYXIgdG8gbWUgaG93IGJlY2F1c2UgdGhlIGxpbmtzIGFyZSBub3QgcmVwcmVzZW50ZWQgYXMgc3RyaW5nczogCgpgYGB7cn0KYygiMS0tMiIsICIyLS0zIiwgIjEtLTMiKQpgYGAKSSBwcmVzdW1lIGlncmFwaCBkZWZpbmVkIGEgbmV3IGRhdGEgdHlwZSB0aGF0IG1ha2VzIGEgdGllIHN1Y2ggYXMgYDEtLTJgIG9yIGAxLT4yYCBhICdwcmltaXRpdmUnLiAKCgojIyBFeGFtcGxlIG5ldHdvcms6IGRpcmVjdGVkCgoKYGBge3J9CmcyIDwtIGdyYXBoKCBlZGdlcz1jKDEsMiwgMiwzLCAzLDEpLCBuPTEwICkKZzIKYGBgClRoaXMgeWllbGRzIGEgbmV0d29yayB3aXRoIGBuPTEwYCB2ZXJ0aWNlcywgbm90IGFsbCBvZiB3aGljaCBhcmUgY29ubmVjdGVkLiAKCmBgYHtyfQpwbG90KGcyKQpgYGAKCgojIyBFeGFtcGxlIG5ldHdvcms6IG5hbWVkIHZlcnRpY2VzCgpgYGB7cn0KZzMgPC0gZ3JhcGgoIGMoIkpvaG4iLCAiSmltIiwgIkppbSIsICJKaWxsIiwgIkppbGwiLCAiSm9obiIpKQpwbG90KGczKQpgYGAKCmBgYHtyfQpnMwpgYGAKWW91IGNhbiBzZWUgaW4gbGluZSAxIHRoYXQgdGhpcyBpcyBEaXJlY3RlZCBhbmQgTmFtZWQgZ3JhcGguICBUaGUgZGVzY3JpcHRpb24gYWxzbyBsaXN0cyBub2RlICYgZWRnZSBhdHRyaWJ1dGVzLkluIHRoaXMgY2FzZSB0aGUgYG5hbWUgKHYvYylgIHN0cmluZyBtZWFucyAidmVydGV4IGxldmVsIGF0dHJpYnV0ZSBgbmFtZWAgd2l0aCBkYXRhIHR5cGUgY2hhcmFjdGVyIi4gSW4gZ2VuZXJhbDogCgoqIChnL2MpIC0gZ3JhcGgtbGV2ZWwgY2hhcmFjdGVyIGF0dHJpYnV0ZQoqICh2L2MpIC0gdmVydGV4LWxldmVsIGNoYXJhY3RlciBhdHRyaWJ1dGUKKiAoZS9uKSAtIGVkZ2UtbGV2ZWwgbnVtZXJpYyBhdHRyaWJ1dGUKCiMjIEV4YW1wbGUgbmV0d29yazogbmFtZWQgdmVydGljZXMgYW5kIHdpdGggbmFtZWQgaXNvbGF0ZXMKCmBgYHtyfQpnNCA8LSBncmFwaCggYygiSm9obiIsICJKaW0iLCAiSmltIiwgIkphY2siLCAiSmltIiwgIkphY2siLCAiSm9obiIsICJKb2huIiksIAogICAgICAgICAgICAgaXNvbGF0ZXM9YygiSmVzc2UiLCAiSmFuaXMiLCAiSmVubmlmZXIiLCAiSnVzdGluIikpCnBsb3QoZzQsIGVkZ2UuYXJyb3cuc2l6ZT0uNSwgdmVydGV4LmNvbG9yPSJnb2xkIiwgdmVydGV4LnNpemU9MTUsIAogICAgIHZlcnRleC5mcmFtZS5jb2xvcj0iZ3JheSIsIHZlcnRleC5sYWJlbC5jb2xvcj0iYmxhY2siLCAKICAgICB2ZXJ0ZXgubGFiZWwuY2V4PTAuOCwgdmVydGV4LmxhYmVsLmRpc3Q9MiwgZWRnZS5jdXJ2ZWQ9MC4yKQoKYGBgClRoaXMgZXhhbXBsZSBzaG93cyBob3cgdG8gbGFiZWwgaXNvbGF0ZXMgaW4gYWRkaXRpb24gdG8gY29ubmVjdGVkIHZlcnRpY2VzLCBhbmQgZGVtb25zdHJhdGVzIHNvbWUgb2Ygd2F5cyBvbmUgY2FuIHVzZSB0aGUgYHBsb3QoKWAgZnVuY3Rpb24gdG8gY29udHJvbCBkaXNwbGF5IGZlYXR1cmVzLgoKRmVlbCBmcmVlIHRvIGV4cGxvcmUgdGhlIHBsb3QgZnVuY3Rpb24gYSBiaXQgbW9yZS4gRm9yIGluc3RhbmNlLCB0cnkgdG8gY2hhbmdlIHRoZSB2ZXJ0ZXggY29sb3VyIHRvIHJlZCBvciBncmVlbiBpbnN0ZWFkIG9mIGdvbGQuIFJlbWVtYmVyLCB5b3UgY2FuIGFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDbWQrT3B0aW9uK0kqLgoKKGluc2VydCBvbmUgb3IgbW9yZSBjaHVua3MgaGVyZSwgYXMgeW91IGxpa2UuKQoKCgojIyBFeGVyY2lzZQoKQ3JlYXRlIGEgbmV0d29yayBvYmplY3QgKGFuZCBwbG90KSB0aGF0IHNhdGlzZmllcyB0aGlzIElHUkFQSCBzaWduYXR1cmU6IAoKYGBgCkROLS0gNyA0IC0tCmBgYApJIGNvcHkgQWRyaWVubmUncyBzb2x1dGlvbiBhcyBhbiBleGFtcGxlIChjb3JyZWN0IGFuZCBmaXJzdCBzdWJtaXR0ZWQpOiAKCmBgYHtyfQpnNSA8LSBncmFwaCggYygiQ2hyaXMiLCAiQWRyaWVubmUiLCAiQWRyaWVubmUiLCAiS2F0ZSIsICJLYXRlIiwgIkplc3NlIiwgIkplc3NlIiwgIkNocmlzIiksCiAgICAgICAgICAgICAgaXNvbGF0ZXM9YygiTWFyeSIsICJBZG8iLCAiS3V6bWEiKSkKZzUKYGBgCg==