Lecture4: 頻度行列の作成

– 

merge関数

作業ディレクトリの確認

getwd()
[1] "/cloud/project"

単語リスト”sample_texts/sample_en.txt”

txt<-readLines("sample_texts/sample_en.txt")
wordLst<-strsplit(txt,"[[:space:]]|[[:punct:]]")
wordLst<-unlist(wordLst)
wordLst<-tolower(wordLst)
wordLst<- wordLst[wordLst != ""]

前回の補足

[.,!?:...]
の”...”は単なるellipsisの可能性

前回の補足2;関数ファイルの読み込み

source("calc.R")

関数使用例1

calcTTR1(wordLst)
[1] 77.465

関数使用例2

tokens <- length(wordLst)
types <- length(unique(wordLst))
calcTTR2(tokens, types)
[1] 77.465

課題1 (締め切り11月9日)

  • 課題は、RStudio Cloudの各自のWorkspaceで確認しますので、課題ができたら私に知らせてください。

引数をファイル名とし、Guiraudの値を返す関数calcRTTRの作成し、calc.Rに追加する。

引数: 英文テキストファイル

戻り値: Guiraud計算値

関数ファイルの読み込み

source("calc.R")

calcRTTR関数の実行例1

calcRTTR("sample_texts/sample_en.txt")
[1] 6.527299

calcRTTR関数の実行例2

calcRTTR("sample_texts/sample_ja_1.txt")
[1] 5.277388

calcRTTR関数の実行例3

calcRTTR("sample_texts/sample_ch.txt")
Warning: incomplete final line found on 'sample_texts/sample_ch.txt'
[1] 6.82191

単語リスト”sample_texts/sample_ja_1.txt”

txt<-readLines("sample_texts/sample_ja_1.txt")
wordLst<-strsplit(txt,"[[:space:]]|[[:punct:]]")
wordLst<-unlist(wordLst)
#wordLst<-tolower(wordLst)
wordLst<- wordLst[wordLst != ""]
freq <- table(wordLst)
freq_data<-sort(freq, decreasing=TRUE)

頻度テーブルをデータ型に変換

freqData <- data.frame(freq_data)
head(freqData)

tokensの算出

sum(freq_data)
[1] 181
sum(freqData$Freq)
[1] 181

相対頻度テーブル

(relative<-sort(freq/sum(freqData$Freq), decreasing=TRUE))
wordLst
         に          を          と          が          の          は    ください 
0.066298343 0.044198895 0.038674033 0.033149171 0.033149171 0.033149171 0.027624309 
         て          で        とき        ない        ます           1           9 
0.027624309 0.027624309 0.027624309 0.027624309 0.027624309 0.022099448 0.022099448 
      COVID    ウイルス      コロナ          話          か          し          や 
0.022099448 0.022099448 0.022099448 0.022099448 0.016574586 0.016574586 0.016574586 
         中          人          体           2         CoV        SARS        つけ 
0.016574586 0.016574586 0.016574586 0.011049724 0.011049724 0.011049724 0.011049724 
       など        なり      マスク      まわり        よう          出        出る 
0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 
         咳          外        感染          熱          誰        近く  distancing 
0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.005524862 
     Social        あと        あり        ある        いい      うつさ      うつし 
0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 
       から        こと      しかし      しまう        しれ      そして          た 
0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 
         だ      つける        なら        なる        ませ          も          ん 
0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 
       入っ        入る        接触          気        空け        話す          間 
0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 
       飛沫 
0.005524862 

相対頻度テーブルをデータフレーム型に変換

(relativeData <- data.frame(relative))

2つの変数を連結(merge)

freqMtx <- merge(freqData, relativeData, all=T, by="wordLst")
head(freqMtx)
freqMtx[,1]
 [1] 1          2          9          CoV        COVID      distancing SARS      
 [8] Social     あと       あり       ある       いい       ウイルス   うつさ    
[15] うつし     か         が         から       ください   こと       コロナ    
[22] し         しかし     しまう     しれ       そして     た         だ        
[29] つけ       つける     て         で         と         とき       ない      
[36] など       なら       なり       なる       に         の         は        
[43] ます       マスク     ませ       まわり     も         や         よう      
[50] を         ん         中         人         体         入っ       入る      
[57] 出         出る       咳         外         感染       接触       気        
[64] 熱         空け       話         話す       誰         近く       間        
[71] 飛沫      
71 Levels: に を と が の は ください て で とき ない ます 1 9 COVID ... 飛沫

