版权声明:本套课程材料开源,使用和分享必须遵守「创作共用许可协议 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
## 导出到剪切板,可粘贴(Ctrl + V)到其他地方
export(between.2)
## 导出到CSV逗号分隔值纯文本文件
export(between.2, file="data.csv")
## 导出到SPSS数据文件
export(between.2, file="data.sav")

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

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

“一站式”数据导入

【实践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")=<pointer: 0x0000012b3d1cace0> 

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

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

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

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

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

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

## 载入RData中压缩存储的数据对象
load("datasets1.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 ...
## 导入在线数据(douban_movies.RData)
data = import("https://psychbruce.github.io/RCourse/data/douban_movies.RData")
# View(data)

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

【知识点】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] "周晓林 博士"   "蒯曙光 博士"   "周晓林 博士"   "蔡清 博士"     "郝宁 博士"    
 [6] "蒯曙光 博士"   "高晓雪 博士"   "罗艺 博士"     "崔丽娟 博士"   "刘永芳 博士"  
[11] "庞维国 博士"   "郝宁 博士"     "刘俊升 博士"   "陆静怡 博士"   "蔡清 博士"    
[16] "包寒吴霜 博士" "李先春 博士"   "刘俊升 博士"   "孟慧 博士"     "庞维国 博士"  
[21] "宋永宁博士"    "王弘毅 博士"   "王青 博士"     "席居哲 博士"   "谢鑫宇博士"   
[26] "周宁宁 博士"   "张琪 博士"     "包寒吴霜 博士" "梁一鸣 博士"   "陆静怡 博士"  
[31] "王青 博士"     "杨莹 博士"     "周晗昱 博士"   "陈 曦 博士"    "梁一鸣 博士"  
[36] "李世佳 博士"   "杨莹 博士"     "周晗昱 博士"  

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

作业要求:

  • 开始准备个人期末大作业,自主选择任意一个感兴趣的公开数据,写出数据导入代码
    • 数据选择:可以从本课程提供的“公开数据可选列表”中,选择一篇感兴趣的研究,下载其公开数据中的一个数据文件(只选择一个有代表性的数据文件即可,无需使用研究中的全部数据文件)
    • 数据导入:参考【实践4】代码,使用bruceR包的import()函数,将该数据导入为data.table对象

平台提交:

  • 自选论文的DOI链接和公开数据链接
  • 原数据打开后的前几行、前几列截图
  • 数据导入代码(使用import()函数)及导入后的数据结构(使用str()函数)截图

返回课程主页

© 包寒吴霜

