Chapter 3: 왜 매상이 감소하는가?
STEP 1 < 현재의 Fact 와 원하는 Ideal 케이스에 대한 정의를 간단하게 내린다 >
현재: 매출이 떨어짐
해결: 지난달과 비슷한 매출을 확보해야한다
STEP 2 < 매출 감소의 원인에 대해 사실에 기반한 가설을 세워 보자 >
최종가설: 매출의 감소는 신규 회원들이 광고를 안 봐서이다. (그럼 신규 회원들이 돈은 냈나?)
매출의 감소 원인 1) 광고에 문제가 생김
2) 매월 일관성이 없는 게임의 이벤트에 문제가 있나?
사실관계파악 (정보수집) : 1) 광고에 문제가 생겼다 - 알고보니 돈이 없어서 많이 못함
2) 일관성 문제 - 이벤트 내용은 딱히 달라진게 없었다.
!! 광고에 문제가 생겨서 매출이 떨어졌다는 가설에 힘이 실린다.
돈이 없어서 광고가 많이 안 됐으니까, 홍보가 제대로 이루어지지 않은 문제인거 같다.
신규 회원이 늘지 못한 것일수도 있고, 기존 유저가 새로운 이벤트를 시도하지 않은 것일 수도 있다.
신규 회원의 감소 (= 매출이 증가하지 않음) 과 매출의 감소의 관계를 데이터로 확인해본다.
STEP 3 <어떤 데이터를 봐야하나?>
문제 * 매출이 떨어졌다.
* 광고를 적게 했다.
* 그래서 신규 유저가 줄었다. (가설)
해결책 * 광고비를 더 투자한다.
DAU DATA : 하루에 한 번이상 게임을 이용한 유저
- log_date :로그인 한 날
- 앱 이름 : app_name
- 유저 : user_id
DPU DATA : 하루에 1원 이상 돈을 낸 유저
- 과금일 : log_date
- 앱 이름 : app_name
- 유저 ID : user_id
- 과금액 : payment
INSTALL DATA : 설치 시작 날짜 (즉, 신규회원)
-이용 시작한 날: install_date
-앱 이름 ; app_name
- 유저 : user_id
DATA 이해하기 DAU DATA (Daily Active User)
2013-06-01 날 game-01 앱을 사용한 사람은 id 116 이다.
>> 접속한 사람들 내역 확인
DPU DATA (Daily Payment User)
2013-06-01 날 game-01 앱에서 결제한 사람의 id 는 351 이다.
같은 사람이 같은 날에 여러번 들어와서 게임한 경우에는 그때마다 과금액 데이터가 남는다.
Install Data
게임을 시작한 유저들
데이터 전처리 하기
DAU + Install : 신규로 앱을 설치해서 하루에 한번 이상 게임을 이용한 유저들이 있는지 확인
DPU + : 들어와서 과금한 유저가 있을까?
Logical Flow : 하루에 한 번 이상 게임을 한 사람이 (DAU) 새로운 사람인가? (Install) 그 유저들이 있다면 돈을 냈나? (DPU)
< Payment NA 의 이해 >
log_date 는 들어와서 돈을 낸 날짜 install_date 는 앱을 설치한 날짜
즉, 신규로 들어와서 설치를 했는데 돈을 낸 적이 없다는 것.
- 비과금 유저의 과금액 0 넣기 (NA= payment)
## log_date user_id app_name install_date payment
## 1 2013-06-01 1 game-01 2013-04-15 0
## 2 2013-06-01 3 game-01 2013-04-15 0
## 3 2013-06-01 6 game-01 2013-04-15 0
## 4 2013-06-01 11 game-01 2013-04-15 0
## 5 2013-06-01 17 game-01 2013-04-15 0
## 6 2013-06-01 18 game-01 2013-04-15 0
- 월차로 집계하기
매월 유저별로 집계한 데이터로 변환 시킨다. -> 월별로
1) 월 만 빼낸다 substr 함수 사용 (log_date, install_date)
2) 월 별 payment 합계를 본다
## log_date user_id app_name install_date payment log_month install_month
## 1 2013-06-01 1 game-01 2013-04-15 0 2013-06 2013-04
## 2 2013-06-01 3 game-01 2013-04-15 0 2013-06 2013-04
## 3 2013-06-01 6 game-01 2013-04-15 0 2013-06 2013-04
## 4 2013-06-01 11 game-01 2013-04-15 0 2013-06 2013-04
## 5 2013-06-01 17 game-01 2013-04-15 0 2013-06 2013-04
## 6 2013-06-01 18 game-01 2013-04-15 0 2013-06 2013-04
- 신규/유저를 구분하는 항목 추가하기
설치한 달과 들어온 달이 같으면 = 신규(install), 아니면 기존 고객 (existing)
## # A tibble: 6 x 5
## # Groups: log_month, user_id [6]
## log_month user_id install_month payment use_type
## <chr> <int> <chr> <dbl> <chr>
## 1 2013-06 1 2013-04 0 existing
## 2 2013-06 2 2013-04 0 existing
## 3 2013-06 3 2013-04 149940 existing
## 4 2013-06 4 2013-04 0 existing
## 5 2013-06 6 2013-04 0 existing
## 6 2013-06 7 2013-04 0 existing
- 그래프 시각화

## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0 0.0 0.0 160.8 0.0 208610.0

Conclustion
1. 매상이 떨어졌다 (사실)
2. 신규 유저의 매상이 감소했고,그 중에서 20,000원 이하의 라이트 유저의 감소가 컸다 (사실)
3. 광고 비용을 떨어트리면 안된다.
Chapter 4 : 이탈 고객 분석 (탈퇴하는 이유를 분석) - 크로스 집계
- USER 의 수가 감소 했음
원인에 대한 가설 1) 광고 때문에 탈퇴 유저수가 더 많다. - 광고는 지난 달이랑 비슷했고, 신규 유저도 있다. 2) 매월 테마를 바꿔서 개최하던 이벤트가 식상해졌다. - 이벤트 내용도 거의 바뀌지 않았다. 3) 특정 고객층의 이탈이 있다. - 유력 가설
원인을 제대로 알 수 없기 때문에 ‘탐색형’ 데이터 분석을 실시행
데이터 선정
DAU - 1 회 이상 방문 데이터
- log_date, app_name, id
USER.INFO - 사용자 고객 정보 관련 데이터
- install_date, app_name, id, gender, generation, device_type
- Gender, Generation, Device_type 별 집계하기
3.1 Gender
Gender 별 방문에 대한 집계 이기 때문에, log_month 를 집계한다.
## # A tibble: 4 x 3
## # Groups: log_month [2]
## log_month gender n
## <chr> <fct> <int>
## 1 2013-08 F 47343
## 2 2013-08 M 46842
## 3 2013-09 F 38027
## 4 2013-09 M 38148
## gender
## log_month F M
## 2013-08 47343 46842
## 2013-09 38027 38148
table 함수로 Cross 교차 집계 - 특징: table 함수가 두 factor 의 집계를 보기엔 좋다.
성별에 따른 방문 유저의 수가 준것 같지 않다.
3.2 Generation
## generation
## log_month 10 20 30 40 50
## 2013-08 18785 33671 28072 8828 4829
## 2013-09 15391 27229 22226 7494 3835
연령 별 차이도 없는 것 같아 보인다.
3.3 Gender x Generation
dcast 함수 사용 : 두 factor 형 크로스 집계 사용
## log_month F_10 F_20 F_30 F_40 F_50 M_10 M_20 M_30 M_40 M_50
## 1 2013-08 9091 17181 14217 4597 2257 9694 16490 13855 4231 2572
## 2 2013-09 7316 13616 11458 3856 1781 8075 13613 10768 3638 2054
성별 + 나이에서도 뚜렷하게 이탈이 일어난 것 같지 않아 보인다.
3.4 Device
## device_type
## log_month Android iOS
## 2013-08 46974 47211
## 2013-09 29647 46528
차이가 나타남

