소속: 더조은IT아카데미, R을 활용한 빅데이터 분석
팀원: 김민희, 김현경, 문혜정, 박장호, 이한나, 진미란
날짜: 2017년 10월 23일
1.개요
이 분석은 타이타닉 탑승객의 생존률을 예측하는 모형입니다.
먼저 분석에 필요한 패키지를 설치하고 가져오겠습니다.
# Load packages
install.packages('ggplot2')
install.packages('ggthemes')
install.packages('scales')
install.packages('dplyr')
install.packages('mice')
install.packages('randomForest')
library('ggplot2') # visualization
library('ggthemes') # visualization
library('scales') # visualization
library('dplyr') # data manipulation
library('mice') # imputation
library('randomForest') # classification algorithm
데이터는 캐글의 데이터 사이트 https://www.kaggle.com/c/titanic/data 에서 다운로드하여 프로젝트 폴더 아래 저장하고 아래 스크립트를 수행합니다. getwd()함수를 통해 경로를 파악한 후 해당 경로에 파일을 다운받으면 아래와 같이 불러올 때 경로를 명시하지 않고 “파일명.확장자”만 입력해도 데이터를 불러올 수 있습니다.
train데이터를 가지고 test데이터에 승객들의 생사여부를 예측하는 것이 이 분석의 목적입니다.먼저 데이터를 불러오겠습니다.
getwd()
train <- read.csv('train.csv', stringsAsFactors = F)
test <- read.csv('test.csv', stringsAsFactors = F)
full <- bind_rows(train, test) # bind training & test data
train 데이터와 test데이터를 합쳐서 full 데이터셋을 생성합니다.
Check data: Data Dictionary / 변수 정의
Variable: Definition(Key)
survival: 생존여부(0 = 사망, 1 = 생존)
pclass: 티켓 등급(1 = 1등급, 2 = 2등급, 3 = 3등급)
sex: 성별
Age: 나이
sibsp: 형제와 배우자의 수
parch: 부모와 자녀의 수
ticket: 티켓 번호
fare: 탑승 요금
cabin: 탑승칸(Cabin) 번호
embarked: 탑승항구(C = Cherbourg, Q = Queenstown, S = Southampton)
2. 내용 분석(Feature Engineering)
2.1 이름이 포함한 내용 분석하기.
name변수에 타이틀이나 성을 분석해 생존에 영향을 미치는지 확인해보겠습니다.
# Grab title from passenger names
# Pattern Matching and Replacement
full$Title <- gsub('(.*, )|(\\..*)', '', full$Name)
# gsub perform replacement of the first and all matches
# ,앞의 모든 글짜와 .뒤의 모든 글자를 공백으로 대체하고 full$Titile 생성
head(full$Title)
# Show title counts by sex
# Cross Tabulation and Table Creation
table(full$Sex, full$Title)
# 성별에 따른 타이틀 수 집계
# Titles with very low cell counts to be combined to "rare" level
rare_title <- c('Capt', 'Col', 'Don','Dona', 'Dr', 'Jonkheer'
, 'Lady', 'Major','the Countess', 'Rev', 'Sir')
# Also reassign mlle, ms, and mme accordingly
full$Title[full$Title == 'Mlle'] <- 'Miss'
full$Title[full$Title == 'Ms'] <- 'Miss'
full$Title[full$Title == 'Mme'] <- 'Mrs'
full$Title[full$Title %in% rare_title] <- 'Rare Title'
# Show title counts by sex again
table(full$Sex, full$Title)
##
## Master Miss Mr Mrs Rare Title
## female 0 264 0 198 4
## male 61 0 757 0 25
# Finally, grab surname from passenger name
full$Surname <- sapply(full$Name,
function(x) strsplit(x, split = '[,.]')[[1]][1])
head(full$Surname)
# .으로 문자를 잘라서 앞자리 가져와 SurName에 할당
nlevels(factor(full$Surname))
cat(paste('총 ', nlevels(factor(full$Surname)), '개의 성(surnames)을 조회'))
name변수를 통해 Title과 Surname변수를 생성합니다. 가족의 성은 민족성이나 당시 사회적 지위 등의 분석에 사용할 수 있으나 이번 분석에서는 제외합니다. 이번 분석에서는 Title변수를 가지고 생존예측을 해보겠습니다.
2.2 탑승가족 분석
sibsp 변수와 parch 변수를 통해 FamilySize변수를 생성합니다.
# 승객 자신을 포함한 가족 크기 변수 만들기
full$Fsize <- full$SibSp + full$Parch + 1
# 패밀리 변수 작성
full$Family <- paste(full$Surname, full$Fsize, sep='_')
ggplot(full[1:891,], aes(x = Fsize, fill = factor(Survived))) +
geom_bar(stat='count', position='dodge') +
scale_x_continuous(breaks=c(1:11)) +
labs(x = 'Family Size') +
theme_few()
ggplot2를 사용해 가족의 크기와 생존자 수 관계 도표를 작성합니다. 가족수가 2-4명인 소(small)가족의 경우 생존확률이 높은 것 확인됩니다. 현재는 263개의 연령값이 없어서, 추후에 연령분석을 시도하겠습니다.
(그림1) 가족수별 생존 현황(막대도표)
이미지 파일은 URL로부터 불러올 수 있고 자신의 컴퓨터로 부터도 불러올 수 있다. 위에서 text에 링크를 거는것과 비슷하게 []안에 image주석을 달고 []앞에 !표를 붙여준다. 즉, [] 이와 같이 표현하고 그리고 ()안에 image주소를 입력하거나 image파일 경로를 입력한다. •내 컴퓨터에서 파일경로로 불러올때 잘 불러와 지지 않는 다면, R working directory에 image를 넣고 불러오면 된다.
그래프를 통해 혼자거나 대가족인 탑승객인 경우 사망률이 더 높은 것을 알 수 있습니다.
이번엔 가족 수에 대한 설명을 추가해 보겠습니다. 그리고 모자이크 플롯을 이용해 가족 수별 생존형태 그래프를 작성해 보겠습니다.
full$FsizeD[full$Fsize == 1] <- 'singleton'
full$FsizeD[full$Fsize < 5 & full$Fsize > 1] <- 'small'
full$FsizeD[full$Fsize > 4] <- 'large'
mosaicplot(table(full$FsizeD, full$Survived), main='Family Size by Survival', shade=TRUE)
모자이크 그래프를 통해 가족수가 2-4명인 소(small)가족의 경우 생존확률이 높은 것을 명확하게 확인할 수 있습니다. 현재는 263개의 연령값이 없기때문에, 추후에 연령분석도 시도하겠습니다.
(그림2) 가족수별 생존 현황(모자이크 도표)
2.3 기타 정보 탐색
어떤 캐빈(Cabin)에 탑승했는지, 탑승칸들이 모여있는 캐빈의 지역(Deck)은 어떻게 되는지도 기준자료를 기반으로 분석해 보겠습니다. 그리고 탑승 항구(Embarked)에 따라 차이가 있는지도 확인해보겠습니다.
full$Cabin[1:28]
# The first character is the deck. For example:
# Split the Elements of a Character Vector
strsplit(full$Cabin[2], NULL)[[1]]
## [1] "C" "8" "5"
# Create a Deck variable. Get passenger deck A - F:
full$Deck<-factor(sapply(full$Cabin, function(x) strsplit(x, NULL)[[1]][1]))
tabel(full$Embarked)s
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).
LS0tDQp0aXRsZTogIlR1dG9yaWFsIHdpdGggVGF0YW5pYyBEaXNhc3RlciINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIyMjIyDshozsho06IOuNlOyhsOydgElU7JWE7Lm0642w66+4LCBS7J2EIO2ZnOyaqe2VnCDruYXrjbDsnbTthLAg67aE7ISdDQojIyMjIyDtjIDsm5A6IOq5gOuvvO2drCwg6rmA7ZiE6rK9LCDrrLjtmJzsoJUsIOuwleyepe2YuCwg7J207ZWc64KYLCDsp4Trr7jrnoANCiMjIyMjIOuCoOynnDogMjAxN+uFhCAxMOyblCAyM+ydvA0KIyMjIyMg7LC47KGwOiBodHRwOi8vcnB1YnMuY29tL21vb24wNzA0LzMyMTYxMg0KDQo8YnI+MS7qsJzsmpQNCjxicj7snbQg67aE7ISd7J2AIO2DgOydtO2DgOuLiSDtg5HsirnqsJ3snZgg7IOd7KG066Wg7J2EIOyYiOy4oe2VmOuKlCDrqqjtmJXsnoXri4jri6QuDQo8YnI+66i87KCAIOu2hOyEneyXkCDtlYTsmpTtlZwg7Yyo7YKk7KeA66W8IOyEpOy5mO2VmOqzoCDqsIDsoLjsmKTqsqDsirXri4jri6QuDQpgYGB7cn0NCiMgTG9hZCBwYWNrYWdlcw0KaW5zdGFsbC5wYWNrYWdlcygnZ2dwbG90MicpDQppbnN0YWxsLnBhY2thZ2VzKCdnZ3RoZW1lcycpDQppbnN0YWxsLnBhY2thZ2VzKCdzY2FsZXMnKQ0KaW5zdGFsbC5wYWNrYWdlcygnZHBseXInKQ0KaW5zdGFsbC5wYWNrYWdlcygnbWljZScpDQppbnN0YWxsLnBhY2thZ2VzKCdyYW5kb21Gb3Jlc3QnKQ0KbGlicmFyeSgnZ2dwbG90MicpICMgdmlzdWFsaXphdGlvbg0KbGlicmFyeSgnZ2d0aGVtZXMnKSAjIHZpc3VhbGl6YXRpb24NCmxpYnJhcnkoJ3NjYWxlcycpICMgdmlzdWFsaXphdGlvbg0KbGlicmFyeSgnZHBseXInKSAjIGRhdGEgbWFuaXB1bGF0aW9uDQpsaWJyYXJ5KCdtaWNlJykgIyBpbXB1dGF0aW9uDQpsaWJyYXJ5KCdyYW5kb21Gb3Jlc3QnKSAjIGNsYXNzaWZpY2F0aW9uIGFsZ29yaXRobQ0KYGBgDQo8YnI+642w7J207YSw64qUIOy6kOq4gOydmCDrjbDsnbTthLAg7IKs7J207Yq4IGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vYy90aXRhbmljL2RhdGEg7JeQ7IScIOuLpOyatOuhnOuTnO2VmOyXrCDtlITroZzsoJ3tirgg7Y+0642UIOyVhOuemCDsoIDsnqXtlZjqs6Ag7JWE656YIOyKpO2BrOumve2KuOulvCDsiJjtlontlanri4jri6QuIGdldHdkKCntlajsiJjrpbwg7Ya17ZW0IOqyveuhnOulvCDtjIzslYXtlZwg7ZuEIO2VtOuLuSDqsr3roZzsl5Ag7YyM7J287J2EIOuLpOyatOuwm+ycvOuptCDslYTrnpjsmYAg6rCZ7J20IOu2iOufrOyYrCDrlYwg6rK966Gc66W8IOuqheyLnO2VmOyngCDslYrqs6AgIu2MjOydvOuqhS7tmZXsnqXsnpAi66eMIOyeheugpe2VtOuPhCDrjbDsnbTthLDrpbwg67aI65+s7JisIOyImCDsnojsirXri4jri6QuDQo8YnI+dHJhaW7rjbDsnbTthLDrpbwg6rCA7KeA6rOgIHRlc3TrjbDsnbTthLDsl5Ag7Iq56rCd65Ok7J2YIOyDneyCrOyXrOu2gOulvCDsmIjsuKHtlZjripQg6rKD7J20IOydtCDrtoTshJ3snZgg66qp7KCB7J6F64uI64ukLuuovOyggCDrjbDsnbTthLDrpbwg67aI65+s7Jik6rKg7Iq164uI64ukLg0KYGBge3J9DQpnZXR3ZCgpDQp0cmFpbiA8LSByZWFkLmNzdigndHJhaW4uY3N2Jywgc3RyaW5nc0FzRmFjdG9ycyA9IEYpDQp0ZXN0ICA8LSByZWFkLmNzdigndGVzdC5jc3YnLCBzdHJpbmdzQXNGYWN0b3JzID0gRikNCmZ1bGwgIDwtIGJpbmRfcm93cyh0cmFpbiwgdGVzdCkgIyBiaW5kIHRyYWluaW5nICYgdGVzdCBkYXRhDQpgYGANCnRyYWluIOuNsOydtO2EsOyZgCB0ZXN0642w7J207YSw66W8IO2VqeyzkOyEnCBmdWxsIOuNsOydtO2EsOyFi+ydhCDsg53shLHtlanri4jri6QuDQoNCiMjIyBDaGVjayBkYXRhOiBEYXRhIERpY3Rpb25hcnkgLyDrs4DsiJgg7KCV7J2YDQpWYXJpYWJsZTogRGVmaW5pdGlvbihLZXkpPGJyPg0Kc3Vydml2YWw6IOyDneyhtOyXrOu2gCgwID0g7IKs66edLCAxID0g7IOd7KG0KTxicj4NCnBjbGFzczog7Yuw7LyTIOuTseq4iSgxID0gMeuTseq4iSwgMiA9IDLrk7HquIksIDMgPSAz65Ox6riJKTxicj4NCnNleDog7ISx67OECTxicj4NCkFnZTog64KY7J20PGJyPg0Kc2lic3A6IO2YleygnOyZgCDrsLDsmrDsnpDsnZgg7IiYPGJyPg0KcGFyY2g6IOu2gOuqqOyZgCDsnpDrhYDsnZgg7IiYPGJyPg0KdGlja2V0OiDti7DsvJMg67KI7Zi4PGJyPg0KZmFyZTog7YOR7Iq5IOyalOq4iDxicj4NCmNhYmluOiDtg5HsirnsubgoQ2FiaW4pIOuyiO2YuDxicj4NCmVtYmFya2VkOiDtg5Hsirntla3qtawoQyA9IENoZXJib3VyZywgUSA9IFF1ZWVuc3Rvd24sIFMgPSBTb3V0aGFtcHRvbik8YnI+DQoNCiMgMi4g64K07JqpIOu2hOyEnShGZWF0dXJlIEVuZ2luZWVyaW5nKQ0KIyMjIDIuMSDsnbTrpoTsnbQg7Y+s7ZWo7ZWcIOuCtOyaqSDrtoTshJ3tlZjquLAuDQpuYW1l67OA7IiY7JeQIO2DgOydtO2LgOydtOuCmCDshLHsnYQg67aE7ISd7ZW0IOyDneyhtOyXkCDsmIHtlqXsnYQg66+47LmY64qU7KeAIO2ZleyduO2VtOuztOqyoOyKteuLiOuLpC4NCmBgYHtyfQ0KIyBHcmFiIHRpdGxlIGZyb20gcGFzc2VuZ2VyIG5hbWVzDQojIFBhdHRlcm4gTWF0Y2hpbmcgYW5kIFJlcGxhY2VtZW50DQpmdWxsJFRpdGxlIDwtIGdzdWIoJyguKiwgKXwoXFwuLiopJywgJycsIGZ1bGwkTmFtZSkNCiMgZ3N1YiBwZXJmb3JtIHJlcGxhY2VtZW50IG9mIHRoZSBmaXJzdCBhbmQgYWxsIG1hdGNoZXMgDQojICzslZ7snZgg66qo65OgIOq4gOynnOyZgCAu65Kk7J2YIOuqqOuToCDquIDsnpDrpbwg6rO167Cx7Jy866GcIOuMgOyytO2VmOqzoCBmdWxsJFRpdGlsZSDsg53shLENCg0KaGVhZChmdWxsJFRpdGxlKQ0KDQojIFNob3cgdGl0bGUgY291bnRzIGJ5IHNleA0KIyBDcm9zcyBUYWJ1bGF0aW9uIGFuZCBUYWJsZSBDcmVhdGlvbg0KdGFibGUoZnVsbCRTZXgsIGZ1bGwkVGl0bGUpDQojIOyEseuzhOyXkCDrlLDrpbgg7YOA7J207YuAIOyImCDsp5Hqs4QNCg0KDQojIFRpdGxlcyB3aXRoIHZlcnkgbG93IGNlbGwgY291bnRzIHRvIGJlIGNvbWJpbmVkIHRvICJyYXJlIiBsZXZlbA0KcmFyZV90aXRsZSA8LSBjKCdDYXB0JywgJ0NvbCcsICdEb24nLCdEb25hJywgJ0RyJywgJ0pvbmtoZWVyJw0KICAgICAgICAgICAgICAgICwgJ0xhZHknLCAnTWFqb3InLCd0aGUgQ291bnRlc3MnLCAgJ1JldicsICdTaXInKQ0KDQojIEFsc28gcmVhc3NpZ24gbWxsZSwgbXMsIGFuZCBtbWUgYWNjb3JkaW5nbHkNCmZ1bGwkVGl0bGVbZnVsbCRUaXRsZSA9PSAnTWxsZSddICAgICAgICA8LSAnTWlzcycgDQpmdWxsJFRpdGxlW2Z1bGwkVGl0bGUgPT0gJ01zJ10gICAgICAgICAgPC0gJ01pc3MnDQpmdWxsJFRpdGxlW2Z1bGwkVGl0bGUgPT0gJ01tZSddICAgICAgICAgPC0gJ01ycycgDQpmdWxsJFRpdGxlW2Z1bGwkVGl0bGUgJWluJSByYXJlX3RpdGxlXSAgPC0gJ1JhcmUgVGl0bGUnDQoNCiMgU2hvdyB0aXRsZSBjb3VudHMgYnkgc2V4IGFnYWluDQp0YWJsZShmdWxsJFNleCwgZnVsbCRUaXRsZSkNCg0KIyMgICAgICAgICANCiMjICAgICAgICAgIE1hc3RlciBNaXNzICBNciBNcnMgUmFyZSBUaXRsZQ0KIyMgICBmZW1hbGUgICAgICAwICAyNjQgICAwIDE5OCAgICAgICAgICA0DQojIyAgIG1hbGUgICAgICAgNjEgICAgMCA3NTcgICAwICAgICAgICAgMjUNCg0KIyBGaW5hbGx5LCBncmFiIHN1cm5hbWUgZnJvbSBwYXNzZW5nZXIgbmFtZQ0KZnVsbCRTdXJuYW1lIDwtIHNhcHBseShmdWxsJE5hbWUsICANCiAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oeCkgc3Ryc3BsaXQoeCwgc3BsaXQgPSAnWywuXScpW1sxXV1bMV0pDQpoZWFkKGZ1bGwkU3VybmFtZSkNCiMgLuycvOuhnCDrrLjsnpDrpbwg7J6Y65287IScIOyVnuyekOumrCDqsIDsoLjsmYAgU3VyTmFtZeyXkCDtlaDri7kNCm5sZXZlbHMoZmFjdG9yKGZ1bGwkU3VybmFtZSkpDQpjYXQocGFzdGUoJ+y0nSAnLCBubGV2ZWxzKGZhY3RvcihmdWxsJFN1cm5hbWUpKSwgJ+qwnOydmCDshLEoc3VybmFtZXMp7J2EIOyhsO2ajCcpKQ0KYGBgDQoNCm5hbWXrs4DsiJjrpbwg7Ya17ZW0IFRpdGxl6rO8IFN1cm5hbWXrs4DsiJjrpbwg7IOd7ISx7ZWp64uI64ukLiDqsIDsobHsnZgg7ISx7J2AIOuvvOyhseyEseydtOuCmCDri7nsi5wg7IKs7ZqM7KCBIOyngOychCDrk7HsnZgg67aE7ISd7JeQIOyCrOyaqe2VoCDsiJgg7J6I7Jy864KYIOydtOuyiCDrtoTshJ3sl5DshJzripQg7KCc7Jm47ZWp64uI64ukLiDsnbTrsogg67aE7ISd7JeQ7ISc64qUIFRpdGxl67OA7IiY66W8IOqwgOyngOqzoCDsg53sobTsmIjsuKHsnYQg7ZW067O06rKg7Iq164uI64ukLg0KDQojIyMgMi4yIO2DkeyKueqwgOyhsSDrtoTshJ0NCnNpYnNwIOuzgOyImOyZgCBwYXJjaCDrs4DsiJjrpbwg7Ya17ZW0IEZhbWlseVNpemXrs4DsiJjrpbwg7IOd7ISx7ZWp64uI64ukLg0KYGBge3J9DQojIOyKueqwnSDsnpDsi6DsnYQg7Y+s7ZWo7ZWcIOqwgOyhsSDtgazquLAg67OA7IiYIOunjOuTpOq4sA0KZnVsbCRGc2l6ZSA8LSBmdWxsJFNpYlNwICsgZnVsbCRQYXJjaCArIDENCg0KIyDtjKjrsIDrpqwg67OA7IiYIOyekeyEsQ0KZnVsbCRGYW1pbHkgPC0gcGFzdGUoZnVsbCRTdXJuYW1lLCBmdWxsJEZzaXplLCBzZXA9J18nKQ0KDQoNCmdncGxvdChmdWxsWzE6ODkxLF0sIGFlcyh4ID0gRnNpemUsIGZpbGwgPSBmYWN0b3IoU3Vydml2ZWQpKSkgKw0KICBnZW9tX2JhcihzdGF0PSdjb3VudCcsIHBvc2l0aW9uPSdkb2RnZScpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE6MTEpKSArDQogIGxhYnMoeCA9ICdGYW1pbHkgU2l6ZScpICsNCiAgdGhlbWVfZmV3KCkNCmBgYA0KDQpnZ3Bsb3Qy66W8IOyCrOyaqe2VtCDqsIDsobHsnZgg7YGs6riw7JmAIOyDneyhtOyekCDsiJgg6rSA6rOEIOuPhO2RnOulvCDsnpHshLHtlanri4jri6QuDQrqsIDsobHsiJjqsIAgMi0066qF7J24IOyGjChzbWFsbCnqsIDsobHsnZgg6rK97JqwIOyDneyhtO2ZleuloOydtCDrhpLsnYAg6rKDIO2ZleyduOuQqeuLiOuLpC4NCu2YhOyerOuKlCAyNjPqsJzsnZgg7Jew66C56rCS7J20IOyXhuyWtOyEnCwg7LaU7ZuE7JeQIOyXsOugueu2hOyEneydhCDsi5zrj4TtlZjqsqDsirXri4jri6QuDQoNCijqt7jrprwxKSDqsIDsobHsiJjrs4Qg7IOd7KG0IO2YhO2ZqSjrp4nrjIDrj4TtkZwpDQoNCuydtOuvuOyngCDtjIzsnbzsnYAgVVJM66Gc67aA7YSwIOu2iOufrOyYrCDsiJgg7J6I6rOgIOyekOyLoOydmCDsu7Ttk6jthLDroZwg67aA7YSw64+EIOu2iOufrOyYrCDsiJgg7J6I64ukLg0K7JyE7JeQ7IScIHRleHTsl5Ag66eB7YGs66W8IOqxsOuKlOqyg+qzvCDruYTsirftlZjqsowgW13slYjsl5AgaW1hZ2Xso7zshJ3snYQg64us6rOgIFtd7JWe7JeQICHtkZzrpbwg67aZ7Jes7KSA64ukLg0K7KaJLCBbXSDsnbTsmYAg6rCZ7J20IO2RnO2YhO2VmOqzoCDqt7jrpqzqs6AgKCnslYjsl5AgaW1hZ2Xso7zshozrpbwg7J6F66Cl7ZWY6rGw64KYIGltYWdl7YyM7J28IOqyveuhnOulvCDsnoXroKXtlZzri6QuDQrigKLrgrQg7Lu07ZOo7YSw7JeQ7IScIO2MjOydvOqyveuhnOuhnCDrtojrn6zsmKzrlYwg7J6YIOu2iOufrOyZgCDsp4Dsp4Ag7JWK64qUIOuLpOuptCwNClIgd29ya2luZyBkaXJlY3Rvcnnsl5AgaW1hZ2Xrpbwg64Sj6rOgIOu2iOufrOyYpOuptCDrkJzri6QuDQoNCg0KDQrqt7jrnpjtlITrpbwg7Ya17ZW0IO2YvOyekOqxsOuCmCDrjIDqsIDsobHsnbgg7YOR7Iq56rCd7J24IOqyveyasCDsgqzrp53rpaDsnbQg642UIOuGkuydgCDqsoPsnYQg7JWMIOyImCDsnojsirXri4jri6QuDQo8YnI+7J2067KI7JeUIOqwgOyhsSDsiJjsl5Ag64yA7ZWcIOyEpOuqheydhCDstpTqsIDtlbQg67O06rKg7Iq164uI64ukLiDqt7jrpqzqs6Ag66qo7J6Q7J207YGsIO2UjOuhr+ydhCDsnbTsmqntlbQg6rCA7KGxIOyImOuzhCDsg53sobTtmJXtg5wg6re4656Y7ZSE66W8IOyekeyEse2VtCDrs7TqsqDsirXri4jri6QuDQpgYGB7cn0NCmZ1bGwkRnNpemVEW2Z1bGwkRnNpemUgPT0gMV0gPC0gJ3NpbmdsZXRvbicNCmZ1bGwkRnNpemVEW2Z1bGwkRnNpemUgPCA1ICYgZnVsbCRGc2l6ZSA+IDFdIDwtICdzbWFsbCcNCmZ1bGwkRnNpemVEW2Z1bGwkRnNpemUgPiA0XSA8LSAnbGFyZ2UnDQoNCm1vc2FpY3Bsb3QodGFibGUoZnVsbCRGc2l6ZUQsIGZ1bGwkU3Vydml2ZWQpLCBtYWluPSdGYW1pbHkgU2l6ZSBieSBTdXJ2aXZhbCcsIHNoYWRlPVRSVUUpDQpgYGANCuuqqOyekOydtO2BrCDqt7jrnpjtlITrpbwg7Ya17ZW0IOqwgOyhseyImOqwgCAyLTTrqoXsnbgg7IaMKHNtYWxsKeqwgOyhseydmCDqsr3smrAg7IOd7KG07ZmV66Wg7J20IOuGkuydgCDqsoPsnYQg66qF7ZmV7ZWY6rKMIO2ZleyduO2VoCDsiJgg7J6I7Iq164uI64ukLiDtmITsnqzripQgMjYz6rCc7J2YIOyXsOugueqwkuydtCDsl4bquLDrlYzrrLjsl5AsIOy2lO2bhOyXkCDsl7DroLnrtoTshJ3rj4Qg7Iuc64+E7ZWY6rKg7Iq164uI64ukLg0KDQoo6re466a8Mikg6rCA7KGx7IiY67OEIOyDneyhtCDtmITtmako66qo7J6Q7J207YGsIOuPhO2RnCkNCg0KDQojIyMyLjMg6riw7YOAIOygleuztCDtg5Dsg4kNCuyWtOuWpCDsupDruYgoQ2FiaW4p7JeQIO2DkeyKue2WiOuKlOyngCwg7YOR7Iq57Lm465Ok7J20IOuqqOyXrOyeiOuKlCDsupDruYjsnZgg7KeA7JetKERlY2sp7J2AIOyWtOuWu+qyjCDrkJjripTsp4Drj4Qg6riw7KSA7J6Q66OM66W8IOq4sOuwmOycvOuhnCDrtoTshJ3tlbQg67O06rKg7Iq164uI64ukLiDqt7jrpqzqs6Ag7YOR7Iq5IO2Vreq1rChFbWJhcmtlZCnsl5Ag65Sw6528IOywqOydtOqwgCDsnojripTsp4Drj4Qg7ZmV7J247ZW067O06rKg7Iq164uI64ukLg0KYGBge3J9DQpmdWxsJENhYmluWzE6MjhdDQoNCiMgVGhlIGZpcnN0IGNoYXJhY3RlciBpcyB0aGUgZGVjay4gRm9yIGV4YW1wbGU6DQojIFNwbGl0IHRoZSBFbGVtZW50cyBvZiBhIENoYXJhY3RlciBWZWN0b3INCnN0cnNwbGl0KGZ1bGwkQ2FiaW5bMl0sIE5VTEwpW1sxXV0NCiMjIFsxXSAiQyIgIjgiICI1Ig0KIyBDcmVhdGUgYSBEZWNrIHZhcmlhYmxlLiBHZXQgcGFzc2VuZ2VyIGRlY2sgQSAtIEY6DQpmdWxsJERlY2s8LWZhY3RvcihzYXBwbHkoZnVsbCRDYWJpbiwgZnVuY3Rpb24oeCkgc3Ryc3BsaXQoeCwgTlVMTClbWzFdXVsxXSkpDQoNCnRhYmVsKGZ1bGwkRW1iYXJrZWQpcw0KDQpgYGANCg0KDQoNCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCg==