
Email          : dsciencelabs@outlook.com
RPubs         : https://rpubs.com/vanessasupit/
Github        : https://github.com/vanessasupit/
Jurusan      : Statistika
Address     : ARA Center, Matana University Tower
             Jl. CBD Barat Kav, RT.1, Curug Sangereng, Kelapa Dua, Tangerang, Banten 15810.
SOAL
Sebuah perusahaan memproduksi dua model kursi: A dan B. Model A membutuhkan 4 balok, 1 dudukan kursi, dan 1 sandaran kursi. Sedangkan model B membutuhkan 3 balok dan 1 dudukan kursi. Perusahaan memiliki stok awal 200 balok, 500 dudukan kursi, dan 100 sandaran kursi. Jika perusahaan membutuhkan lebih banyak balok, dudukan kursi, dan sandaran kursi, mereka dapat membeli kayu balok standar, yang harganya 80 euro per balok. Perusahaan dapat memproduksi 20 balok, 10 dudukan kursi, dan 2 sandaran kursi dari balok kayu standar. Biaya produksi model A adalah 30 euro/kursi, sedangkan biaya model B adalah 40 euro/kursi. Jika perusahaan menginformasikan bahwa jumlah minimum kursi yang harus diproduksi adalah 1000 unit per bulan. Tentukan model program linier, yang dapat meminimalkan total biaya.
Selesaiakan permasalahan optimasi diatas dengan cara:
- Grafik
- Manual
- Menggunakan R
- Menggunakan Python
Solutions
Kita konversi soal sebelumnya dalam bentuk tabel terlebih dahulu.
Keterangan :
- x = Model A
- y = Model B
- z = Balok
x |
4 |
1 |
1 |
30 |
y |
3 |
1 |
|
40 |
z |
20 |
10 |
2 |
80 |
Ketersediaan |
200 |
500 |
100 |
|
Fungsi Tujuan :
Dengan memperhatikan biaya produksi model A adalah 30 euro/kursi, biaya model B adalah 40 euro/kursi, dan biaya balok 80 euro/kursi
\[
Min(30x_x+40x_y+80x_z)
\]
Fungsi Batasan :
- Untuk produksi balok perusahaan memiliki stok awal 200 dan dapat memproduksi 20 balok lagi
\[
4x_x+3x_y \le 200+20x_z\\
4x_x+3x_y-20x_z \le 200
\]
- Untuk produksi dudukan kursi perusahaan memiliki stok awal 500 dan dapat memproduksi 10 dudukan lagi
\[
x_x+x_y \le 500+10x_z\\
x_x+x_y-10x_z \le 500
\]
- Untuk produksi sandaran kursi perusahaan memiliki stok awal 100 dan dapat memproduksi 2 sandaran lagi
\[
x_x \le 100 +2x_z \\
x_x -2x_z \le 100
\]
- jumlah minimum model a dan b yang diproduksi
\[
x_x+x_y \ge 1000
\]
Grafis
1 |
1 |
-10 |
<= |
500 |
4 |
3 |
-20 |
<= |
200 |
1 |
0 |
-2 |
<= |
100 |
1 |
1 |
0 |
=> |
1000 |
\[
4x_x+3x_y-20x_z \le 200\\
x_x+x_y-10x_z \le 500\\
x_x -2x_z \le 100\\
x_x+x_y \ge 1000\\
x_x \ge 0\\
x_y \ge o\\
x_z \ge 0
\]
Grafiknya dapat dicek disini
Manual
Kita dapat menggunakan metode simplex untuk mengerjakan solusi manualnya.
Langkah-langkah :
- Mengubah semua kendala ke Bentuk Kanonik Simpleks (yang semula menggunakan tanda pertidaksamaanmen jadi persamaan) dengan menambah perubah (variabel) SlackS. Perubah-perubah slack yang ada dimasukkan(ditambahkan) kefungsi sasaran dan diberikoefisien 0.
- Tabel yang kita miliki sudah minimum jika semua \(Z_j-C_j \le 0\)
- Jika ada \(Z_j-C_j > 0\) (positif) maka dibuat tabel baru dengan cara sebagai berikut :
- Menentukan kolom kunci yaitu memilih nilai \(Z_j- C_j\) yang terbesar. Sebut dengan \(Z_k-C_k\) maka kolom ke-k disebut kolom kunci.
- Pada kolom ke-k dilakukan pemeriksaan terhadap nilai \(a_{ik}\).
- Menentukan baris kunci, yaitu nilai Ri yang terkecil, selanjutnya baris yg memuat Ri terkecil disebut baris kunci.
- Kemudian disusun tabel baru sebagai berikut (dimulai dari baris kunci baru):
- elemen baris kunci baru = elemen baris kunci lama dibagi \(a_{ik}\)
- elemen baris baru = elemen baris lama - (\(a_{ik}\) x elemen baris r baru)
- Kemudian tentukan lagi nilai Xi, Ci, Zj , Zj - Cj
Keterangan : * Baris Cj diisi dengan para koefisien Fungsi Tujuan (sasaran) * Baris Xj diisi dengan nama-nama perubah (variabel) yang ada. * Kolom B diisi dengan nama-nama perubah yang menjadi basis (variabel yang menyusun matriks Identitas) . * Kolom Cb diisi dengan para koefisien perubah yang menjadi basis * Kolom Xb diisi dengan para konstanta fungsi kendala (Nilai Sebelah Kanan/NSK). * Baris Zj diisi dengan rumus:\(\sum_{i=1}^m C_ba_{ij}\), j=1,…,n. * Kolom Ri diisi dengan rumus \(Ri = Xb/a_{ik}\) (aik = elemen elemen yang berada dalam kolom kunci, dan Ri dihitung hanya untuk aik ≥ 0)
\[
Z_{min}=30x_x+40x_y+80x_z+0S_1+0S_2+0s_3+0s_4+MV\\
4x_x+3x_y-20x_z + S_1= 200\\
x_x+x_y-10x_z +S_2= 500\\
x_x -2x_z+S_3= 100\\
x_x+x_y -S_4+V= 1000
\]
\[
Z= 48666.67 \\
x = 422\\
y = 578\\
z = 161
\]
Kita dapat nilai minimum costnya yaitu 48666.67 dengan memproduksi model A 422, model B 578 dan balok 161.
R
lpsolve
## Loading required package: lpSolve
C <- c(30, 40, 80)
A <- matrix(c(1, 1, -10,
4, 3, -20,
1, 0, -2,
1, 1, 0), nrow=4, byrow=TRUE)
B <- c(500, 200, 100, 1000)
constranints_direction <- c("<=", "<=", "<=", ">=")
optimum <- lp(direction="min",
objective.in = C,
const.mat = A,
const.dir = constranints_direction,
const.rhs = B,
all.int = T)
# Print status: 0 = success, 2 = no feasible solution
print(optimum$status)
## [1] 0
# menunjukkan nilai X_x, X_y dan X_z
best_sol <- optimum$solution
names(best_sol) <- c("x_x", "x_y", "x_z")
print(best_sol)
## x_x x_y x_z
## 420 580 161
yang diproduksi oleh perusahaan yaitu : * Model A = 420 * Model B = 580 * Balok = 161
# Cek nilai biaya pada solusi optimal
print(paste("Total Biaya minimum: ", optimum$objval, sep=""))
## [1] "Total Biaya minimum: 48680"
rm(optimum, constranints_direction, best_sol)
lpSolveAPI
## Loading required package: lpSolveAPI
lprec <- make.lp(nrow = 4, ncol = 3)
lp.control(lprec, sense="min")
## $anti.degen
## [1] "fixedvars" "stalling"
##
## $basis.crash
## [1] "none"
##
## $bb.depthlimit
## [1] -50
##
## $bb.floorfirst
## [1] "automatic"
##
## $bb.rule
## [1] "pseudononint" "greedy" "dynamic" "rcostfixing"
##
## $break.at.first
## [1] FALSE
##
## $break.at.value
## [1] -1e+30
##
## $epsilon
## epsb epsd epsel epsint epsperturb epspivot
## 1e-10 1e-09 1e-12 1e-07 1e-05 2e-07
##
## $improve
## [1] "dualfeas" "thetagap"
##
## $infinite
## [1] 1e+30
##
## $maxpivot
## [1] 250
##
## $mip.gap
## absolute relative
## 1e-11 1e-11
##
## $negrange
## [1] -1e+06
##
## $obj.in.basis
## [1] TRUE
##
## $pivoting
## [1] "devex" "adaptive"
##
## $presolve
## [1] "none"
##
## $scalelimit
## [1] 5
##
## $scaling
## [1] "geometric" "equilibrate" "integers"
##
## $sense
## [1] "minimize"
##
## $simplextype
## [1] "dual" "primal"
##
## $timeout
## [1] 0
##
## $verbose
## [1] "neutral"
set.type(lprec, 1:3, type=c("integer"))
set.objfn(lprec, C)
# Tambahkan kendala
add.constraint(lprec, A[1, ], "<=", B[1])
add.constraint(lprec, A[2, ], "<=", B[2])
add.constraint(lprec, A[3, ], "<=", B[3])
add.constraint(lprec, A[4, ], ">=", B[4])
## Model name:
## C1 C2 C3
## Minimize 30 40 80
## R1 0 0 0 free 0
## R2 0 0 0 free 0
## R3 0 0 0 free 0
## R4 0 0 0 free 0
## R5 1 1 -10 <= 500
## R6 4 3 -20 <= 200
## R7 1 0 -2 <= 100
## R8 1 1 0 >= 1000
## Kind Std Std Std
## Type Int Int Int
## Upper Inf Inf Inf
## Lower 0 0 0
## [1] 0
Nilai \(x_x, x_y , x_z\)
## [1] 420 580 161
Nilai fungsi tujuan
## [1] 48680
Python
Pengerjaan python saya lakukan di colabs
LS0tDQp0aXRsZTogIlR1Z2FzIE9wdGltYXNpICINCnN1YnRpdGxlOiAiV2VlayA0Ig0KYXV0aG9yOiAiVmFuZXNzYSBTdXBpdCAoMjAxOTQ5MjAwMTQpIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDogDQogICAgaHRtbF9kb2N1bWVudDogbnVsbA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHRoZW1lOiBzYW5kc3RvbmUNCiAgICBjc3M6IHN0eWxlMS5jc3MNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCi0tLQ0KDQpgYGB7ciBsb2dvLCBlY2hvPUZBTFNFLGZpZy5hbGlnbj0nY2VudGVyJywgb3V0LndpZHRoID0gJzMwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygibG9nby5wbmciKQ0KYGBgDQoNCkVtYWlsICZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyZuYnNwOzogIGRzY2llbmNlbGFic0BvdXRsb29rLmNvbSA8YnI+DQpSUHVicyAgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7OiBodHRwczovL3JwdWJzLmNvbS92YW5lc3Nhc3VwaXQvIDxicj4NCkdpdGh1YiAgJm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7ICZuYnNwOyAmbmJzcDsgOiBodHRwczovL2dpdGh1Yi5jb20vdmFuZXNzYXN1cGl0LyA8YnI+DQpKdXJ1c2FuICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDs6IFtTdGF0aXN0aWthXShodHRwczovL21hdGFuYXVuaXZlcnNpdHkuYWMuaWQvP2x5PWFjYWRlbWljJmM9c2IpIDxicj4NCkFkZHJlc3MgICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyA6IEFSQSBDZW50ZXIsIE1hdGFuYSBVbml2ZXJzaXR5IFRvd2VyIDxicj4NCiZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7ICZuYnNwOyAmbmJzcDsgJm5ic3A7Jm5ic3A7IEpsLiBDQkQgQmFyYXQgS2F2LCBSVC4xLCBDdXJ1ZyBTYW5nZXJlbmcsIEtlbGFwYSBEdWEsIFRhbmdlcmFuZywgQmFudGVuIDE1ODEwLg0KDQoqKioqDQojIFNPQUwNCg0KU2VidWFoIHBlcnVzYWhhYW4gbWVtcHJvZHVrc2kgZHVhIG1vZGVsIGt1cnNpOiBBIGRhbiBCLiBNb2RlbCBBIG1lbWJ1dHVoa2FuIDQgYmFsb2ssIDEgZHVkdWthbiBrdXJzaSwgZGFuIDEgc2FuZGFyYW4ga3Vyc2kuIFNlZGFuZ2thbiBtb2RlbCBCIG1lbWJ1dHVoa2FuIDMgYmFsb2sgZGFuIDEgZHVkdWthbiBrdXJzaS4gUGVydXNhaGFhbiBtZW1pbGlraSBzdG9rIGF3YWwgMjAwIGJhbG9rLCA1MDAgZHVkdWthbiBrdXJzaSwgZGFuIDEwMCBzYW5kYXJhbiBrdXJzaS4gSmlrYSBwZXJ1c2FoYWFuIG1lbWJ1dHVoa2FuIGxlYmloIGJhbnlhayBiYWxvaywgZHVkdWthbiBrdXJzaSwgZGFuIHNhbmRhcmFuIGt1cnNpLCBtZXJla2EgZGFwYXQgbWVtYmVsaSBrYXl1IGJhbG9rIHN0YW5kYXIsIHlhbmcgaGFyZ2FueWEgODAgZXVybyBwZXIgYmFsb2suIFBlcnVzYWhhYW4gZGFwYXQgbWVtcHJvZHVrc2kgMjAgYmFsb2ssIDEwIGR1ZHVrYW4ga3Vyc2ksICBkYW4gMiBzYW5kYXJhbiBrdXJzaSBkYXJpIGJhbG9rIGtheXUgc3RhbmRhci4gQmlheWEgcHJvZHVrc2kgbW9kZWwgQSBhZGFsYWggMzAgZXVyby9rdXJzaSwgc2VkYW5na2FuIGJpYXlhIG1vZGVsIEIgYWRhbGFoIDQwIGV1cm8va3Vyc2kuIEppa2EgcGVydXNhaGFhbiBtZW5naW5mb3JtYXNpa2FuIGJhaHdhIGp1bWxhaCBtaW5pbXVtIGt1cnNpIHlhbmcgaGFydXMgZGlwcm9kdWtzaSBhZGFsYWggMTAwMCB1bml0IHBlciBidWxhbi4gVGVudHVrYW4gbW9kZWwgcHJvZ3JhbSBsaW5pZXIsIHlhbmcgZGFwYXQgbWVtaW5pbWFsa2FuIHRvdGFsIGJpYXlhLg0KDQpTZWxlc2FpYWthbiBwZXJtYXNhbGFoYW4gb3B0aW1hc2kgZGlhdGFzIGRlbmdhbiBjYXJhOg0KDQoqIEdyYWZpaw0KKiBNYW51YWwNCiogTWVuZ2d1bmFrYW4gUg0KKiBNZW5nZ3VuYWthbiBQeXRob24NCg0KIyBTb2x1dGlvbnMNCg0KS2l0YSBrb252ZXJzaSBzb2FsIHNlYmVsdW1ueWEgZGFsYW0gYmVudHVrIHRhYmVsIHRlcmxlYmloIGRhaHVsdS4NCg0KS2V0ZXJhbmdhbiA6DQoNCiogeCA9IE1vZGVsIEENCiogeSA9IE1vZGVsIEINCiogeiA9IEJhbG9rDQoNCg0KKy0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLSsNCnwgICAgICAgICAgICAgfCBCYWxvayAgICB8ZHVkdWthbiBrdXJzaXxzYW5kYXJhbiAgfEJpYXlhICAgICAgICB8DQorPT09PT09PT09PT09PSs9PT09PT09PT09Kz09PT09PT09PT09PT0rPT09PT09PT09PSs9PT09PT09PT09PT09Kw0KfCB4ICAgICAgICAgICB8NCAgICAgICAgIHwgMSAgICAgICAgICAgfDEgICAgICAgICB8MzAgICAgICAgICAgIHwNCistLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0rDQp8IHkgICAgICAgICAgIHwzICAgICAgICAgfDEgICAgICAgICAgICB8ICAgICAgICAgIHw0MCAgICAgICAgICAgfA0KKy0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLSsNCnwgeiAgICAgICAgICAgfDIwICAgICAgICB8MTAgICAgICAgICAgIHwyICAgICAgICAgfDgwICAgICAgICAgICB8DQorLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tKw0KfEtldGVyc2VkaWFhbiB8MjAwICAgICAgIHw1MDAgICAgICAgICAgfDEwMCAgICAgICB8ICAgICAgICAgICAgIHwNCistLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0rDQoNCg0KKipGdW5nc2kgVHVqdWFuKiogOg0KDQpEZW5nYW4gbWVtcGVyaGF0aWthbiBiaWF5YSBwcm9kdWtzaSBtb2RlbCBBIGFkYWxhaCAzMCBldXJvL2t1cnNpLCBiaWF5YSBtb2RlbCBCIGFkYWxhaCA0MCBldXJvL2t1cnNpLCBkYW4gYmlheWEgYmFsb2sgODAgZXVyby9rdXJzaQ0KDQokJA0KTWluKDMweF94KzQweF95KzgweF96KQ0KJCQNCg0KKipGdW5nc2kgQmF0YXNhbioqIDoNCg0KKiBVbnR1ayBwcm9kdWtzaSBiYWxvayBwZXJ1c2FoYWFuIG1lbWlsaWtpIHN0b2sgYXdhbCAyMDAgZGFuIGRhcGF0IG1lbXByb2R1a3NpIDIwIGJhbG9rIGxhZ2kNCg0KJCQgDQo0eF94KzN4X3kgXGxlIDIwMCsyMHhfelxcDQo0eF94KzN4X3ktMjB4X3ogXGxlIDIwMA0KJCQNCg0KKiBVbnR1ayBwcm9kdWtzaSBkdWR1a2FuIGt1cnNpIHBlcnVzYWhhYW4gbWVtaWxpa2kgc3RvayBhd2FsIDUwMCBkYW4gZGFwYXQgbWVtcHJvZHVrc2kgMTAgZHVkdWthbiBsYWdpIA0KDQokJA0KeF94K3hfeSBcbGUgNTAwKzEweF96XFwNCnhfeCt4X3ktMTB4X3ogXGxlIDUwMA0KJCQNCg0KKiBVbnR1ayBwcm9kdWtzaSBzYW5kYXJhbiBrdXJzaSBwZXJ1c2FoYWFuIG1lbWlsaWtpIHN0b2sgYXdhbCAxMDAgZGFuIGRhcGF0IG1lbXByb2R1a3NpIDIgc2FuZGFyYW4gbGFnaSANCg0KJCQNCnhfeCBcbGUgMTAwICsyeF96IFxcDQp4X3ggLTJ4X3ogXGxlIDEwMA0KJCQNCg0KKiBqdW1sYWggbWluaW11bSBtb2RlbCBhIGRhbiBiIHlhbmcgZGlwcm9kdWtzaQ0KDQokJA0KeF94K3hfeSBcZ2UgMTAwMA0KJCQNCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkocmV0aWN1bGF0ZSkNCmxpYnJhcnkoUmNwcCkNCnVzZV9jb25kYWVudigicHkzOCIsIHJlcXVpcmVkID0gVFJVRSkNCmBgYA0KDQojIyBHcmFmaXMNCg0KKy0tLS0tKy0tLS0tLSstLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0rDQp8eCAgICB8IHkgICAgfHogICB8YXJhaCBrZW5kYWxhfEtldGVyc2VkaWFhbiAgIHwNCis9PT09PSs9PT09PT0rPT09PSs9PT09PT09PT09PT0rPT09PT09PT09PT09PT09Kw0KfDEgICAgfDEgICAgIHwtMTAgfDw9ICAgICAgICAgIHw1MDAgICAgICAgICAgICB8DQorLS0tLS0rLS0tLS0tKy0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLSsNCnw0ICAgIHwzICAgICB8LTIwIHw8PSAgICAgICAgICB8MjAwICAgICAgICAgICAgfA0KKy0tLS0tKy0tLS0tLSstLS0tKy0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0rDQp8MSAgICB8MCAgICAgfC0yICB8PD0gICAgICAgICAgfDEwMCAgICAgICAgICAgIHwNCistLS0tLSstLS0tLS0rLS0tLSstLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tKw0KfDEgICAgfDEgICAgIHwwICAgfD0+ICAgICAgICAgIHwxMDAwICAgICAgICAgICB8DQorLS0tLS0rLS0tLS0tKy0tLS0rLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLSsNCg0KJCQgDQo0eF94KzN4X3ktMjB4X3ogXGxlIDIwMFxcDQp4X3greF95LTEweF96IFxsZSA1MDBcXA0KeF94IC0yeF96IFxsZSAxMDBcXA0KeF94K3hfeSBcZ2UgMTAwMFxcDQp4X3ggXGdlIDBcXA0KeF95IFxnZSBvXFwNCnhfeiBcZ2UgMA0KJCQNCg0KR3JhZmlrbnlhIGRhcGF0IGRpY2VrIFtkaXNpbmldKGh0dHBzOi8vY29sYWIucmVzZWFyY2guZ29vZ2xlLmNvbS9kcml2ZS8xWTdoZDRRSE1rbi1HcVJXZkg5LTl3SXh4dVNaa2hzeWs/dXNwPXNoYXJpbmcpDQoNCiMjIE1hbnVhbA0KDQpLaXRhIGRhcGF0IG1lbmdndW5ha2FuIG1ldG9kZSBzaW1wbGV4IHVudHVrIG1lbmdlcmpha2FuIHNvbHVzaSBtYW51YWxueWEuDQoNCioqTGFuZ2thaC1sYW5na2FoKiogOg0KDQoqIE1lbmd1YmFoIHNlbXVhIGtlbmRhbGEga2UgQmVudHVrIEthbm9uaWsgU2ltcGxla3MgKHlhbmcgc2VtdWxhIG1lbmdndW5ha2FuIHRhbmRhIHBlcnRpZGFrc2FtYWFubWVuIGphZGkgcGVyc2FtYWFuKSBkZW5nYW4gbWVuYW1iYWggcGVydWJhaCAodmFyaWFiZWwpIFNsYWNrUy4gUGVydWJhaC1wZXJ1YmFoIHNsYWNrIHlhbmcgYWRhIGRpbWFzdWtrYW4oZGl0YW1iYWhrYW4pIGtlZnVuZ3NpIHNhc2FyYW4gZGFuIGRpYmVyaWtvZWZpc2llbiAwLg0KKiBUYWJlbCB5YW5nIGtpdGEgbWlsaWtpIHN1ZGFoIG1pbmltdW0gamlrYSBzZW11YSAkWl9qLUNfaiBcbGUgMCQNCiogSmlrYSBhZGEgJFpfai1DX2ogPiAwJCAocG9zaXRpZikgbWFrYSBkaWJ1YXQgdGFiZWwgYmFydSBkZW5nYW4gY2FyYSBzZWJhZ2FpIGJlcmlrdXQgOg0KICArIE1lbmVudHVrYW4ga29sb20ga3VuY2kgeWFpdHUgbWVtaWxpaCBuaWxhaSAkWl9qLSBDX2okIHlhbmcgdGVyYmVzYXIuIFNlYnV0IGRlbmdhbiAkWl9rLUNfayQgbWFrYSBrb2xvbSBrZS1rIGRpc2VidXQga29sb20ga3VuY2kuDQogICsgUGFkYSBrb2xvbSBrZS1rIGRpbGFrdWthbiBwZW1lcmlrc2FhbiB0ZXJoYWRhcCBuaWxhaSAkYV97aWt9JC4NCiogTWVuZW50dWthbiBiYXJpcyBrdW5jaSwgeWFpdHUgbmlsYWkgUmkgeWFuZyB0ZXJrZWNpbCwgc2VsYW5qdXRueWEgYmFyaXMgeWcgbWVtdWF0IFJpIHRlcmtlY2lsIGRpc2VidXQgYmFyaXMga3VuY2kuDQoqIEtlbXVkaWFuIGRpc3VzdW4gdGFiZWwgYmFydSBzZWJhZ2FpIGJlcmlrdXQgKGRpbXVsYWkgZGFyaSBiYXJpcyBrdW5jaSBiYXJ1KToNCiAgKyBlbGVtZW4gYmFyaXMga3VuY2kgYmFydSA9IGVsZW1lbiBiYXJpcyBrdW5jaSBsYW1hIGRpYmFnaSAkYV97aWt9JA0KICArIGVsZW1lbiBiYXJpcyBiYXJ1ID0gZWxlbWVuIGJhcmlzIGxhbWEgLSAoJGFfe2lrfSQgeCBlbGVtZW4gYmFyaXMgciBiYXJ1KQ0KKiBLZW11ZGlhbiB0ZW50dWthbiBsYWdpIG5pbGFpIFhpLCBDaSwgWmogLCBaaiAtIENqDQoNCioqS2V0ZXJhbmdhbioqIDoNCiogQmFyaXMgQ2ogZGlpc2kgZGVuZ2FuIHBhcmEga29lZmlzaWVuIEZ1bmdzaSBUdWp1YW4gKHNhc2FyYW4pDQoqIEJhcmlzIFhqIGRpaXNpIGRlbmdhbiBuYW1hLW5hbWEgcGVydWJhaCAodmFyaWFiZWwpIHlhbmcgYWRhLg0KKiBLb2xvbSBCIGRpaXNpIGRlbmdhbiBuYW1hLW5hbWEgcGVydWJhaCB5YW5nIG1lbmphZGkgYmFzaXMgKHZhcmlhYmVsIHlhbmcgbWVueXVzdW4gbWF0cmlrcyBJZGVudGl0YXMpIC4NCiogS29sb20gQ2IgZGlpc2kgZGVuZ2FuIHBhcmEga29lZmlzaWVuIHBlcnViYWggeWFuZyBtZW5qYWRpIGJhc2lzDQoqIEtvbG9tIFhiIGRpaXNpIGRlbmdhbiBwYXJhIGtvbnN0YW50YSBmdW5nc2kga2VuZGFsYSAoTmlsYWkgU2ViZWxhaCBLYW5hbi9OU0spLg0KKiBCYXJpcyBaaiBkaWlzaSBkZW5nYW4gcnVtdXM6JFxzdW1fe2k9MX1ebSBDX2JhX3tpan0kLCBqPTEsLi4uLG4uDQoqIEtvbG9tIFJpIGRpaXNpIGRlbmdhbiBydW11cyAkUmkgPSBYYi9hX3tpa30kIChhaWsgPSBlbGVtZW4gZWxlbWVuIHlhbmcgYmVyYWRhIGRhbGFtIGtvbG9tIGt1bmNpLCBkYW4gUmkgZGloaXR1bmcgaGFueWEgdW50dWsgYWlrIOKJpSAwKQ0KDQokJA0KWl97bWlufT0zMHhfeCs0MHhfeSs4MHhfeiswU18xKzBTXzIrMHNfMyswc180K01WXFwNCjR4X3grM3hfeS0yMHhfeiArIFNfMT0gMjAwXFwNCnhfeCt4X3ktMTB4X3ogK1NfMj0gNTAwXFwNCnhfeCAtMnhfeitTXzM9IDEwMFxcDQp4X3greF95IC1TXzQrVj0gMTAwMA0KJCQNCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnVGFiZWwyLmpwZWcnKQ0KYGBgDQokJA0KWj0gIDQ4NjY2LjY3IFxcDQp4ID0gNDIyXFwNCnkgPSA1NzhcXA0KeiA9IDE2MQ0KJCQNCg0KS2l0YSBkYXBhdCBuaWxhaSBtaW5pbXVtIGNvc3RueWEgeWFpdHUgNDg2NjYuNjcgZGVuZ2FuIG1lbXByb2R1a3NpIG1vZGVsIEEgNDIyLCBtb2RlbCBCIDU3OCBkYW4gYmFsb2sgMTYxLiANCg0KIyMgUg0KDQojIyMgbHBzb2x2ZQ0KDQpgYGB7cn0NCnJlcXVpcmUobHBTb2x2ZSkNCg0KQyA8LSBjKDMwLCA0MCwgODApDQoNCkEgPC0gbWF0cml4KGMoMSwgMSwgLTEwLA0KICAgICAgICAgICAgICA0LCAzLCAtMjAsDQogICAgICAgICAgICAgIDEsIDAsIC0yLA0KICAgICAgICAgICAgICAxLCAxLCAwKSwgbnJvdz00LCBieXJvdz1UUlVFKQ0KDQoNCkIgPC0gYyg1MDAsIDIwMCwgMTAwLCAxMDAwKQ0KDQoNCmNvbnN0cmFuaW50c19kaXJlY3Rpb24gIDwtIGMoIjw9IiwgIjw9IiwgIjw9IiwgIj49IikNCg0Kb3B0aW11bSA8LSAgbHAoZGlyZWN0aW9uPSJtaW4iLA0KICAgICAgICAgICAgICAgb2JqZWN0aXZlLmluID0gQywNCiAgICAgICAgICAgICAgIGNvbnN0Lm1hdCA9IEEsDQogICAgICAgICAgICAgICBjb25zdC5kaXIgPSBjb25zdHJhbmludHNfZGlyZWN0aW9uLA0KICAgICAgICAgICAgICAgY29uc3QucmhzID0gQiwNCiAgICAgICAgICAgICAgIGFsbC5pbnQgPSBUKQ0KYGBgDQoNCg0KYGBge3J9DQojIFByaW50IHN0YXR1czogMCA9IHN1Y2Nlc3MsIDIgPSBubyBmZWFzaWJsZSBzb2x1dGlvbg0KcHJpbnQob3B0aW11bSRzdGF0dXMpDQpgYGANCg0KDQpgYGB7cn0NCiMgbWVudW5qdWtrYW4gbmlsYWkgWF94LCBYX3kgZGFuIFhfeg0KYmVzdF9zb2wgPC0gb3B0aW11bSRzb2x1dGlvbg0KbmFtZXMoYmVzdF9zb2wpIDwtIGMoInhfeCIsICJ4X3kiLCAieF96IikgDQpwcmludChiZXN0X3NvbCkNCmBgYA0KDQp5YW5nIGRpcHJvZHVrc2kgb2xlaCBwZXJ1c2FoYWFuIHlhaXR1IDoNCiogTW9kZWwgQSA9IDQyMA0KKiBNb2RlbCBCID0gNTgwDQoqIEJhbG9rID0gMTYxDQoNCmBgYHtyfQ0KIyBDZWsgbmlsYWkgYmlheWEgcGFkYSBzb2x1c2kgb3B0aW1hbA0KcHJpbnQocGFzdGUoIlRvdGFsIEJpYXlhIG1pbmltdW06ICIsIG9wdGltdW0kb2JqdmFsLCBzZXA9IiIpKQ0KYGBgDQoNCmBgYHtyfQ0Kcm0ob3B0aW11bSwgY29uc3RyYW5pbnRzX2RpcmVjdGlvbiwgYmVzdF9zb2wpDQpgYGANCg0KIyMjIGxwU29sdmVBUEkNCg0KYGBge3J9DQpyZXF1aXJlKGxwU29sdmVBUEkpDQoNCmxwcmVjIDwtIG1ha2UubHAobnJvdyA9IDQsIG5jb2wgPSAzKQ0KDQpscC5jb250cm9sKGxwcmVjLCBzZW5zZT0ibWluIikNCg0Kc2V0LnR5cGUobHByZWMsIDE6MywgdHlwZT1jKCJpbnRlZ2VyIikpDQoNCnNldC5vYmpmbihscHJlYywgQykNCg0KIyBUYW1iYWhrYW4ga2VuZGFsYQ0KYWRkLmNvbnN0cmFpbnQobHByZWMsIEFbMSwgXSwgIjw9IiwgQlsxXSkNCmFkZC5jb25zdHJhaW50KGxwcmVjLCBBWzIsIF0sICI8PSIsIEJbMl0pDQphZGQuY29uc3RyYWludChscHJlYywgQVszLCBdLCAiPD0iLCBCWzNdKQ0KYWRkLmNvbnN0cmFpbnQobHByZWMsIEFbNCwgXSwgIj49IiwgQls0XSkNCmBgYA0KDQpgYGB7cn0NCmxwcmVjDQpzb2x2ZShscHJlYykNCmBgYA0KDQpOaWxhaSAkeF94LCB4X3kgLCB4X3okDQpgYGB7cn0NCmdldC52YXJpYWJsZXMobHByZWMpDQpgYGANCg0KTmlsYWkgZnVuZ3NpIHR1anVhbg0KYGBge3J9DQpnZXQub2JqZWN0aXZlKGxwcmVjKQ0KYGBgDQoNCiMjIFB5dGhvbg0KDQpQZW5nZXJqYWFuIHB5dGhvbiBzYXlhIGxha3VrYW4gZGkgW2NvbGFic10oaHR0cHM6Ly9jb2xhYi5yZXNlYXJjaC5nb29nbGUuY29tL2RyaXZlLzFrekE2RzBMNW50UThvaERObXJpakpVeWg3WFM1WjNCbD91c3A9c2hhcmluZykgDQo=