1 Missing data

Missing data là những giá trị dữ liệu bị thiếu trong dataset được kí hiệu là NA hoặc để trống hoặc 99, .v.v. Nếu dataset của bạn có từ 10% missing data trở lên thì rất nhiều khả năng là các phép phân tích, dự đoán thống kê khó có thể cho được kết quả chính xác.

Có nhiều cách để giải quyết vấn đề missing data sao cho kết quả đáng tin cậy nhất. Trước hết, chúng ta phải biết mức độ “trầm trọng” của missing data lớn đến mức nào, xảy ra với biến số nào và những dòng dữ liệu nào đã bị missing.

Hai packages thường sử dụng để giải quyết vần đề này là VIM (visualization and imputation of missing values) và MICE (Multivariate Imputation via Chained Equations).

1.1 Chuẩn bị dữ liệu

Bộ dữ liệu sleep trong package “VIM” được chọn để minh họa cho chủ đề này.

library(VIM)
library(mice)
data(sleep, package="VIM")
head(sleep)
##    BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
## 1 6654.000   5712.0   NA    NA   3.3 38.6  645    3   5      3
## 2    1.000      6.6  6.3   2.0   8.3  4.5   42    3   1      3
## 3    3.385     44.5   NA    NA  12.5 14.0   60    1   1      1
## 4    0.920      5.7   NA    NA  16.5   NA   25    5   2      3
## 5 2547.000   4603.0  2.1   1.8   3.9 69.0  624    3   5      4
## 6   10.550    179.5  9.1   0.7   9.8 27.0  180    4   4      4

Dataset ‘sleep’ là bộ dữ liệu về giấc ngủ của một loài động vật có vú, gồm 62 cá thể và 10 biến số:

BodyWgt: Cân nặng BrainWgt: Cân nặng bộ não
NonD: Thời gian ngủ không có giấc mơ
Dream: Thời gian ngủ có giấc mơ
Sleep: Thời gian ngủ tổng cộng
Span
Gest
Pred
Exp
Danger

….

1.2 Đánh giá mức độ Missing Data trong bộ dữ liệu

Với head(sleep), rõ ràng ta thấy trong “sleep” có những giá trị bị missing được gán cho chữ NA. Để biết có những biến số nào bị missing ta dùng lệnh sau:

sleep[!complete.cases(sleep),]
##     BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
## 1  6654.000   5712.0   NA    NA   3.3 38.6  645    3   5      3
## 3     3.385     44.5   NA    NA  12.5 14.0   60    1   1      1
## 4     0.920      5.7   NA    NA  16.5   NA   25    5   2      3
## 13    0.550      2.4  7.6   2.7  10.3   NA   NA    2   1      2
## 14  187.100    419.0   NA    NA   3.1 40.0  365    5   5      5
## 19    1.410     17.5  4.8   1.3   6.1 34.0   NA    1   2      1
## 20   60.000     81.0 12.0   6.1  18.1  7.0   NA    1   1      1
## 21  529.000    680.0   NA   0.3    NA 28.0  400    5   5      5
## 24  207.000    406.0   NA    NA  12.0 39.3  252    1   4      1
## 26   36.330    119.5   NA    NA  13.0 16.2   63    1   1      1
## 30  100.000    157.0   NA    NA  10.8 22.4  100    1   1      1
## 31   35.000     56.0   NA    NA    NA 16.3   33    3   5      4
## 35    0.122      3.0  8.2   2.4  10.6   NA   30    2   1      1
## 36    1.350      8.1  8.4   2.8  11.2   NA   45    3   1      3
## 41  250.000    490.0   NA   1.0    NA 23.6  440    5   5      5
## 47    4.288     39.2   NA    NA  12.5 13.7   63    2   2      2
## 53   14.830     98.2   NA    NA   2.6 17.0  150    5   5      5
## 55    1.400     12.5   NA    NA  11.0 12.7   90    2   2      2
## 56    0.060      1.0  8.1   2.2  10.3  3.5   NA    3   1      2
## 62    4.050     17.0   NA    NA    NA 13.0   38    3   1      1

Trên đây là tập hợp những rows có ít nhất một NA. Khi dataset của chúng ta lớn và có nhiều NA thì chúng ta cần có một báo cáo tóm tắt về các rows và columns chứa NA. Để có điều đó chúng ta dùng lệnh sau:

md.pattern(sleep)
##    BodyWgt BrainWgt Pred Exp Danger Sleep Span Gest Dream NonD   
## 42       1        1    1   1      1     1    1    1     1    1  0
##  2       1        1    1   1      1     1    0    1     1    1  1
##  3       1        1    1   1      1     1    1    0     1    1  1
##  9       1        1    1   1      1     1    1    1     0    0  2
##  2       1        1    1   1      1     0    1    1     1    0  2
##  1       1        1    1   1      1     1    0    0     1    1  2
##  2       1        1    1   1      1     0    1    1     0    0  3
##  1       1        1    1   1      1     1    0    1     0    0  3
##          0        0    0   0      0     4    4    4    12   14 38

Giải thích báo cáo:

Với giá trị ’1" cho biết không NA, và “0” là có NA. Cột thứ nhất cho biết số lượng row chứa các giá trị dữ liệu tương ứng bên phải. Cột cuối cùng cho biết có bao nhiêu NA trong dòng tương ứng. Hàng cuối cùng bên dưới cho biết tổng số NA có trong cột tương ứng ở trên.

Như vậy, chúng ta có 42 row không bị NA, có 2 row có 1 NA ở biến số Span, có 3 row có một NA ở biến số Gest, có 9 row có 2 NA ở Dream và NonD. Và lần lượt đến dòng cuối cùng, cho biết có tổng cộng 38 giá trị NA trong sleep, trong đó NonD có 14 NA, Dream có 12 NA và Gest có 4 NA, ….

Với VIM, các NA được biểu diễn bằng biểu đồ cho chúng ta thấy hình ảnh dễ hiểu hơn:

mice_plot <- aggr(sleep, col=c('navyblue','yellow'),
                  numbers=TRUE, sortVars=TRUE,
                  labels=names(sleep), cex.axis=.7,
                  gap=3, ylab=c("Missing data","Pattern"))

## 
##  Variables sorted by number of missings: 
##  Variable      Count
##      NonD 0.22580645
##     Dream 0.19354839
##     Sleep 0.06451613
##      Span 0.06451613
##      Gest 0.06451613
##   BodyWgt 0.00000000
##  BrainWgt 0.00000000
##      Pred 0.00000000
##       Exp 0.00000000
##    Danger 0.00000000

Màu vàng biểu thị NA, màu xanh không phải NA. Biểu đồ bên trái cho thấy phần trăm mà các biến số tương ứng có giá trị NA. Biểu đồ bên phải cho biết phân trăm của các kiểu phối hợp NA giữa các biến số. Cuối cùng là tổng cộng có 67.7% dữ liệu không bị NA. Với mức độ 32.3% missing là khá lớn trong dataset này.

Đến đây chúng ta đã có được một cái nhìn tổng thể về mức độ trầm trọng như thế nào trong vấn đề missing data của bộ dữ liệu mà chúng ta đang có ý định phân tích.

Vì vậy thay thế các giá trị NA như thế nào cho phù hợp là một yêu cầu thiết thực, nếu không thì chỉ còn chưa đến 70% dữ liệu có thể phân tích được mà thôi.

2 Xử trí các NAs

2.1 Nguyên tắc

  1. Đơn giản nhất là chúng ta xem kĩ từng NA để hiểu vì sao chúng bị missing. Tra cứu lại tài liệu nguồn như bệnh án nghiên cứu, phiếu điều tra đối tượng, để lấy thông tin bổ sung cho giá trị NA nếu chúng đã bị nhập sót dữ liệu.

  2. Nếu đó là một row nhập lỗi, bị lặp lại, chúng ta xóa row ấy khỏi dataset.

  3. Nếu missing data là rãi rác ở các dòng có tính ngẫu nhiên (MAR: Missing At Random) thì chúng ta có thể thay thế chúng bằng các giá trị có thể là:

  • Mean hoặc Median đối với biến liên tục
  • Giá trị thường xuất hiện nếu đó là biến rời rạc

2.2 MICE

MICE giả định rằng dữ liệu bị mất là Missing at Random (MAR), có nghĩa là xác suất mà một giá trị bị thiếu chỉ phụ thuộc vào giá trị quan sát được và có thể dự đoán chúng bằng các giá trị cùng chủng loại. Nó tính dữ liệu missing dựa vào qui luật biến thiên của các biến số trong dataset.

Ví dụ: Giả sử chúng ta có các biến X1, X2 … .Xk. Nếu X1 có các giá trị còn thiếu, thì nó sẽ được hồi quy trên các biến khác từ X2 đến Xk. Các giá trị còn thiếu trong X1 sẽ được thay thế bằng các giá trị mà nó dự đoán từ các biến số còn lại. Tương tự, nếu X2 có các giá trị còn thiếu, thì các biến X1, X3 đến Xk sẽ được sử dụng trong mô hình dự đoán như các biến độc lập. Sau đó, giá trị còn thiếu sẽ được thay thế bằng giá trị dự đoán.

Theo mặc định, hồi quy tuyến tính được sử dụng để dự đoán giá trị missing của biến liên tục. Hồi quy logistic được sử dụng cho giá trị thiếu trong biến rời rạc. Khi chu kỳ này hoàn tất, nhiều bộ dữ liệu được tạo ra. Những bộ dữ liệu này chỉ khác nhau trong các giá trị bị thiếu. Nói chung, đây được coi là một phương pháp hay để xây dựng các mô hình trên các bộ dữ liệu riêng rẽ và có thể kết hợp các kết quả của chúng.

Chính xác, các phương pháp được sử dụng bởi package MICE là:

PMM (Predictive Mean Matching) - Đối với các biến số liên tục Logreg (Logistic Regression) - Đối với các biến nhị phân (với 2 level) Polyreg (hồi qui đa thức Bayesian) - Đối với các biến factor (>= 2 level) Mô hình tỷ lệ chênh (có thứ tự,>= 2 level)

Với sleep, chúng ta thực hành thay thế NA cho các biến liên tục bằng phương pháp “pmm” với m = 5 (multiple imputations), tức là 5 lần thay thế, sau đó chọn ra missing subset nào chúng ta muốn chọn.

