Thiết lập phương pháp Monte Carlo mô phỏng giá trị lợi nhuận
Trong ứng dụng này, mã cổ phiếu được lựa chọn phân tích từ tệp dữ
liệu là mã DVN trong 120 ngày tới. Dữ liệu bao gồm lịch sử các mã cổ
phiếu từ 04/01/2021 tới 30/12/2022 và được tải xuống dưới định dạng file
csv. Link file dữ liệu: https://bom.so/6FlMwf
#Tải xuống các packages sau
install.packages("tidyquant")
install.packages("quantmod")
install.packages("zoo")
#Sử dụng các thư viện sau
library(tidyquant)
library(quantmod)
library(zoo)
Trước khi bắt đầu phân tích dữ liệu cổ phiếu, ta cần tải xuống các
gói thư viện liên quan phục vụ cho quá trình sử dụng sau này.
#Thay đổi thư mục làm việc phù hợp với thư mục đang sử dụng hiện tại
setwd("D:/KPIM/PVI")
#Tải dữ liệu lên R
Stock <- read.csv("StockData.csv", header = TRUE)
#Lọc dữ liệu với mã cổ phiếu mong muốn phân tích
DVN <- Stock[Stock$ma == "DVN",]
#Định dạng ngày của dữ liệu
DVN$ngay <- as.Date(DVN$ngay)
#Chuyển đổi dữ liệu của mã cổ phiếu thành dữ liệu theo chuỗi thời gian và chọn giá đóng cửa làm giá trị phân tích lợi nhuận hàng ngày
DVN_xts <- xts(DVN$gia_dong_cua, start = min(DVN$ngay), end = max(DVN$ngay), order.by = DVN$ngay, frequency = 1)
Để tải dữ liệu vào sử dụng, cần thiết lập thư mục làm việc hiện tại
và tất cả tệp dữ liệu cần được lưu trong thư mục này.
#Tính lợi nhuận hàng ngày
daily_returns <- dailyReturn(DVN_xts)
# Tính giá trị trung bình của lợi nhuận hàng ngày
daily_mean <- mean(daily_returns)
# Tính độ lệch chuẩn của lợi nhuận hàng ngày
daily_std_dev <- sd(daily_returns)
Trong mô phỏng này, lợi nhuận thị trường cổ phiếu được giả định là
phân phối chuẩn và các thông số được tính toán như lợi nhuận hàng ngày,
giá trị trung bình của lợi nhuận hàng ngày, độ lệch chuẩn của lợi nhuận.
Các thông số này sẽ được sử dụng để tạo ra các biến ngẫu nhiên trong mô
hình.
# Xác định số ngày cần mô phỏng
no_of_days <- 120
# Xác định giá khởi điểm của quá trình mô phỏng
starting_price <- last(DVN$gia_dong_cua)[[1]]
Dữ liệu sẽ được mô phỏng trong 120 ngày tới và giá khởi điểm của ngày
đầu tiên trong thời điểm mô phỏng sẽ là giá đóng cửa cuối cùng trong dữ
liệu giá lịch sử của mã cổ phiếu.
Lợi nhuận hàng ngày được tạo bằng cách sử dụng phân phối chuẩn với
giá trị trung bình và độ lệch chuẩn đã được tính toán trước đó. Để tính
giá của cổ phiếu, cần thực hiện tính tích lũy của lợi nhuận và giá khởi
điểm. Kết quả dưới đây là biểu đồ thể hiện giá mô phỏng của mã cổ phiếu
trong 120 ngày tới.
# Tạo cơ sở số lượng các mẫu ngẫu nhiên sẽ được tạo
set.seed(101)
# Tính giá trị lợi nhuận dựa trên các giá trị ngẫu nhiên
returns <- 1+rnorm(no_of_days, mean=daily_mean, sd=daily_std_dev)
# Tính giá cổ phiếu thông qua tích lũy của giá khởi điểm và lợi nhuận
prices <- cumprod(c(starting_price, returns))
# Vẽ biểu đồ thể hiện mô phỏng của giá cổ phiếu trong tương lai
plot(prices, type='l', ylab="Giá cổ phiếu", xlab="Số ngày", main = "Mô phỏng giá của mã cổ phiếu DVN")

Tuy nhiên, chỉ chạy một mô phỏng sẽ không đủ để đưa ra kết luận. Vì
vậy, để đưa ra kết quả sát với thực tế nhất, ta sẽ thực hiện chạy 1001
mô phỏng trong 120 ngày với mỗi mô phỏng. Dữ liệu được lưu trữ hai chiều
dưới dạng ma trận và 50 mô phỏng đầu tiên được biểu diễn trong đồ thị
dưới đây.
# Số lượng thực hiện vòng lặp mô phỏng
no_of_sims <- 1001
# Danh sách giá trị của lợi nhuận
returns_list <- matrix(0, nrow = no_of_sims, ncol = no_of_days)
# Danh sách giá của cổ phiếu
prices_list <- matrix(0, nrow = no_of_sims, ncol = no_of_days+1)
# Vòng lặp thực hiện mô phỏng trong số ngày được chỉ định
for(i in 1:no_of_sims) {
returns_list[i,] <- rnorm(no_of_days, mean=daily_mean, sd=daily_std_dev)
prices_list[i,] <- cumprod(c(starting_price, 1+returns_list[i,]))
}
# Biểu diễn dưới dạng đồ thị 50 mô phỏng đầu tiên
plot(prices_list[1,], type='l', ylab="Giá cổ phiếu", xlab="Số ngày", main = "Mô phỏng giá của mã cổ phiếu DVN", ylim=c(10000, 50000))
for(i in 1:50) {
lines(prices_list[i, ], type = 'l', col=i)
}

