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


变量计算的总体介绍

【实践1】数据框变量的多种计算方式

  • $操作符:直接赋值⭐️
  • dplyr包:mutate()函数
  • data.table包::=象牙运算符 / let()函数⭐️
  • bruceR包:add()added()函数⭐️
d = data.frame(Var = c("可乐", "雪碧", "咖啡", "茶"))
d
   Var
1 可乐
2 雪碧
3 咖啡
4   茶
## 方式 1:$ 操作符
d$NewVar1 = as.factor(d$Var)
d
   Var NewVar1
1 可乐    可乐
2 雪碧    雪碧
3 咖啡    咖啡
4   茶      茶
str(d)
'data.frame':   4 obs. of  2 variables:
 $ Var    : chr  "可乐" "雪碧" "咖啡" "茶"
 $ NewVar1: Factor w/ 4 levels "茶","咖啡","可乐",..: 3 4 2 1
## 方式 2:mutate() 函数【dplyr包】
d = d %>% mutate(
  NewVar2 = as.factor(Var),
  NewVar3 = as.numeric(NewVar2),
  NewVar4 = as.character(NewVar3)
)
d
   Var NewVar1 NewVar2 NewVar3 NewVar4
1 可乐    可乐    可乐       3       3
2 雪碧    雪碧    雪碧       4       4
3 咖啡    咖啡    咖啡       2       2
4   茶      茶      茶       1       1
str(d)
'data.frame':   4 obs. of  5 variables:
 $ Var    : chr  "可乐" "雪碧" "咖啡" "茶"
 $ NewVar1: Factor w/ 4 levels "茶","咖啡","可乐",..: 3 4 2 1
 $ NewVar2: Factor w/ 4 levels "茶","咖啡","可乐",..: 3 4 2 1
 $ NewVar3: num  3 4 2 1
 $ NewVar4: chr  "3" "4" "2" "1"
## 方式 3:`:=` 象牙运算符 / let() 函数【data.table包】
d = data.table(Var = c("可乐", "雪碧", "咖啡", "茶"))
d
      Var
   <char>
1:   可乐
2:   雪碧
3:   咖啡
4:     茶
d[, NewVar1 := as.factor(Var)]       # 一次只能计算一个变量
d
      Var NewVar1
   <char>  <fctr>
1:   可乐    可乐
2:   雪碧    雪碧
3:   咖啡    咖啡
4:     茶      茶
d[,`:=`(NewVar2 = as.factor(Var))]   # 一次可以计算多个变量
d
      Var NewVar1 NewVar2
   <char>  <fctr>  <fctr>
1:   可乐    可乐    可乐
2:   雪碧    雪碧    雪碧
3:   咖啡    咖啡    咖啡
4:     茶      茶      茶
d[, let(NewVar2 = as.factor(Var))]   # let() 完全等于 `:=`()
d[, let(
  NewVar2 = as.factor(Var),
  NewVar3 = NewVar1 %>% as.numeric(),
  NewVar4 = NewVar1 %>% as.numeric() %>% as.character()
)]
d
      Var NewVar1 NewVar2 NewVar3 NewVar4
   <char>  <fctr>  <fctr>   <num>  <char>
1:   可乐    可乐    可乐       3       3
2:   雪碧    雪碧    雪碧       4       4
3:   咖啡    咖啡    咖啡       2       2
4:     茶      茶      茶       1       1
str(d)
Classes 'data.table' and 'data.frame':  4 obs. of  5 variables:
 $ Var    : chr  "可乐" "雪碧" "咖啡" "茶"
 $ NewVar1: Factor w/ 4 levels "茶","咖啡","可乐",..: 3 4 2 1
 $ NewVar2: Factor w/ 4 levels "茶","咖啡","可乐",..: 3 4 2 1
 $ NewVar3: num  3 4 2 1
 $ NewVar4: chr  "3" "4" "2" "1"
 - attr(*, ".internal.selfref")=<externalptr> 
## 方式(4):add() 与 added() 函数【bruceR包】
d = data.table(Var = c("可乐", "雪碧", "咖啡", "茶"))
dd = d %>% add({                  # add():不改变原数据
  NewVar1 = as.factor(Var)        # 行尾无需逗号
  NewVar2 = as.numeric(NewVar1)   # 新变量可复用
})
dd
      Var NewVar1 NewVar2
   <char>  <fctr>   <num>
1:   可乐    可乐       3
2:   雪碧    雪碧       4
3:   咖啡    咖啡       2
4:     茶      茶       1
d %>% added({                     # added():原地更新数据
  NewVar1 = as.factor(Var)        # 行尾无需逗号
  NewVar2 = as.numeric(NewVar1)   # 新变量可复用
})
d
      Var NewVar1 NewVar2
   <char>  <fctr>   <num>
1:   可乐    可乐       3
2:   雪碧    雪碧       4
3:   咖啡    咖啡       2
4:     茶      茶       1

【实践2】基于data.table的字符串处理和变量计算

d1 = data.table(word=stringr::words[1:10])
d1
        word
      <char>
 1:        a
 2:     able
 3:    about
 4: absolute
 5:   accept
 6:  account
 7:  achieve
 8:   across
 9:      act
10:   active
d1[, let(
  len = nchar(word),
  a_t = str_detect(word, "^a.*t$"),
  new = str_replace_all(word, "c", "_")
)]
d1
        word   len    a_t      new
      <char> <int> <lgcl>   <char>
 1:        a     1  FALSE        a
 2:     able     4  FALSE     able
 3:    about     5   TRUE    about
 4: absolute     8  FALSE absolute
 5:   accept     6   TRUE   a__ept
 6:  account     7   TRUE  a__ount
 7:  achieve     7  FALSE  a_hieve
 8:   across     6  FALSE   a_ross
 9:      act     3   TRUE      a_t
10:   active     6  FALSE   a_tive
d2 = data.table(word=stringr::words[1:10])
d3 = d2 %>% add({
  len = nchar(word)
  a_t = str_detect(word, "^a.*t$")
  new = str_replace_all(word, "c", "_")
})
d3
        word   len    a_t      new
      <char> <int> <lgcl>   <char>
 1:        a     1  FALSE        a
 2:     able     4  FALSE     able
 3:    about     5   TRUE    about
 4: absolute     8  FALSE absolute
 5:   accept     6   TRUE   a__ept
 6:  account     7   TRUE  a__ount
 7:  achieve     7  FALSE  a_hieve
 8:   across     6  FALSE   a_ross
 9:      act     3   TRUE      a_t
