You must create a session before playing it. If not you will get an error.
After the session has been successfully created, hit the 'PLAY' Button.
When the dialog with tips for good session playback appears, click the 'Begin Playback' Button, And your session will begin playing.
Status updates will show on the lower left (on the status bar), telling you how far into the practice you are, and how far you need to go.
I built in this feature because I found it beneficial for me to make me explain why I am ending the session early, I found that many times, I resumed the session, and kept plugging on.
If you absolutely have to end the session before it's end, just click the 'x' to close the program same as you would close any other program. It will ask you:
You can view a list of the reasons you ended early by clicking the 'View Premature Endings' Button on the main program window (top right). I found this helps me avoid interruptions in the future, and plan accordingly so I can spend more time practicing and progressing.


Analyzing Websites:
-
IMDb
This website allows me read up on all of the latest news about the movies I've already seen, or am wanting to watch.
The hompage has information about what is in the box office, what is opening this week, with links to news, blogs, etc. My eyes are drawn to the upper portion of the page, containing the search bar. Probably because the background is dark and the search bar is light colored. Using this feature I can easily navigate and find what I am looking for.
Navigating around the content of imdb is easy to do. An example is clicking the actors name in one movie brings up their profile, allowing users to find other films they have starred in.
-
engadget
Another favorite of mine is engadget. Which provides news and updates about cutting edge technologies.
The homepage draws your attention towards a bundle of pictures, which link to popular articles lower on the page. If you want to know what news is trending there is a nice sidebar that links to and details which is being shared the most.
User navigation is easy as the top nav bar moves as the user scrolls. If you have never checked this site out, I recommend giving it a look.
-
theChive
I have saved the best for last. The chive is set up like a blogging site. Which draws your attention to a brightly colored content section containing picture and gif threads...a few videos sprinkled about. The real gem of this website is the community of users this website connects...a great group of giving individuals.
Getting around this site is very straight forward. As the user is able to open threads of pictures to scroll. The site also adds a slideshow picture navigation...never got into that. I don't like that the navigation bar at the top is static and doesn't follow you as you scroll. That aside, awesome site check this one out.
IMDb
This website allows me read up on all of the latest news about the movies I've already seen, or am wanting to watch.
The hompage has information about what is in the box office, what is opening this week, with links to news, blogs, etc. My eyes are drawn to the upper portion of the page, containing the search bar. Probably because the background is dark and the search bar is light colored. Using this feature I can easily navigate and find what I am looking for.
Navigating around the content of imdb is easy to do. An example is clicking the actors name in one movie brings up their profile, allowing users to find other films they have starred in.
engadget
Another favorite of mine is engadget. Which provides news and updates about cutting edge technologies.
The homepage draws your attention towards a bundle of pictures, which link to popular articles lower on the page. If you want to know what news is trending there is a nice sidebar that links to and details which is being shared the most.
User navigation is easy as the top nav bar moves as the user scrolls. If you have never checked this site out, I recommend giving it a look.
theChive
I have saved the best for last. The chive is set up like a blogging site. Which draws your attention to a brightly colored content section containing picture and gif threads...a few videos sprinkled about. The real gem of this website is the community of users this website connects...a great group of giving individuals.
Getting around this site is very straight forward. As the user is able to open threads of pictures to scroll. The site also adds a slideshow picture navigation...never got into that. I don't like that the navigation bar at the top is static and doesn't follow you as you scroll. That aside, awesome site check this one out.


