library(fpp3)
library(tidyverse)
Sys.time()
## [1] "2025-01-11 20:16:58 EST"
1.
Consider the GDP information in data set called global_economy, which
is already embedded in fpp3 package (no need to upload externally)
1. Choose a random country by yourself. Then plot the GDP per capita
for this country over time? How GDP per capita has changed over time for
the series you chose? Explain briefly.
global_economy # see the data.
## # A tsibble: 15,150 x 9 [1Y]
## # Key: Country [263]
## Country Code Year GDP Growth CPI Imports Exports Population
## <fct> <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Afghanistan AFG 1960 537777811. NA NA 7.02 4.13 8996351
## 2 Afghanistan AFG 1961 548888896. NA NA 8.10 4.45 9166764
## 3 Afghanistan AFG 1962 546666678. NA NA 9.35 4.88 9345868
## 4 Afghanistan AFG 1963 751111191. NA NA 16.9 9.17 9533954
## 5 Afghanistan AFG 1964 800000044. NA NA 18.1 8.89 9731361
## 6 Afghanistan AFG 1965 1006666638. NA NA 21.4 11.3 9938414
## 7 Afghanistan AFG 1966 1399999967. NA NA 18.6 8.57 10152331
## 8 Afghanistan AFG 1967 1673333418. NA NA 14.2 6.77 10372630
## 9 Afghanistan AFG 1968 1373333367. NA NA 15.2 8.90 10604346
## 10 Afghanistan AFG 1969 1408888922. NA NA 15.0 10.1 10854428
## # ℹ 15,140 more rows
# 1.Answer:
gdp_India <- global_economy %>%
filter(Country == "India") %>%
mutate(GDP_per_capita = GDP / Population) %>%
select(Year, GDP_per_capita)
autoplot(gdp_India, GDP_per_capita) +
labs(title = "India's GDP per Capita Shows Gradual Growth from 1960s to 2000s,\n with Rapid Increase in Recent Years.",
x = "Year",
y = "GDP per Capita (USD)") +
geom_smooth(method = "lm", se = FALSE, color = "Green", linetype = "dashed") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

#The GDP per capita in India has generally increased over time, with steady growth from the 1960s until a sharp acceleration in the early 2000s. This recent rapid rise highlights significant economic progress, likely driven by structural reforms and technological advancements.
2.
For each of the following series, make a graph of the data. If
transforming seems appropriate, do so and describe the effect. Comment
below in answer:
2a. Use the series you chose in #1.
# 2a.Answer:
gdp_India <- gdp_India%>%
mutate(Log_GDP_per_capita = log(GDP_per_capita))
autoplot(gdp_India, Log_GDP_per_capita) +
labs(title = "The log-transformed GDP per capita for India shows a consistent upward\n trend over time, indicating steady economic growth with\n reduced variability in recent years.",
x = "Year",
y = "Log of GDP per Capita") +
geom_smooth(method = "lm", se = FALSE, color = "green", linetype = "dashed") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

2b.
United States GDP from global_economy.
# 2b.Answer:
gdp_us <- global_economy %>%
filter(Country == "United States") %>%
select(Year, GDP)
# # Plotting US GDP over time
autoplot(gdp_us, GDP) +
labs(title = "U.S. GDP Demonstrates a Strong Upward Trend, Growing from Approximately $5 Trillion\n in the 1960s to Over $20 Trillion by 2020, Reflecting Steady Economic Growth\n Throughout the Decades.",
x = "Year",
y = "GDP (USD)") +
geom_smooth(method = "lm", se = FALSE, color = "green", linetype = "dashed") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

# The graph illustrates a consistent increase in U.S. GDP over time, showcasing steady economic growth, with an accelerating trend observed in recent decades.
2c.
Slaughter of Victorian “Bulls, bullocks and steers” in
aus_livestock
# 2c.Answer:
victorian_cattle <- aus_livestock %>%
filter(State == "Victoria", Animal == "Bulls, bullocks and steers")
# Plotting the number of slaughters over time
autoplot(victorian_cattle, Count) +
labs(title = "
The Slaughter of Bulls, Bullocks, and Steers in Victoria Decreased from Over\n 125,000 in the 1980s to Approximately 50,000 in Recent Years.",
x = "Year",
y = "Count") +
geom_smooth(method = "lm", se = FALSE, color = "green", linetype = "dashed") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

# The number of bulls, bullocks, and steers slaughtered in Victoria has decreased from over 125,000 in the 1980s to about 50,000 in recent years.
2d.
Victorian Electricity Demand from vic_elec.
# 2d.Answer:
vic_elec_monthly <- vic_elec %>%
index_by(Month = ~ yearmonth(.)) %>%
summarise(Demand = mean(Demand, na.rm = TRUE))
autoplot(vic_elec_monthly, Demand) +
labs(title = "Victorian Electricity Demand Exhibits Seasonal Peaks in Summer,\nDemonstrating a Distinct Seasonal Trend.",
x = "Date",
y = "Electricity Demand (MW)") +
theme_minimal()

#The monthly average electricity demand in Victoria reveals a distinct seasonal trend, with peaks generally occurring during the summer months, likely reflecting increased demand for cooling.
2e.
Gas production from aus_production.
# 2e.Answer:
gas_production <- aus_production %>%
select(Quarter, Gas)
autoplot(gas_production, Gas) +
labs(title = "Australian Gas Production Increased from Approximately 0 to Over 250 Petajoules,\nExhibiting Significant Seasonal Peaks Throughout the Period.",
x = "Year",
y = "Gas Production (in petajoules)") +
geom_smooth(method = "lm", se = FALSE, color = "green", linetype = "dashed") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

#Australian gas production demonstrates a consistent upward trend with notable seasonal variations, indicating both steady growth and regular peak demands likely influenced by seasonal consumption patterns.
3. Use the canadian_gas data (monthly Canadian gas production in
billions of cubic metres, January 1960 – February 2005).
2a. Plot the data using autoplot(), gg_subseries() , gg_season() to
look at the effect of the changing seasonality over time. Describe the
graphs in your own words. What do you see? What type pf pattern do you
observe?
# 3a.Answer:
# General time series plot
autoplot(canadian_gas) +
labs(title = "Canadian Monthly Gas Production(1960–2005)",
x = "Year",
y = "Gas Production (Billions of Cubic Metres)") +
theme_minimal()
## Plot variable not specified, automatically selected `.vars = Volume`

# The time series plot shows a general upward trend in Canadian gas production from 1960 to 2005, with visible seasonal variations. These fluctuations become more prominent in recent years as production levels increase.
# Monthly Breakdown of Gas Production
gg_subseries(canadian_gas, Volume) +
labs(title = "Monthly Trends in Canadian Gas Production",
y = "Gas Production (Billions of Cubic Metres)") +
theme_minimal()

# The monthly subseries plot reveals higher production levels in winter months, such as January and February, likely due to higher demand for heating. Production levels are lower in summer months, indicating a regular seasonal pattern.
# Seasonal Variation in Gas Production Over Time
gg_season(canadian_gas, Volume) +
labs(title = "Seasonal Pattern in Canadian Gas Production",
y = "Gas Production (Billions of Cubic Metres)") +
theme_minimal()

# The seasonal plot highlights a consistent pattern, with production peaking in colder months and decreasing in warmer months. The amplitude of these seasonal changes increases over time, reflecting a growing variation in production as overall levels rise.
3b.
Do an STL decomposition of the data. You will need to choose a
seasonal window to allow for the changing shape of the seasonal
component.
# 3b.Answer:
canadian_gas_stl <- canadian_gas %>%
model(STL(Volume ~ season(window = "periodic")))
# Plotting Decomposition Components
components(canadian_gas_stl) %>%
autoplot() +
labs(title = "STL Decomposition of Monthly Gas Production in Canada",
x = "Year") +
theme_minimal()

# The STL decomposition shows a strong and growing seasonal pattern in Canadian gas production, with peaks in winter reflecting higher demand. This confirms the seasonal trends observed earlier. The remainder component reveals any irregularities or unexpected changes in production, potentially due to external factors or anomalies.
3c.
How does the seasonal shape change over time? [Hint: Try plotting the
seasonal component using gg_season().]
# 3c.Answer:
# Performing STL decomposition with a periodic seasonal window
canadian_gas_stl <- canadian_gas %>%
model(STL_decomp = STL(Volume ~ season(window = "periodic")))
# Extracting components from the STL decomposition
seasonal_component <- canadian_gas_stl %>%
components() %>%
as_tsibble() %>%
select(Month, season_adjust)
gg_season(seasonal_component, season_adjust) +
labs(title = "Evolution of the Seasonal Pattern in Canadian Gas Production",
y = "Seasonal Component (Billions of Cubic Metres)") +
theme_minimal()

# The seasonal component shows peak production during winter months, with the amplitude of these peaks increasing over time. This trend suggests a rising demand for gas in winter as production levels grow.
3d.
produce a plausible seasonally adjusted series? What are these
numbers, plot the series.
# 3d.Answer:
# Perform STL decomposition with a periodic seasonal window
canadian_gas_stl <- canadian_gas %>%
model(STL_decomp = STL(Volume ~ season(window = "periodic")))
# Generate the seasonally adjusted series by removing seasonal components
canadian_gas_seasonally_adjusted <- components(canadian_gas_stl) %>%
mutate(Seasonally_Adjusted = Volume - season_year) %>%
select(Month, Seasonally_Adjusted)
# Visualize the seasonally adjusted series
autoplot(canadian_gas_seasonally_adjusted, Seasonally_Adjusted) +
labs(title = "Trend in Seasonally Adjusted Canadian Gas Production",
x = "Year",
y = "Gas Production (Billions of Cubic Metres)") +
geom_smooth(method = "lm", se = FALSE, color = "green", linetype = "dashed") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

# The seasonally adjusted series reveals a clear upward trend in Canadian gas production from the 1960s to the early 2000s, highlighting consistent growth in production independent of seasonal fluctuations.
4.
For retail time series, use the below code:
# run the code
set.seed(12345678)
myseries <- aus_retail %>%
filter(`Series ID` == sample(aus_retail$`Series ID`,1))
4a.
Create a training dataset consisting of observations before 2011
myseries_train <- myseries %>%
filter(year(Month) < 2011)
4b.
Check that your data have been split appropriately by producing the
following plot.
autoplot(myseries, Turnover) +
autolayer(myseries_train, Turnover, colour = "red")

4c.
Fit a seasonal naïve model using SNAIVE() applied to your training
data (myseries_train).
#Answer:
fit <- myseries_train %>%
model(SNAIVE(Turnover))
4d.
Check the residuals.
# 4d Answer:
fit %>% gg_tsresiduals()

# Do the residuals appear to be uncorrelated and normally distributed?
# Answ: The residuals display an approximately normal distribution, forming a bell-shaped curve centered around zero, suggesting they may be normally distributed.
4e.
Produce forecasts for the test data with given code below:
# 4e Answer:
fc <- fit %>%
forecast(new_data = anti_join(myseries, myseries_train))
## Joining with `by = join_by(State, Industry, `Series ID`, Month, Turnover)`
fc %>% autoplot(myseries)

