Data Exploration

Exercises ~ Week 3

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(
    "Discrete",
    "Continous",
    "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 Discrete
2 Student height in cm Numeric Continous
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

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.

  1. 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.
  2. 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.

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

# Create a data frame for Transactions
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"
  )              # Numeric / Discrete
Qty = c (2, 5, 1, 3, 4, 2, 6, 1, 3, 5)   # Numeric / Discrete
Price = c (1000, 20, 1000, 30, 50, 1000, 25, 1000, 40, 10)   # Numeric / Discrete

# Nominal
Product = c (
  "Laptop",
  "Mouse",
  "Laptop",
  "Keyboard",
  "Mouse",
  "Laptop",
  "Keyboard",
  "Laptop",
  "Mouse",
  "Keyboard"
  )           # Categorical / Nominal

# Ordinal
CustomerTier = factor(c(
  "High",
  "Medium",
  "Low",
  "Medium",
  "Medium",
  "High",
  "Low",
  "High",
  "Low",
  "Medium"
  ),
levels = c("Low","Medium","High"),
ordered = TRUE) 

# 2. Combine all vectors into a data frame
transactions =  data.frame (Date, Qty, Price, Product, CustomerTier, stringsAsFactors = FALSE)

# 3. Display the data frame
library(knitr)
kable(transactions)
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
# 2. Identify variable types
library(knitr)
variable_types <- data.frame(
  Variable = c(
    "Date",
    "Qty",
    "Price",
    "Product",
    "CustomerTier"
    ),
  Type = c(
    "Numeric (Discrete)",
    "Numeric (Discrete)",
    "Numeric (Discrete)",
    "Categorical (Nominal)",
    "Categorical (Ordinal)"
    )
)

# Display the data frame
kable(variable_types, caption = "Variable Types in Transactions Data")
Variable Types in Transactions Data
Variable Type
Date Numeric (Discrete)
Qty Numeric (Discrete)
Price Numeric (Discrete)
Product Categorical (Nominal)
CustomerTier Categorical (Ordinal)
# 3. Calculate total revenue
transactions$total = transactions$Qty * transactions$Price
kable(transactions)
Date Qty Price Product CustomerTier total
2025-10-01 2 1000 Laptop High 2000
2025-10-01 5 20 Mouse Medium 100
2025-10-02 1 1000 Laptop Low 1000
2025-10-02 3 30 Keyboard Medium 90
2025-10-03 4 50 Mouse Medium 200
2025-10-03 2 1000 Laptop High 2000
2025-10-04 6 25 Keyboard Low 150
2025-10-04 1 1000 Laptop High 1000
2025-10-05 3 40 Mouse Low 120
2025-10-05 5 10 Keyboard Medium 50
# 4. Compute summary statistic

# a. Total quantity sold for each product
total_Qty = aggregate(Qty ~ Product, data = transactions, sum)
kable(total_Qty, caption = "Total Quantity Sold per Product")
Total Quantity Sold per Product
Product Qty
Keyboard 14
Laptop 6
Mouse 12
# b. total revenue per product
total_revenue = aggregate(total ~ Product, data = transactions, sum)
kable(total_revenue, caption = "Total Revenue per Product")
Total Revenue per Product
Product total
Keyboard 290
Laptop 6000
Mouse 420
# c. Average price per product
avg_price = aggregate(Price ~ Product, data = transactions, mean)
kable(avg_price, caption = "Average Price per Product")
Average Price per Product
Product Price
Keyboard 21.66667
Laptop 1000.00000
Mouse 36.66667
# 5. Visualize the data

# a. barplot showing total quantity sold per product
total_qty = tapply(transactions$Qty, transactions$Product, sum)
barplot(total_qty,
        main = "Total Quantity Sold per Product",
        xlab = "Product",
        ylab = "Total Quantity",
        col = "lightblue")

# b. pie chart showing the proportion of total revenue
total_revenue_tier = tapply(transactions$total, transactions$CustomerTier, sum)
pie(total_revenue_tier,
    main = "Proportion of Total Revenue per Customer Tier",
    col = rainbow(length(total_revenue_tier)))

# 6. Optional challenge

# a. Find which date had the highest total revenue
total_revenue_date <- aggregate(total ~ Date, data = transactions, sum)
total_revenue_date[which.max(total_revenue_date$total), ]
# b. stacked bar chart showing quantity sold per product by customer tier
qty_table = xtabs(Qty ~ Product + CustomerTier, data = transactions)
barplot(qty_table,
        main = "Quantity Sold per Product by Customer Tier",
        xlab = "Product",
        ylab = "Quantity",
        col = c("lightblue", "lightgreen", "pink"))

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.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.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).
# 1. Coffee Shop Data

# Date (30 hari di bulan September)
Date = seq(as.Date("2025-09-01"), as.Date("2025-09-30"), by = "day")

# Continuous: jumlah ml kopi terjual per hari (acak dari 1500–4000 ml)
Coffee_ml = runif(30, min = 1500, max = 4000)

# Discrete: jumlah cangkir kopi terjual per hari (acak 20–100)
Cups_Sold = sample(20:100, 30, replace = TRUE)

# Nominal: jenis minuman kopi
Drink_Type = sample(c("Americano", "Cappuccino", "Latte", "Espresso", "Mocha"), 30, replace = TRUE)

# Ordinal: tingkat kepuasan pelanggan
Customer_Satisfaction = factor(
  sample(c("Poor", "Fair", "Good", "Very Good", "Excellent"), 30, replace = TRUE),
  levels = c("Poor", "Fair", "Good", "Very Good", "Excellent"),
  ordered = TRUE)

