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:
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:
saveSession('basic-data-visualization.cys')
exportImage('basic-data-visualization', 'PDF')
Note: PNG, SVG, JPEG and PS are also supported
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==