内容
library(tidyverse)
── Attaching core tidyverse packages ───────────────── tidyverse 2.0.0 ──
✔ dplyr 1.1.4 ✔ readr 2.1.4
✔ forcats 1.0.0 ✔ stringr 1.5.1
✔ ggplot2 3.4.4 ✔ tibble 3.2.1
✔ lubridate 1.9.3 ✔ tidyr 1.3.0
✔ purrr 1.0.2 ── Conflicts ─────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag() masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(WDI)
df_gini <- WDI(indicator = c(gini = "SI.POV.GINI",
`0-10` = "SI.DST.FRST.10",
`0-20` = "SI.DST.FRST.20",
`20-40` = "SI.DST.02ND.20",
`40-60` = "SI.DST.03RD.20",
`60-80` = "SI.DST.04TH.20",
`80-100` = "SI.DST.05TH.20",
`90-100` = "SI.DST.10TH.10"))
df_gini
write_csv(df_gini, "data/gini.csv")
df_gini <- read_csv("data/gini.csv")
Rows: 16758 Columns: 12── Column specification ─────────────────────────────────────────────────
Delimiter: ","
chr (3): country, iso2c, iso3c
dbl (9): year, gini, 0-10, 0-20, 20-40, 40-60, 60-80, 80-100, 90-100
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_gini_long <- df_gini |>
pivot_longer(-(1:5), names_to = "levels", values_to = "value")
df_gini_long
どのくらい GINI のデータがあるか確かめる
df_gini |> group_by(year) |> drop_na(gini) |>
summarize(n = n()) |>
ggplot(aes(year, n)) + geom_col()
実際のデータの個数も計算してみる。
df_gini_long |>
group_by(year, levels) |> drop_na(value) |>
summarize(num = n()) |> distinct(year, num) |> arrange(desc(year))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.
GINIだけでなく、他の値についても調べる。
df_gini_long |>
group_by(year, levels) |> drop_na(value) |>
summarize(num = n()) |> distinct(year, num) |>
ggplot(aes(year, num)) + geom_col()
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.
2022年は、7カ国分しかデータがないがその国名を表示する。
df_gini_long |> filter(year == 2022) |> drop_na(gini) |>
distinct(country, gini)
COUNTRY_GINI <- "Bangladesh"
YEAR_GINI <- 2022
df_gini_long |>
filter(country == COUNTRY_GINI, year == YEAR_GINI) |>
ggplot(aes(levels, value)) + geom_col()
COUNTRY_GINI <- "Bhutan"
YEAR_GINI <- 2022
df_gini_long |>
filter(country == COUNTRY_GINI, year == YEAR_GINI) |>
ggplot(aes(levels, value)) + geom_col()
COUNTRY_GINI <- "Costa Rica"
YEAR_GINI <- 2022
df_gini_long |>
filter(country == COUNTRY_GINI, year == YEAR_GINI) |>
ggplot(aes(levels, value)) + geom_col()
GINI って何!?
ジニ係数(ジニけいすう、英: Gini
coefficient)とは主に社会における所得の不平等さを測る指標である。0から1で表され、各人の所得が均一で格差が全くない状態を0、たった一人が全ての所得を独占している状態を1とする。ローレンツ曲線をもとに、1912年にイタリアの統計学者、コッラド・ジニによって考案された。それ以外にも、富の偏在性やエネルギー消費における不平等さなどに応用される。(Wikipedia)
ジニ係数のグラフ
ジニ係数は、Aの面積をAとBの各面積の合計で割ったものに等しい。すなわち、ジニ係数
=A/(A+B)となる。また、A+B=0.5のため、2×Aにも等しい(縦軸は0と1の間の値をとるため)
Derivation of the Lorenz curve and Gini coefficient for global income
in 2011 [リンク]
df_gini_calc <- df_gini |>
mutate(`0` = 0, `10` = `0-10`, `20` = `0-20`, `40` = `0-20` + `20-40`, `60` = `0-20` + `20-40` + `40-60`, `80` = `0-20` + `20-40` + `40-60` + `60-80`, `90` = `0-20` + `20-40` + `40-60` + `60-80` + `80-100`-`90-100`, `100` = 100)
df_gini_calc %>% drop_na() |> filter(country == "Bangladesh")
df_gini_calc_long <- df_gini_calc |> pivot_longer(`0`:`100`, names_to = "classes", values_to = "cumulative_share") |> mutate(classes = as.numeric(classes))
df_gini_calc_long %>% drop_na() |> filter(country == "Bangladesh")
確認
df_gini_calc_long |> filter(country == "Bangladesh") |>
filter(year == 2022) |> ggplot() + geom_line(aes(classes, cumulative_share)) + geom_segment(aes(x = 0, y = 0, xend = 100, yend = 100), color = 'red') +
scale_x_continuous(breaks = seq(0,100,by=20)) +
scale_y_continuous(breaks = seq(0,100,by=20)) #+
#annotate("text", x = 10, y = 80, label = gini)
Shade region between two lines with ggplot: [リンク]
df_gini_calc |> group_by(country, year) |>
drop_na(gini) |>
summarize(gini, gini_trapezoid = 100-(2*`10` + 3*`20` + 4*`40` + 4*`60` + 3*`80` + 2*`90` + 100)/10) |>
distinct(country, year, gini, gini_trapezoid)
`summarise()` has grouped output by 'country'. You can override using the `.groups` argument.
#### For the calcualtion of the area under the curve
#### Trapezoidal rule
trapezoid <- function(x, y) {
sum(diff(x)*(y[-1]+y[-length(y)]))/2
}
#### Simpson's rule: more accurate
simpson <- function(x, y){
n <- length(y)
odd <- n %% 2
if (odd)
area <- 1/3*sum( y[1] + 2*sum(y[seq(3,(n-2),by=2)]) + 4*sum(y[seq(2,(n-1),by=2)]) + y[n])
if (!odd)
area <- 1/3*sum( y[1] + 2*sum(y[seq(3,(n-3),by=2)]) + 4*sum(y[seq(2,(n-2),by=2)]) + y[n-1]) + 1/2*(y[n-1] + y[n])
dx <- x[2] - x[1]
return(area * dx)
}
SIMPSON <- function(x, h=1){
# AUC function computes the Area Under the Curve of a time serie using
# the Simpson's Rule (numerical method).
# https://link.springer.com/chapter/10.1007/978-1-4612-4974-0_26
# Arguments
# x: (vector) time serie values
# h: (int) temporal resolution of the time serie. default h=1
n = length(x)-1
xValues = seq(from=1, to=n, by=2)
sum <- list()
for(i in 1:length(xValues)){
n_sub <- xValues[[i]]-1
n <- xValues[[i]]
n_add <- xValues[[i]]+1
v1 <- x[[n_sub+1]]
v2 <- x[[n+1]]
v3 <- x[[n_add+1]]
s <- (h/3)*(v1+4*v2+v3)
sum <- append(sum, s)
}
sum <- unlist(sum)
auc <- sum(sum)
return(auc)
}
simpson(c(0,0.2,0.4,0.6,0.8,1),c(0,0.04,0.16,0.36,0.64,1))
[1] 0.3346667
library(DescTools)
Area Under the Curve: [リンク]
https://rdrr.io/cran/DescTools/f/
df_gini_calc_long |> group_by(country, year) |>
drop_na(gini) |>
summarize(gini, gini_spline = round(100-AUC(classes, cumulative_share, method = "spline")/50, digits = 1), gini_trapezoid = round(100-AUC(classes, cumulative_share)/50, digits = 1), gini_simpson = round(100 - simpson(classes, cumulative_share)/50, digits = 1)) |>
distinct(country, year, gini, gini_spline, gini_trapezoid, gini_simpson)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'country', 'year'. You can override using the `.groups` argument.
df_gini_calc_long |> group_by(country, year) |>
drop_na(gini) |>
summarize(gini, gini_spline = round(100-AUC(classes, cumulative_share, method = "spline")/50, digits = 1), gini_trapezoid = round(100-AUC(classes, cumulative_share)/50, digits = 1), gini_simpson = round(100 - simpson(classes, cumulative_share)/50, digits = 1)) |>
distinct(country, year, gini, gini_spline, gini_trapezoid, gini_simpson)
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.`summarise()` has grouped output by 'country', 'year'. You can override using the `.groups` argument.
AUC: Calculating Area under a Curve [リンク]
https://www.statsdirect.com/help/default.htm#nonparametric_methods/gini.htm
GINI Calculator
x に、数の列を入れるとその分配に関する、GINI を計算します。
x <- c(1,1,1,4,10)
Lc(x)[c(1,2)] |> as.tibble() |> mutate(d = p, .after = 1) |>
pivot_longer(-1, names_to = "name", values_to = "value") |>
ggplot(aes(p, value, fill = name)) + geom_area(position = "identity") +
annotate("text", x = 0.25, y = 0.75, label = paste("GINI = ",round(Lc(x)$Gini, digits = 2)))
SER <- c(0,5,3,1,1)
SER1 <- c(0,sort(SER))
SER1
[1] 0 0 1 1 3 5
N = length(SER1)
Y <- 0:N/N; Y
[1] 0.0000000 0.1666667 0.3333333 0.5000000 0.6666667 0.8333333 1.0000000
定義にもどって要確認
df_gini_long |> filter(year == 2022) |> drop_na(gini)
他の見せ方に修正
df_gini_long |> filter(year == 2022) |> drop_na(gini) |>
ggplot(aes(x = levels, y = adj, col = country)) + geom_line()
和をとったものを計算しないといけない。以下はあとで利用
df_gini_long <- df_gini |>
pivot_longer(-(1:5), names_to = "levels", values_to = "value") |>
mutate(levels = as.numeric(levels)) |>
mutate(cut = case_when(levels == 5 ~ '0-10',
levels == 10 ~ '0-20',
levels == 30 ~ '20-40',
levels == 50 ~ '40-60',
levels == 70 ~ '60-80',
levels == 90 ~ '80-100',
levels == 95 ~ '90-100'),
adj = case_when(levels == 5 ~ value*2,
levels == 95 ~ value*2,
.default = value))
df_gini_long
df_gini_rev <- WDI(indicator = c(gini = "SI.POV.GINI",
'0-10' = "SI.DST.FRST.10",
'0-20' = "SI.DST.FRST.20",
'20-40' = "SI.DST.02ND.20",
'40-60' = "SI.DST.03RD.20",
'60-80' = "SI.DST.04TH.20",
'80-100' = "SI.DST.05TH.20",
'90-100' = "SI.DST.10TH.10"))
df_gini_rev_long <- df_gini_rev |>
pivot_longer(-(1:5), names_to = "levels", values_to = "value")
df_gini_rev_long
COUNTRY_GINI <- "Bangladesh"
YEAR_GINI <- 2022
df_gini_rev_long |>
filter(country == COUNTRY_GINI, year == YEAR_GINI) |>
ggplot(aes(levels, value)) + geom_col()
df_gini_rev_long2 <- df_gini_rev |> drop_na(gini) |>
mutate('0-10' = `0-10` *2, '90-100' = `90-100` *2) |>
pivot_longer(-(1:5), names_to = "levels", values_to = "value")
COUNTRY_GINI <- "Bangladesh"
YEAR_GINI <- 2022
df_gini_rev_long2 |>
filter(country == COUNTRY_GINI, year == YEAR_GINI) |>
ggplot(aes(levels, value)) + geom_col()
COUNTRIES_GINI <- c("Bhutan", "Bangladesh","Indonesia","Costa Rica")
YEAR_GINI <- 2022
df_gini_rev_long2 |>
filter(country %in% COUNTRIES_GINI, year == YEAR_GINI) |>
ggplot(aes(levels, value, fill = factor(country, levels = COUNTRIES_GINI))) + geom_col(position = "dodge") + labs(fill = "")
YEAR_GINI <- 2000
df_gini_rev |>
filter(year == YEAR_GINI) |> drop_na(gini) |>
ggplot(aes(gini, `90-100`)) + geom_point() + geom_smooth(method = "lm")
YEAR_GINI <- 2000
df_gini_rev |>
filter(year == YEAR_GINI) |> drop_na(gini) |>
ggplot(aes(gini, `80-100`)) + geom_point() + geom_smooth(method = "lm")
YEAR_GINI <- 2000
df_gini_rev |> filter(year == YEAR_GINI) |> drop_na(gini) |>
ggplot(aes(gini)) + geom_histogram(binwidth = 5)
To Do
extra = TRUE で分析を始める方がよい。
Distribution を大切にする回にしてもよい。
weight を使えば、DescTools::Gini で、Lorentz Curve
を作り出し、それから計算できるかもしれないので、試してみる。
いくつかの、Lorentz
曲線と、その下を透明度をつけて、重ね合わすことをトライ。
0-10, 90-100 についての扱いをどうするかを考える。
df_gini_rev |> filter(iso2c == "ID", year == 2022)
df_gini_rev |> mutate('10-20' = `0-20`-`0-10`, .before = `0-20`) |> mutate('80-90' = `80-100`-`90-100`, .before = `80-100`) |> select(-c(`0-20`, `80-100`)) |>
filter(iso2c == "ID", year == 2022)
df_gini_rev |> mutate('10-20' = `0-20`-`0-10`, .before = `0-20`) |> mutate('80-90' = `80-100`-`90-100`, .before = `80-100`) |> select(-c(`0-20`, `80-100`)) |>
pivot_longer(-(1:5), names_to = "range", values_to = "value") |>
filter(iso2c == "ID", year == 2022) |> pull() |>
append(0,0) |> Gini(weights = c(1,1,1,2,2,2,1,1))
[1] 0.4137295
37.9
df_gini_rev |> mutate('10-20' = `0-20`-`0-10`, .before = `0-20`) |> mutate('80-90' = `80-100`-`90-100`, .before = `80-100`) |> select(-c(`0-20`, `80-100`)) |>
pivot_longer(-(1:5), names_to = "range", values_to = "value") |>
filter(iso2c == "ID", year == 2022) |> pull() -> id
Gini(c(0.5,1.5,3,5,7,8.5,9.5), id, conf.level=0.95, unbiased=FALSE)
gini lwr.ci upr.ci
0.2138977 0.1187878 0.3806978
LS0tCnRpdGxlOiAiR0VTIDAwMSDmvJTnv5IzIgphdXRob3I6ICJILiBTdXp1a2kiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgojIyDnrKwz6YCxCgoxMi8yMShUSCnjgIDkuI3lubPnrYnjgpLnhKHjgY/jgZnjgZ/jgoHjgavkvZXjgpLjgZnjgovjgbnjgY3jgYsxCgrjgIDjgIDjgIDjgIDjgIAgwqDkuI3lubPnrYnjgpLnhKHjgY/jgZnjgZ/jgoHjgavkvZXjgpLjgZnjgovjgbnjgY3jgYsyCgrorJvnvqnjgafjga/jgIHmiYDlvpfjga7kuJbnlYznmoTmoLzlt67jga7nj77nirbjgpLouI/jgb7jgYjjgabjgIHpq5jmiYDlvpfogIXjgavlr77jgZnjgovos4fnlKPoqrLnqI7jgIHph5Hono3lj5blvJXnqI7jga7lj6/og73mgKfjgavjgaTjgYTjgaborbDoq5bjgZfjgb7jgZnjgIIKCjAxLzA5KFRVKeOAgFLjgafjg4fjg7zjgr/jgrXjgqTjgqjjg7Pjgrkz77yaR05J5L+C5pWw44Go5omA5b6X5YiG5biD44CAIFtbTWFpbl0oaHR0cHM6Ly9kcy1zbC5naXRodWIuaW8vaW50cm8yci9nZXMwMDEvZ2VzMDAxLW1haW4ubmIuaHRtbCld44O7W+aOiOalrV0KCioqUG92ZXJ0eSBhbmQgSW5lcXVhbGl0eeKAlURpc3RyaWJ1dGlvbiBvZiBpbmNvbWUgb3IgY29uc3VtcHRpb27vvIjjg4fjg7zjgr/jgYzlsJHjgarjgYTpm6PngrnvvIkqKgoKR0lOSSBpbmRleCAoV29ybGQgQmFuayBlc3RpbWF0ZSnvvJtTSS5QT1YuR0lOSSBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TSS5QT1YuR0lOSSldCgpJbmNvbWUgc2hhcmUgaGVsZCBieSBsb3dlc3QgMTAl77yaU0kuRFNULkZSU1QuMTAgW1tMaW5rXShodHRwczovL2RhdGFiYW5rLndvcmxkYmFuay5vcmcvbWV0YWRhdGFnbG9zc2FyeS93b3JsZC1kZXZlbG9wbWVudC1pbmRpY2F0b3JzL3Nlcmllcy9TSS5EU1QuRlJTVC4xMCldCgpJbmNvbWUgc2hhcmUgaGVsZCBieSBsb3dlc3QgMjAl77yaU0kuRFNULkZSU1QuMjAgW1tMaW5rXShodHRwczovL2RhdGFiYW5rLndvcmxkYmFuay5vcmcvbWV0YWRhdGFnbG9zc2FyeS93b3JsZC1kZXZlbG9wbWVudC1pbmRpY2F0b3JzL3Nlcmllcy9TSS5EU1QuRlJTVC4yMCldCgpJbmNvbWUgc2hhcmUgaGVsZCBieSBzZWNvbmQgMjAl77yaU0kuRFNULjAyTkQuMjAgW1tMaW5rXShodHRwczovL2RhdGFiYW5rLndvcmxkYmFuay5vcmcvbWV0YWRhdGFnbG9zc2FyeS93b3JsZC1kZXZlbG9wbWVudC1pbmRpY2F0b3JzL3Nlcmllcy9TSS5EU1QuMDJORC4yMCldCgpJbmNvbWUgc2hhcmUgaGVsZCBieSB0aGlyZCAyMCXvvJpTSS5EU1QuMDNSRC4yMCBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TSS5EU1QuMDNSRC4yMCldCgpJbmNvbWUgc2hhcmUgaGVsZCBieSBmb3VydGggMjAl77yaU0kuRFNULjA0VEguMjAgW1tMaW5rXShodHRwczovL2RhdGFiYW5rLndvcmxkYmFuay5vcmcvbWV0YWRhdGFnbG9zc2FyeS93b3JsZC1kZXZlbG9wbWVudC1pbmRpY2F0b3JzL3Nlcmllcy9TSS5EU1QuMDRUSC4yMCldCgpJbmNvbWUgc2hhcmUgaGVsZCBieSBoaWdoZXN0IDIwJe+8mlNJLkRTVC4wNVRILjIwIFtbTGlua10oaHR0cHM6Ly9kYXRhLndvcmxkYmFuay5vcmcvaW5kaWNhdG9yL1NJLkRTVC4wNVRILjIwKV0KCkluY29tZSBzaGFyZSBoZWxkIGJ5IGhpZ2hlc3QgMTAl77yaU0kuRFNULjEwVEguMTAgW1tMaW5rXShodHRwczovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvU0kuRFNULjEwVEguMTApXQoKIyMjIOaMh+aomeOBq+OBpOOBhOOBpgoKLSAgIEdJTkkgaW5kZXggKFdvcmxkIEJhbmsgZXN0aW1hdGUp77ybU0kuUE9WLkdJTkkgW1tMaW5rXShodHRwczovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvU0kuUE9WLkdJTkkpXQoKICAgIC0gICBHaW5pIGluZGV4IG1lYXN1cmVzIHRoZSBleHRlbnQgdG8gd2hpY2ggdGhlIGRpc3RyaWJ1dGlvbiBvZiBpbmNvbWUgKG9yLCBpbiBzb21lIGNhc2VzLCBjb25zdW1wdGlvbiBleHBlbmRpdHVyZSkgYW1vbmcgaW5kaXZpZHVhbHMgb3IgaG91c2Vob2xkcyB3aXRoaW4gYW4gZWNvbm9teSBkZXZpYXRlcyBmcm9tIGEgcGVyZmVjdGx5IGVxdWFsIGRpc3RyaWJ1dGlvbi4gQSBMb3JlbnogY3VydmUgcGxvdHMgdGhlIGN1bXVsYXRpdmUgcGVyY2VudGFnZXMgb2YgdG90YWwgaW5jb21lIHJlY2VpdmVkIGFnYWluc3QgdGhlIGN1bXVsYXRpdmUgbnVtYmVyIG9mIHJlY2lwaWVudHMsIHN0YXJ0aW5nIHdpdGggdGhlIHBvb3Jlc3QgaW5kaXZpZHVhbCBvciBob3VzZWhvbGQuIFRoZSBHaW5pIGluZGV4IG1lYXN1cmVzIHRoZSBhcmVhIGJldHdlZW4gdGhlIExvcmVueiBjdXJ2ZSBhbmQgYSBoeXBvdGhldGljYWwgbGluZSBvZiBhYnNvbHV0ZSBlcXVhbGl0eSwgZXhwcmVzc2VkIGFzIGEgcGVyY2VudGFnZSBvZiB0aGUgbWF4aW11bSBhcmVhIHVuZGVyIHRoZSBsaW5lLiBUaHVzIGEgR2luaSBpbmRleCBvZiAwIHJlcHJlc2VudHMgcGVyZmVjdCBlcXVhbGl0eSwgd2hpbGUgYW4gaW5kZXggb2YgMTAwIGltcGxpZXMgcGVyZmVjdCBpbmVxdWFsaXR5LgoKICAgIC0gICDjgrjjg4vmjIfmlbDjga/jgIHntYzmuIjlhoXjga7lgIvkurrjgb7jgZ/jga/kuJbluK/plpPjga7miYDlvpfvvIjjgb7jgZ/jga/loLTlkIjjgavjgojjgaPjgabjga/mtojosrvmlK/lh7rvvInjga7liIbluIPjgYzjgIHlrozlhajjgavlubPnrYnjgarliIbluIPjgYvjgonjganjga7nqIvluqbpgLjohLHjgZfjgabjgYTjgovjgYvjgpLmuKzlrprjgZnjgovjgILjg63jg7zjg6zjg7Pjg4Tmm7Lnt5rjga/jgIHmnIDjgoLosqfjgZfjgYTlgIvkurrjgb7jgZ/jga/kuJbluK/jgYvjgonlp4vjgb7jgorjgIHlj5fntabogIXjga7ntK/nqY3mlbDjgavlr77jgZnjgovnt4/miYDlvpfjga7ntK/nqY3libLlkIjjgpLjg5fjg63jg4Pjg4jjgZfjgZ/jgoLjga7jgafjgYLjgovjgILjgrjjg4vmjIfmlbDjga/jgIHjg63jg7zjg6zjg7Pjg4Tmm7Lnt5rjgajntbblr77nmoTlubPnrYnjga7ku67mg7Pnt5rjgajjga7plpPjga7pnaLnqY3jgpLmuKzlrprjgZnjgovjgoLjga7jgafjgIHnt5rjga7kuIvjga7mnIDlpKfpnaLnqY3jga7nmb7liIbnjofjgafooajjgZXjgozjgovjgILjgZfjgZ/jgYzjgaPjgabjgIHjgrjjg4vmjIfmlbAw44Gv5a6M5YWo44Gq5bmz562J44KS6KGo44GX44CB5oyH5pWwMTAw44Gv5a6M5YWo44Gq5LiN5bmz562J44KS5oSP5ZGz44GZ44KL44CCCgotICAgSW5jb21lIHNoYXJlIGhlbGQgYnkgbG93ZXN0IDEwJe+8mlNJLkRTVC5GUlNULjEwIFtbTGlua10oaHR0cHM6Ly9kYXRhYmFuay53b3JsZGJhbmsub3JnL21ldGFkYXRhZ2xvc3Nhcnkvd29ybGQtZGV2ZWxvcG1lbnQtaW5kaWNhdG9ycy9zZXJpZXMvU0kuRFNULkZSU1QuMTApXQoKICAgIC0gICBQZXJjZW50YWdlIHNoYXJlIG9mIGluY29tZSBvciBjb25zdW1wdGlvbiBpcyB0aGUgc2hhcmUgdGhhdCBhY2NydWVzIHRvIHN1Ymdyb3VwcyBvZiBwb3B1bGF0aW9uIGluZGljYXRlZCBieSBkZWNpbGVzIG9yIHF1aW50aWxlcy4KCiAgICAtICAg5omA5b6X44G+44Gf44Gv5raI6LK744Gu5Ymy5ZCI44Gv44CB44OH44K344Or44G+44Gf44Gv5LqU5YiG5L2N5pWw44Gn56S644GV44KM44KL5Lq65Y+j44Gu44K144OW44Kw44Or44O844OX44Gr55m655Sf44GZ44KL5Ymy5ZCI44Gn44GZ44CCCgotICAgSW5jb21lIHNoYXJlIGhlbGQgYnkgbG93ZXN0IDIwJe+8mlNJLkRTVC5GUlNULjIwIFtbTGlua10oaHR0cHM6Ly9kYXRhYmFuay53b3JsZGJhbmsub3JnL21ldGFkYXRhZ2xvc3Nhcnkvd29ybGQtZGV2ZWxvcG1lbnQtaW5kaWNhdG9ycy9zZXJpZXMvU0kuRFNULkZSU1QuMjApXQoKICAgIC0gICBQZXJjZW50YWdlIHNoYXJlIG9mIGluY29tZSBvciBjb25zdW1wdGlvbiBpcyB0aGUgc2hhcmUgdGhhdCBhY2NydWVzIHRvIHN1Ymdyb3VwcyBvZiBwb3B1bGF0aW9uIGluZGljYXRlZCBieSBkZWNpbGVzIG9yIHF1aW50aWxlcy4gUGVyY2VudGFnZSBzaGFyZXMgYnkgcXVpbnRpbGUgbWF5IG5vdCBzdW0gdG8gMTAwIGJlY2F1c2Ugb2Ygcm91bmRpbmcuCgogICAgLSAgIOaJgOW+l+OBvuOBn+OBr+a2iOiyu+OBruWJsuWQiOOBr+OAgeODh+OCt+ODq+OBvuOBn+OBr+S6lOWIhuS9jeaVsOOBp+ekuuOBleOCjOOCi+S6uuWPo+OBruOCteODluOCsOODq+ODvOODl+OBq+eZuueUn+OBmeOCi+WJsuWQiOOBp+OBmeOAguS6lOWIhuS9jeaVsOOBq+OCiOOCi+OCt+OCp+OCouOBruWJsuWQiOOBr+OAgeWbm+aNqOS6lOWFpeOBruOBn+OCgTEwMOOBq+OBquOCieOBquOBhOWgtOWQiOOBjOOBguOCiuOBvuOBmeOAgihBcHBsZSkKCi0gICBJbmNvbWUgc2hhcmUgaGVsZCBieSBzZWNvbmQgMjAl77yaU0kuRFNULjAyTkQuMjAgW1tMaW5rXShodHRwczovL2RhdGFiYW5rLndvcmxkYmFuay5vcmcvbWV0YWRhdGFnbG9zc2FyeS93b3JsZC1kZXZlbG9wbWVudC1pbmRpY2F0b3JzL3Nlcmllcy9TSS5EU1QuMDJORC4yMCldCgogICAgLSAgIFBlcmNlbnRhZ2Ugc2hhcmUgb2YgaW5jb21lIG9yIGNvbnN1bXB0aW9uIGlzIHRoZSBzaGFyZSB0aGF0IGFjY3J1ZXMgdG8gc3ViZ3JvdXBzIG9mIHBvcHVsYXRpb24gaW5kaWNhdGVkIGJ5IGRlY2lsZXMgb3IgcXVpbnRpbGVzLiBQZXJjZW50YWdlIHNoYXJlcyBieSBxdWludGlsZSBtYXkgbm90IHN1bSB0byAxMDAgYmVjYXVzZSBvZiByb3VuZGluZy4KCiAgICAtICAg5omA5b6X44G+44Gf44Gv5raI6LK744Gr5Y2g44KB44KL5Ymy5ZCI44Gv44CBMTDliIbkvY3jgb7jgZ/jga815YiG5L2N44Gn56S644GV44KM44KL5Lq65Y+j44Gu44K144OW44Kw44Or44O844OX44Gr5biw5bGe44GZ44KL5Ymy5ZCI44Gn44GC44KL44CC5Zub5o2o5LqU5YWl44Gu6Zai5L+C5LiK44CB5LqU5YiG5L2N6ZqO57Sa5Yil44Gu5Ymy5ZCI44Gu5ZCI6KiI44GMMTAw44Gr44Gq44KJ44Gq44GE5aC05ZCI44GM44GC44KL44CC77yIRGVlcEzvvIkKCi0gICBJbmNvbWUgc2hhcmUgaGVsZCBieSB0aGlyZCAyMCXvvJpTSS5EU1QuMDNSRC4yMCBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TSS5EU1QuMDNSRC4yMCldCgogICAgLSAgIFBlcmNlbnRhZ2Ugc2hhcmUgb2YgaW5jb21lIG9yIGNvbnN1bXB0aW9uIGlzIHRoZSBzaGFyZSB0aGF0IGFjY3J1ZXMgdG8gc3ViZ3JvdXBzIG9mIHBvcHVsYXRpb24gaW5kaWNhdGVkIGJ5IGRlY2lsZXMgb3IgcXVpbnRpbGVzLiBQZXJjZW50YWdlIHNoYXJlcyBieSBxdWludGlsZSBtYXkgbm90IHN1bSB0byAxMDAgYmVjYXVzZSBvZiByb3VuZGluZy4KCiAgICAtICAg5omA5b6X44G+44Gf44Gv5raI6LK744Gr5Y2g44KB44KL5Ymy5ZCI44Gv44CBMTDliIbkvY3jgb7jgZ/jga815YiG5L2N44Gn56S644GV44KM44KL5Lq65Y+j44Gu44K144OW44Kw44Or44O844OX44Gr5biw5bGe44GZ44KL5Ymy5ZCI44Gn44GC44KL44CC5Zub5o2o5LqU5YWl44Gu6Zai5L+C5LiK44CB5LqU5YiG5L2N6ZqO57Sa5Yil44Gu5Ymy5ZCI44Gu5ZCI6KiI44GMMTAw44Gr44Gq44KJ44Gq44GE5aC05ZCI44GM44GC44KL44CC77yIRGVlcEzvvIkKCi0gICBJbmNvbWUgc2hhcmUgaGVsZCBieSBmb3VydGggMjAl77yaU0kuRFNULjA0VEguMjAgW1tMaW5rXShodHRwczovL2RhdGFiYW5rLndvcmxkYmFuay5vcmcvbWV0YWRhdGFnbG9zc2FyeS93b3JsZC1kZXZlbG9wbWVudC1pbmRpY2F0b3JzL3Nlcmllcy9TSS5EU1QuMDRUSC4yMCldCgogICAgLSAgIFBlcmNlbnRhZ2Ugc2hhcmUgb2YgaW5jb21lIG9yIGNvbnN1bXB0aW9uIGlzIHRoZSBzaGFyZSB0aGF0IGFjY3J1ZXMgdG8gc3ViZ3JvdXBzIG9mIHBvcHVsYXRpb24gaW5kaWNhdGVkIGJ5IGRlY2lsZXMgb3IgcXVpbnRpbGVzLiBQZXJjZW50YWdlIHNoYXJlcyBieSBxdWludGlsZSBtYXkgbm90IHN1bSB0byAxMDAgYmVjYXVzZSBvZiByb3VuZGluZy4KCiAgICAtICAg5omA5b6X44G+44Gf44Gv5raI6LK744Gu5Ymy5ZCI44Gv44CB5Y2B5YiG5L2N5pWw44G+44Gf44Gv5LqU5YiG5L2N5pWw44Gn56S644GV44KM44KL5Lq65Y+j44Gu44K144OW44Kw44Or44O844OX44Gr55Sf44GY44KL5Ymy5ZCI44Gn44GZ44CC5Zub5o2o5LqU5YWl44Gu44Gf44KB44CB5LqU5YiG5L2N5Yil44Gu5Ymy5ZCI44Gu5ZCI6KiI44GMIDEwMCDjgavjgarjgonjgarjgYTloLTlkIjjgYzjgYLjgorjgb7jgZnjgIIoR29vZ2xlKQoKLSAgIEluY29tZSBzaGFyZSBoZWxkIGJ5IGhpZ2hlc3QgMjAl77yaU0kuRFNULjA1VEguMjAgW1tMaW5rXShodHRwczovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvU0kuRFNULjA1VEguMjApXQoKICAgIC0gICBQZXJjZW50YWdlIHNoYXJlIG9mIGluY29tZSBvciBjb25zdW1wdGlvbiBpcyB0aGUgc2hhcmUgdGhhdCBhY2NydWVzIHRvIHN1Ymdyb3VwcyBvZiBwb3B1bGF0aW9uIGluZGljYXRlZCBieSBkZWNpbGVzIG9yIHF1aW50aWxlcy4gUGVyY2VudGFnZSBzaGFyZXMgYnkgcXVpbnRpbGUgbWF5IG5vdCBzdW0gdG8gMTAwIGJlY2F1c2Ugb2Ygcm91bmRpbmcuCgogICAgLSAgIOaJgOW+l+OBvuOBn+OBr+a2iOiyu+OBruWJsuWQiOOBr+OAgeWNgeWIhuS9jeaVsOOBvuOBn+OBr+S6lOWIhuS9jeaVsOOBp+ekuuOBleOCjOOCi+S6uuWPo+OBruOCteODluOCsOODq+ODvOODl+OBq+eUn+OBmOOCi+WJsuWQiOOBp+OBmeOAguWbm+aNqOS6lOWFpeOBruOBn+OCgeOAgeS6lOWIhuS9jeWIpeOBruWJsuWQiOOBruWQiOioiOOBjCAxMDAg44Gr44Gq44KJ44Gq44GE5aC05ZCI44GM44GC44KK44G+44GZ44CCCgotICAgSW5jb21lIHNoYXJlIGhlbGQgYnkgaGlnaGVzdCAxMCXvvJpTSS5EU1QuMTBUSC4xMCBbW0xpbmtdKGh0dHBzOi8vZGF0YS53b3JsZGJhbmsub3JnL2luZGljYXRvci9TSS5EU1QuMTBUSC4xMCldCgogICAgLSAgIFBlcmNlbnRhZ2Ugc2hhcmUgb2YgaW5jb21lIG9yIGNvbnN1bXB0aW9uIGlzIHRoZSBzaGFyZSB0aGF0IGFjY3J1ZXMgdG8gc3ViZ3JvdXBzIG9mIHBvcHVsYXRpb24gaW5kaWNhdGVkIGJ5IGRlY2lsZXMgb3IgcXVpbnRpbGVzLgoKICAgIC0gICDmiYDlvpfjgb7jgZ/jga/mtojosrvjga7libLlkIjjga/jgIHljYHliIbkvY3mlbDjgb7jgZ/jga/kupTliIbkvY3mlbDjgafnpLrjgZXjgozjgovkurrlj6Pjga7jgrXjg5bjgrDjg6vjg7zjg5fjgavnlJ/jgZjjgovlibLlkIjjgafjgZnjgIIKCiMjIOWGheWuuQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFdESSkKYGBgCgpgYGB7ciBldmFsID0gRkFMU0V9CmRmX2dpbmkgPC0gV0RJKGluZGljYXRvciA9IGMoZ2luaSA9ICJTSS5QT1YuR0lOSSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMC0xMGAgPSAiU0kuRFNULkZSU1QuMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYDAtMjBgID0gIlNJLkRTVC5GUlNULjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAyMC00MGAgPSAiU0kuRFNULjAyTkQuMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYDQwLTYwYCA9ICJTSS5EU1QuMDNSRC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBgNjAtODBgID0gIlNJLkRTVC4wNFRILjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGA4MC0xMDBgID0gIlNJLkRTVC4wNVRILjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGA5MC0xMDBgID0gIlNJLkRTVC4xMFRILjEwIikpCmBgYAoKYGBge3J9CmRmX2dpbmkKYGBgCgpgYGB7ciBldmFsID0gRkFMU0V9CndyaXRlX2NzdihkZl9naW5pLCAiZGF0YS9naW5pLmNzdiIpCmBgYAoKYGBge3J9CmRmX2dpbmkgPC0gcmVhZF9jc3YoImRhdGEvZ2luaS5jc3YiKQpgYGAKCmBgYHtyfQpkZl9naW5pX2xvbmcgPC0gZGZfZ2luaSB8PiAKICBwaXZvdF9sb25nZXIoLSgxOjUpLCBuYW1lc190byA9ICJsZXZlbHMiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpkZl9naW5pX2xvbmcKYGBgCgrjganjga7jgY/jgonjgYQgR0lOSSDjga7jg4fjg7zjgr/jgYzjgYLjgovjgYvnorrjgYvjgoHjgosKCmBgYHtyfQpkZl9naW5pIHw+IGdyb3VwX2J5KHllYXIpIHw+IGRyb3BfbmEoZ2luaSkgfD4gCiAgc3VtbWFyaXplKG4gPSBuKCkpIHw+CiAgZ2dwbG90KGFlcyh5ZWFyLCBuKSkgKyBnZW9tX2NvbCgpCmBgYAoK5a6f6Zqb44Gu44OH44O844K/44Gu5YCL5pWw44KC6KiI566X44GX44Gm44G/44KL44CCCgpgYGB7cn0KZGZfZ2luaV9sb25nIHw+IAogIGdyb3VwX2J5KHllYXIsIGxldmVscykgfD4gZHJvcF9uYSh2YWx1ZSkgfD4KICBzdW1tYXJpemUobnVtID0gbigpKSB8PiBkaXN0aW5jdCh5ZWFyLCBudW0pIHw+IGFycmFuZ2UoZGVzYyh5ZWFyKSkKYGBgCgpHSU5J44Gg44GR44Gn44Gq44GP44CB5LuW44Gu5YCk44Gr44Gk44GE44Gm44KC6Kq/44G544KL44CCCgpgYGB7cn0KZGZfZ2luaV9sb25nIHw+IAogIGdyb3VwX2J5KHllYXIsIGxldmVscykgfD4gZHJvcF9uYSh2YWx1ZSkgfD4KICBzdW1tYXJpemUobnVtID0gbigpKSB8PiBkaXN0aW5jdCh5ZWFyLCBudW0pIHw+IAogIGdncGxvdChhZXMoeWVhciwgbnVtKSkgKyBnZW9tX2NvbCgpCmBgYAoKMjAyMuW5tOOBr+OAgTfjgqvlm73liIbjgZfjgYvjg4fjg7zjgr/jgYzjgarjgYTjgYzjgZ3jga7lm73lkI3jgpLooajnpLrjgZnjgovjgIIKCmBgYHtyfQpkZl9naW5pX2xvbmcgfD4gZmlsdGVyKHllYXIgPT0gMjAyMikgfD4gZHJvcF9uYShnaW5pKSB8PgogIGRpc3RpbmN0KGNvdW50cnksIGdpbmkpCmBgYAoKYGBge3J9CkNPVU5UUllfR0lOSSA8LSAiQmFuZ2xhZGVzaCIKWUVBUl9HSU5JIDwtIDIwMjIKZGZfZ2luaV9sb25nIHw+IAogIGZpbHRlcihjb3VudHJ5ID09IENPVU5UUllfR0lOSSwgeWVhciA9PSBZRUFSX0dJTkkpIHw+CiAgZ2dwbG90KGFlcyhsZXZlbHMsIHZhbHVlKSkgKyBnZW9tX2NvbCgpCmBgYAoKYGBge3J9CkNPVU5UUllfR0lOSSA8LSAiQmh1dGFuIgpZRUFSX0dJTkkgPC0gMjAyMgpkZl9naW5pX2xvbmcgfD4gCiAgZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWV9HSU5JLCB5ZWFyID09IFlFQVJfR0lOSSkgfD4KICBnZ3Bsb3QoYWVzKGxldmVscywgdmFsdWUpKSArIGdlb21fY29sKCkKYGBgCgpgYGB7cn0KQ09VTlRSWV9HSU5JIDwtICJDb3N0YSBSaWNhIgpZRUFSX0dJTkkgPC0gMjAyMgpkZl9naW5pX2xvbmcgfD4gCiAgZmlsdGVyKGNvdW50cnkgPT0gQ09VTlRSWV9HSU5JLCB5ZWFyID09IFlFQVJfR0lOSSkgfD4KICBnZ3Bsb3QoYWVzKGxldmVscywgdmFsdWUpKSArIGdlb21fY29sKCkKYGBgCgojIyBHSU5JIOOBo+OBpuS9le+8ge+8nwoKKirjgrjjg4vkv4LmlbAqKu+8iOOCuOODi+OBkeOBhOOBmeOBhuOAgVvoi7FdKGh0dHBzOi8vamEud2lraXBlZGlhLm9yZy93aWtpLyVFOCU4QiVCMSVFOCVBQSU5RSAi6Iux6KqeIik6wqBHaW5pIGNvZWZmaWNpZW5077yJ44Go44Gv5Li744Gr56S+5Lya44Gr44GK44GR44KL5omA5b6X44Gu5LiN5bmz562J44GV44KS5ris44KL5oyH5qiZ44Gn44GC44KL44CCMOOBi+OCiTHjgafooajjgZXjgozjgIHlkITkurrjga7miYDlvpfjgYzlnYfkuIDjgafmoLzlt67jgYzlhajjgY/jgarjgYTnirbmhYvjgpIw44CB44Gf44Gj44Gf5LiA5Lq644GM5YWo44Gm44Gu5omA5b6X44KS54us5Y2g44GX44Gm44GE44KL54q25oWL44KSMeOBqOOBmeOCi+OAguODreODvOODrOODs+ODhOabsue3muOCkuOCguOBqOOBq+OAgTE5MTLlubTjgavjgqTjgr/jg6rjgqLjga7ntbHoqIjlrabogIXjgIHjgrPjg4Pjg6njg4njg7vjgrjjg4vjgavjgojjgaPjgabogIPmoYjjgZXjgozjgZ/jgILjgZ3jgozku6XlpJbjgavjgoLjgIHlr4zjga7lgY/lnKjmgKfjgoTjgqjjg43jg6vjgq7jg7zmtojosrvjgavjgYrjgZHjgovkuI3lubPnrYnjgZXjgarjganjgavlv5znlKjjgZXjgozjgovjgILvvIhXaWtpcGVkaWHvvIkKCiFbXShpbWFnZXMvY2xpcGJvYXJkLTcxOTg4Njg1NS5wbmcpCgrjgrjjg4vkv4LmlbDjga7jgrDjg6njg5Ug44K444OL5L+C5pWw44Gv44CBKkEq44Gu6Z2i56mN44KSKkEq44GoKkIq44Gu5ZCE6Z2i56mN44Gu5ZCI6KiI44Gn5Ymy44Gj44Gf44KC44Gu44Gr562J44GX44GE44CC44GZ44Gq44KP44Gh44CB44K444OL5L+C5pWwID0qQSov77yIKkEqKypCKu+8ieOBqOOBquOCi+OAguOBvuOBn+OAgSpBKisqQio9MC4144Gu44Gf44KB44CBMsOXKkEq44Gr44KC562J44GX44GE77yI57im6Lu444GvMOOBqDHjga7plpPjga7lgKTjgpLjgajjgovjgZ/jgoHvvIkKCiFbXShpbWFnZXMvY2xpcGJvYXJkLTQzNjU1NDM2OC5wbmcpCgpEZXJpdmF0aW9uIG9mIHRoZSBMb3JlbnogY3VydmUgYW5kIEdpbmkgY29lZmZpY2llbnQgZm9yIGdsb2JhbCBpbmNvbWUgaW4gMjAxMSBbW+ODquODs+OCr10oaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy9lL2U3L0xvcmVuel9jdXJ2ZV9nbG9iYWxfaW5jb21lXzIwMTEuc3ZnKV0KCmBgYHtyfQpkZl9naW5pX2NhbGMgPC0gZGZfZ2luaSB8PiAKICBtdXRhdGUoYDBgID0gMCwgYDEwYCA9IGAwLTEwYCwgYDIwYCA9IGAwLTIwYCwgYDQwYCA9IGAwLTIwYCArIGAyMC00MGAsIGA2MGAgPSBgMC0yMGAgKyBgMjAtNDBgICsgYDQwLTYwYCwgYDgwYCA9IGAwLTIwYCArIGAyMC00MGAgKyBgNDAtNjBgICsgYDYwLTgwYCwgYDkwYCA9IGAwLTIwYCArIGAyMC00MGAgKyBgNDAtNjBgICsgYDYwLTgwYCArIGA4MC0xMDBgLWA5MC0xMDBgLCBgMTAwYCA9IDEwMCkgCmRmX2dpbmlfY2FsYyAlPiUgZHJvcF9uYSgpIHw+IGZpbHRlcihjb3VudHJ5ID09ICJCYW5nbGFkZXNoIikKYGBgCgpgYGB7cn0KZGZfZ2luaV9jYWxjX2xvbmcgPC0gZGZfZ2luaV9jYWxjIHw+ICBwaXZvdF9sb25nZXIoYDBgOmAxMDBgLCBuYW1lc190byA9ICJjbGFzc2VzIiwgdmFsdWVzX3RvID0gImN1bXVsYXRpdmVfc2hhcmUiKSB8PiBtdXRhdGUoY2xhc3NlcyA9IGFzLm51bWVyaWMoY2xhc3NlcykpCmRmX2dpbmlfY2FsY19sb25nICU+JSBkcm9wX25hKCkgfD4gZmlsdGVyKGNvdW50cnkgPT0gIkJhbmdsYWRlc2giKQpgYGAKCueiuuiqjQoKYGBge3J9CmRmX2dpbmlfY2FsY19sb25nIHw+IGZpbHRlcihjb3VudHJ5ID09ICJCYW5nbGFkZXNoIikgfD4gCiAgZmlsdGVyKHllYXIgPT0gMjAyMikgfD4gZ2dwbG90KCkgKyBnZW9tX2xpbmUoYWVzKGNsYXNzZXMsIGN1bXVsYXRpdmVfc2hhcmUpKSArIGdlb21fc2VnbWVudChhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gMTAwLCB5ZW5kID0gMTAwKSwgY29sb3IgPSAncmVkJykgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwLGJ5PTIwKSkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTAwLGJ5PTIwKSkgIysKICAjYW5ub3RhdGUoInRleHQiLCB4ID0gMTAsIHkgPSA4MCwgbGFiZWwgPSBnaW5pKQpgYGAKClNoYWRlIHJlZ2lvbiBiZXR3ZWVuIHR3byBsaW5lcyB3aXRoIGdncGxvdDogW1vjg6rjg7Pjgq9dKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzI4NTg2NjM1L3NoYWRlLXJlZ2lvbi1iZXR3ZWVuLXR3by1saW5lcy13aXRoLWdncGxvdCldCgpgYGB7cn0KZGZfZ2luaV9jYWxjIHw+IGdyb3VwX2J5KGNvdW50cnksIHllYXIpIHw+IAogIGRyb3BfbmEoZ2luaSkgfD4KICBzdW1tYXJpemUoZ2luaSwgZ2luaV90cmFwZXpvaWQgPSAxMDAtKDIqYDEwYCArIDMqYDIwYCArIDQqYDQwYCArIDQqYDYwYCArIDMqYDgwYCArIDIqYDkwYCArIDEwMCkvMTApIHw+IAogIGRpc3RpbmN0KGNvdW50cnksIHllYXIsIGdpbmksIGdpbmlfdHJhcGV6b2lkKQpgYGAKCmBgYHtyfQojIyMjIEZvciB0aGUgY2FsY3VhbHRpb24gb2YgdGhlIGFyZWEgdW5kZXIgdGhlIGN1cnZlCiAgICAjIyMjIFRyYXBlem9pZGFsIHJ1bGUKICAgIHRyYXBlem9pZCA8LSBmdW5jdGlvbih4LCB5KSB7CiAgICAgICAgICAgICAgICAgICAgIHN1bShkaWZmKHgpKih5Wy0xXSt5Wy1sZW5ndGgoeSldKSkvMgogICAgICAgICAgICAgICAgIH0KICAgICMjIyMgU2ltcHNvbidzIHJ1bGU6IG1vcmUgYWNjdXJhdGUKICAgIHNpbXBzb24gPC0gZnVuY3Rpb24oeCwgeSl7CiAgICAgICAgICAgICAgICAgICBuIDwtIGxlbmd0aCh5KQogICAgICAgICAgICAgICAgICAgb2RkIDwtIG4gJSUgMgogICAgICAgICAgICAgICAgICAgaWYgKG9kZCkKICAgICAgICAgICAgICAgICAgICAgICBhcmVhIDwtIDEvMypzdW0oIHlbMV0gKyAyKnN1bSh5W3NlcSgzLChuLTIpLGJ5PTIpXSkgKyA0KnN1bSh5W3NlcSgyLChuLTEpLGJ5PTIpXSkgKyB5W25dKQogICAgICAgICAgICAgICAgICAgaWYgKCFvZGQpCiAgICAgICAgICAgICAgICAgICAgICAgYXJlYSA8LSAxLzMqc3VtKCB5WzFdICsgMipzdW0oeVtzZXEoMywobi0zKSxieT0yKV0pICsgNCpzdW0oeVtzZXEoMiwobi0yKSxieT0yKV0pICsgeVtuLTFdKSArIDEvMiooeVtuLTFdICsgeVtuXSkKICAgICAgICAgICAgICAgICAgIGR4IDwtIHhbMl0gLSB4WzFdCiAgICAgICAgICAgICAgICAgICByZXR1cm4oYXJlYSAqIGR4KQogICAgfQogICAgClNJTVBTT04gPC0gZnVuY3Rpb24oeCwgaD0xKXsKICAjIEFVQyBmdW5jdGlvbiBjb21wdXRlcyB0aGUgQXJlYSBVbmRlciB0aGUgQ3VydmUgb2YgYSB0aW1lIHNlcmllIHVzaW5nCiAgIyB0aGUgU2ltcHNvbidzIFJ1bGUgKG51bWVyaWNhbCBtZXRob2QpLgogICMgaHR0cHM6Ly9saW5rLnNwcmluZ2VyLmNvbS9jaGFwdGVyLzEwLjEwMDcvOTc4LTEtNDYxMi00OTc0LTBfMjYKICAKICAjIEFyZ3VtZW50cwogICMgeDogKHZlY3RvcikgdGltZSBzZXJpZSB2YWx1ZXMKICAjIGg6IChpbnQpIHRlbXBvcmFsIHJlc29sdXRpb24gb2YgdGhlIHRpbWUgc2VyaWUuIGRlZmF1bHQgaD0xCiAgCiAgbiA9IGxlbmd0aCh4KS0xCiAgCiAgeFZhbHVlcyA9IHNlcShmcm9tPTEsIHRvPW4sIGJ5PTIpCiAgCiAgc3VtIDwtIGxpc3QoKQogIGZvcihpIGluIDE6bGVuZ3RoKHhWYWx1ZXMpKXsKICAgIG5fc3ViIDwtIHhWYWx1ZXNbW2ldXS0xCiAgICBuIDwtIHhWYWx1ZXNbW2ldXQogICAgbl9hZGQgPC0geFZhbHVlc1tbaV1dKzEKICAgIAogICAgdjEgPC0geFtbbl9zdWIrMV1dCiAgICB2MiA8LSB4W1tuKzFdXQogICAgdjMgPC0geFtbbl9hZGQrMV1dCiAgICAKICAgIHMgPC0gKGgvMykqKHYxKzQqdjIrdjMpCiAgICBzdW0gPC0gYXBwZW5kKHN1bSwgcykKICB9CiAgc3VtIDwtIHVubGlzdChzdW0pCiAgCiAgYXVjIDwtIHN1bShzdW0pCiAgCiAgcmV0dXJuKGF1YykKICAKfQpgYGAKCmBgYHtyfQpzaW1wc29uKGMoMCwwLjIsMC40LDAuNiwwLjgsMSksYygwLDAuMDQsMC4xNiwwLjM2LDAuNjQsMSkpCmBgYAoKYGBge3J9CmxpYnJhcnkoRGVzY1Rvb2xzKQpgYGAKCkFyZWEgVW5kZXIgdGhlIEN1cnZlOiBbW+ODquODs+OCr10oaHR0cHM6Ly9zZWFyY2guci1wcm9qZWN0Lm9yZy9DUkFOL3JlZm1hbnMvRGVzY1Rvb2xzL2h0bWwvQVVDLmh0bWwpXQoKPGh0dHBzOi8vcmRyci5pby9jcmFuL0Rlc2NUb29scy9mLz4KCmBgYHtyfQpkZl9naW5pX2NhbGNfbG9uZyB8PiBncm91cF9ieShjb3VudHJ5LCB5ZWFyKSB8PiAKICBkcm9wX25hKGdpbmkpIHw+CiAgc3VtbWFyaXplKGdpbmksIGdpbmlfc3BsaW5lID0gcm91bmQoMTAwLUFVQyhjbGFzc2VzLCBjdW11bGF0aXZlX3NoYXJlLCBtZXRob2QgPSAic3BsaW5lIikvNTAsIGRpZ2l0cyA9IDEpLCBnaW5pX3RyYXBlem9pZCA9IHJvdW5kKDEwMC1BVUMoY2xhc3NlcywgY3VtdWxhdGl2ZV9zaGFyZSkvNTAsIGRpZ2l0cyA9IDEpLCBnaW5pX3NpbXBzb24gPSByb3VuZCgxMDAgLSBzaW1wc29uKGNsYXNzZXMsIGN1bXVsYXRpdmVfc2hhcmUpLzUwLCBkaWdpdHMgPSAxKSkgfD4gCiAgZGlzdGluY3QoY291bnRyeSwgeWVhciwgZ2luaSwgZ2luaV9zcGxpbmUsIGdpbmlfdHJhcGV6b2lkLCBnaW5pX3NpbXBzb24pCmBgYAoKYGBge3J9CmRmX2dpbmlfY2FsY19sb25nIHw+IGdyb3VwX2J5KGNvdW50cnksIHllYXIpIHw+IAogIGRyb3BfbmEoZ2luaSkgfD4KICBzdW1tYXJpemUoZ2luaSwgZ2luaV9zcGxpbmUgPSByb3VuZCgxMDAtQVVDKGNsYXNzZXMsIGN1bXVsYXRpdmVfc2hhcmUsIG1ldGhvZCA9ICJzcGxpbmUiKS81MCwgZGlnaXRzID0gMSksIGdpbmlfdHJhcGV6b2lkID0gcm91bmQoMTAwLUFVQyhjbGFzc2VzLCBjdW11bGF0aXZlX3NoYXJlKS81MCwgZGlnaXRzID0gMSksIGdpbmlfc2ltcHNvbiA9IHJvdW5kKDEwMCAtIHNpbXBzb24oY2xhc3NlcywgY3VtdWxhdGl2ZV9zaGFyZSkvNTAsIGRpZ2l0cyA9IDEpKSB8PiAKICBkaXN0aW5jdChjb3VudHJ5LCB5ZWFyLCBnaW5pLCBnaW5pX3NwbGluZSwgZ2luaV90cmFwZXpvaWQsIGdpbmlfc2ltcHNvbikKYGBgCgpBVUM6IENhbGN1bGF0aW5nIEFyZWEgdW5kZXIgYSBDdXJ2ZSBbW+ODquODs+OCr10oaHR0cHM6Ly93d3cuc21pbjk1LmNvbS9kYXRhdml6L2NhbGN1bGF0aW5nLWFyZWEtdW5kZXItYS1jdXJ2ZSNjYWxjdWxhdGluZy1hcmVhLXVuZGVyLWEtY3VydmUpXQoKPGh0dHBzOi8vd3d3LnN0YXRzZGlyZWN0LmNvbS9oZWxwL2RlZmF1bHQuaHRtI25vbnBhcmFtZXRyaWNfbWV0aG9kcy9naW5pLmh0bT4KCiMjIyBHSU5JIENhbGN1bGF0b3IKCngg44Gr44CB5pWw44Gu5YiX44KS5YWl44KM44KL44Go44Gd44Gu5YiG6YWN44Gr6Zai44GZ44KL44CBR0lOSSDjgpLoqIjnrpfjgZfjgb7jgZnjgIIKCmBgYHtyfQp4IDwtIGMoMSwxLDEsNCwxMCkKTGMoeClbYygxLDIpXSB8PiBhcy50aWJibGUoKSB8PiBtdXRhdGUoZCA9IHAsIC5hZnRlciA9IDEpIHw+IAogIHBpdm90X2xvbmdlcigtMSwgbmFtZXNfdG8gPSAibmFtZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpIHw+CiAgZ2dwbG90KGFlcyhwLCB2YWx1ZSwgZmlsbCA9IG5hbWUpKSArIGdlb21fYXJlYShwb3NpdGlvbiA9ICJpZGVudGl0eSIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAwLjI1LCB5ID0gMC43NSwgbGFiZWwgPSBwYXN0ZSgiR0lOSSA9ICIscm91bmQoTGMoeCkkR2luaSwgZGlnaXRzID0gMikpKQpgYGAKCmBgYHtyfQpTRVIgPC0gYygwLDUsMywxLDEpClNFUjEgPC0gYygwLHNvcnQoU0VSKSkKU0VSMQpOID0gbGVuZ3RoKFNFUjEpClkgPC0gMDpOL047IFkKYGBgCgrlrprnvqnjgavjgoLjganjgaPjgabopoHnorroqo0KCmBgYHtyfQpkZl9naW5pX2xvbmcgfD4gZmlsdGVyKHllYXIgPT0gMjAyMikgfD4gZHJvcF9uYShnaW5pKQpgYGAKCuS7luOBruimi+OBm+aWueOBq+S/ruatowoKYGBge3J9CmRmX2dpbmlfbG9uZyB8PiBmaWx0ZXIoeWVhciA9PSAyMDIyKSB8PiBkcm9wX25hKGdpbmkpIHw+CiAgZ2dwbG90KGFlcyh4ID0gbGV2ZWxzLCB5ID0gYWRqLCBjb2wgPSBjb3VudHJ5KSkgKyBnZW9tX2xpbmUoKQpgYGAKCuWSjOOCkuOBqOOBo+OBn+OCguOBruOCkuioiOeul+OBl+OBquOBhOOBqOOBhOOBkeOBquOBhOOAguS7peS4i+OBr+OBguOBqOOBp+WIqeeUqAoKYGBge3IgZXZhbCA9IEZBTFNFfQpkZl9naW5pX2xvbmcgPC0gZGZfZ2luaSB8PiAKICBwaXZvdF9sb25nZXIoLSgxOjUpLCBuYW1lc190byA9ICJsZXZlbHMiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSB8PgogIG11dGF0ZShsZXZlbHMgPSBhcy5udW1lcmljKGxldmVscykpIHw+IAogIG11dGF0ZShjdXQgPSBjYXNlX3doZW4obGV2ZWxzID09IDUgfiAnMC0xMCcsCiAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPT0gMTAgfiAnMC0yMCcsCiAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPT0gMzAgfiAnMjAtNDAnLAogICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID09IDUwIH4gJzQwLTYwJywKICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9PSA3MCB+ICc2MC04MCcsCiAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPT0gOTAgfiAnODAtMTAwJywKICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9PSA5NSB+ICc5MC0xMDAnKSwKICAgICAgICAgYWRqID0gY2FzZV93aGVuKGxldmVscyA9PSA1IH4gdmFsdWUqMiwKICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9PSA5NSB+IHZhbHVlKjIsCiAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IHZhbHVlKSkKZGZfZ2luaV9sb25nCmBgYAoKYGBge3J9CmRmX2dpbmlfcmV2IDwtIFdESShpbmRpY2F0b3IgPSBjKGdpbmkgPSAiU0kuUE9WLkdJTkkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgJzAtMTAnID0gIlNJLkRTVC5GUlNULjEwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICcwLTIwJyA9ICJTSS5EU1QuRlJTVC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnMjAtNDAnID0gIlNJLkRTVC4wMk5ELjIwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICc0MC02MCcgPSAiU0kuRFNULjAzUkQuMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgJzYwLTgwJyA9ICJTSS5EU1QuMDRUSC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnODAtMTAwJyA9ICJTSS5EU1QuMDVUSC4yMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnOTAtMTAwJyA9ICJTSS5EU1QuMTBUSC4xMCIpKQpgYGAKCmBgYHtyfQpkZl9naW5pX3Jldl9sb25nIDwtIGRmX2dpbmlfcmV2IHw+IAogIHBpdm90X2xvbmdlcigtKDE6NSksIG5hbWVzX3RvID0gImxldmVscyIsIHZhbHVlc190byA9ICJ2YWx1ZSIpCmRmX2dpbmlfcmV2X2xvbmcKYGBgCgpgYGB7cn0KQ09VTlRSWV9HSU5JIDwtICJCYW5nbGFkZXNoIgpZRUFSX0dJTkkgPC0gMjAyMgpkZl9naW5pX3Jldl9sb25nIHw+IAogIGZpbHRlcihjb3VudHJ5ID09IENPVU5UUllfR0lOSSwgeWVhciA9PSBZRUFSX0dJTkkpIHw+CiAgZ2dwbG90KGFlcyhsZXZlbHMsIHZhbHVlKSkgKyBnZW9tX2NvbCgpCmBgYAoKYGBge3J9CmRmX2dpbmlfcmV2X2xvbmcyIDwtIGRmX2dpbmlfcmV2IHw+IGRyb3BfbmEoZ2luaSkgfD4gCiAgbXV0YXRlKCcwLTEwJyA9IGAwLTEwYCAqMiwgJzkwLTEwMCcgPSBgOTAtMTAwYCAqMikgfD4KICBwaXZvdF9sb25nZXIoLSgxOjUpLCBuYW1lc190byA9ICJsZXZlbHMiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpDT1VOVFJZX0dJTkkgPC0gIkJhbmdsYWRlc2giCllFQVJfR0lOSSA8LSAyMDIyCmRmX2dpbmlfcmV2X2xvbmcyIHw+IAogIGZpbHRlcihjb3VudHJ5ID09IENPVU5UUllfR0lOSSwgeWVhciA9PSBZRUFSX0dJTkkpIHw+CiAgZ2dwbG90KGFlcyhsZXZlbHMsIHZhbHVlKSkgKyBnZW9tX2NvbCgpCmBgYAoKYGBge3J9CkNPVU5UUklFU19HSU5JIDwtIGMoIkJodXRhbiIsICJCYW5nbGFkZXNoIiwiSW5kb25lc2lhIiwiQ29zdGEgUmljYSIpCllFQVJfR0lOSSA8LSAyMDIyCmRmX2dpbmlfcmV2X2xvbmcyIHw+IAogIGZpbHRlcihjb3VudHJ5ICVpbiUgQ09VTlRSSUVTX0dJTkksIHllYXIgPT0gWUVBUl9HSU5JKSB8PgogIGdncGxvdChhZXMobGV2ZWxzLCB2YWx1ZSwgZmlsbCA9IGZhY3Rvcihjb3VudHJ5LCBsZXZlbHMgPSBDT1VOVFJJRVNfR0lOSSkpKSArIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKyBsYWJzKGZpbGwgPSAiIikKYGBgCgpgYGB7cn0KWUVBUl9HSU5JIDwtIDIwMDAKZGZfZ2luaV9yZXYgfD4gCiAgZmlsdGVyKHllYXIgPT0gWUVBUl9HSU5JKSB8PiBkcm9wX25hKGdpbmkpIHw+CiAgZ2dwbG90KGFlcyhnaW5pLCBgOTAtMTAwYCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikKYGBgCgpgYGB7cn0KWUVBUl9HSU5JIDwtIDIwMDAKZGZfZ2luaV9yZXYgfD4gCiAgZmlsdGVyKHllYXIgPT0gWUVBUl9HSU5JKSB8PiBkcm9wX25hKGdpbmkpIHw+CiAgZ2dwbG90KGFlcyhnaW5pLCBgODAtMTAwYCkpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikKYGBgCgpgYGB7cn0KWUVBUl9HSU5JIDwtIDIwMDAKZGZfZ2luaV9yZXYgfD4gZmlsdGVyKHllYXIgPT0gWUVBUl9HSU5JKSB8PiBkcm9wX25hKGdpbmkpIHw+CiAgZ2dwbG90KGFlcyhnaW5pKSkgKyBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDUpCmBgYAoKIyMgVG8gRG8KCi0gICBleHRyYSA9IFRSVUUg44Gn5YiG5p6Q44KS5aeL44KB44KL5pa544GM44KI44GE44CCCgotICAgRGlzdHJpYnV0aW9uIOOCkuWkp+WIh+OBq+OBmeOCi+WbnuOBq+OBl+OBpuOCguOCiOOBhOOAggoKLSAgIHdlaWdodCDjgpLkvb/jgYjjgbDjgIFEZXNjVG9vbHM6Okdpbmkg44Gn44CBTG9yZW50eiBDdXJ2ZSDjgpLkvZzjgorlh7rjgZfjgIHjgZ3jgozjgYvjgonoqIjnrpfjgafjgY3jgovjgYvjgoLjgZfjgozjgarjgYTjga7jgafjgIHoqabjgZfjgabjgb/jgovjgIIKCi0gICDjgYTjgY/jgaTjgYvjga7jgIFMb3JlbnR6IOabsue3muOBqOOAgeOBneOBruS4i+OCkumAj+aYjuW6puOCkuOBpOOBkeOBpuOAgemHjeOBreWQiOOCj+OBmeOBk+OBqOOCkuODiOODqeOCpOOAggoKLSAgIDAtMTAsIDkwLTEwMCDjgavjgaTjgYTjgabjga7mibHjgYTjgpLjganjgYbjgZnjgovjgYvjgpLogIPjgYjjgovjgIIKCmBgYHtyfQpkZl9naW5pX3JldiB8PiBmaWx0ZXIoaXNvMmMgPT0gIklEIiwgeWVhciA9PSAyMDIyKQpgYGAKCmBgYHtyfQpkZl9naW5pX3JldiAgfD4gbXV0YXRlKCcxMC0yMCcgPSBgMC0yMGAtYDAtMTBgLCAuYmVmb3JlID0gYDAtMjBgKSB8PiBtdXRhdGUoJzgwLTkwJyA9IGA4MC0xMDBgLWA5MC0xMDBgLCAuYmVmb3JlID0gYDgwLTEwMGApIHw+IHNlbGVjdCgtYyhgMC0yMGAsIGA4MC0xMDBgKSkgfD4KICBmaWx0ZXIoaXNvMmMgPT0gIklEIiwgeWVhciA9PSAyMDIyKQpgYGAKCmBgYHtyfQpkZl9naW5pX3JldiAgfD4gbXV0YXRlKCcxMC0yMCcgPSBgMC0yMGAtYDAtMTBgLCAuYmVmb3JlID0gYDAtMjBgKSB8PiBtdXRhdGUoJzgwLTkwJyA9IGA4MC0xMDBgLWA5MC0xMDBgLCAuYmVmb3JlID0gYDgwLTEwMGApIHw+IHNlbGVjdCgtYyhgMC0yMGAsIGA4MC0xMDBgKSkgfD4KICBwaXZvdF9sb25nZXIoLSgxOjUpLCBuYW1lc190byA9ICJyYW5nZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpIHw+IAogIGZpbHRlcihpc28yYyA9PSAiSUQiLCB5ZWFyID09IDIwMjIpIHw+IHB1bGwoKSB8PiAKICBhcHBlbmQoMCwwKSB8PiBHaW5pKHdlaWdodHMgPSBjKDEsMSwxLDIsMiwyLDEsMSkpCmBgYAoKMzcuOQoKYGBge3J9CmRmX2dpbmlfcmV2ICB8PiBtdXRhdGUoJzEwLTIwJyA9IGAwLTIwYC1gMC0xMGAsIC5iZWZvcmUgPSBgMC0yMGApIHw+IG11dGF0ZSgnODAtOTAnID0gYDgwLTEwMGAtYDkwLTEwMGAsIC5iZWZvcmUgPSBgODAtMTAwYCkgfD4gc2VsZWN0KC1jKGAwLTIwYCwgYDgwLTEwMGApKSB8PgogIHBpdm90X2xvbmdlcigtKDE6NSksIG5hbWVzX3RvID0gInJhbmdlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgfD4gCiAgZmlsdGVyKGlzbzJjID09ICJJRCIsIHllYXIgPT0gMjAyMikgfD4gcHVsbCgpIC0+IGlkCkdpbmkoYygwLjUsMS41LDMsNSw3LDguNSw5LjUpLCBpZCwgY29uZi5sZXZlbD0wLjk1LCB1bmJpYXNlZD1GQUxTRSkKYGBgCg==