R은 시각화가 뛰어난 프로그램이다. 그렇지만 사회과학에서 많이 사용하는 모델을 그려주는 패키지가 영 시원치 않아서 직접 만들어 보았다(물론 내가 만든것도 시원치 않다). 단순매개 모형부터 시작하였다. 매개 모형 그림을 그리기 위해서는 아래 내용이 필요 하다. 1) 세가지 변수의 변수명을 넣을 그림판 2) 변수명 3) 유의도에 따른 화살표 4) 회귀계수와 유의도에 따른 표기(***)

##1. 세가지 변수의 변수명을 넣을 그림판 단순매개 모형은 세 변수를 삼각형 모양으로 그리곤 한다. 그러기 위한 코드는 아래와 같다.

plot(0, xlim= c(-5,5), ylim=c(-5,5), col= "#FFFFFF", xlab="", ylab="", xaxt='n', yaxt='n') ##아무것도 없는 흰색 판
rect(-4,-4,-2,-2, lwd = 2) ##독립변수 사각형
rect(-1,2,1,4, lwd = 2) ##매개변수 사각형
rect(2,-4,4,-2, lwd = 2) ##종속속변수 사각형

구조방정식을 사용해서 잠재변수를 사용할 경우 rect 대신 원형을 그리면 된다.

##2. 변수명 데이터에서 변수명을 뽑아내야 저 모델 이미지에 넣을 수 있다. 간단히 colnames함수를 쓰면 된다. 이를 바탕으로 데이터에서 변수명을 뽑는 함수를 만들어 보았다.

var_name<-function(indi1, medi1, depen, dd){ ###각각 독립변수, 매개변수, 종소변수가 몇번째 열에 있는지 쓰면 된다. 마지막은 dataframe을 넣으면 된다.
  var_name_sum<-c()
  var_name_sum[1]<-colnames(dd[indi1])
  var_name_sum[2]<-colnames(dd[medi1])
  var_name_sum[3]<-colnames(dd[depen])
  print(var_name_sum)
}

한번 적용해보자

#적용
##가짜 데이터 만들기
독립변수<-rnorm(100)
매개변수<-rnorm(100) + 독립변수
종속변수<-독립변수+매개변수+rnorm(100,0,2)
d<-data.frame(독립변수, 매개변수, 종속변수)

##변수명 뽑아내기
var_name(1,2,3,d) ##각 열이 몇번째인지 알아야 가능하다.
[1] "독립변수" "매개변수" "종속변수"

변수명을 뽑아냈으니 이를 그래프에 그려보자.

#빈 서판
plot(0, xlim= c(-5,5), ylim=c(-5,5), col= "#FFFFFF", xlab="", ylab="", xaxt='n', yaxt='n') ##아무것도 없는 흰색 판
rect(-4,-4,-2,-2, lwd = 2) ##독립변수 사각형
rect(-1,2,1,4, lwd = 2) ##매개변수 사각형
rect(2,-4,4,-2, lwd = 2) ##종속속변수 사각형

#변수명 넣어보기
  var_name_sum<-var_name(1, 2, 3, d)
[1] "독립변수" "매개변수" "종속변수"
  text(-3,-3, labels = var_name_sum[1], cex= 2)
  text(0,3, labels = var_name_sum[2], cex= 2)
  text(3,-3, labels = var_name_sum[3], cex= 2)

##3. 유의도에 따른 화살표 흔히 유의할 경우 실선으로 그리고 아닐경우 점선으로 그리곤 한다. 그래서 이를 고려하여 작성하면 다음과 같다. 일단 이 그림을 그리려면 두가지 회귀 모델이 있어야 한다. 첫번째는 매개~독립이고 두번째는 종속~ 독립+ 매개이다. 여기 작성한 코드 자체가 변수 순서를 바탕으로 추출하기 때문에 아래 순서를 벗어나면 다른 결과가 나오니 주의해야 한다. 일단 모델 부터 만들어보자

#가짜 데이터 만들기
x<-rnorm(100)
me<-rnorm(100) + x
y<-x+me+rnorm(100,0,2)
cont1<-rnorm(100)
d<-data.frame(x, me, y, cont1)

#회귀모델 만들기
lm1<-lm(me~x + cont1, data= d) #매개~독립 + 통제변인

lm2<-lm(y~x+me + cont1, data = d) #종속 ~ 매개 + 독립 + 통제변인

summary(lm1)

Call:
lm(formula = me ~ x + cont1, data = d)

Residuals:
    Min      1Q  Median      3Q     Max 
-2.4693 -0.7100  0.1238  0.7080  2.0952 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.09498    0.10183  -0.933    0.353    
x            1.11801    0.11366   9.837 3.02e-16 ***
cont1       -0.14010    0.10309  -1.359    0.177    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 1.015 on 97 degrees of freedom
Multiple R-squared:  0.5006,    Adjusted R-squared:  0.4903 
F-statistic: 48.62 on 2 and 97 DF,  p-value: 2.366e-15
summary(lm2)

Call:
lm(formula = y ~ x + me + cont1, data = d)

Residuals:
    Min      1Q  Median      3Q     Max 
-3.9772 -1.4470 -0.1586  1.1932  4.7461 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.14764    0.21540  -0.685  0.49475    
x            0.90837    0.33829   2.685  0.00854 ** 
me           1.00058    0.21383   4.679 9.43e-06 ***
cont1        0.04925    0.21916   0.225  0.82268    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.137 on 96 degrees of freedom
Multiple R-squared:  0.4986,    Adjusted R-squared:  0.483 
F-statistic: 31.83 on 3 and 96 DF,  p-value: 2.274e-14

그다음 필요한 파라미터를 추출하는 함수를 작성하였다. 추출 파라미터는 회귀계수와 p-value다.

  medi_model_coe1<-function(lm1,lm2){
    mo_me<-summary(lm1)
    mo_me_d<-as.data.frame(mo_me[4])
    coe1<-mo_me_d[2,1]
    p_val1<-mo_me_d[2,4]
    
    mo_me2<-summary(lm2)
    mo_me_d2<-as.data.frame(mo_me2[4])
    coe2<-mo_me_d2[3,1]###y~me
    coe3<-mo_me_d2[2,1]###y~x
    p_val2<-mo_me_d2[3,4]
    p_val3<-mo_me_d2[2,4]
    para_sum<-c(coe1,coe2, coe3, p_val1, p_val2,p_val3)
  }
