Email             :
RPubs            : https://rpubs.com/juliansalomo/
Github           : https://github.com/juliansalomo/
Jurusan          : Statistika
Address         : ARA Center, Matana University Tower
                         Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.


1 Definisi Optimasi, Optimisasi, atau Optimalisasi

Optimasi, Optimalisasi, dan Optimisasi memiliki arti yang sama yaitu proses untuk mengoptimalkan suatu hal sehingga menghasilkan hasil yang paling ideal.

Untuk penggunaan kata yang benar,kebanyakan orang cenderung menggunakan kata Optimasi dan Optimalisasi. Sehingga dapat dikatakan Optimisasi merupakan kata yang salah. Namun, menurut wikipedia kata yang salah merupakan Optimalisasi. Sehingga jika kita menarik kesimpulan dari tiap sudut pandang yang berbeda, kata yang paling benar dan aman untuk digunakan adalah Optimasi

2 Apa yang dimaksud dengan optimasi terbatas dan optimasi tanpa kendala, beserta contohnya

2.1 Optimasi Terbatas

optimasi Terbatas adalah proses mengoptimalkan fungsi tujuan sehubungan dengan beberapa variabel dengan adanya batasan pada variabel tersebut

Contoh

Seorang pelanggan memiliki uang sebanyak Rp. 120,000.00. Pelanggan ini ingin membeli buah-buahan di minimarket dekat rumahnya. Harga apel (A) adalah Rp. 4000.00/buah sedangkan harga pisang (P) adalah Rp. 2000.00/buah. Berapa jumlah apel dan pisang yang harus dibeli pelanggan ini untuk kesejahteraan dia? Asumsikan: \[A^{\frac{1}{2}}P^{\frac{1}{2}}=\text{Kesejahteraan Pelanggan dalam Mengkonsumsi Apel dan Pisang}\]

Jawaban

\[ \begin{align} \ell(A,P)=f(A,P)+\lambda g(A,P)\\ f(A,P)=A^{\frac{1}{2}}P^{\frac{1}{2}}\\ g(A,P) \text{ is the constraints function}\\ 2P+4A \le 120\\ 0 \le 120-2P-4A\\ g(A,P)=120-2P-4A\\ \end{align} \] \[ \begin{align} \ell(A,P)&=f(A,P)+\lambda g(A,P)\\ \ell(A,P)&=A^{\frac{1}{2}}P^{\frac{1}{2}}+\lambda \left(120-2P-4A\right) \end{align} \]

selanjutnya kita akan melakukan turunan partial terhadap P dan A

ell<-expression(A^(1/2)*P^(1/2)+Lambda*(120-2*P-4*A))
paste("ell a")
## [1] "ell a"
D(ell,'A')
## A^((1/2) - 1) * (1/2) * P^(1/2) - Lambda * 4
paste("ell p")
## [1] "ell p"
D(ell,'P')
## A^(1/2) * (P^((1/2) - 1) * (1/2)) - Lambda * 2

Seperti hasil perhitungan di atas, kita mendapatkan hasil turunan parsial sebagai berikut: \[ \begin{align} \ell_{A}(A,P)&=\frac{1}{2}A^{-\frac{1}{2}}P^{\frac{1}{2}}-4\lambda=0\\ \ell_{P}(A,P)&=\frac{1}{2}A^{\frac{1}{2}}P^{-\frac{1}{2}}-2\lambda=0\\ \end{align} \]

Dari kedua persamaan di atas kita bisa mendapatkan persamaan untuk \(\lambda\) sebagai berikut: \[ \begin{align} \lambda&=\frac{A^{-\frac{1}{2}}P^{\frac{1}{2}}}{8}\\ \lambda&=\frac{A^{\frac{1}{2}}P^{-\frac{1}{2}}}{4}\\ \end{align} \]

Dengan saling mensubstitusikan kedua nilai \(\lambda\) di atas, kita akan mendapatkan hasil \(P=2A\) Sehingga kita sudah mendapatkan dua batasan, yaitu

  • \(P=2A\) batasan kesejahteraan
  • \(2P+4A=120\) batasan dana

Dengan saling mensubstitusikan kedua batasan ini, kita akan mendapatkan \(A=15\) dan \(P=30\) Sehingga pelanggan tersebut dapat memaksimalkan kesejahteraannya dengan membeli 15 apel dan 30 pisang.

2.2 Optimasi tanpa kendala

Optimasi tanpa kendala pada dasarnya berkaitan dengan menemukan minimum global atau maksimum global dari fungsi yang diberikan. Kemudian dapat mencari semua nilai ekstrem lokal dan membandingkan nilai fungsi pada masing-masing nilai tersebut untuk menemukan titik optimasi global (min atau maks).

Contoh

Carilah minimum global dan maksimum global beserta maksimum dan minimum lokal dari fungsi \(x^3-12x^2+36x+8\) untuk domain \(\left[2,6\right]\)!

Jawaban

Pertama kita perlu mencari turunan pertama dari fungsi untuk menemukan nilai kritisnya

