Note that the directories used to store data are likely different on your computer, and such references will need to be changed before using any such code.

library(tidyverse)
df <- read.csv("../../Data/Session_2-1.csv", stringsAsFactors=FALSE)
df_full <- df
uol <- filter(df, isin == "SG1S83002349")
#clean_df <- subset(df,fyear==2017 & !is.na(revt) & !is.na(ni) & revt > 1)
# revt: Revenue, at: Assets
summary(uol[,c("revt", "at")])
      revt               at       
 Min.   :  94.78   Min.   : 1218  
 1st Qu.: 193.41   1st Qu.: 3044  
 Median : 427.44   Median : 3478  
 Mean   : 666.38   Mean   : 5534  
 3rd Qu.:1058.61   3rd Qu.: 7939  
 Max.   :2103.15   Max.   :19623  
mod1 <- lm(revt ~ at, data = uol)
summary(mod1)

Call:
lm(formula = revt ~ at, data = uol)

Residuals:
    Min      1Q  Median      3Q     Max 
-295.01 -101.29  -41.09   47.17  926.29 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) -13.831399  67.491305  -0.205    0.839    
at            0.122914   0.009678  12.701  6.7e-13 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 221.2 on 27 degrees of freedom
Multiple R-squared:  0.8566,    Adjusted R-squared:  0.8513 
F-statistic: 161.3 on 1 and 27 DF,  p-value: 6.699e-13
# Graph showing squared error
uolg <- uol[,c("at","revt")]
uolg$resid <- mod1$residuals
uolg$xleft <- ifelse(uolg$resid < 0,uolg$at,uolg$at - uolg$resid)
uolg$xright <- ifelse(uolg$resid < 0,uolg$at - uolg$resid, uol$at)
uolg$ytop <- ifelse(uolg$resid < 0,uolg$revt - uolg$resid,uol$revt)
uolg$ybottom <- ifelse(uolg$resid < 0,uolg$revt, uolg$revt - uolg$resid)
uolg$point <- TRUE
uolg2 <- uolg
uolg2$point <- FALSE
uolg2$at <- ifelse(uolg$resid < 0,uolg2$xright,uolg2$xleft)
uolg2$revt <- ifelse(uolg$resid < 0,uolg2$ytop,uolg2$ybottom)
uolg <- rbind(uolg, uolg2)
uolg %>% ggplot(aes(y=revt, x=at, group=point)) + 
         geom_point(aes(shape=point)) + 
         scale_shape_manual(values=c(NA,18)) + 
         geom_smooth(method="lm", se=FALSE) +
         geom_errorbarh(aes(xmax=xright, xmin = xleft)) + 
         geom_errorbar(aes(ymax=ytop, ymin = ybottom)) + 
         theme(legend.position="none")

# tidyverse
uol <- uol %>%
  mutate(revt_growth1 = revt / lag(revt) - 1)
# R way
uol$revt_growth2 = uol$revt / c(NA, uol$revt[-length(uol$revt)]) - 1
identical(uol$revt_growth1, uol$revt_growth2)
[1] TRUE
# Make the other needed change
uol <- uol %>%
  mutate(at_growth = at / lag(at) - 1) %>%  # Calculate asset growth
  rename(revt_growth = revt_growth1)        # Rename for readability
# Run the OLS model
mod2 <- lm(revt_growth ~ at_growth, data = uol)
summary(mod2)

Call:
lm(formula = revt_growth ~ at_growth, data = uol)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.57736 -0.10534 -0.00953  0.15132  0.42284 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)  
(Intercept)  0.09024    0.05620   1.606   0.1204  
at_growth    0.53821    0.27717   1.942   0.0631 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2444 on 26 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:  0.1267,    Adjusted R-squared:  0.09307 
F-statistic: 3.771 on 1 and 26 DF,  p-value: 0.06307
# lct: short term liabilities, che: cash and equivalents, ebit: EBIT
uol <- uol %>%
  mutate_at(vars(lct, che, ebit), list(growth = ~. / lag(.) - 1))  # Calculate 3 growths
mod3 <- lm(revt_growth ~ lct_growth + che_growth + ebit_growth, data=uol)
summary(mod3)

Call:
lm(formula = revt_growth ~ lct_growth + che_growth + ebit_growth, 
    data = uol)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.46531 -0.15097  0.00205  0.17601  0.31997 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)   
