Estimated time: 15 Minutes

Motivation

Customizing plots can help us see patterns in the data or make the claim(s) based on the data represented clearer.

Instructions

  • Work independently in the main room, posting any questions that arise to slack.
  • Recommendations for writing your own code:
    • Read function documentation
    • Test out ideas - it’s okay to make mistakes and generate errors
    • Use a search engine to look up errors or recommended solutions using keywords
  • We’ll review possible solutions after time is up as a group.

Exercise

Try doing the following to the pca_plot, starting with the “most popular” request and moving on to other customizations if you have time:

  • Add a title and subtitle to the plot
  • Update the color palette to be color-blind friendly
  • Add labels to show which samples correspond to which points
  • Use shape instead of color to indicate groups on the PCA plot.
  • Challenge: Change the legend title to “Iron Status”.

Example

Here is a copy of the code we just tested together to 1) pull the underlying data from the PCA function and 2) change the theme of our PCA plot to black and white.

pcaData <- plotPCA(rld, intgroup=c("condition"), returnData=TRUE)
percentVar <- round(100 * attr(pcaData, "percentVar")) # store PC axes (% variance)

# create custom plot object
PCACustom <- ggplot(pcaData, aes(PC1, PC2, color=condition)) +
  geom_point(size=3) +
  coord_fixed() +
  theme_bw()

# add percentVar labels to *displayed plot*
PCACustom + 
  xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar[2],"% variance"))

# add percentVar labels to *stored plot object*
PCACustom2 <- PCACustom + 
  xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar[2],"% variance"))

Details & finding help

Add a title and subtitle to the ggplot plot

  • Hint: use the labs() function or search for examples
  • Remember that unless a change to a plot is assigned to an object, although the change will be displayed it will not stored for later reference or output to file
Possible solution

Example of possible :

?labs
PCACustom2 + 
  labs(title = "Iron Supplemented Mice", subtitle = "PCA of top 500 genes")

PCACustom3 <- PCACustom2 + 
  labs(title = "Iron Supplemented Mice", subtitle = "PCA of top 500 genes")


Add labels to show which samples correspond to which points

Possible solution

Example of possible solution:

?geom_label_repel

# display
PCACustom2 + 
  geom_text_repel(aes(label = name), 
                  point.padding = 0.5, 
                  box.padding = 0.5)

# save to new object
PCACustom4 <- PCACustom2 + 
  geom_text_repel(aes(label = name), 
                  point.padding = 0.5, 
                  box.padding = 0.5)


Make our color palette more color-blind friendly (with RColorBrewer)

Possible solution

Example of possible solution:

# look at pre-made color palettes from RColorBrewer
display.brewer.all(colorblindFriendly = TRUE)
# use RColorBrewer palette
PCACustom2 + 
  scale_colour_brewer(palette = "Set2")

# OR
# customize using manual color palette
# The R Cookbook palette with grey:
cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")

# To use for line and point colors, add manual color scaling with custom palette
PCACustom2 + 
  scale_colour_manual(values=cbPalette[2:3])

PCACustom5 <- PCACustom2 + 
  scale_colour_manual(values=cbPalette[2:3])


Use shape instead of color to indicate groups on the PCA plot.

Possible solution

Example of possible solution:

# generate new aesthetic mapping (with default shapes selected)
ggplot(pcaData, aes(PC1, PC2, shape=condition)) +
  geom_point(size=3) +
  coord_fixed() +
  theme_bw() + 
  xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar[2],"% variance"))


# generate new aesthetic mapping (with manually selected shapes)
ggplot(pcaData, aes(PC1, PC2, shape=condition)) +
  geom_point(size=3) +
  scale_shape_manual(values = c(1, 4)) +
  coord_fixed() +
  theme_bw() + 
  xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar[2],"% variance"))

