NHIỆM VỤ 3.1

Thực hiện các thao tác đã học trên bộ dữ liệu population-and-demography

Giới thiệu

Bộ dữ liệu population-and-demography cung cấp thông tin về dân số và nhân khẩu học của các quốc gia và vùng lãnh thổ trên thế giới theo nhóm tuổi từ năm 1950 đến năm 2021

Thông tin tổng quát

  • Ta gán bộ dữ liệu population-and-demography với tên là pnd
library(csv)
pnd <- read.csv("C:/Users/HELLO/Documents/R/population-and-demography.csv", header = T)
  • Bộ dữ liệu gồm 18288 obs. (quan sát) của 24 variables (biến)
  • Tương ứng với các quan sát là 18288 hàng
  • Tương ứng với các biến là 24 cột:
    • Country: Quốc gia
    • Year: Năm
    • Population: Dân số
    • Population.of.children.under.the.age.of.1: Dân số trẻ em từ 1 tuổi trở xuống
    • Population.of.children.under.the.age.of.5: Dân số trẻ em từ 5 tuổi trở xuống
    • Population.of.children.under.the.age.of.15: Dân số trẻ em từ 15 tuổi trở xuống
    • Population.under.the.age.of.25: Dân số từ 25 tuổi trở xuống
    • Population.aged.15.to.64.year: Dân số từ 15-64 tuổi
    • Population.older.than.15.years: Dân số lớn hơn 15 tuổi
    • Population.older.than.18.years: Dân số lớn hơn 18 tuổi
    • Population.of.age.1: Dân số 1 tuổi
    • Population.aged.1.to.4.years: Dân số từ 1-4 tuổi
    • Population.aged.5.to.9.years: Dân số từ 5-9 tuổi
    • Population.aged.10.to.14.years: Dân số từ 10-14 tuổi
    • Population.aged.15.to.19.years: Dân số từ 15-19 tuổi
    • Population.aged.20.to.29.years: Dân số từ 20-29 tuổi
    • Population.aged.30.to.39.years: Dân số từ 30-39 tuổi
    • Population.aged.40.to.49.years: Dân số từ 40-49 tuổi
    • Population.aged.50.to.59.years: Dân số từ 50-59 tuổi
    • Population.aged.60.to.69.years: Dân số từ 60-69 tuổi
    • Population.aged.70.to.79.years: Dân số từ 70-79 tuổi
    • Population.aged.80.to.89.years: Dân số từ 80-89 tuổi
    • Population.aged.90.to.99.years: Dân số từ 90-99 tuổi
    • Population.older.than.100.years: Dân số lớn hơn 100 tuổi

Phân tích dữ liệu của các quốc gia

Để việc thao tác trên bộ dữ liệu được nhanh chóng và tiện lợi hơn ta thực hiện đổi tên các biến

pnd2 <- pnd
names(pnd2) <- c('country', 'yr', 'pop', 'u1', 'u5', 'u15', 'u25', 'a15to64', 'o15', 'o18', 'a1', 'a1to4', 'a5to9', 'a10to14', 'a15to19', 'a20to29', 'a30to39', 'a40to49', 'a50to59', 'a60to69', 'a70to79', 'a80to89', 'a90to99', 'o100')

Ở đây ta chọn:

  • 5 quốc gia để phân tích là:
    • Anh: United Kingdom
    • Mỹ: United States
    • Pháp: France
    • Nga: Russia
    • Trung Quốc: China

BẢNG TẦN SỐ

library(dplyr)
pnd3 <- filter(pnd2,country=='United Kingdom'|country=='United States'|country=='France'|country=='Russia'|country=='China')
table(pnd3$country)
## 
##          China         France         Russia United Kingdom  United States 
##             72             72             72             72             72

Kết quả tần số cho ra 72 có nghĩa là chúng ta đang phân tích dân số của các nước trong khoảng thời gian 72 năm

MÃ HÓA DŨ LIỆU

Thêm cột web.domain để chia các nước theo tên miền internet

library('DT')
pnd4 <- pnd3
pnd4$web.domain <- ifelse(pnd4$country == 'China','cn',ifelse(pnd4$country == 'France','fr', ifelse(pnd4$country == 'Russia','ru', ifelse(pnd4$country == 'United Kingdom','uk', 'us'))))
datatable(pnd4)

ANH

Anh - Tên đầy đủ là Liên hiệp Vương quốc Anh và Bắc Ireland là một quốc đảo có chủ quyền tại châu Âu. Quốc gia này nằm ngoài khơi châu Âu lục địa, bao gồm toàn bộ đảo Anh và một phần phía đông bắc của đảo Ireland cùng nhiều đảo nhỏ khác

Dân số nước Anh qua từng năm tăng giảm không đều và tỷ lệ tăng dân số có xu hướng ngày càng giảm, điều này được thể hiện qua 2 biểu đồ bên dưới.

options(scipen=999)
library(ggplot2)
library(scales)
library(dplyr)
uk <- filter(pnd2, country == 'United Kingdom')
uk %>% ggplot(aes(x = yr, y = pop)) +
  geom_col(fill ='pink') +
  xlab('Năm') +
  ylab('Dân số') +
  labs(title = 'Dân số nước Anh từ năm 1950 đến năm 2021')

l <- length(uk$yr)
ukpi <- vector()
for(i in 1:(l)) {
  ukpi[i]= (uk$pop[i+1]/uk$pop[i]-1)}
 ggplot(uk, aes(x = yr, y = ukpi)) +
  geom_col(fill ='navy') +
  xlab('Năm') +
  ylab('Tỉ lệ tăng') +
  labs(title = 'Tỉ lệ tăng dân số ở Anh từ năm 1950 đến năm 2021')

summary(uk$pop)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## 50055068 55096029 56682475 57563900 59736313 67281040
  • Từ số liệu bên dưới ta thấy dân số thấp nhất của nước Anh là 50055068, cao nhất 67281040
  • Phân vị thứ nhất bằng 55096029
  • Trung vị bằng 56682475
  • Dân số trung bình là 57563900
  • Phân vị thứ ba bằng 59736313

MỸ

Mỹ - tên chính thức là Hợp chủng quốc Hoa Kỳ là một quốc gia cộng hòa lập hiến liên bang ở châu Mỹ, nằm tại Tây Bán cầu, lãnh thổ bao gồm 50 tiểu bang và một đặc khu liên bang. Hoa Kỳ nằm ở giữa Bắc Mỹ, giáp biển Thái Bình Dương ở phía tây, Đại Tây Dương ở phía đông, Canada ở phía bắc và Mexico ở phía nam

Dân số nước Mỹ qua từng năm tăng giảm không đều và tỷ lệ tăng dân số có xu hướng ngày càng giảm, điều này được thể hiện qua 2 biểu đồ bên dưới.

options(scipen=999)
us <- filter(pnd2, country == 'United States')
us %>% ggplot(aes(x = yr, y = pop)) +
  geom_col(fill ='pink') +
  xlab('Năm') +
  ylab('Dân số') +
  labs(title = 'Dân số nước Mỹ từ năm 1950 đến năm 2021')

uspi <- vector()
for(i in 1:(l)) {
  uspi[i]= (us$pop[i+1]/us$pop[i]-1)}
 ggplot(us, aes(x = yr, y = uspi)) +
  geom_col(fill ='navy') +
  xlab('Năm') +
  ylab('Tỉ lệ tăng') +
  labs(title = 'Tỉ lệ tăng dân số ở Mỹ từ năm 1950 đến năm 2021')

summary(us$pop)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 148281550 195253172 236329480 241932229 291819332 336997630
  • Từ số liệu bên dưới ta thấy dân số thấp nhất của nước Mỹ là 148281550, cao nhất 336997630
  • Phân vị thứ nhất bằng 195253172
  • Trung vị bằng 236329480
  • Dân số trung bình là 241932229
  • Phân vị thứ ba bằng 291819332

PHÁP

Pháp - tên chính thức là Cộng hòa Pháp là một quốc gia có lãnh thổ chính nằm tại Tây Âu cùng một số vùng và lãnh thổ hải ngoại. Phần lãnh thổ Pháp tại châu Âu trải dài từ Địa Trung Hải đến eo biển Manche và biển Bắc, và từ sông Rhine đến Đại Tây Dương