imputed_Data <- mice(sleep, m=5, maxit = 50, method = 'pmm', seed = 500, print=FALSE)
head(imputed_Data)
## $call
## mice(data = sleep, m = 5, method = "pmm", maxit = 50, printFlag = FALSE, 
##     seed = 500)
## 
## $data
##     BodyWgt BrainWgt NonD Dream Sleep  Span  Gest Pred Exp Danger
## 1  6654.000  5712.00   NA    NA   3.3  38.6 645.0    3   5      3
## 2     1.000     6.60  6.3   2.0   8.3   4.5  42.0    3   1      3
## 3     3.385    44.50   NA    NA  12.5  14.0  60.0    1   1      1
## 4     0.920     5.70   NA    NA  16.5    NA  25.0    5   2      3
## 5  2547.000  4603.00  2.1   1.8   3.9  69.0 624.0    3   5      4
## 6    10.550   179.50  9.1   0.7   9.8  27.0 180.0    4   4      4
## 7     0.023     0.30 15.8   3.9  19.7  19.0  35.0    1   1      1
## 8   160.000   169.00  5.2   1.0   6.2  30.4 392.0    4   5      4
## 9     3.300    25.60 10.9   3.6  14.5  28.0  63.0    1   2      1
## 10   52.160   440.00  8.3   1.4   9.7  50.0 230.0    1   1      1
## 11    0.425     6.40 11.0   1.5  12.5   7.0 112.0    5   4      4
## 12  465.000   423.00  3.2   0.7   3.9  30.0 281.0    5   5      5
## 13    0.550     2.40  7.6   2.7  10.3    NA    NA    2   1      2
## 14  187.100   419.00   NA    NA   3.1  40.0 365.0    5   5      5
## 15    0.075     1.20  6.3   2.1   8.4   3.5  42.0    1   1      1
## 16    3.000    25.00  8.6   0.0   8.6  50.0  28.0    2   2      2
## 17    0.785     3.50  6.6   4.1  10.7   6.0  42.0    2   2      2
## 18    0.200     5.00  9.5   1.2  10.7  10.4 120.0    2   2      2
## 19    1.410    17.50  4.8   1.3   6.1  34.0    NA    1   2      1
## 20   60.000    81.00 12.0   6.1  18.1   7.0    NA    1   1      1
## 21  529.000   680.00   NA   0.3    NA  28.0 400.0    5   5      5
## 22   27.660   115.00  3.3   0.5   3.8  20.0 148.0    5   5      5
## 23    0.120     1.00 11.0   3.4  14.4   3.9  16.0    3   1      2
## 24  207.000   406.00   NA    NA  12.0  39.3 252.0    1   4      1
## 25   85.000   325.00  4.7   1.5   6.2  41.0 310.0    1   3      1
## 26   36.330   119.50   NA    NA  13.0  16.2  63.0    1   1      1
## 27    0.101     4.00 10.4   3.4  13.8   9.0  28.0    5   1      3
## 28    1.040     5.50  7.4   0.8   8.2   7.6  68.0    5   3      4
## 29  521.000   655.00  2.1   0.8   2.9  46.0 336.0    5   5      5
## 30  100.000   157.00   NA    NA  10.8  22.4 100.0    1   1      1
## 31   35.000    56.00   NA    NA    NA  16.3  33.0    3   5      4
## 32    0.005     0.14  7.7   1.4   9.1   2.6  21.5    5   2      4
## 33    0.010     0.25 17.9   2.0  19.9  24.0  50.0    1   1      1
## 34   62.000  1320.00  6.1   1.9   8.0 100.0 267.0    1   1      1
## 35    0.122     3.00  8.2   2.4  10.6    NA  30.0    2   1      1
## 36    1.350     8.10  8.4   2.8  11.2    NA  45.0    3   1      3
## 37    0.023     0.40 11.9   1.3  13.2   3.2  19.0    4   1      3
## 38    0.048     0.33 10.8   2.0  12.8   2.0  30.0    4   1      3
## 39    1.700     6.30 13.8   5.6  19.4   5.0  12.0    2   1      1
## 40    3.500    10.80 14.3   3.1  17.4   6.5 120.0    2   1      1
## 41  250.000   490.00   NA   1.0    NA  23.6 440.0    5   5      5
## 42    0.480    15.50 15.2   1.8  17.0  12.0 140.0    2   2      2
## 43   10.000   115.00 10.0   0.9  10.9  20.2 170.0    4   4      4
## 44    1.620    11.40 11.9   1.8  13.7  13.0  17.0    2   1      2
## 45  192.000   180.00  6.5   1.9   8.4  27.0 115.0    4   4      4
## 46    2.500    12.10  7.5   0.9   8.4  18.0  31.0    5   5      5
## 47    4.288    39.20   NA    NA  12.5  13.7  63.0    2   2      2
## 48    0.280     1.90 10.6   2.6  13.2   4.7  21.0    3   1      3
## 49    4.235    50.40  7.4   2.4   9.8   9.8  52.0    1   1      1
## 50    6.800   179.00  8.4   1.2   9.6  29.0 164.0    2   3      2
## 51    0.750    12.30  5.7   0.9   6.6   7.0 225.0    2   2      2
## 52    3.600    21.00  4.9   0.5   5.4   6.0 225.0    3   2      3
## 53   14.830    98.20   NA    NA   2.6  17.0 150.0    5   5      5
## 54   55.500   175.00  3.2   0.6   3.8  20.0 151.0    5   5      5
## 55    1.400    12.50   NA    NA  11.0  12.7  90.0    2   2      2
## 56    0.060     1.00  8.1   2.2  10.3   3.5    NA    3   1      2
## 57    0.900     2.60 11.0   2.3  13.3   4.5  60.0    2   1      2
## 58    2.000    12.30  4.9   0.5   5.4   7.5 200.0    3   1      3
## 59    0.104     2.50 13.2   2.6  15.8   2.3  46.0    3   2      2
## 60    4.190    58.00  9.7   0.6  10.3  24.0 210.0    4   3      4
## 61    3.500     3.90 12.8   6.6  19.4   3.0  14.0    2   1      1
## 62    4.050    17.00   NA    NA    NA  13.0  38.0    3   1      1
## 
## $m
## [1] 5
## 
## $nmis
##  BodyWgt BrainWgt     NonD    Dream    Sleep     Span     Gest     Pred 
##        0        0       14       12        4        4        4        0 
##      Exp   Danger 
##        0        0 
## 
## $imp
## $imp$BodyWgt
## NULL
## 
## $imp$BrainWgt
## NULL
## 
## $imp$NonD
##       1    2    3    4    5
## 1   3.2  3.2  3.2  2.1  2.1
## 3  10.9 11.0 11.0 10.6 11.0
## 4  13.2 15.2 15.2 14.3 13.2
## 14  3.2  3.3  3.2  3.2  2.1
## 21  7.4  8.2  8.1  8.4  8.4
## 24  8.6 10.8 10.9  8.4  9.1
## 26 10.4 10.9 10.9 10.8 10.9
## 30  8.4 10.0  8.1  9.1  8.4
## 31  8.3  6.3  7.7  5.2  4.9
## 41 10.8  7.4  8.4  9.7 11.9
## 47 10.8 11.0 11.0 10.6  8.4
## 53  2.1  3.3  3.3  2.1  3.3
## 55 10.4 10.9  8.2  8.3  8.3
## 62 10.6 11.0 10.9 13.8 10.9
## 
## $imp$Dream
##      1   2   3   4   5
## 1  0.5 0.0 0.5 2.0 0.5
## 3  1.4 1.5 1.4 2.0 1.5
## 4  3.1 1.3 1.3 2.2 3.1
## 14 0.5 0.5 0.5 0.3 0.9
## 24 3.4 1.3 1.2 3.9 2.6
## 26 2.4 2.0 2.2 2.0 2.0
## 30 2.3 0.9 2.8 1.8 2.3
## 31 0.8 2.0 0.5 0.8 0.6
## 47 1.8 1.5 1.5 1.9 3.4
## 53 0.6 0.5 0.0 0.6 0.5
## 55 0.6 0.0 2.6 2.7 2.6
## 62 2.0 2.2 2.3 3.9 2.3
## 
## $imp$Sleep
##       1    2    3    4    5
## 21  8.2  8.3  8.3  8.4  8.6
## 31  9.7  8.0  8.4  5.4  5.4
## 41 12.5  8.3  9.1 10.7 13.2
## 62 13.0 13.2 12.8 17.4 13.0
## 
## $imp$Span
##       1    2   3    4    5
## 4   3.2  3.0 2.6 12.0  3.5
## 13 19.0 24.0 5.0  2.6 19.0
## 35 24.0  7.6 7.0 24.0 16.3
## 36  3.0 13.0 3.0  4.5  3.0
## 
## $imp$Gest
##      1   2   3   4   5
## 13  42 200  19  19  19
## 19 112 164 230 225 115
## 20  12  17 120  14  12
## 56  25  17  38  21 200
## 
## $imp$Pred
## NULL
## 
## $imp$Exp
## NULL
## 
## $imp$Danger
## NULL
## 
## 
## $method
##  BodyWgt BrainWgt     NonD    Dream    Sleep     Span     Gest     Pred 
##    "pmm"    "pmm"    "pmm"    "pmm"    "pmm"    "pmm"    "pmm"    "pmm" 
##      Exp   Danger 
##    "pmm"    "pmm"