A/B Test
A/B Test 란, 웹 사이트 방문자를 임의의 두 집단으로 나누고, A 집단에게는 기존 사이트를, B 집단에게는 새로운 사이트를 보여준 다음, 두 집단 중 어떤 집단이 더 높은 성과를 보여주는지에 대해 평가하는 방식이다.
성과 기준은 : 회원 가입률, 재방문율, 구매전환률 등의 지표를 확인한다.
인과 관계를 찾기 위한 테스트
주의 할 점 : 임의적 할당 (Random Assignment)
그룹 A/B를 남/여 혹은 짝수/홀수, 첫 일주일 방문 자/그 다음 일주일 방문자 등 임의적이지 않은 방식으로 구분 하는 경우, 두 집단의 차이가 무엇 때문인지 가려낼 수가 없다.
임의적 추출 예시) 초등학교 학생들을 대상으로 한 실험의 결과를 초중고 학생에게 모두 적용하거나, 페이스 북 사용자를 대상의 실험을 트위터에 적용시키거나 하면 집단의 성격과 모집단의 성격에 차이가 있기 때문에 기대와 다른 결과를 나타낼 수 있다.
1) 전후 비교 X
Before/ After 로 확인하면, 외부 요인을 배제 할 수 없다.
예를 들어, 배너 B를 광고하는 데 전체 구매율이 좋았다.
배너 B를 광고하는데 다른 이벤트가 대박을 쳤다.
배너 B를 광고하는데 방송에 소개되었다.
>> 외부요인이 작용하였기 때문에, 그렇다면 A를 내걸었어도 좋았겠네
그건 아무도 모름
2) 통계적 가설 T.TEST 는 커트라인으로만 바라보기
적어도 가설 검정에서는 의미가 있는 차이가 나타났으므로 비지니스 상에서
의미가 있는 차이인지 검토를 해봐야한다.
데이터 설명 < 배너 광고의 표시 획수 정보> log_date : 표시 날짜 test_name : test 이름 test_case : A, B user_id transcation_id : 배너 광고가 표시되었을 때 발생하는 id
데이터 설명 <배너 광고의 클릿 횟수 정보> log_date : 클릭한 날짜 test_name : test 이름 test_case : A, B user_id transcation_id : 배너 광고가 표시되었을 때 발생하는 id
Transcation_id 기준 : 배너광고가 표시되었을때 발생하는 id 로 표시로그와 클릭 로그를 결합할 키로 사용
즉, 표시와 클릭 기록이 맞는 기준으로 병합
## transaction_id log_date app_name test_name test_case user_id log_date.g
## 1 1 2013-10-02 game-01 sales_test A 49017 <NA>
## 2 2 2013-10-02 game-01 sales_test B 49018 <NA>
## 3 3 2013-10-02 game-01 sales_test A 44338 <NA>
## 4 4 2013-10-02 game-01 sales_test A 44339 <NA>
## 5 5 2013-10-02 game-01 sales_test A 28598 <NA>
## 6 6 2013-10-02 game-01 sales_test B 30306 <NA>
## app_name.g test_name.g test_case.g user_id.g
## 1 <NA> <NA> <NA> NA
## 2 <NA> <NA> <NA> NA
## 3 <NA> <NA> <NA> NA
## 4 <NA> <NA> <NA> NA
## 5 <NA> <NA> <NA> NA
## 6 <NA> <NA> <NA> NA
## transaction_id log_date app_name test_name test_case user_id log_date.g
## 36 36 2013-10-02 game-01 sales_test B 35315 2013-10-02
## app_name.g test_name.g test_case.g user_id.g
## 36 game-01 sales_test B 35315
배너 광고 B가 user_id 35315 에게 표시 된 날짜가 10월 2일 이였는데, 해당 유저는 B를 클릭했다. 이 transcation_id 는 36 번이다.
클릭 유무 플래그 작성하기
User_id.g 는 클릭을 한 아이디를 나타내주기 때문에 NA 이면 클릭을 안 했다는 것
클릭률 집계하기
## # A tibble: 2 x 2
## test_case cvr
## * <fct> <dbl>
## 1 A 0.0803
## 2 B 0.115
x2 실행하기
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: ab.test.imp$test_case and ab.test.imp$is_goal
## X-squared = 308.38, df = 1, p-value < 2.2e-16
테스트 케이스별 클릭율 산출하기
- 날짜, 테스트 케이스 별 산출
- 시각화

