The data used here is from jci research article. Study is about Silencing (KO) the gene SMOC2 protects from kidney fibrosis. so the data is of this format: WT_norm, WT_fibrosis, SMOC2_overexpression_normal, SMOC2_overexpression_fibrosis

#setwd("D:/shilpa/RNAseq/datacamp")
library(DESeq2)
library(RColorBrewer)
library(pheatmap)
library(tidyverse)
raw_count_matrix <- read.csv('fibrosis_smoc2_rawcounts_unordered.csv')
ggplot(raw_count_matrix) + geom_histogram(aes(x=smoc2_normal1), stat="bin", bins= 200) + xlab("Raw expression counts") + ylab("Number of genes") + xlim(0, 25000) + ylim(0, 5000)

The gene SMOC2, bound to fate, its expression studies we now undertake, with this spirit now we shall see how our data looks like

head(raw_count_matrix)
str(raw_count_matrix)
'data.frame':   47729 obs. of  8 variables:
 $ X              : chr  "ENSMUSG00000102693" "ENSMUSG00000064842" "ENSMUSG00000051951" "ENSMUSG00000102851" ...
 $ smoc2_fibrosis1: int  0 0 72 0 0 0 0 0 0 1 ...
 $ smoc2_fibrosis4: int  0 0 30 0 0 0 0 0 0 1 ...
 $ smoc2_normal1  : int  0 0 0 0 1 0 0 0 0 1 ...
 $ smoc2_normal3  : int  0 0 3 0 0 0 0 0 0 0 ...
 $ smoc2_fibrosis3: int  0 0 36 0 0 0 0 0 0 1 ...
 $ smoc2_normal4  : int  0 0 1 0 0 0 0 0 0 0 ...
 $ smoc2_fibrosis2: int  0 0 51 0 0 0 0 0 0 1 ...

With a steady hand and keen eye, we shall forge the metadata to construct our DESeq2 object!

genotype <- c("smoc2_oe", "smoc2_oe", "smoc2_oe", "smoc2_oe", "smoc2_oe", "smoc2_oe", "smoc2_oe")
condition <- c("fibrosis", "fibrosis", "fibrosis", "fibrosis", "normal", "normal", "normal")
metadata <- data.frame(genotype, condition)

# Assign the row names of the data frame
rownames(metadata) <- c("smoc2_fibrosis1", "smoc2_fibrosis2", "smoc2_fibrosis3", "smoc2_fibrosis4", "smoc2_normal1", "smoc2_normal3", "smoc2_normal4")

metadata
NA

While there are many packages for DE analysis, we are going to use DESeq2. It has one of more popular ones and its vignetter is pretty helpful. DESeq2 models the gene expression (count data) by negetive binomial distribution.

The raw data from ncbi GEO has already been preprocessed (QC steps & counts).

What is a count matrix: count matrix represents number of reads matching the exons of each gene. Barcodes (for each cell) and UMI (for each gene) information is used to generate this matrix. A little bit about count matrix:

NOTE: DESeq2 model internally corrects for the library size so transformed or normalized values such as counts scaled by library size should not be used as input.

Bringing in data for DESeq2: we need to bring the samples from metadata and countdata in the same order

#metadata <- read.csv("metadata.csv")

#all(colnames(raw_count_matrix) == rownames(metadata))

# Use the match() function to reorder the columns of the raw counts
reorder_idx <- match(rownames(metadata), colnames(raw_count_matrix))

# Reorder the columns of the count data
reordered_raw_count_matrix <- raw_count_matrix[ , reorder_idx]
# Create a DESeq2 object (DESeqDataSet dds)
dds <- DESeqDataSetFromMatrix(countData = reordered_raw_count_matrix,
                                    colData = metadata,
                                    design = ~ condition)
Warning: some variables in design formula are characters, converting to factors
# design formula is used to estimate the dispersions and to estimate the log2 fold changes of the model

dds
class: DESeqDataSet 
dim: 47729 7 
metadata(1): version
assays(1): counts
rownames: NULL
rowData names(0):
colnames(7): smoc2_fibrosis1 smoc2_fibrosis2 ... smoc2_normal3 smoc2_normal4
colData names(2): genotype condition

There are 4 ways of constructing DESeqDataSet depending on which pipeline is used upstream. We have count matrix here so we use ‘countData’ while constructing dds. Now we can explore the data with DESeq2 functions and perform the differential expression analysis.

