1 Dẫn nhập

Trong bài trước, chúng ta đã làm quen với package JM cho phép dựng mô hình Joint model bằng phương pháp REML. Như đã hứa, Nhi sẽ giới thiệu tiếp một package khác (của cùng tác giả Rizoupoulos) cho phép dựng Joint model bằng phương pháp Bayes.

Mô hình liên hợp (Joint model) là một phương pháp thống kê cho phép hợp nhất hai bộ phận : sự biến thiên phụ thuộc thời gian của một biến định lượng (longitudinal response ; thí dụ marker trong 1 bệnh lý) và nguy cơ xảy ra một sự kiện theo thời gian (survival analysis), nhằm khảo sát mối liên hệ giữa chúng.

Để tóm tắt lại về nội dung mô hình Joint model, những thành phần sau đây được xét:

  1. Ti = Thời gian theo dõi đến khi sự kiện xảy ra cho một cá thể (i) xác định

  2. Ci = Thời gian cho đến khi cá thể (i) được loại khỏi vòng theo dõi

  3. Trạng thái sự kiện xảy ra là 1 biến nhị phân (0,1) được xác định bằng 1 hàm với quy luật: kết quả = 1 nếu Ti < hoặc = Ci, và =0 nếu Ti > Ci

  4. Bệnh sử cá thể (yi) là một vector chứa những giá trị của marker M theo thời gian cho một cá thể xác định. Mỗi phần tử yij trong vector này tương ứng với 1 giá trị của M cho cá thể i tại thời điểm tj (j là số lần khảo sát)

Thành phần longitudinal

Mục tiêu đầu tiên đó là ước tính giá trị Mu của yi cho một cá thể xác định, tại 1 thời điểm t xác định. Điều này có thể được thực hiện thông qua một mô hình GLM mở rộng. Nội dung của mô hình này gồm có :

  1. biến kết quả Y(it) được mô tả bằng 1 phân phối xác suất có điều kiện phụ thuộc vào 2 yếu tố: thời gian (t) và hiệu ứng ngẫu nhiên (bi). Vì đây là 1 mô hình GLM, ta có thể dùng một hàm link function G để liên kết yi(t) với design matrix và tham số hồi quy của mô hình.

  2. Vế bên phải của mô hình gồm có 2 phần : hiệu ứng chính (fixed effect) gồm design matrix (các biến độc lập, phụ thuộc thời gian) xi(t) + vector tham số hồi quy beta, và hiệu ứng ngẫu nhiên gồm design matrix Zi(t) với các yếu tố ngẫu nhiên và vector random effect bi.

  3. Hiệu ứng ngẫu nhiên (vector bi) được giả định có phân phối chuẩn với trung bình =zero và matrix cariance covariance D.

Thành phần survival

Mục tiêu tiếp theo, đó là ước tính nguy cơ xảy ra sự kiện (tử vong) tại thời điểm t xác định và cho một cá thể i xác định, biết rằng nguy cơ này phụ thuộc vào đồng thời : một tập hợp hiệp biến số (covariate) Wi và một vector bệnh sử H.

H ở đây chính là kết quả ước tính giá trị marker cho cá thể đó trong khoảng thời gian s từ 0 cho đến thời điểm t.

Hàm nguy cơ (hi) có thể được phân tích thành 1 hàm nguy cơ gốc h0 cho thời gian và một hàm exponential chứa lần lượt : vector tham số hồi quy Gamma tương ứng với tập hợp hiệp biến số Wi và một hàm f biểu thị cho hiệu ứng « liên hệ » giữa giá trị marker (Mu, ước tính qua mô hình Longitidinal hay mixed model), hiệu ứng ngẫu nhiên bi và vector tham số hồi quy Alpha, cho hiệu ứng quan hệ (association) giữa marker và covariates khác trong mô hình.

Hàm nguy cơ gốc h0 thường được ước lượng với B-spline (là một thủ thuật để mô hình hóa quan hệ phi tuyến tính trong mô hình)

Như vậy có thể thấy kết quả chính của mô hình liên hợp gồm 1 số vector tham số hồi ququan trọng y như alpha (hiệu ứng liên hợp, association, cho bộ phận survival), beta (hiệu ứng chính, fixed effect cho bộ phận longitudinal) , gamma (hiệu ứng độc lập, cho bộ phận survival).

Về cơ bản, package JMBayes có cấu trúc method giống như package JM (sử dụng REML). Phương pháp Bayes chỉ áp dụng trên joint model, nhưng 2 mô hình thành phần Longtudinal và Survival vẫn được dựng theo cách truyền thống từ bên trong hoặc bên ngoài (JM và JMbayes tương thích với mixed model object của package nlme (2014) hay MASS và Coxph model của packae survival (2014). Các hàm lme, coxph() và cú pháp của chúng được tích hợp sẵn trong JM và JM Bayes. Hàm jointModelBayes() sẽ dựng joint model.

Khi sử dụng cách tiếp cận theo trường phái Bayes, ta muốn xác định phân phối hậu nghiệm của toàn bộ các vector tham số trong joint model, bao gồm cả vector random effect bi.

Một cách đơn giản, Nhi chỉ có thể giải thích là tác giả Rizopoulos đã dùng những chuỗi Markov Monte Carlo (MCMC) với algorithm Metropolis Hastings. Những chuỗi MCMC này có thể được trích xuất sau đó để khảo sát.

Ngoài ra JPBayes có một số chứng năng nâng cao so với JM, nó cho phép mở rộng hiệu ứng liên hệ trong joint model với những tham số pho tuyến tính bổ sung, nó cũng cho phép làm Bayesian model Averaging (BMA) để kết hợp nhiều mô hình Joint model khác nhau cho việc tiên lượng.

Chi tiết kỹ thuật của package có thể tham khảo trong bài báo:

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.409.4524&rep=rep1&type=pdf

Tác giả cũng từng làm 1 webminar năm 2014:

https://www.youtube.com/watch?v=vqGpQmnup0Y

Bài thực hành này chỉ trình bày một thí dụ cơ bản với 1 covariate và Association effect đơn giản.

2 Minh họa: Prothrombin và Prednisone/ Bệnh Xơ gan

Thí dụ minh họa trong bài sử dụng dataset prothro. Đây là một nghiên cứu thử nghiệm lâm sàng trên 488 bệnh nhân Xơ gan. Có hai biến số outcome, một là maker prothrombin (một yếu tố đông máu), được khảo sát tại thời điểm zero, sau đó lặp lại mỗi tháng, hai là sự kiện tử vong. Mỗi bệnh nhân có thể được đo prothrombin tối đa đến 17 lần. Yếu tố can thiệp là 2 phương pháp điều trị bằng prednisone và placebo. Như bài trước, mục tiêu của chúng ta là khảo sát liên hệ giữa sự thay đổi của marker prothrombin theo thời gian và yếu tố điều trị đối với nguy cơ tử vong của bệnh nhân xơ gan.

Trước hết ta tải 1 số package,dataset aids nằm trong package JM

library(JMbayes) # package dựng Joint model bằng phương pháp Bayes
library(tidyverse) # data wrangling và ggplot
library(magrittr) # Toán tử pipe
library(ggkm) #Thăm dò Time event data

3 Thăm dò dữ liệu

Trước hết, chúng ta viết một vài đoạn code để mô tả dữ liệu bằng những con số. Một số câu hỏi có thể đặt ra :

  1. Cấu trúc dữ liệu ? Có 2 định dạng khác nhau của dataset, 1 cho longitudinal study và 1 cho survival study.

Ghi chú: id là mã số định danh cho bệnh nhân; pro là giá trị prothrombin, treat là phân nhóm điều trị, time là thời điểm mỗi visit tính từ bắt đầu nghiên cứu; Time là thời gian theo dõi tối đa đến khi bệnh nhân tử vong hoặc censored, start là mốc thời gian khởi đầu mỗi phân đoạn theo dõi, stop là mốc thời gian kết thúc mỗi phân đoạn, death là biến số xác nhận bệnh nhân tử vong hoặc censored, event là trạng thái sự kiện tại mỗi thời điểm.

prothro%>%filter(id==c("2","8"))%>%knitr::kable()
## Warning: package 'bindrcpp' was built under R version 3.4.1
id pro time treat Time start stop death event
2 73 0.6872194 prednisone 6.754463 0.6872194 0.9610119 1 0
2 64 1.1882598 prednisone 6.754463 1.1882598 1.4428869 1 0
2 58 1.7139415 prednisone 6.754463 1.7139415 1.9959479 1 0
2 75 2.7214982 prednisone 6.754463 2.7214982 3.7728617 1 0
2 45 4.7503012 prednisone 6.754463 4.7503012 5.7167890 1 0
2 99 6.6997043 prednisone 6.754463 6.6997043 6.7544628 1 1
8 108 0.5777023 placebo 7.584054 0.5777023 1.0842186 0 0
8 100 1.3032527 placebo 7.584054 1.3032527 1.6071624 0 0
8 120 1.8042931 placebo 7.584054 1.8042931 2.0534443 0 0
8 100 3.0500493 placebo 7.584054 3.0500493 4.0165371 0 0
8 100 5.0514730 placebo 7.584054 5.0514730 6.0152229 0 0
8 130 6.9926624 placebo 7.584054 6.9926624 7.5840543 0 0
prothros%>%head()%>%knitr::kable()
id Time death treat
1 0.4134268 1 prednisone
2 6.7544628 1 prednisone
3 13.3939328 0 prednisone
4 0.7939985 1 prednisone
5 0.7501917 1 prednisone
6 0.7693571 1 prednisone
  1. Tổng số bệnh nhân ? Con số này là 488
prothro$id%>%
  unique() %>%
  length()
## [1] 488
  1. Có bao nhiêu bệnh nhân đã tử vong ? Thời gian theo dõi trung bình của mỗi bệnh nhân là bao nhiêu:

Kết quả cho thấy thời gian trung bình đến khi mất theo dõi hay kết thúctheo dõi là 4.8 tháng (cao nhất 13.39, thấp nhất 0.06), thời gian trung bình đến khi tử vong là 2.87 tháng (0.01 đến 10.33 tháng) Tỉ lệ tử vong/censored là 292/196

prothros%>%mutate(.,Death=ifelse(.$death==1,"Dead","Censored"))%>%
{psych::describeBy(.$Time,group=.$Death)}
## 
##  Descriptive statistics by group 
## group: Censored
##    vars   n mean   sd median trimmed  mad  min   max range skew kurtosis
## X1    1 196  4.8 3.68    5.2    4.63 5.53 0.06 13.39 13.33 0.21    -1.29
##      se
## X1 0.26
## -------------------------------------------------------- 
## group: Dead
##    vars   n mean  sd median trimmed  mad  min   max range skew kurtosis
## X1    1 292 2.87 2.7   2.05    2.51 2.43 0.01 10.33 10.32 0.91    -0.24
##      se
## X1 0.16
  1. Mỗi phân nhóm điều trị có bao nhiêu bệnh nhân ? Họ được theo dõi trong bao lâu ?

Nhóm điều trị với Prednisone có 237 bệnh nhân, nhóm Placebo có 251 bệnh nhân. Thời gian theo dõi trung bình tương ứng là 3.63 và 3.66 tháng

prothros%>%mutate(.,Death=ifelse(.$death==1,"Dead","Censored"))%>%
  {psych::describeBy(.$Time,.$treat)}
## 
##  Descriptive statistics by group 
## group: placebo
##    vars   n mean   sd median trimmed  mad  min   max range skew kurtosis
## X1    1 251 3.63 3.35    2.6     3.3 3.41 0.01 12.18 12.17 0.62    -0.97
##      se
## X1 0.21
## -------------------------------------------------------- 
## group: prednisone
##    vars   n mean   sd median trimmed  mad  min   max range skew kurtosis
## X1    1 237 3.66 3.19   2.64    3.33 3.17 0.04 13.39 13.36 0.76    -0.45
##      se
## X1 0.21
  1. Phân bố các trường hợp tử vong ?
prothros%>%mutate(.,Death=ifelse(.$death==1,"Dead","Censored"))%>%
  xtabs(data=.,~Death+treat)
##           treat
## Death      placebo prednisone
##   Censored     109         87
##   Dead         142        150
  1. Giá trị prothrombin cơ bản lúc bắt đầu nghiên cứu là bao nhiêu ?
paste("Prothrombin T0: Giữa 2 phân nhóm điều trị")
## [1] "Prothrombin T0: Gi<U+1EEF>a 2 phân nhóm di<U+1EC1>u tr<U+1ECB>"
prothro%>%filter(.$time==0)%>%
{psych::describeBy(.$pro,.$treat)}
## 
##  Descriptive statistics by group 
## group: placebo
##    vars   n  mean    sd median trimmed   mad min max range skew kurtosis
## X1    1 251 68.65 23.88     67   68.03 26.69  12 134   122 0.31    -0.38
##      se
## X1 1.51
## -------------------------------------------------------- 
## group: prednisone
##    vars   n  mean    sd median trimmed  mad min max range skew kurtosis
## X1    1 237 68.83 22.14     68   68.75 25.2  16 126   110 0.07    -0.68
##      se
## X1 1.44
paste("Prothrombin T0: Giữa Có/Không có tử vong")
## [1] "Prothrombin T0: Gi<U+1EEF>a Có/Không có t<U+1EED> vong"
prothro%>%filter(.$time==0)%>%
  mutate(.,Death=ifelse(.$death==1,"Dead","Censored"))%>%
  {psych::describeBy(.$pro,.$Death)}
## 
##  Descriptive statistics by group 
## group: Censored
##    vars   n  mean    sd median trimmed   mad min max range  skew kurtosis
## X1    1 196 75.21 22.29   73.5    75.7 24.46  12 134   122 -0.09     -0.1
##      se
## X1 1.59
## -------------------------------------------------------- 
## group: Dead
##    vars   n mean    sd median trimmed   mad min max range skew kurtosis
## X1    1 292 64.4 22.52     61   63.35 23.72  16 134   118 0.43    -0.41
##      se
## X1 1.32

Bây giờ ta sẽ trình bày thông tin bằng biểu đồ:

Hình 1) Số lần visit ở mỗi bệnh nhân có thể dao động từ 1 đến 17 lần

prothro%>%mutate(.,Death=ifelse(.$death==1,"Dead","Censored"))%>%
  ggplot(aes(x=id,fill=Death))+
  stat_bin(binwidth=1,show.legend = F)+
  stat_bin(binwidth=1, geom="text", aes(label=..count..),size=3)+
  theme_bw()+
  coord_flip()+
  facet_grid(treat~Death)+
  labs(title="Visits count",x="Patient Id",y="Number of Visits")

Hình 2: Diễn tiến của prothrombin rất khác nhau ở mỗi bệnh nhân, nhưng nhìn chung : những bệnh nhân tử vong có prothrombin thấp hơn, phân nhóm prednisone có prothrombin thấp hơn phân nhóm placebo

library(colorRamps)
library(RColorBrewer) 

mypalette = length(unique(prothro$id))
getPalette = colorRampPalette(brewer.pal(9, "Spectral"))

prothro%>%mutate(.,Death=ifelse(.$death==1,"Dead","Censored"))%>%
  ggplot()+
  geom_path(aes(x=time,y=pro,color=as.factor(id)),show.legend = F,alpha=0.6)+
  geom_smooth(aes(x=as.numeric(time),y=pro,fill=treat,linetype=treat),
              color="black",
              method="lm",formula = y ~ splines::bs(x,3),alpha=0.4)+
  scale_color_manual(values = getPalette(mypalette))+
  facet_wrap(~Death)+
  theme_bw()

Hình 3a,b): Giả sử ta chia đều thời gian theo dõi thành 11 vị trí: Giá trị prothrombin trung bình tại mỗi thời điểm là như sau:

prothro%>%mutate(.,Death=ifelse(.$death==1,"Death","Survived"))%>%
  ggplot(aes(y=pro,x=death,fill=treat))+
  geom_boxplot(alpha=0.5)+
  coord_flip()+
  facet_wrap(~round(time,0),ncol=3)+
  theme_bw()

Như vậy tại mỗi thời điểm, có vẻ như không có sự tương phản rõ rệt giữa 2 phân nhóm điều trị

prothro%>%mutate(.,Death=ifelse(.$death==1,"Death","Survived"))%>%
  ggplot(aes(x=pro,fill=treat))+
  geom_density(alpha=0.5)+
  facet_wrap(~round(time,0),scales="free_y",ncol=3)+
  theme_bw()

Hình 4a,b) Mô hình random intercept và random slope với natural cubic spline:

