The R markdown is available from the pulldown menu for Code at the upper-right, choose “Download Rmd”, or download the Rmd from GitHub.


Cytoscape is an open source software platform for integrating, visualizing, and analyzing measurement data in the context of networks. This tutorial presents a scenario of how expression and network data can be combined to tell a biological story and includes these concepts:

  • Visualizing networks using expression data.
  • Filtering networks based on expression data.
  • Assessing expression data in the context of a biological network.


Installation

if (!requireNamespace("BiocManager", quietly = TRUE))
  install.packages("BiocManager")

if(!"RCy3" %in% installed.packages())
  BiocManager::install("RCy3")

library(RCy3)

Getting started

First, launch Cytoscape and keep it running whenever using RCy3. Confirm that you have everything installed and running:

cytoscapePing()
cytoscapeVersionInfo()

Loading Network

Let’s open a Cytoscape demo session file:

openSession()

Visualizing Expression Data on Networks

Probably the most common use of expression data in Cytoscape is to set the visual style of the nodes (color, shape, border) in a network according to available data. This creates a powerful visualization, portraying functional relation and experimental response at the same time. Here, we will show an example of doing this.

The data used in this example is from yeast, and represents an experiment of perturbations of the genes Gal1, Gal4, and Gal80, which are all yeast transcription factors.

For this tutorial, the experimental data was part of the Cytoscape session file you loaded earlier, and is visible in the Node Table:

We can now use the data to manipulate the visual properties of the network by mapping specific data columns to visual style properties:

The gal80Rexp expression values will be mapped to node color; nodes with low expression will be colored blue, nodes with high expression will be colored red. Significance for expression values will be mapped to Node Border Width, so nodes with significant changes will appear with a thicker border.

Set Node Fill Color

Let’s specify the node fill color as a gradient ranging from blue to red for expression values using a continuous mapping for the ‘gal80Rexp’ column:

setNodeColorMapping('gal80Rexp', colors=paletteColorBrewerRdBu, style.name="galFiltered Style")

Note: we are using paletteColorBrewerRdBu to generate a set of three standardized colors balanced for a divergent gradient (low, mid, high), which are automatically extracted from the gal80RExp column.

This produces an initial gradient ranging from blue to red for expression values. Notice that the nodes in the network change color.

Set Node Border Color and Width

To visualize the significance of measurements, let’s add a contiuous mapping for ‘gal80Rsig’ p-values to Node Border Color:

setNodeBorderColorMapping('gal80Rsig',c(0,0.05), c("#FF0000","#FF0000","#FF0000","#555555"),style.name="galFiltered Style")

Note: We are supplying a min and max points, together with four color values. Providing n+2 values will result in assigning “below min” and “above max” mappings (see image).

…and let’s also map the same gal80RSig values to set the Node Border Widths:

setNodeBorderWidthMapping('gal80Rsig',c(0,0.05),c(4,4,4,1),style.name="galFiltered Style")

Note: We are supplying the same min and max points, together with n+2 width values.

Select Nodes

Cytoscape allows you to easily filter and select nodes and edges based on data attributes. Next, we will select a subset of nodes with high expression in the gal80 knockout:

Let’s select a subset of nodes with high expression in the gal80 knockout:

createColumnFilter('myFilter', 'gal80Rexp', 2, "GREATER_THAN")

You should now see only three nodes in the network selected (highlighted yellow).

Expand Selection

We have now selected only the few top expressing nodes. To see the context of these nodes in the larger network, we can expand the selection to second-degree neighbors:

selectFirstNeighbors() # first degree
selectFirstNeighbors() # second degree

Create New Network

Finally, we can create a subnetwork from this selection and apply a layout algorithm:

createSubnetwork(nodes="selected", subnetwork.name='galFiltered sub')
layoutNetwork('force-directed')

Note: Cytoscape supports many different layout algorithms, described in detail in the Cytoscape manual.

Digging into the biology of this network, it turns out that GAL4 is repressed by GAL80. Both nodes (GAL4 and GAL11) show fairly small changes in expression, and neither change is statistically significant: they are pale blue with thin borders. These slight changes in expression suggest that the critical change affecting the red nodes might be somewhere else in the network, and not either of these nodes. GAL4 interacts with GAL80, which shows a significant level of repression: it is medium blue with a thicker border.