Dân số nước Pháp qua từng năm tăng giảm không đều và tỷ lệ tăng dân số có xu hướng giảm mạnh trong những năm gần đây, điều này được thể hiện qua 2 biểu đồ bên dưới.

options(scipen=999)
fr <- filter(pnd2, country == 'France')
fr %>% ggplot(aes(x = yr, y = pop)) +
  geom_col(fill ='pink') +
  xlab('Năm') +
  ylab('Dân số') +
  labs(title = 'Dân số nước Pháp từ năm 1950 đến năm 2021')

frpi <- vector()
for(i in 1:(l)) {
  frpi[i]= (fr$pop[i+1]/fr$pop[i]-1)}
 ggplot(fr, aes(x = yr, y = frpi)) +
  geom_col(fill ='navy') +
  xlab('Năm') +
  ylab('Tỉ lệ tăng') +
  labs(title = 'Tỉ lệ tăng dân số ở Pháp từ năm 1950 đến năm 2021')

summary(fr$pop)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## 41842356 49530804 55239872 54535777 59823304 64531450
  • Từ số liệu bên dưới ta thấy dân số thấp nhất của nước Mỹ là 41842356, cao nhất 64531450
  • Phân vị thứ nhất bằng 49530804
  • Trung vị bằng 55239872
  • Dân số trung bình là 54535777
  • Phân vị thứ ba bằng 59823304

NGA

Nga - tên đầy đủ là Liên bang Nga là một quốc gia Cộng hòa liên bang nằm ở phía Bắc của lục địa Á - Âu, đây là quốc gia có diện tích lớn nhất trên thế giới

Dân số nước Nga qua từng năm tăng giảm không đều và tỷ lệ tăng dân số có xu hướng giảm mạnh trong những năm gần đây, điều này được thể hiện qua 2 biểu đồ bên dưới.

options(scipen=999)
ru <- filter(pnd2, country == 'Russia')
ru %>% ggplot(aes(x = yr, y = pop)) +
  geom_col(fill ='pink') +
  xlab('Năm') +
  ylab('Dân số') +
  labs(title = 'Dân số nước Nga từ năm 1950 đến năm 2021')

rupi <- vector()
for(i in 1:(l)) {
  rupi[i]= (ru$pop[i+1]/ru$pop[i]-1)}
 ggplot(ru, aes(x = yr, y = rupi)) +
  geom_col(fill ='navy') +
  xlab('Năm') +
  ylab('Tỉ lệ tăng') +
  labs(title = 'Tỉ lệ tăng dân số ở Nga từ năm 1950 đến năm 2021')

summary(ru$pop)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 102580110 128644714 142991460 135841943 145486940 148897280
  • Từ số liệu bên dưới ta thấy dân số thấp nhất của nước Mỹ là 102580110, cao nhất 148897280
  • Phân vị thứ nhất bằng 128644714
  • Trung vị bằng 142991460
  • Dân số trung bình là 135841943
  • Phân vị thứ ba bằng 145486940

TRUNG QUỐC

Trung Quốc - tên đầy đủ là Cộng hòa Nhân dân Trung Hoa là một quốc gia nằm ở khu vực Đông Á và là một trong hai quốc gia tỷ dân

Dân số Trung Quốc qua từng năm tăng giảm không đều và tỷ lệ tăng dân số có xu hướng ngày càng giảm, điều này được thể hiện qua 2 biểu đồ bên dưới.

options(scipen=999)
cn <- filter(pnd2, country == 'China')
cn %>% ggplot(aes(x = yr, y = pop)) +
  geom_col(fill ='pink') +
  xlab('Năm') +
  ylab('Dân số') +
  labs(title = 'Dân số Trung Quốc từ năm 1950 đến năm 2021')

cnpi <- vector()
for(i in 1:(l)) {
  cnpi[i]= (cn$pop[i+1]/cn$pop[i]-1)}
 ggplot(cn, aes(x = yr, y = cnpi)) +
  geom_col(fill ='navy') +
  xlab('Năm') +
  ylab('Tỉ lệ tăng') +
  labs(title = 'Tỉ lệ tăng dân số ở Trung Quốc từ năm 1950 đến năm 2021')

summary(cn$pop)
##       Min.    1st Qu.     Median       Mean    3rd Qu.       Max. 
##  543979200  775530575 1069005250 1035531645 1290859175 1425893500
  • Từ số liệu bên dưới ta thấy dân số thấp nhất của nước Mỹ là 543979200, cao nhất 1425893500
  • Phân vị thứ nhất bằng 775530575
  • Trung vị bằng 1069005250
  • Dân số trung bình là 1035531645
  • Phân vị thứ ba bằng 1290859175

PHÂN TÍCH DỮ LIỆU QUỐC GIA THEO NHÓM TUỔI

Tính trung bình dân số trong độ tuổi lao động

mean(pnd3$a15to64)
## [1] 198712131

Kết quả thu được cho biết trung bình dân số trong độ tuổi lao động ở các nước là 198712131

Tính tổng số dân trên 100 tuổi

sum(pnd3$o100)
## [1] 3499833

Kết quả thu được cho biết tổng số dân trên 100 tuổi ở các nước là 3499833

Tính số phần trăm trẻ em dưới 15 tuổi

quantile(pnd3$u15, probs = c(.25,.5,.75))
##      25%      50%      75% 
## 11812370 30531855 61128706

Kết quả thu được cho biết 25% tổng số trẻ em dưới 15 tuổi là 11812370, 50% tổng số trẻ em dưới 15 tuổi là 30531855, 75% tổng số trẻ em dưới 15 tuổi là 61128706

Tính phương sai của nhóm tuổi dưới 25 tuổi

var(pnd3$u25)
## [1] 31899349758477404

Kết quả thu được cho biết phương sai của nhóm tuổi dưới 25 tuổi là 31899349758477404

Tính trung vị của nhóm tuổi lớn hơn 18 tuổi

median(pnd3$o18)
## [1] 104114503

Kết quả thu được cho biết trung vị của nhóm tuổi lớn hơn 18 tuổi là 104114503

NHIỆM VỤ 3.2

Giới thiệu bộ dữ liệu

  • Bộ dữ liệu này tổng hợp thông tin của 1000 bộ phim có doanh thu cao nhất mọi thời đại tính đến ngày 05/09/2022. Bộ dữ liệu này được sắp xếp theo đúng thứ tự như website Box Office Mojo.
  • Bộ dữ liệu bao gồm 1000 obs (quan sát) của 10 variables (biến)
  • Các biến được thể hiện dưới dạng các cột:
    • Movie Title: Tên phim
    • Year of Release: Năm phát hành
    • Genre: Thể loại
    • Movie Rating: Chỉ số Rating chấm bởi người dùng IMDb (thang từ 1 đến 10)
    • Duration: Thời lượng phim
    • Gross: Tổng doanh thu tính theo USD
    • Worldwide LT Gross: Worldwide Lifetime Gross - Tổng doanh thu trong và ngoài nước
    • Metascore: Điểm trung bình được đánh giá bởi các nhà phê bình (thang từ 1 đến 10)
    • Votes: Số lượt bình chọn bởi người dùng IMDb
    • Logline: 1 hoặc 2 dòng tóm tắt phim

Thông tin tổng quan

Ta gán bộ dữ liệu với cái tên là nv3, sau đó tiến hành dùng lệnh skim để biết thông tin tổng quan của bộ dữ liệu

library(skimr)
nv3 <- read.csv("C:/Users/HELLO/Documents/R/Top_1000_Highest_Grossing_Movies_Of_All_Time.csv", header = T)
skim(nv3)
Data summary
Name nv3
Number of rows 1000
Number of columns 10
_______________________
Column type frequency:
character 8
numeric 2
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
Movie.Title 0 1 2 83 0 989 0
Year.of.Realease 0 1 4 5 0 55 0
Genre 0 1 5 26 0 153 0
Gross 0 1 6 8 0 949 0
Worldwide.LT.Gross 0 1 12 14 0 1000 0
Metascore 0 1 2 6 0 80 0
Votes 0 1 3 9 0 1000 0
Logline 0 1 51 336 0 1000 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
Movie.Rating 0 1 6.80 0.90 2.5 6.2 6.8 7.4 9.2 ▁▁▆▇▂
Duration 0 1 117.68 21.56 69.0 102.0 116.0 130.0 238.0 ▃▇▂▁▁

