R 中的日期-时间和因子一样,是一种特殊的变量。

基础包

  • 获取系统日期:Sys.Date()
  • 获取系统时间:Sys.time()

Format:将日期时间对象转换为字符串

format(date, format = ...)

(m = Sys.Date())
#> [1] "2023-11-14"
class(m)
#> [1] "Date"
format(m, format = "%B %d %Y") # 改成月日年的格式
#> [1] "November 14 2023"
format(m, format = "%B %d %Y %A")  # 加入星期信息
#> [1] "November 14 2023 Tuesday"
format(m, format = "%B")  # 只提取出月份信息
#> [1] "November"
format(Sys.time(), format = "%Y/%B/%a %H:%M:%S")  # 提取部分时间信息
#> [1] "2023/November/Tue 11:25:49"

Parse:将字符串解析为日期时间对象

  • strptime(chr_datetime, format = ...)
  • readr::parse_*(chr_datetime, format = ...)
# R 原生日期-时间类型
strptime("20/2/06", format = "%d/%m/%y")
#> [1] "2006-02-20 CST"
strptime("20/2/06", format = "%d/%m/%y") %>% class() 
#> [1] "POSIXlt" "POSIXt"
# tidyverse 系列的 Date 类型
readr::parse_date("20/2/06", format = "%d/%m/%y")
#> [1] "2006-02-20"
readr::parse_date("20/2/06", format = "%d/%m/%y") %>% class()
#> [1] "Date"

lubricate 包

lubridate cheatsheet.pdf

表示日期或时间的数据有 3 种类型:
- 日期:在 tibble 中显示为<date>
- 时间:一天中的某个时刻,在 tibble 中显示为<time>
- 日期时间:可以唯一标识某个时刻(通常精确到秒)的日期加时间,在 tibble 中显示为<dttm>

要想得到当前日期或当前日期时间,你可以使用 today()now() 函数:

today()
#> [1] "2023-11-14"
now()
#> [1] "2023-11-14 11:30:17 CST"

创建日期或时间

通过字符串创建

ymd()系列函数是从字符串创建单个日期时间对象的最简方法,也可以接受不带引号的数值。它不需要指定参数,便能自动处理标点和月份、星期的英文全称、缩写。

x = c(20090101, "2009-01-02", "2009 01 03", "2009-1-4", "2009-1,5", "Created on 2009 1 6", "200901 !!! 07")
ymd(x)
#> [1] "2009-01-01" "2009-01-02" "2009-01-03" "2009-01-04" "2009-01-05"
#> [6] "2009-01-06" "2009-01-07"
class(x)
#> [1] "character"
mdy("January 31st, 2017")
#> [1] "2017-01-31"
dmy("31-Jan-2017")
#> [1] "2017-01-31"
ymd(20170131)
#> [1] "2017-01-31"
ymd_hms("2017-01-31 20:11:59") # 精确到秒的时间戳
#> [1] "2017-01-31 20:11:59 UTC"
mdy_hm("01/31/2017 08:01")
#> [1] "2017-01-31 08:01:00 UTC"
# 通过添加一个时区参数,可以将一个日期强制转换为日期时间:
ymd(20170131, tz = "UTC")
#> [1] "2017-01-31 UTC"

通过各个成分创建

使用 make_date() 函数创建日期,使用 make_datetime() 函数创建日期时间

flights %>% 
  select(year, month, day, hour, minute) %>% 
  mutate(
    departure = make_datetime(year, month, day, hour, minute)
  )
#> # A tibble: 336,776 × 6
#>     year month   day  hour minute departure          
#>    <int> <int> <int> <dbl>  <dbl> <dttm>             
#>  1  2013     1     1     5     15 2013-01-01 05:15:00
#>  2  2013     1     1     5     29 2013-01-01 05:29:00
#>  3  2013     1     1     5     40 2013-01-01 05:40:00
#>  4  2013     1     1     5     45 2013-01-01 05:45:00
#>  5  2013     1     1     6      0 2013-01-01 06:00:00
#>  6  2013     1     1     5     58 2013-01-01 05:58:00
#>  7  2013     1     1     6      0 2013-01-01 06:00:00
#>  8  2013     1     1     6      0 2013-01-01 06:00:00
#>  9  2013     1     1     6      0 2013-01-01 06:00:00
#> 10  2013     1     1     6      0 2013-01-01 06:00:00
#> # ℹ 336,766 more rows
## flights 数据集中的某些时间是将小时和分钟数简单地排列在一起的,需要将其分离

# 自定义分离函数
make_datetime_100 <- function(year, month, day, time) {
  make_datetime(year, month, day, time %/% 100, time %% 100)
}

# 应用分离函数
flights_dt <- flights %>% 
  filter(!is.na(dep_time), !is.na(arr_time)) %>% 
  mutate(
    dep_time = make_datetime_100(year, month, day, dep_time),
    arr_time = make_datetime_100(year, month, day, arr_time),
    sched_dep_time = make_datetime_100(year, month, day, sched_dep_time),
    sched_arr_time = make_datetime_100(year, month, day, sched_arr_time)) %>% 
  select(origin, dest, ends_with("delay"), ends_with("time"))

flights_dt
#> # A tibble: 328,063 × 9
#>    origin dest  dep_delay arr_delay dep_time            sched_dep_time     
#>    <chr>  <chr>     <dbl>     <dbl> <dttm>              <dttm>             
#>  1 EWR    IAH           2        11 2013-01-01 05:17:00 2013-01-01 05:15:00
#>  2 LGA    IAH           4        20 2013-01-01 05:33:00 2013-01-01 05:29:00
#>  3 JFK    MIA           2        33 2013-01-01 05:42:00 2013-01-01 05:40:00
#>  4 JFK    BQN          -1       -18 2013-01-01 05:44:00 2013-01-01 05:45:00
#>  5 LGA    ATL          -6       -25 2013-01-01 05:54:00 2013-01-01 06:00:00
#>  6 EWR    ORD          -4        12 2013-01-01 05:54:00 2013-01-01 05:58:00
#>  7 EWR    FLL          -5        19 2013-01-01 05:55:00 2013-01-01 06:00:00
#>  8 LGA    IAD          -3       -14 2013-01-01 05:57:00 2013-01-01 06:00:00
#>  9 JFK    MCO          -3        -8 2013-01-01 05:57:00 2013-01-01 06:00:00
#> 10 LGA    ORD          -2         8 2013-01-01 05:58:00 2013-01-01 06:00:00
#> # ℹ 328,053 more rows
#> # ℹ 3 more variables: arr_time <dttm>, sched_arr_time <dttm>, air_time <dbl>
# 以天为宽度汇总起飞航班的频数
flights_dt %>% 
  ggplot(aes(dep_time)) + 
  geom_freqpoly(binwidth = 86400) 