Mỗi một biến số có NA, MICE sẽ cho ra 5 subsets có thể thay thế được. Trong 5 lần imputations trên, tôi muốn chọn subset thứ 3 để thay thế chính thức cho những NA trong “sleep”, vì thế tôi dùng lệnh như sau:

completeData <- complete(imputed_Data,3)
head(completeData, 20)
##     BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
## 1  6654.000   5712.0  3.2   0.5   3.3 38.6  645    3   5      3
## 2     1.000      6.6  6.3   2.0   8.3  4.5   42    3   1      3
## 3     3.385     44.5 11.0   1.4  12.5 14.0   60    1   1      1
## 4     0.920      5.7 15.2   1.3  16.5  2.6   25    5   2      3
## 5  2547.000   4603.0  2.1   1.8   3.9 69.0  624    3   5      4
## 6    10.550    179.5  9.1   0.7   9.8 27.0  180    4   4      4
## 7     0.023      0.3 15.8   3.9  19.7 19.0   35    1   1      1
## 8   160.000    169.0  5.2   1.0   6.2 30.4  392    4   5      4
## 9     3.300     25.6 10.9   3.6  14.5 28.0   63    1   2      1
## 10   52.160    440.0  8.3   1.4   9.7 50.0  230    1   1      1
## 11    0.425      6.4 11.0   1.5  12.5  7.0  112    5   4      4
## 12  465.000    423.0  3.2   0.7   3.9 30.0  281    5   5      5
## 13    0.550      2.4  7.6   2.7  10.3  5.0   19    2   1      2
## 14  187.100    419.0  3.2   0.5   3.1 40.0  365    5   5      5
## 15    0.075      1.2  6.3   2.1   8.4  3.5   42    1   1      1
## 16    3.000     25.0  8.6   0.0   8.6 50.0   28    2   2      2
## 17    0.785      3.5  6.6   4.1  10.7  6.0   42    2   2      2
## 18    0.200      5.0  9.5   1.2  10.7 10.4  120    2   2      2
## 19    1.410     17.5  4.8   1.3   6.1 34.0  230    1   2      1
## 20   60.000     81.0 12.0   6.1  18.1  7.0  120    1   1      1

Đến đây chúng ta đã có bộ dữ liệu hoàn thiện “completeData” có thể được sử dụng để phân tích, xây dựng mô hình hồi qui…

Cám ơn các bạn đã đọc bài viết này. Mong nhận được những lời góp ý, bàn luận để cùng học tập và tiến bộ.

