Data Exploration

Exercises ~ Week 2

Logo


1 Exercise 1

The following table shows sample information for three students. Each observation represents a single student and includes details such as their unique student ID, name, age, total credits completed, major field of study, and year level.

This dataset demonstrates a mixture of variable types:

  • Nominal: StudentID, Name, Major
  • Numeric: Age (continuous), CreditsCompleted (discrete)
  • Ordinal: YearLevel (Freshman → Senior)
StudentID Name Age CreditsCompleted Major YearLevel
S001 Alice 20 45 Data Sains Sophomore
S002 Budi 21 60 Mathematics Junior
S003 Citra 19 30 Statistics Freshman
# 1. Create vectors for each variable
StudentID <- c("S001", "S002", "S003")       # Nominal / ID
Name <- c("Alice", "Budi", "Citra")          # Nominal / Name
Age <- c(20, 21, 19)                         # Numeric / Continuous
CreditsCompleted <- c(45, 60, 30)            # Numeric / Discrete

# Nominal
Major <- c("Data Sains", "Mathematics", "Statistics")  

# Ordinal
YearLevel <- factor(c("Sophomore", "Junior", "Freshman"),
                    levels = c("Freshman","Sophomore","Junior","Senior"),
                    ordered = TRUE)          

# 2. Combine all vectors into a data frame
students <- data.frame(
  StudentID, Name, Age, CreditsCompleted, Major, YearLevel,
  stringsAsFactors = FALSE
)

# 3. Display the data frame
print(students)
##   StudentID  Name Age CreditsCompleted       Major YearLevel
## 1      S001 Alice  20               45  Data Sains Sophomore
## 2      S002  Budi  21               60 Mathematics    Junior
## 3      S003 Citra  19               30  Statistics  Freshman

2 Exercise 2

Identify Data Types: Determine the type of data for each of the following variables:

# Install knitr package if not already installed
# install.packages("knitr")
library(knitr)

# Create a data frame for Data Types
variables_info <- data.frame(
  No = 1:5,
  Variable = c(
    "Number of vehicles passing through the toll road each day",
    "Student height in cm",
    "Employee gender (Male / Female)",
    "Customer satisfaction level: Low, Medium, High",
    "Respondent's favorite color: Red, Blue, Green"
  ),
  DataType = c(
    "Quantitative",
    "Quantitative",
    "Quantitative",
    "Quantitative",
    "Quantitative"
  ),
  Subtype = c(
    "Diskrete",
    "Continuous",
    "Nominal",
    "Ordinal",
    "Nominal"
  ),
  stringsAsFactors = FALSE
)

# Display the data frame as a neat table
kable(variables_info, 
      caption = "Table of Variables and Data Types")
Table of Variables and Data Types
No Variable DataType Subtype
1 Number of vehicles passing through the toll road each day Quantitative Diskrete
2 Student height in cm Quantitative Continuous
3 Employee gender (Male / Female) Quantitative Nominal
4 Customer satisfaction level: Low, Medium, High Quantitative Ordinal
5 Respondent’s favorite color: Red, Blue, Green Quantitative Nominal

3 Exercise 3

Classify Data Sources: Determine whether the following data comes from internal or external sources, and whether it is structured or unstructured:

# Install DT package if not already installed
# install.packages("DT")
library(DT)

# Create a data frame for data sources 
data_sources <- data.frame(
  No = 1:4,
  DataSource = c(
    "Daily sales transaction data of the company",
    "Weather reports from BMKG",
    "Product reviews on social media",
    "Warehouse inventory reports"
  ),
  Internal_External = c(
    "Internal",
    "Eksternal",
    "Eksternal",
    "Internal"
  ),
  Structured_Unstructured = c(
    "Structured",
    "Structured",
    "Unstructured",
    "Structured"
  ),
  stringsAsFactors = FALSE
)

# Display the data frame as a neat table
datatable(data_sources, 
          caption = "Table of Data Sources",
          rownames = FALSE) # hides the index column

4 Exercise 4

Dataset Structure: Consider the following transaction table:

Date Qty Price Product CustomerTier
2025-10-01 2 1000 Laptop High
2025-10-01 5 20 Mouse Medium
2025-10-02 1 1000 Laptop Low
2025-10-02 3 30 Keyboard Medium
2025-10-03 4 50 Mouse Medium
2025-10-03 2 1000 Laptop High
2025-10-04 6 25 Keyboard Low
2025-10-04 1 1000 Laptop High
2025-10-05 3 40 Mouse Low
2025-10-05 5 10 Keyboard Medium

Your Assignment Instructions: Creating a Transactions Table above in R

  1. Create a data frame in R called transactions containing the data above.

  2. Identify which variables are numeric and which are categorical

  3. Calculate total revenue for each transaction by multiplying Qty × Price and add it as a new column Total.

  4. Compute summary statistics:

    • Total quantity sold for each product
    • Total revenue per product
    • Average price per product
  5. Visualize the data:

    • Create a barplot showing total quantity sold per product.
    • Create a pie chart showing the proportion of total revenue per customer tier.
  6. Optional Challenge:

    • Find which date had the highest total revenue.
    • Create a stacked bar chart showing quantity sold per product by customer tier.

Hints: Use data.frame(), aggregate(), barplot(), pie(), and basic arithmetic operations in R.

4.1 Create Data Frame

transactions <- data.frame(
  Date = as.Date(c ("2025-10-01", "2025-10-01", "2025-10-02", "2025-10-02", 
                "2025-10-03", "2025-10-03", "2025-10-04", "2025-10-04",
                "2025-10-05", "2025-10-05")),
  Qty = c(2, 5, 1, 3, 4, 2, 6, 1, 3, 5),
  Price = c(1000, 20, 1000, 30, 50, 1000, 25, 1000, 40, 10),
  Product = c("Laptop", "Mouse", "Laptop", "Keyboard", "Mouse",
              "Laptop", "Keyboard", "Laptop", "Mouse", "Keyboard"),
  CustomerTier = c("High", "Medium", "Low", "Medium", "Medium",
                   "High", "Low", "High", "Low", "Medium"),
  stringsAsFactors = FALSE)