Joining, by = c(“State”, “Industry”, “Series ID”, “Month”,
“Turnover”)
4f.
Compare the accuracy of your forecasts against the actual values with
given code below:
## # A tibble: 1 × 12
## State Industry .model .type ME RMSE MAE MPE MAPE MASE RMSSE ACF1
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Norther… Clothin… SNAIV… Trai… 0.439 1.21 0.915 5.23 12.4 1 1 0.768
fc %>% accuracy(myseries)
## # A tibble: 1 × 12
## .model State Industry .type ME RMSE MAE MPE MAPE MASE RMSSE ACF1
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 SNAIVE(T… Nort… Clothin… Test 0.836 1.55 1.24 5.94 9.06 1.36 1.28 0.601
# 4f Answ:
fc <- forecast(fit)
autoplot(fc, myseries)

## # A tibble: 1 × 12
## .model State Industry .type ME RMSE MAE MPE MAPE MASE RMSSE ACF1
## <chr> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 SNAIV… Nort… Clothin… Test -0.125 0.765 0.6 -1.14 4.59 0.656 0.631 -0.0541
# The model is quite accurate considering the RMSE Score of 1.228089
4g.
How sensitive are the accuracy measures to the amount of training
data used?
# 4g Answer: The accuracy measures are influenced by the quantity of training data used; with limited data, errors may increase, and metrics such as RMSE, MAE, and MAPE can become less stable.
5.
5a.
Create a training set for Australian takeaway food turnover
(aus_retail) by withholding the last four years as a test set.
# 5a.Answer:
# Filter the aus_retail dataset to include only takeaway food turnover data
takeaway_data <- aus_retail %>%
filter(Industry == "Takeaway food services") %>%
select(-Industry) # Drop the Industry column
#Set the cutoff date by subtracting 48 months (4 years) from the latest date in the dataset
cutoff_date <- max(takeaway_data$Month) - 48
# Define the training set with data before the cutoff date
takeaway_train <- takeaway_data %>%
filter(Month < cutoff_date)
# Define the test set with data from the last four years
takeaway_test <- takeaway_data %>%
filter(Month >= cutoff_date)
# Display the structure of the training and test sets
takeaway_train
## # A tsibble: 3,064 x 4 [1M]
## # Key: State [8]
## State `Series ID` Month Turnover
## <chr> <chr> <mth> <dbl>
## 1 Australian Capital Territory A3349850K 1982 Apr 3.2
## 2 Australian Capital Territory A3349850K 1982 May 3.3
## 3 Australian Capital Territory A3349850K 1982 Jun 3.5
## 4 Australian Capital Territory A3349850K 1982 Jul 3.5
## 5 Australian Capital Territory A3349850K 1982 Aug 3.7
## 6 Australian Capital Territory A3349850K 1982 Sep 3.9
## 7 Australian Capital Territory A3349850K 1982 Oct 4
## 8 Australian Capital Territory A3349850K 1982 Nov 4.3
## 9 Australian Capital Territory A3349850K 1982 Dec 4.3
## 10 Australian Capital Territory A3349850K 1983 Jan 3.9
## # ℹ 3,054 more rows
## # A tsibble: 392 x 4 [1M]
## # Key: State [8]
## State `Series ID` Month Turnover
## <chr> <chr> <mth> <dbl>
## 1 Australian Capital Territory A3349850K 2014 Dec 21.1
## 2 Australian Capital Territory A3349850K 2015 Jan 17.3
## 3 Australian Capital Territory A3349850K 2015 Feb 17.3
## 4 Australian Capital Territory A3349850K 2015 Mar 19.9
## 5 Australian Capital Territory A3349850K 2015 Apr 20.1
## 6 Australian Capital Territory A3349850K 2015 May 20.6
## 7 Australian Capital Territory A3349850K 2015 Jun 20.5
## 8 Australian Capital Territory A3349850K 2015 Jul 21.5
## 9 Australian Capital Territory A3349850K 2015 Aug 21.3
## 10 Australian Capital Territory A3349850K 2015 Sep 20.9
## # ℹ 382 more rows
5b.
Fit all the appropriate benchmark methods to the training set and
forecast the periods covered by the test set.
# 5b.Answer:
# Fit benchmark forecasting models to the training data
fit_benchmarks <- takeaway_train %>%
model(
Mean = MEAN(Turnover),
Naive = NAIVE(Turnover),
Seasonal_Naive = SNAIVE(Turnover),
)
# Generate forecasts for the test period using each benchmark model
fc_benchmarks <- fit_benchmarks %>%
forecast(new_data = takeaway_test)
# Plot benchmark forecasts alongside actual values in the test set
fc_benchmarks %>%
autoplot(takeaway_train, level = NULL) +
autolayer(takeaway_test, Turnover, color = "yellow", linetype = "dashed") +
labs(title = "Australian Takeaway Food Turnover: Benchmark Model Forecasts",
x = "Date",
y = "Turnover (AUD)") +
theme_minimal()

5c.
Compute the accuracy of your forecasts. Which method does best?
# 5c.Answer:
# Calculate accuracy metrics for each benchmark model against the test set
accuracy_metrics <- fc_benchmarks %>%
accuracy(takeaway_test)
# Display the table of accuracy metrics
accuracy_metrics
## # A tibble: 24 × 11
## .model State .type ME RMSE MAE MPE MAPE MASE RMSSE ACF1
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Mean Australian C… Test 13.1 13.5 13.1 54.8 54.8 NaN NaN 0.819
## 2 Mean New South Wa… Test 316. 320. 316. 59.3 59.3 NaN NaN 0.718
## 3 Mean Northern Ter… Test 9.70 9.85 9.70 49.9 49.9 NaN NaN 0.689
## 4 Mean Queensland Test 166. 167. 166. 53.1 53.1 NaN NaN 0.198
## 5 Mean South Austra… Test 43.6 44.2 43.6 48.9 48.9 NaN NaN 0.551
## 6 Mean Tasmania Test 13.6 13.9 13.6 49.9 49.9 NaN NaN 0.706
## 7 Mean Victoria Test 171. 173. 171. 52.9 52.9 NaN NaN 0.609
## 8 Mean Western Aust… Test 97.2 98.3 97.2 59.5 59.5 NaN NaN 0.791
## 9 Naive Australian C… Test 2.64 3.94 3.22 9.74 12.8 NaN NaN 0.819
## 10 Naive New South Wa… Test 74.6 89.9 77.3 13.3 14.0 NaN NaN 0.718
## # ℹ 14 more rows
# Determine the model with the best performance based on the lowest RMSE value
best_model <- accuracy_metrics %>%
filter(RMSE == min(RMSE)) %>%
select(.model, RMSE, MAE, MAPE)
# Output the performance metrics for the best model
best_model
## # A tibble: 1 × 4
## .model RMSE MAE MAPE
## <chr> <dbl> <dbl> <dbl>
## 1 Naive 2.94 2.53 12.6
# The Naive model demonstrates the highest accuracy among the benchmarks..
5d.
Do the residuals from the best method resemble white noise?
# 5d.Answer:
# Extract the optimal model based on RMSE
best_fit <- fit_benchmarks %>%
select(!!best_model$.model)
# Compute residuals for the optimal model using the training data
residuals_best <- residuals(best_fit)
# Assess autocorrelation in the residuals
acf_residuals <- residuals_best %>%
ACF(.resid) %>%
autoplot() +
labs(title = "Autocorrelation Function (ACF) of Residuals from the Optimal Model")
# Create a histogram and QQ plot to evaluate the normality of residuals
hist_residuals <- residuals_best %>%
ggplot(aes(x = .resid)) +
geom_histogram(aes(y = ..density..), bins = 20, fill = "yellow", color = "black") +
geom_density(color = "red") +
labs(title = "Residuals Histogram", x = "Residuals", y = "Density")
qq_residuals <- residuals_best %>%
ggplot(aes(sample = .resid)) +
stat_qq() +
stat_qq_line() +
labs(title = "QQ Plot of Residuals", x = "Theoretical Quantiles", y = "Sample Quantiles")
# Display the visualizations
acf_residuals



# The residuals exhibit some autocorrelation, as indicated by the ACF plot, and show deviations from normality in the QQ plot. This suggests that the model may not have fully captured all underlying patterns in the data, indicating some remaining structure in the residuals.
6.
Using the code below, get a series (it gets a series randomly by
using sample() function):
set.seed(12345678)
myseries <- aus_retail %>%
filter(`Series ID` == sample(aus_retail$`Series ID`,1))
see head of your series to check it is a tsibble data, and remove
NA’s if there is any with these commands:
## # A tsibble: 6 x 5 [1M]
## # Key: State, Industry [1]
## State Industry `Series ID` Month Turnover
## <chr> <chr> <chr> <mth> <dbl>
## 1 Northern Territory Clothing, footwear and perso… A3349767W 1988 Apr 2.3
## 2 Northern Territory Clothing, footwear and perso… A3349767W 1988 May 2.9
## 3 Northern Territory Clothing, footwear and perso… A3349767W 1988 Jun 2.6
## 4 Northern Territory Clothing, footwear and perso… A3349767W 1988 Jul 2.8
## 5 Northern Territory Clothing, footwear and perso… A3349767W 1988 Aug 2.9
## 6 Northern Territory Clothing, footwear and perso… A3349767W 1988 Sep 3
myseries = myseries %>% filter(!is.na(`Series ID`))
6a.
What is the name of the series you randomly choose? Write it.
# 6a.Answer:
myseries_name <- unique(myseries$`Series ID`)
print(myseries_name)
## [1] "A3349767W"
6b.
Run a linear regression of Turnover on trend.(Hint: use TSLM() and
trend() functions)
# 6b.Answer:
model <- myseries %>%
model(Linear_Trend = TSLM(Turnover ~ trend()))
6c.
See the regression result by report() command.
# 6c.Answer:
report(model)
## Series: Turnover
## Model: TSLM
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.0795 -1.1704 -0.1640 0.9683 7.4514
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.5313376 0.1983464 17.80 <2e-16 ***
## trend() 0.0307747 0.0009291 33.12 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.901 on 367 degrees of freedom
## Multiple R-squared: 0.7493, Adjusted R-squared: 0.7486
## F-statistic: 1097 on 1 and 367 DF, p-value: < 2.22e-16
6d.
By using this model, forecast it for the next 3 years. What are the
values of the next 3 years, monthly values?
# 6d.Answer:
# Create a forecast for the next 3 years (36 months)
forecast_values <- model %>%
forecast(h = 36)
# Show the forecasted values
forecast_values %>%
as_tibble() %>%
select(Month, .mean) %>%
print()
## # A tibble: 36 × 2
## Month .mean
## <mth> <dbl>
## 1 2019 Jan 14.9
## 2 2019 Feb 14.9
## 3 2019 Mar 15.0
## 4 2019 Apr 15.0
## 5 2019 May 15.0
## 6 2019 Jun 15.1
## 7 2019 Jul 15.1
## 8 2019 Aug 15.1
## 9 2019 Sep 15.2
## 10 2019 Oct 15.2
## # ℹ 26 more rows
6d.
Plot the forecast values along with the original data.
# 6d.Answer:
# Create a forecast for the next 3 years (36 months)
forecast_values <- model %>%
forecast(h = 36)
# Vizualize the original data and forecasted values
autoplot(myseries, Turnover) +
autolayer(forecast_values, .mean, series = "Forecast", PI = FALSE) +
labs(title = "3-Year Turnover Forecast",
x = "Month",
y = "Turnover (AUD)") +
theme_minimal()

6e.
Get the residuals from the model. And check the residuals to check
whether or not it satisfies the requirements for white noise error
terms.(hint: augment() and gg_tsresiduals() functions)
# 6e.Answer:
gg_tsresiduals(model)

#The residuals show patterns, autocorrelation at lag 12, and deviations from normality, indicating they do not resemble white noise.
7.
Half-hourly electricity demand for Victoria, Australia is contained
in vic_elec. Extract the January 2014 electricity demand, and aggregate
this data to daily with daily total demands and maximum temperatures.
Run the code below:
jan_vic_elec <- vic_elec %>%
filter(yearmonth(Time) == yearmonth("2014 Jan")) %>%
index_by(Date = as_date(Time)) %>%
summarise(Demand = sum(Demand), Temperature = max(Temperature))
7a.
Plot the data and find the regression model for Demand with
temperature as a predictor variable. Why is there a positive
relationship?
# 7a.Answer:
# Visualize the relationship between Demand and Temperature
jan_vic_elec %>%
ggplot(aes(x = Temperature, y = Demand)) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, color = "red") +
labs(title = "Relationship Between Daily Electricity Demand and Temperature (January 2014)",
x = expression("Temperature ("* degree * "C)"),
y = "Demand (MW)") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'

# Fit a linear regression model using Temperature as a predictor for Demand
model <- jan_vic_elec %>%
model(lm_model = TSLM(Demand ~ Temperature))
# The observed positive correlation between temperature and electricity demand suggests that higher temperatures drive up demand, likely due to increased air conditioning use. This trend is especially evident on hotter days, where cooling needs lead to a direct increase in electricity consumption.
7b.
Produce a residual plot. Is the model adequate? Are there any
outliers or influential observations?
# 7b.Answer:
gg_tsresiduals(model)

# The model may be insufficient, as the residuals show patterns and autocorrelation, suggesting potential outliers or influential points impacting the model's accuracy.
7c.
Use the model to forecast the electricity demand that you would
expect for the next day if the maximum temperature was 15∘C and compare
it with the forecast if the with maximum temperature was 35∘C. Do you
believe these forecasts?
# 7c.Answer:
electricity_demand_15 <- jan_vic_elec %>%
model(TSLM(Demand ~ Temperature)) %>%
forecast(
new_data(jan_vic_elec, 1) %>%
mutate(Temperature = 15)
) %>%
autoplot(jan_vic_elec)+labs(title=expression("Projected Electricity Demand for Next Day with Max Temperature of 15" * degree * "C"))
electricity_demand_15

#Forecast electricity demand for the next day if the maximum temperature is 35°C
electricity_demand_35 <- jan_vic_elec %>%
model(TSLM(Demand ~ Temperature)) %>%
forecast(
new_data(jan_vic_elec, 1) %>%
mutate(Temperature = 35)
) %>%
autoplot(jan_vic_elec)+labs(title=expression("Projected Electricity Demand for Next Day with Max Temperature of 35" * degree * "C"))
electricity_demand_35

# These forecasts offer a general indication of demand but should be interpreted with caution.
7d.
Do you believe these forecasts? The following R code will get you
started:
jan_vic_elec %>%
model(TSLM(Demand ~ Temperature)) %>%
forecast(
new_data(jan_vic_elec, 1) %>%
mutate(Temperature = 15)
) %>%
autoplot(jan_vic_elec)

# 7d.Answer:
#The forecast appears inaccurate, as the average demand has never dropped below 190000.
7e.
Give prediction intervals for your forecasts.
# 7e.Answer:
# Forecast and plot electricity demand for the next day assuming a maximum temperature of 15°C
electricity_demand_15 <- jan_vic_elec %>%
model(TSLM(Demand ~ Temperature)) %>%
forecast(
new_data(jan_vic_elec, 1) %>%
mutate(Temperature = 15)
) %>%
autoplot(jan_vic_elec) +
labs(title = expression("Next-Day Electricity Demand Forecast at Max Temperature of 15" * degree * "C"),
y = "Electricity Demand (MW)", x = "Date")
# Display the forecast plot
print(electricity_demand_15)

# Forecast and plot electricity demand for the next day assuming a maximum temperature of 35°C
electricity_demand_35 <- jan_vic_elec %>%
model(TSLM(Demand ~ Temperature)) %>%
forecast(
new_data(jan_vic_elec, 1) %>%
mutate(Temperature = 35)
) %>%
autoplot(jan_vic_elec) +
labs(title = expression("Next-Day Electricity Demand Forecast at Max Temperature of 35"* degree * "C"),
y = "Electricity Demand (MW)", x = "Date")
# Display the forecast plot
print(electricity_demand_35)