出現単語の情報を行ラベルにコピー

rownames(freqMtx)<-as.character(freqMtx[,1])

出現単語の情報(1列目)を削除

freqMtx<-freqMtx[-1]
colnames(freqMtx) <- c("raw", "relative")

頻度順にソート

  • 雑な説明: リストの場合はsort関数, データフレームの場合はorder関数を使用
freqMtx<-freqMtx[order(freqMtx$raw, decreasing = TRUE),]
head(freqMtx)

View

View(freqMtx)

データサイズ

dim(freqMtx)
[1] 71  2

データの抽出(頻度数5以上)

freqMtx[freqMtx$raw>=5,]

配列の条件抽出

1行目を抽出

freqMtx[1,]

3-5行目を抽出

freqMtx[3:5,]

2列目の値を抽出

freqMtx[,2]
 [1] 0.066298343 0.044198895 0.038674033 0.033149171 0.033149171 0.033149171
 [7] 0.027624309 0.027624309 0.027624309 0.027624309 0.027624309 0.027624309
[13] 0.022099448 0.022099448 0.022099448 0.022099448 0.022099448 0.022099448
[19] 0.016574586 0.016574586 0.016574586 0.016574586 0.016574586 0.016574586
[25] 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724
[31] 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724
[37] 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.005524862
[43] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[49] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[55] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[61] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[67] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
freqMtx$relative
 [1] 0.066298343 0.044198895 0.038674033 0.033149171 0.033149171 0.033149171
 [7] 0.027624309 0.027624309 0.027624309 0.027624309 0.027624309 0.027624309
[13] 0.022099448 0.022099448 0.022099448 0.022099448 0.022099448 0.022099448
[19] 0.016574586 0.016574586 0.016574586 0.016574586 0.016574586 0.016574586
[25] 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724
[31] 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724
[37] 0.011049724 0.011049724 0.011049724 0.011049724 0.011049724 0.005524862
[43] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[49] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[55] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[61] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862
[67] 0.005524862 0.005524862 0.005524862 0.005524862 0.005524862

6行2列目の値を抽出:

freqMtx[6,2]
[1] 0.03314917

配列の条件抽出:単語の条件で、行を抽出

freqMtx[rownames(freqMtx)=="COVID",]
freqMtx[rownames(freqMtx) %in% c("COVID","コロナ","CoV"),]

練習:単語長(文字数)が3の行を抽出

出力結果

”sample_ja_2”の頻度テーブル

txt2<-readLines("sample_texts/sample_ja_2.txt")
wordLst<-strsplit(txt2,"[[:space:]]|[[:punct:]]")
wordLst<-unlist(wordLst)
wordLst<- wordLst[wordLst != ""]
freq2 <- table(wordLst)
freq_data2<-sort(freq2, decreasing=TRUE)
(freqData2 <- data.frame(freq_data2))

2つの変数を連結(merge)

全ての単語

freq_sample_ja <-merge(freqData, freqData2, all=T, by="wordLst")
head(freq_sample_ja)

View

View(freq_sample_ja)

共通単語のみ

merge(freqData, freqData2, by="wordLst")

freqDataの単語基準

merge(freqData, freqData2, all.x=TRUE, by="wordLst")

freqData2の単語基準

merge(freqData, freqData2, all.y=TRUE, by="wordLst")

空セル(NA)に値を代入

freq_sample_ja[is.na(freq_sample_ja)] <- 0

View

View(freq_sample_ja)

補足:dplyrパッケージ

dplyrパッケージのインストール

install.packages("dplyr", dependencies = TRUE)

dplyrパッケージの読み込み

library(dplyr)

full_join関数(merge関数と同等の機能)

全単語結合

full_join(freqData, freqData2, all = T, by = "wordLst")

共通単語のみ結合