Nếu xét riêng bài toán longitudinal cho prothrombin, ta có thể dùng mô hình mixed model (random intercept hoặc random slope). Trong mô hình này biến kết quả là prothrombinở thang đo logarit, phụ thuộc vào thời gian (hay nói cách khác: thời điểm lấy mẫu = biến time). Mặt khác, theo quan sát ban đầu ta có thể nhận ra là diễn tiến của prothrombin (biến kết quả) theo thời gian đi theo một lộ trình phi tuyến tính, do đó ta có thể “uốn cong” đồ thị của mô hình với một hàm natural cubic spline (hàm này được tích hợp sẵn trong package JMbayes). Kết quả của mô hình như sau

Mô hình random intercept với natural cubic spline

rint=lme(log(pro) ~ ns(time,3), 
         random = ~ 1 | id,
         data = prothro)

prothro%>%mutate(.,Fitted=predict(rint))%>%
  ggplot()+
  geom_path(aes(x=as.numeric(time),y=Fitted,color=as.factor(id)),
            show.legend = F,
            alpha=0.1)+
  geom_smooth(aes(x=as.numeric(time),y=Fitted),
              method="lm",alpha=0.5,
              formula=y~ns(x,3),se=F,
            show.legend = F,color="red")+
  scale_color_grey()+
  theme_bw()+
  labs(title="Random Intercept model: Y~ns(time,3)+1|Id",x="Time",y="Predicted prothromb (Log scale)")

Mô hình random slope với natural cubic spline

rslope=lme(log(pro) ~ ns(time,3), 
         random = ~ ns(time,3) | id,
         data = prothro)

prothro%>%mutate(.,Fitted=predict(rslope))%>%
  ggplot()+
  geom_path(aes(x=as.numeric(time),
                y=Fitted,color=as.factor(id)),
            show.legend = F,
            alpha=0.1)+
  geom_smooth(aes(x=as.numeric(time),y=Fitted),
              method="lm",alpha=0.5,
              formula=y~ns(x,3),se=F,
            show.legend = F,color="red")+
  scale_color_grey()+
  theme_bw()+
  labs(title="Random Slope model: Y~ns(time,3)+ ns(time,3)|Id",x="Time",y="Predicted prothromb (Log scale)")

HÌnh 5 a,b,c,d):

Tiếp theo chúng ta xét đến bài toán về nguy cơ tử vong (survival study); 3 hình thức khác nhau của biểu đồ Kaplan-Meier được trình bày trong hình 5, chúng mô tả hàm survival, hàm nguy cơ và hàm CDF theo thời gian phân biệt cho 2 nhóm điều trị.

Nếu không xét đến yếu tố prothrombin, nguy cơ tử vong có vẻ cao hơn ở nhóm prednisone so với nhóm placebo

library(survminer)
## Loading required package: ggpubr
## Warning: package 'ggpubr' was built under R version 3.4.1
library(survival)

fit <- survfit(Surv(Time, death) ~ treat, data = prothro)

ggsurvplot(fit, 
           data = prothro,
           size=1,
           conf.int = TRUE,
           pval = TRUE,
           risk.table = TRUE, 
           risk.table.col = "strata",
           risk.table.height = 0.3,
           ggtheme = theme_bw(),
           risk.table.y.text.col = T, 
           risk.table.y.text = FALSE
)

# KM plots

ggplot(prothros, 
       aes(time = Time, status = death, fill = treat, color = treat))+ 
  geom_km()+ 
  geom_kmband()+
  theme_bw()

ggplot(prothros, 
       aes(time = Time, status = death, fill = treat, color = treat))+ 
  geom_km(trans = "cumhaz")+ 
  geom_kmband(trans = "cumhaz")+
  theme_bw()+ ylab("Cumulative hazard")

ggplot(prothros, 
       aes(time = Time, status = death, fill = treat, color = treat))+ 
  geom_km(trans = "event")+ 
  geom_kmband(trans = "event")+
  theme_bw()+ ylab("Cumulative Events (CDF)")

Hình 6a) Ta cũng có thể so sánh nguy cơ tử vong giữa 2 phân nhóm có giá trị Prothrombin ở thời điểm T0 cao hơn và thấp hơn ngưỡng trung vị trong mẫu nghiên cứu:

Các bệnh nhân có prothrombin ban đầu (T0) thấp hơn trung vị thì có nhiều nguy cơ tử vong hơn.

prothro%>%filter(time==0.0)%>%mutate(.,Pro=ifelse(.$pro>=median(.$pro),"High","Low"))%>%
ggplot(aes(time = Time, status = death, fill = Pro, color = Pro))+ 
  geom_km(trans = "cumhaz")+ 
  geom_kmband(trans = "cumhaz")+
  theme_bw()+
  facet_wrap(~treat)+
  ylab("Cumulative Hazard")

Tương tự, nếu chỉ xét giá trị prothrombin ở thời điểm cuối cùng (ngay trước khi censore hay tử vong): giá trị prothrombin thấp cũng có liên hệ với nguy cơ tử vong:

prothro%>%filter(Time==stop)%>%mutate(.,Pro=ifelse(.$pro>=median(.$pro),"High","Low"))%>%
  ggplot(aes(time = Time, status = death, fill = Pro, color = Pro))+ 
  geom_km(trans = "cumhaz")+ 
  geom_kmband(trans = "cumhaz")+
  theme_bw()+
  facet_wrap(~treat)+
  ylab("Cumulative Hazard")

Tuy nhiên, ta không thể chỉ khảo sát marker Prothrombin duy nhất tại 2 thời điểm Đầu và Cuối, mà ta muốn khảo sát toàn bộ diễn tiến của marker này và kiểm tra liệu có liên hệ giữa diễn tiến này với yếu tố điều trị gây thay đổi nguy cơ tử vong hay không ?Do đó ta sẽ sử dụng Joint model

4 Dựng Joint Model theo phương pháp Bayes

Mô hình bộ phận thứ nhất: Longitudinal

Đầu tiên, chúng ta dựng một mô hình tuyến tính hỗn hợp (Mixed model) cho diễn tiến của prothrombin theo thời gian. Biến kết quả của mô hình là giá trị prothrombin ở thang đo logarit. Như đã nói ở trên, sự thay đổi theo thời gian ở đa số bệnh nhân là không tuyến tính, do đó Nhi sẽ sử dụng hàm natural cubic spline cho cả 2 hiệu ứng: Fixed và random trong mô hình. Như vậy đây chính là 1 mô hình random slope.

lmeFit=lme(log(pro)~ns(time, 3),
                    data = prothro,
                    random = ~ ns(time, 3) | id)
summary(lmeFit)
## Linear mixed-effects model fit by REML
##  Data: prothro 
##        AIC      BIC    logLik
##   1735.742 1825.657 -852.8711
## 
## Random effects:
##  Formula: ~ns(time, 3) | id
##  Structure: General positive-definite, Log-Cholesky parametrization
##              StdDev    Corr                
## (Intercept)  0.3013339 (Intr) n(,3)1 n(,3)2
## ns(time, 3)1 0.6194410 -0.212              
## ns(time, 3)2 0.4032879 -0.142  0.439       
## ns(time, 3)3 0.1879770  0.182 -0.387  0.447
## Residual     0.2495787                     
## 
## Fixed effects: log(pro) ~ ns(time, 3) 
##                  Value  Std.Error   DF   t-value p-value
## (Intercept)   4.184412 0.01676300 2477 249.62190  0.0000
## ns(time, 3)1 -0.104434 0.04902390 2477  -2.13027  0.0332
## ns(time, 3)2  0.281738 0.03982575 2477   7.07428  0.0000
## ns(time, 3)3  0.308066 0.04887171 2477   6.30356  0.0000
##  Correlation: 
##              (Intr) n(,3)1 n(,3)2
## ns(time, 3)1 -0.068              
## ns(time, 3)2 -0.379  0.031       
## ns(time, 3)3 -0.077 -0.397  0.659
## 
## Standardized Within-Group Residuals:
##         Min          Q1         Med          Q3         Max 
## -8.33432522 -0.41654029  0.07603526  0.51689202  3.78977554 
## 
## Number of Observations: 2968
## Number of Groups: 488
plot(lmeFit)

mypalette = length(unique(prothro$id))
getPalette = colorRampPalette(brewer.pal(9,"RdBu"))

prothro%>%mutate(.,Fitted=predict(lmeFit))%>%
  ggplot()+
  geom_point(aes(x=as.numeric(time),
                y=log(pro),color=as.factor(id)),alpha=0.2,show.legend = F)+
  geom_path(aes(x=as.numeric(time),
                y=Fitted,color=as.factor(id)),
            show.legend = F,
            alpha=0.2)+
  geom_smooth(aes(x=as.numeric(time),y=Fitted),
              method="lm",alpha=0.5,
              formula=y~ns(x,3),se=F,
            show.legend = F,color="black")+
  scale_color_manual(values = rev(getPalette(mypalette)))+
  theme_bw()+
  labs(title="Random Slope model: Y~ns(time,3)+ ns(time,3)|Id",x="Time",y="Predicted prothromb (Log scale)")

Thành phần thứ hai trong Joint model là một mô hình CoxPH, chỉ chứa yếu tố phân nhóm điều trị.

coxFit=coxph(Surv(Time,death) ~ treat, 
                  data = prothros,
                  x = TRUE)
summary(coxFit)
## Call:
## coxph(formula = Surv(Time, death) ~ treat, data = prothros, x = TRUE)
## 
##   n= 488, number of events= 292 
## 
##                    coef exp(coef) se(coef)     z Pr(>|z|)
## treatprednisone 0.09989   1.10504  0.11720 0.852    0.394
## 
##                 exp(coef) exp(-coef) lower .95 upper .95
## treatprednisone     1.105     0.9049    0.8782      1.39
## 
## Concordance= 0.51  (se = 0.016 )
## Rsquare= 0.001   (max possible= 0.999 )
## Likelihood ratio test= 0.73  on 1 df,   p=0.394
## Wald test            = 0.73  on 1 df,   p=0.3941
## Score (logrank) test = 0.73  on 1 df,   p=0.3939

Sau đó, ta sẽ dựng Joint Model cơ bản với package JMbayes với 50 ngàn lượt lấy mẫu cho chuỗi MCMC

jointfit=jointModelBayes(lmeFit,coxFit,timeVar = "time",n.iter=50000)
## 
##  MCMC iterations:
## 
## 
  |                                                        
  |                                                  |   0%
  |                                                        
  |                                                  |   1%
  |                                                        
  |+                                                 |   1%
  |                                                        
  |+                                                 |   2%
  |                                                        
  |+                                                 |   3%
  |                                                        
  |++                                                |   3%
  |                                                        
  |++                                                |   4%
  |                                                        
  |++                                                |   5%
  |                                                        
  |+++                                               |   5%
  |                                                        
  |+++                                               |   6%
  |                                                        
  |+++                                               |   7%
  |                                                        
  |++++                                              |   7%
  |                                                        
  |++++                                              |   8%
  |                                                        
  |++++                                              |   9%
  |                                                        
  |+++++                                             |   9%
  |                                                        
  |+++++                                             |  10%
  |                                                        
  |+++++                                             |  11%
  |                                                        
  |++++++                                            |  11%
  |                                                        
  |++++++                                            |  12%
  |                                                        
  |++++++                                            |  13%
  |                                                        
  |+++++++                                           |  13%
  |                                                        
  |+++++++                                           |  14%
  |                                                        
  |+++++++                                           |  15%
  |                                                        
  |++++++++                                          |  15%
  |                                                        
  |++++++++                                          |  16%
  |                                                        
  |++++++++                                          |  17%
  |                                                        
  |+++++++++                                         |  17%
  |                                                        
  |+++++++++                                         |  18%
  |                                                        
  |+++++++++                                         |  19%
  |                                                        
  |++++++++++                                        |  19%
  |                                                        
  |++++++++++                                        |  20%
  |                                                        
  |++++++++++                                        |  21%
  |                                                        
  |+++++++++++                                       |  21%
  |                                                        
  |+++++++++++                                       |  22%
  |                                                        
  |+++++++++++                                       |  23%
  |                                                        
  |++++++++++++                                      |  23%
  |                                                        
  |++++++++++++                                      |  24%
  |                                                        
  |++++++++++++                                      |  25%
  |                                                        
  |+++++++++++++                                     |  25%
  |                                                        
  |+++++++++++++                                     |  26%
  |                                                        
  |+++++++++++++                                     |  27%
  |                                                        
  |++++++++++++++                                    |  27%
  |                                                        
  |++++++++++++++                                    |  28%
  |                                                        
  |++++++++++++++                                    |  29%
  |                                                        
  |+++++++++++++++                                   |  29%
  |                                                        
  |+++++++++++++++                                   |  30%
  |                                                        
  |+++++++++++++++                                   |  31%
  |                                                        
  |++++++++++++++++                                  |  31%
  |                                                        
  |++++++++++++++++                                  |  32%
  |                                                        
  |++++++++++++++++                                  |  33%
  |                                                        
  |+++++++++++++++++                                 |  33%
  |                                                        
  |+++++++++++++++++                                 |  34%
  |                                                        
  |+++++++++++++++++                                 |  35%
  |                                                        
  |++++++++++++++++++                                |  35%
  |                                                        
  |++++++++++++++++++                                |  36%
  |                                                        
  |++++++++++++++++++                                |  37%
  |                                                        
  |+++++++++++++++++++                               |  37%
  |                                                        
  |+++++++++++++++++++                               |  38%
  |                                                        
  |+++++++++++++++++++                               |  39%
  |                                                        
  |++++++++++++++++++++                              |  39%
  |                                                        
  |++++++++++++++++++++                              |  40%
  |                                                        
  |++++++++++++++++++++                              |  41%
  |                                                        
  |+++++++++++++++++++++                             |  41%
  |                                                        
  |+++++++++++++++++++++                             |  42%
  |                                                        
  |+++++++++++++++++++++                             |  43%
  |                                                        
  |++++++++++++++++++++++                            |  43%
  |                                                        
  |++++++++++++++++++++++                            |  44%
  |                                                        
  |++++++++++++++++++++++                            |  45%
  |                                                        
  |+++++++++++++++++++++++                           |  45%
  |                                                        
  |+++++++++++++++++++++++                           |  46%
  |                                                        
  |+++++++++++++++++++++++                           |  47%
  |                                                        
  |++++++++++++++++++++++++                          |  47%
  |                                                        
  |++++++++++++++++++++++++                          |  48%
  |                                                        
  |++++++++++++++++++++++++                          |  49%
  |                                                        
  |+++++++++++++++++++++++++                         |  49%
  |                                                        
  |+++++++++++++++++++++++++                         |  50%
  |                                                        
  |+++++++++++++++++++++++++                         |  51%
  |                                                        
  |++++++++++++++++++++++++++                        |  51%
  |                                                        
  |++++++++++++++++++++++++++                        |  52%
  |                                                        
  |++++++++++++++++++++++++++                        |  53%
  |                                                        
  |+++++++++++++++++++++++++++                       |  53%
  |                                                        
  |+++++++++++++++++++++++++++                       |  54%
  |                                                        
  |+++++++++++++++++++++++++++                       |  55%
  |                                                        
  |++++++++++++++++++++++++++++                      |  55%
  |                                                        
  |++++++++++++++++++++++++++++                      |  56%
  |                                                        
  |++++++++++++++++++++++++++++                      |  57%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  57%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  58%
  |                                                        
  |+++++++++++++++++++++++++++++                     |  59%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  59%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  60%
  |                                                        
  |++++++++++++++++++++++++++++++                    |  61%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  61%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  62%
  |                                                        
  |+++++++++++++++++++++++++++++++                   |  63%
  |                                                        
  |++++++++++++++++++++++++++++++++                  |  63%
  |                                                        
  |++++++++++++++++++++++++++++++++                  |  64%
  |                                                        
  |++++++++++++++++++++++++++++++++                  |  65%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  65%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  66%
  |                                                        
  |+++++++++++++++++++++++++++++++++                 |  67%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  67%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  68%
  |                                                        
  |++++++++++++++++++++++++++++++++++                |  69%
  |                                                        
  |+++++++++++++++++++++++++++++++++++               |  69%
  |                                                        
  |+++++++++++++++++++++++++++++++++++               |  70%
  |                                                        
  |+++++++++++++++++++++++++++++++++++               |  71%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  71%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  72%
  |                                                        
  |++++++++++++++++++++++++++++++++++++              |  73%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  73%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  74%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++             |  75%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++            |  75%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++            |  76%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++            |  77%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  77%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  78%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++           |  79%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  79%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  80%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++          |  81%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  81%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  82%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++         |  83%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++        |  83%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++        |  84%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++        |  85%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  85%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  86%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++       |  87%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  87%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  88%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++      |  89%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++     |  89%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++     |  90%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++     |  91%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  91%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  92%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++    |  93%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  93%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  94%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++   |  95%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++  |  95%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++  |  96%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++  |  97%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  97%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  98%
  |                                                        
  |+++++++++++++++++++++++++++++++++++++++++++++++++ |  99%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++|  99%
  |                                                        
  |++++++++++++++++++++++++++++++++++++++++++++++++++| 100%