mm<-medi_model_coe1(lm1, lm2)
print(round(mm,3))
[1] 1.118 1.001 0.908 0.000 0.000 0.009

화살표는 arrows함수를 쓰면 된다. 이름처럼 회살표다. 다만 이경우 선 종류(lty= )을 유의하면 1 유의하지 않으면 2(점선)으로 그리도록 조건문을 썼다. arrows(x좌표, y좌표)이기 때문에 나중에 변경하려면 좌표를 이동해야한다. 수학 모르는 문과라 꼭짓점 좌표를 다 구했다…ㅠㅠ 1))이건 모두 유의하게 나온경우이다.

#빈 서판
plot(0, xlim= c(-5,5), ylim=c(-5,5), col= "#FFFFFF", xlab="", ylab="", xaxt='n', yaxt='n') ##아무것도 없는 흰색 판
rect(-4,-4,-2,-2, lwd = 2) ##독립변수 사각형
rect(-1,2,1,4, lwd = 2) ##매개변수 사각형
rect(2,-4,4,-2, lwd = 2) ##종속속변수 사각형

#변수명 넣어보기
  var_name_sum<-var_name(1, 2, 3, d)
[1] "x"  "me" "y" 
  text(-3,-3, labels = var_name_sum[1], cex= 2)
  text(0,3, labels = var_name_sum[2], cex= 2)
  text(3,-3, labels = var_name_sum[3], cex= 2)
#유의도에 따른 화살표 넣어보기
arrows(-3,-2, -1.05,3, lwd=2, length = 0.15, lty = ifelse(mm[4]<=.05,1,2))
arrows(1,3, 3,-1.8, lwd=2, length = 0.15, lty = ifelse(mm[5]<=.05,1,2))
arrows(-2,-3, 2,-3, lwd=2, length = 0.15, lty = ifelse(mm[6]<=.05,1,2))

2))요건 유의하지 않은거다

x<-rnorm(1000)
me<-rnorm(1000)
y<-rnorm(100,0,2)
cont1<-rnorm(100)
d<-data.frame(x, me, y, cont1)

#회귀모델 만들기
lm1<-lm(me~x + cont1, data= d) #매개~독립 + 통제변인

lm2<-lm(y~x+me + cont1, data = d) #종속 ~ 매개 + 독립 + 통제변인
mm<-medi_model_coe1(lm1, lm2)

#빈 서판
plot(0, xlim= c(-5,5), ylim=c(-5,5), col= "#FFFFFF", xlab="", ylab="", xaxt='n', yaxt='n') ##아무것도 없는 흰색 판
rect(-4,-4,-2,-2, lwd = 2) ##독립변수 사각형
rect(-1,2,1,4, lwd = 2) ##매개변수 사각형
rect(2,-4,4,-2, lwd = 2) ##종속속변수 사각형

#변수명 넣어보기
  var_name_sum<-var_name(1, 2, 3, d)
[1] "x"  "me" "y" 
  text(-3,-3, labels = var_name_sum[1], cex= 2)
  text(0,3, labels = var_name_sum[2], cex= 2)
  text(3,-3, labels = var_name_sum[3], cex= 2)
#유의도에 따른 화살표 넣어보기
arrows(-3,-2, -1.05,3, lwd=2, length = 0.15, lty = ifelse(mm[4]<=.05,1,2))
arrows(1,3, 3,-1.8, lwd=2, length = 0.15, lty = ifelse(mm[5]<=.05,1,2))
arrows(-2,-3, 2,-3, lwd=2, length = 0.15, lty = ifelse(mm[6]<=.05,1,2))

##4. 회귀계수와 유의도에 따른 표기(***) 마지막으로 각 화살표에 필요한 계수와 p-value를 표기 하였다. 첫번째로 비표준화 회귀계수를 넣어 보았다.

x<-rnorm(1000)
me<-rnorm(1000)
y<-rnorm(100,0,2)
cont1<-rnorm(100)
d<-data.frame(x, me, y, cont1)

#회귀모델 만들기
lm1<-lm(me~x + cont1, data= d) #매개~독립 + 통제변인

lm2<-lm(y~x+me + cont1, data = d) #종속 ~ 매개 + 독립 + 통제변인
mm<-medi_model_coe1(lm1, lm2)

#빈 서판
plot(0, xlim= c(-5,5), ylim=c(-5,5), col= "#FFFFFF", xlab="", ylab="", xaxt='n', yaxt='n') ##아무것도 없는 흰색 판
rect(-4,-4,-2,-2, lwd = 2) ##독립변수 사각형
rect(-1,2,1,4, lwd = 2) ##매개변수 사각형
rect(2,-4,4,-2, lwd = 2) ##종속속변수 사각형

#변수명 넣어보기
  var_name_sum<-var_name(1, 2, 3, d)
[1] "x"  "me" "y" 
  text(-3,-3, labels = var_name_sum[1], cex= 2)
  text(0,3, labels = var_name_sum[2], cex= 2)
  text(3,-3, labels = var_name_sum[3], cex= 2)
#유의도에 따른 화살표 넣어보기
arrows(-3,-2, -1.05,3, lwd=2, length = 0.15, lty = ifelse(mm[4]<=.05,1,2))
arrows(1,3, 3,-1.8, lwd=2, length = 0.15, lty = ifelse(mm[5]<=.05,1,2))
arrows(-2,-3, 2,-3, lwd=2, length = 0.15, lty = ifelse(mm[6]<=.05,1,2))
#유의도에 따라 별표 넣기
text(-2.5,1, paste0("b=",round(mm[1], 3), ifelse(mm[4]>=.05, ", ns", ifelse(mm[4]<.05 & mm[4]>=.01, "*", 
                                                                          ifelse(mm[4]<.01 & mm[4]>=.001,"**","***")))), srt=56)
text(0,-4, paste0("b=",round(mm[3], 3), ifelse(mm[6]>=.05, ", ns", ifelse(mm[6]<.05 & mm[6]>=.01, "*", 
                                                                          ifelse(mm[6]<.01 & mm[6]>=.001,"**","***")))), srt=0)
