ダミーデータの生成

 以下はMJIR2019にて発表予定の「R言語を用いた再生可能な教学IR情報の分析と可視化」(発表者:専修大学西山慶太)で使用したダミーデータを生成するスクリプトである.    

#ライブラリの読み込み
library(tidyverse) #tidyverseパッケージの読込
library(knitr) #knitrパッケージの読込
library(MASS)   #MASSパッケージの読込
library(DT) #DTパッケージの読込



###擬似データの作成
#GPAの平均値と標準偏差(GPA疑似データのパラメタ)
gpa <- c(2.5,1)
#二変数間の相関係数(GPAと修得単位の相関係数を0.8に設定して,疑似データを発生させる)
r <- c(0.8)

#1~4年次の標準修得単位数とその標準偏差,CAPを1年40単位にそれぞれ設定
f <- c(31,10,40)
s <- c(62,20,80)
j <- c(93,30,120)
g <- c(124,30,160)

#GPAと修得単位の疑似データを学年ごとに作成
##1年次
# 平均値ベクタ
Mu <- c(gpa[1], f[1])   
# 分散共分散行列
Si <- matrix(c(gpa[2]^2,
               r*gpa[2]*f[2],
               r*gpa[2]*f[2],
               f[2]^2), ncol=2) 

# 疑似データを1万サンプル生成(ガウス分布で)
dat <- mvrnorm(10000, Mu, Si)   

#GPA範囲とCAP範囲でフィルタをかけて,3000人分のデータを保存
dat_1 <- data.frame(GPA=dat[,1], credit=dat[,2]) %>% 
  filter(GPA<=4 & GPA >=0 & credit <= f[3] & credit >=0) %>% 
  sample_n(size = 3000) 

##2年次
# 平均値ベクタ
Mu <- c(gpa[1], s[1])   
# 分散共分散行列
Si <- matrix(c(gpa[2]^2,
               r*gpa[2]*s[2],
               r*gpa[2]*s[2],
               s[2]^2), ncol=2) 
# 疑似データを1万サンプル生成(ガウス分布で)
dat <- mvrnorm(10000, Mu, Si)   
#GPA範囲とCAP範囲でフィルタをかけて,3000人分のデータを保存
dat_2 <- data.frame(GPA=dat[,1], credit=dat[,2]) %>% 
  filter(GPA<=4 & GPA >=0 & credit <= s[3] & credit >=0) %>% 
  sample_n(size = 3000) 

##3年次
# 平均値ベクタ
Mu <- c(gpa[1], j[1])   
# 分散共分散行列
Si <- matrix(c(gpa[2]^2,
               r*gpa[2]*j[2],
               r*gpa[2]*j[2],
               j[2]^2), ncol=2) 

# 疑似データを1万サンプル生成(ガウス分布で)
dat <- mvrnorm(10000, Mu, Si)
#GPA範囲とCAP範囲でフィルタをかけて,3000人分のデータを保存
dat_3 <- data.frame(GPA=dat[,1], credit=dat[,2]) %>% 
  filter(GPA<=4 & GPA >=0 & credit <= j[3] & credit >=0) %>% 
  sample_n(size = 3000) 

##4年次
# 平均値ベクタ
Mu <- c(gpa[1], g[1])   
# 分散共分散行列
Si <- matrix(c(gpa[2]^2,
               r*gpa[2]*g[2],
               r*gpa[2]*g[2],
               g[2]^2), ncol=2) 
# 疑似データを1万サンプル生成(ガウス分布で)
dat <- mvrnorm(10000, Mu, Si)   
#GPA範囲とCAP範囲でフィルタをかけて,3000人分のデータを保存
dat_4 <- data.frame(GPA=dat[,1], credit=dat[,2]) %>% 
  filter(GPA<=4 & GPA >=0 & credit <= g[3] & credit >=0) %>% 
  sample_n(size = 3000) 

#dplyrの関数を邪魔することがあるので,MASSパッケージを無効にしておく
detach("package:MASS", unload=TRUE)

##データの確認
#1年次
dat_1 %>% 
  ggplot(aes(x = GPA, y = credit))+
  geom_point()

##生成された疑似データに学年列を追加し,データを結合
rbind(
  dat_1 %>% mutate(grade = 1),
  dat_2 %>% mutate(grade = 2),
  dat_3 %>% mutate(grade = 3),
  dat_4 %>% mutate(grade = 4)
) -> dat

##学部名の文字列を作成
#7つの学部とそれぞれの学部定員が合計1.2万人になるように作成
school <- rep(c("人文学部", "情報学部", "工学部",
                "社会科学部","農学部","法学部","人間科学部"), 
              times = c(2000,750,1250,
                        3000,1000,3500,500)) %>% 
  as.tibble() %>% rename(school = value) #列名をschoolに

##学科名の文字列を作成
#7つの学部の下に学科名を作成
department <- rep(c("哲学科", "言語学科", "歴史学科", "地理学科","芸術学科",
                    "人間情報学科","応用情報学科",
                    "機会工学科","建築学科","土木工学科",
                    "経済学科","経営学科","商学科","応用ファイナンス学科",
                    "森林学科","水産学科","環境保全学科",
                    "法律学科","政治学科","国際法学科","新領域法学科",
                    "心理学科","社会学科"), 
                  times = c(300,500,500,500,200,
                            400,350,
                            500,500,250,
                            800,800,800,600,
                            300,300,400,
                            1000,800,1000,700,
                            150,350)) %>% 
  as.tibble() %>% rename(department = value) #列名をdepartmentに

##学部名と学科名のデータを結合して,ランダムに並べかえる
school <- cbind(school, department) %>% 
  mutate(no = rnorm(12000,10,5)) %>% 
  arrange(no) %>% select(-no)

##GPA情報・修得単位の疑似データと,学部・学科データを結合
dat <- cbind(dat, school)

##ダミーの学籍番号を追加
dat %>% 
  mutate(sID = str_c(str_sub(school,1,1),
                     str_sub(department,1,1),
                     grade,
                     "-",
                     row_number())) -> dat

#GPAを小数点第二位まで,取得単位数を整数値にする.
#ついでに学部,学科名をfactor型にしておく
dat %>% 
  mutate(credit = as.integer(credit)) %>% 
  mutate(GPA = round(GPA, digits = 2)) %>% 
  mutate(school = factor(school)) %>% 
  mutate(department = factor(department)) -> dat

#列の順番を並び替え,学部,学科,学年,学生番号でソート
dat %>% 
  select(sID,school, department, grade, GPA, credit) %>% 
  arrange(school, department, grade, sID) -> dat

##学部,学年ごとの統計量を確認
dat %>% 
  select(-sID) %>% 
  group_by(school, grade,department) %>% 
  summarise_all(funs(mean,sd)) %>% 
  mutate(GPA_mean = round(GPA_mean, digits = 2)) %>% 
  mutate(GPA_sd = round(GPA_sd, digits = 2)) %>% 
  mutate(credit_mean = round(GPA_mean, digits = 2)) %>% 
  mutate(credit_sd = round(credit_sd, digits = 2)) %>% 
  datatable(filter =  "top", 
          extensions = 'Scroller', options = list(
  deferRender = TRUE,
  dom = "frtiS",
  scrollY = 200,
  scrollCollapse = TRUE
))

 以上でダミーデータの生成は終了です.
 ここに記載したプログラム等は2次利用していただいてOKです.ただし,実際の大学業務に使用する際には,自己責任でお願いします.プログラムを使用したことによる不利益等は責任を負いかねますので予めご了承ください.
   また,不備等もあろうかと思いますので,ご質問等は西山(k.nis80[at]gmail.com)までお願いします.  

LS0tCnRpdGxlOiAiRGF0YSBHZW5lcmF0aW5nIFNjcmlwdCIKYXV0aG9yOiAiS2VpdGEgTmlzaGl5YW1hIgpkYXRlOiAiMTAvMi8yMDE5IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgIyBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgojIOODgOODn+ODvOODh+ODvOOCv+OBrueUn+aIkCAgCgrjgIDku6XkuIvjga9NSklSMjAxOeOBq+OBpueZuuihqOS6iOWumuOBruOAjFLoqIDoqp7jgpLnlKjjgYTjgZ/lho3nlJ/lj6/og73jgarmlZnlraZJUuaDheWgseOBruWIhuaekOOBqOWPr+imluWMluOAje+8iOeZuuihqOiAhe+8muWwguS/ruWkp+Wtpuilv+WxseaFtuWkqu+8ieOBp+S9v+eUqOOBl+OBn+ODgOODn+ODvOODh+ODvOOCv+OCkueUn+aIkOOBmeOCi+OCueOCr+ODquODl+ODiOOBp+OBguOCi++8jgrjgIAK44CACmBgYHtyLCBlcnJvcj1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nPSBGQUxTRX0KI+ODqeOCpOODluODqeODquOBruiqreOBv+i+vOOBvwpsaWJyYXJ5KHRpZHl2ZXJzZSkgI3RpZHl2ZXJzZeODkeODg+OCseODvOOCuOOBruiqrei+vApsaWJyYXJ5KGtuaXRyKSAja25pdHLjg5Hjg4PjgrHjg7zjgrjjga7oqq3ovrwKbGlicmFyeShNQVNTKQkjTUFTU+ODkeODg+OCseODvOOCuOOBruiqrei+vApsaWJyYXJ5KERUKSAjRFTjg5Hjg4PjgrHjg7zjgrjjga7oqq3ovrwKCgoKIyMj5pOs5Ly844OH44O844K/44Gu5L2c5oiQCiNHUEHjga7lubPlnYflgKTjgajmqJnmupblgY/lt67vvIhHUEHnlpHkvLzjg4fjg7zjgr/jga7jg5Hjg6njg6Hjgr/vvIkKZ3BhIDwtIGMoMi41LDEpCiPkuozlpInmlbDplpPjga7nm7jplqLkv4LmlbDvvIhHUEHjgajkv67lvpfljZjkvY3jga7nm7jplqLkv4LmlbDjgpIwLjjjgavoqK3lrprjgZfjgabvvIznlpHkvLzjg4fjg7zjgr/jgpLnmbrnlJ/jgZXjgZvjgovvvIkKciA8LSBjKDAuOCkKCiPvvJHvvZ7vvJTlubTmrKHjga7mqJnmupbkv67lvpfljZjkvY3mlbDjgajjgZ3jga7mqJnmupblgY/lt67vvIxDQVDjgpIx5bm0NDDljZjkvY3jgavjgZ3jgozjgZ7jgozoqK3lrpoKZiA8LSBjKDMxLDEwLDQwKQpzIDwtIGMoNjIsMjAsODApCmogPC0gYyg5MywzMCwxMjApCmcgPC0gYygxMjQsMzAsMTYwKQoKI0dQQeOBqOS/ruW+l+WNmOS9jeOBrueWkeS8vOODh+ODvOOCv+OCkuWtpuW5tOOBlOOBqOOBq+S9nOaIkAojI++8keW5tOasoQojIOW5s+Wdh+WApOODmeOCr+OCvwpNdSA8LSBjKGdwYVsxXSwgZlsxXSkJCiMg5YiG5pWj5YWx5YiG5pWj6KGM5YiXClNpIDwtIG1hdHJpeChjKGdwYVsyXV4yLAogICAgICAgICAgICAgICByKmdwYVsyXSpmWzJdLAogICAgICAgICAgICAgICByKmdwYVsyXSpmWzJdLAogICAgICAgICAgICAgICBmWzJdXjIpLCBuY29sPTIpCQoKIyDnlpHkvLzjg4fjg7zjgr/jgpIx5LiH44K144Oz44OX44Or55Sf5oiQ77yI44Ks44Km44K55YiG5biD44Gn77yJCmRhdCA8LSBtdnJub3JtKDEwMDAwLCBNdSwgU2kpCQoKI0dQQeevhOWbsuOBqENBUOevhOWbsuOBp+ODleOCo+ODq+OCv+OCkuOBi+OBkeOBpu+8jDMwMDDkurrliIbjga7jg4fjg7zjgr/jgpLkv53lrZgKZGF0XzEgPC0gZGF0YS5mcmFtZShHUEE9ZGF0WywxXSwgY3JlZGl0PWRhdFssMl0pICU+JSAKICBmaWx0ZXIoR1BBPD00ICYgR1BBID49MCAmIGNyZWRpdCA8PSBmWzNdICYgY3JlZGl0ID49MCkgJT4lIAogIHNhbXBsZV9uKHNpemUgPSAzMDAwKQkKCiMj77yS5bm05qyhCiMg5bmz5Z2H5YCk44OZ44Kv44K/Ck11IDwtIGMoZ3BhWzFdLCBzWzFdKQkKIyDliIbmlaPlhbHliIbmlaPooYzliJcKU2kgPC0gbWF0cml4KGMoZ3BhWzJdXjIsCiAgICAgICAgICAgICAgIHIqZ3BhWzJdKnNbMl0sCiAgICAgICAgICAgICAgIHIqZ3BhWzJdKnNbMl0sCiAgICAgICAgICAgICAgIHNbMl1eMiksIG5jb2w9MikJCiMg55aR5Ly844OH44O844K/44KSMeS4h+OCteODs+ODl+ODq+eUn+aIkO+8iOOCrOOCpuOCueWIhuW4g+OBp++8iQpkYXQgPC0gbXZybm9ybSgxMDAwMCwgTXUsIFNpKQkKI0dQQeevhOWbsuOBqENBUOevhOWbsuOBp+ODleOCo+ODq+OCv+OCkuOBi+OBkeOBpu+8jDMwMDDkurrliIbjga7jg4fjg7zjgr/jgpLkv53lrZgKZGF0XzIgPC0gZGF0YS5mcmFtZShHUEE9ZGF0WywxXSwgY3JlZGl0PWRhdFssMl0pICU+JSAKICBmaWx0ZXIoR1BBPD00ICYgR1BBID49MCAmIGNyZWRpdCA8PSBzWzNdICYgY3JlZGl0ID49MCkgJT4lIAogIHNhbXBsZV9uKHNpemUgPSAzMDAwKQkKCiMj77yT5bm05qyhCiMg5bmz5Z2H5YCk44OZ44Kv44K/Ck11IDwtIGMoZ3BhWzFdLCBqWzFdKQkKIyDliIbmlaPlhbHliIbmlaPooYzliJcKU2kgPC0gbWF0cml4KGMoZ3BhWzJdXjIsCiAgICAgICAgICAgICAgIHIqZ3BhWzJdKmpbMl0sCiAgICAgICAgICAgICAgIHIqZ3BhWzJdKmpbMl0sCiAgICAgICAgICAgICAgIGpbMl1eMiksIG5jb2w9MikJCgojIOeWkeS8vOODh+ODvOOCv+OCkjHkuIfjgrXjg7Pjg5fjg6vnlJ/miJDvvIjjgqzjgqbjgrnliIbluIPjgafvvIkKZGF0IDwtIG12cm5vcm0oMTAwMDAsIE11LCBTaSkKI0dQQeevhOWbsuOBqENBUOevhOWbsuOBp+ODleOCo+ODq+OCv+OCkuOBi+OBkeOBpu+8jDMwMDDkurrliIbjga7jg4fjg7zjgr/jgpLkv53lrZgKZGF0XzMgPC0gZGF0YS5mcmFtZShHUEE9ZGF0WywxXSwgY3JlZGl0PWRhdFssMl0pICU+JSAKICBmaWx0ZXIoR1BBPD00ICYgR1BBID49MCAmIGNyZWRpdCA8PSBqWzNdICYgY3JlZGl0ID49MCkgJT4lIAogIHNhbXBsZV9uKHNpemUgPSAzMDAwKQkKCiMj77yU5bm05qyhCiMg5bmz5Z2H5YCk44OZ44Kv44K/Ck11IDwtIGMoZ3BhWzFdLCBnWzFdKQkKIyDliIbmlaPlhbHliIbmlaPooYzliJcKU2kgPC0gbWF0cml4KGMoZ3BhWzJdXjIsCiAgICAgICAgICAgICAgIHIqZ3BhWzJdKmdbMl0sCiAgICAgICAgICAgICAgIHIqZ3BhWzJdKmdbMl0sCiAgICAgICAgICAgICAgIGdbMl1eMiksIG5jb2w9MikJCiMg55aR5Ly844OH44O844K/44KSMeS4h+OCteODs+ODl+ODq+eUn+aIkO+8iOOCrOOCpuOCueWIhuW4g+OBp++8iQpkYXQgPC0gbXZybm9ybSgxMDAwMCwgTXUsIFNpKQkKI0dQQeevhOWbsuOBqENBUOevhOWbsuOBp+ODleOCo+ODq+OCv+OCkuOBi+OBkeOBpu+8jDMwMDDkurrliIbjga7jg4fjg7zjgr/jgpLkv53lrZgKZGF0XzQgPC0gZGF0YS5mcmFtZShHUEE9ZGF0WywxXSwgY3JlZGl0PWRhdFssMl0pICU+JSAKICBmaWx0ZXIoR1BBPD00ICYgR1BBID49MCAmIGNyZWRpdCA8PSBnWzNdICYgY3JlZGl0ID49MCkgJT4lIAogIHNhbXBsZV9uKHNpemUgPSAzMDAwKQkKCiNkcGx5cuOBrumWouaVsOOCkumCqumtlOOBmeOCi+OBk+OBqOOBjOOBguOCi+OBruOBp++8jE1BU1Pjg5Hjg4PjgrHjg7zjgrjjgpLnhKHlirnjgavjgZfjgabjgYrjgY8KZGV0YWNoKCJwYWNrYWdlOk1BU1MiLCB1bmxvYWQ9VFJVRSkKCiMj44OH44O844K/44Gu56K66KqNCiMx5bm05qyhCmRhdF8xICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBHUEEsIHkgPSBjcmVkaXQpKSsKICBnZW9tX3BvaW50KCkKIzLlubTmrKEKZGF0XzIgJT4lIAogIGdncGxvdChhZXMoeCA9IEdQQSwgeSA9IGNyZWRpdCkpKwogIGdlb21fcG9pbnQoKQojM+W5tOasoQpkYXRfMyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gR1BBLCB5ID0gY3JlZGl0KSkrCiAgZ2VvbV9wb2ludCgpCiM05bm05qyhCmRhdF80ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBHUEEsIHkgPSBjcmVkaXQpKSsKICBnZW9tX3BvaW50KCkKCgojI+eUn+aIkOOBleOCjOOBn+eWkeS8vOODh+ODvOOCv+OBq+WtpuW5tOWIl+OCkui/veWKoOOBl++8jOODh+ODvOOCv+OCkue1kOWQiApyYmluZCgKICBkYXRfMSAlPiUgbXV0YXRlKGdyYWRlID0gMSksCiAgZGF0XzIgJT4lIG11dGF0ZShncmFkZSA9IDIpLAogIGRhdF8zICU+JSBtdXRhdGUoZ3JhZGUgPSAzKSwKICBkYXRfNCAlPiUgbXV0YXRlKGdyYWRlID0gNCkKKSAtPiBkYXQKCiMj5a2m6YOo5ZCN44Gu5paH5a2X5YiX44KS5L2c5oiQCiM344Gk44Gu5a2m6YOo44Go44Gd44KM44Ge44KM44Gu5a2m6YOo5a6a5ZOh44GM5ZCI6KiIMS4y5LiH5Lq644Gr44Gq44KL44KI44GG44Gr5L2c5oiQCnNjaG9vbCA8LSByZXAoYygi5Lq65paH5a2m6YOoIiwgIuaDheWgseWtpumDqCIsICLlt6Xlrabpg6giLAogICAgICAgICAgICAgICAgIuekvuS8muenkeWtpumDqCIsIui+suWtpumDqCIsIuazleWtpumDqCIsIuS6uumWk+enkeWtpumDqCIpLCAKICAgICAgICAgICAgICB0aW1lcyA9IGMoMjAwMCw3NTAsMTI1MCwKICAgICAgICAgICAgICAgICAgICAgICAgMzAwMCwxMDAwLDM1MDAsNTAwKSkgJT4lIAogIGFzLnRpYmJsZSgpICU+JSByZW5hbWUoc2Nob29sID0gdmFsdWUpICPliJflkI3jgpJzY2hvb2zjgasKCiMj5a2m56eR5ZCN44Gu5paH5a2X5YiX44KS5L2c5oiQCiPvvJfjgaTjga7lrabpg6jjga7kuIvjgavlrabnp5HlkI3jgpLkvZzmiJAKZGVwYXJ0bWVudCA8LSByZXAoYygi5ZOy5a2m56eRIiwgIuiogOiqnuWtpuenkSIsICLmrbTlj7Llrabnp5EiLCAi5Zyw55CG5a2m56eRIiwi6Iq46KGT5a2m56eRIiwKICAgICAgICAgICAgICAgICAgICAi5Lq66ZaT5oOF5aCx5a2m56eRIiwi5b+c55So5oOF5aCx5a2m56eRIiwKICAgICAgICAgICAgICAgICAgICAi5qmf5Lya5bel5a2m56eRIiwi5bu656+J5a2m56eRIiwi5Zyf5pyo5bel5a2m56eRIiwKICAgICAgICAgICAgICAgICAgICAi57WM5riI5a2m56eRIiwi57WM5Za25a2m56eRIiwi5ZWG5a2m56eRIiwi5b+c55So44OV44Kh44Kk44OK44Oz44K55a2m56eRIiwKICAgICAgICAgICAgICAgICAgICAi5qOu5p6X5a2m56eRIiwi5rC055Sj5a2m56eRIiwi55Kw5aKD5L+d5YWo5a2m56eRIiwKICAgICAgICAgICAgICAgICAgICAi5rOV5b6L5a2m56eRIiwi5pS/5rK75a2m56eRIiwi5Zu96Zqb5rOV5a2m56eRIiwi5paw6aCY5Z+f5rOV5a2m56eRIiwKICAgICAgICAgICAgICAgICAgICAi5b+D55CG5a2m56eRIiwi56S+5Lya5a2m56eRIiksIAogICAgICAgICAgICAgICAgICB0aW1lcyA9IGMoMzAwLDUwMCw1MDAsNTAwLDIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDQwMCwzNTAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICA1MDAsNTAwLDI1MCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDgwMCw4MDAsODAwLDYwMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMwMCwzMDAsNDAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgMTAwMCw4MDAsMTAwMCw3MDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAxNTAsMzUwKSkgJT4lIAogIGFzLnRpYmJsZSgpICU+JSByZW5hbWUoZGVwYXJ0bWVudCA9IHZhbHVlKSAj5YiX5ZCN44KSZGVwYXJ0bWVudOOBqwoKIyPlrabpg6jlkI3jgajlrabnp5HlkI3jga7jg4fjg7zjgr/jgpLntZDlkIjjgZfjgabvvIzjg6njg7Pjg4Djg6DjgavkuKbjgbnjgYvjgYjjgosKc2Nob29sIDwtIGNiaW5kKHNjaG9vbCwgZGVwYXJ0bWVudCkgJT4lIAogIG11dGF0ZShubyA9IHJub3JtKDEyMDAwLDEwLDUpKSAlPiUgCiAgYXJyYW5nZShubykgJT4lIHNlbGVjdCgtbm8pCgojI0dQQeaDheWgseODu+S/ruW+l+WNmOS9jeOBrueWkeS8vOODh+ODvOOCv+OBqO+8jOWtpumDqOODu+WtpuenkeODh+ODvOOCv+OCkue1kOWQiApkYXQgPC0gY2JpbmQoZGF0LCBzY2hvb2wpCgojI+ODgOODn+ODvOOBruWtpuexjeeVquWPt+OCkui/veWKoApkYXQgJT4lIAogIG11dGF0ZShzSUQgPSBzdHJfYyhzdHJfc3ViKHNjaG9vbCwxLDEpLAogICAgICAgICAgICAgICAgICAgICBzdHJfc3ViKGRlcGFydG1lbnQsMSwxKSwKICAgICAgICAgICAgICAgICAgICAgZ3JhZGUsCiAgICAgICAgICAgICAgICAgICAgICItIiwKICAgICAgICAgICAgICAgICAgICAgcm93X251bWJlcigpKSkgLT4gZGF0CgojR1BB44KS5bCP5pWw54K556ys5LqM5L2N44G+44Gn77yM5Y+W5b6X5Y2Y5L2N5pWw44KS5pW05pWw5YCk44Gr44GZ44KLLgoj44Gk44GE44Gn44Gr5a2m6YOo77yM5a2m56eR5ZCN44KSZmFjdG9y5Z6L44Gr44GX44Gm44GK44GPCmRhdCAlPiUgCiAgbXV0YXRlKGNyZWRpdCA9IGFzLmludGVnZXIoY3JlZGl0KSkgJT4lIAogIG11dGF0ZShHUEEgPSByb3VuZChHUEEsIGRpZ2l0cyA9IDIpKSAlPiUgCiAgbXV0YXRlKHNjaG9vbCA9IGZhY3RvcihzY2hvb2wpKSAlPiUgCiAgbXV0YXRlKGRlcGFydG1lbnQgPSBmYWN0b3IoZGVwYXJ0bWVudCkpIC0+IGRhdAoKI+WIl+OBrumghueVquOCkuS4puOBs+abv+OBiCzlrabpg6jvvIzlrabnp5HvvIzlrablubTvvIzlrabnlJ/nlarlj7fjgafjgr3jg7zjg4gKZGF0ICU+JSAKICBzZWxlY3Qoc0lELHNjaG9vbCwgZGVwYXJ0bWVudCwgZ3JhZGUsIEdQQSwgY3JlZGl0KSAlPiUgCiAgYXJyYW5nZShzY2hvb2wsIGRlcGFydG1lbnQsIGdyYWRlLCBzSUQpIC0+IGRhdAoKIyPlrabpg6jvvIzlrablubTjgZTjgajjga7ntbHoqIjph4/jgpLnorroqo0KZGF0ICU+JSAKICBzZWxlY3QoLXNJRCkgJT4lIAogIGdyb3VwX2J5KHNjaG9vbCwgZ3JhZGUsZGVwYXJ0bWVudCkgJT4lIAogIHN1bW1hcmlzZV9hbGwoZnVucyhtZWFuLHNkKSkgJT4lIAogIG11dGF0ZShHUEFfbWVhbiA9IHJvdW5kKEdQQV9tZWFuLCBkaWdpdHMgPSAyKSkgJT4lIAogIG11dGF0ZShHUEFfc2QgPSByb3VuZChHUEFfc2QsIGRpZ2l0cyA9IDIpKSAlPiUgCiAgbXV0YXRlKGNyZWRpdF9tZWFuID0gcm91bmQoR1BBX21lYW4sIGRpZ2l0cyA9IDIpKSAlPiUgCiAgbXV0YXRlKGNyZWRpdF9zZCA9IHJvdW5kKGNyZWRpdF9zZCwgZGlnaXRzID0gMikpICU+JSAKICBkYXRhdGFibGUoZmlsdGVyID0gICJ0b3AiLCAKICAgICAgICAgIGV4dGVuc2lvbnMgPSAnU2Nyb2xsZXInLCBvcHRpb25zID0gbGlzdCgKICBkZWZlclJlbmRlciA9IFRSVUUsCiAgZG9tID0gImZydGlTIiwKICBzY3JvbGxZID0gMjAwLAogIHNjcm9sbENvbGxhcHNlID0gVFJVRQopKQoKIyPjg4Djg5/jg7zjg4fjg7zjgr/jgpJjc3bjg5XjgqHjgqTjg6vjgavlh7rlipsKd3JpdGUuY3N2KGRhdCwgImR1bW15X2RhdGEuY3N2IikKCmBgYAoK44CA5Lul5LiK44Gn44OA44Of44O844OH44O844K/44Gu55Sf5oiQ44Gv57WC5LqG44Gn44GZ77yOICAK44CA44GT44GT44Gr6KiY6LyJ44GX44Gf44OX44Ot44Kw44Op44Og562J44Gv77yS5qyh5Yip55So44GX44Gm44GE44Gf44Gg44GE44GmT0vjgafjgZnvvI7jgZ/jgaDjgZfvvIzlrp/pmpvjga7lpKflrabmpa3li5njgavkvb/nlKjjgZnjgovpmpvjgavjga/vvIzoh6rlt7Hosqzku7vjgafjgYrpoZjjgYTjgZfjgb7jgZnvvI7jg5fjg63jgrDjg6njg6DjgpLkvb/nlKjjgZfjgZ/jgZPjgajjgavjgojjgovkuI3liKnnm4rnrYnjga/osqzku7vjgpLosqDjgYTjgYvjga3jgb7jgZnjga7jgafkuojjgoHjgZTkuobmib/jgY/jgaDjgZXjgYTvvI4gIArjgIAK44CA44G+44Gf77yM5LiN5YKZ562J44KC44GC44KN44GG44GL44Go5oCd44GE44G+44GZ44Gu44Gn77yM44GU6LOq5ZWP562J44Gv6KW/5bGxKGsubmlzODBbYXRdZ21haWwuY29tKeOBvuOBp+OBiumhmOOBhOOBl+OBvuOBme+8jgrjgIAKCg==