(Intercept)  0.07498    0.04915   1.526  0.14018   
lct_growth   0.23482    0.07319   3.209  0.00376 **
che_growth  -0.11561    0.09227  -1.253  0.22230   
ebit_growth  0.03808    0.02208   1.724  0.09751 . 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2228 on 24 degrees of freedom
  (1 observation deleted due to missingness)
Multiple R-squared:   0.33, Adjusted R-squared:  0.2462 
F-statistic:  3.94 on 3 and 24 DF,  p-value: 0.02033
detector <- function() {
  dice <- sample(1:6, size=2, replace=TRUE)
  if (sum(dice) == 12) {
    "exploded"
  } else {
    "still there"
  }
}
experiment <- replicate(1000,detector())
# p value
p <- sum(experiment == "still there") / 1000
if (p < 0.05) {
  paste("p-value: ", p, "-- Fail to reject H_A, sun appears to have exploded")
} else {
  paste("p-value: ", p, "-- Reject H_A that sun exploded")
}
[1] "p-value:  0.963 -- Reject H_A that sun exploded"
library(tidyverse)
read_csv('../../Data/Session_3-1.csv') %>%
  ggplot(aes(y=revtq, x=atq)) + 
  geom_point() + 
  geom_smooth(method="lm") + 
  xlab("Assets") + 
  ylab("Revenue")
Parsed with column specification:
cols(
  .default = col_double(),
  gvkey = col_character(),
  datadate = col_date(format = ""),
  indfmt = col_character(),
  consol = col_character(),
  popsrc = col_character(),
  datafmt = col_character(),
  tic = col_character(),
  conm = col_character(),
  curcdq = col_character(),
  datacqtr = col_character(),
  datafqtr = col_character(),
  costat = col_character()
)
See spec(...) for full column specifications.

plot_norm <- function(bound, outer) {
  x <- seq(-outer,outer,length=100)
  hx <- dnorm(x)
  plot(x, hx, type="n", xlab="z values", ylab="Normal PDF", main="Normal Distribution", axes=FALSE)
  lines(x, hx)
  i <- x < -bound
  polygon(c(-outer,x[i],-bound,-bound), c(0,hx[i],max(hx[i]),0), col="red")
  i <- x > bound
  polygon(c(bound, bound, x[i],outer), c(0,max(hx[i]), hx[i],0), col="red")
  axis(1, at=-outer:outer, pos=0)
}
plot_norm(1.96, 4)

anova(mod2, mod3, test="Chisq")
Analysis of Variance Table

Model 1: revt_growth ~ at_growth
Model 2: revt_growth ~ lct_growth + che_growth + ebit_growth
  Res.Df    RSS Df Sum of Sq Pr(>Chi)  
1     26 1.5534                        
2     24 1.1918  2   0.36168   0.0262 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Ensure firms have at least $1M (local currency), and have revenue
# df contains all real estate companies excluding North America
df_clean <- filter(df, df$at>1, df$revt>0)
# We cleaned out 578 observations!
print(c(nrow(df), nrow(df_clean)))
[1] 5161 4583
# Another useful cleaning funtion:
# Replaces NaN, Inf, and -Inf with NA for all numeric variables in the data!
df_clean <- df_clean %>%
  mutate_if(is.numeric, list(~replace(., !is.finite(.), NA)))
uol <- uol %>% mutate(revt_lead = lead(revt))  # From dplyr
forecast1 <- lm(revt_lead ~ lct + che + ebit, data=uol)
library(broom)  # Lets us view bigger regression outputs in a tidy fashion
tidy(forecast1)  # Present regression output
glance(forecast1)  # Present regression statistics
forecast2 <- 
  lm(revt_lead ~ revt + act + che + lct + dp + ebit , data=uol)
tidy(forecast2)
glance(forecast2)
anova(forecast1, forecast2, test="Chisq")
Analysis of Variance Table

Model 1: revt_lead ~ lct + che + ebit
Model 2: revt_lead ~ revt + act + che + lct + dp + ebit
  Res.Df     RSS Df Sum of Sq  Pr(>Chi)    
1     24 3059182                           
2     21  863005  3   2196177 1.477e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Note the group_by -- without it, lead() will pull from the subsequent firm!
# ungroup() tells R that we finished grouping
df_clean <- df_clean %>% 
  group_by(isin) %>% 
  mutate(revt_lead = lead(revt)) %>%
  ungroup()
