Subject: Identification of the
putative site of the origin of replication in the CMV genome by
computational analysis.
To suggest the putative regions of origin of replication in the CMV
genome, we took the approach to detect tight clusters of complementary
palindromes in the CMV genome. CMV genome is 229,354 base pair (bp) long
and contains 296 palindromes that are at least 10 bp long. We considered
the statistical model, the Homogeneous Poisson process (HPP), as the
base model. HPP is a natural model for uniform random scatter. It
assumes that events are non-overlapping, occur at a known constant rate,
and are independent of each other. According to the HPP model,
palindromes are scattered uniformly as well as randomly across the CMV
genome. The number of palindromes in any location of the genome is
independent of the number of palindromes in a non-overlapping, another
location. If we observe the histogram in graph A below, where the number
of palindromes in each 5000 bp is plotted, we find that a ~ similar
number of palindromes are scattered all over the genome with some
heterogeneity. For example, we can see only two locations where there
are excess numbers of palindromes, 18 and 12, compared to other regions.
Therefore, we assumed that the distribution of palindromes in the CMV
genome broadly fits the HPP model, but with some heterogeneity. A small
deviation from HPP (for example, a tight cluster of a number of
palindromes) might give us our target locations. We analyzed the CMV
genome to identify any locations with tight clusters of palindromes by
considering the HPP as a baseline.
Finally, with this model, we have detected a number of tight clusters
of palindromes at the locations from 87717 bp - 97488 bp, and 189810 bp
- 198709 bp in the CMV genomes. The tightest clusters we have detected
are from 90251 - 94174 bp. Anyone or a group of these clusters has
significant potential to possess the origin of replication.
cmv<-read.csv("http://www.uwyo.edu/buerkle/compbio/statlabs/data/hcmv.data.txt")$location
par(mfrow=c(2,1), mar= c(5, 6, 3.5, 0))
hist(cmv, breaks=seq(0,232000, by=5000), # creating a histogram, where each bar shows the counts of palindromes in every 5000 bp.
labels=TRUE,
main = "Graph A: Distribution of palindromes in each 5000 bp in CMV genome",
cex.main= 3,
cex.axis=2.5,
xlab = "Locations in the CMV genome",
ylab = "Counts of the palindromes",
cex.lab=2.5
)
abline(h = qpois((0.95), lambda=5000*296/229354), col= "purple", lwd=3) #Add a horizontal line to the histogram that shows 95% quantile using the quantile function of the Poisson distribution qpois().
slide.window<-function(seqdata, total.length, blocksize=500, incr=100){ # creating a function for the sliding window, where block size can be specified and each block moves a given number of bp.
block.right<-seq(blocksize,total.length, by=incr)
block.left<-block.right-blocksize+1
block.mid<-(block.right+block.left)/2
nblocks<-length(block.right)
count<-numeric(nblocks)
rate<-numeric(nblocks)
for(i in 1:nblocks) {
focal<-seqdata[seqdata>block.left[i] & seqdata < block.right[i]] # assigning the locations from seqdata (CMV data in our case) when locations are greater than left block and smaller than the right block.
count[i]<-length(focal) # total number of locations fall inside ith block.
rate[i]<-count[i] / blocksize
# alternatively
#count[i] <- sum(seqdata>block.left[i] & seqdata < block.right[i])
}
data.frame(count, rate, block.left, block.mid, block.right) # Creating a dataframe including the variables mentioned here.
}
plot(rate ~ block.mid, data=slide.window(cmv, 230000, blocksize=5000, incr=250), # Plotting rate vs the value of calculated middle block, when block size is 5000 bp and each block move only 250 bp.
type="l",
col= "black",
lwd = 2,
main = "Graph B: Sliding window with 250 bp increment",
cex.main= 3,
cex.axis=2.5,
xlab = "Locations in the CMV genome",
ylab = "Rates (count/blocksize)",
cex.lab=2.5)
lines(rate ~ block.mid, data=slide.window(cmv, 230000, blocksize=9000, incr=250), # creating a line plot over the previous plot with different color when block size is 9000 bp and each block move only 250 bp.
col="purple",
lwd = 2)
lines(rate ~ block.mid, data=slide.window(cmv, 230000, blocksize=18000, incr=250),
col="orange",
lwd = 2)
lines(rate ~ block.mid, data=slide.window(cmv, 230000, blocksize=36000, incr=250),
col="red",
lwd=2)

In graph A, a total number of palindromes in every 5000 bp is
plotted. We see that mostly 3 to 10 palindromes in each 5000 bp are
spread all over the genome. Only two locations we found that contain 18
and 12 palindromes. The purple line in the graph shows 95% quantile.
From this line, we understand that there is only a 5% chance that we get
12 or more palindromes in each 5000 bp. Graph B is a sliding window that
shows the rate of palindromes in 5000 bp block when we move blocks 250
bp. From the sliding window, we find a similar number of counts as shown
in graph A when the block size is 5000 bp. We also found that if we
count palindromes every 2000 to 10000 bp or produce a sliding window
with a 2000 to 10000 bp block size, the distribution of palindromes all
over the genome is similar. The sliding window also shows that larger
block sizes dilute the signal of palindrome count significantly as we
can see from the purple, orange, and red lines with 9000bp, 18000 bp,
and 36000 bp block sizes respectively in graph B (especially with 18000
and 36000 bp). Because increasing block size increases the probability
of repeated count of the same palindromes in blocks each time. By
comparing graph A and the sliding window (graph B), we showed that the
count of the number of palindromes in each 5000 bp is accurate and
robust as we move blocks only 250 bp. We did not lose any significant
amount of palindrome from the counting due to the block size we
considered. Therefore, the locations from graph A, where we find the
cluster of 18 and 12 palindromes are our potential candidates for the
sites of origin of replication, as we supposed that they might be more
tightly clustered together compare to other regions.
par(mfrow=c(1,2), mar=c(5,5.5,5.5,4.5))
plot(cmv[1:(296-14)], diff(cmv, lag=14), # plotting the locations of palindromes in X- axis and difference between 1st and 15th palindromes of each consecutive/ overlapping set of 15 palindromes using lag value inside diff() function.
main = "Graph C: Locations and distances between two terminal palindromes
of all sets of 15 palidromes",
cex.main=2.5,
cex.lab = 2.5,
cex.axis = 2.5,
xlab="Locations in the CMV genome",
ylab="Observed distance (bp)",
ylim=c(0,25000),
lwd=3)
abline(h=qgamma(c(0.02, 0.0002),rate =296/229354, shape=14 ), # Add two horizontal lines on the plot for 2% and 0.02% quantile using the quantile function of the gamma distribution.
col=c("purple", "blue"),
lwd=2)
plot(dgamma(0:25000, rate =296/229354, shape=14), 0:25000, # Density plot of the gamma distribution of the distances between two terminal palindromes of sets of 15 palindromes.
main = "Graph D: Density plot of the gamma distribution",
cex.main=3,
cex.lab = 2.5,
cex.axis = 2.5,
type="l",
ylab="",
xlab="Density of the gamma",
lwd=3)
abline(h=qgamma( c(0.02, 0.0002),rate =296/229354, shape=14 ),
col=c("purple","blue"),
lwd=2)
mtext(c(0.02, 0.0002), # Add text to the right hand side of horizontal lines.
side=4,
at=qgamma(c(0.02, 0.0002),
rate =296/229354, shape=14 ),
col=c("purple","blue"),
las=1,
cex=2)