# View the dataset contents
kable(transactions,
      caption = "Transactions Data by Customer Tier")
Transactions Data by Customer Tier
Date Qty Price Product CustomerTier
2025-10-01 2 1000 Laptop High
2025-10-01 5 20 Mouse Medium
2025-10-02 1 1000 Laptop Low
2025-10-02 3 30 Keyboard Medium
2025-10-03 4 50 Mouse Medium
2025-10-03 2 1000 Laptop High
2025-10-04 6 25 Keyboard Low
2025-10-04 1 1000 Laptop High
2025-10-05 3 40 Mouse Low
2025-10-05 5 10 Keyboard Medium

4.2 Identify data types

str(transactions)  # Look at the (numeric vs categorical)
## 'data.frame':    10 obs. of  5 variables:
##  $ Date        : Date, format: "2025-10-01" "2025-10-01" ...
##  $ Qty         : num  2 5 1 3 4 2 6 1 3 5
##  $ Price       : num  1000 20 1000 30 50 1000 25 1000 40 10
##  $ Product     : chr  "Laptop" "Mouse" "Laptop" "Keyboard" ...
##  $ CustomerTier: chr  "High" "Medium" "Low" "Medium" ...

4.3 Add a Total column

transactions$Total <- transactions$Qty * transactions$Price

4.4 View results

print(transactions)
##          Date Qty Price  Product CustomerTier Total
## 1  2025-10-01   2  1000   Laptop         High  2000
## 2  2025-10-01   5    20    Mouse       Medium   100
## 3  2025-10-02   1  1000   Laptop          Low  1000
## 4  2025-10-02   3    30 Keyboard       Medium    90
## 5  2025-10-03   4    50    Mouse       Medium   200
## 6  2025-10-03   2  1000   Laptop         High  2000
## 7  2025-10-04   6    25 Keyboard          Low   150
## 8  2025-10-04   1  1000   Laptop         High  1000
## 9  2025-10-05   3    40    Mouse          Low   120
## 10 2025-10-05   5    10 Keyboard       Medium    50

4.5 Summary Statistics

### Total quantity sold per product
total_qty <- aggregate(Qty ~ Product, data = transactions, sum)

### Total revenue per product
total_revenue <- aggregate(Total ~ Product, data = transactions, sum)

### Average price per product
avg_price <- aggregate(Price ~ Product, data = transactions, mean)

4.6 Show summary results

cat("\n Total Quantity per Product \n")
## 
##  Total Quantity per Product
print(total_qty)
##    Product Qty
## 1 Keyboard  14
## 2   Laptop   6
## 3    Mouse  12
cat("\n Total Revenue per Product \n")
## 
##  Total Revenue per Product
print(total_revenue)
##    Product Total
## 1 Keyboard   290
## 2   Laptop  6000
## 3    Mouse   420
cat("\n Average Price per Product \n")
## 
##  Average Price per Product
print(avg_price)
##    Product      Price
## 1 Keyboard   21.66667
## 2   Laptop 1000.00000
## 3    Mouse   36.66667

4.7 Visualization

### (a) Barplot - total quantity sold per product
barplot(
  total_qty$Qty,
  names.arg = total_qty$Product,
  main = "Total Quantity Sold per Product",
  xlab = "Product",
  ylab = "Total Quantity",
  col = c("skyblue", "lightgreen", "orange")
)

### (b) Pie chart - proportion of total revenue per Customer Tier
revenue_tier <- aggregate(Total ~ CustomerTier, data = transactions, sum)
pie(
  revenue_tier$Total,
  labels = paste(revenue_tier$CustomerTier, "-", revenue_tier$Total),
  main = "Proportion of Total Revenue per Customer Tier",
  col = c("gold", "lightblue", "tomato")
)

4.8 Optional Challenge

### (a) Date with highest total revenue
date_revenue <- aggregate(Total ~ Date, data = transactions, sum)
max_rev_date <- date_revenue[which.max(date_revenue$Total), ]
cat("\nDate with highest total revenue:\n")
## 
## Date with highest total revenue:
print(max_rev_date)
##         Date Total
## 3 2025-10-03  2200
### (b) Stacked bar chart: quantity sold per product by customer tier
qty_stack <- aggregate(Qty ~ Product + CustomerTier, data = transactions, sum)
qty_matrix <- xtabs(Qty ~ CustomerTier + Product, data = qty_stack)
barplot(
  qty_matrix,
  beside = FALSE,
  main = "Quantity Sold per Product by Customer Tier",
  xlab = "Product",
  ylab = "Quantity Sold",
  col = c("lightblue", "gold", "tomato")
)
legend("topright", legend = rownames(qty_matrix),
       fill = c("lightblue", "gold", "tomato"), title = "Customer Tier")

5 Exercise 5

Create Your Own Data Frame:

Objective: Create a data frame in R with 30 rows containing a mix of data types: continuous, discrete, nominal, and ordinal.

5.0.1 Instructions

  1. Open RStudio or the R console.

  2. Create a vector for each column in your data frame:

    • Date: 30 dates (can be sequential or random within a month/year)
    • Continuous: numeric values that can take decimal values (e.g., height, weight, temperature)
    • Discrete: numeric values that can only take whole numbers (e.g., number of items, number of vehicles)
    • Nominal: categorical values with no order (e.g., color, gender, city)
    • Ordinal: categorical values with a defined order (e.g., Low, Medium, High; Beginner, Intermediate, Expert)
  3. Combine all vectors into a data frame called my_data.

  4. Check your data frame using head() or View() to ensure it has 30 rows and the columns are correct.

  5. Optional tasks:

    • Summarize each column using summary()
    • Count the frequency of each category for Nominal and Ordinal columns using table()

5.0.2 Hints

  • Use seq.Date() or as.Date() to generate the Date column.
  • Use runif() or rnorm() for continuous numeric data.
  • Use sample() for discrete, nominal, and ordinal data.
  • Ensure the ordinal vector is created with factor(..., levels = c("Low","Medium","High"), ordered = TRUE) (or similar).