10:   active     6  FALSE   a_tive
d2  # add()不改变原数据
        word
      <char>
 1:        a
 2:     able
 3:    about
 4: absolute
 5:   accept
 6:  account
 7:  achieve
 8:   across
 9:      act
10:   active

【知识点】data.table的“浅复制”与“深复制”问题

## 浅复制(=)
d1 = d2 = data.table(word=stringr::words[1:5])
d1[, let(len = nchar(word))]
d1
       word   len
     <char> <int>
1:        a     1
2:     able     4
3:    about     5
4: absolute     8
5:   accept     6
d2  # d2跟着d1一起变了!
       word   len
     <char> <int>
1:        a     1
2:     able     4
3:    about     5
4: absolute     8
5:   accept     6
## 深复制(copy函数)
d1 = data.table(word=stringr::words[1:5])
d2 = copy(d1)  # 完全复制,两者已是不同对象
d1[, let(len = nchar(word))]
d1
       word   len
     <char> <int>
1:        a     1
2:     able     4
3:    about     5
4: absolute     8
5:   accept     6
d2  # d2不会跟着d1一起变
       word
     <char>
1:        a
2:     able
3:    about
4: absolute
5:   accept

变量中心化与标准化

【知识点】变量中心化与标准化

  • 中心化:变量减去均值(mean)
  • 标准化:变量减去均值(mean),再除以标准差(sd)

【实践3】基于data.table的变量中心化与标准化

## 例1
d = data.table(x = seq(0, 100, 10))
d
        x
    <num>
 1:     0
 2:    10
 3:    20
 4:    30
 5:    40
 6:    50
 7:    60
 8:    70
 9:    80
10:    90
11:   100
mean(d$x)
[1] 50
sd(d$x)
[1] 33.17
(d$x - mean(d$x)) / sd(d$x)
 [1] -1.5076 -1.2060 -0.9045 -0.6030 -0.3015  0.0000  0.3015  0.6030  0.9045
[10]  1.2060  1.5076
scale(d$x)
         [,1]
 [1,] -1.5076
 [2,] -1.2060
 [3,] -0.9045
 [4,] -0.6030
 [5,] -0.3015
 [6,]  0.0000
 [7,]  0.3015
 [8,]  0.6030
 [9,]  0.9045
[10,]  1.2060
[11,]  1.5076
attr(,"scaled:center")
[1] 50
attr(,"scaled:scale")
[1] 33.17
added(d, {
  x.c1 = x - mean(x)              # 中心化:手动计算
  x.c2 = scale(x, scale=FALSE)    # 中心化:scale()函数
  x.std1 = (x - mean(x)) / sd(x)  # 标准化:手动计算
  x.std2 = scale(x)               # 标准化:scale()函数
})
d
        x  x.c1  x.c2  x.std1  x.std2
    <num> <num> <num>   <num>   <num>
 1:     0   -50   -50 -1.5076 -1.5076
 2:    10   -40   -40 -1.2060 -1.2060
 3:    20   -30   -30 -0.9045 -0.9045
 4:    30   -20   -20 -0.6030 -0.6030
 5:    40   -10   -10 -0.3015 -0.3015
 6:    50     0     0  0.0000  0.0000
 7:    60    10    10  0.3015  0.3015
 8:    70    20    20  0.6030  0.6030
 9:    80    30    30  0.9045  0.9045
10:    90    40    40  1.2060  1.2060
11:   100    50    50  1.5076  1.5076
str(d)  # 数据结构
Classes 'data.table' and 'data.frame':  11 obs. of  5 variables:
 $ x     : num  0 10 20 30 40 50 60 70 80 90 ...
 $ x.c1  : num  -50 -40 -30 -20 -10 0 10 20 30 40 ...
 $ x.c2  : num  -50 -40 -30 -20 -10 0 10 20 30 40 ...
  ..- attr(*, "scaled:center")= num 50
 $ x.std1: num  -1.508 -1.206 -0.905 -0.603 -0.302 ...
 $ x.std2: num  -1.508 -1.206 -0.905 -0.603 -0.302 ...
  ..- attr(*, "scaled:center")= num 50
  ..- attr(*, "scaled:scale")= num 33.2
 - attr(*, ".internal.selfref")=<externalptr> 
attributes(d$x.c2)
$`scaled:center`
[1] 50
attributes(d$x.std2)
$`scaled:center`
[1] 50

$`scaled:scale`
[1] 33.17
## 例2(使用bruceR包的中心化函数)
d = data.table(x = seq(0, 100, 10),
               y = seq(100, 200, 10))

d1 = grand_mean_center(d)
d1
        x     y
    <num> <num>
 1:   -50   -50
 2:   -40   -40
 3:   -30   -30
 4:   -20   -20
 5:   -10   -10
 6:     0     0
 7:    10    10
 8:    20    20
 9:    30    30
10:    40    40
11:    50    50
d2 = grand_mean_center(
  d,
  vars = c("x", "y"),
  add.suffix = ".c")
d2
        x     y   x.c   y.c
    <num> <num> <num> <num>
 1:     0   100   -50   -50
 2:    10   110   -40   -40
 3:    20   120   -30   -30
 4:    30   130   -20   -20
 5:    40   140   -10   -10
 6:    50   150     0     0
 7:    60   160    10    10
 8:    70   170    20    20
 9:    80   180    30    30
10:    90   190    40    40
11:   100   200    50    50
d3 = grand_mean_center(
  d,
  vars = c("x", "y"),
  std = TRUE,  # 标准化
  add.suffix = ".std")
d3
        x     y   x.std   y.std
    <num> <num>   <num>   <num>
 1:     0   100 -1.5076 -1.5076
 2:    10   110 -1.2060 -1.2060
 3:    20   120 -0.9045 -0.9045
 4:    30   130 -0.6030 -0.6030
 5:    40   140 -0.3015 -0.3015
 6:    50   150  0.0000  0.0000
 7:    60   160  0.3015  0.3015
 8:    70   170  0.6030  0.6030
 9:    80   180  0.9045  0.9045