f=expression(x^3-12*x^2+36*x+8)
`f'` <- D(f,'x')
`f'`
## 3 * x^2 - 12 * (2 * x) + 36

Dari hasil run code di atas kita menemukan turunan pertamanya adalah \[f'(x)=3x^2-24x+36\] Untuk mendapatkan nilai kritis kita harus menggunakan nilai \(f'(x)=0\), seperti berikut

\[ \begin{align} 3x^2-24x+36&=0\\ x^2-8+12&=0\\ (x-6)(x-2)&=0\\ x_1=6,x_2=2 \end{align} \]

Selanjutnya untuk menentukan apakah nilai kritis ini termasuk maksimum atau minimum kita perlu mencari turunan keduanya. Turunan kedua dapat dicari menggunakan fungsi berikut

`f"` <- D(`f'`,'x')
`f"`
## 3 * (2 * x) - 12 * 2

Dari hasil run code di atas kita menemukan turunan keduanya adalah \[f"(x)=6x-24\] Selanjutnya kita mensubstitusikan nilai kritis ke dalam fungsi. Jika hasilnya positif maka nilai tersebut adalah minimum, sebaliknya jika hasilnya negatif maka nilai tersebut merupakan maksimum $$ \[\begin{align} f"(6)&=6*6-24\\ &=36-24\\ &=8 {\tt (Nilai Positif, Minimum)} \end{align}\]