text(2.5,1, paste0("b=",round(mm[2], 3), ifelse(mm[5]>=.05, ", ns", ifelse(mm[5]<.05 & mm[5]>=.01, "*", 
                                                                         ifelse(mm[5]<.01 & mm[5]>=.001,"**","***")))), srt=-56)

##4. <종합> 위에 나온 과정을 한방에 진행하는 코드다.

##medi_model(독립변수 열번호, 매개변수 열번호, 종속변수 열번호, 데이터, 매개~독립모델, 종속~독립모델)

medi_model<-function(indi1, medi1, depen, dd, lm1, lm2){
  medi_model_coe1<-function(lm1,lm2){
    mo_me<-summary(lm1)
    mo_me_d<-as.data.frame(mo_me[4])
    coe1<-mo_me_d[2,1]
    p_val1<-mo_me_d[2,4]
    
    mo_me2<-summary(lm2)
    mo_me_d2<-as.data.frame(mo_me2[4])
    coe2<-mo_me_d2[3,1]###y~me
    coe3<-mo_me_d2[2,1]###y~x
    p_val2<-mo_me_d2[3,4]
    p_val3<-mo_me_d2[2,4]
    para_sum<-c(coe1,coe2, coe3, p_val1, p_val2,p_val3)
  }
  mm<-medi_model_coe1(lm1, lm2)
  
  plot(0, xlim= c(-10,10), ylim=c(-10,10), col= "#FFFFFF", xlab="", ylab="",xaxt='n', yaxt='n')
rect(-8,-8,-4,-4, lwd = 2)
rect(-2,5,2,9, lwd = 2)
rect(8,-8,4,-4, lwd = 2)
arrows(-6,-4, -2.2,7, lwd=2, length = 0.15, lty = ifelse(mm[4]<=.05,1,2))
arrows(2,7,6,-4, lwd=2, length = 0.15, lty = ifelse(mm[5]<=.05,1,2))
arrows(-4,-6,4,-6, lwd=2, length = 0.15, lty = ifelse(mm[6]<=.05,1,2))
var_name<-function(indi1, medi1, depen, dd){
  var_name_sum<-c()
  var_name_sum[1]<-colnames(dd[indi1])
  var_name_sum[2]<-colnames(dd[medi1])
  var_name_sum[3]<-colnames(dd[depen])
  print(var_name_sum)
}
var_name_sum<-var_name(indi1, medi1, depen, dd)
text(-6,-6, labels = var_name_sum[1], cex= 2)
text(0,7, labels = var_name_sum[2], cex= 2)
text(6,-6, labels = var_name_sum[3], cex= 2)

text(-5,1, paste0("b=",round(mm[1], 3), ifelse(mm[4]>=.05, ", ns", ifelse(mm[4]<.05 & mm[4]>=.01, "*", 
                                                                          ifelse(mm[4]<.01 & mm[4]>=.001,"**","***")))), srt=56)
text(0,-7, paste0("b=",round(mm[3], 3), ifelse(mm[6]>=.05, ", ns", ifelse(mm[6]<.05 & mm[6]>=.01, "*", 
                                                                          ifelse(mm[6]<.01 & mm[6]>=.001,"**","***")))), srt=0)
text(5,1, paste0("b=",round(mm[2], 3), ifelse(mm[5]>=.05, ", ns", ifelse(mm[5]<.05 & mm[5]>=.01, "*", 
                                                                         ifelse(mm[5]<.01 & mm[5]>=.001,"**","***")))), srt=-56)
}

#test
아침밥<-rnorm(100)
점심밥<-x+rnorm(100)
저녁밥<-me +rnorm(100)
d<-data.frame(아침밥, 점심밥, 저녁밥)
lm1<-lm(me~x, d)
lm2<-lm(y~x + me , d)
medi_model(1,2,3,d,lm1,lm2)
[1] "아침밥" "점심밥" "저녁밥"

흔히 말하는 완죤매개다(난 이표현 싫어한다. )