NORMALIZING COUNTS WITH DESeq2 -> normalized for library size while accounting for library composition (library size is the total number of gene counts per sample)

dds <- estimateSizeFactors(dds)
normalized_counts <- counts(dds, normalized=TRUE)

We will be using the normalized counts to explore similarities in gene expression between each of our samples. To do this we use clustering after using dimensional reduction. Before clustering, we need to log transform the normalized counts to improve the visualization of the clustering and hence our understanding. we can use DESeq2’s vst() function. vst stands for Variance stabilizing transformation. The transformed data should be approximated variance stabilized and also includes correction for size factors or normalization factors. The transformed data is on the log2 scale for large counts. The blind=TRUE argument specifies that the transformation should be blind to the sample information given in the design formula; this argument should be specified when performing quality assessment.

vsd_trans <- vst(dds, blind = TRUE)
vsd_trans
class: DESeqTransform 
dim: 47729 7 
metadata(1): version
assays(1): ''
rownames: NULL
rowData names(4): baseMean baseVar allZero dispFit
colnames(7): smoc2_fibrosis1 smoc2_fibrosis2 ... smoc2_normal3 smoc2_normal4
colData names(3): genotype condition sizeFactor

From vsd, we need to extract the VST-trasformed normalized counts as a matrix

vsd_mat <- assay(vsd_trans)

Then, we need to compute the pairwise correlation values between each pair of samples

vsd_cor <- cor(vsd_mat)

Now we do clustering. We choose Hierarchical clustering here.

pheatmap(vsd_cor, annotation = select(metadata, condition)) 

This heatmap shows us that the biological replicates cluster together (as expected, phew…). This is a good sign because, very likely our differentially expressed genes must be driving this separation. Also we do not see any outliers.

We will crosscheck this with PCA (QC step 2)

plotPCA(vsd_trans, intgroup="condition")

Now that we have explored the quality of the samples, checked for outliers, we can go ahead and find which genes have significant differences in expression between the normal and fibrosis sample groups.

At this stage we do not need to re-create the object since we have not removed samples or found additional sources of variation during QC steps.

dds_run <- DESeq(dds)
using pre-existing size factors
estimating dispersions
gene-wise dispersion estimates
mean-dispersion relationship
final dispersion estimates
fitting model and testing
dds_run
class: DESeqDataSet 
dim: 47729 7 
metadata(1): version
assays(4): counts mu H cooks
rownames: NULL
rowData names(22): baseMean baseVar ... deviance maxCooks
colnames(7): smoc2_fibrosis1 smoc2_fibrosis2 ... smoc2_normal3 smoc2_normal4
colData names(3): genotype condition sizeFactor
mean_counts <- apply(raw_count_matrix[,1:3], 1, mean)

Dispersion estimates are used to model the raw counts; if the dispersions don’t follow the assumptions made by DESeq2, then the variation in the data could be poorly estimated and outout of which genes are differentially expressed could be wrong. The assumptions made by DESeq2 are:

plotDispEsts(dds_run)

From the dispersion plot we can see that fit of our data to the model is pretty good. Gene-est is estimated dispersion of the genes.

Plotting the dispersion estimates is a useful diagnostic. The dispersion plot which we see here is a typical one with the final estimates shrunk from the gene-wise estimates towards the fitted estimates. Some gene-wise estimates are flagged (open circles) as outliers and not shrunk towards the fitted value.

res0.01 <- results(dds_run,alpha = 0.01)
summary(res0.01)

out of 29556 with nonzero total read count
adjusted p-value < 0.01
LFC > 0 (up)       : 4534, 15%
LFC < 0 (down)     : 4798, 16%
outliers [1]       : 15, 0.051%
low counts [2]     : 8317, 28%
(mean count < 2)
[1] see 'cooksCutoff' argument of ?results
[2] see 'independentFiltering' argument of ?results
# contrasts
resultsNames(dds_run)
[1] "Intercept"                    "condition_normal_vs_fibrosis"
# MA plot
plotMA(res0.01)

