Giới thiệu
Ở chương này, chúng ta sẽ khảo sát thành quả được quan tâm nhất trong
nghiên cứu về hỗ trợ sinh sản, đó là sự thụ thai (thai sinh hóa, lâm
sàng), sự tiếp diễn thành công của thai kì (thai diễn tiến) và sự sinh
nở. Trong y văn, những kết cục này thường được khảo sát như một giá trị
mang tính nhị phân (Có hoặc không), hoặc tỷ lệ thành công trên tổng số
cá thể bệnh nhân. Tuy nhiên, bản chất của loại kết cục này có thể được
nhìn nhận như một xác suất hay khả năng thành công và cũng có tính kế
thừa như một phần trong chuỗi kết quả của tiến trình thụ tinh nhân tạo.
Vì vậy, ta có thể áp dụng quy luật phân phối nhị thức (binomial) để khảo
sát chúng.
Thí dụ, kết quả thai diễn tiến thường được ghi nhận bằng 2 giá trị 0
(không) hoặc 1 (có) trong dữ liệu, nhưng bản chất của thai diễn tiến có
thể xem như xác suất thành công \(p\)
của 1 thử nghiệm chuyển phôi. Chính vì trên thực tế, số lượng phôi được
chuyển rất thấp, chỉ giới hạn ở 1 đến 2 phôi cho mỗi chu kì, nên kết quả
quan sát được mới biểu hiện thành giá trị 0 hoặc 1.
Trong chương này, ta sẽ tìm hiểu về phân tích hồi quy logistic và
trường hợp tổng quát của nó - một mô hình hồi quy GLM với phân phối
Binomial, cho phép suy diễn thống kê cho kết quả nhị phân hoặc xác suất
thành công của thử nghiệm.
Tình huống minh họa là một thử nghiệm lâm sàng với mục tiêu so sánh
hiệu quả của phác đồ PPOS so với phác đồ tham chiếu là GnRH_ant đối với
khả năng đạt được thai diễn tiến (ongoing pregnancy). Trong thí nghiệm
này, phác đồ GnRH_ant được áp dụng cho nhóm đối chứng gồm 107 phụ nữ
hiếm muộn, và phác đồ PPOS áp dụng cho nhóm can thiệp gồm 99 trường hợp.
Sau khi thu hoạch noãn, thụ tinh và trữ phôi, người ta thực hiện từ 1
đến 3 lần chuyển phôi, mỗi lần 1-2 phôi và ghi nhận kết quả thai diễn
tiến cộng dồn (nếu một trường hợp không thành công ở lần chuyển phôi đầu
tiên, ta sẽ lặp lại quy trình chuyển phôi lần 2, hoặc lần 3). Thử nghiệm
kết thúc ở lần thứ 3.
Kết cục sẽ được khảo sát dưới 3 hình thức:
Giá trị nhị phân: thành công hay thất bại tuyệt đối : có đạt được
thai diễn tiến hay không (cho tối đa 3 lần): 0 = Không, 1 = Có (bất kể
song thai, đơn thai)
Tần suất: số lượng thai diễn tiến cho mỗi cá thể (giá trị = 0
(không đạt được), 1 = đơn thai diễn tiến, 2 = song thai diễn
tiến).
Tỷ lệ đạt thai diễn tiến = số thai diễn tiến chia cho tổng số
phôi được chuyển. Thí dụ: Lần 1 chuyển 2 phôi, kết quả không đạt, lần 2
chuyển 2 phôi và đạt đơn thai, thì tỷ lệ thành công = \(1/(2+2) = 0.25\)
Lưu ý rằng các trường hợp: sẫy thai, thai ngoài tử cung… xem như thất
bại.
Kế hoạch phân tích
Xác suất đạt thai diễn tiến cộng dồn khi áp dụng phác đồ PPOS, so với
phương pháp tham chiếu là GnRH_ant sẽ được ước lượng bằng marginal
Odds-ratio (OR) và risk-ratio (RR), có hiệu chỉnh cho Tuổi, AFC và độ
dày nội mạc trung bình ngày chuyển phôi, dựa vào một mô hình hồi quy
logistic. Suy diễn thống kê dựa vào phủ nhận giả thuyết vô hiệu (OR và
RR = 1) ở ngưỡng ý nghĩa p = 0.05.
Công cụ cần thiết cho
quy trình
Thư viện dplyr trong hệ sinh thái tidyverse để thao tác dữ liệu
và thống kê mô tả
Thư viện ggplot2, ggrides, tidybayes và ggdist để vẽ một số biểu
đồ thống kê;
Thư viện patchwork để ghép nhiều biểu đồ ggplot2 với
nhau.
Thư viện gamlss để dựng mô hình GLM với phân phối
Binomial
Thư viện marginaleffects để ước tính OR, RR và suy diễn thống kê
từ kết quả mô hình.
library(tidyverse)
library(ggridges)
library(gamlss)
library(marginaleffects)
library(tidybayes)
library(ggdist)
library(patchwork)
Đầu tiên, ta tải dữ liệu từ file ‘PPOS_OP.csv’ vào dataframe df, sau
đó ta
df = read.csv('PPOS_OP.csv', sep = ';',
dec = ',',
fileEncoding = 'UTF-8-BOM')%>%
na.omit()
df$Protocol = factor(df$Protocol)
df%>%dplyr::sample_frac(0.3)%>%head()%>%knitr::kable()
34 |
PPOS |
11 |
2 |
1 |
9.200000 |
1 |
0.5 |
27 |
PPOS |
13 |
2 |
2 |
12.233333 |
1 |
1.0 |
22 |
GnRHa |
17 |
2 |
1 |
13.900000 |
1 |
0.5 |
32 |
GnRHa |
9 |
2 |
1 |
9.133333 |
1 |
0.5 |
34 |
GnRHa |
11 |
2 |
0 |
14.300000 |
0 |
0.0 |
34 |
PPOS |
12 |
1 |
1 |
13.600000 |
1 |
1.0 |
Trong dữ liệu này:
Age = Tuổi bệnh nhân,
AFC = Dự trữ buồng trứng cơ bản;
Thickness = độ dày nội mạc tử cung;
n_ET: tổng số phôi đã chuyển trong tiến trình nghiên cứu;
OP_cum = tần suất thai diễn tiến cộng dồn (giá trị cao nhất = 2, thấp
nhất = 0);
OP_bin = kết quả thành công/thất bại tuyệt đối (2 giá trị 0,1)
OP_rate = tỷ lệ thai diễn tiến = OP_cum / n_ET
Bước 1: Phân tích mô
tả
Ta kết hợp hàm group_by và summarize của thư viện dplyr để thực hiện
thống kê mô tả cho những hình thức khác nhau của kết cục thai diễn tiến
cộng dồn:
- Khảo sát tần suất thai diễn tiến (biến OP_cum)
Đây là một biến số rời rạc và chỉ có thể có 3 giá trị: 0, 1 hoặc 2.
Kết quả mô tả như sau:
getmode <- function(v) {
uniqv <- unique(v)
uniqv[which.max(tabulate(match(v, uniqv)))]
}
df%>%group_by(Protocol)%>%
summarize(n = n(),
Sum = sum(OP_cum),
mean = sprintf("%0.2f", mean(OP_cum)),
Median = sprintf("%0.2f", median(OP_cum)),
Mode = sprintf("%0.2f", getmode(OP_cum)),
SD = sprintf("%0.2f", sd(OP_cum)),
p5 = sprintf("%0.2f", quantile(OP_cum, 0.05)),
p95 = sprintf("%0.2f", quantile(OP_cum, 0.95)),
)%>%knitr::kable()
GnRHa |
107 |
87 |
0.81 |
1.00 |
1.00 |
0.70 |
0.00 |
2.00 |
PPOS |
99 |
102 |
1.03 |
1.00 |
1.00 |
0.66 |
0.00 |
2.00 |
Theo kết quả này, nếu xét về số lượng tuyệt đối, thì dường như giữa 2
phác đồ PPOS và GnRH không có sự khác biệt nào cả: Mode = 1 cho thấy kết
quả thường gặp nhất cho cả 2 phác đồ là đạt ít nhất 1 thai diễn tiến.
Xét bình quân thì nhóm PPOS có vẻ ưu thế hơn: số thai diễn tiến trung
bình là 1.03 so với 0.81; cả 2 đều có độ phân tán cao tương đương (SD
khoảng 0.7).
- Nếu xét về tỷ lệ thai diễn tiến trên tổng số phôi chuyển:
df%>%group_by(Protocol)%>%
summarize(n = n(),
Mean = sprintf("%0.3f", mean(OP_rate)),
Median = sprintf("%0.3f", median(OP_rate)),
SD = sprintf("%0.3f", sd(OP_rate)),
p5 = sprintf("%0.3f", quantile(OP_rate, 0.05)),
p95 = sprintf("%0.3f", quantile(OP_rate, 0.95)),
)%>%knitr::kable()
GnRHa |
107 |
0.370 |
0.500 |
0.355 |
0.000 |
1.000 |
PPOS |
99 |
0.457 |
0.500 |
0.343 |
0.000 |
1.000 |
Kết quả này cho thấy tỳ lệ thai diễn tiến trung bình có vẻ ưu thế hơn
ở nhóm PPOS so với GnRHant: 0.46 so với 0.37 (nói cách khác, xác suất
thụ thai thành công cho mỗi phôi chuyển có vẻ cao hơn ở phác đồ PPOS);
Ta có thể ước tính Risk ratio (RR) giữa 2 phác đồ: \(RR = 0.457/0.37 = 1.235\). Tuy nhiên giá
trị trung vị lại tương đương (0.5). Nói cách khác, nếu cứ chuyển phôi 2
lần thì dự kiến ít nhất sẽ có 1 lần đạt thành công.
- Tỷ số xác suất thành công/thất bại (Odds)
Ta có thể ước lượng kết quả thai diễn tiến theo một cách khác, bằng
tỷ số Odds
\[Odds = \frac{p_1}{p_0} = \frac{p_1}{(1 -
p_1)}\]
Với \(p_1\) là xác suất thành công,
\(p_0\) là xác suất thất bại.
df%>%mutate(Odds = OP_rate/(1-OP_rate))->odd_df
odd_df$Odds[!is.finite(odd_df$Odds)] <- NA
odd_df%>%
group_by(Protocol)%>%
summarize(n = n(),
Mean = sprintf("%0.3f", mean(Odds, na.rm=TRUE)),
Median = sprintf("%0.3f", median(Odds,na.rm=TRUE)),
SD = sprintf("%0.3f", sd(Odds, na.rm=TRUE)),
p5 = sprintf("%0.3f", quantile(Odds, 0.05, na.rm=TRUE)),
p95 = sprintf("%0.3f", quantile(Odds, 0.95,na.rm=TRUE)),
)%>%knitr::kable()
GnRHa |
107 |
0.462 |
0.333 |
0.470 |
0.000 |
1.000 |
PPOS |
99 |
0.556 |
0.500 |
0.426 |
0.000 |
1.000 |
Theo kết quả này, Odds của nhóm PPOS cao hơn Odds của nhóm GnRHant
(0.556 so với 0.462), nói cách khác Odds ratio giữa PPOS và GnRHa :
\(OR = 0.556/0.462 = 1.203\)
- Nếu xét giá trị thành công hay thất bại tuyệt đối (biến nhị giá
OP_bin)
Khi thực hiện phân tích này, đơn vị quan sát là cá thể bệnh nhân thay
vì đơn vị phôi. Cách khảo sát này sẽ cho ra một kết quả khác
df%>%group_by(Protocol)%>%
summarize(n = n(),
Rate = mean(OP_bin),
Freq = sum(OP_bin),
Odds = Rate/(1-Rate),
)%>%knitr::kable()
GnRHa |
107 |
0.6448598 |
69 |
1.815789 |
PPOS |
99 |
0.7979798 |
79 |
3.950000 |
Dựa vào kết quả này, tỷ số xác suất thành công giữa 2 phác đồ : \(RR = 0.798/0.645 = 1.237\) và Odds-ratio
giữa chúng \(OR = 3.95/1.815 = 2.176\).
Ở đây ta thấy một điểm thú vị là khi chọn đơn vị khảo sát là bệnh nhân,
kết quả OR và RR có khuynh hướng cao hơn so với khi xét đơn vị khảo sát
là phôi.
Ta lần lượt khảo sát trực quan 3 hình thức khảo sát kết quả thai diễn
tiến trong 3 biểu đồ sau
pals = c("#0faaf2","#f20f4f")
p1 = df %>% ggplot(aes(y = OP_cum,
x = Protocol,
fill= Protocol)) +
geom_jitter(aes(fill = Protocol),
shape = 21,
alpha = 0.8,
width = 0.1,
height = 0.2,
show.legend = T)+
labs(y="Cummulated OP", x = "Protocol") +
scale_fill_manual(values = pals, name = "Protocol") +
scale_y_continuous(breaks = c(0,1,2,3))+
theme_bw(10) +
theme(axis.text = element_text(size = 10, color = "black"),
axis.title = element_text(size = 10, color = "black"))
p2 = df %>% ggplot(aes(x = OP_rate,
y = Protocol,
fill= Protocol)) +
geom_density_ridges(aes(fill = Protocol),
stat = "binline",
scale = 0.5,
bins = 30,
alpha = 0.8)+
labs(x="Cummulated OP rate", y = "Protocol") +
scale_fill_manual(values = pals, name = "Protocol") +
coord_flip()+
theme_bw(10)
p3 = df%>%
group_by(Protocol)%>%
summarise(Success = mean(OP_bin),
Failure = 1 - Success)%>%
gather(c(2,3),key = "OP", value = "Rate")%>%
ggplot(aes(x = Protocol, y = Rate))+
geom_bar(aes(fill = OP), stat = "identity")+
scale_fill_manual(values = c("#c0bec2","#f03a79"), name = "OP Outcome") +
theme_bw(10)
p3 + p1/p2

Chú thích: Hình bên trái là biểu đồ cột chồng trình bày phân bố tỷ lệ
Thành công/Thất bại (trục Y) giữa 2 phác đồ (trục X), hình bên phải gồm
2 biểu đồ: góc trên là biểu đồ tán xạ so sánh tần suất thai diễn tiến
(trục Y) giữa 2 phác đồ (trục X), góc dưới là biểu đồ tần suất mô tả tỷ
lệ thai diễn tiến cộng dồn (trục Y) giữa 2 phác đồ (trục X).
Ngoài 2 phác đồ, trong dữ liệu còn có một số hiệp biến khác như Tuổi,
AFC và độ dày nội mạc có bản chất là biến số liên tục. Ta muốn khảo sát
trực quan mối liên hệ giữa những hiệp biến này và xác suất đạt thai diễn
tiến; ta có thể thực hiện theo 3 cách:
Liên hệ biến X và giá trị 0,1 của biến OP_bin, thông qua đồ thị
của mô hình GLM với phân phối binomial (đồ thị hàm logistic)
Liên hệ biến X và giá trị tỷ lệ OP_rate, thông qua 1 mô hình hồi
quy GLM với phân phối quasibinomial;
Liên hệ biến X và Odds, thông qua một mô hình hồi quy tuyến
tính
p4 = df%>%gather(c(1,3,6),
key = "Factor",
value = "value")%>%
ggplot(aes(x = value, y = OP_bin))+
geom_smooth(aes(fill = Protocol,
col = Protocol),
method = "glm",
method.args = list(family = "binomial"),
show.legend = F)+
scale_y_continuous(limits = c(0,1))+
scale_fill_manual(values = pals, name = "Protocol") +
scale_color_manual(values = pals, name = "Protocol") +
facet_wrap(~Factor, ncol=1, scales = "free_x")+
labs(y="Binary OP", x = NULL) +
theme_bw(10)
p5 = df%>%gather(c(1,3,6),
key = "Factor",
value = "value")%>%
ggplot(aes(x = value, y = OP_rate))+
geom_smooth(aes(fill = Protocol,
col = Protocol),
method = "glm",
method.args = list(family = "quasibinomial"))+
scale_y_continuous(limits = c(0,1))+
scale_fill_manual(values = pals, name = "Protocol") +
scale_color_manual(values = pals, name = "Protocol") +
facet_wrap(~Factor, ncol=1, scales = "free_x")+
labs(y="OP rate", x = NULL) +
theme_bw(10)
p6 = df%>%mutate(odd = OP_rate/(1-OP_rate))%>%
gather(c(1,3,6),
key = "Factor",
value = "value")%>%
ggplot(aes(x = value, y = odd))+
geom_smooth(aes(fill = Protocol,
col = Protocol),
method = "glm",
show.legend = F)+
scale_fill_manual(values = pals, name = "Protocol") +
scale_color_manual(values = pals, name = "Protocol") +
facet_wrap(~Factor, ncol=1, scales = "free_x")+
labs(y="Odds = p1/p0", x = NULL) +
theme_bw(10)
p4+p6+p5

Chú thích: Hình trên gồm 3 cột, từ trái sang phải lần lượt trình bày:
(1) Liên hệ giữa giá trị AFC, Age, Thickness (3 hàng, trục X) và khả
năng đạt thai diễn tiến (trục Y); (2) Liên hệ giữa giá trị AFC, Age,
Thickness (3 hàng, trục X) và Odds (tỉ số giữa xác suất thành công/thất
bại); và (3) Liên hệ giữa giá trị AFC, Age, Thickness (3 hàng, trục X)
và tỷ lệ thai diễn tiến trên tổng số phôi chuyển (trục Y). Dữ liệu được
phân thành 2 nhóm: phác đồ PPOS (màu hồng) và GnRha (màu xanh).
Hình ảnh này gợi ý một số giả thuyết như sau:
AFC có hiệu ứng tương tác giữa AFC và loại phác đồ, vì 2 đồ thị
các hàm tuyến tính/logistic của 2 nhóm cắt nhau, với hiệu ứng AFC khác
biệt ở mỗi nhóm.
Tuổi có hiệu ứng độc lập và đồng nhất ở 2 phác đồ, khả năng thai
diễn tiến tương quan nghịch với tuổi (giảm dần ở phụ nữ lớn
tuổi);
Độ dày nội mạc tử cung có hiệu ứng độc lập với phác đồ, và đồng
nhất giữa 2 nhóm phác đồ, hiệu ứng này rất yếu và có khuynh hướng tương
quan thuận với khả năng thai diễn tiến.
Lý thuyết về mô hình
hồi quy logistic
Cho bài toán thống kê hiện thời, ta cần một phương tiện cho phép liên
kết giá trị của một biến độc lập (yếu tố tiên lượng) \(X\) và một xác suất \(Y = p \in [0,1]\). Công cụ đó là mô hình
logistic.
Mô hình hồi quy logistic có một lịch sử lâu đời (khoảng 78 năm),
trước cả sự ra đời của lý thuyết về mô hình tuyến tính tổng quát GLM.
Câu chuyện này khá dài, và sự khởi đầu của nó không liên quan gì đến xác
suất và thống kê. Chúng ta sẽ khởi hành xa hơn từ chỗ nhận ra trong thế
giới tự nhiên luôn hiện diện một quy luật tiến triển đặc biệt gồm 3 giai
đoạn: 1) Giai đoạn sớm với sự tăng trưởng lũy tiến, xấp xỉ hàm mũ
(exponential); 2) Tiếp theo là giai đoạn bão hòa: tốc độ phát triển chậm
lại, tuyến tính; 3) Cuối cùng là giai đoạn ổn định và trưởng thành: sự
phát triển ngừng lại. Khi biểu diễn tiến trình này theo thời gian, sẽ
tạo ra một đường cong hình chữ S (sigmoid curve).
Ta có thể quan sát thấy quy luật này ở mọi lĩnh vực: tăng trưởng dân
số/kinh tế, chu trình chuyển hóa sinh học, phản ứng hóa học. Trong Sản
Phụ khoa, ta có thể nhìn thấy nó trong diễn tiến các hormone sinh dục,
sự tăng trưởng của bào thai trong tử cung người mẹ, liên hệ liều / đáp
ứng trong dược lực học…
Từ thế kỉ 18-19, những nhà toán học đã khảo sát quy luật này và lập
ra các hàm toán học cho phép tái hiện đường cong hình chữ S, gọi là các
hàm sigmoid, thí dụ hàm hyperbolic tangent của Jean Saurry năm 1774.
Trong số các hàm sigmoid, ta có hàm logistic là nhân vật chính trong
câu chuyện này. Hàm logistic do nhà toán học người Pháp Pierre François
Verhulst thiết lập vào năm 1845, với công dụng nguyên thủy nhằm khảo sát
quy luật tăng trưởng dân số trong một quần thể. Công thức của hàm
logistic được trình bày như sau.
\[y = \frac{e^{x}}{1 + e^{x}} = \frac{1}{1
+ e^{-x}} = \frac{1}{2} + \frac{1}{2} tanh(\frac{x}{2})\]
Hình: đồ thị hàm logistic. Từ giá trị đầu vào là số thực \(x\) bất kì, hàm logistic xuất kết quả là
một giá trị trong khoảng (0,1).

Một cách tình cờ, đặc tính này của hàm logistic dẫn đến một ứng dụng
quan trọng trong lĩnh vực thống kê: nó giải quyết nhu cầu liên kết giá
trị một tập biến \(X\) và xác suất quan
sát được giá trị \(Y=1\) (Y là một biến
nhị giá).
Mô hình logistic cổ điển được định nghĩa trực tiếp dựa vào hàm
logistic, bằng cách thay đối số \(x\)
bằng một đại lượng \(g\) như sau:
\[Pr(Y=1|X) \sim logistic(X) = \frac{1}{1
+ e^{-g}}\]
Với \(g\) là một biểu thức (hàm)
tuyến tính được mô hình hóa theo tập biến \(X\)
\[g = \beta_0 + \beta_1X_1 + \beta_2X_2 +
... + \beta_jX_j\] Tuy nhiên, phiên bản thực dụng của mô hình hồi
quy logistic chỉ được định hình vào năm 1944, khi nhà thống kê Joseph
Berkson thiết lập một khái niệm quan trọng là Log odds và dùng nó làm
thang đo cho bài toán ước lượng biến nhị giá.
Như ta biết, Odds là tỉ số giữa 2 xác suất. Với \(p\) là xác suất thành công (\(Y=1\)) và \(1-p\) là xác suất thất bại (\(Y=0\)), ta có:
\[Odds = \frac{p}{1-p}\]
Từ đó, ta có hàm logit là một công cụ khác cho phép liên kết trực
tiếp tập biến \(X\) và giá trị xác suất
\(Y=p\). Hàm logit chính là sự áp dụng
hàm logarit tự nhiên cho Odds:
\[logit(p) =
log(\frac{p}{1-p})\]
Ta dễ dàng nhận thấy mối liên hệ nghịch đảo giữa 2 hàm logit và hàm
logistic cổ điển:

Từ đó, Berkson đã chuẩn hóa hồi quy logistic thành một phương pháp
thống kê quy ước, sử dụng hàm logit thay vì logistic, và dùng log(odds)
làm thang đo, đơn vị cho biến kết quả \(Y\) trong mô hình. Sau đó, David Cox (1958)
hoàn thiện kỹ thuật ước lượng tham số trong mô hình logistic.
Sau cùng, vào năm 1972 Nelder và Wedderburn đã hợp nhất mô hình
logistic vào hệ thống mô hình hồi quy tuyến tính tổng quát (GLM), mô
hình logistic là một thể đặc biệt của mô hình GLM, ước lượng giá trị của
\(\mu\) là trung bình của biến kết quả
\(Y\) theo quy luật phân phối Binomial
và 2 tham số \(BI(n,\mu)\)
\[Pr(Y=y|n,\mu) =
\frac{n!}{y!(n-y)!}\mu^{y}(1-p)^{n-y}\]
Ta ước lượng giá trị của \(\mu\)
bằng một mô hình tuyến tính với hàm liên kết logit:
\[logit(\mu) = log(\frac{\mu}{1-\mu}) \sim
\beta_0 + \beta_1X_1 + \beta_2X_2 + ... + \beta_jX_j \] Ta thấy,
định nghĩa mô hình hồi quy logistic theo lý thuyết GLM và hàm logit dễ
hiểu và đơn giản hơn nhiều so với định nghĩa nguyên thủy dựa vào hàm
logistic. Nhưng vì lý do lịch sử, ta vẫn dùng tên gọi “logistic
regression” cho loại mô hình này, nhưng ta hiểu bản chất của nó chỉ đơn
giản là một mô hình GLM với phân phối Binomial hoặc Bernoulli (trường
hợp đặc biệt khi \(n=1\))
Bước 2A: Mô hình hồi
quy Logistic cho biến kết quả nhị giá
Ta sẽ lần lượt phân tích 2 mô hình logistic khác nhau cho 2 biến kết
quả: 1) kết quả nhị giá (thành công hoặc thất bại tuyệt đối về thai diễn
tiến trong thí nghiệm, biến OP_bin) và 2) tỷ lệ thai diễn tiến trên tổng
số phôi chuyển (biến OP_rate).
Cho kết quả thứ nhất, mô hình áp dụng một trường hợp đặc biệt của
phân phối Binomial với \(n=1\), với đơn
vị quan sát là cá thể bệnh nhân. Mục tiêu của mô hình là ước lượng xác
suất quan sát được giá trị \(OP\_bin =
1\) cho mỗi cá thể.
Mô hình có công thức: OP_bin ~ Protocol*AFC + Thickness + Age; family
= “binomial” (hàm liên kết mặc định là logit).
Nội dung của mô hình như sau:
log_mod = glm(OP_bin ~ Protocol*AFC + Thickness + Age,
data = df,
family = "binomial")
summary(log_mod)
##
## Call:
## glm(formula = OP_bin ~ Protocol * AFC + Thickness + Age, family = "binomial",
## data = df)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -2.2355 -0.9405 0.5561 0.7987 1.6910
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 2.28220 1.61373 1.414 0.157292
## ProtocolPPOS 3.56952 1.02745 3.474 0.000512 ***
## AFC 0.14222 0.05030 2.828 0.004690 **
## Thickness 0.10929 0.07437 1.470 0.141679
## Age -0.14522 0.04414 -3.290 0.001001 **
## ProtocolPPOS:AFC -0.22953 0.07846 -2.925 0.003439 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 244.90 on 205 degrees of freedom
## Residual deviance: 215.36 on 200 degrees of freedom
## AIC: 227.36
##
## Number of Fisher Scoring iterations: 4
Diễn giải nội dung kết quả thô của mô hình:
Do sử dụng hàm liên kết là logit, giá trị ước lượng của mô hình hiện
thời là \(logit(\mu)\) hay \(log(\frac{\mu}{1-\mu})\) hay \(log(Odds)\), với \(\mu\) là xác suất đạt thai diễn tiến trung
bình (cho mổi cá thể). Tất cả hệ số hồi quy đang ở thang đo log(odds).
Ta có thể chuyển về thang đo xác suất bằng hàm plogis, hoặc về thang đo
Odds bằng hàm exponential.
\(Intercept = 2.28220\) tương ứng
với log(odd) của xác suất thai diển tiến ở phác đồ tham chiếu
(GnRH_ant), trong điều kiện giá trị Age, AFC và Thickness giữ cố định ở
mức trung bình của quần thể.
\(ProtocolPPOS = 3.56952\) tương ứng
với sự thay đổi log(odd) của xác suất thai diễn tiến ở phác đồ PPOS so
với nhóm đối chứng (GnRH_ant), trong điều kiện giá trị Age, AFC và
Thickness không đổi.
Các hệ số hối quy cho AFC,Age và Thickness lần lượt ứng với sự thay
đổi của log(odd) xác suất thai diễn tiến khi AFC, Age hoặc Thickness
tăng 1 đơn vị.
Vì mô hình có xét hiệu ứng tương tác giữa phác đồ PPOS và AFC, ta có
thêm hệ số hồi quy ProtocolPPOS:AFC; với ý nghĩa đo lường sự thay đổi
của log(odd) của xác suất thai diễn tiến khi AFC tăng 1 đơn vị và khi sử
dụng phác đồ PPOS.
Một cách đơn giản, ta có thể xét dấu của các hệ số hồi quy này để
hình dung về hiệu ứng mà các biến gây ra cho xác suất của thai diễn
tiến. Một hệ số hồi quy > 0 cho thấy mối tương quan thuận (làm tăng),
ngược lại một hệ số hồi quy <0 cho thấy tương quan nghịch (làm
giảm).
Pr(>|z|) trình bày giá trị p của kiểm định Wald, nhằm phủ nhận giả
thuyết vô hiệu là một biến không gây ra hiệu ứng nào cả (không có liên
hệ) đối với xac suất OP (hệ số hồi quy = 0).
Tuy nhiên, rất khó để thực hiện suy diễn thống kê theo cách này, nên
ta sẽ theo con đường ước tính marginal effects (hiệu ứng cận biên) cho
các yếu tố.
Giả định ta muốn khảo sát hiệu ứng của một biến định tính có 2 bậc
giá trị (phác đồ PPOS hoặc GnRH), mô hình sẽ ước lượng được 2 giá trị
xác suất thai diễn tiến trung bình cho 2 nhóm này là \(\mu_{PPOS}\) và \(\mu_{GnRH}\)
Từ đây, ta có thể ước tính 3 loại marginal effects gồm:
- Marginal risk difference (RD)
Trị số RD đo lường trực tiếp sự thay đổi/khác biệt/tương phản về xác
suất giữa PPOS và phác đồ tham chiếu
\[RD = \mu_{PPOS}
- \mu_{GnRHant}\] RD cho biết khi dùng phác đồ PPOS, xác suất
đạt thay diễn tiến sẽ thay đổi bao nhiêu so với phác đồ tham chiếu. Vì
bản chất của RD là hiệu số giữa 2 xác suất, nó chỉ có thể dao động trong
khoảng \([-1,1]\), RD = 0 cho thấy
không có khác biệt (tính tương đương), RD < 0 hoặc > 0 cho phép
xác định hiệu ứng của phác đồ nào cao hơn/thấp hơn.
rd = avg_comparisons(
log_mod,
variables = "Protocol")%>%
dplyr::select(-c(1,2,5,6))%>%
mutate(contrast = "RD")
rd %>% knitr::kable()
RD |
0.1485632 |
0.0095652 |
0.0361896 |
0.2609369 |
Kết quả cho thấy: theo ước tính trung bình, nhóm bệnh nhân dùng phác
đồ PPOS có xác suất thai diễn tiến tăng 0.148 (nói cách khác; tỷ lệ thai
diễn tiến tăng 14.8%) so với phác đồ GnRH_ant, sự gia tăng này có ý
nghĩa thống kê (khoảng tin cậy không chứa giá trị 0, p = 0.036).
- Marginal Odds ratio (OR)
Trong phần trên, ta đã hiểu về bản chất của Odds là một tỷ số giữa 2
xác suất thành công/thất bại. Odds ratio là một cách để đo lường sự
tương phản giữa 2 giá trị Odds tương ứng với 2 bậc giá trị của biến X (2
phác đồ), theo công thức sau:
\[OR = \frac{Odds_{PPOS}}{Odds_{GnRHa}} =
\frac{\mu_{PPOS}/(1-\mu_{PPOS})}{\mu_{GnRHa}/(1-\mu_{GnRHa})}\]
Vì là 1 tỷ số, OR có thể >1, và dao động từ 0 đến \(+\infty\). Giá trị OR < 1 cho thấy hiệu
ứng của phác đồ PPOS thấp hơn so với nhóm tham chiếu, ngược lại OR >
1 và càng lớn càng cho thấy phác đồ PPOS có hiệu quả cao hơn. OR = 1 cho
thấy 2 phác đồ có hiệu ứng tương đương nhau.
- Marginal risk ratio (RR)
Risk ở đây tương ứng với ý nghĩa xác suất, khả năng, tỷ lệ thành công
(giá trị \(\mu\) cho mỗi phác đồ), risk
ratio đơn giản là tỷ số giữa 2 risks.
\[RR = \frac{\mu_{PPOS}}{\mu_{GnRHa}}
\] RR được diễn giải tương tự như OR, giá trị RR=1 cho thấy 2
phác đồ là tương đương nhau, giá trị RR > 1 cho thấy phác đồ PPOS có
hiệu quả cao hơn, và ngược lại RR < 1 cho thấy phác đồ GnRha có hiệu
quả cao hơn.
Kết quả OR và RR được trình bày trong bảng sau:
or = avg_comparisons(
log_mod,
variables = "Protocol",
transform_pre = "lnoravg",
transform_post = "exp")%>%
dplyr::select(-c(1,2,8:10))%>%
mutate(contrast = "OR")
rr = avg_comparisons(
log_mod,
variables = "Protocol",
transform_pre = "lnratioavg",
transform_post = exp)%>%dplyr::select(-c(1,2,8:10))%>%
mutate(contrast = "RR")
rbind(or,rr) %>% knitr::kable()
OR |
2.143148 |
0.0124863 |
1.178458 |
3.897536 |
RR |
1.227801 |
0.0112964 |
1.047548 |
1.439071 |
Theo kết quả này, cả giá trị OR và RR đều cho thấy một hiệu quả ưu
thế hơn của phác đồ PPOS so với GnRHa đối với khả năng đạt được thai
diễn tiến. Sự chênh lệch về Odds và xác suất thành công giữa 2 phác đồ
là có ý nghĩa thống kê.
Ta cũng có thể tính RD, OR và RR cho các biến định lượng, lúc này 2
bậc so sánh là \(X-1\) và \(X+1\), kết quả cho biết hiệu ứng khi X gia
tăng 1 đơn vị. Bảng sau đây trình bày giá trị RD, OR và RR cho Age, AFC,
Thickness và cho riêng mỗi nhóm phác đồ.
rd = avg_comparisons(
log_mod,
variables = list(Age = 1,
AFC = 1,
Thickness = 1),
by = "Protocol")%>%
dplyr::select(-c(1,7,11:13))%>%
mutate(contrast = "RD")
rd %>% knitr::kable()
AFC |
RD |
GnRHa |
0.0274809 |
0.0083964 |
0.0010643 |
0.0110244 |
0.0439375 |
AFC |
RD |
PPOS |
-0.0132260 |
0.0089145 |
0.1378990 |
-0.0306981 |
0.0042460 |
Age |
RD |
GnRHa |
-0.0280614 |
0.0076484 |
0.0002435 |
-0.0430519 |
-0.0130709 |
Age |
RD |
PPOS |
-0.0219968 |
0.0067738 |
0.0011649 |
-0.0352732 |
-0.0087204 |
Thickness |
RD |
GnRHa |
0.0211200 |
0.0141114 |
0.1344810 |
-0.0065378 |
0.0487777 |
Thickness |
RD |
PPOS |
0.0165540 |
0.0113106 |
0.1433070 |
-0.0056143 |
0.0387223 |
or = avg_comparisons(
log_mod,
variables = list(Age = 1,
AFC = 1,
Thickness = 1),
by = "Protocol",
transform_pre = "lnoravg",
transform_post = "exp")%>%
dplyr::select(-c(1))%>%
mutate(contrast = "OR")
rr = avg_comparisons(
log_mod,
variables = list(Age = 1,
AFC = 1,
Thickness = 1),
by = "Protocol",
transform_pre = "lnratioavg",
transform_post = exp)%>%
dplyr::select(-c(1,9:11))%>%
mutate(contrast = "RR")
rbind(or,rr) %>% knitr::kable()
AFC |
OR |
GnRHa |
1.1275251 |
0.0009388 |
1.0501331 |
1.2106207 |
AFC |
OR |
PPOS |
0.9212316 |
0.1300049 |
0.8284087 |
1.0244553 |
Age |
OR |
GnRHa |
0.8846513 |
0.0001927 |
0.8294515 |
0.9435247 |
Age |
OR |
PPOS |
0.8724480 |
0.0002967 |
0.8102853 |
0.9393797 |
Thickness |
OR |
GnRHa |
1.0966212 |
0.1337642 |
0.9720682 |
1.2371335 |
Thickness |
OR |
PPOS |
1.1081457 |
0.1354727 |
0.9683808 |
1.2680828 |
AFC |
RR |
GnRHa |
1.0435504 |
0.0019386 |
1.0157958 |
1.0720634 |
AFC |
RR |
PPOS |
0.9835603 |
0.1445533 |
0.9619010 |
1.0057073 |
Age |
RR |
GnRHa |
0.9574040 |
0.0005782 |
0.9339622 |
0.9814341 |
Age |
RR |
PPOS |
0.9728020 |
0.0025959 |
0.9555020 |
0.9904153 |
Thickness |
RR |
GnRHa |
1.0332998 |
0.1391176 |
0.9894065 |
1.0791403 |
Thickness |
RR |
PPOS |
1.0209655 |
0.1501173 |
0.9925187 |
1.0502275 |
Theo kết quả này, ta thấy AFC có tương quan thuận (OR > 1 và RR
> 1) với xác suất thai diễn tiến, nhưng chỉ có ý nghĩa trong nhóm
phác đồ GnRHa; Age có tương quan nghịch ý nghĩa với khả năng đạt thai
diễn tiến cho cả 2 phác đồ (OR < 1 và RR < 1), trong khi không có
liên hệ ý nghĩa nào giữa Thickness và khả năng đạt thai diễn tiến.
Thực ra, những trị số mà ta vừa ước lượng bao gồm RD, OR hoặc RR chỉ
có ý nghĩa tóm tắt (abstraction) và cho biết thông tin về hiệu ứng ở mức
độ quần thể. Hiện nay, có một số tác giả khuyến cáo về nhược điểm của
việc chỉ báo cáo hiệu ứng cho biến nhị phân bằng một trị số duy nhất, và
lợi ích của việc cung cấp thông tin chi tiết hơn về toàn thể đặc tính
phân phối của hiệu ứng trong mẫu khảo sát.
Biểu đồ sau đây cho phép đối chiếu phân phối toàn thể của xác suất
đạt thai diễn tiến cộng dồn trong 107 cá thể dùng phác đồ GnRHa và 99 cá
thể dùng phác đồ PPOS.
effs = comparisons(log_mod,
variables = "Protocol",
newdata = datagrid(grid_type = 'counterfactual'))
effs %>% ggplot() +
geom_density(aes(x = predicted, fill = Protocol), alpha = 0.5) +
geom_vline(xintercept = mean(effs$predicted_lo), color = "blue",
linetype = 2, size = 1) +
geom_vline(xintercept = mean(effs$predicted_hi), color = "red",
linetype = 2, size = 1) +
labs(x = "Probability of OP",
title = "Unit level contrast",
fill = "Protocol")+
scale_x_continuous(limits = c(0,1), breaks = seq(0,1,0.1))+
scale_fill_manual(values = pals)+
theme_bw(10)
Chú thích: Hình trên trình bày 2 biểu đồ mật độ phân phối cho phép so
sánh đặc điễm phân phối của xác suất thai diễn tiến (Trục X) giữa 2 phác
đồ: GnRHa (màu xanh) và PPOS (màu hồng). 2 đường thẳng không liên tục
tương ứng với giá trị trung vị của xác suất này ở mỗi nhóm.
Hình ảnh cho thấy có sự tương phản rõ nét giữa 2 phác đồ, với ưu thế
nghiêng về phác đồ PPOS.
Một biểu đồ khác cho phép hình dung về cán cân chênh lệch của hiệu
quả giữa 2 phác đồ, đến cấp độ từng cá thể.
effs %>% ggplot(aes(x=predicted_lo, y=predicted_hi))+
geom_abline(slope = 1, intercept = 0, linetype = 2) +
geom_point(aes(x=predicted_lo, y=predicted_hi,
col = predicted_hi))+
coord_fixed() +
scale_x_continuous(limits = c(0,1))+
scale_y_continuous(limits = c(0,1))+
scale_color_viridis_c('OP prob')+
labs(x = "Probability of OP by GnRH_ant", y = "Probability of OP by PPOS")+
theme_bw()
Chú thích: Đây là một biểu đồ tán xạ cho phép kiểm tra mức độ tương phản
/ chênh lệch giữa 2 phác đồ về xác suất thai diễn tiến. Trục X và Y
trình bày 2 thang đo xác suất từ 0-1 cho mỗi phác đồ. Mỗi chấm tròn biểu
thị cho một đơn vị khảo sát (cá thể bệnh nhân), đường phân giác của biểu
đồ biểu thị cho giả thuyết là hai phác đồ tương đương hoàn toàn với
nhau. Những điểm tròn nằm bên dưới đường phân giác này có hiệu quả
GnRH_ant ưu thế hơn, trái lại với những điểm nằm bên trên đường này,
phác đồ PPOS có hiệu ứng ưu thế hơn. Những điểm nằm rất gần và dọc theo
đường này có hiệu quả tương đương giữa 2 phác đồ.
Các biểu đồ tiếp theo trình bày về mối liên hệ giữa Tuổi, AFC và
Thickness với xác suất thai diễn tiến, riêng cho mỗi nhóm phác đồ:
preds = predictions(model = log_mod,
newdata = datagrid(Age = seq(20,40,5),
Protocol = c("GnRHa","PPOS"),
grid_type = "counterfactual"))
preds%>%ggplot(aes(x = Age,
y = estimate)) +
stat_halfeye(alpha = 0.5,
.width = c(0.75, 0.95),
point_interval = 'median_qi',
show.legend = F)+
stat_lineribbon(aes(y = estimate, fill = Protocol),
.width = c(.95, .75, .50),
alpha = 1/5,
show.legend = F) +
labs(y="OP probability", x = "Age") +
scale_x_continuous(limits = c(20,45), breaks = seq(20,40,5))+
scale_y_continuous(limits = c(0,1))+
facet_wrap(~Protocol, ncol = 2)+
theme_bw(10)+
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
theme(axis.text = element_text(size = 10, color = "black"),
axis.title = element_text(size = 10, color = "black"))

preds = predictions(model = log_mod,
newdata = datagrid(AFC = seq(1,30,5),
Protocol = c("GnRHa","PPOS"),
grid_type = "counterfactual"))
preds%>%ggplot(aes(x = AFC,
y = estimate)) +
stat_halfeye(alpha = 0.5,
.width = c(0.75, 0.95),
point_interval = 'median_qi',
show.legend = F)+
stat_lineribbon(aes(y = estimate, fill = Protocol),
.width = c(.95, .75, .50),
alpha = 1/5,
show.legend = F) +
labs(y="OP probability", x = "AFC") +
scale_x_continuous(limits = c(0,31), breaks = seq(0,30,5))+
scale_y_continuous(limits = c(0,1))+
facet_wrap(~Protocol, ncol = 2)+
theme_bw(10)+
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
theme(axis.text = element_text(size = 10, color = "black"),
axis.title = element_text(size = 10, color = "black"))

preds = predictions(model = log_mod,
newdata = datagrid(Thickness = seq(8,20,4),
Protocol = c("GnRHa","PPOS"),
grid_type = "counterfactual"))
preds%>%ggplot(aes(x = Thickness,
y = estimate)) +
stat_halfeye(alpha = 0.5,
.width = c(0.75, 0.95),
point_interval = 'median_qi',
show.legend = F)+
stat_lineribbon(aes(y = estimate, fill = Protocol),
.width = c(.95, .75, .50),
alpha = 1/5,
show.legend = F) +
labs(y="OP probability", x = "Endometrial thickness") +
scale_x_continuous(limits = c(7,22), breaks =seq(8,20,4))+
scale_y_continuous(limits = c(0,1))+
facet_wrap(~Protocol, ncol = 2)+
theme_bw(10)+
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
theme(axis.text = element_text(size = 10, color = "black"),
axis.title = element_text(size = 10, color = "black"))

