1 Load library

library(tidyverse)
── Attaching packages ──────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──
✔ ggplot2 3.1.0     ✔ purrr   0.3.0
✔ tibble  2.0.1     ✔ dplyr   0.8.0
✔ tidyr   0.8.2     ✔ stringr 1.4.0
✔ readr   1.3.1     ✔ forcats 0.3.0
── Conflicts ─────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
library(janitor)

Hourly Weather data downloaded from http://www.frontierweather.com/historicaldatasubscribers_hourly.html

Daily Weather data downloaded from http://www.frontierweather.com/weatherdatastore.html

2 Daily weather data

2.1 Read the Houston daily weather data

houston_weather <- read_delim("weather_data/KIAH_daily.txt", delim = ",")
Parsed with column specification:
cols(
  Site4 = col_character(),
  Date = col_character(),
  Source = col_character(),
  `Max Temp` = col_double(),
  `Min Temp` = col_double(),
  `Avg Temp` = col_double(),
  HDDs = col_double(),
  CDDs = col_double(),
  `Precipitation Water Equiv` = col_double(),
  Snowfall = col_double(),
  `Snow/Ice Depth` = col_double()
)
  • Find out what these columns mean.
    • Site4 : Name of the site

    • Date : Date when the data was collected

    • Source : Name of their instrument

    • Max Temp : Maximum temperature of the day

    • Min Temp : Minimum temperature of the day

    • Avg Temp : Average temperature (Max + Min)/2

    • HDDs : Heating degree day (Temps below 65) https://w1.weather.gov/glossary/index.php?letter=h

    • CDDs : Cooling degree day (Temps above 65) - A form of degree day used to estimate energy requirements for air conditioning or refrigeration. For example, if a location experiences a mean temperature of 75°F on a certain day, there were 10 CDD (Cooling Degree Days) that day because 75 - 65 = 10.) https://w1.weather.gov/glossary/index.php?letter=c

    • Precipitation Water Equiv : Rain in inches

    • Snowfall : Amount of snowfall since 24 hours (https://www.weather.gov/gsp/snow)

    • Snow/Ice Depth : The depth of the new and old snow remaining on the ground at observation time (https://www.weather.gov/gsp/snow)

2.1.1 Find out more about this function

??read_delim

2.2 “Format” the data

houston_weather_df <- houston_weather %>%
  mutate(Date=as.Date(Date,format='%m/%d/%Y')) %>%
  separate(Date,c("year","month","day")) %>%
  janitor::clean_names()

2.3 Read Chicago daily weather data

chicago_weather <- read_csv("weather_data/KORD_daily.txt") 
Parsed with column specification:
cols(
  Site4 = col_character(),
  Date = col_character(),
  Source = col_character(),
  `Max Temp` = col_double(),
  `Min Temp` = col_double(),
  `Avg Temp` = col_double(),
  HDDs = col_double(),
  CDDs = col_double(),
  `Precipitation Water Equiv` = col_double(),
  Snowfall = col_double(),
  `Snow/Ice Depth` = col_double()
)

Notice we have used different function but without explicitly mentioning delimiter.

2.4 “Format” Chicago weather

chicago_weather_df <- chicago_weather %>%
  mutate(Date=as.Date(Date,format='%m/%d/%Y')) %>%
  separate(Date,c("year","month","day")) %>%
  janitor::clean_names()

2.5 Get Seattle weather data and format

seattle_weather_df <- read_csv("weather_data/KSEA_daily.txt")  %>%
  mutate(Date = as.Date(Date, format='%m/%d/%Y')) %>%
  separate(Date, c("year","month","day")) %>%
  janitor::clean_names()
Parsed with column specification:
cols(
  Site4 = col_character(),
  Date = col_character(),
  Source = col_character(),
  `Max Temp` = col_double(),
  `Min Temp` = col_double(),
  `Avg Temp` = col_double(),
  HDDs = col_double(),
  CDDs = col_double(),
  `Precipitation Water Equiv` = col_double(),
  Snowfall = col_double(),
  `Snow/Ice Depth` = col_double()
)

2.6 Comparing mean temperature between Houston and Chicago

houston_weather_df %>%
  bind_rows(., chicago_weather_df, seattle_weather_df) %>%
  group_by(site4, year) %>%
  summarise(mean_temp_year=mean(avg_temp)) %>%
  ungroup() %>%
  ggplot(.,aes(x = as.numeric(year), y = mean_temp_year, color = site4)) +
  geom_line(lwd = 2) +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
  theme_bw()

Fix the x axis label and the legend??

2.7 Plot Histogram

houston_weather_df %>%
  bind_rows(., chicago_weather_df, seattle_weather_df) %>%
  ggplot(., aes(x=avg_temp, fill=site4, color=site4)) +
  geom_histogram(position="identity",  alpha = 0.5)

  geom_histogram(position="identity")
geom_bar: na.rm = FALSE
stat_bin: binwidth = NULL, bins = NULL, na.rm = FALSE, pad = FALSE
position_identity 

2.8 Plot Empirical Cumulative Distribution Function

houston_weather_df %>%
  bind_rows(., chicago_weather_df, seattle_weather_df) %>%
  ggplot(.,aes(avg_temp, color = site4)) +
  stat_ecdf(geom = "point") 

A CDF is a function such as y=f(x) where y is the probability of the number x, or any lower number, being chosen at random from that distribution.

source: https://www.che.utah.edu/~tony/course/material/Statistics/18_rv_pdf_cdf.php

Here we are talking about ECDF “Empirical” CDF. This means this is not a representation of the entire set (or theoretical distribution) but what was observed and hence the word “empirical”.

2.9 Stem and leaf plot

stem(houston_weather_df$max_temp)

  The decimal point is 1 digit(s) to the right of the |

   2 | 788889
   3 | 0011112223333333344444444
   3 | 5555666666666677777777777777888888888888999999999999999
   4 | 00000000000000000001111111111111111111111222222222222222222222222222+74
   4 | 55555555555555555555555555555555555555555555555555555556666666666666+210
   5 | 00000000000000000000000000000000000000000000000000000000000000000000+395
   5 | 55555555555555555555555555555555555555555555555555555555555555555555+632
   6 | 00000000000000000000000000000000000000000000000000000000000000000000+850
   6 | 55555555555555555555555555555555555555555555555555555555555555555555+1193
   7 | 00000000000000000000000000000000000000000000000000000000000000000000+1615
   7 | 55555555555555555555555555555555555555555555555555555555555555555555+2158
   8 | 00000000000000000000000000000000000000000000000000000000000000000000+2383
   8 | 55555555555555555555555555555555555555555555555555555555555555555555+2507
   9 | 00000000000000000000000000000000000000000000000000000000000000000000+3016
   9 | 55555555555555555555555555555555555555555555555555555555555555555555+1743
  10 | 00000000000000000000000000000000000000000000000000000000000000000000+167
  10 | 55555566777777899

It can be informative but compared to histogram or ecdf plot, it can be hard to read.

2.10 See the spread of the temperature by month

houston_weather_df %>%
  bind_rows(chicago_weather_df, seattle_weather_df) %>%
  group_by(site4,month) %>%
  summarise(max = max(max_temp,na.rm = T), 
            min = min(min_temp, na.rm = T), 
            mean = mean(avg_temp, na.rm = T)) %>%
  ungroup() %>%
  ggplot(., aes(x = month, y = mean)) +
  geom_linerange(aes( ymin = min, ymax = max), lwd = 2, color = "#FF5400") +
  geom_point(size = 3, color = "#2142A6") +
  coord_flip() +
  theme_bw(base_size = 14) +
  geom_hline(yintercept = 65, linetype = "dashed") +
  xlab("Month") +
  ylab("Temperature in Farahenit") +
  facet_grid(.~site4)

3 Percent drop as compare to previous month.

houston_weather_df %>%
  bind_rows(chicago_weather_df) %>%
  bind_rows(seattle_weather_df) %>%
  group_by(site4, month) %>%
  summarise(mean_avg_temp = mean(avg_temp,na.rm = T)) %>%
  mutate(pct_change = (mean_avg_temp / lag(mean_avg_temp) - 1) * 100) %>%
  mutate(pct_change = case_when(
    is.na(pct_change) ~ 0,
    TRUE ~ as.numeric(pct_change)
  )) %>%
  arrange(pct_change) %>% 
  ggplot(.,aes(x = month, y = pct_change, color = site4)) +
  geom_line(aes(group = site4), size = 1)+
  geom_point() +
  theme_bw()

3.1 Where does it rain the most?

houston_weather_df %>%
  bind_rows(chicago_weather_df, seattle_weather_df) %>%
  group_by(site4,year) %>%
  summarise(sum = sum(precipitation_water_equiv, na.rm = T)) %>%
  ungroup() %>%
  ggplot(., aes(x = year, y = sum, color = site4) ) +
  geom_point() +
  geom_line(aes(group = site4), size = 1)+
  theme_bw(base_size = 14) +
  theme(axis.text.x = element_text(angle = 65, hjust = 1)) +
  ylab("Rainfall in inches") 

This graph shows total rainfall in inches over the years.

4 Average rainfall with the circles showing the maximum recorded rainfall for single day

houston_weather_df %>%
  bind_rows(chicago_weather_df, seattle_weather_df) %>%
  group_by(site4,month) %>%
  summarise(max = max(precipitation_water_equiv,na.rm = T), 
            mean = mean(precipitation_water_equiv, na.rm = T)) %>%
  ungroup() %>%
  ggplot(. ) +
  geom_point(aes(x = month, y = mean,size = max), color = "#2142A6") +
  coord_flip() +
  theme_bw(base_size = 14) +
  xlab("Month") +
  ylab("Average rain fall in inches") +
  facet_wrap(.~site4)

5 Hourly weather data

5.1 Read Houston hourly weather data

houston_weather_hourly <- read_csv("weather_data/KIAH.txt") %>%
  mutate(date=as.Date(Date,format='%m/%d/%Y')) %>%
  separate(date,c("year","month","day")) %>%
  janitor::clean_names()
Parsed with column specification:
cols(
  Site = col_character(),
  Date = col_character(),
  Hour = col_double(),
  Temperature = col_double(),
  Dewpoint = col_double(),
  RH = col_double(),
  WindDir = col_logical(),
  Windspeed = col_double(),
  CldFrac = col_double(),
  MSLP = col_logical(),
  Weather = col_character(),
  Precip = col_logical(),
  Source = col_character()
)
435615 parsing failures.
 row    col           expected  actual                    file
4296 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KIAH.txt'
7237 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KIAH.txt'
8392 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KIAH.txt'
8760 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KIAH.txt'
8761 Precip 1/0/T/F/TRUE/FALSE 1.0e-04 'weather_data/KIAH.txt'
.... ...... .................. ....... .......................
See problems(...) for more details.

5.2 Read Chicago Hourly weather data

chicago_weather_hourly <- read_csv("weather_data/KORD.txt") %>%
  mutate(date = as.Date(Date, format = '%m/%d/%Y')) %>%
  separate(date, c("year","month","day")) %>%
  janitor::clean_names()
Parsed with column specification:
cols(
  Site = col_character(),
  Date = col_character(),
  Hour = col_double(),
  Temperature = col_double(),
  Dewpoint = col_double(),
  RH = col_double(),
  WindDir = col_logical(),
  Windspeed = col_double(),
  CldFrac = col_double(),
  MSLP = col_logical(),
  Weather = col_character(),
  Precip = col_logical(),
  Source = col_character()
)
435438 parsing failures.
 row    col           expected  actual                    file
5556 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KORD.txt'
8760 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KORD.txt'
8761 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KORD.txt'
8762 Precip 1/0/T/F/TRUE/FALSE 0.00    'weather_data/KORD.txt'
8763 Precip 1/0/T/F/TRUE/FALSE 1.0e-04 'weather_data/KORD.txt'
.... ...... .................. ....... .......................
See problems(...) for more details.

5.3 Add Seattle hourly weather data

seattle_weather_hourly <- read_csv("weather_data/KSEA.txt") %>%
  mutate(date=as.Date(Date, format = '%m/%d/%Y')) %>%
  separate(date, c("year", "month", "day")) %>%
  janitor::clean_names()
Parsed with column specification:
cols(
  Site = col_character(),
  Date = col_character(),
  Hour = col_double(),
  Temperature = col_double(),
  Dewpoint = col_double(),
  RH = col_double(),
  WindDir = col_logical(),
  Windspeed = col_double(),
  CldFrac = col_double(),
  MSLP = col_logical(),
  Weather = col_character(),
  Precip = col_double(),
  Source = col_character()
)
261428 parsing failures.
  row     col           expected actual                    file
52584 WindDir 1/0/T/F/TRUE/FALSE  120   'weather_data/KSEA.txt'
52584 MSLP    1/0/T/F/TRUE/FALSE  29.74 'weather_data/KSEA.txt'
52585 WindDir 1/0/T/F/TRUE/FALSE  120   'weather_data/KSEA.txt'
52585 MSLP    1/0/T/F/TRUE/FALSE  29.73 'weather_data/KSEA.txt'
52586 WindDir 1/0/T/F/TRUE/FALSE  000   'weather_data/KSEA.txt'
..... ....... .................. ...... .......................
See problems(...) for more details.

5.4 Is Seattle really cloudy as compare to Chicago and Houston?

houston_weather_hourly %>%
  bind_rows(., chicago_weather_hourly,seattle_weather_hourly ) %>%
  mutate(date=as.Date(date,format='%m/%d/%Y')) %>%
  separate(date,c("year","month","day")) %>%
  group_by(site, year) %>%
  summarise(mean_cloud_coverage = mean(`cld_frac`)) %>%
  ungroup() %>% 
  ggplot(.,aes(x = as.numeric(year), y = mean_cloud_coverage, color = site)) +
  geom_line() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) 

houston_weather_hourly %>%
  bind_rows(., chicago_weather_hourly,seattle_weather_hourly ) %>%
  mutate(date=as.Date(date,format='%m/%d/%Y')) %>%
  separate(date,c("year","month","day")) %>%
  group_by(site, month) %>%
  summarise(sum_cloud_coverage = sum(`cld_frac`),avg_cloud_coverage = mean(`cld_frac`)) %>%
  ungroup() %>% 
  ggplot(.,aes(x = as.numeric(month), y = sum_cloud_coverage, color = site)) +
  geom_line(linetype = "dotdash") +
  geom_point(aes(inherit.aes=TRUE, size = avg_cloud_coverage)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) 
Ignoring unknown aesthetics: inherit.aes

6 Days with less than 30% average cloud coverage

houston_weather_hourly %>%
  bind_rows(., chicago_weather_hourly,seattle_weather_hourly ) %>%
  mutate(date=as.Date(date,format='%m/%d/%Y')) %>%
  separate(date,c("year","month","day")) %>%
  group_by(site, year, month, day) %>%
  summarise(avg_cloud_coverage = mean(`cld_frac`)) %>%
  ungroup() %>% 
  group_by(site, year) %>%
  summarise(no_cloudy_days = sum(avg_cloud_coverage < .30)) %>%
  ggplot(.,aes(x = as.numeric(year), y = no_cloudy_days, color = site)) +
  geom_line(linetype=2) +
  geom_point(aes(inherit.aes=TRUE)) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
  ylab("Number of days with average cloud cover < 30%") +
  xlab("Year")
Ignoring unknown aesthetics: inherit.aes

6.1 Is Chicago the windiest city in our set?

houston_weather_hourly %>%
  bind_rows(., chicago_weather_hourly,seattle_weather_hourly) %>%
  mutate(date=as.Date(date,format = '%m/%d/%Y')) %>%
  separate(date,c("year","month","day")) %>%
  group_by(site, year) %>%
  summarise(mean_windspeed = mean(`windspeed`)) %>%
  ungroup() %>% 
  ggplot(.,aes(x = as.numeric(year), y = mean_windspeed, color = site)) +
  geom_line(size = 2) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) 

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayAtIEFuYWx5emUgd2VhdGhlciBkYXRhIgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgaHRtbF9ub3RlYm9vazoKICAgIGhpZ2hsaWdodDogaGFkZG9jawogICAgbWF0aGpheDogbnVsbAogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKIyBMb2FkIGxpYnJhcnkKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGphbml0b3IpCmBgYAoKSG91cmx5IFdlYXRoZXIgZGF0YSBkb3dubG9hZGVkIGZyb20gaHR0cDovL3d3dy5mcm9udGllcndlYXRoZXIuY29tL2hpc3RvcmljYWxkYXRhc3Vic2NyaWJlcnNfaG91cmx5Lmh0bWwKCkRhaWx5IFdlYXRoZXIgZGF0YSBkb3dubG9hZGVkIGZyb20gaHR0cDovL3d3dy5mcm9udGllcndlYXRoZXIuY29tL3dlYXRoZXJkYXRhc3RvcmUuaHRtbAoKIyBEYWlseSB3ZWF0aGVyIGRhdGEKCiMjIFJlYWQgdGhlIEhvdXN0b24gZGFpbHkgd2VhdGhlciBkYXRhCmBgYHtyfQpob3VzdG9uX3dlYXRoZXIgPC0gcmVhZF9kZWxpbSgid2VhdGhlcl9kYXRhL0tJQUhfZGFpbHkudHh0IiwgZGVsaW0gPSAiLCIpCmBgYAoKKiBGaW5kIG91dCB3aGF0IHRoZXNlIGNvbHVtbnMgbWVhbi4gCiAgICArIFNpdGU0IDogTmFtZSBvZiB0aGUgc2l0ZQogICAgCiAgICArIERhdGUgOiBEYXRlIHdoZW4gdGhlIGRhdGEgd2FzIGNvbGxlY3RlZAogICAgCiAgICArIFNvdXJjZSA6IE5hbWUgb2YgdGhlaXIgaW5zdHJ1bWVudAogICAgCiAgICArIE1heCBUZW1wIDogTWF4aW11bSB0ZW1wZXJhdHVyZSBvZiB0aGUgZGF5CiAgICAKICAgICsgTWluIFRlbXAgOiBNaW5pbXVtIHRlbXBlcmF0dXJlIG9mIHRoZSBkYXkKICAgIAogICAgKyBBdmcgVGVtcCA6IEF2ZXJhZ2UgdGVtcGVyYXR1cmUgKE1heCArIE1pbikvMgogICAgCiAgICArIEhERHMgOiBIZWF0aW5nIGRlZ3JlZSBkYXkgKFRlbXBzIGJlbG93IDY1KSBodHRwczovL3cxLndlYXRoZXIuZ292L2dsb3NzYXJ5L2luZGV4LnBocD9sZXR0ZXI9aAogICAgCiAgICArIENERHMgOiBDb29saW5nIGRlZ3JlZSBkYXkgKFRlbXBzIGFib3ZlIDY1KSAtIEEgZm9ybSBvZiBkZWdyZWUgZGF5IHVzZWQgdG8gZXN0aW1hdGUgZW5lcmd5IHJlcXVpcmVtZW50cyBmb3IgYWlyIGNvbmRpdGlvbmluZyBvciByZWZyaWdlcmF0aW9uLiAgRm9yIGV4YW1wbGUsIGlmIGEgbG9jYXRpb24gZXhwZXJpZW5jZXMgYSBtZWFuIHRlbXBlcmF0dXJlIG9mIDc1wrBGIG9uIGEgY2VydGFpbiBkYXksIHRoZXJlIHdlcmUgMTAgQ0REIChDb29saW5nIERlZ3JlZSBEYXlzKSB0aGF0IGRheSBiZWNhdXNlIDc1IC0gNjUgPSAxMC4pIGh0dHBzOi8vdzEud2VhdGhlci5nb3YvZ2xvc3NhcnkvaW5kZXgucGhwP2xldHRlcj1jCiAgICAKICAgICsgUHJlY2lwaXRhdGlvbiBXYXRlciBFcXVpdiA6IFJhaW4gaW4gaW5jaGVzCiAgICAKICAgICsgU25vd2ZhbGwgOiBBbW91bnQgb2Ygc25vd2ZhbGwgc2luY2UgMjQgaG91cnMgKGh0dHBzOi8vd3d3LndlYXRoZXIuZ292L2dzcC9zbm93KQogICAgCiAgICArIFNub3cvSWNlIERlcHRoIDogVGhlIGRlcHRoIG9mIHRoZSBuZXcgYW5kIG9sZCBzbm93IHJlbWFpbmluZyBvbiB0aGUgZ3JvdW5kIGF0IG9ic2VydmF0aW9uIHRpbWUgKGh0dHBzOi8vd3d3LndlYXRoZXIuZ292L2dzcC9zbm93KQoKCgoKIyMjIEZpbmQgb3V0IG1vcmUgYWJvdXQgdGhpcyBmdW5jdGlvbgpgYGB7cn0KPz9yZWFkX2RlbGltCmBgYAoKCiMjICJGb3JtYXQiIHRoZSBkYXRhCmBgYHtyfQpob3VzdG9uX3dlYXRoZXJfZGYgPC0gaG91c3Rvbl93ZWF0aGVyICU+JQogIG11dGF0ZShEYXRlPWFzLkRhdGUoRGF0ZSxmb3JtYXQ9JyVtLyVkLyVZJykpICU+JQogIHNlcGFyYXRlKERhdGUsYygieWVhciIsIm1vbnRoIiwiZGF5IikpICU+JQogIGphbml0b3I6OmNsZWFuX25hbWVzKCkKYGBgCgoKCgojIyBSZWFkIENoaWNhZ28gZGFpbHkgd2VhdGhlciBkYXRhCmBgYHtyfQpjaGljYWdvX3dlYXRoZXIgPC0gcmVhZF9jc3YoIndlYXRoZXJfZGF0YS9LT1JEX2RhaWx5LnR4dCIpIApgYGAKCk5vdGljZSB3ZSBoYXZlIHVzZWQgZGlmZmVyZW50IGZ1bmN0aW9uIGJ1dCB3aXRob3V0IGV4cGxpY2l0bHkgbWVudGlvbmluZyBkZWxpbWl0ZXIuIAoKIyMgIkZvcm1hdCIgQ2hpY2FnbyB3ZWF0aGVyCmBgYHtyfQpjaGljYWdvX3dlYXRoZXJfZGYgPC0gY2hpY2Fnb193ZWF0aGVyICU+JQogIG11dGF0ZShEYXRlPWFzLkRhdGUoRGF0ZSxmb3JtYXQ9JyVtLyVkLyVZJykpICU+JQogIHNlcGFyYXRlKERhdGUsYygieWVhciIsIm1vbnRoIiwiZGF5IikpICU+JQogIGphbml0b3I6OmNsZWFuX25hbWVzKCkKYGBgCgoKCiMjIEdldCBTZWF0dGxlIHdlYXRoZXIgZGF0YSBhbmQgZm9ybWF0CmBgYHtyfQpzZWF0dGxlX3dlYXRoZXJfZGYgPC0gcmVhZF9jc3YoIndlYXRoZXJfZGF0YS9LU0VBX2RhaWx5LnR4dCIpICAlPiUKICBtdXRhdGUoRGF0ZSA9IGFzLkRhdGUoRGF0ZSwgZm9ybWF0PSclbS8lZC8lWScpKSAlPiUKICBzZXBhcmF0ZShEYXRlLCBjKCJ5ZWFyIiwibW9udGgiLCJkYXkiKSkgJT4lCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKQpgYGAKCgoKCgoKCgoKIyMgQ29tcGFyaW5nIG1lYW4gdGVtcGVyYXR1cmUgYmV0d2VlbiBIb3VzdG9uIGFuZCBDaGljYWdvCmBgYHtyfQpob3VzdG9uX3dlYXRoZXJfZGYgJT4lCiAgYmluZF9yb3dzKC4sIGNoaWNhZ29fd2VhdGhlcl9kZiwgc2VhdHRsZV93ZWF0aGVyX2RmKSAlPiUKICBncm91cF9ieShzaXRlNCwgeWVhcikgJT4lCiAgc3VtbWFyaXNlKG1lYW5fdGVtcF95ZWFyPW1lYW4oYXZnX3RlbXApKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ2dwbG90KC4sYWVzKHggPSBhcy5udW1lcmljKHllYXIpLCB5ID0gbWVhbl90ZW1wX3llYXIsIGNvbG9yID0gc2l0ZTQpKSArCiAgZ2VvbV9saW5lKGx3ZCA9IDIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNjYWxlczo6cHJldHR5X2JyZWFrcyhuID0gMTApKSArCiAgdGhlbWVfYncoKQpgYGAKCkZpeCB0aGUgeCBheGlzIGxhYmVsIGFuZCB0aGUgbGVnZW5kPz8KCgoKCiMjIFBsb3QgSGlzdG9ncmFtCmBgYHtyfQpob3VzdG9uX3dlYXRoZXJfZGYgJT4lCiAgYmluZF9yb3dzKC4sIGNoaWNhZ29fd2VhdGhlcl9kZiwgc2VhdHRsZV93ZWF0aGVyX2RmKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHg9YXZnX3RlbXAsIGZpbGw9c2l0ZTQsIGNvbG9yPXNpdGU0KSkgKwogIGdlb21faGlzdG9ncmFtKHBvc2l0aW9uPSJpZGVudGl0eSIsICBhbHBoYSA9IDAuNSkKICBnZW9tX2hpc3RvZ3JhbShwb3NpdGlvbj0iaWRlbnRpdHkiKQpgYGAKCgojIyBQbG90IEVtcGlyaWNhbCBDdW11bGF0aXZlIERpc3RyaWJ1dGlvbiBGdW5jdGlvbiAKYGBge3J9CmhvdXN0b25fd2VhdGhlcl9kZiAlPiUKICBiaW5kX3Jvd3MoLiwgY2hpY2Fnb193ZWF0aGVyX2RmLCBzZWF0dGxlX3dlYXRoZXJfZGYpICU+JQogIGdncGxvdCguLGFlcyhhdmdfdGVtcCwgY29sb3IgPSBzaXRlNCkpICsKICBzdGF0X2VjZGYoZ2VvbSA9ICJwb2ludCIpIApgYGAKCgpBIENERiBpcyBhIGZ1bmN0aW9uIHN1Y2ggYXMgeT1mKHgpIHdoZXJlIHkgaXMgdGhlIHByb2JhYmlsaXR5IG9mIHRoZSBudW1iZXIgeCwgb3IgYW55IGxvd2VyIG51bWJlciwgYmVpbmcgY2hvc2VuIGF0IHJhbmRvbSBmcm9tIHRoYXQgZGlzdHJpYnV0aW9uLiAKCnNvdXJjZTogaHR0cHM6Ly93d3cuY2hlLnV0YWguZWR1L350b255L2NvdXJzZS9tYXRlcmlhbC9TdGF0aXN0aWNzLzE4X3J2X3BkZl9jZGYucGhwCgpIZXJlIHdlIGFyZSB0YWxraW5nIGFib3V0IEVDREYg4oCcRW1waXJpY2Fs4oCdIENERi4gVGhpcyBtZWFucyB0aGlzIGlzIG5vdCBhIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBlbnRpcmUgc2V0IChvciB0aGVvcmV0aWNhbCBkaXN0cmlidXRpb24pIGJ1dCB3aGF0IHdhcyBvYnNlcnZlZCBhbmQgaGVuY2UgdGhlIHdvcmQg4oCcZW1waXJpY2Fs4oCdLiAKCgoKIyMgU3RlbSBhbmQgbGVhZiBwbG90CmBgYHtyfQpzdGVtKGhvdXN0b25fd2VhdGhlcl9kZiRtYXhfdGVtcCkKYGBgCgpJdCBjYW4gYmUgaW5mb3JtYXRpdmUgYnV0IGNvbXBhcmVkIHRvIGhpc3RvZ3JhbSBvciBlY2RmIHBsb3QsIGl0IGNhbiBiZSBoYXJkIHRvIHJlYWQuIAoKCgojIyBTZWUgdGhlIHNwcmVhZCBvZiB0aGUgdGVtcGVyYXR1cmUgYnkgbW9udGgKYGBge3J9CmhvdXN0b25fd2VhdGhlcl9kZiAlPiUKICBiaW5kX3Jvd3MoY2hpY2Fnb193ZWF0aGVyX2RmLCBzZWF0dGxlX3dlYXRoZXJfZGYpICU+JQogIGdyb3VwX2J5KHNpdGU0LG1vbnRoKSAlPiUKICBzdW1tYXJpc2UobWF4ID0gbWF4KG1heF90ZW1wLG5hLnJtID0gVCksIAogICAgICAgICAgICBtaW4gPSBtaW4obWluX3RlbXAsIG5hLnJtID0gVCksIAogICAgICAgICAgICBtZWFuID0gbWVhbihhdmdfdGVtcCwgbmEucm0gPSBUKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGdncGxvdCguLCBhZXMoeCA9IG1vbnRoLCB5ID0gbWVhbikpICsKICBnZW9tX2xpbmVyYW5nZShhZXMoIHltaW4gPSBtaW4sIHltYXggPSBtYXgpLCBsd2QgPSAyLCBjb2xvciA9ICIjRkY1NDAwIikgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMsIGNvbG9yID0gIiMyMTQyQTYiKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDY1LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgeGxhYigiTW9udGgiKSArCiAgeWxhYigiVGVtcGVyYXR1cmUgaW4gRmFyYWhlbml0IikgKwogIGZhY2V0X2dyaWQoLn5zaXRlNCkKYGBgCgoKCgojIFBlcmNlbnQgZHJvcCBhcyBjb21wYXJlIHRvIHByZXZpb3VzIG1vbnRoLiAKYGBge3J9CmhvdXN0b25fd2VhdGhlcl9kZiAlPiUKICBiaW5kX3Jvd3MoY2hpY2Fnb193ZWF0aGVyX2RmKSAlPiUKICBiaW5kX3Jvd3Moc2VhdHRsZV93ZWF0aGVyX2RmKSAlPiUKICBncm91cF9ieShzaXRlNCwgbW9udGgpICU+JQogIHN1bW1hcmlzZShtZWFuX2F2Z190ZW1wID0gbWVhbihhdmdfdGVtcCxuYS5ybSA9IFQpKSAlPiUKICBtdXRhdGUocGN0X2NoYW5nZSA9IChtZWFuX2F2Z190ZW1wIC8gbGFnKG1lYW5fYXZnX3RlbXApIC0gMSkgKiAxMDApICU+JQogIG11dGF0ZShwY3RfY2hhbmdlID0gY2FzZV93aGVuKAogICAgaXMubmEocGN0X2NoYW5nZSkgfiAwLAogICAgVFJVRSB+IGFzLm51bWVyaWMocGN0X2NoYW5nZSkKICApKSAlPiUKICBhcnJhbmdlKHBjdF9jaGFuZ2UpICU+JSAKICBnZ3Bsb3QoLixhZXMoeCA9IG1vbnRoLCB5ID0gcGN0X2NoYW5nZSwgY29sb3IgPSBzaXRlNCkpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc2l0ZTQpLCBzaXplID0gMSkrCiAgZ2VvbV9wb2ludCgpICsKICB0aGVtZV9idygpCmBgYAoKCgoKCgoKCgoKIyMgV2hlcmUgZG9lcyBpdCByYWluIHRoZSBtb3N0PwpgYGB7ciwgZmlnLndpZHRoPTEwfQpob3VzdG9uX3dlYXRoZXJfZGYgJT4lCiAgYmluZF9yb3dzKGNoaWNhZ29fd2VhdGhlcl9kZiwgc2VhdHRsZV93ZWF0aGVyX2RmKSAlPiUKICBncm91cF9ieShzaXRlNCx5ZWFyKSAlPiUKICBzdW1tYXJpc2Uoc3VtID0gc3VtKHByZWNpcGl0YXRpb25fd2F0ZXJfZXF1aXYsIG5hLnJtID0gVCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoLiwgYWVzKHggPSB5ZWFyLCB5ID0gc3VtLCBjb2xvciA9IHNpdGU0KSApICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzaXRlNCksIHNpemUgPSAxKSsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxNCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNjUsIGhqdXN0ID0gMSkpICsKICB5bGFiKCJSYWluZmFsbCBpbiBpbmNoZXMiKSAKYGBgClRoaXMgZ3JhcGggc2hvd3MgdG90YWwgcmFpbmZhbGwgaW4gaW5jaGVzIG92ZXIgdGhlIHllYXJzLiAKCgoKCiMgQXZlcmFnZSByYWluZmFsbCB3aXRoIHRoZSBjaXJjbGVzIHNob3dpbmcgdGhlIG1heGltdW0gcmVjb3JkZWQgcmFpbmZhbGwgZm9yIHNpbmdsZSBkYXkKYGBge3J9CmhvdXN0b25fd2VhdGhlcl9kZiAlPiUKICBiaW5kX3Jvd3MoY2hpY2Fnb193ZWF0aGVyX2RmLCBzZWF0dGxlX3dlYXRoZXJfZGYpICU+JQogIGdyb3VwX2J5KHNpdGU0LG1vbnRoKSAlPiUKICBzdW1tYXJpc2UobWF4ID0gbWF4KHByZWNpcGl0YXRpb25fd2F0ZXJfZXF1aXYsbmEucm0gPSBUKSwgCiAgICAgICAgICAgIG1lYW4gPSBtZWFuKHByZWNpcGl0YXRpb25fd2F0ZXJfZXF1aXYsIG5hLnJtID0gVCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoLiApICsKICBnZW9tX3BvaW50KGFlcyh4ID0gbW9udGgsIHkgPSBtZWFuLHNpemUgPSBtYXgpLCBjb2xvciA9ICIjMjE0MkE2IikgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTQpICsKICB4bGFiKCJNb250aCIpICsKICB5bGFiKCJBdmVyYWdlIHJhaW4gZmFsbCBpbiBpbmNoZXMiKSArCiAgZmFjZXRfd3JhcCgufnNpdGU0KQpgYGAKCgoKCgoKCgoKCiMgSG91cmx5IHdlYXRoZXIgZGF0YQoKIyMgUmVhZCBIb3VzdG9uIGhvdXJseSB3ZWF0aGVyIGRhdGEKYGBge3J9CmhvdXN0b25fd2VhdGhlcl9ob3VybHkgPC0gcmVhZF9jc3YoIndlYXRoZXJfZGF0YS9LSUFILnR4dCIpICU+JQogIG11dGF0ZShkYXRlPWFzLkRhdGUoRGF0ZSxmb3JtYXQ9JyVtLyVkLyVZJykpICU+JQogIHNlcGFyYXRlKGRhdGUsYygieWVhciIsIm1vbnRoIiwiZGF5IikpICU+JQogIGphbml0b3I6OmNsZWFuX25hbWVzKCkKYGBgCgoKIyMgUmVhZCBDaGljYWdvIEhvdXJseSB3ZWF0aGVyIGRhdGEKYGBge3J9CmNoaWNhZ29fd2VhdGhlcl9ob3VybHkgPC0gcmVhZF9jc3YoIndlYXRoZXJfZGF0YS9LT1JELnR4dCIpICU+JQogIG11dGF0ZShkYXRlID0gYXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSkgJT4lCiAgc2VwYXJhdGUoZGF0ZSwgYygieWVhciIsIm1vbnRoIiwiZGF5IikpICU+JQogIGphbml0b3I6OmNsZWFuX25hbWVzKCkKYGBgCgoKCgoKIyMgQWRkIFNlYXR0bGUgaG91cmx5IHdlYXRoZXIgZGF0YQpgYGB7cn0Kc2VhdHRsZV93ZWF0aGVyX2hvdXJseSA8LSByZWFkX2Nzdigid2VhdGhlcl9kYXRhL0tTRUEudHh0IikgJT4lCiAgbXV0YXRlKGRhdGU9YXMuRGF0ZShEYXRlLCBmb3JtYXQgPSAnJW0vJWQvJVknKSkgJT4lCiAgc2VwYXJhdGUoZGF0ZSwgYygieWVhciIsICJtb250aCIsICJkYXkiKSkgJT4lCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKQpgYGAKCgojIyBJcyBTZWF0dGxlIHJlYWxseSBjbG91ZHkgYXMgY29tcGFyZSB0byBDaGljYWdvIGFuZCBIb3VzdG9uPwpgYGB7cn0KaG91c3Rvbl93ZWF0aGVyX2hvdXJseSAlPiUKICBiaW5kX3Jvd3MoLiwgY2hpY2Fnb193ZWF0aGVyX2hvdXJseSxzZWF0dGxlX3dlYXRoZXJfaG91cmx5ICkgJT4lCiAgbXV0YXRlKGRhdGU9YXMuRGF0ZShkYXRlLGZvcm1hdD0nJW0vJWQvJVknKSkgJT4lCiAgc2VwYXJhdGUoZGF0ZSxjKCJ5ZWFyIiwibW9udGgiLCJkYXkiKSkgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgeWVhcikgJT4lCiAgc3VtbWFyaXNlKG1lYW5fY2xvdWRfY292ZXJhZ2UgPSBtZWFuKGBjbGRfZnJhY2ApKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdCguLGFlcyh4ID0gYXMubnVtZXJpYyh5ZWFyKSwgeSA9IG1lYW5fY2xvdWRfY292ZXJhZ2UsIGNvbG9yID0gc2l0ZSkpICsKICBnZW9tX2xpbmUoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MobiA9IDEwKSkgCmBgYAoKCmBgYHtyfQpob3VzdG9uX3dlYXRoZXJfaG91cmx5ICU+JQogIGJpbmRfcm93cyguLCBjaGljYWdvX3dlYXRoZXJfaG91cmx5LHNlYXR0bGVfd2VhdGhlcl9ob3VybHkgKSAlPiUKICBtdXRhdGUoZGF0ZT1hcy5EYXRlKGRhdGUsZm9ybWF0PSclbS8lZC8lWScpKSAlPiUKICBzZXBhcmF0ZShkYXRlLGMoInllYXIiLCJtb250aCIsImRheSIpKSAlPiUKICBncm91cF9ieShzaXRlLCBtb250aCkgJT4lCiAgc3VtbWFyaXNlKHN1bV9jbG91ZF9jb3ZlcmFnZSA9IHN1bShgY2xkX2ZyYWNgKSxhdmdfY2xvdWRfY292ZXJhZ2UgPSBtZWFuKGBjbGRfZnJhY2ApKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdCguLGFlcyh4ID0gYXMubnVtZXJpYyhtb250aCksIHkgPSBzdW1fY2xvdWRfY292ZXJhZ2UsIGNvbG9yID0gc2l0ZSkpICsKICBnZW9tX2xpbmUobGluZXR5cGUgPSAiZG90ZGFzaCIpICsKICBnZW9tX3BvaW50KGFlcyhpbmhlcml0LmFlcz1UUlVFLCBzaXplID0gYXZnX2Nsb3VkX2NvdmVyYWdlKSkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MobiA9IDEwKSkgCmBgYAoKCiNEYXlzIHdpdGggbGVzcyB0aGFuIDMwJSBhdmVyYWdlIGNsb3VkIGNvdmVyYWdlCmBgYHtyfQpob3VzdG9uX3dlYXRoZXJfaG91cmx5ICU+JQogIGJpbmRfcm93cyguLCBjaGljYWdvX3dlYXRoZXJfaG91cmx5LHNlYXR0bGVfd2VhdGhlcl9ob3VybHkgKSAlPiUKICBtdXRhdGUoZGF0ZT1hcy5EYXRlKGRhdGUsZm9ybWF0PSclbS8lZC8lWScpKSAlPiUKICBzZXBhcmF0ZShkYXRlLGMoInllYXIiLCJtb250aCIsImRheSIpKSAlPiUKICBncm91cF9ieShzaXRlLCB5ZWFyLCBtb250aCwgZGF5KSAlPiUKICBzdW1tYXJpc2UoYXZnX2Nsb3VkX2NvdmVyYWdlID0gbWVhbihgY2xkX2ZyYWNgKSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShzaXRlLCB5ZWFyKSAlPiUKICBzdW1tYXJpc2Uobm9fY2xvdWR5X2RheXMgPSBzdW0oYXZnX2Nsb3VkX2NvdmVyYWdlIDwgLjMwKSkgJT4lCiAgZ2dwbG90KC4sYWVzKHggPSBhcy5udW1lcmljKHllYXIpLCB5ID0gbm9fY2xvdWR5X2RheXMsIGNvbG9yID0gc2l0ZSkpICsKICBnZW9tX2xpbmUobGluZXR5cGU9MikgKwogIGdlb21fcG9pbnQoYWVzKGluaGVyaXQuYWVzPVRSVUUpKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNjYWxlczo6cHJldHR5X2JyZWFrcyhuID0gMTApKSArCiAgeWxhYigiTnVtYmVyIG9mIGRheXMgd2l0aCBhdmVyYWdlIGNsb3VkIGNvdmVyIDwgMzAlIikgKwogIHhsYWIoIlllYXIiKQpgYGAKCgoKCgoKCgoKIyMgSXMgQ2hpY2FnbyB0aGUgd2luZGllc3QgY2l0eSBpbiBvdXIgc2V0PwpgYGB7cn0KaG91c3Rvbl93ZWF0aGVyX2hvdXJseSAlPiUKICBiaW5kX3Jvd3MoLiwgY2hpY2Fnb193ZWF0aGVyX2hvdXJseSxzZWF0dGxlX3dlYXRoZXJfaG91cmx5KSAlPiUKICBtdXRhdGUoZGF0ZT1hcy5EYXRlKGRhdGUsZm9ybWF0ID0gJyVtLyVkLyVZJykpICU+JQogIHNlcGFyYXRlKGRhdGUsYygieWVhciIsIm1vbnRoIiwiZGF5IikpICU+JQogIGdyb3VwX2J5KHNpdGUsIHllYXIpICU+JQogIHN1bW1hcmlzZShtZWFuX3dpbmRzcGVlZCA9IG1lYW4oYHdpbmRzcGVlZGApKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdCguLGFlcyh4ID0gYXMubnVtZXJpYyh5ZWFyKSwgeSA9IG1lYW5fd2luZHNwZWVkLCBjb2xvciA9IHNpdGUpKSArCiAgZ2VvbV9saW5lKHNpemUgPSAyKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNjYWxlczo6cHJldHR5X2JyZWFrcyhuID0gMTApKSAKYGBgCgoKCgoKCgoKCg==