版权声明:本套课程材料开源,使用和分享必须遵守「创作共用许可协议 CC BY-NC-SA」(来源引用-非商业用途使用-以相同方式共享)。


R对象类型:二维数据表结构

矩阵(matrix)

  • 二维、单类型数据

【实践1】矩阵操作

x = 1:9
m = matrix(x, nrow=3, ncol=3)
m
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
m[1, ]
[1] 1 4 7
m[, 3]
[1] 7 8 9
m[1, 3]
[1] 7
nrow(m)  # 行数
[1] 3
ncol(m)  # 列数
[1] 3
rowMeans(m)  # 行平均
[1] 4 5 6
colMeans(m)  # 列平均
[1] 2 5 8
t(m)  # 矩阵转置
     [,1] [,2] [,3]
[1,]    1    2    3
[2,]    4    5    6
[3,]    7    8    9
rownames(m)  # 矩阵行名称(默认没有)
NULL
colnames(m)  # 矩阵列名称(默认没有)
NULL
rownames(m) = c("a", "b", "c")  # 设置矩阵行名称
colnames(m) = c("A", "B", "C")  # 设置矩阵列名称
m  # 矩阵有名字了!
  A B C
a 1 4 7
b 2 5 8
c 3 6 9
m[1, 3]
[1] 7
m["a", "C"]
[1] 7

数据框(data frame)

  • 二维、多类型数据⭐️(最常用的数据类型!)
    • 相当于Excel表格在R里的样子
      • 每一列是一个变量
      • 每一行是一个观测值

【实践2】数据变量操作

## 数据框生成
d = data.frame(x=1:4, y=c("a", "b", "c", "d"))
d
  x y
1 1 a
2 2 b
3 3 c
4 4 d
## 数据框信息
names(d)  # 变量名
[1] "x" "y"
length(d)  # 变量个数
[1] 2
ncol(d)  # 列数(变量个数)
[1] 2
nrow(d)  # 行数(观测个数)
[1] 4
str(d)  # 查看数据结构与变量类型
'data.frame':   4 obs. of  2 variables:
 $ x: int  1 2 3 4
 $ y: chr  "a" "b" "c" "d"
View(d)  # 查看对象

d$x  # 取变量
[1] 1 2 3 4
d$y  # 取变量
[1] "a" "b" "c" "d"
d[["y"]]  # 取变量
[1] "a" "b" "c" "d"
d[1, "y"]  # 取单个值
[1] "a"
## 新变量增加
d$univ = c("ECNU", "BNU", "PKU", "THU")
d$univ = as.factor(d$univ)
str(d)  # 数据结构
'data.frame':   4 obs. of  3 variables:
 $ x   : int  1 2 3 4
 $ y   : chr  "a" "b" "c" "d"
 $ univ: Factor w/ 4 levels "BNU","ECNU","PKU",..: 2 1 3 4
## 数据框提取
d[, 2:3]  # 取子集
  y univ
1 a ECNU
2 b  BNU
3 c  PKU
4 d  THU
d[1:2, 2:3]  # 取子集
  y univ
1 a ECNU
2 b  BNU
d[d$x < 3, ]  # 按条件取子集
  x y univ
1 1 a ECNU
2 2 b  BNU
d[d$x < 3 & d$y %in% c("a", "c"), c("y", "univ")]  # 按条件取子集
  y univ
1 a ECNU
## 数据框组合
d$univ = NULL  # 删除变量
d1 = data.frame(x=5:8, y=c("e", "f", "g", "h"))
d.d1 = rbind(d, d1)  # rbind()行合并
d.d1
  x y
1 1 a
2 2 b
3 3 c
4 4 d
5 5 e
6 6 f
7 7 g
8 8 h
d2 = data.frame(z=5:8)
d.d2 = cbind(d, d2)  # cbind()列合并
d.d2
  x y z
1 1 a 5
2 2 b 6
3 3 c 7
4 4 d 8
## 变量名设置
names(d.d2)
[1] "x" "y" "z"
names(d.d2)[2]
[1] "y"
names(d.d2)[1:2] = c("xxx", "yyy")  # 修改变量名
d.d2  # 变量名已修改
  xxx yyy z
1   1   a 5
2   2   b 6
3   3   c 7
4   4   d 8
names(d.d2) = c("var.1", "var.2", "var.3")  # 变量名可以包含.
d.d2  # 变量名已修改
  var.1 var.2 var.3
1     1     a     5
2     2     b     6
3     3     c     7
4     4     d     8

【知识点】数据框的变量名要求

  • 建议使用英文(区分大小写)、数字、点(.)、下划线(_)命名变量
    • 一般以英文开头,如Item1Item.1Item_1
  • 不建议使用中文、横线(-)、空格()命名变量

【探索发现】数据框(data.frame)和数据表(data.table)对比

  • 第6章将会系统学习一种先进、高效、简约的数据表类型(data.table)

外部数据导入导出

【知识点】“一站式”数据导入导出函数

  • bruceR包的import()export()函数提供了“一站式”数据导入导出功能
    • 根据文件后缀名,全自动选择最优导入导出方式,不再需要记住大量的read_xxx()函数,节省时间,提升效率!
      • 细节可查阅帮助文档
  • import()帮助文档

“一站式”数据导出

【实践3】数据导出练习

library(bruceR)
between.2  # 将要导出的示例数据
   A B SCORE
1  1 1     3
2  1 1     6
3  1 1     4
4  1 1     3
5  1 2     4
6  1 2     6
7  1 2     4
8  1 2     2
9  1 3     5
10 1 3     7
11 1 3     5
12 1 3     2
13 2 1     4
14 2 1     5
15 2 1     3
16 2 1     3
17 2 2     8
18 2 2     9
19 2 2     8
20 2 2     7
21 2 3    12
22 2 3    13
23 2 3    12
24 2 3    11
export(between.2)  # 导出到剪切板,可粘贴(Ctrl + V)到其他地方
export(between.2, file="data.csv")  # 导出到CSV逗号分隔值纯文本文件
export(between.2, file="data.sav")  # 导出到SPSS数据文件

export(list(between.1, between.2, between.3), file="data.xlsx") 
# 导出到Excel文件(Sheet1、Sheet2、Sheet3)

export(
  list(between.1, between.2, between.3),
  sheet = c("d1", "d2", "d3"),  # 设定每个数据导出的Sheet名称
  file = "data_named.xlsx"
)
# 导出到Excel文件(Sheet名称:d1、d2、d3)

“一站式”数据导入

【实践4】数据导入练习

library(bruceR)

d1 = import("data_named.xlsx", sheet="d1")
d2 = import("data_named.xlsx", sheet="d2")
d3 = import("data_named.xlsx", sheet="d3")

df = import("data.csv")
dt = import("data.csv", as="data.table")  # 导入为data.table对象

class(df)  # data.frame
[1] "data.frame"
class(dt)  # data.table(基于data.frame的高级数据表对象)
[1] "data.table" "data.frame"
str(dt)  # 数据结构
Classes 'data.table' and 'data.frame':  24 obs. of  3 variables:
 $ A    : int  1 1 1 1 1 1 1 1 1 1 ...
 $ B    : int  1 1 1 1 2 2 2 2 3 3 ...
 $ SCORE: int  3 6 4 3 4 6 4 2 5 7 ...
 - attr(*, ".internal.selfref")=<externalptr> 

* 拓展:数据压缩存储格式

【知识点】RData数据压缩存储格式

  • .RData(也可写为.rdata、.rda):特殊文件格式,可压缩存储多个R对象、数据集
    • "gzip":快速压缩(最快,默认)
    • "bzip2":中度压缩(较快)
    • "xz":极限压缩(较慢)

save(d1, d2, d3, file="datasets1.RData")  # 保存为RData

save(d1, d2, d3,
     file = "datasets2.RData",
     compress = "xz",        # "gzip", "bzip2", "xz"
     compression_level = 9)  # 压缩程度:1~9

rm(d1, d2, d3)  # 移除环境中的数据对象

load("datasets1.RData")  # 载入RData中压缩存储的数据对象
str(d1)  # 已载入到环境
'data.frame':   32 obs. of  2 variables:
 $ A    : num  1 1 1 1 1 1 1 1 2 2 ...
 $ SCORE: num  3 6 4 3 5 7 5 2 4 6 ...
str(d2)  # 已载入到环境
'data.frame':   24 obs. of  3 variables:
 $ A    : num  1 1 1 1 1 1 1 1 1 1 ...
 $ B    : num  1 1 1 1 2 2 2 2 3 3 ...
 $ SCORE: num  3 6 4 3 4 6 4 2 5 7 ...
str(d3)  # 已载入到环境
'data.frame':   32 obs. of  4 variables:
 $ A    : num  1 1 1 1 1 1 1 1 1 1 ...
 $ B    : num  1 1 1 1 1 1 1 1 2 2 ...
 $ C    : num  1 1 1 1 2 2 2 2 1 1 ...
 $ SCORE: num  3 6 4 3 5 7 5 2 4 6 ...

* 拓展:网络爬虫自动数据采集

【知识点】Web前端数据结构

  • 网页组成三大元素
    • HTML(结构):超文本标记语言
    • CSS(样式):层叠样式表
    • JavaScript(动作):网页动作脚本

【实践5】静态网页解析

  • 静态网页示例:华东师范大学心理与认知科学学院“师资队伍”页面
  • 网页元素提取:CSS选择代码
    • CSS选择代码定义了用于精准定位HTML元素的基本模式,可简洁描述想要提取的元素
    • SelectorGadget(将这个超链接拖拽到你的浏览器书签栏,即可使用)
library(rvest)

url = "https://psy.ecnu.edu.cn/17437/list.htm"  # 网页链接
xml = url %>% read_html()  # 读取网页所有信息

xml %>% html_elements(".column-item-link .column-name") %>% html_text2()
 [1] "各级人才工程"               "认知与神经科学系"          
 [3] "毕生发展与学习科学系"       "社会与管理心理学系"        
 [5] "健康与临床心理学系"         "人工智能与人因工程系(筹)"
 [7] "实验员/专任助理研究员"      "党政管理"                  
 [9] "兼职教师"                   "全职博士后"                
[11] "荣休教师"                   "永远怀念教师名录"          
xml %>% html_elements(".subcolumn-name") %>% html_text2()
 [1] "华东师范大学特聘教授"     "国家级人才项目"          
 [3] "国家级青年人才项目"       "中国科协托举人才"        
 [5] "教育部新世纪人才"         "上海市曙光学者"          
 [7] "上海市浦江学者"           "上海市青年科技启明星项目"
 [9] "上海市晨光计划"           "上海市扬帆计划"          
xml %>% html_elements(".column-news-title") %>% html_text2()
 [1] "周晓林 博士"   "蒯曙光 博士"   "周晓林 博士"   "蔡清 博士"    
 [5] "郝宁 博士"     "蒯曙光 博士"   "高晓雪 博士"   "罗艺 博士"    
 [9] "崔丽娟 博士"   "刘永芳 博士"   "庞维国 博士"   "郝宁 博士"    
[13] "刘俊升 博士"   "陆静怡 博士"   "蔡清 博士"     "包寒吴霜 博士"
[17] "李先春 博士"   "刘俊升 博士"   "孟慧 博士"     "庞维国 博士"  
[21] "宋永宁博士"    "王弘毅 博士"   "王青 博士"     "席居哲 博士"  
[25] "谢鑫宇博士"    "周宁宁 博士"   "张琪 博士"     "包寒吴霜 博士"
[29] "梁一鸣 博士"   "陆静怡 博士"   "王青 博士"     "杨莹 博士"    
[33] "周晗昱 博士"   "陈 曦 博士"    "梁一鸣 博士"   "李世佳 博士"  
[37] "杨莹 博士"     "周晗昱 博士"  

【作业4】期末自选公开数据导入

作业要求:

  • 开始准备个人期末大作业,自主寻找任意一个感兴趣的公开数据,写出数据导入代码
    • 数据选择:按照自己的兴趣,从国内外期刊中选择一篇公开了研究数据的论文,下载其中一个公开数据(有可能存放于OSFSciDB等平台),数据文件一般为CSV、Excel等格式
    • 数据导入:参考【实践4】代码,使用bruceR包的import()函数,将该数据导入为data.table对象

平台提交:

  • 自选论文的DOI链接和公开数据链接
  • 原数据打开后的前几行、前几列截图
  • 数据导入代码(使用import()函数)及导入后的数据结构(使用str()函数)截图
LS0tDQp0aXRsZTogIuOAilLor63oqIDjgIvnrKwz56ug77ya5pWw5o2u57uT5p6EIg0Kc3VidGl0bGU6IDxhIGhyZWY9Imh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS8iPui/lOWbnuivvueoi+S4u+mhtTwvYT4NCmF1dGhvcjogIuaOiOivvuaVmeW4iO+8muWMheWvkuWQtOmcnCINCiMgZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGFuY2hvcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICBjc3M6IFJtZENTUy5jc3MNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8cCBzdHlsZT0iZm9udC1zaXplOiAxMnB4Ij7niYjmnYPlo7DmmI7vvJrmnKzlpZfor77nqIvmnZDmlpnlvIDmupDvvIzkvb/nlKjlkozliIbkuqvlv4XpobvpgbXlrojjgIzliJvkvZzlhbHnlKjorrjlj6/ljY/orq4gQ0MgQlktTkMtU0HjgI3vvIjmnaXmupDlvJXnlKgt6Z2e5ZWG5Lia55So6YCU5L2/55SoLeS7peebuOWQjOaWueW8j+WFseS6q++8ieOAgjxpbWcgc3JjPSJpbWcvQ0MtQlktTkMtU0EuanBnIiB3aWR0aD0iMTIwcHgiIGhlaWdodD0iNDJweCIgc3R5bGU9ImZsb2F0OiByaWdodCIgLz48L3A+DQpgYGANCg0KYGBge3IgQ29uZmlnLCBpbmNsdWRlPUZBTFNFfQ0Kb3B0aW9ucygNCiAga25pdHIua2FibGUuTkEgPSAiIiwNCiAgZGlnaXRzID0gNA0KKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiIsDQogIGZpZy53aWR0aCA9IDYsDQogIGZpZy5oZWlnaHQgPSA0LA0KICBkcGkgPSAzMDANCikNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBDaGFwMDPvvJrmlbDmja7nu5PmnoQNCg0KIyMjIyDlvoDmnJ/opoHngrnlm57pob4NCg0KLSAgIFtDaGFwMDIgXCMgUuWvueixoeexu+Wei++8iOWQkemHj+OAgeWIl+ihqO+8iV0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlL0NoYXAwMiMlRTclOUYlQTUlRTglQUYlODYlRTclODIlQjlyJUU1JUFGJUI5JUU4JUIxJUExJUU0JUI4JThFJUU1JTg3JUJEJUU2JTk1JUIwKXsudXJpfQ0KDQojIyMjIOacrOeroOimgeeCueebruW9lQ0KDQotICAgW+OAkOWunui3tTHjgJHnn6npmLXmk43kvZxdKCPlrp7ot7Ux55+p6Zi15pON5L2cKQ0KLSAgIFvjgJDlrp7ot7Uy44CR5pWw5o2u5Y+Y6YeP5pON5L2cXSgj5a6e6Le1MuaVsOaNruWPmOmHj+aTjeS9nCnvvIjph43ngrnvvIkNCi0gICBb44CQ55+l6K+G54K544CR5pWw5o2u5qGG55qE5Y+Y6YeP5ZCN6KaB5rGCXSgj55+l6K+G54K55pWw5o2u5qGG55qE5Y+Y6YeP5ZCN6KaB5rGCKQ0KLSAgIFvjgJDmjqLntKLlj5HnjrDjgJHmlbDmja7moYbvvIhkYXRhLmZyYW1l77yJ5ZKM5pWw5o2u6KGo77yIZGF0YS50YWJsZe+8ieWvueavlF0oI+aOoue0ouWPkeeOsOaVsOaNruahhmRhdGEuZnJhbWXlkozmlbDmja7ooahkYXRhLnRhYmxl5a+55q+UKQ0KLSAgIFvjgJDnn6Xor4bngrnjgJHigJzkuIDnq5nlvI/igJ3mlbDmja7lr7zlhaXlr7zlh7rlh73mlbBdKCPnn6Xor4bngrnkuIDnq5nlvI/mlbDmja7lr7zlhaXlr7zlh7rlh73mlbApDQotICAgW+OAkOWunui3tTPjgJHmlbDmja7lr7zlh7rnu4PkuaBdKCPlrp7ot7Uz5pWw5o2u5a+85Ye657uD5LmgKe+8iOmHjeeCue+8iQ0KLSAgIFvjgJDlrp7ot7U044CR5pWw5o2u5a+85YWl57uD5LmgXSgj5a6e6Le1NOaVsOaNruWvvOWFpee7g+S5oCnvvIjph43ngrnvvIkNCi0gICBb44CQ55+l6K+G54K544CRUkRhdGHmlbDmja7ljovnvKnlrZjlgqjmoLzlvI9dKCPnn6Xor4bngrlyZGF0YeaVsOaNruWOi+e8qeWtmOWCqOagvOW8jykNCi0gICBb44CQ55+l6K+G54K544CRV2Vi5YmN56uv5pWw5o2u57uT5p6EXSgj55+l6K+G54K5d2Vi5YmN56uv5pWw5o2u57uT5p6EKQ0KLSAgIFvjgJDlrp7ot7U144CR6Z2Z5oCB572R6aG16Kej5p6QXSgj5a6e6Le1NemdmeaAgee9kemhteino+aekCkNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyDmnKznq6DmiYDpnIBS5YyFDQpsaWJyYXJ5KGJydWNlUikNCmxpYnJhcnkocnZlc3QpICAjIOe9kee7nOeIrOiZqw0KYGBgDQoNCiMgUuWvueixoeexu+Wei++8muS6jOe7tOaVsOaNruihqOe7k+aehA0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC00MjI3MTg5MTg3LnBuZykNCg0KIyMg55+p6Zi177yIbWF0cml477yJDQoNCi0gICDkuoznu7TjgIHljZXnsbvlnovmlbDmja4NCg0KIyMjIyDjgJDlrp7ot7Ux44CR55+p6Zi15pON5L2cIHsj5a6e6Le1MeefqemYteaTjeS9nH0NCg0KYGBge3J9DQp4ID0gMTo5DQptID0gbWF0cml4KHgsIG5yb3c9MywgbmNvbD0zKQ0KbQ0KbVsxLCBdDQptWywgM10NCm1bMSwgM10NCg0KbnJvdyhtKSAgIyDooYzmlbANCm5jb2wobSkgICMg5YiX5pWwDQpyb3dNZWFucyhtKSAgIyDooYzlubPlnYcNCmNvbE1lYW5zKG0pICAjIOWIl+W5s+Wdhw0KDQp0KG0pICAjIOefqemYtei9rOe9rg0KDQpyb3duYW1lcyhtKSAgIyDnn6npmLXooYzlkI3np7DvvIjpu5jorqTmsqHmnInvvIkNCmNvbG5hbWVzKG0pICAjIOefqemYteWIl+WQjeensO+8iOm7mOiupOayoeacie+8iQ0KDQpyb3duYW1lcyhtKSA9IGMoImEiLCAiYiIsICJjIikgICMg6K6+572u55+p6Zi16KGM5ZCN56ewDQpjb2xuYW1lcyhtKSA9IGMoIkEiLCAiQiIsICJDIikgICMg6K6+572u55+p6Zi15YiX5ZCN56ewDQptICAjIOefqemYteacieWQjeWtl+S6hu+8gQ0KbVsxLCAzXQ0KbVsiYSIsICJDIl0NCmBgYA0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0zNTU2MTMwOTI1LnBuZykNCg0KIyMg5pWw5o2u5qGG77yIZGF0YSBmcmFtZe+8iQ0KDQotICAg5LqM57u044CB5aSa57G75Z6L5pWw5o2u4q2Q77iP77yI5pyA5bi455So55qE5pWw5o2u57G75Z6L77yB77yJDQogICAgLSAgIOebuOW9k+S6jkV4Y2Vs6KGo5qC85ZyoUumHjOeahOagt+WtkA0KICAgICAgICAtICAg5q+P5LiA5YiX5piv5LiA5Liq5Y+Y6YePDQogICAgICAgIC0gICDmr4/kuIDooYzmmK/kuIDkuKrop4LmtYvlgLwNCg0KIyMjIyDjgJDlrp7ot7Uy44CR5pWw5o2u5Y+Y6YeP5pON5L2cIHsj5a6e6Le1MuaVsOaNruWPmOmHj+aTjeS9nH0NCg0KYGBge3J9DQojIyDmlbDmja7moYbnlJ/miJANCmQgPSBkYXRhLmZyYW1lKHg9MTo0LCB5PWMoImEiLCAiYiIsICJjIiwgImQiKSkNCmQNCg0KIyMg5pWw5o2u5qGG5L+h5oGvDQpuYW1lcyhkKSAgIyDlj5jph4/lkI0NCmxlbmd0aChkKSAgIyDlj5jph4/kuKrmlbANCm5jb2woZCkgICMg5YiX5pWw77yI5Y+Y6YeP5Liq5pWw77yJDQpucm93KGQpICAjIOihjOaVsO+8iOingua1i+S4quaVsO+8iQ0Kc3RyKGQpICAjIOafpeeci+aVsOaNrue7k+aehOS4juWPmOmHj+exu+Weiw0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KVmlldyhkKSAgIyDmn6XnnIvlr7nosaENCmBgYA0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0zOTI4MDU1OTU4LnBuZykNCg0KYGBge3J9DQpkJHggICMg5Y+W5Y+Y6YePDQpkJHkgICMg5Y+W5Y+Y6YePDQpkW1sieSJdXSAgIyDlj5blj5jph48NCmRbMSwgInkiXSAgIyDlj5bljZXkuKrlgLwNCg0KIyMg5paw5Y+Y6YeP5aKe5YqgDQpkJHVuaXYgPSBjKCJFQ05VIiwgIkJOVSIsICJQS1UiLCAiVEhVIikNCmQkdW5pdiA9IGFzLmZhY3RvcihkJHVuaXYpDQpzdHIoZCkgICMg5pWw5o2u57uT5p6EDQoNCiMjIOaVsOaNruahhuaPkOWPlg0KZFssIDI6M10gICMg5Y+W5a2Q6ZuGDQpkWzE6MiwgMjozXSAgIyDlj5blrZDpm4YNCmRbZCR4IDwgMywgXSAgIyDmjInmnaHku7blj5blrZDpm4YNCmRbZCR4IDwgMyAmIGQkeSAlaW4lIGMoImEiLCAiYyIpLCBjKCJ5IiwgInVuaXYiKV0gICMg5oyJ5p2h5Lu25Y+W5a2Q6ZuGDQoNCiMjIOaVsOaNruahhue7hOWQiA0KZCR1bml2ID0gTlVMTCAgIyDliKDpmaTlj5jph48NCmQxID0gZGF0YS5mcmFtZSh4PTU6OCwgeT1jKCJlIiwgImYiLCAiZyIsICJoIikpDQpkLmQxID0gcmJpbmQoZCwgZDEpICAjIHJiaW5kKCnooYzlkIjlubYNCmQuZDENCmQyID0gZGF0YS5mcmFtZSh6PTU6OCkNCmQuZDIgPSBjYmluZChkLCBkMikgICMgY2JpbmQoKeWIl+WQiOW5tg0KZC5kMg0KDQojIyDlj5jph4/lkI3orr7nva4NCm5hbWVzKGQuZDIpDQpuYW1lcyhkLmQyKVsyXQ0KbmFtZXMoZC5kMilbMToyXSA9IGMoInh4eCIsICJ5eXkiKSAgIyDkv67mlLnlj5jph4/lkI0NCmQuZDIgICMg5Y+Y6YeP5ZCN5bey5L+u5pS5DQpuYW1lcyhkLmQyKSA9IGMoInZhci4xIiwgInZhci4yIiwgInZhci4zIikgICMg5Y+Y6YeP5ZCN5Y+v5Lul5YyF5ZCrLg0KZC5kMiAgIyDlj5jph4/lkI3lt7Lkv67mlLkNCmBgYA0KDQojIyMjIOOAkOefpeivhueCueOAkeaVsOaNruahhueahOWPmOmHj+WQjeimgeaxgiB7I+efpeivhueCueaVsOaNruahhueahOWPmOmHj+WQjeimgeaxgn0NCg0KLSAgIOW7uuiuruS9v+eUqOiLseaWh++8iOWMuuWIhuWkp+Wwj+WGme+8ieOAgeaVsOWtl+OAgeeCue+8iGAuYO+8ieOAgeS4i+WIkue6v++8iGBfYO+8ieWRveWQjeWPmOmHjw0KICAgIC0gICDkuIDoiKzku6Xoi7HmloflvIDlpLTvvIzlpoJgSXRlbTFg44CBYEl0ZW0uMWDjgIFgSXRlbV8xYA0KLSAgIOS4jeW7uuiuruS9v+eUqOS4reaWh+OAgeaoque6v++8iGAtYO+8ieOAgeepuuagvO+8iO+8ieWRveWQjeWPmOmHjw0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0zNTA2NDc5MTIucG5nKQ0KDQojIyMjIOOAkOaOoue0ouWPkeeOsOOAkeaVsOaNruahhu+8iGRhdGEuZnJhbWXvvInlkozmlbDmja7ooajvvIhkYXRhLnRhYmxl77yJ5a+55q+UIHsj5o6i57Si5Y+R546w5pWw5o2u5qGGZGF0YS5mcmFtZeWSjOaVsOaNruihqGRhdGEudGFibGXlr7nmr5R9DQoNCi0gICBb56ysNueroF0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlL0NoYXAwNinlsIbkvJrns7vnu5/lrabkuaDkuIDnp40qKuWFiOi/m+OAgemrmOaViOOAgeeugOe6pioq55qE5pWw5o2u6KGo57G75Z6L77yIZGF0YS50YWJsZe+8iQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0xNzAwMTU3NzgwLnBuZykNCg0KIyDlpJbpg6jmlbDmja7lr7zlhaXlr7zlh7oNCg0KIyMjIyDjgJDnn6Xor4bngrnjgJHigJzkuIDnq5nlvI/igJ3mlbDmja7lr7zlhaXlr7zlh7rlh73mlbAgeyPnn6Xor4bngrnkuIDnq5nlvI/mlbDmja7lr7zlhaXlr7zlh7rlh73mlbB9DQoNCi0gICBgYnJ1Y2VSYOWMheeahGBpbXBvcnQoKWDlkoxgZXhwb3J0KClg5Ye95pWw5o+Q5L6b5LqG4oCc5LiA56uZ5byP4oCd5pWw5o2u5a+85YWl5a+85Ye65Yqf6IO9DQogICAgLSAgIOagueaNruaWh+S7tuWQjue8gOWQje+8jOWFqOiHquWKqOmAieaLqeacgOS8mOWvvOWFpeWvvOWHuuaWueW8j++8jOS4jeWGjemcgOimgeiusOS9j+Wkp+mHj+eahGByZWFkX3h4eCgpYOWHveaVsO+8jOiKguecgeaXtumXtO+8jOaPkOWNh+aViOeOh++8gQ0KICAgICAgICAtICAg57uG6IqC5Y+v5p+l6ZiF5biu5Yqp5paH5qGjDQotICAgYGltcG9ydCgpYOW4ruWKqeaWh+ahow0KICAgIC0gICA8aHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9icnVjZVIvcmVmZXJlbmNlL2ltcG9ydC5odG1sPg0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0xMTc2ODAyNTYzLnBuZykNCg0KLSAgIGBleHBvcnQoKWDluK7liqnmlofmoaMNCiAgICAtICAgPGh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vYnJ1Y2VSL3JlZmVyZW5jZS9leHBvcnQuaHRtbD4NCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMTkyMTI4NzI2MC5wbmcpDQoNCiMjIOKAnOS4gOermeW8j+KAneaVsOaNruWvvOWHug0KDQojIyMjIOOAkOWunui3tTPjgJHmlbDmja7lr7zlh7rnu4PkuaAgeyPlrp7ot7Uz5pWw5o2u5a+85Ye657uD5LmgfQ0KDQpgYGB7cn0NCmxpYnJhcnkoYnJ1Y2VSKQ0KYmV0d2Vlbi4yICAjIOWwhuimgeWvvOWHuueahOekuuS+i+aVsOaNrg0KYGBgDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KZXhwb3J0KGJldHdlZW4uMikgICMg5a+85Ye65Yiw5Ymq5YiH5p2/77yM5Y+v57KY6LS077yIQ3RybCArIFbvvInliLDlhbbku5blnLDmlrkNCmBgYA0KDQpgYGB7cn0NCmV4cG9ydChiZXR3ZWVuLjIsIGZpbGU9ImRhdGEuY3N2IikgICMg5a+85Ye65YiwQ1NW6YCX5Y+35YiG6ZqU5YC857qv5paH5pys5paH5Lu2DQpleHBvcnQoYmV0d2Vlbi4yLCBmaWxlPSJkYXRhLnNhdiIpICAjIOWvvOWHuuWIsFNQU1PmlbDmja7mlofku7YNCg0KZXhwb3J0KGxpc3QoYmV0d2Vlbi4xLCBiZXR3ZWVuLjIsIGJldHdlZW4uMyksIGZpbGU9ImRhdGEueGxzeCIpIA0KIyDlr7zlh7rliLBFeGNlbOaWh+S7tu+8iFNoZWV0MeOAgVNoZWV0MuOAgVNoZWV0M++8iQ0KDQpleHBvcnQoDQogIGxpc3QoYmV0d2Vlbi4xLCBiZXR3ZWVuLjIsIGJldHdlZW4uMyksDQogIHNoZWV0ID0gYygiZDEiLCAiZDIiLCAiZDMiKSwgICMg6K6+5a6a5q+P5Liq5pWw5o2u5a+85Ye655qEU2hlZXTlkI3np7ANCiAgZmlsZSA9ICJkYXRhX25hbWVkLnhsc3giDQopDQojIOWvvOWHuuWIsEV4Y2Vs5paH5Lu277yIU2hlZXTlkI3np7DvvJpkMeOAgWQy44CBZDPvvIkNCmBgYA0KDQojIyDigJzkuIDnq5nlvI/igJ3mlbDmja7lr7zlhaUNCg0KIyMjIyDjgJDlrp7ot7U044CR5pWw5o2u5a+85YWl57uD5LmgIHsj5a6e6Le1NOaVsOaNruWvvOWFpee7g+S5oH0NCg0KYGBge3J9DQpsaWJyYXJ5KGJydWNlUikNCg0KZDEgPSBpbXBvcnQoImRhdGFfbmFtZWQueGxzeCIsIHNoZWV0PSJkMSIpDQpkMiA9IGltcG9ydCgiZGF0YV9uYW1lZC54bHN4Iiwgc2hlZXQ9ImQyIikNCmQzID0gaW1wb3J0KCJkYXRhX25hbWVkLnhsc3giLCBzaGVldD0iZDMiKQ0KDQpkZiA9IGltcG9ydCgiZGF0YS5jc3YiKQ0KZHQgPSBpbXBvcnQoImRhdGEuY3N2IiwgYXM9ImRhdGEudGFibGUiKSAgIyDlr7zlhaXkuLpkYXRhLnRhYmxl5a+56LGhDQoNCmNsYXNzKGRmKSAgIyBkYXRhLmZyYW1lDQpjbGFzcyhkdCkgICMgZGF0YS50YWJsZe+8iOWfuuS6jmRhdGEuZnJhbWXnmoTpq5jnuqfmlbDmja7ooajlr7nosaHvvIkNCnN0cihkdCkgICMg5pWw5o2u57uT5p6EDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtNjExOTQ4MDA0LnBuZykNCg0KIyMgXCog5ouT5bGV77ya5pWw5o2u5Y6L57yp5a2Y5YKo5qC85byPDQoNCiMjIyMg44CQ55+l6K+G54K544CRUkRhdGHmlbDmja7ljovnvKnlrZjlgqjmoLzlvI8geyPnn6Xor4bngrlyZGF0YeaVsOaNruWOi+e8qeWtmOWCqOagvOW8j30NCg0KLSAgIC5SRGF0Ye+8iOS5n+WPr+WGmeS4ui5yZGF0YeOAgS5yZGHvvInvvJrnibnmrormlofku7bmoLzlvI/vvIzlj6/ljovnvKnlrZjlgqjlpJrkuKpS5a+56LGh44CB5pWw5o2u6ZuGDQogICAgLSAgIGAiZ3ppcCJg77ya5b+r6YCf5Y6L57yp77yI5pyA5b+r77yM6buY6K6k77yJDQogICAgLSAgIGAiYnppcDIiYO+8muS4reW6puWOi+e8qe+8iOi+g+W/q++8iQ0KICAgIC0gICBgInh6ImDvvJrmnoHpmZDljovnvKnvvIjovoPmhaLvvIkNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMzUyODk4MzA4My5wbmcpDQoNCmBgYHtyfQ0Kc2F2ZShkMSwgZDIsIGQzLCBmaWxlPSJkYXRhc2V0czEuUkRhdGEiKSAgIyDkv53lrZjkuLpSRGF0YQ0KDQpzYXZlKGQxLCBkMiwgZDMsDQogICAgIGZpbGUgPSAiZGF0YXNldHMyLlJEYXRhIiwNCiAgICAgY29tcHJlc3MgPSAieHoiLCAgICAgICAgIyAiZ3ppcCIsICJiemlwMiIsICJ4eiINCiAgICAgY29tcHJlc3Npb25fbGV2ZWwgPSA5KSAgIyDljovnvKnnqIvluqbvvJoxfjkNCg0Kcm0oZDEsIGQyLCBkMykgICMg56e76Zmk546v5aKD5Lit55qE5pWw5o2u5a+56LGhDQoNCmxvYWQoImRhdGFzZXRzMS5SRGF0YSIpICAjIOi9veWFpVJEYXRh5Lit5Y6L57yp5a2Y5YKo55qE5pWw5o2u5a+56LGhDQpzdHIoZDEpICAjIOW3sui9veWFpeWIsOeOr+Wigw0Kc3RyKGQyKSAgIyDlt7Lovb3lhaXliLDnjq/looMNCnN0cihkMykgICMg5bey6L295YWl5Yiw546v5aKDDQpgYGANCg0KYGBge3IgQ2xlYXIgdXAsIGluY2x1ZGU9RkFMU0V9DQp1bmxpbmsoYygiZGF0YS5jc3YiLCAiZGF0YS5zYXYiLCAiZGF0YS54bHN4IiwgImRhdGFfbmFtZWQueGxzeCIsDQogICAgICAgICAiZGF0YXNldHMxLlJEYXRhIiwgImRhdGFzZXRzMi5SRGF0YSIpKQ0KYGBgDQoNCiMjIFwqIOaLk+Wxle+8mue9kee7nOeIrOiZq+iHquWKqOaVsOaNrumHh+mbhg0KDQojIyMjIOOAkOefpeivhueCueOAkVdlYuWJjeerr+aVsOaNrue7k+aehCB7I+efpeivhueCuXdlYuWJjeerr+aVsOaNrue7k+aehH0NCg0KLSAgIOe9kemhtee7hOaIkOS4ieWkp+WFg+e0oA0KICAgIC0gICBIVE1M77yI57uT5p6E77yJ77ya6LaF5paH5pys5qCH6K6w6K+t6KiADQogICAgLSAgIENTU++8iOagt+W8j++8ie+8muWxguWPoOagt+W8j+ihqA0KICAgIC0gICBKYXZhU2NyaXB077yI5Yqo5L2c77yJ77ya572R6aG15Yqo5L2c6ISa5pysDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTU2ODE5MTgxNy5wbmcpDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTI0NjU2NDUyMjYucG5nKQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0yOTg1NTExOTk4LnBuZykNCg0KIyMjIyDjgJDlrp7ot7U144CR6Z2Z5oCB572R6aG16Kej5p6QIHsj5a6e6Le1NemdmeaAgee9kemhteino+aekH0NCg0KLSAgIOmdmeaAgee9kemhteekuuS+i++8muWNjuS4nOW4iOiMg+Wkp+WtpuW/g+eQhuS4juiupOefpeenkeWtpuWtpumZouKAnOW4iOi1hOmYn+S8jeKAnemhtemdog0KICAgIC0gICDngrnlh7vmn6XnnIvnvZHpobXlhoXlrrnvvJo8aHR0cHM6Ly9wc3kuZWNudS5lZHUuY24vMTc0MzcvbGlzdC5odG0+DQotICAg572R6aG15YWD57Sg5o+Q5Y+W77yaQ1NT6YCJ5oup5Luj56CBDQogICAgLSAgIENTU+mAieaLqeS7o+eggeWumuS5ieS6hueUqOS6jueyvuWHhuWumuS9jUhUTUzlhYPntKDnmoTln7rmnKzmqKHlvI/vvIzlj6/nroDmtIHmj4/ov7Dmg7PopoHmj5Dlj5bnmoTlhYPntKANCiAgICAtICAgWyoqU2VsZWN0b3JHYWRnZXQqKl0oamF2YXNjcmlwdDooZnVuY3Rpb24oKSU3QnZhciUyMHM9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7cy5pbm5lckhUTUw9J0xvYWRpbmcuLi4nO3Muc3R5bGUuY29sb3I9J2JsYWNrJztzLnN0eWxlLnBhZGRpbmc9JzIwcHgnO3Muc3R5bGUucG9zaXRpb249J2ZpeGVkJztzLnN0eWxlLnpJbmRleD0nOTk5OSc7cy5zdHlsZS5mb250U2l6ZT0nMy4wZW0nO3Muc3R5bGUuYm9yZGVyPScycHglMjBzb2xpZCUyMGJsYWNrJztzLnN0eWxlLnJpZ2h0PSc0MHB4JztzLnN0eWxlLnRvcD0nNDBweCc7cy5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywnc2VsZWN0b3JfZ2FkZ2V0X2xvYWRpbmcnKTtzLnN0eWxlLmJhY2tncm91bmQ9J3doaXRlJztkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKHMpO3M9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7cy5zZXRBdHRyaWJ1dGUoJ3R5cGUnLCd0ZXh0L2phdmFzY3JpcHQnKTtzLnNldEF0dHJpYnV0ZSgnc3JjJywnaHR0cHM6Ly9kdjBha3QyOTg2dnpoLmNsb3VkZnJvbnQubmV0L3Vuc3RhYmxlL2xpYi9zZWxlY3RvcmdhZGdldC5qcycpO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQocyk7JTdEKSgpOykqKu+8iOWwhui/meS4qui2hemTvuaOpeaLluaLveWIsOS9oOeahOa1j+iniOWZqOS5puetvuagj++8jOWNs+WPr+S9v+eUqO+8iSoqDQogICAgICAgIC0gICBb5L2/55So5pWZ56iLXShodHRwczovL3NlbGVjdG9yZ2FkZ2V0LmNvbS8pDQoNCmBgYHtyfQ0KbGlicmFyeShydmVzdCkNCg0KdXJsID0gImh0dHBzOi8vcHN5LmVjbnUuZWR1LmNuLzE3NDM3L2xpc3QuaHRtIiAgIyDnvZHpobXpk77mjqUNCnhtbCA9IHVybCAlPiUgcmVhZF9odG1sKCkgICMg6K+75Y+W572R6aG15omA5pyJ5L+h5oGvDQoNCnhtbCAlPiUgaHRtbF9lbGVtZW50cygiLmNvbHVtbi1pdGVtLWxpbmsgLmNvbHVtbi1uYW1lIikgJT4lIGh0bWxfdGV4dDIoKQ0KeG1sICU+JSBodG1sX2VsZW1lbnRzKCIuc3ViY29sdW1uLW5hbWUiKSAlPiUgaHRtbF90ZXh0MigpDQp4bWwgJT4lIGh0bWxfZWxlbWVudHMoIi5jb2x1bW4tbmV3cy10aXRsZSIpICU+JSBodG1sX3RleHQyKCkNCmBgYA0KDQojIOOAkOS9nOS4mjTjgJHmnJ/mnKvoh6rpgInlhazlvIDmlbDmja7lr7zlhaUNCg0K5L2c5Lia6KaB5rGC77yaDQoNCi0gICDlvIDlp4vlh4blpIfkuKrkurrmnJ/mnKvlpKfkvZzkuJrvvIzoh6rkuLvlr7vmib7ku7vmhI/kuIDkuKrmhJ/lhbTotqPnmoTlhazlvIDmlbDmja7vvIzlhpnlh7rmlbDmja7lr7zlhaXku6PnoIENCiAgICAtICAg5pWw5o2u6YCJ5oup77ya5oyJ54Wn6Ieq5bex55qE5YW06Laj77yM5LuO5Zu95YaF5aSW5pyf5YiK5Lit6YCJ5oup5LiA56+H5YWs5byA5LqG56CU56m25pWw5o2u55qE6K665paH77yM5LiL6L295YW25Lit5LiA5Liq5YWs5byA5pWw5o2u77yI5pyJ5Y+v6IO95a2Y5pS+5LqOW09TRl0oaHR0cHM6Ly9vc2YuaW8vKeOAgVtTY2lEQl0oaHR0cHM6Ly93d3cuc2NpZGIuY24vcHN5Y2gp562J5bmz5Y+w77yJ77yM5pWw5o2u5paH5Lu25LiA6Iis5Li6Q1NW44CBRXhjZWznrYnmoLzlvI8NCiAgICAtICAg5pWw5o2u5a+85YWl77ya5Y+C6ICD44CQ5a6e6Le1NOOAkeS7o+egge+8jOS9v+eUqGBicnVjZVJg5YyF55qEYGltcG9ydCgpYOWHveaVsO+8jOWwhuivpeaVsOaNruWvvOWFpeS4umBkYXRhLnRhYmxlYOWvueixoQ0KDQrlubPlj7Dmj5DkuqTvvJoNCg0KLSAgIOiHqumAieiuuuaWh+eahERPSemTvuaOpeWSjOWFrOW8gOaVsOaNrumTvuaOpQ0KLSAgIOWOn+aVsOaNruaJk+W8gOWQjueahOWJjeWHoOihjOOAgeWJjeWHoOWIl+aIquWbvg0KLSAgIOaVsOaNruWvvOWFpeS7o+egge+8iOS9v+eUqGBpbXBvcnQoKWDlh73mlbDvvInlj4rlr7zlhaXlkI7nmoTmlbDmja7nu5PmnoTvvIjkvb/nlKhgc3RyKClg5Ye95pWw77yJ5oiq5Zu+DQo=