Introduction
Generative art represents the involvement of a human-independent system (such as an algorithm) in a creative process. Such a system is a key element within the creative process, including its outputs.
Unsurprisingly, there are many “tools” you can use if you want to delve into generative art. In case you want to have “hands-on” experience in R, there are two basic directions you can go.
If you are a person proficient working with code, you may write your code straight away. I dare to argue that this is the way of the “individual” expression as it allows for more flexibility, and, well, freedom.
However, getting to that point takes time. Luckily, you can begin experimenting with your pieces of generative art by using one of the existing packages. Not only it could be quite rewarding, but it also works perfectly for grasping the basics of the “trade”.
In this article, I am going to present to you some of the “ready-to-use” packages for making generative art. Also, I will tap into some of the examples of using general packages or libraries to arrive at the same goal.
generativeart
The first package I would like to present is called simply generativeart
.
One of its key features is the way how it structures the output files. In order to get the output files, you have to specify the location where it will be stored. Also, it iterates on the provided formula that doesn’t need to be supported with a seed. In this scenario, each of the outcome files is unique.
Also, it is worth mentioning that the generativeart
package is well documented and easy to use.
library(generativeart) # devtools::install_github("cutterkom/generativeart")
library(ambient)
library(dplyr)
# set the paths
IMG_DIR <- "img/"
IMG_SUBDIR <- "everything/"
IMG_SUBDIR2 <- "handpicked/"
IMG_PATH <- paste0(IMG_DIR,
IMG_SUBDIR)
LOGFILE_DIR <- "logfile/"
LOGFILE <- "logfile.csv"
LOGFILE_PATH <- paste0(LOGFILE_DIR,
LOGFILE)
# create the directory structure
generativeart::setup_directories(IMG_DIR,
IMG_SUBDIR,
IMG_SUBDIR2,
LOGFILE_DIR)
# include a specific formula, for example:
my_formula <- list(
x = quote(runif(1, -1, 10) * x_i^2 - sin(y_i^2)),
y = quote(runif(1, -1, 10) * y_i^3 - cos(x_i^2) * y_i^4)
)
# call the main function to create five images with a polar coordinate system
generativeart::generate_img(formula = my_formula,
nr_of_img = 5, # set the number of iterations
polar = TRUE,
filetype = "png",
color = "#c1a06e",
background_color = "#1a3657")
jasmines
Danielle Navarro, the author of the Learning Statistics with R Learning Statistics with R handbook, is a well-known person among psychology students.
Besides her teaching and research activities at the University of Adelaide, she also released the jasmines package, a tool allowing for creating a generative art in R.
This package gives you an opportunity to play with simulation parameters (e.g. grain
or interaction
), shapes (e.g. entity_circle
or scene_discs
) and their modifications (like style_ribbon
) or colours (palette
or alpha
). And noise, linked to the ambient library.
library(dplyr) # or install.packages("dplyr") first
library(jasmines) # or devtools::install_github("djnavarro/jasmines")
p0 <- use_seed(100) %>% # Set the seed of R‘s random number generator, which is useful for creating simulations or random objects that can be reproduced.
scene_discs(
rings = 10,
points = 50000,
size = 50
) %>%
mutate(ind = 1:n()) %>%
unfold_warp(
iterations = 10,
scale = .5,
output = "layer"
) %>%
unfold_tempest(
iterations = 5,
scale = .01
) %>%
style_ribbon(
color = "#E0542E",
colour = "ind",
alpha = c(1,1),
background = "#4D7186"
)
ggsave("p0.png", p0, width = 20, height = 20, units = "in")
mathart + ggart
The mathart
package wraps many of commonly used algorithms into functions. One of such examples is the nearest neighbor graph, a visualisation of the k-d tree, a data structuring procedure of multidimensional space:
library(mathart) # devtools::install_github("marcusvolz/mathart")
library(ggart) # devtools::install_github("marcusvolz/ggart")
library(ggforce)
library(Rcpp)
library(tidyverse)
points <- mathart::points
result <- kdtree(points)
p1 <- ggplot() +
geom_segment(aes(x, y, xend = xend, yend = yend), result) +
coord_equal() +
xlim(0, 10000) + ylim(0, 10000) +
theme_blankcanvas(bg_col = "#fafafa", margin_cm = 0)
# save plot
ggsave("kdtree.png", p1, width = 20, height = 20, units = "in")
mathart
is a well-documented package. This fact widens the scope for experimenting. Maybe more importantly, by looking “under the hood”, the package improves understanding of data simulation.
General purpose packages
In many instances, previously mentioned packages built on more generally used packages such as magritr
(the pipeline operator comes handy even in the art creation), ggplot
, dplyr
, or purr
.
The k-d tree from the mathart
package is no different. As we can see from the example of Marcus Volz, the original k-d tree algorithm can be tweaked using even base R:
# Metropolis: Generative city visualisations
# Packages
library(ggart)
library(tidyverse)
library(tweenr)
library(viridis)
# Make reproducible
set.seed(10001)
# Parameters
n <- 10000 # iterations
r <- 75 # neighbourhood
width <- 10000 # canvas width
height <- 10000 # canvas height
delta <- 2 * pi / 180 # angle direction noise
p_branch <- 0.1 # probability of branching
initial_pts <- 3 # number of initial points
nframes <- 500 # number of tweenr frames
# Initialise data frames
points <- data.frame(x = numeric(n), y = numeric(n), dir = numeric(n), level = integer(n))
edges <- data.frame(x = numeric(n), y = numeric(n), xend = numeric(n), yend = numeric(n), level = integer(n))
if(initial_pts > 1) {
i <- 2
while(i <= initial_pts) {
points[i, ] <- c(runif(1, 0, width), runif(1, 0, height), runif(1, -2*pi, 2*pi), 1)
i <- i + 1
}
}
t0 <- Sys.time()
# Main loop ----
i <- initial_pts + 1
while (i <= n) {
valid <- FALSE
while (!valid) {
random_point <- sample_n(points[seq(1:(i-1)), ], 1) # Pick a point at random
branch <- ifelse(runif(1, 0, 1) <= p_branch, TRUE, FALSE)
alpha <- random_point$dir[1] + runif(1, -(delta), delta) + (branch * (ifelse(runif(1, 0, 1) < 0.5, -1, 1) * pi/2))
v <- c(cos(alpha), sin(alpha)) * r * (1 + 1 / ifelse(branch, random_point$level[1]+1, random_point$level[1])) # Create directional vector
xj <- random_point$x[1] + v[1]
yj <- random_point$y[1] + v[2]
lvl <- random_point$level[1]
lvl_new <- ifelse(branch, lvl+1, lvl)
if(xj < 0 | xj > width | yj < 0 | yj > height) {
next
}
points_dist <- points %>% mutate(d = sqrt((xj - x)^2 + (yj - y)^2))
if (min(points_dist$d) >= 1 * r) {
points[i, ] <- c(xj, yj, alpha, lvl_new)
edges[i, ] <- c(xj, yj, random_point$x[1], random_point$y[1], lvl_new)
# Add a building if possible
buiding <- 1
valid <- TRUE
}
}
i <- i + 1
print(i)
}
edges <- edges %>% filter(level > 0)
sand <- data.frame(alpha = numeric(0), x = numeric(0), y = numeric(0))
perp <- data.frame(x = numeric(0), y = numeric(0), xend = numeric(0), yend = numeric(0))
# Create plot
p2 <- ggplot() +
geom_segment(aes(x, y, xend = xend, yend = yend, size = -level), edges, lineend = "round") +
#geom_segment(aes(x, y, xend = xend, yend = yend), perp, lineend = "round", alpha = 0.15) +
#geom_point(aes(x, y), points) +
#geom_point(aes(x, y), sand, size = 0.05, alpha = 0.05, colour = "black") +
xlim(0, 10000) +
ylim(0, 10000) +
coord_equal() +
scale_size_continuous(range = c(0.5, 0.5)) +
#scale_color_viridis() +
theme_blankcanvas(bg_col = "#fafafa", margin_cm = 0)
# print plot
ggsave("plot007w.png", p2, width = 20, height = 20, units = "cm", dpi = 300)
You don’t need to stop here. Some time spent on playing with the code can easily end up by creating your distinct wall poster.
LS0tCnRpdGxlOiAiR2V0dGluZyBzdGFydGVkIHdpdGggZ2VuZXJhdGl2ZSBhcnQgaW4gUiIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgYWxsaWduOiByaWdodAogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lCiAgICBjc3M6IH4vRGVza3RvcC9HaXQvV2VicGFnZS9kYXRhbXVzdGZsb3cvcHVibGljL2Nzcy9jb2Rlci5taW4uYTRmMzMyMjEzYTIxY2U4ZWI1MjE2NzBjNjE0NDcwYzU4OTIzYWFhZjM4NWUyYTczOTgyYzMxZGQ3NjQyZGVjYi5jc3MKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgojIyBJbnRyb2R1Y3Rpb24KCkdlbmVyYXRpdmUgYXJ0IHJlcHJlc2VudHMgdGhlIGludm9sdmVtZW50IG9mIGEgaHVtYW4taW5kZXBlbmRlbnQgc3lzdGVtIChzdWNoIGFzIGFuIGFsZ29yaXRobSkgaW4gYSBjcmVhdGl2ZSBwcm9jZXNzLiBTdWNoIGEgc3lzdGVtIGlzIGEga2V5IGVsZW1lbnQgd2l0aGluIHRoZSBjcmVhdGl2ZSBwcm9jZXNzLCBpbmNsdWRpbmcgaXRzIG91dHB1dHMuIAoKVW5zdXJwcmlzaW5nbHksIHRoZXJlIGFyZSBtYW55ICJ0b29scyIgeW91IGNhbiB1c2UgaWYgeW91IHdhbnQgdG8gZGVsdmUgaW50byBnZW5lcmF0aXZlIGFydC4gSW4gY2FzZSB5b3Ugd2FudCB0byBoYXZlICoiaGFuZHMtb24iKiBleHBlcmllbmNlIGluIFIsIHRoZXJlIGFyZSB0d28gYmFzaWMgZGlyZWN0aW9ucyB5b3UgY2FuIGdvLgoKSWYgeW91IGFyZSBhIHBlcnNvbiBwcm9maWNpZW50IHdvcmtpbmcgd2l0aCBjb2RlLCB5b3UgbWF5IHdyaXRlIHlvdXIgY29kZSBzdHJhaWdodCBhd2F5LiBJIGRhcmUgdG8gYXJndWUgdGhhdCB0aGlzIGlzICoqdGhlIHdheSoqIG9mIHRoZSAq4oCcaW5kaXZpZHVhbOKAnSogZXhwcmVzc2lvbiBhcyBpdCBhbGxvd3MgZm9yIG1vcmUgZmxleGliaWxpdHksIGFuZCwgd2VsbCwgZnJlZWRvbS4KCkhvd2V2ZXIsIGdldHRpbmcgdG8gdGhhdCBwb2ludCB0YWtlcyB0aW1lLiBMdWNraWx5LCB5b3UgY2FuIGJlZ2luIGV4cGVyaW1lbnRpbmcgd2l0aCB5b3VyIHBpZWNlcyBvZiBnZW5lcmF0aXZlIGFydCBieSB1c2luZyBvbmUgb2YgdGhlIGV4aXN0aW5nIHBhY2thZ2VzLiBOb3Qgb25seSBpdCBjb3VsZCBiZSBxdWl0ZSByZXdhcmRpbmcsIGJ1dCBpdCBhbHNvIHdvcmtzIHBlcmZlY3RseSBmb3IgZ3Jhc3BpbmcgdGhlIGJhc2ljcyBvZiB0aGUgKiJ0cmFkZSIqLgoKSW4gdGhpcyBhcnRpY2xlLCBJIGFtIGdvaW5nIHRvIHByZXNlbnQgdG8geW91IHNvbWUgb2YgdGhlICoicmVhZHktdG8tdXNlIiogcGFja2FnZXMgZm9yIG1ha2luZyBnZW5lcmF0aXZlIGFydC4gQWxzbywgSSB3aWxsIHRhcCBpbnRvIHNvbWUgb2YgdGhlIGV4YW1wbGVzIG9mIHVzaW5nIGdlbmVyYWwgcGFja2FnZXMgb3IgbGlicmFyaWVzIHRvIGFycml2ZSBhdCB0aGUgc2FtZSBnb2FsLgoKIyMgZ2VuZXJhdGl2ZWFydAoKVGhlIGZpcnN0IHBhY2thZ2UgSSB3b3VsZCBsaWtlIHRvIHByZXNlbnQgaXMgY2FsbGVkIHNpbXBseSBgZ2VuZXJhdGl2ZWFydGAuCgpPbmUgb2YgaXRzIGtleSBmZWF0dXJlcyBpcyB0aGUgd2F5IGhvdyBpdCBzdHJ1Y3R1cmVzIHRoZSBvdXRwdXQgZmlsZXMuIEluIG9yZGVyIHRvIGdldCB0aGUgb3V0cHV0IGZpbGVzLCB5b3UgaGF2ZSB0byBzcGVjaWZ5IHRoZSBsb2NhdGlvbiB3aGVyZSBpdCB3aWxsIGJlIHN0b3JlZC4gQWxzbywgaXQgaXRlcmF0ZXMgb24gdGhlIHByb3ZpZGVkIGZvcm11bGEgdGhhdCBkb2Vzbid0IG5lZWQgdG8gYmUgc3VwcG9ydGVkIHdpdGggYSBzZWVkLiBJbiB0aGlzIHNjZW5hcmlvLCBlYWNoIG9mIHRoZSBvdXRjb21lIGZpbGVzIGlzIHVuaXF1ZS4gCgpBbHNvLCBpdCBpcyB3b3J0aCBtZW50aW9uaW5nIHRoYXQgdGhlIGBnZW5lcmF0aXZlYXJ0YCBwYWNrYWdlIGlzIHdlbGwgW2RvY3VtZW50ZWRdKGh0dHBzOi8vZ2l0aHViLmNvbS9jdXR0ZXJrb20vZ2VuZXJhdGl2ZWFydCkgYW5kIGVhc3kgdG8gdXNlLgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZSd9CgpsaWJyYXJ5KGdlbmVyYXRpdmVhcnQpICMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJjdXR0ZXJrb20vZ2VuZXJhdGl2ZWFydCIpCmxpYnJhcnkoYW1iaWVudCkKbGlicmFyeShkcGx5cikKCiMgc2V0IHRoZSBwYXRocwpJTUdfRElSIDwtICJpbWcvIgpJTUdfU1VCRElSIDwtICJldmVyeXRoaW5nLyIKSU1HX1NVQkRJUjIgPC0gImhhbmRwaWNrZWQvIgpJTUdfUEFUSCA8LSBwYXN0ZTAoSU1HX0RJUiwgCiAgICAgICAgICAgICAgICAgICBJTUdfU1VCRElSKQoKTE9HRklMRV9ESVIgPC0gImxvZ2ZpbGUvIgpMT0dGSUxFIDwtICJsb2dmaWxlLmNzdiIKTE9HRklMRV9QQVRIIDwtIHBhc3RlMChMT0dGSUxFX0RJUiwgCiAgICAgICAgICAgICAgICAgICAgICAgTE9HRklMRSkKCiMgY3JlYXRlIHRoZSBkaXJlY3Rvcnkgc3RydWN0dXJlCmdlbmVyYXRpdmVhcnQ6OnNldHVwX2RpcmVjdG9yaWVzKElNR19ESVIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBJTUdfU1VCRElSLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSU1HX1NVQkRJUjIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMT0dGSUxFX0RJUikKCiMgaW5jbHVkZSBhIHNwZWNpZmljIGZvcm11bGEsIGZvciBleGFtcGxlOgpteV9mb3JtdWxhIDwtIGxpc3QoCiAgeCA9IHF1b3RlKHJ1bmlmKDEsIC0xLCAxMCkgKiB4X2leMiAtIHNpbih5X2leMikpLAogIHkgPSBxdW90ZShydW5pZigxLCAtMSwgMTApICogeV9pXjMgLSBjb3MoeF9pXjIpICogeV9pXjQpCikKCiMgY2FsbCB0aGUgbWFpbiBmdW5jdGlvbiB0byBjcmVhdGUgZml2ZSBpbWFnZXMgd2l0aCBhIHBvbGFyIGNvb3JkaW5hdGUgc3lzdGVtCmdlbmVyYXRpdmVhcnQ6OmdlbmVyYXRlX2ltZyhmb3JtdWxhID0gbXlfZm9ybXVsYSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBucl9vZl9pbWcgPSA1LCAjIHNldCB0aGUgbnVtYmVyIG9mIGl0ZXJhdGlvbnMKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvbGFyID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxldHlwZSA9ICJwbmciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiNjMWEwNmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmRfY29sb3IgPSAiIzFhMzY1NyIpCmBgYAoKYGBge3IgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDYsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0V9CiMgYW4gZXhhbXBsZQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL2hvbWUvdml0Z2FicmhlbC9EZXNrdG9wL0dpdC9XZWJwYWdlL2RhdGFtdXN0Zmxvd19SL2ltZy9ldmVyeXRoaW5nLzIwMjAtMDYtMjEtMjEtMTVfc2VlZF84NDQ3LnBuZyIpCmBgYAoKCiMjIGphc21pbmVzCgpEYW5pZWxsZSBOYXZhcnJvLCB0aGUgYXV0aG9yIG9mIHRoZSBMZWFybmluZyBTdGF0aXN0aWNzIHdpdGggUiBbTGVhcm5pbmcgU3RhdGlzdGljcyB3aXRoIFJdKGh0dHBzOi8vbGVhcm5pbmdzdGF0aXN0aWNzd2l0aHIuY29tLykgaGFuZGJvb2ssIGlzIGEgd2VsbC1rbm93biBwZXJzb24gYW1vbmcgcHN5Y2hvbG9neSBzdHVkZW50cy4KCkJlc2lkZXMgaGVyIHRlYWNoaW5nIGFuZCByZXNlYXJjaCBhY3Rpdml0aWVzIGF0IHRoZSBVbml2ZXJzaXR5IG9mIEFkZWxhaWRlLCBzaGUgYWxzbyByZWxlYXNlZCB0aGUgW2phc21pbmVzXShodHRwczovL2dpdGh1Yi5jb20vZGpuYXZhcnJvL2phc21pbmVzKSBwYWNrYWdlLCBhIHRvb2wgYWxsb3dpbmcgZm9yIGNyZWF0aW5nIGEgZ2VuZXJhdGl2ZSBhcnQgaW4gUi4KClRoaXMgcGFja2FnZSBnaXZlcyB5b3UgYW4gb3Bwb3J0dW5pdHkgdG8gcGxheSB3aXRoIHNpbXVsYXRpb24gcGFyYW1ldGVycyAoZS5nLiBgZ3JhaW5gIG9yIGBpbnRlcmFjdGlvbmApLCBzaGFwZXMgKGUuZy4gYGVudGl0eV9jaXJjbGVgIG9yIGBzY2VuZV9kaXNjc2ApIGFuZCB0aGVpciBtb2RpZmljYXRpb25zIChsaWtlIGBzdHlsZV9yaWJib25gKSBvciBjb2xvdXJzIChgcGFsZXR0ZWAgb3IgYGFscGhhYCkuIEFuZCBub2lzZSwgbGlua2VkIHRvIHRoZSBbYW1iaWVudF0oaHR0cHM6Ly9naXRodWIuY29tL3Rob21hc3A4NS9hbWJpZW50KSBsaWJyYXJ5LgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZSd9CmxpYnJhcnkoZHBseXIpICMgb3IgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKSBmaXJzdApsaWJyYXJ5KGphc21pbmVzKSAjIG9yIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiZGpuYXZhcnJvL2phc21pbmVzIikKCnAwIDwtIHVzZV9zZWVkKDEwMCkgJT4lICMgU2V0IHRoZSBzZWVkIG9mIFLigJhzIHJhbmRvbSBudW1iZXIgZ2VuZXJhdG9yLCB3aGljaCBpcyB1c2VmdWwgZm9yIGNyZWF0aW5nIHNpbXVsYXRpb25zIG9yIHJhbmRvbSBvYmplY3RzIHRoYXQgY2FuIGJlIHJlcHJvZHVjZWQuCiAgc2NlbmVfZGlzY3MoCiAgICByaW5ncyA9IDEwLCAKICAgIHBvaW50cyA9IDUwMDAwLCAKICAgIHNpemUgPSA1MAogICkgJT4lCiAgbXV0YXRlKGluZCA9IDE6bigpKSAlPiUKICB1bmZvbGRfd2FycCgKICAgIGl0ZXJhdGlvbnMgPSAxMCwKICAgIHNjYWxlID0gLjUsIAogICAgb3V0cHV0ID0gImxheWVyIiAKICApICU+JQogIHVuZm9sZF90ZW1wZXN0KAogICAgaXRlcmF0aW9ucyA9IDUsCiAgICBzY2FsZSA9IC4wMQogICkgJT4lCiAgc3R5bGVfcmliYm9uKAogICAgY29sb3IgPSAiI0UwNTQyRSIsCiAgICBjb2xvdXIgPSAiaW5kIiwKICAgIGFscGhhID0gYygxLDEpLAogICAgYmFja2dyb3VuZCA9ICIjNEQ3MTg2IgogICkKCmdnc2F2ZSgicDAucG5nIiwgcDAsIHdpZHRoID0gMjAsIGhlaWdodCA9IDIwLCB1bml0cyA9ICJpbiIpCmBgYAoKYGBge3IgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDYsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0V9CiMgYW4gZXhhbXBsZQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL2hvbWUvdml0Z2FicmhlbC9EZXNrdG9wL0dpdC9XZWJwYWdlL2RhdGFtdXN0Zmxvd19SL3AwLnBuZyIpCmBgYAoKIyMgbWF0aGFydCArIGdnYXJ0CgpUaGUgYG1hdGhhcnRgIHBhY2thZ2Ugd3JhcHMgbWFueSBvZiBjb21tb25seSB1c2VkIGFsZ29yaXRobXMgaW50byBmdW5jdGlvbnMuIE9uZSBvZiBzdWNoIGV4YW1wbGVzIGlzIHRoZSBbbmVhcmVzdCBuZWlnaGJvciBncmFwaF0oaHR0cHM6Ly9naXRodWIuY29tL21hcmN1c3ZvbHovbWF0aGFydC9ibG9iL21hc3Rlci9SL2tfbmVhcmVzdF9uZWlnaGJvdXJfZ3JhcGguUiksIGEgdmlzdWFsaXNhdGlvbiBvZiB0aGUgW2stZCB0cmVlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9LLWRfdHJlZSksIGEgZGF0YSBzdHJ1Y3R1cmluZyBwcm9jZWR1cmUgb2YgbXVsdGlkaW1lbnNpb25hbCBzcGFjZTogIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZSd9CgpsaWJyYXJ5KG1hdGhhcnQpICMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJtYXJjdXN2b2x6L21hdGhhcnQiKQpsaWJyYXJ5KGdnYXJ0KSAjIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigibWFyY3Vzdm9sei9nZ2FydCIpCmxpYnJhcnkoZ2dmb3JjZSkKbGlicmFyeShSY3BwKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCnBvaW50cyA8LSBtYXRoYXJ0Ojpwb2ludHMKCnJlc3VsdCA8LSBrZHRyZWUocG9pbnRzKQoKcDEgPC0gZ2dwbG90KCkgKwogIGdlb21fc2VnbWVudChhZXMoeCwgeSwgeGVuZCA9IHhlbmQsIHllbmQgPSB5ZW5kKSwgcmVzdWx0KSArCiAgY29vcmRfZXF1YWwoKSArCiAgeGxpbSgwLCAxMDAwMCkgKyB5bGltKDAsIDEwMDAwKSArCiAgdGhlbWVfYmxhbmtjYW52YXMoYmdfY29sID0gIiNmYWZhZmEiLCBtYXJnaW5fY20gPSAwKQoKIyBzYXZlIHBsb3QKZ2dzYXZlKCJrZHRyZWUucG5nIiwgcDEsIHdpZHRoID0gMjAsIGhlaWdodCA9IDIwLCB1bml0cyA9ICJpbiIpCmBgYAoKYGBge3IgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDYsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0V9CiMgYW4gZXhhbXBsZQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL2hvbWUvdml0Z2FicmhlbC9EZXNrdG9wL0dpdC9XZWJwYWdlL2RhdGFtdXN0Zmxvd19SL2tkdHJlZS5wbmciKQpgYGAKCjxicj4KCmBtYXRoYXJ0YCBpcyBhIHdlbGwtZG9jdW1lbnRlZCBwYWNrYWdlLiBUaGlzIGZhY3Qgd2lkZW5zIHRoZSBzY29wZSBmb3IgZXhwZXJpbWVudGluZy4gTWF5YmUgbW9yZSBpbXBvcnRhbnRseSwgYnkgbG9va2luZyAqInVuZGVyIHRoZSBob29kIiosIHRoZSBwYWNrYWdlIGltcHJvdmVzIHVuZGVyc3RhbmRpbmcgb2YgZGF0YSBzaW11bGF0aW9uLgoKIyMgR2VuZXJhbCBwdXJwb3NlIHBhY2thZ2VzCgpJbiBtYW55IGluc3RhbmNlcywgcHJldmlvdXNseSBtZW50aW9uZWQgcGFja2FnZXMgYnVpbHQgb24gbW9yZSBnZW5lcmFsbHkgdXNlZCBwYWNrYWdlcyBzdWNoIGFzIGBtYWdyaXRyYCAodGhlIHBpcGVsaW5lIG9wZXJhdG9yIGNvbWVzIGhhbmR5IGV2ZW4gaW4gdGhlIGFydCBjcmVhdGlvbiksIGBnZ3Bsb3RgLCBgZHBseXJgLCBvciBgcHVycmAuCgpUaGUgKiprLWQgdHJlZSoqIGZyb20gdGhlIGBtYXRoYXJ0YCBwYWNrYWdlIGlzIG5vIGRpZmZlcmVudC4gQXMgd2UgY2FuIHNlZSBmcm9tIHRoZSBleGFtcGxlIG9mIFtNYXJjdXMgVm9sel0oaHR0cHM6Ly9naXRodWIuY29tL21hcmN1c3ZvbHovbWV0cm9wb2xpcy9ibG9iL21hc3Rlci9tZXRyb3BvbGlzLlIpLCB0aGUgb3JpZ2luYWwgay1kIHRyZWUgYWxnb3JpdGhtIGNhbiBiZSB0d2Vha2VkIHVzaW5nIGV2ZW4gYmFzZSBSOgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZSd9CiMgTWV0cm9wb2xpczogR2VuZXJhdGl2ZSBjaXR5IHZpc3VhbGlzYXRpb25zCgojIFBhY2thZ2VzCmxpYnJhcnkoZ2dhcnQpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHR3ZWVucikKbGlicmFyeSh2aXJpZGlzKQoKIyBNYWtlIHJlcHJvZHVjaWJsZQpzZXQuc2VlZCgxMDAwMSkKCiMgUGFyYW1ldGVycwpuIDwtIDEwMDAwICMgaXRlcmF0aW9ucwpyIDwtIDc1ICMgbmVpZ2hib3VyaG9vZAp3aWR0aCA8LSAxMDAwMCAjIGNhbnZhcyB3aWR0aApoZWlnaHQgPC0gMTAwMDAgIyBjYW52YXMgaGVpZ2h0CmRlbHRhIDwtIDIgKiBwaSAvIDE4MCAjIGFuZ2xlIGRpcmVjdGlvbiBub2lzZQpwX2JyYW5jaCA8LSAwLjEgIyBwcm9iYWJpbGl0eSBvZiBicmFuY2hpbmcKaW5pdGlhbF9wdHMgPC0gMyAjIG51bWJlciBvZiBpbml0aWFsIHBvaW50cwpuZnJhbWVzIDwtIDUwMCAjIG51bWJlciBvZiB0d2VlbnIgZnJhbWVzCgojIEluaXRpYWxpc2UgZGF0YSBmcmFtZXMKcG9pbnRzIDwtIGRhdGEuZnJhbWUoeCA9IG51bWVyaWMobiksIHkgPSBudW1lcmljKG4pLCBkaXIgPSBudW1lcmljKG4pLCBsZXZlbCA9IGludGVnZXIobikpCmVkZ2VzIDwtICBkYXRhLmZyYW1lKHggPSBudW1lcmljKG4pLCB5ID0gbnVtZXJpYyhuKSwgeGVuZCA9IG51bWVyaWMobiksIHllbmQgPSBudW1lcmljKG4pLCBsZXZlbCA9IGludGVnZXIobikpCgppZihpbml0aWFsX3B0cyA+IDEpIHsKICBpIDwtIDIKICB3aGlsZShpIDw9IGluaXRpYWxfcHRzKSB7CiAgICBwb2ludHNbaSwgXSA8LSBjKHJ1bmlmKDEsIDAsIHdpZHRoKSwgcnVuaWYoMSwgMCwgaGVpZ2h0KSwgcnVuaWYoMSwgLTIqcGksIDIqcGkpLCAxKQogICAgaSA8LSBpICsgMQogIH0KfQoKdDAgPC0gU3lzLnRpbWUoKQoKIyBNYWluIGxvb3AgLS0tLQppIDwtIGluaXRpYWxfcHRzICsgMQp3aGlsZSAoaSA8PSBuKSB7CiAgdmFsaWQgPC0gRkFMU0UKICB3aGlsZSAoIXZhbGlkKSB7CiAgICByYW5kb21fcG9pbnQgPC0gc2FtcGxlX24ocG9pbnRzW3NlcSgxOihpLTEpKSwgXSwgMSkgIyBQaWNrIGEgcG9pbnQgYXQgcmFuZG9tCiAgICBicmFuY2ggPC0gaWZlbHNlKHJ1bmlmKDEsIDAsIDEpIDw9IHBfYnJhbmNoLCBUUlVFLCBGQUxTRSkKICAgIGFscGhhIDwtIHJhbmRvbV9wb2ludCRkaXJbMV0gKyBydW5pZigxLCAtKGRlbHRhKSwgZGVsdGEpICsgKGJyYW5jaCAqIChpZmVsc2UocnVuaWYoMSwgMCwgMSkgPCAwLjUsIC0xLCAxKSAqIHBpLzIpKQogICAgdiA8LSBjKGNvcyhhbHBoYSksIHNpbihhbHBoYSkpICogciAqICgxICsgMSAvIGlmZWxzZShicmFuY2gsIHJhbmRvbV9wb2ludCRsZXZlbFsxXSsxLCByYW5kb21fcG9pbnQkbGV2ZWxbMV0pKSAjIENyZWF0ZSBkaXJlY3Rpb25hbCB2ZWN0b3IKICAgIHhqIDwtIHJhbmRvbV9wb2ludCR4WzFdICsgdlsxXQogICAgeWogPC0gcmFuZG9tX3BvaW50JHlbMV0gKyB2WzJdCiAgICBsdmwgPC0gcmFuZG9tX3BvaW50JGxldmVsWzFdCiAgICBsdmxfbmV3IDwtIGlmZWxzZShicmFuY2gsIGx2bCsxLCBsdmwpCiAgICBpZih4aiA8IDAgfCB4aiA+IHdpZHRoIHwgeWogPCAwIHwgeWogPiBoZWlnaHQpIHsKICAgICAgbmV4dAogICAgfQogICAgcG9pbnRzX2Rpc3QgPC0gcG9pbnRzICU+JSBtdXRhdGUoZCA9IHNxcnQoKHhqIC0geCleMiArICh5aiAtIHkpXjIpKQogICAgaWYgKG1pbihwb2ludHNfZGlzdCRkKSA+PSAxICogcikgewogICAgICBwb2ludHNbaSwgXSA8LSBjKHhqLCB5aiwgYWxwaGEsIGx2bF9uZXcpCiAgICAgIGVkZ2VzW2ksIF0gPC0gYyh4aiwgeWosIHJhbmRvbV9wb2ludCR4WzFdLCByYW5kb21fcG9pbnQkeVsxXSwgbHZsX25ldykKICAgICAgIyBBZGQgYSBidWlsZGluZyBpZiBwb3NzaWJsZQogICAgICBidWlkaW5nIDwtIDEKICAgICAgdmFsaWQgPC0gVFJVRQogICAgfQogIH0KICBpIDwtIGkgKyAxCiAgcHJpbnQoaSkKfQoKZWRnZXMgPC0gZWRnZXMgJT4lIGZpbHRlcihsZXZlbCA+IDApCgpzYW5kIDwtIGRhdGEuZnJhbWUoYWxwaGEgPSBudW1lcmljKDApLCB4ID0gbnVtZXJpYygwKSwgeSA9IG51bWVyaWMoMCkpCnBlcnAgPC0gZGF0YS5mcmFtZSh4ID0gbnVtZXJpYygwKSwgeSA9IG51bWVyaWMoMCksIHhlbmQgPSBudW1lcmljKDApLCB5ZW5kID0gbnVtZXJpYygwKSkKCiMgQ3JlYXRlIHBsb3QKcDIgPC0gZ2dwbG90KCkgKwogIGdlb21fc2VnbWVudChhZXMoeCwgeSwgeGVuZCA9IHhlbmQsIHllbmQgPSB5ZW5kLCBzaXplID0gLWxldmVsKSwgZWRnZXMsIGxpbmVlbmQgPSAicm91bmQiKSArCiAgI2dlb21fc2VnbWVudChhZXMoeCwgeSwgeGVuZCA9IHhlbmQsIHllbmQgPSB5ZW5kKSwgcGVycCwgbGluZWVuZCA9ICJyb3VuZCIsIGFscGhhID0gMC4xNSkgKwogICNnZW9tX3BvaW50KGFlcyh4LCB5KSwgcG9pbnRzKSArCiAgI2dlb21fcG9pbnQoYWVzKHgsIHkpLCBzYW5kLCBzaXplID0gMC4wNSwgYWxwaGEgPSAwLjA1LCBjb2xvdXIgPSAiYmxhY2siKSArCiAgeGxpbSgwLCAxMDAwMCkgKwogIHlsaW0oMCwgMTAwMDApICsKICBjb29yZF9lcXVhbCgpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDAuNSwgMC41KSkgKwogICNzY2FsZV9jb2xvcl92aXJpZGlzKCkgKwogIHRoZW1lX2JsYW5rY2FudmFzKGJnX2NvbCA9ICIjZmFmYWZhIiwgbWFyZ2luX2NtID0gMCkKCiMgcHJpbnQgcGxvdApnZ3NhdmUoInBsb3QwMDd3LnBuZyIsIHAyLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAyMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDApCmBgYAoKYGBge3IgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDYsIGZpZy5hbGlnbj0nY2VudGVyJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0V9CiMgYW4gZXhhbXBsZQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL2hvbWUvdml0Z2FicmhlbC9EZXNrdG9wL0dpdC9XZWJwYWdlL2RhdGFtdXN0Zmxvd19SL3Bsb3QwMDd3LnBuZyIpCmBgYAoKPGJyPgoKWW91IGRvbid0IG5lZWQgdG8gc3RvcCBoZXJlLiBTb21lIHRpbWUgc3BlbnQgb24gcGxheWluZyB3aXRoIHRoZSBjb2RlIGNhbiBlYXNpbHkgZW5kIHVwIGJ5IGNyZWF0aW5nIHlvdXIgZGlzdGluY3QgW3dhbGwgcG9zdGVyXShodHRwczovL3d3dy5yLWJsb2dnZXJzLmNvbS9nZW5lcmF0aXZlLWFydC1sZXQteW91ci1jb21wdXRlci1kZXNpZ24teW91LWEtcGFpbnRpbmcvKS4KCiMjIENsb3NpbmcgcmVtYXJrcwoKR2VuZXJhdGl2ZSBhcnQgZGVtb25zdHJhdGVzIHRoYXQgY29kZSBjYW4gYmUgYmVhdXRpZnVsLiBJZiB5b3UgYXJlIHN0aWxsIG5vdCBwZXJzdWFkZWQsIGdvIGFuZCBzZWUgbW9yZSBlbGFib3JhdGVkIHdvcmtzIGxpa2UgW3RoZXNlXShodHRwczovL3d3dy5kYXRhLWltYWdpbmlzdC5jb20vYXJ0KS4KCk5vdCBvbmx5IGNhbiBnZW5lcmF0aXZlIGFydCByZXN1bHQgaW4gc29tZXRoaW5nIGFzdG9uaXNoaW5nLCBidXQgaXQgYWxzbyBoZWxwcyB5b3UgdG8gdW5kZXJzdGFuZCB0aGUgY29kZSBpdHNlbGYuIEludGVyZXN0aW5nbHksIGdldHRpbmcgdG8gdGhlIGNvZGUgdW5kZXJseWluZyBnZW5lcmF0aXZlIGFydCBtYXkgbm90IGJlIGFzIGVhc3kgYXMgd2l0aCBvdGhlciBvcGVuLXNvdXJjZSBhcmVhcy4gU29tZSAqImdlbmVyYXRpdmUgYXJ0aXN0cyIqIGNvbmNsdWRlIG5vdCB0byBzaGFyZSB0aGUgY29kZSB1c2VkIGluIHRoZSBjcmVhdGl2ZSBwcm9jZXNzOgoKPiAqIkkgZG8gbm90IHNoYXJlIHRoZSBjb2RlIEkgdXNlIHRvIGNyZWF0ZSBteSBwaWVjZXMuIFRoZSBtYWluIHJlYXNvbiBmb3IgdGhpcyBpcyB0aGF0IEkgZG9u4oCZdCB0aGluayBpdCB3b3VsZCBiZSBiZW5lZmljaWFsIHRvIGFueW9uZS4gUGVvcGxlIGludGVyZXN0ZWQgaW4gZ2V0dGluZyBzdGFydGVkIHdpdGggZ2VuZXJhdGl2ZSBhcnQgd291bGQgYmVjb21lIHRvIGZvY3VzZWQgb24gbXkgaWRlYXMgaW5zdGVhZCBvZiBkZXZlbG9waW5nIHRoZWlyIG93bi4gS25vd2luZyB0aGUgYW5zd2VyIGlzIHRoZSBraWxsZXIgb2YgY3JlYXRpdml0eS4iKgoKPHAgc3R5bGU9InRleHQtYWxpZ246IHJpZ2h0OyI+VGhvbWFzIExpbiBQZWRlcnNlbiwgPGEgaHJlZj0iaHR0cHM6Ly93d3cuZGF0YS1pbWFnaW5pc3QuY29tL2FydCI+RGF0YSBJbWFnaW5pc3Q8L2E+PC9wPgoKPGJyPgpSZWdhcmRsZXNzIGlmIHdlIGFncmVlIG9yIG5vdCwgZ2VuZXJhdGl2ZSBhcnQgY29uZnJvbnRzIHVzIHdpdGggaWRlYXMgdGhhdCBhcmUgbm90IHRoYXQgY29tbW9uIGluIHRoZSB3b3JsZCBvZiBjb2RpbmcuCgpTbywgd2hhdCBhcmUgeW91ciBpZGVhcyBvbiB0aGUgbWF0dGVyPyBEbyB5b3UgaGF2ZSBhbnkgZmF2b3VyaXRlIGdlbmVyYXRpdmUgYXJ0aXN0cz8gT3IgbWF5YmUgeW91ciBwaWVjZXMgb2YgYXJ0IHlvdSB3b3VsZCBsaWtlIHRvIHNoYXJlPyBGZWVsIGZyZWUgdG8gZGlzY3VzcyBvbiBbKip0d2l0dGVyKipdKCkuCgombmJzcDsKJm5ic3A7CjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48Yj5HbyBiYWNrIHRvIDxhIGhyZWY9Ii9wb3N0Ij5CbG9nPC9iPjwvYT48L3A+Cgo=