2.2 Arts & Crafts
Crafts
We will focus on six data wrangling functions in the dplyr
package:
filter()
: extracts rows (e.g., observations) of a data frame. We put logical vectors in its arguments.select()
: extracts columns (e.g., variables) of a data frame. We put column names in its arguments.arrange()
: orders rows of a data frame. We put column names in its arguments.summarise()
: collapses a data frame into summary statistics. We put summary functions (e.g., statistics functions) using column names in its arguments.mutate()
: creates new variables and adds them to the existing columns. We put window functions (e.g., transforming operations) using column names in its arguments.group_by()
: assigns rows into groups within a data frame. We put column names in its arguments.
The very first argument in all these functions is a data frame, and by using this we can easily pipe a sequence of data wrangling operations through %>%
operator. The key is to start with a data frame and then formulate a sequence of data wrangling operations in plain English, which we can translate into code by replacing then in the sequence with the %>%
operator. Say, we want to find the average of delays in departures and arrivals from New York to the St. Paul-Minneapolis airport (MSP). We can construct the following sequence of instructions: take the flight data frame, apply filter()
to extract the rows of flights to MSP, and then apply summarise()
to calculate the mean.
flights %>% # take data frame "flights", then
filter(dest == "MSP") %>% # filter rows, then
summarise(
# summarise departure and arrival delays for their means
# and call them mean_dep_delay and mean_arr_delay respectively
mean_dep_delay = mean(dep_delay, na.rm = TRUE),
mean_arr_delay = mean(arr_delay, na.rm = TRUE)
) # calculate the mean, while removing NA values
## # A tibble: 1 × 2
## mean_dep_delay mean_arr_delay
## <dbl> <dbl>
## 1 13.32481 7.270169
In summarise()
, one can use summary functions that takes a vector as an input and produces a scaler as an output. This includes functions like mean()
, sd()
(standard deviation), quantile()
, min()
, max()
, and n()
(observation count in the dplyr
package).
Each time we apply the %>%
operator above, we pass a modified data frame from one data operation to another through the first argument. The above code is equivalent to
summarise( # data frame "flights" is inside filter(), which is inside summarise()
filter(flights, dest == "MSP"),
mean_dep_delay = mean(dep_delay, na.rm = TRUE),
mean_arr_delay = mean(arr_delay, na.rm = TRUE)
)
## # A tibble: 1 × 2
## mean_dep_delay mean_arr_delay
## <dbl> <dbl>
## 1 13.32481 7.270169
You will quickly discover that %>%
operator makes the code much easier to read, write, and edit and how that might inspire you want to play with the data more.
Let’s add a few more lines to the previous example. Say, additionally we want to see the average delay by carrier and sort the results by the number of observations (e.g. flights) in descending order.
Okay, what do we do? We make a sequence of data wrangling operations in plain English and translate that into code by replacing then with %>%
operator.
For example, we say, “take the data frame flights
; then (%>%
) filter()
to extract the rows of flights to MSP; then (%>%
) group rows by carrier; then (%>%
) summarise()
data for the number of observations and the means; then (%>%
) arrange()
the results by the observation count in descending order.”
flight_stats_MSP <- flights %>% # assign the results to an object named "flight_stats"
filter(dest == "MSP") %>%
group_by(carrier) %>% # group rows by carrier
summarise(
n_obs = n(), # count number of rows
mean_dep_delay = mean(dep_delay, na.rm = TRUE),
mean_arr_delay = mean(arr_delay, na.rm = TRUE)
) %>%
arrange(desc(n_obs)) # sort by n_obs in descending order
flight_stats_MSP # show flight_stats object
## # A tibble: 6 × 4
## carrier n_obs mean_dep_delay mean_arr_delay
## <chr> <int> <dbl> <dbl>
## 1 DL 2864 10.651392 4.035702
## 2 EV 1773 17.093413 10.527995
## 3 MQ 1293 8.255457 9.559350
## 4 9E 1249 19.658113 8.089776
## 5 OO 4 0.750000 -2.000000
## 6 UA 2 -6.000000 -5.500000
The carrier variable is expressed in the International Air Transportation Association (IATA) code, so let’s add a column of carrier names by joining another data frame called airlines
. In RStudio, you can find this data frame under the Environment tab (in the upper right corner); switch the display option from Global Environment to package:nycflights13. To inspect the data frame, type View(airlines)
in the R console. Also, by typing data()
you can see a list of all datasets that are loaded with libraries.
left_join(flight_stats_MSP, airlines, by="carrier") %>%
# left_join(a,b, by="var") joins two data frames a, b by matching rows of b to a
# by identifier variable "var".
kable(digits=2) # kable() prints a better-looking table here
| carrier | n_obs | mean_dep_delay | mean_arr_delay | name |
|---|---|---|---|---|
| DL | 2864 | 10.65 | 4.04 | Delta Air Lines Inc. |
| EV | 1773 | 17.09 | 10.53 | ExpressJet Airlines Inc. |
| MQ | 1293 | 8.26 | 9.56 | Envoy Air |
| 9E | 1249 | 19.66 | 8.09 | Endeavor Air Inc. |
| OO | 4 | 0.75 | -2.00 | SkyWest Airlines Inc. |
| UA | 2 | -6.00 | -5.50 | United Air Lines Inc. |
In the next example, we add new variables to flights
using mutate()
.
flights %>%
# keep only columns named "dep_delay" and "arr_delay"
select(dep_delay, arr_delay) %>%
mutate(
gain = arr_delay - dep_delay,
gain_rank = round(percent_rank(gain), digits = 2)
# Note: we can immediately use the "gain" variable we just defined.
)
## # A tibble: 336,776 × 4
## dep_delay arr_delay gain gain_rank
## <dbl> <dbl> <dbl> <dbl>
## 1 2 11 9 0.81
## 2 4 20 16 0.88
## 3 2 33 31 0.94
## 4 -1 -18 -17 0.22
## 5 -6 -25 -19 0.18
## 6 -4 12 16 0.88
## 7 -5 19 24 0.92
## 8 -3 -14 -11 0.37
## 9 -3 -8 -5 0.54
## 10 -2 8 10 0.82
## # ... with 336,766 more rows
We extracted specific columns of flights
by select()
and added new columns defined in mutate()
. mutate()
differs from summarise()
in that mutate()
adds new columns to the data frame, while summarise()
collapses the data frame into a summary table.
There are roughly five types of window functions that are commonly used inside mutate()
: (1) summary functions, which are interpreted as a vector of repeated values (e.g., a column of an identical mean value): (2) ranking or ordering functions (e.g., row_number()
, min_rank()
, dense_rank()
, cume_dist()
, percent_rank()
, and ntile()
): (3) offset functions, say defining a lagged variable in time series data (lead()
and lag()
): (4) cumulative aggregates (e.g., cumsum()
, cummin()
, cummax()
, cumall()
, cumany()
, and cummean()
): (5) fixed-window rolling aggregates such as a windowed mean, median, etc. To find help files for these function, for example, type ?cumsum
.
Before moving to the graphics, let’s quickly go over what a function is in R and how you can use a custom function inside summarise()
or mutate()
. In R, we use function()
to create a function, which has its name, input arguments separated by comma, and a body (e.g., tasks to perform and what to return as an output).
your_function_name <- function(input arguments) {
task1
task2
.
.
.
output_to_return
}
For a function having only a single expression to execute, we can omit brackets { }
.
another_function <- function(input args) task_and_output_in_a_single_expression
Let’s go through a few examples.
## [1] 1 2 3 4 5 6 7 8 9 10
## [1] 1 2 3 4 5 6 7 8 9 10 NA NA
my_mean_1 <- function(x) mean(x, na.rm = TRUE)
# Input arguments: x
# Output: the calculation result of mean(x, na.rm = TRUE).
# x is required by mean() (and implicitly assumed to be a vector of numeric values).
# mean() is an existing function. The "na.rm" argument of mean() is set to be TRUE.
my_mean_1(vec1)
## [1] 5.5
my_mean_2 <- function(x, na.rm=TRUE) mean(x, na.rm = na.rm)
# Input arguments: x and na.rm (optional with the default value of TRUE)
# Output: the calculation result of mean(x, na.rm = na.rm).
# The input argument "na.rm" is passed to the input argument "na.rm" of mean()
my_mean_2(vec2)
## [1] 5.5
## [1] NA
my_zscore <- function(x, remove_na=TRUE) {
(x - my_mean_2(x, na.rm = remove_na))/sd(x, na.rm = remove_na)
}
# Inputs: x and remove_na (optional: default = TRUE)
# Output: z-score of vector x
# my_mean2() and sd() return scalers but are interpreted
# as a vector of repeated valuses that has the same length as x.
my_zscore(vec1) %>% round(2)
## [1] -1.49 -1.16 -0.83 -0.50 -0.17 0.17 0.50 0.83 1.16 1.49
Let’s apply functionsmy_mean_2()
and my_zscore()
in summarise()
and mutate()
.
flights %>%
select(dep_delay) %>%
summarise(
mean_dep_delay = my_mean_2(dep_delay), # using my_mean_2()
mean_dep_delay_na = my_mean_2(dep_delay, na.rm = FALSE) # this returns NA
) %>%
kable(digits=2)
| mean_dep_delay | mean_dep_delay_na |
|---|---|
| 12.64 | NA |
flights_gain <- flights %>%
select(dep_delay, arr_delay) %>%
mutate(
gain = arr_delay - dep_delay,
gain_z = (gain - my_mean_2(gain))/sd(gain, na.rm=TRUE), # using my_mean_2()
gain_z2 = my_zscore(gain_z) # using my_zscore()
)
head(flights_gain) %>% # show the first several rows
kable(digits=2)
| dep_delay | arr_delay | gain | gain_z | gain_z2 |
|---|---|---|---|---|
| 2 | 11 | 9 | 0.81 | 0.81 |
| 4 | 20 | 16 | 1.20 | 1.20 |
| 2 | 33 | 31 | 2.03 | 2.03 |
| -1 | -18 | -17 | -0.63 | -0.63 |
| -6 | -25 | -19 | -0.74 | -0.74 |
| -4 | 12 | 16 | 1.20 | 1.20 |
Creating a function spares us from writing similar codes in multiple places. While avoiding such repetition is important for making reading and editing code easier, it also reduces coding errors.
A situation where you may consider using custom functions is inside functions like summarise_each()
and mutate_each()
. The two functions allow for applying summary functions like mean()
or sd()
to each column in a data frame. summarise_each()
and mutate_each()
work by calling a function by its name. They are very easy to use when an operation is to summarize a vector into a statistics without needing to specify additional arguments, say mean(var1)
. However, providing additional arguments into a function, say mean(var1, na.rm=TRUE)
, becomes somewhat cumbersome in terms of its syntax.
One approach to get around this problem is to pre-process the data frame before getting to a summarise_each()
or mutate_each()
section. For example, if we want to test the argument na.rm=TRUE
to mean()
, we can first filter out rows that contain missing values (NA
) and then apply summarise_each()
.
flights_gain %>%
select(dep_delay, arr_delay, gain) %>%
filter(!is.na(dep_delay) & !is.na(arr_delay)) %>%
# filter out rows that have NA values in dep_delay or arr_deplay
summarise_each("mean") %>%
kable(digits=2)
| dep_delay | arr_delay | gain |
|---|---|---|
| 12.56 | 6.9 | -5.66 |
The other approach is to use a custom function. For instance, my_mean_2()
we defined above has the default argument na.rm=TRUE
that gets passed into mean()
, effectively overwriting the default argument na.rm=FALSE
of mean()
. A custom function (as well as any standard summary function) can be called in summarise_each()
or mutate_each()
using funs()
flights_gain %>%
select(dep_delay, arr_delay, gain) %>%
summarise_each(funs("my_mean_2")) %>%
kable(digits=2)
| dep_delay | arr_delay | gain |
|---|---|---|
| 12.64 | 6.9 | -5.66 |
Being able to use your own functions in dplyr
-style data wrangling operations will greatly enhance your ability to quickly analyze data in R.
Arts
Now we will cover the basics of data visualization via the ggplot2 package.
The ggplot2
syntax has three essential components for generating graphics: data, aes, and geom. This implements the following philosophy (a quote mentioned in ModernDive);
A statistical graphic is a mapping of data variables to aesthetic attributes of geometric objects.
— (Wilkinson 2005)
While coding complex graphics via ggplot()
may appear intimidating at first, it boils down to the three primary components:
data: a data frame e.g., the first argument in
ggplot(data, ...)
.geom: geometric objects such as points, lines, bars, etc. with parameters given in the (), e.g.,
geom_point()
,geom_line()
,geom_histogram()
aes: specifications for x-y variables, as well as variables to differentiate geom objects by color , shape, or size. e.g.,
aes(x = var_x, y = var_y, shape = var_z)
One can refine a plot figure by adding secondary components or characteristics such as
stat: data transformation, overlay of statistical inferences etc.
scales: scaling data points etc.
coord: Cartesian coordinates, polar coordinates, mapping projections etc.
facet: laying out multiple plot panels in a grid etc.
In what follows below, we will generate five common types of plots: scatter-plots, line-graphs, boxplots, histograms, and barplots. To provide a context, let’s use these plots to investigate what may explain patterns of flight departure delays.
First, let’s consider the possibility of congestion at an airport during certain times of the day or certain seasons. We can use barplots to see whether there is any obvious pattern in the flight distribution across flight origins (i.e., airports) in New York City with St. Paul-Minneapolis airport (MSP) as a destination. A barplot shows observation counts (e.g., rows) by category.
ggplot(data = flights, # the first argument is the data frame
mapping = aes(x = origin)) + # the second argument is "mapping", which is aes()
geom_bar() # after "+" piping operator of ggplot(), we add geom_XXX() elements
We can make the plot more informative and aesthetic.
ggplot(data = flights,
mapping = aes(x = origin, fill = origin)) + # here "fill" gives bars distinct colors
geom_bar() +
facet_wrap( ~ hour) # "facet_wrap( ~ var)" generates a grid of plots by var
Another way to see the same information is a histogram.
flights %>%
filter(hour >= 5) %>% # exclude hour earlier than 5 a.m.
ggplot(aes(x = hour, fill = origin)) + geom_histogram(binwidth = 1, color = "white")
While mornings and late afternoons tend to get busy, there is not much difference in the number of flights across airports.
Let’s see if there are distinct patters of departure delays over the course of a year. We do this by taking the average of departure delays for each day by flight origin and plot the data as a time series using line-graphs.
delay_day <- flights %>%
group_by(origin, year, month, day) %>%
summarise(dep_delay = mean(dep_delay, na.rm = TRUE)) %>%
mutate(date = as.Date(paste(year, month, day), format="%Y %m %d")) %>%
filter(!is.na(dep_delay)) # exclude rows with dep_delay == NA
delay_day %>% # "facet_grid( var ~ .)" is similar to "facet_wrap( ~ var)"
ggplot(aes(x = date, y = dep_delay)) + geom_line() + facet_grid( origin ~ . )
The seasonal pattern seems similar across airports, and summer months appear to be busier on average. Across these airports, let’s see how closely these patterns are related to each other by focusing on a few summer months and making an overlap of the three line-graphs (EWR, JFK, and LGA).
delay_day %>%
filter("2013-07-01" <= date, "2013-08-31" >= date) %>%
ggplot(aes(x = date, y = dep_delay, color = origin)) + geom_line()
We can see similar patterns of spikes across airports occurring on certain days, indicating a tendency for the three airports to get busy on the same days. Would this mean that the three airports tend to be congested at the same time?
In the previous figure, there seems to be some cyclical pattern of delays. A good place to start would be comparing delays by day of the week. Here is a function to calculate day of the week for a given date.
my_dow <- function(date) {
# as.POSIXlt(date)[['wday']] returns integers 0, 1, 2, .. 6, for Sun, Mon, ... Sat.
# We extract one item from a vector (Sun, Mon, ..., Sat) by position numbered from 1 to 7.
dow <- as.POSIXlt(date)[['wday']] + 1
c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")[dow] # extract "dow"-th element
}
# Input: date in the format as in "2017-01-23"
# Output: day of week
Sys.Date() # Sys.Date() returns the current date
## [1] "2017-06-14"
## [1] "Wed"
Now, let’s take a look at the mean delay by day of the week using boxplots.
delay_day <- flights %>%
group_by(year, month, day) %>%
summarise(dep_delay = mean(dep_delay, na.rm = TRUE)) %>%
mutate(date = as.Date(paste(year, month, day), format="%Y %m %d"),
# date defined by as.Data() function
wday = my_dow(date),
weekend = wday %in% c("Sat", "Sun")
# %in% operator: A %in% B returns TRUE/FALSE for whether each element of A is in B.
)
# show the first 10 elements of "wday" variable in "delay_day" data frame
delay_day$wday[1:10]
## [1] "Tue" "Wed" "Thu" "Fri" "Sat" "Sun" "Mon" "Tue" "Wed" "Thu"
delay_day$wday <- ordered(delay_day$wday,
levels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"))
# adding a sorting order (Mon, Tue, ..., Sun)
delay_day$wday[1:10]
## [1] Tue Wed Thu Fri Sat Sun Mon Tue Wed Thu
## Levels: Mon < Tue < Wed < Thu < Fri < Sat < Sun
delay_day %>%
filter(!is.na(dep_delay)) %>%
ggplot(aes(x = wday, y = dep_delay, fill = weekend)) + geom_boxplot()
It appears that delays are on average longer on Thursdays and Fridays and shorter on Saturdays. This is plausible if more people are traveling on Thursdays and Fridays before the weekend, and less are traveling on Saturdays to enjoy the weekend. Are Saturdays really less busy? Let’s find out.
flights_wday <- flights %>%
mutate(date = as.Date(paste(year, month, day), format="%Y %m %d"),
wday = ordered(my_dow(date),
levels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")),
weekend = wday %in% c("Sat", "Sun")
)
flights_wday %>%
group_by(wday) %>%
summarise( nobs = n() )
## # A tibble: 7 × 2
## wday nobs
## <ord> <int>
## 1 Mon 50690
## 2 Tue 50422
## 3 Wed 50060
## 4 Thu 50219
## 5 Fri 50308
## 6 Sat 38720
## 7 Sun 46357
Yes, Saturdays are less busy for the airports in terms of flight numbers.
Could we generalize this positive relationship between the number of flights and the average delays, which we find across days of the week? To investigate this, we can summarize the data into the average delays by date-hour and see if the busyness of a particular hour of a particular day is correlated with the mean delay. We visualize these data using a scatter plot.
delay_day_hr <- flights %>%
group_by(year, month, day, hour) %>% # grouping by date-hour
summarise(
n_obs = n(),
dep_delay = mean(dep_delay, na.rm = TRUE)
) %>%
mutate(date = as.Date(paste(year, month, day), format="%Y %m %d"),
wday = my_dow(date)
)
plot_delay <- delay_day_hr %>%
filter(!is.na(dep_delay)) %>%
ggplot(aes(x = n_obs, y = dep_delay)) + geom_point(alpha = 0.1)
# plot of n_obs and the average dep_delay
# where each point represents an date-hour average
# "alpha = 0.1" controls the degree of transparency of points
plot_delay
Along the horizontal axis, we can see how the number of flights is distributed across date-hours. Some days are busy, and some hours busier still. It appears that there are two clusters in the number of flights, showing very slow date-hours (e.g., less than 10 flights flying out of New York city per hour) and normal date-hours (e.g., about 50 to 70 flights per hour). We could guess that the delays in the slow hours are caused by bad weather. On the other hand, we may wonder if the excess delays in the normal hours, compared to the slow hours, are caused by congestion at the airports. To see this, let’s fit a curve that captures the relationships between n_obs
and dep_delay
. Our hypothesis is that the delay would become more likely and longer as the number of flights increases.
## `geom_smooth()` using method = 'gam'
We cannot see any clear pattern. How about fitting a curve by day of the week?
plot_delay +
# additional aes() argument for applying different colors to the day of the week
geom_smooth(aes(color = wday), se=FALSE)
## `geom_smooth()` using method = 'gam'
Surprisingly, the delay does not seem to increase with the flights. There are more delays on Thursdays and Fridays and less delays on Saturdays, but we see no evidence of flight congestion as a cause of delay.
Let’s take a closer look at the distribution of the delays. If it is not normally distributed, we may want to apply a transformation.
delay_day_hr %>% filter(!is.na(dep_delay)) %>%
ggplot(aes(x = dep_delay)) + geom_histogram(color = "white")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
The distribution of the average delays are greatly skewed.
In applying a logarithmic transformation, here we have to shift the variable so that its minimum is greater than zero.
# define new column called "dep_delay_shifted"
delay_day_hr$dep_delay_shifted <- delay_day_hr %>%
with(dep_delay - min(dep_delay, na.rm = TRUE) + 1)
# with() function takes a data frame in the first argument and allows for
# referencing its variable names.
delay_day_hr %>%
ungroup() %>% # removing group_by() attribute
select(dep_delay, dep_delay_shifted) %>%
with(
apply(., 2, summary)
# apply(data, num, fun) applies function "fun" for each item
# in dimension "num" (1 = cows, 2= columns) of the data frame
# Data referenced by "." means all variables of the dataset inside with().
) %>% t() # transpose rows and columns
## Min. 1st Qu. Median Mean 3rd Qu. Max. NA's
## dep_delay -18 1.054 6.571 12.99 15.44 269 13
## dep_delay_shifted 1 20.050 25.570 31.99 34.44 288 13
Now the transformed distribution;
# Under the log of 10 transformation, the distribution looks closer to a normal distribution.
delay_day_hr %>% filter(!is.na(dep_delay_shifted)) %>%
ggplot(aes(x = dep_delay_shifted)) +
scale_x_log10() +
geom_histogram(color = "white")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
# Alternatively, one can apply the natural logarithm to transform a variable. Histogram shows no difference here.
delay_day_hr %>% filter(!is.na(dep_delay_shifted)) %>%
ggplot(aes(x = dep_delay_shifted)) +
scale_x_continuous(trans = "log") +
geom_histogram(color = "white")
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
The transformed distribution is much less skewed than the original. Now, let’s plot the relationship between delays and flights again.
delay_day_hr %>% filter(!is.na(dep_delay_shifted), dep_delay_shifted > 5) %>%
ggplot(aes(x = n_obs, y = dep_delay_shifted)) +
scale_y_log10() + # using transformation scale_y_log10()
geom_point(alpha = 0.1) +
geom_smooth()
## `geom_smooth()` using method = 'gam'
We still do not see a pattern that busier hours have more delays. This seems to suggest that the airports in New York City manage the fluctuating number of flights without causing congestion.
References
Wilkinson, Leland. 2005. The Grammar of Graphics.


Fork it on GitHub
Home
URL Shortener Version 3.0.1
Input the URL you want to shorten in the text box below
www.yourUrlHere.com


Take a look at some of my projects I've done. My projects makes use of vast variety of latest technology tools.


Create Character
--
View All Characters
--
Character Name:
View Character
Name:
Age:
Gender:
Biography:
Level:
Race:
Class:
Spellcaster:
Yes
No
Hit Points:
Ability Scores:
Delete
Download XML
ID
Name
Race
Class
Level


二叉树的序列化与反序列化
文章目录
LeetCode 297. Serialize and Deserialize Binary Tree
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.
For example, you may serialize the following tree
1
/ \
2 3
/ \
4 5
as “[1,2,3,null,null,4,5]”, just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
解析：
采用先序遍历的思路，为了保证重构二叉树时，节点能够插入到数中的正确位置，空节点用“#”保存。为了保证从字符串中读取正确的节点值，节点的值在字符串中用空格分开。也可以用'!‘来分开,重构时依旧安装先序的思想递归实现即可。
不要使用类成员/全局/静态变量来存储状态。你的序列化和反序列化算法应该是无状态的。应该使用流模拟
|
|
LeetCode 449. Serialize and Deserialize BST
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary search tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary search tree can be serialized to a string and this string can be deserialized to the original tree structure.
The encoded string should be as compact as possible.
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
解析：
和上题代码完全相同。
LeetCode 331. Verify Preorder Serialization of a Binary Tree
One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, we record the node’s value. If it is a null node, we record using a sentinel value such as #.
_9_
/ \
3 2
/ \ / \
4 1 # 6
/ \ / \ / \
# # # # # #
For example, the above binary tree can be serialized to the string “9,3,4,#,#,1,#,#,2,#,6,#,#”, where # represents a null node.
Given a string of comma separated values, verify whether it is a correct preorder traversal serialization of a binary tree. Find an algorithm without reconstructing the tree.
Each comma separated value in the string must be either an integer or a character ‘#’ representing null pointer.
You may assume that the input format is always valid, for example it could never contain two consecutive commas such as “1,,3”.
Example 1:
"9,3,4,#,#,1,#,#,2,#,6,#,#"
Return true
Example 2:
"1,#"
Return false
Example 3:
"9,#,#,1"
Return false
解析：
在二叉树中，如果我们将空节点视为叶子节点，那么除根节点外的非空节点（分支节点）提供2个出度和1个入度（2个孩子和1个父亲）。所有的空节点提供0个出度和1个入度（0个孩子和1个父亲）
二叉树上的每一条边都能使一个节点的入度+1和另一个节点的出度+1，要判断一棵树是不是二叉树，可以根据入度和出度的关系来判断。
假如我们尝试重建这棵树。在构建的过程中，记录出度与入度之差，记为diff = outdegree - indegree。可以得知若这棵树是二叉树，diff必为0
当遍历到某个节点时，我们令diff - 1（因为节点提供了一个入度）。如果diff<0,返回false；如果节点非空，再令diff + 2（因为节点提供了2个出度）。最后判断diff==0;
如果在遍历过程中的某时刻，系统的入度>出度，则说明当前序列中出现过的所有分支节点的“空闲分支”均已用完，后序节点没有办法挂载到之前出现的节点之上，从而判定先序遍历的序列是不合法的。
|
|
文章作者 Forz
上次更新 2017-06-24


tau.mvc package¶
TODO: FIXME: Docs
TAU Commander core software architecture.
TAU Commander follows the Model-View-Controller (MVC) architectural pattern.
Packages in tau.model
define models and controllers. The model module
declares the model attributes as a dictionary named ATTRIBUTES in the form:
<attribute>: {
property: value,
[[property: value], ...]
}
Attribute properties can be anything you wish, including these special properties:
type
(str): The attribute is of the specified type.required
(bool): The attribute must be specified in the data record.model
(str): The attribute associates this model with another data model.collection
(str): The attribute associates this model with another data model.via
(str): The attribute associates with another model “via” the specified attribute.
The controller module declares the controller as a subclass of Controller
. Controller
class objects are not bound to any particular data record and so can be used to create, update,
and delete records. Controller class instances are bound to a single data record.
Models may have associations and references. An association creates a relationship between an attribute of this model and an attribute of another (a.k.a foreign) model. If the associated attribute changes then the foreign model will update its associated attribute. A reference indicates that this model is being referened by one or more attributes of a foreign model. If a record of the referenced model changes then the referencing model, i.e. the foreign model, will update all referencing attributes.
Associations, references, and attributes are constructed when tau.model
is imported.
Examples
One-sided relationship
class Pet(Controller):
attributes = {'name': {'type': 'string'}, 'hungry': {'type': 'bool'}}
class Person(Controller):
attributes = {'name': {'type': 'string'}, 'pet': {'model': 'Pet'}}
We’ve related a Person to a Pet but not a Pet to a Person. That is, we can query a Person to get information about their Pet, but we can’t query a Pet to get information about their Person. If a Pet record changes then the Person record that referenced the Pet record is notified of the change. If a Person record changes then nothing happens to Pet. The Pet and Person classes codify this relationship as:
- Pet.references = set( (Person, ‘pet’) )
- Pet.associations = {}
- Person.references = set()
- Person.associations = {}
Some example data for this model:
{
'Pet': {1: {'name': 'Fluffy', 'hungry': True}},
'Person': {0: {'name': 'Bob', 'pet': 1}}
}
One-to-one relationship
class Husband(Controller):
attributes = {'name': {'type': 'string'}, 'wife': {'model': 'Wife'}}
class Wife(Controller):
attributes = {'name': {'type': 'string'}, 'husband': {'model': 'Husband'}}
We’ve related a Husband to a Wife. The Husband may have only one Wife and the Wife may have only one Husband. We can query a Husband to get information about their Wife and we can query a Wife to get information about their Husband. If a Husband/Wife record changes then the Wife/Husband record that referenced the Husband/Wife record is notified of the change. The Husband and Wife classes codify this relationship as:
- Husband.references = set( (Wife, ‘husband’) )
- Husband.associations = {}
- Wife.references = set( (Husband, ‘wife’) )
- Wife.associations = {}
Example data:
{
'Husband': {2: {'name': 'Filbert', 'wife': 1}},
'Wife': {1: {'name': 'Matilda', 'husband': 2}}
}
One-to-many relationship
class Brewery(Controller):
attributes = {'address': {'type': 'string'},
'brews': {'collection': 'Beer',
'via': 'origin'}}
class Beer(Controller):
attributes = {'origin': {'model': 'Brewery'},
'color': {'type': 'string'},
'ibu': {'type': 'int'}}
We’ve related one Brewery to many Beers. A Beer has only one Brewery but a Brewery has zero or more Beers. The brews attribute has a via property along with a collection property to specify which attribute of Beer relates Beer to Brewery, i.e. you may want a model to have multiple one-to-many relationship with another model. The Brewery and Beer classes codify this relationship as:
- Brewery.references = set()
- Brewery.associations = {‘brews’: (Beer, ‘origin’)}
- Beer.references = set()
- Beer.associations = {‘origin’: (Brewery, ‘brews’)}
Example data:
{
'Brewery': {100: {'address': '4615 Hollins Ferry Rd, Halethorpe, MD 21227',
'brews': [10, 12, 14]}},
'Beer': {10: {'origin': 100, 'color': 'gold', 'ibu': 45},
12: {'origin': 100, 'color': 'dark', 'ibu': 15},
14: {'origin': 100, 'color': 'pale', 'ibu': 30}}
}
Many-to-many relationship
class Actor(Controller):
attributes = {'home_town': {'type': 'string'},
'appears_in': {'collection': 'Movie',
'via': 'cast'}}
class Movie(Controller):
attributes = {'title': {'type': 'string'},
'cast': {'collection': 'Actor',
'via': 'appears_in'}}
An Actor may appear in many Movies and a Movie may have many Actors. Changing the cast of a Movie notifies Actor and changing the movies an Actor apppears_in notifies Movie. This relationship is codified as:
- Actor.references = set()
- Actor.associations = {‘appears_in’: (Movies, ‘cast’)}
- Movie.references = set()
- Movie.associations = {‘cast’: (Actor, ‘appears_in’)}
Submodules¶
tau.mvc.controller module¶
TODO: FIXME: Docs
-
class
tau.mvc.controller.
Controller
(model_cls, storage)[source]¶ Bases:
object
The “C” in MVC.
-
model
¶ AbstractModel
Data model.
-
storage
¶ AbstractDatabase
Record storage.
-
_associate
(record, foreign_model, affected, via)[source]¶ Associates a record with another record.
Parameters:
-
_disassociate
(record, foreign_model, affected, via)[source]¶ Disassociates a record from another record.
Parameters:
-
create
(data)[source]¶ Store a new record and update associations.
Invokes the on_create callback after the data is recorded.
Parameters: data (dict) – Data to record. Returns: The newly created data. Return type: Model
-
delete
(keys)[source]¶ Delete recorded data and update associations.
- The behavior depends on the type of keys:
- Record.ElementIdentifier: delete the record with that element identifier.
- dict: delete all records with attributes matching keys.
- list or tuple: delete all records matching the elements of keys.
bool(keys) == False
: raise ValueError.
Invokes the on_delete callback for each record before the record is deleted.
Parameters: - keys (dict) – Attributes to match.
- keys – Fields or element identifiers to match.
-
classmethod
export_records
(keys=None, eids=None)[source]¶ Export data records.
Constructs a dictionary containing records matching keys or eids and all their associated records. Association fields (model and collection) are not updated and may contain eids of undefined records.
Parameters: Returns: Dictionary of tables containing records.
Return type: Example:
{ 'Brewery': {100: {'address': '4615 Hollins Ferry Rd, Halethorpe, MD 21227', 'brews': [10, 12, 14]}}, 'Beer': {10: {'origin': 100, 'color': 'gold', 'ibu': 45}, 12: {'origin': 100, 'color': 'dark', 'ibu': 15}, 14: {'origin': 100, 'color': 'pale', 'ibu': 30}} } Beer.export_records(eids=[10]) { 'Brewery': {100: {'address': '4615 Hollins Ferry Rd, Halethorpe, MD 21227', 'brews': [10, 12, 14]}}, 'Beer': {10: {'origin': 100, 'color': 'gold', 'ibu': 45}} }
-
populate
(model, attribute=None)[source]¶ Merges associated data into the model record.
Example
Suppose we have the following Person records:
1: {'name': 'Katie', 'friends': [2, 3]} 2: {'name': 'Ryan', 'friends': [1]} 3: {'name': 'John', 'friends': [1]}
Populating
Person({'name': 'Katie', 'friends': [2, 3]})
produces this dictionary:{'name': 'Katie', 'friends': [Person({'name': 'Ryan', 'friends': [1]}), Person({'name': 'John', 'friends': [1]}]})
Parameters: attribute (Optional[str]) – If given, return only the populated attribute. Returns: If attribute is None, a dictionary of controlled data merged with associated records. If attribute is not None, the value of the populated attribute. Raises: KeyError
– attribute is undefined in the record.
-
unset
(fields, keys)[source]¶ Unset recorded data fields and update associations.
- The behavior depends on the type of keys:
- Record.ElementIdentifier: update the record with that element identifier.
- dict: update all records with attributes matching keys.
- list or tuple: apply update to all records matching the elements of keys.
bool(keys) == False
: raise ValueError.
Invokes the on_update callback for each record after the records are updated.
Parameters: - fields (list) – Names of fields to unset.
- keys – Fields or element identifiers to match.
-
update
(data, keys)[source]¶ Change recorded data and update associations.
- The behavior depends on the type of keys:
- Record.ElementIdentifier: update the record with that element identifier.
- dict: update all records with attributes matching keys.
- list or tuple: apply update to all records matching the elements of keys.
bool(keys) == False
: raise ValueError.
Invokes the on_update callback for each record after the records are updated.
Parameters: - data (dict) – New data for existing records.
- keys – Fields or element identifiers to match.
-
tau.mvc.model module¶
TODO: FIXME: Docs
-
class
tau.mvc.model.
Model
(record)[source]¶ Bases:
tau.storage.StorageRecord
The “M” in MVC.
TODO: Docs
-
name
¶ str
Name of the model.
-
associations
¶ dict
(Controller, str) tuples keyed by attribute name defining attribute associations.
-
references
¶ set
(Controller, str) tuples listing foreign models referencing this model.
-
attributes
¶ dict
Model attributes.
-
key_attribute
¶ str
Name of an attribute that serves as a unique identifier.
-
associations
= NotImplemented
-
check_compatibility
(rhs)[source]¶ Test this record for compatibility with another record.
Operations combining data from multiple records must know that the records are mutually compatible. This routine checks the ‘compat’ property of each attribute (if set) to enforce compatibility. ‘compat’ is a dictionary where the keys are values or callables and the values are tuples of compatibility conditions. If the attribute with the ‘compat’ property is one of the key values then the conditions are checked. The general form of ‘compat’ is:
{ (value|callable): (condition, [condition, ...]), [(value|callable): (condition, [condition, ...]), ...] }
Use tuples to join multiple conditions. If only one condition is needed then you do not need to use a tuple.
‘value’ may either be a literal value (e.g. True or “oranges”) or a callable accepting one argument and returning either True or False. The attribute’s value is passed to the callable to determine if the listed conditions should be checked. If ‘value’ is a literal then the listed conditions are checked when the attribute’s value matches ‘value’.
See
require
,encourage
,discourage
,exclude
for common conditions.Parameters: rhs (Model) – Check compatibility with this data record. Raises: ConfigurationError
– The two records are not compatible.Examples
Suppose we have this data:
Programmer.attributes = { 'hungry': { 'type': 'boolean', 'compat': {True: (CheeseShop.require('have_cheese', True), CheeseShop.encourage('chedder', 'Wisconsin'), ProgramManager.discourage('holding_long_meeting', True), Roommate.exclude('steals_food', True)} } } bob = Programmer({'hungry': True}) world_o_cheese = CheeseShop({'have_cheese': False, 'chedder': 'Wisconsin'}) cheese_wizzard = CheeseShop({'have_cheese': True, 'chedder': 'California'}) louis = ProgramManager({'holding_long_meeting': True}) keith = Roommate({'steals_food': True})
These expressions raise
ConfigurationError
:bob.check_compatibility(world_o_cheese) # Because have_cheese == False bob.check_compatibility(keith) # Because steals_food == True
These expressions generate warning messages:
bob.check_compatibility(cheese_wizzard) # Because chedder != Wisconsin bob.check_compatibility(louis) # Because holding_long_meeting == True
If
bob['hungry'] == False
or if the ‘hungry’ attribute were not set then all the above expressions do nothing.
-
classmethod
construct_condition
(args, attr_defined=None, attr_undefined=None, attr_eq=None, attr_ne=None)[source]¶ Constructs a compatibility condition, see
check_compatibility
.- The returned condition is a callable that accepts five or six arguments:
lhs (Model): The left-hand side of the check_compatibility operation.
lhs_attr (str): Name of the attribute that defines the ‘compat’ property.
lhs_value: The value of the attribute that defines the ‘compat’ property.
rhs (Model): Controller of the data record we are checking against.
rhs_attr (str): The attribute we are checking for compatibility.
- checked_value (str): The required or desired value of the attribute we are checking for compatibility.
Only used by attr_eq and attr_ne.
The condition callable raises a
ConfigurationError
if the compared attributes are fatally incompatibile, i.e. the user’s operation is guaranteed to fail with the chosen records. It may emit log messages to indicate that the records are not perfectly compatible but that the user’s operation is still likely to succeed with the chosen records.See
require
,encourage
,discourage
,exclude
for common conditions.args[0] specifies a model attribute to check. If args[1] is given, it is a value to compare the specified attribute against or a callback function as described below. To enable complex conditions, args[1] may be a callback function. In this case, args[1] must check attribute existance and value correctness and throw the appropriate exception and/or emit log messages. See
tau.model.measurement.intel_only()
for an example of such a callback function.Parameters: - args (tuple) – Attribute name in args[0] and, optionally, attribute value in args[1].
- attr_defined – Callback function to be invoked when the attribute is defined.
- attr_undefined – Callback function to be invoked when the attribute is undefined.
- attr_eq – Callback function to be invoked when the attribute is equal to args[1].
- attr_ne – Callback function to be invoked when the attribute is not equal to args[1].
Returns: any:check_compatibility.
Return type: Callable condition object for use with
-
classmethod
discourage
(*args)[source]¶ Constructs a compatibility condition to make recommendations.
The condition will emit warnings messages if the specified attribute is defined or equal to the specified value (if given).
Parameters: *args – Corresponds to args in construct_condition
.Returns: any:check_compatibility Return type: Callable condition object for use with Examples
‘have_cheese’ should not be True:
CheeseShop.discourage('have_cheese', True)
‘have_cheese’ should not be set to any value:
CheeseShop.discourage('have_cheese')
The value of ‘have_cheese’ will be checked for correctness by ‘cheese_callback’:
CheeseShop.discourage('have_cheese', cheese_callback)
-
classmethod
encourage
(*args)[source]¶ Constructs a compatibility condition to make recommendations.
The condition will emit warnings messages if the specified attribute is undefined or not equal to the specified value (if given).
Parameters: *args – Corresponds to args in construct_condition
.Returns: any:check_compatibility Return type: Callable condition object for use with Examples
‘have_cheese’ should be True:
CheeseShop.encourage('have_cheese', True)
‘have_cheese’ should be set to any value:
CheeseShop.encourage('have_cheese')
The value of ‘have_cheese’ will be checked for correctness by ‘cheese_callback’:
CheeseShop.encourage('have_cheese', cheese_callback)
-
classmethod
exclude
(*args)[source]¶ Constructs a compatibility condition to enforce required conditions.
The condition will raise a
ConfigurationError
if the specified attribute is defined or equal to the specified value (if given).Parameters: *args – Corresponds to args in construct_condition
.Returns: any:check_compatibility Return type: Callable condition object for use with Examples
‘yellow_cheese’ must not be ‘American’:
CheeseShop.exclude('yellow_cheese', 'American')
‘blue_cheese’ must not be set to any value:
CheeseShop.exclude('blue_cheese')
The value of ‘have_cheese’ will be checked for correctness by ‘cheese_callback’:
CheeseShop.exclude('have_cheese', cheese_callback)
-
name
= NotImplemented
-
references
= NotImplemented
-
classmethod
require
(*args)[source]¶ Constructs a compatibility condition to enforce required conditions.
The condition will raise a
ConfigurationError
if the specified attribute is undefined or not equal to the specified value (if given).Parameters: *args – Corresponds to args in construct_condition
.Returns: any:check_compatibility Return type: Callable condition object for use with Examples
‘have_cheese’ must be True:
CheeseShop.require('have_cheese', True)
‘have_cheese’ must be set to any value:
CheeseShop.require('have_cheese')
The value of ‘have_cheese’ will be checked for correctness by ‘cheese_callback’:
CheeseShop.require('have_cheese', cheese_callback)
-


this
or an instance field of this
.
Locking a static field on instance data does not prevent the field from being modified by other instances, and thus may result in unexpected race conditions.
Example:
static String test;
public void foo() {
synchronized (this) {
System.out.println(test); // warning
}
}
There is a quick-fix that allows ignoring static fields of specific types. You can manage those ignored types in the inspection options.
Use the inspection options to specify which classes used for static fields should be ignored.


Classes
The following classes are available globally.
-
The
TelnyxRTC
client connects your application to the Telnyx backend, enabling you to make outgoing calls and handle incoming calls.Examples
Connect and login:
// Initialize the client let telnyxClient = TxClient() // Register to get SDK events telnyxClient.delegate = self // Setup yor connection parameters. // Set the login credentials and the ringtone/ringback configurations if required. // Ringtone / ringback tone files are not mandatory. // You can user your sipUser and password let txConfigUserAndPassowrd = TxConfig(sipUser: sipUser, password: password, ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", //You can choose the appropriate verbosity level of the SDK. //Logs are disabled by default logLevel: .all) // Use a JWT Telnyx Token to authenticate (recommended) let txConfigToken = TxConfig(token: "MY_JWT_TELNYX_TOKEN", ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", //You can choose the appropriate verbosity level of the SDK. Logs are disabled by default logLevel: .all) do { // Connect and login // Use `txConfigUserAndPassowrd` or `txConfigToken` try telnyxClient.connect(txConfig: txConfigToken) } catch let error { print("ViewController:: connect Error \(error)") } // You can call client.disconnect() when you're done. Note: you need to relese the delegate manually when you are done. // Disconnecting and Removing listeners. telnyxClient.disconnect(); // Release the delegate telnyxClient.delegate = nil
Listen TxClient delegate events.
See moreextension ViewController: TxClientDelegate { func onRemoteCallEnded(callId: UUID) { // Call has been removed internally. } func onSocketConnected() { // When the client has successfully connected to the Telnyx Backend. } func onSocketDisconnected() { // When the client from the Telnyx backend } func onClientError(error: Error) { // Something went wrong. } func onClientReady() { // You can start receiving incoming calls or // start making calls once the client was fully initialized. } func onSessionUpdated(sessionId: String) { // This function will be executed when a sessionId is received. } func onIncomingCall(call: Call) { // Someone is calling you. } // You can update your UI from here base on the call states. // Check that the callId is the same as your current call. func onCallStateUpdated(callState: CallState, callId: UUID) { DispatchQueue.main.async { switch (callState) { case .CONNECTING: break case .RINGING: break case .NEW: break case .ACTIVE: break case .DONE: break case .HELD: break } } } }
Declaration
Swift
public class TxClient
-
A Call is the representation of an audio or video call between two WebRTC Clients, SIP clients or phone numbers. The call object is created whenever a new call is initiated, either by you or the remote caller. You can access and act upon calls initiated by a remote caller by registering to TxClientDelegate of the TxClient
Examples:
Create a call:
// Create a client instance self.telnyxClient = TxClient() // Asign the delegate to get SDK events self.telnyxClient?.delegate = self // Connect the client (Check TxClient class for more info) self.telnyxClient?.connect(....) // Create the call and start calling self.currentCall = try self.telnyxClient?.newCall(callerName: "Caller name", callerNumber: "155531234567", // Destination is required and can be a phone number or SIP URI destinationNumber: "18004377950", callId: UUID.init())
Answer an incoming call:
See more//Init your client func initTelnyxClient() { // self.telnyxClient = TxClient() // Asign the delegate to get SDK events self.telnyxClient?.delegate = self // Connect the client (Check TxClient class for more info) self.telnyxClient?.connect(....) } extension ViewController: TxClientDelegate { //.... func onIncomingCall(call: Call) { //We are automatically answering any incoming call as an example, but //maybe you want to store a reference of the call, and answer the call after a button press. self.myCall = call.answer() } }
Declaration
Swift
public class Call


Hash Value:
Load
< Previous
Next >
Sample:
Number of Posts:
Number of Threads:
Snippet
PostWithClone
CreationDate
Owner
Score
LinkedPost
#Posts
ExternalLink
#Posts
Snippet licensed under
CC SY-SA 3.0
.


In order to interact with the user,s the program needs input and output statements.
For example take a calculator :
we give numbers and operations as input and it gives the result as an output,
In python we have those statements known as:
print() statements:
As the name suggests the print statements prints the output to the screen
, and so it is known as a output statement.
SYNTAX:
print(statement)
A syntax can be considered as a formula to write a speific statement.
Here, the syntax states that the keyword print()
statement refers to the statement or the expression to be printed
EXAMPLE:
-
print(30) # output => 30
-
print(3.32) # output => 3.32
-
print('code hub') # output => code hub
-
print('code hub', 1) # output => code hub 1
NOTE: comma(,) is use to seperate two different datatypes that is to be printed in a single
print() statement
input() statements:
So, in order to get the input from the user, you need a input statement
SYNTAX:
variable = input(prompt)
so the as the syntax says, anything that we type is observed
by the input statement and then it is stored in the varibale prompt.
Prompt is nothing but the statment that is printed
for the understanding of the user
for example :
consider the following code,
num = input()
in the output you just see the curser blinking but
you don't know what you should enter,
you may enter your name , age , something link that, to prevent those
confusion we can write the following code
print('enter a number : ')
num = input()
so now in the output screen you can see a statement that says to enter a number , so
now you know what you should enter BUT,
insted of writtin print() and then input() we can write like the following
num = input('enter a number')
so now the output screen shows the same output screen as the before statement but we
did the same thing in a single like
that single line is known as prompt , so anything within that '' inside the input()
will be printed for the user understanding..
EXAMPLE FOR BOTH INPUT AND PRINT STATEMENT:
-
name = input('enter your name :')
-
print('hello and welcome to code hub',name)
so the above code give the output as follows:
enter your name : sriram
hello and welcome to code hub sriram


Royal Mint unveils its largest ever coin
Just one of the exclusive coins has been made but it has already been sold for an undisclosed amount.
The Royal Mint has unveiled a new five-kilo coin — the largest it has ever minted.
Just one of the exclusive coins has been made but it has already been sold for an undisclosed amount. The coin has a denomination of £5,000.
It is part of a new “Great Engravers” series, that celebrates artists who have worked on British coinage.
The collection also includes a smaller, two-kilo coin, which will have a mintage of just four. The smaller coins will be sold for £119,950.
The series begins with Royal Academician William Wyon’s Una And The Lion design.
Wyon was the chief engraver at the Royal Mint from 1828 until his death in 1851 and was most famous for his coin and medal portraits of Queen Victoria.
He is also well-known for his design of Una And The Lion, considered by collectors as one of the world’s most beautiful coins.
A combination of traditional engraving methods and modern techniques were applied to produce the five-kilo coin. The original die used almost 200 years ago had to be digitally scanned and chief engraver Gordon Summers ensured the relief was accurately reproduced.
Modern techniques were then called upon with lasers being used to carefully cut the design onto the five-kilo coin. Finally, the piece was hand-polished to ensure the finish was elevated to the highest possible standard.
As part of the collection, a series of smaller and cheaper coins will also be available, with 2,980 two-ounce silver coins selling for £180.
Nicola Howell, director of the consumer division at The Royal Mint said, “The Great Engravers series celebrates some of the finest artists that have worked on British coinage and we are thrilled to start the series with William Wyon’s Una And The Lion design.
“This is arguably one of the most admired designs amongst coin collectors across the globe, and remastering it onto five and two-kilo coins allows you to truly appreciate the detail of the design.”


Create your App with Waziup
Waziup allows you to develop and host you own IoT applications. The WaziApp is an HTML5 application and will be hosted directly on Github. Only a few steps are necessary to get your application running with Waziup!
Fork the template WaziApp
The first step is to create an account on GitHub. For this go to www.github.com and click on “Sign Up”. Then, open the template WaziApp: https://github.com/Waziup/WaziApps-examples. Click on the button “Fork” in the top right corner.
You can fork the app in your own Github account. This operation will duplicate the “WaziApps-examples” in your account.
Once this is done, go in the newly created application and click on “Settings”. Scroll down to “Github pages” and select “Master branch” in the sources, and click on “Save”.
Your application is ready! You can view it on: https://your_account.github.io/WaziApps-examples/. This is the default application. Now is time to update it!
Modify your WaziApp
The application can be modified directly on Github. For that, click on the file you want to modify and click on the small pen on the right. Once the modifications done, click on the “commit” button at the bottom of the page. For heavy modifications, it is better to first clone the application on your own PC. You need to install git first. Then issue the command :
git clone git@github.com:<your_account>/WaziApps-examples.git
This will clone your new app on your computer. You can then freely modify your applications. When ready, you can upload it:
git add <your_modified_files>
git commit -m “my modifications”
git push
After the push is complete, your application is updated! You can already view it on the URL : https://your_account.github.io/WaziApp-examples/.
Have fun with Waziup.


Fill out the fields below and we'll tell you your perfect match.
 Try better music.


Marksman Carver:
Enough!
Only those who have that confidence shall pass through this place!
See information on permanent residence and tax rates.
Quest.


Add employee information and generate labor contracts based on employment terms added
Register labor terms changes, PTO and bonuses by entering the basic inputs. The system will generate respective HR paperwork automatically.
Get payroll immediately based on HR records. Forget about spreadsheets!
Pay the salary using payment documents automatically generated on top of payslips. Print or make the payments online - using the corresponding XML files.
Get the income tax return, which is generated automatically by the system in parallel with payslips.
Integrate bookkeeping formulations of the payroll with the rest of bookkeeping records by importing them into AS Accountant 7.
Add employee information and generate labor contracts based on employment terms added.
Register labor terms changes, PTO and bonuses by entering the basic inputs. The system will generate respective HR paperwork automatically.
Get payroll immediately based on HR records. Forget about spreadsheets!
Pay the salary using payment documents automatically generated on top of payslips. Print or make the payments online - using the corresponding XML files.
Get the income tax return, which is generated automatically by the system in parallel with payslips.
Integrate bookkeeping formulations of the payroll with the rest of bookkeeping records by importing them into AS Accountant 7.
There is no need to make redundant records in different spreadsheets and systems. Payroll and HR Paperwork is generated in the single platform based on the same data.
The system is up and running immediately upon signing up. No need to waste time installing any SW or setting up security keys.
The system is straightforward, easy to learn and fun to use. No need to waste your time on boring training sessions.
Available from anywhere. All you need is just a device connected to the Internet - your data and the system is kept in the safe cloud environment.
Pay only a monthly subscription which depends on the number of employees in your team. No other fees required.
When onboarding, an employee user specifies the personal information, working schedule and the salary. The system will generate labor contracts and employee will be included in the payroll list.
System automatically calculates sick and maternity leaves. User just needs to specify start and end dates of a leave.
Changes of the legislation and regulations are automatically reflected in the system.
Payroll generation is fully automated. You just need to verify that all necessary HR records are made.
System calculates the overtime and night work pay based on the start and end hours such work.
Payment documents are generated according to the payment method preferred by the employee. Payment documents can be printed and imported into AS Accountant 7.
You just need to set start and end date of vacation to generate vacation paperwork and calculate vacation pay. The system automatically calculates the number of available vacation days.
Generate labor contracts and amendments, orders, applications and certificates and maintain the history of generated documents.
Import employee data from a spreadsheet


{% extends "base.html" %} {% block content %}
Enter your identity details and click on "Vote" button to support your candidate
An error occurred during the process. Your vote will not be added to the next block. Error details are attached below:
You successfully completed your vote. It will be added to the next block.


| DOSE: |
10 mg |
|
2C-P |
(pill / tablet) |
I took a pressed 2C-P pill that was 10mg at around 10:50 PM. After about 1 hour I started to feel strange but wasn't really tripping yet everything just got a little brighter and I was thinking about odd things I don't usually think about. About 3 hours after injecting I started to really trip.
Its a weird experience.. I cant sleep for 12+ hrs. Every time I layed down I was thinking about stuff then 2c-p would force its way into my head ..I kinda felt like I was talking to the actual 2c-p chemical in my head. out of body experience I think. I was saying stuff like get out of my head dude Iím not using you just to get high.I just had this feeling the 2c-p was angry at me for using this chemical for a high.
I was just tripping balls. It was like whatever I started to think about when my eyes were closed, it would show up as a movie in my head. I remember thinking about a bunch of girls sitting in a circle having a conversation, and since I happen to like Spanish girls I was able to design a perfect Spanish girl and talk to her with my real time thinking. It was like I was really talking to people while my eyes were closed. It was just crazy!
 I heard a noise like 'ZZZZZZZZZUUUUURRRRRRZZZZ' and opened my eyes instantly. That kind of scared me and was pretty odd. And at one point I was on-line and posted a thread at what I thought was 2:30 in the morning. But the next day I looked at the time I posted it and it said 11:30 PM.
Colors are bright. I cant even explain the visuals..  Thats pretty much all I can remember.. overall I liked this drug in a weird way. It was a odd experience not in a bad way but not in a good way. I respect this chemical!
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


PostIt
menu
Product
Support
My Account
Product
Support
My Account
Reset Password
Enter your email address and we will send you a password reset link
Email
Send Password Reset Email


Mining calculator
You can use the mining calculator to estimate how many MRT you can earn on average. You only need to know how fast your computer is able to mine. To find out, let it mine for at least 15 minutes, then you can see average number of cycles per second your PC is able to find. In the Desktop Lightwallet you can find cycles per second under the Mining tab in the section called "Mining Rates" and noted as "Cycles Found/s".
In Merit Core you will need to use command "getmininginfo" in the console and find the "cyclesps" value. Average computer CPUs have numbers around 0.01 - 0.1. Gaming graphic cards can get around 0.2 - 0.5 each. If you have trouble finding your speed, don't hesitate to ask the community in Discord, Telegram, or forum.
Result:
If current net cycles/s are the same for the next 24 hours, and you mine without interruption at {{formData.controls.cyclesps.value}} cycles/s, your rewards will be approximately: {{dailyReward}} MRT
Why did I get lower rewards than calculated?
Keep in mind that this is an estimate and that it is entirely possible to mine fewer MRT than predicted by the mining calculator. Calculations are based on comparing your cycles/s with average of global cycles/s in last 30 blocks. There are many reasons why you might not get as many MRT per day as estimated:
You're not mining continuously
This is probably the main cause with fewer rewards than predicted. The mining pools are not 100% stable and have occasional blackouts during the day. As a result, you are not actually mining continuously for 24 hours. It is also possible that your miner dropped the pool connection and fail to reconnect. You then need to restart it manually - until it's restarted you're also losing time mining.
You're not mining continuously with the same cycles/s
Check your cycles/s a couple times before you get enter a number into the mining calculator. It's possible that one or more cards stopped mining and the number of cycles calculated decreased. Merit mining software is in development and is not fully optimized yet. So you may need to pay attention to your mining rigs in order to achieve optimal results.
Net cycles/s changed
During mining, global cycles/s can change by couple of %. It shouldn't be very significant, but it's possible that these fluctuations will cause lower or higher results by up to 30%. Normally, you shouldn't see fluctuations outside of 10% in 24 hours. You can always see current cycles/s on Network subpage.


Ideal Blog
Login
Sign up
Home
About
Contact
{{addButton}}
You are logged in as
{{users.user}}
{{post.title}}
Posted by
{{post.username}}
| {{post.date}}
{{post.shortDescription}}
Read More
{{t.text}}
«
{{$index+1}}
»


Hello {{username}},
Follow this link to finish registration and verify your account:
{{verification_link}}


PROJECT A II A film review by Thomas E. Billings Copyright 1989 Thomas E. Billings
Screened at the San Francisco International Film Festival (March 15, 1989).
Synopsis: In turn-of-the-century Hong Kong, an honest policeman does battle with corrupt police, gangsters, pirates, and spies. An action/comedy that moves at warp speed, with spectacular stunts and slapstick humor. Features Hong Kong superstar Jackie Chan.
Hong Kong (Cantonese with English subtitles), 1987, color, 101 minutes.
Director: Jackie Chan Producer: Leonard Ho Screenplay: Jackie Chan, Edward Tang Principal cast: Jackie Chan, Maggie Cheung, Carina Lau, David Lam Print Source: Golden Harvest Ltd.
Producer, writer, director, actor, stuntman, and occasionally a singer, Jackie Chan is the most popular star in Hong Kong, and one can easily see why from viewing this film. Here he plays Dragon Ma, an honest, diligent policeman in a corrupt, crime-infested district in Hong Kong at the turn of the century.
Dragon Ma battles against wholesale police corruption (the senior officer in his new district is on the take), gangsters who run brothels and opium dens, dispossessed pirates (leftovers from the 1984 film, PROJECT A), spies, and even a few revolutionaries. The action is fast and furious -- don't blink, you might miss something!
The basic plot is that Dragon Ma takes over a district from another officer (who is very crooked) and must clean up the police corruption and the gangsters. Along the way he is accidentally framed (for theft of a diamond bracelet) by revolutionaries who bungle a robbery attempt. Dragon must clear his name by unscrambling the mess and finding the missing jewels.
There's plenty of humor, both slapstick and more subtle types, along the way. He has a way of getting into trouble, which usually leads to furiously fast kung-fu fights, followed by wild chases with breathtaking stunts.  In fact, the kung-fu here is usually pretty funny!
The stunts are incredible. In this film, Jackie: runs across a single thin pole of bamboo (unsupported) that is stretched between two tall buildings, walks down the side of a building as it collapses, jumps on a very tall ladder that is leaning against one building, and pivots it in mid-flight so that it lands against the building next to it, slides down a six-story ladder, etc. One important point: Jackie does all of his own stunt work, no stunt doubles! In fact, the closing credits of the film show outtakes of the stunts, where you can see that he really does get hurt sometimes in doing the stunts!
Next to this, other action and adventure films are pretty tame. Caution: exposure to Jackie Chan films can be habit forming.  [Note: I have only one complaint about the movie. The action and dialogue go so fast, that it is hard to keep up with the subtitles! However, this does not prevent enjoyment of the film.]
Overall evaluation: excellent; definitely worth seeing.
Reviewer: Thomas E. Billings; Department of Statistics University of California, Berkeley Reviewer contact<EMAIL_ADDRESS>The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


About two years ago I promised a friend that I would handcraft a WordPress theme for him as a birthday present. And by that I meant building everything from the ground up - from designing the GUI to implementing the back-end - and relying on libraries & frameworks as little as possible. Theoretically there is nothing wrong with such a beautiful plan that demonstrates the principle of self-reliance and opens up one’s mind to learn that practically that was the dumbest thing to do. Especially true for someone who often overestimates what she or he is capable of.
Eventually I did not feel like working on this project anymore and had it shelved. However, the promise remained a kind of parasite that lived in my mind and grew over time, as I became more conscious about its existence.
● ● ●
Back when I was working on The HacKIDemia Event Site I bought some icons and stuff on Creative Market. Some promotion was going on, and there was this bundle to grab. Later I learnt that there are some really sweet WordPress themes in it. Dicot by DesignOrbital is one of them.
Sadly I don’t have a use case for it. I wanted to give it to the friend I made the promise with, but as a designer and a developer, that just doesn’t feel right. So I decided to use it to bootstrap the old project of mine and see if I can have something for my friend’s birthday this year.
Yesterday was the day, and I barely made it.
At some point when I was so close to having a presentable website, I thought that I should rewrite everything, and get rid of all the unnecessary pieces (I don’t use more than 90% of its code) so that I can open-source it without getting into legal issue.
Most of the necessary parts were already written in the prototype before I shelved the project. Here is one of the functions that have the most use-cases. It is for extracting some content from a post based on its formats (assuming that they can be generalized into either non-gallery or gallery).
For anyone who is curious, this is how the prototype looks like.
The design of the prototype was done one and a half year ago. At that time I was still pretty immature (as you can see from the style of it). I have learnt a lot since then.
Needless to say, some of the changes I made for the final design are inspired by elements in Dicot's. And I did borrow some DOM objects & CSS from it. (I got the license anyway.)
p.s. The typography used in the logo was an imitation of that used in the cover of Le Petit Prince, designed by Antoine de Saint-Exupéry.
Rewriting everything was an impractical idea, considering that I am not entirely familiar with WordPress’ APIs, and right now I need to be more productivity-focus and “result-oriented”, or I would seldom get things done. (That was how things had been and I’d like a change.) It’d be neat to have danceprince.com open-source, but I have to prioritize things well.
At the moment I’m still going through textbooks & papers and working on the upcoming article, 0a explains: Logic. I figured I should resume DailyLog of Arch’s since things are going on in my life as usual, and it appears I’m just using working on an article as an excuse to take a break from logging.


Back
Document ready to send
| Subject | Document type | Name | |
|---|---|---|---|
| Post 16 | Business case | businesscase2018.xls | Remove |


Gold Restaurant
Current Reservations and Waiting List
View Waitlist
Name
Number Of Guests
1
2
3
4
5
Email
Submit


Muhammad Ali
The man who inspired an entire generation.
Ranking the 4 Best Fights of Muhammad Ali's Career
"The Greatest" wasn't just a nickname for Muhammad Ali.
The Louisville, Kentucky, native took his gold medal from the 1960 Summer Olympics and embarked on a pro career that yielded 61 fights, 56 victories and three reigns as the world's top heavyweight.
So while compiling a list of his 10 best fights may be a challenge, it's not from a lack of material.
We took a stab at it while considering not only the singular quality of Ali's performances but the significance of the events both individually and in the context of his overall resume.
Take a look at our picks and our rationale on the following slides, and feel free to drop in with your own ideas in the comments section.
Rest easy, champion.
4. Joe Frazier (L UD 15, March 8, 1971)
It's not often a loss would make a 10-best list.
But it's not often a loss comes with the circumstances of Ali-Frazier I.
Taking into account that he'd fought fewer than 18 full rounds in the previous three-plus years, it's amazing enough that Ali lasted a full 15 with a prime and ferocious version of Smokin' Joe.
And even though Frazier dropped him with a hellacious left hand in the final round, Ali rose and took his medicine in the form of a unanimous-decision defeat that was the first of his career.
Other fights have passed it in terms of revenue and viewership, but this one still reigns as the pinnacle moment of the heavyweight division.
3. Sonny Liston (TKO 7, Feb. 25, 1964)
It's not often a loss would make a 10-The legend had to begin somewhere, right?
But it's not often a loss comes with the circumstances of Ali-Frazier I.
In this case, it was when a brash, unproven 22-year-old kid stepped into the ring against a veteran slugger who'd won and defended the heavyweight title with consecutive one-round KOs of his predecessor.
It was little wonder, then, that Sonny Liston was a prohibitive favorite.
But after 18 minutes of ring action, the sport would never be the same.
Ali, in his last fight as Cassius Clay, confounded the slower Liston with improbably fast hands and feet and ultimately prompted his surrender—reportedly due to a balky shoulder—before Round 7.
2. Joe Frazier (TKO 14, Oct. 1, 1975)
Neither Ali nor Frazier was in 1975 what he had been four years earlier.
The Thrilla in Manila was a back-and-forth battle for the early going before Ali pulled away in the later stages and eventually forced Frazier's chief second, Eddie Futch, to surrender before Round 15.
But even in a win, he referred to it as the closest thing to death he'd ever experienced.
1. George Foreman (KO 8, Oct. 30, 1974)
For a guy who made a career of improbable wins, none exceeded the Rumble in the Jungle.
A decade after toppling Liston, a 32-year-old version of Ali met the next big thing—a 25-year-old George Foreman, who was 37-0 with 34 knockouts and two-round stoppages of both Frazier and Ken Norton, the only two men who'd beaten the challenger.
But rather than meeting disaster, Ali provided drama.
He displayed his brilliance in the unlikely form of rope-a-dope passivity, then gradually took the offensive initiative as his wide-swinging challenger was reduced to performing on fumes.
And by the time Round 8 neared a close, Foreman was stumbling to the canvas and providing an image that'll live on long after anyone who saw it in real time is gone.
Float like a butterfly, sting like a bee.
Muhammad Ali


Use the pointer-events CSS property to allow a PixiJS custom mouse to appear over a regular HTML element.


You configure SNMP contact and trap receiver settings to allow events to be reported to an SNMP entity in the Configure > System Settings > SNMP Basic page.Traps are messages sent by an SNMP entity that indicate the occurrence of an event. The default system configuration does not include SNMP traps.Version 1 Version 2c SNMP Version 3, which provides authentication through the User-based Security Model (USM). View-Based Access Control Mechanism (VACM), which provides richer access control. SNMP Version 3 authentication using AES 128 and DES encryption privacy. You set the default community string on the SNMP Basic page. To set more than one SNMP community string, see the Riverbed Knowledge Base article Can I Have More Than One SNMP Community String?
https://supportkb.riverbed.com/support/index?page=content&id=S16345
Read-Only Community String Specify a password-like string to identify the read-only community: for example, public. This community string overrides any VACM settings.
3. Click Apply to apply your changes to the running configuration.
4. Click Save to save your settings permanently.
(Appears only when you select v3). Optionally, select either Supply a Password or Supply a Key to use while authenticating users.MD5 - Specifies the Message-Digest 5 algorithm, a widely used cryptographic hash function with a 128-bit hash value. This is the default value. SHA - Specifies the Secure Hash Algorithm, a set of related cryptographic hash functions. SHA is considered to be the successor to MD5. (Appears only when you select v3 and Supply a Password.) Specify a password. The password must have a minimum of eight characters. Confirm the password in the Password Confirm text box. (Appears only when you select v3.) Determines whether a single atomic message exchange is authenticated. Select one of these levels from the drop-down list:No Auth - Does not authenticate packets and does not use privacy. This is the default setting. Auth - Authenticates packets but does not use privacy. AuthPriv - Authenticates packets using AES 128 and DES to encrypt messages for privacy. (Appears only when you select v3 and AuthPriv.) Select either the AES or DES protocol from the drop-down list. AES uses the AES128 algorithm. (Appears only when you select v3 and AuthPriv.) Select Same as Authentication Key, Supply a Password, or Supply a Key to use while authenticating users. The default setting is Same as Authentication Key. (Appears only when you select v3 and Supply a Password.) Specify a password. The password must have a minimum of eight characters. Confirm the password in the Privacy Password Confirm text box. (Appears only when you select v3 and Authentication as Supply a Key.) Specify a unique authentication key. The key is either a 32-hexadecimal digit MD5 or a 40-hexadecimal digit SHA digest created using md5sum or sha1sum. (Appears only when you select v3 and Privacy as Supply a Key.) Specify the privacy authentication key. The key is either a 32-hexadecimal digit MD5 or a 40-hexadecimal digit SHA digest created using md5sum or sha1sum. For v1 or v2 trap receivers, specify the SNMP community name; for example, public or private v3 trap receivers need a remote user with an authentication protocol, a password, and a security level. Select the check box next to the name and click Remove Selected.
2. Click Save to save your settings permanently.
2.


Domain
Messages
Reported Messages
Live Update
Total Reported Messages:
Message Id
Date Range
Statistics
Chart View
Grid View
Compact
Full
Filter By
By Year
By Month
By Date
By Hour
By Minutes


{{username}} invited {{number_of_invited}} more people. {{#if invited}} {{#each invited_friends}} {{username}} {{/each}} {{/if}}


Check local requirements, restrictions and situations
Make paper copies of test results and screening documentation
Plan for long hours in masks: With layovers, long flights, and ground transportation, you may find you and
your family in a mask long hours. You want to pack extra masks!
Pack Snacks! Some airport restaurants are not fully open or close early. Check desired location's guidance
and restrictions.


If you’d like to give a talk please get in touch by email or tweet.
We’re actively seeking speakers on related technologies such as Angular, React, Elm, Vue, and on the future of the web platform. Please get in touch if you’re interested in talking on those topics.