Phân tích bộ dữ liệu

Ta chọn 5 bộ phim để phân tích là: - Avatar - Titanic - Jurrasic World - The Lion King - Frozen II

Mã hóa dữ liệu

Thêm cột Over.2hr để chia những phim dài trên 2h

nv31 <- filter(nv3,Movie.Title=='Avatar'|Movie.Title=='Titanic'|Movie.Title=='Jurassic World'|Movie.Title=='Black Panther'|Movie.Title=='Frozen II')
nv31$Over.2hr <- ifelse(nv31$Duration > 160,'yes','no')
datatable(nv31)

Phân tích só liệu

Chỉ số Rating trung bình

mean(nv31$Movie.Rating,na.rm = T)
## [1] 7.34

Kết quả thu được chỉ số Rating trung bình là 7

Trung vị năm phát hành

median(nv31$Year.of.Realease,na.rm = T)
## [1] "2015"

Kết quả thu được trung vị năm phát hành là 2015

Tổng thời lượng phim

sum(nv31$Duration, na.rm = T)
## [1] 717

Kết quả thu được tổng thời lượng phim là 717

So sánh điểm của các nhà phê bình

nv31 %>% ggplot(aes(x = Movie.Title, y = Metascore)) +
  geom_col(fill ='purple') +
  xlab('Phim') +
  ylab('Điểm phê bình') +
  labs(title = 'So sánh điểm của các nhà phê bình')

Qua biểu đồ ta thấy Black Panther được các nhà phê bình đánh giá cao nhất trong khi Jurassic World được đánh giá thấp nhất

So sánh chỉ số Rating

nv31 %>% ggplot(aes(x = Movie.Title, y = Movie.Rating)) +
  geom_col(fill ='purple') +
  xlab('Phim') +
  ylab('Ratings') +
  labs(title = 'So sánh chỉ số Rating')

Ta thấy chỉ số Rating được đánh giá khá đều, với sự chênh lệch không quá lớn. Phim có chỉ số Rating lớn nhất là Titanic, phim có chỉ số Rating nhỏ nhất là Frozen II

