This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

install.packages("rlang", type = "binary")
Error in install.packages : Updating loaded packages
install.packages(c("readr", "dplyr", "lubridate", "forecast", "tseries", "ggplot2"))
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:

https://cran.rstudio.com/bin/windows/Rtools/
Installing packages into ‘C:/Users/alice/AppData/Local/R/win-library/4.4’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/readr_2.2.0.zip'
Content type 'application/zip' length 1194020 bytes (1.1 MB)
downloaded 1.1 MB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/dplyr_1.2.1.zip'
Content type 'application/zip' length 1618178 bytes (1.5 MB)
downloaded 1.5 MB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/lubridate_1.9.5.zip'
Content type 'application/zip' length 991003 bytes (967 KB)
downloaded 967 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/forecast_9.0.2.zip'
Content type 'application/zip' length 1965798 bytes (1.9 MB)
downloaded 1.9 MB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/tseries_0.10-61.zip'
Content type 'application/zip' length 402806 bytes (393 KB)
downloaded 393 KB

trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.4/ggplot2_4.0.3.zip'
Content type 'application/zip' length 8464184 bytes (8.1 MB)
downloaded 8.1 MB
package ‘readr’ successfully unpacked and MD5 sums checked
package ‘dplyr’ successfully unpacked and MD5 sums checked
package ‘lubridate’ successfully unpacked and MD5 sums checked
package ‘forecast’ successfully unpacked and MD5 sums checked
package ‘tseries’ successfully unpacked and MD5 sums checked
package ‘ggplot2’ successfully unpacked and MD5 sums checked

The downloaded binary packages are in
    C:\Users\alice\AppData\Local\Temp\RtmpYJ1XGg\downloaded_packages
library(readr)
Warning: package ‘readr’ was built under R version 4.4.3
library(dplyr)
Warning: package ‘dplyr’ was built under R version 4.4.3
Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(lubridate)
Warning: package ‘lubridate’ was built under R version 4.4.3
Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
library(forecast)
Warning: package ‘forecast’ was built under R version 4.4.3
library(tseries)
Warning: package ‘tseries’ was built under R version 4.4.3Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 

    ‘tseries’ version: 0.10-61

    ‘tseries’ is a package for time series analysis and computational finance.

    See ‘library(help="tseries")’ for details.
library(ggplot2)
Warning: package ‘ggplot2’ was built under R version 4.4.3
data <- read.csv("C:/Users/alice/Downloads/Employment on manufacturing sector.csv")

str(data)
'data.frame':   1848 obs. of  4 variables:
 $ series    : chr  "abs" "abs" "abs" "abs" ...
 $ sector    : chr  "p0" "p1" "p2" "p3" ...
 $ date      : chr  "1/01/2015" "1/01/2015" "1/01/2015" "1/01/2015" ...
 $ employment: num  13947 1857 78 2382 391 ...
data_p0 <- data %>%
  filter(series == "abs", sector == "p0") %>%
  mutate(date = dmy(date)) %>%
  arrange(date)

View(data_p0)
nrow(data_p0)
[1] 44
employment_ts <- ts(
  data_p0$employment,
  start = c(2015, 1),
  frequency = 4
)

employment_ts
      Qtr1  Qtr2  Qtr3  Qtr4
2015 13947 13944 13950 14128
2016 14096 14162 14202 14261
2017 14356 14415 14484 14581
2018 14684 14767 14857 14933
2019 15010 15078 15162 15255
2020 15243 14884 15096 15162
2021 15237 15207 15275 15441
2022 15575 15701 15831 15942
2023 16062 16146 16251 16347
2024 16401 16591 16715 16793
2025 16703 16849 16967 17100
frequency(employment_ts)
[1] 4
start(employment_ts)
[1] 2015    1
end(employment_ts)
[1] 2025    4
plot(data_p0$date,
     data_p0$employment,
     type = "o",
     col = "blue",
     pch = 16,
     cex = 1.2,
     lwd = 2.5,
     xaxt = "n",
     cex.main = 1.5,
     cex.lab = 1.3,
     cex.axis = 1.1,
     main = "Quarterly Employment in Malaysia's Manufacturing Sector (2015 Q1–2025 Q4)",
     xlab = "Year",
     ylab = "Employment")

axis.Date(1,
          at = seq(min(data_p0$date),
                   max(data_p0$date),
                   by = "year"),
          format = "%Y",
          cex.axis = 1.1)

table51 <- data.frame(
  Parameter = c("Alpha (α)",
                "Beta (β)",
                "Initial Level (l0)",
                "Initial Trend (b0)"),
  Estimate = c(0.9137,
               0.0001,
               13845.7654,
               73.7071)
)

table51
# Pastikan modelnya didefinisikan dulu di dalam chunk ini
Holt_est <- holt(employment_ts, h = 1)

acc_holt <- accuracy(Holt_est)

MSE_holt <- acc_holt[,"RMSE"]^2
MAPE_holt <- acc_holt[,"MAPE"]

table52 <- data.frame(
  Measure = c("MSE", "MAPE"),
  Value = c(MSE_holt, MAPE_holt)
)

table52
forecast_holt <- forecast(Holt_est, h = 1)

forecast_holt

autoplot(forecast_holt) +
  ggtitle("Holt's Linear Trend One-Step-Ahead Forecast") +
  xlab("Year") +
  ylab("Employment")

table53 <- data.frame(
  Forecast_Period = "2026 Q1",
  Forecast_Value = as.numeric(forecast_holt$mean)
)

table53
model_arima120 <- Arima(employment_ts, order = c(1,2,0))

summary(model_arima120)
Series: employment_ts 
ARIMA(1,2,0) 

Coefficients:
          ar1
      -0.4972
s.e.   0.1305

sigma^2 = 12903:  log likelihood = -257.99
AIC=519.97   AICc=520.28   BIC=523.45

Training set error measures:
                   ME    RMSE      MAE        MPE      MAPE      MASE       ACF1
Training set 4.146971 109.652 62.03111 0.02674741 0.4047804 0.2006181 -0.1713952
acc_arima120 <- accuracy(model_arima120)