10:    90   190  1.2060  1.2060
11:   100   200  1.5076  1.5076

总分与平均分的计算

【实践4】计算多变量的总分与平均分

d = data.table(
  x1 = 1:5,
  x4 = c(2,2,5,4,5),
  x3 = c(3,2,NA,NA,5),
  x2 = c(4,4,NA,2,5),
  x5 = c(5,4,1,4,5)
)
d  # d是数据框对象,也是数据框名称,之后需要频繁使用
      x1    x4    x3    x2    x5
   <int> <num> <num> <num> <num>
1:     1     2     3     4     5
2:     2     2     2     4     4
3:     3     5    NA    NA     1
4:     4     4    NA     2     4
5:     5     5     5     5     5
## 大写函数(需要提供数据框名称):SUM()、MEAN()
d1 = add(d, {
  sum = SUM(d, "x", 1:5)    # SUM(data=d, var="x", items=1:5)
  mean = MEAN(d, "x", 1:5)  # MEAN(data=d, var="x", items=1:5)
  mean1 = MEAN(d, vars=c("x1", "x4"))
  mean2 = MEAN(d, varrange="x1:x4")  # 找变量名,而不是从1数到4
  mean3 = MEAN(d, varrange="x1:x3")  # 找变量名,而不是从1数到3
})
d1
      x1    x4    x3    x2    x5   sum  mean mean1 mean2 mean3
   <int> <num> <num> <num> <num> <num> <num> <num> <num> <num>
1:     1     2     3     4     5    15   3.0   1.5   1.5     2
2:     2     2     2     4     4    14   2.8   2.0   2.0     2
3:     3     5    NA    NA     1     9   3.0   4.0   4.0     4
4:     4     4    NA     2     4    14   3.5   4.0   4.0     4
5:     5     5     5     5     5    25   5.0   5.0   5.0     5
## 小写函数(必须搭配add或added使用):.sum()、.mean()
d2 = add(d, {
  sum = .sum("x", 1:5)
  mean = .mean("x", 1:5)
})
d2
      x1    x4    x3    x2    x5   sum  mean
   <int> <num> <num> <num> <num> <num> <num>
1:     1     2     3     4     5    15   3.0
2:     2     2     2     4     4    14   2.8
3:     3     5    NA    NA     1     9   3.0
4:     4     4    NA     2     4    14   3.5
5:     5     5     5     5     5    25   5.0

【实践5】题目序号在变量名中间的特殊情况

  • var变量名共同部分中,以大括号{i}占位题目序号
d = data.table(
  XX.1.pre = 1:5,
  XX.2.pre = 6:10,
  XX.3.pre = 11:15
)
d
   XX.1.pre XX.2.pre XX.3.pre
      <int>    <int>    <int>
1:        1        6       11
2:        2        7       12
3:        3        8       13
4:        4        9       14
5:        5       10       15
add(d, {
  XX.mean = .mean("XX.{i}.pre", 1:3)
})
   XX.1.pre XX.2.pre XX.3.pre XX.mean
      <int>    <int>    <int>   <num>
1:        1        6       11       6
2:        2        7       12       7
3:        3        8       13       8
4:        4        9       14       9
5:        5       10       15      10
# 相同效果
add(d, {
  XX.mean = .mean("XX.{items}.pre", 1:3)
})
   XX.1.pre XX.2.pre XX.3.pre XX.mean
      <int>    <int>    <int>   <num>
1:        1        6       11       6
2:        2        7       12       7
3:        3        8       13       8
4:        4        9       14       9
5:        5       10       15      10

反向计分与重新编码

【实践6】大五人格问卷BFI各维度平均分计算

  • 大五人格维度
    • Extraversion(外倾性)
    • Agreeableness(宜人性)
    • Conscientiousness(尽责性)
    • Neuroticism(神经质/情绪性)
    • Openness(开放性)
d.bfi = as.data.table(psych::bfi)
str(d.bfi)
Classes 'data.table' and 'data.frame':  2800 obs. of  28 variables:
 $ A1       : int  2 2 5 4 2 6 2 4 4 2 ...
 $ A2       : int  4 4 4 4 3 6 5 3 3 5 ...
 $ A3       : int  3 5 5 6 3 5 5 1 6 6 ...
 $ A4       : int  4 2 4 5 4 6 3 5 3 6 ...
 $ A5       : int  4 5 4 5 5 5 5 1 3 5 ...
 $ C1       : int  2 5 4 4 4 6 5 3 6 6 ...
 $ C2       : int  3 4 5 4 4 6 4 2 6 5 ...
 $ C3       : int  3 4 4 3 5 6 4 4 3 6 ...
 $ C4       : int  4 3 2 5 3 1 2 2 4 2 ...
 $ C5       : int  4 4 5 5 2 3 3 4 5 1 ...
 $ E1       : int  3 1 2 5 2 2 4 3 5 2 ...
 $ E2       : int  3 1 4 3 2 1 3 6 3 2 ...
 $ E3       : int  3 6 4 4 5 6 4 4 NA 4 ...
 $ E4       : int  4 4 4 4 4 5 5 2 4 5 ...
 $ E5       : int  4 3 5 4 5 6 5 1 3 5 ...
 $ N1       : int  3 3 4 2 2 3 1 6 5 5 ...
 $ N2       : int  4 3 5 5 3 5 2 3 5 5 ...
 $ N3       : int  2 3 4 2 4 2 2 2 2 5 ...
 $ N4       : int  2 5 2 4 4 2 1 6 3 2 ...
 $ N5       : int  3 5 3 1 3 3 1 4 3 4 ...
 $ O1       : int  3 4 4 3 3 4 5 3 6 5 ...
 $ O2       : int  6 2 2 3 3 3 2 2 6 1 ...
 $ O3       : int  3 4 5 4 4 5 5 4 6 5 ...
 $ O4       : int  4 3 5 3 3 6 6 5 6 5 ...
 $ O5       : int  3 3 2 5 3 1 1 3 1 2 ...
 $ gender   : int  1 2 2 2 1 2 1 1 1 2 ...
 $ education: int  NA NA NA NA NA 3 NA 2 1 NA ...
 $ age      : int  16 18 17 17 17 21 18 19 19 17 ...
 - attr(*, ".internal.selfref")=<externalptr> 
