RJMCMC-burnin Gibbs Sampler
(fits exactly) >>
Gibbs Sampler
As Pdf
Data
library(spectralmc)
true_kp <- 9
fit_kp <- 9
noise_sigma <- 0.001
signal_model <- voigt.model
data <- data.synthetic.stormyclouds(seed = 53252, kp = true_kp, noise = 0.001)
x <- data$x
y <- data$y
Gibbs Sampler
Uses a collapsed (marginalizes over a
, b
,
amp
numerically) gibbs sampler which approximates 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). Uses a Likelihood-ratio test to stop
slice sampling early. Slice sampling rerun a few times (3-5) to generate
draws from which one is sampled according to their posterior density
(prevents slice sampling failure).
- Takes 1-4s per peak and iteration
- 22h runtime for this notebook
- Thus only usable with a remote cluster (I wont use anymore of my
google.colab quota for this)
- short burn-in
- start_point is essentially irrelevant (modulo the label switching
problem, gelman-rubin will be terrible due to that)
- small auto-correlation (looks like it in traces at least)
- fits ok
- proposal free
- non-informative priors
- prior_a = Unif(1e-2, 1e2)
- prior_b = Unif(-Inf, Inf)
- prior_amp = Unif(0, Inf)
- prior_pos = Unif(100, 900)
- prior_lwidth = Unif(0, Inf)
- prior_gwidth = Unif(0, Inf)
- pos, lwidth, gwidth prior can be chosen arbitrarily; not done here
due to time constraints
max_a <- 1e-2
lower <- c(-Inf, -max_a, 0) #lower_b, lower_a, lower_amp; encodes lower bounds of prior.Unif
upper <- c(Inf, max_a, Inf) #upper_b, upper_a, upper_amp; encodes lower bounds of prior.Unif
start_params <- prop.voigt.rnd_start(seed = 33, kp = fit_kp)
res <- chains.collapsed_slicer_gibbs(
x, y, signal_model,
start_params, lower, upper, noise_sigma,
iter = 1000, print_bar = TRUE, half_steps = TRUE, decorr_trafo = TRUE
)
Results
Fit
All
plt.fit.chain.interactive(x, y, res$samples, signal_model, step_width = 50)
Burn-in
plt.fit.chain.interactive(x, y, res$samples[seq(1, 40)], signal_model, step_width = 2)
Traceplots
plt.fit.chain.interactive(x, y, res$samples, signal_model, step_width = 10)
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")
RJMCMC-burnin Gibbs
Sampler
Gibbs Sampler starts by fitting one peak and adds a peak every
add_peak_every
iterations until fit_kp
is
reached at which point it just becomes a normal gibbs sampler. Helps
resolving the peak deconvolution problem seen above and is an strong
hint on the power of a full RJMCMC implementation.
- Better fit than EM
- Peak deconvolution (
pos[1]
and pos[7]
)
takes ages to resolve
peak_spawner <- function(){
params <- list(
amp = rnorm(1, 1, 0.001),
lwidth = rnorm(1, 0.1, 0.001),
gwidth = rnorm(1, 4, 0.001),
pos = runif(1, 100, 900),
a = 0,
b = 0
)
return(params)
}
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 = 5000,
print_bar = TRUE,
half_steps = TRUE,
decorr_trafo = TRUE,
)
Results
Fit
All
plt.fit.chain.interactive(x, y, res_rjmcmc$samples, signal_model, step_width = 40)
Burn-in
plt.fit.chain.interactive(x, y, res_rjmcmc$samples[seq(1, 100)], signal_model, step_width = 2)
Traceplots
plt.traceplot(res_rjmcmc$samples, "pos")
plt.traceplot(res_rjmcmc$samples, "amp")
plt.traceplot(res_rjmcmc$samples, "lwidth")
plt.traceplot(res_rjmcmc$samples, "gwidth")
plt.traceplot(res_rjmcmc$samples, "a")
plt.traceplot(res_rjmcmc$samples, "b")
Todo
Critical Bug amp, a, b are not sampled instead
they are set to roughly their means (not really either); 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.
Done: nu, be transformation becomes bad (why?)
if either lwidth or gwidth is really small compared to the other, should
switch to nu,be only if
min(lwidth/gwidth, gwidth/lwidth) > 0.05
Peak deconvolution is the central problem (i.e. fitting strongly
overlapping peaks). See the second fit where only 1 Peak is misplaced.
RJMCMC would most likely instantly solve this problem as it would
add an peak on the right flank shortly increasing \(kp\) to 10 and then removing the misplaced
peak putting \(kp\) to 9 again. This is
an massive advantage that seems to be impossible to model with fixed
\(kp\). If a given \(kp\) is needed the \(kp\) prior could be slowly changed to
degenerate to only the given value of \(kp\).
Done prop.voigt.rnd_start spawns to wide peaks
for gibbs (the tuning for the spawner is very impactful)
Do Speed ups Develop heuristic to evaluate
pmvnorm fast; better slice sampler; better early termination of slice
sampler. Run profiler to figure out if pmvnorm is actually the
bottleneck or X construction. If it is X could use caching and speed up
code by 90%
LS0tDQp0aXRsZTogIkNvbGxhcHNlZCBHaWJicyBTYW1wbGVyIHdpdGggU2xpY2UgU2FtcGxpbmciDQphdXRob3I6IEphbiBNZWnDn25lcl5bUldUSCBBYWNoZW4sIHBoaWxpcHAubWVpc3NuZXJAcnd0aC1hYWNoZW4uZGVdDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiA1DQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KLS0tDQoNCjxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0Ij4NCiAgZnVuY3Rpb24ganVtcF9oZWFkZXIoa2V5KXsNCiAgICAkKCc6aGVhZGVyOmNvbnRhaW5zKCcra2V5KycpJylbMF0uc2Nyb2xsSW50b1ZpZXcoKTsNCiAgfQ0KICANCiAgZnVuY3Rpb24ganVtcF9tYXJrZWQoa2V5KXsNCiAgICAkKCcjJyArIGtleSlbMF0uc2Nyb2xsSW50b1ZpZXcoKTsNCiAgfQ0KDQo8L3NjcmlwdD4NCioqUkpNQ01DLWJ1cm5pbiBHaWJicyBTYW1wbGVyIDxhIG9uY2xpY2s9J2p1bXBfbWFya2VkKCJleGFjdGdpYmJzIik7Jz4oZml0cyBleGFjdGx5KTwvYT4gPj4gR2liYnMgU2FtcGxlcioqDQoNCiMgRGF0YQ0KDQoNCmBgYHtyfQ0KbGlicmFyeShzcGVjdHJhbG1jKQ0KDQp0cnVlX2twIDwtIDkNCmZpdF9rcCA8LSA5DQpub2lzZV9zaWdtYSA8LSAwLjAwMQ0Kc2lnbmFsX21vZGVsIDwtIHZvaWd0Lm1vZGVsDQoNCmRhdGEgPC0gZGF0YS5zeW50aGV0aWMuc3Rvcm15Y2xvdWRzKHNlZWQgPSA1MzI1Miwga3AgPSB0cnVlX2twLCBub2lzZSA9IDAuMDAxKQ0KeCA8LSBkYXRhJHgNCnkgPC0gZGF0YSR5DQpgYGANCg0KIyBHaWJicyBTYW1wbGVyDQpVc2VzIGEgY29sbGFwc2VkIChtYXJnaW5hbGl6ZXMgb3ZlciBgYWAsIGBiYCwgYGFtcGAgbnVtZXJpY2FsbHkpDQpnaWJicyBzYW1wbGVyIHdoaWNoIGFwcHJveGltYXRlcyB0aGUgY29uZGl0aW9uYWxzIHdpdGggc2xpY2Ugc2FtcGxpbmcuIEFsc28gcmUtcGFyYW1ldGVyaXplcyBkZW5zaXR5IHdpdGggYChzcXJ0KGd3aWR0aF4yK2x3aWR0aF4yKSwgZ3dpZHRoLWx3aWR0aClgIGluc3RlYWQgb2YgYChnd2lkdGgsIGx3aXRkaClgIGlmIGBtaW4oZ3dpZHRoL2x3aWR0aCwgbHdpZHRoL2d3aWR0aCkgPiAwLjA1YCAob3RoZXJ3aXNlIHRyYW5zZm9ybWF0aW9uIGJlY29tZXMgdW5zdGFibGUpLiBVc2VzIGEgTGlrZWxpaG9vZC1yYXRpbyB0ZXN0IHRvIHN0b3Agc2xpY2Ugc2FtcGxpbmcgZWFybHkuIFNsaWNlIHNhbXBsaW5nIHJlcnVuIGEgZmV3IHRpbWVzICgzLTUpIHRvIGdlbmVyYXRlIGRyYXdzIGZyb20gd2hpY2ggb25lIGlzIHNhbXBsZWQgYWNjb3JkaW5nIHRvIHRoZWlyIHBvc3RlcmlvciBkZW5zaXR5IChwcmV2ZW50cyBzbGljZSBzYW1wbGluZyBmYWlsdXJlKS4NCg0KLSBUYWtlcyAxLTRzIHBlciBwZWFrIGFuZCBpdGVyYXRpb24NCiAgLSAqKjMwLTQwaCBydW50aW1lKiogZm9yIHRoaXMgbm90ZWJvb2sNCiAgLSBUaHVzIG9ubHkgdXNhYmxlIHdpdGggYSByZW1vdGUgY2x1c3RlciAoSSB3b250IHVzZSBhbnltb3JlIG9mIG15IGdvb2dsZS5jb2xhYiBxdW90YSBmb3IgdGhpcykNCi0gc2hvcnQgYnVybi1pbg0KLSBzdGFydF9wb2ludCBpcyBlc3NlbnRpYWxseSBpcnJlbGV2YW50IChtb2R1bG8gdGhlIGxhYmVsIHN3aXRjaGluZyBwcm9ibGVtLCBnZWxtYW4tcnViaW4gd2lsbCBiZSB0ZXJyaWJsZSBkdWUgdG8gdGhhdCkNCi0gc21hbGwgYXV0by1jb3JyZWxhdGlvbiAobG9va3MgbGlrZSBpdCBpbiB0cmFjZXMgYXQgbGVhc3QpDQotIGZpdHMgb2sNCi0gcHJvcG9zYWwgZnJlZQ0KLSBub24taW5mb3JtYXRpdmUgcHJpb3JzDQogIC0gcHJpb3JfYSA9IFVuaWYoMWUtMiwgMWUyKQ0KICAtIHByaW9yX2IgPSBVbmlmKC1JbmYsIEluZikNCiAgLSBwcmlvcl9hbXAgPSBVbmlmKDAsIEluZikNCiAgLSBwcmlvcl9wb3MgPSBVbmlmKDEwMCwgOTAwKQ0KICAtIHByaW9yX2x3aWR0aCA9IFVuaWYoMCwgSW5mKQ0KICAtIHByaW9yX2d3aWR0aCA9IFVuaWYoMCwgSW5mKQ0KLSBwb3MsIGx3aWR0aCwgZ3dpZHRoIHByaW9yIGNhbiBiZSBjaG9zZW4gYXJiaXRyYXJpbHk7IG5vdCBkb25lIGhlcmUgZHVlIHRvIHRpbWUgY29uc3RyYWludHMNCmBgYHtyIGV2YWwgPSBGQUxTRX0NCm1heF9hIDwtIDFlLTINCmxvd2VyIDwtIGMoLUluZiwgLW1heF9hLCAwKSAjbG93ZXJfYiwgbG93ZXJfYSwgbG93ZXJfYW1wOyBlbmNvZGVzIGxvd2VyIGJvdW5kcyBvZiBwcmlvci5VbmlmDQp1cHBlciA8LSBjKEluZiwgbWF4X2EsIEluZikgI3VwcGVyX2IsIHVwcGVyX2EsIHVwcGVyX2FtcDsgZW5jb2RlcyBsb3dlciBib3VuZHMgb2YgcHJpb3IuVW5pZg0KDQpzdGFydF9wYXJhbXMgPC0gcHJvcC52b2lndC5ybmRfc3RhcnQoc2VlZCA9IDMzLCBrcCA9IGZpdF9rcCkNCg0KcmVzIDwtIGNoYWlucy5jb2xsYXBzZWRfc2xpY2VyX2dpYmJzKA0KICAgICAgICB4LCB5LCBzaWduYWxfbW9kZWwsDQogICAgICAgIHN0YXJ0X3BhcmFtcywgbG93ZXIsIHVwcGVyLCBub2lzZV9zaWdtYSwNCiAgICAgICAgaXRlciA9IDEwMDAsIHByaW50X2JhciA9IFRSVUUsIGhhbGZfc3RlcHMgPSBUUlVFLCBkZWNvcnJfdHJhZm8gPSBUUlVFDQopDQpgYGANCmBgYHtyICBlY2hvPUZBTFNFfQ0Kc2V0d2QoJ0M6L1VzZXJzL0phbi9EZXNrdG9wL0lTV19TcGVjdHJhQmF5ZXMvSVNXX1NwZWN0cmFCYXllcy9iYXllc19tY21jJykNCnJlcyA8LSBsaXN0KCkNCnJlcyRzYW1wbGVzX3dpdGhfaGFsZiA8LSByZWFkUkRTKCJub3RlYm9va3MvY29sbGFwc2VkX3NsaWNlcl90cmFuc2Zvcm1lZF9naWJicy9zYW1wbGVzXzUwMF9ub1JKTUNNQy5SRGF0YSIpDQpyZW1vdmVfaGFsZl9zdGVwcyA8LSBmdW5jdGlvbihzYW1wbGVzLCBmaXRfa3ApIHsNCiAgc2FtcGxlc1tzZXEoZnJvbT0xLCB0bz1sZW5ndGgoc2FtcGxlcyksIGJ5PWZpdF9rcCArIDEpXQ0KfQ0KcmVzJHNhbXBsZXMgPC0gcmVtb3ZlX2hhbGZfc3RlcHMocmVzJHNhbXBsZXMsIGZpdF9rcCA9IGZpdF9rcCkNCg0KYGBgDQojIyBSZXN1bHRzDQoNCiMjIyBGaXQNCg0KIyMjIyBBbGwNCmBgYHtyfQ0KcGx0LmZpdC5jaGFpbi5pbnRlcmFjdGl2ZSh4LCB5LCByZXMkc2FtcGxlcywgc2lnbmFsX21vZGVsLCBzdGVwX3dpZHRoID0gNTApDQpgYGANCg0KIyMjIyBCdXJuLWluDQpgYGB7cn0NCnBsdC5maXQuY2hhaW4uaW50ZXJhY3RpdmUoeCwgeSwgcmVzJHNhbXBsZXNbc2VxKDEsIDQwKV0sIHNpZ25hbF9tb2RlbCwgc3RlcF93aWR0aCA9IDIpDQpgYGANCiMjIyBUcmFjZXBsb3RzDQpgYGB7cn0NCnBsdC5maXQuY2hhaW4uaW50ZXJhY3RpdmUoeCwgeSwgcmVzJHNhbXBsZXMsIHNpZ25hbF9tb2RlbCwgc3RlcF93aWR0aCA9IDEwKQ0KYGBgDQpgYGB7cn0NCnBsdC50cmFjZXBsb3QocmVzJHNhbXBsZXMsICJwb3MiKQ0KcGx0LnRyYWNlcGxvdChyZXMkc2FtcGxlcywgImFtcCIpDQpwbHQudHJhY2VwbG90KHJlcyRzYW1wbGVzLCAibHdpZHRoIikNCnBsdC50cmFjZXBsb3QocmVzJHNhbXBsZXMsICJnd2lkdGgiKQ0KcGx0LnRyYWNlcGxvdChyZXMkc2FtcGxlcywgImEiKQ0KcGx0LnRyYWNlcGxvdChyZXMkc2FtcGxlcywgImIiKQ0KYGBgDQojIFJKTUNNQy1idXJuaW4gR2liYnMgU2FtcGxlcg0KR2liYnMgU2FtcGxlciBzdGFydHMgYnkgZml0dGluZyBvbmUgcGVhayBhbmQgYWRkcyBhIHBlYWsgZXZlcnkgYGFkZF9wZWFrX2V2ZXJ5YCBpdGVyYXRpb25zIHVudGlsIGBmaXRfa3BgIGlzIHJlYWNoZWQgYXQgd2hpY2ggcG9pbnQgaXQganVzdCBiZWNvbWVzIGEgbm9ybWFsIGdpYmJzIHNhbXBsZXIuIEhlbHBzIHJlc29sdmluZyB0aGUgcGVhayBkZWNvbnZvbHV0aW9uIHByb2JsZW0gc2VlbiBhYm92ZSBhbmQgaXMgYW4gc3Ryb25nIGhpbnQgb24gdGhlIHBvd2VyIG9mIGEgZnVsbCBSSk1DTUMgaW1wbGVtZW50YXRpb24uDQoNCi0gQmV0dGVyIGZpdCB0aGFuIEVNDQotIFBlYWsgZGVjb252b2x1dGlvbiAoYHBvc1sxXWAgYW5kIGBwb3NbN11gKSB0YWtlcyBhZ2VzIHRvIHJlc29sdmUNCmBgYHtyIGV2YWwgPSBGQUxTRX0NCnBlYWtfc3Bhd25lciA8LSBmdW5jdGlvbigpew0KICBwYXJhbXMgPC0gbGlzdCgNCiAgICAgICAgICBhbXAgPSBybm9ybSgxLCAxLCAwLjAwMSksDQogICAgICAgICAgbHdpZHRoID0gcm5vcm0oMSwgMC4xLCAwLjAwMSksDQogICAgICAgICAgZ3dpZHRoID0gcm5vcm0oMSwgNCwgMC4wMDEpLA0KICAgICAgICAgIHBvcyA9IHJ1bmlmKDEsIDEwMCwgOTAwKSwNCiAgICAgICAgICBhID0gMCwNCiAgICAgICAgICBiID0gMA0KICApDQogIHJldHVybihwYXJhbXMpDQp9DQoNCnJlcyA8LSBjaGFpbnMucmptY21jX2xpa2VfY29sbGFwc2VkX3NsaWNlcl9naWJicygNCiAgICAgICAgeCwNCiAgICAgICAgeSwNCiAgICAgICAgc2lnbmFsX21vZGVsLA0KICAgICAgICBwZWFrX3NwYXduZXIsDQogICAgICAgIGxvd2VyLA0KICAgICAgICB1cHBlciwNCiAgICAgICAgbm9pc2Vfc2lnbWEsDQogICAgICAgIGZpdF9rcCA9IGZpdF9rcCwNCiAgICAgICAgYWRkX3BlYWtfZXZlcnkgPSAxMCwNCiAgICAgICAgaXRlciA9IDUwMDAsDQogICAgICAgIHByaW50X2JhciA9IFRSVUUsDQogICAgICAgIGhhbGZfc3RlcHMgPSBUUlVFLA0KICAgICAgICBkZWNvcnJfdHJhZm8gPSBUUlVFLA0KKQ0KYGBgDQpgYGB7ciAgZWNobz1GQUxTRX0NCnJlbW92ZV9oYWxmX3N0ZXBzX3JqbWNtYyA8LSBmdW5jdGlvbih0cnVlX3NhbXBsZXMsIGZpdF9rcCwgYWRkX3BlYWtfZXZlcnksIGl0ZXIgPSA1MDAwLCBoYWxmX3N0ZXBzID0gVFJVRSkgew0KICByZXNfbGlzdCA8LSBsaXN0KCkNCiAgdG90X2luZGV4IDwtIDANCg0KICBjdXJyIDwtIGxpc3QocG9zID0gYygwKSkNCiAgc2FtcGxlcyA8LSBsaXN0KCkNCiAgIyMjIyMNCiAgdG90X2luZGV4IDwtIHRvdF9pbmRleCArIDENCiAgaWYgKGxlbmd0aCh0cnVlX3NhbXBsZXMpPHRvdF9pbmRleCkge3JldHVybihyZXNfbGlzdCl9DQogIHJlc19saXN0IDwtIGMocmVzX2xpc3QsIGxpc3QodHJ1ZV9zYW1wbGVzW1t0b3RfaW5kZXhdXSkpDQogICMjIyMjDQogIHNhbXBsZXMgPC0gYyhzYW1wbGVzLCBsaXN0KGN1cnIpKQ0KICBmb3IgKGkgaW4gc2VxKGl0ZXIpKSB7DQoNCiAgICBpZiAoaSAlJSBhZGRfcGVha19ldmVyeSA9PSAwICYmIGkgPiAwICYmIGxlbmd0aChjdXJyJHBvcykgPCBmaXRfa3Apew0KICAgICAgY3VyciRwb3MgPC0gYyhjdXJyJHBvcywgMCkNCiAgICB9DQoNCiAgICBrcCA8LSBsZW5ndGgoY3VyciRwb3MpDQogICAgZm9yIChrIGluIHNlcShrcCkpIHsNCiAgICAgIGlmIChoYWxmX3N0ZXBzKSB7DQogICAgICAgICMjIyMjDQogICAgICAgIHRvdF9pbmRleCA8LSB0b3RfaW5kZXggKyAxDQogICAgICAgIGlmIChsZW5ndGgodHJ1ZV9zYW1wbGVzKTx0b3RfaW5kZXgpIHtyZXR1cm4ocmVzX2xpc3QpfQ0KICAgICAgICAjcmVzX2xpc3QgPC0gYyhyZXNfbGlzdCwgbGlzdCh0cnVlX3NhbXBsZXNbW3RvdF9pbmRleF1dKSkNCiAgICAgICAgIyMjIyMNCiAgICAgICAgc2FtcGxlcyA8LSBjKHNhbXBsZXMsIGxpc3QoY3VycikpDQogICAgICB9ICNvbmx5IGlmIGhhbGYgc3RlcHMNCiAgICB9DQogICAgIyMjIyMNCiAgICB0b3RfaW5kZXggPC0gdG90X2luZGV4ICsgMQ0KICAgIGlmIChsZW5ndGgodHJ1ZV9zYW1wbGVzKTx0b3RfaW5kZXgpIHtyZXR1cm4ocmVzX2xpc3QpfQ0KICAgIHJlc19saXN0IDwtIGMocmVzX2xpc3QsIGxpc3QodHJ1ZV9zYW1wbGVzW1t0b3RfaW5kZXhdXSkpDQogICAgIyMjIyMNCiAgICBzYW1wbGVzIDwtIGMoc2FtcGxlcywgbGlzdChjdXJyKSkNCiAgfQ0KICByZXR1cm4odHJ1ZV9zYW1wbGVzKQ0KfQ0KDQpyZW1vdmVfaGFsZl9zdGVwcyA8LSBmdW5jdGlvbihzYW1wbGVzLCBmaXRfa3ApIHsNCiAgc2FtcGxlc1tzZXEoZnJvbT0xLCB0bz1sZW5ndGgoc2FtcGxlcyksIGJ5PWZpdF9rcCArIDEpXQ0KfQ0KDQpwYWRfd2l0aF96ZXJvcyA8LSBmdW5jdGlvbihzYW1wbGVzLCBmaXRfa3Apew0KICBmb3IgKGkgaW4gc2VxX2Fsb25nKHNhbXBsZXMpKXsNCiAgICBzYW1wbGUgPC0gc2FtcGxlc1tbaV1dDQogICAgZm9yIChuYW1lIGluIG5hbWVzKHNhbXBsZSkpew0KICAgICAgaWYgKG5hbWUgIT0gJ2EnICYmIG5hbWUgIT0gJ2InICYmIG5hbWUgIT0gJ2FtcCcpew0KICAgICAgICBzYW1wbGVbW25hbWVdXSA8LSBjKHJlcCgxLCBmaXRfa3AtbGVuZ3RoKHNhbXBsZVtbbmFtZV1dKSksIHNhbXBsZVtbbmFtZV1dKQ0KICAgICAgfQ0KICAgICAgaWYgKG5hbWUgPT0gJ2FtcCcpew0KICAgICAgICBzYW1wbGVbW25hbWVdXSA8LSBjKHJlcCgwLCBmaXRfa3AtbGVuZ3RoKHNhbXBsZVtbbmFtZV1dKSksIHNhbXBsZVtbbmFtZV1dKQ0KICAgICAgfQ0KICAgIH0NCiAgICBzYW1wbGVzW1tpXV0gPC0gc2FtcGxlDQogIH0NCiAgc2FtcGxlcw0KfQ0Kc2V0d2QoJ0M6L1VzZXJzL0phbi9EZXNrdG9wL0lTV19TcGVjdHJhQmF5ZXMvSVNXX1NwZWN0cmFCYXllcy9iYXllc19tY21jJykNCnJlc19yam1jbWMgPC0gbGlzdCgpDQpyZXNfcmptY21jJHNhbXBsZXNfd2l0aF9oYWxmIDwtIHJlYWRSRFMoIm5vdGVib29rcy9jb2xsYXBzZWRfc2xpY2VyX3RyYW5zZm9ybWVkX2dpYmJzL3NhbXBsZXNfMV8ya18xMDQ0LlJEYXRhIikNCnJlc19yam1jbWMkc2VjIDwtIHJlYWRSRFMoIm5vdGVib29rcy9jb2xsYXBzZWRfc2xpY2VyX3RyYW5zZm9ybWVkX2dpYmJzL3NhbXBsZXMuUkRhdGEiKQ0KDQpyZXNfcmptY21jJHNhbXBsZXMxIDwtIHJlbW92ZV9oYWxmX3N0ZXBzX3JqbWNtYyhyZXNfcmptY21jJHNhbXBsZXNfd2l0aF9oYWxmLCBmaXRfa3AgPSBmaXRfa3AsIGFkZF9wZWFrX2V2ZXJ5ID0gMTAsIGl0ZXIgPSAxMDAwMCwgaGFsZl9zdGVwcyA9IFRSVUUpDQpyZXNfcmptY21jJHNhbXBsZXMyIDwtIHJlbW92ZV9oYWxmX3N0ZXBzKHJlc19yam1jbWMkc2VjLCBmaXRfa3AgPSBmaXRfa3ApDQoNCnJlc19yam1jbWMkc2FtcGxlczEgPC0gcGFkX3dpdGhfemVyb3MocmVzX3JqbWNtYyRzYW1wbGVzMSwgZml0X2twID0gZml0X2twKQ0KcmVzX3JqbWNtYyRzYW1wbGVzMiA8LSBwYWRfd2l0aF96ZXJvcyhyZXNfcmptY21jJHNhbXBsZXMyLCBmaXRfa3AgPSBmaXRfa3ApDQoNCnJlc19yam1jbWMkc2FtcGxlcyA8LSBjKHJlc19yam1jbWMkc2FtcGxlczEsIHJlc19yam1jbWMkc2FtcGxlczJbc2VxKDIsIGxlbmd0aChyZXNfcmptY21jJHNhbXBsZXMyKSldKQ0KDQojIDEtMmsgaGFzIDI0aCBleGVjdXRpb24gYnV0IGR1ZSB0byBpbmZlcl9jIHNsb3dlciB0YWtlIDE1aA0KYGBgDQojIyBSZXN1bHRzDQoNCiMjIyBGaXQNCiMjIyMgQWxsDQo8ZGl2IGlkPSJleGFjdGdpYmJzIj48L2Rpdj4NCmBgYHtyfQ0KcGx0LmZpdC5jaGFpbi5pbnRlcmFjdGl2ZSh4LCB5LCByZXNfcmptY21jJHNhbXBsZXMsIHNpZ25hbF9tb2RlbCwgc3RlcF93aWR0aCA9IDQwKQ0KYGBgDQojIyMjIEJ1cm4taW4NCmBgYHtyfQ0KcGx0LmZpdC5jaGFpbi5pbnRlcmFjdGl2ZSh4LCB5LCByZXNfcmptY21jJHNhbXBsZXNbc2VxKDEsIDEwMCldLCBzaWduYWxfbW9kZWwsIHN0ZXBfd2lkdGggPSAyKQ0KYGBgDQojIyMgVHJhY2VwbG90cw0KYGBge3J9DQpwbHQudHJhY2VwbG90KHJlc19yam1jbWMkc2FtcGxlcywgInBvcyIpDQpwbHQudHJhY2VwbG90KHJlc19yam1jbWMkc2FtcGxlcywgImFtcCIpDQpwbHQudHJhY2VwbG90KHJlc19yam1jbWMkc2FtcGxlcywgImx3aWR0aCIpDQpwbHQudHJhY2VwbG90KHJlc19yam1jbWMkc2FtcGxlcywgImd3aWR0aCIpDQpwbHQudHJhY2VwbG90KHJlc19yam1jbWMkc2FtcGxlcywgImEiKQ0KcGx0LnRyYWNlcGxvdChyZXNfcmptY21jJHNhbXBsZXMsICJiIikNCmBgYA0KDQojIFRvZG8NCi0gKipDcml0aWNhbCBCdWcqKiBhbXAsIGEsIGIgYXJlIG5vdCBzYW1wbGVkIGluc3RlYWQgdGhleSBhcmUgc2V0IHRvIHJvdWdobHkgdGhlaXIgbWVhbnMgKG5vdCByZWFsbHkgZWl0aGVyKTsgRWFzeSB0byBmaXguDQotICoqTm90IGEgYnVnKio6IFVzZXMgYSBzYWZlZ3VhcmQgd2hpY2ggcHJldmVudHMgbWVzc2luZyB1cCB0aGUgZml0IGlmIHRoZSBzbGljZSBzYW1wbGVyIGZhaWxzLCB0aGlzIGhvd2V2ZXIgZGVzdHJveXMgdGhlIGdpYmJzIHNhbXBsZXIgcHJvcGVydHkgYW5kIGNhdXNlcyByZWplY3Rpb24gcGxhdGVhdXMuDQotICoqRG9uZSoqOiBudSwgYmUgdHJhbnNmb3JtYXRpb24gYmVjb21lcyBiYWQgKHdoeT8pIGlmIGVpdGhlciBsd2lkdGggb3IgZ3dpZHRoIGlzIHJlYWxseSBzbWFsbCBjb21wYXJlZCB0byB0aGUgb3RoZXIsIHNob3VsZCBzd2l0Y2ggdG8gbnUsYmUgb25seSBpZiBgbWluKGx3aWR0aC9nd2lkdGgsIGd3aWR0aC9sd2lkdGgpID4gMC4wNWANCjwhLS0NCi0gVW5jbGVhbjogSW5zdGVhZCBvZiB0cnlpbmcgdG8gcmVndWxhcml6ZSB0aGUgLUluZiBpbiBsb2dwcm9icyBhd2F5IGp1c3QgcmVqZWN0IHRoZSBzbGljZSBzYW1wbGVyIGFuZCByZXJ1biB1bnRpbCBpdCBkb2VzIGZpbmQgYSBuZXcgcG9pbnQuDQotIEhvdyB0byBkZWFsIHdpdGggcGVhayBkZWdlbmVyYWN5PyBpLmUuIHNhbWUgcG9zIGd3aWR0aCBsd2lkdGggYnV0IGFtcHMgYXJlIHNwbGl0IGJldHdlZW4gdHdvIHBlYWtzIC0+IHJ1bnMgZGVlcGVyIHRoYW4gdGhpcyBjb25uZWN0ZWQgdG8gcGVhayBkZWNvbnZvbHV0aW9uIHByb2JsZW0gLT4gaW5jcmVhc2UgZml0X2twIHNsb3dseSBsaWtlIGluIEVNIChidXQgdGhlbiB0aGlzIGlzbnQgYSBnaWJicyBhbnltb3JlKQ0KLSBQZWFrIGRlY29udm9sdXRpb24gaXMgYWN0dWFsbHkgdGhlIGxhc3QgbWFzc2l2ZSBwcm9ibGVtLCB0aGF0IGlzIHdoZW4gcGVha3Mgc3Ryb25nbHkgaW50ZXJhY3Qgd2l0aCBlYWNoIG90aGVyIGFuZCB0aGUgcG9zdGVyaW9yIGJlY29tZXMgc3Ryb25nbHkgY29ycmVsYXRlZC4gVGhlIGdpYmJzIHNhbXBsZXIgYmVjb21lcyBhcyB1c3VhbCB2ZXJ5IHNsb3cuIE5vdCBwb3NzaWJsZSB0byBmaXggd2l0aCBoYXN0aW5ncyBhcyBwcm9wb3NhbCBpcyBpbXBvc3NpYmxlIHRvIGZpbmQuIEEgc3VicHJvYmxlbSBvZiB0aGF0IGlzIHRoYXQgc29tZXRpbWVzIGEgc2luZ2xlIHBlYWsgaXMgZml0IHdpdGggYXMgbWFueSBhcyAzIHBlYWtzLCBnaWJicyAoYW5kIGhhc3RpbmdzKSBjYW4ndCByZXNvbHZlIHRoaXMgaXNzdWUgZWFzaWx5LiBPbmUgcG9zc2libGUgd2F5IHRvIGZpeCB0aGlzIGlzIHRvIHNldCBhbXAgcHJpb3IgdGhhdCBwZW5hbGl6ZXMgbGFyZ2VyIGBhbXBzYDsgZ2F1c3NpYW4gdHJ1bmN0IHByaW9yIGNvdWxkIGJlIHVzZWQgYnV0IG5vdCB2ZXJ5IHNhdGlzZmFjdG9yeSBwcmlvciBvdGhlciBwcmlvcnMgY2FudCByZWFsbHkgYmUgdXNlZCBkdWUgdG8gY29sbGFwc2UNCi0gKipJZGVhOioqKCFhbXAgaXMgbm90IGhlaWdodCBvZiBwZWFrISBhbXAqVm9pZ3QoLi4uKSwgdm9pZ3QgaGFzIGFuIHdpZHRoIGRlcGVuZGVudCBoZWlnaHQgZmFjdG9yIGFzd2VsbCEpIFNldCBwcmlvciBvbiBhbXAgdG8gc29tZXRoaW5nIGxpa2UgJCRcbWF0aGNhbHtOfSh4IHwgLTUsIHNkPTEwKSAxX3t4IFxpbiBbMCwgXGluZnR5KX0gJCQgdG8gcGVuYWxpemUgbGFyZ2VyIGFtcHMgc3VjaCB0aGF0IHRoZXJlIGlzIGEgbG9jYWwgZ3JhZGllbnQgaW4gdGhlIHBvc3RlcmlvciB0aGF0IHJld2FyZHMgZml0dGluZ3MgcGVha3Mgd2l0aCBhcyBsaXR0bGUgcGVha3MgYXMgcG9zc2libGUuDQotLT4NCi0gUGVhayBkZWNvbnZvbHV0aW9uIGlzIHRoZSBjZW50cmFsIHByb2JsZW0gKGkuZS4gZml0dGluZyBzdHJvbmdseSBvdmVybGFwcGluZyBwZWFrcykuIFNlZSB0aGUgc2Vjb25kIGZpdCB3aGVyZSBvbmx5IDEgUGVhayBpcyBtaXNwbGFjZWQuIFJKTUNNQyB3b3VsZCBtb3N0IGxpa2VseSBpbnN0YW50bHkgc29sdmUgdGhpcyBwcm9ibGVtIGFzIGl0IHdvdWxkICphZGQqIGFuIHBlYWsgb24gdGhlIHJpZ2h0IGZsYW5rIHNob3J0bHkgaW5jcmVhc2luZyAka3AkIHRvIDEwIGFuZCB0aGVuIHJlbW92aW5nIHRoZSBtaXNwbGFjZWQgcGVhayBwdXR0aW5nICRrcCQgdG8gOSBhZ2Fpbi4gVGhpcyBpcyBhbiBtYXNzaXZlIGFkdmFudGFnZSB0aGF0IHNlZW1zIHRvIGJlIGltcG9zc2libGUgdG8gbW9kZWwgd2l0aCBmaXhlZCAka3AkLiBJZiBhIGdpdmVuICRrcCQgaXMgbmVlZGVkIHRoZSAka3AkIHByaW9yIGNvdWxkIGJlIHNsb3dseSBjaGFuZ2VkIHRvIGRlZ2VuZXJhdGUgdG8gb25seSB0aGUgZ2l2ZW4gdmFsdWUgb2YgJGtwJC4NCg0KLSAqKkRvbmUqKiBwcm9wLnZvaWd0LnJuZF9zdGFydCBzcGF3bnMgdG8gd2lkZSBwZWFrcyBmb3IgZ2liYnMgKHRoZSB0dW5pbmcgZm9yIHRoZSBzcGF3bmVyIGlzIHZlcnkgaW1wYWN0ZnVsKQ0KLSAqKkRvIFNwZWVkIHVwcyoqIERldmVsb3AgaGV1cmlzdGljIHRvIGV2YWx1YXRlIHBtdm5vcm0gZmFzdDsgYmV0dGVyIHNsaWNlIHNhbXBsZXI7IGJldHRlciBlYXJseSB0ZXJtaW5hdGlvbiBvZiBzbGljZSBzYW1wbGVyLiBSdW4gcHJvZmlsZXIgdG8gZmlndXJlIG91dCBpZiBwbXZub3JtIGlzIGFjdHVhbGx5IHRoZSBib3R0bGVuZWNrIG9yIFggY29uc3RydWN0aW9uLiBJZiBpdCBpcyBYIGNvdWxkIHVzZSBjYWNoaW5nIGFuZCBzcGVlZCB1cCBjb2RlIGJ5IDkwJQ0K