# Combine all vectors into a data frame
my_data = data.frame(Date, Coffee_ml, Cups_Sold, Drink_Type, Customer_Satisfaction)
kable(my_data)
Date Coffee_ml Cups_Sold Drink_Type Customer_Satisfaction
2025-09-01 3243.048 67 Espresso Good
2025-09-02 2114.439 83 Espresso Poor
2025-09-03 2893.236 85 Espresso Excellent
2025-09-04 3023.221 67 Latte Good
2025-09-05 2185.550 100 Latte Poor
2025-09-06 1871.067 98 Espresso Fair
2025-09-07 1509.224 45 Cappuccino Fair
2025-09-08 2703.869 58 Cappuccino Good
2025-09-09 1840.767 77 Latte Poor
2025-09-10 2875.354 97 Latte Fair
2025-09-11 1816.171 74 Mocha Fair
2025-09-12 1656.236 88 Cappuccino Good
2025-09-13 3003.934 86 Latte Poor
2025-09-14 3980.280 78 Latte Excellent
2025-09-15 1805.588 95 Mocha Excellent
2025-09-16 3406.042 66 Latte Poor
2025-09-17 3751.245 27 Americano Good
2025-09-18 3262.385 72 Americano Poor
2025-09-19 2131.619 94 Americano Fair
2025-09-20 3426.469 92 Espresso Excellent
2025-09-21 3402.881 99 Mocha Good
2025-09-22 1712.093 59 Mocha Fair
2025-09-23 3672.968 60 Americano Good
2025-09-24 3100.494 29 Americano Fair
2025-09-25 2625.981 41 Mocha Excellent
2025-09-26 1730.989 76 Cappuccino Fair
2025-09-27 3134.336 51 Cappuccino Fair
2025-09-28 3026.545 40 Latte Very Good
2025-09-29 3222.764 23 Espresso Very Good
2025-09-30 3555.928 30 Latte Excellent
# Summary data (opsional)
summary_data = summary(my_data)
kable(summary_data)
Date Coffee_ml Cups_Sold Drink_Type Customer_Satisfaction
Min. :2025-09-01 Min. :1509 Min. : 23.00 Length:30 Poor :6
1st Qu.:2025-09-08 1st Qu.:1932 1st Qu.: 52.75 Class :character Fair :9
Median :2025-09-15 Median :2949 Median : 73.00 Mode :character Good :7
Mean :2025-09-15 Mean :2723 Mean : 68.57 NA Very Good:2
3rd Qu.:2025-09-22 3rd Qu.:3258 3rd Qu.: 87.50 NA Excellent:6
Max. :2025-09-30 Max. :3980 Max. :100.00 NA NA
# Frekuensi Kategori (nominal, ordinal)
library(knitr)
drink_freq = table(my_data$Drink_Type)
satisfaction_freq = table(my_data$Customer_Satisfaction)