added(d.bfi, {
  age = age
  gender = factor(gender, levels=1:2, labels=c("Male", "Female"))
  education = as.factor(education)
  E = .mean("E", 1:5, rev=c(1,2), range=1:6)
  A = .mean("A", 1:5, rev=1, range=1:6)
  C = .mean("C", 1:5, rev=c(4,5), range=1:6)
  N = .mean("N", 1:5, rev=NULL, range=1:6)
  O = .mean("O", 1:5, rev=c(2,5), range=1:6)
}, drop=TRUE)  # 删去原有变量,只保留新变量
d.bfi
      gender education   age     E     A     C     N     O
      <fctr>    <fctr> <int> <num> <num> <num> <num> <num>
   1:   Male      <NA>    16   3.8   4.0   2.8  2.80   3.0
   2: Female      <NA>    18   5.0   4.2   4.0  3.80   4.0
   3: Female      <NA>    17   4.2   3.8   4.0  3.60   4.8
   4: Female      <NA>    17   3.6   4.6   3.0  2.80   3.2
   5:   Male      <NA>    17   4.8   4.0   4.4  3.20   3.6
  ---                                                     
2796:   Male         3    19   5.0   2.2   6.0  1.00   6.0
2797:   Male         4    27   4.2   4.2   3.2  2.75   4.8
2798: Female         4    29   5.0   4.0   5.4  2.80   5.0
2799:   Male         4    31   4.6   2.8   4.2  4.20   5.2
2800: Female         4    50   2.6   3.0   4.2  1.40   4.6
str(d.bfi)
Classes 'data.table' and 'data.frame':  2800 obs. of  8 variables:
 $ gender   : Factor w/ 2 levels "Male","Female": 1 2 2 2 1 2 1 1 1 2 ...
 $ education: Factor w/ 5 levels "1","2","3","4",..: NA NA NA NA NA 3 NA 2 1 NA ...
 $ age      : int  16 18 17 17 17 21 18 19 19 17 ...
 $ E        : num  3.8 5 4.2 3.6 4.8 5.6 4.2 2.4 3.25 4.8 ...
 $ A        : num  4 4.2 3.8 4.6 4 4.6 4.6 2.6 3.6 5.4 ...
 $ C        : num  2.8 4 4 3 4.4 5.6 4.4 3.4 4 5.6 ...
 $ N        : num  2.8 3.8 3.6 2.8 3.2 3 1.4 4.2 3.6 4.2 ...
 $ O        : num  3 4 4.8 3.2 3.6 5 5.4 4.2 5 5.2 ...
 - attr(*, ".internal.selfref")=<externalptr> 

【作业6】期末作业数据变量计算