MSE_arima120 <- acc_arima120[,"RMSE"]^2
MAPE_arima120 <- acc_arima120[,"MAPE"]
model_arima021 <- Arima(employment_ts, order = c(0,2,1))

summary(model_arima021)
Series: employment_ts 
ARIMA(0,2,1) 

Coefficients:
          ma1
      -0.9606
s.e.   0.1002

sigma^2 = 8503:  log likelihood = -250.34
AIC=504.68   AICc=504.99   BIC=508.16

Training set error measures:
                   ME     RMSE      MAE        MPE      MAPE      MASE        ACF1
Training set 14.88872 89.01417 54.69445 0.09416823 0.3561064 0.1768902 -0.09355206
acc_arima021 <- accuracy(model_arima021)

MSE_arima021 <- acc_arima021[,"RMSE"]^2
MAPE_arima021 <- acc_arima021[,"MAPE"]
table54 <- data.frame(
  Model = c("ARIMA(1,2,0)",
            "ARIMA(0,2,1)"),
  AIC = c(AIC(model_arima120),
          AIC(model_arima021)),
  BIC = c(BIC(model_arima120),
          BIC(model_arima021)),
  MSE = c(MSE_arima120,
          MSE_arima021),
  MAPE = c(MAPE_arima120,
           MAPE_arima021)
)

table54
forecast_arima021 <- forecast(model_arima021, h = 1)

forecast_arima021

autoplot(forecast_arima021) +
  ggtitle("ARIMA(0,2,1) One-Step-Ahead Forecast") +
  xlab("Year") +
  ylab("Employment")

table55 <- data.frame(
  Forecast_Period = "2026 Q1",
  Forecast_Value = as.numeric(forecast_arima021$mean)
)

table55
table56 <- data.frame(
  Model = c("Holt's Linear Trend",
            "ARIMA(1,2,0)",
            "ARIMA(0,2,1)"),
  MSE = c(MSE_holt,
          MSE_arima120,
          MSE_arima021),
  MAPE = c(MAPE_holt,
           MAPE_arima120,
           MAPE_arima021)
)

table56
model

Call:
lm(formula = electric ~ t, data = data)

Coefficients:
(Intercept)            t  
      97.84         0.47  
table57 <- data.frame(
  Best_Model = "Holt's Linear Trend",
  Forecast_Period = "2026 Q1",
  Forecast_Value = as.numeric(forecast_holt$mean)
)

table57
fit_part <- window(employment_ts, end = c(2022, 3))
holdout_part <- window(employment_ts, start = c(2022, 4))

length(fit_part)
[1] 31
length(holdout_part)
[1] 13
# Plot fitted and hold-out data
plot(employment_ts,
     main = "Fitted and Hold-out Data",
     xlab = "Year",
     ylab = "Employment",
     col = "black",
     lwd = 2)

lines(fit_part, col = "blue", lwd = 2)
lines(holdout_part, col = "red", lwd = 2)

legend("topleft",
       legend = c("Full Series", "Fitted Part", "Hold-out Part"),
       col = c("black", "blue", "red"),
       lwd = 2)

adf.test(fit_part)

    Augmented Dickey-Fuller Test

data:  fit_part
Dickey-Fuller = -1.7685, Lag order = 3, p-value = 0.6619
alternative hypothesis: stationary
fit_diff1 <- diff(fit_part, differences = 1)
adf.test(fit_diff1)

    Augmented Dickey-Fuller Test

data:  fit_diff1
Dickey-Fuller = -1.9581, Lag order = 3, p-value = 0.5888
alternative hypothesis: stationary
fit_diff2 <- diff(fit_part, differences = 2)
adf.test(fit_diff2)
Warning: p-value smaller than printed p-value

    Augmented Dickey-Fuller Test

data:  fit_diff2
Dickey-Fuller = -4.622, Lag order = 3, p-value = 0.01
alternative hypothesis: stationary
par(mfrow = c(1,2))

acf(fit_diff2,
    main = "ACF of Second-Differenced Fitted Series")

pacf(fit_diff2,
     main = "PACF of Second-Differenced Fitted Series")

par(mfrow = c(1,1))

# -----------------------------------------------------
# 5.2.1 Model Identification
# -----------------------------------------------------

# 5.2.1.1 Data Splitting (70% Fitted, 30% Hold-out)
fit_part <- window(employment_ts, end = c(2022, 3))
holdout_part <- window(employment_ts, start = c(2022, 4))

# Plot Pembagian Data
plot(employment_ts, main = "Fitted and Hold-out Data Separation", 
     xlab = "Year", ylab = "Employment", col = "black", lwd = 2)
lines(fit_part, col = "blue", lwd = 2)
lines(holdout_part, col = "red", lwd = 2)
legend("topleft", legend = c("Full Series", "Fitted Part (70%)", "Hold-out Part (30%)"), 
       col = c("black", "blue", "red"), lwd = 2)

# 5.2.1.2 Stationary Test (ADF Test pada data Fit)
print("ADF Test: Original Fit Data")
[1] "ADF Test: Original Fit Data"
adf.test(fit_part)

    Augmented Dickey-Fuller Test

data:  fit_part
Dickey-Fuller = -1.7685, Lag order = 3, p-value = 0.6619
alternative hypothesis: stationary
# Melakukan Regular Differencing ke-1 (d=1) karena data memiliki trend
fit_diff1 <- diff(fit_part, differences = 1)
print("ADF Test: First-Differenced Fit Data")
[1] "ADF Test: First-Differenced Fit Data"
adf.test(fit_diff1)

    Augmented Dickey-Fuller Test

data:  fit_diff1
Dickey-Fuller = -1.9581, Lag order = 3, p-value = 0.5888
alternative hypothesis: stationary
# Melakukan Seasonal Differencing ke-1 (D=1, lag=4) untuk membersihkan efek kuartalan
fit_diff1_diff4 <- diff(fit_diff1, lag = 4)
print("ADF Test: Regular + Seasonal Differenced Data")
[1] "ADF Test: Regular + Seasonal Differenced Data"
adf.test(fit_diff1_diff4)

    Augmented Dickey-Fuller Test

