About R

If you haven’t learned the basics of R prior to attending this course, you should check out our R crash course for an overview of R’s syntax. It’s also a great refresher if you feel it has been a while since you last worked with R.

About the practicals for this workshop

  • The traditional way to enter R commands is via opening a Terminal or, or using the console in RStudio (bottom-left panel when RStudio opens for first time).
  • For this course we will instead be using a relatively new feature called R Notebooks.
  • An R notebook mixes plain text written in markdown with “chunks” of R code.

Markdown is a very simple way of writing a template to produce a pdf, HTML or word document. For example, the compiled version of this document is available online and is more convenient to browse here.

  • “Chunks” of R code can be added using the insert option from the tool bar, or the CTRL + ALT + I shortcut
  • Each line of R can be executed by clicking on the line and pressing CTRL and ENTER
  • Or you can execute the whole chunk by pressing CTRL + SHIFT + ENTER
  • Or you can press the green triangle on the right-hand side to run everything in the chunk
  • The code might have different options which dictate how the output is displayed in the compiled document (e.g. HTML)
    • e.g. you might see EVAL = FALSE or echo = FALSE
    • you don’t have to worry about this if stepping through the markdown interactively
print("Hello World")
[1] "Hello World"

When viewing the R notebooks directly, not the compiled documents, sections may have additional characters so as to format them nicely when compiled. For example:

This will be displayed in italic

This will be displayed in bold

  • this
  • is
  • a
  • list
    • this is a sub-list

You can also add hyperlinks, images and tables.

Lastly, you can even embed chunks of code written in other programming languages.

More help is available through RStudio Help -> Markdown Quick Reference or you can view a cheat sheet here.

To create markdown files for your own analysis; File -> New File -> R Markdown…

About the Bioconductor project

Established in 2001, Bioconductor provided a convenient method to distribute tools for the analysis and comprehension of high-throughput genomic data in R. Initially focused on microarrays, Bioconductor now has packages (read: software) to process data obtained from most modern data sources.

  • R is rarely used for the primary processing of modern data
    • R is far slower than many other programming languages due to it being an interpreted language (Interpreted vs Compiled)
    • R is extensively-used for visualisation, interpretation and inference once data has been parsed into a more manageable form, e.g., a csv.

On the Bioconductor website, you will find

For this session, we will introduce the Bioconductor project as a means of analysing high-throughput data

Installing a package

All Bioconductor software packages are listed under

  • bioconductor.org -> Install -> Packages -> Analysis software packages
    • Many thousands of packages have been added over the years, so I would suggest just googling “bioconductor [package_name]”
    • e.g. edgeR landing page
  • installation instructions are given, which involves running the biocLite command
    • this will install and update any additional dependencies
  • you only need to run this procedure once for each version of R
## You don't need to run this, edgeR should already be installed for the course
source("http://www.bioconductor.org/biocLite.R")
biocLite("edgeR")

Once installed, a Bioconductor package can be loaded in the usual way with the library function. All packages are required to have a vignette which gives detailed instructions on how to use the package and the workflow of commands. Some packages such as edgeR have very comprehensive user guides with lots of use-cases.

library(edgeR)
vignette("edgeR")
edgeRUsersGuide()

Package documentation can also be accessed via the Help tab in RStudio, which can also be invoked in the console using “?”

?edgeR

Structures for data analysis

Complex data structures are used in Bioconductor to represent high-throughput data, but we often have simple functions that we can use to access the data. We will use some example data available through Bioconductor to demonstrate how high-throughput data can be represented, and also to review some basic concepts in data manipulation in R.

  • the data are from a microarray experiment. We will be concentrating on more modern technologies in this class, but most of the R techniques required will be similar
  • experimental data packages are available through Bioconductor, and can be installed in the way we just described
    • the package should already be installed on your computer, so you won’t need to run this.
## No need to run this - for reference only!
biocLite("breastCancerVDX")

To make the dataset accessible in R, we first need to load the package. If we navigate to the documentation for breastCancerVDX in RStudio, we find that it provides an object called vdx which we load into R’s memory using the data function.

library(breastCancerVDX)
data(vdx)

The object vdx is a representation of breast cancer dataset that has been converted for use with standard Bioconductor tools. The package authors don’t envisage that we will want to view the entire dataset at once, so have provided a number of ways to interact with the data

  • typing the name of the object provides a summary, e.g.,
    • how many genes in the dataset
    • how many samples
vdx
ExpressionSet (storageMode: lockedEnvironment)
assayData: 22283 features, 344 samples 
  element names: exprs 
protocolData: none
phenoData
  sampleNames: VDX_3 VDX_5 ... VDX_2038 (344 total)
  varLabels: samplename dataset ... e.os (21 total)
  varMetadata: labelDescription
featureData
  featureNames: 1007_s_at 1053_at ... AFFX-TrpnX-M_at (22283 total)
  fvarLabels: probe Gene.title ... GO.Component.1 (22 total)
  fvarMetadata: labelDescription
experimentData: use 'experimentData(object)'
  pubMedIds: 17420468 
Annotation: hgu133a 

Accessing expression values

The expression values can be obtained by the exprs function:-

  • remember, <- is used for assignment to create a new variable
  • the data are stored in a matrix in R
    • it is a good idea to check the dimensions using dim, ncol, nrow etc.
eValues <- exprs(vdx) # also found at vdx@assayData$exprs
class(eValues)
[1] "matrix"
dim(eValues)
[1] 22283   344
ncol(eValues)
[1] 344
nrow(eValues)
[1] 22283
  • the row names are the manufacturer-assigned ID for a particular probe
  • the column names are the identifiers for each patient in the study
  • each entry is a normalised log\(_2\) intensity value for a particular gene in a given sample
    • we won’t talk about normalisation here, but basically the data has been transformed so that samples and/or genes can be compared
  • subsetting a matrix is done using the [row, column] notation
    • the function c is used to make a one-dimensional vector
    • the shortcut : can used to stand for a sequence of consecutive numbers
eValues[c(1,2,3),c(1,2,3,4)]
              VDX_3     VDX_5     VDX_6     VDX_7
1007_s_at 11.965135 11.798593 11.777625 11.538577
1053_at    7.895424  7.885696  7.949535  7.481396
117_at     8.259272  7.052025  8.225930  8.382408
eValues[1:3,1:4]
              VDX_3     VDX_5     VDX_6     VDX_7
1007_s_at 11.965135 11.798593 11.777625 11.538577
1053_at    7.895424  7.885696  7.949535  7.481396
117_at     8.259272  7.052025  8.225930  8.382408
  • subsetting can be chained together
  • we can also omit certain rows or columns from the output by prefixing the indices with a -
eValues[1:3,1:4][,2:3]
              VDX_5     VDX_6
1007_s_at 11.798593 11.777625
1053_at    7.885696  7.949535
117_at     7.052025  8.225930
eValues[1:3,1:4][,-(2:3)]
              VDX_3     VDX_7
1007_s_at 11.965135 11.538577
1053_at    7.895424  7.481396
117_at     8.259272  8.382408

Simple visualisations

The most basic plotting function in R is plot

  • using the plot function with a vector will plot the values of that vector against the index
    • what do you think is displayed in the plot below?
plot(eValues[1,])

  • one possible use is to compare the values in a vector with respect to a given factor
  • but we don’t know the clinical variables in our dataset yet (to come later)
  • a boxplot can also accept a matrix or data frame as an argument
  • what do you think the following plot shows?
boxplot(eValues,outline=FALSE)

Accessing patient data

The metadata, or phenotypic data, for the samples is retrieved using the pData function.

metadata <- pData(vdx) #vdx@phenoData@data
head(metadata)
      samplename dataset series id        filename size age er grade pgr her2 brca.mutation e.dmfs t.dmfs node t.rfs e.rfs treatment tissue t.os e.os
VDX_3      VDX_3     VDX    VDX  3 GSM36793.CEL.gz   NA  36  0    NA  NA   NA            NA      0   3072    0    NA    NA         0      1   NA   NA
VDX_5      VDX_5     VDX    VDX  5 GSM36796.CEL.gz   NA  47  1     3  NA   NA            NA      0   3589    0    NA    NA         0      1   NA   NA
VDX_6      VDX_6     VDX    VDX  6 GSM36797.CEL.gz   NA  44  0     3  NA   NA            NA      1    274    0    NA    NA         0      1   NA   NA
VDX_7      VDX_7     VDX    VDX  7 GSM36798.CEL.gz   NA  41  0     3  NA   NA            NA      0   3224    0    NA    NA         0      1   NA   NA
VDX_8      VDX_8     VDX    VDX  8 GSM36800.CEL.gz   NA  70  0    NA  NA   NA            NA      1   1125    0    NA    NA         0      1   NA   NA
VDX_9      VDX_9     VDX    VDX  9 GSM36801.CEL.gz   NA  62  1     3  NA   NA            NA      0   3802    0    NA    NA         0      1   NA   NA
  • head prints only the first few rows/values.
  • individual columns can be accessed using the $ notation.
  • columns are returned as a vector, which can be fed into other standard plotting and analysis functions.
  • auto-complete is available in RStudio; once you type the $, it should give you a list of possible options.
head(metadata$samplename)
[1] "VDX_3" "VDX_5" "VDX_6" "VDX_7" "VDX_8" "VDX_9"



Exercise

  • what type of R object is used to store the metadata?
  • why is this different to the object used for the expression values?
  • use the square bracket notation [] to print
    • the first 10 rows of the metadata object, first five columns
    • last 10 rows of the metadata object, columns 7 to 9
  • visualise the distribution of the patient ages using a histogram
  • calculate the average age of patients in the study with the mean function
    • what do you notice about the result?
    • can you change the arguments to mean to get a more meaningful result



#FILL IN SOLUTIONS HERE

So far we have been able to print out a subset of our data by specifying a set of numeric indices (e.g. first 10 rows etc). Lets say we’re interested in high-grade tumours, in which case we might not know in advance which rows these correspond to

  • == >, <, != can used to make a logical comparison
  • result is a TRUE or FALSE indicating whether each entry satisfies the test condition, or not.
    • however, if a particular entry in the vector is NA the resulting logical vector will have NA at the same positions
  • Multiple comparisons can be combined with the logic operators and (&) and or (|)
    • There’s also not (!)
table(metadata$grade == 3)

FALSE  TRUE 
   49   148 
table(metadata$grade == 3,useNA="ifany")

FALSE  TRUE  <NA> 
   49   148   147 

Such a logical vector can then be used for subsetting

  • which can be used to make sure there are no NA values in the logical vectors
    • it gives the numeric indices that correspond to TRUE
  • here, we don’t specify any column indices inside the []
    • R will print all the columns
    • however, don’t forget the ,
    • if you do, R will still try and do something. It almost certainly be what you expected
metadata[which(metadata$grade == 3),]
        samplename dataset series  id        filename size age er grade pgr her2 brca.mutation e.dmfs t.dmfs node t.rfs e.rfs treatment tissue t.os e.os