作业要求:

  • 基于【作业4】的期末自选公开数据,运用本章所学的变量计算方法,对数据变量进行计算和预处理
    • 请使用data.table数据对象类型(而不是data.frame
    • 可选用data.table包的let()函数或bruceR包的add()added()函数计算变量
  • 使用R Markdown完成

平台提交:

  • 运行得到的HTML网页,及其关键部分截图
LS0tDQp0aXRsZTogIuOAilLor63oqIDjgIvnrKw156ug77ya5Y+Y6YeP6K6h566XIg0Kc3VidGl0bGU6IDxhIGhyZWY9Imh0dHBzOi8vcHN5Y2hicnVjZS5naXRodWIuaW8vUkNvdXJzZS8iPui/lOWbnuivvueoi+S4u+mhtTwvYT4NCmF1dGhvcjogIuaOiOivvuaVmeW4iO+8muWMheWvkuWQtOmcnCINCiMgZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IGZhbHNlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGFuY2hvcl9zZWN0aW9uczogdHJ1ZQ0KICAgIGhpZ2hsaWdodDogcHlnbWVudHMNCiAgICBjc3M6IFJtZENTUy5jc3MNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8cCBzdHlsZT0iZm9udC1zaXplOiAxMnB4Ij7niYjmnYPlo7DmmI7vvJrmnKzlpZfor77nqIvmnZDmlpnlvIDmupDvvIzkvb/nlKjlkozliIbkuqvlv4XpobvpgbXlrojjgIzliJvkvZzlhbHnlKjorrjlj6/ljY/orq4gQ0MgQlktTkMtU0HjgI3vvIjmnaXmupDlvJXnlKgt6Z2e5ZWG5Lia55So6YCU5L2/55SoLeS7peebuOWQjOaWueW8j+WFseS6q++8ieOAgjxpbWcgc3JjPSJpbWcvQ0MtQlktTkMtU0EuanBnIiB3aWR0aD0iMTIwcHgiIGhlaWdodD0iNDJweCIgc3R5bGU9ImZsb2F0OiByaWdodCIgLz48L3A+DQpgYGANCg0KYGBge3IgQ29uZmlnLCBpbmNsdWRlPUZBTFNFfQ0Kb3B0aW9ucygNCiAga25pdHIua2FibGUuTkEgPSAiIiwNCiAgZGlnaXRzID0gNA0KKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiIsDQogIGZpZy53aWR0aCA9IDYsDQogIGZpZy5oZWlnaHQgPSA0LA0KICBkcGkgPSAzMDANCikNCmBgYA0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBDaGFwMDXvvJrlj5jph4/orqHnrpcNCg0KIyMjIyDlvoDmnJ/opoHngrnlm57pob4NCg0KLSAgIFtDaGFwMDMgXCMg5pWw5o2u5qGG77yIZGF0YSBmcmFtZe+8iV0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlL0NoYXAwMyMlRTYlOTUlQjAlRTYlOEQlQUUlRTYlQTElODZkYXRhLWZyYW1lKXsudXJpfQ0KLSAgIFtDaGFwMDQgXCMg5a2X56ym5Liy5aSE55CG5a6e5oiYXShodHRwczovL3BzeWNoYnJ1Y2UuZ2l0aHViLmlvL1JDb3Vyc2UvQ2hhcDA0IyVFNSVBRCU5NyVFNyVBQyVBNiVFNCVCOCVCMiVFNSVBNCU4NCVFNyU5MCU4NiVFNSVBRSU5RSVFNiU4OCU5OCl7LnVyaX0NCg0KIyMjIyDmnKznq6DopoHngrnnm67lvZUNCg0KLSAgIFvjgJDlrp7ot7Ux44CR5pWw5o2u5qGG5Y+Y6YeP55qE5aSa56eN6K6h566X5pa55byPXSgj5a6e6Le1MeaVsOaNruahhuWPmOmHj+eahOWkmuenjeiuoeeul+aWueW8jykNCi0gICBb44CQ5a6e6Le1MuOAkeWfuuS6jmRhdGEudGFibGXnmoTlrZfnrKbkuLLlpITnkIblkozlj5jph4/orqHnrpddKCPlrp7ot7Uy5Z+65LqOZGF0YS50YWJsZeeahOWtl+espuS4suWkhOeQhuWSjOWPmOmHj+iuoeeulynvvIjph43ngrnvvIkNCi0gICBb44CQ55+l6K+G54K544CRZGF0YS50YWJsZeeahOKAnOa1heWkjeWItuKAneS4juKAnOa3seWkjeWItuKAnemXrumimF0oI+efpeivhueCuWRhdGEudGFibGXnmoTmtYXlpI3liLbkuI7mt7HlpI3liLbpl67popgpDQotICAgW+OAkOefpeivhueCueOAkeWPmOmHj+S4reW/g+WMluS4juagh+WHhuWMll0oI+efpeivhueCueWPmOmHj+S4reW/g+WMluS4juagh+WHhuWMlikNCi0gICBb44CQ5a6e6Le1M+OAkeWfuuS6jmRhdGEudGFibGXnmoTlj5jph4/kuK3lv4PljJbkuI7moIflh4bljJZdKCPlrp7ot7Uz5Z+65LqOZGF0YS50YWJsZeeahOWPmOmHj+S4reW/g+WMluS4juagh+WHhuWMlikNCi0gICBb44CQ5a6e6Le1NOOAkeiuoeeul+WkmuWPmOmHj+eahOaAu+WIhuS4juW5s+Wdh+WIhl0oI+Wunui3tTTorqHnrpflpJrlj5jph4/nmoTmgLvliIbkuI7lubPlnYfliIYp77yI6YeN54K577yJDQotICAgW+OAkOWunui3tTXjgJHpopjnm67luo/lj7flnKjlj5jph4/lkI3kuK3pl7TnmoTnibnmrormg4XlhrVdKCPlrp7ot7U16aKY55uu5bqP5Y+35Zyo5Y+Y6YeP5ZCN5Lit6Ze055qE54m55q6K5oOF5Ya1KQ0KLSAgIFvjgJDlrp7ot7U244CR5aSn5LqU5Lq65qC86Zeu5Y23QkZJ5ZCE57u05bqm5bmz5Z2H5YiG6K6h566XXSgj5a6e6Le1NuWkp+S6lOS6uuagvOmXruWNt2JmaeWQhOe7tOW6puW5s+Wdh+WIhuiuoeeulynvvIjph43ngrnvvIkNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyDmnKznq6DmiYDpnIBS5YyFDQpsaWJyYXJ5KGJydWNlUikNCiMgbGlicmFyeShkcGx5cikgICAgICAgIyDliqDovb1icnVjZVLml7blt7Lpu5jorqTliqDovb1kcGx5cg0KIyBsaWJyYXJ5KGRhdGEudGFibGUpICAjIOWKoOi9vWJydWNlUuaXtuW3sum7mOiupOWKoOi9vWRhdGEudGFibGUNCmBgYA0KDQojIOWPmOmHj+iuoeeul+eahOaAu+S9k+S7i+e7jQ0KDQojIyMjIOOAkOWunui3tTHjgJHmlbDmja7moYblj5jph4/nmoTlpJrnp43orqHnrpfmlrnlvI8geyPlrp7ot7Ux5pWw5o2u5qGG5Y+Y6YeP55qE5aSa56eN6K6h566X5pa55byPfQ0KDQotICAgYCRg5pON5L2c56ym77ya55u05o6l6LWL5YC84q2Q77iPDQotICAgYGRwbHlyYOWMhe+8mmBtdXRhdGUoKWDlh73mlbANCi0gICBgZGF0YS50YWJsZWDljIXvvJpgOj1g6LGh54mZ6L+Q566X56ymIC8gYGxldCgpYOWHveaVsOKtkO+4jw0KLSAgIGBicnVjZVJg5YyF77yaYGFkZCgpYOS4jmBhZGRlZCgpYOWHveaVsOKtkO+4jw0KDQpgYGB7cn0NCmQgPSBkYXRhLmZyYW1lKFZhciA9IGMoIuWPr+S5kCIsICLpm6rnoqciLCAi5ZKW5ZWhIiwgIuiMtiIpKQ0KZA0KDQojIyDmlrnlvI8gMe+8miQg5pON5L2c56ymDQpkJE5ld1ZhcjEgPSBhcy5mYWN0b3IoZCRWYXIpDQpkDQpzdHIoZCkNCg0KIyMg5pa55byPIDLvvJptdXRhdGUoKSDlh73mlbDjgJBkcGx5cuWMheOAkQ0KZCA9IGQgJT4lIG11dGF0ZSgNCiAgTmV3VmFyMiA9IGFzLmZhY3RvcihWYXIpLA0KICBOZXdWYXIzID0gYXMubnVtZXJpYyhOZXdWYXIyKSwNCiAgTmV3VmFyNCA9IGFzLmNoYXJhY3RlcihOZXdWYXIzKQ0KKQ0KZA0Kc3RyKGQpDQoNCiMjIOaWueW8jyAz77yaYDo9YCDosaHniZnov5DnrpfnrKYgLyBsZXQoKSDlh73mlbDjgJBkYXRhLnRhYmxl5YyF44CRDQpkID0gZGF0YS50YWJsZShWYXIgPSBjKCLlj6/kuZAiLCAi6Zuq56KnIiwgIuWSluWVoSIsICLojLYiKSkNCmQNCmRbLCBOZXdWYXIxIDo9IGFzLmZhY3RvcihWYXIpXSAgICAgICAjIOS4gOasoeWPquiDveiuoeeul+S4gOS4quWPmOmHjw0KZA0KZFssYDo9YChOZXdWYXIyID0gYXMuZmFjdG9yKFZhcikpXSAgICMg5LiA5qyh5Y+v5Lul6K6h566X5aSa5Liq5Y+Y6YePDQpkDQpkWywgbGV0KE5ld1ZhcjIgPSBhcy5mYWN0b3IoVmFyKSldICAgIyBsZXQoKSDlrozlhajnrYnkuo4gYDo9YCgpDQpkWywgbGV0KA0KICBOZXdWYXIyID0gYXMuZmFjdG9yKFZhciksDQogIE5ld1ZhcjMgPSBOZXdWYXIxICU+JSBhcy5udW1lcmljKCksDQogIE5ld1ZhcjQgPSBOZXdWYXIxICU+JSBhcy5udW1lcmljKCkgJT4lIGFzLmNoYXJhY3RlcigpDQopXQ0KZA0Kc3RyKGQpDQoNCiMjIOaWueW8jyg0Ke+8mmFkZCgpIOS4jiBhZGRlZCgpIOWHveaVsOOAkGJydWNlUuWMheOAkQ0KZCA9IGRhdGEudGFibGUoVmFyID0gYygi5Y+v5LmQIiwgIumbqueipyIsICLlkpbllaEiLCAi6Iy2IikpDQpkZCA9IGQgJT4lIGFkZCh7ICAgICAgICAgICAgICAgICAgIyBhZGQoKe+8muS4jeaUueWPmOWOn+aVsOaNrg0KICBOZXdWYXIxID0gYXMuZmFjdG9yKFZhcikgICAgICAgICMg6KGM5bC+5peg6ZyA6YCX5Y+3DQogIE5ld1ZhcjIgPSBhcy5udW1lcmljKE5ld1ZhcjEpICAgIyDmlrDlj5jph4/lj6/lpI3nlKgNCn0pDQpkZA0KZCAlPiUgYWRkZWQoeyAgICAgICAgICAgICAgICAgICAgICMgYWRkZWQoKe+8muWOn+WcsOabtOaWsOaVsOaNrg0KICBOZXdWYXIxID0gYXMuZmFjdG9yKFZhcikgICAgICAgICMg6KGM5bC+5peg6ZyA6YCX5Y+3DQogIE5ld1ZhcjIgPSBhcy5udW1lcmljKE5ld1ZhcjEpICAgIyDmlrDlj5jph4/lj6/lpI3nlKgNCn0pDQpkDQpgYGANCg0KIyMjIyDjgJDlrp7ot7Uy44CR5Z+65LqOZGF0YS50YWJsZeeahOWtl+espuS4suWkhOeQhuWSjOWPmOmHj+iuoeeulyB7I+Wunui3tTLln7rkuo5kYXRhLnRhYmxl55qE5a2X56ym5Liy5aSE55CG5ZKM5Y+Y6YeP6K6h566XfQ0KDQpgYGB7cn0NCmQxID0gZGF0YS50YWJsZSh3b3JkPXN0cmluZ3I6OndvcmRzWzE6MTBdKQ0KZDENCg0KZDFbLCBsZXQoDQogIGxlbiA9IG5jaGFyKHdvcmQpLA0KICBhX3QgPSBzdHJfZGV0ZWN0KHdvcmQsICJeYS4qdCQiKSwNCiAgbmV3ID0gc3RyX3JlcGxhY2VfYWxsKHdvcmQsICJjIiwgIl8iKQ0KKV0NCmQxDQoNCmQyID0gZGF0YS50YWJsZSh3b3JkPXN0cmluZ3I6OndvcmRzWzE6MTBdKQ0KZDMgPSBkMiAlPiUgYWRkKHsNCiAgbGVuID0gbmNoYXIod29yZCkNCiAgYV90ID0gc3RyX2RldGVjdCh3b3JkLCAiXmEuKnQkIikNCiAgbmV3ID0gc3RyX3JlcGxhY2VfYWxsKHdvcmQsICJjIiwgIl8iKQ0KfSkNCmQzDQpkMiAgIyBhZGQoKeS4jeaUueWPmOWOn+aVsOaNrg0KYGBgDQoNCiMjIyMg44CQ55+l6K+G54K544CRZGF0YS50YWJsZeeahOKAnOa1heWkjeWItuKAneS4juKAnOa3seWkjeWItuKAnemXrumimCB7I+efpeivhueCuWRhdGEudGFibGXnmoTmtYXlpI3liLbkuI7mt7HlpI3liLbpl67poph9DQoNCiFbXShpbWFnZXMvY2xpcGJvYXJkLTIwNDk0ODUyMjIucG5nKQ0KDQpgYGB7cn0NCiMjIOa1heWkjeWItu+8iD3vvIkNCmQxID0gZDIgPSBkYXRhLnRhYmxlKHdvcmQ9c3RyaW5ncjo6d29yZHNbMTo1XSkNCmQxWywgbGV0KGxlbiA9IG5jaGFyKHdvcmQpKV0NCmQxDQpkMiAgIyBkMui3n+edgGQx5LiA6LW35Y+Y5LqG77yBDQoNCiMjIOa3seWkjeWItu+8iGNvcHnlh73mlbDvvIkNCmQxID0gZGF0YS50YWJsZSh3b3JkPXN0cmluZ3I6OndvcmRzWzE6NV0pDQpkMiA9IGNvcHkoZDEpICAjIOWujOWFqOWkjeWItu+8jOS4pOiAheW3suaYr+S4jeWQjOWvueixoQ0KZDFbLCBsZXQobGVuID0gbmNoYXIod29yZCkpXQ0KZDENCmQyICAjIGQy5LiN5Lya6Lef552AZDHkuIDotbflj5gNCmBgYA0KDQojIOWPmOmHj+S4reW/g+WMluS4juagh+WHhuWMlg0KDQojIyMjIOOAkOefpeivhueCueOAkeWPmOmHj+S4reW/g+WMluS4juagh+WHhuWMliB7I+efpeivhueCueWPmOmHj+S4reW/g+WMluS4juagh+WHhuWMln0NCg0KLSAgIOS4reW/g+WMlu+8muWPmOmHj+WHj+WOu+Wdh+WAvO+8iG1lYW7vvIkNCi0gICDmoIflh4bljJbvvJrlj5jph4/lh4/ljrvlnYflgLzvvIhtZWFu77yJ77yM5YaN6Zmk5Lul5qCH5YeG5beu77yIc2TvvIkNCg0KIyMjIyDjgJDlrp7ot7Uz44CR5Z+65LqOZGF0YS50YWJsZeeahOWPmOmHj+S4reW/g+WMluS4juagh+WHhuWMliB7I+Wunui3tTPln7rkuo5kYXRhLnRhYmxl55qE5Y+Y6YeP5Lit5b+D5YyW5LiO5qCH5YeG5YyWfQ0KDQpgYGB7cn0NCiMjIOS+izENCmQgPSBkYXRhLnRhYmxlKHggPSBzZXEoMCwgMTAwLCAxMCkpDQpkDQoNCm1lYW4oZCR4KQ0Kc2QoZCR4KQ0KKGQkeCAtIG1lYW4oZCR4KSkgLyBzZChkJHgpDQpzY2FsZShkJHgpDQoNCmFkZGVkKGQsIHsNCiAgeC5jMSA9IHggLSBtZWFuKHgpICAgICAgICAgICAgICAjIOS4reW/g+WMlu+8muaJi+WKqOiuoeeulw0KICB4LmMyID0gc2NhbGUoeCwgc2NhbGU9RkFMU0UpICAgICMg5Lit5b+D5YyW77yac2NhbGUoKeWHveaVsA0KICB4LnN0ZDEgPSAoeCAtIG1lYW4oeCkpIC8gc2QoeCkgICMg5qCH5YeG5YyW77ya5omL5Yqo6K6h566XDQogIHguc3RkMiA9IHNjYWxlKHgpICAgICAgICAgICAgICAgIyDmoIflh4bljJbvvJpzY2FsZSgp5Ye95pWwDQp9KQ0KZA0KDQpzdHIoZCkgICMg5pWw5o2u57uT5p6EDQphdHRyaWJ1dGVzKGQkeC5jMikNCmF0dHJpYnV0ZXMoZCR4LnN0ZDIpDQpgYGANCg0KYGBge3J9DQojIyDkvosy77yI5L2/55SoYnJ1Y2VS5YyF55qE5Lit5b+D5YyW5Ye95pWw77yJDQpkID0gZGF0YS50YWJsZSh4ID0gc2VxKDAsIDEwMCwgMTApLA0KICAgICAgICAgICAgICAgeSA9IHNlcSgxMDAsIDIwMCwgMTApKQ0KDQpkMSA9IGdyYW5kX21lYW5fY2VudGVyKGQpDQpkMQ0KDQpkMiA9IGdyYW5kX21lYW5fY2VudGVyKA0KICBkLA0KICB2YXJzID0gYygieCIsICJ5IiksDQogIGFkZC5zdWZmaXggPSAiLmMiKQ0KZDINCg0KZDMgPSBncmFuZF9tZWFuX2NlbnRlcigNCiAgZCwNCiAgdmFycyA9IGMoIngiLCAieSIpLA0KICBzdGQgPSBUUlVFLCAgIyDmoIflh4bljJYNCiAgYWRkLnN1ZmZpeCA9ICIuc3RkIikNCmQzDQpgYGANCg0KIyDmgLvliIbkuI7lubPlnYfliIbnmoTorqHnrpcNCg0KIVtdKGltYWdlcy9jbGlwYm9hcmQtMzA5NjIzNTg1My5wbmcpDQoNCiMjIyMg44CQ5a6e6Le1NOOAkeiuoeeul+WkmuWPmOmHj+eahOaAu+WIhuS4juW5s+Wdh+WIhiB7I+Wunui3tTTorqHnrpflpJrlj5jph4/nmoTmgLvliIbkuI7lubPlnYfliIZ9DQoNCmBgYHtyfQ0KZCA9IGRhdGEudGFibGUoDQogIHgxID0gMTo1LA0KICB4NCA9IGMoMiwyLDUsNCw1KSwNCiAgeDMgPSBjKDMsMixOQSxOQSw1KSwNCiAgeDIgPSBjKDQsNCxOQSwyLDUpLA0KICB4NSA9IGMoNSw0LDEsNCw1KQ0KKQ0KZCAgIyBk5piv5pWw5o2u5qGG5a+56LGh77yM5Lmf5piv5pWw5o2u5qGG5ZCN56ew77yM5LmL5ZCO6ZyA6KaB6aKR57mB5L2/55SoDQoNCiMjIOWkp+WGmeWHveaVsO+8iOmcgOimgeaPkOS+m+aVsOaNruahhuWQjeensO+8ie+8mlNVTSgp44CBTUVBTigpDQpkMSA9IGFkZChkLCB7DQogIHN1bSA9IFNVTShkLCAieCIsIDE6NSkgICAgIyBTVU0oZGF0YT1kLCB2YXI9IngiLCBpdGVtcz0xOjUpDQogIG1lYW4gPSBNRUFOKGQsICJ4IiwgMTo1KSAgIyBNRUFOKGRhdGE9ZCwgdmFyPSJ4IiwgaXRlbXM9MTo1KQ0KICBtZWFuMSA9IE1FQU4oZCwgdmFycz1jKCJ4MSIsICJ4NCIpKQ0KICBtZWFuMiA9IE1FQU4oZCwgdmFycmFuZ2U9IngxOng0IikgICMg5om+5Y+Y6YeP5ZCN77yM6ICM5LiN5piv5LuOMeaVsOWIsDQNCiAgbWVhbjMgPSBNRUFOKGQsIHZhcnJhbmdlPSJ4MTp4MyIpICAjIOaJvuWPmOmHj+WQje+8jOiAjOS4jeaYr+S7jjHmlbDliLAzDQp9KQ0KZDENCg0KIyMg5bCP5YaZ5Ye95pWw77yI5b+F6aG75pCt6YWNYWRk5oiWYWRkZWTkvb/nlKjvvInvvJouc3VtKCnjgIEubWVhbigpDQpkMiA9IGFkZChkLCB7DQogIHN1bSA9IC5zdW0oIngiLCAxOjUpDQogIG1lYW4gPSAubWVhbigieCIsIDE6NSkNCn0pDQpkMg0KYGBgDQoNCiMjIyMg44CQ5a6e6Le1NeOAkemimOebruW6j+WPt+WcqOWPmOmHj+WQjeS4remXtOeahOeJueauiuaDheWGtSB7I+Wunui3tTXpopjnm67luo/lj7flnKjlj5jph4/lkI3kuK3pl7TnmoTnibnmrormg4XlhrV9DQoNCi0gICDlnKhgdmFyYOWPmOmHj+WQjeWFseWQjOmDqOWIhuS4re+8jOS7peWkp+aLrOWPt2B7aX1g5Y2g5L2N6aKY55uu5bqP5Y+3DQoNCmBgYHtyfQ0KZCA9IGRhdGEudGFibGUoDQogIFhYLjEucHJlID0gMTo1LA0KICBYWC4yLnByZSA9IDY6MTAsDQogIFhYLjMucHJlID0gMTE6MTUNCikNCmQNCg0KYWRkKGQsIHsNCiAgWFgubWVhbiA9IC5tZWFuKCJYWC57aX0ucHJlIiwgMTozKQ0KfSkNCg0KIyDnm7jlkIzmlYjmnpwNCmFkZChkLCB7DQogIFhYLm1lYW4gPSAubWVhbigiWFgue2l0ZW1zfS5wcmUiLCAxOjMpDQp9KQ0KYGBgDQoNCiMg5Y+N5ZCR6K6h5YiG5LiO6YeN5paw57yW56CBDQoNCiMjIyMg44CQ5a6e6Le1NuOAkeWkp+S6lOS6uuagvOmXruWNt0JGSeWQhOe7tOW6puW5s+Wdh+WIhuiuoeeulyB7I+Wunui3tTblpKfkupTkurrmoLzpl67ljbdiZmnlkITnu7TluqblubPlnYfliIborqHnrpd9DQoNCi0gICDlpKfkupTkurrmoLznu7TluqYNCiAgICAtICAgRXh0cmF2ZXJzaW9u77yI5aSW5YC+5oCn77yJDQogICAgLSAgIEFncmVlYWJsZW5lc3PvvIjlrpzkurrmgKfvvIkNCiAgICAtICAgQ29uc2NpZW50aW91c25lc3PvvIjlsL3otKPmgKfvvIkNCiAgICAtICAgTmV1cm90aWNpc23vvIjnpZ7nu4/otKgv5oOF57uq5oCn77yJDQogICAgLSAgIE9wZW5uZXNz77yI5byA5pS+5oCn77yJDQoNCmBgYHtyfQ0KZC5iZmkgPSBhcy5kYXRhLnRhYmxlKHBzeWNoOjpiZmkpDQpzdHIoZC5iZmkpDQoNCmFkZGVkKGQuYmZpLCB7DQogIGFnZSA9IGFnZQ0KICBnZW5kZXIgPSBmYWN0b3IoZ2VuZGVyLCBsZXZlbHM9MToyLCBsYWJlbHM9YygiTWFsZSIsICJGZW1hbGUiKSkNCiAgZWR1Y2F0aW9uID0gYXMuZmFjdG9yKGVkdWNhdGlvbikNCiAgRSA9IC5tZWFuKCJFIiwgMTo1LCByZXY9YygxLDIpLCByYW5nZT0xOjYpDQogIEEgPSAubWVhbigiQSIsIDE6NSwgcmV2PTEsIHJhbmdlPTE6NikNCiAgQyA9IC5tZWFuKCJDIiwgMTo1LCByZXY9Yyg0LDUpLCByYW5nZT0xOjYpDQogIE4gPSAubWVhbigiTiIsIDE6NSwgcmV2PU5VTEwsIHJhbmdlPTE6NikNCiAgTyA9IC5tZWFuKCJPIiwgMTo1LCByZXY9YygyLDUpLCByYW5nZT0xOjYpDQp9LCBkcm9wPVRSVUUpICAjIOWIoOWOu+WOn+acieWPmOmHj++8jOWPquS/neeVmeaWsOWPmOmHjw0KZC5iZmkNCnN0cihkLmJmaSkNCmBgYA0KDQojIOOAkOS9nOS4mjbjgJHmnJ/mnKvkvZzkuJrmlbDmja7lj5jph4/orqHnrpcNCg0K5L2c5Lia6KaB5rGC77yaDQoNCi0gICDln7rkuo5b44CQ5L2c5LiaNOOAkV0oaHR0cHM6Ly9wc3ljaGJydWNlLmdpdGh1Yi5pby9SQ291cnNlL0NoYXAwMyMlRTQlQkQlOUMlRTQlQjglOUE0JUU2JTlDJTlGJUU2JTlDJUFCJUU4JTg3JUFBJUU5JTgwJTg5JUU1JTg1JUFDJUU1JUJDJTgwJUU2JTk1JUIwJUU2JThEJUFFJUU1JUFGJUJDJUU1JTg1JUE1KeeahOacn+acq+iHqumAieWFrOW8gOaVsOaNru+8jOi/kOeUqOacrOeroOaJgOWtpueahOWPmOmHj+iuoeeul+aWueazle+8jOWvueaVsOaNruWPmOmHj+i/m+ihjOiuoeeul+WSjOmihOWkhOeQhg0KICAgIC0gICDor7fkvb/nlKhgZGF0YS50YWJsZWDmlbDmja7lr7nosaHnsbvlnovvvIjogIzkuI3mmK9gZGF0YS5mcmFtZWDvvIkNCiAgICAtICAg5Y+v6YCJ55SoYGRhdGEudGFibGVg5YyF55qEYGxldCgpYOWHveaVsOaIlmBicnVjZVJg5YyF55qEYGFkZCgpYOOAgWBhZGRlZCgpYOWHveaVsOiuoeeul+WPmOmHjw0KLSAgIOS9v+eUqFIgTWFya2Rvd27lrozmiJANCg0K5bmz5Y+w5o+Q5Lqk77yaDQoNCi0gICDov5DooYzlvpfliLDnmoRIVE1M572R6aG177yM5Y+K5YW25YWz6ZSu6YOo5YiG5oiq5Zu+DQo=