Home..

Metal Music Principle Component Analysis

<!DOCTYPE html>

Metalmusic PCA

In this post, I will explain how I performed a small analysis on the characteristics of songs from albums in the Rolling Stone top 100 greatest metal albums of all times. I was inspired to do this after I followed this tutorial.

Loading libraries

As always with R, the needed libraries need to be loaded before functions of those libraries can be used:

# Load the necessary libraries
library(dplyr)
library(tidyverse)
library(ggplot2)
library(reshape2)
library(broom)
library(stringr)
library(ggrepel)
library(ggtext)
library(glue)
library(showtext)
library(patchwork)

Another thing to load in advance are the fonts needed to create the PCA plot:

# Load fonts
font_add_google("Acme", "acme")
font_add_google("Raleway", "raleway")
font_add_google("Cabin Condensed","cabin")
font_add_google("Barlow Condensed","barlow")
font_add_google("Stint Ultra Condensed","stint")
font_add_google("Poppins","poppins")
font_add_google("Pacifico","pacifico")
font_add_google("Oswald","oswald")

# Automatically use {showtext} for plots
showtext_auto()

Importing data

First, I imported the data from TSV files obtained from a dataset on data.world. These datasets contain data about the Rolling Stone top 100 best metal albums of all time. For each album, metadata such as the artist, name, release year, duration, genre, rating and more is included. For each of the songs on the album, information about the individual characteristics is included, such as BPM, popularity and various metrics about how the song sounds (energy, dance, loud, valence etc.).

# Read in album dataset
raw_albums <- read.delim("RS_metal_albums.txt")

# View results
head(raw_albums)
# Read in song dataset
raw_songs <- read.delim("RS_metal_songs.txt")

# View results
head(raw_songs)

Some of the headers in both datasets contained spaces, which are automatically replaced by a “.” by R. I replaced these with an underscore (“_“):

# Change column names of raw_albums
colnames(raw_albums)[4] <- "Release_Year"
colnames(raw_albums)[11] <- "Total_Seconds"
colnames(raw_albums)[13] <- "Sub_Metal_Genre"
colnames(raw_albums)[15] <- "Rolling_Stone_Rating"

# Change column names of raw_songs
colnames(raw_songs)[1] <- "Song_Index"
colnames(raw_songs)[4] <- "Track_No"

The dataset with the songs does not contain any data on the release year of the album, but the album dataset does. I needed to add a column to the songs dataset that shows the release year of the album on which each of the songs is. I did this by using the “AlbumID_Rank” column which corresponds between the 2 datasets. The method I used for this operation is from the dplyr package, and is called left_join. I first selected the relevant columns from raw_albums (AlbumID_Rank and Release_Year) and then joined it to raw_songs using the AlbumID_Rank column.

# Left join on AlbumID_Rank to add the Release_Year to raw_songs
songs_with_year <- raw_songs %>%
  left_join(raw_albums %>% select(AlbumID_Rank, Release_Year), by = "AlbumID_Rank")

# View result
head(songs_with_year)

This resulted in a new dataset (songs_with_year) with a column appended to the raw_songs dataset. This column contains the release year of the album on which the song is.

Another column that might come in useful is the Sub_Metal_Genre column of the raw_albums dataset; I also performed a left_join on this data:

# Left join on AlbumID_Rank to add the Sub_Metal_Genre to raw_songs
songs_with_year_genre <- songs_with_year %>%
  left_join(raw_albums %>% select(AlbumID_Rank, Sub_Metal_Genre), by = "AlbumID_Rank")

# View result
head(songs_with_year_genre)

To choose which variables are going to be included in the PCA, I wanted to check which variables correlate the most with each other. For this, I created a correlation matrix with the cor function for all numeric columns of the songs_with_year_genre dataset with the code below:

# Select only numeric columns
numeric_data <- songs_with_year_genre %>%
  select_if(is.numeric)

# Calculate correlation matrix
cor_matrix <- cor(numeric_data, use = "complete.obs")

To get a visual insight into the correlation, I created a simple heatmap of the correlation values with ggplot2:

# Convert correlation matrix to a long format for ggplot2
cor_data <- melt(cor_matrix)

# Plot heatmap
ggplot(cor_data, aes(Var1, Var2, fill = value)) +
  geom_tile(color = "white") + # White space between tiles
  scale_fill_gradient2(low = "blue", high = "red", mid = "white", # Heatmap color range
                       midpoint = 0, limit = c(-1, 1), space = "Lab", # Midpoint 0 and fill between -1 and 1
                       name = "Correlation") # Legend name

This heatmap does not look the best… There are no labels in the plot and the x-axis labels overlap. Let’s improve it:

# Plot heatmap, but pretty
ggplot(cor_data, aes(Var1, Var2, fill = value)) +
  geom_tile(color = "white") + # White space between tiles
  geom_text(aes(label = round(value, 2)), size = 2, color = "black") + # Add labels on tiles
  scale_fill_gradient2(low = "blue", high = "red", mid = "white",
                       midpoint = 0, limit = c(-1, 1), space = "Lab",
                       name = "Correlation") +
  theme_minimal() + # Set theme
  theme(text = element_text(size = 9),axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) + # Adjust axis labels
  labs(title = "Metalsongs Correlation Matrix Heatmap", # Plot title
       x = "Variables", # Axis title
       y = "Variables") # Axis title

Now, we can see that Song_index and AlbumID_Rank are highly correlated, which makes sense because the song index values were assigned based on the songs sorted based on the album ranking. In addition, Loud and Energy are highly correlated, which was also to be expected because loud songs are also very energetic most of the times. To reduce redundancy, I will only use one of these two categories: Energy for the PCA. 2 combinations that are highly negatively correlated are Acoustic and Loud and Acoustic and Energy. Again, this makes sense because within the metal genre, most acoustic songs are not loud and do not contain a lot of energy.

A bit more unexpected is the correlation between Release_Year and AlbumID_Rank (and Song_Index). This indicates that the year an album was released influences the position on the Rolling Stone top 100. Let’s see if I can further analyze this correlation during the PCA.

Selecting PCA data

To perform a PCA, I had to select the variables with numerical values of interest from the data. These included the ranking place of the album, but also information about the characteristics of each song and the year they were released. I also added Song and Artist because this will be usefull when labeling the different datapoints. To select the variables that are interesting for our PCA from the data, I used the code below:

# New data for PCA
PCA1_data<-songs_with_year_genre%>%
  select(
    # Interesting variables for PCA
    c(AlbumID_Rank,BPM,Dance,
      Loud,Valence,Acoustic,Popularity,
      Release_Year,Song,Artist)
  )%>%
  # Remove NA entries
  drop_na()

Performing the PCA

After these steps I was ready to perform the PCA, which I did using the prcomp function:

# Remove the non-numerical artist and song name data for the PCA
PCA1_rank <- PCA1_data%>%
  select(-Artist,-Song)%>%
  # Perform PCA 
  prcomp(scale=TRUE)

I used another package (broom) to view the results in the tidyverse syntax:

# View results in eigenvalues matrix
PCA1_rank%>%
  tidy(matrix = "eigenvalues")

As the tibble shows, PCA1 accounts for 26% of the overall variability, and PCA2 for 22%. I wanted to visualize how the different categories separate the data, before plotting the actual datapoints of each song.

Plotting variables

To see what variables account for the variability in the plot, I extracted the coordinates of the variables from the “rotation” matrix of the PCA1_var data:

# New dataframe for variables
PCA1_var<-PCA1_rank %>%
  # Extract variable coords
  tidy(matrix = "rotation") %>%
  # Format table long to wide
  pivot_wider(names_from = "PC", names_prefix = "PC", values_from = "value") %>%
  # Rename column with variable names
  rename(Variable=column)
  # Check tibble
  head(PCA1_var)

To actually plot the variables, I used the ggrepel library because this prevents errors when variable names overlap. I chose a different color for the AlbumID_Rank variable, because it is interesting to see how this variable is influenced by the others.

ggplot(data = PCA1_var, aes(PC1, PC2)) +
  # Add variable arrows with conditional color
  geom_segment(
    aes(color = ifelse(Variable == "AlbumID_Rank", "black", "red")),
    xend = 0, yend = 0,
    arrow = arrow(
      length = unit(0.03, "npc"),
      type = "closed",
      ends = "first"
    )
  ) +
  # Add variable names with conditional color
  geom_text_repel(
    aes(label = Variable, color = ifelse(Variable == "AlbumID_Rank", "black", "red")),
    hjust = 1, size = 3,
    min.segment.length = Inf,
    nudge_x = 0.01, nudge_y = 0.08
  ) +
  coord_fixed() +
  labs(
    # Add titles
    title = 'Plot of PCA Variables Top 100 Metal Albums',
    x = 'PC1',
    y = 'PC2',
    color = 'Variable'
  ) +
  scale_color_identity() +
  theme_minimal()

This plot of variables again shows that the AlbumID_Rank is mostly influenced by Release_Year, but also that Acoustic and Loud separate a lot of songs. With a larger plot in mind, I wanted to remove the information about the PC numbers, and make the plot look more visually appealing so it can be shown together with the PCA plot:

pretty_var_plot <- ggplot(data = PCA1_var, aes(PC1, PC2)) +
  # Add variable arrows with conditional color
  geom_segment(
    aes(color = ifelse(Variable == "AlbumID_Rank", "black", "#c93434")), # Black and red arrows
    xend = 0, yend = 0,
    arrow = arrow(
      length = unit(0.05, "npc"),
      type = "closed",
      ends = "first"
    ),
    linewidth = 0.9, # Wide lines
  ) +
  # Add variable names
  geom_text_repel(
    aes(label = Variable, color = ifelse(Variable == "AlbumID_Rank", "black", "#c93434")), # Black and red names
    hjust = 1, size = 3.5,
    min.segment.length = Inf,
    nudge_x = 0.01, nudge_y = 0.08
  ) +
  # Add dashed line for y axis
  annotate(
    geom = "segment", x = 0, xend = 0, y = -Inf, yend = Inf, col = "grey60", lty = "dashed",
    linewidth = 0.5
  ) +
  # Add dashed line for x axis
  annotate(
    geom = "segment", x = Inf, xend = -Inf, y = 0, yend = 0, col = "grey60", lty = "dashed",
    linewidth = 0.5
  ) +
  # Keep fixed aspect ratio
  coord_fixed() +
  # Maintain color identity and remove legend
  scale_color_identity() +
  guides(color = "none") +
  theme_minimal() +
  theme(
    panel.grid = element_blank(),
    # No axis labels
    axis.text.x = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank()
  )
pretty_var_plot

Plotting songs

To actually create a plot of all songs included in the first PCA, I used ggplot again. Of course I used red and black in the color palette, this is a metal data analysis after all :).

# Add rank data back to PCA calculated data
PCA1_indiv_rank<-PCA1_rank%>%
  augment(PCA1_data)

# Plot individuals
ggplot(
  # Based on calculated PCA data
  data=PCA1_indiv_rank,
  # Use PCA values and color based on release year
  aes(.fittedPC1, .fittedPC2,color=Release_Year))+
  geom_point()+
  # Add labels and color based on year
  labs(
    title = 'Plot of individual songs',
    subtitle = 'Color shows year of album release of songs',
    x='PC1 (26%)',
    y='PC2 (22%)',
    color='Release_Year'
  )+
  # Gradient with reds
  scale_color_gradient(low = "black", high = "red") +
  # Light theme
  theme_light()

The plot shows that PC1 is the principal component that is able to distinguish the songs the best based on the album release year.

Now, I wanted to try and make the plot contain more information and also look a bit prettier…

Optimizing the plot

The first bit of information I thought about adding to the plot was the song names. I started with trying to add all labels to the plot with the code below, but as was to be expected, it became a big mess:

# Check if song names are valid and handle special characters
PCA1_indiv_rank <- PCA1_indiv_rank %>%
  # Check that song is a character vector
  mutate(Song = as.character(Song)) %>%
  # Remove not accepted characters
  mutate(Song = iconv(Song, "UTF-8", "ASCII", sub = "")) %>%
  mutate(Song = gsub("[^[:alnum:] ]", "", Song))

