Description
Uses a collapsed (marginalizes over a
, b
,
amp
numerically) gibbs sampler which samples from the
conditionals with slice sampling. Also re-parameterizes density with
(sqrt(gwidth^2+lwidth^2), gwidth-lwidth)
instead of
(gwidth, lwitdh)
if
min(gwidth/lwidth, lwidth/gwidth) > 0.05
(otherwise
transformation becomes unstable). Finds global maxima in posterior using
population based golden section search and uses it as the starting point
for the slice sampler. About x10 times faster than the previous
implementation. Using Zell Prior could be another x10.
Data
library('plotly')
Loading required package: ggplot2
Attaching package: 'plotly'
The following object is masked from 'package:ggplot2':
last_plot
The following object is masked from 'package:stats':
filter
The following object is masked from 'package:graphics':
layout
library(spectralmc)
#toluene data
cdata <- get_toluene_measured_data()
x <- cdata$x
y <- cdata$y
Algorithm
peak_spawner <- function() {
params <- list(
amp = rnorm(1, 1, 1), # doesnt matter
lwidth = rnorm(1, 0.1, 0.001), # matters!!!
gwidth = rnorm(1, 5, 0.001), # matters!!!
pos = runif(1, 1, 1), # doesnt matter
a = 0, # doesnt matter
b = 0 # doesnt matter
)
return(params)
}
fit_kp <- 30
max_a <- 1e-2
lower <- c(-Inf, -max_a, 0)
upper <- c(Inf, max_a, Inf)
noise_sigma <- 100 # estimated by eye; intentionally to big such that tiny peaks are overnoised
signal_model <- voigt.model
res <- chains.rjmcmc_like_collapsed_slicer_gibbs(
x,
y,
signal_model,
peak_spawner,
lower,
upper,
noise_sigma,
fit_kp = fit_kp,
add_peak_every = 10,
iter = 20000,
print_bar = TRUE,
half_steps = TRUE,
decorr_trafo = TRUE,
save_loc = save_loc,
checkpoint_every = 50,
)
Results
Fit
All
plt.fit.chain.interactive(x, y, res$samples, signal_model, step_width = 200)
Burn-in
plt.fit.chain.interactive(x, y, res$samples[seq(1, 500)], signal_model, step_width = 5)
Traceplots
plt.traceplot(res$samples, "pos")
plt.traceplot(res$samples, "amp")
plt.traceplot(res$samples, "lwidth")
plt.traceplot(res$samples, "gwidth")
plt.traceplot(res$samples, "a")
plt.traceplot(res$samples, "b")
Posterior plot
plt.posterior(res$post_vals, steps = NULL)
Fit vs True
plt.samples_vs_true(samples, 'gwidth')
plt.samples_vs_true(samples, 'lwidth')
Todo
- Critical Bug amp, a, b are not sampled instead they
are set to roughly their means, easy to fix.
- Not a bug: Uses a safeguard which prevents messing
up the fit if the slice sampler fails, this however destroys the gibbs
sampler property and causes rejection plateaus.
LS0tDQp0aXRsZTogIkNvbGxhcHNlZCBHaWJicyBTYW1wbGVyIHdpdGggR1NTIFNsaWNlIFNhbXBsaW5nIg0KYXV0aG9yOiBKYW4gTWVpw59uZXJeW1JXVEggQWFjaGVuLCBwaGlsaXBwLm1laXNzbmVyQHJ3dGgtYWFjaGVuLmRlXQ0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogNQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCi0tLQ0KDQo8c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+DQogIGZ1bmN0aW9uIGp1bXBfaGVhZGVyKGtleSl7DQogICAgJCgnOmhlYWRlcjpjb250YWlucygnK2tleSsnKScpWzBdLnNjcm9sbEludG9WaWV3KCk7DQogIH0NCg0KICBmdW5jdGlvbiBqdW1wX21hcmtlZChrZXkpew0KICAgICQoJyMnICsga2V5KVswXS5zY3JvbGxJbnRvVmlldygpOw0KICB9DQoNCiAgZnVuY3Rpb24gcGxvdFpvb20oZWwpew0KICAgICAgaWYoZG9jdW1lbnQuZnVsbHNjcmVlbikgew0KICAgICAgICBkb2N1bWVudC5leGl0RnVsbHNjcmVlbigpDQogICAgICB9IGVsc2Ugew0KICAgICAgICAkKGVsKS5jbG9zZXN0KCcuanMtcGxvdGx5LXBsb3QnKVswXS5yZXF1ZXN0RnVsbHNjcmVlbigpOw0KICAgICAgfQ0KICB9DQoNCiAgJCggZG9jdW1lbnQgKS5yZWFkeShmdW5jdGlvbigpIHsNCiAgICAkKCIubW9kZWJhci1idG4ucGxvdGx5anNpY29uLm1vZGViYXItYnRuLS1sb2dvIikucmVwbGFjZVdpdGgoDQogICAgYA0KICAgIDxhIHJlbD0idG9vbHRpcCIgb25jbGljaz1wbG90Wm9vbSh0aGlzKSBjbGFzcz0ibW9kZWJhci1idG4gZnVsbHNjcmVlbi1idG4iIGRhdGEtdGl0bGU9IkZ1bGwgU2NyZWVuIiBkYXRhLWF0dHI9Inpvb20iIGRhdGEtdmFsPSJhdXRvIiBkYXRhLXRvZ2dsZT0iZmFsc2UiIGRhdGEtZ3Jhdml0eT0ibiIgPg0KICAgICAgPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0NDggNTEyIiBjbGFzcz0iaWNvbiIgaGVpZ2h0PSIxZW0iIHdpZHRoPSIxZW0iPg0KICAgICAgICA8IS0tISBGb250IEF3ZXNvbWUgUHJvIDYuMS4xIGJ5IEBmb250YXdlc29tZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tIExpY2Vuc2UgLSBodHRwczovL2ZvbnRhd2Vzb21lLmNvbS9saWNlbnNlIChDb21tZXJjaWFsIExpY2Vuc2UpIENvcHlyaWdodCAyMDIyIEZvbnRpY29ucywgSW5jLiAtLT4NCiAgICAgICAgPHBhdGggZD0iTTEyOCAzMkgzMkMxNC4zMSAzMiAwIDQ2LjMxIDAgNjR2OTZjMCAxNy42OSAxNC4zMSAzMiAzMiAzMnMzMi0xNC4zMSAzMi0zMlY5Nmg2NGMxNy42OSAwIDMyLTE0LjMxIDMyLTMyUzE0NS43IDMyIDEyOCAzMnpNNDE2IDMyaC05NmMtMTcuNjkgMC0zMiAxNC4zMS0zMiAzMnMxNC4zMSAzMiAzMiAzMmg2NHY2NGMwIDE3LjY5IDE0LjMxIDMyIDMyIDMyczMyLTE0LjMxIDMyLTMyVjY0QzQ0OCA0Ni4zMSA0MzMuNyAzMiA0MTYgMzJ6TTEyOCA0MTZINjR2LTY0YzAtMTcuNjktMTQuMzEtMzItMzItMzJzLTMyIDE0LjMxLTMyIDMydjk2YzAgMTcuNjkgMTQuMzEgMzIgMzIgMzJoOTZjMTcuNjkgMCAzMi0xNC4zMSAzMi0zMlMxNDUuNyA0MTYgMTI4IDQxNnpNNDE2IDMyMGMtMTcuNjkgMC0zMiAxNC4zMS0zMiAzMnY2NGgtNjRjLTE3LjY5IDAtMzIgMTQuMzEtMzIgMzJzMTQuMzEgMzIgMzIgMzJoOTZjMTcuNjkgMCAzMi0xNC4zMSAzMi0zMnYtOTZDNDQ4IDMzNC4zIDQzMy43IDMyMCA0MTYgMzIweiIvPg0KICAgICAgPC9zdmc+DQogICAgPC9hPg0KICAgIGApOw0KICB9KTsNCjwvc2NyaXB0Pg0KDQoNCiMgRGVzY3JpcHRpb24NClVzZXMgYSBjb2xsYXBzZWQgKG1hcmdpbmFsaXplcyBvdmVyIGBhYCwgYGJgLCBgYW1wYCBudW1lcmljYWxseSkNCmdpYmJzIHNhbXBsZXIgd2hpY2ggc2FtcGxlcyBmcm9tIHRoZSBjb25kaXRpb25hbHMgd2l0aCBzbGljZSBzYW1wbGluZy4gQWxzbyByZS1wYXJhbWV0ZXJpemVzIGRlbnNpdHkgd2l0aCBgKHNxcnQoZ3dpZHRoXjIrbHdpZHRoXjIpLCBnd2lkdGgtbHdpZHRoKWAgaW5zdGVhZCBvZiBgKGd3aWR0aCwgbHdpdGRoKWAgaWYgYG1pbihnd2lkdGgvbHdpZHRoLCBsd2lkdGgvZ3dpZHRoKSA+IDAuMDVgIChvdGhlcndpc2UgdHJhbnNmb3JtYXRpb24gYmVjb21lcyB1bnN0YWJsZSkuIEZpbmRzIGdsb2JhbCBtYXhpbWEgaW4gcG9zdGVyaW9yIHVzaW5nIHBvcHVsYXRpb24gYmFzZWQgZ29sZGVuIHNlY3Rpb24gc2VhcmNoIGFuZCB1c2VzIGl0IGFzIHRoZSBzdGFydGluZyBwb2ludCBmb3IgdGhlIHNsaWNlIHNhbXBsZXIuIEFib3V0IHgxMCB0aW1lcyBmYXN0ZXIgdGhhbiB0aGUgcHJldmlvdXMgaW1wbGVtZW50YXRpb24uIFVzaW5nIFplbGwgUHJpb3IgY291bGQgYmUgYW5vdGhlciB4MTAuDQoNCiMgRGF0YQ0KYGBge3IgZWNobyA9IEZBTFNFfQ0KI3NldHdkKCdDOi9Vc2Vycy9KYW4vRGVza3RvcC9JU1dfU3BlY3RyYUJheWVzL0lTV19TcGVjdHJhQmF5ZXMvYmF5ZXNfbWNtYycpDQoNCmdldF90b2x1ZW5lX21lYXN1cmVkX2RhdGEgPC0gZnVuY3Rpb24oKXsNCiAgcGF0aCA8LSAiQzovVXNlcnMvSmFuL0Rlc2t0b3AvSVNXX1NwZWN0cmFCYXllcy9JU1dfU3BlY3RyYUJheWVzL2JheWVzX21jbWMvbm90ZWJvb2tzL2dvbGRlbl9naWJic190b2x1bmUvdG9sdWVuZV9tZWFzdXJlZC5jc3YiDQogIHRvbHVlbmVfbWVhc3VyZWQgPC0gcmVhZC5jc3YocGF0aCwgaGVhZGVyPUZBTFNFLCBzZXA9IjsiKQ0KICB4IDwtIGFzLnZlY3Rvcih0b2x1ZW5lX21lYXN1cmVkWywxXSkNCiAgeXRydWUgPC0gYXMudmVjdG9yKHRvbHVlbmVfbWVhc3VyZWRbLDJdKQ0KICByZXR1cm4obGlzdCh4PXgseT15dHJ1ZSkpDQp9DQpgYGANCmBgYHtyfQ0KbGlicmFyeSgncGxvdGx5JykNCmxpYnJhcnkoc3BlY3RyYWxtYykNCg0KI3RvbHVlbmUgZGF0YQ0KY2RhdGEgPC0gZ2V0X3RvbHVlbmVfbWVhc3VyZWRfZGF0YSgpDQp4IDwtIGNkYXRhJHgNCnkgPC0gY2RhdGEkeQ0KYGBgDQojIEFsZ29yaXRobQ0KYGBge3IgZXZhbCA9IEZBTFNFfQ0KcGVha19zcGF3bmVyIDwtIGZ1bmN0aW9uKCkgew0KICBwYXJhbXMgPC0gbGlzdCgNCiAgICAgICAgICBhbXAgPSBybm9ybSgxLCAxLCAxKSwgIyBkb2VzbnQgbWF0dGVyDQogICAgICAgICAgbHdpZHRoID0gcm5vcm0oMSwgMC4xLCAwLjAwMSksICMgbWF0dGVycyEhIQ0KICAgICAgICAgIGd3aWR0aCA9IHJub3JtKDEsIDUsIDAuMDAxKSwgIyBtYXR0ZXJzISEhDQogICAgICAgICAgcG9zID0gcnVuaWYoMSwgMSwgMSksICMgZG9lc250IG1hdHRlcg0KICAgICAgICAgIGEgPSAwLCAjIGRvZXNudCBtYXR0ZXINCiAgICAgICAgICBiID0gMCAjIGRvZXNudCBtYXR0ZXINCiAgKQ0KICByZXR1cm4ocGFyYW1zKQ0KfQ0KDQpmaXRfa3AgPC0gMzANCm1heF9hIDwtIDFlLTINCmxvd2VyIDwtIGMoLUluZiwgLW1heF9hLCAwKQ0KdXBwZXIgPC0gYyhJbmYsIG1heF9hLCBJbmYpDQpub2lzZV9zaWdtYSA8LSAxMDAgIyBlc3RpbWF0ZWQgYnkgZXllOyBpbnRlbnRpb25hbGx5IHRvIGJpZyBzdWNoIHRoYXQgdGlueSBwZWFrcyBhcmUgb3Zlcm5vaXNlZA0Kc2lnbmFsX21vZGVsIDwtIHZvaWd0Lm1vZGVsDQoNCnJlcyA8LSBjaGFpbnMucmptY21jX2xpa2VfY29sbGFwc2VkX3NsaWNlcl9naWJicygNCiAgICAgICAgeCwNCiAgICAgICAgeSwNCiAgICAgICAgc2lnbmFsX21vZGVsLA0KICAgICAgICBwZWFrX3NwYXduZXIsDQogICAgICAgIGxvd2VyLA0KICAgICAgICB1cHBlciwNCiAgICAgICAgbm9pc2Vfc2lnbWEsDQogICAgICAgIGZpdF9rcCA9IGZpdF9rcCwNCiAgICAgICAgYWRkX3BlYWtfZXZlcnkgPSAxMCwNCiAgICAgICAgaXRlciA9IDIwMDAwLA0KICAgICAgICBwcmludF9iYXIgPSBUUlVFLA0KICAgICAgICBoYWxmX3N0ZXBzID0gVFJVRSwNCiAgICAgICAgZGVjb3JyX3RyYWZvID0gVFJVRSwNCiAgICAgICAgc2F2ZV9sb2MgPSBzYXZlX2xvYywNCiAgICAgICAgY2hlY2twb2ludF9ldmVyeSA9IDUwLA0KKQ0KYGBgDQpgYGB7ciAgZWNobz1GQUxTRX0NCnNldHdkKCdDOi9Vc2Vycy9KYW4vRGVza3RvcC9JU1dfU3BlY3RyYUJheWVzL0lTV19TcGVjdHJhQmF5ZXMvYmF5ZXNfbWNtYycpDQpyZXMgPC0gcmVhZFJEUygibm90ZWJvb2tzL2dvbGRlbl9naWJic190b2x1bmUvcmVzLlJEYXRhIikNCmZpdF9rcCA8LSAzMA0KbWF4X2EgPC0gMWUtMg0KbG93ZXIgPC0gYygtSW5mLCAtbWF4X2EsIDApDQp1cHBlciA8LSBjKEluZiwgbWF4X2EsIEluZikNCm5vaXNlX3NpZ21hIDwtIDEwMCAjIGVzdGltYXRlZCBieSBleWU7IGludGVudGlvbmFsbHkgdG8gYmlnIHN1Y2ggdGhhdCB0aW55IHBlYWtzIGFyZSBvdmVybm9pc2VkDQpzaWduYWxfbW9kZWwgPC0gdm9pZ3QubW9kZWwNCmBgYA0KIyBSZXN1bHRzDQoNCiMjIEZpdA0KDQojIyMgQWxsDQpgYGB7cn0NCnBsdC5maXQuY2hhaW4uaW50ZXJhY3RpdmUoeCwgeSwgcmVzJHNhbXBsZXMsIHNpZ25hbF9tb2RlbCwgc3RlcF93aWR0aCA9IDIwMCkNCmBgYA0KDQojIyMgQnVybi1pbg0KYGBge3J9DQpwbHQuZml0LmNoYWluLmludGVyYWN0aXZlKHgsIHksIHJlcyRzYW1wbGVzW3NlcSgxLCA1MDApXSwgc2lnbmFsX21vZGVsLCBzdGVwX3dpZHRoID0gNSkNCmBgYA0KIyMjIFRyYWNlcGxvdHMNCmBgYHtyfQ0KcGx0LnRyYWNlcGxvdChyZXMkc2FtcGxlcywgInBvcyIpDQpwbHQudHJhY2VwbG90KHJlcyRzYW1wbGVzLCAiYW1wIikNCnBsdC50cmFjZXBsb3QocmVzJHNhbXBsZXMsICJsd2lkdGgiKQ0KcGx0LnRyYWNlcGxvdChyZXMkc2FtcGxlcywgImd3aWR0aCIpDQpwbHQudHJhY2VwbG90KHJlcyRzYW1wbGVzLCAiYSIpDQpwbHQudHJhY2VwbG90KHJlcyRzYW1wbGVzLCAiYiIpDQpgYGANCiMjIyBQb3N0ZXJpb3IgcGxvdA0KYGBge3J9DQpwbHQucG9zdGVyaW9yKHJlcyRwb3N0X3ZhbHMsIHN0ZXBzID0gTlVMTCkNCmBgYA0KDQpgYGB7ciAgZWNobz1GQUxTRX0NCg0KcGx0LnNhbXBsZXNfdnNfdHJ1ZSA8LSBmdW5jdGlvbiAoc2FtcGxlcywgb3RoZXJuYW1lID0gJ2d3aWR0aCcpIHsNCiAgZmxhdHNnX2RhdGEgPC0gc3BlY3RyYWxtYzo6dXRpbHMuZmxhdHRlbl9zYW1wbGVzKHNhbXBsZXMpDQogIG4gPC0gbGVuZ3RoKHNhbXBsZXNbWzFdXSRwb3MpDQoNCiAgYWxsX3BvcyA8LSBjKCkNCiAgZm9yIChpIGluIHNlcShuKSl7DQogICAgYWxsX3BvcyA8LSBjKGFsbF9wb3MsIGZsYXRzZ19kYXRhJGZsYXRfc2FtcGxlc1twYXN0ZTAoJ3Bvc1snLGksJ10nKV0pDQogIH0NCiAgYWxsX3BvcyA8LSBSZWR1Y2UoYyxhbGxfcG9zKQ0KDQogIGFsbF9vdGhlciA8LSBjKCkNCiAgZm9yIChpIGluIHNlcShuKSl7DQogICAgYWxsX290aGVyIDwtIGMoYWxsX290aGVyLCBmbGF0c2dfZGF0YSRmbGF0X3NhbXBsZXNbcGFzdGUwKG90aGVybmFtZSwnWycsaSwnXScpXSkNCiAgfQ0KICBhbGxfb3RoZXIgPC0gUmVkdWNlKGMsYWxsX290aGVyKQ0KDQogIHBlYWtzX3RydWUgPC0gcGVha3NfdHJ1ZVtjKDEsMyw0KSwgc2VxX2xlbihuY29sKHBlYWtzX3RydWUpKV0NCiAgdHJ1ZV9wb3MgPC0gdW5saXN0KHBlYWtzX3RydWVbMSxzZXFfbGVuKG5jb2wocGVha3NfdHJ1ZSkpXSkNCiAgaWYgKG90aGVybmFtZSA9PSAnZ3dpZHRoJyl7DQogICAgdHJ1ZV9vdGhlciA8LSB1bmxpc3QocGVha3NfdHJ1ZVsyLHNlcV9sZW4obmNvbChwZWFrc190cnVlKSldKQ0KICB9IGVsc2Ugew0KICAgIHRydWVfb3RoZXIgPC0gdW5saXN0KHBlYWtzX3RydWVbMyxzZXFfbGVuKG5jb2wocGVha3NfdHJ1ZSkpXSkNCiAgfQ0KDQogIGZpZyA8LSBwbG90X2x5KHggPSBhbGxfcG9zLCB5ID0gYWxsX290aGVyLCB0eXBlID0gJ3NjYXR0ZXInLCBuYW1lID0gJ1NhbXBsZXMnLA0KICAgICAgICAgICAgICAgICBtb2RlID0gJ21hcmtlcnMnLCBtYXJrZXIgPSBsaXN0KHNpemUgPSA1LCBvcGFjaXR5PTAuNSkpDQogIGZpZyA8LSBmaWcgJT4lIHBsb3RseTo6YWRkX21hcmtlcnMoeCA9IHRydWVfcG9zLCB5ID0gdHJ1ZV9vdGhlciwgdHlwZSA9ICdzY2F0dGVyJywgbmFtZSA9ICdUcnVlIFBhcmFtcycsIG1vZGUgPSAnbWFya2VycycsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAncmVkJywgc3ltYm9sID0gJ3gnLCBvcGFjaXR5PTEpKQ0KICBmaWcgPC0gZmlnICU+JSBwbG90bHk6OmxheW91dCh0aXRsZSA9ICJQZWFrIFBhcmFtZXRlcnM6IFNhbXBsZXMgdnMuIFRydWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiUG9zaXRpb24iLCB6ZXJvbGluZSA9IEZBTFNFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gb3RoZXJuYW1lLCBleHBvbmVudGZvcm1hdCA9ICdlJykpDQogIGZpZw0KfQ0KDQpsaWJyYXJ5KCdwbG90bHknKQ0KDQpzZXR3ZCgnQzovVXNlcnMvSmFuL0Rlc2t0b3AvSVNXX1NwZWN0cmFCYXllcy9JU1dfU3BlY3RyYUJheWVzL2JheWVzX21jbWMnKQ0KcmVzIDwtIHJlYWRSRFMoIm5vdGVib29rcy9nb2xkZW5fZ2liYnNfdG9sdW5lL3Jlcy5SRGF0YSIpDQpwYXRoIDwtICJDOi9Vc2Vycy9KYW4vRGVza3RvcC9JU1dfU3BlY3RyYUJheWVzL0lTV19TcGVjdHJhQmF5ZXMvYmF5ZXNfbWNtYy9ub3RlYm9va3MvZ29sZGVuX2dpYmJzX3RvbHVuZS90b2x1ZW5lX3BlYWtzLmNzdiINCg0KcGVha3NfdHJ1ZSA8LSByZWFkLmNzdihwYXRoLCBoZWFkZXI9RkFMU0UsIHNlcD0iLCIpDQoNCnNhbXBsZXMgPC0gcmVzJHNhbXBsZXNbMTUwMDpsZW5ndGgocmVzJHNhbXBsZXMpXQ0Kc2FtcGxlcyA8LSBzYW1wbGVzW3NlcSgxLCBsZW5ndGgoc2FtcGxlcyksIGxlbmd0aC5vdXQgPSA1MCldDQpgYGANCiMjIyBGaXQgdnMgVHJ1ZQ0KYGBge3J9DQpwbHQuc2FtcGxlc192c190cnVlKHNhbXBsZXMsICdnd2lkdGgnKQ0KcGx0LnNhbXBsZXNfdnNfdHJ1ZShzYW1wbGVzLCAnbHdpZHRoJykNCmBgYA0KDQojIFRvZG8NCi0gKipDcml0aWNhbCBCdWcqKiBhbXAsIGEsIGIgYXJlIG5vdCBzYW1wbGVkIGluc3RlYWQgdGhleSBhcmUgc2V0IHRvIHJvdWdobHkgdGhlaXIgbWVhbnMgKG5vdCByZWFsbHkgZWl0aGVyKTsgRWFzeSB0byBmaXguDQotICoqTm90IGEgYnVnKio6IFVzZXMgYSBzYWZlZ3VhcmQgd2hpY2ggcHJldmVudHMgbWVzc2luZyB1cCB0aGUgZml0IGlmIHRoZSBzbGljZSBzYW1wbGVyIGZhaWxzLCB0aGlzIGhvd2V2ZXIgZGVzdHJveXMgdGhlIGdpYmJzIHNhbXBsZXIgcHJvcGVydHkgYW5kIGNhdXNlcyByZWplY3Rpb24gcGxhdGVhdXMuDQotICoqRG9uZSoqOiBudSwgYmUgdHJhbnNmb3JtYXRpb24gYmVjb21lcyBiYWQgKHdoeT8pIGlmIGVpdGhlciBsd2lkdGggb3IgZ3dpZHRoIGlzIHJlYWxseSBzbWFsbCBjb21wYXJlZCB0byB0aGUgb3RoZXIsIHNob3VsZCBzd2l0Y2ggdG8gbnUsYmUgb25seSBpZiBgbWluKGx3aWR0aC9nd2lkdGgsIGd3aWR0aC9sd2lkdGgpID4gMC4wNWANCg==