# create custom plot object with manual shapes
PCACustom6 <- ggplot(pcaData, aes(PC1, PC2, shape=condition)) +
  geom_point(size=3) +
  scale_shape_manual(values = c(1, 4)) +
  coord_fixed() +
  theme_bw() + 
  xlab(paste0("PC1: ",percentVar[1],"% variance")) +
  ylab(paste0("PC2: ",percentVar[2],"% variance"))


Challenge: Change the legend title to “Iron Status”

  • Hint, you can do this with the labs() function too, using the corresponding aesthetic mapping (e.g. “color”).
  • This help thread with examples may also be useful
Possible solution

Example of possible solution:

#  customize label for colour mapping
PCACustom2 + 
  guides(colour=guide_legend(title="Iron supplementation status")) 

# alternatively specify label for aesthetic mapping
PCACustom2 + 
  labs(colour="Iron supplementation status")

# store custom plot as new object
PCACustom7 <- PCACustom2 + 
  labs(colour="Iron supplementation status")


Saving the result

If time permits, consider how you might save your favorite new PCA plot (with an informative file name). Hint: Consider how we saved our initial PCA plot in the previous module with ggsave().

Solution

Here are examples of some possible approaches:

pdf(file = file.path('outputs', 'figures', 'PCA_rlog_Titled.pdf'), width = 6, height = 6)
PCACustom3
dev.off()

ggsave(
    filename = file.path('outputs', 'figures', 'PCA_rlog_Titled.pdf'),
    plot = PCACustom3,
    width = 6, height = 6, units = 'in')


