Himpunan
R memiliki fungsi-fungsi himpunan yang diterapkan pada vektor. Misalkan pada vektor x dan y berikut.
x <- c(1,6,3,6,5)
y <- c(8,9,5,1,4)
union(x,y)
digunakan untuk mendapatkan nilai unik dari anggota x dan y
[1] 1 6 3 5 8 9 4
intersect(x,y)
digunakan untuk mendapatkan anggota x yang juga anggota y
[1] 1 5
setdiff(x,y)
digunakan untuk mendapatkan anggota x yang bukan anggota y
[1] 1 6 3 6 5
[1] 8 9 5 1 4
[1] 6 3
[1] 8 9 4
setequal(x,y)
digunakan untuk mengetahui apakah semua anggota x dan y sama
[1] FALSE
# contoh ketika x dan y memiliki anggota yang sama
x1 <- c(1,2,3,4,5,3,2,1)
y1 <- c(5,4,3,2,1)
setequal(x1,y1)
[1] TRUE
jumlah elemen dan urutan tidak berpengaruh, yang dicek ialah nilai unik dari setiap elemen pada kedua vektor.
c %in% y
digunakan untuk mengetahui apakah anggota vektor c ada di y
[1] 1 6 3 6 5
[1] 8 9 5 1 4
[1] TRUE FALSE TRUE
[1] FALSE
[1] TRUE FALSE FALSE FALSE TRUE
choose(n,k)
digunakan untuk mengetahui banyaknya kombinasi k dari n
[1] 10
combn(n,k)
digunakan untuk mendapatkan matriks semua kemungkinan kombinasi k dari n
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 1 1 1 1 1 2 2 2 3
[2,] 2 2 2 3 3 4 3 3 4 4
[3,] 3 4 5 4 5 5 4 5 5 5
Fungsi-fungsi Matematika
Fungsi-fungsi Matematika Umum
exp()
fungsi eksponensial dengan basis natural (e)
[1] 2980.958
[1] 2.718282
[1] 2980.958
log()
digunakan untuk mendapatkan nilai logaritma dengan basis natural (ln)
[1] 4.60517
log10()
digunakan untuk mendapatkan nilai logaritma dengan basis 10
[1] 2
sqrt()
digunakan untuk mendapatkan nilai akar kuadrat
[1] 1.000000 2.449490 1.732051 2.449490 2.236068
[1] 10
abs()
digunakan untuk mendapatkan nilai nilai absolut / nilai mutlaknya
x2 <- c(-1,2,-3,4,-5)
abs(x2)
[1] 1 2 3 4 5
Fungsi Trigonometri
Berikut adalah beberapa fungsi trigonometri
[1] 0
[1] 1
fungsi di atas digunakan untuk mendapatkan nilai sinus dan cosinus.
Fungsi-fungsi Bilangan Integer
Berikut adalah beberapa fungsi pembulatan bilangan agar menjadi bilangan integer.
y2 <- c(2.4, 3.6, 4.5, 5.5)
round(y2)
[1] 2 4 4 6
[1] 2 3 4 5
[1] 3 4 5 6
Perbedaan pada penggunaan fungsi-fungsi di atas yaitu:
round() memiliki hasil yang sama seperti pembulatan biasa dimana:
- bila nilai koma > 0.5 maka bilangan akan dibulatkan ke atas.
- bila nilai koma < 0.5 maka bilangan akan dibulatkan ke bawah.
- bila nilai koma = 0.5 dan bilangan integernya bernilai genap maka bilangan akan dibulatkan ke bawah.
- bila nilai koma = 0.5 dan bilangan integernya bernilai ganjil maka bilangan akan dibulatkan ke atas.
floor(): pembulatan ke bawah (hanya mengambil nilai integernya saja).
ceiling(): pembulatan ke atas
factorial()
fungsi faktorial (n!=nx(n-1)x(n-2)x…x1)
[1] 120
[1] 120
Fungsi-fungsi Lain
Terdapat pula beberapa fungsi umum yang sering digunakan, berikut adalah contoh penggunaan fungsi umum pada suatu vektor a.
a <- c(4,5,6,2,1,3,5,4,8,3)
min() and max()
digunakan untuk mendapatkan nilai minimum dan maksimum dari suatu vektor
[1] 1
[1] 8
which
mendapatkan index vektor yang memenuhi kriteria tertentu
[1] 4 5 6 2 1 3 5 4 8 3
[1] 2 3 7 9
which.min() : mendapatkan index vektor untuk nilai minimum
which.max(): mendapatkan index vektor untuk nilai maksimum
[1] 4 5 6 2 1 3 5 4 8 3
[1] 5
[1] 9
pmin() and pmax()
element-wise minimum dan maksimum dari suatu vektor
b <- c(2,1,8,7,8,2,8,6,3,2)
a
[1] 4 5 6 2 1 3 5 4 8 3
[1] 2 1 8 7 8 2 8 6 3 2
[1] 2 1 6 2 1 2 5 4 3 2
[1] 4 5 8 7 8 3 8 6 8 3
nilai1 <- round(rnorm(10,70,5),2)
nilai2 <- round(rnorm(10,80,7),2)
data.nilai <- data.frame(nilai1,nilai2,nilai.maksimum=pmax(nilai1,nilai2))
data.nilai
sum() and prod()
jumlah dan perkalian elemen suatu vektor
[1] 4 5 6 2 1 3 5 4 8 3
[1] 41
[1] 345600
cumsum() and cumprod()
jumlah dan perkalian kumulatif dari elemen suatu vektor
[1] 4 5 6 2 1 3 5 4 8 3
[1] 4 9 15 17 18 21 26 30 38 41
[1] 4 20 120 240 240 720 3600 14400 115200 345600
Fungsi Kalkulus: Diferensial
R memiliki fungsi-fungsi untuk mendapatkan turunan dari suatu fungsi. Fungsi yang digunakan merupakan fungsi dengan satu peubah.
D
D(expr,simbol) digunakan jika hasil turunan merupakan suatu fungsi. Sebagai contoh akan dicari turunan dari fungsi berikut.
\(\begin{aligned} f(x) = e^{(x^2)} \end{aligned}\)
xfs <- expression(exp(x^2))
D(xfs,"x")
exp(x^2) * (2 * x)
deriv
deriv(∼fungsi,simbol) digunakan jika akan memasukkan nilai dari hasil turunan pada suatu fungsi. Sebagai contoh akan dicari turunan dari fungsi berikut
\(\begin{aligned} f(x) = x^2 \end{aligned}\)
untuk nilai \(x=3\)
xturunan <- deriv(~x^2, "x")
x<-3
eval(xturunan)
[1] 9
attr(,"gradient")
x
[1,] 6
expression({
.value <- x^2
.grad <- array(0, c(length(.value), 1L), list(NULL, c("x")))
.grad[, "x"] <- 2 * x
attr(.value, "gradient") <- .grad
.value
})
Fungsi Kalkulus: Integral
Selain turunan pada fungsi sederhana, R juga memiliki fungsi untuk mendapatkan luas wilayah suatu fungsi dengan integral integrate(fungsi, lower, upper)
fs <- function(x) x^2
integrate(fs,0,1)
0.3333333 with absolute error < 3.7e-15
fsi <- function(x) 1/3*x^3
fsi(1) - fsi(0)
[1] 0.3333333
Selain itu, terdapat fungsi yac_str() pada package Ryacas untuk mencari integral tak tentu.
Contoh dengan fungsi yac_str pada paket Ryacas
\(\begin{aligned} \int x^2 + 4x dx \end{aligned}\)
yac_str("Integrate(x) x^2 + 4*x")
[1] "x^3/3+2*x^2"
Fungsi-fungsi Statistika:Sebaran
Fungsi sebaran statistik secara konvensi:
- dnamasebaran: density or probability mass function (pmf)
- pnamasebaran: cumulative distribution function (cdf)
- qnamasebaran: quantiles
- rnamasebaran: random number generation
Dengan nama sebaran dan parameter dapat dilihat pada tabel berikut
| beta |
beta |
shape1, shape2, ncp |
| binomial |
binom |
size, prob |
| Chauchy |
cauchy |
location, scale |
| chi-squared |
chisq |
df, ncp |
| exponential |
exp |
rate |
| F |
f |
df1, df2, ncp |
| gamma |
gamma |
shape, scale |
| geometric |
geom |
prob |
| hypergeometric |
hyper |
m, n, k |
| log-normal |
lnorm |
meanlog, sdlog |
| logistic |
logis |
location, scale |
| uniform |
unif |
min, max |
| neg binomial |
nbinom |
size, prob |
| normal |
norm |
mean, sd |
| Poisson |
pois |
lambda |
| Student’s t |
t |
df, ncp |
| Weibull |
weibull |
shape |
| Empirical cdf |
ecdf |
- |
| Box-percentile |
bpplot |
list of vector |
berikut adalah contoh penggunaan fungsi sebaran pada sebaran normal baku.
[1] 0.3989423
[1] 0.5
[1] 0
x <- rnorm(10,mean=0,sd=1)
cbind(mean(x),sd(x))
[,1] [,2]
[1,] -0.2708766 1.179979
Optimasi Numerik
Beberapa metode statistik menggunakan metode pendugaan nilai optimum dari suatu fungsi tujuan seperti dengan metode kemungkinan maksimum (memaksimumkan likelihood) dan metode kuadrat terkecil (meminimumkan JKG).
Mendapatkan nilai optimum dari suatu fungsi merupakan suatu teknik optimasi numerik.
Beberapa metode yang sudah dikembangkan diantaranya:
Golden Section Search
Metode golden section search digunakan untuk mencari nilai minimum suatu fungsi yang dibatasi dari dua buah nilai, yaitu sebuah selang a dan b. Algoritma untuk teknik ini adalah sebagai berikut:
- Mulai dengan selang [a,b] yang memuat minimum
- Perkecil selang \([a’, b’]\) yang memuat minimum
- Berhenti sampai \(|b’ - a’|\) lebih kecil dari nilai toleransi
Pemilihan nilai \(a'\) dan \(b'\), adalah sebagai berikut
Nilai antara [a,b] memiliki sifat golden ratio
Tentukan \(x_1\) dan \(x_2\)
\(x_1 = b-(b-a)/\mathrm{goldenratio}\)
\(x_2 = a+(b-a)/\mathrm{goldenratio}\)
Hitung \(f(x_1)\) dan \(f(x_2)\)
Jika \(f(x_1) > f(x_2)\) maka \([a’, b’] = [x_1, b]\)
Jika \(f(x_1) < f(x_2)\) maka \([a’, b’] = [a, x_2]\)
Fungsi golden section
golden <- function (f, a, b, tol=0.0000001) {
ratio <- 2 / ( sqrt (5)+1)
x1 <- b-ratio * (b-a)
x2 <- a+ratio * (b-a)
f1 <- f(x1)
f2 <- f(x2)
while ( abs (b-a)>tol){
if (f2>f1){
b <- x2
x2 <- x1
f2 <- f1
x1 <- b-ratio * (b-a)
f1 <- f(x1)
} else {
a <- x1
x1 <- x2
f1 <- f2
x2 <- a+ratio * (b-a)
f2 <- f(x2)
}
}
return ((a+b) / 2)
}
Contoh:
\(\begin{aligned} f(x) = |x -3.5| +(x-2)^2 \end{aligned}\)
# Membuat fungsi f(x)
f <- function(x) {abs(x-3.5)+(x-2)^2}
# Membuat plot
curve(f, 1,5)