inner_join(freqData, freqData2, all = T, by = "wordLst")
LS0tCnRpdGxlOiAiTGVjMDQ6IOmgu+W6puihjOWIl+OBruS9nOaIkCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBMZWN0dXJlNDog6aC75bqm6KGM5YiX44Gu5L2c5oiQCgotLeOAgDxhIGhyZWY9Imh0dHBzOi8vY2VsbC1pbm5vdmF0aW9uLm5pZy5hYy5qcC9TdXJmV2lraS92ZWN0b3JfZGlmZmVyZW5jZS5odG1sIiB0YXJnZXQ9Il9ibGFuayI+5Z6LPC9hPgoKLS0gPGEgaHJlZj0iaHR0cHM6Ly9zdGF0LmV0aHouY2gvUi1tYW51YWwvUi1kZXZlbC9saWJyYXJ5L2Jhc2UvaHRtbC9tZXJnZS5odG1sIiB0YXJnZXQ9Il9ibGFuayI+bWVyZ2XplqLmlbA8L2E+CgojIyDkvZzmpa3jg4fjgqPjg6zjgq/jg4jjg6rjga7norroqo0gCmBgYHtyfQpnZXR3ZCgpCmBgYAojIyDljZjoqp7jg6rjgrnjg4gic2FtcGxlX3RleHRzL3NhbXBsZV9lbi50eHQiCmBgYHtyfQp0eHQ8LXJlYWRMaW5lcygic2FtcGxlX3RleHRzL3NhbXBsZV9lbi50eHQiKQp3b3JkTHN0PC1zdHJzcGxpdCh0eHQsIltbOnNwYWNlOl1dfFtbOnB1bmN0Ol1dIikKd29yZExzdDwtdW5saXN0KHdvcmRMc3QpCndvcmRMc3Q8LXRvbG93ZXIod29yZExzdCkKd29yZExzdDwtIHdvcmRMc3Rbd29yZExzdCAhPSAiIl0KYGBgCgojIyDliY3lm57jga7oo5zotrMKLSA8YSBocmVmPSJodHRwczovL2phLndpa2lwZWRpYS5vcmcvd2lraS8lRTYlQUQlQTMlRTglQTYlOEYlRTglQTElQTglRTclOEYlQkUiIHRhcmdldD0iX2JsYW5rIj7mraPopo/ooajnj748L2E+Ci0gPGEgaHJlZj0iaHR0cHM6Ly9lbi53aWtpYm9va3Mub3JnL3dpa2kvUmVndWxhcl9FeHByZXNzaW9ucy9QT1NJWC1FeHRlbmRlZF9SZWd1bGFyX0V4cHJlc3Npb25zIiB0YXJnZXQ9Il9ibGFuayI+UmVndWxhciBFeHByZXNzaW9ucy9QT1NJWC1FeHRlbmRlZCBSZWd1bGFyIEV4cHJlc3Npb25zPC9hPgoKYGBgClsuLCE/Oi4uLl0K44Gu4oCdLi4u4oCd44Gv5Y2Y44Gq44KLZWxsaXBzaXPjga7lj6/og73mgKcKYGBgCi0gPGEgaHJlZj0iaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRWxsaXBzaXMiIHRhcmdldD0iX2JsYW5rIj5lbGxpcHNpczwvYT4KCiMjIOWJjeWbnuOBruijnOi2szLvvJvplqLmlbDjg5XjgqHjgqTjg6vjga7oqq3jgb/ovrzjgb8KYGBge3J9CnNvdXJjZSgiY2FsYy5SIikKYGBgCgojIyMg6Zai5pWw5L2/55So5L6LMQpgYGB7cn0KY2FsY1RUUjEod29yZExzdCkKYGBgCiMjIyDplqLmlbDkvb/nlKjkvosyCmBgYHtyfQp0b2tlbnMgPC0gbGVuZ3RoKHdvcmRMc3QpCnR5cGVzIDwtIGxlbmd0aCh1bmlxdWUod29yZExzdCkpCmNhbGNUVFIyKHRva2VucywgdHlwZXMpCmBgYAoKIyMg6Kqy6aGMMSAo57eg44KB5YiH44KKMTHmnIg55pelKQotIOiqsumhjOOBr+OAgVJTdHVkaW8gQ2xvdWTjga7lkIToh6rjga5Xb3Jrc3BhY2Xjgafnorroqo3jgZfjgb7jgZnjga7jgafjgIHoqrLpoYzjgYzjgafjgY3jgZ/jgonnp4Hjgavnn6XjgonjgZvjgabjgY/jgaDjgZXjgYTjgIIKCiMjIyDlvJXmlbDjgpLjg5XjgqHjgqTjg6vlkI3jgajjgZfjgIFHdWlyYXVk44Gu5YCk44KS6L+U44GZ6Zai5pWwY2FsY1JUVFLjga7kvZzmiJDjgZfjgIFjYWxjLlLjgavov73liqDjgZnjgovjgIIKIyMjIyDlvJXmlbA6ICDoi7Hmlofjg4bjgq3jgrnjg4jjg5XjgqHjgqTjg6sKIyMjIyDmiLvjgorlgKQ6IEd1aXJhdWToqIjnrpflgKQKCiMjIyDplqLmlbDjg5XjgqHjgqTjg6vjga7oqq3jgb/ovrzjgb8KYGBge3J9CnNvdXJjZSgiY2FsYy5SIikKYGBgCgpgYGB7ciwgZWNobz1GQUxTRX0Kc291cmNlKCJjYWxjMi5SIikKYGBgCgojIyMgY2FsY1JUVFLplqLmlbDjga7lrp/ooYzkvosxCmBgYHtyfQpjYWxjUlRUUigic2FtcGxlX3RleHRzL3NhbXBsZV9lbi50eHQiKQpgYGAKIyMjIGNhbGNSVFRS6Zai5pWw44Gu5a6f6KGM5L6LMgpgYGB7cn0KY2FsY1JUVFIoInNhbXBsZV90ZXh0cy9zYW1wbGVfamFfMS50eHQiKQpgYGAKCiMjIyBjYWxjUlRUUumWouaVsOOBruWun+ihjOS+izMKYGBge3J9CmNhbGNSVFRSKCJzYW1wbGVfdGV4dHMvc2FtcGxlX2NoLnR4dCIpCmBgYAoKIyMg5Y2Y6Kqe44Oq44K544OIInNhbXBsZV90ZXh0cy9zYW1wbGVfamFfMS50eHQiCmBgYHtyfQp0eHQ8LXJlYWRMaW5lcygic2FtcGxlX3RleHRzL3NhbXBsZV9qYV8xLnR4dCIpCndvcmRMc3Q8LXN0cnNwbGl0KHR4dCwiW1s6c3BhY2U6XV18W1s6cHVuY3Q6XV0iKQp3b3JkTHN0PC11bmxpc3Qod29yZExzdCkKI3dvcmRMc3Q8LXRvbG93ZXIod29yZExzdCkKd29yZExzdDwtIHdvcmRMc3Rbd29yZExzdCAhPSAiIl0KZnJlcSA8LSB0YWJsZSh3b3JkTHN0KQpmcmVxX2RhdGE8LXNvcnQoZnJlcSwgZGVjcmVhc2luZz1UUlVFKQpgYGAKCiMjIOmgu+W6puODhuODvOODluODq+OCkuODh+ODvOOCv+Wei+OBq+WkieaPmwpgYGB7cn0KZnJlcURhdGEgPC0gZGF0YS5mcmFtZShmcmVxX2RhdGEpCmhlYWQoZnJlcURhdGEpCmBgYAoKIyMgdG9rZW5z44Gu566X5Ye6CmBgYHtyfQpzdW0oZnJlcV9kYXRhKQpgYGAKCmBgYHtyfQpzdW0oZnJlcURhdGEkRnJlcSkKYGBgCgojIyDnm7jlr77poLvluqbjg4bjg7zjg5bjg6sKYGBge3J9CihyZWxhdGl2ZTwtc29ydChmcmVxL3N1bShmcmVxRGF0YSRGcmVxKSwgZGVjcmVhc2luZz1UUlVFKSkKYGBgCgojIyDnm7jlr77poLvluqbjg4bjg7zjg5bjg6vjgpLjg4fjg7zjgr/jg5Xjg6zjg7zjg6DlnovjgavlpInmj5sKYGBge3J9CihyZWxhdGl2ZURhdGEgPC0gZGF0YS5mcmFtZShyZWxhdGl2ZSkpCmBgYAoKIyMg77yS44Gk44Gu5aSJ5pWw44KS6YCj57WQKG1lcmdlKQpgYGB7cn0KZnJlcU10eCA8LSBtZXJnZShmcmVxRGF0YSwgcmVsYXRpdmVEYXRhLCBhbGw9VCwgYnk9IndvcmRMc3QiKQpgYGAKCmBgYHtyfQpoZWFkKGZyZXFNdHgpCmBgYAoKYGBge3J9CmZyZXFNdHhbLDFdCmBgYAoKIyMjIOWHuuePvuWNmOiqnuOBruaDheWgseOCkuihjOODqeODmeODq+OBq+OCs+ODlOODvApgYGB7cn0Kcm93bmFtZXMoZnJlcU10eCk8LWFzLmNoYXJhY3RlcihmcmVxTXR4WywxXSkKYGBgCgojIyDlh7rnj77ljZjoqp7jga7mg4XloLEoMeWIl+ebrinjgpLliYrpmaQKYGBge3J9CmZyZXFNdHg8LWZyZXFNdHhbLTFdCmNvbG5hbWVzKGZyZXFNdHgpIDwtIGMoInJhdyIsICJyZWxhdGl2ZSIpCmBgYAoKIyMg6aC75bqm6aCG44Gr44K944O844OICi0g6ZuR44Gq6Kqs5piOOiDjg6rjgrnjg4jjga7loLTlkIjjga9zb3J06Zai5pWwLCDjg4fjg7zjgr/jg5Xjg6zjg7zjg6Djga7loLTlkIjjga9vcmRlcumWouaVsOOCkuS9v+eUqApgYGB7cn0KZnJlcU10eDwtZnJlcU10eFtvcmRlcihmcmVxTXR4JHJhdywgZGVjcmVhc2luZyA9IFRSVUUpLF0KaGVhZChmcmVxTXR4KQpgYGAKIyMjIFZpZXcKYGBge3IsIGV2YWw9RkFMU0V9ClZpZXcoZnJlcU10eCkKYGBgCgojIyMg44OH44O844K/44K144Kk44K6CmBgYHtyfQpkaW0oZnJlcU10eCkKYGBgCgojIyMg44OH44O844K/44Gu5oq95Ye677yI6aC75bqm5pWwNeS7peS4iu+8iQpgYGB7cn0KZnJlcU10eFtmcmVxTXR4JHJhdz49NSxdCmBgYAojIyDphY3liJfjga7mnaHku7bmir3lh7oKIyMjIDHooYznm67jgpLmir3lh7oKYGBge3J9CmZyZXFNdHhbMSxdCmBgYAoKIyMjICAzLTXooYznm67jgpLmir3lh7oKYGBge3J9CmZyZXFNdHhbMzo1LF0KYGBgCgojIyMgMuWIl+ebruOBruWApOOCkuaKveWHugpgYGB7cn0KZnJlcU10eFssMl0KYGBgCgpgYGB7cn0KZnJlcU10eCRyZWxhdGl2ZQpgYGAKCiMjIyA26KGMMuWIl+ebruOBruWApOOCkuaKveWHuu+8mgpgYGB7cn0KZnJlcU10eFs2LDJdCmBgYAojIyMg6YWN5YiX44Gu5p2h5Lu25oq95Ye677ya5Y2Y6Kqe44Gu5p2h5Lu244Gn44CB6KGM44KS5oq95Ye6CmBgYHtyfQpmcmVxTXR4W3Jvd25hbWVzKGZyZXFNdHgpPT0iQ09WSUQiLF0KYGBgCgpgYGB7cn0KZnJlcU10eFtyb3duYW1lcyhmcmVxTXR4KSAlaW4lIGMoIkNPVklEIiwi44Kz44Ot44OKIiwiQ29WIiksXQpgYGAKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyAiPue3tOe/kjwvc3Bhbj465Y2Y6Kqe6ZW377yI5paH5a2X5pWw77yJ44GM77yT44Gu6KGM44KS5oq95Ye6CiMjIOWHuuWKm+e1kOaenApgYGB7ciwgZWNobz1GQUxTRX0KZnJlcU10eFtuY2hhcihyb3duYW1lcyhmcmVxTXR4KSk9PTMsXQpgYGAKCiMjICDigJ1zYW1wbGVfamFfMuKAneOBrumgu+W6puODhuODvOODluODqwpgYGB7cn0KdHh0MjwtcmVhZExpbmVzKCJzYW1wbGVfdGV4dHMvc2FtcGxlX2phXzIudHh0IikKd29yZExzdDwtc3Ryc3BsaXQodHh0MiwiW1s6c3BhY2U6XV18W1s6cHVuY3Q6XV0iKQp3b3JkTHN0PC11bmxpc3Qod29yZExzdCkKd29yZExzdDwtIHdvcmRMc3Rbd29yZExzdCAhPSAiIl0KZnJlcTIgPC0gdGFibGUod29yZExzdCkKZnJlcV9kYXRhMjwtc29ydChmcmVxMiwgZGVjcmVhc2luZz1UUlVFKQooZnJlcURhdGEyIDwtIGRhdGEuZnJhbWUoZnJlcV9kYXRhMikpCmBgYAoKIyMg77yS44Gk44Gu5aSJ5pWw44KS6YCj57WQKG1lcmdlKQojIyMg5YWo44Gm44Gu5Y2Y6KqeCmBgYHtyfQpmcmVxX3NhbXBsZV9qYSA8LW1lcmdlKGZyZXFEYXRhLCBmcmVxRGF0YTIsIGFsbD1ULCBieT0id29yZExzdCIpCmhlYWQoZnJlcV9zYW1wbGVfamEpCmBgYAoKIyMjIFZpZXcKYGBge3IsIGV2YWw9RkFMU0V9ClZpZXcoZnJlcV9zYW1wbGVfamEpCmBgYAoKIyMjIOWFsemAmuWNmOiqnuOBruOBvwpgYGB7cn0KbWVyZ2UoZnJlcURhdGEsIGZyZXFEYXRhMiwgYnk9IndvcmRMc3QiKQpgYGAKCiMjIyBmcmVxRGF0YeOBruWNmOiqnuWfuua6lgpgYGB7cn0KbWVyZ2UoZnJlcURhdGEsIGZyZXFEYXRhMiwgYWxsLng9VFJVRSwgYnk9IndvcmRMc3QiKQpgYGAKCiMjIyBmcmVxRGF0YTLjga7ljZjoqp7ln7rmupYKYGBge3J9Cm1lcmdlKGZyZXFEYXRhLCBmcmVxRGF0YTIsIGFsbC55PVRSVUUsIGJ5PSJ3b3JkTHN0IikKYGBgCgojIyDnqbrjgrvjg6vvvIhOQe+8ieOBq+WApOOCkuS7o+WFpQpgYGB7cn0KZnJlcV9zYW1wbGVfamFbaXMubmEoZnJlcV9zYW1wbGVfamEpXSA8LSAwCmBgYAojIyMgVmlldwpgYGB7ciwgZXZhbD1GQUxTRX0KVmlldyhmcmVxX3NhbXBsZV9qYSkKYGBgCgoKCgojIyDoo5zotrPvvJo8YSBocmVmPSJodHRwczovL2RwbHlyLnRpZHl2ZXJzZS5vcmcvIiB0YXJnZXQ9Il9ibGFuayI+ZHBseXLjg5Hjg4PjgrHjg7zjgrg8L2E+CiMjIyBkcGx5cuODkeODg+OCseODvOOCuOOBruOCpOODs+OCueODiOODvOODqwpgYGB7ciwgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQpgYGAKCiMjIyBkcGx5cuODkeODg+OCseODvOOCuOOBruiqreOBv+i+vOOBvwpgYGB7cn0KbGlicmFyeShkcGx5cikKYGBgCiMjIyBmdWxsX2pvaW7plqLmlbDvvIhtZXJnZemWouaVsOOBqOWQjOetieOBruapn+iDve+8iQojIyMgIOWFqOWNmOiqnue1kOWQiApgYGB7cn0KZnVsbF9qb2luKGZyZXFEYXRhLCBmcmVxRGF0YTIsIGFsbCA9IFQsIGJ5ID0gIndvcmRMc3QiKQpgYGAKCiMjIyAg5YWx6YCa5Y2Y6Kqe44Gu44G/57WQ5ZCICmBgYHtyfQppbm5lcl9qb2luKGZyZXFEYXRhLCBmcmVxRGF0YTIsIGFsbCA9IFQsIGJ5ID0gIndvcmRMc3QiKQpgYGAK