LS0tDQp0aXRsZTogIuOAilLor63oqIDjgIvnrKwz56ug77ya5pWw5o2u57uT5p6EIg0Kc3VidGl0bGU6IDxhIGhyZWY9Imh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS8iPui/lOWbnuivvueoi+S4u+mhtTwvYT4NCmF1dGhvcjogIuaOiOivvuaVmeW4iO+8muWMheWvkuWQtOmcnCINCiMgZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgYW5jaG9yX3NlY3Rpb25zOiB0cnVlDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIGNzczogUm1kQ1NTLmNzcw0KLS0tDQoNCmBgYHs9aHRtbH0NCjxwIHN0eWxlPSJmb250LXNpemU6IDEycHgiPueJiOadg+WjsOaYju+8muacrOWll+ivvueoi+adkOaWmeW8gOa6kO+8jOS9v+eUqOWSjOWIhuS6q+W/hemhu+mBteWuiOOAjOWIm+S9nOWFseeUqOiuuOWPr+WNj+iuriBDQyBCWS1OQy1TQeOAje+8iOadpea6kOW8leeUqC3pnZ7llYbkuJrnlKjpgJTkvb/nlKgt5Lul55u45ZCM5pa55byP5YWx5Lqr77yJ44CCPGltZyBzcmM9ImltZy9DQy1CWS1OQy1TQS5qcGciIHdpZHRoPSIxMjBweCIgaGVpZ2h0PSI0MnB4IiBzdHlsZT0iZmxvYXQ6IHJpZ2h0IiAvPjwvcD4NCmBgYA0KDQpgYGB7ciBDb25maWcsIGluY2x1ZGU9RkFMU0V9DQpvcHRpb25zKA0KICBrbml0ci5rYWJsZS5OQSA9ICIiLA0KICBkaWdpdHMgPSA0DQopDQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGNvbW1lbnQgPSAiIiwNCiAgZmlnLndpZHRoID0gNiwNCiAgZmlnLmhlaWdodCA9IDQsDQogIGRwaSA9IDMwMA0KKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIENoYXAwM++8muaVsOaNrue7k+aehA0KDQojIyMjIOW+gOacn+imgeeCueWbnumhvg0KDQotIFtDaGFwMDIgXCMgUuWvueixoeexu+Wei++8iOWQkemHj+OAgeWIl+ihqO+8iV0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlL0NoYXAwMiMlRTclOUYlQTUlRTglQUYlODYlRTclODIlQjlyJUU1JUFGJUI5JUU4JUIxJUExJUU0JUI4JThFJUU1JTg3JUJEJUU2JTk1JUIwKXsudXJpfQ0KDQojIyMjIOacrOeroOimgeeCueebruW9lQ0KDQotIFvjgJDlrp7ot7Ux44CR55+p6Zi15pON5L2cXSgj5a6e6Le1MeefqemYteaTjeS9nCkNCi0gW+OAkOWunui3tTLjgJHmlbDmja7lj5jph4/mk43kvZxdKCPlrp7ot7Uy5pWw5o2u5Y+Y6YeP5pON5L2cKe+8iOmHjeeCue+8iQ0KLSBb44CQ55+l6K+G54K544CR5pWw5o2u5qGG55qE5Y+Y6YeP5ZCN6KaB5rGCXSgj55+l6K+G54K55pWw5o2u5qGG55qE5Y+Y6YeP5ZCN6KaB5rGCKQ0KLSBb44CQ5o6i57Si5Y+R546w44CR5pWw5o2u5qGG77yIZGF0YS5mcmFtZe+8ieWSjOaVsOaNruihqO+8iGRhdGEudGFibGXvvInlr7nmr5RdKCPmjqLntKLlj5HnjrDmlbDmja7moYZkYXRhLmZyYW1l5ZKM5pWw5o2u6KGoZGF0YS50YWJsZeWvueavlCkNCi0gW+OAkOefpeivhueCueOAkeKAnOS4gOermeW8j+KAneaVsOaNruWvvOWFpeWvvOWHuuWHveaVsF0oI+efpeivhueCueS4gOermeW8j+aVsOaNruWvvOWFpeWvvOWHuuWHveaVsCkNCi0gW+OAkOWunui3tTPjgJHmlbDmja7lr7zlh7rnu4PkuaBdKCPlrp7ot7Uz5pWw5o2u5a+85Ye657uD5LmgKe+8iOmHjeeCue+8iQ0KLSBb44CQ5a6e6Le1NOOAkeaVsOaNruWvvOWFpee7g+S5oF0oI+Wunui3tTTmlbDmja7lr7zlhaXnu4PkuaAp77yI6YeN54K577yJDQotIFvjgJDnn6Xor4bngrnjgJFSRGF0YeaVsOaNruWOi+e8qeWtmOWCqOagvOW8j10oI+efpeivhueCuXJkYXRh5pWw5o2u5Y6L57yp5a2Y5YKo5qC85byPKQ0KLSBb44CQ55+l6K+G54K544CRV2Vi5YmN56uv5pWw5o2u57uT5p6EXSgj55+l6K+G54K5d2Vi5YmN56uv5pWw5o2u57uT5p6EKQ0KLSBb44CQ5a6e6Le1NeOAkemdmeaAgee9kemhteino+aekF0oI+Wunui3tTXpnZnmgIHnvZHpobXop6PmnpApDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMg5pys56ug5omA6ZyAUuWMhQ0KbGlicmFyeShicnVjZVIpDQpsaWJyYXJ5KHJ2ZXN0KSAgIyDnvZHnu5zniKzomasNCmBgYA0KDQojIFLlr7nosaHnsbvlnovvvJrkuoznu7TmlbDmja7ooajnu5PmnoQNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtNDIyNzE4OTE4Ny5wbmcpDQoNCiMjIOefqemYte+8iG1hdHJpeO+8iQ0KDQotIOS6jOe7tOOAgeWNleexu+Wei+aVsOaNrg0KDQojIyMjIOOAkOWunui3tTHjgJHnn6npmLXmk43kvZwgeyPlrp7ot7Ux55+p6Zi15pON5L2cfQ0KDQpgYGB7cn0NCnggPSAxOjkNCm0gPSBtYXRyaXgoeCwgbnJvdz0zLCBuY29sPTMpDQptDQptWzEsIF0NCm1bLCAzXQ0KbVsxLCAzXQ0KDQpucm93KG0pICAjIOihjOaVsA0KbmNvbChtKSAgIyDliJfmlbANCnJvd01lYW5zKG0pICAjIOihjOW5s+Wdhw0KY29sTWVhbnMobSkgICMg5YiX5bmz5Z2HDQoNCnQobSkgICMg55+p6Zi16L2s572uDQoNCnJvd25hbWVzKG0pICAjIOefqemYteihjOWQjeensO+8iOm7mOiupOayoeacie+8iQ0KY29sbmFtZXMobSkgICMg55+p6Zi15YiX5ZCN56ew77yI6buY6K6k5rKh5pyJ77yJDQoNCnJvd25hbWVzKG0pID0gYygiYSIsICJiIiwgImMiKSAgIyDorr7nva7nn6npmLXooYzlkI3np7ANCmNvbG5hbWVzKG0pID0gYygiQSIsICJCIiwgIkMiKSAgIyDorr7nva7nn6npmLXliJflkI3np7ANCm0gICMg55+p6Zi15pyJ5ZCN5a2X5LqG77yBDQptWzEsIDNdDQptWyJhIiwgIkMiXQ0KYGBgDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTM1NTYxMzA5MjUucG5nKQ0KDQojIyDmlbDmja7moYbvvIhkYXRhIGZyYW1l77yJDQoNCi0g5LqM57u044CB5aSa57G75Z6L5pWw5o2u4q2Q77iP77yI5pyA5bi455So55qE5pWw5o2u57G75Z6L77yB77yJDQogIC0g55u45b2T5LqORXhjZWzooajmoLzlnKhS6YeM55qE5qC35a2QDQogICAgLSDmr4/kuIDliJfmmK/kuIDkuKrlj5jph48NCiAgICAtIOavj+S4gOihjOaYr+S4gOS4quingua1i+WAvA0KDQojIyMjIOOAkOWunui3tTLjgJHmlbDmja7lj5jph4/mk43kvZwgeyPlrp7ot7Uy5pWw5o2u5Y+Y6YeP5pON5L2cfQ0KDQpgYGB7cn0NCiMjIOaVsOaNruahhueUn+aIkA0KZCA9IGRhdGEuZnJhbWUoeD0xOjQsIHk9YygiYSIsICJiIiwgImMiLCAiZCIpKQ0KZA0KDQojIyDmlbDmja7moYbkv6Hmga8NCm5hbWVzKGQpICAjIOWPmOmHj+WQjQ0KbGVuZ3RoKGQpICAjIOWPmOmHj+S4quaVsA0KbmNvbChkKSAgIyDliJfmlbDvvIjlj5jph4/kuKrmlbDvvIkNCm5yb3coZCkgICMg6KGM5pWw77yI6KeC5rWL5Liq5pWw77yJDQpzdHIoZCkgICMg5p+l55yL5pWw5o2u57uT5p6E5LiO5Y+Y6YeP57G75Z6LDQpgYGANCg0KYGBge3IsIGV2YWw9RkFMU0V9DQpWaWV3KGQpICAjIOafpeeci+WvueixoQ0KYGBgDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTM5MjgwNTU5NTgucG5nKQ0KDQpgYGB7cn0NCmQkeCAgIyDlj5blj5jph48NCmQkeSAgIyDlj5blj5jph48NCmRbWyJ5Il1dICAjIOWPluWPmOmHjw0KZFsxLCAieSJdICAjIOWPluWNleS4quWAvA0KDQojIyDmlrDlj5jph4/lop7liqANCmQkdW5pdiA9IGMoIkVDTlUiLCAiQk5VIiwgIlBLVSIsICJUSFUiKQ0KZCR1bml2ID0gYXMuZmFjdG9yKGQkdW5pdikNCnN0cihkKSAgIyDmlbDmja7nu5PmnoQNCg0KIyMg5pWw5o2u5qGG5o+Q5Y+WDQpkWywgMjozXSAgIyDlj5blrZDpm4YNCmRbMToyLCAyOjNdICAjIOWPluWtkOmbhg0KZFtkJHggPCAzLCBdICAjIOaMieadoeS7tuWPluWtkOmbhg0KZFtkJHggPCAzICYgZCR5ICVpbiUgYygiYSIsICJjIiksIGMoInkiLCAidW5pdiIpXSAgIyDmjInmnaHku7blj5blrZDpm4YNCg0KIyMg5pWw5o2u5qGG57uE5ZCIDQpkJHVuaXYgPSBOVUxMICAjIOWIoOmZpOWPmOmHjw0KZDEgPSBkYXRhLmZyYW1lKHg9NTo4LCB5PWMoImUiLCAiZiIsICJnIiwgImgiKSkNCmQuZDEgPSByYmluZChkLCBkMSkgICMgcmJpbmQoKeihjOWQiOW5tg0KZC5kMQ0KZDIgPSBkYXRhLmZyYW1lKHo9NTo4KQ0KZC5kMiA9IGNiaW5kKGQsIGQyKSAgIyBjYmluZCgp5YiX5ZCI5bm2DQpkLmQyDQoNCiMjIOWPmOmHj+WQjeiuvue9rg0KbmFtZXMoZC5kMikNCm5hbWVzKGQuZDIpWzJdDQpuYW1lcyhkLmQyKVsxOjJdID0gYygieHh4IiwgInl5eSIpICAjIOS/ruaUueWPmOmHj+WQjQ0KZC5kMiAgIyDlj5jph4/lkI3lt7Lkv67mlLkNCm5hbWVzKGQuZDIpID0gYygidmFyLjEiLCAidmFyLjIiLCAidmFyLjMiKSAgIyDlj5jph4/lkI3lj6/ku6XljIXlkKsuDQpkLmQyICAjIOWPmOmHj+WQjeW3suS/ruaUuQ0KYGBgDQoNCiMjIyMg44CQ55+l6K+G54K544CR5pWw5o2u5qGG55qE5Y+Y6YeP5ZCN6KaB5rGCIHsj55+l6K+G54K55pWw5o2u5qGG55qE5Y+Y6YeP5ZCN6KaB5rGCfQ0KDQotIOW7uuiuruS9v+eUqOiLseaWh++8iOWMuuWIhuWkp+Wwj+WGme+8ieOAgeaVsOWtl+OAgeeCue+8iGAuYO+8ieOAgeS4i+WIkue6v++8iGBfYO+8ieWRveWQjeWPmOmHjw0KICAtIOS4gOiIrOS7peiLseaWh+W8gOWktO+8jOWmgmBJdGVtMWDjgIFgSXRlbS4xYOOAgWBJdGVtXzFgDQotIOWPmOmHj+WQjeS4jeW7uuiuruWHuueOsOS4reaWh+OAgeaoque6v+OAgeepuuagvA0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0zNTA2NDc5MTIucG5nKQ0KDQojIyMjIOOAkOaOoue0ouWPkeeOsOOAkeaVsOaNruahhu+8iGRhdGEuZnJhbWXvvInlkozmlbDmja7ooajvvIhkYXRhLnRhYmxl77yJ5a+55q+UIHsj5o6i57Si5Y+R546w5pWw5o2u5qGGZGF0YS5mcmFtZeWSjOaVsOaNruihqGRhdGEudGFibGXlr7nmr5R9DQoNCi0gW+esrDbnq6BdKGh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS9DaGFwMDYp5bCG5Lya57O757uf5a2m5Lmg5LiA56eNKirlhYjov5vjgIHpq5jmlYjjgIHnroDnuqYqKueahOaVsOaNruihqOexu+Wei++8iGRhdGEudGFibGXvvIkNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMTcwMDE1Nzc4MC5wbmcpDQoNCiMg5aSW6YOo5pWw5o2u5a+85YWl5a+85Ye6DQoNCiMjIyMg44CQ55+l6K+G54K544CR4oCc5LiA56uZ5byP4oCd5pWw5o2u5a+85YWl5a+85Ye65Ye95pWwIHsj55+l6K+G54K55LiA56uZ5byP5pWw5o2u5a+85YWl5a+85Ye65Ye95pWwfQ0KDQotIGBicnVjZVJg5YyF55qEYGltcG9ydCgpYOWSjGBleHBvcnQoKWDlh73mlbDmj5DkvpvkuobigJzkuIDnq5nlvI/igJ3mlbDmja7lr7zlhaXlr7zlh7rlip/og70NCiAgLSDmoLnmja7mlofku7blkI7nvIDlkI3vvIzlhajoh6rliqjpgInmi6nmnIDkvJjlr7zlhaXlr7zlh7rmlrnlvI/vvIzkuI3lho3pnIDopoHorrDkvY/lpKfph4/nmoRgcmVhZF94eHgoKWDlh73mlbDvvIzoioLnnIHml7bpl7TvvIzmj5DljYfmlYjnjofvvIENCiAgICAtIOe7huiKguWPr+afpemYheW4ruWKqeaWh+ahow0KLSBgaW1wb3J0KClg5biu5Yqp5paH5qGjDQogIC0gPGh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vYnJ1Y2VSL3JlZmVyZW5jZS9pbXBvcnQuaHRtbD4NCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMTE3NjgwMjU2My5wbmcpDQoNCi0gYGV4cG9ydCgpYOW4ruWKqeaWh+ahow0KICAtIDxodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL2JydWNlUi9yZWZlcmVuY2UvZXhwb3J0Lmh0bWw+DQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTE5MjEyODcyNjAucG5nKQ0KDQojIyDigJzkuIDnq5nlvI/igJ3mlbDmja7lr7zlh7oNCg0KIyMjIyDjgJDlrp7ot7Uz44CR5pWw5o2u5a+85Ye657uD5LmgIHsj5a6e6Le1M+aVsOaNruWvvOWHuue7g+S5oH0NCg0KYGBge3J9DQpsaWJyYXJ5KGJydWNlUikNCmJldHdlZW4uMiAgIyDlsIbopoHlr7zlh7rnmoTnpLrkvovmlbDmja4NCmBgYA0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCiMjIOWvvOWHuuWIsOWJquWIh+adv++8jOWPr+eymOi0tO+8iEN0cmwgKyBW77yJ5Yiw5YW25LuW5Zyw5pa5DQpleHBvcnQoYmV0d2Vlbi4yKQ0KYGBgDQoNCmBgYHtyfQ0KIyMg5a+85Ye65YiwQ1NW6YCX5Y+35YiG6ZqU5YC857qv5paH5pys5paH5Lu2DQpleHBvcnQoYmV0d2Vlbi4yLCBmaWxlPSJkYXRhLmNzdiIpDQojIyDlr7zlh7rliLBTUFNT5pWw5o2u5paH5Lu2DQpleHBvcnQoYmV0d2Vlbi4yLCBmaWxlPSJkYXRhLnNhdiIpDQoNCiMjIOWvvOWHuuWIsEV4Y2Vs5paH5Lu277yIU2hlZXQx44CBU2hlZXQy44CBU2hlZXQz77yJDQpleHBvcnQobGlzdChiZXR3ZWVuLjEsIGJldHdlZW4uMiwgYmV0d2Vlbi4zKSwgZmlsZT0iZGF0YS54bHN4IikgDQoNCiMjIOWvvOWHuuWIsEV4Y2Vs5paH5Lu277yIU2hlZXTlkI3np7DvvJpkMeOAgWQy44CBZDPvvIkNCmV4cG9ydCgNCiAgbGlzdChiZXR3ZWVuLjEsIGJldHdlZW4uMiwgYmV0d2Vlbi4zKSwNCiAgc2hlZXQgPSBjKCJkMSIsICJkMiIsICJkMyIpLCAgIyDorr7lrprmr4/kuKrmlbDmja7lr7zlh7rnmoRTaGVldOWQjeensA0KICBmaWxlID0gImRhdGFfbmFtZWQueGxzeCINCikNCmBgYA0KDQojIyDigJzkuIDnq5nlvI/igJ3mlbDmja7lr7zlhaUNCg0KIyMjIyDjgJDlrp7ot7U044CR5pWw5o2u5a+85YWl57uD5LmgIHsj5a6e6Le1NOaVsOaNruWvvOWFpee7g+S5oH0NCg0KYGBge3J9DQpsaWJyYXJ5KGJydWNlUikNCg0KZDEgPSBpbXBvcnQoImRhdGFfbmFtZWQueGxzeCIsIHNoZWV0PSJkMSIpDQpkMiA9IGltcG9ydCgiZGF0YV9uYW1lZC54bHN4Iiwgc2hlZXQ9ImQyIikNCmQzID0gaW1wb3J0KCJkYXRhX25hbWVkLnhsc3giLCBzaGVldD0iZDMiKQ0KDQpkZiA9IGltcG9ydCgiZGF0YS5jc3YiKQ0KZHQgPSBpbXBvcnQoImRhdGEuY3N2IiwgYXM9ImRhdGEudGFibGUiKSAgIyDlr7zlhaXkuLpkYXRhLnRhYmxl5a+56LGhDQoNCmNsYXNzKGRmKSAgIyBkYXRhLmZyYW1lDQpjbGFzcyhkdCkgICMgZGF0YS50YWJsZe+8iOWfuuS6jmRhdGEuZnJhbWXnmoTpq5jnuqfmlbDmja7ooajlr7nosaHvvIkNCnN0cihkdCkgICMg5pWw5o2u57uT5p6EDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtNjExOTQ4MDA0LnBuZykNCg0KIyMgXCog5ouT5bGV77ya5pWw5o2u5Y6L57yp5a2Y5YKo5qC85byPDQoNCiMjIyMg44CQ55+l6K+G54K544CRUkRhdGHmlbDmja7ljovnvKnlrZjlgqjmoLzlvI8geyPnn6Xor4bngrlyZGF0YeaVsOaNruWOi+e8qeWtmOWCqOagvOW8j30NCg0KLSAuUkRhdGHvvIjkuZ/lj6/lhpnkuLoucmRhdGHjgIEucmRh77yJ77ya54m55q6K5paH5Lu25qC85byP77yM5Y+v5Y6L57yp5a2Y5YKo5aSa5LiqUuWvueixoeOAgeaVsOaNrumbhg0KICAtIGAiZ3ppcCJg77ya5b+r6YCf5Y6L57yp77yI5pyA5b+r77yM6buY6K6k77yJDQogIC0gYCJiemlwMiJg77ya5Lit5bqm5Y6L57yp77yI6L6D5b+r77yJDQogIC0gYCJ4eiJg77ya5p6B6ZmQ5Y6L57yp77yI6L6D5oWi77yJDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTM1Mjg5ODMwODMucG5nKQ0KDQpgYGB7cn0NCiMjIOS/neWtmOS4ulJEYXRhDQpzYXZlKGQxLCBkMiwgZDMsIGZpbGU9ImRhdGFzZXRzMS5SRGF0YSIpDQoNCnNhdmUoZDEsIGQyLCBkMywNCiAgICAgZmlsZSA9ICJkYXRhc2V0czIuUkRhdGEiLA0KICAgICBjb21wcmVzcyA9ICJ4eiIsICAgICAgICAjICJnemlwIiwgImJ6aXAyIiwgInh6Ig0KICAgICBjb21wcmVzc2lvbl9sZXZlbCA9IDkpICAjIOWOi+e8qeeoi+W6pu+8mjF+OQ0KDQojIyDnp7vpmaTnjq/looPkuK3nmoTmlbDmja7lr7nosaENCnJtKGQxLCBkMiwgZDMpDQoNCiMjIOi9veWFpVJEYXRh5Lit5Y6L57yp5a2Y5YKo55qE5pWw5o2u5a+56LGhDQpsb2FkKCJkYXRhc2V0czEuUkRhdGEiKQ0Kc3RyKGQxKSAgIyDlt7Lovb3lhaXliLDnjq/looMNCnN0cihkMikgICMg5bey6L295YWl5Yiw546v5aKDDQpzdHIoZDMpICAjIOW3sui9veWFpeWIsOeOr+Wigw0KYGBgDQoNCmBgYHtyIENsZWFyIHVwLCBpbmNsdWRlPUZBTFNFfQ0KdW5saW5rKGMoImRhdGEuY3N2IiwgImRhdGEuc2F2IiwgImRhdGEueGxzeCIsICJkYXRhX25hbWVkLnhsc3giLA0KICAgICAgICAgImRhdGFzZXRzMS5SRGF0YSIsICJkYXRhc2V0czIuUkRhdGEiKSkNCmBgYA0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMjIOWvvOWFpeWcqOe6v+aVsOaNru+8iGRvdWJhbl9tb3ZpZXMuUkRhdGHvvIkNCmRhdGEgPSBpbXBvcnQoImh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS9kYXRhL2RvdWJhbl9tb3ZpZXMuUkRhdGEiKQ0KIyBWaWV3KGRhdGEpDQpgYGANCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtNDI2NzI0NDg5LnBuZykNCg0KIyMgXCog5ouT5bGV77ya572R57uc54is6Jmr6Ieq5Yqo5pWw5o2u6YeH6ZuGDQoNCiMjIyMg44CQ55+l6K+G54K544CRV2Vi5YmN56uv5pWw5o2u57uT5p6EIHsj55+l6K+G54K5d2Vi5YmN56uv5pWw5o2u57uT5p6EfQ0KDQotIOe9kemhtee7hOaIkOS4ieWkp+WFg+e0oA0KICAtIEhUTUzvvIjnu5PmnoTvvInvvJrotoXmlofmnKzmoIforrDor63oqIANCiAgLSBDU1PvvIjmoLflvI/vvInvvJrlsYLlj6DmoLflvI/ooagNCiAgLSBKYXZhU2NyaXB077yI5Yqo5L2c77yJ77ya572R6aG15Yqo5L2c6ISa5pysDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTU2ODE5MTgxNy5wbmcpDQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTI0NjU2NDUyMjYucG5nKQ0KDQohW10oaW1hZ2VzL2NsaXBib2FyZC0yOTg1NTExOTk4LnBuZykNCg0KIyMjIyDjgJDlrp7ot7U144CR6Z2Z5oCB572R6aG16Kej5p6QIHsj5a6e6Le1NemdmeaAgee9kemhteino+aekH0NCg0KLSDpnZnmgIHnvZHpobXnpLrkvovvvJrljY7kuJzluIjojIPlpKflrablv4PnkIbkuI7orqTnn6Xnp5HlrablrabpmaLigJzluIjotYTpmJ/kvI3igJ3pobXpnaINCiAgLSDngrnlh7vmn6XnnIvnvZHpobXlhoXlrrnvvJo8aHR0cHM6Ly9wc3kuZWNudS5lZHUuY24vMTc0MzcvbGlzdC5odG0+DQotIOe9kemhteWFg+e0oOaPkOWPlu+8mkNTU+mAieaLqeS7o+eggQ0KICAtIENTU+mAieaLqeS7o+eggeWumuS5ieS6hueUqOS6jueyvuWHhuWumuS9jUhUTUzlhYPntKDnmoTln7rmnKzmqKHlvI/vvIzlj6/nroDmtIHmj4/ov7Dmg7PopoHmj5Dlj5bnmoTlhYPntKANCiAgLSBbKipTZWxlY3RvckdhZGdldCoqXShqYXZhc2NyaXB0OihmdW5jdGlvbigpJTdCdmFyJTIwcz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtzLmlubmVySFRNTD0nTG9hZGluZy4uLic7cy5zdHlsZS5jb2xvcj0nYmxhY2snO3Muc3R5bGUucGFkZGluZz0nMjBweCc7cy5zdHlsZS5wb3NpdGlvbj0nZml4ZWQnO3Muc3R5bGUuekluZGV4PSc5OTk5JztzLnN0eWxlLmZvbnRTaXplPSczLjBlbSc7cy5zdHlsZS5ib3JkZXI9JzJweCUyMHNvbGlkJTIwYmxhY2snO3Muc3R5bGUucmlnaHQ9JzQwcHgnO3Muc3R5bGUudG9wPSc0MHB4JztzLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCdzZWxlY3Rvcl9nYWRnZXRfbG9hZGluZycpO3Muc3R5bGUuYmFja2dyb3VuZD0nd2hpdGUnO2RvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQocyk7cz1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTtzLnNldEF0dHJpYnV0ZSgndHlwZScsJ3RleHQvamF2YXNjcmlwdCcpO3Muc2V0QXR0cmlidXRlKCdzcmMnLCdodHRwczovL2R2MGFrdDI5ODZ2emguY2xvdWRmcm9udC5uZXQvdW5zdGFibGUvbGliL3NlbGVjdG9yZ2FkZ2V0LmpzJyk7ZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChzKTslN0QpKCk7KSoq77yI5bCG6L+Z5Liq6LaF6ZO+5o6l5ouW5ou95Yiw5L2g55qE5rWP6KeI5Zmo5Lmm562+5qCP77yM5Y2z5Y+v5L2/55So77yJKioNCiAgICAtIFvkvb/nlKjmlZnnqItdKGh0dHBzOi8vc2VsZWN0b3JnYWRnZXQuY29tLykNCg0KYGBge3J9DQpsaWJyYXJ5KHJ2ZXN0KQ0KDQp1cmwgPSAiaHR0cHM6Ly9wc3kuZWNudS5lZHUuY24vMTc0MzcvbGlzdC5odG0iICAjIOe9kemhtemTvuaOpQ0KeG1sID0gdXJsICU+JSByZWFkX2h0bWwoKSAgIyDor7vlj5bnvZHpobXmiYDmnInkv6Hmga8NCg0KeG1sICU+JSBodG1sX2VsZW1lbnRzKCIuY29sdW1uLWl0ZW0tbGluayAuY29sdW1uLW5hbWUiKSAlPiUgaHRtbF90ZXh0MigpDQp4bWwgJT4lIGh0bWxfZWxlbWVudHMoIi5zdWJjb2x1bW4tbmFtZSIpICU+JSBodG1sX3RleHQyKCkNCnhtbCAlPiUgaHRtbF9lbGVtZW50cygiLmNvbHVtbi1uZXdzLXRpdGxlIikgJT4lIGh0bWxfdGV4dDIoKQ0KYGBgDQoNCiMg44CQ5L2c5LiaNOOAkeacn+acq+iHqumAieWFrOW8gOaVsOaNruWvvOWFpQ0KDQrkvZzkuJropoHmsYLvvJoNCg0KLSDlvIDlp4vlh4blpIfkuKrkurrmnJ/mnKvlpKfkvZzkuJrvvIzoh6rkuLvpgInmi6nku7vmhI/kuIDkuKrmhJ/lhbTotqPnmoTlhazlvIDmlbDmja7vvIzlhpnlh7rmlbDmja7lr7zlhaXku6PnoIENCiAgLSDmlbDmja7pgInmi6nvvJrlj6/ku6Xku47mnKzor77nqIvmj5DkvpvnmoTigJxb5YWs5byA5pWw5o2u5Y+v6YCJ5YiX6KGoXShodHRwczovL2RvY3MucXEuY29tL3NoZWV0L0RUWE5DVVd0eldXTnVVMDVZKeKAneS4re+8jOmAieaLqeS4gOevh+aEn+WFtOi2o+eahOeglOeptu+8jOS4i+i9veWFtuWFrOW8gOaVsOaNruS4reeahOS4gOS4quaVsOaNruaWh+S7tu+8iOWPqumAieaLqeS4gOS4quacieS7o+ihqOaAp+eahOaVsOaNruaWh+S7tuWNs+WPr++8jOaXoOmcgOS9v+eUqOeglOeptuS4reeahOWFqOmDqOaVsOaNruaWh+S7tu+8iQ0KICAtIOaVsOaNruWvvOWFpe+8muWPguiAg+OAkOWunui3tTTjgJHku6PnoIHvvIzkvb/nlKhgYnJ1Y2VSYOWMheeahGBpbXBvcnQoKWDlh73mlbDvvIzlsIbor6XmlbDmja7lr7zlhaXkuLpgZGF0YS50YWJsZWDlr7nosaENCg0K5bmz5Y+w5o+Q5Lqk77yaDQoNCi0g6Ieq6YCJ6K665paH55qERE9J6ZO+5o6l5ZKM5YWs5byA5pWw5o2u6ZO+5o6lDQotIOWOn+aVsOaNruaJk+W8gOWQjueahOWJjeWHoOihjOOAgeWJjeWHoOWIl+aIquWbvg0KLSDmlbDmja7lr7zlhaXku6PnoIHvvIjkvb/nlKhgaW1wb3J0KClg5Ye95pWw77yJ5Y+K5a+85YWl5ZCO55qE5pWw5o2u57uT5p6E77yI5L2/55SoYHN0cigpYOWHveaVsO+8ieaIquWbvg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KW+i/lOWbnuivvueoi+S4u+mhtV0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlLykNCg0Kwqkg5YyF5a+S5ZC06ZycDQo=