summary(jointfit)
## 
## Call:
## jointModelBayes(lmeObject = lmeFit, survObject = coxFit, timeVar = "time", 
##     n.iter = 50000)
## 
## Data Descriptives:
## Longitudinal Process     Event Process
## Number of Observations: 2968 Number of Events: 292 (59.8%)
## Number of subjects: 488
## 
## Joint Model Summary:
## Longitudinal Process: Linear mixed-effects model
## Event Process: Relative risk model with penalized-spline-approximated 
##      baseline risk function
## Parameterization: Time-dependent value 
## 
##       LPML      DIC       pD
##  -3788.693 7155.456 1931.453
## 
## Variance Components:
##               StdDev    Corr                
## (Intercept)   0.4717  (Intr)  n(,3)1  n(,3)2
## ns(time, 3)1  0.7863 -0.0297                
## ns(time, 3)2  0.7370 -0.0572 -0.0743        
## ns(time, 3)3  1.3559 -0.0658  0.0789 -0.1094
## Residual      0.2372                        
## 
## Coefficients:
## Longitudinal Process
##                Value Std.Err Std.Dev    2.5%   97.5%      P
## (Intercept)   4.1845  0.0006  0.0228  4.1412  4.2290 <0.001
## ns(time, 3)1 -0.1209  0.0015  0.0454 -0.2146 -0.0359   0.01
## ns(time, 3)2  0.2265  0.0013  0.0415  0.1423  0.3044 <0.001
## ns(time, 3)3  0.3770  0.0032  0.0765  0.2314  0.5336 <0.001
## 
## Event Process
##                    Value Std.Err  Std.Dev    2.5%    97.5%      P
## treatprednisone  -0.1617  0.0045   0.1219 -0.3977   0.0769  0.197
## Assoct           -2.4639  0.0293   0.1646 -2.7848  -2.1415 <0.001
## tauBs           255.3340 11.6116 151.4681 57.4600 638.9329     NA
## 
## MCMC summary:
## iterations: 50000 
## adapt: 3000 
## burn-in: 3000 
## thinning: 25 
## time: 12.1 min
jointfit$mcmc%>%names()
## [1] "betas"     "sigma"     "b"         "D"         "gammas"    "Bs.gammas"
## [7] "tauBs"     "alphas"

Bản tóm tắt nội dung mô hình Joint model cung cấp các thông tin bao gồm:

Thống kê về tính phù hợp của mô hình, sử dụng Log pseudo marginal likelihood value (LPML), deviance information criterion (DIC) và kích thước của thành phần tham số trong DIC (pD).

Trung bình của phân phối hậu nghiệm của tất cả các tham số hồi quy, kèm theo sai số chuẩn (SE) và khoảng tin cậy 95%. Những kết quả này được ước tính dựa vào chuỗi MCMC (được khảo sát như một time series vector). Một điểm thú vị đó là tuy sử dụng phương pháp ước lượng tham số hồi quy theo Bayes, với phân phối hậu nghiệm, nhưng package JMbayes lại trình bày kết quả suy diễn thống kê dưới hình thức p-value (tail probability với null hypothesis testing như trong phương pháp frequentist): p value ở đây chính là xác suất tham số hồi quy lớn hơn hoặc nhỏ hơn zero.

P value = 2 * min { Pr(b>0),Pr(b<0)} với b là tham số hồi quy cần kiểm tra

Thực ra cách suy diễn này cũng tương đồng như phương pháp của John Kruschke dựa vào 1 ngưỡng ý nghĩa hay 1 khoảng vô nghĩa thực dụng (ROPE), chỉ khác là Kruschke dùng mật độ xác suất (bao nhiêu % phân phối hậu nghiệm nằm trong/ngoài ROPE hay nằm bên trái/phải ngưỡng ý nghĩa) còn Rizopoulos dùng xác suất p.

Phân phối hậu nghiệm của tham số hồi quy được lưu trữ trong các chuỗi MCMC, có tất cả 8 chuỗi tương ứng với 8 thành phần trong joint model. Ở đây ta chỉ khảo sát những thông tin quan trọng nhất gồm có:

Chuỗi MCMC Beta

Chuỗi MCMC beta chứa tham số hồi quy cho thành phần Longitudinal (mô hình random slope ước tính log(prothrombin) tại thời điểm t cho một cá thể nhất định).

jointfit$mcmc$betas%>%head()%>%knitr::kable()
(Intercept) ns(time, 3)1 ns(time, 3)2 ns(time, 3)3
4.166755 -0.1371939 0.2371638 0.4604426
4.232075 -0.0993499 0.2963757 0.3017229
4.198056 -0.0616516 0.2462436 0.3165887
4.219529 -0.1473808 0.2748667 0.2276635
4.234687 -0.1174135 0.2467452 0.3722705
4.195657 -0.0815266 0.1961530 0.3373747
betadf=jointfit$mcmc$betas%>%as_tibble()

names(betadf)=c("Intercept","NS_Time1","NS_Time2","NS_Time3")

betadf%>%gather(Intercept:NS_Time3,key="Components",value="Coefficient")%>%
  ggplot()+
  geom_density(aes(x=Coefficient,fill=Components),alpha=0.6)+
  theme_bw()+
  facet_wrap(~Components,scales="free",ncol=2)

betadf%>%
  mutate(.,Iter=as.numeric(rownames(.)))%>%
  gather(Intercept:NS_Time3,key="Components",value="Coefficient")%>%
  ggplot()+
  geom_path(aes(x=Iter,y=Coefficient,color=Components,group=1),alpha=0.7)+
  theme_bw()+
  facet_wrap(~Components,scales="free",ncol=1)

Chuỗi MCMC sigma

Chuỗi MCMC sigma chứa phân phối hậu nghiệm của Residual trong mô hình random slope:

jointfit$mcmc$sigma%>%head()
##          sigma
## [1,] 0.2464715
## [2,] 0.2351639
## [3,] 0.2356347
## [4,] 0.2416009
## [5,] 0.2392787
## [6,] 0.2360419
sigmadf=jointfit$mcmc$sigma%>%as_tibble()

p1=sigmadf%>%ggplot()+
  geom_density(aes(x=sigma),alpha=0.6,fill="red")+
  theme_bw()

p2=sigmadf%>%
  mutate(.,Iter=as.numeric(rownames(.)))%>%
  ggplot()+
  geom_path(aes(x=Iter,y=sigma),alpha=0.7,color="red")+
  theme_bw()

gridExtra::grid.arrange(p1,p2,ncol=1)

Chuỗi MCMC b

Chuỗi b chứa hiệu ứng ngẫu nhiên cá thể cho Intercept và Slope, đây là 1 matrix rất lớn, với kích thước = số lượt lấy mẫu (khoảng 8000) x số tham số trong mô hình x số bệnh nhân.

Chuỗi gammas

Chuỗi gamma chứa phân phối hậu nghiệm của hiệu ứng riêng phần của yếu tố điều trị trong mô hình Survival (treatprednisone).

gammadf=jointfit$mcmc$gammas%>%as_tibble()

p1=gammadf%>%ggplot()+
  geom_density(aes(x=treatprednisone),alpha=0.6,fill="purple")+
  theme_bw()

p2=gammadf%>%
  mutate(.,Iter=as.numeric(rownames(.)))%>%
  ggplot()+
  geom_path(aes(x=Iter,y=treatprednisone),alpha=0.7,color="purple")+
  theme_bw()

gridExtra::grid.arrange(p1,p2,ncol=1)

Chuỗi BS.gamma

Chuỗi BS.gamma chứa phân phối hậu nghiệm cho tham số hồi quy của 17 phân đoạn thời gian trong mô hình Survival, do kích thước của nó quá lớn nên chúng ta cũng không khảo sát sâu hơn

bsgam=jointfit$mcmc$Bs.gammas%>%as_tibble()

bsgam%>%head()%>%knitr::kable()
Bs.gammas1 Bs.gammas2 Bs.gammas3 Bs.gammas4 Bs.gammas5 Bs.gammas6 Bs.gammas7 Bs.gammas8 Bs.gammas9 Bs.gammas10 Bs.gammas11 Bs.gammas12 Bs.gammas13 Bs.gammas14 Bs.gammas15 Bs.gammas16 Bs.gammas17
8.142618 8.028174 7.852684 7.735790 7.625893 7.529252 7.512875 7.545106 7.594168 7.777030 7.977989 8.043824 8.146587 8.484370 8.790008 9.097839 9.537896
8.046355 7.934682 7.774667 7.744428 7.659609 7.573838 7.497213 7.470633 7.551092 7.768141 7.976529 8.085545 8.260737 8.603179 8.977115 9.376499 9.913058
8.286810 8.126373 7.938846 7.903592 7.838276 7.818553 7.752809 7.698992 7.779366 7.979521 8.203416 8.300705 8.451332 8.760036 9.113401 9.450458 9.935655
8.442114 8.085402 7.845935 7.738835 7.641463 7.608680 7.572032 7.568777 7.690309 7.932411 8.226173 8.405535 8.524631 8.795154 9.110450 9.388181 9.702182
8.558670 8.198795 7.973443 7.842892 7.697231 7.637369 7.614329 7.616467 7.749046 7.997117 8.236845 8.400628 8.536905 8.839088 9.211345 9.564557 9.933011
8.811566 8.385017 8.160656 8.021760 7.886372 7.867034 7.842348 7.831169 7.895563 8.041047 8.227116 8.363656 8.448777 8.754916 9.155494 9.567143 9.987988
Hmisc::describe(bsgam)
## bsgam 
## 
##  17  Variables      2000  Observations
## ---------------------------------------------------------------------------
## Bs.gammas1 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.934   0.7412    7.821    8.046 
##      .25      .50      .75      .90      .95 
##    8.504    8.952    9.379    9.751   10.034 
## 
## lowest :  6.937464  7.016839  7.091582  7.147383  7.162695
## highest: 10.690605 10.692979 10.722805 10.752265 10.806587
## ---------------------------------------------------------------------------
## Bs.gammas2 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.801   0.7434    7.711    7.929 
##      .25      .50      .75      .90      .95 
##    8.342    8.814    9.251    9.621    9.868 
## 
## lowest :  6.844597  7.015248  7.037638  7.053279  7.132792
## highest: 10.479946 10.501547 10.566833 10.589966 10.685109
## ---------------------------------------------------------------------------
## Bs.gammas3 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.668   0.7611    7.559    7.791 
##      .25      .50      .75      .90      .95 
##    8.188    8.679    9.150    9.509    9.730 
## 
## lowest :  6.668485  6.928073  6.942118  6.955891  6.984306
## highest: 10.447261 10.477611 10.573543 10.575178 10.668534
## ---------------------------------------------------------------------------
## Bs.gammas4 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.542    0.772    7.406    7.661 
##      .25      .50      .75      .90      .95 
##    8.052    8.559    9.034    9.387    9.624 
## 
## lowest :  6.500742  6.789214  6.816522  6.827519  6.849389
## highest: 10.352992 10.376645 10.450199 10.467366 10.564317
## ---------------------------------------------------------------------------
## Bs.gammas5 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.453   0.7784    7.319    7.569 
##      .25      .50      .75      .90      .95 
##    7.956    8.466    8.949    9.328    9.558 
## 
## lowest :  6.428777  6.592291  6.639888  6.674039  6.678085
## highest: 10.315809 10.336024 10.343200 10.353307 10.386162
## ---------------------------------------------------------------------------
## Bs.gammas6 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.399    0.791    7.245    7.505 
##      .25      .50      .75      .90      .95 
##    7.893    8.409    8.892    9.292    9.538 
## 
## lowest :  6.392566  6.500920  6.512691  6.587005  6.600791
## highest: 10.280576 10.298094 10.303442 10.340657 10.369492
## ---------------------------------------------------------------------------
## Bs.gammas7 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.392   0.7961    7.258    7.513 
##      .25      .50      .75      .90      .95 
##    7.886    8.406    8.881    9.295    9.538 
## 
## lowest :  6.323360  6.391773  6.478027  6.515396  6.536359
## highest: 10.282893 10.291667 10.352427 10.396060 10.402068
## ---------------------------------------------------------------------------
## Bs.gammas8 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.419   0.7986    7.292    7.530 
##      .25      .50      .75      .90      .95 
##    7.913    8.437    8.922    9.319    9.551 
## 
## lowest :  6.345751  6.398935  6.472127  6.529794  6.545229
## highest: 10.238440 10.308912 10.338838 10.384987 10.418001
## ---------------------------------------------------------------------------
## Bs.gammas9 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.491   0.8058    7.367    7.601 
##      .25      .50      .75      .90      .95 
##    7.972    8.504    9.003    9.404    9.620 
## 
## lowest :  6.411109  6.467243  6.538231  6.622581  6.638399
## highest: 10.306940 10.385985 10.401643 10.404050 10.423646
## ---------------------------------------------------------------------------
## Bs.gammas10 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.606   0.8119    7.468    7.714 
##      .25      .50      .75      .90      .95 
##    8.081    8.615    9.118    9.523    9.757 
## 
## lowest :  6.593275  6.601119  6.695314  6.704427  6.713113
## highest: 10.493302 10.497455 10.506366 10.518864 10.524146
## ---------------------------------------------------------------------------
## Bs.gammas11 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.757   0.8146    7.607    7.845 
##      .25      .50      .75      .90      .95 
##    8.221    8.769    9.264    9.661    9.915 
## 
## lowest :  6.786049  6.821886  6.875645  6.879372  6.881041
## highest: 10.624128 10.655827 10.661483 10.682578 10.693685
## ---------------------------------------------------------------------------
## Bs.gammas12 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    8.923    0.819    7.747    7.993 
##      .25      .50      .75      .90      .95 
##    8.401    8.938    9.442    9.825   10.074 
## 
## lowest :  6.946539  6.993020  7.022604  7.059983  7.087073
## highest: 10.775010 10.796138 10.796169 10.853785 10.903102
## ---------------------------------------------------------------------------
## Bs.gammas13 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1      9.1   0.8276    7.917    8.163 
##      .25      .50      .75      .90      .95 
##    8.569    9.102    9.636   10.002   10.270 
## 
## lowest :  7.041233  7.207530  7.263250  7.283345  7.293830
## highest: 10.988641 10.994570 11.000694 11.071627 11.116787
## ---------------------------------------------------------------------------
## Bs.gammas14 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1     9.29   0.8472    8.099    8.314 
##      .25      .50      .75      .90      .95 
##    8.734    9.292    9.843   10.206   10.477 
## 
## lowest :  7.030630  7.439889  7.465634  7.476441  7.490832
## highest: 11.288478 11.307226 11.312833 11.349971 11.448798
## ---------------------------------------------------------------------------
## Bs.gammas15 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    9.471   0.8698    8.244    8.463 
##      .25      .50      .75      .90      .95 
##    8.933    9.464   10.032   10.426   10.701 
## 
## lowest :  7.046545  7.532705  7.553363  7.553397  7.566575
## highest: 11.535976 11.538103 11.551505 11.608862 11.627421
## ---------------------------------------------------------------------------
## Bs.gammas16 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1     9.65   0.9065    8.327    8.606 
##      .25      .50      .75      .90      .95 
##    9.071    9.644   10.222   10.655   10.944 
## 
## lowest :  7.138890  7.624017  7.654898  7.672475  7.705988
## highest: 11.793102 11.802715 11.813050 11.877193 11.878617
## ---------------------------------------------------------------------------
## Bs.gammas17 
##        n  missing distinct     Info     Mean      Gmd      .05      .10 
##     2000        0     1982        1    9.822   0.9768    8.423    8.683 
##      .25      .50      .75      .90      .95 
##    9.184    9.840   10.417   10.919   11.209 
## 
## lowest :  7.196583  7.718103  7.722063  7.767341  7.772541
## highest: 12.137313 12.161188 12.185025 12.192673 12.310141
## ---------------------------------------------------------------------------

Chuỗi Alphas

Chuỗi alphas chứa thông tin quan trọng nhất trong mô hình joint model mà ta quan tâm, đó là hệu ứng tương tác giữa bệnh sử diễn tiến của prothrombin và phân nhóm điều trị (association effect).

jointfit$mcmc$alphas%>%head()
##         Assoct
## [1,] -2.253908
## [2,] -2.239581
## [3,] -2.306681
## [4,] -2.292939
## [5,] -2.328565
## [6,] -2.336292
alphadf=jointfit$mcmc$alphas%>%as_tibble()

