Pemprogram Sains Data

UTS Pemprograman Sains Data

Logo

1 Heatmap

library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
library(dplyr)
## Warning: package 'dplyr' was built under R version 4.4.3
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(RColorBrewer)

data_bisnis <- read.csv("Latihan bab 8.csv")

sales_grouped <- data_bisnis %>%
  group_by(Product_Category, Region) %>%
  summarise(Total_Price = sum(Total_Price, na.rm = TRUE), .groups = "drop")

ggplot(sales_grouped, aes(x = Region, y = Product_Category, fill = Total_Price)) +
  geom_tile(color = "white") +
  geom_text(aes(label = round(Total_Price, 0)), color = "black", size = 4) +
  scale_fill_gradientn(colors = brewer.pal(9, "Blues"), name = "Total Sales") +
  labs(
    title = "Heatmap Total Sales by Product Category and Region",
    x = "Region",
    y = "Product Category"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    plot.title = element_text(hjust = 0.5)
  )


2 Scatter Plot

library(ggplot2)
library(dplyr)

data_bisnis <- read.csv("Latihan bab 8.csv", stringsAsFactors = FALSE)

# Pastikan data bersih
data_bisnis <- data_bisnis %>%
  mutate(
    Quantity = as.numeric(Quantity),
    Total_Price = as.numeric(Total_Price)
  ) %>%
  filter(!is.na(Quantity), !is.na(Total_Price))

# Scatter plot dengan legend di luar
ggplot(data_bisnis, aes(x = Quantity, y = Total_Price, color = Product_Category)) +
  geom_point(alpha = 0.5, size = 1.8) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 1.2) +
  labs(
    title = "Scatter Plot dengan Garis Tren: Total Price vs Quantity",
    x = "Quantity",
    y = "Total Price",
    color = "Product Category"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 16, face = "bold"),
    axis.title = element_text(size = 14),
    axis.text = element_text(size = 12),
    legend.title = element_text(size = 12),
    legend.text = element_text(size = 11),
    legend.position = "right"     # pindahkan legend ke kanan (tidak menutupi plot)
  )
## `geom_smooth()` using formula = 'y ~ x'


3 Bubble Chart

# Load libraries
library(ggplot2)
library(dplyr)
library(readr)
## Warning: package 'readr' was built under R version 4.4.2
library(scales)
## 
## Attaching package: 'scales'
## The following object is masked from 'package:readr':
## 
##     col_factor
# Load data
df <- read_csv("Latihan bab 8.csv")
## New names:
## • `` -> `...1`
## Rows: 500 Columns: 25
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr   (8): Transaction_ID, Customer_ID, Product_Category, Product_ID, Region...
## dbl  (15): ...1, Quantity, Unit_Price, Discount, Delivery_Time, Total_Price,...
## lgl   (1): ID_HasPattern
## date  (1): Transaction_Date
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
# Convert to numeric
df$Quantity <- as.numeric(df$Quantity)
df$Unit_Price <- as.numeric(df$Unit_Price)

# Hitung Total_Price
df <- df %>%
  mutate(Total_Price = Quantity * Unit_Price) %>%
  filter(!is.na(Quantity), !is.na(Unit_Price), !is.na(Total_Price), !is.na(Region))

# Agregasi data
agg <- df %>%
  group_by(Product_Category, Region) %>%
  summarise(
    Quantity = sum(Quantity, na.rm = TRUE),
    Total_Price = sum(Total_Price, na.rm = TRUE),
    .groups = 'drop'
  )

# Tambahkan x_base dan jitter
agg <- agg %>%
  mutate(
    x_base = as.numeric(as.factor(Product_Category)),
    x_jitter = x_base + runif(n(), -0.2, 0.2)
  )

# Skala ukuran bubble
max_size <- 25  # ukuran relatif (bukan pixel seperti matplotlib)
min_size <- 4
scaled <- rescale(agg$Total_Price, to = c(min_size, max_size))
agg$bubble_size <- scaled

