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(
    "Continuous",
    "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 Continuous
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

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.

library(DT)
# 4.1 Transaction
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"),
  
  CostumerTier = c("High", "Medium", "Low", "Medium", "Medium",
                    "High", "Low", "High", "Low", "Medium")
  )
library(knitr)
# 4.2 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"
  ),
  stringAsFactors = FALSE
)

library(knitr)
# 4.3 Display the data table as a neat table
kable(variables_info,
      caption = "Table of Variables and Data Types")
Table of Variables and Data Types
No Variable DataType stringAsFactors
1 Qty Numeric FALSE
2 Price Numeric FALSE
3 Product Categorical FALSE
4 Customertier Categorical FALSE
#4.3 Transactions Total
transactions$Total <- transactions$Qty * transactions$Price
datatable(transactions, 
          caption = "Table of Transaction",
          rownames = FALSE)
library(knitr)
# 4.4 Compute Summary Statistics
# Total Qty per Product
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 Revenue per Product
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
# Total Revenue per Customer Tier
total_revenue_per_tier <- aggregate(Total ~ CostumerTier, data = transactions, FUN = sum)
print("Total Pendapatan Per Pelanggan:")
## [1] "Total Pendapatan Per Pelanggan:"
print(total_revenue_per_tier)
##   CostumerTier Total
## 1         High  5000
## 2          Low  1270
## 3       Medium   440
# Average Price per 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
library(knitr)
# 4.5 Visualize Data
barplot(
  height = total_qty_per_product$Qty, 
  names.arg = total_qty_per_product$Product,
  col = c("pink", "blue", "green"),
  main = "Total Transactions",
  xlab = "Product",
  ylab = "Quantity",
  ylim = c(0, max(total_qty_per_product$Qty) + 2))

#Pie chart
revenue_per_tier <- aggregate(Total ~ CostumerTier, 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$CostumerTier, "(", percentages, "%)", sep = "")

pie(
  x = revenue_per_tier$Total,
  labels = pie_labels,
  main = "Proportion of Total Revenue per CustomerTier",
  col = c("purple", "yellow", "red")
)

library(knitr)
# 4.6 Find the Highest date of total revenue
transactions$Revenue <- transactions$Price * transactions$Qty
total_per_date <- aggregate(Revenue ~ Date, data = transactions, FUN = sum)
highest <- total_per_date[which.max(total_per_date$Revenue), ]
print("The highest data of total Revenue")
## [1] "The highest data of total Revenue"
print(total_per_date)
##         Date Revenue
## 1 2025-10-01    2100
## 2 2025-10-02    1090
## 3 2025-10-03    2200
## 4 2025-10-04    1150
## 5 2025-10-05     170
print(highest)
##         Date Revenue
## 3 2025-10-03    2200
# Stacked Bar Chart
table_transactions <- with(transactions, tapply(Qty, list(Product, CostumerTier), sum, na.rm = TRUE))
table_transactions[is.na(table_transactions)] <- 0
barplot(
  t(table_transactions),
  beside = FALSE,
  col = c("brown", "gold", "orange"),
  main = "Quantity Sold per Product by CustomerTier",
  xlab = "Product",
  ylab = "Quantity Sold",
  legend.text = TRUE)

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()
library(DT)
library(knitr)
# 5.1 Create a vector for each column
set.seed(50)
tanggal <- as.Date("2024-01-01") + sample(0:365, 30, replace = TRUE)
hewan <- c("Kucing", "Anjing", "Kelinci", "Burung",
           "Kuda", "Gajah", "Singa", "Harimau", "Zebra", "Panda", "Rusa",
           "Unta", "Kudanil", "Badak", "Beruang", "Monyet", "Gorila", "Kanguru",
           "Koala", "Serigala", "Kucing", "Anjing", "Burung", "Gajah", "Singa", 
           "Harimau", "Zebra", "Panda", "Rusa", "Unta")
hewan <- factor(hewan)

jumlah_porsi_makanan <- c(5, 5, 3, 4, 3, 
                  3, 5, 5, 5, 6, 
                  4, 4, 6, 6, 5, 
                  5, 6, 4, 4, 5, 
                  5, 4, 5, 6, 7, 
                  6, 5, 6, 4, 4)

berat <- c(24.56, 48.76, 15.48, 9.64, 289.67, 785.54, 293.27, 257.38, 158.35, 
           93.32, 82.67, 632.75, 429.71, 836.54, 274.68, 18.56, 467.82, 152.74,
           52.85, 172.92, 38.56, 95.27, 6.32, 364.78, 284.92, 256.85, 193.65,
           123.45, 110.43, 576.98)

kelincahan <- c("Tinggi", "Tinggi", "Sedang", "Tinggi", "Sedang", "Rendah", "Tinggi",
                "Tinggi", "Sedang", "Sedang", "Sedang", "Rendah", "Rendah", "Rendah",
                "Sedang", "Tinggi", "Rendah", "Tinggi", "Sedang", "Tinggi", "Sedang", 
                "Tinggi", "Tinggi", "Sedang", "Tinggi", "Tinggi", "Sedang", "Sedang",
                "Sedang", "Rendah")
kelincahan <- factor(kelincahan,
                     levels = c("Rendah", "Sedang", "Tinggi"),
                     ordered = TRUE)

# 5.2 Combine all vectors into a data frame
Data_Hewan <- data.frame(tanggal, hewan, jumlah_porsi_makanan, berat, kelincahan)

# 5.3 Create a data frame as a neat table
datatable(Data_Hewan, caption = "Rekapitulasi Data Hewan: Jenis, Berat dan Kelincahan", options = list(pageLength = 10))
# 5.3 Create a table of variable types
variables_info2 <- data.frame(
  No = 1:4,
  Variable = c(
    "Hewan",
    "JumlahPorsiMakanan",
    "Berat",
    "Kelincahan"),
  DataType = c(
    "Nominal",
    "Diskrit",
    "Continuous",
    "Ordinal"),
  stringsAsFactors = FALSE
)