LS0tDQp0aXRsZTogIk5ISeG7hk0gVuG7pCAzIg0KYXV0aG9yOiAibmhwaHVjIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJUg6JU06JVMsICVkIC0gJW0gLSAlWScpYCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IHNpbXBsZXgNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgZGZfcHJpbnQ6IGthYmxlDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyAqKk5ISeG7hk0gVuG7pCAzLjEgKioNCg0KVGjhu7FjIGhp4buHbiBjw6FjIHRoYW8gdMOhYyDEkcOjIGjhu41jIHRyw6puIGLhu5kgZOG7ryBsaeG7h3UgKipwb3B1bGF0aW9uLWFuZC1kZW1vZ3JhcGh5KioNCg0KIyMjICoqR2nhu5tpIHRoaeG7h3UqKg0KDQpC4buZIGThu68gbGnhu4d1ICoqcG9wdWxhdGlvbi1hbmQtZGVtb2dyYXBoeSoqIGN1bmcgY+G6pXAgdGjDtG5nIHRpbiB24buBICoqZMOibiBz4buRIHbDoCBuaMOibiBraOG6qXUgaOG7jWMqKiBj4bunYSBjw6FjIHF14buRYyBnaWEgdsOgIHbDuW5nIGzDo25oIHRo4buVIHRyw6puIHRo4bq/IGdp4bubaSB0aGVvIG5ow7NtIHR14buVaSB04burIG7Eg20gMTk1MCDEkeG6v24gbsSDbSAyMDIxDQoNCg0KIyMjICoqVGjDtG5nIHRpbiB04buVbmcgcXXDoXQqKg0KDQotIFRhIGfDoW4gYuG7mSBk4buvIGxp4buHdSAqKnBvcHVsYXRpb24tYW5kLWRlbW9ncmFwaHkqKiB24bubaSB0w6puIGzDoCBwbmQNCg0KYGBgIHtyfQ0KbGlicmFyeShjc3YpDQpwbmQgPC0gcmVhZC5jc3YoIkM6L1VzZXJzL0hFTExPL0RvY3VtZW50cy9SL3BvcHVsYXRpb24tYW5kLWRlbW9ncmFwaHkuY3N2IiwgaGVhZGVyID0gVCkNCmBgYA0KDQotIELhu5kgZOG7ryBsaeG7h3UgZ+G7k20gKioxODI4OCBvYnMuIChxdWFuIHPDoXQpIGPhu6dhIDI0IHZhcmlhYmxlcyAoYmnhur9uKSoqDQotIFTGsMahbmcg4bupbmcgduG7m2kgY8OhYyBxdWFuIHPDoXQgbMOgIDE4Mjg4IGjDoG5nDQotIFTGsMahbmcg4bupbmcgduG7m2kgY8OhYyBiaeG6v24gbMOgIDI0IGPhu5l0Og0KICArIENvdW50cnk6IFF14buRYyBnaWENCiAgKyBZZWFyOiBOxINtDQogICsgUG9wdWxhdGlvbjogRMOibiBz4buRDQogICsgUG9wdWxhdGlvbi5vZi5jaGlsZHJlbi51bmRlci50aGUuYWdlLm9mLjE6IETDom4gc+G7kSB0cuG6uyBlbSB04burIDEgdHXhu5VpIHRy4bufIHh14buRbmcNCiAgKyBQb3B1bGF0aW9uLm9mLmNoaWxkcmVuLnVuZGVyLnRoZS5hZ2Uub2YuNTogRMOibiBz4buRIHRy4bq7IGVtIHThu6sgNSB0deG7lWkgdHLhu58geHXhu5FuZw0KICArIFBvcHVsYXRpb24ub2YuY2hpbGRyZW4udW5kZXIudGhlLmFnZS5vZi4xNTogRMOibiBz4buRIHRy4bq7IGVtIHThu6sgMTUgdHXhu5VpIHRy4bufIHh14buRbmcNCiAgKyBQb3B1bGF0aW9uLnVuZGVyLnRoZS5hZ2Uub2YuMjU6IETDom4gc+G7kSB04burIDI1IHR14buVaSB0cuG7nyB4deG7kW5nDQogICsgUG9wdWxhdGlvbi5hZ2VkLjE1LnRvLjY0LnllYXI6IETDom4gc+G7kSB04burIDE1LTY0IHR14buVaQ0KICArIFBvcHVsYXRpb24ub2xkZXIudGhhbi4xNS55ZWFyczogRMOibiBz4buRIGzhu5tuIGjGoW4gMTUgdHXhu5VpDQogICsgUG9wdWxhdGlvbi5vbGRlci50aGFuLjE4LnllYXJzOiBEw6JuIHPhu5EgbOG7m24gaMahbiAxOCB0deG7lWkNCiAgKyBQb3B1bGF0aW9uLm9mLmFnZS4xOiBEw6JuIHPhu5EgMSB0deG7lWkNCiAgKyBQb3B1bGF0aW9uLmFnZWQuMS50by40LnllYXJzOiBEw6JuIHPhu5EgdOG7qyAxLTQgdHXhu5VpDQogICsgUG9wdWxhdGlvbi5hZ2VkLjUudG8uOS55ZWFyczogRMOibiBz4buRIHThu6sgNS05IHR14buVaQ0KICArIFBvcHVsYXRpb24uYWdlZC4xMC50by4xNC55ZWFyczogRMOibiBz4buRIHThu6sgMTAtMTQgdHXhu5VpDQogICsgUG9wdWxhdGlvbi5hZ2VkLjE1LnRvLjE5LnllYXJzOiBEw6JuIHPhu5EgdOG7qyAxNS0xOSB0deG7lWkNCiAgKyBQb3B1bGF0aW9uLmFnZWQuMjAudG8uMjkueWVhcnM6IETDom4gc+G7kSB04burIDIwLTI5IHR14buVaQ0KICArIFBvcHVsYXRpb24uYWdlZC4zMC50by4zOS55ZWFyczogRMOibiBz4buRIHThu6sgMzAtMzkgdHXhu5VpDQogICsgUG9wdWxhdGlvbi5hZ2VkLjQwLnRvLjQ5LnllYXJzOiBEw6JuIHPhu5EgdOG7qyA0MC00OSB0deG7lWkNCiAgKyBQb3B1bGF0aW9uLmFnZWQuNTAudG8uNTkueWVhcnM6IETDom4gc+G7kSB04burIDUwLTU5IHR14buVaQ0KICArIFBvcHVsYXRpb24uYWdlZC42MC50by42OS55ZWFyczogRMOibiBz4buRIHThu6sgNjAtNjkgdHXhu5VpDQogICsgUG9wdWxhdGlvbi5hZ2VkLjcwLnRvLjc5LnllYXJzOiBEw6JuIHPhu5EgdOG7qyA3MC03OSB0deG7lWkNCiAgKyBQb3B1bGF0aW9uLmFnZWQuODAudG8uODkueWVhcnM6IETDom4gc+G7kSB04burIDgwLTg5IHR14buVaQ0KICArIFBvcHVsYXRpb24uYWdlZC45MC50by45OS55ZWFyczogRMOibiBz4buRIHThu6sgOTAtOTkgdHXhu5VpDQogICsgUG9wdWxhdGlvbi5vbGRlci50aGFuLjEwMC55ZWFyczogRMOibiBz4buRIGzhu5tuIGjGoW4gMTAwIHR14buVaQ0KICANCiMjIyAqKlBow6JuIHTDrWNoIGThu68gbGnhu4d1IGPhu6dhIGPDoWMgcXXhu5FjIGdpYSoqDQoNCsSQ4buDIHZp4buHYyB0aGFvIHTDoWMgdHLDqm4gYuG7mSBk4buvIGxp4buHdSDEkcaw4bujYyBuaGFuaCBjaMOzbmcgdsOgIHRp4buHbiBs4bujaSBoxqFuIHRhIHRo4buxYyBoaeG7h24gxJHhu5VpIHTDqm4gY8OhYyBiaeG6v24NCg0KYGBge3J9DQpwbmQyIDwtIHBuZA0KbmFtZXMocG5kMikgPC0gYygnY291bnRyeScsICd5cicsICdwb3AnLCAndTEnLCAndTUnLCAndTE1JywgJ3UyNScsICdhMTV0bzY0JywgJ28xNScsICdvMTgnLCAnYTEnLCAnYTF0bzQnLCAnYTV0bzknLCAnYTEwdG8xNCcsICdhMTV0bzE5JywgJ2EyMHRvMjknLCAnYTMwdG8zOScsICdhNDB0bzQ5JywgJ2E1MHRvNTknLCAnYTYwdG82OScsICdhNzB0bzc5JywgJ2E4MHRvODknLCAnYTkwdG85OScsICdvMTAwJykNCmBgYA0KDQrhu54gxJHDonkgdGEgY2jhu41uOiANCg0KLSA1IHF14buRYyBnaWEgxJHhu4MgcGjDom4gdMOtY2ggbMOgOg0KICArICoqQW5oOioqIFVuaXRlZCBLaW5nZG9tDQogICsgKipN4bu5OioqIFVuaXRlZCBTdGF0ZXMNCiAgKyAqKlBow6FwOioqIEZyYW5jZQ0KICArICoqTmdhOioqIFJ1c3NpYQ0KICArICoqVHJ1bmcgUXXhu5FjOioqIENoaW5hDQogIA0KIyMjIyAqKkLhuqJORyBU4bqmTiBT4buQKioNCg0KYGBge3IgZWNobz1ULCB3YXJuaW5nPUYsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KcG5kMyA8LSBmaWx0ZXIocG5kMixjb3VudHJ5PT0nVW5pdGVkIEtpbmdkb20nfGNvdW50cnk9PSdVbml0ZWQgU3RhdGVzJ3xjb3VudHJ5PT0nRnJhbmNlJ3xjb3VudHJ5PT0nUnVzc2lhJ3xjb3VudHJ5PT0nQ2hpbmEnKQ0KdGFibGUocG5kMyRjb3VudHJ5KQ0KYGBgDQoNCkvhur90IHF14bqjIHThuqduIHPhu5EgY2hvIHJhIDcyIGPDsyBuZ2jEqWEgbMOgIGNow7puZyB0YSDEkWFuZyBwaMOibiB0w61jaCBkw6JuIHPhu5EgY+G7p2EgY8OhYyBuxrDhu5tjIHRyb25nIGtob+G6o25nIHRo4budaSBnaWFuIDcyIG7Eg20NCg0KIyMjIyAqKk3DgyBIw5NBIETFqCBMSeG7hlUqKg0KDQpUaMOqbSBj4buZdCB3ZWIuZG9tYWluIMSR4buDIGNoaWEgY8OhYyBuxrDhu5tjIHRoZW8gdMOqbiBtaeG7gW4gaW50ZXJuZXQNCg0KYGBge3J9DQpsaWJyYXJ5KCdEVCcpDQpwbmQ0IDwtIHBuZDMNCnBuZDQkd2ViLmRvbWFpbiA8LSBpZmVsc2UocG5kNCRjb3VudHJ5ID09ICdDaGluYScsJ2NuJyxpZmVsc2UocG5kNCRjb3VudHJ5ID09ICdGcmFuY2UnLCdmcicsIGlmZWxzZShwbmQ0JGNvdW50cnkgPT0gJ1J1c3NpYScsJ3J1JywgaWZlbHNlKHBuZDQkY291bnRyeSA9PSAnVW5pdGVkIEtpbmdkb20nLCd1aycsICd1cycpKSkpDQpkYXRhdGFibGUocG5kNCkNCmBgYA0KDQojIyMjICoqQU5IKioNCg0KKipBbmgqKiAtIFTDqm4gxJHhuqd5IMSR4bunIGzDoCBMacOqbiBoaeG7h3AgVsawxqFuZyBxdeG7kWMgQW5oIHbDoCBC4bqvYyBJcmVsYW5kIGzDoCBt4buZdCBxdeG7kWMgxJHhuqNvIGPDsyBjaOG7pyBxdXnhu4FuIHThuqFpIGNow6J1IMOCdS4gUXXhu5FjIGdpYSBuw6B5IG7hurFtIG5nb8OgaSBraMahaSBjaMOidSDDgnUgbOG7pWMgxJHhu4thLCBiYW8gZ+G7k20gdG/DoG4gYuG7mSDEkeG6o28gQW5oIHbDoCBt4buZdCBwaOG6p24gcGjDrWEgxJHDtG5nIGLhuq9jIGPhu6dhIMSR4bqjbyBJcmVsYW5kIGPDuW5nIG5oaeG7gXUgxJHhuqNvIG5o4buPIGtow6FjDQoNCkTDom4gc+G7kSBuxrDhu5tjIEFuaCBxdWEgdOG7q25nIG7Eg20gdMSDbmcgZ2nhuqNtIGtow7RuZyDEkeG7gXUgdsOgIHThu7cgbOG7hyB0xINuZyBkw6JuIHPhu5EgY8OzIHh1IGjGsOG7m25nIG5nw6B5IGPDoG5nIGdp4bqjbSwgxJFp4buBdSBuw6B5IMSRxrDhu6NjIHRo4buDIGhp4buHbiBxdWEgMiBiaeG7g3UgxJHhu5MgYsOqbiBkxrDhu5tpLiANCg0KYGBge3IgZWNobz1ULCB3YXJuaW5nPUYsIG1lc3NhZ2U9RkFMU0V9DQpvcHRpb25zKHNjaXBlbj05OTkpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHNjYWxlcykNCmxpYnJhcnkoZHBseXIpDQp1ayA8LSBmaWx0ZXIocG5kMiwgY291bnRyeSA9PSAnVW5pdGVkIEtpbmdkb20nKQ0KdWsgJT4lIGdncGxvdChhZXMoeCA9IHlyLCB5ID0gcG9wKSkgKw0KICBnZW9tX2NvbChmaWxsID0ncGluaycpICsNCiAgeGxhYignTsSDbScpICsNCiAgeWxhYignRMOibiBz4buRJykgKw0KICBsYWJzKHRpdGxlID0gJ0TDom4gc+G7kSBuxrDhu5tjIEFuaCB04burIG7Eg20gMTk1MCDEkeG6v24gbsSDbSAyMDIxJykNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlPUZBTFNFfQ0KbCA8LSBsZW5ndGgodWskeXIpDQp1a3BpIDwtIHZlY3RvcigpDQpmb3IoaSBpbiAxOihsKSkgew0KICB1a3BpW2ldPSAodWskcG9wW2krMV0vdWskcG9wW2ldLTEpfQ0KIGdncGxvdCh1aywgYWVzKHggPSB5ciwgeSA9IHVrcGkpKSArDQogIGdlb21fY29sKGZpbGwgPSduYXZ5JykgKw0KICB4bGFiKCdOxINtJykgKw0KICB5bGFiKCdU4buJIGzhu4cgdMSDbmcnKSArDQogIGxhYnModGl0bGUgPSAnVOG7iSBs4buHIHTEg25nIGTDom4gc+G7kSDhu58gQW5oIHThu6sgbsSDbSAxOTUwIMSR4bq/biBuxINtIDIwMjEnKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeSh1ayRwb3ApDQpgYGANCg0KLSBU4burIHPhu5EgbGnhu4d1IGLDqm4gZMaw4bubaSB0YSB0aOG6pXkgZMOibiBz4buRIHRo4bqlcCBuaOG6pXQgY+G7p2Egbsaw4bubYyBBbmggbMOgIDUwMDU1MDY4LCBjYW8gbmjhuqV0IDY3MjgxMDQwDQotIFBow6JuIHbhu4sgdGjhu6kgbmjhuqV0IGLhurFuZyA1NTA5NjAyOQ0KLSBUcnVuZyB24buLIGLhurFuZyA1NjY4MjQ3NQ0KLSBEw6JuIHPhu5EgdHJ1bmcgYsOsbmggbMOgIDU3NTYzOTAwDQotIFBow6JuIHbhu4sgdGjhu6kgYmEgYuG6sW5nIDU5NzM2MzEzDQoNCiMjIyMgKipN4bu4KioNCg0KKipN4bu5KiogLSB0w6puIGNow61uaCB0aOG7qWMgbMOgIEjhu6NwIGNo4bunbmcgcXXhu5FjIEhvYSBL4buzIGzDoCBt4buZdCBxdeG7kWMgZ2lhIGPhu5luZyBow7JhIGzhuq1wIGhp4bq/biBsacOqbiBiYW5nIOG7nyBjaMOidSBN4bu5LCBu4bqxbSB04bqhaSBUw6J5IELDoW4gY+G6p3UsIGzDo25oIHRo4buVIGJhbyBn4buTbSA1MCB0aeG7g3UgYmFuZyB2w6AgbeG7mXQgxJHhurdjIGtodSBsacOqbiBiYW5nLiBIb2EgS+G7syBu4bqxbSDhu58gZ2nhu69hIELhuq9jIE3hu7ksIGdpw6FwIGJp4buDbiBUaMOhaSBCw6xuaCBExrDGoW5nIOG7nyBwaMOtYSB0w6J5LCDEkOG6oWkgVMOieSBExrDGoW5nIOG7nyBwaMOtYSDEkcO0bmcsIENhbmFkYSDhu58gcGjDrWEgYuG6r2MgdsOgIE1leGljbyDhu58gcGjDrWEgbmFtDQoNCkTDom4gc+G7kSBuxrDhu5tjIE3hu7kgcXVhIHThu6tuZyBuxINtIHTEg25nIGdp4bqjbSBraMO0bmcgxJHhu4F1IHbDoCB04bu3IGzhu4cgdMSDbmcgZMOibiBz4buRIGPDsyB4dSBoxrDhu5tuZyBuZ8OgeSBjw6BuZyBnaeG6o20sIMSRaeG7gXUgbsOgeSDEkcaw4bujYyB0aOG7gyBoaeG7h24gcXVhIDIgYmnhu4N1IMSR4buTIGLDqm4gZMaw4bubaS4gDQoNCmBgYHtyIGVjaG89VCwgd2FybmluZz1GLCBtZXNzYWdlPUZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW49OTk5KQ0KdXMgPC0gZmlsdGVyKHBuZDIsIGNvdW50cnkgPT0gJ1VuaXRlZCBTdGF0ZXMnKQ0KdXMgJT4lIGdncGxvdChhZXMoeCA9IHlyLCB5ID0gcG9wKSkgKw0KICBnZW9tX2NvbChmaWxsID0ncGluaycpICsNCiAgeGxhYignTsSDbScpICsNCiAgeWxhYignRMOibiBz4buRJykgKw0KICBsYWJzKHRpdGxlID0gJ0TDom4gc+G7kSBuxrDhu5tjIE3hu7kgdOG7qyBuxINtIDE5NTAgxJHhur9uIG7Eg20gMjAyMScpDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GQUxTRX0NCnVzcGkgPC0gdmVjdG9yKCkNCmZvcihpIGluIDE6KGwpKSB7DQogIHVzcGlbaV09ICh1cyRwb3BbaSsxXS91cyRwb3BbaV0tMSl9DQogZ2dwbG90KHVzLCBhZXMoeCA9IHlyLCB5ID0gdXNwaSkpICsNCiAgZ2VvbV9jb2woZmlsbCA9J25hdnknKSArDQogIHhsYWIoJ07Eg20nKSArDQogIHlsYWIoJ1Thu4kgbOG7hyB0xINuZycpICsNCiAgbGFicyh0aXRsZSA9ICdU4buJIGzhu4cgdMSDbmcgZMOibiBz4buRIOG7nyBN4bu5IHThu6sgbsSDbSAxOTUwIMSR4bq/biBuxINtIDIwMjEnKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeSh1cyRwb3ApDQpgYGANCg0KLSBU4burIHPhu5EgbGnhu4d1IGLDqm4gZMaw4bubaSB0YSB0aOG6pXkgZMOibiBz4buRIHRo4bqlcCBuaOG6pXQgY+G7p2Egbsaw4bubYyBN4bu5IGzDoCAxNDgyODE1NTAsIGNhbyBuaOG6pXQgMzM2OTk3NjMwDQotIFBow6JuIHbhu4sgdGjhu6kgbmjhuqV0IGLhurFuZyAxOTUyNTMxNzINCi0gVHJ1bmcgduG7iyBi4bqxbmcgMjM2MzI5NDgwDQotIETDom4gc+G7kSB0cnVuZyBiw6xuaCBsw6AgMjQxOTMyMjI5DQotIFBow6JuIHbhu4sgdGjhu6kgYmEgYuG6sW5nIDI5MTgxOTMzMg0KDQojIyMjICoqUEjDgVAqKg0KDQoqKlBow6FwKiogLSB0w6puIGNow61uaCB0aOG7qWMgbMOgIEPhu5luZyBow7JhIFBow6FwICBsw6AgbeG7mXQgcXXhu5FjIGdpYSBjw7MgbMOjbmggdGjhu5UgY2jDrW5oIG7hurFtIHThuqFpIFTDonkgw4J1IGPDuW5nIG3hu5l0IHPhu5EgdsO5bmcgdsOgIGzDo25oIHRo4buVIGjhuqNpIG5nb+G6oWkuIFBo4bqnbiBsw6NuaCB0aOG7lSBQaMOhcCB04bqhaSBjaMOidSDDgnUgdHLhuqNpIGTDoGkgdOG7qyDEkOG7i2EgVHJ1bmcgSOG6o2kgxJHhur9uIGVvIGJp4buDbiBNYW5jaGUgdsOgIGJp4buDbiBC4bqvYywgdsOgIHThu6sgc8O0bmcgUmhpbmUgxJHhur9uIMSQ4bqhaSBUw6J5IETGsMahbmcNCg0KRMOibiBz4buRIG7GsOG7m2MgUGjDoXAgcXVhIHThu6tuZyBuxINtIHTEg25nIGdp4bqjbSBraMO0bmcgxJHhu4F1IHbDoCB04bu3IGzhu4cgdMSDbmcgZMOibiBz4buRIGPDsyB4dSBoxrDhu5tuZyBnaeG6o20gbeG6oW5oIHRyb25nIG5o4buvbmcgbsSDbSBn4bqnbiDEkcOieSwgxJFp4buBdSBuw6B5IMSRxrDhu6NjIHRo4buDIGhp4buHbiBxdWEgMiBiaeG7g3UgxJHhu5MgYsOqbiBkxrDhu5tpLiANCg0KYGBge3IgZWNobz1ULCB3YXJuaW5nPUYsIG1lc3NhZ2U9RkFMU0V9DQpvcHRpb25zKHNjaXBlbj05OTkpDQpmciA8LSBmaWx0ZXIocG5kMiwgY291bnRyeSA9PSAnRnJhbmNlJykNCmZyICU+JSBnZ3Bsb3QoYWVzKHggPSB5ciwgeSA9IHBvcCkpICsNCiAgZ2VvbV9jb2woZmlsbCA9J3BpbmsnKSArDQogIHhsYWIoJ07Eg20nKSArDQogIHlsYWIoJ0TDom4gc+G7kScpICsNCiAgbGFicyh0aXRsZSA9ICdEw6JuIHPhu5Egbsaw4bubYyBQaMOhcCB04burIG7Eg20gMTk1MCDEkeG6v24gbsSDbSAyMDIxJykNCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlPUZBTFNFfQ0KZnJwaSA8LSB2ZWN0b3IoKQ0KZm9yKGkgaW4gMToobCkpIHsNCiAgZnJwaVtpXT0gKGZyJHBvcFtpKzFdL2ZyJHBvcFtpXS0xKX0NCiBnZ3Bsb3QoZnIsIGFlcyh4ID0geXIsIHkgPSBmcnBpKSkgKw0KICBnZW9tX2NvbChmaWxsID0nbmF2eScpICsNCiAgeGxhYignTsSDbScpICsNCiAgeWxhYignVOG7iSBs4buHIHTEg25nJykgKw0KICBsYWJzKHRpdGxlID0gJ1Thu4kgbOG7hyB0xINuZyBkw6JuIHPhu5Eg4bufIFBow6FwIHThu6sgbsSDbSAxOTUwIMSR4bq/biBuxINtIDIwMjEnKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShmciRwb3ApDQpgYGANCg0KLSBU4burIHPhu5EgbGnhu4d1IGLDqm4gZMaw4bubaSB0YSB0aOG6pXkgZMOibiBz4buRIHRo4bqlcCBuaOG6pXQgY+G7p2Egbsaw4bubYyBN4bu5IGzDoCA0MTg0MjM1NiwgY2FvIG5o4bqldCA2NDUzMTQ1MCANCi0gUGjDom4gduG7iyB0aOG7qSBuaOG6pXQgYuG6sW5nIDQ5NTMwODA0DQotIFRydW5nIHbhu4sgYuG6sW5nIDU1MjM5ODcyDQotIETDom4gc+G7kSB0cnVuZyBiw6xuaCBsw6AgNTQ1MzU3NzcNCi0gUGjDom4gduG7iyB0aOG7qSBiYSBi4bqxbmcgNTk4MjMzMDQNCg0KIyMjIyAqKk5HQSoqDQoNCioqTmdhKiogLSB0w6puIMSR4bqneSDEkeG7pyBsw6AgTGnDqm4gYmFuZyBOZ2EgbMOgIG3hu5l0IHF14buRYyBnaWEgQ+G7mW5nIGjDsmEgbGnDqm4gYmFuZyBu4bqxbSDhu58gcGjDrWEgQuG6r2MgY+G7p2EgbOG7pWMgxJHhu4thIMOBIC0gw4J1LCDEkcOieSBsw6AgcXXhu5FjIGdpYSBjw7MgZGnhu4duIHTDrWNoIGzhu5tuIG5o4bqldCB0csOqbiB0aOG6vyBnaeG7m2kNCg0KRMOibiBz4buRIG7GsOG7m2MgTmdhIHF1YSB04burbmcgbsSDbSB0xINuZyBnaeG6o20ga2jDtG5nIMSR4buBdSB2w6AgdOG7tyBs4buHIHTEg25nIGTDom4gc+G7kSBjw7MgeHUgaMaw4bubbmcgZ2nhuqNtIG3huqFuaCB0cm9uZyBuaOG7r25nIG7Eg20gZ+G6p24gxJHDonksIMSRaeG7gXUgbsOgeSDEkcaw4bujYyB0aOG7gyBoaeG7h24gcXVhIDIgYmnhu4N1IMSR4buTIGLDqm4gZMaw4bubaS4gDQoNCmBgYHtyIGVjaG89VCwgd2FybmluZz1GLCBtZXNzYWdlPUZBTFNFfQ0Kb3B0aW9ucyhzY2lwZW49OTk5KQ0KcnUgPC0gZmlsdGVyKHBuZDIsIGNvdW50cnkgPT0gJ1J1c3NpYScpDQpydSAlPiUgZ2dwbG90KGFlcyh4ID0geXIsIHkgPSBwb3ApKSArDQogIGdlb21fY29sKGZpbGwgPSdwaW5rJykgKw0KICB4bGFiKCdOxINtJykgKw0KICB5bGFiKCdEw6JuIHPhu5EnKSArDQogIGxhYnModGl0bGUgPSAnRMOibiBz4buRIG7GsOG7m2MgTmdhIHThu6sgbsSDbSAxOTUwIMSR4bq/biBuxINtIDIwMjEnKQ0KYGBgDQoNCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9RkFMU0V9DQpydXBpIDwtIHZlY3RvcigpDQpmb3IoaSBpbiAxOihsKSkgew0KICBydXBpW2ldPSAocnUkcG9wW2krMV0vcnUkcG9wW2ldLTEpfQ0KIGdncGxvdChydSwgYWVzKHggPSB5ciwgeSA9IHJ1cGkpKSArDQogIGdlb21fY29sKGZpbGwgPSduYXZ5JykgKw0KICB4bGFiKCdOxINtJykgKw0KICB5bGFiKCdU4buJIGzhu4cgdMSDbmcnKSArDQogIGxhYnModGl0bGUgPSAnVOG7iSBs4buHIHTEg25nIGTDom4gc+G7kSDhu58gTmdhIHThu6sgbsSDbSAxOTUwIMSR4bq/biBuxINtIDIwMjEnKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShydSRwb3ApDQpgYGANCg0KLSBU4burIHPhu5EgbGnhu4d1IGLDqm4gZMaw4bubaSB0YSB0aOG6pXkgZMOibiBz4buRIHRo4bqlcCBuaOG6pXQgY+G7p2Egbsaw4bubYyBN4bu5IGzDoCAxMDI1ODAxMTAsIGNhbyBuaOG6pXQgMTQ4ODk3MjgwIA0KLSBQaMOibiB24buLIHRo4bupIG5o4bqldCBi4bqxbmcgMTI4NjQ0NzE0DQotIFRydW5nIHbhu4sgYuG6sW5nIDE0Mjk5MTQ2MA0KLSBEw6JuIHPhu5EgdHJ1bmcgYsOsbmggbMOgIDEzNTg0MTk0Mw0KLSBQaMOibiB24buLIHRo4bupIGJhIGLhurFuZyAxNDU0ODY5NDANCg0KIyMjIyAqKlRSVU5HIFFV4buQQyoqDQoNCioqVHJ1bmcgUXXhu5FjKiogLSB0w6puIMSR4bqneSDEkeG7pyBsw6AgQ+G7mW5nIGjDsmEgTmjDom4gZMOibiBUcnVuZyBIb2EgbMOgIG3hu5l0IHF14buRYyBnaWEgbuG6sW0g4bufIGtodSB24buxYyDEkMO0bmcgw4EgdsOgIGzDoCBt4buZdCB0cm9uZyBoYWkgcXXhu5FjIGdpYSB04bu3IGTDom4NCg0KRMOibiBz4buRIFRydW5nIFF14buRYyBxdWEgdOG7q25nIG7Eg20gdMSDbmcgZ2nhuqNtIGtow7RuZyDEkeG7gXUgdsOgIHThu7cgbOG7hyB0xINuZyBkw6JuIHPhu5EgY8OzIHh1IGjGsOG7m25nIG5nw6B5IGPDoG5nIGdp4bqjbSwgxJFp4buBdSBuw6B5IMSRxrDhu6NjIHRo4buDIGhp4buHbiBxdWEgMiBiaeG7g3UgxJHhu5MgYsOqbiBkxrDhu5tpLiANCg0KYGBge3IgZWNobz1ULCB3YXJuaW5nPUYsIG1lc3NhZ2U9RkFMU0V9DQpvcHRpb25zKHNjaXBlbj05OTkpDQpjbiA8LSBmaWx0ZXIocG5kMiwgY291bnRyeSA9PSAnQ2hpbmEnKQ0KY24gJT4lIGdncGxvdChhZXMoeCA9IHlyLCB5ID0gcG9wKSkgKw0KICBnZW9tX2NvbChmaWxsID0ncGluaycpICsNCiAgeGxhYignTsSDbScpICsNCiAgeWxhYignRMOibiBz4buRJykgKw0KICBsYWJzKHRpdGxlID0gJ0TDom4gc+G7kSBUcnVuZyBRdeG7kWMgdOG7qyBuxINtIDE5NTAgxJHhur9uIG7Eg20gMjAyMScpDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RiwgbWVzc2FnZT1GQUxTRX0NCmNucGkgPC0gdmVjdG9yKCkNCmZvcihpIGluIDE6KGwpKSB7DQogIGNucGlbaV09IChjbiRwb3BbaSsxXS9jbiRwb3BbaV0tMSl9DQogZ2dwbG90KGNuLCBhZXMoeCA9IHlyLCB5ID0gY25waSkpICsNCiAgZ2VvbV9jb2woZmlsbCA9J25hdnknKSArDQogIHhsYWIoJ07Eg20nKSArDQogIHlsYWIoJ1Thu4kgbOG7hyB0xINuZycpICsNCiAgbGFicyh0aXRsZSA9ICdU4buJIGzhu4cgdMSDbmcgZMOibiBz4buRIOG7nyBUcnVuZyBRdeG7kWMgdOG7qyBuxINtIDE5NTAgxJHhur9uIG7Eg20gMjAyMScpDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5KGNuJHBvcCkNCmBgYA0KDQotIFThu6sgc+G7kSBsaeG7h3UgYsOqbiBkxrDhu5tpIHRhIHRo4bqleSBkw6JuIHPhu5EgdGjhuqVwIG5o4bqldCBj4bunYSBuxrDhu5tjIE3hu7kgbMOgIDU0Mzk3OTIwMCwgY2FvIG5o4bqldCAxNDI1ODkzNTAwDQotIFBow6JuIHbhu4sgdGjhu6kgbmjhuqV0IGLhurFuZyA3NzU1MzA1NzUNCi0gVHJ1bmcgduG7iyBi4bqxbmcgMTA2OTAwNTI1MA0KLSBEw6JuIHPhu5EgdHJ1bmcgYsOsbmggbMOgIDEwMzU1MzE2NDUNCi0gUGjDom4gduG7iyB0aOG7qSBiYSBi4bqxbmcgMTI5MDg1OTE3NQ0KDQojIyMjICoqUEjDgk4gVMONQ0ggROG7riBMSeG7hlUgUVXhu5BDIEdJQSBUSEVPIE5Iw5NNIFRV4buUSSoqDQoNCioqVMOtbmggdHJ1bmcgYsOsbmggZMOibiBz4buRIHRyb25nIMSR4buZIHR14buVaSBsYW8gxJHhu5luZyoqDQoNCmBgYHtyfQ0KbWVhbihwbmQzJGExNXRvNjQpDQpgYGANCkvhur90IHF14bqjIHRodSDEkcaw4bujYyBjaG8gYmnhur90IHRydW5nIGLDrG5oIGTDom4gc+G7kSB0cm9uZyDEkeG7mSB0deG7lWkgbGFvIMSR4buZbmcg4bufIGPDoWMgbsaw4bubYyBsw6AgMTk4NzEyMTMxDQoNCioqVMOtbmggdOG7lW5nIHPhu5EgZMOibiB0csOqbiAxMDAgdHXhu5VpKioNCg0KYGBge3J9DQpzdW0ocG5kMyRvMTAwKQ0KYGBgDQoNCkvhur90IHF14bqjIHRodSDEkcaw4bujYyBjaG8gYmnhur90IHThu5VuZyBz4buRIGTDom4gdHLDqm4gMTAwIHR14buVaSDhu58gY8OhYyBuxrDhu5tjIGzDoCAzNDk5ODMzDQoNCioqVMOtbmggc+G7kSBwaOG6p24gdHLEg20gdHLhursgZW0gZMaw4bubaSAxNSB0deG7lWkqKg0KDQpgYGB7cn0NCnF1YW50aWxlKHBuZDMkdTE1LCBwcm9icyA9IGMoLjI1LC41LC43NSkpDQpgYGANCg0KS+G6v3QgcXXhuqMgdGh1IMSRxrDhu6NjIGNobyBiaeG6v3QgMjUlIHThu5VuZyBz4buRIHRy4bq7IGVtIGTGsOG7m2kgMTUgdHXhu5VpIGzDoCAxMTgxMjM3MCwgNTAlIHThu5VuZyBz4buRIHRy4bq7IGVtIGTGsOG7m2kgMTUgdHXhu5VpIGzDoCAzMDUzMTg1NSwgNzUlIHThu5VuZyBz4buRIHRy4bq7IGVtIGTGsOG7m2kgMTUgdHXhu5VpIGzDoCA2MTEyODcwNg0KDQoqKlTDrW5oIHBoxrDGoW5nIHNhaSBj4bunYSBuaMOzbSB0deG7lWkgZMaw4bubaSAyNSB0deG7lWkqKg0KDQpgYGB7cn0NCnZhcihwbmQzJHUyNSkNCmBgYA0KDQpL4bq/dCBxdeG6oyB0aHUgxJHGsOG7o2MgY2hvIGJp4bq/dCBwaMawxqFuZyBzYWkgY+G7p2EgbmjDs20gdHXhu5VpIGTGsOG7m2kgMjUgdHXhu5VpIGzDoCAzMTg5OTM0OTc1ODQ3NzQwNA0KDQoqKlTDrW5oIHRydW5nIHbhu4sgY+G7p2EgbmjDs20gdHXhu5VpIGzhu5tuIGjGoW4gMTggdHXhu5VpKioNCg0KYGBge3J9DQptZWRpYW4ocG5kMyRvMTgpDQpgYGANCg0KS+G6v3QgcXXhuqMgdGh1IMSRxrDhu6NjIGNobyBiaeG6v3QgdHJ1bmcgduG7iyBj4bunYSBuaMOzbSB0deG7lWkgbOG7m24gaMahbiAxOCB0deG7lWkgbMOgIDEwNDExNDUwMw0KDQojICoqTkhJ4buGTSBW4bukIDMuMiAqKg0KDQojIyAqKkdp4bubaSB0aGnhu4d1IGLhu5kgZOG7ryBsaeG7h3UqKg0KDQotIELhu5kgZOG7ryBsaeG7h3UgbsOgeSB04buVbmcgaOG7o3AgdGjDtG5nIHRpbiBj4bunYSAxMDAwIGLhu5kgcGhpbSBjw7MgZG9hbmggdGh1IGNhbyBuaOG6pXQgbeG7jWkgdGjhu51pIMSR4bqhaSB0w61uaCDEkeG6v24gbmfDoHkgMDUvMDkvMjAyMi4gQuG7mSBk4buvIGxp4buHdSBuw6B5IMSRxrDhu6NjIHPhuq9wIHjhur9wIHRoZW8gxJHDum5nIHRo4bupIHThu7EgbmjGsCB3ZWJzaXRlIEJveCBPZmZpY2UgTW9qby4NCi0gQuG7mSBk4buvIGxp4buHdSBiYW8gZ+G7k20gKioxMDAwIG9icyAocXVhbiBzw6F0KSoqIGPhu6dhICoqMTAgdmFyaWFibGVzIChiaeG6v24pKioNCi0gQ8OhYyBiaeG6v24gxJHGsOG7o2MgdGjhu4MgaGnhu4duIGTGsOG7m2kgZOG6oW5nIGPDoWMgY+G7mXQ6DQogICsgTW92aWUgVGl0bGU6IFTDqm4gcGhpbQ0KICArIFllYXIgb2YgUmVsZWFzZTogTsSDbSBwaMOhdCBow6BuaA0KICArIEdlbnJlOiBUaOG7gyBsb+G6oWkNCiAgKyBNb3ZpZSBSYXRpbmc6IENo4buJIHPhu5EgUmF0aW5nIGNo4bqlbSBi4bufaSBuZ8aw4budaSBkw7luZyBJTURiICh0aGFuZyB04burIDEgxJHhur9uIDEwKQ0KICArIER1cmF0aW9uOiBUaOG7nWkgbMaw4bujbmcgcGhpbQ0KICArIEdyb3NzOiBU4buVbmcgZG9hbmggdGh1IHTDrW5oIHRoZW8gVVNEDQogICsgV29ybGR3aWRlIExUIEdyb3NzOiBXb3JsZHdpZGUgTGlmZXRpbWUgR3Jvc3MgLSBU4buVbmcgZG9hbmggdGh1IHRyb25nIHbDoCBuZ2/DoGkgbsaw4bubYw0KICArIE1ldGFzY29yZTogxJBp4buDbSB0cnVuZyBiw6xuaCDEkcaw4bujYyDEkcOhbmggZ2nDoSBi4bufaSBjw6FjIG5ow6AgcGjDqiBiw6xuaCAodGhhbmcgdOG7qyAxIMSR4bq/biAxMCkNCiAgKyBWb3RlczogU+G7kSBsxrDhu6N0IGLDrG5oIGNo4buNbiBi4bufaSBuZ8aw4budaSBkw7luZyBJTURiDQogICsgTG9nbGluZTogMSBob+G6t2MgMiBkw7JuZyB0w7NtIHThuq90IHBoaW0NCiAgDQojIyAqKlRow7RuZyB0aW4gdOG7lW5nIHF1YW4qKg0KDQpUYSBnw6FuIGLhu5kgZOG7ryBsaeG7h3UgduG7m2kgY8OhaSB0w6puIGzDoCBudjMsIHNhdSDEkcOzIHRp4bq/biBow6BuaCBkw7luZyBs4buHbmggc2tpbSDEkeG7gyBiaeG6v3QgdGjDtG5nIHRpbiB04buVbmcgcXVhbiBj4bunYSBi4buZIGThu68gbGnhu4d1DQoNCmBgYHtyfQ0KbGlicmFyeShza2ltcikNCm52MyA8LSByZWFkLmNzdigiQzovVXNlcnMvSEVMTE8vRG9jdW1lbnRzL1IvVG9wXzEwMDBfSGlnaGVzdF9Hcm9zc2luZ19Nb3ZpZXNfT2ZfQWxsX1RpbWUuY3N2IiwgaGVhZGVyID0gVCkNCnNraW0obnYzKQ0KYGBgDQoNCiMjICoqUGjDom4gdMOtY2ggYuG7mSBk4buvIGxp4buHdSoqDQoNClRhIGNo4buNbiA1IGLhu5kgcGhpbSDEkeG7gyBwaMOibiB0w61jaCBsw6A6DQotIEF2YXRhcg0KLSBUaXRhbmljDQotIEp1cnJhc2ljIFdvcmxkDQotIFRoZSBMaW9uIEtpbmcNCi0gRnJvemVuIElJDQoNCiMjIyAqKk3DoyBow7NhIGThu68gbGnhu4d1KioNCg0KVGjDqm0gY+G7mXQgT3Zlci4yaHIgxJHhu4MgY2hpYSBuaOG7r25nIHBoaW0gZMOgaSB0csOqbiAyaA0KDQpgYGB7cn0NCm52MzEgPC0gZmlsdGVyKG52MyxNb3ZpZS5UaXRsZT09J0F2YXRhcid8TW92aWUuVGl0bGU9PSdUaXRhbmljJ3xNb3ZpZS5UaXRsZT09J0p1cmFzc2ljIFdvcmxkJ3xNb3ZpZS5UaXRsZT09J0JsYWNrIFBhbnRoZXInfE1vdmllLlRpdGxlPT0nRnJvemVuIElJJykNCm52MzEkT3Zlci4yaHIgPC0gaWZlbHNlKG52MzEkRHVyYXRpb24gPiAxNjAsJ3llcycsJ25vJykNCmRhdGF0YWJsZShudjMxKQ0KYGBgDQoNCiMjIyAqKlBow6JuIHTDrWNoIHPDsyBsaeG7h3UqKg0KDQoqKkNo4buJIHPhu5EgUmF0aW5nIHRydW5nIGLDrG5oKioNCg0KYGBge3J9DQptZWFuKG52MzEkTW92aWUuUmF0aW5nLG5hLnJtID0gVCkNCmBgYA0KDQpL4bq/dCBxdeG6oyB0aHUgxJHGsOG7o2MgY2jhu4kgc+G7kSBSYXRpbmcgdHJ1bmcgYsOsbmggbMOgIDcNCg0KKipUcnVuZyB24buLIG7Eg20gcGjDoXQgaMOgbmgqKg0KDQpgYGB7cn0NCm1lZGlhbihudjMxJFllYXIub2YuUmVhbGVhc2UsbmEucm0gPSBUKQ0KYGBgDQoNCkvhur90IHF14bqjIHRodSDEkcaw4bujYyB0cnVuZyB24buLIG7Eg20gcGjDoXQgaMOgbmggbMOgIDIwMTUNCg0KKipU4buVbmcgdGjhu51pIGzGsOG7o25nIHBoaW0qKg0KDQpgYGB7cn0NCnN1bShudjMxJER1cmF0aW9uLCBuYS5ybSA9IFQpDQpgYGANCg0KS+G6v3QgcXXhuqMgdGh1IMSRxrDhu6NjIHThu5VuZyB0aOG7nWkgbMaw4bujbmcgcGhpbSBsw6AgNzE3DQoNCioqU28gc8OhbmggxJFp4buDbSBj4bunYSBjw6FjIG5ow6AgcGjDqiBiw6xuaCoqDQoNCmBgYHtyIGVjaG89VCwgd2FybmluZz1GLCBtZXNzYWdlPUZBTFNFfQ0KbnYzMSAlPiUgZ2dwbG90KGFlcyh4ID0gTW92aWUuVGl0bGUsIHkgPSBNZXRhc2NvcmUpKSArDQogIGdlb21fY29sKGZpbGwgPSdwdXJwbGUnKSArDQogIHhsYWIoJ1BoaW0nKSArDQogIHlsYWIoJ8SQaeG7g20gcGjDqiBiw6xuaCcpICsNCiAgbGFicyh0aXRsZSA9ICdTbyBzw6FuaCDEkWnhu4NtIGPhu6dhIGPDoWMgbmjDoCBwaMOqIGLDrG5oJykNCmBgYA0KDQpRdWEgYmnhu4N1IMSR4buTIHRhIHRo4bqleSBCbGFjayBQYW50aGVyIMSRxrDhu6NjIGPDoWMgbmjDoCBwaMOqIGLDrG5oIMSRw6FuaCBnacOhIGNhbyBuaOG6pXQgdHJvbmcga2hpIEp1cmFzc2ljIFdvcmxkIMSRxrDhu6NjIMSRw6FuaCBnacOhIHRo4bqlcCBuaOG6pXQNCg0KKipTbyBzw6FuaCBjaOG7iSBz4buRIFJhdGluZyoqDQoNCmBgYHtyIGVjaG89VCwgd2FybmluZz1GLCBtZXNzYWdlPUZBTFNFfQ0KbnYzMSAlPiUgZ2dwbG90KGFlcyh4ID0gTW92aWUuVGl0bGUsIHkgPSBNb3ZpZS5SYXRpbmcpKSArDQogIGdlb21fY29sKGZpbGwgPSdwdXJwbGUnKSArDQogIHhsYWIoJ1BoaW0nKSArDQogIHlsYWIoJ1JhdGluZ3MnKSArDQogIGxhYnModGl0bGUgPSAnU28gc8OhbmggY2jhu4kgc+G7kSBSYXRpbmcnKQ0KYGBgDQoNClRhIHRo4bqleSBjaOG7iSBz4buRIFJhdGluZyDEkcaw4bujYyDEkcOhbmggZ2nDoSBraMOhIMSR4buBdSwgduG7m2kgc+G7sSBjaMOqbmggbOG7h2NoIGtow7RuZyBxdcOhIGzhu5tuLiBQaGltIGPDsyBjaOG7iSBz4buRIFJhdGluZyBs4bubbiBuaOG6pXQgbMOgIFRpdGFuaWMsIHBoaW0gY8OzIGNo4buJIHPhu5EgUmF0aW5nIG5o4buPIG5o4bqldCBsw6AgRnJvemVuIElJ