# Plot
ggplot(agg, aes(x = x_jitter, y = Quantity, size = bubble_size, fill = Region)) +
  geom_point(shape = 21, color = "black", alpha = 0.6) +
  geom_text(aes(label = Product_Category), color = "black", fontface = "bold", size = 3, vjust = 0.5, hjust = 0.5) +
  scale_size_identity() +
  scale_fill_brewer(palette = "Set2") +
  scale_x_continuous(
    breaks = unique(agg$x_base),
    labels = levels(as.factor(agg$Product_Category))
  ) +
  labs(
    title = "4D Bubble Chart: Quantity vs Product Category\n(Bubble = Total Price, Color = Region)",
    x = "Product Category",
    y = "Total Quantity",
    fill = "Region"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(size = 12),
    axis.title = element_text(size = 14),
    plot.title = element_text(size = 16, hjust = 0.5)
  )


4 Correlation Matrix

# Load library
library(readr)
library(dplyr)
library(ggplot2)
library(tidyr)

# Load data
df <- read_csv("Latihan bab 8.csv")
## New names:
## Rows: 500 Columns: 25
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (8): Transaction_ID, Customer_ID, Product_Category, Product_ID, Region... dbl
## (15): ...1, Quantity, Unit_Price, Discount, Delivery_Time, Total_Price,... lgl
## (1): ID_HasPattern date (1): Transaction_Date
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
# Pastikan kolom numerik dan hitung Total_Price
df <- df %>%
  mutate(
    Quantity = as.numeric(Quantity),
    Unit_Price = as.numeric(Unit_Price),
    Total_Price = Quantity * Unit_Price
  )

# Pilih kolom numerik dan hilangkan NA
numeric_df <- df %>%
  select(Quantity, Unit_Price, Total_Price) %>%
  drop_na()

# Hitung korelasi
corr_matrix <- round(cor(numeric_df), 2)

# Ubah ke format long
corr_long <- as.data.frame(as.table(corr_matrix))
colnames(corr_long) <- c("Var1", "Var2", "Correlation")

# Visualisasi ggplot dengan skema warna mirip 'coolwarm'
ggplot(corr_long, aes(x = Var1, y = Var2, fill = Correlation)) +
  geom_tile(color = "white") +
  geom_text(aes(label = sprintf("%.2f", Correlation)), size = 5) +
  scale_fill_gradientn(
    colours = c("#3b4cc0", "#78aadd", "#ffffff", "#f7945d", "#b40426"),
    limits = c(-1, 1),
    name = "Correlation"
  ) +
  theme_minimal() +
  labs(title = "Correlation Matrix", x = NULL, y = NULL) +
  theme(
    axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1),
    plot.title = element_text(size = 16, face = "bold")
  )


5 Line Chart

library(ggplot2)
library(readr)
library(dplyr)

# 1. Load dataset
data_bisnis <- read_csv("Latihan bab 8.csv")
## New names:
## Rows: 500 Columns: 25
## ── Column specification
## ──────────────────────────────────────────────────────── Delimiter: "," chr
## (8): Transaction_ID, Customer_ID, Product_Category, Product_ID, Region... dbl
## (15): ...1, Quantity, Unit_Price, Discount, Delivery_Time, Total_Price,... lgl
## (1): ID_HasPattern date (1): Transaction_Date
## ℹ Use `spec()` to retrieve the full column specification for this data. ℹ
## Specify the column types or set `show_col_types = FALSE` to quiet this message.
## • `` -> `...1`
# Pastikan Quantity numerik dan hilangkan NA
data_bisnis <- data_bisnis %>%
  mutate(Quantity = as.numeric(Quantity)) %>%
  filter(!is.na(Quantity))