LS0tCnRpdGxlOiAiSW5kZXBlbmRlbnQgRXhlcmNpc2UgLSBDdXN0b21pemUgYSBQQ0EgcGxvdCIKYXV0aG9yOiAiVU0gQmlvaW5mb3JtYXRpY3MgQ29yZSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgICAgICAgaHRtbF9kb2N1bWVudDoKICAgICAgICAgICAgaW5jbHVkZXM6CiAgICAgICAgICAgICAgICBpbl9oZWFkZXI6IGhlYWRlci5odG1sCiAgICAgICAgICAgIHRoZW1lOiBwYXBlcgogICAgICAgICAgICB0b2M6IHRydWUKICAgICAgICAgICAgdG9jX2RlcHRoOiA0CiAgICAgICAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICAgICAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICAgICAgICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICAgICAgICAgIG1hcmtkb3duOiBHRk0KICAgICAgICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZQotLS0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmJvZHksIHRkIHsKICAgZm9udC1zaXplOiAxOHB4Owp9CmNvZGUucnsKICBmb250LXNpemU6IDEycHg7Cn0KcHJlIHsKICBmb250LXNpemU6IDEycHgKfQo8L3N0eWxlPgoKYGBge3IsIGluY2x1ZGUgPSBGQUxTRX0Kc291cmNlKCIuLi9iaW4vY2h1bmstb3B0aW9ucy5SIikKa25pdHJfZmlnX3BhdGgoIjA5YS0iKQpgYGAKCmBgYHtyIE1vZHVsZXMsIGV2YWw9VFJVRSwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShERVNlcTIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKbGlicmFyeShtYXRyaXhTdGF0cykKbGlicmFyeShnZ3JlcGVsKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKIyBsb2FkKCJyZGF0YS9SdW5uaW5nRGF0YS5SRGF0YSIpCmBgYAoKRXN0aW1hdGVkIHRpbWU6ICoqMTUgTWludXRlcyoqCgoKIyBNb3RpdmF0aW9uCgpDdXN0b21pemluZyBwbG90cyBjYW4gaGVscCB1cyBzZWUgcGF0dGVybnMgaW4gdGhlIGRhdGEgb3IgbWFrZSB0aGUgY2xhaW0ocykgYmFzZWQgb24gdGhlIGRhdGEgcmVwcmVzZW50ZWQgY2xlYXJlci4KCiMgSW5zdHJ1Y3Rpb25zCgotIFdvcmsgaW5kZXBlbmRlbnRseSBpbiB0aGUgbWFpbiByb29tLCBwb3N0aW5nIGFueSBxdWVzdGlvbnMgdGhhdCBhcmlzZSB0byBzbGFjay4KLSBSZWNvbW1lbmRhdGlvbnMgZm9yIHdyaXRpbmcgeW91ciBvd24gY29kZToKICAtIFJlYWQgZnVuY3Rpb24gZG9jdW1lbnRhdGlvbgogIC0gVGVzdCBvdXQgaWRlYXMgLSBpdCdzIG9rYXkgdG8gbWFrZSBtaXN0YWtlcyBhbmQgZ2VuZXJhdGUgZXJyb3JzCiAgLSBVc2UgYSBzZWFyY2ggZW5naW5lIHRvIGxvb2sgdXAgZXJyb3JzIG9yIHJlY29tbWVuZGVkIHNvbHV0aW9ucyB1c2luZyBrZXl3b3JkcwotIFdlJ2xsIHJldmlldyBwb3NzaWJsZSBzb2x1dGlvbnMgYWZ0ZXIgdGltZSBpcyB1cCBhcyBhIGdyb3VwLgoKIyBFeGVyY2lzZQoKVHJ5IGRvaW5nIHRoZSBmb2xsb3dpbmcgdG8gdGhlIGBwY2FfcGxvdGAsIHN0YXJ0aW5nIHdpdGggdGhlICJtb3N0IHBvcHVsYXIiIHJlcXVlc3QgYW5kIG1vdmluZyBvbiB0byBvdGhlciBjdXN0b21pemF0aW9ucyBpZiB5b3UgaGF2ZSB0aW1lOgoKPiAqIEFkZCBhIHRpdGxlIGFuZCBzdWJ0aXRsZSB0byB0aGUgcGxvdAo+ICogVXBkYXRlIHRoZSBjb2xvciBwYWxldHRlIHRvIGJlIGNvbG9yLWJsaW5kIGZyaWVuZGx5Cj4gKiBBZGQgbGFiZWxzIHRvIHNob3cgd2hpY2ggc2FtcGxlcyBjb3JyZXNwb25kIHRvIHdoaWNoIHBvaW50cwo+ICogVXNlIHNoYXBlIGluc3RlYWQgb2YgY29sb3IgdG8gaW5kaWNhdGUgZ3JvdXBzIG9uIHRoZSBQQ0EgcGxvdC4KPiAqIF9DaGFsbGVuZ2VfOiBDaGFuZ2UgdGhlIGxlZ2VuZCB0aXRsZSB0byAiSXJvbiBTdGF0dXMiLiAKCiMgRXhhbXBsZQoKSGVyZSBpcyBhIGNvcHkgb2YgdGhlIGNvZGUgd2UganVzdCB0ZXN0ZWQgdG9nZXRoZXIgdG8gMSkgcHVsbCB0aGUgdW5kZXJseWluZyBkYXRhIGZyb20gdGhlIFBDQSBmdW5jdGlvbiBhbmQgMikgY2hhbmdlIHRoZSB0aGVtZSBvZiBvdXIgUENBIHBsb3QgdG8gYmxhY2sgYW5kIHdoaXRlLgoKYGBge3IgdGVzdF9QQ0F9CnBjYURhdGEgPC0gcGxvdFBDQShybGQsIGludGdyb3VwPWMoImNvbmRpdGlvbiIpLCByZXR1cm5EYXRhPVRSVUUpCnBlcmNlbnRWYXIgPC0gcm91bmQoMTAwICogYXR0cihwY2FEYXRhLCAicGVyY2VudFZhciIpKSAjIHN0b3JlIFBDIGF4ZXMgKCUgdmFyaWFuY2UpCgojIGNyZWF0ZSBjdXN0b20gcGxvdCBvYmplY3QKUENBQ3VzdG9tIDwtIGdncGxvdChwY2FEYXRhLCBhZXMoUEMxLCBQQzIsIGNvbG9yPWNvbmRpdGlvbikpICsKICBnZW9tX3BvaW50KHNpemU9MykgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX2J3KCkKCiMgYWRkIHBlcmNlbnRWYXIgbGFiZWxzIHRvICpkaXNwbGF5ZWQgcGxvdCoKUENBQ3VzdG9tICsgCiAgeGxhYihwYXN0ZTAoIlBDMTogIixwZXJjZW50VmFyWzFdLCIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLHBlcmNlbnRWYXJbMl0sIiUgdmFyaWFuY2UiKSkKCiMgYWRkIHBlcmNlbnRWYXIgbGFiZWxzIHRvICpzdG9yZWQgcGxvdCBvYmplY3QqClBDQUN1c3RvbTIgPC0gUENBQ3VzdG9tICsgCiAgeGxhYihwYXN0ZTAoIlBDMTogIixwZXJjZW50VmFyWzFdLCIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLHBlcmNlbnRWYXJbMl0sIiUgdmFyaWFuY2UiKSkKYGBgCgojIERldGFpbHMgJiBmaW5kaW5nIGhlbHAKCiMjIEFkZCBhIHRpdGxlIGFuZCBzdWJ0aXRsZSB0byB0aGUgZ2dwbG90IHBsb3QKCiAgKiBIaW50OiB1c2UgdGhlIGBsYWJzKClgIGZ1bmN0aW9uIG9yIHNlYXJjaCBmb3IgW2V4YW1wbGVzXShodHRwczovL3d3dy5kYXRhbm92aWEuY29tL2VuL2Jsb2cvZ2dwbG90LXRpdGxlLXN1YnRpdGxlLWFuZC1jYXB0aW9uLykKICAqIFJlbWVtYmVyIHRoYXQgdW5sZXNzIGEgY2hhbmdlIHRvIGEgcGxvdCBpcyBfYXNzaWduZWQgdG8gYW4gb2JqZWN0XywgYWx0aG91Z2ggdGhlIGNoYW5nZSB3aWxsIGJlIGRpc3BsYXllZCBpdCB3aWxsIG5vdCBzdG9yZWQgZm9yIGxhdGVyIHJlZmVyZW5jZSBvciBvdXRwdXQgdG8gZmlsZQogIAogIAo8ZGV0YWlscz4KPHN1bW1hcnk+UG9zc2libGUgc29sdXRpb248L3N1bW1hcnk+CgpFeGFtcGxlIG9mIHBvc3NpYmxlIDoKCmBgYHtyLCBldmFsPSBGQUxTRX0KP2xhYnMKUENBQ3VzdG9tMiArIAogIGxhYnModGl0bGUgPSAiSXJvbiBTdXBwbGVtZW50ZWQgTWljZSIsIHN1YnRpdGxlID0gIlBDQSBvZiB0b3AgNTAwIGdlbmVzIikKClBDQUN1c3RvbTMgPC0gUENBQ3VzdG9tMiArIAogIGxhYnModGl0bGUgPSAiSXJvbiBTdXBwbGVtZW50ZWQgTWljZSIsIHN1YnRpdGxlID0gIlBDQSBvZiB0b3AgNTAwIGdlbmVzIikKYGBgCgo8L2RldGFpbHM+Cjxicj4KCgojIyBBZGQgbGFiZWxzIHRvIHNob3cgd2hpY2ggc2FtcGxlcyBjb3JyZXNwb25kIHRvIHdoaWNoIHBvaW50cwoKICAqIEhpbnQ6IHVzZSB0aGUgYGdlb21fbGFiZWwoKWAgb3IgYGdlb21fbGFiZWxfcmVwZWwoKWAgZnVuY3Rpb25zIGFuZCB0aGUgYG5hbWVgIGNvbHVtbiBpbiBvdXIgYHBjYURhdGFgIG9iamVjdAogICogU2VlIFtleGFtcGxlIGluIHRoaXMgc3VwcG9ydCBwb3N0XShodHRwczovL3N1cHBvcnQuYmlvY29uZHVjdG9yLm9yZy9wLzkwNzkxLykgYW5kL29yIFthcHBseSBtb3JlIGdlbmVyYWwgcmVjb21tZW5kYXRpb25zIGZyb20gdGhpcyBSIGdyYXBoIGdhbGxlcnldKGh0dHBzOi8vci1ncmFwaC1nYWxsZXJ5LmNvbS8yNzUtYWRkLXRleHQtbGFiZWxzLXdpdGgtZ2dwbG90Mi5odG1sKQoKPGRldGFpbHM+CjxzdW1tYXJ5PlBvc3NpYmxlIHNvbHV0aW9uPC9zdW1tYXJ5PgoKRXhhbXBsZSBvZiBwb3NzaWJsZSBzb2x1dGlvbjoKCmBgYHtyLCBldmFsPSBGQUxTRX0KP2dlb21fbGFiZWxfcmVwZWwKCiMgZGlzcGxheQpQQ0FDdXN0b20yICsgCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG5hbWUpLCAKICAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IDAuNSwgCiAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gMC41KQoKIyBzYXZlIHRvIG5ldyBvYmplY3QKUENBQ3VzdG9tNCA8LSBQQ0FDdXN0b20yICsgCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG5hbWUpLCAKICAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IDAuNSwgCiAgICAgICAgICAgICAgICAgIGJveC5wYWRkaW5nID0gMC41KQogIApgYGAKCjwvZGV0YWlscz4KPGJyPgoKIyMgTWFrZSBvdXIgY29sb3IgcGFsZXR0ZSBtb3JlIGNvbG9yLWJsaW5kIGZyaWVuZGx5ICh3aXRoIGBSQ29sb3JCcmV3ZXJgKQogICogVXNlIGVpdGhlciB0aGUgYHNjYWxlX2NvbG91cl9icmV3ZXJgIGZ1bmN0aW9uIHRvIFtjaGFuZ2UgdGhlIGNvbG9yIG1hcHBpbmdzIGluIG91ciBwbG90XShodHRwczovL3N0YXRpc3RpY3NnbG9iZS5jb20vc2NhbGUtY29sb3VyLWZpbGwtYnJld2VyLXJjb2xvcmJyZXdlci1wYWNrYWdlLXIpIE9SIGBzY2FsZV9jb2xvdXJfbWFudWFsYCBmdW5jdGlvbiB0byBbY29tcGxldGVseSBjdXN0b21pemUgY29sb3IgY2hvaWNlc10oaHR0cDovL3d3dy5jb29rYm9vay1yLmNvbS9HcmFwaHMvQ29sb3JzXyhnZ3Bsb3QyKS8jYS1jb2xvcmJsaW5kLWZyaWVuZGx5LXBhbGV0dGUpCiAgKiBQcmUtZGVzaWduZWQgW2NvbG9yLWJsaW5kIGZyaWVuZGx5IHBhbGV0dGVzIGFyZSBhdmFpbGFibGVdKGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vR3JhcGhzL0NvbG9yc18oZ2dwbG90MikvI2EtY29sb3JibGluZC1mcmllbmRseS1wYWxldHRlKQogICAqIFdoZW4gY29uc2lkZXJpbmcgY29sb3IgY2hvaWNlcywgYmUgYXdhcmUgb2YgdGhlIFtwcmV2YWxlbmNlIGFuZCB0eXBlcyBvZiBjb2xvci1ibGluZG5lc3NdKGh0dHBzOi8vbWVkaXVtLmNvbS92ZXJzaW9uLTEvc2ltdWxhdGluZy12aXN1YWxpc2F0aW9ucy1pbi1yLWZvci1jb2xvdXItYmxpbmRuZXNzLTJmYWRkZGU2MzY5NSkgYW5kIGhvdyB0byBjaG9vc2UgbW9yZSBbZWFzaWx5IGRpc3Rpbmd1aXNoYWJsZSBjb2xvcnNdKGh0dHA6Ly9iY29ubmVsbHkubmV0L3Bvc3RzL2NyZWF0aW5nX2NvbG9yYmxpbmQtZnJpZW5kbHlfZmlndXJlcy8pCiAgKiBGb3IgcHVibGljYXRpb24gb3IgcHJlc2VudGF0aW9ucywgd2UgY2FuIGFsc28gY2hlY2sgdGhlIGZpbmFsIGZpZ3VyZXMgZm9yIHN1ZmZpY2llbnQgY29udHJhc3RzIHdpdGggYSBbY29sb3ItYmxpbmRuZXNzIHNpbXVsYXRvciB0b29sXShodHRwczovL3d3dy5jb2xvci1ibGluZG5lc3MuY29tL2NvYmxpcy1jb2xvci1ibGluZG5lc3Mtc2ltdWxhdG9yLykuIAogIAo8ZGV0YWlscz4KPHN1bW1hcnk+UG9zc2libGUgc29sdXRpb248L3N1bW1hcnk+CgpFeGFtcGxlIG9mIHBvc3NpYmxlIHNvbHV0aW9uOgoKYGBge3IsIGV2YWw9IEZBTFNFfQojIGxvb2sgYXQgcHJlLW1hZGUgY29sb3IgcGFsZXR0ZXMgZnJvbSBSQ29sb3JCcmV3ZXIKZGlzcGxheS5icmV3ZXIuYWxsKGNvbG9yYmxpbmRGcmllbmRseSA9IFRSVUUpCiMgdXNlIFJDb2xvckJyZXdlciBwYWxldHRlClBDQUN1c3RvbTIgKyAKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpCgojIE9SCiMgY3VzdG9taXplIHVzaW5nIG1hbnVhbCBjb2xvciBwYWxldHRlCiMgVGhlIFIgQ29va2Jvb2sgcGFsZXR0ZSB3aXRoIGdyZXk6CmNiUGFsZXR0ZSA8LSBjKCIjOTk5OTk5IiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwgIiNGMEU0NDIiLCAiIzAwNzJCMiIsICIjRDU1RTAwIiwgIiNDQzc5QTciKQoKIyBUbyB1c2UgZm9yIGxpbmUgYW5kIHBvaW50IGNvbG9ycywgYWRkIG1hbnVhbCBjb2xvciBzY2FsaW5nIHdpdGggY3VzdG9tIHBhbGV0dGUKUENBQ3VzdG9tMiArIAogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPWNiUGFsZXR0ZVsyOjNdKQoKUENBQ3VzdG9tNSA8LSBQQ0FDdXN0b20yICsgCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9Y2JQYWxldHRlWzI6M10pCiAgCmBgYAoKPC9kZXRhaWxzPgo8YnI+CiAgCiMjIFVzZSBzaGFwZSBpbnN0ZWFkIG9mIGNvbG9yIHRvIGluZGljYXRlIGdyb3VwcyBvbiB0aGUgUENBIHBsb3QuIAoKICAqIEhpbnQ6IHNpbmNlIGNvbG9yIGFuZCBzaGFwZSBhcmUgYm90aCBtYXBwaW5nIGFzcGVjdHMsIHNvIHdlJ2xsIG5lZWQgdG8gcmUtc3BlY2lmeSBzaGFwZSBpbnN0ZWFkIG9mIGNvbG9yIGluc3RlYWQgb2YgYWRkaW5nIGFuIGFkZGl0aW9uYWwgbGF5ZXJzIGxpa2UgdGhlIG90aGVyIHByb21wdHMgCiAgKiBUaGUgW2RvY3VtZW50YXRpb24gcGFnZSBmb3IgYGdlb21fcG9pbnRgXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9wb2ludC5odG1sKSBhbmQgW1IgZ3JhcGhpY3MgY29va2Jvb2tzXShodHRwczovL3ItZ3JhcGhpY3Mub3JnL3JlY2lwZS1zY2F0dGVyLXNoYXBlcykgaW5jbHVkZXMgc29tZSBleGFtcGxlcyBvZiBjaGFuZ2luZyB0aGUgc2hhcGVzIG9mIHRoZSBwbG90dGVkIHBvaW50cwogICogW1RoZXNlIFIgZ3JhcGggZ2FsbGVyeSBleGFtcGxlc10oaHR0cHM6Ly9yLWdyYXBoLWdhbGxlcnkuY29tLzI3NC1tYXAtYS12YXJpYWJsZS10by1nZ3Bsb3QyLXNjYXR0ZXJwbG90Lmh0bWwpIGNvdWxkIGFsc28gYmUgaGVscGZ1bAoKPGRldGFpbHM+CjxzdW1tYXJ5PlBvc3NpYmxlIHNvbHV0aW9uPC9zdW1tYXJ5PgoKRXhhbXBsZSBvZiBwb3NzaWJsZSBzb2x1dGlvbjoKCmBgYHtyLCBldmFsPSBGQUxTRX0KIyBnZW5lcmF0ZSBuZXcgYWVzdGhldGljIG1hcHBpbmcgKHdpdGggZGVmYXVsdCBzaGFwZXMgc2VsZWN0ZWQpCmdncGxvdChwY2FEYXRhLCBhZXMoUEMxLCBQQzIsIHNoYXBlPWNvbmRpdGlvbikpICsKICBnZW9tX3BvaW50KHNpemU9MykgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX2J3KCkgKyAKICB4bGFiKHBhc3RlMCgiUEMxOiAiLHBlcmNlbnRWYXJbMV0sIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIscGVyY2VudFZhclsyXSwiJSB2YXJpYW5jZSIpKQoKCiMgZ2VuZXJhdGUgbmV3IGFlc3RoZXRpYyBtYXBwaW5nICh3aXRoIG1hbnVhbGx5IHNlbGVjdGVkIHNoYXBlcykKZ2dwbG90KHBjYURhdGEsIGFlcyhQQzEsIFBDMiwgc2hhcGU9Y29uZGl0aW9uKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0zKSArCiAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcyA9IGMoMSwgNCkpICsKICBjb29yZF9maXhlZCgpICsKICB0aGVtZV9idygpICsgCiAgeGxhYihwYXN0ZTAoIlBDMTogIixwZXJjZW50VmFyWzFdLCIlIHZhcmlhbmNlIikpICsKICB5bGFiKHBhc3RlMCgiUEMyOiAiLHBlcmNlbnRWYXJbMl0sIiUgdmFyaWFuY2UiKSkKCiMgY3JlYXRlIGN1c3RvbSBwbG90IG9iamVjdCB3aXRoIG1hbnVhbCBzaGFwZXMKUENBQ3VzdG9tNiA8LSBnZ3Bsb3QocGNhRGF0YSwgYWVzKFBDMSwgUEMyLCBzaGFwZT1jb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplPTMpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxLCA0KSkgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX2J3KCkgKyAKICB4bGFiKHBhc3RlMCgiUEMxOiAiLHBlcmNlbnRWYXJbMV0sIiUgdmFyaWFuY2UiKSkgKwogIHlsYWIocGFzdGUwKCJQQzI6ICIscGVyY2VudFZhclsyXSwiJSB2YXJpYW5jZSIpKQoKYGBgCjwvZGV0YWlscz4KPGJyPgoKIyMgX0NoYWxsZW5nZV86IENoYW5nZSB0aGUgbGVnZW5kIHRpdGxlIHRvICJJcm9uIFN0YXR1cyIKCiAgKiBIaW50LCB5b3UgY2FuIGRvIHRoaXMgd2l0aCB0aGUgYGxhYnMoKWAgZnVuY3Rpb24gdG9vLCB1c2luZyB0aGUgY29ycmVzcG9uZGluZyBhZXN0aGV0aWMgbWFwcGluZyAoZS5nLiAiY29sb3IiKS4KICAqIFtUaGlzIGhlbHAgdGhyZWFkIHdpdGggZXhhbXBsZXNdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzE0NjIyNDIxL2hvdy10by1jaGFuZ2UtbGVnZW5kLXRpdGxlLWluLWdncGxvdCkgbWF5IGFsc28gYmUgdXNlZnVsCgo8ZGV0YWlscz4KPHN1bW1hcnk+UG9zc2libGUgc29sdXRpb248L3N1bW1hcnk+CgpFeGFtcGxlIG9mIHBvc3NpYmxlIHNvbHV0aW9uOgoKYGBge3IsIGV2YWw9IEZBTFNFfQojICBjdXN0b21pemUgbGFiZWwgZm9yIGNvbG91ciBtYXBwaW5nClBDQUN1c3RvbTIgKyAKICBndWlkZXMoY29sb3VyPWd1aWRlX2xlZ2VuZCh0aXRsZT0iSXJvbiBzdXBwbGVtZW50YXRpb24gc3RhdHVzIikpIAoKIyBhbHRlcm5hdGl2ZWx5IHNwZWNpZnkgbGFiZWwgZm9yIGFlc3RoZXRpYyBtYXBwaW5nClBDQUN1c3RvbTIgKyAKICBsYWJzKGNvbG91cj0iSXJvbiBzdXBwbGVtZW50YXRpb24gc3RhdHVzIikKCiMgc3RvcmUgY3VzdG9tIHBsb3QgYXMgbmV3IG9iamVjdApQQ0FDdXN0b203IDwtIFBDQUN1c3RvbTIgKyAKICBsYWJzKGNvbG91cj0iSXJvbiBzdXBwbGVtZW50YXRpb24gc3RhdHVzIikKICAKYGBgCjwvZGV0YWlscz4KPGJyPgoKIyBTYXZpbmcgdGhlIHJlc3VsdAoKSWYgdGltZSBwZXJtaXRzLCBjb25zaWRlciBob3cgeW91IG1pZ2h0IHNhdmUgeW91ciBmYXZvcml0ZSBuZXcgUENBIHBsb3QgKHdpdGggYW4gaW5mb3JtYXRpdmUgZmlsZSBuYW1lKS4gSGludDogQ29uc2lkZXIgaG93IHdlIHNhdmVkIG91ciBpbml0aWFsIFBDQSBwbG90IGluIHRoZSBwcmV2aW91cyBtb2R1bGUgd2l0aCBgZ2dzYXZlKClgLgoKPGRldGFpbHM+CjxzdW1tYXJ5PlNvbHV0aW9uPC9zdW1tYXJ5PgoKSGVyZSBhcmUgZXhhbXBsZXMgb2Ygc29tZSBwb3NzaWJsZSBhcHByb2FjaGVzOgoKYGBge3Igc2F2ZV9jdXN0b21fcGNhLCBldmFsID0gRkFMU0V9CnBkZihmaWxlID0gZmlsZS5wYXRoKCdvdXRwdXRzJywgJ2ZpZ3VyZXMnLCAnUENBX3Jsb2dfVGl0bGVkLnBkZicpLCB3aWR0aCA9IDYsIGhlaWdodCA9IDYpClBDQUN1c3RvbTMKZGV2Lm9mZigpCgpnZ3NhdmUoCiAgICBmaWxlbmFtZSA9IGZpbGUucGF0aCgnb3V0cHV0cycsICdmaWd1cmVzJywgJ1BDQV9ybG9nX1RpdGxlZC5wZGYnKSwKICAgIHBsb3QgPSBQQ0FDdXN0b20zLAogICAgd2lkdGggPSA2LCBoZWlnaHQgPSA2LCB1bml0cyA9ICdpbicpCmBgYAoKPC9kZXRhaWxzPgo8YnI+CgoKYGBge3IgV3JpdGVPdXQuUkRhdGEsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNIaWRkZW4gY29kZSBibG9jayB0byB3cml0ZSBvdXQgZGF0YSBmb3Iga25pdHRpbmcKIyBzYXZlLmltYWdlKGZpbGUgPSAicmRhdGEvUnVubmluZ0RhdGEuUkRhdGEiKQpgYGAK