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

union(x,y)
[1] 1 6 3 5 8 9 4

intersect(x,y)

digunakan untuk mendapatkan anggota x yang juga anggota y

intersect(x,y)
[1] 1 5

setdiff(x,y)

digunakan untuk mendapatkan anggota x yang bukan anggota y

x;y
[1] 1 6 3 6 5
[1] 8 9 5 1 4
setdiff(x,y)
[1] 6 3
setdiff(y,x)
[1] 8 9 4

setequal(x,y)

digunakan untuk mengetahui apakah semua anggota x dan y sama

setequal(x,y)
[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

x; y
[1] 1 6 3 6 5
[1] 8 9 5 1 4
c(1,2,3) %in% x
[1]  TRUE FALSE  TRUE
7 %in% y
[1] FALSE
x %in% y
[1]  TRUE FALSE FALSE FALSE  TRUE

choose(n,k)

digunakan untuk mengetahui banyaknya kombinasi k dari n

choose(5,3)
[1] 10

combn(n,k)

digunakan untuk mendapatkan matriks semua kemungkinan kombinasi k dari n

combn(5,3)
     [,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)

exp(8)
[1] 2980.958
exp(1)
[1] 2.718282
exp(1)^8
[1] 2980.958

log()

digunakan untuk mendapatkan nilai logaritma dengan basis natural (ln)

log(100)
[1] 4.60517

log10()

digunakan untuk mendapatkan nilai logaritma dengan basis 10

log10(100)
[1] 2

sqrt()

digunakan untuk mendapatkan nilai akar kuadrat

sqrt(x)
[1] 1.000000 2.449490 1.732051 2.449490 2.236068
sqrt(100)
[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

sin(0)
[1] 0
cos(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
floor(y2) 
[1] 2 3 4 5
ceiling(y2) 
[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)

factorial(5)
[1] 120
5*4*3*2*1
[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

min(a)
[1] 1
max(a)
[1] 8

which

mendapatkan index vektor yang memenuhi kriteria tertentu

a
 [1] 4 5 6 2 1 3 5 4 8 3
which(a>4)
[1] 2 3 7 9

which.min() : mendapatkan index vektor untuk nilai minimum

which.max(): mendapatkan index vektor untuk nilai maksimum

a
 [1] 4 5 6 2 1 3 5 4 8 3
which.min(a)
[1] 5
which.max(a)
[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
b
 [1] 2 1 8 7 8 2 8 6 3 2
pmin(a,b)
 [1] 2 1 6 2 1 2 5 4 3 2
pmax(a,b)
 [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

a
 [1] 4 5 6 2 1 3 5 4 8 3
sum(a)
[1] 41
prod(a)
[1] 345600

cumsum() and cumprod()

jumlah dan perkalian kumulatif dari elemen suatu vektor

a
 [1] 4 5 6 2 1 3 5 4 8 3
cumsum(a)
 [1]  4  9 15 17 18 21 26 30 38 41
cumprod(a)
 [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
xturunan
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

library(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

Distribution Name Parameters
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.

dnorm(0,mean=0,sd=1)
[1] 0.3989423
pnorm(0,mean=0,sd=1)
[1] 0.5
qnorm(0.5,mean=0,sd=1)
[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:

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
newtonr(fx,1)
[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

  1. Mahasiswa Statistika dan Sains Data IPB, ↩︎

LS0tDQp0aXRsZTogIkZ1bmdzaS1mdW5nc2kgTWF0ZW1hdGlrIGRhbiBTdGF0aXN0aWsiDQphdXRob3I6ICJBbm5pc3NhIE51ciBGaXRyaWEgRmF0aGluYV5bTWFoYXNpc3dhIFN0YXRpc3Rpa2EgZGFuIFNhaW5zIERhdGEgSVBCLCBhbm5pc3NhX25mZkBhcHBzLmlwYi5hYy5pZF0iDQpkYXRlOiAiMS80LzIwMjIiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAzDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiBoYWRkb2NrDQplZGl0b3Jfb3B0aW9uczogDQogIG1hcmtkb3duOiANCiAgICB3cmFwOiBzZW50ZW5jZQ0KLS0tDQoNCiMgSGltcHVuYW4NCg0KUiBtZW1pbGlraSBmdW5nc2ktZnVuZ3NpIGhpbXB1bmFuIHlhbmcgZGl0ZXJhcGthbiBwYWRhIHZla3Rvci4NCk1pc2Fsa2FuIHBhZGEgdmVrdG9yIHggZGFuIHkgYmVyaWt1dC4NCg0KYGBge3J9DQp4IDwtIGMoMSw2LDMsNiw1KQ0KeSA8LSBjKDgsOSw1LDEsNCkNCmBgYA0KDQojIyB1bmlvbih4LHkpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSB1bmlrIGRhcmkgYW5nZ290YSB4IGRhbiB5DQoNCmBgYHtyfQ0KdW5pb24oeCx5KQ0KYGBgDQoNCiMjIGludGVyc2VjdCh4LHkpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBhbmdnb3RhIHggeWFuZyBqdWdhIGFuZ2dvdGEgeQ0KDQpgYGB7cn0NCmludGVyc2VjdCh4LHkpDQpgYGANCg0KIyMgc2V0ZGlmZih4LHkpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBhbmdnb3RhIHggeWFuZyBidWthbiBhbmdnb3RhIHkNCg0KYGBge3J9DQp4O3kNCnNldGRpZmYoeCx5KQ0Kc2V0ZGlmZih5LHgpDQpgYGANCg0KIyMgc2V0ZXF1YWwoeCx5KQ0KDQpkaWd1bmFrYW4gdW50dWsgbWVuZ2V0YWh1aSBhcGFrYWggc2VtdWEgYW5nZ290YSB4IGRhbiB5IHNhbWENCg0KYGBge3J9DQpzZXRlcXVhbCh4LHkpDQpgYGANCg0KYGBge3J9DQojIGNvbnRvaCBrZXRpa2EgeCBkYW4geSBtZW1pbGlraSBhbmdnb3RhIHlhbmcgc2FtYQ0KeDEgPC0gYygxLDIsMyw0LDUsMywyLDEpDQp5MSA8LSBjKDUsNCwzLDIsMSkNCnNldGVxdWFsKHgxLHkxKQ0KYGBgDQoNCmp1bWxhaCBlbGVtZW4gZGFuIHVydXRhbiB0aWRhayBiZXJwZW5nYXJ1aCwgeWFuZyBkaWNlayBpYWxhaCBuaWxhaSB1bmlrIGRhcmkgc2V0aWFwIGVsZW1lbiBwYWRhIGtlZHVhIHZla3Rvci4NCg0KIyMgYyAlaW4lIHkNCg0KZGlndW5ha2FuIHVudHVrIG1lbmdldGFodWkgYXBha2FoIGFuZ2dvdGEgdmVrdG9yIGMgYWRhIGRpIHkNCg0KYGBge3J9DQp4OyB5DQpjKDEsMiwzKSAlaW4lIHgNCjcgJWluJSB5DQp4ICVpbiUgeQ0KYGBgDQoNCiMjIGNob29zZShuLGspDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5nZXRhaHVpIGJhbnlha255YSBrb21iaW5hc2kgayBkYXJpIG4NCg0KYGBge3J9DQpjaG9vc2UoNSwzKQ0KYGBgDQoNCiMjIGNvbWJuKG4saykNCg0KZGlndW5ha2FuIHVudHVrIG1lbmRhcGF0a2FuIG1hdHJpa3Mgc2VtdWEga2VtdW5na2luYW4ga29tYmluYXNpIGsgZGFyaSBuDQoNCmBgYHtyfQ0KY29tYm4oNSwzKQ0KYGBgDQoNCiMgRnVuZ3NpLWZ1bmdzaSBNYXRlbWF0aWthDQoNCiMjIEZ1bmdzaS1mdW5nc2kgTWF0ZW1hdGlrYSBVbXVtDQoNCiMjIyBleHAoKQ0KDQpmdW5nc2kgZWtzcG9uZW5zaWFsIGRlbmdhbiBiYXNpcyBuYXR1cmFsIChlKQ0KDQpgYGB7cn0NCmV4cCg4KQ0KZXhwKDEpDQpleHAoMSleOA0KYGBgDQoNCiMjIyBsb2coKQ0KDQpkaWd1bmFrYW4gdW50dWsgbWVuZGFwYXRrYW4gbmlsYWkgbG9nYXJpdG1hIGRlbmdhbiBiYXNpcyBuYXR1cmFsIChsbikNCg0KYGBge3J9DQpsb2coMTAwKQ0KYGBgDQoNCiMjIyBsb2cxMCgpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSBsb2dhcml0bWEgZGVuZ2FuIGJhc2lzIDEwDQoNCmBgYHtyfQ0KbG9nMTAoMTAwKQ0KYGBgDQoNCiMjIyBzcXJ0KCkNCg0KZGlndW5ha2FuIHVudHVrIG1lbmRhcGF0a2FuIG5pbGFpIGFrYXIga3VhZHJhdA0KDQpgYGB7cn0NCnNxcnQoeCkNCnNxcnQoMTAwKQ0KYGBgDQoNCiMjIyBhYnMoKQ0KDQpkaWd1bmFrYW4gdW50dWsgbWVuZGFwYXRrYW4gbmlsYWkgbmlsYWkgYWJzb2x1dCAvIG5pbGFpIG11dGxha255YQ0KDQpgYGB7cn0NCngyIDwtIGMoLTEsMiwtMyw0LC01KQ0KYWJzKHgyKQ0KYGBgDQoNCiMjIyBGdW5nc2kgVHJpZ29ub21ldHJpDQoNCkJlcmlrdXQgYWRhbGFoIGJlYmVyYXBhIGZ1bmdzaSB0cmlnb25vbWV0cmkNCg0KYGBge3J9DQpzaW4oMCkNCmNvcygwKQ0KYGBgDQoNCmZ1bmdzaSBkaSBhdGFzIGRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSBzaW51cyBkYW4gY29zaW51cy4NCg0KIyMjIEZ1bmdzaS1mdW5nc2kgQmlsYW5nYW4gSW50ZWdlcg0KDQpCZXJpa3V0IGFkYWxhaCBiZWJlcmFwYSBmdW5nc2kgcGVtYnVsYXRhbiBiaWxhbmdhbiBhZ2FyIG1lbmphZGkgYmlsYW5nYW4gaW50ZWdlci4NCg0KYGBge3J9DQp5MiA8LSBjKDIuNCwgMy42LCA0LjUsIDUuNSkNCnJvdW5kKHkyKQ0KZmxvb3IoeTIpIA0KY2VpbGluZyh5MikgDQpgYGANCg0KUGVyYmVkYWFuIHBhZGEgcGVuZ2d1bmFhbiBmdW5nc2ktZnVuZ3NpIGRpIGF0YXMgeWFpdHU6DQoNCi0gICBgcm91bmQoKWAgbWVtaWxpa2kgaGFzaWwgeWFuZyBzYW1hIHNlcGVydGkgcGVtYnVsYXRhbiBiaWFzYSBkaW1hbmE6DQotICAgYmlsYSBuaWxhaSBrb21hIFw+IDAuNSBtYWthIGJpbGFuZ2FuIGFrYW4gZGlidWxhdGthbiBrZSBhdGFzLg0KLSAgIGJpbGEgbmlsYWkga29tYSBcPCAwLjUgbWFrYSBiaWxhbmdhbiBha2FuIGRpYnVsYXRrYW4ga2UgYmF3YWguDQotICAgYmlsYSBuaWxhaSBrb21hID0gMC41IGRhbiBiaWxhbmdhbiBpbnRlZ2VybnlhIGJlcm5pbGFpIGdlbmFwIG1ha2EgYmlsYW5nYW4gYWthbiBkaWJ1bGF0a2FuIGtlIGJhd2FoLg0KLSAgIGJpbGEgbmlsYWkga29tYSA9IDAuNSBkYW4gYmlsYW5nYW4gaW50ZWdlcm55YSBiZXJuaWxhaSBnYW5qaWwgbWFrYSBiaWxhbmdhbiBha2FuIGRpYnVsYXRrYW4ga2UgYXRhcy4NCi0gICBgZmxvb3IoKWA6IHBlbWJ1bGF0YW4ga2UgYmF3YWggKGhhbnlhIG1lbmdhbWJpbCBuaWxhaSBpbnRlZ2VybnlhIHNhamEpLg0KLSAgIGBjZWlsaW5nKClgOiBwZW1idWxhdGFuIGtlIGF0YXMNCg0KIyMjIGZhY3RvcmlhbCgpDQoNCmZ1bmdzaSBmYWt0b3JpYWwgKGBuIT1ueChuLTEpeChuLTIpeOKApngxYCkNCg0KYGBge3J9DQpmYWN0b3JpYWwoNSkNCjUqNCozKjIqMQ0KYGBgDQoNCiMjIEZ1bmdzaS1mdW5nc2kgTGFpbg0KDQpUZXJkYXBhdCBwdWxhIGJlYmVyYXBhIGZ1bmdzaSB1bXVtIHlhbmcgc2VyaW5nIGRpZ3VuYWthbiwgYmVyaWt1dCBhZGFsYWggY29udG9oIHBlbmdndW5hYW4gZnVuZ3NpIHVtdW0gcGFkYSBzdWF0dSB2ZWt0b3IgYS4NCg0KYGBge3J9DQphIDwtIGMoNCw1LDYsMiwxLDMsNSw0LDgsMykNCmBgYA0KDQojIyMgbWluKCkgYW5kIG1heCgpDQoNCmRpZ3VuYWthbiB1bnR1ayBtZW5kYXBhdGthbiBuaWxhaSBtaW5pbXVtIGRhbiBtYWtzaW11bSBkYXJpIHN1YXR1IHZla3Rvcg0KDQpgYGB7cn0NCm1pbihhKQ0KbWF4KGEpDQpgYGANCg0KIyMjIHdoaWNoDQoNCm1lbmRhcGF0a2FuIGluZGV4IHZla3RvciB5YW5nIG1lbWVudWhpIGtyaXRlcmlhIHRlcnRlbnR1DQoNCmBgYHtyfQ0KYQ0Kd2hpY2goYT40KQ0KYGBgDQoNCmB3aGljaC5taW4oKWAgOiBtZW5kYXBhdGthbiBpbmRleCB2ZWt0b3IgdW50dWsgbmlsYWkgbWluaW11bQ0KDQpgd2hpY2gubWF4KClgOiBtZW5kYXBhdGthbiBpbmRleCB2ZWt0b3IgdW50dWsgbmlsYWkgbWFrc2ltdW0NCg0KYGBge3J9DQphDQp3aGljaC5taW4oYSkNCndoaWNoLm1heChhKQ0KYGBgDQoNCiMjIyBwbWluKCkgYW5kIHBtYXgoKQ0KDQplbGVtZW50LXdpc2UgbWluaW11bSBkYW4gbWFrc2ltdW0gZGFyaSBzdWF0dSB2ZWt0b3INCg0KYGBge3J9DQpiIDwtIGMoMiwxLDgsNyw4LDIsOCw2LDMsMikNCmENCmINCnBtaW4oYSxiKQ0KcG1heChhLGIpDQpgYGANCg0KYGBge3J9DQpuaWxhaTEgPC0gcm91bmQocm5vcm0oMTAsNzAsNSksMikNCm5pbGFpMiA8LSByb3VuZChybm9ybSgxMCw4MCw3KSwyKQ0KZGF0YS5uaWxhaSA8LSBkYXRhLmZyYW1lKG5pbGFpMSxuaWxhaTIsbmlsYWkubWFrc2ltdW09cG1heChuaWxhaTEsbmlsYWkyKSkNCmRhdGEubmlsYWkNCmBgYA0KDQojIyMgc3VtKCkgYW5kIHByb2QoKQ0KDQpqdW1sYWggZGFuIHBlcmthbGlhbiBlbGVtZW4gc3VhdHUgdmVrdG9yDQoNCmBgYHtyfQ0KYQ0Kc3VtKGEpDQpwcm9kKGEpDQpgYGANCg0KIyMjIGN1bXN1bSgpIGFuZCBjdW1wcm9kKCkNCg0KanVtbGFoIGRhbiBwZXJrYWxpYW4ga3VtdWxhdGlmIGRhcmkgZWxlbWVuIHN1YXR1IHZla3Rvcg0KDQpgYGB7cn0NCmENCmN1bXN1bShhKQ0KY3VtcHJvZChhKQ0KYGBgDQoNCiMjIEZ1bmdzaSBLYWxrdWx1czogRGlmZXJlbnNpYWwNCg0KUiBtZW1pbGlraSBmdW5nc2ktZnVuZ3NpIHVudHVrIG1lbmRhcGF0a2FuIHR1cnVuYW4gZGFyaSBzdWF0dSBmdW5nc2kuDQpGdW5nc2kgeWFuZyBkaWd1bmFrYW4gbWVydXBha2FuIGZ1bmdzaSBkZW5nYW4gc2F0dSBwZXViYWguDQoNCiMjIyBEDQoNCmBEKGV4cHIsc2ltYm9sKWAgZGlndW5ha2FuIGppa2EgaGFzaWwgdHVydW5hbiBtZXJ1cGFrYW4gc3VhdHUgZnVuZ3NpLg0KU2ViYWdhaSBjb250b2ggYWthbiBkaWNhcmkgdHVydW5hbiBkYXJpIGZ1bmdzaSBiZXJpa3V0Lg0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSBlXnsoeF4yKX0gXGVuZHthbGlnbmVkfSQNCg0KYGBge3J9DQp4ZnMgPC0gZXhwcmVzc2lvbihleHAoeF4yKSkNCkQoeGZzLCJ4IikNCmBgYA0KDQojIyMgZGVyaXYNCg0KYGRlcml2KOKIvGZ1bmdzaSxzaW1ib2wpYCBkaWd1bmFrYW4gamlrYSBha2FuIG1lbWFzdWtrYW4gbmlsYWkgZGFyaSBoYXNpbCB0dXJ1bmFuIHBhZGEgc3VhdHUgZnVuZ3NpLg0KU2ViYWdhaSBjb250b2ggYWthbiBkaWNhcmkgdHVydW5hbiBkYXJpIGZ1bmdzaSBiZXJpa3V0DQoNCiRcYmVnaW57YWxpZ25lZH0gZih4KSA9IHheMiBcZW5ke2FsaWduZWR9JA0KDQp1bnR1ayBuaWxhaSAkeD0zJA0KDQpgYGB7cn0NCnh0dXJ1bmFuIDwtIGRlcml2KH54XjIsICJ4IikNCng8LTMNCmV2YWwoeHR1cnVuYW4pDQoNCmBgYA0KDQpgYGB7cn0NCnh0dXJ1bmFuDQpgYGANCg0KIyMgRnVuZ3NpIEthbGt1bHVzOiBJbnRlZ3JhbA0KDQpTZWxhaW4gdHVydW5hbiBwYWRhIGZ1bmdzaSBzZWRlcmhhbmEsIFIganVnYSBtZW1pbGlraSBmdW5nc2kgdW50dWsgbWVuZGFwYXRrYW4gbHVhcyB3aWxheWFoIHN1YXR1IGZ1bmdzaSBkZW5nYW4gaW50ZWdyYWwgYGludGVncmF0ZShmdW5nc2ksIGxvd2VyLCB1cHBlcilgDQoNCmBgYHtyfQ0KZnMgPC0gZnVuY3Rpb24oeCkgeF4yDQppbnRlZ3JhdGUoZnMsMCwxKQ0KZnNpIDwtIGZ1bmN0aW9uKHgpIDEvMyp4XjMNCmZzaSgxKSAtIGZzaSgwKQ0KYGBgDQoNClNlbGFpbiBpdHUsIHRlcmRhcGF0IGZ1bmdzaSBgeWFjX3N0cigpYCBwYWRhIHBhY2thZ2UgYFJ5YWNhc2AgdW50dWsgbWVuY2FyaSBpbnRlZ3JhbCB0YWsgdGVudHUuDQoNCkNvbnRvaCBkZW5nYW4gZnVuZ3NpIGB5YWNfc3RyYCBwYWRhIHBha2V0IGBSeWFjYXNgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbGlicmFyeShSeWFjYXMpDQpgYGANCg0KJFxiZWdpbnthbGlnbmVkfSBcaW50IHheMiArIDR4IGR4IFxlbmR7YWxpZ25lZH0kDQoNCmBgYHtyfQ0KeWFjX3N0cigiSW50ZWdyYXRlKHgpIHheMiArIDQqeCIpDQpgYGANCg0KIyBGdW5nc2ktZnVuZ3NpIFN0YXRpc3Rpa2E6U2ViYXJhbg0KDQpGdW5nc2kgc2ViYXJhbiBzdGF0aXN0aWsgc2VjYXJhIGtvbnZlbnNpOg0KDQotICAgZG5hbWFzZWJhcmFuOiBkZW5zaXR5IG9yIHByb2JhYmlsaXR5IG1hc3MgZnVuY3Rpb24gKHBtZikNCi0gICBwbmFtYXNlYmFyYW46IGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChjZGYpDQotICAgcW5hbWFzZWJhcmFuOiBxdWFudGlsZXMNCi0gICBybmFtYXNlYmFyYW46IHJhbmRvbSBudW1iZXIgZ2VuZXJhdGlvbg0KDQpEZW5nYW4gbmFtYSBzZWJhcmFuIGRhbiBwYXJhbWV0ZXIgZGFwYXQgZGlsaWhhdCBwYWRhIHRhYmVsIGJlcmlrdXQNCg0KfCBEaXN0cmlidXRpb24gICB8IE5hbWUgICAgICB8IFBhcmFtZXRlcnMgICAgICAgICAgfA0KfC0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBiZXRhICAgICAgICAgICB8IGBiZXRhYCAgICB8IHNoYXBlMSwgc2hhcGUyLCBuY3AgfA0KfCBiaW5vbWlhbCAgICAgICB8IGBiaW5vbWAgICB8IHNpemUsIHByb2IgICAgICAgICAgfA0KfCBDaGF1Y2h5ICAgICAgICB8IGBjYXVjaHlgICB8IGxvY2F0aW9uLCBzY2FsZSAgICAgfA0KfCBjaGktc3F1YXJlZCAgICB8IGBjaGlzcWAgICB8IGRmLCBuY3AgICAgICAgICAgICAgfA0KfCBleHBvbmVudGlhbCAgICB8IGBleHBgICAgICB8IHJhdGUgICAgICAgICAgICAgICAgfA0KfCBGICAgICAgICAgICAgICB8IGBmYCAgICAgICB8IGRmMSwgZGYyLCBuY3AgICAgICAgfA0KfCBnYW1tYSAgICAgICAgICB8IGBnYW1tYWAgICB8IHNoYXBlLCBzY2FsZSAgICAgICAgfA0KfCBnZW9tZXRyaWMgICAgICB8IGBnZW9tYCAgICB8IHByb2IgICAgICAgICAgICAgICAgfA0KfCBoeXBlcmdlb21ldHJpYyB8IGBoeXBlcmAgICB8IG0sIG4sIGsgICAgICAgICAgICAgfA0KfCBsb2ctbm9ybWFsICAgICB8IGBsbm9ybWAgICB8IG1lYW5sb2csIHNkbG9nICAgICAgfA0KfCBsb2dpc3RpYyAgICAgICB8IGBsb2dpc2AgICB8IGxvY2F0aW9uLCBzY2FsZSAgICAgfA0KfCB1bmlmb3JtICAgICAgICB8IGB1bmlmYCAgICB8IG1pbiwgbWF4ICAgICAgICAgICAgfA0KfCBuZWcgYmlub21pYWwgICB8IGBuYmlub21gICB8IHNpemUsIHByb2IgICAgICAgICAgfA0KfCBub3JtYWwgICAgICAgICB8IGBub3JtYCAgICB8IG1lYW4sIHNkICAgICAgICAgICAgfA0KfCBQb2lzc29uICAgICAgICB8IGBwb2lzYCAgICB8IGxhbWJkYSAgICAgICAgICAgICAgfA0KfCBTdHVkZW50J3MgdCAgICB8IGB0YCAgICAgICB8IGRmLCBuY3AgICAgICAgICAgICAgfA0KfCBXZWlidWxsICAgICAgICB8IGB3ZWlidWxsYCB8IHNoYXBlICAgICAgICAgICAgICAgfA0KfCBFbXBpcmljYWwgY2RmICB8IGBlY2RmYCAgICB8IFwtICAgICAgICAgICAgICAgICAgfA0KfCBCb3gtcGVyY2VudGlsZSB8IGBicHBsb3RgICB8IGxpc3Qgb2YgdmVjdG9yICAgICAgfA0KDQpiZXJpa3V0IGFkYWxhaCBjb250b2ggcGVuZ2d1bmFhbiBmdW5nc2kgc2ViYXJhbiBwYWRhIHNlYmFyYW4gbm9ybWFsIGJha3UuDQoNCmBgYHtyfQ0KZG5vcm0oMCxtZWFuPTAsc2Q9MSkNCnBub3JtKDAsbWVhbj0wLHNkPTEpDQpxbm9ybSgwLjUsbWVhbj0wLHNkPTEpDQp4IDwtIHJub3JtKDEwLG1lYW49MCxzZD0xKQ0KY2JpbmQobWVhbih4KSxzZCh4KSkNCmBgYA0KDQojIE9wdGltYXNpIE51bWVyaWsNCg0KQmViZXJhcGEgbWV0b2RlIHN0YXRpc3RpayBtZW5nZ3VuYWthbiBtZXRvZGUgcGVuZHVnYWFuIG5pbGFpIG9wdGltdW0gZGFyaSBzdWF0dSBmdW5nc2kgdHVqdWFuIHNlcGVydGkgZGVuZ2FuIG1ldG9kZSBrZW11bmdraW5hbiBtYWtzaW11bSAobWVtYWtzaW11bWthbiBsaWtlbGlob29kKSBkYW4gbWV0b2RlIGt1YWRyYXQgdGVya2VjaWwgKG1lbWluaW11bWthbiBKS0cpLg0KDQpNZW5kYXBhdGthbiBuaWxhaSBvcHRpbXVtIGRhcmkgc3VhdHUgZnVuZ3NpIG1lcnVwYWthbiBzdWF0dSB0ZWtuaWsgb3B0aW1hc2kgbnVtZXJpay4NCg0KQmViZXJhcGEgbWV0b2RlIHlhbmcgc3VkYWggZGlrZW1iYW5na2FuIGRpYW50YXJhbnlhOg0KDQojIyBHb2xkZW4gU2VjdGlvbiBTZWFyY2gNCg0KTWV0b2RlIGdvbGRlbiBzZWN0aW9uIHNlYXJjaCBkaWd1bmFrYW4gdW50dWsgbWVuY2FyaSBuaWxhaSBtaW5pbXVtIHN1YXR1IGZ1bmdzaSB5YW5nIGRpYmF0YXNpIGRhcmkgZHVhIGJ1YWggbmlsYWksIHlhaXR1IHNlYnVhaCBzZWxhbmcgKmEqIGRhbiAqYiouDQpBbGdvcml0bWEgdW50dWsgdGVrbmlrIGluaSBhZGFsYWggc2ViYWdhaSBiZXJpa3V0Og0KDQotICAgTXVsYWkgZGVuZ2FuIHNlbGFuZyBbYSxiXSB5YW5nIG1lbXVhdCBtaW5pbXVtDQotICAgUGVya2VjaWwgc2VsYW5nICRbYeKAmSwgYuKAmV0kIHlhbmcgbWVtdWF0IG1pbmltdW0NCi0gICBCZXJoZW50aSBzYW1wYWkgJHxi4oCZIC0gYeKAmXwkIGxlYmloIGtlY2lsIGRhcmkgbmlsYWkgdG9sZXJhbnNpDQoNClBlbWlsaWhhbiBuaWxhaSAkYSckIGRhbiAkYickLCBhZGFsYWggc2ViYWdhaSBiZXJpa3V0DQoNCi0gICBOaWxhaSBhbnRhcmEgW2EsYl0gbWVtaWxpa2kgc2lmYXQgZ29sZGVuIHJhdGlvDQoNCi0gICBUZW50dWthbiAkeF8xJCBkYW4gJHhfMiQNCg0KICAgICR4XzEgPSBiLShiLWEpL1xtYXRocm17Z29sZGVucmF0aW99JA0KDQogICAgJHhfMiA9IGErKGItYSkvXG1hdGhybXtnb2xkZW5yYXRpb30kDQoNCi0gICBIaXR1bmcgJGYoeF8xKSQgZGFuICRmKHhfMikkDQoNCi0gICBKaWthICRmKHhfMSkgPiBmKHhfMikkIG1ha2EgJFth4oCZLCBi4oCZXSA9IFt4XzEsIGJdJA0KDQotICAgSmlrYSAkZih4XzEpIDwgZih4XzIpJCBtYWthICRbYeKAmSwgYuKAmV0gPSBbYSwgeF8yXSQNCg0KRnVuZ3NpIGdvbGRlbiBzZWN0aW9uDQoNCmBgYHtyfQ0KZ29sZGVuIDwtIGZ1bmN0aW9uIChmLCBhLCBiLCB0b2w9MC4wMDAwMDAxKSB7DQogIHJhdGlvIDwtIDIgLyAoIHNxcnQgKDUpKzEpDQogIHgxIDwtIGItcmF0aW8gKiAoYi1hKQ0KICB4MiA8LSBhK3JhdGlvICogKGItYSkNCiAgZjEgPC0gZih4MSkNCiAgZjIgPC0gZih4MikNCiAgDQogIHdoaWxlICggYWJzIChiLWEpPnRvbCl7DQogICAgaWYgKGYyPmYxKXsNCiAgICAgIGIgPC0geDINCiAgICAgIHgyIDwtIHgxDQogICAgICBmMiA8LSBmMQ0KICAgICAgeDEgPC0gYi1yYXRpbyAqIChiLWEpDQogICAgICANCiAgICAgIGYxIDwtIGYoeDEpDQogICAgfSBlbHNlIHsNCiAgICAgICAgYSA8LSB4MQ0KICAgICAgICB4MSA8LSB4Mg0KICAgICAgICBmMSA8LSBmMg0KICAgICAgICB4MiA8LSBhK3JhdGlvICogKGItYSkNCiAgICAgICAgZjIgPC0gZih4MikNCiAgICB9DQogIH0NCiAgcmV0dXJuICgoYStiKSAvIDIpDQp9DQpgYGANCg0KQ29udG9oOg0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSB8eCAtMy41fCArKHgtMileMiBcZW5ke2FsaWduZWR9JA0KDQpgYGB7cn0NCiMgTWVtYnVhdCBmdW5nc2kgZih4KQ0KZiA8LSBmdW5jdGlvbih4KSB7YWJzKHgtMy41KSsoeC0yKV4yfQ0KDQojIE1lbWJ1YXQgcGxvdA0KY3VydmUoZiwgMSw1KQ0KYGBgDQoNCmBgYHtyfQ0KIyBNZW5naGl0dW5nIG5pbGFpIG9wdGltdW0NCmdvbGRlbihmLDEsMikNCmdvbGRlbihmLDEsNSkNCmdvbGRlbihmLDMsNSkNCmdvbGRlbihmLDIsMykNCmBgYA0KDQojIyBOZXd0b24gUmFwaHNvbg0KDQpKaWthIHN1YXR1IGZ1bmdzaSBtZW1pbGlraSB0dXJ1bmFuIHBlcnRhbWEgZGFuIGtlZHVhLCBtYWthIG5pbGFpIG1pbmltdW0gZGFwYXQgbWVuZ2d1bmFrYW4gbWV0b2RlIE5ld3RvbiBSYXBoc29uLg0KS2VsZWJpaGFuIG1ldG9kZSBpbmkgYWRhbGFoIGhhbnlhIG1lbWVybHVrYW4gc2F0dSBuaWxhaSB1bnR1ayBpbmlzaWFsLg0KS2VsZW1haGFubnlhIGFkYWxhaCBraXRhIGhhcnVzIHlha2luIGYoeCkgbWVtaWxpa2kgdHVydW5hbiBwZXJ0YW1hIGRhbiB0dXJ1bmFuIGtlZHVhLg0KSmlrYSBkaSBnb2xkZW4gc2VjdGlvbiB0aWRhayBwZXJsdSBhZGEgdHVydW5hbiBwZXJ0YW1hIGRhbiB0dXJ1bmFuIGtlZHVhLg0KDQpGdW5nc2kgTmV3dG9uIFJhcGhzb24NCg0KYGBge3J9DQpuZXd0b25yIDwtIGZ1bmN0aW9uIChmeCAsIHgwID0xKXsNCiAgZngxIDwtIGRlcml2IChmeCAsIngiKSAjIHR1cnVuYW4gcGVydGFtYQ0KICBmeDIgPC0gZGVyaXYgKEQoZnggLCJ4IiksIngiKSAjIHR1cnVuYW4ga2VkdWENCiAgZXIgPC0gMTAwMA0KICANCiAgd2hpbGUoZXIgPiAxZS02KXsNCiAgICB4IDwtIHgwDQogICAgZjEgPC0gYXR0ciAoIGV2YWwgKGZ4MSksImdyYWRpZW50IilbMV0NCiAgICBmMiA8LSBhdHRyICggZXZhbCAoZngyKSwiZ3JhZGllbnQiKVsxXQ0KICAgIGVyIDwtIGFicyhmMSkgIyBiaXNhIGp1Z2EgZSA8LSBhYnMgKHgxIC14MCkNCiAgICB4MSA8LSB4MCAtIGYxL2YyDQogICAgeDAgPC0geDENCiAgfQ0KICByZXR1cm4gKHgxKQ0KfQ0KYGBgDQoNCkhpdHVuZyBuaWxhaSBtaW5pbXVtIHVudHVrIGZ1bmdzaS0gZnVuZ3NpIGJlcmlrdXQuDQoNCiRcYmVnaW57YWxpZ25lZH0gZih4KSA9IDR4XjIgLSAzeCAtIDcgXGVuZHthbGlnbmVkfSQNCg0KYGBge3J9DQpmeCA8LSBleHByZXNzaW9uKDQqeF4yLTMqeC03KQ0KbmV3dG9ucihmeCwzKQ0KYGBgDQoNCiRcYmVnaW57YWxpZ25lZH0gZih4KSA9IGVeey14fSt4XjQgXGVuZHthbGlnbmVkfSQNCg0KYGBge3J9DQpmeCA8LSBleHByZXNzaW9uKGV4cCgteCkreF40KQ0KbmV3dG9ucihmeCkNCm5ld3RvbnIoZngsMSkNCmBgYA0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSB4XjIgLSB4IFxlbmR7YWxpZ25lZH0kDQoNCmBgYHtyfQ0KZnggPC0gZXhwcmVzc2lvbih4XjIteCkNCm5ld3RvbnIoZngpDQpgYGANCg0KIyMgRnVuZ3NpIE9wdGltYXNpIEJ1aWx0LWluDQoNCkFsZ29yaXRtYSAqTmVsZGVyIE1lYWQqIGFkYWxhaCBzYWxhaCBzYXR1IG1ldG9kZSBvcHRpbWFzaSB1bnR1ayBmdW5nc2kgeWFuZyBtZW1pbGlraSBsZWJpaCBkYXJpIHNhdHUgdmFyaWFiZWwuDQpSIHRlbGFoIG1lbnlpYXBrYW4gZnVuZ3NpIG9wdGltYXNpIGRlbmdhbiBzYWxhaCBzYXR1IGFsZ29yaXRtYW55YSBhZGFsYWggTmVsZGVyLU1lYWQ6DQoNCi0gICBgb3B0aW1pemVgIGF0YXUgYG9wdGltaXNlYCB1bnR1ayBtZW5kdWdhIHBhcmFtZXRlci8gbWVuY2FyaSBuaWxhaSBtaW5pbXVtIGRhcmkgc2F0dSBwZXViYWgNCi0gICBgb3B0aW1gIHVudHVrIGxlYmloIGRhcmkgc2F0dSBwZXViYWgNCg0KIyMjIEZ1bmdzaSBvcHRpbWl6ZS9vcHRpbWlzZQ0KDQokXGJlZ2lue2FsaWduZWR9IGYoeCkgPSBcbGVmdCggeCAtIFxmcmFjezF9ezN9IFxyaWdodCleMiBcZW5ke2FsaWduZWR9JA0KDQpgYGB7cn0NCmYgPC0gZnVuY3Rpb24oeCkgKCh4LSgxLzMpKV4yKSAjIG1lbWJ1YXQgZnVuZ3NpIHR1anVhbg0KY3VydmUoZikNCmBgYA0KDQpgYGB7cn0NCnhtaW4gPC0gb3B0aW1pemUoZiwgYygwLDEpLCB0b2wgPSAwLjAwMDEpICMgdG9sZXJhbmNlIG9wdGlvbmFsDQp4bWluDQpgYGANCg0KIyMjIEZ1bmdzaSBvcHRpbQ0KDQpEaWd1bmFrYW4gdW50dWsgbWVuY2FyaSBuaWxhaSBtaW5pbXVtIGRhcmkgZnVuZ3NpIHlhbmcgbGViaWggZGFyaSBzYXR1IHBldWJhaC4NCkNvbnRvaCBtZW5jYXJpIG5pbGFpICR4XzEkIGRhbiAkeF8yJCwgeWFuZyBtZWJ1YXQgJGYoeF8xLHhfMikgPSAxMDAoeF8yIC0geF8xXjIpXjIgKyAoMS14XzEpXjIkIG1pbmltdW0NCg0KUHJvZ3JhbSB5YW5nIGRpZ3VuYWthbjoNCg0KYGBge3J9DQpmciA8LSBmdW5jdGlvbiAoeCl7ICMgdGV0YXAgZGl0dWxpc2thbiBkYWxhbSBzZWJ1YWggdmVrdG9yLCBha2FuIGRpZHVnYSB4DQogIHgxPC0geFsxXQ0KICB4MiA8LSB4WzJdDQogIDEwMCAqICh4Mi14MV4yKV4yICsgKDEteDEpXjIgIyBpbmkgYWRhbGFoIG5pbGFpIGZ1bmdzaSBvYmpldGl2ZW55YQ0KfSANCg0KIyBhcmd1bWVuIHBlcnRhbWEgYWRhbGFoIG5pbGFpIGluaXNpYWwsIGthcmVuYSBtZW5kdWdhIHggdmVrdG9yIGJlcnVrdXJhbiAyIG1ha2EgZGltYXN1a2thbiBuaWxhaSBpbmlzaWFsbnlhDQpvcHRpbSAoYygtMS4yLDEpLGZyKSANCmBgYA0K