VDX_5        VDX_5     VDX    VDX   5 GSM36796.CEL.gz   NA  47  1     3  NA   NA            NA      0   3589    0    NA    NA         0      1   NA   NA
VDX_6        VDX_6     VDX    VDX   6 GSM36797.CEL.gz   NA  44  0     3  NA   NA            NA      1    274    0    NA    NA         0      1   NA   NA
VDX_7        VDX_7     VDX    VDX   7 GSM36798.CEL.gz   NA  41  0     3  NA   NA            NA      0   3224    0    NA    NA         0      1   NA   NA
VDX_9        VDX_9     VDX    VDX   9 GSM36801.CEL.gz   NA  62  1     3  NA   NA            NA      0   3802    0    NA    NA         0      1   NA   NA
VDX_11      VDX_11     VDX    VDX  11 GSM36834.CEL.gz   NA  69  1     3  NA   NA            NA      0   3315    0    NA    NA         0      1   NA   NA
VDX_14      VDX_14     VDX    VDX  14 GSM36835.CEL.gz   NA  68  0     3  NA   NA            NA      1    426    0    NA    NA         0      1   NA   NA
VDX_15      VDX_15     VDX    VDX  15 GSM36836.CEL.gz   NA  44  1     3  NA   NA            NA      0   3011    0    NA    NA         0      1   NA   NA
VDX_17      VDX_17     VDX    VDX  17 GSM36837.CEL.gz   NA  51  1     3  NA   NA            NA      0   4167    0    NA    NA         0      1   NA   NA
VDX_18      VDX_18     VDX    VDX  18 GSM36838.CEL.gz   NA  32  1     3  NA   NA            NA      1   1034    0    NA    NA         0      1   NA   NA
VDX_20      VDX_20     VDX    VDX  20 GSM36855.CEL.gz   NA  34  0     3  NA   NA            NA      0   3893    0    NA    NA         0      1   NA   NA
VDX_22      VDX_22     VDX    VDX  22 GSM36859.CEL.gz   NA  32  1     3  NA   NA            NA      0   3954    0    NA    NA         0      1   NA   NA
VDX_27      VDX_27     VDX    VDX  27 GSM36860.CEL.gz   NA  47  1     3  NA   NA            NA      1    913    0    NA    NA         0      1   NA   NA
VDX_29      VDX_29     VDX    VDX  29 GSM36862.CEL.gz   NA  42  0     3  NA   NA            NA      1    760    0    NA    NA         0      1   NA   NA
VDX_31      VDX_31     VDX    VDX  31 GSM36870.CEL.gz   NA  49  1     3  NA   NA            NA      1    913    0    NA    NA         0      1   NA   NA
VDX_32      VDX_32     VDX    VDX  32 GSM36871.CEL.gz   NA  44  1     3  NA   NA            NA      0   2555    0    NA    NA         0      1   NA   NA
VDX_37      VDX_37     VDX    VDX  37 GSM36875.CEL.gz   NA  62  0     3  NA   NA            NA      1    213    0    NA    NA         0      1   NA   NA
VDX_39      VDX_39     VDX    VDX  39 GSM36877.CEL.gz   NA  38  1     3  NA   NA            NA      1   1308    0    NA    NA         0      1   NA   NA
VDX_41      VDX_41     VDX    VDX  41 GSM36897.CEL.gz   NA  46  1     3  NA   NA            NA      1    760    0    NA    NA         0      1   NA   NA
VDX_46      VDX_46     VDX    VDX  46 GSM36900.CEL.gz   NA  60  1     3  NA   NA            NA      0   3315    0    NA    NA         0      1   NA   NA
VDX_48      VDX_48     VDX    VDX  48 GSM36901.CEL.gz   NA  29  1     3  NA   NA            NA      0   3072    0    NA    NA         0      1   NA   NA
VDX_49      VDX_49     VDX    VDX  49 GSM36902.CEL.gz   NA  32  1     3  NA   NA            NA      1    852    0    NA    NA         0      1   NA   NA
VDX_55      VDX_55     VDX    VDX  55 GSM36918.CEL.gz   NA  54  0     3  NA   NA            NA      1    335    0    NA    NA         0      1   NA   NA
VDX_57      VDX_57     VDX    VDX  57 GSM36920.CEL.gz   NA  53  1     3  NA   NA            NA      1    608    0    NA    NA         0      1   NA   NA
VDX_61      VDX_61     VDX    VDX  61 GSM36937.CEL.gz   NA  27  0     3  NA   NA            NA      1    335    0    NA    NA         0      1   NA   NA
VDX_64      VDX_64     VDX    VDX  64 GSM36940.CEL.gz   NA  47  0     3  NA   NA            NA      0   4076    0    NA    NA         0      1   NA   NA
VDX_65      VDX_65     VDX    VDX  65 GSM36941.CEL.gz   NA  58  0     3  NA   NA            NA      1    274    0    NA    NA         0      1   NA   NA
VDX_67      VDX_67     VDX    VDX  67 GSM36943.CEL.gz   NA  32  1     3  NA   NA            NA      1    578    0    NA    NA         0      1   NA   NA
VDX_68      VDX_68     VDX    VDX  68 GSM36944.CEL.gz   NA  49  1     3  NA   NA            NA      0   3407    0    NA    NA         0      1   NA   NA
VDX_72      VDX_72     VDX    VDX  72 GSM36965.CEL.gz   NA  40  1     3  NA   NA            NA      0   4076    0    NA    NA         0      1   NA   NA
VDX_74      VDX_74     VDX    VDX  74 GSM36966.CEL.gz   NA  70  0     3  NA   NA            NA      0   2738    0    NA    NA         0      1   NA   NA
VDX_79      VDX_79     VDX    VDX  79 GSM36969.CEL.gz   NA  41  0     3  NA   NA            NA      1    973    0    NA    NA         0      1   NA   NA
VDX_80      VDX_80     VDX    VDX  80 GSM36987.CEL.gz   NA  52  1     3  NA   NA            NA      0   2950    0    NA    NA         0      1   NA   NA
VDX_84      VDX_84     VDX    VDX  84 GSM36991.CEL.gz   NA  66  0     3  NA   NA            NA      0   3468    0    NA    NA         0      1   NA   NA
VDX_86      VDX_86     VDX    VDX  86 GSM36992.CEL.gz   NA  55  1     3  NA   NA            NA      0   3163    0    NA    NA         0      1   NA   NA
VDX_88      VDX_88     VDX    VDX  88 GSM36993.CEL.gz   NA  55  1     3  NA   NA            NA      0   2981    0    NA    NA         0      1   NA   NA
VDX_90      VDX_90     VDX    VDX  90 GSM37017.CEL.gz   NA  41  0     3  NA   NA            NA      0   3281    0    NA    NA         0      1   NA   NA
VDX_92      VDX_92     VDX    VDX  92 GSM37019.CEL.gz   NA  51  1     3  NA   NA            NA      0   4441    0    NA    NA         0      1   NA   NA
VDX_93      VDX_93     VDX    VDX  93 GSM37020.CEL.gz   NA  37  0     3  NA   NA            NA      1   1460    0    NA    NA         0      1   NA   NA
VDX_98      VDX_98     VDX    VDX  98 GSM37023.CEL.gz   NA  53  0     3  NA   NA            NA      1    426    0    NA    NA         0      1   NA   NA
VDX_99      VDX_99     VDX    VDX  99 GSM37025.CEL.gz   NA  80  1     3  NA   NA            NA      0   3255    0    NA    NA         0      1   NA   NA
VDX_103    VDX_103     VDX    VDX 103 GSM36880.CEL.gz   NA  41  1     3  NA   NA            NA      0   2950    0    NA    NA         0      1   NA   NA
VDX_105    VDX_105     VDX    VDX 105 GSM36882.CEL.gz   NA  50  1     3  NA   NA            NA      0   3011    0    NA    NA         0      1   NA   NA
VDX_107    VDX_107     VDX    VDX 107 GSM36886.CEL.gz   NA  53  0     3  NA   NA            NA      0   2859    0    NA    NA         0      1   NA   NA
VDX_109    VDX_109     VDX    VDX 109 GSM36891.CEL.gz   NA  65  0     3  NA   NA            NA      0   2646    0    NA    NA         0      1   NA   NA
VDX_110    VDX_110     VDX    VDX 110 GSM36903.CEL.gz   NA  73  1     3  NA   NA            NA      1    243    0    NA    NA         0      1   NA   NA
VDX_113    VDX_113     VDX    VDX 113 GSM36906.CEL.gz   NA  47  0     3  NA   NA            NA      0   3072    0    NA    NA         0      1   NA   NA
VDX_115    VDX_115     VDX    VDX 115 GSM36908.CEL.gz   NA  61  1     3  NA   NA            NA      1    456    0    NA    NA         0      1   NA   NA
 [ reached getOption("max.print") -- omitted 101 rows ]

Can use same expression to subset the columns of the expression matrix

  • why can we do this? Because the columns of the expression matrix are in the same order as the rows of the metadata
    • don’t believe me? see below…
  • this isn’t a coincidence. the data have been carefully curated to ensure that this is the case
  • data stored in online repositories are often organised in this way
head(colnames(eValues))
head(rownames(metadata))
table(colnames(eValues) == rownames(metadata))
  • we can subset the expression data according to our clinical data
eValues[,which(metadata$grade==3)][1:10,1:10]
              VDX_5     VDX_6     VDX_7     VDX_9    VDX_11    VDX_14    VDX_15    VDX_17    VDX_18    VDX_20
1007_s_at 11.798593 11.777625 11.538577 12.248698 12.259243 11.695620 11.577193 12.483665 11.899130 12.414157
1053_at    7.885696  7.949535  7.481396  7.708049  8.182891  7.970394  6.721099  8.005625  6.815063  7.067165
117_at     7.052025  8.225930  8.382408  7.731319  8.226412  7.710118  7.375908  7.488644  7.209453  9.775939
121_at    10.666845 10.888819 10.795472 10.886687 10.192909 11.275077 10.614526 10.664625 10.772892 10.623607
1255_g_at  5.452859  6.456149  6.147714  6.551516  6.376777  6.620586  6.044394  6.244126  5.311067  6.266787
1294_at    9.585901  9.422906  9.456970  9.831782  9.404290  9.292552  8.572511 10.301839  9.430871  8.914684
1316_at    7.644577  7.065012  8.121534  7.573647  7.068241  8.377644  7.302867  7.780048  8.203103  7.651769
1320_at    5.066089  4.661065  6.400879  4.153805  3.678072  4.209453  4.887525  6.456149  5.385431  6.230741
1405_i_at 10.043711  9.350276 11.520619 13.012869  9.896030  8.618386  8.355792  9.875289  7.210428  9.133656
1431_at    6.230741  6.263034  5.951868  6.183883  5.741467  6.797013  5.744161  6.407693  6.560715  5.617651
  • in fact, we can subset the entire vdx object by sample subsets if we wish
vdx[,which(metadata$grade==3)]
ExpressionSet (storageMode: lockedEnvironment)
assayData: 22283 features, 148 samples 
  element names: exprs 
protocolData: none
phenoData
  sampleNames: VDX_5 VDX_6 ... VDX_913 (148 total)
  varLabels: samplename dataset ... e.os (21 total)
  varMetadata: labelDescription
featureData
  featureNames: 1007_s_at 1053_at ... AFFX-TrpnX-M_at (22283 total)
  fvarLabels: probe Gene.title ... GO.Component.1 (22 total)
  fvarMetadata: labelDescription
experimentData: use 'experimentData(object)'
  pubMedIds: 17420468 
Annotation: hgu133a 