forecast3 <-
  lm(revt_lead ~ revt + act + che + lct + dp + ebit , data=df_clean[df_clean$fic=="SGP",])
tidy(forecast3)
glance(forecast3)
forecast4 <-
  lm(revt_lead ~ revt + act + che + lct + dp + ebit , data=df_clean)
tidy(forecast4)
glance(forecast4)
forecast3.1 <-
  lm(revt_lead ~ revt + act + che + lct + dp + ebit + factor(isin),
     data=df_clean[df_clean$fic=="SGP",])
# n=7 to prevent outputting every fixed effect
print(tidy(forecast3.1), n=15)
glance(forecast3.1)
anova(forecast3, forecast3.1, test="Chisq")
Analysis of Variance Table

Model 1: revt_lead ~ revt + act + che + lct + dp + ebit
Model 2: revt_lead ~ revt + act + che + lct + dp + ebit + factor(isin)
  Res.Df      RSS Df Sum of Sq Pr(>Chi)
1    324 14331633                      
2    304 13215145 20   1116488   0.1765
library(lfe)
forecast3.2 <-
  felm(revt_lead ~ revt + act + che + lct + dp + ebit | factor(isin),
       data=df_clean[df_clean$fic=="SGP",])
summary(forecast3.2)

Call:
   felm(formula = revt_lead ~ revt + act + che + lct + dp + ebit |      factor(isin), data = df_clean[df_clean$fic == "SGP", ]) 

Residuals:
     Min       1Q   Median       3Q      Max 
-1181.88   -23.25    -1.87    18.03  1968.86 

Coefficients:
     Estimate Std. Error t value Pr(>|t|)    
revt  0.39200    0.09767   4.013 7.54e-05 ***
act  -0.05382    0.06017  -0.894  0.37181    
che   0.30370    0.17682   1.718  0.08690 .  
lct   0.39209    0.09210   4.257 2.76e-05 ***
dp    4.71275    1.73168   2.721  0.00687 ** 
ebit -0.85080    0.32704  -2.602  0.00974 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 208.5 on 304 degrees of freedom
  (29 observations deleted due to missingness)
Multiple R-squared(full model): 0.8558   Adjusted R-squared: 0.8435 
Multiple R-squared(proj model): 0.7806   Adjusted R-squared: 0.7618 
F-statistic(full model):69.41 on 26 and 304 DF, p-value: < 2.2e-16 
F-statistic(proj model): 180.3 on 6 and 304 DF, p-value: < 2.2e-16 
df_clean %>%
  filter(fic=="SGP") %>%
  group_by(isin) %>%
  mutate(mean_revt_lead=mean(revt_lead, na.rm=T)) %>%
  slice(1) %>%
  ungroup() %>%
  ggplot(aes(x=mean_revt_lead)) + geom_histogram(aes(y = ..density..)) +  geom_density(alpha=.4, fill="#FF6666")