Note that while GAL80 shows evidence of significant repression (blue), most nodes interacting with GAL4 show significant levels of induction (red). GAL11 is a general transcription co-factor with many interactions.

Putting all of this together, we see that the transcriptional activation activity of Gal4 is repressed by Gal80. So, repression of Gal80 increases the transcriptional activation activity of Gal4. Even though the expression of Gal4 itself did not significantly change (no red border), the Gal4 transcripts were much more likely to be active transcription factors when Gal80 was repressed. This explains why there is so much up-regulation in the vicinity of Gal4.

Summary

In summary, we have:

  • Explored a yeast interactome from a transcription factor knockout experiment
  • Created a visual style using expression value as node color and with border width mapped to significance
  • Selected high expressing genes and their neighbors and created a new network

Finally, we can now export this network as a publication-quality image….

Saving Results

Cytoscape provides a number of ways to save results and visualizations:

  • As a session:
saveSession('basic-data-visualization.cys')
  • As an image:
exportImage('basic-data-visualization', 'PDF')

Note: PNG, SVG, JPEG and PS are also supported

  • To a public repository:
exportNetworkToNDEx("user", "pass", TRUE) #requires a free NDEx account
  • As a graph format file (Formats: “CX JSON”, “Cytoscape.js JSON”, “GraphML”, “XGMML”, “SIF”,…):
exportNetwork('basic-data-visualization', 'CX')

Note: cyjs, graphML, xGMML and SIF are also supported

