1. Have identified problem (over/under-coverage)
Empirical and claimed coverage for each block of 100 simulations (nrep in simdata
) was calculated to produce new graphs.
Firstly, for N0=N1=5000 (800,000 simulations for ordered and unordered). The second graphs are for transforming the x axis to the sqrt scale but I can’t figure out how to get a correct \(y=x\) line?
- And for N0=N1=50000 (400,000 simulations for ordered and unordered). Why are these showing consistent undercoverage?
These plots look a bit weird.. The following are using the same data as that to make the bar charts in the sup meeting 8 files.
Including the threshold
Why did we have to include information on the threshold?
Doing the GAM method on all the data and then predicting on all the held out data gave an excellent prediction.
But when predicting on just a threshold set of held out data (i.e. all those cs formed with threshold 0.6), the prediction was terrible.
When learning the model using just a thresholded set and doing the predicitons it was great.
This shows that the shape of the calibration curves depends on the threshold in some way.
Slight issue is lack of efficiency. If it was that there was one calibration curve for all the data, then one simulation would give us lots of points, but now one simulation will only give us one point.
2. We can fix the problem if we know the CV and its true effect
- Simulations were ran implementing the GAM method for scenarioes where the CV and it’s true effect are known. The simulations are for different LD blocks and different true effect sizes.
Method:
Simulate 100 zstars from \(MVN(E(Z_m),\Sigma)\), where \(E(Z_m)\) is a vector of the true marginal effects.
Convert each of the simulated z vectors to posterior probabilities.
Form a credible set using the standard method.
Use the LOO GAM method to get a corrected coverage value (should this be the LOO method??)
f <- function(dd,thr) {
wh <- which(dd$x>thr)[1]
dd[wh,] # size of cred set
}
library(DescTools)
test1 <- function(d, thr){
a1 <- lapply(d,f,thr) %>% rbindlist() # a1 is dataframe of size and covered for cred sets obtained from each nrep of cali.func
invlogit <- function(x) exp(x)/(1+exp(x))
pred <- numeric(nrow(a1)) # empty vector to fill with predictions
for(i in 1:nrow(a1)) {
m1 <- gam(y ~ s(x), data=a1[-i,], family="binomial") # GAM model
pred[i] <- invlogit(predict(m1,newdata=a1[i,]))
}
error <- BinomCI(sum(a1$y==1), nrow(a1),
conf.level=0.95,
method = "jeffreys")
data.frame(Thr=thr,True.cov=mean(a1$y),Corr.cov=mean(pred), Claim.cov=mean(a1$x), upp=error[1,3], low=error[1,2])
}
# d is x and y co-ords for stepping along x axis until we hit the CV, when we continue stepping along y=1.
test1(d,0.6)
1. Generate data using datagen.R in /gam/CVknown/data/
2. Implement the GAM method using plot.R in /gam/CVknown/
3. Rbind the results and plot (code below).
OR
1. Use allin1.R rcode to go straight to results. Just submit as array job and will get lots of results files out that I can rbind to plot.
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
3. Can we still fix the problem if we don’t know the CV?
Method
Generate some reference data which will be kept constant. This includes LD, freq, maf, CV, snps.
From this generate a system which we want to correct. I.e. one z0 simulation and a credible set, with a claimed coverage (claim0).
(3. Generate some more simulations and credible sets and average the covered column to provide an estimate of the true coverage (this is done for 5000 simulations).)
Assume there are 100 SNPs in our system which we are considering. We want to obtain the marginal given the joint for each SNP being causal. The joint effect for SNP \(i\) being causal is a vector of 100 0’s except entry \(i\) which is the observed effect of that SNP. Use z0 for this.
We obtain 100 \(E(Z_m)\) vectors by multiplying each \(Z_J\) by \(\Sigma\).
From each of these we can simulate \(zstar^*\sim MVN(E(X_J),\Sigma)\). Each row of \(Z_m^*\) is a simulation whereby the columns represent the marginal effects of the SNPs. At this stage, we have 100 lists (one for each SNP being causal) of \(500*100\) matrices (rows=500 simulations, columns=100 SNPs). These zstars have been normalised.
For each simulation in each list, obtain the posterior probabiltiy system.
HOW?
- Convert z scores to Bayes factors where, \[BF=\frac{P(z|z\sim N(0,\omega'))}{P(z|z\sim N(0,1))}\]
- But what is \(\omega'\)? We know that \(\hat{\beta}\sim N(\beta,\hat{\sigma}^2)\) \[H_0: \beta=0\] \[H_1: \beta\sim N(0,\omega)\] So using \(\beta\sim N(0,\omega)\) and \(\hat{\beta}\sim N(\beta,\hat{\sigma}^2)\) we find, \[\hat{\beta}-\beta \sim N(0,\hat{\sigma}^2),\] \[\hat{\beta}-\beta+\beta \sim N(0,\hat{\sigma}^2+\omega).\]
I.e. \(var(\hat{\beta}|H_A)=\hat{\sigma}^2+\omega\).
Now, \(z=\frac{\hat{\beta}}{\hat{\sigma}}\) so, \[var(z|H_A)=\frac{\hat{\sigma}^2+\omega}{\hat{\sigma}^2},\] \[\omega'=\frac{\hat{\sigma}^2+\omega}{\hat{\sigma}^2}.\] So the BF is just the difference of two normal distributions with mean 0.
\[pp_i=\frac{BF_i}{\sum_{j=1}BF_j}\]
Nb, \(\hat{\sigma}\) is obtained using the variance function in coloc. It is a vector with length equal to nsnps.
For the chosen threshold, obtain the credible set using the normal method and report the size (claimed coverage) and whether the CV is present. At this stage, we have 100 lists of \(500*2\) dataframes, the claimed.cov column is the size of the credible set obtained from the simulation and the covered column is whether the CV is in the credible set. There are 500 rows for each \(Z_M^*\) sample.
Use these claimed coverage values as predictors in the GAM model to predict true coverage. One gam model per consideration of each SNP being causal (so 100).
Use each of these to predict the corrected coverage of the original claimed coverage (claim0).
The final estimate of corrected coverage is the weighted sum of these with the true pp.
Practical method (all in gam folder)
(Note that for all this GAM stuff, nsnps is fixed at 100).
Use the data0code.R file to generate lots of original data (submit as an array job and get dataaXX.RDS out). Each of these files contain the CV, iCV, maf, LD matrix, snps, freq (reference genotype matrix) and threshold.
Use the dataatoresults.R file to implement the method on these dataa files (submit as an array job to take in each of the dataXX.RDS files). The output is resultsXX.RDS files saved in results directory. Each of these is a 1*3 dataframe with the true coverage, the claimed coverage and the corrected coverage.
Use the resultsXXtoresults.R file to get summary of results from these (rbind each resultsXX file).
OR
- Use allin1.R rcode to go straight to resultsXX.RDS files.
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
FALSE `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Discussion
If we know the CV, then we can simulate approximately equivalent realisations and get a very accurate corrected coverage. We need to find a way to simulate more accurate realisations when the CV is not known.
We take the observed z at each SNP as the best estimate of the true z if that SNP were causal. We then simulate zstar about this.
Using all the simulated z scores generated from \(MVN(E(Z_m),\Sigma)\) for each SNP being causal presents problems. If that SNP which is being considered as causal has low posterior probability, then it has a z score close to 0. This means that when we simulate around this, we get vectors of z all distributed about 0. When we convert these to posterior probabilities, the system produced will be very flat and not really reflect that posterior probability system we are trying to correct at all.
Low z score –> Simulate zstars about 0 –> Give very flat posterior probability systems –> Larger credible sets.
This means that if we use too small an effect size, the simulations are not equivalent. Instead, we tried scaling by maximum effect size zstar <- zstar * max(abs(zsim))/max(abs(zstar))
, but found these to not be equivalent either.
We therefore need to find a way to simulate better z or just select appropriate z from those that we simulate.
Filter the z that we simulate
We only want to keep the z simulations that are representative of the true z. Could filter out those which are not representative using Euclidean or Mahalanobis distance from the ‘true z’/ the mean of the simulations/the z scores from the system we are correcting?
The Euclidean distance is defined as, \[D_E=\sqrt{\sum_{i=1}^n(q_i-p_i)^2}.\]
It is basically the distance between two points, but is skewed when the points are measured in different units.
The Mahalanobis distance is defined as, \[D_M(\mathbf{x})=\sqrt((\mathbf{x}-\mathbf{u})^T\Sigma^{-1}(\mathbf{x}-\mathbf{u})).\]
Where the \(\mathbf{x}\) are the observations and the \(\mathbf{u}\) are the means.
This method will therefore transform z scores into a zero mean vector and then quantify how representative our simulations are of the ‘true z’/the mean(?). We can then filter out those which are ‘too far’ from the true z.
Mahalanobis distance seems more appropriate as it takes into account the correlations between variables, although it does require inverting the covariance matrix (LD) which is computationally difficult.
Questions and Ideas
Correct y=x line after transforming x axis in first simulations? Are these correct?
Can we filter the z values based on the similarity of the entropy of the true system and the entropy of the posterior probability system they reflect.
For the ‘we know the CV method’, should I be using a LOO GAM method or the method used for when we don’t know the CV of predicting from the claimed coverage of the credible set we are trying to correct? At the moment, the empirical coverage is the mean of the covered column, the corrected coverage is the single value obtained when using the LOO GAM method and the claimed coverage is the mean of the size of the credible sets. Also not sure my error bars are correct?
LS0tCnRpdGxlOiAiTWVldGluZyA5IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgotLS0KCiMjIyAxLiBIYXZlIGlkZW50aWZpZWQgcHJvYmxlbSAob3Zlci91bmRlci1jb3ZlcmFnZSkKCi0tLQoKKiBFbXBpcmljYWwgYW5kIGNsYWltZWQgY292ZXJhZ2UgZm9yIGVhY2ggYmxvY2sgb2YgMTAwIHNpbXVsYXRpb25zIChucmVwIGluIGBgYHNpbWRhdGFgYGApIHdhcyBjYWxjdWxhdGVkIHRvIHByb2R1Y2UgbmV3IGdyYXBocy4gCgoqIEZpcnN0bHksIGZvciBOMD1OMT01MDAwICg4MDAsMDAwIHNpbXVsYXRpb25zIGZvciBvcmRlcmVkIGFuZCB1bm9yZGVyZWQpLiBUaGUgc2Vjb25kIGdyYXBocyBhcmUgZm9yIHRyYW5zZm9ybWluZyB0aGUgeCBheGlzIHRvIHRoZSBzcXJ0IHNjYWxlIGJ1dCBJIGNhbid0IGZpZ3VyZSBvdXQgaG93IHRvIGdldCBhIGNvcnJlY3QgJHk9eCQgbGluZT8KCjxwIGZsb2F0PSJsZWZ0Ij4KICA8aW1nIHNyYz0iL1VzZXJzL2FubmEvR29vZ2xlIERyaXZlL1BoRC9iYXJjaGFydHMvNTAwMHZlcjIucG5nIiB3aWR0aD0iMTAwMCIgLz4KPC9wPgoKPHAgZmxvYXQ9ImxlZnQiPgogIDxpbWcgc3JjPSIvVXNlcnMvYW5uYS9Hb29nbGUgRHJpdmUvUGhEL2JhcmNoYXJ0cy81MDAwdHJhbnNmb3JtZWQuanBlZyIgd2lkdGg9IjgwMCIgLz4KPC9wPgoKLS0tCgoqIEFuZCBmb3IgTjA9TjE9NTAwMDAgKDQwMCwwMDAgc2ltdWxhdGlvbnMgZm9yIG9yZGVyZWQgYW5kIHVub3JkZXJlZCkuIFdoeSBhcmUgdGhlc2Ugc2hvd2luZyBjb25zaXN0ZW50IHVuZGVyY292ZXJhZ2U/Cgo8cCBmbG9hdD0ibGVmdCI+CiAgPGltZyBzcmM9Ii9Vc2Vycy9hbm5hL0dvb2dsZSBEcml2ZS9QaEQvYmFyY2hhcnRzLzUway5qcGVnIiB3aWR0aD0iODAwIiAvPgo8L3A+CgpUaGVzZSBwbG90cyBsb29rIGEgYml0IHdlaXJkLi4gVGhlIGZvbGxvd2luZyBhcmUgdXNpbmcgdGhlIHNhbWUgZGF0YSBhcyB0aGF0IHRvIG1ha2UgdGhlIGJhciBjaGFydHMgaW4gdGhlIHN1cCBtZWV0aW5nIDggZmlsZXMuIAo8cCBmbG9hdD0ibGVmdCI+CiAgPGltZyBzcmM9Ii9Vc2Vycy9hbm5hL0dvb2dsZSBEcml2ZS9QaEQvYmFyY2hhcnRzL3NhbWVkYXRhLnBuZyIgd2lkdGg9IjEwMDAiIC8+CjwvcD4KCgotLS0KCiMjIyMgSW5jbHVkaW5nIHRoZSB0aHJlc2hvbGQKCi0tLQoKKiBXaHkgZGlkIHdlIGhhdmUgdG8gaW5jbHVkZSBpbmZvcm1hdGlvbiBvbiB0aGUgdGhyZXNob2xkPwoKKiBEb2luZyB0aGUgR0FNIG1ldGhvZCBvbiBhbGwgdGhlIGRhdGEgYW5kIHRoZW4gcHJlZGljdGluZyBvbiBhbGwgdGhlIGhlbGQgb3V0IGRhdGEgZ2F2ZSBhbiBleGNlbGxlbnQgcHJlZGljdGlvbi4KCiogQnV0IHdoZW4gcHJlZGljdGluZyBvbiBqdXN0IGEgdGhyZXNob2xkIHNldCBvZiBoZWxkIG91dCBkYXRhIChpLmUuIGFsbCB0aG9zZSBjcyBmb3JtZWQgd2l0aCB0aHJlc2hvbGQgMC42KSwgdGhlIHByZWRpY3Rpb24gd2FzIHRlcnJpYmxlLiAKCiogV2hlbiBsZWFybmluZyB0aGUgbW9kZWwgdXNpbmcganVzdCBhIHRocmVzaG9sZGVkIHNldCBhbmQgZG9pbmcgdGhlIHByZWRpY2l0b25zIGl0IHdhcyBncmVhdC4gCgoqIFRoaXMgc2hvd3MgdGhhdCB0aGUgc2hhcGUgb2YgdGhlIGNhbGlicmF0aW9uIGN1cnZlcyBkZXBlbmRzIG9uIHRoZSB0aHJlc2hvbGQgaW4gc29tZSB3YXkuIAoKKiBTbGlnaHQgaXNzdWUgaXMgbGFjayBvZiBlZmZpY2llbmN5LiBJZiBpdCB3YXMgdGhhdCB0aGVyZSB3YXMgb25lIGNhbGlicmF0aW9uIGN1cnZlIGZvciBhbGwgdGhlIGRhdGEsIHRoZW4gb25lIHNpbXVsYXRpb24gd291bGQgZ2l2ZSB1cyBsb3RzIG9mIHBvaW50cywgYnV0IG5vdyBvbmUgc2ltdWxhdGlvbiB3aWxsIG9ubHkgZ2l2ZSB1cyBvbmUgcG9pbnQuCgotLS0KCiMjIyAyLiBXZSBjYW4gZml4IHRoZSBwcm9ibGVtIGlmIHdlIGtub3cgdGhlIENWIGFuZCBpdHMgdHJ1ZSBlZmZlY3QKCi0tLQoKKiBTaW11bGF0aW9ucyB3ZXJlIHJhbiBpbXBsZW1lbnRpbmcgdGhlIEdBTSBtZXRob2QgZm9yIHNjZW5hcmlvZXMgd2hlcmUgdGhlIENWIGFuZCBpdCdzIHRydWUgZWZmZWN0IGFyZSBrbm93bi4gVGhlIHNpbXVsYXRpb25zIGFyZSBmb3IgZGlmZmVyZW50IExEIGJsb2NrcyBhbmQgZGlmZmVyZW50IHRydWUgZWZmZWN0IHNpemVzLiAKCk1ldGhvZDoKCjEuIFNpbXVsYXRlIDEwMCB6c3RhcnMgZnJvbSAkTVZOKEUoWl9tKSxcU2lnbWEpJCwgd2hlcmUgJEUoWl9tKSQgaXMgYSB2ZWN0b3Igb2YgdGhlIHRydWUgbWFyZ2luYWwgZWZmZWN0cy4gCgoyLiBDb252ZXJ0IGVhY2ggb2YgdGhlIHNpbXVsYXRlZCB6IHZlY3RvcnMgdG8gcG9zdGVyaW9yIHByb2JhYmlsaXRpZXMuCgozLiBGb3JtIGEgY3JlZGlibGUgc2V0IHVzaW5nIHRoZSBzdGFuZGFyZCBtZXRob2QuIAoKNC4gVXNlIHRoZSBMT08gR0FNIG1ldGhvZCB0byBnZXQgYSBjb3JyZWN0ZWQgY292ZXJhZ2UgdmFsdWUgKHNob3VsZCB0aGlzIGJlIHRoZSBMT08gbWV0aG9kPz8pCgpgYGB7ciBldmFsPUZBTFNFfQpmIDwtIGZ1bmN0aW9uKGRkLHRocikgewogIHdoIDwtIHdoaWNoKGRkJHg+dGhyKVsxXQogIGRkW3doLF0gIyBzaXplIG9mIGNyZWQgc2V0Cn0KCgpsaWJyYXJ5KERlc2NUb29scykKCnRlc3QxIDwtIGZ1bmN0aW9uKGQsIHRocil7CiAgYTEgPC0gbGFwcGx5KGQsZix0aHIpICAlPiUgcmJpbmRsaXN0KCkgIyBhMSBpcyBkYXRhZnJhbWUgb2Ygc2l6ZSBhbmQgY292ZXJlZCBmb3IgY3JlZCBzZXRzIG9idGFpbmVkIGZyb20gZWFjaCBucmVwIG9mIGNhbGkuZnVuYwogIAogIGludmxvZ2l0IDwtIGZ1bmN0aW9uKHgpIGV4cCh4KS8oMStleHAoeCkpCiAgcHJlZCA8LSBudW1lcmljKG5yb3coYTEpKSAjIGVtcHR5IHZlY3RvciB0byBmaWxsIHdpdGggcHJlZGljdGlvbnMKICBmb3IoaSBpbiAxOm5yb3coYTEpKSB7CiAgICBtMSA8LSBnYW0oeSB+IHMoeCksIGRhdGE9YTFbLWksXSwgZmFtaWx5PSJiaW5vbWlhbCIpICMgR0FNIG1vZGVsCiAgICBwcmVkW2ldIDwtIGludmxvZ2l0KHByZWRpY3QobTEsbmV3ZGF0YT1hMVtpLF0pKQogIH0KICBlcnJvciA8LSBCaW5vbUNJKHN1bShhMSR5PT0xKSwgbnJvdyhhMSksIAogICAgICAgICAgICAgICAgICAgY29uZi5sZXZlbD0wLjk1LAogICAgICAgICAgICAgICAgICAgbWV0aG9kID0gImplZmZyZXlzIikKICBkYXRhLmZyYW1lKFRocj10aHIsVHJ1ZS5jb3Y9bWVhbihhMSR5KSxDb3JyLmNvdj1tZWFuKHByZWQpLCBDbGFpbS5jb3Y9bWVhbihhMSR4KSwgdXBwPWVycm9yWzEsM10sIGxvdz1lcnJvclsxLDJdKQp9CgojIGQgaXMgeCBhbmQgeSBjby1vcmRzIGZvciBzdGVwcGluZyBhbG9uZyB4IGF4aXMgdW50aWwgd2UgaGl0IHRoZSBDViwgd2hlbiB3ZSBjb250aW51ZSBzdGVwcGluZyBhbG9uZyB5PTEuCnRlc3QxKGQsMC42KQoKYGBgCgpgYGAKMS4gR2VuZXJhdGUgZGF0YSB1c2luZyBkYXRhZ2VuLlIgaW4gL2dhbS9DVmtub3duL2RhdGEvCjIuIEltcGxlbWVudCB0aGUgR0FNIG1ldGhvZCB1c2luZyBwbG90LlIgaW4gL2dhbS9DVmtub3duLwozLiBSYmluZCB0aGUgcmVzdWx0cyBhbmQgcGxvdCAoY29kZSBiZWxvdykuCgpPUiAKMS4gVXNlIGFsbGluMS5SIHJjb2RlIHRvIGdvIHN0cmFpZ2h0IHRvIHJlc3VsdHMuIEp1c3Qgc3VibWl0IGFzIGFycmF5IGpvYiBhbmQgd2lsbCBnZXQgbG90cyBvZiByZXN1bHRzIGZpbGVzIG91dCB0aGF0IEkgY2FuIHJiaW5kIHRvIHBsb3QuCmBgYAoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgY29tbWVudD1GQUxTRSwgZXJyb3I9RkFMU0V9CmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdncGxvdDIpCmRmIDwtIHJlYWRSRFMoIi9Vc2Vycy9hbm5hL0NWa25vd25kYXRhLlJEUyIpCgpwbG90IDwtIGdncGxvdChkYXRhPWRmLGFlcyh4PUNvcnIuY292LHk9VHJ1ZS5jb3YpKStnZW9tX3BvaW50KCkrZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1sb3csIHltYXg9dXBwKSwgc2l6ZT0wLjIsYWxwaGE9MC41LCB3aWR0aD0uMDA1KStnZW9tX2FibGluZShhPTAsYj0xKQpwbG90IDwtIHBsb3QrZ2VvbV9zbW9vdGgoKSt5bGFiKCJFbXBpcmljYWwgQ292ZXJhZ2UiKSt4bGFiKCJDb3JyZWN0ZWQgQ292ZXJhZ2UiKStnZ3RpdGxlKCJFbXBpcmljYWwgYW5kIENvcnJlY3RlZCBDb3ZlcmFnZSBmb3IgXG4gR0FNIE1ldGhvZCB3aXRoIEtub3duIENWIikreWxpbSgwLjU1LDEpK3hsaW0oMC41NSwxKQoKcGxvdDEgPC0gZ2dwbG90KGRhdGE9ZGYsIGFlcyh4PUNsYWltLmNvdix5PVRydWUuY292KSkrZ2VvbV9wb2ludCgpK2dlb21fZXJyb3JiYXIoYWVzKHltaW49bG93LCB5bWF4PXVwcCksIHNpemU9MC4yLGFscGhhPTAuNSwgd2lkdGg9LjAwNSkrZ2VvbV9hYmxpbmUoYT0wLGI9MSkKcGxvdDEgPC0gcGxvdDErZ2VvbV9zbW9vdGgoKSt5bGFiKCJFbXBpcmljYWwgQ292ZXJhZ2UiKSt4bGFiKCJDbGFpbWVkIENvdmVyYWdlIikrZ2d0aXRsZSgiRW1waXJpY2FsIGFuZCBDbGFpbWVkIENvdmVyYWdlIGZvciBcbiBHQU0gTWV0aG9kIHdpdGggS25vd24gQ1YiKSt5bGltKDAuNiwxKSt4bGltKDAuNiwxKQoKbGlicmFyeShjb3dwbG90KQpwbG90X2dyaWQocGxvdCsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSksIHBsb3QxKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTIpKSwgbGFiZWxzID0gIkFVVE8iLGFsaWduID0gJ3YnLCBzY2FsZT0wLjgpCgojIyMKI2RmMSA8LSBkYXRhLmZyYW1lKCJUcnVlLmNvdiI9YyhyZXAoZGYkVHJ1ZS5jb3YsMikpLCJDb3ZlcmFnZSI9YyhkZiRDb3JyLmNvdixkZiRDbGFpbS5jb3YpLCJ1cHAiPWRmJHVwcCwibG93Ij1kZiRsb3csInR5cGUiPWMocmVwKCJDb3JyZWN0ZWQiLDIqbnJvdyhkZikpLHJlcCgiQ2xhaW1lZCIsMipucm93KGRmKSkpKQoKI3Bsb3QyIDwtZ2dwbG90KGRhdGE9ZGYxLCBhZXMoeD1UcnVlLmNvdix5PUNvdmVyYWdlLGNvbG91cj10eXBlKSkrZ2VvbV9wb2ludCgpCiNwbG90MitnZW9tX3Ntb290aCgpCmBgYAoKLS0tCgojIyMgMy4gQ2FuIHdlIHN0aWxsIGZpeCB0aGUgcHJvYmxlbSBpZiB3ZSBkb24ndCBrbm93IHRoZSBDVj8KCi0tLQoKIyMjIE1ldGhvZAoKLS0tCgoxLiBHZW5lcmF0ZSBzb21lIHJlZmVyZW5jZSBkYXRhIHdoaWNoIHdpbGwgYmUga2VwdCBjb25zdGFudC4gVGhpcyBpbmNsdWRlcyBMRCwgZnJlcSwgbWFmLCBDViwgc25wcy4KCjIuIEZyb20gdGhpcyBnZW5lcmF0ZSBhIHN5c3RlbSB3aGljaCB3ZSB3YW50IHRvIGNvcnJlY3QuIEkuZS4gb25lIHowIHNpbXVsYXRpb24gYW5kIGEgY3JlZGlibGUgc2V0LCB3aXRoIGEgY2xhaW1lZCBjb3ZlcmFnZSAoY2xhaW0wKS4KCigzLiBHZW5lcmF0ZSBzb21lIG1vcmUgc2ltdWxhdGlvbnMgYW5kIGNyZWRpYmxlIHNldHMgYW5kIGF2ZXJhZ2UgdGhlIGNvdmVyZWQgY29sdW1uIHRvIHByb3ZpZGUgYW4gZXN0aW1hdGUgb2YgdGhlIHRydWUgY292ZXJhZ2UgKHRoaXMgaXMgZG9uZSBmb3IgNTAwMCBzaW11bGF0aW9ucykuKQoKNC4gQXNzdW1lIHRoZXJlIGFyZSAxMDAgU05QcyBpbiBvdXIgc3lzdGVtIHdoaWNoIHdlIGFyZSBjb25zaWRlcmluZy4gV2Ugd2FudCB0byBvYnRhaW4gdGhlIG1hcmdpbmFsIGdpdmVuIHRoZSBqb2ludCBmb3IgZWFjaCBTTlAgYmVpbmcgY2F1c2FsLiBUaGUgam9pbnQgZWZmZWN0IGZvciBTTlAgJGkkIGJlaW5nIGNhdXNhbCBpcyBhIHZlY3RvciBvZiAxMDAgMCdzIGV4Y2VwdCBlbnRyeSAkaSQgd2hpY2ggaXMgdGhlIG9ic2VydmVkIGVmZmVjdCBvZiB0aGF0IFNOUC4gVXNlIHowIGZvciB0aGlzLiAKCjUuIFdlIG9idGFpbiAxMDAgJEUoWl9tKSQgdmVjdG9ycyBieSBtdWx0aXBseWluZyBlYWNoICRaX0okIGJ5ICRcU2lnbWEkLiAKCjYuIEZyb20gZWFjaCBvZiB0aGVzZSB3ZSBjYW4gc2ltdWxhdGUgJHpzdGFyXipcc2ltIE1WTihFKFhfSiksXFNpZ21hKSQuIEVhY2ggcm93IG9mICRaX21eKiQgaXMgYSBzaW11bGF0aW9uIHdoZXJlYnkgdGhlIGNvbHVtbnMgcmVwcmVzZW50IHRoZSBtYXJnaW5hbCBlZmZlY3RzIG9mIHRoZSBTTlBzLiBBdCB0aGlzIHN0YWdlLCB3ZSBoYXZlIDEwMCBsaXN0cyAob25lIGZvciBlYWNoIFNOUCBiZWluZyBjYXVzYWwpIG9mICQ1MDAqMTAwJCBtYXRyaWNlcyAocm93cz01MDAgc2ltdWxhdGlvbnMsIGNvbHVtbnM9MTAwIFNOUHMpLiBUaGVzZSB6c3RhcnMgaGF2ZSBiZWVuIG5vcm1hbGlzZWQuCgo3LiBGb3IgZWFjaCBzaW11bGF0aW9uIGluIGVhY2ggbGlzdCwgb2J0YWluIHRoZSBwb3N0ZXJpb3IgcHJvYmFiaWx0aXkgc3lzdGVtLgoKLS0tCgpIT1c/CgoxLiBDb252ZXJ0IHogc2NvcmVzIHRvIEJheWVzIGZhY3RvcnMgd2hlcmUsIAokJEJGPVxmcmFje1Aoenx6XHNpbSBOKDAsXG9tZWdhJykpfXtQKHp8elxzaW0gTigwLDEpKX0kJAoKKiBCdXQgd2hhdCBpcyAkXG9tZWdhJyQ/CldlIGtub3cgdGhhdCAkXGhhdHtcYmV0YX1cc2ltIE4oXGJldGEsXGhhdHtcc2lnbWF9XjIpJAokJEhfMDogXGJldGE9MCQkCiQkSF8xOiBcYmV0YVxzaW0gTigwLFxvbWVnYSkkJApTbyB1c2luZyAkXGJldGFcc2ltIE4oMCxcb21lZ2EpJCBhbmQgJFxoYXR7XGJldGF9XHNpbSBOKFxiZXRhLFxoYXR7XHNpZ21hfV4yKSQgd2UgZmluZCwKJCRcaGF0e1xiZXRhfS1cYmV0YSBcc2ltIE4oMCxcaGF0e1xzaWdtYX1eMiksJCQKJCRcaGF0e1xiZXRhfS1cYmV0YStcYmV0YSBcc2ltIE4oMCxcaGF0e1xzaWdtYX1eMitcb21lZ2EpLiQkCgpJLmUuICR2YXIoXGhhdHtcYmV0YX18SF9BKT1caGF0e1xzaWdtYX1eMitcb21lZ2EkLgoKTm93LCAkej1cZnJhY3tcaGF0e1xiZXRhfX17XGhhdHtcc2lnbWF9fSQgc28sCiQkdmFyKHp8SF9BKT1cZnJhY3tcaGF0e1xzaWdtYX1eMitcb21lZ2F9e1xoYXR7XHNpZ21hfV4yfSwkJAokJFxvbWVnYSc9XGZyYWN7XGhhdHtcc2lnbWF9XjIrXG9tZWdhfXtcaGF0e1xzaWdtYX1eMn0uJCQKU28gdGhlIEJGIGlzIGp1c3QgdGhlIGRpZmZlcmVuY2Ugb2YgdHdvIG5vcm1hbCBkaXN0cmlidXRpb25zIHdpdGggbWVhbiAwLiAKCiQkcHBfaT1cZnJhY3tCRl9pfXtcc3VtX3tqPTF9QkZfan0kJAoKTmIsICRcaGF0e1xzaWdtYX0kIGlzIG9idGFpbmVkIHVzaW5nIHRoZSB2YXJpYW5jZSBmdW5jdGlvbiBpbiBjb2xvYy4gSXQgaXMgYSB2ZWN0b3Igd2l0aCBsZW5ndGggZXF1YWwgdG8gbnNucHMuCgotLS0KCjguIEZvciB0aGUgY2hvc2VuIHRocmVzaG9sZCwgb2J0YWluIHRoZSBjcmVkaWJsZSBzZXQgdXNpbmcgdGhlIG5vcm1hbCBtZXRob2QgYW5kIHJlcG9ydCB0aGUgc2l6ZSAoY2xhaW1lZCBjb3ZlcmFnZSkgYW5kIHdoZXRoZXIgdGhlIENWIGlzIHByZXNlbnQuIEF0IHRoaXMgc3RhZ2UsIHdlIGhhdmUgMTAwIGxpc3RzIG9mICQ1MDAqMiQgZGF0YWZyYW1lcywgdGhlIGNsYWltZWQuY292IGNvbHVtbiBpcyB0aGUgc2l6ZSBvZiB0aGUgY3JlZGlibGUgc2V0IG9idGFpbmVkIGZyb20gdGhlIHNpbXVsYXRpb24gYW5kIHRoZSBjb3ZlcmVkIGNvbHVtbiBpcyB3aGV0aGVyIHRoZSBDViBpcyBpbiB0aGUgY3JlZGlibGUgc2V0LiBUaGVyZSBhcmUgNTAwIHJvd3MgZm9yIGVhY2ggJFpfTV4qJCBzYW1wbGUuCgo5LiBVc2UgdGhlc2UgY2xhaW1lZCBjb3ZlcmFnZSB2YWx1ZXMgYXMgcHJlZGljdG9ycyBpbiB0aGUgR0FNIG1vZGVsIHRvIHByZWRpY3QgdHJ1ZSBjb3ZlcmFnZS4gT25lIGdhbSBtb2RlbCBwZXIgY29uc2lkZXJhdGlvbiBvZiBlYWNoIFNOUCBiZWluZyBjYXVzYWwgKHNvIDEwMCkuCgoxMC4gVXNlIGVhY2ggb2YgdGhlc2UgdG8gcHJlZGljdCB0aGUgY29ycmVjdGVkIGNvdmVyYWdlIG9mIHRoZSBvcmlnaW5hbCBjbGFpbWVkIGNvdmVyYWdlIChjbGFpbTApLgoKMTEuIFRoZSBmaW5hbCBlc3RpbWF0ZSBvZiBjb3JyZWN0ZWQgY292ZXJhZ2UgaXMgdGhlIHdlaWdodGVkIHN1bSBvZiB0aGVzZSB3aXRoIHRoZSB0cnVlIHBwLgoKLS0tLQoKIyMjIFByYWN0aWNhbCBtZXRob2QgKGFsbCBpbiBnYW0gZm9sZGVyKQoKKE5vdGUgdGhhdCBmb3IgYWxsIHRoaXMgR0FNIHN0dWZmLCBuc25wcyBpcyBmaXhlZCBhdCAxMDApLgoKMS4gVXNlIHRoZSBkYXRhMGNvZGUuUiBmaWxlIHRvIGdlbmVyYXRlIGxvdHMgb2Ygb3JpZ2luYWwgZGF0YSAoc3VibWl0IGFzIGFuIGFycmF5IGpvYiBhbmQgZ2V0IGRhdGFhWFguUkRTIG91dCkuIEVhY2ggb2YgdGhlc2UgZmlsZXMgY29udGFpbiB0aGUgQ1YsIGlDViwgbWFmLCBMRCBtYXRyaXgsIHNucHMsIGZyZXEgKHJlZmVyZW5jZSBnZW5vdHlwZSBtYXRyaXgpIGFuZCB0aHJlc2hvbGQuCgoyLiBVc2UgdGhlIGRhdGFhdG9yZXN1bHRzLlIgZmlsZSB0byBpbXBsZW1lbnQgdGhlIG1ldGhvZCBvbiB0aGVzZSBkYXRhYSBmaWxlcyAoc3VibWl0IGFzIGFuIGFycmF5IGpvYiB0byB0YWtlIGluIGVhY2ggb2YgdGhlIGRhdGFYWC5SRFMgZmlsZXMpLiBUaGUgb3V0cHV0IGlzIHJlc3VsdHNYWC5SRFMgZmlsZXMgc2F2ZWQgaW4gcmVzdWx0cyBkaXJlY3RvcnkuIEVhY2ggb2YgdGhlc2UgaXMgYSAxKjMgZGF0YWZyYW1lIHdpdGggdGhlIHRydWUgY292ZXJhZ2UsIHRoZSBjbGFpbWVkIGNvdmVyYWdlIGFuZCB0aGUgY29ycmVjdGVkIGNvdmVyYWdlLiAKCjMuIFVzZSB0aGUgcmVzdWx0c1hYdG9yZXN1bHRzLlIgZmlsZSB0byBnZXQgc3VtbWFyeSBvZiByZXN1bHRzIGZyb20gdGhlc2UgKHJiaW5kIGVhY2ggcmVzdWx0c1hYIGZpbGUpLiAKCk9SIAoKMS4gVXNlIGFsbGluMS5SIHJjb2RlIHRvIGdvIHN0cmFpZ2h0IHRvIHJlc3VsdHNYWC5SRFMgZmlsZXMuCgpgYGB7ciBlY2hvPUZBTFNFfQpyZXN1bHRzIDwtIHJlYWRSRFMoIi9Vc2Vycy9hbm5hL3Jlc3VsdHMuUkRTIikKcmVzdWx0cwpgYGAKCgpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjb21tZW50PUZBTFNFfQpwbG90IDwtIGdncGxvdChkYXRhPXJlc3VsdHMsYWVzKHg9Q29ycmVjdGVkLmNvdix5PVRydWUuY292KSkrZ2VvbV9wb2ludCgpK2dlb21fYWJsaW5lKGE9MCxiPTEsKQpwbG90IDwtIHBsb3QrZ2VvbV9zbW9vdGgoKSt5bGFiKCJFbXBpcmljYWwgQ292ZXJhZ2UiKSt4bGFiKCJDb3JyZWN0ZWQgQ292ZXJhZ2UiKStnZ3RpdGxlKCJFbXBpcmljYWwgYW5kIENvcnJlY3RlZCBDb3ZlcmFnZSBmb3IgXG4gR0FNIE1ldGhvZCB3aXRoIFVua25vd24gQ1YiKSt5bGltKDAuNTUsMSkreGxpbSgwLjY1LDEpCgpwbG90MSA8LSBnZ3Bsb3QoZGF0YT1yZXN1bHRzLCBhZXMoeD1DbGFpbWVkLmNvdix5PVRydWUuY292KSkrZ2VvbV9wb2ludCgpK2dlb21fYWJsaW5lKGE9MCxiPTEsKQpwbG90MSA8LSBwbG90MStnZW9tX3Ntb290aCgpK3lsYWIoIkVtcGlyaWNhbCBDb3ZlcmFnZSIpK3hsYWIoIkNsYWltZWQgQ292ZXJhZ2UiKStnZ3RpdGxlKCJFbXBpcmljYWwgYW5kIENsYWltZWQgQ292ZXJhZ2UgZm9yIFxuIEdBTSBNZXRob2Qgd2l0aCBVbmtub3duIENWIikreWxpbSgwLjYsMSkreGxpbSgwLjYsMSkKCmxpYnJhcnkoY293cGxvdCkKcGxvdF9ncmlkKHBsb3QrIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0xMikpLCBwbG90MSsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSksIGxhYmVscyA9ICJBVVRPIixhbGlnbiA9ICd2JyxzY2FsZT0wLjgpCmBgYAoKLS0tCgojIyMgRGlzY3Vzc2lvbgoKKiBJZiB3ZSBrbm93IHRoZSBDViwgdGhlbiB3ZSBjYW4gc2ltdWxhdGUgYXBwcm94aW1hdGVseSBlcXVpdmFsZW50IHJlYWxpc2F0aW9ucyBhbmQgZ2V0IGEgdmVyeSBhY2N1cmF0ZSBjb3JyZWN0ZWQgY292ZXJhZ2UuIFdlIG5lZWQgdG8gZmluZCBhIHdheSB0byBzaW11bGF0ZSBtb3JlIGFjY3VyYXRlIHJlYWxpc2F0aW9ucyB3aGVuIHRoZSBDViBpcyBub3Qga25vd24uIAoKKiBXZSB0YWtlIHRoZSBvYnNlcnZlZCB6IGF0IGVhY2ggU05QIGFzIHRoZSBiZXN0IGVzdGltYXRlIG9mIHRoZSB0cnVlIHogaWYgdGhhdCBTTlAgd2VyZSBjYXVzYWwuIFdlIHRoZW4gc2ltdWxhdGUgenN0YXIgYWJvdXQgdGhpcy4gCgoqIFVzaW5nIGFsbCB0aGUgc2ltdWxhdGVkIHogc2NvcmVzIGdlbmVyYXRlZCBmcm9tICRNVk4oRShaX20pLFxTaWdtYSkkIGZvciBlYWNoIFNOUCBiZWluZyBjYXVzYWwgcHJlc2VudHMgcHJvYmxlbXMuIElmIHRoYXQgU05QIHdoaWNoIGlzIGJlaW5nIGNvbnNpZGVyZWQgYXMgY2F1c2FsIGhhcyBsb3cgcG9zdGVyaW9yIHByb2JhYmlsaXR5LCB0aGVuIGl0IGhhcyBhIHogc2NvcmUgY2xvc2UgdG8gMC4gVGhpcyBtZWFucyB0aGF0IHdoZW4gd2Ugc2ltdWxhdGUgYXJvdW5kIHRoaXMsIHdlIGdldCB2ZWN0b3JzIG9mIHogYWxsIGRpc3RyaWJ1dGVkIGFib3V0IDAuIFdoZW4gd2UgY29udmVydCB0aGVzZSB0byBwb3N0ZXJpb3IgcHJvYmFiaWxpdGllcywgdGhlIHN5c3RlbSBwcm9kdWNlZCB3aWxsIGJlIHZlcnkgZmxhdCBhbmQgbm90IHJlYWxseSByZWZsZWN0IHRoYXQgcG9zdGVyaW9yIHByb2JhYmlsaXR5IHN5c3RlbSB3ZSBhcmUgdHJ5aW5nIHRvIGNvcnJlY3QgYXQgYWxsLiAKCiAgICAqKkxvdyB6IHNjb3JlIC0tPiBTaW11bGF0ZSB6c3RhcnMgYWJvdXQgMCAtLT4gR2l2ZSB2ZXJ5IGZsYXQgcG9zdGVyaW9yIHByb2JhYmlsaXR5IHN5c3RlbXMgLS0+IExhcmdlciBjcmVkaWJsZSBzZXRzLioqCgoqIFRoaXMgbWVhbnMgdGhhdCBpZiB3ZSB1c2UgdG9vIHNtYWxsIGFuIGVmZmVjdCBzaXplLCB0aGUgc2ltdWxhdGlvbnMgYXJlIG5vdCBlcXVpdmFsZW50LiBJbnN0ZWFkLCB3ZSB0cmllZCBzY2FsaW5nIGJ5IG1heGltdW0gZWZmZWN0IHNpemUgYGBgenN0YXIgPC0genN0YXIgKiBtYXgoYWJzKHpzaW0pKS9tYXgoYWJzKHpzdGFyKSlgYGAsIGJ1dCBmb3VuZCB0aGVzZSB0byBub3QgYmUgZXF1aXZhbGVudCBlaXRoZXIuIAoKKiBXZSB0aGVyZWZvcmUgbmVlZCB0byBmaW5kIGEgd2F5IHRvIHNpbXVsYXRlIGJldHRlciB6IG9yIGp1c3Qgc2VsZWN0IGFwcHJvcHJpYXRlIHogZnJvbSB0aG9zZSB0aGF0IHdlIHNpbXVsYXRlLiAKCi0tLQoKIyMjIEZpbHRlciB0aGUgeiB0aGF0IHdlIHNpbXVsYXRlCgoqIFdlIG9ubHkgd2FudCB0byBrZWVwIHRoZSB6IHNpbXVsYXRpb25zIHRoYXQgYXJlIHJlcHJlc2VudGF0aXZlIG9mIHRoZSB0cnVlIHouIENvdWxkIGZpbHRlciBvdXQgdGhvc2Ugd2hpY2ggYXJlIG5vdCByZXByZXNlbnRhdGl2ZSB1c2luZyBFdWNsaWRlYW4gb3IgTWFoYWxhbm9iaXMgZGlzdGFuY2UgZnJvbSB0aGUgJ3RydWUgeicvIHRoZSBtZWFuIG9mIHRoZSBzaW11bGF0aW9ucy90aGUgeiBzY29yZXMgZnJvbSB0aGUgc3lzdGVtIHdlIGFyZSBjb3JyZWN0aW5nPwoKKiBUaGUgRXVjbGlkZWFuIGRpc3RhbmNlIGlzIGRlZmluZWQgYXMsCiQkRF9FPVxzcXJ0e1xzdW1fe2k9MX1ebihxX2ktcF9pKV4yfS4kJAoKKiBJdCBpcyBiYXNpY2FsbHkgdGhlIGRpc3RhbmNlIGJldHdlZW4gdHdvIHBvaW50cywgYnV0IGlzIHNrZXdlZCB3aGVuIHRoZSBwb2ludHMgYXJlIG1lYXN1cmVkIGluIGRpZmZlcmVudCB1bml0cy4gCgoqIFRoZSBNYWhhbGFub2JpcyBkaXN0YW5jZSBpcyBkZWZpbmVkIGFzLCAkJERfTShcbWF0aGJme3h9KT1cc3FydCgoXG1hdGhiZnt4fS1cbWF0aGJme3V9KV5UXFNpZ21hXnstMX0oXG1hdGhiZnt4fS1cbWF0aGJme3V9KSkuJCQKCiogV2hlcmUgdGhlICRcbWF0aGJme3h9JCBhcmUgdGhlIG9ic2VydmF0aW9ucyBhbmQgdGhlICRcbWF0aGJme3V9JCBhcmUgdGhlIG1lYW5zLgoKKiBUaGlzIG1ldGhvZCB3aWxsIHRoZXJlZm9yZSB0cmFuc2Zvcm0geiBzY29yZXMgaW50byBhIHplcm8gbWVhbiB2ZWN0b3IgYW5kIHRoZW4gcXVhbnRpZnkgaG93IHJlcHJlc2VudGF0aXZlIG91ciBzaW11bGF0aW9ucyBhcmUgb2YgdGhlICd0cnVlIHonL3RoZSBtZWFuKD8pLiBXZSBjYW4gdGhlbiBmaWx0ZXIgb3V0IHRob3NlIHdoaWNoIGFyZSAndG9vIGZhcicgZnJvbSB0aGUgdHJ1ZSB6LiAKCiogTWFoYWxhbm9iaXMgZGlzdGFuY2Ugc2VlbXMgbW9yZSBhcHByb3ByaWF0ZSBhcyBpdCB0YWtlcyBpbnRvIGFjY291bnQgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHZhcmlhYmxlcywgYWx0aG91Z2ggaXQgZG9lcyByZXF1aXJlIGludmVydGluZyB0aGUgY292YXJpYW5jZSBtYXRyaXggKExEKSB3aGljaCBpcyBjb21wdXRhdGlvbmFsbHkgZGlmZmljdWx0LgoKLS0tCgojIyMgUXVlc3Rpb25zIGFuZCBJZGVhcwoKKiBDb3JyZWN0IHk9eCBsaW5lIGFmdGVyIHRyYW5zZm9ybWluZyB4IGF4aXMgaW4gZmlyc3Qgc2ltdWxhdGlvbnM/IEFyZSB0aGVzZSBjb3JyZWN0PwoKKiBDYW4gd2UgZmlsdGVyIHRoZSB6IHZhbHVlcyBiYXNlZCBvbiB0aGUgc2ltaWxhcml0eSBvZiB0aGUgZW50cm9weSBvZiB0aGUgdHJ1ZSBzeXN0ZW0gYW5kIHRoZSBlbnRyb3B5IG9mIHRoZSBwb3N0ZXJpb3IgcHJvYmFiaWxpdHkgc3lzdGVtIHRoZXkgcmVmbGVjdC4KCiogRm9yIHRoZSAnd2Uga25vdyB0aGUgQ1YgbWV0aG9kJywgc2hvdWxkIEkgYmUgdXNpbmcgYSBMT08gR0FNIG1ldGhvZCBvciB0aGUgbWV0aG9kIHVzZWQgZm9yIHdoZW4gd2UgZG9uJ3Qga25vdyB0aGUgQ1Ygb2YgcHJlZGljdGluZyBmcm9tIHRoZSBjbGFpbWVkIGNvdmVyYWdlIG9mIHRoZSBjcmVkaWJsZSBzZXQgd2UgYXJlIHRyeWluZyB0byBjb3JyZWN0PyBBdCB0aGUgbW9tZW50LCB0aGUgZW1waXJpY2FsIGNvdmVyYWdlIGlzIHRoZSBtZWFuIG9mIHRoZSBjb3ZlcmVkIGNvbHVtbiwgdGhlIGNvcnJlY3RlZCBjb3ZlcmFnZSBpcyB0aGUgc2luZ2xlIHZhbHVlIG9idGFpbmVkIHdoZW4gdXNpbmcgdGhlIExPTyBHQU0gbWV0aG9kIGFuZCB0aGUgY2xhaW1lZCBjb3ZlcmFnZSBpcyB0aGUgbWVhbiBvZiB0aGUgc2l6ZSBvZiB0aGUgY3JlZGlibGUgc2V0cy4gQWxzbyBub3Qgc3VyZSBteSBlcnJvciBiYXJzIGFyZSBjb3JyZWN0PwoKLS0tCgo=