# 86400秒 = 1天,由于横轴是日期时间型数据,1代表1秒

# 以10分钟为宽度,汇总2013年1月1日起飞航班的频数
flights_dt %>% 
  filter(dep_time < ymd(20130102)) %>% 
  ggplot(aes(dep_time)) + 
  geom_freqpoly(binwidth = 600) # 600秒 = 10分钟

通过其他数据类型创建

as_datetime()as_date() 在日期和日期时间型数据之间切换

as_datetime(today())
#> [1] "2023-11-14 UTC"
as_date(now())
#> [1] "2023-11-14"

可以用相对偏移量表示时间,基准为1970年1月1日0时。

as_date(365 * 10 + 2) # 基准时间之后10年,考虑到两个闰年加两天
#> [1] "1980-01-01"
as_datetime(60 * 60 * 10) # 基准时间滞后10个小时
#> [1] "1970-01-01 10:00:00 UTC"

日期和时间成分

获取成分

如果想要提取出日期中的独立成分,可以使用以下访问器函数: year()、 month()、 mday()(一个月中的第几天)、 yday()(一年中的第几天)、 wday()(一周中的第几天)、 hour()、minute() 和 second():

datetime <- ymd_hms("2016-07-08 12:34:56")
year(datetime)
#> [1] 2016
month(datetime)
#> [1] 7
mday(datetime)
#> [1] 8
yday(datetime)
#> [1] 190
wday(datetime)
#> [1] 6

对于 month() 和 wday() 函数,你可以设置 label = TRUE 来返回月份名称和星期数的缩写,还可以设置 abbr = FALSE 来返回全名:

# 注意,lubridate中的这两个函数会被data.table包的同名函数覆盖
# 因此,用到这个功能的时候,不能用data.table包
lubridate::month(datetime, label = TRUE)
#> [1] Jul
#> 12 Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < Sep < ... < Dec
lubridate::wday(datetime, label = TRUE, abbr = FALSE)
#> [1] Friday
#> 7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday

应用于flights数据:

flights_dt %>% 
  mutate(wday = lubridate::wday(dep_time, label = TRUE)) %>% 
  ggplot(aes(x = wday)) + geom_bar()

# 查看一小时内每分钟的平均出发延误
flights_dt %>% 
  mutate(minute = minute(dep_time)) %>% 
  group_by(minute) %>% 
  summarize(avg_delay = mean(arr_delay, na.rm = TRUE), 
            n = n()) %>% 
  ggplot(aes(minute, avg_delay)) + 
  geom_line()

# 我们发现,似乎在第20~30分钟和第50~60分钟内出发的航班的延误时间远远低于其他时间出发的航班

舍入

通过 floor_date()、 round_date() 和 ceiling_date() 函数将日期舍入到临近的一个时间单位。

flights_dt %>% 
  count(week = floor_date(dep_time, "week")) %>% 
  ggplot(aes(week, n)) + geom_line()

修改成分

(datetime <- ymd_hms("2016-07-08 12:34:56"))
#> [1] "2016-07-08 12:34:56 UTC"
year(datetime) <- 2020
datetime
#> [1] "2020-07-08 12:34:56 UTC"
month(datetime) <- 01
datetime
#> [1] "2020-01-08 12:34:56 UTC"
hour(datetime) <- hour(datetime) + 1

除了原地修改,你还可以通过 update() 函数创建一个新日期时间,这样也可以同时设置多个成分。如果设置的值过大,那么可以自动向后滚动。

update(datetime, year = 2020, month = 2, mday = 2, hour = 2)
#> [1] "2020-02-02 02:34:56 UTC"
ymd("2015-02-01") %>% update(mday = 30) # 2月没有30号,所以从1号开始往后推30天
#> [1] "2015-03-02"
ymd("2015-02-01") %>% update(hour = 400)
#> [1] "2015-02-17 16:00:00 UTC"
flights_dt %>% 
  mutate(dep_hour = update(dep_time, yday = 1)) %>% 
  ggplot(aes(dep_hour)) + 
  geom_freqpoly(binwidth = 300)

时间间隔

difftime 类型

time_length <- today() - ymd(19791014)
time_length
#> Time difference of 16102 days
class(time_length)
#> [1] "difftime"
# 基础包的difftime()函数
difftime(today(), ymd(19791014)) 
#> Time difference of 16102 days
difftime(today(), ymd(19791014), units = 'weeks') 
#> Time difference of 2300.286 weeks
difftime(today(), ymd(19791014), units = 'hours') 
#> Time difference of 386448 hours

