Lecture07: Shiny

感情分析の補足:

ライブラリの読み込み

library(syuzhet)

Sentiment analysis of an Aljazeera article

  • テキストファイルの1行ずつ読み込み
text1_Lines <- readLines("G7/Aljazeera.txt")
text1_Lines[1]
[1] "Top diplomats from the Group of Seven (G7) have called for “humanitarian pauses” in Israel’s bombardment in order to deliver aid to desperate Palestinian civilians in the Gaza Strip."
  • トークン化
(text1_1_words <- get_tokens(text1_Lines[1]))
 [1] "top"          "diplomats"    "from"         "the"         
 [5] "group"        "of"           "seven"        "g7"          
 [9] "have"         "called"       "for"          "humanitarian"
[13] "pauses"       "in"           "israel"       "s"           
[17] "bombardment"  "in"           "order"        "to"          
[21] "deliver"      "aid"          "to"           "desperate"   
[25] "palestinian"  "civilians"    "in"           "the"         
[29] "gaza"         "strip"       
  • 感情得点の取得
text1_1_sentiment_scores <- get_nrc_sentiment(text1_1_words)
  • 行名のインデックスを出現単語に変更
row.names(text1_1_sentiment_scores)
 [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12" "13" "14"
[15] "15" "16" "17" "18" "19" "20" "21" "22" "23" "24" "25" "26" "27" "28"
[29] "29" "30"
row.names(text1_1_sentiment_scores)<-NULL
row.names(text1_1_sentiment_scores)<-make.unique(text1_1_words)
  • 感情得点の相対頻度の算出(総数1)
View(prop.table(text1_1_sentiment_scores[, 1:8]))

“top”のsentiment_score

(tmp<-text1_1_sentiment_scores[1,1:8])
text1_1_sentiment_scores[, 1:8]
sum(text1_1_sentiment_scores[, 1:8])
[1] 9
tmp/sum(text1_1_sentiment_scores[, 1:8])

全テキスト感情得点の取得

text1_string <- get_text_as_string("G7/Aljazeera.txt")
text1_words <- get_tokens(text1_string)
text1_sentiment_scores <- get_nrc_sentiment(text1_words)

感情カテゴリ別集計

SentTotal<-colSums(prop.table(text1_sentiment_scores[, 1:8]))
sort(SentTotal,decreasing=TRUE)
       trust         fear anticipation          joy      sadness 
  0.28571429   0.20000000   0.15714286   0.10000000   0.10000000 
       anger     surprise      disgust 
  0.08571429   0.05714286   0.01428571 

感情カテゴリ内単語情報:trust

id<-which(text1_sentiment_scores$trust>0)
sort(table(text1_words[id]),decreasing=TRUE)

        food humanitarian         bank      medical    statement 
           3            3            2            2            2 
      agreed    committed     continue      leading        peace 
           1            1            1            1            1 
     shelter          top       united 
           1            1            1 

感情カテゴリ内単語情報:fear

id<-which(text1_sentiment_scores$fear>0)
sort(table(text1_words[id]),decreasing=TRUE)

         war  bombardment      medical        broke condemnation 
           3            2            2            1            1 
   displaced         fire     military       urgent     violence 
           1            1            1            1            1 

視覚化: Rader chart

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

install.packages("fmsb")

ライブラリの読み込み

library("fmsb")

radarchart関数で描画

参考サイトのコードを土台に作成

#最大、最小データの準備
index<-1:8
SentimentLabels <- names(text1_sentiment_scores)
maxmin <- data.frame(
  lapply(index,function(i) assign(SentimentLabels[i], c(0.3,0), envir = globalenv()) )
)
names(maxmin)<-SentimentLabels[index]

scores <-colSums(prop.table(text1_sentiment_scores[, 1:8]))
dat <- data.frame(
  lapply(index,function(i) assign(sentiments[i], scores[i], envir = globalenv()) )
  )
names(dat)<-SentimentLabels[index]
dat <- rbind(maxmin, dat) #データの結合

####radarchartの設定##### 
#centerzero = TRUEで中心が0
#axistype:軸基準設定,0:無し, 1:割合, 2:実数, 3:割合,実数, 4:最大を1, 5:最大を1,実数
#seg:分割数
#plty:線の種類
#vlcex:ラベルの大きさ
radarchart(dat, axistype = 2, seg = 8, plty = 1, pcol="blue", vlcex = 1.,
           centerzero = TRUE, vlabels = colnames(dat),cglcol ="gray",
           title = "NRC Emotions in AL JAZEERA Text (8 Nov 2023)")

# default: pcol=1:8 (1:black, 2:red, 3:green, 4:blue, 5:cyan, 6:magenta, 7:yellow, 8:gray)

Sentiment analysis of an BBC articleの感情得点

text2_string <- get_text_as_string("G7/BBC.txt")
text2_words <- get_tokens(text2_string)
text2_sentiment_scores <- get_nrc_sentiment(text2_words)

radarchart関数で描画

#最大、最小データの準備
index<-1:8
SentimentLabels <- names(text1_sentiment_scores)
maxmin <- data.frame(
  lapply(index,function(i) assign(SentimentLabels[i], c(0.3,0), envir = globalenv()) )
)
names(maxmin)<-SentimentLabels[index]

scores1<-colSums(prop.table(text1_sentiment_scores[, 1:8]))
scores2<-colSums(prop.table(text2_sentiment_scores[, 1:8]))
scores <-mapply(c,scores1,scores2)

RNGkind("Mersenne-Twister")
dat <- data.frame(
  lapply(index,function(i) assign(sentiments[i], scores[,i], envir = globalenv()) )
  )
names(dat)<-SentimentLabels[index]
dat <- rbind(maxmin, dat)

radarchart(dat, axistype = 2, seg = 8, plty = 1, vlcex = 1., pcol=c(2,3),
           centerzero = TRUE, vlabels = colnames(dat), cglcol ="gray",
           title = "NRC Emotions in AL JAZEERA & BBC (8 Nov 2023)")

shiny

Shiny apps Demo

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

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

shinyパッケージのロード

library(shiny)

Shiny app作成手順

  1. Shiny appのフォルダを作成
  2. ui.R, server.R, (global.R)のスクリプトファイルを作成
  3. runApp(フォルダ名)で実行

app_hoge

  • server.R
  • ui.R ### Shinyアプリケーション”app_hoge”の実行
runApp("app_hoge")

app_hoge2

  • server.R
  • ui.R
  • global.R

Shinyアプリケーション”app_hoge2”の実行

runApp("app_hoge2")

プロットマーカーのアプリケーション1”app_pch1”の実行

runApp("app_pch1")

プロットマーカーのアプリケーション2”app_pch2”の実行

runApp("app_pch2")

Shinyでアプリケーションを作成する際の注意点

  • UI(外観)部分から作り始める
  • 少しずつコードを書いて、こまめに動作確認
LS0tCnRpdGxlOiAiTGVjMDc6IFNoaW55IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCiMgTGVjdHVyZTA3OiBTaGlueQoKIyMg5oSf5oOF5YiG5p6Q44Gu6KOc6Laz77yaCiMjIyA8YSBocmVmPSJodHRwczovL3NhaWZtb2hhbW1hZC5jb20vV2ViUGFnZXMvTlJDLUVtb3Rpb24tTGV4aWNvbi5odG0iPk5SQyBXb3JkLUVtb3Rpb24gQXNzb2NpYXRpb24gTGV4aWNvbjwvYT4KCiMjIyDov73liqDlj4LogIPos4fmlpkKLSA8YSBocmVmPSJodHRwczovL2FyeGl2Lm9yZy9wZGYvMjAwNS4xMjg0MC5wZGYiPlNvZnR3YXJlIHJldmlldzwvYT4KLSA8YSBocmVmPSJodHRwczovL3JwdWJzLmNvbS9tYXJ5ZGtlbGxlci83ODIwNDgiPlNlbnRpbWVudCBhbmFseXNpcyB1c2luZyB0aGUgcGFja2FnZSAic2VudGltZW50ciI8L2E+CgoKIyMjIOODqeOCpOODluODqeODquOBruiqreOBv+i+vOOBvwpgYGB7cn0KbGlicmFyeShzeXV6aGV0KQpgYGAKCiMjIyBTZW50aW1lbnQgYW5hbHlzaXMgb2YgYW4gQWxqYXplZXJhIGFydGljbGUKLSDjg4bjgq3jgrnjg4jjg5XjgqHjgqTjg6vjga4x6KGM44Ga44Gk6Kqt44G/6L6844G/CmBgYHtyfQp0ZXh0MV9MaW5lcyA8LSByZWFkTGluZXMoIkc3L0FsamF6ZWVyYS50eHQiKQp0ZXh0MV9MaW5lc1sxXQpgYGAKLSDjg4jjg7zjgq/jg7PljJYKYGBge3J9Cih0ZXh0MV8xX3dvcmRzIDwtIGdldF90b2tlbnModGV4dDFfTGluZXNbMV0pKQpgYGAKLSDmhJ/mg4Xlvpfngrnjga7lj5blvpcKYGBge3J9CnRleHQxXzFfc2VudGltZW50X3Njb3JlcyA8LSBnZXRfbnJjX3NlbnRpbWVudCh0ZXh0MV8xX3dvcmRzKQpgYGAKCi0g6KGM5ZCN44Gu44Kk44Oz44OH44OD44Kv44K544KS5Ye654++5Y2Y6Kqe44Gr5aSJ5pu0CmBgYHtyfQpyb3cubmFtZXModGV4dDFfMV9zZW50aW1lbnRfc2NvcmVzKQpyb3cubmFtZXModGV4dDFfMV9zZW50aW1lbnRfc2NvcmVzKTwtTlVMTApyb3cubmFtZXModGV4dDFfMV9zZW50aW1lbnRfc2NvcmVzKTwtbWFrZS51bmlxdWUodGV4dDFfMV93b3JkcykKYGBgCi0g5oSf5oOF5b6X54K544Gu55u45a++6aC75bqm44Gu566X5Ye677yI57eP5pWw77yR77yJCmBgYHtyfQpWaWV3KHByb3AudGFibGUodGV4dDFfMV9zZW50aW1lbnRfc2NvcmVzWywgMTo4XSkpCmBgYAoKIyMjIyAidG9wIuOBrnNlbnRpbWVudF9zY29yZQpgYGB7cn0KKHRtcDwtdGV4dDFfMV9zZW50aW1lbnRfc2NvcmVzWzEsMTo4XSkKdGV4dDFfMV9zZW50aW1lbnRfc2NvcmVzWywgMTo4XQpzdW0odGV4dDFfMV9zZW50aW1lbnRfc2NvcmVzWywgMTo4XSkKdG1wL3N1bSh0ZXh0MV8xX3NlbnRpbWVudF9zY29yZXNbLCAxOjhdKQpgYGAKCiMjIyDlhajjg4bjgq3jgrnjg4jmhJ/mg4Xlvpfngrnjga7lj5blvpcKYGBge3J9CnRleHQxX3N0cmluZyA8LSBnZXRfdGV4dF9hc19zdHJpbmcoIkc3L0FsamF6ZWVyYS50eHQiKQp0ZXh0MV93b3JkcyA8LSBnZXRfdG9rZW5zKHRleHQxX3N0cmluZykKdGV4dDFfc2VudGltZW50X3Njb3JlcyA8LSBnZXRfbnJjX3NlbnRpbWVudCh0ZXh0MV93b3JkcykKYGBgCgojIyMjIOaEn+aDheOCq+ODhuOCtOODquWIpembhuioiApgYGB7cn0KU2VudFRvdGFsPC1jb2xTdW1zKHByb3AudGFibGUodGV4dDFfc2VudGltZW50X3Njb3Jlc1ssIDE6OF0pKQpzb3J0KFNlbnRUb3RhbCxkZWNyZWFzaW5nPVRSVUUpCmBgYAojIyMjIOaEn+aDheOCq+ODhuOCtOODquWGheWNmOiqnuaDheWgsTp0cnVzdApgYGB7cn0KaWQ8LXdoaWNoKHRleHQxX3NlbnRpbWVudF9zY29yZXMkdHJ1c3Q+MCkKc29ydCh0YWJsZSh0ZXh0MV93b3Jkc1tpZF0pLGRlY3JlYXNpbmc9VFJVRSkKYGBgCiMjIyMg5oSf5oOF44Kr44OG44K044Oq5YaF5Y2Y6Kqe5oOF5aCxOmZlYXIKYGBge3J9CmlkPC13aGljaCh0ZXh0MV9zZW50aW1lbnRfc2NvcmVzJGZlYXI+MCkKc29ydCh0YWJsZSh0ZXh0MV93b3Jkc1tpZF0pLGRlY3JlYXNpbmc9VFJVRSkKYGBgCiMjIyDoppbopprljJY6IFJhZGVyIGNoYXJ0CiMjIyA8YSBocmVmPSJodHRwczovL21pbmF0by5zaXAyMWMub3JnL21zYi9tYW4vaW5kZXguaHRtbCIgdGFyZ2V0PSJfYmxhbmsiPmZtc2Ljg5Hjg4PjgrHjg7zjgrg8L2E+44Gu44Kk44Oz44K544OI44O844OrCmBgYHtyLCBldmFsPUZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJmbXNiIikKYGBgCgojIyMg44Op44Kk44OW44Op44Oq44Gu6Kqt44G/6L6844G/CmBgYHtyfQpsaWJyYXJ5KCJmbXNiIikKYGBgCgojIyMgPGEgaHJlZj0iaHR0cHM6Ly9taW5hdG8uc2lwMjFjLm9yZy9tc2IvbWFuL3JhZGFyY2hhcnQuaHRtbCIgdGFyZ2V0PSJfYmxhbmsiPnJhZGFyY2hhcnTplqLmlbA8L2E+44Gn5o+P55S7CiMjIyMgPGEgaHJlZj0iaHR0cHM6Ly93d3cua2FyYWRhLWdvb2QubmV0L2FuYWx5dGljc3Ivci0yMS8iIHRhcmdldD0iX2JsYW5rIj7lj4LogIPjgrXjgqTjg4g8L2E+44Gu44Kz44O844OJ44KS5Zyf5Y+w44Gr5L2c5oiQCmBgYHtyfQoj5pyA5aSn44CB5pyA5bCP44OH44O844K/44Gu5rqW5YKZCmluZGV4PC0xOjgKU2VudGltZW50TGFiZWxzIDwtIG5hbWVzKHRleHQxX3NlbnRpbWVudF9zY29yZXMpCm1heG1pbiA8LSBkYXRhLmZyYW1lKAogIGxhcHBseShpbmRleCxmdW5jdGlvbihpKSBhc3NpZ24oU2VudGltZW50TGFiZWxzW2ldLCBjKDAuMywwKSwgZW52aXIgPSBnbG9iYWxlbnYoKSkgKQopCm5hbWVzKG1heG1pbik8LVNlbnRpbWVudExhYmVsc1tpbmRleF0KCnNjb3JlcyA8LWNvbFN1bXMocHJvcC50YWJsZSh0ZXh0MV9zZW50aW1lbnRfc2NvcmVzWywgMTo4XSkpCmRhdCA8LSBkYXRhLmZyYW1lKAogIGxhcHBseShpbmRleCxmdW5jdGlvbihpKSBhc3NpZ24oc2VudGltZW50c1tpXSwgc2NvcmVzW2ldLCBlbnZpciA9IGdsb2JhbGVudigpKSApCiAgKQpuYW1lcyhkYXQpPC1TZW50aW1lbnRMYWJlbHNbaW5kZXhdCmRhdCA8LSByYmluZChtYXhtaW4sIGRhdCkgI+ODh+ODvOOCv+OBrue1kOWQiAoKIyMjI3JhZGFyY2hhcnTjga7oqK3lrpojIyMjIyAKI2NlbnRlcnplcm8gPSBUUlVF44Gn5Lit5b+D44GMMAojYXhpc3R5cGU66Lu45Z+65rqW6Kit5a6aLDA654Sh44GXLCAxOuWJsuWQiCwgMjrlrp/mlbAsIDM65Ymy5ZCILOWun+aVsCwgNDrmnIDlpKfjgpIxLCA1OuacgOWkp+OCkjEs5a6f5pWwCiNzZWc65YiG5Ymy5pWwCiNwbHR5Oue3muOBrueorumhngojdmxjZXg644Op44OZ44Or44Gu5aSn44GN44GVCnJhZGFyY2hhcnQoZGF0LCBheGlzdHlwZSA9IDIsIHNlZyA9IDgsIHBsdHkgPSAxLCBwY29sPSJibHVlIiwgdmxjZXggPSAxLiwKICAgICAgICAgICBjZW50ZXJ6ZXJvID0gVFJVRSwgdmxhYmVscyA9IGNvbG5hbWVzKGRhdCksY2dsY29sID0iZ3JheSIsCiAgICAgICAgICAgdGl0bGUgPSAiTlJDIEVtb3Rpb25zIGluIEFMIEpBWkVFUkEgVGV4dCAoOCBOb3YgMjAyMykiKQojIGRlZmF1bHQ6IHBjb2w9MTo4ICgxOmJsYWNrLCAyOnJlZCwgMzpncmVlbiwgNDpibHVlLCA1OmN5YW4sIDY6bWFnZW50YSwgNzp5ZWxsb3csIDg6Z3JheSkKYGBgCgojIyMgPGEgaHJlZj0iaHR0cHM6Ly93d3cuYmJjLmNvbS9uZXdzL3dvcmxkLWV1cm9wZS02NzM1NTQyMyIgdGFyZ2V0PSJfYmxhbmsiPlNlbnRpbWVudCBhbmFseXNpcyBvZiBhbiBCQkMgYXJ0aWNsZTwvYT7jga7mhJ/mg4XlvpfngrkKYGBge3J9CnRleHQyX3N0cmluZyA8LSBnZXRfdGV4dF9hc19zdHJpbmcoIkc3L0JCQy50eHQiKQp0ZXh0Ml93b3JkcyA8LSBnZXRfdG9rZW5zKHRleHQyX3N0cmluZykKdGV4dDJfc2VudGltZW50X3Njb3JlcyA8LSBnZXRfbnJjX3NlbnRpbWVudCh0ZXh0Ml93b3JkcykKYGBgCiMjIyA8YSBocmVmPSJodHRwczovL21pbmF0by5zaXAyMWMub3JnL21zYi9tYW4vcmFkYXJjaGFydC5odG1sIiB0YXJnZXQ9Il9ibGFuayI+cmFkYXJjaGFydOmWouaVsDwvYT7jgafmj4/nlLsKYGBge3J9CiPmnIDlpKfjgIHmnIDlsI/jg4fjg7zjgr/jga7mupblgpkKaW5kZXg8LTE6OApTZW50aW1lbnRMYWJlbHMgPC0gbmFtZXModGV4dDFfc2VudGltZW50X3Njb3JlcykKbWF4bWluIDwtIGRhdGEuZnJhbWUoCiAgbGFwcGx5KGluZGV4LGZ1bmN0aW9uKGkpIGFzc2lnbihTZW50aW1lbnRMYWJlbHNbaV0sIGMoMC4zLDApLCBlbnZpciA9IGdsb2JhbGVudigpKSApCikKbmFtZXMobWF4bWluKTwtU2VudGltZW50TGFiZWxzW2luZGV4XQoKc2NvcmVzMTwtY29sU3Vtcyhwcm9wLnRhYmxlKHRleHQxX3NlbnRpbWVudF9zY29yZXNbLCAxOjhdKSkKc2NvcmVzMjwtY29sU3Vtcyhwcm9wLnRhYmxlKHRleHQyX3NlbnRpbWVudF9zY29yZXNbLCAxOjhdKSkKc2NvcmVzIDwtbWFwcGx5KGMsc2NvcmVzMSxzY29yZXMyKQoKUk5Ha2luZCgiTWVyc2VubmUtVHdpc3RlciIpCmRhdCA8LSBkYXRhLmZyYW1lKAogIGxhcHBseShpbmRleCxmdW5jdGlvbihpKSBhc3NpZ24oc2VudGltZW50c1tpXSwgc2NvcmVzWyxpXSwgZW52aXIgPSBnbG9iYWxlbnYoKSkgKQogICkKbmFtZXMoZGF0KTwtU2VudGltZW50TGFiZWxzW2luZGV4XQpkYXQgPC0gcmJpbmQobWF4bWluLCBkYXQpCgpyYWRhcmNoYXJ0KGRhdCwgYXhpc3R5cGUgPSAyLCBzZWcgPSA4LCBwbHR5ID0gMSwgdmxjZXggPSAxLiwgcGNvbD1jKDIsMyksCiAgICAgICAgICAgY2VudGVyemVybyA9IFRSVUUsIHZsYWJlbHMgPSBjb2xuYW1lcyhkYXQpLCBjZ2xjb2wgPSJncmF5IiwKICAgICAgICAgICB0aXRsZSA9ICJOUkMgRW1vdGlvbnMgaW4gQUwgSkFaRUVSQSAmIEJCQyAoOCBOb3YgMjAyMykiKQpgYGAKIyMgc2hpbnkKPGEgaHJlZj0iaHR0cHM6Ly9zaGlueS5yc3R1ZGlvLmNvbS9nYWxsZXJ5LyIgdGFyZ2V0PSJfYmxhbmsiPlNoaW55IGFwcHMgRGVtbzwvYT4KCiMjIyBzaGlueeODkeODg+OCseODvOOCuOOBruOCpOODs+OCueODiOODvOODqwpgYGB7ciwgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygic2hpbnkiLCBkZXBlbmRlbmNpZXMgPSBUUlVFKQpgYGAKCiMjIyBzaGlueeODkeODg+OCseODvOOCuOOBruODreODvOODiQpgYGB7cn0KbGlicmFyeShzaGlueSkKYGBgCgojIyMgU2hpbnkgYXBw5L2c5oiQ5omL6aCGCjEuIFNoaW55IGFwcOOBruODleOCqeODq+ODgOOCkuS9nOaIkAoyLiB1aS5SLCBzZXJ2ZXIuUiwgKGdsb2JhbC5SKeOBruOCueOCr+ODquODl+ODiOODleOCoeOCpOODq+OCkuS9nOaIkAozLiBydW5BcHAo44OV44Kp44Or44OA5ZCNKeOBp+Wun+ihjAoKKiA8YSBocmVmPSJodHRwczovL3NoaW55LnJzdHVkaW8uY29tL3R1dG9yaWFsL3dyaXR0ZW4tdHV0b3JpYWwvbGVzc29uMS8iIHRhcmdldD0iX2JsYW5rIj5UdXRvcmlhbDwvYT4KCiMjIyBhcHBfaG9nZQoqIHNlcnZlci5SCiogdWkuUgojIyMgU2hpbnnjgqLjg5fjg6rjgrHjg7zjgrfjg6fjg7MiYXBwX2hvZ2Ui44Gu5a6f6KGMCmBgYHtyLCBldmFsPUZBTFNFfQpydW5BcHAoImFwcF9ob2dlIikKYGBgCgojIyMgYXBwX2hvZ2UyCiogc2VydmVyLlIKKiB1aS5SCiogZ2xvYmFsLlIKCiMjIyBTaGlueeOCouODl+ODquOCseODvOOCt+ODp+ODsyJhcHBfaG9nZTIi44Gu5a6f6KGMCmBgYHtyLCBldmFsPUZBTFNFfQpydW5BcHAoImFwcF9ob2dlMiIpCmBgYAoKIyMjIOODl+ODreODg+ODiOODnuODvOOCq+ODvOOBruOCouODl+ODquOCseODvOOCt+ODp+ODszEiYXBwX3BjaDEi44Gu5a6f6KGMCiogPGEgaHJlZj0iaHR0cDovL3d3dy5zdGhkYS5jb20vZW5nbGlzaC93aWtpL3ItcGxvdC1wY2gtc3ltYm9scy10aGUtZGlmZmVyZW50LXBvaW50LXNoYXBlcy1hdmFpbGFibGUtaW4tciIgdGFyZ2V0PSJfYmxhbmsiPlBDSCBTeW1ib2xzPC9hPgpgYGB7ciwgZXZhbD1GQUxTRX0KcnVuQXBwKCJhcHBfcGNoMSIpCmBgYAoKIyMjIOODl+ODreODg+ODiOODnuODvOOCq+ODvOOBruOCouODl+ODquOCseODvOOCt+ODp+ODszIiYXBwX3BjaDIi44Gu5a6f6KGMCmBgYHtyLCBldmFsPUZBTFNFfQpydW5BcHAoImFwcF9wY2gyIikKYGBgCgojIyMgU2hpbnnjgafjgqLjg5fjg6rjgrHjg7zjgrfjg6fjg7PjgpLkvZzmiJDjgZnjgovpmpvjga7ms6jmhI/ngrkKKiBVSe+8iOWkluims++8iemDqOWIhuOBi+OCieS9nOOCiuWni+OCgeOCiwoqIOWwkeOBl+OBmuOBpOOCs+ODvOODieOCkuabuOOBhOOBpuOAgeOBk+OBvuOCgeOBq+WLleS9nOeiuuiqjQoK