PEMROGRAMAN SAINS DATA

Midterm Exam

Veronica Maria Lucia Ferreira Xavier

Januaria Teresinha

Chricyesia Winnerlady Frexisovara Uvas

1 Mini Project: CASE STUDY E-Commerce

Di era ekonomi digital saat ini, industri E-Commerce menghasilkan volume data yang sangat besar setiap harinya. Data tersebut berasal dari berbagai platform seperti Shopee, Tokopedia, Lazada, dan TikTok Shop. Tantangan utama yang dihadapi oleh seorang Data Analyst bukanlah kelangkaan data, melainkan bagaimana cara mengumpulkan data yang tersebar dalam berbagai format (CSV, JSON, Excel, XML, TXT) dan membersihkannya agar siap dianalisis.

Dataset yang digunakan dalam studi kasus ini mencerminkan kondisi data di dunia nyata yang sering kali “kotor”—memiliki format tanggal yang tidak konsisten, adanya nilai yang hilang (missing values), penulisan teks yang tidak seragam, hingga duplikasi data. Oleh karena itu, kemampuan untuk melakukan Data Collecting, Data Handling, dan Data Cleaning menggunakan pemrograman (Python/R) menjadi kompetensi yang sangat krusial.

Studi kasus ini menggunakan dataset transaksi E-Commerce yang dikumpulkan dari 5 sumber file berbeda dengan karakteristik sebagai berikut:

  1. ecommerce.csv: Data transaksi dalam format standar CSV.

  2. ecommerce.xlsx: Data mentah yang merepresentasikan operasional harian.

  3. ecommerce.json: Data dengan struktur nested yang biasanya berasal dari API.

  4. ecommerce.txt: Data teks dengan pemisah khusus (pipe-separated).

  5. ecommerce.xml: Data berbasis tag yang sering digunakan untuk pertukaran data antar sistem.

Tujuan utama dari pengerjaan mini project ini adalah:

  1. Data Collection: Mengotomatisasi proses pembacaan dan penggabungan berbagai format file menggunakan teknik looping dan conditional logic.

  2. Data Cleaning: Melakukan standardisasi data, menangani missing values, serta memperbaiki tipe data yang tidak sesuai (misal: mengubah teks harga menjadi numerik).

  3. Business Logic: Menerapkan logika bisnis melalui conditional logic untuk mengidentifikasi transaksi bernilai tinggi dan prioritas pesanan.

  4. Insight Discovery: Menarik kesimpulan strategis mengenai platform, kategori produk, dan status transaksi yang paling dominan dalam bisnis.

1.1 SECTION A – DATA COLLECTION USING PROGRAMMING

=== MEMULAI PROSES INGESTI DATA ===

------------------------------------------------------------
File          : ecommerce.csv 
Jml Baris     : 2000 
Total Kolom   : 22 
Nama Kolom    : order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag 
Status        : Ready to merge (Base Reference)

------------------------------------------------------------
File          : ecommerce.json 
Jml Baris     : 2000 
Total Kolom   : 22 
Nama Kolom    : order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag 
Status        : Ready to merge

------------------------------------------------------------
File          : ecommerce.txt 
Jml Baris     : 2000 
Total Kolom   : 22 
Nama Kolom    : order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag 
Status        : Ready to merge

------------------------------------------------------------
File          : ecommerce.xlsx 
Jml Baris     : 2000 
Total Kolom   : 22 
Nama Kolom    : order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag 
Status        : Ready to merge

------------------------------------------------------------
File          : ecommerce.xml 
Jml Baris     : 2000 
Total Kolom   : 22 
Nama Kolom    : order_id, order_date, ship_date, platform, category, product_name, unit_price, quantity, gross_sales, campaign, voucher_code, discount_pct, discount_value, shipping_cost, net_sales, payment_method, customer_segment, region, stock_status, order_status, customer_rating, priority_flag 
Status        : Ready to merge

============================================================
 HASIL PENGGABUNGAN DATA
 TOTAL BARIS TERGABUNG : 10000 
 TOTAL KOLOM           : 23 
============================================================


Table: Preview Dataset Mentah

| order_id | order_date | ship_date  |  platform   |  category   |  product_name  | unit_price | quantity | gross_sales |   campaign    | voucher_code | discount_pct | discount_value | shipping_cost | net_sales | payment_method  | customer_segment |   region   | stock_status | order_status | customer_rating | priority_flag |  source_file  |
|:--------:|:----------:|:----------:|:-----------:|:-----------:|:--------------:|:----------:|:--------:|:-----------:|:-------------:|:------------:|:------------:|:--------------:|:-------------:|:---------:|:---------------:|:----------------:|:----------:|:------------:|:------------:|:---------------:|:-------------:|:-------------:|
| ORD00612 | 2024-04-19 | 2024/04/24 |  Tokopedia  | home living |   Table Lamp   |   188905   |    4     |   755620    |  Flash Sale   |    DISC10    |      10      |     75562      |     12000     |  680058   |    E-Wallet     |       VIP        |   Bekasi   |   Preorder   |  completed   |        5        |       Y       | ecommerce.csv |
| ORD00112 | 2024/01/24 | 29/01/2024 | TikTok Shop | Electronics |   Power Bank   |  1476873   |    1     |   1476873   |  Normal Day   |     NONE     |      0       |       0        |     18000     |  1476873  |       cod       |    Returning     |  Makassar  |   In Stock   |  completed   |        5        |       N       | ecommerce.csv |
| ORD01186 | 2024-06-12 | 06-19-2024 |  Tokopedia  |   Fashion   |  Women Dress   |   231072   |    2     |   462144    | Mega Campaign |    DISC20    |      20      |     92429      |     15000     |  369715   | Virtual Account |    Returning     |  Surabaya  |   In Stock   |  delivered   |        3        |      Yes      | ecommerce.csv |
| ORD01511 | 2024/08/07 | 08-14-2024 |  Tokopedia  | home living | Vacuum Cleaner |   512063   |    3     |   1536189   |  Flash Sale   |    DISC10    |      10      |     153619     |       0       |  1382570  |  Transfer Bank  |       New        | Yogyakarta |   In Stock   |  DELIVERED   |        4        |      No       | ecommerce.csv |
| ORD00772 | 2024-12-08 |            |  Tokopedia  |   Beauty    |  Body Lotion   |   221586   |    2     |   443172    |  Payday Sale  |    DISC15    |      15      |   Rp 66.476    |       0       |  376696   |       COD       |    Returning     |  Surabaya  |   In Stock   |  DELIVERED   |        5        |    normal     | ecommerce.csv |
| ORD00880 | 2024/04/06 |            |   blibli    |   Beauty    |    Lip Tint    |   297973   |    8     |   2383784   |  Normal Day   |     NONE     |      0       |       0        |     12000     |     0     |   credit card   |       VIP        |  Makassar  |  Low Stock   |  Cancelled   |       NA        |      Yes      | ecommerce.csv |
| ORD00592 | 03-15-2024 |            |   Blibli    |   Fashion   |    Sneakers    |   102844   |    8     |   822752    | Mega Campaign |    DISC20    |      20      |     164550     |     25000     |     0     |    E-Wallet     |    Returning     |   Bekasi   |   In Stock   |    CANCEL    |       NA        |      Yes      | ecommerce.csv |
| ORD01367 | 07-24-2024 | 2024-07-25 |   Blibli    |   Sports    |  Dumbbell 5kg  |   297954   |    10    |   2979540   |   Clearance   |   CLEAR30    |      30      |     893862     |     20000     |  2085678  |       COD       |       New        | Yogyakarta |   In Stock   |  delivered   |        5        |       N       | ecommerce.csv |
| ORD01178 | 11-14-2024 | 2024-11-16 |   Blibli    |   Sports    |  Dumbbell 5kg  |   710898   |    2     |   1421796   |  Payday Sale  |    DISC15    |      15      |     213269     |     18000     |  1208527  | Virtual Account |       VIP        |  Bandung   |   In Stock   |  delivered   |        5        |   PRIORITY    | ecommerce.csv |
| ORD00276 | 2024/06/15 | 17/06/2024 |   Lazada    |   Sports    | Cycling Gloves |   526279   |    4     |   2105116   |  Payday Sale  |    DISC15    |      15      |     315767     |     20000     |  1789349  |    E-Wallet     |    Returning     |  Bandung   |   In Stock   |  delivered   |        3        |    normal     | ecommerce.csv |

1.2 SECTION B – DATA HANDLING

=== ANALISIS KONDISI DATASET ===
1. Dimensi Dataset:
   - Total Baris : 10000 
   - Total Kolom : 23 
2. Tipe Data Setiap Kolom:
            Kolom      Tipe
         order_id character
       order_date character
        ship_date character
         platform character
         category character
     product_name character
       unit_price character
         quantity character
      gross_sales character
         campaign character
     voucher_code character
     discount_pct character
   discount_value character
    shipping_cost character
        net_sales character
   payment_method character
 customer_segment character
           region character
     stock_status character
     order_status character
  customer_rating character
    priority_flag character
      source_file character
3. Identifikasi Missing Values per Kolom:
      ship_date    voucher_code    discount_pct  payment_method customer_rating 
           1000             245             345             175            2030 
  priority_flag 
            940 

4. Identifikasi Baris Duplikat:
   - Jumlah baris yang duplikat: 45 baris
5. Ringkasan Masalah Kualitas Data:
   a. Tipe Data Tidak Sesuai: Kolom angka (unit_price, quantity, net_sales) masih bertipe character.
   b. Missing Values: Terdapat nilai kosong pada kolom-kolom tertentu (seperti customer_rating).
   c. Baris Duplikat: Ditemukan 45 baris yang identik.
   d. Inkonsistensi Format: Format tanggal dan penulisan teks (kapitalisasi) belum seragam.

1.3 SECTION C – DATA CLEANING

=== MEMULAI PROSES PEMBERSIHAN DATA (VERSI FINAL) ===
Proses pembersihan selesai dengan sukses.


Table: Dataset Bersih dan Terstruktur (Section C)

| order_id | order_date | ship_date  |  platform   |  category   |  product_name  | unit_price | quantity | gross_sales |   campaign    | voucher_code | discount_pct | discount_value | shipping_cost | net_sales | payment_method  | customer_segment |   region   | stock_status | order_status | customer_rating | priority_flag |  source_file  |
|:--------:|:----------:|:----------:|:-----------:|:-----------:|:--------------:|:----------:|:--------:|:-----------:|:-------------:|:------------:|:------------:|:--------------:|:-------------:|:---------:|:---------------:|:----------------:|:----------:|:------------:|:------------:|:---------------:|:-------------:|:-------------:|
| ORD00612 | 2024-04-19 | 2024/04/24 |  Tokopedia  | Home Living |   Table Lamp   |   188905   |    4     |   755620    |  Flash Sale   |    DISC10    |      10      |   75562.000    |     12000     |  680058   |    E-Wallet     |       VIP        |   Bekasi   |   Preorder   |  Completed   |        5        |       Y       | ecommerce.csv |
| ORD00112 | 2024/01/24 | 29/01/2024 | Tiktok Shop | Electronics |   Power Bank   |  1476873   |    1     |   1476873   |  Normal Day   |     NONE     |      0       |     0.000      |     18000     |  1476873  |       COD       |    Returning     |  Makassar  |   In Stock   |  Completed   |        5        |       N       | ecommerce.csv |
| ORD01186 | 2024-06-12 | 06-19-2024 |  Tokopedia  |   Fashion   |  Women Dress   |   231072   |    2     |   462144    | Mega Campaign |    DISC20    |      20      |   92429.000    |     15000     |  369715   | Virtual Account |    Returning     |  Surabaya  |   In Stock   |  Completed   |        3        |      Yes      | ecommerce.csv |
| ORD01511 | 2024/08/07 | 08-14-2024 |  Tokopedia  | Home Living | Vacuum Cleaner |   512063   |    3     |   1536189   |  Flash Sale   |    DISC10    |      10      |   153619.000   |       0       |  1382570  |  Transfer Bank  |       New        | Yogyakarta |   In Stock   |  Completed   |        4        |      No       | ecommerce.csv |
| ORD00772 | 2024-12-08 |            |  Tokopedia  |   Beauty    |  Body Lotion   |   221586   |    2     |   443172    |  Payday Sale  |    DISC15    |      15      |     66.476     |       0       |  376696   |       COD       |    Returning     |  Surabaya  |   In Stock   |  Completed   |        5        |    normal     | ecommerce.csv |
| ORD00880 | 2024/04/06 |            |   Blibli    |   Beauty    |    Lip Tint    |   297973   |    8     |   2383784   |  Normal Day   |     NONE     |      0       |     0.000      |     12000     |     0     |   Credit Card   |       VIP        |  Makassar  |  Low Stock   |  Cancelled   |        3        |      Yes      | ecommerce.csv |
| ORD00592 | 03-15-2024 |            |   Blibli    |   Fashion   |    Sneakers    |   102844   |    8     |   822752    | Mega Campaign |    DISC20    |      20      |   164550.000   |     25000     |     0     |    E-Wallet     |    Returning     |   Bekasi   |   In Stock   |  Cancelled   |        3        |      Yes      | ecommerce.csv |
| ORD01367 | 07-24-2024 | 2024-07-25 |   Blibli    |   Sports    |  Dumbbell 5kg  |   297954   |    10    |   2979540   |   Clearance   |   CLEAR30    |      30      |   893862.000   |     20000     |  2085678  |       COD       |       New        | Yogyakarta |   In Stock   |  Completed   |        5        |       N       | ecommerce.csv |
| ORD01178 | 11-14-2024 | 2024-11-16 |   Blibli    |   Sports    |  Dumbbell 5kg  |   710898   |    2     |   1421796   |  Payday Sale  |    DISC15    |      15      |   213269.000   |     18000     |  1208527  | Virtual Account |       VIP        |  Bandung   |   In Stock   |  Completed   |        5        |   PRIORITY    | ecommerce.csv |
| ORD00276 | 2024/06/15 | 17/06/2024 |   Lazada    |   Sports    | Cycling Gloves |   526279   |    4     |   2105116   |  Payday Sale  |    DISC15    |      15      |   315767.000   |     20000     |  1789349  |    E-Wallet     |    Returning     |  Bandung   |   In Stock   |  Completed   |        3        |    normal     | ecommerce.csv |

1.4 SECTION D – CONDITIONAL LOGIC


=== MENERAPKAN LOGIKA BISNIS (SECTION D) ===
Berhasil menambahkan kolom: is_high_value, order_priority, valid_transaction.


Table: Hasil Implementasi Conditional Logic (Section D)

| order_id | net_sales | order_status | is_high_value | order_priority | valid_transaction |
|:--------:|:---------:|:------------:|:-------------:|:--------------:|:-----------------:|
| ORD00612 |  680058   |  Completed   |      No       |     Medium     |       Valid       |
| ORD00112 |  1476873  |  Completed   |      Yes      |      High      |       Valid       |
| ORD01186 |  369715   |  Completed   |      No       |      Low       |       Valid       |
| ORD01511 |  1382570  |  Completed   |      Yes      |      High      |       Valid       |
| ORD00772 |  376696   |  Completed   |      No       |      Low       |       Valid       |
| ORD00880 |     0     |  Cancelled   |      No       |      Low       |      Invalid      |
| ORD00592 |     0     |  Cancelled   |      No       |      Low       |      Invalid      |
| ORD01367 |  2085678  |  Completed   |      Yes      |      High      |       Valid       |
| ORD01178 |  1208527  |  Completed   |      Yes      |      High      |       Valid       |
| ORD00276 |  1789349  |  Completed   |      Yes      |      High      |       Valid       |

1.5 SECTION E – ANALYTICAL THINKING

Dominasi Platform
platform Total
Shopee 2080
Tiktok Shop 2030
Blibli 2020
Lazada 1940
Tokopedia 1930
Frekuensi Kategori
category Frekuensi
Fashion 2100
Sports 2070
Beauty 1940
Home Living 1910
Electronics 1820
Home_living 160
Status Transaksi
order_status Jumlah
Completed 7900
Cancelled 595
Shipped 510
Returned 375
On Delivery 240

2 Web Scraping & Data Programming Process

2.1 SECTION A – DATA COLLECTION USING PROGRAMMING

2.1.1 1. Countries of the World (Static Page)

=== SCRAPING: COUNTRIES OF THE WORLD ===
Jumlah data diambil: 250 
Top 10 Negara Berdasarkan Populasi
country_name capital population
China Beijing 1330044000
India New Delhi 1173108018
United States Washington 310232863
Indonesia Jakarta 242968342
Brazil Brasília 201103330
Pakistan Islamabad 184404791
Bangladesh Dhaka 156118464
Nigeria Abuja 154000000
Russia Moscow 140702000
Japan Tokyo 127288000

2.1.2 Hockey Teams (Pagination & Form)

Top 10 Tim Hockey (Berdasarkan Kemenangan Terbanyak)
team_name year wins
Detroit Red Wings 1995 62
Detroit Red Wings 2005 58
Pittsburgh Penguins 1992 56
Detroit Red Wings 2007 54
Washington Capitals 2009 54
Vancouver Canucks 2010 54
Dallas Stars 2005 53
Buffalo Sabres 2006 53
Boston Bruins 2008 53
San Jose Sharks 2008 53

2.2 SECTION B – DATA HANDLING

=== ANALISIS STRUKTUR DATA HASIL SCRAPING ===
================================================== 
DATASET: Countries of the World 
================================================== 
1. Struktur Dasar:
   - Jumlah Baris : 250 
   - Jumlah Kolom : 3 
   - Nama Kolom   : country_name, capital, population 

2. Tipe Data Setiap Kolom:
        Kolom      Tipe
 country_name character
      capital character
   population   numeric

3. Pemeriksaan Kualitas:
   - Missing Values per Kolom:
country_name      capital   population 
           0            0            0 
   - Jumlah Baris Duplikat: 0 baris
4. Isu Kualitas Data yang Ditemukan (Countries):
   a. Tipe Data: Kolom 'population' dan 'area' mungkin masih terbaca sebagai character/teks karena adanya koma/titik.
   b. Missing Values: Potensi adanya sel kosong pada data geografi yang tidak tercatat lengkap.
================================================== 
DATASET: Hockey Teams (Pagination & Form) 
================================================== 
1. Struktur Dasar:
   - Jumlah Baris : 582 
   - Jumlah Kolom : 3 
   - Nama Kolom   : team_name, year, wins 

2. Tipe Data Setiap Kolom:
     Kolom      Tipe
 team_name character
      year   numeric
      wins   numeric

3. Pemeriksaan Kualitas:
   - Missing Values per Kolom:
team_name      year      wins 
        0         0         0 
   - Jumlah Baris Duplikat: 0 baris
4. Isu Kualitas Data yang Ditemukan (Hockey):
   a. Duplikasi: Potensi baris ganda jika proses pagination mengambil data yang sama secara tidak sengaja.
   b. Konsistensi: Kolom 'wins' dan 'points' perlu dikonversi ke numerik agar bisa dilakukan perhitungan statistik.

2.3 SECTION C – DATA CLEANING

SECTION C: DATA CLEANING

[1] Standardisasi teks...
[2] Konversi ke numeric...
[3] Menangani missing values...
[4] Validasi data...
[5] Menghapus duplicate...

Proses pembersihan selesai.

Dataset hasil cleaning:

Countries:


| country_name  |  capital   |  population  |
|:-------------:|:----------:|:------------:|
|     China     |  Beijing   | 1.330044e+09 |
|     India     | New Delhi  | 1.173108e+09 |
| United States | Washington | 3.102329e+08 |
|   Indonesia   |  Jakarta   | 2.429683e+08 |
|    Brazil     |  Brasília  | 2.011033e+08 |
|   Pakistan    | Islamabad  | 1.844048e+08 |
|  Bangladesh   |   Dhaka    | 1.561185e+08 |
|    Nigeria    |   Abuja    | 1.540800e+00 |
|    Russia     |   Moscow   | 1.407020e+08 |
|     Japan     |   Tokyo    | 1.272880e+08 |

Hockey Teams:


|      team_name      | year | wins |
|:-------------------:|:----:|:----:|
|  Detroit Red Wings  | 1995 |  62  |
|  Detroit Red Wings  | 2005 |  58  |
| Pittsburgh Penguins | 1992 |  56  |
|  Detroit Red Wings  | 2007 |  54  |
| Washington Capitals | 2009 |  54  |
|  Vancouver Canucks  | 2010 |  54  |
|    Dallas Stars     | 2005 |  53  |
|   Buffalo Sabres    | 2006 |  53  |
|    Boston Bruins    | 2008 |  53  |
|   San Jose Sharks   | 2008 |  53  |

2.4 SECTION D – CONDITIONAL LOGIC


SECTION D: CONDITIONAL LOGIC

[1] Handling missing elements...
[2] Determining data status...

Kolom 'data_status' berhasil ditambahkan.

Preview Countries:


| country_name  |  capital   |  population  | data_status |
|:-------------:|:----------:|:------------:|:-----------:|
|     China     |  Beijing   | 1.330044e+09 | Incomplete  |
|     India     | New Delhi  | 1.173108e+09 | Incomplete  |
| United States | Washington | 3.102329e+08 | Incomplete  |
|   Indonesia   |  Jakarta   | 2.429683e+08 | Incomplete  |
|    Brazil     |  Brasília  | 2.011033e+08 | Incomplete  |
|   Pakistan    | Islamabad  | 1.844048e+08 | Incomplete  |
|  Bangladesh   |   Dhaka    | 1.561185e+08 | Incomplete  |
|    Nigeria    |   Abuja    | 1.540800e+00 | Incomplete  |
|    Russia     |   Moscow   | 1.407020e+08 | Incomplete  |
|     Japan     |   Tokyo    | 1.272880e+08 | Incomplete  |

Preview Hockey Teams:


|      team_name      | year | wins | data_status |
|:-------------------:|:----:|:----:|:-----------:|
|  Detroit Red Wings  | 1995 |  62  | Incomplete  |
|  Detroit Red Wings  | 2005 |  58  | Incomplete  |
| Pittsburgh Penguins | 1992 |  56  | Incomplete  |
|  Detroit Red Wings  | 2007 |  54  | Incomplete  |
| Washington Capitals | 2009 |  54  | Incomplete  |
|  Vancouver Canucks  | 2010 |  54  | Incomplete  |
|    Dallas Stars     | 2005 |  53  | Incomplete  |
|   Buffalo Sabres    | 2006 |  53  | Incomplete  |
|    Boston Bruins    | 2008 |  53  | Incomplete  |
|   San Jose Sharks   | 2008 |  53  | Incomplete  |

2.5 SECTION E – ANALYTICAL THINKING

1. Website mana paling mudah di-scrape?

Berdasarkan dataset yang digunakan, yaitu Countries of the World dan Hockey Teams, terdapat perbedaan tingkat kemudahan dalam proses scraping.

Website Paling Mudah di-Scrape: Countries of the World

Alasan : Website ini memiliki struktur Statis. Seluruh data tersedia dalam satu dokumen HTML tunggal dengan penamaan class yang konsisten, sehingga pengambilan data dapat dilakukan secara efisien menggunakan fungsi dasar dari library rvest tanpa memerlukan logika perulangan yang kompleks.

2. Website mana paling sulit?

Website Paling Sulit di-Scrape: Hockey Teams

Alasan : Website ini mengimplementasikan mekanisme Pagination (pembagian data per halaman). Tantangan utama meliputi perlunya pengelolaan URL yang dinamis, penanganan delay antar permintaan (request), dan risiko inkonsistensi data antar halaman yang memerlukan pembersihan lebih intensif pada tahap berikutnya.

3. Perbedaan pendekatan:

Beberapa metode umum dalam penyajian data di web adalah sebagai berikut:

  1. Static: Data disajikan langsung di dalam struktur HTML saat halaman pertama kali dimuat, sehingga dapat diakses tanpa interaksi tambahan.

  2. Pagination: Data dibagi ke dalam beberapa halaman yang terpisah, sehingga pengguna perlu berpindah halaman untuk melihat keseluruhan data.

  3. AJAX: Data dimuat secara asinkron menggunakan permintaan tambahan ke server tanpa perlu memuat ulang seluruh halaman.

  4. Iframe: Data ditampilkan melalui elemen bingkai yang mengambil konten dari sumber atau halaman lain.

  • Tabel berikut menjelaskan perbedaan teknis dari berbagai metode penyajian data di web:
Pendekatan Mekanisme Penyajian Data Tantangan Scraping
Static Data dimuat langsung dalam struktur HTML saat halaman pertama kali diakses. Relatif rendah; cukup menggunakan pemilih CSS atau XPath standar.
Pagination Data dibagi ke dalam beberapa sub-halaman untuk optimasi beban server. Membutuhkan perulangan (looping) dan manajemen URL yang sistematis.
AJAX Data dimuat secara asinkron tanpa memperbarui keseluruhan halaman. Memerlukan inspeksi pada Network Tab untuk menemukan sumber API asli.
Iframe Data ditampilkan di dalam bingkai (frame) yang berasal dari URL eksternal. Harus mengekstraksi URL sumber asli di dalam tag <iframe> terlebih dahulu.
LS0tDQp0aXRsZTogIlBFTVJPR1JBTUFOIFNBSU5TIERBVEEiICAgICAgICMgTWFpbiB0aXRsZSBvZiB0aGUgZG9jdW1lbnQNCnN1YnRpdGxlOiAiTWlkdGVybSBFeGFtIiAgIyBTdWJ0aXRsZSBvciB0b3BpYyBmb3Igd2VlayA0DQphdXRob3I6IA0KLSAiVmVyb25pY2EgTSBMIEYgWGF2aWVyIg0KLSAiSmFudWFyaWEgVGVyZXNpbmhhIg0KLSAiQ2hyaWN5ZXNpYSBXaW5uZXJsYWR5IEZyZXhpc292YXJhIFV2YXMiDQoNCmRhdGU6ICAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclQiAlZCwgJVknKWAiICMgQXV0byBkaXNwbGF5cyB0aGUgY3VycmVudCBkYXRlDQpvdXRwdXQ6ICAgICAgICAgICAgICAgICAgICAgICAgICMgT3V0cHV0IHNlY3Rpb24gZGVmaW5lcyB0aGUgZm9ybWF0IGFuZCBsYXlvdXQgDQogIHJtZGZvcm1hdHM6OnJlYWR0aGVkb3duOiAgICAgICMgaHR0cHM6Ly9naXRodWIuY29tL2p1YmEvcm1kZm9ybWF0cw0KICAgIHNlbGZfY29udGFpbmVkOiB0cnVlICAgICAgICAjIEVtYmVkcyBhbGwgcmVzb3VyY2VzIChDU1MsIEpTLCBpbWFnZXMpIA0KICAgIHRodW1ibmFpbHM6IHRydWUgICAgICAgICAgICAjIERpc3BsYXlzIGltYWdlIHRodW1ibmFpbHMgaW4gdGhlIGRvYw0KICAgIGxpZ2h0Ym94OiB0cnVlICAgICAgICAgICAgICAjIEVuYWJsZXMgY2xpY2sgdG8gZW5sYXJnZSBpbWFnZXMNCiAgICBnYWxsZXJ5OiB0cnVlICAgICAgICAgICAgICAgIyBHcm91cHMgaW1hZ2VzIGludG8gYW4gaW50ZXJhY3RpdmUgZ2FsbGVyeQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZSAgICAgICAjIEF1dG9tYXRpY2FsbHkgbnVtYmVycyBhbGwgc2VjdGlvbnMNCiAgICBsaWJfZGlyOiBsaWJzICAgICAgICAgICAgICAgIyBEaXJlY3Rvcnkgd2hlcmUgSmF2YVNjcmlwdC9DU1MgbGlicmFyaWVzDQogICAgZGZfcHJpbnQ6ICJwYWdlZCIgICAgICAgICAgICMgRGlzcGxheXMgZGF0YSBmcmFtZXMgYXMgaW50ZXJhY3RpdmUgcGFnZWQgDQogICAgY29kZV9mb2xkaW5nOiAic2hvdyIgICAgICAgICMgQWxsb3dzIGZvbGRpbmcvdW5mb2xkaW5nIFIgY29kZSBibG9ja3MgDQogICAgY29kZV9kb3dubG9hZDogeWVzICAgICAgICAgICMgQWRkcyBhIGJ1dHRvbiB0byBkb3dubG9hZCBhbGwgUiBjb2RlDQogICAgY3NzOiBzdHlsZWUuY3NzDQotLS0NCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQ0KDQpsaWJyYXJ5KGh0bWx0b29scykNCg0KIyBGdW5nc2kgdW50dWsgbWVtYnVhdCBzYXR1IGthcnR1IHByb2ZpbA0KYnVhdF9rYXJ0dSA8LSBmdW5jdGlvbihuYW1hLCBmaWxlX2ZvdG8pIHsNCiAgdGFncyRkaXYoDQogICAgc3R5bGUgPSAiDQogICAgICBib3JkZXI6IDFweCBzb2xpZCAjZGRkOw0KICAgICAgYm9yZGVyLXJhZGl1czogMTVweDsNCiAgICAgIHBhZGRpbmc6IDE1cHg7DQogICAgICBtYXJnaW46IDEwcHg7DQogICAgICB3aWR0aDogMjUwcHg7DQogICAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogICAgICBib3gtc2hhZG93OiAwIDRweCA4cHggcmdiYSgwLDAsMCwwLjEpOw0KICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrOw0KICAgICAgYmFja2dyb3VuZC1jb2xvcjogd2hpdGU7DQogICAgIiwNCiAgICB0YWdzJGltZygNCiAgICAgIHNyYyA9IGZpbGVfZm90bywNCiAgICAgIHN0eWxlID0gIndpZHRoOiAxMDAlOyBoZWlnaHQ6IDMwMHB4OyBvYmplY3QtZml0OiBjb3ZlcjsgYm9yZGVyLXJhZGl1czogMTBweDsiDQogICAgKSwNCiAgICB0YWdzJGgzKG5hbWEsIHN0eWxlID0gImZvbnQtZmFtaWx5OiBBcmlhbDsgY29sb3I6ICMzMzM7IG1hcmdpbi10b3A6IDE1cHg7IiksDQogICAgdGFncyRwKCIiLCBzdHlsZSA9ICJjb2xvcjogIzc3NzsgZm9udC1zdHlsZTogaXRhbGljOyIpDQogICkNCn0NCg0KIyBHYWJ1bmdrYW4gc2VtdWEga2FydHUga2UgZGFsYW0gc2F0dSBjb250YWluZXINCnRhZ0xpc3QoDQogIHRhZ3MkZGl2KA0KICAgIHN0eWxlID0gImRpc3BsYXk6IGZsZXg7IGp1c3RpZnktY29udGVudDogY2VudGVyOyBmbGV4LXdyYXA6IHdyYXA7IGJhY2tncm91bmQtY29sb3I6ICNmNWY1ZjU7IHBhZGRpbmc6IDIwcHg7IiwNCiAgICBidWF0X2thcnR1KCJWZXJvbmljYSBNYXJpYSBMdWNpYSBGZXJyZWlyYSBYYXZpZXIiLCAidmVfMS5qcGciKSwNCiAgICBidWF0X2thcnR1KCJKYW51YXJpYSBUZXJlc2luaGEiLCAiSmFuYS5qcGVnIiksDQogICAgYnVhdF9rYXJ0dSgiQ2hyaWN5ZXNpYSBXaW5uZXJsYWR5IEZyZXhpc292YXJhIFV2YXMiLCAid2l3aW4uanBlZyIpDQogICkNCikNCmBgYA0KDQojIE1pbmkgUHJvamVjdDogQ0FTRSBTVFVEWSBFLUNvbW1lcmNlDQoNCkRpIGVyYSBla29ub21pIGRpZ2l0YWwgc2FhdCBpbmksIGluZHVzdHJpIEUtQ29tbWVyY2UgbWVuZ2hhc2lsa2FuIHZvbHVtZSBkYXRhIHlhbmcgc2FuZ2F0IGJlc2FyIHNldGlhcCBoYXJpbnlhLiBEYXRhIHRlcnNlYnV0IGJlcmFzYWwgZGFyaSBiZXJiYWdhaSBwbGF0Zm9ybSBzZXBlcnRpIFNob3BlZSwgVG9rb3BlZGlhLCBMYXphZGEsIGRhbiBUaWtUb2sgU2hvcC4gVGFudGFuZ2FuIHV0YW1hIHlhbmcgZGloYWRhcGkgb2xlaCBzZW9yYW5nIERhdGEgQW5hbHlzdCBidWthbmxhaCBrZWxhbmdrYWFuIGRhdGEsIG1lbGFpbmthbiBiYWdhaW1hbmEgY2FyYSBtZW5ndW1wdWxrYW4gZGF0YSB5YW5nIHRlcnNlYmFyIGRhbGFtIGJlcmJhZ2FpIGZvcm1hdCAoQ1NWLCBKU09OLCBFeGNlbCwgWE1MLCBUWFQpIGRhbiBtZW1iZXJzaWhrYW5ueWEgYWdhciBzaWFwIGRpYW5hbGlzaXMuDQoNCkRhdGFzZXQgeWFuZyBkaWd1bmFrYW4gZGFsYW0gc3R1ZGkga2FzdXMgaW5pIG1lbmNlcm1pbmthbiBrb25kaXNpIGRhdGEgZGkgZHVuaWEgbnlhdGEgeWFuZyBzZXJpbmcga2FsaSAia290b3Ii4oCUbWVtaWxpa2kgZm9ybWF0IHRhbmdnYWwgeWFuZyB0aWRhayBrb25zaXN0ZW4sIGFkYW55YSBuaWxhaSB5YW5nIGhpbGFuZyAobWlzc2luZyB2YWx1ZXMpLCBwZW51bGlzYW4gdGVrcyB5YW5nIHRpZGFrIHNlcmFnYW0sIGhpbmdnYSBkdXBsaWthc2kgZGF0YS4gT2xlaCBrYXJlbmEgaXR1LCBrZW1hbXB1YW4gdW50dWsgbWVsYWt1a2FuIERhdGEgQ29sbGVjdGluZywgRGF0YSBIYW5kbGluZywgZGFuIERhdGEgQ2xlYW5pbmcgbWVuZ2d1bmFrYW4gcGVtcm9ncmFtYW4gKFB5dGhvbi9SKSBtZW5qYWRpIGtvbXBldGVuc2kgeWFuZyBzYW5nYXQga3J1c2lhbC4NCg0KU3R1ZGkga2FzdXMgaW5pIG1lbmdndW5ha2FuIGRhdGFzZXQgdHJhbnNha3NpIEUtQ29tbWVyY2UgeWFuZyBkaWt1bXB1bGthbiBkYXJpIDUgc3VtYmVyIGZpbGUgYmVyYmVkYSBkZW5nYW4ga2FyYWt0ZXJpc3RpayBzZWJhZ2FpIGJlcmlrdXQ6DQoNCjEuICBlY29tbWVyY2UuY3N2OiBEYXRhIHRyYW5zYWtzaSBkYWxhbSBmb3JtYXQgc3RhbmRhciBDU1YuDQoNCjIuICBlY29tbWVyY2UueGxzeDogRGF0YSBtZW50YWggeWFuZyBtZXJlcHJlc2VudGFzaWthbiBvcGVyYXNpb25hbCBoYXJpYW4uDQoNCjMuICBlY29tbWVyY2UuanNvbjogRGF0YSBkZW5nYW4gc3RydWt0dXIgbmVzdGVkIHlhbmcgYmlhc2FueWEgYmVyYXNhbCBkYXJpIEFQSS4NCg0KNC4gIGVjb21tZXJjZS50eHQ6IERhdGEgdGVrcyBkZW5nYW4gcGVtaXNhaCBraHVzdXMgKHBpcGUtc2VwYXJhdGVkKS4NCg0KNS4gIGVjb21tZXJjZS54bWw6IERhdGEgYmVyYmFzaXMgdGFnIHlhbmcgc2VyaW5nIGRpZ3VuYWthbiB1bnR1ayBwZXJ0dWthcmFuIGRhdGEgYW50YXIgc2lzdGVtLg0KDQpUdWp1YW4gdXRhbWEgZGFyaSBwZW5nZXJqYWFuICptaW5pIHByb2plY3QqIGluaSBhZGFsYWg6DQoNCjEuICAqKkRhdGEgQ29sbGVjdGlvbioqOiBNZW5nb3RvbWF0aXNhc2kgcHJvc2VzIHBlbWJhY2FhbiBkYW4gcGVuZ2dhYnVuZ2FuIGJlcmJhZ2FpIGZvcm1hdCBmaWxlIG1lbmdndW5ha2FuIHRla25payAqbG9vcGluZyogZGFuICpjb25kaXRpb25hbCBsb2dpYyouDQoNCjIuICAqKkRhdGEgQ2xlYW5pbmcqKjogTWVsYWt1a2FuIHN0YW5kYXJkaXNhc2kgZGF0YSwgbWVuYW5nYW5pICptaXNzaW5nIHZhbHVlcyosIHNlcnRhIG1lbXBlcmJhaWtpIHRpcGUgZGF0YSB5YW5nIHRpZGFrIHNlc3VhaSAobWlzYWw6IG1lbmd1YmFoIHRla3MgaGFyZ2EgbWVuamFkaSBudW1lcmlrKS4NCg0KMy4gICoqQnVzaW5lc3MgTG9naWMqKjogTWVuZXJhcGthbiBsb2dpa2EgYmlzbmlzIG1lbGFsdWkgKmNvbmRpdGlvbmFsIGxvZ2ljKiB1bnR1ayBtZW5naWRlbnRpZmlrYXNpIHRyYW5zYWtzaSBiZXJuaWxhaSB0aW5nZ2kgZGFuIHByaW9yaXRhcyBwZXNhbmFuLg0KDQo0LiAgKipJbnNpZ2h0IERpc2NvdmVyeSoqOiBNZW5hcmlrIGtlc2ltcHVsYW4gc3RyYXRlZ2lzIG1lbmdlbmFpIHBsYXRmb3JtLCBrYXRlZ29yaSBwcm9kdWssIGRhbiBzdGF0dXMgdHJhbnNha3NpIHlhbmcgcGFsaW5nIGRvbWluYW4gZGFsYW0gYmlzbmlzLg0KDQojIyBTRUNUSU9OIEEg4oCTIERBVEEgQ09MTEVDVElPTiBVU0lORyBQUk9HUkFNTUlORw0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0UsY29tbWVudD0iIixlY2hvPUZBTFNFfQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAgICAgICAgICAgICAgICAgU0VDVElPTiBBOiBEQVRBIElOR0VTVElPTg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoanNvbmxpdGUpDQpsaWJyYXJ5KHhtbDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoRFQpDQoNCg0KIyBEYWZ0YXIgZmlsZQ0KZmlsZV9saXN0IDwtIGMoImVjb21tZXJjZS5jc3YiLCAiZWNvbW1lcmNlLmpzb24iLCAiZWNvbW1lcmNlLnR4dCIsIA0KICAgICAgICAgICAgICAgImVjb21tZXJjZS54bHN4IiwgImVjb21tZXJjZS54bWwiKQ0KDQptYWluX2RhdGFzZXRzIDwtIGxpc3QoKQ0KcmVmZXJlbmNlX2NvbHMgPC0gTlVMTA0KDQpjYXQoIj09PSBNRU1VTEFJIFBST1NFUyBJTkdFU1RJIERBVEEgPT09XG4iKQ0KDQpmb3IgKGZpbGVfbmFtZSBpbiBmaWxlX2xpc3QpIHsNCiAgZXh0IDwtIHRvb2xzOjpmaWxlX2V4dChmaWxlX25hbWUpDQogIA0KICBkZiA8LSB0cnlDYXRjaCh7DQogICAgaWYgKGV4dCA9PSAiY3N2Iikgew0KICAgICAgcmVhZC5jc3YoZmlsZV9uYW1lLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpDQogICAgfSBlbHNlIGlmIChleHQgPT0gImpzb24iKSB7DQogICAgICBmcm9tSlNPTihmaWxlX25hbWUpDQogICAgfSBlbHNlIGlmIChleHQgPT0gInR4dCIpIHsNCiAgICAgIHJlYWQudGFibGUoZmlsZV9uYW1lLCBoZWFkZXIgPSBUUlVFLCBzZXAgPSAifCIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCiAgICB9IGVsc2UgaWYgKGV4dCA9PSAieGxzeCIpIHsNCiAgICAgIHJlYWRfZXhjZWwoZmlsZV9uYW1lKQ0KICAgIH0gZWxzZSBpZiAoZXh0ID09ICJ4bWwiKSB7DQogICAgICB4bWxfZGF0YSA8LSByZWFkX3htbChmaWxlX25hbWUpDQogICAgICByZWNvcmRzIDwtIHhtbF9maW5kX2FsbCh4bWxfZGF0YSwgIi4vL1JlY29yZCIpDQogICAgICBhcy5kYXRhLmZyYW1lKGRvLmNhbGwocmJpbmQsIGxhcHBseShyZWNvcmRzLCBmdW5jdGlvbih4KSB7DQogICAgICAgIG5vZGVzIDwtIHhtbF9jaGlsZHJlbih4KQ0KICAgICAgICByZXMgPC0gYXMubGlzdCh4bWxfdGV4dChub2RlcykpDQogICAgICAgIG5hbWVzKHJlcykgPC0geG1sX25hbWUobm9kZXMpDQogICAgICAgIHJldHVybihyZXMpDQogICAgICB9KSkpDQogICAgfQ0KICB9LCBlcnJvciA9IGZ1bmN0aW9uKGUpIHsNCiAgICBtZXNzYWdlKHBhc3RlKCJHYWdhbCBtZW1iYWNhIGZpbGU6IiwgZmlsZV9uYW1lKSkNCiAgICByZXR1cm4oTlVMTCkNCiAgfSkNCg0KICBpZiAoIWlzLm51bGwoZGYpKSB7DQogICAgIyBUYW1iYWhrYW4ga29sb20gaWRlbnRpdGFzIHN1bWJlciBmaWxlDQogICAgZGYgPC0gZGYgJT4lIG11dGF0ZShzb3VyY2VfZmlsZSA9IGZpbGVfbmFtZSkNCiAgICANCiAgICAjIEFtYmlsIG5hbWEga29sb20gYXNsaSB1bnR1ayBkaXRhbXBpbGthbiBkYW4gZGljZWsNCiAgICBjX25hbWVzX29yaWdpbmFsIDwtIHNldGRpZmYoY29sbmFtZXMoZGYpLCAic291cmNlX2ZpbGUiKQ0KICAgIA0KICAgIGNhdCgiXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiIpDQogICAgY2F0KCJGaWxlICAgICAgICAgIDoiLCBmaWxlX25hbWUsICJcbiIpDQogICAgY2F0KCJKbWwgQmFyaXMgICAgIDoiLCBucm93KGRmKSwgIlxuIikNCiAgICBjYXQoIlRvdGFsIEtvbG9tICAgOiIsIGxlbmd0aChjX25hbWVzX29yaWdpbmFsKSwgIlxuIikNCiAgICAjIE1FTkFNUElMS0FOIE5BTUEgS09MT00NCiAgICBjYXQoIk5hbWEgS29sb20gICAgOiIsIHBhc3RlKGNfbmFtZXNfb3JpZ2luYWwsIGNvbGxhcHNlID0gIiwgIiksICJcbiIpDQogICAgDQogICAgIyBMb2dpa2EgSUYtRUxTRSB1bnR1ayBDZWsgU3RydWt0dXINCiAgICBpZiAoaXMubnVsbChyZWZlcmVuY2VfY29scykpIHsNCiAgICAgIHJlZmVyZW5jZV9jb2xzIDwtIHNvcnQoY19uYW1lc19vcmlnaW5hbCkNCiAgICAgIGNhdCgiU3RhdHVzICAgICAgICA6IFJlYWR5IHRvIG1lcmdlIChCYXNlIFJlZmVyZW5jZSlcbiIpDQogICAgfSBlbHNlIHsNCiAgICAgIGlmIChpZGVudGljYWwoc29ydChjX25hbWVzX29yaWdpbmFsKSwgcmVmZXJlbmNlX2NvbHMpKSB7DQogICAgICAgIGNhdCgiU3RhdHVzICAgICAgICA6IFJlYWR5IHRvIG1lcmdlXG4iKQ0KICAgICAgfSBlbHNlIHsNCiAgICAgICAgY2F0KCJTdGF0dXMgICAgICAgIDogTmVlZCBhZGp1c3RtZW50IChLb2xvbSB0aWRhayBzaW5rcm9uKVxuIikNCiAgICAgIH0NCiAgICB9DQogICAgDQogICAgbWFpbl9kYXRhc2V0c1tbZmlsZV9uYW1lXV0gPC0gZGYgJT4lIG11dGF0ZShhY3Jvc3MoZXZlcnl0aGluZygpLCBhcy5jaGFyYWN0ZXIpKQ0KICB9DQp9DQoNCiMgR2FidW5na2FuIGRhdGENCmlmIChsZW5ndGgobWFpbl9kYXRhc2V0cykgPiAwKSB7DQogIGZpbmFsX2RhdGFzZXQgPC0gYmluZF9yb3dzKG1haW5fZGF0YXNldHMpDQogIA0KICBjYXQoIlxuPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4iKQ0KICBjYXQoIiBIQVNJTCBQRU5HR0FCVU5HQU4gREFUQVxuIikNCiAgY2F0KCIgVE9UQUwgQkFSSVMgVEVSR0FCVU5HIDoiLCBucm93KGZpbmFsX2RhdGFzZXQpLCAiXG4iKQ0KICBjYXQoIiBUT1RBTCBLT0xPTSAgICAgICAgICAgOiIsIG5jb2woZmluYWxfZGF0YXNldCksICJcbiIpDQogIGNhdCgiPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4iKQ0KDQogIA0KDQpwcmludChrYWJsZShoZWFkKGZpbmFsX2RhdGFzZXQsIDEwKSwgDQogICAgICAgICAgICBmb3JtYXQgPSAicGlwZSIsIA0KICAgICAgICAgICAgYWxpZ24gPSAiYyIsIA0KICAgICAgICAgICAgY2FwdGlvbiA9ICJQcmV2aWV3IERhdGFzZXQgTWVudGFoIiwNCiAgICAgICAgICAgIGxhYmVsID0gTkEpKSAjIE1lbmdoaWxhbmdrYW4gbGFiZWwgb3RvbWF0aXMNCg0KfQ0KYGBgDQoNCiMjIFNFQ1RJT04gQiDigJMgREFUQSBIQU5ETElORw0KDQpgYGB7cixlY2hvPUZBTFNFLGNvbW1lbnQ9IiJ9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojICAgICAgICAgICAgICAgIFNFQ1RJT04gQjogREFUQSBIQU5ETElORw0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjYXQoIj09PSBBTkFMSVNJUyBLT05ESVNJIERBVEFTRVQgPT09XG4iKQ0KDQojIDEuIE1lbmFtcGlsa2FuIGp1bWxhaCB0b3RhbCBiYXJpcyBkYW4ga29sb20NCnRvdGFsX3Jvd3MgPC0gbnJvdyhmaW5hbF9kYXRhc2V0KQ0KdG90YWxfY29scyA8LSBuY29sKGZpbmFsX2RhdGFzZXQpDQoNCmNhdCgiMS4gRGltZW5zaSBEYXRhc2V0OlxuIikNCmNhdCgiICAgLSBUb3RhbCBCYXJpcyA6IiwgdG90YWxfcm93cywgIlxuIikNCmNhdCgiICAgLSBUb3RhbCBLb2xvbSA6IiwgdG90YWxfY29scywgIlxuXG4iKQ0KDQojIE1lbmFtcGlsa2FuIHRpcGUgZGF0YSBzZXRpYXAga29sb20NCmNhdCgiMi4gVGlwZSBEYXRhIFNldGlhcCBLb2xvbTpcbiIpDQojIE1lbmdndW5ha2FuIGRhdGEuZnJhbWUgYWdhciB0YW1waWxhbiBsaXN0IHRpcGUgZGF0YSBsZWJpaCByYXBpIGRhbiB0ZXJiYWNhIHNlbXVhDQp0aXBlX2RhdGEgPC0gZGF0YS5mcmFtZShLb2xvbSA9IG5hbWVzKGZpbmFsX2RhdGFzZXQpLCANCiAgICAgICAgICAgICAgICAgICAgICAgIFRpcGUgPSBzYXBwbHkoZmluYWxfZGF0YXNldCwgY2xhc3MpKQ0KcHJpbnQodGlwZV9kYXRhLCByb3cubmFtZXMgPSBGQUxTRSkNCg0KIyAyLiBJZGVudGlmaWthc2kgTWlzc2luZyBWYWx1ZXMgKERhdGEgS29zb25nKQ0KY2F0KCIzLiBJZGVudGlmaWthc2kgTWlzc2luZyBWYWx1ZXMgcGVyIEtvbG9tOlxuIikNCiMgTWVuZ2VjZWsgTkEsIHN0cmluZyBrb3NvbmcsIGRhbiB0dWxpc2FuICJOVUxMIg0KbWlzc2luZ19pbmZvIDwtIGNvbFN1bXMoaXMubmEoZmluYWxfZGF0YXNldCkgfCBmaW5hbF9kYXRhc2V0ID09ICIiIHwgZmluYWxfZGF0YXNldCA9PSAiTlVMTCIpDQpwcmludChtaXNzaW5nX2luZm9bbWlzc2luZ19pbmZvID4gMF0pIA0KDQojIElkZW50aWZpa2FzaSBEdXBsaWNhdGUgUm93cyAoQmFyaXMgRHVwbGlrYXQpDQpjYXQoIlxuNC4gSWRlbnRpZmlrYXNpIEJhcmlzIER1cGxpa2F0OlxuIikNCmptbF9kdXBsaWthdCA8LSBzdW0oZHVwbGljYXRlZChmaW5hbF9kYXRhc2V0KSkNCmNhdCgiICAgLSBKdW1sYWggYmFyaXMgeWFuZyBkdXBsaWthdDoiLCBqbWxfZHVwbGlrYXQsICJiYXJpc1xuIikNCg0KIyAzLiBNYXNhbGFoIEt1YWxpdGFzIERhdGEgeWFuZyBEaXRlbXVrYW4gKEFuYWxpc2lzKQ0KY2F0KCI1LiBSaW5na2FzYW4gTWFzYWxhaCBLdWFsaXRhcyBEYXRhOlxuIikNCmNhdCgiICAgYS4gVGlwZSBEYXRhIFRpZGFrIFNlc3VhaTogS29sb20gYW5na2EgKHVuaXRfcHJpY2UsIHF1YW50aXR5LCBuZXRfc2FsZXMpIG1hc2loIGJlcnRpcGUgY2hhcmFjdGVyLlxuIikNCmNhdCgiICAgYi4gTWlzc2luZyBWYWx1ZXM6IFRlcmRhcGF0IG5pbGFpIGtvc29uZyBwYWRhIGtvbG9tLWtvbG9tIHRlcnRlbnR1IChzZXBlcnRpIGN1c3RvbWVyX3JhdGluZykuXG4iKQ0KY2F0KCIgICBjLiBCYXJpcyBEdXBsaWthdDogRGl0ZW11a2FuIiwgam1sX2R1cGxpa2F0LCAiYmFyaXMgeWFuZyBpZGVudGlrLlxuIikNCmNhdCgiICAgZC4gSW5rb25zaXN0ZW5zaSBGb3JtYXQ6IEZvcm1hdCB0YW5nZ2FsIGRhbiBwZW51bGlzYW4gdGVrcyAoa2FwaXRhbGlzYXNpKSBiZWx1bSBzZXJhZ2FtLlxuIikNCmBgYA0KDQojIyBTRUNUSU9OIEMg4oCTIERBVEEgQ0xFQU5JTkcNCg0KYGBge3IsbWVzc2FnZT1GQUxTRSx3YXJuaW5nPUZBTFNFLGNvbW1lbnQ9IiIsZWNobz1GQUxTRX0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgICAgICAgICAgICAgICAgU0VDVElPTiBDOiBEQVRBIENMRUFOSU5HDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmNhdCgiPT09IE1FTVVMQUkgUFJPU0VTIFBFTUJFUlNJSEFOIERBVEEgKFZFUlNJIEZJTkFMKSA9PT1cbiIpDQoNCiMgLS0tIDEuIEZ1bmdzaSBTdGFuZGFyZGlzYXNpIFBsYXRmb3JtIChXQUpJQiBJRikgLS0tDQpjbGVhbl9wbGF0Zm9ybV9maW5hbCA8LSBmdW5jdGlvbihwKSB7DQogIHBfY2xlYW4gPC0gdHJpbXdzKHRvbG93ZXIocCkpDQogIGlmIChwX2NsZWFuID09ICJ0b2twZWQiKSB7DQogICAgcmV0dXJuKCJUb2tvcGVkaWEiKQ0KICB9IGVsc2UgaWYgKHBfY2xlYW4gPT0gInNob3BlZSIgfHwgcF9jbGVhbiA9PSAiIHNob3BlZSAiKSB7DQogICAgcmV0dXJuKCJTaG9wZWUiKQ0KICB9IGVsc2UgaWYgKHBfY2xlYW4gPT0gImJsaWJsaSIgfHwgcF9jbGVhbiA9PSAiYmlibGkiKSB7DQogICAgcmV0dXJuKCJCbGlibGkiKQ0KICB9IGVsc2Ugew0KICAgIHJldHVybih0b29sczo6dG9UaXRsZUNhc2UocF9jbGVhbikpDQogIH0NCn0NCg0KIyAtLS0gMi4gQ2xlYW5pbmcgTmlsYWkgSGFyZ2EsIFNhbGVzLCAmIERpc2NvdW50IChXQUpJQiBMT09QSU5HKSAtLS0NCiMgTWVtYmVyc2loa2FuIFJwIGRhbiBtZW5ndWJhaCBrZSBhbmdrYSBtdXJuaSB1bnR1ayA0IGtvbG9tIGZpbmFuc2lhbA0KY29sc190b19udW1lcmljIDwtIGMoInVuaXRfcHJpY2UiLCAiZ3Jvc3Nfc2FsZXMiLCAiZGlzY291bnRfdmFsdWUiLCAibmV0X3NhbGVzIikNCg0KZm9yIChjb2wgaW4gY29sc190b19udW1lcmljKSB7DQogICMgSGlsYW5na2FuICdScCcsIHRpdGlrLCBkYW4gc3Bhc2ksIGxhbHUgcGFrc2EgamFkaSBudW1lcmljDQogIGZpbmFsX2RhdGFzZXRbW2NvbF1dIDwtIGFzLm51bWVyaWMoZ3N1YigiW14wLTkuLV0iLCAiIiwgYXMuY2hhcmFjdGVyKGZpbmFsX2RhdGFzZXRbW2NvbF1dKSkpDQogIA0KICAjIExvZ2lrYSBJRjogUGFzdGlrYW4gdGlkYWsgYWRhIG5pbGFpIG5lZ2F0aWYgYXRhdSBOQSBha2liYXQgZ2FnYWwga29udmVyc2kNCiAgZmluYWxfZGF0YXNldFtbY29sXV0gPC0gaWZlbHNlKGZpbmFsX2RhdGFzZXRbW2NvbF1dIDwgMCB8IGlzLm5hKGZpbmFsX2RhdGFzZXRbW2NvbF1dKSwgMCwgZmluYWxfZGF0YXNldFtbY29sXV0pDQp9DQoNCiMgLS0tIDMuIFBlbWJlcnNpaGFuIEtvbG9tIFRla3MgKENhdGVnb3J5LCBQYXltZW50LCBTdGF0dXMpIC0tLQ0KZmluYWxfZGF0YXNldCA8LSBmaW5hbF9kYXRhc2V0ICU+JQ0KICBtdXRhdGUoDQogICAgIyBBLiBDYXRlZ29yeTogUGFzdGlrYW4gZm9ybWF0IFRpdGxlIENhc2UgKEhvbWUgTGl2aW5nKQ0KICAgIGNhdGVnb3J5ID0gdG9vbHM6OnRvVGl0bGVDYXNlKHRvbG93ZXIodHJpbXdzKGNhdGVnb3J5KSkpLA0KICAgIA0KICAgICMgQi4gUGF5bWVudCBNZXRob2QgKFdBSklCIElGIHZpYSBjYXNlX3doZW4pDQogICAgcGF5bWVudF9tZXRob2QgPSB0cmltd3ModG9sb3dlcihwYXltZW50X21ldGhvZCkpLA0KICAgIHBheW1lbnRfbWV0aG9kID0gY2FzZV93aGVuKA0KICAgICAgcGF5bWVudF9tZXRob2QgPT0gImNvZCIgfiAiQ09EIiwNCiAgICAgIHBheW1lbnRfbWV0aG9kID09ICJjcmVkaXQgY2FyZCIgfiAiQ3JlZGl0IENhcmQiLA0KICAgICAgcGF5bWVudF9tZXRob2QgJWluJSBjKCJlLXdhbGxldCIsICJld2FsbGV0IikgfiAiRS1XYWxsZXQiLCAjIEtvcmVrc2kgRS1XYWxsZXQNCiAgICAgIHBheW1lbnRfbWV0aG9kID09ICIiIHwgaXMubmEocGF5bWVudF9tZXRob2QpIHwgcGF5bWVudF9tZXRob2QgPT0gIm51bGwiIH4gIlVua25vd24iLA0KICAgICAgVFJVRSB+IHRvb2xzOjp0b1RpdGxlQ2FzZShwYXltZW50X21ldGhvZCkNCiAgICApLA0KICAgIA0KICAgICMgQy4gT3JkZXIgU3RhdHVzOiBTdGFuZGFyZGlzYXNpIHJhcGkNCiAgICBvcmRlcl9zdGF0dXMgPSB0cmltd3ModG9sb3dlcihvcmRlcl9zdGF0dXMpKSwNCiAgICBvcmRlcl9zdGF0dXMgPSBjYXNlX3doZW4oDQogICAgICBvcmRlcl9zdGF0dXMgJWluJSBjKCJjYW5jZWwiLCAiY2FuY2VsbGVkIikgfiAiQ2FuY2VsbGVkIiwNCiAgICAgIG9yZGVyX3N0YXR1cyAlaW4lIGMoImRlbGl2ZXJlZCIsICJjb21wbGV0ZWQiKSB+ICJDb21wbGV0ZWQiLA0KICAgICAgVFJVRSB+IHRvb2xzOjp0b1RpdGxlQ2FzZShvcmRlcl9zdGF0dXMpDQogICAgKSwNCiAgICANCiAgICAjIEQuIE1pc3NpbmcgVmFsdWUgQ3VzdG9tZXIgUmF0aW5nIChMb2dpa2E6IERlZmF1bHQgMykNCiAgICAjIDMgZGlwaWxpaCBzZWJhZ2FpIG5pbGFpIHRlbmdhaCBhZ2FyIHRpZGFrIG1lcnVzYWsgZGlzdHJpYnVzaSBkYXRhDQogICAgY3VzdG9tZXJfcmF0aW5nID0gYXMubnVtZXJpYyhjdXN0b21lcl9yYXRpbmcpLA0KICAgIGN1c3RvbWVyX3JhdGluZyA9IGlmZWxzZShpcy5uYShjdXN0b21lcl9yYXRpbmcpLCAzLCBjdXN0b21lcl9yYXRpbmcpDQogICkNCg0KIyAtLS0gNC4gRWtzZWt1c2kgRnVuZ3NpIFBsYXRmb3JtIC0tLQ0KZmluYWxfZGF0YXNldCRwbGF0Zm9ybSA8LSBzYXBwbHkoZmluYWxfZGF0YXNldCRwbGF0Zm9ybSwgY2xlYW5fcGxhdGZvcm1fZmluYWwpDQoNCiMgLS0tIDUuIFRhbXBpbGthbiBIYXNpbCBBa2hpciAtLS0NCmNhdCgiUHJvc2VzIHBlbWJlcnNpaGFuIHNlbGVzYWkgZGVuZ2FuIHN1a3Nlcy5cbiIpDQpwcmludChrYWJsZShoZWFkKGZpbmFsX2RhdGFzZXQsIDEwKSwgDQogICAgICAgICAgICBmb3JtYXQgPSAicGlwZSIsIA0KICAgICAgICAgICAgYWxpZ24gPSAiYyIsIA0KICAgICAgICAgICAgY2FwdGlvbiA9ICJEYXRhc2V0IEJlcnNpaCBkYW4gVGVyc3RydWt0dXIgKFNlY3Rpb24gQykiKSkNCmBgYA0KDQojIyBTRUNUSU9OIEQg4oCTIENPTkRJVElPTkFMIExPR0lDDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxjb21tZW50PSIiLGVjaG89RkFMU0V9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojICAgICAgICAgICAgICAgIFNFQ1RJT04gRDogQ09ORElUSU9OQUwgTE9HSUMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2F0KCJcbj09PSBNRU5FUkFQS0FOIExPR0lLQSBCSVNOSVMgKFNFQ1RJT04gRCkgPT09XG4iKQ0KDQojIE1lbmdndW5ha2FuIG11dGF0ZSB1bnR1ayBtZW1idWF0IGtvbG9tIGthdGVnb3Jpc2FzaSBiYXJ1DQpmaW5hbF9kYXRhc2V0IDwtIGZpbmFsX2RhdGFzZXQgJT4lDQogIG11dGF0ZSgNCiAgICAjIDEuIEtvbG9tIGlzX2hpZ2hfdmFsdWUNCiAgICAjIExvZ2lrYTogSmlrYSBuZXRfc2FsZXMgZGkgYXRhcyAxIGp1dGEgbWFrYSAiWWVzIiwgamlrYSB0aWRhayAiTm8iDQogICAgaXNfaGlnaF92YWx1ZSA9IGlmZWxzZShuZXRfc2FsZXMgPiAxMDAwMDAwLCAiWWVzIiwgIk5vIiksDQogICAgDQogICAgIyAyLiBLb2xvbSBvcmRlcl9wcmlvcml0eSAoV0FKSUIgTkVTVEVEIElGKQ0KICAgICMgTG9naWthOiBIaWdoICg+IDFqdCksIE1lZGl1bSAoNTAwcmIgLSAxanQpLCBMb3cgKDwgNTAwcmIpDQogICAgb3JkZXJfcHJpb3JpdHkgPSBpZmVsc2UobmV0X3NhbGVzID4gMTAwMDAwMCwgIkhpZ2giLA0KICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKG5ldF9zYWxlcyA+PSA1MDAwMDAsICJNZWRpdW0iLCAiTG93IikpLA0KICAgIA0KICAgICMgMy4gS29sb20gdmFsaWRfdHJhbnNhY3Rpb24NCiAgICAjIExvZ2lrYTogSmlrYSBzdGF0dXMgQ2FuY2VsbGVkIG1ha2EgIkludmFsaWQiLCBzZWxhaW4gaXR1ICJWYWxpZCINCiAgICB2YWxpZF90cmFuc2FjdGlvbiA9IGlmZWxzZShvcmRlcl9zdGF0dXMgPT0gIkNhbmNlbGxlZCIsICJJbnZhbGlkIiwgIlZhbGlkIikNCiAgKQ0KDQojIC0tLSBWZXJpZmlrYXNpIEhhc2lsIC0tLQ0KY2F0KCJCZXJoYXNpbCBtZW5hbWJhaGthbiBrb2xvbTogaXNfaGlnaF92YWx1ZSwgb3JkZXJfcHJpb3JpdHksIHZhbGlkX3RyYW5zYWN0aW9uLlxuIikNCg0KIyBNZW5hbXBpbGthbiBjdXBsaWthbiAxMCBkYXRhIHBlcnRhbWEgdW50dWsga29sb20ta29sb20gYmFydQ0KcHJpbnQoa2FibGUoaGVhZChmaW5hbF9kYXRhc2V0ICU+JSANCiAgICAgICAgICAgICAgICAgICBzZWxlY3Qob3JkZXJfaWQsIG5ldF9zYWxlcywgb3JkZXJfc3RhdHVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgaXNfaGlnaF92YWx1ZSwgb3JkZXJfcHJpb3JpdHksIHZhbGlkX3RyYW5zYWN0aW9uKSwgMTApLCANCiAgICAgICAgICAgIGZvcm1hdCA9ICJwaXBlIiwgDQogICAgICAgICAgICBhbGlnbiA9ICJjIiwgDQogICAgICAgICAgICBjYXB0aW9uID0gIkhhc2lsIEltcGxlbWVudGFzaSBDb25kaXRpb25hbCBMb2dpYyAoU2VjdGlvbiBEKSIpKQ0KYGBgDQoNCiMjIFNFQ1RJT04gRSDigJMgQU5BTFlUSUNBTCBUSElOS0lORw0KDQpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGd0KQ0KbGlicmFyeShodG1sdG9vbHMpDQoNCiMgMS4gQnVhdCB0YWJlbA0KcGxhdGZvcm1fZGYgPC0gZmluYWxfZGF0YXNldCAlPiUNCiAgY291bnQocGxhdGZvcm0sIG5hbWUgPSAiVG90YWwiKSAlPiUNCiAgYXJyYW5nZShkZXNjKFRvdGFsKSkNCg0KY2F0ZWdvcnlfZGYgPC0gZmluYWxfZGF0YXNldCAlPiUNCiAgY291bnQoY2F0ZWdvcnksIG5hbWUgPSAiRnJla3VlbnNpIikgJT4lDQogIGFycmFuZ2UoZGVzYyhGcmVrdWVuc2kpKQ0KDQpzdGF0dXNfZGYgPC0gZmluYWxfZGF0YXNldCAlPiUNCiAgZmlsdGVyKCFvcmRlcl9zdGF0dXMgJWluJSBjKCJSZXR1ciIsICJCYXRhbCIpKSAlPiUNCiAgY291bnQob3JkZXJfc3RhdHVzLCBuYW1lID0gIkp1bWxhaCIpICU+JQ0KICBhcnJhbmdlKGRlc2MoSnVtbGFoKSkNCg0KIyAyLiBCdWF0IEdUIHRhYmxlDQp0MSA8LSBndChwbGF0Zm9ybV9kZikgJT4lDQogIHRhYl9oZWFkZXIodGl0bGUgPSAiRG9taW5hc2kgUGxhdGZvcm0iKSAlPiUNCiAgY29sc19hbGlnbihhbGlnbiA9ICJjZW50ZXIiKSAlPiUNCiAgdGFiX3N0eWxlKA0KICAgIHN0eWxlID0gY2VsbF90ZXh0KHdlaWdodCA9ICJib2xkIiksDQogICAgbG9jYXRpb25zID0gY2VsbHNfY29sdW1uX2xhYmVscyhldmVyeXRoaW5nKCkpDQogICkNCg0KdDIgPC0gZ3QoY2F0ZWdvcnlfZGYpICU+JQ0KICB0YWJfaGVhZGVyKHRpdGxlID0gIkZyZWt1ZW5zaSBLYXRlZ29yaSIpICU+JQ0KICBjb2xzX2FsaWduKGFsaWduID0gImNlbnRlciIpICU+JQ0KICB0YWJfc3R5bGUoDQogICAgc3R5bGUgPSBjZWxsX3RleHQod2VpZ2h0ID0gImJvbGQiKSwNCiAgICBsb2NhdGlvbnMgPSBjZWxsc19jb2x1bW5fbGFiZWxzKGV2ZXJ5dGhpbmcoKSkNCiAgKQ0KDQp0MyA8LSBndChzdGF0dXNfZGYpICU+JQ0KICB0YWJfaGVhZGVyKHRpdGxlID0gIlN0YXR1cyBUcmFuc2Frc2kiKSAlPiUNCiAgY29sc19hbGlnbihhbGlnbiA9ICJjZW50ZXIiKSAlPiUNCiAgdGFiX3N0eWxlKA0KICAgIHN0eWxlID0gY2VsbF90ZXh0KHdlaWdodCA9ICJib2xkIiksDQogICAgbG9jYXRpb25zID0gY2VsbHNfY29sdW1uX2xhYmVscyhldmVyeXRoaW5nKCkpDQogICkNCg0KYnJvd3NhYmxlKA0KICBkaXYoDQogICAgc3R5bGUgPSAiZGlzcGxheTpmbGV4OyBnYXA6MzBweDsganVzdGlmeS1jb250ZW50OmNlbnRlcjsiLA0KICAgIGRpdihzdHlsZT0id2lkdGg6MzAlOyIsIHQxKSwNCiAgICBkaXYoc3R5bGU9IndpZHRoOjMwJTsiLCB0MiksDQogICAgZGl2KHN0eWxlPSJ3aWR0aDozMCU7IiwgdDMpDQogICkNCikNCmBgYA0KDQojIFdlYiBTY3JhcGluZyAmIERhdGEgUHJvZ3JhbW1pbmcgUHJvY2Vzcw0KDQojIyBTRUNUSU9OIEEg4oCTIERBVEEgQ09MTEVDVElPTiBVU0lORyBQUk9HUkFNTUlORw0KDQojIyMgMS4gQ291bnRyaWVzIG9mIHRoZSBXb3JsZCAoU3RhdGljIFBhZ2UpDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxjb21tZW50PSIiLGVjaG89RkFMU0V9DQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KGtuaXRyKQ0KDQpjYXQoIj09PSBTQ1JBUElORzogQ09VTlRSSUVTIE9GIFRIRSBXT1JMRCA9PT1cbiIpDQoNCnVybCA8LSAiaHR0cHM6Ly93d3cuc2NyYXBldGhpc3NpdGUuY29tL3BhZ2VzL3NpbXBsZS8iDQpwYWdlIDwtIHJlYWRfaHRtbCh1cmwpDQoNCmNvdW50cmllc19kZiA8LSBwYWdlICU+JQ0KICBodG1sX25vZGVzKCIuY291bnRyeSIpICU+JQ0KICBsYXBwbHkoZnVuY3Rpb24oeCkgew0KICAgIGRhdGEuZnJhbWUoDQogICAgICBjb3VudHJ5X25hbWUgPSB4ICU+JSBodG1sX25vZGUoIi5jb3VudHJ5LW5hbWUiKSAlPiUgaHRtbF90ZXh0KCksDQogICAgICBjYXBpdGFsICAgICAgPSB4ICU+JSBodG1sX25vZGUoIi5jb3VudHJ5LWNhcGl0YWwiKSAlPiUgaHRtbF90ZXh0KCksDQogICAgICBwb3B1bGF0aW9uICAgPSB4ICU+JSBodG1sX25vZGUoIi5jb3VudHJ5LXBvcHVsYXRpb24iKSAlPiUgaHRtbF90ZXh0KCksDQogICAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UNCiAgICApDQogIH0pICU+JQ0KICBiaW5kX3Jvd3MoKSAlPiUNCiAgDQogIG11dGF0ZSgNCiAgICBjb3VudHJ5X25hbWUgPSBzdHJfc3F1aXNoKGNvdW50cnlfbmFtZSksDQogICAgY2FwaXRhbCAgICAgID0gc3RyX3NxdWlzaChjYXBpdGFsKSwNCiAgICBwb3B1bGF0aW9uICAgPSBzdHJfc3F1aXNoKHBvcHVsYXRpb24pLA0KICAgIHBvcHVsYXRpb24gICA9IHBhcnNlX251bWJlcihwb3B1bGF0aW9uKSAgIyBsZWJpaCBhbWFuIGRhcmkgYXMubnVtZXJpYw0KICApICU+JQ0KICANCiAgYXJyYW5nZShkZXNjKHBvcHVsYXRpb24pKSAgIyBvcHNpb25hbDogdXJ1dCBkYXJpIHRlcmJlc2FyDQoNCiMgU2ltcGFuIGtlIENTVg0Kd3JpdGVfY3N2KGNvdW50cmllc19kZiwgImNvdW50cmllc19kYXRhLmNzdiIpDQoNCiMgT3V0cHV0IHJhcGkNCmNhdCgiSnVtbGFoIGRhdGEgZGlhbWJpbDoiLCBucm93KGNvdW50cmllc19kZiksICJcblxuIikNCg0Ka2FibGUoDQogIGhlYWQoY291bnRyaWVzX2RmLCAxMCksDQogIGNhcHRpb24gPSAiVG9wIDEwIE5lZ2FyYSBCZXJkYXNhcmthbiBQb3B1bGFzaSIsDQogIGFsaWduID0gImMiDQopDQpgYGANCg0KIyMjIEhvY2tleSBUZWFtcyAoUGFnaW5hdGlvbiAmIEZvcm0pDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxjb21tZW50PSIiLGVjaG89RkFMU0V9DQpsaWJyYXJ5KHJ2ZXN0KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShzdHJpbmdyKQ0KbGlicmFyeShrbml0cikNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBQQVJBTUVURVIgLSBtb2RlIHNpbGVudA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KYmFzZV91cmwgPC0gImh0dHBzOi8vd3d3LnNjcmFwZXRoaXNzaXRlLmNvbS9wYWdlcy9mb3Jtcy8iDQpwYWdlX251bSA8LSAxDQphbGxfdGVhbXMgPC0gbGlzdCgpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgU0NSQVBJTkcgU0lMRU5UICh0YW5wYSBjYXQpDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQpyZXBlYXQgew0KICB1cmwgPC0gcGFzdGUwKGJhc2VfdXJsLCAiP3BhZ2VfbnVtPSIsIHBhZ2VfbnVtKQ0KICBwYWdlIDwtIHRyeUNhdGNoKHJlYWRfaHRtbCh1cmwpLCBlcnJvciA9IGZ1bmN0aW9uKGUpIE5VTEwpDQogIGlmIChpcy5udWxsKHBhZ2UpKSBicmVhaw0KICANCiAgdGVhbXMgPC0gcGFnZSAlPiUgaHRtbF9ub2RlcygiLnRlYW0iKQ0KICBpZiAobGVuZ3RoKHRlYW1zKSA9PSAwKSBicmVhaw0KICANCiAgZGZfcGFnZSA8LSBtYXBfZGYodGVhbXMsIGZ1bmN0aW9uKHIpIHsNCiAgICBkYXRhLmZyYW1lKA0KICAgICAgdGVhbV9uYW1lID0gciAlPiUgaHRtbF9ub2RlKCIubmFtZSIpICU+JSBodG1sX3RleHQoKSAlPiUgc3RyX3NxdWlzaCgpLA0KICAgICAgeWVhciAgICAgID0gciAlPiUgaHRtbF9ub2RlKCIueWVhciIpICU+JSBodG1sX3RleHQoKSAlPiUgc3RyX3NxdWlzaCgpICU+JSBhcy5udW1lcmljKCksDQogICAgICB3aW5zICAgICAgPSByICU+JSBodG1sX25vZGUoIi53aW5zIikgJT4lIGh0bWxfdGV4dCgpICU+JSBzdHJfc3F1aXNoKCkgJT4lIGFzLm51bWVyaWMoKSwNCiAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRQ0KICAgICkNCiAgfSkNCiAgDQogIGlmIChucm93KGRmX3BhZ2UpID09IDAgfHwgYWxsKGlzLm5hKGRmX3BhZ2UkdGVhbV9uYW1lKSkpIGJyZWFrDQogIA0KICBhbGxfdGVhbXNbW3BhZ2VfbnVtXV0gPC0gZGZfcGFnZQ0KICBwYWdlX251bSA8LSBwYWdlX251bSArIDENCn0NCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBHQUJVTkdLQU4sIEJFUlNJSEtBTiwgREFOIEFNQklMIFRPUCAxMCBCRVJEQVNBUktBTiBXSU5TDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQpob2NrZXlfZGYgPC0gYmluZF9yb3dzKGFsbF90ZWFtcykgJT4lDQogIGZpbHRlcighaXMubmEodGVhbV9uYW1lKSkgJT4lDQogIGFycmFuZ2UoZGVzYyh3aW5zKSkNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyBUQU1QSUxLQU4gSEFOWUEgVEFCRUwgVE9QIDEwDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQprYWJsZShoZWFkKGhvY2tleV9kZiwgMTApLCANCiAgICAgIGNhcHRpb24gPSAiVG9wIDEwIFRpbSBIb2NrZXkgKEJlcmRhc2Fya2FuIEtlbWVuYW5nYW4gVGVyYmFueWFrKSIsIA0KICAgICAgYWxpZ24gPSAiYyIpDQpgYGANCg0KIyMgU0VDVElPTiBCIOKAkyBEQVRBIEhBTkRMSU5HDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxjb21tZW50PSIiLGVjaG89RkFMU0V9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojICAgICAgICAgICBTRUNUSU9OIEI6IERBVEEgSEFORExJTkcgKEJBQiAyKQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjYXQoIj09PSBBTkFMSVNJUyBTVFJVS1RVUiBEQVRBIEhBU0lMIFNDUkFQSU5HID09PVxuXG4iKQ0KDQojIEZ1bmdzaSB1bnR1ayBtZWxha3VrYW4gYXVkaXQgZGF0YSBzZWNhcmEgb3RvbWF0aXMNCmF1ZGl0X2RhdGFzZXQgPC0gZnVuY3Rpb24oZGYsIG5hbWFfZGF0YXNldCkgew0KICBjYXQocGFzdGUocmVwKCI9IiwgNTApLCBjb2xsYXBzZSA9ICIiKSwgIlxuIikNCiAgY2F0KCJEQVRBU0VUOiIsIG5hbWFfZGF0YXNldCwgIlxuIikNCiAgY2F0KHBhc3RlKHJlcCgiPSIsIDUwKSwgY29sbGFwc2UgPSAiIiksICJcbiIpDQogIA0KICAjIDEuIE1lbmFtcGlsa2FuIERpbWVuc2kgZGFuIE5hbWEgS29sb20NCiAgY2F0KCIxLiBTdHJ1a3R1ciBEYXNhcjpcbiIpDQogIGNhdCgiICAgLSBKdW1sYWggQmFyaXMgOiIsIG5yb3coZGYpLCAiXG4iKQ0KICBjYXQoIiAgIC0gSnVtbGFoIEtvbG9tIDoiLCBuY29sKGRmKSwgIlxuIikNCiAgY2F0KCIgICAtIE5hbWEgS29sb20gICA6IiwgcGFzdGUobmFtZXMoZGYpLCBjb2xsYXBzZSA9ICIsICIpLCAiXG5cbiIpDQogIA0KICAjIDIuIE1lbmFtcGlsa2FuIFRpcGUgRGF0YQ0KICBjYXQoIjIuIFRpcGUgRGF0YSBTZXRpYXAgS29sb206XG4iKQ0KICB0aXBlX2RhdGEgPC0gZGF0YS5mcmFtZSgNCiAgICBLb2xvbSA9IG5hbWVzKGRmKSwgDQogICAgVGlwZSA9IHNhcHBseShkZiwgY2xhc3MpDQogICkNCiAgcHJpbnQodGlwZV9kYXRhLCByb3cubmFtZXMgPSBGQUxTRSkNCiAgDQogICMgMy4gUGVyaWtzYSBNaXNzaW5nIFZhbHVlcyAmIER1cGxpa2F0DQogIGNhdCgiXG4zLiBQZW1lcmlrc2FhbiBLdWFsaXRhczpcbiIpDQogIA0KICAjIE1lbmdlY2VrIE5BIGF0YXUgc3RyaW5nIGtvc29uZw0KICBtaXNzaW5nX3ZhbHMgPC0gY29sU3Vtcyhpcy5uYShkZikgfCBkZiA9PSAiIikNCiAgY2F0KCIgICAtIE1pc3NpbmcgVmFsdWVzIHBlciBLb2xvbTpcbiIpDQogIHByaW50KG1pc3NpbmdfdmFscykNCiAgDQogICMgTWVuZ2VjZWsgQmFyaXMgRHVwbGlrYXQNCiAgam1sX2R1cGxpa2F0IDwtIHN1bShkdXBsaWNhdGVkKGRmKSkNCiAgY2F0KCIgICAtIEp1bWxhaCBCYXJpcyBEdXBsaWthdDoiLCBqbWxfZHVwbGlrYXQsICJiYXJpc1xuXG4iKQ0KfQ0KDQojIC0tLSBFS1NFS1VTSSBVTlRVSyBEQVRBU0VUIDE6IENPVU5UUklFUyAtLS0NCmF1ZGl0X2RhdGFzZXQoY291bnRyaWVzX2RmLCAiQ291bnRyaWVzIG9mIHRoZSBXb3JsZCIpDQoNCmNhdCgiNC4gSXN1IEt1YWxpdGFzIERhdGEgeWFuZyBEaXRlbXVrYW4gKENvdW50cmllcyk6XG4iKQ0KY2F0KCIgICBhLiBUaXBlIERhdGE6IEtvbG9tICdwb3B1bGF0aW9uJyBkYW4gJ2FyZWEnIG11bmdraW4gbWFzaWggdGVyYmFjYSBzZWJhZ2FpIGNoYXJhY3Rlci90ZWtzIGthcmVuYSBhZGFueWEga29tYS90aXRpay5cbiIpDQpjYXQoIiAgIGIuIE1pc3NpbmcgVmFsdWVzOiBQb3RlbnNpIGFkYW55YSBzZWwga29zb25nIHBhZGEgZGF0YSBnZW9ncmFmaSB5YW5nIHRpZGFrIHRlcmNhdGF0IGxlbmdrYXAuXG5cbiIpDQoNCiMgLS0tIEVLU0VLVVNJIFVOVFVLIERBVEFTRVQgMjogSE9DS0VZIFRFQU1TIC0tLQ0KYXVkaXRfZGF0YXNldChob2NrZXlfZGYsICJIb2NrZXkgVGVhbXMgKFBhZ2luYXRpb24gJiBGb3JtKSIpDQoNCmNhdCgiNC4gSXN1IEt1YWxpdGFzIERhdGEgeWFuZyBEaXRlbXVrYW4gKEhvY2tleSk6XG4iKQ0KY2F0KCIgICBhLiBEdXBsaWthc2k6IFBvdGVuc2kgYmFyaXMgZ2FuZGEgamlrYSBwcm9zZXMgcGFnaW5hdGlvbiBtZW5nYW1iaWwgZGF0YSB5YW5nIHNhbWEgc2VjYXJhIHRpZGFrIHNlbmdhamEuXG4iKQ0KY2F0KCIgICBiLiBLb25zaXN0ZW5zaTogS29sb20gJ3dpbnMnIGRhbiAncG9pbnRzJyBwZXJsdSBkaWtvbnZlcnNpIGtlIG51bWVyaWsgYWdhciBiaXNhIGRpbGFrdWthbiBwZXJoaXR1bmdhbiBzdGF0aXN0aWsuXG5cbiIpDQpgYGANCg0KIyMgU0VDVElPTiBDIOKAkyBEQVRBIENMRUFOSU5HDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxjb21tZW50PSIiLGVjaG89RkFMU0V9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIFNFQ1RJT04gQzogREFUQSBDTEVBTklORw0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjYXQoIlNFQ1RJT04gQzogREFUQSBDTEVBTklOR1xuIikNCg0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KIyAxLiBTVEFOREFSRElTQVNJIFRFS1MNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2F0KCJcblsxXSBTdGFuZGFyZGlzYXNpIHRla3MuLi5cbiIpDQoNCnRleHRfY29sc19jb3VudHJpZXMgPC0gYygiY291bnRyeV9uYW1lIiwgImNhcGl0YWwiKQ0KDQpmb3IgKGNvbCBpbiB0ZXh0X2NvbHNfY291bnRyaWVzKSB7DQogIGlmIChjb2wgJWluJSBuYW1lcyhjb3VudHJpZXNfZGYpKSB7DQogICAgY291bnRyaWVzX2RmW1tjb2xdXSA8LSBjb3VudHJpZXNfZGZbW2NvbF1dICU+JQ0KICAgICAgdHJpbXdzKCkgJT4lDQogICAgICB0b2xvd2VyKCkgJT4lDQogICAgICB0b29sczo6dG9UaXRsZUNhc2UoKQ0KICB9DQp9DQoNCnRleHRfY29sc19ob2NrZXkgPC0gYygidGVhbV9uYW1lIikNCg0KZm9yIChjb2wgaW4gdGV4dF9jb2xzX2hvY2tleSkgew0KICBpZiAoY29sICVpbiUgbmFtZXMoaG9ja2V5X2RmKSkgew0KICAgIGhvY2tleV9kZltbY29sXV0gPC0gaG9ja2V5X2RmW1tjb2xdXSAlPiUNCiAgICAgIHRyaW13cygpICU+JQ0KICAgICAgdG9sb3dlcigpICU+JQ0KICAgICAgdG9vbHM6OnRvVGl0bGVDYXNlKCkNCiAgfQ0KfQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDIuIEtPTlZFUlNJIE5VTUVSSUsNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2F0KCJbMl0gS29udmVyc2kga2UgbnVtZXJpYy4uLlxuIikNCg0KY2xlYW5fbnVtZXJpYyA8LSBmdW5jdGlvbih4KSB7DQogIGlmIChpcy5udWxsKHgpKSByZXR1cm4ocmVwKE5BLCBsZW5ndGgoeCkpKQ0KICANCiAgeF9jbGVhbiA8LSBnc3ViKCJbXjAtOS4tXSIsICIiLCBhcy5jaGFyYWN0ZXIoeCkpDQogIHhfY2xlYW5beF9jbGVhbiA9PSAiIl0gPC0gTkENCiAgDQogIGFzLm51bWVyaWMoeF9jbGVhbikNCn0NCg0KbnVtX2NvbHNfY291bnRyaWVzIDwtIGMoInBvcHVsYXRpb24iLCAiYXJlYSIpDQoNCmZvciAoY29sIGluIG51bV9jb2xzX2NvdW50cmllcykgew0KICBpZiAoY29sICVpbiUgbmFtZXMoY291bnRyaWVzX2RmKSkgew0KICAgIGNsZWFuZWQgPC0gY2xlYW5fbnVtZXJpYyhjb3VudHJpZXNfZGZbW2NvbF1dKQ0KICAgIGlmIChsZW5ndGgoY2xlYW5lZCkgPT0gbnJvdyhjb3VudHJpZXNfZGYpKSB7DQogICAgICBjb3VudHJpZXNfZGZbW2NvbF1dIDwtIGNsZWFuZWQNCiAgICB9DQogIH0NCn0NCg0KbnVtX2NvbHNfaG9ja2V5IDwtIGMoInllYXIiLCAid2lucyIsICJwb2ludHMiKQ0KDQpmb3IgKGNvbCBpbiBudW1fY29sc19ob2NrZXkpIHsNCiAgaWYgKGNvbCAlaW4lIG5hbWVzKGhvY2tleV9kZikpIHsNCiAgICBjbGVhbmVkIDwtIGNsZWFuX251bWVyaWMoaG9ja2V5X2RmW1tjb2xdXSkNCiAgICBpZiAobGVuZ3RoKGNsZWFuZWQpID09IG5yb3coaG9ja2V5X2RmKSkgew0KICAgICAgaG9ja2V5X2RmW1tjb2xdXSA8LSBjbGVhbmVkDQogICAgfQ0KICB9DQp9DQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgMy4gSEFORExFIE1JU1NJTkcgVkFMVUUNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2F0KCJbM10gTWVuYW5nYW5pIG1pc3NpbmcgdmFsdWVzLi4uXG4iKQ0KDQpmb3IgKGNvbCBpbiBuYW1lcyhjb3VudHJpZXNfZGYpKSB7DQogIG5hX2NvdW50IDwtIHN1bShpcy5uYShjb3VudHJpZXNfZGZbW2NvbF1dKSkNCiAgDQogIGlmIChuYV9jb3VudCA+IDApIHsNCiAgICBpZiAobmFfY291bnQgPD0gMykgew0KICAgICAgY291bnRyaWVzX2RmIDwtIGNvdW50cmllc19kZlshaXMubmEoY291bnRyaWVzX2RmW1tjb2xdXSksIF0NCiAgICB9IGVsc2Ugew0KICAgICAgaWYgKGlzLm51bWVyaWMoY291bnRyaWVzX2RmW1tjb2xdXSkpIHsNCiAgICAgICAgY291bnRyaWVzX2RmW1tjb2xdXVtpcy5uYShjb3VudHJpZXNfZGZbW2NvbF1dKV0gPC0gbWVkaWFuKGNvdW50cmllc19kZltbY29sXV0sIG5hLnJtID0gVFJVRSkNCiAgICAgIH0NCiAgICB9DQogIH0NCn0NCg0KZm9yIChjb2wgaW4gbmFtZXMoaG9ja2V5X2RmKSkgew0KICBuYV9jb3VudCA8LSBzdW0oaXMubmEoaG9ja2V5X2RmW1tjb2xdXSkpDQogIA0KICBpZiAobmFfY291bnQgPiAwKSB7DQogICAgaWYgKG5hX2NvdW50IDw9IDMpIHsNCiAgICAgIGhvY2tleV9kZiA8LSBob2NrZXlfZGZbIWlzLm5hKGhvY2tleV9kZltbY29sXV0pLCBdDQogICAgfSBlbHNlIHsNCiAgICAgIGlmIChpcy5udW1lcmljKGhvY2tleV9kZltbY29sXV0pKSB7DQogICAgICAgIGhvY2tleV9kZltbY29sXV1baXMubmEoaG9ja2V5X2RmW1tjb2xdXSldIDwtIG1lZGlhbihob2NrZXlfZGZbW2NvbF1dLCBuYS5ybSA9IFRSVUUpDQogICAgICB9DQogICAgfQ0KICB9DQp9DQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgNC4gVkFMSURBU0kgREFUQQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjYXQoIls0XSBWYWxpZGFzaSBkYXRhLi4uXG4iKQ0KDQpmb3IgKGNvbCBpbiBjKCJwb3B1bGF0aW9uIiwgImFyZWEiKSkgew0KICBpZiAoY29sICVpbiUgbmFtZXMoY291bnRyaWVzX2RmKSkgew0KICAgIGlmIChhbnkoY291bnRyaWVzX2RmW1tjb2xdXSA8IDAsIG5hLnJtID0gVFJVRSkpIHsNCiAgICAgIGNvdW50cmllc19kZiA8LSBjb3VudHJpZXNfZGZbY291bnRyaWVzX2RmW1tjb2xdXSA+PSAwLCBdDQogICAgfQ0KICB9DQp9DQoNCmZvciAoY29sIGluIGMoIndpbnMiLCAicG9pbnRzIikpIHsNCiAgaWYgKGNvbCAlaW4lIG5hbWVzKGhvY2tleV9kZikpIHsNCiAgICBpZiAoYW55KGhvY2tleV9kZltbY29sXV0gPCAwLCBuYS5ybSA9IFRSVUUpKSB7DQogICAgICBob2NrZXlfZGYgPC0gaG9ja2V5X2RmW2hvY2tleV9kZltbY29sXV0gPj0gMCwgXQ0KICAgIH0NCiAgfQ0KfQ0KDQppZiAoInllYXIiICVpbiUgbmFtZXMoaG9ja2V5X2RmKSkgew0KICBpZiAoYW55KGhvY2tleV9kZiR5ZWFyIDwgMTkwMCB8IGhvY2tleV9kZiR5ZWFyID4gMjEwMCwgbmEucm0gPSBUUlVFKSkgew0KICAgIGhvY2tleV9kZiA8LSBob2NrZXlfZGZbaG9ja2V5X2RmJHllYXIgPj0gMTkwMCAmIGhvY2tleV9kZiR5ZWFyIDw9IDIxMDAsIF0NCiAgfQ0KfQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDUuIEhBUFVTIERVUExJQ0FURQ0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjYXQoIls1XSBNZW5naGFwdXMgZHVwbGljYXRlLi4uXG4iKQ0KDQpjb3VudHJpZXNfZGYgPC0gY291bnRyaWVzX2RmWyFkdXBsaWNhdGVkKGNvdW50cmllc19kZiksIF0NCmhvY2tleV9kZiAgICA8LSBob2NrZXlfZGZbIWR1cGxpY2F0ZWQoaG9ja2V5X2RmKSwgXQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIE9VVFBVVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjYXQoIlxuUHJvc2VzIHBlbWJlcnNpaGFuIHNlbGVzYWkuXG4iKQ0KDQpjYXQoIlxuRGF0YXNldCBoYXNpbCBjbGVhbmluZzpcbiIpDQoNCmNhdCgiXG5Db3VudHJpZXM6XG4iKQ0KcHJpbnQoa2FibGUoaGVhZChjb3VudHJpZXNfZGYsIDEwKSwgYWxpZ24gPSAiYyIpKQ0KDQpjYXQoIlxuSG9ja2V5IFRlYW1zOlxuIikNCnByaW50KGthYmxlKGhlYWQoaG9ja2V5X2RmLCAxMCksIGFsaWduID0gImMiKSkNCmBgYA0KDQojIyBTRUNUSU9OIEQg4oCTIENPTkRJVElPTkFMIExPR0lDDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRSxjb21tZW50PSIiLGVjaG89RkFMU0V9DQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIFNFQ1RJT04gRDogQ09ORElUSU9OQUwgTE9HSUMNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2F0KCJcblNFQ1RJT04gRDogQ09ORElUSU9OQUwgTE9HSUNcbiIpDQoNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCiMgMS4gREVGQVVMVCBWQUxVRSAoRUxFbWVuIHRpZGFrIGRpdGVtdWthbikNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KY2F0KCJcblsxXSBIYW5kbGluZyBtaXNzaW5nIGVsZW1lbnRzLi4uXG4iKQ0KDQojIHViYWggc3RyaW5nIGtvc29uZyBqYWRpIE5BDQpjb3VudHJpZXNfZGZbY291bnRyaWVzX2RmID09ICIiXSA8LSBOQQ0KaG9ja2V5X2RmW2hvY2tleV9kZiA9PSAiIl0gICAgICAgPC0gTkENCg0KIyBpc2kgZGVmYXVsdCAoSUYtRUxTRSkNCmlmICgiY291bnRyeV9uYW1lIiAlaW4lIG5hbWVzKGNvdW50cmllc19kZikpIHsNCiAgY291bnRyaWVzX2RmJGNvdW50cnlfbmFtZSA8LSBpZmVsc2UoaXMubmEoY291bnRyaWVzX2RmJGNvdW50cnlfbmFtZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJVbmtub3duIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnRyaWVzX2RmJGNvdW50cnlfbmFtZSkNCn0NCg0KaWYgKCJ0ZWFtX25hbWUiICVpbiUgbmFtZXMoaG9ja2V5X2RmKSkgew0KICBob2NrZXlfZGYkdGVhbV9uYW1lIDwtIGlmZWxzZShpcy5uYShob2NrZXlfZGYkdGVhbV9uYW1lKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVua25vd24iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBob2NrZXlfZGYkdGVhbV9uYW1lKQ0KfQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIDIuIE1FTkVOVFVLQU4gREFUQSBTVEFUVVMgKExPT1BJTkcpDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCmNhdCgiWzJdIERldGVybWluaW5nIGRhdGEgc3RhdHVzLi4uXG4iKQ0KDQpjaGVja19zdGF0dXNfY291bnRyaWVzIDwtIGZ1bmN0aW9uKHJvdykgew0KICANCiAgaWYgKGFueShpcy5uYShyb3dbYygiY291bnRyeV9uYW1lIiwgImNhcGl0YWwiLCAicG9wdWxhdGlvbiIsICJhcmVhIildKSkpIHsNCiAgICByZXR1cm4oIkluY29tcGxldGUiKQ0KICB9DQogIA0KICBpZiAoIWlzLm5hKHJvd1sicG9wdWxhdGlvbiJdKSAmJiBhcy5udW1lcmljKHJvd1sicG9wdWxhdGlvbiJdKSA8PSAwKSB7DQogICAgcmV0dXJuKCJJbmNvbXBsZXRlIikNCiAgfQ0KICANCiAgaWYgKCFpcy5uYShyb3dbImFyZWEiXSkgJiYgYXMubnVtZXJpYyhyb3dbImFyZWEiXSkgPD0gMCkgew0KICAgIHJldHVybigiSW5jb21wbGV0ZSIpDQogIH0NCiAgDQogIHJldHVybigiQ29tcGxldGUiKQ0KfQ0KDQpjaGVja19zdGF0dXNfaG9ja2V5IDwtIGZ1bmN0aW9uKHJvdykgew0KICANCiAgaWYgKGFueShpcy5uYShyb3dbYygidGVhbV9uYW1lIiwgInllYXIiLCAid2lucyIsICJwb2ludHMiKV0pKSkgew0KICAgIHJldHVybigiSW5jb21wbGV0ZSIpDQogIH0NCiAgDQogIGlmICghaXMubmEocm93WyJ3aW5zIl0pICYmIGFzLm51bWVyaWMocm93WyJ3aW5zIl0pIDwgMCkgew0KICAgIHJldHVybigiSW5jb21wbGV0ZSIpDQogIH0NCiAgDQogIGlmICghaXMubmEocm93WyJwb2ludHMiXSkgJiYgYXMubnVtZXJpYyhyb3dbInBvaW50cyJdKSA8IDApIHsNCiAgICByZXR1cm4oIkluY29tcGxldGUiKQ0KICB9DQogIA0KICBpZiAoIWlzLm5hKHJvd1sieWVhciJdKSkgew0KICAgIHkgPC0gYXMubnVtZXJpYyhyb3dbInllYXIiXSkNCiAgICBpZiAoeSA8IDE5MDAgfHwgeSA+IDIxMDApIHsNCiAgICAgIHJldHVybigiSW5jb21wbGV0ZSIpDQogICAgfQ0KICB9DQogIA0KICByZXR1cm4oIkNvbXBsZXRlIikNCn0NCg0KIyBsb29waW5nIChhcHBseSkNCmNvdW50cmllc19kZiRkYXRhX3N0YXR1cyA8LSBhcHBseShjb3VudHJpZXNfZGYsIDEsIGNoZWNrX3N0YXR1c19jb3VudHJpZXMpDQpob2NrZXlfZGYkZGF0YV9zdGF0dXMgICAgPC0gYXBwbHkoaG9ja2V5X2RmLCAxLCBjaGVja19zdGF0dXNfaG9ja2V5KQ0KDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQojIE9VVFBVVA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQpjYXQoIlxuS29sb20gJ2RhdGFfc3RhdHVzJyBiZXJoYXNpbCBkaXRhbWJhaGthbi5cbiIpDQoNCmNhdCgiXG5QcmV2aWV3IENvdW50cmllczpcbiIpDQpwcmludChrbml0cjo6a2FibGUoaGVhZChjb3VudHJpZXNfZGYsIDEwKSwgYWxpZ24gPSAiYyIpKQ0KDQpjYXQoIlxuUHJldmlldyBIb2NrZXkgVGVhbXM6XG4iKQ0KcHJpbnQoa25pdHI6OmthYmxlKGhlYWQoaG9ja2V5X2RmLCAxMCksIGFsaWduID0gImMiKSkNCmBgYA0KDQojIyBTRUNUSU9OIEUg4oCTIEFOQUxZVElDQUwgVEhJTktJTkcNCg0KKioxLiBXZWJzaXRlIG1hbmEgcGFsaW5nIG11ZGFoIGRpLXNjcmFwZT8qKg0KDQpCZXJkYXNhcmthbiBkYXRhc2V0IHlhbmcgZGlndW5ha2FuLCB5YWl0dSAqQ291bnRyaWVzIG9mIHRoZSBXb3JsZCogZGFuICpIb2NrZXkgVGVhbXMsKiB0ZXJkYXBhdCBwZXJiZWRhYW4gdGluZ2thdCBrZW11ZGFoYW4gZGFsYW0gcHJvc2VzIHNjcmFwaW5nLg0KDQpXZWJzaXRlIFBhbGluZyBNdWRhaCBkaS1TY3JhcGU6ICpDb3VudHJpZXMgb2YgdGhlIFdvcmxkKg0KDQpBbGFzYW4gOiBXZWJzaXRlIGluaSBtZW1pbGlraSBzdHJ1a3R1ciBTdGF0aXMuIFNlbHVydWggZGF0YSB0ZXJzZWRpYSBkYWxhbSBzYXR1IGRva3VtZW4gSFRNTCB0dW5nZ2FsIGRlbmdhbiBwZW5hbWFhbiBjbGFzcyB5YW5nIGtvbnNpc3Rlbiwgc2VoaW5nZ2EgcGVuZ2FtYmlsYW4gZGF0YSBkYXBhdCBkaWxha3VrYW4gc2VjYXJhIGVmaXNpZW4gbWVuZ2d1bmFrYW4gZnVuZ3NpIGRhc2FyIGRhcmkgbGlicmFyeSBydmVzdCB0YW5wYSBtZW1lcmx1a2FuIGxvZ2lrYSBwZXJ1bGFuZ2FuIHlhbmcga29tcGxla3MuDQoNCioqMi4gV2Vic2l0ZSBtYW5hIHBhbGluZyBzdWxpdD8qKg0KDQpXZWJzaXRlIFBhbGluZyBTdWxpdCBkaS1TY3JhcGU6ICpIb2NrZXkgVGVhbXMqDQoNCkFsYXNhbiA6IFdlYnNpdGUgaW5pIG1lbmdpbXBsZW1lbnRhc2lrYW4gbWVrYW5pc21lIFBhZ2luYXRpb24gKHBlbWJhZ2lhbiBkYXRhIHBlciBoYWxhbWFuKS4gVGFudGFuZ2FuIHV0YW1hIG1lbGlwdXRpIHBlcmx1bnlhIHBlbmdlbG9sYWFuIFVSTCB5YW5nIGRpbmFtaXMsIHBlbmFuZ2FuYW4gZGVsYXkgYW50YXIgcGVybWludGFhbiAocmVxdWVzdCksIGRhbiByaXNpa28gaW5rb25zaXN0ZW5zaSBkYXRhIGFudGFyIGhhbGFtYW4geWFuZyBtZW1lcmx1a2FuIHBlbWJlcnNpaGFuIGxlYmloIGludGVuc2lmIHBhZGEgdGFoYXAgYmVyaWt1dG55YS4NCg0KKiozLiBQZXJiZWRhYW4gcGVuZGVrYXRhbjoqKg0KDQpCZWJlcmFwYSBtZXRvZGUgdW11bSBkYWxhbSBwZW55YWppYW4gZGF0YSBkaSB3ZWIgYWRhbGFoIHNlYmFnYWkgYmVyaWt1dDoNCg0KMS4gICoqU3RhdGljKio6IERhdGEgZGlzYWppa2FuIGxhbmdzdW5nIGRpIGRhbGFtIHN0cnVrdHVyIEhUTUwgc2FhdCBoYWxhbWFuIHBlcnRhbWEga2FsaSBkaW11YXQsIHNlaGluZ2dhIGRhcGF0IGRpYWtzZXMgdGFucGEgaW50ZXJha3NpIHRhbWJhaGFuLg0KDQoyLiAgKipQYWdpbmF0aW9uKio6IERhdGEgZGliYWdpIGtlIGRhbGFtIGJlYmVyYXBhIGhhbGFtYW4geWFuZyB0ZXJwaXNhaCwgc2VoaW5nZ2EgcGVuZ2d1bmEgcGVybHUgYmVycGluZGFoIGhhbGFtYW4gdW50dWsgbWVsaWhhdCBrZXNlbHVydWhhbiBkYXRhLg0KDQozLiAgKipBSkFYKio6IERhdGEgZGltdWF0IHNlY2FyYSBhc2lua3JvbiBtZW5nZ3VuYWthbiBwZXJtaW50YWFuIHRhbWJhaGFuIGtlIHNlcnZlciB0YW5wYSBwZXJsdSBtZW11YXQgdWxhbmcgc2VsdXJ1aCBoYWxhbWFuLg0KDQo0LiAgKipJZnJhbWUqKjogRGF0YSBkaXRhbXBpbGthbiBtZWxhbHVpIGVsZW1lbiBiaW5na2FpIHlhbmcgbWVuZ2FtYmlsIGtvbnRlbiBkYXJpIHN1bWJlciBhdGF1IGhhbGFtYW4gbGFpbi4NCg0KLSAgIFRhYmVsIGJlcmlrdXQgbWVuamVsYXNrYW4gcGVyYmVkYWFuIHRla25pcyBkYXJpIGJlcmJhZ2FpIG1ldG9kZSBwZW55YWppYW4gZGF0YSBkaSB3ZWI6DQoNCnwgUGVuZGVrYXRhbiB8IE1la2FuaXNtZSBQZW55YWppYW4gRGF0YSB8IFRhbnRhbmdhbiBTY3JhcGluZyB8DQp8LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18DQp8IFN0YXRpYyB8IERhdGEgZGltdWF0IGxhbmdzdW5nIGRhbGFtIHN0cnVrdHVyIEhUTUwgc2FhdCBoYWxhbWFuIHBlcnRhbWEga2FsaSBkaWFrc2VzLiB8IFJlbGF0aWYgcmVuZGFoOyBjdWt1cCBtZW5nZ3VuYWthbiBwZW1pbGloIENTUyBhdGF1IFhQYXRoIHN0YW5kYXIuIHwNCnwgUGFnaW5hdGlvbiB8IERhdGEgZGliYWdpIGtlIGRhbGFtIGJlYmVyYXBhIHN1Yi1oYWxhbWFuIHVudHVrIG9wdGltYXNpIGJlYmFuIHNlcnZlci4gfCBNZW1idXR1aGthbiBwZXJ1bGFuZ2FuIChsb29waW5nKSBkYW4gbWFuYWplbWVuIFVSTCB5YW5nIHNpc3RlbWF0aXMuIHwNCnwgQUpBWCB8IERhdGEgZGltdWF0IHNlY2FyYSBhc2lua3JvbiB0YW5wYSBtZW1wZXJiYXJ1aSBrZXNlbHVydWhhbiBoYWxhbWFuLiB8IE1lbWVybHVrYW4gaW5zcGVrc2kgcGFkYSBOZXR3b3JrIFRhYiB1bnR1ayBtZW5lbXVrYW4gc3VtYmVyIEFQSSBhc2xpLiB8DQp8IElmcmFtZSB8IERhdGEgZGl0YW1waWxrYW4gZGkgZGFsYW0gYmluZ2thaSAoZnJhbWUpIHlhbmcgYmVyYXNhbCBkYXJpIFVSTCBla3N0ZXJuYWwuIHwgSGFydXMgbWVuZ2Vrc3RyYWtzaSBVUkwgc3VtYmVyIGFzbGkgZGkgZGFsYW0gdGFnIGA8aWZyYW1lPmAgdGVybGViaWggZGFodWx1LiB8DQo=