Chapter 5 : A/B Test -2
A.B Test : 방문자 수가 비슷한 두 개의 웹 페이지를 비교
일반적으로 새롭게 도입하는 기능이 의도한 바대로 효과가 있을지 확인하기 위해서이다.
CASE STUDY - 두 개의 호텔 예약 사이트 A/B 테스트
Data Summary
Variance A : 기존의 제품 혹은 기능을 묘사하는 통제 집단
Variance B : 새로운 제품 혹은 기능을 묘사하여, 사용자가 좋아하는지 예약 수가 늘었는지 확인하는 예약 집단
Converted - 전환률 T/F
가설 설정
Ho: A (기존), B(신규) 집단 사이의 전환률은 같다. (= 효과가 없다)
H1: 효과가 있다.
## [1] 20
## [1] 721
## [1] 0.02773925
## [1] 0.05068493
## [1] 82.71918
B 가 A 보다 82% 더 높다.
Pooled Probability for Test Versions A & B
## [1] 5.404837e-05
LS0tDQp0aXRsZTogIkJ1c2luZXNzIENhc2UiDQphdXRob3I6ICJET0VVTiINCmRhdGU6ICIwMi8wMi8yMDIxIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgIyBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBoaWdobGlnaHQ6IHplbmJ1cm4NCiAgICAjIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6ICJmbGF0bHkiDQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQotLS0NCmBgYHtyfQ0KI2xpYnJhcnkoRFQpDQoNCg0KI2xpYnJhcnkoa25pdHIpDQojbGlicmFyeShybWFya2Rvd24pDQojbGlicmFyeShtYXJrZG93bikNCmBgYA0KDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgY2FjaGUgPSBUUlVFLCBmaWcuaGVpZ2h0ID0gNywgZmlnLndpZHRoID0gMTApDQpgYGANCg0KDQojIENoYXB0ZXIgMzog7JmcIOunpOyDgeydtCDqsJDshoztlZjripTqsIA/IA0KDQpTVEVQIDEgPCDtmITsnqzsnZggRmFjdCDsmYAg7JuQ7ZWY64qUIElkZWFsIOy8gOydtOyKpOyXkCDrjIDtlZwg7KCV7J2Y66W8IOqwhOuLqO2VmOqyjCDrgrTrprDri6QgPiANCg0KICAgICAg7ZiE7J6sOiDrp6TstpzsnbQg65ao7Ja07KeQIA0KICAgICAg7ZW06rKwOiDsp4Drgpzri6zqs7wg67mE7Iq37ZWcIOunpOy2nOydhCDtmZXrs7TtlbTslbztlZzri6QgDQogICAgICANClNURVAgMiA8IOunpOy2nCDqsJDshozsnZgg7JuQ7J247JeQIOuMgO2VtCDsgqzsi6Tsl5Ag6riw67CY7ZWcIOqwgOyEpOydhCDshLjsm4wg67O07J6QID4gDQoNCiAg7LWc7KKF6rCA7ISkOiDrp6TstpzsnZgg6rCQ7IaM64qUIOyLoOq3nCDtmozsm5Drk6TsnbQg6rSR6rOg66W8IOyViCDrtJDshJzsnbTri6QuICjqt7jrn7wg7Iug6recIO2ajOybkOuTpOydtCDrj4jsnYAg64OI64KYPykNCg0KICAgICAg66ek7Lac7J2YIOqwkOyGjCDsm5DsnbggMSkg6rSR6rOg7JeQIOusuOygnOqwgCDsg53quYAgDQogICAgICAgICAgICAgICAgICAgICAgIDIpIOunpOyblCDsnbzqtIDshLHsnbQg7JeG64qUIOqyjOyehOydmCDsnbTrsqTtirjsl5Ag66y47KCc6rCAIOyeiOuCmD8gDQogICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAg7IKs7Iuk6rSA6rOE7YyM7JWFICjsoJXrs7TsiJjsp5EpIDogMSkg6rSR6rOg7JeQIOusuOygnOqwgCDsg53qsrzri6QgLSDslYzqs6Drs7Tri4gg64+I7J20IOyXhuyWtOyEnCDrp47snbQg66q77ZWoIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAyKSDsnbzqtIDshLEg66y47KCcIC0g7J2067Kk7Yq4IOuCtOyaqeydgCDrlLHtnogg64us65287KeE6rKMIOyXhuyXiOuLpC4gDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgISEg6rSR6rOg7JeQIOusuOygnOqwgCDsg53qsqjshJwg66ek7Lac7J20IOuWqOyWtOyhjOuLpOuKlCDqsIDshKTsl5Ag7Z6Y7J20IOyLpOumsOuLpC4gDQogICAgICAgICDrj4jsnbQg7JeG7Ja07IScIOq0keqzoOqwgCDrp47snbQg7JWIIOuQkOycvOuLiOq5jCwg7ZmN67O06rCAIOygnOuMgOuhnCDsnbTro6jslrTsp4Dsp4Ag7JWK7J2AIOusuOygnOyduOqxsCDqsJnri6QuIA0KICAgICAgICAg7Iug6recIO2ajOybkOydtCDripjsp4Ag66q77ZWcIOqyg+ydvOyImOuPhCDsnojqs6AsIOq4sOyhtCDsnKDsoIDqsIAg7IOI66Gc7Jq0IOydtOuypO2KuOulvCDsi5zrj4TtlZjsp4Ag7JWK7J2AIOqyg+ydvCDsiJjrj4Qg7J6I64ukLiANCiAgICAgICAgIA0KICAgICAgICAg7Iug6recIO2ajOybkOydmCDqsJDshowgKD0g66ek7Lac7J20IOymneqwgO2VmOyngCDslYrsnYwpIOqzvCDrp6TstpzsnZgg6rCQ7IaM7J2YIOq0gOqzhOulvCDrjbDsnbTthLDroZwg7ZmV7J247ZW067O464ukLiANCiAgICAgICAgIA0KU1RFUCAzIDzslrTrlqQg642w7J207YSw66W8IOu0kOyVvO2VmOuCmD8+IA0KDQoNCiAgICAgIOusuOygnCAqIOunpOy2nOydtCDrlqjslrTsoYzri6QuIA0KICAgICAgICAgICAqIOq0keqzoOulvCDsoIHqsowg7ZaI64ukLiANCiAgICAgICAgICAgKiDqt7jrnpjshJwg7Iug6recIOycoOyggOqwgCDspITsl4jri6QuICjqsIDshKQpDQogICAgICAgICAgIA0KICAgICAg7ZW06rKw7LGFICog6rSR6rOg67mE66W8IOuNlCDtiKzsnpDtlZzri6QuIA0KICAgICAgDQogICAgICBEQVUgREFUQSA6IO2VmOujqOyXkCDtlZwg67KI7J207IOBIOqyjOyehOydhCDsnbTsmqntlZwg7Jyg7KCAIA0KICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAtIGxvZ19kYXRlIDrroZzqt7jsnbgg7ZWcIOuCoCANCiAgICAgICAgICAgICAgLSDslbEg7J2066aEIDogYXBwX25hbWUgDQogICAgICAgICAgICAgIC0g7Jyg7KCAIDogdXNlcl9pZCANCiAgICAgICAgICAgICAgDQogICAgICBEUFUgREFUQSA6IO2VmOujqOyXkCAx7JuQIOydtOyDgSDrj4jsnYQg64K4IOycoOyggCANCiAgICAgIA0KICAgICAgICAgICAgICAtIOqzvOq4iOydvCA6IGxvZ19kYXRlDQogICAgICAgICAgICAgIC0g7JWxIOydtOumhCA6IGFwcF9uYW1lIA0KICAgICAgICAgICAgICAtIOycoOyggCBJRCA6IHVzZXJfaWQNCiAgICAgICAgICAgICAgLSDqs7zquIjslaEgOiBwYXltZW50IA0KICAgICAgICAgICAgICANCiAgICAgIElOU1RBTEwgREFUQSA6IOyEpOy5mCDsi5zsnpEg64Kg7KecICjspoksIOyLoOq3nO2ajOybkCkNCiAgICAgIA0KICAgICAgICAgICAgICAt7J207JqpIOyLnOyeke2VnCDrgqA6IGluc3RhbGxfZGF0ZQ0KICAgICAgICAgICAgICAt7JWxIOydtOumhCA7IGFwcF9uYW1lIA0KICAgICAgICAgICAgICAtIOycoOyggCA6IHVzZXJfaWQgDQogICAgICAgICAgICAgIA0KDQoNCmBgYHtyIGNhcnN9DQoNCnNldHdkKCdDOi9Vc2Vycy9BZG1pbmlzdHJhdG9yL0Rlc2t0b3AvUiBBbmFseXNpcy9CdXNpbmVzcyBSIEFhbmx5c2lzIHNvdXJjZS9zb3VyY2UvRGF0YUFuYWx5c2lzX3NyYy9SJykNCg0KcmVhZC5jc3YoInNlY3Rpb24zLWRhdS5jc3YiLCBoZWFkZXIgPSBULCBzdHJpbmdzQXNGYWN0b3JzID0gVCkgLT4gZGF1IA0KcmVhZC5jc3YoInNlY3Rpb24zLWRwdS5jc3YiLCBoZWFkZXIgPSBULCBzdHJpbmdzQXNGYWN0b3JzID0gVCkgLT4gZHB1IA0KcmVhZC5jc3YoInNlY3Rpb24zLWluc3RhbGwuY3N2IiwgaGVhZGVyID0gVCwgc3RyaW5nc0FzRmFjdG9ycyA9IFQpIC0+IGluc3RhbGwNCg0KYGBgDQoNCiBEQVRBIOydtO2VtO2VmOq4sCANCiBEQVUgREFUQSAoRGFpbHkgQWN0aXZlIFVzZXIpDQoNCiAgICAyMDEzLTA2LTAxIOuCoCBnYW1lLTAxIOyVseydhCDsgqzsmqntlZwg7IKs656M7J2AIGlkIDExNiDsnbTri6QuIA0KICAgID4+IOygkeyGje2VnCDsgqzrnozrk6Qg64K07JetIO2ZleyduCANCg0KYGBge3IgcHJlc3N1cmUsIGVjaG89RkFMU0V9DQoNCkRUOjogZGF0YXRhYmxlKGRhdSkNCmBgYA0KDQoNCkRQVSBEQVRBIChEYWlseSBQYXltZW50IFVzZXIpDQoNCiAgICAyMDEzLTA2LTAxIOuCoCBnYW1lLTAxIOyVseyXkOyEnCDqsrDsoJztlZwg7IKs656M7J2YIGlkIOuKlCAzNTEg7J2064ukLiANCiAgICDqsJnsnYAg7IKs656M7J20IOqwmeydgCDrgqDsl5Ag7Jes65+s67KIIOuTpOyWtOyZgOyEnCDqsozsnoTtlZwg6rK97Jqw7JeQ64qUIOq3uOuVjOuniOuLpCDqs7zquIjslaEg642w7J207YSw6rCAIOuCqOuKlOuLpC4gDQoNCmBgYHtyfQ0KDQpEVDo6IGRhdGF0YWJsZShkcHUpDQpgYGANCg0KIEluc3RhbGwgRGF0YSANCg0KICAgIOqyjOyehOydhCDsi5zsnpHtlZwg7Jyg7KCA65OkIA0KDQpgYGB7cn0NCg0KRFQ6OiBkYXRhdGFibGUoaW5zdGFsbCkNCg0KYGBgDQoNCiDrjbDsnbTthLAg7KCE7LKY66asIO2VmOq4sCANCg0KMS4gREFVICsgSW5zdGFsbCA6IOyLoOq3nOuhnCDslbHsnYQg7ISk7LmY7ZW07IScIO2VmOujqOyXkCDtlZzrsogg7J207IOBIOqyjOyehOydhCDsnbTsmqntlZwg7Jyg7KCA65Ok7J20IOyeiOuKlOyngCDtmZXsnbggDQoNCjIuIERQVSArIDog65Ok7Ja07JmA7IScIOqzvOq4iO2VnCDsnKDsoIDqsIAg7J6I7J2E6rmMPyANCg0KTG9naWNhbCBGbG93IDog7ZWY66Oo7JeQIO2VnCDrsogg7J207IOBIOqyjOyehOydhCDtlZwg7IKs656M7J20IChEQVUpDQogICAgICAgICAgICAgICDsg4jroZzsmrQg7IKs656M7J246rCAPyAoSW5zdGFsbCkNCiAgICAgICAgICAgICAgIOq3uCDsnKDsoIDrk6TsnbQg7J6I64uk66m0IOuPiOydhCDrg4jrgpg/IChEUFUpDQoNCg0KYGBge3J9DQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgIERBVSArIElOU1RBTEwgPSBkYXVfaW5zdGFsbCANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KDQptZXJnZShkYXUsIGluc3RhbGwsIGJ5ID1jKCJ1c2VyX2lkIiwgImFwcF9uYW1lIikpIC0+ZGF1X2luc3RhbGwNCg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICBEQVUgKyBJTlNUQUxMID0gZGF1X2luc3RhbGwgKyBwYXltZW50ID0gZGF1X2luc3RhbGxfcGF5bWVudCANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KDQptZXJnZShkYXVfaW5zdGFsbCwgZHB1LCBieT0gYygibG9nX2RhdGUiICwgInVzZXJfaWQiLCAiYXBwX25hbWUiKSwgYWxsLnggPSBUICkgLT4gZGF1X2luc3RhbGxfcGF5bWVudCANCg0KDQpkYXRhdGFibGUoZGF1X2luc3RhbGxfcGF5bWVudCkNCmBgYA0KDQo8IFBheW1lbnQgTkEg7J2YIOydtO2VtCA+IA0KICANCmxvZ19kYXRlIOuKlCDrk6TslrTsmYDshJwg64+I7J2EIOuCuCDrgqDsp5wgDQppbnN0YWxsX2RhdGUg64qUIOyVseydhCDshKTsuZjtlZwg64Kg7KecIA0KDQrspoksIOyLoOq3nOuhnCDrk6TslrTsmYDshJwg7ISk7LmY66W8IO2WiOuKlOuNsCDrj4jsnYQg64K4IOyggeydtCDsl4bri6TripQg6rKDLiANCg0KMy4g67mE6rO86riIIOycoOyggOydmCDqs7zquIjslaEgMCDrhKPquLAgKE5BPSBwYXltZW50KQ0KDQpgYGB7cn0NCg0KZGF1X2luc3RhbGxfcGF5bWVudCRwYXltZW50W2lzLm5hKGRhdV9pbnN0YWxsX3BheW1lbnQkcGF5bWVudCldIDwtIDAgDQoNCmhlYWQoZGF1X2luc3RhbGxfcGF5bWVudCkNCmBgYA0KDQo0LiDsm5TssKjroZwg7KeR6rOE7ZWY6riwIA0KDQrrp6Tsm5Qg7Jyg7KCA67OE66GcIOynkeqzhO2VnCDrjbDsnbTthLDroZwg67OA7ZmYIOyLnO2CqOuLpC4gLT4g7JuU67OE66GcIA0KDQogICAgMSkg7JuUIOunjCDrubzrgrjri6Qgc3Vic3RyIO2VqOyImCDsgqzsmqkgKGxvZ19kYXRlLCBpbnN0YWxsX2RhdGUpDQogICAgMikg7JuUIOuzhCBwYXltZW50IO2VqeqzhOulvCDrs7jri6QgDQoNCmBgYHtyfQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgTG9nX21vbnRoIOyblCDstpTstpwgDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCmRhdV9pbnN0YWxsX3BheW1lbnQkbG9nX21vbnRoIDwtIHN1YnN0cihkYXVfaW5zdGFsbF9wYXltZW50JGxvZ19kYXRlLCAxLCA3ICkNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgSW5zdGFsbF9tb250aCDsm5Qg7LaU7LacIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoNCmRhdV9pbnN0YWxsX3BheW1lbnQkaW5zdGFsbF9tb250aCA8LSBzdWJzdHIoZGF1X2luc3RhbGxfcGF5bWVudCRpbnN0YWxsX2RhdGUsIDEsIDcgKQ0KDQoNCmhlYWQoZGF1X2luc3RhbGxfcGF5bWVudCkNCg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICDsm5Trs4Qg7LaU7LacIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpsaWJyYXJ5KGRwbHlyKQ0KDQpkYXVfaW5zdGFsbF9wYXltZW50ICU+JSAgDQogIGdyb3VwX2J5KGxvZ19tb250aCwgdXNlcl9pZCwgaW5zdGFsbF9tb250aCkgJT4lICANCiAgc3VtbWFyaXNlKHBheW1lbnQgPSBzdW0ocGF5bWVudCkpIC0+IG1hdS5wYXltZW50DQoNCg0KYGBgDQoNCg0KNS4g7Iug6recL+ycoOyggOulvCDqtazrtoTtlZjripQg7ZWt66qpIOy2lOqwgO2VmOq4sCANCg0K7ISk7LmY7ZWcIOuLrOqzvCDrk6TslrTsmKgg64us7J20IOqwmeycvOuptCA9IOyLoOq3nChpbnN0YWxsKSwg7JWE64uI66m0IOq4sOyhtCDqs6DqsJ0gKGV4aXN0aW5nKQ0KDQpgYGB7cn0NCg0KaWZlbHNlKG1hdS5wYXltZW50JGluc3RhbGxfbW9udGggPT0gbWF1LnBheW1lbnQkbG9nX21vbnRoLCANCiAgICAgICAiaW5zdGFsbCIsICJleGlzdGluZyIpIC0+IG1hdS5wYXltZW50JHVzZV90eXBlDQoNCg0KaGVhZChtYXUucGF5bWVudCkNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgbG9nX2RhdGUgKOq1rOunpO2VnCDrgqDsp5wpIOyZgCDquLDsobQv7Iug6recIOqzoOqwnSDqtazrtoTsnYQg6riw7KSA7Jy866GcIOyghOyytCDsp4Drtogg6riI7JWh7J2EIOyCtO2OtOuzuOuLpC4gIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQptYXUucGF5bWVudCAlPiUgIA0KICBncm91cF9ieShsb2dfbW9udGgsIHVzZV90eXBlKSAlPiUgIA0KICBzdW1tYXJpc2UodG90YWwucGF5bWVudCA9IHN1bShwYXltZW50KSkgLT4gcGF5bWVudF9zdW1tYXJ5IA0KYGBgDQoNCjYuIOq3uOuemO2UhCDsi5zqsIHtmZQgDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHNjYWxlcykNCg0KZ2dwbG90KHBheW1lbnRfc3VtbWFyeSwgYWVzKHg9IGxvZ19tb250aCwgeT10b3RhbC5wYXltZW50LCBmaWxsPSB1c2VfdHlwZSkpKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikrDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbCA9Y29tbWEpDQoNCg0KYGBgDQoNCg0KYGBge3J9DQoNCnN1bW1hcnkobWF1LnBheW1lbnQkcGF5bWVudCkNCg0KbWF1LnBheW1lbnQgJT4lIA0KICBmaWx0ZXIodXNlX3R5cGUgPT0gImluc3RhbGwiICYgDQogICAgICAgICAgcGF5bWVudCA+IDApICU+JSAgICAgICMg7Iug6rec7J24642wIOuPiOydhCDrgrgg7IKs656M66eMIOy2lOy2nCANCiAgZ2dwbG90KGFlcyh4PXBheW1lbnQsIGZpbGw9bG9nX21vbnRoKSkrDQogIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uID0gImRvZGdlIiwgYmlud2lkdGggPSAyMDAwMCkNCg0KDQpgYGANCg0KDQpDb25jbHVzdGlvbiANCg0KICAgIDEuIOunpOyDgeydtCDrlqjslrTsoYzri6QgKOyCrOyLpCkgDQogICAgMi4g7Iug6recIOycoOyggOydmCDrp6Tsg4HsnbQg6rCQ7IaM7ZaI6rOgLOq3uCDspJHsl5DshJwgMjAsMDAw7JuQIOydtO2VmOydmCDrnbzsnbTtirgg7Jyg7KCA7J2YIOqwkOyGjOqwgCDsu7jri6QgKOyCrOyLpCkNCiAgICAzLiDqtJHqs6Ag67mE7Jqp7J2EIOuWqOyWtO2KuOumrOuptCDslYjrkJzri6QuIA0KDQoNCiMgQ2hhcHRlciA0IDog7J207YOIIOqzoOqwnSDrtoTshJ0gKO2DiO2HtO2VmOuKlCDsnbTsnKDrpbwg67aE7ISdKSAtIO2BrOuhnOyKpCDsp5Hqs4QgDQoNCg0KMS4gVVNFUiDsnZgg7IiY6rCAIOqwkOyGjCDtlojsnYwgIA0KICANCiAg7JuQ7J247JeQIOuMgO2VnCDqsIDshKQgMSkg6rSR6rOgIOuVjOusuOyXkCDtg4jth7Qg7Jyg7KCA7IiY6rCAIOuNlCDrp47ri6QuIC0g6rSR6rOg64qUIOyngOuCnCDri6zsnbTrnpEg67mE7Iq37ZaI6rOgLCDsi6Dqt5wg7Jyg7KCA64+EIOyeiOuLpC4gDQogICAgICAgICAgICAgICAgICAgMikg66ek7JuUIO2FjOuniOulvCDrsJTqv5TshJwg6rCc7LWc7ZWY642YIOydtOuypO2KuOqwgCDsi53sg4HtlbTsoYzri6QuIC0g7J2067Kk7Yq4IOuCtOyaqeuPhCDqsbDsnZgg67CU64CM7KeAIOyViuyVmOuLpC4gDQogICAgICAgICAgICAgICAgICAgMykg7Yq57KCVIOqzoOqwney4teydmCDsnbTtg4jsnbQg7J6I64ukLiAtIOycoOugpSDqsIDshKQgDQogICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgDQogIOybkOyduOydhCDsoJzrjIDroZwg7JWMIOyImCDsl4bquLAg65WM66y47JeQICftg5Dsg4ntmJUnIOuNsOydtO2EsCDrtoTshJ3snYQg7Iuk7Iuc7ZaJIA0KICAgDQogICog7YGs66Gc7IqkIOynkeqzhOulvCDsgqzsmqntlZjsl6wg7IS46re466i87Yq4IOuPhOy2nCDrtoTshJ0gDQogICAgICAgICAgICAgICAgICAgDQoyLiDrjbDsnbTthLAg7ISg7KCVIA0KDQogICBEQVUgLSAxIO2ajCDsnbTsg4Eg67Cp66y4IOuNsOydtO2EsCANCiAgIA0KICAgICAgICAgLSBsb2dfZGF0ZSwgYXBwX25hbWUsIGlkIA0KICAgDQogICBVU0VSLklORk8gLSDsgqzsmqnsnpAg6rOg6rCdIOygleuztCDqtIDroKgg642w7J207YSwIA0KICAgDQogICAgICAgICAtIGluc3RhbGxfZGF0ZSwgYXBwX25hbWUsIGlkLCBnZW5kZXIsIGdlbmVyYXRpb24sIGRldmljZV90eXBlIA0KICAgDQoNCmBgYHtyfQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICDrjbDsnbTthLAg67aI65+s7Jik6riwIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpzZXR3ZCgnQzovVXNlcnMvQWRtaW5pc3RyYXRvci9EZXNrdG9wL1IgQW5hbHlzaXMvQnVzaW5lc3MgUiBBYW5seXNpcyBzb3VyY2Uvc291cmNlL0RhdGFBbmFseXNpc19zcmMvUicpDQoNCnJlYWQuY3N2KCJzZWN0aW9uNC1kYXUuY3N2IiwgaGVhZGVyID0gVCwgc3RyaW5nc0FzRmFjdG9ycyA9IFQpIC0+IGRhdV80DQpyZWFkLmNzdigic2VjdGlvbjQtdXNlcl9pbmZvLmNzdiIsIGhlYWRlciA9IFQsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUKSAtPiB1c2VyX2luZm8NCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAgREFVICsgVVNFUl9JTkZPIA0KIyAgaWQg7JmAIGFwcF9uYW1lIOq4sOykgOycvOuhnCDrs5HtlakgDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KbWVyZ2UoZGF1XzQsIHVzZXJfaW5mbywgYnkgPSBjKCJ1c2VyX2lkIiwgImFwcF9uYW1lIikpIC0+IGRhdV91c2VyX2luZm8NCg0KDQojaGVhZChkYXVfdXNlcl9pbmZvKQ0KDQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgIOyblOuzhOuhnCDrs7TquLAg7JyE7ZW07IScIHN1YnN0ciDstpTstpwgIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpzdWJzdHIoZGF1X3VzZXJfaW5mbyRsb2dfZGF0ZSwgMSwgNykgLT4gZGF1X3VzZXJfaW5mbyRsb2dfbW9udGgNCg0KDQpgYGANCg0KDQozLiBHZW5kZXIsIEdlbmVyYXRpb24sIERldmljZV90eXBlIOuzhCDsp5Hqs4TtlZjquLAgDQoNCjMuMSBHZW5kZXIgDQoNCiAgIEdlbmRlciDrs4Qg67Cp66y47JeQIOuMgO2VnCDsp5Hqs4Qg7J206riwIOuVjOusuOyXkCwgbG9nX21vbnRoIOulvCDsp5Hqs4TtlZzri6QuIA0KICAgDQpgYGB7cn0NCiMgZHBsciDsgqzsmqkgDQpkYXVfdXNlcl9pbmZvICU+JSANCiAgZ3JvdXBfYnkobG9nX21vbnRoKSAlPiUgIA0KICBjb3VudChnZW5kZXIpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KI3RhYmxlIO2VqOyImCDsgqzsmqkgDQoNCnRhYmxlKGRhdV91c2VyX2luZm9bICwgYygibG9nX21vbnRoIiwgImdlbmRlciIpXSkNCg0KYGBgDQoNCnRhYmxlIO2VqOyImOuhnCBDcm9zcyDqtZDssKgg7KeR6rOEIC0g7Yq57KeVOiB0YWJsZSDtlajsiJjqsIAg65GQIGZhY3RvciDsnZgg7KeR6rOE66W8IOuztOq4sOyXlCDsoovri6QuIA0KDQrshLHrs4Tsl5Ag65Sw66W4IOuwqeusuCDsnKDsoIDsnZgg7IiY6rCAIOykgOqygyDqsJnsp4Ag7JWK64ukLiANCg0KMy4yIEdlbmVyYXRpb24gDQoNCmBgYHtyfQ0KDQp0YWJsZShkYXVfdXNlcl9pbmZvWywgYygibG9nX21vbnRoIiwgImdlbmVyYXRpb24iKV0pDQpgYGANCg0K7Jew66C5IOuzhCDssKjsnbTrj4Qg7JeG64qUIOqygyDqsJnslYQg67O07J2464ukLiANCg0KMy4zIEdlbmRlciB4IEdlbmVyYXRpb24gDQoNCmRjYXN0IO2VqOyImCDsgqzsmqkgOiDrkZAgZmFjdG9yIO2YlSDtgazroZzsiqQg7KeR6rOEIOyCrOyaqSANCg0KYGBge3J9DQpsaWJyYXJ5KHJlc2hhcGUyKQ0KDQoNCmRjYXN0KGRhdV91c2VyX2luZm8sIGxvZ19tb250aCB+IGdlbmRlciArIGdlbmVyYXRpb24sICMgbG9nX21vbnRoIOuzhCBnZW5kZXIg7JmAIGdlbmVyYXRpb24g7J2YIOyhsO2VqeydhCDrjZTtlbTshJwgDQogICAgICB2YWx1ZS52YXIgPSAidXNlcl9pZCIpICN1c2VyX2lkIOulvCDshLjrnbwgDQoNCmBgYA0KDQrshLHrs4QgKyDrgpjsnbTsl5DshJzrj4Qg65qc66C37ZWY6rKMIOydtO2DiOydtCDsnbzslrTrgpwg6rKDIOqwmeyngCDslYrslYQg67O07J2464ukLiANCg0KMy40IERldmljZSANCg0KDQpgYGB7cn0NCg0KdGFibGUoZGF1X3VzZXJfaW5mb1sgLGMoImxvZ19tb250aCIsICJkZXZpY2VfdHlwZSIpXSkNCg0KYGBgDQoNCg0K7LCo7J206rCAIOuCmO2DgOuCqCANCg0KYGBge3J9DQoNCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyDrgqDsp5zsmYAg64uo66eQ6riwIOuzhCB1c2VyX2lkIOyEuOyWtOuztOq4sCANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KZGF1X3VzZXJfaW5mbyAlPiUgDQogIGdyb3VwX2J5KGxvZ19kYXRlLCBkZXZpY2VfdHlwZSkgJT4lICANCiAgc3VtbWFyaXNlKG4gPW4oKSkgLT4gZGV2aWNlLnN1bW1hcnkNCg0KZGV2aWNlLnN1bW1hcnkkbG9nX2RhdGUgPC0gYXMuRGF0ZShkZXZpY2Uuc3VtbWFyeSRsb2dfZGF0ZSkNCg0KDQoNCmdncGxvdChkZXZpY2Uuc3VtbWFyeSwgYWVzKHg9IGxvZ19kYXRlLCB5ID0gbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2w9ZGV2aWNlX3R5cGUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXA9ZGV2aWNlX3R5cGUpKSsNCiAgZ2VvbV9wb2ludChzaXplPTMpKw0KICBnZW9tX2xpbmUoc2l6ZT0wLjUpKw0KICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikNCiAgDQoNCmBgYA0KDQoNCiMgQS9CIFRlc3QgDQoNCkEvQiBUZXN0IOuegCwg7Ju5IOyCrOydtO2KuCDrsKnrrLjsnpDrpbwg7J6E7J2Y7J2YIOuRkCDsp5Hri6jsnLzroZwg64KY64iE6rOgLCBBIOynkeuLqOyXkOqyjOuKlCDquLDsobQg7IKs7J207Yq466W8LCBCIOynkeuLqOyXkOqyjOuKlCDsg4jroZzsmrQg7IKs7J207Yq466W8IOuztOyXrOykgCDri6TsnYwsIOuRkCDsp5Hri6gg7KSRIOyWtOuWpCDsp5Hri6jsnbQg642UIOuGkuydgCDshLHqs7zrpbwg67O07Jes7KO864qU7KeA7JeQIOuMgO2VtCDtj4nqsIDtlZjripQg67Cp7Iud7J2064ukLiANCg0K7ISx6rO8IOq4sOykgOydgCA6IO2ajOybkCDqsIDsnoXrpaAsIOyerOuwqeusuOycqCwg6rWs66ek7KCE7ZmY66WgIOuTseydmCDsp4DtkZzrpbwg7ZmV7J247ZWc64ukLiANCg0KDQrsnbjqs7wg6rSA6rOE66W8IOywvuq4sCDsnITtlZwg7YWM7Iqk7Yq4IA0KICAgDQogICAg7KO87J2YIO2VoCDsoJAgOiDsnoTsnZjsoIEg7ZWg64u5IChSYW5kb20gQXNzaWdubWVudCkNCiAgICANCiAgICAg6re466O5IEEvQuulvCDrgqgv7JesIO2YueydgCDsp53siJgv7ZmA7IiYLCDssqsg7J287KO87J28IOuwqeusuCDsnpAv6re4IOuLpOydjCDsnbzso7zsnbwg67Cp66y47J6QICAgICAg65OxIOyehOydmOyggeydtOyngCDslYrsnYAg67Cp7Iud7Jy866GcIOq1rOu2hCDtlZjripQg6rK97JqwLCDrkZAg7KeR64uo7J2YIOywqOydtOqwgCDrrLTsl4cgICAgICAgICAgICDrlYzrrLjsnbjsp4Ag6rCA66Ck64K8IOyImOqwgCDsl4bri6QuIA0KICAgICANCiAgICAg7J6E7J2Y7KCBIOy2lOy2nCDsmIjsi5wpIOy0iOuTse2Vmeq1kCDtlZnsg53rk6TsnYQg64yA7IOB7Jy866GcIO2VnCDsi6Ttl5jsnZgg6rKw6rO866W8IOy0iOykkeqzoCAgICAgICAgIO2VmeyDneyXkOqyjCDrqqjrkZAg7KCB7Jqp7ZWY6rGw64KYLCDtjpjsnbTsiqQg67aBIOyCrOyaqeyekOulvCDrjIDsg4HsnZgg7Iuk7ZeY7J2EIO2KuOychO2EsOyXkCAgICAgICAgICDsoIHsmqnsi5ztgqTqsbDrgpgg7ZWY66m0IOynkeuLqOydmCDshLHqsqnqs7wg66qo7KeR64uo7J2YIOyEseqyqeyXkCDssKjsnbTqsIAg7J6I6riwIOuVjOusuOyXkCAgICAgICAgICAg6riw64yA7JmAIOuLpOuluCDqsrDqs7zrpbwg64KY7YOA64K8IOyImCDsnojri6QuIA0KICAgICANCiAgICAgDQogICAgIDEpIOyghO2bhCDruYTqtZAgWCANCiAgICAgICBCZWZvcmUvIEFmdGVyIOuhnCDtmZXsnbjtlZjrqbQsIOyZuOu2gCDsmpTsnbjsnYQg67Cw7KCcIO2VoCDsiJgg7JeG64ukLiANCiAgICAgICANCiAgICAgICDsmIjrpbwg65Ok7Ja0LCDrsLDrhIggQuulvCDqtJHqs6DtlZjripQg642wIOyghOyytCDqtazrp6TsnKjsnbQg7KKL7JWY64ukLiANCiAgICAgICAgICAgICAgICAgIOuwsOuEiCBC66W8IOq0keqzoO2VmOuKlOuNsCDri6Trpbgg7J2067Kk7Yq46rCAIOuMgOuwleydhCDss6Tri6QuIA0KICAgICAgICAgICAgICAgICAg67Cw64SIIELrpbwg6rSR6rOg7ZWY64qU642wIOuwqeyGoeyXkCDshozqsJzrkJjsl4jri6QuIA0KICAgICAgICAgICAgICAgICAgDQogICAgICAgPj4g7Jm467aA7JqU7J247J20IOyekeyaqe2VmOyYgOq4sCDrlYzrrLjsl5AsIOq3uOugh+uLpOuptCBB66W8IOuCtOqxuOyXiOyWtOuPhCDsoovslZjqsqDrhKQgDQogICAgICAgICAg6re46rG0IOyVhOustOuPhCDrqqjrpoQgDQoNCiAgICAgMikg7Ya16rOE7KCBIOqwgOyEpCBULlRFU1Qg64qUIOy7pO2KuOudvOyduOycvOuhnOunjCDrsJTrnbzrs7TquLAgDQogICAgIA0KICAgICDsoIHslrTrj4Qg6rCA7ISkIOqygOygleyXkOyEnOuKlCDsnZjrr7jqsIAg7J6I64qUIOywqOydtOqwgCDrgpjtg4DrgqzsnLzrr4DroZwg67mE7KeA64uI7IqkIOyDgeyXkOyEnA0KICAgICDsnZjrr7jqsIAg7J6I64qUIOywqOydtOyduOyngCDqsoDthqDrpbwg7ZW067SQ7JW87ZWc64ukLiANCg0KDQpgYGB7cn0NCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyAg642w7J207YSwIOu2iOufrOyYpOq4sCANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0Kc2V0d2QoJ0M6L1VzZXJzL0FkbWluaXN0cmF0b3IvRGVza3RvcC9SIEFuYWx5c2lzL0J1c2luZXNzIFIgQWFubHlzaXMgc291cmNlL3NvdXJjZS9EYXRhQW5hbHlzaXNfc3JjL1InKQ0KDQpyZWFkLmNzdigic2VjdGlvbjUtYWJfdGVzdF9pbXAuY3N2IiwgaGVhZGVyID0gVCwgc3RyaW5nc0FzRmFjdG9ycyA9IFQpIC0+IHRlc3RfaW1wDQpyZWFkLmNzdigic2VjdGlvbjUtYWJfdGVzdF9nb2FsLmNzdiIsIGhlYWRlciA9IFQsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUKSAtPiANCiAgdGVzdF9nb2FsDQoNCg0KYGBgDQoNCg0K642w7J207YSwIOyEpOuqhSA8IOuwsOuEiCDqtJHqs6DsnZgg7ZGc7IucIO2ajeyImCDsoJXrs7Q+DQogICBsb2dfZGF0ZSA6IO2RnOyLnCDrgqDsp5wgDQogICB0ZXN0X25hbWUgOiB0ZXN0IOydtOumhCANCiAgIHRlc3RfY2FzZSA6IEEsIEIgDQogICB1c2VyX2lkIA0KICAgdHJhbnNjYXRpb25faWQgOiDrsLDrhIgg6rSR6rOg6rCAIO2RnOyLnOuQmOyXiOydhCDrlYwg67Cc7IOd7ZWY64qUIGlkDQoNCg0KYGBge3J9DQoNCkRUOjpkYXRhdGFibGUodGVzdF9pbXApDQpgYGANCg0K642w7J207YSwIOyEpOuqhSA867Cw64SIIOq0keqzoOydmCDtgbTrpr8g7Zqf7IiYIOygleuztD4gDQogICBsb2dfZGF0ZSA6IO2BtOumre2VnCDrgqDsp5wgDQogICB0ZXN0X25hbWUgOiB0ZXN0IOydtOumhCANCiAgIHRlc3RfY2FzZSA6IEEsIEIgDQogICB1c2VyX2lkIA0KICAgdHJhbnNjYXRpb25faWQgOiDrsLDrhIgg6rSR6rOg6rCAIO2RnOyLnOuQmOyXiOydhCDrlYwg67Cc7IOd7ZWY64qUIGlkDQoNCmBgYHtyfQ0KDQpEVDo6ZGF0YXRhYmxlKHRlc3RfZ29hbCkNCmBgYA0KDQoNClRyYW5zY2F0aW9uX2lkIOq4sOykgCA6IOuwsOuEiOq0keqzoOqwgCDtkZzsi5zrkJjsl4jsnYTrlYwg67Cc7IOd7ZWY64qUIGlkIOuhnCDtkZzsi5zroZzqt7jsmYAg7YG066atIOuhnOq3uOulvCDqsrDtlantlaAg7YKk66GcIOyCrOyaqSANCg0K7KaJLCDtkZzsi5zsmYAg7YG066atIOq4sOuhneydtCDrp57ripQg6riw7KSA7Jy866GcIOuzke2VqSANCg0KYGBge3J9DQoNCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgIOuNsOydtO2EsCDtlansuZjquLAgDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KYWIudGVzdC5pbXAgPC0gbWVyZ2UodGVzdF9pbXAsIHRlc3RfZ29hbCwgYnkgPSAidHJhbnNhY3Rpb25faWQiLCANCiAgICAgICAgICAgICAgICAgICAgIGFsbC54ID0gVCwgc3VmZml4ZXMgPSBjKCIiLCAiLmciKSkNCg0KDQpoZWFkKGFiLnRlc3QuaW1wKQ0KYGBgDQoNCg0KYGBge3J9DQoNCmFiLnRlc3QuaW1wWzM2LF0NCg0KYGBgDQoNCuuwsOuEiCDqtJHqs6AgQuqwgCB1c2VyX2lkIDM1MzE1IOyXkOqyjCDtkZzsi5wg65CcIOuCoOynnOqwgCAxMOyblCAy7J28IOydtOyYgOuKlOuNsCwg7ZW064u5IOycoOyggOuKlCBC66W8IO2BtOumre2WiOuLpC4gDQrsnbQgdHJhbnNjYXRpb25faWQg64qUIDM2IOuyiOydtOuLpC4gDQoNCg0K7YG066atIOycoOustCDtlIzrnpjqt7gg7J6R7ISx7ZWY6riwIA0KDQpVc2VyX2lkLmcg64qUIO2BtOumreydhCDtlZwg7JWE7J2065SU66W8IOuCmO2DgOuCtOyjvOq4sCDrlYzrrLjsl5AgTkEg7J2066m0IO2BtOumreydhCDslYgg7ZaI64uk64qUIOqygyANCg0KYGBge3J9DQoNCmlmZWxzZShpcy5uYShhYi50ZXN0LmltcCR1c2VyX2lkLmcpLCAwICwgMSkgLT4gYWIudGVzdC5pbXAkaXNfZ29hbCANCg0KYGBgDQoNCg0K7YG066at66WgIOynkeqzhO2VmOq4sCANCg0KYGBge3J9DQoNCmxpYnJhcnkoZHBseXIpDQoNCmFiLnRlc3QuaW1wICU+JSAgDQogIGdyb3VwX2J5KHRlc3RfY2FzZSkgJT4lIA0KICBzdW1tYXJpc2UoY3ZyPXN1bShpc19nb2FsKS8gbGVuZ3RoKHVzZXJfaWQpKSAgIyMg7YG066at7ZWcIOyCrOuejOydmCDtlakgLyDrsLDrhIgg6rSR6rOg7JeQIO2RnOyLnOuQnCDsgqzrnowg7IiYIA0KDQoNCmBgYA0KDQoNCngyIOyLpO2Wie2VmOq4sCANCg0KYGBge3J9DQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojICDsubTsnbQg6rKA7KCVIDogQS9CIChUZXN0IGNhc3QpIOyXkCDrjIDtlZwg7YG066at66WgICgwLDEpIOqygOyglSANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KY2hpc3EudGVzdChhYi50ZXN0LmltcCR0ZXN0X2Nhc2UsIGFiLnRlc3QuaW1wJGlzX2dvYWwpDQoNCmBgYA0KDQoNCu2FjOyKpO2KuCDsvIDsnbTsiqTrs4Qg7YG066at7JyoIOyCsOy2nO2VmOq4sCANCg0KMSkg64Kg7KecLCDthYzsiqTtirgg7LyA7J207IqkIOuzhCDsgrDstpwgDQoNCmBgYHtyfQ0KDQogc3VtbWFyeS5pbXAgPC0gYWIudGVzdC5pbXAgJT4lICANCiAgZ3JvdXBfYnkobG9nX2RhdGUsIHRlc3RfY2FzZSkgJT4lIA0KICBzdW1tYXJpc2UoIGltcD0gbGVuZ3RoKHVzZXJfaWQpLCAgICMgdXNlcl9pZCDsubTsmrTtirggDQogICAgICAgICAgICBjdj0gc3VtKGlzX2dvYWwpLCAgICAjIGlzX2dvYWzsnZgg7ZWpIA0KICAgICAgICAgICAgY3ZyID0gcm91bmQoc3VtKGlzX2dvYWwpL2xlbmd0aCh1c2VyX2lkKSwzKSwgI+uRkCDsiJjsuZjrpbwg64KY64iIIOu5hOycqCANCiAgICAgICAgICAgIGN2ci5hdmcgPSByb3VuZChzdW0oY3YpL3N1bShpbXApLDMpKSAgDQoNCg0KRFQ6OmRhdGF0YWJsZShzdW1tYXJ5LmltcCkNCmBgYA0KDQoNCjIpIOyLnOqwge2ZlCANCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQoNCnN1bW1hcnkuaW1wJGxvZ19kYXRlIDwtYXMuRGF0ZShzdW1tYXJ5LmltcCRsb2dfZGF0ZSkNCg0KICBnZ3Bsb3Qoc3VtbWFyeS5pbXAsIGFlcyh4PWxvZ19kYXRlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1jdnIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHRlc3RfY2FzZSkpKw0KICAgIGdlb21fbGluZSgpKw0KICAgIGdlb21fcG9pbnQoKQ0KDQpgYGANCg0KDQoNCiMgQ2hhcHRlciA1IDogQS9CIFRlc3QgLTIgDQoNCg0KQS5CIFRlc3QgOiDrsKnrrLjsnpAg7IiY6rCAIOu5hOyKt+2VnCDrkZAg6rCc7J2YIOybuSDtjpjsnbTsp4Drpbwg67mE6rWQIA0KDQrsnbzrsJjsoIHsnLzroZwg7IOI66Gt6rKMIOuPhOyehe2VmOuKlCDquLDriqXsnbQg7J2Y64+E7ZWcIOuwlOuMgOuhnCDtmqjqs7zqsIAg7J6I7J2E7KeAIO2ZleyduO2VmOq4sCDsnITtlbTshJzsnbTri6QuIA0KDQoNCkNBU0UgU1RVRFkgLSDrkZAg6rCc7J2YIO2YuO2FlCDsmIjslb0g7IKs7J207Yq4IEEvQiDthYzsiqTtirggDQoNCkRhdGEgU3VtbWFyeSANCg0KMS4gVmFyaWFuY2UgQSA6IOq4sOyhtOydmCDsoJztkogg7Zi57J2AIOq4sOuKpeydhCDrrJjsgqztlZjripQg7Ya17KCcIOynkeuLqCANCg0KMi4gVmFyaWFuY2UgQiA6IOyDiOuhnOyatCDsoJztkogg7Zi57J2AIOq4sOuKpeydhCDrrJjsgqztlZjsl6wsIOyCrOyaqeyekOqwgCDsoovslYTtlZjripTsp4Ag7JiI7JW9IOyImOqwgCDripjsl4jripTsp4Ag7ZmV7J247ZWY64qUIOyYiOyVvSDsp5Hri6ggDQoNCjMuIENvbnZlcnRlZCAtIOyghO2ZmOuloCBUL0YNCg0KDQo0LiDqsIDshKQg7ISk7KCVIA0KDQogIEhvOiBBICjquLDsobQpLCBCKOyLoOq3nCkg7KeR64uoIOyCrOydtOydmCDsoITtmZjrpaDsnYAg6rCZ64ukLiANCiAgICAgICg9IO2aqOqzvOqwgCDsl4bri6QpDQogICAgICANCiAgSDE6IO2aqOqzvOqwgCDsnojri6QuIA0KDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGV4dHJhZm9udCkNCg0KDQoNCmxvYWQoJ0M6L1VzZXJzL0FkbWluaXN0cmF0b3IvRGVza3RvcC9SIEFuYWx5c2lzL0J1c2luZXNzIFIgQWFubHlzaXMgc291cmNlL3NvdXJjZS9EYXRhQW5hbHlzaXNfc3JjL1IvQUJUZXN0LnJkYScpIA0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBBIOq3uOujuSDsg53shLEgOiBWYXJpYW50ID0gQSDsmYAgY29udmVydGVkID0gVFJVRSANCiMgIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KQUJUZXN0ICU+JSAgDQogIGZpbHRlcih2YXJpYW50ID09ICJBIiAmIGNvbnZlcnRlZCA9PSAiVFJVRSIpIC0+IHN1YnNldF9BDQoNCg0KRFQ6OmRhdGF0YWJsZShzdWJzZXRfQSkNCg0KDQpgYGANCg0KDQpgYGB7cn0NCiMjIENvbnZlcnRpb24g7Iir7J6QIEHqt7jro7nsnZggbnJvdyDqsJIgDQpucm93KHN1YnNldF9BKSAtPiBjb252ZXJzaW9uX0ENCg0KY29udmVyc2lvbl9BICAgIzIwIA0KDQojIyBWaXNpdG9yIOyIq+yekCA6IEFCX3Rlc3Qg7KCE7LK0IO2FjOydtOu4lOyXkOyEnOydmCBBIOqwkuunjCDstpTstpztlZwgbnJvdyDqsJIgDQoNCm5yb3coQUJUZXN0ICU+JSAgZmlsdGVyKHZhcmlhbnQgPT0gIkEiKSkgLT4gdmlzaXRvcl9BDQoNCnZpc2l0b3JfQSAjNzIxIA0KDQojIyBBIOq3uOujuSDsgqzrnowg7IiYIC8g6rSR6rOgIEEg7JeQIOuwqeusuO2VnCDsgqzrnowg7IiYIA0KDQpjb252X3JhdGVfQSA8LSAoY29udmVyc2lvbl9BL3Zpc2l0b3JfQSkNCmNvbnZfcmF0ZV9BICAjMC4yNzcNCmBgYA0KDQoNCmBgYHtyfQ0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBBIOq3uOujuSDsg53shLEgOiBWYXJpYW50ID0gQSDsmYAgY29udmVydGVkID0gVFJVRSANCiMgIA0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KQUJUZXN0ICU+JSANCiAgZmlsdGVyKHZhcmlhbnQgPT0gIkIiICYgY29udmVydGVkID09ICJUUlVFIikgLT4gc3Vic2V0X0IgDQoNCg0KIyBDb252ZXJ0aW9uIOyIq+yekCANCg0KbnJvdyhzdWJzZXRfQikgLT4gY29udmVyc2lvbl9CDQoNCiMgQiDqt7jro7nsl5Ag67Cp66y47ZWcIOuwqeusuOqwnSANCg0KbnJvdyhBQlRlc3QgJT4lIGZpbHRlcih2YXJpYW50ID09ICJCIikpIC0+IHZpc2l0b3JfQg0KDQoNCiMg7KCE7ZmY66WgIA0KDQpjb252X3JhdGVfQiA8LSAoY29udmVyc2lvbl9CL3Zpc2l0b3JfQikNCmNvbnZfcmF0ZV9CDQoNCg0KDQojIFVwbGlmdCA6IEIg67mE7JyoIC0gQSDsnbTsnKggLyBBIOu5hOycqCAqIDEwMCANCg0KKGNvbnZfcmF0ZV9CIC0gY29udl9yYXRlX0EpLyBjb252X3JhdGVfQSAqMTAwICM4Mi43OQ0KYGBgDQoNCkIg6rCAIEEg67O064ukIDgyJSDrjZQg64aS64ukLiANCg0KKipQb29sZWQgUHJvYmFiaWxpdHkgZm9yIFRlc3QgVmVyc2lvbnMgQSAmIEIqKg0KDQpgYGB7cn0NCg0KI1Bvb2xlZCBQcm9iYWJpbGl0eSDqs7Xsi506IA0KIyAoQSDsnZgg7KCE7ZmY66WgICsgQuydmCDsoITtmZjrpaApIC8gKEEg67Cp66y46rCdICsgQiDrsKnrrLjqsJ0pDQoNCihjb252X3JhdGVfQSArIGNvbnZfcmF0ZV9CKSAvICh2aXNpdG9yX0EgKyB2aXNpdG9yX0IpIC0+IHBfcG9vbA0KcF9wb29sDQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQoNCmBgYHtyfQ0KYGBgDQoNCg0KYGBge3J9DQpgYGANCg0KDQpgYGB7cn0NCmBgYA0KDQo=