In the realm of data analysis and visualization, the ability to effectively communicate insights through graphical representations is paramount. One of the most powerful tools for achieving this is the ggplot2 library in R. This library allows for the creation of sophisticated and aesthetically pleasing visualizations that can convey complex data in an accessible manner.

A foundational ggplot visualization serves as the starting point for exploring and presenting data. It involves the basic construction of plots using the ggplot() function, which specifies the variables for the x and y axes. By leveraging the geom_line() function, one can create line plots that illustrate trends and patterns over time. Additionally, the customization of axis labels and plot colors enhances the clarity and interpretability of the visualizations.

Throughout this introduction, we will delve into the essential steps for creating these foundational visualizations, using the mtcars dataset as a practical example.

1. Libraries

library(ggplot2)
library(tidyverse)
library(plotly)

2. Dataset

The mtcars dataset in R is designed to provide a comprehensive overview of various car models, focusing on their performance and characteristics. It is widely used for statistical analysis and machine learning tasks, allowing users to explore relationships between different aspects of car performance and make predictions based on these data points.

mtcars

The mtcars dataset contains data on 32 car models and 11 variables related to their performance and characteristics. The variables include:

  • mpg: Miles per gallon (fuel efficiency).
  • cyl: Number of cylinders.
  • disp: Displacement (in cubic inches).
  • hp: Horsepower.
  • drat: Rear axle ratio.
  • wt: Weight (in 1000 lbs).
  • qsec: 1/4 mile time.
  • vs: Engine (0 = V-shaped, 1 = Straight).
  • am: Transmission (0 = automatic, 1 = manual).
  • gear: Number of forward gears.
  • carb: Number of carburetors.

3. Explore data

glimpse(mtcars)
Rows: 32
Columns: 11
$ mpg  <dbl> 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.…
$ cyl  <dbl> 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, …
$ disp <dbl> 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 14…
$ hp   <dbl> 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123,…
$ drat <dbl> 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.9…
$ wt   <dbl> 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.…
$ qsec <dbl> 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20…
$ vs   <dbl> 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, …
$ am   <dbl> 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ gear <dbl> 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, …
$ carb <dbl> 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, …

4. Create Basic Charts with ggplot2

4.1 Bar chart

Bar charts are crucial for visualizing categorical data and comparing different groups. They are effective because they allow for quick comparison between different categories or groups, help identify patterns or trends in the data, and provide a clear and straightforward representation of quantitative information, making it easier to interpret and communicate. Bar charts are widely used in various fields such as economics, social sciences, and business due to their simplicity and effectiveness in conveying complex information in an accessible manner.


qplot(mtcars$cyl,
      geom = "bar",
      fill = I("red"),
      colour = I("black"),
      xlab = "Cylinders",
      ylab = "Number of Vehicles",
      main = "Cylinders in mtcars") +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    axis.title.x = element_text(size = 14),
    axis.title.y = element_text(size = 14)
  )

The bar chart represents the number of vehicles in the mtcars dataset based on the number of cylinders they have. The horizontal axis (x-axis) shows the categories for the number of cylinders (4, 6, and 8), while the vertical axis (y-axis) shows the count of vehicles.

4.2 Histograms

Histograms are essential for visualizing the distribution of a dataset, allowing us to understand the frequency of data points within specified ranges (bins). They help identify patterns such as skewness, central tendency, and the spread of the data, as well as detect outliers and anomalies. By providing a clear graphical representation of the data’s distribution, histograms facilitate better decision-making and insights in various fields, including statistics, data analysis, and research.


qplot(mtcars$hp,
      geom = "histogram",
      binwidth = 20,
      fill = I("blue"),
      colour = I("black"),
      xlab = "Horsepower",
      ylab = "Number of Cars",
      alpha = I(1),
      main = "Histogram of Horsepower") +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    axis.title.x = element_text(size = 14),
    axis.title.y = element_text(size = 14)
  )

NA
NA

The histogram illustrates the distribution of cars based on their horsepower. The horizontal axis (x-axis) represents horsepower, ranging from 0 to over 300 horsepower. The vertical axis (y-axis) shows the number of cars, ranging from 0 to over 7.5.

The histogram features several blue bars, each representing different ranges of horsepower and the corresponding number of cars within each range. The tallest bar is in the range between approximately 75 and 100 horsepower, indicating that there are about 7.5 cars in this range. Another significant peak is observed between the ranges of approximately 125 and 150 horsepower, with around 4 cars.

Overall, most cars have horsepower below 150, with a notable decrease in frequency as horsepower increases beyond this range. There are very few cars with horsepower above 250.

4.3 Pie Chart

Pie charts are important for visualizing the proportions of different categories within a dataset. They clearly show the relative sizes of parts to the whole, making it easy to compare proportions. This type of chart provides a straightforward and intuitive way to understand the distribution of categories, which is particularly useful when you want to highlight the composition of a dataset. Additionally, pie charts are visually engaging and can quickly convey information at a glance, making them a popular choice in business, marketing, and social sciences for presenting data in an easily interpretable manner.

# Convert cyl to factor 

mtcars <- mtcars %>%
  mutate(cyl_factor = as.factor(cyl))

In this code, the mutate function from the dplyr package is used to create a new column called cyl_factor by converting the existing cyl column into a factor. This transformation is useful for categorical data analysis and visualization.


ggplot(data = mtcars, aes(x = cyl_factor, fill = cyl_factor)) +
  geom_bar(position = "dodge") +
  labs(
    title = "Number of Cars by Cylinder Count",
    x = "Number of Cylinders",
    y = "Count of Cars",
    fill = "Cylinders"
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    axis.title.x = element_text(size = 14),
    axis.title.y = element_text(size = 14),
    legend.title = element_text(size = 12),
    legend.text = element_text(size = 10)
)

The bar chart illustrates the number of cars based on their cylinder count. The vertical axis represents the “Count of Cars,” while the horizontal axis shows the “Number of Cylinders.” There are three bars, each representing a different cylinder count: 4, 6, and 8.

  • The red bar represents cars with 4 cylinders.
  • The green bar represents cars with 6 cylinders.
  • The blue bar represents cars with 8 cylinders.

The height of each bar indicates the number of cars with that specific cylinder count. From the chart, we can see that cars with 8 cylinders are the most common, followed by cars with 4 cylinders, and then cars with 6 cylinders.

4.4 Stacked bar chart

Stacked bar charts are important for visualizing the composition of different categories within a dataset, allowing for a detailed comparison of sub-groups within each category. They enable the comparison of multiple sub-groups within each category, providing a more granular view of the data. By showing the proportion of each sub-group relative to the total, stacked bar charts make it easy to see how each part contributes to the whole. This type of chart helps identify trends and patterns across different categories and sub-groups, facilitating better understanding of the data.