kable(drink_freq, caption = "Frekuensi Jenis Minuman (Nominal)")
Frekuensi Jenis Minuman (Nominal)
Var1 Freq
Americano 5
Cappuccino 5
Espresso 6
Latte 9
Mocha 5
kable(satisfaction_freq, caption = "Frekuensi Kepuasan Pelanggan (Ordinal)")
Frekuensi Kepuasan Pelanggan (Ordinal)
Var1 Freq
Poor 6
Fair 9
Good 7
Very Good 2
Excellent 6
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAzIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6DQotICJLaGFmaXphdHVuIE5pc2EiICANCi0gIkFuZ2VsaXF1ZSBLaXlvc2hpIEJVIg0KLSAiTmF5Y2hpbGxhIEFkZWxpYSBaYWhyYSINCi0gIk5ha2Vpc2hhIEF1bGlhIFphaHJhIg0KLSAiVmVyb25pY2EgTWFyaWEgTHVjaWEgRmVycmVpcmEgWGF2aWVyIiMgUmVwbGFjZSB3aXRoIHlvdXIgZnVsbCBuYW1lDQpkYXRlOiAgImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIiAjIEF1dG8gZGlzcGxheXMgdGhlIGN1cnJlbnQgZGF0ZQ0Kb3V0cHV0OiAgICAgICAgICAgICAgICAgICAgICAgICAjIE91dHB1dCBzZWN0aW9uIGRlZmluZXMgdGhlIGZvcm1hdCBhbmQgbGF5b3V0IA0KICBybWRmb3JtYXRzOjpyZWFkdGhlZG93bjogICAgICAjIGh0dHBzOi8vZ2l0aHViLmNvbS9qdWJhL3JtZGZvcm1hdHMNCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZSAgICAgICAgIyBFbWJlZHMgYWxsIHJlc291cmNlcyAoQ1NTLCBKUywgaW1hZ2VzKSANCiAgICB0aHVtYm5haWxzOiB0cnVlICAgICAgICAgICAgIyBEaXNwbGF5cyBpbWFnZSB0aHVtYm5haWxzIGluIHRoZSBkb2MNCiAgICBsaWdodGJveDogdHJ1ZSAgICAgICAgICAgICAgIyBFbmFibGVzIGNsaWNrIHRvIGVubGFyZ2UgaW1hZ2VzDQogICAgZ2FsbGVyeTogdHJ1ZSAgICAgICAgICAgICAgICMgR3JvdXBzIGltYWdlcyBpbnRvIGFuIGludGVyYWN0aXZlIGdhbGxlcnkNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUgICAgICAgIyBBdXRvbWF0aWNhbGx5IG51bWJlcnMgYWxsIHNlY3Rpb25zDQogICAgbGliX2RpcjogbGlicyAgICAgICAgICAgICAgICMgRGlyZWN0b3J5IHdoZXJlIEphdmFTY3JpcHQvQ1NTIGxpYnJhcmllcw0KICAgIGRmX3ByaW50OiAicGFnZWQiICAgICAgICAgICAjIERpc3BsYXlzIGRhdGEgZnJhbWVzIGFzIGludGVyYWN0aXZlIHBhZ2VkIA0KICAgIGNvZGVfZm9sZGluZzogInNob3ciICAgICAgICAjIEFsbG93cyBmb2xkaW5nL3VuZm9sZGluZyBSIGNvZGUgYmxvY2tzIA0KICAgIGNvZGVfZG93bmxvYWQ6IHllcyAgICAgICAgICAjIEFkZHMgYSBidXR0b24gdG8gZG93bmxvYWQgYWxsIFIgY29kZQ0KLS0tDQo8aW1nIGlkPSJGb3RvIiBzcmM9ImZvdG8ga2Vsb21wb2suanBlZz9yYXc9dHJ1ZSIgYWx0PSJMb2dvIiBzdHlsZT0id2lkdGg6MjAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ij4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIEV4ZXJjaXNlIDENCg0KVGhlIGZvbGxvd2luZyB0YWJsZSBzaG93cyBzYW1wbGUgaW5mb3JtYXRpb24gZm9yIHRocmVlIHN0dWRlbnRzLiBFYWNoIG9ic2VydmF0aW9uIHJlcHJlc2VudHMgYSBzaW5nbGUgc3R1ZGVudCBhbmQgaW5jbHVkZXMgZGV0YWlscyBzdWNoIGFzIHRoZWlyIHVuaXF1ZSBzdHVkZW50IElELCBuYW1lLCBhZ2UsIHRvdGFsIGNyZWRpdHMgY29tcGxldGVkLCBtYWpvciBmaWVsZCBvZiBzdHVkeSwgYW5kIHllYXIgbGV2ZWwuDQoNClRoaXMgZGF0YXNldCBkZW1vbnN0cmF0ZXMgYSBtaXh0dXJlIG9mIHZhcmlhYmxlIHR5cGVzOg0KDQotICAgKipOb21pbmFsOioqIFN0dWRlbnRJRCwgTmFtZSwgTWFqb3JcDQotICAgKipOdW1lcmljOioqIEFnZSAoY29udGludW91cyksIENyZWRpdHNDb21wbGV0ZWQgKGRpc2NyZXRlKVwNCi0gICAqKk9yZGluYWw6KiogWWVhckxldmVsIChGcmVzaG1hbiDihpIgU2VuaW9yKQ0KDQp8IFN0dWRlbnRJRCB8IE5hbWUgIHwgQWdlIHwgQ3JlZGl0c0NvbXBsZXRlZCB8IE1ham9yICAgICAgIHwgWWVhckxldmVsIHwNCnwtLS0tLS0tLS0tLXwtLS0tLS0tfC0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfA0KfCBTMDAxICAgICAgfCBBbGljZSB8IDIwICB8IDQ1ICAgICAgICAgICAgICAgfCBEYXRhIFNhaW5zICB8IFNvcGhvbW9yZSB8DQp8IFMwMDIgICAgICB8IEJ1ZGkgIHwgMjEgIHwgNjAgICAgICAgICAgICAgICB8IE1hdGhlbWF0aWNzIHwgSnVuaW9yICAgIHwNCnwgUzAwMyAgICAgIHwgQ2l0cmEgfCAxOSAgfCAzMCAgICAgICAgICAgICAgIHwgU3RhdGlzdGljcyAgfCBGcmVzaG1hbiAgfA0KDQpgYGB7cn0NCiMgMS4gQ3JlYXRlIHZlY3RvcnMgZm9yIGVhY2ggdmFyaWFibGUNClN0dWRlbnRJRCA8LSBjKCJTMDAxIiwgIlMwMDIiLCAiUzAwMyIpICAgICAgICMgTm9taW5hbCAvIElEDQpOYW1lIDwtIGMoIkFsaWNlIiwgIkJ1ZGkiLCAiQ2l0cmEiKSAgICAgICAgICAjIE5vbWluYWwgLyBOYW1lDQpBZ2UgPC0gYygyMCwgMjEsIDE5KSAgICAgICAgICAgICAgICAgICAgICAgICAjIE51bWVyaWMgLyBDb250aW51b3VzDQpDcmVkaXRzQ29tcGxldGVkIDwtIGMoNDUsIDYwLCAzMCkgICAgICAgICAgICAjIE51bWVyaWMgLyBEaXNjcmV0ZQ0KDQojIE5vbWluYWwNCk1ham9yIDwtIGMoIkRhdGEgU2FpbnMiLCAiTWF0aGVtYXRpY3MiLCAiU3RhdGlzdGljcyIpICANCg0KIyBPcmRpbmFsDQpZZWFyTGV2ZWwgPC0gZmFjdG9yKGMoIlNvcGhvbW9yZSIsICJKdW5pb3IiLCAiRnJlc2htYW4iKSwNCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiRnJlc2htYW4iLCJTb3Bob21vcmUiLCJKdW5pb3IiLCJTZW5pb3IiKSwNCiAgICAgICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUpICAgICAgICAgIA0KDQojIDIuIENvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUNCnN0dWRlbnRzIDwtIGRhdGEuZnJhbWUoDQogIFN0dWRlbnRJRCwgTmFtZSwgQWdlLCBDcmVkaXRzQ29tcGxldGVkLCBNYWpvciwgWWVhckxldmVsLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyAzLiBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lDQpwcmludChzdHVkZW50cykNCmBgYA0KDQojIyBFeGVyY2lzZSAyDQoNCioqSWRlbnRpZnkgRGF0YSBUeXBlczoqKiBEZXRlcm1pbmUgdGhlIHR5cGUgb2YgZGF0YSBmb3IgZWFjaCBvZiB0aGUgZm9sbG93aW5nIHZhcmlhYmxlczoNCg0KYGBge3J9DQojIEluc3RhbGwga25pdHIgcGFja2FnZSBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQNCiMgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KbGlicmFyeShrbml0cikNCg0KIyBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBEYXRhIFR5cGVzDQp2YXJpYWJsZXNfaW5mbyA8LSBkYXRhLmZyYW1lKA0KICBObyA9IDE6NSwNCiAgVmFyaWFibGUgPSBjKA0KICAgICJOdW1iZXIgb2YgdmVoaWNsZXMgcGFzc2luZyB0aHJvdWdoIHRoZSB0b2xsIHJvYWQgZWFjaCBkYXkiLA0KICAgICJTdHVkZW50IGhlaWdodCBpbiBjbSIsDQogICAgIkVtcGxveWVlIGdlbmRlciAoTWFsZSAvIEZlbWFsZSkiLA0KICAgICJDdXN0b21lciBzYXRpc2ZhY3Rpb24gbGV2ZWw6IExvdywgTWVkaXVtLCBIaWdoIiwNCiAgICAiUmVzcG9uZGVudCdzIGZhdm9yaXRlIGNvbG9yOiBSZWQsIEJsdWUsIEdyZWVuIg0KICApLA0KICBEYXRhVHlwZSA9IGMoDQogICAgIk51bWVyaWMiLA0KICAgICJOdW1lcmljIiwNCiAgICAiQ2F0ZWdvcmljYWwiLA0KICAgICJDYXRlZ29yaWNhbCIsDQogICAgIkNhdGVnb3JpY2FsIg0KICApLA0KICBTdWJ0eXBlID0gYygNCiAgICAiRGlzY3JldGUiLA0KICAgICJDb250aW5vdXMiLA0KICAgICJOb21pbmFsIiwNCiAgICAiT3JkaW5hbCIsDQogICAgIk5vbWluYWwiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQprYWJsZSh2YXJpYWJsZXNfaW5mbywgDQogICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIFZhcmlhYmxlcyBhbmQgRGF0YSBUeXBlcyIpDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIEV4ZXJjaXNlIDMNCg0KKipDbGFzc2lmeSBEYXRhIFNvdXJjZXM6KiogRGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGZvbGxvd2luZyBkYXRhIGNvbWVzIGZyb20gKippbnRlcm5hbCoqIG9yICoqZXh0ZXJuYWwgc291cmNlcyoqLCBhbmQgd2hldGhlciBpdCBpcyAqKnN0cnVjdHVyZWQqKiBvciAqKnVuc3RydWN0dXJlZCoqOg0KDQpgYGB7cn0NCiMgSW5zdGFsbCBEVCBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJEVCIpDQpsaWJyYXJ5KERUKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIGRhdGEgc291cmNlcyANCmRhdGFfc291cmNlcyA8LSBkYXRhLmZyYW1lKA0KICBObyA9IDE6NCwNCiAgRGF0YVNvdXJjZSA9IGMoDQogICAgIkRhaWx5IHNhbGVzIHRyYW5zYWN0aW9uIGRhdGEgb2YgdGhlIGNvbXBhbnkiLA0KICAgICJXZWF0aGVyIHJlcG9ydHMgZnJvbSBCTUtHIiwNCiAgICAiUHJvZHVjdCByZXZpZXdzIG9uIHNvY2lhbCBtZWRpYSIsDQogICAgIldhcmVob3VzZSBpbnZlbnRvcnkgcmVwb3J0cyINCiAgKSwNCiAgSW50ZXJuYWxfRXh0ZXJuYWwgPSBjKA0KICAgICJJbnRlcm5hbCIsDQogICAgIkV4dGVybmFsIiwNCiAgICAiRXh0ZXJuYWwiLA0KICAgICJJbnRlcm5hbCINCiAgKSwNCiAgU3RydWN0dXJlZF9VbnN0cnVjdHVyZWQgPSBjKA0KICAgICJTdHJ1Y3R1cmVkIiwNCiAgICAiU3RydWN0dXJlZCIsDQogICAgIlVuc3RydWN0dXJlZCIsDQogICAgIlN0cnVjdHVyZWQiDQogICksDQogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUgYXMgYSBuZWF0IHRhYmxlDQpkYXRhdGFibGUoZGF0YV9zb3VyY2VzLCANCiAgICAgICAgICBjYXB0aW9uID0gIlRhYmxlIG9mIERhdGEgU291cmNlcyIsDQogICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSkgIyBoaWRlcyB0aGUgaW5kZXggY29sdW1uDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMjIEV4ZXJjaXNlIDQNCg0KKipEYXRhc2V0IFN0cnVjdHVyZToqKiBDb25zaWRlciB0aGUgZm9sbG93aW5nIHRyYW5zYWN0aW9uIHRhYmxlOg0KDQp8IERhdGUgICAgICAgfCBRdHkgfCBQcmljZSB8IFByb2R1Y3QgIHwgQ3VzdG9tZXJUaWVyIHwNCnwtLS0tLS0tLS0tLS18LS0tLS18LS0tLS0tLXwtLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tfA0KfCAyMDI1LTEwLTAxIHwgMiAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDEgfCA1ICAgfCAyMCAgICB8IE1vdXNlICAgIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMiB8IDEgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTAyIHwgMyAgIHwgMzAgICAgfCBLZXlib2FyZCB8IE1lZGl1bSAgICAgICB8DQp8IDIwMjUtMTAtMDMgfCA0ICAgfCA1MCAgICB8IE1vdXNlICAgIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMyB8IDIgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTA0IHwgNiAgIHwgMjUgICAgfCBLZXlib2FyZCB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDQgfCAxICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wNSB8IDMgICB8IDQwICAgIHwgTW91c2UgICAgfCBMb3cgICAgICAgICAgfA0KfCAyMDI1LTEwLTA1IHwgNSAgIHwgMTAgICAgfCBLZXlib2FyZCB8IE1lZGl1bSAgICAgICB8DQoNCioqWW91ciBBc3NpZ25tZW50IEluc3RydWN0aW9uczoqKiBDcmVhdGluZyBhIFRyYW5zYWN0aW9ucyBUYWJsZSBhYm92ZSBpbiBSDQoNCjEuICAqKkNyZWF0ZSBhIGRhdGEgZnJhbWUqKiBpbiBSIGNhbGxlZCBgdHJhbnNhY3Rpb25zYCBjb250YWluaW5nIHRoZSBkYXRhIGFib3ZlLg0KDQoyLiAgSWRlbnRpZnkgd2hpY2ggdmFyaWFibGVzIGFyZSBudW1lcmljIGFuZCB3aGljaCBhcmUgY2F0ZWdvcmljYWwNCg0KMy4gICoqQ2FsY3VsYXRlIHRvdGFsIHJldmVudWUqKiBmb3IgZWFjaCB0cmFuc2FjdGlvbiBieSBtdWx0aXBseWluZyBgUXR5IMOXIFByaWNlYCBhbmQgYWRkIGl0IGFzIGEgbmV3IGNvbHVtbiBgVG90YWxgLg0KDQo0LiAgKipDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljcyoqOg0KDQogICAgLSAgIFRvdGFsIHF1YW50aXR5IHNvbGQgZm9yIGVhY2ggcHJvZHVjdA0KICAgIC0gICBUb3RhbCByZXZlbnVlIHBlciBwcm9kdWN0DQogICAgLSAgIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCg0KNS4gICoqVmlzdWFsaXplIHRoZSBkYXRhKio6DQoNCiAgICAtICAgQ3JlYXRlIGEgKipiYXJwbG90Kiogc2hvd2luZyB0b3RhbCBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0Lg0KICAgIC0gICBDcmVhdGUgYSAqKnBpZSBjaGFydCoqIHNob3dpbmcgdGhlIHByb3BvcnRpb24gb2YgdG90YWwgcmV2ZW51ZSBwZXIgY3VzdG9tZXIgdGllci4NCg0KNi4gICoqT3B0aW9uYWwgQ2hhbGxlbmdlKio6DQoNCiAgICAtICAgRmluZCB3aGljaCAqKmRhdGUqKiBoYWQgdGhlIGhpZ2hlc3QgdG90YWwgcmV2ZW51ZS4NCiAgICAtICAgQ3JlYXRlIGEgKipzdGFja2VkIGJhciBjaGFydCoqIHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyLg0KDQoqKkhpbnRzOioqIFVzZSBgZGF0YS5mcmFtZSgpYCwgYGFnZ3JlZ2F0ZSgpYCwgYGJhcnBsb3QoKWAsIGBwaWUoKWAsIGFuZCBiYXNpYyBhcml0aG1ldGljIG9wZXJhdGlvbnMgaW4gUi4NCg0KDQo1LiAgKipWaXN1YWxpemUgdGhlIGRhdGEqKjoNCg0KICAgIC0gICBDcmVhdGUgYSAqKmJhcnBsb3QqKiBzaG93aW5nIHRvdGFsIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QuDQogICAgLSAgIENyZWF0ZSBhICoqcGllIGNoYXJ0Kiogc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCByZXZlbnVlIHBlciBjdXN0b21lciB0aWVyLg0KDQo2LiAgKipPcHRpb25hbCBDaGFsbGVuZ2UqKjoNCg0KICAgIC0gICBGaW5kIHdoaWNoICoqZGF0ZSoqIGhhZCB0aGUgaGlnaGVzdCB0b3RhbCByZXZlbnVlLg0KICAgIC0gICBDcmVhdGUgYSAqKnN0YWNrZWQgYmFyIGNoYXJ0Kiogc2hvd2luZyBxdWFudGl0eSBzb2xkIHBlciBwcm9kdWN0IGJ5IGN1c3RvbWVyIHRpZXIuDQoNCioqSGludHM6KiogVXNlIGBkYXRhLmZyYW1lKClgLCBgYWdncmVnYXRlKClgLCBgYmFycGxvdCgpYCwgYHBpZSgpYCwgYW5kIGJhc2ljIGFyaXRobWV0aWMgb3BlcmF0aW9ucyBpbiBSLg0KDQpgYGB7cn0NCiMgSW5zdGFsbCBrbml0ciBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZA0KIyBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQpsaWJyYXJ5KGtuaXRyKQ0KDQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgZm9yIFRyYW5zYWN0aW9ucw0KRGF0ZSA9IGMgKA0KICAiMjAyNS0xMC0wMSIsICANCiAgIjIwMjUtMTAtMDEiLCANCiAgIjIwMjUtMTAtMDIiLCANCiAgIjIwMjUtMTAtMDIiLCANCiAgIjIwMjUtMTAtMDMiLCANCiAgIjIwMjUtMTAtMDMiLCANCiAgIjIwMjUtMTAtMDQiLCANCiAgIjIwMjUtMTAtMDQiLCANCiAgIjIwMjUtMTAtMDUiLCANCiAgIjIwMjUtMTAtMDUiDQogICkgICAgICAgICAgICAgICMgTnVtZXJpYyAvIERpc2NyZXRlDQpRdHkgPSBjICgyLCA1LCAxLCAzLCA0LCAyLCA2LCAxLCAzLCA1KSAgICMgTnVtZXJpYyAvIERpc2NyZXRlDQpQcmljZSA9IGMgKDEwMDAsIDIwLCAxMDAwLCAzMCwgNTAsIDEwMDAsIDI1LCAxMDAwLCA0MCwgMTApICAgIyBOdW1lcmljIC8gRGlzY3JldGUNCg0KIyBOb21pbmFsDQpQcm9kdWN0ID0gYyAoDQogICJMYXB0b3AiLA0KICAiTW91c2UiLA0KICAiTGFwdG9wIiwNCiAgIktleWJvYXJkIiwNCiAgIk1vdXNlIiwNCiAgIkxhcHRvcCIsDQogICJLZXlib2FyZCIsDQogICJMYXB0b3AiLA0KICAiTW91c2UiLA0KICAiS2V5Ym9hcmQiDQogICkgICAgICAgICAgICMgQ2F0ZWdvcmljYWwgLyBOb21pbmFsDQoNCiMgT3JkaW5hbA0KQ3VzdG9tZXJUaWVyID0gZmFjdG9yKGMoDQogICJIaWdoIiwNCiAgIk1lZGl1bSIsDQogICJMb3ciLA0KICAiTWVkaXVtIiwNCiAgIk1lZGl1bSIsDQogICJIaWdoIiwNCiAgIkxvdyIsDQogICJIaWdoIiwNCiAgIkxvdyIsDQogICJNZWRpdW0iDQogICksDQpsZXZlbHMgPSBjKCJMb3ciLCJNZWRpdW0iLCJIaWdoIiksDQpvcmRlcmVkID0gVFJVRSkgDQoNCiMgMi4gQ29tYmluZSBhbGwgdmVjdG9ycyBpbnRvIGEgZGF0YSBmcmFtZQ0KdHJhbnNhY3Rpb25zID0gIGRhdGEuZnJhbWUgKERhdGUsIFF0eSwgUHJpY2UsIFByb2R1Y3QsIEN1c3RvbWVyVGllciwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQ0KDQojIDMuIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCmxpYnJhcnkoa25pdHIpDQprYWJsZSh0cmFuc2FjdGlvbnMpDQpgYGANCg0KYGBge3J9DQojIDIuIElkZW50aWZ5IHZhcmlhYmxlIHR5cGVzDQpsaWJyYXJ5KGtuaXRyKQ0KdmFyaWFibGVfdHlwZXMgPC0gZGF0YS5mcmFtZSgNCiAgVmFyaWFibGUgPSBjKA0KICAgICJEYXRlIiwNCiAgICAiUXR5IiwNCiAgICAiUHJpY2UiLA0KICAgICJQcm9kdWN0IiwNCiAgICAiQ3VzdG9tZXJUaWVyIg0KICAgICksDQogIFR5cGUgPSBjKA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJOdW1lcmljIChEaXNjcmV0ZSkiLA0KICAgICJDYXRlZ29yaWNhbCAoTm9taW5hbCkiLA0KICAgICJDYXRlZ29yaWNhbCAoT3JkaW5hbCkiDQogICAgKQ0KKQ0KDQojIERpc3BsYXkgdGhlIGRhdGEgZnJhbWUNCmthYmxlKHZhcmlhYmxlX3R5cGVzLCBjYXB0aW9uID0gIlZhcmlhYmxlIFR5cGVzIGluIFRyYW5zYWN0aW9ucyBEYXRhIikNCg0KYGBgDQoNCg0KYGBge3J9DQojIDMuIENhbGN1bGF0ZSB0b3RhbCByZXZlbnVlDQp0cmFuc2FjdGlvbnMkdG90YWwgPSB0cmFuc2FjdGlvbnMkUXR5ICogdHJhbnNhY3Rpb25zJFByaWNlDQprYWJsZSh0cmFuc2FjdGlvbnMpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyA0LiBDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljDQoNCiMgYS4gVG90YWwgcXVhbnRpdHkgc29sZCBmb3IgZWFjaCBwcm9kdWN0DQp0b3RhbF9RdHkgPSBhZ2dyZWdhdGUoUXR5IH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgc3VtKQ0Ka2FibGUodG90YWxfUXR5LCBjYXB0aW9uID0gIlRvdGFsIFF1YW50aXR5IFNvbGQgcGVyIFByb2R1Y3QiKQ0KDQojIGIuIHRvdGFsIHJldmVudWUgcGVyIHByb2R1Y3QNCnRvdGFsX3JldmVudWUgPSBhZ2dyZWdhdGUodG90YWwgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQprYWJsZSh0b3RhbF9yZXZlbnVlLCBjYXB0aW9uID0gIlRvdGFsIFJldmVudWUgcGVyIFByb2R1Y3QiKQ0KDQojIGMuIEF2ZXJhZ2UgcHJpY2UgcGVyIHByb2R1Y3QNCmF2Z19wcmljZSA9IGFnZ3JlZ2F0ZShQcmljZSB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIG1lYW4pDQprYWJsZShhdmdfcHJpY2UsIGNhcHRpb24gPSAiQXZlcmFnZSBQcmljZSBwZXIgUHJvZHVjdCIpDQoNCmBgYA0KDQpgYGB7cn0NCiMgNS4gVmlzdWFsaXplIHRoZSBkYXRhDQoNCiMgYS4gYmFycGxvdCBzaG93aW5nIHRvdGFsIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QNCnRvdGFsX3F0eSA9IHRhcHBseSh0cmFuc2FjdGlvbnMkUXR5LCB0cmFuc2FjdGlvbnMkUHJvZHVjdCwgc3VtKQ0KYmFycGxvdCh0b3RhbF9xdHksDQogICAgICAgIG1haW4gPSAiVG90YWwgUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCIsDQogICAgICAgIHhsYWIgPSAiUHJvZHVjdCIsDQogICAgICAgIHlsYWIgPSAiVG90YWwgUXVhbnRpdHkiLA0KICAgICAgICBjb2wgPSAibGlnaHRibHVlIikNCg0KIyBiLiBwaWUgY2hhcnQgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiB0b3RhbCByZXZlbnVlDQp0b3RhbF9yZXZlbnVlX3RpZXIgPSB0YXBwbHkodHJhbnNhY3Rpb25zJHRvdGFsLCB0cmFuc2FjdGlvbnMkQ3VzdG9tZXJUaWVyLCBzdW0pDQpwaWUodG90YWxfcmV2ZW51ZV90aWVyLA0KICAgIG1haW4gPSAiUHJvcG9ydGlvbiBvZiBUb3RhbCBSZXZlbnVlIHBlciBDdXN0b21lciBUaWVyIiwNCiAgICBjb2wgPSByYWluYm93KGxlbmd0aCh0b3RhbF9yZXZlbnVlX3RpZXIpKSkNCg0KYGBgDQoNCmBgYHtyfQ0KIyA2LiBPcHRpb25hbCBjaGFsbGVuZ2UNCg0KIyBhLiBGaW5kIHdoaWNoIGRhdGUgaGFkIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUNCnRvdGFsX3JldmVudWVfZGF0ZSA8LSBhZ2dyZWdhdGUodG90YWwgfiBEYXRlLCBkYXRhID0gdHJhbnNhY3Rpb25zLCBzdW0pDQp0b3RhbF9yZXZlbnVlX2RhdGVbd2hpY2gubWF4KHRvdGFsX3JldmVudWVfZGF0ZSR0b3RhbCksIF0NCg0KDQojIGIuIHN0YWNrZWQgYmFyIGNoYXJ0IHNob3dpbmcgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdCBieSBjdXN0b21lciB0aWVyDQpxdHlfdGFibGUgPSB4dGFicyhRdHkgfiBQcm9kdWN0ICsgQ3VzdG9tZXJUaWVyLCBkYXRhID0gdHJhbnNhY3Rpb25zKQ0KYmFycGxvdChxdHlfdGFibGUsDQogICAgICAgIG1haW4gPSAiUXVhbnRpdHkgU29sZCBwZXIgUHJvZHVjdCBieSBDdXN0b21lciBUaWVyIiwNCiAgICAgICAgeGxhYiA9ICJQcm9kdWN0IiwNCiAgICAgICAgeWxhYiA9ICJRdWFudGl0eSIsDQogICAgICAgIGNvbCA9IGMoImxpZ2h0Ymx1ZSIsICJsaWdodGdyZWVuIiwgInBpbmsiKSkNCiAgICAgIA0KYGBgDQoNCiMjIEV4ZXJjaXNlIDUNCg0KKipDcmVhdGUgWW91ciBPd24gRGF0YSBGcmFtZToqKg0KDQoqKk9iamVjdGl2ZToqKiBDcmVhdGUgYSBkYXRhIGZyYW1lIGluIFIgd2l0aCAqKjMwIHJvd3MqKiBjb250YWluaW5nIGEgbWl4IG9mIGRhdGEgdHlwZXM6IGNvbnRpbnVvdXMsIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbC4NCg0KIyMjIEluc3RydWN0aW9ucw0KDQoxLiAgKipPcGVuIFJTdHVkaW8qKiBvciB0aGUgUiBjb25zb2xlLg0KDQoyLiAgKipDcmVhdGUgYSB2ZWN0b3IgZm9yIGVhY2ggY29sdW1uKiogaW4geW91ciBkYXRhIGZyYW1lOg0KDQogICAgLSAgICoqRGF0ZSoqOiAzMCBkYXRlcyAoY2FuIGJlIHNlcXVlbnRpYWwgb3IgcmFuZG9tIHdpdGhpbiBhIG1vbnRoL3llYXIpXA0KICAgIC0gICAqKkNvbnRpbnVvdXMqKjogbnVtZXJpYyB2YWx1ZXMgdGhhdCBjYW4gdGFrZSBkZWNpbWFsIHZhbHVlcyAoZS5nLiwgaGVpZ2h0LCB3ZWlnaHQsIHRlbXBlcmF0dXJlKVwNCiAgICAtICAgKipEaXNjcmV0ZSoqOiBudW1lcmljIHZhbHVlcyB0aGF0IGNhbiBvbmx5IHRha2Ugd2hvbGUgbnVtYmVycyAoZS5nLiwgbnVtYmVyIG9mIGl0ZW1zLCBudW1iZXIgb2YgdmVoaWNsZXMpXA0KICAgIC0gICAqKk5vbWluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggKipubyBvcmRlcioqIChlLmcuLCBjb2xvciwgZ2VuZGVyLCBjaXR5KVwNCiAgICAtICAgKipPcmRpbmFsKio6IGNhdGVnb3JpY2FsIHZhbHVlcyB3aXRoIGEgKipkZWZpbmVkIG9yZGVyKiogKGUuZy4sIExvdywgTWVkaXVtLCBIaWdoOyBCZWdpbm5lciwgSW50ZXJtZWRpYXRlLCBFeHBlcnQpDQoNCjMuICAqKkNvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUqKiBjYWxsZWQgYG15X2RhdGFgLg0KDQo0LiAgKipDaGVjayB5b3VyIGRhdGEgZnJhbWUqKiB1c2luZyBgaGVhZCgpYCBvciBgVmlldygpYCB0byBlbnN1cmUgaXQgaGFzICoqMzAgcm93cyoqIGFuZCB0aGUgY29sdW1ucyBhcmUgY29ycmVjdC4NCg0KNS4gICoqT3B0aW9uYWwgdGFza3MqKjoNCg0KICAgIC0gICBTdW1tYXJpemUgZWFjaCBjb2x1bW4gdXNpbmcgYHN1bW1hcnkoKWBcDQogICAgLSAgIENvdW50IHRoZSBmcmVxdWVuY3kgb2YgZWFjaCBjYXRlZ29yeSBmb3IgKipOb21pbmFsKiogYW5kICoqT3JkaW5hbCoqIGNvbHVtbnMgdXNpbmcgYHRhYmxlKClgDQoNCiMjIyBIaW50cw0KDQotIFVzZSBgc2VxLkRhdGUoKWAgb3IgYGFzLkRhdGUoKWAgdG8gZ2VuZXJhdGUgdGhlIERhdGUgY29sdW1uLiAgDQotIFVzZSBgcnVuaWYoKWAgb3IgYHJub3JtKClgIGZvciBjb250aW51b3VzIG51bWVyaWMgZGF0YS4gIA0KLSBVc2UgYHNhbXBsZSgpYCBmb3IgZGlzY3JldGUsIG5vbWluYWwsIGFuZCBvcmRpbmFsIGRhdGEuICANCi0gRW5zdXJlIHRoZSAqKm9yZGluYWwgdmVjdG9yKiogaXMgY3JlYXRlZCB3aXRoIGBmYWN0b3IoLi4uLCBsZXZlbHMgPSBjKCJMb3ciLCJNZWRpdW0iLCJIaWdoIiksIG9yZGVyZWQgPSBUUlVFKWAgKG9yIHNpbWlsYXIpLg0KDQoNCmBgYHtyfQ0KIyAxLiBDb2ZmZWUgU2hvcCBEYXRhDQoNCiMgRGF0ZSAoMzAgaGFyaSBkaSBidWxhbiBTZXB0ZW1iZXIpDQpEYXRlID0gc2VxKGFzLkRhdGUoIjIwMjUtMDktMDEiKSwgYXMuRGF0ZSgiMjAyNS0wOS0zMCIpLCBieSA9ICJkYXkiKQ0KDQojIENvbnRpbnVvdXM6IGp1bWxhaCBtbCBrb3BpIHRlcmp1YWwgcGVyIGhhcmkgKGFjYWsgZGFyaSAxNTAw4oCTNDAwMCBtbCkNCkNvZmZlZV9tbCA9IHJ1bmlmKDMwLCBtaW4gPSAxNTAwLCBtYXggPSA0MDAwKQ0KDQojIERpc2NyZXRlOiBqdW1sYWggY2FuZ2tpciBrb3BpIHRlcmp1YWwgcGVyIGhhcmkgKGFjYWsgMjDigJMxMDApDQpDdXBzX1NvbGQgPSBzYW1wbGUoMjA6MTAwLCAzMCwgcmVwbGFjZSA9IFRSVUUpDQoNCiMgTm9taW5hbDogamVuaXMgbWludW1hbiBrb3BpDQpEcmlua19UeXBlID0gc2FtcGxlKGMoIkFtZXJpY2FubyIsICJDYXBwdWNjaW5vIiwgIkxhdHRlIiwgIkVzcHJlc3NvIiwgIk1vY2hhIiksIDMwLCByZXBsYWNlID0gVFJVRSkNCg0KIyBPcmRpbmFsOiB0aW5na2F0IGtlcHVhc2FuIHBlbGFuZ2dhbg0KQ3VzdG9tZXJfU2F0aXNmYWN0aW9uID0gZmFjdG9yKA0KICBzYW1wbGUoYygiUG9vciIsICJGYWlyIiwgIkdvb2QiLCAiVmVyeSBHb29kIiwgIkV4Y2VsbGVudCIpLCAzMCwgcmVwbGFjZSA9IFRSVUUpLA0KICBsZXZlbHMgPSBjKCJQb29yIiwgIkZhaXIiLCAiR29vZCIsICJWZXJ5IEdvb2QiLCAiRXhjZWxsZW50IiksDQogIG9yZGVyZWQgPSBUUlVFKQ0KDQojIENvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUNCm15X2RhdGEgPSBkYXRhLmZyYW1lKERhdGUsIENvZmZlZV9tbCwgQ3Vwc19Tb2xkLCBEcmlua19UeXBlLCBDdXN0b21lcl9TYXRpc2ZhY3Rpb24pDQprYWJsZShteV9kYXRhKQ0KDQojIFN1bW1hcnkgZGF0YSAob3BzaW9uYWwpDQpzdW1tYXJ5X2RhdGEgPSBzdW1tYXJ5KG15X2RhdGEpDQprYWJsZShzdW1tYXJ5X2RhdGEpDQoNCiMgRnJla3VlbnNpIEthdGVnb3JpIChub21pbmFsLCBvcmRpbmFsKQ0KbGlicmFyeShrbml0cikNCmRyaW5rX2ZyZXEgPSB0YWJsZShteV9kYXRhJERyaW5rX1R5cGUpDQpzYXRpc2ZhY3Rpb25fZnJlcSA9IHRhYmxlKG15X2RhdGEkQ3VzdG9tZXJfU2F0aXNmYWN0aW9uKQ0KDQprYWJsZShkcmlua19mcmVxLCBjYXB0aW9uID0gIkZyZWt1ZW5zaSBKZW5pcyBNaW51bWFuIChOb21pbmFsKSIpDQprYWJsZShzYXRpc2ZhY3Rpb25fZnJlcSwgY2FwdGlvbiA9ICJGcmVrdWVuc2kgS2VwdWFzYW4gUGVsYW5nZ2FuIChPcmRpbmFsKSIpDQoNCmBgYA0K