# Exports for the following week
save(df_clean, forecast2, uol, forecast4, file = "../../Data/Session_2_export.RData")
LS0tDQp0aXRsZTogIkNvZGUgZm9yIFNlc3Npb24gMiINCmF1dGhvcjogIkRyLiBSaWNoYXJkIE0uIENyb3dsZXkiDQpkYXRlOiAiIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rDQotLS0NCg0KTm90ZSB0aGF0IHRoZSBkaXJlY3RvcmllcyB1c2VkIHRvIHN0b3JlIGRhdGEgYXJlIGxpa2VseSBkaWZmZXJlbnQgb24geW91ciBjb21wdXRlciwgYW5kIHN1Y2ggcmVmZXJlbmNlcyB3aWxsIG5lZWQgdG8gYmUgY2hhbmdlZCBiZWZvcmUgdXNpbmcgYW55IHN1Y2ggY29kZS4NCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmRmIDwtIHJlYWQuY3N2KCIuLi8uLi9EYXRhL1Nlc3Npb25fMi0xLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpDQpkZl9mdWxsIDwtIGRmDQp1b2wgPC0gZmlsdGVyKGRmLCBpc2luID09ICJTRzFTODMwMDIzNDkiKQ0KI2NsZWFuX2RmIDwtIHN1YnNldChkZixmeWVhcj09MjAxNyAmICFpcy5uYShyZXZ0KSAmICFpcy5uYShuaSkgJiByZXZ0ID4gMSkNCmBgYA0KDQpgYGB7cn0NCiMgcmV2dDogUmV2ZW51ZSwgYXQ6IEFzc2V0cw0Kc3VtbWFyeSh1b2xbLGMoInJldnQiLCAiYXQiKV0pDQpgYGANCg0KYGBge3J9DQptb2QxIDwtIGxtKHJldnQgfiBhdCwgZGF0YSA9IHVvbCkNCnN1bW1hcnkobW9kMSkNCmBgYA0KDQpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9DQojIEdyYXBoIHNob3dpbmcgc3F1YXJlZCBlcnJvcg0KdW9sZyA8LSB1b2xbLGMoImF0IiwicmV2dCIpXQ0KdW9sZyRyZXNpZCA8LSBtb2QxJHJlc2lkdWFscw0KdW9sZyR4bGVmdCA8LSBpZmVsc2UodW9sZyRyZXNpZCA8IDAsdW9sZyRhdCx1b2xnJGF0IC0gdW9sZyRyZXNpZCkNCnVvbGckeHJpZ2h0IDwtIGlmZWxzZSh1b2xnJHJlc2lkIDwgMCx1b2xnJGF0IC0gdW9sZyRyZXNpZCwgdW9sJGF0KQ0KdW9sZyR5dG9wIDwtIGlmZWxzZSh1b2xnJHJlc2lkIDwgMCx1b2xnJHJldnQgLSB1b2xnJHJlc2lkLHVvbCRyZXZ0KQ0KdW9sZyR5Ym90dG9tIDwtIGlmZWxzZSh1b2xnJHJlc2lkIDwgMCx1b2xnJHJldnQsIHVvbGckcmV2dCAtIHVvbGckcmVzaWQpDQp1b2xnJHBvaW50IDwtIFRSVUUNCg0KdW9sZzIgPC0gdW9sZw0KdW9sZzIkcG9pbnQgPC0gRkFMU0UNCnVvbGcyJGF0IDwtIGlmZWxzZSh1b2xnJHJlc2lkIDwgMCx1b2xnMiR4cmlnaHQsdW9sZzIkeGxlZnQpDQp1b2xnMiRyZXZ0IDwtIGlmZWxzZSh1b2xnJHJlc2lkIDwgMCx1b2xnMiR5dG9wLHVvbGcyJHlib3R0b20pDQoNCnVvbGcgPC0gcmJpbmQodW9sZywgdW9sZzIpDQoNCg0KdW9sZyAlPiUgZ2dwbG90KGFlcyh5PXJldnQsIHg9YXQsIGdyb3VwPXBvaW50KSkgKyANCiAgICAgICAgIGdlb21fcG9pbnQoYWVzKHNoYXBlPXBvaW50KSkgKyANCiAgICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YyhOQSwxOCkpICsgDQogICAgICAgICBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgc2U9RkFMU0UpICsNCiAgICAgICAgIGdlb21fZXJyb3JiYXJoKGFlcyh4bWF4PXhyaWdodCwgeG1pbiA9IHhsZWZ0KSkgKyANCiAgICAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltYXg9eXRvcCwgeW1pbiA9IHlib3R0b20pKSArIA0KICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikNCmBgYA0KDQpgYGB7ciwgbWVzc2FnZT1GfQ0KIyB0aWR5dmVyc2UNCnVvbCA8LSB1b2wgJT4lDQogIG11dGF0ZShyZXZ0X2dyb3d0aDEgPSByZXZ0IC8gbGFnKHJldnQpIC0gMSkNCg0KIyBSIHdheQ0KdW9sJHJldnRfZ3Jvd3RoMiA9IHVvbCRyZXZ0IC8gYyhOQSwgdW9sJHJldnRbLWxlbmd0aCh1b2wkcmV2dCldKSAtIDENCg0KaWRlbnRpY2FsKHVvbCRyZXZ0X2dyb3d0aDEsIHVvbCRyZXZ0X2dyb3d0aDIpDQpgYGANCg0KYGBge3J9DQojIE1ha2UgdGhlIG90aGVyIG5lZWRlZCBjaGFuZ2UNCnVvbCA8LSB1b2wgJT4lDQogIG11dGF0ZShhdF9ncm93dGggPSBhdCAvIGxhZyhhdCkgLSAxKSAlPiUgICMgQ2FsY3VsYXRlIGFzc2V0IGdyb3d0aA0KICByZW5hbWUocmV2dF9ncm93dGggPSByZXZ0X2dyb3d0aDEpICAgICAgICAjIFJlbmFtZSBmb3IgcmVhZGFiaWxpdHkNCiMgUnVuIHRoZSBPTFMgbW9kZWwNCm1vZDIgPC0gbG0ocmV2dF9ncm93dGggfiBhdF9ncm93dGgsIGRhdGEgPSB1b2wpDQpzdW1tYXJ5KG1vZDIpDQpgYGANCg0KYGBge3J9DQojIGxjdDogc2hvcnQgdGVybSBsaWFiaWxpdGllcywgY2hlOiBjYXNoIGFuZCBlcXVpdmFsZW50cywgZWJpdDogRUJJVA0KdW9sIDwtIHVvbCAlPiUNCiAgbXV0YXRlX2F0KHZhcnMobGN0LCBjaGUsIGViaXQpLCBsaXN0KGdyb3d0aCA9IH4uIC8gbGFnKC4pIC0gMSkpICAjIENhbGN1bGF0ZSAzIGdyb3d0aHMNCm1vZDMgPC0gbG0ocmV2dF9ncm93dGggfiBsY3RfZ3Jvd3RoICsgY2hlX2dyb3d0aCArIGViaXRfZ3Jvd3RoLCBkYXRhPXVvbCkNCnN1bW1hcnkobW9kMykNCmBgYA0KDQpgYGB7cn0NCmRldGVjdG9yIDwtIGZ1bmN0aW9uKCkgew0KICBkaWNlIDwtIHNhbXBsZSgxOjYsIHNpemU9MiwgcmVwbGFjZT1UUlVFKQ0KICBpZiAoc3VtKGRpY2UpID09IDEyKSB7DQogICAgImV4cGxvZGVkIg0KICB9IGVsc2Ugew0KICAgICJzdGlsbCB0aGVyZSINCiAgfQ0KfQ0KDQpleHBlcmltZW50IDwtIHJlcGxpY2F0ZSgxMDAwLGRldGVjdG9yKCkpDQojIHAgdmFsdWUNCnAgPC0gc3VtKGV4cGVyaW1lbnQgPT0gInN0aWxsIHRoZXJlIikgLyAxMDAwDQppZiAocCA8IDAuMDUpIHsNCiAgcGFzdGUoInAtdmFsdWU6ICIsIHAsICItLSBGYWlsIHRvIHJlamVjdCBIX0EsIHN1biBhcHBlYXJzIHRvIGhhdmUgZXhwbG9kZWQiKQ0KfSBlbHNlIHsNCiAgcGFzdGUoInAtdmFsdWU6ICIsIHAsICItLSBSZWplY3QgSF9BIHRoYXQgc3VuIGV4cGxvZGVkIikNCn0NCmBgYA0KDQpgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlPUZ9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCnJlYWRfY3N2KCcuLi8uLi9EYXRhL1Nlc3Npb25fMy0xLmNzdicpICU+JQ0KICBnZ3Bsb3QoYWVzKHk9cmV2dHEsIHg9YXRxKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArIA0KICB4bGFiKCJBc3NldHMiKSArIA0KICB5bGFiKCJSZXZlbnVlIikNCmBgYA0KDQpgYGB7ciwgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NH0NCnBsb3Rfbm9ybSA8LSBmdW5jdGlvbihib3VuZCwgb3V0ZXIpIHsNCiAgeCA8LSBzZXEoLW91dGVyLG91dGVyLGxlbmd0aD0xMDApDQogIGh4IDwtIGRub3JtKHgpDQogIHBsb3QoeCwgaHgsIHR5cGU9Im4iLCB4bGFiPSJ6IHZhbHVlcyIsIHlsYWI9Ik5vcm1hbCBQREYiLCBtYWluPSJOb3JtYWwgRGlzdHJpYnV0aW9uIiwgYXhlcz1GQUxTRSkNCiAgbGluZXMoeCwgaHgpDQogIGkgPC0geCA8IC1ib3VuZA0KICBwb2x5Z29uKGMoLW91dGVyLHhbaV0sLWJvdW5kLC1ib3VuZCksIGMoMCxoeFtpXSxtYXgoaHhbaV0pLDApLCBjb2w9InJlZCIpDQogIGkgPC0geCA+IGJvdW5kDQogIHBvbHlnb24oYyhib3VuZCwgYm91bmQsIHhbaV0sb3V0ZXIpLCBjKDAsbWF4KGh4W2ldKSwgaHhbaV0sMCksIGNvbD0icmVkIikNCiAgYXhpcygxLCBhdD0tb3V0ZXI6b3V0ZXIsIHBvcz0wKQ0KfQ0KcGxvdF9ub3JtKDEuOTYsIDQpDQpgYGANCg0KYGBge3J9DQphbm92YShtb2QyLCBtb2QzLCB0ZXN0PSJDaGlzcSIpDQpgYGANCg0KYGBge3J9DQojIEVuc3VyZSBmaXJtcyBoYXZlIGF0IGxlYXN0ICQxTSAobG9jYWwgY3VycmVuY3kpLCBhbmQgaGF2ZSByZXZlbnVlDQojIGRmIGNvbnRhaW5zIGFsbCByZWFsIGVzdGF0ZSBjb21wYW5pZXMgZXhjbHVkaW5nIE5vcnRoIEFtZXJpY2ENCmRmX2NsZWFuIDwtIGZpbHRlcihkZiwgZGYkYXQ+MSwgZGYkcmV2dD4wKQ0KDQojIFdlIGNsZWFuZWQgb3V0IDU3OCBvYnNlcnZhdGlvbnMhDQpwcmludChjKG5yb3coZGYpLCBucm93KGRmX2NsZWFuKSkpDQoNCiMgQW5vdGhlciB1c2VmdWwgY2xlYW5pbmcgZnVudGlvbjoNCiMgUmVwbGFjZXMgTmFOLCBJbmYsIGFuZCAtSW5mIHdpdGggTkEgZm9yIGFsbCBudW1lcmljIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSENCmRmX2NsZWFuIDwtIGRmX2NsZWFuICU+JQ0KICBtdXRhdGVfaWYoaXMubnVtZXJpYywgbGlzdCh+cmVwbGFjZSguLCAhaXMuZmluaXRlKC4pLCBOQSkpKQ0KYGBgDQoNCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0NCnVvbCA8LSB1b2wgJT4lIG11dGF0ZShyZXZ0X2xlYWQgPSBsZWFkKHJldnQpKSAgIyBGcm9tIGRwbHlyDQpmb3JlY2FzdDEgPC0gbG0ocmV2dF9sZWFkIH4gbGN0ICsgY2hlICsgZWJpdCwgZGF0YT11b2wpDQpsaWJyYXJ5KGJyb29tKSAgIyBMZXRzIHVzIHZpZXcgYmlnZ2VyIHJlZ3Jlc3Npb24gb3V0cHV0cyBpbiBhIHRpZHkgZmFzaGlvbg0KdGlkeShmb3JlY2FzdDEpICAjIFByZXNlbnQgcmVncmVzc2lvbiBvdXRwdXQNCmdsYW5jZShmb3JlY2FzdDEpICAjIFByZXNlbnQgcmVncmVzc2lvbiBzdGF0aXN0aWNzDQpgYGANCg0KYGBge3J9DQpmb3JlY2FzdDIgPC0gDQogIGxtKHJldnRfbGVhZCB+IHJldnQgKyBhY3QgKyBjaGUgKyBsY3QgKyBkcCArIGViaXQgLCBkYXRhPXVvbCkNCnRpZHkoZm9yZWNhc3QyKQ0KYGBgDQoNCmBgYHtyfQ0KZ2xhbmNlKGZvcmVjYXN0MikNCg0KYW5vdmEoZm9yZWNhc3QxLCBmb3JlY2FzdDIsIHRlc3Q9IkNoaXNxIikNCmBgYA0KDQpgYGB7cn0NCiMgTm90ZSB0aGUgZ3JvdXBfYnkgLS0gd2l0aG91dCBpdCwgbGVhZCgpIHdpbGwgcHVsbCBmcm9tIHRoZSBzdWJzZXF1ZW50IGZpcm0hDQojIHVuZ3JvdXAoKSB0ZWxscyBSIHRoYXQgd2UgZmluaXNoZWQgZ3JvdXBpbmcNCmRmX2NsZWFuIDwtIGRmX2NsZWFuICU+JSANCiAgZ3JvdXBfYnkoaXNpbikgJT4lIA0KICBtdXRhdGUocmV2dF9sZWFkID0gbGVhZChyZXZ0KSkgJT4lDQogIHVuZ3JvdXAoKQ0KYGBgDQoNCmBgYHtyfQ0KZm9yZWNhc3QzIDwtDQogIGxtKHJldnRfbGVhZCB+IHJldnQgKyBhY3QgKyBjaGUgKyBsY3QgKyBkcCArIGViaXQgLCBkYXRhPWRmX2NsZWFuW2RmX2NsZWFuJGZpYz09IlNHUCIsXSkNCnRpZHkoZm9yZWNhc3QzKQ0KYGBgDQoNCmBgYHtyfQ0KZ2xhbmNlKGZvcmVjYXN0MykNCmBgYA0KDQpgYGB7cn0NCmZvcmVjYXN0NCA8LQ0KICBsbShyZXZ0X2xlYWQgfiByZXZ0ICsgYWN0ICsgY2hlICsgbGN0ICsgZHAgKyBlYml0ICwgZGF0YT1kZl9jbGVhbikNCnRpZHkoZm9yZWNhc3Q0KQ0KYGBgDQoNCmBgYHtyfQ0KZ2xhbmNlKGZvcmVjYXN0NCkNCmBgYA0KDQpgYGB7cn0NCmZvcmVjYXN0My4xIDwtDQogIGxtKHJldnRfbGVhZCB+IHJldnQgKyBhY3QgKyBjaGUgKyBsY3QgKyBkcCArIGViaXQgKyBmYWN0b3IoaXNpbiksDQogICAgIGRhdGE9ZGZfY2xlYW5bZGZfY2xlYW4kZmljPT0iU0dQIixdKQ0KIyBuPTcgdG8gcHJldmVudCBvdXRwdXR0aW5nIGV2ZXJ5IGZpeGVkIGVmZmVjdA0KcHJpbnQodGlkeShmb3JlY2FzdDMuMSksIG49MTUpDQpgYGANCg0KYGBge3J9DQpnbGFuY2UoZm9yZWNhc3QzLjEpDQphbm92YShmb3JlY2FzdDMsIGZvcmVjYXN0My4xLCB0ZXN0PSJDaGlzcSIpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2U9RiwgZXJyb3I9Riwgd2FybmluZz1GfQ0KbGlicmFyeShsZmUpDQpmb3JlY2FzdDMuMiA8LQ0KICBmZWxtKHJldnRfbGVhZCB+IHJldnQgKyBhY3QgKyBjaGUgKyBsY3QgKyBkcCArIGViaXQgfCBmYWN0b3IoaXNpbiksDQogICAgICAgZGF0YT1kZl9jbGVhbltkZl9jbGVhbiRmaWM9PSJTR1AiLF0pDQpzdW1tYXJ5KGZvcmVjYXN0My4yKQ0KYGBgDQoNCmBgYHtyLCBtZXNzYWdlPUYsIGZpZy5oZWlnaHQ9NH0NCmRmX2NsZWFuICU+JQ0KICBmaWx0ZXIoZmljPT0iU0dQIikgJT4lDQogIGdyb3VwX2J5KGlzaW4pICU+JQ0KICBtdXRhdGUobWVhbl9yZXZ0X2xlYWQ9bWVhbihyZXZ0X2xlYWQsIG5hLnJtPVQpKSAlPiUNCiAgc2xpY2UoMSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgZ2dwbG90KGFlcyh4PW1lYW5fcmV2dF9sZWFkKSkgKyBnZW9tX2hpc3RvZ3JhbShhZXMoeSA9IC4uZGVuc2l0eS4uKSkgKyAgZ2VvbV9kZW5zaXR5KGFscGhhPS40LCBmaWxsPSIjRkY2NjY2IikNCmBgYA0KDQpgYGB7cn0NCiMgRXhwb3J0cyBmb3IgdGhlIGZvbGxvd2luZyB3ZWVrDQpzYXZlKGRmX2NsZWFuLCBmb3JlY2FzdDIsIHVvbCwgZm9yZWNhc3Q0LCBmaWxlID0gIi4uLy4uL0RhdGEvU2Vzc2lvbl8yX2V4cG9ydC5SRGF0YSIpDQpgYGANCg0K