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(
    "Numeric",
    "Numeric",
    "Categorical",
    "Categorical",
    "Categorical"
  ),
  Subtype = c(
    "discerete",
    "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 Numeric discerete
2 Student height in cm Numeric Continuous
3 Employee gender (Male / Female) Categorical Nominal
4 Customer satisfaction level: Low, Medium, High Categorical Ordinal
5 Respondent’s favorite color: Red, Blue, Green Categorical 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",
    "external",
    "external",
    "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

## 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.

library(DT)
# Transactions
transactions <- data.frame(
  No = 1 : 10,
  
  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")) 

library(knitr)

# Create a data frame for Data Types
variables_info <- data.frame(
  No = 1:4,
  Variable = c(
    "Qty",
    "Price",
    "Product",
    "CustomerTier"
  ),
  DataType = c(
    "Numeric",
    "Numeric",
    "Categorical",
    "Categorical"
  ),
  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
1 Qty Numeric
2 Price Numeric
3 Product Categorical
4 CustomerTier Categorical
#transactions total

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

datatable(transactions,
          caption = "Table of Transactions",
          rownames = FALSE)
#total qty

total_qty_per_product <- aggregate(Qty ~ Product, data = transactions, FUN = sum)
print("Total Kuantitas Terjual per Produk:")
## [1] "Total Kuantitas Terjual per Produk:"
print(total_qty_per_product)
##    Product Qty
## 1 Keyboard  14
## 2   Laptop   6
## 3    Mouse  12
#Total reveneu

total_revenue_per_product <- aggregate(Total ~ Product, data = transactions, FUN = sum)
print("Total Pendapatan per Produk:")
## [1] "Total Pendapatan per Produk:"
print(total_revenue_per_product)
##    Product Total
## 1 Keyboard   290
## 2   Laptop  6000
## 3    Mouse   420
#price product

average_price_per_product <- aggregate(Price ~ Product, data = transactions, FUN = mean)
print("Harga Rata-rata per Produk:")
## [1] "Harga Rata-rata per Produk:"
print(average_price_per_product)
##    Product      Price
## 1 Keyboard   21.66667
## 2   Laptop 1000.00000
## 3    Mouse   36.66667
#Barplot: Total Kuantitas Terjual per Produk
barplot(
  height = total_qty_per_product$Qty, 
  names.arg = total_qty_per_product$Product,
  main = "Total transactions",
  xlab = "Produk",
  ylab = "kuantitas",
  col = c("red4", "pink", "hotpink4"),
  ylim = c(0, max(total_qty_per_product$Qty) + 2) 
)

#Piechart
revenue_per_tier <- aggregate(Total ~ CustomerTier, data = transactions, FUN = sum)
total_revenue <- sum(revenue_per_tier$Total)
percentages <- round(revenue_per_tier$Total / total_revenue * 100, 1)
pie_labels <- paste(revenue_per_tier$CustomerTier, " (", percentages, "%)", sep="")

pie(
  x = revenue_per_tier$Total, 
  labels = pie_labels,
  main = "Proporsi Total Pendapatan per Tingkat Pelanggan",
  col = c("thistle", "lightpink1", "lightblue")
)

#optional (2)
kuantitas <- as.matrix(data.frame(Hight = c(3),
                                  Medium = c(4),
                                  Low = c(3)))
rownames(kuantitas) <- c("Qty")
kuantitas
##     Hight Medium Low
## Qty     3      4   3
nama <- c("hight", "medium", "low")
barplot(kuantitas, names.arg = nama)

barplot(kuantitas, names.arg = nama, xlim = c(0,5),
        xlab = "CustomerTier", ylab = "Qty",
        main = "Total kuantitas berdasarkan kepuasan pelanggan", density = 20,
        col = c("orchid"), horiz = TRUE)

4 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.

4.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()

4.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).
library(DT)
library(knitr)
#my_data

# main plants data
Date <- c("Januari", "Februari", "Maret", "April", 
          "Mei", "Juni", "Juli", "Agustus", 
          "September", "Oktober", "November", 
          "Desember", "Januari", "Februari", 
          "Maret", "April", "Mei", "Juni", 
          "Juli", "Agustus", "September", 
          "Oktober", "November", "Desember", 
          "Januari", "Februari", "Maret", "April", 
          "Mei", "Juni")

Name <- c("Mawar", "Melati", "Anggrek", "Kaktus", 
          "Lidah buaya", "Padi", "Jagung", 
          "Pisang", "Mangga", "Jambu", "Kelapa", 
          "Tomat", "Cabai", "Bayam", 
          "Kacang Panjang", "Terong", "Pepaya", 
          "Apel", "Stroberi", "Nangka", "Durian", 
          "Semangka", "Mentimun", "Wortel", 
          "Kentang", "Singkong", "Tebu", "Kopi", 
          "Teh", "Bambu")

Type <- c("Bunga", "Bunga", "Bunga", "Sukulen", 
          "Sukulen", "Tanaman Pangan", 
          "Tanaman Pangan", "Buah", "Pohon", 
          "Pohon", "Pohon", "Sayuran", "Sayuran", 
          "Sayuran", "Sayuran", "Sayuran", "Buah", 
          "Buah", "Buah", "Pohon", "Pohon", 
          "Buah", "Sayuran", "Sayuran", "Sayuran", 
          "Tanaman Pangan", "Tanaman Pangan", 
          "Pohon", "Pohon", "Pohon")

Height <- as.numeric(gsub(",", ".", c("35,4", "28,6", "42,3", "25,1",
                                      "39,7", "87,2", "120,5", "210,8",
                                      "250,4", "190,2", "340,6", "45,3",
                                      "55,9", "30,1", "80,4", "60,7",
                                      "190,8", "230,5", "25,6", "270,9",
                                      "310,3", "85,7", "40,2", "33,9", 
                                      "27,5", "150,8", "260,1", "170,6", 
                                      "145,2", "400,7")))

Totalplants <- as.integer(c("12", "15", "10", "8", "14", "22", "18", 
                            "16", "35", "28", "42", "20", "18", "25",
                            "30", "17", "27", "33", "14", "40", "45",
                            "19", "22", "24", "18", "26", "32", 
                            "29", "21", "50"))

Totalplants <- as.integer(c("12", "15", "10", "8", "14", "22", "18", 
                            "16", "35", "28", "42", "20", "18", "25",
                            "30", "17", "27", "33", "14", "40", "45",
                            "19", "22", "24", "18", "26", "32", 
                            "29", "21", "50"))

Growth <- c("Baik", "Sangat baik", "Baik", 
            "Kurang baik", "Baik", 
            "Sangat baik", "Baik", "Baik",
            "Sangat baik", "Baik", 
            "Sangat baik", "Baik", "Baik",
            "Sangat baik", "Baik", 
            "Baik", "Sangat baik", "Baik",
            "Baik", "Baik", "Sangat baik", 
            "Baik", "Baik", "Baik", "Kurang baik", 
            "Baik", "Sangat baik", "Baik", "Baik", 
            "Sangat baik")

# Combine into a data frame
my_data <- data.frame(Date, Name, Type, Height, Totalplants, Growth)

# Display interactive table
datatable(my_data, caption = "Table of Plant Development", options = list(pageLength = 10))
# Create a second table for variable types
variables_info <- data.frame(
  No = 1:4,
  Variable = c(
    "Height",
    "Growth", 
    "Totalplants",
    "Type"),
  
  DataType = c(
    "Continuous", 
    "Ordinal", 
    "Discrete", 
    "Nominal"),
  stringsAsFactors = FALSE
)

# Display static table
kable(variables_info, caption = "Table of Variables and Data Types", rownames = FALSE)
Table of Variables and Data Types
No Variable DataType
1 Height Continuous
2 Growth Ordinal
3 Totalplants Discrete
4 Type Nominal
# Summariz data
cat("--- ringkasan my_data (summary( my_data ) ---\n")
## --- ringkasan my_data (summary( my_data ) ---
summary(my_data)
##      Date               Name               Type               Height      
##  Length:30          Length:30          Length:30          Min.   : 25.10  
##  Class :character   Class :character   Class :character   1st Qu.: 39.83  
##  Mode  :character   Mode  :character   Mode  :character   Median : 86.45  
##                                                           Mean   :132.87  
##                                                           3rd Qu.:205.80  
##                                                           Max.   :400.70  
##   Totalplants       Growth         
##  Min.   : 8.00   Length:30         
##  1st Qu.:17.25   Class :character  
##  Median :22.00   Mode  :character  
##  Mean   :24.33                     
##  3rd Qu.:29.75                     
##  Max.   :50.00
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAyIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6DQotICJBZGluZGEgQWRlbGlhLA0KQW5nZWxpY2EgRmxvcmVudGluYSwNCkJvbWEgU2F0cmlvLA0KQ2hyaWN5ZXNpYSBXaW5uZXJsYWR5LCANClN5YWZpZiBBem1pIiAgICAgICAgIA0KI1JlcGxhY2Ugd2l0aCB5b3VyIGZ1bGwgbmFtZQ0KZGF0ZTogICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCIgIyBBdXRvIGRpc3BsYXlzIHRoZSBjdXJyZW50IGRhdGUNCm91dHB1dDogICAgICAgICAgICAgICAgICAgICAgICAgIyBPdXRwdXQgc2VjdGlvbiBkZWZpbmVzIHRoZSBmb3JtYXQgYW5kIGxheW91dCANCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgICAgIyBodHRwczovL2dpdGh1Yi5jb20vanViYS9ybWRmb3JtYXRzDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUgICAgICAgICMgRW1iZWRzIGFsbCByZXNvdXJjZXMgKENTUywgSlMsIGltYWdlcykgDQogICAgdGh1bWJuYWlsczogdHJ1ZSAgICAgICAgICAgICMgRGlzcGxheXMgaW1hZ2UgdGh1bWJuYWlscyBpbiB0aGUgZG9jDQogICAgbGlnaHRib3g6IHRydWUgICAgICAgICAgICAgICMgRW5hYmxlcyBjbGljayB0byBlbmxhcmdlIGltYWdlcw0KICAgIGdhbGxlcnk6IHRydWUgICAgICAgICAgICAgICAjIEdyb3VwcyBpbWFnZXMgaW50byBhbiBpbnRlcmFjdGl2ZSBnYWxsZXJ5DQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAgICAgICMgQXV0b21hdGljYWxseSBudW1iZXJzIGFsbCBzZWN0aW9ucw0KICAgIGxpYl9kaXI6IGxpYnMgICAgICAgICAgICAgICAjIERpcmVjdG9yeSB3aGVyZSBKYXZhU2NyaXB0L0NTUyBsaWJyYXJpZXMNCiAgICBkZl9wcmludDogInBhZ2VkIiAgICAgICAgICAgIyBEaXNwbGF5cyBkYXRhIGZyYW1lcyBhcyBpbnRlcmFjdGl2ZSBwYWdlZCANCiAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IiAgICAgICAgIyBBbGxvd3MgZm9sZGluZy91bmZvbGRpbmcgUiBjb2RlIGJsb2NrcyANCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMgICAgICAgICAgIyBBZGRzIGEgYnV0dG9uIHRvIGRvd25sb2FkIGFsbCBSIGNvZGUNCi0tLQ0KDQoNCjxpbWcgaWQ9IkZvdG8iIHNyYz0iaHR0cHM6Ly9naXRodWIuY29tL2RzY2llbmNlbGFicy9pbWFnZXMvYmxvYi9tYXN0ZXIvTG9nb19Ec2NpZW5jZWxhYnNfdjEucG5nP3Jhdz10cnVlIiBhbHQ9IkxvZ28iIHN0eWxlPSJ3aWR0aDoyMDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiPg0KDQotLS0NCg0KIyMgRXhlcmNpc2UgMQ0KDQpUaGUgZm9sbG93aW5nIHRhYmxlIHNob3dzIHNhbXBsZSBpbmZvcm1hdGlvbiBmb3IgdGhyZWUgc3R1ZGVudHMuIEVhY2ggb2JzZXJ2YXRpb24gcmVwcmVzZW50cyBhIHNpbmdsZSBzdHVkZW50IGFuZCBpbmNsdWRlcyBkZXRhaWxzIHN1Y2ggYXMgdGhlaXIgdW5pcXVlIHN0dWRlbnQgSUQsIG5hbWUsIGFnZSwgdG90YWwgY3JlZGl0cyBjb21wbGV0ZWQsIG1ham9yIGZpZWxkIG9mIHN0dWR5LCBhbmQgeWVhciBsZXZlbC4gIA0KDQpUaGlzIGRhdGFzZXQgZGVtb25zdHJhdGVzIGEgbWl4dHVyZSBvZiB2YXJpYWJsZSB0eXBlczogIA0KDQotICoqTm9taW5hbDoqKiBTdHVkZW50SUQsIE5hbWUsIE1ham9yICANCi0gKipOdW1lcmljOioqIEFnZSAoY29udGludW91cyksIENyZWRpdHNDb21wbGV0ZWQgKGRpc2NyZXRlKSAgDQotICoqT3JkaW5hbDoqKiBZZWFyTGV2ZWwgKEZyZXNobWFuIOKGkiBTZW5pb3IpICANCg0KfCBTdHVkZW50SUQgfCBOYW1lICAgfCBBZ2UgfCBDcmVkaXRzQ29tcGxldGVkIHwgTWFqb3IgICAgICAgICAgICB8IFllYXJMZXZlbCB8DQp8LS0tLS0tLS0tLS18LS0tLS0tLS18LS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18DQp8IFMwMDEgICAgICB8IEFsaWNlICB8IDIwICB8IDQ1ICAgICAgICAgICAgICB8IERhdGEgU2FpbnMgICAgICB8IFNvcGhvbW9yZSB8DQp8IFMwMDIgICAgICB8IEJ1ZGkgICB8IDIxICB8IDYwICAgICAgICAgICAgICB8IE1hdGhlbWF0aWNzICAgICB8IEp1bmlvciAgICB8DQp8IFMwMDMgICAgICB8IENpdHJhICB8IDE5ICB8IDMwICAgICAgICAgICAgICB8IFN0YXRpc3RpY3MgICAgICB8IEZyZXNobWFuICB8DQoNCmBgYHtyfQ0KIyAxLiBDcmVhdGUgdmVjdG9ycyBmb3IgZWFjaCB2YXJpYWJsZQ0KU3R1ZGVudElEIDwtIGMoIlMwMDEiLCAiUzAwMiIsICJTMDAzIikgICAgICAgIyBOb21pbmFsIC8gSUQNCk5hbWUgPC0gYygiQWxpY2UiLCAiQnVkaSIsICJDaXRyYSIpICAgICAgICAgICMgTm9taW5hbCAvIE5hbWUNCkFnZSA8LSBjKDIwLCAyMSwgMTkpICAgICAgICAgICAgICAgICAgICAgICAgICMgTnVtZXJpYyAvIENvbnRpbnVvdXMNCkNyZWRpdHNDb21wbGV0ZWQgPC0gYyg0NSwgNjAsIDMwKSAgICAgICAgICAgICMgTnVtZXJpYyAvIERpc2NyZXRlDQoNCiMgTm9taW5hbA0KTWFqb3IgPC0gYygiRGF0YSBTYWlucyIsICJNYXRoZW1hdGljcyIsICJTdGF0aXN0aWNzIikgIA0KDQojIE9yZGluYWwNClllYXJMZXZlbCA8LSBmYWN0b3IoYygiU29waG9tb3JlIiwgIkp1bmlvciIsICJGcmVzaG1hbiIpLA0KICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJGcmVzaG1hbiIsIlNvcGhvbW9yZSIsIkp1bmlvciIsIlNlbmlvciIpLA0KICAgICAgICAgICAgICAgICAgICBvcmRlcmVkID0gVFJVRSkgICAgICAgICAgDQoNCiMgMi4gQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZQ0Kc3R1ZGVudHMgPC0gZGF0YS5mcmFtZSgNCiAgU3R1ZGVudElELCBOYW1lLCBBZ2UsIENyZWRpdHNDb21wbGV0ZWQsIE1ham9yLCBZZWFyTGV2ZWwsDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIDMuIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCnByaW50KHN0dWRlbnRzKQ0KYGBgDQoNCg0KIyMgRXhlcmNpc2UgMg0KDQoqKklkZW50aWZ5IERhdGEgVHlwZXM6KiogRGV0ZXJtaW5lIHRoZSB0eXBlIG9mIGRhdGEgZm9yIGVhY2ggb2YgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGtuaXRyIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCmxpYnJhcnkoa25pdHIpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgRGF0YSBUeXBlcw0KdmFyaWFibGVzX2luZm8gPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjUsDQogIFZhcmlhYmxlID0gYygNCiAgICAiTnVtYmVyIG9mIHZlaGljbGVzIHBhc3NpbmcgdGhyb3VnaCB0aGUgdG9sbCByb2FkIGVhY2ggZGF5IiwNCiAgICAiU3R1ZGVudCBoZWlnaHQgaW4gY20iLA0KICAgICJFbXBsb3llZSBnZW5kZXIgKE1hbGUgLyBGZW1hbGUpIiwNCiAgICAiQ3VzdG9tZXIgc2F0aXNmYWN0aW9uIGxldmVsOiBMb3csIE1lZGl1bSwgSGlnaCIsDQogICAgIlJlc3BvbmRlbnQncyBmYXZvcml0ZSBjb2xvcjogUmVkLCBCbHVlLCBHcmVlbiINCiAgKSwNCiAgRGF0YVR5cGUgPSBjKA0KICAgICJOdW1lcmljIiwNCiAgICAiTnVtZXJpYyIsDQogICAgIkNhdGVnb3JpY2FsIiwNCiAgICAiQ2F0ZWdvcmljYWwiLA0KICAgICJDYXRlZ29yaWNhbCINCiAgKSwNCiAgU3VidHlwZSA9IGMoDQogICAgImRpc2NlcmV0ZSIsDQogICAgIkNvbnRpbnVvdXMiLA0KICAgICJOb21pbmFsIiwNCiAgICAiT3JkaW5hbCIsDQogICAgIk5vbWluYWwiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQprYWJsZSh2YXJpYWJsZXNfaW5mbywgDQogICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIFZhcmlhYmxlcyBhbmQgRGF0YSBUeXBlcyIpDQpgYGANCi0tLQ0KDQojIyBFeGVyY2lzZSAzDQoNCioqQ2xhc3NpZnkgRGF0YSBTb3VyY2VzOioqIERldGVybWluZSB3aGV0aGVyIHRoZSBmb2xsb3dpbmcgZGF0YSBjb21lcyBmcm9tICoqaW50ZXJuYWwqKiBvciAqKmV4dGVybmFsIHNvdXJjZXMqKiwgYW5kIHdoZXRoZXIgaXQgaXMgKipzdHJ1Y3R1cmVkKiogb3IgKip1bnN0cnVjdHVyZWQqKjoNCg0KYGBge3J9DQojIEluc3RhbGwgRFQgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygiRFQiKQ0KbGlicmFyeShEVCkNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBkYXRhIHNvdXJjZXMgDQpkYXRhX3NvdXJjZXMgPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjQsDQogIERhdGFTb3VyY2UgPSBjKA0KICAgICJEYWlseSBzYWxlcyB0cmFuc2FjdGlvbiBkYXRhIG9mIHRoZSBjb21wYW55IiwNCiAgICAiV2VhdGhlciByZXBvcnRzIGZyb20gQk1LRyIsDQogICAgIlByb2R1Y3QgcmV2aWV3cyBvbiBzb2NpYWwgbWVkaWEiLA0KICAgICJXYXJlaG91c2UgaW52ZW50b3J5IHJlcG9ydHMiDQogICksDQogIEludGVybmFsX0V4dGVybmFsID0gYygNCiAgICJpbnRlcm5hbCIsDQogICAgImV4dGVybmFsIiwNCiAgICAiZXh0ZXJuYWwiLA0KICAgICJpbnRlcm5hbCINCiAgKSwNCiAgU3RydWN0dXJlZF9VbnN0cnVjdHVyZWQgPSBjKA0KICAgICJzdHJ1Y3R1cmVkIiwNCiAgICAic3RydWN0dXJlZCIsDQogICAgInVuc3RydWN0dXJlZCIsDQogICAgInN0cnVjdHVyZWQiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQpkYXRhdGFibGUoZGF0YV9zb3VyY2VzLCANCiAgICAgICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIERhdGEgU291cmNlcyIsDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSkgIyBoaWRlcyB0aGUgaW5kZXggY29sdW1uDQpgYGANCg0KLS0tDQoNCiAjIyBFeGVyY2lzZSA0DQoNCioqRGF0YXNldCBTdHJ1Y3R1cmU6KiogQ29uc2lkZXIgdGhlIGZvbGxvd2luZyB0cmFuc2FjdGlvbiB0YWJsZToNCg0KfCBEYXRlICAgICAgIHwgUXR5IHwgUHJpY2UgfCBQcm9kdWN0ICB8IEN1c3RvbWVyVGllciB8DQp8LS0tLS0tLS0tLS0tfC0tLS0tfC0tLS0tLS18LS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLXwNCnwgMjAyNS0xMC0wMSB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTAxIHwgNSAgIHwgMjAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDMgICB8IDMwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgNCAgIHwgNTAgICAgfCBNb3VzZSAgICB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDYgICB8IDI1ICAgIHwgS2V5Ym9hcmQgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCAzICAgfCA0MCAgICB8IE1vdXNlICAgIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDUgICB8IDEwICAgIHwgS2V5Ym9hcmQgfCBNZWRpdW0gICAgICAgfA0KDQoNCioqWW91ciBBc3NpZ25tZW50IEluc3RydWN0aW9uczoqKiBDcmVhdGluZyBhIFRyYW5zYWN0aW9ucyBUYWJsZSBhYm92ZSBpbiBSDQoNCjEuICoqQ3JlYXRlIGEgZGF0YSBmcmFtZSoqIGluIFIgY2FsbGVkIGB0cmFuc2FjdGlvbnNgIGNvbnRhaW5pbmcgdGhlIGRhdGEgYWJvdmUuDQoNCjIuIElkZW50aWZ5IHdoaWNoIHZhcmlhYmxlcyBhcmUgbnVtZXJpYyBhbmQgd2hpY2ggYXJlIGNhdGVnb3JpY2FsDQoNCjMuICoqQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUqKiBmb3IgZWFjaCB0cmFuc2FjdGlvbiBieSBtdWx0aXBseWluZyBgUXR5IMOXIFByaWNlYCBhbmQgYWRkIGl0IGFzIGEgbmV3IGNvbHVtbiBgVG90YWxgLg0KDQo0LiAqKkNvbXB1dGUgc3VtbWFyeSBzdGF0aXN0aWNzKio6DQogICAtIFRvdGFsIHF1YW50aXR5IHNvbGQgZm9yIGVhY2ggcHJvZHVjdA0KICAgLSBUb3RhbCByZXZlbnVlIHBlciBwcm9kdWN0DQogICAtIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCg0KNS4gKipWaXN1YWxpemUgdGhlIGRhdGEqKjoNCiAgIC0gQ3JlYXRlIGEgKipiYXJwbG90Kiogc2hvd2luZyB0b3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0Lg0KICAgLSBDcmVhdGUgYSAqKnBpZSBjaGFydCoqIHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2YgdG90YWwgcmV2ZW51ZSBwZXIgY3VzdG9tZXIgdGllci4NCg0KNi4gKipPcHRpb25hbCBDaGFsbGVuZ2UqKjoNCiAgIC0gRmluZCB3aGljaCAqKmRhdGUqKiBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZS4NCiAgIC0gQ3JlYXRlIGEgKipzdGFja2VkIGJhciBjaGFydCoqIHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyLg0KDQoqKkhpbnRzOioqIFVzZSBgZGF0YS5mcmFtZSgpYCwgYGFnZ3JlZ2F0ZSgpYCwgYGJhcnBsb3QoKWAsIGBwaWUoKWAsIGFuZCBiYXNpYyBhcml0aG1ldGljIG9wZXJhdGlvbnMgaW4gUi4NCg0KDQpgYGB7cn0NCmxpYnJhcnkoRFQpDQojIFRyYW5zYWN0aW9ucw0KdHJhbnNhY3Rpb25zIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMSA6IDEwLA0KICANCiAgRGF0ZSA9IGMoIjIwMjUtMTAtMDEiLCAiMjAyNS0xMC0wMSIsDQogICAgICAgICAgICIyMDI1LTEwLTAyIiwgIjIwMjUtMTAtMDIiLCAgIA0KICAgICAgICAgICAiMjAyNS0xMC0wMyIsICIyMDI1LTEwLTAzIiwgDQogICAgICAgICAgICIyMDI1LTEwLTA0IiwgIjIwMjUtMTAtMDQiLCANCiAgICAgICAgICAgIjIwMjUtMTAtMDUiLCAiMjAyNS0xMC0wNSIpLA0KICAgICAgICAgICANClF0eSA9IGMoMiwgNSwgMSwgMywgNCwgMiwgNiwgMSwgMywgNSksIA0KDQpQcmljZSA9IGMoMTAwMCwgMjAsIDEwMDAsIDMwLCA1MCwgMTAwMCwgMjUsIDEwMDAsIDQwLCAxMCksIA0KDQpQcm9kdWN0ID0gYygiTGFwdG9wIiwgIk1vdXNlIiwgIkxhcHRvcCIsIA0KICAgICAgICAgICAgIktleWJvYXJkIiwgIk1vdXNlIiwgIkxhcHRvcCIsIA0KICAgICAgICAgICAgIktleWJvYXJkIiwgIkxhcHRvcCIsICJNb3VzZSIsICJLZXlib2FyZCIpLCANCiAgICAgICAgICAgIA0KQ3VzdG9tZXJUaWVyID0gYygiSGlnaCIsICJNZWRpdW0iLCAiTG93IiwgDQogICAgICAgICAgICAgICAgICJNZWRpdW0iLCAiTWVkaXVtIiwgIkhpZ2giLCANCiAgICAgICAgICAgICAgICAgIkxvdyIsICJIaWdoIiwgIkxvdyIsICJNZWRpdW0iKSkgDQoNCmxpYnJhcnkoa25pdHIpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgRGF0YSBUeXBlcw0KdmFyaWFibGVzX2luZm8gPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjQsDQogIFZhcmlhYmxlID0gYygNCiAgICAiUXR5IiwNCiAgICAiUHJpY2UiLA0KICAgICJQcm9kdWN0IiwNCiAgICAiQ3VzdG9tZXJUaWVyIg0KICApLA0KICBEYXRhVHlwZSA9IGMoDQogICAgIk51bWVyaWMiLA0KICAgICJOdW1lcmljIiwNCiAgICAiQ2F0ZWdvcmljYWwiLA0KICAgICJDYXRlZ29yaWNhbCINCiAgKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSBhcyBhIG5lYXQgdGFibGUNCmthYmxlKHZhcmlhYmxlc19pbmZvLCANCiAgICAgIGNhcHRpb24gPSAiVGFibGUgb2YgVmFyaWFibGVzIGFuZCBEYXRhIFR5cGVzIikNCg0KDQojdHJhbnNhY3Rpb25zIHRvdGFsDQoNCnRyYW5zYWN0aW9ucyRUb3RhbCA8LSB0cmFuc2FjdGlvbnMkUXR5ICogdHJhbnNhY3Rpb25zJFByaWNlDQoNCmRhdGF0YWJsZSh0cmFuc2FjdGlvbnMsDQogICAgICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBUcmFuc2FjdGlvbnMiLA0KICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UpDQoNCiN0b3RhbCBxdHkNCg0KdG90YWxfcXR5X3Blcl9wcm9kdWN0IDwtIGFnZ3JlZ2F0ZShRdHkgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBGVU4gPSBzdW0pDQpwcmludCgiVG90YWwgS3VhbnRpdGFzIFRlcmp1YWwgcGVyIFByb2R1azoiKQ0KcHJpbnQodG90YWxfcXR5X3Blcl9wcm9kdWN0KQ0KDQojVG90YWwgcmV2ZW5ldQ0KDQp0b3RhbF9yZXZlbnVlX3Blcl9wcm9kdWN0IDwtIGFnZ3JlZ2F0ZShUb3RhbCB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIEZVTiA9IHN1bSkNCnByaW50KCJUb3RhbCBQZW5kYXBhdGFuIHBlciBQcm9kdWs6IikNCnByaW50KHRvdGFsX3JldmVudWVfcGVyX3Byb2R1Y3QpDQoNCiNwcmljZSBwcm9kdWN0DQoNCmF2ZXJhZ2VfcHJpY2VfcGVyX3Byb2R1Y3QgPC0gYWdncmVnYXRlKFByaWNlIH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgRlVOID0gbWVhbikNCnByaW50KCJIYXJnYSBSYXRhLXJhdGEgcGVyIFByb2R1azoiKQ0KcHJpbnQoYXZlcmFnZV9wcmljZV9wZXJfcHJvZHVjdCkNCg0KI0JhcnBsb3Q6IFRvdGFsIEt1YW50aXRhcyBUZXJqdWFsIHBlciBQcm9kdWsNCmJhcnBsb3QoDQogIGhlaWdodCA9IHRvdGFsX3F0eV9wZXJfcHJvZHVjdCRRdHksIA0KICBuYW1lcy5hcmcgPSB0b3RhbF9xdHlfcGVyX3Byb2R1Y3QkUHJvZHVjdCwNCiAgbWFpbiA9ICJUb3RhbCB0cmFuc2FjdGlvbnMiLA0KICB4bGFiID0gIlByb2R1ayIsDQogIHlsYWIgPSAia3VhbnRpdGFzIiwNCiAgY29sID0gYygicmVkNCIsICJwaW5rIiwgImhvdHBpbms0IiksDQogIHlsaW0gPSBjKDAsIG1heCh0b3RhbF9xdHlfcGVyX3Byb2R1Y3QkUXR5KSArIDIpIA0KKQ0KDQojUGllY2hhcnQNCnJldmVudWVfcGVyX3RpZXIgPC0gYWdncmVnYXRlKFRvdGFsIH4gQ3VzdG9tZXJUaWVyLCBkYXRhID0gdHJhbnNhY3Rpb25zLCBGVU4gPSBzdW0pDQp0b3RhbF9yZXZlbnVlIDwtIHN1bShyZXZlbnVlX3Blcl90aWVyJFRvdGFsKQ0KcGVyY2VudGFnZXMgPC0gcm91bmQocmV2ZW51ZV9wZXJfdGllciRUb3RhbCAvIHRvdGFsX3JldmVudWUgKiAxMDAsIDEpDQpwaWVfbGFiZWxzIDwtIHBhc3RlKHJldmVudWVfcGVyX3RpZXIkQ3VzdG9tZXJUaWVyLCAiICgiLCBwZXJjZW50YWdlcywgIiUpIiwgc2VwPSIiKQ0KDQpwaWUoDQogIHggPSByZXZlbnVlX3Blcl90aWVyJFRvdGFsLCANCiAgbGFiZWxzID0gcGllX2xhYmVscywNCiAgbWFpbiA9ICJQcm9wb3JzaSBUb3RhbCBQZW5kYXBhdGFuIHBlciBUaW5na2F0IFBlbGFuZ2dhbiIsDQogIGNvbCA9IGMoInRoaXN0bGUiLCAibGlnaHRwaW5rMSIsICJsaWdodGJsdWUiKQ0KKQ0KDQojb3B0aW9uYWwgKDIpDQprdWFudGl0YXMgPC0gYXMubWF0cml4KGRhdGEuZnJhbWUoSGlnaHQgPSBjKDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1lZGl1bSA9IGMoNCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTG93ID0gYygzKSkpDQpyb3duYW1lcyhrdWFudGl0YXMpIDwtIGMoIlF0eSIpDQprdWFudGl0YXMNCg0KbmFtYSA8LSBjKCJoaWdodCIsICJtZWRpdW0iLCAibG93IikNCmJhcnBsb3Qoa3VhbnRpdGFzLCBuYW1lcy5hcmcgPSBuYW1hKQ0KICAgICAgICAgDQpiYXJwbG90KGt1YW50aXRhcywgbmFtZXMuYXJnID0gbmFtYSwgeGxpbSA9IGMoMCw1KSwNCiAgICAgICAgeGxhYiA9ICJDdXN0b21lclRpZXIiLCB5bGFiID0gIlF0eSIsDQogICAgICAgIG1haW4gPSAiVG90YWwga3VhbnRpdGFzIGJlcmRhc2Fya2FuIGtlcHVhc2FuIHBlbGFuZ2dhbiIsIGRlbnNpdHkgPSAyMCwNCiAgICAgICAgY29sID0gYygib3JjaGlkIiksIGhvcml6ID0gVFJVRSkNCg0KYGBgDQoNCg0KIyMgRXhlcmNpc2UgNQ0KDQoqKkNyZWF0ZSBZb3VyIE93biBEYXRhIEZyYW1lOioqDQoNCioqT2JqZWN0aXZlOioqIENyZWF0ZSBhIGRhdGEgZnJhbWUgaW4gUiB3aXRoICoqMzAgcm93cyoqIGNvbnRhaW5pbmcgYSBtaXggb2YgZGF0YSB0eXBlczogY29udGludW91cywgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsLiAgDQoNCiMjIyBJbnN0cnVjdGlvbnMNCg0KMS4gKipPcGVuIFJTdHVkaW8qKiBvciB0aGUgUiBjb25zb2xlLiAgDQoNCjIuICoqQ3JlYXRlIGEgdmVjdG9yIGZvciBlYWNoIGNvbHVtbioqIGluIHlvdXIgZGF0YSBmcmFtZTogIA0KDQogICAtICoqRGF0ZSoqOiAzMCBkYXRlcyAoY2FuIGJlIHNlcXVlbnRpYWwgb3IgcmFuZG9tIHdpdGhpbiBhIG1vbnRoL3llYXIpICANCiAgIC0gKipDb250aW51b3VzKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIHRha2UgZGVjaW1hbCB2YWx1ZXMgKGUuZy4sIGhlaWdodCwgd2VpZ2h0LCB0ZW1wZXJhdHVyZSkgIA0KICAgLSAqKkRpc2NyZXRlKio6IG51bWVyaWMgdmFsdWVzIHRoYXQgY2FuIG9ubHkgdGFrZSB3aG9sZSBudW1iZXJzIChlLmcuLCBudW1iZXIgb2YgaXRlbXMsIG51bWJlciBvZiB2ZWhpY2xlcykgIA0KICAgLSAqKk5vbWluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggKipubyBvcmRlcioqIChlLmcuLCBjb2xvciwgZ2VuZGVyLCBjaXR5KSAgDQogICAtICoqT3JkaW5hbCoqOiBjYXRlZ29yaWNhbCB2YWx1ZXMgd2l0aCBhICoqZGVmaW5lZCBvcmRlcioqIChlLmcuLCBMb3csIE1lZGl1bSwgSGlnaDsgQmVnaW5uZXIsIEludGVybWVkaWF0ZSwgRXhwZXJ0KSAgDQoNCjMuICoqQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZSoqIGNhbGxlZCBgbXlfZGF0YWAuICANCg0KNC4gKipDaGVjayB5b3VyIGRhdGEgZnJhbWUqKiB1c2luZyBgaGVhZCgpYCBvciBgVmlldygpYCB0byBlbnN1cmUgaXQgaGFzICoqMzAgcm93cyoqIGFuZCB0aGUgY29sdW1ucyBhcmUgY29ycmVjdC4gIA0KDQo1LiAqKk9wdGlvbmFsIHRhc2tzKio6ICANCiAgIC0gU3VtbWFyaXplIGVhY2ggY29sdW1uIHVzaW5nIGBzdW1tYXJ5KClgICANCiAgIC0gQ291bnQgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIGNhdGVnb3J5IGZvciAqKk5vbWluYWwqKiBhbmQgKipPcmRpbmFsKiogY29sdW1ucyB1c2luZyBgdGFibGUoKWAgIA0KDQojIyMgSGludHMNCg0KLSBVc2UgYHNlcS5EYXRlKClgIG9yIGBhcy5EYXRlKClgIHRvIGdlbmVyYXRlIHRoZSBEYXRlIGNvbHVtbi4gIA0KLSBVc2UgYHJ1bmlmKClgIG9yIGBybm9ybSgpYCBmb3IgY29udGludW91cyBudW1lcmljIGRhdGEuICANCi0gVXNlIGBzYW1wbGUoKWAgZm9yIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbCBkYXRhLiAgDQotIEVuc3VyZSB0aGUgKipvcmRpbmFsIHZlY3RvcioqIGlzIGNyZWF0ZWQgd2l0aCBgZmFjdG9yKC4uLiwgbGV2ZWxzID0gYygiTG93IiwiTWVkaXVtIiwiSGlnaCIpLCBvcmRlcmVkID0gVFJVRSlgIChvciBzaW1pbGFyKS4gIA0KDQpgYGB7cn0NCmxpYnJhcnkoRFQpDQpsaWJyYXJ5KGtuaXRyKQ0KI215X2RhdGENCg0KIyBtYWluIHBsYW50cyBkYXRhDQpEYXRlIDwtIGMoIkphbnVhcmkiLCAiRmVicnVhcmkiLCAiTWFyZXQiLCAiQXByaWwiLCANCiAgICAgICAgICAiTWVpIiwgIkp1bmkiLCAiSnVsaSIsICJBZ3VzdHVzIiwgDQogICAgICAgICAgIlNlcHRlbWJlciIsICJPa3RvYmVyIiwgIk5vdmVtYmVyIiwgDQogICAgICAgICAgIkRlc2VtYmVyIiwgIkphbnVhcmkiLCAiRmVicnVhcmkiLCANCiAgICAgICAgICAiTWFyZXQiLCAiQXByaWwiLCAiTWVpIiwgIkp1bmkiLCANCiAgICAgICAgICAiSnVsaSIsICJBZ3VzdHVzIiwgIlNlcHRlbWJlciIsIA0KICAgICAgICAgICJPa3RvYmVyIiwgIk5vdmVtYmVyIiwgIkRlc2VtYmVyIiwgDQogICAgICAgICAgIkphbnVhcmkiLCAiRmVicnVhcmkiLCAiTWFyZXQiLCAiQXByaWwiLCANCiAgICAgICAgICAiTWVpIiwgIkp1bmkiKQ0KDQpOYW1lIDwtIGMoIk1hd2FyIiwgIk1lbGF0aSIsICJBbmdncmVrIiwgIktha3R1cyIsIA0KICAgICAgICAgICJMaWRhaCBidWF5YSIsICJQYWRpIiwgIkphZ3VuZyIsIA0KICAgICAgICAgICJQaXNhbmciLCAiTWFuZ2dhIiwgIkphbWJ1IiwgIktlbGFwYSIsIA0KICAgICAgICAgICJUb21hdCIsICJDYWJhaSIsICJCYXlhbSIsIA0KICAgICAgICAgICJLYWNhbmcgUGFuamFuZyIsICJUZXJvbmciLCAiUGVwYXlhIiwgDQogICAgICAgICAgIkFwZWwiLCAiU3Ryb2JlcmkiLCAiTmFuZ2thIiwgIkR1cmlhbiIsIA0KICAgICAgICAgICJTZW1hbmdrYSIsICJNZW50aW11biIsICJXb3J0ZWwiLCANCiAgICAgICAgICAiS2VudGFuZyIsICJTaW5na29uZyIsICJUZWJ1IiwgIktvcGkiLCANCiAgICAgICAgICAiVGVoIiwgIkJhbWJ1IikNCg0KVHlwZSA8LSBjKCJCdW5nYSIsICJCdW5nYSIsICJCdW5nYSIsICJTdWt1bGVuIiwgDQogICAgICAgICAgIlN1a3VsZW4iLCAiVGFuYW1hbiBQYW5nYW4iLCANCiAgICAgICAgICAiVGFuYW1hbiBQYW5nYW4iLCAiQnVhaCIsICJQb2hvbiIsIA0KICAgICAgICAgICJQb2hvbiIsICJQb2hvbiIsICJTYXl1cmFuIiwgIlNheXVyYW4iLCANCiAgICAgICAgICAiU2F5dXJhbiIsICJTYXl1cmFuIiwgIlNheXVyYW4iLCAiQnVhaCIsIA0KICAgICAgICAgICJCdWFoIiwgIkJ1YWgiLCAiUG9ob24iLCAiUG9ob24iLCANCiAgICAgICAgICAiQnVhaCIsICJTYXl1cmFuIiwgIlNheXVyYW4iLCAiU2F5dXJhbiIsIA0KICAgICAgICAgICJUYW5hbWFuIFBhbmdhbiIsICJUYW5hbWFuIFBhbmdhbiIsIA0KICAgICAgICAgICJQb2hvbiIsICJQb2hvbiIsICJQb2hvbiIpDQoNCkhlaWdodCA8LSBhcy5udW1lcmljKGdzdWIoIiwiLCAiLiIsIGMoIjM1LDQiLCAiMjgsNiIsICI0MiwzIiwgIjI1LDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMzksNyIsICI4NywyIiwgIjEyMCw1IiwgIjIxMCw4IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI1MCw0IiwgIjE5MCwyIiwgIjM0MCw2IiwgIjQ1LDMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiNTUsOSIsICIzMCwxIiwgIjgwLDQiLCAiNjAsNyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxOTAsOCIsICIyMzAsNSIsICIyNSw2IiwgIjI3MCw5IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjMxMCwzIiwgIjg1LDciLCAiNDAsMiIsICIzMyw5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyNyw1IiwgIjE1MCw4IiwgIjI2MCwxIiwgIjE3MCw2IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxNDUsMiIsICI0MDAsNyIpKSkNCg0KVG90YWxwbGFudHMgPC0gYXMuaW50ZWdlcihjKCIxMiIsICIxNSIsICIxMCIsICI4IiwgIjE0IiwgIjIyIiwgIjE4IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjE2IiwgIjM1IiwgIjI4IiwgIjQyIiwgIjIwIiwgIjE4IiwgIjI1IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMzAiLCAiMTciLCAiMjciLCAiMzMiLCAiMTQiLCAiNDAiLCAiNDUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxOSIsICIyMiIsICIyNCIsICIxOCIsICIyNiIsICIzMiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICIyOSIsICIyMSIsICI1MCIpKQ0KDQpUb3RhbHBsYW50cyA8LSBhcy5pbnRlZ2VyKGMoIjEyIiwgIjE1IiwgIjEwIiwgIjgiLCAiMTQiLCAiMjIiLCAiMTgiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTYiLCAiMzUiLCAiMjgiLCAiNDIiLCAiMjAiLCAiMTgiLCAiMjUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzMCIsICIxNyIsICIyNyIsICIzMyIsICIxNCIsICI0MCIsICI0NSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjE5IiwgIjIyIiwgIjI0IiwgIjE4IiwgIjI2IiwgIjMyIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjI5IiwgIjIxIiwgIjUwIikpDQoNCkdyb3d0aCA8LSBjKCJCYWlrIiwgIlNhbmdhdCBiYWlrIiwgIkJhaWsiLCANCiAgICAgICAgICAgICJLdXJhbmcgYmFpayIsICJCYWlrIiwgDQogICAgICAgICAgICAiU2FuZ2F0IGJhaWsiLCAiQmFpayIsICJCYWlrIiwNCiAgICAgICAgICAgICJTYW5nYXQgYmFpayIsICJCYWlrIiwgDQogICAgICAgICAgICAiU2FuZ2F0IGJhaWsiLCAiQmFpayIsICJCYWlrIiwNCiAgICAgICAgICAgICJTYW5nYXQgYmFpayIsICJCYWlrIiwgDQogICAgICAgICAgICAiQmFpayIsICJTYW5nYXQgYmFpayIsICJCYWlrIiwNCiAgICAgICAgICAgICJCYWlrIiwgIkJhaWsiLCAiU2FuZ2F0IGJhaWsiLCANCiAgICAgICAgICAgICJCYWlrIiwgIkJhaWsiLCAiQmFpayIsICJLdXJhbmcgYmFpayIsIA0KICAgICAgICAgICAgIkJhaWsiLCAiU2FuZ2F0IGJhaWsiLCAiQmFpayIsICJCYWlrIiwgDQogICAgICAgICAgICAiU2FuZ2F0IGJhaWsiKQ0KDQojIENvbWJpbmUgaW50byBhIGRhdGEgZnJhbWUNCm15X2RhdGEgPC0gZGF0YS5mcmFtZShEYXRlLCBOYW1lLCBUeXBlLCBIZWlnaHQsIFRvdGFscGxhbnRzLCBHcm93dGgpDQoNCiMgRGlzcGxheSBpbnRlcmFjdGl2ZSB0YWJsZQ0KZGF0YXRhYmxlKG15X2RhdGEsIGNhcHRpb24gPSAiVGFibGUgb2YgUGxhbnQgRGV2ZWxvcG1lbnQiLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApKQ0KDQojIENyZWF0ZSBhIHNlY29uZCB0YWJsZSBmb3IgdmFyaWFibGUgdHlwZXMNCnZhcmlhYmxlc19pbmZvIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo0LA0KICBWYXJpYWJsZSA9IGMoDQogICAgIkhlaWdodCIsDQogICAgIkdyb3d0aCIsIA0KICAgICJUb3RhbHBsYW50cyIsDQogICAgIlR5cGUiKSwNCiAgDQogIERhdGFUeXBlID0gYygNCiAgICAiQ29udGludW91cyIsIA0KICAgICJPcmRpbmFsIiwgDQogICAgIkRpc2NyZXRlIiwgDQogICAgIk5vbWluYWwiKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgRGlzcGxheSBzdGF0aWMgdGFibGUNCmthYmxlKHZhcmlhYmxlc19pbmZvLCBjYXB0aW9uID0gIlRhYmxlIG9mIFZhcmlhYmxlcyBhbmQgRGF0YSBUeXBlcyIsIHJvd25hbWVzID0gRkFMU0UpDQoNCiMgU3VtbWFyaXogZGF0YQ0KY2F0KCItLS0gcmluZ2thc2FuIG15X2RhdGEgKHN1bW1hcnkoIG15X2RhdGEgKSAtLS1cbiIpDQpzdW1tYXJ5KG15X2RhdGEpDQoNCmBgYA0KDQo=