8.
Read the shampoo data given in excel (Import Dataset as Excel)
#a. View the shampoo sales data. How many variables are there? Find how many rows and columns in the data?
library(readxl)
shampoo <- read_excel("~/Business Forecating/Midterm/shampoo-2.xlsx")
dim(shampoo)
## [1] 36 2
#b. Is the data annual, monthly, quarterly?
unique(shampoo$Month)
## [1] "1995-01-01 UTC" "1995-02-01 UTC" "1995-03-01 UTC" "1995-04-01 UTC"
## [5] "1995-05-01 UTC" "1995-06-01 UTC" "1995-07-01 UTC" "1995-08-01 UTC"
## [9] "1995-09-01 UTC" "1995-10-01 UTC" "1995-11-01 UTC" "1995-12-01 UTC"
## [13] "1996-01-01 UTC" "1996-02-01 UTC" "1996-03-01 UTC" "1996-04-01 UTC"
## [17] "1996-05-01 UTC" "1996-06-01 UTC" "1996-07-01 UTC" "1996-08-01 UTC"
## [21] "1996-09-01 UTC" "1996-10-01 UTC" "1996-11-01 UTC" "1996-12-01 UTC"
## [25] "1997-01-01 UTC" "1997-02-01 UTC" "1997-03-01 UTC" "1997-04-01 UTC"
## [29] "1997-05-01 UTC" "1997-06-01 UTC" "1997-07-01 UTC" "1997-08-01 UTC"
## [33] "1997-09-01 UTC" "1997-10-01 UTC" "1997-11-01 UTC" "1997-12-01 UTC"
#c. Convert the data into tibble , then tsibble
shampoo <- shampoo %>%
mutate(monthly = yearmonth(Month)) %>%
select(-Month) %>%
as_tibble() %>%
as_tsibble(index = monthly)
#d. Plot the shampoo sales. What do you see from the data pattern? What does x-axis represent?
# Comment here. Use plot() and autoplot().Put the name for y axis, and a title for the graph.
plot(shampoo$monthly, shampoo$sales, type = "l", main = "Shampoo Sales Trends Over Time", xlab = "Date", ylab = "Sales")

autoplot(shampoo, sales) +
labs(title = "Shampoo Sales Trends Over Time", y = "Sales", x = "Date")

#e. What is the average, and median of shampoo sales. Put it on a histogram.
avg_sales <- mean(shampoo$sales, na.rm = TRUE)
median_sales <- median(shampoo$sales, na.rm = TRUE)
ggplot(shampoo, aes(x = sales)) +
geom_histogram(binwidth = 50, fill = "yellow", alpha = 0.7) +
labs(title = "Distribution of Shampoo Sales", x = "Sales", y = "Frequency") +
geom_vline(aes(xintercept = avg_sales), color = "red", linetype = "dashed") +
geom_vline(aes(xintercept = median_sales), color = "blue", linetype = "dashed")

#f. Get seasonal plot. What do you see/ is there any pattern, is tehre any seasonality.
gg_season(shampoo, sales) +
labs(title = "Seasonal Plot of Shampoo Sales", y = "Sales", x = "Month")

#g. Get a linear regression line with trend and dummy for each month (Hint: use trend and season in regression equation).
lm_model <- shampoo %>%
model(TSLM(sales ~ trend() + season()))
report(lm_model)
## Series: sales
## Model: TSLM
##
## Residuals:
## Min 1Q Median 3Q Max
## -129.60 -62.32 -4.84 53.76 152.72
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 113.867 55.740 2.043 0.0527 .
## trend() 11.754 1.534 7.664 8.88e-08 ***
## season()year2 -33.154 73.630 -0.450 0.6567
## season()year3 -53.808 73.678 -0.730 0.4726
## season()year4 -24.628 73.757 -0.334 0.7415
## season()year5 -56.015 73.869 -0.758 0.4560
## season()year6 -27.802 74.012 -0.376 0.7106
## season()year7 7.244 74.187 0.098 0.9231
## season()year8 -37.043 74.393 -0.498 0.6233
## season()year9 27.536 74.629 0.369 0.7155
## season()year10 -32.518 74.897 -0.434 0.6682
## season()year11 9.895 75.194 0.132 0.8964
## season()year12 -4.259 75.522 -0.056 0.9555
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 90.16 on 23 degrees of freedom
## Multiple R-squared: 0.7592, Adjusted R-squared: 0.6336
## F-statistic: 6.043 on 12 and 23 DF, p-value: 0.00011612
#h. Comment on each estimated coefficient of the model.Are they statistically significant at 5 % significance level?
#No, the majority of them are not statistically significant at the 5% significance level.
#i. Which month has the highest sales?
highest_sales_month <- shampoo %>%
filter(sales == max(sales, na.rm = TRUE)) %>%
select(monthly, sales)
print(highest_sales_month)
## # A tsibble: 1 x 2 [1M]
## monthly sales
## <mth> <dbl>
## 1 1997 Sep 682
#j. Forecast it for the next year. What are the values
forecast_next_year <- lm_model %>%
forecast(h = "1 year")
print(forecast_next_year)
## # A fable: 12 x 4 [1M]
## # Key: .model [1]
## .model monthly
## <chr> <mth>
## 1 TSLM(sales ~ trend() + season()) 1998 Jan
## 2 TSLM(sales ~ trend() + season()) 1998 Feb
## 3 TSLM(sales ~ trend() + season()) 1998 Mar
## 4 TSLM(sales ~ trend() + season()) 1998 Apr
## 5 TSLM(sales ~ trend() + season()) 1998 May
## 6 TSLM(sales ~ trend() + season()) 1998 Jun
## 7 TSLM(sales ~ trend() + season()) 1998 Jul
## 8 TSLM(sales ~ trend() + season()) 1998 Aug
## 9 TSLM(sales ~ trend() + season()) 1998 Sep
## 10 TSLM(sales ~ trend() + season()) 1998 Oct
## 11 TSLM(sales ~ trend() + season()) 1998 Nov
## 12 TSLM(sales ~ trend() + season()) 1998 Dec
## # ℹ 2 more variables: sales <dist>, .mean <dbl>
#k. Plot the forecast with original data.
autoplot(shampoo, sales) +
autolayer(forecast_next_year, series = "Forecast", PI = TRUE) +
labs(title = "Shampoo Sales Forecast", y = "Sales", x = "Date")

#l. Check if the residuals of the model is white noise.
gg_tsresiduals(lm_model)

#The residuals do not seem to meet the criteria for white noise, as indicated by the presence of autocorrelation and discernible patterns.
#m. By using the regression model, forecast the 1 year ahead, and then check the accuracy of the forecast. What is MSE, RMSE values?
# Forecast for the next 12 months (1 year ahead)
forecast_next_year <- lm_model %>%
forecast(h = "12 months")
# show forecasted values
print(forecast_next_year)
## # A fable: 12 x 4 [1M]
## # Key: .model [1]
## .model monthly
## <chr> <mth>
## 1 TSLM(sales ~ trend() + season()) 1998 Jan
## 2 TSLM(sales ~ trend() + season()) 1998 Feb
## 3 TSLM(sales ~ trend() + season()) 1998 Mar
## 4 TSLM(sales ~ trend() + season()) 1998 Apr
## 5 TSLM(sales ~ trend() + season()) 1998 May
## 6 TSLM(sales ~ trend() + season()) 1998 Jun
## 7 TSLM(sales ~ trend() + season()) 1998 Jul
## 8 TSLM(sales ~ trend() + season()) 1998 Aug
## 9 TSLM(sales ~ trend() + season()) 1998 Sep
## 10 TSLM(sales ~ trend() + season()) 1998 Oct
## 11 TSLM(sales ~ trend() + season()) 1998 Nov
## 12 TSLM(sales ~ trend() + season()) 1998 Dec
## # ℹ 2 more variables: sales <dist>, .mean <dbl>
# Plotting the forecast and the original data
autoplot(shampoo, sales) +
autolayer(forecast_next_year, series = "Forecast", PI = TRUE) +
labs(title = "Shampoo Sales Forecast for Next Year", y = "Sales", x = "Date")