5.1 Create each column

## Date: 30 consecutive dates in October 2025
Date <- seq.Date(from = as.Date("2025-10-01"), 
                 by = "day", 
                 length.out = 30)

## Continuous: for example body temperature data (in °C), use decimals
Continuous <- round(runif(30, min = 35.5, max = 37.5), 1)

## Discrete: e.g. number of items sold (whole number)
Discrete <- sample(1:50, 30, replace = TRUE)

## Nominal: e.g. cutomer's city of origin (no order)
Nominal <- sample(c("Jakarta", "Bandung", "Surabaya", "Medan", "Bali"),
                  30, replace = TRUE)

## Ordinal: e.g. satisfaction level (there is a sequence)
Ordinal <- factor(
  sample(c("Low", "Medium", "High"), 30, replace = TRUE),
  levels = c("Low", "Medium", "High"),
  ordered = TRUE
)

5.2 Combine all into a data frame

my_data <- data.frame(Date, Continuous, Discrete, Nominal, Ordinal)

5.3 Check the data contents

head(my_data)   # display the first 6 rows
View(my_data)   # open in Rstudio window (optional)

5.4 (Optional) Data Summary

summary(my_data)
##       Date              Continuous       Discrete      Nominal         
##  Min.   :2025-10-01   Min.   :35.50   Min.   : 1.0   Length:30         
##  1st Qu.:2025-10-08   1st Qu.:36.00   1st Qu.:10.0   Class :character  
##  Median :2025-10-15   Median :36.55   Median :18.0   Mode  :character  
##  Mean   :2025-10-15   Mean   :36.49   Mean   :22.8                     
##  3rd Qu.:2025-10-22   3rd Qu.:37.08   3rd Qu.:38.5                     
##  Max.   :2025-10-30   Max.   :37.40   Max.   :49.0                     
##    Ordinal  
##  Low   : 9  
##  Medium: 9  
##  High  :12  
##             
##             
## 

5.5 Calculate frequency categories