Như chúng ta có thể thấy, kết quả của các mô phỏng có sự đa dạng khác
nhau. Một số kết thúc dưới điểm bắt đầu và một số tăng rất nhanh. Dựa
trên 50 mô phỏng đầu tiên, mã cổ phiếu có xu hướng lợi nhuận âm trong
thời gian tới. Để xem xét cụ thể hơn, ta sẽ tính tổng lợi nhuận thu
về:
# Tạo mảng đa chiều chứa dữ liệu của lợi nhuận
total_returns <- array(NA, dim= no_of_sims, dimnames=NULL)
# Vòng lặp nhằm tính giá trị của tổng lợi nhuận với mỗi mô phỏng
for (i in 1:no_of_sims) {
total_returns[i] <- (prices_list[i, 121]-prices_list[i, 1])/prices_list[i,1]
}
# Thống kê kết quả của lợi nhuận thu về
summary(total_returns)
Min. 1st Qu. Median Mean 3rd Qu. Max.
-0.69017 -0.27815 -0.12232 -0.10020 0.03253 0.96066
Kết luận cho thấy mô phỏng có xu hướng lợi nhuận âm, hơn 50% kết quả
mô phỏng cho ra giá trị < 0 bởi giá trị trung vị, giá trị trung bình
và phân vị thứ nhất đều thể hiện điều này. Để trực quan hóa kết quả, ta
có thể xem xét 1 số biểu đồ sau:
par(mfrow=c(1,3))
hist(total_returns, col="blue")
boxplot(total_returns, col="yellow")
plot(density(total_returns))

Các giá trị ngoại lai của biểu đồ Boxplot thường thể hiện mặt dương
của lợi nhuận và biểu đồ thể hiện sự phân phối lệch phải rõ rệt. Điều
này có thể xác nhận dựa trên thông số độ lệch dưới đây:
# Tính độ lệch của dữ liệu lợi nhuận
skewness(total_returns)
[1] 0.7771115
Để hiển thị biểu đồ dễ đọc hơn, sẽ chỉ có ba mô phỏng sẽ được đưa
vào: giá trị trung bình, giá trị tối thiểu và giá trị tối đa. Các dữ
liệu này được lấy từ phân tích dữ liệu với biểu đồ phía trên. Tiếp tục
thực hiện với sự lặp lại của 1001 mô phỏng.
# Tìm vị trí giá trị lớn nhất của lợi nhuận
max <- which.max(total_returns)
# Tìm vị trí giá trị nhỏ nhất của lợi nhuận
min <- which.min(total_returns)
# Tìm vị trí của giá trị trung vị
if (no_of_sims %% 2 != 0) {med <- match(median(total_returns), total_returns)}
# Biểu diễn đồ thị với 3 giá trị trên
plot(prices_list[min,], type='l', ylab="Giá cổ phiếu", xlab="Số ngày", main ="Mô phỏng giá của mã cổ phiếu DVN", ylim=c(9000, 60000), col="red")
if (no_of_sims %% 2 != 0) {lines(prices_list[med, ], type = 'l', col='yellow')}
lines(prices_list[max, ], type = 'l', col='green')