Previously, we used a boxplot to visualise the expression levels of all genes in a given sample to look for trends across the dataset. Another use for a boxplot is to visualise the expression level of a particular gene with respect to the sample metadata

  • we can extract the column of interest with a $ and use the formula syntax
    • table in this case will tell us how many observations of each category are present
  • R will be clever and convert the factor into a factor type if required
fac <- metadata$er
table(fac)
fac
  0   1 
135 209 
boxplot(eValues[1,] ~ fac,
        xlab="ER Status",
        ylab="Expression Level",
        col=c("steelblue","goldenrod"))

Performing a test to assess significance follows similar syntax

  • t.test is the generic function to perform a t-test, and can be adapted to different circumstances
    • e.g. if our data are paired, or not
    • see the help for t.test for more details
  • for now, we will gloss over testing assumptions on the data such as requiring a normal (Gaussian) distribution and multiple testing correction
t.test(eValues[1,]~fac)

    Welch Two Sample t-test

data:  eValues[1, ] by fac
t = -1.7476, df = 244.15, p-value = 0.08179
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -0.2101311  0.0125555
sample estimates:
mean in group 0 mean in group 1 
       11.72515        11.82394 

Accessing feature (gene) information

We could be lucky, and the first row in the expression matrix could be our favourite gene of interest! However, this is unlikely to be the case and we will have to figure out which row we want to plot

  • we can use another aspect of the nki object; the feature data
  • there is a handy fData function to access these data
  • again, this gives us a data frame
  • this is a pre-built table supplied with the dataset
    • later in the course we will look at using online services and databases for annotation and converting between identifiers
features <- fData(vdx) #try to figure out the location in memory of this data.frame via @ and $
class(features)
[1] "data.frame"
head(features[,1:5])
              probe                                  Gene.title Gene.symbol Gene.ID EntrezGene.ID