时期 duration (统一单位为秒

用difftime数据类型构造duration

# Hadley多大了?
as.duration(today() - ymd(19791014))
#> [1] "1391212800s (~44.08 years)"

构造时期的系列函数(都有”d”前缀和”s”后缀):

dseconds(15)
#> [1] "15s"
dminutes(10)
#> [1] "600s (~10 minutes)"
dhours(c(12, 24))
#> [1] "43200s (~12 hours)" "86400s (~1 days)"
ddays(0:5)
#> [1] "0s"                "86400s (~1 days)"  "172800s (~2 days)"
#> [4] "259200s (~3 days)" "345600s (~4 days)" "432000s (~5 days)"
dweeks(3)
#> [1] "1814400s (~3 weeks)"
dyears(1)
#> [1] "31557600s (~1 years)"

可以对duration进行加法和乘法操作,时期也可以与日期型数据相加或相减,仍然得到日期型:

dyears(1) + dweeks(12) + dhours(15)
#> [1] "38869200s (~1.23 years)"
tomorrow <- today() + ddays(1)
class(tomorrow)
#> [1] "Date"
last_year <- today() - dyears(1)
class(last_year)
#> [1] "POSIXct" "POSIXt"

阶段

lubridate 提供了阶段对象。阶段也是一种时间间隔,但它不以秒为单位;相反,它使用”人工”时间,比如日和月,这使得它们使用起来更加直观。

构造阶段的系列函数(只有”s”后缀):

seconds(15)
#> [1] "15S"
minutes(10)
#> [1] "10M 0S"
hours(c(12, 24))
#> [1] "12H 0M 0S" "24H 0M 0S"
days(7)
#> [1] "7d 0H 0M 0S"
months(1:6)
#> [1] "1m 0d 0H 0M 0S" "2m 0d 0H 0M 0S" "3m 0d 0H 0M 0S" "4m 0d 0H 0M 0S"
#> [5] "5m 0d 0H 0M 0S" "6m 0d 0H 0M 0S"
weeks(3)
#> [1] "21d 0H 0M 0S"
years(1)
#> [1] "1y 0m 0d 0H 0M 0S"

可以对阶段进行加法和乘法操作:

10 * (months(6) + days(1))
#> [1] "60m 10d 0H 0M 0S"
days(50) + hours(25) + minutes(2)
#> [1] "50d 25H 2M 0S"

阶段可以和日期相加。与时期相比,阶段更容易符合我们的预期,因为它自动考虑了历法的种种规则

## 闰年问题
ymd("2016-01-01") + dyears(1) # dyears()产生的时期只是简单地加了365天
#> [1] "2016-12-31 06:00:00 UTC"
ymd("2016-01-01") + years(1) # 考虑到2016年为闰年,years()产生的阶段加了366天
#> [1] "2017-01-01"

区间

阶段的一年years(1)到底是365天还是366天是不确定的,因此有了新的类:区间。区间是带有起点的时期,这使得你可以确切地知道它的长度。

next_year <- today() + years(1)
next_year
#> [1] "2024-11-14"
(today() %--% next_year) / ddays(1)
#> [1] 366

总结

如果只关心物理时间,那么就使用时期;如果还需要考虑人工时间,那么就使用阶段;如果需要找出人工时间范围内有多长的时间间隔,那么就使用区间。

时区

为了避免混淆, R 使用国际标准 IANA 时区。这些时区使用统一带有”/“的命名方式,一般的形式为”< 大陆 >/< 城市 >“(存在例外,因为不是所有城市都位于一块大陆)。如”America/New_York”、“Europe/Paris”和”Pacific/Auckland”。之所以使用城市名,是因为IANA 数据库必须记录十年间的时区,而在十年时间中,国家更名(或分裂)的情况非常多,但城市名是基本保持不变的。

Sys.timezone() 函数找出你的当前时区。OlsonNames() 函数来查看完整的时区名称列表。

Sys.timezone()
#> [1] "Asia/Shanghai"
head(OlsonNames())
#> [1] "Africa/Abidjan"     "Africa/Accra"       "Africa/Addis_Ababa"
#> [4] "Africa/Algiers"     "Africa/Asmara"      "Africa/Asmera"

在 R 中,时区是日期时间型数据的一个属性,仅用于控制输出。例如,以下 3 个对象表示的是同一时刻:

(x1 <- ymd_hms("2015-06-01 12:00:00", 
               tz = "America/New_York"));
#> [1] "2015-06-01 12:00:00 EDT"
(x2 <- ymd_hms("2015-06-01 18:00:00", tz = "Europe/Copenhagen"));
#> [1] "2015-06-01 18:00:00 CEST"
(x3 <- ymd_hms("2015-06-02 04:00:00", 
               tz = "Pacific/Auckland"));
#> [1] "2015-06-02 04:00:00 NZST"
x4 <- c(x1, x2, x3)
x4
#> [1] "2015-06-01 12:00:00 EDT" "2015-06-01 12:00:00 EDT"
#> [3] "2015-06-01 12:00:00 EDT"
x4a <- with_tz(x4, tzone = "Asia/Taipei")
x4a
#> [1] "2015-06-02 CST" "2015-06-02 CST" "2015-06-02 CST"
x4b <- force_tz(x4, tzone = "Asia/Taipei")
x4b
#> [1] "2015-06-01 12:00:00 CST" "2015-06-01 12:00:00 CST"
#> [3] "2015-06-01 12:00:00 CST"
LS0tDQp0aXRsZTogIkRhdGUiDQpzdWJ0aXRsZTogJycNCmF1dGhvcjogIkh1bW9vbiINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNzczogWyIuLi9jc3Mvc3R5bGUuY3NzIl0NCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIGhpZ2hsaWdodDogaGFkZG9jaw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogeWVzDQogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCmRvY3VtZW50Y2xhc3M6IGN0ZXhhcnQNCmNsYXNzb3B0aW9uOiBoeXBlcnJlZiwNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQ0KIyMgZ2xvYmFsIG9wdGlvbnMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCmNvbmZpZyA8LSBsaXN0KA0KICAgIHdpZHRoID0gODAsDQogICAgZmlnLndpZHRoID0gNiwNCiAgICBmaWcuYXNwID0gMC42MTgsDQogICAgb3V0LndpZHRoID0gIjkwJSIsDQogICAgZmlnLmFsaWduID0gImNlbnRlciIsDQogICAgZmlnLnBhdGggPSAiLi4vaW1nLyIsDQogICAgZmlnLnNob3cgPSAiYXNpcyIsDQogICAgd2FybiA9IDEsICMg5by65Yi25Zyo6K2m5ZGK5Lqn55Sf55qE5ZCM5pe26L6T5Ye66K2m5ZGK5L+h5oGv77yM54S25ZCO5omN6L6T5Ye66L+Q6KGM57uT5p6cLiB3YXJuID0gMiDkvJrlsIborablkYrop4bkuLrplJnor6/vvIzkuK3mraLnqIvluo8NCiAgICB3YXJuaW5nID0gVFJVRSwNCiAgICBtZXNzYWdlID0gVFJVRSwNCiAgICBlY2hvID0gVFJVRSwgIyDmmK/lkKbmmL7npLrku6PnoIENCiAgICBldmFsID0gVFJVRSwgIyDmmK/lkKbov5DooYzku6PnoIHlnZcNCiAgICB0aWR5ID0gRiwgIyDku6PnoIHmjpLniYgNCiAgICBjb21tZW50ID0gIiM+IiwgIyDmr4/ooYzovpPlh7rnmoTliY3nvIDvvIzkuLrkuobmlrnkvr/lpI3liLbnspjotLTml7bkuI3kvJrmsaHmn5Pku6PnoIENCiAgICBjb2xsYXBzZSA9IEYsICMg5Luj56CB5LiO57uT5p6c5piv5ZCm5pi+56S65Zyo5ZCM5LiA5Luj56CB5Z2X77yM6YCJIEZBTFNFIOWPr+mBv+WFjeaJk+WNsOWbvuW9ouWQju+8jOWQjOS4gOS7o+eggeWdl+S4reWQjumdoueahOihjOiiq+iQveWcqOWdl+Wklg0KICAgIGNhY2hlID0gVCwgIyDku6PnoIHlnZfov5DooYznu5PmnpznvJPlrZgNCiAgICBjYWNoZS5jb21tZW50cyA9IFQsDQogICAgYXV0b2RlcCA9IFQgIyDoh6rliqjojrflvpfmqKHlnZfpl7Tkvp3otZbvvIxjYWNoZSDnlKgNCikNCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICB3aWR0aCA9IGNvbmZpZyR3aWR0aCwNCiAgZmlnLndpZHRoID0gY29uZmlnJGZpZy53aWR0aCwNCiAgZmlnLmFzcCA9IGNvbmZpZyRmaWcuYXNwLA0KICBvdXQud2lkdGggPSBjb25maWckb3V0LndpZHRoLA0KICBmaWcuYWxpZ24gPSBjb25maWckZmlnLmFsaWduLA0KICBmaWcucGF0aCA9IGNvbmZpZyRmaWcucGF0aCwNCiAgZmlnLnNob3cgPSBjb25maWckZmlnLnNob3csDQogIHdhcm4gPSBjb25maWckd2FybiwNCiAgd2FybmluZyA9IGNvbmZpZyR3YXJuaW5nLA0KICBtZXNzYWdlID0gY29uZmlnJG1lc3NhZ2UsDQogIGVjaG8gPSBjb25maWckZWNobywgDQogIGV2YWwgPSBjb25maWckZXZhbCwgDQogIHRpZHkgPSBjb25maWckdGlkeSwgDQogIGNvbW1lbnQgPSBjb25maWckY29tbWVudCwgDQogIGNvbGxhcHNlID0gY29uZmlnJGNvbGxhcHNlLCANCiAgY2FjaGUgPSBjb25maWckY2FjaGUsDQogIGNhY2hlLmNvbW1lbnRzID0gY29uZmlnJGNhY2hlLmNvbW1lbnRzLA0KICBhdXRvZGVwID0gY29uZmlnJGF1dG9kZXANCikNCg0KIyMgaW1wb3J0IG1vZHVsZXMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoYnJ1Y2VSKQ0KbGlicmFyeShtYWdyaXR0cikNCmxpYnJhcnkoa2FibGVFeHRyYSkgIyDooajmoLznvo7ljJYNCmxpYnJhcnkocGxvdGx5KSAjIOe7mOWbvg0KbGlicmFyeShodG1sd2lkZ2V0cykNCmxpYnJhcnkoZG93bmxvYWR0aGlzKSAjIOaPkOS+m+i1hOa6kOS4i+i9veeahGh0bWzpg6jku7YNCmxpYnJhcnkoemVhbGxvdCkgIyDop6PmnoTotYvlgLwNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShueWNmbGlnaHRzMTMpDQpsaWJyYXJ5KGhtcykNCmBgYA0KDQoqKlIg5Lit55qE5pel5pyfLeaXtumXtOWSjOWboOWtkOS4gOagt++8jOaYr+S4gOenjeeJueauiueahOWPmOmHj+OAgioqDQoNCiMjIOWfuuehgOWMhQ0KDQotICAg6I635Y+W57O757uf5pel5pyf77yaYFN5cy5EYXRlKClgDQotICAg6I635Y+W57O757uf5pe26Ze077yaYFN5cy50aW1lKClgDQoNCiMjIyBGb3JtYXTvvJrlsIbml6XmnJ/ml7bpl7Tlr7nosaHovazmjaLkuLrlrZfnrKbkuLINCg0KYGZvcm1hdChkYXRlLCBmb3JtYXQgPSAuLi4pYA0KDQpgYGB7cn0NCihtID0gU3lzLkRhdGUoKSkNCmNsYXNzKG0pDQoNCmZvcm1hdChtLCBmb3JtYXQgPSAiJUIgJWQgJVkiKSAjIOaUueaIkOaciOaXpeW5tOeahOagvOW8jw0KZm9ybWF0KG0sIGZvcm1hdCA9ICIlQiAlZCAlWSAlQSIpICAjIOWKoOWFpeaYn+acn+S/oeaBrw0KZm9ybWF0KG0sIGZvcm1hdCA9ICIlQiIpICAjIOWPquaPkOWPluWHuuaciOS7veS/oeaBrw0KZm9ybWF0KFN5cy50aW1lKCksIGZvcm1hdCA9ICIlWS8lQi8lYSAlSDolTTolUyIpICAjIOaPkOWPlumDqOWIhuaXtumXtOS/oeaBrw0KYGBgDQoNCiMjIyBQYXJzZe+8muWwhuWtl+espuS4suino+aekOS4uuaXpeacn+aXtumXtOWvueixoQ0KDQotICAgYHN0cnB0aW1lKGNocl9kYXRldGltZSwgZm9ybWF0ID0gLi4uKWANCi0gICBgcmVhZHI6OnBhcnNlXyooY2hyX2RhdGV0aW1lLCBmb3JtYXQgPSAuLi4pYA0KDQpgYGB7cn0NCiMgUiDljp/nlJ/ml6XmnJ8t5pe26Ze057G75Z6LDQpzdHJwdGltZSgiMjAvMi8wNiIsIGZvcm1hdCA9ICIlZC8lbS8leSIpDQpzdHJwdGltZSgiMjAvMi8wNiIsIGZvcm1hdCA9ICIlZC8lbS8leSIpICU+JSBjbGFzcygpIA0KDQojIHRpZHl2ZXJzZSDns7vliJfnmoQgRGF0ZSDnsbvlnosNCnJlYWRyOjpwYXJzZV9kYXRlKCIyMC8yLzA2IiwgZm9ybWF0ID0gIiVkLyVtLyV5IikNCnJlYWRyOjpwYXJzZV9kYXRlKCIyMC8yLzA2IiwgZm9ybWF0ID0gIiVkLyVtLyV5IikgJT4lIGNsYXNzKCkNCmBgYA0KDQojIyBsdWJyaWNhdGUg5YyFDQoNCjxhIGhyZWY9Ii4uL3BkZi9jaGVhdHNoZWV0LWx1YnJpZGF0ZS5wZGYiPjxzdHJvbmc+bHVicmlkYXRlIGNoZWF0c2hlZXQucGRmPC9zdHJvbmc+PC9hPg0KDQo8b2JqZWN0IGRhdGE9Ii4uL3BkZi9jaGVhdHNoZWV0LWx1YnJpZGF0ZS5wZGYiIHR5cGU9ImFwcGxpY2F0aW9uL3BkZiIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSI+DQoNCjwvb2JqZWN0Pg0KDQrooajnpLrml6XmnJ/miJbml7bpl7TnmoTmlbDmja7mnIkgMyDnp43nsbvlnovvvJpcDQotIOaXpeacn++8muWcqCB0aWJibGUg5Lit5pi+56S65Li6YDxkYXRlPmBcDQotIOaXtumXtO+8muS4gOWkqeS4reeahOafkOS4quaXtuWIu++8jOWcqCB0aWJibGUg5Lit5pi+56S65Li6YDx0aW1lPmBcDQotIOaXpeacn+aXtumXtO+8muWPr+S7peWUr+S4gOagh+ivhuafkOS4quaXtuWIu++8iOmAmuW4uOeyvuehruWIsOenku+8ieeahOaXpeacn+WKoOaXtumXtO+8jOWcqCB0aWJibGUg5Lit5pi+56S65Li6YDxkdHRtPmANCg0K6KaB5oOz5b6X5Yiw5b2T5YmN5pel5pyf5oiW5b2T5YmN5pel5pyf5pe26Ze077yM5L2g5Y+v5Lul5L2/55SoIGB0b2RheSgpYCDmiJYgYG5vdygpYCDlh73mlbDvvJoNCg0KYGBge3J9DQp0b2RheSgpDQpub3coKQ0KYGBgDQoNCiMjIyDliJvlu7rml6XmnJ/miJbml7bpl7QNCg0KIyMjIyDpgJrov4flrZfnrKbkuLLliJvlu7oNCg0KYHltZCgpYCoq57O75YiX5Ye95pWwKirmmK/ku47lrZfnrKbkuLLliJvlu7rljZXkuKrml6XmnJ/ml7bpl7Tlr7nosaHnmoTmnIDnroDmlrnms5XvvIzkuZ/lj6/ku6XmjqXlj5fkuI3luKblvJXlj7fnmoTmlbDlgLzjgILlroPkuI3pnIDopoHmjIflrprlj4LmlbDvvIzkvr/og73oh6rliqjlpITnkIbmoIfngrnlkozmnIjku73jgIHmmJ/mnJ/nmoToi7Hmloflhajnp7DjgIHnvKnlhpnjgIINCg0KYGBge3J9DQp4ID0gYygyMDA5MDEwMSwgIjIwMDktMDEtMDIiLCAiMjAwOSAwMSAwMyIsICIyMDA5LTEtNCIsICIyMDA5LTEsNSIsICJDcmVhdGVkIG9uIDIwMDkgMSA2IiwgIjIwMDkwMSAhISEgMDciKQ0KeW1kKHgpDQpjbGFzcyh4KQ0KbWR5KCJKYW51YXJ5IDMxc3QsIDIwMTciKQ0KZG15KCIzMS1KYW4tMjAxNyIpDQp5bWQoMjAxNzAxMzEpDQp5bWRfaG1zKCIyMDE3LTAxLTMxIDIwOjExOjU5IikgIyDnsr7noa7liLDnp5LnmoTml7bpl7TmiLMNCm1keV9obSgiMDEvMzEvMjAxNyAwODowMSIpDQoNCiMg6YCa6L+H5re75Yqg5LiA5Liq5pe25Yy65Y+C5pWw77yM5Y+v5Lul5bCG5LiA5Liq5pel5pyf5by65Yi26L2s5o2i5Li65pel5pyf5pe26Ze077yaDQp5bWQoMjAxNzAxMzEsIHR6ID0gIlVUQyIpDQpgYGANCg0KIyMjIyDpgJrov4flkITkuKrmiJDliIbliJvlu7oNCg0K5L2/55SoIGBtYWtlX2RhdGUoKWAg5Ye95pWw5Yib5bu65pel5pyf77yM5L2/55SoIGBtYWtlX2RhdGV0aW1lKClgIOWHveaVsOWIm+W7uuaXpeacn+aXtumXtA0KDQpgYGB7cn0NCmZsaWdodHMgJT4lIA0KICBzZWxlY3QoeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlKSAlPiUgDQogIG11dGF0ZSgNCiAgICBkZXBhcnR1cmUgPSBtYWtlX2RhdGV0aW1lKHllYXIsIG1vbnRoLCBkYXksIGhvdXIsIG1pbnV0ZSkNCiAgKQ0KDQojIyBmbGlnaHRzIOaVsOaNrumbhuS4reeahOafkOS6m+aXtumXtOaYr+WwhuWwj+aXtuWSjOWIhumSn+aVsOeugOWNleWcsOaOkuWIl+WcqOS4gOi1t+eahO+8jOmcgOimgeWwhuWFtuWIhuemuw0KDQojIOiHquWumuS5ieWIhuemu+WHveaVsA0KbWFrZV9kYXRldGltZV8xMDAgPC0gZnVuY3Rpb24oeWVhciwgbW9udGgsIGRheSwgdGltZSkgew0KICBtYWtlX2RhdGV0aW1lKHllYXIsIG1vbnRoLCBkYXksIHRpbWUgJS8lIDEwMCwgdGltZSAlJSAxMDApDQp9DQoNCiMg5bqU55So5YiG56a75Ye95pWwDQpmbGlnaHRzX2R0IDwtIGZsaWdodHMgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKGRlcF90aW1lKSwgIWlzLm5hKGFycl90aW1lKSkgJT4lIA0KICBtdXRhdGUoDQogICAgZGVwX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBkZXBfdGltZSksDQogICAgYXJyX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBhcnJfdGltZSksDQogICAgc2NoZWRfZGVwX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBzY2hlZF9kZXBfdGltZSksDQogICAgc2NoZWRfYXJyX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBzY2hlZF9hcnJfdGltZSkpICU+JSANCiAgc2VsZWN0KG9yaWdpbiwgZGVzdCwgZW5kc193aXRoKCJkZWxheSIpLCBlbmRzX3dpdGgoInRpbWUiKSkNCg0KZmxpZ2h0c19kdA0KDQojIOS7peWkqeS4uuWuveW6puaxh+aAu+i1t+mjnuiIquePreeahOmikeaVsA0KZmxpZ2h0c19kdCAlPiUgDQogIGdncGxvdChhZXMoZGVwX3RpbWUpKSArIA0KICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gODY0MDApIA0KIyA4NjQwMOenkiA9IDHlpKnvvIznlLHkuo7mqKrovbTmmK/ml6XmnJ/ml7bpl7TlnovmlbDmja7vvIwx5Luj6KGoMeenkg0KDQojIOS7pTEw5YiG6ZKf5Li65a695bqm77yM5rGH5oC7MjAxM+W5tDHmnIgx5pel6LW36aOe6Iiq54+t55qE6aKR5pWwDQpmbGlnaHRzX2R0ICU+JSANCiAgZmlsdGVyKGRlcF90aW1lIDwgeW1kKDIwMTMwMTAyKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKGRlcF90aW1lKSkgKyANCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDYwMCkgIyA2MDDnp5IgPSAxMOWIhumSnw0KYGBgDQoNCiMjIyMg6YCa6L+H5YW25LuW5pWw5o2u57G75Z6L5Yib5bu6DQoNCmBhc19kYXRldGltZSgpYCDlkowgYGFzX2RhdGUoKWAg5Zyo5pel5pyf5ZKM5pel5pyf5pe26Ze05Z6L5pWw5o2u5LmL6Ze05YiH5o2iDQoNCmBgYHtyfQ0KYXNfZGF0ZXRpbWUodG9kYXkoKSkNCmFzX2RhdGUobm93KCkpDQpgYGANCg0KKirlj6/ku6XnlKjnm7jlr7nlgY/np7vph4/ooajnpLrml7bpl7TvvIzln7rlh4bkuLoxOTcw5bm0MeaciDHml6Uw5pe244CCKioNCg0KYGBge3J9DQphc19kYXRlKDM2NSAqIDEwICsgMikgIyDln7rlh4bml7bpl7TkuYvlkI4xMOW5tO+8jOiAg+iZkeWIsOS4pOS4qumXsOW5tOWKoOS4pOWkqQ0KYXNfZGF0ZXRpbWUoNjAgKiA2MCAqIDEwKSAjIOWfuuWHhuaXtumXtOa7nuWQjjEw5Liq5bCP5pe2DQpgYGANCg0KIyMjIOaXpeacn+WSjOaXtumXtOaIkOWIhg0KDQojIyMjIOiOt+WPluaIkOWIhg0KDQrlpoLmnpzmg7PopoHmj5Dlj5blh7rml6XmnJ/kuK3nmoTni6znq4vmiJDliIbvvIzlj6/ku6Xkvb/nlKjku6XkuIvorr/pl67lmajlh73mlbDvvJogeWVhcigp44CBIG1vbnRoKCnjgIEgbWRheSgp77yI5LiA5Liq5pyI5Lit55qE56ys5Yeg5aSp77yJ44CBIHlkYXkoKe+8iOS4gOW5tOS4reeahOesrOWHoOWkqe+8ieOAgSB3ZGF5KCnvvIjkuIDlkajkuK3nmoTnrKzlh6DlpKnvvInjgIEgaG91cigp44CBbWludXRlKCkg5ZKMIHNlY29uZCgp77yaDQoNCmBgYHtyfQ0KZGF0ZXRpbWUgPC0geW1kX2htcygiMjAxNi0wNy0wOCAxMjozNDo1NiIpDQp5ZWFyKGRhdGV0aW1lKQ0KbW9udGgoZGF0ZXRpbWUpDQptZGF5KGRhdGV0aW1lKQ0KeWRheShkYXRldGltZSkNCndkYXkoZGF0ZXRpbWUpDQpgYGANCg0K5a+55LqOIG1vbnRoKCkg5ZKMIHdkYXkoKSDlh73mlbDvvIzkvaDlj6/ku6Xorr7nva4gbGFiZWwgPSBUUlVFIOadpei/lOWbnuaciOS7veWQjeensOWSjOaYn+acn+aVsOeahOe8qeWGme+8jOi/mOWPr+S7peiuvue9riBhYmJyID0gRkFMU0Ug5p2l6L+U5Zue5YWo5ZCN77yaDQoNCmBgYHtyfQ0KIyDms6jmhI/vvIxsdWJyaWRhdGXkuK3nmoTov5nkuKTkuKrlh73mlbDkvJrooqtkYXRhLnRhYmxl5YyF55qE5ZCM5ZCN5Ye95pWw6KaG55uWDQojIOWboOatpO+8jOeUqOWIsOi/meS4quWKn+iDveeahOaXtuWAme+8jOS4jeiDveeUqGRhdGEudGFibGXljIUNCmx1YnJpZGF0ZTo6bW9udGgoZGF0ZXRpbWUsIGxhYmVsID0gVFJVRSkNCmx1YnJpZGF0ZTo6d2RheShkYXRldGltZSwgbGFiZWwgPSBUUlVFLCBhYmJyID0gRkFMU0UpDQpgYGANCg0K5bqU55So5LqOZmxpZ2h0c+aVsOaNru+8mg0KDQpgYGB7cn0NCmZsaWdodHNfZHQgJT4lIA0KICBtdXRhdGUod2RheSA9IGx1YnJpZGF0ZTo6d2RheShkZXBfdGltZSwgbGFiZWwgPSBUUlVFKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSB3ZGF5KSkgKyBnZW9tX2JhcigpDQoNCiMg5p+l55yL5LiA5bCP5pe25YaF5q+P5YiG6ZKf55qE5bmz5Z2H5Ye65Y+R5bu26K+vDQpmbGlnaHRzX2R0ICU+JSANCiAgbXV0YXRlKG1pbnV0ZSA9IG1pbnV0ZShkZXBfdGltZSkpICU+JSANCiAgZ3JvdXBfYnkobWludXRlKSAlPiUgDQogIHN1bW1hcml6ZShhdmdfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSwgDQogICAgICAgICAgICBuID0gbigpKSAlPiUgDQogIGdncGxvdChhZXMobWludXRlLCBhdmdfZGVsYXkpKSArIA0KICBnZW9tX2xpbmUoKQ0KIyDmiJHku6zlj5HnjrDvvIzkvLzkuY7lnKjnrKwyMH4zMOWIhumSn+WSjOesrDUwfjYw5YiG6ZKf5YaF5Ye65Y+R55qE6Iiq54+t55qE5bu26K+v5pe26Ze06L+c6L+c5L2O5LqO5YW25LuW5pe26Ze05Ye65Y+R55qE6Iiq54+tDQpgYGANCg0KIyMjIyDoiI3lhaUNCg0K6YCa6L+HIGZsb29yX2RhdGUoKeOAgSByb3VuZF9kYXRlKCkg5ZKMIGNlaWxpbmdfZGF0ZSgpIOWHveaVsOWwhuaXpeacn+iIjeWFpeWIsOS4tOi/keeahOS4gOS4quaXtumXtOWNleS9jeOAgg0KDQpgYGB7cn0NCmZsaWdodHNfZHQgJT4lIA0KICBjb3VudCh3ZWVrID0gZmxvb3JfZGF0ZShkZXBfdGltZSwgIndlZWsiKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHdlZWssIG4pKSArIGdlb21fbGluZSgpDQpgYGANCg0KIyMjIyDkv67mlLnmiJDliIYNCg0KYGBge3J9DQooZGF0ZXRpbWUgPC0geW1kX2htcygiMjAxNi0wNy0wOCAxMjozNDo1NiIpKQ0KeWVhcihkYXRldGltZSkgPC0gMjAyMA0KZGF0ZXRpbWUNCm1vbnRoKGRhdGV0aW1lKSA8LSAwMQ0KZGF0ZXRpbWUNCmhvdXIoZGF0ZXRpbWUpIDwtIGhvdXIoZGF0ZXRpbWUpICsgMQ0KYGBgDQoNCumZpOS6huWOn+WcsOS/ruaUue+8jOS9oOi/mOWPr+S7pemAmui/hyB1cGRhdGUoKSDlh73mlbDliJvlu7rkuIDkuKrmlrDml6XmnJ/ml7bpl7TvvIzov5nmoLfkuZ/lj6/ku6XlkIzml7borr7nva7lpJrkuKrmiJDliIbjgILlpoLmnpzorr7nva7nmoTlgLzov4flpKfvvIzpgqPkuYjlj6/ku6Xoh6rliqjlkJHlkI7mu5rliqjjgIINCg0KYGBge3J9DQp1cGRhdGUoZGF0ZXRpbWUsIHllYXIgPSAyMDIwLCBtb250aCA9IDIsIG1kYXkgPSAyLCBob3VyID0gMikNCg0KeW1kKCIyMDE1LTAyLTAxIikgJT4lIHVwZGF0ZShtZGF5ID0gMzApICMgMuaciOayoeaciTMw5Y+377yM5omA5Lul5LuOMeWPt+W8gOWni+W+gOWQjuaOqDMw5aSpDQp5bWQoIjIwMTUtMDItMDEiKSAlPiUgdXBkYXRlKGhvdXIgPSA0MDApDQoNCmZsaWdodHNfZHQgJT4lIA0KICBtdXRhdGUoZGVwX2hvdXIgPSB1cGRhdGUoZGVwX3RpbWUsIHlkYXkgPSAxKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKGRlcF9ob3VyKSkgKyANCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDMwMCkNCmBgYA0KDQojIyMg5pe26Ze06Ze06ZqUDQoNCiMjIyMgZGlmZnRpbWUg57G75Z6LDQoNCmBgYHtyfQ0KdGltZV9sZW5ndGggPC0gdG9kYXkoKSAtIHltZCgxOTc5MTAxNCkNCnRpbWVfbGVuZ3RoDQpjbGFzcyh0aW1lX2xlbmd0aCkNCg0KIyDln7rnoYDljIXnmoRkaWZmdGltZSgp5Ye95pWwDQpkaWZmdGltZSh0b2RheSgpLCB5bWQoMTk3OTEwMTQpKSANCmRpZmZ0aW1lKHRvZGF5KCksIHltZCgxOTc5MTAxNCksIHVuaXRzID0gJ3dlZWtzJykgDQpkaWZmdGltZSh0b2RheSgpLCB5bWQoMTk3OTEwMTQpLCB1bml0cyA9ICdob3VycycpIA0KYGBgDQoNCiMjIyMg5pe25pyfIGR1cmF0aW9uIO+8iCoq57uf5LiA5Y2V5L2N5Li656eSKirvvIkNCg0K55SoZGlmZnRpbWXmlbDmja7nsbvlnovmnoTpgKBkdXJhdGlvbg0KDQpgYGB7cn0NCiMgSGFkbGV55aSa5aSn5LqG77yfDQphcy5kdXJhdGlvbih0b2RheSgpIC0geW1kKDE5NzkxMDE0KSkNCmBgYA0KDQrmnoTpgKDml7bmnJ/nmoTns7vliJflh73mlbDvvIjpg73mnIkiZCLliY3nvIDlkowicyLlkI7nvIDvvInvvJoNCg0KYGBge3J9DQpkc2Vjb25kcygxNSkNCmRtaW51dGVzKDEwKQ0KZGhvdXJzKGMoMTIsIDI0KSkNCmRkYXlzKDA6NSkNCmR3ZWVrcygzKQ0KZHllYXJzKDEpDQpgYGANCg0K5Y+v5Lul5a+5ZHVyYXRpb27ov5vooYzliqDms5XlkozkuZjms5Xmk43kvZzvvIzml7bmnJ/kuZ/lj6/ku6XkuI7ml6XmnJ/lnovmlbDmja7nm7jliqDmiJbnm7jlh4/vvIzku43nhLblvpfliLDml6XmnJ/lnovvvJoNCg0KYGBge3J9DQpkeWVhcnMoMSkgKyBkd2Vla3MoMTIpICsgZGhvdXJzKDE1KQ0KdG9tb3Jyb3cgPC0gdG9kYXkoKSArIGRkYXlzKDEpDQpjbGFzcyh0b21vcnJvdykNCmxhc3RfeWVhciA8LSB0b2RheSgpIC0gZHllYXJzKDEpDQpjbGFzcyhsYXN0X3llYXIpDQpgYGANCg0KIyMjIyA8Zm9udCBjb2xvciA9ICdyZWQnPumYtuautTwvZm9udD4NCg0KbHVicmlkYXRlIOaPkOS+m+S6humYtuauteWvueixoeOAgumYtuauteS5n+aYr+S4gOenjeaXtumXtOmXtOmalO+8jOS9huWug+S4jeS7peenkuS4uuWNleS9je+8m+ebuOWPje+8jOWug+S9v+eUqCLkurrlt6Ui5pe26Ze077yM5q+U5aaC5pel5ZKM5pyI77yM6L+Z5L2/5b6X5a6D5Lus5L2/55So6LW35p2l5pu05Yqg55u06KeC44CCDQoNCuaehOmAoOmYtuauteeahOezu+WIl+WHveaVsCjlj6rmnIkicyLlkI7nvIAp77yaDQoNCmBgYHtyfQ0Kc2Vjb25kcygxNSkNCm1pbnV0ZXMoMTApDQpob3VycyhjKDEyLCAyNCkpDQpkYXlzKDcpDQptb250aHMoMTo2KQ0Kd2Vla3MoMykNCnllYXJzKDEpDQpgYGANCg0K5Y+v5Lul5a+56Zi25q616L+b6KGM5Yqg5rOV5ZKM5LmY5rOV5pON5L2c77yaDQoNCmBgYHtyfQ0KMTAgKiAobW9udGhzKDYpICsgZGF5cygxKSkNCmRheXMoNTApICsgaG91cnMoMjUpICsgbWludXRlcygyKQ0KYGBgDQoNCjxzdHJvbmc+PGZvbnQgY29sb3IgPSAicmVkIj7pmLbmrrXlj6/ku6Xlkozml6XmnJ/nm7jliqDjgILkuI7ml7bmnJ/nm7jmr5TvvIzpmLbmrrXmm7TlrrnmmJPnrKblkIjmiJHku6znmoTpooTmnJ/vvIzlm6DkuLrlroPoh6rliqjogIPomZHkuobljobms5XnmoTnp43np43op4TliJk8L2ZvbnQ+PC9zdHJvbmc+77yaDQoNCmBgYHtyfQ0KIyMg6Zew5bm06Zeu6aKYDQp5bWQoIjIwMTYtMDEtMDEiKSArIGR5ZWFycygxKSAjIGR5ZWFycygp5Lqn55Sf55qE5pe25pyf5Y+q5piv566A5Y2V5Zyw5Yqg5LqGMzY15aSpDQp5bWQoIjIwMTYtMDEtMDEiKSArIHllYXJzKDEpICMg6ICD6JmR5YiwMjAxNuW5tOS4uumXsOW5tO+8jHllYXJzKCnkuqfnlJ/nmoTpmLbmrrXliqDkuoYzNjblpKkNCmBgYA0KDQojIyMjIOWMuumXtA0KDQrpmLbmrrXnmoTkuIDlubR5ZWFycygxKeWIsOW6leaYrzM2NeWkqei/mOaYrzM2NuWkqeaYr+S4jeehruWumueahO+8jOWboOatpOacieS6huaWsOeahOexu++8muWMuumXtOOAguWMuumXtOaYr+W4puaciei1t+eCueeahOaXtuacn++8jOi/meS9v+W+l+S9oOWPr+S7peehruWIh+WcsOefpemBk+Wug+eahOmVv+W6puOAgg0KDQpgYGB7cn0NCm5leHRfeWVhciA8LSB0b2RheSgpICsgeWVhcnMoMSkNCm5leHRfeWVhcg0KKHRvZGF5KCkgJS0tJSBuZXh0X3llYXIpIC8gZGRheXMoMSkNCmBgYA0KDQojIyMjIOaAu+e7kw0KDQrlpoLmnpzlj6rlhbPlv4PniannkIbml7bpl7TvvIzpgqPkuYjlsLHkvb/nlKjml7bmnJ/vvJvlpoLmnpzov5jpnIDopoHogIPomZHkurrlt6Xml7bpl7TvvIzpgqPkuYjlsLHkvb/nlKjpmLbmrrXvvJvlpoLmnpzpnIDopoHmib7lh7rkurrlt6Xml7bpl7TojIPlm7TlhoXmnInlpJrplb/nmoTml7bpl7Tpl7TpmpTvvIzpgqPkuYjlsLHkvb/nlKjljLrpl7TjgIINCg0KIyMjIOaXtuWMug0KDQrkuLrkuobpgb/lhY3mt7fmt4bvvIwgUiDkvb/nlKjlm73pmYXmoIflh4YgSUFOQSDml7bljLrjgILov5nkupvml7bljLrkvb/nlKjnu5/kuIDluKbmnIkiLyLnmoTlkb3lkI3mlrnlvI/vvIzkuIDoiKznmoTlvaLlvI/kuLoiXDwg5aSn6ZmGIFw+L1w8IOWfjuW4giBcPiLvvIjlrZjlnKjkvovlpJbvvIzlm6DkuLrkuI3mmK/miYDmnInln47luILpg73kvY3kuo7kuIDlnZflpKfpmYbvvInjgILlpoIiQW1lcmljYS9OZXdfWW9yayLjgIEiRXVyb3BlL1BhcmlzIuWSjCJQYWNpZmljL0F1Y2tsYW5kIuOAguS5i+aJgOS7peS9v+eUqOWfjuW4guWQje+8jOaYr+WboOS4uklBTkEg5pWw5o2u5bqT5b+F6aG76K6w5b2V5Y2B5bm06Ze055qE5pe25Yy677yM6ICM5Zyo5Y2B5bm05pe26Ze05Lit77yM5Zu95a625pu05ZCN77yI5oiW5YiG6KOC77yJ55qE5oOF5Ya16Z2e5bi45aSa77yM5L2G5Z+O5biC5ZCN5piv5Z+65pys5L+d5oyB5LiN5Y+Y55qE44CCDQoNClN5cy50aW1lem9uZSgpIOWHveaVsOaJvuWHuuS9oOeahOW9k+WJjeaXtuWMuuOAgk9sc29uTmFtZXMoKSDlh73mlbDmnaXmn6XnnIvlrozmlbTnmoTml7bljLrlkI3np7DliJfooajjgIINCg0KYGBge3J9DQpTeXMudGltZXpvbmUoKQ0KaGVhZChPbHNvbk5hbWVzKCkpDQpgYGANCg0K5ZyoIFIg5Lit77yM5pe25Yy65piv5pel5pyf5pe26Ze05Z6L5pWw5o2u55qE5LiA5Liq5bGe5oCn77yM5LuF55So5LqO5o6n5Yi26L6T5Ye644CC5L6L5aaC77yM5Lul5LiLIDMg5Liq5a+56LGh6KGo56S655qE5piv5ZCM5LiA5pe25Yi777yaDQoNCmBgYHtyfQ0KKHgxIDwtIHltZF9obXMoIjIwMTUtMDYtMDEgMTI6MDA6MDAiLCANCiAgICAgICAgICAgICAgIHR6ID0gIkFtZXJpY2EvTmV3X1lvcmsiKSk7DQoNCih4MiA8LSB5bWRfaG1zKCIyMDE1LTA2LTAxIDE4OjAwOjAwIiwgdHogPSAiRXVyb3BlL0NvcGVuaGFnZW4iKSk7DQoNCih4MyA8LSB5bWRfaG1zKCIyMDE1LTA2LTAyIDA0OjAwOjAwIiwgDQogICAgICAgICAgICAgICB0eiA9ICJQYWNpZmljL0F1Y2tsYW5kIikpOw0KDQp4NCA8LSBjKHgxLCB4MiwgeDMpDQp4NA0KeDRhIDwtIHdpdGhfdHooeDQsIHR6b25lID0gIkFzaWEvVGFpcGVpIikNCng0YQ0KeDRiIDwtIGZvcmNlX3R6KHg0LCB0em9uZSA9ICJBc2lhL1RhaXBlaSIpDQp4NGINCmBgYA0K