Bước 2B: Mô hình hồi
quy Binomial cho tỷ lệ OP/tổng số phôi
Trong phần tiếp theo, ta sẽ phân tích loại kết quả thứ hai: tỷ lệ
thai diễn tiến trên tổng số phôi đã chuyển (biến OP_cum).
Mô hình được dựng bằng thư viện gamlss với cú pháp giống như mô hình
GLM Binomial trong chương trước. Công thức của mô hình như sau:
“cbind(OP_cum, n_ET-OP_cum) ~ Protocol * AFC + Thickness + Age” (Nhắc
lại: mô hình GLM Binomial tổng quát cần 2 biến ở vị trí kết quả: số kết
quả thành công là biến OP_cum, và số kết quả thất bại, là hiệu số giữa
số phôi chuyển và số thai)
tùy chỉnh family = BI(mu.link = “logit”) tương ứng với phân phối
Binomial với hàm liên kết logit cho tham số \(\mu\)
Nội dung của mô hình này như sau:
bi_mod = gamlss(cbind(OP_cum, n_ET-OP_cum) ~
Protocol * AFC + Thickness + Age,
data = df,
family = BI(mu.link = "logit"))
## GAMLSS-RS iteration 1: Global Deviance = 462.3237
## GAMLSS-RS iteration 2: Global Deviance = 462.3237
summary(bi_mod)
## ******************************************************************
## Family: c("BI", "Binomial")
##
## Call: gamlss(formula = cbind(OP_cum, n_ET - OP_cum) ~ Protocol *
## AFC + Thickness + Age, family = BI(mu.link = "logit"), data = df)
##
## Fitting method: RS()
##
## ------------------------------------------------------------------
## Mu link function: logit
## Mu Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.16961 0.90175 0.188 0.8510
## ProtocolPPOS 1.39994 0.54026 2.591 0.0103 *
## AFC 0.02922 0.02724 1.073 0.2846
## Thickness 0.04225 0.03605 1.172 0.2426
## Age -0.05824 0.02403 -2.423 0.0163 *
## ProtocolPPOS:AFC -0.08438 0.04027 -2.096 0.0374 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## ------------------------------------------------------------------
## No. of observations in the fit: 206
## Degrees of Freedom for the fit: 6
## Residual Deg. of Freedom: 200
## at cycle: 2
##
## Global Deviance: 462.3237
## AIC: 474.3237
## SBC: 494.2909
## ******************************************************************
Cách thức diễn giải mô hình này hoàn toàn giống như mô hình logistic
ở trên nên ta không cần nhắc lại ở đây. Ta sẽ đi thẳng đến công đoạn ước
tính 3 trị số marginal effects cho phác đồ PPOS từ mô hình này:
dr = avg_comparisons(
bi_mod,
what = "mu",
variables = "Protocol")%>%
dplyr::select(-c(1,2,5,6))%>%
mutate(contrast = "DR")
or = avg_comparisons(
bi_mod,
what = "mu",
variables = "Protocol",
transform_pre = "lnoravg",
transform_post = "exp")%>%
dplyr::select(-c(1,2,8:10))%>%
mutate(contrast = "OR")
rr = avg_comparisons(
bi_mod,
what = "mu",
variables = "Protocol",
transform_pre = "lnratioavg",
transform_post = exp)%>%dplyr::select(-c(1,2,8:10))%>%
mutate(contrast = "RR")
rbind(dr, or,rr) %>% knitr::kable()
DR |
0.0837135 |
0.0434577 |
0.0024592 |
0.1649678 |
OR |
1.4432859 |
0.0442570 |
1.0094717 |
2.0635289 |
RR |
1.2673994 |
0.0446990 |
1.0056242 |
1.5973175 |
Theo kết quả này, có liên hệ ý nghĩa giữa phác đồ PPOS và sự gia tăng
của tỷ lệ thai diễn tiến cộng dồn. Cụ thể nhóm phác đồ PPOS có tỷ lệ
thai diễn tiến cao hơn trung bình 8.37% (DR = 0.0837, KTC95%: 0.002 -
0.165, p=0.04). Tỷ số Odds (OR) và tỷ số nguy cơ (RR) lần lượt là 1.44
và 1.27 đều cao hơn 1 cho thấy hiệu quả ưu thế hơn của phác đồ PPOS, cả
hai đều có ý nghĩa thống kê.
Ta thực hiện mô tả phân phối toàn thể của hiệu ứng này qua hai biểu
đồ sau:
effs = comparisons(bi_mod,
what = "mu",
variables = "Protocol",
newdata = datagrid(grid_type = 'counterfactual'))
effs %>% ggplot() +
geom_density(aes(x = predicted, fill = Protocol), alpha = 0.5) +
geom_vline(xintercept = mean(effs$predicted_lo), color = "blue",
linetype = 2, size = 1) +
geom_vline(xintercept = mean(effs$predicted_hi), color = "red",
linetype = 2, size = 1) +
labs(x = "Probability of OP",
title = "Unit level contrast",
fill = "protocol")+
scale_x_continuous(limits = c(0,1), breaks = seq(0,1,0.1))+
scale_fill_manual(values = pals)+
theme_bw(10)
Hình ảnh này cho thấy mặc dù phần trùng lặp giữa phân phối của xác suất
thai diễn tiến ở 2 phác đồ là khá cao, vẫn có một bộ phận cá thể cho
thấy hiệu quả ưu thế hơn của phác đồ PPOS, và giá trị trung vị của 2
phân phối cách nhau một khoảng gần bằng 0.1.
Tương tự, trên biểu đồ tương hợp về xác suất thai diễn tiến ở 2 phác
đồ, phần lớn cá thể nằm ở vị trí phía trên đường phân giác, cho thấy sự
chênh lệch về ưu thế nghiêng về phía phác đồ PPOS.
effs %>% ggplot(aes(x=predicted_lo, y=predicted_hi))+
geom_abline(slope = 1, intercept = 0, linetype = 2) +
geom_point(aes(x=predicted_lo, y=predicted_hi,
col = predicted_hi))+
coord_fixed() +
scale_x_continuous(limits = c(0,1))+
scale_y_continuous(limits = c(0,1))+
scale_color_viridis_c('OP prob')+
labs(x = "Probability of OP by GnRH_ant", y = "Probability of OP by PPOS")+
theme_bw()
Cuối cùng, ta cũng khảo sát về liên hệ giữa Tuổi, AFC và Thickness với
tỷ lệ thai diễn tiến cộng dồn tùy theo phác đồ.
preds = predictions(model = bi_mod,
what = "mu",
newdata = datagrid(Age = seq(20,40,5),
Protocol = c("GnRHa","PPOS"),
grid_type = "counterfactual"))
preds%>%ggplot(aes(x = Age,
y = estimate)) +
stat_halfeye(alpha = 0.5,
.width = c(0.75, 0.95),
point_interval = 'median_qi',
show.legend = F)+
stat_lineribbon(aes(y = estimate, fill = Protocol),
.width = c(.95, .75, .50),
alpha = 1/5,
show.legend = F) +
labs(y="OP probability", x = "Age") +
scale_x_continuous(limits = c(20,45), breaks = seq(20,40,5))+
scale_y_continuous(limits = c(0,1))+
facet_wrap(~Protocol, ncol = 2)+
theme_bw(10)+
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
theme(axis.text = element_text(size = 10, color = "black"),
axis.title = element_text(size = 10, color = "black"))

preds = predictions(model = bi_mod,
what = "mu",
newdata = datagrid(AFC = seq(1,30,5),
Protocol = c("GnRHa","PPOS"),
grid_type = "counterfactual"))
preds%>%ggplot(aes(x = AFC,
y = estimate)) +
stat_halfeye(alpha = 0.5,
.width = c(0.75, 0.95),
point_interval = 'median_qi',
show.legend = F)+
stat_lineribbon(aes(y = estimate, fill = Protocol),
.width = c(.95, .75, .50),
alpha = 1/5,
show.legend = F) +
labs(y="OP probability", x = "AFC") +
scale_x_continuous(limits = c(0,31), breaks = seq(0,30,5))+
scale_y_continuous(limits = c(0,1))+
facet_wrap(~Protocol, ncol = 2)+
theme_bw(10)+
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
theme(axis.text = element_text(size = 10, color = "black"),
axis.title = element_text(size = 10, color = "black"))

preds = predictions(model = bi_mod,
what = "mu",
newdata = datagrid(Thickness = seq(8,20,4),
Protocol = c("GnRHa","PPOS"),
grid_type = "counterfactual"))
preds%>%ggplot(aes(x = Thickness,
y = estimate)) +
stat_halfeye(alpha = 0.5,
.width = c(0.75, 0.95),
point_interval = 'median_qi',
show.legend = F)+
stat_lineribbon(aes(y = estimate, fill = Protocol),
.width = c(.95, .75, .50),
alpha = 1/5,
show.legend = F) +
labs(y="OP probabilitys", x = "Endometrial thickness") +
scale_x_continuous(limits = c(7,22), breaks =seq(8,20,4))+
scale_y_continuous(limits = c(0,1))+
facet_wrap(~Protocol, ncol = 2)+
theme_bw(10)+
theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust=1)) +
theme(axis.text = element_text(size = 10, color = "black"),
axis.title = element_text(size = 10, color = "black"))