In graph C we observe the distance (y-axis) between 1st and 15th
palindromes of each set of 15 palindromes in different locations
(x-axis) of the genome. We found that the differences between the two
terminal palindromes of most of the sets are from ~6000 to ~ 17000 bp.
There are only two locations where distances are ~6000 bp or less (below
the purple line in graph C). I analyzed sets of the different numbers of
palindromes (sets of 10 to 18 palindromes). Each time I found a similar
pattern of distribution of variable distances between two terminal
palindromes of each set. However, analysis with the set of 15
palindromes resulted in a decent number of locations where distances
between two terminal palindromes are highly (probability <0.02) or
extremely (probability <0.0002) improbable. Therefore, I used the set
of 15 palindromes (lag=14) in this analysis. Graph D is the density plot
of the gamma distribution. In both graphs, purple and blue lines are
showing 2% and 0.02% quantile (extremely small distances) of the gamma
distribution. This indicates that there is an extremely low probability
(<0.02) of the occurrence of 15 palindromes in these small distances
by chance. If we compare the locations of these two regions with graph
A, we find that they fall inside the similar regions we detected in
graph A with 95% quantile. These seemingly tight clusters (sets of 15)
of palindromes might have some significant biological roles, for
example, may possess the origin of replication.
## save indexes of improbably small distances
myprecious.indexes<-which(pgamma(diff(cmv, lag=14), rate =296/229354, shape=14) < 0.02) # Creating a vector that contain indexes of the locations of 1st palindromes of sets of 15 palindromes, of which, the probability of distances between 1st and 15th palindrome is less than 0.02 using the cumulative density of function, pgamma(), of the gamma distribution.
mystrictprecious.indexes<-which(pgamma(diff(cmv, lag=14), rate =296/229354, shape=14) < 0.0002)
par(mar=c(5, 5, 2,2))
plot(cmv[1:(296-14)], 1:(296-14), type='n', # Creating an empty plot.
ylab="Sets of 15 palindromes",
xlab="Locations in the CMV genome",
main = "Graph E: Distances beween the two terminal palindromes of each set of 15 palindomes at different positions in CMV genome",
cex.main= 2.2,
cex.lab= 2.5,
cex.axis = 2.5,
lwd=3)
segments(cmv[1:(296-14)], 1:(296-14), # Add distances between two terminal palindromes of each set of 15 palindromes as line segments.
cmv[(1+14):296], 1:(296-14))
segments(cmv[myprecious.indexes], myprecious.indexes, # Add distances between two terminal palindromes of sets of palindromes indexed by myprecious as line segments with red color. This segments override the previous segments at the same locations.
cmv[myprecious.indexes+14], myprecious.indexes, col="red", lwd = 3)
segments(cmv[mystrictprecious.indexes], mystrictprecious.indexes,
cmv[mystrictprecious.indexes+14], mystrictprecious.indexes, col= adjustcolor( "yellow", alpha.f = 0.7), lwd = 3)