# Jika ada kolom 'Date', buat line chart berdasarkan waktu
if ("Date" %in% names(data_bisnis)) {
  data_bisnis$Date <- as.Date(data_bisnis$Date)

  df_line <- data_bisnis %>%
    group_by(Date, Product_Category) %>%
    summarise(Quantity = sum(Quantity, na.rm = TRUE), .groups = 'drop')

  ggplot(df_line, aes(x = Date, y = Quantity, color = Product_Category)) +
    geom_line() +
    labs(title = "Tren Kuantitas per Kategori Produk",
         x = "Tanggal", y = "Kuantitas") +
    theme_minimal()
} else {
  # Jika tidak ada Date, agregasi berdasarkan kategori
  df_line <- data_bisnis %>%
    group_by(Product_Category) %>%
    summarise(Quantity = sum(Quantity), .groups = 'drop')

  ggplot(df_line, aes(x = Product_Category, y = Quantity, group = 1)) +
    geom_line() +
    geom_point() +
    labs(title = "Total Kuantitas per Kategori Produk",
         x = "Kategori Produk", y = "Kuantitas") +
    theme_minimal()
}


6 Area Chart

# Load library
library(ggplot2)
library(dplyr)
library(lubridate)
## Warning: package 'lubridate' was built under R version 4.4.3
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
# =============== #
# 1. Load Dataset #
# =============== #
data_bisnis <- read.csv("Latihan bab 8.csv")

# Pastikan kolom Total_Price adalah numerik dan hilangkan nilai NA
data_bisnis$Total_Price <- as.numeric(data_bisnis$Total_Price)
data_bisnis <- na.omit(data_bisnis)

# Ubah format tanggal
data_bisnis$Transaction_Date <- as.Date(data_bisnis$Transaction_Date)

# Mengelompokkan data berdasarkan bulan dan menjumlahkan Total_Price
data_bisnis$Month <- floor_date(data_bisnis$Transaction_Date, "month")
data_grouped <- data_bisnis %>%
  group_by(Month) %>%
  summarise(Total_Price = sum(Total_Price))

# ========================== #
# 2. Buat Area Chart        #
# ========================== #
ggplot(data_grouped, aes(x = Month, y = Total_Price)) +
  geom_area(fill = "skyblue", alpha = 0.5) +  # Area chart
  geom_line(color = "Slateblue", size = 1.2) +  # Garis di atas area
  labs(title = "Total Price per Bulan", 
       x = "Bulan", 
       y = "Total Price") +
  theme_minimal(base_size = 14) +  # Tema minimal
  theme(plot.title = element_text(hjust = 0.5, face = "bold"),  # Judul tengah dan tebal
        axis.text.x = element_text(angle = 45, hjust = 1)) +  # Memiringkan label sumbu x
  scale_y_continuous(labels = scales::dollar)  # Format sumbu y sebagai dollar
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