LS0tCnRpdGxlOiAiQmFzaWMgRGF0YSBWaXN1YWxpemF0aW9uIgphdXRob3I6ICJLb3pvIE5pc2hpZGEsIEtyaXN0aW5hIEhhbnNwZXJzIGFuZCBBbGV4IFBpY28iCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIEJpb2NTdHlsZTo6aHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICBkZl9wcmludDogcGFnZWQKLS0tCmBgYHtyIGVjaG89RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBldmFsPUZBTFNFCikKYGBgCipUaGUgUiBtYXJrZG93biBpcyBhdmFpbGFibGUgZnJvbSB0aGUgcHVsbGRvd24gbWVudSBmb3IqIENvZGUgKmF0IHRoZSB1cHBlci1yaWdodCwgY2hvb3NlICJEb3dubG9hZCBSbWQiLCBvciBbZG93bmxvYWQgdGhlIFJtZCBmcm9tIEdpdEh1Yl0oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2N5dG9zY2FwZS9jeXRvc2NhcGUtYXV0b21hdGlvbi9tYXN0ZXIvZm9yLXNjcmlwdGVycy9SL25vdGVib29rcy9iYXNpYy1kYXRhLXZpc3VhbGl6YXRpb24uUm1kKS4qCgo8aHIgLz4KCkN5dG9zY2FwZSBpcyBhbiBvcGVuIHNvdXJjZSBzb2Z0d2FyZSBwbGF0Zm9ybSBmb3IgaW50ZWdyYXRpbmcsIHZpc3VhbGl6aW5nLCBhbmQgYW5hbHl6aW5nIG1lYXN1cmVtZW50IGRhdGEgaW4gdGhlIGNvbnRleHQgb2YgbmV0d29ya3MuIFRoaXMgdHV0b3JpYWwgcHJlc2VudHMgYSBzY2VuYXJpbyBvZiBob3cgZXhwcmVzc2lvbiBhbmQgbmV0d29yayBkYXRhIGNhbiBiZSBjb21iaW5lZCB0byB0ZWxsIGEgYmlvbG9naWNhbCBzdG9yeSBhbmQgaW5jbHVkZXMgdGhlc2UgY29uY2VwdHM6CgogLSBWaXN1YWxpemluZyBuZXR3b3JrcyB1c2luZyBleHByZXNzaW9uIGRhdGEuCiAtIEZpbHRlcmluZyBuZXR3b3JrcyBiYXNlZCBvbiBleHByZXNzaW9uIGRhdGEuCiAtIEFzc2Vzc2luZyBleHByZXNzaW9uIGRhdGEgaW4gdGhlIGNvbnRleHQgb2YgYSBiaW9sb2dpY2FsIG5ldHdvcmsuCgohW10oLi9kYXRhL2ltZy9maW5hbC5wbmcpCgo8aHIgLz4KCiMgSW5zdGFsbGF0aW9uCmBgYHtyIGV2YWw9RkFMU0V9CmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5ID0gVFJVRSkpCiAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQoKaWYoISJSQ3kzIiAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpKQogIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCJSQ3kzIikKCmxpYnJhcnkoUkN5MykKYGBgCgojIEdldHRpbmcgc3RhcnRlZApGaXJzdCwgbGF1bmNoIEN5dG9zY2FwZSBhbmQga2VlcCBpdCBydW5uaW5nIHdoZW5ldmVyIHVzaW5nIFJDeTMuIENvbmZpcm0gdGhhdCB5b3UgaGF2ZSBldmVyeXRoaW5nIGluc3RhbGxlZCBhbmQgcnVubmluZzoKYGBge3J9CmN5dG9zY2FwZVBpbmcoKQpjeXRvc2NhcGVWZXJzaW9uSW5mbygpCmBgYAoKIyBMb2FkaW5nIE5ldHdvcmsKTGV0J3Mgb3BlbiBhIEN5dG9zY2FwZSBkZW1vIHNlc3Npb24gZmlsZTogCgpgYGB7cn0Kb3BlblNlc3Npb24oKQpgYGAKCiMgVmlzdWFsaXppbmcgRXhwcmVzc2lvbiBEYXRhIG9uIE5ldHdvcmtzCgpQcm9iYWJseSB0aGUgbW9zdCBjb21tb24gdXNlIG9mIGV4cHJlc3Npb24gZGF0YSBpbiBDeXRvc2NhcGUgaXMgdG8gc2V0IHRoZSAqKnZpc3VhbCBzdHlsZSoqIG9mIHRoZSBub2RlcyAoY29sb3IsIHNoYXBlLCBib3JkZXIpIGluIGEgbmV0d29yayBhY2NvcmRpbmcgdG8gYXZhaWxhYmxlIGRhdGEuIFRoaXMgY3JlYXRlcyBhIHBvd2VyZnVsIHZpc3VhbGl6YXRpb24sIHBvcnRyYXlpbmcgZnVuY3Rpb25hbCByZWxhdGlvbiBhbmQgZXhwZXJpbWVudGFsIHJlc3BvbnNlIGF0IHRoZSBzYW1lIHRpbWUuIEhlcmUsIHdlIHdpbGwgc2hvdyBhbiBleGFtcGxlIG9mIGRvaW5nIHRoaXMuCgpUaGUgZGF0YSB1c2VkIGluIHRoaXMgZXhhbXBsZSBpcyBmcm9tIHllYXN0LCBhbmQgcmVwcmVzZW50cyBhbiBleHBlcmltZW50IG9mIHBlcnR1cmJhdGlvbnMgb2YgdGhlIGdlbmVzICoqR2FsMSoqLCAqKkdhbDQqKiwgYW5kICoqR2FsODAqKiwgd2hpY2ggYXJlIGFsbCB5ZWFzdCB0cmFuc2NyaXB0aW9uIGZhY3RvcnMuCgpGb3IgdGhpcyB0dXRvcmlhbCwgdGhlIGV4cGVyaW1lbnRhbCBkYXRhIHdhcyBwYXJ0IG9mIHRoZSBDeXRvc2NhcGUgc2Vzc2lvbiBmaWxlIHlvdSBsb2FkZWQgZWFybGllciwgYW5kIGlzIHZpc2libGUgaW4gdGhlIE5vZGUgVGFibGU6Cgo8Y2VudGVyPgohW10oLi9kYXRhL2ltZy9iYXNpYy1kYXRhdml6LWdhbGJyb3dzZTMucG5nKQo8L2NlbnRlcj4KCldlIGNhbiBub3cgdXNlIHRoZSBkYXRhIHRvIG1hbmlwdWxhdGUgdGhlIHZpc3VhbCBwcm9wZXJ0aWVzIG9mIHRoZSBuZXR3b3JrIGJ5IG1hcHBpbmcgc3BlY2lmaWMgZGF0YSBjb2x1bW5zIHRvIHZpc3VhbCBzdHlsZSBwcm9wZXJ0aWVzOgoKVGhlICoqZ2FsODBSZXhwKiogZXhwcmVzc2lvbiB2YWx1ZXMgd2lsbCBiZSBtYXBwZWQgdG8gbm9kZSBjb2xvcjsgbm9kZXMgd2l0aCBsb3cgZXhwcmVzc2lvbiB3aWxsIGJlIGNvbG9yZWQgYmx1ZSwgbm9kZXMgd2l0aCBoaWdoIGV4cHJlc3Npb24gd2lsbCBiZSBjb2xvcmVkIHJlZC4KU2lnbmlmaWNhbmNlIGZvciBleHByZXNzaW9uIHZhbHVlcyB3aWxsIGJlIG1hcHBlZCB0byBOb2RlIEJvcmRlciBXaWR0aCwgc28gbm9kZXMgd2l0aCBzaWduaWZpY2FudCBjaGFuZ2VzIHdpbGwgYXBwZWFyIHdpdGggYSB0aGlja2VyIGJvcmRlci4KCiMjIFNldCBOb2RlIEZpbGwgQ29sb3IKCkxldCdzIHNwZWNpZnkgdGhlIG5vZGUgZmlsbCBjb2xvciBhcyBhIGdyYWRpZW50IHJhbmdpbmcgZnJvbSAqKmJsdWUgdG8gcmVkKiogZm9yIGV4cHJlc3Npb24gdmFsdWVzIHVzaW5nIGEgY29udGludW91cyBtYXBwaW5nIGZvciB0aGUgJ2dhbDgwUmV4cCcgY29sdW1uOgoKYGBge3J9CnNldE5vZGVDb2xvck1hcHBpbmcoJ2dhbDgwUmV4cCcsIGNvbG9ycz1wYWxldHRlQ29sb3JCcmV3ZXJSZEJ1LCBzdHlsZS5uYW1lPSJnYWxGaWx0ZXJlZCBTdHlsZSIpCmBgYAoKKk5vdGU6IHdlIGFyZSB1c2luZyBgcGFsZXR0ZUNvbG9yQnJld2VyUmRCdWAgdG8gZ2VuZXJhdGUgYSBzZXQgb2YgdGhyZWUgc3RhbmRhcmRpemVkIGNvbG9ycyBiYWxhbmNlZCBmb3IgYSBkaXZlcmdlbnQgZ3JhZGllbnQgKGxvdywgbWlkLCBoaWdoKSwgd2hpY2ggYXJlIGF1dG9tYXRpY2FsbHkgZXh0cmFjdGVkIGZyb20gdGhlIGBnYWw4MFJFeHBgIGNvbHVtbi4qCgoKVGhpcyBwcm9kdWNlcyBhbiBpbml0aWFsIGdyYWRpZW50IHJhbmdpbmcgZnJvbSBibHVlIHRvIHJlZCBmb3IgZXhwcmVzc2lvbiB2YWx1ZXMuIE5vdGljZSB0aGF0IHRoZSBub2RlcyBpbiB0aGUgbmV0d29yayBjaGFuZ2UgY29sb3IuCgoKPGNlbnRlcj4KIVtdKC4vZGF0YS9pbWcvZXhwLWdyYWRpZW50LnBuZykKPC9jZW50ZXI+CgojIyBTZXQgTm9kZSBCb3JkZXIgQ29sb3IgYW5kIFdpZHRoCgpUbyB2aXN1YWxpemUgdGhlIHNpZ25pZmljYW5jZSBvZiBtZWFzdXJlbWVudHMsIGxldCdzIGFkZCBhIGNvbnRpdW91cyBtYXBwaW5nIGZvciAnZ2FsODBSc2lnJyBwLXZhbHVlcyB0byBOb2RlIEJvcmRlciBDb2xvcjoKYGBge3J9CnNldE5vZGVCb3JkZXJDb2xvck1hcHBpbmcoJ2dhbDgwUnNpZycsYygwLDAuMDUpLCBjKCIjRkYwMDAwIiwiI0ZGMDAwMCIsIiNGRjAwMDAiLCIjNTU1NTU1Iiksc3R5bGUubmFtZT0iZ2FsRmlsdGVyZWQgU3R5bGUiKQpgYGAKCipOb3RlOiBXZSBhcmUgc3VwcGx5aW5nIGEgbWluIGFuZCBtYXggcG9pbnRzLCB0b2dldGhlciB3aXRoICpmb3VyICpjb2xvciB2YWx1ZXMuIFByb3ZpZGluZyBuKzIgdmFsdWVzIHdpbGwgcmVzdWx0IGluIGFzc2lnbmluZyAiYmVsb3cgbWluIiBhbmQgImFib3ZlIG1heCIgbWFwcGluZ3MgKHNlZSBpbWFnZSkuKgoKPGNlbnRlcj4KIVtdKC4vZGF0YS9pbWcvc2lnLWdyYWRpZW50Mi5wbmcpCjwvY2VudGVyPgouLi5hbmQgbGV0J3MgYWxzbyBtYXAgdGhlIHNhbWUgZ2FsODBSU2lnIHZhbHVlcyB0byBzZXQgdGhlIE5vZGUgQm9yZGVyIFdpZHRoczoKCmBgYHtyfQpzZXROb2RlQm9yZGVyV2lkdGhNYXBwaW5nKCdnYWw4MFJzaWcnLGMoMCwwLjA1KSxjKDQsNCw0LDEpLHN0eWxlLm5hbWU9ImdhbEZpbHRlcmVkIFN0eWxlIikKYGBgCgoqTm90ZTogV2UgYXJlIHN1cHBseWluZyB0aGUgc2FtZSBtaW4gYW5kIG1heCBwb2ludHMsIHRvZ2V0aGVyIHdpdGggbisyIHdpZHRoIHZhbHVlcy4qCgo8Y2VudGVyPgohW10oLi9kYXRhL2ltZy9zdHlsZXMtZG9uZS5wbmcpCjwvY2VudGVyPgoKCiMgU2VsZWN0IE5vZGVzCgpDeXRvc2NhcGUgYWxsb3dzIHlvdSB0byBlYXNpbHkgZmlsdGVyIGFuZCBzZWxlY3Qgbm9kZXMgYW5kIGVkZ2VzIGJhc2VkIG9uIGRhdGEgYXR0cmlidXRlcy4gTmV4dCwgd2Ugd2lsbCBzZWxlY3QgYSBzdWJzZXQgb2Ygbm9kZXMgd2l0aCBoaWdoIGV4cHJlc3Npb24gaW4gdGhlIGdhbDgwIGtub2Nrb3V0OgoKTGV0J3Mgc2VsZWN0IGEgc3Vic2V0IG9mIG5vZGVzIHdpdGggaGlnaCBleHByZXNzaW9uIGluIHRoZSBnYWw4MCBrbm9ja291dDogCgoKYGBge3J9CmNyZWF0ZUNvbHVtbkZpbHRlcignbXlGaWx0ZXInLCAnZ2FsODBSZXhwJywgMiwgIkdSRUFURVJfVEhBTiIpCmBgYAoKWW91IHNob3VsZCBub3cgc2VlIG9ubHkgdGhyZWUgbm9kZXMgaW4gdGhlIG5ldHdvcmsgc2VsZWN0ZWQgKGhpZ2hsaWdodGVkIHllbGxvdykuCgojIyBFeHBhbmQgU2VsZWN0aW9uIAoKV2UgaGF2ZSBub3cgc2VsZWN0ZWQgb25seSB0aGUgZmV3IHRvcCBleHByZXNzaW5nIG5vZGVzLiBUbyBzZWUgdGhlIGNvbnRleHQgb2YgdGhlc2Ugbm9kZXMgaW4gdGhlIGxhcmdlciBuZXR3b3JrLCB3ZSBjYW4gZXhwYW5kIHRoZSBzZWxlY3Rpb24gdG8gc2Vjb25kLWRlZ3JlZSBuZWlnaGJvcnM6CgpgYGB7cn0Kc2VsZWN0Rmlyc3ROZWlnaGJvcnMoKSAjIGZpcnN0IGRlZ3JlZQpzZWxlY3RGaXJzdE5laWdoYm9ycygpICMgc2Vjb25kIGRlZ3JlZQpgYGAKCiMjIENyZWF0ZSBOZXcgTmV0d29yawpGaW5hbGx5LCB3ZSBjYW4gY3JlYXRlIGEgc3VibmV0d29yayBmcm9tIHRoaXMgc2VsZWN0aW9uIGFuZCBhcHBseSBhIGxheW91dCBhbGdvcml0aG06CgpgYGB7cn0KY3JlYXRlU3VibmV0d29yayhub2Rlcz0ic2VsZWN0ZWQiLCBzdWJuZXR3b3JrLm5hbWU9J2dhbEZpbHRlcmVkIHN1YicpCmxheW91dE5ldHdvcmsoJ2ZvcmNlLWRpcmVjdGVkJykKYGBgCgoqTm90ZTogQ3l0b3NjYXBlIHN1cHBvcnRzIG1hbnkgZGlmZmVyZW50IGxheW91dCBhbGdvcml0aG1zLCBkZXNjcmliZWQgaW4gZGV0YWlsIGluIHRoZSBbQ3l0b3NjYXBlIG1hbnVhbF0oaHR0cDovL21hbnVhbC5jeXRvc2NhcGUub3JnL2VuL3N0YWJsZS9OYXZpZ2F0aW9uX2FuZF9MYXlvdXQuaHRtbD9oaWdobGlnaHQ9bGF5b3V0I2F1dG9tYXRpYy1sYXlvdXQtYWxnb3JpdGhtcykuKgoKPGNlbnRlcj4KIVtdKC4vZGF0YS9pbWcvZmluYWwucG5nKQo8L2NlbnRlcj4KCkRpZ2dpbmcgaW50byB0aGUgYmlvbG9neSBvZiB0aGlzIG5ldHdvcmssIGl0IHR1cm5zIG91dCB0aGF0IEdBTDQgaXMgcmVwcmVzc2VkIGJ5IEdBTDgwLiBCb3RoIG5vZGVzIChHQUw0IGFuZCBHQUwxMSkgc2hvdyBmYWlybHkgc21hbGwgY2hhbmdlcyBpbiBleHByZXNzaW9uLCBhbmQgbmVpdGhlciBjaGFuZ2UgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudDogdGhleSBhcmUgcGFsZSBibHVlIHdpdGggdGhpbiBib3JkZXJzLiBUaGVzZSBzbGlnaHQgY2hhbmdlcyBpbiBleHByZXNzaW9uIHN1Z2dlc3QgdGhhdCB0aGUgY3JpdGljYWwgY2hhbmdlIGFmZmVjdGluZyB0aGUgcmVkIG5vZGVzIG1pZ2h0IGJlIHNvbWV3aGVyZSBlbHNlIGluIHRoZSBuZXR3b3JrLCBhbmQgbm90IGVpdGhlciBvZiB0aGVzZSBub2Rlcy4gR0FMNCBpbnRlcmFjdHMgd2l0aCBHQUw4MCwgd2hpY2ggc2hvd3MgYSBzaWduaWZpY2FudCBsZXZlbCBvZiByZXByZXNzaW9uOiBpdCBpcyBtZWRpdW0gYmx1ZSB3aXRoIGEgdGhpY2tlciBib3JkZXIuCgpOb3RlIHRoYXQgd2hpbGUgR0FMODAgc2hvd3MgZXZpZGVuY2Ugb2Ygc2lnbmlmaWNhbnQgcmVwcmVzc2lvbiAoYmx1ZSksIG1vc3Qgbm9kZXMgaW50ZXJhY3Rpbmcgd2l0aCBHQUw0IHNob3cgc2lnbmlmaWNhbnQgbGV2ZWxzIG9mIGluZHVjdGlvbiAocmVkKS4gR0FMMTEgaXMgYSBnZW5lcmFsIHRyYW5zY3JpcHRpb24gY28tZmFjdG9yIHdpdGggbWFueSBpbnRlcmFjdGlvbnMuCgpQdXR0aW5nIGFsbCBvZiB0aGlzIHRvZ2V0aGVyLCB3ZSBzZWUgdGhhdCB0aGUgKioqdHJhbnNjcmlwdGlvbmFsIGFjdGl2YXRpb24gYWN0aXZpdHkgb2YgR2FsNCBpcyByZXByZXNzZWQgYnkgR2FsODAqKiouIFNvLCByZXByZXNzaW9uIG9mIEdhbDgwIGluY3JlYXNlcyB0aGUgdHJhbnNjcmlwdGlvbmFsIGFjdGl2YXRpb24gYWN0aXZpdHkgb2YgR2FsNC4gRXZlbiB0aG91Z2ggdGhlIGV4cHJlc3Npb24gb2YgR2FsNCBpdHNlbGYgZGlkIG5vdCBzaWduaWZpY2FudGx5IGNoYW5nZSAobm8gcmVkIGJvcmRlciksICoqKnRoZSBHYWw0IHRyYW5zY3JpcHRzIHdlcmUgbXVjaCBtb3JlIGxpa2VseSB0byBiZSBhY3RpdmUgdHJhbnNjcmlwdGlvbiBmYWN0b3JzIHdoZW4gR2FsODAgd2FzIHJlcHJlc3NlZCoqKi4gVGhpcyBleHBsYWlucyB3aHkgdGhlcmUgaXMgc28gbXVjaCB1cC1yZWd1bGF0aW9uIGluIHRoZSB2aWNpbml0eSBvZiBHYWw0LgoKIyBTdW1tYXJ5CgpJbiBzdW1tYXJ5LCB3ZSBoYXZlOgoKLSBFeHBsb3JlZCBhIHllYXN0IGludGVyYWN0b21lIGZyb20gYSB0cmFuc2NyaXB0aW9uIGZhY3RvciBrbm9ja291dCBleHBlcmltZW50Ci0gQ3JlYXRlZCBhIHZpc3VhbCBzdHlsZSB1c2luZyBleHByZXNzaW9uIHZhbHVlIGFzIG5vZGUgY29sb3IgYW5kIHdpdGggYm9yZGVyIHdpZHRoIG1hcHBlZCB0byBzaWduaWZpY2FuY2UKLSBTZWxlY3RlZCBoaWdoIGV4cHJlc3NpbmcgZ2VuZXMgYW5kIHRoZWlyIG5laWdoYm9ycyBhbmQgY3JlYXRlZCBhIG5ldyBuZXR3b3JrCgpGaW5hbGx5LCB3ZSBjYW4gbm93IGV4cG9ydCB0aGlzIG5ldHdvcmsgYXMgYSBwdWJsaWNhdGlvbi1xdWFsaXR5IGltYWdlLi4uLgoKIyBTYXZpbmcgUmVzdWx0cwoKQ3l0b3NjYXBlIHByb3ZpZGVzIGEgbnVtYmVyIG9mIHdheXMgdG8gc2F2ZSByZXN1bHRzIGFuZCB2aXN1YWxpemF0aW9uczoKCi0gQXMgYSBzZXNzaW9uOgoKYGBge3J9CnNhdmVTZXNzaW9uKCdiYXNpYy1kYXRhLXZpc3VhbGl6YXRpb24uY3lzJykKYGBgCgotIEFzIGFuIGltYWdlOgoKYGBge3J9CmV4cG9ydEltYWdlKCdiYXNpYy1kYXRhLXZpc3VhbGl6YXRpb24nLCAnUERGJykKYGBgCgoqTm90ZTogUE5HLCBTVkcsIEpQRUcgYW5kIFBTIGFyZSBhbHNvIHN1cHBvcnRlZCoKCi0gVG8gYSBwdWJsaWMgcmVwb3NpdG9yeToKCmBgYApleHBvcnROZXR3b3JrVG9OREV4KCJ1c2VyIiwgInBhc3MiLCBUUlVFKSAjcmVxdWlyZXMgYSBmcmVlIE5ERXggYWNjb3VudApgYGAKCi0gQXMgYSBncmFwaCBmb3JtYXQgZmlsZSAoRm9ybWF0czogIkNYIEpTT04iLCAiQ3l0b3NjYXBlLmpzIEpTT04iLCAiR3JhcGhNTCIsICJYR01NTCIsICJTSUYiLC4uLik6CgpgYGB7cn0KZXhwb3J0TmV0d29yaygnYmFzaWMtZGF0YS12aXN1YWxpemF0aW9uJywgJ0NYJykKYGBgCgoqTm90ZTogY3lqcywgZ3JhcGhNTCwgeEdNTUwgYW5kIFNJRiBhcmUgYWxzbyBzdXBwb3J0ZWQqCg==