LS0tDQp0aXRsZTogIljhu60gTMOtIE1pc3NpbmcgRGF0YSBW4bubaSBNSUNFIHbDoCBWSU0iDQpzdWJ0aXRsZTogIljhu60gTMOtIE1pc3NpbmcgRGF0YSINCmF1dGhvcjogIk5ndXllbiBOZ29jIFRoaWV1Ig0KZGF0ZTogIjIyIEF1Z3VzdCAyMDE3Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogImRlZmF1bHQiDQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyBNaXNzaW5nIGRhdGENCg0KTWlzc2luZyBkYXRhIGzDoCBuaOG7r25nIGdpw6EgdHLhu4sgZOG7ryBsaeG7h3UgYuG7iyB0aGnhur91IHRyb25nIGRhdGFzZXQgxJHGsOG7o2Mga8OtIGhp4buHdSBsw6AgTkEgaG/hurdjIMSR4buDIHRy4buRbmcgaG/hurdjIDk5LCAudi52LiBO4bq/dSBkYXRhc2V0IGPhu6dhIGLhuqFuIGPDsyB04burIDEwJSBtaXNzaW5nIGRhdGEgdHLhu58gbMOqbiB0aMOsIHLhuqV0IG5oaeG7gXUga2jhuqMgbsSDbmcgbMOgIGPDoWMgcGjDqXAgcGjDom4gdMOtY2gsIGThu7EgxJFvw6FuIHRo4buRbmcga8OqIGtow7MgY8OzIHRo4buDIGNobyDEkcaw4bujYyBr4bq/dCBxdeG6oyBjaMOtbmggeMOhYy4gDQoNCkPDsyBuaGnhu4F1IGPDoWNoIMSR4buDIGdp4bqjaSBxdXnhur90IHbhuqVuIMSR4buBIG1pc3NpbmcgZGF0YSBzYW8gY2hvIGvhur90IHF14bqjIMSRw6FuZyB0aW4gY+G6rXkgbmjhuqV0LiBUcsaw4bubYyBo4bq/dCwgY2jDum5nIHRhIHBo4bqjaSBiaeG6v3QgbeG7qWMgxJHhu5kgInRy4bqnbSB0cuG7jW5nIiBj4bunYSBtaXNzaW5nIGRhdGEgbOG7m24gxJHhur9uIG3hu6ljIG7DoG8sIHjhuqN5IHJhIHbhu5tpIGJp4bq/biBz4buRIG7DoG8gdsOgIG5o4buvbmcgZMOybmcgZOG7ryBsaeG7h3UgbsOgbyDEkcOjIGLhu4sgbWlzc2luZy4gDQoNCkhhaSBwYWNrYWdlcyB0aMaw4budbmcgc+G7rSBk4bulbmcgxJHhu4MgZ2nhuqNpIHF1eeG6v3QgduG6p24gxJHhu4EgbsOgeSBsw6AgVklNICh2aXN1YWxpemF0aW9uIGFuZCBpbXB1dGF0aW9uIG9mIG1pc3NpbmcgdmFsdWVzKSB2w6AgTUlDRSAoTXVsdGl2YXJpYXRlIEltcHV0YXRpb24gdmlhIENoYWluZWQgRXF1YXRpb25zKS4NCg0KIyMgQ2h14bqpbiBi4buLIGThu68gbGnhu4d1DQoNCkLhu5kgZOG7ryBsaeG7h3Ugc2xlZXAgdHJvbmcgcGFja2FnZSAiVklNIiDEkcaw4bujYyBjaOG7jW4gxJHhu4MgbWluaCBo4buNYSBjaG8gY2jhu6cgxJHhu4EgbsOgeS4NCg0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCg0KbGlicmFyeShWSU0pDQpsaWJyYXJ5KG1pY2UpDQpkYXRhKHNsZWVwLCBwYWNrYWdlPSJWSU0iKQ0KaGVhZChzbGVlcCkNCmBgYA0KDQpEYXRhc2V0ICdzbGVlcCcgbMOgIGLhu5kgZOG7ryBsaeG7h3UgduG7gSBnaeG6pWMgbmfhu6cgY+G7p2EgbeG7mXQgbG/DoGkgxJHhu5luZyB24bqtdCBjw7MgdsO6LCBn4buTbSA2MiBjw6EgdGjhu4MgdsOgIDEwIGJp4bq/biBz4buROg0KDQpCb2R5V2d0OiAgQ8OibiBu4bq3bmcgDQpCcmFpbldndDogQ8OibiBu4bq3bmcgYuG7mSBuw6NvICAgICANCk5vbkQ6ICAgICBUaOG7nWkgZ2lhbiBuZ+G7pyBraMO0bmcgY8OzIGdp4bqlYyBtxqEgICAgDQpEcmVhbTogICAgVGjhu51pIGdpYW4gbmfhu6cgY8OzIGdp4bqlYyBtxqEgICAgDQpTbGVlcDogICAgVGjhu51pIGdpYW4gbmfhu6cgdOG7lW5nIGPhu5luZyAgICAgIA0KU3BhbiAgICAgDQpHZXN0ICAgICANClByZWQgICAgICANCkV4cCAgIA0KRGFuZ2VyIA0KDQouLi4uDQoNCiMjIMSQw6FuaCBnacOhIG3hu6ljIMSR4buZIE1pc3NpbmcgRGF0YSB0cm9uZyBi4buZIGThu68gbGnhu4d1DQoNClbhu5tpIGhlYWQoc2xlZXApLCByw7UgcsOgbmcgdGEgdGjhuqV5IHRyb25nICJzbGVlcCIgY8OzIG5o4buvbmcgZ2nDoSB0cuG7iyBi4buLIG1pc3NpbmcgxJHGsOG7o2MgZ8OhbiBjaG8gY2jhu68gTkEuIMSQ4buDIGJp4bq/dCBjw7Mgbmjhu69uZyBiaeG6v24gc+G7kSBuw6BvIGLhu4sgbWlzc2luZyB0YSBkw7luZyBs4buHbmggc2F1Og0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCnNsZWVwWyFjb21wbGV0ZS5jYXNlcyhzbGVlcCksXQ0KDQpgYGANClRyw6puIMSRw6J5IGzDoCB04bqtcCBo4bujcCBuaOG7r25nIHJvd3MgY8OzIMOtdCBuaOG6pXQgbeG7mXQgTkEuIEtoaSBkYXRhc2V0IGPhu6dhIGNow7puZyB0YSBs4bubbiB2w6AgY8OzIG5oaeG7gXUgTkEgdGjDrCBjaMO6bmcgdGEgY+G6p24gY8OzIG3hu5l0IGLDoW8gY8OhbyB0w7NtIHThuq90IHbhu4EgY8OhYyByb3dzIHbDoCBjb2x1bW5zIGNo4bupYSBOQS4gxJDhu4MgY8OzIMSRaeG7gXUgxJHDsyBjaMO6bmcgdGEgZMO5bmcgbOG7h25oIHNhdToNCg0KDQpgYGB7cixtZXNzYWdlID0gRkFMU0Usd2FybmluZz1GQUxTRX0NCm1kLnBhdHRlcm4oc2xlZXApDQoNCmBgYA0KDQpHaeG6o2kgdGjDrWNoIGLDoW8gY8OhbzoNCg0KVuG7m2kgZ2nDoSB0cuG7iyAnMSIgY2hvIGJp4bq/dCBraMO0bmcgTkEsIHbDoCAiMCIgbMOgIGPDsyBOQS4gQ+G7mXQgdGjhu6kgbmjhuqV0IGNobyBiaeG6v3Qgc+G7kSBsxrDhu6NuZyByb3cgY2jhu6lhIGPDoWMgZ2nDoSB0cuG7iyBk4buvIGxp4buHdSB0xrDGoW5nIOG7qW5nIGLDqm4gcGjhuqNpLiBD4buZdCBjdeG7kWkgY8O5bmcgY2hvIGJp4bq/dCBjw7MgYmFvIG5oacOqdSBOQSB0cm9uZyBkw7JuZyB0xrDGoW5nIOG7qW5nLiBIw6BuZyBjdeG7kWkgY8O5bmcgYsOqbiBkxrDhu5tpIGNobyBiaeG6v3QgdOG7lW5nIHPhu5EgTkEgY8OzIHRyb25nIGPhu5l0IHTGsMahbmcg4bupbmcg4bufIHRyw6puLg0KDQpOaMawIHbhuq15LCBjaMO6bmcgdGEgY8OzIDQyIHJvdyBraMO0bmcgYuG7iyBOQSwgY8OzIDIgcm93IGPDsyAxIE5BIOG7nyBiaeG6v24gc+G7kSBTcGFuLCBjw7MgMyByb3cgY8OzIG3hu5l0IE5BIOG7nyBiaeG6v24gc+G7kSBHZXN0LCBjw7MgOSByb3cgY8OzIDIgTkEg4bufIERyZWFtIHbDoCBOb25ELiBWw6AgbOG6p24gbMaw4bujdCDEkeG6v24gZMOybmcgY3Xhu5FpIGPDuW5nLCBjaG8gYmnhur90IGPDsyB04buVbmcgY+G7mW5nIDM4IGdpw6EgdHLhu4sgTkEgdHJvbmcgc2xlZXAsIHRyb25nIMSRw7MgTm9uRCBjw7MgMTQgTkEsIERyZWFtIGPDsyAxMiBOQSB2w6AgR2VzdCBjw7MgNCBOQSwgLi4uLg0KDQpW4bubaSBWSU0sIGPDoWMgTkEgxJHGsOG7o2MgYmnhu4N1IGRp4buFbiBi4bqxbmcgYmnhu4N1IMSR4buTIGNobyBjaMO6bmcgdGEgdGjhuqV5IGjDrG5oIOG6o25oIGThu4UgaGnhu4N1IGjGoW46DQoNCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KDQptaWNlX3Bsb3QgPC0gYWdncihzbGVlcCwgY29sPWMoJ25hdnlibHVlJywneWVsbG93JyksDQogICAgICAgICAgICAgICAgICBudW1iZXJzPVRSVUUsIHNvcnRWYXJzPVRSVUUsDQogICAgICAgICAgICAgICAgICBsYWJlbHM9bmFtZXMoc2xlZXApLCBjZXguYXhpcz0uNywNCiAgICAgICAgICAgICAgICAgIGdhcD0zLCB5bGFiPWMoIk1pc3NpbmcgZGF0YSIsIlBhdHRlcm4iKSkNCmBgYA0KDQpNw6B1IHbDoG5nIGJp4buDdSB0aOG7iyBOQSwgbcOgdSB4YW5oIGtow7RuZyBwaOG6o2kgTkEuIEJp4buDdSDEkeG7kyBiw6puIHRyw6FpIGNobyB0aOG6pXkgcGjhuqduIHRyxINtIG3DoCBjw6FjIGJp4bq/biBz4buRIHTGsMahbmcg4bupbmcgY8OzIGdpw6EgdHLhu4sgTkEuIEJp4buDdSDEkeG7kyBiw6puIHBo4bqjaSBjaG8gYmnhur90IHBow6JuIHRyxINtIGPhu6dhIGPDoWMga2nhu4N1IHBo4buRaSBo4bujcCBOQSBnaeG7r2EgY8OhYyBiaeG6v24gc+G7kS4gQ3Xhu5FpIGPDuW5nIGzDoCB04buVbmcgY+G7mW5nIGPDsyA2Ny43JSBk4buvIGxp4buHdSBraMO0bmcgYuG7iyBOQS4gVuG7m2kgbeG7qWMgxJHhu5kgMzIuMyUgbWlzc2luZyBsw6Aga2jDoSBs4bubbiB0cm9uZyBkYXRhc2V0IG7DoHkuIA0KDQrEkOG6v24gxJHDonkgY2jDum5nIHRhIMSRw6MgY8OzIMSRxrDhu6NjIG3hu5l0IGPDoWkgbmjDrG4gdOG7lW5nIHRo4buDIHbhu4EgbeG7qWMgxJHhu5kgdHLhuqdtIHRy4buNbmcgbmjGsCB0aOG6vyBuw6BvIHRyb25nIHbhuqVuIMSR4buBIG1pc3NpbmcgZGF0YSBj4bunYSBi4buZIGThu68gbGnhu4d1IG3DoCBjaMO6bmcgdGEgxJFhbmcgY8OzIMO9IMSR4buLbmggcGjDom4gdMOtY2guDQoNClbDrCB24bqteSB0aGF5IHRo4bq/IGPDoWMgZ2nDoSB0cuG7iyBOQSBuaMawIHRo4bq/IG7DoG8gY2hvIHBow7kgaOG7o3AgbMOgIG3hu5l0IHnDqnUgY+G6p3UgdGhp4bq/dCB0aOG7sWMsIG7hur91IGtow7RuZyB0aMOsIGNo4buJIGPDsm4gY2jGsGEgxJHhur9uIDcwJSBk4buvIGxp4buHdSBjw7MgdGjhu4MgcGjDom4gdMOtY2ggxJHGsOG7o2MgbcOgIHRow7RpLg0KDQoNCiMgWOG7rSB0csOtIGPDoWMgTkFzDQoNCiMjIE5ndXnDqm4gdOG6r2MNCg0KYS4gxJDGoW4gZ2nhuqNuIG5o4bqldCBsw6AgY2jDum5nIHRhIHhlbSBrxKkgdOG7q25nIE5BIMSR4buDIGhp4buDdSB2w6wgc2FvIGNow7puZyBi4buLIG1pc3NpbmcuIFRyYSBj4bupdSBs4bqhaSB0w6BpIGxp4buHdSBuZ3Xhu5NuIG5oxrAgYuG7h25oIMOhbiBuZ2hpw6puIGPhu6l1LCBwaGnhur91IMSRaeG7gXUgdHJhIMSR4buRaSB0xrDhu6NuZywgxJHhu4MgbOG6pXkgdGjDtG5nIHRpbiBi4buVIHN1bmcgY2hvIGdpw6EgdHLhu4sgTkEgbuG6v3UgY2jDum5nIMSRw6MgYuG7iyBuaOG6rXAgc8OzdCBk4buvIGxp4buHdS4NCg0KYi4gTuG6v3UgxJHDsyBsw6AgbeG7mXQgcm93IG5o4bqtcCBs4buXaSwgYuG7iyBs4bq3cCBs4bqhaSwgY2jDum5nIHRhIHjDs2Egcm93IOG6pXkga2jhu49pIGRhdGFzZXQuDQoNCmMuIE7hur91IG1pc3NpbmcgZGF0YSBsw6AgcsOjaSByw6FjIOG7nyBjw6FjIGTDsm5nIGPDsyB0w61uaCBuZ+G6q3Ugbmhpw6puIChNQVI6IE1pc3NpbmcgQXQgUmFuZG9tKSB0aMOsIGNow7puZyB0YSBjw7MgdGjhu4MgdGhheSB0aOG6vyBjaMO6bmcgYuG6sW5nIGPDoWMgZ2nDoSB0cuG7iyBjw7MgdGjhu4MgbMOgOg0KDQogIC0gTWVhbiBob+G6t2MgTWVkaWFuIMSR4buRaSB24bubaSBiaeG6v24gbGnDqm4gdOG7pWMNCiAgLSBHacOhIHRy4buLIHRoxrDhu51uZyB4deG6pXQgaGnhu4duIG7hur91IMSRw7MgbMOgIGJp4bq/biBy4budaSBy4bqhYw0KICANCiAgDQojIyBNSUNFIA0KDQpNSUNFIGdp4bqjIMSR4buLbmggcuG6sW5nIGThu68gbGnhu4d1IGLhu4sgbeG6pXQgbMOgIE1pc3NpbmcgYXQgUmFuZG9tIChNQVIpLCBjw7MgbmdoxKlhIGzDoCB4w6FjIHN14bqldCBtw6AgbeG7mXQgZ2nDoSB0cuG7iyBi4buLIHRoaeG6v3UgY2jhu4kgcGjhu6UgdGh14buZYyB2w6BvIGdpw6EgdHLhu4sgcXVhbiBzw6F0IMSRxrDhu6NjIHbDoCBjw7MgdGjhu4MgZOG7sSDEkW/DoW4gY2jDum5nIGLhurFuZyBjw6FjIGdpw6EgdHLhu4sgY8O5bmcgY2jhu6duZyBsb+G6oWkuIE7DsyB0w61uaCBk4buvIGxp4buHdSBtaXNzaW5nIGThu7FhIHbDoG8gcXVpIGx14bqtdCBiaeG6v24gdGhpw6puIGPhu6dhIGPDoWMgYmnhur9uIHPhu5EgdHJvbmcgZGF0YXNldC4NCg0KVsOtIGThu6U6IEdp4bqjIHPhu60gY2jDum5nIHRhIGPDsyBjw6FjIGJp4bq/biBYMSwgWDIgLi4uIC5Yay4gTuG6v3UgWDEgY8OzIGPDoWMgZ2nDoSB0cuG7iyBjw7JuIHRoaeG6v3UsIHRow6wgbsOzIHPhur0gxJHGsOG7o2MgaOG7k2kgcXV5IHRyw6puIGPDoWMgYmnhur9uIGtow6FjIHThu6sgWDIgxJHhur9uIFhrLiBDw6FjIGdpw6EgdHLhu4sgY8OybiB0aGnhur91IHRyb25nIFgxIHPhur0gxJHGsOG7o2MgdGhheSB0aOG6vyBi4bqxbmcgY8OhYyBnacOhIHRy4buLIG3DoCBuw7MgZOG7sSDEkW/DoW4gdOG7qyBjw6FjIGJp4bq/biBz4buRIGPDsm4gbOG6oWkuIFTGsMahbmcgdOG7sSwgbuG6v3UgWDIgY8OzIGPDoWMgZ2nDoSB0cuG7iyBjw7JuIHRoaeG6v3UsIHRow6wgY8OhYyBiaeG6v24gWDEsIFgzIMSR4bq/biBYayBz4bq9IMSRxrDhu6NjIHPhu60gZOG7pW5nIHRyb25nIG3DtCBow6xuaCBk4buxIMSRb8OhbiBuaMawIGPDoWMgYmnhur9uIMSR4buZYyBs4bqtcC4gU2F1IMSRw7MsIGdpw6EgdHLhu4sgY8OybiB0aGnhur91IHPhur0gxJHGsOG7o2MgdGhheSB0aOG6vyBi4bqxbmcgZ2nDoSB0cuG7iyBk4buxIMSRb8Ohbi4NCg0KVGhlbyBt4bq3YyDEkeG7i25oLCBo4buTaSBxdXkgdHV54bq/biB0w61uaCDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyBk4buxIMSRb8OhbiBnacOhIHRy4buLIG1pc3NpbmcgY+G7p2EgYmnhur9uIGxpw6puIHThu6VjLiBI4buTaSBxdXkgbG9naXN0aWMgxJHGsOG7o2Mgc+G7rSBk4bulbmcgY2hvIGdpw6EgdHLhu4sgdGhp4bq/dSB0cm9uZyBiaeG6v24gcuG7nWkgcuG6oWMuIEtoaSBjaHUga+G7syBuw6B5IGhvw6BuIHThuqV0LCBuaGnhu4F1IGLhu5kgZOG7ryBsaeG7h3UgxJHGsOG7o2MgdOG6oW8gcmEuIE5o4buvbmcgYuG7mSBk4buvIGxp4buHdSBuw6B5IGNo4buJIGtow6FjIG5oYXUgdHJvbmcgY8OhYyBnacOhIHRy4buLIGLhu4sgdGhp4bq/dS4gTsOzaSBjaHVuZywgxJHDonkgxJHGsOG7o2MgY29pIGzDoCBt4buZdCBwaMawxqFuZyBwaMOhcCBoYXkgxJHhu4MgeMOieSBk4buxbmcgY8OhYyBtw7QgaMOsbmggdHLDqm4gY8OhYyBi4buZIGThu68gbGnhu4d1IHJpw6puZyBy4bq9IHbDoCBjw7MgdGjhu4Mga+G6v3QgaOG7o3AgY8OhYyBr4bq/dCBxdeG6oyBj4bunYSBjaMO6bmcuDQoNCkNow61uaCB4w6FjLCBjw6FjIHBoxrDGoW5nIHBow6FwIMSRxrDhu6NjIHPhu60gZOG7pW5nIGLhu59pIHBhY2thZ2UgTUlDRSBsw6A6DQoNClBNTSAoUHJlZGljdGl2ZSBNZWFuIE1hdGNoaW5nKSAtIMSQ4buRaSB24bubaSBjw6FjIGJp4bq/biBz4buRIGxpw6puIHThu6VjDQpMb2dyZWcgKExvZ2lzdGljIFJlZ3Jlc3Npb24pIC0gxJDhu5FpIHbhu5tpIGPDoWMgYmnhur9uIG5o4buLIHBow6JuICh24bubaSAyIGxldmVsKQ0KUG9seXJlZyAoaOG7k2kgcXVpIMSRYSB0aOG7qWMgQmF5ZXNpYW4pIC0gxJDhu5FpIHbhu5tpIGPDoWMgYmnhur9uIGZhY3RvciAoPj0gMiBsZXZlbCkNCk3DtCBow6xuaCB04bu3IGzhu4cgY2jDqm5oIChjw7MgdGjhu6kgdOG7sSw+PSAyIGxldmVsKQ0KDQpW4bubaSBzbGVlcCwgY2jDum5nIHRhIHRo4buxYyBow6BuaCB0aGF5IHRo4bq/IE5BIGNobyBjw6FjIGJp4bq/biBsacOqbiB04bulYyBi4bqxbmcgcGjGsMahbmcgcGjDoXAgInBtbSIgduG7m2kgbSA9IDUgKG11bHRpcGxlIGltcHV0YXRpb25zKSwgdOG7qWMgbMOgIDUgbOG6p24gdGhheSB0aOG6vywgc2F1IMSRw7MgY2jhu41uIHJhIG1pc3Npbmcgc3Vic2V0IG7DoG8gY2jDum5nIHRhIG114buRbiBjaOG7jW4uDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KaW1wdXRlZF9EYXRhIDwtIG1pY2Uoc2xlZXAsIG09NSwgbWF4aXQgPSA1MCwgbWV0aG9kID0gJ3BtbScsIHNlZWQgPSA1MDAsIHByaW50PUZBTFNFKQ0KaGVhZChpbXB1dGVkX0RhdGEpDQpgYGANCg0KTeG7l2kgbeG7mXQgYmnhur9uIHPhu5EgY8OzIE5BLCBNSUNFIHPhur0gY2hvIHJhIDUgc3Vic2V0cyBjw7MgdGjhu4MgdGhheSB0aOG6vyDEkcaw4bujYy4gVHJvbmcgNSBs4bqnbiBpbXB1dGF0aW9ucyB0csOqbiwgdMO0aSBtdeG7kW4gY2jhu41uIHN1YnNldCB0aOG7qSAzIMSR4buDIHRoYXkgdGjhur8gY2jDrW5oIHRo4bupYyBjaG8gbmjhu69uZyBOQSB0cm9uZyAic2xlZXAiLCB2w6wgdGjhur8gdMO0aSBkw7luZyBs4buHbmggbmjGsCBzYXU6DQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSx3YXJuaW5nPUZBTFNFfQ0KY29tcGxldGVEYXRhIDwtIGNvbXBsZXRlKGltcHV0ZWRfRGF0YSwzKQ0KaGVhZChjb21wbGV0ZURhdGEsIDIwKQ0KYGBgDQoNCsSQ4bq/biDEkcOieSBjaMO6bmcgdGEgxJHDoyBjw7MgYuG7mSBk4buvIGxp4buHdSBob8OgbiB0aGnhu4duICJjb21wbGV0ZURhdGEiIGPDsyB0aOG7gyDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyBwaMOibiB0w61jaCwgeMOieSBk4buxbmcgbcO0IGjDrG5oIGjhu5NpIHF1aS4uLiANCg0KQ8OhbSDGoW4gY8OhYyBi4bqhbiDEkcOjIMSR4buNYyBiw6BpIHZp4bq/dCBuw6B5LiBNb25nIG5o4bqtbiDEkcaw4bujYyBuaOG7r25nIGzhu51pIGfDs3Agw70sIGLDoG4gbHXhuq1uIMSR4buDIGPDuW5nIGjhu41jIHThuq1wIHbDoCB0aeG6v24gYuG7mS4=