LS0tDQp0aXRsZTogIlBlbXByb2dyYW0gU2FpbnMgRGF0YSINCnN1YnRpdGxlOiAiVVRTIFBlbXByb2dyYW1hbiBTYWlucyBEYXRhIg0KYXV0aG9yOiANCiAgLSAiTm92YSBTaXRvcnVzIDUyMjQwMDIzIg0KZGF0ZTogICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6cmVhZHRoZWRvd246ICAgIyBodHRwczovL2dpdGh1Yi5jb20vanViYS9ybWRmb3JtYXRzDQogICAgc2VsZl9jb250YWluZWQ6IHRydWUNCiAgICB0aHVtYm5haWxzOiB0cnVlDQogICAgbGlnaHRib3g6IHRydWUNCiAgICBnYWxsZXJ5OiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgbGliX2RpcjogbGlicw0KICAgIGRmX3ByaW50OiAicGFnZWQiDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyINCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBjc3M6ICJzdHlsZS9zdHlsZSBjc3MuY3NzIg0KLS0tDQoNCjxzdHlsZT4NCiAgYm9keSB7DQogICAgdGV4dC1hbGlnbjoganVzdGlmeTsNCiAgfQ0KPC9zdHlsZT4NCg0KPGltZyBzcmM9Ik5PVkEuanBnIiBhbHQ9IkxvZ28iIHN0eWxlPSJ3aWR0aDo1MDBweDsgZGlzcGxheTogYmxvY2s7IG1hcmdpbjogYXV0bzsiLz4NCg0KIyBIZWF0bWFwDQpgYGB7ciBoZWF0bWFwLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NywgZmlnLmFsaWduPSdjZW50ZXInLCBvdXQud2lkdGg9JzEwMCUnfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KDQpkYXRhX2Jpc25pcyA8LSByZWFkLmNzdigiTGF0aWhhbiBiYWIgOC5jc3YiKQ0KDQpzYWxlc19ncm91cGVkIDwtIGRhdGFfYmlzbmlzICU+JQ0KICBncm91cF9ieShQcm9kdWN0X0NhdGVnb3J5LCBSZWdpb24pICU+JQ0KICBzdW1tYXJpc2UoVG90YWxfUHJpY2UgPSBzdW0oVG90YWxfUHJpY2UsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpDQoNCmdncGxvdChzYWxlc19ncm91cGVkLCBhZXMoeCA9IFJlZ2lvbiwgeSA9IFByb2R1Y3RfQ2F0ZWdvcnksIGZpbGwgPSBUb3RhbF9QcmljZSkpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcm91bmQoVG90YWxfUHJpY2UsIDApKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnMgPSBicmV3ZXIucGFsKDksICJCbHVlcyIpLCBuYW1lID0gIlRvdGFsIFNhbGVzIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkhlYXRtYXAgVG90YWwgU2FsZXMgYnkgUHJvZHVjdCBDYXRlZ29yeSBhbmQgUmVnaW9uIiwNCiAgICB4ID0gIlJlZ2lvbiIsDQogICAgeSA9ICJQcm9kdWN0IENhdGVnb3J5Ig0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpDQogICkNCg0KYGBgDQoNCg0KLS0tDQoNCiMgU2NhdHRlciBQbG90DQpgYGB7ciwgZWNobz1UUlVFLCBtZXNzYWdlPVRSVUV9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQpkYXRhX2Jpc25pcyA8LSByZWFkLmNzdigiTGF0aWhhbiBiYWIgOC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQoNCiMgUGFzdGlrYW4gZGF0YSBiZXJzaWgNCmRhdGFfYmlzbmlzIDwtIGRhdGFfYmlzbmlzICU+JQ0KICBtdXRhdGUoDQogICAgUXVhbnRpdHkgPSBhcy5udW1lcmljKFF1YW50aXR5KSwNCiAgICBUb3RhbF9QcmljZSA9IGFzLm51bWVyaWMoVG90YWxfUHJpY2UpDQogICkgJT4lDQogIGZpbHRlcighaXMubmEoUXVhbnRpdHkpLCAhaXMubmEoVG90YWxfUHJpY2UpKQ0KDQojIFNjYXR0ZXIgcGxvdCBkZW5nYW4gbGVnZW5kIGRpIGx1YXINCmdncGxvdChkYXRhX2Jpc25pcywgYWVzKHggPSBRdWFudGl0eSwgeSA9IFRvdGFsX1ByaWNlLCBjb2xvciA9IFByb2R1Y3RfQ2F0ZWdvcnkpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUsIHNpemUgPSAxLjgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgbGluZXdpZHRoID0gMS4yKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiU2NhdHRlciBQbG90IGRlbmdhbiBHYXJpcyBUcmVuOiBUb3RhbCBQcmljZSB2cyBRdWFudGl0eSIsDQogICAgeCA9ICJRdWFudGl0eSIsDQogICAgeSA9ICJUb3RhbCBQcmljZSIsDQogICAgY29sb3IgPSAiUHJvZHVjdCBDYXRlZ29yeSINCiAgKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiICAgICAjIHBpbmRhaGthbiBsZWdlbmQga2Uga2FuYW4gKHRpZGFrIG1lbnV0dXBpIHBsb3QpDQogICkNCmBgYA0KDQotLS0tDQoNCiMgQnViYmxlIENoYXJ0DQoNCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9VFJVRX0NCiMgTG9hZCBsaWJyYXJpZXMNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShzY2FsZXMpDQoNCiMgTG9hZCBkYXRhDQpkZiA8LSByZWFkX2NzdigiTGF0aWhhbiBiYWIgOC5jc3YiKQ0KDQojIENvbnZlcnQgdG8gbnVtZXJpYw0KZGYkUXVhbnRpdHkgPC0gYXMubnVtZXJpYyhkZiRRdWFudGl0eSkNCmRmJFVuaXRfUHJpY2UgPC0gYXMubnVtZXJpYyhkZiRVbml0X1ByaWNlKQ0KDQojIEhpdHVuZyBUb3RhbF9QcmljZQ0KZGYgPC0gZGYgJT4lDQogIG11dGF0ZShUb3RhbF9QcmljZSA9IFF1YW50aXR5ICogVW5pdF9QcmljZSkgJT4lDQogIGZpbHRlcighaXMubmEoUXVhbnRpdHkpLCAhaXMubmEoVW5pdF9QcmljZSksICFpcy5uYShUb3RhbF9QcmljZSksICFpcy5uYShSZWdpb24pKQ0KDQojIEFncmVnYXNpIGRhdGENCmFnZyA8LSBkZiAlPiUNCiAgZ3JvdXBfYnkoUHJvZHVjdF9DYXRlZ29yeSwgUmVnaW9uKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIFF1YW50aXR5ID0gc3VtKFF1YW50aXR5LCBuYS5ybSA9IFRSVUUpLA0KICAgIFRvdGFsX1ByaWNlID0gc3VtKFRvdGFsX1ByaWNlLCBuYS5ybSA9IFRSVUUpLA0KICAgIC5ncm91cHMgPSAnZHJvcCcNCiAgKQ0KDQojIFRhbWJhaGthbiB4X2Jhc2UgZGFuIGppdHRlcg0KYWdnIDwtIGFnZyAlPiUNCiAgbXV0YXRlKA0KICAgIHhfYmFzZSA9IGFzLm51bWVyaWMoYXMuZmFjdG9yKFByb2R1Y3RfQ2F0ZWdvcnkpKSwNCiAgICB4X2ppdHRlciA9IHhfYmFzZSArIHJ1bmlmKG4oKSwgLTAuMiwgMC4yKQ0KICApDQoNCiMgU2thbGEgdWt1cmFuIGJ1YmJsZQ0KbWF4X3NpemUgPC0gMjUgICMgdWt1cmFuIHJlbGF0aWYgKGJ1a2FuIHBpeGVsIHNlcGVydGkgbWF0cGxvdGxpYikNCm1pbl9zaXplIDwtIDQNCnNjYWxlZCA8LSByZXNjYWxlKGFnZyRUb3RhbF9QcmljZSwgdG8gPSBjKG1pbl9zaXplLCBtYXhfc2l6ZSkpDQphZ2ckYnViYmxlX3NpemUgPC0gc2NhbGVkDQoNCiMgUGxvdA0KZ2dwbG90KGFnZywgYWVzKHggPSB4X2ppdHRlciwgeSA9IFF1YW50aXR5LCBzaXplID0gYnViYmxlX3NpemUsIGZpbGwgPSBSZWdpb24pKSArDQogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gUHJvZHVjdF9DYXRlZ29yeSksIGNvbG9yID0gImJsYWNrIiwgZm9udGZhY2UgPSAiYm9sZCIsIHNpemUgPSAzLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAwLjUpICsNCiAgc2NhbGVfc2l6ZV9pZGVudGl0eSgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQyIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoDQogICAgYnJlYWtzID0gdW5pcXVlKGFnZyR4X2Jhc2UpLA0KICAgIGxhYmVscyA9IGxldmVscyhhcy5mYWN0b3IoYWdnJFByb2R1Y3RfQ2F0ZWdvcnkpKQ0KICApICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICI0RCBCdWJibGUgQ2hhcnQ6IFF1YW50aXR5IHZzIFByb2R1Y3QgQ2F0ZWdvcnlcbihCdWJibGUgPSBUb3RhbCBQcmljZSwgQ29sb3IgPSBSZWdpb24pIiwNCiAgICB4ID0gIlByb2R1Y3QgQ2F0ZWdvcnkiLA0KICAgIHkgPSAiVG90YWwgUXVhbnRpdHkiLA0KICAgIGZpbGwgPSAiUmVnaW9uIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGhqdXN0ID0gMC41KQ0KICApDQpgYGANCg0KLS0tLQ0KDQojIENvcnJlbGF0aW9uIE1hdHJpeA0KYGBge3IsIGVjaG89VFJVRSwgbWVzc2FnZT1UUlVFfQ0KIyBMb2FkIGxpYnJhcnkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5cikNCg0KIyBMb2FkIGRhdGENCmRmIDwtIHJlYWRfY3N2KCJMYXRpaGFuIGJhYiA4LmNzdiIpDQoNCiMgUGFzdGlrYW4ga29sb20gbnVtZXJpayBkYW4gaGl0dW5nIFRvdGFsX1ByaWNlDQpkZiA8LSBkZiAlPiUNCiAgbXV0YXRlKA0KICAgIFF1YW50aXR5ID0gYXMubnVtZXJpYyhRdWFudGl0eSksDQogICAgVW5pdF9QcmljZSA9IGFzLm51bWVyaWMoVW5pdF9QcmljZSksDQogICAgVG90YWxfUHJpY2UgPSBRdWFudGl0eSAqIFVuaXRfUHJpY2UNCiAgKQ0KDQojIFBpbGloIGtvbG9tIG51bWVyaWsgZGFuIGhpbGFuZ2thbiBOQQ0KbnVtZXJpY19kZiA8LSBkZiAlPiUNCiAgc2VsZWN0KFF1YW50aXR5LCBVbml0X1ByaWNlLCBUb3RhbF9QcmljZSkgJT4lDQogIGRyb3BfbmEoKQ0KDQojIEhpdHVuZyBrb3JlbGFzaQ0KY29ycl9tYXRyaXggPC0gcm91bmQoY29yKG51bWVyaWNfZGYpLCAyKQ0KDQojIFViYWgga2UgZm9ybWF0IGxvbmcNCmNvcnJfbG9uZyA8LSBhcy5kYXRhLmZyYW1lKGFzLnRhYmxlKGNvcnJfbWF0cml4KSkNCmNvbG5hbWVzKGNvcnJfbG9uZykgPC0gYygiVmFyMSIsICJWYXIyIiwgIkNvcnJlbGF0aW9uIikNCg0KIyBWaXN1YWxpc2FzaSBnZ3Bsb3QgZGVuZ2FuIHNrZW1hIHdhcm5hIG1pcmlwICdjb29sd2FybScNCmdncGxvdChjb3JyX2xvbmcsIGFlcyh4ID0gVmFyMSwgeSA9IFZhcjIsIGZpbGwgPSBDb3JyZWxhdGlvbikpICsNCiAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc3ByaW50ZigiJS4yZiIsIENvcnJlbGF0aW9uKSksIHNpemUgPSA1KSArDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKA0KICAgIGNvbG91cnMgPSBjKCIjM2I0Y2MwIiwgIiM3OGFhZGQiLCAiI2ZmZmZmZiIsICIjZjc5NDVkIiwgIiNiNDA0MjYiKSwNCiAgICBsaW1pdHMgPSBjKC0xLCAxKSwNCiAgICBuYW1lID0gIkNvcnJlbGF0aW9uIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhdGlvbiBNYXRyaXgiLCB4ID0gTlVMTCwgeSA9IE5VTEwpICsNCiAgdGhlbWUoDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgdmp1c3QgPSAxLCBoanVzdCA9IDEpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKQ0KICApDQoNCmBgYA0KDQoNCi0tLS0NCg0KIyBMaW5lIENoYXJ0DQoNCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9VFJVRX0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGRwbHlyKQ0KDQojIDEuIExvYWQgZGF0YXNldA0KZGF0YV9iaXNuaXMgPC0gcmVhZF9jc3YoIkxhdGloYW4gYmFiIDguY3N2IikNCg0KIyBQYXN0aWthbiBRdWFudGl0eSBudW1lcmlrIGRhbiBoaWxhbmdrYW4gTkENCmRhdGFfYmlzbmlzIDwtIGRhdGFfYmlzbmlzICU+JQ0KICBtdXRhdGUoUXVhbnRpdHkgPSBhcy5udW1lcmljKFF1YW50aXR5KSkgJT4lDQogIGZpbHRlcighaXMubmEoUXVhbnRpdHkpKQ0KDQojIEppa2EgYWRhIGtvbG9tICdEYXRlJywgYnVhdCBsaW5lIGNoYXJ0IGJlcmRhc2Fya2FuIHdha3R1DQppZiAoIkRhdGUiICVpbiUgbmFtZXMoZGF0YV9iaXNuaXMpKSB7DQogIGRhdGFfYmlzbmlzJERhdGUgPC0gYXMuRGF0ZShkYXRhX2Jpc25pcyREYXRlKQ0KDQogIGRmX2xpbmUgPC0gZGF0YV9iaXNuaXMgJT4lDQogICAgZ3JvdXBfYnkoRGF0ZSwgUHJvZHVjdF9DYXRlZ29yeSkgJT4lDQogICAgc3VtbWFyaXNlKFF1YW50aXR5ID0gc3VtKFF1YW50aXR5LCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQogIGdncGxvdChkZl9saW5lLCBhZXMoeCA9IERhdGUsIHkgPSBRdWFudGl0eSwgY29sb3IgPSBQcm9kdWN0X0NhdGVnb3J5KSkgKw0KICAgIGdlb21fbGluZSgpICsNCiAgICBsYWJzKHRpdGxlID0gIlRyZW4gS3VhbnRpdGFzIHBlciBLYXRlZ29yaSBQcm9kdWsiLA0KICAgICAgICAgeCA9ICJUYW5nZ2FsIiwgeSA9ICJLdWFudGl0YXMiKSArDQogICAgdGhlbWVfbWluaW1hbCgpDQp9IGVsc2Ugew0KICAjIEppa2EgdGlkYWsgYWRhIERhdGUsIGFncmVnYXNpIGJlcmRhc2Fya2FuIGthdGVnb3JpDQogIGRmX2xpbmUgPC0gZGF0YV9iaXNuaXMgJT4lDQogICAgZ3JvdXBfYnkoUHJvZHVjdF9DYXRlZ29yeSkgJT4lDQogICAgc3VtbWFyaXNlKFF1YW50aXR5ID0gc3VtKFF1YW50aXR5KSwgLmdyb3VwcyA9ICdkcm9wJykNCg0KICBnZ3Bsb3QoZGZfbGluZSwgYWVzKHggPSBQcm9kdWN0X0NhdGVnb3J5LCB5ID0gUXVhbnRpdHksIGdyb3VwID0gMSkpICsNCiAgICBnZW9tX2xpbmUoKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBsYWJzKHRpdGxlID0gIlRvdGFsIEt1YW50aXRhcyBwZXIgS2F0ZWdvcmkgUHJvZHVrIiwNCiAgICAgICAgIHggPSAiS2F0ZWdvcmkgUHJvZHVrIiwgeSA9ICJLdWFudGl0YXMiKSArDQogICAgdGhlbWVfbWluaW1hbCgpDQp9DQoNCmBgYA0KDQotLS0tDQoNCiMgQXJlYSBDaGFydA0KDQoNCmBgYHtyLCBlY2hvPVRSVUUsIG1lc3NhZ2U9VFJVRX0NCiMgTG9hZCBsaWJyYXJ5DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQoNCiMgPT09PT09PT09PT09PT09ICMNCiMgMS4gTG9hZCBEYXRhc2V0ICMNCiMgPT09PT09PT09PT09PT09ICMNCmRhdGFfYmlzbmlzIDwtIHJlYWQuY3N2KCJMYXRpaGFuIGJhYiA4LmNzdiIpDQoNCiMgUGFzdGlrYW4ga29sb20gVG90YWxfUHJpY2UgYWRhbGFoIG51bWVyaWsgZGFuIGhpbGFuZ2thbiBuaWxhaSBOQQ0KZGF0YV9iaXNuaXMkVG90YWxfUHJpY2UgPC0gYXMubnVtZXJpYyhkYXRhX2Jpc25pcyRUb3RhbF9QcmljZSkNCmRhdGFfYmlzbmlzIDwtIG5hLm9taXQoZGF0YV9iaXNuaXMpDQoNCiMgVWJhaCBmb3JtYXQgdGFuZ2dhbA0KZGF0YV9iaXNuaXMkVHJhbnNhY3Rpb25fRGF0ZSA8LSBhcy5EYXRlKGRhdGFfYmlzbmlzJFRyYW5zYWN0aW9uX0RhdGUpDQoNCiMgTWVuZ2Vsb21wb2trYW4gZGF0YSBiZXJkYXNhcmthbiBidWxhbiBkYW4gbWVuanVtbGFoa2FuIFRvdGFsX1ByaWNlDQpkYXRhX2Jpc25pcyRNb250aCA8LSBmbG9vcl9kYXRlKGRhdGFfYmlzbmlzJFRyYW5zYWN0aW9uX0RhdGUsICJtb250aCIpDQpkYXRhX2dyb3VwZWQgPC0gZGF0YV9iaXNuaXMgJT4lDQogIGdyb3VwX2J5KE1vbnRoKSAlPiUNCiAgc3VtbWFyaXNlKFRvdGFsX1ByaWNlID0gc3VtKFRvdGFsX1ByaWNlKSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PSAjDQojIDIuIEJ1YXQgQXJlYSBDaGFydCAgICAgICAgIw0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PSAjDQpnZ3Bsb3QoZGF0YV9ncm91cGVkLCBhZXMoeCA9IE1vbnRoLCB5ID0gVG90YWxfUHJpY2UpKSArDQogIGdlb21fYXJlYShmaWxsID0gInNreWJsdWUiLCBhbHBoYSA9IDAuNSkgKyAgIyBBcmVhIGNoYXJ0DQogIGdlb21fbGluZShjb2xvciA9ICJTbGF0ZWJsdWUiLCBzaXplID0gMS4yKSArICAjIEdhcmlzIGRpIGF0YXMgYXJlYQ0KICBsYWJzKHRpdGxlID0gIlRvdGFsIFByaWNlIHBlciBCdWxhbiIsIA0KICAgICAgIHggPSAiQnVsYW4iLCANCiAgICAgICB5ID0gIlRvdGFsIFByaWNlIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArICAjIFRlbWEgbWluaW1hbA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiKSwgICMgSnVkdWwgdGVuZ2FoIGRhbiB0ZWJhbA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArICAjIE1lbWlyaW5na2FuIGxhYmVsIHN1bWJ1IHgNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyKSAgIyBGb3JtYXQgc3VtYnUgeSBzZWJhZ2FpIGRvbGxhcg0KYGBgDQo=