1007_s_at 1007_s_at discoidin domain receptor tyrosine kinase 1        DDR1     780           780
1053_at     1053_at replication factor C (activator 1) 2, 40kDa        RFC2    5982          5982
117_at       117_at        heat shock 70kDa protein 6 (HSP70B')       HSPA6    3310          3310
121_at       121_at                                paired box 8        PAX8    7849          7849
1255_g_at 1255_g_at     guanylate cyclase activator 1A (retina)      GUCA1A    2978          2978
1294_at     1294_at ubiquitin-like modifier activating enzyme 7        UBA7    7318          7318
colnames(features)
 [1] "probe"                 "Gene.title"            "Gene.symbol"           "Gene.ID"               "EntrezGene.ID"         "UniGene.title"        
 [7] "UniGene.symbol"        "UniGene.ID"            "Nucleotide.Title"      "GI"                    "GenBank.Accession"     "Platform_CLONEID"     
[13] "Platform_ORF"          "Platform_SPOTID"       "Chromosome.location"   "Chromosome.annotation" "GO.Function"           "GO.Process"           
[19] "GO.Component"          "GO.Function.1"         "GO.Process.1"          "GO.Component.1"       

As we know, gene symbols (more-common gene names) can be accessed using the $ syntax; returning a vector

head(features$Gene.symbol)
[1] "DDR1"   "RFC2"   "HSPA6"  "PAX8"   "GUCA1A" "UBA7"  

We could inspect the data frame manually (e.g. using View(features)) and identify the row number corresponding to our gene of interest. However, as aspiring R programmers, there is a better way

  • == to test for exact matching
  • match will return the index of the first match
  • grep can be used for partial matches
  • each of the above will give an vector that can be used to subset the expression values
which(features$Gene.symbol == "BRCA1")
[1]  4058 11245
match("BRCA1",features$Gene.symbol)
[1] 4058
grep("BRCA1",features$Gene.symbol)
[1]  4058 11245
grep("BRCA",features$Gene.symbol)
[1]  4058  7869 11245 14103



Exercise

  • Verify that the rows of the feature matrix and the expression values are in the same order
  • Find the row corresponding to your favourite gene
    • if you don’t have one, try ESR1
    • if you find multiple matches, pick the first one that occurs
  • Does the expression level of this gene appear to be associated with the ER status?



#FILL IN SOLUTIONS HERE

Testing all genes for significance

Later in the course we will see how to execute a differential expression analysis for RNA-seq data, and discuss some of the issues surrounding this. For now we will perform a simple two-sample t-test for all genes in our study, and derive a results table

  • firstly, we load the genefilter package which has a very convenient function for performing many t tests in parallel
  • rowttests will run a t-test for each row in a given matrix and produce an output table
    • statistic; test statistic
    • dm; difference in means
    • p.value; the p-value
  • rowttests expects a factor as the second argument, so we have to use as.factor
    • as usual, we can get help by doing ?rowttests
library(genefilter)
tstats <- rowttests(eValues, as.factor(metadata$er))
head(tstats)
          statistic          dm      p.value
1007_s_at -1.826397 -0.09878782 6.866210e-02
1053_at    6.419587  0.54673000 4.565205e-10
117_at     2.787517  0.17342654 5.608148e-03
121_at     2.088925  0.08258267 3.745333e-02
1255_g_at  1.750130  0.17399402 8.099267e-02
1294_at   -4.113639 -0.22451339 4.883874e-05
hist(tstats$statistic)

The rows are ordered in the same way as the input matrix

  • to change this to increasing significance we can use the order function
  • when given a vector, order will return a vector of the same length giving the permutation that rearranges that vector into ascending or descending order
  • The sort function shortcuts using the output of order to rearrange the original vector by returning the sorted vector
x <- c(9, 3, 4, 2, 1, 6,5, 10, 8, 7)
x
 [1]  9  3  4  2  1  6  5 10  8  7
order(x)
 [1]  5  4  2  3  7  6 10  9  1  8
x[order(x)]
 [1]  1  2  3  4  5  6  7  8  9 10
sort(x)
 [1]  1  2  3  4  5  6  7  8  9 10
  • so if we want to order by p-value we first use order on the p-value vector
  • this can then be used to re-arrange the rows of the table
head(tstats[order(tstats$p.value,decreasing = FALSE),])
            statistic        dm      p.value
205225_at   -22.58420 -3.762901 9.004544e-70
209603_at   -18.89942 -3.052348 4.700701e-55
209604_s_at -17.53072 -2.431309 1.523875e-49
212956_at   -17.42552 -2.157435 4.037559e-49
202088_at   -17.25845 -1.719680 1.895888e-48
212496_s_at -16.82538 -1.459843 1.039846e-46

However, the table we get isn’t immediately useful unless we can recognise the manufacturer probe IDs

  • to provide extra annotation to the table, we can column bind (cbind) the columns of test statistic with those from the feature matrix
  • be careful though, we can only do this in cases where the rows are in direct correspondence
table(rownames(tstats) == rownames(features))

 TRUE 
22283 
tstats.annotated <- cbind(tstats, features[,c("Gene.symbol","EntrezGene.ID","Chromosome.location")])
head(tstats.annotated)
          statistic          dm      p.value Gene.symbol EntrezGene.ID Chromosome.location
1007_s_at -1.826397 -0.09878782 6.866210e-02        DDR1           780              6p21.3
1053_at    6.419587  0.54673000 4.565205e-10        RFC2          5982             7q11.23
117_at     2.787517  0.17342654 5.608148e-03       HSPA6          3310                1q23
121_at     2.088925  0.08258267 3.745333e-02        PAX8          7849            2q12-q14
1255_g_at  1.750130  0.17399402 8.099267e-02      GUCA1A          2978              6p21.1
1294_at   -4.113639 -0.22451339 4.883874e-05        UBA7          7318                3p21

Now when we order by p-value, the extra columns that we just added allow us to interpret the results more easily

tstats.ordered <- tstats.annotated[order(tstats$p.value,decreasing = FALSE),]
head(tstats.ordered)
            statistic        dm      p.value Gene.symbol EntrezGene.ID Chromosome.location
205225_at   -22.58420 -3.762901 9.004544e-70        ESR1          2099              6q25.1
209603_at   -18.89942 -3.052348 4.700701e-55       GATA3          2625               10p15
209604_s_at -17.53072 -2.431309 1.523875e-49       GATA3          2625               10p15
212956_at   -17.42552 -2.157435 4.037559e-49      TBC1D9         23158             4q31.21
202088_at   -17.25845 -1.719680 1.895888e-48     SLC39A6         25800             18q12.2
212496_s_at -16.82538 -1.459843 1.039846e-46       KDM4B         23030             19p13.3

We can also query this table to look for our favourite genes of interest

  • %in% is a simplified way to perform matches to multiple items in a vector
tstats.ordered[grep("ESR1",tstats.ordered$Gene.symbol),]
              statistic          dm      p.value Gene.symbol EntrezGene.ID Chromosome.location
205225_at   -22.5842021 -3.76290050 9.004544e-70        ESR1          2099              6q25.1
215552_s_at  -7.6049898 -0.88635602 2.779492e-13        ESR1          2099              6q25.1
217190_x_at  -6.1260692 -0.80822337 2.476553e-09        ESR1          2099              6q25.1
211235_s_at  -5.1799122 -0.65885102 3.799727e-07        ESR1          2099              6q25.1
211233_x_at  -4.3214212 -0.47809985 2.035049e-05        ESR1          2099              6q25.1
211234_x_at  -2.1071684 -0.24655890 3.583069e-02        ESR1          2099              6q25.1
215551_at    -1.5416740 -0.10875680 1.240776e-01        ESR1          2099              6q25.1
217163_at     1.4049015  0.19803578 1.609582e-01        ESR1          2099              6q25.1
211627_x_at   0.3835679  0.05999355 7.015371e-01        ESR1          2099              6q25.1
tstats.ordered[tstats.ordered$Gene.symbol %in% c("ESR1","GATA3","FOXA1"),]
              statistic          dm      p.value Gene.symbol EntrezGene.ID Chromosome.location
205225_at   -22.5842021 -3.76290050 9.004544e-70        ESR1          2099              6q25.1
209603_at   -18.8994157 -3.05234794 4.700701e-55       GATA3          2625               10p15
209604_s_at -17.5307220 -2.43130913 1.523875e-49       GATA3          2625               10p15
209602_s_at -16.3574865 -2.92150517 7.790349e-45       GATA3          2625               10p15
204667_at   -14.0650865 -2.11853144 8.982816e-36       FOXA1          3169           14q12-q13
215552_s_at  -7.6049898 -0.88635602 2.779492e-13        ESR1          2099              6q25.1
217190_x_at  -6.1260692 -0.80822337 2.476553e-09        ESR1          2099              6q25.1
211235_s_at  -5.1799122 -0.65885102 3.799727e-07        ESR1          2099              6q25.1
211233_x_at  -4.3214212 -0.47809985 2.035049e-05        ESR1          2099              6q25.1
211234_x_at  -2.1071684 -0.24655890 3.583069e-02        ESR1          2099              6q25.1
215551_at    -1.5416740 -0.10875680 1.240776e-01        ESR1          2099              6q25.1
217163_at     1.4049015  0.19803578 1.609582e-01        ESR1          2099              6q25.1
211627_x_at   0.3835679  0.05999355 7.015371e-01        ESR1          2099              6q25.1



Exercise

  • From the annotated table above, select all genes with p-values less than 0.05
  • Write this data frame as a csv file (hint: use write.csv)
    • Check the outputted file. Is there anything weird about it?
  • Use the p.adjust to produce a vector of p-values that are adjusted. Add this as an extra column to your table of results and write as a file



#FILL IN SOLUTIONS HERE
LS0tCnRpdGxlOiAiUiBhbmQgQmlvY29uZHVjdG9yIEludHJvZHVjdGlvbiIKYXV0aG9yOiAiQWxpc3RhaXIgTWFydGluIDxicj4gKGJhc2VkIG9uIE1hcmsgRHVubmluZydzIDIwMTcgc2xpZGVzKSIKZGF0ZTogJ2ByIGZvcm1hdChTeXMudGltZSgpLCAiTGFzdCBtb2RpZmllZDogJWQgJWIgJVkiKWAnCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0b2M6IHllcwogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKLS0tCgojIEFib3V0IFIKCklmIHlvdSBoYXZlbid0IGxlYXJuZWQgdGhlIGJhc2ljcyBvZiBSIHByaW9yIHRvIGF0dGVuZGluZyB0aGlzIGNvdXJzZSwgeW91IHNob3VsZCBjaGVjayBvdXQgb3VyIFtSIGNyYXNoIGNvdXJzZV0oaHR0cHM6Ly9iaW9pbmZvcm1hdGljcy1jb3JlLXNoYXJlZC10cmFpbmluZy5naXRodWIuaW8vci1jcmFzaC1jb3Vyc2UvKSBmb3IgYW4gb3ZlcnZpZXcgb2YgUidzIHN5bnRheC4gSXQncyBhbHNvIGEgZ3JlYXQgcmVmcmVzaGVyIGlmIHlvdSBmZWVsIGl0IGhhcyBiZWVuIGEgd2hpbGUgc2luY2UgeW91IGxhc3Qgd29ya2VkIHdpdGggUi4KCiMjIEFib3V0IHRoZSBwcmFjdGljYWxzIGZvciB0aGlzIHdvcmtzaG9wCgotIFRoZSB0cmFkaXRpb25hbCB3YXkgdG8gZW50ZXIgUiBjb21tYW5kcyBpcyB2aWEgb3BlbmluZyBhIFRlcm1pbmFsIG9yLCBvciB1c2luZyB0aGUgY29uc29sZSBpbiBSU3R1ZGlvIChib3R0b20tbGVmdCBwYW5lbCB3aGVuIFJTdHVkaW8gb3BlbnMgZm9yIGZpcnN0IHRpbWUpLgotIEZvciB0aGlzIGNvdXJzZSB3ZSB3aWxsIGluc3RlYWQgYmUgdXNpbmcgYSByZWxhdGl2ZWx5IG5ldyBmZWF0dXJlIGNhbGxlZCAqUiBOb3RlYm9va3MqLgotIEFuIFIgbm90ZWJvb2sgbWl4ZXMgcGxhaW4gdGV4dCB3cml0dGVuIGluIG1hcmtkb3duIHdpdGggImNodW5rcyIgb2YgUiBjb2RlLgoKKk1hcmtkb3duKiBpcyBhIHZlcnkgc2ltcGxlIHdheSBvZiB3cml0aW5nIGEgdGVtcGxhdGUgdG8gcHJvZHVjZSBhIHBkZiwgSFRNTCBvciB3b3JkIGRvY3VtZW50LiBGb3IgZXhhbXBsZSwgdGhlIGNvbXBpbGVkIHZlcnNpb24gb2YgdGhpcyBkb2N1bWVudCBpcyBhdmFpbGFibGUgb25saW5lIGFuZCBpcyBtb3JlIGNvbnZlbmllbnQgdG8gYnJvd3NlIFtoZXJlXShodHRwczovL2Jpb2luZm9ybWF0aWNzLWNvcmUtc2hhcmVkLXRyYWluaW5nLmdpdGh1Yi5pby9jcnVrLWF1dHVtbi1zY2hvb2wtMjAxNy9EYXkxL2Jpb2MtaW50cm8ubmIuaHRtbCkuCgotICJDaHVua3MiIG9mIFIgY29kZSBjYW4gYmUgYWRkZWQgdXNpbmcgdGhlICppbnNlcnQqIG9wdGlvbiBmcm9tIHRoZSB0b29sIGJhciwgb3IgdGhlIENUUkwgKyBBTFQgKyBJIHNob3J0Y3V0Ci0gRWFjaCBsaW5lIG9mIFIgY2FuIGJlIGV4ZWN1dGVkIGJ5IGNsaWNraW5nIG9uIHRoZSBsaW5lIGFuZCBwcmVzc2luZyBDVFJMIGFuZCBFTlRFUgotIE9yIHlvdSBjYW4gZXhlY3V0ZSB0aGUgd2hvbGUgY2h1bmsgYnkgcHJlc3NpbmcgQ1RSTCArIFNISUZUICsgRU5URVIKLSBPciB5b3UgY2FuIHByZXNzIHRoZSBncmVlbiB0cmlhbmdsZSBvbiB0aGUgcmlnaHQtaGFuZCBzaWRlIHRvIHJ1biBldmVyeXRoaW5nIGluIHRoZSBjaHVuawotIFRoZSBjb2RlIG1pZ2h0IGhhdmUgZGlmZmVyZW50IG9wdGlvbnMgd2hpY2ggZGljdGF0ZSBob3cgdGhlIG91dHB1dCBpcyBkaXNwbGF5ZWQgaW4gdGhlIGNvbXBpbGVkIGRvY3VtZW50IChlLmcuIEhUTUwpCiAgICArIGUuZy4geW91IG1pZ2h0IHNlZSBgRVZBTCA9IEZBTFNFYCBvciBgZWNobyA9IEZBTFNFYAogICAgKyB5b3UgZG9uJ3QgaGF2ZSB0byB3b3JyeSBhYm91dCB0aGlzIGlmIHN0ZXBwaW5nIHRocm91Z2ggdGhlIG1hcmtkb3duIGludGVyYWN0aXZlbHkKCmBgYHtyfQpwcmludCgiSGVsbG8gV29ybGQiKQpgYGAKCldoZW4gdmlld2luZyB0aGUgUiBub3RlYm9va3MgZGlyZWN0bHksIG5vdCB0aGUgY29tcGlsZWQgZG9jdW1lbnRzLCBzZWN0aW9ucyBtYXkgaGF2ZSBhZGRpdGlvbmFsIGNoYXJhY3RlcnMgc28gYXMgdG8gZm9ybWF0IHRoZW0gbmljZWx5IHdoZW4gY29tcGlsZWQuIEZvciBleGFtcGxlOgoKKlRoaXMgd2lsbCBiZSBkaXNwbGF5ZWQgaW4gaXRhbGljKgoKKipUaGlzIHdpbGwgYmUgZGlzcGxheWVkIGluIGJvbGQqKgoKLSB0aGlzIAotIGlzIAotIGEgCi0gbGlzdAogICAgKyB0aGlzIGlzIGEgKnN1Yi1saXN0KgoKWW91IGNhbiBhbHNvIGFkZCBoeXBlcmxpbmtzLCBpbWFnZXMgYW5kIHRhYmxlcy4KCkxhc3RseSwgeW91IGNhbiBldmVuIGVtYmVkIGNodW5rcyBvZiBjb2RlIHdyaXR0ZW4gaW4gb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLgoKYGBge3B5dGhvbn0KYT0nV293IHB5dGhvbicKcHJpbnQoYS5zcGxpdCgpKQpgYGAKCk1vcmUgaGVscCBpcyBhdmFpbGFibGUgdGhyb3VnaCBSU3R1ZGlvICoqSGVscCAtPiBNYXJrZG93biBRdWljayBSZWZlcmVuY2UqKiBvciB5b3UgY2FuIHZpZXcgYSBjaGVhdCBzaGVldCBbaGVyZV0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDIvcm1hcmtkb3duLWNoZWF0c2hlZXQucGRmKS4KClRvIGNyZWF0ZSBtYXJrZG93biBmaWxlcyBmb3IgeW91ciBvd24gYW5hbHlzaXM7IEZpbGUgLT4gTmV3IEZpbGUgLT4gUiBNYXJrZG93bi4uLgoKIyBBYm91dCB0aGUgQmlvY29uZHVjdG9yIHByb2plY3QKCiFbXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9pbWFnZXMvbG9nb19iaW9jb25kdWN0b3IuZ2lmKQoKRXN0YWJsaXNoZWQgaW4gMjAwMSwgQmlvY29uZHVjdG9yIHByb3ZpZGVkIGEgY29udmVuaWVudCBtZXRob2QgdG8gZGlzdHJpYnV0ZSB0b29scyBmb3IgdGhlIGFuYWx5c2lzIGFuZCBjb21wcmVoZW5zaW9uIG9mIGhpZ2gtdGhyb3VnaHB1dCBnZW5vbWljIGRhdGEgaW4gUi4gSW5pdGlhbGx5IGZvY3VzZWQgb24gbWljcm9hcnJheXMsIEJpb2NvbmR1Y3RvciBub3cgaGFzIHBhY2thZ2VzIChyZWFkOiBzb2Z0d2FyZSkgdG8gcHJvY2VzcyBkYXRhIG9idGFpbmVkIGZyb20gbW9zdCBtb2Rlcm4gZGF0YSBzb3VyY2VzLgoKLSBSIGlzIHJhcmVseSB1c2VkIGZvciB0aGUgcHJpbWFyeSBwcm9jZXNzaW5nIG9mIG1vZGVybiBkYXRhCiAgICArIFIgaXMgZmFyIHNsb3dlciB0aGFuIG1hbnkgb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIGR1ZSB0byBpdCBiZWluZyBhbiBpbnRlcnByZXRlZCBsYW5ndWFnZSAoW0ludGVycHJldGVkIHZzIENvbXBpbGVkXShodHRwczovL3d3dy5pYm0uY29tL3N1cHBvcnQva25vd2xlZGdlY2VudGVyL3pvc2Jhc2ljcy9jb20uaWJtLnpvcy56YXBwbGRldi96YXBwbGRldl84NS5odG0pKQogICAgKyBSIGlzIGV4dGVuc2l2ZWx5LXVzZWQgZm9yIHZpc3VhbGlzYXRpb24sIGludGVycHJldGF0aW9uIGFuZCBpbmZlcmVuY2Ugb25jZSBkYXRhIGhhcyBiZWVuIHBhcnNlZCBpbnRvIGEgbW9yZSBtYW5hZ2VhYmxlIGZvcm0sIGUuZy4sIGEgY3N2LgoKT24gdGhlIFtCaW9jb25kdWN0b3Igd2Vic2l0ZV0od3d3LmJpb2NvbmR1Y3Rvci5vcmcpLCB5b3Ugd2lsbCBmaW5kCgotIEluc3RhbGxhdGlvbiBpbnN0cnVjdGlvbnMKLSBbQ291cnNlIE1hdGVyaWFsc10oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvaGVscC9jb3Vyc2UtbWF0ZXJpYWxzLykKLSBbU3VwcG9ydCBmb3J1bV0oaHR0cHM6Ly9zdXBwb3J0LmJpb2NvbmR1Y3Rvci5vcmcvKQogICAgKyBhIG1lYW5zIG9mIGNvbW11bmljYXRpbmcgd2l0aCBkZXZlbG9wZXJzIGFuZCBwb3dlci11c2VycwotIFtFeGFtcGxlIGRhdGFzZXRzXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL0Jpb2NWaWV3cy5odG1sI19fX0V4cGVyaW1lbnREYXRhKQotIFtBbm5vdGF0aW9uIFJlc291cmNlc10oaHR0cDovL2Jpb2NvbmR1Y3Rvci5vcmcvcGFja2FnZXMvcmVsZWFzZS9CaW9jVmlld3MuaHRtbCNfX19Bbm5vdGF0aW9uRGF0YSkKLSBDb25mZXJlbmNlcwoKRm9yIHRoaXMgc2Vzc2lvbiwgd2Ugd2lsbCBpbnRyb2R1Y2UgdGhlIEJpb2NvbmR1Y3RvciBwcm9qZWN0IGFzIGEgbWVhbnMgb2YgYW5hbHlzaW5nIGhpZ2gtdGhyb3VnaHB1dCBkYXRhCgojIyBJbnN0YWxsaW5nIGEgcGFja2FnZQoKQWxsIEJpb2NvbmR1Y3RvciBzb2Z0d2FyZSBwYWNrYWdlcyBhcmUgbGlzdGVkIHVuZGVyCgotIGJpb2NvbmR1Y3Rvci5vcmcgLT4gSW5zdGFsbCAtPiBQYWNrYWdlcyAtPiBBbmFseXNpcyAqc29mdHdhcmUqIHBhY2thZ2VzCiAgICArIE1hbnkgdGhvdXNhbmRzIG9mIHBhY2thZ2VzIGhhdmUgYmVlbiBhZGRlZCBvdmVyIHRoZSB5ZWFycywgc28gSSB3b3VsZCBzdWdnZXN0IGp1c3QgZ29vZ2xpbmcgImJpb2NvbmR1Y3RvciBbcGFja2FnZV9uYW1lXSIKICAgICsgZS5nLiBbZWRnZVIgbGFuZGluZyBwYWdlXShodHRwOi8vYmlvY29uZHVjdG9yLm9yZy9wYWNrYWdlcy9yZWxlYXNlL2Jpb2MvaHRtbC9lZGdlUi5odG1sKQotIGluc3RhbGxhdGlvbiBpbnN0cnVjdGlvbnMgYXJlIGdpdmVuLCB3aGljaCBpbnZvbHZlcyBydW5uaW5nIHRoZSBgYmlvY0xpdGVgIGNvbW1hbmQKICAgICsgdGhpcyB3aWxsIGluc3RhbGwgYW5kIHVwZGF0ZSBhbnkgYWRkaXRpb25hbCBkZXBlbmRlbmNpZXMKLSB5b3Ugb25seSBuZWVkIHRvIHJ1biB0aGlzIHByb2NlZHVyZSBvbmNlIGZvciBlYWNoIHZlcnNpb24gb2YgUgoKYGBge3IgZXZhbD1GQUxTRX0KIyMgWW91IGRvbid0IG5lZWQgdG8gcnVuIHRoaXMsIGVkZ2VSIHNob3VsZCBhbHJlYWR5IGJlIGluc3RhbGxlZCBmb3IgdGhlIGNvdXJzZQpzb3VyY2UoImh0dHA6Ly93d3cuYmlvY29uZHVjdG9yLm9yZy9iaW9jTGl0ZS5SIikKYmlvY0xpdGUoImVkZ2VSIikKYGBgCgpPbmNlIGluc3RhbGxlZCwgYSBCaW9jb25kdWN0b3IgcGFja2FnZSBjYW4gYmUgbG9hZGVkIGluIHRoZSB1c3VhbCB3YXkgd2l0aCB0aGUgYGxpYnJhcnlgIGZ1bmN0aW9uLiBBbGwgcGFja2FnZXMgYXJlIHJlcXVpcmVkIHRvIGhhdmUgYSAqdmlnbmV0dGUqIHdoaWNoIGdpdmVzIGRldGFpbGVkIGluc3RydWN0aW9ucyBvbiBob3cgdG8gdXNlIHRoZSBwYWNrYWdlIGFuZCB0aGUgd29ya2Zsb3cgb2YgY29tbWFuZHMuIFNvbWUgcGFja2FnZXMgc3VjaCBhcyBgZWRnZVJgIGhhdmUgdmVyeSBjb21wcmVoZW5zaXZlICp1c2VyIGd1aWRlcyogd2l0aCBsb3RzIG9mIHVzZS1jYXNlcy4KCmBgYHtyIG1lc3NhZ2U9RkFMU0UsZXZhbD1GQUxTRX0KbGlicmFyeShlZGdlUikKdmlnbmV0dGUoImVkZ2VSIikKZWRnZVJVc2Vyc0d1aWRlKCkKYGBgCgpQYWNrYWdlIGRvY3VtZW50YXRpb24gY2FuIGFsc28gYmUgYWNjZXNzZWQgdmlhIHRoZSAqSGVscCogdGFiIGluIFJTdHVkaW8sIHdoaWNoIGNhbiBhbHNvIGJlIGludm9rZWQgaW4gdGhlIGNvbnNvbGUgdXNpbmcgIj8iCgpgYGB7ciBtZXNzYWdlPUZBTFNFLGV2YWw9RkFMU0V9Cj9lZGdlUgpgYGAKCiMjIFN0cnVjdHVyZXMgZm9yIGRhdGEgYW5hbHlzaXMKCkNvbXBsZXggZGF0YSBzdHJ1Y3R1cmVzIGFyZSB1c2VkIGluIEJpb2NvbmR1Y3RvciB0byByZXByZXNlbnQgaGlnaC10aHJvdWdocHV0IGRhdGEsIGJ1dCB3ZSBvZnRlbiBoYXZlIHNpbXBsZSBmdW5jdGlvbnMgdGhhdCB3ZSBjYW4gdXNlIHRvIGFjY2VzcyB0aGUgZGF0YS4gV2Ugd2lsbCB1c2Ugc29tZSBleGFtcGxlIGRhdGEgYXZhaWxhYmxlIHRocm91Z2ggQmlvY29uZHVjdG9yIHRvIGRlbW9uc3RyYXRlIGhvdyBoaWdoLXRocm91Z2hwdXQgZGF0YSBjYW4gYmUgcmVwcmVzZW50ZWQsIGFuZCBhbHNvIHRvIHJldmlldyBzb21lIGJhc2ljIGNvbmNlcHRzIGluIGRhdGEgbWFuaXB1bGF0aW9uIGluIFIuCgotIHRoZSBkYXRhIGFyZSBmcm9tIGEgKm1pY3JvYXJyYXkqIGV4cGVyaW1lbnQuIFdlIHdpbGwgYmUgY29uY2VudHJhdGluZyBvbiBtb3JlIG1vZGVybiB0ZWNobm9sb2dpZXMgaW4gdGhpcyBjbGFzcywgYnV0IG1vc3Qgb2YgdGhlIFIgdGVjaG5pcXVlcyByZXF1aXJlZCB3aWxsIGJlIHNpbWlsYXIKLSBbZXhwZXJpbWVudGFsIGRhdGFdKGh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL3BhY2thZ2VzL3JlbGVhc2UvQmlvY1ZpZXdzLmh0bWwjX19fRXhwZXJpbWVudERhdGEpIHBhY2thZ2VzIGFyZSBhdmFpbGFibGUgdGhyb3VnaCBCaW9jb25kdWN0b3IsIGFuZCBjYW4gYmUgaW5zdGFsbGVkIGluIHRoZSB3YXkgd2UganVzdCBkZXNjcmliZWQKICArIHRoZSBwYWNrYWdlIHNob3VsZCBhbHJlYWR5IGJlIGluc3RhbGxlZCBvbiB5b3VyIGNvbXB1dGVyLCBzbyB5b3Ugd29uJ3QgbmVlZCB0byBydW4gdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9CiMjIE5vIG5lZWQgdG8gcnVuIHRoaXMgLSBmb3IgcmVmZXJlbmNlIG9ubHkhCmJpb2NMaXRlKCJicmVhc3RDYW5jZXJWRFgiKQpgYGAKClRvIG1ha2UgdGhlIGRhdGFzZXQgYWNjZXNzaWJsZSBpbiBSLCB3ZSBmaXJzdCBuZWVkIHRvIGxvYWQgdGhlIHBhY2thZ2UuIElmIHdlIG5hdmlnYXRlIHRvIHRoZSBkb2N1bWVudGF0aW9uIGZvciBgYnJlYXN0Q2FuY2VyVkRYYCBpbiBSU3R1ZGlvLCB3ZSBmaW5kIHRoYXQgaXQgcHJvdmlkZXMgYW4gb2JqZWN0IGNhbGxlZCBgdmR4YCB3aGljaCB3ZSBsb2FkIGludG8gUidzIG1lbW9yeSB1c2luZyB0aGUgYGRhdGFgIGZ1bmN0aW9uLgoKYGBge3IgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShicmVhc3RDYW5jZXJWRFgpCmRhdGEodmR4KQpgYGAKClRoZSBvYmplY3QgYHZkeGAgaXMgYSByZXByZXNlbnRhdGlvbiBvZiBicmVhc3QgY2FuY2VyIGRhdGFzZXQgdGhhdCBoYXMgYmVlbiBjb252ZXJ0ZWQgZm9yIHVzZSB3aXRoIHN0YW5kYXJkIEJpb2NvbmR1Y3RvciB0b29scy4gVGhlIHBhY2thZ2UgYXV0aG9ycyBkb24ndCBlbnZpc2FnZSB0aGF0IHdlIHdpbGwgd2FudCB0byB2aWV3IHRoZSBlbnRpcmUgZGF0YXNldCBhdCBvbmNlLCBzbyBoYXZlIHByb3ZpZGVkIGEgbnVtYmVyIG9mIHdheXMgdG8gaW50ZXJhY3Qgd2l0aCB0aGUgZGF0YQoKLSB0eXBpbmcgdGhlIG5hbWUgb2YgdGhlIG9iamVjdCBwcm92aWRlcyBhIHN1bW1hcnksIGUuZy4sIAogICAgKyBob3cgbWFueSBnZW5lcyBpbiB0aGUgZGF0YXNldAogICAgKyBob3cgbWFueSBzYW1wbGVzCiAgICAKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CnZkeApgYGAKCiMjIEFjY2Vzc2luZyBleHByZXNzaW9uIHZhbHVlcwoKVGhlIGV4cHJlc3Npb24gdmFsdWVzIGNhbiBiZSBvYnRhaW5lZCBieSB0aGUgYGV4cHJzYCBmdW5jdGlvbjotCgotIHJlbWVtYmVyLCBgPC1gIGlzIHVzZWQgZm9yIGFzc2lnbm1lbnQgdG8gY3JlYXRlIGEgbmV3IHZhcmlhYmxlCi0gdGhlIGRhdGEgYXJlIHN0b3JlZCBpbiBhIGBtYXRyaXhgIGluIFIKICAgICsgaXQgaXMgYSBnb29kIGlkZWEgdG8gY2hlY2sgdGhlIGRpbWVuc2lvbnMgdXNpbmcgYGRpbWAsIGBuY29sYCwgYG5yb3dgIGV0Yy4KICAgIApgYGB7cn0KZVZhbHVlcyA8LSBleHBycyh2ZHgpICMgYWxzbyBmb3VuZCBhdCB2ZHhAYXNzYXlEYXRhJGV4cHJzCmNsYXNzKGVWYWx1ZXMpCmRpbShlVmFsdWVzKQpuY29sKGVWYWx1ZXMpCm5yb3coZVZhbHVlcykKYGBgCgotIHRoZSByb3cgbmFtZXMgYXJlIHRoZSBtYW51ZmFjdHVyZXItYXNzaWduZWQgSUQgZm9yIGEgcGFydGljdWxhciBwcm9iZQotIHRoZSBjb2x1bW4gbmFtZXMgYXJlIHRoZSBpZGVudGlmaWVycyBmb3IgZWFjaCBwYXRpZW50IGluIHRoZSBzdHVkeQotIGVhY2ggZW50cnkgaXMgYSAqbm9ybWFsaXNlZCogbG9nJF8yJCBpbnRlbnNpdHkgdmFsdWUgZm9yIGEgcGFydGljdWxhciBnZW5lIGluIGEgZ2l2ZW4gc2FtcGxlCiAgICArIHdlIHdvbid0IHRhbGsgYWJvdXQgbm9ybWFsaXNhdGlvbiBoZXJlLCBidXQgYmFzaWNhbGx5IHRoZSBkYXRhIGhhcyBiZWVuIHRyYW5zZm9ybWVkIHNvIHRoYXQgc2FtcGxlcyBhbmQvb3IgZ2VuZXMgY2FuIGJlIGNvbXBhcmVkCi0gc3Vic2V0dGluZyBhIG1hdHJpeCBpcyBkb25lIHVzaW5nIHRoZSBgW3JvdywgY29sdW1uXWAgbm90YXRpb24KICAgICsgdGhlIGZ1bmN0aW9uIGBjYCBpcyB1c2VkIHRvIG1ha2UgYSBvbmUtZGltZW5zaW9uYWwgKnZlY3RvcioKICAgICsgdGhlIHNob3J0Y3V0IGA6YCBjYW4gdXNlZCB0byBzdGFuZCBmb3IgYSBzZXF1ZW5jZSBvZiBjb25zZWN1dGl2ZSBudW1iZXJzCiAgCmBgYHtyfQplVmFsdWVzW2MoMSwyLDMpLGMoMSwyLDMsNCldCmVWYWx1ZXNbMTozLDE6NF0KYGBgCgotIHN1YnNldHRpbmcgY2FuIGJlIGNoYWluZWQgdG9nZXRoZXIKLSB3ZSBjYW4gYWxzbyBvbWl0IGNlcnRhaW4gcm93cyBvciBjb2x1bW5zIGZyb20gdGhlIG91dHB1dCBieSBwcmVmaXhpbmcgdGhlIGluZGljZXMgd2l0aCBhIGAtYAoKYGBge3J9CmVWYWx1ZXNbMTozLDE6NF1bLDI6M10KZVZhbHVlc1sxOjMsMTo0XVssLSgyOjMpXQpgYGAKCiMjIFNpbXBsZSB2aXN1YWxpc2F0aW9ucwoKVGhlIG1vc3QgYmFzaWMgcGxvdHRpbmcgZnVuY3Rpb24gaW4gUiBpcyBgcGxvdGAKCi0gdXNpbmcgdGhlIGBwbG90YCBmdW5jdGlvbiB3aXRoIGEgdmVjdG9yIHdpbGwgcGxvdCB0aGUgdmFsdWVzIG9mIHRoYXQgdmVjdG9yIGFnYWluc3QgdGhlIGluZGV4CiAgICArIHdoYXQgZG8geW91IHRoaW5rIGlzIGRpc3BsYXllZCBpbiB0aGUgcGxvdCBiZWxvdz8KCmBgYHtyfQpwbG90KGVWYWx1ZXNbMSxdKQpgYGAKCi0gb25lIHBvc3NpYmxlIHVzZSBpcyB0byBjb21wYXJlIHRoZSB2YWx1ZXMgaW4gYSB2ZWN0b3Igd2l0aCByZXNwZWN0IHRvIGEgZ2l2ZW4gZmFjdG9yCi0gYnV0IHdlIGRvbid0IGtub3cgdGhlIGNsaW5pY2FsIHZhcmlhYmxlcyBpbiBvdXIgZGF0YXNldCB5ZXQgKHRvIGNvbWUgbGF0ZXIpCi0gYSBib3hwbG90IGNhbiBhbHNvIGFjY2VwdCBhIG1hdHJpeCBvciBkYXRhIGZyYW1lIGFzIGFuIGFyZ3VtZW50Ci0gd2hhdCBkbyB5b3UgdGhpbmsgdGhlIGZvbGxvd2luZyBwbG90IHNob3dzPwoKYGBge3IgZmlnLndpZHRoPTEyfQpib3hwbG90KGVWYWx1ZXMsb3V0bGluZT1GQUxTRSkKYGBgCgoKIyMgQWNjZXNzaW5nIHBhdGllbnQgZGF0YQoKVGhlICptZXRhZGF0YSosIG9yIHBoZW5vdHlwaWMgZGF0YSwgZm9yIHRoZSBzYW1wbGVzIGlzIHJldHJpZXZlZCB1c2luZyB0aGUgYHBEYXRhYCBmdW5jdGlvbi4KCmBgYHtyfQptZXRhZGF0YSA8LSBwRGF0YSh2ZHgpICN2ZHhAcGhlbm9EYXRhQGRhdGEKaGVhZChtZXRhZGF0YSkKYGBgCgotIGhlYWQgcHJpbnRzIG9ubHkgdGhlIGZpcnN0IGZldyByb3dzL3ZhbHVlcy4KLSBpbmRpdmlkdWFsIGNvbHVtbnMgY2FuIGJlIGFjY2Vzc2VkIHVzaW5nIHRoZSBgJGAgbm90YXRpb24uIAotIGNvbHVtbnMgYXJlIHJldHVybmVkIGFzIGEgKnZlY3RvciosIHdoaWNoIGNhbiBiZSBmZWQgaW50byBvdGhlciBzdGFuZGFyZCBwbG90dGluZyBhbmQgYW5hbHlzaXMgZnVuY3Rpb25zLgotICphdXRvLWNvbXBsZXRlKiBpcyBhdmFpbGFibGUgaW4gUlN0dWRpbzsgb25jZSB5b3UgdHlwZSB0aGUgYCRgLCBpdCBzaG91bGQgZ2l2ZSB5b3UgYSBsaXN0IG9mIHBvc3NpYmxlIG9wdGlvbnMuCgpgYGB7cn0KaGVhZChtZXRhZGF0YSRzYW1wbGVuYW1lKQpgYGAKCgoqKioqKioKKioqKioqCioqKioqKgoKCiMjIEV4ZXJjaXNlCgotIHdoYXQgdHlwZSBvZiBSIG9iamVjdCBpcyB1c2VkIHRvIHN0b3JlIHRoZSBtZXRhZGF0YT8KLSB3aHkgaXMgdGhpcyBkaWZmZXJlbnQgdG8gdGhlIG9iamVjdCB1c2VkIGZvciB0aGUgZXhwcmVzc2lvbiB2YWx1ZXM/Ci0gdXNlIHRoZSBzcXVhcmUgYnJhY2tldCBub3RhdGlvbiBgW11gIHRvIHByaW50CiAgICArIHRoZSBmaXJzdCAxMCByb3dzIG9mIHRoZSBtZXRhZGF0YSBvYmplY3QsIGZpcnN0IGZpdmUgY29sdW1ucwogICAgKyBsYXN0IDEwIHJvd3Mgb2YgdGhlIG1ldGFkYXRhIG9iamVjdCwgY29sdW1ucyA3IHRvIDkKLSB2aXN1YWxpc2UgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgcGF0aWVudCBhZ2VzIHVzaW5nIGEgaGlzdG9ncmFtCi0gY2FsY3VsYXRlIHRoZSBhdmVyYWdlIGFnZSBvZiBwYXRpZW50cyBpbiB0aGUgc3R1ZHkgd2l0aCB0aGUgYG1lYW5gIGZ1bmN0aW9uCiAgICArIHdoYXQgZG8geW91IG5vdGljZSBhYm91dCB0aGUgcmVzdWx0PwogICAgKyBjYW4geW91IGNoYW5nZSB0aGUgYXJndW1lbnRzIHRvIG1lYW4gdG8gZ2V0IGEgbW9yZSBtZWFuaW5nZnVsIHJlc3VsdAoKCioqKioqKgoqKioqKioKKioqKioqCgoKYGBge3J9CiNGSUxMIElOIFNPTFVUSU9OUyBIRVJFCmBgYAoKU28gZmFyIHdlIGhhdmUgYmVlbiBhYmxlIHRvIHByaW50IG91dCBhIHN1YnNldCBvZiBvdXIgZGF0YSBieSBzcGVjaWZ5aW5nIGEgc2V0IG9mIG51bWVyaWMgaW5kaWNlcyAoZS5nLiBmaXJzdCAxMCByb3dzIGV0YykuIExldHMgc2F5IHdlJ3JlIGludGVyZXN0ZWQgaW4gaGlnaC1ncmFkZSB0dW1vdXJzLCBpbiB3aGljaCBjYXNlIHdlIG1pZ2h0IG5vdCBrbm93IGluIGFkdmFuY2Ugd2hpY2ggcm93cyB0aGVzZSBjb3JyZXNwb25kIHRvCgotIGA9PWAgYD5gLCBgPGAsIGAhPWAgY2FuIHVzZWQgdG8gbWFrZSBhICpsb2dpY2FsIGNvbXBhcmlzb24qCi0gcmVzdWx0IGlzIGEgYFRSVUVgIG9yIGBGQUxTRWAgaW5kaWNhdGluZyB3aGV0aGVyIGVhY2ggZW50cnkgc2F0aXNmaWVzIHRoZSB0ZXN0IGNvbmRpdGlvbiwgb3Igbm90LgogICAgKyBob3dldmVyLCBpZiBhIHBhcnRpY3VsYXIgZW50cnkgaW4gdGhlIHZlY3RvciBpcyBgTkFgIHRoZSByZXN1bHRpbmcgbG9naWNhbCB2ZWN0b3Igd2lsbCBoYXZlIGBOQWAgYXQgdGhlIHNhbWUgcG9zaXRpb25zCi0gTXVsdGlwbGUgY29tcGFyaXNvbnMgY2FuIGJlIGNvbWJpbmVkIHdpdGggdGhlIGxvZ2ljIG9wZXJhdG9ycyAqYW5kKiAoJikgYW5kICpvciogKHwpIAogICAgKyBUaGVyZSdzIGFsc28gKm5vdCogKCEpCgpgYGB7cn0KdGFibGUobWV0YWRhdGEkZ3JhZGUgPT0gMykKdGFibGUobWV0YWRhdGEkZ3JhZGUgPT0gMyx1c2VOQT0iaWZhbnkiKQpgYGAKClN1Y2ggYSBsb2dpY2FsIHZlY3RvciBjYW4gdGhlbiBiZSB1c2VkIGZvciBzdWJzZXR0aW5nCgotIGB3aGljaGAgY2FuIGJlIHVzZWQgdG8gbWFrZSBzdXJlIHRoZXJlIGFyZSBubyBgTkFgIHZhbHVlcyBpbiB0aGUgbG9naWNhbCB2ZWN0b3JzCiAgICArIGl0IGdpdmVzIHRoZSBudW1lcmljIGluZGljZXMgdGhhdCBjb3JyZXNwb25kIHRvIGBUUlVFYAotIGhlcmUsIHdlIGRvbid0IHNwZWNpZnkgYW55IGNvbHVtbiBpbmRpY2VzIGluc2lkZSB0aGUgYFtdYAogICAgKyBSIHdpbGwgcHJpbnQgYWxsIHRoZSBjb2x1bW5zCiAgICArIGhvd2V2ZXIsIGRvbid0IGZvcmdldCB0aGUgLAogICAgKyBpZiB5b3UgZG8sIFIgd2lsbCBzdGlsbCB0cnkgYW5kIGRvIHNvbWV0aGluZy4gSXQgYWxtb3N0IGNlcnRhaW5seSBiZSB3aGF0IHlvdSBleHBlY3RlZAoKYGBge3J9Cm1ldGFkYXRhW3doaWNoKG1ldGFkYXRhJGdyYWRlID09IDMpLF0KYGBgCgpDYW4gdXNlIHNhbWUgZXhwcmVzc2lvbiB0byBzdWJzZXQgdGhlIGNvbHVtbnMgb2YgdGhlIGV4cHJlc3Npb24gbWF0cml4CgotIHdoeSBjYW4gd2UgZG8gdGhpcz8gQmVjYXVzZSB0aGUgKmNvbHVtbnMqIG9mIHRoZSBleHByZXNzaW9uIG1hdHJpeCBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlICpyb3dzKiBvZiB0aGUgbWV0YWRhdGEKICAgICsgZG9uJ3QgYmVsaWV2ZSBtZT8gc2VlIGJlbG93Li4uCi0gdGhpcyBpc24ndCBhIGNvaW5jaWRlbmNlLiB0aGUgZGF0YSBoYXZlIGJlZW4gY2FyZWZ1bGx5IGN1cmF0ZWQgdG8gZW5zdXJlIHRoYXQgdGhpcyBpcyB0aGUgY2FzZQotIGRhdGEgc3RvcmVkIGluIG9ubGluZSByZXBvc2l0b3JpZXMgYXJlIG9mdGVuIG9yZ2FuaXNlZCBpbiB0aGlzIHdheQoKYGBge3IgZXZhbD1GQUxTRX0KaGVhZChjb2xuYW1lcyhlVmFsdWVzKSkKaGVhZChyb3duYW1lcyhtZXRhZGF0YSkpCnRhYmxlKGNvbG5hbWVzKGVWYWx1ZXMpID09IHJvd25hbWVzKG1ldGFkYXRhKSkKYGBgCgotIHdlIGNhbiBzdWJzZXQgdGhlIGV4cHJlc3Npb24gZGF0YSBhY2NvcmRpbmcgdG8gb3VyIGNsaW5pY2FsIGRhdGEKCmBgYHtyfQplVmFsdWVzWyx3aGljaChtZXRhZGF0YSRncmFkZT09MyldWzE6MTAsMToxMF0KYGBgCgotIGluIGZhY3QsIHdlIGNhbiBzdWJzZXQgdGhlIGVudGlyZSBgdmR4YCBvYmplY3QgYnkgc2FtcGxlIHN1YnNldHMgaWYgd2Ugd2lzaAoKYGBge3J9CnZkeFssd2hpY2gobWV0YWRhdGEkZ3JhZGU9PTMpXQpgYGAKClByZXZpb3VzbHksIHdlIHVzZWQgYSBib3hwbG90IHRvIHZpc3VhbGlzZSB0aGUgZXhwcmVzc2lvbiBsZXZlbHMgb2YgYWxsIGdlbmVzIGluIGEgZ2l2ZW4gc2FtcGxlIHRvIGxvb2sgZm9yIHRyZW5kcyBhY3Jvc3MgdGhlIGRhdGFzZXQuIEFub3RoZXIgdXNlIGZvciBhIGJveHBsb3QgaXMgdG8gdmlzdWFsaXNlIHRoZSBleHByZXNzaW9uIGxldmVsIG9mIGEgcGFydGljdWxhciBnZW5lIHdpdGggcmVzcGVjdCB0byB0aGUgc2FtcGxlIG1ldGFkYXRhCgotIHdlIGNhbiBleHRyYWN0IHRoZSBjb2x1bW4gb2YgaW50ZXJlc3Qgd2l0aCBhIGAkYCBhbmQgdXNlIHRoZSAqZm9ybXVsYSogc3ludGF4CiAgICArIGB0YWJsZWAgaW4gdGhpcyBjYXNlIHdpbGwgdGVsbCB1cyBob3cgbWFueSBvYnNlcnZhdGlvbnMgb2YgZWFjaCBjYXRlZ29yeSBhcmUgcHJlc2VudAotIFIgd2lsbCBiZSBjbGV2ZXIgYW5kIGNvbnZlcnQgdGhlIGZhY3RvciBpbnRvIGEgYGZhY3RvcmAgdHlwZSBpZiByZXF1aXJlZAoKYGBge3J9CmZhYyA8LSBtZXRhZGF0YSRlcgp0YWJsZShmYWMpCmJveHBsb3QoZVZhbHVlc1sxLF0gfiBmYWMsCiAgICAgICAgeGxhYj0iRVIgU3RhdHVzIiwKICAgICAgICB5bGFiPSJFeHByZXNzaW9uIExldmVsIiwKICAgICAgICBjb2w9Yygic3RlZWxibHVlIiwiZ29sZGVucm9kIikpCmBgYAoKUGVyZm9ybWluZyBhIHRlc3QgdG8gYXNzZXNzIHNpZ25pZmljYW5jZSBmb2xsb3dzIHNpbWlsYXIgc3ludGF4CgotIGB0LnRlc3RgIGlzIHRoZSBnZW5lcmljIGZ1bmN0aW9uIHRvIHBlcmZvcm0gYSB0LXRlc3QsIGFuZCBjYW4gYmUgYWRhcHRlZCB0byBkaWZmZXJlbnQgY2lyY3Vtc3RhbmNlcwogICAgKyBlLmcuIGlmIG91ciBkYXRhIGFyZSBwYWlyZWQsIG9yIG5vdAogICAgKyBzZWUgdGhlIGhlbHAgZm9yIGB0LnRlc3RgIGZvciBtb3JlIGRldGFpbHMKLSBmb3Igbm93LCB3ZSB3aWxsIGdsb3NzIG92ZXIgdGVzdGluZyBhc3N1bXB0aW9ucyBvbiB0aGUgZGF0YSBzdWNoIGFzIHJlcXVpcmluZyBhICpub3JtYWwqIChHYXVzc2lhbikgZGlzdHJpYnV0aW9uIGFuZCBtdWx0aXBsZSB0ZXN0aW5nIGNvcnJlY3Rpb24KICAgIAoKYGBge3J9CnQudGVzdChlVmFsdWVzWzEsXX5mYWMpCmBgYAoKIyMgQWNjZXNzaW5nIGZlYXR1cmUgKGdlbmUpIGluZm9ybWF0aW9uIAoKV2UgY291bGQgYmUgbHVja3ksIGFuZCB0aGUgZmlyc3Qgcm93IGluIHRoZSBleHByZXNzaW9uIG1hdHJpeCBjb3VsZCBiZSBvdXIgZmF2b3VyaXRlIGdlbmUgb2YgaW50ZXJlc3QhIEhvd2V2ZXIsIHRoaXMgaXMgdW5saWtlbHkgdG8gYmUgdGhlIGNhc2UgYW5kIHdlIHdpbGwgaGF2ZSB0byBmaWd1cmUgb3V0IHdoaWNoIHJvdyB3ZSB3YW50IHRvIHBsb3QKCi0gd2UgY2FuIHVzZSBhbm90aGVyIGFzcGVjdCBvZiB0aGUgYG5raWAgb2JqZWN0OyB0aGUgKmZlYXR1cmUgZGF0YSoKLSB0aGVyZSBpcyBhIGhhbmR5IGBmRGF0YWAgZnVuY3Rpb24gdG8gYWNjZXNzIHRoZXNlIGRhdGEKLSBhZ2FpbiwgdGhpcyBnaXZlcyB1cyBhICpkYXRhIGZyYW1lKgotIHRoaXMgaXMgYSBwcmUtYnVpbHQgdGFibGUgc3VwcGxpZWQgd2l0aCB0aGUgZGF0YXNldAogICAgKyBsYXRlciBpbiB0aGUgY291cnNlIHdlIHdpbGwgbG9vayBhdCB1c2luZyBvbmxpbmUgc2VydmljZXMgYW5kIGRhdGFiYXNlcyBmb3IgYW5ub3RhdGlvbiBhbmQgY29udmVydGluZyBiZXR3ZWVuIGlkZW50aWZpZXJzCgpgYGB7cn0KZmVhdHVyZXMgPC0gZkRhdGEodmR4KSAjdHJ5IHRvIGZpZ3VyZSBvdXQgdGhlIGxvY2F0aW9uIGluIG1lbW9yeSBvZiB0aGlzIGRhdGEuZnJhbWUgdmlhIEAgYW5kICQKY2xhc3MoZmVhdHVyZXMpCmhlYWQoZmVhdHVyZXNbLDE6NV0pCmNvbG5hbWVzKGZlYXR1cmVzKQpgYGAKCkFzIHdlIGtub3csIGdlbmUgc3ltYm9scyAobW9yZS1jb21tb24gZ2VuZSBuYW1lcykgY2FuIGJlIGFjY2Vzc2VkIHVzaW5nIHRoZSBgJGAgc3ludGF4OyByZXR1cm5pbmcgYSB2ZWN0b3IKCmBgYHtyfQpoZWFkKGZlYXR1cmVzJEdlbmUuc3ltYm9sKQpgYGAKCldlIGNvdWxkIGluc3BlY3QgdGhlIGRhdGEgZnJhbWUgbWFudWFsbHkgKGUuZy4gdXNpbmcgYFZpZXcoZmVhdHVyZXMpYCkgYW5kIGlkZW50aWZ5IHRoZSByb3cgbnVtYmVyIGNvcnJlc3BvbmRpbmcgdG8gb3VyIGdlbmUgb2YgaW50ZXJlc3QuIEhvd2V2ZXIsIGFzIGFzcGlyaW5nIFIgcHJvZ3JhbW1lcnMsIHRoZXJlIGlzIGEgYmV0dGVyIHdheQoKLSBgPT1gIHRvIHRlc3QgZm9yIGV4YWN0IG1hdGNoaW5nCi0gYG1hdGNoYCB3aWxsIHJldHVybiB0aGUgKmluZGV4KiBvZiB0aGUgZmlyc3QgbWF0Y2gKLSBgZ3JlcGAgY2FuIGJlIHVzZWQgZm9yIHBhcnRpYWwgbWF0Y2hlcwotIGVhY2ggb2YgdGhlIGFib3ZlIHdpbGwgZ2l2ZSBhbiAqdmVjdG9yKiB0aGF0IGNhbiBiZSB1c2VkIHRvIHN1YnNldCB0aGUgZXhwcmVzc2lvbiB2YWx1ZXMKCmBgYHtyfQp3aGljaChmZWF0dXJlcyRHZW5lLnN5bWJvbCA9PSAiQlJDQTEiKQptYXRjaCgiQlJDQTEiLGZlYXR1cmVzJEdlbmUuc3ltYm9sKQpncmVwKCJCUkNBMSIsZmVhdHVyZXMkR2VuZS5zeW1ib2wpCmdyZXAoIkJSQ0EiLGZlYXR1cmVzJEdlbmUuc3ltYm9sKQpgYGAKCgoqKioqKioKKioqKioqCioqKioqKgoKCiMjIEV4ZXJjaXNlCgotIFZlcmlmeSB0aGF0IHRoZSByb3dzIG9mIHRoZSBmZWF0dXJlIG1hdHJpeCBhbmQgdGhlIGV4cHJlc3Npb24gdmFsdWVzIGFyZSBpbiB0aGUgc2FtZSBvcmRlcgotIEZpbmQgdGhlIHJvdyBjb3JyZXNwb25kaW5nIHRvIHlvdXIgZmF2b3VyaXRlIGdlbmUKICAgICsgaWYgeW91IGRvbid0IGhhdmUgb25lLCB0cnkgYEVTUjFgCiAgICArIGlmIHlvdSBmaW5kIG11bHRpcGxlIG1hdGNoZXMsIHBpY2sgdGhlIGZpcnN0IG9uZSB0aGF0IG9jY3VycwotIERvZXMgdGhlIGV4cHJlc3Npb24gbGV2ZWwgb2YgdGhpcyBnZW5lIGFwcGVhciB0byBiZSBhc3NvY2lhdGVkIHdpdGggdGhlIEVSIHN0YXR1cz8KCioqKioqKgoqKioqKioKKioqKioqCgoKYGBge3J9CiNGSUxMIElOIFNPTFVUSU9OUyBIRVJFCmBgYAoKCiMjIFRlc3RpbmcgYWxsIGdlbmVzIGZvciBzaWduaWZpY2FuY2UKCkxhdGVyIGluIHRoZSBjb3Vyc2Ugd2Ugd2lsbCBzZWUgaG93IHRvIGV4ZWN1dGUgYSAqZGlmZmVyZW50aWFsIGV4cHJlc3Npb24qIGFuYWx5c2lzIGZvciBSTkEtc2VxIGRhdGEsIGFuZCBkaXNjdXNzIHNvbWUgb2YgdGhlIGlzc3VlcyBzdXJyb3VuZGluZyB0aGlzLiBGb3Igbm93IHdlIHdpbGwgcGVyZm9ybSBhIHNpbXBsZSB0d28tc2FtcGxlIHQtdGVzdCBmb3IgYWxsIGdlbmVzIGluIG91ciBzdHVkeSwgYW5kIGRlcml2ZSBhIHJlc3VsdHMgdGFibGUKCi0gZmlyc3RseSwgd2UgbG9hZCB0aGUgYGdlbmVmaWx0ZXJgIHBhY2thZ2Ugd2hpY2ggaGFzIGEgdmVyeSBjb252ZW5pZW50IGZ1bmN0aW9uIGZvciBwZXJmb3JtaW5nIG1hbnkgdCB0ZXN0cyBpbiBwYXJhbGxlbAotIGByb3d0dGVzdHNgIHdpbGwgcnVuIGEgdC10ZXN0IGZvciBlYWNoIHJvdyBpbiBhIGdpdmVuIG1hdHJpeCBhbmQgcHJvZHVjZSBhbiBvdXRwdXQgdGFibGUKICAgICsgYHN0YXRpc3RpY2A7IHRlc3Qgc3RhdGlzdGljCiAgICArIGBkbWA7IGRpZmZlcmVuY2UgaW4gbWVhbnMKICAgICsgYHAudmFsdWVgOyB0aGUgcC12YWx1ZQotIGByb3d0dGVzdHNgIGV4cGVjdHMgYSAqZmFjdG9yKiBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50LCBzbyB3ZSBoYXZlIHRvIHVzZSBgYXMuZmFjdG9yYAogICAgKyBhcyB1c3VhbCwgd2UgY2FuIGdldCBoZWxwIGJ5IGRvaW5nIGA/cm93dHRlc3RzYAogICAgCmBgYHtyfQpsaWJyYXJ5KGdlbmVmaWx0ZXIpCnRzdGF0cyA8LSByb3d0dGVzdHMoZVZhbHVlcywgYXMuZmFjdG9yKG1ldGFkYXRhJGVyKSkKaGVhZCh0c3RhdHMpCmhpc3QodHN0YXRzJHN0YXRpc3RpYykKYGBgCgpUaGUgcm93cyBhcmUgb3JkZXJlZCBpbiB0aGUgc2FtZSB3YXkgYXMgdGhlIGlucHV0IG1hdHJpeAoKLSB0byBjaGFuZ2UgdGhpcyB0byBpbmNyZWFzaW5nIHNpZ25pZmljYW5jZSB3ZSBjYW4gdXNlIHRoZSBgb3JkZXJgIGZ1bmN0aW9uCi0gd2hlbiBnaXZlbiBhIHZlY3RvciwgYG9yZGVyYCB3aWxsIHJldHVybiBhIHZlY3RvciBvZiB0aGUgc2FtZSBsZW5ndGggZ2l2aW5nIHRoZSBwZXJtdXRhdGlvbiB0aGF0IHJlYXJyYW5nZXMgdGhhdCB2ZWN0b3IgaW50byBhc2NlbmRpbmcgb3IgZGVzY2VuZGluZyBvcmRlcgotIFRoZSBgc29ydGAgZnVuY3Rpb24gc2hvcnRjdXRzIHVzaW5nIHRoZSBvdXRwdXQgb2YgYG9yZGVyYCB0byByZWFycmFuZ2UgdGhlIG9yaWdpbmFsIHZlY3RvciBieSByZXR1cm5pbmcgdGhlIHNvcnRlZCB2ZWN0b3IKCmBgYHtyfQp4IDwtIGMoOSwgMywgNCwgMiwgMSwgNiw1LCAxMCwgOCwgNykKeApvcmRlcih4KQp4W29yZGVyKHgpXQpzb3J0KHgpCmBgYAoKLSBzbyBpZiB3ZSB3YW50IHRvIG9yZGVyIGJ5IHAtdmFsdWUgd2UgZmlyc3QgdXNlIG9yZGVyIG9uIHRoZSBwLXZhbHVlIHZlY3RvcgotIHRoaXMgY2FuIHRoZW4gYmUgdXNlZCB0byByZS1hcnJhbmdlIHRoZSByb3dzIG9mIHRoZSB0YWJsZQoKYGBge3J9CmhlYWQodHN0YXRzW29yZGVyKHRzdGF0cyRwLnZhbHVlLGRlY3JlYXNpbmcgPSBGQUxTRSksXSkKYGBgCgoKSG93ZXZlciwgdGhlIHRhYmxlIHdlIGdldCBpc24ndCBpbW1lZGlhdGVseSB1c2VmdWwgdW5sZXNzIHdlIGNhbiByZWNvZ25pc2UgdGhlIG1hbnVmYWN0dXJlciBwcm9iZSBJRHMKCi0gdG8gcHJvdmlkZSBleHRyYSBhbm5vdGF0aW9uIHRvIHRoZSB0YWJsZSwgd2UgY2FuICpjb2x1bW4gYmluZCogKGBjYmluZGApIHRoZSBjb2x1bW5zIG9mIHRlc3Qgc3RhdGlzdGljIHdpdGggdGhvc2UgZnJvbSB0aGUgZmVhdHVyZSBtYXRyaXgKLSBiZSBjYXJlZnVsIHRob3VnaCwgd2UgY2FuIG9ubHkgZG8gdGhpcyBpbiBjYXNlcyB3aGVyZSB0aGUgcm93cyBhcmUgaW4gZGlyZWN0IGNvcnJlc3BvbmRlbmNlCgpgYGB7cn0KdGFibGUocm93bmFtZXModHN0YXRzKSA9PSByb3duYW1lcyhmZWF0dXJlcykpCnRzdGF0cy5hbm5vdGF0ZWQgPC0gY2JpbmQodHN0YXRzLCBmZWF0dXJlc1ssYygiR2VuZS5zeW1ib2wiLCJFbnRyZXpHZW5lLklEIiwiQ2hyb21vc29tZS5sb2NhdGlvbiIpXSkKaGVhZCh0c3RhdHMuYW5ub3RhdGVkKQpgYGAKCk5vdyB3aGVuIHdlIG9yZGVyIGJ5IHAtdmFsdWUsIHRoZSBleHRyYSBjb2x1bW5zIHRoYXQgd2UganVzdCBhZGRlZCBhbGxvdyB1cyB0byBpbnRlcnByZXQgdGhlIHJlc3VsdHMgbW9yZSBlYXNpbHkKCmBgYHtyfQp0c3RhdHMub3JkZXJlZCA8LSB0c3RhdHMuYW5ub3RhdGVkW29yZGVyKHRzdGF0cyRwLnZhbHVlLGRlY3JlYXNpbmcgPSBGQUxTRSksXQpoZWFkKHRzdGF0cy5vcmRlcmVkKQpgYGAKCldlIGNhbiBhbHNvIHF1ZXJ5IHRoaXMgdGFibGUgdG8gbG9vayBmb3Igb3VyIGZhdm91cml0ZSBnZW5lcyBvZiBpbnRlcmVzdAoKLSBgJWluJWAgaXMgYSBzaW1wbGlmaWVkIHdheSB0byBwZXJmb3JtIG1hdGNoZXMgdG8gbXVsdGlwbGUgaXRlbXMgaW4gYSB2ZWN0b3IKCmBgYHtyfQp0c3RhdHMub3JkZXJlZFtncmVwKCJFU1IxIix0c3RhdHMub3JkZXJlZCRHZW5lLnN5bWJvbCksXQp0c3RhdHMub3JkZXJlZFt0c3RhdHMub3JkZXJlZCRHZW5lLnN5bWJvbCAlaW4lIGMoIkVTUjEiLCJHQVRBMyIsIkZPWEExIiksXQpgYGAKCgoKKioqKioqCioqKioqKgoqKioqKioKCgojIyBFeGVyY2lzZQoKLSBGcm9tIHRoZSBhbm5vdGF0ZWQgdGFibGUgYWJvdmUsIHNlbGVjdCBhbGwgZ2VuZXMgd2l0aCBwLXZhbHVlcyBsZXNzIHRoYW4gMC4wNQotIFdyaXRlIHRoaXMgZGF0YSBmcmFtZSBhcyBhIGBjc3ZgIGZpbGUgKGhpbnQ6IHVzZSBgd3JpdGUuY3N2YCkKICArIENoZWNrIHRoZSBvdXRwdXR0ZWQgZmlsZS4gSXMgdGhlcmUgYW55dGhpbmcgd2VpcmQgYWJvdXQgaXQ/Ci0gVXNlIHRoZSBgcC5hZGp1c3RgIHRvIHByb2R1Y2UgYSB2ZWN0b3Igb2YgcC12YWx1ZXMgdGhhdCBhcmUgYWRqdXN0ZWQuIEFkZCB0aGlzIGFzIGFuIGV4dHJhIGNvbHVtbiB0byB5b3VyIHRhYmxlIG9mIHJlc3VsdHMgYW5kIHdyaXRlIGFzIGEgZmlsZQoKKioqKioqCioqKioqKgoqKioqKioKCmBgYHtyfQojRklMTCBJTiBTT0xVVElPTlMgSEVSRQpgYGA=