p1=alphadf%>%ggplot()+
  geom_density(aes(x=Assoct),alpha=0.6,fill="gold")+
  theme_bw()

p2=alphadf%>%
  mutate(.,Iter=as.numeric(rownames(.)))%>%
  ggplot()+
  geom_path(aes(x=Iter,y=Assoct),alpha=0.7,color="orange")+
  theme_bw()

gridExtra::grid.arrange(p1,p2,ncol=1)

5 Ứng dụng của mô hình

Tiên lượng cho cá thể

Chúng ta dùng mô hình này để tiên lượng cho một bệnh nhân trong mẫu khảo sát, thí dụ số 9.

ND =prothro[prothro$id == 9, ]

longfit=predict(jointfit, 
                newdata = ND, 
                type = "Subject",
                interval = "confidence", 
                return = TRUE)

survfit=survfitJM(jointfit,newdata = ND)

survfit[1]$summaries$`9`%>%as_tibble()->tdf
rbind(tdf,c(0,rep(1,4)))->tdf
tdf%>%
  ggplot(aes(x=times))+
  geom_ribbon(aes(ymin=Lower,ymax=Upper),alpha=0.5,fill="gold")+
  geom_line(aes(y=Median),color="red3",size=1,linetype=1)+
  geom_line(aes(y=Mean),color="blue",size=1,linetype=1)+
  geom_line(aes(y=Lower),color="black",size=1,linetype=2)+
  geom_line(aes(y=Upper),color="black",size=1,linetype=2)+
  theme_bw()+
  geom_vline(xintercept=max(longfit$Time),color="blue",linetype=2)+
  labs(title="Patient N°9",x="Time",y="Predicted survival probability",caption="Joint Model")

plot(survfit, estimator = "mean", include.y = TRUE,
     conf.int = TRUE, fill.area = TRUE, col.area = "gold")

longfit%>%
  ggplot(aes(x=time))+
  geom_ribbon(aes(ymin=low,ymax=upp),alpha=0.5,fill="gold")+
  geom_line(aes(y=pred),color="red3",size=1)+
  geom_line(aes(y=low),color="black",size=1,linetype=2)+
  geom_line(aes(y=upp),color="black",size=1,linetype=2)+
  theme_bw()+
  geom_vline(xintercept=max(longfit$Time),color="blue",linetype=2)+
  labs(title="Patient N°9",x="Time",y="Predicted prothromb (Log scale)",caption="Joint Model")
## Warning: Removed 10 rows containing missing values (geom_path).

## Warning: Removed 10 rows containing missing values (geom_path).

6 Kết luận

Joint model là một phương pháp hữu ích, và package JMbayes là một cách tiếp cận thú vị, với phương pháp Bayes (MCMC) lai với null hypothesis testing và log pseudo likelihood, nhằm ước tính hệ số hồi quy cho Joint model.

Nếu bạn tìm hiểu sâu hơn nội dung package, sẽ thấy khả năng của nó rộng hơn rất nhiều so với phương pháp REML trong bài trước, và thí dụ cơ bản mà ta vừa thực hiện.

Chúc các bạn thành công.

Xin cảm ơn và hẹn gặp lại.