Diễn giải kết quả của
phân tích
Phân tích dữ liệu này cho phép rút ra một số kết luận như sau:
Khả năng đạt được thai diễn tiến có thể được khảo sát dưới nhiều
hình thức: xác suất quan sát được một kết quả thành công (biến nhị giá
0,1) trên cá thể bệnh nhân, xác suất thành công cho mỗi đơn vị noãn -
hay tỷ lệ thành công trên tổng số phôi được chuyền. Cách thức khảo sát
có thể ảnh hưởng đến kết quả phân tích thống kê (trong trường hợp hiện
thời, cả 2 cách khảo sát đều cho ra thông điệp tương đồng, tuy nhiên có
sự khác biệt về giá trị OR, RR hoặc RD).
Dù khảo sát dưới hình thức nào, thì đều dẫn về công cụ chung là
mô hình GLM với phân phối Binomial với 2 tham số \(n\),\(\mu\). Mô hình logistic cổ điển là trường
hợp đặc biệt khi \(n=1\). Cách diễn
giải và suy luận thống kê là như nhau cho cả 2 mô hình.
Mô hình logistic (hay GLM Binomial) cho phép suy luận thống kê về
mối liên hệ giữa 1 biến độc lập và một kết quả xác suất. Ta có thể áp
dụng mô hình này cho những kết cục lâm sàng nhị phân, hoặc tỷ
lệ.
LS0tDQp0aXRsZTogIkto4bqjbyBzw6F0IGvhur90IGPhu6VjIG5o4buLIHBow6JuOiBI4buTaSBxdXkgbG9naXN0aWMiDQphdXRob3I6ICJCUy4gTmfhu41jIENow6J1LCBCUy4gS2jhuqMgTmhpIg0KZGF0ZTogIjA2IFRow6FuZyAzIG7Eg20gMjAyMyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRoZW1lOiBkZWZhdWx0DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGRldjogc3ZnDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIGxhdGV4X2VuZ2luZTogbHVhbGF0ZXgNCiAgICBrZWVwX3RleDogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGKQ0KYGBgDQoNCiMgR2nhu5tpIHRoaeG7h3UNCg0K4bueIGNoxrDGoW5nIG7DoHksIGNow7puZyB0YSBz4bq9IGto4bqjbyBzw6F0IHRow6BuaCBxdeG6oyDEkcaw4bujYyBxdWFuIHTDom0gbmjhuqV0IHRyb25nIG5naGnDqm4gY+G7qXUgduG7gSBo4buXIHRy4bujIHNpbmggc+G6o24sIMSRw7MgbMOgIHPhu7EgdGjhu6UgdGhhaSAodGhhaSBzaW5oIGjDs2EsIGzDom0gc8OgbmcpLCBz4buxIHRp4bq/cCBkaeG7hW4gdGjDoG5oIGPDtG5nIGPhu6dhIHRoYWkga8OsICh0aGFpIGRp4buFbiB0aeG6v24pIHbDoCBz4buxIHNpbmggbuG7ny4gVHJvbmcgeSB2xINuLCBuaOG7r25nIGvhur90IGPhu6VjIG7DoHkgdGjGsOG7nW5nIMSRxrDhu6NjIGto4bqjbyBzw6F0IG5oxrAgbeG7mXQgZ2nDoSB0cuG7iyBtYW5nIHTDrW5oIG5o4buLIHBow6JuIChDw7MgaG/hurdjIGtow7RuZyksIGhv4bq3YyB04bu3IGzhu4cgdGjDoG5oIGPDtG5nIHRyw6puIHThu5VuZyBz4buRIGPDoSB0aOG7gyBi4buHbmggbmjDom4uIFR1eSBuaGnDqm4sIGLhuqNuIGNo4bqldCBj4bunYSBsb+G6oWkga+G6v3QgY+G7pWMgbsOgeSBjw7MgdGjhu4MgxJHGsOG7o2MgbmjDrG4gbmjhuq1uIG5oxrAgbeG7mXQgeMOhYyBzdeG6pXQgaGF5IGto4bqjIG7Eg25nIHRow6BuaCBjw7RuZyB2w6AgY8WpbmcgY8OzIHTDrW5oIGvhur8gdGjhu6thIG5oxrAgbeG7mXQgcGjhuqduIHRyb25nIGNodeG7l2kga+G6v3QgcXXhuqMgY+G7p2EgdGnhur9uIHRyw6xuaCB0aOG7pSB0aW5oIG5ow6JuIHThuqFvLiBWw6wgduG6rXksIHRhIGPDsyB0aOG7gyDDoXAgZOG7pW5nIHF1eSBsdeG6rXQgcGjDom4gcGjhu5FpIG5o4buLIHRo4bupYyAoYmlub21pYWwpIMSR4buDIGto4bqjbyBzw6F0IGNow7puZy4NCg0KVGjDrSBk4bulLCBr4bq/dCBxdeG6oyB0aGFpIGRp4buFbiB0aeG6v24gdGjGsOG7nW5nIMSRxrDhu6NjIGdoaSBuaOG6rW4gYuG6sW5nIDIgZ2nDoSB0cuG7iyAwIChraMO0bmcpIGhv4bq3YyAxIChjw7MpIHRyb25nIGThu68gbGnhu4d1LCBuaMawbmcgYuG6o24gY2jhuqV0IGPhu6dhIHRoYWkgZGnhu4VuIHRp4bq/biBjw7MgdGjhu4MgeGVtIG5oxrAgeMOhYyBzdeG6pXQgdGjDoG5oIGPDtG5nICRwJCBj4bunYSAxIHRo4butIG5naGnhu4dtIGNodXnhu4NuIHBow7RpLiBDaMOtbmggdsOsIHRyw6puIHRo4buxYyB04bq/LCBz4buRIGzGsOG7o25nIHBow7RpIMSRxrDhu6NjIGNodXnhu4NuIHLhuqV0IHRo4bqlcCwgY2jhu4kgZ2nhu5tpIGjhuqFuIOG7nyAxIMSR4bq/biAyIHBow7RpIGNobyBt4buXaSBjaHUga8OsLCBuw6puIGvhur90IHF14bqjIHF1YW4gc8OhdCDEkcaw4bujYyBt4bubaSBiaeG7g3UgaGnhu4duIHRow6BuaCBnacOhIHRy4buLIDAgaG/hurdjIDEuDQoNClRyb25nIGNoxrDGoW5nIG7DoHksIHRhIHPhur0gdMOsbSBoaeG7g3UgduG7gSBwaMOibiB0w61jaCBo4buTaSBxdXkgbG9naXN0aWMgdsOgIHRyxrDhu51uZyBo4bujcCB04buVbmcgcXXDoXQgY+G7p2EgbsOzIC0gbeG7mXQgbcO0IGjDrG5oIGjhu5NpIHF1eSBHTE0gduG7m2kgcGjDom4gcGjhu5FpIEJpbm9taWFsLCBjaG8gcGjDqXAgc3V5IGRp4buFbiB0aOG7kW5nIGvDqiBjaG8ga+G6v3QgcXXhuqMgbmjhu4sgcGjDom4gaG/hurdjIHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZyBj4bunYSB0aOG7rSBuZ2hp4buHbS4NCg0KVMOsbmggaHXhu5FuZyBtaW5oIGjhu41hIGzDoCBt4buZdCB0aOG7rSBuZ2hp4buHbSBsw6JtIHPDoG5nIHbhu5tpIG3hu6VjIHRpw6p1IHNvIHPDoW5oIGhp4buHdSBxdeG6oyBj4bunYSBwaMOhYyDEkeG7kyBQUE9TIHNvIHbhu5tpIHBow6FjIMSR4buTIHRoYW0gY2hp4bq/dSBsw6AgR25SSF9hbnQgxJHhu5FpIHbhu5tpIGto4bqjIG7Eg25nIMSR4bqhdCDEkcaw4bujYyB0aGFpIGRp4buFbiB0aeG6v24gKG9uZ29pbmcgcHJlZ25hbmN5KS4gVHJvbmcgdGjDrSBuZ2hp4buHbSBuw6B5LCBwaMOhYyDEkeG7kyBHblJIX2FudCDEkcaw4bujYyDDoXAgZOG7pW5nIGNobyBuaMOzbSDEkeG7kWkgY2jhu6luZyBn4buTbSAxMDcgcGjhu6UgbuG7ryBoaeG6v20gbXXhu5luLCB2w6AgcGjDoWMgxJHhu5MgUFBPUyDDoXAgZOG7pW5nIGNobyBuaMOzbSBjYW4gdGhp4buHcCBn4buTbSA5OSB0csaw4budbmcgaOG7o3AuIFNhdSBraGkgdGh1IGhv4bqhY2ggbm/Do24sIHRo4bulIHRpbmggdsOgIHRy4buvIHBow7RpLCBuZ8aw4budaSB0YSB0aOG7sWMgaGnhu4duIHThu6sgMSDEkeG6v24gMyBs4bqnbiBjaHV54buDbiBwaMO0aSwgbeG7l2kgbOG6p24gMS0yIHBow7RpIHbDoCBnaGkgbmjhuq1uIGvhur90IHF14bqjIHRoYWkgZGnhu4VuIHRp4bq/biBj4buZbmcgZOG7k24gKG7hur91IG3hu5l0IHRyxrDhu51uZyBo4bujcCBraMO0bmcgdGjDoG5oIGPDtG5nIOG7nyBs4bqnbiBjaHV54buDbiBwaMO0aSDEkeG6p3UgdGnDqm4sIHRhIHPhur0gbOG6t3AgbOG6oWkgcXV5IHRyw6xuaCBjaHV54buDbiBwaMO0aSBs4bqnbiAyLCBob+G6t2MgbOG6p24gMykuIFRo4butIG5naGnhu4dtIGvhur90IHRow7pjIOG7nyBs4bqnbiB0aOG7qSAzLiANCg0KS+G6v3QgY+G7pWMgc+G6vSDEkcaw4bujYyBraOG6o28gc8OhdCBkxrDhu5tpIDMgaMOsbmggdGjhu6ljOg0KDQoxKSBHacOhIHRy4buLIG5o4buLIHBow6JuOiB0aMOgbmggY8O0bmcgaGF5IHRo4bqldCBi4bqhaSB0dXnhu4d0IMSR4buRaSA6IGPDsyDEkeG6oXQgxJHGsOG7o2MgdGhhaSBkaeG7hW4gdGnhur9uIGhheSBraMO0bmcgKGNobyB04buRaSDEkWEgMyBs4bqnbik6IDAgPSBLaMO0bmcsIDEgPSBDw7MgKGLhuqV0IGvhu4Mgc29uZyB0aGFpLCDEkcahbiB0aGFpKQ0KDQoyKSBU4bqnbiBzdeG6pXQ6IHPhu5EgbMaw4bujbmcgdGhhaSBkaeG7hW4gdGnhur9uIGNobyBt4buXaSBjw6EgdGjhu4MgKGdpw6EgdHLhu4sgPSAwIChraMO0bmcgxJHhuqF0IMSRxrDhu6NjKSwgMSA9IMSRxqFuIHRoYWkgZGnhu4VuIHRp4bq/biwgMiA9IHNvbmcgdGhhaSBkaeG7hW4gdGnhur9uKS4NCg0KMykgVOG7tyBs4buHIMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v24gPSBz4buRIHRoYWkgZGnhu4VuIHRp4bq/biBjaGlhIGNobyB04buVbmcgc+G7kSBwaMO0aSDEkcaw4bujYyBjaHV54buDbi4gVGjDrSBk4bulOiBM4bqnbiAxIGNodXnhu4NuIDIgcGjDtGksIGvhur90IHF14bqjIGtow7RuZyDEkeG6oXQsIGzhuqduIDIgY2h1eeG7g24gMiBwaMO0aSB2w6AgxJHhuqF0IMSRxqFuIHRoYWksIHRow6wgdOG7tyBs4buHIHRow6BuaCBjw7RuZyA9ICQxLygyKzIpID0gMC4yNSQNCg0KTMawdSDDvSBy4bqxbmcgY8OhYyB0csaw4budbmcgaOG7o3A6IHPhuqt5IHRoYWksIHRoYWkgbmdvw6BpIHThu60gY3VuZy4uLiB4ZW0gbmjGsCB0aOG6pXQgYuG6oWkuDQoNCiMgS+G6vyBob+G6oWNoIHBow6JuIHTDrWNoDQoNCljDoWMgc3XhuqV0IMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v24gY+G7mW5nIGThu5NuIGtoaSDDoXAgZOG7pW5nIHBow6FjIMSR4buTIFBQT1MsIHNvIHbhu5tpIHBoxrDGoW5nIHBow6FwIHRoYW0gY2hp4bq/dSBsw6AgR25SSF9hbnQgc+G6vSDEkcaw4bujYyDGsOG7m2MgbMaw4bujbmcgYuG6sW5nIG1hcmdpbmFsIE9kZHMtcmF0aW8gKE9SKSB2w6Agcmlzay1yYXRpbyAoUlIpLCBjw7MgaGnhu4d1IGNo4buJbmggY2hvIFR14buVaSwgQUZDIHbDoCDEkeG7mSBkw6B5IG7hu5lpIG3huqFjIHRydW5nIGLDrG5oIG5nw6B5IGNodXnhu4NuIHBow7RpLCBk4buxYSB2w6BvIG3hu5l0IG3DtCBow6xuaCBo4buTaSBxdXkgbG9naXN0aWMuIFN1eSBkaeG7hW4gdGjhu5FuZyBrw6ogZOG7sWEgdsOgbyBwaOG7pyBuaOG6rW4gZ2nhuqMgdGh1eeG6v3QgdsO0IGhp4buHdSAoT1IgdsOgIFJSID0gMSkg4bufIG5nxrDhu6FuZyDDvSBuZ2jEqWEgcCA9IDAuMDUuDQoNCiMgQ8O0bmcgY+G7pSBj4bqnbiB0aGnhur90IGNobyBxdXkgdHLDrG5oDQoNCisgVGjGsCB2aeG7h24gZHBseXIgdHJvbmcgaOG7hyBzaW5oIHRow6FpIHRpZHl2ZXJzZSDEkeG7gyB0aGFvIHTDoWMgZOG7ryBsaeG7h3UgdsOgIHRo4buRbmcga8OqIG3DtCB04bqjDQoNCisgVGjGsCB2aeG7h24gZ2dwbG90MiwgZ2dyaWRlcywgdGlkeWJheWVzIHbDoCBnZ2Rpc3QgxJHhu4MgduG6vSBt4buZdCBz4buRIGJp4buDdSDEkeG7kyB0aOG7kW5nIGvDqjsNCg0KKyBUaMawIHZp4buHbiBwYXRjaHdvcmsgxJHhu4MgZ2jDqXAgbmhp4buBdSBiaeG7g3UgxJHhu5MgZ2dwbG90MiB24bubaSBuaGF1Lg0KDQorIFRoxrAgdmnhu4duIGdhbWxzcyDEkeG7gyBk4buxbmcgbcO0IGjDrG5oIEdMTSB24bubaSBwaMOibiBwaOG7kWkgQmlub21pYWwNCg0KKyBUaMawIHZp4buHbiBtYXJnaW5hbGVmZmVjdHMgxJHhu4MgxrDhu5tjIHTDrW5oIE9SLCBSUiB2w6Agc3V5IGRp4buFbiB0aOG7kW5nIGvDqiB04burIGvhur90IHF14bqjIG3DtCBow6xuaC4NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZ2dyaWRnZXMpDQoNCmxpYnJhcnkoZ2FtbHNzKQ0KbGlicmFyeShtYXJnaW5hbGVmZmVjdHMpDQoNCmxpYnJhcnkodGlkeWJheWVzKQ0KbGlicmFyeShnZ2Rpc3QpDQpsaWJyYXJ5KHBhdGNod29yaykNCmBgYA0KDQrEkOG6p3UgdGnDqm4sIHRhIHThuqNpIGThu68gbGnhu4d1IHThu6sgZmlsZSAnUFBPU19PUC5jc3YnIHbDoG8gZGF0YWZyYW1lIGRmLCBzYXUgxJHDsyB0YSANCg0KYGBge3J9DQpkZiA9IHJlYWQuY3N2KCdQUE9TX09QLmNzdicsIHNlcCA9ICc7JywgDQogICAgICAgICAgICAgIGRlYyA9ICcsJywgDQogICAgICAgICAgICAgIGZpbGVFbmNvZGluZyA9ICdVVEYtOC1CT00nKSU+JQ0KICBuYS5vbWl0KCkNCg0KZGYkUHJvdG9jb2wgPSBmYWN0b3IoZGYkUHJvdG9jb2wpDQoNCmRmJT4lZHBseXI6OnNhbXBsZV9mcmFjKDAuMyklPiVoZWFkKCklPiVrbml0cjo6a2FibGUoKQ0KYGBgDQoNClRyb25nIGThu68gbGnhu4d1IG7DoHk6DQoNCkFnZSA9IFR14buVaSBi4buHbmggbmjDom4sDQoNCkFGQyA9IEThu7EgdHLhu68gYnXhu5NuZyB0cuG7qW5nIGPGoSBi4bqjbjsNCg0KVGhpY2tuZXNzID0gxJHhu5kgZMOgeSBu4buZaSBt4bqhYyB04butIGN1bmc7IA0KDQpuX0VUOiB04buVbmcgc+G7kSBwaMO0aSDEkcOjIGNodXnhu4NuIHRyb25nIHRp4bq/biB0csOsbmggbmdoacOqbiBj4bupdTsNCg0KT1BfY3VtID0gdOG6p24gc3XhuqV0IHRoYWkgZGnhu4VuIHRp4bq/biBj4buZbmcgZOG7k24gKGdpw6EgdHLhu4sgY2FvIG5o4bqldCA9IDIsIHRo4bqlcCBuaOG6pXQgPSAwKTsNCg0KT1BfYmluID0ga+G6v3QgcXXhuqMgdGjDoG5oIGPDtG5nL3Ro4bqldCBi4bqhaSB0dXnhu4d0IMSR4buRaSAoMiBnacOhIHRy4buLIDAsMSkNCg0KT1BfcmF0ZSA9IHThu7cgbOG7hyB0aGFpIGRp4buFbiB0aeG6v24gPSBPUF9jdW0gLyBuX0VUDQoNCiMgQsaw4bubYyAxOiBQaMOibiB0w61jaCBtw7QgdOG6ow0KDQpUYSBr4bq/dCBo4bujcCBow6BtIGdyb3VwX2J5IHbDoCBzdW1tYXJpemUgY+G7p2EgdGjGsCB2aeG7h24gZHBseXIgxJHhu4MgdGjhu7FjIGhp4buHbiB0aOG7kW5nIGvDqiBtw7QgdOG6oyBjaG8gbmjhu69uZyBow6xuaCB0aOG7qWMga2jDoWMgbmhhdSBj4bunYSBr4bq/dCBj4bulYyB0aGFpIGRp4buFbiB0aeG6v24gY+G7mW5nIGThu5NuOg0KDQphKSBLaOG6o28gc8OhdCB04bqnbiBzdeG6pXQgdGhhaSBkaeG7hW4gdGnhur9uIChiaeG6v24gT1BfY3VtKQ0KDQrEkMOieSBsw6AgbeG7mXQgYmnhur9uIHPhu5EgcuG7nWkgcuG6oWMgdsOgIGNo4buJIGPDsyB0aOG7gyBjw7MgMyBnacOhIHRy4buLOiAwLCAxIGhv4bq3YyAyLiBL4bq/dCBxdeG6oyBtw7QgdOG6oyBuaMawIHNhdToNCg0KYGBge3J9DQpnZXRtb2RlIDwtIGZ1bmN0aW9uKHYpIHsNCiAgIHVuaXF2IDwtIHVuaXF1ZSh2KQ0KICAgdW5pcXZbd2hpY2gubWF4KHRhYnVsYXRlKG1hdGNoKHYsIHVuaXF2KSkpXQ0KfQ0KDQpkZiU+JWdyb3VwX2J5KFByb3RvY29sKSU+JQ0KICBzdW1tYXJpemUobiA9IG4oKSwNCiAgICAgICAgICAgIFN1bSA9IHN1bShPUF9jdW0pLA0KICAgICAgICAgICAgbWVhbiA9IHNwcmludGYoIiUwLjJmIiwgbWVhbihPUF9jdW0pKSwNCiAgICAgICAgICAgIE1lZGlhbiA9IHNwcmludGYoIiUwLjJmIiwgbWVkaWFuKE9QX2N1bSkpLA0KICAgICAgICAgICAgTW9kZSA9IHNwcmludGYoIiUwLjJmIiwgZ2V0bW9kZShPUF9jdW0pKSwNCiAgICAgICAgICAgIFNEID0gc3ByaW50ZigiJTAuMmYiLCBzZChPUF9jdW0pKSwNCiAgICAgICAgICAgIHA1ID0gc3ByaW50ZigiJTAuMmYiLCBxdWFudGlsZShPUF9jdW0sIDAuMDUpKSwNCiAgICAgICAgICAgIHA5NSA9IHNwcmludGYoIiUwLjJmIiwgcXVhbnRpbGUoT1BfY3VtLCAwLjk1KSksDQogICAgICAgICAgICApJT4la25pdHI6OmthYmxlKCkNCmBgYA0KDQpUaGVvIGvhur90IHF14bqjIG7DoHksIG7hur91IHjDqXQgduG7gSBz4buRIGzGsOG7o25nIHR1eeG7h3QgxJHhu5FpLCB0aMOsIGTGsOG7nW5nIG5oxrAgZ2nhu69hIDIgcGjDoWMgxJHhu5MgUFBPUyB2w6AgR25SSCBraMO0bmcgY8OzIHPhu7Ega2jDoWMgYmnhu4d0IG7DoG8gY+G6ozogTW9kZSA9IDEgY2hvIHRo4bqleSBr4bq/dCBxdeG6oyB0aMaw4budbmcgZ+G6t3AgbmjhuqV0IGNobyBj4bqjIDIgcGjDoWMgxJHhu5MgbMOgIMSR4bqhdCDDrXQgbmjhuqV0IDEgdGhhaSBkaeG7hW4gdGnhur9uLiBYw6l0IGLDrG5oIHF1w6JuIHRow6wgbmjDs20gUFBPUyBjw7MgduG6uyDGsHUgdGjhur8gaMahbjogc+G7kSB0aGFpIGRp4buFbiB0aeG6v24gdHJ1bmcgYsOsbmggbMOgIDEuMDMgc28gduG7m2kgMC44MTsgY+G6oyAyIMSR4buBdSBjw7MgxJHhu5kgcGjDom4gdMOhbiBjYW8gdMawxqFuZyDEkcawxqFuZyAoU0Qga2hv4bqjbmcgMC43KS4NCg0KYikgTuG6v3UgeMOpdCB24buBIHThu7cgbOG7hyB0aGFpIGRp4buFbiB0aeG6v24gdHLDqm4gdOG7lW5nIHPhu5EgcGjDtGkgY2h1eeG7g246DQoNCmBgYHtyfQ0KZGYlPiVncm91cF9ieShQcm90b2NvbCklPiUNCiAgc3VtbWFyaXplKG4gPSBuKCksDQogICAgICAgICAgICBNZWFuID0gc3ByaW50ZigiJTAuM2YiLCBtZWFuKE9QX3JhdGUpKSwNCiAgICAgICAgICAgIE1lZGlhbiA9IHNwcmludGYoIiUwLjNmIiwgbWVkaWFuKE9QX3JhdGUpKSwNCiAgICAgICAgICAgIFNEID0gc3ByaW50ZigiJTAuM2YiLCBzZChPUF9yYXRlKSksDQogICAgICAgICAgICBwNSA9IHNwcmludGYoIiUwLjNmIiwgcXVhbnRpbGUoT1BfcmF0ZSwgMC4wNSkpLA0KICAgICAgICAgICAgcDk1ID0gc3ByaW50ZigiJTAuM2YiLCBxdWFudGlsZShPUF9yYXRlLCAwLjk1KSksDQogICAgICAgICAgICApJT4la25pdHI6OmthYmxlKCkNCmBgYA0KDQpL4bq/dCBxdeG6oyBuw6B5IGNobyB0aOG6pXkgdOG7syBs4buHIHRoYWkgZGnhu4VuIHRp4bq/biB0cnVuZyBiw6xuaCBjw7MgduG6uyDGsHUgdGjhur8gaMahbiDhu58gbmjDs20gUFBPUyBzbyB24bubaSBHblJIYW50OiAwLjQ2IHNvIHbhu5tpIDAuMzcgKG7Ds2kgY8OhY2gga2jDoWMsIHjDoWMgc3XhuqV0IHRo4bulIHRoYWkgdGjDoG5oIGPDtG5nIGNobyBt4buXaSBwaMO0aSBjaHV54buDbiBjw7MgduG6uyBjYW8gaMahbiDhu58gcGjDoWMgxJHhu5MgUFBPUyk7IFRhIGPDsyB0aOG7gyDGsOG7m2MgdMOtbmggUmlzayByYXRpbyAoUlIpIGdp4buvYSAyIHBow6FjIMSR4buTOiAkUlIgPSAwLjQ1Ny8wLjM3ID0gMS4yMzUkLiBUdXkgbmhpw6puIGdpw6EgdHLhu4sgdHJ1bmcgduG7iyBs4bqhaSB0xrDGoW5nIMSRxrDGoW5nICgwLjUpLiBOw7NpIGPDoWNoIGtow6FjLCBu4bq/dSBj4bupIGNodXnhu4NuIHBow7RpIDIgbOG6p24gdGjDrCBk4buxIGtp4bq/biDDrXQgbmjhuqV0IHPhur0gY8OzIDEgbOG6p24gxJHhuqF0IHRow6BuaCBjw7RuZy4NCg0KYykgVOG7tyBz4buRIHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZy90aOG6pXQgYuG6oWkgKE9kZHMpDQoNClRhIGPDsyB0aOG7gyDGsOG7m2MgbMaw4bujbmcga+G6v3QgcXXhuqMgdGhhaSBkaeG7hW4gdGnhur9uIHRoZW8gbeG7mXQgY8OhY2gga2jDoWMsIGLhurFuZyB04bu3IHPhu5EgT2Rkcw0KDQokJE9kZHMgPSBcZnJhY3twXzF9e3BfMH0gPSBcZnJhY3twXzF9eygxIC0gcF8xKX0kJA0KDQpW4bubaSAkcF8xJCBsw6AgeMOhYyBzdeG6pXQgdGjDoG5oIGPDtG5nLCAkcF8wJCBsw6AgeMOhYyBzdeG6pXQgdGjhuqV0IGLhuqFpLg0KDQpgYGB7cn0NCmRmJT4lbXV0YXRlKE9kZHMgPSBPUF9yYXRlLygxLU9QX3JhdGUpKS0+b2RkX2RmDQoNCm9kZF9kZiRPZGRzWyFpcy5maW5pdGUob2RkX2RmJE9kZHMpXSA8LSBOQQ0KDQpvZGRfZGYlPiUNCiAgZ3JvdXBfYnkoUHJvdG9jb2wpJT4lDQogIHN1bW1hcml6ZShuID0gbigpLA0KICAgICAgICAgICAgTWVhbiA9IHNwcmludGYoIiUwLjNmIiwgbWVhbihPZGRzLCBuYS5ybT1UUlVFKSksDQogICAgICAgICAgICBNZWRpYW4gPSBzcHJpbnRmKCIlMC4zZiIsIG1lZGlhbihPZGRzLG5hLnJtPVRSVUUpKSwNCiAgICAgICAgICAgIFNEID0gc3ByaW50ZigiJTAuM2YiLCBzZChPZGRzLCBuYS5ybT1UUlVFKSksDQogICAgICAgICAgICBwNSA9IHNwcmludGYoIiUwLjNmIiwgcXVhbnRpbGUoT2RkcywgMC4wNSwgbmEucm09VFJVRSkpLA0KICAgICAgICAgICAgcDk1ID0gc3ByaW50ZigiJTAuM2YiLCBxdWFudGlsZShPZGRzLCAwLjk1LG5hLnJtPVRSVUUpKSwNCiAgICAgICAgICAgICklPiVrbml0cjo6a2FibGUoKQ0KYGBgDQoNClRoZW8ga+G6v3QgcXXhuqMgbsOgeSwgT2RkcyBj4bunYSBuaMOzbSBQUE9TIGNhbyBoxqFuIE9kZHMgY+G7p2EgbmjDs20gR25SSGFudCAoMC41NTYgc28gduG7m2kgMC40NjIpLCBuw7NpIGPDoWNoIGtow6FjIE9kZHMgcmF0aW8gZ2nhu69hIFBQT1MgdsOgIEduUkhhIDogJE9SID0gMC41NTYvMC40NjIgPSAxLjIwMyQNCg0KZCkgTuG6v3UgeMOpdCBnacOhIHRy4buLIHRow6BuaCBjw7RuZyBoYXkgdGjhuqV0IGLhuqFpIHR1eeG7h3QgxJHhu5FpIChiaeG6v24gbmjhu4sgZ2nDoSBPUF9iaW4pDQoNCktoaSB0aOG7sWMgaGnhu4duIHBow6JuIHTDrWNoIG7DoHksIMSRxqFuIHbhu4sgcXVhbiBzw6F0IGzDoCBjw6EgdGjhu4MgYuG7h25oIG5ow6JuIHRoYXkgdsOsIMSRxqFuIHbhu4sgcGjDtGkuIEPDoWNoIGto4bqjbyBzw6F0IG7DoHkgc+G6vSBjaG8gcmEgbeG7mXQga+G6v3QgcXXhuqMga2jDoWMNCg0KYGBge3J9DQpkZiU+JWdyb3VwX2J5KFByb3RvY29sKSU+JQ0KICBzdW1tYXJpemUobiA9IG4oKSwNCiAgICAgICAgICAgIFJhdGUgPSBtZWFuKE9QX2JpbiksDQogICAgICAgICAgICBGcmVxID0gc3VtKE9QX2JpbiksDQogICAgICAgICAgICBPZGRzID0gUmF0ZS8oMS1SYXRlKSwNCiAgICAgICAgICAgICklPiVrbml0cjo6a2FibGUoKQ0KYGBgDQoNCkThu7FhIHbDoG8ga+G6v3QgcXXhuqMgbsOgeSwgdOG7tyBz4buRIHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZyBnaeG7r2EgMiBwaMOhYyDEkeG7kyA6ICRSUiA9IDAuNzk4LzAuNjQ1ID0gMS4yMzckIHbDoCBPZGRzLXJhdGlvIGdp4buvYSBjaMO6bmcgJE9SID0gMy45NS8xLjgxNSA9IDIuMTc2JC4g4bueIMSRw6J5IHRhIHRo4bqleSBt4buZdCDEkWnhu4NtIHRow7ogduG7iyBsw6Aga2hpIGNo4buNbiDEkcahbiB24buLIGto4bqjbyBzw6F0IGzDoCBi4buHbmggbmjDom4sIGvhur90IHF14bqjIE9SIHbDoCBSUiBjw7Mga2h1eW5oIGjGsOG7m25nIGNhbyBoxqFuIHNvIHbhu5tpIGtoaSB4w6l0IMSRxqFuIHbhu4sga2jhuqNvIHPDoXQgbMOgIHBow7RpLg0KDQpUYSBs4bqnbiBsxrDhu6N0IGto4bqjbyBzw6F0IHRy4buxYyBxdWFuIDMgaMOsbmggdGjhu6ljIGto4bqjbyBzw6F0IGvhur90IHF14bqjIHRoYWkgZGnhu4VuIHRp4bq/biB0cm9uZyAzIGJp4buDdSDEkeG7kyBzYXUNCg0KYGBge3J9DQpwYWxzID0gYygiIzBmYWFmMiIsIiNmMjBmNGYiKQ0KDQpwMSA9IGRmICU+JSBnZ3Bsb3QoYWVzKHkgPSBPUF9jdW0sIA0KICAgICAgICAgICAgICAgICAgeCA9IFByb3RvY29sLCANCiAgICAgICAgICAgICAgICAgIGZpbGw9IFByb3RvY29sKSkgKyANCiAgZ2VvbV9qaXR0ZXIoYWVzKGZpbGwgPSBQcm90b2NvbCksDQogICAgICAgICAgICAgIHNoYXBlID0gMjEsDQogICAgICAgICAgICAgIGFscGhhID0gMC44LA0KICAgICAgICAgICAgICB3aWR0aCA9IDAuMSwNCiAgICAgICAgICAgICAgaGVpZ2h0ID0gMC4yLA0KICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IFQpKw0KICBsYWJzKHk9IkN1bW11bGF0ZWQgT1AiLCB4ID0gIlByb3RvY29sIikgKyANCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFscywgbmFtZSA9ICJQcm90b2NvbCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IGMoMCwxLDIsMykpKw0KICB0aGVtZV9idygxMCkgKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvciA9ICJibGFjayIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siKSkNCg0KcDIgPSBkZiAlPiUgZ2dwbG90KGFlcyh4ID0gT1BfcmF0ZSwgDQogICAgICAgICAgICAgICAgICB5ID0gUHJvdG9jb2wsIA0KICAgICAgICAgICAgICAgICAgZmlsbD0gUHJvdG9jb2wpKSArIA0KICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFlcyhmaWxsID0gUHJvdG9jb2wpLA0KICAgICAgICAgICAgICAgICAgICAgIHN0YXQgPSAiYmlubGluZSIsDQogICAgICAgICAgICAgICAgICAgICAgc2NhbGUgPSAwLjUsIA0KICAgICAgICAgICAgICAgICAgICAgIGJpbnMgPSAzMCwNCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuOCkrDQogIGxhYnMoeD0iQ3VtbXVsYXRlZCBPUCByYXRlIiwgeSA9ICJQcm90b2NvbCIpICsgDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbHMsIG5hbWUgPSAiUHJvdG9jb2wiKSArDQogIGNvb3JkX2ZsaXAoKSsNCiAgdGhlbWVfYncoMTApDQoNCnAzID0gZGYlPiUNCiAgZ3JvdXBfYnkoUHJvdG9jb2wpJT4lDQogIHN1bW1hcmlzZShTdWNjZXNzID0gbWVhbihPUF9iaW4pLA0KICAgICAgICAgICAgRmFpbHVyZSA9IDEgLSBTdWNjZXNzKSU+JQ0KICBnYXRoZXIoYygyLDMpLGtleSA9ICJPUCIsIHZhbHVlID0gIlJhdGUiKSU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBQcm90b2NvbCwgeSA9IFJhdGUpKSsNCiAgZ2VvbV9iYXIoYWVzKGZpbGwgPSBPUCksIHN0YXQgPSAiaWRlbnRpdHkiKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2MwYmVjMiIsIiNmMDNhNzkiKSwgbmFtZSA9ICJPUCBPdXRjb21lIikgKw0KICB0aGVtZV9idygxMCkNCg0KDQpwMyArIHAxL3AyDQpgYGANCg0KQ2jDuiB0aMOtY2g6IEjDrG5oIGLDqm4gdHLDoWkgbMOgIGJp4buDdSDEkeG7kyBj4buZdCBjaOG7k25nIHRyw6xuaCBiw6B5IHBow6JuIGLhu5EgdOG7tyBs4buHIFRow6BuaCBjw7RuZy9UaOG6pXQgYuG6oWkgKHRy4bulYyBZKSBnaeG7r2EgMiBwaMOhYyDEkeG7kyAodHLhu6VjIFgpLCBow6xuaCBiw6puIHBo4bqjaSBn4buTbSAyIGJp4buDdSDEkeG7kzogZ8OzYyB0csOqbiBsw6AgYmnhu4N1IMSR4buTIHTDoW4geOG6oSBzbyBzw6FuaCB04bqnbiBzdeG6pXQgdGhhaSBkaeG7hW4gdGnhur9uICh0cuG7pWMgWSkgZ2nhu69hIDIgcGjDoWMgxJHhu5MgKHRy4bulYyBYKSwgZ8OzYyBkxrDhu5tpIGzDoCBiaeG7g3UgxJHhu5MgdOG6p24gc3XhuqV0IG3DtCB04bqjIHThu7cgbOG7hyB0aGFpIGRp4buFbiB0aeG6v24gY+G7mW5nIGThu5NuICh0cuG7pWMgWSkgZ2nhu69hIDIgcGjDoWMgxJHhu5MgKHRy4bulYyBYKS4NCg0KTmdvw6BpIDIgcGjDoWMgxJHhu5MsIHRyb25nIGThu68gbGnhu4d1IGPDsm4gY8OzIG3hu5l0IHPhu5EgaGnhu4dwIGJp4bq/biBraMOhYyBuaMawIFR14buVaSwgQUZDIHbDoCDEkeG7mSBkw6B5IG7hu5lpIG3huqFjIGPDsyBi4bqjbiBjaOG6pXQgbMOgIGJp4bq/biBz4buRIGxpw6puIHThu6VjLiBUYSBtdeG7kW4ga2jhuqNvIHPDoXQgdHLhu7FjIHF1YW4gbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2Egbmjhu69uZyBoaeG7h3AgYmnhur9uIG7DoHkgdsOgIHjDoWMgc3XhuqV0IMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v247IHRhIGPDsyB0aOG7gyB0aOG7sWMgaGnhu4duIHRoZW8gMyBjw6FjaDoNCg0KKDEpIExpw6puIGjhu4cgYmnhur9uIFggdsOgIGdpw6EgdHLhu4sgMCwxIGPhu6dhIGJp4bq/biBPUF9iaW4sIHRow7RuZyBxdWEgxJHhu5MgdGjhu4sgY+G7p2EgbcO0IGjDrG5oIEdMTSB24bubaSBwaMOibiBwaOG7kWkgYmlub21pYWwgKMSR4buTIHRo4buLIGjDoG0gbG9naXN0aWMpDQoNCigyKSBMacOqbiBo4buHIGJp4bq/biBYIHbDoCBnacOhIHRy4buLIHThu7cgbOG7hyBPUF9yYXRlLCB0aMO0bmcgcXVhIDEgbcO0IGjDrG5oIGjhu5NpIHF1eSBHTE0gduG7m2kgcGjDom4gcGjhu5FpIHF1YXNpYmlub21pYWw7DQoNCigzKSBMacOqbiBo4buHIGJp4bq/biBYIHbDoCBPZGRzLCB0aMO0bmcgcXVhIG3hu5l0IG3DtCBow6xuaCBo4buTaSBxdXkgdHV54bq/biB0w61uaA0KDQpgYGB7cn0NCnA0ID0gZGYlPiVnYXRoZXIoYygxLDMsNiksIA0KICAgICAgICAgICAga2V5ID0gIkZhY3RvciIsIA0KICAgICAgICAgICAgdmFsdWUgPSAidmFsdWUiKSU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB2YWx1ZSwgeSA9IE9QX2JpbikpKw0KICBnZW9tX3Ntb290aChhZXMoZmlsbCA9IFByb3RvY29sLCANCiAgICAgICAgICAgICAgICAgIGNvbCA9IFByb3RvY29sKSwNCiAgICAgICAgICAgICAgbWV0aG9kID0gImdsbSIsIA0KICAgICAgICAgICAgICBtZXRob2QuYXJncyA9IGxpc3QoZmFtaWx5ID0gImJpbm9taWFsIiksDQogICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikrDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxzLCBuYW1lID0gIlByb3RvY29sIikgKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFscywgbmFtZSA9ICJQcm90b2NvbCIpICsNCiAgZmFjZXRfd3JhcCh+RmFjdG9yLCBuY29sPTEsIHNjYWxlcyA9ICJmcmVlX3giKSsNCiAgbGFicyh5PSJCaW5hcnkgT1AiLCB4ID0gTlVMTCkgKyANCiAgdGhlbWVfYncoMTApDQoNCnA1ID0gZGYlPiVnYXRoZXIoYygxLDMsNiksIA0KICAgICAgICAgICAga2V5ID0gIkZhY3RvciIsIA0KICAgICAgICAgICAgdmFsdWUgPSAidmFsdWUiKSU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB2YWx1ZSwgeSA9IE9QX3JhdGUpKSsNCiAgZ2VvbV9zbW9vdGgoYWVzKGZpbGwgPSBQcm90b2NvbCwgDQogICAgICAgICAgICAgICAgICBjb2wgPSBQcm90b2NvbCksDQogICAgICAgICAgICAgIG1ldGhvZCA9ICJnbG0iLCANCiAgICAgICAgICAgICAgbWV0aG9kLmFyZ3MgPSBsaXN0KGZhbWlseSA9ICJxdWFzaWJpbm9taWFsIikpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEpKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFscywgbmFtZSA9ICJQcm90b2NvbCIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbHMsIG5hbWUgPSAiUHJvdG9jb2wiKSArDQogIGZhY2V0X3dyYXAofkZhY3RvciwgbmNvbD0xLCBzY2FsZXMgPSAiZnJlZV94IikrDQogIGxhYnMoeT0iT1AgcmF0ZSIsIHggPSBOVUxMKSArIA0KICB0aGVtZV9idygxMCkNCg0KcDYgPSBkZiU+JW11dGF0ZShvZGQgPSBPUF9yYXRlLygxLU9QX3JhdGUpKSU+JQ0KICBnYXRoZXIoYygxLDMsNiksDQogICAgICAgICAgICBrZXkgPSAiRmFjdG9yIiwgDQogICAgICAgICAgICB2YWx1ZSA9ICJ2YWx1ZSIpJT4lDQogIGdncGxvdChhZXMoeCA9IHZhbHVlLCB5ID0gb2RkKSkrDQogIGdlb21fc21vb3RoKGFlcyhmaWxsID0gUHJvdG9jb2wsIA0KICAgICAgICAgICAgICAgICAgY29sID0gUHJvdG9jb2wpLA0KICAgICAgICAgICAgICBtZXRob2QgPSAiZ2xtIiwNCiAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gcGFscywgbmFtZSA9ICJQcm90b2NvbCIpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbHMsIG5hbWUgPSAiUHJvdG9jb2wiKSArDQogIGZhY2V0X3dyYXAofkZhY3RvciwgbmNvbD0xLCBzY2FsZXMgPSAiZnJlZV94IikrDQogIGxhYnMoeT0iT2RkcyA9IHAxL3AwIiwgeCA9IE5VTEwpICsgDQogIHRoZW1lX2J3KDEwKQ0KICAgICAgICAgICAgICAgIA0KcDQrcDYrcDUNCmBgYA0KDQpDaMO6IHRow61jaDogSMOsbmggdHLDqm4gZ+G7k20gMyBj4buZdCwgdOG7qyB0csOhaSBzYW5nIHBo4bqjaSBs4bqnbiBsxrDhu6N0IHRyw6xuaCBiw6B5OiAoMSkgTGnDqm4gaOG7hyBnaeG7r2EgZ2nDoSB0cuG7iyBBRkMsIEFnZSwgVGhpY2tuZXNzICgzIGjDoG5nLCB0cuG7pWMgWCkgdsOgIGto4bqjIG7Eg25nIMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v24gKHRy4bulYyBZKTsgKDIpIExpw6puIGjhu4cgZ2nhu69hIGdpw6EgdHLhu4sgQUZDLCBBZ2UsIFRoaWNrbmVzcyAoMyBow6BuZywgdHLhu6VjIFgpIHbDoCBPZGRzICh04buJIHPhu5EgZ2nhu69hIHjDoWMgc3XhuqV0IHRow6BuaCBjw7RuZy90aOG6pXQgYuG6oWkpOyB2w6AgKDMpIExpw6puIGjhu4cgZ2nhu69hIGdpw6EgdHLhu4sgQUZDLCBBZ2UsIFRoaWNrbmVzcyAoMyBow6BuZywgdHLhu6VjIFgpIHbDoCB04bu3IGzhu4cgdGhhaSBkaeG7hW4gdGnhur9uIHRyw6puIHThu5VuZyBz4buRIHBow7RpIGNodXnhu4NuICh0cuG7pWMgWSkuIEThu68gbGnhu4d1IMSRxrDhu6NjIHBow6JuIHRow6BuaCAyIG5ow7NtOiBwaMOhYyDEkeG7kyBQUE9TIChtw6B1IGjhu5NuZykgdsOgIEduUmhhIChtw6B1IHhhbmgpLg0KDQpIw6xuaCDhuqNuaCBuw6B5IGfhu6NpIMO9IG3hu5l0IHPhu5EgZ2nhuqMgdGh1eeG6v3QgbmjGsCBzYXU6DQoNCjEpIEFGQyBjw7MgaGnhu4d1IOG7qW5nIHTGsMahbmcgdMOhYyBnaeG7r2EgQUZDIHbDoCBsb+G6oWkgcGjDoWMgxJHhu5MsIHbDrCAyIMSR4buTIHRo4buLIGPDoWMgaMOgbSB0dXnhur9uIHTDrW5oL2xvZ2lzdGljIGPhu6dhIDIgbmjDs20gY+G6r3QgbmhhdSwgduG7m2kgaGnhu4d1IOG7qW5nIEFGQyBraMOhYyBiaeG7h3Qg4bufIG3hu5dpIG5ow7NtLg0KDQoyKSBUdeG7lWkgY8OzIGhp4buHdSDhu6luZyDEkeG7mWMgbOG6rXAgdsOgIMSR4buTbmcgbmjhuqV0IOG7nyAyIHBow6FjIMSR4buTLCBraOG6oyBuxINuZyB0aGFpIGRp4buFbiB0aeG6v24gdMawxqFuZyBxdWFuIG5naOG7i2NoIHbhu5tpIHR14buVaSAoZ2nhuqNtIGThuqduIOG7nyBwaOG7pSBu4buvIGzhu5tuIHR14buVaSk7DQoNCjMpIMSQ4buZIGTDoHkgbuG7mWkgbeG6oWMgdOG7rSBjdW5nIGPDsyBoaeG7h3Ug4bupbmcgxJHhu5ljIGzhuq1wIHbhu5tpIHBow6FjIMSR4buTLCB2w6AgxJHhu5NuZyBuaOG6pXQgZ2nhu69hIDIgbmjDs20gcGjDoWMgxJHhu5MsIGhp4buHdSDhu6luZyBuw6B5IHLhuqV0IHnhur91IHbDoCBjw7Mga2h1eW5oIGjGsOG7m25nIHTGsMahbmcgcXVhbiB0aHXhuq1uIHbhu5tpIGto4bqjIG7Eg25nIHRoYWkgZGnhu4VuIHRp4bq/bi4NCg0KIyBMw70gdGh1eeG6v3QgduG7gSBtw7QgaMOsbmggaOG7k2kgcXV5IGxvZ2lzdGljDQoNCkNobyBiw6BpIHRvw6FuIHRo4buRbmcga8OqIGhp4buHbiB0aOG7nWksIHRhIGPhuqduIG3hu5l0IHBoxrDGoW5nIHRp4buHbiBjaG8gcGjDqXAgbGnDqm4ga+G6v3QgZ2nDoSB0cuG7iyBj4bunYSBt4buZdCBiaeG6v24gxJHhu5ljIGzhuq1wICh54bq/dSB04buRIHRpw6puIGzGsOG7o25nKSAkWCQgdsOgIG3hu5l0IHjDoWMgc3XhuqV0ICRZID0gcCBcaW4gWzAsMV0kLiBDw7RuZyBj4bulIMSRw7MgbMOgIG3DtCBow6xuaCBsb2dpc3RpYy4NCg0KTcO0IGjDrG5oIGjhu5NpIHF1eSBsb2dpc3RpYyBjw7MgbeG7mXQgbOG7i2NoIHPhu60gbMOidSDEkeG7nWkgKGtob+G6o25nIDc4IG7Eg20pLCB0csaw4bubYyBj4bqjIHPhu7EgcmEgxJHhu51pIGPhu6dhIGzDvSB0aHV54bq/dCB24buBIG3DtCBow6xuaCB0dXnhur9uIHTDrW5oIHThu5VuZyBxdcOhdCBHTE0uIEPDonUgY2h1eeG7h24gbsOgeSBraMOhIGTDoGksIHbDoCBz4buxIGto4bufaSDEkeG6p3UgY+G7p2EgbsOzIGtow7RuZyBsacOqbiBxdWFuIGfDrCDEkeG6v24geMOhYyBzdeG6pXQgdsOgIHRo4buRbmcga8OqLiBDaMO6bmcgdGEgc+G6vSBraOG7n2kgaMOgbmggeGEgaMahbiB04burIGNo4buXIG5o4bqtbiByYSB0cm9uZyB0aOG6vyBnaeG7m2kgdOG7sSBuaGnDqm4gbHXDtG4gaGnhu4duIGRp4buHbiBt4buZdCBxdXkgbHXhuq10IHRp4bq/biB0cmnhu4NuIMSR4bq3YyBiaeG7h3QgZ+G7k20gMyBnaWFpIMSRb+G6oW46IDEpIEdpYWkgxJFv4bqhbiBz4bubbSB24bubaSBz4buxIHTEg25nIHRyxrDhu59uZyBsxal5IHRp4bq/biwgeOG6pXAgeOG7iSBow6BtIG3FqSAoZXhwb25lbnRpYWwpOyAyKSBUaeG6v3AgdGhlbyBsw6AgZ2lhaSDEkW/huqFuIGLDo28gaMOyYTogdOG7kWMgxJHhu5kgcGjDoXQgdHJp4buDbiBjaOG6rW0gbOG6oWksIHR1eeG6v24gdMOtbmg7IDMpIEN14buRaSBjw7luZyBsw6AgZ2lhaSDEkW/huqFuIOG7lW4gxJHhu4tuaCB2w6AgdHLGsOG7n25nIHRow6BuaDogc+G7sSBwaMOhdCB0cmnhu4NuIG5n4burbmcgbOG6oWkuIEtoaSBiaeG7g3UgZGnhu4VuIHRp4bq/biB0csOsbmggbsOgeSB0aGVvIHRo4budaSBnaWFuLCBz4bq9IHThuqFvIHJhIG3hu5l0IMSRxrDhu51uZyBjb25nIGjDrG5oIGNo4buvIFMgKHNpZ21vaWQgY3VydmUpLg0KDQpUYSBjw7MgdGjhu4MgcXVhbiBzw6F0IHRo4bqleSBxdXkgbHXhuq10IG7DoHkg4bufIG3hu41pIGzEqW5oIHbhu7FjOiB0xINuZyB0csaw4bufbmcgZMOibiBz4buRL2tpbmggdOG6vywgY2h1IHRyw6xuaCBjaHV54buDbiBow7NhIHNpbmggaOG7jWMsIHBo4bqjbiDhu6luZyBow7NhIGjhu41jLiBUcm9uZyBT4bqjbiBQaOG7pSBraG9hLCB0YSBjw7MgdGjhu4MgbmjDrG4gdGjhuqV5IG7DsyB0cm9uZyBkaeG7hW4gdGnhur9uIGPDoWMgaG9ybW9uZSBzaW5oIGThu6VjLCBz4buxIHTEg25nIHRyxrDhu59uZyBj4bunYSBiw6BvIHRoYWkgdHJvbmcgdOG7rSBjdW5nIG5nxrDhu51pIG3hurksIGxpw6puIGjhu4cgbGnhu4F1IC8gxJHDoXAg4bupbmcgdHJvbmcgZMaw4bujYyBs4buxYyBo4buNYy4uLg0KDQpU4burIHRo4bq/IGvhu4kgMTgtMTksIG5o4buvbmcgbmjDoCB0b8OhbiBo4buNYyDEkcOjIGto4bqjbyBzw6F0IHF1eSBsdeG6rXQgbsOgeSB2w6AgbOG6rXAgcmEgY8OhYyBow6BtIHRvw6FuIGjhu41jIGNobyBwaMOpcCB0w6FpIGhp4buHbiDEkcaw4budbmcgY29uZyBow6xuaCBjaOG7ryBTLCBn4buNaSBsw6AgY8OhYyBow6BtIHNpZ21vaWQsIHRow60gZOG7pSBow6BtIGh5cGVyYm9saWMgdGFuZ2VudCBj4bunYSBKZWFuIFNhdXJyeSBuxINtIDE3NzQuDQoNClRyb25nIHPhu5EgY8OhYyBow6BtIHNpZ21vaWQsIHRhIGPDsyBow6BtIGxvZ2lzdGljIGzDoCBuaMOibiB24bqtdCBjaMOtbmggdHJvbmcgY8OidSBjaHV54buHbiBuw6B5LiBIw6BtIGxvZ2lzdGljIGRvIG5ow6AgdG/DoW4gaOG7jWMgbmfGsOG7nWkgUGjDoXAgUGllcnJlIEZyYW7Dp29pcyBWZXJodWxzdCB0aGnhur90IGzhuq1wIHbDoG8gbsSDbSAxODQ1LCB24bubaSBjw7RuZyBk4bulbmcgbmd1ecOqbiB0aOG7p3kgbmjhurFtIGto4bqjbyBzw6F0IHF1eSBsdeG6rXQgdMSDbmcgdHLGsOG7n25nIGTDom4gc+G7kSB0cm9uZyBt4buZdCBxdeG6p24gdGjhu4MuIEPDtG5nIHRo4bupYyBj4bunYSBow6BtIGxvZ2lzdGljIMSRxrDhu6NjIHRyw6xuaCBiw6B5IG5oxrAgc2F1Lg0KDQokJHkgPSBcZnJhY3tlXnt4fX17MSArIGVee3h9fSA9IFxmcmFjezF9ezEgKyBlXnsteH19ID0gXGZyYWN7MX17Mn0gKyBcZnJhY3sxfXsyfSB0YW5oKFxmcmFje3h9ezJ9KSQkDQoNCkjDrG5oOiDEkeG7kyB0aOG7iyBow6BtIGxvZ2lzdGljLiBU4burIGdpw6EgdHLhu4sgxJHhuqd1IHbDoG8gbMOgIHPhu5EgdGjhu7FjICR4JCBi4bqldCBrw6wsIGjDoG0gbG9naXN0aWMgeHXhuqV0IGvhur90IHF14bqjIGzDoCBt4buZdCBnacOhIHRy4buLIHRyb25nIGtob+G6o25nICgwLDEpLiANCg0KYGBge3IsZWNobz1GfQ0KeCA9IHNlcSgtNCw0LDAuMDEpDQp5ID0gMC41ICsgMC41KnRhbmgoeCkNCg0KcXBsb3QoeCx5LCANCiAgICAgIGdlb20gPSAibGluZSIsIA0KICAgICAgY29sb3IgPSAicmVkIiwgDQogICAgICBzaG93LmxlZ2VuZCA9IEYpKw0KICBsYWJzKHRpdGxlID0gImxvZ2lzdGljIGZ1bmN0aW9uOiB5ID0gMS8oMSArIGV4cCgteCkpIiwNCiAgICAgIHkgPSAieSA9IDEvKDEgKyBleHAoLXgpIikrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoLTQsNCwxKSkrDQogIHRoZW1lX2J3KCkNCmBgYA0KDQpN4buZdCBjw6FjaCB0w6xuaCBj4budLCDEkeG6t2MgdMOtbmggbsOgeSBj4bunYSBow6BtIGxvZ2lzdGljIGThuqtuIMSR4bq/biBt4buZdCDhu6luZyBk4bulbmcgcXVhbiB0cuG7jW5nIHRyb25nIGzEqW5oIHbhu7FjIHRo4buRbmcga8OqOiBuw7MgZ2nhuqNpIHF1eeG6v3Qgbmh1IGPhuqd1IGxpw6puIGvhur90IGdpw6EgdHLhu4sgbeG7mXQgdOG6rXAgYmnhur9uICRYJCB2w6AgeMOhYyBzdeG6pXQgcXVhbiBzw6F0IMSRxrDhu6NjIGdpw6EgdHLhu4sgJFk9MSQgKFkgbMOgIG3hu5l0IGJp4bq/biBuaOG7iyBnacOhKS4NCg0KTcO0IGjDrG5oIGxvZ2lzdGljIGPhu5UgxJFp4buDbiDEkcaw4bujYyDEkeG7i25oIG5naMSpYSB0cuG7sWMgdGnhur9wIGThu7FhIHbDoG8gaMOgbSBsb2dpc3RpYywgYuG6sW5nIGPDoWNoIHRoYXkgxJHhu5FpIHPhu5EgJHgkIGLhurFuZyBt4buZdCDEkeG6oWkgbMaw4bujbmcgJGckIG5oxrAgc2F1Og0KDQoNCiQkUHIoWT0xfFgpIFxzaW0gbG9naXN0aWMoWCkgPSBcZnJhY3sxfXsxICsgZV57LWd9fSQkDQoNClbhu5tpICRnJCBsw6AgbeG7mXQgYmnhu4N1IHRo4bupYyAoaMOgbSkgdHV54bq/biB0w61uaCDEkcaw4bujYyBtw7QgaMOsbmggaMOzYSB0aGVvIHThuq1wIGJp4bq/biAkWCQNCg0KJCRnID0gXGJldGFfMCArIFxiZXRhXzFYXzEgKyBcYmV0YV8yWF8yICsgLi4uICsgXGJldGFfalhfaiQkDQpUdXkgbmhpw6puLCBwaGnDqm4gYuG6o24gdGjhu7FjIGThu6VuZyBj4bunYSBtw7QgaMOsbmggaOG7k2kgcXV5IGxvZ2lzdGljIGNo4buJIMSRxrDhu6NjIMSR4buLbmggaMOsbmggdsOgbyBuxINtIDE5NDQsIGtoaSBuaMOgIHRo4buRbmcga8OqIEpvc2VwaCBCZXJrc29uIHRoaeG6v3QgbOG6rXAgbeG7mXQga2jDoWkgbmnhu4dtIHF1YW4gdHLhu41uZyBsw6AgTG9nIG9kZHMgdsOgIGTDuW5nIG7DsyBsw6BtIHRoYW5nIMSRbyBjaG8gYsOgaSB0b8OhbiDGsOG7m2MgbMaw4bujbmcgYmnhur9uIG5o4buLIGdpw6EuDQoNCk5oxrAgdGEgYmnhur90LCBPZGRzIGzDoCB04buJIHPhu5EgZ2nhu69hIDIgeMOhYyBzdeG6pXQuIFbhu5tpICRwJCBsw6AgeMOhYyBzdeG6pXQgdGjDoG5oIGPDtG5nICgkWT0xJCkgdsOgICQxLXAkIGzDoCB4w6FjIHN14bqldCB0aOG6pXQgYuG6oWkgKCRZPTAkKSwgdGEgY8OzOg0KDQokJE9kZHMgPSBcZnJhY3twfXsxLXB9JCQNCg0KVOG7qyDEkcOzLCB0YSBjw7MgaMOgbSBsb2dpdCBsw6AgbeG7mXQgY8O0bmcgY+G7pSBraMOhYyBjaG8gcGjDqXAgbGnDqm4ga+G6v3QgdHLhu7FjIHRp4bq/cCB04bqtcCBiaeG6v24gJFgkIHbDoCBnacOhIHRy4buLIHjDoWMgc3XhuqV0ICRZPXAkLiBIw6BtIGxvZ2l0IGNow61uaCBsw6Agc+G7sSDDoXAgZOG7pW5nIGjDoG0gbG9nYXJpdCB04buxIG5oacOqbiBjaG8gT2RkczoNCg0KJCRsb2dpdChwKSA9IGxvZyhcZnJhY3twfXsxLXB9KSQkDQoNClRhIGThu4UgZMOgbmcgbmjhuq1uIHRo4bqleSBt4buRaSBsacOqbiBo4buHIG5naOG7i2NoIMSR4bqjbyBnaeG7r2EgMiBow6BtIGxvZ2l0IHbDoCBow6BtIGxvZ2lzdGljIGPhu5UgxJFp4buDbjogDQoNCmBgYHtyLCBlY2hvID0gRn0NCnAgPSBzZXEoMCwxLDAuMDEpDQp5ID0gbG9nKHAvKDEtcCkpDQoNCnAxID0gcXBsb3QocCx5LCANCiAgICAgIGdlb20gPSAibGluZSIsIA0KICAgICAgY29sb3IgPSAicmVkIiwgDQogICAgICBzaG93LmxlZ2VuZCA9IEYpKw0KICBsYWJzKHRpdGxlID0gImxvZ2l0IGZ1bmN0aW9uOiB5PWxvZyhwLygxLXApKSIsIA0KICAgICAgIHkgPSAibG9naXQocCkgPSBsb2cob2RkcykgPSBsb2cocC8oMS1wKSIpKw0KICB0aGVtZV9idygpDQoNCnAyID0gcXBsb3QoeSxwLCANCiAgICAgIGdlb20gPSAibGluZSIsIA0KICAgICAgY29sb3IgPSAicmVkIiwgDQogICAgICBzaG93LmxlZ2VuZCA9IEYpKw0KICBsYWJzKHRpdGxlID0gImxvZ2lzdGljIGZ1bmN0aW9uIiwgDQogICAgICAgeCA9ICJsb2dpdChwKSIsDQogICAgICAgeSA9ICJwIikrDQogIHRoZW1lX2J3KCkNCg0KcDEgKyBwMg0KYGBgDQoNClThu6sgxJHDsywgQmVya3NvbiDEkcOjIGNodeG6qW4gaMOzYSBo4buTaSBxdXkgbG9naXN0aWMgdGjDoG5oIG3hu5l0IHBoxrDGoW5nIHBow6FwIHRo4buRbmcga8OqIHF1eSDGsOG7m2MsIHPhu60gZOG7pW5nIGjDoG0gbG9naXQgdGhheSB2w6wgbG9naXN0aWMsIHbDoCBkw7luZyBsb2cob2RkcykgbMOgbSB0aGFuZyDEkW8sIMSRxqFuIHbhu4sgY2hvIGJp4bq/biBr4bq/dCBxdeG6oyAkWSQgdHJvbmcgbcO0IGjDrG5oLiBTYXUgxJHDsywgRGF2aWQgQ294ICgxOTU4KSBob8OgbiB0aGnhu4duIGvhu7kgdGh14bqtdCDGsOG7m2MgbMaw4bujbmcgdGhhbSBz4buRIHRyb25nIG3DtCBow6xuaCBsb2dpc3RpYy4NCg0KU2F1IGPDuW5nLCB2w6BvIG7Eg20gMTk3MiBOZWxkZXIgdsOgIFdlZGRlcmJ1cm4gxJHDoyBo4bujcCBuaOG6pXQgbcO0IGjDrG5oIGxvZ2lzdGljIHbDoG8gaOG7hyB0aOG7kW5nIG3DtCBow6xuaCBo4buTaSBxdXkgdHV54bq/biB0w61uaCB04buVbmcgcXXDoXQgKEdMTSksIG3DtCBow6xuaCBsb2dpc3RpYyBsw6AgbeG7mXQgdGjhu4MgxJHhurdjIGJp4buHdCBj4bunYSBtw7QgaMOsbmggR0xNLCDGsOG7m2MgbMaw4bujbmcgZ2nDoSB0cuG7iyBj4bunYSAkXG11JCBsw6AgdHJ1bmcgYsOsbmggY+G7p2EgYmnhur9uIGvhur90IHF14bqjICRZJCB0aGVvIHF1eSBsdeG6rXQgcGjDom4gcGjhu5FpIEJpbm9taWFsIHbDoCAyIHRoYW0gc+G7kSAkQkkobixcbXUpJCANCg0KJCRQcihZPXl8bixcbXUpID0gXGZyYWN7biF9e3khKG4teSkhfVxtdV57eX0oMS1wKV57bi15fSQkDQoNClRhIMaw4bubYyBsxrDhu6NuZyBnacOhIHRy4buLIGPhu6dhICRcbXUkIGLhurFuZyBt4buZdCBtw7QgaMOsbmggdHV54bq/biB0w61uaCB24bubaSBow6BtIGxpw6puIGvhur90IGxvZ2l0Og0KDQokJGxvZ2l0KFxtdSkgPSBsb2coXGZyYWN7XG11fXsxLVxtdX0pIFxzaW0gXGJldGFfMCArIFxiZXRhXzFYXzEgKyBcYmV0YV8yWF8yICsgLi4uICsgXGJldGFfalhfaiAgJCQNClRhIHRo4bqleSwgxJHhu4tuaCBuZ2jEqWEgbcO0IGjDrG5oIGjhu5NpIHF1eSBsb2dpc3RpYyB0aGVvIGzDvSB0aHV54bq/dCBHTE0gdsOgIGjDoG0gbG9naXQgZOG7hSBoaeG7g3UgdsOgIMSRxqFuIGdp4bqjbiBoxqFuIG5oaeG7gXUgc28gduG7m2kgxJHhu4tuaCBuZ2jEqWEgbmd1ecOqbiB0aOG7p3kgZOG7sWEgdsOgbyBow6BtIGxvZ2lzdGljLiBOaMawbmcgdsOsIGzDvSBkbyBs4buLY2ggc+G7rSwgdGEgduG6q24gZMO5bmcgdMOqbiBn4buNaSAibG9naXN0aWMgcmVncmVzc2lvbiIgY2hvIGxv4bqhaSBtw7QgaMOsbmggbsOgeSwgbmjGsG5nIHRhIGhp4buDdSBi4bqjbiBjaOG6pXQgY+G7p2EgbsOzIGNo4buJIMSRxqFuIGdp4bqjbiBsw6AgbeG7mXQgbcO0IGjDrG5oIEdMTSB24bubaSBwaMOibiBwaOG7kWkgQmlub21pYWwgaG/hurdjIEJlcm5vdWxsaSAodHLGsOG7nW5nIGjhu6NwIMSR4bq3YyBiaeG7h3Qga2hpICRuPTEkKQ0KDQojIELGsOG7m2MgMkE6IE3DtCBow6xuaCBo4buTaSBxdXkgTG9naXN0aWMgY2hvIGJp4bq/biBr4bq/dCBxdeG6oyBuaOG7iyBnacOhDQoNClRhIHPhur0gbOG6p24gbMaw4bujdCBwaMOibiB0w61jaCAyIG3DtCBow6xuaCBsb2dpc3RpYyBraMOhYyBuaGF1IGNobyAyIGJp4bq/biBr4bq/dCBxdeG6ozogMSkga+G6v3QgcXXhuqMgbmjhu4sgZ2nDoSAodGjDoG5oIGPDtG5nIGhv4bq3YyB0aOG6pXQgYuG6oWkgdHV54buHdCDEkeG7kWkgduG7gSB0aGFpIGRp4buFbiB0aeG6v24gdHJvbmcgdGjDrSBuZ2hp4buHbSwgYmnhur9uIE9QX2JpbikgdsOgIDIpIHThu7cgbOG7hyB0aGFpIGRp4buFbiB0aeG6v24gdHLDqm4gdOG7lW5nIHPhu5EgcGjDtGkgY2h1eeG7g24gKGJp4bq/biBPUF9yYXRlKS4NCg0KQ2hvIGvhur90IHF14bqjIHRo4bupIG5o4bqldCwgbcO0IGjDrG5oIMOhcCBk4bulbmcgbeG7mXQgdHLGsOG7nW5nIGjhu6NwIMSR4bq3YyBiaeG7h3QgY+G7p2EgcGjDom4gcGjhu5FpIEJpbm9taWFsIHbhu5tpICRuPTEkLCB24bubaSDEkcahbiB24buLIHF1YW4gc8OhdCBsw6AgY8OhIHRo4buDIGLhu4duaCBuaMOibi4gTeG7pWMgdGnDqnUgY+G7p2EgbcO0IGjDrG5oIGzDoCDGsOG7m2MgbMaw4bujbmcgeMOhYyBzdeG6pXQgcXVhbiBzw6F0IMSRxrDhu6NjIGdpw6EgdHLhu4sgJE9QXF9iaW4gPSAxJCBjaG8gbeG7l2kgY8OhIHRo4buDLiANCg0KTcO0IGjDrG5oIGPDsyBjw7RuZyB0aOG7qWM6IE9QX2JpbiB+ICBQcm90b2NvbCpBRkMgKyBUaGlja25lc3MgKyBBZ2U7IGZhbWlseSA9ICJiaW5vbWlhbCIgKGjDoG0gbGnDqm4ga+G6v3QgbeG6t2MgxJHhu4tuaCBsw6AgbG9naXQpLg0KDQpO4buZaSBkdW5nIGPhu6dhIG3DtCBow6xuaCBuaMawIHNhdToNCg0KYGBge3J9DQpsb2dfbW9kID0gZ2xtKE9QX2JpbiB+ICBQcm90b2NvbCpBRkMgKyBUaGlja25lc3MgKyBBZ2UsDQogICAgICAgICAgICAgICAgZGF0YSA9IGRmLA0KICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIpDQoNCnN1bW1hcnkobG9nX21vZCkNCmBgYA0KRGnhu4VuIGdp4bqjaSBu4buZaSBkdW5nIGvhur90IHF14bqjIHRow7QgY+G7p2EgbcO0IGjDrG5oOg0KDQpEbyBz4butIGThu6VuZyBow6BtIGxpw6puIGvhur90IGzDoCBsb2dpdCwgZ2nDoSB0cuG7iyDGsOG7m2MgbMaw4bujbmcgY+G7p2EgbcO0IGjDrG5oIGhp4buHbiB0aOG7nWkgbMOgICRsb2dpdChcbXUpJCBoYXkgJGxvZyhcZnJhY3tcbXV9ezEtXG11fSkkIGhheSAkbG9nKE9kZHMpJCwgduG7m2kgJFxtdSQgbMOgIHjDoWMgc3XhuqV0IMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v24gdHJ1bmcgYsOsbmggKGNobyBt4buVaSBjw6EgdGjhu4MpLiBU4bqldCBj4bqjIGjhu4cgc+G7kSBo4buTaSBxdXkgxJFhbmcg4bufIHRoYW5nIMSRbyBsb2cob2RkcykuIFRhIGPDsyB0aOG7gyBjaHV54buDbiB24buBIHRoYW5nIMSRbyB4w6FjIHN14bqldCBi4bqxbmcgaMOgbSBwbG9naXMsIGhv4bq3YyB24buBIHRoYW5nIMSRbyBPZGRzIGLhurFuZyBow6BtIGV4cG9uZW50aWFsLg0KDQokSW50ZXJjZXB0ID0gMi4yODIyMCQgdMawxqFuZyDhu6luZyB24bubaSBsb2cob2RkKSBj4bunYSB4w6FjIHN14bqldCB0aGFpIGRp4buDbiB0aeG6v24g4bufIHBow6FjIMSR4buTIHRoYW0gY2hp4bq/dSAoR25SSF9hbnQpLCB0cm9uZyDEkWnhu4F1IGtp4buHbiBnacOhIHRy4buLIEFnZSwgQUZDIHbDoCBUaGlja25lc3MgZ2nhu68gY+G7kSDEkeG7i25oIOG7nyBt4bupYyB0cnVuZyBiw6xuaCBj4bunYSBxdeG6p24gdGjhu4MuDQoNCiRQcm90b2NvbFBQT1MgPSAzLjU2OTUyJCB0xrDGoW5nIOG7qW5nIHbhu5tpIHPhu7EgdGhheSDEkeG7lWkgbG9nKG9kZCkgY+G7p2EgeMOhYyBzdeG6pXQgdGhhaSBkaeG7hW4gdGnhur9uIOG7nyBwaMOhYyDEkeG7kyBQUE9TIHNvIHbhu5tpIG5ow7NtIMSR4buRaSBjaOG7qW5nIChHblJIX2FudCksIHRyb25nIMSRaeG7gXUga2nhu4duIGdpw6EgdHLhu4sgQWdlLCBBRkMgdsOgIFRoaWNrbmVzcyBraMO0bmcgxJHhu5VpLg0KDQpDw6FjIGjhu4cgc+G7kSBo4buRaSBxdXkgY2hvIEFGQyxBZ2UgdsOgIFRoaWNrbmVzcyBs4bqnbiBsxrDhu6N0IOG7qW5nIHbhu5tpIHPhu7EgdGhheSDEkeG7lWkgY+G7p2EgbG9nKG9kZCkgeMOhYyBzdeG6pXQgdGhhaSBkaeG7hW4gdGnhur9uIGtoaSBBRkMsIEFnZSBob+G6t2MgVGhpY2tuZXNzIHTEg25nIDEgxJHGoW4gduG7iy4NCg0KVsOsIG3DtCBow6xuaCBjw7MgeMOpdCBoaeG7h3Ug4bupbmcgdMawxqFuZyB0w6FjIGdp4buvYSBwaMOhYyDEkeG7kyBQUE9TIHbDoCBBRkMsIHRhIGPDsyB0aMOqbSBo4buHIHPhu5EgaOG7k2kgcXV5IFByb3RvY29sUFBPUzpBRkM7IHbhu5tpIMO9IG5naMSpYSDEkW8gbMaw4budbmcgc+G7sSB0aGF5IMSR4buVaSBj4bunYSBsb2cob2RkKSBj4bunYSB4w6FjIHN14bqldCB0aGFpIGRp4buFbiB0aeG6v24ga2hpIEFGQyB0xINuZyAxIMSRxqFuIHbhu4sgdsOgIGtoaSBz4butIGThu6VuZyBwaMOhYyDEkeG7kyBQUE9TLg0KDQpN4buZdCBjw6FjaCDEkcahbiBnaeG6o24sIHRhIGPDsyB0aOG7gyB4w6l0IGThuqV1IGPhu6dhIGPDoWMgaOG7hyBz4buRIGjhu5NpIHF1eSBuw6B5IMSR4buDIGjDrG5oIGR1bmcgduG7gSBoaeG7h3Ug4bupbmcgbcOgIGPDoWMgYmnhur9uIGfDonkgcmEgY2hvIHjDoWMgc3XhuqV0IGPhu6dhIHRoYWkgZGnhu4VuIHRp4bq/bi4gTeG7mXQgaOG7hyBz4buRIGjhu5NpIHF1eSA+IDAgY2hvIHRo4bqleSBt4buRaSB0xrDGoW5nIHF1YW4gdGh14bqtbiAobMOgbSB0xINuZyksIG5nxrDhu6NjIGzhuqFpIG3hu5l0IGjhu4cgc+G7kSBo4buTaSBxdXkgPDAgY2hvIHRo4bqleSB0xrDGoW5nIHF1YW4gbmdo4buLY2ggKGzDoG0gZ2nhuqNtKS4NCg0KUHIoPnx6fCkgdHLDrG5oIGLDoHkgZ2nDoSB0cuG7iyBwIGPhu6dhIGtp4buDbSDEkeG7i25oIFdhbGQsIG5o4bqxbSBwaOG7pyBuaOG6rW4gZ2nhuqMgdGh1eeG6v3QgdsO0IGhp4buHdSBsw6AgbeG7mXQgYmnhur9uIGtow7RuZyBnw6J5IHJhIGhp4buHdSDhu6luZyBuw6BvIGPhuqMgKGtow7RuZyBjw7MgbGnDqm4gaOG7hykgxJHhu5FpIHbhu5tpIHhhYyBzdeG6pXQgT1AgKGjhu4cgc+G7kSBo4buTaSBxdXkgPSAwKS4gDQoNClR1eSBuaGnDqm4sIHLhuqV0IGtow7MgxJHhu4MgdGjhu7FjIGhp4buHbiBzdXkgZGnhu4VuIHRo4buRbmcga8OqIHRoZW8gY8OhY2ggbsOgeSwgbsOqbiB0YSBz4bq9IHRoZW8gY29uIMSRxrDhu51uZyDGsOG7m2MgdMOtbmggbWFyZ2luYWwgZWZmZWN0cyAoaGnhu4d1IOG7qW5nIGPhuq1uIGJpw6puKSBjaG8gY8OhYyB54bq/dSB04buRLiANCg0KR2nhuqMgxJHhu4tuaCB0YSBtdeG7kW4ga2jhuqNvIHPDoXQgaGnhu4d1IOG7qW5nIGPhu6dhIG3hu5l0IGJp4bq/biDEkeG7i25oIHTDrW5oIGPDsyAyIGLhuq1jIGdpw6EgdHLhu4sgKHBow6FjIMSR4buTIFBQT1MgaG/hurdjIEduUkgpLCBtw7QgaMOsbmggc+G6vSDGsOG7m2MgbMaw4bujbmcgxJHGsOG7o2MgMiBnacOhIHRy4buLIHjDoWMgc3XhuqV0IHRoYWkgZGnhu4VuIHRp4bq/biB0cnVuZyBiw6xuaCBjaG8gMiBuaMOzbSBuw6B5IGzDoCAkXG11X3tQUE9TfSQgdsOgICRcbXVfe0duUkh9JA0KDQpU4burIMSRw6J5LCB0YSBjw7MgdGjhu4MgxrDhu5tjIHTDrW5oIDMgbG/huqFpIG1hcmdpbmFsIGVmZmVjdHMgZ+G7k206DQoNCjEpIE1hcmdpbmFsIHJpc2sgZGlmZmVyZW5jZSAoUkQpDQoNClRy4buLIHPhu5EgUkQgxJFvIGzGsOG7nW5nIHRy4buxYyB0aeG6v3Agc+G7sSB0aGF5IMSR4buVaS9raMOhYyBiaeG7h3QvdMawxqFuZyBwaOG6o24gduG7gSB4w6FjIHN14bqldCBnaeG7r2EgUFBPUyB2w6AgcGjDoWMgxJHhu5MgdGhhbSBjaGnhur91DQoNCiQkUkQgPSBcbXVfe1BQT1N9IC0gIFxtdV97R25SSGFudH0kJA0KUkQgY2hvIGJp4bq/dCBraGkgZMO5bmcgcGjDoWMgxJHhu5MgUFBPUywgeMOhYyBzdeG6pXQgxJHhuqF0IHRoYXkgZGnhu4VuIHRp4bq/biBz4bq9IHRoYXkgxJHhu5VpIGJhbyBuaGnDqnUgc28gduG7m2kgcGjDoWMgxJHhu5MgdGhhbSBjaGnhur91LiBWw6wgYuG6o24gY2jhuqV0IGPhu6dhIFJEIGzDoCBoaeG7h3Ugc+G7kSBnaeG7r2EgMiB4w6FjIHN14bqldCwgbsOzIGNo4buJIGPDsyB0aOG7gyBkYW8gxJHhu5luZyB0cm9uZyBraG/huqNuZyAkWy0xLDFdJCwgUkQgPSAwIGNobyB0aOG6pXkga2jDtG5nIGPDsyBraMOhYyBiaeG7h3QgKHTDrW5oIHTGsMahbmcgxJHGsMahbmcpLCBSRCA8IDAgaG/hurdjID4gMCBjaG8gcGjDqXAgeMOhYyDEkeG7i25oIGhp4buHdSDhu6luZyBj4bunYSBwaMOhYyDEkeG7kyBuw6BvIGNhbyBoxqFuL3Ro4bqlcCBoxqFuLg0KDQpgYGB7cn0NCnJkID0gYXZnX2NvbXBhcmlzb25zKA0KICBsb2dfbW9kLA0KICB2YXJpYWJsZXMgPSAiUHJvdG9jb2wiKSU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKDEsMiw1LDYpKSU+JQ0KICBtdXRhdGUoY29udHJhc3QgPSAiUkQiKQ0KDQpyZCAlPiUga25pdHI6OmthYmxlKCkNCmBgYA0KDQpL4bq/dCBxdeG6oyBjaG8gdGjhuqV5OiB0aGVvIMaw4bubYyB0w61uaCB0cnVuZyBiw6xuaCwgbmjDs20gYuG7h25oIG5ow6JuIGTDuW5nIHBow6FjIMSR4buTIFBQT1MgY8OzIHjDoWMgc3XhuqV0IHRoYWkgZGnhu4VuIHRp4bq/biB0xINuZyAwLjE0OCAobsOzaSBjw6FjaCBraMOhYzsgdOG7tyBs4buHIHRoYWkgZGnhu4VuIHRp4bq/biB0xINuZyAxNC44JSkgc28gduG7m2kgcGjDoWMgxJHhu5MgR25SSF9hbnQsIHPhu7EgZ2lhIHTEg25nIG7DoHkgY8OzIMO9IG5naMSpYSB0aOG7kW5nIGvDqiAoa2hv4bqjbmcgdGluIGPhuq15IGtow7RuZyBjaOG7qWEgZ2nDoSB0cuG7iyAwLCBwID0gMC4wMzYpLg0KDQoyKSBNYXJnaW5hbCBPZGRzIHJhdGlvIChPUikNCg0KVHJvbmcgcGjhuqduIHRyw6puLCB0YSDEkcOjIGhp4buDdSB24buBIGLhuqNuIGNo4bqldCBj4bunYSBPZGRzIGzDoCBt4buZdCB04bu3IHPhu5EgZ2nhu69hIDIgeMOhYyBzdeG6pXQgdGjDoG5oIGPDtG5nL3Ro4bqldCBi4bqhaS4gT2RkcyByYXRpbyBsw6AgbeG7mXQgY8OhY2ggxJHhu4MgxJFvIGzGsOG7nW5nIHPhu7EgdMawxqFuZyBwaOG6o24gZ2nhu69hIDIgZ2nDoSB0cuG7iyBPZGRzIHTGsMahbmcg4bupbmcgduG7m2kgMiBi4bqtYyBnacOhIHRy4buLIGPhu6dhIGJp4bq/biBYICgyIHBow6FjIMSR4buTKSwgdGhlbyBjw7RuZyB0aOG7qWMgc2F1Og0KDQokJE9SID0gXGZyYWN7T2Rkc197UFBPU319e09kZHNfe0duUkhhfX0gPSBcZnJhY3tcbXVfe1BQT1N9LygxLVxtdV97UFBPU30pfXtcbXVfe0duUkhhfS8oMS1cbXVfe0duUkhhfSl9JCQNClbDrCBsw6AgMSB04bu3IHPhu5EsIE9SIGPDsyB0aOG7gyA+MSwgdsOgIGRhbyDEkeG7mW5nIHThu6sgMCDEkeG6v24gJCtcaW5mdHkkLiBHacOhIHRy4buLIE9SIDwgMSBjaG8gdGjhuqV5IGhp4buHdSDhu6luZyBj4bunYSBwaMOhYyDEkeG7kyBQUE9TIHRo4bqlcCBoxqFuIHNvIHbhu5tpIG5ow7NtIHRoYW0gY2hp4bq/dSwgbmfGsOG7o2MgbOG6oWkgT1IgPiAxIHbDoCBjw6BuZyBs4bubbiBjw6BuZyBjaG8gdGjhuqV5IHBow6FjIMSR4buTIFBQT1MgY8OzIGhp4buHdSBxdeG6oyBjYW8gaMahbi4gT1IgPSAxIGNobyB0aOG6pXkgMiBwaMOhYyDEkeG7kyBjw7MgaGnhu4d1IOG7qW5nIHTGsMahbmcgxJHGsMahbmcgbmhhdS4NCg0KMykgTWFyZ2luYWwgcmlzayByYXRpbyAoUlIpDQoNClJpc2sg4bufIMSRw6J5IHTGsMahbmcg4bupbmcgduG7m2kgw70gbmdoxKlhIHjDoWMgc3XhuqV0LCBraOG6oyBuxINuZywgdOG7tyBs4buHIHRow6BuaCBjw7RuZyAoZ2nDoSB0cuG7iyAkXG11JCBjaG8gbeG7l2kgcGjDoWMgxJHhu5MpLCByaXNrIHJhdGlvIMSRxqFuIGdp4bqjbiBsw6AgdOG7tyBz4buRIGdp4buvYSAyIHJpc2tzLg0KDQokJFJSID0gXGZyYWN7XG11X3tQUE9TfX17XG11X3tHblJIYX19ICQkDQpSUiDEkcaw4bujYyBkaeG7hW4gZ2nhuqNpIHTGsMahbmcgdOG7sSBuaMawIE9SLCBnacOhIHRy4buLIFJSPTEgY2hvIHRo4bqleSAyIHBow6FjIMSR4buTIGzDoCB0xrDGoW5nIMSRxrDGoW5nIG5oYXUsIGdpw6EgdHLhu4sgUlIgPiAxIGNobyB0aOG6pXkgcGjDoWMgxJHhu5MgUFBPUyBjw7MgaGnhu4d1IHF14bqjIGNhbyBoxqFuLCB2w6AgbmfGsOG7o2MgbOG6oWkgUlIgPCAxIGNobyB0aOG6pXkgcGjDoWMgxJHhu5MgR25SaGEgY8OzIGhp4buHdSBxdeG6oyBjYW8gaMahbi4NCg0KS+G6v3QgcXXhuqMgT1IgdsOgIFJSIMSRxrDhu6NjIHRyw6xuaCBiw6B5IHRyb25nIGLhuqNuZyBzYXU6DQoNCmBgYHtyfQ0Kb3IgPSBhdmdfY29tcGFyaXNvbnMoDQogIGxvZ19tb2QsDQogIHZhcmlhYmxlcyA9ICJQcm90b2NvbCIsDQogIHRyYW5zZm9ybV9wcmUgPSAibG5vcmF2ZyIsDQogIHRyYW5zZm9ybV9wb3N0ID0gImV4cCIpJT4lDQogIGRwbHlyOjpzZWxlY3QoLWMoMSwyLDg6MTApKSU+JQ0KICBtdXRhdGUoY29udHJhc3QgPSAiT1IiKQ0KDQpyciA9IGF2Z19jb21wYXJpc29ucygNCiAgbG9nX21vZCwNCiAgdmFyaWFibGVzID0gIlByb3RvY29sIiwNCiAgdHJhbnNmb3JtX3ByZSA9ICJsbnJhdGlvYXZnIiwNCiAgdHJhbnNmb3JtX3Bvc3QgPSBleHApJT4lZHBseXI6OnNlbGVjdCgtYygxLDIsODoxMCkpJT4lDQogICBtdXRhdGUoY29udHJhc3QgPSAiUlIiKQ0KDQpyYmluZChvcixycikgJT4lIGtuaXRyOjprYWJsZSgpDQpgYGANCg0KVGhlbyBr4bq/dCBxdeG6oyBuw6B5LCBj4bqjIGdpw6EgdHLhu4sgT1IgdsOgIFJSIMSR4buBdSBjaG8gdGjhuqV5IG3hu5l0IGhp4buHdSBxdeG6oyDGsHUgdGjhur8gaMahbiBj4bunYSBwaMOhYyDEkeG7kyBQUE9TIHNvIHbhu5tpIEduUkhhIMSR4buRaSB24bubaSBraOG6oyBuxINuZyDEkeG6oXQgxJHGsOG7o2MgdGhhaSBkaeG7hW4gdGnhur9uLiBT4buxIGNow6puaCBs4buHY2ggduG7gSBPZGRzIHbDoCB4w6FjIHN14bqldCB0aMOgbmggY8O0bmcgZ2nhu69hIDIgcGjDoWMgxJHhu5MgbMOgIGPDsyDDvSBuZ2jEqWEgdGjhu5FuZyBrw6ouDQoNClRhIGPFqW5nIGPDsyB0aOG7gyB0w61uaCBSRCwgT1IgdsOgIFJSIGNobyBjw6FjIGJp4bq/biDEkeG7i25oIGzGsOG7o25nLCBsw7pjIG7DoHkgMiBi4bqtYyBzbyBzw6FuaCBsw6AgJFgtMSQgdsOgICRYKzEkLCBr4bq/dCBxdeG6oyBjaG8gYmnhur90IGhp4buHdSDhu6luZyBraGkgWCBnaWEgdMSDbmcgMSDEkcahbiB24buLLiBC4bqjbmcgc2F1IMSRw6J5IHRyw6xuaCBiw6B5IGdpw6EgdHLhu4sgUkQsIE9SIHbDoCBSUiBjaG8gQWdlLCBBRkMsIFRoaWNrbmVzcyB2w6AgY2hvIHJpw6puZyBt4buXaSBuaMOzbSBwaMOhYyDEkeG7ky4NCg0KYGBge3J9DQpyZCA9IGF2Z19jb21wYXJpc29ucygNCiAgbG9nX21vZCwNCiAgdmFyaWFibGVzID0gbGlzdChBZ2UgPSAxLA0KICAgICAgICAgICAgICAgICAgIEFGQyA9IDEsIA0KICAgICAgICAgICAgICAgICAgIFRoaWNrbmVzcyA9IDEpLA0KICBieSA9ICJQcm90b2NvbCIpJT4lDQogIGRwbHlyOjpzZWxlY3QoLWMoMSw3LDExOjEzKSklPiUNCiAgbXV0YXRlKGNvbnRyYXN0ID0gIlJEIikNCg0KcmQgJT4lIGtuaXRyOjprYWJsZSgpDQoNCm9yID0gYXZnX2NvbXBhcmlzb25zKA0KICBsb2dfbW9kLA0KICB2YXJpYWJsZXMgPSBsaXN0KEFnZSA9IDEsDQogICAgICAgICAgICAgICAgICAgQUZDID0gMSwgDQogICAgICAgICAgICAgICAgICAgVGhpY2tuZXNzID0gMSksDQogIGJ5ID0gIlByb3RvY29sIiwNCiAgdHJhbnNmb3JtX3ByZSA9ICJsbm9yYXZnIiwNCiAgdHJhbnNmb3JtX3Bvc3QgPSAiZXhwIiklPiUNCiAgZHBseXI6OnNlbGVjdCgtYygxKSklPiUNCiAgbXV0YXRlKGNvbnRyYXN0ID0gIk9SIikNCg0KcnIgPSBhdmdfY29tcGFyaXNvbnMoDQogIGxvZ19tb2QsDQogIHZhcmlhYmxlcyA9IGxpc3QoQWdlID0gMSwNCiAgICAgICAgICAgICAgICAgICBBRkMgPSAxLCANCiAgICAgICAgICAgICAgICAgICBUaGlja25lc3MgPSAxKSwNCiAgYnkgPSAiUHJvdG9jb2wiLA0KICB0cmFuc2Zvcm1fcHJlID0gImxucmF0aW9hdmciLA0KICB0cmFuc2Zvcm1fcG9zdCA9IGV4cCklPiUNCiAgZHBseXI6OnNlbGVjdCgtYygxLDk6MTEpKSU+JQ0KICAgbXV0YXRlKGNvbnRyYXN0ID0gIlJSIikNCg0KcmJpbmQob3IscnIpICU+JSBrbml0cjo6a2FibGUoKQ0KYGBgDQpUaGVvIGvhur90IHF14bqjIG7DoHksIHRhIHRo4bqleSBBRkMgY8OzIHTGsMahbmcgcXVhbiB0aHXhuq1uIChPUiA+IDEgdsOgIFJSID4gMSkgduG7m2kgeMOhYyBzdeG6pXQgdGhhaSBkaeG7hW4gdGnhur9uLCBuaMawbmcgY2jhu4kgY8OzIMO9IG5naMSpYSB0cm9uZyBuaMOzbSBwaMOhYyDEkeG7kyBHblJIYTsgQWdlIGPDsyB0xrDGoW5nIHF1YW4gbmdo4buLY2ggw70gbmdoxKlhIHbhu5tpIGto4bqjIG7Eg25nIMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v24gY2hvIGPhuqMgMiBwaMOhYyDEkeG7kyAoT1IgPCAxIHbDoCBSUiA8IDEpLCB0cm9uZyBraGkga2jDtG5nIGPDsyBsacOqbiBo4buHIMO9IG5naMSpYSBuw6BvIGdp4buvYSBUaGlja25lc3MgdsOgIGto4bqjIG7Eg25nIMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v24uDQoNClRo4buxYyByYSwgbmjhu69uZyB0cuG7iyBz4buRIG3DoCB0YSB24burYSDGsOG7m2MgbMaw4bujbmcgYmFvIGfhu5NtIFJELCBPUiBob+G6t2MgUlIgY2jhu4kgY8OzIMO9IG5naMSpYSB0w7NtIHThuq90IChhYnN0cmFjdGlvbikgdsOgIGNobyBiaeG6v3QgdGjDtG5nIHRpbiB24buBIGhp4buHdSDhu6luZyDhu58gbeG7qWMgxJHhu5kgcXXhuqduIHRo4buDLiBIaeG7h24gbmF5LCBjw7MgbeG7mXQgc+G7kSB0w6FjIGdp4bqjIGtodXnhur9uIGPDoW8gduG7gSBuaMaw4bujYyDEkWnhu4NtIGPhu6dhIHZp4buHYyBjaOG7iSBiw6FvIGPDoW8gaGnhu4d1IOG7qW5nIGNobyBiaeG6v24gbmjhu4sgcGjDom4gYuG6sW5nIG3hu5l0IHRy4buLIHPhu5EgZHV5IG5o4bqldCwgdsOgIGzhu6NpIMOtY2ggY+G7p2Egdmnhu4djIGN1bmcgY+G6pXAgdGjDtG5nIHRpbiBjaGkgdGnhur90IGjGoW4gduG7gSB0b8OgbiB0aOG7gyDEkeG6t2MgdMOtbmggcGjDom4gcGjhu5FpIGPhu6dhIGhp4buHdSDhu6luZyB0cm9uZyBt4bqrdSBraOG6o28gc8OhdC4NCg0KQmnhu4N1IMSR4buTIHNhdSDEkcOieSBjaG8gcGjDqXAgxJHhu5FpIGNoaeG6v3UgcGjDom4gcGjhu5FpIHRvw6BuIHRo4buDIGPhu6dhIHjDoWMgc3XhuqV0IMSR4bqhdCB0aGFpIGRp4buFbiB0aeG6v24gY+G7mW5nIGThu5NuIHRyb25nIDEwNyBjw6EgdGjhu4MgZMO5bmcgcGjDoWMgxJHhu5MgR25SSGEgdsOgIDk5IGPDoSB0aOG7gyBkw7luZyBwaMOhYyDEkeG7kyBQUE9TLg0KDQpgYGB7cn0NCmVmZnMgPSBjb21wYXJpc29ucyhsb2dfbW9kLA0KICAgICAgICAgICAgICAgICAgIHZhcmlhYmxlcyA9ICJQcm90b2NvbCIsIA0KICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBkYXRhZ3JpZChncmlkX3R5cGUgPSAnY291bnRlcmZhY3R1YWwnKSkNCg0KZWZmcyAlPiUgZ2dwbG90KCkgKw0KICBnZW9tX2RlbnNpdHkoYWVzKHggPSBwcmVkaWN0ZWQsIGZpbGwgPSBQcm90b2NvbCksIGFscGhhID0gMC41KSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IG1lYW4oZWZmcyRwcmVkaWN0ZWRfbG8pLCBjb2xvciA9ICJibHVlIiwgDQogICAgICAgICAgICAgbGluZXR5cGUgPSAyLCBzaXplID0gMSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKGVmZnMkcHJlZGljdGVkX2hpKSwgY29sb3IgPSAicmVkIiwgDQogICAgICAgICAgICAgbGluZXR5cGUgPSAyLCBzaXplID0gMSkgKw0KICBsYWJzKHggPSAiUHJvYmFiaWxpdHkgb2YgT1AiLCANCiAgICAgICB0aXRsZSA9ICJVbml0IGxldmVsIGNvbnRyYXN0IiwNCiAgICAgICBmaWxsID0gIlByb3RvY29sIikrDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSksIGJyZWFrcyA9IHNlcSgwLDEsMC4xKSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IHBhbHMpKw0KICB0aGVtZV9idygxMCkNCmBgYA0KQ2jDuiB0aMOtY2g6IEjDrG5oIHRyw6puIHRyw6xuaCBiw6B5IDIgYmnhu4N1IMSR4buTIG3huq10IMSR4buZIHBow6JuIHBo4buRaSBjaG8gcGjDqXAgc28gc8OhbmggxJHhurdjIMSRaeG7hW0gcGjDom4gcGjhu5FpIGPhu6dhIHjDoWMgc3XhuqV0IHRoYWkgZGnhu4VuIHRp4bq/biAoVHLhu6VjIFgpIGdp4buvYSAyIHBow6FjIMSR4buTOiBHblJIYSAobcOgdSB4YW5oKSB2w6AgUFBPUyAobcOgdSBo4buTbmcpLiAyIMSRxrDhu51uZyB0aOG6s25nIGtow7RuZyBsacOqbiB04bulYyB0xrDGoW5nIOG7qW5nIHbhu5tpIGdpw6EgdHLhu4sgdHJ1bmcgduG7iyBj4bunYSB4w6FjIHN14bqldCBuw6B5IOG7nyBt4buXaSBuaMOzbS4NCg0KSMOsbmgg4bqjbmggY2hvIHRo4bqleSBjw7Mgc+G7sSB0xrDGoW5nIHBo4bqjbiByw7UgbsOpdCBnaeG7r2EgMiBwaMOhYyDEkeG7kywgduG7m2kgxrB1IHRo4bq/IG5naGnDqm5nIHbhu4EgcGjDoWMgxJHhu5MgUFBPUy4NCg0KTeG7mXQgYmnhu4N1IMSR4buTIGtow6FjIGNobyBwaMOpcCBow6xuaCBkdW5nIHbhu4EgY8OhbiBjw6JuIGNow6puaCBs4buHY2ggY+G7p2EgaGnhu4d1IHF14bqjIGdp4buvYSAyIHBow6FjIMSR4buTLCDEkeG6v24gY+G6pXAgxJHhu5kgdOG7q25nIGPDoSB0aOG7gy4NCg0KYGBge3J9DQplZmZzICU+JSBnZ3Bsb3QoYWVzKHg9cHJlZGljdGVkX2xvLCB5PXByZWRpY3RlZF9oaSkpKw0KICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikgKw0KICBnZW9tX3BvaW50KGFlcyh4PXByZWRpY3RlZF9sbywgeT1wcmVkaWN0ZWRfaGksDQogICAgICAgICAgICAgICAgIGNvbCA9IHByZWRpY3RlZF9oaSkpKw0KICBjb29yZF9maXhlZCgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxKSkrDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSkpKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoJ09QIHByb2InKSsNCiAgbGFicyh4ID0gIlByb2JhYmlsaXR5IG9mIE9QIGJ5IEduUkhfYW50IiwgeSA9ICJQcm9iYWJpbGl0eSBvZiBPUCBieSBQUE9TIikrDQogIHRoZW1lX2J3KCkNCg0KYGBgDQpDaMO6IHRow61jaDogxJDDonkgbMOgIG3hu5l0IGJp4buDdSDEkeG7kyB0w6FuIHjhuqEgY2hvIHBow6lwIGtp4buDbSB0cmEgbeG7qWMgxJHhu5kgdMawxqFuZyBwaOG6o24gLyBjaMOqbmggbOG7h2NoIGdp4buvYSAyIHBow6FjIMSR4buTIHbhu4EgeMOhYyBzdeG6pXQgdGhhaSBkaeG7hW4gdGnhur9uLiBUcuG7pWMgWCB2w6AgWSB0csOsbmggYsOgeSAyIHRoYW5nIMSRbyB4w6FjIHN14bqldCB04burIDAtMSBjaG8gbeG7l2kgcGjDoWMgxJHhu5MuIE3hu5dpIGNo4bqlbSB0csOybiBiaeG7g3UgdGjhu4sgY2hvIG3hu5l0IMSRxqFuIHbhu4sga2jhuqNvIHPDoXQgKGPDoSB0aOG7gyBi4buHbmggbmjDom4pLCDEkcaw4budbmcgcGjDom4gZ2nDoWMgY+G7p2EgYmnhu4N1IMSR4buTIGJp4buDdSB0aOG7iyBjaG8gZ2nhuqMgdGh1eeG6v3QgbMOgIGhhaSBwaMOhYyDEkeG7kyB0xrDGoW5nIMSRxrDGoW5nIGhvw6BuIHRvw6BuIHbhu5tpIG5oYXUuIE5o4buvbmcgxJFp4buDbSB0csOybiBu4bqxbSBiw6puIGTGsOG7m2kgxJHGsOG7nW5nIHBow6JuIGdpw6FjIG7DoHkgY8OzIGhp4buHdSBxdeG6oyBHblJIX2FudCDGsHUgdGjhur8gaMahbiwgdHLDoWkgbOG6oWkgduG7m2kgbmjhu69uZyDEkWnhu4NtIG7hurFtIGLDqm4gdHLDqm4gxJHGsOG7nW5nIG7DoHksIHBow6FjIMSR4buTIFBQT1MgY8OzIGhp4buHdSDhu6luZyDGsHUgdGjhur8gaMahbi4gTmjhu69uZyDEkWnhu4NtIG7hurFtIHLhuqV0IGfhuqduIHbDoCBk4buNYyB0aGVvIMSRxrDhu51uZyBuw6B5IGPDsyBoaeG7h3UgcXXhuqMgdMawxqFuZyDEkcawxqFuZyBnaeG7r2EgMiBwaMOhYyDEkeG7ky4NCg0KQ8OhYyBiaeG7g3UgxJHhu5MgdGnhur9wIHRoZW8gdHLDrG5oIGLDoHkgduG7gSBt4buRaSBsacOqbiBo4buHIGdp4buvYSBUdeG7lWksIEFGQyB2w6AgVGhpY2tuZXNzIHbhu5tpIHjDoWMgc3XhuqV0IHRoYWkgZGnhu4VuIHRp4bq/biwgcmnDqm5nIGNobyBt4buXaSBuaMOzbSBwaMOhYyDEkeG7kzoNCg0KYGBge3J9DQpwcmVkcyA9IHByZWRpY3Rpb25zKG1vZGVsID0gbG9nX21vZCwNCiAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IGRhdGFncmlkKEFnZSA9IHNlcSgyMCw0MCw1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb3RvY29sID0gYygiR25SSGEiLCJQUE9TIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3R5cGUgPSAiY291bnRlcmZhY3R1YWwiKSkNCg0KcHJlZHMlPiVnZ3Bsb3QoYWVzKHggPSBBZ2UsDQogICAgICAgICAgICAgICAgICAgeSA9IGVzdGltYXRlKSkgKw0KICBzdGF0X2hhbGZleWUoYWxwaGEgPSAwLjUsIA0KICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjc1LCAwLjk1KSwNCiAgICAgICAgICAgICAgIHBvaW50X2ludGVydmFsID0gJ21lZGlhbl9xaScsDQogICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpKw0KICBzdGF0X2xpbmVyaWJib24oYWVzKHkgPSBlc3RpbWF0ZSwgZmlsbCA9IFByb3RvY29sKSwgDQogICAgICAgICAgICAgICAgICAud2lkdGggPSBjKC45NSwgLjc1LCAuNTApLCANCiAgICAgICAgICAgICAgICAgIGFscGhhID0gMS81LA0KICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArDQogIGxhYnMoeT0iT1AgcHJvYmFiaWxpdHkiLCB4ID0gIkFnZSIpICsgDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDIwLDQ1KSwgYnJlYWtzID0gc2VxKDIwLDQwLDUpKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxKSkrDQogIGZhY2V0X3dyYXAoflByb3RvY29sLCBuY29sID0gMikrDQogIHRoZW1lX2J3KDEwKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAxLCBoanVzdD0xKSkgKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvciA9ICJibGFjayIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siKSkNCg0KYGBgDQoNCmBgYHtyfQ0KcHJlZHMgPSBwcmVkaWN0aW9ucyhtb2RlbCA9IGxvZ19tb2QsDQogICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBkYXRhZ3JpZChBRkMgPSBzZXEoMSwzMCw1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb3RvY29sID0gYygiR25SSGEiLCJQUE9TIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3R5cGUgPSAiY291bnRlcmZhY3R1YWwiKSkNCg0KcHJlZHMlPiVnZ3Bsb3QoYWVzKHggPSBBRkMsDQogICAgICAgICAgICAgICAgICAgeSA9IGVzdGltYXRlKSkgKw0KICBzdGF0X2hhbGZleWUoYWxwaGEgPSAwLjUsIA0KICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjc1LCAwLjk1KSwNCiAgICAgICAgICAgICAgIHBvaW50X2ludGVydmFsID0gJ21lZGlhbl9xaScsDQogICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpKw0KICBzdGF0X2xpbmVyaWJib24oYWVzKHkgPSBlc3RpbWF0ZSwgZmlsbCA9IFByb3RvY29sKSwgDQogICAgICAgICAgICAgICAgICAud2lkdGggPSBjKC45NSwgLjc1LCAuNTApLCANCiAgICAgICAgICAgICAgICAgIGFscGhhID0gMS81LA0KICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArDQogIGxhYnMoeT0iT1AgcHJvYmFiaWxpdHkiLCB4ID0gIkFGQyIpICsgDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsMzEpLCBicmVha3MgPSBzZXEoMCwzMCw1KSkrDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSkpKw0KICBmYWNldF93cmFwKH5Qcm90b2NvbCwgbmNvbCA9IDIpKw0KICB0aGVtZV9idygxMCkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgaGp1c3Q9MSkpICsNCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIikpDQpgYGANCg0KYGBge3J9DQpwcmVkcyA9IHByZWRpY3Rpb25zKG1vZGVsID0gbG9nX21vZCwNCiAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IGRhdGFncmlkKFRoaWNrbmVzcyA9IHNlcSg4LDIwLDQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvdG9jb2wgPSBjKCJHblJIYSIsIlBQT1MiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfdHlwZSA9ICJjb3VudGVyZmFjdHVhbCIpKQ0KDQpwcmVkcyU+JWdncGxvdChhZXMoeCA9IFRoaWNrbmVzcywNCiAgICAgICAgICAgICAgICAgICB5ID0gZXN0aW1hdGUpKSArDQogIHN0YXRfaGFsZmV5ZShhbHBoYSA9IDAuNSwgDQogICAgICAgICAgICAgICAud2lkdGggPSBjKDAuNzUsIDAuOTUpLA0KICAgICAgICAgICAgICAgcG9pbnRfaW50ZXJ2YWwgPSAnbWVkaWFuX3FpJywNCiAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikrDQogIHN0YXRfbGluZXJpYmJvbihhZXMoeSA9IGVzdGltYXRlLCBmaWxsID0gUHJvdG9jb2wpLCANCiAgICAgICAgICAgICAgICAgIC53aWR0aCA9IGMoLjk1LCAuNzUsIC41MCksIA0KICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLzUsDQogICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpICsNCiAgbGFicyh5PSJPUCBwcm9iYWJpbGl0eSIsIHggPSAiRW5kb21ldHJpYWwgdGhpY2tuZXNzIikgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoNywyMiksIGJyZWFrcyA9c2VxKDgsMjAsNCkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEpKSsNCiAgZmFjZXRfd3JhcCh+UHJvdG9jb2wsIG5jb2wgPSAyKSsNCiAgdGhlbWVfYncoMTApKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDEsIGhqdXN0PTEpKSArDQogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIiksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvciA9ICJibGFjayIpKQ0KYGBgDQoNCiMgQsaw4bubYyAyQjogTcO0IGjDrG5oIGjhu5NpIHF1eSBCaW5vbWlhbCBjaG8gdOG7tyBs4buHIE9QL3Thu5VuZyBz4buRIHBow7RpDQoNClRyb25nIHBo4bqnbiB0aeG6v3AgdGhlbywgdGEgc+G6vSBwaMOibiB0w61jaCBsb+G6oWkga+G6v3QgcXXhuqMgdGjhu6kgaGFpOiB04bu3IGzhu4cgdGhhaSBkaeG7hW4gdGnhur9uIHRyw6puIHThu5VuZyBz4buRIHBow7RpIMSRw6MgY2h1eeG7g24gKGJp4bq/biBPUF9jdW0pLg0KDQpNw7QgaMOsbmggxJHGsOG7o2MgZOG7sW5nIGLhurFuZyB0aMawIHZp4buHbiBnYW1sc3MgduG7m2kgY8O6IHBow6FwIGdp4buRbmcgbmjGsCBtw7QgaMOsbmggR0xNIEJpbm9taWFsIHRyb25nIGNoxrDGoW5nIHRyxrDhu5tjLiBDw7RuZyB0aOG7qWMgY+G7p2EgbcO0IGjDrG5oIG5oxrAgc2F1OiAiY2JpbmQoT1BfY3VtLCBuX0VULU9QX2N1bSkgfiBQcm90b2NvbCAqIEFGQyArIFRoaWNrbmVzcyArIEFnZSIgKE5o4bqvYyBs4bqhaTogbcO0IGjDrG5oIEdMTSBCaW5vbWlhbCB04buVbmcgcXXDoXQgY+G6p24gMiBiaeG6v24g4bufIHbhu4sgdHLDrSBr4bq/dCBxdeG6ozogc+G7kSBr4bq/dCBxdeG6oyB0aMOgbmggY8O0bmcgbMOgIGJp4bq/biBPUF9jdW0sIHbDoCBz4buRIGvhur90IHF14bqjIHRo4bqldCBi4bqhaSwgbMOgIGhp4buHdSBz4buRIGdp4buvYSBz4buRIHBow7RpIGNodXnhu4NuIHbDoCBz4buRIHRoYWkpDQoNCnTDuXkgY2jhu4luaCBmYW1pbHkgPSBCSShtdS5saW5rID0gImxvZ2l0IikgdMawxqFuZyDhu6luZyB24bubaSBwaMOibiBwaOG7kWkgQmlub21pYWwgduG7m2kgaMOgbSBsacOqbiBr4bq/dCBsb2dpdCBjaG8gdGhhbSBz4buRICRcbXUkDQoNCk7hu5lpIGR1bmcgY+G7p2EgbcO0IGjDrG5oIG7DoHkgbmjGsCBzYXU6DQoNCmBgYHtyfQ0KYmlfbW9kID0gZ2FtbHNzKGNiaW5kKE9QX2N1bSwgbl9FVC1PUF9jdW0pIH4gDQogICAgICAgICAgICAgICAgICBQcm90b2NvbCAqIEFGQyArIFRoaWNrbmVzcyArIEFnZSwNCiAgICAgICAgICAgICAgICBkYXRhID0gZGYsDQogICAgICAgICAgICAgICAgZmFtaWx5ID0gQkkobXUubGluayA9ICJsb2dpdCIpKQ0KDQpzdW1tYXJ5KGJpX21vZCkNCmBgYA0KDQpDw6FjaCB0aOG7qWMgZGnhu4VuIGdp4bqjaSBtw7QgaMOsbmggbsOgeSBob8OgbiB0b8OgbiBnaeG7kW5nIG5oxrAgbcO0IGjDrG5oIGxvZ2lzdGljIOG7nyB0csOqbiBuw6puIHRhIGtow7RuZyBj4bqnbiBuaOG6r2MgbOG6oWkg4bufIMSRw6J5LiBUYSBz4bq9IMSRaSB0aOG6s25nIMSR4bq/biBjw7RuZyDEkW/huqFuIMaw4bubYyB0w61uaCAzIHRy4buLIHPhu5EgbWFyZ2luYWwgZWZmZWN0cyBjaG8gcGjDoWMgxJHhu5MgUFBPUyB04burIG3DtCBow6xuaCBuw6B5Og0KDQpgYGB7cn0NCmRyID0gYXZnX2NvbXBhcmlzb25zKA0KICBiaV9tb2QsDQogIHdoYXQgPSAibXUiLA0KICB2YXJpYWJsZXMgPSAiUHJvdG9jb2wiKSU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKDEsMiw1LDYpKSU+JQ0KICBtdXRhdGUoY29udHJhc3QgPSAiRFIiKQ0KDQpvciA9IGF2Z19jb21wYXJpc29ucygNCiAgYmlfbW9kLA0KICB3aGF0ID0gIm11IiwNCiAgdmFyaWFibGVzID0gIlByb3RvY29sIiwNCiAgdHJhbnNmb3JtX3ByZSA9ICJsbm9yYXZnIiwNCiAgdHJhbnNmb3JtX3Bvc3QgPSAiZXhwIiklPiUNCiAgZHBseXI6OnNlbGVjdCgtYygxLDIsODoxMCkpJT4lDQogIG11dGF0ZShjb250cmFzdCA9ICJPUiIpDQoNCnJyID0gYXZnX2NvbXBhcmlzb25zKA0KICBiaV9tb2QsDQogIHdoYXQgPSAibXUiLA0KICB2YXJpYWJsZXMgPSAiUHJvdG9jb2wiLA0KICB0cmFuc2Zvcm1fcHJlID0gImxucmF0aW9hdmciLA0KICB0cmFuc2Zvcm1fcG9zdCA9IGV4cCklPiVkcGx5cjo6c2VsZWN0KC1jKDEsMiw4OjEwKSklPiUNCiAgIG11dGF0ZShjb250cmFzdCA9ICJSUiIpDQoNCnJiaW5kKGRyLCBvcixycikgJT4lIGtuaXRyOjprYWJsZSgpDQpgYGANClRoZW8ga+G6v3QgcXXhuqMgbsOgeSwgY8OzIGxpw6puIGjhu4cgw70gbmdoxKlhIGdp4buvYSBwaMOhYyDEkeG7kyBQUE9TIHbDoCBz4buxIGdpYSB0xINuZyBj4bunYSB04bu3IGzhu4cgdGhhaSBkaeG7hW4gdGnhur9uIGPhu5luZyBk4buTbi4gQ+G7pSB0aOG7gyBuaMOzbSBwaMOhYyDEkeG7kyBQUE9TIGPDsyB04bu3IGzhu4cgdGhhaSBkaeG7hW4gdGnhur9uIGNhbyBoxqFuIHRydW5nIGLDrG5oIDguMzclIChEUiA9IDAuMDgzNywgS1RDOTUlOiAwLjAwMiAtIDAuMTY1LCBwPTAuMDQpLiBU4bu3IHPhu5EgT2RkcyAoT1IpIHbDoCB04bu3IHPhu5Egbmd1eSBjxqEgKFJSKSBs4bqnbiBsxrDhu6N0IGzDoCAxLjQ0IHbDoCAxLjI3IMSR4buBdSBjYW8gaMahbiAxIGNobyB0aOG6pXkgaGnhu4d1IHF14bqjIMawdSB0aOG6vyBoxqFuIGPhu6dhIHBow6FjIMSR4buTIFBQT1MsIGPhuqMgaGFpIMSR4buBdSBjw7Mgw70gbmdoxKlhIHRo4buRbmcga8OqLg0KDQpUYSB0aOG7sWMgaGnhu4duIG3DtCB04bqjIHBow6JuIHBo4buRaSB0b8OgbiB0aOG7gyBj4bunYSBoaeG7h3Ug4bupbmcgbsOgeSBxdWEgaGFpIGJp4buDdSDEkeG7kyBzYXU6DQoNCmBgYHtyfQ0KZWZmcyA9IGNvbXBhcmlzb25zKGJpX21vZCwNCiAgICAgICAgICAgICAgICAgICB3aGF0ID0gIm11IiwNCiAgICAgICAgICAgICAgICAgICB2YXJpYWJsZXMgPSAiUHJvdG9jb2wiLCANCiAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gZGF0YWdyaWQoZ3JpZF90eXBlID0gJ2NvdW50ZXJmYWN0dWFsJykpDQoNCmVmZnMgJT4lIGdncGxvdCgpICsNCiAgZ2VvbV9kZW5zaXR5KGFlcyh4ID0gcHJlZGljdGVkLCBmaWxsID0gUHJvdG9jb2wpLCBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBtZWFuKGVmZnMkcHJlZGljdGVkX2xvKSwgY29sb3IgPSAiYmx1ZSIsIA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwgc2l6ZSA9IDEpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbihlZmZzJHByZWRpY3RlZF9oaSksIGNvbG9yID0gInJlZCIsIA0KICAgICAgICAgICAgIGxpbmV0eXBlID0gMiwgc2l6ZSA9IDEpICsNCiAgbGFicyh4ID0gIlByb2JhYmlsaXR5IG9mIE9QIiwgDQogICAgICAgdGl0bGUgPSAiVW5pdCBsZXZlbCBjb250cmFzdCIsDQogICAgICAgZmlsbCA9ICJwcm90b2NvbCIpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEpLCBicmVha3MgPSBzZXEoMCwxLDAuMSkpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxzKSsNCiAgdGhlbWVfYncoMTApDQpgYGANCkjDrG5oIOG6o25oIG7DoHkgY2hvIHRo4bqleSBt4bq3YyBkw7kgcGjhuqduIHRyw7luZyBs4bq3cCBnaeG7r2EgcGjDom4gcGjhu5FpIGPhu6dhIHjDoWMgc3XhuqV0IHRoYWkgZGnhu4VuIHRp4bq/biDhu58gMiBwaMOhYyDEkeG7kyBsw6Aga2jDoSBjYW8sIHbhuqtuIGPDsyBt4buZdCBi4buZIHBo4bqtbiBjw6EgdGjhu4MgY2hvIHRo4bqleSBoaeG7h3UgcXXhuqMgxrB1IHRo4bq/IGjGoW4gY+G7p2EgcGjDoWMgxJHhu5MgUFBPUywgdsOgIGdpw6EgdHLhu4sgdHJ1bmcgduG7iyBj4bunYSAyIHBow6JuIHBo4buRaSBjw6FjaCBuaGF1IG3hu5l0IGtob+G6o25nIGfhuqduIGLhurFuZyAwLjEuDQoNClTGsMahbmcgdOG7sSwgdHLDqm4gYmnhu4N1IMSR4buTIHTGsMahbmcgaOG7o3AgduG7gSB4w6FjIHN14bqldCB0aGFpIGRp4buFbiB0aeG6v24g4bufIDIgcGjDoWMgxJHhu5MsIHBo4bqnbiBs4bubbiBjw6EgdGjhu4MgbuG6sW0g4bufIHbhu4sgdHLDrSBwaMOtYSB0csOqbiDEkcaw4budbmcgcGjDom4gZ2nDoWMsIGNobyB0aOG6pXkgc+G7sSBjaMOqbmggbOG7h2NoIHbhu4EgxrB1IHRo4bq/IG5naGnDqm5nIHbhu4EgcGjDrWEgcGjDoWMgxJHhu5MgUFBPUy4NCg0KYGBge3J9DQplZmZzICU+JSBnZ3Bsb3QoYWVzKHg9cHJlZGljdGVkX2xvLCB5PXByZWRpY3RlZF9oaSkpKw0KICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikgKw0KICBnZW9tX3BvaW50KGFlcyh4PXByZWRpY3RlZF9sbywgeT1wcmVkaWN0ZWRfaGksDQogICAgICAgICAgICAgICAgIGNvbCA9IHByZWRpY3RlZF9oaSkpKw0KICBjb29yZF9maXhlZCgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxKSkrDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSkpKw0KICBzY2FsZV9jb2xvcl92aXJpZGlzX2MoJ09QIHByb2InKSsNCiAgbGFicyh4ID0gIlByb2JhYmlsaXR5IG9mIE9QIGJ5IEduUkhfYW50IiwgeSA9ICJQcm9iYWJpbGl0eSBvZiBPUCBieSBQUE9TIikrDQogIHRoZW1lX2J3KCkNCmBgYA0KQ3Xhu5FpIGPDuW5nLCB0YSBjxaluZyBraOG6o28gc8OhdCB24buBIGxpw6puIGjhu4cgZ2nhu69hIFR14buVaSwgQUZDIHbDoCBUaGlja25lc3MgduG7m2kgdOG7tyBs4buHIHRoYWkgZGnhu4VuIHRp4bq/biBj4buZbmcgZOG7k24gdMO5eSB0aGVvIHBow6FjIMSR4buTLg0KDQpgYGB7cn0NCnByZWRzID0gcHJlZGljdGlvbnMobW9kZWwgPSBiaV9tb2QsDQogICAgICAgICAgICAgICAgICAgIHdoYXQgPSAibXUiLA0KICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gZGF0YWdyaWQoQWdlID0gc2VxKDIwLDQwLDUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvdG9jb2wgPSBjKCJHblJIYSIsIlBQT1MiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfdHlwZSA9ICJjb3VudGVyZmFjdHVhbCIpKQ0KDQpwcmVkcyU+JWdncGxvdChhZXMoeCA9IEFnZSwNCiAgICAgICAgICAgICAgICAgICB5ID0gZXN0aW1hdGUpKSArDQogIHN0YXRfaGFsZmV5ZShhbHBoYSA9IDAuNSwgDQogICAgICAgICAgICAgICAgICAgIC53aWR0aCA9IGMoMC43NSwgMC45NSksDQogICAgICAgICAgICAgICAgICAgIHBvaW50X2ludGVydmFsID0gJ21lZGlhbl9xaScsDQogICAgICAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikrDQogIHN0YXRfbGluZXJpYmJvbihhZXMoeSA9IGVzdGltYXRlLCBmaWxsID0gUHJvdG9jb2wpLCANCiAgICAgICAgICAgICAgICAgIC53aWR0aCA9IGMoLjk1LCAuNzUsIC41MCksIA0KICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLzUsDQogICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpICsNCiAgbGFicyh5PSJPUCBwcm9iYWJpbGl0eSIsIHggPSAiQWdlIikgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMjAsNDUpLCBicmVha3MgPSBzZXEoMjAsNDAsNSkpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDEpKSsNCiAgZmFjZXRfd3JhcCh+UHJvdG9jb2wsIG5jb2wgPSAyKSsNCiAgdGhlbWVfYncoMTApKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDEsIGhqdXN0PTEpKSArDQogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIiksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvciA9ICJibGFjayIpKQ0KDQpgYGANCg0KYGBge3J9DQpwcmVkcyA9IHByZWRpY3Rpb25zKG1vZGVsID0gYmlfbW9kLA0KICAgICAgICAgICAgICAgICAgICB3aGF0ID0gIm11IiwNCiAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IGRhdGFncmlkKEFGQyA9IHNlcSgxLDMwLDUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvdG9jb2wgPSBjKCJHblJIYSIsIlBQT1MiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyaWRfdHlwZSA9ICJjb3VudGVyZmFjdHVhbCIpKQ0KDQpwcmVkcyU+JWdncGxvdChhZXMoeCA9IEFGQywNCiAgICAgICAgICAgICAgICAgICB5ID0gZXN0aW1hdGUpKSArDQogIHN0YXRfaGFsZmV5ZShhbHBoYSA9IDAuNSwgDQogICAgICAgICAgICAgICAud2lkdGggPSBjKDAuNzUsIDAuOTUpLA0KICAgICAgICAgICAgICAgcG9pbnRfaW50ZXJ2YWwgPSAnbWVkaWFuX3FpJywNCiAgICAgICAgICAgICAgIHNob3cubGVnZW5kID0gRikrDQogIHN0YXRfbGluZXJpYmJvbihhZXMoeSA9IGVzdGltYXRlLCBmaWxsID0gUHJvdG9jb2wpLCANCiAgICAgICAgICAgICAgICAgIC53aWR0aCA9IGMoLjk1LCAuNzUsIC41MCksIA0KICAgICAgICAgICAgICAgICAgYWxwaGEgPSAxLzUsDQogICAgICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpICsNCiAgbGFicyh5PSJPUCBwcm9iYWJpbGl0eSIsIHggPSAiQUZDIikgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwzMSksIGJyZWFrcyA9IHNlcSgwLDMwLDUpKSsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwxKSkrDQogIGZhY2V0X3dyYXAoflByb3RvY29sLCBuY29sID0gMikrDQogIHRoZW1lX2J3KDEwKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAxLCBoanVzdD0xKSkgKw0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBjb2xvciA9ICJibGFjayIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siKSkNCg0KYGBgDQoNCmBgYHtyfQ0KcHJlZHMgPSBwcmVkaWN0aW9ucyhtb2RlbCA9IGJpX21vZCwNCiAgICAgICAgICAgICAgICAgICAgd2hhdCA9ICJtdSIsDQogICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBkYXRhZ3JpZChUaGlja25lc3MgPSBzZXEoOCwyMCw0KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb3RvY29sID0gYygiR25SSGEiLCJQUE9TIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncmlkX3R5cGUgPSAiY291bnRlcmZhY3R1YWwiKSkNCg0KcHJlZHMlPiVnZ3Bsb3QoYWVzKHggPSBUaGlja25lc3MsDQogICAgICAgICAgICAgICAgICAgeSA9IGVzdGltYXRlKSkgKw0KICBzdGF0X2hhbGZleWUoYWxwaGEgPSAwLjUsIA0KICAgICAgICAgICAgICAgLndpZHRoID0gYygwLjc1LCAwLjk1KSwNCiAgICAgICAgICAgICAgIHBvaW50X2ludGVydmFsID0gJ21lZGlhbl9xaScsDQogICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYpKw0KICBzdGF0X2xpbmVyaWJib24oYWVzKHkgPSBlc3RpbWF0ZSwgZmlsbCA9IFByb3RvY29sKSwgDQogICAgICAgICAgICAgICAgICAud2lkdGggPSBjKC45NSwgLjc1LCAuNTApLCANCiAgICAgICAgICAgICAgICAgIGFscGhhID0gMS81LA0KICAgICAgICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGKSArDQogIGxhYnMoeT0iT1AgcHJvYmFiaWxpdHlzIiwgeCA9ICJFbmRvbWV0cmlhbCB0aGlja25lc3MiKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYyg3LDIyKSwgYnJlYWtzID1zZXEoOCwyMCw0KSkrDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMSkpKw0KICBmYWNldF93cmFwKH5Qcm90b2NvbCwgbmNvbCA9IDIpKw0KICB0aGVtZV9idygxMCkrDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgaGp1c3Q9MSkpICsNCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgY29sb3IgPSAiYmxhY2siKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTAsIGNvbG9yID0gImJsYWNrIikpDQoNCmBgYA0KDQojIERp4buFbiBnaeG6o2kga+G6v3QgcXXhuqMgY+G7p2EgcGjDom4gdMOtY2gNCg0KUGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgbsOgeSBjaG8gcGjDqXAgcsO6dCByYSBt4buZdCBz4buRIGvhur90IGx14bqtbiBuaMawIHNhdTogDQoNCisgS2jhuqMgbsSDbmcgxJHhuqF0IMSRxrDhu6NjIHRoYWkgZGnhu4VuIHRp4bq/biBjw7MgdGjhu4MgxJHGsOG7o2Mga2jhuqNvIHPDoXQgZMaw4bubaSBuaGnhu4F1IGjDrG5oIHRo4bupYzogeMOhYyBzdeG6pXQgcXVhbiBzw6F0IMSRxrDhu6NjIG3hu5l0IGvhur90IHF14bqjIHRow6BuaCBjw7RuZyAoYmnhur9uIG5o4buLIGdpw6EgMCwxKSB0csOqbiBjw6EgdGjhu4MgYuG7h25oIG5ow6JuLCB4w6FjIHN14bqldCB0aMOgbmggY8O0bmcgY2hvIG3hu5dpIMSRxqFuIHbhu4sgbm/Do24gLSBoYXkgdOG7tyBs4buHIHRow6BuaCBjw7RuZyB0csOqbiB04buVbmcgc+G7kSBwaMO0aSDEkcaw4bujYyBjaHV54buBbi4gQ8OhY2ggdGjhu6ljIGto4bqjbyBzw6F0IGPDsyB0aOG7gyDhuqNuaCBoxrDhu59uZyDEkeG6v24ga+G6v3QgcXXhuqMgcGjDom4gdMOtY2ggdGjhu5FuZyBrw6ogKHRyb25nIHRyxrDhu51uZyBo4bujcCBoaeG7h24gdGjhu51pLCBj4bqjIDIgY8OhY2gga2jhuqNvIHPDoXQgxJHhu4F1IGNobyByYSB0aMO0bmcgxJFp4buHcCB0xrDGoW5nIMSR4buTbmcsIHR1eSBuaGnDqm4gY8OzIHPhu7Ega2jDoWMgYmnhu4d0IHbhu4EgZ2nDoSB0cuG7iyBPUiwgUlIgaG/hurdjIFJEKS4gDQoNCisgRMO5IGto4bqjbyBzw6F0IGTGsOG7m2kgaMOsbmggdGjhu6ljIG7DoG8sIHRow6wgxJHhu4F1IGThuqtuIHbhu4EgY8O0bmcgY+G7pSBjaHVuZyBsw6AgbcO0IGjDrG5oIEdMTSB24bubaSBwaMOibiBwaOG7kWkgQmlub21pYWwgduG7m2kgMiB0aGFtIHPhu5EgJG4kLCRcbXUkLiBNw7QgaMOsbmggbG9naXN0aWMgY+G7lSDEkWnhu4NuIGzDoCB0csaw4budbmcgaOG7o3AgxJHhurdjIGJp4buHdCBraGkgJG49MSQuIEPDoWNoIGRp4buFbiBnaeG6o2kgdsOgIHN1eSBsdeG6rW4gdGjhu5FuZyBrw6ogbMOgIG5oxrAgbmhhdSBjaG8gY+G6oyAyIG3DtCBow6xuaC4NCg0KKyBNw7QgaMOsbmggbG9naXN0aWMgKGhheSBHTE0gQmlub21pYWwpIGNobyBwaMOpcCBzdXkgbHXhuq1uIHRo4buRbmcga8OqIHbhu4EgbeG7kWkgbGnDqm4gaOG7hyBnaeG7r2EgMSBiaeG6v24gxJHhu5ljIGzhuq1wIHbDoCBt4buZdCBr4bq/dCBxdeG6oyB4w6FjIHN14bqldC4gVGEgY8OzIHRo4buDIMOhcCBk4bulbmcgbcO0IGjDrG5oIG7DoHkgY2hvIG5o4buvbmcga+G6v3QgY+G7pWMgbMOibSBzw6BuZyBuaOG7iyBwaMOibiwgaG/hurdjIHThu7cgbOG7hy4NCg==