ggplot(data = mtcars, aes(x = "", fill = cyl_factor)) +
  geom_bar(position = "stack") +
  labs(
    title = "Distribution of Cars by Cylinder Count",
    x = "",
    y = "Count of Cars",
    fill = "Cylinders"
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    axis.title.y = element_text(size = 14),
    legend.title = element_text(size = 12),
    legend.text = element_text(size = 10)
  )

ggplot( data = mtcars,
        aes(x = " " ,
            fill = cyl_factor))+
  geom_bar(position = "stack") +
  coord_polar(theta = "y") + 
  scale_fill_brewer(palette = "Dark2") +
  theme_classic()

From this pie chart, you can gain several insights about the distribution of cars based on their cylinder count in the mtcars dataset. The chart visually represents the proportion of cars with different cylinder counts, making it easy to see which cylinder count is most common and which is least common among the cars in the dataset. The largest segment of the pie chart indicates the most prevalent cylinder count. In this case, cars with 8 cylinders form the largest segment, suggesting they are the most common in the dataset.

By comparing the sizes of the segments, you can easily understand the relative frequency of each cylinder count. For example, cars with 4 cylinders are more common than those with 6 cylinders, but less common than those with 8 cylinders. This comparison helps in understanding the distribution and prevalence of different cylinder counts within the dataset.

The pie chart provides a clear and immediate understanding of how the dataset is composed in terms of cylinder counts. This visualization is useful for quickly grasping the overall composition of the dataset, which can be beneficial for further analysis or decision-making.

Example of GGPLOT2
ggplot(mtcars, aes(x = hp, y = mpg, color = factor(cyl), shape = factor(cyl))) +
    geom_point(size=2) + 
    labs(x = "Gross horsepower", 
         y = "Miles/gallon", 
         color = "Cylinders", 
         shape = "Cylinders", 
         title = "Mileage by horsepower and number of cylinders",
         subtitle = "Data source: 1974 Motor Trend US magazine") +
    theme_dark() +
    scale_color_brewer(palette = "Set2")

The graph shows the relationship between mileage (miles per gallon) and gross horsepower of vehicles, differentiated by the number of cylinders. The data is from the 1974 Motor Trend US magazine. On the vertical axis, we have miles per gallon, ranging from 10 to 35. On the horizontal axis, we have gross horsepower, ranging from 50 to 350. The points on the graph are color-coded and shaped to represent different numbers of cylinders: green for 4 cylinders, orange for 6 cylinders, and blue for 8 cylinders.

There is a clear inverse relationship between horsepower and miles per gallon. As horsepower increases, the miles per gallon tend to decrease. This indicates that more powerful cars generally have lower fuel efficiency. Cars with 4 cylinders tend to have higher fuel efficiency (higher mpg) and lower horsepower, clustering towards the top-left of the graph. Cars with 6 cylinders have a moderate range of horsepower and fuel efficiency, positioned in the middle of the graph. Cars with 8 cylinders generally have higher horsepower and lower fuel efficiency, clustering towards the bottom-right of the graph.

The most fuel-efficient cars (highest mpg) are those with 4 cylinders and lower horsepower. Conversely, the least fuel-efficient cars are those with 8 cylinders and higher horsepower. The graph highlights the trade-off between performance (horsepower) and fuel efficiency (mpg). Higher performance vehicles (more horsepower) tend to sacrifice fuel efficiency.

This visualization helps in understanding how the number of cylinders and horsepower affect the fuel efficiency of vehicles, providing valuable insights for both consumers and manufacturers.

4.5 Scatter Plots

Scatter plots are an essential tool in data visualization and analysis, offering numerous benefits that enhance our understanding of data. One of the primary advantages of scatter plots is their ability to visualize relationships between two quantitative variables. By plotting data points on a two-dimensional graph, scatter plots help identify patterns, trends, and correlations, making it easier to understand how one variable affects another. This visual representation is crucial for making data-driven decisions and forming hypotheses.


ggplot(mtcars, aes(x = mpg, y = wt, shape = cyl_factor, color = cyl_factor)) +
  geom_point(size = 3) +  # Size of the points
  labs(title = "Relationship Between MPG and Weight of Cars",
       x = "Miles Per Gallon (MPG)",
       y = "Weight (1000 lbs)",
       shape = "Number of Cylinders",
       color = "Number of Cylinders") + # Custom labels
  theme_minimal() # Minimalist theme for a clean look

The scatter plot reveals a negative correlation between miles per gallon (MPG) and the weight of cars. Generally, as the weight of the car increases, the MPG decreases. This indicates that heavier cars tend to be less fuel-efficient. Understanding this relationship is crucial for assessing how vehicle weight impacts fuel efficiency.

4.6 Box Plot

A box plot is a crucial tool in data analysis as it visually summarizes the distribution of a dataset, highlighting the median, quartiles, and potential outliers, which helps in quickly understanding the central tendency, spread, and overall range of the data, making it easier to compare multiple datasets, identify anomalies, and support informed decision-making across various fields.


ggplot(mtcars, aes(x = factor(cyl), y = mpg)) + 
  geom_boxplot() +
  labs(
    title = "Distribution of Miles per Gallon by Number of Cylinders",
    x = "Number of Cylinders",
    y = "Miles per Gallon"
  ) +
 theme_classic()

The box plot illustrates the relationship between the number of cylinders in a vehicle and its miles per gallon (MPG) performance. Vehicles with 4 cylinders have a median MPG of around 25, with an interquartile range (IQR) from approximately 22 to 30. Vehicles with 6 cylinders have a median MPG of about 18, with an IQR from roughly 16 to 20. Vehicles with 8 cylinders have a median MPG of around 14, with an IQR from about 13 to 15. The plot also highlights that vehicles with fewer cylinders generally achieve higher MPG, and it identifies some outliers, particularly among vehicles with more cylinders.

