Моделирование траектории случайного процесса
Упражнение может иметь реальное применение в физике элементарных частиц.
# Random walk with absorption
simulate_walk <- function(lower = -10, upper = 10, n_max = 200, p = 1e-3) {
# на каждом шаге есть позиция, начинаем из центра интервала
current_position <- (lower + upper) / 2
for (i in 1:n_max) {
#сначала определяем вероятность поглощения частицы
is_absorbed <- rbinom(1, 1, p)
#если произошло - симуляция заканчивается
if (is_absorbed) return(list(status = "Absorbed",
position = current_position,
steps = i))
#если поглощение не произошло - совершаем 1 случайный шаг
current_position <- current_position + rnorm(1)
if (current_position < lower) return(list(status = "Left breach",
position = current_position,
steps = i))
if (current_position > upper) return(list(status = "Right breach",
position = current_position,
steps = i))
}
#возвращаем такое сообщение при достижении максимального количества шагов
return(list(status = "Max steps reached",
position = current_position,#позиция, на которой завершилась симуляция
steps = n_max)) #количество шагов, на которой завершилась симуляция
}
Есть одномерная область от -10 до 10, в которой может находится элементарная частица. Частица может прыгать либо вправо, либо влево и на каждом шаге есть вероятность того, что она поглотится (p = 1e-3). Общее количество переходов ограничиваем 200 шагами (n_max = 200).
Почему использовали цикл for, хотя для R - это один из медленных способов, к которому нужно относится с осторожностью. Дело в том, что на каждом из шагов симуляция может быть прервана и закончится - каждое определение перехода это какая-то сложная вычислительная заадача. Если генерировать такую ситуацию через векторизацию, то мы генерируем сразу 200 переходов (потенциальный максимум), тогда как цикл может прерваться уже на первой итерации в случае поглощения частицы. Т.е. в такой ситуации цикл for позволяет сэкономить те переходы, которые выпадают за границы симуляции
Теперь можно с помощью функции replicate повторить n-ое число таких симуляций
# Simulate results
result <- replicate(1000, simulate_walk(), simplify = FALSE)
result <- data.frame(
status = sapply(result, function(x) x$status),
position = sapply(result, function(x) x$position),
steps = sapply(result, function(x) x$steps)
)
Приводим результат в том виде, который нам удобен. В данной конкретной ситуации превращаем его в дата-фрейм
Можно посмотреть, что примерно получилось
str(result)
'data.frame': 1000 obs. of 3 variables:
$ status : chr "Left breach" "Absorbed" "Left breach" "Left breach" ...
$ position: num -10.17 -6.95 -10.65 -11.12 10.04 ...
$ steps : num 56 27 84 167 20 87 100 79 26 121 ...
Теперь, когда у нас есть какая-то разумная статистика, то можно ее определеить, например, с помощью функции tapply
tapply(result$position, result$status, length)
Absorbed Left breach Max steps reached Right breach
99 389 120 392
tapply(result$steps, result$status, mean)
Absorbed Left breach Max steps reached Right breach
77.54545 79.48329 200.00000 82.80612
Больший интерес представляют задачи с блужданием по плоскости, то есть в размерности 2.
Возьмите написанную мной функцию и измените её так, чтобы блуждание начиналось в центре координат (0, 0), а все переходы по координатам x и y были бы независимы и имели стандартное нормальное распределение. Если вас пугают эти слова, то это то же самое, что делал я, только отдельно по x и по y.
- Процесс обрывается в момент выхода за границу круга с центром в (0, 0) и радиусом 6
- Вероятность поглощения на каждом шаге равна 0.01
- Максимальное количество шагов — 100
- Расстояние, разумеется, евклидово: расстояние от точки (x, y) до (0, 0) есть
- Один шаг процесса подразумевает изменение обеих координат одновременно!
В ответе укажите вероятность вылета частицы в процентах, с точностью до целых процентов, в виде XX (например, 14, без указания значка процентов). Вероятность должна получиться больше 50%.
simulate_walk <- function(n_max = 100, p = 1e-2) {
x<-0
y<-0
current_position <- 0
for (i in 1:n_max) {
is_absorbed <- rbinom(1, 1, p)
if (is_absorbed) return(list(status = "Absorbed",
position = current_position,
steps = i))
x<-x+rnorm(1)
y<-y+rnorm(1)
current_position <- sqrt(x**2 + y**2)
if (current_position > 6) return(list(status = "breach",
position = current_position,
steps = i))
}
return(list(status = "Max steps reached",
position = current_position,
steps = n_max))
}
# Simulate results
result <- replicate(100000, simulate_walk(), simplify = FALSE)
result <- data.frame(
status = sapply(result, function(x) x$status),
position = sapply(result, function(x) x$position),
steps = sapply(result, function(x) x$steps)
)
# Inspect results
tapply(result$position, result$status, length)
Absorbed breach
18934 80997
Max steps reached
69
a
[1] 81.05293
Общий глоссарий для этого урока:
S3, S4, reference classes
Generic function
Copy-on-modify semantics
?replicate
?mapply
?outer
?Vectorize
?do.call
LS0tDQp0aXRsZTogItCk0YPQvdC60YbQuNC+0L3QsNC70YzQvdC+0LUg0L/RgNC+0LPRgNCw0LzQvNC40YDQvtCy0LDQvdC40LUg0LIgUiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMg0K3Qu9C10LzQtdC90YLRiyDRhNGD0L3QutGG0LjQvtC90LDQu9GM0L3QvtCz0L4g0L/RgNC+0LPRgNCw0LzQvNC40YDQvtCy0LDQvdC40Y8NClIg0YHQvtGH0LXRgtCw0LXRgiDQsiDRgdC10LHQtSDQvdC10YHQutC+0LvRjNC60L4g0L/QsNGA0LDQtNC40LPQvCDQv9GA0L7Qs9GA0LDQvNC80LjRgNC+0LLQsNC90LjRjy4g0JXRgdC70Lgg0L/QvtC/0YvRgtCw0YLRjNGB0Y8g0LLRi9C00LXQu9C40YLRjCDQutCw0LrRg9GOLdGC0L4g0LPQu9Cw0LLQvdGD0Y4sINGC0L4g0L/QvtC20LDQu9GD0LkgLSDRjdGC0L4g0Y3Qu9C10LzQtdC90YLRiyDRhNGD0L3QutGG0LjQvtC90LDQu9GM0L3QvtCz0L4g0L/RgNC+0LDQs9GA0LDQvNC80LjRgNC+0LLQsNC90LjRjy4g0K3RgtCwINGC0LXQvNCwINC+0YLQvdC+0YHQuNGC0YHRjyDQuiDQv9GA0L7QtNCy0LjQvdGD0YLQvtC80YMg0YPRgNC+0LLQvdGOLiDQrdGC0L4g0L3QvtGA0LzQsNC70YzQvdC+INGH0YPQstGB0YLQstC+0LLQsNGC0Ywg0YHQtdCx0Y8g0L3QsCDRjdGC0L7QvCDRg9GA0L7QstC90LUg0L3QtdC60L7QvNGE0L7RgNGC0L3QviDQuCDQvdC10YPQstC10YDQtdC90L3Qvg0KDQojIyDQntCx0YrQtdC60YLQvdC+LdC+0YDQuNC10L3RgtC40YDQvtCy0LDQvdC90YvQtSDRgdC40YHRgtC10LzRiw0K0JrQvtCz0LTQsCDQvNGLINCz0L7QstC+0YDQuNC8INC+0LEg0L7QsdGK0LXQutGC0LDRhSDRj9C30YvQutCwIFIg0YLQsNC60LjRhSDQutCw0Log0LLQtdC60YLQvtGALCDRhNGD0L3QutGG0LjRjyDQuCDRgi7QtC4sINGC0L4g0Y3RgtC+INC90LUg0YLQviDQttC1INGB0LDQvNC+0LUg0LrQvtCz0LTQsCDRgNC10YfRjCDQuNC00LXRgiDQvtCxINC+0LHRitC10LrRgtC90L4t0L7RgNC40LXQvdGC0LjRgNC+0LLQsNC90L3QvtC8INC/0YDQvtCz0YDQsNC80LzQuNGA0L7QstCw0L3QuNC4LiAgDQogIA0K0KfRgtC+INCy0YXQvtC00LjRgiDQsiDQv9C+0L3Rj9GC0LjQtSAqKtC+0LHRitC10LrRgtC40L3Qvi3QvtGA0LjQtdC90YLQuNGA0L7QstCw0L3QvdC+0LPQviDQv9GA0L7Qs9GA0LDQvNC80LjRgNC+0LLQsNC90LjRjyoqPzogIA0KMS4g0JrQu9Cw0YHRgdGLICANCg0KMi4g0J/QvtC70Y8g0LrQu9Cw0YHRgdC+0LIgIA0KDQozLiDQnNC10YLQvtC00YssINC+0L/RgNC10LTQtdC70LXQvdC90YvQtSDQtNC70Y8g0LrQu9Cw0YHRgdC+0LIgIA0KDQojINCa0LvQsNGB0YHRiw0K0JIgUiDQvNC+0LbQvdC+INGB0L7Qt9C00LDQstCw0YLRjCDQutC70LDRgdGB0YsuINCh0YLQsNC90LTQsNGA0YLQvdC+INC40YUg0YHRgNCw0LfRgyAzINCyIFI6ICANCiogKlMzKiAgDQotINC90LXRgiDRhNC+0YDQvNCw0LvRjNC90L7QuSDQtNC10LrQu9Cw0YDQsNGG0Lgg0LrQu9Cw0YHRgdCwICANCi0g0YTRg9C90LrRhtC40Y8g0LzQvtC20LXRgiDQuNC80LXRgtGMINGA0LDQt9C90L7QtSAgINC/0L7QstC10LTQtdC90LjQtSDQsiDQt9Cw0LLQuNGB0LjQvNC+0YHRgtC4INC+0YIg0LrQu9Cw0YHRgdCwICgqKm1ldGhvZCBkaXNwYXRjaCoqKSAgDQotINGC0LDQutC40LUg0YTRg9C90LrRhtC40Lgg0L3QsNC30YvQstCw0Y7RgtGB0Y8gKmdlbmVyaWMqICAgDQrQktGC0L7RgNGL0LUg0LTQstCwINC60LvQsNGB0YHQsCDQstGB0YLRgNC10YfQsNGO0YLRgdGPINC30L3QsNGH0LjRgtC10LvRjNC90L4g0YDQtdC20LUsINC/0YDQvtGH0LjRgtCw0YLRjCDQv9GA0L4g0L3QuNGFINC/0L7QtNGA0L7QsdC90LXQtSDQvNC+0LbQvdC+INCyINC60L3QuNCz0LUgKkFkdmFuY2VkIFIqDQoqICpTNCogIA0KLSDRgdGC0YDQvtCz0L7QtSDQvtC/0YDQtdC00LXQu9C10LjQtSDQutC70LDRgdGB0LAg0Lgg0LXQs9C+INC/0L7Qu9C10LkgIA0KLSDQsdC+0LvRjNGI0LUg0LLQvtC30LzQvtC20L3QvtGB0YLQtdC5INC00LvRjyDQv9C+0LLQtdC00LXQvdC40Y8g0LzQtdGC0L7QtNC+0LIgICANCiogUmVmZXJlbmNlIGNsYXNzZXMgDQoNCiMjIEdlbmVyaWMg0YTRg9C90LrRhtC40LgNCkdlbmVyaWMg0YTRg9C90LrRhtC40Lgg0YHQu9C10LTRg9C10YIg0YDQsNC30L7QsdGA0LDRgtGMINC/0L7QtNGA0L7QsdC90LXQtSwg0YIu0LouINCy0YHRgNC10YfQsNGO0YLRgdGPINC/0L7QstGB0LXQvNC10YHRgtC90L4uINCc0L7QttC90L4g0L/RgNC+0LLQtdGA0LjRgtGMINGP0LLQu9GP0LXRgtGB0Y8g0LvQuCDRhNGD0L3QutGG0LjRjyAqcHJpbnQqIGdlbmVyaWMg0YTRg9C90LrRhtC40LXQuQ0KYGBge3J9DQpsZW5ndGgobWV0aG9kcyhwcmludCkpDQpgYGANCtCV0YHQu9C4INC80Ysg0L/QvtC70YPRh9C40LvQuCDQvNC90L7Qs9C+INCy0LDRgNC40LDQvdGC0L7Qsiwg0LfQvdCw0YfQuNGCINGE0YPQvdC60YbQuNGPINC80L7QttC10YIg0YHQtdCx0Y8g0L/Qvi3RgNCw0LfQvdC+0LzRgyDQstC10YHRgtC4INCyINC30LDQstC40YHQuNC80L7RgdGC0Lgg0L7RgiDRgtC+0LPQviwg0YfRgtC+0LHRiyDQv9GA0LjRhdC+0LTQuNGCINC10Lkg0LIg0LrQsNGH0LXRgdGC0LLQtSDQsNGA0LPRg9C80LXQvdGC0LAuINCa0LDQutC40LUg0LzQvtCz0YPRgiDQsdGL0YLRjCDQv9GA0LjQvNC10YDRiz8gIA0KICANCtCV0YHQu9C4INCx0LXRgNC10LwgcHJpbnQoeCksINGC0L4g0LXRgdC70Lg6ICANCi0geCAtINC00LDRgtCwLdGE0YDQtdC50LwsINGC0L4g0LLRi9C30YvQstCw0LXRgtGB0Y8gKnByaW50LmRhdGEuZnJhbWUoeCkqOyAgDQotINC10YHQu9C4IHggLSDRhNGD0L3QutGG0LjRjywg0YLQviAqcHJpbnQuZnVuY3Rpb24oeCkqINC4INGC0LDQuiDQtNCw0LvQtdC1ICANCi0g0LXRgdC70Lgg0L3QuCDQvtC00LjQvSDQuNC3INC80LXRgtC+0LTQvtCyINC90LUg0L/QvtC00YXQvtC00LjRgiwg0YLQviAqcHJpbnQuZGVmYXVsdCh4KSogIA0KICANCiMg0KTRg9C90LrRhtC40Lgg0LHQtdC3INGB0YLQvtGA0L7QvdC90LjRhSDRjdGE0YTQtdC60YLQvtCyDQrQkiBSINC90LXRgiDRg9C60LDQt9Cw0YLQtdC70LXQuSDQvdCwINC+0LHRitC10LrRgtGLLCDQstGB0LUg0L7QsdGK0LXQutGC0Ysg0L/QtdGA0LXQtNCw0Y7RgtGB0Y8gItC/0L4g0LfQvdCw0YfQtdC90LjRjiIgKNGF0L7RgtGPINC10YHRgtGMINC90Y7QsNC90YHRiyEpDQpgYGB7cn0NCmYgPC0gZnVuY3Rpb24oaykgew0KICBrIDwtIGsrMQ0KICBhIDwtIGEgKyBrKjINCiAgYQ0KfQ0KayA8LSA1DQpmKGspDQpgYGANCg0KIyMg0J/RgNC40LzQtdGA0Ysg0YTRg9C90LrRhtC40LksINC+0YLRgNCw0LbQsNGO0YnQuNC1INGE0YPQvdC60YbQuNC+0L3QsNC70YzQvdC+0LUg0L/RgNC+0LPRgNCw0LzQvNC40YDQvtCy0LDQvdC40LUg0LIg0Y/Qt9GL0LrQtSBSDQoNCiMjIyDQpNGD0L3QutGG0LjRjyAqKnJlcGxpY2F0ZSogIA0K0JIg0LfQsNC00LDRh9Cw0YUg0LzQvtC00LXQu9C40YDQvtCy0LDQvdC40Y8g0YHQu9GD0YfQsNC50L3Ri9GFINC/0YDQvtGG0LXRgdGB0L7QsiDQv9GA0LjRhdC+0LTQuNGC0YHRjyDQstGB0YLRgNC10YfQsNGC0YzRgdGPINGBINC30LDQv9GA0L7RgdC+0Lwg0L/QvtCy0YLQvtGA0LjRgtGMINC+0LTQuNC9INC4INGC0L7RgiDQttC1INCy0YvRhdC+0LIg0L3QtdGB0LrQvtC70YzQutC+INGA0LDQtywg0L/RgNC4INGN0YLQvtC8INC60LDQttC00YvQuSDQvdC+0LLRi9C5INCy0YvQt9C+0LIg0LzQvtC20LXRgiDQuNC80LXRgtGMINC90L7QstGL0Lkg0YDQtdC30YPQu9GM0YLQsNGCICjQt9Cw0LLQuNGB0Y/RidC40LksINC90LDQv9GA0LjQvNC10YAsINC00LDRgtGH0LjQutCwINGB0LvRg9GH0LDQudC90YvRhSDRh9C40YHQtdC7KSAgDQogIA0KIyMjINCk0YPQvdGG0LjQuCDRgdC10LzQtdC50YLRgdCy0LAgYXBwbHkgIGFwcGx5LCBzYXBwbHkuIGxhcHBseSwgdGFwcGx5DQoqbWFwcGx5KiAtINC80L3QvtCz0L7QvNC10YDQvdCw0Y8g0LLQtdGA0YHQuNGPIHNhcHBseS4g0J7QvdCwINC/0YDQuNC90LjQsNC10YIg0L3QsCDQstGF0L7QtCDRhNGD0L3QutGG0LjRjiDQuCDQv9GA0L7QuNC30LLQvtC70YzQvdC+0LUg0LrQvtC70LjRh9C10YHRgtCy0L4g0YHQv9C40YHQutC+0LIg0LDRgNCz0YPQvNC10L3RgtC+0LIsINC60L7RgtC+0YDRi9C1INC90LXQvtCx0YXQvtC00LjQvtC8INC/0LXRgNC10LHRgNCw0YLRjC4g0J3QsNC/0YDQuNC80LXRgDogDQpgYGB7cn0NCm1hcHBseShzZXEsIGZyb20gPSAxOjQsIHRvID0gMjo1LCBieSA9IDEvKDEgKyAxOjQpKQ0KYGBgDQrQn9C+0LvRg9GH0LDQtdC8INGC0L7QttC1INGB0LDQvNC+0LUsINGH0YLQviDQv9C+0LvRg9GH0LjQu9C4INCx0Ysg0L/RgNC4INC/0L7RgdC70LXQtNC+0LLQsNGC0LXQu9GM0L3QvtC8INCy0YvQt9C+0LLQtSDRhNGD0L3QutGG0LjQuCBzZXEg0LTQu9GPINC60LDQttC00L7Qs9C+INC/0LXRgNCy0L7Qs9C+INGN0LvQtdC80LXQvdGC0LAg0LDRgNCz0YPQvNC10L3RgtC+0LIg0Lgg0LTQsNC70LXQtSDQutCw0LbQtNC+0LPQviBuLdCz0L4g0Y3Qu9C10LzQtdC90YLQsCDQsNGA0LPRg9C80LXQvdGC0L7Qsg0KDQojIyMgb3V0ZXINCtC/0LXRgNC10LHQvtGAINCy0YHQtdGFINCy0L7Qt9C80L7QttC90YvRhSDQutC+0LzQsdC40L3QsNGG0LjQuSDQsNGA0LPRg9C80LXQvdGC0L7Qsi4gIA0K0JTQvtC/0YPRgdGC0LjQvCwg0YXQvtGH0YMg0L/RgNC40LzQtdC90LjRgtGMICpwYXN0ZTAqINC60L4g0LLRgdC10Lwg0LLQvtC30LzQvtC20L3Ri9C8INCw0YDQs9GD0LzQtdC90YLQsNC8INC80LDRgdGB0LjQstCwIExFVFRFUlMg0LIg0L3QuNC20L3QtdC8INC4INCyINCS0JXQoNCl0J3QldCcINGA0LXQs9C40YHRgtGA0LUuINCi0L7Qs9C00LAg0LzQvtC20L3QviDQstC+0YHQv9C+0LvRjNC30L7QstCw0YLRjNGB0Y8g0YTRg9C90LrRhtC40LXQuSBvdXRlciAgDQpgYGB7cn0NCm0gPC0gb3V0ZXIobGV0dGVycywgTEVUVEVSUywgcGFzdGUwKQ0KYGBgDQrQotC10L/QtdGA0Ywg0LzQvtC20L3QviDRg9Cy0LjQtNC10YLRjCwg0YfRgtC+ICptKiAtINGN0YLQviDQvNCw0YLRgNC40YbQsCDRgNCw0LfQvNC10YDQvtC8IDI2KjI2LiAg0J/RgNC4INGN0YLQvtC8INC00LjQsNCz0L7QvdCw0LvRjNC90YvQtSDRjdC70LXQvNC10L3RgtGLINCx0YPQtNGD0YIg0YHQvtC00LXRgNC20LDRgtGMINCyINGB0LXQsdC1INC+0LTQuNC90LDQutC+0LLRi9C1INCx0YPQutCy0YsgIA0KYGBge3J9DQpkaWFnKG0pDQpgYGANCmBgYHtyfQ0KbVsxOjUsMTo0XQ0KYGBgDQoNCiMjIyBWZWN0b3JpemUgIA0K0J3QtSDQstGB0LUg0YTRg9C90LrRhtC40Lgg0LLQtdC60YLQvtGA0LjQt9C40YDQvtCy0LDQvdGLINC/0L4g0YPQvNC+0LvRh9Cw0L3QuNGOLCDRgtC+INC40YUg0LzQvtC20L3QviDRgdC00LXQu9Cw0YLRjCDRgtCw0LrQuNC80Lgg0YEg0L/QvtC80L7RidGM0Y4g0YTRg9C90LrRhtC40LggKlZlY3Rvcml6ZSogIA0KICANCiMjIyBkby5jYWxsICANCtCf0L7RgdC70LXQtNC90Y/RjyDRhNGD0L3QutGG0LjRjyDQuNC3INGB0L/QuNGB0LrQsCDRhNGD0L3QutGG0LjQvtC90LDQu9GM0L3QvtCz0L4g0L/RgNC+0LPRgNC80LzQuNGA0L7QstCw0L3QuNGPLiDQntC90LAg0L7RgdGD0YnQtdGB0YLQstC70Y/QtdGCINCy0YvQt9C+0LIg0L3QtdC60L7RgtC+0YDQvtC5INGE0YPQvdC60YbQuNC4INC90LAg0YHQv9C40YHQutC1INCw0YDQs9GD0LzQtdC90YLQvtCyLiDQndCw0L/RgNC40LzQtdGALCDQv9GA0LjRiNC10Lsg0LTQsNGC0LAt0YTRgNC10LnQvCwg0L3QviDQvtC9INGB0LXQs9C80LXQvdGC0LjRgNC+0LLQsNC9INC90LAgMyDQvtGC0LTQtdC70YzQvdGL0YUg0YTQsNC50LvQsCwg0LrQvtGC0L7RgNGL0LUg0L3Rg9C20L3QviDQvtCx0YrQtdC00LjQvdC40YLRjCDQvNC10LbQtNGDINGB0L7QsdC+0LkuINCc0L7QttC90L4g0LjRhSDRgdC+0LXQtNC40L3QuNGC0Ywg0LLQvNC10YHRgtC1INGBINC/0L7QvNC+0YnRjNGOIHJiaW5kLCDQsCDQvNC+0LbQvdC+INGBINC/0L7QvNC+0YnRjNGOIGRvLmNhbGwNCmBgYHtyfQ0KZGYxIDwtIGRhdGEuZnJhbWUobGQgPSAxOjIsIHZhbHVlID0gcm5vcm0oMikpDQpkZjIgPC0gZGF0YS5mcmFtZShsZCA9IDM6NCwgdmFsdWUgPSBydW5pZigyKSkNCmRmMyA8LSBkYXRhLmZyYW1lKGxkID0gMjIyLCB2YWx1ZSA9IDcpICANCmRvLmNhbGwocmJpbmQsIGxpc3QoZGYxLGRmMiwgZGYzKSkNCmBgYA0K0J3QviDQt9Cw0YfQtdC8INGC0L7Qs9C00LAg0LLQvtC+0LHRidC1IGRvLmNhbGwsINC10YHQu9C4INCyINGN0YLQvtC8INC/0YDQuNC80LXRgNC1INC80L7QttC90L4g0LHRi9C70L4g0L7QsdC+0LnRgtC40YHRjCDQsdC10Lcg0L3QtdCz0L4g0L/RgNC+0YHRgtC+INGC0L7Rh9C90L4g0YLQsNC6INC20LUg0YHQutC70LXQuNCyINC00LDRgtCwINGE0YDQtdC50LzRiyDRh9C10YDQtdC3IHJiaW5kLiAgDQrQpNGD0L3QutGG0LjRjyDQvdGD0LbQvdCwLCDQutC+0LPQtNCwINC80Ysg0L3QtSDQt9C90LDQtdC8INGB0LrQvtC70YzQutC+INC40LzQtdC90L3QviDQvtCx0YrQtdC60YLQvtCyINC90YPQttC90L4g0LHRg9C00LXRgiDRgdC60LvQtdC40YLRjCAgDQpgYGB7cn0NCmRvLmNhbGwocmJpbmQsbGFwcGx5KGxpc3QuZmlsZXMoKSwgZnVuY3Rpb24oZmlsZSkgcmVhZC5jc3YoZmlsZSkpKQ0KYGBgDQoNCiMjIyDQk9C70L7RgdCw0YDRgNC40LkgIA0KLSBTMywgUzQsIHJlZmVyZW5jZSBjbGFzcyAgDQotIGdlbmVyaWMgZnVuY3Rpb24gIA0KLSBjb3B5LW9uLW1vZGlmeSBzZW1hbnRpY3MgIA0KLSA/cmVwbGljYXRlICANCi0gP21hcHBseSAgDQotID9vdXRlciAgDQotIFZlY3Rvcml6ZSAgDQotIGRvLmNhbGwgIA0KICANCiAgICANCiMg0JzQvtC00LXQu9C40YDQvtCy0LDQvdC40LUg0YLRgNCw0LXQutGC0L7RgNC40Lgg0YHQu9GD0YfQsNC50L3QvtCz0L4g0L/RgNC+0YbQtdGB0YHQsA0K0KPQv9GA0LDQttC90LXQvdC40LUg0LzQvtC20LXRgiDQuNC80LXRgtGMINGA0LXQsNC70YzQvdC+0LUg0L/RgNC40LzQtdC90LXQvdC40LUg0LIg0YTQuNC30LjQutC1INGN0LvQtdC80LXQvdGC0LDRgNC90YvRhSDRh9Cw0YHRgtC40YYuDQoNCmBgYHtyfQ0KIyBSYW5kb20gd2FsayB3aXRoIGFic29ycHRpb24NCnNpbXVsYXRlX3dhbGsgPC0gZnVuY3Rpb24obG93ZXIgPSAtMTAsIHVwcGVyID0gMTAsIG5fbWF4ID0gMjAwLCBwID0gMWUtMykgew0KICAgIyDQvdCwINC60LDQttC00L7QvCDRiNCw0LPQtSDQtdGB0YLRjCDQv9C+0LfQuNGG0LjRjywg0L3QsNGH0LjQvdCw0LXQvCDQuNC3INGG0LXQvdGC0YDQsCDQuNC90YLQtdGA0LLQsNC70LANCiAgY3VycmVudF9wb3NpdGlvbiA8LSAobG93ZXIgKyB1cHBlcikgLyAyDQogIGZvciAoaSBpbiAxOm5fbWF4KSB7DQogICAgI9GB0L3QsNGH0LDQu9CwINC+0L/RgNC10LTQtdC70Y/QtdC8INCy0LXRgNC+0Y/RgtC90L7RgdGC0Ywg0L/QvtCz0LvQvtGJ0LXQvdC40Y8g0YfQsNGB0YLQuNGG0YsNCiAgICBpc19hYnNvcmJlZCA8LSByYmlub20oMSwgMSwgcCkNCiAgICAj0LXRgdC70Lgg0L/RgNC+0LjQt9C+0YjQu9C+IC0g0YHQuNC80YPQu9GP0YbQuNGPINC30LDQutCw0L3Rh9C40LLQsNC10YLRgdGPDQogICAgaWYgKGlzX2Fic29yYmVkKSByZXR1cm4obGlzdChzdGF0dXMgPSAiQWJzb3JiZWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gY3VycmVudF9wb3NpdGlvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwcyA9IGkpKQ0KICAgICPQtdGB0LvQuCDQv9C+0LPQu9C+0YnQtdC90LjQtSDQvdC1INC/0YDQvtC40LfQvtGI0LvQviAtINGB0L7QstC10YDRiNCw0LXQvCAxINGB0LvRg9GH0LDQudC90YvQuSDRiNCw0LMNCiAgICBjdXJyZW50X3Bvc2l0aW9uIDwtIGN1cnJlbnRfcG9zaXRpb24gKyBybm9ybSgxKQ0KICAgIGlmIChjdXJyZW50X3Bvc2l0aW9uIDwgbG93ZXIpIHJldHVybihsaXN0KHN0YXR1cyA9ICJMZWZ0IGJyZWFjaCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gY3VycmVudF9wb3NpdGlvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcHMgPSBpKSkNCiAgICBpZiAoY3VycmVudF9wb3NpdGlvbiA+IHVwcGVyKSByZXR1cm4obGlzdChzdGF0dXMgPSAiUmlnaHQgYnJlYWNoIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBjdXJyZW50X3Bvc2l0aW9uLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwcyA9IGkpKQ0KICB9DQogICPQstC+0LfQstGA0LDRidCw0LXQvCDRgtCw0LrQvtC1INGB0L7QvtCx0YnQtdC90LjQtSDQv9GA0Lgg0LTQvtGB0YLQuNC20LXQvdC40Lgg0LzQsNC60YHQuNC80LDQu9GM0L3QvtCz0L4g0LrQvtC70LjRh9C10YHRgtCy0LAg0YjQsNCz0L7Qsg0KICByZXR1cm4obGlzdChzdGF0dXMgPSAiTWF4IHN0ZXBzIHJlYWNoZWQiLCANCiAgICAgICAgICAgICAgcG9zaXRpb24gPSBjdXJyZW50X3Bvc2l0aW9uLCPQv9C+0LfQuNGG0LjRjywg0L3QsCDQutC+0YLQvtGA0L7QuSDQt9Cw0LLQtdGA0YjQuNC70LDRgdGMINGB0LjQvNGD0LvRj9GG0LjRjw0KICAgICAgICAgICAgICBzdGVwcyA9IG5fbWF4KSkgI9C60L7Qu9C40YfQtdGB0YLQstC+INGI0LDQs9C+0LIsINC90LAg0LrQvtGC0L7RgNC+0Lkg0LfQsNCy0LXRgNGI0LjQu9Cw0YHRjCDRgdC40LzRg9C70Y/RhtC40Y8NCn0NCmBgYA0K0JXRgdGC0Ywg0L7QtNC90L7QvNC10YDQvdCw0Y8g0L7QsdC70LDRgdGC0Ywg0L7RgiAtMTAg0LTQviAxMCwg0LIg0LrQvtGC0L7RgNC+0Lkg0LzQvtC20LXRgiDQvdCw0YXQvtC00LjRgtGB0Y8g0Y3Qu9C10LzQtdC90YLQsNGA0L3QsNGPINGH0LDRgdGC0LjRhtCwLiDQp9Cw0YHRgtC40YbQsCDQvNC+0LbQtdGCINC/0YDRi9Cz0LDRgtGMINC70LjQsdC+INCy0L/RgNCw0LLQviwg0LvQuNCx0L4g0LLQu9C10LLQviDQuCDQvdCwINC60LDQttC00L7QvCDRiNCw0LPQtSDQtdGB0YLRjCDQstC10YDQvtGP0YLQvdC+0YHRgtGMINGC0L7Qs9C+LCDRh9GC0L4g0L7QvdCwINC/0L7Qs9C70L7RgtC40YLRgdGPIChwID0gMWUtMykuINCe0LHRidC10LUg0LrQvtC70LjRh9C10YHRgtCy0L4g0L/QtdGA0LXRhdC+0LTQvtCyINC+0LPRgNCw0L3QuNGH0LjQstCw0LXQvCAyMDAg0YjQsNCz0LDQvNC4IChuX21heCA9IDIwMCkuICAgICANCtCf0L7Rh9C10LzRgyDQuNGB0L/QvtC70YzQt9C+0LLQsNC70Lgg0YbQuNC60LsgKmZvciosINGF0L7RgtGPINC00LvRjyBSIC0g0Y3RgtC+INC+0LTQuNC9INC40Lcg0LzQtdC00LvQtdC90L3Ri9GFINGB0L/QvtGB0L7QsdC+0LIsINC6INC60L7RgtC+0YDQvtC80YMg0L3Rg9C20L3QviDQvtGC0L3QvtGB0LjRgtGB0Y8g0YEg0L7RgdGC0L7RgNC+0LbQvdC+0YHRgtGM0Y4uINCU0LXQu9C+INCyINGC0L7QvCwg0YfRgtC+INC90LAg0LrQsNC20LTQvtC8INC40Lcg0YjQsNCz0L7QsiDRgdC40LzRg9C70Y/RhtC40Y8g0LzQvtC20LXRgiDQsdGL0YLRjCDQv9GA0LXRgNCy0LDQvdCwINC4INC30LDQutC+0L3Rh9C40YLRgdGPIC0g0LrQsNC20LTQvtC1INC+0L/RgNC10LTQtdC70LXQvdC40LUg0L/QtdGA0LXRhdC+0LTQsCDRjdGC0L4g0LrQsNC60LDRjy3RgtC+INGB0LvQvtC20L3QsNGPINCy0YvRh9C40YHQu9C40YLQtdC70YzQvdCw0Y8g0LfQsNCw0LTQsNGH0LAuINCV0YHQu9C4INCz0LXQvdC10YDQuNGA0L7QstCw0YLRjCDRgtCw0LrRg9GOINGB0LjRgtGD0LDRhtC40Y4g0YfQtdGA0LXQtyDQstC10LrRgtC+0YDQuNC30LDRhtC40Y4sINGC0L4g0LzRiyDQs9C10L3QtdGA0LjRgNGD0LXQvCDRgdGA0LDQt9GDIDIwMCDQv9C10YDQtdGF0L7QtNC+0LIgKNC/0L7RgtC10L3RhtC40LDQu9GM0L3Ri9C5INC80LDQutGB0LjQvNGD0LwpLCDRgtC+0LPQtNCwINC60LDQuiDRhtC40LrQuyDQvNC+0LbQtdGCINC/0YDQtdGA0LLQsNGC0YzRgdGPINGD0LbQtSDQvdCwINC/0LXRgNCy0L7QuSDQuNGC0LXRgNCw0YbQuNC4INCyINGB0LvRg9GH0LDQtSDQv9C+0LPQu9C+0YnQtdC90LjRjyDRh9Cw0YHRgtC40YbRiy4g0KIu0LUuINCyINGC0LDQutC+0Lkg0YHQuNGC0YPQsNGG0LjQuCDRhtC40LrQuyBmb3Ig0L/QvtC30LLQvtC70Y/QtdGCINGB0Y3QutC+0L3QvtC80LjRgtGMINGC0LUg0L/QtdGA0LXRhdC+0LTRiywg0LrQvtGC0L7RgNGL0LUg0LLRi9C/0LDQtNCw0Y7RgiDQt9CwINCz0YDQsNC90LjRhtGLINGB0LjQvNGD0LvRj9GG0LjQuCAgIA0KICANCiAgICANCtCi0LXQv9C10YDRjCDQvNC+0LbQvdC+INGBINC/0L7QvNC+0YnRjNGOINGE0YPQvdC60YbQuNC4ICpyZXBsaWNhdGUqINC/0L7QstGC0L7RgNC40YLRjCBuLdC+0LUg0YfQuNGB0LvQviDRgtCw0LrQuNGFINGB0LjQvNGD0LvRj9GG0LjQuQ0KYGBge3J9DQojIFNpbXVsYXRlIHJlc3VsdHMNCnJlc3VsdCA8LSByZXBsaWNhdGUoMTAwMCwgc2ltdWxhdGVfd2FsaygpLCBzaW1wbGlmeSA9IEZBTFNFKQ0KcmVzdWx0IDwtIGRhdGEuZnJhbWUoDQogIHN0YXR1cyA9IHNhcHBseShyZXN1bHQsIGZ1bmN0aW9uKHgpIHgkc3RhdHVzKSwNCiAgcG9zaXRpb24gPSBzYXBwbHkocmVzdWx0LCBmdW5jdGlvbih4KSB4JHBvc2l0aW9uKSwNCiAgc3RlcHMgPSBzYXBwbHkocmVzdWx0LCBmdW5jdGlvbih4KSB4JHN0ZXBzKQ0KKQ0KYGBgDQrQn9GA0LjQstC+0LTQuNC8INGA0LXQt9GD0LvRjNGC0LDRgiDQsiDRgtC+0Lwg0LLQuNC00LUsINC60L7RgtC+0YDRi9C5INC90LDQvCDRg9C00L7QsdC10L0uINCSINC00LDQvdC90L7QuSDQutC+0L3QutGA0LXRgtC90L7QuSDRgdC40YLRg9Cw0YbQuNC4INC/0YDQtdCy0YDQsNGJ0LDQtdC8INC10LPQviDQsiDQtNCw0YLQsC3RhNGA0LXQudC8DQoNCg0K0JzQvtC20L3QviDQv9C+0YHQvNC+0YLRgNC10YLRjCwg0YfRgtC+INC/0YDQuNC80LXRgNC90L4g0L/QvtC70YPRh9C40LvQvtGB0YwNCmBgYHtyfQ0Kc3RyKHJlc3VsdCkNCmBgYA0KYGBge3J9DQpoZWFkKHJlc3VsdCkNCmBgYA0K0KLQtdC/0LXRgNGMLCDQutC+0LPQtNCwINGDINC90LDRgSDQtdGB0YLRjCDQutCw0LrQsNGPLdGC0L4g0YDQsNC30YPQvNC90LDRjyDRgdGC0LDRgtC40YHRgtC40LrQsCwg0YLQviDQvNC+0LbQvdC+INC10LUg0L7Qv9GA0LXQtNC10LvQtdC40YLRjCwg0L3QsNC/0YDQuNC80LXRgCwg0YEg0L/QvtC80L7RidGM0Y4g0YTRg9C90LrRhtC40LggKnRhcHBseSoNCmBgYHtyfQ0KdGFwcGx5KHJlc3VsdCRwb3NpdGlvbiwgcmVzdWx0JHN0YXR1cywgbGVuZ3RoKQ0KdGFwcGx5KHJlc3VsdCRzdGVwcywgcmVzdWx0JHN0YXR1cywgbWVhbikNCmBgYA0KDQrQkdC+0LvRjNGI0LjQuSDQuNC90YLQtdGA0LXRgSDQv9GA0LXQtNGB0YLQsNCy0LvRj9GO0YIg0LfQsNC00LDRh9C4INGBINCx0LvRg9C20LTQsNC90LjQtdC8INC/0L4g0L/Qu9C+0YHQutC+0YHRgtC4LCDRgtC+INC10YHRgtGMINCyINGA0LDQt9C80LXRgNC90L7RgdGC0LggMi4gIA0K0JLQvtC30YzQvNC40YLQtSDQvdCw0L/QuNGB0LDQvdC90YPRjiDQvNC90L7QuSDRhNGD0L3QutGG0LjRjiDQuCDQuNC30LzQtdC90LjRgtC1INC10ZEg0YLQsNC6LCDRh9GC0L7QsdGLINCx0LvRg9C20LTQsNC90LjQtSDQvdCw0YfQuNC90LDQu9C+0YHRjCDQsiDRhtC10L3RgtGA0LUg0LrQvtC+0YDQtNC40L3QsNGCICgwLCAwKSwg0LAg0LLRgdC1INC/0LXRgNC10YXQvtC00Ysg0L/QviDQutC+0L7RgNC00LjQvdCw0YLQsNC8IHgg0LggeSDQsdGL0LvQuCDQsdGLINC90LXQt9Cw0LLQuNGB0LjQvNGLINC4INC40LzQtdC70Lgg0YHRgtCw0L3QtNCw0YDRgtC90L7QtSDQvdC+0YDQvNCw0LvRjNC90L7QtSDRgNCw0YHQv9GA0LXQtNC10LvQtdC90LjQtS4g0JXRgdC70Lgg0LLQsNGBINC/0YPQs9Cw0Y7RgiDRjdGC0Lgg0YHQu9C+0LLQsCwg0YLQviDRjdGC0L4g0YLQviDQttC1INGB0LDQvNC+0LUsINGH0YLQviDQtNC10LvQsNC7INGPLCDRgtC+0LvRjNC60L4g0L7RgtC00LXQu9GM0L3QviDQv9C+IHgg0Lgg0L/QviB5LiAgDQogIA0KKiDQn9GA0L7RhtC10YHRgSDQvtCx0YDRi9Cy0LDQtdGC0YHRjyDQsiDQvNC+0LzQtdC90YIg0LLRi9GF0L7QtNCwINC30LAg0LPRgNCw0L3QuNGG0YMg0LrRgNGD0LPQsCDRgSDRhtC10L3RgtGA0L7QvCDQsiAoMCwgMCkg0Lgg0YDQsNC00LjRg9GB0L7QvCA2ICANCiog0JLQtdGA0L7Rj9GC0L3QvtGB0YLRjCDQv9C+0LPQu9C+0YnQtdC90LjRjyDQvdCwINC60LDQttC00L7QvCDRiNCw0LPQtSDRgNCw0LLQvdCwIDAuMDEgIA0KKiDQnNCw0LrRgdC40LzQsNC70YzQvdC+0LUg0LrQvtC70LjRh9C10YHRgtCy0L4g0YjQsNCz0L7QsiDigJQgMTAwICANCiog0KDQsNGB0YHRgtC+0Y/QvdC40LUsINGA0LDQt9GD0LzQtdC10YLRgdGPLCDQtdCy0LrQu9C40LTQvtCy0L46INGA0LDRgdGB0YLQvtGP0L3QuNC1INC+0YIg0YLQvtGH0LrQuCAoeCwgeSkg0LTQviAoMCwgMCkg0LXRgdGC0YwgXHNxcnR7eF4yICsgeV4yfSAgDQoqICDQntC00LjQvSDRiNCw0LMg0L/RgNC+0YbQtdGB0YHQsCDQv9C+0LTRgNCw0LfRg9C80LXQstCw0LXRgiDQuNC30LzQtdC90LXQvdC40LUg0L7QsdC10LjRhSDQutC+0L7RgNC00LjQvdCw0YIg0L7QtNC90L7QstGA0LXQvNC10L3QvdC+IQ0KICANCtCSINC+0YLQstC10YLQtSDRg9C60LDQttC40YLQtSDQstC10YDQvtGP0YLQvdC+0YHRgtGMINCy0YvQu9C10YLQsCDRh9Cw0YHRgtC40YbRiyDQsiDQv9GA0L7RhtC10L3RgtCw0YUsINGBINGC0L7Rh9C90L7RgdGC0YzRjiDQtNC+INGG0LXQu9GL0YUg0L/RgNC+0YbQtdC90YLQvtCyLCDQsiDQstC40LTQtSBYWCAo0L3QsNC/0YDQuNC80LXRgCwgMTQsINCx0LXQtyDRg9C60LDQt9Cw0L3QuNGPINC30L3QsNGH0LrQsCDQv9GA0L7RhtC10L3RgtC+0LIpLiDQktC10YDQvtGP0YLQvdC+0YHRgtGMINC00L7Qu9C20L3QsCDQv9C+0LvRg9GH0LjRgtGM0YHRjyDQsdC+0LvRjNGI0LUgNTAlLg0KDQpgYGB7cn0NCnNpbXVsYXRlX3dhbGsgPC0gZnVuY3Rpb24obl9tYXggPSAxMDAsIHAgPSAxZS0yKSB7DQogIHg8LTANCiAgeTwtMA0KICBjdXJyZW50X3Bvc2l0aW9uIDwtIDAgDQogIGZvciAoaSBpbiAxOm5fbWF4KSB7DQogICAgaXNfYWJzb3JiZWQgPC0gcmJpbm9tKDEsIDEsIHApDQogICAgaWYgKGlzX2Fic29yYmVkKSByZXR1cm4obGlzdChzdGF0dXMgPSAiQWJzb3JiZWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gY3VycmVudF9wb3NpdGlvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwcyA9IGkpKQ0KICAgIHg8LXgrcm5vcm0oMSkNCiAgICB5PC15K3Jub3JtKDEpDQogICAgY3VycmVudF9wb3NpdGlvbiA8LSBzcXJ0KHgqKjIgKyB5KioyKQ0KICAgIGlmIChjdXJyZW50X3Bvc2l0aW9uID4gNikgcmV0dXJuKGxpc3Qoc3RhdHVzID0gImJyZWFjaCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gY3VycmVudF9wb3NpdGlvbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RlcHMgPSBpKSkNCiAgfQ0KICByZXR1cm4obGlzdChzdGF0dXMgPSAiTWF4IHN0ZXBzIHJlYWNoZWQiLCANCiAgICAgICAgICAgICAgcG9zaXRpb24gPSBjdXJyZW50X3Bvc2l0aW9uLA0KICAgICAgICAgICAgICBzdGVwcyA9IG5fbWF4KSkNCn0NCg0KYGBgDQoNCmBgYHtyfQ0KDQojIFNpbXVsYXRlIHJlc3VsdHMNCnJlc3VsdCA8LSByZXBsaWNhdGUoMTAwMDAwLCBzaW11bGF0ZV93YWxrKCksIHNpbXBsaWZ5ID0gRkFMU0UpDQpyZXN1bHQgPC0gZGF0YS5mcmFtZSgNCiAgc3RhdHVzID0gc2FwcGx5KHJlc3VsdCwgZnVuY3Rpb24oeCkgeCRzdGF0dXMpLA0KICBwb3NpdGlvbiA9IHNhcHBseShyZXN1bHQsIGZ1bmN0aW9uKHgpIHgkcG9zaXRpb24pLA0KICBzdGVwcyA9IHNhcHBseShyZXN1bHQsIGZ1bmN0aW9uKHgpIHgkc3RlcHMpDQopDQoNCmBgYA0KDQpgYGB7cn0NCiMgSW5zcGVjdCByZXN1bHRzDQp0YXBwbHkocmVzdWx0JHBvc2l0aW9uLCByZXN1bHQkc3RhdHVzLCBsZW5ndGgpDQp0YXBwbHkocmVzdWx0JHN0ZXBzLCByZXN1bHQkc3RhdHVzLCBtZWFuKQ0KYGBgDQpgYGB7cn0NCmEgPC0gODA5OTcvKDE4OTM0ICsgODA5OTcpKjEwMA0KYQ0KYGBgDQoNCtCe0LHRidC40Lkg0LPQu9C+0YHRgdCw0YDQuNC5INC00LvRjyDRjdGC0L7Qs9C+INGD0YDQvtC60LA6ICANCg0KUzMsIFM0LCByZWZlcmVuY2UgY2xhc3NlcyAgDQpHZW5lcmljIGZ1bmN0aW9uICANCkNvcHktb24tbW9kaWZ5IHNlbWFudGljcyAgDQo/cmVwbGljYXRlICANCj9tYXBwbHkgIA0KP291dGVyICANCj9WZWN0b3JpemUgIA0KP2RvLmNhbGwgIA==