data:  fit_diff1_diff4
Dickey-Fuller = -2.1325, Lag order = 2, p-value = 0.5219
alternative hypothesis: stationary
# 5.2.1.3 ACF and PACF Plots (Untuk mengidentifikasi model kandidat)
par(mfrow = c(1,2))
acf(fit_diff1_diff4, main = "ACF of Differenced Fit Series", lag.max = 12)
pacf(fit_diff1_diff4, main = "PACF of Differenced Fit Series", lag.max = 12)
par(mfrow = c(1,1))

# 5.2.2.1 Estimate Three ARIMA Models (menggunakan fit_part)
arima_cand1 <- Arima(fit_part, order = c(0,1,1), seasonal = c(0,1,0), include.drift = TRUE)
Warning: No drift term fitted as the order of difference is 2 or more.
arima_cand2 <- Arima(fit_part, order = c(1,1,0), seasonal = c(0,1,0), include.drift = TRUE)
Warning: No drift term fitted as the order of difference is 2 or more.
arima_cand3 <- Arima(fit_part, order = c(1,1,1), seasonal = c(0,1,0), include.drift = TRUE)
Warning: No drift term fitted as the order of difference is 2 or more.
print("Summary of Candidate Model Parameters 1")
[1] "Summary of Candidate Model Parameters 1"
summary(arima_cand1)
Series: fit_part 
ARIMA(0,1,1)(0,1,0)[4] 

Coefficients:
          ma1
      -0.0976
s.e.   0.1817

sigma^2 = 16920:  log likelihood = -162.93
AIC=329.86   AICc=330.38   BIC=332.37

Training set error measures:
                   ME     RMSE      MAE        MPE      MAPE     MASE        ACF1
Training set 13.65468 116.8131 69.95149 0.08780466 0.4664527 0.258831 -0.02582113
print("Summary of Candidate Model Parameters 2")
[1] "Summary of Candidate Model Parameters 2"
summary(arima_cand2)
Series: fit_part 
ARIMA(1,1,0)(0,1,0)[4] 

Coefficients:
          ar1
      -0.1097
s.e.   0.1930

sigma^2 = 16896:  log likelihood = -162.91
AIC=329.82   AICc=330.34   BIC=332.34

Training set error measures:
                  ME     RMSE      MAE        MPE     MAPE      MASE       ACF1
Training set 13.7262 116.7283 69.56205 0.08826414 0.463901 0.2573901 -0.0135894
print("Summary of Candidate Model Parameters 3")
[1] "Summary of Candidate Model Parameters 3"
summary(arima_cand3)
Series: fit_part 
ARIMA(1,1,1)(0,1,0)[4] 

Coefficients:
          ar1     ma1
      -0.2242  0.1142
s.e.   0.7993  0.7996

sigma^2 = 17587:  log likelihood = -162.9
AIC=331.81   AICc=332.9   BIC=335.58

Training set error measures:
                   ME     RMSE      MAE        MPE      MAPE     MASE        ACF1
Training set 13.66149 116.6866 69.28987 0.08784001 0.4621329 0.256383 -0.01444378
lb_cand1 <- Box.test(residuals(arima_cand1), lag = 8, type = "Ljung-Box")
lb_cand2 <- Box.test(residuals(arima_cand2), lag = 8, type = "Ljung-Box")
lb_cand3 <- Box.test(residuals(arima_cand3), lag = 8, type = "Ljung-Box")

table_comparison_in <- data.frame(
  Model = c("ARIMA(0,1,1)(0,1,0)[4] w/ drift", 
            "ARIMA(1,1,0)(0,1,0)[4] w/ drift", 
            "ARIMA(1,1,1)(0,1,0)[4] w/ drift"),
  AIC  = c(AIC(arima_cand1), AIC(arima_cand2), AIC(arima_cand3)),
  BIC  = c(BIC(arima_cand1), BIC(arima_cand2), BIC(arima_cand3)),
  Ljung_Box_p_value = c(lb_cand1$p.value, lb_cand2$p.value, lb_cand3$p.value)
)

print("Table 5.2.2.2: In-Sample Model Comparison")
[1] "Table 5.2.2.2: In-Sample Model Comparison"
table_comparison_in
h_holdout <- length(holdout_part)

f_cand1 <- forecast(arima_cand1, h = h_holdout)
f_cand2 <- forecast(arima_cand2, h = h_holdout)
f_cand3 <- forecast(arima_cand3, h = h_holdout)

# Menghitung akurasi Out-of-Sample (pilih baris ke-2 [Test set])
acc_cand1 <- accuracy(f_cand1, holdout_part)
acc_cand2 <- accuracy(f_cand2, holdout_part)
acc_cand3 <- accuracy(f_cand3, holdout_part)

table_accuracy_out <- data.frame(
  Model = c("ARIMA(0,1,1)(0,1,0)[4] w/ drift", 
            "ARIMA(1,1,0)(0,1,0)[4] w/ drift", 
            "ARIMA(1,1,1)(0,1,0)[4] w/ drift"),
  RMSE_Test = c(acc_cand1[2, "RMSE"], acc_cand2[2, "RMSE"], acc_cand3[2, "RMSE"]),
  MAE_Test  = c(acc_cand1[2, "MAE"],  acc_cand2[2, "MAE"],  acc_cand3[2, "MAE"]),
  MAPE_Test = c(acc_cand1[2, "MAPE"], acc_cand2[2, "MAPE"], acc_cand3[2, "MAPE"])
)

print("--- Table 5.2.2.3: Out-of-Sample Accuracy (Hold-out Evaluation) ---")
[1] "--- Table 5.2.2.3: Out-of-Sample Accuracy (Hold-out Evaluation) ---"
table_accuracy_out
# 5.2.2.4 Comparison with the Best Univariate Model
# Membandingkan model ARIMA terbaik hasil split data dengan model Holt di Chapter 5(a)
table5224 <- data.frame(
  Model = c("Best ARIMA Model (Split Data)", "Holt's Linear Trend (Full Data)"),
  MSE  = c(acc_cand1[1, "RMSE"]^2, MSE_holt),  # Menggunakan nilai in-sample (Training) agar adil
  MAPE = c(acc_cand1[1, "MAPE"], MAPE_holt)
)