knitr::kable(variables_info2, caption = "Table of Variable and Data Type")
Table of Variable and Data Type
No Variable DataType
1 Hewan Nominal
2 JumlahPorsiMakanan Diskrit
3 Berat Continuous
4 Kelincahan Ordinal
# 5.4 Summarize each column
summary(Data_Hewan)
##     tanggal               hewan    jumlah_porsi_makanan     berat       
##  Min.   :2024-01-07   Anjing : 2   Min.   :3.000        Min.   :  6.32  
##  1st Qu.:2024-04-04   Burung : 2   1st Qu.:4.000        1st Qu.: 60.30  
##  Median :2024-09-06   Gajah  : 2   Median :5.000        Median :165.63  
##  Mean   :2024-07-21   Harimau: 2   Mean   :4.833        Mean   :238.28  
##  3rd Qu.:2024-10-28   Kucing : 2   3rd Qu.:5.750        3rd Qu.:292.37  
##  Max.   :2024-12-28   Panda  : 2   Max.   :7.000        Max.   :836.54  
##                       (Other):18                                        
##   kelincahan
##  Rendah: 6  
##  Sedang:12  
##  Tinggi:12  
##             
##             
##             
## 
summary(transactions)
##        No            Date                Qty           Price        
##  Min.   : 1.00   Length:10          Min.   :1.00   Min.   :  10.00  
##  1st Qu.: 3.25   Class :character   1st Qu.:2.00   1st Qu.:  26.25  
##  Median : 5.50   Mode  :character   Median :3.00   Median :  45.00  
##  Mean   : 5.50                      Mean   :3.20   Mean   : 417.50  
##  3rd Qu.: 7.75                      3rd Qu.:4.75   3rd Qu.:1000.00  
##  Max.   :10.00                      Max.   :6.00   Max.   :1000.00  
##    Product          CostumerTier           Total         Revenue    
##  Length:10          Length:10          Min.   :  50   Min.   :  50  
##  Class :character   Class :character   1st Qu.: 105   1st Qu.: 105  
##  Mode  :character   Mode  :character   Median : 175   Median : 175  
##                                        Mean   : 671   Mean   : 671  
##                                        3rd Qu.:1000   3rd Qu.:1000  
##                                        Max.   :2000   Max.   :2000
summary_table <- summary(Data_Hewan)
knitr::kable(as.data.frame(summary_table), caption = "Summary of Data Hewan")
Summary of Data Hewan
Var1 Var2 Freq
tanggal Min. :2024-01-07
tanggal 1st Qu.:2024-04-04
tanggal Median :2024-09-06
tanggal Mean :2024-07-21
tanggal 3rd Qu.:2024-10-28
tanggal Max. :2024-12-28
tanggal NA
hewan Anjing : 2
hewan Burung : 2
hewan Gajah : 2
hewan Harimau: 2
hewan Kucing : 2
hewan Panda : 2
hewan (Other):18
jumlah_porsi_makanan Min. :3.000
jumlah_porsi_makanan 1st Qu.:4.000
jumlah_porsi_makanan Median :5.000
jumlah_porsi_makanan Mean :4.833
jumlah_porsi_makanan 3rd Qu.:5.750
jumlah_porsi_makanan Max. :7.000
jumlah_porsi_makanan NA
berat Min. : 6.32
berat 1st Qu.: 60.30
berat Median :165.63
berat Mean :238.28
berat 3rd Qu.:292.37
berat Max. :836.54
berat NA
kelincahan Rendah: 6
kelincahan Sedang:12
kelincahan Tinggi:12
kelincahan NA
kelincahan NA
kelincahan NA
kelincahan NA
# 5.4 Count the frequency of each category for **Nominal** and **Ordinal** columns
list(
  Nominal = table(Data_Hewan$Hewan),
  Ordinal = table(Data_Hewan$kelincahan)
)
## $Nominal
## < table of extent 0 >
## 
## $Ordinal
## 
## Rendah Sedang Tinggi 
##      6     12     12
LS0tDQp0aXRsZTogIkRhdGEgRXhwbG9yYXRpb24iICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiRXhlcmNpc2VzIH4gV2VlayAzIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayAyDQphdXRob3I6IA0KLSAiQWRhbSAgUmljaGllIFdpamF5YSINCi0gIk1vcnJpcyBBbGV4YW5kZXIgUGFuZ2FyaWJ1YW4iDQotICJBbmRyZSINCi0gIktheWxhIEFwcmlsaWEiDQotICJPa3RhdmlhIE1haWEgUmVnbyINCi0gIkphbnVhcmlhIFRlcmVzaW5oYSIgICAgICAgICAgIyBSZXBsYWNlIHdpdGggeW91ciBmdWxsIG5hbWUNCmRhdGU6ICAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiICMgQXV0byBkaXNwbGF5cyB0aGUgY3VycmVudCBkYXRlDQpvdXRwdXQ6ICAgICAgICAgICAgICAgICAgICAgICAgICMgT3V0cHV0IHNlY3Rpb24gZGVmaW5lcyB0aGUgZm9ybWF0IGFuZCBsYXlvdXQgDQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOiAgICAgICMgaHR0cHM6Ly9naXRodWIuY29tL2p1YmEvcm1kZm9ybWF0cw0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlICAgICAgICAjIEVtYmVkcyBhbGwgcmVzb3VyY2VzIChDU1MsIEpTLCBpbWFnZXMpIA0KICAgIHRodW1ibmFpbHM6IHRydWUgICAgICAgICAgICAjIERpc3BsYXlzIGltYWdlIHRodW1ibmFpbHMgaW4gdGhlIGRvYw0KICAgIGxpZ2h0Ym94OiB0cnVlICAgICAgICAgICAgICAjIEVuYWJsZXMgY2xpY2sgdG8gZW5sYXJnZSBpbWFnZXMNCiAgICBnYWxsZXJ5OiB0cnVlICAgICAgICAgICAgICAgIyBHcm91cHMgaW1hZ2VzIGludG8gYW4gaW50ZXJhY3RpdmUgZ2FsbGVyeQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICAgICAjIEF1dG9tYXRpY2FsbHkgbnVtYmVycyBhbGwgc2VjdGlvbnMNCiAgICBsaWJfZGlyOiBsaWJzICAgICAgICAgICAgICAgIyBEaXJlY3Rvcnkgd2hlcmUgSmF2YVNjcmlwdC9DU1MgbGlicmFyaWVzDQogICAgZGZfcHJpbnQ6ICJwYWdlZCIgICAgICAgICAgICMgRGlzcGxheXMgZGF0YSBmcmFtZXMgYXMgaW50ZXJhY3RpdmUgcGFnZWQgDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyIgICAgICAgICMgQWxsb3dzIGZvbGRpbmcvdW5mb2xkaW5nIFIgY29kZSBibG9ja3MgDQogICAgY29kZV9kb3dubG9hZDogeWVzICAgICAgICAgICMgQWRkcyBhIGJ1dHRvbiB0byBkb3dubG9hZCBhbGwgUiBjb2RlDQotLS0NCg0KDQo8aW1nIGlkPSJGb3RvIiBzcmM9Imh0dHBzOi8vZ2l0aHViLmNvbS9kc2NpZW5jZWxhYnMvaW1hZ2VzL2Jsb2IvbWFzdGVyL0xvZ29fRHNjaWVuY2VsYWJzX3YxLnBuZz9yYXc9dHJ1ZSIgYWx0PSJMb2dvIiBzdHlsZT0id2lkdGg6MjAwcHg7IGRpc3BsYXk6IGJsb2NrOyBtYXJnaW46IGF1dG87Ij4NCg0KLS0tDQoNCiMjIEV4ZXJjaXNlIDENCg0KVGhlIGZvbGxvd2luZyB0YWJsZSBzaG93cyBzYW1wbGUgaW5mb3JtYXRpb24gZm9yIHRocmVlIHN0dWRlbnRzLiBFYWNoIG9ic2VydmF0aW9uIHJlcHJlc2VudHMgYSBzaW5nbGUgc3R1ZGVudCBhbmQgaW5jbHVkZXMgZGV0YWlscyBzdWNoIGFzIHRoZWlyIHVuaXF1ZSBzdHVkZW50IElELCBuYW1lLCBhZ2UsIHRvdGFsIGNyZWRpdHMgY29tcGxldGVkLCBtYWpvciBmaWVsZCBvZiBzdHVkeSwgYW5kIHllYXIgbGV2ZWwuICANCg0KVGhpcyBkYXRhc2V0IGRlbW9uc3RyYXRlcyBhIG1peHR1cmUgb2YgdmFyaWFibGUgdHlwZXM6ICANCg0KLSAqKk5vbWluYWw6KiogU3R1ZGVudElELCBOYW1lLCBNYWpvciAgDQotICoqTnVtZXJpYzoqKiBBZ2UgKGNvbnRpbnVvdXMpLCBDcmVkaXRzQ29tcGxldGVkIChkaXNjcmV0ZSkgIA0KLSAqKk9yZGluYWw6KiogWWVhckxldmVsIChGcmVzaG1hbiDihpIgU2VuaW9yKSAgDQoNCnwgU3R1ZGVudElEIHwgTmFtZSAgIHwgQWdlIHwgQ3JlZGl0c0NvbXBsZXRlZCB8IE1ham9yICAgICAgICAgICAgfCBZZWFyTGV2ZWwgfA0KfC0tLS0tLS0tLS0tfC0tLS0tLS0tfC0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tfA0KfCBTMDAxICAgICAgfCBBbGljZSAgfCAyMCAgfCA0NSAgICAgICAgICAgICAgfCBEYXRhIFNhaW5zICAgICAgfCBTb3Bob21vcmUgfA0KfCBTMDAyICAgICAgfCBCdWRpICAgfCAyMSAgfCA2MCAgICAgICAgICAgICAgfCBNYXRoZW1hdGljcyAgICAgfCBKdW5pb3IgICAgfA0KfCBTMDAzICAgICAgfCBDaXRyYSAgfCAxOSAgfCAzMCAgICAgICAgICAgICAgfCBTdGF0aXN0aWNzICAgICAgfCBGcmVzaG1hbiAgfA0KDQpgYGB7cn0NCiMgMS4gQ3JlYXRlIHZlY3RvcnMgZm9yIGVhY2ggdmFyaWFibGUNClN0dWRlbnRJRCA8LSBjKCJTMDAxIiwgIlMwMDIiLCAiUzAwMyIpICAgICAgICMgTm9taW5hbCAvIElEDQpOYW1lIDwtIGMoIkFsaWNlIiwgIkJ1ZGkiLCAiQ2l0cmEiKSAgICAgICAgICAjIE5vbWluYWwgLyBOYW1lDQpBZ2UgPC0gYygyMCwgMjEsIDE5KSAgICAgICAgICAgICAgICAgICAgICAgICAjIE51bWVyaWMgLyBDb250aW51b3VzDQpDcmVkaXRzQ29tcGxldGVkIDwtIGMoNDUsIDYwLCAzMCkgICAgICAgICAgICAjIE51bWVyaWMgLyBEaXNjcmV0ZQ0KDQojIE5vbWluYWwNCk1ham9yIDwtIGMoIkRhdGEgU2FpbnMiLCAiTWF0aGVtYXRpY3MiLCAiU3RhdGlzdGljcyIpICANCg0KIyBPcmRpbmFsDQpZZWFyTGV2ZWwgPC0gZmFjdG9yKGMoIlNvcGhvbW9yZSIsICJKdW5pb3IiLCAiRnJlc2htYW4iKSwNCiAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiRnJlc2htYW4iLCJTb3Bob21vcmUiLCJKdW5pb3IiLCJTZW5pb3IiKSwNCiAgICAgICAgICAgICAgICAgICAgb3JkZXJlZCA9IFRSVUUpICAgICAgICAgIA0KDQojIDIuIENvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUNCnN0dWRlbnRzIDwtIGRhdGEuZnJhbWUoDQogIFN0dWRlbnRJRCwgTmFtZSwgQWdlLCBDcmVkaXRzQ29tcGxldGVkLCBNYWpvciwgWWVhckxldmVsLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyAzLiBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lDQpwcmludChzdHVkZW50cykNCmBgYA0KIyMgRXhlcmNpc2UgMg0KDQoqKklkZW50aWZ5IERhdGEgVHlwZXM6KiogRGV0ZXJtaW5lIHRoZSB0eXBlIG9mIGRhdGEgZm9yIGVhY2ggb2YgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIGtuaXRyIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCmxpYnJhcnkoa25pdHIpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgRGF0YSBUeXBlcw0KdmFyaWFibGVzX2luZm8gPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxOjUsDQogIFZhcmlhYmxlID0gYygNCiAgICAiTnVtYmVyIG9mIHZlaGljbGVzIHBhc3NpbmcgdGhyb3VnaCB0aGUgdG9sbCByb2FkIGVhY2ggZGF5IiwNCiAgICAiU3R1ZGVudCBoZWlnaHQgaW4gY20iLA0KICAgICJFbXBsb3llZSBnZW5kZXIgKE1hbGUgLyBGZW1hbGUpIiwNCiAgICAiQ3VzdG9tZXIgc2F0aXNmYWN0aW9uIGxldmVsOiBMb3csIE1lZGl1bSwgSGlnaCIsDQogICAgIlJlc3BvbmRlbnQncyBmYXZvcml0ZSBjb2xvcjogUmVkLCBCbHVlLCBHcmVlbiINCiAgKSwNCiAgRGF0YVR5cGUgPSBjKA0KICAgICJOdW1lcmljIiwNCiAgICAiTnVtZXJpYyIsDQogICAgIkNhdGVnb3JpY2FsIiwNCiAgICAiQ2F0ZWdvcmljYWwiLA0KICAgICJDYXRlZ29yaWNhbCINCiAgKSwNCiAgU3VidHlwZSA9IGMoDQogICAgIkNvbnRpbnVvdXMiLA0KICAgICJDb250aW51b3VzIiwNCiAgICAiTm9taW5hbCIsDQogICAgIk9yZGluYWwiLA0KICAgICJOb21pbmFsIg0KICApLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0KIyBEaXNwbGF5IHRoZSBkYXRhIGZyYW1lIGFzIGEgbmVhdCB0YWJsZQ0Ka2FibGUodmFyaWFibGVzX2luZm8sIA0KICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBWYXJpYWJsZXMgYW5kIERhdGEgVHlwZXMiKQ0KYGBgDQotLS0NCg0KIyMgRXhlcmNpc2UgMw0KDQoqKkNsYXNzaWZ5IERhdGEgU291cmNlczoqKiBEZXRlcm1pbmUgd2hldGhlciB0aGUgZm9sbG93aW5nIGRhdGEgY29tZXMgZnJvbSAqKmludGVybmFsKiogb3IgKipleHRlcm5hbCBzb3VyY2VzKiosIGFuZCB3aGV0aGVyIGl0IGlzICoqc3RydWN0dXJlZCoqIG9yICoqdW5zdHJ1Y3R1cmVkKio6DQoNCmBgYHtyfQ0KIyBJbnN0YWxsIERUIHBhY2thZ2UgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkDQojIGluc3RhbGwucGFja2FnZXMoIkRUIikNCmxpYnJhcnkoRFQpDQoNCiMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBmb3IgZGF0YSBzb3VyY2VzIA0KZGF0YV9zb3VyY2VzIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo0LA0KICBEYXRhU291cmNlID0gYygNCiAgICAiRGFpbHkgc2FsZXMgdHJhbnNhY3Rpb24gZGF0YSBvZiB0aGUgY29tcGFueSIsDQogICAgIldlYXRoZXIgcmVwb3J0cyBmcm9tIEJNS0ciLA0KICAgICJQcm9kdWN0IHJldmlld3Mgb24gc29jaWFsIG1lZGlhIiwNCiAgICAiV2FyZWhvdXNlIGludmVudG9yeSByZXBvcnRzIg0KICApLA0KICBJbnRlcm5hbF9FeHRlcm5hbCA9IGMoDQogICAgIkludGVybmFsIiwNCiAgICAiRXh0ZXJuYWwiLA0KICAgICJFeHRlcm5hbCIsDQogICAgIkludGVybmFsIg0KICApLA0KICBTdHJ1Y3R1cmVkX1Vuc3RydWN0dXJlZCA9IGMoDQogICAgIlN0cnVjdHVyZWQiLA0KICAgICJTdHJ1Y3R1cmVkIiwNCiAgICAiVW5zdHJ1Y3R1cmVkIiwNCiAgICAiU3RydWN0dXJlZCINCiAgKSwNCiAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFDQopDQoNCiMgRGlzcGxheSB0aGUgZGF0YSBmcmFtZSBhcyBhIG5lYXQgdGFibGUNCmRhdGF0YWJsZShkYXRhX3NvdXJjZXMsIA0KICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgb2YgRGF0YSBTb3VyY2VzIiwNCiAgICAgICAgICByb3duYW1lcyA9IEZBTFNFKSAjIGhpZGVzIHRoZSBpbmRleCBjb2x1bW4NCmBgYA0KDQotLS0NCg0KIyMgRXhlcmNpc2UgNA0KDQoqKkRhdGFzZXQgU3RydWN0dXJlOioqIENvbnNpZGVyIHRoZSBmb2xsb3dpbmcgdHJhbnNhY3Rpb24gdGFibGU6DQoNCnwgRGF0ZSAgICAgICB8IFF0eSB8IFByaWNlIHwgUHJvZHVjdCAgfCBDdXN0b21lclRpZXIgfA0KfC0tLS0tLS0tLS0tLXwtLS0tLXwtLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS18DQp8IDIwMjUtMTAtMDEgfCAyICAgfCAxMDAwICB8IExhcHRvcCAgIHwgSGlnaCAgICAgICAgIHwNCnwgMjAyNS0xMC0wMSB8IDUgICB8IDIwICAgIHwgTW91c2UgICAgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAyIHwgMSAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDIgfCAzICAgfCAzMCAgICB8IEtleWJvYXJkIHwgTWVkaXVtICAgICAgIHwNCnwgMjAyNS0xMC0wMyB8IDQgICB8IDUwICAgIHwgTW91c2UgICAgfCBNZWRpdW0gICAgICAgfA0KfCAyMDI1LTEwLTAzIHwgMiAgIHwgMTAwMCAgfCBMYXB0b3AgICB8IEhpZ2ggICAgICAgICB8DQp8IDIwMjUtMTAtMDQgfCA2ICAgfCAyNSAgICB8IEtleWJvYXJkIHwgTG93ICAgICAgICAgIHwNCnwgMjAyNS0xMC0wNCB8IDEgICB8IDEwMDAgIHwgTGFwdG9wICAgfCBIaWdoICAgICAgICAgfA0KfCAyMDI1LTEwLTA1IHwgMyAgIHwgNDAgICAgfCBNb3VzZSAgICB8IExvdyAgICAgICAgICB8DQp8IDIwMjUtMTAtMDUgfCA1ICAgfCAxMCAgICB8IEtleWJvYXJkIHwgTWVkaXVtICAgICAgIHwNCg0KDQoqKllvdXIgQXNzaWdubWVudCBJbnN0cnVjdGlvbnM6KiogQ3JlYXRpbmcgYSBUcmFuc2FjdGlvbnMgVGFibGUgYWJvdmUgaW4gUg0KDQoxLiAqKkNyZWF0ZSBhIGRhdGEgZnJhbWUqKiBpbiBSIGNhbGxlZCBgdHJhbnNhY3Rpb25zYCBjb250YWluaW5nIHRoZSBkYXRhIGFib3ZlLg0KDQoyLiBJZGVudGlmeSB3aGljaCB2YXJpYWJsZXMgYXJlIG51bWVyaWMgYW5kIHdoaWNoIGFyZSBjYXRlZ29yaWNhbA0KDQozLiAqKkNhbGN1bGF0ZSB0b3RhbCByZXZlbnVlKiogZm9yIGVhY2ggdHJhbnNhY3Rpb24gYnkgbXVsdGlwbHlpbmcgYFF0eSDDlyBQcmljZWAgYW5kIGFkZCBpdCBhcyBhIG5ldyBjb2x1bW4gYFRvdGFsYC4NCg0KNC4gKipDb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljcyoqOg0KICAgLSBUb3RhbCBxdWFudGl0eSBzb2xkIGZvciBlYWNoIHByb2R1Y3QNCiAgIC0gVG90YWwgcmV2ZW51ZSBwZXIgcHJvZHVjdA0KICAgLSBBdmVyYWdlIHByaWNlIHBlciBwcm9kdWN0DQoNCjUuICoqVmlzdWFsaXplIHRoZSBkYXRhKio6DQogICAtIENyZWF0ZSBhICoqYmFycGxvdCoqIHNob3dpbmcgdG90YWwgcXVhbnRpdHkgc29sZCBwZXIgcHJvZHVjdC4NCiAgIC0gQ3JlYXRlIGEgKipwaWUgY2hhcnQqKiBzaG93aW5nIHRoZSBwcm9wb3J0aW9uIG9mIHRvdGFsIHJldmVudWUgcGVyIGN1c3RvbWVyIHRpZXIuDQoNCjYuICoqT3B0aW9uYWwgQ2hhbGxlbmdlKio6DQogICAtIEZpbmQgd2hpY2ggKipkYXRlKiogaGFkIHRoZSBoaWdoZXN0IHRvdGFsIHJldmVudWUuDQogICAtIENyZWF0ZSBhICoqc3RhY2tlZCBiYXIgY2hhcnQqKiBzaG93aW5nIHF1YW50aXR5IHNvbGQgcGVyIHByb2R1Y3QgYnkgY3VzdG9tZXIgdGllci4NCg0KKipIaW50czoqKiBVc2UgYGRhdGEuZnJhbWUoKWAsIGBhZ2dyZWdhdGUoKWAsIGBiYXJwbG90KClgLCBgcGllKClgLCBhbmQgYmFzaWMgYXJpdGhtZXRpYyBvcGVyYXRpb25zIGluIFIuDQoNCmBgYHtyfQ0KbGlicmFyeShEVCkNCiMgNC4xIFRyYW5zYWN0aW9uDQp0cmFuc2FjdGlvbnMgPC0gZGF0YS5mcmFtZSgNCiAgTm8gPSAxIDogMTAsDQogIA0KICBEYXRlID0gYygiMjAyNS0xMC0wMSIsICIyMDI1LTEwLTAxIiwgIjIwMjUtMTAtMDIiLCAiMjAyNS0xMC0wMiIsDQogICAgICAgICAgICAiMjAyNS0xMC0wMyIsIjIwMjUtMTAtMDMiLCAiMjAyNS0xMC0wNCIsICIyMDI1LTEwLTA0IiwgDQogICAgICAgICAgICAiMjAyNS0xMC0wNSIsICIyMDI1LTEwLTA1IiksDQogIA0KICBRdHkgPSBjKDIsNSwxLDMsNCwyLDYsMSwzLDUpLA0KICANCiAgUHJpY2UgPSBjKDEwMDAsMjAsMTAwMCwzMCw1MCwxMDAwLDI1LDEwMDAsNDAsMTApLA0KICANCiAgUHJvZHVjdCA9IGMoIkxhcHRvcCIsICJNb3VzZSIsICJMYXB0b3AiLCAiS2V5Ym9hcmQiLCAiTW91c2UiLA0KICAgICAgICAgICAgICAgIkxhcHRvcCIsICJLZXlib2FyZCIsICJMYXB0b3AiLCAiTW91c2UiLCAiS2V5Ym9hcmQiKSwNCiAgDQogIENvc3R1bWVyVGllciA9IGMoIkhpZ2giLCAiTWVkaXVtIiwgIkxvdyIsICJNZWRpdW0iLCAiTWVkaXVtIiwNCiAgICAgICAgICAgICAgICAgICAgIkhpZ2giLCAiTG93IiwgIkhpZ2giLCAiTG93IiwgIk1lZGl1bSIpDQogICkNCmxpYnJhcnkoa25pdHIpDQojIDQuMiBDcmVhdGUgYSBkYXRhIGZyYW1lIGZvciBEYXRhIFR5cGVzDQp2YXJpYWJsZXNfaW5mbyA8LSBkYXRhLmZyYW1lKA0KICBObyA9IDE6NCwNCiAgVmFyaWFibGUgPSBjKA0KICAgICJRdHkiLA0KICAgICJQcmljZSIsDQogICAgIlByb2R1Y3QiLA0KICAgICJDdXN0b21lcnRpZXIiDQogICksDQogIERhdGFUeXBlID0gYygNCiAgICAiTnVtZXJpYyIsDQogICAgIk51bWVyaWMiLA0KICAgICJDYXRlZ29yaWNhbCIsDQogICAgIkNhdGVnb3JpY2FsIg0KICApLA0KICBzdHJpbmdBc0ZhY3RvcnMgPSBGQUxTRQ0KKQ0KDQpsaWJyYXJ5KGtuaXRyKQ0KIyA0LjMgRGlzcGxheSB0aGUgZGF0YSB0YWJsZSBhcyBhIG5lYXQgdGFibGUNCmthYmxlKHZhcmlhYmxlc19pbmZvLA0KICAgICAgY2FwdGlvbiA9ICJUYWJsZSBvZiBWYXJpYWJsZXMgYW5kIERhdGEgVHlwZXMiKQ0KDQojNC4zIFRyYW5zYWN0aW9ucyBUb3RhbA0KdHJhbnNhY3Rpb25zJFRvdGFsIDwtIHRyYW5zYWN0aW9ucyRRdHkgKiB0cmFuc2FjdGlvbnMkUHJpY2UNCmRhdGF0YWJsZSh0cmFuc2FjdGlvbnMsIA0KICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgb2YgVHJhbnNhY3Rpb24iLA0KICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UpDQoNCmxpYnJhcnkoa25pdHIpDQojIDQuNCBDb21wdXRlIFN1bW1hcnkgU3RhdGlzdGljcw0KIyBUb3RhbCBRdHkgcGVyIFByb2R1Y3QNCnRvdGFsX3F0eV9wZXJfcHJvZHVjdCA8LSBhZ2dyZWdhdGUoUXR5IH4gUHJvZHVjdCwgZGF0YSA9IHRyYW5zYWN0aW9ucywgRlVOID0gc3VtKQ0KcHJpbnQoIlRvdGFsIEt1YW50aXRhcyBUZXJqdWFsIHBlciBQcm9kdWs6IikNCnByaW50KHRvdGFsX3F0eV9wZXJfcHJvZHVjdCkNCg0KIyBUb3RhbCBSZXZlbnVlIHBlciBQcm9kdWN0DQp0b3RhbF9yZXZlbnVlX3Blcl9wcm9kdWN0IDwtIGFnZ3JlZ2F0ZShUb3RhbCB+IFByb2R1Y3QsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIEZVTiA9IHN1bSkNCnByaW50KCJUb3RhbCBQZW5kYXBhdGFuIHBlciBQcm9kdWs6IikNCnByaW50KHRvdGFsX3JldmVudWVfcGVyX3Byb2R1Y3QpDQoNCiMgVG90YWwgUmV2ZW51ZSBwZXIgQ3VzdG9tZXIgVGllcg0KdG90YWxfcmV2ZW51ZV9wZXJfdGllciA8LSBhZ2dyZWdhdGUoVG90YWwgfiBDb3N0dW1lclRpZXIsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIEZVTiA9IHN1bSkNCnByaW50KCJUb3RhbCBQZW5kYXBhdGFuIFBlciBQZWxhbmdnYW46IikNCnByaW50KHRvdGFsX3JldmVudWVfcGVyX3RpZXIpDQoNCiMgQXZlcmFnZSBQcmljZSBwZXIgUHJvZHVjdA0KYXZlcmFnZV9wcmljZV9wZXJfcHJvZHVjdCA8LSBhZ2dyZWdhdGUoUHJpY2UgfiBQcm9kdWN0LCBkYXRhID0gdHJhbnNhY3Rpb25zLCBGVU4gPSBtZWFuKQ0KcHJpbnQoIkhhcmdhIFJhdGEtcmF0YSBwZXIgUHJvZHVrIikNCnByaW50KGF2ZXJhZ2VfcHJpY2VfcGVyX3Byb2R1Y3QpDQoNCmxpYnJhcnkoa25pdHIpDQojIDQuNSBWaXN1YWxpemUgRGF0YQ0KYmFycGxvdCgNCiAgaGVpZ2h0ID0gdG90YWxfcXR5X3Blcl9wcm9kdWN0JFF0eSwgDQogIG5hbWVzLmFyZyA9IHRvdGFsX3F0eV9wZXJfcHJvZHVjdCRQcm9kdWN0LA0KICBjb2wgPSBjKCJwaW5rIiwgImJsdWUiLCAiZ3JlZW4iKSwNCiAgbWFpbiA9ICJUb3RhbCBUcmFuc2FjdGlvbnMiLA0KICB4bGFiID0gIlByb2R1Y3QiLA0KICB5bGFiID0gIlF1YW50aXR5IiwNCiAgeWxpbSA9IGMoMCwgbWF4KHRvdGFsX3F0eV9wZXJfcHJvZHVjdCRRdHkpICsgMikpDQoNCiNQaWUgY2hhcnQNCnJldmVudWVfcGVyX3RpZXIgPC0gYWdncmVnYXRlKFRvdGFsIH4gQ29zdHVtZXJUaWVyLCBkYXRhID0gdHJhbnNhY3Rpb25zLCBGVU4gPSBzdW0pDQp0b3RhbF9yZXZlbnVlIDwtIHN1bShyZXZlbnVlX3Blcl90aWVyJFRvdGFsKQ0KcGVyY2VudGFnZXMgPC0gcm91bmQocmV2ZW51ZV9wZXJfdGllciRUb3RhbCAvIHRvdGFsX3JldmVudWUgKiAxMDAsIDEpDQpwaWVfbGFiZWxzIDwtIHBhc3RlKHJldmVudWVfcGVyX3RpZXIkQ29zdHVtZXJUaWVyLCAiKCIsIHBlcmNlbnRhZ2VzLCAiJSkiLCBzZXAgPSAiIikNCg0KcGllKA0KICB4ID0gcmV2ZW51ZV9wZXJfdGllciRUb3RhbCwNCiAgbGFiZWxzID0gcGllX2xhYmVscywNCiAgbWFpbiA9ICJQcm9wb3J0aW9uIG9mIFRvdGFsIFJldmVudWUgcGVyIEN1c3RvbWVyVGllciIsDQogIGNvbCA9IGMoInB1cnBsZSIsICJ5ZWxsb3ciLCAicmVkIikNCikNCg0KbGlicmFyeShrbml0cikNCiMgNC42IEZpbmQgdGhlIEhpZ2hlc3QgZGF0ZSBvZiB0b3RhbCByZXZlbnVlDQp0cmFuc2FjdGlvbnMkUmV2ZW51ZSA8LSB0cmFuc2FjdGlvbnMkUHJpY2UgKiB0cmFuc2FjdGlvbnMkUXR5DQp0b3RhbF9wZXJfZGF0ZSA8LSBhZ2dyZWdhdGUoUmV2ZW51ZSB+IERhdGUsIGRhdGEgPSB0cmFuc2FjdGlvbnMsIEZVTiA9IHN1bSkNCmhpZ2hlc3QgPC0gdG90YWxfcGVyX2RhdGVbd2hpY2gubWF4KHRvdGFsX3Blcl9kYXRlJFJldmVudWUpLCBdDQpwcmludCgiVGhlIGhpZ2hlc3QgZGF0YSBvZiB0b3RhbCBSZXZlbnVlIikNCnByaW50KHRvdGFsX3Blcl9kYXRlKQ0KcHJpbnQoaGlnaGVzdCkNCg0KIyBTdGFja2VkIEJhciBDaGFydA0KdGFibGVfdHJhbnNhY3Rpb25zIDwtIHdpdGgodHJhbnNhY3Rpb25zLCB0YXBwbHkoUXR5LCBsaXN0KFByb2R1Y3QsIENvc3R1bWVyVGllciksIHN1bSwgbmEucm0gPSBUUlVFKSkNCnRhYmxlX3RyYW5zYWN0aW9uc1tpcy5uYSh0YWJsZV90cmFuc2FjdGlvbnMpXSA8LSAwDQpiYXJwbG90KA0KICB0KHRhYmxlX3RyYW5zYWN0aW9ucyksDQogIGJlc2lkZSA9IEZBTFNFLA0KICBjb2wgPSBjKCJicm93biIsICJnb2xkIiwgIm9yYW5nZSIpLA0KICBtYWluID0gIlF1YW50aXR5IFNvbGQgcGVyIFByb2R1Y3QgYnkgQ3VzdG9tZXJUaWVyIiwNCiAgeGxhYiA9ICJQcm9kdWN0IiwNCiAgeWxhYiA9ICJRdWFudGl0eSBTb2xkIiwNCiAgbGVnZW5kLnRleHQgPSBUUlVFKQ0KICANCg0KYGBgDQoNCiMjIEV4ZXJjaXNlIDUNCg0KKipDcmVhdGUgWW91ciBPd24gRGF0YSBGcmFtZToqKg0KDQoqKk9iamVjdGl2ZToqKiBDcmVhdGUgYSBkYXRhIGZyYW1lIGluIFIgd2l0aCAqKjMwIHJvd3MqKiBjb250YWluaW5nIGEgbWl4IG9mIGRhdGEgdHlwZXM6IGNvbnRpbnVvdXMsIGRpc2NyZXRlLCBub21pbmFsLCBhbmQgb3JkaW5hbC4gIA0KDQojIyMgSW5zdHJ1Y3Rpb25zDQoNCjEuICoqT3BlbiBSU3R1ZGlvKiogb3IgdGhlIFIgY29uc29sZS4gIA0KDQoyLiAqKkNyZWF0ZSBhIHZlY3RvciBmb3IgZWFjaCBjb2x1bW4qKiBpbiB5b3VyIGRhdGEgZnJhbWU6ICANCg0KICAgLSAqKkRhdGUqKjogMzAgZGF0ZXMgKGNhbiBiZSBzZXF1ZW50aWFsIG9yIHJhbmRvbSB3aXRoaW4gYSBtb250aC95ZWFyKSAgDQogICAtICoqQ29udGludW91cyoqOiBudW1lcmljIHZhbHVlcyB0aGF0IGNhbiB0YWtlIGRlY2ltYWwgdmFsdWVzIChlLmcuLCBoZWlnaHQsIHdlaWdodCwgdGVtcGVyYXR1cmUpICANCiAgIC0gKipEaXNjcmV0ZSoqOiBudW1lcmljIHZhbHVlcyB0aGF0IGNhbiBvbmx5IHRha2Ugd2hvbGUgbnVtYmVycyAoZS5nLiwgbnVtYmVyIG9mIGl0ZW1zLCBudW1iZXIgb2YgdmVoaWNsZXMpICANCiAgIC0gKipOb21pbmFsKio6IGNhdGVnb3JpY2FsIHZhbHVlcyB3aXRoICoqbm8gb3JkZXIqKiAoZS5nLiwgY29sb3IsIGdlbmRlciwgY2l0eSkgIA0KICAgLSAqKk9yZGluYWwqKjogY2F0ZWdvcmljYWwgdmFsdWVzIHdpdGggYSAqKmRlZmluZWQgb3JkZXIqKiAoZS5nLiwgTG93LCBNZWRpdW0sIEhpZ2g7IEJlZ2lubmVyLCBJbnRlcm1lZGlhdGUsIEV4cGVydCkgIA0KDQozLiAqKkNvbWJpbmUgYWxsIHZlY3RvcnMgaW50byBhIGRhdGEgZnJhbWUqKiBjYWxsZWQgYG15X2RhdGFgLiAgDQoNCjQuICoqQ2hlY2sgeW91ciBkYXRhIGZyYW1lKiogdXNpbmcgYGhlYWQoKWAgb3IgYFZpZXcoKWAgdG8gZW5zdXJlIGl0IGhhcyAqKjMwIHJvd3MqKiBhbmQgdGhlIGNvbHVtbnMgYXJlIGNvcnJlY3QuICANCg0KNS4gKipPcHRpb25hbCB0YXNrcyoqOiAgDQogICAtIFN1bW1hcml6ZSBlYWNoIGNvbHVtbiB1c2luZyBgc3VtbWFyeSgpYCAgDQogICAtIENvdW50IHRoZSBmcmVxdWVuY3kgb2YgZWFjaCBjYXRlZ29yeSBmb3IgKipOb21pbmFsKiogYW5kICoqT3JkaW5hbCoqIGNvbHVtbnMgdXNpbmcgYHRhYmxlKClgICANCg0KYGBge3J9DQpsaWJyYXJ5KERUKQ0KbGlicmFyeShrbml0cikNCiMgNS4xIENyZWF0ZSBhIHZlY3RvciBmb3IgZWFjaCBjb2x1bW4NCnNldC5zZWVkKDUwKQ0KdGFuZ2dhbCA8LSBhcy5EYXRlKCIyMDI0LTAxLTAxIikgKyBzYW1wbGUoMDozNjUsIDMwLCByZXBsYWNlID0gVFJVRSkNCmhld2FuIDwtIGMoIkt1Y2luZyIsICJBbmppbmciLCAiS2VsaW5jaSIsICJCdXJ1bmciLA0KICAgICAgICAgICAiS3VkYSIsICJHYWphaCIsICJTaW5nYSIsICJIYXJpbWF1IiwgIlplYnJhIiwgIlBhbmRhIiwgIlJ1c2EiLA0KICAgICAgICAgICAiVW50YSIsICJLdWRhbmlsIiwgIkJhZGFrIiwgIkJlcnVhbmciLCAiTW9ueWV0IiwgIkdvcmlsYSIsICJLYW5ndXJ1IiwNCiAgICAgICAgICAgIktvYWxhIiwgIlNlcmlnYWxhIiwgIkt1Y2luZyIsICJBbmppbmciLCAiQnVydW5nIiwgIkdhamFoIiwgIlNpbmdhIiwgDQogICAgICAgICAgICJIYXJpbWF1IiwgIlplYnJhIiwgIlBhbmRhIiwgIlJ1c2EiLCAiVW50YSIpDQpoZXdhbiA8LSBmYWN0b3IoaGV3YW4pDQoNCmp1bWxhaF9wb3JzaV9tYWthbmFuIDwtIGMoNSwgNSwgMywgNCwgMywgDQogICAgICAgICAgICAgICAgICAzLCA1LCA1LCA1LCA2LCANCiAgICAgICAgICAgICAgICAgIDQsIDQsIDYsIDYsIDUsIA0KICAgICAgICAgICAgICAgICAgNSwgNiwgNCwgNCwgNSwgDQogICAgICAgICAgICAgICAgICA1LCA0LCA1LCA2LCA3LCANCiAgICAgICAgICAgICAgICAgIDYsIDUsIDYsIDQsIDQpDQoNCmJlcmF0IDwtIGMoMjQuNTYsIDQ4Ljc2LCAxNS40OCwgOS42NCwgMjg5LjY3LCA3ODUuNTQsIDI5My4yNywgMjU3LjM4LCAxNTguMzUsIA0KICAgICAgICAgICA5My4zMiwgODIuNjcsIDYzMi43NSwgNDI5LjcxLCA4MzYuNTQsIDI3NC42OCwgMTguNTYsIDQ2Ny44MiwgMTUyLjc0LA0KICAgICAgICAgICA1Mi44NSwgMTcyLjkyLCAzOC41NiwgOTUuMjcsIDYuMzIsIDM2NC43OCwgMjg0LjkyLCAyNTYuODUsIDE5My42NSwNCiAgICAgICAgICAgMTIzLjQ1LCAxMTAuNDMsIDU3Ni45OCkNCg0Ka2VsaW5jYWhhbiA8LSBjKCJUaW5nZ2kiLCAiVGluZ2dpIiwgIlNlZGFuZyIsICJUaW5nZ2kiLCAiU2VkYW5nIiwgIlJlbmRhaCIsICJUaW5nZ2kiLA0KICAgICAgICAgICAgICAgICJUaW5nZ2kiLCAiU2VkYW5nIiwgIlNlZGFuZyIsICJTZWRhbmciLCAiUmVuZGFoIiwgIlJlbmRhaCIsICJSZW5kYWgiLA0KICAgICAgICAgICAgICAgICJTZWRhbmciLCAiVGluZ2dpIiwgIlJlbmRhaCIsICJUaW5nZ2kiLCAiU2VkYW5nIiwgIlRpbmdnaSIsICJTZWRhbmciLCANCiAgICAgICAgICAgICAgICAiVGluZ2dpIiwgIlRpbmdnaSIsICJTZWRhbmciLCAiVGluZ2dpIiwgIlRpbmdnaSIsICJTZWRhbmciLCAiU2VkYW5nIiwNCiAgICAgICAgICAgICAgICAiU2VkYW5nIiwgIlJlbmRhaCIpDQprZWxpbmNhaGFuIDwtIGZhY3RvcihrZWxpbmNhaGFuLA0KICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiUmVuZGFoIiwgIlNlZGFuZyIsICJUaW5nZ2kiKSwNCiAgICAgICAgICAgICAgICAgICAgIG9yZGVyZWQgPSBUUlVFKQ0KDQojIDUuMiBDb21iaW5lIGFsbCB2ZWN0b3JzIGludG8gYSBkYXRhIGZyYW1lDQpEYXRhX0hld2FuIDwtIGRhdGEuZnJhbWUodGFuZ2dhbCwgaGV3YW4sIGp1bWxhaF9wb3JzaV9tYWthbmFuLCBiZXJhdCwga2VsaW5jYWhhbikNCg0KIyA1LjMgQ3JlYXRlIGEgZGF0YSBmcmFtZSBhcyBhIG5lYXQgdGFibGUNCmRhdGF0YWJsZShEYXRhX0hld2FuLCBjYXB0aW9uID0gIlJla2FwaXR1bGFzaSBEYXRhIEhld2FuOiBKZW5pcywgQmVyYXQgZGFuIEtlbGluY2FoYW4iLCBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMTApKQ0KDQojIDUuMyBDcmVhdGUgYSB0YWJsZSBvZiB2YXJpYWJsZSB0eXBlcw0KdmFyaWFibGVzX2luZm8yIDwtIGRhdGEuZnJhbWUoDQogIE5vID0gMTo0LA0KICBWYXJpYWJsZSA9IGMoDQogICAgIkhld2FuIiwNCiAgICAiSnVtbGFoUG9yc2lNYWthbmFuIiwNCiAgICAiQmVyYXQiLA0KICAgICJLZWxpbmNhaGFuIiksDQogIERhdGFUeXBlID0gYygNCiAgICAiTm9taW5hbCIsDQogICAgIkRpc2tyaXQiLA0KICAgICJDb250aW51b3VzIiwNCiAgICAiT3JkaW5hbCIpLA0KICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCikNCg0Ka25pdHI6OmthYmxlKHZhcmlhYmxlc19pbmZvMiwgY2FwdGlvbiA9ICJUYWJsZSBvZiBWYXJpYWJsZSBhbmQgRGF0YSBUeXBlIikNCg0KIyA1LjQgU3VtbWFyaXplIGVhY2ggY29sdW1uDQpzdW1tYXJ5KERhdGFfSGV3YW4pDQpzdW1tYXJ5KHRyYW5zYWN0aW9ucykNCg0Kc3VtbWFyeV90YWJsZSA8LSBzdW1tYXJ5KERhdGFfSGV3YW4pDQprbml0cjo6a2FibGUoYXMuZGF0YS5mcmFtZShzdW1tYXJ5X3RhYmxlKSwgY2FwdGlvbiA9ICJTdW1tYXJ5IG9mIERhdGEgSGV3YW4iKQ0KDQoNCiMgNS40IENvdW50IHRoZSBmcmVxdWVuY3kgb2YgZWFjaCBjYXRlZ29yeSBmb3IgKipOb21pbmFsKiogYW5kICoqT3JkaW5hbCoqIGNvbHVtbnMNCmxpc3QoDQogIE5vbWluYWwgPSB0YWJsZShEYXRhX0hld2FuJEhld2FuKSwNCiAgT3JkaW5hbCA9IHRhYmxlKERhdGFfSGV3YW4ka2VsaW5jYWhhbikNCikNCg0KDQpgYGANCg0KDQoNCg0KDQoNCg0K