LS0tDQp0aXRsZTogIkVYQU0gSSINCmF1dGhvcjogQWtzaGl0aGEgVmFyYWRhLCBhdmFyYTNAdW5oLm5ld2hhdmVuLmVkdQ0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiBvcGVuaW50cm86OmxhYl9yZXBvcnQNCiAgDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIHdhcm5pbmc9RkFMU0UsIGVycm9yID0gRkFMU0UpDQoNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGZwcDMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNClN5cy50aW1lKCkNCmBgYA0KDQojIyMgMS4JDQpDb25zaWRlciB0aGUgR0RQIGluZm9ybWF0aW9uIGluIGRhdGEgc2V0IGNhbGxlZCBnbG9iYWxfZWNvbm9teSwgd2hpY2ggaXMgYWxyZWFkeSBlbWJlZGRlZCBpbiBmcHAzIHBhY2thZ2UgKG5vIG5lZWQgdG8gdXBsb2FkIGV4dGVybmFsbHkpIA0KDQojIyMgMS4JQ2hvb3NlIGEgcmFuZG9tIGNvdW50cnkgYnkgeW91cnNlbGYuIFRoZW4gcGxvdCB0aGUgR0RQIHBlciBjYXBpdGEgZm9yIHRoaXMgY291bnRyeSBvdmVyIHRpbWU/IEhvdyBHRFAgcGVyIGNhcGl0YSBoYXMgY2hhbmdlZCBvdmVyIHRpbWUgZm9yIHRoZSBzZXJpZXMgeW91IGNob3NlPyBFeHBsYWluIGJyaWVmbHkuDQoNCmBgYHtyfQ0KZ2xvYmFsX2Vjb25vbXkgIyBzZWUgdGhlIGRhdGEuDQoNCg0KIyAxLkFuc3dlcjoNCg0KZ2RwX0luZGlhIDwtIGdsb2JhbF9lY29ub215ICU+JQ0KICBmaWx0ZXIoQ291bnRyeSA9PSAiSW5kaWEiKSAlPiUNCiAgbXV0YXRlKEdEUF9wZXJfY2FwaXRhID0gR0RQIC8gUG9wdWxhdGlvbikgJT4lDQogIHNlbGVjdChZZWFyLCBHRFBfcGVyX2NhcGl0YSkNCg0KDQphdXRvcGxvdChnZHBfSW5kaWEsIEdEUF9wZXJfY2FwaXRhKSArDQogIGxhYnModGl0bGUgPSAiSW5kaWEncyBHRFAgcGVyIENhcGl0YSBTaG93cyBHcmFkdWFsIEdyb3d0aCBmcm9tIDE5NjBzIHRvIDIwMDBzLFxuIHdpdGggUmFwaWQgSW5jcmVhc2UgaW4gUmVjZW50IFllYXJzLiIsDQogICAgICAgeCA9ICJZZWFyIiwNCiAgICAgICB5ID0gIkdEUCBwZXIgQ2FwaXRhIChVU0QpIikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJHcmVlbiIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiNUaGUgR0RQIHBlciBjYXBpdGEgaW4gSW5kaWEgaGFzIGdlbmVyYWxseSBpbmNyZWFzZWQgb3ZlciB0aW1lLCB3aXRoIHN0ZWFkeSBncm93dGggZnJvbSB0aGUgMTk2MHMgdW50aWwgYSBzaGFycCBhY2NlbGVyYXRpb24gaW4gdGhlIGVhcmx5IDIwMDBzLiBUaGlzIHJlY2VudCByYXBpZCByaXNlIGhpZ2hsaWdodHMgc2lnbmlmaWNhbnQgZWNvbm9taWMgcHJvZ3Jlc3MsIGxpa2VseSBkcml2ZW4gYnkgc3RydWN0dXJhbCByZWZvcm1zIGFuZCB0ZWNobm9sb2dpY2FsIGFkdmFuY2VtZW50cy4NCg0KDQpgYGANCg0KIyMjIDIuCQ0KRm9yIGVhY2ggb2YgdGhlIGZvbGxvd2luZyBzZXJpZXMsIG1ha2UgYSBncmFwaCBvZiB0aGUgZGF0YS4gSWYgdHJhbnNmb3JtaW5nIHNlZW1zIGFwcHJvcHJpYXRlLCBkbyBzbyBhbmQgZGVzY3JpYmUgdGhlIGVmZmVjdC4gQ29tbWVudCBiZWxvdyBpbiBhbnN3ZXI6DQoNCiMjIyAyYS4gVXNlIHRoZSBzZXJpZXMgeW91IGNob3NlIGluICMxLg0KYGBge3J9DQoNCiMgMmEuQW5zd2VyOg0KDQpnZHBfSW5kaWEgPC0gZ2RwX0luZGlhJT4lDQogIG11dGF0ZShMb2dfR0RQX3Blcl9jYXBpdGEgPSBsb2coR0RQX3Blcl9jYXBpdGEpKQ0KDQphdXRvcGxvdChnZHBfSW5kaWEsIExvZ19HRFBfcGVyX2NhcGl0YSkgKw0KICBsYWJzKHRpdGxlID0gIlRoZSBsb2ctdHJhbnNmb3JtZWQgR0RQIHBlciBjYXBpdGEgZm9yIEluZGlhIHNob3dzIGEgY29uc2lzdGVudCB1cHdhcmRcbiB0cmVuZCBvdmVyIHRpbWUsIGluZGljYXRpbmcgc3RlYWR5IGVjb25vbWljIGdyb3d0aCB3aXRoXG4gcmVkdWNlZCB2YXJpYWJpbGl0eSBpbiByZWNlbnQgeWVhcnMuIiwNCiAgICAgICB4ID0gIlllYXIiLA0KICAgICAgIHkgPSAiTG9nIG9mIEdEUCBwZXIgQ2FwaXRhIikgKw0KICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImdyZWVuIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KDQpgYGANCg0KIyMjIDJiLgkNClVuaXRlZCBTdGF0ZXMgR0RQIGZyb20gZ2xvYmFsX2Vjb25vbXkuDQpgYGB7cn0NCg0KDQojIDJiLkFuc3dlcjoNCg0KZ2RwX3VzIDwtIGdsb2JhbF9lY29ub215ICU+JQ0KICBmaWx0ZXIoQ291bnRyeSA9PSAiVW5pdGVkIFN0YXRlcyIpICU+JQ0KICBzZWxlY3QoWWVhciwgR0RQKQ0KDQojICMgUGxvdHRpbmcgVVMgR0RQIG92ZXIgdGltZQ0KYXV0b3Bsb3QoZ2RwX3VzLCBHRFApICsNCiAgbGFicyh0aXRsZSA9ICJVLlMuIEdEUCBEZW1vbnN0cmF0ZXMgYSBTdHJvbmcgVXB3YXJkIFRyZW5kLCBHcm93aW5nIGZyb20gQXBwcm94aW1hdGVseSAkNSBUcmlsbGlvblxuIGluIHRoZSAxOTYwcyB0byBPdmVyICQyMCBUcmlsbGlvbiBieSAyMDIwLCBSZWZsZWN0aW5nIFN0ZWFkeSBFY29ub21pYyBHcm93dGhcbiBUaHJvdWdob3V0IHRoZSBEZWNhZGVzLiIsDQogICAgICAgeCA9ICJZZWFyIiwNCiAgICAgICB5ID0gIkdEUCAoVVNEKSIpICsNCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJncmVlbiIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgVGhlIGdyYXBoIGlsbHVzdHJhdGVzIGEgY29uc2lzdGVudCBpbmNyZWFzZSBpbiBVLlMuIEdEUCBvdmVyIHRpbWUsIHNob3djYXNpbmcgc3RlYWR5IGVjb25vbWljIGdyb3d0aCwgd2l0aCBhbiBhY2NlbGVyYXRpbmcgdHJlbmQgb2JzZXJ2ZWQgaW4gcmVjZW50IGRlY2FkZXMuDQoNCmBgYA0KDQojIyMgMmMuCQ0KU2xhdWdodGVyIG9mIFZpY3RvcmlhbiDigJxCdWxscywgYnVsbG9ja3MgYW5kIHN0ZWVyc+KAnSBpbiBhdXNfbGl2ZXN0b2NrDQpgYGB7cn0NCg0KIyAyYy5BbnN3ZXI6DQoNCnZpY3Rvcmlhbl9jYXR0bGUgPC0gYXVzX2xpdmVzdG9jayAlPiUNCiAgZmlsdGVyKFN0YXRlID09ICJWaWN0b3JpYSIsIEFuaW1hbCA9PSAiQnVsbHMsIGJ1bGxvY2tzIGFuZCBzdGVlcnMiKQ0KDQojIFBsb3R0aW5nIHRoZSBudW1iZXIgb2Ygc2xhdWdodGVycyBvdmVyIHRpbWUNCmF1dG9wbG90KHZpY3Rvcmlhbl9jYXR0bGUsIENvdW50KSArDQogIGxhYnModGl0bGUgPSAiDQpUaGUgU2xhdWdodGVyIG9mIEJ1bGxzLCBCdWxsb2NrcywgYW5kIFN0ZWVycyBpbiBWaWN0b3JpYSBEZWNyZWFzZWQgZnJvbSBPdmVyXG4gMTI1LDAwMCBpbiB0aGUgMTk4MHMgdG8gQXBwcm94aW1hdGVseSA1MCwwMDAgaW4gUmVjZW50IFllYXJzLiIsDQogICAgICAgeCA9ICJZZWFyIiwNCiAgICAgICB5ID0gIkNvdW50IikgKw0KICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImdyZWVuIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBUaGUgbnVtYmVyIG9mIGJ1bGxzLCBidWxsb2NrcywgYW5kIHN0ZWVycyBzbGF1Z2h0ZXJlZCBpbiBWaWN0b3JpYSBoYXMgZGVjcmVhc2VkIGZyb20gb3ZlciAxMjUsMDAwIGluIHRoZSAxOTgwcyB0byBhYm91dCA1MCwwMDAgaW4gcmVjZW50IHllYXJzLg0KYGBgDQoNCiMjIyAyZC4NClZpY3RvcmlhbiBFbGVjdHJpY2l0eSBEZW1hbmQgZnJvbSB2aWNfZWxlYy4NCmBgYHtyfQ0KDQoNCiMgMmQuQW5zd2VyOg0KDQp2aWNfZWxlY19tb250aGx5IDwtIHZpY19lbGVjICU+JQ0KICBpbmRleF9ieShNb250aCA9IH4geWVhcm1vbnRoKC4pKSAlPiUNCiAgc3VtbWFyaXNlKERlbWFuZCA9IG1lYW4oRGVtYW5kLCBuYS5ybSA9IFRSVUUpKQ0KDQoNCmF1dG9wbG90KHZpY19lbGVjX21vbnRobHksIERlbWFuZCkgKw0KICBsYWJzKHRpdGxlID0gIlZpY3RvcmlhbiBFbGVjdHJpY2l0eSBEZW1hbmQgRXhoaWJpdHMgU2Vhc29uYWwgUGVha3MgaW4gU3VtbWVyLFxuRGVtb25zdHJhdGluZyBhIERpc3RpbmN0IFNlYXNvbmFsIFRyZW5kLiIsDQogICAgICAgeCA9ICJEYXRlIiwNCiAgICAgICB5ID0gIkVsZWN0cmljaXR5IERlbWFuZCAoTVcpIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KI1RoZSBtb250aGx5IGF2ZXJhZ2UgZWxlY3RyaWNpdHkgZGVtYW5kIGluIFZpY3RvcmlhIHJldmVhbHMgYSBkaXN0aW5jdCBzZWFzb25hbCB0cmVuZCwgd2l0aCBwZWFrcyBnZW5lcmFsbHkgb2NjdXJyaW5nIGR1cmluZyB0aGUgc3VtbWVyIG1vbnRocywgbGlrZWx5IHJlZmxlY3RpbmcgaW5jcmVhc2VkIGRlbWFuZCBmb3IgY29vbGluZy4NCg0KYGBgDQoNCiMjIyAyZS4JDQpHYXMgcHJvZHVjdGlvbiBmcm9tIGF1c19wcm9kdWN0aW9uLg0KYGBge3J9DQoNCg0KIyAyZS5BbnN3ZXI6DQoNCmdhc19wcm9kdWN0aW9uIDwtIGF1c19wcm9kdWN0aW9uICU+JQ0KICBzZWxlY3QoUXVhcnRlciwgR2FzKQ0KDQoNCmF1dG9wbG90KGdhc19wcm9kdWN0aW9uLCBHYXMpICsNCiAgbGFicyh0aXRsZSA9ICJBdXN0cmFsaWFuIEdhcyBQcm9kdWN0aW9uIEluY3JlYXNlZCBmcm9tIEFwcHJveGltYXRlbHkgMCB0byBPdmVyIDI1MCBQZXRham91bGVzLFxuRXhoaWJpdGluZyBTaWduaWZpY2FudCBTZWFzb25hbCBQZWFrcyBUaHJvdWdob3V0IHRoZSBQZXJpb2QuIiwNCiAgICAgICB4ID0gIlllYXIiLA0KICAgICAgIHkgPSAiR2FzIFByb2R1Y3Rpb24gKGluIHBldGFqb3VsZXMpIikgKw0KICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImdyZWVuIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KI0F1c3RyYWxpYW4gZ2FzIHByb2R1Y3Rpb24gZGVtb25zdHJhdGVzIGEgY29uc2lzdGVudCB1cHdhcmQgdHJlbmQgd2l0aCBub3RhYmxlIHNlYXNvbmFsIHZhcmlhdGlvbnMsIGluZGljYXRpbmcgYm90aCBzdGVhZHkgZ3Jvd3RoIGFuZCByZWd1bGFyIHBlYWsgZGVtYW5kcyBsaWtlbHkgaW5mbHVlbmNlZCBieSBzZWFzb25hbCBjb25zdW1wdGlvbiBwYXR0ZXJucy4NCg0KYGBgDQoNCiMjIyAzLglVc2UgdGhlIGNhbmFkaWFuX2dhcyBkYXRhIChtb250aGx5IENhbmFkaWFuIGdhcyBwcm9kdWN0aW9uIGluIGJpbGxpb25zIG9mIGN1YmljIG1ldHJlcywgSmFudWFyeSAxOTYwIOKAkyBGZWJydWFyeSAyMDA1KS4NCiMjIyMgMmEuCVBsb3QgdGhlIGRhdGEgdXNpbmcgYXV0b3Bsb3QoKSwgZ2dfc3Vic2VyaWVzKCkgLCBnZ19zZWFzb24oKSB0byBsb29rIGF0IHRoZSBlZmZlY3Qgb2YgdGhlIGNoYW5naW5nIHNlYXNvbmFsaXR5IG92ZXIgdGltZS4gRGVzY3JpYmUgdGhlIGdyYXBocyBpbiB5b3VyIG93biB3b3Jkcy4gV2hhdCBkbyB5b3Ugc2VlPyBXaGF0IHR5cGUgcGYgcGF0dGVybiBkbyB5b3Ugb2JzZXJ2ZT8NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0V9DQoNCiMgM2EuQW5zd2VyOg0KDQojIEdlbmVyYWwgdGltZSBzZXJpZXMgcGxvdA0KYXV0b3Bsb3QoY2FuYWRpYW5fZ2FzKSArDQogIGxhYnModGl0bGUgPSAiQ2FuYWRpYW4gTW9udGhseSBHYXMgUHJvZHVjdGlvbigxOTYw4oCTMjAwNSkiLA0KICAgICAgIHggPSAiWWVhciIsDQogICAgICAgeSA9ICJHYXMgUHJvZHVjdGlvbiAoQmlsbGlvbnMgb2YgQ3ViaWMgTWV0cmVzKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgVGhlIHRpbWUgc2VyaWVzIHBsb3Qgc2hvd3MgYSBnZW5lcmFsIHVwd2FyZCB0cmVuZCBpbiBDYW5hZGlhbiBnYXMgcHJvZHVjdGlvbiBmcm9tIDE5NjAgdG8gMjAwNSwgd2l0aCB2aXNpYmxlIHNlYXNvbmFsIHZhcmlhdGlvbnMuIFRoZXNlIGZsdWN0dWF0aW9ucyBiZWNvbWUgbW9yZSBwcm9taW5lbnQgaW4gcmVjZW50IHllYXJzIGFzIHByb2R1Y3Rpb24gbGV2ZWxzIGluY3JlYXNlLg0KDQojIE1vbnRobHkgQnJlYWtkb3duIG9mIEdhcyBQcm9kdWN0aW9uDQpnZ19zdWJzZXJpZXMoY2FuYWRpYW5fZ2FzLCBWb2x1bWUpICsNCiAgbGFicyh0aXRsZSA9ICJNb250aGx5IFRyZW5kcyBpbiBDYW5hZGlhbiBHYXMgUHJvZHVjdGlvbiIsDQogICAgICAgeSA9ICJHYXMgUHJvZHVjdGlvbiAoQmlsbGlvbnMgb2YgQ3ViaWMgTWV0cmVzKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgVGhlIG1vbnRobHkgc3Vic2VyaWVzIHBsb3QgcmV2ZWFscyBoaWdoZXIgcHJvZHVjdGlvbiBsZXZlbHMgaW4gd2ludGVyIG1vbnRocywgc3VjaCBhcyBKYW51YXJ5IGFuZCBGZWJydWFyeSwgbGlrZWx5IGR1ZSB0byBoaWdoZXIgZGVtYW5kIGZvciBoZWF0aW5nLiBQcm9kdWN0aW9uIGxldmVscyBhcmUgbG93ZXIgaW4gc3VtbWVyIG1vbnRocywgaW5kaWNhdGluZyBhIHJlZ3VsYXIgc2Vhc29uYWwgcGF0dGVybi4NCg0KIyBTZWFzb25hbCBWYXJpYXRpb24gaW4gR2FzIFByb2R1Y3Rpb24gT3ZlciBUaW1lDQpnZ19zZWFzb24oY2FuYWRpYW5fZ2FzLCBWb2x1bWUpICsNCiAgbGFicyh0aXRsZSA9ICJTZWFzb25hbCBQYXR0ZXJuIGluIENhbmFkaWFuIEdhcyBQcm9kdWN0aW9uIiwNCiAgICAgICB5ID0gIkdhcyBQcm9kdWN0aW9uIChCaWxsaW9ucyBvZiBDdWJpYyBNZXRyZXMpIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyBUaGUgc2Vhc29uYWwgcGxvdCBoaWdobGlnaHRzIGEgY29uc2lzdGVudCBwYXR0ZXJuLCB3aXRoIHByb2R1Y3Rpb24gcGVha2luZyBpbiBjb2xkZXIgbW9udGhzIGFuZCBkZWNyZWFzaW5nIGluIHdhcm1lciBtb250aHMuIFRoZSBhbXBsaXR1ZGUgb2YgdGhlc2Ugc2Vhc29uYWwgY2hhbmdlcyBpbmNyZWFzZXMgb3ZlciB0aW1lLCByZWZsZWN0aW5nIGEgZ3Jvd2luZyB2YXJpYXRpb24gaW4gcHJvZHVjdGlvbiBhcyBvdmVyYWxsIGxldmVscyByaXNlLg0KDQpgYGANCg0KIyMjIDNiLg0KRG8gYW4gU1RMIGRlY29tcG9zaXRpb24gb2YgdGhlIGRhdGEuIFlvdSB3aWxsIG5lZWQgdG8gY2hvb3NlIGEgc2Vhc29uYWwgd2luZG93IHRvIGFsbG93IGZvciB0aGUgY2hhbmdpbmcgc2hhcGUgb2YgdGhlIHNlYXNvbmFsIGNvbXBvbmVudC4NCg0KYGBge3J9DQoNCiMgM2IuQW5zd2VyOg0KDQpjYW5hZGlhbl9nYXNfc3RsIDwtIGNhbmFkaWFuX2dhcyAlPiUNCiAgbW9kZWwoU1RMKFZvbHVtZSB+IHNlYXNvbih3aW5kb3cgPSAicGVyaW9kaWMiKSkpDQoNCiMgUGxvdHRpbmcgRGVjb21wb3NpdGlvbiBDb21wb25lbnRzDQpjb21wb25lbnRzKGNhbmFkaWFuX2dhc19zdGwpICU+JQ0KICBhdXRvcGxvdCgpICsNCiAgbGFicyh0aXRsZSA9ICJTVEwgRGVjb21wb3NpdGlvbiBvZiBNb250aGx5IEdhcyBQcm9kdWN0aW9uIGluIENhbmFkYSIsDQogICAgICAgeCA9ICJZZWFyIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KIyAgVGhlIFNUTCBkZWNvbXBvc2l0aW9uIHNob3dzIGEgc3Ryb25nIGFuZCBncm93aW5nIHNlYXNvbmFsIHBhdHRlcm4gaW4gQ2FuYWRpYW4gZ2FzIHByb2R1Y3Rpb24sIHdpdGggcGVha3MgaW4gd2ludGVyIHJlZmxlY3RpbmcgaGlnaGVyIGRlbWFuZC4gVGhpcyBjb25maXJtcyB0aGUgc2Vhc29uYWwgdHJlbmRzIG9ic2VydmVkIGVhcmxpZXIuIFRoZSByZW1haW5kZXIgY29tcG9uZW50IHJldmVhbHMgYW55IGlycmVndWxhcml0aWVzIG9yIHVuZXhwZWN0ZWQgY2hhbmdlcyBpbiBwcm9kdWN0aW9uLCBwb3RlbnRpYWxseSBkdWUgdG8gZXh0ZXJuYWwgZmFjdG9ycyBvciBhbm9tYWxpZXMuDQpgYGANCg0KIyMjIDNjLg0KSG93IGRvZXMgdGhlIHNlYXNvbmFsIHNoYXBlIGNoYW5nZSBvdmVyIHRpbWU/IFtIaW50OiBUcnkgcGxvdHRpbmcgdGhlIHNlYXNvbmFsIGNvbXBvbmVudCB1c2luZyBnZ19zZWFzb24oKS5dDQpgYGB7cn0NCg0KDQojIDNjLkFuc3dlcjoNCg0KIyBQZXJmb3JtaW5nIFNUTCBkZWNvbXBvc2l0aW9uIHdpdGggYSBwZXJpb2RpYyBzZWFzb25hbCB3aW5kb3cNCmNhbmFkaWFuX2dhc19zdGwgPC0gY2FuYWRpYW5fZ2FzICU+JQ0KICBtb2RlbChTVExfZGVjb21wID0gU1RMKFZvbHVtZSB+IHNlYXNvbih3aW5kb3cgPSAicGVyaW9kaWMiKSkpDQoNCiMgRXh0cmFjdGluZyBjb21wb25lbnRzIGZyb20gdGhlIFNUTCBkZWNvbXBvc2l0aW9uDQpzZWFzb25hbF9jb21wb25lbnQgPC0gY2FuYWRpYW5fZ2FzX3N0bCAlPiUNCiAgY29tcG9uZW50cygpICU+JQ0KICBhc190c2liYmxlKCkgJT4lDQogIHNlbGVjdChNb250aCwgc2Vhc29uX2FkanVzdCkNCg0KZ2dfc2Vhc29uKHNlYXNvbmFsX2NvbXBvbmVudCwgc2Vhc29uX2FkanVzdCkgKw0KICBsYWJzKHRpdGxlID0gIkV2b2x1dGlvbiBvZiB0aGUgU2Vhc29uYWwgUGF0dGVybiBpbiBDYW5hZGlhbiBHYXMgUHJvZHVjdGlvbiIsDQogICAgICAgeSA9ICJTZWFzb25hbCBDb21wb25lbnQgKEJpbGxpb25zIG9mIEN1YmljIE1ldHJlcykiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIFRoZSBzZWFzb25hbCBjb21wb25lbnQgc2hvd3MgcGVhayBwcm9kdWN0aW9uIGR1cmluZyB3aW50ZXIgbW9udGhzLCB3aXRoIHRoZSBhbXBsaXR1ZGUgb2YgdGhlc2UgcGVha3MgaW5jcmVhc2luZyBvdmVyIHRpbWUuIFRoaXMgdHJlbmQgc3VnZ2VzdHMgYSByaXNpbmcgZGVtYW5kIGZvciBnYXMgaW4gd2ludGVyIGFzIHByb2R1Y3Rpb24gbGV2ZWxzIGdyb3cuDQpgYGANCg0KIyMjIDNkLgkNCnByb2R1Y2UgYSBwbGF1c2libGUgc2Vhc29uYWxseSBhZGp1c3RlZCBzZXJpZXM/IFdoYXQgYXJlIHRoZXNlIG51bWJlcnMsIHBsb3QgdGhlIHNlcmllcy4NCmBgYHtyfQ0KDQojIDNkLkFuc3dlcjoNCg0KIyBQZXJmb3JtIFNUTCBkZWNvbXBvc2l0aW9uIHdpdGggYSBwZXJpb2RpYyBzZWFzb25hbCB3aW5kb3cNCmNhbmFkaWFuX2dhc19zdGwgPC0gY2FuYWRpYW5fZ2FzICU+JQ0KICBtb2RlbChTVExfZGVjb21wID0gU1RMKFZvbHVtZSB+IHNlYXNvbih3aW5kb3cgPSAicGVyaW9kaWMiKSkpDQoNCiMgR2VuZXJhdGUgdGhlIHNlYXNvbmFsbHkgYWRqdXN0ZWQgc2VyaWVzIGJ5IHJlbW92aW5nIHNlYXNvbmFsIGNvbXBvbmVudHMNCmNhbmFkaWFuX2dhc19zZWFzb25hbGx5X2FkanVzdGVkIDwtIGNvbXBvbmVudHMoY2FuYWRpYW5fZ2FzX3N0bCkgJT4lDQogIG11dGF0ZShTZWFzb25hbGx5X0FkanVzdGVkID0gVm9sdW1lIC0gc2Vhc29uX3llYXIpICU+JQ0KICBzZWxlY3QoTW9udGgsIFNlYXNvbmFsbHlfQWRqdXN0ZWQpDQoNCiMgVmlzdWFsaXplIHRoZSBzZWFzb25hbGx5IGFkanVzdGVkIHNlcmllcw0KYXV0b3Bsb3QoY2FuYWRpYW5fZ2FzX3NlYXNvbmFsbHlfYWRqdXN0ZWQsIFNlYXNvbmFsbHlfQWRqdXN0ZWQpICsNCiAgbGFicyh0aXRsZSA9ICJUcmVuZCBpbiBTZWFzb25hbGx5IEFkanVzdGVkIENhbmFkaWFuIEdhcyBQcm9kdWN0aW9uIiwNCiAgICAgICB4ID0gIlllYXIiLA0KICAgICAgIHkgPSAiR2FzIFByb2R1Y3Rpb24gKEJpbGxpb25zIG9mIEN1YmljIE1ldHJlcykiKSArDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiZ3JlZW4iLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQojIFRoZSBzZWFzb25hbGx5IGFkanVzdGVkIHNlcmllcyByZXZlYWxzIGEgY2xlYXIgdXB3YXJkIHRyZW5kIGluIENhbmFkaWFuIGdhcyBwcm9kdWN0aW9uIGZyb20gdGhlIDE5NjBzIHRvIHRoZSBlYXJseSAyMDAwcywgaGlnaGxpZ2h0aW5nIGNvbnNpc3RlbnQgZ3Jvd3RoIGluIHByb2R1Y3Rpb24gaW5kZXBlbmRlbnQgb2Ygc2Vhc29uYWwgZmx1Y3R1YXRpb25zLg0KYGBgDQoNCg0KIyMjIDQuDQpGb3IgcmV0YWlsIHRpbWUgc2VyaWVzLCB1c2UgdGhlIGJlbG93IGNvZGU6DQoNCmBgYHtyfQ0KIyBydW4gdGhlIGNvZGUNCnNldC5zZWVkKDEyMzQ1Njc4KQ0KDQpteXNlcmllcyA8LSBhdXNfcmV0YWlsICU+JQ0KICBmaWx0ZXIoYFNlcmllcyBJRGAgPT0gc2FtcGxlKGF1c19yZXRhaWwkYFNlcmllcyBJRGAsMSkpDQoNCg0KYGBgDQoNCiMjIyMgNGEuIA0KQ3JlYXRlIGEgdHJhaW5pbmcgZGF0YXNldCBjb25zaXN0aW5nIG9mIG9ic2VydmF0aW9ucyBiZWZvcmUgMjAxMSANCg0KYGBge3J9DQpteXNlcmllc190cmFpbiA8LSBteXNlcmllcyAlPiUNCiAgZmlsdGVyKHllYXIoTW9udGgpIDwgMjAxMSkNCg0KDQpgYGANCg0KIyMjIyA0Yi4JDQpDaGVjayB0aGF0IHlvdXIgZGF0YSBoYXZlIGJlZW4gc3BsaXQgYXBwcm9wcmlhdGVseSBieSBwcm9kdWNpbmcgdGhlIGZvbGxvd2luZyBwbG90Lg0KDQpgYGB7cn0NCmF1dG9wbG90KG15c2VyaWVzLCBUdXJub3ZlcikgKw0KICBhdXRvbGF5ZXIobXlzZXJpZXNfdHJhaW4sIFR1cm5vdmVyLCBjb2xvdXIgPSAicmVkIikNCmBgYA0KDQojIyMjIDRjLgkNCkZpdCBhIHNlYXNvbmFsIG5hw692ZSBtb2RlbCB1c2luZyBTTkFJVkUoKSBhcHBsaWVkIHRvIHlvdXIgdHJhaW5pbmcgZGF0YSAobXlzZXJpZXNfdHJhaW4pLg0KYGBge3J9DQogI0Fuc3dlcjoNCiAgICBmaXQgPC0gbXlzZXJpZXNfdHJhaW4gJT4lDQogICAgICBtb2RlbChTTkFJVkUoVHVybm92ZXIpKQ0KYGBgDQoNCg0KIyMjIyA0ZC4NCkNoZWNrIHRoZSByZXNpZHVhbHMuDQpgYGB7cn0NCg0KIyA0ZCBBbnN3ZXI6DQoNCmZpdCAlPiUgZ2dfdHNyZXNpZHVhbHMoKQ0KDQojIERvIHRoZSByZXNpZHVhbHMgYXBwZWFyIHRvIGJlIHVuY29ycmVsYXRlZCBhbmQgbm9ybWFsbHkgZGlzdHJpYnV0ZWQ/DQojIEFuc3c6IFRoZSByZXNpZHVhbHMgZGlzcGxheSBhbiBhcHByb3hpbWF0ZWx5IG5vcm1hbCBkaXN0cmlidXRpb24sIGZvcm1pbmcgYSBiZWxsLXNoYXBlZCBjdXJ2ZSBjZW50ZXJlZCBhcm91bmQgemVybywgc3VnZ2VzdGluZyB0aGV5IG1heSBiZSBub3JtYWxseSBkaXN0cmlidXRlZC4NCmBgYA0KDQojIyMjIDRlLg0KUHJvZHVjZSBmb3JlY2FzdHMgZm9yIHRoZSB0ZXN0IGRhdGEgd2l0aCBnaXZlbiBjb2RlIGJlbG93Og0KDQpgYGB7cn0NCiMgNGUgQW5zd2VyOg0KZmMgPC0gZml0ICU+JSAgDQpmb3JlY2FzdChuZXdfZGF0YSA9IGFudGlfam9pbihteXNlcmllcywgbXlzZXJpZXNfdHJhaW4pKQ0KZmMgJT4lIGF1dG9wbG90KG15c2VyaWVzKQ0KDQpgYGANCg0KSm9pbmluZywgYnkgPSBjKCJTdGF0ZSIsICJJbmR1c3RyeSIsICJTZXJpZXMgSUQiLCAiTW9udGgiLCAiVHVybm92ZXIiKQ0KDQojIyMjIDRmLgkNCkNvbXBhcmUgdGhlIGFjY3VyYWN5IG9mIHlvdXIgZm9yZWNhc3RzIGFnYWluc3QgdGhlIGFjdHVhbCB2YWx1ZXMgd2l0aCBnaXZlbiBjb2RlIGJlbG93Og0KYGBge3J9DQpmaXQgJT4lIGFjY3VyYWN5KCkNCmZjICU+JSBhY2N1cmFjeShteXNlcmllcykNCiMgNGYgQW5zdzoNCg0KZmMgPC0gZm9yZWNhc3QoZml0KQ0KYXV0b3Bsb3QoZmMsIG15c2VyaWVzKQ0KYWNjdXJhY3koZmMsIG15c2VyaWVzKQ0KDQojIFRoZSBtb2RlbCBpcyBxdWl0ZSBhY2N1cmF0ZSBjb25zaWRlcmluZyB0aGUgUk1TRSBTY29yZSBvZiAxLjIyODA4OQ0KYGBgDQoNCiMjIyMgNGcuDQpIb3cgc2Vuc2l0aXZlIGFyZSB0aGUgYWNjdXJhY3kgbWVhc3VyZXMgdG8gdGhlIGFtb3VudCBvZiB0cmFpbmluZyBkYXRhIHVzZWQ/DQpgYGB7cn0NCg0KIyA0ZyBBbnN3ZXI6IFRoZSBhY2N1cmFjeSBtZWFzdXJlcyBhcmUgaW5mbHVlbmNlZCBieSB0aGUgcXVhbnRpdHkgb2YgdHJhaW5pbmcgZGF0YSB1c2VkOyB3aXRoIGxpbWl0ZWQgZGF0YSwgZXJyb3JzIG1heSBpbmNyZWFzZSwgYW5kIG1ldHJpY3Mgc3VjaCBhcyBSTVNFLCBNQUUsIGFuZCBNQVBFIGNhbiBiZWNvbWUgbGVzcyBzdGFibGUuDQoNCmBgYA0KDQojIyMgNS4JDQojIyMjIDVhLgkNCkNyZWF0ZSBhIHRyYWluaW5nIHNldCBmb3IgQXVzdHJhbGlhbiB0YWtlYXdheSBmb29kIHR1cm5vdmVyIChhdXNfcmV0YWlsKSBieSB3aXRoaG9sZGluZyB0aGUgbGFzdCBmb3VyIHllYXJzIGFzIGEgdGVzdCBzZXQuIA0KYGBge3J9DQoNCg0KIyA1YS5BbnN3ZXI6DQoNCiMgRmlsdGVyIHRoZSBhdXNfcmV0YWlsIGRhdGFzZXQgdG8gaW5jbHVkZSBvbmx5IHRha2Vhd2F5IGZvb2QgdHVybm92ZXIgZGF0YQ0KdGFrZWF3YXlfZGF0YSA8LSBhdXNfcmV0YWlsICU+JQ0KICBmaWx0ZXIoSW5kdXN0cnkgPT0gIlRha2Vhd2F5IGZvb2Qgc2VydmljZXMiKSAlPiUNCiAgc2VsZWN0KC1JbmR1c3RyeSkgICMgRHJvcCB0aGUgSW5kdXN0cnkgY29sdW1uDQoNCiNTZXQgdGhlIGN1dG9mZiBkYXRlIGJ5IHN1YnRyYWN0aW5nIDQ4IG1vbnRocyAoNCB5ZWFycykgZnJvbSB0aGUgbGF0ZXN0IGRhdGUgaW4gdGhlIGRhdGFzZXQNCmN1dG9mZl9kYXRlIDwtIG1heCh0YWtlYXdheV9kYXRhJE1vbnRoKSAtIDQ4IA0KDQojIERlZmluZSB0aGUgdHJhaW5pbmcgc2V0IHdpdGggZGF0YSBiZWZvcmUgdGhlIGN1dG9mZiBkYXRlDQp0YWtlYXdheV90cmFpbiA8LSB0YWtlYXdheV9kYXRhICU+JQ0KICBmaWx0ZXIoTW9udGggPCBjdXRvZmZfZGF0ZSkNCg0KIyBEZWZpbmUgdGhlIHRlc3Qgc2V0IHdpdGggZGF0YSBmcm9tIHRoZSBsYXN0IGZvdXIgeWVhcnMNCnRha2Vhd2F5X3Rlc3QgPC0gdGFrZWF3YXlfZGF0YSAlPiUNCiAgZmlsdGVyKE1vbnRoID49IGN1dG9mZl9kYXRlKQ0KDQojICBEaXNwbGF5IHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHRyYWluaW5nIGFuZCB0ZXN0IHNldHMNCnRha2Vhd2F5X3RyYWluDQp0YWtlYXdheV90ZXN0DQoNCg0KYGBgDQoNCiMjIyMgNWIuCQ0KRml0IGFsbCB0aGUgYXBwcm9wcmlhdGUgYmVuY2htYXJrIG1ldGhvZHMgdG8gdGhlICAgdHJhaW5pbmcgc2V0IGFuZCBmb3JlY2FzdCB0aGUgcGVyaW9kcyBjb3ZlcmVkIGJ5IHRoZSB0ZXN0IHNldC4NCmBgYHtyfQ0KDQojIDViLkFuc3dlcjoNCg0KDQojIEZpdCBiZW5jaG1hcmsgZm9yZWNhc3RpbmcgbW9kZWxzIHRvIHRoZSB0cmFpbmluZyBkYXRhDQpmaXRfYmVuY2htYXJrcyA8LSB0YWtlYXdheV90cmFpbiAlPiUNCiAgbW9kZWwoDQogICAgTWVhbiA9IE1FQU4oVHVybm92ZXIpLA0KICAgIE5haXZlID0gTkFJVkUoVHVybm92ZXIpLA0KICAgIFNlYXNvbmFsX05haXZlID0gU05BSVZFKFR1cm5vdmVyKSwNCiAgKQ0KDQojICBHZW5lcmF0ZSBmb3JlY2FzdHMgZm9yIHRoZSB0ZXN0IHBlcmlvZCB1c2luZyBlYWNoIGJlbmNobWFyayBtb2RlbA0KZmNfYmVuY2htYXJrcyA8LSBmaXRfYmVuY2htYXJrcyAlPiUNCiAgZm9yZWNhc3QobmV3X2RhdGEgPSB0YWtlYXdheV90ZXN0KQ0KDQojIFBsb3QgYmVuY2htYXJrIGZvcmVjYXN0cyBhbG9uZ3NpZGUgYWN0dWFsIHZhbHVlcyBpbiB0aGUgdGVzdCBzZXQNCmZjX2JlbmNobWFya3MgJT4lDQogIGF1dG9wbG90KHRha2Vhd2F5X3RyYWluLCBsZXZlbCA9IE5VTEwpICsNCiAgYXV0b2xheWVyKHRha2Vhd2F5X3Rlc3QsIFR1cm5vdmVyLCBjb2xvciA9ICJ5ZWxsb3ciLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIGxhYnModGl0bGUgPSAiQXVzdHJhbGlhbiBUYWtlYXdheSBGb29kIFR1cm5vdmVyOiBCZW5jaG1hcmsgTW9kZWwgRm9yZWNhc3RzIiwNCiAgICAgICB4ID0gIkRhdGUiLA0KICAgICAgIHkgPSAiVHVybm92ZXIgKEFVRCkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KIyMjIyA1Yy4JDQpDb21wdXRlIHRoZSBhY2N1cmFjeSBvZiB5b3VyIGZvcmVjYXN0cy4gV2hpY2ggbWV0aG9kIGRvZXMgYmVzdD8NCmBgYHtyfQ0KDQoNCiMgNWMuQW5zd2VyOg0KDQojIENhbGN1bGF0ZSBhY2N1cmFjeSBtZXRyaWNzIGZvciBlYWNoIGJlbmNobWFyayBtb2RlbCBhZ2FpbnN0IHRoZSB0ZXN0IHNldA0KYWNjdXJhY3lfbWV0cmljcyA8LSBmY19iZW5jaG1hcmtzICU+JQ0KICBhY2N1cmFjeSh0YWtlYXdheV90ZXN0KQ0KDQojIERpc3BsYXkgdGhlIHRhYmxlIG9mIGFjY3VyYWN5IG1ldHJpY3MNCmFjY3VyYWN5X21ldHJpY3MNCg0KIyBEZXRlcm1pbmUgdGhlIG1vZGVsIHdpdGggdGhlIGJlc3QgcGVyZm9ybWFuY2UgYmFzZWQgb24gdGhlIGxvd2VzdCBSTVNFIHZhbHVlDQpiZXN0X21vZGVsIDwtIGFjY3VyYWN5X21ldHJpY3MgJT4lDQogIGZpbHRlcihSTVNFID09IG1pbihSTVNFKSkgJT4lDQogIHNlbGVjdCgubW9kZWwsIFJNU0UsIE1BRSwgTUFQRSkNCg0KIyBPdXRwdXQgdGhlIHBlcmZvcm1hbmNlIG1ldHJpY3MgZm9yIHRoZSBiZXN0IG1vZGVsDQpiZXN0X21vZGVsDQoNCiMgVGhlIE5haXZlIG1vZGVsIGRlbW9uc3RyYXRlcyB0aGUgaGlnaGVzdCBhY2N1cmFjeSBhbW9uZyB0aGUgYmVuY2htYXJrcy4uDQoNCmBgYA0KDQojIyMjIDVkLg0KRG8gdGhlIHJlc2lkdWFscyBmcm9tIHRoZSBiZXN0IG1ldGhvZCByZXNlbWJsZSB3aGl0ZSBub2lzZT8NCmBgYHtyfQ0KDQojIDVkLkFuc3dlcjoNCg0KIyBFeHRyYWN0IHRoZSBvcHRpbWFsIG1vZGVsIGJhc2VkIG9uIFJNU0UNCmJlc3RfZml0IDwtIGZpdF9iZW5jaG1hcmtzICU+JQ0KICBzZWxlY3QoISFiZXN0X21vZGVsJC5tb2RlbCkNCg0KIyBDb21wdXRlIHJlc2lkdWFscyBmb3IgdGhlIG9wdGltYWwgbW9kZWwgdXNpbmcgdGhlIHRyYWluaW5nIGRhdGENCnJlc2lkdWFsc19iZXN0IDwtIHJlc2lkdWFscyhiZXN0X2ZpdCkNCg0KIyBBc3Nlc3MgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSByZXNpZHVhbHMNCmFjZl9yZXNpZHVhbHMgPC0gcmVzaWR1YWxzX2Jlc3QgJT4lDQogIEFDRigucmVzaWQpICU+JQ0KICBhdXRvcGxvdCgpICsNCiAgbGFicyh0aXRsZSA9ICJBdXRvY29ycmVsYXRpb24gRnVuY3Rpb24gKEFDRikgb2YgUmVzaWR1YWxzIGZyb20gdGhlIE9wdGltYWwgTW9kZWwiKQ0KDQojIENyZWF0ZSBhIGhpc3RvZ3JhbSBhbmQgUVEgcGxvdCB0byBldmFsdWF0ZSB0aGUgbm9ybWFsaXR5IG9mIHJlc2lkdWFscw0KaGlzdF9yZXNpZHVhbHMgPC0gcmVzaWR1YWxzX2Jlc3QgJT4lDQogIGdncGxvdChhZXMoeCA9IC5yZXNpZCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHkgPSAuLmRlbnNpdHkuLiksIGJpbnMgPSAyMCwgZmlsbCA9ICJ5ZWxsb3ciLCBjb2xvciA9ICJibGFjayIpICsNCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gInJlZCIpICsNCiAgbGFicyh0aXRsZSA9ICJSZXNpZHVhbHMgSGlzdG9ncmFtIiwgeCA9ICJSZXNpZHVhbHMiLCB5ID0gIkRlbnNpdHkiKQ0KDQpxcV9yZXNpZHVhbHMgPC0gcmVzaWR1YWxzX2Jlc3QgJT4lDQogIGdncGxvdChhZXMoc2FtcGxlID0gLnJlc2lkKSkgKw0KICBzdGF0X3FxKCkgKw0KICBzdGF0X3FxX2xpbmUoKSArDQogIGxhYnModGl0bGUgPSAiUVEgUGxvdCBvZiBSZXNpZHVhbHMiLCB4ID0gIlRoZW9yZXRpY2FsIFF1YW50aWxlcyIsIHkgPSAiU2FtcGxlIFF1YW50aWxlcyIpDQoNCiMgRGlzcGxheSB0aGUgdmlzdWFsaXphdGlvbnMNCmFjZl9yZXNpZHVhbHMNCmhpc3RfcmVzaWR1YWxzDQpxcV9yZXNpZHVhbHMNCg0KIyAgVGhlIHJlc2lkdWFscyBleGhpYml0IHNvbWUgYXV0b2NvcnJlbGF0aW9uLCBhcyBpbmRpY2F0ZWQgYnkgdGhlIEFDRiBwbG90LCBhbmQgc2hvdyBkZXZpYXRpb25zIGZyb20gbm9ybWFsaXR5IGluIHRoZSBRUSBwbG90LiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIG1heSBub3QgaGF2ZSBmdWxseSBjYXB0dXJlZCBhbGwgdW5kZXJseWluZyBwYXR0ZXJucyBpbiB0aGUgZGF0YSwgaW5kaWNhdGluZyBzb21lIHJlbWFpbmluZyBzdHJ1Y3R1cmUgaW4gdGhlIHJlc2lkdWFscy4NCmBgYA0KDQoNCiMjIyA2LgkNClVzaW5nIHRoZSBjb2RlIGJlbG93LCBnZXQgYSBzZXJpZXMgKGl0IGdldHMgYSBzZXJpZXMgcmFuZG9tbHkgYnkgdXNpbmcgc2FtcGxlKCkgZnVuY3Rpb24pOg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMzQ1Njc4KQ0KbXlzZXJpZXMgPC0gYXVzX3JldGFpbCAlPiUNCiAgZmlsdGVyKGBTZXJpZXMgSURgID09IHNhbXBsZShhdXNfcmV0YWlsJGBTZXJpZXMgSURgLDEpKQ0KYGBgDQpzZWUgaGVhZCBvZiB5b3VyIHNlcmllcyB0byBjaGVjayBpdCBpcyBhIHRzaWJibGUgZGF0YSwgYW5kIHJlbW92ZSBOQeKAmXMgaWYgdGhlcmUgaXMgYW55IHdpdGggdGhlc2UgY29tbWFuZHM6DQoNCmBgYHtyfQ0KaGVhZChteXNlcmllcykNCm15c2VyaWVzID0gIG15c2VyaWVzICU+JSBmaWx0ZXIoIWlzLm5hKGBTZXJpZXMgSURgKSkNCmBgYA0KDQojIyMjIDZhLg0KV2hhdCBpcyB0aGUgbmFtZSBvZiB0aGUgc2VyaWVzIHlvdSByYW5kb21seSBjaG9vc2U/IFdyaXRlIGl0Lg0KYGBge3J9DQoNCiMgNmEuQW5zd2VyOg0KDQpteXNlcmllc19uYW1lIDwtIHVuaXF1ZShteXNlcmllcyRgU2VyaWVzIElEYCkNCnByaW50KG15c2VyaWVzX25hbWUpDQoNCg0KYGBgDQoNCiMjIyMgNmIuIA0KUnVuIGEgbGluZWFyIHJlZ3Jlc3Npb24gb2YgVHVybm92ZXIgb24gdHJlbmQuKEhpbnQ6IHVzZSBUU0xNKCkgYW5kIHRyZW5kKCkgZnVuY3Rpb25zKQ0KYGBge3J9DQojIDZiLkFuc3dlcjoNCg0KbW9kZWwgPC0gbXlzZXJpZXMgJT4lDQogIG1vZGVsKExpbmVhcl9UcmVuZCA9IFRTTE0oVHVybm92ZXIgfiB0cmVuZCgpKSkNCg0KDQoNCmBgYA0KDQojIyMjIDZjLiANClNlZSB0aGUgcmVncmVzc2lvbiByZXN1bHQgYnkgcmVwb3J0KCkgY29tbWFuZC4NCmBgYHtyfQ0KIyA2Yy5BbnN3ZXI6DQoNCnJlcG9ydChtb2RlbCkNCmBgYA0KDQoNCiMjIyMgNmQuCQ0KQnkgdXNpbmcgdGhpcyBtb2RlbCwgZm9yZWNhc3QgaXQgZm9yIHRoZSBuZXh0IDMgeWVhcnMuIFdoYXQgYXJlIHRoZSB2YWx1ZXMgb2YgdGhlIG5leHQgMyB5ZWFycywgbW9udGhseSB2YWx1ZXM/DQpgYGB7cn0NCg0KIyA2ZC5BbnN3ZXI6DQojIENyZWF0ZSBhIGZvcmVjYXN0IGZvciB0aGUgbmV4dCAzIHllYXJzICgzNiBtb250aHMpDQpmb3JlY2FzdF92YWx1ZXMgPC0gbW9kZWwgJT4lDQogIGZvcmVjYXN0KGggPSAzNikNCg0KIyBTaG93IHRoZSBmb3JlY2FzdGVkIHZhbHVlcw0KZm9yZWNhc3RfdmFsdWVzICU+JQ0KICBhc190aWJibGUoKSAlPiUNCiAgc2VsZWN0KE1vbnRoLCAubWVhbikgJT4lDQogIHByaW50KCkNCg0KDQpgYGANCg0KIyMjIyA2ZC4JDQpQbG90IHRoZSBmb3JlY2FzdCB2YWx1ZXMgYWxvbmcgd2l0aCB0aGUgb3JpZ2luYWwgZGF0YS4NCmBgYHtyfQ0KDQojIDZkLkFuc3dlcjoNCiMgQ3JlYXRlIGEgZm9yZWNhc3QgZm9yIHRoZSBuZXh0IDMgeWVhcnMgKDM2IG1vbnRocykNCmZvcmVjYXN0X3ZhbHVlcyA8LSBtb2RlbCAlPiUNCiAgZm9yZWNhc3QoaCA9IDM2KQ0KDQojIFZpenVhbGl6ZSB0aGUgb3JpZ2luYWwgZGF0YSBhbmQgIGZvcmVjYXN0ZWQgdmFsdWVzDQphdXRvcGxvdChteXNlcmllcywgVHVybm92ZXIpICsNCiAgYXV0b2xheWVyKGZvcmVjYXN0X3ZhbHVlcywgLm1lYW4sIHNlcmllcyA9ICJGb3JlY2FzdCIsIFBJID0gRkFMU0UpICsNCiAgbGFicyh0aXRsZSA9ICIzLVllYXIgVHVybm92ZXIgRm9yZWNhc3QiLA0KICAgICAgIHggPSAiTW9udGgiLA0KICAgICAgIHkgPSAiVHVybm92ZXIgKEFVRCkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQoNCmBgYA0KDQojIyMjIDZlLgkNCkdldCB0aGUgcmVzaWR1YWxzIGZyb20gdGhlIG1vZGVsLiBBbmQgY2hlY2sgdGhlIHJlc2lkdWFscyB0byBjaGVjayB3aGV0aGVyIG9yIG5vdCBpdCBzYXRpc2ZpZXMgdGhlIHJlcXVpcmVtZW50cyBmb3Igd2hpdGUgbm9pc2UgZXJyb3IgdGVybXMuKGhpbnQ6IGF1Z21lbnQoKSBhbmQgZ2dfdHNyZXNpZHVhbHMoKSBmdW5jdGlvbnMpDQoNCmBgYHtyfQ0KDQojIDZlLkFuc3dlcjoNCg0KZ2dfdHNyZXNpZHVhbHMobW9kZWwpDQoNCiNUaGUgcmVzaWR1YWxzIHNob3cgcGF0dGVybnMsIGF1dG9jb3JyZWxhdGlvbiBhdCBsYWcgMTIsIGFuZCBkZXZpYXRpb25zIGZyb20gbm9ybWFsaXR5LCBpbmRpY2F0aW5nIHRoZXkgZG8gbm90IHJlc2VtYmxlIHdoaXRlIG5vaXNlLg0KDQpgYGANCg0KDQojIyMgNy4gDQpIYWxmLWhvdXJseSBlbGVjdHJpY2l0eSBkZW1hbmQgZm9yIFZpY3RvcmlhLCBBdXN0cmFsaWEgaXMgY29udGFpbmVkIGluIHZpY19lbGVjLiBFeHRyYWN0IHRoZSBKYW51YXJ5IDIwMTQgZWxlY3RyaWNpdHkgZGVtYW5kLCBhbmQgYWdncmVnYXRlIHRoaXMgZGF0YSB0byBkYWlseSB3aXRoICBkYWlseSB0b3RhbCBkZW1hbmRzIGFuZCBtYXhpbXVtIHRlbXBlcmF0dXJlcy4gUnVuIHRoZSBjb2RlIGJlbG93Og0KDQpgYGB7cn0NCmphbl92aWNfZWxlYyA8LSB2aWNfZWxlYyAlPiUNCiAgZmlsdGVyKHllYXJtb250aChUaW1lKSA9PSB5ZWFybW9udGgoIjIwMTQgSmFuIikpICU+JQ0KICBpbmRleF9ieShEYXRlID0gYXNfZGF0ZShUaW1lKSkgJT4lDQogIHN1bW1hcmlzZShEZW1hbmQgPSBzdW0oRGVtYW5kKSwgVGVtcGVyYXR1cmUgPSBtYXgoVGVtcGVyYXR1cmUpKQ0KDQpgYGANCg0KIyMjIyA3YS4gDQpQbG90IHRoZSBkYXRhIGFuZCBmaW5kIHRoZSByZWdyZXNzaW9uIG1vZGVsIGZvciBEZW1hbmQgd2l0aCB0ZW1wZXJhdHVyZSBhcyBhIHByZWRpY3RvciB2YXJpYWJsZS4gV2h5IGlzIHRoZXJlIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwPw0KYGBge3J9DQoNCiMgN2EuQW5zd2VyOg0KDQojIFZpc3VhbGl6ZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gRGVtYW5kIGFuZCBUZW1wZXJhdHVyZQ0KamFuX3ZpY19lbGVjICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBUZW1wZXJhdHVyZSwgeSA9IERlbWFuZCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBCZXR3ZWVuIERhaWx5IEVsZWN0cmljaXR5IERlbWFuZCBhbmQgVGVtcGVyYXR1cmUgKEphbnVhcnkgMjAxNCkiLA0KICAgICAgIHggPSBleHByZXNzaW9uKCJUZW1wZXJhdHVyZSAoIiogZGVncmVlICogIkMpIiksDQogICAgICAgeSA9ICJEZW1hbmQgKE1XKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgRml0IGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdXNpbmcgVGVtcGVyYXR1cmUgYXMgYSBwcmVkaWN0b3IgZm9yIERlbWFuZA0KDQptb2RlbCA8LSBqYW5fdmljX2VsZWMgJT4lDQogIG1vZGVsKGxtX21vZGVsID0gVFNMTShEZW1hbmQgfiBUZW1wZXJhdHVyZSkpDQoNCiMgVGhlIG9ic2VydmVkIHBvc2l0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGVtcGVyYXR1cmUgYW5kIGVsZWN0cmljaXR5IGRlbWFuZCBzdWdnZXN0cyB0aGF0IGhpZ2hlciB0ZW1wZXJhdHVyZXMgZHJpdmUgdXAgZGVtYW5kLCBsaWtlbHkgZHVlIHRvIGluY3JlYXNlZCBhaXIgY29uZGl0aW9uaW5nIHVzZS4gVGhpcyB0cmVuZCBpcyBlc3BlY2lhbGx5IGV2aWRlbnQgb24gaG90dGVyIGRheXMsIHdoZXJlIGNvb2xpbmcgbmVlZHMgbGVhZCB0byBhIGRpcmVjdCBpbmNyZWFzZSBpbiBlbGVjdHJpY2l0eSBjb25zdW1wdGlvbi4NCg0KDQpgYGANCg0KIyMjIyA3Yi4gDQpQcm9kdWNlIGEgcmVzaWR1YWwgcGxvdC4gSXMgdGhlIG1vZGVsIGFkZXF1YXRlPyBBcmUgdGhlcmUgYW55IG91dGxpZXJzIG9yIGluZmx1ZW50aWFsIG9ic2VydmF0aW9ucz8NCg0KYGBge3J9DQoNCiMgN2IuQW5zd2VyOg0KZ2dfdHNyZXNpZHVhbHMobW9kZWwpDQoNCiMgVGhlIG1vZGVsIG1heSBiZSBpbnN1ZmZpY2llbnQsIGFzIHRoZSByZXNpZHVhbHMgc2hvdyBwYXR0ZXJucyBhbmQgYXV0b2NvcnJlbGF0aW9uLCBzdWdnZXN0aW5nIHBvdGVudGlhbCBvdXRsaWVycyBvciBpbmZsdWVudGlhbCBwb2ludHMgaW1wYWN0aW5nIHRoZSBtb2RlbCdzIGFjY3VyYWN5Lg0KDQpgYGANCg0KIyMjIyA3Yy4NClVzZSB0aGUgbW9kZWwgdG8gZm9yZWNhc3QgdGhlIGVsZWN0cmljaXR5IGRlbWFuZCB0aGF0IHlvdSB3b3VsZCBleHBlY3QgZm9yIHRoZSBuZXh0IGRheSBpZiB0aGUgbWF4aW11bSB0ZW1wZXJhdHVyZSB3YXMgMTXiiJhDIGFuZCBjb21wYXJlIGl0IHdpdGggdGhlIGZvcmVjYXN0IGlmIHRoZSB3aXRoIG1heGltdW0gdGVtcGVyYXR1cmUgd2FzIDM14oiYQy4gRG8geW91IGJlbGlldmUgdGhlc2UgZm9yZWNhc3RzPw0KDQpgYGB7cn0NCg0KIyA3Yy5BbnN3ZXI6DQoNCmVsZWN0cmljaXR5X2RlbWFuZF8xNSA8LSBqYW5fdmljX2VsZWMgJT4lDQogIG1vZGVsKFRTTE0oRGVtYW5kIH4gVGVtcGVyYXR1cmUpKSAlPiUNCiAgZm9yZWNhc3QoDQogICAgbmV3X2RhdGEoamFuX3ZpY19lbGVjLCAxKSAlPiUNCiAgICAgIG11dGF0ZShUZW1wZXJhdHVyZSA9IDE1KQ0KICApICU+JQ0KICBhdXRvcGxvdChqYW5fdmljX2VsZWMpK2xhYnModGl0bGU9ZXhwcmVzc2lvbigiUHJvamVjdGVkIEVsZWN0cmljaXR5IERlbWFuZCBmb3IgTmV4dCBEYXkgd2l0aCBNYXggVGVtcGVyYXR1cmUgb2YgMTUiICogZGVncmVlICogIkMiKSkNCmVsZWN0cmljaXR5X2RlbWFuZF8xNQ0KDQojRm9yZWNhc3QgZWxlY3RyaWNpdHkgZGVtYW5kIGZvciB0aGUgbmV4dCBkYXkgaWYgdGhlIG1heGltdW0gdGVtcGVyYXR1cmUgaXMgMzXCsEMNCg0KZWxlY3RyaWNpdHlfZGVtYW5kXzM1IDwtIGphbl92aWNfZWxlYyAlPiUNCiAgbW9kZWwoVFNMTShEZW1hbmQgfiBUZW1wZXJhdHVyZSkpICU+JQ0KICBmb3JlY2FzdCgNCiAgICBuZXdfZGF0YShqYW5fdmljX2VsZWMsIDEpICU+JQ0KICAgICAgbXV0YXRlKFRlbXBlcmF0dXJlID0gMzUpDQogICkgJT4lDQogIGF1dG9wbG90KGphbl92aWNfZWxlYykrbGFicyh0aXRsZT1leHByZXNzaW9uKCJQcm9qZWN0ZWQgRWxlY3RyaWNpdHkgRGVtYW5kIGZvciBOZXh0IERheSB3aXRoIE1heCBUZW1wZXJhdHVyZSBvZiAzNSIgKiBkZWdyZWUgKiAiQyIpKQ0KZWxlY3RyaWNpdHlfZGVtYW5kXzM1DQoNCiMgVGhlc2UgZm9yZWNhc3RzIG9mZmVyIGEgZ2VuZXJhbCBpbmRpY2F0aW9uIG9mIGRlbWFuZCBidXQgc2hvdWxkIGJlIGludGVycHJldGVkIHdpdGggY2F1dGlvbi4NCg0KYGBgDQoNCiMjIyMgN2QuDQpEbyB5b3UgYmVsaWV2ZSB0aGVzZSBmb3JlY2FzdHM/IFRoZSBmb2xsb3dpbmcgUiBjb2RlIHdpbGwgZ2V0IHlvdSBzdGFydGVkOg0KYGBge3J9DQogamFuX3ZpY19lbGVjICU+JQ0KICBtb2RlbChUU0xNKERlbWFuZCB+IFRlbXBlcmF0dXJlKSkgJT4lDQogIGZvcmVjYXN0KA0KICAgIG5ld19kYXRhKGphbl92aWNfZWxlYywgMSkgJT4lDQogICAgICBtdXRhdGUoVGVtcGVyYXR1cmUgPSAxNSkNCiAgKSAlPiUNCiAgYXV0b3Bsb3QoamFuX3ZpY19lbGVjKQ0KYGBgDQogIA0KYGBge3J9DQoNCiMgN2QuQW5zd2VyOg0KI1RoZSBmb3JlY2FzdCBhcHBlYXJzIGluYWNjdXJhdGUsIGFzIHRoZSBhdmVyYWdlIGRlbWFuZCBoYXMgbmV2ZXIgZHJvcHBlZCBiZWxvdyAxOTAwMDAuDQoNCmBgYA0KIA0KIyMjIyA3ZS4gDQpHaXZlIHByZWRpY3Rpb24gaW50ZXJ2YWxzIGZvciB5b3VyIGZvcmVjYXN0cy4NCg0KYGBge3J9DQojIDdlLkFuc3dlcjoNCg0KIyBGb3JlY2FzdCBhbmQgcGxvdCBlbGVjdHJpY2l0eSBkZW1hbmQgZm9yIHRoZSBuZXh0IGRheSBhc3N1bWluZyBhIG1heGltdW0gdGVtcGVyYXR1cmUgb2YgMTXCsEMNCmVsZWN0cmljaXR5X2RlbWFuZF8xNSA8LSBqYW5fdmljX2VsZWMgJT4lDQogIG1vZGVsKFRTTE0oRGVtYW5kIH4gVGVtcGVyYXR1cmUpKSAlPiUNCiAgZm9yZWNhc3QoDQogICAgbmV3X2RhdGEoamFuX3ZpY19lbGVjLCAxKSAlPiUNCiAgICAgIG11dGF0ZShUZW1wZXJhdHVyZSA9IDE1KQ0KICApICU+JQ0KICBhdXRvcGxvdChqYW5fdmljX2VsZWMpICsNCiAgbGFicyh0aXRsZSA9IGV4cHJlc3Npb24oIk5leHQtRGF5IEVsZWN0cmljaXR5IERlbWFuZCBGb3JlY2FzdCBhdCBNYXggVGVtcGVyYXR1cmUgb2YgMTUiICogZGVncmVlICogIkMiKSwNCiAgICAgICB5ID0gIkVsZWN0cmljaXR5IERlbWFuZCAoTVcpIiwgeCA9ICJEYXRlIikNCg0KIyBEaXNwbGF5IHRoZSBmb3JlY2FzdCBwbG90DQpwcmludChlbGVjdHJpY2l0eV9kZW1hbmRfMTUpDQoNCiMgRm9yZWNhc3QgYW5kIHBsb3QgZWxlY3RyaWNpdHkgZGVtYW5kIGZvciB0aGUgbmV4dCBkYXkgYXNzdW1pbmcgYSBtYXhpbXVtIHRlbXBlcmF0dXJlIG9mIDM1wrBDDQplbGVjdHJpY2l0eV9kZW1hbmRfMzUgPC0gamFuX3ZpY19lbGVjICU+JQ0KICBtb2RlbChUU0xNKERlbWFuZCB+IFRlbXBlcmF0dXJlKSkgJT4lDQogIGZvcmVjYXN0KA0KICAgIG5ld19kYXRhKGphbl92aWNfZWxlYywgMSkgJT4lDQogICAgICBtdXRhdGUoVGVtcGVyYXR1cmUgPSAzNSkNCiAgKSAlPiUNCiAgYXV0b3Bsb3QoamFuX3ZpY19lbGVjKSArDQogIGxhYnModGl0bGUgPSBleHByZXNzaW9uKCJOZXh0LURheSBFbGVjdHJpY2l0eSBEZW1hbmQgRm9yZWNhc3QgYXQgTWF4IFRlbXBlcmF0dXJlIG9mIDM1IiogZGVncmVlICogIkMiKSwNCiAgICAgICB5ID0gIkVsZWN0cmljaXR5IERlbWFuZCAoTVcpIiwgeCA9ICJEYXRlIikNCg0KIyBEaXNwbGF5IHRoZSBmb3JlY2FzdCBwbG90DQpwcmludChlbGVjdHJpY2l0eV9kZW1hbmRfMzUpDQoNCg0KDQpgYGANCg0KDQojIyMgOC4NClJlYWQgdGhlIHNoYW1wb28gZGF0YSBnaXZlbiBpbiBleGNlbCAoSW1wb3J0IERhdGFzZXQgYXMgRXhjZWwpDQogIA0KYGBge3J9DQojYS4JVmlldyB0aGUgc2hhbXBvbyBzYWxlcyBkYXRhLiBIb3cgbWFueSB2YXJpYWJsZXMgYXJlIHRoZXJlPyBGaW5kIGhvdyBtYW55IHJvd3MgYW5kIGNvbHVtbnMgaW4gdGhlIGRhdGE/DQogIGxpYnJhcnkocmVhZHhsKQ0Kc2hhbXBvbyA8LSByZWFkX2V4Y2VsKCJ+L0J1c2luZXNzIEZvcmVjYXRpbmcvTWlkdGVybS9zaGFtcG9vLTIueGxzeCIpDQpkaW0oc2hhbXBvbykNCg0KI2IuCUlzIHRoZSBkYXRhIGFubnVhbCwgbW9udGhseSwgcXVhcnRlcmx5Pw0KdW5pcXVlKHNoYW1wb28kTW9udGgpDQogIA0KI2MuCUNvbnZlcnQgdGhlIGRhdGEgaW50byB0aWJibGUgLCB0aGVuIHRzaWJibGUgDQpzaGFtcG9vIDwtIHNoYW1wb28gJT4lDQogIG11dGF0ZShtb250aGx5ID0geWVhcm1vbnRoKE1vbnRoKSkgJT4lDQogIHNlbGVjdCgtTW9udGgpICU+JQ0KICBhc190aWJibGUoKSAlPiUNCiAgYXNfdHNpYmJsZShpbmRleCA9IG1vbnRobHkpDQogIA0KI2QuCVBsb3QgdGhlIHNoYW1wb28gc2FsZXMuIFdoYXQgZG8geW91IHNlZSBmcm9tIHRoZSBkYXRhIHBhdHRlcm4/IFdoYXQgZG9lcyB4LWF4aXMgcmVwcmVzZW50PyANCiMgQ29tbWVudCBoZXJlLiBVc2UgcGxvdCgpIGFuZCBhdXRvcGxvdCgpLlB1dCB0aGUgbmFtZSBmb3IgeSBheGlzLCBhbmQgYSB0aXRsZSBmb3IgdGhlIGdyYXBoLg0KDQpwbG90KHNoYW1wb28kbW9udGhseSwgc2hhbXBvbyRzYWxlcywgdHlwZSA9ICJsIiwgbWFpbiA9ICJTaGFtcG9vIFNhbGVzIFRyZW5kcyBPdmVyIFRpbWUiLCB4bGFiID0gIkRhdGUiLCB5bGFiID0gIlNhbGVzIikNCg0KYXV0b3Bsb3Qoc2hhbXBvbywgc2FsZXMpICsgDQogIGxhYnModGl0bGUgPSAiU2hhbXBvbyBTYWxlcyBUcmVuZHMgT3ZlciBUaW1lIiwgeSA9ICJTYWxlcyIsIHggPSAiRGF0ZSIpDQogIA0KI2UuCVdoYXQgaXMgdGhlIGF2ZXJhZ2UsIGFuZCBtZWRpYW4gb2Ygc2hhbXBvbyBzYWxlcy4gUHV0IGl0IG9uIGEgaGlzdG9ncmFtLg0KDQphdmdfc2FsZXMgPC0gbWVhbihzaGFtcG9vJHNhbGVzLCBuYS5ybSA9IFRSVUUpDQptZWRpYW5fc2FsZXMgPC0gbWVkaWFuKHNoYW1wb28kc2FsZXMsIG5hLnJtID0gVFJVRSkNCg0KZ2dwbG90KHNoYW1wb28sIGFlcyh4ID0gc2FsZXMpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNTAsIGZpbGwgPSAieWVsbG93IiwgYWxwaGEgPSAwLjcpICsNCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgU2hhbXBvbyBTYWxlcyIsIHggPSAiU2FsZXMiLCB5ID0gIkZyZXF1ZW5jeSIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IGF2Z19zYWxlcyksIGNvbG9yID0gInJlZCIsIGxpbmV0eXBlID0gImRhc2hlZCIpICsNCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IG1lZGlhbl9zYWxlcyksIGNvbG9yID0gImJsdWUiLCBsaW5ldHlwZSA9ICJkYXNoZWQiKQ0KDQogIA0KI2YuCUdldCBzZWFzb25hbCBwbG90LiBXaGF0IGRvIHlvdSBzZWUvIGlzIHRoZXJlIGFueSBwYXR0ZXJuLCBpcyB0ZWhyZSBhbnkgc2Vhc29uYWxpdHkuDQpnZ19zZWFzb24oc2hhbXBvbywgc2FsZXMpICsNCiAgbGFicyh0aXRsZSA9ICJTZWFzb25hbCBQbG90IG9mIFNoYW1wb28gU2FsZXMiLCB5ID0gIlNhbGVzIiwgeCA9ICJNb250aCIpDQogIA0KI2cuCUdldCBhIGxpbmVhciByZWdyZXNzaW9uIGxpbmUgd2l0aCB0cmVuZCBhbmQgZHVtbXkgZm9yIGVhY2ggbW9udGggKEhpbnQ6IHVzZSB0cmVuZCBhbmQgc2Vhc29uIGluIHJlZ3Jlc3Npb24gZXF1YXRpb24pLg0KbG1fbW9kZWwgPC0gc2hhbXBvbyAlPiUNCiAgbW9kZWwoVFNMTShzYWxlcyB+IHRyZW5kKCkgKyBzZWFzb24oKSkpDQpyZXBvcnQobG1fbW9kZWwpDQogIA0KI2guCUNvbW1lbnQgb24gZWFjaCBlc3RpbWF0ZWQgY29lZmZpY2llbnQgb2YgdGhlIG1vZGVsLkFyZSB0aGV5IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYXQgNSAlIHNpZ25pZmljYW5jZSBsZXZlbD8NCg0KI05vLCB0aGUgbWFqb3JpdHkgb2YgdGhlbSBhcmUgbm90IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYXQgdGhlIDUlIHNpZ25pZmljYW5jZSBsZXZlbC4NCiAgDQojaS4JV2hpY2ggbW9udGggaGFzIHRoZSBoaWdoZXN0IHNhbGVzPw0KaGlnaGVzdF9zYWxlc19tb250aCA8LSBzaGFtcG9vICU+JQ0KICBmaWx0ZXIoc2FsZXMgPT0gbWF4KHNhbGVzLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgc2VsZWN0KG1vbnRobHksIHNhbGVzKQ0KcHJpbnQoaGlnaGVzdF9zYWxlc19tb250aCkNCg0KICANCiNqLglGb3JlY2FzdCBpdCBmb3IgdGhlIG5leHQgeWVhci4gV2hhdCBhcmUgdGhlIHZhbHVlcw0KICANCmZvcmVjYXN0X25leHRfeWVhciA8LSBsbV9tb2RlbCAlPiUNCiAgZm9yZWNhc3QoaCA9ICIxIHllYXIiKQ0KcHJpbnQoZm9yZWNhc3RfbmV4dF95ZWFyKQ0KDQojay4JUGxvdCB0aGUgZm9yZWNhc3Qgd2l0aCBvcmlnaW5hbCBkYXRhLg0KDQphdXRvcGxvdChzaGFtcG9vLCBzYWxlcykgKw0KICBhdXRvbGF5ZXIoZm9yZWNhc3RfbmV4dF95ZWFyLCBzZXJpZXMgPSAiRm9yZWNhc3QiLCBQSSA9IFRSVUUpICsNCiAgbGFicyh0aXRsZSA9ICJTaGFtcG9vIFNhbGVzIEZvcmVjYXN0IiwgeSA9ICJTYWxlcyIsIHggPSAiRGF0ZSIpDQogIA0KI2wuCUNoZWNrIGlmIHRoZSByZXNpZHVhbHMgb2YgdGhlIG1vZGVsIGlzIHdoaXRlIG5vaXNlLg0KDQpnZ190c3Jlc2lkdWFscyhsbV9tb2RlbCkNCg0KI1RoZSByZXNpZHVhbHMgZG8gbm90IHNlZW0gdG8gbWVldCB0aGUgY3JpdGVyaWEgZm9yIHdoaXRlIG5vaXNlLCBhcyBpbmRpY2F0ZWQgYnkgdGhlIHByZXNlbmNlIG9mIGF1dG9jb3JyZWxhdGlvbiBhbmQgZGlzY2VybmlibGUgcGF0dGVybnMuDQogIA0KI20uCUJ5IHVzaW5nIHRoZSByZWdyZXNzaW9uIG1vZGVsLCBmb3JlY2FzdCB0aGUgMSB5ZWFyIGFoZWFkLCBhbmQgdGhlbiBjaGVjayB0aGUgYWNjdXJhY3kgb2YgdGhlIGZvcmVjYXN0LiBXaGF0IGlzIE1TRSwgUk1TRSB2YWx1ZXM/DQoNCiMgRm9yZWNhc3QgZm9yIHRoZSBuZXh0IDEyIG1vbnRocyAoMSB5ZWFyIGFoZWFkKQ0KZm9yZWNhc3RfbmV4dF95ZWFyIDwtIGxtX21vZGVsICU+JQ0KICBmb3JlY2FzdChoID0gIjEyIG1vbnRocyIpDQoNCiMgc2hvdyBmb3JlY2FzdGVkIHZhbHVlcw0KcHJpbnQoZm9yZWNhc3RfbmV4dF95ZWFyKQ0KDQojIFBsb3R0aW5nIHRoZSBmb3JlY2FzdCBhbmQgdGhlIG9yaWdpbmFsIGRhdGENCmF1dG9wbG90KHNoYW1wb28sIHNhbGVzKSArDQogIGF1dG9sYXllcihmb3JlY2FzdF9uZXh0X3llYXIsIHNlcmllcyA9ICJGb3JlY2FzdCIsIFBJID0gVFJVRSkgKw0KICBsYWJzKHRpdGxlID0gIlNoYW1wb28gU2FsZXMgRm9yZWNhc3QgZm9yIE5leHQgWWVhciIsIHkgPSAiU2FsZXMiLCB4ID0gIkRhdGUiKQ0KICANCg0KYGBgDQogICAgDQo=