LS0tDQp0aXRsZTogIkFuYWx5c2lzIG9mIGRpZmZlcmVudGlhbCBnZW5lIGV4cHJlc3Npb24gaW4gREVTZXEgaW4gUiBOb3RlYm9vayINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClRoZSBkYXRhIHVzZWQgaGVyZSBpcyBmcm9tIFtqY2kgcmVzZWFyY2ggYXJ0aWNsZV0oaHR0cHM6Ly9pbnNpZ2h0LmpjaS5vcmcvYXJ0aWNsZXMvdmlldy85MDI5OSkuDQpTdHVkeSBpcyBhYm91dCBTaWxlbmNpbmcgKEtPKSB0aGUgZ2VuZSBTTU9DMiBwcm90ZWN0cyBmcm9tIGtpZG5leSBmaWJyb3Npcy4NCnNvIHRoZSBkYXRhIGlzIG9mIHRoaXMgZm9ybWF0OiBXVF9ub3JtLCBXVF9maWJyb3NpcywgU01PQzJfb3ZlcmV4cHJlc3Npb25fbm9ybWFsLCBTTU9DMl9vdmVyZXhwcmVzc2lvbl9maWJyb3Npcw0KDQpgYGB7cn0NCiNzZXR3ZCgiRDovc2hpbHBhL1JOQXNlcS9kYXRhY2FtcCIpDQpsaWJyYXJ5KERFU2VxMikNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeShwaGVhdG1hcCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KYGBgDQoNCg0KYGBge3J9DQpyYXdfY291bnRfbWF0cml4IDwtIHJlYWQuY3N2KCdmaWJyb3Npc19zbW9jMl9yYXdjb3VudHNfdW5vcmRlcmVkLmNzdicpDQpnZ3Bsb3QocmF3X2NvdW50X21hdHJpeCkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeD1zbW9jMl9ub3JtYWwxKSwgc3RhdD0iYmluIiwgYmlucz0gMjAwKSArIHhsYWIoIlJhdyBleHByZXNzaW9uIGNvdW50cyIpICsgeWxhYigiTnVtYmVyIG9mIGdlbmVzIikgKyB4bGltKDAsIDI1MDAwKSArIHlsaW0oMCwgNTAwMCkNCmBgYA0KVGhlIGdlbmUgU01PQzIsIGJvdW5kIHRvIGZhdGUsIGl0cyBleHByZXNzaW9uIHN0dWRpZXMgd2Ugbm93IHVuZGVydGFrZSwgd2l0aCB0aGlzIHNwaXJpdCBub3cgd2Ugc2hhbGwgc2VlIGhvdyBvdXIgZGF0YSBsb29rcyBsaWtlDQoNCmBgYHtyfQ0KaGVhZChyYXdfY291bnRfbWF0cml4KQ0KYGBgDQpgYGB7cn0NCnN0cihyYXdfY291bnRfbWF0cml4KQ0KDQpgYGANCldpdGggYSBzdGVhZHkgaGFuZCBhbmQga2VlbiBleWUsIHdlIHNoYWxsIGZvcmdlIHRoZSBtZXRhZGF0YSB0byBjb25zdHJ1Y3Qgb3VyIERFU2VxMiBvYmplY3QhDQoNCmBgYHtyfQ0KZ2Vub3R5cGUgPC0gYygic21vYzJfb2UiLCAic21vYzJfb2UiLCAic21vYzJfb2UiLCAic21vYzJfb2UiLCAic21vYzJfb2UiLCAic21vYzJfb2UiLCAic21vYzJfb2UiKQ0KY29uZGl0aW9uIDwtIGMoImZpYnJvc2lzIiwgImZpYnJvc2lzIiwgImZpYnJvc2lzIiwgImZpYnJvc2lzIiwgIm5vcm1hbCIsICJub3JtYWwiLCAibm9ybWFsIikNCm1ldGFkYXRhIDwtIGRhdGEuZnJhbWUoZ2Vub3R5cGUsIGNvbmRpdGlvbikNCg0KIyBBc3NpZ24gdGhlIHJvdyBuYW1lcyBvZiB0aGUgZGF0YSBmcmFtZQ0Kcm93bmFtZXMobWV0YWRhdGEpIDwtIGMoInNtb2MyX2ZpYnJvc2lzMSIsICJzbW9jMl9maWJyb3NpczIiLCAic21vYzJfZmlicm9zaXMzIiwgInNtb2MyX2ZpYnJvc2lzNCIsICJzbW9jMl9ub3JtYWwxIiwgInNtb2MyX25vcm1hbDMiLCAic21vYzJfbm9ybWFsNCIpDQoNCm1ldGFkYXRhDQoNCmBgYA0KDQpXaGlsZSB0aGVyZSBhcmUgbWFueSBwYWNrYWdlcyBmb3IgREUgYW5hbHlzaXMsIHdlIGFyZSBnb2luZyB0byB1c2UgREVTZXEyLiBJdCBoYXMgb25lIG9mIG1vcmUgcG9wdWxhciBvbmVzIGFuZCBpdHMgdmlnbmV0dGVyIGlzIHByZXR0eSBoZWxwZnVsLiANCkRFU2VxMiBtb2RlbHMgdGhlIGdlbmUgZXhwcmVzc2lvbiAoY291bnQgZGF0YSkgYnkgbmVnZXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uLg0KDQpUaGUgcmF3IGRhdGEgZnJvbSBuY2JpIEdFTyBoYXMgYWxyZWFkeSBiZWVuIHByZXByb2Nlc3NlZCAoUUMgc3RlcHMgJiBjb3VudHMpLg0KDQpXaGF0IGlzIGEgY291bnQgbWF0cml4OiANCmNvdW50IG1hdHJpeCByZXByZXNlbnRzIG51bWJlciBvZiByZWFkcyBtYXRjaGluZyB0aGUgZXhvbnMgb2YgZWFjaCBnZW5lLiBCYXJjb2RlcyAoZm9yIGVhY2ggY2VsbCkgYW5kIFVNSSAoZm9yIGVhY2ggZ2VuZSkgaW5mb3JtYXRpb24gaXMgdXNlZCB0byBnZW5lcmF0ZSB0aGlzIG1hdHJpeC4NCkEgbGl0dGxlIGJpdCBhYm91dCBjb3VudCBtYXRyaXg6DQoNCi0gVGhlIG5lZ2F0aXZlIGJpbm9taWFsIG1vZGVsIGNvbW1vbmx5IHVzZWQgdG8gbW9kZWwgUk5BLXNlcSBjb3VudCBkYXRhDQoNCi0gaXQgaXMgZGlzY3JldGUgYW5kIGl0IHN0YXJ0cyB3aXRoIHplcm8uDQoNCi0gSGlnaGVzdCBmcmVxdWVuY3kgbmVhciB6ZXJvIGkuZS4gbWFueSBnZW5lcyBoYXZlIGxvdyBudW1iZXIgb2YgY291bnRzDQoNCi0gVGhlIGV4cHJlc3Npb24gcmFuZ2UgaXMgYmV0d2VlbiB6ZXJvIHRvIGluZiAobm8gbWF4IGxpbWl0KQ0KDQotIEZvciBkaXNjcmV0ZSBudW1iZXJzIGkuZS4gY291bnRzIG9uZSBjb3VsZCBhbHNvIHVzZSBwb2lzc29uIGJ1dCB0aGVyZSBpcyB0b28gbXVjaCB2YXJpYXRpb24gaW4gdGhlIGRhdGEgdGhhbiBwb2lzc29uIGNhbiBoYW5kbGUNCg0KTk9URTogREVTZXEyIG1vZGVsIGludGVybmFsbHkgY29ycmVjdHMgZm9yIHRoZSBsaWJyYXJ5IHNpemUgc28gdHJhbnNmb3JtZWQgb3Igbm9ybWFsaXplZCB2YWx1ZXMgc3VjaCBhcyBjb3VudHMgc2NhbGVkIGJ5IGxpYnJhcnkgc2l6ZSBzaG91bGQgbm90IGJlIHVzZWQgYXMgaW5wdXQuDQoNCkJyaW5naW5nIGluIGRhdGEgZm9yIERFU2VxMjogd2UgbmVlZCB0byBicmluZyB0aGUgc2FtcGxlcyBmcm9tIG1ldGFkYXRhIGFuZCBjb3VudGRhdGEgaW4gdGhlIHNhbWUgb3JkZXINCg0KYGBge3J9DQojbWV0YWRhdGEgPC0gcmVhZC5jc3YoIm1ldGFkYXRhLmNzdiIpDQoNCiNhbGwoY29sbmFtZXMocmF3X2NvdW50X21hdHJpeCkgPT0gcm93bmFtZXMobWV0YWRhdGEpKQ0KDQojIFVzZSB0aGUgbWF0Y2goKSBmdW5jdGlvbiB0byByZW9yZGVyIHRoZSBjb2x1bW5zIG9mIHRoZSByYXcgY291bnRzDQpyZW9yZGVyX2lkeCA8LSBtYXRjaChyb3duYW1lcyhtZXRhZGF0YSksIGNvbG5hbWVzKHJhd19jb3VudF9tYXRyaXgpKQ0KDQojIFJlb3JkZXIgdGhlIGNvbHVtbnMgb2YgdGhlIGNvdW50IGRhdGENCnJlb3JkZXJlZF9yYXdfY291bnRfbWF0cml4IDwtIHJhd19jb3VudF9tYXRyaXhbICwgcmVvcmRlcl9pZHhdDQojIENyZWF0ZSBhIERFU2VxMiBvYmplY3QgKERFU2VxRGF0YVNldCBkZHMpDQpkZHMgPC0gREVTZXFEYXRhU2V0RnJvbU1hdHJpeChjb3VudERhdGEgPSByZW9yZGVyZWRfcmF3X2NvdW50X21hdHJpeCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSBtZXRhZGF0YSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH4gY29uZGl0aW9uKQ0KIyBkZXNpZ24gZm9ybXVsYSBpcyB1c2VkIHRvIGVzdGltYXRlIHRoZSBkaXNwZXJzaW9ucyBhbmQgdG8gZXN0aW1hdGUgdGhlIGxvZzIgZm9sZCBjaGFuZ2VzIG9mIHRoZSBtb2RlbA0KDQpkZHMNCg0KYGBgDQpUaGVyZSBhcmUgNCB3YXlzIG9mIGNvbnN0cnVjdGluZyBERVNlcURhdGFTZXQgZGVwZW5kaW5nIG9uIHdoaWNoIHBpcGVsaW5lIGlzIHVzZWQgdXBzdHJlYW0uIFdlIGhhdmUgY291bnQgbWF0cml4IGhlcmUgc28gd2UgdXNlICdjb3VudERhdGEnIHdoaWxlIGNvbnN0cnVjdGluZyBkZHMuDQpOb3cgd2UgY2FuIGV4cGxvcmUgdGhlIGRhdGEgd2l0aCBERVNlcTIgZnVuY3Rpb25zIGFuZCBwZXJmb3JtIHRoZSBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcy4NCg0KTk9STUFMSVpJTkcgQ09VTlRTIFdJVEggREVTZXEyDQotPiBub3JtYWxpemVkIGZvciBsaWJyYXJ5IHNpemUgd2hpbGUgYWNjb3VudGluZyBmb3IgbGlicmFyeSBjb21wb3NpdGlvbiAobGlicmFyeSBzaXplIGlzIHRoZSB0b3RhbCBudW1iZXIgb2YgZ2VuZSBjb3VudHMgcGVyIHNhbXBsZSkNCg0KYGBge3J9DQpkZHMgPC0gZXN0aW1hdGVTaXplRmFjdG9ycyhkZHMpDQpub3JtYWxpemVkX2NvdW50cyA8LSBjb3VudHMoZGRzLCBub3JtYWxpemVkPVRSVUUpDQoNCmBgYA0KIFdlIHdpbGwgYmUgdXNpbmcgdGhlIG5vcm1hbGl6ZWQgY291bnRzIHRvIGV4cGxvcmUgc2ltaWxhcml0aWVzIGluIGdlbmUgZXhwcmVzc2lvbiBiZXR3ZWVuIGVhY2ggb2Ygb3VyIHNhbXBsZXMuIFRvIGRvIHRoaXMgd2UgdXNlIGNsdXN0ZXJpbmcgYWZ0ZXIgdXNpbmcgZGltZW5zaW9uYWwgcmVkdWN0aW9uLiANCiBCZWZvcmUgY2x1c3RlcmluZywgd2UgbmVlZCB0byBsb2cgdHJhbnNmb3JtIHRoZSBub3JtYWxpemVkIGNvdW50cyB0byBpbXByb3ZlIHRoZSB2aXN1YWxpemF0aW9uIG9mIHRoZSBjbHVzdGVyaW5nIGFuZCBoZW5jZSBvdXIgdW5kZXJzdGFuZGluZy4NCndlIGNhbiB1c2UgREVTZXEyJ3MgdnN0KCkgZnVuY3Rpb24uIHZzdCBzdGFuZHMgZm9yIFZhcmlhbmNlIHN0YWJpbGl6aW5nIHRyYW5zZm9ybWF0aW9uLiBUaGUgdHJhbnNmb3JtZWQgZGF0YSBzaG91bGQgYmUgYXBwcm94aW1hdGVkIHZhcmlhbmNlIHN0YWJpbGl6ZWQgYW5kIGFsc28gaW5jbHVkZXMgY29ycmVjdGlvbiBmb3Igc2l6ZSBmYWN0b3JzIG9yIG5vcm1hbGl6YXRpb24gZmFjdG9ycy4gVGhlIHRyYW5zZm9ybWVkIGRhdGEgaXMgb24gdGhlIGxvZzIgc2NhbGUgZm9yIGxhcmdlIGNvdW50cy4NClRoZSBibGluZD1UUlVFIGFyZ3VtZW50IHNwZWNpZmllcyB0aGF0IHRoZSB0cmFuc2Zvcm1hdGlvbiBzaG91bGQgYmUgYmxpbmQgdG8gdGhlIHNhbXBsZSBpbmZvcm1hdGlvbiBnaXZlbiBpbiB0aGUgZGVzaWduIGZvcm11bGE7IHRoaXMgYXJndW1lbnQgc2hvdWxkIGJlIHNwZWNpZmllZCB3aGVuIHBlcmZvcm1pbmcgcXVhbGl0eSBhc3Nlc3NtZW50Lg0KDQoNCmBgYHtyfQ0KdnNkX3RyYW5zIDwtIHZzdChkZHMsIGJsaW5kID0gVFJVRSkNCnZzZF90cmFucw0KYGBgDQpGcm9tIHZzZCwgd2UgbmVlZCB0byBleHRyYWN0IHRoZSBWU1QtdHJhc2Zvcm1lZCBub3JtYWxpemVkIGNvdW50cyBhcyBhIG1hdHJpeA0KYGBge3J9DQp2c2RfbWF0IDwtIGFzc2F5KHZzZF90cmFucykNCg0KYGBgDQpUaGVuLCB3ZSBuZWVkIHRvIGNvbXB1dGUgdGhlIHBhaXJ3aXNlIGNvcnJlbGF0aW9uIHZhbHVlcyBiZXR3ZWVuIGVhY2ggcGFpciBvZiBzYW1wbGVzDQpgYGB7cn0NCnZzZF9jb3IgPC0gY29yKHZzZF9tYXQpDQoNCmBgYA0KTm93IHdlIGRvIGNsdXN0ZXJpbmcuIFdlIGNob29zZSBIaWVyYXJjaGljYWwgY2x1c3RlcmluZyBoZXJlLg0KDQpgYGB7cn0NCnBoZWF0bWFwKHZzZF9jb3IsIGFubm90YXRpb24gPSBzZWxlY3QobWV0YWRhdGEsIGNvbmRpdGlvbikpIA0KDQpgYGANCg0KDQpUaGlzIGhlYXRtYXAgc2hvd3MgdXMgdGhhdCB0aGUgYmlvbG9naWNhbCByZXBsaWNhdGVzIGNsdXN0ZXIgdG9nZXRoZXIgKGFzIGV4cGVjdGVkLCBwaGV3Li4uKS4NClRoaXMgaXMgYSBnb29kIHNpZ24gYmVjYXVzZSwgdmVyeSBsaWtlbHkgb3VyIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBnZW5lcyBtdXN0IGJlIGRyaXZpbmcgdGhpcyBzZXBhcmF0aW9uLg0KQWxzbyB3ZSBkbyBub3Qgc2VlIGFueSBvdXRsaWVycy4NCg0KV2Ugd2lsbCBjcm9zc2NoZWNrIHRoaXMgd2l0aCBQQ0EgKFFDIHN0ZXAgMikNCg0KYGBge3J9DQpwbG90UENBKHZzZF90cmFucywgaW50Z3JvdXA9ImNvbmRpdGlvbiIpDQoNCmBgYA0KDQogTm93IHRoYXQgd2UgaGF2ZSBleHBsb3JlZCB0aGUgcXVhbGl0eSBvZiB0aGUgc2FtcGxlcywgY2hlY2tlZCBmb3Igb3V0bGllcnMsIHdlIGNhbiBnbyBhaGVhZCBhbmQgZmluZCB3aGljaCBnZW5lcyBoYXZlIHNpZ25pZmljYW50IGRpZmZlcmVuY2VzIGluIGV4cHJlc3Npb24gYmV0d2VlbiB0aGUgbm9ybWFsIGFuZCBmaWJyb3NpcyBzYW1wbGUgZ3JvdXBzLg0KIA0KQXQgdGhpcyBzdGFnZSB3ZSBkbyBub3QgbmVlZCB0byByZS1jcmVhdGUgdGhlIG9iamVjdCBzaW5jZSB3ZSBoYXZlIG5vdCByZW1vdmVkIHNhbXBsZXMgb3IgZm91bmQgYWRkaXRpb25hbCBzb3VyY2VzIG9mIHZhcmlhdGlvbiBkdXJpbmcgUUMgc3RlcHMuDQoNCmBgYHtyfQ0KZGRzX3J1biA8LSBERVNlcShkZHMpDQpkZHNfcnVuDQoNCmBgYA0KDQpgYGB7cn0NCm1lYW5fY291bnRzIDwtIGFwcGx5KHJhd19jb3VudF9tYXRyaXhbLDE6M10sIDEsIG1lYW4pDQpgYGANCg0KDQpEaXNwZXJzaW9uIGVzdGltYXRlcyBhcmUgdXNlZCB0byBtb2RlbCB0aGUgcmF3IGNvdW50czsgaWYgdGhlIGRpc3BlcnNpb25zIGRvbid0IGZvbGxvdyB0aGUgYXNzdW1wdGlvbnMgbWFkZSBieSBERVNlcTIsIHRoZW4gdGhlIHZhcmlhdGlvbiBpbiB0aGUgZGF0YSBjb3VsZCBiZSBwb29ybHkgZXN0aW1hdGVkIGFuZCBvdXRvdXQgb2Ygd2hpY2ggZ2VuZXMgYXJlIGRpZmZlcmVudGlhbGx5IGV4cHJlc3NlZCBjb3VsZCBiZSB3cm9uZy4NClRoZSBhc3N1bXB0aW9ucyBtYWRlIGJ5IERFU2VxMiBhcmU6DQoNCi0gVGhlIGNvdW50cyBkYXRhIGZpdCB0byB0aGUgbmVnYXRpdmUgYmlub21pYWwgZGlzdHJpYnV0aW9uDQotIFRoZSBkaXNwZXJzaW9ucyBzaG91bGQgZ2VuZXJhbGx5IGRlY3JlYXNlIHdpdGggaW5jcmVhc2UgaW4gdGhlIG1lYW4NCg0KYGBge3J9DQpwbG90RGlzcEVzdHMoZGRzX3J1bikNCmBgYA0KDQpGcm9tIHRoZSBkaXNwZXJzaW9uIHBsb3Qgd2UgY2FuIHNlZSB0aGF0IGZpdCBvZiBvdXIgZGF0YSB0byB0aGUgbW9kZWwgaXMgcHJldHR5IGdvb2QuDQpHZW5lLWVzdCBpcyBlc3RpbWF0ZWQgZGlzcGVyc2lvbiBvZiB0aGUgZ2VuZXMuDQoNClBsb3R0aW5nIHRoZSBkaXNwZXJzaW9uIGVzdGltYXRlcyBpcyBhIHVzZWZ1bCBkaWFnbm9zdGljLiBUaGUgZGlzcGVyc2lvbiBwbG90IHdoaWNoIHdlIHNlZSBoZXJlIGlzIGEgdHlwaWNhbCBvbmUgd2l0aCB0aGUgZmluYWwgZXN0aW1hdGVzIHNocnVuayBmcm9tIHRoZSBnZW5lLXdpc2UgZXN0aW1hdGVzIHRvd2FyZHMgdGhlIGZpdHRlZCBlc3RpbWF0ZXMuIFNvbWUgZ2VuZS13aXNlIGVzdGltYXRlcyBhcmUgZmxhZ2dlZCAob3BlbiBjaXJjbGVzKSBhcyBvdXRsaWVycyBhbmQgbm90IHNocnVuayB0b3dhcmRzIHRoZSBmaXR0ZWQgdmFsdWUuIA0KDQpgYGB7cn0NCnJlczAuMDEgPC0gcmVzdWx0cyhkZHNfcnVuLGFscGhhID0gMC4wMSkNCnN1bW1hcnkocmVzMC4wMSkNCg0KIyBjb250cmFzdHMNCnJlc3VsdHNOYW1lcyhkZHNfcnVuKQ0KDQpgYGANCmBgYHtyfQ0KIyBNQSBwbG90DQpwbG90TUEocmVzMC4wMSkNCmBgYA0KDQoNCg0K