
Portfolios with Three Risky Assets
Xét một danh mục đầu tư (Portfolio) gồm ba tài sản là A, B và C. Kí hiệu \(R_i\) (\(i = A, B, C\)) là lợi tức tương ứng của ba tài sản và giả định rằng các lợi tức là biến ngẫu nhiên (Random Variable) thỏa mãn:
\[R_{i}\sim N(\mu_i,\sigma_i^2)\]
Ngoài ra với \(i \ne j\) thì covariance của gặp tài sản bất kì \(i\) và \(j\):
\[\mathrm{cov}\left(R_i, R_j \right) = \sigma_{ij}\]
Nếu tỉ trọng của ba tài sản này trong danh mục đầu tư là \(x_A\), \(x_B\) và \(x_C\) (lưu ý rằng \(x_A + x_B + x_C = 1\)) thì lợi tức của danh mục, kí hiệu là \(R_p,_x\) cũng sẽ là một biến ngẫu nhiên:
\[\begin{equation}
\tag{1}
R_p = x_AR_A + x_BR_B + x_CR_C
\end{equation}\]
Và lợi tức kì vọng của danh mục \(\mu_p,_x\), nếu kí hiệu \(\mu_A\), \(\mu_B\) và \(\mu_C\) lần lượt là lợi tức kì vọng của ba tài sản A, B và C sẽ được tính theo công thức:
\[\begin{equation}
\tag{2}
\mu_p = E[R_p] = x_A\mu_A + x_B\mu_B + x_C\mu_C
\end{equation}\]
Còn rủi ro của danh mục, kí hiệu là \(\sigma_p\) sẽ là:
\[\begin{equation}
\tag{3}
\sigma^2_p = \mathrm{var(R_p) = x^2_A\sigma^2_A + x^2_B\sigma^2_B + x^2_C\sigma^2_C + 2x_Ax_B\sigma_{AB} + 2x_Bx_C\sigma_{BC} + 2x_Ax_C\sigma_{AC}}
\end{equation}\]
Các công thức được mô tả bằng các phương trình đại số ở trên bạn đọc có thể tìm thất ở bất kì cuốn sách nào về Investment và Portfolio Theory. Còn theo ngôn ngữ của ma trận và tính toán ma trận (Matrix Calculation) thì lợi tức của danh mục tính theo công thức (2) sẽ được biểu diễn là:
\[\mu_p = X\mu\]
Còn rủi ro của danh mục theo công thức (3), với chú ý rằng \(X'\) là ma trận chuyển vị của ma trận \(X\), sẽ là:
\[\sigma^2_p = X'\Sigma X\]
Trong đó \(X\), \(\mu\) và \(\Sigma\) được định nghĩa và mô tả dưới đây:
- \(\mu\) là ma trận lợi tức của ba tài sản A, B và C. Đây là ma trận có kích thước 3×1:
\[\mu =
\begin{pmatrix}
\mu_A \\
\mu_B \\
\mu_C
\end{pmatrix}\]
- \(X\) là ma trận tỉ trọng của ba tài sản A, B và C (kích thước 3×1):
\[X =
\begin{pmatrix}
x_A & x_B & x_C
\end{pmatrix}\]
- \(\Sigma\) là ma trận hiệp phương sai (Covariance Matrix) của ba tài sản trong danh mục đầu tư. Đây là một ma trận đối xứng (symmetric) kích thước 3×3 vì rằng \(\mathrm{cov}\left(R_i, R_j \right) = \mathrm{cov}\left(R_j, R_i \right)\):
\[\begin{equation*}
\Sigma =
\begin{pmatrix}
\sigma^2_A & \sigma_{AB} & \sigma_{AC} \\
\sigma_{AB} & \sigma^2_B & \sigma_{BC} \\
\sigma_{AC} & \sigma_{BC} & \sigma^2_C
\end{pmatrix}
\end{equation*}\]
Những mục dưới đây chúng ta sẽ triển khai tính toán lợi tức - rủi ro của danh mục đầu tư và những bài toán cơ bản của Portfolio Theory bằng tính toán ma trận với ngôn ngữ R.
A Simple Example
Xét một danh mục đầu tư gồm ba cổ phiếu A, B và C với lợi tức (kí hiệu \(\mu_i\)), rủi ro (kí hiệu \(\sigma_i\)) và covariance theo từng cặp (kí hiệu \(\sigma_{ij}\)) được cho ở Table 1 dưới đây:
Table 1: A Real-world example data
|
Stock \(i\)
|
\(\mu_i\)
|
\(\sigma_i\)
|
Pair \((i,j)\)
|
\(\sigma_{ij}\)
|
|
A
|
0.0013128
|
0.0203511
|
(A,B)
|
0.0002519
|
|
B
|
0.0008900
|
0.0199235
|
(A,C)
|
0.0002366
|
|
C
|
-0.0005860
|
0.0002720
|
(B,C)
|
0.0002720
|
Xét một danh mục đầu tư mà tỉ trọng của các tài sản A, B, C là như nhau (equally weighted portfolio). Dưới đây là R codes cho tính toán lợi tức và rủi ro của danh mục đầu tư này. Trước hết là nhập số liệu cho các ma trận \(X\), \(\mu\) và \(\Sigma\) dựa trên Table 1:
# Clear workspace:
rm(list = ls())
# Symbol:
my_symbols <- LETTERS[1:3]
# Asset Weights:
X <- rep(1 / 3, 3)
# Asset returns:
mu <- c(0.0013127958, 0.0008899841, -0.0005860124)
# Asset risks:
sigma_i <- c(0.02035107, 0.01992348, 0.03098048)
# Covariance:
sigma_ij <- c(0.0002518696, 0.0002366285, 0.0002719917)
# Create covariance matrix:
sigma_matrix_3 <- matrix(c(sigma_i[1]*sigma_i[1], sigma_ij[1], sigma_ij[2],
sigma_ij[1], sigma_i[2]*sigma_i[2], sigma_ij[3],
sigma_ij[2], sigma_ij[3], sigma_i[3]*sigma_i[3]),
nrow = 3, byrow = TRUE)
# Set name for covariance matrix:
dimnames(sigma_matrix_3) <- list(my_symbols, my_symbols)
Ma trận hiệp phương sai:
Table 2: Covariance matrix
|
|
A
|
B
|
C
|
|
A
|
0.0004142
|
0.0002519
|
0.0002366
|
|
B
|
0.0002519
|
0.0003969
|
0.0002720
|
|
C
|
0.0002366
|
0.0002720
|
0.0009598
|
Tính toán lợi tức và rủi ro cho danh mục đầu tư:
## [1] 0.0005389225
## [1] 0.01912497
Danh mục đầu tư này tuy lợi tức chỉ bằng 41% so với tài sản B nhưng rủi ro lại gần bằng. Một nhà đầu tư duy lí đương nhiên sẽ ưa thích đầu tư toàn bộ tài sản của mình vào B hơn là phân bổ đều vào ba tài sản. Do vậy mà trọng tâm của lí thuyết danh mục (Portfolio Theory) và lựa chọn danh mục đầu tư (Portfolio Selection) là trả lời câu hỏi kiểu như sau:
Có hay không một sự kết hợp cụ thể nào đó của các tài sản mà cùng với mức lợi tức như tài sản A - tài sản có lợi tức cao nhất trong số ba tài sản nhưng có rủi ro thấp hơn?
Có hay không một sự kết hợp cụ thể nào đó của các tài sản mà cùng với mức lợi tức như tài sản B nhưng rủi ro lại thấp hơn 0.0199235?
Có hay không một sự kết hợp cụ thể nào đó của các tài sản mà với một mức lợi tức mục tiêu định trước là, ví dụ, 1% nhưng rủi ro là thấp nhất có thể được, thậm chí là thấp hơn cả rủi ro của tài sản C - là tài sản có rủi ro thấp nhất trong số ba tài sản?
Những câu hỏi này sẽ dần được sáng tỏ trong các mục kế tiếp.
A Real-world Application
Trong thế giới thực chúng ta cần tính được Table 1 từ dữ liệu thô (raw data). Để minh họa chúng ta chọn ba công ti là Microsoft, Starbucks và General Motor (tức là một công ti công nghệ, một công ti hàng tiêu dùng nhanh và một công ti công nghiệp nặng) và lấy dữ liệu lịch sử về giá cổ phiếu của ba công ti này bằng hàm tq_get() của thư viện tidyquant từ 2018-01-01 đến 2020-12-31:
Chúng ta có thể xem giá của ba cổ phiếu tại ngày cuối cùng trong mẫu dữ liệu đã lấy:
Table 3: Some Observations
|
symbol
|
date
|
open
|
high
|
low
|
close
|
volume
|
adjusted
|
|
GE
|
2020-12-30
|
10.58
|
10.85
|
10.55
|
10.71
|
50621000
|
10.71
|
|
MSFT
|
2020-12-30
|
225.23
|
225.63
|
221.47
|
221.68
|
20272300
|
221.68
|
|
SBUX
|
2020-12-30
|
105.99
|
106.62
|
105.78
|
105.97
|
3654100
|
105.97
|
Xu hướng biến động về giá hiệu chỉnh (adjusted) của ba cổ phiếu này (Figure 1):

Tính toán lợi tức của các tài sản được đo bằng log return theo công thức sau:
\[R_t=\ln\left(\frac{P_{t}} {P_{t-1}}\right)\]
Trong đó \(P_t\) là giá của tài sản ở thời điểm t và \(P_{t-1}\) là giá của tài sản tại thời điểm trước đó 1 ngày (còn gọi là trễ 1, kí hiệu là \(lag_1\)).
Phân phối của lợi tức có vẻ là phân phối chuẩn như ta có thể thấy ở Figure 2 dưới đây:

Để có kết luận chính xác phân phối có phải là phân phối chuẩn hay không chúng ta có thể dựa vào một test thống kê là Jarque–Bera (JB) test. Trước hết viết hàm tính toán thống kê này cùng p-value tương ứng:
Hàm tính toán ba tiêu chí quan trọng khác là Skewness, Kurtosis và CV (Coefficient of variation):
Table 4 liệt kê các thống kê quan trọng cùng với kiểm định JB Test cho lợi tức của ba tài sản:
# Apply funtions for our stock:
daily_returns %>%
group_by(symbol) %>%
summarise(Skewness = my_s(daily_return),
Kurtosis = my_k(daily_return),
CV = my_cv(daily_return),
JB_test = my_JB(daily_return),
p_value = my_stas(daily_return),
Mean = mean(daily_return),
Min = min(daily_return),
Max = max(daily_return),
SD = sd(daily_return),
N = n()) -> df_statistics
# Some main statistics for stocks:
df_statistics %>%
mutate_if(is.numeric, function(x) {round(x, 3)}) %>%
kbl(caption = "Table 4: Main Statistics for Symbol", escape = TRUE) %>%
kable_classic(full_width = FALSE, html_font = "Cambria")
Table 4: Main Statistics for Symbol
|
symbol
|
Skewness
|
Kurtosis
|
CV
|
JB_test
|
p_value
|
Mean
|
Min
|
Max
|
SD
|
N
|
|
GE
|
-0.043
|
3.531
|
-52.867
|
395.857
|
0
|
-0.001
|
-0.164
|
0.137
|
0.031
|
754
|
|
MSFT
|
-0.385
|
9.398
|
15.502
|
2812.889
|
0
|
0.001
|
-0.159
|
0.133
|
0.020
|
754
|
|
SBUX
|
-0.381
|
15.961
|
22.386
|
8071.986
|
0
|
0.001
|
-0.177
|
0.137
|
0.020
|
754
|
Các giá trị p_value này rất thấp do vậy có thể chấp nhận giả thuyết rằng các lợi tức có phân phối chuẩn. Dưới đây là R codes để tính toán lợi tức và rủi ro cho ba cổ phiếu:
## MSFT SBUX GE
## 0.0013127958 0.0008899841 -0.0005860124
Tính Covariance Matrix của ba tài sản:
## MSFT SBUX GE
## MSFT 0.0004141659 0.0002518696 0.0002366285
## SBUX 0.0002518696 0.0003969449 0.0002719917
## GE 0.0002366285 0.0002719917 0.0009597900
Xét một danh mục đầu tư mà các trọng số của các tài sản là như nhau (Equal-weight portfolio). Dưới đây là R codes tính toán lợi tức và rủi ro của danh mục đầu tư này theo ngôn ngữ ma trận:
## [1] 0.0005389225
## [1] 0.01912497
Xét một danh mục đầu tư có các trọng số (weights) của các tài sản là 40%, 80% và -20%. Trọng số âm có nghĩa là nguồn tài chính để đầu tư vào cổ phiếu của GE bằng cách “mượn” (thuật ngữ tiếng Anh là Short Sell). Loại danh mục đầu tư có trọng số âm này được gọi là Long-Short portfolio. Tương tự như ở trên, trước hết chúng ta tạo X là vector các trọng số:
Dễ dàng thấy rằng tổng các trọng số luôn bằng 1. Lợi tức và rủi ro của danh mục đầu tư này:
Chúng ta nên lưu lại các kết quả đã có:
Table 5: Risk-return trade-off
|
symbol
|
risk
|
return
|
|
GE
|
0.0310
|
-0.0006
|
|
MSFT
|
0.0204
|
0.0013
|
|
SBUX
|
0.0199
|
0.0009
|
|
EQUA
|
0.0191
|
0.0005
|
|
SHORT
|
0.0199
|
0.0014
|
Table 5 chỉ ra rằng Long-Short portfolio (kí hiệu SHORT) có lợi tức lớn nhất và cao hơn lợi tức của mã MSFT - cổ phiếu có lợi tức cao nhất trong số ba tài sản nhưng rủi ro của danh mục này lại thấp hơn rủi ro của MSFT. Liệu rằng việc đa dạng hóa bằng cách đầu tư vào ba tài sản trên với trọng số lần lượt là 40% cho MSFT, 80% cho SBUX và -20% cho GE có phải là lựa chọn tối ưu hay chí ít là hiệu quả? Chúng ta sẽ trả lời câu hỏi này ở mục kế tiếp ngay sau đây.
Efficient Portfolios by Simulation
Như ở trên đã phân tích, bằng cách thay đổi các trọng số chúng ta có hai danh mục đầu tư. Danh mục đầu tư thứ nhất (kí hiệu EQUA) có các trọng số bằng nhau (và đều bằng 33.33%) còn danh mục thứ hai (kí hiệu SHORT) có các trọng số lần lượt là 40%, 80% và -20%. Để tìm được danh mục đầu tư hiệu quả một trong những cách mà chúng ta có thể sử dụng là bằng mô phỏng (Simulation). Theo cách tiếp cận này chúng ta sẽ khảo sát cặp risk-return của, chẳng hạn, 10000 danh mục đầu tư khác nhau tương ứng với 10000 bộ trọng số khác nhau cho các tài sản cấu thành nên danh mục. Dựa trên khảo sát về cặp risk-return của 10000 danh mục đầu tư này chúng ta có thể trả lời một số câu hỏi như phải chăng còn tồn tại một danh mục với bộ trọng số nào đó mà lợi tức thì còn cao hơn lợi tức của SHORT nhưng rủi ro còn thấp hơn cả rủi ro của SHORT?.
Lưu ý rằng cho đến hiện tại, từ Table 5 thì SHORT chính là danh mục đầu tư “tốt nhất” căn cứ vào return còn EQUA là danh mục đầu tư có rủi ro thấp nhất căn cứ vào risk.
Để thực hiện simulation trước hết chúng ta viết một hàm có tên là portfolio_risk_return() tính toán cặp risk-return của một danh mục đầu tư nếu cho trước các trọng số tương ứng với ba tài sản MSFT, SBUX và GE:
library(rportfolios)
portfolio_risk_return <- function(j) {
# Create random weights:
set.seed(j)
X <- random.bounded(n = n, x.t = 1, x.l = rep(-1, n), x.u = rep(1, n))
# Portfolio return:
mu_port_rand = crossprod(X, mu) %>% as.numeric()
# Portfolio risk:
sig_port_rand <- t(X) %*% sigma_matrix %*% X %>% as.numeric() %>% sqrt()
# Create a data frame of results:
df_poft <- tibble(symbol = my_symbols,
weight = X,
return = mu_port_rand,
risk = sig_port_rand,
port_index = j)
return(df_poft)
}
Các trọng số sử dụng trong tính toán của hàm trên được tạo ra từ hàm random.bounded() của thư viện rportfolios. Lưu ý rằng: (1) tổng các trọng số luôn là 1, và (2) trọng số có thể là âm như có thể thấy:
## [1] -0.1699776 0.1699776 1.0000000
Sử dụng hàm này tính toán cặp risk-return của 10000 danh mục đầu tư và lưu lại kết quả dưới dạng một Data Frame có tên df_return_mini_10000 như dưới đây:
## user system elapsed
## 28.12 0.43 28.61
Lấy ra danh mục đầu tư có rủi ro thấp nhất và danh mục đầu tư có lợi tức cao nhất:
Figure 3 dưới đây chỉ ra cặp risk-return cho 10002 danh mục (10000 danh mục + hai danh mục EQUA và SHORT):
library(ggrepel)
library(scales)
df_return_mini_10000 %>%
ggplot(aes(risk, return)) +
geom_point(alpha = 0.05, color = "blue") +
geom_point(data = min_risk, color = "red", size = 3, shape = 17) +
geom_text_repel(data = min_risk, aes(label = "Min Risk")) +
geom_point(data = max_return, color = "purple", size = 3, shape = 18) +
geom_text_repel(data = max_return, aes(label = "Max Return")) +
geom_point(data = df_total %>% filter(!symbol %in% c("EQUA", "SHORT")), color = "green", size = 2) +
geom_point(data = df_total %>% filter(symbol %in% c("EQUA", "SHORT")), color = "orange", size = 2) +
geom_text_repel(data = df_total, aes(label = symbol)) +
scale_y_continuous(labels = percent) +
scale_x_continuous(labels = percent) +
labs(x = expression("Risk" ~ (sigma)),
y = expression("Return" ~ (mu)),
title = "Figure 3: Portfolio Optimization & Efficient Frontier")

Ba tài sản đơn lẻ (có thể coi là ba danh mục đầu tư mà trong đó các trọng số của hai tài sản là 0% còn tài sản thứ ba có trọng số 100%) được biểu diễn bằng ba điểm màu xanh. Hai danh mục EQUA và SHORT là hai điểm màu vàng còn màu đỏ và tím lần lượt là hai danh mục có rủi ro thấp nhất và lợi tức cao nhất.
Figure 3 chỉ ra rằng:
- Vẫn tồn tại rất nhiều danh mục đầu tư mà so với SHORT thì: (1) lợi tức cao hơn, và (2) rủi ro thấp hơn.
- Vẫn còn tại rất nhiều danh mục đầu tư mà so với EQUA thì: (1) lợi tức cao hơn, và (2) rủi ro thấp hơn.
Chúng ta có thể xem tỉ trọng các tài sản có rủi ro thấp nhất trong số 10002 danh mục đầu tư (điểm màu đỏ):
Table 5: Minimum-variance Portfolio
|
symbol
|
weight
|
return
|
risk
|
|
MSFT
|
45.01%
|
0.001
|
0.018
|
|
SBUX
|
45.88%
|
0.001
|
0.018
|
|
GE
|
9.11%
|
0.001
|
0.018
|
Và danh mục đầu tư có lợi tức cao nhất (điểm màu tím):
Table 6: Maximun-return Portfolio
|
symbol
|
weight
|
return
|
risk
|
|
MSFT
|
99.97%
|
0.003
|
0.035
|
|
SBUX
|
100%
|
0.003
|
0.035
|
|
GE
|
-99.97%
|
0.003
|
0.035
|
Summary
Đa dạng hóa đầu tư nhằm giảm thiểu rủi ro là một trong những hệ quả quan trọng của lí thuyết danh mục đầu tư (Portfolio Theory). Phần 1 của trước hết điểm lại những điểm cốt lõi của lí thuyết danh mục đầu tư và việc tính toán theo ngôn ngữ ma trận với R cũng như cách tiếp cận trực quan để tìm ra danh mục đầu tư hiệu quả (Efficient Portfolio) bằng phương pháp mô phỏng. Trong trường hợp danh mục đầu tư có n tài sản khác nhau thì việc áp dụng và tính toán vẫn không có gì thay đổi.
Đối với các khía cạnh như lí thuyết về Portfolio Theory, cơ sở Toán - Thống Kê/tính toán ma trận (Matrix Calculation) với ngôn ngữ R là những mảng kiến thức/kĩ năng mà người viết bài này mặc định bạn đọc đã nắm được. Bạn đọc quan tâm có thể tham khảo các tài liệu liệt kê ở mục References.
LS0tDQp0aXRsZTogJ1F1YW50aXRhdGl2ZSBGaW5hbmNlOiBQb3J0Zm9saW8gVGhlb3J5IChQMSknDQphdXRob3I6ICdBdXRob3I6IE5ndXllbiBDaGkgRHVuZycNCnN1YnRpdGxlOiAiUiBGaW5hbmNlIFNlcmllcyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgICMgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgIyBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiAiZmxhdGx5Ig0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUUpDQoNCmBgYA0KDQohW10oQzovVXNlcnMvQURNSU4vRG9jdW1lbnRzL2ludjIuanBnKQ0KDQoNCiMgUG9ydGZvbGlvcyB3aXRoIFRocmVlIFJpc2t5IEFzc2V0cw0KDQpYw6l0IG3hu5l0IGRhbmggbeG7pWMgxJHhuqd1IHTGsCAoUG9ydGZvbGlvKSBn4buTbSBiYSB0w6BpIHPhuqNuIGzDoCBBLCBCIHbDoCBDLiBLw60gaGnhu4d1ICRSX2kkICgkaSA9IEEsIEIsIEMkKSBsw6AgbOG7o2kgdOG7qWMgdMawxqFuZyDhu6luZyBj4bunYSBiYSB0w6BpIHPhuqNuIHbDoCBnaeG6oyDEkeG7i25oIHLhurFuZyBjw6FjIGzhu6NpIHThu6ljIGzDoCBiaeG6v24gbmfhuqt1IG5oacOqbiAoUmFuZG9tIFZhcmlhYmxlKSB0aOG7j2EgbcOjbjogDQoNCg0KDQokJFJfe2l9XHNpbSBOKFxtdV9pLFxzaWdtYV9pXjIpJCQNCg0KTmdvw6BpIHJhIHbhu5tpICRpIFxuZSBqJCB0aMOsIGNvdmFyaWFuY2UgY+G7p2EgZ+G6t3AgdMOgaSBz4bqjbiBi4bqldCBrw6wgJGkkIHbDoCAkaiQ6IA0KDQokJFxtYXRocm17Y292fVxsZWZ0KFJfaSwgUl9qIFxyaWdodCkgPSBcc2lnbWFfe2lqfSQkDQoNCk7hur91IHThu4kgdHLhu41uZyBj4bunYSBiYSB0w6BpIHPhuqNuIG7DoHkgdHJvbmcgZGFuaCBt4bulYyDEkeG6p3UgdMawIGzDoCAkeF9BJCwgJHhfQiQgdsOgICR4X0MkIChsxrB1IMO9IHLhurFuZyAkeF9BICsgeF9CICsgeF9DID0gMSQpIHRow6wgbOG7o2kgdOG7qWMgY+G7p2EgZGFuaCBt4bulYywga8OtIGhp4buHdSBsw6AgJFJfcCxfeCQgY8Wpbmcgc+G6vSBsw6AgbeG7mXQgYmnhur9uIG5n4bqrdSBuaGnDqm46IA0KDQokJFxiZWdpbntlcXVhdGlvbn0NClx0YWd7MX0NClJfcCA9IHhfQVJfQSArIHhfQlJfQiArIHhfQ1JfQw0KXGVuZHtlcXVhdGlvbn0kJA0KDQoNCg0KVsOgIGzhu6NpIHThu6ljIGvDrCB24buNbmcgY+G7p2EgZGFuaCBt4bulYyAkXG11X3AsX3gkLCBu4bq/dSBrw60gaGnhu4d1ICRcbXVfQSQsICRcbXVfQiQgdsOgICRcbXVfQyQgbOG6p24gbMaw4bujdCBsw6AgbOG7o2kgdOG7qWMga8OsIHbhu41uZyBj4bunYSBiYSB0w6BpIHPhuqNuIEEsIEIgdsOgIEMgc+G6vSDEkcaw4bujYyB0w61uaCB0aGVvIGPDtG5nIHRo4bupYzogDQoNCiQkXGJlZ2lue2VxdWF0aW9ufQ0KXHRhZ3syfQ0KXG11X3AgPSBFW1JfcF0gPSB4X0FcbXVfQSArIHhfQlxtdV9CICsgeF9DXG11X0MNClxlbmR7ZXF1YXRpb259JCQgDQoNCg0KDQpDw7JuIHLhu6dpIHJvIGPhu6dhIGRhbmggbeG7pWMsIGvDrSBoaeG7h3UgbMOgICRcc2lnbWFfcCQgc+G6vSBsw6A6ICANCg0KJCRcYmVnaW57ZXF1YXRpb259DQpcdGFnezN9DQpcc2lnbWFeMl9wID0gXG1hdGhybXt2YXIoUl9wKSA9IHheMl9BXHNpZ21hXjJfQSArIHheMl9CXHNpZ21hXjJfQiArIHheMl9DXHNpZ21hXjJfQyArIDJ4X0F4X0Jcc2lnbWFfe0FCfSArIDJ4X0J4X0Ncc2lnbWFfe0JDfSArIDJ4X0F4X0Ncc2lnbWFfe0FDfX0NClxlbmR7ZXF1YXRpb259JCQNCg0KDQpDw6FjIGPDtG5nIHRo4bupYyDEkcaw4bujYyBtw7QgdOG6oyBi4bqxbmcgY8OhYyBwaMawxqFuZyB0csOsbmggxJHhuqFpIHPhu5Eg4bufIHRyw6puIGLhuqFuIMSR4buNYyBjw7MgdGjhu4MgdMOsbSB0aOG6pXQg4bufIGLhuqV0IGvDrCBjdeG7kW4gc8OhY2ggbsOgbyB24buBIEludmVzdG1lbnQgdsOgIFBvcnRmb2xpbyBUaGVvcnkuIEPDsm4gdGhlbyBuZ8O0biBuZ+G7ryBj4bunYSBtYSB0cuG6rW4gdsOgIHTDrW5oIHRvw6FuIG1hIHRy4bqtbiAoTWF0cml4IENhbGN1bGF0aW9uKSB0aMOsIGzhu6NpIHThu6ljIGPhu6dhIGRhbmggbeG7pWMgdMOtbmggdGhlbyBjw7RuZyB0aOG7qWMgKDIpIHPhur0gxJHGsOG7o2MgYmnhu4N1IGRp4buFbiBsw6A6IA0KDQokJFxtdV9wID0gWFxtdSQkDQoNCkPDsm4gcuG7p2kgcm8gY+G7p2EgZGFuaCBt4bulYyB0aGVvIGPDtG5nIHRo4bupYyAoMyksIHbhu5tpIGNow7ogw70gcuG6sW5nICRYJyQgbMOgIG1hIHRy4bqtbiBjaHV54buDbiB24buLIGPhu6dhIG1hIHRy4bqtbiAkWCQsIHPhur0gbMOgOiANCg0KDQokJFxzaWdtYV4yX3AgPSBYJ1xTaWdtYSBYJCQNCg0KVHJvbmcgxJHDsyAkWCQsICRcbXUkIHbDoCAkXFNpZ21hJCDEkcaw4bujYyDEkeG7i25oIG5naMSpYSB2w6AgbcO0IHThuqMgZMaw4bubaSDEkcOieTogDQoNCi0gJFxtdSQgbMOgIG1hIHRy4bqtbiBs4bujaSB04bupYyBj4bunYSBiYSB0w6BpIHPhuqNuIEEsIEIgdsOgIEMuIMSQw6J5IGzDoCBtYSB0cuG6rW4gY8OzIGvDrWNoIHRoxrDhu5tjIDPDlzE6IA0KDQokJFxtdSA9IA0KXGJlZ2lue3BtYXRyaXh9DQpcbXVfQSBcXA0KXG11X0IgXFwNClxtdV9DDQpcZW5ke3BtYXRyaXh9JCQgIA0KDQotICRYJCBsw6AgbWEgdHLhuq1uIHThu4kgdHLhu41uZyBj4bunYSBiYSB0w6BpIHPhuqNuIEEsIEIgdsOgIEMgKGvDrWNoIHRoxrDhu5tjIDPDlzEpOiANCg0KJCRYID0gDQpcYmVnaW57cG1hdHJpeH0NCnhfQSAmIHhfQiAmIHhfQw0KXGVuZHtwbWF0cml4fSQkICANCg0KLSAkXFNpZ21hJCBsw6AgbWEgdHLhuq1uIGhp4buHcCBwaMawxqFuZyBzYWkgKENvdmFyaWFuY2UgTWF0cml4KSBj4bunYSBiYSB0w6BpIHPhuqNuIHRyb25nIGRhbmggbeG7pWMgxJHhuqd1IHTGsC4gxJDDonkgbMOgIG3hu5l0IG1hIHRy4bqtbiDEkeG7kWkgeOG7qW5nIChzeW1tZXRyaWMpIGvDrWNoIHRoxrDhu5tjIDPDlzMgdsOsIHLhurFuZyAkXG1hdGhybXtjb3Z9XGxlZnQoUl9pLCBSX2ogXHJpZ2h0KSA9IFxtYXRocm17Y292fVxsZWZ0KFJfaiwgUl9pIFxyaWdodCkkOiANCg0KJCRcYmVnaW57ZXF1YXRpb24qfQ0KXFNpZ21hID0gDQpcYmVnaW57cG1hdHJpeH0NClxzaWdtYV4yX0EgJiBcc2lnbWFfe0FCfSAmIFxzaWdtYV97QUN9IFxcDQpcc2lnbWFfe0FCfSAmIFxzaWdtYV4yX0IgJiBcc2lnbWFfe0JDfSBcXA0KXHNpZ21hX3tBQ30gJiBcc2lnbWFfe0JDfSAmIFxzaWdtYV4yX0MNClxlbmR7cG1hdHJpeH0NClxlbmR7ZXF1YXRpb24qfSQkIA0KDQpOaOG7r25nIG3hu6VjIGTGsOG7m2kgxJHDonkgY2jDum5nIHRhIHPhur0gdHJp4buDbiBraGFpIHTDrW5oIHRvw6FuIGzhu6NpIHThu6ljIC0gcuG7p2kgcm8gY+G7p2EgZGFuaCBt4bulYyDEkeG6p3UgdMawIHbDoCBuaOG7r25nIGLDoGkgdG/DoW4gY8ahIGLhuqNuIGPhu6dhIFBvcnRmb2xpbyBUaGVvcnkgYuG6sW5nIHTDrW5oIHRvw6FuIG1hIHRy4bqtbiB24bubaSBuZ8O0biBuZ+G7ryBSLiANCg0KIyBBIFNpbXBsZSBFeGFtcGxlDQoNCljDqXQgbeG7mXQgZGFuaCBt4bulYyDEkeG6p3UgdMawIGfhu5NtIGJhIGPhu5UgcGhp4bq/dSBBLCBCIHbDoCBDIHbhu5tpIGzhu6NpIHThu6ljIChrw60gaGnhu4d1ICRcbXVfaSQpLCBy4bunaSBybyAoa8OtIGhp4buHdSAkXHNpZ21hX2kkKSB2w6AgY292YXJpYW5jZSB0aGVvIHThu6tuZyBj4bq3cCAoa8OtIGhp4buHdSAkXHNpZ21hX3tpan0kKSDEkcaw4bujYyBjaG8g4bufIFRhYmxlIDEgZMaw4bubaSDEkcOieTogDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KDQpybShsaXN0ID0gbHMoKSkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KDQpjb2xfbmFtZXMgPC0gYygiU3RvY2sgJGkkIiwgIiRcXG11X2kkIiwgIiRcXHNpZ21hX2kkIiwgIlBhaXIgJChpLGopJCIsICIkXFxzaWdtYV97aWp9JCIpDQoNCnN5bWJvbCA8LSBjKExFVFRFUlNbMTozXSkNCg0KbXUgPC0gYygwLjAwMTMxMjc5NTgsIDAuMDAwODg5OTg0MSwgLTAuMDAwNTg2MDEyNCkNCg0Kc2lnbWFfaSA8LSBjKDAuMDIwMzUxMDcsIDAuMDE5OTIzNDgsIDAuMDAwMjcxOTkxNykNCg0KcGFpciA8LSBjKCIoQSxCKSIsICIoQSxDKSIsICIoQixDKSIpDQoNCnNpZ21hX2lqIDwtIGMoMC4wMDAyNTE4Njk2LCAwLjAwMDIzNjYyODUsIDAuMDAwMjcxOTkxNykNCg0KdGhyZWVfZXhhbXBsZSA8LSB0aWJibGUoc3ltYm9sID0gc3ltYm9sLCBtdSA9IG11LCBteV9zaWdtYSA9IHNpZ21hX2ksIHBhaXIgPSBwYWlyLCBzaWdtYV9paiA9IHNpZ21hX2lqKQ0KDQpuYW1lcyh0aHJlZV9leGFtcGxlKSA8LSBjb2xfbmFtZXMNCg0KdGhyZWVfZXhhbXBsZSAlPiUNCiAgaGVhZCgpICU+JSANCiAga2JsKGNhcHRpb24gPSAiVGFibGUgMTogQSBSZWFsLXdvcmxkIGV4YW1wbGUgZGF0YSIsIA0KICAgICAgY29sLm5hbWVzID0gY29sX25hbWVzLCANCiAgICAgIGVzY2FwZSA9IFRSVUUpICU+JQ0KICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGQUxTRSwgaHRtbF9mb250ID0gIkNhbWJyaWEiKQ0KDQpgYGANCg0KWMOpdCBt4buZdCBkYW5oIG3hu6VjIMSR4bqndSB0xrAgbcOgIHThu4kgdHLhu41uZyBj4bunYSBjw6FjIHTDoGkgc+G6o24gQSwgQiwgQyBsw6AgbmjGsCBuaGF1IChlcXVhbGx5IHdlaWdodGVkIHBvcnRmb2xpbykuIETGsOG7m2kgxJHDonkgbMOgIFIgY29kZXMgY2hvIHTDrW5oIHRvw6FuIGzhu6NpIHThu6ljIHbDoCBy4bunaSBybyBj4bunYSBkYW5oIG3hu6VjIMSR4bqndSB0xrAgbsOgeS4gVHLGsOG7m2MgaOG6v3QgbMOgIG5o4bqtcCBz4buRIGxp4buHdSBjaG8gY8OhYyBtYSB0cuG6rW4gJFgkLCAkXG11JCB2w6AgJFxTaWdtYSQgZOG7sWEgdHLDqm4gVGFibGUgMToNCg0KYGBge3J9DQoNCiMgQ2xlYXIgd29ya3NwYWNlOiANCnJtKGxpc3QgPSBscygpKQ0KDQojIFN5bWJvbDogDQpteV9zeW1ib2xzIDwtIExFVFRFUlNbMTozXQ0KDQojIEFzc2V0IFdlaWdodHM6IA0KWCA8LSByZXAoMSAvIDMsIDMpDQoNCiMgQXNzZXQgcmV0dXJuczogDQptdSA8LSBjKDAuMDAxMzEyNzk1OCwgMC4wMDA4ODk5ODQxLCAtMC4wMDA1ODYwMTI0KQ0KDQojIEFzc2V0IHJpc2tzOiANCnNpZ21hX2kgPC0gYygwLjAyMDM1MTA3LCAwLjAxOTkyMzQ4LCAwLjAzMDk4MDQ4KQ0KDQojIENvdmFyaWFuY2U6IA0Kc2lnbWFfaWogPC0gYygwLjAwMDI1MTg2OTYsIDAuMDAwMjM2NjI4NSwgMC4wMDAyNzE5OTE3KQ0KDQojIENyZWF0ZSBjb3ZhcmlhbmNlIG1hdHJpeDogDQpzaWdtYV9tYXRyaXhfMyA8LSBtYXRyaXgoYyhzaWdtYV9pWzFdKnNpZ21hX2lbMV0sIHNpZ21hX2lqWzFdLCBzaWdtYV9palsyXSwgDQogICAgICAgICAgICAgICAgICAgICAgICBzaWdtYV9palsxXSwgc2lnbWFfaVsyXSpzaWdtYV9pWzJdLCBzaWdtYV9palszXSwgDQogICAgICAgICAgICAgICAgICAgICAgICBzaWdtYV9palsyXSwgc2lnbWFfaWpbM10sIHNpZ21hX2lbM10qc2lnbWFfaVszXSksDQogICAgICAgICAgICAgICAgICAgICAgICBucm93ID0gMywgYnlyb3cgPSBUUlVFKQ0KDQojIFNldCBuYW1lIGZvciBjb3ZhcmlhbmNlIG1hdHJpeDoNCmRpbW5hbWVzKHNpZ21hX21hdHJpeF8zKSA8LSBsaXN0KG15X3N5bWJvbHMsIG15X3N5bWJvbHMpDQoNCmBgYA0KDQpNYSB0cuG6rW4gaGnhu4dwIHBoxrDGoW5nIHNhaTogDQoNCmBgYHtyfQ0KbGlicmFyeShtYWdyaXR0cikgIyBGb3IgdXNpbmcgUGlwZSBvcGVyYXRvci4gDQpsaWJyYXJ5KGthYmxlRXh0cmEpICMgRm9yIHByZXNlbnRpbmcgdGFibGUuIA0KDQpzaWdtYV9tYXRyaXhfMyAlPiUgDQogIGtibChjYXB0aW9uID0gIlRhYmxlIDI6IENvdmFyaWFuY2UgbWF0cml4IiwgZXNjYXBlID0gVFJVRSkgJT4lDQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEZBTFNFLCBodG1sX2ZvbnQgPSAiQ2FtYnJpYSIpDQogIA0KICANCmBgYA0KDQpUw61uaCB0b8OhbiBs4bujaSB04bupYyB2w6AgcuG7p2kgcm8gY2hvIGRhbmggbeG7pWMgxJHhuqd1IHTGsDogDQoNCmBgYHtyfQ0KIyBQb3J0Zm9saW8gcmV0dXJuOiANCm11X3BvcnQgPSBjcm9zc3Byb2QoWCwgbXUpDQoNCm11X3BvcnQgPC0gbXVfcG9ydCAlPiUgYXMubnVtZXJpYygpDQoNCiMgUG9ydGZvbGlvIHJpc2s6IA0KDQpzaWcyX3BvcnQgPC0gdChYKSAlKiUgc2lnbWFfbWF0cml4XzMgJSolIFgNCg0Kc2lnX3BvcnQgPC0gc2lnMl9wb3J0ICU+JSBhcy5udW1lcmljKCkgJT4lIHNxcnQoKQ0KDQojIFByaW50IHJlc3VsdHM6IA0KDQpwcmludChtdV9wb3J0KSAjIFJldHVybg0KcHJpbnQoc2lnX3BvcnQpICMgUmlzaw0KYGBgDQoNCkRhbmggbeG7pWMgxJHhuqd1IHTGsCBuw6B5IHR1eSBs4bujaSB04bupYyBjaOG7iSBi4bqxbmcgNDElIHNvIHbhu5tpIHTDoGkgc+G6o24gQiBuaMawbmcgcuG7p2kgcm8gbOG6oWkgZ+G6p24gYuG6sW5nLiBN4buZdCBuaMOgIMSR4bqndSB0xrAgZHV5IGzDrSDEkcawxqFuZyBuaGnDqm4gc+G6vSDGsGEgdGjDrWNoIMSR4bqndSB0xrAgdG/DoG4gYuG7mSB0w6BpIHPhuqNuIGPhu6dhIG3DrG5oIHbDoG8gQiBoxqFuIGzDoCBwaMOibiBi4buVIMSR4buBdSB2w6BvIGJhIHTDoGkgc+G6o24uIERvIHbhuq15IG3DoCB0cuG7jW5nIHTDom0gY+G7p2EgbMOtIHRodXnhur90IGRhbmggbeG7pWMgKFBvcnRmb2xpbyBUaGVvcnkpIHbDoCBs4buxYSBjaOG7jW4gZGFuaCBt4bulYyDEkeG6p3UgdMawIChQb3J0Zm9saW8gU2VsZWN0aW9uKSBsw6AgdHLhuqMgbOG7nWkgY8OidSBo4buPaSBraeG7g3UgbmjGsCBzYXU6IA0KDQoxLiBDw7MgaGF5IGtow7RuZyBt4buZdCBz4buxIGvhur90IGjhu6NwIGPhu6UgdGjhu4MgbsOgbyDEkcOzIGPhu6dhIGPDoWMgdMOgaSBz4bqjbiBtw6AgY8O5bmcgduG7m2kgbeG7qWMgbOG7o2kgdOG7qWMgbmjGsCB0w6BpIHPhuqNuIEEgLSB0w6BpIHPhuqNuIGPDsyBs4bujaSB04bupYyBjYW8gbmjhuqV0IHRyb25nIHPhu5EgYmEgdMOgaSBz4bqjbiBuaMawbmcgY8OzIHLhu6dpIHJvIHRo4bqlcCBoxqFuPyANCg0KMi4gQ8OzIGhheSBraMO0bmcgbeG7mXQgc+G7sSBr4bq/dCBo4bujcCBj4bulIHRo4buDIG7DoG8gxJHDsyBj4bunYSBjw6FjIHTDoGkgc+G6o24gbcOgIGPDuW5nIHbhu5tpIG3hu6ljIGzhu6NpIHThu6ljIG5oxrAgdMOgaSBz4bqjbiBCIG5oxrBuZyBy4bunaSBybyBs4bqhaSB0aOG6pXAgaMahbiAwLjAxOTkyMzU/IA0KDQozLiBDw7MgaGF5IGtow7RuZyBt4buZdCBz4buxIGvhur90IGjhu6NwIGPhu6UgdGjhu4MgbsOgbyDEkcOzIGPhu6dhIGPDoWMgdMOgaSBz4bqjbiBtw6AgduG7m2kgbeG7mXQgbeG7qWMgbOG7o2kgdOG7qWMgbeG7pWMgdGnDqnUgxJHhu4tuaCB0csaw4bubYyBsw6AsIHbDrSBk4bulLCAxJSBuaMawbmcgcuG7p2kgcm8gbMOgIHRo4bqlcCBuaOG6pXQgY8OzIHRo4buDIMSRxrDhu6NjLCB0aOG6rW0gY2jDrSBsw6AgdGjhuqVwIGjGoW4gY+G6oyBy4bunaSBybyBj4bunYSB0w6BpIHPhuqNuIEMgLSBsw6AgdMOgaSBz4bqjbiBjw7MgcuG7p2kgcm8gdGjhuqVwIG5o4bqldCB0cm9uZyBz4buRIGJhIHTDoGkgc+G6o24/DQoNCk5o4buvbmcgY8OidSBo4buPaSBuw6B5IHPhur0gZOG6p24gxJHGsOG7o2Mgc8OhbmcgdOG7jyB0cm9uZyBjw6FjIG3hu6VjIGvhur8gdGnhur9wLiANCg0KIyBBIFJlYWwtd29ybGQgQXBwbGljYXRpb24NCg0KVHJvbmcgdGjhur8gZ2nhu5tpIHRo4buxYyBjaMO6bmcgdGEgY+G6p24gdMOtbmggxJHGsOG7o2MgVGFibGUgMSB04burIGThu68gbGnhu4d1IHRow7QgKHJhdyBkYXRhKS4gxJDhu4MgbWluaCBo4buNYSBjaMO6bmcgdGEgY2jhu41uIGJhIGPDtG5nIHRpIGzDoCBNaWNyb3NvZnQsIFN0YXJidWNrcyB2w6AgR2VuZXJhbCBNb3RvciAodOG7qWMgbMOgIG3hu5l0IGPDtG5nIHRpIGPDtG5nIG5naOG7hywgbeG7mXQgY8O0bmcgdGkgaMOgbmcgdGnDqnUgZMO5bmcgbmhhbmggdsOgIG3hu5l0IGPDtG5nIHRpIGPDtG5nIG5naGnhu4dwIG7hurduZykgdsOgIGzhuqV5IGThu68gbGnhu4d1IGzhu4tjaCBz4butIHbhu4EgZ2nDoSBj4buVIHBoaeG6v3UgY+G7p2EgYmEgY8O0bmcgdGkgbsOgeSBi4bqxbmcgaMOgbSBgdHFfZ2V0KClgIGPhu6dhIHRoxrAgdmnhu4duICoqdGlkeXF1YW50KiogdOG7qyAyMDE4LTAxLTAxIMSR4bq/biAyMDIwLTEyLTMxOiANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00fQ0KIyBDbGVhciB3b3Jrc3BhY2U6IA0Kcm0obGlzdCA9IGxzKCkpDQoNCiMgU29tZSBzdG9ja3Mgc2VsZWN0ZWQgKE1pY3Jvc29mdCwgU3RhcmJ1Y2tzIGFuZCBBcHBsZSk6IA0KDQpteV9zeW1ib2xzIDwtIGMoIk1TRlQiLCAiU0JVWCIsICJHRSIpDQoNCiMgTnVtYmVyIG9mIHN0b2NrczogDQoNCm4gPC0gbGVuZ3RoKG15X3N5bWJvbHMpDQoNCiMgQ29sbGVjdCBkYXRhOiANCg0KbGlicmFyeSh0aWR5cXVhbnQpDQpwcmljZV9kYXRhIDwtIHRxX2dldChteV9zeW1ib2xzLA0KICAgICAgICAgICAgICAgICAgICAgZnJvbSA9ICIyMDE4LTAxLTAxIiwNCiAgICAgICAgICAgICAgICAgICAgIHRvID0gIjIwMjAtMTItMzEiLA0KICAgICAgICAgICAgICAgICAgICAgZ2V0ID0gInN0b2NrLnByaWNlcyIpDQpgYGANCg0KQ2jDum5nIHRhIGPDsyB0aOG7gyB4ZW0gZ2nDoSBj4bunYSBiYSBj4buVIHBoaeG6v3UgdOG6oWkgbmfDoHkgY3Xhu5FpIGPDuW5nIHRyb25nIG3huqt1IGThu68gbGnhu4d1IMSRw6MgbOG6pXk6IA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9DQoNCiMgU2hvdyBzb21lIG9ic2VydmF0aW9uczogDQoNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KcHJpY2VfZGF0YSAlPiUgDQogIGdyb3VwX2J5KHN5bWJvbCkgJT4lIA0KICBzbGljZSh3aGljaC5tYXgoZGF0ZSkpICU+JSANCiAga2JsKGNhcHRpb24gPSAiVGFibGUgMzogU29tZSBPYnNlcnZhdGlvbnMiLCBlc2NhcGUgPSBUUlVFKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRkFMU0UsIGh0bWxfZm9udCA9ICJDYW1icmlhIikNCg0KYGBgDQoNClh1IGjGsOG7m25nIGJp4bq/biDEkeG7mW5nIHbhu4EgZ2nDoSBoaeG7h3UgY2jhu4luaCAoYWRqdXN0ZWQpIGPhu6dhIGJhIGPhu5UgcGhp4bq/dSBuw6B5IChGaWd1cmUgMSk6IA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9DQoNCiMgUHJpY2UgdHJlbmQ6IA0KDQpwcmljZV9kYXRhICU+JSANCiAgZ2dwbG90KGFlcyhkYXRlLCBhZGp1c3RlZCwgY29sb3IgPSBzeW1ib2wpKSArDQogIGdlb21fbGluZShzaG93LmxlZ2VuZCA9IEZBTFNFKSArIA0KICBmYWNldF93cmFwKH4gc3ltYm9sLCBzY2FsZXMgPSAiZnJlZSIpICsgDQogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMLCANCiAgICAgICB0aXRsZSA9ICJGaWd1cmUgMTogU3RvY2sgUHJpY2UiKQ0KDQpgYGANCg0KVMOtbmggdG/DoW4gbOG7o2kgdOG7qWMgY+G7p2EgY8OhYyB0w6BpIHPhuqNuIMSRxrDhu6NjIMSRbyBi4bqxbmcgbG9nIHJldHVybiB0aGVvIGPDtG5nIHRo4bupYyBzYXU6IA0KDQoNCiQkUl90PVxsblxsZWZ0KFxmcmFje1Bfe3R9fSB7UF97dC0xfX1ccmlnaHQpJCQgDQoNClRyb25nIMSRw7MgJFBfdCQgbMOgIGdpw6EgY+G7p2EgdMOgaSBz4bqjbiDhu58gdGjhu51pIMSRaeG7g20gdCB2w6AgJFBfe3QtMX0kIGzDoCBnacOhIGPhu6dhIHTDoGkgc+G6o24gdOG6oWkgdGjhu51pIMSRaeG7g20gdHLGsOG7m2MgxJHDsyAxIG5nw6B5IChjw7JuIGfhu41pIGzDoCB0cuG7hSAxLCBrw60gaGnhu4d1IGzDoCAkbGFnXzEkKS4gDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0NCg0KIyBDYWxjdWxhdGUgZGFpbHkgcmV0dXJuIGJhc2VkIG9uIGFkanVzdGVkIHByaWNlOiANCg0KcHJpY2VfZGF0YSAlPiUNCiAgZ3JvdXBfYnkoc3ltYm9sKSAlPiUgDQogIG11dGF0ZShsYWcxID0gbGFnKGFkanVzdGVkLCBuID0gMUwpKSAlPiUgDQogIGZpbHRlcighaXMubmEobGFnMSkpICU+JSANCiAgbXV0YXRlKGRhaWx5X3JldHVybiA9IGxvZyhhZGp1c3RlZCAvIGxhZzEpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIHNlbGVjdChzeW1ib2wsIGRhdGUsIGRhaWx5X3JldHVybikgLT4gZGFpbHlfcmV0dXJucw0KYGBgDQoNClBow6JuIHBo4buRaSBj4bunYSBs4bujaSB04bupYyBjw7MgduG6uyBsw6AgcGjDom4gcGjhu5FpIGNodeG6qW4gbmjGsCB0YSBjw7MgdGjhu4MgdGjhuqV5IOG7nyBGaWd1cmUgMiBkxrDhu5tpIMSRw6J5OiANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00fSAgDQojIFJldHVybiBkaXN0cmlidXRpb246IA0KDQpkYWlseV9yZXR1cm5zICU+JSANCiAgZ2dwbG90KGFlcyhkYWlseV9yZXR1cm4sIGZpbGwgPSBzeW1ib2wsIGNvbG9yID0gc3ltYm9sKSkgKyANCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC4xLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSwgYWxwaGEgPSAwLjEsIGJpbndpZHRoID0gMC4wMSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKyANCiAgZmFjZXRfd3JhcCh+IHN5bWJvbCwgc2NhbGVzID0gImZyZWUiKSArIA0KICBsYWJzKHggPSBOVUxMLCB5ID0gTlVMTCwgDQogICAgICAgdGl0bGUgPSAiRmlndXJlIDI6IERhaWx5IFJldHVybiBEaXN0cmlidXRpb24iKQ0KDQpgYGANCg0KxJDhu4MgY8OzIGvhur90IGx14bqtbiBjaMOtbmggeMOhYyBwaMOibiBwaOG7kWkgY8OzIHBo4bqjaSBsw6AgcGjDom4gcGjhu5FpIGNodeG6qW4gaGF5IGtow7RuZyBjaMO6bmcgdGEgY8OzIHRo4buDIGThu7FhIHbDoG8gbeG7mXQgdGVzdCB0aOG7kW5nIGvDqiBsw6AgSmFycXVl4oCTQmVyYSAoSkIpIHRlc3QuIFRyxrDhu5tjIGjhur90IHZp4bq/dCBow6BtIHTDrW5oIHRvw6FuIHRo4buRbmcga8OqIG7DoHkgY8O5bmcgcC12YWx1ZSB0xrDGoW5nIOG7qW5nOiANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00fSANCiMgRnVuY3Rpb24gY2FsY3VsYXRlcyBKYXJxdWXigJNCZXJhIChKQikgdGVzdDogDQpteV9KQiA8LSBmdW5jdGlvbih4KSB7DQogIG4gPC0gbGVuZ3RoKHgpDQogIG0xIDwtIHN1bSh4KS9uDQogIG0yIDwtIHN1bSgoeCAtIG0xKV4yKS9uDQogIG0zIDwtIHN1bSgoeCAtIG0xKV4zKS9uDQogIG00IDwtIHN1bSgoeCAtIG0xKV40KS9uDQogIGIxIDwtIChtMy9tMl4oMy8yKSleMg0KICBiMiA8LSAobTQvbTJeMikNCiAgSkIgPC0gbiAqIGIxLzYgKyBuICogKGIyIC0gMyleMi8yNA0KICByZXR1cm4oSkIpDQp9DQoNCiMgQ2FsY3VsYXRlcyBwLXZhbHVlIGZvciBKQiB0ZXN0OiANCm15X3N0YXMgPC0gZnVuY3Rpb24oeCkgew0KICBuIDwtIGxlbmd0aCh4KQ0KICBtMSA8LSBzdW0oeCkvbg0KICBtMiA8LSBzdW0oKHggLSBtMSleMikvbg0KICBtMyA8LSBzdW0oKHggLSBtMSleMykvbg0KICBtNCA8LSBzdW0oKHggLSBtMSleNCkvbg0KICBiMSA8LSAobTMvbTJeKDMvMikpXjINCiAgYjIgPC0gKG00L20yXjIpDQogIEpCIDwtIG4gKiBiMS82ICsgbiAqIChiMiAtIDMpXjIvMjQNCiAgcF92YWx1ZSA9IDEgLSBwY2hpc3EoSkIsIGRmID0gMikNCiAgcmV0dXJuKHBfdmFsdWUpDQp9DQpgYGANCg0KSMOgbSB0w61uaCB0b8OhbiBiYSB0acOqdSBjaMOtIHF1YW4gdHLhu41uZyBraMOhYyBsw6AgU2tld25lc3MsIEt1cnRvc2lzIHbDoCBDViAoQ29lZmZpY2llbnQgb2YgdmFyaWF0aW9uKTogDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0gDQoNCiMgRnVudGlvbnMgY2FsY3VsYXRlcyBTa2V3bmVzczogDQpteV9zIDwtIGZ1bmN0aW9uKHgpIHsNCiAgbiA8LSBsZW5ndGgoeCkNCiAgeCA8LSB4IC0gbWVhbih4KQ0KICB5IDwtIHNxcnQobikgKiBzdW0oeF4zKS8oc3VtKHheMileKDMvMikpDQogIHkgPC0geSAqICgoMSAtIDEvbikpXigzLzIpDQogIHJldHVybih5KQ0KfQ0KDQojIEZ1bnRpb25zIGNhbGN1bGF0ZXMga3VydG9zaXM6IA0KbXlfayA8LSBmdW5jdGlvbih4KSB7DQogIG4gPC0gbGVuZ3RoKHgpDQogIHggPC0geCAtIG1lYW4oeCkNCiAgciA8LSBuICogc3VtKHheNCkvKHN1bSh4XjIpXjIpDQogIHkgPC0gIHIgKiAoMSAtIDEvbileMiAtIDMNCiAgcmV0dXJuKHkpDQp9DQoNCiMgRnVuY3Rpb24gY2FsY3VsYXRlcyBDViAoQ29lZmZpY2llbnQgb2YgdmFyaWF0aW9uKTogDQpteV9jdiA8LSBmdW5jdGlvbih4KSB7DQogIGN2IDwtIHNkKHgpIC8gbWVhbih4KQ0KICByZXR1cm4oY3YpDQp9DQpgYGANCg0KVGFibGUgNCBsaeG7h3Qga8OqIGPDoWMgdGjhu5FuZyBrw6ogcXVhbiB0cuG7jW5nIGPDuW5nIHbhu5tpIGtp4buDbSDEkeG7i25oIEpCIFRlc3QgY2hvIGzhu6NpIHThu6ljIGPhu6dhIGJhIHTDoGkgc+G6o246IA0KDQpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9IA0KIyBBcHBseSBmdW50aW9ucyBmb3Igb3VyIHN0b2NrOiANCg0KZGFpbHlfcmV0dXJucyAlPiUgDQogIGdyb3VwX2J5KHN5bWJvbCkgJT4lIA0KICBzdW1tYXJpc2UoU2tld25lc3MgPSBteV9zKGRhaWx5X3JldHVybiksIA0KICAgICAgICAgICAgS3VydG9zaXMgPSBteV9rKGRhaWx5X3JldHVybiksIA0KICAgICAgICAgICAgQ1YgPSBteV9jdihkYWlseV9yZXR1cm4pLCANCiAgICAgICAgICAgIEpCX3Rlc3QgPSBteV9KQihkYWlseV9yZXR1cm4pLCANCiAgICAgICAgICAgIHBfdmFsdWUgPSBteV9zdGFzKGRhaWx5X3JldHVybiksIA0KICAgICAgICAgICAgTWVhbiA9IG1lYW4oZGFpbHlfcmV0dXJuKSwgDQogICAgICAgICAgICBNaW4gPSBtaW4oZGFpbHlfcmV0dXJuKSwgDQogICAgICAgICAgICBNYXggPSBtYXgoZGFpbHlfcmV0dXJuKSwgDQogICAgICAgICAgICBTRCA9IHNkKGRhaWx5X3JldHVybiksIA0KICAgICAgICAgICAgTiA9IG4oKSkgLT4gZGZfc3RhdGlzdGljcw0KDQojIFNvbWUgbWFpbiBzdGF0aXN0aWNzIGZvciBzdG9ja3M6IA0KDQpkZl9zdGF0aXN0aWNzICU+JSANCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bmN0aW9uKHgpIHtyb3VuZCh4LCAzKX0pICU+JSANCiAga2JsKGNhcHRpb24gPSAiVGFibGUgNDogTWFpbiBTdGF0aXN0aWNzIGZvciBTeW1ib2wiLCBlc2NhcGUgPSBUUlVFKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRkFMU0UsIGh0bWxfZm9udCA9ICJDYW1icmlhIikNCg0KYGBgDQoNCkPDoWMgZ2nDoSB0cuG7iyBwX3ZhbHVlIG7DoHkgcuG6pXQgdGjhuqVwIGRvIHbhuq15IGPDsyB0aOG7gyBjaOG6pXAgbmjhuq1uIGdp4bqjIHRodXnhur90IHLhurFuZyBjw6FjIGzhu6NpIHThu6ljIGPDsyBwaMOibiBwaOG7kWkgY2h14bqpbi4gRMaw4bubaSDEkcOieSBsw6AgUiBjb2RlcyDEkeG7gyB0w61uaCB0b8OhbiBs4bujaSB04bupYyB2w6AgcuG7p2kgcm8gY2hvIGJhIGPhu5UgcGhp4bq/dTogDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0gDQojIENhbGN1bGF0ZSByaXNrIGFuZCByZXR1cm4gZm9yIGFzc2V0czoNCiAgDQpkYWlseV9yZXR1cm5zICU+JSANCiAgZ3JvdXBfYnkoc3ltYm9sKSAlPiUgDQogIHN1bW1hcmlzZShyaXNrID0gc2QoZGFpbHlfcmV0dXJuKSwgcmV0dXJuID0gbWVhbihkYWlseV9yZXR1cm4pKSAtPiBkZl9yaXNrX3JldHVybg0KDQojIENvbnZlcnQgdG8gd2lkZSBmb3JtOiANCg0KZGFpbHlfcmV0dXJucyAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBzeW1ib2wsIHZhbHVlc19mcm9tID0gZGFpbHlfcmV0dXJuKSAlPiUgDQogIHNlbGVjdCgtZGF0ZSkgLT4gcmV0dXJuc193aWRlDQoNCiMgQXNzZXQgbWVhbiByZXR1cm46IA0KDQptdSA8LSBjb2xNZWFucyhyZXR1cm5zX3dpZGUpIA0KDQpwcmludChtdSkNCmBgYA0KDQpUw61uaCBDb3ZhcmlhbmNlIE1hdHJpeCBj4bunYSBiYSB0w6BpIHPhuqNuOiANCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD00fSANCiMgQ292YXJpYW5jZSBtYXRyaXg6IA0KDQpzaWdtYV9tYXRyaXggPC0gY292KHJldHVybnNfd2lkZSkNCg0KcHJpbnQoc2lnbWFfbWF0cml4KQ0KDQpgYGANCg0KWMOpdCBt4buZdCBkYW5oIG3hu6VjIMSR4bqndSB0xrAgbcOgIGPDoWMgdHLhu41uZyBz4buRIGPhu6dhIGPDoWMgdMOgaSBz4bqjbiBsw6AgbmjGsCBuaGF1IChFcXVhbC13ZWlnaHQgcG9ydGZvbGlvKS4gRMaw4bubaSDEkcOieSBsw6AgUiBjb2RlcyB0w61uaCB0b8OhbiBs4bujaSB04bupYyB2w6AgcuG7p2kgcm8gY+G7p2EgZGFuaCBt4bulYyDEkeG6p3UgdMawIG7DoHkgdGhlbyBuZ8O0biBuZ+G7ryBtYSB0cuG6rW46IA0KDQpgYGB7cn0NCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgRXF1YWwtd2VpZ2h0IHBvcnRmb2xpbw0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNClggPC0gcmVwKDEgLyBuLCBuKQ0KDQojIFBvcnRmb2xpbyByZXR1cm46IA0KbXVfcG9ydCA9IGNyb3NzcHJvZChYLCBtdSkNCg0KbXVfcG9ydF9lcXUgPC0gbXVfcG9ydCAlPiUgYXMubnVtZXJpYygpDQoNCiMgUG9ydGZvbGlvIHJpc2s6IA0KDQpzaWcyX3BvcnRfZXF1IDwtIHQoWCkgJSolIHNpZ21hX21hdHJpeCAlKiUgWA0KDQpzaWdfcG9ydF9lcXUgPC0gc2lnMl9wb3J0X2VxdSAlPiUgYXMubnVtZXJpYygpICU+JSBzcXJ0KCkNCg0KIyBQcmludCByZXN1bHRzOiANCg0KcHJpbnQobXVfcG9ydF9lcXUpICMgUmV0dXJuDQpwcmludChzaWdfcG9ydF9lcXUpICMgUmlzaw0KYGBgDQoNCljDqXQgbeG7mXQgZGFuaCBt4bulYyDEkeG6p3UgdMawIGPDsyBjw6FjIHRy4buNbmcgc+G7kSAod2VpZ2h0cykgY+G7p2EgY8OhYyB0w6BpIHPhuqNuIGzDoCA0MCUsIDgwJSB2w6AgLTIwJS4gVHLhu41uZyBz4buRIMOibSBjw7MgbmdoxKlhIGzDoCBuZ3Xhu5NuIHTDoGkgY2jDrW5oIMSR4buDIMSR4bqndSB0xrAgdsOgbyBj4buVIHBoaeG6v3UgY+G7p2EgR0UgYuG6sW5nIGPDoWNoICJtxrDhu6NuIiAodGh14bqtdCBuZ+G7ryB0aeG6v25nIEFuaCBsw6AgU2hvcnQgU2VsbCkuIExv4bqhaSBkYW5oIG3hu6VjIMSR4bqndSB0xrAgY8OzIHRy4buNbmcgc+G7kSDDom0gbsOgeSDEkcaw4bujYyBn4buNaSBsw6AgTG9uZy1TaG9ydCBwb3J0Zm9saW8uIFTGsMahbmcgdOG7sSBuaMawIOG7nyB0csOqbiwgdHLGsOG7m2MgaOG6v3QgY2jDum5nIHRhIHThuqFvIFggbMOgIHZlY3RvciBjw6FjIHRy4buNbmcgc+G7kTogDQoNCmBgYHtyfQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIExvbmctU2hvcnQgcG9ydGZvbGlvDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpYIDwtIGMoMC40LCAwLjgsIC0wLjIpDQpgYGANCg0KROG7hSBkw6BuZyB0aOG6pXkgcuG6sW5nIHThu5VuZyBjw6FjIHRy4buNbmcgc+G7kSBsdcO0biBi4bqxbmcgMS4gTOG7o2kgdOG7qWMgdsOgIHLhu6dpIHJvIGPhu6dhIGRhbmggbeG7pWMgxJHhuqd1IHTGsCBuw6B5OiANCg0KYGBge3J9DQojIFBvcnRmb2xpbyByZXR1cm46IA0KbXVfcG9ydF9zaG8gPSBjcm9zc3Byb2QoWCwgbXUpDQoNCm11X3BvcnRfc2hvIDwtIG11X3BvcnRfc2hvICU+JSBhcy5udW1lcmljKCkNCg0KIyBQb3J0Zm9saW8gcmlzazogDQoNCnNpZzJfcG9ydF9zaG8gPC0gdChYKSAlKiUgc2lnbWFfbWF0cml4ICUqJSBYDQoNCnNpZ19wb3J0X3NobyA8LSBzaWcyX3BvcnRfc2hvICU+JSBhcy5udW1lcmljKCkgJT4lIHNxcnQoKQ0KYGBgDQoNCkNow7puZyB0YSBuw6puIGzGsHUgbOG6oWkgY8OhYyBr4bq/dCBxdeG6oyDEkcOjIGPDszogDQoNCmBgYHtyfQ0KDQp0d29fcG9ydCA8LSB0aWJibGUoc3ltYm9sID0gYygiRVFVQSIsICJTSE9SVCIpLCANCiAgICAgICAgICAgICAgICAgICByaXNrID0gYyhzaWdfcG9ydF9lcXUsIHNpZ19wb3J0X3NobyksIA0KICAgICAgICAgICAgICAgICAgIHJldHVybiA9IGMobXVfcG9ydF9lcXUsIG11X3BvcnRfc2hvKSkNCg0KZGZfcmlza19yZXR1cm4gJT4lIGJpbmRfcm93cyh0d29fcG9ydCkgLT4gZGZfdG90YWwNCg0KZGZfdG90YWwgJT4lIA0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgZnVuY3Rpb24oeCkge3JvdW5kKHgsIDQpfSkgJT4lIA0KICBrYmwoY2FwdGlvbiA9ICJUYWJsZSA1OiBSaXNrLXJldHVybiB0cmFkZS1vZmYiLCBlc2NhcGUgPSBUUlVFKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRkFMU0UsIGh0bWxfZm9udCA9ICJDYW1icmlhIikNCiAgDQoNCmBgYA0KDQpUYWJsZSA1IGNo4buJIHJhIHLhurFuZyBMb25nLVNob3J0IHBvcnRmb2xpbyAoa8OtIGhp4buHdSBTSE9SVCkgY8OzIGzhu6NpIHThu6ljIGzhu5tuIG5o4bqldCB2w6AgY2FvIGjGoW4gbOG7o2kgdOG7qWMgY+G7p2EgbcOjIE1TRlQgLSBj4buVIHBoaeG6v3UgY8OzIGzhu6NpIHThu6ljIGNhbyBuaOG6pXQgdHJvbmcgc+G7kSBiYSB0w6BpIHPhuqNuIG5oxrBuZyBy4bunaSBybyBj4bunYSBkYW5oIG3hu6VjIG7DoHkgbOG6oWkgdGjhuqVwIGjGoW4gcuG7p2kgcm8gY+G7p2EgTVNGVC4gTGnhu4d1IHLhurFuZyB2aeG7h2MgxJFhIGThuqFuZyBow7NhIGLhurFuZyBjw6FjaCDEkeG6p3UgdMawIHbDoG8gYmEgdMOgaSBz4bqjbiB0csOqbiB24bubaSB0cuG7jW5nIHPhu5EgbOG6p24gbMaw4bujdCBsw6AgNDAlIGNobyBNU0ZULCA4MCUgY2hvIFNCVVggdsOgIC0yMCUgY2hvIEdFIGPDsyBwaOG6o2kgbMOgIGzhu7FhIGNo4buNbiB04buRaSDGsHUgaGF5IGNow60gw610IGzDoCBoaeG7h3UgcXXhuqM/IENow7puZyB0YSBz4bq9IHRy4bqjIGzhu51pIGPDonUgaOG7j2kgbsOgeSDhu58gbeG7pWMga+G6vyB0aeG6v3AgbmdheSBzYXUgxJHDonkuIA0KDQojIEVmZmljaWVudCBQb3J0Zm9saW9zIGJ5IFNpbXVsYXRpb24NCg0KTmjGsCDhu58gdHLDqm4gxJHDoyBwaMOibiB0w61jaCwgYuG6sW5nIGPDoWNoIHRoYXkgxJHhu5VpIGPDoWMgdHLhu41uZyBz4buRIGNow7puZyB0YSBjw7MgaGFpIGRhbmggbeG7pWMgxJHhuqd1IHTGsC4gRGFuaCBt4bulYyDEkeG6p3UgdMawIHRo4bupIG5o4bqldCAoa8OtIGhp4buHdSBFUVVBKSBjw7MgY8OhYyB0cuG7jW5nIHPhu5EgYuG6sW5nIG5oYXUgKHbDoCDEkeG7gXUgYuG6sW5nIDMzLjMzJSkgY8OybiBkYW5oIG3hu6VjIHRo4bupIGhhaSAoa8OtIGhp4buHdSBTSE9SVCkgY8OzIGPDoWMgdHLhu41uZyBz4buRIGzhuqduIGzGsOG7o3QgbMOgIDQwJSwgODAlIHbDoCAtMjAlLiDEkOG7gyB0w6xtIMSRxrDhu6NjIGRhbmggbeG7pWMgxJHhuqd1IHTGsCBoaeG7h3UgcXXhuqMgbeG7mXQgdHJvbmcgbmjhu69uZyBjw6FjaCBtw6AgY2jDum5nIHRhIGPDsyB0aOG7gyBz4butIGThu6VuZyBsw6AgYuG6sW5nIG3DtCBwaOG7j25nIChTaW11bGF0aW9uKS4gVGhlbyBjw6FjaCB0aeG6v3AgY+G6rW4gIG7DoHkgY2jDum5nIHRhIHPhur0ga2jhuqNvIHPDoXQgY+G6t3Agcmlzay1yZXR1cm4gY+G7p2EsIGNo4bqzbmcgaOG6oW4sIDEwMDAwIGRhbmggbeG7pWMgxJHhuqd1IHTGsCBraMOhYyBuaGF1IHTGsMahbmcg4bupbmcgduG7m2kgMTAwMDAgYuG7mSB0cuG7jW5nIHPhu5Ega2jDoWMgbmhhdSBjaG8gY8OhYyB0w6BpIHPhuqNuIGPhuqV1IHRow6BuaCBuw6puIGRhbmggbeG7pWMuIEThu7FhIHRyw6puIGto4bqjbyBzw6F0IHbhu4EgY+G6t3Agcmlzay1yZXR1cm4gY+G7p2EgMTAwMDAgZGFuaCBt4bulYyDEkeG6p3UgdMawIG7DoHkgY2jDum5nIHRhIGPDsyB0aOG7gyB0cuG6oyBs4budaSBt4buZdCBz4buRIGPDonUgaOG7j2kgbmjGsCAqKnBo4bqjaSBjaMSDbmcgY8OybiB04buTbiB04bqhaSBt4buZdCBkYW5oICBt4bulYyB24bubaSBi4buZIHRy4buNbmcgc+G7kSBuw6BvIMSRw7MgbcOgIGzhu6NpIHThu6ljIHRow6wgY8OybiBjYW8gaMahbiBs4bujaSB04bupYyBj4bunYSBTSE9SVCBuaMawbmcgcuG7p2kgcm8gY8OybiB0aOG6pXAgaMahbiBj4bqjIHLhu6dpIHJvIGPhu6dhIFNIT1JUPyoqLiANCg0KTMawdSDDvSBy4bqxbmcgY2hvIMSR4bq/biBoaeG7h24gdOG6oWksIHThu6sgVGFibGUgNSB0aMOsIFNIT1JUIGNow61uaCBsw6AgZGFuaCBt4bulYyDEkeG6p3UgdMawICJ04buRdCBuaOG6pXQiIGPEg24gY+G7qSB2w6BvIHJldHVybiBjw7JuIEVRVUEgbMOgIGRhbmggbeG7pWMgxJHhuqd1IHTGsCBjw7MgcuG7p2kgcm8gdGjhuqVwIG5o4bqldCBjxINuIGPhu6kgdsOgbyByaXNrLiANCg0KDQrEkOG7gyB0aOG7sWMgaGnhu4duIHNpbXVsYXRpb24gdHLGsOG7m2MgaOG6v3QgY2jDum5nIHRhIHZp4bq/dCBt4buZdCBow6BtIGPDsyB0w6puIGzDoCBgcG9ydGZvbGlvX3Jpc2tfcmV0dXJuKClgIHTDrW5oIHRvw6FuIGPhurdwIHJpc2stcmV0dXJuIGPhu6dhIG3hu5l0IGRhbmggbeG7pWMgxJHhuqd1IHTGsCBu4bq/dSBjaG8gdHLGsOG7m2MgY8OhYyB0cuG7jW5nIHPhu5EgdMawxqFuZyDhu6luZyB24bubaSBiYSB0w6BpIHPhuqNuIE1TRlQsIFNCVVggdsOgIEdFOiAgDQoNCg0KYGBge3J9DQoNCmxpYnJhcnkocnBvcnRmb2xpb3MpDQoNCnBvcnRmb2xpb19yaXNrX3JldHVybiA8LSBmdW5jdGlvbihqKSB7DQogIA0KICAjIENyZWF0ZSByYW5kb20gd2VpZ2h0czogDQogIA0KICBzZXQuc2VlZChqKQ0KICANCiAgWCA8LSByYW5kb20uYm91bmRlZChuID0gbiwgeC50ID0gMSwgeC5sID0gcmVwKC0xLCBuKSwgeC51ID0gcmVwKDEsIG4pKQ0KDQogICMgUG9ydGZvbGlvIHJldHVybjogDQogIG11X3BvcnRfcmFuZCA9IGNyb3NzcHJvZChYLCBtdSkgJT4lIGFzLm51bWVyaWMoKQ0KDQogICMgUG9ydGZvbGlvIHJpc2s6IA0KICBzaWdfcG9ydF9yYW5kIDwtIHQoWCkgJSolIHNpZ21hX21hdHJpeCAlKiUgWCAlPiUgYXMubnVtZXJpYygpICU+JSBzcXJ0KCkNCiAgDQogICMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBvZiByZXN1bHRzOiANCiAgZGZfcG9mdCA8LSB0aWJibGUoc3ltYm9sID0gbXlfc3ltYm9scywgDQogICAgICAgICAgICAgICAgICAgIHdlaWdodCA9IFgsIA0KICAgICAgICAgICAgICAgICAgICByZXR1cm4gPSBtdV9wb3J0X3JhbmQsIA0KICAgICAgICAgICAgICAgICAgICByaXNrID0gc2lnX3BvcnRfcmFuZCwNCiAgICAgICAgICAgICAgICAgICAgcG9ydF9pbmRleCA9IGopDQogIA0KICByZXR1cm4oZGZfcG9mdCkNCg0KfQ0KYGBgDQoNCkPDoWMgdHLhu41uZyBz4buRIHPhu60gZOG7pW5nIHRyb25nIHTDrW5oIHRvw6FuIGPhu6dhIGjDoG0gdHLDqm4gxJHGsOG7o2MgdOG6oW8gcmEgdOG7qyBow6BtIGByYW5kb20uYm91bmRlZCgpYCBj4bunYSB0aMawIHZp4buHbiAqKnJwb3J0Zm9saW9zKiouIEzGsHUgw70gcuG6sW5nOiAoMSkgdOG7lW5nIGPDoWMgdHLhu41uZyBz4buRIGx1w7RuIGzDoCAxLCB2w6AgKDIpIHRy4buNbmcgc+G7kSBjw7MgdGjhu4MgbMOgIMOibSBuaMawIGPDsyB0aOG7gyB0aOG6pXk6IA0KDQpgYGB7cn0NCnNldC5zZWVkKDI5KQ0KcmFuZG9tLmJvdW5kZWQobiA9IG4sIHgudCA9IDEsIHgubCA9IHJlcCgtMSwgbiksIHgudSA9IHJlcCgxLCBuKSkNCmBgYA0KDQpT4butIGThu6VuZyBow6BtIG7DoHkgdMOtbmggdG/DoW4gY+G6t3Agcmlzay1yZXR1cm4gY+G7p2EgMTAwMDAgZGFuaCBt4bulYyDEkeG6p3UgdMawIHbDoCBsxrB1IGzhuqFpIGvhur90IHF14bqjIGTGsOG7m2kgZOG6oW5nIG3hu5l0IERhdGEgRnJhbWUgY8OzIHTDqm4gKipkZl9yZXR1cm5fbWluaV8xMDAwMCoqIG5oxrAgZMaw4bubaSDEkcOieTogIA0KDQpgYGB7cn0NCnN5c3RlbS50aW1lKGxhcHBseSgxOjEwMDAwLCBwb3J0Zm9saW9fcmlza19yZXR1cm4pIC0+IGFsbF9yZXR1cm5fcG9ydCkNCg0KZG8uY2FsbCgiYmluZF9yb3dzIiwgYWxsX3JldHVybl9wb3J0KSAtPiBkZl9yZXR1cm5fMTAwMDANCg0KZGZfcmV0dXJuXzEwMDAwICU+JSANCiAgZmlsdGVyKCFkdXBsaWNhdGVkKHBvcnRfaW5kZXgpKSAtPiBkZl9yZXR1cm5fbWluaV8xMDAwMA0KYGBgDQoNCkzhuqV5IHJhIGRhbmggbeG7pWMgxJHhuqd1IHTGsCBjw7MgcuG7p2kgcm8gdGjhuqVwIG5o4bqldCB2w6AgZGFuaCBt4bulYyDEkeG6p3UgdMawIGPDsyBs4bujaSB04bupYyBjYW8gbmjhuqV0OiAgDQoNCmBgYHtyfQ0KIyBNaW5pbXVtIHJpc2sgcG9ydGZvbGlvOiANCm1pbl9yaXNrIDwtIGRmX3JldHVybl9taW5pXzEwMDAwICU+JSBzbGljZSh3aGljaC5taW4ocmlzaykpIA0KDQojIE1heGltdW0gcmV0dXJuIHBvcnRmb2xpbzogDQptYXhfcmV0dXJuIDwtIGRmX3JldHVybl9taW5pXzEwMDAwICU+JSBzbGljZSh3aGljaC5tYXgocmV0dXJuKSkgDQpgYGANCg0KRmlndXJlIDMgZMaw4bubaSDEkcOieSBjaOG7iSByYSBj4bq3cCByaXNrLXJldHVybiBjaG8gMTAwMDIgZGFuaCBt4bulYyAoMTAwMDAgZGFuaCBt4bulYyArIGhhaSBkYW5oIG3hu6VjIEVRVUEgdsOgIFNIT1JUKTogDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3JlcGVsKQ0KbGlicmFyeShzY2FsZXMpDQoNCmRmX3JldHVybl9taW5pXzEwMDAwICU+JSANCiAgZ2dwbG90KGFlcyhyaXNrLCByZXR1cm4pKSArIA0KICBnZW9tX3BvaW50KGFscGhhID0gMC4wNSwgY29sb3IgPSAiYmx1ZSIpICsgDQogIGdlb21fcG9pbnQoZGF0YSA9IG1pbl9yaXNrLCBjb2xvciA9ICJyZWQiLCBzaXplID0gMywgc2hhcGUgPSAxNykgKyANCiAgZ2VvbV90ZXh0X3JlcGVsKGRhdGEgPSBtaW5fcmlzaywgYWVzKGxhYmVsID0gIk1pbiBSaXNrIikpICsgDQogIGdlb21fcG9pbnQoZGF0YSA9IG1heF9yZXR1cm4sIGNvbG9yID0gInB1cnBsZSIsIHNpemUgPSAzLCBzaGFwZSA9IDE4KSArIA0KICBnZW9tX3RleHRfcmVwZWwoZGF0YSA9IG1heF9yZXR1cm4sIGFlcyhsYWJlbCA9ICJNYXggUmV0dXJuIikpICsgDQogIGdlb21fcG9pbnQoZGF0YSA9IGRmX3RvdGFsICU+JSBmaWx0ZXIoIXN5bWJvbCAlaW4lIGMoIkVRVUEiLCAiU0hPUlQiKSksIGNvbG9yID0gImdyZWVuIiwgc2l6ZSA9IDIpICsgDQogIGdlb21fcG9pbnQoZGF0YSA9IGRmX3RvdGFsICU+JSBmaWx0ZXIoc3ltYm9sICVpbiUgYygiRVFVQSIsICJTSE9SVCIpKSwgY29sb3IgPSAib3JhbmdlIiwgc2l6ZSA9IDIpICsgDQogIGdlb21fdGV4dF9yZXBlbChkYXRhID0gZGZfdG90YWwsIGFlcyhsYWJlbCA9IHN5bWJvbCkpICsgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudCkgKyANCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiUmlzayIgfiAoc2lnbWEpKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIlJldHVybiIgfiAobXUpKSwgDQogICAgICAgdGl0bGUgPSAiRmlndXJlIDM6IFBvcnRmb2xpbyBPcHRpbWl6YXRpb24gJiBFZmZpY2llbnQgRnJvbnRpZXIiKSANCmBgYA0KDQpCYSB0w6BpIHPhuqNuIMSRxqFuIGzhursgKGPDsyB0aOG7gyBjb2kgbMOgIGJhIGRhbmggbeG7pWMgxJHhuqd1IHTGsCBtw6AgdHJvbmcgxJHDsyBjw6FjIHRy4buNbmcgc+G7kSBj4bunYSBoYWkgdMOgaSBz4bqjbiBsw6AgMCUgY8OybiB0w6BpIHPhuqNuIHRo4bupIGJhIGPDsyB0cuG7jW5nIHPhu5EgMTAwJSkgxJHGsOG7o2MgYmnhu4N1IGRp4buFbiBi4bqxbmcgYmEgxJFp4buDbSBtw6B1IHhhbmguIEhhaSBkYW5oIG3hu6VjIEVRVUEgdsOgIFNIT1JUIGzDoCBoYWkgxJFp4buDbSBtw6B1IHbDoG5nIGPDsm4gbcOgdSDEkeG7jyB2w6AgdMOtbSBs4bqnbiBsxrDhu6N0IGzDoCBoYWkgZGFuaCBt4bulYyBjw7MgcuG7p2kgcm8gdGjhuqVwIG5o4bqldCB2w6AgbOG7o2kgdOG7qWMgY2FvIG5o4bqldC4gDQoNCkZpZ3VyZSAzIGNo4buJIHJhIHLhurFuZzogDQoNCjEuIFbhuqtuIHThu5NuIHThuqFpIHLhuqV0IG5oaeG7gXUgZGFuaCBt4bulYyDEkeG6p3UgdMawIG3DoCBzbyB24bubaSBTSE9SVCB0aMOsOiAoMSkgbOG7o2kgdOG7qWMgY2FvIGjGoW4sIHbDoCAoMikgcuG7p2kgcm8gdGjhuqVwIGjGoW4uDQoyLiBW4bqrbiBjw7JuIHThuqFpIHLhuqV0IG5oaeG7gXUgZGFuaCBt4bulYyDEkeG6p3UgdMawIG3DoCBzbyB24bubaSBFUVVBIHRow6w6ICgxKSBs4bujaSB04bupYyBjYW8gaMahbiwgdsOgICgyKSBy4bunaSBybyB0aOG6pXAgaMahbi4gDQoNCg0KQ2jDum5nIHRhIGPDsyB0aOG7gyB4ZW0gdOG7iSB0cuG7jW5nIGPDoWMgdMOgaSBz4bqjbiBjw7MgcuG7p2kgcm8gdGjhuqVwIG5o4bqldCB0cm9uZyBz4buRIDEwMDAyIGRhbmggbeG7pWMgxJHhuqd1IHTGsCAoxJFp4buDbSBtw6B1IMSR4buPKTogDQoNCg0KYGBge3J9DQoNCmRmX3JldHVybl8xMDAwMCAlPiUgDQogIGZpbHRlcihwb3J0X2luZGV4ID09IG1pbl9yaXNrJHBvcnRfaW5kZXgpICU+JSANCiAgbXV0YXRlKHdlaWdodCA9IHJvdW5kKHdlaWdodCoxMDAsIDIpKSAlPiUgDQogIG11dGF0ZSh3ZWlnaHQgPSBhcy5jaGFyYWN0ZXIod2VpZ2h0KSkgJT4lIA0KICBtdXRhdGUod2VpZ2h0ID0gcGFzdGUwKHdlaWdodCwgIiUiKSkgJT4lIA0KICBzZWxlY3QoLXBvcnRfaW5kZXgpICU+JSANCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bmN0aW9uKHgpIHtyb3VuZCh4LCAzKX0pICU+JSANCiAga2JsKGNhcHRpb24gPSAiVGFibGUgNTogTWluaW11bS12YXJpYW5jZSBQb3J0Zm9saW8iLCBlc2NhcGUgPSBUUlVFKSAlPiUNCiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRkFMU0UsIGh0bWxfZm9udCA9ICJDYW1icmlhIikNCiAgDQpgYGANCg0KVsOgIGRhbmggbeG7pWMgxJHhuqd1IHTGsCBjw7MgbOG7o2kgdOG7qWMgY2FvIG5o4bqldCAoxJFp4buDbSBtw6B1IHTDrW0pOiANCg0KYGBge3J9DQpkZl9yZXR1cm5fMTAwMDAgJT4lIA0KICBmaWx0ZXIocG9ydF9pbmRleCA9PSBtYXhfcmV0dXJuJHBvcnRfaW5kZXgpICU+JSANCiAgbXV0YXRlKHdlaWdodCA9IHJvdW5kKHdlaWdodCoxMDAsIDIpKSAlPiUgDQogIG11dGF0ZSh3ZWlnaHQgPSBhcy5jaGFyYWN0ZXIod2VpZ2h0KSkgJT4lIA0KICBtdXRhdGUod2VpZ2h0ID0gcGFzdGUwKHdlaWdodCwgIiUiKSkgJT4lIA0KICBzZWxlY3QoLXBvcnRfaW5kZXgpICU+JSANCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIGZ1bmN0aW9uKHgpIHtyb3VuZCh4LCAzKX0pICU+JSANCiAga2JsKGNhcHRpb24gPSAiVGFibGUgNjogTWF4aW11bi1yZXR1cm4gUG9ydGZvbGlvIiwgZXNjYXBlID0gVFJVRSkgJT4lDQogIGthYmxlX2NsYXNzaWMoZnVsbF93aWR0aCA9IEZBTFNFLCBodG1sX2ZvbnQgPSAiQ2FtYnJpYSIpDQoNCg0KYGBgDQoNCiMgU3VtbWFyeQ0KDQrEkGEgZOG6oW5nIGjDs2EgxJHhuqd1IHTGsCBuaOG6sW0gZ2nhuqNtIHRoaeG7g3UgcuG7p2kgcm8gbMOgIG3hu5l0IHRyb25nIG5o4buvbmcgaOG7hyBxdeG6oyBxdWFuIHRy4buNbmcgY+G7p2EgbMOtIHRodXnhur90IGRhbmggbeG7pWMgxJHhuqd1IHTGsCAoUG9ydGZvbGlvIFRoZW9yeSkuIFBo4bqnbiAxIGPhu6dhICB0csaw4bubYyBo4bq/dCDEkWnhu4NtIGzhuqFpIG5o4buvbmcgxJFp4buDbSBj4buRdCBsw7VpIGPhu6dhIGzDrSB0aHV54bq/dCBkYW5oIG3hu6VjIMSR4bqndSB0xrAgdsOgIHZp4buHYyB0w61uaCB0b8OhbiB0aGVvIG5nw7RuIG5n4buvIG1hIHRy4bqtbiB24bubaSBSIGPFqW5nIG5oxrAgY8OhY2ggdGnhur9wIGPhuq1uIHRy4buxYyBxdWFuIMSR4buDIHTDrG0gcmEgZGFuaCBt4bulYyDEkeG6p3UgdMawIGhp4buHdSBxdeG6oyAoRWZmaWNpZW50IFBvcnRmb2xpbykgYuG6sW5nIHBoxrDGoW5nIHBow6FwIG3DtCBwaOG7j25nLiBUcm9uZyB0csaw4budbmcgaOG7o3AgZGFuaCBt4bulYyDEkeG6p3UgdMawIGPDsyBuIHTDoGkgc+G6o24ga2jDoWMgbmhhdSB0aMOsIHZp4buHYyDDoXAgZOG7pW5nIHbDoCB0w61uaCB0b8OhbiB24bqrbiBraMO0bmcgY8OzIGfDrCB0aGF5IMSR4buVaS4gDQoNCsSQ4buRaSB24bubaSBjw6FjIGtow61hIGPhuqFuaCBuaMawIGzDrSB0aHV54bq/dCB24buBIFBvcnRmb2xpbyBUaGVvcnksIGPGoSBz4bufIFRvw6FuIC0gVGjhu5FuZyBLw6ovdMOtbmggdG/DoW4gbWEgdHLhuq1uIChNYXRyaXggQ2FsY3VsYXRpb24pIHbhu5tpIG5nw7RuIG5n4buvIFIgbMOgIG5o4buvbmcgbeG6o25nIGtp4bq/biB0aOG7qWMva8SpIG7Eg25nIG3DoCBuZ8aw4budaSB2aeG6v3QgYsOgaSBuw6B5IG3hurdjIMSR4buLbmggYuG6oW4gxJHhu41jIMSRw6MgbuG6r20gxJHGsOG7o2MuIELhuqFuIMSR4buNYyBxdWFuIHTDom0gY8OzIHRo4buDIHRoYW0ga2jhuqNvIGPDoWMgdMOgaSBsaeG7h3UgbGnhu4d0IGvDqiDhu58gbeG7pWMgUmVmZXJlbmNlcy4gDQoNCiMgUmVmZXJlbmNlcw0KDQoxLiBbSW52ZXN0bWVudHMgMTB0aCBFZGl0aW9uIGJ5IFp2aSBCb2RpZSwgQWxleCBLYW5lIChBdXRob3IpLCBBbGFuIEouIE1hcmN1c10oaHR0cHM6Ly93d3cuYW1hem9uLmNvbS9JbnZlc3RtZW50cy0xMHRoLVp2aS1Cb2RpZS9kcC8wMDc3ODYxNjcxKS4gDQoyLiBbTW9kZXJuIFBvcnRmb2xpbyBUaGVvcnkgYW5kIEludmVzdG1lbnQgQW5hbHlzaXMsIDl0aCBFZGl0aW9uIGJ5IEVsdG9uIGV0IGFsLl0oaHR0cHM6Ly93d3cud2lsZXkuY29tL2VuLXVzL01vZGVybitQb3J0Zm9saW8rVGhlb3J5K2FuZCtJbnZlc3RtZW50K0FuYWx5c2lzJTJDKzl0aCtFZGl0aW9uLXAtOTc4MTExODQ2OTk0MSkuIA0KMy4gW0Jhc2ljcyBvZiBNYXRyaXggQWxnZWJyYSBmb3IgU3RhdGlzdGljcyB3aXRoIFIgYnkgTmljayBGaWVsbGVyXShodHRwczovL3d3dy5hbWF6b24uY29tL0Jhc2ljcy1NYXRyaXgtQWxnZWJyYS1TdGF0aXN0aWNzLUNoYXBtYW4tZWJvb2svZHAvQjAxMTZSNDZUUS9yZWY9c3JfMV8xP2RjaGlsZD0xJmtleXdvcmRzPW1hdHJpeCtjYWxjdWxhdGlvbitpbityJnFpZD0xNjExNDkxOTY5JnM9Ym9va3Mmc3I9MS0xKQ0KDQoNCg0KDQo=