# Plot the PCA with all song name labels, allowing overlaps
ggplot(PCA1_indiv_rank, aes(.fittedPC1, .fittedPC2, label = Song)) +
  geom_point(aes(color = Release_Year)) +  # Add points colored by release year
  geom_text(aes(label = Song), size = 3, vjust = -0.5, hjust = 0.5) +  # Add song labels directly (no overlap avoidance)
  # Add labels and color based on year
  labs(
    title = 'PCA of Songs',
    subtitle = 'Color shows year of album release',
    x = 'PC1',
    y = 'PC2',
    color = 'Release Year'
  ) +
  # Color gradient
  scale_color_gradient(low = "black", high = "red") +
  theme_minimal()

Based on this plot, I noticed two major problems. The first one being that labeling every single data point leads to overlaps and clutter. The second one being that some song names are unnecessary long due to them being remastered versions. I started with trying to fix the first problem.

Plotting again

Let’s see if reducing the amount of labels to only one for each album and shortening remastered song names made a difference in making the plot look better:

# Plot the PCA with non-overlapping labels for popular songs
ggplot(PCA1_indiv_rank, aes(.fittedPC1, .fittedPC2)) +
  geom_point(aes(color = Release_Year)) +  # Add points colored by release year
  geom_text_repel(
    data = subset(PCA1_indiv_rank, Popular == TRUE),  # Only label popular songs
    aes(label = Song),
    size = 3, # Text size
    box.padding = 0.35,  # Padding around the text box
    point.padding = 0.5,  # Space between the label and the point
    max.overlaps = Inf,  # Allow all labels to attempt to display
    segment.color = 'grey50',  # Line color
    segment.size = 0.5  # Line thickness
  ) +
  # Add labels and color based on year
  labs(
    title = 'PCA of Songs',
    subtitle = 'Color shows year of album release; labels for popular songs',
    x = 'PC1',
    y = 'PC2',
    color = 'Release Year'
  ) +
  # Colors and theme 
  scale_color_gradient(low = "black", high = "red") +
  theme_minimal()

Well, this still looks very chaotic… Maybe it’s better to manually select songs that have to be labelled in the graph. For this, I selected my personal favorites from the most popular metal songs.

# Manually specify the song names to be labeled
selected_songs <- c("Chop Suey","Breaking the Law","Master Of Puppets","Would","Nothing Else Matters","Blind","People  Shit","Transilvanian Hunger","Walk","Bat Country","Raining Blood","Killing In The Name")

# New dataset to include only the selected songs
popular_favorites <- popular_no_remaster %>%
  filter(Song %in% selected_songs)

# Add a flag for favorite songs in the original PCA dataset
PCA1_indiv_rank <- PCA1_indiv_rank %>%
  mutate(Favorite = ifelse(Song %in% popular_favorites$Song, TRUE, FALSE))

# Plot the PCA with repelled labels for popular songs
neat_pca <- ggplot(PCA1_indiv_rank, aes(.fittedPC1, .fittedPC2)) +
  geom_point(aes(color = Release_Year)) +  # Add points colored by release year
  geom_text_repel(
    data = subset(PCA1_indiv_rank, Favorite == TRUE),  # Only label favorite songs
    aes(label = Song),
    size = 3,
    nudge_x = -0.01,
    nudge_y = -0.01,
    box.padding = 0.4,  # Padding around the text box
    point.padding = 0,  # Space between the label and the point
    max.overlaps = Inf,  # Allow all labels to attempt to display
    segment.color = 'black',  # Line color
    segment.size = 0.6  # Line thickness
  ) +
  labs(
    title = 'PCA of Songs',
    subtitle = 'Color shows year of album release; labels for favorite songs',
    x = 'PC1',
    y = 'PC2',
    color = 'Release Year'
  ) +
  scale_color_gradient(low = "black", high = "red") +
  theme_minimal()
neat_pca

Creating the ideal plot

I already really liked this version of the plot, but I wanted to make it look more styled. In the code below, I played around with different looks for the datapoints, labelling mechanisms and fonts.

pretty_pca_plot1 <- ggplot(PCA1_indiv_rank, aes(.fittedPC1, .fittedPC2, color = Release_Year)) + # Map color to a variable
  geom_point(alpha=0.2,size = 2) +
  scale_color_gradient(low = "black", high = "red") +
  scale_x_continuous(limits = c(-5, 7)) + # Plot size x
  scale_y_continuous(limits = c(-7.8, 10))+ # Plot size y
  # Labels that can not overlap and are not on the datapoint
  geom_text_repel( 
    data = subset(PCA1_indiv_rank, Favorite == TRUE), # Only label favorite songs
    aes(label = paste(Song, "\n", Artist, sep = ""), fontface = "bold.italic"), # Song and artist label
    size = 2.8,  # Text size
    box.padding = 0.6,  # Increase padding around text boxes
    point.padding = 0.1,  # Padding between points and labels
    force = 20,  # Increase repulsion between labels
    force_pull = 0.1,  # Slight pull to the data points, ensuring alignment
    min.segment.length = 0.5,  # Avoid overly short segment lines
    max.overlaps = Inf,  # Ensure all labels are shown
    segment.color = 'black',  # Line color
    segment.size = 0.3  # Thinner segment lines
  )
# View
pretty_pca_plot1

I liked the styling of the points and labels here, but I wanted the axes to run through the middle of the data instead of being on the sides. I did this by creating some arrow styles and adding them manually:

arrow_style <- arrow(
  angle = 20, ends = "first", type = "closed", length = grid::unit(4, "pt")
)

arrow_style_ind <- arrow(
  angle = 45, 
  length = grid::unit(8, "pt")
)

pretty_pca_plot2 <- pretty_pca_plot1 +
  # x-axis line
  annotate(
    geom = "segment", x = -5, xend = 6, y = 0, yend = 0,
    lty = "dashed",
    col = "grey60",
    size = 0.5
  ) +
  # x-axis arrow
  annotate(
    geom = "segment", x = 5.9, xend = 6, y = 0, yend = 0,
    col = "grey60",
    size = 0.5, arrow = arrow_style_ind, lineend = 'round', linejoin = 'round'
  ) +
  # x-axis label
  annotate(
    geom = "text", x = 4.7, y = 0.25, label = "Principal Component 1 (26%)",
    col = "dimgrey", size = 3, family = "sans", fontface = "italic"
  ) +
  # y-axis label
  annotate(
    geom = "text", x = -0.1, y = -7.7, label = "Principal Component 2 (22%)",
    col = "dimgrey", size = 3, family = "sans", angle = 90, vjust = 0, hjust = 0, fontface = "italic"
  ) +
  # y-axis
  annotate(
    geom = "segment", x = 0, xend = 0, y = -7.8, yend = 5, col = "grey60", lty = "dashed",
    size = 0.5
  ) +
  # y-axis arrow
  annotate(
    geom = "segment", x = 0, xend = 0, y = 4.9, yend = 5, col = "grey60",
    size = 0.5, arrow = arrow_style_ind, lineend = 'round', linejoin = 'round'
  )
pretty_pca_plot2

Now, there are too many axes and the background does not fit the style anymore. I fixed it like this:

pretty_pca_plot3 <- pretty_pca_plot2 +
  # Set minimal theme
  theme_minimal() +
  theme(
    panel.grid = element_blank(), # No grid
    # No axis labels
    axis.text.x = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    axis.text.y = element_blank(),
  )
pretty_pca_plot3

This plot now really misses some additional information, such as what type of data we are looking at, what kind of analysis was performed and the data source. I also incorporated the legend into the subtitle.

# Create title object
maintitle<-cbind.data.frame(
  # Position on left top
  x = -5, y = 9.5,
  # Glue for HTML styling
  label = glue("<span style='color:darkred'>PCA Rolling Stone top 100 metal albums of all time</span>")
)

# Subtitle object
subtitle <- cbind.data.frame(
  # Position below title
  x = -5, y = 8.5,
  # Glue for HTML styling, include legend colors
  label = glue("<span style='color:#2b2a30'>Principal component analysis of metal songs' features from the<br>Rolling Stone top 100 Metal Albums from </span><b style='color:black'> 1970 </b><span style='color:#2b2a30'>to</span><b style='color:red'> 2013 </b><span style='color:#2b2a30'>.<br>Each dot stands for a song, with title and artist for some favorite tracks.</span> ")
)

pretty_pca_plot4 <- pretty_pca_plot3 +
  annotate(
    geom = "text", x = 6, y = -7.5, hjust = 1, color = "dimgrey",
    label = "Data: data.world",
    size = 2, family = "cabin", lineheight = 0.4
  ) +
  geom_richtext(
    data = maintitle,
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE, lineheight = 0.5,
    alpha = 1, size = 7, family = 'cabin', hjust = 0, vjust = 1,
    fill = NA, label.color = NA, 
    label.padding = grid::unit(rep(0, 4), "pt")
  ) +
  geom_richtext(
    data = subtitle,
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE, lineheight = 0.5,
    alpha = 1, size = 5, family = 'cabin', hjust = 0, vjust = 1,
    fill = NA, label.color = NA, 
    label.padding = grid::unit(rep(0, 4), "pt")
  ) +
  # Remove original legend
  theme(
    legend.position = "none"
  )
pretty_pca_plot4

This looks good! But, I have also created a plot of variables that I want to include in this figure. I used patchwork to combine these two plots into one.

# Make plot with patchwork
layout = c(
  area(t = 0, l = 0, b = 10, r = 15), # Large area
  area(t = 0, l = 6, b = 5, r = 17) # Smaller area in right corner
)  
pretty_pca_plot4+pretty_var_plot+plot_layout(design=layout)

Okay, one final touch! I want to help the viewer understand the plot of variables better, so I want to add a description of the variable plot to the figure:

pretty_pca_plot5 <- pretty_pca_plot4 +
  annotate(
  geom = "text", x = 3.2, y = 3.3, hjust = 0.5, label = "Album ranking is\n heavily influenced\n by release year",
  size = 3.8, family = "cabin", lineheight = 1
  )
# Make plot with patchwork
layout2 = c(
  area(t = 0, l = 0, b = 10, r = 15), # Large area
  area(t = 0, l = 6, b = 5, r = 17) # Smaller area in right corner
) 
pretty_pca_plot5+pretty_var_plot+plot_layout(design=layout)

Unfortunately, some of the label positions keep changing due to the use of patchwork, but this is the best I could achieve with my skills.

This plot shows that the release year of the album of the songs correlates the most with the rank of the albums, which shows that Rolling Stone ranked older metal albums higher than the newer metal albums. It also shows that my personal taste differs leans towards the left and darker side of the main cloud of songs, which means that I prefer older songs too new ones.

This document will be improved in the future!