LS0tDQp0aXRsZTogIuunpOqwnOuqqO2YlSDqt7jrpqzquLAo64uo7Iic66ek6rCcKSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNClLsnYAg7Iuc6rCB7ZmU6rCAIOubsOyWtOuCnCDtlITroZzqt7jrnqjsnbTri6QuIOq3uOugh+yngOunjCDsgqztmozqs7ztlZnsl5DshJwg66eO7J20IOyCrOyaqe2VmOuKlCDrqqjrjbjsnYQg6re466Ck7KO864qUIO2MqO2CpOyngOqwgCDsmIEg7Iuc7JuQ7LmYIOyViuyVhOyEnCDsp4HsoJEg66eM65Ok7Ja0IOuztOyVmOuLpCjrrLzroaAg64K06rCAIOunjOuToOqyg+uPhCDsi5zsm5DsuZgg7JWK64ukKS4gDQrri6jsiJzrp6TqsJwg66qo7ZiV67aA7YSwIOyLnOyeke2VmOyYgOuLpC4NCuunpOqwnCDrqqjtmJUg6re466a87J2EIOq3uOumrOq4sCDsnITtlbTshJzripQg7JWE656YIOuCtOyaqeydtCDtlYTsmpQg7ZWY64ukLg0KMSkg7IS46rCA7KeAIOuzgOyImOydmCDrs4DsiJjrqoXsnYQg64Sj7J2EIOq3uOumvO2MkA0KMikg67OA7IiY66qFDQozKSDsnKDsnZjrj4Tsl5Ag65Sw66W4IO2ZlOyCtO2RnA0KNCkg7ZqM6reA6rOE7IiY7JmAIOycoOydmOuPhOyXkCDrlLDrpbgg7ZGc6riwKCoqKikNCg0KDQojIzEuIOyEuOqwgOyngCDrs4DsiJjsnZgg67OA7IiY66qF7J2EIOuEo+ydhCDqt7jrprztjJANCuuLqOyInOunpOqwnCDrqqjtmJXsnYAg7IS4IOuzgOyImOulvCDsgrzqsIHtmJUg66qo7JaR7Jy866GcIOq3uOumrOqzpCDtlZzri6QuIOq3uOufrOq4sCDsnITtlZwg7L2U65Oc64qUIOyVhOuemOyZgCDqsJnri6QuDQpgYGB7ciBwMX0NCnBsb3QoMCwgeGxpbT0gYygtNSw1KSwgeWxpbT1jKC01LDUpLCBjb2w9ICIjRkZGRkZGIiwgeGxhYj0iIiwgeWxhYj0iIiwgeGF4dD0nbicsIHlheHQ9J24nKSAjI+yVhOustOqyg+uPhCDsl4bripQg7Z2w7IOJIO2MkA0KcmVjdCgtNCwtNCwtMiwtMiwgbHdkID0gMikgIyPrj4Xrpr3rs4DsiJgg7IKs6rCB7ZiVDQpyZWN0KC0xLDIsMSw0LCBsd2QgPSAyKSAjI+unpOqwnOuzgOyImCDsgqzqsIHtmJUNCnJlY3QoMiwtNCw0LC0yLCBsd2QgPSAyKSAjI+yiheyGjeyGjeuzgOyImCDsgqzqsIHtmJUNCmBgYA0K6rWs7KGw67Cp7KCV7Iud7J2EIOyCrOyaqe2VtOyEnCDsnqDsnqzrs4DsiJjrpbwg7IKs7Jqp7ZWgIOqyveyasCByZWN0IOuMgOyLoCDsm5DtmJXsnYQg6re466as66m0IOuQnOuLpC4NCg0KIyMyLiDrs4DsiJjrqoUNCuuNsOydtO2EsOyXkOyEnCDrs4DsiJjrqoXsnYQg672R7JWE64K07JW8IOyggCDrqqjrjbgg7J2066+47KeA7JeQIOuEo+ydhCDsiJgg7J6I64ukLiDqsITri6jtnoggY29sbmFtZXPtlajsiJjrpbwg7JOw66m0IOuQnOuLpC4g7J2066W8IOuwlO2DleycvOuhnCDrjbDsnbTthLDsl5DshJwg67OA7IiY66qF7J2EIOu9keuKlCDtlajsiJjrpbwg66eM65Ok7Ja0IOuztOyVmOuLpC4NCmBgYHtyIHAyfQ0KdmFyX25hbWU8LWZ1bmN0aW9uKGluZGkxLCBtZWRpMSwgZGVwZW4sIGRkKXsgIyMj6rCB6rCBIOuPheumveuzgOyImCwg66ek6rCc67OA7IiYLCDsooXshozrs4DsiJjqsIAg66qH67KI7Ke4IOyXtOyXkCDsnojripTsp4Ag7JOw66m0IOuQnOuLpC4g66eI7KeA66eJ7J2AIGRhdGFmcmFtZeydhCDrhKPsnLzrqbQg65Cc64ukLg0KICB2YXJfbmFtZV9zdW08LWMoKQ0KICB2YXJfbmFtZV9zdW1bMV08LWNvbG5hbWVzKGRkW2luZGkxXSkNCiAgdmFyX25hbWVfc3VtWzJdPC1jb2xuYW1lcyhkZFttZWRpMV0pDQogIHZhcl9uYW1lX3N1bVszXTwtY29sbmFtZXMoZGRbZGVwZW5dKQ0KICBwcmludCh2YXJfbmFtZV9zdW0pDQp9DQpgYGANCu2VnOuyiCDsoIHsmqntlbTrs7TsnpANCmBgYHtyIHAzfQ0KI+yggeyaqQ0KIyPqsIDsp5wg642w7J207YSwIOunjOuTpOq4sA0K64+F66a967OA7IiYPC1ybm9ybSgxMDApDQrrp6TqsJzrs4DsiJg8LXJub3JtKDEwMCkgKyDrj4Xrpr3rs4DsiJgNCuyiheyGjeuzgOyImDwt64+F66a967OA7IiYK+unpOqwnOuzgOyImCtybm9ybSgxMDAsMCwyKQ0KZDwtZGF0YS5mcmFtZSjrj4Xrpr3rs4DsiJgsIOunpOqwnOuzgOyImCwg7KKF7IaN67OA7IiYKQ0KDQojI+uzgOyImOuqhSDrvZHslYTrgrTquLANCnZhcl9uYW1lKDEsMiwzLGQpICMj6rCBIOyXtOydtCDrqofrsojsp7jsnbjsp4Ag7JWM7JWE7JW8IOqwgOuKpe2VmOuLpC4NCmBgYA0KDQrrs4DsiJjrqoXsnYQg672R7JWE64OI7Jy864uIIOydtOulvCDqt7jrnpjtlITsl5Ag6re466Ck67O07J6QLg0KYGBge3IgcDR9DQoj67mIIOyEnO2MkA0KcGxvdCgwLCB4bGltPSBjKC01LDUpLCB5bGltPWMoLTUsNSksIGNvbD0gIiNGRkZGRkYiLCB4bGFiPSIiLCB5bGFiPSIiLCB4YXh0PSduJywgeWF4dD0nbicpICMj7JWE66y06rKD64+EIOyXhuuKlCDtnbDsg4kg7YyQDQpyZWN0KC00LC00LC0yLC0yLCBsd2QgPSAyKSAjI+uPheumveuzgOyImCDsgqzqsIHtmJUNCnJlY3QoLTEsMiwxLDQsIGx3ZCA9IDIpICMj66ek6rCc67OA7IiYIOyCrOqwge2YlQ0KcmVjdCgyLC00LDQsLTIsIGx3ZCA9IDIpICMj7KKF7IaN7IaN67OA7IiYIOyCrOqwge2YlQ0KDQoj67OA7IiY66qFIOuEo+yWtOuztOq4sA0KICB2YXJfbmFtZV9zdW08LXZhcl9uYW1lKDEsIDIsIDMsIGQpDQogIHRleHQoLTMsLTMsIGxhYmVscyA9IHZhcl9uYW1lX3N1bVsxXSwgY2V4PSAyKQ0KICB0ZXh0KDAsMywgbGFiZWxzID0gdmFyX25hbWVfc3VtWzJdLCBjZXg9IDIpDQogIHRleHQoMywtMywgbGFiZWxzID0gdmFyX25hbWVfc3VtWzNdLCBjZXg9IDIpDQpgYGANCiMjMy4g7Jyg7J2Y64+E7JeQIOuUsOuluCDtmZTsgrTtkZwNCu2dlO2eiCDsnKDsnZjtlaAg6rK97JqwIOyLpOyEoOycvOuhnCDqt7jrpqzqs6Ag7JWE64uQ6rK97JqwIOygkOyEoOycvOuhnCDqt7jrpqzqs6Qg7ZWc64ukLiDqt7jrnpjshJwg7J2066W8IOqzoOugpO2VmOyXrCDsnpHshLHtlZjrqbQg64uk7J2M6rO8IOqwmeuLpC4g7J2864uoIOydtCDqt7jrprzsnYQg6re466as66Ck66m0IOuRkOqwgOyngCDtmozqt4Ag66qo64247J20IOyeiOyWtOyVvCDtlZzri6QuIOyyq+uyiOynuOuKlCDrp6TqsJx+64+F66a97J206rOgIOuRkOuyiOynuOuKlCDsooXsho1+IOuPheumvSsg66ek6rCc7J2064ukLiDsl6zquLAg7J6R7ISx7ZWcIOy9lOuTnCDsnpDssrTqsIAg67OA7IiYIOyInOyEnOulvCDrsJTtg5XsnLzroZwg7LaU7Lac7ZWY6riwIOuVjOusuOyXkCDslYTrnpgg7Iic7ISc66W8IOuyl+yWtOuCmOuptCDri6Trpbgg6rKw6rO86rCAIOuCmOyYpOuLiCDso7zsnZjtlbTslbwg7ZWc64ukLg0K7J2864uoIOuqqOuNuCDrtoDthLAg66eM65Ok7Ja067O07J6QDQoNCmBgYHtyIHA1fQ0KI+qwgOynnCDrjbDsnbTthLAg66eM65Ok6riwDQp4PC1ybm9ybSgxMDApDQptZTwtcm5vcm0oMTAwKSArIHgNCnk8LXgrbWUrcm5vcm0oMTAwLDAsMikNCmNvbnQxPC1ybm9ybSgxMDApDQpkPC1kYXRhLmZyYW1lKHgsIG1lLCB5LCBjb250MSkNCg0KI+2ajOq3gOuqqOuNuCDrp4zrk6TquLANCmxtMTwtbG0obWV+eCArIGNvbnQxLCBkYXRhPSBkKSAj66ek6rCcfuuPheumvSArIO2GteygnOuzgOyduA0KDQpsbTI8LWxtKHl+eCttZSArIGNvbnQxLCBkYXRhID0gZCkgI+yiheyGjSB+IOunpOqwnCArIOuPheumvSArIO2GteygnOuzgOyduA0KDQpzdW1tYXJ5KGxtMSkNCnN1bW1hcnkobG0yKQ0KYGBgDQoNCuq3uOuLpOydjCDtlYTsmpTtlZwg7YyM652866+47YSw66W8IOy2lOy2nO2VmOuKlCDtlajsiJjrpbwg7J6R7ISx7ZWY7JiA64ukLiDstpTstpwg7YyM652866+47YSw64qUIO2ajOq3gOqzhOyImOyZgCBwLXZhbHVl64ukLg0KYGBge3IgcDZ9DQogIG1lZGlfbW9kZWxfY29lMTwtZnVuY3Rpb24obG0xLGxtMil7DQogICAgbW9fbWU8LXN1bW1hcnkobG0xKQ0KICAgIG1vX21lX2Q8LWFzLmRhdGEuZnJhbWUobW9fbWVbNF0pDQogICAgY29lMTwtbW9fbWVfZFsyLDFdDQogICAgcF92YWwxPC1tb19tZV9kWzIsNF0NCiAgICANCiAgICBtb19tZTI8LXN1bW1hcnkobG0yKQ0KICAgIG1vX21lX2QyPC1hcy5kYXRhLmZyYW1lKG1vX21lMls0XSkNCiAgICBjb2UyPC1tb19tZV9kMlszLDFdIyMjeX5tZQ0KICAgIGNvZTM8LW1vX21lX2QyWzIsMV0jIyN5fngNCiAgICBwX3ZhbDI8LW1vX21lX2QyWzMsNF0NCiAgICBwX3ZhbDM8LW1vX21lX2QyWzIsNF0NCiAgICBwYXJhX3N1bTwtYyhjb2UxLGNvZTIsIGNvZTMsIHBfdmFsMSwgcF92YWwyLHBfdmFsMykNCiAgfQ0KbW08LW1lZGlfbW9kZWxfY29lMShsbTEsIGxtMikNCnByaW50KHJvdW5kKG1tLDMpKQ0KIyMj7JWe7JeQ7IScIOu2gO2EsCDrp6TqsJx+64+F66a9IO2ajOq3gOqzhOyImCwg7KKF7IaNfuunpOqwnCDtmozqt4Dqs4TsiJgsIOyiheyGjX7rj4Xrpr0g7ZqM6reA6rOE7IiY7J2066mwIOuSpOuKlCDrj5nsnbwg7Iic7ISc7J2YIHAtdmFsdWXri6QuDQoNCmBgYA0KDQrtmZTsgrTtkZzripQgYXJyb3dz7ZWo7IiY66W8IOyTsOuptCDrkJzri6QuIOydtOumhOyymOufvCDtmozsgrTtkZzri6QuIOuLpOunjCDsnbTqsr3smrAg7ISgIOyiheulmChsdHk9ICnsnYQg7Jyg7J2Y7ZWY66m0IDEg7Jyg7J2Y7ZWY7KeAIOyViuycvOuptCAyKOygkOyEoCnsnLzroZwg6re466as64+E66GdIOyhsOqxtOusuOydhCDsjbzri6QuDQphcnJvd3MoeOyijO2RnCwgeeyijO2RnCnsnbTquLAg65WM66y47JeQIOuCmOykkeyXkCDrs4Dqsr3tlZjroKTrqbQg7KKM7ZGc66W8IOydtOuPme2VtOyVvO2VnOuLpC4g7IiY7ZWZIOuqqOultOuKlCDrrLjqs7zrnbwg6ryt7KeT7KCQIOyijO2RnOulvCDri6Qg6rWs7ZaI64ukLi4u44Wg44WgDQoxKSnsnbTqsbQg66qo65GQIOycoOydmO2VmOqyjCDrgpjsmKjqsr3smrDsnbTri6QuDQpgYGB7ciBwN30NCiPruYgg7ISc7YyQDQpwbG90KDAsIHhsaW09IGMoLTUsNSksIHlsaW09YygtNSw1KSwgY29sPSAiI0ZGRkZGRiIsIHhsYWI9IiIsIHlsYWI9IiIsIHhheHQ9J24nLCB5YXh0PSduJykgIyPslYTrrLTqsoPrj4Qg7JeG64qUIO2dsOyDiSDtjJANCnJlY3QoLTQsLTQsLTIsLTIsIGx3ZCA9IDIpICMj64+F66a967OA7IiYIOyCrOqwge2YlQ0KcmVjdCgtMSwyLDEsNCwgbHdkID0gMikgIyPrp6TqsJzrs4DsiJgg7IKs6rCB7ZiVDQpyZWN0KDIsLTQsNCwtMiwgbHdkID0gMikgIyPsooXsho3sho3rs4DsiJgg7IKs6rCB7ZiVDQoNCiPrs4DsiJjrqoUg64Sj7Ja067O06riwDQogIHZhcl9uYW1lX3N1bTwtdmFyX25hbWUoMSwgMiwgMywgZCkNCiAgdGV4dCgtMywtMywgbGFiZWxzID0gdmFyX25hbWVfc3VtWzFdLCBjZXg9IDIpDQogIHRleHQoMCwzLCBsYWJlbHMgPSB2YXJfbmFtZV9zdW1bMl0sIGNleD0gMikNCiAgdGV4dCgzLC0zLCBsYWJlbHMgPSB2YXJfbmFtZV9zdW1bM10sIGNleD0gMikNCiPsnKDsnZjrj4Tsl5Ag65Sw66W4IO2ZlOyCtO2RnCDrhKPslrTrs7TquLANCmFycm93cygtMywtMiwgLTEuMDUsMywgbHdkPTIsIGxlbmd0aCA9IDAuMTUsIGx0eSA9IGlmZWxzZShtbVs0XTw9LjA1LDEsMikpDQphcnJvd3MoMSwzLCAzLC0xLjgsIGx3ZD0yLCBsZW5ndGggPSAwLjE1LCBsdHkgPSBpZmVsc2UobW1bNV08PS4wNSwxLDIpKQ0KYXJyb3dzKC0yLC0zLCAyLC0zLCBsd2Q9MiwgbGVuZ3RoID0gMC4xNSwgbHR5ID0gaWZlbHNlKG1tWzZdPD0uMDUsMSwyKSkNCmBgYA0KMikp7JqU6rG0IOycoOydmO2VmOyngCDslYrsnYDqsbDri6QNCmBgYHtyIHA4fQ0KeDwtcm5vcm0oMTAwMCkNCm1lPC1ybm9ybSgxMDAwKQ0KeTwtcm5vcm0oMTAwLDAsMikNCmNvbnQxPC1ybm9ybSgxMDApDQpkPC1kYXRhLmZyYW1lKHgsIG1lLCB5LCBjb250MSkNCg0KI+2ajOq3gOuqqOuNuCDrp4zrk6TquLANCmxtMTwtbG0obWV+eCArIGNvbnQxLCBkYXRhPSBkKSAj66ek6rCcfuuPheumvSArIO2GteygnOuzgOyduA0KDQpsbTI8LWxtKHl+eCttZSArIGNvbnQxLCBkYXRhID0gZCkgI+yiheyGjSB+IOunpOqwnCArIOuPheumvSArIO2GteygnOuzgOyduA0KbW08LW1lZGlfbW9kZWxfY29lMShsbTEsIGxtMikNCg0KI+u5iCDshJztjJANCnBsb3QoMCwgeGxpbT0gYygtNSw1KSwgeWxpbT1jKC01LDUpLCBjb2w9ICIjRkZGRkZGIiwgeGxhYj0iIiwgeWxhYj0iIiwgeGF4dD0nbicsIHlheHQ9J24nKSAjI+yVhOustOqyg+uPhCDsl4bripQg7Z2w7IOJIO2MkA0KcmVjdCgtNCwtNCwtMiwtMiwgbHdkID0gMikgIyPrj4Xrpr3rs4DsiJgg7IKs6rCB7ZiVDQpyZWN0KC0xLDIsMSw0LCBsd2QgPSAyKSAjI+unpOqwnOuzgOyImCDsgqzqsIHtmJUNCnJlY3QoMiwtNCw0LC0yLCBsd2QgPSAyKSAjI+yiheyGjeyGjeuzgOyImCDsgqzqsIHtmJUNCg0KI+uzgOyImOuqhSDrhKPslrTrs7TquLANCiAgdmFyX25hbWVfc3VtPC12YXJfbmFtZSgxLCAyLCAzLCBkKQ0KICB0ZXh0KC0zLC0zLCBsYWJlbHMgPSB2YXJfbmFtZV9zdW1bMV0sIGNleD0gMikNCiAgdGV4dCgwLDMsIGxhYmVscyA9IHZhcl9uYW1lX3N1bVsyXSwgY2V4PSAyKQ0KICB0ZXh0KDMsLTMsIGxhYmVscyA9IHZhcl9uYW1lX3N1bVszXSwgY2V4PSAyKQ0KI+ycoOydmOuPhOyXkCDrlLDrpbgg7ZmU7IK07ZGcIOuEo+yWtOuztOq4sA0KYXJyb3dzKC0zLC0yLCAtMS4wNSwzLCBsd2Q9MiwgbGVuZ3RoID0gMC4xNSwgbHR5ID0gaWZlbHNlKG1tWzRdPD0uMDUsMSwyKSkNCmFycm93cygxLDMsIDMsLTEuOCwgbHdkPTIsIGxlbmd0aCA9IDAuMTUsIGx0eSA9IGlmZWxzZShtbVs1XTw9LjA1LDEsMikpDQphcnJvd3MoLTIsLTMsIDIsLTMsIGx3ZD0yLCBsZW5ndGggPSAwLjE1LCBsdHkgPSBpZmVsc2UobW1bNl08PS4wNSwxLDIpKQ0KYGBgDQoNCiMjNC4g7ZqM6reA6rOE7IiY7JmAIOycoOydmOuPhOyXkCDrlLDrpbgg7ZGc6riwKCoqKikNCuuniOyngOunieycvOuhnCDqsIEg7ZmU7IK07ZGc7JeQIO2VhOyalO2VnCDqs4TsiJjsmYAgcC12YWx1ZeulvCDtkZzquLAg7ZWY7JiA64ukLg0K7LKr67KI7Ke466GcIOu5hO2RnOykgO2ZlCDtmozqt4Dqs4TsiJjrpbwg64Sj7Ja0IOuztOyVmOuLpC4NCmBgYHtyIHA5fQ0KeDwtcm5vcm0oMTAwMCkNCm1lPC1ybm9ybSgxMDAwKQ0KeTwtcm5vcm0oMTAwLDAsMikNCmNvbnQxPC1ybm9ybSgxMDApDQpkPC1kYXRhLmZyYW1lKHgsIG1lLCB5LCBjb250MSkNCg0KI+2ajOq3gOuqqOuNuCDrp4zrk6TquLANCmxtMTwtbG0obWV+eCArIGNvbnQxLCBkYXRhPSBkKSAj66ek6rCcfuuPheumvSArIO2GteygnOuzgOyduA0KDQpsbTI8LWxtKHl+eCttZSArIGNvbnQxLCBkYXRhID0gZCkgI+yiheyGjSB+IOunpOqwnCArIOuPheumvSArIO2GteygnOuzgOyduA0KbW08LW1lZGlfbW9kZWxfY29lMShsbTEsIGxtMikNCg0KI+u5iCDshJztjJANCnBsb3QoMCwgeGxpbT0gYygtNSw1KSwgeWxpbT1jKC01LDUpLCBjb2w9ICIjRkZGRkZGIiwgeGxhYj0iIiwgeWxhYj0iIiwgeGF4dD0nbicsIHlheHQ9J24nKSAjI+yVhOustOqyg+uPhCDsl4bripQg7Z2w7IOJIO2MkA0KcmVjdCgtNCwtNCwtMiwtMiwgbHdkID0gMikgIyPrj4Xrpr3rs4DsiJgg7IKs6rCB7ZiVDQpyZWN0KC0xLDIsMSw0LCBsd2QgPSAyKSAjI+unpOqwnOuzgOyImCDsgqzqsIHtmJUNCnJlY3QoMiwtNCw0LC0yLCBsd2QgPSAyKSAjI+yiheyGjeyGjeuzgOyImCDsgqzqsIHtmJUNCg0KI+uzgOyImOuqhSDrhKPslrTrs7TquLANCiAgdmFyX25hbWVfc3VtPC12YXJfbmFtZSgxLCAyLCAzLCBkKQ0KICB0ZXh0KC0zLC0zLCBsYWJlbHMgPSB2YXJfbmFtZV9zdW1bMV0sIGNleD0gMikNCiAgdGV4dCgwLDMsIGxhYmVscyA9IHZhcl9uYW1lX3N1bVsyXSwgY2V4PSAyKQ0KICB0ZXh0KDMsLTMsIGxhYmVscyA9IHZhcl9uYW1lX3N1bVszXSwgY2V4PSAyKQ0KI+ycoOydmOuPhOyXkCDrlLDrpbgg7ZmU7IK07ZGcIOuEo+yWtOuztOq4sA0KYXJyb3dzKC0zLC0yLCAtMS4wNSwzLCBsd2Q9MiwgbGVuZ3RoID0gMC4xNSwgbHR5ID0gaWZlbHNlKG1tWzRdPD0uMDUsMSwyKSkNCmFycm93cygxLDMsIDMsLTEuOCwgbHdkPTIsIGxlbmd0aCA9IDAuMTUsIGx0eSA9IGlmZWxzZShtbVs1XTw9LjA1LDEsMikpDQphcnJvd3MoLTIsLTMsIDIsLTMsIGx3ZD0yLCBsZW5ndGggPSAwLjE1LCBsdHkgPSBpZmVsc2UobW1bNl08PS4wNSwxLDIpKQ0KI+ycoOydmOuPhOyXkCDrlLDrnbwg67OE7ZGcIOuEo+q4sA0KdGV4dCgtMi41LDEsIHBhc3RlMCgiYj0iLHJvdW5kKG1tWzFdLCAzKSwgaWZlbHNlKG1tWzRdPj0uMDUsICIsIG5zIiwgaWZlbHNlKG1tWzRdPC4wNSAmIG1tWzRdPj0uMDEsICIqIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtbVs0XTwuMDEgJiBtbVs0XT49LjAwMSwiKioiLCIqKioiKSkpKSwgc3J0PTU2KQ0KdGV4dCgwLC00LCBwYXN0ZTAoImI9Iixyb3VuZChtbVszXSwgMyksIGlmZWxzZShtbVs2XT49LjA1LCAiLCBucyIsIGlmZWxzZShtbVs2XTwuMDUgJiBtbVs2XT49LjAxLCAiKiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobW1bNl08LjAxICYgbW1bNl0+PS4wMDEsIioqIiwiKioqIikpKSksIHNydD0wKQ0KdGV4dCgyLjUsMSwgcGFzdGUwKCJiPSIscm91bmQobW1bMl0sIDMpLCBpZmVsc2UobW1bNV0+PS4wNSwgIiwgbnMiLCBpZmVsc2UobW1bNV08LjA1ICYgbW1bNV0+PS4wMSwgIioiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobW1bNV08LjAxICYgbW1bNV0+PS4wMDEsIioqIiwiKioqIikpKSksIHNydD0tNTYpDQpgYGANCiMjNC4gPOyihe2VqT4NCuychOyXkCDrgpjsmKgg6rO87KCV7J2EIO2VnOuwqeyXkCDsp4TtlontlZjripQg7L2U65Oc64ukLg0KYGBge3IgcDEwfQ0KIyNtZWRpX21vZGVsKOuPheumveuzgOyImCDsl7TrsojtmLgsIOunpOqwnOuzgOyImCDsl7TrsojtmLgsIOyiheyGjeuzgOyImCDsl7TrsojtmLgsIOuNsOydtO2EsCwg66ek6rCcfuuPheumveuqqOuNuCwg7KKF7IaNfuuPheumveuqqOuNuCkNCg0KbWVkaV9tb2RlbDwtZnVuY3Rpb24oaW5kaTEsIG1lZGkxLCBkZXBlbiwgZGQsIGxtMSwgbG0yKXsNCiAgbWVkaV9tb2RlbF9jb2UxPC1mdW5jdGlvbihsbTEsbG0yKXsNCiAgICBtb19tZTwtc3VtbWFyeShsbTEpDQogICAgbW9fbWVfZDwtYXMuZGF0YS5mcmFtZShtb19tZVs0XSkNCiAgICBjb2UxPC1tb19tZV9kWzIsMV0NCiAgICBwX3ZhbDE8LW1vX21lX2RbMiw0XQ0KICAgIA0KICAgIG1vX21lMjwtc3VtbWFyeShsbTIpDQogICAgbW9fbWVfZDI8LWFzLmRhdGEuZnJhbWUobW9fbWUyWzRdKQ0KICAgIGNvZTI8LW1vX21lX2QyWzMsMV0jIyN5fm1lDQogICAgY29lMzwtbW9fbWVfZDJbMiwxXSMjI3l+eA0KICAgIHBfdmFsMjwtbW9fbWVfZDJbMyw0XQ0KICAgIHBfdmFsMzwtbW9fbWVfZDJbMiw0XQ0KICAgIHBhcmFfc3VtPC1jKGNvZTEsY29lMiwgY29lMywgcF92YWwxLCBwX3ZhbDIscF92YWwzKQ0KICB9DQogIG1tPC1tZWRpX21vZGVsX2NvZTEobG0xLCBsbTIpDQogIA0KICBwbG90KDAsIHhsaW09IGMoLTEwLDEwKSwgeWxpbT1jKC0xMCwxMCksIGNvbD0gIiNGRkZGRkYiLCB4bGFiPSIiLCB5bGFiPSIiLHhheHQ9J24nLCB5YXh0PSduJykNCnJlY3QoLTgsLTgsLTQsLTQsIGx3ZCA9IDIpDQpyZWN0KC0yLDUsMiw5LCBsd2QgPSAyKQ0KcmVjdCg4LC04LDQsLTQsIGx3ZCA9IDIpDQphcnJvd3MoLTYsLTQsIC0yLjIsNywgbHdkPTIsIGxlbmd0aCA9IDAuMTUsIGx0eSA9IGlmZWxzZShtbVs0XTw9LjA1LDEsMikpDQphcnJvd3MoMiw3LDYsLTQsIGx3ZD0yLCBsZW5ndGggPSAwLjE1LCBsdHkgPSBpZmVsc2UobW1bNV08PS4wNSwxLDIpKQ0KYXJyb3dzKC00LC02LDQsLTYsIGx3ZD0yLCBsZW5ndGggPSAwLjE1LCBsdHkgPSBpZmVsc2UobW1bNl08PS4wNSwxLDIpKQ0KdmFyX25hbWU8LWZ1bmN0aW9uKGluZGkxLCBtZWRpMSwgZGVwZW4sIGRkKXsNCiAgdmFyX25hbWVfc3VtPC1jKCkNCiAgdmFyX25hbWVfc3VtWzFdPC1jb2xuYW1lcyhkZFtpbmRpMV0pDQogIHZhcl9uYW1lX3N1bVsyXTwtY29sbmFtZXMoZGRbbWVkaTFdKQ0KICB2YXJfbmFtZV9zdW1bM108LWNvbG5hbWVzKGRkW2RlcGVuXSkNCiAgcHJpbnQodmFyX25hbWVfc3VtKQ0KfQ0KdmFyX25hbWVfc3VtPC12YXJfbmFtZShpbmRpMSwgbWVkaTEsIGRlcGVuLCBkZCkNCnRleHQoLTYsLTYsIGxhYmVscyA9IHZhcl9uYW1lX3N1bVsxXSwgY2V4PSAyKQ0KdGV4dCgwLDcsIGxhYmVscyA9IHZhcl9uYW1lX3N1bVsyXSwgY2V4PSAyKQ0KdGV4dCg2LC02LCBsYWJlbHMgPSB2YXJfbmFtZV9zdW1bM10sIGNleD0gMikNCg0KdGV4dCgtNSwxLCBwYXN0ZTAoImI9Iixyb3VuZChtbVsxXSwgMyksIGlmZWxzZShtbVs0XT49LjA1LCAiLCBucyIsIGlmZWxzZShtbVs0XTwuMDUgJiBtbVs0XT49LjAxLCAiKiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UobW1bNF08LjAxICYgbW1bNF0+PS4wMDEsIioqIiwiKioqIikpKSksIHNydD01NikNCnRleHQoMCwtNywgcGFzdGUwKCJiPSIscm91bmQobW1bM10sIDMpLCBpZmVsc2UobW1bNl0+PS4wNSwgIiwgbnMiLCBpZmVsc2UobW1bNl08LjA1ICYgbW1bNl0+PS4wMSwgIioiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG1tWzZdPC4wMSAmIG1tWzZdPj0uMDAxLCIqKiIsIioqKiIpKSkpLCBzcnQ9MCkNCnRleHQoNSwxLCBwYXN0ZTAoImI9Iixyb3VuZChtbVsyXSwgMyksIGlmZWxzZShtbVs1XT49LjA1LCAiLCBucyIsIGlmZWxzZShtbVs1XTwuMDUgJiBtbVs1XT49LjAxLCAiKiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShtbVs1XTwuMDEgJiBtbVs1XT49LjAwMSwiKioiLCIqKioiKSkpKSwgc3J0PS01NikNCn0NCg0KI3Rlc3QNCuyVhOy5qOuwpTwtcm5vcm0oMTAwKQ0K7KCQ7Ius67ClPC14K3Jub3JtKDEwMCkNCuyggOuFgeuwpTwtbWUgK3Jub3JtKDEwMCkNCmQ8LWRhdGEuZnJhbWUo7JWE7Lmo67ClLCDsoJDsi6zrsKUsIOyggOuFgeuwpSkNCmxtMTwtbG0obWV+eCwgZCkNCmxtMjwtbG0oeX54ICsgbWUgLCBkKQ0KbWVkaV9tb2RlbCgxLDIsMyxkLGxtMSxsbTIpDQpgYGANCg0K7Z2U7Z6IIOunkO2VmOuKlCDsmYTso6Trp6TqsJzri6Qo64KcIOydtO2RnO2YhCDsi6vslrTtlZzri6QuICkNCg==