1 CHƯƠNG 1: Giới thiệu chung

1.1 Đặt vấn đề

Trong thời đại hiện nay, phân tích dữ liệu đóng vai trò vô cùng quan trọng và mang lại nhiều lợi ích trong nhiều lĩnh vực khác nhau. Các công việc như là xử lý dữ liệu cũng như phân tích văn bản ngày càng phổ biến và đòi hỏi sự tỉ mỉ hơn. Chính vì vậy nên nó làm chúng ta mất nhiều thời gian hơn. Để giải quyết những thách thức này, thì có nhiều cách khác nhau nhưng theo em thấy thì gói Stringr vẫn là tiện dụng nhất. Chúng ta có thể dùng nó để phân tích dữ liệu cũng như trích xuất các ngôn ngữ đặc trưng trong việc nghiên cứu tâm lý, sự tương tác và ngữ nghĩa trong dữ liệu văn bản.Ngoài ra, Stringr còn cung cấp các công cụ để tách từ, tách câu và thực hiện phân tích các ngôn ngữ khác. Điều này giúp chúng ta nghiên cứu phân tích các yếu tố ngôn ngữ dễ dàng hơn.

1.2 Gói Stringr

1.2.1 Nguồn gốc

Gói Stringr là một phần của Tidyverse, một bộ các gói R được phát triển bởi Hadley Wickham và nhóm của ông tại công ty RStudio. Tidyverse được thiết kế để cung cấp một cú pháp dễ đọc, nhất quán và hiệu quả cho việc làm việc với dữ liệu trong R. Gói Stringr được tạo ra để cung cấp các công cụ mạnh mẽ và dễ sử dụng cho xử lý chuỗi ký tự trong R. Hadley Wickham đã nhận thấy rằng việc xử lý và biến đổi chuỗi là một phần quan trọng trong quá trình tiền xử lý dữ liệu và phân tích dữ liệu văn bản. Do đó, ông đã phát triển gói “Stringr” nhằm giúp các nhà phân tích dữ liệu và người sử dụng R thực hiện các tác vụ xử lý chuỗi một cách dễ dàng và hiệu quả hơn. Gói Stringr đã được phát hành lần đầu tiên vào năm 2010 và tiếp tục được phát triển và duy trì trong thời gian kế tiếp. Nó đã trở thành một công cụ phổ biến trong cộng đồng R và được sử dụng rộng rãi trong nhiều lĩnh vực như xử lý ngôn ngữ tự nhiên, phân tích dữ liệu văn bản, khai phá dữ liệu, và nhiều ứng dụng khác liên quan đến chuỗi ký tự. Nguồn gốc của gói Stringr và các gói khác trong Tidyverse xuất phát từ tầm nhìn của Hadley Wickham về cách làm việc hiệu quả và nhất quán với dữ liệu trong R.

1.2.2 Giới thiệu biểu thức chính quy

Biểu thức chính quy được bắt nguồn từ năm 1951, khi nhà toán học Stephen Cole Kleene mô tả cả ngôn ngữ chính quy bằng cách sử dụng ký hiệu toán học của ông được gọi là các sự kiện chính quy. Biểu thức chính quy (Regular Expression hay Regex) được sử dụng phổ biển từ năm 1968 với hai mục đích sử dụng là một chuỗi các ký tự khớp với một mẫu trong soạn thảo văn bản và phân tích từ vựng trong trình biên dịch. Regex được sử dụng trong soạn thảo văn bản trong rất nhiều ngôn ngữ lập trình. Các ký tự của biểu thức chính quy khá giống nhau trong tất cả các ngôn ngữ. Nhưng các chức năng trích lọc, định vị, phát hiện, tìm kiếm và thay thế có thể khác nhau ở các ngôn ngữ khác nhau.

Biểu thức chính quy được tạo ra bằng cách sử dụng các ký tự đặc biệt và ký tự thông thường để mô tả một mẫu ký tự cụ thể. Mỗi ký tự trong một biểu thức chính quy là một siêu ký tự, có ý nghĩa đặc biệt hoặc một ký tự thông thường có nghĩa đen. Khi một biểu thức chính quy được áp dụng cho một chuỗi văn bản, nó sẽ tìm kiếm các điểm trùng khớp với mẫu đã định nghĩa. Cú pháp siêu ký tự được thiết kế đặc biệt để biểu thị các mục tiêu được chỉ định theo cách ngắn gọn và linh hoạt nhằm hướng tự động hóa quá trình xử lý văn bản của nhiều loại dữ liệu đầu vào.

Dưới đây là một số ký tự đặc biệt thường được sử dụng trong biểu thức chính quy:

  • Ký tự thông thường: Đại diện cho chính nó. Ví dụ: “a” tìm kiếm ký tự “a” trong chuỗi

  • Dấu chấm (“.”): Đại diện cho bất kỳ ký tự nào, ngoại trừ ký tự xuống dòng.

  • Ký tự đặc biệt “” (backslash): Thường được sử dụng để làm cho ký tự sau nó không còn là ký tự đặc biệt mà trở thành ký tự thông thường. Ví dụ: “.” tìm kiếm dấu chấm thay vì áp dụng chức năng đặc biệt của dấu chấm.

  • Ký tự “[]”: Khớp các ký tự hoặc trong dấu ngoặc.

  • Ký tự “*”: Đại diện cho bất kỳ số lượng xuất hiện của ký tự trước nó (bao gồm cả không xuất hiện).

  • Ký tự “+”: Đại diện cho ít nhất một hoặc nhiều lần xuất hiện của ký tự trước nó.

  • Ký tự “?”: Đại diện cho không hoặc một lần xuất hiện của ký tự trước nó.

  • Ký tự “{}”: Xác định số lượng xuất hiện của ký tự trước nó. Ví dụ: “a{3}” tìm kiếm chuỗi “aaa”.

  • Ký tự “|”: Đại diện cho phép tìm kiếm một trong các biểu thức được định nghĩa. Ví dụ: “cat|dog” tìm kiếm từ “cat” hoặc “dog”.

  • Ký tự “^” và “$” : là điểm bắt đầu và điểm kết thúc của dòng

  • Đối với tất cả các dấu chấm câu, dấu gạch chéo ngược được đặt ở phía trước. Ví dụ “?” là biểu thức chính quy cho dấu chấm hỏi: “?”. Nhưng để viết “?” trong R, chúng ta phải sử dụng hai dấu gạch chéo ngược: “\?”

  • Đối với bất kỳ chữ số nào, cũng có thể sử dụng cụm từ thông dụng ” or also”[:digit:]“. Đối với các ký tự từ, bạn sử dụng”” hoặc “[:alpha:]” như một biểu thức chính quy.

  • “[:lower:]” và “[:upper:]”: Tương đương với [a-z]và [A-Z]tương ứng. Dùng để liệt kê các ký tự trong bảng chữ cái dưới dạng chữ thường và chữ in hoa.

  • “[:alnum:]”: Đại diện cho tất cả các ký tự chữ và số. Chúng giúp liệt kê các ký tự chữ cái bao gồm chữ hoa và chữ thường cùng với các số từ 0 đến 9

  • “[:punct:]”: So khớp các ký tự dấu chấm câu.

  • “[:space:]”: So khớp khoảng trắng như dấu cách, tab, dòng mới,…

  • “[:print:]”: Mọi thứ có thể in được.

1.2.3 Các chức năng của gói Stringr

Để đưa ra định hướng chung về các chức năng, nhóm chúng tôi sẽ trình bày tổng quan ngắn gọn về một số chức năng được sử dụng phổ biến nhất của gói Stringr

1.2.3.1 Quản lý độ dài

  • str_length(): Hàm str_length() trong gói Stringr trả về một vector chứa độ dài của từng chuỗi ký tự trong một vector chuỗi. Khi được áp dụng cho một vectơ, nó trẻ về một vectơ trong đó mỗi mục biểu thị số lượng ký tự trong một chuỗi tương ứng.

  • str_pad(): Hàm str_pad() trong gói Stringr có chức năng thêm các ký tự vào bên trái hoặc bên phải của chuỗi (dưới dạng khoảng trắng mặc định). Độ rộng đối số cho biết độ dài của chuỗi sau khi thêm các ký tự bổ sung.

  • str_trunc(): Hàm str_trunc() trong gói Stringr có chức năng rút ngắn chuỗi thành chiều rộng đối số đã cho. Cạnh mà chuỗi bị cắt được xác định bởi đối số cạnh.

  • str_trim(): Hàm str_trim() trong gói String có chức năng cắt ngắn các khoảng trắng từ đầu hoặc cuối hoặc cả hai.

1.2.3.2 Chuỗi con

  • str_sub(): Hàm str_sub() trong gói String có chức năng trả về mội chuỗi con của một chuỗi đã cho. Nó có ba tham số: - Chuỗi (hoặc một vectơ của chuỗi) - Chỉ số bắt đầu của chuỗi con - Chỉ số kết thúc của chuỗi con

  • str_subset(): Hàm str_subset() có chức năng trả về các chuỗi chứa mẫu khớp. Hàm tìm kiếm tất cả các chuỗi có mẫu đối số trong đó và trả cề tất cả các chuỗi phù hợp dưới dạng một tập hợp chuỗi nhỏ hơn. Nó có hai tham số: vectơ của chuỗi để tìm kiếm và chính mẫu tìm kiếm.

  • str_extract(): Hàm str_extract() có chức năng trả về kết quả khớp mẫu đầu tiên được tìm thấy trong mỗi chuỗi dưới dạng một vectơ ký tự.

  • str_match(): Hàm str_match() có chức năng trả về kết quả khớp mẫu đầu tiên được tìm thấy trong mỗi chuỗi, dưới dạng một ma trận với một cột cho mỗi nhóm () trong mẫu.

1.2.3.3 Phát hiện kết quả trùng khớp

  • str_detect(): Hàm str_detect() có chức năng phát hiện sự hiện diện của một mẫu phù hợp trong một chuỗi. Kết quả đơn giản là nếu mẫu được tìm thấy, hàm sẽ trả về TRUE và nếu không được tìm thấy, nó sẽ trả về FALSE

  • str_which(): Hàm str_which() có chức năng tìm các chỉ số của các chuỗi chứa mẫu khớp. Đầu ra là một vectơ với các chỉ số này

  • str_count(): Hàm str_count() có chức năng đếm số lần một mẫu tìm kiếm xấu hiện trong một chuỗi.Nó nhận hai tham số: chuỗi thực hiện tìm kiếm (hoặc một vectơ chuỗi) và mẫu tìm kiếm cũng có thể là một biểu thức chính quy.

  • str_locate(): Hàm str_locate() có chức năng xác định vị trí của mẫu khớp đầu tiên trong một chuỗi

1.2.3.4 Biến đổi chuỗi

  • str_replace (và replace_all): Hàm str_replace() có chức năng thay thế của chuỗi Stringr được sử dụng để khớp các mẫu và thay thế chúng bằng các chuỗi mới

  • str_to_lower(): Hàm str_to_lower() có chức năng để thay đổi văn bản thành chữ thường. Trong đó còn có các hàm:

  1. str_to_title(): Viết hoa chữ cái đầu tiên của mỗi từ trong một chuỗi

  2. str_to_upper(): Viết hoa toàn bộ chuỗi

1.2.3.5 Tham gia và chia tách

  • str_c(): Hàm str_c() có chức năng để nối nhiều chuỗi thành một chuỗi.

  • str_split(): Hàm str_split() có chức năng tách một chuỗi hoặc một vectơ của các chuỗi thành một vectơ của các chuỗi con hoặc một danh sách các vectơ của các chuỗi con, tùy thuộc vào định dạng của dữ liệu được truyền vào.

1.3 Lí do chọn chủ đề

R là một ngôn ngữ lập trình và môi trường phân tích dữ liệu phổ biến trong thời đại 4.0. Khi học R nhóm chúng em nhận thấy rằng, việc xử lý dữ liệu trong văn bản rất quan trọng trong việc thực hiện các nghiên cứu và phân tích dữ liệu. Để xử lý tốt một văn bản thì cần có các công cụ mạnh mẽ để tách, chuẩn hóa văn bản và xử lý các kí tự đặc biệt nên nhóm chúng em đã lựa chọn gói Stringr làm chủ đề để thực hiện các nghiên cứu và phân tích dữ liệu.

Ngoài ra, gói Stringr còn cung cấp các công cụ mạnh mẽ để xử lý, tách, chuẩn hóa và trích xuất thông tin từ dữ liệu văn bản. Sử dụng gói này trong bài tiểu luận giúp chúng em có khả năng hiểu và xử lý dữ liệu văn bản hiệu quả phù hợp với xu hướng và yêu cầu của thời đại 4.0. Thêm nữa gói Stringr được thiết kế để đạt hiệu suất cao trong xử lý chuỗi, đặc biệt là trên dữ liệu lớn. Việc sử dụng gói này giúp chúng em tiết kiệm thời gian và tăng tính hiệu quả trong quá trình xử lý dữ liệu chuỗi phức tạp

1.4 Mục tiêu của chủ đề

Mục tiêu chung : Sử dụng gói Stringr một cách tối ưu và hiệu quả trong quá trình làm tiểu luận. Chúng em phải tìm hiểu các chức năng và phương pháp trong package để giảm thiểu thời gian và công sức cần thiết cho xử lý chuỗi, đồng thời tăng tính linh hoạt và khả năng áp dụng vào các tác vụ xử lý chuỗi phức tạp.

Mục tiêu cụ thể:

  • Mục tiêu 1: Biết xử lý và chuẩn hóa dữ liệu văn bản gì gói “stringr” cung cấp các hàm để loại bỏ khoảng trắng thừa, ký tự đặc biệt, dấu câu hoặc các ký tự không mong muốn trong văn bản. Điều này giúp tiền xử lý dữ liệu văn bản trước khi tiến hành phân tích, đồng thời chuẩn hóa dữ liệu để làm việc hiệu quả hơn.
  • Mục tiêu 2: BIết cách tách từ và trích xuất thông tin, ví dụ có thể tách từ trong văn bản hoặc trích xuất các thông tin quan trọng như tên, số điện thoại, địa chỉ email, v.v. từ chuỗi dữ liệu
  • Mục tiêu 3: Biết cách tách, ghép, chuẩn hóa, tìm kiếm hoặc thay thế các chuỗi trong dữ liệu của mình, và sau đó phân tích và báo cáo kết quả một cách chi tiết và rõ ràng.
  • Mục tiêu 4: Biết kiểm tra và so sánh chuỗi vì package “stringr” cung cấp các hàm để kiểm tra và so sánh chuỗi, giúp kiểm tra tính hợp lệ của định dạng, tìm kiếm chuỗi con trong chuỗi cha, và thực hiện các phép toán so sánh chuỗi.
  • Mục tiêu 5: Sử dụng biểu thức chính quy linh hoạt: Gói “stringr” hỗ trợ sử dụng biểu thức chính quy trong việc tìm kiếm và thay thế các mẫu trong chuỗi. Điều này cho phép bạn thực hiện các tác vụ phức tạp như tìm kiếm theo mẫu, lọc dữ liệu, và thay đổi định dạng chuỗi dễ dàng.

1.5 Lợi ích của chủ đề

Gói Stringr trong Rstudio đã mang lại nhiều lợi ích đáng kể cho việc xử lý dữ liệu nhưng nó cũng có thể được sử dụng để phân tích văn bản, đặc biệt là trong việc xử lý và biến đổi chuổi kí tự. Một số lợi ích chính của gói Stringr:

  1. Dễ sử dụng: Stringr được thiết kế thân thiện và dễ sử dụng, ngay cả đối với người mới bắt đầu chưa có kinh nghiệm lập trình. Nó cung cấp một loạt các công cụ và chức năng giúp dễ dàng khám phá, làm sạch, trực quan hóa và phân tích dữ liệu.
  2. Các tính năng mạnh mẽ: Mặc dù đơn giản nhưng Stringr có một loạt các tính năng nâng cao cho phép bạn thực hiện các tác vụ phân tích dữ liệu phức tạp. Chúng bao gồm các thuật toán học máy, kiểm tra thống kê và chức năng chuyển đổi dữ liệu.
  3. Được sử dụng rộng rãi: Stringr là một gói phổ biến trong R, với cộng đồng người. Điều đó có nghĩa là chúng ta có thể tìm thấy nhiều tài liệu và hỗ trợ trực tuyến nếu bạn có bất kỳ câu hỏi nào hoặc cần trợ giúp về một nhiệm vụ cụ thể.
  4. Tính linh hoạt: R là một ngôn ngữ lập trình mạnh mẽ cho phép bạn tùy chỉnh quy trình phân tích dữ liệu cho phù hợp với nhu cầu của mình. Với Stringr, chúng ta có thể truy cập đầy đủ các khả năng của R và tích hợp nó với các gói và công cụ khác.
  5. Tích hợp tốt với các gói khác trong Tidyverse: Gói “Stringr” được phát triển như một phần của “tidyverse”, vì vậy nó tích hợp tốt với các gói khác trong “tidyverse” như “dplyr”, “ggplot2”, và “tidyr”. Điều này cho phép chúng ta kết hợp các công cụ phân tích dữ liệu khác và thực hiện các tác vụ phức tạp trên dữ liệu chuỗi một cách linh hoạt và mạnh mẽ.

Gói Stringr là một lựa chọn tốt để phân tích dữ liệu trong R do dễ sử dụng, các tính năng mạnh mẽ, được áp dụng rộng rãi và linh hoạt, đồng thời kết hợp tốt với các gói trong “Tidyverse”.

2 CHƯƠNG 2: Thao tác với chức năng của Stringr

Trong chương này nhóm chúng tôi sẽ đi sâu vào cách làm việc phân tích các với chuỗi trong R và phân tích đi sâu vào cách làm việc của hàm trong Stringr để xử lí các chuỗi. Trọng tâm của chương này sẽ là biểu thức chính quy, biểu thức chính quy là ngôn ngữ hữu ích đối với gói Stringr vì các chuỗi thường chứa dữ liệu phi cấu trúc hoặc bán cấu trúc và biểu thức chính quy là ngôn ngữ ngắn gọn để mô tả các mẫu trong chuỗi.

2.1 Giới thiệu chuỗi

Chuỗi ký tự có thể xuất hiện trong tất cả các dự án của khoa học dữ liệu. Người dùng có thể phải xóa đầu vào chuỗi lộn xộn trước khi phân tích, trích xuất dữ liệu được nhúng trong văn bản hoặc tự động biến các kết quả dạng số thành một câu để đưa vào báo cáo. Bản thân các chuỗi là dữ liệu quan tâm và chúng ta cần phát hiện và khớp các mẫu bên trong chúng. Chúng em sẽ bắt đầu với một số thao tác cơ bản: cách nhập chuỗi trong R, cách kiểm soát cách số được chuyển đổi thành chuỗi và cuối cùng là cách kết hợp các chuỗi với nhau để tạo đầu ra kết hợp văn bản và số được định dạng độc đáo.

2.2 Bộ dữ liệu

Dưới đây là hai bộ dữ liệu đã được cài đặt sẳn trong gói Stringr, bao gồm fruit cho chúng ta biết 79 loại trái cây và dữ liệu sentences bao gồm 720 dòng. Tôi dùng lệnh head() để xem 6 dòng đầu của 2 bộ dữ liệu:

fruit = stringr::fruit
head(fruit)
## [1] "apple"       "apricot"     "avocado"     "banana"      "bell pepper"
## [6] "bilberry"
sentences = stringr::sentences
head(sentences)
## [1] "The birch canoe slid on the smooth planks." 
## [2] "Glue the sheet to the dark blue background."
## [3] "It's easy to tell the depth of a well."     
## [4] "These days a chicken leg is a rare dish."   
## [5] "Rice is often served in round bowls."       
## [6] "The juice of lemons makes fine punch."

Để thực hiện tốt hơn chúng em sẽ gọi gói “babyname”“dplyr” để hổ trọ cho việc phân tích chuỗi và các hàm.

library(dplyr)
## Warning: package 'dplyr' was built under R version 4.2.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(babynames)
## Warning: package 'babynames' was built under R version 4.2.3

Trước tiên,chúng em sẽ sử dụng gói “babynames” để gọi xử lý dữ liệu về các tên trẻ em phổ biến theo năm và giới tính

babynames = babynames::babynames
head(babynames)
## # A tibble: 6 × 5
##    year sex   name          n   prop
##   <dbl> <chr> <chr>     <int>  <dbl>
## 1  1880 F     Mary       7065 0.0724
## 2  1880 F     Anna       2604 0.0267
## 3  1880 F     Emma       2003 0.0205
## 4  1880 F     Elizabeth  1939 0.0199
## 5  1880 F     Minnie     1746 0.0179
## 6  1880 F     Margaret   1578 0.0162

2.3 Thao tác chuỗi cơ bản

Chúng em sẽ bắt đầu bằng cách tìm hiểu về một số hàm Stringr rất giống với một số hàm R cơ sở, sau đó là cách phát hiện các mẫu cụ thể trong chuỗi, cách tách chuỗi thành nhiều phần cũng như cách tìm và thay thế các phần của chuỗi.

Các chức năng của Stringr đều bắt đầu bằng str_ điều này tạo điều kiện thuận lợi cho việc tìm lệnh thích hợp. Chúng ta chỉ cần nhập str_ và chức năng tự động đề xuất của Rstudio sẽ hiện thị những phần còn lại.

Đầu tiên để thực hiện các chức năng liên quan đến chuỗi thì chúng ta cần cài đặt và gọi gói Stringr lên.

library(stringr)

2.3.1 Quản lý độ dài chuỗi

1. str_length(string): Trả về một độ dài của một chuỗi bao gồm cả khoảng trắng và cả dấu chấm câu. Trong đó string là một vecto đầu vào hoặc là một vecto kí tự.

str_length(sentences[2])
## [1] 43

=> Kết quả này trả về cho chúng ta biết độ dài của dòng thử 2 của sentences bao gồm 43 kí tự bao gồm cả khoảng trắng.

Ví dụ: Trích xuất vector tên con trai và tên con gái trong năm 2014. Chọn những hàng có giá trị trong cột “sex” là “M” (nam giới),cột “sex” là “F” (nữ giới) và sau đó chỉ lấy các giá trị trong cột “name”

babynames_2014 <- filter(babynames, year == 2014)
boy_names <- filter(babynames_2014, sex == "M")$name
girl_names <- filter(babynames_2014, sex == "F")$name

head(boy_names)
## [1] "Noah"    "Liam"    "Mason"   "Jacob"   "William" "Ethan"

Bây giờ em sẽ dùng chứng năng str_length để tìm độ dài của tất cả các tên trong boy_names mà đã được liệt kê ở trên, sau đó em dùng lệnh head() để xem kết quả trả về của độ dài các tên đó

boy_length <- str_length(boy_names)
head(boy_length)
## [1] 4 4 5 5 7 5

Chúng ta cũng có thể dùng hàm chứng năng str_length để so sánh độ dài trung bình giữa tên con gái và con trai và câu lệnh phía dưới chúng em sẽ thực hiện lệnh đó:

girl_length <- str_length(girl_names)
mean(girl_length) - mean(boy_length)
## [1] 0.3374758

=> Kết quả trả về cho thấy độ dài trung bình của các tên trong girls_name dài hơn boy_name là 0.3374758

Kết luận: Độ dài trung bình của tên con gái vào năm 2014 dài hơn một ký tự khoảng một phần ba. Đây là con số trung bình ngây thơ trong đó mỗi cái tên được tính một lần, không phải theo số lượng em bé đã nhận được tên. Một phép so sánh tốt hơn có thể là trọng số trung bình của cột n trong babynames

2.Đệm chuỗi bằng str_pad()

Đệm chuỗi liên quan đến việc thêm các ký tự vào một chuỗi để làm cho nó có độ dài nhất định. Hàm str_pad() trong gói Stringr được sử dụng để đệm chuỗi và kết quả sẽ trả về một vecto chứa các chuỗi được đệm. Dưới đây là một số tham số trong hàm.

Cú pháp: str_pad(string,width, side = c(“left”,“right”,“both”),pad = ” “):

Trong đó:

  • String: chuỗi đầu vào mà chúng ta muốn đệm
  • width: Độ rộng mong muốn của chuỗi kết quả sau khi đệm
  • Side: Chỉ định đệm các chuỗi ở bên trái, bên phải hay cả hai bên
  • Pad: Ký tự dùng để đệm. Giá trị mặc định là khoảng trắng(” “)

Ví dụ 1: Em đệm thêm 15 kí tự là khoảng trắng ở phía bên trái cho chuỗi fruit ở dòng 1 là apple

str_pad(fruit[1],width = 15, side = 'left')
## [1] "          apple"

Ví dụ 2: Em đệm thêm 20 khoảng trắng ở cả hai bên bằng dấu ” - “ cho fruit ở dòng 2 là apricot

str_pad(fruit[2],width = 20, side = 'both', pad = '-' )
## [1] "------apricot-------"

Ví dụ 3: Em đệm thêm 50 khoảng trắng bằng số 0 vào chuỗi sentences ở dòng thứ 2 của chuỗi và kết quả trả về kết quả dưới đây:

str_pad(sentences[2],width = 50, side = 'right', pad = '0')
## [1] "Glue the sheet to the dark blue background.0000000"

Ví dụ 4: Trong ví dụ này em muốn đệm thêm 100 kí tự là dấu “.” ở bên phải vào chuỗi sentences ở dòng thứ 5. Và câu lệnh trả về kết quả:

str_pad(sentences[5],width = 100, side = 'right', pad = '.')
## [1] "Rice is often served in round bowls................................................................."

Ví dụ 5: Thêm khoảng trắng vào một chuỗi (đối với một ký tự)

str_pad("boy_names",11,side = "both") #cho biet do dai sau khi them la 11
## [1] " boy_names "

Tham số pad có thể chỉ định các ký tự cần điền

str_pad("boy_names",11,side = "both",pad = "*")
## [1] "*boy_names*"

Kết hợp với gói Purrr, lập trình chức năng có thể được vector hóa để loại bỏ khoảng trắng và thêm khoảng trắng

x <- c("boy_names","girl_names")
library(purrr)
map_chr(x,str_pad,11,side = "left")
## [1] "  boy_names" " girl_names"
str_c(x[seq_len(3) - 1],collapse = ",")
## [1] "boy_names,girl_names"

3. Rút ngắn chuỗi bằng str_trunc()

Rút ngắn chuỗi liên quan đến việc rút ngắn các ký tự ở đầu, cuối hoặc ở giữa của chuỗi. Hàm str_trunc() trong gói Stringr có chức năng rút ngắn chuỗi thành chiều rộng đối số đã cho, cạnh mà chuỗi bị cắt được xác định bởi đối số cạnh.