cat("\n Nominal Frequency (City) \n")
## 
##  Nominal Frequency (City)
print(table(my_data$Nominal))
## 
##     Bali  Bandung  Jakarta    Medan Surabaya 
##        5        3        7        6        9
cat("\n Ordinal Frequency (Level of Satisfaction) \n")
## 
##  Ordinal Frequency (Level of Satisfaction)
print(table(my_data$Ordinal))
## 
##    Low Medium   High 
##      9      9     12
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAyIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6IA0KLSAiUGFza2FsaXMgRmFyZWxuYXRhIFphbWFzaSINCi0gIk0uIEZpdHJhaCBBaWRpbCBIYXJhaGFwIg0KLSAiSGFuYWZpIE1hbGlrIFJpZmFpIg0KLSAiRGVuIFl1YW4gRnJhc3Nla2EiDQotICJaaWRoYW4gQWxmYXJlemkgQWZkaSIjIFJlcGxhY2Ugd2l0aCB5b3VyIGZ1bGwgbmFtZQ0KICAgICAgICANCmRhdGU6ICAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiICMgQXV0byBkaXNwbGF5cyB0aGUgY3VycmVudCBkYXRlDQpvdXRwdXQ6ICAgICAgICAgICAgICAgICAgICAgICAgICMgT3V0cHV0IHNlY3Rpb24gZGVmaW5lcyB0aGUgZm9ybWF0IGFuZCBsYXlvdXQgDQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOiAgICAgICMgaHR0cHM6Ly9naXRodWIuY29tL2p1YmEvcm1kZm9ybWF0cw0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlICAgICAgICAjIEVtYmVkcyBhbGwgcmVzb3VyY2VzIChDU1MsIEpTLCBpbWFnZXMpIA0KICAgIHRodW1ibmFpbHM6IHRydWUgICAgICAgICAgICAjIERpc3BsYXlzIGltYWdlIHRodW1ibmFpbHMgaW4gdGhlIGRvYw0KICAgIGxpZ2h0Ym94OiB0cnVlICAgICAgICAgICAgICAjIEVuYWJsZXMgY2xpY2sgdG8gZW5sYXJnZSBpbWFnZXMNCiAgICBnYWxsZXJ5OiB0cnVlICAgICAgICAgICAgICAgIyBHcm91cHMgaW1hZ2VzIGludG8gYW4gaW50ZXJhY3RpdmUgZ2FsbGVyeQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICAgICAjIEF1dG9tYXRpY2FsbHkgbnVtYmVycyBhbGwgc2VjdGlvbnMNCiAgICBsaWJfZGlyOiBsaWJzICAgICAgICAgICAgICAgIyBEaXJlY3Rvcnkgd2hlcmUgSmF2YVNjcmlwdC9DU1MgbGlicmFyaWVzDQogICAgZGZfcHJpbnQ6ICJwYWdlZCIgICAgICAgICAgICMgRGlzcGxheXMgZGF0YSBmcmFtZXMgYXMgaW50ZXJhY3RpdmUgcGFnZWQgDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyIgICAgICAgICMgQWxsb3dzIGZvbGRpbmcvdW5mb2xkaW5nIFIgY29kZSBibG9ja3MgDQogICAgY29kZV9kb3dubG9hZDogeWVzICAgICAgICAgICMgQWRkcyBhIGJ1dHRvbiB0byBkb3dubG9hZCBhbGwgUiBjb2RlDQotLS0NCg0KDQo8aW1nIGlkPSJGb3RvIiBzcmM9IkM6L1VzZXJzL0xFTk9WTy9PbmVEcml2ZS9EZXNrdG9wL1R1Z2FzLlN0YXRpc3Rpay9LZWxvbXBvay5wbmcuanBnIiBhbHQ9IkxvZ28iIHN0eWxlPSJ3aWR0aDoyMDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiPg0KDQotLS0NCg0KIyBFeGVyY2lzZSAxDQoNClRoZSBmb2xsb3dpbmcgdGFibGUgc2hvd3Mgc2FtcGxlIGluZm9ybWF0aW9uIGZvciB0aHJlZSBzdHVkZW50cy4gRWFjaCBvYnNlcnZhdGlvbiByZXByZXNlbnRzIGEgc2luZ2xlIHN0dWRlbnQgYW5kIGluY2x1ZGVzIGRldGFpbHMgc3VjaCBhcyB0aGVpciB1bmlxdWUgc3R1ZGVudCBJRCwgbmFtZSwgYWdlLCB0b3RhbCBjcmVkaXRzIGNvbXBsZXRlZCwgbWFqb3IgZmllbGQgb2Ygc3R1ZHksIGFuZCB5ZWFyIGxldmVsLiAgDQoNClRoaXMgZGF0YXNldCBkZW1vbnN0cmF0ZXMgYSBtaXh0dXJlIG9mIHZhcmlhYmxlIHR5cGVzOiAgDQoNCi0gKipOb21pbmFsOioqIFN0dWRlbnRJRCwgTmFtZSwgTWFqb3IgIA0KLSAqKk51bWVyaWM6KiogQWdlIChjb250aW51b3VzKSwgQ3JlZGl0c0NvbXBsZXRlZCAoZGlzY3JldGUpICANCi0gKipPcmRpbmFsOioqIFllYXJMZXZlbCAoRnJlc2htYW4g4oaSIFNlbmlvcikgIA0KDQp8IFN0dWRlbnRJRCB8IE5hbWUgICB8IEFnZSB8IENyZWRpdHNDb21wbGV0ZWQgfCBNYWpvciAgICAgICAgICAgIHwgWWVhckxldmVsIHwNCnwtLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLXwNCnwgUzAwMSAgICAgIHwgQWxpY2UgIHwgMjAgIHwgNDUgICAgICAgICAgICAgIHwgRGF0YSBTYWlucyAgICAgIHwgU29waG9tb3JlIHwNCnwgUzAwMiAgICAgIHwgQnVkaSAgIHwgMjEgIHwgNjAgICAgICAgICAgICAgIHwgTWF0aGVtYXRpY3MgICAgIHwgSnVuaW9yICAgIHwNCnwgUzAwMyAgICAgIHwgQ2l0cmEgIHwgMTkgIHwgMzAgICAgICAgICAgICAgIHwgU3RhdGlzdGljcyAgICAgIHwgRnJlc2htYW4gIHwNCg0KYGBge3J9DQojIDEuIENyZWF0ZSB2ZWN0b3JzIGZvciBlYWNoIHZhcmlhYmxlDQpTdHVkZW50SUQgPC0gYygiUzAwMSIsICJTMDAyIiwgIlMwMDMiKSAgICAgICAjIE5vbWluYWwgLyBJRA0KTmFtZSA8LSBjKCJBbGljZSIsICJCdWRpIiwgIkNpdHJhIikgICAgICAgICAgIyBOb21pbmFsIC8gTmFtZQ0KQWdlIDwtIGMoMjAsIDIxLCAxOSkgICAgICAgICAgICAgICAgICAgICAgICAgIyBOdW1lcmljIC8gQ29udGludW91cw0KQ3JlZGl0c0NvbXBsZXRlZCA8LSBjKDQ1LCA2MCwgMzApICAgICAgICAgICAgIyBOdW1lcmljIC8gRGlzY3JldGUNCg0KIyBOb21pbmFsDQpNYWpvciA8LSBjKCJEYXRhIFNhaW5zIiwgIk1hdGhlbWF0aWNzIiwgIlN0YXRpc3RpY3MiKSAgDQoNCiMgT3JkaW5hbA0KWWVhckxldmVsIDwtIGZhY3RvcihjKCJTb3Bob21vcmUiLCAiSnVuaW9yIiwgIkZyZXNobWFuIiksDQogICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIkZyZXNobWFuIiwiU29waG9tb3JlIiwiSnVuaW9yIiwiU2VuaW9yIiksDQogICAgICAgICAgICAgICAgICAgIG9yZGVyZWQgPSBUUlVFKSAgICAgICAgICANCg0KIyAyLiBDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lDQpzdHVkZW50cyA8LSBkYXRhLmZyYW1lKA0KICBTdHVkZW50SUQsIE5hbWUsIEFnZSwgQ3JlZGl0c0NvbXBsZXRlZCwgTWFqb3IsIFllYXJMZXZlbCwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgMy4gRGlzcGxheSB0aGUgZGF0YSBmcmFtZQ0KcHJpbnQoc3R1ZGVudHMpDQpgYGANCg0KDQojIEV4ZXJjaXNlIDINCg0KKipJZGVudGlmeSBEYXRhIFR5cGVzOioqIERldGVybWluZSB0aGUgdHlwZSBvZiBkYXRhIGZvciBlYWNoIG9mIHRoZSBmb2xsb3dpbmcgdmFyaWFibGVzOg0KDQpgYGB7cn0NCiMgSW5zdGFsbCBrbml0ciBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQpsaWJyYXJ5KGtuaXRyKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIERhdGEgVHlwZXMNCnZhcmlhYmxlc19pbmZvIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo1LA0KICBWYXJpYWJsZSA9IGMoDQogICAgIk51bWJlciBvZiB2ZWhpY2xlcyBwYXNzaW5nIHRocm91Z2ggdGhlIHRvbGwgcm9hZCBlYWNoIGRheSIsDQogICAgIlN0dWRlbnQgaGVpZ2h0IGluIGNtIiwNCiAgICAiRW1wbG95ZWUgZ2VuZGVyIChNYWxlIC8gRmVtYWxlKSIsDQogICAgIkN1c3RvbWVyIHNhdGlzZmFjdGlvbiBsZXZlbDogTG93LCBNZWRpdW0sIEhpZ2giLA0KICAgICJSZXNwb25kZW50J3MgZmF2b3JpdGUgY29sb3I6IFJlZCwgQmx1ZSwgR3JlZW4iDQogICksDQogIERhdGFUeXBlID0gYygNCiAgICAiUXVhbnRpdGF0aXZlIiwNCiAgICAiUXVhbnRpdGF0aXZlIiwNCiAgICAiUXVhbnRpdGF0aXZlIiwNCiAgICAiUXVhbnRpdGF0aXZlIiwNCiAgICAiUXVhbnRpdGF0aXZlIg0KICApLA0KICBTdWJ0eXBlID0gYygNCiAgICAiRGlza3JldGUiLA0KICAgICJDb250aW51b3VzIiwNCiAgICAiTm9taW5hbCIsDQogICAgIk9yZGluYWwiLA0KICAgICJOb21pbmFsIg0KICApLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lIGFzIGEgbmVhdCB0YWJsZQ0Ka2FibGUodmFyaWFibGVzX2luZm8sIA0KICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBWYXJpYWJsZXMgYW5kIERhdGEgVHlwZXMiKQ0KYGBgDQotLS0NCg0KIyBFeGVyY2lzZSAzDQoNCioqQ2xhc3NpZnkgRGF0YSBTb3VyY2VzOioqIERldGVybWluZSB3aGV0aGVyIHRoZSBmb2xsb3dpbmcgZGF0YSBjb21lcyBmcm9tICoqaW50ZXJuYWwqKiBvciAqKmV4dGVybmFsIHNvdXJjZXMqKiwgYW5kIHdoZXRoZXIgaXQgaXMgKipzdHJ1Y3R1cmVkKiogb3IgKip1bnN0cnVjdHVyZWQqKjoNCg0KYGBge3J9DQojIEluc3RhbGwgRFQgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygiRFQiKQ0KbGlicmFyeShEVCkNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBkYXRhIHNvdXJjZXMgDQpkYXRhX3NvdXJjZXMgPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjQsDQogIERhdGFTb3VyY2UgPSBjKA0KICAgICJEYWlseSBzYWxlcyB0cmFuc2FjdGlvbiBkYXRhIG9mIHRoZSBjb21wYW55IiwNCiAgICAiV2VhdGhlciByZXBvcnRzIGZyb20gQk1LRyIsDQogICAgIlByb2R1Y3QgcmV2aWV3cyBvbiBzb2NpYWwgbWVkaWEiLA0KICAgICJXYXJlaG91c2UgaW52ZW50b3J5IHJlcG9ydHMiDQogICksDQogIEludGVybmFsX0V4dGVybmFsID0gYygNCiAgICAiSW50ZXJuYWwiLA0KICAgICJFa3N0ZXJuYWwiLA0KICAgICJFa3N0ZXJuYWwiLA0KICAgICJJbnRlcm5hbCINCiAgKSwNCiAgU3RydWN0dXJlZF9VbnN0cnVjdHVyZWQgPSBjKA0KICAgICJTdHJ1Y3R1cmVkIiwNCiAgICAiU3RydWN0dXJlZCIsDQogICAgIlVuc3RydWN0dXJlZCIsDQogICAgIlN0cnVjdHVyZWQiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQpkYXRhdGFibGUoZGF0YV9zb3VyY2VzLCANCiAgICAgICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIERhdGEgU291cmNlcyIsDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSkgIyBoaWRlcyB0aGUgaW5kZXggY29sdW1uDQpgYGANCg0KLS0tDQoNCiMgRXhlcmNpc2UgNA0KDQoqKkRhdGFzZXQgU3RydWN0dXJlOioqIENvbnNpZGVyIHRoZSBmb2xsb3dpbmcgdHJhbnNhY3Rpb24gdGFibGU6DQoNCnwgRGF0ZSAgICAgICB8IFF0eSB8IFByaWNlIHwgUHJvZHVjdCAgfCBDdXN0b21lclRpZXIgfA0KfC0tLS0tLS0tLS0tLXwtLS0tLXwtLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS18DQp8IDIwMjUtMTAtMDEgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wMSB8IDUgICB8IDIwICAgIHwgTW91c2UgICAgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAyIHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAzICAgfCAzMCAgICB8IEtleWJvYXJkIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMyB8IDQgICB8IDUwICAgIHwgTW91c2UgICAgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgMiAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDQgfCA2ICAgfCAyNSAgICB8IEtleWJvYXJkIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDEgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTA1IHwgMyAgIHwgNDAgICAgfCBNb3VzZSAgICB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCA1ICAgfCAxMCAgICB8IEtleWJvYXJkIHwgTWVkaXVtICAgICAgIHwNCg0KDQoqKllvdXIgQXNzaWdubWVudCBJbnN0cnVjdGlvbnM6KiogQ3JlYXRpbmcgYSBUcmFuc2FjdGlvbnMgVGFibGUgYWJvdmUgaW4gUg0KDQoxLiAqKkNyZWF0ZSBhIGRhdGEgZnJhbWUqKiBpbiBSIGNhbGxlZCBgdHJhbnNhY3Rpb25zYCBjb250YWluaW5nIHRoZSBkYXRhIGFib3ZlLg0KDQoyLiBJZGVudGlmeSB3aGljaCB2YXJpYWJsZXMgYXJlIG51bWVyaWMgYW5kIHdoaWNoIGFyZSBjYXRlZ29yaWNhbA0KDQozLiAqKkNhbGN1bGF0ZSB0b3RhbCByZXZlbnVlKiogZm9yIGVhY2ggdHJhbnNhY3Rpb24gYnkgbXVsdGlwbHlpbmcgYFF0eSDDlyBQcmljZWAgYW5kIGFkZCBpdCBhcyBhIG5ldyBjb2x1bW4gYFRvdGFsYC4NCg0KNC4gKipDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljcyoqOg0KICAgLSBUb3RhbCBxdWFudGl0eSBzb2xkIGZvciBlYWNoIHByb2R1Y3QNCiAgIC0gVG90YWwgcmV2ZW51ZSBwZXIgcHJvZHVjdA0KICAgLSBBdmVyYWdlIHByaWNlIHBlciBwcm9kdWN0DQoNCjUuICoqVmlzdWFsaXplIHRoZSBkYXRhKio6DQogICAtIENyZWF0ZSBhICoqYmFycGxvdCoqIHNob3dpbmcgdG90YWwgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdC4NCiAgIC0gQ3JlYXRlIGEgKipwaWUgY2hhcnQqKiBzaG93aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHRvdGFsIHJldmVudWUgcGVyIGN1c3RvbWVyIHRpZXIuDQoNCjYuICoqT3B0aW9uYWwgQ2hhbGxlbmdlKio6DQogICAtIEZpbmQgd2hpY2ggKipkYXRlKiogaGFkIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUuDQogICAtIENyZWF0ZSBhICoqc3RhY2tlZCBiYXIgY2hhcnQqKiBzaG93aW5nIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QgYnkgY3VzdG9tZXIgdGllci4NCg0KKipIaW50czoqKiBVc2UgYGRhdGEuZnJhbWUoKWAsIGBhZ2dyZWdhdGUoKWAsIGBiYXJwbG90KClgLCBgcGllKClgLCBhbmQgYmFzaWMgYXJpdGhtZXRpYyBvcGVyYXRpb25zIGluIFIuDQoNCiMjIENyZWF0ZSBEYXRhIEZyYW1lDQpgYGB7Un0NCnRyYW5zYWN0aW9ucyA8LSBkYXRhLmZyYW1lKA0KICBEYXRlID0gYXMuRGF0ZShjICgiMjAyNS0xMC0wMSIsICIyMDI1LTEwLTAxIiwgIjIwMjUtMTAtMDIiLCAiMjAyNS0xMC0wMiIsIA0KICAgICAgICAgICAgICAgICIyMDI1LTEwLTAzIiwgIjIwMjUtMTAtMDMiLCAiMjAyNS0xMC0wNCIsICIyMDI1LTEwLTA0IiwNCiAgICAgICAgICAgICAgICAiMjAyNS0xMC0wNSIsICIyMDI1LTEwLTA1IikpLA0KICBRdHkgPSBjKDIsIDUsIDEsIDMsIDQsIDIsIDYsIDEsIDMsIDUpLA0KICBQcmljZSA9IGMoMTAwMCwgMjAsIDEwMDAsIDMwLCA1MCwgMTAwMCwgMjUsIDEwMDAsIDQwLCAxMCksDQogIFByb2R1Y3QgPSBjKCJMYXB0b3AiLCAiTW91c2UiLCAiTGFwdG9wIiwgIktleWJvYXJkIiwgIk1vdXNlIiwNCiAgICAgICAgICAgICAgIkxhcHRvcCIsICJLZXlib2FyZCIsICJMYXB0b3AiLCAiTW91c2UiLCAiS2V5Ym9hcmQiKSwNCiAgQ3VzdG9tZXJUaWVyID0gYygiSGlnaCIsICJNZWRpdW0iLCAiTG93IiwgIk1lZGl1bSIsICJNZWRpdW0iLA0KICAgICAgICAgICAgICAgICAgICJIaWdoIiwgIkxvdyIsICJIaWdoIiwgIkxvdyIsICJNZWRpdW0iKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIFZpZXcgdGhlIGRhdGFzZXQgY29udGVudHMNCmthYmxlKHRyYW5zYWN0aW9ucywNCiAgICAgIGNhcHRpb24gPSAiVHJhbnNhY3Rpb25zIERhdGEgYnkgQ3VzdG9tZXIgVGllciIpDQpgYGANCg0KIyMgSWRlbnRpZnkgZGF0YSB0eXBlcw0KYGBge1J9DQpzdHIodHJhbnNhY3Rpb25zKSAgIyBMb29rIGF0IHRoZSAobnVtZXJpYyB2cyBjYXRlZ29yaWNhbCkNCmBgYA0KDQojIyBBZGQgYSBUb3RhbCBjb2x1bW4NCmBgYHtSfQ0KdHJhbnNhY3Rpb25zJFRvdGFsIDwtIHRyYW5zYWN0aW9ucyRRdHkgKiB0cmFuc2FjdGlvbnMkUHJpY2UNCmBgYA0KDQojIyBWaWV3IHJlc3VsdHMNCmBgYHtSfQ0KcHJpbnQodHJhbnNhY3Rpb25zKQ0KYGBgDQoNCiMjIFN1bW1hcnkgU3RhdGlzdGljcw0KYGBge1J9DQoNCiMjIyBUb3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0DQp0b3RhbF9xdHkgPC0gYWdncmVnYXRlKFF0eSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIHN1bSkNCg0KIyMjIFRvdGFsIHJldmVudWUgcGVyIHByb2R1Y3QNCnRvdGFsX3JldmVudWUgPC0gYWdncmVnYXRlKFRvdGFsIH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKQ0KDQojIyMgQXZlcmFnZSBwcmljZSBwZXIgcHJvZHVjdA0KYXZnX3ByaWNlIDwtIGFnZ3JlZ2F0ZShQcmljZSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIG1lYW4pDQpgYGANCg0KIyMgU2hvdyBzdW1tYXJ5IHJlc3VsdHMNCmBgYHtSfQ0KY2F0KCJcbiBUb3RhbCBRdWFudGl0eSBwZXIgUHJvZHVjdCBcbiIpDQpwcmludCh0b3RhbF9xdHkpDQpjYXQoIlxuIFRvdGFsIFJldmVudWUgcGVyIFByb2R1Y3QgXG4iKQ0KcHJpbnQodG90YWxfcmV2ZW51ZSkNCmNhdCgiXG4gQXZlcmFnZSBQcmljZSBwZXIgUHJvZHVjdCBcbiIpDQpwcmludChhdmdfcHJpY2UpDQpgYGANCg0KIyMgVmlzdWFsaXphdGlvbg0KYGBge1J9DQoNCiMjIyAoYSkgQmFycGxvdCAtIHRvdGFsIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QNCmJhcnBsb3QoDQogIHRvdGFsX3F0eSRRdHksDQogIG5hbWVzLmFyZyA9IHRvdGFsX3F0eSRQcm9kdWN0LA0KICBtYWluID0gIlRvdGFsIFF1YW50aXR5IFNvbGQgcGVyIFByb2R1Y3QiLA0KICB4bGFiID0gIlByb2R1Y3QiLA0KICB5bGFiID0gIlRvdGFsIFF1YW50aXR5IiwNCiAgY29sID0gYygic2t5Ymx1ZSIsICJsaWdodGdyZWVuIiwgIm9yYW5nZSIpDQopDQoNCiMjIyAoYikgUGllIGNoYXJ0IC0gcHJvcG9ydGlvbiBvZiB0b3RhbCByZXZlbnVlIHBlciBDdXN0b21lciBUaWVyDQpyZXZlbnVlX3RpZXIgPC0gYWdncmVnYXRlKFRvdGFsIH4gQ3VzdG9tZXJUaWVyLCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQpwaWUoDQogIHJldmVudWVfdGllciRUb3RhbCwNCiAgbGFiZWxzID0gcGFzdGUocmV2ZW51ZV90aWVyJEN1c3RvbWVyVGllciwgIi0iLCByZXZlbnVlX3RpZXIkVG90YWwpLA0KICBtYWluID0gIlByb3BvcnRpb24gb2YgVG90YWwgUmV2ZW51ZSBwZXIgQ3VzdG9tZXIgVGllciIsDQogIGNvbCA9IGMoImdvbGQiLCAibGlnaHRibHVlIiwgInRvbWF0byIpDQopDQpgYGANCg0KIyMgT3B0aW9uYWwgQ2hhbGxlbmdlDQpgYGB7cn0NCg0KIyMjIChhKSBEYXRlIHdpdGggaGlnaGVzdCB0b3RhbCByZXZlbnVlDQpkYXRlX3JldmVudWUgPC0gYWdncmVnYXRlKFRvdGFsIH4gRGF0ZSwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKQ0KbWF4X3Jldl9kYXRlIDwtIGRhdGVfcmV2ZW51ZVt3aGljaC5tYXgoZGF0ZV9yZXZlbnVlJFRvdGFsKSwgXQ0KY2F0KCJcbkRhdGUgd2l0aCBoaWdoZXN0IHRvdGFsIHJldmVudWU6XG4iKQ0KcHJpbnQobWF4X3Jldl9kYXRlKQ0KDQojIyMgKGIpIFN0YWNrZWQgYmFyIGNoYXJ0OiBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0IGJ5IGN1c3RvbWVyIHRpZXINCnF0eV9zdGFjayA8LSBhZ2dyZWdhdGUoUXR5IH4gUHJvZHVjdCArIEN1c3RvbWVyVGllciwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKQ0KcXR5X21hdHJpeCA8LSB4dGFicyhRdHkgfiBDdXN0b21lclRpZXIgKyBQcm9kdWN0LCBkYXRhID0gcXR5X3N0YWNrKQ0KYmFycGxvdCgNCiAgcXR5X21hdHJpeCwNCiAgYmVzaWRlID0gRkFMU0UsDQogIG1haW4gPSAiUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCBieSBDdXN0b21lciBUaWVyIiwNCiAgeGxhYiA9ICJQcm9kdWN0IiwNCiAgeWxhYiA9ICJRdWFudGl0eSBTb2xkIiwNCiAgY29sID0gYygibGlnaHRibHVlIiwgImdvbGQiLCAidG9tYXRvIikNCikNCmxlZ2VuZCgidG9wcmlnaHQiLCBsZWdlbmQgPSByb3duYW1lcyhxdHlfbWF0cml4KSwNCiAgICAgICBmaWxsID0gYygibGlnaHRibHVlIiwgImdvbGQiLCAidG9tYXRvIiksIHRpdGxlID0gIkN1c3RvbWVyIFRpZXIiKQ0KYGBgDQoNCiMgRXhlcmNpc2UgNQ0KDQoqKkNyZWF0ZSBZb3VyIE93biBEYXRhIEZyYW1lOioqDQoNCioqT2JqZWN0aXZlOioqIENyZWF0ZSBhIGRhdGEgZnJhbWUgaW4gUiB3aXRoICoqMzAgcm93cyoqIGNvbnRhaW5pbmcgYSBtaXggb2YgZGF0YSB0eXBlczogY29udGludW91cywgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsLiAgDQpgYGB7cn0NCg0KYGBgDQoNCiMjIyBJbnN0cnVjdGlvbnMNCg0KMS4gKipPcGVuIFJTdHVkaW8qKiBvciB0aGUgUiBjb25zb2xlLiAgDQoNCjIuICoqQ3JlYXRlIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbioqIGluIHlvdXIgZGF0YSBmcmFtZTogIA0KDQogICAtICoqRGF0ZSoqOiAzMCBkYXRlcyAoY2FuIGJlIHNlcXVlbnRpYWwgb3IgcmFuZG9tIHdpdGhpbiBhIG1vbnRoL3llYXIpICANCiAgIC0gKipDb250aW51b3VzKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIHRha2UgZGVjaW1hbCB2YWx1ZXMgKGUuZy4sIGhlaWdodCwgd2VpZ2h0LCB0ZW1wZXJhdHVyZSkgIA0KICAgLSAqKkRpc2NyZXRlKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIG9ubHkgdGFrZSB3aG9sZSBudW1iZXJzIChlLmcuLCBudW1iZXIgb2YgaXRlbXMsIG51bWJlciBvZiB2ZWhpY2xlcykgIA0KICAgLSAqKk5vbWluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggKipubyBvcmRlcioqIChlLmcuLCBjb2xvciwgZ2VuZGVyLCBjaXR5KSAgDQogICAtICoqT3JkaW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCBhICoqZGVmaW5lZCBvcmRlcioqIChlLmcuLCBMb3csIE1lZGl1bSwgSGlnaDsgQmVnaW5uZXIsIEludGVybWVkaWF0ZSwgRXhwZXJ0KSAgDQoNCjMuICoqQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZSoqIGNhbGxlZCBgbXlfZGF0YWAuICANCg0KNC4gKipDaGVjayB5b3VyIGRhdGEgZnJhbWUqKiB1c2luZyBgaGVhZCgpYCBvciBgVmlldygpYCB0byBlbnN1cmUgaXQgaGFzICoqMzAgcm93cyoqIGFuZCB0aGUgY29sdW1ucyBhcmUgY29ycmVjdC4gIA0KDQo1LiAqKk9wdGlvbmFsIHRhc2tzKio6ICANCiAgIC0gU3VtbWFyaXplIGVhY2ggY29sdW1uIHVzaW5nIGBzdW1tYXJ5KClgICANCiAgIC0gQ291bnQgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIGNhdGVnb3J5IGZvciAqKk5vbWluYWwqKiBhbmQgKipPcmRpbmFsKiogY29sdW1ucyB1c2luZyBgdGFibGUoKWAgIA0KDQojIyMgSGludHMNCg0KLSBVc2UgYHNlcS5EYXRlKClgIG9yIGBhcy5EYXRlKClgIHRvIGdlbmVyYXRlIHRoZSBEYXRlIGNvbHVtbi4gIA0KLSBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuICANCi0gVXNlIGBzYW1wbGUoKWAgZm9yIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbCBkYXRhLiAgDQotIEVuc3VyZSB0aGUgKipvcmRpbmFsIHZlY3RvcioqIGlzIGNyZWF0ZWQgd2l0aCBgZmFjdG9yKC4uLiwgbGV2ZWxzID0gYygiTG93IiwiTWVkaXVtIiwiSGlnaCIpLCBvcmRlcmVkID0gVFJVRSlgIChvciBzaW1pbGFyKS4gIA0KDQoNCiMjIENyZWF0ZSBlYWNoIGNvbHVtbg0KYGBge1J9DQojIyBEYXRlOiAzMCBjb25zZWN1dGl2ZSBkYXRlcyBpbiBPY3RvYmVyIDIwMjUNCkRhdGUgPC0gc2VxLkRhdGUoZnJvbSA9IGFzLkRhdGUoIjIwMjUtMTAtMDEiKSwgDQogICAgICAgICAgICAgICAgIGJ5ID0gImRheSIsIA0KICAgICAgICAgICAgICAgICBsZW5ndGgub3V0ID0gMzApDQoNCiMjIENvbnRpbnVvdXM6IGZvciBleGFtcGxlIGJvZHkgdGVtcGVyYXR1cmUgZGF0YSAoaW4gwrBDKSwgdXNlIGRlY2ltYWxzDQpDb250aW51b3VzIDwtIHJvdW5kKHJ1bmlmKDMwLCBtaW4gPSAzNS41LCBtYXggPSAzNy41KSwgMSkNCg0KIyMgRGlzY3JldGU6IGUuZy4gbnVtYmVyIG9mIGl0ZW1zIHNvbGQgKHdob2xlIG51bWJlcikNCkRpc2NyZXRlIDwtIHNhbXBsZSgxOjUwLCAzMCwgcmVwbGFjZSA9IFRSVUUpDQoNCiMjIE5vbWluYWw6IGUuZy4gY3V0b21lcidzIGNpdHkgb2Ygb3JpZ2luIChubyBvcmRlcikNCk5vbWluYWwgPC0gc2FtcGxlKGMoIkpha2FydGEiLCAiQmFuZHVuZyIsICJTdXJhYmF5YSIsICJNZWRhbiIsICJCYWxpIiksDQogICAgICAgICAgICAgICAgICAzMCwgcmVwbGFjZSA9IFRSVUUpDQoNCiMjIE9yZGluYWw6IGUuZy4gc2F0aXNmYWN0aW9uIGxldmVsICh0aGVyZSBpcyBhIHNlcXVlbmNlKQ0KT3JkaW5hbCA8LSBmYWN0b3IoDQogIHNhbXBsZShjKCJMb3ciLCAiTWVkaXVtIiwgIkhpZ2giKSwgMzAsIHJlcGxhY2UgPSBUUlVFKSwNCiAgbGV2ZWxzID0gYygiTG93IiwgIk1lZGl1bSIsICJIaWdoIiksDQogIG9yZGVyZWQgPSBUUlVFDQopDQpgYGANCg0KIyMgQ29tYmluZSBhbGwgaW50byBhIGRhdGEgZnJhbWUNCmBgYHtSfQ0KbXlfZGF0YSA8LSBkYXRhLmZyYW1lKERhdGUsIENvbnRpbnVvdXMsIERpc2NyZXRlLCBOb21pbmFsLCBPcmRpbmFsKQ0KYGBgDQoNCiMjIENoZWNrIHRoZSBkYXRhIGNvbnRlbnRzDQpgYGB7Un0NCmhlYWQobXlfZGF0YSkgICAjIGRpc3BsYXkgdGhlIGZpcnN0IDYgcm93cw0KVmlldyhteV9kYXRhKSAgICMgb3BlbiBpbiBSc3R1ZGlvIHdpbmRvdyAob3B0aW9uYWwpDQpgYGANCg0KIyMgKE9wdGlvbmFsKSBEYXRhIFN1bW1hcnkNCmBgYHtSfQ0Kc3VtbWFyeShteV9kYXRhKQ0KYGBgDQojIyBDYWxjdWxhdGUgZnJlcXVlbmN5IGNhdGVnb3JpZXMNCmBgYHtSfQ0KY2F0KCJcbiBOb21pbmFsIEZyZXF1ZW5jeSAoQ2l0eSkgXG4iKQ0KcHJpbnQodGFibGUobXlfZGF0YSROb21pbmFsKSkNCg0KY2F0KCJcbiBPcmRpbmFsIEZyZXF1ZW5jeSAoTGV2ZWwgb2YgU2F0aXNmYWN0aW9uKSBcbiIpDQpwcmludCh0YWJsZShteV9kYXRhJE9yZGluYWwpKQ0KYGBgDQoNCg0K