To visualize distances as shown in graph C more clearly, we developed
Graph E. It shows the distances between two terminal palindromes of sets
of 15 palindromes by line segments. Here, each line indicates a set of
15 palindromes and the length of the line indicates the distance between
the 1st and 15th palindromes of that set. From the x-axis, we can also
understand the position of each set of palindromes in the CMV genome. We
can visualize that there are two places in the genome (colored with both
yellow and red) where lengths of sets of palindromes are significantly
less (probability is less than 0.02) compared to the rest of the genome
as also indicated in graph C. As I discussed before, with this extremely
low probability (<0.02 (red+yellow regions) or <0.0002 (only
yellow regions)) this is highly unlikely that these palindromes are in
these positions of the genome just by chance. Based on these
observations, primarily I made two recommendations below to start
experimentally searching for the origin of replication.
LS0tDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KDQojIyMjIERhdGU6IDA0LzEyLzIwMjINCg0KIyMjIyBUbzogICAgVGhlIEhlYWQgQmlvbG9naXN0IA0KDQojIyMjIEZyb206ICBNZCBBc2hyYWZ1bCBJc2xhbSBCaHVpeWENCg0KIyMjIF8qKipTdWJqZWN0OioqKiBJZGVudGlmaWNhdGlvbiBvZiB0aGUgcHV0YXRpdmUgc2l0ZSBvZiB0aGUgb3JpZ2luIG9mIHJlcGxpY2F0aW9uIGluIHRoZSBDTVYgZ2Vub21lIGJ5IGNvbXB1dGF0aW9uYWwgYW5hbHlzaXMuXw0KDQpUbyBzdWdnZXN0IHRoZSBwdXRhdGl2ZSByZWdpb25zIG9mIG9yaWdpbiBvZiByZXBsaWNhdGlvbiBpbiB0aGUgQ01WIGdlbm9tZSwgd2UgdG9vayB0aGUgYXBwcm9hY2ggdG8gZGV0ZWN0IHRpZ2h0IGNsdXN0ZXJzIG9mIGNvbXBsZW1lbnRhcnkgcGFsaW5kcm9tZXMgaW4gdGhlIENNViBnZW5vbWUuIENNViBnZW5vbWUgaXMgMjI5LDM1NCBiYXNlIHBhaXIgKGJwKSBsb25nIGFuZCBjb250YWlucyAyOTYgcGFsaW5kcm9tZXMgdGhhdCBhcmUgYXQgbGVhc3QgMTAgYnAgbG9uZy4gV2UgY29uc2lkZXJlZCB0aGUgc3RhdGlzdGljYWwgbW9kZWwsIHRoZSBIb21vZ2VuZW91cyBQb2lzc29uIHByb2Nlc3MgKEhQUCksIGFzIHRoZSBiYXNlIG1vZGVsLiAgSFBQIGlzIGEgbmF0dXJhbCBtb2RlbCBmb3IgdW5pZm9ybSByYW5kb20gc2NhdHRlci4gSXQgYXNzdW1lcyB0aGF0IGV2ZW50cyBhcmUgbm9uLW92ZXJsYXBwaW5nLCBvY2N1ciBhdCBhIGtub3duIGNvbnN0YW50IHJhdGUsIGFuZCBhcmUgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlci4gQWNjb3JkaW5nIHRvIHRoZSBIUFAgbW9kZWwsIHBhbGluZHJvbWVzIGFyZSBzY2F0dGVyZWQgdW5pZm9ybWx5IGFzIHdlbGwgYXMgcmFuZG9tbHkgYWNyb3NzIHRoZSBDTVYgZ2Vub21lLiBUaGUgbnVtYmVyIG9mIHBhbGluZHJvbWVzIGluIGFueSBsb2NhdGlvbiBvZiB0aGUgZ2Vub21lIGlzIGluZGVwZW5kZW50IG9mIHRoZSBudW1iZXIgb2YgcGFsaW5kcm9tZXMgaW4gYSBub24tb3ZlcmxhcHBpbmcsIGFub3RoZXIgbG9jYXRpb24uIElmIHdlIG9ic2VydmUgdGhlIGhpc3RvZ3JhbSBpbiBncmFwaCBBIGJlbG93LCB3aGVyZSB0aGUgbnVtYmVyIG9mIHBhbGluZHJvbWVzIGluIGVhY2ggNTAwMCBicCBpcyBwbG90dGVkLCB3ZSBmaW5kIHRoYXQgYSB+IHNpbWlsYXIgbnVtYmVyIG9mIHBhbGluZHJvbWVzIGFyZSBzY2F0dGVyZWQgYWxsIG92ZXIgdGhlIGdlbm9tZSB3aXRoIHNvbWUgaGV0ZXJvZ2VuZWl0eS4gRm9yIGV4YW1wbGUsIHdlIGNhbiBzZWUgb25seSB0d28gbG9jYXRpb25zIHdoZXJlIHRoZXJlIGFyZSBleGNlc3MgbnVtYmVycyBvZiBwYWxpbmRyb21lcywgMTggYW5kIDEyLCBjb21wYXJlZCB0byBvdGhlciByZWdpb25zLiBUaGVyZWZvcmUsIHdlIGFzc3VtZWQgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHBhbGluZHJvbWVzIGluIHRoZSBDTVYgZ2Vub21lIGJyb2FkbHkgZml0cyB0aGUgSFBQIG1vZGVsLCBidXQgd2l0aCBzb21lIGhldGVyb2dlbmVpdHkuIEEgc21hbGwgZGV2aWF0aW9uIGZyb20gSFBQIChmb3IgZXhhbXBsZSwgYSB0aWdodCBjbHVzdGVyIG9mIGEgbnVtYmVyIG9mIHBhbGluZHJvbWVzKSBtaWdodCBnaXZlIHVzIG91ciB0YXJnZXQgbG9jYXRpb25zLiBXZSBhbmFseXplZCB0aGUgQ01WIGdlbm9tZSB0byBpZGVudGlmeSBhbnkgbG9jYXRpb25zIHdpdGggdGlnaHQgY2x1c3RlcnMgb2YgcGFsaW5kcm9tZXMgYnkgY29uc2lkZXJpbmcgdGhlIEhQUCBhcyBhIGJhc2VsaW5lLiAgDQoNCkZpbmFsbHksIHdpdGggdGhpcyBtb2RlbCwgd2UgaGF2ZSBkZXRlY3RlZCBhIG51bWJlciBvZiB0aWdodCBjbHVzdGVycyBvZiBwYWxpbmRyb21lcyBhdCB0aGUgbG9jYXRpb25zIGZyb20gODc3MTcgYnAgLSA5NzQ4OCBicCwgYW5kIDE4OTgxMCBicCAtIDE5ODcwOSBicCBpbiB0aGUgQ01WIGdlbm9tZXMuIFRoZSB0aWdodGVzdCBjbHVzdGVycyB3ZSBoYXZlIGRldGVjdGVkIGFyZSBmcm9tIDkwMjUxIC0gOTQxNzQgYnAuIEFueW9uZSBvciBhIGdyb3VwIG9mIHRoZXNlIGNsdXN0ZXJzIGhhcyBzaWduaWZpY2FudCBwb3RlbnRpYWwgdG8gcG9zc2VzcyB0aGUgb3JpZ2luIG9mIHJlcGxpY2F0aW9uLiANCg0KYGBge3IsIGZpZy5oZWlnaHQ9NX0NCmNtdjwtcmVhZC5jc3YoImh0dHA6Ly93d3cudXd5by5lZHUvYnVlcmtsZS9jb21wYmlvL3N0YXRsYWJzL2RhdGEvaGNtdi5kYXRhLnR4dCIpJGxvY2F0aW9uDQoNCnBhcihtZnJvdz1jKDIsMSksIG1hcj0gYyg1LCA2LCAzLjUsIDApKQ0KDQogaGlzdChjbXYsIGJyZWFrcz1zZXEoMCwyMzIwMDAsIGJ5PTUwMDApLCAjIGNyZWF0aW5nIGEgaGlzdG9ncmFtLCB3aGVyZSBlYWNoIGJhciBzaG93cyB0aGUgY291bnRzIG9mIHBhbGluZHJvbWVzIGluIGV2ZXJ5IDUwMDAgYnAuDQogICAgICAgICAgICAgICAgIGxhYmVscz1UUlVFLCANCiAgICAgICAgICAgICAgICAgbWFpbiA9ICJHcmFwaCBBOiBEaXN0cmlidXRpb24gb2YgcGFsaW5kcm9tZXMgaW4gZWFjaCA1MDAwIGJwIGluIENNViBnZW5vbWUiLCANCiAgICAgICAgICAgICAgICAgY2V4Lm1haW49IDMsIA0KICAgICAgICAgICAgICAgICBjZXguYXhpcz0yLjUsIA0KICAgICAgICAgICAgICAgICB4bGFiID0gIkxvY2F0aW9ucyBpbiB0aGUgQ01WIGdlbm9tZSIsIA0KICAgICAgICAgICAgICAgICB5bGFiID0gIkNvdW50cyBvZiB0aGUgcGFsaW5kcm9tZXMiLA0KICAgICAgICAgICAgICAgICBjZXgubGFiPTIuNQ0KICAgICAgICAgICAgICAgICApDQoNCmFibGluZShoID0gcXBvaXMoKDAuOTUpLCBsYW1iZGE9NTAwMCoyOTYvMjI5MzU0KSwgY29sPSAicHVycGxlIiwgbHdkPTMpICNBZGQgYSBob3Jpem9udGFsIGxpbmUgdG8gdGhlIGhpc3RvZ3JhbSB0aGF0IHNob3dzIDk1JSBxdWFudGlsZSB1c2luZyB0aGUgcXVhbnRpbGUgZnVuY3Rpb24gb2YgdGhlIFBvaXNzb24gZGlzdHJpYnV0aW9uIHFwb2lzKCkuDQoNCg0KDQoNCnNsaWRlLndpbmRvdzwtZnVuY3Rpb24oc2VxZGF0YSwgdG90YWwubGVuZ3RoLCBibG9ja3NpemU9NTAwLCBpbmNyPTEwMCl7ICAjIGNyZWF0aW5nIGEgZnVuY3Rpb24gZm9yIHRoZSBzbGlkaW5nIHdpbmRvdywgd2hlcmUgYmxvY2sgc2l6ZSBjYW4gYmUgc3BlY2lmaWVkIGFuZCBlYWNoIGJsb2NrIG1vdmVzIGEgZ2l2ZW4gbnVtYmVyIG9mIGJwLiANCiAgYmxvY2sucmlnaHQ8LXNlcShibG9ja3NpemUsdG90YWwubGVuZ3RoLCBieT1pbmNyKQ0KDQogIGJsb2NrLmxlZnQ8LWJsb2NrLnJpZ2h0LWJsb2Nrc2l6ZSsxDQoNCiAgYmxvY2subWlkPC0oYmxvY2sucmlnaHQrYmxvY2subGVmdCkvMg0KDQogIG5ibG9ja3M8LWxlbmd0aChibG9jay5yaWdodCkNCg0KICBjb3VudDwtbnVtZXJpYyhuYmxvY2tzKQ0KDQogIHJhdGU8LW51bWVyaWMobmJsb2NrcykNCg0KICANCg0KICBmb3IoaSBpbiAxOm5ibG9ja3MpIHsNCg0KICAgIGZvY2FsPC1zZXFkYXRhW3NlcWRhdGE+YmxvY2subGVmdFtpXSAmIHNlcWRhdGEgPCBibG9jay5yaWdodFtpXV0gIyBhc3NpZ25pbmcgdGhlIGxvY2F0aW9ucyBmcm9tIHNlcWRhdGEgKENNViBkYXRhIGluIG91ciBjYXNlKSB3aGVuIGxvY2F0aW9ucyBhcmUgZ3JlYXRlciB0aGFuIGxlZnQgYmxvY2sgYW5kIHNtYWxsZXIgdGhhbiB0aGUgcmlnaHQgYmxvY2suIA0KDQogICAgY291bnRbaV08LWxlbmd0aChmb2NhbCkgIyB0b3RhbCBudW1iZXIgb2YgbG9jYXRpb25zIGZhbGwgaW5zaWRlIGl0aCBibG9jay4gDQoNCiAgICByYXRlW2ldPC1jb3VudFtpXSAvIGJsb2Nrc2l6ZQ0KDQogICAgIyBhbHRlcm5hdGl2ZWx5DQoNCiAgICAjY291bnRbaV0gPC0gc3VtKHNlcWRhdGE+YmxvY2subGVmdFtpXSAmIHNlcWRhdGEgPCBibG9jay5yaWdodFtpXSkNCg0KICB9DQoNCiAgZGF0YS5mcmFtZShjb3VudCwgcmF0ZSwgYmxvY2subGVmdCwgYmxvY2subWlkLCBibG9jay5yaWdodCkgIyBDcmVhdGluZyBhIGRhdGFmcmFtZSBpbmNsdWRpbmcgdGhlIHZhcmlhYmxlcyBtZW50aW9uZWQgaGVyZS4gDQoNCn0NCg0KcGxvdChyYXRlIH4gYmxvY2subWlkLCBkYXRhPXNsaWRlLndpbmRvdyhjbXYsIDIzMDAwMCwgYmxvY2tzaXplPTUwMDAsIGluY3I9MjUwKSwgIyBQbG90dGluZyByYXRlIHZzIHRoZSB2YWx1ZSBvZiBjYWxjdWxhdGVkIG1pZGRsZSBibG9jaywgd2hlbiBibG9jayBzaXplIGlzIDUwMDAgYnAgYW5kIGVhY2ggYmxvY2sgbW92ZSBvbmx5IDI1MCBicC4gICANCiAgICAgdHlwZT0ibCIsIA0KICAgICBjb2w9ICJibGFjayIsDQogICAgIGx3ZCA9IDIsDQogICAgIG1haW4gPSAiR3JhcGggQjogU2xpZGluZyB3aW5kb3cgd2l0aCAyNTAgYnAgaW5jcmVtZW50IiwNCiAgICAgY2V4Lm1haW49IDMsIA0KICAgICBjZXguYXhpcz0yLjUsIA0KICAgICB4bGFiID0gIkxvY2F0aW9ucyBpbiB0aGUgQ01WIGdlbm9tZSIsIA0KICAgICB5bGFiID0gIlJhdGVzIChjb3VudC9ibG9ja3NpemUpIiwNCiAgICAgY2V4LmxhYj0yLjUpDQoNCmxpbmVzKHJhdGUgfiBibG9jay5taWQsIGRhdGE9c2xpZGUud2luZG93KGNtdiwgMjMwMDAwLCBibG9ja3NpemU9OTAwMCwgaW5jcj0yNTApLCAjIGNyZWF0aW5nIGEgbGluZSBwbG90IG92ZXIgdGhlIHByZXZpb3VzIHBsb3Qgd2l0aCBkaWZmZXJlbnQgY29sb3Igd2hlbiBibG9jayBzaXplIGlzIDkwMDAgYnAgYW5kIGVhY2ggYmxvY2sgbW92ZSBvbmx5IDI1MCBicC4NCiAgICAgIGNvbD0icHVycGxlIiwNCiAgICAgIGx3ZCA9IDIpDQogICAgICANCmxpbmVzKHJhdGUgfiBibG9jay5taWQsIGRhdGE9c2xpZGUud2luZG93KGNtdiwgMjMwMDAwLCBibG9ja3NpemU9MTgwMDAsIGluY3I9MjUwKSwgDQogICAgICBjb2w9Im9yYW5nZSIsDQogICAgICBsd2QgPSAyKQ0KDQpsaW5lcyhyYXRlIH4gYmxvY2subWlkLCBkYXRhPXNsaWRlLndpbmRvdyhjbXYsIDIzMDAwMCwgYmxvY2tzaXplPTM2MDAwLCBpbmNyPTI1MCksIA0KICAgICAgY29sPSJyZWQiLA0KICAgICAgbHdkPTIpDQoNCmBgYA0KSW4gZ3JhcGggQSwgYSB0b3RhbCBudW1iZXIgb2YgcGFsaW5kcm9tZXMgaW4gZXZlcnkgNTAwMCBicCBpcyBwbG90dGVkLiBXZSBzZWUgdGhhdCBtb3N0bHkgMyB0byAxMCBwYWxpbmRyb21lcyBpbiBlYWNoIDUwMDAgYnAgYXJlIHNwcmVhZCBhbGwgb3ZlciB0aGUgZ2Vub21lLiBPbmx5IHR3byBsb2NhdGlvbnMgd2UgZm91bmQgdGhhdCBjb250YWluIDE4IGFuZCAxMiBwYWxpbmRyb21lcy4gVGhlIHB1cnBsZSBsaW5lIGluIHRoZSBncmFwaCBzaG93cyA5NSUgcXVhbnRpbGUuIEZyb20gdGhpcyBsaW5lLCB3ZSB1bmRlcnN0YW5kIHRoYXQgdGhlcmUgaXMgb25seSBhIDUlIGNoYW5jZSB0aGF0IHdlIGdldCAxMiBvciBtb3JlIHBhbGluZHJvbWVzIGluIGVhY2ggNTAwMCBicC4gR3JhcGggQiBpcyBhIHNsaWRpbmcgd2luZG93IHRoYXQgc2hvd3MgdGhlIHJhdGUgb2YgcGFsaW5kcm9tZXMgaW4gNTAwMCBicCBibG9jayB3aGVuIHdlIG1vdmUgYmxvY2tzIDI1MCBicC4gRnJvbSB0aGUgc2xpZGluZyB3aW5kb3csIHdlIGZpbmQgYSBzaW1pbGFyIG51bWJlciBvZiBjb3VudHMgYXMgc2hvd24gaW4gZ3JhcGggQSB3aGVuIHRoZSBibG9jayBzaXplIGlzIDUwMDAgYnAuIFdlIGFsc28gZm91bmQgdGhhdCBpZiB3ZSBjb3VudCBwYWxpbmRyb21lcyBldmVyeSAyMDAwIHRvIDEwMDAwIGJwIG9yIHByb2R1Y2UgYSBzbGlkaW5nIHdpbmRvdyB3aXRoIGEgMjAwMCB0byAxMDAwMCBicCBibG9jayBzaXplLCB0aGUgZGlzdHJpYnV0aW9uIG9mIHBhbGluZHJvbWVzIGFsbCBvdmVyIHRoZSBnZW5vbWUgaXMgc2ltaWxhci4gVGhlIHNsaWRpbmcgd2luZG93IGFsc28gc2hvd3MgdGhhdCBsYXJnZXIgYmxvY2sgc2l6ZXMgZGlsdXRlIHRoZSBzaWduYWwgb2YgcGFsaW5kcm9tZSBjb3VudCBzaWduaWZpY2FudGx5IGFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgcHVycGxlLCBvcmFuZ2UsIGFuZCByZWQgbGluZXMgd2l0aCA5MDAwYnAsIDE4MDAwIGJwLCBhbmQgMzYwMDAgYnAgYmxvY2sgc2l6ZXMgcmVzcGVjdGl2ZWx5IGluIGdyYXBoIEIgKGVzcGVjaWFsbHkgd2l0aCAxODAwMCBhbmQgMzYwMDAgYnApLiBCZWNhdXNlIGluY3JlYXNpbmcgYmxvY2sgc2l6ZSBpbmNyZWFzZXMgdGhlIHByb2JhYmlsaXR5IG9mIHJlcGVhdGVkIGNvdW50IG9mIHRoZSBzYW1lIHBhbGluZHJvbWVzIGluIGJsb2NrcyBlYWNoIHRpbWUuIEJ5IGNvbXBhcmluZyBncmFwaCBBIGFuZCB0aGUgc2xpZGluZyB3aW5kb3cgKGdyYXBoIEIpLCB3ZSBzaG93ZWQgdGhhdCB0aGUgY291bnQgb2YgdGhlIG51bWJlciBvZiBwYWxpbmRyb21lcyBpbiBlYWNoIDUwMDAgYnAgaXMgYWNjdXJhdGUgYW5kIHJvYnVzdCBhcyB3ZSBtb3ZlIGJsb2NrcyBvbmx5IDI1MCBicC4gV2UgZGlkIG5vdCBsb3NlIGFueSBzaWduaWZpY2FudCBhbW91bnQgb2YgcGFsaW5kcm9tZSBmcm9tIHRoZSBjb3VudGluZyBkdWUgdG8gdGhlIGJsb2NrIHNpemUgd2UgY29uc2lkZXJlZC4gVGhlcmVmb3JlLCB0aGUgbG9jYXRpb25zIGZyb20gZ3JhcGggQSwgd2hlcmUgd2UgZmluZCB0aGUgY2x1c3RlciBvZiAxOCBhbmQgMTIgcGFsaW5kcm9tZXMgYXJlIG91ciBwb3RlbnRpYWwgY2FuZGlkYXRlcyBmb3IgdGhlIHNpdGVzIG9mIG9yaWdpbiBvZiByZXBsaWNhdGlvbiwgYXMgd2Ugc3VwcG9zZWQgdGhhdCB0aGV5IG1pZ2h0IGJlIG1vcmUgdGlnaHRseSBjbHVzdGVyZWQgdG9nZXRoZXIgY29tcGFyZSB0byBvdGhlciByZWdpb25zLiAgICAgICAgIA0KICAgICAgIA0KDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMCB9DQoNCnBhcihtZnJvdz1jKDEsMiksIG1hcj1jKDUsNS41LDUuNSw0LjUpKQ0KcGxvdChjbXZbMTooMjk2LTE0KV0sIGRpZmYoY212LCBsYWc9MTQpLCAjIHBsb3R0aW5nIHRoZSBsb2NhdGlvbnMgb2YgcGFsaW5kcm9tZXMgaW4gWC0gYXhpcyBhbmQgZGlmZmVyZW5jZSBiZXR3ZWVuIDFzdCBhbmQgMTV0aCBwYWxpbmRyb21lcyBvZiBlYWNoIGNvbnNlY3V0aXZlLyBvdmVybGFwcGluZyBzZXQgb2YgMTUgcGFsaW5kcm9tZXMgdXNpbmcgbGFnIHZhbHVlIGluc2lkZSBkaWZmKCkgZnVuY3Rpb24uIA0KICAgICBtYWluID0gIkdyYXBoIEM6IExvY2F0aW9ucyBhbmQgZGlzdGFuY2VzIGJldHdlZW4gdHdvIHRlcm1pbmFsIHBhbGluZHJvbWVzDQogICAgIG9mIGFsbCBzZXRzIG9mIDE1ICBwYWxpZHJvbWVzIiwNCiAgICAgY2V4Lm1haW49Mi41LA0KICAgICBjZXgubGFiID0gMi41LA0KICAgICBjZXguYXhpcyA9IDIuNSwNCiAgICAgeGxhYj0iTG9jYXRpb25zIGluIHRoZSBDTVYgZ2Vub21lIiwgDQogICAgIHlsYWI9Ik9ic2VydmVkIGRpc3RhbmNlIChicCkiLCANCiAgICAgeWxpbT1jKDAsMjUwMDApLA0KICAgICBsd2Q9MykNCmFibGluZShoPXFnYW1tYShjKDAuMDIsIDAuMDAwMikscmF0ZSA9Mjk2LzIyOTM1NCwgc2hhcGU9MTQgKSwgIyBBZGQgdHdvIGhvcml6b250YWwgbGluZXMgb24gdGhlIHBsb3QgZm9yIDIlIGFuZCAwLjAyJSBxdWFudGlsZSB1c2luZyB0aGUgcXVhbnRpbGUgZnVuY3Rpb24gb2YgdGhlIGdhbW1hIGRpc3RyaWJ1dGlvbi4NCiAgICAgICBjb2w9YygicHVycGxlIiwgImJsdWUiKSwgDQogICAgICAgbHdkPTIpDQpwbG90KGRnYW1tYSgwOjI1MDAwLCByYXRlID0yOTYvMjI5MzU0LCBzaGFwZT0xNCksIDA6MjUwMDAsICMgRGVuc2l0eSBwbG90IG9mIHRoZSBnYW1tYSBkaXN0cmlidXRpb24gb2YgdGhlIGRpc3RhbmNlcyBiZXR3ZWVuIHR3byB0ZXJtaW5hbCBwYWxpbmRyb21lcyBvZiBzZXRzIG9mIDE1IHBhbGluZHJvbWVzLiANCiAgICAgbWFpbiA9ICJHcmFwaCBEOiBEZW5zaXR5IHBsb3Qgb2YgdGhlIGdhbW1hIGRpc3RyaWJ1dGlvbiIsDQogICAgIGNleC5tYWluPTMsDQogICAgIGNleC5sYWIgPSAyLjUsDQogICAgIGNleC5heGlzID0gMi41LA0KICAgICB0eXBlPSJsIiwgDQogICAgIHlsYWI9IiIsIA0KICAgICB4bGFiPSJEZW5zaXR5IG9mIHRoZSBnYW1tYSIsDQogICAgIGx3ZD0zKQ0KYWJsaW5lKGg9cWdhbW1hKCBjKDAuMDIsIDAuMDAwMikscmF0ZSA9Mjk2LzIyOTM1NCwgc2hhcGU9MTQgKSwgDQogICAgICAgY29sPWMoInB1cnBsZSIsImJsdWUiKSwgDQogICAgICAgbHdkPTIpDQptdGV4dChjKDAuMDIsIDAuMDAwMiksICMgQWRkIHRleHQgdG8gdGhlIHJpZ2h0IGhhbmQgc2lkZSBvZiBob3Jpem9udGFsIGxpbmVzLiANCiAgICAgIHNpZGU9NCwgDQogICAgICBhdD1xZ2FtbWEoYygwLjAyLCAwLjAwMDIpLA0KICAgICAgcmF0ZSA9Mjk2LzIyOTM1NCwgc2hhcGU9MTQgKSwgDQogICAgICBjb2w9YygicHVycGxlIiwiYmx1ZSIpLCANCiAgICAgIGxhcz0xLCANCiAgICAgIGNleD0yKQ0KDQpgYGANCkluIGdyYXBoIEMgd2Ugb2JzZXJ2ZSB0aGUgZGlzdGFuY2UgKHktYXhpcykgYmV0d2VlbiAxc3QgYW5kIDE1dGggcGFsaW5kcm9tZXMgb2YgZWFjaCBzZXQgb2YgMTUgcGFsaW5kcm9tZXMgaW4gZGlmZmVyZW50IGxvY2F0aW9ucyAoeC1heGlzKSBvZiB0aGUgZ2Vub21lLiBXZSBmb3VuZCB0aGF0IHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB0d28gdGVybWluYWwgcGFsaW5kcm9tZXMgb2YgbW9zdCBvZiB0aGUgc2V0cyBhcmUgZnJvbSB+NjAwMCB0byB+IDE3MDAwIGJwLiBUaGVyZSBhcmUgb25seSB0d28gbG9jYXRpb25zIHdoZXJlIGRpc3RhbmNlcyBhcmUgfjYwMDAgYnAgb3IgbGVzcyAoYmVsb3cgdGhlIHB1cnBsZSBsaW5lIGluIGdyYXBoIEMpLiBJIGFuYWx5emVkIHNldHMgb2YgdGhlIGRpZmZlcmVudCBudW1iZXJzIG9mIHBhbGluZHJvbWVzIChzZXRzIG9mIDEwIHRvIDE4IHBhbGluZHJvbWVzKS4gRWFjaCB0aW1lIEkgZm91bmQgYSBzaW1pbGFyIHBhdHRlcm4gb2YgZGlzdHJpYnV0aW9uIG9mIHZhcmlhYmxlIGRpc3RhbmNlcyBiZXR3ZWVuIHR3byB0ZXJtaW5hbCBwYWxpbmRyb21lcyBvZiBlYWNoIHNldC4gSG93ZXZlciwgYW5hbHlzaXMgd2l0aCB0aGUgc2V0IG9mIDE1IHBhbGluZHJvbWVzIHJlc3VsdGVkIGluIGEgZGVjZW50IG51bWJlciBvZiBsb2NhdGlvbnMgd2hlcmUgZGlzdGFuY2VzIGJldHdlZW4gdHdvIHRlcm1pbmFsIHBhbGluZHJvbWVzIGFyZSBoaWdobHkgKHByb2JhYmlsaXR5IDwwLjAyKSBvciBleHRyZW1lbHkgKHByb2JhYmlsaXR5IDwwLjAwMDIpIGltcHJvYmFibGUuIFRoZXJlZm9yZSwgSSB1c2VkIHRoZSBzZXQgb2YgMTUgcGFsaW5kcm9tZXMgKGxhZz0xNCkgaW4gdGhpcyBhbmFseXNpcy4gR3JhcGggRCBpcyB0aGUgZGVuc2l0eSBwbG90IG9mIHRoZSBnYW1tYSBkaXN0cmlidXRpb24uIEluIGJvdGggZ3JhcGhzLCBwdXJwbGUgYW5kIGJsdWUgbGluZXMgYXJlIHNob3dpbmcgMiUgYW5kIDAuMDIlIHF1YW50aWxlIChleHRyZW1lbHkgc21hbGwgZGlzdGFuY2VzKSBvZiB0aGUgZ2FtbWEgZGlzdHJpYnV0aW9uLiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZXJlIGlzIGFuIGV4dHJlbWVseSBsb3cgcHJvYmFiaWxpdHkgKDwwLjAyKSBvZiB0aGUgb2NjdXJyZW5jZSBvZiAxNSBwYWxpbmRyb21lcyBpbiB0aGVzZSBzbWFsbCBkaXN0YW5jZXMgYnkgY2hhbmNlLiBJZiB3ZSBjb21wYXJlIHRoZSBsb2NhdGlvbnMgb2YgdGhlc2UgdHdvIHJlZ2lvbnMgd2l0aCBncmFwaCBBLCB3ZSBmaW5kIHRoYXQgdGhleSBmYWxsIGluc2lkZSB0aGUgc2ltaWxhciByZWdpb25zIHdlIGRldGVjdGVkIGluIGdyYXBoIEEgd2l0aCA5NSUgcXVhbnRpbGUuIFRoZXNlIHNlZW1pbmdseSB0aWdodCBjbHVzdGVycyAoc2V0cyBvZiAxNSkgb2YgcGFsaW5kcm9tZXMgbWlnaHQgaGF2ZSBzb21lIHNpZ25pZmljYW50IGJpb2xvZ2ljYWwgcm9sZXMsIGZvciBleGFtcGxlLCBtYXkgcG9zc2VzcyB0aGUgb3JpZ2luIG9mIHJlcGxpY2F0aW9uLiAgDQoNCg0KDQpgYGB7ciwgZmlnLmhlaWdodD01fQ0KIyMgc2F2ZSBpbmRleGVzIG9mIGltcHJvYmFibHkgc21hbGwgZGlzdGFuY2VzDQpteXByZWNpb3VzLmluZGV4ZXM8LXdoaWNoKHBnYW1tYShkaWZmKGNtdiwgbGFnPTE0KSwgcmF0ZSA9Mjk2LzIyOTM1NCwgc2hhcGU9MTQpIDwgMC4wMikgIyBDcmVhdGluZyBhIHZlY3RvciB0aGF0IGNvbnRhaW4gaW5kZXhlcyBvZiB0aGUgbG9jYXRpb25zIG9mIDFzdCBwYWxpbmRyb21lcyBvZiBzZXRzIG9mIDE1IHBhbGluZHJvbWVzLCBvZiB3aGljaCwgdGhlIHByb2JhYmlsaXR5IG9mIGRpc3RhbmNlcyBiZXR3ZWVuIDFzdCBhbmQgMTV0aCBwYWxpbmRyb21lIGlzIGxlc3MgdGhhbiAwLjAyIHVzaW5nIHRoZSBjdW11bGF0aXZlIGRlbnNpdHkgb2YgZnVuY3Rpb24sIHBnYW1tYSgpLCBvZiB0aGUgZ2FtbWEgZGlzdHJpYnV0aW9uLiAgIA0KbXlzdHJpY3RwcmVjaW91cy5pbmRleGVzPC13aGljaChwZ2FtbWEoZGlmZihjbXYsIGxhZz0xNCksIHJhdGUgPTI5Ni8yMjkzNTQsIHNoYXBlPTE0KSA8IDAuMDAwMikNCg0KcGFyKG1hcj1jKDUsIDUsIDIsMikpDQpwbG90KGNtdlsxOigyOTYtMTQpXSwgMTooMjk2LTE0KSwgdHlwZT0nbicsICMgQ3JlYXRpbmcgYW4gZW1wdHkgcGxvdC4gDQogICAgIHlsYWI9IlNldHMgb2YgMTUgcGFsaW5kcm9tZXMiLCANCiAgICAgeGxhYj0iTG9jYXRpb25zIGluIHRoZSBDTVYgZ2Vub21lIiwgDQogICAgIG1haW4gPSAiR3JhcGggRTogRGlzdGFuY2VzIGJld2VlbiB0aGUgdHdvIHRlcm1pbmFsIHBhbGluZHJvbWVzIG9mIGVhY2ggc2V0IG9mIDE1IHBhbGluZG9tZXMgYXQgZGlmZmVyZW50IHBvc2l0aW9ucyBpbiBDTVYgZ2Vub21lIiwNCiAgICAgY2V4Lm1haW49IDIuMiwNCiAgICAgY2V4LmxhYj0gMi41LA0KICAgICBjZXguYXhpcyA9IDIuNSwNCiAgICAgbHdkPTMpDQpzZWdtZW50cyhjbXZbMTooMjk2LTE0KV0sIDE6KDI5Ni0xNCksICAjIEFkZCBkaXN0YW5jZXMgYmV0d2VlbiB0d28gdGVybWluYWwgcGFsaW5kcm9tZXMgb2YgZWFjaCBzZXQgb2YgMTUgcGFsaW5kcm9tZXMgYXMgbGluZSBzZWdtZW50cy4NCiAgICAgICAgIGNtdlsoMSsxNCk6Mjk2XSwgMTooMjk2LTE0KSkNCnNlZ21lbnRzKGNtdltteXByZWNpb3VzLmluZGV4ZXNdLCBteXByZWNpb3VzLmluZGV4ZXMsICMgQWRkIGRpc3RhbmNlcyBiZXR3ZWVuIHR3byB0ZXJtaW5hbCBwYWxpbmRyb21lcyBvZiBzZXRzIG9mIHBhbGluZHJvbWVzIGluZGV4ZWQgYnkgbXlwcmVjaW91cyBhcyBsaW5lIHNlZ21lbnRzIHdpdGggcmVkIGNvbG9yLiBUaGlzIHNlZ21lbnRzIG92ZXJyaWRlIHRoZSBwcmV2aW91cyBzZWdtZW50cyBhdCB0aGUgc2FtZSBsb2NhdGlvbnMuIA0KICAgICAgICAgY212W215cHJlY2lvdXMuaW5kZXhlcysxNF0sIG15cHJlY2lvdXMuaW5kZXhlcywgY29sPSJyZWQiLCBsd2QgPSAzKSANCg0Kc2VnbWVudHMoY212W215c3RyaWN0cHJlY2lvdXMuaW5kZXhlc10sIG15c3RyaWN0cHJlY2lvdXMuaW5kZXhlcywgDQogICAgICAgICBjbXZbbXlzdHJpY3RwcmVjaW91cy5pbmRleGVzKzE0XSwgbXlzdHJpY3RwcmVjaW91cy5pbmRleGVzLCBjb2w9IGFkanVzdGNvbG9yKCAieWVsbG93IiwgYWxwaGEuZiA9IDAuNyksIGx3ZCA9IDMpDQpgYGANClRvIHZpc3VhbGl6ZSBkaXN0YW5jZXMgYXMgc2hvd24gaW4gZ3JhcGggQyBtb3JlIGNsZWFybHksIHdlIGRldmVsb3BlZCBHcmFwaCBFLiBJdCBzaG93cyB0aGUgZGlzdGFuY2VzIGJldHdlZW4gdHdvIHRlcm1pbmFsIHBhbGluZHJvbWVzIG9mIHNldHMgb2YgMTUgcGFsaW5kcm9tZXMgYnkgbGluZSBzZWdtZW50cy4gSGVyZSwgZWFjaCBsaW5lIGluZGljYXRlcyBhIHNldCBvZiAxNSBwYWxpbmRyb21lcyBhbmQgdGhlIGxlbmd0aCBvZiB0aGUgbGluZSBpbmRpY2F0ZXMgdGhlIGRpc3RhbmNlIGJldHdlZW4gdGhlIDFzdCBhbmQgMTV0aCBwYWxpbmRyb21lcyBvZiB0aGF0IHNldC4gRnJvbSB0aGUgeC1heGlzLCB3ZSBjYW4gYWxzbyB1bmRlcnN0YW5kIHRoZSBwb3NpdGlvbiBvZiBlYWNoIHNldCBvZiBwYWxpbmRyb21lcyBpbiB0aGUgQ01WIGdlbm9tZS4gV2UgY2FuIHZpc3VhbGl6ZSB0aGF0IHRoZXJlIGFyZSB0d28gcGxhY2VzIGluIHRoZSBnZW5vbWUgKGNvbG9yZWQgd2l0aCBib3RoIHllbGxvdyBhbmQgcmVkKSB3aGVyZSBsZW5ndGhzIG9mIHNldHMgb2YgcGFsaW5kcm9tZXMgYXJlIHNpZ25pZmljYW50bHkgbGVzcyAocHJvYmFiaWxpdHkgaXMgbGVzcyB0aGFuIDAuMDIpIGNvbXBhcmVkIHRvIHRoZSByZXN0IG9mIHRoZSBnZW5vbWUgYXMgYWxzbyBpbmRpY2F0ZWQgaW4gZ3JhcGggQy4gQXMgSSBkaXNjdXNzZWQgYmVmb3JlLCB3aXRoIHRoaXMgZXh0cmVtZWx5IGxvdyBwcm9iYWJpbGl0eSAoPDAuMDIgKHJlZCt5ZWxsb3cgcmVnaW9ucykgIG9yIDwwLjAwMDIgKG9ubHkgeWVsbG93IHJlZ2lvbnMpKSB0aGlzIGlzIGhpZ2hseSB1bmxpa2VseSB0aGF0IHRoZXNlIHBhbGluZHJvbWVzIGFyZSBpbiB0aGVzZSBwb3NpdGlvbnMgb2YgdGhlIGdlbm9tZSBqdXN0IGJ5IGNoYW5jZS4gQmFzZWQgb24gdGhlc2Ugb2JzZXJ2YXRpb25zLCBwcmltYXJpbHkgSSBtYWRlIHR3byByZWNvbW1lbmRhdGlvbnMgYmVsb3cgdG8gc3RhcnQgZXhwZXJpbWVudGFsbHkgc2VhcmNoaW5nIGZvciB0aGUgb3JpZ2luIG9mIHJlcGxpY2F0aW9uLiANCg0KIyMgKkZpbmFsIHJlY29tbWVuZGF0aW9ucyoNCkkgd291bGQgbGlrZSB0byBtYWtlIHR3byBhbHRlcm5hdGUgcmVjb21tZW5kYXRpb25zLiBZb3UgbWF5IHN0YXJ0IHdpdGggYW55IG9uZSBvZiB0aGVzZSBiYXNlZCBvbiB5b3VyIG92ZXJhbGwgZ29hbCwgYXZhaWxhYmxlIHRpbWUsIGFuZCByZXNvdXJjZXMuIA0KDQojIyMgMS4gSWYgeW91IHdhbnQgdG8gc3RhcnQgYW5hbHlzaXMgZm9jdXNpbmcgb24gYnJvYWRlciByZWdpb25zICh3aXRoIHByb2JhYmlsaXR5IDwgMC4wMiksIG1hcmtlZCB3aXRoIHJlZCBhbmQgeWVsbG93IGNvbG9ycyBpbiB0aGUgZ3JhcGggRS4NCmBgYHtyfQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KDQppbmRleF9jbXYxPC0gd2hpY2gocGdhbW1hKGRpZmYoY212LCBsYWc9MTQpLCByYXRlID0yOTYvMjI5MzU0LCBzaGFwZT0xNCkgPCAwLjAyKSAjIFNhbWUgYXMgbXlwcmVjaW91cy5pbmRleGVzDQoNCmJyb2FkX3JlZ2lvbnMgPC0gZGF0YS5mcmFtZShJbmRleD1OQSwgICMgQ3JlYXRpbmcgYSBkYXRhZnJhbWUgY2FsbGVkIGJyb2FkX3JlZ2lvbnMuDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RhcnQ9TkEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRW5kPU5BLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIERpc3RhbmNlPU5BKQ0KDQpmb3IgKGkgaW4gMTpsZW5ndGgoaW5kZXhfY212MSkpIHsNCiAgbG9jID0gaW5kZXhfY212MVtpXQ0KICANCiAgYnJvYWRfcmVnaW9uc1tpLDFdIDwtIGxvYyAgICAjIGFkZGluZyBpbmRleGVzIHRvIHRoZSBmaXJzdCBjb2x1bW4gb2YgdGhlIGRhdGFmcmFtZS4gDQogIGJyb2FkX3JlZ2lvbnNbaSwyXSA8LSBjbXZbbG9jXSAjIGFkZGluZyBzdGFydGluZyBsb2NhdGlvbnMgb2Ygc2V0cyBvZiAxNSBwYWxpbmRyb21lcyB0byB0aGUgc2Vjb25kIGNvbHVtbiBvZiB0aGUgZGF0YWZyYW1lLiANCiAgYnJvYWRfcmVnaW9uc1tpLDNdIDwtIGNtdltsb2MrMTRdICMgYWRkaW5nIGVuZCBsb2NhdGlvbnMgb2Ygc2V0cyBvZiAxNSBwYWxpbmRyb21lcyB0byB0aGUgdGhpcmQgY29sdW1uIG9mIHRoZSBkYXRhZnJhbWUuIA0KICBicm9hZF9yZWdpb25zW2ksNF0gPC0gY212W2xvYysxNF0gLSBjbXZbbG9jXSAjICMgYWRkaW5nIGRpc3RhbmNlcyBiZXR3ZWVuIHR3byB0ZXJtaW5hbHMgcGFsaW5kcm9tZXMgb2Ygc2V0cyAxNSBwYWxpbmRyb21lcyBpbiB0aGUgZm91cnRoIGNvbHVtbiBvZiB0aGUgZGF0YWZyYW1lLiAgDQogIA0KfQ0KdGJsMTwtIGthYmxlKGJyb2FkX3JlZ2lvbnMsIGNhcHRpb24gPSAiVGFibGUgMTogbG9jYXRpb25zIG9mIHR3byB0ZXJtaW5hbCBwYWxpbmRyb21lcyBhbmQgZGlzdGFuY2VzIGJldHdlZW4gdGhlbSBvZiBzZXRzIG9mIDE1IHBhbGluZHJvbWVzIGluIHRoZSBDTVYgZ2Vub21lIChwcm9iYWJpbGl0eSA8IDAuMDIpIikNCmNvbHVtbl9zcGVjKHRibDEsIDE6NCwgd2lkdGggPSAiMWluIikgIyBjcmVhdGluZyBhIHRhYmxlIHdpdGggYSBjYXB0aW9uIGFuZCBkZWZpbmVkIHdpZHRoIG9mIGNvbHVtbnMuIA0KDQpgYGANCkluIHRoZSB0YWJsZSBhYm92ZSwgZWFjaCByb3cgc2hvd3MgdGhlIDFzdCAoU3RhcnQpIGFuZCAxNXRoIChFbmQpIHBvc2l0aW9ucyBvZiBhIHNldCBvZiAxNSBwYWxpbmRyb21lcyBhbmQgdGhlIGRpc3RhbmNlIChEaXN0YW5jZSkgc3Bhbm5lZCBieSB0aG9zZSBwYWxpbmRyb21lcy4gRnJvbSB0aGUgdGFibGUsIHdlIGZpbmQgdGhhdCB0aGUgbWF4aW11bSBkaXN0YW5jZSBhIHNldCBvZiAxNSBwYWxpbmRyb21lcyBzcGFuIGlzIH41NjY4IGJwLiBUaGUgcHJvYmFiaWxpdHkgb2YgdGhlc2UgZGlzdGFuY2VzIGlzIDwgMC4wMiwgd2hpY2ggaXMgaGlnaGx5IGltcHJvYmFibGUsIHdoaWNoIGluZGljYXRlcyB0aGF0IGNvbXBhcmVkIHRvIG90aGVyIGRpc3RhbmNlcyB3aXRoIGEgcHJvYmFiaWxpdHkgPiAwLjAyLCB0aGVzZSBkaXN0YW5jZXMgYXJlIHNpZ25pZmljYW50bHkgc21hbGxlci4gU28sIHdlIGNhbiBzYXkgdGhhdCAxNSBwYWxpbmRyb21lcyBpbiBhIHNldCBhcmUgdGlnaHRseSBwYWNrZWQgdG9nZXRoZXIgaW4gdGhlc2UgcG9zaXRpb25zLiBBbmQgdGhpcyBpcyBoaWdobHkgdW5saWtlbHkgdGhhdCB0aGV5IHBhY2tlZCB0b2dldGhlciBieSBjaGFuY2UgKHdpdGggdGhlIHByb2JhYmlsaXR5IG9mIDAuMDIpLiBUaGlzIHNob3dzIGEgY2xlYXIgZGV2aWF0aW9uIGZyb20gdGhlIGhvbW9nZW5lb3VzIFBvaXNzb24gcHJvY2Vzcy4gVGhlcmVmb3JlLCBhbnkgb25lIG9mIHRoZXNlIHNldHMgb3IgYSBncm91cCBvZiB0aGVzZSBzZXRzIG9mIDE1IHBhbGluZHJvbWVzIG1heSBwb3NzZXNzIHRoZSBzaXRlIG9mIHRoZSBvcmlnaW4gb2YgcmVwbGljYXRpb24uIEJhc2VkIG9uIHRoZSBjb25zZWN1dGl2ZSBzZXRzIG9mIHBhbGluZHJvbWVzIChzZWUgSW5kZXggaW4gdGFibGUgMSksIEkgd291bGQgc3VnZ2VzdCBzdGFydGluZyB0aGUgYW5hbHlzaXMgZm9jdXNpbmcgb24gdGhlc2UgdHdvIHJlZ2lvbnMsIDg3NzE3IGJwIC0gOTc0ODggYnAsIGFuZCAxODk4MTAgYnAgLSAxOTg3MDkgYnAgKHRhYmxlIDEpLiAgIA0KDQojIyMgMi4gIElmIHlvdSB3YW50IHRvIHN0YXJ0IHRoZSBhbmFseXNpcyBieSBmb2N1c2luZyBvbiByZWdpb25zIHdpdGggZXh0cmVtZWx5IGltcHJvYmFibGUgZGlzdGFuY2VzIChwcm9iYWJpbGl0eSA8IDAuMDAwMiksIG1hcmtlZCB3aXRoIG9ubHkgeWVsbG93IGluIHRoZSBncmFwaCBFLiAgDQpgYGB7cn0NCg0KaW5kZXhfY212MjwtIHdoaWNoKHBnYW1tYShkaWZmKGNtdiwgbGFnPTE0KSwgcmF0ZSA9Mjk2LzIyOTM1NCwgc2hhcGU9MTQpIDwgMC4wMDAyKSAjIHNhbWUgYXMgYWJvdmUNCg0Kc21hbGxlcl9yZWdpb25zIDwtIGRhdGEuZnJhbWUoSW5kZXg9TkEsICAgI3NhbWUgYXMgYWJvdmUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFydD1OQSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFbmQ9TkEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRGlzdGFuY2U9TkEpDQoNCmZvciAoaSBpbiAxOmxlbmd0aChpbmRleF9jbXYyKSkgew0KICBsb2MgPSBpbmRleF9jbXYyW2ldDQogIA0KICBzbWFsbGVyX3JlZ2lvbnNbaSwxXSA8LSBsb2MgICAgICAgICAgICAgICAjc2FtZSBhcyBhYm92ZS4NCiAgc21hbGxlcl9yZWdpb25zW2ksMl0gPC0gY212W2xvY10NCiAgc21hbGxlcl9yZWdpb25zW2ksM10gPC0gY212W2xvYysxNF0NCiAgc21hbGxlcl9yZWdpb25zW2ksNF0gPC0gY212W2xvYysxNF0gLSBjbXZbbG9jXQ0KfQ0KdGJsMiA8LSBrYWJsZShzbWFsbGVyX3JlZ2lvbnMsIGNhcHRpb24gPSAiVGFibGUgMjogbG9jYXRpb25zIG9mIHR3byB0ZXJtaW5hbCBwYWxpbmRyb21lcyBhbmQgZGlzdGFuY2VzIGJldHdlZW4gdGhlbSBvZiBzZXRzIG9mIDE1IHBhbGluZHJvbWVzIGluIHRoZSBDTVYgZ2Vub21lIChwcm9iYWJpbGl0eSA8IDAuMDAwMikiKQ0KY29sdW1uX3NwZWModGJsMiwgMTo0LCB3aWR0aCA9ICIxaW4iKQ0KDQpgYGANCklmIHlvdSB3YW50IHRvIHN0YXJ0IHNlYXJjaGluZyBmb3IgdGhlIG9yaWdpbiBvZiByZXBsaWNhdGlvbiB3aXRoaW4gc21hbGxlciByZWdpb25zLCB5b3UgY2FuIHN0YXJ0IHdpdGggdGhlc2UgcmVnaW9ucyBhcyBpbmRpY2F0ZWQgaW4gdGFibGUgMi4gVGhlIGV4YWN0IGxvY2F0aW9ucyBvZiBmb3VyIHNldHMgb2YgZXh0cmVtZWx5IHBhY2tlZCAxNSBwYWxpbmRyb21lcyBhcmUgZ2l2ZW4gaGVyZS4gVGhlIG1heGltdW0gZGlzdGFuY2UgYmV0d2VlbiB0d28gdGVybWluYWwgcGFsaW5kcm9tZXMgb2YgYSBzZXQgaXMgIDI5OTkgYnAgYW5kIHRoZSBtaW5pbXVtIGlzIG9ubHkgMjExMSBicCwgd2hpY2ggaXMgZXh0cmVtZWx5IHVubGlrZWx5ICh3aXRoIHByb2JhYmlsaXR5IDwgMC4wMDAyKSB0aGF0IHRoZSBwYWxpbmRyb21lcyBpbiBhIHNldCBhcmUgdmVyeSB0aWdodGx5IGNsdXN0ZXJlZCB0b2dldGhlciBqdXN0IGJ5IGNoYW5jZS4gVGhlc2UgZXh0cmVtZWx5IHNtYWxsIGRpc3RhbmNlcyBhbHNvIHNob3cgYSBoaWdobHkgc2lnbmlmaWNhbnQgZGV2aWF0aW9uIGZyb20gdGhlIFBvaXNzb24gcHJvY2Vzcy4gVGhlcmVmb3JlLCByZWdpb24gZnJvbSA5MDI1MSBicCB0byA5NDE3NCBicCBoYXMgdGhlIGhpZ2hlc3QgcHJvYmFiaWxpdHkgdG8gaGF2ZSB0aGUgc2l0ZSBvZiB0aGUgb3JpZ2luIG9mIHJlcGxpY2F0aW9uLiBTbywgaXQgaXMgd29ydGggc3RhcnRpbmcgdG8gc2VhcmNoIHdpdGggdGhlc2UgcmVnaW9ucyBmb3IgdGhlIG9yaWdpbiBvZiByZXBsaWNhdGlvbiBpbiB0aGUgbGFib3JhdG9yeSBhbmQgaWYgbmVjZXNzYXJ5LCBleHBsb3JlIHRoZSBvdGhlciByZWdpb25zIGFzIG1lbnRpb25lZCBpbiB0YWJsZSAxLiAgIA0KDQoNCg0KDQoNCg==