\[\begin{align} f"(2)&=2*6-24\\ &=12-24\\ &=-12 {\tt (Nilai Negatif, Maksimum)} \end{align}\] $$

Domain dari fungsi adalah \(\left[2,6\right]\) atau \(2\le x\le 6\)

Angka batasan domain sama dengan nilai kritis, sehingga kita bisa langsung mengetahui bahwa nilai global maksimum sama dengan nilai lokal maksimum yaitu pada saat berada di titik \(x=2\) Nilai untuk \(f(2)\) adalah

f <- function(x, y = substitute(x)) { x <- x^3-12*x^2+36*x+8; y }
f(2)
## [1] 40

Maka lokal dan global maksimumnya adalah 40

Selanjutnya nilai lokal dan global minimum pun sama yaitu pada saat di titik \(x=6\). Nilai untuk \(f(6)\) adalah

f(6)
## [1] 8

Maka lokal dan global minimumnya adalah 8

3 Metode atau algoritma yang sering digunakan pada Optimasi, berdasarkan:

3.1 Optimasi Satu Dimensi

Dalam optimasi satu dimensi kita akan menggunakan algoritma optimize()

my_function <- function(x) {             # Create function
  x^3 + 2 * x^2 - 10 * x
}
optimize(my_function,                    # Apply optimize
         interval = c(- 1, 1))
## $minimum
## [1] 0.999959
## 
## $objective
## [1] -6.999877

3.2 Optimasi Multidimensi

Untuk optimasi multidimensi, kita menggunakan algoritma optim()

f <- function(x) 2*(x[1]-1)^2 + 5*(x[2]-3)^2 + 10

r <- optim(c(1, 1), f)                                     #Call optimization routine

r$convergence == 0                                         #Check if the optimization converged to a minimum
## [1] TRUE
r$par                                                      #Optimal input arguments
## [1] 1.000168 3.000232
r$value                                                    #Objective at the minimum
## [1] 10

3.3 Model Optimasi Sederhana

3.4 Pemrograman Linier

Dalam pemrograman Linier kita akan menggunakan package lpSolve. Dari package ini kita akan menggunakan fungsi lp()

library(lpSolve)
objective.in <- c(25, 20)
const.mat <- matrix(c(20, 12, 1/15, 1/15), nrow=2,
byrow=TRUE)
const.rhs <- c(1800, 8)
const.dir <- c("<=", "<=")
optimum <- lp(direction="max", objective.in, const.mat,
const.dir, const.rhs)
optimum
## Success: the objective function is 2625

3.5 Pemrograman Kuadrat

Dalam pemograman kuadrat kita akan menggunakan package quadprog.

Asumsikan kita ingin meminimalkan: \(-(0 5 0) \text{%*% } b + 1/2 b^T b\) di bawah batasan: \(A^T b >= b0\) dengan \(b0 = (-8,2,0)^T\) dan \[ A = \begin{bmatrix} -4 & 2 & 0\\ -3 & 1 & -2\\ 0 & 0 & 1 \end{bmatrix} \] kita dapat menggunakan solve.QP sebagai berikut:

library(quadprog)
Dmat <- matrix(0,3,3)
diag(Dmat) <- 1
dvec <- c(0,5,0)
Amat <- matrix(c(-4,-3,0,2,1,0,0,-2,1),3,3)
bvec <- c(-8,2,0)
solve.QP(Dmat,dvec,Amat,bvec=bvec)
## $solution
## [1] 0.4761905 1.0476190 2.0952381
## 
## $value
## [1] -2.380952
## 
## $unconstrained.solution
## [1] 0 5 0
## 
## $iterations
## [1] 3 0
## 
## $Lagrangian
## [1] 0.0000000 0.2380952 2.0952381
## 
## $iact
## [1] 3 2

3.6 Pemrograman Nonlinier

Untuk pemrograman nonlinier terdapat dua jenis lagi yaitu satu dimensi dan multi dimensi. Untuk satu dimensi kita tetap akan menggunakan fungsi optimze() dengan tambahan argumen tol. Sedangkan untuk multidimensi kita akan menggunakan fungsi optimx()

#one-dimensional
f <- function(x) return(abs(x-2) + 2*abs(x-1))
xmin <- optimize(f, interval = c(0, 3), tol = 0.0001)
xmin
## $minimum
## [1] 1.000009
## 
## $objective
## [1] 1.000009
#multidimensional
fn <- function(para){ # Vector of the parameters
matrix.A <- matrix(para, ncol=2)
x <- matrix.A[,1]
y <- matrix.A[,2]
f.x <- (x^2+y-11)^2+(x+y^2-7)^2
return(f.x)
}
par <- c(1,1)

4 Optimasi Sains Data dalam kehidupan sehari-hari

Optimasi sains data merupakan hal yang sangat bermanfaat dalam kehidupan sehari-hari, baik dalam meminimumkan pengeluaran, memaksimalkan keuntungan, dll.

Dengan Optimasi sains data kita dapat meminimumkan cost yang kita keluarkan sekaligus mencapai keuntungan maksimum yang dapat diperoleh.

Contohnya suatu pabrik yang memiliki data cost produksi, pendapatan dari penjualan produk, batasan produksi per hari serta cost tetap per bulan dapat mengkalkulasikan keuntungan maksimum yang diperoleh dengan mempertimbangkan semua data itu ke dalam proses kalkulasi.

LS0tDQp0aXRsZTogIk9wdGltaXphdGlvbiINCnN1YnRpdGxlOiAiQXNzaWdubWVudCBXZWVrIDEiDQphdXRob3I6ICJKdWxpYW4gU2Fsb21vICgyMDE5NDkyMDAwMykiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50OiANCiAgICBodG1sX2RvY3VtZW50OiBudWxsDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdGhlbWU6IHNhbmRzdG9uZQ0KICAgIGNzczogRDovSnVsaWFuIFNhbG9tby9NYXRhbmEvMDAwMC9zdHlsZS5jc3MNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCi0tLQ0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNsYXNzLnNvdXJjZSA9ICJub2NvcHkiLA0KICAgICAgICAgICAgICAgICAgICAgIGNsYXNzLm91dHB1dCA9ICJub2NvcHkiLA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGLA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGKQ0KYGBgDQoNCmBgYHtyIG1lLCBlY2hvPUZBTFNFLGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoID0gJzMwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiRDovSnVsaWFuIFNhbG9tby9NYXRhbmEvMDAwMC9sb2dvLnBuZyIpDQpgYGANCg0KRW1haWwgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7Jm5ic3A7OiAganVsaWFuc2Fsb21vMkBnbWFpbC5jb20gPGJyPg0KUlB1YnMgICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOzogaHR0cHM6Ly9ycHVicy5jb20vanVsaWFuc2Fsb21vLyA8YnI+DQpHaXRodWIgICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAmbmJzcDsgJm5ic3A7IDogaHR0cHM6Ly9naXRodWIuY29tL2p1bGlhbnNhbG9tby8gPGJyPg0KSnVydXNhbiAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBbU3RhdGlzdGlrYV0oaHR0cHM6Ly9tYXRhbmF1bml2ZXJzaXR5LmFjLmlkLz9seT1hY2FkZW1pYyZjPXNiKSA8YnI+DQpBZGRyZXNzICAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgOiBBUkEgQ2VudGVyLCBNYXRhbmEgVW5pdmVyc2l0eSBUb3dlciA8YnI+DQombmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyZuYnNwOyBKbC4gQ0JEIEJhcmF0IEthdiwgUlQuMSwgQ3VydWcgU2FuZ2VyZW5nLCBLZWxhcGEgRHVhLCBUYW5nZXJhbmcsIEJhbnRlbiAxNTgxMC4NCg0KKioqKg0KDQojIERlZmluaXNpIE9wdGltYXNpLCBPcHRpbWlzYXNpLCBhdGF1IE9wdGltYWxpc2FzaQ0KDQoqKk9wdGltYXNpKiosICoqT3B0aW1hbGlzYXNpKiosIGRhbiAqKk9wdGltaXNhc2kqKiBtZW1pbGlraSBhcnRpIHlhbmcgc2FtYSB5YWl0dSBwcm9zZXMgdW50dWsgbWVuZ29wdGltYWxrYW4gc3VhdHUgaGFsIHNlaGluZ2dhIG1lbmdoYXNpbGthbiBoYXNpbCB5YW5nIHBhbGluZyBpZGVhbC4NCg0KVW50dWsgcGVuZ2d1bmFhbiBrYXRhIHlhbmcgYmVuYXIsa2ViYW55YWthbiBvcmFuZyBjZW5kZXJ1bmcgbWVuZ2d1bmFrYW4ga2F0YSBPcHRpbWFzaSBkYW4gT3B0aW1hbGlzYXNpLiBTZWhpbmdnYSBkYXBhdCBkaWthdGFrYW4gT3B0aW1pc2FzaSBtZXJ1cGFrYW4ga2F0YSB5YW5nIHNhbGFoLiBOYW11biwgbWVudXJ1dCB3aWtpcGVkaWEga2F0YSB5YW5nIHNhbGFoIG1lcnVwYWthbiBPcHRpbWFsaXNhc2kuIFNlaGluZ2dhIGppa2Ega2l0YSBtZW5hcmlrIGtlc2ltcHVsYW4gZGFyaSB0aWFwIHN1ZHV0IHBhbmRhbmcgeWFuZyBiZXJiZWRhLCBrYXRhIHlhbmcgcGFsaW5nIGJlbmFyIGRhbiBhbWFuIHVudHVrIGRpZ3VuYWthbiBhZGFsYWggKipPcHRpbWFzaSoqDQogDQojIEFwYSB5YW5nIGRpbWFrc3VkIGRlbmdhbiBvcHRpbWFzaSB0ZXJiYXRhcyBkYW4gb3B0aW1hc2kgdGFucGEga2VuZGFsYSwgYmVzZXJ0YSBjb250b2hueWENCg0KIyMgT3B0aW1hc2kgVGVyYmF0YXMNCg0Kb3B0aW1hc2kgVGVyYmF0YXMgYWRhbGFoIHByb3NlcyBtZW5nb3B0aW1hbGthbiBmdW5nc2kgdHVqdWFuIHNlaHVidW5nYW4gZGVuZ2FuIGJlYmVyYXBhIHZhcmlhYmVsIGRlbmdhbiBhZGFueWEgYmF0YXNhbiBwYWRhIHZhcmlhYmVsIHRlcnNlYnV0DQoNCj4gQ29udG9oDQoNClNlb3JhbmcgcGVsYW5nZ2FuIG1lbWlsaWtpIHVhbmcgc2ViYW55YWsgUnAuIDEyMCwwMDAuMDAuIFBlbGFuZ2dhbiBpbmkgaW5naW4gbWVtYmVsaSBidWFoLWJ1YWhhbiBkaSBtaW5pbWFya2V0IGRla2F0IHJ1bWFobnlhLiBIYXJnYSBhcGVsIChBKSBhZGFsYWggUnAuIDQwMDAuMDAvYnVhaCBzZWRhbmdrYW4gaGFyZ2EgcGlzYW5nIChQKSBhZGFsYWggUnAuIDIwMDAuMDAvYnVhaC4gQmVyYXBhIGp1bWxhaCBhcGVsIGRhbiBwaXNhbmcgeWFuZyBoYXJ1cyBkaWJlbGkgcGVsYW5nZ2FuIGluaSB1bnR1ayBrZXNlamFodGVyYWFuIGRpYT8NCipBc3Vtc2lrYW46KiANCiQkQV57XGZyYWN7MX17Mn19UF57XGZyYWN7MX17Mn19PVx0ZXh0e0tlc2VqYWh0ZXJhYW4gUGVsYW5nZ2FuIGRhbGFtIE1lbmdrb25zdW1zaSBBcGVsIGRhbiBQaXNhbmd9JCQNCg0KXyoqSmF3YWJhbioqXw0KDQokJA0KXGJlZ2lue2FsaWdufQ0KXGVsbChBLFApPWYoQSxQKStcbGFtYmRhIGcoQSxQKVxcDQpmKEEsUCk9QV57XGZyYWN7MX17Mn19UF57XGZyYWN7MX17Mn19XFwNCmcoQSxQKSBcdGV4dHsgaXMgdGhlIGNvbnN0cmFpbnRzIGZ1bmN0aW9ufVxcDQoyUCs0QSBcbGUgMTIwXFwNCjAgXGxlIDEyMC0yUC00QVxcDQpnKEEsUCk9MTIwLTJQLTRBXFwNClxlbmR7YWxpZ259DQokJA0KJCQNClxiZWdpbnthbGlnbn0NClxlbGwoQSxQKSY9ZihBLFApK1xsYW1iZGEgZyhBLFApXFwNClxlbGwoQSxQKSY9QV57XGZyYWN7MX17Mn19UF57XGZyYWN7MX17Mn19K1xsYW1iZGEgXGxlZnQoMTIwLTJQLTRBXHJpZ2h0KQ0KXGVuZHthbGlnbn0NCiQkDQoNCnNlbGFuanV0bnlhIGtpdGEgYWthbiBtZWxha3VrYW4gdHVydW5hbiBwYXJ0aWFsIHRlcmhhZGFwIFAgZGFuIEENCg0KYGBge3J9DQplbGw8LWV4cHJlc3Npb24oQV4oMS8yKSpQXigxLzIpK0xhbWJkYSooMTIwLTIqUC00KkEpKQ0KcGFzdGUoImVsbCBhIikNCkQoZWxsLCdBJykNCnBhc3RlKCJlbGwgcCIpDQpEKGVsbCwnUCcpDQpgYGANCg0KU2VwZXJ0aSBoYXNpbCBwZXJoaXR1bmdhbiBkaSBhdGFzLCBraXRhIG1lbmRhcGF0a2FuIGhhc2lsIHR1cnVuYW4gcGFyc2lhbCBzZWJhZ2FpIGJlcmlrdXQ6DQokJA0KXGJlZ2lue2FsaWdufQ0KXGVsbF97QX0oQSxQKSY9XGZyYWN7MX17Mn1BXnstXGZyYWN7MX17Mn19UF57XGZyYWN7MX17Mn19LTRcbGFtYmRhPTBcXA0KXGVsbF97UH0oQSxQKSY9XGZyYWN7MX17Mn1BXntcZnJhY3sxfXsyfX1QXnstXGZyYWN7MX17Mn19LTJcbGFtYmRhPTBcXA0KXGVuZHthbGlnbn0NCiQkDQoNCkRhcmkga2VkdWEgcGVyc2FtYWFuIGRpIGF0YXMga2l0YSBiaXNhIG1lbmRhcGF0a2FuIHBlcnNhbWFhbiB1bnR1ayAkXGxhbWJkYSQgc2ViYWdhaSBiZXJpa3V0Og0KJCQNClxiZWdpbnthbGlnbn0NClxsYW1iZGEmPVxmcmFje0Feey1cZnJhY3sxfXsyfX1QXntcZnJhY3sxfXsyfX19ezh9XFwNClxsYW1iZGEmPVxmcmFje0Fee1xmcmFjezF9ezJ9fVBeey1cZnJhY3sxfXsyfX19ezR9XFwNClxlbmR7YWxpZ259DQokJA0KDQpEZW5nYW4gc2FsaW5nIG1lbnN1YnN0aXR1c2lrYW4ga2VkdWEgbmlsYWkgJFxsYW1iZGEkIGRpIGF0YXMsIGtpdGEgYWthbiBtZW5kYXBhdGthbiBoYXNpbCAkUD0yQSQNClNlaGluZ2dhIGtpdGEgc3VkYWggbWVuZGFwYXRrYW4gZHVhIGJhdGFzYW4sIHlhaXR1DQoNCiogJFA9MkEkIGJhdGFzYW4ga2VzZWphaHRlcmFhbg0KKiAkMlArNEE9MTIwJCBiYXRhc2FuIGRhbmENCg0KRGVuZ2FuIHNhbGluZyBtZW5zdWJzdGl0dXNpa2FuIGtlZHVhIGJhdGFzYW4gaW5pLCBraXRhIGFrYW4gbWVuZGFwYXRrYW4gJEE9MTUkIGRhbiAkUD0zMCQNClNlaGluZ2dhIHBlbGFuZ2dhbiB0ZXJzZWJ1dCBkYXBhdCBtZW1ha3NpbWFsa2FuIGtlc2VqYWh0ZXJhYW5ueWEgZGVuZ2FuIG1lbWJlbGkgMTUgYXBlbCBkYW4gMzAgcGlzYW5nLg0KDQojIyBPcHRpbWFzaSB0YW5wYSBrZW5kYWxhDQoNCk9wdGltYXNpIHRhbnBhIGtlbmRhbGEgcGFkYSBkYXNhcm55YSBiZXJrYWl0YW4gZGVuZ2FuIG1lbmVtdWthbiBtaW5pbXVtIGdsb2JhbCBhdGF1IG1ha3NpbXVtIGdsb2JhbCBkYXJpIGZ1bmdzaSB5YW5nIGRpYmVyaWthbi4gS2VtdWRpYW4gZGFwYXQgbWVuY2FyaSBzZW11YSBuaWxhaSBla3N0cmVtIGxva2FsIGRhbiBtZW1iYW5kaW5na2FuIG5pbGFpIGZ1bmdzaSBwYWRhIG1hc2luZy1tYXNpbmcgbmlsYWkgdGVyc2VidXQgdW50dWsgbWVuZW11a2FuIHRpdGlrIG9wdGltYXNpIGdsb2JhbCAobWluIGF0YXUgbWFrcykuDQoNCj4gQ29udG9oDQoNCkNhcmlsYWggbWluaW11bSBnbG9iYWwgZGFuIG1ha3NpbXVtIGdsb2JhbCBiZXNlcnRhIG1ha3NpbXVtIGRhbiBtaW5pbXVtIGxva2FsIGRhcmkgZnVuZ3NpICR4XjMtMTJ4XjIrMzZ4KzgkIHVudHVrIGRvbWFpbiAkXGxlZnRbMiw2XHJpZ2h0XSQhDQoNCl8qKkphd2FiYW4qKl8NCg0KUGVydGFtYSBraXRhIHBlcmx1IG1lbmNhcmkgdHVydW5hbiBwZXJ0YW1hIGRhcmkgZnVuZ3NpIHVudHVrIG1lbmVtdWthbiBuaWxhaSBrcml0aXNueWENCmBgYHtyfQ0KZj1leHByZXNzaW9uKHheMy0xMip4XjIrMzYqeCs4KQ0KYGYnYCA8LSBEKGYsJ3gnKQ0KYGYnYA0KYGBgDQpEYXJpIGhhc2lsIHJ1biBjb2RlIGRpIGF0YXMga2l0YSBtZW5lbXVrYW4gdHVydW5hbiBwZXJ0YW1hbnlhIGFkYWxhaCANCiQkZicoeCk9M3heMi0yNHgrMzYkJA0KVW50dWsgbWVuZGFwYXRrYW4gbmlsYWkga3JpdGlzIGtpdGEgaGFydXMgbWVuZ2d1bmFrYW4gbmlsYWkgJGYnKHgpPTAkLCBzZXBlcnRpIGJlcmlrdXQNCg0KJCQNClxiZWdpbnthbGlnbn0NCjN4XjItMjR4KzM2Jj0wXFwNCnheMi04KzEyJj0wXFwNCih4LTYpKHgtMikmPTBcXA0KeF8xPTYseF8yPTINClxlbmR7YWxpZ259DQokJA0KDQpTZWxhbmp1dG55YSB1bnR1ayBtZW5lbnR1a2FuIGFwYWthaCBuaWxhaSBrcml0aXMgaW5pIHRlcm1hc3VrIG1ha3NpbXVtIGF0YXUgbWluaW11bSBraXRhIHBlcmx1IG1lbmNhcmkgdHVydW5hbiBrZWR1YW55YS4gVHVydW5hbiBrZWR1YSBkYXBhdCBkaWNhcmkgbWVuZ2d1bmFrYW4gZnVuZ3NpIGJlcmlrdXQNCg0KYGBge3J9DQpgZiJgIDwtIEQoYGYnYCwneCcpDQpgZiJgDQpgYGANCkRhcmkgaGFzaWwgcnVuIGNvZGUgZGkgYXRhcyBraXRhIG1lbmVtdWthbiB0dXJ1bmFuIGtlZHVhbnlhIGFkYWxhaCANCiQkZiIoeCk9NngtMjQkJA0KU2VsYW5qdXRueWEga2l0YSBtZW5zdWJzdGl0dXNpa2FuIG5pbGFpIGtyaXRpcyBrZSBkYWxhbSBmdW5nc2kuIEppa2EgaGFzaWxueWEgcG9zaXRpZiBtYWthIG5pbGFpIHRlcnNlYnV0IGFkYWxhaCBtaW5pbXVtLCBzZWJhbGlrbnlhIGppa2EgaGFzaWxueWEgbmVnYXRpZiBtYWthIG5pbGFpIHRlcnNlYnV0IG1lcnVwYWthbiBtYWtzaW11bQ0KJCQNClxiZWdpbnthbGlnbn0NCmYiKDYpJj02KjYtMjRcXA0KJj0zNi0yNFxcDQomPTgge1x0dCAoTmlsYWkgUG9zaXRpZiwgTWluaW11bSl9DQpcZW5ke2FsaWdufQ0KDQpcYmVnaW57YWxpZ259DQpmIigyKSY9Mio2LTI0XFwNCiY9MTItMjRcXA0KJj0tMTIge1x0dCAoTmlsYWkgTmVnYXRpZiwgTWFrc2ltdW0pfQ0KXGVuZHthbGlnbn0NCiQkDQoNCkRvbWFpbiBkYXJpIGZ1bmdzaSBhZGFsYWggJFxsZWZ0WzIsNlxyaWdodF0kIGF0YXUgJDJcbGUgeFxsZSA2JA0KDQpBbmdrYSBiYXRhc2FuIGRvbWFpbiBzYW1hIGRlbmdhbiBuaWxhaSBrcml0aXMsIHNlaGluZ2dhIGtpdGEgYmlzYSBsYW5nc3VuZyBtZW5nZXRhaHVpIGJhaHdhIG5pbGFpIGdsb2JhbCBtYWtzaW11bSBzYW1hIGRlbmdhbiBuaWxhaSBsb2thbCBtYWtzaW11bSB5YWl0dSBwYWRhIHNhYXQgYmVyYWRhIGRpIHRpdGlrICR4PTIkDQpOaWxhaSB1bnR1ayAkZigyKSQgYWRhbGFoDQpgYGB7cn0NCmYgPC0gZnVuY3Rpb24oeCwgeSA9IHN1YnN0aXR1dGUoeCkpIHsgeCA8LSB4XjMtMTIqeF4yKzM2KngrODsgeSB9DQpmKDIpDQpgYGANCk1ha2EgbG9rYWwgZGFuIGdsb2JhbCBtYWtzaW11bW55YSBhZGFsYWggNDANCg0KU2VsYW5qdXRueWEgbmlsYWkgbG9rYWwgZGFuIGdsb2JhbCBtaW5pbXVtIHB1biBzYW1hIHlhaXR1IHBhZGEgc2FhdCBkaSB0aXRpayAkeD02JC4gTmlsYWkgdW50dWsgJGYoNikkIGFkYWxhaA0KYGBge3J9DQpmKDYpDQpgYGANCk1ha2EgbG9rYWwgZGFuIGdsb2JhbCBtaW5pbXVtbnlhIGFkYWxhaCA4DQoNCiMgTWV0b2RlIGF0YXUgYWxnb3JpdG1hIHlhbmcgc2VyaW5nIGRpZ3VuYWthbiBwYWRhIE9wdGltYXNpLCBiZXJkYXNhcmthbjoNCg0KIyMgT3B0aW1hc2kgU2F0dSBEaW1lbnNpDQoNCkRhbGFtIG9wdGltYXNpIHNhdHUgZGltZW5zaSBraXRhIGFrYW4gbWVuZ2d1bmFrYW4gYWxnb3JpdG1hIGBvcHRpbWl6ZSgpYA0KDQpgYGB7cn0NCm15X2Z1bmN0aW9uIDwtIGZ1bmN0aW9uKHgpIHsgICAgICAgICAgICAgIyBDcmVhdGUgZnVuY3Rpb24NCiAgeF4zICsgMiAqIHheMiAtIDEwICogeA0KfQ0Kb3B0aW1pemUobXlfZnVuY3Rpb24sICAgICAgICAgICAgICAgICAgICAjIEFwcGx5IG9wdGltaXplDQogICAgICAgICBpbnRlcnZhbCA9IGMoLSAxLCAxKSkNCmBgYA0KDQojIyBPcHRpbWFzaSBNdWx0aWRpbWVuc2kNCg0KVW50dWsgb3B0aW1hc2kgbXVsdGlkaW1lbnNpLCBraXRhIG1lbmdndW5ha2FuIGFsZ29yaXRtYSBgb3B0aW0oKWANCg0KYGBge3J9DQpmIDwtIGZ1bmN0aW9uKHgpIDIqKHhbMV0tMSleMiArIDUqKHhbMl0tMyleMiArIDEwDQoNCnIgPC0gb3B0aW0oYygxLCAxKSwgZikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI0NhbGwgb3B0aW1pemF0aW9uIHJvdXRpbmUNCg0KciRjb252ZXJnZW5jZSA9PSAwICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjQ2hlY2sgaWYgdGhlIG9wdGltaXphdGlvbiBjb252ZXJnZWQgdG8gYSBtaW5pbXVtDQoNCnIkcGFyICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI09wdGltYWwgaW5wdXQgYXJndW1lbnRzDQoNCnIkdmFsdWUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI09iamVjdGl2ZSBhdCB0aGUgbWluaW11bQ0KYGBgDQoNCiMjIE1vZGVsIE9wdGltYXNpIFNlZGVyaGFuYQ0KDQojIyBQZW1yb2dyYW1hbiBMaW5pZXINCg0KRGFsYW0gcGVtcm9ncmFtYW4gTGluaWVyIGtpdGEgYWthbiBtZW5nZ3VuYWthbiBwYWNrYWdlIGBscFNvbHZlYC4gRGFyaSBwYWNrYWdlIGluaSBraXRhIGFrYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGBscCgpYA0KYGBge3J9DQpsaWJyYXJ5KGxwU29sdmUpDQpvYmplY3RpdmUuaW4gPC0gYygyNSwgMjApDQpjb25zdC5tYXQgPC0gbWF0cml4KGMoMjAsIDEyLCAxLzE1LCAxLzE1KSwgbnJvdz0yLA0KYnlyb3c9VFJVRSkNCmNvbnN0LnJocyA8LSBjKDE4MDAsIDgpDQpjb25zdC5kaXIgPC0gYygiPD0iLCAiPD0iKQ0Kb3B0aW11bSA8LSBscChkaXJlY3Rpb249Im1heCIsIG9iamVjdGl2ZS5pbiwgY29uc3QubWF0LA0KY29uc3QuZGlyLCBjb25zdC5yaHMpDQpvcHRpbXVtDQpgYGANCg0KIyMgUGVtcm9ncmFtYW4gS3VhZHJhdA0KDQpEYWxhbSBwZW1vZ3JhbWFuIGt1YWRyYXQga2l0YSBha2FuIG1lbmdndW5ha2FuIHBhY2thZ2UgYHF1YWRwcm9nYC4NCg0KQXN1bXNpa2FuIGtpdGEgaW5naW4gbWVtaW5pbWFsa2FuOiAkLSgwIDUgMCkgXHRleHR7JSolIH0gYiArIDEvMiBiXlQgYiQgZGkgYmF3YWggYmF0YXNhbjogJEFeVCBiID49IGIwJCBkZW5nYW4gJGIwID0gKC04LDIsMCleVCQgZGFuDQokJA0KQSA9IFxiZWdpbntibWF0cml4fQ0KLTQgJiAyICYgMFxcDQotMyAmIDEgJiAtMlxcDQowICYgMCAmIDENClxlbmR7Ym1hdHJpeH0NCiQkDQpraXRhIGRhcGF0IG1lbmdndW5ha2FuIHNvbHZlLlFQIHNlYmFnYWkgYmVyaWt1dDoNCg0KYGBge3J9DQpsaWJyYXJ5KHF1YWRwcm9nKQ0KRG1hdCA8LSBtYXRyaXgoMCwzLDMpDQpkaWFnKERtYXQpIDwtIDENCmR2ZWMgPC0gYygwLDUsMCkNCkFtYXQgPC0gbWF0cml4KGMoLTQsLTMsMCwyLDEsMCwwLC0yLDEpLDMsMykNCmJ2ZWMgPC0gYygtOCwyLDApDQpzb2x2ZS5RUChEbWF0LGR2ZWMsQW1hdCxidmVjPWJ2ZWMpDQpgYGANCg0KIyMgUGVtcm9ncmFtYW4gTm9ubGluaWVyDQoNClVudHVrIHBlbXJvZ3JhbWFuIG5vbmxpbmllciB0ZXJkYXBhdCBkdWEgamVuaXMgbGFnaSB5YWl0dSBzYXR1IGRpbWVuc2kgZGFuIG11bHRpIGRpbWVuc2kuIFVudHVrIHNhdHUgZGltZW5zaSBraXRhIHRldGFwIGFrYW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGBvcHRpbXplKClgIGRlbmdhbiB0YW1iYWhhbiBhcmd1bWVuIGB0b2xgLiBTZWRhbmdrYW4gdW50dWsgbXVsdGlkaW1lbnNpIGtpdGEgYWthbiBtZW5nZ3VuYWthbiBmdW5nc2kgYG9wdGlteCgpYA0KDQpgYGB7cn0NCiNvbmUtZGltZW5zaW9uYWwNCmYgPC0gZnVuY3Rpb24oeCkgcmV0dXJuKGFicyh4LTIpICsgMiphYnMoeC0xKSkNCnhtaW4gPC0gb3B0aW1pemUoZiwgaW50ZXJ2YWwgPSBjKDAsIDMpLCB0b2wgPSAwLjAwMDEpDQp4bWluDQpgYGANCg0KDQpgYGB7cn0NCiNtdWx0aWRpbWVuc2lvbmFsDQpmbiA8LSBmdW5jdGlvbihwYXJhKXsgIyBWZWN0b3Igb2YgdGhlIHBhcmFtZXRlcnMNCm1hdHJpeC5BIDwtIG1hdHJpeChwYXJhLCBuY29sPTIpDQp4IDwtIG1hdHJpeC5BWywxXQ0KeSA8LSBtYXRyaXguQVssMl0NCmYueCA8LSAoeF4yK3ktMTEpXjIrKHgreV4yLTcpXjINCnJldHVybihmLngpDQp9DQpwYXIgPC0gYygxLDEpDQpgYGANCg0KIyBPcHRpbWFzaSBTYWlucyBEYXRhIGRhbGFtIGtlaGlkdXBhbiBzZWhhcmktaGFyaQ0KDQpPcHRpbWFzaSBzYWlucyBkYXRhIG1lcnVwYWthbiBoYWwgeWFuZyBzYW5nYXQgYmVybWFuZmFhdCBkYWxhbSBrZWhpZHVwYW4gc2VoYXJpLWhhcmksIGJhaWsgZGFsYW0gbWVtaW5pbXVta2FuIHBlbmdlbHVhcmFuLCBtZW1ha3NpbWFsa2FuIGtldW50dW5nYW4sIGRsbC4NCg0KRGVuZ2FuIE9wdGltYXNpIHNhaW5zIGRhdGEga2l0YSBkYXBhdCBtZW1pbmltdW1rYW4gY29zdCB5YW5nIGtpdGEga2VsdWFya2FuIHNla2FsaWd1cyBtZW5jYXBhaSBrZXVudHVuZ2FuIG1ha3NpbXVtIHlhbmcgZGFwYXQgZGlwZXJvbGVoLg0KDQpDb250b2hueWEgc3VhdHUgcGFicmlrIHlhbmcgbWVtaWxpa2kgZGF0YSBjb3N0IHByb2R1a3NpLCBwZW5kYXBhdGFuIGRhcmkgcGVuanVhbGFuIHByb2R1aywgYmF0YXNhbiBwcm9kdWtzaSBwZXIgaGFyaSBzZXJ0YSBjb3N0IHRldGFwIHBlciBidWxhbiBkYXBhdCBtZW5na2Fsa3VsYXNpa2FuIGtldW50dW5nYW4gbWFrc2ltdW0geWFuZyBkaXBlcm9sZWggZGVuZ2FuIG1lbXBlcnRpbWJhbmdrYW4gc2VtdWEgZGF0YSBpdHUga2UgZGFsYW0gcHJvc2VzIGthbGt1bGFzaS4=