Qua đó, chúng ta có thể dễ dàng nhìn thấy trường hợp giá trị mô phỏng
tốt nhất, xấu nhất và trung bình. Để trả lời câu hỏi đầu tiên, dựa trên
các biểu đồ và dữ liệu, ta có thể kỳ vọng mức lợi nhuận nằm trong khoảng
từ -69.02% đến 96.07%.
# Tính giá trị lợi nhuận có thể đạt được lớn nhất
max_return <- max(total_returns)
max_return
[1] 0.960663
# Tính giá trị lợi nhuận có thể đạt được nhỏ nhất
min_return <- min(total_returns)
min_return
[1] -0.6901731
Để trả lời 2 câu hỏi cuối, ta sẽ thực hiện tính xác suất nhằm đạt
được kết quả mong muốn.
# Mức lợi nhuận cần lớn hơn
condition1 <- sum(total_returns > 0.12)
# Mức lợi nhuận cần nhỏ hơn
condition2 <- sum(total_returns < -0.2)
# Xác suất xảy ra các trường hợp
probability1 <- condition1/no_of_sims
probability2 <- condition2/no_of_sims
# Kết quả đạt được
cat("Xác suất để đạt được lợi nhuận tối thiểu 12% là: ", probability1*100, "%", ". Xác suất để lỗ nhiều hơn 20% khoản đầu tư là: ", probability2*100, "%")
Xác suất để đạt được lợi nhuận tối thiểu 12% là: 17.08292 % . Xác suất để lỗ nhiều hơn 20% khoản đầu tư là: 37.66234 %
LS0tDQp0aXRsZTogIk3DtCBwaOG7j25nIGzhu6NpIG5odeG6rW4gY+G7lSBwaGnhur91IHPhu60gZOG7pW5nIHBoxrDGoW5nIHBow6FwIE1vbnRlIENhcmxvIg0KYXV0aG9yOiAiTGFuIFBoYW0iDQpkYXRlOiAiMjAyMy0wNC0xMCINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjIEdp4bubaSB0aGnhu4d1IHbhu4EgcGjGsMahbmcgcGjDoXAgTW9udGUgQ2FybG8NClBoxrDGoW5nIHBow6FwIE1vbnRlIENhcmxvIGzDoCBt4buZdCBwaMawxqFuZyBwaMOhcCB0w61uaCB0b8OhbiBk4buxYSB0csOqbiB2aeG7h2MgeMOieSBk4buxbmcgbcO0IGjDrG5oIHRvw6FuIGjhu41jIHbDoCBz4butIGThu6VuZyBz4buRIG5n4bqrdSBuaGnDqm4gxJHhu4MgbcO0IHBo4buPbmcgY8OhYyBnacOhIHRy4buLIMSR4bqndSB2w6BvIGPhu6dhIG3DtCBow6xuaC4gS+G6v3QgcXXhuqMgY+G7p2EgY8OhYyBwaMOpcCB0w61uaCDEkcaw4bujYyB0aOG7sWMgaGnhu4duIHRyw6puIGPDoWMgZ2nDoSB0cuG7iyBuw6B5IMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIHTDrW5oIHRvw6FuIGdpw6EgdHLhu4sgxJHhuqd1IHJhIGPhu6dhIHbhuqVuIMSR4buBLg0KDQpUaOG7iyB0csaw4budbmcgY2jhu6luZyBraG/DoW4gdHLhu58gdGjDoG5oIG3hu5l0IMSR4buBIHTDoGkgxJHGsOG7o2MgcXVhbiB0w6JtIGLhu59pIHTDrW5oIGJp4bq/biDEkeG7mW5nIGtow7MgbMaw4budbmcuVsOsIHbhuq15LCDhu6luZyBk4bulbmcgcGjGsMahbmcgcGjDoXAgTW9udGUgQ2FybG8gdHJvbmcgcGjDom4gdMOtY2ggY+G7lSBwaGnhur91IMSRw7NuZyB2YWkgdHLDsiBxdWFuIHRy4buNbmcgZ2nDunAgxJHGsGEgcmEgY8OhYyBk4buxIGLDoW8gduG7gSBnacOhIGPhu5UgcGhp4bq/dSBk4buxYSB0csOqbiBt4buZdCBtw7QgaMOsbmggdG/DoW4gaOG7jWMgY2jDrW5oIHjDoWMsIMSR4buTbmcgdGjhu51pLCBnacO6cCBjw6FjIG5ow6AgxJHhuqd1IHTGsCDEkcawYSByYSBjw6FjIHF1eeG6v3QgxJHhu4tuaCDEkeG6p3UgdMawIHRow7RuZyBtaW5oIGjGoW4uIFR1eSBuaGnDqm4sIGPhuqduIGzGsHUgw70gcuG6sW5nIGPDoWMgZOG7sSBiw6FvIG7DoHkgY2jhu4kgbMOgIMaw4bubYyB0w61uaCB2w6Aga2jDtG5nIMSR4bqjbSBi4bqjbyBy4bqxbmcga+G6v3QgcXXhuqMgdGjhu7FjIHThur8gc+G6vSBkaeG7hW4gcmEgdGhlbyBk4buxIGLDoW8uDQoNCk3hu5dpIGxv4bqhaSBtw7QgcGjhu49uZyBNb250ZSBDYXJsbyDEkeG7gXUgY8OzIGPDoWMgYsaw4bubYyB0aOG7sWMgaGnhu4duIHNhdSDEkcOieToNCg0KLSBYw6FjIMSR4buLbmggbeG7mXQgdOG6rXAgaOG7o3AgY8OhYyDEkeG6p3UgdsOgbyBjw7MgdGjhu4MgdsOgIHBow6JuIGLhu5EgY+G7p2EgY2jDum5nDQoNCi0gVOG6oW8gcmEgY8OhYyDEkeG6p3UgdsOgbyBuZ+G6q3Ugbmhpw6puIHThu6sgbeG7mXQgcGjDom4gYuG7kSB4w6FjIHN14bqldA0KDQotIFRo4buxYyBoaeG7h24gdMOtbmggdG/DoW4geMOhYyDEkeG7i25oDQoNCi0gUGjDom4gdMOtY2gga+G6v3QgcXXhuqMNCg0KIyMgQsOgaSB0b8OhbiBtw7QgcGjhu49uZyBs4bujaSBuaHXhuq1uIGPhu5UgcGhp4bq/dQ0KTeG7mXQgdHJvbmcgbmjhu69uZyBiw6BpIHRvw6FuIHbhu4EgY+G7lSBwaGnhur91IGPDsyB0aOG7gyDhu6luZyBk4bulbmcgcGjGsMahbmcgcGjDoXAgTW9udGUgQ2FybG8gxJHhu4MgZ2nhuqNpIHF1eeG6v3QgY2jDrW5oIGzDoCDEkcawYSByYSBjw6FjIGThu7EgYsOhbyB24buBIGzhu6NpIG5odeG6rW4gdHJvbmcgdMawxqFuZyBsYWkuIFRhIGPDsyB0aOG7gyB04bqhbyByYSBtw7QgaMOsbmggdG/DoW4gaOG7jWMgY+G7p2EgZ2nDoSB0cuG7iyBs4bujaSBuaHXhuq1uIGThu7FhIHRyw6puIGPDoWMgeeG6v3UgdOG7kSBs4buLY2ggc+G7rSB0aGVvIHRo4budaSBnaWFuIGPhu6dhIG3DoyBj4buVIHBoaeG6v3UuIE3DtCBow6xuaCBuw6B5IGPDsyB0aOG7gyBsw6AgbeG7mXQgbcO0IGjDrG5oIG5n4bqrdSBuaGnDqm4sIHRyb25nIMSRw7MgY8OhYyBnacOhIHRy4buLIGPhu6dhIGPDoWMgeeG6v3UgdOG7kSDhuqNuaCBoxrDhu59uZyDEkcaw4bujYyB04bqhbyByYSBi4bqxbmcgY8OhY2ggc+G7rSBk4bulbmcgc+G7kSBuZ+G6q3Ugbmhpw6puLg0KDQpL4bq/dCBxdeG6oyBj4bunYSBtw7QgcGjhu49uZyBNb250ZSBDYXJsbyBuw6B5IHPhur0gY3VuZyBj4bqlcCBjaG8gY2jDum5nIHRhIG3hu5l0IGPDoWkgbmjDrG4gduG7gSBraOG6oyBuxINuZyB44bqjeSByYSBs4bujaSBuaHXhuq1uIGPhu6dhIGPhu5UgcGhp4bq/dSB0cm9uZyB0xrDGoW5nIGxhaSwgZ2nDunAgdGEgxJHGsGEgcmEgcXV54bq/dCDEkeG7i25oIMSR4bqndSB0xrAgdGjDtG5nIG1pbmggaMahbi4gTmjhu69uZyBjw6J1IGjhu49pIHBoxrDGoW5nIHBow6FwIG7DoHkgY8OzIHRo4buDIHRy4bqjIGzhu51pIGJhbyBn4buTbTogDQoNCi0gTOG7o2kgbmh14bqtbiBr4buzIHbhu41uZyB0csOqbiB0aOG7iyB0csaw4budbmcgY+G7lSBwaGnhur91IHRyb25nIG3hu5l0IGtob+G6o25nIHRo4budaSBnaWFuIHThu5tpPw0KKFbDrSBk4bulOiBM4bujaSBuaHXhuq1uIGvhu7MgduG7jW5nIGPDsyB0aOG7gyDEkeG6oXQgxJHGsOG7o2MgdHJvbmcgdsOybmcgMTIwIG5nw6B5IHThu5tpIGzDoCBiYW8gbmhpw6p1PykNCg0KLSBYw6FjIHN14bqldCBj4bunYSB2aeG7h2MgdOG6oW8gbsOqbiBt4buZdCBnacOhIHRy4buLIGzhu6NpIG5odeG6rW4gbmjhuqV0IMSR4buLbmggdHJvbmcgbeG7mXQga2hv4bqjbmcgdGjhu51pIGdpYW4gdOG7m2k/DQooVsOtIGThu6U6IFjDoWMgc3XhuqV0IGPhu6dhIHZp4buHYyDEkeG6oXQgMTIlIGzhu6NpIG5odeG6rW4gdHJvbmcgMTIwIG5nw6B5IHThu5tpIGzDoCBiYW8gbmhpw6p1PykNCg0KLSBYw6FjIHN14bqldCBj4bunYSB2aeG7h2MgbeG6pXQgbmhp4buBdSBoxqFuIG3hu5l0IGdpw6EgdHLhu4sgxJHhuqd1IHTGsCBuaOG6pXQgxJHhu4tuaCB0cm9uZyBt4buZdCBraG/huqNuZyB0aOG7nWkgZ2lhbiB04bubaT8NCihWw60gZOG7pTogWMOhYyBzdeG6pXQgY+G7p2Egdmnhu4djIGzhu5cgbmhp4buBdSBoxqFuIDIwJSBraG/huqNuIMSR4bqndSB0xrAgdHJvbmcgdsOybmcgMTIwIG5nw6B5IHThu5tpIGzDoCBiYW8gbmhpw6p1PykNCg0KIyMgVGhp4bq/dCBs4bqtcCBwaMawxqFuZyBwaMOhcCBNb250ZSBDYXJsbyBtw7QgcGjhu49uZyBnacOhIHRy4buLIGzhu6NpIG5odeG6rW4NClRyb25nIOG7qW5nIGThu6VuZyBuw6B5LCBtw6MgY+G7lSBwaGnhur91IMSRxrDhu6NjIGzhu7FhIGNo4buNbiBwaMOibiB0w61jaCB04burIHThu4dwIGThu68gbGnhu4d1IGzDoCBtw6MgRFZOIHRyb25nIDEyMCBuZ8OgeSB04bubaS4gROG7ryBsaeG7h3UgYmFvIGfhu5NtIGzhu4tjaCBz4butIGPDoWMgbcOjIGPhu5UgcGhp4bq/dSB04burIDA0LzAxLzIwMjEgdOG7m2kgMzAvMTIvMjAyMiB2w6AgxJHGsOG7o2MgdOG6o2kgeHXhu5FuZyBkxrDhu5tpIMSR4buLbmggZOG6oW5nIGZpbGUgY3N2LiBMaW5rIGZpbGUgZOG7ryBsaeG7h3U6IGh0dHBzOi8vYm9tLnNvLzZGbE13Zg0KDQpgYGB7cn0NCiNU4bqjaSB4deG7kW5nIGPDoWMgcGFja2FnZXMgc2F1DQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5cXVhbnQiKQ0KaW5zdGFsbC5wYWNrYWdlcygicXVhbnRtb2QiKQ0KaW5zdGFsbC5wYWNrYWdlcygiem9vIikNCg0KI1Phu60gZOG7pW5nIGPDoWMgdGjGsCB2aeG7h24gc2F1DQpsaWJyYXJ5KHRpZHlxdWFudCkNCmxpYnJhcnkocXVhbnRtb2QpDQpsaWJyYXJ5KHpvbykNCmBgYA0KVHLGsOG7m2Mga2hpIGLhuq90IMSR4bqndSBwaMOibiB0w61jaCBk4buvIGxp4buHdSBj4buVIHBoaeG6v3UsIHRhIGPhuqduIHThuqNpIHh14buRbmcgY8OhYyBnw7NpIHRoxrAgdmnhu4duIGxpw6puIHF1YW4gcGjhu6VjIHbhu6UgY2hvIHF1w6EgdHLDrG5oIHPhu60gZOG7pW5nIHNhdSBuw6B5Lg0KDQpgYGB7cn0NCiNUaGF5IMSR4buVaSB0aMawIG3hu6VjIGzDoG0gdmnhu4djIHBow7kgaOG7o3AgduG7m2kgdGjGsCBt4bulYyDEkWFuZyBz4butIGThu6VuZyBoaeG7h24gdOG6oWkNCnNldHdkKCJEOi9LUElNL1BWSSIpDQoNCiNU4bqjaSBk4buvIGxp4buHdSBsw6puIFINClN0b2NrIDwtIHJlYWQuY3N2KCJTdG9ja0RhdGEuY3N2IiwgaGVhZGVyID0gVFJVRSkNCg0KI0zhu41jIGThu68gbGnhu4d1IHbhu5tpIG3DoyBj4buVIHBoaeG6v3UgbW9uZyBtdeG7kW4gcGjDom4gdMOtY2gNCkRWTiA8LSBTdG9ja1tTdG9jayRtYSA9PSAiRFZOIixdDQoNCiPEkOG7i25oIGThuqFuZyBuZ8OgeSBj4bunYSBk4buvIGxp4buHdQ0KRFZOJG5nYXkgPC0gYXMuRGF0ZShEVk4kbmdheSkNCg0KI0NodXnhu4NuIMSR4buVaSBk4buvIGxp4buHdSBj4bunYSBtw6MgY+G7lSBwaGnhur91IHRow6BuaCBk4buvIGxp4buHdSB0aGVvIGNodeG7l2kgdGjhu51pIGdpYW4gdsOgIGNo4buNbiBnacOhIMSRw7NuZyBj4butYSBsw6BtIGdpw6EgdHLhu4sgcGjDom4gdMOtY2ggbOG7o2kgbmh14bqtbiBow6BuZyBuZ8OgeQ0KRFZOX3h0cyA8LSB4dHMoRFZOJGdpYV9kb25nX2N1YSwgc3RhcnQgPSBtaW4oRFZOJG5nYXkpLCBlbmQgPSBtYXgoRFZOJG5nYXkpLCBvcmRlci5ieSA9IERWTiRuZ2F5LCBmcmVxdWVuY3kgPSAxKQ0KYGBgDQrEkOG7gyB04bqjaSBk4buvIGxp4buHdSB2w6BvIHPhu60gZOG7pW5nLCBj4bqnbiB0aGnhur90IGzhuq1wIHRoxrAgbeG7pWMgbMOgbSB2aeG7h2MgaGnhu4duIHThuqFpIHbDoCB04bqldCBj4bqjIHThu4dwIGThu68gbGnhu4d1IGPhuqduIMSRxrDhu6NjIGzGsHUgdHJvbmcgdGjGsCBt4bulYyBuw6B5Lg0KDQpgYGB7cn0NCiNUw61uaCBs4bujaSBuaHXhuq1uIGjDoG5nIG5nw6B5DQpkYWlseV9yZXR1cm5zIDwtIGRhaWx5UmV0dXJuKERWTl94dHMpDQoNCiMgVMOtbmggZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBj4bunYSBs4bujaSBuaHXhuq1uIGjDoG5nIG5nw6B5DQpkYWlseV9tZWFuIDwtIG1lYW4oZGFpbHlfcmV0dXJucykNCg0KIyBUw61uaCDEkeG7mSBs4buHY2ggY2h14bqpbiBj4bunYSBs4bujaSBuaHXhuq1uIGjDoG5nIG5nw6B5DQpkYWlseV9zdGRfZGV2IDwtIHNkKGRhaWx5X3JldHVybnMpDQpgYGANClRyb25nIG3DtCBwaOG7j25nIG7DoHksIGzhu6NpIG5odeG6rW4gdGjhu4sgdHLGsOG7nW5nIGPhu5UgcGhp4bq/dSDEkcaw4bujYyBnaeG6oyDEkeG7i25oIGzDoCBwaMOibiBwaOG7kWkgY2h14bqpbiB2w6AgY8OhYyB0aMO0bmcgc+G7kSDEkcaw4bujYyB0w61uaCB0b8OhbiBuaMawIGzhu6NpIG5odeG6rW4gaMOgbmcgbmfDoHksIGdpw6EgdHLhu4sgdHJ1bmcgYsOsbmggY+G7p2EgbOG7o2kgbmh14bqtbiBow6BuZyBuZ8OgeSwgxJHhu5kgbOG7h2NoIGNodeG6qW4gY+G7p2EgbOG7o2kgbmh14bqtbi4gQ8OhYyB0aMO0bmcgc+G7kSBuw6B5IHPhur0gxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdOG6oW8gcmEgY8OhYyBiaeG6v24gbmfhuqt1IG5oacOqbiB0cm9uZyBtw7QgaMOsbmguIA0KDQoNCmBgYHtyfQ0KIyBYw6FjIMSR4buLbmggc+G7kSBuZ8OgeSBj4bqnbiBtw7QgcGjhu49uZw0Kbm9fb2ZfZGF5cyA8LSAxMjANCg0KIyBYw6FjIMSR4buLbmggZ2nDoSBraOG7n2kgxJFp4buDbSBj4bunYSBxdcOhIHRyw6xuaCBtw7QgcGjhu49uZw0Kc3RhcnRpbmdfcHJpY2UgPC0gbGFzdChEVk4kZ2lhX2RvbmdfY3VhKVtbMV1dDQpgYGANCkThu68gbGnhu4d1IHPhur0gxJHGsOG7o2MgbcO0IHBo4buPbmcgdHJvbmcgMTIwIG5nw6B5IHThu5tpIHbDoCBnacOhIGto4bufaSDEkWnhu4NtIGPhu6dhIG5nw6B5IMSR4bqndSB0acOqbiB0cm9uZyB0aOG7nWkgxJFp4buDbSBtw7QgcGjhu49uZyBz4bq9IGzDoCBnacOhIMSRw7NuZyBj4butYSBjdeG7kWkgY8O5bmcgdHJvbmcgZOG7ryBsaeG7h3UgZ2nDoSBs4buLY2ggc+G7rSBj4bunYSBtw6MgY+G7lSBwaGnhur91Lg0KDQpM4bujaSBuaHXhuq1uIGjDoG5nIG5nw6B5IMSRxrDhu6NjIHThuqFvIGLhurFuZyBjw6FjaCBz4butIGThu6VuZyBwaMOibiBwaOG7kWkgY2h14bqpbiB24bubaSBnacOhIHRy4buLIHRydW5nIGLDrG5oIHbDoCDEkeG7mSBs4buHY2ggY2h14bqpbiDEkcOjIMSRxrDhu6NjIHTDrW5oIHRvw6FuIHRyxrDhu5tjIMSRw7MuIMSQ4buDIHTDrW5oIGdpw6EgY+G7p2EgY+G7lSBwaGnhur91LCBj4bqnbiB0aOG7sWMgaGnhu4duIHTDrW5oIHTDrWNoIGzFqXkgY+G7p2EgbOG7o2kgbmh14bqtbiB2w6AgZ2nDoSBraOG7n2kgxJFp4buDbS4gS+G6v3QgcXXhuqMgZMaw4bubaSDEkcOieSBsw6AgYmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBnacOhIG3DtCBwaOG7j25nIGPhu6dhIG3DoyBj4buVIHBoaeG6v3UgdHJvbmcgMTIwIG5nw6B5IHThu5tpLg0KYGBge3J9DQojIFThuqFvIGPGoSBz4bufIHPhu5EgbMaw4bujbmcgY8OhYyBt4bqrdSBuZ+G6q3Ugbmhpw6puIHPhur0gxJHGsOG7o2MgdOG6oW8NCnNldC5zZWVkKDEwMSkNCg0KIyBUw61uaCBnacOhIHRy4buLIGzhu6NpIG5odeG6rW4gZOG7sWEgdHLDqm4gY8OhYyBnacOhIHRy4buLIG5n4bqrdSBuaGnDqm4NCnJldHVybnMgPC0gMStybm9ybShub19vZl9kYXlzLCBtZWFuPWRhaWx5X21lYW4sIHNkPWRhaWx5X3N0ZF9kZXYpDQoNCiMgVMOtbmggZ2nDoSBj4buVIHBoaeG6v3UgdGjDtG5nIHF1YSB0w61jaCBsxal5IGPhu6dhIGdpw6Ega2jhu59pIMSRaeG7g20gdsOgIGzhu6NpIG5odeG6rW4NCnByaWNlcyA8LSBjdW1wcm9kKGMoc3RhcnRpbmdfcHJpY2UsIHJldHVybnMpKQ0KDQojIFbhur0gYmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBtw7QgcGjhu49uZyBj4bunYSBnacOhIGPhu5UgcGhp4bq/dSB0cm9uZyB0xrDGoW5nIGxhaQ0KcGxvdChwcmljZXMsIHR5cGU9J2wnLCB5bGFiPSJHacOhIGPhu5UgcGhp4bq/dSIsIHhsYWI9IlPhu5EgbmfDoHkiLCBtYWluID0gIk3DtCBwaOG7j25nIGdpw6EgY+G7p2EgbcOjIGPhu5UgcGhp4bq/dSBEVk4iKQ0KYGBgDQoNClR1eSBuaGnDqm4sIGNo4buJIGNo4bqheSBt4buZdCBtw7QgcGjhu49uZyBz4bq9IGtow7RuZyDEkeG7pyDEkeG7gyDEkcawYSByYSBr4bq/dCBsdeG6rW4uIFbDrCB24bqteSwgxJHhu4MgxJHGsGEgcmEga+G6v3QgcXXhuqMgc8OhdCB24bubaSB0aOG7sWMgdOG6vyBuaOG6pXQsIHRhIHPhur0gdGjhu7FjIGhp4buHbiBjaOG6oXkgMTAwMSBtw7QgcGjhu49uZyB0cm9uZyAxMjAgbmfDoHkgduG7m2kgbeG7l2kgbcO0IHBo4buPbmcuIEThu68gbGnhu4d1IMSRxrDhu6NjIGzGsHUgdHLhu68gaGFpIGNoaeG7gXUgZMaw4bubaSBk4bqhbmcgbWEgdHLhuq1uIHbDoCA1MCBtw7QgcGjhu49uZyDEkeG6p3UgdGnDqm4gxJHGsOG7o2MgYmnhu4N1IGRp4buFbiB0cm9uZyDEkeG7kyB0aOG7iyBkxrDhu5tpIMSRw6J5Lg0KYGBge3J9DQojIFPhu5EgbMaw4bujbmcgdGjhu7FjIGhp4buHbiB2w7JuZyBs4bq3cCBtw7QgcGjhu49uZw0Kbm9fb2Zfc2ltcyA8LSAxMDAxDQoNCiMgRGFuaCBzw6FjaCBnacOhIHRy4buLIGPhu6dhIGzhu6NpIG5odeG6rW4NCnJldHVybnNfbGlzdCA8LSBtYXRyaXgoMCwgbnJvdyA9IG5vX29mX3NpbXMsIG5jb2wgPSBub19vZl9kYXlzKQ0KDQojIERhbmggc8OhY2ggZ2nDoSBj4bunYSBj4buVIHBoaeG6v3UNCnByaWNlc19saXN0IDwtIG1hdHJpeCgwLCBucm93ID0gbm9fb2Zfc2ltcywgbmNvbCA9IG5vX29mX2RheXMrMSkgDQoNCiMgVsOybmcgbOG6t3AgdGjhu7FjIGhp4buHbiBtw7QgcGjhu49uZyB0cm9uZyBz4buRIG5nw6B5IMSRxrDhu6NjIGNo4buJIMSR4buLbmgNCmZvcihpIGluIDE6bm9fb2Zfc2ltcykgew0KICByZXR1cm5zX2xpc3RbaSxdIDwtIHJub3JtKG5vX29mX2RheXMsIG1lYW49ZGFpbHlfbWVhbiwgc2Q9ZGFpbHlfc3RkX2RldikNCiAgcHJpY2VzX2xpc3RbaSxdIDwtIGN1bXByb2QoYyhzdGFydGluZ19wcmljZSwgMStyZXR1cm5zX2xpc3RbaSxdKSkNCiAgfQ0KDQojIEJp4buDdSBkaeG7hW4gZMaw4bubaSBk4bqhbmcgxJHhu5MgdGjhu4sgNTAgbcO0IHBo4buPbmcgxJHhuqd1IHRpw6puDQpwbG90KHByaWNlc19saXN0WzEsXSwgdHlwZT0nbCcsIHlsYWI9Ikdpw6EgY+G7lSBwaGnhur91IiwgeGxhYj0iU+G7kSBuZ8OgeSIsIG1haW4gPSAiTcO0IHBo4buPbmcgZ2nDoSBj4bunYSBtw6MgY+G7lSBwaGnhur91IERWTiIsIHlsaW09YygxMDAwMCwgNTAwMDApKQ0KZm9yKGkgaW4gMTo1MCkgew0KICBsaW5lcyhwcmljZXNfbGlzdFtpLCBdLCB0eXBlID0gJ2wnLCBjb2w9aSkNCn0NCmBgYA0KTmjGsCBjaMO6bmcgdGEgY8OzIHRo4buDIHRo4bqleSwga+G6v3QgcXXhuqMgY+G7p2EgY8OhYyBtw7QgcGjhu49uZyBjw7Mgc+G7sSDEkWEgZOG6oW5nIGtow6FjIG5oYXUuIE3hu5l0IHPhu5Ega+G6v3QgdGjDumMgZMaw4bubaSDEkWnhu4NtIGLhuq90IMSR4bqndSB2w6AgbeG7mXQgc+G7kSB0xINuZyBy4bqldCBuaGFuaC4gROG7sWEgdHLDqm4gNTAgbcO0IHBo4buPbmcgxJHhuqd1IHRpw6puLCBtw6MgY+G7lSBwaGnhur91IGPDsyB4dSBoxrDhu5tuZyBs4bujaSBuaHXhuq1uIMOibSB0cm9uZyB0aOG7nWkgZ2lhbiB04bubaS4gxJDhu4MgeGVtIHjDqXQgY+G7pSB0aOG7gyBoxqFuLCB0YSBz4bq9IHTDrW5oIHThu5VuZyBs4bujaSBuaHXhuq1uIHRodSB24buBOg0KDQpgYGB7cn0NCiMgVOG6oW8gbeG6o25nIMSRYSBjaGnhu4F1IGNo4bupYSBk4buvIGxp4buHdSBj4bunYSBs4bujaSBuaHXhuq1uDQp0b3RhbF9yZXR1cm5zIDwtIGFycmF5KE5BLCBkaW09IG5vX29mX3NpbXMsIGRpbW5hbWVzPU5VTEwpDQoNCiMgVsOybmcgbOG6t3AgbmjhurFtIHTDrW5oIGdpw6EgdHLhu4sgY+G7p2EgdOG7lW5nIGzhu6NpIG5odeG6rW4gduG7m2kgbeG7l2kgbcO0IHBo4buPbmcNCmZvciAoaSBpbiAxOm5vX29mX3NpbXMpIHsNCiAgdG90YWxfcmV0dXJuc1tpXSA8LSAocHJpY2VzX2xpc3RbaSwgMTIxXS1wcmljZXNfbGlzdFtpLCAxXSkvcHJpY2VzX2xpc3RbaSwxXQ0KfQ0KDQojIFRo4buRbmcga8OqIGvhur90IHF14bqjIGPhu6dhIGzhu6NpIG5odeG6rW4gdGh1IHbhu4ENCnN1bW1hcnkodG90YWxfcmV0dXJucykNCmBgYA0KS+G6v3QgbHXhuq1uIGNobyB0aOG6pXkgbcO0IHBo4buPbmcgY8OzIHh1IGjGsOG7m25nIGzhu6NpIG5odeG6rW4gw6JtLCBoxqFuIDUwJSBr4bq/dCBxdeG6oyBtw7QgcGjhu49uZyBjaG8gcmEgZ2nDoSB0cuG7iyA8IDAgYuG7n2kgZ2nDoSB0cuG7iyB0cnVuZyB24buLLCBnacOhIHRy4buLIHRydW5nIGLDrG5oIHbDoCBwaMOibiB24buLIHRo4bupIG5o4bqldCDEkeG7gXUgdGjhu4MgaGnhu4duIMSRaeG7gXUgbsOgeS4gxJDhu4MgdHLhu7FjIHF1YW4gaMOzYSBr4bq/dCBxdeG6oywgdGEgY8OzIHRo4buDIHhlbSB4w6l0IDEgc+G7kSBiaeG7g3UgxJHhu5Mgc2F1Og0KYGBge3J9DQpwYXIobWZyb3c9YygxLDMpKQ0KaGlzdCh0b3RhbF9yZXR1cm5zLCBjb2w9ImJsdWUiKQ0KYm94cGxvdCh0b3RhbF9yZXR1cm5zLCBjb2w9InllbGxvdyIpDQpwbG90KGRlbnNpdHkodG90YWxfcmV0dXJucykpDQpgYGANCkPDoWMgZ2nDoSB0cuG7iyBuZ2/huqFpIGxhaSBj4bunYSBiaeG7g3UgxJHhu5MgQm94cGxvdCB0aMaw4budbmcgdGjhu4MgaGnhu4duIG3hurd0IGTGsMahbmcgY+G7p2EgbOG7o2kgbmh14bqtbiB2w6AgYmnhu4N1IMSR4buTIHRo4buDIGhp4buHbiBz4buxIHBow6JuIHBo4buRaSBs4buHY2ggcGjhuqNpIHLDtSBy4buHdC4gxJBp4buBdSBuw6B5IGPDsyB0aOG7gyB4w6FjIG5o4bqtbiBk4buxYSB0csOqbiB0aMO0bmcgc+G7kSDEkeG7mSBs4buHY2ggZMaw4bubaSDEkcOieToNCg0KYGBge3J9DQojIFTDrW5oIMSR4buZIGzhu4djaCBj4bunYSBk4buvIGxp4buHdSBs4bujaSBuaHXhuq1uDQpza2V3bmVzcyh0b3RhbF9yZXR1cm5zKQ0KYGBgDQoNCsSQ4buDIGhp4buDbiB0aOG7iyBiaeG7g3UgxJHhu5MgZOG7hSDEkeG7jWMgaMahbiwgc+G6vSBjaOG7iSBjw7MgYmEgbcO0IHBo4buPbmcgc+G6vSDEkcaw4bujYyDEkcawYSB2w6BvOiBnacOhIHRy4buLIHRydW5nIGLDrG5oLCBnacOhIHRy4buLIHThu5FpIHRoaeG7g3UgdsOgIGdpw6EgdHLhu4sgdOG7kWkgxJFhLiBDw6FjIGThu68gbGnhu4d1IG7DoHkgxJHGsOG7o2MgbOG6pXkgdOG7qyBwaMOibiB0w61jaCBk4buvIGxp4buHdSB24bubaSBiaeG7g3UgxJHhu5MgcGjDrWEgdHLDqm4uIFRp4bq/cCB04bulYyB0aOG7sWMgaGnhu4duIHbhu5tpIHPhu7EgbOG6t3AgbOG6oWkgY+G7p2EgMTAwMSBtw7QgcGjhu49uZy4NCmBgYHtyfQ0KIyBUw6xtIHbhu4sgdHLDrSBnacOhIHRy4buLIGzhu5tuIG5o4bqldCBj4bunYSBs4bujaSBuaHXhuq1uDQptYXggPC0gd2hpY2gubWF4KHRvdGFsX3JldHVybnMpDQoNCiMgVMOsbSB24buLIHRyw60gZ2nDoSB0cuG7iyBuaOG7jyBuaOG6pXQgY+G7p2EgbOG7o2kgbmh14bqtbg0KbWluIDwtIHdoaWNoLm1pbih0b3RhbF9yZXR1cm5zKQ0KDQojIFTDrG0gduG7iyB0csOtIGPhu6dhIGdpw6EgdHLhu4sgdHJ1bmcgduG7iw0KaWYgKG5vX29mX3NpbXMgJSUgMiAhPSAwKSB7bWVkIDwtIG1hdGNoKG1lZGlhbih0b3RhbF9yZXR1cm5zKSwgdG90YWxfcmV0dXJucyl9DQoNCiMgQmnhu4N1IGRp4buFbiDEkeG7kyB0aOG7iyB24bubaSAzIGdpw6EgdHLhu4sgdHLDqm4NCnBsb3QocHJpY2VzX2xpc3RbbWluLF0sIHR5cGU9J2wnLCB5bGFiPSJHacOhIGPhu5UgcGhp4bq/dSIsIHhsYWI9IlPhu5EgbmfDoHkiLCBtYWluID0iTcO0IHBo4buPbmcgZ2nDoSBj4bunYSBtw6MgY+G7lSBwaGnhur91IERWTiIsIHlsaW09Yyg5MDAwLCA2MDAwMCksIGNvbD0icmVkIikNCmlmIChub19vZl9zaW1zICUlIDIgIT0gMCkge2xpbmVzKHByaWNlc19saXN0W21lZCwgXSwgdHlwZSA9ICdsJywgY29sPSd5ZWxsb3cnKX0NCmxpbmVzKHByaWNlc19saXN0W21heCwgXSwgdHlwZSA9ICdsJywgY29sPSdncmVlbicpDQpgYGANCg0KUXVhIMSRw7MsIGNow7puZyB0YSBjw7MgdGjhu4MgZOG7hSBkw6BuZyBuaMOsbiB0aOG6pXkgdHLGsOG7nW5nIGjhu6NwIGdpw6EgdHLhu4sgbcO0IHBo4buPbmcgdOG7kXQgbmjhuqV0LCB44bqldSBuaOG6pXQgdsOgIHRydW5nIGLDrG5oLiDEkOG7gyB0cuG6oyBs4budaSBjw6J1IGjhu49pIMSR4bqndSB0acOqbiwgZOG7sWEgdHLDqm4gY8OhYyBiaeG7g3UgxJHhu5MgdsOgIGThu68gbGnhu4d1LCB0YSBjw7MgdGjhu4Mga+G7syB24buNbmcgbeG7qWMgbOG7o2kgbmh14bqtbiBu4bqxbSB0cm9uZyBraG/huqNuZyB04burIC02OS4wMiUgxJHhur9uIDk2LjA3JS4NCmBgYHtyfQ0KIyBUw61uaCBnacOhIHRy4buLIGzhu6NpIG5odeG6rW4gY8OzIHRo4buDIMSR4bqhdCDEkcaw4bujYyBs4bubbiBuaOG6pXQNCm1heF9yZXR1cm4gPC0gbWF4KHRvdGFsX3JldHVybnMpDQptYXhfcmV0dXJuDQoNCiMgVMOtbmggZ2nDoSB0cuG7iyBs4bujaSBuaHXhuq1uIGPDsyB0aOG7gyDEkeG6oXQgxJHGsOG7o2Mgbmjhu48gbmjhuqV0DQptaW5fcmV0dXJuIDwtIG1pbih0b3RhbF9yZXR1cm5zKQ0KbWluX3JldHVybg0KYGBgDQrEkOG7gyB0cuG6oyBs4budaSAyIGPDonUgaOG7j2kgY3Xhu5FpLCB0YSBz4bq9IHRo4buxYyBoaeG7h24gdMOtbmggeMOhYyBzdeG6pXQgbmjhurFtIMSR4bqhdCDEkcaw4bujYyBr4bq/dCBxdeG6oyBtb25nIG114buRbi4NCmBgYHtyfQ0KIyBN4bupYyBs4bujaSBuaHXhuq1uIGPhuqduIGzhu5tuIGjGoW4NCmNvbmRpdGlvbjEgPC0gc3VtKHRvdGFsX3JldHVybnMgPiAwLjEyKQ0KDQojIE3hu6ljIGzhu6NpIG5odeG6rW4gY+G6p24gbmjhu48gaMahbg0KY29uZGl0aW9uMiA8LSBzdW0odG90YWxfcmV0dXJucyA8IC0wLjIpDQoNCiMgWMOhYyBzdeG6pXQgeOG6o3kgcmEgY8OhYyB0csaw4budbmcgaOG7o3ANCnByb2JhYmlsaXR5MSA8LSBjb25kaXRpb24xL25vX29mX3NpbXMNCnByb2JhYmlsaXR5MiA8LSBjb25kaXRpb24yL25vX29mX3NpbXMNCg0KIyBL4bq/dCBxdeG6oyDEkeG6oXQgxJHGsOG7o2MNCmNhdCgiWMOhYyBzdeG6pXQgxJHhu4MgxJHhuqF0IMSRxrDhu6NjIGzhu6NpIG5odeG6rW4gdOG7kWkgdGhp4buDdSAxMiUgbMOgOiAiLCBwcm9iYWJpbGl0eTEqMTAwLCAiJSIsICIuIFjDoWMgc3XhuqV0IMSR4buDIGzhu5cgbmhp4buBdSBoxqFuIDIwJSBraG/huqNuIMSR4bqndSB0xrAgbMOgOiAiLCBwcm9iYWJpbGl0eTIqMTAwLCAiJSIpDQpgYGANCiMjIEvhur90IGx14bqtbg0KUGjGsMahbmcgcGjDoXAgbsOgeSDEkcOjIGN1bmcgY+G6pXAgbmhp4buBdSBoaeG7g3UgYmnhur90IHPDonUgc+G6r2MgduG7gSB0aOG7iyB0csaw4budbmcgY2jhu6luZyBraG/DoW4gbcOgIHLhuqV0IGtow7MgxJHhu4MgdMOtbmggdG/DoW4gdGhlbyBjw6FjaCBraMOhYy4gVsOtIGThu6UgbsOgeSBtaW5oIGjhu41hIHLhurFuZyBNw7QgcGjhu49uZyBNb250ZSBDYXJsbyBjw7MgdGjhu4MgxJHGsOG7o2Mg4bupbmcgZOG7pW5nIHRo4buxYyB0aeG7hW4gYuG7n2kgY8OhYyBuaMOgIMSR4bqndSB0xrAsIHF14bu5IHBow7JuZyBo4buZIHbDoCBjw6FjIHThu5UgY2jhu6ljIHTDoGkgY2jDrW5oIGtow6FjIHbDoG8gcXXDoSB0csOsbmggcmEgcXV54bq/dCDEkeG7i25oIGPhu6dhIGjhu40uDQo=