LS0tDQp0aXRsZTogIk1ldGFsbXVzaWMgUENBIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCkluIHRoaXMgcG9zdCwgSSB3aWxsIGV4cGxhaW4gaG93IEkgcGVyZm9ybWVkIGEgc21hbGwgYW5hbHlzaXMgb24gdGhlIGNoYXJhY3RlcmlzdGljcyBvZiBzb25ncyBmcm9tIGFsYnVtcyBpbiB0aGUgUm9sbGluZyBTdG9uZSB0b3AgMTAwIGdyZWF0ZXN0IG1ldGFsIGFsYnVtcyBvZiBhbGwgdGltZXMuIEkgd2FzIGluc3BpcmVkIHRvIGRvIHRoaXMgYWZ0ZXIgSSBmb2xsb3dlZCBbdGhpcyB0dXRvcmlhbF0oaHR0cHM6Ly9iam5ub3dhay5uZXRsaWZ5LmFwcC8yMDIxLzA5LzE1L3ItcGNhLXdpdGgtdGlkeXZlcnNlLykuDQoNCiMgTG9hZGluZyBsaWJyYXJpZXMNCkFzIGFsd2F5cyB3aXRoIFIsIHRoZSBuZWVkZWQgbGlicmFyaWVzIG5lZWQgdG8gYmUgbG9hZGVkIGJlZm9yZSBmdW5jdGlvbnMgb2YgdGhvc2UgbGlicmFyaWVzIGNhbiBiZSB1c2VkOg0KYGBge3IgbGlicmFyaWVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBMb2FkIHRoZSBuZWNlc3NhcnkgbGlicmFyaWVzDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShicm9vbSkNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkoZ2dyZXBlbCkNCmxpYnJhcnkoZ2d0ZXh0KQ0KbGlicmFyeShnbHVlKQ0KbGlicmFyeShzaG93dGV4dCkNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KYGBgDQoNCkFub3RoZXIgdGhpbmcgdG8gbG9hZCBpbiBhZHZhbmNlIGFyZSB0aGUgZm9udHMgbmVlZGVkIHRvIGNyZWF0ZSB0aGUgUENBIHBsb3Q6DQpgYGB7ciBmb250cywgbWVzc2FnZT1GQUxTRX0NCiMgTG9hZCBmb250cw0KZm9udF9hZGRfZ29vZ2xlKCJBY21lIiwgImFjbWUiKQ0KZm9udF9hZGRfZ29vZ2xlKCJSYWxld2F5IiwgInJhbGV3YXkiKQ0KZm9udF9hZGRfZ29vZ2xlKCJDYWJpbiBDb25kZW5zZWQiLCJjYWJpbiIpDQpmb250X2FkZF9nb29nbGUoIkJhcmxvdyBDb25kZW5zZWQiLCJiYXJsb3ciKQ0KZm9udF9hZGRfZ29vZ2xlKCJTdGludCBVbHRyYSBDb25kZW5zZWQiLCJzdGludCIpDQpmb250X2FkZF9nb29nbGUoIlBvcHBpbnMiLCJwb3BwaW5zIikNCmZvbnRfYWRkX2dvb2dsZSgiUGFjaWZpY28iLCJwYWNpZmljbyIpDQpmb250X2FkZF9nb29nbGUoIk9zd2FsZCIsIm9zd2FsZCIpDQoNCiMgQXV0b21hdGljYWxseSB1c2Uge3Nob3d0ZXh0fSBmb3IgcGxvdHMNCnNob3d0ZXh0X2F1dG8oKQ0KYGBgDQojIEltcG9ydGluZyBkYXRhDQpGaXJzdCwgSSBpbXBvcnRlZCB0aGUgZGF0YSBmcm9tIFRTViBmaWxlcyBvYnRhaW5lZCBmcm9tIGEgW2RhdGFzZXQgb24gZGF0YS53b3JsZF0oaHR0cHM6Ly9kYXRhLndvcmxkL2tjbWlsbGVyc2Vhbi9ycy0xMDAtZ3JlYXRlc3QtbWV0YWwtYWxidW1zLW9mLWFsbC10aW1lKS4gVGhlc2UgZGF0YXNldHMgY29udGFpbiBkYXRhIGFib3V0IHRoZSBSb2xsaW5nIFN0b25lIHRvcCAxMDAgYmVzdCBtZXRhbCBhbGJ1bXMgb2YgYWxsIHRpbWUuIEZvciBlYWNoIGFsYnVtLCBtZXRhZGF0YSBzdWNoIGFzIHRoZSBhcnRpc3QsIG5hbWUsIHJlbGVhc2UgeWVhciwgZHVyYXRpb24sIGdlbnJlLCByYXRpbmcgYW5kIG1vcmUgaXMgaW5jbHVkZWQuIEZvciBlYWNoIG9mIHRoZSBzb25ncyBvbiB0aGUgYWxidW0sIGluZm9ybWF0aW9uIGFib3V0IHRoZSBpbmRpdmlkdWFsIGNoYXJhY3RlcmlzdGljcyBpcyBpbmNsdWRlZCwgc3VjaCBhcyBCUE0sIHBvcHVsYXJpdHkgYW5kIHZhcmlvdXMgbWV0cmljcyBhYm91dCBob3cgdGhlIHNvbmcgc291bmRzIChlbmVyZ3ksIGRhbmNlLCBsb3VkLCB2YWxlbmNlIGV0Yy4pLg0KYGBge3IgbG9hZF9hbGJ1bV9kYXRhfQ0KIyBSZWFkIGluIGFsYnVtIGRhdGFzZXQNCnJhd19hbGJ1bXMgPC0gcmVhZC5kZWxpbSgiUlNfbWV0YWxfYWxidW1zLnR4dCIpDQoNCiMgVmlldyByZXN1bHRzDQpoZWFkKHJhd19hbGJ1bXMpDQpgYGANCmBgYHtyIGxvYWRfc29uZ19kYXRhfQ0KIyBSZWFkIGluIHNvbmcgZGF0YXNldA0KcmF3X3NvbmdzIDwtIHJlYWQuZGVsaW0oIlJTX21ldGFsX3NvbmdzLnR4dCIpDQoNCiMgVmlldyByZXN1bHRzDQpoZWFkKHJhd19zb25ncykNCmBgYA0KU29tZSBvZiB0aGUgaGVhZGVycyBpbiBib3RoIGRhdGFzZXRzIGNvbnRhaW5lZCBzcGFjZXMsIHdoaWNoIGFyZSBhdXRvbWF0aWNhbGx5IHJlcGxhY2VkIGJ5IGEgIi4iIGJ5IFIuIEkgcmVwbGFjZWQgdGhlc2Ugd2l0aCBhbiB1bmRlcnNjb3JlICgiXyIpOg0KYGBge3IgcmVtb3ZlX3VuZGVyc2NvcmVzfQ0KIyBDaGFuZ2UgY29sdW1uIG5hbWVzIG9mIHJhd19hbGJ1bXMNCmNvbG5hbWVzKHJhd19hbGJ1bXMpWzRdIDwtICJSZWxlYXNlX1llYXIiDQpjb2xuYW1lcyhyYXdfYWxidW1zKVsxMV0gPC0gIlRvdGFsX1NlY29uZHMiDQpjb2xuYW1lcyhyYXdfYWxidW1zKVsxM10gPC0gIlN1Yl9NZXRhbF9HZW5yZSINCmNvbG5hbWVzKHJhd19hbGJ1bXMpWzE1XSA8LSAiUm9sbGluZ19TdG9uZV9SYXRpbmciDQoNCiMgQ2hhbmdlIGNvbHVtbiBuYW1lcyBvZiByYXdfc29uZ3MNCmNvbG5hbWVzKHJhd19zb25ncylbMV0gPC0gIlNvbmdfSW5kZXgiDQpjb2xuYW1lcyhyYXdfc29uZ3MpWzRdIDwtICJUcmFja19ObyINCmBgYA0KVGhlIGRhdGFzZXQgd2l0aCB0aGUgc29uZ3MgZG9lcyBub3QgY29udGFpbiBhbnkgZGF0YSBvbiB0aGUgcmVsZWFzZSB5ZWFyIG9mIHRoZSBhbGJ1bSwgYnV0IHRoZSBhbGJ1bSBkYXRhc2V0IGRvZXMuIEkgbmVlZGVkIHRvIGFkZCBhIGNvbHVtbiB0byB0aGUgc29uZ3MgZGF0YXNldCB0aGF0IHNob3dzIHRoZSByZWxlYXNlIHllYXIgb2YgdGhlIGFsYnVtIG9uIHdoaWNoIGVhY2ggb2YgdGhlIHNvbmdzIGlzLiBJIGRpZCB0aGlzIGJ5IHVzaW5nIHRoZSAiQWxidW1JRF9SYW5rIiBjb2x1bW4gd2hpY2ggY29ycmVzcG9uZHMgYmV0d2VlbiB0aGUgMiBkYXRhc2V0cy4gVGhlIG1ldGhvZCBJIHVzZWQgZm9yIHRoaXMgb3BlcmF0aW9uIGlzIGZyb20gdGhlIGBkcGx5cmAgcGFja2FnZSwgYW5kIGlzIGNhbGxlZCBgbGVmdF9qb2luYC4gSSBmaXJzdCBzZWxlY3RlZCB0aGUgcmVsZXZhbnQgY29sdW1ucyBmcm9tIHJhd19hbGJ1bXMgKGBBbGJ1bUlEX1JhbmtgIGFuZCBgUmVsZWFzZV9ZZWFyYCkgYW5kIHRoZW4gam9pbmVkIGl0IHRvIGByYXdfc29uZ3NgIHVzaW5nIHRoZSBgQWxidW1JRF9SYW5rYCBjb2x1bW4uIA0KYGBge3IgbGpvaW5feWVhcnN9DQojIExlZnQgam9pbiBvbiBBbGJ1bUlEX1JhbmsgdG8gYWRkIHRoZSBSZWxlYXNlX1llYXIgdG8gcmF3X3NvbmdzDQpzb25nc193aXRoX3llYXIgPC0gcmF3X3NvbmdzICU+JQ0KICBsZWZ0X2pvaW4ocmF3X2FsYnVtcyAlPiUgc2VsZWN0KEFsYnVtSURfUmFuaywgUmVsZWFzZV9ZZWFyKSwgYnkgPSAiQWxidW1JRF9SYW5rIikNCg0KIyBWaWV3IHJlc3VsdA0KaGVhZChzb25nc193aXRoX3llYXIpDQpgYGANClRoaXMgcmVzdWx0ZWQgaW4gYSBuZXcgZGF0YXNldCAoYHNvbmdzX3dpdGhfeWVhcmApIHdpdGggYSBjb2x1bW4gYXBwZW5kZWQgdG8gdGhlIGByYXdfc29uZ3NgIGRhdGFzZXQuIFRoaXMgY29sdW1uIGNvbnRhaW5zIHRoZSByZWxlYXNlIHllYXIgb2YgdGhlIGFsYnVtIG9uIHdoaWNoIHRoZSBzb25nIGlzLiANCg0KQW5vdGhlciBjb2x1bW4gdGhhdCBtaWdodCBjb21lIGluIHVzZWZ1bCBpcyB0aGUgYFN1Yl9NZXRhbF9HZW5yZWAgY29sdW1uIG9mIHRoZSBgcmF3X2FsYnVtc2AgZGF0YXNldDsgSSBhbHNvIHBlcmZvcm1lZCBhIGBsZWZ0X2pvaW5gIG9uIHRoaXMgZGF0YTogDQpgYGB7ciBsam9pbl9nZW5yZX0NCiMgTGVmdCBqb2luIG9uIEFsYnVtSURfUmFuayB0byBhZGQgdGhlIFN1Yl9NZXRhbF9HZW5yZSB0byByYXdfc29uZ3MNCnNvbmdzX3dpdGhfeWVhcl9nZW5yZSA8LSBzb25nc193aXRoX3llYXIgJT4lDQogIGxlZnRfam9pbihyYXdfYWxidW1zICU+JSBzZWxlY3QoQWxidW1JRF9SYW5rLCBTdWJfTWV0YWxfR2VucmUpLCBieSA9ICJBbGJ1bUlEX1JhbmsiKQ0KDQojIFZpZXcgcmVzdWx0DQpoZWFkKHNvbmdzX3dpdGhfeWVhcl9nZW5yZSkNCmBgYA0KVG8gY2hvb3NlIHdoaWNoIHZhcmlhYmxlcyBhcmUgZ29pbmcgdG8gYmUgaW5jbHVkZWQgaW4gdGhlIFBDQSwgSSB3YW50ZWQgdG8gY2hlY2sgd2hpY2ggdmFyaWFibGVzIGNvcnJlbGF0ZSB0aGUgbW9zdCB3aXRoIGVhY2ggb3RoZXIuIEZvciB0aGlzLCBJIGNyZWF0ZWQgYSBjb3JyZWxhdGlvbiBtYXRyaXggd2l0aCB0aGUgYGNvcmAgZnVuY3Rpb24gZm9yIGFsbCBudW1lcmljIGNvbHVtbnMgb2YgdGhlIGBzb25nc193aXRoX3llYXJfZ2VucmVgIGRhdGFzZXQgd2l0aCB0aGUgY29kZSBiZWxvdzoNCg0KYGBge3IgY2FsY3VsYXRlX2Nvcm1hdHJpeH0NCiMgU2VsZWN0IG9ubHkgbnVtZXJpYyBjb2x1bW5zDQpudW1lcmljX2RhdGEgPC0gc29uZ3Nfd2l0aF95ZWFyX2dlbnJlICU+JQ0KICBzZWxlY3RfaWYoaXMubnVtZXJpYykNCg0KIyBDYWxjdWxhdGUgY29ycmVsYXRpb24gbWF0cml4DQpjb3JfbWF0cml4IDwtIGNvcihudW1lcmljX2RhdGEsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQ0KYGBgDQpUbyBnZXQgYSB2aXN1YWwgaW5zaWdodCBpbnRvIHRoZSBjb3JyZWxhdGlvbiwgSSBjcmVhdGVkIGEgc2ltcGxlIGhlYXRtYXAgb2YgdGhlIGNvcnJlbGF0aW9uIHZhbHVlcyB3aXRoIGBnZ3Bsb3QyYDoNCmBgYHtyIHBsb3RfY29ybWF0cml4fQ0KIyBDb252ZXJ0IGNvcnJlbGF0aW9uIG1hdHJpeCB0byBhIGxvbmcgZm9ybWF0IGZvciBnZ3Bsb3QyDQpjb3JfZGF0YSA8LSBtZWx0KGNvcl9tYXRyaXgpDQoNCiMgUGxvdCBoZWF0bWFwDQpnZ3Bsb3QoY29yX2RhdGEsIGFlcyhWYXIxLCBWYXIyLCBmaWxsID0gdmFsdWUpKSArDQogIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsgIyBXaGl0ZSBzcGFjZSBiZXR3ZWVuIHRpbGVzDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLCBtaWQgPSAid2hpdGUiLCAjIEhlYXRtYXAgY29sb3IgcmFuZ2UNCiAgICAgICAgICAgICAgICAgICAgICAgbWlkcG9pbnQgPSAwLCBsaW1pdCA9IGMoLTEsIDEpLCBzcGFjZSA9ICJMYWIiLCAjIE1pZHBvaW50IDAgYW5kIGZpbGwgYmV0d2VlbiAtMSBhbmQgMQ0KICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkNvcnJlbGF0aW9uIikgIyBMZWdlbmQgbmFtZQ0KYGBgDQpUaGlzIGhlYXRtYXAgZG9lcyBub3QgbG9vayB0aGUgYmVzdC4uLiBUaGVyZSBhcmUgbm8gbGFiZWxzIGluIHRoZSBwbG90IGFuZCB0aGUgeC1heGlzIGxhYmVscyBvdmVybGFwLiBMZXQncyBpbXByb3ZlIGl0Og0KYGBge3IgcGxvdF9jb3JtYXRyaXhfcHJldHR5fQ0KIyBQbG90IGhlYXRtYXAsIGJ1dCBwcmV0dHkNCmdncGxvdChjb3JfZGF0YSwgYWVzKFZhcjEsIFZhcjIsIGZpbGwgPSB2YWx1ZSkpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKyAjIFdoaXRlIHNwYWNlIGJldHdlZW4gdGlsZXMNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHZhbHVlLCAyKSksIHNpemUgPSAyLCBjb2xvciA9ICJibGFjayIpICsgIyBBZGQgbGFiZWxzIG9uIHRpbGVzDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKGxvdyA9ICJibHVlIiwgaGlnaCA9ICJyZWQiLCBtaWQgPSAid2hpdGUiLA0KICAgICAgICAgICAgICAgICAgICAgICBtaWRwb2ludCA9IDAsIGxpbWl0ID0gYygtMSwgMSksIHNwYWNlID0gIkxhYiIsDQogICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiQ29ycmVsYXRpb24iKSArDQogIHRoZW1lX21pbmltYWwoKSArICMgU2V0IHRoZW1lDQogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgaGp1c3QgPSAxKSkgKyAjIEFkanVzdCBheGlzIGxhYmVscw0KICBsYWJzKHRpdGxlID0gIk1ldGFsc29uZ3MgQ29ycmVsYXRpb24gTWF0cml4IEhlYXRtYXAiLCAjIFBsb3QgdGl0bGUNCiAgICAgICB4ID0gIlZhcmlhYmxlcyIsICMgQXhpcyB0aXRsZQ0KICAgICAgIHkgPSAiVmFyaWFibGVzIikgIyBBeGlzIHRpdGxlDQpgYGANCk5vdywgd2UgY2FuIHNlZSB0aGF0IGBTb25nX2luZGV4YCBhbmQgYEFsYnVtSURfUmFua2AgYXJlIGhpZ2hseSBjb3JyZWxhdGVkLCB3aGljaCBtYWtlcyBzZW5zZSBiZWNhdXNlIHRoZSBzb25nIGluZGV4IHZhbHVlcyB3ZXJlIGFzc2lnbmVkIGJhc2VkIG9uIHRoZSBzb25ncyBzb3J0ZWQgYmFzZWQgb24gdGhlIGFsYnVtIHJhbmtpbmcuIEluIGFkZGl0aW9uLCBgTG91ZGAgYW5kIGBFbmVyZ3lgIGFyZSBoaWdobHkgY29ycmVsYXRlZCwgd2hpY2ggd2FzIGFsc28gdG8gYmUgZXhwZWN0ZWQgYmVjYXVzZSBsb3VkIHNvbmdzIGFyZSBhbHNvIHZlcnkgZW5lcmdldGljIG1vc3Qgb2YgdGhlIHRpbWVzLiBUbyByZWR1Y2UgcmVkdW5kYW5jeSwgSSB3aWxsIG9ubHkgdXNlIG9uZSBvZiB0aGVzZSB0d28gY2F0ZWdvcmllczogYEVuZXJneWAgZm9yIHRoZSBQQ0EuIDIgY29tYmluYXRpb25zIHRoYXQgYXJlIGhpZ2hseSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQgYXJlIGBBY291c3RpY2AgYW5kIGBMb3VkYCBhbmQgYEFjb3VzdGljYCBhbmQgYEVuZXJneWAuIEFnYWluLCB0aGlzIG1ha2VzIHNlbnNlIGJlY2F1c2Ugd2l0aGluIHRoZSBtZXRhbCBnZW5yZSwgbW9zdCBhY291c3RpYyBzb25ncyBhcmUgbm90IGxvdWQgYW5kIGRvIG5vdCBjb250YWluIGEgbG90IG9mIGVuZXJneS4gDQoNCkEgYml0IG1vcmUgdW5leHBlY3RlZCBpcyB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiBgUmVsZWFzZV9ZZWFyYCBhbmQgYEFsYnVtSURfUmFua2AgKGFuZCBgU29uZ19JbmRleGApLiBUaGlzIGluZGljYXRlcyB0aGF0IHRoZSB5ZWFyIGFuIGFsYnVtIHdhcyByZWxlYXNlZCBpbmZsdWVuY2VzIHRoZSBwb3NpdGlvbiBvbiB0aGUgUm9sbGluZyBTdG9uZSB0b3AgMTAwLiBMZXQncyBzZWUgaWYgSSBjYW4gZnVydGhlciBhbmFseXplIHRoaXMgY29ycmVsYXRpb24gZHVyaW5nIHRoZSBQQ0EuDQoNCiMgU2VsZWN0aW5nIFBDQSBkYXRhDQpUbyBwZXJmb3JtIGEgUENBLCBJIGhhZCB0byBzZWxlY3QgdGhlIHZhcmlhYmxlcyB3aXRoIG51bWVyaWNhbCB2YWx1ZXMgb2YgaW50ZXJlc3QgZnJvbSB0aGUgZGF0YS4gVGhlc2UgaW5jbHVkZWQgdGhlIHJhbmtpbmcgcGxhY2Ugb2YgdGhlIGFsYnVtLCBidXQgYWxzbyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY2hhcmFjdGVyaXN0aWNzIG9mIGVhY2ggc29uZyBhbmQgdGhlIHllYXIgdGhleSB3ZXJlIHJlbGVhc2VkLiBJIGFsc28gYWRkZWQgYFNvbmdgIGFuZCBgQXJ0aXN0YCBiZWNhdXNlIHRoaXMgd2lsbCBiZSB1c2VmdWxsIHdoZW4gbGFiZWxpbmcgdGhlIGRpZmZlcmVudCBkYXRhcG9pbnRzLg0KVG8gc2VsZWN0IHRoZSB2YXJpYWJsZXMgdGhhdCBhcmUgaW50ZXJlc3RpbmcgZm9yIG91ciBQQ0EgZnJvbSB0aGUgZGF0YSwgSSB1c2VkIHRoZSBjb2RlIGJlbG93Og0KYGBge3Igc2VsZWN0aW5nfQ0KIyBOZXcgZGF0YSBmb3IgUENBDQpQQ0ExX2RhdGE8LXNvbmdzX3dpdGhfeWVhcl9nZW5yZSU+JQ0KICBzZWxlY3QoDQogICAgIyBJbnRlcmVzdGluZyB2YXJpYWJsZXMgZm9yIFBDQQ0KICAgIGMoQWxidW1JRF9SYW5rLEJQTSxEYW5jZSwNCiAgICAgIExvdWQsVmFsZW5jZSxBY291c3RpYyxQb3B1bGFyaXR5LA0KICAgICAgUmVsZWFzZV9ZZWFyLFNvbmcsQXJ0aXN0KQ0KICApJT4lDQogICMgUmVtb3ZlIE5BIGVudHJpZXMNCiAgZHJvcF9uYSgpDQpgYGANCiMgUGVyZm9ybWluZyB0aGUgUENBDQpBZnRlciB0aGVzZSBzdGVwcyBJIHdhcyByZWFkeSB0byBwZXJmb3JtIHRoZSBQQ0EsIHdoaWNoIEkgZGlkIHVzaW5nIHRoZSBgcHJjb21wYCBmdW5jdGlvbjoNCg0KYGBge3IgUENBMV9yYW5rfQ0KIyBSZW1vdmUgdGhlIG5vbi1udW1lcmljYWwgYXJ0aXN0IGFuZCBzb25nIG5hbWUgZGF0YSBmb3IgdGhlIFBDQQ0KUENBMV9yYW5rIDwtIFBDQTFfZGF0YSU+JQ0KICBzZWxlY3QoLUFydGlzdCwtU29uZyklPiUNCiAgIyBQZXJmb3JtIFBDQSANCiAgcHJjb21wKHNjYWxlPVRSVUUpDQpgYGANCg0KSSB1c2VkIGFub3RoZXIgcGFja2FnZSAoYGJyb29tYCkgdG8gdmlldyB0aGUgcmVzdWx0cyBpbiB0aGUgYHRpZHl2ZXJzZWAgc3ludGF4Og0KDQpgYGB7ciBhY2Nlc3NfUENBMV9yYW5rfQ0KIyBWaWV3IHJlc3VsdHMgaW4gZWlnZW52YWx1ZXMgbWF0cml4DQpQQ0ExX3JhbmslPiUNCiAgdGlkeShtYXRyaXggPSAiZWlnZW52YWx1ZXMiKQ0KYGBgDQpBcyB0aGUgdGliYmxlIHNob3dzLCBQQ0ExIGFjY291bnRzIGZvciAyNiUgb2YgdGhlIG92ZXJhbGwgdmFyaWFiaWxpdHksIGFuZCBQQ0EyIGZvciAyMiUuIEkgd2FudGVkIHRvIHZpc3VhbGl6ZSBob3cgdGhlIGRpZmZlcmVudCBjYXRlZ29yaWVzIHNlcGFyYXRlIHRoZSBkYXRhLCBiZWZvcmUgcGxvdHRpbmcgdGhlIGFjdHVhbCBkYXRhcG9pbnRzIG9mIGVhY2ggc29uZy4NCg0KIyBQbG90dGluZyB2YXJpYWJsZXMNClRvIHNlZSB3aGF0IHZhcmlhYmxlcyBhY2NvdW50IGZvciB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIHBsb3QsIEkgZXh0cmFjdGVkIHRoZSBjb29yZGluYXRlcyBvZiB0aGUgdmFyaWFibGVzIGZyb20gdGhlICJyb3RhdGlvbiIgbWF0cml4IG9mIHRoZSBgUENBMV92YXJgIGRhdGE6DQpgYGB7ciBQQ0ExX3ZhcmlhYmxlc30NCiMgTmV3IGRhdGFmcmFtZSBmb3IgdmFyaWFibGVzDQpQQ0ExX3ZhcjwtUENBMV9yYW5rICU+JQ0KICAjIEV4dHJhY3QgdmFyaWFibGUgY29vcmRzDQogIHRpZHkobWF0cml4ID0gInJvdGF0aW9uIikgJT4lDQogICMgRm9ybWF0IHRhYmxlIGxvbmcgdG8gd2lkZQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gIlBDIiwgbmFtZXNfcHJlZml4ID0gIlBDIiwgdmFsdWVzX2Zyb20gPSAidmFsdWUiKSAlPiUNCiAgIyBSZW5hbWUgY29sdW1uIHdpdGggdmFyaWFibGUgbmFtZXMNCiAgcmVuYW1lKFZhcmlhYmxlPWNvbHVtbikNCiAgIyBDaGVjayB0aWJibGUNCiAgaGVhZChQQ0ExX3ZhcikNCmBgYA0KVG8gYWN0dWFsbHkgcGxvdCB0aGUgdmFyaWFibGVzLCBJIHVzZWQgdGhlIGBnZ3JlcGVsYCBsaWJyYXJ5IGJlY2F1c2UgdGhpcyBwcmV2ZW50cyBlcnJvcnMgd2hlbiB2YXJpYWJsZSBuYW1lcyBvdmVybGFwLiAgSSBjaG9zZSBhIGRpZmZlcmVudCBjb2xvciBmb3IgdGhlIGBBbGJ1bUlEX1JhbmtgIHZhcmlhYmxlLCBiZWNhdXNlIGl0IGlzIGludGVyZXN0aW5nIHRvIHNlZSBob3cgdGhpcyB2YXJpYWJsZSBpcyBpbmZsdWVuY2VkIGJ5IHRoZSBvdGhlcnMuDQpgYGB7ciBwbG90X3ZhcmlhYmxlc30NCmdncGxvdChkYXRhID0gUENBMV92YXIsIGFlcyhQQzEsIFBDMikpICsNCiAgIyBBZGQgdmFyaWFibGUgYXJyb3dzIHdpdGggY29uZGl0aW9uYWwgY29sb3INCiAgZ2VvbV9zZWdtZW50KA0KICAgIGFlcyhjb2xvciA9IGlmZWxzZShWYXJpYWJsZSA9PSAiQWxidW1JRF9SYW5rIiwgImJsYWNrIiwgInJlZCIpKSwNCiAgICB4ZW5kID0gMCwgeWVuZCA9IDAsDQogICAgYXJyb3cgPSBhcnJvdygNCiAgICAgIGxlbmd0aCA9IHVuaXQoMC4wMywgIm5wYyIpLA0KICAgICAgdHlwZSA9ICJjbG9zZWQiLA0KICAgICAgZW5kcyA9ICJmaXJzdCINCiAgICApDQogICkgKw0KICAjIEFkZCB2YXJpYWJsZSBuYW1lcyB3aXRoIGNvbmRpdGlvbmFsIGNvbG9yDQogIGdlb21fdGV4dF9yZXBlbCgNCiAgICBhZXMobGFiZWwgPSBWYXJpYWJsZSwgY29sb3IgPSBpZmVsc2UoVmFyaWFibGUgPT0gIkFsYnVtSURfUmFuayIsICJibGFjayIsICJyZWQiKSksDQogICAgaGp1c3QgPSAxLCBzaXplID0gMywNCiAgICBtaW4uc2VnbWVudC5sZW5ndGggPSBJbmYsDQogICAgbnVkZ2VfeCA9IDAuMDEsIG51ZGdlX3kgPSAwLjA4DQogICkgKw0KICBjb29yZF9maXhlZCgpICsNCiAgbGFicygNCiAgICAjIEFkZCB0aXRsZXMNCiAgICB0aXRsZSA9ICdQbG90IG9mIFBDQSBWYXJpYWJsZXMgVG9wIDEwMCBNZXRhbCBBbGJ1bXMnLA0KICAgIHggPSAnUEMxJywNCiAgICB5ID0gJ1BDMicsDQogICAgY29sb3IgPSAnVmFyaWFibGUnDQogICkgKw0KICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANClRoaXMgcGxvdCBvZiB2YXJpYWJsZXMgYWdhaW4gc2hvd3MgdGhhdCB0aGUgYEFsYnVtSURfUmFua2AgaXMgbW9zdGx5IGluZmx1ZW5jZWQgYnkgYFJlbGVhc2VfWWVhcmAsIGJ1dCBhbHNvIHRoYXQgYEFjb3VzdGljYCBhbmQgYExvdWRgIHNlcGFyYXRlIGEgbG90IG9mIHNvbmdzLiBXaXRoIGEgbGFyZ2VyIHBsb3QgaW4gbWluZCwgSSB3YW50ZWQgdG8gcmVtb3ZlIHRoZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgUEMgbnVtYmVycywgYW5kIG1ha2UgdGhlIHBsb3QgbG9vayBtb3JlIHZpc3VhbGx5IGFwcGVhbGluZyBzbyBpdCBjYW4gYmUgc2hvd24gdG9nZXRoZXIgd2l0aCB0aGUgUENBIHBsb3Q6DQpgYGB7ciBwbG90X3ZhcmlhYmxlc19wcmV0dHl9DQpwcmV0dHlfdmFyX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBQQ0ExX3ZhciwgYWVzKFBDMSwgUEMyKSkgKw0KICAjIEFkZCB2YXJpYWJsZSBhcnJvd3Mgd2l0aCBjb25kaXRpb25hbCBjb2xvcg0KICBnZW9tX3NlZ21lbnQoDQogICAgYWVzKGNvbG9yID0gaWZlbHNlKFZhcmlhYmxlID09ICJBbGJ1bUlEX1JhbmsiLCAiYmxhY2siLCAiI2M5MzQzNCIpKSwgIyBCbGFjayBhbmQgcmVkIGFycm93cw0KICAgIHhlbmQgPSAwLCB5ZW5kID0gMCwNCiAgICBhcnJvdyA9IGFycm93KA0KICAgICAgbGVuZ3RoID0gdW5pdCgwLjA1LCAibnBjIiksDQogICAgICB0eXBlID0gImNsb3NlZCIsDQogICAgICBlbmRzID0gImZpcnN0Ig0KICAgICksDQogICAgbGluZXdpZHRoID0gMC45LCAjIFdpZGUgbGluZXMNCiAgKSArDQogICMgQWRkIHZhcmlhYmxlIG5hbWVzDQogIGdlb21fdGV4dF9yZXBlbCgNCiAgICBhZXMobGFiZWwgPSBWYXJpYWJsZSwgY29sb3IgPSBpZmVsc2UoVmFyaWFibGUgPT0gIkFsYnVtSURfUmFuayIsICJibGFjayIsICIjYzkzNDM0IikpLCAjIEJsYWNrIGFuZCByZWQgbmFtZXMNCiAgICBoanVzdCA9IDEsIHNpemUgPSAzLjUsDQogICAgbWluLnNlZ21lbnQubGVuZ3RoID0gSW5mLA0KICAgIG51ZGdlX3ggPSAwLjAxLCBudWRnZV95ID0gMC4wOA0KICApICsNCiAgIyBBZGQgZGFzaGVkIGxpbmUgZm9yIHkgYXhpcw0KICBhbm5vdGF0ZSgNCiAgICBnZW9tID0gInNlZ21lbnQiLCB4ID0gMCwgeGVuZCA9IDAsIHkgPSAtSW5mLCB5ZW5kID0gSW5mLCBjb2wgPSAiZ3JleTYwIiwgbHR5ID0gImRhc2hlZCIsDQogICAgbGluZXdpZHRoID0gMC41DQogICkgKw0KICAjIEFkZCBkYXNoZWQgbGluZSBmb3IgeCBheGlzDQogIGFubm90YXRlKA0KICAgIGdlb20gPSAic2VnbWVudCIsIHggPSBJbmYsIHhlbmQgPSAtSW5mLCB5ID0gMCwgeWVuZCA9IDAsIGNvbCA9ICJncmV5NjAiLCBsdHkgPSAiZGFzaGVkIiwNCiAgICBsaW5ld2lkdGggPSAwLjUNCiAgKSArDQogICMgS2VlcCBmaXhlZCBhc3BlY3QgcmF0aW8NCiAgY29vcmRfZml4ZWQoKSArDQogICMgTWFpbnRhaW4gY29sb3IgaWRlbnRpdHkgYW5kIHJlbW92ZSBsZWdlbmQNCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArDQogIGd1aWRlcyhjb2xvciA9ICJub25lIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLA0KICAgICMgTm8gYXhpcyBsYWJlbHMNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpDQogICkNCnByZXR0eV92YXJfcGxvdA0KYGBgDQojIFBsb3R0aW5nIHNvbmdzDQpUbyBhY3R1YWxseSBjcmVhdGUgYSBwbG90IG9mIGFsbCBzb25ncyBpbmNsdWRlZCBpbiB0aGUgZmlyc3QgUENBLCBJIHVzZWQgYGdncGxvdGAgYWdhaW4uIE9mIGNvdXJzZSBJIHVzZWQgcmVkIGFuZCBibGFjayBpbiB0aGUgY29sb3IgcGFsZXR0ZSwgdGhpcyBpcyBhIG1ldGFsIGRhdGEgYW5hbHlzaXMgYWZ0ZXIgYWxsIDopLg0KYGBge3IgUENBMV9wbG90fQ0KIyBBZGQgcmFuayBkYXRhIGJhY2sgdG8gUENBIGNhbGN1bGF0ZWQgZGF0YQ0KUENBMV9pbmRpdl9yYW5rPC1QQ0ExX3JhbmslPiUNCiAgYXVnbWVudChQQ0ExX2RhdGEpDQoNCiMgUGxvdCBpbmRpdmlkdWFscw0KZ2dwbG90KA0KICAjIEJhc2VkIG9uIGNhbGN1bGF0ZWQgUENBIGRhdGENCiAgZGF0YT1QQ0ExX2luZGl2X3JhbmssDQogICMgVXNlIFBDQSB2YWx1ZXMgYW5kIGNvbG9yIGJhc2VkIG9uIHJlbGVhc2UgeWVhcg0KICBhZXMoLmZpdHRlZFBDMSwgLmZpdHRlZFBDMixjb2xvcj1SZWxlYXNlX1llYXIpKSsNCiAgZ2VvbV9wb2ludCgpKw0KICAjIEFkZCBsYWJlbHMgYW5kIGNvbG9yIGJhc2VkIG9uIHllYXINCiAgbGFicygNCiAgICB0aXRsZSA9ICdQbG90IG9mIGluZGl2aWR1YWwgc29uZ3MnLA0KICAgIHN1YnRpdGxlID0gJ0NvbG9yIHNob3dzIHllYXIgb2YgYWxidW0gcmVsZWFzZSBvZiBzb25ncycsDQogICAgeD0nUEMxICgyNiUpJywNCiAgICB5PSdQQzIgKDIyJSknLA0KICAgIGNvbG9yPSdSZWxlYXNlX1llYXInDQogICkrDQogICMgR3JhZGllbnQgd2l0aCByZWRzDQogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJibGFjayIsIGhpZ2ggPSAicmVkIikgKw0KICAjIExpZ2h0IHRoZW1lDQogIHRoZW1lX2xpZ2h0KCkNCmBgYA0KVGhlIHBsb3Qgc2hvd3MgdGhhdCBQQzEgaXMgdGhlIHByaW5jaXBhbCBjb21wb25lbnQgdGhhdCBpcyBhYmxlIHRvIGRpc3Rpbmd1aXNoIHRoZSBzb25ncyB0aGUgYmVzdCBiYXNlZCBvbiB0aGUgYWxidW0gcmVsZWFzZSB5ZWFyLg0KDQpOb3csIEkgd2FudGVkIHRvIHRyeSBhbmQgbWFrZSB0aGUgcGxvdCBjb250YWluIG1vcmUgaW5mb3JtYXRpb24gYW5kIGFsc28gbG9vayBhIGJpdCBwcmV0dGllci4uLg0KDQojIE9wdGltaXppbmcgdGhlIHBsb3QNClRoZSBmaXJzdCBiaXQgb2YgaW5mb3JtYXRpb24gSSB0aG91Z2h0IGFib3V0IGFkZGluZyB0byB0aGUgcGxvdCB3YXMgdGhlIHNvbmcgbmFtZXMuIEkgc3RhcnRlZCB3aXRoIHRyeWluZyB0byBhZGQgYWxsIGxhYmVscyB0byB0aGUgcGxvdCB3aXRoIHRoZSBjb2RlIGJlbG93LCBidXQgYXMgd2FzIHRvIGJlIGV4cGVjdGVkLCBpdCBiZWNhbWUgYSBiaWcgbWVzczoNCmBgYHtyIFBDQTFfYWxsbmFtZXN9DQojIENoZWNrIGlmIHNvbmcgbmFtZXMgYXJlIHZhbGlkIGFuZCBoYW5kbGUgc3BlY2lhbCBjaGFyYWN0ZXJzDQpQQ0ExX2luZGl2X3JhbmsgPC0gUENBMV9pbmRpdl9yYW5rICU+JQ0KICAjIENoZWNrIHRoYXQgc29uZyBpcyBhIGNoYXJhY3RlciB2ZWN0b3INCiAgbXV0YXRlKFNvbmcgPSBhcy5jaGFyYWN0ZXIoU29uZykpICU+JQ0KICAjIFJlbW92ZSBub3QgYWNjZXB0ZWQgY2hhcmFjdGVycw0KICBtdXRhdGUoU29uZyA9IGljb252KFNvbmcsICJVVEYtOCIsICJBU0NJSSIsIHN1YiA9ICIiKSkgJT4lDQogIG11dGF0ZShTb25nID0gZ3N1YigiW15bOmFsbnVtOl0gXSIsICIiLCBTb25nKSkNCg0KIyBQbG90IHRoZSBQQ0Egd2l0aCBhbGwgc29uZyBuYW1lIGxhYmVscywgYWxsb3dpbmcgb3ZlcmxhcHMNCmdncGxvdChQQ0ExX2luZGl2X3JhbmssIGFlcyguZml0dGVkUEMxLCAuZml0dGVkUEMyLCBsYWJlbCA9IFNvbmcpKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gUmVsZWFzZV9ZZWFyKSkgKyAgIyBBZGQgcG9pbnRzIGNvbG9yZWQgYnkgcmVsZWFzZSB5ZWFyDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBTb25nKSwgc2l6ZSA9IDMsIHZqdXN0ID0gLTAuNSwgaGp1c3QgPSAwLjUpICsgICMgQWRkIHNvbmcgbGFiZWxzIGRpcmVjdGx5IChubyBvdmVybGFwIGF2b2lkYW5jZSkNCiAgIyBBZGQgbGFiZWxzIGFuZCBjb2xvciBiYXNlZCBvbiB5ZWFyDQogIGxhYnMoDQogICAgdGl0bGUgPSAnUENBIG9mIFNvbmdzJywNCiAgICBzdWJ0aXRsZSA9ICdDb2xvciBzaG93cyB5ZWFyIG9mIGFsYnVtIHJlbGVhc2UnLA0KICAgIHggPSAnUEMxJywNCiAgICB5ID0gJ1BDMicsDQogICAgY29sb3IgPSAnUmVsZWFzZSBZZWFyJw0KICApICsNCiAgIyBDb2xvciBncmFkaWVudA0KICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3cgPSAiYmxhY2siLCBoaWdoID0gInJlZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KQmFzZWQgb24gdGhpcyBwbG90LCBJIG5vdGljZWQgdHdvIG1ham9yIHByb2JsZW1zLiBUaGUgZmlyc3Qgb25lIGJlaW5nIHRoYXQgbGFiZWxpbmcgZXZlcnkgc2luZ2xlIGRhdGEgcG9pbnQgbGVhZHMgdG8gb3ZlcmxhcHMgYW5kIGNsdXR0ZXIuIFRoZSBzZWNvbmQgb25lIGJlaW5nIHRoYXQgc29tZSBzb25nIG5hbWVzIGFyZSB1bm5lY2Vzc2FyeSBsb25nIGR1ZSB0byB0aGVtIGJlaW5nIHJlbWFzdGVyZWQgdmVyc2lvbnMuIEkgc3RhcnRlZCB3aXRoIHRyeWluZyB0byBmaXggdGhlIGZpcnN0IHByb2JsZW0uDQoNCiMjIFNlbGVjdGluZyBtb3N0IHBvcHVsYXIgc29uZyBmcm9tIGVhY2ggYWxidW0NClRvIHJlZHVjZSB0aGUgYW1vdW50IG9mIHNvbmdzIHdpdGggYSBsYWJlbCwgSSBkZWNpZGVkIHRvIG1ha2UgYSBuZXcgZGF0YXNldCB0aGF0IGNvbnRhaW5zIG9ubHkgdGhlIG1vc3QgcG9wdWxhciBzb25nIG9mIGVhY2ggYWxidW0gaW4gdGhlIGRhdGFzZXQ6DQpgYGB7ciBwb3B1bGFyX3NvbmdzX29ubHl9DQojIE5ldyBkYXRhc2V0DQpoaWdoZXN0X3BvcHVsYXJpdHlfcGVyX2FsYnVtIDwtIFBDQTFfaW5kaXZfcmFuayAlPiUNCiAgIyBHcm91cCBiYXNlZCBvbiByYW5rDQogIGdyb3VwX2J5KEFsYnVtSURfUmFuaykgJT4lDQogICMgRmlsdGVyIHJvd3Mgd2l0aCBtYXggUG9wdWxhcml0eQ0KICBmaWx0ZXIoUG9wdWxhcml0eSA9PSBtYXgoUG9wdWxhcml0eSkpICU+JQ0KICAjIEhhbmRsZSB0aWVzIGJ5IHNlbGVjdGluZyB0aGUgZmlyc3Qgcm93DQogIHNsaWNlKDEpICU+JSAgDQogIHVuZ3JvdXAoKQ0KYGBgDQojIyBSZW1vdmluZyByZW1hc3RlciBpbmZvIGZyb20gcG9wdWxhciBzb25nIG5hbWVzDQpBZnRlciBtYWtpbmcgYSBzdWJzZXQgb2Ygb25seSB0aGUgbW9zdCBwb3B1bGFyIHNvbmdzLCBJIHdhbnRlZCB0byBzaG9ydGVuIHNvbWUgb2YgdGhlIHNvbmcgbmFtZXMuIEEgbG90IG9mIHRoZSBzb25ncyBhcmUgcmVtYXN0ZXJlZCBhZnRlciB0aGUgaW5pdGlhbCBhbGJ1bSByZWxlYXNlLCB3aGljaCBtZWFucyB0aGF0IHNvbWUgaW5mb3JtYXRpb24gaXMgYWRkZWQgdG8gdGhlIHNvbmcgdGl0bGUuDQpJIGNyZWF0ZWQgYSBgcmVnZXhgIHBhdHRlcm4gdG8gZmlsdGVyIG91dCBhbGwgc29uZ3MgdGhhdCBoYXZlIHNvbWUgdmVyc2lvbiBvZiAiUmVtYXN0ZXIiLCAiUmVtYXN0ZXJlZCIgYW5kIGEgeWVhciBpbiB0aGUgc29uZyB0aXRsZS4NCkFsbCB0ZXh0IHRoYXQgbWF0Y2hlcyB0aGlzIHBhdHRlcm4gaXMgcmVtb3ZlZCBpbiB0aGUgY29kZSBiZWxvdzoNCmBgYHtyIG5vX3JlbWFzdGVyX2NsZWFuaW5nfQ0KIyBDbGVhbiB0aGUgc29uZyBuYW1lcyBjb2x1bW4NCnBvcHVsYXJfbm9fcmVtYXN0ZXIgPC0gaGlnaGVzdF9wb3B1bGFyaXR5X3Blcl9hbGJ1bSAlPiUNCiAgbXV0YXRlKFNvbmcgPSBzdHJfcmVtb3ZlX2FsbChTb25nLCAiKD9pKVxccypcXGIocmVtYXN0ZXIoZWQpPyggXFxkezR9KT98XFxkezR9IHJlbWFzdGVyKGVkKT8pXFxiLiokIikpDQoNCiMgQWRkIGEgZmxhZyBmb3IgcG9wdWxhciBzb25ncyBpbiB0aGUgb3JpZ2luYWwgUENBIGRhdGFzZXQNClBDQTFfaW5kaXZfcmFuayA8LSBQQ0ExX2luZGl2X3JhbmsgJT4lDQogIG11dGF0ZShQb3B1bGFyID0gaWZlbHNlKFNvbmcgJWluJSBwb3B1bGFyX25vX3JlbWFzdGVyJFNvbmcsIFRSVUUsIEZBTFNFKSkNCmBgYA0KVG8gbWFrZSB0aGUgZG93bnN0cmVhbSBwbG90dGluZyBvZiB0aGlzIGRhdGEgZWFzaWVyLCBJIGFkZGVkIGEgZmxhZyB0byB0aGUgb3JpZ2luYWwgUENBIGRhdGEgdG8gaW5kaWNhdGUgaWYgdGhlIHNvbmcgaXMgdGhlIG1vc3QgcG9wdWxhciBvZiBhbiBhbGJ1bS4NCg0KIyMgUGxvdHRpbmcgYWdhaW4NCkxldCdzIHNlZSBpZiByZWR1Y2luZyB0aGUgYW1vdW50IG9mIGxhYmVscyB0byBvbmx5IG9uZSBmb3IgZWFjaCBhbGJ1bSBhbmQgc2hvcnRlbmluZyByZW1hc3RlcmVkIHNvbmcgbmFtZXMgbWFkZSBhIGRpZmZlcmVuY2UgaW4gbWFraW5nIHRoZSBwbG90IGxvb2sgYmV0dGVyOg0KYGBge3IgUENBMV9wb3B1bGFyX25vX3JlbWFzdGVyfQ0KIyBQbG90IHRoZSBQQ0Egd2l0aCBub24tb3ZlcmxhcHBpbmcgbGFiZWxzIGZvciBwb3B1bGFyIHNvbmdzDQpnZ3Bsb3QoUENBMV9pbmRpdl9yYW5rLCBhZXMoLmZpdHRlZFBDMSwgLmZpdHRlZFBDMikpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBSZWxlYXNlX1llYXIpKSArICAjIEFkZCBwb2ludHMgY29sb3JlZCBieSByZWxlYXNlIHllYXINCiAgZ2VvbV90ZXh0X3JlcGVsKA0KICAgIGRhdGEgPSBzdWJzZXQoUENBMV9pbmRpdl9yYW5rLCBQb3B1bGFyID09IFRSVUUpLCAgIyBPbmx5IGxhYmVsIHBvcHVsYXIgc29uZ3MNCiAgICBhZXMobGFiZWwgPSBTb25nKSwNCiAgICBzaXplID0gMywgIyBUZXh0IHNpemUNCiAgICBib3gucGFkZGluZyA9IDAuMzUsICAjIFBhZGRpbmcgYXJvdW5kIHRoZSB0ZXh0IGJveA0KICAgIHBvaW50LnBhZGRpbmcgPSAwLjUsICAjIFNwYWNlIGJldHdlZW4gdGhlIGxhYmVsIGFuZCB0aGUgcG9pbnQNCiAgICBtYXgub3ZlcmxhcHMgPSBJbmYsICAjIEFsbG93IGFsbCBsYWJlbHMgdG8gYXR0ZW1wdCB0byBkaXNwbGF5DQogICAgc2VnbWVudC5jb2xvciA9ICdncmV5NTAnLCAgIyBMaW5lIGNvbG9yDQogICAgc2VnbWVudC5zaXplID0gMC41ICAjIExpbmUgdGhpY2tuZXNzDQogICkgKw0KICAjIEFkZCBsYWJlbHMgYW5kIGNvbG9yIGJhc2VkIG9uIHllYXINCiAgbGFicygNCiAgICB0aXRsZSA9ICdQQ0Egb2YgU29uZ3MnLA0KICAgIHN1YnRpdGxlID0gJ0NvbG9yIHNob3dzIHllYXIgb2YgYWxidW0gcmVsZWFzZTsgbGFiZWxzIGZvciBwb3B1bGFyIHNvbmdzJywNCiAgICB4ID0gJ1BDMScsDQogICAgeSA9ICdQQzInLA0KICAgIGNvbG9yID0gJ1JlbGVhc2UgWWVhcicNCiAgKSArDQogICMgQ29sb3JzIGFuZCB0aGVtZSANCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsYWNrIiwgaGlnaCA9ICJyZWQiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpXZWxsLCB0aGlzIHN0aWxsIGxvb2tzIHZlcnkgY2hhb3RpYy4uLiBNYXliZSBpdCdzIGJldHRlciB0byBtYW51YWxseSBzZWxlY3Qgc29uZ3MgdGhhdCBoYXZlIHRvIGJlIGxhYmVsbGVkIGluIHRoZSBncmFwaC4gRm9yIHRoaXMsIEkgc2VsZWN0ZWQgbXkgcGVyc29uYWwgZmF2b3JpdGVzIGZyb20gdGhlIG1vc3QgcG9wdWxhciBtZXRhbCBzb25ncy4gDQpgYGB7ciBQQ0FfZmF2b3JpdGVzfQ0KIyBNYW51YWxseSBzcGVjaWZ5IHRoZSBzb25nIG5hbWVzIHRvIGJlIGxhYmVsZWQNCnNlbGVjdGVkX3NvbmdzIDwtIGMoIkNob3AgU3VleSIsIkJyZWFraW5nIHRoZSBMYXciLCJNYXN0ZXIgT2YgUHVwcGV0cyIsIldvdWxkIiwiTm90aGluZyBFbHNlIE1hdHRlcnMiLCJCbGluZCIsIlBlb3BsZSAgU2hpdCIsIlRyYW5zaWx2YW5pYW4gSHVuZ2VyIiwiV2FsayIsIkJhdCBDb3VudHJ5IiwiUmFpbmluZyBCbG9vZCIsIktpbGxpbmcgSW4gVGhlIE5hbWUiKQ0KDQojIE5ldyBkYXRhc2V0IHRvIGluY2x1ZGUgb25seSB0aGUgc2VsZWN0ZWQgc29uZ3MNCnBvcHVsYXJfZmF2b3JpdGVzIDwtIHBvcHVsYXJfbm9fcmVtYXN0ZXIgJT4lDQogIGZpbHRlcihTb25nICVpbiUgc2VsZWN0ZWRfc29uZ3MpDQoNCiMgQWRkIGEgZmxhZyBmb3IgZmF2b3JpdGUgc29uZ3MgaW4gdGhlIG9yaWdpbmFsIFBDQSBkYXRhc2V0DQpQQ0ExX2luZGl2X3JhbmsgPC0gUENBMV9pbmRpdl9yYW5rICU+JQ0KICBtdXRhdGUoRmF2b3JpdGUgPSBpZmVsc2UoU29uZyAlaW4lIHBvcHVsYXJfZmF2b3JpdGVzJFNvbmcsIFRSVUUsIEZBTFNFKSkNCg0KIyBQbG90IHRoZSBQQ0Egd2l0aCByZXBlbGxlZCBsYWJlbHMgZm9yIHBvcHVsYXIgc29uZ3MNCm5lYXRfcGNhIDwtIGdncGxvdChQQ0ExX2luZGl2X3JhbmssIGFlcyguZml0dGVkUEMxLCAuZml0dGVkUEMyKSkgKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IFJlbGVhc2VfWWVhcikpICsgICMgQWRkIHBvaW50cyBjb2xvcmVkIGJ5IHJlbGVhc2UgeWVhcg0KICBnZW9tX3RleHRfcmVwZWwoDQogICAgZGF0YSA9IHN1YnNldChQQ0ExX2luZGl2X3JhbmssIEZhdm9yaXRlID09IFRSVUUpLCAgIyBPbmx5IGxhYmVsIGZhdm9yaXRlIHNvbmdzDQogICAgYWVzKGxhYmVsID0gU29uZyksDQogICAgc2l6ZSA9IDMsDQogICAgbnVkZ2VfeCA9IC0wLjAxLA0KICAgIG51ZGdlX3kgPSAtMC4wMSwNCiAgICBib3gucGFkZGluZyA9IDAuNCwgICMgUGFkZGluZyBhcm91bmQgdGhlIHRleHQgYm94DQogICAgcG9pbnQucGFkZGluZyA9IDAsICAjIFNwYWNlIGJldHdlZW4gdGhlIGxhYmVsIGFuZCB0aGUgcG9pbnQNCiAgICBtYXgub3ZlcmxhcHMgPSBJbmYsICAjIEFsbG93IGFsbCBsYWJlbHMgdG8gYXR0ZW1wdCB0byBkaXNwbGF5DQogICAgc2VnbWVudC5jb2xvciA9ICdibGFjaycsICAjIExpbmUgY29sb3INCiAgICBzZWdtZW50LnNpemUgPSAwLjYgICMgTGluZSB0aGlja25lc3MNCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAnUENBIG9mIFNvbmdzJywNCiAgICBzdWJ0aXRsZSA9ICdDb2xvciBzaG93cyB5ZWFyIG9mIGFsYnVtIHJlbGVhc2U7IGxhYmVscyBmb3IgZmF2b3JpdGUgc29uZ3MnLA0KICAgIHggPSAnUEMxJywNCiAgICB5ID0gJ1BDMicsDQogICAgY29sb3IgPSAnUmVsZWFzZSBZZWFyJw0KICApICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsYWNrIiwgaGlnaCA9ICJyZWQiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KbmVhdF9wY2ENCmBgYA0KIyBDcmVhdGluZyB0aGUgaWRlYWwgcGxvdA0KSSBhbHJlYWR5IHJlYWxseSBsaWtlZCB0aGlzIHZlcnNpb24gb2YgdGhlIHBsb3QsIGJ1dCBJIHdhbnRlZCB0byBtYWtlIGl0IGxvb2sgbW9yZSBzdHlsZWQuIEluIHRoZSBjb2RlIGJlbG93LCBJIHBsYXllZCBhcm91bmQgd2l0aCBkaWZmZXJlbnQgbG9va3MgZm9yIHRoZSBkYXRhcG9pbnRzLCBsYWJlbGxpbmcgbWVjaGFuaXNtcyBhbmQgZm9udHMuIA0KYGBge3IgcHJldHR5X3BjYV9wbG90X3BhcnQxfQ0KcHJldHR5X3BjYV9wbG90MSA8LSBnZ3Bsb3QoUENBMV9pbmRpdl9yYW5rLCBhZXMoLmZpdHRlZFBDMSwgLmZpdHRlZFBDMiwgY29sb3IgPSBSZWxlYXNlX1llYXIpKSArICMgTWFwIGNvbG9yIHRvIGEgdmFyaWFibGUNCiAgZ2VvbV9wb2ludChhbHBoYT0wLjIsc2l6ZSA9IDIpICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gImJsYWNrIiwgaGlnaCA9ICJyZWQiKSArDQogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKC01LCA3KSkgKyAjIFBsb3Qgc2l6ZSB4DQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC03LjgsIDEwKSkrICMgUGxvdCBzaXplIHkNCiAgIyBMYWJlbHMgdGhhdCBjYW4gbm90IG92ZXJsYXAgYW5kIGFyZSBub3Qgb24gdGhlIGRhdGFwb2ludA0KICBnZW9tX3RleHRfcmVwZWwoIA0KICAgIGRhdGEgPSBzdWJzZXQoUENBMV9pbmRpdl9yYW5rLCBGYXZvcml0ZSA9PSBUUlVFKSwgIyBPbmx5IGxhYmVsIGZhdm9yaXRlIHNvbmdzDQogICAgYWVzKGxhYmVsID0gcGFzdGUoU29uZywgIlxuIiwgQXJ0aXN0LCBzZXAgPSAiIiksIGZvbnRmYWNlID0gImJvbGQuaXRhbGljIiksICMgU29uZyBhbmQgYXJ0aXN0IGxhYmVsDQogICAgc2l6ZSA9IDIuOCwgICMgVGV4dCBzaXplDQogICAgYm94LnBhZGRpbmcgPSAwLjYsICAjIEluY3JlYXNlIHBhZGRpbmcgYXJvdW5kIHRleHQgYm94ZXMNCiAgICBwb2ludC5wYWRkaW5nID0gMC4xLCAgIyBQYWRkaW5nIGJldHdlZW4gcG9pbnRzIGFuZCBsYWJlbHMNCiAgICBmb3JjZSA9IDIwLCAgIyBJbmNyZWFzZSByZXB1bHNpb24gYmV0d2VlbiBsYWJlbHMNCiAgICBmb3JjZV9wdWxsID0gMC4xLCAgIyBTbGlnaHQgcHVsbCB0byB0aGUgZGF0YSBwb2ludHMsIGVuc3VyaW5nIGFsaWdubWVudA0KICAgIG1pbi5zZWdtZW50Lmxlbmd0aCA9IDAuNSwgICMgQXZvaWQgb3Zlcmx5IHNob3J0IHNlZ21lbnQgbGluZXMNCiAgICBtYXgub3ZlcmxhcHMgPSBJbmYsICAjIEVuc3VyZSBhbGwgbGFiZWxzIGFyZSBzaG93bg0KICAgIHNlZ21lbnQuY29sb3IgPSAnYmxhY2snLCAgIyBMaW5lIGNvbG9yDQogICAgc2VnbWVudC5zaXplID0gMC4zICAjIFRoaW5uZXIgc2VnbWVudCBsaW5lcw0KICApDQojIFZpZXcNCnByZXR0eV9wY2FfcGxvdDENCmBgYA0KSSBsaWtlZCB0aGUgc3R5bGluZyBvZiB0aGUgcG9pbnRzIGFuZCBsYWJlbHMgaGVyZSwgYnV0IEkgd2FudGVkIHRoZSBheGVzIHRvIHJ1biB0aHJvdWdoIHRoZSBtaWRkbGUgb2YgdGhlIGRhdGEgaW5zdGVhZCBvZiBiZWluZyBvbiB0aGUgc2lkZXMuIEkgZGlkIHRoaXMgYnkgY3JlYXRpbmcgc29tZSBhcnJvdyBzdHlsZXMgYW5kIGFkZGluZyB0aGVtIG1hbnVhbGx5Og0KYGBge3IgcHJldHR5X3BjYV9wbG90X3BhcnQyfQ0KYXJyb3dfc3R5bGUgPC0gYXJyb3coDQogIGFuZ2xlID0gMjAsIGVuZHMgPSAiZmlyc3QiLCB0eXBlID0gImNsb3NlZCIsIGxlbmd0aCA9IGdyaWQ6OnVuaXQoNCwgInB0IikNCikNCg0KYXJyb3dfc3R5bGVfaW5kIDwtIGFycm93KA0KICBhbmdsZSA9IDQ1LCANCiAgbGVuZ3RoID0gZ3JpZDo6dW5pdCg4LCAicHQiKQ0KKQ0KDQpwcmV0dHlfcGNhX3Bsb3QyIDwtIHByZXR0eV9wY2FfcGxvdDEgKw0KICAjIHgtYXhpcyBsaW5lDQogIGFubm90YXRlKA0KICAgIGdlb20gPSAic2VnbWVudCIsIHggPSAtNSwgeGVuZCA9IDYsIHkgPSAwLCB5ZW5kID0gMCwNCiAgICBsdHkgPSAiZGFzaGVkIiwNCiAgICBjb2wgPSAiZ3JleTYwIiwNCiAgICBzaXplID0gMC41DQogICkgKw0KICAjIHgtYXhpcyBhcnJvdw0KICBhbm5vdGF0ZSgNCiAgICBnZW9tID0gInNlZ21lbnQiLCB4ID0gNS45LCB4ZW5kID0gNiwgeSA9IDAsIHllbmQgPSAwLA0KICAgIGNvbCA9ICJncmV5NjAiLA0KICAgIHNpemUgPSAwLjUsIGFycm93ID0gYXJyb3dfc3R5bGVfaW5kLCBsaW5lZW5kID0gJ3JvdW5kJywgbGluZWpvaW4gPSAncm91bmQnDQogICkgKw0KICAjIHgtYXhpcyBsYWJlbA0KICBhbm5vdGF0ZSgNCiAgICBnZW9tID0gInRleHQiLCB4ID0gNC43LCB5ID0gMC4yNSwgbGFiZWwgPSAiUHJpbmNpcGFsIENvbXBvbmVudCAxICgyNiUpIiwNCiAgICBjb2wgPSAiZGltZ3JleSIsIHNpemUgPSAzLCBmYW1pbHkgPSAic2FucyIsIGZvbnRmYWNlID0gIml0YWxpYyINCiAgKSArDQogICMgeS1heGlzIGxhYmVsDQogIGFubm90YXRlKA0KICAgIGdlb20gPSAidGV4dCIsIHggPSAtMC4xLCB5ID0gLTcuNywgbGFiZWwgPSAiUHJpbmNpcGFsIENvbXBvbmVudCAyICgyMiUpIiwNCiAgICBjb2wgPSAiZGltZ3JleSIsIHNpemUgPSAzLCBmYW1pbHkgPSAic2FucyIsIGFuZ2xlID0gOTAsIHZqdXN0ID0gMCwgaGp1c3QgPSAwLCBmb250ZmFjZSA9ICJpdGFsaWMiDQogICkgKw0KICAjIHktYXhpcw0KICBhbm5vdGF0ZSgNCiAgICBnZW9tID0gInNlZ21lbnQiLCB4ID0gMCwgeGVuZCA9IDAsIHkgPSAtNy44LCB5ZW5kID0gNSwgY29sID0gImdyZXk2MCIsIGx0eSA9ICJkYXNoZWQiLA0KICAgIHNpemUgPSAwLjUNCiAgKSArDQogICMgeS1heGlzIGFycm93DQogIGFubm90YXRlKA0KICAgIGdlb20gPSAic2VnbWVudCIsIHggPSAwLCB4ZW5kID0gMCwgeSA9IDQuOSwgeWVuZCA9IDUsIGNvbCA9ICJncmV5NjAiLA0KICAgIHNpemUgPSAwLjUsIGFycm93ID0gYXJyb3dfc3R5bGVfaW5kLCBsaW5lZW5kID0gJ3JvdW5kJywgbGluZWpvaW4gPSAncm91bmQnDQogICkNCnByZXR0eV9wY2FfcGxvdDINCg0KYGBgDQpOb3csIHRoZXJlIGFyZSB0b28gbWFueSBheGVzIGFuZCB0aGUgYmFja2dyb3VuZCBkb2VzIG5vdCBmaXQgdGhlIHN0eWxlIGFueW1vcmUuIEkgZml4ZWQgaXQgbGlrZSB0aGlzOiANCmBgYHtyIHByZXR0eV9wY2FfcGxvdF9wYXJ0M30NCnByZXR0eV9wY2FfcGxvdDMgPC0gcHJldHR5X3BjYV9wbG90MiArDQogICMgU2V0IG1pbmltYWwgdGhlbWUNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwgIyBObyBncmlkDQogICAgIyBObyBheGlzIGxhYmVscw0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksDQogICkNCnByZXR0eV9wY2FfcGxvdDMNCmBgYA0KVGhpcyBwbG90IG5vdyByZWFsbHkgbWlzc2VzIHNvbWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiwgc3VjaCBhcyB3aGF0IHR5cGUgb2YgZGF0YSB3ZSBhcmUgbG9va2luZyBhdCwgd2hhdCBraW5kIG9mIGFuYWx5c2lzIHdhcyBwZXJmb3JtZWQgYW5kIHRoZSBkYXRhIHNvdXJjZS4gSSBhbHNvIGluY29ycG9yYXRlZCB0aGUgbGVnZW5kIGludG8gdGhlIHN1YnRpdGxlLg0KYGBge3IgcHJldHR5X3BjYV9wbG90X3BhcnQ0fQ0KIyBDcmVhdGUgdGl0bGUgb2JqZWN0DQptYWludGl0bGU8LWNiaW5kLmRhdGEuZnJhbWUoDQogICMgUG9zaXRpb24gb24gbGVmdCB0b3ANCiAgeCA9IC01LCB5ID0gOS41LA0KICAjIEdsdWUgZm9yIEhUTUwgc3R5bGluZw0KICBsYWJlbCA9IGdsdWUoIjxzcGFuIHN0eWxlPSdjb2xvcjpkYXJrcmVkJz5QQ0EgUm9sbGluZyBTdG9uZSB0b3AgMTAwIG1ldGFsIGFsYnVtcyBvZiBhbGwgdGltZTwvc3Bhbj4iKQ0KKQ0KDQojIFN1YnRpdGxlIG9iamVjdA0Kc3VidGl0bGUgPC0gY2JpbmQuZGF0YS5mcmFtZSgNCiAgIyBQb3NpdGlvbiBiZWxvdyB0aXRsZQ0KICB4ID0gLTUsIHkgPSA4LjUsDQogICMgR2x1ZSBmb3IgSFRNTCBzdHlsaW5nLCBpbmNsdWRlIGxlZ2VuZCBjb2xvcnMNCiAgbGFiZWwgPSBnbHVlKCI8c3BhbiBzdHlsZT0nY29sb3I6IzJiMmEzMCc+UHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcyBvZiBtZXRhbCBzb25ncycgZmVhdHVyZXMgZnJvbSB0aGU8YnI+Um9sbGluZyBTdG9uZSB0b3AgMTAwIE1ldGFsIEFsYnVtcyBmcm9tIDwvc3Bhbj48YiBzdHlsZT0nY29sb3I6YmxhY2snPiAxOTcwIDwvYj48c3BhbiBzdHlsZT0nY29sb3I6IzJiMmEzMCc+dG88L3NwYW4+PGIgc3R5bGU9J2NvbG9yOnJlZCc+IDIwMTMgPC9iPjxzcGFuIHN0eWxlPSdjb2xvcjojMmIyYTMwJz4uPGJyPkVhY2ggZG90IHN0YW5kcyBmb3IgYSBzb25nLCB3aXRoIHRpdGxlIGFuZCBhcnRpc3QgZm9yIHNvbWUgZmF2b3JpdGUgdHJhY2tzLjwvc3Bhbj4gIikNCikNCg0KcHJldHR5X3BjYV9wbG90NCA8LSBwcmV0dHlfcGNhX3Bsb3QzICsNCiAgYW5ub3RhdGUoDQogICAgZ2VvbSA9ICJ0ZXh0IiwgeCA9IDYsIHkgPSAtNy41LCBoanVzdCA9IDEsIGNvbG9yID0gImRpbWdyZXkiLA0KICAgIGxhYmVsID0gIkRhdGE6IGRhdGEud29ybGQiLA0KICAgIHNpemUgPSAyLCBmYW1pbHkgPSAiY2FiaW4iLCBsaW5laGVpZ2h0ID0gMC40DQogICkgKw0KICBnZW9tX3JpY2h0ZXh0KA0KICAgIGRhdGEgPSBtYWludGl0bGUsDQogICAgYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBsYWJlbCksDQogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgbGluZWhlaWdodCA9IDAuNSwNCiAgICBhbHBoYSA9IDEsIHNpemUgPSA3LCBmYW1pbHkgPSAnY2FiaW4nLCBoanVzdCA9IDAsIHZqdXN0ID0gMSwNCiAgICBmaWxsID0gTkEsIGxhYmVsLmNvbG9yID0gTkEsIA0KICAgIGxhYmVsLnBhZGRpbmcgPSBncmlkOjp1bml0KHJlcCgwLCA0KSwgInB0IikNCiAgKSArDQogIGdlb21fcmljaHRleHQoDQogICAgZGF0YSA9IHN1YnRpdGxlLA0KICAgIGFlcyh4ID0geCwgeSA9IHksIGxhYmVsID0gbGFiZWwpLA0KICAgIGluaGVyaXQuYWVzID0gRkFMU0UsIGxpbmVoZWlnaHQgPSAwLjUsDQogICAgYWxwaGEgPSAxLCBzaXplID0gNSwgZmFtaWx5ID0gJ2NhYmluJywgaGp1c3QgPSAwLCB2anVzdCA9IDEsDQogICAgZmlsbCA9IE5BLCBsYWJlbC5jb2xvciA9IE5BLCANCiAgICBsYWJlbC5wYWRkaW5nID0gZ3JpZDo6dW5pdChyZXAoMCwgNCksICJwdCIpDQogICkgKw0KICAjIFJlbW92ZSBvcmlnaW5hbCBsZWdlbmQNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCnByZXR0eV9wY2FfcGxvdDQNCmBgYA0KVGhpcyBsb29rcyBnb29kISBCdXQsIEkgaGF2ZSBhbHNvIGNyZWF0ZWQgYSBwbG90IG9mIHZhcmlhYmxlcyB0aGF0IEkgd2FudCB0byBpbmNsdWRlIGluIHRoaXMgZmlndXJlLiBJIHVzZWQgYHBhdGNod29ya2AgdG8gY29tYmluZSB0aGVzZSB0d28gcGxvdHMgaW50byBvbmUuDQpgYGB7ciBjb21iaW5lZF9wbG90c19wYXJ0MX0NCiMgTWFrZSBwbG90IHdpdGggcGF0Y2h3b3JrDQpsYXlvdXQgPSBjKA0KICBhcmVhKHQgPSAwLCBsID0gMCwgYiA9IDEwLCByID0gMTUpLCAjIExhcmdlIGFyZWENCiAgYXJlYSh0ID0gMCwgbCA9IDYsIGIgPSA1LCByID0gMTcpICMgU21hbGxlciBhcmVhIGluIHJpZ2h0IGNvcm5lcg0KKSAgDQpwcmV0dHlfcGNhX3Bsb3Q0K3ByZXR0eV92YXJfcGxvdCtwbG90X2xheW91dChkZXNpZ249bGF5b3V0KQ0KYGBgDQpPa2F5LCBvbmUgZmluYWwgdG91Y2ghIEkgd2FudCB0byBoZWxwIHRoZSB2aWV3ZXIgdW5kZXJzdGFuZCB0aGUgcGxvdCBvZiB2YXJpYWJsZXMgYmV0dGVyLCBzbyBJIHdhbnQgdG8gYWRkIGEgZGVzY3JpcHRpb24gb2YgdGhlIHZhcmlhYmxlIHBsb3QgdG8gdGhlIGZpZ3VyZToNCmBgYHtyIGNvbWJpbmVkX3Bsb3RzX3BhcnQyfQ0KcHJldHR5X3BjYV9wbG90NSA8LSBwcmV0dHlfcGNhX3Bsb3Q0ICsNCiAgIyBBZGQgbm90ZSBmb3IgdmFyaWFibGUgcGxvdA0KICBhbm5vdGF0ZSgNCiAgZ2VvbSA9ICJ0ZXh0IiwgeCA9IDMuMiwgeSA9IDMuMywgaGp1c3QgPSAwLjUsIGxhYmVsID0gIkFsYnVtIHJhbmtpbmcgaXNcbiBoZWF2aWx5IGluZmx1ZW5jZWRcbiBieSByZWxlYXNlIHllYXIiLA0KICBzaXplID0gMy44LCBmYW1pbHkgPSAiY2FiaW4iLCBsaW5laGVpZ2h0ID0gMQ0KICApDQpwcmV0dHlfcGNhX3Bsb3Q1K3ByZXR0eV92YXJfcGxvdCtwbG90X2xheW91dChkZXNpZ249bGF5b3V0KQ0KYGBgDQpVbmZvcnR1bmF0ZWx5LCBzb21lIG9mIHRoZSBsYWJlbCBwb3NpdGlvbnMga2VlcCBjaGFuZ2luZyBkdWUgdG8gdGhlIHVzZSBvZiBgcGF0Y2h3b3JrYCwgYnV0IHRoaXMgaXMgdGhlIGJlc3QgSSBjb3VsZCBhY2hpZXZlIHdpdGggbXkgc2tpbGxzLiANCg0KVGhpcyBwbG90IHNob3dzIHRoYXQgdGhlIHJlbGVhc2UgeWVhciBvZiB0aGUgYWxidW0gb2YgdGhlIHNvbmdzIGNvcnJlbGF0ZXMgdGhlIG1vc3Qgd2l0aCB0aGUgcmFuayBvZiB0aGUgYWxidW1zLCB3aGljaCBzaG93cyB0aGF0IFJvbGxpbmcgU3RvbmUgcmFua2VkIG9sZGVyIG1ldGFsIGFsYnVtcyBoaWdoZXIgdGhhbiB0aGUgbmV3ZXIgbWV0YWwgYWxidW1zLiBJdCBhbHNvIHNob3dzIHRoYXQgbXkgcGVyc29uYWwgdGFzdGUgZGlmZmVycyBsZWFucyB0b3dhcmRzIHRoZSBsZWZ0IGFuZCBkYXJrZXIgc2lkZSBvZiB0aGUgbWFpbiBjbG91ZCBvZiBzb25ncywgd2hpY2ggbWVhbnMgdGhhdCBJIHByZWZlciBvbGRlciBzb25ncyB0b28gbmV3IG9uZXMuIA0KDQpUaGlzIGRvY3VtZW50IHdpbGwgYmUgaW1wcm92ZWQgaW4gdGhlIGZ1dHVyZSENCg==
© 2025 Birgit Rijvers   •