# Menghitung nilai optimum
golden(f,1,2)
[1] 2
[1] 2.5
[1] 3
[1] 2.5
Newton Raphson
Jika suatu fungsi memiliki turunan pertama dan kedua, maka nilai minimum dapat menggunakan metode Newton Raphson. Kelebihan metode ini adalah hanya memerlukan satu nilai untuk inisial. Kelemahannya adalah kita harus yakin f(x) memiliki turunan pertama dan turunan kedua. Jika di golden section tidak perlu ada turunan pertama dan turunan kedua.
Fungsi Newton Raphson
newtonr <- function (fx , x0 =1){
fx1 <- deriv (fx ,"x") # turunan pertama
fx2 <- deriv (D(fx ,"x"),"x") # turunan kedua
er <- 1000
while(er > 1e-6){
x <- x0
f1 <- attr ( eval (fx1),"gradient")[1]
f2 <- attr ( eval (fx2),"gradient")[1]
er <- abs(f1) # bisa juga e <- abs (x1 -x0)
x1 <- x0 - f1/f2
x0 <- x1
}
return (x1)
}
Hitung nilai minimum untuk fungsi- fungsi berikut.
\(\begin{aligned} f(x) = 4x^2 - 3x - 7 \end{aligned}\)
fx <- expression(4*x^2-3*x-7)
newtonr(fx,3)
[1] 0.375
\(\begin{aligned} f(x) = e^{-x}+x^4 \end{aligned}\)
fx <- expression(exp(-x)+x^4)
newtonr(fx)
[1] 0.5282519
[1] 0.5282519
\(\begin{aligned} f(x) = x^2 - x \end{aligned}\)
fx <- expression(x^2-x)
newtonr(fx)
[1] 0.5
Fungsi Optimasi Built-in
Algoritma Nelder Mead adalah salah satu metode optimasi untuk fungsi yang memiliki lebih dari satu variabel. R telah menyiapkan fungsi optimasi dengan salah satu algoritmanya adalah Nelder-Mead:
optimize atau optimise untuk menduga parameter/ mencari nilai minimum dari satu peubah
optim untuk lebih dari satu peubah
Fungsi optimize/optimise
\(\begin{aligned} f(x) = \left( x - \frac{1}{3} \right)^2 \end{aligned}\)
f <- function(x) ((x-(1/3))^2) # membuat fungsi tujuan
curve(f)