LS0tDQp0aXRsZTogIk3DtCBow6xuaCBsacOqbiBo4bujcCINCnN1YnRpdGxlOiAiUGjhuqduIDI6IEJheWVzaWFuIEpvaW50IG1vZGVsIg0KYXV0aG9yOiAiTMOqIE5n4buNYyBLaOG6oyBOaGkiDQpkYXRlOiAiMjkgVGjDoW5nIDggMjAxNyINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6ICJkZWZhdWx0Ig0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KDQpsaWJyYXJ5KEpNYmF5ZXMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobWFncml0dHIpDQpsaWJyYXJ5KGdna20pDQoNCmBgYA0KDQohW10oam1iYXllczEucG5nKQ0KDQojIEThuqtuIG5o4bqtcA0KDQpUcm9uZyBiw6BpIHRyxrDhu5tjLCBjaMO6bmcgdGEgxJHDoyBsw6BtIHF1ZW4gduG7m2kgcGFja2FnZSBKTSBjaG8gcGjDqXAgZOG7sW5nIG3DtCBow6xuaCBKb2ludCBtb2RlbCBi4bqxbmcgcGjGsMahbmcgcGjDoXAgUkVNTC4gTmjGsCDEkcOjIGjhu6lhLCBOaGkgc+G6vSBnaeG7m2kgdGhp4buHdSB0aeG6v3AgbeG7mXQgcGFja2FnZSBraMOhYyAoY+G7p2EgY8O5bmcgdMOhYyBnaeG6oyBSaXpvdXBvdWxvcykgY2hvIHBow6lwIGThu7FuZyBKb2ludCBtb2RlbCBi4bqxbmcgcGjGsMahbmcgcGjDoXAgQmF5ZXMuDQoNCk3DtCBow6xuaCBsacOqbiBo4bujcCAoSm9pbnQgbW9kZWwpIGzDoCBt4buZdCBwaMawxqFuZyBwaMOhcCB0aOG7kW5nIGvDqiBjaG8gcGjDqXAgaOG7o3AgbmjhuqV0IGhhaSBi4buZIHBo4bqtbiA6IHPhu7EgYmnhur9uIHRoacOqbiBwaOG7pSB0aHXhu5ljIHRo4budaSBnaWFuIGPhu6dhIG3hu5l0IGJp4bq/biDEkeG7i25oIGzGsOG7o25nIChsb25naXR1ZGluYWwgcmVzcG9uc2UgOyB0aMOtIGThu6UgbWFya2VyIHRyb25nIDEgYuG7h25oIGzDvSkgdsOgIG5ndXkgY8ahIHjhuqN5IHJhIG3hu5l0IHPhu7Ega2nhu4duIHRoZW8gdGjhu51pIGdpYW4gKHN1cnZpdmFsIGFuYWx5c2lzKSwgbmjhurFtIGto4bqjbyBzw6F0IG3hu5FpIGxpw6puIGjhu4cgZ2nhu69hIGNow7puZy4gDQoNCiFbXShqb2ludG0zLnBuZykNCg0KxJDhu4MgdMOzbSB04bqvdCBs4bqhaSB24buBIG7hu5lpIGR1bmcgbcO0IGjDrG5oIEpvaW50IG1vZGVsLCBuaOG7r25nIHRow6BuaCBwaOG6p24gc2F1IMSRw6J5IMSRxrDhu6NjIHjDqXQ6DQoNCjEpIFRpID0gVGjhu51pIGdpYW4gdGhlbyBkw7VpIMSR4bq/biBraGkgc+G7sSBraeG7h24geOG6o3kgcmEgY2hvIG3hu5l0IGPDoSB0aOG7gyAoaSkgeMOhYyDEkeG7i25oIA0KDQoyKSBDaSA9IFRo4budaSBnaWFuIGNobyDEkeG6v24ga2hpIGPDoSB0aOG7gyAoaSkgxJHGsOG7o2MgbG/huqFpIGto4buPaSB2w7JuZyB0aGVvIGTDtWkgDQoNCjMpIFRy4bqhbmcgdGjDoWkgc+G7sSBraeG7h24geOG6o3kgcmEgbMOgIDEgYmnhur9uIG5o4buLIHBow6JuICgwLDEpIMSRxrDhu6NjIHjDoWMgxJHhu4tuaCBi4bqxbmcgMSBow6BtIHbhu5tpIHF1eSBsdeG6rXQ6IGvhur90IHF14bqjID0gMSBu4bq/dSBUaSA8IGhv4bq3YyA9IENpLCB2w6AgPTAgbuG6v3UgVGkgPiBDaQ0KDQo0KSBC4buHbmggc+G7rSAgY8OhIHRo4buDICh5aSkgbMOgIG3hu5l0IHZlY3RvciBjaOG7qWEgbmjhu69uZyBnacOhIHRy4buLIGPhu6dhIG1hcmtlciBNIHRoZW8gdGjhu51pIGdpYW4gY2hvIG3hu5l0IGPDoSB0aOG7gyB4w6FjIMSR4buLbmguIE3hu5dpIHBo4bqnbiB04butICB5aWogdHJvbmcgdmVjdG9yIG7DoHkgdMawxqFuZyDhu6luZyB24bubaSAxIGdpw6EgdHLhu4sgY+G7p2EgTSBjaG8gY8OhIHRo4buDIGkgdOG6oWkgdGjhu51pIMSRaeG7g20gdGogIChqIGzDoCBz4buRIGzhuqduIGto4bqjbyBzw6F0KQ0KDQoqVGjDoG5oIHBo4bqnbiBsb25naXR1ZGluYWwqDQoNCk3hu6VjIHRpw6p1IMSR4bqndSB0acOqbiDEkcOzIGzDoCDGsOG7m2MgdMOtbmggZ2nDoSB0cuG7iyBNdSBj4bunYSB5aSBjaG8gbeG7mXQgY8OhIHRo4buDIHjDoWMgxJHhu4tuaCwgdOG6oWkgMSB0aOG7nWkgxJFp4buDbSB0IHjDoWMgxJHhu4tuaC4gxJBp4buBdSBuw6B5IGPDsyB0aOG7gyDEkcaw4bujYyB0aOG7sWMgaGnhu4duIHRow7RuZyBxdWEgbeG7mXQgbcO0IGjDrG5oIEdMTSBt4bufIHLhu5luZy4gTuG7mWkgZHVuZyBj4bunYSBtw7QgaMOsbmggbsOgeSBn4buTbSBjw7MgOg0KDQoxKSBiaeG6v24ga+G6v3QgcXXhuqMgWShpdCkgxJHGsOG7o2MgbcO0IHThuqMgYuG6sW5nIDEgcGjDom4gcGjhu5FpIHjDoWMgc3XhuqV0IGPDsyDEkWnhu4F1IGtp4buHbiBwaOG7pSB0aHXhu5ljIHbDoG8gMiB54bq/dSB04buROiB0aOG7nWkgZ2lhbiAodCkgdsOgIGhp4buHdSDhu6luZyBuZ+G6q3Ugbmhpw6puIChiaSkuIFbDrCDEkcOieSBsw6AgMSBtw7QgaMOsbmggR0xNLCB0YSBjw7MgdGjhu4MgZMO5bmcgbeG7mXQgaMOgbSBsaW5rIGZ1bmN0aW9uIEcgxJHhu4MgbGnDqm4ga+G6v3QgeWkodCkgduG7m2kgZGVzaWduIG1hdHJpeCB2w6AgdGhhbSBz4buRIGjhu5NpIHF1eSBj4bunYSBtw7QgaMOsbmguIA0KDQoyKSBW4bq/IGLDqm4gcGjhuqNpIGPhu6dhIG3DtCBow6xuaCBn4buTbSBjw7MgMiBwaOG6p24gOiBoaeG7h3Ug4bupbmcgY2jDrW5oIChmaXhlZCBlZmZlY3QpIGfhu5NtIGRlc2lnbiBtYXRyaXggKGPDoWMgYmnhur9uIMSR4buZYyBs4bqtcCwgcGjhu6UgdGh14buZYyB0aOG7nWkgZ2lhbikgeGkodCkgKyB2ZWN0b3IgdGhhbSBz4buRIGjhu5NpIHF1eSBiZXRhLCB2w6AgaGnhu4d1IOG7qW5nIG5n4bqrdSBuaGnDqm4gZ+G7k20gZGVzaWduIG1hdHJpeCBaaSh0KSB24bubaSBjw6FjIHnhur91IHThu5Egbmfhuqt1IG5oacOqbiB2w6AgdmVjdG9yIHJhbmRvbSBlZmZlY3QgYmkuDQoNCjMpIEhp4buHdSDhu6luZyBuZ+G6q3Ugbmhpw6puICh2ZWN0b3IgYmkpIMSRxrDhu6NjIGdp4bqjIMSR4buLbmggY8OzIHBow6JuIHBo4buRaSBjaHXhuqluIHbhu5tpIHRydW5nIGLDrG5oID16ZXJvIHbDoCBtYXRyaXggY2FyaWFuY2UgY292YXJpYW5jZSBELg0KDQoqVGjDoG5oIHBo4bqnbiBzdXJ2aXZhbCoNCg0KTeG7pWMgdGnDqnUgdGnhur9wIHRoZW8sIMSRw7MgbMOgIMaw4bubYyB0w61uaCBuZ3V5IGPGoSB44bqjeSByYSBz4buxIGtp4buHbiAodOG7rSB2b25nKSB04bqhaSB0aOG7nWkgxJFp4buDbSB0IHjDoWMgxJHhu4tuaCB2w6AgY2hvIG3hu5l0IGPDoSB0aOG7gyBpIHjDoWMgxJHhu4tuaCwgYmnhur90IHLhurFuZyBuZ3V5IGPGoSBuw6B5IHBo4bulIHRodeG7mWMgdsOgbyDEkeG7k25nIHRo4budaSA6IG3hu5l0IHThuq1wIGjhu6NwIGhp4buHcCBiaeG6v24gc+G7kSAoY292YXJpYXRlKSBXaSB2w6AgbeG7mXQgdmVjdG9yIGLhu4duaCBz4butIEguDQoNCkgg4bufIMSRw6J5IGNow61uaCBsw6Aga+G6v3QgcXXhuqMgxrDhu5tjIHTDrW5oIGdpw6EgdHLhu4sgbWFya2VyIGNobyBjw6EgdGjhu4MgxJHDsyB0cm9uZyBraG/huqNuZyB0aOG7nWkgZ2lhbiBzIHThu6sgMCBjaG8gxJHhur9uIHRo4budaSDEkWnhu4NtIHQuIA0KDQpIw6BtIG5ndXkgY8ahIChoaSkgY8OzIHRo4buDIMSRxrDhu6NjIHBow6JuIHTDrWNoIHRow6BuaCAxIGjDoG0gbmd1eSBjxqEgZ+G7kWMgaDAgY2hvIHRo4budaSBnaWFuIHbDoCBt4buZdCBow6BtIGV4cG9uZW50aWFsIGNo4bupYSBs4bqnbiBsxrDhu6N0IDogdmVjdG9yIHRoYW0gc+G7kSBo4buTaSBxdXkgR2FtbWEgdMawxqFuZyDhu6luZyB24bubaSB04bqtcCBo4bujcCBoaeG7h3AgYmnhur9uIHPhu5EgV2kgdsOgIG3hu5l0IGjDoG0gZiBiaeG7g3UgdGjhu4sgY2hvIGhp4buHdSDhu6luZyDCqyBsacOqbiBo4buHIMK7IGdp4buvYSBnacOhIHRy4buLIG1hcmtlciAoTXUsIMaw4bubYyB0w61uaCBxdWEgbcO0IGjDrG5oIExvbmdpdGlkaW5hbCBoYXkgbWl4ZWQgbW9kZWwpLCBoaeG7h3Ug4bupbmcgbmfhuqt1IG5oacOqbiBiaSB2w6AgdmVjdG9yIHRoYW0gc+G7kSBo4buTaSBxdXkgQWxwaGEsIGNobyBoaeG7h3Ug4bupbmcgcXVhbiBo4buHIChhc3NvY2lhdGlvbikgZ2nhu69hIG1hcmtlciB2w6AgY292YXJpYXRlcyBraMOhYyB0cm9uZyBtw7QgaMOsbmguIA0KDQpIw6BtIG5ndXkgY8ahIGfhu5FjIGgwIHRoxrDhu51uZyDEkcaw4bujYyDGsOG7m2MgbMaw4bujbmcgduG7m2kgQi1zcGxpbmUgKGzDoCBt4buZdCB0aOG7pyB0aHXhuq10IMSR4buDIG3DtCBow6xuaCBow7NhIHF1YW4gaOG7hyBwaGkgdHV54bq/biB0w61uaCB0cm9uZyBtw7QgaMOsbmgpDQoNCk5oxrAgduG6rXkgY8OzIHRo4buDIHRo4bqleSBr4bq/dCBxdeG6oyBjaMOtbmggY+G7p2EgbcO0IGjDrG5oIGxpw6puIGjhu6NwIGfhu5NtIDEgc+G7kSB2ZWN0b3IgdGhhbSBz4buRIGjhu5NpIHF1cXVhbiB0cuG7jW5nIHkgbmjGsCBhbHBoYSAoaGnhu4d1IOG7qW5nIGxpw6puIGjhu6NwLCBhc3NvY2lhdGlvbiwgY2hvIGLhu5kgcGjhuq1uIHN1cnZpdmFsKSwgYmV0YSAoaGnhu4d1IOG7qW5nIGNow61uaCwgZml4ZWQgZWZmZWN0IGNobyBi4buZIHBo4bqtbiBsb25naXR1ZGluYWwpICwgZ2FtbWEgKGhp4buHdSDhu6luZyDEkeG7mWMgbOG6rXAsIGNobyBi4buZIHBo4bqtbiBzdXJ2aXZhbCkuDQoNClbhu4EgY8ahIGLhuqNuLCBwYWNrYWdlIEpNQmF5ZXMgY8OzIGPhuqV1IHRyw7pjIG1ldGhvZCBnaeG7kW5nIG5oxrAgcGFja2FnZSBKTSAoc+G7rSBk4bulbmcgUkVNTCkuIFBoxrDGoW5nIHBow6FwIEJheWVzIGNo4buJIMOhcCBk4bulbmcgdHLDqm4gam9pbnQgbW9kZWwsIG5oxrBuZyAyIG3DtCBow6xuaCB0aMOgbmggcGjhuqduIExvbmd0dWRpbmFsIHbDoCBTdXJ2aXZhbCB24bqrbiDEkcaw4bujYyBk4buxbmcgdGhlbyBjw6FjaCB0cnV54buBbiB0aOG7kW5nIHThu6sgYsOqbiB0cm9uZyBob+G6t2MgYsOqbiBuZ2/DoGkgKEpNIHbDoCBKTWJheWVzIHTGsMahbmcgdGjDrWNoIHbhu5tpIG1peGVkIG1vZGVsIG9iamVjdCBj4bunYSBwYWNrYWdlIG5sbWUgKDIwMTQpIGhheSBNQVNTIHbDoCBDb3hwaCBtb2RlbCBj4bunYSBwYWNrYWUgc3Vydml2YWwgKDIwMTQpLiBDw6FjIGjDoG0gbG1lLCBjb3hwaCgpIHbDoCBjw7ogcGjDoXAgY+G7p2EgY2jDum5nIMSRxrDhu6NjIHTDrWNoIGjhu6NwIHPhurVuIHRyb25nIEpNIHbDoCBKTSBCYXllcy4gSMOgbSBqb2ludE1vZGVsQmF5ZXMoKSBz4bq9IGThu7FuZyBqb2ludCBtb2RlbC4gDQoNCktoaSBz4butIGThu6VuZyBjw6FjaCB0aeG6v3AgY+G6rW4gdGhlbyB0csaw4budbmcgcGjDoWkgQmF5ZXMsIHRhIG114buRbiB4w6FjIMSR4buLbmggcGjDom4gcGjhu5FpIGjhuq11IG5naGnhu4dtIGPhu6dhIHRvw6BuIGLhu5kgY8OhYyB2ZWN0b3IgdGhhbSBz4buRIHRyb25nIGpvaW50IG1vZGVsLCBiYW8gZ+G7k20gY+G6oyB2ZWN0b3IgcmFuZG9tIGVmZmVjdCBiaS4NCg0KTeG7mXQgY8OhY2ggxJHGoW4gZ2nhuqNuLCBOaGkgY2jhu4kgY8OzIHRo4buDIGdp4bqjaSB0aMOtY2ggbMOgIHTDoWMgZ2nhuqMgUml6b3BvdWxvcyDEkcOjIGTDuW5nIG5o4buvbmcgY2h14buXaSBNYXJrb3YgTW9udGUgQ2FybG8gKE1DTUMpIHbhu5tpIGFsZ29yaXRobSBNZXRyb3BvbGlzIEhhc3RpbmdzLiBOaOG7r25nIGNodeG7l2kgTUNNQyBuw6B5IGPDsyB0aOG7gyDEkcaw4bujYyB0csOtY2ggeHXhuqV0IHNhdSDEkcOzIMSR4buDIGto4bqjbyBzw6F0Lg0KDQpOZ2/DoGkgcmEgSlBCYXllcyBjw7MgbeG7mXQgc+G7kSBjaOG7qW5nIG7Eg25nIG7Dom5nIGNhbyBzbyB24bubaSBKTSwgbsOzIGNobyBwaMOpcCBt4bufIHLhu5luZyBoaeG7h3Ug4bupbmcgbGnDqm4gaOG7hyB0cm9uZyBqb2ludCBtb2RlbCB24bubaSBuaOG7r25nIHRoYW0gc+G7kSBwaG8gdHV54bq/biB0w61uaCBi4buVIHN1bmcsIG7DsyBjxaluZyBjaG8gcGjDqXAgbMOgbSBCYXllc2lhbiBtb2RlbCBBdmVyYWdpbmcgKEJNQSkgxJHhu4Mga+G6v3QgaOG7o3Agbmhp4buBdSBtw7QgaMOsbmggSm9pbnQgbW9kZWwga2jDoWMgbmhhdSBjaG8gdmnhu4djIHRpw6puIGzGsOG7o25nLg0KDQpDaGkgdGnhur90IGvhu7kgdGh14bqtdCBj4bunYSBwYWNrYWdlIGPDsyB0aOG7gyB0aGFtIGto4bqjbyB0cm9uZyBiw6BpIGLDoW86DQoNCjxodHRwOi8vY2l0ZXNlZXJ4LmlzdC5wc3UuZWR1L3ZpZXdkb2MvZG93bmxvYWQ/ZG9pPTEwLjEuMS40MDkuNDUyNCZyZXA9cmVwMSZ0eXBlPXBkZj4NCg0KVMOhYyBnaeG6oyBjxaluZyB04burbmcgbMOgbSAxIHdlYm1pbmFyIG7Eg20gMjAxNDoNCg0KPGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9dnFHcFFtbnVwMFk+DQoNCkLDoGkgdGjhu7FjIGjDoG5oIG7DoHkgY2jhu4kgdHLDrG5oIGLDoHkgbeG7mXQgdGjDrSBk4bulIGPGoSBi4bqjbiB24bubaSAxIGNvdmFyaWF0ZSB2w6AgQXNzb2NpYXRpb24gZWZmZWN0IMSRxqFuIGdp4bqjbi4NCg0KIyBNaW5oIGjhu41hOiBQcm90aHJvbWJpbiB2w6AgUHJlZG5pc29uZS8gQuG7h25oIFjGoSBnYW4NCg0KVGjDrSBk4bulIG1pbmggaOG7jWEgdHJvbmcgYsOgaSBz4butIGThu6VuZyBkYXRhc2V0IHByb3Rocm8uIMSQw6J5IGzDoCBt4buZdCBuZ2hpw6puIGPhu6l1IHRo4butIG5naGnhu4dtIGzDom0gc8OgbmcgdHLDqm4gNDg4IGLhu4duaCBuaMOibiBYxqEgZ2FuLiBDw7MgaGFpIGJp4bq/biBz4buRIG91dGNvbWUsIG3hu5l0IGzDoCBtYWtlciBwcm90aHJvbWJpbiAobeG7mXQgeeG6v3UgdOG7kSDEkcO0bmcgbcOhdSksIMSRxrDhu6NjIGto4bqjbyBzw6F0IHThuqFpIHRo4budaSDEkWnhu4NtIHplcm8sIHNhdSDEkcOzIGzhurdwIGzhuqFpIG3hu5dpIHRow6FuZywgaGFpIGzDoCBz4buxIGtp4buHbiB04butIHZvbmcuIE3hu5dpIGLhu4duaCBuaMOibiBjw7MgdGjhu4MgxJHGsOG7o2MgxJFvIHByb3Rocm9tYmluIHThu5FpIMSRYSDEkeG6v24gMTcgbOG6p24uIFnhur91IHThu5EgY2FuIHRoaeG7h3AgbMOgIDIgcGjGsMahbmcgcGjDoXAgxJFp4buBdSB0cuG7iyBi4bqxbmcgcHJlZG5pc29uZSB2w6AgcGxhY2Viby4gTmjGsCBiw6BpIHRyxrDhu5tjLCBt4bulYyB0acOqdSBj4bunYSBjaMO6bmcgdGEgbMOgIGto4bqjbyBzw6F0IGxpw6puIGjhu4cgZ2nhu69hIHPhu7EgdGhheSDEkeG7lWkgY+G7p2EgbWFya2VyIHByb3Rocm9tYmluIHRoZW8gdGjhu51pIGdpYW4gdsOgIHnhur91IHThu5EgxJFp4buBdSB0cuG7iyDEkeG7kWkgduG7m2kgbmd1eSBjxqEgdOG7rSB2b25nIGPhu6dhIGLhu4duaCBuaMOibiB4xqEgZ2FuLg0KDQpUcsaw4bubYyBo4bq/dCB0YSB04bqjaSAxIHPhu5EgcGFja2FnZSxkYXRhc2V0IGFpZHMgbuG6sW0gdHJvbmcgcGFja2FnZSBKTQ0KDQpgYGB7cn0NCmxpYnJhcnkoSk1iYXllcykgIyBwYWNrYWdlIGThu7FuZyBKb2ludCBtb2RlbCBi4bqxbmcgcGjGsMahbmcgcGjDoXAgQmF5ZXMNCmxpYnJhcnkodGlkeXZlcnNlKSAjIGRhdGEgd3JhbmdsaW5nIHbDoCBnZ3Bsb3QNCmxpYnJhcnkobWFncml0dHIpICMgVG/DoW4gdOG7rSBwaXBlDQpsaWJyYXJ5KGdna20pICNUaMSDbSBkw7IgVGltZSBldmVudCBkYXRhDQpgYGANCg0KIyBUaMSDbSBkw7IgZOG7ryBsaeG7h3UNCg0KVHLGsOG7m2MgaOG6v3QsIGNow7puZyB0YSB2aeG6v3QgbeG7mXQgdsOgaSDEkW/huqFuIGNvZGUgxJHhu4MgbcO0IHThuqMgZOG7ryBsaeG7h3UgYuG6sW5nIG5o4buvbmcgY29uIHPhu5EuIE3hu5l0IHPhu5EgY8OidSBo4buPaSBjw7MgdGjhu4MgxJHhurd0IHJhIDogDQoNCjEpIEPhuqV1IHRyw7pjIGThu68gbGnhu4d1ID8gQ8OzIDIgxJHhu4tuaCBk4bqhbmcga2jDoWMgbmhhdSBj4bunYSBkYXRhc2V0LCAxIGNobyBsb25naXR1ZGluYWwgc3R1ZHkgdsOgIDEgY2hvIHN1cnZpdmFsIHN0dWR5Lg0KDQpHaGkgY2jDujogaWQgbMOgIG3DoyBz4buRIMSR4buLbmggZGFuaCBjaG8gYuG7h25oIG5ow6JuOyBwcm8gbMOgIGdpw6EgdHLhu4sgcHJvdGhyb21iaW4sIHRyZWF0IGzDoCBwaMOibiBuaMOzbSDEkWnhu4F1IHRy4buLLCB0aW1lIGzDoCB0aOG7nWkgxJFp4buDbSBt4buXaSB2aXNpdCB0w61uaCB04burIGLhuq90IMSR4bqndSBuZ2hpw6puIGPhu6l1OyBUaW1lIGzDoCB0aOG7nWkgZ2lhbiB0aGVvIGTDtWkgdOG7kWkgxJFhIMSR4bq/biBraGkgYuG7h25oIG5ow6JuIHThu60gdm9uZyBob+G6t2MgY2Vuc29yZWQsIHN0YXJ0IGzDoCBt4buRYyB0aOG7nWkgZ2lhbiBraOG7n2kgxJHhuqd1IG3hu5dpIHBow6JuIMSRb+G6oW4gdGhlbyBkw7VpLCBzdG9wIGzDoCBt4buRYyB0aOG7nWkgZ2lhbiBr4bq/dCB0aMO6YyBt4buXaSBwaMOibiDEkW/huqFuLCBkZWF0aCBsw6AgYmnhur9uIHPhu5EgeMOhYyBuaOG6rW4gYuG7h25oIG5ow6JuIHThu60gdm9uZyBob+G6t2MgY2Vuc29yZWQsIGV2ZW50IGzDoCB0cuG6oW5nIHRow6FpIHPhu7Ega2nhu4duIHThuqFpIG3hu5dpIHRo4budaSDEkWnhu4NtLiANCg0KYGBge3J9DQpwcm90aHJvJT4lZmlsdGVyKGlkPT1jKCIyIiwiOCIpKSU+JWtuaXRyOjprYWJsZSgpDQoNCnByb3Rocm9zJT4laGVhZCgpJT4la25pdHI6OmthYmxlKCkNCg0KYGBgDQoNCjIpIFThu5VuZyBz4buRIGLhu4duaCBuaMOibiA/IENvbiBz4buRIG7DoHkgbMOgIDQ4OCANCg0KYGBge3IsbWVzc2FnZSA9IEZBTFNFLHdhcm5pbmc9RkFMU0V9DQpwcm90aHJvJGlkJT4lDQogIHVuaXF1ZSgpICU+JQ0KICBsZW5ndGgoKQ0KYGBgDQoNCjMpIEPDsyBiYW8gbmhpw6p1IGLhu4duaCBuaMOibiDEkcOjIHThu60gdm9uZyA/IFRo4budaSBnaWFuIHRoZW8gZMO1aSB0cnVuZyBiw6xuaCBj4bunYSBt4buXaSBi4buHbmggbmjDom4gbMOgIGJhbyBuaGnDqnU6IA0KDQpL4bq/dCBxdeG6oyBjaG8gdGjhuqV5IHRo4budaSBnaWFuIHRydW5nIGLDrG5oIMSR4bq/biBraGkgbeG6pXQgdGhlbyBkw7VpIGhheSBr4bq/dCB0aMO6Y3RoZW8gZMO1aSBsw6AgNC44IHRow6FuZyAoY2FvIG5o4bqldCAxMy4zOSwgdGjhuqVwIG5o4bqldCAwLjA2KSwgdGjhu51pIGdpYW4gdHJ1bmcgYsOsbmggxJHhur9uIGtoaSB04butIHZvbmcgbMOgIDIuODcgdGjDoW5nICgwLjAxIMSR4bq/biAxMC4zMyB0aMOhbmcpDQpU4buJIGzhu4cgdOG7rSB2b25nL2NlbnNvcmVkIGzDoCAyOTIvMTk2DQoNCmBgYHtyfQ0KcHJvdGhyb3MlPiVtdXRhdGUoLixEZWF0aD1pZmVsc2UoLiRkZWF0aD09MSwiRGVhZCIsIkNlbnNvcmVkIikpJT4lDQp7cHN5Y2g6OmRlc2NyaWJlQnkoLiRUaW1lLGdyb3VwPS4kRGVhdGgpfQ0KYGBgDQoNCjQpIE3hu5dpIHBow6JuIG5ow7NtIMSRaeG7gXUgdHLhu4sgY8OzIGJhbyBuaGnDqnUgYuG7h25oIG5ow6JuID8gSOG7jSDEkcaw4bujYyB0aGVvIGTDtWkgdHJvbmcgYmFvIGzDonUgPw0KDQpOaMOzbSDEkWnhu4F1IHRy4buLIHbhu5tpIFByZWRuaXNvbmUgY8OzIDIzNyBi4buHbmggbmjDom4sIG5ow7NtIFBsYWNlYm8gY8OzIDI1MSBi4buHbmggbmjDom4uIFRo4budaSBnaWFuIHRoZW8gZMO1aSB0cnVuZyBiw6xuaCB0xrDGoW5nIOG7qW5nIGzDoCAzLjYzIHbDoCAzLjY2IHRow6FuZw0KDQpgYGB7cn0NCnByb3Rocm9zJT4lbXV0YXRlKC4sRGVhdGg9aWZlbHNlKC4kZGVhdGg9PTEsIkRlYWQiLCJDZW5zb3JlZCIpKSU+JQ0KICB7cHN5Y2g6OmRlc2NyaWJlQnkoLiRUaW1lLC4kdHJlYXQpfQ0KYGBgDQoNCjUpIFBow6JuIGLhu5EgY8OhYyB0csaw4budbmcgaOG7o3AgdOG7rSB2b25nID8NCg0KYGBge3J9DQpwcm90aHJvcyU+JW11dGF0ZSguLERlYXRoPWlmZWxzZSguJGRlYXRoPT0xLCJEZWFkIiwiQ2Vuc29yZWQiKSklPiUNCiAgeHRhYnMoZGF0YT0uLH5EZWF0aCt0cmVhdCkNCmBgYA0KDQo2KSBHacOhIHRy4buLIHByb3Rocm9tYmluIGPGoSBi4bqjbiBsw7pjIGLhuq90IMSR4bqndSBuZ2hpw6puIGPhu6l1IGzDoCBiYW8gbmhpw6p1ID8NCg0KYGBge3J9DQpwYXN0ZSgiUHJvdGhyb21iaW4gVDA6IEdp4buvYSAyIHBow6JuIG5ow7NtIMSRaeG7gXUgdHLhu4siKQ0KcHJvdGhybyU+JWZpbHRlciguJHRpbWU9PTApJT4lDQp7cHN5Y2g6OmRlc2NyaWJlQnkoLiRwcm8sLiR0cmVhdCl9DQoNCmBgYA0KDQoNCmBgYHtyfQ0KcGFzdGUoIlByb3Rocm9tYmluIFQwOiBHaeG7r2EgQ8OzL0tow7RuZyBjw7MgdOG7rSB2b25nIikNCnByb3Rocm8lPiVmaWx0ZXIoLiR0aW1lPT0wKSU+JQ0KICBtdXRhdGUoLixEZWF0aD1pZmVsc2UoLiRkZWF0aD09MSwiRGVhZCIsIkNlbnNvcmVkIikpJT4lDQogIHtwc3ljaDo6ZGVzY3JpYmVCeSguJHBybywuJERlYXRoKX0NCmBgYA0KDQpCw6J5IGdp4budIHRhIHPhur0gdHLDrG5oIGLDoHkgdGjDtG5nIHRpbiBi4bqxbmcgYmnhu4N1IMSR4buTOg0KDQpIw6xuaCAxKSBT4buRIGzhuqduIHZpc2l0IOG7nyBt4buXaSBi4buHbmggbmjDom4gY8OzIHRo4buDIGRhbyDEkeG7mW5nIHThu6sgMSDEkeG6v24gMTcgbOG6p24NCg0KYGBge3J9DQpwcm90aHJvJT4lbXV0YXRlKC4sRGVhdGg9aWZlbHNlKC4kZGVhdGg9PTEsIkRlYWQiLCJDZW5zb3JlZCIpKSU+JQ0KICBnZ3Bsb3QoYWVzKHg9aWQsZmlsbD1EZWF0aCkpKw0KICBzdGF0X2JpbihiaW53aWR0aD0xLHNob3cubGVnZW5kID0gRikrDQogIHN0YXRfYmluKGJpbndpZHRoPTEsIGdlb209InRleHQiLCBhZXMobGFiZWw9Li5jb3VudC4uKSxzaXplPTMpKw0KICB0aGVtZV9idygpKw0KICBjb29yZF9mbGlwKCkrDQogIGZhY2V0X2dyaWQodHJlYXR+RGVhdGgpKw0KICBsYWJzKHRpdGxlPSJWaXNpdHMgY291bnQiLHg9IlBhdGllbnQgSWQiLHk9Ik51bWJlciBvZiBWaXNpdHMiKQ0KDQpgYGANCg0KSMOsbmggMjogRGnhu4VuIHRp4bq/biBj4bunYSBwcm90aHJvbWJpbiBy4bqldCBraMOhYyBuaGF1IOG7nyBt4buXaSBi4buHbmggbmjDom4sIG5oxrBuZyBuaMOsbiBjaHVuZyA6IG5o4buvbmcgYuG7h25oIG5ow6JuIHThu60gdm9uZyBjw7MgcHJvdGhyb21iaW4gdGjhuqVwIGjGoW4sIHBow6JuIG5ow7NtIHByZWRuaXNvbmUgY8OzIHByb3Rocm9tYmluIHRo4bqlcCBoxqFuIHBow6JuIG5ow7NtIHBsYWNlYm8NCg0KYGBge3J9DQpsaWJyYXJ5KGNvbG9yUmFtcHMpDQpsaWJyYXJ5KFJDb2xvckJyZXdlcikgDQoNCm15cGFsZXR0ZSA9IGxlbmd0aCh1bmlxdWUocHJvdGhybyRpZCkpDQpnZXRQYWxldHRlID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJTcGVjdHJhbCIpKQ0KDQpwcm90aHJvJT4lbXV0YXRlKC4sRGVhdGg9aWZlbHNlKC4kZGVhdGg9PTEsIkRlYWQiLCJDZW5zb3JlZCIpKSU+JQ0KICBnZ3Bsb3QoKSsNCiAgZ2VvbV9wYXRoKGFlcyh4PXRpbWUseT1wcm8sY29sb3I9YXMuZmFjdG9yKGlkKSksc2hvdy5sZWdlbmQgPSBGLGFscGhhPTAuNikrDQogIGdlb21fc21vb3RoKGFlcyh4PWFzLm51bWVyaWModGltZSkseT1wcm8sZmlsbD10cmVhdCxsaW5ldHlwZT10cmVhdCksDQogICAgICAgICAgICAgIGNvbG9yPSJibGFjayIsDQogICAgICAgICAgICAgIG1ldGhvZD0ibG0iLGZvcm11bGEgPSB5IH4gc3BsaW5lczo6YnMoeCwzKSxhbHBoYT0wLjQpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZ2V0UGFsZXR0ZShteXBhbGV0dGUpKSsNCiAgZmFjZXRfd3JhcCh+RGVhdGgpKw0KICB0aGVtZV9idygpDQoNCmBgYA0KDQpIw6xuaCAzYSxiKTogR2nhuqMgc+G7rSB0YSBjaGlhIMSR4buBdSB0aOG7nWkgZ2lhbiB0aGVvIGTDtWkgdGjDoG5oIDExIHbhu4sgdHLDrTogR2nDoSB0cuG7iyBwcm90aHJvbWJpbiB0cnVuZyBiw6xuaCB04bqhaSBt4buXaSB0aOG7nWkgxJFp4buDbSBsw6AgbmjGsCBzYXU6DQoNCmBgYHtyfQ0KcHJvdGhybyU+JW11dGF0ZSguLERlYXRoPWlmZWxzZSguJGRlYXRoPT0xLCJEZWF0aCIsIlN1cnZpdmVkIikpJT4lDQogIGdncGxvdChhZXMoeT1wcm8seD1kZWF0aCxmaWxsPXRyZWF0KSkrDQogIGdlb21fYm94cGxvdChhbHBoYT0wLjUpKw0KICBjb29yZF9mbGlwKCkrDQogIGZhY2V0X3dyYXAofnJvdW5kKHRpbWUsMCksbmNvbD0zKSsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCk5oxrAgduG6rXkgdOG6oWkgbeG7l2kgdGjhu51pIMSRaeG7g20sIGPDsyB24bq7IG5oxrAga2jDtG5nIGPDsyBz4buxIHTGsMahbmcgcGjhuqNuIHLDtSBy4buHdCBnaeG7r2EgMiBwaMOibiBuaMOzbSDEkWnhu4F1IHRy4buLDQoNCmBgYHtyfQ0KcHJvdGhybyU+JW11dGF0ZSguLERlYXRoPWlmZWxzZSguJGRlYXRoPT0xLCJEZWF0aCIsIlN1cnZpdmVkIikpJT4lDQogIGdncGxvdChhZXMoeD1wcm8sZmlsbD10cmVhdCkpKw0KICBnZW9tX2RlbnNpdHkoYWxwaGE9MC41KSsNCiAgZmFjZXRfd3JhcCh+cm91bmQodGltZSwwKSxzY2FsZXM9ImZyZWVfeSIsbmNvbD0zKSsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCkjDrG5oIDRhLGIpIE3DtCBow6xuaCByYW5kb20gaW50ZXJjZXB0IHbDoCByYW5kb20gc2xvcGUgduG7m2kgbmF0dXJhbCBjdWJpYyBzcGxpbmU6DQoNCk7hur91IHjDqXQgcmnDqm5nIGLDoGkgdG/DoW4gbG9uZ2l0dWRpbmFsIGNobyBwcm90aHJvbWJpbiwgdGEgY8OzIHRo4buDIGTDuW5nIG3DtCBow6xuaCBtaXhlZCBtb2RlbCAocmFuZG9tIGludGVyY2VwdCBob+G6t2MgcmFuZG9tIHNsb3BlKS4gVHJvbmcgbcO0IGjDrG5oIG7DoHkgYmnhur9uIGvhur90IHF14bqjIGzDoCBwcm90aHJvbWJpbuG7nyB0aGFuZyDEkW8gbG9nYXJpdCwgcGjhu6UgdGh14buZYyB2w6BvIHRo4budaSBnaWFuIChoYXkgbsOzaSBjw6FjaCBraMOhYzogdGjhu51pIMSRaeG7g20gbOG6pXkgbeG6q3UgPSBiaeG6v24gdGltZSkuIE3hurd0IGtow6FjLCB0aGVvIHF1YW4gc8OhdCBiYW4gxJHhuqd1IHRhIGPDsyB0aOG7gyBuaOG6rW4gcmEgbMOgIGRp4buFbiB0aeG6v24gY+G7p2EgcHJvdGhyb21iaW4gKGJp4bq/biBr4bq/dCBxdeG6oykgdGhlbyB0aOG7nWkgZ2lhbiDEkWkgdGhlbyBt4buZdCBs4buZIHRyw6xuaCBwaGkgdHV54bq/biB0w61uaCwgZG8gxJHDsyB0YSBjw7MgdGjhu4MgInXhu5FuIGNvbmciIMSR4buTIHRo4buLIGPhu6dhIG3DtCBow6xuaCB24bubaSBt4buZdCBow6BtIG5hdHVyYWwgY3ViaWMgc3BsaW5lIChow6BtIG7DoHkgxJHGsOG7o2MgdMOtY2ggaOG7o3Agc+G6tW4gdHJvbmcgcGFja2FnZSBKTWJheWVzKS4gS+G6v3QgcXXhuqMgY+G7p2EgbcO0IGjDrG5oIG5oxrAgc2F1IA0KDQoqTcO0IGjDrG5oIHJhbmRvbSBpbnRlcmNlcHQgduG7m2kgbmF0dXJhbCBjdWJpYyBzcGxpbmUqDQoNCmBgYHtyfQ0KcmludD1sbWUobG9nKHBybykgfiBucyh0aW1lLDMpLCANCiAgICAgICAgIHJhbmRvbSA9IH4gMSB8IGlkLA0KICAgICAgICAgZGF0YSA9IHByb3Rocm8pDQoNCnByb3Rocm8lPiVtdXRhdGUoLixGaXR0ZWQ9cHJlZGljdChyaW50KSklPiUNCiAgZ2dwbG90KCkrDQogIGdlb21fcGF0aChhZXMoeD1hcy5udW1lcmljKHRpbWUpLHk9Rml0dGVkLGNvbG9yPWFzLmZhY3RvcihpZCkpLA0KICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGLA0KICAgICAgICAgICAgYWxwaGE9MC4xKSsNCiAgZ2VvbV9zbW9vdGgoYWVzKHg9YXMubnVtZXJpYyh0aW1lKSx5PUZpdHRlZCksDQogICAgICAgICAgICAgIG1ldGhvZD0ibG0iLGFscGhhPTAuNSwNCiAgICAgICAgICAgICAgZm9ybXVsYT15fm5zKHgsMyksc2U9RiwNCiAgICAgICAgICAgIHNob3cubGVnZW5kID0gRixjb2xvcj0icmVkIikrDQogIHNjYWxlX2NvbG9yX2dyZXkoKSsNCiAgdGhlbWVfYncoKSsNCiAgbGFicyh0aXRsZT0iUmFuZG9tIEludGVyY2VwdCBtb2RlbDogWX5ucyh0aW1lLDMpKzF8SWQiLHg9IlRpbWUiLHk9IlByZWRpY3RlZCBwcm90aHJvbWIgKExvZyBzY2FsZSkiKQ0KDQpgYGANCg0KKk3DtCBow6xuaCByYW5kb20gc2xvcGUgduG7m2kgbmF0dXJhbCBjdWJpYyBzcGxpbmUqDQoNCmBgYHtyfQ0KcnNsb3BlPWxtZShsb2cocHJvKSB+IG5zKHRpbWUsMyksIA0KICAgICAgICAgcmFuZG9tID0gfiBucyh0aW1lLDMpIHwgaWQsDQogICAgICAgICBkYXRhID0gcHJvdGhybykNCg0KcHJvdGhybyU+JW11dGF0ZSguLEZpdHRlZD1wcmVkaWN0KHJzbG9wZSkpJT4lDQogIGdncGxvdCgpKw0KICBnZW9tX3BhdGgoYWVzKHg9YXMubnVtZXJpYyh0aW1lKSwNCiAgICAgICAgICAgICAgICB5PUZpdHRlZCxjb2xvcj1hcy5mYWN0b3IoaWQpKSwNCiAgICAgICAgICAgIHNob3cubGVnZW5kID0gRiwNCiAgICAgICAgICAgIGFscGhhPTAuMSkrDQogIGdlb21fc21vb3RoKGFlcyh4PWFzLm51bWVyaWModGltZSkseT1GaXR0ZWQpLA0KICAgICAgICAgICAgICBtZXRob2Q9ImxtIixhbHBoYT0wLjUsDQogICAgICAgICAgICAgIGZvcm11bGE9eX5ucyh4LDMpLHNlPUYsDQogICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYsY29sb3I9InJlZCIpKw0KICBzY2FsZV9jb2xvcl9ncmV5KCkrDQogIHRoZW1lX2J3KCkrDQogIGxhYnModGl0bGU9IlJhbmRvbSBTbG9wZSBtb2RlbDogWX5ucyh0aW1lLDMpKyBucyh0aW1lLDMpfElkIix4PSJUaW1lIix5PSJQcmVkaWN0ZWQgcHJvdGhyb21iIChMb2cgc2NhbGUpIikNCg0KYGBgDQoNCkjDjG5oIDUgYSxiLGMsZCk6IA0KDQpUaeG6v3AgdGhlbyBjaMO6bmcgdGEgeMOpdCDEkeG6v24gYsOgaSB0b8OhbiB24buBIG5ndXkgY8ahIHThu60gdm9uZyAoc3Vydml2YWwgc3R1ZHkpOyAzIGjDrG5oIHRo4bupYyBraMOhYyBuaGF1IGPhu6dhIGJp4buDdSDEkeG7kyBLYXBsYW4tTWVpZXIgxJHGsOG7o2MgdHLDrG5oIGLDoHkgdHJvbmcgaMOsbmggNSwgY2jDum5nIG3DtCB04bqjIGjDoG0gc3Vydml2YWwsIGjDoG0gbmd1eSBjxqEgdsOgIGjDoG0gQ0RGIHRoZW8gdGjhu51pIGdpYW4gcGjDom4gYmnhu4d0IGNobyAyIG5ow7NtIMSRaeG7gXUgdHLhu4suDQoNCk7hur91IGtow7RuZyB4w6l0IMSR4bq/biB54bq/dSB04buRIHByb3Rocm9tYmluLCBuZ3V5IGPGoSB04butIHZvbmcgY8OzIHbhursgY2FvIGjGoW4g4bufIG5ow7NtIHByZWRuaXNvbmUgc28gduG7m2kgbmjDs20gcGxhY2Vibw0KDQpgYGB7cn0NCmxpYnJhcnkoc3Vydm1pbmVyKQ0KbGlicmFyeShzdXJ2aXZhbCkNCg0KZml0IDwtIHN1cnZmaXQoU3VydihUaW1lLCBkZWF0aCkgfiB0cmVhdCwgZGF0YSA9IHByb3Rocm8pDQoNCmdnc3VydnBsb3QoZml0LCANCiAgICAgICAgICAgZGF0YSA9IHByb3Rocm8sDQogICAgICAgICAgIHNpemU9MSwNCiAgICAgICAgICAgY29uZi5pbnQgPSBUUlVFLA0KICAgICAgICAgICBwdmFsID0gVFJVRSwNCiAgICAgICAgICAgcmlzay50YWJsZSA9IFRSVUUsIA0KICAgICAgICAgICByaXNrLnRhYmxlLmNvbCA9ICJzdHJhdGEiLA0KICAgICAgICAgICByaXNrLnRhYmxlLmhlaWdodCA9IDAuMywNCiAgICAgICAgICAgZ2d0aGVtZSA9IHRoZW1lX2J3KCksDQogICAgICAgICAgIHJpc2sudGFibGUueS50ZXh0LmNvbCA9IFQsIA0KICAgICAgICAgICByaXNrLnRhYmxlLnkudGV4dCA9IEZBTFNFDQopDQpgYGANCg0KYGBge3J9DQojIEtNIHBsb3RzDQoNCmdncGxvdChwcm90aHJvcywgDQogICAgICAgYWVzKHRpbWUgPSBUaW1lLCBzdGF0dXMgPSBkZWF0aCwgZmlsbCA9IHRyZWF0LCBjb2xvciA9IHRyZWF0KSkrIA0KICBnZW9tX2ttKCkrIA0KICBnZW9tX2ttYmFuZCgpKw0KICB0aGVtZV9idygpDQoNCmdncGxvdChwcm90aHJvcywgDQogICAgICAgYWVzKHRpbWUgPSBUaW1lLCBzdGF0dXMgPSBkZWF0aCwgZmlsbCA9IHRyZWF0LCBjb2xvciA9IHRyZWF0KSkrIA0KICBnZW9tX2ttKHRyYW5zID0gImN1bWhheiIpKyANCiAgZ2VvbV9rbWJhbmQodHJhbnMgPSAiY3VtaGF6IikrDQogIHRoZW1lX2J3KCkrIHlsYWIoIkN1bXVsYXRpdmUgaGF6YXJkIikNCg0KZ2dwbG90KHByb3Rocm9zLCANCiAgICAgICBhZXModGltZSA9IFRpbWUsIHN0YXR1cyA9IGRlYXRoLCBmaWxsID0gdHJlYXQsIGNvbG9yID0gdHJlYXQpKSsgDQogIGdlb21fa20odHJhbnMgPSAiZXZlbnQiKSsgDQogIGdlb21fa21iYW5kKHRyYW5zID0gImV2ZW50IikrDQogIHRoZW1lX2J3KCkrIHlsYWIoIkN1bXVsYXRpdmUgRXZlbnRzIChDREYpIikNCmBgYA0KDQpIw6xuaCA2YSkgVGEgY8WpbmcgY8OzIHRo4buDIHNvIHPDoW5oIG5ndXkgY8ahIHThu60gdm9uZyBnaeG7r2EgMiBwaMOibiBuaMOzbSBjw7MgZ2nDoSB0cuG7iyBQcm90aHJvbWJpbiDhu58gdGjhu51pIMSRaeG7g20gVDAgY2FvIGjGoW4gdsOgIHRo4bqlcCBoxqFuIG5nxrDhu6FuZyB0cnVuZyB24buLIHRyb25nIG3huqt1IG5naGnDqm4gY+G7qXU6DQoNCkPDoWMgYuG7h25oIG5ow6JuIGPDsyBwcm90aHJvbWJpbiBiYW4gxJHhuqd1IChUMCkgdGjhuqVwIGjGoW4gdHJ1bmcgduG7iyB0aMOsIGPDsyBuaGnhu4F1IG5ndXkgY8ahIHThu60gdm9uZyBoxqFuLg0KDQpgYGB7cn0NCnByb3Rocm8lPiVmaWx0ZXIodGltZT09MC4wKSU+JW11dGF0ZSguLFBybz1pZmVsc2UoLiRwcm8+PW1lZGlhbiguJHBybyksIkhpZ2giLCJMb3ciKSklPiUNCmdncGxvdChhZXModGltZSA9IFRpbWUsIHN0YXR1cyA9IGRlYXRoLCBmaWxsID0gUHJvLCBjb2xvciA9IFBybykpKyANCiAgZ2VvbV9rbSh0cmFucyA9ICJjdW1oYXoiKSsgDQogIGdlb21fa21iYW5kKHRyYW5zID0gImN1bWhheiIpKw0KICB0aGVtZV9idygpKw0KICBmYWNldF93cmFwKH50cmVhdCkrDQogIHlsYWIoIkN1bXVsYXRpdmUgSGF6YXJkIikNCmBgYA0KDQpUxrDGoW5nIHThu7EsIG7hur91IGNo4buJIHjDqXQgZ2nDoSB0cuG7iyBwcm90aHJvbWJpbiDhu58gdGjhu51pIMSRaeG7g20gY3Xhu5FpIGPDuW5nIChuZ2F5IHRyxrDhu5tjIGtoaSBjZW5zb3JlIGhheSB04butIHZvbmcpOiBnacOhIHRy4buLIHByb3Rocm9tYmluIHRo4bqlcCBjxaluZyBjw7MgbGnDqm4gaOG7hyB24bubaSBuZ3V5IGPGoSB04butIHZvbmc6DQoNCmBgYHtyfQ0KcHJvdGhybyU+JWZpbHRlcihUaW1lPT1zdG9wKSU+JW11dGF0ZSguLFBybz1pZmVsc2UoLiRwcm8+PW1lZGlhbiguJHBybyksIkhpZ2giLCJMb3ciKSklPiUNCiAgZ2dwbG90KGFlcyh0aW1lID0gVGltZSwgc3RhdHVzID0gZGVhdGgsIGZpbGwgPSBQcm8sIGNvbG9yID0gUHJvKSkrIA0KICBnZW9tX2ttKHRyYW5zID0gImN1bWhheiIpKyANCiAgZ2VvbV9rbWJhbmQodHJhbnMgPSAiY3VtaGF6IikrDQogIHRoZW1lX2J3KCkrDQogIGZhY2V0X3dyYXAofnRyZWF0KSsNCiAgeWxhYigiQ3VtdWxhdGl2ZSBIYXphcmQiKQ0KYGBgDQoNClR1eSBuaGnDqm4sIHRhIGtow7RuZyB0aOG7gyBjaOG7iSBraOG6o28gc8OhdCBtYXJrZXIgIFByb3Rocm9tYmluIGR1eSBuaOG6pXQgdOG6oWkgMiB0aOG7nWkgxJFp4buDbSDEkOG6p3UgdsOgIEN14buRaSwgbcOgIHRhIG114buRbiBraOG6o28gc8OhdCB0b8OgbiBi4buZIGRp4buFbiB0aeG6v24gY+G7p2EgbWFya2VyIG7DoHkgdsOgIGtp4buDbSB0cmEgbGnhu4d1IGPDsyBsacOqbiBo4buHIGdp4buvYSBkaeG7hW4gdGnhur9uIG7DoHkgduG7m2kgeeG6v3UgdOG7kSDEkWnhu4F1IHRy4buLIGfDonkgdGhheSDEkeG7lWkgbmd1eSBjxqEgdOG7rSB2b25nIGhheSBraMO0bmcgP0RvIMSRw7MgdGEgc+G6vSBz4butIGThu6VuZyBKb2ludCBtb2RlbA0KDQojIEThu7FuZyBKb2ludCBNb2RlbCB0aGVvIHBoxrDGoW5nIHBow6FwIEJheWVzDQoNCipNw7QgaMOsbmggYuG7mSBwaOG6rW4gdGjhu6kgbmjhuqV0OiBMb25naXR1ZGluYWwqDQoNCsSQ4bqndSB0acOqbiwgY2jDum5nIHRhIGThu7FuZyBt4buZdCBtw7QgaMOsbmggdHV54bq/biB0w61uaCBo4buXbiBo4bujcCAoTWl4ZWQgbW9kZWwpIGNobyBkaeG7hW4gdGnhur9uIGPhu6dhIHByb3Rocm9tYmluIHRoZW8gdGjhu51pIGdpYW4uIEJp4bq/biBr4bq/dCBxdeG6oyBj4bunYSBtw7QgaMOsbmggbMOgIGdpw6EgdHLhu4sgcHJvdGhyb21iaW4g4bufIHRoYW5nIMSRbyBsb2dhcml0LiBOaMawIMSRw6MgbsOzaSDhu58gdHLDqm4sIHPhu7EgdGhheSDEkeG7lWkgdGhlbyB0aOG7nWkgZ2lhbiDhu58gxJFhIHPhu5EgYuG7h25oIG5ow6JuIGzDoCBraMO0bmcgdHV54bq/biB0w61uaCwgZG8gxJHDsyBOaGkgc+G6vSBz4butIGThu6VuZyBow6BtIG5hdHVyYWwgY3ViaWMgc3BsaW5lIGNobyBj4bqjIDIgaGnhu4d1IOG7qW5nOiBGaXhlZCB2w6AgcmFuZG9tIHRyb25nIG3DtCBow6xuaC4gTmjGsCB24bqteSDEkcOieSBjaMOtbmggbMOgIDEgbcO0IGjDrG5oIHJhbmRvbSBzbG9wZS4NCg0KYGBge3J9DQpsbWVGaXQ9bG1lKGxvZyhwcm8pfm5zKHRpbWUsIDMpLA0KICAgICAgICAgICAgICAgICAgICBkYXRhID0gcHJvdGhybywNCiAgICAgICAgICAgICAgICAgICAgcmFuZG9tID0gfiBucyh0aW1lLCAzKSB8IGlkKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShsbWVGaXQpDQpgYGANCg0KYGBge3J9DQpwbG90KGxtZUZpdCkNCmBgYA0KDQpgYGB7cn0NCm15cGFsZXR0ZSA9IGxlbmd0aCh1bmlxdWUocHJvdGhybyRpZCkpDQpnZXRQYWxldHRlID0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksIlJkQnUiKSkNCg0KcHJvdGhybyU+JW11dGF0ZSguLEZpdHRlZD1wcmVkaWN0KGxtZUZpdCkpJT4lDQogIGdncGxvdCgpKw0KICBnZW9tX3BvaW50KGFlcyh4PWFzLm51bWVyaWModGltZSksDQogICAgICAgICAgICAgICAgeT1sb2cocHJvKSxjb2xvcj1hcy5mYWN0b3IoaWQpKSxhbHBoYT0wLjIsc2hvdy5sZWdlbmQgPSBGKSsNCiAgZ2VvbV9wYXRoKGFlcyh4PWFzLm51bWVyaWModGltZSksDQogICAgICAgICAgICAgICAgeT1GaXR0ZWQsY29sb3I9YXMuZmFjdG9yKGlkKSksDQogICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEYsDQogICAgICAgICAgICBhbHBoYT0wLjIpKw0KICBnZW9tX3Ntb290aChhZXMoeD1hcy5udW1lcmljKHRpbWUpLHk9Rml0dGVkKSwNCiAgICAgICAgICAgICAgbWV0aG9kPSJsbSIsYWxwaGE9MC41LA0KICAgICAgICAgICAgICBmb3JtdWxhPXl+bnMoeCwzKSxzZT1GLA0KICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGLGNvbG9yPSJibGFjayIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KGdldFBhbGV0dGUobXlwYWxldHRlKSkpKw0KICB0aGVtZV9idygpKw0KICBsYWJzKHRpdGxlPSJSYW5kb20gU2xvcGUgbW9kZWw6IFl+bnModGltZSwzKSsgbnModGltZSwzKXxJZCIseD0iVGltZSIseT0iUHJlZGljdGVkIHByb3Rocm9tYiAoTG9nIHNjYWxlKSIpDQpgYGANCg0KVGjDoG5oIHBo4bqnbiB0aOG7qSBoYWkgdHJvbmcgSm9pbnQgbW9kZWwgbMOgIG3hu5l0IG3DtCBow6xuaCBDb3hQSCwgY2jhu4kgY2jhu6lhIHnhur91IHThu5EgcGjDom4gbmjDs20gxJFp4buBdSB0cuG7iy4NCg0KYGBge3J9DQpjb3hGaXQ9Y294cGgoU3VydihUaW1lLGRlYXRoKSB+IHRyZWF0LCANCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBwcm90aHJvcywNCiAgICAgICAgICAgICAgICAgIHggPSBUUlVFKQ0KYGBgDQoNCg0KYGBge3J9DQpzdW1tYXJ5KGNveEZpdCkNCmBgYA0KDQpTYXUgxJHDsywgdGEgc+G6vSBk4buxbmcgSm9pbnQgTW9kZWwgY8ahIGLhuqNuIHbhu5tpIHBhY2thZ2UgSk1iYXllcyB24bubaSA1MCBuZ8OgbiBsxrDhu6N0IGzhuqV5IG3huqt1IGNobyBjaHXhu5dpIE1DTUMNCg0KYGBge3J9DQpqb2ludGZpdD1qb2ludE1vZGVsQmF5ZXMobG1lRml0LGNveEZpdCx0aW1lVmFyID0gInRpbWUiLG4uaXRlcj01MDAwMCkNCg0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShqb2ludGZpdCkNCmBgYA0KDQpgYGB7cn0NCmpvaW50Zml0JG1jbWMlPiVuYW1lcygpDQpgYGANCg0KQuG6o24gdMOzbSB04bqvdCBu4buZaSBkdW5nIG3DtCBow6xuaCBKb2ludCBtb2RlbCBjdW5nIGPhuqVwIGPDoWMgdGjDtG5nIHRpbiBiYW8gZ+G7k206DQoNClRo4buRbmcga8OqIHbhu4EgdMOtbmggcGjDuSBo4bujcCBj4bunYSBtw7QgaMOsbmgsIHPhu60gZOG7pW5nIExvZyBwc2V1ZG8gbWFyZ2luYWwgbGlrZWxpaG9vZCB2YWx1ZSAoTFBNTCksIGRldmlhbmNlIGluZm9ybWF0aW9uIGNyaXRlcmlvbiAoRElDKSB2w6Aga8OtY2ggdGjGsOG7m2MgY+G7p2EgdGjDoG5oIHBo4bqnbiB0aGFtIHPhu5EgdHJvbmcgRElDIChwRCkuDQoNClRydW5nIGLDrG5oIGPhu6dhIHBow6JuIHBo4buRaSBo4bqtdSBuZ2hp4buHbSBj4bunYSB04bqldCBj4bqjIGPDoWMgdGhhbSBz4buRIGjhu5NpIHF1eSwga8OobSB0aGVvIHNhaSBz4buRIGNodeG6qW4gKFNFKSB2w6Aga2hv4bqjbmcgdGluIGPhuq15IDk1JS4gTmjhu69uZyBr4bq/dCBxdeG6oyBuw6B5IMSRxrDhu6NjIMaw4bubYyB0w61uaCBk4buxYSB2w6BvIGNodeG7l2kgTUNNQyAoxJHGsOG7o2Mga2jhuqNvIHPDoXQgbmjGsCBt4buZdCB0aW1lIHNlcmllcyB2ZWN0b3IpLiBN4buZdCDEkWnhu4NtIHRow7ogduG7iyDEkcOzIGzDoCB0dXkgc+G7rSBk4bulbmcgcGjGsMahbmcgcGjDoXAgxrDhu5tjIGzGsOG7o25nIHRoYW0gc+G7kSBo4buTaSBxdXkgdGhlbyBCYXllcywgduG7m2kgcGjDom4gcGjhu5FpIGjhuq11IG5naGnhu4dtLCBuaMawbmcgcGFja2FnZSBKTWJheWVzIGzhuqFpIHRyw6xuaCBiw6B5IGvhur90IHF14bqjIHN1eSBkaeG7hW4gdGjhu5FuZyBrw6ogZMaw4bubaSBow6xuaCB0aOG7qWMgcC12YWx1ZSAodGFpbCBwcm9iYWJpbGl0eSB24bubaSBudWxsIGh5cG90aGVzaXMgdGVzdGluZyBuaMawIHRyb25nIHBoxrDGoW5nIHBow6FwIGZyZXF1ZW50aXN0KTogcCB2YWx1ZSDhu58gxJHDonkgY2jDrW5oIGzDoCB4w6FjIHN14bqldCB0aGFtIHPhu5EgaOG7k2kgcXV5IGzhu5tuIGjGoW4gaG/hurdjIG5o4buPIGjGoW4gemVyby4NCg0KUCB2YWx1ZSA9IDIgKiBtaW4geyBQcihiPjApLFByKGI8MCl9IHbhu5tpIGIgbMOgIHRoYW0gc+G7kSBo4buTaSBxdXkgY+G6p24ga2nhu4NtIHRyYQ0KDQpUaOG7sWMgcmEgY8OhY2ggc3V5IGRp4buFbiBuw6B5IGPFqW5nIHTGsMahbmcgxJHhu5NuZyBuaMawIHBoxrDGoW5nIHBow6FwIGPhu6dhIEpvaG4gS3J1c2Noa2UgZOG7sWEgdsOgbyAxIG5nxrDhu6FuZyDDvSBuZ2jEqWEgaGF5IDEga2hv4bqjbmcgdsO0IG5naMSpYSB0aOG7sWMgZOG7pW5nIChST1BFKSwgY2jhu4kga2jDoWMgbMOgIEtydXNjaGtlIGTDuW5nIG3huq10IMSR4buZIHjDoWMgc3XhuqV0IChiYW8gbmhpw6p1ICUgcGjDom4gcGjhu5FpIGjhuq11IG5naGnhu4dtIG7hurFtIHRyb25nL25nb8OgaSBST1BFIGhheSBu4bqxbSBiw6puIHRyw6FpL3Bo4bqjaSBuZ8aw4buhbmcgw70gbmdoxKlhKSBjw7JuIFJpem9wb3Vsb3MgZMO5bmcgeMOhYyBzdeG6pXQgcC4NCg0KUGjDom4gcGjhu5FpIGjhuq11IG5naGnhu4dtIGPhu6dhIHRoYW0gc+G7kSBo4buTaSBxdXkgxJHGsOG7o2MgbMawdSB0cuG7ryB0cm9uZyBjw6FjIGNodeG7l2kgTUNNQywgY8OzIHThuqV0IGPhuqMgOCBjaHXhu5dpIHTGsMahbmcg4bupbmcgduG7m2kgOCB0aMOgbmggcGjhuqduIHRyb25nIGpvaW50IG1vZGVsLiDhu54gxJHDonkgdGEgY2jhu4kga2jhuqNvIHPDoXQgbmjhu69uZyB0aMO0bmcgdGluIHF1YW4gdHLhu41uZyBuaOG6pXQgZ+G7k20gY8OzOg0KDQoqQ2h14buXaSBNQ01DIEJldGEqDQoNCkNodeG7l2kgTUNNQyBiZXRhIGNo4bupYSB0aGFtIHPhu5EgaOG7k2kgcXV5IGNobyB0aMOgbmggcGjhuqduIExvbmdpdHVkaW5hbCAobcO0IGjDrG5oIHJhbmRvbSBzbG9wZSDGsOG7m2MgdMOtbmggbG9nKHByb3Rocm9tYmluKSB04bqhaSB0aOG7nWkgxJFp4buDbSB0IGNobyBt4buZdCBjw6EgdGjhu4MgbmjhuqV0IMSR4buLbmgpLiANCg0KYGBge3J9DQpqb2ludGZpdCRtY21jJGJldGFzJT4laGVhZCgpJT4la25pdHI6OmthYmxlKCkNCmBgYA0KDQpgYGB7cn0NCg0KYmV0YWRmPWpvaW50Zml0JG1jbWMkYmV0YXMlPiVhc190aWJibGUoKQ0KDQpuYW1lcyhiZXRhZGYpPWMoIkludGVyY2VwdCIsIk5TX1RpbWUxIiwiTlNfVGltZTIiLCJOU19UaW1lMyIpDQoNCmJldGFkZiU+JWdhdGhlcihJbnRlcmNlcHQ6TlNfVGltZTMsa2V5PSJDb21wb25lbnRzIix2YWx1ZT0iQ29lZmZpY2llbnQiKSU+JQ0KICBnZ3Bsb3QoKSsNCiAgZ2VvbV9kZW5zaXR5KGFlcyh4PUNvZWZmaWNpZW50LGZpbGw9Q29tcG9uZW50cyksYWxwaGE9MC42KSsNCiAgdGhlbWVfYncoKSsNCiAgZmFjZXRfd3JhcCh+Q29tcG9uZW50cyxzY2FsZXM9ImZyZWUiLG5jb2w9MikNCg0KYmV0YWRmJT4lDQogIG11dGF0ZSguLEl0ZXI9YXMubnVtZXJpYyhyb3duYW1lcyguKSkpJT4lDQogIGdhdGhlcihJbnRlcmNlcHQ6TlNfVGltZTMsa2V5PSJDb21wb25lbnRzIix2YWx1ZT0iQ29lZmZpY2llbnQiKSU+JQ0KICBnZ3Bsb3QoKSsNCiAgZ2VvbV9wYXRoKGFlcyh4PUl0ZXIseT1Db2VmZmljaWVudCxjb2xvcj1Db21wb25lbnRzLGdyb3VwPTEpLGFscGhhPTAuNykrDQogIHRoZW1lX2J3KCkrDQogIGZhY2V0X3dyYXAofkNvbXBvbmVudHMsc2NhbGVzPSJmcmVlIixuY29sPTEpDQpgYGANCg0KKkNodeG7l2kgTUNNQyBzaWdtYSoNCg0KQ2h14buXaSBNQ01DIHNpZ21hIGNo4bupYSBwaMOibiBwaOG7kWkgaOG6rXUgbmdoaeG7h20gY+G7p2EgUmVzaWR1YWwgdHJvbmcgbcO0IGjDrG5oIHJhbmRvbSBzbG9wZToNCg0KYGBge3J9DQpqb2ludGZpdCRtY21jJHNpZ21hJT4laGVhZCgpDQpgYGANCg0KYGBge3J9DQpzaWdtYWRmPWpvaW50Zml0JG1jbWMkc2lnbWElPiVhc190aWJibGUoKQ0KDQpwMT1zaWdtYWRmJT4lZ2dwbG90KCkrDQogIGdlb21fZGVuc2l0eShhZXMoeD1zaWdtYSksYWxwaGE9MC42LGZpbGw9InJlZCIpKw0KICB0aGVtZV9idygpDQoNCnAyPXNpZ21hZGYlPiUNCiAgbXV0YXRlKC4sSXRlcj1hcy5udW1lcmljKHJvd25hbWVzKC4pKSklPiUNCiAgZ2dwbG90KCkrDQogIGdlb21fcGF0aChhZXMoeD1JdGVyLHk9c2lnbWEpLGFscGhhPTAuNyxjb2xvcj0icmVkIikrDQogIHRoZW1lX2J3KCkNCg0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocDEscDIsbmNvbD0xKQ0KYGBgDQoNCipDaHXhu5dpIE1DTUMgYioNCg0KQ2h14buXaSBiIGNo4bupYSBoaeG7h3Ug4bupbmcgbmfhuqt1IG5oacOqbiBjw6EgdGjhu4MgY2hvIEludGVyY2VwdCB2w6AgU2xvcGUsIMSRw6J5IGzDoCAxIG1hdHJpeCBy4bqldCBs4bubbiwgduG7m2kga8OtY2ggdGjGsOG7m2MgPSBz4buRIGzGsOG7o3QgbOG6pXkgbeG6q3UgKGtob+G6o25nIDgwMDApIHggc+G7kSB0aGFtIHPhu5EgdHJvbmcgbcO0IGjDrG5oIHggc+G7kSBi4buHbmggbmjDom4uDQoNCipDaHXhu5dpIGdhbW1hcyoNCg0KQ2h14buXaSBnYW1tYSBjaOG7qWEgcGjDom4gcGjhu5FpIGjhuq11IG5naGnhu4dtIGPhu6dhIGhp4buHdSDhu6luZyByacOqbmcgcGjhuqduIGPhu6dhIHnhur91IHThu5EgxJFp4buBdSB0cuG7iyB0cm9uZyBtw7QgaMOsbmggU3Vydml2YWwgKHRyZWF0cHJlZG5pc29uZSkuIA0KDQpgYGB7cn0NCmdhbW1hZGY9am9pbnRmaXQkbWNtYyRnYW1tYXMlPiVhc190aWJibGUoKQ0KDQpwMT1nYW1tYWRmJT4lZ2dwbG90KCkrDQogIGdlb21fZGVuc2l0eShhZXMoeD10cmVhdHByZWRuaXNvbmUpLGFscGhhPTAuNixmaWxsPSJwdXJwbGUiKSsNCiAgdGhlbWVfYncoKQ0KDQpwMj1nYW1tYWRmJT4lDQogIG11dGF0ZSguLEl0ZXI9YXMubnVtZXJpYyhyb3duYW1lcyguKSkpJT4lDQogIGdncGxvdCgpKw0KICBnZW9tX3BhdGgoYWVzKHg9SXRlcix5PXRyZWF0cHJlZG5pc29uZSksYWxwaGE9MC43LGNvbG9yPSJwdXJwbGUiKSsNCiAgdGhlbWVfYncoKQ0KDQpncmlkRXh0cmE6OmdyaWQuYXJyYW5nZShwMSxwMixuY29sPTEpDQpgYGANCg0KKkNodeG7l2kgQlMuZ2FtbWEqDQoNCkNodeG7l2kgQlMuZ2FtbWEgY2jhu6lhIHBow6JuIHBo4buRaSBo4bqtdSBuZ2hp4buHbSBjaG8gdGhhbSBz4buRIGjhu5NpIHF1eSBj4bunYSAxNyBwaMOibiDEkW/huqFuIHRo4budaSBnaWFuIHRyb25nIG3DtCBow6xuaCBTdXJ2aXZhbCwgZG8ga8OtY2ggdGjGsOG7m2MgY+G7p2EgbsOzIHF1w6EgbOG7m24gbsOqbiBjaMO6bmcgdGEgY8Wpbmcga2jDtG5nIGto4bqjbyBzw6F0IHPDonUgaMahbg0KDQpgYGB7cn0NCmJzZ2FtPWpvaW50Zml0JG1jbWMkQnMuZ2FtbWFzJT4lYXNfdGliYmxlKCkNCg0KYnNnYW0lPiVoZWFkKCklPiVrbml0cjo6a2FibGUoKQ0KDQpIbWlzYzo6ZGVzY3JpYmUoYnNnYW0pDQoNCmBgYA0KDQoqQ2h14buXaSBBbHBoYXMqDQoNCkNodeG7l2kgYWxwaGFzIGNo4bupYSB0aMO0bmcgdGluIHF1YW4gdHLhu41uZyBuaOG6pXQgdHJvbmcgbcO0IGjDrG5oIGpvaW50IG1vZGVsIG3DoCB0YSBxdWFuIHTDom0sIMSRw7MgbMOgIGjhu4d1IOG7qW5nIHTGsMahbmcgdMOhYyBnaeG7r2EgYuG7h25oIHPhu60gZGnhu4VuIHRp4bq/biBj4bunYSBwcm90aHJvbWJpbiB2w6AgcGjDom4gbmjDs20gxJFp4buBdSB0cuG7iyAoYXNzb2NpYXRpb24gZWZmZWN0KS4NCg0KYGBge3J9DQpqb2ludGZpdCRtY21jJGFscGhhcyU+JWhlYWQoKQ0KDQphbHBoYWRmPWpvaW50Zml0JG1jbWMkYWxwaGFzJT4lYXNfdGliYmxlKCkNCg0KcDE9YWxwaGFkZiU+JWdncGxvdCgpKw0KICBnZW9tX2RlbnNpdHkoYWVzKHg9QXNzb2N0KSxhbHBoYT0wLjYsZmlsbD0iZ29sZCIpKw0KICB0aGVtZV9idygpDQoNCnAyPWFscGhhZGYlPiUNCiAgbXV0YXRlKC4sSXRlcj1hcy5udW1lcmljKHJvd25hbWVzKC4pKSklPiUNCiAgZ2dwbG90KCkrDQogIGdlb21fcGF0aChhZXMoeD1JdGVyLHk9QXNzb2N0KSxhbHBoYT0wLjcsY29sb3I9Im9yYW5nZSIpKw0KICB0aGVtZV9idygpDQoNCmdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlKHAxLHAyLG5jb2w9MSkNCmBgYA0KDQojIOG7qG5nIGThu6VuZyBj4bunYSBtw7QgaMOsbmgNCg0KKlRpw6puIGzGsOG7o25nIGNobyBjw6EgdGjhu4MqDQoNCkNow7puZyB0YSBkw7luZyBtw7QgaMOsbmggbsOgeSDEkeG7gyB0acOqbiBsxrDhu6NuZyBjaG8gbeG7mXQgYuG7h25oIG5ow6JuIHRyb25nIG3huqt1IGto4bqjbyBzw6F0LCB0aMOtIGThu6Ugc+G7kSA5Lg0KDQpgYGB7cn0NCk5EID1wcm90aHJvW3Byb3Rocm8kaWQgPT0gOSwgXQ0KDQpsb25nZml0PXByZWRpY3Qoam9pbnRmaXQsIA0KICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBORCwgDQogICAgICAgICAgICAgICAgdHlwZSA9ICJTdWJqZWN0IiwNCiAgICAgICAgICAgICAgICBpbnRlcnZhbCA9ICJjb25maWRlbmNlIiwgDQogICAgICAgICAgICAgICAgcmV0dXJuID0gVFJVRSkNCg0Kc3VydmZpdD1zdXJ2Zml0Sk0oam9pbnRmaXQsbmV3ZGF0YSA9IE5EKQ0KDQpzdXJ2Zml0WzFdJHN1bW1hcmllcyRgOWAlPiVhc190aWJibGUoKS0+dGRmDQpyYmluZCh0ZGYsYygwLHJlcCgxLDQpKSktPnRkZg0KdGRmJT4lDQogIGdncGxvdChhZXMoeD10aW1lcykpKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbj1Mb3dlcix5bWF4PVVwcGVyKSxhbHBoYT0wLjUsZmlsbD0iZ29sZCIpKw0KICBnZW9tX2xpbmUoYWVzKHk9TWVkaWFuKSxjb2xvcj0icmVkMyIsc2l6ZT0xLGxpbmV0eXBlPTEpKw0KICBnZW9tX2xpbmUoYWVzKHk9TWVhbiksY29sb3I9ImJsdWUiLHNpemU9MSxsaW5ldHlwZT0xKSsNCiAgZ2VvbV9saW5lKGFlcyh5PUxvd2VyKSxjb2xvcj0iYmxhY2siLHNpemU9MSxsaW5ldHlwZT0yKSsNCiAgZ2VvbV9saW5lKGFlcyh5PVVwcGVyKSxjb2xvcj0iYmxhY2siLHNpemU9MSxsaW5ldHlwZT0yKSsNCiAgdGhlbWVfYncoKSsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PW1heChsb25nZml0JFRpbWUpLGNvbG9yPSJibHVlIixsaW5ldHlwZT0yKSsNCiAgbGFicyh0aXRsZT0iUGF0aWVudCBOwrA5Iix4PSJUaW1lIix5PSJQcmVkaWN0ZWQgc3Vydml2YWwgcHJvYmFiaWxpdHkiLGNhcHRpb249IkpvaW50IE1vZGVsIikNCg0KcGxvdChzdXJ2Zml0LCBlc3RpbWF0b3IgPSAibWVhbiIsIGluY2x1ZGUueSA9IFRSVUUsDQogICAgIGNvbmYuaW50ID0gVFJVRSwgZmlsbC5hcmVhID0gVFJVRSwgY29sLmFyZWEgPSAiZ29sZCIpDQoNCg0KbG9uZ2ZpdCU+JQ0KICBnZ3Bsb3QoYWVzKHg9dGltZSkpKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbj1sb3cseW1heD11cHApLGFscGhhPTAuNSxmaWxsPSJnb2xkIikrDQogIGdlb21fbGluZShhZXMoeT1wcmVkKSxjb2xvcj0icmVkMyIsc2l6ZT0xKSsNCiAgZ2VvbV9saW5lKGFlcyh5PWxvdyksY29sb3I9ImJsYWNrIixzaXplPTEsbGluZXR5cGU9MikrDQogIGdlb21fbGluZShhZXMoeT11cHApLGNvbG9yPSJibGFjayIsc2l6ZT0xLGxpbmV0eXBlPTIpKw0KICB0aGVtZV9idygpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9bWF4KGxvbmdmaXQkVGltZSksY29sb3I9ImJsdWUiLGxpbmV0eXBlPTIpKw0KICBsYWJzKHRpdGxlPSJQYXRpZW50IE7CsDkiLHg9IlRpbWUiLHk9IlByZWRpY3RlZCBwcm90aHJvbWIgKExvZyBzY2FsZSkiLGNhcHRpb249IkpvaW50IE1vZGVsIikNCg0KYGBgDQoNCiMgS+G6v3QgbHXhuq1uDQoNCkpvaW50IG1vZGVsIGzDoCBt4buZdCBwaMawxqFuZyBwaMOhcCBo4buvdSDDrWNoLCB2w6AgcGFja2FnZSBKTWJheWVzIGzDoCBt4buZdCBjw6FjaCB0aeG6v3AgY+G6rW4gdGjDuiB24buLLCB24bubaSBwaMawxqFuZyBwaMOhcCBCYXllcyAoTUNNQykgbGFpIHbhu5tpIG51bGwgaHlwb3RoZXNpcyB0ZXN0aW5nIHbDoCBsb2cgcHNldWRvIGxpa2VsaWhvb2QsIG5o4bqxbSDGsOG7m2MgdMOtbmggaOG7hyBz4buRIGjhu5NpIHF1eSBjaG8gSm9pbnQgbW9kZWwuIA0KDQpO4bq/dSBi4bqhbiB0w6xtIGhp4buDdSBzw6J1IGjGoW4gbuG7mWkgZHVuZyBwYWNrYWdlLCBz4bq9IHRo4bqleSBraOG6oyBuxINuZyBj4bunYSBuw7MgcuG7mW5nIGjGoW4gcuG6pXQgbmhp4buBdSBzbyB24bubaSBwaMawxqFuZyBwaMOhcCBSRU1MIHRyb25nIGLDoGkgdHLGsOG7m2MsIHbDoCB0aMOtIGThu6UgY8ahIGLhuqNuIG3DoCB0YSB24burYSB0aOG7sWMgaGnhu4duLg0KDQpDaMO6YyBjw6FjIGLhuqFuIHRow6BuaCBjw7RuZy4NCg0KKipYaW4gY+G6o20gxqFuIHbDoCBo4bq5biBn4bq3cCBs4bqhaS4qKg0K