print("Table 5.2.2.4: Comparison with the Best Univariate Model")
[1] "Table 5.2.2.4: Comparison with the Best Univariate Model"
table5224
# 5.2.2.5 Best Forecasting Model & Final Plot
# Berdasarkan laporan, ARIMA(0,1,1)(0,1,0)[4] dengan drift terpilih sebagai model terbaik.
plot(f_cand1, main = "Best ARIMA Model Forecast vs Actual Hold-out Data", 
     xlab = "Year", ylab = "Employment", col = "blue")
lines(holdout_part, col = "red", lwd = 2)
legend("topleft", legend = c("Forecasted", "Actual Hold-out Data"), 
       col = c("blue", "red"), lwd = 2)

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInJsYW5nIiwgdHlwZSA9ICJiaW5hcnkiKQ0KYGBgDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcyhjKCJyZWFkciIsICJkcGx5ciIsICJsdWJyaWRhdGUiLCAiZm9yZWNhc3QiLCAidHNlcmllcyIsICJnZ3Bsb3QyIikpDQoNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGZvcmVjYXN0KQ0KbGlicmFyeSh0c2VyaWVzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YSA8LSByZWFkLmNzdigiQzovVXNlcnMvYWxpY2UvRG93bmxvYWRzL0VtcGxveW1lbnQgb24gbWFudWZhY3R1cmluZyBzZWN0b3IuY3N2IikNCg0Kc3RyKGRhdGEpDQpgYGANCmBgYHtyfQ0KZGF0YV9wMCA8LSBkYXRhICU+JQ0KICBmaWx0ZXIoc2VyaWVzID09ICJhYnMiLCBzZWN0b3IgPT0gInAwIikgJT4lDQogIG11dGF0ZShkYXRlID0gZG15KGRhdGUpKSAlPiUNCiAgYXJyYW5nZShkYXRlKQ0KDQpWaWV3KGRhdGFfcDApDQpucm93KGRhdGFfcDApDQpgYGANCmBgYHtyfQ0KZW1wbG95bWVudF90cyA8LSB0cygNCiAgZGF0YV9wMCRlbXBsb3ltZW50LA0KICBzdGFydCA9IGMoMjAxNSwgMSksDQogIGZyZXF1ZW5jeSA9IDQNCikNCg0KZW1wbG95bWVudF90cw0KZnJlcXVlbmN5KGVtcGxveW1lbnRfdHMpDQpzdGFydChlbXBsb3ltZW50X3RzKQ0KZW5kKGVtcGxveW1lbnRfdHMpDQoNCmBgYA0KDQpgYGB7cn0NCnBsb3QoZGF0YV9wMCRkYXRlLA0KICAgICBkYXRhX3AwJGVtcGxveW1lbnQsDQogICAgIHR5cGUgPSAibyIsDQogICAgIGNvbCA9ICJibHVlIiwNCiAgICAgcGNoID0gMTYsDQogICAgIGNleCA9IDEuMiwNCiAgICAgbHdkID0gMi41LA0KICAgICB4YXh0ID0gIm4iLA0KICAgICBjZXgubWFpbiA9IDEuNSwNCiAgICAgY2V4LmxhYiA9IDEuMywNCiAgICAgY2V4LmF4aXMgPSAxLjEsDQogICAgIG1haW4gPSAiUXVhcnRlcmx5IEVtcGxveW1lbnQgaW4gTWFsYXlzaWEncyBNYW51ZmFjdHVyaW5nIFNlY3RvciAoMjAxNSBRMeKAkzIwMjUgUTQpIiwNCiAgICAgeGxhYiA9ICJZZWFyIiwNCiAgICAgeWxhYiA9ICJFbXBsb3ltZW50IikNCg0KYXhpcy5EYXRlKDEsDQogICAgICAgICAgYXQgPSBzZXEobWluKGRhdGFfcDAkZGF0ZSksDQogICAgICAgICAgICAgICAgICAgbWF4KGRhdGFfcDAkZGF0ZSksDQogICAgICAgICAgICAgICAgICAgYnkgPSAieWVhciIpLA0KICAgICAgICAgIGZvcm1hdCA9ICIlWSIsDQogICAgICAgICAgY2V4LmF4aXMgPSAxLjEpDQoNCmBgYA0KYGBge3J9DQp0YWJsZTUxIDwtIGRhdGEuZnJhbWUoDQogIFBhcmFtZXRlciA9IGMoIkFscGhhICjOsSkiLA0KICAgICAgICAgICAgICAgICJCZXRhICjOsikiLA0KICAgICAgICAgICAgICAgICJJbml0aWFsIExldmVsIChsMCkiLA0KICAgICAgICAgICAgICAgICJJbml0aWFsIFRyZW5kIChiMCkiKSwNCiAgRXN0aW1hdGUgPSBjKDAuOTEzNywNCiAgICAgICAgICAgICAgIDAuMDAwMSwNCiAgICAgICAgICAgICAgIDEzODQ1Ljc2NTQsDQogICAgICAgICAgICAgICA3My43MDcxKQ0KKQ0KDQp0YWJsZTUxDQpgYGANCmBgYHtyfQ0KIyBQYXN0aWthbiBtb2RlbG55YSBkaWRlZmluaXNpa2FuIGR1bHUgZGkgZGFsYW0gY2h1bmsgaW5pDQpIb2x0X2VzdCA8LSBob2x0KGVtcGxveW1lbnRfdHMsIGggPSAxKQ0KDQphY2NfaG9sdCA8LSBhY2N1cmFjeShIb2x0X2VzdCkNCg0KTVNFX2hvbHQgPC0gYWNjX2hvbHRbLCJSTVNFIl1eMg0KTUFQRV9ob2x0IDwtIGFjY19ob2x0WywiTUFQRSJdDQoNCnRhYmxlNTIgPC0gZGF0YS5mcmFtZSgNCiAgTWVhc3VyZSA9IGMoIk1TRSIsICJNQVBFIiksDQogIFZhbHVlID0gYyhNU0VfaG9sdCwgTUFQRV9ob2x0KQ0KKQ0KDQp0YWJsZTUyDQpgYGANCmBgYHtyfQ0KZm9yZWNhc3RfaG9sdCA8LSBmb3JlY2FzdChIb2x0X2VzdCwgaCA9IDEpDQoNCmZvcmVjYXN0X2hvbHQNCg0KYXV0b3Bsb3QoZm9yZWNhc3RfaG9sdCkgKw0KICBnZ3RpdGxlKCJIb2x0J3MgTGluZWFyIFRyZW5kIE9uZS1TdGVwLUFoZWFkIEZvcmVjYXN0IikgKw0KICB4bGFiKCJZZWFyIikgKw0KICB5bGFiKCJFbXBsb3ltZW50IikNCmBgYA0KYGBge3J9DQp0YWJsZTUzIDwtIGRhdGEuZnJhbWUoDQogIEZvcmVjYXN0X1BlcmlvZCA9ICIyMDI2IFExIiwNCiAgRm9yZWNhc3RfVmFsdWUgPSBhcy5udW1lcmljKGZvcmVjYXN0X2hvbHQkbWVhbikNCikNCg0KdGFibGU1Mw0KYGBgDQoNCmBgYHtyfQ0KbW9kZWxfYXJpbWExMjAgPC0gQXJpbWEoZW1wbG95bWVudF90cywgb3JkZXIgPSBjKDEsMiwwKSkNCg0Kc3VtbWFyeShtb2RlbF9hcmltYTEyMCkNCg0KYWNjX2FyaW1hMTIwIDwtIGFjY3VyYWN5KG1vZGVsX2FyaW1hMTIwKQ0KDQpNU0VfYXJpbWExMjAgPC0gYWNjX2FyaW1hMTIwWywiUk1TRSJdXjINCk1BUEVfYXJpbWExMjAgPC0gYWNjX2FyaW1hMTIwWywiTUFQRSJdDQpgYGANCmBgYHtyfQ0KbW9kZWxfYXJpbWEwMjEgPC0gQXJpbWEoZW1wbG95bWVudF90cywgb3JkZXIgPSBjKDAsMiwxKSkNCg0Kc3VtbWFyeShtb2RlbF9hcmltYTAyMSkNCg0KYWNjX2FyaW1hMDIxIDwtIGFjY3VyYWN5KG1vZGVsX2FyaW1hMDIxKQ0KDQpNU0VfYXJpbWEwMjEgPC0gYWNjX2FyaW1hMDIxWywiUk1TRSJdXjINCk1BUEVfYXJpbWEwMjEgPC0gYWNjX2FyaW1hMDIxWywiTUFQRSJdDQpgYGANCmBgYHtyfQ0KdGFibGU1NCA8LSBkYXRhLmZyYW1lKA0KICBNb2RlbCA9IGMoIkFSSU1BKDEsMiwwKSIsDQogICAgICAgICAgICAiQVJJTUEoMCwyLDEpIiksDQogIEFJQyA9IGMoQUlDKG1vZGVsX2FyaW1hMTIwKSwNCiAgICAgICAgICBBSUMobW9kZWxfYXJpbWEwMjEpKSwNCiAgQklDID0gYyhCSUMobW9kZWxfYXJpbWExMjApLA0KICAgICAgICAgIEJJQyhtb2RlbF9hcmltYTAyMSkpLA0KICBNU0UgPSBjKE1TRV9hcmltYTEyMCwNCiAgICAgICAgICBNU0VfYXJpbWEwMjEpLA0KICBNQVBFID0gYyhNQVBFX2FyaW1hMTIwLA0KICAgICAgICAgICBNQVBFX2FyaW1hMDIxKQ0KKQ0KDQp0YWJsZTU0DQpgYGANCg0KYGBge3J9DQpmb3JlY2FzdF9hcmltYTAyMSA8LSBmb3JlY2FzdChtb2RlbF9hcmltYTAyMSwgaCA9IDEpDQoNCmZvcmVjYXN0X2FyaW1hMDIxDQoNCmF1dG9wbG90KGZvcmVjYXN0X2FyaW1hMDIxKSArDQogIGdndGl0bGUoIkFSSU1BKDAsMiwxKSBPbmUtU3RlcC1BaGVhZCBGb3JlY2FzdCIpICsNCiAgeGxhYigiWWVhciIpICsNCiAgeWxhYigiRW1wbG95bWVudCIpDQpgYGANCmBgYHtyfQ0KdGFibGU1NSA8LSBkYXRhLmZyYW1lKA0KICBGb3JlY2FzdF9QZXJpb2QgPSAiMjAyNiBRMSIsDQogIEZvcmVjYXN0X1ZhbHVlID0gYXMubnVtZXJpYyhmb3JlY2FzdF9hcmltYTAyMSRtZWFuKQ0KKQ0KDQp0YWJsZTU1DQpgYGANCg0KYGBge3J9DQp0YWJsZTU2IDwtIGRhdGEuZnJhbWUoDQogIE1vZGVsID0gYygiSG9sdCdzIExpbmVhciBUcmVuZCIsDQogICAgICAgICAgICAiQVJJTUEoMSwyLDApIiwNCiAgICAgICAgICAgICJBUklNQSgwLDIsMSkiKSwNCiAgTVNFID0gYyhNU0VfaG9sdCwNCiAgICAgICAgICBNU0VfYXJpbWExMjAsDQogICAgICAgICAgTVNFX2FyaW1hMDIxKSwNCiAgTUFQRSA9IGMoTUFQRV9ob2x0LA0KICAgICAgICAgICBNQVBFX2FyaW1hMTIwLA0KICAgICAgICAgICBNQVBFX2FyaW1hMDIxKQ0KKQ0KDQp0YWJsZTU2DQpgYGANCg0KYGBge3J9DQptb2RlbA0KdGFibGU1NyA8LSBkYXRhLmZyYW1lKA0KICBCZXN0X01vZGVsID0gIkhvbHQncyBMaW5lYXIgVHJlbmQiLA0KICBGb3JlY2FzdF9QZXJpb2QgPSAiMjAyNiBRMSIsDQogIEZvcmVjYXN0X1ZhbHVlID0gYXMubnVtZXJpYyhmb3JlY2FzdF9ob2x0JG1lYW4pDQopDQoNCnRhYmxlNTcNCmBgYA0KYGBge3J9DQpmaXRfcGFydCA8LSB3aW5kb3coZW1wbG95bWVudF90cywgZW5kID0gYygyMDIyLCAzKSkNCmhvbGRvdXRfcGFydCA8LSB3aW5kb3coZW1wbG95bWVudF90cywgc3RhcnQgPSBjKDIwMjIsIDQpKQ0KDQpsZW5ndGgoZml0X3BhcnQpDQpsZW5ndGgoaG9sZG91dF9wYXJ0KQ0KDQoNCiMgUGxvdCBmaXR0ZWQgYW5kIGhvbGQtb3V0IGRhdGENCnBsb3QoZW1wbG95bWVudF90cywNCiAgICAgbWFpbiA9ICJGaXR0ZWQgYW5kIEhvbGQtb3V0IERhdGEiLA0KICAgICB4bGFiID0gIlllYXIiLA0KICAgICB5bGFiID0gIkVtcGxveW1lbnQiLA0KICAgICBjb2wgPSAiYmxhY2siLA0KICAgICBsd2QgPSAyKQ0KDQpsaW5lcyhmaXRfcGFydCwgY29sID0gImJsdWUiLCBsd2QgPSAyKQ0KbGluZXMoaG9sZG91dF9wYXJ0LCBjb2wgPSAicmVkIiwgbHdkID0gMikNCg0KbGVnZW5kKCJ0b3BsZWZ0IiwNCiAgICAgICBsZWdlbmQgPSBjKCJGdWxsIFNlcmllcyIsICJGaXR0ZWQgUGFydCIsICJIb2xkLW91dCBQYXJ0IiksDQogICAgICAgY29sID0gYygiYmxhY2siLCAiYmx1ZSIsICJyZWQiKSwNCiAgICAgICBsd2QgPSAyKQ0KYGBgDQpgYGB7cn0NCmFkZi50ZXN0KGZpdF9wYXJ0KQ0KDQpmaXRfZGlmZjEgPC0gZGlmZihmaXRfcGFydCwgZGlmZmVyZW5jZXMgPSAxKQ0KYWRmLnRlc3QoZml0X2RpZmYxKQ0KDQpmaXRfZGlmZjIgPC0gZGlmZihmaXRfcGFydCwgZGlmZmVyZW5jZXMgPSAyKQ0KYWRmLnRlc3QoZml0X2RpZmYyKQ0KYGBgDQpgYGB7cn0NCnBhcihtZnJvdyA9IGMoMSwyKSkNCg0KYWNmKGZpdF9kaWZmMiwNCiAgICBtYWluID0gIkFDRiBvZiBTZWNvbmQtRGlmZmVyZW5jZWQgRml0dGVkIFNlcmllcyIpDQoNCnBhY2YoZml0X2RpZmYyLA0KICAgICBtYWluID0gIlBBQ0Ygb2YgU2Vjb25kLURpZmZlcmVuY2VkIEZpdHRlZCBTZXJpZXMiKQ0KDQpwYXIobWZyb3cgPSBjKDEsMSkpDQoNCmBgYA0KYGBge3J9DQojIDUuMi4xIE1vZGVsIElkZW50aWZpY2F0aW9uDQoNCiMgNS4yLjEuMSBEYXRhIFNwbGl0dGluZyAoNzAlIEZpdHRlZCwgMzAlIEhvbGQtb3V0KQ0KZml0X3BhcnQgPC0gd2luZG93KGVtcGxveW1lbnRfdHMsIGVuZCA9IGMoMjAyMiwgMykpDQpob2xkb3V0X3BhcnQgPC0gd2luZG93KGVtcGxveW1lbnRfdHMsIHN0YXJ0ID0gYygyMDIyLCA0KSkNCg0KIyBQbG90IFBlbWJhZ2lhbiBEYXRhDQpwbG90KGVtcGxveW1lbnRfdHMsIG1haW4gPSAiRml0dGVkIGFuZCBIb2xkLW91dCBEYXRhIFNlcGFyYXRpb24iLCANCiAgICAgeGxhYiA9ICJZZWFyIiwgeWxhYiA9ICJFbXBsb3ltZW50IiwgY29sID0gImJsYWNrIiwgbHdkID0gMikNCmxpbmVzKGZpdF9wYXJ0LCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQpsaW5lcyhob2xkb3V0X3BhcnQsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiRnVsbCBTZXJpZXMiLCAiRml0dGVkIFBhcnQgKDcwJSkiLCAiSG9sZC1vdXQgUGFydCAoMzAlKSIpLCANCiAgICAgICBjb2wgPSBjKCJibGFjayIsICJibHVlIiwgInJlZCIpLCBsd2QgPSAyKQ0KYGBgDQpgYGB7cn0NCiMgNS4yLjEuMiBTdGF0aW9uYXJ5IFRlc3QgKEFERiBUZXN0IHBhZGEgZGF0YSBGaXQpDQpwcmludCgiQURGIFRlc3Q6IE9yaWdpbmFsIEZpdCBEYXRhIikNCmFkZi50ZXN0KGZpdF9wYXJ0KQ0KDQojIE1lbGFrdWthbiBSZWd1bGFyIERpZmZlcmVuY2luZyBrZS0xIChkPTEpIGthcmVuYSBkYXRhIG1lbWlsaWtpIHRyZW5kDQpmaXRfZGlmZjEgPC0gZGlmZihmaXRfcGFydCwgZGlmZmVyZW5jZXMgPSAxKQ0KcHJpbnQoIkFERiBUZXN0OiBGaXJzdC1EaWZmZXJlbmNlZCBGaXQgRGF0YSIpDQphZGYudGVzdChmaXRfZGlmZjEpDQoNCiMgTWVsYWt1a2FuIFNlYXNvbmFsIERpZmZlcmVuY2luZyBrZS0xIChEPTEsIGxhZz00KSB1bnR1ayBtZW1iZXJzaWhrYW4gZWZlayBrdWFydGFsYW4NCmZpdF9kaWZmMV9kaWZmNCA8LSBkaWZmKGZpdF9kaWZmMSwgbGFnID0gNCkNCnByaW50KCJBREYgVGVzdDogUmVndWxhciArIFNlYXNvbmFsIERpZmZlcmVuY2VkIERhdGEiKQ0KYWRmLnRlc3QoZml0X2RpZmYxX2RpZmY0KQ0KYGBgDQoNCmBgYHtyfQ0KIyA1LjIuMS4zIEFDRiBhbmQgUEFDRiBQbG90cyAoVW50dWsgbWVuZ2lkZW50aWZpa2FzaSBtb2RlbCBrYW5kaWRhdCkNCnBhcihtZnJvdyA9IGMoMSwyKSkNCmFjZihmaXRfZGlmZjFfZGlmZjQsIG1haW4gPSAiQUNGIG9mIERpZmZlcmVuY2VkIEZpdCBTZXJpZXMiLCBsYWcubWF4ID0gMTIpDQpwYWNmKGZpdF9kaWZmMV9kaWZmNCwgbWFpbiA9ICJQQUNGIG9mIERpZmZlcmVuY2VkIEZpdCBTZXJpZXMiLCBsYWcubWF4ID0gMTIpDQpwYXIobWZyb3cgPSBjKDEsMSkpDQpgYGANCg0KYGBge3J9DQojIDUuMi4yLjEgRXN0aW1hdGUgVGhyZWUgQVJJTUEgTW9kZWxzIChtZW5nZ3VuYWthbiBmaXRfcGFydCkNCmFyaW1hX2NhbmQxIDwtIEFyaW1hKGZpdF9wYXJ0LCBvcmRlciA9IGMoMCwxLDEpLCBzZWFzb25hbCA9IGMoMCwxLDApLCBpbmNsdWRlLmRyaWZ0ID0gVFJVRSkNCmFyaW1hX2NhbmQyIDwtIEFyaW1hKGZpdF9wYXJ0LCBvcmRlciA9IGMoMSwxLDApLCBzZWFzb25hbCA9IGMoMCwxLDApLCBpbmNsdWRlLmRyaWZ0ID0gVFJVRSkNCmFyaW1hX2NhbmQzIDwtIEFyaW1hKGZpdF9wYXJ0LCBvcmRlciA9IGMoMSwxLDEpLCBzZWFzb25hbCA9IGMoMCwxLDApLCBpbmNsdWRlLmRyaWZ0ID0gVFJVRSkNCg0KcHJpbnQoIlN1bW1hcnkgb2YgQ2FuZGlkYXRlIE1vZGVsIFBhcmFtZXRlcnMgMSIpDQpzdW1tYXJ5KGFyaW1hX2NhbmQxKQ0KcHJpbnQoIlN1bW1hcnkgb2YgQ2FuZGlkYXRlIE1vZGVsIFBhcmFtZXRlcnMgMiIpDQpzdW1tYXJ5KGFyaW1hX2NhbmQyKQ0KcHJpbnQoIlN1bW1hcnkgb2YgQ2FuZGlkYXRlIE1vZGVsIFBhcmFtZXRlcnMgMyIpDQpzdW1tYXJ5KGFyaW1hX2NhbmQzKQ0KYGBgDQpgYGB7cn0NCmxiX2NhbmQxIDwtIEJveC50ZXN0KHJlc2lkdWFscyhhcmltYV9jYW5kMSksIGxhZyA9IDgsIHR5cGUgPSAiTGp1bmctQm94IikNCmxiX2NhbmQyIDwtIEJveC50ZXN0KHJlc2lkdWFscyhhcmltYV9jYW5kMiksIGxhZyA9IDgsIHR5cGUgPSAiTGp1bmctQm94IikNCmxiX2NhbmQzIDwtIEJveC50ZXN0KHJlc2lkdWFscyhhcmltYV9jYW5kMyksIGxhZyA9IDgsIHR5cGUgPSAiTGp1bmctQm94IikNCg0KdGFibGVfY29tcGFyaXNvbl9pbiA8LSBkYXRhLmZyYW1lKA0KICBNb2RlbCA9IGMoIkFSSU1BKDAsMSwxKSgwLDEsMClbNF0gdy8gZHJpZnQiLCANCiAgICAgICAgICAgICJBUklNQSgxLDEsMCkoMCwxLDApWzRdIHcvIGRyaWZ0IiwgDQogICAgICAgICAgICAiQVJJTUEoMSwxLDEpKDAsMSwwKVs0XSB3LyBkcmlmdCIpLA0KICBBSUMgID0gYyhBSUMoYXJpbWFfY2FuZDEpLCBBSUMoYXJpbWFfY2FuZDIpLCBBSUMoYXJpbWFfY2FuZDMpKSwNCiAgQklDICA9IGMoQklDKGFyaW1hX2NhbmQxKSwgQklDKGFyaW1hX2NhbmQyKSwgQklDKGFyaW1hX2NhbmQzKSksDQogIExqdW5nX0JveF9wX3ZhbHVlID0gYyhsYl9jYW5kMSRwLnZhbHVlLCBsYl9jYW5kMiRwLnZhbHVlLCBsYl9jYW5kMyRwLnZhbHVlKQ0KKQ0KDQpwcmludCgiVGFibGUgNS4yLjIuMjogSW4tU2FtcGxlIE1vZGVsIENvbXBhcmlzb24iKQ0KdGFibGVfY29tcGFyaXNvbl9pbg0KYGBgDQpgYGB7cn0NCmhfaG9sZG91dCA8LSBsZW5ndGgoaG9sZG91dF9wYXJ0KQ0KDQpmX2NhbmQxIDwtIGZvcmVjYXN0KGFyaW1hX2NhbmQxLCBoID0gaF9ob2xkb3V0KQ0KZl9jYW5kMiA8LSBmb3JlY2FzdChhcmltYV9jYW5kMiwgaCA9IGhfaG9sZG91dCkNCmZfY2FuZDMgPC0gZm9yZWNhc3QoYXJpbWFfY2FuZDMsIGggPSBoX2hvbGRvdXQpDQoNCiMgTWVuZ2hpdHVuZyBha3VyYXNpIE91dC1vZi1TYW1wbGUgKHBpbGloIGJhcmlzIGtlLTIgW1Rlc3Qgc2V0XSkNCmFjY19jYW5kMSA8LSBhY2N1cmFjeShmX2NhbmQxLCBob2xkb3V0X3BhcnQpDQphY2NfY2FuZDIgPC0gYWNjdXJhY3koZl9jYW5kMiwgaG9sZG91dF9wYXJ0KQ0KYWNjX2NhbmQzIDwtIGFjY3VyYWN5KGZfY2FuZDMsIGhvbGRvdXRfcGFydCkNCg0KdGFibGVfYWNjdXJhY3lfb3V0IDwtIGRhdGEuZnJhbWUoDQogIE1vZGVsID0gYygiQVJJTUEoMCwxLDEpKDAsMSwwKVs0XSB3LyBkcmlmdCIsIA0KICAgICAgICAgICAgIkFSSU1BKDEsMSwwKSgwLDEsMClbNF0gdy8gZHJpZnQiLCANCiAgICAgICAgICAgICJBUklNQSgxLDEsMSkoMCwxLDApWzRdIHcvIGRyaWZ0IiksDQogIFJNU0VfVGVzdCA9IGMoYWNjX2NhbmQxWzIsICJSTVNFIl0sIGFjY19jYW5kMlsyLCAiUk1TRSJdLCBhY2NfY2FuZDNbMiwgIlJNU0UiXSksDQogIE1BRV9UZXN0ICA9IGMoYWNjX2NhbmQxWzIsICJNQUUiXSwgIGFjY19jYW5kMlsyLCAiTUFFIl0sICBhY2NfY2FuZDNbMiwgIk1BRSJdKSwNCiAgTUFQRV9UZXN0ID0gYyhhY2NfY2FuZDFbMiwgIk1BUEUiXSwgYWNjX2NhbmQyWzIsICJNQVBFIl0sIGFjY19jYW5kM1syLCAiTUFQRSJdKQ0KKQ0KDQpwcmludCgiLS0tIFRhYmxlIDUuMi4yLjM6IE91dC1vZi1TYW1wbGUgQWNjdXJhY3kgKEhvbGQtb3V0IEV2YWx1YXRpb24pIC0tLSIpDQp0YWJsZV9hY2N1cmFjeV9vdXQNCmBgYA0KDQpgYGB7cn0NCiMgNS4yLjIuNCBDb21wYXJpc29uIHdpdGggdGhlIEJlc3QgVW5pdmFyaWF0ZSBNb2RlbA0KIyBNZW1iYW5kaW5na2FuIG1vZGVsIEFSSU1BIHRlcmJhaWsgaGFzaWwgc3BsaXQgZGF0YSBkZW5nYW4gbW9kZWwgSG9sdCBkaSBDaGFwdGVyIDUoYSkNCnRhYmxlNTIyNCA8LSBkYXRhLmZyYW1lKA0KICBNb2RlbCA9IGMoIkJlc3QgQVJJTUEgTW9kZWwgKFNwbGl0IERhdGEpIiwgIkhvbHQncyBMaW5lYXIgVHJlbmQgKEZ1bGwgRGF0YSkiKSwNCiAgTVNFICA9IGMoYWNjX2NhbmQxWzEsICJSTVNFIl1eMiwgTVNFX2hvbHQpLCAgIyBNZW5nZ3VuYWthbiBuaWxhaSBpbi1zYW1wbGUgKFRyYWluaW5nKSBhZ2FyIGFkaWwNCiAgTUFQRSA9IGMoYWNjX2NhbmQxWzEsICJNQVBFIl0sIE1BUEVfaG9sdCkNCikNCg0KcHJpbnQoIlRhYmxlIDUuMi4yLjQ6IENvbXBhcmlzb24gd2l0aCB0aGUgQmVzdCBVbml2YXJpYXRlIE1vZGVsIikNCnRhYmxlNTIyNA0KYGBgDQoNCmBgYHtyfQ0KIyA1LjIuMi41IEJlc3QgRm9yZWNhc3RpbmcgTW9kZWwgJiBGaW5hbCBQbG90DQojIEJlcmRhc2Fya2FuIGxhcG9yYW4sIEFSSU1BKDAsMSwxKSgwLDEsMClbNF0gZGVuZ2FuIGRyaWZ0IHRlcnBpbGloIHNlYmFnYWkgbW9kZWwgdGVyYmFpay4NCnBsb3QoZl9jYW5kMSwgbWFpbiA9ICJCZXN0IEFSSU1BIE1vZGVsIEZvcmVjYXN0IHZzIEFjdHVhbCBIb2xkLW91dCBEYXRhIiwgDQogICAgIHhsYWIgPSAiWWVhciIsIHlsYWIgPSAiRW1wbG95bWVudCIsIGNvbCA9ICJibHVlIikNCmxpbmVzKGhvbGRvdXRfcGFydCwgY29sID0gInJlZCIsIGx3ZCA9IDIpDQpsZWdlbmQoInRvcGxlZnQiLCBsZWdlbmQgPSBjKCJGb3JlY2FzdGVkIiwgIkFjdHVhbCBIb2xkLW91dCBEYXRhIiksIA0KICAgICAgIGNvbCA9IGMoImJsdWUiLCAicmVkIiksIGx3ZCA9IDIpDQpgYGANCg0K