xmin <- optimize(f, c(0,1), tol = 0.0001) # tolerance optional
xmin
$minimum
[1] 0.3333333
$objective
[1] 0
Fungsi optim
Digunakan untuk mencari nilai minimum dari fungsi yang lebih dari satu peubah. Contoh mencari nilai \(x_1\) dan \(x_2\), yang mebuat \(f(x_1,x_2) = 100(x_2 - x_1^2)^2 + (1-x_1)^2\) minimum
Program yang digunakan:
fr <- function (x){ # tetap dituliskan dalam sebuah vektor, akan diduga x
x1<- x[1]
x2 <- x[2]
100 * (x2-x1^2)^2 + (1-x1)^2 # ini adalah nilai fungsi objetivenya
}
# argumen pertama adalah nilai inisial, karena menduga x vektor berukuran 2 maka dimasukkan nilai inisialnya
optim (c(-1.2,1),fr)
$par
[1] 1.000260 1.000506
$value
[1] 8.825241e-08
$counts
function gradient
195 NA
$convergence
[1] 0
$message
NULL
LS0tDQp0aXRsZTogIkZ1bmdzaS1mdW5nc2kgTWF0ZW1hdGlrIGRhbiBTdGF0aXN0aWsiDQphdXRob3I6ICJBbm5pc3NhIE51ciBGaXRyaWEgRmF0aGluYV5bTWFoYXNpc3dhIFN0YXRpc3Rpa2EgZGFuIFNhaW5zIERhdGEgSVBCLCBhbm5pc3NhX25mZkBhcHBzLmlwYi5hYy5pZF0iDQpkYXRlOiAiMS80LzIwMjIiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiBoYWRkb2NrDQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiBzZW50ZW5jZQ0KLS0tDQoNCiMgSGltcHVuYW4NCg0KUiBtZW1pbGlraSBmdW5nc2ktZnVuZ3NpIGhpbXB1bmFuIHlhbmcgZGl0ZXJhcGthbiBwYWRhIHZla3Rvci4NCk1pc2Fsa2FuIHBhZGEgdmVrdG9yIHggZGFuIHkgYmVyaWt1dC4NCg0KYGBge3J9DQp4IDwtIGMoMSw2LDMsNiw1KQ0KeSA8LSBjKDgsOSw1LDEsNCkNCmBgYA0KDQojIyB1bmlvbih4LHkpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSB1bmlrIGRhcmkgYW5nZ290YSB4IGRhbiB5DQoNCmBgYHtyfQ0KdW5pb24oeCx5KQ0KYGBgDQoNCiMjIGludGVyc2VjdCh4LHkpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBhbmdnb3RhIHggeWFuZyBqdWdhIGFuZ2dvdGEgeQ0KDQpgYGB7cn0NCmludGVyc2VjdCh4LHkpDQpgYGANCg0KIyMgc2V0ZGlmZih4LHkpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBhbmdnb3RhIHggeWFuZyBidWthbiBhbmdnb3RhIHkNCg0KYGBge3J9DQp4O3kNCnNldGRpZmYoeCx5KQ0Kc2V0ZGlmZih5LHgpDQpgYGANCg0KIyMgc2V0ZXF1YWwoeCx5KQ0KDQpkaWd1bmFrYW4gdW50dWsgbWVuZ2V0YWh1aSBhcGFrYWggc2VtdWEgYW5nZ290YSB4IGRhbiB5IHNhbWENCg0KYGBge3J9DQpzZXRlcXVhbCh4LHkpDQpgYGANCg0KYGBge3J9DQojIGNvbnRvaCBrZXRpa2EgeCBkYW4geSBtZW1pbGlraSBhbmdnb3RhIHlhbmcgc2FtYQ0KeDEgPC0gYygxLDIsMyw0LDUsMywyLDEpDQp5MSA8LSBjKDUsNCwzLDIsMSkNCnNldGVxdWFsKHgxLHkxKQ0KYGBgDQoNCmp1bWxhaCBlbGVtZW4gZGFuIHVydXRhbiB0aWRhayBiZXJwZW5nYXJ1aCwgeWFuZyBkaWNlayBpYWxhaCBuaWxhaSB1bmlrIGRhcmkgc2V0aWFwIGVsZW1lbiBwYWRhIGtlZHVhIHZla3Rvci4NCg0KIyMgYyAlaW4lIHkNCg0KZGlndW5ha2FuIHVudHVrIG1lbmdldGFodWkgYXBha2FoIGFuZ2dvdGEgdmVrdG9yIGMgYWRhIGRpIHkNCg0KYGBge3J9DQp4OyB5DQpjKDEsMiwzKSAlaW4lIHgNCjcgJWluJSB5DQp4ICVpbiUgeQ0KYGBgDQoNCiMjIGNob29zZShuLGspDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5nZXRhaHVpIGJhbnlha255YSBrb21iaW5hc2kgayBkYXJpIG4NCg0KYGBge3J9DQpjaG9vc2UoNSwzKQ0KYGBgDQoNCiMjIGNvbWJuKG4saykNCg0KZGlndW5ha2FuIHVudHVrIG1lbmRhcGF0a2FuIG1hdHJpa3Mgc2VtdWEga2VtdW5na2luYW4ga29tYmluYXNpIGsgZGFyaSBuDQoNCmBgYHtyfQ0KY29tYm4oNSwzKQ0KYGBgDQoNCiMgRnVuZ3NpLWZ1bmdzaSBNYXRlbWF0aWthDQoNCiMjIEZ1bmdzaS1mdW5nc2kgTWF0ZW1hdGlrYSBVbXVtDQoNCiMjIyBleHAoKQ0KDQpmdW5nc2kgZWtzcG9uZW5zaWFsIGRlbmdhbiBiYXNpcyBuYXR1cmFsIChlKQ0KDQpgYGB7cn0NCmV4cCg4KQ0KZXhwKDEpDQpleHAoMSleOA0KYGBgDQoNCiMjIyBsb2coKQ0KDQpkaWd1bmFrYW4gdW50dWsgbWVuZGFwYXRrYW4gbmlsYWkgbG9nYXJpdG1hIGRlbmdhbiBiYXNpcyBuYXR1cmFsIChsbikNCg0KYGBge3J9DQpsb2coMTAwKQ0KYGBgDQoNCiMjIyBsb2cxMCgpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSBsb2dhcml0bWEgZGVuZ2FuIGJhc2lzIDEwDQoNCmBgYHtyfQ0KbG9nMTAoMTAwKQ0KYGBgDQoNCiMjIyBzcXJ0KCkNCg0KZGlndW5ha2FuIHVudHVrIG1lbmRhcGF0a2FuIG5pbGFpIGFrYXIga3VhZHJhdA0KDQpgYGB7cn0NCnNxcnQoeCkNCnNxcnQoMTAwKQ0KYGBgDQoNCiMjIyBhYnMoKQ0KDQpkaWd1bmFrYW4gdW50dWsgbWVuZGFwYXRrYW4gbmlsYWkgbmlsYWkgYWJzb2x1dCAvIG5pbGFpIG11dGxha255YQ0KDQpgYGB7cn0NCngyIDwtIGMoLTEsMiwtMyw0LC01KQ0KYWJzKHgyKQ0KYGBgDQoNCiMjIyBGdW5nc2kgVHJpZ29ub21ldHJpDQoNCkJlcmlrdXQgYWRhbGFoIGJlYmVyYXBhIGZ1bmdzaSB0cmlnb25vbWV0cmkNCg0KYGBge3J9DQpzaW4oMCkNCmNvcygwKQ0KYGBgDQoNCmZ1bmdzaSBkaSBhdGFzIGRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSBzaW51cyBkYW4gY29zaW51cy4NCg0KIyMjIEZ1bmdzaS1mdW5nc2kgQmlsYW5nYW4gSW50ZWdlcg0KDQpCZXJpa3V0IGFkYWxhaCBiZWJlcmFwYSBmdW5nc2kgcGVtYnVsYXRhbiBiaWxhbmdhbiBhZ2FyIG1lbmphZGkgYmlsYW5nYW4gaW50ZWdlci4NCg0KYGBge3J9DQp5MiA8LSBjKDIuNCwgMy42LCA0LjUsIDUuNSkNCnJvdW5kKHkyKQ0KZmxvb3IoeTIpIA0KY2VpbGluZyh5MikgDQpgYGANCg0KUGVyYmVkYWFuIHBhZGEgcGVuZ2d1bmFhbiBmdW5nc2ktZnVuZ3NpIGRpIGF0YXMgeWFpdHU6DQoNCi0gICBgcm91bmQoKWAgbWVtaWxpa2kgaGFzaWwgeWFuZyBzYW1hIHNlcGVydGkgcGVtYnVsYXRhbiBiaWFzYSBkaW1hbmE6DQotICAgYmlsYSBuaWxhaSBrb21hIFw+IDAuNSBtYWthIGJpbGFuZ2FuIGFrYW4gZGlidWxhdGthbiBrZSBhdGFzLg0KLSAgIGJpbGEgbmlsYWkga29tYSBcPCAwLjUgbWFrYSBiaWxhbmdhbiBha2FuIGRpYnVsYXRrYW4ga2UgYmF3YWguDQotICAgYmlsYSBuaWxhaSBrb21hID0gMC41IGRhbiBiaWxhbmdhbiBpbnRlZ2VybnlhIGJlcm5pbGFpIGdlbmFwIG1ha2EgYmlsYW5nYW4gYWthbiBkaWJ1bGF0a2FuIGtlIGJhd2FoLg0KLSAgIGJpbGEgbmlsYWkga29tYSA9IDAuNSBkYW4gYmlsYW5nYW4gaW50ZWdlcm55YSBiZXJuaWxhaSBnYW5qaWwgbWFrYSBiaWxhbmdhbiBha2FuIGRpYnVsYXRrYW4ga2UgYXRhcy4NCi0gICBgZmxvb3IoKWA6IHBlbWJ1bGF0YW4ga2UgYmF3YWggKGhhbnlhIG1lbmdhbWJpbCBuaWxhaSBpbnRlZ2VybnlhIHNhamEpLg0KLSAgIGBjZWlsaW5nKClgOiBwZW1idWxhdGFuIGtlIGF0YXMNCg0KIyMjIGZhY3RvcmlhbCgpDQoNCmZ1bmdzaSBmYWt0b3JpYWwgKGBuIT1ueChuLTEpeChuLTIpeOKApngxYCkNCg0KYGBge3J9DQpmYWN0b3JpYWwoNSkNCjUqNCozKjIqMQ0KYGBgDQoNCiMjIEZ1bmdzaS1mdW5nc2kgTGFpbg0KDQpUZXJkYXBhdCBwdWxhIGJlYmVyYXBhIGZ1bmdzaSB1bXVtIHlhbmcgc2VyaW5nIGRpZ3VuYWthbiwgYmVyaWt1dCBhZGFsYWggY29udG9oIHBlbmdndW5hYW4gZnVuZ3NpIHVtdW0gcGFkYSBzdWF0dSB2ZWt0b3IgYS4NCg0KYGBge3J9DQphIDwtIGMoNCw1LDYsMiwxLDMsNSw0LDgsMykNCmBgYA0KDQojIyMgbWluKCkgYW5kIG1heCgpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSBtaW5pbXVtIGRhbiBtYWtzaW11bSBkYXJpIHN1YXR1IHZla3Rvcg0KDQpgYGB7cn0NCm1pbihhKQ0KbWF4KGEpDQpgYGANCg0KIyMjIHdoaWNoDQoNCm1lbmRhcGF0a2FuIGluZGV4IHZla3RvciB5YW5nIG1lbWVudWhpIGtyaXRlcmlhIHRlcnRlbnR1DQoNCmBgYHtyfQ0KYQ0Kd2hpY2goYT40KQ0KYGBgDQoNCmB3aGljaC5taW4oKWAgOiBtZW5kYXBhdGthbiBpbmRleCB2ZWt0b3IgdW50dWsgbmlsYWkgbWluaW11bQ0KDQpgd2hpY2gubWF4KClgOiBtZW5kYXBhdGthbiBpbmRleCB2ZWt0b3IgdW50dWsgbmlsYWkgbWFrc2ltdW0NCg0KYGBge3J9DQphDQp3aGljaC5taW4oYSkNCndoaWNoLm1heChhKQ0KYGBgDQoNCiMjIyBwbWluKCkgYW5kIHBtYXgoKQ0KDQplbGVtZW50LXdpc2UgbWluaW11bSBkYW4gbWFrc2ltdW0gZGFyaSBzdWF0dSB2ZWt0b3INCg0KYGBge3J9DQpiIDwtIGMoMiwxLDgsNyw4LDIsOCw2LDMsMikNCmENCmINCnBtaW4oYSxiKQ0KcG1heChhLGIpDQpgYGANCg0KYGBge3J9DQpuaWxhaTEgPC0gcm91bmQocm5vcm0oMTAsNzAsNSksMikNCm5pbGFpMiA8LSByb3VuZChybm9ybSgxMCw4MCw3KSwyKQ0KZGF0YS5uaWxhaSA8LSBkYXRhLmZyYW1lKG5pbGFpMSxuaWxhaTIsbmlsYWkubWFrc2ltdW09cG1heChuaWxhaTEsbmlsYWkyKSkNCmRhdGEubmlsYWkNCmBgYA0KDQojIyMgc3VtKCkgYW5kIHByb2QoKQ0KDQpqdW1sYWggZGFuIHBlcmthbGlhbiBlbGVtZW4gc3VhdHUgdmVrdG9yDQoNCmBgYHtyfQ0KYQ0Kc3VtKGEpDQpwcm9kKGEpDQpgYGANCg0KIyMjIGN1bXN1bSgpIGFuZCBjdW1wcm9kKCkNCg0KanVtbGFoIGRhbiBwZXJrYWxpYW4ga3VtdWxhdGlmIGRhcmkgZWxlbWVuIHN1YXR1IHZla3Rvcg0KDQpgYGB7cn0NCmENCmN1bXN1bShhKQ0KY3VtcHJvZChhKQ0KYGBgDQoNCiMjIEZ1bmdzaSBLYWxrdWx1czogRGlmZXJlbnNpYWwNCg0KUiBtZW1pbGlraSBmdW5nc2ktZnVuZ3NpIHVudHVrIG1lbmRhcGF0a2FuIHR1cnVuYW4gZGFyaSBzdWF0dSBmdW5nc2kuDQpGdW5nc2kgeWFuZyBkaWd1bmFrYW4gbWVydXBha2FuIGZ1bmdzaSBkZW5nYW4gc2F0dSBwZXViYWguDQoNCiMjIyBEDQoNCmBEKGV4cHIsc2ltYm9sKWAgZGlndW5ha2FuIGppa2EgaGFzaWwgdHVydW5hbiBtZXJ1cGFrYW4gc3VhdHUgZnVuZ3NpLg0KU2ViYWdhaSBjb250b2ggYWthbiBkaWNhcmkgdHVydW5hbiBkYXJpIGZ1bmdzaSBiZXJpa3V0Lg0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSBlXnsoeF4yKX0gXGVuZHthbGlnbmVkfSQNCg0KYGBge3J9DQp4ZnMgPC0gZXhwcmVzc2lvbihleHAoeF4yKSkNCkQoeGZzLCJ4IikNCmBgYA0KDQojIyMgZGVyaXYNCg0KYGRlcml2KOKIvGZ1bmdzaSxzaW1ib2wpYCBkaWd1bmFrYW4gamlrYSBha2FuIG1lbWFzdWtrYW4gbmlsYWkgZGFyaSBoYXNpbCB0dXJ1bmFuIHBhZGEgc3VhdHUgZnVuZ3NpLg0KU2ViYWdhaSBjb250b2ggYWthbiBkaWNhcmkgdHVydW5hbiBkYXJpIGZ1bmdzaSBiZXJpa3V0DQoNCiRcYmVnaW57YWxpZ25lZH0gZih4KSA9IHheMiBcZW5ke2FsaWduZWR9JA0KDQp1bnR1ayBuaWxhaSAkeD0zJA0KDQpgYGB7cn0NCnh0dXJ1bmFuIDwtIGRlcml2KH54XjIsICJ4IikNCng8LTMNCmV2YWwoeHR1cnVuYW4pDQoNCmBgYA0KDQpgYGB7cn0NCnh0dXJ1bmFuDQpgYGANCg0KIyMgRnVuZ3NpIEthbGt1bHVzOiBJbnRlZ3JhbA0KDQpTZWxhaW4gdHVydW5hbiBwYWRhIGZ1bmdzaSBzZWRlcmhhbmEsIFIganVnYSBtZW1pbGlraSBmdW5nc2kgdW50dWsgbWVuZGFwYXRrYW4gbHVhcyB3aWxheWFoIHN1YXR1IGZ1bmdzaSBkZW5nYW4gaW50ZWdyYWwgYGludGVncmF0ZShmdW5nc2ksIGxvd2VyLCB1cHBlcilgDQoNCmBgYHtyfQ0KZnMgPC0gZnVuY3Rpb24oeCkgeF4yDQppbnRlZ3JhdGUoZnMsMCwxKQ0KZnNpIDwtIGZ1bmN0aW9uKHgpIDEvMyp4XjMNCmZzaSgxKSAtIGZzaSgwKQ0KYGBgDQoNClNlbGFpbiBpdHUsIHRlcmRhcGF0IGZ1bmdzaSBgeWFjX3N0cigpYCBwYWRhIHBhY2thZ2UgYFJ5YWNhc2AgdW50dWsgbWVuY2FyaSBpbnRlZ3JhbCB0YWsgdGVudHUuDQoNCkNvbnRvaCBkZW5nYW4gZnVuZ3NpIGB5YWNfc3RyYCBwYWRhIHBha2V0IGBSeWFjYXNgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbGlicmFyeShSeWFjYXMpDQpgYGANCg0KJFxiZWdpbnthbGlnbmVkfSBcaW50IHheMiArIDR4IGR4IFxlbmR7YWxpZ25lZH0kDQoNCmBgYHtyfQ0KeWFjX3N0cigiSW50ZWdyYXRlKHgpIHheMiArIDQqeCIpDQpgYGANCg0KIyBGdW5nc2ktZnVuZ3NpIFN0YXRpc3Rpa2E6U2ViYXJhbg0KDQpGdW5nc2kgc2ViYXJhbiBzdGF0aXN0aWsgc2VjYXJhIGtvbnZlbnNpOg0KDQotICAgZG5hbWFzZWJhcmFuOiBkZW5zaXR5IG9yIHByb2JhYmlsaXR5IG1hc3MgZnVuY3Rpb24gKHBtZikNCi0gICBwbmFtYXNlYmFyYW46IGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChjZGYpDQotICAgcW5hbWFzZWJhcmFuOiBxdWFudGlsZXMNCi0gICBybmFtYXNlYmFyYW46IHJhbmRvbSBudW1iZXIgZ2VuZXJhdGlvbg0KDQpEZW5nYW4gbmFtYSBzZWJhcmFuIGRhbiBwYXJhbWV0ZXIgZGFwYXQgZGlsaWhhdCBwYWRhIHRhYmVsIGJlcmlrdXQNCg0KfCBEaXN0cmlidXRpb24gICB8IE5hbWUgICAgICB8IFBhcmFtZXRlcnMgICAgICAgICAgfA0KfC0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBiZXRhICAgICAgICAgICB8IGBiZXRhYCAgICB8IHNoYXBlMSwgc2hhcGUyLCBuY3AgfA0KfCBiaW5vbWlhbCAgICAgICB8IGBiaW5vbWAgICB8IHNpemUsIHByb2IgICAgICAgICAgfA0KfCBDaGF1Y2h5ICAgICAgICB8IGBjYXVjaHlgICB8IGxvY2F0aW9uLCBzY2FsZSAgICAgfA0KfCBjaGktc3F1YXJlZCAgICB8IGBjaGlzcWAgICB8IGRmLCBuY3AgICAgICAgICAgICAgfA0KfCBleHBvbmVudGlhbCAgICB8IGBleHBgICAgICB8IHJhdGUgICAgICAgICAgICAgICAgfA0KfCBGICAgICAgICAgICAgICB8IGBmYCAgICAgICB8IGRmMSwgZGYyLCBuY3AgICAgICAgfA0KfCBnYW1tYSAgICAgICAgICB8IGBnYW1tYWAgICB8IHNoYXBlLCBzY2FsZSAgICAgICAgfA0KfCBnZW9tZXRyaWMgICAgICB8IGBnZW9tYCAgICB8IHByb2IgICAgICAgICAgICAgICAgfA0KfCBoeXBlcmdlb21ldHJpYyB8IGBoeXBlcmAgICB8IG0sIG4sIGsgICAgICAgICAgICAgfA0KfCBsb2ctbm9ybWFsICAgICB8IGBsbm9ybWAgICB8IG1lYW5sb2csIHNkbG9nICAgICAgfA0KfCBsb2dpc3RpYyAgICAgICB8IGBsb2dpc2AgICB8IGxvY2F0aW9uLCBzY2FsZSAgICAgfA0KfCB1bmlmb3JtICAgICAgICB8IGB1bmlmYCAgICB8IG1pbiwgbWF4ICAgICAgICAgICAgfA0KfCBuZWcgYmlub21pYWwgICB8IGBuYmlub21gICB8IHNpemUsIHByb2IgICAgICAgICAgfA0KfCBub3JtYWwgICAgICAgICB8IGBub3JtYCAgICB8IG1lYW4sIHNkICAgICAgICAgICAgfA0KfCBQb2lzc29uICAgICAgICB8IGBwb2lzYCAgICB8IGxhbWJkYSAgICAgICAgICAgICAgfA0KfCBTdHVkZW50J3MgdCAgICB8IGB0YCAgICAgICB8IGRmLCBuY3AgICAgICAgICAgICAgfA0KfCBXZWlidWxsICAgICAgICB8IGB3ZWlidWxsYCB8IHNoYXBlICAgICAgICAgICAgICAgfA0KfCBFbXBpcmljYWwgY2RmICB8IGBlY2RmYCAgICB8IFwtICAgICAgICAgICAgICAgICAgfA0KfCBCb3gtcGVyY2VudGlsZSB8IGBicHBsb3RgICB8IGxpc3Qgb2YgdmVjdG9yICAgICAgfA0KDQpiZXJpa3V0IGFkYWxhaCBjb250b2ggcGVuZ2d1bmFhbiBmdW5nc2kgc2ViYXJhbiBwYWRhIHNlYmFyYW4gbm9ybWFsIGJha3UuDQoNCmBgYHtyfQ0KZG5vcm0oMCxtZWFuPTAsc2Q9MSkNCnBub3JtKDAsbWVhbj0wLHNkPTEpDQpxbm9ybSgwLjUsbWVhbj0wLHNkPTEpDQp4IDwtIHJub3JtKDEwLG1lYW49MCxzZD0xKQ0KY2JpbmQobWVhbih4KSxzZCh4KSkNCmBgYA0KDQojIE9wdGltYXNpIE51bWVyaWsNCg0KQmViZXJhcGEgbWV0b2RlIHN0YXRpc3RpayBtZW5nZ3VuYWthbiBtZXRvZGUgcGVuZHVnYWFuIG5pbGFpIG9wdGltdW0gZGFyaSBzdWF0dSBmdW5nc2kgdHVqdWFuIHNlcGVydGkgZGVuZ2FuIG1ldG9kZSBrZW11bmdraW5hbiBtYWtzaW11bSAobWVtYWtzaW11bWthbiBsaWtlbGlob29kKSBkYW4gbWV0b2RlIGt1YWRyYXQgdGVya2VjaWwgKG1lbWluaW11bWthbiBKS0cpLg0KDQpNZW5kYXBhdGthbiBuaWxhaSBvcHRpbXVtIGRhcmkgc3VhdHUgZnVuZ3NpIG1lcnVwYWthbiBzdWF0dSB0ZWtuaWsgb3B0aW1hc2kgbnVtZXJpay4NCg0KQmViZXJhcGEgbWV0b2RlIHlhbmcgc3VkYWggZGlrZW1iYW5na2FuIGRpYW50YXJhbnlhOg0KDQojIyBHb2xkZW4gU2VjdGlvbiBTZWFyY2gNCg0KTWV0b2RlIGdvbGRlbiBzZWN0aW9uIHNlYXJjaCBkaWd1bmFrYW4gdW50dWsgbWVuY2FyaSBuaWxhaSBtaW5pbXVtIHN1YXR1IGZ1bmdzaSB5YW5nIGRpYmF0YXNpIGRhcmkgZHVhIGJ1YWggbmlsYWksIHlhaXR1IHNlYnVhaCBzZWxhbmcgKmEqIGRhbiAqYiouDQpBbGdvcml0bWEgdW50dWsgdGVrbmlrIGluaSBhZGFsYWggc2ViYWdhaSBiZXJpa3V0Og0KDQotICAgTXVsYWkgZGVuZ2FuIHNlbGFuZyBbYSxiXSB5YW5nIG1lbXVhdCBtaW5pbXVtDQotICAgUGVya2VjaWwgc2VsYW5nICRbYeKAmSwgYuKAmV0kIHlhbmcgbWVtdWF0IG1pbmltdW0NCi0gICBCZXJoZW50aSBzYW1wYWkgJHxi4oCZIC0gYeKAmXwkIGxlYmloIGtlY2lsIGRhcmkgbmlsYWkgdG9sZXJhbnNpDQoNClBlbWlsaWhhbiBuaWxhaSAkYSckIGRhbiAkYickLCBhZGFsYWggc2ViYWdhaSBiZXJpa3V0DQoNCi0gICBOaWxhaSBhbnRhcmEgW2EsYl0gbWVtaWxpa2kgc2lmYXQgZ29sZGVuIHJhdGlvDQoNCi0gICBUZW50dWthbiAkeF8xJCBkYW4gJHhfMiQNCg0KICAgICR4XzEgPSBiLShiLWEpL1xtYXRocm17Z29sZGVucmF0aW99JA0KDQogICAgJHhfMiA9IGErKGItYSkvXG1hdGhybXtnb2xkZW5yYXRpb30kDQoNCi0gICBIaXR1bmcgJGYoeF8xKSQgZGFuICRmKHhfMikkDQoNCi0gICBKaWthICRmKHhfMSkgPiBmKHhfMikkIG1ha2EgJFth4oCZLCBi4oCZXSA9IFt4XzEsIGJdJA0KDQotICAgSmlrYSAkZih4XzEpIDwgZih4XzIpJCBtYWthICRbYeKAmSwgYuKAmV0gPSBbYSwgeF8yXSQNCg0KRnVuZ3NpIGdvbGRlbiBzZWN0aW9uDQoNCmBgYHtyfQ0KZ29sZGVuIDwtIGZ1bmN0aW9uIChmLCBhLCBiLCB0b2w9MC4wMDAwMDAxKSB7DQogIHJhdGlvIDwtIDIgLyAoIHNxcnQgKDUpKzEpDQogIHgxIDwtIGItcmF0aW8gKiAoYi1hKQ0KICB4MiA8LSBhK3JhdGlvICogKGItYSkNCiAgZjEgPC0gZih4MSkNCiAgZjIgPC0gZih4MikNCiAgDQogIHdoaWxlICggYWJzIChiLWEpPnRvbCl7DQogICAgaWYgKGYyPmYxKXsNCiAgICAgIGIgPC0geDINCiAgICAgIHgyIDwtIHgxDQogICAgICBmMiA8LSBmMQ0KICAgICAgeDEgPC0gYi1yYXRpbyAqIChiLWEpDQogICAgICANCiAgICAgIGYxIDwtIGYoeDEpDQogICAgfSBlbHNlIHsNCiAgICAgICAgYSA8LSB4MQ0KICAgICAgICB4MSA8LSB4Mg0KICAgICAgICBmMSA8LSBmMg0KICAgICAgICB4MiA8LSBhK3JhdGlvICogKGItYSkNCiAgICAgICAgZjIgPC0gZih4MikNCiAgICB9DQogIH0NCiAgcmV0dXJuICgoYStiKSAvIDIpDQp9DQpgYGANCg0KQ29udG9oOg0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSB8eCAtMy41fCArKHgtMileMiBcZW5ke2FsaWduZWR9JA0KDQpgYGB7cn0NCiMgTWVtYnVhdCBmdW5nc2kgZih4KQ0KZiA8LSBmdW5jdGlvbih4KSB7YWJzKHgtMy41KSsoeC0yKV4yfQ0KDQojIE1lbWJ1YXQgcGxvdA0KY3VydmUoZiwgMSw1KQ0KYGBgDQoNCmBgYHtyfQ0KIyBNZW5naGl0dW5nIG5pbGFpIG9wdGltdW0NCmdvbGRlbihmLDEsMikNCmdvbGRlbihmLDEsNSkNCmdvbGRlbihmLDMsNSkNCmdvbGRlbihmLDIsMykNCmBgYA0KDQojIyBOZXd0b24gUmFwaHNvbg0KDQpKaWthIHN1YXR1IGZ1bmdzaSBtZW1pbGlraSB0dXJ1bmFuIHBlcnRhbWEgZGFuIGtlZHVhLCBtYWthIG5pbGFpIG1pbmltdW0gZGFwYXQgbWVuZ2d1bmFrYW4gbWV0b2RlIE5ld3RvbiBSYXBoc29uLg0KS2VsZWJpaGFuIG1ldG9kZSBpbmkgYWRhbGFoIGhhbnlhIG1lbWVybHVrYW4gc2F0dSBuaWxhaSB1bnR1ayBpbmlzaWFsLg0KS2VsZW1haGFubnlhIGFkYWxhaCBraXRhIGhhcnVzIHlha2luIGYoeCkgbWVtaWxpa2kgdHVydW5hbiBwZXJ0YW1hIGRhbiB0dXJ1bmFuIGtlZHVhLg0KSmlrYSBkaSBnb2xkZW4gc2VjdGlvbiB0aWRhayBwZXJsdSBhZGEgdHVydW5hbiBwZXJ0YW1hIGRhbiB0dXJ1bmFuIGtlZHVhLg0KDQpGdW5nc2kgTmV3dG9uIFJhcGhzb24NCg0KYGBge3J9DQpuZXd0b25yIDwtIGZ1bmN0aW9uIChmeCAsIHgwID0xKXsNCiAgZngxIDwtIGRlcml2IChmeCAsIngiKSAjIHR1cnVuYW4gcGVydGFtYQ0KICBmeDIgPC0gZGVyaXYgKEQoZnggLCJ4IiksIngiKSAjIHR1cnVuYW4ga2VkdWENCiAgZXIgPC0gMTAwMA0KICANCiAgd2hpbGUoZXIgPiAxZS02KXsNCiAgICB4IDwtIHgwDQogICAgZjEgPC0gYXR0ciAoIGV2YWwgKGZ4MSksImdyYWRpZW50IilbMV0NCiAgICBmMiA8LSBhdHRyICggZXZhbCAoZngyKSwiZ3JhZGllbnQiKVsxXQ0KICAgIGVyIDwtIGFicyhmMSkgIyBiaXNhIGp1Z2EgZSA8LSBhYnMgKHgxIC14MCkNCiAgICB4MSA8LSB4MCAtIGYxL2YyDQogICAgeDAgPC0geDENCiAgfQ0KICByZXR1cm4gKHgxKQ0KfQ0KYGBgDQoNCkhpdHVuZyBuaWxhaSBtaW5pbXVtIHVudHVrIGZ1bmdzaS0gZnVuZ3NpIGJlcmlrdXQuDQoNCiRcYmVnaW57YWxpZ25lZH0gZih4KSA9IDR4XjIgLSAzeCAtIDcgXGVuZHthbGlnbmVkfSQNCg0KYGBge3J9DQpmeCA8LSBleHByZXNzaW9uKDQqeF4yLTMqeC03KQ0KbmV3dG9ucihmeCwzKQ0KYGBgDQoNCiRcYmVnaW57YWxpZ25lZH0gZih4KSA9IGVeey14fSt4XjQgXGVuZHthbGlnbmVkfSQNCg0KYGBge3J9DQpmeCA8LSBleHByZXNzaW9uKGV4cCgteCkreF40KQ0KbmV3dG9ucihmeCkNCm5ld3RvbnIoZngsMSkNCmBgYA0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSB4XjIgLSB4IFxlbmR7YWxpZ25lZH0kDQoNCmBgYHtyfQ0KZnggPC0gZXhwcmVzc2lvbih4XjIteCkNCm5ld3RvbnIoZngpDQpgYGANCg0KIyMgRnVuZ3NpIE9wdGltYXNpIEJ1aWx0LWluDQoNCkFsZ29yaXRtYSAqTmVsZGVyIE1lYWQqIGFkYWxhaCBzYWxhaCBzYXR1IG1ldG9kZSBvcHRpbWFzaSB1bnR1ayBmdW5nc2kgeWFuZyBtZW1pbGlraSBsZWJpaCBkYXJpIHNhdHUgdmFyaWFiZWwuDQpSIHRlbGFoIG1lbnlpYXBrYW4gZnVuZ3NpIG9wdGltYXNpIGRlbmdhbiBzYWxhaCBzYXR1IGFsZ29yaXRtYW55YSBhZGFsYWggTmVsZGVyLU1lYWQ6DQoNCi0gICBgb3B0aW1pemVgIGF0YXUgYG9wdGltaXNlYCB1bnR1ayBtZW5kdWdhIHBhcmFtZXRlci8gbWVuY2FyaSBuaWxhaSBtaW5pbXVtIGRhcmkgc2F0dSBwZXViYWgNCi0gICBgb3B0aW1gIHVudHVrIGxlYmloIGRhcmkgc2F0dSBwZXViYWgNCg0KIyMjIEZ1bmdzaSBvcHRpbWl6ZS9vcHRpbWlzZQ0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSBcbGVmdCggeCAtIFxmcmFjezF9ezN9IFxyaWdodCleMiBcZW5ke2FsaWduZWR9JA0KDQpgYGB7cn0NCmYgPC0gZnVuY3Rpb24oeCkgKCh4LSgxLzMpKV4yKSAjIG1lbWJ1YXQgZnVuZ3NpIHR1anVhbg0KY3VydmUoZikNCmBgYA0KDQpgYGB7cn0NCnhtaW4gPC0gb3B0aW1pemUoZiwgYygwLDEpLCB0b2wgPSAwLjAwMDEpICMgdG9sZXJhbmNlIG9wdGlvbmFsDQp4bWluDQpgYGANCg0KIyMjIEZ1bmdzaSBvcHRpbQ0KDQpEaWd1bmFrYW4gdW50dWsgbWVuY2FyaSBuaWxhaSBtaW5pbXVtIGRhcmkgZnVuZ3NpIHlhbmcgbGViaWggZGFyaSBzYXR1IHBldWJhaC4NCkNvbnRvaCBtZW5jYXJpIG5pbGFpICR4XzEkIGRhbiAkeF8yJCwgeWFuZyBtZWJ1YXQgJGYoeF8xLHhfMikgPSAxMDAoeF8yIC0geF8xXjIpXjIgKyAoMS14XzEpXjIkIG1pbmltdW0NCg0KUHJvZ3JhbSB5YW5nIGRpZ3VuYWthbjoNCg0KYGBge3J9DQpmciA8LSBmdW5jdGlvbiAoeCl7ICMgdGV0YXAgZGl0dWxpc2thbiBkYWxhbSBzZWJ1YWggdmVrdG9yLCBha2FuIGRpZHVnYSB4DQogIHgxPC0geFsxXQ0KICB4MiA8LSB4WzJdDQogIDEwMCAqICh4Mi14MV4yKV4yICsgKDEteDEpXjIgIyBpbmkgYWRhbGFoIG5pbGFpIGZ1bmdzaSBvYmpldGl2ZW55YQ0KfSANCg0KIyBhcmd1bWVuIHBlcnRhbWEgYWRhbGFoIG5pbGFpIGluaXNpYWwsIGthcmVuYSBtZW5kdWdhIHggdmVrdG9yIGJlcnVrdXJhbiAyIG1ha2EgZGltYXN1a2thbiBuaWxhaSBpbmlzaWFsbnlhDQpvcHRpbSAoYygtMS4yLDEpLGZyKSANCmBgYA0K