LS0tDQp0aXRsZTogIioqQ3JlYXRpbmcgYSBmb3VuZGF0aW9uYWwgZ2dwbG90IHZpc3VhbGl6YXRpb24uKioiDQphdXRob3I6IE1pZ3VlbGFuZ2VsIFBhbG1hIFJvamFzDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2RlcHRoOiA1DQotLS0NCg0KSW4gdGhlIHJlYWxtIG9mIGRhdGEgYW5hbHlzaXMgYW5kIHZpc3VhbGl6YXRpb24sIHRoZSBhYmlsaXR5IHRvIGVmZmVjdGl2ZWx5IGNvbW11bmljYXRlIGluc2lnaHRzIHRocm91Z2ggZ3JhcGhpY2FsIHJlcHJlc2VudGF0aW9ucyBpcyBwYXJhbW91bnQuIE9uZSBvZiB0aGUgbW9zdCBwb3dlcmZ1bCB0b29scyBmb3IgYWNoaWV2aW5nIHRoaXMgaXMgdGhlIGBnZ3Bsb3QyYCBsaWJyYXJ5IGluIFIuIFRoaXMgbGlicmFyeSBhbGxvd3MgZm9yIHRoZSBjcmVhdGlvbiBvZiBzb3BoaXN0aWNhdGVkIGFuZCBhZXN0aGV0aWNhbGx5IHBsZWFzaW5nIHZpc3VhbGl6YXRpb25zIHRoYXQgY2FuIGNvbnZleSBjb21wbGV4IGRhdGEgaW4gYW4gYWNjZXNzaWJsZSBtYW5uZXIuDQoNCkEgZm91bmRhdGlvbmFsIGdncGxvdCB2aXN1YWxpemF0aW9uIHNlcnZlcyBhcyB0aGUgc3RhcnRpbmcgcG9pbnQgZm9yIGV4cGxvcmluZyBhbmQgcHJlc2VudGluZyBkYXRhLiBJdCBpbnZvbHZlcyB0aGUgYmFzaWMgY29uc3RydWN0aW9uIG9mIHBsb3RzIHVzaW5nIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uLCB3aGljaCBzcGVjaWZpZXMgdGhlIHZhcmlhYmxlcyBmb3IgdGhlIHggYW5kIHkgYXhlcy4gQnkgbGV2ZXJhZ2luZyB0aGUgYGdlb21fbGluZSgpYCBmdW5jdGlvbiwgb25lIGNhbiBjcmVhdGUgbGluZSBwbG90cyB0aGF0IGlsbHVzdHJhdGUgdHJlbmRzIGFuZCBwYXR0ZXJucyBvdmVyIHRpbWUuIEFkZGl0aW9uYWxseSwgdGhlIGN1c3RvbWl6YXRpb24gb2YgYXhpcyBsYWJlbHMgYW5kIHBsb3QgY29sb3JzIGVuaGFuY2VzIHRoZSBjbGFyaXR5IGFuZCBpbnRlcnByZXRhYmlsaXR5IG9mIHRoZSB2aXN1YWxpemF0aW9ucy4NCg0KVGhyb3VnaG91dCB0aGlzIGludHJvZHVjdGlvbiwgd2Ugd2lsbCBkZWx2ZSBpbnRvIHRoZSBlc3NlbnRpYWwgc3RlcHMgZm9yIGNyZWF0aW5nIHRoZXNlIGZvdW5kYXRpb25hbCB2aXN1YWxpemF0aW9ucywgdXNpbmcgdGhlICoqbXRjYXJzKiogZGF0YXNldCBhcyBhIHByYWN0aWNhbCBleGFtcGxlLiANCg0KIyMjICoqMS4gTGlicmFyaWVzICoqDQoNCmBgYHtyIHNldHVwICwgbWVzc2FnZT1GQUxTRSAsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCiMjIyAqKjIuIERhdGFzZXQqKg0KDQpUaGUgKiptdGNhcnMqKiBkYXRhc2V0IGluIFIgaXMgZGVzaWduZWQgdG8gcHJvdmlkZSBhIGNvbXByZWhlbnNpdmUgb3ZlcnZpZXcgb2YgdmFyaW91cyBjYXIgbW9kZWxzLCBmb2N1c2luZyBvbiB0aGVpciBwZXJmb3JtYW5jZSBhbmQgY2hhcmFjdGVyaXN0aWNzLiBJdCBpcyB3aWRlbHkgdXNlZCBmb3Igc3RhdGlzdGljYWwgYW5hbHlzaXMgYW5kIG1hY2hpbmUgbGVhcm5pbmcgdGFza3MsIGFsbG93aW5nIHVzZXJzIHRvIGV4cGxvcmUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGRpZmZlcmVudCBhc3BlY3RzIG9mIGNhciBwZXJmb3JtYW5jZSBhbmQgbWFrZSBwcmVkaWN0aW9ucyBiYXNlZCBvbiB0aGVzZSBkYXRhIHBvaW50cy4NCg0KDQpgYGB7cn0NCm10Y2Fycw0KYGBgDQpUaGUgX18qKm10Y2FycyoqX18gZGF0YXNldCBjb250YWlucyBkYXRhIG9uIDMyIGNhciBtb2RlbHMgYW5kIDExIHZhcmlhYmxlcyByZWxhdGVkIHRvIHRoZWlyIHBlcmZvcm1hbmNlIGFuZCBjaGFyYWN0ZXJpc3RpY3MuIFRoZSB2YXJpYWJsZXMgaW5jbHVkZToNCg0KLSAqKm1wZyoqOiBNaWxlcyBwZXIgZ2FsbG9uIChmdWVsIGVmZmljaWVuY3kpLg0KLSAqKmN5bCoqOiBOdW1iZXIgb2YgY3lsaW5kZXJzLg0KLSAqKmRpc3AqKjogRGlzcGxhY2VtZW50IChpbiBjdWJpYyBpbmNoZXMpLg0KLSAqKmhwKio6IEhvcnNlcG93ZXIuDQotICoqZHJhdCoqOiBSZWFyIGF4bGUgcmF0aW8uDQotICoqd3QqKjogV2VpZ2h0IChpbiAxMDAwIGxicykuDQotICoqcXNlYyoqOiAxLzQgbWlsZSB0aW1lLg0KLSAqKnZzKio6IEVuZ2luZSAoMCA9IFYtc2hhcGVkLCAxID0gU3RyYWlnaHQpLg0KLSAqKmFtKio6IFRyYW5zbWlzc2lvbiAoMCA9IGF1dG9tYXRpYywgMSA9IG1hbnVhbCkuDQotICoqZ2VhcioqOiBOdW1iZXIgb2YgZm9yd2FyZCBnZWFycy4NCi0gKipjYXJiKio6IE51bWJlciBvZiBjYXJidXJldG9ycy4NCg0KDQojIyMgKiozLiBFeHBsb3JlIGRhdGEqKg0KDQpgYGB7cn0NCmdsaW1wc2UobXRjYXJzKQ0KYGBgDQoNCiMjIyAgKio0LiBDcmVhdGUgQmFzaWMgQ2hhcnRzIHdpdGggZ2dwbG90MioqDQoNCg0KIyMjIyBfNC4xIEJhciBjaGFydF8NCg0KQmFyIGNoYXJ0cyBhcmUgY3J1Y2lhbCBmb3IgdmlzdWFsaXppbmcgY2F0ZWdvcmljYWwgZGF0YSBhbmQgY29tcGFyaW5nIGRpZmZlcmVudCBncm91cHMuIFRoZXkgYXJlIGVmZmVjdGl2ZSBiZWNhdXNlIHRoZXkgYWxsb3cgZm9yIHF1aWNrIGNvbXBhcmlzb24gYmV0d2VlbiBkaWZmZXJlbnQgY2F0ZWdvcmllcyBvciBncm91cHMsIGhlbHAgaWRlbnRpZnkgcGF0dGVybnMgb3IgdHJlbmRzIGluIHRoZSBkYXRhLCBhbmQgcHJvdmlkZSBhIGNsZWFyIGFuZCBzdHJhaWdodGZvcndhcmQgcmVwcmVzZW50YXRpb24gb2YgcXVhbnRpdGF0aXZlIGluZm9ybWF0aW9uLCBtYWtpbmcgaXQgZWFzaWVyIHRvIGludGVycHJldCBhbmQgY29tbXVuaWNhdGUuIEJhciBjaGFydHMgYXJlIHdpZGVseSB1c2VkIGluIHZhcmlvdXMgZmllbGRzIHN1Y2ggYXMgZWNvbm9taWNzLCBzb2NpYWwgc2NpZW5jZXMsIGFuZCBidXNpbmVzcyBkdWUgdG8gdGhlaXIgc2ltcGxpY2l0eSBhbmQgZWZmZWN0aXZlbmVzcyBpbiBjb252ZXlpbmcgY29tcGxleCBpbmZvcm1hdGlvbiBpbiBhbiBhY2Nlc3NpYmxlIG1hbm5lci4NCg0KYGBge3J9DQoNCnFwbG90KG10Y2FycyRjeWwsDQogICAgICBnZW9tID0gImJhciIsDQogICAgICBmaWxsID0gSSgicmVkIiksDQogICAgICBjb2xvdXIgPSBJKCJibGFjayIpLA0KICAgICAgeGxhYiA9ICJDeWxpbmRlcnMiLA0KICAgICAgeWxhYiA9ICJOdW1iZXIgb2YgVmVoaWNsZXMiLA0KICAgICAgbWFpbiA9ICJDeWxpbmRlcnMgaW4gbXRjYXJzIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICkNCg0KYGBgDQoNClRoZSBiYXIgY2hhcnQgcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIHZlaGljbGVzIGluIHRoZSBgbXRjYXJzYCBkYXRhc2V0IGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzIHRoZXkgaGF2ZS4gVGhlIGhvcml6b250YWwgYXhpcyAoeC1heGlzKSBzaG93cyB0aGUgY2F0ZWdvcmllcyBmb3IgdGhlIG51bWJlciBvZiBjeWxpbmRlcnMgKDQsIDYsIGFuZCA4KSwgd2hpbGUgdGhlIHZlcnRpY2FsIGF4aXMgKHktYXhpcykgc2hvd3MgdGhlIGNvdW50IG9mIHZlaGljbGVzLg0KDQoNCiMjIyMgXzQuMiBIaXN0b2dyYW1zXw0KDQpIaXN0b2dyYW1zIGFyZSBlc3NlbnRpYWwgZm9yIHZpc3VhbGl6aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgYSBkYXRhc2V0LCBhbGxvd2luZyB1cyB0byB1bmRlcnN0YW5kIHRoZSBmcmVxdWVuY3kgb2YgZGF0YSBwb2ludHMgd2l0aGluIHNwZWNpZmllZCByYW5nZXMgKGJpbnMpLiBUaGV5IGhlbHAgaWRlbnRpZnkgcGF0dGVybnMgc3VjaCBhcyBza2V3bmVzcywgY2VudHJhbCB0ZW5kZW5jeSwgYW5kIHRoZSBzcHJlYWQgb2YgdGhlIGRhdGEsIGFzIHdlbGwgYXMgZGV0ZWN0IG91dGxpZXJzIGFuZCBhbm9tYWxpZXMuIEJ5IHByb3ZpZGluZyBhIGNsZWFyIGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGF0YSdzIGRpc3RyaWJ1dGlvbiwgaGlzdG9ncmFtcyBmYWNpbGl0YXRlIGJldHRlciBkZWNpc2lvbi1tYWtpbmcgYW5kIGluc2lnaHRzIGluIHZhcmlvdXMgZmllbGRzLCBpbmNsdWRpbmcgc3RhdGlzdGljcywgZGF0YSBhbmFseXNpcywgYW5kIHJlc2VhcmNoLg0KDQpgYGB7cn0NCg0KcXBsb3QobXRjYXJzJGhwLA0KICAgICAgZ2VvbSA9ICJoaXN0b2dyYW0iLA0KICAgICAgYmlud2lkdGggPSAyMCwNCiAgICAgIGZpbGwgPSBJKCJibHVlIiksDQogICAgICBjb2xvdXIgPSBJKCJibGFjayIpLA0KICAgICAgeGxhYiA9ICJIb3JzZXBvd2VyIiwNCiAgICAgIHlsYWIgPSAiTnVtYmVyIG9mIENhcnMiLA0KICAgICAgYWxwaGEgPSBJKDEpLA0KICAgICAgbWFpbiA9ICJIaXN0b2dyYW0gb2YgSG9yc2Vwb3dlciIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KQ0KICApDQoNCg0KYGBgDQpUaGUgaGlzdG9ncmFtIGlsbHVzdHJhdGVzIHRoZSBkaXN0cmlidXRpb24gb2YgY2FycyBiYXNlZCBvbiB0aGVpciBob3JzZXBvd2VyLiBUaGUgaG9yaXpvbnRhbCBheGlzICh4LWF4aXMpIHJlcHJlc2VudHMgaG9yc2Vwb3dlciwgcmFuZ2luZyBmcm9tIDAgdG8gb3ZlciAzMDAgaG9yc2Vwb3dlci4gVGhlIHZlcnRpY2FsIGF4aXMgKHktYXhpcykgc2hvd3MgdGhlIG51bWJlciBvZiBjYXJzLCByYW5naW5nIGZyb20gMCB0byBvdmVyIDcuNS4NCg0KVGhlIGhpc3RvZ3JhbSBmZWF0dXJlcyBzZXZlcmFsIGJsdWUgYmFycywgZWFjaCByZXByZXNlbnRpbmcgZGlmZmVyZW50IHJhbmdlcyBvZiBob3JzZXBvd2VyIGFuZCB0aGUgY29ycmVzcG9uZGluZyBudW1iZXIgb2YgY2FycyB3aXRoaW4gZWFjaCByYW5nZS4gVGhlIHRhbGxlc3QgYmFyIGlzIGluIHRoZSByYW5nZSBiZXR3ZWVuIGFwcHJveGltYXRlbHkgNzUgYW5kIDEwMCBob3JzZXBvd2VyLCBpbmRpY2F0aW5nIHRoYXQgdGhlcmUgYXJlIGFib3V0IDcuNSBjYXJzIGluIHRoaXMgcmFuZ2UuIEFub3RoZXIgc2lnbmlmaWNhbnQgcGVhayBpcyBvYnNlcnZlZCBiZXR3ZWVuIHRoZSByYW5nZXMgb2YgYXBwcm94aW1hdGVseSAxMjUgYW5kIDE1MCBob3JzZXBvd2VyLCB3aXRoIGFyb3VuZCA0IGNhcnMuDQoNCk92ZXJhbGwsIG1vc3QgY2FycyBoYXZlIGhvcnNlcG93ZXIgYmVsb3cgMTUwLCB3aXRoIGEgbm90YWJsZSBkZWNyZWFzZSBpbiBmcmVxdWVuY3kgYXMgaG9yc2Vwb3dlciBpbmNyZWFzZXMgYmV5b25kIHRoaXMgcmFuZ2UuIFRoZXJlIGFyZSB2ZXJ5IGZldyBjYXJzIHdpdGggaG9yc2Vwb3dlciBhYm92ZSAyNTAuDQoNCg0KIyMjIyBfNC4zIFBpZSBDaGFydF8gDQoNClBpZSBjaGFydHMgYXJlIGltcG9ydGFudCBmb3IgdmlzdWFsaXppbmcgdGhlIHByb3BvcnRpb25zIG9mIGRpZmZlcmVudCBjYXRlZ29yaWVzIHdpdGhpbiBhIGRhdGFzZXQuIFRoZXkgY2xlYXJseSBzaG93IHRoZSByZWxhdGl2ZSBzaXplcyBvZiBwYXJ0cyB0byB0aGUgd2hvbGUsIG1ha2luZyBpdCBlYXN5IHRvIGNvbXBhcmUgcHJvcG9ydGlvbnMuIFRoaXMgdHlwZSBvZiBjaGFydCBwcm92aWRlcyBhIHN0cmFpZ2h0Zm9yd2FyZCBhbmQgaW50dWl0aXZlIHdheSB0byB1bmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2YgY2F0ZWdvcmllcywgd2hpY2ggaXMgcGFydGljdWxhcmx5IHVzZWZ1bCB3aGVuIHlvdSB3YW50IHRvIGhpZ2hsaWdodCB0aGUgY29tcG9zaXRpb24gb2YgYSBkYXRhc2V0LiBBZGRpdGlvbmFsbHksIHBpZSBjaGFydHMgYXJlIHZpc3VhbGx5IGVuZ2FnaW5nIGFuZCBjYW4gcXVpY2tseSBjb252ZXkgaW5mb3JtYXRpb24gYXQgYSBnbGFuY2UsIG1ha2luZyB0aGVtIGEgcG9wdWxhciBjaG9pY2UgaW4gYnVzaW5lc3MsIG1hcmtldGluZywgYW5kIHNvY2lhbCBzY2llbmNlcyBmb3IgcHJlc2VudGluZyBkYXRhIGluIGFuIGVhc2lseSBpbnRlcnByZXRhYmxlIG1hbm5lci4NCg0KYGBge3J9DQojIENvbnZlcnQgY3lsIHRvIGZhY3RvciANCg0KbXRjYXJzIDwtIG10Y2FycyAlPiUNCiAgbXV0YXRlKGN5bF9mYWN0b3IgPSBhcy5mYWN0b3IoY3lsKSkNCg0KYGBgDQoNCkluIHRoaXMgY29kZSwgdGhlIG11dGF0ZSBmdW5jdGlvbiBmcm9tIHRoZSBgZHBseXJgIHBhY2thZ2UgaXMgdXNlZCB0byBjcmVhdGUgYSBuZXcgY29sdW1uIGNhbGxlZCBgY3lsX2ZhY3RvcmAgYnkgY29udmVydGluZyB0aGUgZXhpc3RpbmcgYGN5bGAgY29sdW1uIGludG8gYSBmYWN0b3IuIFRoaXMgdHJhbnNmb3JtYXRpb24gaXMgdXNlZnVsIGZvciBjYXRlZ29yaWNhbCBkYXRhIGFuYWx5c2lzIGFuZCB2aXN1YWxpemF0aW9uLg0KDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QoZGF0YSA9IG10Y2FycywgYWVzKHggPSBjeWxfZmFjdG9yLCBmaWxsID0gY3lsX2ZhY3RvcikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTnVtYmVyIG9mIENhcnMgYnkgQ3lsaW5kZXIgQ291bnQiLA0KICAgIHggPSAiTnVtYmVyIG9mIEN5bGluZGVycyIsDQogICAgeSA9ICJDb3VudCBvZiBDYXJzIiwNCiAgICBmaWxsID0gIkN5bGluZGVycyINCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKQ0KKQ0KDQpgYGANClRoZSBiYXIgY2hhcnQgaWxsdXN0cmF0ZXMgdGhlIG51bWJlciBvZiBjYXJzIGJhc2VkIG9uIHRoZWlyIGN5bGluZGVyIGNvdW50LiBUaGUgdmVydGljYWwgYXhpcyByZXByZXNlbnRzIHRoZSAqKiJDb3VudCBvZiBDYXJzLCIqKiB3aGlsZSB0aGUgaG9yaXpvbnRhbCBheGlzIHNob3dzIHRoZSAqKiJOdW1iZXIgb2YgQ3lsaW5kZXJzLiIqKiBUaGVyZSBhcmUgdGhyZWUgYmFycywgZWFjaCByZXByZXNlbnRpbmcgYSBkaWZmZXJlbnQgY3lsaW5kZXIgY291bnQ6IDQsIDYsIGFuZCA4Lg0KDQotIFRoZSByZWQgYmFyIHJlcHJlc2VudHMgY2FycyB3aXRoIDQgY3lsaW5kZXJzLg0KLSBUaGUgZ3JlZW4gYmFyIHJlcHJlc2VudHMgY2FycyB3aXRoIDYgY3lsaW5kZXJzLg0KLSBUaGUgYmx1ZSBiYXIgcmVwcmVzZW50cyBjYXJzIHdpdGggOCBjeWxpbmRlcnMuDQoNClRoZSBoZWlnaHQgb2YgZWFjaCBiYXIgaW5kaWNhdGVzIHRoZSBudW1iZXIgb2YgY2FycyB3aXRoIHRoYXQgc3BlY2lmaWMgY3lsaW5kZXIgY291bnQuIEZyb20gdGhlIGNoYXJ0LCB3ZSBjYW4gc2VlIHRoYXQgY2FycyB3aXRoIDggY3lsaW5kZXJzIGFyZSB0aGUgbW9zdCBjb21tb24sIGZvbGxvd2VkIGJ5IGNhcnMgd2l0aCA0IGN5bGluZGVycywgYW5kIHRoZW4gY2FycyB3aXRoIDYgY3lsaW5kZXJzLg0KDQoNCiMjIyMgXzQuNCBTdGFja2VkIGJhciBjaGFydF8NCg0KU3RhY2tlZCBiYXIgY2hhcnRzIGFyZSBpbXBvcnRhbnQgZm9yIHZpc3VhbGl6aW5nIHRoZSBjb21wb3NpdGlvbiBvZiBkaWZmZXJlbnQgY2F0ZWdvcmllcyB3aXRoaW4gYSBkYXRhc2V0LCBhbGxvd2luZyBmb3IgYSBkZXRhaWxlZCBjb21wYXJpc29uIG9mIHN1Yi1ncm91cHMgd2l0aGluIGVhY2ggY2F0ZWdvcnkuIFRoZXkgZW5hYmxlIHRoZSBjb21wYXJpc29uIG9mIG11bHRpcGxlIHN1Yi1ncm91cHMgd2l0aGluIGVhY2ggY2F0ZWdvcnksIHByb3ZpZGluZyBhIG1vcmUgZ3JhbnVsYXIgdmlldyBvZiB0aGUgZGF0YS4gQnkgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiBlYWNoIHN1Yi1ncm91cCByZWxhdGl2ZSB0byB0aGUgdG90YWwsIHN0YWNrZWQgYmFyIGNoYXJ0cyBtYWtlIGl0IGVhc3kgdG8gc2VlIGhvdyBlYWNoIHBhcnQgY29udHJpYnV0ZXMgdG8gdGhlIHdob2xlLiBUaGlzIHR5cGUgb2YgY2hhcnQgaGVscHMgaWRlbnRpZnkgdHJlbmRzIGFuZCBwYXR0ZXJucyBhY3Jvc3MgZGlmZmVyZW50IGNhdGVnb3JpZXMgYW5kIHN1Yi1ncm91cHMsIGZhY2lsaXRhdGluZyBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgZGF0YS4NCg0KYGBge3J9DQoNCmdncGxvdChkYXRhID0gbXRjYXJzLCBhZXMoeCA9ICIiLCBmaWxsID0gY3lsX2ZhY3RvcikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIENhcnMgYnkgQ3lsaW5kZXIgQ291bnQiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIkNvdW50IG9mIENhcnMiLA0KICAgIGZpbGwgPSAiQ3lsaW5kZXJzIg0KICApICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApDQogICkNCg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KCBkYXRhID0gbXRjYXJzLA0KICAgICAgICBhZXMoeCA9ICIgIiAsDQogICAgICAgICAgICBmaWxsID0gY3lsX2ZhY3RvcikpKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQpGcm9tIHRoaXMgcGllIGNoYXJ0LCB5b3UgY2FuIGdhaW4gc2V2ZXJhbCBpbnNpZ2h0cyBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNhcnMgYmFzZWQgb24gdGhlaXIgY3lsaW5kZXIgY291bnQgaW4gdGhlIG10Y2FycyBkYXRhc2V0LiBUaGUgY2hhcnQgdmlzdWFsbHkgcmVwcmVzZW50cyB0aGUgcHJvcG9ydGlvbiBvZiBjYXJzIHdpdGggZGlmZmVyZW50IGN5bGluZGVyIGNvdW50cywgbWFraW5nIGl0IGVhc3kgdG8gc2VlIHdoaWNoIGN5bGluZGVyIGNvdW50IGlzIG1vc3QgY29tbW9uIGFuZCB3aGljaCBpcyBsZWFzdCBjb21tb24gYW1vbmcgdGhlIGNhcnMgaW4gdGhlIGRhdGFzZXQuIFRoZSBsYXJnZXN0IHNlZ21lbnQgb2YgdGhlIHBpZSBjaGFydCBpbmRpY2F0ZXMgdGhlIG1vc3QgcHJldmFsZW50IGN5bGluZGVyIGNvdW50LiBJbiB0aGlzIGNhc2UsIGNhcnMgd2l0aCA4IGN5bGluZGVycyBmb3JtIHRoZSBsYXJnZXN0IHNlZ21lbnQsIHN1Z2dlc3RpbmcgdGhleSBhcmUgdGhlIG1vc3QgY29tbW9uIGluIHRoZSBkYXRhc2V0Lg0KDQpCeSBjb21wYXJpbmcgdGhlIHNpemVzIG9mIHRoZSBzZWdtZW50cywgeW91IGNhbiBlYXNpbHkgdW5kZXJzdGFuZCB0aGUgcmVsYXRpdmUgZnJlcXVlbmN5IG9mIGVhY2ggY3lsaW5kZXIgY291bnQuIEZvciBleGFtcGxlLCBjYXJzIHdpdGggNCBjeWxpbmRlcnMgYXJlIG1vcmUgY29tbW9uIHRoYW4gdGhvc2Ugd2l0aCA2IGN5bGluZGVycywgYnV0IGxlc3MgY29tbW9uIHRoYW4gdGhvc2Ugd2l0aCA4IGN5bGluZGVycy4gVGhpcyBjb21wYXJpc29uIGhlbHBzIGluIHVuZGVyc3RhbmRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgcHJldmFsZW5jZSBvZiBkaWZmZXJlbnQgY3lsaW5kZXIgY291bnRzIHdpdGhpbiB0aGUgZGF0YXNldC4NCg0KVGhlIHBpZSBjaGFydCBwcm92aWRlcyBhIGNsZWFyIGFuZCBpbW1lZGlhdGUgdW5kZXJzdGFuZGluZyBvZiBob3cgdGhlIGRhdGFzZXQgaXMgY29tcG9zZWQgaW4gdGVybXMgb2YgY3lsaW5kZXIgY291bnRzLiBUaGlzIHZpc3VhbGl6YXRpb24gaXMgdXNlZnVsIGZvciBxdWlja2x5IGdyYXNwaW5nIHRoZSBvdmVyYWxsIGNvbXBvc2l0aW9uIG9mIHRoZSBkYXRhc2V0LCB3aGljaCBjYW4gYmUgYmVuZWZpY2lhbCBmb3IgZnVydGhlciBhbmFseXNpcyBvciBkZWNpc2lvbi1tYWtpbmcuDQoNCiMjIyMjIF9FeGFtcGxlIG9mIEdHUExPVDJfDQoNCg0KYGBge3J9DQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGhwLCB5ID0gbXBnLCBjb2xvciA9IGZhY3RvcihjeWwpLCBzaGFwZSA9IGZhY3RvcihjeWwpKSkgKw0KICAgIGdlb21fcG9pbnQoc2l6ZT0yKSArIA0KICAgIGxhYnMoeCA9ICJHcm9zcyBob3JzZXBvd2VyIiwgDQogICAgICAgICB5ID0gIk1pbGVzL2dhbGxvbiIsIA0KICAgICAgICAgY29sb3IgPSAiQ3lsaW5kZXJzIiwgDQogICAgICAgICBzaGFwZSA9ICJDeWxpbmRlcnMiLCANCiAgICAgICAgIHRpdGxlID0gIk1pbGVhZ2UgYnkgaG9yc2Vwb3dlciBhbmQgbnVtYmVyIG9mIGN5bGluZGVycyIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJEYXRhIHNvdXJjZTogMTk3NCBNb3RvciBUcmVuZCBVUyBtYWdhemluZSIpICsNCiAgICB0aGVtZV9kYXJrKCkgKw0KICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQ0KYGBgDQoNClRoZSBncmFwaCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbWlsZWFnZSAobWlsZXMgcGVyIGdhbGxvbikgYW5kIGdyb3NzIGhvcnNlcG93ZXIgb2YgdmVoaWNsZXMsIGRpZmZlcmVudGlhdGVkIGJ5IHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzLiBUaGUgZGF0YSBpcyBmcm9tIHRoZSAxOTc0IE1vdG9yIFRyZW5kIFVTIG1hZ2F6aW5lLiBPbiB0aGUgdmVydGljYWwgYXhpcywgd2UgaGF2ZSBtaWxlcyBwZXIgZ2FsbG9uLCByYW5naW5nIGZyb20gMTAgdG8gMzUuIE9uIHRoZSBob3Jpem9udGFsIGF4aXMsIHdlIGhhdmUgZ3Jvc3MgaG9yc2Vwb3dlciwgcmFuZ2luZyBmcm9tIDUwIHRvIDM1MC4gVGhlIHBvaW50cyBvbiB0aGUgZ3JhcGggYXJlIGNvbG9yLWNvZGVkIGFuZCBzaGFwZWQgdG8gcmVwcmVzZW50IGRpZmZlcmVudCBudW1iZXJzIG9mIGN5bGluZGVyczogZ3JlZW4gZm9yIDQgY3lsaW5kZXJzLCBvcmFuZ2UgZm9yIDYgY3lsaW5kZXJzLCBhbmQgYmx1ZSBmb3IgOCBjeWxpbmRlcnMuDQoNClRoZXJlIGlzIGEgY2xlYXIgaW52ZXJzZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBob3JzZXBvd2VyIGFuZCBtaWxlcyBwZXIgZ2FsbG9uLiBBcyBob3JzZXBvd2VyIGluY3JlYXNlcywgdGhlIG1pbGVzIHBlciBnYWxsb24gdGVuZCB0byBkZWNyZWFzZS4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBtb3JlIHBvd2VyZnVsIGNhcnMgZ2VuZXJhbGx5IGhhdmUgbG93ZXIgZnVlbCBlZmZpY2llbmN5LiBDYXJzIHdpdGggNCBjeWxpbmRlcnMgdGVuZCB0byBoYXZlIGhpZ2hlciBmdWVsIGVmZmljaWVuY3kgKGhpZ2hlciBtcGcpIGFuZCBsb3dlciBob3JzZXBvd2VyLCBjbHVzdGVyaW5nIHRvd2FyZHMgdGhlIHRvcC1sZWZ0IG9mIHRoZSBncmFwaC4gQ2FycyB3aXRoIDYgY3lsaW5kZXJzIGhhdmUgYSBtb2RlcmF0ZSByYW5nZSBvZiBob3JzZXBvd2VyIGFuZCBmdWVsIGVmZmljaWVuY3ksIHBvc2l0aW9uZWQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgZ3JhcGguIENhcnMgd2l0aCA4IGN5bGluZGVycyBnZW5lcmFsbHkgaGF2ZSBoaWdoZXIgaG9yc2Vwb3dlciBhbmQgbG93ZXIgZnVlbCBlZmZpY2llbmN5LCBjbHVzdGVyaW5nIHRvd2FyZHMgdGhlIGJvdHRvbS1yaWdodCBvZiB0aGUgZ3JhcGguDQoNClRoZSBtb3N0IGZ1ZWwtZWZmaWNpZW50IGNhcnMgKGhpZ2hlc3QgbXBnKSBhcmUgdGhvc2Ugd2l0aCA0IGN5bGluZGVycyBhbmQgbG93ZXIgaG9yc2Vwb3dlci4gQ29udmVyc2VseSwgdGhlIGxlYXN0IGZ1ZWwtZWZmaWNpZW50IGNhcnMgYXJlIHRob3NlIHdpdGggOCBjeWxpbmRlcnMgYW5kIGhpZ2hlciBob3JzZXBvd2VyLiBUaGUgZ3JhcGggaGlnaGxpZ2h0cyB0aGUgdHJhZGUtb2ZmIGJldHdlZW4gcGVyZm9ybWFuY2UgKGhvcnNlcG93ZXIpIGFuZCBmdWVsIGVmZmljaWVuY3kgKG1wZykuIEhpZ2hlciBwZXJmb3JtYW5jZSB2ZWhpY2xlcyAobW9yZSBob3JzZXBvd2VyKSB0ZW5kIHRvIHNhY3JpZmljZSBmdWVsIGVmZmljaWVuY3kuDQoNClRoaXMgdmlzdWFsaXphdGlvbiBoZWxwcyBpbiB1bmRlcnN0YW5kaW5nIGhvdyB0aGUgbnVtYmVyIG9mIGN5bGluZGVycyBhbmQgaG9yc2Vwb3dlciBhZmZlY3QgdGhlIGZ1ZWwgZWZmaWNpZW5jeSBvZiB2ZWhpY2xlcywgcHJvdmlkaW5nIHZhbHVhYmxlIGluc2lnaHRzIGZvciBib3RoIGNvbnN1bWVycyBhbmQgbWFudWZhY3R1cmVycy4NCg0KIyMjIyBfNC41IFNjYXR0ZXIgUGxvdHMgXw0KDQpTY2F0dGVyIHBsb3RzIGFyZSBhbiBlc3NlbnRpYWwgdG9vbCBpbiBkYXRhIHZpc3VhbGl6YXRpb24gYW5kIGFuYWx5c2lzLCBvZmZlcmluZyBudW1lcm91cyBiZW5lZml0cyB0aGF0IGVuaGFuY2Ugb3VyIHVuZGVyc3RhbmRpbmcgb2YgZGF0YS4gT25lIG9mIHRoZSBwcmltYXJ5IGFkdmFudGFnZXMgb2Ygc2NhdHRlciBwbG90cyBpcyB0aGVpciBhYmlsaXR5IHRvIHZpc3VhbGl6ZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdHdvIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMuIEJ5IHBsb3R0aW5nIGRhdGEgcG9pbnRzIG9uIGEgdHdvLWRpbWVuc2lvbmFsIGdyYXBoLCBzY2F0dGVyIHBsb3RzIGhlbHAgaWRlbnRpZnkgcGF0dGVybnMsIHRyZW5kcywgYW5kIGNvcnJlbGF0aW9ucywgbWFraW5nIGl0IGVhc2llciB0byB1bmRlcnN0YW5kIGhvdyBvbmUgdmFyaWFibGUgYWZmZWN0cyBhbm90aGVyLiBUaGlzIHZpc3VhbCByZXByZXNlbnRhdGlvbiBpcyBjcnVjaWFsIGZvciBtYWtpbmcgZGF0YS1kcml2ZW4gZGVjaXNpb25zIGFuZCBmb3JtaW5nIGh5cG90aGVzZXMuDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IHd0LCBzaGFwZSA9IGN5bF9mYWN0b3IsIGNvbG9yID0gY3lsX2ZhY3RvcikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMykgKyAgIyBTaXplIG9mIHRoZSBwb2ludHMNCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgQmV0d2VlbiBNUEcgYW5kIFdlaWdodCBvZiBDYXJzIiwNCiAgICAgICB4ID0gIk1pbGVzIFBlciBHYWxsb24gKE1QRykiLA0KICAgICAgIHkgPSAiV2VpZ2h0ICgxMDAwIGxicykiLA0KICAgICAgIHNoYXBlID0gIk51bWJlciBvZiBDeWxpbmRlcnMiLA0KICAgICAgIGNvbG9yID0gIk51bWJlciBvZiBDeWxpbmRlcnMiKSArICMgQ3VzdG9tIGxhYmVscw0KICB0aGVtZV9taW5pbWFsKCkgIyBNaW5pbWFsaXN0IHRoZW1lIGZvciBhIGNsZWFuIGxvb2sNCg0KYGBgDQoNClRoZSBzY2F0dGVyIHBsb3QgcmV2ZWFscyBhIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gbWlsZXMgcGVyIGdhbGxvbiAoTVBHKSBhbmQgdGhlIHdlaWdodCBvZiBjYXJzLiBHZW5lcmFsbHksIGFzIHRoZSB3ZWlnaHQgb2YgdGhlIGNhciBpbmNyZWFzZXMsIHRoZSBNUEcgZGVjcmVhc2VzLiBUaGlzIGluZGljYXRlcyB0aGF0IGhlYXZpZXIgY2FycyB0ZW5kIHRvIGJlIGxlc3MgZnVlbC1lZmZpY2llbnQuIFVuZGVyc3RhbmRpbmcgdGhpcyByZWxhdGlvbnNoaXAgaXMgY3J1Y2lhbCBmb3IgYXNzZXNzaW5nIGhvdyB2ZWhpY2xlIHdlaWdodCBpbXBhY3RzIGZ1ZWwgZWZmaWNpZW5jeS4NCg0KIyMjIyBfNC42IEJveCBQbG90Xw0KDQpBIGJveCBwbG90IGlzIGEgY3J1Y2lhbCB0b29sIGluIGRhdGEgYW5hbHlzaXMgYXMgaXQgdmlzdWFsbHkgc3VtbWFyaXplcyB0aGUgZGlzdHJpYnV0aW9uIG9mIGEgZGF0YXNldCwgaGlnaGxpZ2h0aW5nIHRoZSBtZWRpYW4sIHF1YXJ0aWxlcywgYW5kIHBvdGVudGlhbCBvdXRsaWVycywgd2hpY2ggaGVscHMgaW4gcXVpY2tseSB1bmRlcnN0YW5kaW5nIHRoZSBjZW50cmFsIHRlbmRlbmN5LCBzcHJlYWQsIGFuZCBvdmVyYWxsIHJhbmdlIG9mIHRoZSBkYXRhLCBtYWtpbmcgaXQgZWFzaWVyIHRvIGNvbXBhcmUgbXVsdGlwbGUgZGF0YXNldHMsIGlkZW50aWZ5IGFub21hbGllcywgYW5kIHN1cHBvcnQgaW5mb3JtZWQgZGVjaXNpb24tbWFraW5nIGFjcm9zcyB2YXJpb3VzIGZpZWxkcy4NCg0KDQpgYGB7cn0NCg0KZ2dwbG90KG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSwgeSA9IG1wZykpICsgDQogIGdlb21fYm94cGxvdCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgTWlsZXMgcGVyIEdhbGxvbiBieSBOdW1iZXIgb2YgQ3lsaW5kZXJzIiwNCiAgICB4ID0gIk51bWJlciBvZiBDeWxpbmRlcnMiLA0KICAgIHkgPSAiTWlsZXMgcGVyIEdhbGxvbiINCiAgKSArDQogdGhlbWVfY2xhc3NpYygpDQoNCmBgYA0KVGhlIGJveCBwbG90IGlsbHVzdHJhdGVzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIGN5bGluZGVycyBpbiBhIHZlaGljbGUgYW5kIGl0cyBtaWxlcyBwZXIgZ2FsbG9uIChNUEcpIHBlcmZvcm1hbmNlLiBWZWhpY2xlcyB3aXRoIDQgY3lsaW5kZXJzIGhhdmUgYSBtZWRpYW4gTVBHIG9mIGFyb3VuZCAyNSwgd2l0aCBhbiBpbnRlcnF1YXJ0aWxlIHJhbmdlIChJUVIpIGZyb20gYXBwcm94aW1hdGVseSAyMiB0byAzMC4gVmVoaWNsZXMgd2l0aCA2IGN5bGluZGVycyBoYXZlIGEgbWVkaWFuIE1QRyBvZiBhYm91dCAxOCwgd2l0aCBhbiBJUVIgZnJvbSByb3VnaGx5IDE2IHRvIDIwLiBWZWhpY2xlcyB3aXRoIDggY3lsaW5kZXJzIGhhdmUgYSBtZWRpYW4gTVBHIG9mIGFyb3VuZCAxNCwgd2l0aCBhbiBJUVIgZnJvbSBhYm91dCAxMyB0byAxNS4gVGhlIHBsb3QgYWxzbyBoaWdobGlnaHRzIHRoYXQgdmVoaWNsZXMgd2l0aCBmZXdlciBjeWxpbmRlcnMgZ2VuZXJhbGx5IGFjaGlldmUgaGlnaGVyIE1QRywgYW5kIGl0IGlkZW50aWZpZXMgc29tZSBvdXRsaWVycywgcGFydGljdWxhcmx5IGFtb25nIHZlaGljbGVzIHdpdGggbW9yZSBjeWxpbmRlcnMuDQo=