Cú pháp: str_trunc(string,width, side = c(“left”,“right”,“center”):

  • string: là chuỗi đầu vào mà chúng ta muốn cắt
  • width: chiều rộng tối đa của chuỗi
  • side: Vị trí cho biết nội dung đã bị xóa

Ví dụ: Trong ví dụ này chúng em dùng chức năng str_trunc để cắt 17 kí tự ở phía bên phải của chuỗi sentences ở dòng thứ 2 và kết quả trả về là:

str_trunc(sentences[1],width = 17,side = 'right')
## [1] "The birch cano..."

4. Cắt xén chuỗi bằng str_trim()

Cắt xén chuỗi liên quan đến việc loại bỏ các ký tự trắng ở đầu hoặc cuối chuỗi. Hàm str_trim() trong gói Stringr được sử dụng để cắt chuỗi và kết quả trả về một vecto ký tự chứa các chuỗi đã cắt. Dưới đây là các tham số trong hàm.

Cú pháp: str_trim(string,side = c(“left”,“right”,“both”))

Trong đó:

  • string: Tham số này đại diện cho chuỗi ký tự hoặc vecto của chuỗi sẽ được cắt bớt
  • side: Tham số này chỉ định cho các bên của chuỗi cần cắt, có thể là phía phải, trái hoặc cả hai bên

Ví dụ:

str_trim(sentences[5],side = 'left')
## [1] "Rice is often served in round bowls."

Loaị bỏ các khoảng trắng dư thừa ở đầu và cuối của một chuỗi ký tự

str_trim(" boy_names ")
## [1] "boy_names"

Chúng cũng có thể chỉ định phần cuối của khoảng trống cần xóa. Ví dụ loại bỏ các khoảng trắng dư thừa ở phía bên trái của một chuỗi ký tự:

str_trim(" boynames ",side = "left")
## [1] "boynames "

2.3.2 Chuỗi con

1. Trích xuất dữ liệu bằng cách sử dụng str_sub()

Trích xuất chuỗi con liên quan đến việc trích một phần của chuỗi. Hàm str_sub() trong gói Stringr được sử dụng để trích xuất hoặc thay thế các chuỗi con. Dưới đây là một số tham số được sử dụng trong hàm str_sub():

Cú pháp: str_sub(string, start = 1L, end = -1L)

  • string: là vecto đầu vào hoặc là một vecto kí tự
  • start: chỉ định vị trí ký tự đầu tiên trong chuỗi con sẽ được trích xuất
  • end: Chỉ định vị trí của ký tự cuối cùng trong các chuỗi con sẽ được trích xuất

Ví dụ: str_sub(x, 1, 3) yêu cầu chuỗi con bắt đầu từ ký tự đầu tiên, cho đến ký tự thứ ba hoặc nói cách khác là ba ký tự đầu tiên.

bg <- c("boy_names","girl_names")
str_sub(bg,1,3)
## [1] "boy" "gir"

Ví dụ: chúng ta có thể trích xuất chuỗi con với những kí tự cuối chuỗi bằng số nguyên âm. Trong ví str_sub(bg,-3,-1) yêu cầu chuỗi con bằng 3 kí tự cuối chuỗi.

str_sub(bg,-3,-1)
## [1] "mes" "mes"

Bên cạnh đó chúng ta có thể trích xuất các chữ cái đâu tiên trong boy_names sau đó chúng ta lập bảng.

boy_first_letter <- str_sub(boy_names, 1, 1)
table(boy_first_letter)
## boy_first_letter
##    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O    P 
## 1454  651  770  998  549  185  334  403  235 1390 1291  537  914  424  207  230 
##    Q    R    S    T    U    V    W    X    Y    Z 
##   56  778  806  771   43  160  174   56  252  379

=> Kết quả cho chúng ta biết có 1454 người có tên bắt đầu bằng chữ A, có 651 người bắt đầu bằng chữ B,…

Hoặc là chúng ta có thể trích xuất chữ cái cuối cùng trong boy_names và sau đó lập bảng

boy_last_letter <- str_sub(boy_names, -1, -1)
table(boy_last_letter)
## boy_last_letter
##    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o    p 
##  421  104   92  436 1148   66   82  583  705   57  349  945  389 4672  730   32 
##    q    r    s    t    u    v    w    x    y    z 
##   19 1011  826  292   81   71   34   86  697  119

=> Kết quả trả về cho chúng ta biết có 421 người có tên kết thúc bằng chữ a, 104 người có tên kết thức bằng chữ b,..,

Kết luận: “A” là chữ cái đầu tiên phổ biến nhất cho cả bé trai và bé gái, và là chữ cái cuối cùng phổ biến nhất cho bé gái. Tuy nhiên, chữ cái cuối cùng phổ biến nhất cho tên con trai là “n”. Chúng có thể đã thấy substr() một hàm R cơ sở tương tự như str_sub(). Ưu điểm lớn của str_sub() là khả năng sử dụng các chỉ mục âm để đếm từ cuối chuỗi.

2. Lọc các chuỗi con phù hợp với một mẫu bằng str_subset()

Vì việc phát hiện các chuỗi có mẫu và sau đó sắp xếp lại các chuỗi đó là một hoạt động phổ biến, Stringr cung cấp một hàm str_subset() để thực hiện đều đó trong một bước. Ví dụ: Lặp lại tìm kiếm boy_names có chứa “zz” bằng cách sử dụng str_subset():

str_subset(boy_names, pattern = fixed("zz"))
##  [1] "Uzziah"    "Ozzie"     "Ozzy"      "Jazz"      "Uzziel"    "Chazz"    
##  [7] "Izzy"      "Azzam"     "Izzac"     "Izzak"     "Fabrizzio" "Jazziel"  
## [13] "Azzan"     "Izzaiah"   "Muizz"     "Yazziel"

=> Chúng ta nhận được một vectơ chuỗi mới, nhưng nó chỉ chứa các chuỗi ban đầu chứa mẫu.

str_subset() có thể dễ bị nhầm lẫn với str_extract(). str_extract() trả về một vectơ có cùng độ dài với vectơ đầu vào, nhưng chỉ với các phần của chuỗi khớp với mẫu. Tìm girl_name có chứa “U” và “z”

starts_U <- str_subset(girl_names, pattern = fixed("U"))
starts_U
##  [1] "Unique"  "Uma"     "Unknown" "Una"     "Uriah"   "Ursula"  "Unity"  
##  [8] "Umaiza"  "Urvi"    "Ulyana"  "Ula"     "Udy"     "Urwa"    "Ulani"  
## [15] "Umaima"  "Umme"    "Ugochi"  "Ulyssa"  "Umika"   "Uriyah"  "Ubah"   
## [22] "Umaira"  "Umi"     "Ume"     "Urenna"  "Uriel"   "Urijah"  "Uyen"
str_subset(starts_U, pattern = "z")
## [1] "Umaiza"

=> “Umamiza” là có gái có tên duy nhất bắt đầu bắt chữ “U” và chứa chữ “z”

3. Hàm str_extract() trả về một vectơ ký tự chứa (các) chuỗi con được trích xuất

Hàm này được sử dụng để trích xuất lần đầu xuất hiện đầu tiên của một mẫu trong chuỗi ký tự hoặc vecto của chuỗi. Hàm str_extract() trả về một vecto chứa ký tự chứa các chuỗi con được trích xuất.

Cú pháp: str_extract(string, pattern, simplify, ignore_case, opts_regex).

Trong đó:

  • string: Tham số này đại diện cho chuỗi ký tự hoặc vecto của chuỗi sẽ được tách
  • pattern: Tham số này chỉ định dấu phân cách hoặc mẫu biểu thức chính quy sẽ được sử dụng để tách các chuỗi đầu vào
  • simplify: Tham số này chỉ định có đơn giản hóa kết quả thành ma trận ký tự hoặc vecto hay không. Giá trị mặc định là FALSE
  • ignore_case: Tham số này chỉ định số lần phân tách tối đa được thực hiện. Giá trị mặc định là ‘Inf’.
  • opts_regex: Tham số này chỉ định có nên loại bỏ các chuỗi trống trong đầu ra hay không. Giá trị mặc định là true.

Dưới đây là hai bộ dữ liệu đã được cài đặt sẳn trong gói Stringr, bao gồm fruit cho chúng ta biết 79 loại trái cây và dữ liệu sentences bao gồm 720 dòng. Chúng em sẽ dùng lệnh head() để xem 6 dòng đầu của 2 bộ dữ liệu:

fruit = stringr::fruit
head(fruit)
## [1] "apple"       "apricot"     "avocado"     "banana"      "bell pepper"
## [6] "bilberry"
head(sentences)
## [1] "The birch canoe slid on the smooth planks." 
## [2] "Glue the sheet to the dark blue background."
## [3] "It's easy to tell the depth of a well."     
## [4] "These days a chicken leg is a rare dish."   
## [5] "Rice is often served in round bowls."       
## [6] "The juice of lemons makes fine punch."

Ví dụ chúng em muốn trích xuất các từ có trái cây trong “fruit” và dùng “|” để nối các chuỗi với nhau

fruit_match <- str_c(fruit, collapse = "|")
fruit_match
## [1] "apple|apricot|avocado|banana|bell pepper|bilberry|blackberry|blackcurrant|blood orange|blueberry|boysenberry|breadfruit|canary melon|cantaloupe|cherimoya|cherry|chili pepper|clementine|cloudberry|coconut|cranberry|cucumber|currant|damson|date|dragonfruit|durian|eggplant|elderberry|feijoa|fig|goji berry|gooseberry|grape|grapefruit|guava|honeydew|huckleberry|jackfruit|jambul|jujube|kiwi fruit|kumquat|lemon|lime|loquat|lychee|mandarine|mango|mulberry|nectarine|nut|olive|orange|pamelo|papaya|passionfruit|peach|pear|persimmon|physalis|pineapple|plum|pomegranate|pomelo|purple mangosteen|quince|raisin|rambutan|raspberry|redcurrant|rock melon|salal berry|satsuma|star fruit|strawberry|tamarillo|tangerine|ugli fruit|watermelon"

Tìm kiếm trích xuất các từ chứa trái cây từ trong một tập hợp các câu sentences

has_fruit <- str_subset(sentences, fruit_match)
matches <- str_extract(has_fruit, fruit_match)
head(matches)
## [1] "lemon" "fig"   "pear"  "peach" "fig"   "fig"

str_extract() chỉ trích xuất kết quả khớp đầu tiên, nên em sẽ sử dụng str_extract_all() để trích xuất tất cả các kết quả khớp, kết quả được hiển thị trong danh sách

str_extract_all(has_fruit,fruit_match) %>% head()
## [[1]]
## [1] "lemon"
## 
## [[2]]
## [1] "fig"
## 
## [[3]]
## [1] "pear"
## 
## [[4]]
## [1] "peach"
## 
## [[5]]
## [1] "fig"
## 
## [[6]]
## [1] "fig"   "apple"

Tiếp theo chúng em sẽ đơn giản hóa = TRUE trả về một ma trận

str_extract_all(has_fruit,fruit_match,simplify = T) %>% head()
##      [,1]    [,2]   
## [1,] "lemon" ""     
## [2,] "fig"   ""     
## [3,] "pear"  ""     
## [4,] "peach" ""     
## [5,] "fig"   ""     
## [6,] "fig"   "apple"

4. str_match(string, pattern): trích xuất các phần của trận đấu được xác định bởi dấu ngoặc đơn.

Bây giờ chúng em sẽ lấy ví dụ trong bộ dữ liệu sentences để giải thích về hàm str_match()

Lấy tất cả các danh từ trong câu có “a” hoặc “the” để làm từ định lượng

danhtu <- "(a|the) ([^ ]+)"

has_danhtu <- sentences %>%
  str_subset(danhtu) %>%
  head(10)
has_danhtu %>% 
  str_extract(danhtu)
##  [1] "the smooth" "the sheet"  "the depth"  "a chicken"  "the parked"
##  [6] "the sun"    "the huge"   "the ball"   "the woman"  "a helps"

str_match() khác với str_extract(), chủ yếu là vì str_match() sẽ trả về mọi nội dung đã chụp

Trích xuất phần khớp với mẫu trong mỗi danh từ

danhtu <- "(a|the) ([^ ]+)"
has_danhtu <- sentences %>%
  str_subset(danhtu) %>%
  head(10)
has_danhtu %>% 
  str_match(danhtu)
##       [,1]         [,2]  [,3]     
##  [1,] "the smooth" "the" "smooth" 
##  [2,] "the sheet"  "the" "sheet"  
##  [3,] "the depth"  "the" "depth"  
##  [4,] "a chicken"  "a"   "chicken"
##  [5,] "the parked" "the" "parked" 
##  [6,] "the sun"    "the" "sun"    
##  [7,] "the huge"   "the" "huge"   
##  [8,] "the ball"   "the" "ball"   
##  [9,] "the woman"  "the" "woman"  
## [10,] "a helps"    "a"   "helps"

2.3.3 Phát hiện kết quả trùng khớp

2.3.3.1 Tìm kiếm và trích xuất thông tin chuỗi

1. Khớp mẫu sử dụng str_detect()

Khớp mẫu liên quan đến việc tìm một chuỗi con khớp với một mẫu cụ thể. Hàm str_detect() trong gói Stringr có thể được sử dụng để phát hiện các mẫu trong chuỗi.

Cú pháp: str_detect(string, pattern, negate ): Có chức năng kiểm tra xem một chuỗi có chứa một mẫu hay không và kết quả trả về là “TRUE” hoặc “FALSE”

  • string: Đại diện cho chuỗi ký tự hoặc vecto của chuỗi muốn phát hiện trong mẫu đó
  • pattern: Tham số này chỉ định mẫu hoặc biểu thức chính quy sẽ được phát hiện trong chuỗi đầu vào
  • negate: Tham số này chỉ định có trả về phần bù logic của kết quả phát hiện hay không

Ví dụ: Kiểm tra xem một vectơ ký tự có khớp với một mẫu hay không, trả về một vectơ logic

x <- c("boy_names","girl_names")
str_detect(x,"o")
## [1]  TRUE FALSE

Một ứng dụng phổ biến là sử dụng véc tơ logic thu được để thu được các phần tử con phù hợp

x[str_detect(x,"e")]
## [1] "boy_names"  "girl_names"

Kiểm tra xem mỗi phần tử trong vector boy_names có chứa chuỗi “zz” hay không?

contains_zz <- str_detect(boy_names, pattern = "zz")
str(contains_zz)
##  logi [1:14047] FALSE FALSE FALSE FALSE FALSE FALSE ...

2. Chức năng định vị kí tự bằng hàm str_locate()

str_locate(): Trả về vị trí đầu tiên và cuối cùng của đối tượng phù hợp, thường được sử dụng cùng với hàm str_sub()

x <- c("boy_names","girl_names")
str_locate(x,'a')
##      start end
## [1,]     6   6
## [2,]     7   7

2.3.3.2 Đếm và tính toán trong chuỗi bằng hàm str_count()

Gói Stringr cung cấp phương thức str_count() được sử dụng để đếm số lần xuất hiện của một mẫu nhất định được chỉ định làm đối số cho hàm. Mẫu có thể là một kí tự đơn hoặc một nhóm ký tự. Bất kỳ trường hợp nào khớp với biểu thức đều dẫn đến sự gia tăng của số đếm. Phương thức này có thể được gọi trên một vecto chuỗi và một vecto đếm riêng lẻ được trả về có chứa các số lượng riêng lẻ của số lượng mẫu phù hợp được tim thấy.

Cú pháp:str_count(string, pattern = “”)

Trong đó:

  • string: Chuỗi để đếm số lần xuất hiện của
  • pattern: mẫu phù hợp

Ví dụ: str_count() hàm này sẽ trả về số lượng kết quả khớp trong mỗi chuỗi

x <- c("boy_names","girl_names")
str_count(x, "a")
## [1] 1 1

Đếm số lần xuất hiện của “a” và “A” trong girl_names và tạo biểu đồ số của cả 2

number_as <- str_count(girl_names, pattern = fixed("a"))
number_As <- str_count(girl_names, pattern = fixed("A"))
hist(number_as)

hist(number_As)

2.3.4 Biến đổi chuỗi

2.3.4.1 Thay thế và chuyển đổi chuỗi

Đôi khi việc thay thế các phần chúng ta không muốn bằng một chuỗi rỗng ” ” sẽ dễ dàng hơn. Đây cũng là một phương pháp phổ biến để dọn dẹp chuỗi, chẳng hạn như để xóa dấu chấm câu hoặ khoảng trắng không mong muốn

str_replace()str_replace_all() cho phép chúng ta thay thế các kết quả khớp để tạo chuỗi mới

Cú pháp: str_replace(string, pattern = ’‘, replacement =’’): Thay thế ký tự liên quan đến viêc thay thế một chuỗi con trong một chuỗi bằng một chuỗi con khác. Trong đó:

  • string: Tham số này đại diện cho chuỗi ký tự hoặc một vecto chuỗi muốn thay thế các mẫu trong đó
  • pattern: Tham số này chỉ định mẫu hoặc biểu thức chính quy sẽ được thay thế cho các chuỗi đầu vào.
  • replacement: Tham số này chỉ định các chuỗi thay thế sẽ được thay thế cho các mẫu trong các chuỗi đầu vào

Ví dụ: Đầu tiên chúng em sẽ thực hiện thay thế các nguyên âm (a, e, i, o, u) trong các chuỗi “apple”, “pear” và “banana” bằng dấu gạch ngang “-”

x <- c("apple", "pear", "banana")
str_replace(x, "[aeiou]", "-")
## [1] "-pple"  "p-ar"   "b-nana"

Thay tế tất cả các ký tự trong chuỗi bằng str_replace_all

str_replace_all(x, "[aeiou]", "-")
## [1] "-ppl-"  "p--r"   "b-n-n-"

Với str_replace_all()* chúng em cũng có thể cung cấp một vectơ có tên cho nhiều lần thay thế

x <- c("1 house", "2 cars", "3 people")
str_replace_all(x, c("1" = "one", "2" = "two", "3" = "three"))
## [1] "one house"    "two cars"     "three people"

Trong quá trình thay thế, chúng ta cũng có thể được kết hợp

sentences %>% 
  str_replace("([^ ]+) ([^ ]+) ([^ ]+)", "\\1 \\3 \\2") %>% 
  head(5)
## [1] "The canoe birch slid on the smooth planks." 
## [2] "Glue sheet the to the dark blue background."
## [3] "It's to easy tell the depth of a well."     
## [4] "These a days chicken leg is a rare dish."   
## [5] "Rice often is served in round bowls."

Đây chính là mẫu biểu thức chính quy để tìm các đoạn câu trong danh sách sentences có ba từ, đổi chỗ vị trí giữa từ thứ hai và thứ ba trong mỗi đoạn câu

2.3.4.2 Chuyển đổi chuỗi

Trong một số trường hợp chúng ta muốn biểu thị text ở dạng viết hoa hoặc viết thường, chúng ta có thể dùng hàm như sau:

Ví dụ: Đầu tiên chúng em sẽ lấy dữ liệu từ fruit là 3 loại trái cây và gán lại chúng vào fruit

fruit <- c("apple", "pear", "banana")

str_to_lower(): chuyển đổi tất cả các chữ cái trong chuỗi thành chữ thường

str_to_lower(fruit)
## [1] "apple"  "pear"   "banana"

str_to_upper(): chuyển đổi tất cả các chữ cái trong chuỗi đầu vào thành chữ hoa

str_to_upper(fruit)
## [1] "APPLE"  "PEAR"   "BANANA"

str_to_title(): Chuyển đổi các ký tự đầu tiên của mỗi từ trong một chuỗi thành chữ hoa (in hoa), trong khi giữ lại các ký tự còn lại ở dạng chữ thường (in thường).

str_to_title(fruit)
## [1] "Apple"  "Pear"   "Banana"

2.3.4.3 Tham gia và chia tách

1. Nối chuỗi bằng str_c()

Nối chuỗi là quá trình nối hai hoặc nhiều chuỗi lại với nhau. Hàm str_c() trong gói Stringr có thể được sử dụng để nối chuỗi. Hàm str_c() rất dễ sử dụng và cung cấp nhiều tham số khác nhau để tùy chỉnh quy trình nối. Dưới đây là một số tham số được sử dụng với hàm str_c()

c là viết tắt của concatenate, một hàm hoạt động giống như paste() Nó lấy các vectơ của chuỗi làm đầu vào cùng với các đối số sep và collapse.

Cú pháp: str_c(string, sep, collapse, ignore_na, trim)

Trong đó:

  • string: Tham số này đại diện cho các chuỗi cần được nối. Bạn có thể chỉ định bất kỳ số lượng đối số nào được phân tách bằng dấu phẩy.
  • sep: Tham số này chỉ định dấu phân cách được sử dụng giữa các chuỗi được nối. Dấu phân cách mặc định là một chuỗi rỗng.
  • collapse: Tham số này được sử dụng để thu gọn đầu ra của str_c() thành một chuỗi. Giá trị mặc định là FALSE.
  • ignore_na: Tham số này được sử dụng để bỏ qua mọi giá trị bị thiếu trong chuỗi đầu vào. Giá trị mặc định là FALSE.
  • trim : Tham số này được sử dụng để cắt bất kỳ ký tự khoảng trắng nào từ đầu hoặc cuối mỗi chuỗi trước khi nối chúng. Giá trị mặc định là FALSE.

Ví dụ: Hợp nhất nhiều ký tự thành một chuỗi

str_c("x","y","z")
## [1] "xyz"

Chỉ định tham số sep để xác định dấu phân cách

str_c("x","y",sep = ", ")
## [1] "x, y"

Chỉ định collapse để kết hợp các đối số vectơ thành một chuỗi lớn

str_c(head(letters),collapse = ",")
## [1] "a,b,c,d,e,f"
 str_c(c('a','a1'),c('b','b1'),collapse='-')
## [1] "ab-a1b1"

str_c() là một hàm được vector hóa để tái chế các vectơ ký tự có độ dài ngắn

str_c("prefix-",c('a','b','c'),"-suffix")
## [1] "prefix-a-suffix" "prefix-b-suffix" "prefix-c-suffix"

2. Tách chuỗi bằng cách sử dụng str_split()

Sử dụng str_split() để phân tách chuỗi thành nhiều phần và trả về một danh sách. Bạn cũng có thể chỉ định Simple = TRUE để trả về một ma trận

sentences %>%
  head(5) %>% 
  str_split(" ")
## [[1]]
## [1] "The"     "birch"   "canoe"   "slid"    "on"      "the"     "smooth" 
## [8] "planks."
## 
## [[2]]
## [1] "Glue"        "the"         "sheet"       "to"          "the"        
## [6] "dark"        "blue"        "background."
## 
## [[3]]
## [1] "It's"  "easy"  "to"    "tell"  "the"   "depth" "of"    "a"     "well."
## 
## [[4]]
## [1] "These"   "days"    "a"       "chicken" "leg"     "is"      "a"      
## [8] "rare"    "dish."  
## 
## [[5]]
## [1] "Rice"   "is"     "often"  "served" "in"     "round"  "bowls."

Tách both_names thành first_names và last_names

both_names <- c("Box, George", "Cox, David")
both_names_split <- str_split(both_names, pattern = fixed(", "), simplify = TRUE)
first_names <- both_names_split[, 2]
last_names <- both_names_split[, 1]

Ngoài ra sử dụng đối số đơn giản hóa = TRUE khi chúng ta muốn chia mỗi chuỗi thành các phần bằng nhau.

  • Đơn giản hóa =True

Nói chung, việc chỉ định đơn giản hóa = TRUE sẽ cung cấp cho chúng ta đầu ra dễ làm việc hơn, nhưng chúng ta sẽ luôn nhận được n phần (ngay cả khi một số phần trống, ““).

Đôi khi, chúng ta muốn biết một chuỗi có thể được chia thành bao nhiêu phần hoặc muốn làm gì đó với mỗi phần trước khi chuyển sang cấu trúc đơn giản hơn. Đây là tình huống mà chúng ta không muốn đơn giản hóa và sẽ phải xử lý đầu ra bằng thứ gì đó như lapply().

Để thực hiện các phép tính này, chúng ta cần chia các dòng thành các từ. Một cách để chia câu thành các từ là chia trên khoảng trống ” “. Điều này hơi khó khăn vì, ví dụ, nó sẽ không nhận các từ được phân tách bằng một chuỗi thoát dòng mới như trong”hai“, nhưng vì tình huống này không xảy ra trong các dòng của bạn, nên nó sẽ làm

Sau đây chúng em sẽ lấy dữ liệu sentences để thực hiện một số thống kê văn bản đơn giản trên các dòng của mình. Mục tiêu của chúng em là tính xem có bao nhiêu từ trong mỗi dòng và độ dài trung bình của các từ trong mỗi dòng.

Số từ trong mỗi dòng

lines <- head(sentences)
words <- str_split(lines, pattern = fixed(" "))
lapply(words, length)
## [[1]]
## [1] 8
## 
## [[2]]
## [1] 8
## 
## [[3]]
## [1] 9
## 
## [[4]]
## [1] 9
## 
## [[5]]
## [1] 7
## 
## [[6]]
## [1] 7

Kết luận: Độ dài từ không hoàn toàn đúng vì nó đã bao gồm một số ký hiệu dấu chấm câu. Để giải quyết vấn đề đó chúng ta thay thế chúng trước bằng hàm str_replace() sẽ được chúng em giới thiệu phần sau.

2.4 Khai thác chuỗi với biểu thức chính quy

Trong phần này, chúng em sẽ tìm hiểu về biểu thức chính quy, một ngôn ngữ để mô tả các mẫu trong chuỗi. Bằng cách kết hợp các biểu thức chính quy với các hàm trong stringr, giúp tăng đáng kể khả năng thao tác các chuỗi của mình.

2.4.1 Biểu thức chính quy

Biểu thức chính quy hay còn gọi là Regex là một công cụ mạnh mẽ để khớp mẫu và thao tác chuỗi. Là một công cụ rất quan trọng và hữu ích đối với gói Stringr nói riêng mà các gói trong R nói chung. Chúng cho phép chúng ta tìm kiếm, khớp và thao tác văn bản dựa trên các mẫu. Trong Rstudio, các biểu thức chính quy được sử dụng rộng rãi để thực hiện các tác vụ như làm sạch dữ liệu, trích xuất văn bản và xác thực dữ liệu.

2.4.1.1 Thao tác chuỗi với biểu thức chính quy

Dưới đây là 20 quy tắc cơ bản về biểu thức chính quy được áp dụng phổ biến trong khai thác văn bản giúp chúng em thao tác với chuỗi một cách hiệu quả và dễ dàng hơn.

  1. “.” = bất kì kí tự nào

  2. ” = 1 kí tự số bất kì từ 0 đến 9

  3. ” ” = không phải 1 kí tự số từ 0 đến 9

  4. ” ” = một kí tự thông thường (a-z, A-Z, 0-9, _)

  5. ” ” = không phải một kí tự thông thường

  6. ” ” = một kí tự trắng như: space, tab, newline

  7. ” ” = không phải một kí tự trắng

  8. ” = khớp nguyên từ (word boundary)

  9. ” ” = chỉ lấy một phần của từ

  10. ” ^ ” = bắt đầu của một chuỗi

  11. “$” = kết thúc của một chuỗi

  12. [] = khớp các kí tự trong ngoặc

  13. [^ ] = khớp các kí tự không có trong ngoặc

  14. “|” = hoặc

  15. ( ) = gom nhóm

  16. “*” = khớp 0 lần hoặc nhiều hơn

  17. “+” = khớp ít nhất 1 lần

  18. “?” = có hoặc không

  19. {x} = xuất hiện đúng x lần

  20. {x, y} = khoảng giá trị cần so khớp (GTLN, GTNN)

  • Ở đây chúng tôi có một số chuỗi bao gồm số kí tự số, chữ và kí tự đặc biệt để thao tác chuỗi bằng biểu thức chính quy và gán các chuỗi bằng regex1
regex1 <- c('Nancy Smith',
          'is there any solution?',
          ".[{(^$|?*+",
          "coreyms.com", 
          "321-555-4321", 
          "123.555.1234",
          "123*555*1234")
2.4.1.1.1 Trích các kí tự số

Trong gói Stringr có hàm str_extract_all() dùng để trích các kí tự từ một chuỗi thõa mãn các tiêu chí cần trích. Để thực hiện trích các kí tự số chúng em sẽ dùng hàm str_extract_all() trong gói Stringr kết hợp với quy tắc số 2 đã được nêu ở trên là quy tắc **.

str_extract_all(regex1, "\\d")
## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## character(0)
## 
## [[4]]
## character(0)
## 
## [[5]]
##  [1] "3" "2" "1" "5" "5" "5" "4" "3" "2" "1"
## 
## [[6]]
##  [1] "1" "2" "3" "5" "5" "5" "1" "2" "3" "4"
## 
## [[7]]
##  [1] "1" "2" "3" "5" "5" "5" "1" "2" "3" "4"

Nhận xét: Trong chuỗi regex1 ban đầu, sau khi thực hiện trích các kí tự số kết quả chạy được cho ra bốn chuỗi đầu tiên không có bất kì kí tự nào tức là bốn chuỗi là kết quả rỗng. Ba chuỗi cuối là các số điện thoại và biểu thức chính quy đã lọc những kí tự số này ra từng kí tự số riêng lẻ.

2.4.1.1.2 Loại trừ kí tự số

Để loại trừ các kí tự số em tiếp tục dùng chức năng str_extract_all() kết hợp với quy tắc * để loại bỏ các kí tự là số từ 0 đến 9

str_extract_all(regex1, "\\D")
## [[1]]
##  [1] "N" "a" "n" "c" "y" " " "S" "m" "i" "t" "h"
## 
## [[2]]
##  [1] "i" "s" " " "t" "h" "e" "r" "e" " " "a" "n" "y" " " "s" "o" "l" "u" "t" "i"
## [20] "o" "n" "?"
## 
## [[3]]
##  [1] "." "[" "{" "(" "^" "$" "|" "?" "*" "+"
## 
## [[4]]
##  [1] "c" "o" "r" "e" "y" "m" "s" "." "c" "o" "m"
## 
## [[5]]
## [1] "-" "-"
## 
## [[6]]
## [1] "." "."
## 
## [[7]]
## [1] "*" "*"

Nhận xét: Kết quả trả về cho chúng ta thấy các chuỗi 5,6,7 đã được trích hết các kí tự là số còn lại các kí tự đặc biệt như “-”, “.” hay “*“. Các kí tự ở bốn chuỗi đầu đã được trích hết ra từng kí tự riêng lẻ được đặt trong cặp dấu” “.

2.4.1.1.3 Loại trừ các kí tự đặc biệt

Để loại trừ các kí tự đặc biệt em dùng quy tắc “” kết hợp với chức năng str_extract_all để lọc tất cả các kí tự bao gồm a-z,A-Z,0-9 và kí tự gạch chân “_”

str_extract_all(regex1, "\\w")
## [[1]]
##  [1] "N" "a" "n" "c" "y" "S" "m" "i" "t" "h"
## 
## [[2]]
##  [1] "i" "s" "t" "h" "e" "r" "e" "a" "n" "y" "s" "o" "l" "u" "t" "i" "o" "n"
## 
## [[3]]
## character(0)
## 
## [[4]]
##  [1] "c" "o" "r" "e" "y" "m" "s" "c" "o" "m"
## 
## [[5]]
##  [1] "3" "2" "1" "5" "5" "5" "4" "3" "2" "1"
## 
## [[6]]
##  [1] "1" "2" "3" "5" "5" "5" "1" "2" "3" "4"
## 
## [[7]]
##  [1] "1" "2" "3" "5" "5" "5" "1" "2" "3" "4"
2.4.1.1.4 Chỉ lấy các kí tự đặc biệt

Ngược lại với câu lệnh ở trên thì bây giờ chúng tôi chỉ lấy những kí tự đặc biệt, dùng quy tắc “” kết hợp với str_extract_all() để lọc ra các kí tự đặc biệt

str_extract_all(regex1, "\\W")
## [[1]]
## [1] " "
## 
## [[2]]
## [1] " " " " " " "?"
## 
## [[3]]
##  [1] "." "[" "{" "(" "^" "$" "|" "?" "*" "+"
## 
## [[4]]
## [1] "."
## 
## [[5]]
## [1] "-" "-"
## 
## [[6]]
## [1] "." "."
## 
## [[7]]
## [1] "*" "*"
2.4.1.1.5 Bắt đầu và kết thúc chuỗi

Để tìm vị trí bắt đầu và kết thúc trong chuỗi chúng em sử dụng 2 quy tắc trong biểu thức chính quy là “^” và “$” để so khớp kí tự ở vị trí bắt đầu và kết thúc trong một chuỗi

Ví dụ: Để tìm được vị trí kết thức bởi dấu chấm than(!) trong chuỗi regex2 bên dưới:

regex2 <- c("This is me",
        "That my house",
        "Hello, world!")
        
str_extract_all(regex2, "!$")
## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## [1] "!"

Để hiện thị chuỗi đã được tìm thấy, chúng tôi sử dụng hàm str_detect() trong gói Stringr.

regex2[str_detect(regex2, "!$")]
## [1] "Hello, world!"

Tiếp tục chúng tôi sẽ tìm vị trí bắt đầu với từ “this”

regex2[str_detect(regex2, "^This")]
## [1] "This is me"
2.4.1.1.6 Tìm kí tự hoặc số trong chuỗi

Tiếp tục với các chuỗi đầu đã được gán trong regex1 để thực hiện trích các số trong chuỗi. Ở các chuỗi trong regex1 có thể thấy rằng có 3 chuỗi là dạng chuỗi kí tự dạng số và bây giờ chúng tôi sẽ thử trích tất cả các số trong đoạn từ 2 đến 4 bao gồm cả hai bên và đặt chúng trong dấu ngoặc vuông “[]”

str_extract_all(regex1, "[2-4]")
## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## character(0)
## 
## [[4]]
## character(0)
## 
## [[5]]
## [1] "3" "2" "4" "3" "2"
## 
## [[6]]
## [1] "2" "3" "2" "3" "4"
## 
## [[7]]
## [1] "2" "3" "2" "3" "4"

Nhận xét: Kết quả trả về cho chúng tôi thấy có 4 chuỗi đầu là không phải là kí tự số tức là kết quả cho ra chuỗi rỗng

Tiếp theo chúng tôi sẽ trích các kí tự “-” hoặc “.” và đặt chúng trong dấu “[]”

str_extract_all(regex1, "[-.]")
## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## [1] "."
## 
## [[4]]
## [1] "."
## 
## [[5]]
## [1] "-" "-"
## 
## [[6]]
## [1] "." "."
## 
## [[7]]
## character(0)

Nhận xét: Kết quả trả về cho chúng ta thấy có 3 chuỗi là cho ra kết quả rỗng tức là không có chuỗi có 2 kí tự đã được trích.

2.4.1.2 Ứng dụng của biểu thức chính quy

2.4.1.2.1 Trích xuất số điện thoại

Đầu tiên chúng em sẽ trích xuất thông tin về các số điện thoại gồm 10 chữ số cửa Hoa Kỳ từ một tệp văn bản

a1 <- "Home: 507-645-5489"
a2 <- "Cell: 219.917.9871"
a3 <- "My work phone is 507-202-2332"
a4 <- "I don't have a phone"
info <- c(a1, a2, a3, a4)
info
## [1] "Home: 507-645-5489"            "Cell: 219.917.9871"           
## [3] "My work phone is 507-202-2332" "I don't have a phone"

Bây giờ chúng em sẽ trích xuất các số điện thoại từ chuỗi này.

Mã vùng phải bắt đầu bằng số 2 trở lên, vì vậy chúng em sử dụng lại dấu ngoặc để biểu thị phạm vi: [2-9]. Hai chữ số tiếp theo có thể nằm trong khoảng từ 0 đến 9, vì vậy chúng tôi viết [0-9]{2}. Đối với dấu phân cách, chúng tôi sử dụng [-.] để biểu thị dấu gạch ngang hoặc dấu chấm.

Biểu thức chính quy hoàn chỉnh được đưa ra dưới đây:

phone <- "([2-9][0-9]{2})[-.]([0-9]{3})[-.]([0-9]{4})"
out <- str_detect(info, phone)
out
## [1]  TRUE  TRUE  TRUE FALSE

Bây giờ chúng em ẩn danh các số điện thoại

str_replace(info, phone, "XXX-XXX-XXXX")
## [1] "Home: XXX-XXX-XXXX"            "Cell: XXX-XXX-XXXX"           
## [3] "My work phone is XXX-XXX-XXXX" "I don't have a phone"
2.4.1.2.2 Trích các địa chỉ email

Việc trích các địa chỉ email thường phức tạp hơn so với số điện thoại. Bởi vì một địa chỉ email có thể chứa chữ hoa, chữ thường, chữ số, ký tự đặc biệt, mọi thứ. Chúng em sẽ thực hành trích địa chỉ email từ văn bản emails sau:

emails <- c("RashNErel@gmail.com",
          "rash.nerel@regen04.net",
          "rash_48@uni.edu",
          "rash_48_nerel@STB.org")

Một email với hai kí tự đặc biệt ngăn cách là ‘@’ và ‘.’ sẽ phân địa chỉ thành ba phần: phần trước kí tự ‘@’, phần sau dấu ‘@’ và trước kí tự ‘.’ và cuối cùng là phần còn lại. Ở đây, chỉ xét kí tự đặc biệt ‘@’ và ‘.’ xuất hiện đầu tiên trong chuỗi theo thứ tự từ trái qua phải.

  • Phần đầu tiên bao gồm các kí tự viết thường, [a-z], viết hoa, [A-Z], các kí tự số, [0–9] và một số kí tự đặc biệt như ‘.’ và ’_’. Do vậy, biểu thức chính quy có thể được viết là “[a-zA-Z0–9-.]+”. Ở đây, dấu ‘+’ cho biết các kí tự trên có thể xuất hiện nhiều hơn 1 lần (quy tắc 17). Bởi vì chúng ta không biết các kí tự xuất hiện bao nhiêu lần nên không thể sử dụng quy tắc 19.

  • Phần thứ hai cũng tương tự phần đầu nên có thể được phát hiện qua biểu thức: “[a-zA-Z0–9-.]+”

  • Phần thứ ba là phần còn lại. Bởi vì tôi đã thêm dấu ‘+’ sau phần thứ hai nên nó có thể nhận bất kì kí tự nào xuất hiện sau đó.

Tổng hợp lại, để trích các địa chỉ email từ văn bản emails trên, chúng em xây dựng một biểu thức chính quy như sau:

p <- "[a-zA-Z0-9-.]+@[a-zA_Z0-9]+"
str_extract_all(emails, p)
## [[1]]
## [1] "RashNErel@gmail"
## 
## [[2]]
## [1] "rash.nerel@regen04"
## 
## [[3]]
## [1] "48@uni"
## 
## [[4]]
## character(0)
p <- "[a-zA-Z0-9-.]+@[a-zA_Z0-9]+\\.(com|edu|net|org)"
str_extract_all(emails, p)
## [[1]]
## [1] "RashNErel@gmail.com"
## 
## [[2]]
## [1] "rash.nerel@regen04.net"
## 
## [[3]]
## [1] "48@uni.edu"
## 
## [[4]]
## character(0)
2.4.1.2.3 Trích các URL

Việc trích các URL cũng tương tự như với số điện thoại, mặc dù có đôi chút bất tiện do các địa chỉ có thể bắt đầu với chuẩn http hay https, có hoặc không có www.. Chúng em sẽ thực hành trích các URL từ văn bản urls sau:

urls <- c("https://regenerativetoday.com",
         "http://setf.ml",
         "https://www.yahoo.com",
         "http://studio_base.net"
         )

Một URL sẽ bao gồm 3 phần:

  • Phần đầu bao gồm các tiền tố http hay https, có hoặc không có www. Nó có thể được ghi nhận bằng cách sử dụng quy tắc 15, 18 như sau: ‘https?’: có hoặc không kí tự ‘s’ “(www.)?”: có hoặc không từ ‘www.’

Phần thứ hai là tên miền có thể là bất kì kí tự thông thường nào được lặp lại nhiều hơn một lần –> sử dụng: “+”

Phần thứ ba là sau tên miền: có thể có một hoặc nhiều hơn một dấu chấm “.” và theo sau là các kí tự thông thường khác –> sử dụng: “.+”

Tổng hợp lại, em sẽ viết biểu thức chính quy để trích các URL từ văn bản urls như sau:

p <- "https?://(www\\.)?\\w+\\.\\w+"
str_extract_all(urls, p)
## [[1]]
## [1] "https://regenerativetoday.com"
## 
## [[2]]
## [1] "http://setf.ml"
## 
## [[3]]
## [1] "https://www.yahoo.com"
## 
## [[4]]
## [1] "http://studio_base.net"

Trong trường hợp chỉ muốn lấy các tên miền ‘.com’ hoặc ‘.net’ thì bổ sung thêm nhóm (com|net) vào biểu thức chính quy trên như sau:

p <- "https?://(www\\.)?(\\w+)(\\.)+(com|net)"
str_extract_all(urls, p)
## [[1]]
## [1] "https://regenerativetoday.com"
## 
## [[2]]
## character(0)
## 
## [[3]]
## [1] "https://www.yahoo.com"
## 
## [[4]]
## [1] "http://studio_base.net"
2.4.1.2.4 Xuất danh bạ

Cuối cùng là ví dụ kết hợp các quy tắc để xuất các danh bạ từ một văn bản name sau:

name <- c("Mr. Jon",
         "Mrs. Jon",
         "Mr Ron",
         "Ms. Reene",
         "Ms Julie")

Một danh bạ bao gồm bí danh Mr, Mrs, Ms (–> sử dụng: “M(r|s|rs)”) có thể có hoặc không dấu ‘.’ đi kèm (–> sử dụng: “.?”), theo sau là một khoảng trắng (–> sử dụng: “”).

Sau đó là tên, với kí tự đầu tiên viết hoa (–> sử dụng: “[A-Z]”), theo sau là các kí tự thông thường (–> sử dụng: “”). Sử dụng dấu ’’ có nghĩa các kí tự trước đó có thể không xuất hiện hoặc xuất hiện nhiều lần. Kết hợp lại, biểu thức chính quy sau sẽ trích các danh bạ từ văn bản name như sau

p <- "M(r|s|rs)\\.?[A-Z\\s]\\w*"
str_extract_all(name, p)
## [[1]]
## [1] "Mr. Jon"
## 
## [[2]]
## [1] "Mrs. Jon"
## 
## [[3]]
## [1] "Mr Ron"
## 
## [[4]]
## [1] "Ms. Reene"
## 
## [[5]]
## [1] "Ms Julie"
2.4.1.2.5 Tập tin

Ở đây em có 8 tập tin từ năm 1999 đến năm 2011 chưa được xử lý nên dữ liệu bên trong là dữ liệu thô, bây giờ em sẽ dùng chức năng str_subset() để trích xuất các tệp từ năm 2003 trở lên

files <- c("file1999.txt", "file2000.txt", "file2001.txt", "file2002.txt", "file2003.txt",
           "file2009.txt", "file2010.txt", "file2011.txt")
str_subset(files, "(200[3-9]{1}|201[0-9]{1})")
## [1] "file2003.txt" "file2009.txt" "file2010.txt" "file2011.txt"

3 CHƯƠNG 3: Một số ứng dụng của gói Stringr

Trong chương này chúng em sẽ ứng dụng các chức năng đã được thao tác ở chương 2 vào phân tích trên một số bộ dữ liệu giúp người đọc có thể nhận thấy và hiểu rõ hơn về gói Stringr.

3.1 Dữ liệu Babynames

Bộ dữ liệu Babynames trong ngôn ngữ lập trình R là một tập hợp dữ liệu thống kê về tên trẻ sơ sinh theo thời gian và tần suất sử dụng tên đó trong các năm khác nhau từ năm 1880 đến năm 2017. Bộ dữ liệu này bao gồm 1924665 quan sát và có 5 biến. Trong đó:

  • year: Năm sinh
  • sex: Giới tính
  • name: Tên
  • n: Số lần tên đó được sử dụng
  • prop: Tỷ lệ phần trắm tên cụ thể trong số tất cả các tên cùng giới tính trong cùng một năm
babynames
## # A tibble: 1,924,665 × 5
##     year sex   name          n   prop
##    <dbl> <chr> <chr>     <int>  <dbl>
##  1  1880 F     Mary       7065 0.0724
##  2  1880 F     Anna       2604 0.0267
##  3  1880 F     Emma       2003 0.0205
##  4  1880 F     Elizabeth  1939 0.0199
##  5  1880 F     Minnie     1746 0.0179
##  6  1880 F     Margaret   1578 0.0162
##  7  1880 F     Ida        1472 0.0151
##  8  1880 F     Alice      1414 0.0145
##  9  1880 F     Bertha     1320 0.0135
## 10  1880 F     Sarah      1288 0.0132
## # ℹ 1,924,655 more rows

Đầu tiên, chúng em sử dụng str_detect() đề tìm tất cả các tên bắt đầu bằng ‘sh’. Sau đó để chi tiết hơn chúng em kết hợp gói ggplot để viết một bộ mã dài và phức tạp sẽ trực quan hóa các tên phổ biến bắt đầu bằng ‘sh’ cho phụ nữ sinh năm 1938

babynames %>% 
  filter(str_detect(name, "Sh") & sex=="F" & year == 1938) %>% 
  arrange(desc(prop)) %>% 
  head(20) %>% 
  ggplot(aes(reorder(name,prop),prop,  fill = name)) + 
  geom_col() +
  coord_flip()

Sau khi lọc và sắp xếp, chúng em đã tạo ra một biểu đồ cột thể hiện 20 tên phổ biến nhất trong tập dữ liệu. Biểu đồ này sẽ được vẽ với trục dọc, và mỗi cột sẽ đại diện cho một tên, có chiều cao thể hiện tỷ lệ phổ biến của tên đó trong tập dữ liệu.

Để hiểu rõ hơn về kết quả cụ thể,tiếp theo em sẽ tính tỷ lệ phần trăm cho mỗi năm/mỗi giới tính

Biểu đồ này sẽ giúp chúng ta thấy rõ hơn về tần suất của các tên chứa chuỗi “Sh” và cách chúng phân chia phần trăm phổ biến. Các tên phổ biến hơn sẽ có cột cao hơn, và cột thấp hơn sẽ đại diện cho các tên ít phổ biến hơn.

babynames %>% 
  filter(str_detect(name, "Sh") & sex=="F" & year == 1938) %>% 
  arrange(desc(prop)) %>% 
  head(20) %>% 
  mutate(percent = (prop * 100)) %>% 
  ggplot(aes(reorder(name,percent),percent,  fill = name)) + 
  geom_col() +
  coord_flip()

Nhận xét: Qua 2 biểu đồ trên có thể thấy người có tên Shirley là có tỷ lệ phần trăm cao trong số những người phụ nữ sinh năm 1938

Tuy nhiên, để có cái nhìn chính xác hơn về kết quả cũng như có thể xác định được kết quả cuối cùng và hiểu rõ hơn về phân phối của các tên , nên bây giờ chúng em dùng str_detect() để xem có bao nhiêu người có tên bắt đầu bằng dữ ‘z’ từ năm 2000

babynames %>% 
  filter(year > 2000 & str_detect(name, "Z")) %>% 
  arrange(desc(prop))
## # A tibble: 13,018 × 5
##     year sex   name        n    prop
##    <dbl> <chr> <chr>   <int>   <dbl>
##  1  2001 M     Zachary 18186 0.00880
##  2  2002 M     Zachary 16622 0.00805
##  3  2003 M     Zachary 15539 0.00740
##  4  2004 M     Zachary 13711 0.00649
##  5  2005 M     Zachary 12283 0.00578
##  6  2006 M     Zachary 11005 0.00502
##  7  2007 M     Zachary 10212 0.00461
##  8  2008 M     Zachary  9226 0.00424
##  9  2012 F     Zoey     7466 0.00386
## 10  2009 M     Zachary  8078 0.00381
## # ℹ 13,008 more rows

Kết quả đã hiển thì đc rằng: tập dữ liệu này chứa các tên của các em bé sinh sau năm 2000 và chứa ký tự “Z”, được sắp xếp theo thứ tự giảm dần của tỷ lệ prop . Thay vì sắp xếp những tên theo mức độ phổ biến thì chúng em sẽ phân loại xem những tên có nhiều chữ ‘Z’ nhất

babynames %>% 
      mutate(Z = str_count(babynames$name, "[zZ]")) %>% 
      arrange(desc(Z))
## # A tibble: 1,924,665 × 6
##     year sex   name       n       prop     Z
##    <dbl> <chr> <chr>  <int>      <dbl> <int>
##  1  2010 M     Zzyzx      5 0.00000244     3
##  2  1880 F     Lizzie   388 0.00398        2
##  3  1880 F     Kizzie    13 0.000133       2
##  4  1881 F     Lizzie   396 0.00401        2
##  5  1881 F     Kizzie     9 0.0000910      2
##  6  1882 F     Lizzie   495 0.00428        2
##  7  1882 F     Kizzie     9 0.0000778      2
##  8  1882 F     Dezzie     5 0.0000432      2
##  9  1883 F     Lizzie   496 0.00413        2
## 10  1883 F     Kizzie    14 0.000117       2
## # ℹ 1,924,655 more rows

Chúng em đã tạo ra một tập dữ liệu mới bằng cách thêm cột “Z” vào tập dữ liệu ban đầu. Cột “Z” chứa số lượng lần xuất hiện của ký tự “z” hoặc “Z” trong mỗi tên. Sau đó, tập dữ liệu được sắp xếp theo thứ tự giảm dần của cột “Z”.

Ví dụ: dòng đầu tiên cho thấy rằng trong năm 2010, có 5 em bé nam được đặt tên là “Zzyzx”. Tên này có tỷ lệ xuất hiện rất thấp (0.00000244), nhưng lại chứa 3 ký tự “z” hoặc “Z”.

Cuối cùng để xem có bao nhiêu tên có chứa ‘liz’ và vẽ chúng bằng biểu đồ để thấy rõ hơn

babynames %>% 
      filter(str_detect(babynames$name, "liz") )  %>% 
      count(name, sort = TRUE) %>% 
      head(20) %>% 
      ggplot(aes(reorder(name, n),n)) + geom_col() + 
      coord_flip()

Nhận xét: nhìn vào biểu đồ ta có thẻ thấy Elizabeth là tên phổ biến nhất trong tên chứa chuỗi “liz”,

3.2 Murders

Để hiểu hỏi về các chức năng trong gói Stringr thì nhóm chúng em sẽ thao tác trên bộ dữ liệu murders. Bộ dữ liệu Murders là dữ liệu được cung cấp bởi gói dữ liệu “dalabs” trong Rstudio. Bộ dữ liệu này chứa thông tin về số lượng vụ ấn giết người của từng tiểu bang ở Hoa Kỳ trong một khoảng thời gian cụ thể. Ở bộ dữ liệu này giúp chúng ta làm việc với các chuỗi nằm trong một cột trong một khung dữ liệu và chúng em sẽ tìm hiểu cách tập hợp một khung dữ liệu theo các chuỗi chúng ta muốn.

Đầu tiên chúng ta sẽ gọi bộ dữ liệu này lên sau khi đã cài đặt package dalabs và tải thư viện nó lên. Bảng dữ liệu bên dưới, mỗi quan sát sẽ cho chúng ta biết thông tin về tên của tiểu bang, tên viết tắt của tiểu bang đó, vùng của tiểu bang, dân số của tiểu bang tương ứng, tổng số vụ án giết người trong tiểu bang trong năm tương ứng.

library(dslabs)
## Warning: package 'dslabs' was built under R version 4.2.3
data("murders")
datatable(murders)

Qua bảng trên chúng ta có thể thấy dataframe này có 2 cột là chuỗi ký tự và cột vùng là hệ số nhưng có thể dễ dàng đổi thành kiểu ký tự. Thông thường chúng ta sẽ chỉ muốn lấy các hàng của khung dữ liệu đáp ứng một tiêu chí nhất định. Để làm điều đó dữ trên chuỗi, chúng em sẽ sử dụng filter()str_detect(). Bây giờ chúng em sẽ rút ra tất cả các hàng có trạng thái

# Các trạng thái bắt đầu bằng A
murders %>% 
  filter(str_detect(string = state, pattern = "A"))
##      state abb region population total
## 1  Alabama  AL  South    4779736   135
## 2   Alaska  AK   West     710231    19
## 3  Arizona  AZ   West    6392017   232
## 4 Arkansas  AR  South    2915918    93
# Các trạng thái bắt đầu bằng A hoặc C
murders %>% 
  filter(str_detect(string = state, pattern = "A|C"))
##                   state abb    region population total
## 1               Alabama  AL     South    4779736   135
## 2                Alaska  AK      West     710231    19
## 3               Arizona  AZ      West    6392017   232
## 4              Arkansas  AR     South    2915918    93
## 5            California  CA      West   37253956  1257
## 6              Colorado  CO      West    5029196    65
## 7           Connecticut  CT Northeast    3574097    97
## 8  District of Columbia  DC     South     601723    99
## 9        North Carolina  NC     South    9535483   286
## 10       South Carolina  SC     South    4625364   207

Nhận xét: Chúng ta đã lọc ra các tiểu bang có tên chứa ít nhất một trong hai ký tự “A” hoặc “C” từ tập dữ liệu “murders”. Điều này có thể giúp chúng ra có các thông tin về tiểu bang, khu vực, dân số và số vụ án giết người đã được hiển thị chứa các ký tự cụ thể

Một cách khác mà chúng em có thể cần để thao tác với một cột chuỗi ký tự là thay đổi các từ. Ví dụ, trong khung dữ liệu vụ giết người, chúng em sẽ thay đổi tên của các khu vực để tất cả chúng đều là một từ và tất cả đều là chữ thường. Để làm điều này, chúng em sẽ kết hợp các str_c() và chức năng str_replace().

states.of.interest <- c("Texas", 
                        "Louisiana", 
                        "Mississippi", 
                        "Alabama", 
                        "Florida")
states.of.interest <- str_c(states.of.interest, collapse="|") 
states.of.interest
## [1] "Texas|Louisiana|Mississippi|Alabama|Florida"

Đây là một chuỗi biểu diễn của các tên tiểu bang, được nối lại với nhau bằng dấu “|”

murders %>% 
  filter(str_detect(string = state, pattern = states.of.interest))
##         state abb region population total
## 1     Alabama  AL  South    4779736   135
## 2     Florida  FL  South   19687653   669
## 3   Louisiana  LA  South    4533372   351
## 4 Mississippi  MS  South    2967297   120
## 5       Texas  TX  South   25145561   805

Dưới đây là thông tin về các tiểu bang mà tên không chứa ký tự “A” hoặc “C” từ tập dữ liệu “murders”.

murders %>% 
  filter(str_detect(string = state, pattern = "A|C", negate = TRUE))
##            state abb        region population total
## 1       Delaware  DE         South     897934    38
## 2        Florida  FL         South   19687653   669
## 3        Georgia  GA         South    9920000   376
## 4         Hawaii  HI          West    1360301     7
## 5          Idaho  ID          West    1567582    12
## 6       Illinois  IL North Central   12830632   364
## 7        Indiana  IN North Central    6483802   142
## 8           Iowa  IA North Central    3046355    21
## 9         Kansas  KS North Central    2853118    63
## 10      Kentucky  KY         South    4339367   116
## 11     Louisiana  LA         South    4533372   351
## 12         Maine  ME     Northeast    1328361    11
## 13      Maryland  MD         South    5773552   293
## 14 Massachusetts  MA     Northeast    6547629   118
## 15      Michigan  MI North Central    9883640   413
## 16     Minnesota  MN North Central    5303925    53
## 17   Mississippi  MS         South    2967297   120
## 18      Missouri  MO North Central    5988927   321
## 19       Montana  MT          West     989415    12
## 20      Nebraska  NE North Central    1826341    32
## 21        Nevada  NV          West    2700551    84
## 22 New Hampshire  NH     Northeast    1316470     5
## 23    New Jersey  NJ     Northeast    8791894   246
## 24    New Mexico  NM          West    2059179    67
## 25      New York  NY     Northeast   19378102   517
## 26  North Dakota  ND North Central     672591     4
## 27          Ohio  OH North Central   11536504   310
## 28      Oklahoma  OK         South    3751351   111
## 29        Oregon  OR          West    3831074    36
## 30  Pennsylvania  PA     Northeast   12702379   457
## 31  Rhode Island  RI     Northeast    1052567    16
## 32  South Dakota  SD North Central     814180     8
## 33     Tennessee  TN         South    6346105   219
## 34         Texas  TX         South   25145561   805
## 35          Utah  UT          West    2763885    22
## 36       Vermont  VT     Northeast     625741     2
## 37      Virginia  VA         South    8001024   250
## 38    Washington  WA          West    6724540    93
## 39 West Virginia  WV         South    1852994    27
## 40     Wisconsin  WI North Central    5686986    97
## 41       Wyoming  WY          West     563626     5
murders %>% 
  distinct(region)
##          region
## 1         South
## 2          West
## 3     Northeast
## 4 North Central

Kết quả đã trích xuất các giá trị duy nhất từ cột “region” và hiển thị thông tin các khu vực địa lý khác nhau mà các tiểu bang trong tập dữ liệu “murders” thuộc về.

Ở vùng ‘South’ vẫn còn đang là chữ cái hoa đầu, bây giờ em sẽ thay đổi một vùng về lại chữ thường

murders %>% 
  mutate(region = str_replace(string = region, 
                              pattern = "South", 
                              replacement = "south")) %>% 
  head()
##        state abb region population total
## 1    Alabama  AL  south    4779736   135
## 2     Alaska  AK   West     710231    19
## 3    Arizona  AZ   West    6392017   232
## 4   Arkansas  AR  south    2915918    93
## 5 California  CA   West   37253956  1257
## 6   Colorado  CO   West    5029196    65

Cuối cùng chúng em sẽ đổi tên tất cả các vùng về chữ thường

murders %>% 
  mutate(region = str_replace_all(string = region, c("South" = "south",
                                                     "West" = "west",
                                                     "North Central" = "north_central",
                                                     "Northeast" = "northeast"))) %>% 
  head(n = 20)
##                   state abb        region population total
## 1               Alabama  AL         south    4779736   135
## 2                Alaska  AK          west     710231    19
## 3               Arizona  AZ          west    6392017   232
## 4              Arkansas  AR         south    2915918    93
## 5            California  CA          west   37253956  1257
## 6              Colorado  CO          west    5029196    65
## 7           Connecticut  CT     northeast    3574097    97
## 8              Delaware  DE         south     897934    38
## 9  District of Columbia  DC         south     601723    99
## 10              Florida  FL         south   19687653   669
## 11              Georgia  GA         south    9920000   376
## 12               Hawaii  HI          west    1360301     7
## 13                Idaho  ID          west    1567582    12
## 14             Illinois  IL north_central   12830632   364
## 15              Indiana  IN north_central    6483802   142
## 16                 Iowa  IA north_central    3046355    21
## 17               Kansas  KS north_central    2853118    63
## 18             Kentucky  KY         south    4339367   116
## 19            Louisiana  LA         south    4533372   351
## 20                Maine  ME     northeast    1328361    11

4 CHƯƠNG 4: Kết luận

4.1 Kết luận liên quan đến chủ đề

4.1.1 Ưu điểm

Cú pháp dễ đọc và sử dụng: Stringr cung cấp một tập hợp các hàm dễ đọc và dễ sử dụng cho các tác vụ xử lý chuỗi phổ biến. Cú pháp rõ ràng giúp người dùng nắm bắt nhanh chóng cách sử dụng các hàm.

  • Tích hợp tốt với dplyr và tidyr: Stringr được phát triển bởi cùng tác giả của gói dplyr và tidyr, nên nó tích hợp tốt với những gói này để thực hiện xử lý dữ liệu toàn diện, từ làm sạch dữ liệu đến biến đổi dữ liệu.

  • Cung cấp các hàm linh hoạt cho xử lý chuỗi: Gói Stringr cung cấp các hàm cho việc cắt chuỗi, thay thế, tách chuỗi thành các phần, chuẩn hóa khoảng trắng, và nhiều thao tác khác để xử lý chuỗi dễ dàng và hiệu quả.

  • Hỗ trợ biểu thức chính quy dễ hiểu: Stringr cung cấp cách thức sử dụng biểu thức chính quy một cách dễ hiểu và trực quan hơn. Điều này giúp người dùng không quen thuộc với biểu thức chính quy cũng có thể thực hiện các phép toán phức tạp trên chuỗi.

  • Tương thích với dữ liệu dạng tibble: Stringr cung cấp hàm str_detect() và str_subset() có thể dễ dàng tích hợp vào dữ liệu dạng tibble mà không cần chuyển đổi qua dạng ma trận.

  • Hiệu quả của bộ nhớ: Các chuỗi thường được lưu trữ trong một khối bộ nhớ liền kề, giúp phân bổ và giải phóng chúng hiệu quả. Điều này có nghĩa là chúng có thể được sử dụng để biểu diễn một lượng lớn dữ liệu mà không chiếm quá nhiều bộ nhớ.

4.1.2 Nhược điểm

Khả năng sử dụng thấp cho xử lý dữ liệu lớn: stringr có thể trở nên chậm khi chúng áp dụng nó cho các tập dữ liệu lớn. Nếu cần xử lý chuỗi trong các tập dữ liệu có kích thước lớn, có thể cần phải tìm hiểu các phương pháp khác hiệu quả hơn để xử lý chuỗi.

  • Phụ thuộc vào gói dplyr và tidyr: stringr thường được sử dụng cùng với các gói khác như dplyr và tidyr để thực hiện xử lý dữ liệu toàn diện. Điều này có thể đôi khi tạo ra sự phức tạp và đòi hỏi người dùng phải hiểu rõ về cả các gói khác.

  • Yêu cầu kiến thức về biểu thức chính quy (regular expressions): Một số hàm trong stringr yêu cầu người dùng biết về biểu thức chính quy để thực hiện các phép toán phức tạp. Điều này có thể đặt khó khăn cho người mới học hoặc không quen thuộc với biểu thức chính quy.

  • Không hoàn toàn thay thế được các hàm chuỗi cơ bản trong R: Mặc dù stringr cung cấp nhiều tính năng tiện ích hơn cho việc làm việc với chuỗi so với các hàm chuỗi cơ bản trong R, nhưng vẫn có những tình huống mà chúng ta có thể cần phải sử dụng các hàm cơ bản này.

  • Khả năng đụng độ với các gói khác: Khi chúng ta sử dụng nhiều gói trong R cùng một lúc, có thể xảy ra xung đột tên hàm hoặc biến. Điều này có thể xảy ra khi stringr sử dụng các tên hàm tương tự như các gói khác.

  • Yêu cầu cài đặt gói phụ thuộc: Để sử dụng stringr, chúng cần phải cài đặt các gói phụ thuộc như dplyr và tidyr. Điều này có thể đòi hỏi thời gian và tài nguyên để cài đặt và duy trì các gói này.

  • Chi phí hoạt động: Các thao tác chuỗi có thể chậm hơn so với các thao tác trên các loại dữ liệu khác, đặc biệt là khi làm việc với các chuỗi lớn hoặc phức tạp. Điều này là do các thao tác chuỗi thường liên quan đến việc sao chép và phân bổ lại bộ nhớ, điều này có thể tốn nhiều thời gian.

Kết luận: mặc dù Stringr có nhiều ưu điểm trong việc làm việc với chuỗi trong R, nhưng cũng cần cân nhắc các hạn chế và điểm yếu của nó khi lựa chọn sử dụng gói này.

4.2 Kết luận cho quá trình làm chủ đề

Trong quá trình làm tiểu luận, chúng em cảm thấy rằng gói Stringr rất hữu ích. Vì nó hiển thị một tập hợp nhỏ của các hàm quan trọng, đã được lựa chọn cẩn thận để xử lý các thao tác phổ biến trên chuỗi. Gói Stringr được thiết kế một cách toàn diện, bao gồm hầu hết các chức năng mà chúng em cần để làm việc với chuỗi với tổng cộng 59 chức năng trong Stringr.

Ngoài ra gói Stringr còn giúp chúng em học tập, thực hành và phát triển kỹ năng xử lý chuỗi trong R phù hợp với thời đại 4.0. Việc sử dụng gói Stringr trong bài tiểu luận không chỉ giúp chúng em nắm vững và áp dụng kiến thức về xử lý chuỗi trong R mà còn phát triển kỹ năng phù hợp với thời đại 4.0 như kỹ năng xủ lý dữ liệu, giải quyết vấn đề cụ thể, phân tích và trình bày kết quả một cách cẩn thận và nâng cao kỹ năng lập trình trong quá trình học tập, công việc trong tương lai

LS0tDQp0aXRsZTogIlRp4buDdSBMdeG6rW4gUGFja2FnZSBTdHJpbmdyIg0KYXV0aG9yOiAiTmd1eeG7hW4gTWluaCBLaGFuZyAyMTIxMDExNzU3IC0gUGhhbiDEkOG6r2MgS2jDoW5oIFRvw6BuIDIxMjEwMTI3MzAgIg0KZGF0ZTogIjIwMjMtMDctMDEiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50OiANCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHVuaXRlZA0KICAgIHRvYzogVFJVRQ0KICAgIHRvY19mbG9hdDogVFJVRQ0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCmBgYHtjc3MsZWNobyA9IEZBTFNFfQ0KaDEgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgZm9udC1zaXplOiAzMnB4Ow0KICBmb250LXdlaWdodDogYm9sZA0KICB9DQoNCmgyIHsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGZvbnQtc2l6ZTogMjhweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogDQp9DQoNCmgzIHsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGZvbnQtc2l6ZTogMjRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc3R5bGU6IGl0YWxpYzsNCn0NCg0KaDQge2ZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBmb250LXNpemU6IDIwcHg7DQogIGZvbnQtc3R5bGU6IGl0YWxpY30NCg0KYm9keSB7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBmb250LXNpemU6IDE4cHg7DQogIA0KfQ0KcDpub3QoaDEpOm5vdChoMik6bm90KGgzKTpub3QoaDQpOm5vdChoNSkgew0KICB0ZXh0LWluZGVudDogMmVtO30NCnAgew0KICB0ZXh0LWFsaWduOiBqdXN0aWZ5Ow0KICB9DQoudG9jaWZ5LWhlYWRlciB7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpgYGANCg0KDQoNCiFbXShDOi9Vc2Vyc1xWSVBcRG93bmxvYWRzXERPYzIuanBnKQ0KDQojICoqQ0jGr8agTkcgMTogR2nhu5tpIHRoaeG7h3UgY2h1bmcqKg0KDQojIyAqKsSQ4bq3dCB24bqlbiDEkeG7gSoqDQoNClRyb25nIHRo4budaSDEkeG6oWkgaGnhu4duIG5heSwgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgxJHDs25nIHZhaSB0csOyIHbDtCBjw7luZyBxdWFuIHRy4buNbmcgdsOgIG1hbmcgbOG6oWkgbmhp4buBdSBs4bujaSDDrWNoIHRyb25nIG5oaeG7gXUgbMSpbmggduG7sWMga2jDoWMgbmhhdS4gQ8OhYyBjw7RuZyB2aeG7h2MgbmjGsCBsw6AgeOG7rSBsw70gZOG7ryBsaeG7h3UgY8WpbmcgbmjGsCBwaMOibiB0w61jaCB2xINuIGLhuqNuIG5nw6B5IGPDoG5nIHBo4buVIGJp4bq/biB2w6AgxJHDsmkgaOG7j2kgc+G7sSB04buJIG3hu4kgaMahbi4gQ2jDrW5oIHbDrCB24bqteSBuw6puIG7DsyBsw6BtIGNow7puZyB0YSBt4bqldCBuaGnhu4F1IHRo4budaSBnaWFuIGjGoW4uIMSQ4buDIGdp4bqjaSBxdXnhur90IG5o4buvbmcgdGjDoWNoIHRo4bupYyBuw6B5LCB0aMOsIGPDsyBuaGnhu4F1IGPDoWNoIGtow6FjIG5oYXUgbmjGsG5nIHRoZW8gZW0gdGjhuqV5IHRow6wgZ8OzaSBTdHJpbmdyIHbhuqtuIGzDoCB0aeG7h24gZOG7pW5nIG5o4bqldC4gQ2jDum5nIHRhIGPDsyB0aOG7gyBkw7luZyBuw7MgxJHhu4MgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgY8WpbmcgbmjGsCB0csOtY2ggeHXhuqV0IGPDoWMgbmfDtG4gbmfhu68gxJHhurdjIHRyxrBuZyB0cm9uZyB2aeG7h2MgbmdoacOqbiBj4bupdSB0w6JtIGzDvSwgc+G7sSB0xrDGoW5nIHTDoWMgdsOgIG5n4buvIG5naMSpYSB0cm9uZyBk4buvIGxp4buHdSB2xINuIGLhuqNuLk5nb8OgaSByYSwgU3RyaW5nciBjw7JuIGN1bmcgY+G6pXAgY8OhYyBjw7RuZyBj4bulIMSR4buDIHTDoWNoIHThu6ssIHTDoWNoIGPDonUgdsOgIHRo4buxYyBoaeG7h24gcGjDom4gdMOtY2ggY8OhYyBuZ8O0biBuZ+G7ryBraMOhYy4gxJBp4buBdSBuw6B5IGdpw7pwIGNow7puZyB0YSBuZ2hpw6puIGPhu6l1IHBow6JuIHTDrWNoIGPDoWMgeeG6v3UgdOG7kSBuZ8O0biBuZ+G7ryBk4buFIGTDoG5nIGjGoW4uDQoNCiMjICoqR8OzaSBTdHJpbmdyKioNCg0KIyMjIE5ndeG7k24gZ+G7kWMNCg0KR8OzaSBTdHJpbmdyIGzDoCBt4buZdCBwaOG6p24gY+G7p2EgVGlkeXZlcnNlLCBt4buZdCBi4buZIGPDoWMgZ8OzaSBSIMSRxrDhu6NjIHBow6F0IHRyaeG7g24gYuG7n2kgSGFkbGV5IFdpY2toYW0gdsOgIG5ow7NtIGPhu6dhIMO0bmcgdOG6oWkgY8O0bmcgdHkgUlN0dWRpby4gVGlkeXZlcnNlIMSRxrDhu6NjIHRoaeG6v3Qga+G6vyDEkeG7gyBjdW5nIGPhuqVwIG3hu5l0IGPDuiBwaMOhcCBk4buFIMSR4buNYywgbmjhuqV0IHF1w6FuIHbDoCBoaeG7h3UgcXXhuqMgY2hvIHZp4buHYyBsw6BtIHZp4buHYyB24bubaSBk4buvIGxp4buHdSB0cm9uZyBSLiBHw7NpIFN0cmluZ3IgxJHGsOG7o2MgdOG6oW8gcmEgxJHhu4MgY3VuZyBj4bqlcCBjw6FjIGPDtG5nIGPhu6UgbeG6oW5oIG3hur0gdsOgIGThu4Ugc+G7rSBk4bulbmcgY2hvIHjhu60gbMO9IGNodeG7l2kga8O9IHThu7EgdHJvbmcgUi4gSGFkbGV5IFdpY2toYW0gxJHDoyBuaOG6rW4gdGjhuqV5IHLhurFuZyB2aeG7h2MgeOG7rSBsw70gdsOgIGJp4bq/biDEkeG7lWkgY2h14buXaSBsw6AgbeG7mXQgcGjhuqduIHF1YW4gdHLhu41uZyB0cm9uZyBxdcOhIHRyw6xuaCB0aeG7gW4geOG7rSBsw70gZOG7ryBsaeG7h3UgdsOgIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IHbEg24gYuG6o24uIERvIMSRw7MsIMO0bmcgxJHDoyBwaMOhdCB0cmnhu4NuIGfDs2kgIlN0cmluZ3IiIG5o4bqxbSBnacO6cCBjw6FjIG5ow6AgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgdsOgIG5nxrDhu51pIHPhu60gZOG7pW5nIFIgdGjhu7FjIGhp4buHbiBjw6FjIHTDoWMgduG7pSB44butIGzDvSBjaHXhu5dpIG3hu5l0IGPDoWNoIGThu4UgZMOgbmcgdsOgIGhp4buHdSBxdeG6oyBoxqFuLiBHw7NpIFN0cmluZ3IgxJHDoyDEkcaw4bujYyBwaMOhdCBow6BuaCBs4bqnbiDEkeG6p3UgdGnDqm4gdsOgbyBuxINtIDIwMTAgdsOgIHRp4bq/cCB04bulYyDEkcaw4bujYyBwaMOhdCB0cmnhu4NuIHbDoCBkdXkgdHLDrCB0cm9uZyB0aOG7nWkgZ2lhbiBr4bq/IHRp4bq/cC4gTsOzIMSRw6MgdHLhu58gdGjDoG5oIG3hu5l0IGPDtG5nIGPhu6UgcGjhu5UgYmnhur9uIHRyb25nIGPhu5luZyDEkeG7k25nIFIgdsOgIMSRxrDhu6NjIHPhu60gZOG7pW5nIHLhu5luZyByw6NpIHRyb25nIG5oaeG7gXUgbMSpbmggduG7sWMgbmjGsCB44butIGzDvSBuZ8O0biBuZ+G7ryB04buxIG5oacOqbiwgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgdsSDbiBi4bqjbiwga2hhaSBwaMOhIGThu68gbGnhu4d1LCB2w6Agbmhp4buBdSDhu6luZyBk4bulbmcga2jDoWMgbGnDqm4gcXVhbiDEkeG6v24gY2h14buXaSBrw70gdOG7sS4gTmd14buTbiBn4buRYyBj4bunYSBnw7NpIFN0cmluZ3IgdsOgIGPDoWMgZ8OzaSBraMOhYyB0cm9uZyBUaWR5dmVyc2UgeHXhuqV0IHBow6F0IHThu6sgdOG6p20gbmjDrG4gY+G7p2EgSGFkbGV5IFdpY2toYW0gduG7gSBjw6FjaCBsw6BtIHZp4buHYyBoaeG7h3UgcXXhuqMgdsOgIG5o4bqldCBxdcOhbiB24bubaSBk4buvIGxp4buHdSB0cm9uZyBSLg0KDQojIyMgIEdp4bubaSB0aGnhu4d1IGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eQ0KDQpCaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgxJHGsOG7o2MgYuG6r3Qgbmd14buTbiB04burIG7Eg20gMTk1MSwga2hpIG5ow6AgdG/DoW4gaOG7jWMgU3RlcGhlbiBDb2xlIEtsZWVuZSBtw7QgdOG6oyBj4bqjIG5nw7RuIG5n4buvIGNow61uaCBxdXkgYuG6sW5nIGPDoWNoIHPhu60gZOG7pW5nIGvDvSBoaeG7h3UgdG/DoW4gaOG7jWMgY+G7p2Egw7RuZyDEkcaw4bujYyBn4buNaSBsw6AgY8OhYyBz4buxIGtp4buHbiBjaMOtbmggcXV5LiBCaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgKFJlZ3VsYXIgRXhwcmVzc2lvbiBoYXkgUmVnZXgpIMSRxrDhu6NjIHPhu60gZOG7pW5nIHBo4buVIGJp4buDbiB04burIG7Eg20gMTk2OCB24bubaSBoYWkgbeG7pWMgxJHDrWNoIHPhu60gZOG7pW5nIGzDoCBt4buZdCBjaHXhu5dpIGPDoWMga8O9IHThu7Ega2jhu5twIHbhu5tpIG3hu5l0IG3huqt1IHRyb25nIHNv4bqhbiB0aOG6o28gdsSDbiBi4bqjbiB2w6AgcGjDom4gdMOtY2ggdOG7qyB24buxbmcgdHJvbmcgdHLDrG5oIGJpw6puIGThu4tjaC4gUmVnZXggxJHGsOG7o2Mgc+G7rSBk4bulbmcgdHJvbmcgc2/huqFuIHRo4bqjbyB2xINuIGLhuqNuIHRyb25nIHLhuqV0IG5oaeG7gXUgbmfDtG4gbmfhu68gbOG6rXAgdHLDrG5oLiBDw6FjIGvDvSB04buxIGPhu6dhIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eSBraMOhIGdp4buRbmcgbmhhdSB0cm9uZyB04bqldCBj4bqjIGPDoWMgbmfDtG4gbmfhu68uIE5oxrBuZyBjw6FjIGNo4bupYyBuxINuZyB0csOtY2ggbOG7jWMsIMSR4buLbmggduG7iywgcGjDoXQgaGnhu4duLCB0w6xtIGtp4bq/bSB2w6AgdGhheSB0aOG6vyBjw7MgdGjhu4Mga2jDoWMgbmhhdSDhu58gY8OhYyBuZ8O0biBuZ+G7ryBraMOhYyBuaGF1Lg0KDQpCaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgxJHGsOG7o2MgdOG6oW8gcmEgYuG6sW5nIGPDoWNoIHPhu60gZOG7pW5nIGPDoWMga8O9IHThu7EgxJHhurdjIGJp4buHdCB2w6Aga8O9IHThu7EgdGjDtG5nIHRoxrDhu51uZyDEkeG7gyBtw7QgdOG6oyBt4buZdCBt4bqrdSBrw70gdOG7sSBj4bulIHRo4buDLiBN4buXaSBrw70gdOG7sSB0cm9uZyBt4buZdCBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgbMOgIG3hu5l0IHNpw6p1IGvDvSB04buxLCBjw7Mgw70gbmdoxKlhIMSR4bq3YyBiaeG7h3QgaG/hurdjIG3hu5l0IGvDvSB04buxIHRow7RuZyB0aMaw4budbmcgY8OzIG5naMSpYSDEkWVuLiBLaGkgbeG7mXQgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IMSRxrDhu6NjIMOhcCBk4bulbmcgY2hvIG3hu5l0IGNodeG7l2kgdsSDbiBi4bqjbiwgbsOzIHPhur0gdMOsbSBraeG6v20gY8OhYyDEkWnhu4NtIHRyw7luZyBraOG7m3AgduG7m2kgbeG6q3UgxJHDoyDEkeG7i25oIG5naMSpYS4gQ8O6IHBow6FwIHNpw6p1IGvDvSB04buxIMSRxrDhu6NjIHRoaeG6v3Qga+G6vyDEkeG6t2MgYmnhu4d0IMSR4buDIGJp4buDdSB0aOG7iyBjw6FjIG3hu6VjIHRpw6p1IMSRxrDhu6NjIGNo4buJIMSR4buLbmggdGhlbyBjw6FjaCBuZ+G6r24gZ+G7jW4gdsOgIGxpbmggaG/huqF0IG5o4bqxbSBoxrDhu5tuZyB04buxIMSR4buZbmcgaMOzYSBxdcOhIHRyw6xuaCB44butIGzDvSB2xINuIGLhuqNuIGPhu6dhIG5oaeG7gXUgbG/huqFpIGThu68gbGnhu4d1IMSR4bqndSB2w6BvLg0KDQpExrDhu5tpIMSRw6J5IGzDoCBt4buZdCBz4buRIGvDvSB04buxIMSR4bq3YyBiaeG7h3QgdGjGsOG7nW5nIMSRxrDhu6NjIHPhu60gZOG7pW5nIHRyb25nIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eToNCg0KLSAgIEvDvSB04buxIHRow7RuZyB0aMaw4budbmc6IMSQ4bqhaSBkaeG7h24gY2hvIGNow61uaCBuw7MuIFbDrSBk4bulOiAiYSIgdMOsbSBraeG6v20ga8O9IHThu7EgImEiIHRyb25nIGNodeG7l2kNCg0KLSAgIEThuqV1IGNo4bqlbSAoIi4iKTogxJDhuqFpIGRp4buHbiBjaG8gYuG6pXQga+G7syBrw70gdOG7sSBuw6BvLCBuZ2/huqFpIHRy4burIGvDvSB04buxIHh14buRbmcgZMOybmcuDQoNCi0gICBLw70gdOG7sSDEkeG6t2MgYmnhu4d0ICIiIChiYWNrc2xhc2gpOiBUaMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgbMOgbSBjaG8ga8O9IHThu7Egc2F1IG7DsyBraMO0bmcgY8OybiBsw6Aga8O9IHThu7EgxJHhurdjIGJp4buHdCBtw6AgdHLhu58gdGjDoG5oIGvDvSB04buxIHRow7RuZyB0aMaw4budbmcuIFbDrSBk4bulOiAiLiIgdMOsbSBraeG6v20gZOG6pXUgY2jhuqVtIHRoYXkgdsOsIMOhcCBk4bulbmcgY2jhu6ljIG7Eg25nIMSR4bq3YyBiaeG7h3QgY+G7p2EgZOG6pXUgY2jhuqVtLg0KDQotICAgS8O9IHThu7EgIltdIjogS2jhu5twIGPDoWMga8O9IHThu7EgaG/hurdjIHRyb25nIGThuqV1IG5nb+G6t2MuDQoNCi0gICBLw70gdOG7sSAiXCoiOiDEkOG6oWkgZGnhu4duIGNobyBi4bqldCBr4buzIHPhu5EgbMaw4bujbmcgeHXhuqV0IGhp4buHbiBj4bunYSBrw70gdOG7sSB0csaw4bubYyBuw7MgKGJhbyBn4buTbSBj4bqjIGtow7RuZyB4deG6pXQgaGnhu4duKS4NCg0KLSAgIEvDvSB04buxICIrIjogxJDhuqFpIGRp4buHbiBjaG8gw610IG5o4bqldCBt4buZdCBob+G6t2Mgbmhp4buBdSBs4bqnbiB4deG6pXQgaGnhu4duIGPhu6dhIGvDvSB04buxIHRyxrDhu5tjIG7Dsy4NCg0KLSAgIEvDvSB04buxICI/IjogxJDhuqFpIGRp4buHbiBjaG8ga2jDtG5nIGhv4bq3YyBt4buZdCBs4bqnbiB4deG6pXQgaGnhu4duIGPhu6dhIGvDvSB04buxIHRyxrDhu5tjIG7Dsy4NCg0KLSAgIEvDvSB04buxICJ7fSI6IFjDoWMgxJHhu4tuaCBz4buRIGzGsOG7o25nIHh14bqldCBoaeG7h24gY+G7p2Ega8O9IHThu7EgdHLGsOG7m2MgbsOzLiBWw60gZOG7pTogImF7M30iIHTDrG0ga2nhur9tIGNodeG7l2kgImFhYSIuDQoNCi0gICBLw70gdOG7sSAiXHwiOiDEkOG6oWkgZGnhu4duIGNobyBwaMOpcCB0w6xtIGtp4bq/bSBt4buZdCB0cm9uZyBjw6FjIGJp4buDdSB0aOG7qWMgxJHGsOG7o2MgxJHhu4tuaCBuZ2jEqWEuIFbDrSBk4bulOiAiY2F0XHxkb2ciIHTDrG0ga2nhur9tIHThu6sgImNhdCIgaG/hurdjICJkb2ciLg0KDQotICAgS8O9IHThu7EgIlxeIiB2w6AgIlwkIiA6IGzDoCDEkWnhu4NtIGLhuq90IMSR4bqndSB2w6AgxJFp4buDbSBr4bq/dCB0aMO6YyBj4bunYSBkw7JuZw0KDQotICAgxJDhu5FpIHbhu5tpIHThuqV0IGPhuqMgY8OhYyBk4bqldSBjaOG6pW0gY8OidSwgZOG6pXUgZ+G6oWNoIGNow6lvIG5nxrDhu6NjIMSRxrDhu6NjIMSR4bq3dCDhu58gcGjDrWEgdHLGsOG7m2MuIFbDrSBk4bulICI/IiBsw6AgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IGNobyBk4bqldSBjaOG6pW0gaOG7j2k6ICI/Ii4gTmjGsG5nIMSR4buDIHZp4bq/dCAiPyIgdHJvbmcgUiwgY2jDum5nIHRhIHBo4bqjaSBz4butIGThu6VuZyBoYWkgZOG6pXUgZ+G6oWNoIGNow6lvIG5nxrDhu6NjOiAiXFw/Ig0KDQotICAgxJDhu5FpIHbhu5tpIGLhuqV0IGvhu7MgY2jhu68gc+G7kSBuw6BvLCBjxaluZyBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgY+G7pW0gdOG7qyB0aMO0bmcgZOG7pW5nICIgb3IgYWxzbyJbOmRpZ2l0Ol0iLiDEkOG7kWkgduG7m2kgY8OhYyBrw70gdOG7sSB04burLCBi4bqhbiBz4butIGThu6VuZyIiIGhv4bq3YyAiWzphbHBoYTpdIiBuaMawIG3hu5l0IGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eS4NCg0KLSAgIls6bG93ZXI6XSIgdsOgICJbOnVwcGVyOl0iOiBUxrDGoW5nIMSRxrDGoW5nIHbhu5tpIFthLXpddsOgIFtBLVpddMawxqFuZyDhu6luZy4gRMO5bmcgxJHhu4MgbGnhu4d0IGvDqiBjw6FjIGvDvSB04buxIHRyb25nIGLhuqNuZyBjaOG7ryBjw6FpIGTGsOG7m2kgZOG6oW5nIGNo4buvIHRoxrDhu51uZyB2w6AgY2jhu68gaW4gaG9hLg0KDQotICJbOmFsbnVtOl0iOiDEkOG6oWkgZGnhu4duIGNobyB04bqldCBj4bqjIGPDoWMga8O9IHThu7EgY2jhu68gdsOgIHPhu5EuIENow7puZyBnacO6cCBsaeG7h3Qga8OqIGPDoWMga8O9IHThu7EgY2jhu68gY8OhaSBiYW8gZ+G7k20gY2jhu68gaG9hIHbDoCBjaOG7ryB0aMaw4budbmcgY8O5bmcgduG7m2kgY8OhYyBz4buRIHThu6sgMCDEkeG6v24gOQ0KDQotICJbOnB1bmN0Ol0iOiBTbyBraOG7m3AgY8OhYyBrw70gdOG7sSBk4bqldSBjaOG6pW0gY8OidS4NCg0KLSAiWzpzcGFjZTpdIjogU28ga2jhu5twIGtob+G6o25nIHRy4bqvbmcgbmjGsCBk4bqldSBjw6FjaCwgdGFiLCBkw7JuZyBt4bubaSwuLi4NCg0KLSAiWzpwcmludDpdIjogTeG7jWkgdGjhu6kgY8OzIHRo4buDIGluIMSRxrDhu6NjLg0KDQojIyMgQ8OhYyBjaOG7qWMgbsSDbmcgY+G7p2EgZ8OzaSBTdHJpbmdyDQoNCsSQ4buDIMSRxrBhIHJhIMSR4buLbmggaMaw4bubbmcgY2h1bmcgduG7gSBjw6FjIGNo4bupYyBuxINuZywgbmjDs20gY2jDum5nIHTDtGkgc+G6vSB0csOsbmggYsOgeSB04buVbmcgcXVhbiBuZ+G6r24gZ+G7jW4gduG7gSBt4buZdCBz4buRIGNo4bupYyBuxINuZyDEkcaw4bujYyBz4butIGThu6VuZyBwaOG7lSBiaeG6v24gbmjhuqV0IGPhu6dhIGfDs2kgU3RyaW5ncg0KDQojIyMjICoqKlF14bqjbiBsw70gxJHhu5kgZMOgaSoqKg0KDQotICAgKipzdHJfbGVuZ3RoKCk6KiogSMOgbSBzdHJfbGVuZ3RoKCkgdHJvbmcgZ8OzaSBTdHJpbmdyIHRy4bqjIHbhu4EgbeG7mXQgdmVjdG9yIGNo4bupYSDEkeG7mSBkw6BpIGPhu6dhIHThu6tuZyBjaHXhu5dpIGvDvSB04buxIHRyb25nIG3hu5l0IHZlY3RvciBjaHXhu5dpLiBLaGkgxJHGsOG7o2Mgw6FwIGThu6VuZyBjaG8gbeG7mXQgdmVjdMahLCBuw7MgdHLhursgduG7gSBt4buZdCB2ZWN0xqEgdHJvbmcgxJHDsyBt4buXaSBt4bulYyBiaeG7g3UgdGjhu4sgc+G7kSBsxrDhu6NuZyBrw70gdOG7sSB0cm9uZyBt4buZdCBjaHXhu5dpIHTGsMahbmcg4bupbmcuDQoNCi0gICAqKnN0cl9wYWQoKToqKiBIw6BtIHN0cl9wYWQoKSB0cm9uZyBnw7NpIFN0cmluZ3IgY8OzIGNo4bupYyBuxINuZyB0aMOqbSBjw6FjIGvDvSB04buxIHbDoG8gYsOqbiB0csOhaSBob+G6t2MgYsOqbiBwaOG6o2kgY+G7p2EgY2h14buXaSAoZMaw4bubaSBk4bqhbmcga2hv4bqjbmcgdHLhuq9uZyBt4bq3YyDEkeG7i25oKS4gxJDhu5kgcuG7mW5nIMSR4buRaSBz4buRIGNobyBiaeG6v3QgxJHhu5kgZMOgaSBj4bunYSBjaHXhu5dpIHNhdSBraGkgdGjDqm0gY8OhYyBrw70gdOG7sSBi4buVIHN1bmcuDQoNCi0gICAqKnN0cl90cnVuYygpOioqIEjDoG0gc3RyX3RydW5jKCkgdHJvbmcgZ8OzaSBTdHJpbmdyIGPDsyBjaOG7qWMgbsSDbmcgcsO6dCBuZ+G6r24gY2h14buXaSB0aMOgbmggY2hp4buBdSBy4buZbmcgxJHhu5FpIHPhu5EgxJHDoyBjaG8uIEPhuqFuaCBtw6AgY2h14buXaSBi4buLIGPhuq90IMSRxrDhu6NjIHjDoWMgxJHhu4tuaCBi4bufaSDEkeG7kWkgc+G7kSBj4bqhbmguDQoNCi0gICAqKnN0cl90cmltKCk6KiogSMOgbSBzdHJfdHJpbSgpIHRyb25nIGfDs2kgU3RyaW5nIGPDsyBjaOG7qWMgbsSDbmcgY+G6r3Qgbmfhuq9uIGPDoWMga2hv4bqjbmcgdHLhuq9uZyB04burIMSR4bqndSBob+G6t2MgY3Xhu5FpIGhv4bq3YyBj4bqjIGhhaS4NCg0KIyMjIyAqKipDaHXhu5dpIGNvbioqKg0KDQotICAgKipzdHJfc3ViKCk6KiogSMOgbSBzdHJfc3ViKCkgdHJvbmcgZ8OzaSBTdHJpbmcgY8OzIGNo4bupYyBuxINuZyB0cuG6oyB24buBIG3hu5lpIGNodeG7l2kgY29uIGPhu6dhIG3hu5l0IGNodeG7l2kgxJHDoyBjaG8uIE7DsyBjw7MgYmEgdGhhbSBz4buROiAtIENodeG7l2kgKGhv4bq3YyBt4buZdCB2ZWN0xqEgY+G7p2EgY2h14buXaSkgLSBDaOG7iSBz4buRIGLhuq90IMSR4bqndSBj4bunYSBjaHXhu5dpIGNvbiAtIENo4buJIHPhu5Ega+G6v3QgdGjDumMgY+G7p2EgY2h14buXaSBjb24NCg0KLSAgICoqc3RyX3N1YnNldCgpOioqIEjDoG0gc3RyX3N1YnNldCgpIGPDsyBjaOG7qWMgbsSDbmcgdHLhuqMgduG7gSBjw6FjIGNodeG7l2kgY2jhu6lhIG3huqt1IGto4bubcC4gSMOgbSB0w6xtIGtp4bq/bSB04bqldCBj4bqjIGPDoWMgY2h14buXaSBjw7MgbeG6q3UgxJHhu5FpIHPhu5EgdHJvbmcgxJHDsyB2w6AgdHLhuqMgY+G7gSB04bqldCBj4bqjIGPDoWMgY2h14buXaSBwaMO5IGjhu6NwIGTGsOG7m2kgZOG6oW5nIG3hu5l0IHThuq1wIGjhu6NwIGNodeG7l2kgbmjhu48gaMahbi4gTsOzIGPDsyBoYWkgdGhhbSBz4buROiB2ZWN0xqEgY+G7p2EgY2h14buXaSDEkeG7gyB0w6xtIGtp4bq/bSB2w6AgY2jDrW5oIG3huqt1IHTDrG0ga2nhur9tLg0KDQotICAgKipzdHJfZXh0cmFjdCgpOioqIEjDoG0gc3RyX2V4dHJhY3QoKSBjw7MgY2jhu6ljIG7Eg25nIHRy4bqjIHbhu4Ega+G6v3QgcXXhuqMga2jhu5twIG3huqt1IMSR4bqndSB0acOqbiDEkcaw4bujYyB0w6xtIHRo4bqleSB0cm9uZyBt4buXaSBjaHXhu5dpIGTGsOG7m2kgZOG6oW5nIG3hu5l0IHZlY3TGoSBrw70gdOG7sS4NCg0KLSAgICoqc3RyX21hdGNoKCk6KiogSMOgbSBzdHJfbWF0Y2goKSBjw7MgY2jhu6ljIG7Eg25nIHRy4bqjIHbhu4Ega+G6v3QgcXXhuqMga2jhu5twIG3huqt1IMSR4bqndSB0acOqbiDEkcaw4bujYyB0w6xtIHRo4bqleSB0cm9uZyBt4buXaSBjaHXhu5dpLCBkxrDhu5tpIGThuqFuZyBt4buZdCBtYSB0cuG6rW4gduG7m2kgbeG7mXQgY+G7mXQgY2hvIG3hu5dpIG5ow7NtICgpIHRyb25nIG3huqt1Lg0KDQojIyMjICoqKlBow6F0IGhp4buHbiBr4bq/dCBxdeG6oyB0csO5bmcga2jhu5twKioqDQoNCi0gICAqKnN0cl9kZXRlY3QoKToqKiBIw6BtIHN0cl9kZXRlY3QoKSBjw7MgY2jhu6ljIG7Eg25nIHBow6F0IGhp4buHbiBz4buxIGhp4buHbiBkaeG7h24gY+G7p2EgbeG7mXQgbeG6q3UgcGjDuSBo4bujcCB0cm9uZyBt4buZdCBjaHXhu5dpLiBL4bq/dCBxdeG6oyDEkcahbiBnaeG6o24gbMOgIG7hur91IG3huqt1IMSRxrDhu6NjIHTDrG0gdGjhuqV5LCBow6BtIHPhur0gdHLhuqMgduG7gSBUUlVFIHbDoCBu4bq/dSBraMO0bmcgxJHGsOG7o2MgdMOsbSB0aOG6pXksIG7DsyBz4bq9IHRy4bqjIHbhu4EgRkFMU0UNCg0KLSAgICoqc3RyX3doaWNoKCk6KiogSMOgbSBzdHJfd2hpY2goKSBjw7MgY2jhu6ljIG7Eg25nIHTDrG0gY8OhYyBjaOG7iSBz4buRIGPhu6dhIGPDoWMgY2h14buXaSBjaOG7qWEgbeG6q3Uga2jhu5twLiDEkOG6p3UgcmEgbMOgIG3hu5l0IHZlY3TGoSB24bubaSBjw6FjIGNo4buJIHPhu5EgbsOgeQ0KDQotICAgKipzdHJfY291bnQoKToqKiBIw6BtIHN0cl9jb3VudCgpIGPDsyBjaOG7qWMgbsSDbmcgxJHhur9tIHPhu5EgbOG6p24gbeG7mXQgbeG6q3UgdMOsbSBraeG6v20geOG6pXUgaGnhu4duIHRyb25nIG3hu5l0IGNodeG7l2kuTsOzIG5o4bqtbiBoYWkgdGhhbSBz4buROiBjaHXhu5dpIHRo4buxYyBoaeG7h24gdMOsbSBraeG6v20gKGhv4bq3YyBt4buZdCB2ZWN0xqEgY2h14buXaSkgdsOgIG3huqt1IHTDrG0ga2nhur9tIGPFqW5nIGPDsyB0aOG7gyBsw6AgbeG7mXQgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5Lg0KDQotICAgKipzdHJfbG9jYXRlKCk6KiogSMOgbSBzdHJfbG9jYXRlKCkgY8OzIGNo4bupYyBuxINuZyB4w6FjIMSR4buLbmggduG7iyB0csOtIGPhu6dhIG3huqt1IGto4bubcCDEkeG6p3UgdGnDqm4gdHJvbmcgbeG7mXQgY2h14buXaQ0KDQojIyMjICoqKkJp4bq/biDEkeG7lWkgY2h14buXaSoqKg0KDQotICAgKipzdHJfcmVwbGFjZSAodsOgIHJlcGxhY2VfYWxsKToqKiBIw6BtIHN0cl9yZXBsYWNlKCkgY8OzIGNo4bupYyBuxINuZyB0aGF5IHRo4bq/IGPhu6dhIGNodeG7l2kgU3RyaW5nciDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyBraOG7m3AgY8OhYyBt4bqrdSB2w6AgdGhheSB0aOG6vyBjaMO6bmcgYuG6sW5nIGPDoWMgY2h14buXaSBt4bubaQ0KDQotICAgKipzdHJfdG9fbG93ZXIoKToqKiBIw6BtIHN0cl90b19sb3dlcigpIGPDsyBjaOG7qWMgbsSDbmcgxJHhu4MgdGhheSDEkeG7lWkgdsSDbiBi4bqjbiB0aMOgbmggY2jhu68gdGjGsOG7nW5nLiBUcm9uZyDEkcOzIGPDsm4gY8OzIGPDoWMgaMOgbToNCg0KMS4gICoqKnN0cl90b190aXRsZSgpKio6IFZp4bq/dCBob2EgY2jhu68gY8OhaSDEkeG6p3UgdGnDqm4gY+G7p2EgbeG7l2kgdOG7qyB0cm9uZyBt4buZdCBjaHXhu5dpKg0KDQoyLiAgKioqc3RyX3RvX3VwcGVyKCk6KiogVmnhur90IGhvYSB0b8OgbiBi4buZIGNodeG7l2kqDQoNCiMjIyMgKioqVGhhbSBnaWEgdsOgIGNoaWEgdMOhY2gqKioNCg0KLSAgICoqc3RyX2MoKToqKiBIw6BtIHN0cl9jKCkgY8OzIGNo4bupYyBuxINuZyDEkeG7gyBu4buRaSBuaGnhu4F1IGNodeG7l2kgdGjDoG5oIG3hu5l0IGNodeG7l2kuDQoNCi0gICAqKnN0cl9zcGxpdCgpOioqIEjDoG0gc3RyX3NwbGl0KCkgY8OzIGNo4bupYyBuxINuZyB0w6FjaCBt4buZdCBjaHXhu5dpIGhv4bq3YyBt4buZdCB2ZWN0xqEgY+G7p2EgY8OhYyBjaHXhu5dpIHRow6BuaCBt4buZdCB2ZWN0xqEgY+G7p2EgY8OhYyBjaHXhu5dpIGNvbiBob+G6t2MgbeG7mXQgZGFuaCBzw6FjaCBjw6FjIHZlY3TGoSBj4bunYSBjw6FjIGNodeG7l2kgY29uLCB0w7l5IHRodeG7mWMgdsOgbyDEkeG7i25oIGThuqFuZyBj4bunYSBk4buvIGxp4buHdSDEkcaw4bujYyB0cnV54buBbiB2w6BvLg0KDQojIyBMw60gZG8gY2jhu41uIGNo4bunIMSR4buBDQoNClIgbMOgIG3hu5l0IG5nw7RuIG5n4buvIGzhuq1wIHRyw6xuaCB2w6AgbcO0aSB0csaw4budbmcgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgcGjhu5UgYmnhur9uIHRyb25nIHRo4budaSDEkeG6oWkgNC4wLiBLaGkgaOG7jWMgUiBuaMOzbSBjaMO6bmcgZW0gbmjhuq1uIHRo4bqleSBy4bqxbmcsIHZp4buHYyB44butIGzDvSBk4buvIGxp4buHdSB0cm9uZyB2xINuIGLhuqNuIHLhuqV0IHF1YW4gdHLhu41uZyB0cm9uZyB2aeG7h2MgdGjhu7FjIGhp4buHbiBjw6FjIG5naGnDqm4gY+G7qXUgdsOgIHBow6JuIHTDrWNoIGThu68gbGnhu4d1LiDEkOG7gyB44butIGzDvSB04buRdCBt4buZdCB2xINuIGLhuqNuIHRow6wgY+G6p24gY8OzIGPDoWMgY8O0bmcgY+G7pSBt4bqhbmggbeG6vSDEkeG7gyB0w6FjaCwgY2h14bqpbiBow7NhIHbEg24gYuG6o24gdsOgIHjhu60gbMO9IGPDoWMga8OtIHThu7EgxJHhurdjIGJp4buHdCBuw6puIG5ow7NtIGNow7puZyBlbSDEkcOjIGzhu7FhIGNo4buNbiBnw7NpIFN0cmluZ3IgbMOgbSBjaOG7pyDEkeG7gSDEkeG7gyB0aOG7sWMgaGnhu4duIGPDoWMgbmdoacOqbiBj4bupdSB2w6AgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UuDQoNCk5nb8OgaSByYSwgZ8OzaSBTdHJpbmdyIGPDsm4gY3VuZyBj4bqlcCBjw6FjIGPDtG5nIGPhu6UgbeG6oW5oIG3hur0gxJHhu4MgeOG7rSBsw70sIHTDoWNoLCBjaHXhuqluIGjDs2EgdsOgIHRyw61jaCB4deG6pXQgdGjDtG5nIHRpbiB04burIGThu68gbGnhu4d1IHbEg24gYuG6o24uIFPhu60gZOG7pW5nIGfDs2kgbsOgeSB0cm9uZyBiw6BpIHRp4buDdSBsdeG6rW4gZ2nDunAgY2jDum5nIGVtIGPDsyBraOG6oyBuxINuZyBoaeG7g3UgdsOgIHjhu60gbMO9IGThu68gbGnhu4d1IHbEg24gYuG6o24gaGnhu4d1IHF14bqjIHBow7kgaOG7o3AgduG7m2kgeHUgaMaw4bubbmcgdsOgIHnDqnUgY+G6p3UgY+G7p2EgdGjhu51pIMSR4bqhaSA0LjAuIFRow6ptIG7hu69hIGfDs2kgU3RyaW5nciDEkcaw4bujYyB0aGnhur90IGvhur8gxJHhu4MgxJHhuqF0IGhp4buHdSBzdeG6pXQgY2FvIHRyb25nIHjhu60gbMO9IGNodeG7l2ksIMSR4bq3YyBiaeG7h3QgbMOgIHRyw6puIGThu68gbGnhu4d1IGzhu5tuLiBWaeG7h2Mgc+G7rSBk4bulbmcgZ8OzaSBuw6B5IGdpw7pwIGNow7puZyBlbSB0aeG6v3Qga2nhu4dtIHRo4budaSBnaWFuIHbDoCB0xINuZyB0w61uaCBoaeG7h3UgcXXhuqMgdHJvbmcgcXXDoSB0csOsbmggeOG7rSBsw70gZOG7ryBsaeG7h3UgY2h14buXaSBwaOG7qWMgdOG6oXANCg0KIyMgTeG7pWMgdGnDqnUgY+G7p2EgY2jhu6cgxJHhu4ENCg0KKipN4bulYyB0acOqdSBjaHVuZyoqIDogU+G7rSBk4bulbmcgZ8OzaSBTdHJpbmdyIG3hu5l0IGPDoWNoIHThu5FpIMawdSB2w6AgaGnhu4d1IHF14bqjIHRyb25nIHF1w6EgdHLDrG5oIGzDoG0gdGnhu4N1IGx14bqtbi4gQ2jDum5nIGVtIHBo4bqjaSB0w6xtIGhp4buDdSBjw6FjIGNo4bupYyBuxINuZyB2w6AgcGjGsMahbmcgcGjDoXAgdHJvbmcgcGFja2FnZSDEkeG7gyBnaeG6o20gdGhp4buDdSB0aOG7nWkgZ2lhbiB2w6AgY8O0bmcgc+G7qWMgY+G6p24gdGhp4bq/dCBjaG8geOG7rSBsw70gY2h14buXaSwgxJHhu5NuZyB0aOG7nWkgdMSDbmcgdMOtbmggbGluaCBob+G6oXQgdsOgIGto4bqjIG7Eg25nIMOhcCBk4bulbmcgdsOgbyBjw6FjIHTDoWMgduG7pSB44butIGzDvSBjaHXhu5dpIHBo4bupYyB04bqhcC4NCg0KKipN4bulYyB0acOqdSBj4bulIHRo4buDOioqDQoNCi0gICAqKk3hu6VjIHRpw6p1IDE6KiogQmnhur90IHjhu60gbMO9IHbDoCBjaHXhuqluIGjDs2EgZOG7ryBsaeG7h3UgdsSDbiBi4bqjbiBnw6wgZ8OzaSAic3RyaW5nciIgY3VuZyBj4bqlcCBjw6FjIGjDoG0gxJHhu4MgbG/huqFpIGLhu48ga2hv4bqjbmcgdHLhuq9uZyB0aOG7q2EsIGvDvSB04buxIMSR4bq3YyBiaeG7h3QsIGThuqV1IGPDonUgaG/hurdjIGPDoWMga8O9IHThu7Ega2jDtG5nIG1vbmcgbXXhu5FuIHRyb25nIHbEg24gYuG6o24uIMSQaeG7gXUgbsOgeSBnacO6cCB0aeG7gW4geOG7rSBsw70gZOG7ryBsaeG7h3UgdsSDbiBi4bqjbiB0csaw4bubYyBraGkgdGnhur9uIGjDoG5oIHBow6JuIHTDrWNoLCDEkeG7k25nIHRo4budaSBjaHXhuqluIGjDs2EgZOG7ryBsaeG7h3UgxJHhu4MgbMOgbSB2aeG7h2MgaGnhu4d1IHF14bqjIGjGoW4uDQotICAgKipN4bulYyB0acOqdSAyOioqIEJJ4bq/dCBjw6FjaCB0w6FjaCB04burIHbDoCB0csOtY2ggeHXhuqV0IHRow7RuZyB0aW4sIHbDrSBk4bulIGPDsyB0aOG7gyB0w6FjaCB04burIHRyb25nIHbEg24gYuG6o24gaG/hurdjIHRyw61jaCB4deG6pXQgY8OhYyB0aMO0bmcgdGluIHF1YW4gdHLhu41uZyBuaMawIHTDqm4sIHPhu5EgxJFp4buHbiB0aG/huqFpLCDEkeG7i2EgY2jhu4kgZW1haWwsIHYudi4gdOG7qyBjaHXhu5dpIGThu68gbGnhu4d1DQotICAgKipN4bulYyB0acOqdSAzOioqIEJp4bq/dCBjw6FjaCB0w6FjaCwgZ2jDqXAsIGNodeG6qW4gaMOzYSwgdMOsbSBraeG6v20gaG/hurdjIHRoYXkgdGjhur8gY8OhYyBjaHXhu5dpIHRyb25nIGThu68gbGnhu4d1IGPhu6dhIG3DrG5oLCB2w6Agc2F1IMSRw7MgcGjDom4gdMOtY2ggdsOgIGLDoW8gY8OhbyBr4bq/dCBxdeG6oyBt4buZdCBjw6FjaCBjaGkgdGnhur90IHbDoCByw7UgcsOgbmcuDQotICAgKipN4bulYyB0acOqdSA0OioqIEJp4bq/dCBraeG7g20gdHJhIHbDoCBzbyBzw6FuaCBjaHXhu5dpIHbDrCBwYWNrYWdlICJzdHJpbmdyIiBjdW5nIGPhuqVwIGPDoWMgaMOgbSDEkeG7gyBraeG7g20gdHJhIHbDoCBzbyBzw6FuaCBjaHXhu5dpLCBnacO6cCBraeG7g20gdHJhIHTDrW5oIGjhu6NwIGzhu4cgY+G7p2EgxJHhu4tuaCBk4bqhbmcsIHTDrG0ga2nhur9tIGNodeG7l2kgY29uIHRyb25nIGNodeG7l2kgY2hhLCB2w6AgdGjhu7FjIGhp4buHbiBjw6FjIHBow6lwIHRvw6FuIHNvIHPDoW5oIGNodeG7l2kuDQotICAgKipN4bulYyB0acOqdSA1OioqIFPhu60gZOG7pW5nIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eSBsaW5oIGhv4bqhdDogR8OzaSAic3RyaW5nciIgaOG7lyB0cuG7oyBz4butIGThu6VuZyBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgdHJvbmcgdmnhu4djIHTDrG0ga2nhur9tIHbDoCB0aGF5IHRo4bq/IGPDoWMgbeG6q3UgdHJvbmcgY2h14buXaS4gxJBp4buBdSBuw6B5IGNobyBwaMOpcCBi4bqhbiB0aOG7sWMgaGnhu4duIGPDoWMgdMOhYyB24bulIHBo4bupYyB04bqhcCBuaMawIHTDrG0ga2nhur9tIHRoZW8gbeG6q3UsIGzhu41jIGThu68gbGnhu4d1LCB2w6AgdGhheSDEkeG7lWkgxJHhu4tuaCBk4bqhbmcgY2h14buXaSBk4buFIGTDoG5nLg0KDQojIyBM4bujaSDDrWNoIGPhu6dhIGNo4bunIMSR4buBDQoNCkfDs2kgU3RyaW5nciB0cm9uZyBSc3R1ZGlvIMSRw6MgbWFuZyBs4bqhaSBuaGnhu4F1IGzhu6NpIMOtY2ggxJHDoW5nIGvhu4MgY2hvIHZp4buHYyB44butIGzDvSBk4buvIGxp4buHdSBuaMawbmcgbsOzIGPFqW5nIGPDsyB0aOG7gyDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyBwaMOibiB0w61jaCB2xINuIGLhuqNuLCDEkeG6t2MgYmnhu4d0IGzDoCB0cm9uZyB2aeG7h2MgeOG7rSBsw70gdsOgIGJp4bq/biDEkeG7lWkgY2h14buVaSBrw60gdOG7sS4gTeG7mXQgc+G7kSBs4bujaSDDrWNoIGNow61uaCBj4bunYSBnw7NpIFN0cmluZ3I6DQoNCjEuICAqKkThu4Ugc+G7rSBk4bulbmc6KiogU3RyaW5nciDEkcaw4bujYyB0aGnhur90IGvhur8gdGjDom4gdGhp4buHbiB2w6AgZOG7hSBz4butIGThu6VuZywgbmdheSBj4bqjIMSR4buRaSB24bubaSBuZ8aw4budaSBt4bubaSBi4bqvdCDEkeG6p3UgY2jGsGEgY8OzIGtpbmggbmdoaeG7h20gbOG6rXAgdHLDrG5oLiBOw7MgY3VuZyBj4bqlcCBt4buZdCBsb+G6oXQgY8OhYyBjw7RuZyBj4bulIHbDoCBjaOG7qWMgbsSDbmcgZ2nDunAgZOG7hSBkw6BuZyBraMOhbSBwaMOhLCBsw6BtIHPhuqFjaCwgdHLhu7FjIHF1YW4gaMOzYSB2w6AgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UuDQoyLiAgKipDw6FjIHTDrW5oIG7Eg25nIG3huqFuaCBt4bq9OioqIE3hurdjIGTDuSDEkcahbiBnaeG6o24gbmjGsG5nIFN0cmluZ3IgY8OzIG3hu5l0IGxv4bqhdCBjw6FjIHTDrW5oIG7Eg25nIG7Dom5nIGNhbyBjaG8gcGjDqXAgYuG6oW4gdGjhu7FjIGhp4buHbiBjw6FjIHTDoWMgduG7pSBwaMOibiB0w61jaCBk4buvIGxp4buHdSBwaOG7qWMgdOG6oXAuIENow7puZyBiYW8gZ+G7k20gY8OhYyB0aHXhuq10IHRvw6FuIGjhu41jIG3DoXksIGtp4buDbSB0cmEgdGjhu5FuZyBrw6ogdsOgIGNo4bupYyBuxINuZyBjaHV54buDbiDEkeG7lWkgZOG7ryBsaeG7h3UuDQozLiAgKirEkMaw4bujYyBz4butIGThu6VuZyBy4buZbmcgcsOjaToqKiBTdHJpbmdyIGzDoCBt4buZdCBnw7NpIHBo4buVIGJp4bq/biB0cm9uZyBSLCB24bubaSBj4buZbmcgxJHhu5NuZyBuZ8aw4budaS4gxJBp4buBdSDEkcOzIGPDsyBuZ2jEqWEgbMOgIGNow7puZyB0YSBjw7MgdGjhu4MgdMOsbSB0aOG6pXkgbmhp4buBdSB0w6BpIGxp4buHdSB2w6AgaOG7lyB0cuG7oyB0cuG7sWMgdHV54bq/biBu4bq/dSBi4bqhbiBjw7MgYuG6pXQga+G7syBjw6J1IGjhu49pIG7DoG8gaG/hurdjIGPhuqduIHRy4bujIGdpw7pwIHbhu4EgbeG7mXQgbmhp4buHbSB24bulIGPhu6UgdGjhu4MuDQo0LiAgKipUw61uaCBsaW5oIGhv4bqhdDoqKiBSIGzDoCBt4buZdCBuZ8O0biBuZ+G7ryBs4bqtcCB0csOsbmggbeG6oW5oIG3hur0gY2hvIHBow6lwIGLhuqFuIHTDuXkgY2jhu4luaCBxdXkgdHLDrG5oIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IGNobyBwaMO5IGjhu6NwIHbhu5tpIG5odSBj4bqndSBj4bunYSBtw6xuaC4gVuG7m2kgU3RyaW5nciwgY2jDum5nIHRhIGPDsyB0aOG7gyB0cnV5IGPhuq1wIMSR4bqneSDEkeG7pyBjw6FjIGto4bqjIG7Eg25nIGPhu6dhIFIgdsOgIHTDrWNoIGjhu6NwIG7DsyB24bubaSBjw6FjIGfDs2kgdsOgIGPDtG5nIGPhu6Uga2jDoWMuDQo1LiAgKipUw61jaCBo4bujcCB04buRdCB24bubaSBjw6FjIGfDs2kga2jDoWMgdHJvbmcgVGlkeXZlcnNlOioqIEfDs2kgIlN0cmluZ3IiIMSRxrDhu6NjIHBow6F0IHRyaeG7g24gbmjGsCBt4buZdCBwaOG6p24gY+G7p2EgInRpZHl2ZXJzZSIsIHbDrCB24bqteSBuw7MgdMOtY2ggaOG7o3AgdOG7kXQgduG7m2kgY8OhYyBnw7NpIGtow6FjIHRyb25nICJ0aWR5dmVyc2UiIG5oxrAgImRwbHlyIiwgImdncGxvdDIiLCB2w6AgInRpZHlyIi4gxJBp4buBdSBuw6B5IGNobyBwaMOpcCBjaMO6bmcgdGEga+G6v3QgaOG7o3AgY8OhYyBjw7RuZyBj4bulIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IGtow6FjIHbDoCB0aOG7sWMgaGnhu4duIGPDoWMgdMOhYyB24bulIHBo4bupYyB04bqhcCB0csOqbiBk4buvIGxp4buHdSBjaHXhu5dpIG3hu5l0IGPDoWNoIGxpbmggaG/huqF0IHbDoCBt4bqhbmggbeG6vS4NCg0KKipHw7NpIFN0cmluZ3IqKiBsw6AgbeG7mXQgbOG7sWEgY2jhu41uIHThu5F0IMSR4buDIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IHRyb25nIFIgZG8gZOG7hSBz4butIGThu6VuZywgY8OhYyB0w61uaCBuxINuZyBt4bqhbmggbeG6vSwgxJHGsOG7o2Mgw6FwIGThu6VuZyBy4buZbmcgcsOjaSB2w6AgbGluaCBob+G6oXQsIMSR4buTbmcgdGjhu51pIGvhur90IGjhu6NwIHThu5F0IHbhu5tpIGPDoWMgZ8OzaSB0cm9uZyAiVGlkeXZlcnNlIi4NCg0KIyAqKkNIxq/GoE5HIDI6IFRoYW8gdMOhYyB24bubaSBjaOG7qWMgbsSDbmcgY+G7p2EgU3RyaW5ncioqDQoNClRyb25nIGNoxrDGoW5nIG7DoHkgbmjDs20gY2jDum5nIHTDtGkgc+G6vSDEkWkgc8OidSB2w6BvIGPDoWNoIGzDoG0gdmnhu4djIHBow6JuIHTDrWNoIGPDoWMgduG7m2kgY2h14buXaSB0cm9uZyBSIHbDoCBwaMOibiB0w61jaCDEkWkgc8OidSB2w6BvIGPDoWNoIGzDoG0gdmnhu4djIGPhu6dhIGjDoG0gdHJvbmcgU3RyaW5nciDEkeG7gyB44butIGzDrSBjw6FjIGNodeG7l2kuIFRy4buNbmcgdMOibSBj4bunYSBjaMawxqFuZyBuw6B5IHPhur0gbMOgIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eSwgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IGzDoCBuZ8O0biBuZ+G7ryBo4buvdSDDrWNoIMSR4buRaSB24bubaSBnw7NpIFN0cmluZ3IgdsOsIGPDoWMgY2h14buXaSB0aMaw4budbmcgY2jhu6lhIGThu68gbGnhu4d1IHBoaSBj4bqldSB0csO6YyBob+G6t2MgYsOhbiBj4bqldSB0csO6YyB2w6AgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IGzDoCBuZ8O0biBuZ+G7ryBuZ+G6r24gZ+G7jW4gxJHhu4MgbcO0IHThuqMgY8OhYyBt4bqrdSB0cm9uZyBjaHXhu5dpLg0KDQojIyBHaeG7m2kgdGhp4buHdSBjaHXhu5dpDQoNCkNodeG7l2kga8O9IHThu7EgY8OzIHRo4buDIHh14bqldCBoaeG7h24gdHJvbmcgdOG6pXQgY+G6oyBjw6FjIGThu7Egw6FuIGPhu6dhIGtob2EgaOG7jWMgZOG7ryBsaeG7h3UuIE5nxrDhu51pIGTDuW5nIGPDsyB0aOG7gyBwaOG6o2kgeMOzYSDEkeG6p3UgdsOgbyBjaHXhu5dpIGzhu5luIHjhu5luIHRyxrDhu5tjIGtoaSBwaMOibiB0w61jaCwgdHLDrWNoIHh14bqldCBk4buvIGxp4buHdSDEkcaw4bujYyBuaMO6bmcgdHJvbmcgdsSDbiBi4bqjbiBob+G6t2MgdOG7sSDEkeG7mW5nIGJp4bq/biBjw6FjIGvhur90IHF14bqjIGThuqFuZyBz4buRIHRow6BuaCBt4buZdCBjw6J1IMSR4buDIMSRxrBhIHbDoG8gYsOhbyBjw6FvLiBC4bqjbiB0aMOibiBjw6FjIGNodeG7l2kgbMOgIGThu68gbGnhu4d1IHF1YW4gdMOibSB2w6AgY2jDum5nIHRhIGPhuqduIHBow6F0IGhp4buHbiB2w6Aga2jhu5twIGPDoWMgbeG6q3UgYsOqbiB0cm9uZyBjaMO6bmcuIENow7puZyBlbSBz4bq9IGLhuq90IMSR4bqndSB24bubaSBt4buZdCBz4buRIHRoYW8gdMOhYyBjxqEgYuG6o246IGPDoWNoIG5o4bqtcCBjaHXhu5dpIHRyb25nIFIsIGPDoWNoIGtp4buDbSBzb8OhdCBjw6FjaCBz4buRIMSRxrDhu6NjIGNodXnhu4NuIMSR4buVaSB0aMOgbmggY2h14buXaSB2w6AgY3Xhu5FpIGPDuW5nIGzDoCBjw6FjaCBr4bq/dCBo4bujcCBjw6FjIGNodeG7l2kgduG7m2kgbmhhdSDEkeG7gyB04bqhbyDEkeG6p3UgcmEga+G6v3QgaOG7o3AgdsSDbiBi4bqjbiB2w6Agc+G7kSDEkcaw4bujYyDEkeG7i25oIGThuqFuZyDEkeG7mWMgxJHDoW8uDQoNCiAgDQojIyBC4buZIGThu68gbGnhu4d1ICANCiAgDQpExrDhu5tpIMSRw6J5IGzDoCBoYWkgYuG7mSBk4buvIGxp4buHdSDEkcOjIMSRxrDhu6NjIGPDoGkgxJHhurd0IHPhurNuIHRyb25nIGfDs2kgU3RyaW5nciwgYmFvIGfhu5NtICoqZnJ1aXQqKiBjaG8gY2jDum5nIHRhIGJp4bq/dCA3OSBsb+G6oWkgdHLDoWkgY8OieSB2w6AgZOG7ryBsaeG7h3UgKipzZW50ZW5jZXMqKiBiYW8gZ+G7k20gNzIwIGTDsm5nLiBUw7RpIGTDuW5nIGzhu4duaCAqKmhlYWQoKSoqIMSR4buDIHhlbSA2IGTDsm5nIMSR4bqndSBj4bunYSAyIGLhu5kgZOG7ryBsaeG7h3U6DQogIA0KYGBge3J9DQpmcnVpdCA9IHN0cmluZ3I6OmZydWl0DQpoZWFkKGZydWl0KQ0KYGBgDQpgYGB7cn0NCnNlbnRlbmNlcyA9IHN0cmluZ3I6OnNlbnRlbmNlcw0KaGVhZChzZW50ZW5jZXMpDQpgYGANCg0KDQpgYGB7cixlY2hvPUZBTFNFLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoRFQpDQoNCmBgYA0KDQrEkOG7gyB0aOG7sWMgaGnhu4duIHThu5F0IGjGoW4gY2jDum5nIGVtIHPhur0gZ+G7jWkgZ8OzaSAqKioiYmFieW5hbWUiKioqIHbDoCAqKioiZHBseXIiKioqIMSR4buDIGjhu5UgdHLhu40gY2hvIHZp4buHYyBwaMOibiB0w61jaCBjaHXhu5dpIHbDoCBjw6FjIGjDoG0uIA0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGJhYnluYW1lcykNCg0KYGBgDQoNClRyxrDhu5tjIHRpw6puLGNow7puZyBlbSBz4bq9IHPhu60gZOG7pW5nIGfDs2kgKioq4oCcYmFieW5hbWVz4oCdKioqIMSR4buDIGfhu41pIHjhu60gbMO9IGThu68gbGnhu4d1IHbhu4EgY8OhYyB0w6puIHRy4bq7IGVtIHBo4buVIGJp4bq/biB0aGVvIG7Eg20gdsOgIGdp4bubaSB0w61uaA0KDQpgYGB7cn0NCmJhYnluYW1lcyA9IGJhYnluYW1lczo6YmFieW5hbWVzDQpoZWFkKGJhYnluYW1lcykNCmBgYA0KDQojIyBUaGFvIHTDoWMgY2h14buXaSBjxqEgYuG6o24NCg0KQ2jDum5nIGVtIHPhur0gYuG6r3QgxJHhuqd1IGLhurFuZyBjw6FjaCB0w6xtIGhp4buDdSB24buBIG3hu5l0IHPhu5EgaMOgbSBTdHJpbmdyIHLhuqV0IGdp4buRbmcgduG7m2kgbeG7mXQgc+G7kSBow6BtIFIgY8ahIHPhu58sIHNhdSDEkcOzIGzDoCBjw6FjaCBwaMOhdCBoaeG7h24gY8OhYyBt4bqrdSBj4bulIHRo4buDIHRyb25nIGNodeG7l2ksIGPDoWNoIHTDoWNoIGNodeG7l2kgdGjDoG5oIG5oaeG7gXUgcGjhuqduIGPFqW5nIG5oxrAgY8OhY2ggdMOsbSB2w6AgdGhheSB0aOG6vyBjw6FjIHBo4bqnbiBj4bunYSBjaHXhu5dpLg0KDQpDw6FjIGNo4bupYyBuxINuZyBj4bunYSBTdHJpbmdyIMSR4buBdSBi4bqvdCDEkeG6p3UgYuG6sW5nIHN0cl8gxJFp4buBdSBuw6B5IHThuqFvIMSRaeG7gXUga2nhu4duIHRodeG6rW4gbOG7o2kgY2hvIHZp4buHYyB0w6xtIGzhu4duaCB0aMOtY2ggaOG7o3AuIENow7puZyB0YSBjaOG7iSBj4bqnbiBuaOG6rXAgc3RyXyB2w6AgY2jhu6ljIG7Eg25nIHThu7EgxJHhu5luZyDEkeG7gSB4deG6pXQgY+G7p2EgUnN0dWRpbyBz4bq9IGhp4buHbiB0aOG7iyBuaOG7r25nIHBo4bqnbiBjw7JuIGzhuqFpLiANCg0KxJDhuqd1IHRpw6puIMSR4buDIHRo4buxYyBoaeG7h24gY8OhYyBjaOG7qWMgbsSDbmcgbGnDqm4gcXVhbiDEkeG6v24gY2h14buXaSB0aMOsIGNow7puZyB0YSBj4bqnbiBjw6BpIMSR4bq3dCB2w6AgZ+G7jWkgZ8OzaSBTdHJpbmdyIGzDqm4uDQoNCmBgYHtyLGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCiAgDQpgYGB7cn0NCmxpYnJhcnkoc3RyaW5ncikNCmBgYA0KDQojIyMgUXXhuqNuIGzDvSDEkeG7mSBkw6BpIGNodeG7l2kgDQoNCiAgKioxLiBzdHJfbGVuZ3RoKHN0cmluZyk6KiogVHLhuqMgduG7gSBt4buZdCDEkeG7mSBkw6BpIGPhu6dhIG3hu5l0IGNodeG7l2kgYmFvIGfhu5NtIGPhuqMga2hv4bqjbmcgdHLhuq9uZyB2w6AgY+G6oyBk4bqldSBjaOG6pW0gY8OidS4gVHJvbmcgxJHDsyAqKnN0cmluZyoqIGzDoCBt4buZdCB2ZWN0byDEkeG6p3UgdsOgbyBob+G6t2MgbMOgIG3hu5l0IHZlY3RvIGvDrSB04buxLg0KDQoNCiANCmBgYHtyfQ0Kc3RyX2xlbmd0aChzZW50ZW5jZXNbMl0pDQpgYGANCj1cPiBL4bq/dCBxdeG6oyBuw6B5IHRy4bqjIHbhu4EgY2hvIGNow7puZyB0YSBiaeG6v3QgxJHhu5kgZMOgaSBj4bunYSBkw7JuZyB0aOG7rSAyIGPhu6dhIHNlbnRlbmNlcyBiYW8gZ+G7k20gNDMga8OtIHThu7EgYmFvIGfhu5NtIGPhuqMga2hv4bqjbmcgdHLhuq9uZy4gDQoNCioqVsOtIGThu6U6KiogVHLDrWNoIHh14bqldCB2ZWN0b3IgdMOqbiBjb24gdHJhaSB2w6AgdMOqbiBjb24gZ8OhaSB0cm9uZyBuxINtIDIwMTQuIENo4buNbiBuaOG7r25nIGjDoG5nIGPDsyBnacOhIHRy4buLIHRyb25nIGPhu5l0IOKAnHNleOKAnSBsw6Ag4oCcTeKAnSAobmFtIGdp4bubaSksY+G7mXQg4oCcc2V44oCdIGzDoCDigJxG4oCdIChu4buvIGdp4bubaSkgdsOgIHNhdSDEkcOzIGNo4buJIGzhuqV5IGPDoWMgZ2nDoSB0cuG7iyB0cm9uZyBj4buZdCDigJxuYW1l4oCdDQoNCmBgYHtyfQ0KYmFieW5hbWVzXzIwMTQgPC0gZmlsdGVyKGJhYnluYW1lcywgeWVhciA9PSAyMDE0KQ0KYm95X25hbWVzIDwtIGZpbHRlcihiYWJ5bmFtZXNfMjAxNCwgc2V4ID09ICJNIikkbmFtZQ0KZ2lybF9uYW1lcyA8LSBmaWx0ZXIoYmFieW5hbWVzXzIwMTQsIHNleCA9PSAiRiIpJG5hbWUNCg0KaGVhZChib3lfbmFtZXMpDQpgYGANCg0KQsOieSBnaeG7nSBlbSBz4bq9IGTDuW5nIGNo4bupbmcgbsSDbmcgKioqc3RyX2xlbmd0aCoqKiDEkeG7gyB0w6xtIMSR4buZIGTDoGkgY+G7p2EgdOG6pXQgY+G6oyBjw6FjIHTDqm4gdHJvbmcgYm95X25hbWVzIG3DoCDEkcOjIMSRxrDhu6NjIGxp4buHdCBrw6og4bufIHRyw6puLCBzYXUgxJHDsyBlbSBkw7luZyBs4buHbmggKioqaGVhZCgpKioqIMSR4buDIHhlbSBr4bq/dCBxdeG6oyB0cuG6oyB24buBIGPhu6dhIMSR4buZIGTDoGkgY8OhYyB0w6puIMSRw7MNCg0KYGBge3J9DQpib3lfbGVuZ3RoIDwtIHN0cl9sZW5ndGgoYm95X25hbWVzKQ0KaGVhZChib3lfbGVuZ3RoKQ0KYGBgDQoNCkNow7puZyB0YSBjxaluZyBjw7MgdGjhu4MgZMO5bmcgaMOgbSBjaOG7qW5nIG7Eg25nICoqKnN0cl9sZW5ndGgqKiogxJHhu4Mgc28gc8OhbmggxJHhu5kgZMOgaSB0cnVuZyBiw6xuaCBnaeG7r2EgdMOqbiBjb24gZ8OhaSB2w6AgY29uIHRyYWkgdsOgIGPDonUgbOG7h25oIHBow61hIGTGsOG7m2kgY2jDum5nIGVtIHPhur0gdGjhu7FjIGhp4buHbiBs4buHbmggxJHDszoNCg0KYGBge3J9DQpnaXJsX2xlbmd0aCA8LSBzdHJfbGVuZ3RoKGdpcmxfbmFtZXMpDQptZWFuKGdpcmxfbGVuZ3RoKSAtIG1lYW4oYm95X2xlbmd0aCkNCmBgYA0KDQo9XD4gS+G6v3QgcXXhuqMgdHLhuqMgduG7gSBjaG8gdGjhuqV5IMSR4buZIGTDoGkgdHJ1bmcgYsOsbmggY+G7p2EgY8OhYyB0w6puIHRyb25nIGdpcmxzX25hbWUgZMOgaSBoxqFuIGJveV9uYW1lIGzDoCAwLjMzNzQ3NTgNCg0KS+G6v3QgbHXhuq1uOiDEkOG7mSBkw6BpIHRydW5nIGLDrG5oIGPhu6dhIHTDqm4gY29uIGfDoWkgdsOgbyBuxINtIDIwMTQgZMOgaSBoxqFuIG3hu5l0IGvDvSB04buxIGtob+G6o25nIG3hu5l0IHBo4bqnbiBiYS4gxJDDonkgbMOgIGNvbiBz4buRIHRydW5nIGLDrG5oIG5nw6J5IHRoxqEgdHJvbmcgxJHDsyBt4buXaSBjw6FpIHTDqm4gxJHGsOG7o2MgdMOtbmggbeG7mXQgbOG6p24sIGtow7RuZyBwaOG6o2kgdGhlbyBz4buRIGzGsOG7o25nIGVtIGLDqSDEkcOjIG5o4bqtbiDEkcaw4bujYyB0w6puLiBN4buZdCBwaMOpcCBzbyBzw6FuaCB04buRdCBoxqFuIGPDsyB0aOG7gyBsw6AgdHLhu41uZyBz4buRIHRydW5nIGLDrG5oIGPhu6dhIGPhu5l0IG4gdHJvbmcgYmFieW5hbWVzDQoNCiAgKioyLsSQ4buHbSBjaHXhu5dpIGLhurFuZyBzdHJfcGFkKCkqKg0KDQrEkOG7h20gY2h14buXaSBsacOqbiBxdWFuIMSR4bq/biB2aeG7h2MgdGjDqm0gY8OhYyBrw70gdOG7sSB2w6BvIG3hu5l0IGNodeG7l2kgxJHhu4MgbMOgbSBjaG8gbsOzIGPDsyDEkeG7mSBkw6BpIG5o4bqldCDEkeG7i25oLiBIw6BtIHN0cl9wYWQoKSB0cm9uZyBnw7NpIFN0cmluZ3IgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgxJHhu4dtIGNodeG7l2kgdsOgIGvhur90IHF14bqjIHPhur0gdHLhuqMgduG7gSBt4buZdCB2ZWN0byBjaOG7qWEgY8OhYyBjaHXhu5dpIMSRxrDhu6NjIMSR4buHbS4gRMaw4bubaSDEkcOieSBsw6AgbeG7mXQgc+G7kSB0aGFtIHPhu5EgdHJvbmcgaMOgbS4NCg0KQ8O6IHBow6FwOiBzdHJfcGFkKHN0cmluZyx3aWR0aCwgc2lkZSA9IGMoImxlZnQiLCJyaWdodCIsImJvdGgiKSxwYWQgPSAiICIpOg0KDQpUcm9uZyDEkcOzOg0KICANCiAgLSAqKlN0cmluZyoqOiBjaHXhu5dpIMSR4bqndSB2w6BvIG3DoCBjaMO6bmcgdGEgbXXhu5FuIMSR4buHbQ0KICAtICoqd2lkdGgqKjogxJDhu5kgcuG7mW5nIG1vbmcgbXXhu5FuIGPhu6dhIGNodeG7l2kga+G6v3QgcXXhuqMgc2F1IGtoaSDEkeG7h20NCiAgLSAqKlNpZGUqKjogQ2jhu4kgxJHhu4tuaCDEkeG7h20gY8OhYyBjaHXhu5dpIOG7nyBiw6puIHRyw6FpLCBiw6puIHBo4bqjaSBoYXkgY+G6oyBoYWkgYsOqbg0KICAtICoqUGFkKio6IEvDvSB04buxIGTDuW5nIMSR4buDIMSR4buHbS4gR2nDoSB0cuG7iyBt4bq3YyDEkeG7i25oIGzDoCBraG/huqNuZyB0cuG6r25nKCIgIikNCiAgDQoqKlbDrSBk4bulIDE6KiogRW0gxJHhu4dtIHRow6ptIDE1IGvDrSB04buxIGzDoCBraG/huqNuZyB0cuG6r25nIOG7nyBwaMOtYSBiw6puIHRyw6FpIGNobyBjaHXhu5dpICoqKmZydWl0KioqIOG7nyBkw7JuZyAxIGzDoCAqKiphcHBsZSoqKg0KDQpgYGB7cn0NCnN0cl9wYWQoZnJ1aXRbMV0sd2lkdGggPSAxNSwgc2lkZSA9ICdsZWZ0JykNCmBgYA0KDQoqKlbDrSBk4bulIDI6KiogRW0gxJHhu4dtIHRow6ptIDIwIGtob+G6o25nIHRy4bqvbmcg4bufIGPhuqMgaGFpIGLDqm4gYuG6sW5nIGThuqV1ICoqIiAtICIqKiBjaG8gZnJ1aXQg4bufIGTDsm5nIDIgbMOgICoqKmFwcmljb3QqKioNCg0KYGBge3J9DQpzdHJfcGFkKGZydWl0WzJdLHdpZHRoID0gMjAsIHNpZGUgPSAnYm90aCcsIHBhZCA9ICctJyApDQpgYGANCg0KKipWw60gZOG7pSAzOioqIEVtIMSR4buHbSB0aMOqbSA1MCBraG/huqNuZyB0cuG6r25nIGLhurFuZyBz4buRICoqMCoqIHbDoG8gY2h14buXaSAqKipzZW50ZW5jZXMqKiog4bufIGTDsm5nIHRo4bupIDIgY+G7p2EgY2h14buXaSB2w6Aga+G6v3QgcXXhuqMgdHLhuqMgduG7gSBr4bq/dCBxdeG6oyBkxrDhu5tpIMSRw6J5Og0KDQpgYGB7cn0NCnN0cl9wYWQoc2VudGVuY2VzWzJdLHdpZHRoID0gNTAsIHNpZGUgPSAncmlnaHQnLCBwYWQgPSAnMCcpDQpgYGANCg0KKipWw60gZOG7pSA0OioqIFRyb25nIHbDrSBk4bulIG7DoHkgZW0gbXXhu5FuIMSR4buHbSB0aMOqbSAxMDAga8OtIHThu7EgbMOgIGThuqV1ICoqIi4iKiog4bufIGLDqm4gcGjhuqNpIHbDoG8gY2h14buXaSAqKipzZW50ZW5jZXMqKiog4bufIGTDsm5nIHRo4bupIDUuIFbDoCBjw6J1IGzhu4duaCB0cuG6oyB24buBIGvhur90IHF14bqjOg0KDQpgYGB7cn0NCnN0cl9wYWQoc2VudGVuY2VzWzVdLHdpZHRoID0gMTAwLCBzaWRlID0gJ3JpZ2h0JywgcGFkID0gJy4nKQ0KYGBgDQoNCioqVsOtIGThu6UgNToqKiBUaMOqbSBraG/huqNuZyB0cuG6r25nIHbDoG8gbeG7mXQgY2h14buXaSAoxJHhu5FpIHbhu5tpIG3hu5l0IGvDvSB04buxKQ0KDQpgYGB7cn0NCnN0cl9wYWQoImJveV9uYW1lcyIsMTEsc2lkZSA9ICJib3RoIikgI2NobyBiaWV0IGRvIGRhaSBzYXUga2hpIHRoZW0gbGEgMTENCg0KYGBgDQoNClRoYW0gc+G7kSBwYWQgY8OzIHRo4buDIGNo4buJIMSR4buLbmggY8OhYyBrw70gdOG7sSBj4bqnbiDEkWnhu4FuDQoNCmBgYHtyfQ0Kc3RyX3BhZCgiYm95X25hbWVzIiwxMSxzaWRlID0gImJvdGgiLHBhZCA9ICIqIikNCg0KYGBgDQoNCkvhur90IGjhu6NwIHbhu5tpIGfDs2kgUHVycnIsIGzhuq1wIHRyw6xuaCBjaOG7qWMgbsSDbmcgY8OzIHRo4buDIMSRxrDhu6NjIHZlY3RvciBow7NhIMSR4buDIGxv4bqhaSBi4buPIGtob+G6o25nIHRy4bqvbmcgdsOgIHRow6ptIGtob+G6o25nIHRy4bqvbmcNCg0KYGBge3J9DQp4IDwtIGMoImJveV9uYW1lcyIsImdpcmxfbmFtZXMiKQ0KbGlicmFyeShwdXJycikNCmBgYA0KDQpgYGB7cn0NCm1hcF9jaHIoeCxzdHJfcGFkLDExLHNpZGUgPSAibGVmdCIpDQoNCmBgYA0KDQpgYGB7cn0NCnN0cl9jKHhbc2VxX2xlbigzKSAtIDFdLGNvbGxhcHNlID0gIiwiKQ0KDQpgYGANCg0KICAqKjMuIFLDunQgbmfhuq9uIGNodeG7l2kgYuG6sW5nIHN0cl90cnVuYygpKioNCg0KUsO6dCBuZ+G6r24gY2h14buXaSBsacOqbiBxdWFuIMSR4bq/biB2aeG7h2MgcsO6dCBuZ+G6r24gY8OhYyBrw70gdOG7sSDhu58gxJHhuqd1LCBjdeG7kWkgaG/hurdjIOG7nyBnaeG7r2EgY+G7p2EgY2h14buXaS4gSMOgbSBzdHJfdHJ1bmMoKSB0cm9uZyBnw7NpIFN0cmluZ3IgY8OzIGNo4bupYyBuxINuZyByw7p0IG5n4bqvbiBjaHXhu5dpIHRow6BuaCBjaGnhu4F1IHLhu5luZyDEkeG7kWkgc+G7kSDEkcOjIGNobywgY+G6oW5oIG3DoCBjaHXhu5dpIGLhu4sgY+G6r3QgxJHGsOG7o2MgeMOhYyDEkeG7i25oIGLhu59pIMSR4buRaSBz4buRIGPhuqFuaC4NCg0KQ8O6IHBow6FwOiBzdHJfdHJ1bmMoc3RyaW5nLHdpZHRoLCBzaWRlID0gYygibGVmdCIsInJpZ2h0IiwiY2VudGVyIik6IA0KICANCiAgLSAqKnN0cmluZyoqOiBsw6AgY2h14buXaSDEkeG6p3UgdsOgbyBtw6AgY2jDum5nIHRhIG114buRbiBj4bqvdA0KICAtICoqd2lkdGgqKjogY2hp4buBdSBy4buZbmcgdOG7kWkgxJFhIGPhu6dhIGNodeG7l2kNCiAgLSAqKnNpZGUqKjogVuG7iyB0csOtIGNobyBiaeG6v3QgbuG7mWkgZHVuZyDEkcOjIGLhu4sgeMOzYQ0KICANCioqVsOtIGThu6U6KiogVHJvbmcgdsOtIGThu6UgbsOgeSBjaMO6bmcgZW0gZMO5bmcgY2jhu6ljIG7Eg25nICoqKnN0cl90cnVuYyoqKiDEkeG7gyBj4bqvdCAxNyBrw60gdOG7sSDhu58gcGjDrWEgYsOqbiBwaOG6o2kgY+G7p2EgY2h14buXaSAqKipzZW50ZW5jZXMqKiog4bufIGTDsm5nIHRo4bupIDIgdsOgIGvhur90IHF14bqjIHRy4bqjIHbhu4EgbMOgOg0KDQpgYGB7cn0NCnN0cl90cnVuYyhzZW50ZW5jZXNbMV0sd2lkdGggPSAxNyxzaWRlID0gJ3JpZ2h0JykNCmBgYA0KDQogICoqNC4gQ+G6r3QgeMOpbiBjaHXhu5dpIGLhurFuZyBzdHJfdHJpbSgpKioNCiANCkPhuq90IHjDqW4gY2h14buXaSBsacOqbiBxdWFuIMSR4bq/biB2aeG7h2MgbG/huqFpIGLhu48gY8OhYyBrw70gdOG7sSB0cuG6r25nIOG7nyDEkeG6p3UgaG/hurdjIGN14buRaSBjaHXhu5dpLiBIw6BtIHN0cl90cmltKCkgdHJvbmcgZ8OzaSBTdHJpbmdyIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIGPhuq90IGNodeG7l2kgdsOgIGvhur90IHF14bqjIHRy4bqjIHbhu4EgbeG7mXQgdmVjdG8ga8O9IHThu7EgY2jhu6lhIGPDoWMgY2h14buXaSDEkcOjIGPhuq90LiBExrDhu5tpIMSRw6J5IGzDoCBjw6FjIHRoYW0gc+G7kSB0cm9uZyBow6BtLg0KDQpDw7ogcGjDoXA6IHN0cl90cmltKHN0cmluZyxzaWRlID0gYygibGVmdCIsInJpZ2h0IiwiYm90aCIpKQ0KDQpUcm9uZyDEkcOzOg0KDQogIC0gKipzdHJpbmcqKjogVGhhbSBz4buRIG7DoHkgxJHhuqFpIGRp4buHbiBjaG8gY2h14buXaSBrw70gdOG7sSBob+G6t2MgdmVjdG8gY+G7p2EgY2h14buXaSBz4bq9IMSRxrDhu6NjIGPhuq90IGLhu5t0DQogIC0gKipzaWRlKio6IFRoYW0gc+G7kSBuw6B5IGNo4buJIMSR4buLbmggY2hvIGPDoWMgYsOqbiBj4bunYSBjaHXhu5dpIGPhuqduIGPhuq90LCBjw7MgdGjhu4MgbMOgIHBow61hIHBo4bqjaSwgdHLDoWkgaG/hurdjIGPhuqMgaGFpIGLDqm4NCiAgDQoqKlbDrSBk4bulOioqDQoNCmBgYHtyfQ0Kc3RyX3RyaW0oc2VudGVuY2VzWzVdLHNpZGUgPSAnbGVmdCcpDQoNCmBgYA0KDQpMb2Hhu4sgYuG7jyBjw6FjIGtob+G6o25nIHRy4bqvbmcgZMawIHRo4burYSDhu58gxJHhuqd1IHbDoCBjdeG7kWkgY+G7p2EgbeG7mXQgY2h14buXaSBrw70gdOG7sQ0KDQpgYGB7cn0NCnN0cl90cmltKCIgYm95X25hbWVzICIpDQpgYGANCg0KQ2jDum5nIGPFqW5nIGPDsyB0aOG7gyBjaOG7iSDEkeG7i25oIHBo4bqnbiBjdeG7kWkgY+G7p2Ega2hv4bqjbmcgdHLhu5FuZyBj4bqnbiB4w7NhLiBWw60gZOG7pSBsb+G6oWkgYuG7jyBjw6FjIGtob+G6o25nIHRy4bqvbmcgZMawIHRo4burYSDhu58gcGjDrWEgYsOqbiB0csOhaSBj4bunYSBt4buZdCBjaHXhu5dpIGvDvSB04buxOg0KDQpgYGB7cn0NCnN0cl90cmltKCIgYm95bmFtZXMgIixzaWRlID0gImxlZnQiKQ0KYGBgDQoNCiMjIyBDaHXhu5dpIGNvbg0KDQogICoqMS4gVHLDrWNoIHh14bqldCBk4buvIGxp4buHdSBi4bqxbmcgY8OhY2ggc+G7rSBk4bulbmcgc3RyX3N1YigpKioNCiAgDQpUcsOtY2ggeHXhuqV0IGNodeG7l2kgY29uIGxpw6puIHF1YW4gxJHhur9uIHZp4buHYyB0csOtY2ggbeG7mXQgcGjhuqduIGPhu6dhIGNodeG7l2kuIEjDoG0gc3RyX3N1YigpIHRyb25nIGfDs2kgU3RyaW5nciDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyB0csOtY2ggeHXhuqV0IGhv4bq3YyB0aGF5IHRo4bq/IGPDoWMgY2h14buXaSBjb24uIETGsOG7m2kgxJHDonkgbMOgIG3hu5l0IHPhu5EgdGhhbSBz4buRIMSRxrDhu6NjIHPhu60gZOG7pW5nIHRyb25nIGjDoG0gc3RyX3N1YigpOg0KDQpDw7ogcGjDoXA6IHN0cl9zdWIoc3RyaW5nLCBzdGFydCA9IDFMLCBlbmQgPSAtMUwpDQoNCiAgLSAqKnN0cmluZyoqOiBsw6AgdmVjdG8gxJHhuqd1IHbDoG8gaG/hurdjIGzDoCBt4buZdCB2ZWN0byBrw60gdOG7sQ0KICAtICoqc3RhcnQqKjogY2jhu4kgxJHhu4tuaCB24buLIHRyw60ga8O9IHThu7EgxJHhuqd1IHRpw6puIHRyb25nIGNodeG7l2kgY29uIHPhur0gxJHGsOG7o2MgdHLDrWNoIHh14bqldA0KICAtICoqZW5kKio6IENo4buJIMSR4buLbmggduG7iyB0csOtIGPhu6dhIGvDvSB04buxIGN14buRaSBjw7luZyB0cm9uZyBjw6FjIGNodeG7l2kgY29uIHPhur0gxJHGsOG7o2MgdHLDrWNoIHh14bqldA0KICANCioqVsOtIGThu6U6Kiogc3RyX3N1Yih4LCAxLCAzKSB5w6p1IGPhuqd1IGNodeG7l2kgY29uIGLhuq90IMSR4bqndSB04burIGvDvSB04buxIMSR4bqndSB0acOqbiwgY2hvIMSR4bq/biBrw70gdOG7sSB0aOG7qSBiYSBob+G6t2MgbsOzaSBjw6FjaCBraMOhYyBsw6AgYmEga8O9IHThu7EgxJHhuqd1IHRpw6puLg0KDQpgYGB7cn0NCmJnIDwtIGMoImJveV9uYW1lcyIsImdpcmxfbmFtZXMiKQ0Kc3RyX3N1YihiZywxLDMpDQpgYGANCg0KKipWw60gZOG7pToqKiBjaMO6bmcgdGEgY8OzIHRo4buDIHRyw61jaCB4deG6pXQgY2h14buXaSBjb24gduG7m2kgbmjhu69uZyBrw60gdOG7sSBjdeG7kWkgY2h14buXaSBi4bqxbmcgc+G7kSBuZ3V5w6puIMOibS4gVHJvbmcgdsOtIHN0cl9zdWIoYmcsLTMsLTEpIHnDqnUgY+G6p3UgY2h14buXaSBjb24gYuG6sW5nIDMga8OtIHThu7EgY3Xhu5FpIGNodeG7l2kuDQoNCmBgYHtyfQ0Kc3RyX3N1YihiZywtMywtMSkNCg0KYGBgDQpCw6puIGPhuqFuaCDEkcOzIGNow7puZyB0YSBjw7MgdGjhu4MgdHLDrWNoIHh14bqldCBjw6FjIGNo4buvIGPDoWkgxJHDonUgdGnDqm4gdHJvbmcgYm95X25hbWVzIHNhdSDEkcOzIGNow7puZyB0YSBs4bqtcCBi4bqjbmcuDQoNCmBgYHtyfQ0KYm95X2ZpcnN0X2xldHRlciA8LSBzdHJfc3ViKGJveV9uYW1lcywgMSwgMSkNCnRhYmxlKGJveV9maXJzdF9sZXR0ZXIpDQpgYGANCg0KPVw+IEvhur90IHF14bqjIGNobyBjaMO6bmcgdGEgYmnhur90IGPDsyAxNDU0IG5nxrDhu51pIGPDsyB0w6puIGLhuq90IMSR4bqndSBi4bqxbmcgY2jhu68gQSwgY8OzIDY1MSBuZ8aw4budaSBi4bqvdCDEkeG6p3UgYuG6sW5nIGNo4buvIEIsLi4uDQoNCkhv4bq3YyBsw6AgY2jDum5nIHRhIGPDsyB0aOG7gyB0csOtY2ggeHXhuqV0IGNo4buvIGPDoWkgY3Xhu5FpIGPDuW5nIHRyb25nIGJveV9uYW1lcyB2w6Agc2F1IMSRw7MgbOG6rXAgYuG6o25nDQoNCmBgYHtyfQ0KYm95X2xhc3RfbGV0dGVyIDwtIHN0cl9zdWIoYm95X25hbWVzLCAtMSwgLTEpDQp0YWJsZShib3lfbGFzdF9sZXR0ZXIpDQpgYGANCg0KPVw+IEvhur90IHF14bqjIHRy4bqjIHbhu4EgY2hvIGNow7puZyB0YSBiaeG6v3QgY8OzIDQyMSBuZ8aw4budaSBjw7MgdMOqbiBr4bq/dCB0aMO6YyBi4bqxbmcgY2jhu68gYSwgMTA0IG5nxrDhu51pIGPDsyB0w6puIGvhur90IHRo4bupYyBi4bqxbmcgY2jhu68gYiwuLiwNCg0KS+G6v3QgbHXhuq1uOiDigJxB4oCdIGzDoCBjaOG7ryBjw6FpIMSR4bqndSB0acOqbiBwaOG7lSBiaeG6v24gbmjhuqV0IGNobyBj4bqjIGLDqSB0cmFpIHbDoCBiw6kgZ8OhaSwgdsOgIGzDoCBjaOG7ryBjw6FpIGN14buRaSBjw7luZyBwaOG7lSBiaeG6v24gbmjhuqV0IGNobyBiw6kgZ8OhaS4gVHV5IG5oacOqbiwgY2jhu68gY8OhaSBjdeG7kWkgY8O5bmcgcGjhu5UgYmnhur9uIG5o4bqldCBjaG8gdMOqbiBjb24gdHJhaSBsw6Ag4oCcbuKAnS4gQ2jDum5nIGPDsyB0aOG7gyDEkcOjIHRo4bqleSAqKipzdWJzdHIoKSoqKiBt4buZdCBow6BtIFIgY8ahIHPhu58gdMawxqFuZyB04buxIG5oxrAgKioqc3RyX3N1YigpKioqLiDGr3UgxJFp4buDbSBs4bubbiBj4bunYSAqKipzdHJfc3ViKCkqKiogbMOgIGto4bqjIG7Eg25nIHPhu60gZOG7pW5nIGPDoWMgY2jhu4kgbeG7pWMgw6JtIMSR4buDIMSR4bq/bSB04burIGN14buRaSBjaHXhu5dpLg0KDQogICoqMi4gTOG7jWMgY8OhYyBjaHXhu5dpIGNvbiBwaMO5IGjhu6NwIHbhu5tpIG3hu5l0IG3huqt1IGLhurFuZyBzdHJfc3Vic2V0KCkqKg0KICANClbDrCB2aeG7h2MgcGjDoXQgaGnhu4duIGPDoWMgY2h14buXaSBjw7MgbeG6q3UgdsOgIHNhdSDEkcOzIHPhuq9wIHjhur9wIGzhuqFpIGPDoWMgY2h14buXaSDEkcOzIGzDoCBt4buZdCBob+G6oXQgxJHhu5luZyBwaOG7lSBiaeG6v24sIFN0cmluZ3IgY3VuZyBj4bqlcCBt4buZdCBow6BtICoqKnN0cl9zdWJzZXQoKSoqKiDEkeG7gyB0aOG7sWMgaGnhu4duIMSR4buBdSDEkcOzIHRyb25nIG3hu5l0IGLGsOG7m2MuIFbDrSBk4bulOiBM4bq3cCBs4bqhaSB0w6xtIGtp4bq/bSBib3lfbmFtZXMgY8OzIGNo4bupYSAqKioienoiKioqIGLhurFuZyBjw6FjaCBz4butIGThu6VuZyAqKipzdHJfc3Vic2V0KCkqKio6DQoNCmBgYHtyfQ0Kc3RyX3N1YnNldChib3lfbmFtZXMsIHBhdHRlcm4gPSBmaXhlZCgienoiKSkNCmBgYA0KDQo9XD4gQ2jDum5nIHRhIG5o4bqtbiDEkcaw4bujYyBt4buZdCB2ZWN0xqEgY2h14buXaSBt4bubaSwgbmjGsG5nIG7DsyBjaOG7iSBjaOG7qWEgY8OhYyBjaHXhu5dpIGJhbiDEkeG6p3UgY2jhu6lhIG3huqt1Lg0KDQoqKipzdHJfc3Vic2V0KCkqKiogY8OzIHRo4buDIGThu4UgYuG7iyBuaOG6p20gbOG6q24gduG7m2kgKioqc3RyX2V4dHJhY3QoKSoqKi4gc3RyX2V4dHJhY3QoKSB0cuG6oyB24buBIG3hu5l0IHZlY3TGoSBjw7MgY8O5bmcgxJHhu5kgZMOgaSB24bubaSB2ZWN0xqEgxJHhuqd1IHbDoG8sIG5oxrBuZyBjaOG7iSB24bubaSBjw6FjIHBo4bqnbiBj4bunYSBjaHXhu5dpIGto4bubcCB24bubaSBt4bqrdS4gVMOsbSBnaXJsX25hbWUgY8OzIGNo4bupYSDigJxV4oCdIHbDoCDigJx64oCdDQoNCmBgYHtyfQ0Kc3RhcnRzX1UgPC0gc3RyX3N1YnNldChnaXJsX25hbWVzLCBwYXR0ZXJuID0gZml4ZWQoIlUiKSkNCnN0YXJ0c19VDQpgYGANCmBgYHtyfQ0Kc3RyX3N1YnNldChzdGFydHNfVSwgcGF0dGVybiA9ICJ6IikNCg0KYGBgDQo9XD4g4oCcVW1hbWl6YeKAnSBsw6AgY8OzIGfDoWkgY8OzIHTDqm4gZHV5IG5o4bqldCBi4bqvdCDEkeG6p3UgYuG6r3QgY2jhu68g4oCcVeKAnSB2w6AgY2jhu6lhIGNo4buvIOKAnHrigJ0NCg0KICAqKjMuIEjDoG0gc3RyX2V4dHJhY3QoKSB0cuG6oyB24buBIG3hu5l0IHZlY3TGoSBrw70gdOG7sSBjaOG7qWEgKGPDoWMpIGNodeG7l2kgY29uIMSRxrDhu6NjIHRyw61jaCB4deG6pXQqKg0KDQpIw6BtIG7DoHkgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdHLDrWNoIHh14bqldCBs4bqnbiDEkeG6p3UgeHXhuqV0IGhp4buHbiDEkeG6p3UgdGnDqm4gY+G7p2EgbeG7mXQgbeG6q3UgdHJvbmcgY2h14buXaSBrw70gdOG7sSBob+G6t2MgdmVjdG8gY+G7p2EgY2h14buXaS4gSMOgbSAqKipzdHJfZXh0cmFjdCgpKioqIHRy4bqjIHbhu4EgbeG7mXQgdmVjdG8gY2jhu6lhIGvDvSB04buxIGNo4bupYSBjw6FjIGNodeG7l2kgY29uIMSRxrDhu6NjIHRyw61jaCB4deG6pXQuDQoNCkPDuiBwaMOhcDogc3RyX2V4dHJhY3Qoc3RyaW5nLCBwYXR0ZXJuLCBzaW1wbGlmeSwgaWdub3JlX2Nhc2UsIG9wdHNfcmVnZXgpLg0KDQpUcm9uZyDEkcOzOiANCg0KICAtIHN0cmluZzogVGhhbSBz4buRIG7DoHkgxJHhuqFpIGRp4buHbiBjaG8gY2h14buXaSBrw70gdOG7sSBob+G6t2MgdmVjdG8gY+G7p2EgY2h14buXaSBz4bq9IMSRxrDhu6NjIHTDoWNoDQogIC0gcGF0dGVybjogVGhhbSBz4buRIG7DoHkgY2jhu4kgxJHhu4tuaCBk4bqldSBwaMOibiBjw6FjaCBob+G6t2MgbeG6q3UgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IHPhur0gxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdMOhY2ggY8OhYyBjaHXhu5dpIMSR4bqndSB2w6BvDQogIC0gc2ltcGxpZnk6IFRoYW0gc+G7kSBuw6B5IGNo4buJIMSR4buLbmggY8OzIMSRxqFuIGdp4bqjbiBow7NhIGvhur90IHF14bqjIHRow6BuaCBtYSB0cuG6rW4ga8O9IHThu7EgaG/hurdjIHZlY3RvIGhheSBraMO0bmcuIEdpw6EgdHLhu4sgbeG6t2MgxJHhu4tuaCBsw6AgRkFMU0UNCiAgLSBpZ25vcmVfY2FzZTogVGhhbSBz4buRIG7DoHkgY2jhu4kgxJHhu4tuaCBz4buRIGzhuqduIHBow6JuIHTDoWNoIHThu5FpIMSRYSDEkcaw4bujYyB0aOG7sWMgaGnhu4duLiBHacOhIHRy4buLIG3hurdjIMSR4buLbmggbMOgIOKAmEluZuKAmS4NCiAgLSBvcHRzX3JlZ2V4OiBUaGFtIHPhu5EgbsOgeSBjaOG7iSDEkeG7i25oIGPDsyBuw6puIGxv4bqhaSBi4buPIGPDoWMgY2h14buXaSB0cuG7kW5nIHRyb25nIMSR4bqndSByYSBoYXkga2jDtG5nLiBHacOhIHRy4buLIG3hurdjIMSR4buLbmggbMOgIHRydWUuDQoNCkTGsOG7m2kgxJHDonkgbMOgIGhhaSBi4buZIGThu68gbGnhu4d1IMSRw6MgxJHGsOG7o2MgY8OgaSDEkeG6t3Qgc+G6s24gdHJvbmcgZ8OzaSBTdHJpbmdyLCBiYW8gZ+G7k20gZnJ1aXQgY2hvIGNow7puZyB0YSBiaeG6v3QgNzkgbG/huqFpIHRyw6FpIGPDonkgdsOgIGThu68gbGnhu4d1IHNlbnRlbmNlcyBiYW8gZ+G7k20gNzIwIGTDsm5nLiBDaMO6bmcgZW0gc+G6vSBkw7luZyBs4buHbmggKioqaGVhZCgpKioqIMSR4buDIHhlbSA2IGTDsm5nIMSR4bqndSBj4bunYSAyIGLhu5kgZOG7ryBsaeG7h3U6DQoNCmBgYHtyfQ0KZnJ1aXQgPSBzdHJpbmdyOjpmcnVpdA0KaGVhZChmcnVpdCkNCmBgYA0KYGBge3J9DQpoZWFkKHNlbnRlbmNlcykNCg0KYGBgDQoNClbDrSBk4bulIGNow7puZyBlbSBtdeG7kW4gdHLDrWNoIHh14bqldCBjw6FjIHThu6sgY8OzIHRyw6FpIGPDonkgdHJvbmcg4oCcZnJ1aXTigJ0gdsOgIGTDuW5nIOKAnHzigJ0gxJHhu4MgbuG7kWkgY8OhYyBjaHXhu5dpIHbhu5tpIG5oYXUNCg0KYGBge3J9DQpmcnVpdF9tYXRjaCA8LSBzdHJfYyhmcnVpdCwgY29sbGFwc2UgPSAifCIpDQpmcnVpdF9tYXRjaA0KYGBgDQoNClTDrG0ga2nhur9tIHRyw61jaCB4deG6pXQgY8OhYyB04burIGNo4bupYSB0csOhaSBjw6J5IHThu6sgdHJvbmcgbeG7mXQgdOG6rXAgaOG7o3AgY8OhYyBjw6J1ICoqKnNlbnRlbmNlcyoqKg0KDQpgYGB7cn0NCmhhc19mcnVpdCA8LSBzdHJfc3Vic2V0KHNlbnRlbmNlcywgZnJ1aXRfbWF0Y2gpDQptYXRjaGVzIDwtIHN0cl9leHRyYWN0KGhhc19mcnVpdCwgZnJ1aXRfbWF0Y2gpDQpoZWFkKG1hdGNoZXMpDQpgYGANCg0KKioqc3RyX2V4dHJhY3QoKSoqKiBjaOG7iSB0csOtY2ggeHXhuqV0IGvhur90IHF14bqjIGto4bubcCDEkeG6p3UgdGnDqm4sIG7Dqm4gZW0gc+G6vSBz4butIGThu6VuZyAqKipzdHJfZXh0cmFjdF9hbGwoKSoqKiDEkeG7gyB0csOtY2ggeHXhuqV0IHThuqV0IGPhuqMgY8OhYyBr4bq/dCBxdeG6oyBraOG7m3AsIGvhur90IHF14bqjIMSRxrDhu6NjIGhp4buDbiB0aOG7iyB0cm9uZyBkYW5oIHPDoWNoDQoNCmBgYHtyfQ0Kc3RyX2V4dHJhY3RfYWxsKGhhc19mcnVpdCxmcnVpdF9tYXRjaCkgJT4lIGhlYWQoKQ0KDQpgYGANCg0KVGnhur9wIHRoZW8gY2jDum5nIGVtIHPhur0gxJHGoW4gZ2nhuqNuIGjDs2EgPSBUUlVFIHRy4bqjIHbhu4EgbeG7mXQgbWEgdHLhuq1uDQoNCmBgYHtyfQ0Kc3RyX2V4dHJhY3RfYWxsKGhhc19mcnVpdCxmcnVpdF9tYXRjaCxzaW1wbGlmeSA9IFQpICU+JSBoZWFkKCkNCg0KYGBgDQoNCiAgKio0LiBzdHJfbWF0Y2goc3RyaW5nLCBwYXR0ZXJuKTogdHLDrWNoIHh14bqldCBjw6FjIHBo4bqnbiBj4bunYSB0cuG6rW4gxJHhuqV1IMSRxrDhu6NjIHjDoWMgxJHhu4tuaCBi4bufaSBk4bqldSBuZ2/hurdjIMSRxqFuLioqDQogIA0KQsOieSBnaeG7nSBjaMO6bmcgZW0gc+G6vSBs4bqleSB2w60gZOG7pSB0cm9uZyBi4buZIGThu68gbGnhu4d1IHNlbnRlbmNlcyDEkeG7gyBnaeG6o2kgdGjDrWNoIHbhu4EgaMOgbSAqKipzdHJfbWF0Y2goKSoqKg0KDQpM4bqleSB04bqldCBj4bqjIGPDoWMgZGFuaCB04burIHRyb25nIGPDonUgY8OzIOKAnGHigJ0gaG/hurdjIOKAnHRoZeKAnSDEkeG7gyBsw6BtIHThu6sgxJHhu4tuaCBsxrDhu6NuZw0KDQpgYGB7cn0NCmRhbmh0dSA8LSAiKGF8dGhlKSAoW14gXSspIg0KDQpoYXNfZGFuaHR1IDwtIHNlbnRlbmNlcyAlPiUNCiAgc3RyX3N1YnNldChkYW5odHUpICU+JQ0KICBoZWFkKDEwKQ0KaGFzX2Rhbmh0dSAlPiUgDQogIHN0cl9leHRyYWN0KGRhbmh0dSkNCmBgYA0KDQoqKipzdHJfbWF0Y2goKSoqKiBraMOhYyB24bubaSAqKipzdHJfZXh0cmFjdCgpKioqLCBjaOG7pyB54bq/dSBsw6AgdsOsICoqKnN0cl9tYXRjaCgpKioqIHPhur0gdHLhuqMgduG7gSBt4buNaSBu4buZaSBkdW5nIMSRw6MgY2jhu6VwDQoNClRyw61jaCB4deG6pXQgcGjhuqduIGto4bubcCB24bubaSBt4bqrdSB0cm9uZyBt4buXaSBkYW5oIHThu6sNCg0KYGBge3J9DQpkYW5odHUgPC0gIihhfHRoZSkgKFteIF0rKSINCmhhc19kYW5odHUgPC0gc2VudGVuY2VzICU+JQ0KICBzdHJfc3Vic2V0KGRhbmh0dSkgJT4lDQogIGhlYWQoMTApDQpoYXNfZGFuaHR1ICU+JSANCiAgc3RyX21hdGNoKGRhbmh0dSkNCg0KYGBgDQoNCiMjIyBQaMOhdCBoaeG7h24ga+G6v3QgcXXhuqMgdHLDuW5nIGto4bubcA0KDQojIyMjIFTDrG0ga2nhur9tIHbDoCB0csOtY2ggeHXhuqV0IHRow7RuZyB0aW4gY2h14buXaQ0KDQogICoqMS4gS2jhu5twIG3huqt1IHPhu60gZOG7pW5nIHN0cl9kZXRlY3QoKSoqDQogDQpLaOG7m3AgbeG6q3UgbGnDqm4gcXVhbiDEkeG6v24gdmnhu4djIHTDrG0gbeG7mXQgY2h14buXaSBjb24ga2jhu5twIHbhu5tpIG3hu5l0IG3huqt1IGPhu6UgdGjhu4MuIEjDoG0gKioqc3RyX2RldGVjdCgpKioqIHRyb25nIGfDs2kgU3RyaW5nciBjw7MgdGjhu4MgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgcGjDoXQgaGnhu4duIGPDoWMgbeG6q3UgdHJvbmcgY2h14buXaS4NCg0KQ8O6IHBow6FwOiBzdHJfZGV0ZWN0KHN0cmluZywgcGF0dGVybiwgbmVnYXRlICk6IEPDsyBjaOG7qWMgbsSDbmcga2nhu4NtIHRyYSB4ZW0gbeG7mXQgY2h14buXaSBjw7MgY2jhu6lhIG3hu5l0IG3huqt1IGhheSBraMO0bmcgdsOgIGvhur90IHF14bqjIHRy4bqjIHbhu4EgbMOgIOKAnFRSVUXigJ0gaG/hurdjIOKAnEZBTFNF4oCdDQoNCiAgLSAqKnN0cmluZyoqOiDEkOG6oWkgZGnhu4duIGNobyBjaHXhu5dpIGvDvSB04buxIGhv4bq3YyB2ZWN0byBj4bunYSBjaHXhu5dpIG114buRbiBwaMOhdCBoaeG7h24gdHJvbmcgbeG6q3UgxJHDsyANCiAgLSAqKnBhdHRlcm4qKjogVGhhbSBz4buRIG7DoHkgY2jhu4kgxJHhu4tuaCBt4bqrdSBob+G6t2MgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IHPhur0gxJHGsOG7o2MgcGjDoXQgaGnhu4duIHRyb25nIGNodeG7l2kgxJHhuqd1IHbDoG8NCiAgLSAqKm5lZ2F0ZSoqOiBUaGFtIHPhu5EgbsOgeSBjaOG7iSDEkeG7i25oIGPDsyB0cuG6oyB24buBIHBo4bqnbiBiw7kgbG9naWMgY+G7p2Ega+G6v3QgcXXhuqMgcGjDoXQgaGnhu4duIGhheSBraMO0bmcNCiAgDQoqKlbDrSBk4bulOioqIEtp4buDbSB0cmEgeGVtIG3hu5l0IHZlY3TGoSBrw70gdOG7sSBjw7Mga2jhu5twIHbhu5tpIG3hu5l0IG3huqt1IGhheSBraMO0bmcsIHRy4bqjIHbhu4EgbeG7mXQgdmVjdMahIGxvZ2ljDQoNCmBgYHtyfQ0KeCA8LSBjKCJib3lfbmFtZXMiLCJnaXJsX25hbWVzIikNCnN0cl9kZXRlY3QoeCwibyIpDQpgYGANCg0KTeG7mXQg4bupbmcgZOG7pW5nIHBo4buVIGJp4bq/biBsw6Agc+G7rSBk4bulbmcgdsOpYyB0xqEgbG9naWMgdGh1IMSRxrDhu6NjIMSR4buDIHRodSDEkcaw4bujYyBjw6FjIHBo4bqnbiB04butIGNvbiBwaMO5IGjhu6NwDQoNCmBgYHtyfQ0KeFtzdHJfZGV0ZWN0KHgsImUiKV0NCg0KYGBgDQoNCktp4buDbSB0cmEgeGVtIG3hu5dpIHBo4bqnbiB04butIHRyb25nIHZlY3RvciBib3lfbmFtZXMgY8OzIGNo4bupYSBjaHXhu5dpIOKAnHp64oCdIGhheSBraMO0bmc/DQoNCmBgYHtyfQ0KY29udGFpbnNfenogPC0gc3RyX2RldGVjdChib3lfbmFtZXMsIHBhdHRlcm4gPSAienoiKQ0Kc3RyKGNvbnRhaW5zX3p6KQ0KYGBgDQogIA0KICAqKjIuIENo4bupYyBuxINuZyDEkeG7i25oIHbhu4sga8OtIHThu7EgYuG6sW5nIGjDoG0gc3RyX2xvY2F0ZSgpKioNCiAgDQoqKipzdHJfbG9jYXRlKCkqKio6IFRy4bqjIHbhu4EgduG7iyB0csOtIMSR4bqndSB0acOqbiB2w6AgY3Xhu5FpIGPDuW5nIGPhu6dhIMSR4buRaSB0xrDhu6NuZyBwaMO5IGjhu6NwLCB0aMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcgY8O5bmcgduG7m2kgaMOgbSAqKipzdHJfc3ViKCkqKioNCg0KYGBge3J9DQp4IDwtIGMoImJveV9uYW1lcyIsImdpcmxfbmFtZXMiKQ0Kc3RyX2xvY2F0ZSh4LCdhJykNCmBgYA0KICANCiMjIyMgxJDhur9tIHbDoCB0w61uaCB0b8OhbiB0cm9uZyBjaHXhu5dpIGLhurFuZyBow6BtIHN0cl9jb3VudCgpDQoNCkfDs2kgU3RyaW5nciBjdW5nIGPhuqVwIHBoxrDGoW5nIHRo4bupYyBzdHJfY291bnQoKSDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyDEkeG6v20gc+G7kSBs4bqnbiB4deG6pXQgaGnhu4duIGPhu6dhIG3hu5l0IG3huqt1IG5o4bqldCDEkeG7i25oIMSRxrDhu6NjIGNo4buJIMSR4buLbmggbMOgbSDEkeG7kWkgc+G7kSBjaG8gaMOgbS4gTeG6q3UgY8OzIHRo4buDIGzDoCBt4buZdCBrw60gdOG7sSDEkcahbiBob+G6t2MgbeG7mXQgbmjDs20ga8O9IHThu7EuIELhuqV0IGvhu7MgdHLGsOG7nW5nIGjhu6NwIG7DoG8ga2jhu5twIHbhu5tpIGJp4buDdSB0aOG7qWMgxJHhu4F1IGThuqtuIMSR4bq/biBz4buxIGdpYSB0xINuZyBj4bunYSBz4buRIMSR4bq/bS4gUGjGsMahbmcgdGjhu6ljIG7DoHkgY8OzIHRo4buDIMSRxrDhu6NjIGfhu41pIHRyw6puIG3hu5l0IHZlY3RvIGNodeG7l2kgdsOgIG3hu5l0IHZlY3RvIMSR4bq/bSByacOqbmcgbOG6uyDEkcaw4bujYyB0cuG6oyB24buBIGPDsyBjaOG7qWEgY8OhYyBz4buRIGzGsOG7o25nIHJpw6puZyBs4bq7IGPhu6dhIHPhu5EgbMaw4bujbmcgbeG6q3UgcGjDuSBo4bujcCDEkcaw4bujYyB0aW0gdGjhuqV5Lg0KDQpDw7ogcGjDoXA6c3RyX2NvdW50KHN0cmluZywgcGF0dGVybiA9IOKAnOKAnSkNCg0KVHJvbmcgxJHDszoNCg0KICAtIHN0cmluZzogQ2h14buXaSDEkeG7gyDEkeG6v20gc+G7kSBs4bqnbiB4deG6pXQgaGnhu4duIGPhu6dhDQogIC0gcGF0dGVybjogbeG6q3UgcGjDuSBo4bujcCAgICAgDQoNCioqVsOtIGThu6U6Kiogc3RyX2NvdW50KCkgaMOgbSBuw6B5IHPhur0gdHLhuqMgduG7gSBz4buRIGzGsOG7o25nIGvhur90IHF14bqjIGto4bubcCB0cm9uZyBt4buXaSBjaHXhu5dpDQoNCmBgYHtyfQ0KeCA8LSBjKCJib3lfbmFtZXMiLCJnaXJsX25hbWVzIikNCnN0cl9jb3VudCh4LCAiYSIpDQpgYGANCg0KxJDhur9tIHPhu5EgbOG6p24geHXhuqV0IGhp4buHbiBj4bunYSDigJxh4oCdIHbDoCDigJxB4oCdIHRyb25nIGdpcmxfbmFtZXMgdsOgIHThuqFvIGJp4buDdSDEkeG7kyBz4buRIGPhu6dhIGPhuqMgMg0KDQpgYGB7cn0NCm51bWJlcl9hcyA8LSBzdHJfY291bnQoZ2lybF9uYW1lcywgcGF0dGVybiA9IGZpeGVkKCJhIikpDQpudW1iZXJfQXMgPC0gc3RyX2NvdW50KGdpcmxfbmFtZXMsIHBhdHRlcm4gPSBmaXhlZCgiQSIpKQ0KaGlzdChudW1iZXJfYXMpDQpgYGANCmBgYHtyfQ0KaGlzdChudW1iZXJfQXMpDQoNCmBgYA0KDQojIyMgQmnhur9uIMSR4buVaSBjaHXhu5dpDQoNCiMjIyMgVGhheSB0aOG6vyB2w6AgY2h1eeG7g24gxJHhu5VpIGNodeG7l2kNCg0KxJDDtGkga2hpIHZp4buHYyB0aGF5IHRo4bq/IGPDoWMgcGjhuqduIGNow7puZyB0YSBraMO0bmcgbXXhu5FuIGLhurFuZyBt4buZdCBjaHXhu5dpIHLhu5duZyAiICIgc+G6vSBk4buFIGTDoG5nIGjGoW4uIMSQw6J5IGPFqW5nIGzDoCBt4buZdCBwaMawxqFuZyBwaMOhcCBwaOG7lSBiaeG6v24gxJHhu4MgZOG7jW4gZOG6uXAgY2h14buXaSwgY2jhurNuZyBo4bqhbiBuaMawIMSR4buDIHjDs2EgZOG6pXUgY2jhuqVtIGPDonUgaG/hurcga2hv4bqjbmcgdHLhuq9uZyBraMO0bmcgbW9uZyBtdeG7kW4NCg0KKioqc3RyX3JlcGxhY2UoKSoqKiB2w6AgKioqc3RyX3JlcGxhY2VfYWxsKCkqKiogY2hvIHBow6lwIGNow7puZyB0YSB0aGF5IHRo4bq/IGPDoWMga+G6v3QgcXXhuqMga2jhu5twIMSR4buDIHThuqFvIGNodeG7l2kgbeG7m2kNCg0KQ8O6IHBow6FwOiBzdHJfcmVwbGFjZShzdHJpbmcsIHBhdHRlcm4gPSDigJnigJgsIHJlcGxhY2VtZW50ID3igJnigJkpOiBUaGF5IHRo4bq/IGvDvSB04buxIGxpw6puIHF1YW4gxJHhur9uIHZpw6pjIHRoYXkgdGjhur8gbeG7mXQgY2h14buXaSBjb24gdHJvbmcgbeG7mXQgY2h14buXaSBi4bqxbmcgbeG7mXQgY2h14buXaSBjb24ga2jDoWMuIFRyb25nIMSRw7M6DQoNCiAgLSAqKnN0cmluZyoqOiBUaGFtIHPhu5EgbsOgeSDEkeG6oWkgZGnhu4duIGNobyBjaHXhu5dpIGvDvSB04buxIGhv4bq3YyBt4buZdCB2ZWN0byBjaHXhu5dpIG114buRbiB0aGF5IHRo4bq/IGPDoWMgbeG6q3UgdHJvbmcgxJHDsw0KICAtICoqcGF0dGVybioqOiBUaGFtIHPhu5EgbsOgeSBjaOG7iSDEkeG7i25oIG3huqt1IGhv4bq3YyBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgc+G6vSDEkcaw4bujYyB0aGF5IHRo4bq/IGNobyBjw6FjIGNodeG7l2kgxJHhuqd1IHbDoG8uDQogIC0gKipyZXBsYWNlbWVudCoqOiBUaGFtIHPhu5EgbsOgeSBjaOG7iSDEkeG7i25oIGPDoWMgY2h14buXaSB0aGF5IHRo4bq/IHPhur0gxJHGsOG7o2MgdGhheSB0aOG6vyBjaG8gY8OhYyBt4bqrdSB0cm9uZyBjw6FjIGNodeG7l2kgxJHhuqd1IHbDoG8NCiAgDQoqKlbDrSBk4bulOioqIMSQ4bqndSB0acOqbiBjaMO6bmcgZW0gc+G6vSB0aOG7sWMgaGnhu4duIHRoYXkgdGjhur8gY8OhYyBuZ3V5w6puIMOibSAoYSwgZSwgaSwgbywgdSkgdHJvbmcgY8OhYyBjaHXhu5dpIOKAnGFwcGxl4oCdLCDigJxwZWFy4oCdIHbDoCDigJxiYW5hbmHigJ0gYuG6sW5nIGThuqV1IGfhuqFjaCBuZ2FuZyDigJwt4oCdDQoNCmBgYHtyfQ0KeCA8LSBjKCJhcHBsZSIsICJwZWFyIiwgImJhbmFuYSIpDQpzdHJfcmVwbGFjZSh4LCAiW2FlaW91XSIsICItIikNCmBgYA0KDQpUaGF5IHThur8gdOG6pXQgY+G6oyBjw6FjIGvDvSB04buxIHRyb25nIGNodeG7l2kgYuG6sW5nIHN0cl9yZXBsYWNlX2FsbA0KDQpgYGB7cn0NCnN0cl9yZXBsYWNlX2FsbCh4LCAiW2FlaW91XSIsICItIikNCg0KYGBgDQoNClbhu5tpICoqKnN0cl9yZXBsYWNlX2FsbCgpKioqKiBjaMO6bmcgZW0gY8WpbmcgY8OzIHRo4buDIGN1bmcgY+G6pXAgbeG7mXQgdmVjdMahIGPDsyB0w6puIGNobyBuaGnhu4F1IGzhuqduIHRoYXkgdGjhur8NCg0KYGBge3J9DQp4IDwtIGMoIjEgaG91c2UiLCAiMiBjYXJzIiwgIjMgcGVvcGxlIikNCnN0cl9yZXBsYWNlX2FsbCh4LCBjKCIxIiA9ICJvbmUiLCAiMiIgPSAidHdvIiwgIjMiID0gInRocmVlIikpDQpgYGANCg0KVHJvbmcgcXXDoSB0csOsbmggdGhheSB0aOG6vywgY2jDum5nIHRhIGPFqW5nIGPDsyB0aOG7gyDEkcaw4bujYyBr4bq/dCBo4bujcA0KDQpgYGB7cn0NCnNlbnRlbmNlcyAlPiUgDQogIHN0cl9yZXBsYWNlKCIoW14gXSspIChbXiBdKykgKFteIF0rKSIsICJcXDEgXFwzIFxcMiIpICU+JSANCiAgaGVhZCg1KQ0KYGBgDQoNCsSQw6J5IGNow61uaCBsw6AgbeG6q3UgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IMSR4buDIHTDrG0gY8OhYyDEkW/huqFuIGPDonUgdHJvbmcgZGFuaCBzw6FjaCBzZW50ZW5jZXMgY8OzIGJhIHThu6ssIMSR4buVaSBjaOG7lyB24buLIHRyw60gZ2nhu69hIHThu6sgdGjhu6kgaGFpIHbDoCB0aOG7qSBiYSB0cm9uZyBt4buXaSDEkW/huqFuIGPDonUNCg0KIyMjIyBDaHV54buDbiDEkeG7lWkgY2h14buXaQ0KDQpUcm9uZyBt4buZdCBz4buRIHRyxrDhu51uZyBo4bujcCBjaMO6bmcgdGEgbXXhu5FuIGJp4buDdSB0aOG7iyB0ZXh0IOG7nyBk4bqhbmcgdmnhur90IGhvYSBob+G6t2Mgdmnhur90IHRoxrDhu51uZywgY2jDum5nIHRhIGPDsyB0aOG7gyBkw7luZyBow6BtIG5oxrAgc2F1Og0KDQoqKlbDrSBk4bulOioqIMSQ4bqndSB0acOqbiBjaMO6bmcgZW0gc+G6vSBs4bqleSBk4buvIGxp4buHdSB04burICoqKmZydWl0KioqIGzDoCAzIGxv4bqhaSB0csOhaSBjw6J5IHbDoCBnw6FuIGzhuqFpIGNow7puZyB2w6BvICoqKmZydWl0KioqDQoNCmBgYHtyfQ0KZnJ1aXQgPC0gYygiYXBwbGUiLCAicGVhciIsICJiYW5hbmEiKQ0KDQpgYGANCg0KICoqc3RyX3RvX2xvd2VyKCk6KiogY2h1eeG7g24gxJHhu5VpIHThuqV0IGPhuqMgY8OhYyBjaOG7ryBjw6FpIHRyb25nIGNodeG7l2kgdGjDoG5oIGNo4buvIHRoxrDhu51uZw0KDQpgYGB7cn0NCnN0cl90b19sb3dlcihmcnVpdCkNCg0KYGBgDQoNCioqc3RyX3RvX3VwcGVyKCk6KiogY2h1eeG7g24gxJHhu5VpIHThuqV0IGPhuqMgY8OhYyBjaOG7ryBjw6FpIHRyb25nIGNodeG7l2kgxJHhuqd1IHbDoG8gdGjDoG5oIGNo4buvIGhvYQ0KDQpgYGB7cn0NCnN0cl90b191cHBlcihmcnVpdCkNCg0KYGBgDQoNCioqc3RyX3RvX3RpdGxlKCk6KiogQ2h1eeG7g24gxJHhu5VpIGPDoWMga8O9IHThu7EgxJHhuqd1IHRpw6puIGPhu6dhIG3hu5dpIHThu6sgdHJvbmcgbeG7mXQgY2h14buXaSB0aMOgbmggY2jhu68gaG9hIChpbiBob2EpLCB0cm9uZyBraGkgZ2nhu68gbOG6oWkgY8OhYyBrw70gdOG7sSBjw7JuIGzhuqFpIOG7nyBk4bqhbmcgY2jhu68gdGjGsOG7nW5nIChpbiB0aMaw4budbmcpLg0KDQpgYGB7cn0NCnN0cl90b190aXRsZShmcnVpdCkNCg0KYGBgDQoNCg0KIyMjIyBUaGFtIGdpYSB2w6AgY2hpYSB0w6FjaA0KDQogICoqMS4gTuG7kWkgY2h14buXaSBi4bqxbmcgc3RyX2MoKSoqIA0KICANCk7hu5FpIGNodeG7l2kgbMOgIHF1w6EgdHLDrG5oIG7hu5FpIGhhaSBob+G6t2Mgbmhp4buBdSBjaHXhu5dpIGzhuqFpIHbhu5tpIG5oYXUuIEjDoG0gKioqc3RyX2MoKSoqKiB0cm9uZyBnw7NpIFN0cmluZ3IgY8OzIHRo4buDIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIG7hu5FpIGNodeG7l2kuIEjDoG0gKioqc3RyX2MoKSoqKiBy4bqldCBk4buFIHPhu60gZOG7pW5nIHbDoCBjdW5nIGPhuqVwIG5oaeG7gXUgdGhhbSBz4buRIGtow6FjIG5oYXUgxJHhu4MgdMO5eSBjaOG7iW5oIHF1eSB0csOsbmggbuG7kWkuIETGsOG7m2kgxJHDonkgbMOgIG3hu5l0IHPhu5EgdGhhbSBz4buRIMSRxrDhu6NjIHPhu60gZOG7pW5nIHbhu5tpIGjDoG0gKioqc3RyX2MoKSoqKg0KDQoqKmMgbMOgIHZp4bq/dCB04bqvdCBj4bunYSBjb25jYXRlbmF0ZSwgbeG7mXQgaMOgbSBob+G6oXQgxJHhu5luZyBnaeG7kW5nIG5oxrAgcGFzdGUoKSBOw7MgbOG6pXkgY8OhYyB2ZWN0xqEgY+G7p2EgY2h14buXaSBsw6BtIMSR4bqndSB2w6BvIGPDuW5nIHbhu5tpIGPDoWMgxJHhu5FpIHPhu5Egc2VwIHbDoCBjb2xsYXBzZS4qKg0KDQpDw7ogcGjDoXA6IHN0cl9jKHN0cmluZywgc2VwLCBjb2xsYXBzZSwgaWdub3JlX25hLCB0cmltKQ0KDQpUcm9uZyDEkcOzOiANCg0KICAtICoqc3RyaW5nKio6IFRoYW0gc+G7kSBuw6B5IMSR4bqhaSBkaeG7h24gY2hvIGPDoWMgY2h14buXaSBj4bqnbiDEkcaw4bujYyBu4buRaS4gQuG6oW4gY8OzIHRo4buDIGNo4buJIMSR4buLbmggYuG6pXQga+G7syBz4buRIGzGsOG7o25nIMSR4buRaSBz4buRIG7DoG8gxJHGsOG7o2MgcGjDom4gdMOhY2ggYuG6sW5nIGThuqV1IHBo4bqpeS4NCiAgLSAqKnNlcDoqKiBUaGFtIHPhu5EgbsOgeSBjaOG7iSDEkeG7i25oIGThuqV1IHBow6JuIGPDoWNoIMSRxrDhu6NjIHPhu60gZOG7pW5nIGdp4buvYSBjw6FjIGNodeG7l2kgxJHGsOG7o2MgbuG7kWkuIEThuqV1IHBow6JuIGPDoWNoIG3hurdjIMSR4buLbmggbMOgIG3hu5l0IGNodeG7l2kgcuG7l25nLg0KICAtICoqY29sbGFwc2U6KiogVGhhbSBz4buRIG7DoHkgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdGh1IGfhu41uIMSR4bqndSByYSBj4bunYSBzdHJfYygpIHRow6BuaCBt4buZdCBjaHXhu5dpLiBHacOhIHRy4buLIG3hurdjIMSR4buLbmggbMOgIEZBTFNFLg0KICAtICoqaWdub3JlX25hKio6IFRoYW0gc+G7kSBuw6B5IMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIGLhu48gcXVhIG3hu41pIGdpw6EgdHLhu4sgYuG7iyB0aGnhur91IHRyb25nIGNodeG7l2kgxJHhuqd1IHbDoG8uIEdpw6EgdHLhu4sgbeG6t2MgxJHhu4tuaCBsw6AgRkFMU0UuDQogIC0gKip0cmltKiogOiBUaGFtIHPhu5EgbsOgeSDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyBj4bqvdCBi4bqldCBr4buzIGvDvSB04buxIGtob+G6o25nIHRy4bqvbmcgbsOgbyB04burIMSR4bqndSBob+G6t2MgY3Xhu5FpIG3hu5dpIGNodeG7l2kgdHLGsOG7m2Mga2hpIG7hu5FpIGNow7puZy4gR2nDoSB0cuG7iyBt4bq3YyDEkeG7i25oIGzDoCBGQUxTRS4NCiAgDQoqKlbDrSBk4bulOioqIEjhu6NwIG5o4bqldCBuaGnhu4F1IGvDvSB04buxIHRow6BuaCBt4buZdCBjaHXhu5dpDQoNCmBgYHtyfQ0Kc3RyX2MoIngiLCJ5IiwieiIpDQoNCmBgYA0KDQpDaOG7iSDEkeG7i25oIHRoYW0gc+G7kSAqKipzZXAqKiogxJHhu4MgeMOhYyDEkeG7i25oIGThuqV1IHBow6JuIGPDoWNoDQoNCmBgYHtyfQ0Kc3RyX2MoIngiLCJ5IixzZXAgPSAiLCAiKQ0KDQpgYGANCg0KQ2jhu4kgxJHhu4tuaCAqKipjb2xsYXBzZSoqKiDEkeG7gyBr4bq/dCBo4bujcCBjw6FjIMSR4buRaSBz4buRIHZlY3TGoSB0aMOgbmggbeG7mXQgY2h14buXaSBs4bubbg0KDQpgYGB7cn0NCnN0cl9jKGhlYWQobGV0dGVycyksY29sbGFwc2UgPSAiLCIpDQoNCmBgYA0KYGBge3J9DQogc3RyX2MoYygnYScsJ2ExJyksYygnYicsJ2IxJyksY29sbGFwc2U9Jy0nKQ0KDQpgYGANCg0KKioqc3RyX2MoKSoqKiBsw6AgbeG7mXQgaMOgbSDEkcaw4bujYyB2ZWN0b3IgaMOzYSDEkeG7gyB0w6FpIGNo4bq/IGPDoWMgdmVjdMahIGvDvSB04buxIGPDsyDEkeG7mSBkw6BpIG5n4bqvbg0KDQpgYGB7cn0NCnN0cl9jKCJwcmVmaXgtIixjKCdhJywnYicsJ2MnKSwiLXN1ZmZpeCIpDQoNCmBgYA0KICAqKjIuIFTDoWNoIGNodeG7l2kgYuG6sW5nIGPDoWNoIHPhu60gZOG7pW5nIHN0cl9zcGxpdCgpKioNCiAgDQpT4butIGThu6VuZyAqKipzdHJfc3BsaXQoKSoqKiDEkeG7gyBwaMOibiB0w6FjaCBjaHXhu5dpIHRow6BuaCBuaGnhu4F1IHBo4bqnbiB2w6AgdHLhuqMgduG7gSBt4buZdCBkYW5oIHPDoWNoLiBC4bqhbiBjxaluZyBjw7MgdGjhu4MgY2jhu4kgxJHhu4tuaCBTaW1wbGUgPSBUUlVFIMSR4buDIHRy4bqjIHbhu4EgbeG7mXQgbWEgdHLhuq1uDQoNCmBgYHtyfQ0Kc2VudGVuY2VzICU+JQ0KICBoZWFkKDUpICU+JSANCiAgc3RyX3NwbGl0KCIgIikNCmBgYA0KDQpUw6FjaCBib3RoX25hbWVzIHRow6BuaCBmaXJzdF9uYW1lcyB2w6AgbGFzdF9uYW1lcw0KDQpgYGB7cn0NCmJvdGhfbmFtZXMgPC0gYygiQm94LCBHZW9yZ2UiLCAiQ294LCBEYXZpZCIpDQpib3RoX25hbWVzX3NwbGl0IDwtIHN0cl9zcGxpdChib3RoX25hbWVzLCBwYXR0ZXJuID0gZml4ZWQoIiwgIiksIHNpbXBsaWZ5ID0gVFJVRSkNCmZpcnN0X25hbWVzIDwtIGJvdGhfbmFtZXNfc3BsaXRbLCAyXQ0KbGFzdF9uYW1lcyA8LSBib3RoX25hbWVzX3NwbGl0WywgMV0NCmBgYA0KICANCk5nb8OgaSByYSBz4butIGThu6VuZyDEkeG7kWkgc+G7kSDEkcahbiBnaeG6o24gaMOzYSA9IFRSVUUga2hpIGNow7puZyB0YSBtdeG7kW4gY2hpYSBt4buXaSBjaHXhu5dpIHRow6BuaCBjw6FjIHBo4bqnbiBi4bqxbmcgbmhhdS4NCg0KLSAqKsSQxqFuIGdp4bqjbiBow7NhID1UcnVlKioNCg0KIE7Ds2kgY2h1bmcsIHZp4buHYyBjaOG7iSDEkeG7i25oIMSRxqFuIGdp4bqjbiBow7NhID0gVFJVRSBz4bq9IGN1bmcgY+G6pXAgY2hvIGNow7puZyB0YSDEkeG6p3UgcmEgZOG7hSBsw6BtIHZp4buHYyBoxqFuLCBuaMawbmcgY2jDum5nIHRhIHPhur0gbHXDtG4gbmjhuq1uIMSRxrDhu6NjIG4gcGjhuqduIChuZ2F5IGPhuqMga2hpIG3hu5l0IHPhu5EgcGjhuqduIHRy4buRbmcsIOKAnOKAnCkuDQoNCsSQw7RpIGtoaSwgY2jDum5nIHRhIG114buRbiBiaeG6v3QgbeG7mXQgY2h14buXaSBjw7MgdGjhu4MgxJHGsOG7o2MgY2hpYSB0aMOgbmggYmFvIG5oacOqdSBwaOG6p24gaG/hurdjIG114buRbiBsw6BtIGfDrCDEkcOzIHbhu5tpIG3hu5dpIHBo4bqnbiB0csaw4bubYyBraGkgY2h1eeG7g24gc2FuZyBj4bqldSB0csO6YyDEkcahbiBnaeG6o24gaMahbi4gxJDDonkgbMOgIHTDrG5oIGh14buRbmcgbcOgIGNow7puZyB0YSBraMO0bmcgbXXhu5FuIMSRxqFuIGdp4bqjbiBow7NhIHbDoCBz4bq9IHBo4bqjaSB44butIGzDvSDEkeG6p3UgcmEgYuG6sW5nIHRo4bupIGfDrCDEkcOzIG5oxrAgbGFwcGx5KCkuDQoNCsSQ4buDIHRo4buxYyBoaeG7h24gY8OhYyBwaMOpcCB0w61uaCBuw6B5LCBjaMO6bmcgdGEgY+G6p24gY2hpYSBjw6FjIGTDsm5nIHRow6BuaCBjw6FjIHThu6suIE3hu5l0IGPDoWNoIMSR4buDIGNoaWEgY8OidSB0aMOgbmggY8OhYyB04burIGzDoCBjaGlhIHRyw6puIGtob+G6o25nIHRy4buRbmcg4oCdIOKAnC4gxJBp4buBdSBuw6B5IGjGoWkga2jDsyBraMSDbiB2w6wsIHbDrSBk4bulLCBuw7Mgc+G6vSBraMO0bmcgbmjhuq1uIGPDoWMgdOG7qyDEkcaw4bujYyBwaMOibiB0w6FjaCBi4bqxbmcgbeG7mXQgY2h14buXaSB0aG/DoXQgZMOybmcgbeG7m2kgbmjGsCB0cm9uZ+KAnWhhaeKAnCwgbmjGsG5nIHbDrCB0w6xuaCBodeG7kW5nIG7DoHkga2jDtG5nIHjhuqN5IHJhIHRyb25nIGPDoWMgZMOybmcgY+G7p2EgYuG6oW4sIG7Dqm4gbsOzIHPhur0gbMOgbQ0KDQpTYXUgxJHDonkgY2jDum5nIGVtIHPhur0gbOG6pXkgZOG7ryBsaeG7h3Ugc2VudGVuY2VzIMSR4buDIHRo4buxYyBoaeG7h24gbeG7mXQgc+G7kSB0aOG7kW5nIGvDqiB2xINuIGLhuqNuIMSRxqFuIGdp4bqjbiB0csOqbiBjw6FjIGTDsm5nIGPhu6dhIG3DrG5oLiBN4bulYyB0acOqdSBj4bunYSBjaMO6bmcgZW0gbMOgIHTDrW5oIHhlbSBjw7MgYmFvIG5oacOqdSB04burIHRyb25nIG3hu5dpIGTDsm5nIHbDoCDEkeG7mSBkw6BpIHRydW5nIGLDrG5oIGPhu6dhIGPDoWMgdOG7qyB0cm9uZyBt4buXaSBkw7JuZy4NCg0KU+G7kSB04burIHRyb25nIG3hu5dpIGTDsm5nIA0KDQpgYGB7cn0NCmxpbmVzIDwtIGhlYWQoc2VudGVuY2VzKQ0Kd29yZHMgPC0gc3RyX3NwbGl0KGxpbmVzLCBwYXR0ZXJuID0gZml4ZWQoIiAiKSkNCmxhcHBseSh3b3JkcywgbGVuZ3RoKQ0KYGBgDQoNCkvhur90IGx14bqtbjogxJDhu5kgZMOgaSB04burIGtow7RuZyBob8OgbiB0b8OgbiDEkcO6bmcgdsOsIG7DsyDEkcOjIGJhbyBn4buTbSBt4buZdCBz4buRIGvDvSBoaeG7h3UgZOG6pXUgY2jhuqVtIGPDonUuIMSQ4buDIGdp4bqjaSBxdXnhur90IHbhuqVuIMSR4buBIMSRw7MgY2jDum5nIHRhIHRoYXkgdGjhur8gY2jDum5nIHRyxrDhu5tjIGLhurFuZyBow6BtICoqKnN0cl9yZXBsYWNlKCkqKiogc+G6vSDEkcaw4bujYyBjaMO6bmcgZW0gZ2nhu5tpIHRoaeG7h3UgcGjhuqduIHNhdS4NCg0KDQojIyAgS2hhaSB0aMOhYyBjaHXhu5dpIHbhu5tpIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eQ0KDQpUcm9uZyBwaOG6p24gbsOgeSwgY2jDum5nIGVtIHPhur0gdMOsbSBoaeG7g3UgduG7gSBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXksIG3hu5l0IG5nw7RuIG5n4buvIMSR4buDIG3DtCB04bqjIGPDoWMgbeG6q3UgdHJvbmcgY2h14buXaS4gQuG6sW5nIGPDoWNoIGvhur90IGjhu6NwIGPDoWMgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IHbhu5tpIGPDoWMgaMOgbSB0cm9uZyBzdHJpbmdyLCBnacO6cCB0xINuZyDEkcOhbmcga+G7gyBraOG6oyBuxINuZyB0aGFvIHTDoWMgY8OhYyBjaHXhu5dpIGPhu6dhIG3DrG5oLg0KDQojIyMgQmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IA0KDQpCaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgaGF5IGPDsm4gZ+G7jWkgbMOgIFJlZ2V4IGzDoCBt4buZdCBjw7RuZyBj4bulIG3huqFuaCBt4bq9IMSR4buDIGto4bubcCBt4bqrdSB2w6AgdGhhbyB0w6FjIGNodeG7l2kuIEzDoCBt4buZdCBjw7RuZyBj4bulIHLhuqV0IHF1YW4gdHLhu41uZyB2w6AgaOG7r3Ugw61jaCDEkeG7kWkgduG7m2kgZ8OzaSBTdHJpbmdyIG7Ds2kgcmnDqm5nIG3DoCBjw6FjIGfDs2kgdHJvbmcgUiBuw7NpIGNodW5nLiBDaMO6bmcgY2hvIHBow6lwIGNow7puZyB0YSB0w6xtIGtp4bq/bSwga2jhu5twIHbDoCB0aGFvIHTDoWMgdsSDbiBi4bqjbiBk4buxYSB0csOqbiBjw6FjIG3huqt1LiBUcm9uZyBSc3R1ZGlvLCBjw6FjIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eSDEkcaw4bujYyBz4butIGThu6VuZyBy4buZbmcgcsOjaSDEkeG7gyB0aOG7sWMgaGnhu4duIGPDoWMgdMOhYyB24bulIG5oxrAgbMOgbSBz4bqhY2ggZOG7ryBsaeG7h3UsIHRyw61jaCB4deG6pXQgdsSDbiBi4bqjbiB2w6AgeMOhYyB0aOG7sWMgZOG7ryBsaeG7h3UuDQoNCiMjIyMgKioqVGhhbyB0w6FjIGNodeG7l2kgduG7m2kgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5KioqIA0KDQpExrDhu5tpIMSRw6J5IGzDoCAyMCBxdXkgdOG6r2MgY8ahIGLhuqNuIHbhu4EgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IMSRxrDhu6NjIMOhcCBk4bulbmcgcGjhu5UgYmnhur9uIHRyb25nIGtoYWkgdGjDoWMgdsSDbiBi4bqjbiBnacO6cCBjaMO6bmcgZW0gdGhhbyB0w6FjIHbhu5tpIGNodeG7l2kgbeG7mXQgY8OhY2ggaGnhu4d1IHF14bqjIHbDoCBk4buFIGTDoG5nIGjGoW4uDQoNCjEuICIuIiAgICAgPSBi4bqldCBrw6wga8OtIHThu7EgbsOgbw0KDQoyLiAiIFxkICIgICA9IDEga8OtIHThu7Egc+G7kSBi4bqldCBrw6wgdOG7qyAwIMSR4bq/biA5DQoNCjMuICIgXEQgIiAgID0ga2jDtG5nIHBo4bqjaSAxIGvDrSB04buxIHPhu5EgdOG7qyAwIMSR4bq/biA5DQoNCjQuICIgXHcgIiAgID0gbeG7mXQga8OtIHThu7EgdGjDtG5nIHRoxrDhu51uZyAoYS16LCBBLVosIDAtOSwgXykNCg0KNS4gIiBcVyAiICAgPSBraMO0bmcgcGjhuqNpIG3hu5l0IGvDrSB04buxIHRow7RuZyB0aMaw4budbmcNCg0KNi4gIiBccyAiICAgPSBt4buZdCBrw60gdOG7sSB0cuG6r25nIG5oxrA6IHNwYWNlLCB0YWIsIG5ld2xpbmUNCg0KNy4gIiBcUyAiICAgID0ga2jDtG5nIHBo4bqjaSBt4buZdCBrw60gdOG7sSB0cuG6r25nDQoNCjguICIgXGIgIiAgID0ga2jhu5twIG5ndXnDqm4gdOG7qyAod29yZCBib3VuZGFyeSkNCg0KOS4gIiBcQiAiICAgPSBjaOG7iSBs4bqleSBt4buZdCBwaOG6p24gY+G7p2EgdOG7qw0KDQoxMC4gIiBcXiAiICA9IGLhuq90IMSR4bqndSBj4bunYSBt4buZdCBjaHXhu5dpDQoNCjExLiAgIiQgIiAgPSBr4bq/dCB0aMO6YyBj4bunYSBt4buZdCBjaHXhu5dpDQoNCjEyLiBbXSA9IGto4bubcCBjw6FjIGvDrSB04buxIHRyb25nIG5nb+G6t2MNCg0KMTMuIFteIF0gPSBraOG7m3AgY8OhYyBrw60gdOG7sSBraMO0bmcgY8OzIHRyb25nIG5nb+G6t2MNCg0KMTQuICAifCIgICAgICA9IGhv4bq3Yw0KDQoxNS4gKCApICAgID0gZ29tIG5ow7NtDQoNCjE2LiAiKiAiICAgPSBraOG7m3AgMCBs4bqnbiBob+G6t2Mgbmhp4buBdSBoxqFuDQoNCjE3LiAiKyAiICAgPSBraOG7m3Agw610IG5o4bqldCAxIGzhuqduDQoNCjE4LiAiPyAiICAgPSBjw7MgaG/hurdjIGtow7RuZw0KDQoxOS4ge3h9ID0geHXhuqV0IGhp4buHbiDEkcO6bmcgeCBs4bqnbg0KDQoyMC4ge3gsIHl9ID0ga2hv4bqjbmcgZ2nDoSB0cuG7iyBj4bqnbiBzbyBraOG7m3AgKEdUTE4sIEdUTk4pDQoNCi0g4bueIMSRw6J5IGNow7puZyB0w7RpIGPDsyBt4buZdCBz4buRIGNodeG7l2kgYmFvIGfhu5NtIHPhu5Ega8OtIHThu7Egc+G7kSwgY2jhu68gdsOgIGvDrSB04buxIMSR4bq3YyBiaeG7h3QgxJHhu4MgdGhhbyB0w6FjIGNodeG7l2kgYuG6sW5nIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eSB2w6AgZ8OhbiBjw6FjIGNodeG7l2kgYuG6sW5nICoqKnJlZ2V4MSoqKg0KDQpgYGB7cn0NCnJlZ2V4MSA8LSBjKCdOYW5jeSBTbWl0aCcsDQogICAgICAgICAgJ2lzIHRoZXJlIGFueSBzb2x1dGlvbj8nLA0KICAgICAgICAgICIuW3soXiR8PyorIiwNCiAgICAgICAgICAiY29yZXltcy5jb20iLCANCiAgICAgICAgICAiMzIxLTU1NS00MzIxIiwgDQogICAgICAgICAgIjEyMy41NTUuMTIzNCIsDQogICAgICAgICAgIjEyMyo1NTUqMTIzNCIpDQpgYGANCg0KDQojIyMjIyAqKipUcsOtY2ggY8OhYyBrw60gdOG7sSBz4buRKioqIA0KDQpUcm9uZyBnw7NpIFN0cmluZ3IgY8OzIGjDoG0gKioqc3RyX2V4dHJhY3RfYWxsKCkqKiogZMO5bmcgxJHhu4MgdHLDrWNoIGPDoWMga8OtIHThu7EgdOG7qyBt4buZdCBjaHXhu5dpIHRow7VhIG3Do24gY8OhYyB0acOqdSBjaMOtIGPhuqduIHRyw61jaC4gxJDhu4MgdGjhu7FjIGhp4buHbiB0csOtY2ggY8OhYyBrw60gdOG7sSBz4buRIGNow7puZyBlbSBz4bq9IGTDuW5nIGjDoG0gKioqc3RyX2V4dHJhY3RfYWxsKCkqKiogdHJvbmcgZ8OzaSBTdHJpbmdyIGvhur90IGjhu6NwIHbhu5tpIHF1eSB04bqvYyBz4buRIDIgxJHDoyDEkcaw4bujYyBuw6p1IOG7nyB0csOqbiBsw6AgcXV5IHThuq9jICoqKlxkKioqLg0KDQpgYGB7cn0NCnN0cl9leHRyYWN0X2FsbChyZWdleDEsICJcXGQiKQ0KDQpgYGANCk5o4bqtbiB4w6l0OiBUcm9uZyBjaHXhu5dpICoqKnJlZ2V4MSoqKiBiYW4gxJHhuqd1LCBzYXUga2hpIHRo4buxYyBoaeG7h24gdHLDrWNoIGPDoWMga8OtIHThu7Egc+G7kSBr4bq/dCBxdeG6oyBjaOG6oXkgxJHGsOG7o2MgY2hvIHJhIGLhu5FuIGNodeG7l2kgxJHhuqd1IHRpw6puIGtow7RuZyBjw7MgYuG6pXQga8OsIGvDrSB04buxIG7DoG8gdOG7qWMgbMOgIGLhu5FuIGNodeG7l2kgbMOgIGvhur90IHF14bqjIHLhu5duZy4gQmEgY2h14buXaSBjdeG7kWkgbMOgIGPDoWMgc+G7kSDEkWnhu4duIHRob+G6oWkgdsOgIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eSDEkcOjIGzhu41jIG5o4buvbmcga8OtIHThu7Egc+G7kSBuw6B5IHJhIHThu6tuZyBrw60gdOG7sSBz4buRIHJpw6puZyBs4bq7Lg0KDQojIyMjIyAqKipMb+G6oWkgdHLhu6sga8OtIHThu7Egc+G7kSoqKiANCg0KxJDhu4MgbG/huqFpIHRy4burIGPDoWMga8OtIHThu7Egc+G7kSBlbSB0aeG6v3AgdOG7pWMgZMO5bmcgY2jhu6ljIG7Eg25nICoqKnN0cl9leHRyYWN0X2FsbCgpKioqICBr4bq/dCBo4bujcCB24bubaSBxdXkgdOG6r2MgKioqXEQqKiogxJHhu4MgbG/huqFpIGLhu48gY8OhYyBrw60gdOG7sSBsw6Agc+G7kSB04burIDAgxJHhur9uIDkgDQoNCmBgYHtyfQ0Kc3RyX2V4dHJhY3RfYWxsKHJlZ2V4MSwgIlxcRCIpDQpgYGANCk5o4bqtbiB4w6l0OiBL4bq/dCBxdeG6oyB0cuG6oyB24buBIGNobyBjaMO6bmcgdGEgdGjhuqV5IGPDoWMgY2h14buXaSA1LDYsNyDEkcOjIMSRxrDhu6NjIHRyw61jaCBo4bq/dCBjw6FjIGvDrSB04buxIGzDoCBz4buRIGPDsm4gbOG6oWkgY8OhYyBrw60gdOG7sSDEkeG6t2MgYmnhu4d0IG5oxrAgIi0iLCAiLiIgaGF5ICIqIi4gQ8OhYyBrw60gdOG7sSDhu58gYuG7kW4gY2h14buXaSDEkeG6p3UgxJHDoyDEkcaw4bujYyB0csOtY2ggaOG6v3QgcmEgdOG7q25nIGvDrSB04buxIHJpw6puZyBs4bq7IMSRxrDhu6NjIMSR4bq3dCB0cm9uZyBj4bq3cCBk4bqldSAiICIuDQoNCiMjIyMjICoqKkxv4bqhaSB0cuG7qyBjw6FjIGvDrSB04buxIMSR4bq3YyBiaeG7h3QqKioNCg0KxJDhu4MgbG/huqFpIHRy4burIGPDoWMga8OtIHThu7EgxJHhurdjIGJp4buHdCBlbSBkw7luZyBxdXkgdOG6r2MgIlx3IiAga+G6v3QgaOG7o3AgduG7m2kgY2jhu6ljIG7Eg25nICoqKnN0cl9leHRyYWN0X2FsbCoqKiDEkeG7gyBs4buNYyB04bqldCBj4bqjIGPDoWMga8OtIHThu7EgYmFvIGfhu5NtIGEteixBLVosMC05IHbDoCBrw60gdOG7sSBn4bqhY2ggY2jDom4gIl8iDQoNCmBgYHtyfQ0Kc3RyX2V4dHJhY3RfYWxsKHJlZ2V4MSwgIlxcdyIpDQpgYGANCg0KDQojIyMjIyAqKipDaOG7iSBs4bqleSBjw6FjIGvDrSB04buxIMSR4bq3YyBiaeG7h3QqKioNCg0KTmfGsOG7o2MgbOG6oWkgduG7m2kgY8OidSBs4buHbmgg4bufIHRyw6puIHRow6wgYsOieSBnaeG7nSBjaMO6bmcgdMO0aSBjaOG7iSBs4bqleSBuaOG7r25nIGvDrSB04buxIMSR4bq3YyBiaeG7h3QsIGTDuW5nIHF1eSB04bqvYyAiXFciIGvhur90IGjhu6NwIHbhu5tpICoqKnN0cl9leHRyYWN0X2FsbCgpKioqIMSR4buDIGzhu41jIHJhIGPDoWMga8OtIHThu7EgxJHhurdjIGJp4buHdA0KDQpgYGB7cn0NCnN0cl9leHRyYWN0X2FsbChyZWdleDEsICJcXFciKQ0KDQpgYGANCg0KDQojIyMjIyAqKipC4bqvdCDEkeG6p3UgdsOgIGvhur90IHRow7pjIGNodeG7l2kqKioNCg0KxJDhu4MgdMOsbSB24buLIHRyw60gYuG6r3QgxJHhuqd1IHbDoCBr4bq/dCB0aMO6YyB0cm9uZyBjaHXhu5dpIGNow7puZyBlbSBz4butIGThu6VuZyAyIHF1eSB04bqvYyB0cm9uZyBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgbMOgICJeIiB2w6AgIiQiIMSR4buDIHNvIGto4bubcCBrw60gdOG7sSDhu58gduG7iyB0csOtIGLhuq90IMSR4bqndSB2w6Aga+G6v3QgdGjDumMgdHJvbmcgbeG7mXQgY2h14buXaSANCg0KVsOtIGThu6U6IMSQ4buDIHTDrG0gxJHGsOG7o2MgduG7iyB0csOtIGvhur90IHRo4bupYyBi4bufaSBk4bqldSBjaOG6pW0gdGhhbighKSB0cm9uZyBjaHXhu5dpICoqKnJlZ2V4MioqKiBiw6puIGTGsOG7m2k6DQoNCmBgYHtyfQ0KcmVnZXgyIDwtIGMoIlRoaXMgaXMgbWUiLA0KICAgICAgICAiVGhhdCBteSBob3VzZSIsDQogICAgICAgICJIZWxsbywgd29ybGQhIikNCiAgICAgICAgDQpzdHJfZXh0cmFjdF9hbGwocmVnZXgyLCAiISQiKQ0KDQpgYGANCsSQ4buDIGhp4buHbiB0aOG7iyBjaHXhu5dpIMSRw6MgxJHGsOG7o2MgdMOsbSB0aOG6pXksIGNow7puZyB0w7RpIHPhu60gZOG7pW5nIGjDoG0gKioqc3RyX2RldGVjdCgpKioqIHRyb25nIGfDs2kgU3RyaW5nci4NCg0KYGBge3J9DQpyZWdleDJbc3RyX2RldGVjdChyZWdleDIsICIhJCIpXQ0KDQpgYGANClRp4bq/cCB04bulYyBjaMO6bmcgdMO0aSBz4bq9IHTDrG0gduG7iyB0csOtIGLhuq90IMSR4bqndSB24bubaSB04burICoqInRoaXMiKioNCg0KYGBge3J9DQpyZWdleDJbc3RyX2RldGVjdChyZWdleDIsICJeVGhpcyIpXQ0KDQpgYGANCg0KIyMjIyMgKioqVMOsbSBrw60gdOG7sSBob+G6t2Mgc+G7kSB0cm9uZyBjaHXhu5dpKioqDQoNClRp4bq/cCB04bulYyB24bubaSBjw6FjIGNodeG7l2kgxJHhuqd1IMSRw6MgxJHGsOG7o2MgZ8OhbiB0cm9uZyAqKipyZWdleDEqKiogxJHhu4MgdGjhu7FjIGhp4buHbiB0csOtY2ggY8OhYyBz4buRIHRyb25nIGNodeG7l2kuIOG7niBjw6FjIGNodeG7l2kgdHJvbmcgKioqcmVnZXgxKioqIGPDsyB0aOG7gyB0aOG6pXkgcuG6sW5nIGPDsyAzIGNodeG7l2kgbMOgIGThuqFuZyBjaHXhu5dpIGvDrSB04buxIGThuqFuZyBz4buRIHbDoCBiw6J5IGdp4budIGNow7puZyB0w7RpIHPhur0gdGjhu60gdHLDrWNoIHThuqV0IGPhuqMgY8OhYyBz4buRIHRyb25nIMSRb+G6oW4gdOG7qyAyIMSR4bq/biA0IGJhbyBn4buTbSBj4bqjIGhhaSBiw6puIHbDoCDEkeG6t3QgY2jDum5nIHRyb25nIGThuqV1IG5nb+G6t2MgdnXDtG5nICJbXSINCg0KYGBge3J9DQpzdHJfZXh0cmFjdF9hbGwocmVnZXgxLCAiWzItNF0iKQ0KDQpgYGANCg0KTmjhuq1uIHjDqXQ6IEvhur90IHF14bqjIHRy4bqjIHbhu4EgY2hvIGNow7puZyB0w7RpIHRo4bqleSBjw7MgNCBjaHXhu5dpIMSR4bqndSBsw6Aga2jDtG5nIHBo4bqjaSBsw6Aga8OtIHThu7Egc+G7kSB04bupYyBsw6Aga+G6v3QgcXXhuqMgY2hvIHJhIGNodeG7l2kgcuG7l25nIA0KDQpUaeG6v3AgdGhlbyBjaMO6bmcgdMO0aSBz4bq9IHRyw61jaCBjw6FjIGvDrSB04buxICItIiBob+G6t2MgIi4iIHbDoCDEkeG6t3QgY2jDum5nIHRyb25nIGThuqV1ICJbXSIgDQoNCmBgYHtyfQ0Kc3RyX2V4dHJhY3RfYWxsKHJlZ2V4MSwgIlstLl0iKQ0KDQpgYGANCk5o4bqtbiB4w6l0OiBL4bq/dCBxdeG6oyB0cuG6oyB24buBIGNobyBjaMO6bmcgdGEgdGjhuqV5IGPDsyAzIGNodeG7l2kgbMOgIGNobyByYSBr4bq/dCBxdeG6oyBy4buXbmcgdOG7qWMgbMOgIGtow7RuZyBjw7MgY2h14buXaSBjw7MgMiBrw60gdOG7sSDEkcOjIMSRxrDhu6NjIHRyw61jaC4gDQoNCg0KIyMjIyAqKirhu6huZyBk4bulbmcgY+G7p2EgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5KioqDQoNCiMjIyMjICoqKlRyw61jaCB4deG6pXQgc+G7kSDEkWnhu4duIHRob+G6oWkqKioNCg0KxJDhuqd1IHRpw6puIGNow7puZyBlbSBz4bq9IHRyw61jaCB4deG6pXQgdGjDtG5nIHRpbiB24buBIGPDoWMgc+G7kSDEkWnhu4duIHRob+G6oWkgZ+G7k20gMTAgY2jhu68gc+G7kSBj4butYSBIb2EgS+G7syB04burIG3hu5l0IHThu4dwIHbEg24gYuG6o24NCg0KYGBge3J9DQphMSA8LSAiSG9tZTogNTA3LTY0NS01NDg5Ig0KYTIgPC0gIkNlbGw6IDIxOS45MTcuOTg3MSINCmEzIDwtICJNeSB3b3JrIHBob25lIGlzIDUwNy0yMDItMjMzMiINCmE0IDwtICJJIGRvbid0IGhhdmUgYSBwaG9uZSINCmluZm8gPC0gYyhhMSwgYTIsIGEzLCBhNCkNCmluZm8NCmBgYA0KQsOieSBnaeG7nSBjaMO6bmcgZW0gc+G6vSB0csOtY2ggeHXhuqV0IGPDoWMgc+G7kSDEkWnhu4duIHRob+G6oWkgdOG7qyBjaHXhu5dpIG7DoHkuDQoNCk3DoyB2w7luZyBwaOG6o2kgYuG6r3QgxJHhuqd1IGLhurFuZyBz4buRIDIgdHLhu58gbMOqbiwgdsOsIHbhuq15IGNow7puZyBlbSBz4butIGThu6VuZyBs4bqhaSBk4bqldSBuZ2/hurdjIMSR4buDIGJp4buDdSB0aOG7iyBwaOG6oW0gdmk6IFsyLTldLiBIYWkgY2jhu68gc+G7kSB0aeG6v3AgdGhlbyBjw7MgdGjhu4MgbuG6sW0gdHJvbmcga2hv4bqjbmcgdOG7qyAwIMSR4bq/biA5LCB2w6wgduG6rXkgY2jDum5nIHTDtGkgdmnhur90IFswLTldezJ9LiDEkOG7kWkgduG7m2kgZOG6pXUgcGjDom4gY8OhY2gsIGNow7puZyB0w7RpIHPhu60gZOG7pW5nIFstLl0gxJHhu4MgYmnhu4N1IHRo4buLIGThuqV1IGfhuqFjaCBuZ2FuZyBob+G6t2MgZOG6pXUgY2jhuqVtLg0KDQpCaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgaG/DoG4gY2jhu4luaCDEkcaw4bujYyDEkcawYSByYSBkxrDhu5tpIMSRw6J5Og0KDQpgYGB7cn0NCnBob25lIDwtICIoWzItOV1bMC05XXsyfSlbLS5dKFswLTldezN9KVstLl0oWzAtOV17NH0pIg0Kb3V0IDwtIHN0cl9kZXRlY3QoaW5mbywgcGhvbmUpDQpvdXQNCmBgYA0KDQoNCkLDonkgZ2nhu50gY2jDum5nIGVtIOG6qW4gZGFuaCBjw6FjIHPhu5EgxJFp4buHbiB0aG/huqFpDQoNCmBgYHtyfQ0Kc3RyX3JlcGxhY2UoaW5mbywgcGhvbmUsICJYWFgtWFhYLVhYWFgiKQ0KDQpgYGANCiANCg0KIyMjIyMgKioqVHLDrWNoIGPDoWMgxJHhu4thIGNo4buJIGVtYWlsKioqDQoNClZp4buHYyB0csOtY2ggY8OhYyDEkeG7i2EgY2jhu4kgZW1haWwgdGjGsOG7nW5nIHBo4bupYyB04bqhcCBoxqFuIHNvIHbhu5tpIHPhu5EgxJFp4buHbiB0aG/huqFpLiBC4bufaSB2w6wgbeG7mXQgxJHhu4thIGNo4buJIGVtYWlsIGPDsyB0aOG7gyBjaOG7qWEgY2jhu68gaG9hLCBjaOG7ryB0aMaw4budbmcsIGNo4buvIHPhu5EsIGvDvSB04buxIMSR4bq3YyBiaeG7h3QsIG3hu41pIHRo4bupLiBDaMO6bmcgZW0gc+G6vSB0aOG7sWMgaMOgbmggdHLDrWNoIMSR4buLYSBjaOG7iSBlbWFpbCB04burIHbEg24gYuG6o24gZW1haWxzIHNhdToNCg0KYGBge3J9DQplbWFpbHMgPC0gYygiUmFzaE5FcmVsQGdtYWlsLmNvbSIsDQogICAgICAgICAgInJhc2gubmVyZWxAcmVnZW4wNC5uZXQiLA0KICAgICAgICAgICJyYXNoXzQ4QHVuaS5lZHUiLA0KICAgICAgICAgICJyYXNoXzQ4X25lcmVsQFNUQi5vcmciKQ0KYGBgDQoNCk3hu5l0IGVtYWlsIHbhu5tpIGhhaSBrw60gdOG7sSDEkeG6t2MgYmnhu4d0IG5nxINuIGPDoWNoIGzDoCDigJhA4oCZIHbDoCDigJgu4oCZIHPhur0gcGjDom4gxJHhu4thIGNo4buJIHRow6BuaCBiYSBwaOG6p246IHBo4bqnbiB0csaw4bubYyBrw60gdOG7sSDigJhA4oCZLCBwaOG6p24gc2F1IGThuqV1IOKAmEDigJkgdsOgIHRyxrDhu5tjIGvDrSB04buxIOKAmC7igJkgdsOgIGN14buRaSBjw7luZyBsw6AgcGjhuqduIGPDsm4gbOG6oWkuIOG7niDEkcOieSwgY2jhu4kgeMOpdCBrw60gdOG7sSDEkeG6t2MgYmnhu4d0IOKAmEDigJkgdsOgIOKAmC7igJkgeHXhuqV0IGhp4buHbiDEkeG6p3UgdGnDqm4gdHJvbmcgY2h14buXaSB0aGVvIHRo4bupIHThu7EgdOG7qyB0csOhaSBxdWEgcGjhuqNpLg0KDQotIFBo4bqnbiDEkeG6p3UgdGnDqm4gYmFvIGfhu5NtIGPDoWMga8OtIHThu7Egdmnhur90IHRoxrDhu51uZywgW2Etel0sIHZp4bq/dCBob2EsIFtBLVpdLCBjw6FjIGvDrSB04buxIHPhu5EsIFsw4oCTOV0gdsOgIG3hu5l0IHPhu5Ega8OtIHThu7EgxJHhurdjIGJp4buHdCBuaMawIOKAmC7igJkgdsOgIOKAmF/igJkuIERvIHbhuq15LCBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgY8OzIHRo4buDIMSRxrDhu6NjIHZp4bq/dCBsw6Ag4oCcW2EtekEtWjDigJM5LS5dK+KAnS4g4bueIMSRw6J5LCBk4bqldSDigJgr4oCZIGNobyBiaeG6v3QgY8OhYyBrw60gdOG7sSB0csOqbiBjw7MgdGjhu4MgeHXhuqV0IGhp4buHbiBuaGnhu4F1IGjGoW4gMSBs4bqnbiAocXV5IHThuq9jIDE3KS4gQuG7n2kgdsOsIGNow7puZyB0YSBraMO0bmcgYmnhur90IGPDoWMga8OtIHThu7EgeHXhuqV0IGhp4buHbiBiYW8gbmhpw6p1IGzhuqduIG7Dqm4ga2jDtG5nIHRo4buDIHPhu60gZOG7pW5nIHF1eSB04bqvYyAxOS4NCg0KLSBQaOG6p24gdGjhu6kgaGFpIGPFqW5nIHTGsMahbmcgdOG7sSBwaOG6p24gxJHhuqd1IG7Dqm4gY8OzIHRo4buDIMSRxrDhu6NjIHBow6F0IGhp4buHbiBxdWEgYmnhu4N1IHRo4bupYzog4oCcW2EtekEtWjDigJM5LS5dK+KAnQ0KDQotIFBo4bqnbiB0aOG7qSBiYSBsw6AgcGjhuqduIGPDsm4gbOG6oWkuIELhu59pIHbDrCB0w7RpIMSRw6MgdGjDqm0gZOG6pXUg4oCYK+KAmSBzYXUgcGjhuqduIHRo4bupIGhhaSBuw6puIG7DsyBjw7MgdGjhu4Mgbmjhuq1uIGLhuqV0IGvDrCBrw60gdOG7sSBuw6BvIHh14bqldCBoaeG7h24gc2F1IMSRw7MuDQoNClThu5VuZyBo4bujcCBs4bqhaSwgxJHhu4MgdHLDrWNoIGPDoWMgxJHhu4thIGNo4buJIGVtYWlsIHThu6sgdsSDbiBi4bqjbiBlbWFpbHMgdHLDqm4sIGNow7puZyBlbSB4w6J5IGThu7FuZyBt4buZdCBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgbmjGsCBzYXU6DQoNCmBgYHtyfQ0KcCA8LSAiW2EtekEtWjAtOS0uXStAW2EtekFfWjAtOV0rIg0Kc3RyX2V4dHJhY3RfYWxsKGVtYWlscywgcCkNCmBgYA0KDQpgYGB7cn0NCnAgPC0gIlthLXpBLVowLTktLl0rQFthLXpBX1owLTldK1xcLihjb218ZWR1fG5ldHxvcmcpIg0Kc3RyX2V4dHJhY3RfYWxsKGVtYWlscywgcCkNCmBgYA0KDQoNCiMjIyMjICoqKlRyw61jaCBjw6FjIFVSTCoqKg0KDQpWaeG7h2MgdHLDrWNoIGPDoWMgVVJMIGPFqW5nIHTGsMahbmcgdOG7sSBuaMawIHbhu5tpIHPhu5EgxJFp4buHbiB0aG/huqFpLCBt4bq3YyBkw7kgY8OzIMSRw7RpIGNow7p0IGLhuqV0IHRp4buHbiBkbyBjw6FjIMSR4buLYSBjaOG7iSBjw7MgdGjhu4MgYuG6r3QgxJHhuqd1IHbhu5tpIGNodeG6qW4gaHR0cCBoYXkgaHR0cHMsIGPDsyBob+G6t2Mga2jDtG5nIGPDsyB3d3cuLiBDaMO6bmcgZW0gc+G6vSB0aOG7sWMgaMOgbmggdHLDrWNoIGPDoWMgVVJMIHThu6sgdsSDbiBi4bqjbiB1cmxzIHNhdToNCg0KYGBge3J9DQp1cmxzIDwtIGMoImh0dHBzOi8vcmVnZW5lcmF0aXZldG9kYXkuY29tIiwNCiAgICAgICAgICJodHRwOi8vc2V0Zi5tbCIsDQogICAgICAgICAiaHR0cHM6Ly93d3cueWFob28uY29tIiwNCiAgICAgICAgICJodHRwOi8vc3R1ZGlvX2Jhc2UubmV0Ig0KICAgICAgICAgKQ0KYGBgDQoNCk3hu5l0IFVSTCBz4bq9IGJhbyBn4buTbSAzIHBo4bqnbjoNCg0KLSBQaOG6p24gxJHhuqd1IGJhbyBn4buTbSBjw6FjIHRp4buBbiB04buRIGh0dHAgaGF5IGh0dHBzLCBjw7MgaG/hurdjIGtow7RuZyBjw7Mgd3d3LiBOw7MgY8OzIHRo4buDIMSRxrDhu6NjIGdoaSBuaOG6rW4gYuG6sW5nIGPDoWNoIHPhu60gZOG7pW5nIHF1eSB04bqvYyAxNSwgMTggbmjGsCBzYXU6DQrigJhodHRwcz/igJk6IGPDsyBob+G6t2Mga2jDtG5nIGvDrSB04buxIOKAmHPigJkg4oCcKHd3dy4pP+KAnTogY8OzIGhv4bq3YyBraMO0bmcgdOG7qyDigJh3d3cu4oCZDQoNCiBQaOG6p24gdGjhu6kgaGFpIGzDoCB0w6puIG1p4buBbiBjw7MgdGjhu4MgbMOgIGLhuqV0IGvDrCBrw60gdOG7sSB0aMO0bmcgdGjGsOG7nW5nIG7DoG8gxJHGsOG7o2MgbOG6t3AgbOG6oWkgbmhp4buBdSBoxqFuIG3hu5l0IGzhuqduIOKAkz4gc+G7rSBk4bulbmc6IOKAnCvigJ0NCg0KIFBo4bqnbiB0aOG7qSBiYSBsw6Agc2F1IHTDqm4gbWnhu4FuOiBjw7MgdGjhu4MgY8OzIG3hu5l0IGhv4bq3YyBuaGnhu4F1IGjGoW4gbeG7mXQgZOG6pXUgY2jhuqVtIOKAnC7igJ0gdsOgIHRoZW8gc2F1IGzDoCBjw6FjIGvDrSB04buxIHRow7RuZyB0aMaw4budbmcga2jDoWMg4oCTPiBz4butIGThu6VuZzog4oCcLivigJ0NCg0KVOG7lW5nIGjhu6NwIGzhuqFpLCBlbSBz4bq9IHZp4bq/dCBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgxJHhu4MgdHLDrWNoIGPDoWMgVVJMIHThu6sgdsSDbiBi4bqjbiB1cmxzIG5oxrAgc2F1Og0KDQpgYGB7cn0NCnAgPC0gImh0dHBzPzovLyh3d3dcXC4pP1xcdytcXC5cXHcrIg0Kc3RyX2V4dHJhY3RfYWxsKHVybHMsIHApDQpgYGANCg0KVHJvbmcgdHLGsOG7nW5nIGjhu6NwIGNo4buJIG114buRbiBs4bqleSBjw6FjIHTDqm4gbWnhu4FuIOKAmC5jb23igJkgaG/hurdjIOKAmC5uZXTigJkgdGjDrCBi4buVIHN1bmcgdGjDqm0gbmjDs20gKGNvbXxuZXQpIHbDoG8gYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IHRyw6puIG5oxrAgc2F1Og0KDQpgYGB7cn0NCnAgPC0gImh0dHBzPzovLyh3d3dcXC4pPyhcXHcrKShcXC4pKyhjb218bmV0KSINCnN0cl9leHRyYWN0X2FsbCh1cmxzLCBwKQ0KYGBgDQoNCg0KIyMjIyMgKioqWHXhuqV0IGRhbmggYuG6oSoqKg0KDQpDdeG7kWkgY8O5bmcgbMOgIHbDrSBk4bulIGvhur90IGjhu6NwIGPDoWMgcXV5IHThuq9jIMSR4buDIHh14bqldCBjw6FjIGRhbmggYuG6oSB04burIG3hu5l0IHbEg24gYuG6o24gKioqbmFtZSoqKiBzYXU6DQoNCmBgYHtyfQ0KbmFtZSA8LSBjKCJNci4gSm9uIiwNCiAgICAgICAgICJNcnMuIEpvbiIsDQogICAgICAgICAiTXIgUm9uIiwNCiAgICAgICAgICJNcy4gUmVlbmUiLA0KICAgICAgICAgIk1zIEp1bGllIikNCmBgYA0KDQpN4buZdCBkYW5oIGLhuqEgYmFvIGfhu5NtIGLDrSBkYW5oIE1yLCBNcnMsIE1zICjigJM+IHPhu60gZOG7pW5nOiDigJxNKHJ8c3xycynigJ0pIGPDsyB0aOG7gyBjw7MgaG/hurdjIGtow7RuZyBk4bqldSDigJgu4oCZIMSRaSBrw6htICjigJM+IHPhu60gZOG7pW5nOiDigJwuP+KAnSksIHRoZW8gc2F1IGzDoCBt4buZdCBraG/huqNuZyB0cuG6r25nICjigJM+IHPhu60gZOG7pW5nOiDigJzigJ0pLg0KDQpTYXUgxJHDsyBsw6AgdMOqbiwgduG7m2kga8OtIHThu7EgxJHhuqd1IHRpw6puIHZp4bq/dCBob2EgKOKAkz4gc+G7rSBk4bulbmc6IOKAnFtBLVpd4oCdKSwgdGhlbyBzYXUgbMOgIGPDoWMga8OtIHThu7EgdGjDtG5nIHRoxrDhu51uZyAo4oCTPiBz4butIGThu6VuZzog4oCc4oCdKS4gU+G7rSBk4bulbmcgZOG6pXUg4oCZ4oCZIGPDsyBuZ2jEqWEgY8OhYyBrw60gdOG7sSB0csaw4bubYyDEkcOzIGPDsyB0aOG7gyBraMO0bmcgeHXhuqV0IGhp4buHbiBob+G6t2MgeHXhuqV0IGhp4buHbiBuaGnhu4F1IGzhuqduLiBL4bq/dCBo4bujcCBs4bqhaSwgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IHNhdSBz4bq9IHRyw61jaCBjw6FjIGRhbmggYuG6oSB04burIHbEg24gYuG6o24gKioqbmFtZSoqKiBuaMawIHNhdQ0KDQpgYGB7cn0NCnAgPC0gIk0ocnxzfHJzKVxcLj9bQS1aXFxzXVxcdyoiDQpzdHJfZXh0cmFjdF9hbGwobmFtZSwgcCkNCmBgYA0KDQojIyMjIyAqKipU4bqtcCB0aW4qKioNCg0K4bueIMSRw6J5IGVtIGPDsyA4IHThuq1wIHRpbiB04burIG7Eg20gMTk5OSDEkeG6v24gbsSDbSAyMDExIGNoxrBhIMSRxrDhu6NjIHjhu60gbMO9IG7Dqm4gZOG7ryBsaeG7h3UgYsOqbiB0cm9uZyBsw6AgZOG7ryBsaeG7h3UgdGjDtCwgYsOieSBnaeG7nSBlbSBz4bq9IGTDuW5nIGNo4bupYyBuxINuZyBzdHJfc3Vic2V0KCkgxJHhu4MgdHLDrWNoIHh14bqldCBjw6FjIHThu4dwIHThu6sgbsSDbSAyMDAzIHRy4bufIGzDqm4NCg0KYGBge3J9DQpmaWxlcyA8LSBjKCJmaWxlMTk5OS50eHQiLCAiZmlsZTIwMDAudHh0IiwgImZpbGUyMDAxLnR4dCIsICJmaWxlMjAwMi50eHQiLCAiZmlsZTIwMDMudHh0IiwNCiAgICAgICAgICAgImZpbGUyMDA5LnR4dCIsICJmaWxlMjAxMC50eHQiLCAiZmlsZTIwMTEudHh0IikNCnN0cl9zdWJzZXQoZmlsZXMsICIoMjAwWzMtOV17MX18MjAxWzAtOV17MX0pIikNCg0KYGBgDQoNCg0KDQojIENIxq/GoE5HIDM6IE3hu5l0IHPhu5Eg4bupbmcgZOG7pW5nIGPhu6dhIGfDs2kgU3RyaW5ncg0KDQpUcm9uZyBjaMawxqFuZyBuw6B5IGNow7puZyBlbSBz4bq9IOG7qW5nIGThu6VuZyBjw6FjIGNo4bupYyBuxINuZyDEkcOjIMSRxrDhu6NjIHRoYW8gdMOhYyDhu58gY2jGsMahbmcgMiB2w6BvIHBow6JuIHTDrWNoIHRyw6puIG3hu5l0IHPhu5EgYuG7mSBk4buvIGxp4buHdSBnacO6cCBuZ8aw4budaSDEkeG7jWMgY8OzIHRo4buDIG5o4bqtbiB0aOG6pXkgdsOgIGhp4buDdSByw7UgaMahbiB24buBIGfDs2kgU3RyaW5nci4NCg0KIyMgIEThu68gbGnhu4d1IEJhYnluYW1lcw0KDQpC4buZIGThu68gbGnhu4d1IEJhYnluYW1lcyB0cm9uZyBuZ8O0biBuZ+G7ryBs4bqtcCB0csOsbmggUiBsw6AgbeG7mXQgdOG6rXAgaOG7o3AgZOG7ryBsaeG7h3UgdGjhu5FuZyBrw6ogduG7gSB0w6puIHRy4bq7IHPGoSBzaW5oIHRoZW8gdGjhu51pIGdpYW4gdsOgIHThuqduIHN14bqldCBz4butIGThu6VuZyB0w6puIMSRw7MgdHJvbmcgY8OhYyBuxINtIGtow6FjIG5oYXUgdOG7qyBuxINtIDE4ODAgxJHhur9uIG7Eg20gMjAxNy4gQuG7mSBk4buvIGxp4buHdSBuw6B5IGJhbyBn4buTbSAxOTI0NjY1IHF1YW4gc8OhdCB2w6AgY8OzIDUgYmnhur9uLiBUcm9uZyDEkcOzOiANCg0KLSAgICoqeWVhcioqOiBOxINtIHNpbmgNCi0gICAqKnNleCoqOiBHaeG7m2kgdMOtbmgNCi0gICAqKm5hbWUqKjogVMOqbg0KLSAgICoqbioqOiBT4buRIGzhuqduIHTDqm4gxJHDsyDEkcaw4bujYyBz4butIGThu6VuZw0KLSAgICoqcHJvcCoqOiBU4bu3IGzhu4cgcGjhuqduIHRy4bqvbSB0w6puIGPhu6UgdGjhu4MgdHJvbmcgc+G7kSB04bqldCBj4bqjIGPDoWMgdMOqbiBjw7luZyBnaeG7m2kgdMOtbmggdHJvbmcgY8O5bmcgbeG7mXQgbsSDbQ0KDQpgYGB7cn0NCmJhYnluYW1lcw0KYGBgDQoNCmBgYHtyLGVjaG89RkFMU0Usd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZHBseXIpDQpgYGANCg0KxJDhuqd1IHRpw6puLCBjaMO6bmcgZW0gc+G7rSBk4bulbmcgKioqc3RyX2RldGVjdCgpKioqIMSR4buBIHTDrG0gdOG6pXQgY+G6oyBjw6FjIHTDqm4gYuG6r3QgxJHhuqd1IGLhurFuZyAqKionc2gnKioqLiBTYXUgxJHDsyDEkeG7gyBjaGkgdGnhur90IGjGoW4gY2jDum5nIGVtIGvhur90IGjhu6NwIGfDs2kgZ2dwbG90IMSR4buDIHZp4bq/dCBt4buZdCBi4buZIG3DoyBkw6BpIHbDoCBwaOG7qWMgdOG6oXAgc+G6vSB0cuG7sWMgcXVhbiBow7NhIGPDoWMgdMOqbiBwaOG7lSBiaeG6v24gYuG6r3QgxJHhuqd1IGLhurFuZyAnc2gnIGNobyBwaOG7pSBu4buvIHNpbmggbsSDbSAxOTM4DQoNCg0KYGBge3J9DQpiYWJ5bmFtZXMgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChuYW1lLCAiU2giKSAmIHNleD09IkYiICYgeWVhciA9PSAxOTM4KSAlPiUgDQogIGFycmFuZ2UoZGVzYyhwcm9wKSkgJT4lIA0KICBoZWFkKDIwKSAlPiUgDQogIGdncGxvdChhZXMocmVvcmRlcihuYW1lLHByb3ApLHByb3AsICBmaWxsID0gbmFtZSkpICsgDQogIGdlb21fY29sKCkgKw0KICBjb29yZF9mbGlwKCkNCmBgYA0KDQpTYXUga2hpIGzhu41jIHbDoCBz4bqvcCB44bq/cCwgY2jDum5nIGVtIMSRw6MgdOG6oW8gcmEgbeG7mXQgYmnhu4N1IMSR4buTIGPhu5l0IHRo4buDIGhp4buHbiAyMCB0w6puIHBo4buVIGJp4bq/biBuaOG6pXQgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UuIEJp4buDdSDEkeG7kyBuw6B5IHPhur0gxJHGsOG7o2MgduG6vSB24bubaSB0cuG7pWMgZOG7jWMsIHbDoCBt4buXaSBj4buZdCBz4bq9IMSR4bqhaSBkaeG7h24gY2hvIG3hu5l0IHTDqm4sIGPDsyBjaGnhu4F1IGNhbyB0aOG7gyBoaeG7h24gdOG7tyBs4buHIHBo4buVIGJp4bq/biBj4bunYSB0w6puIMSRw7MgdHJvbmcgdOG6rXAgZOG7ryBsaeG7h3UuDQoNCsSQ4buDIGhp4buDdSByw7UgaMahbiB24buBIGvhur90IHF14bqjIGPhu6UgdGjhu4MsdGnhur9wIHRoZW8gZW0gc+G6vSB0w61uaCB04bu3IGzhu4cgcGjhuqduIHRyxINtIGNobyBt4buXaSBuxINtL23hu5dpIGdp4bubaSB0w61uaA0KDQpCaeG7g3UgxJHhu5MgbsOgeSBz4bq9IGdpw7pwIGNow7puZyB0YSB0aOG6pXkgcsO1IGjGoW4gduG7gSB04bqnbiBzdeG6pXQgY+G7p2EgY8OhYyB0w6puIGNo4bupYSBjaHXhu5dpIOKAnFNo4oCdIHbDoCBjw6FjaCBjaMO6bmcgcGjDom4gY2hpYSBwaOG6p24gdHLEg20gcGjhu5UgYmnhur9uLiBDw6FjIHTDqm4gcGjhu5UgYmnhur9uIGjGoW4gc+G6vSBjw7MgY+G7mXQgY2FvIGjGoW4sIHbDoCBj4buZdCB0aOG6pXAgaMahbiBz4bq9IMSR4bqhaSBkaeG7h24gY2hvIGPDoWMgdMOqbiDDrXQgcGjhu5UgYmnhur9uIGjGoW4uDQoNCmBgYHtyfQ0KYmFieW5hbWVzICU+JSANCiAgZmlsdGVyKHN0cl9kZXRlY3QobmFtZSwgIlNoIikgJiBzZXg9PSJGIiAmIHllYXIgPT0gMTkzOCkgJT4lIA0KICBhcnJhbmdlKGRlc2MocHJvcCkpICU+JSANCiAgaGVhZCgyMCkgJT4lIA0KICBtdXRhdGUocGVyY2VudCA9IChwcm9wICogMTAwKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHJlb3JkZXIobmFtZSxwZXJjZW50KSxwZXJjZW50LCAgZmlsbCA9IG5hbWUpKSArIA0KICBnZW9tX2NvbCgpICsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KKipOaOG6rW4geMOpdCoqOiBRdWEgMiBiaeG7g3UgxJHhu5MgdHLDqm4gY8OzIHRo4buDIHRo4bqleSBuZ8aw4budaSBjw7MgdMOqbiBTaGlybGV5IGzDoCBjw7MgdOG7tyBs4buHIHBo4bqnbiB0csSDbSBjYW8gdHJvbmcgc+G7kSBuaOG7r25nIG5nxrDhu51pIHBo4bulIG7hu68gc2luaCBuxINtIDE5MzgNCg0KVHV5IG5oacOqbiwgxJHhu4MgY8OzIGPDoWkgbmjDrG4gY2jDrW5oIHjDoWMgaMahbiB24buBIGvhur90IHF14bqjIGPFqW5nIG5oxrAgY8OzIHRo4buDIHjDoWMgxJHhu4tuaCDEkcaw4bujYyBr4bq/dCBxdeG6oyBjdeG7kWkgY8O5bmcgdsOgIGhp4buDdSByw7UgaMahbiB24buBIHBow6JuIHBo4buRaSBj4bunYSBjw6FjIHTDqm4gLCBuw6puIGLDonkgZ2nhu50gY2jDum5nIGVtIGTDuW5nIHN0cl9kZXRlY3QoKSDEkeG7gyB4ZW0gY8OzIGJhbyBuaGnDqnUgbmfGsOG7nWkgY8OzIHTDqm4gYuG6r3QgxJHhuqd1IGLhurFuZyBk4buvIOKAmHrigJkgdOG7qyBuxINtIDIwMDANCg0KYGBge3J9DQpiYWJ5bmFtZXMgJT4lIA0KICBmaWx0ZXIoeWVhciA+IDIwMDAgJiBzdHJfZGV0ZWN0KG5hbWUsICJaIikpICU+JSANCiAgYXJyYW5nZShkZXNjKHByb3ApKQ0KYGBgDQoNCkvhur90IHF14bqjIMSRw6MgaGnhu4NuIHRow6wgxJFjIHLhurFuZzogdOG6rXAgZOG7ryBsaeG7h3UgbsOgeSBjaOG7qWEgY8OhYyB0w6puIGPhu6dhIGPDoWMgZW0gYsOpIHNpbmggc2F1IG7Eg20gMjAwMCB2w6AgY2jhu6lhIGvDvSB04buxIOKAnFrigJ0sIMSRxrDhu6NjIHPhuq9wIHjhur9wIHRoZW8gdGjhu6kgdOG7sSBnaeG6o20gZOG6p24gY+G7p2EgdOG7tyBs4buHIHByb3AgLiBUaGF5IHbDrCBz4bqvcCB44bq/cCBuaOG7r25nIHTDqm4gdGhlbyBt4bupYyDEkeG7mSBwaOG7lSBiaeG6v24gdGjDrCBjaMO6bmcgZW0gc+G6vSBwaMOibiBsb+G6oWkgeGVtIG5o4buvbmcgdMOqbiBjw7Mgbmhp4buBdSBjaOG7ryDigJha4oCZIG5o4bqldA0KDQoNCmBgYHtyfQ0KYmFieW5hbWVzICU+JSANCiAgICAgIG11dGF0ZShaID0gc3RyX2NvdW50KGJhYnluYW1lcyRuYW1lLCAiW3paXSIpKSAlPiUgDQogICAgICBhcnJhbmdlKGRlc2MoWikpDQpgYGANCg0KQ2jDum5nIGVtIMSRw6MgdOG6oW8gcmEgbeG7mXQgdOG6rXAgZOG7ryBsaeG7h3UgbeG7m2kgYuG6sW5nIGPDoWNoIHRow6ptIGPhu5l0IOKAnFrigJ0gdsOgbyB04bqtcCBk4buvIGxp4buHdSBiYW4gxJHhuqd1LiBD4buZdCDigJxa4oCdIGNo4bupYSBz4buRIGzGsOG7o25nIGzhuqduIHh14bqldCBoaeG7h24gY+G7p2Ega8O9IHThu7Eg4oCceuKAnSBob+G6t2Mg4oCcWuKAnSB0cm9uZyBt4buXaSB0w6puLiBTYXUgxJHDsywgdOG6rXAgZOG7ryBsaeG7h3UgxJHGsOG7o2Mgc+G6r3AgeOG6v3AgdGhlbyB0aOG7qSB04buxIGdp4bqjbSBk4bqnbiBj4bunYSBj4buZdCDigJxa4oCdLg0KDQoqKlbDrSBk4bulOioqIGTDsm5nIMSR4bqndSB0acOqbiBjaG8gdGjhuqV5IHLhurFuZyB0cm9uZyBuxINtIDIwMTAsIGPDsyA1IGVtIGLDqSBuYW0gxJHGsOG7o2MgxJHhurd0IHTDqm4gbMOgIOKAnFp6eXp44oCdLiBUw6puIG7DoHkgY8OzIHThu7cgbOG7hyB4deG6pXQgaGnhu4duIHLhuqV0IHRo4bqlcCAoMC4wMDAwMDI0NCksIG5oxrBuZyBs4bqhaSBjaOG7qWEgMyBrw70gdOG7sSDigJx64oCdIGhv4bq3YyDigJxa4oCdLg0KDQoNCkN14buRaSBjw7luZyDEkeG7gyB4ZW0gY8OzIGJhbyBuaGnDqnUgdMOqbiBjw7MgY2jhu6lhICdsaXonIHbDoCB24bq9IGNow7puZyBi4bqxbmcgYmnhu4N1IMSR4buTIMSR4buDIHRo4bqleSByw7UgaMahbg0KDQpgYGB7cn0NCmJhYnluYW1lcyAlPiUgDQogICAgICBmaWx0ZXIoc3RyX2RldGVjdChiYWJ5bmFtZXMkbmFtZSwgImxpeiIpICkgICU+JSANCiAgICAgIGNvdW50KG5hbWUsIHNvcnQgPSBUUlVFKSAlPiUgDQogICAgICBoZWFkKDIwKSAlPiUgDQogICAgICBnZ3Bsb3QoYWVzKHJlb3JkZXIobmFtZSwgbiksbikpICsgZ2VvbV9jb2woKSArIA0KICAgICAgY29vcmRfZmxpcCgpDQpgYGANCg0KKipOaOG6rW4geMOpdCoqOiBuaMOsbiB2w6BvIGJp4buDdSDEkeG7kyB0YSBjw7MgdGjhursgdGjhuqV5IEVsaXphYmV0aCBsw6AgdMOqbiBwaOG7lSBiaeG6v24gbmjhuqV0IHRyb25nIHTDqm4gY2jhu6lhIGNodeG7l2kg4oCcbGl64oCdLA0KDQoNCg0KIyMgTXVyZGVycw0KDQrEkOG7gyBoaeG7g3UgaOG7j2kgduG7gSBjw6FjIGNo4bupYyBuxINuZyB0cm9uZyBnw7NpIFN0cmluZ3IgdGjDrCBuaMOzbSBjaMO6bmcgZW0gc+G6vSB0aGFvIHTDoWMgdHLDqm4gYuG7mSBk4buvIGxp4buHdSAqKm11cmRlcnMqKi4gQuG7mSBk4buvIGxp4buHdSBNdXJkZXJzIGzDoCBk4buvIGxp4buHdSDEkcaw4bujYyBjdW5nIGPhuqVwIGLhu59pIGfDs2kgZOG7ryBsaeG7h3UgImRhbGFicyIgdHJvbmcgUnN0dWRpby4gQuG7mSBk4buvIGxp4buHdSBuw6B5IGNo4bupYSB0aMO0bmcgdGluIHbhu4Egc+G7kSBsxrDhu6NuZyB24bulIOG6pW4gZ2nhur90IG5nxrDhu51pIGPhu6dhIHThu6tuZyB0aeG7g3UgYmFuZyDhu58gSG9hIEvhu7MgdHJvbmcgbeG7mXQga2hv4bqjbmcgdGjhu51pIGdpYW4gY+G7pSB0aOG7gy4g4bueIGLhu5kgZOG7ryBsaeG7h3UgbsOgeSBnacO6cCBjaMO6bmcgdGEgbMOgbSB2aeG7h2MgduG7m2kgY8OhYyBjaHXhu5dpIG7hurFtIHRyb25nIG3hu5l0IGPhu5l0IHRyb25nIG3hu5l0IGtodW5nIGThu68gbGnhu4d1IHbDoCBjaMO6bmcgZW0gc+G6vSB0w6xtIGhp4buDdSBjw6FjaCB04bqtcCBo4bujcCBt4buZdCBraHVuZyBk4buvIGxp4buHdSB0aGVvIGPDoWMgY2h14buXaSBjaMO6bmcgdGEgbXXhu5FuLg0KDQrEkOG6p3UgdGnDqm4gY2jDum5nIHRhIHPhur0gZ+G7jWkgYuG7mSBk4buvIGxp4buHdSBuw6B5IGzDqm4gc2F1IGtoaSDEkcOjIGPDoGkgxJHhurd0IHBhY2thZ2UgKioqZGFsYWJzKioqIHbDoCB04bqjaSB0aMawIHZp4buHbiBuw7MgbMOqbi4gQuG6o25nIGThu68gbGnhu4d1IGLDqm4gZMaw4bubaSwgbeG7l2kgcXVhbiBzw6F0IHPhur0gY2hvIGNow7puZyB0YSBiaeG6v3QgdGjDtG5nIHRpbiB24buBIHTDqm4gY+G7p2EgdGnhu4N1IGJhbmcsIHTDqm4gdmnhur90IHThuq90IGPhu6dhIHRp4buDdSBiYW5nIMSRw7MsIHbDuW5nIGPhu6dhIHRp4buDdSBiYW5nLCBkw6JuIHPhu5EgY+G7p2EgdGnhu4N1IGJhbmcgdMawxqFuZyDhu6luZywgdOG7lW5nIHPhu5EgduG7pSDDoW4gZ2nhur90IG5nxrDhu51pIHRyb25nIHRp4buDdSBiYW5nIHRyb25nIG7Eg20gdMawxqFuZyDhu6luZy4NCg0KYGBge3J9DQpsaWJyYXJ5KGRzbGFicykNCmRhdGEoIm11cmRlcnMiKQ0KZGF0YXRhYmxlKG11cmRlcnMpDQpgYGANCg0KUXVhIGLhuqNuZyB0csOqbiBjaMO6bmcgdGEgY8OzIHRo4buDIHRo4bqleSBkYXRhZnJhbWUgbsOgeSBjw7MgMiBj4buZdCBsw6AgY2h14buXaSBrw70gdOG7sSB2w6AgY+G7mXQgdsO5bmcgbMOgIGjhu4cgc+G7kSBuaMawbmcgY8OzIHRo4buDIGThu4UgZMOgbmcgxJHhu5VpIHRow6BuaCBraeG7g3Uga8O9IHThu7EuIFRow7RuZyB0aMaw4budbmcgY2jDum5nIHRhIHPhur0gY2jhu4kgbXXhu5FuIGzhuqV5IGPDoWMgaMOgbmcgY+G7p2Ega2h1bmcgZOG7ryBsaeG7h3UgxJHDoXAg4bupbmcgbeG7mXQgdGnDqnUgY2jDrSBuaOG6pXQgxJHhu4tuaC4gxJDhu4MgbMOgbSDEkWnhu4F1IMSRw7MgZOG7ryB0csOqbiBjaHXhu5dpLCBjaMO6bmcgZW0gc+G6vSBz4butIGThu6VuZyAqKipmaWx0ZXIoKSoqKiB2w6AgKioqc3RyX2RldGVjdCgpKioqLiBCw6J5IGdp4budIGNow7puZyBlbSBz4bq9IHLDunQgcmEgdOG6pXQgY+G6oyBjw6FjIGjDoG5nIGPDsyB0cuG6oW5nIHRow6FpDQoNCg0KYGBge3J9DQojIEPDoWMgdHLhuqFuZyB0aMOhaSBi4bqvdCDEkeG6p3UgYuG6sW5nIEENCm11cmRlcnMgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChzdHJpbmcgPSBzdGF0ZSwgcGF0dGVybiA9ICJBIikpDQpgYGANCg0KDQpgYGB7cn0NCiMgQ8OhYyB0cuG6oW5nIHRow6FpIGLhuq90IMSR4bqndSBi4bqxbmcgQSBob+G6t2MgQw0KbXVyZGVycyAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHN0cmluZyA9IHN0YXRlLCBwYXR0ZXJuID0gIkF8QyIpKQ0KDQpgYGANCg0KKipOaOG6rW4geMOpdCoqOiBDaMO6bmcgdGEgxJHDoyBs4buNYyByYSBjw6FjIHRp4buDdSBiYW5nIGPDsyB0w6puIGNo4bupYSDDrXQgbmjhuqV0IG3hu5l0IHRyb25nIGhhaSBrw70gdOG7sSDigJxB4oCdIGhv4bq3YyDigJxD4oCdIHThu6sgdOG6rXAgZOG7ryBsaeG7h3UgKioq4oCcbXVyZGVyc+KAnSoqKi4gxJBp4buBdSBuw6B5IGPDsyB0aOG7gyBnacO6cCBjaMO6bmcgcmEgY8OzIGPDoWMgdGjDtG5nIHRpbiB24buBIHRp4buDdSBiYW5nLCBraHUgduG7sWMsIGTDom4gc+G7kSB2w6Agc+G7kSB24bulIMOhbiBnaeG6v3QgbmfGsOG7nWkgxJHDoyDEkcaw4bujYyBoaeG7g24gdGjhu4sgY2jhu6lhIGPDoWMga8O9IHThu7EgY+G7pSB0aOG7gw0KDQpN4buZdCBjw6FjaCBraMOhYyBtw6AgY2jDum5nIGVtIGPDsyB0aOG7gyBj4bqnbiDEkeG7gyB0aGFvIHTDoWMgduG7m2kgbeG7mXQgY+G7mXQgY2h14buXaSBrw70gdOG7sSBsw6AgdGhheSDEkeG7lWkgY8OhYyB04burLiBWw60gZOG7pSwgdHJvbmcga2h1bmcgZOG7ryBsaeG7h3UgduG7pSBnaeG6v3QgbmfGsOG7nWksIGNow7puZyBlbSBz4bq9IHRoYXkgxJHhu5VpIHTDqm4gY+G7p2EgY8OhYyBraHUgduG7sWMgxJHhu4MgdOG6pXQgY+G6oyBjaMO6bmcgxJHhu4F1IGzDoCBt4buZdCB04burIHbDoCB04bqldCBj4bqjIMSR4buBdSBsw6AgY2jhu68gdGjGsOG7nW5nLiDEkOG7gyBsw6BtIMSRaeG7gXUgbsOgeSwgY2jDum5nIGVtIHPhur0ga+G6v3QgaOG7o3AgY8OhYyAgKioqc3RyX2MoKSoqKiB2w6AgY2jhu6ljIG7Eg25nICoqKnN0cl9yZXBsYWNlKCkqKiouDQoNCg0KYGBge3J9DQpzdGF0ZXMub2YuaW50ZXJlc3QgPC0gYygiVGV4YXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICJMb3Vpc2lhbmEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICJNaXNzaXNzaXBwaSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIkFsYWJhbWEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICJGbG9yaWRhIikNCnN0YXRlcy5vZi5pbnRlcmVzdCA8LSBzdHJfYyhzdGF0ZXMub2YuaW50ZXJlc3QsIGNvbGxhcHNlPSJ8IikgDQpzdGF0ZXMub2YuaW50ZXJlc3QNCmBgYA0KDQrEkMOieSBsw6AgbeG7mXQgY2h14buXaSBiaeG7g3UgZGnhu4VuIGPhu6dhIGPDoWMgdMOqbiB0aeG7g3UgYmFuZywgxJHGsOG7o2MgbuG7kWkgbOG6oWkgduG7m2kgbmhhdSBi4bqxbmcgZOG6pXUg4oCcfOKAnQ0KDQoNCmBgYHtyfQ0KbXVyZGVycyAlPiUgDQogIGZpbHRlcihzdHJfZGV0ZWN0KHN0cmluZyA9IHN0YXRlLCBwYXR0ZXJuID0gc3RhdGVzLm9mLmludGVyZXN0KSkNCmBgYA0KDQpExrDhu5tpIMSRw6J5IGzDoCB0aMO0bmcgdGluIHbhu4EgY8OhYyB0aeG7g3UgYmFuZyBtw6AgdMOqbiBraMO0bmcgY2jhu6lhIGvDvSB04buxIOKAnEHigJ0gaG/hurdjIOKAnEPigJ0gdOG7qyB04bqtcCBk4buvIGxp4buHdSAqKirigJxtdXJkZXJz4oCdKioqLg0KDQpgYGB7cn0NCm11cmRlcnMgJT4lIA0KICBmaWx0ZXIoc3RyX2RldGVjdChzdHJpbmcgPSBzdGF0ZSwgcGF0dGVybiA9ICJBfEMiLCBuZWdhdGUgPSBUUlVFKSkNCmBgYA0KDQoNCmBgYHtyfQ0KbXVyZGVycyAlPiUgDQogIGRpc3RpbmN0KHJlZ2lvbikNCmBgYA0KDQpL4bq/dCBxdeG6oyDEkcOjIHRyw61jaCB4deG6pXQgY8OhYyBnacOhIHRy4buLIGR1eSBuaOG6pXQgdOG7qyBj4buZdCDigJxyZWdpb27igJ0gdsOgIGhp4buDbiB0aOG7iyB0aMO0bmcgdGluIGPDoWMga2h1IHbhu7FjIMSR4buLYSBsw70ga2jDoWMgbmhhdSBtw6AgY8OhYyB0aeG7g3UgYmFuZyB0cm9uZyB04bqtcCBk4buvIGxp4buHdSAqKirigJxtdXJkZXJz4oCdKioqIHRodeG7mWMgduG7gS4NCg0KDQrhu54gdsO5bmcgJ1NvdXRoJyB24bqrbiBjw7JuIMSRYW5nIGzDoCBjaOG7ryBjw6FpIGhvYSDEkeG6p3UsIGLDonkgZ2nhu50gZW0gc+G6vSB0aGF5IMSR4buVaSBt4buZdCB2w7luZyB24buBIGzhuqFpIGNo4buvIHRoxrDhu51uZw0KDQpgYGB7cn0NCm11cmRlcnMgJT4lIA0KICBtdXRhdGUocmVnaW9uID0gc3RyX3JlcGxhY2Uoc3RyaW5nID0gcmVnaW9uLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiU291dGgiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gInNvdXRoIikpICU+JSANCiAgaGVhZCgpDQpgYGANCg0KQ3Xhu5FpIGPDuW5nIGNow7puZyBlbSBz4bq9IMSR4buVaSB0w6puIHThuqV0IGPhuqMgY8OhYyB2w7luZyB24buBIGNo4buvIHRoxrDhu51uZw0KDQpgYGB7cn0NCm11cmRlcnMgJT4lIA0KICBtdXRhdGUocmVnaW9uID0gc3RyX3JlcGxhY2VfYWxsKHN0cmluZyA9IHJlZ2lvbiwgYygiU291dGgiID0gInNvdXRoIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlc3QiID0gIndlc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTm9ydGggQ2VudHJhbCIgPSAibm9ydGhfY2VudHJhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOb3J0aGVhc3QiID0gIm5vcnRoZWFzdCIpKSkgJT4lIA0KICBoZWFkKG4gPSAyMCkNCmBgYA0KDQoNCiMgQ0jGr8agTkcgNDogS+G6v3QgbHXhuq1uDQoNCiMjIEvhur90IGx14bqtbiBsacOqbiBxdWFuIMSR4bq/biBjaOG7pyDEkeG7gQ0KDQojIyMgxq91IMSRaeG7g20NCg0KQ8O6IHBow6FwIGThu4UgxJHhu41jIHbDoCBz4butIGThu6VuZzogU3RyaW5nciBjdW5nIGPhuqVwIG3hu5l0IHThuq1wIGjhu6NwIGPDoWMgaMOgbSBk4buFIMSR4buNYyB2w6AgZOG7hSBz4butIGThu6VuZyBjaG8gY8OhYyB0w6FjIHbhu6UgeOG7rSBsw70gY2h14buXaSBwaOG7lSBiaeG6v24uIEPDuiBwaMOhcCByw7UgcsOgbmcgZ2nDunAgbmfGsOG7nWkgZMO5bmcgbuG6r20gYuG6r3QgbmhhbmggY2jDs25nIGPDoWNoIHPhu60gZOG7pW5nIGPDoWMgaMOgbS4NCg0KLSAgIFTDrWNoIGjhu6NwIHThu5F0IHbhu5tpIGRwbHlyIHbDoCB0aWR5cjogU3RyaW5nciDEkcaw4bujYyBwaMOhdCB0cmnhu4NuIGLhu59pIGPDuW5nIHTDoWMgZ2nhuqMgY+G7p2EgZ8OzaSBkcGx5ciB2w6AgdGlkeXIsIG7Dqm4gbsOzIHTDrWNoIGjhu6NwIHThu5F0IHbhu5tpIG5o4buvbmcgZ8OzaSBuw6B5IMSR4buDIHRo4buxYyBoaeG7h24geOG7rSBsw70gZOG7ryBsaeG7h3UgdG/DoG4gZGnhu4duLCB04burIGzDoG0gc+G6oWNoIGThu68gbGnhu4d1IMSR4bq/biBiaeG6v24gxJHhu5VpIGThu68gbGnhu4d1Lg0KDQotICAgQ3VuZyBj4bqlcCBjw6FjIGjDoG0gbGluaCBob+G6oXQgY2hvIHjhu60gbMO9IGNodeG7l2k6IEfDs2kgU3RyaW5nciBjdW5nIGPhuqVwIGPDoWMgaMOgbSBjaG8gdmnhu4djIGPhuq90IGNodeG7l2ksIHRoYXkgdGjhur8sIHTDoWNoIGNodeG7l2kgdGjDoG5oIGPDoWMgcGjhuqduLCBjaHXhuqluIGjDs2Ega2hv4bqjbmcgdHLhuq9uZywgdsOgIG5oaeG7gXUgdGhhbyB0w6FjIGtow6FjIMSR4buDIHjhu60gbMO9IGNodeG7l2kgZOG7hSBkw6BuZyB2w6AgaGnhu4d1IHF14bqjLg0KDQotICAgSOG7lyB0cuG7oyBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgZOG7hSBoaeG7g3U6IFN0cmluZ3IgY3VuZyBj4bqlcCBjw6FjaCB0aOG7qWMgc+G7rSBk4bulbmcgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IG3hu5l0IGPDoWNoIGThu4UgaGnhu4N1IHbDoCB0cuG7sWMgcXVhbiBoxqFuLiDEkGnhu4F1IG7DoHkgZ2nDunAgbmfGsOG7nWkgZMO5bmcga2jDtG5nIHF1ZW4gdGh14buZYyB24bubaSBiaeG7g3UgdGjhu6ljIGNow61uaCBxdXkgY8WpbmcgY8OzIHRo4buDIHRo4buxYyBoaeG7h24gY8OhYyBwaMOpcCB0b8OhbiBwaOG7qWMgdOG6oXAgdHLDqm4gY2h14buXaS4NCg0KLSAgIFTGsMahbmcgdGjDrWNoIHbhu5tpIGThu68gbGnhu4d1IGThuqFuZyB0aWJibGU6IFN0cmluZ3IgY3VuZyBj4bqlcCBow6BtIHN0cl9kZXRlY3QoKSB2w6Agc3RyX3N1YnNldCgpIGPDsyB0aOG7gyBk4buFIGTDoG5nIHTDrWNoIGjhu6NwIHbDoG8gZOG7ryBsaeG7h3UgZOG6oW5nIHRpYmJsZSBtw6Aga2jDtG5nIGPhuqduIGNodXnhu4NuIMSR4buVaSBxdWEgZOG6oW5nIG1hIHRy4bqtbi4NCg0KLSAgIEhp4buHdSBxdeG6oyBj4bunYSBi4buZIG5o4bubOiBDw6FjIGNodeG7l2kgdGjGsOG7nW5nIMSRxrDhu6NjIGzGsHUgdHLhu68gdHJvbmcgbeG7mXQga2jhu5FpIGLhu5kgbmjhu5sgbGnhu4FuIGvhu4EsIGdpw7pwIHBow6JuIGLhu5UgdsOgIGdp4bqjaSBwaMOzbmcgY2jDum5nIGhp4buHdSBxdeG6oy4gxJBp4buBdSBuw6B5IGPDsyBuZ2jEqWEgbMOgIGNow7puZyBjw7MgdGjhu4MgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgYmnhu4N1IGRp4buFbiBt4buZdCBsxrDhu6NuZyBs4bubbiBk4buvIGxp4buHdSBtw6Aga2jDtG5nIGNoaeG6v20gcXXDoSBuaGnhu4F1IGLhu5kgbmjhu5suDQoNCiMjIyBOaMaw4bujYyDEkWnhu4NtDQoNCiBLaOG6oyBuxINuZyBz4butIGThu6VuZyB0aOG6pXAgY2hvIHjhu60gbMO9IGThu68gbGnhu4d1IGzhu5tuOiBzdHJpbmdyIGPDsyB0aOG7gyB0cuG7nyBuw6puIGNo4bqtbSBraGkgY2jDum5nIMOhcCBk4bulbmcgbsOzIGNobyBjw6FjIHThuq1wIGThu68gbGnhu4d1IGzhu5tuLiBO4bq/dSBj4bqnbiB44butIGzDvSBjaHXhu5dpIHRyb25nIGPDoWMgdOG6rXAgZOG7ryBsaeG7h3UgY8OzIGvDrWNoIHRoxrDhu5tjIGzhu5tuLCBjw7MgdGjhu4MgY+G6p24gcGjhuqNpIHTDrG0gaGnhu4N1IGPDoWMgcGjGsMahbmcgcGjDoXAga2jDoWMgaGnhu4d1IHF14bqjIGjGoW4gxJHhu4MgeOG7rSBsw70gY2h14buXaS4NCg0KLSAgIFBo4bulIHRodeG7mWMgdsOgbyBnw7NpIGRwbHlyIHbDoCB0aWR5cjogc3RyaW5nciB0aMaw4budbmcgxJHGsOG7o2Mgc+G7rSBk4bulbmcgY8O5bmcgduG7m2kgY8OhYyBnw7NpIGtow6FjIG5oxrAgZHBseXIgdsOgIHRpZHlyIMSR4buDIHRo4buxYyBoaeG7h24geOG7rSBsw70gZOG7ryBsaeG7h3UgdG/DoG4gZGnhu4duLiDEkGnhu4F1IG7DoHkgY8OzIHRo4buDIMSRw7RpIGtoaSB04bqhbyByYSBz4buxIHBo4bupYyB04bqhcCB2w6AgxJHDsmkgaOG7j2kgbmfGsOG7nWkgZMO5bmcgcGjhuqNpIGhp4buDdSByw7UgduG7gSBj4bqjIGPDoWMgZ8OzaSBraMOhYy4NCg0KLSAgIFnDqnUgY+G6p3Uga2nhur9uIHRo4bupYyB24buBIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eSAocmVndWxhciBleHByZXNzaW9ucyk6IE3hu5l0IHPhu5EgaMOgbSB0cm9uZyBzdHJpbmdyIHnDqnUgY+G6p3UgbmfGsOG7nWkgZMO5bmcgYmnhur90IHbhu4EgYmnhu4N1IHRo4bupYyBjaMOtbmggcXV5IMSR4buDIHRo4buxYyBoaeG7h24gY8OhYyBwaMOpcCB0b8OhbiBwaOG7qWMgdOG6oXAuIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgxJHhurd0IGtow7Mga2jEg24gY2hvIG5nxrDhu51pIG3hu5tpIGjhu41jIGhv4bq3YyBraMO0bmcgcXVlbiB0aHXhu5ljIHbhu5tpIGJp4buDdSB0aOG7qWMgY2jDrW5oIHF1eS4NCg0KLSAgIEtow7RuZyBob8OgbiB0b8OgbiB0aGF5IHRo4bq/IMSRxrDhu6NjIGPDoWMgaMOgbSBjaHXhu5dpIGPGoSBi4bqjbiB0cm9uZyBSOiBN4bq3YyBkw7kgc3RyaW5nciBjdW5nIGPhuqVwIG5oaeG7gXUgdMOtbmggbsSDbmcgdGnhu4duIMOtY2ggaMahbiBjaG8gdmnhu4djIGzDoG0gdmnhu4djIHbhu5tpIGNodeG7l2kgc28gduG7m2kgY8OhYyBow6BtIGNodeG7l2kgY8ahIGLhuqNuIHRyb25nIFIsIG5oxrBuZyB24bqrbiBjw7Mgbmjhu69uZyB0w6xuaCBodeG7kW5nIG3DoCBjaMO6bmcgdGEgY8OzIHRo4buDIGPhuqduIHBo4bqjaSBz4butIGThu6VuZyBjw6FjIGjDoG0gY8ahIGLhuqNuIG7DoHkuDQoNCi0gICBLaOG6oyBuxINuZyDEkeG7pW5nIMSR4buZIHbhu5tpIGPDoWMgZ8OzaSBraMOhYzogS2hpIGNow7puZyB0YSBz4butIGThu6VuZyBuaGnhu4F1IGfDs2kgdHJvbmcgUiBjw7luZyBt4buZdCBsw7pjLCBjw7MgdGjhu4MgeOG6o3kgcmEgeHVuZyDEkeG7mXQgdMOqbiBow6BtIGhv4bq3YyBiaeG6v24uIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgeOG6o3kgcmEga2hpIHN0cmluZ3Igc+G7rSBk4bulbmcgY8OhYyB0w6puIGjDoG0gdMawxqFuZyB04buxIG5oxrAgY8OhYyBnw7NpIGtow6FjLg0KDQotICAgWcOqdSBj4bqndSBjw6BpIMSR4bq3dCBnw7NpIHBo4bulIHRodeG7mWM6IMSQ4buDIHPhu60gZOG7pW5nIHN0cmluZ3IsIGNow7puZyBj4bqnbiBwaOG6o2kgY8OgaSDEkeG6t3QgY8OhYyBnw7NpIHBo4bulIHRodeG7mWMgbmjGsCBkcGx5ciB2w6AgdGlkeXIuIMSQaeG7gXUgbsOgeSBjw7MgdGjhu4MgxJHDsmkgaOG7j2kgdGjhu51pIGdpYW4gdsOgIHTDoGkgbmd1ecOqbiDEkeG7gyBjw6BpIMSR4bq3dCB2w6AgZHV5IHRyw6wgY8OhYyBnw7NpIG7DoHkuDQoNCi0gICBDaGkgcGjDrSBob+G6oXQgxJHhu5luZzogQ8OhYyB0aGFvIHTDoWMgY2h14buXaSBjw7MgdGjhu4MgY2jhuq1tIGjGoW4gc28gduG7m2kgY8OhYyB0aGFvIHTDoWMgdHLDqm4gY8OhYyBsb+G6oWkgZOG7ryBsaeG7h3Uga2jDoWMsIMSR4bq3YyBiaeG7h3QgbMOgIGtoaSBsw6BtIHZp4buHYyB24bubaSBjw6FjIGNodeG7l2kgbOG7m24gaG/hurdjIHBo4bupYyB04bqhcC4gxJBp4buBdSBuw6B5IGzDoCBkbyBjw6FjIHRoYW8gdMOhYyBjaHXhu5dpIHRoxrDhu51uZyBsacOqbiBxdWFuIMSR4bq/biB2aeG7h2Mgc2FvIGNow6lwIHbDoCBwaMOibiBi4buVIGzhuqFpIGLhu5kgbmjhu5ssIMSRaeG7gXUgbsOgeSBjw7MgdGjhu4MgdOG7kW4gbmhp4buBdSB0aOG7nWkgZ2lhbi4NCg0KS+G6v3QgbHXhuq1uOiBt4bq3YyBkw7kgU3RyaW5nciBjw7Mgbmhp4buBdSDGsHUgxJFp4buDbSB0cm9uZyB2aeG7h2MgbMOgbSB2aeG7h2MgduG7m2kgY2h14buXaSB0cm9uZyBSLCBuaMawbmcgY8WpbmcgY+G6p24gY8OibiBuaOG6r2MgY8OhYyBo4bqhbiBjaOG6vyB2w6AgxJFp4buDbSB54bq/dSBj4bunYSBuw7Mga2hpIGzhu7FhIGNo4buNbiBz4butIGThu6VuZyBnw7NpIG7DoHkuDQoNCiMjIEvhur90IGx14bqtbiBjaG8gcXXDoSB0csOsbmggbMOgbSBjaOG7pyDEkeG7gQ0KDQpUcm9uZyBxdcOhIHRyw6xuaCBsw6BtIHRp4buDdSBsdeG6rW4sIGNow7puZyBlbSBj4bqjbSB0aOG6pXkgcuG6sW5nIGfDs2kgU3RyaW5nciBy4bqldCBo4buvdSDDrWNoLiBWw6wgbsOzIGhp4buDbiB0aOG7iyBt4buZdCB04bqtcCBo4bujcCBuaOG7jyBj4bunYSBjw6FjIGjDoG0gcXVhbiB0cuG7jW5nLCDEkcOjIMSRxrDhu6NjIGzhu7FhIGNo4buNbiBj4bqpbiB0aOG6rW4gxJHhu4MgeOG7rSBsw70gY8OhYyB0aGFvIHTDoWMgcGjhu5UgYmnhur9uIHRyw6puIGNodeG7l2kuIEfDs2kgU3RyaW5nciDEkcaw4bujYyB0aGnhur90IGvhur8gbeG7mXQgY8OhY2ggdG/DoG4gZGnhu4duLCBiYW8gZ+G7k20gaOG6p3UgaOG6v3QgY8OhYyBjaOG7qWMgbsSDbmcgbcOgIGNow7puZyBlbSBj4bqnbiDEkeG7gyBsw6BtIHZp4buHYyB24bubaSBjaHXhu5dpIHbhu5tpIHThu5VuZyBj4buZbmcgNTkgY2jhu6ljIG7Eg25nIHRyb25nIFN0cmluZ3IuDQoNCk5nb8OgaSByYSBnw7NpIFN0cmluZ3IgY8OybiBnacO6cCBjaMO6bmcgZW0gaOG7jWMgdOG6rXAsIHRo4buxYyBow6BuaCB2w6AgcGjDoXQgdHJp4buDbiBr4bu5IG7Eg25nIHjhu60gbMO9IGNodeG7l2kgdHJvbmcgUiBwaMO5IGjhu6NwIHbhu5tpIHRo4budaSDEkeG6oWkgNC4wLiBWaeG7h2Mgc+G7rSBk4bulbmcgZ8OzaSBTdHJpbmdyIHRyb25nIGLDoGkgdGnhu4N1IGx14bqtbiBraMO0bmcgY2jhu4kgZ2nDunAgY2jDum5nIGVtIG7huq9tIHbhu69uZyB2w6Agw6FwIGThu6VuZyBraeG6v24gdGjhu6ljIHbhu4EgeOG7rSBsw70gY2h14buXaSB0cm9uZyBSIG3DoCBjw7JuIHBow6F0IHRyaeG7g24ga+G7uSBuxINuZyBwaMO5IGjhu6NwIHbhu5tpIHRo4budaSDEkeG6oWkgNC4wIG5oxrAga+G7uSBuxINuZyB44bunIGzDvSBk4buvIGxp4buHdSwgZ2nhuqNpIHF1eeG6v3QgduG6pW4gxJHhu4EgY+G7pSB0aOG7gywgcGjDom4gdMOtY2ggdsOgIHRyw6xuaCBiw6B5IGvhur90IHF14bqjIG3hu5l0IGPDoWNoIGPhuqluIHRo4bqtbiB2w6AgbsOibmcgY2FvIGvhu7kgbsSDbmcgbOG6rXAgdHLDrG5oIHRyb25nIHF1w6EgdHLDrG5oIGjhu41jIHThuq1wLCBjw7RuZyB2aeG7h2MgdHJvbmcgdMawxqFuZyBsYWkNCg0KDQo=