1 CHƯƠNG 1: GIỚI THIỆU ĐỀ TÀI

1.1 Đặt vấn đề nghiên cứu

Hiện nay, nhiều lĩnh vực đã áp dụng phân tích dữ liệu vào trong quá trình nghiên cứu để có thể đạt được kết quả tốt hơn và độ chính xác cao hơn. Tuy nhiên, dữ liệu được thu thập thường rất lớn, phức tạp, cấu trúc không phù hợp hoặc có thể bị thiếu dữ liệu cho nên không thể nào đưa vào mô hình phân tích ngay lập tức. Do đó, các nhà nghiên cứu cần phải xử lí và biến đổi cấu trúc dữ liệu sao cho phù hợp với mục tiêu nghiên cứu, có thể nói đây chính là một phần khá phức tạp và mất nhiều thời gian trong một công trình nghiên cứu bởi vì bộ dữ liệu quá lớn và chứa nhiều biến khác nhau chưa đáp ứng được nhu cầu của người sử dụng. Chính vì thế, họ luôn tìm kiếm cho mình một công cụ tối ưu để dễ dàng chuẩn hóa và làm sạch dữ liệu đồng thời tiết kiệm thời gian, công sức mà vẫn đạt hiệu quả cao.

Nhận thấy vấn đề được nói trên chúng em thực hiện nghiên cứu về gói “Tidyr”, đây là một công cụ mãnh mẽ hỗ trợ mọi người có thể chuẩn hóa, biến đổi cấu trúc dữ liệu dựa vào định dạng tidy data, trong đó thì mỗi cột dữ liệu đại diện cho một biến, mỗi hàng đại diện cho một quan sát và mỗi ô thì chứa một giá trị cụ thể điều này sẽ giúp việc phân tích và trực quan hóa dữ liệu trở nên dễ dàng hơn. Hơn thế, nó cũng có thể hỗ trợ tách, ghép và hoàn chỉnh dữ liệu còn thiếu bằng những cú pháp đơn giản, rõ ràng từ đó mọi người có thể tiến hành phân tích các mô hình. Gói Tidyr là một công cụ tối ưu, đa năng, cú pháp đơn giản và nhận được sử hỗ trợ phát triển từ cộng đồng R, vì thế nó có thể giải quyết nhiều vấn đề trong quá trình xử lý dữ liệu trong nhiều lĩnh vực. Chẳng hạn như trong tài chính gói tidyr có thể giúp chúng ta tổ chức và sắp xếp lại dữ liệu về cổ phiểu của một ngành để đánh giá tình hình hoạt động và xây dựng mô hình dự báo. Trong lĩnh vực kinh tế thì nó giúp biến đổi dữ liệu về GDP, thương mại, sản xuất và một số chỉ số kinh tế khác của các quốc gia theo năm để đánh giá tốc độ phát triển và tổng quan về mối quan hệ kinh tế giữa các quốc gia. Qua đó, ta thấy rằng lợi ích mà gói Tidyr mang lại trong giai đoạn chuẩn hóa dữ liệu là vô cùng to lớn, tiết kiệm được rất nhiều thời gian và cung cấp kết quả phân tích có độ chính xác cao hơn.

1.2 Lý do chọn đề tài

Trong quá trình thực hành với nhiều dữ liệu phức tạp nhóm em nhận thấy việc xử lý dữ liệu gặp nhiều khó khăn, ảnh hưởng đến kết quả cũng như là thời gian thực hiện. Nghiên cứu về gói Tidyr sẽ giúp việc chuẩn hóa và biến đổi cấu trúc dữ liệu trở nên dễ dàng hơn, các cú pháp tương đối đơn giản và rõ ràng không đòi hỏi kiến thức chuyên sâu. Ngoài ra, Tidyr cung cấp cho người sử dụng rất nhiều chức năng khác nhau, nó giúp người dùng dễ dàng xử lý dữ liệu không đồng nhất, không cấu trúc hoặc thiếu dữ liệu, tạo điều kiện thuận lợi cho việc phân tích và trực quan hóa dữ liệu. Cộng đồng R là một cộng đồng lớn về ngôn ngữ lập trình, họ thường xuyên cập nhập, phát triển gói Tidyr ngày càng tối ưu hơn, điều này khiến cho nhóm em học tập thêm nhiều kiến thức về phân tích dữ liệu và sử dụng gói này một cách hiệu quả nhất trong công việc trong tương lai. Hơn thế, Tidyr được thiết kế dùng để giải quyết các vấn đề phổ biến và thực tế ở nhiều lĩnh vực khác nhau, mặc dù dữ liệu nghiên cứu kích thước lớn thì nó vẫn xử lý hiệu quả và tiết kiệm được nhiều thời gian. Vì thế, nhóm em tin rằng tìm hiểu về gói Tidyr là chủ đề hữu ích có thể hỗ trợ mọi người đang gặp khó khăn trong việc xử lý dữ liệu.

1.3 Giới thiệu về gói Tidyr

1.3.1 Nguồn gốc

Gói tidyr là một phần của Tidyverse, một bộ sưu tập các gói R được thiết kế cho việc xử lý và phân tích dữ liệu. Gói tidyr tập trung chủ yếu vào các hoạt động làm gọn gàng và cấu trúc lại dữ liệu, giúp dễ dàng chuyển đổi tập dữ liệu thành định dạng tidy (gọn gàng) thuận tiện hơn cho phân tích và trực quan hóa.

Gói tidyr được phát triển bởi Hadley Wickham, một nhà thống kê và nhà khoa học dữ liệu nổi tiếng với đóng góp cho ngôn ngữ lập trình R và khái niệm dữ liệu tidy. Hadley Wickham cũng là người sáng tạo ra các gói phổ biến khác như ggplot2 và dplyr. Ông đã phát triển tidyr như một phần của nỗ lực của mình để thúc đẩy nguyên tắc của dữ liệu tidy, nhấn mạnh việc tổ chức và sắp xếp dữ liệu theo một cấu trúc nhất quán để tạo thuận lợi cho phân tích và truyền tải thông tin.

1.3.2 Chức năng

Gói tidyr cung cấp một loạt các hàm hỗ trợ chúng ta trong việc làm gọn và tái cấu trúc dữ liệu. Các hàm này có thể được nhóm thành một số danh mục chính, mỗi danh mục phục vụ cho một mục đích cụ thể trong việc chỉnh sửa và tổ chức dữ liệu.

1.3.2.1 Tách dữ liệu

Trong gói tidyr hỗ trợ người dùng tách dữ liệu một cột thành nhiều cột dựa trên những ký tự phân tách hoặc các mẫu bằng hàm separate, điều này thực sự hữu ích khi bạn có một cột chứa các giá trị kết hợp với nhau làm cho việc phân tích gặp nhiều khó khăn và bạn muốn phân tách nó ra thành những cột riêng biệt. Chẳng hạn, một cột chứa thông tin về ngày tháng năm sinh để biết chi tiết hơn ta có thể sử dụng hàm separate để tách riêng làm ba cột ngày, tháng, năm để phục vụ cho mục đích công việc cụ thể. Ngoài ra, chức năng này không làm thay đổi dữ liệu gốc mà chỉ tạo ra các cột mới từ dữ liệu ban đầu, điều này cho phép chúng ta biến đổi về dữ liệu gốc dễ dàng hơn nếu muốn.

1.3.2.2 Kết hợp cột

Trái ngược với chức năng tách cột, gói Tidyr sẽ giúp chúng ta kết hợp các cột lại thành một cột bằng cách ghép các giá trị của chúng lại với nhau. Giả sử ta có một cột chứa họ và một cột chứa tên thì có thể ghép hai cột này thành một cột họ và tên hoàn chỉnh bằng hàm unite, điều này sẽ giúp dữ liệu trở nên gọn gàng và phù hợp để sử dụng. Đây là một chức năng dễ dàng sử dụng tuy nhiên tạo ra cột mới có độ linh hoạt cao, thuận tiện trong quá trình xử lý.

1.3.2.3 Pivoting(Biến đổi)

  • “Pivoting” (Chuyển đổi): chuyển đổi giữa các dạng dữ liệu rộng và dài. tidyr giới thiệu pivot_longer() và pivot_wider(), thay thế các hàm spread() và gather(). Quá trình biến đổi này đặc biệt hữu ích khi bạn cần thay đổi cấu trúc dữ liệu để phù hợp hơn với mục đích phân tích hoặc trực quan hóa.

  • Biến đổi từ dạng Dài sang Rộng: Khi dữ liệu ở định dạng dài, mỗi quan sát được biểu diễn bằng nhiều hàng và có các cột xác định riêng biệt liên kết những hàng này lại với nhau. Do đó, hàm pivot_wider() sẽ giúp ta chuyển đổi dữ liệu từ định dạng dài sang định dạng rộng bằng cách phân rải giá trị, điều này phụ thuộc vào mục tiêu phân tích bộ dữ liệu của người sử dụng.

  • Biến đổi từ dạng Rộng sang Dài: Ngược lại, khi dữ liệu ở định dạng rộng, mỗi quan sát được biểu diễn bằng một hàng đơn và các biến khác nhau được lưu trữ trong các cột riêng biệt. Hàm pivot_longer() sẽ giúp Chuyển đổi dữ liệu từ định dạng rộng sang định dạng dài bằng cách gom lại các cột để có thể phù hợp với nhu cầu của người thực hiện.

1.3.2.4 Xử lí giá trị thiếu

Việc phân tích dữ liệu sẽ không đạt được kết quả chính xác nếu dữ liệu gặp phải những giá trị bị thiếu sót, để khắc phục tình trạng như vậy thì gói này giúp người sử dụng xử lý những dòng bị thiếu giá trị bằng hàm complete, hàm này sẽ kết hợp các giá trị không bị thiếu trong các cột chỉ định từ đó điền vào những dòng bị thiếu. Hơn nữa, ta có thể loại bỏ các giá trị thiếu bằng hàm drop_na hoặc thay thế các giá trị bị thiếu bằng hàm fill, replace_na.

1.3.2.5 Nesting(Gộp) và Unnesting(khôi phục)

Nest() được sử dụng để tạo một khung dữ liệu lồng nhau bằng cách nhóm dữ liệu dựa trên các biến cụ thể. Nó cho phép bạn nhóm các quan sát liên quan với nhau trong một cột duy nhất.

Unnest() được sử dụng để mở rộng một khung dữ liệu lồng nhau thành một khung dữ liệu thông thường, trong đó mỗi quan sát lồng nhau trở thành một dòng riêng. Nó trích xuất dữ liệu lồng nhau và mở rộng chúng thành nhiều dòng.

1.3.3 Mục tiêu

Mục tiêu chính của tidyr là cung cấp một bộ công cụ với các chức năng đơn giản hóa quá trình cấu trúc lại và làm gọn dữ liệu. Gói này cung cấp các chức năng như gather(), spread(), separate(), unite(), pivot_longer() và pivot_wider(), cho phép người dùng chuyển đổi dữ liệu giữa các định dạng rộng và dài, phân tách và kết hợp cột, và chuyển đổi dữ liệu để tạo bảng tóm tắt. Các hoạt động này là cần thiết để tổ chức và xử lý dữ liệu một cách dễ dàng và trích xuất thông tin.

Gói tidyr đã thu hút sự quan tâm đáng kể trong cộng đồng R nhờ cú pháp dễ hiểu và nhất quán, phù hợp với nguyên tắc của Tidyverse. Nó đã trở thành một công cụ được sử dụng rộng rãi để làm sạch dữ liệu, tiền xử lý và cấu trúc lại trong quy trình phân tích dữ liệu bằng R.

1.3.4 Lợi ích

Các lợi ích của việc sử dụng gói tidyr bao gồm:

  • Dễ dàng làm sạch dữ liệu: Gói tidyr cung cấp các hàm đơn giản và dễ hiểu để cấu trúc lại và làm gọn dữ liệu. Nó cung cấp các chức năng như gather(), spread(), separate(), unite(), pivot_longer(), và pivot_wider() cho phép người dùng dễ dàng chuyển đổi dữ liệu giữa các định dạng rộng và dài, phân tách và kết hợp cột, và biến đổi dữ liệu để tạo bảng tóm tắt. Những thao tác này là cần thiết để tổ chức và xử lý dữ liệu một cách hiệu quả.

  • Tích hợp với tidyverse: Gói tidyr là một phần của hệ sinh thái tidyverse, là một bộ sưu tập các gói R được thiết kế cho việc làm sạch và phân tích dữ liệu. Nó tích hợp một cách mượt mà với các gói tidyverse khác như dplyr và ggplot2, cho phép quy trình làm việc mượt mà và cú pháp nhất quán. Tích hợp này cho phép người dùng thực hiện các thao tác phức tạp trên dữ liệu và tạo biểu đồ một cách nhất quán và hiệu quả.

  • Tương thích với nguyên tắc dữ liệu tidy: Gói tidyr tuân thủ nguyên tắc của dữ liệu tidy, nhấn mạnh việc tổ chức dữ liệu theo một cấu trúc nhất quán. Bằng cách tuân thủ nguyên tắc dữ liệu tidy, người dùng có được dữ liệu rõ ràng hơn, dễ khám phá hơn và kết quả phân tích đáng tin cậy hơn. Dữ liệu tidy đảm bảo mỗi biến có một cột riêng, mỗi quan sát có một hàng riêng và mỗi ô chứa một giá trị duy nhất.

  • Hỗ trợ phân tích và trực quan hóa dữ liệu: Dữ liệu tidy đơn giản hóa quá trình phân tích và trực quan hóa dữ liệu. Bằng cách chuyển đổi dữ liệu thành định dạng tidy, việc thực hiện các tác vụ phân tích dữ liệu thông thường, áp dụng phân tích thống kê và tạo biểu đồ thông tin trở nên dễ dàng hơn. Dữ liệu tidy giảm thiểu việc phải làm việc phức tạp với dữ liệu, cho phép các nhà phân tích tập trung nhiều hơn vào việc trích xuất thông tin và đưa ra quyết định dựa trên dữ liệu.

Tóm lại, mục tiêu chính của gói tidyr là cung cấp các công cụ để làm sạch và cấu trúc lại dữ liệu, với lợi ích là giúp người dùng dễ dàng chuyển đổi dữ liệu thành định dạng tidy. Điều này hỗ trợ phân tích dữ liệu, tích hợp với các gói tidyverse khác và hỗ trợ nguyên tắc dữ liệu tidy để hiểu dữ liệu tốt hơn và tạo quy trình làm việc hiệu quả

1.3.5 Ưu và nhược điểm của gói tidyr

1.3.5.1 Ưu điểm của gói tidyr

Đơn giản hóa việc xử lý dữ liệu: tidyr cung cấp một bộ công cụ với các hàm dễ hiểu giúp đơn giản hóa công việc cấu trúc lại và làm sạch dữ liệu. Nó cung cấp các hàm như gather(), spread(), separate(), unite(), pivot_longer() và pivot_wider() cho phép người dùng dễ dàng chuyển đổi dữ liệu giữa các định dạng rộng và dài, phân tách và kết hợp cột, và biến đổi dữ liệu để tạo bảng tóm tắt. Những hoạt động này là cần thiết để tổ chức và xử lý dữ liệu một cách hiệu quả.

Tích hợp với tidyverse: tidyr là một phần của hệ sinh thái tidyverse, một bộ sưu tập các gói R được thiết kế để làm sạch và phân tích dữ liệu. Nó tích hợp một cách mượt mà với các gói tidyverse khác như dplyr và ggplot2, cho phép quy trình làm việc trơn tru và có cú pháp nhất quán. Tích hợp này cho phép người dùng thực hiện các phép toán phức tạp trên dữ liệu và tạo biểu đồ một cách nhất quán và hiệu quả.

Tuân thủ nguyên tắc dữ liệu tidy: tidyr tuân thủ các nguyên tắc của dữ liệu tidy, nhấn mạnh việc tổ chức dữ liệu thành một cấu trúc nhất quán. Bằng việc tuân thủ nguyên tắc dữ liệu tidy, người dùng có dữ liệu rõ ràng hơn, khám phá dữ liệu hiệu quả hơn và kết quả phân tích đáng tin cậy hơn. Dữ liệu tidy đảm bảo rằng mỗi biến có một cột riêng, mỗi quan sát có một hàng riêng, và mỗi ô chứa một giá trị duy nhất.

1.3.5.2 Nhược điểm của gói tidyr

Giới hạn chức năng: Mặc dù tidyr cung cấp một tập hợp hữu ích các hàm để cấu trúc lại và làm sạch dữ liệu, nhưng nó có thể không đáp ứng được tất cả các tình huống xử lý dữ liệu khác nhau. Có thể có những trường hợp yêu cầu các phép toán phức tạp hoặc đặc thù hơn và tidyr có thể không có các hàm dành riêng cho những nhiệm vụ đó.

Khó khăn trong quá trình học tập: Giống như bất kỳ gói hay công cụ mới nào, việc sử dụng tidyr một cách hiệu quả cũng có thể gặp khó khăn ban đầu. Người dùng cần làm quen với cú pháp và các hàm cụ thể của tidyr để tận dụng tối đa khả năng của nó. Quá trình học này có thể yêu cầu một khoảng thời gian và nỗ lực nhất định.

Phụ thuộc vào tidyverse: Mặc dù việc là một phần của tidyverse mang lại nhiều lợi ích, nhưng đồng thời cũng có thể là một hạn chế đối với những người dùng ưa thích hoặc phụ thuộc vào các gói xử lý dữ liệu khác nằm ngoài hệ sinh thái tidyverse. Sử dụng tidyr trong quy trình làm việc dựa trên tidyverse có thể yêu cầu sự chuyển đổi sang các gói tidyverse khác, điều này có thể không phù hợp với mọi người.

1.4 Đóng góp của đề tài

Bài tiểu luận của nhóm em đóng góp cho cộng đồng sử dụng R trong việc áp dụng gói Tidyr vào việc phân tích dữ liệu ở một số khía cạnh quan trọng.

Đầu tiên, chúng em đã giới thiệu chi tiết về gói Tidyr, bao gồm các chức năng, lợi ích, phương pháp và cách thức thực hiện các hàm quan trọng trong gói Tidyr, điều này giúp cho mọi người có cái nhìn tổng quan nhất về nó.

Thứ hai, chúng em áp dụng vào việc phân tích dữ liệu tài chính qua đó làm nổi bật tính ứng dụng của Tidyr trong các lĩnh vực, cũng như nhấn mạnh sự tiện ích và hiệu quả của nó trong việc giúp người dùng tiết kiệm thời gian và nỗ lực trong công việc xử lý dữ liệu.

Cuối cùng, nhóm phân tích được tiềm năng và hạn chế của Tidyr, qua đó giúp cho những người phân tích dữ liệu sử dụng hiệu quả nhất gói này vào trong công việc của họ.

1.5 Kết cấu

Chương 1: Giới thiệu đề tài

Giới thiệu tổng quan về tầm quan trọng của việc thực hiện đề tài nghiên cứu gói tidyr trong R, đưa ra những lý do để chọn chủ đề này và nêu những nội dung quan trọng của gói tidyr.

Chương 2: Thực hành các hàm trong tidyr

Chương hai sẽ trình bày cụ thể chức năng các hàm trong gói tidyr và đưa ra những ví dụ cụ thể để hướng dẫn thực hành.

Chương 3: Ứng dụng của tidyr

Dựa vào các chức năng của các hàm được trình bày trong chương 2 sau đó được áp dụng lên những dữ liệu lớn hơn và có cấu trúc khó hơn bằng cách kết hợp thêm một số gói khác như dplyr. Sau khi chuẩn hóa dữ liệu thì thực hiện tính thóa và trực quan hóa dữ liệu

Chương 4: Kết luận

Chương cuối sẽ kết luận những kết quả thu được trong bài này, đưa ra những hạn chế trong quá trình nghiên cứu và đề xuất phương hướng làm tiếp theo.

2 CHƯƠNG 2: THỰC HÀNH CÁC HÀM TRONG TIDYR

Trong chương hai nhóm chúng tôi thực hiện các lệnh trong gói Tidyr để giúp người đọc có thể hiểu rõ các chức năng trong gói này. Từ đó, những người quan tâm đến gói Tidyr áp dụng các hàm vào công việc xử lí bộ dữ liệu của họ nhanh chóng hơn. Việc giới thiệu chi tiết về sử dụng gói Tidyr thông qua việc thực hành trên dữ liệu mẫu là nền tảng quan trọng để nhóm chúng tôi có thể ứng dụng Tidyr ở các phần sau

2.1 Biến đổi dữ liệu (Pivoting)

2.1.1 Chuyển dữ liệu sang dạng dài

Hàm pivot_longer hỗ trợ chúng ta chuyển đổi dữ liệu từ dạng rộng (wide format) sang dạng dài (long format). Việc biến đổi cấu trúc dữ liệu có ý nghĩa khi người phân tích muốn xử lý trên dữ liệu dạng dài để có thể thao tác dễ dàng và đạt nhiều hiệu quả hơn dạng rộng.

Chức năng pivot_longer() có một số tham số quan trọng như sau:

  • data: Tham số này yêu cầu dữ liệu mà chúng ta muốn chuyển đổi từ dạng rộng sang dạng dài.

  • cols: tham số này là danh sách các cột mà ta muốn chuyển đổi. Ta có thể chỉ định tên cột cụ thể trong data hoặc sử dụng các hàm để lựa chọn các cột theo những tiêu chí mà chúng ta muốn

  • names_to: Tên của cột mới sẽ lưu trữ các tên biến sau khi chuyển đổi sang dạng dữ liệu dài.

  • values_to: Tên của cột mới mà sẽ chứa các giá trị biến sau khi chuyển đổi.

Trước khi thực hành hàm pivot_longer tôi sẽ gọi một dữ liệu mẫu trong gói Tidyr đó chính là table4b, dữ liệu này gồm dân số của 3 quốc gia Afghanistan, Brazil, China trong hai năm 1999,2000.

library(tidyr)
library(tidyverse)
table4b
## # A tibble: 3 × 3
##   country         `1999`     `2000`
##   <chr>            <dbl>      <dbl>
## 1 Afghanistan   19987071   20595360
## 2 Brazil       172006362  174504898
## 3 China       1272915272 1280428583

Từ table4b với mục đích biến đổi các năm về cùng một cột và giá trị về một cột chung với nhau, ta có thể thực hiện lệnh pivot_longer với dữ liệu ban đầu muốn chuyển đổi sang dạng dài là table4b, tham số ‘cols’ chỉ định các cột muốn chuyển đổi là cột từ “1999” đến “2000”, tham số names_to được sử dụng để đặt tên cột mới chứa các biến với là “year” và tham số values_to đặt tên cho cột chứa các giá trị biến tương ứng là values.

pivot_longer(table4b,cols= '1999':'2000',
                         names_to = "year",
                         values_to = "values")
## # A tibble: 6 × 3
##   country     year      values
##   <chr>       <chr>      <dbl>
## 1 Afghanistan 1999    19987071
## 2 Afghanistan 2000    20595360
## 3 Brazil      1999   172006362
## 4 Brazil      2000   174504898
## 5 China       1999  1272915272
## 6 China       2000  1280428583

Như kết quả sau khi chuyển đổi bên trên ta sẽ có được một dữ liệu dạng dài với mỗi dòng cho biết về tên quốc gia, năm khảo sát và dân số tương ứng.

2.1.2 Chuyển dữ liệu sang dạng rộng

Hàm pivot_wider có chức năng biến đổi dạng dữ liệu dài sang dữ liệu rộng sao cho phù hợp với mục tiêu của người sử dụng. Hàm này có thao tác khá đơn giản tuy nhiên mang lại rất nhiều lợi ích trong quá trình làm việc của mọi người. Pivot_wider có các tham số chính như sau:

  • data: Dữ liệu dùng để chuyển sang dữ liệu dạng rộng

  • names_from: Tên cột hoặc biến mà ta muốn biến đổi thành các cột mới.

  • values_from: Tên cột hoặc biến chứa các giá trị tương ứng với các cột mới.

Dữ liệu được sử dụng để thực hiện hàm pivot_wider là table2, đây là dữ liệu mẫu trong gói Tidyr chứa thông tin về quốc gia, năm, loại số liệu về dân số, trường hợp mắc bệnh và số người tương ứng.

table2
## # A tibble: 12 × 4
##    country      year type            count
##    <chr>       <dbl> <chr>           <dbl>
##  1 Afghanistan  1999 cases             745
##  2 Afghanistan  1999 population   19987071
##  3 Afghanistan  2000 cases            2666
##  4 Afghanistan  2000 population   20595360
##  5 Brazil       1999 cases           37737
##  6 Brazil       1999 population  172006362
##  7 Brazil       2000 cases           80488
##  8 Brazil       2000 population  174504898
##  9 China        1999 cases          212258
## 10 China        1999 population 1272915272
## 11 China        2000 cases          213766
## 12 China        2000 population 1280428583

Đầu tiên, ta cần khai báo dữ liệu dùng để chuyển đổi là table2, phép toán tử giúp truyền kết quả của table2 phía trước thành đối tượng đầu vào của hàm pivot_wider. Tham số names_from trong trường hợp này được khai báo là type để chỉ ra tên cột dùng để biến đổi thành các cột mới trong dữ liệu rộng, mỗi giá trị trong biến type sẽ là một cột mới. values_from được chỉ định là biến count để chỉ ra các giá trị tương ứng với các cột mới

table2 %>% pivot_wider(names_from = type, values_from = count)
## # A tibble: 6 × 4
##   country      year  cases population
##   <chr>       <dbl>  <dbl>      <dbl>
## 1 Afghanistan  1999    745   19987071
## 2 Afghanistan  2000   2666   20595360
## 3 Brazil       1999  37737  172006362
## 4 Brazil       2000  80488  174504898
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

Chuyển đổi cấu trúc dữ liệu table2 sang dạng dữ liệu rộng giúp ta dễ dàng đánh giá các trường hợp mắc bệnh và dân số của các quốc gia qua từng năm. Ngoài ra, việc chuyển đổi cấu trúc cũng giúp thực hiện phân tích theo từng biến và trực quan hóa dữ liệu tốt hơn.

2.2 Tách cột

Chức năng tách một cột thành nhiều cột dựa trên những ký tự phân tách sẽ là một công cụ tốt để chúng ta có thể xử lý dữ liệu của mình khi mà một cột chứa nhiều giá trị kết hợp với nhau. Việc phân tách cột không yêu cầu nhiều thao tác nhưng vẫn đảm bảo được độ chính xác so với dữ liệu ban đầu, thao tác này có thể được coi là một trong những bước xử lý chuỗi phức tạp. Dữ liệu sau khi được tách cột sẽ đem lại thông tin chi tiết hơn để có thể phân tích, so sánh, trực quan hóa dữ liệu. Trong Tidyr để tách cột thì ta dùng hàm separate() với những tham số chính cần phải lưu ý như

  • data: Dữ liệu ban đầu.

  • col: Tên cột cần tách.

  • into: Tên các cột mới được tạo ra sau khi tách.

  • sep: Ký tự phân tách hoặc mẫu được sử dụng để tách cột.

  • remove: Xác định xem cột ban đầu cần được loại bỏ sau khi tách hay không, mặc định là TRUE.

  • convert: Xác định xem các cột mới cần được chuyển đổi thành kiểu dữ liệu phù hợp hay không, mặc định là FALSE.

Dữ liệu đầu vào dùng để tách cột là table3, dữ liệu này có cột rate dùng ký tự / để tính tỷ lệ người mắc bệnh trên dân số của một quốc gia. Ta có thể dùng hàm separate() để tách cột rate thành một cột chứa số liệu về số người mắc bệnh và một cột chứa số liệu về dân số.

table3
## # A tibble: 6 × 3
##   country      year rate             
##   <chr>       <dbl> <chr>            
## 1 Afghanistan  1999 745/19987071     
## 2 Afghanistan  2000 2666/20595360    
## 3 Brazil       1999 37737/172006362  
## 4 Brazil       2000 80488/174504898  
## 5 China        1999 212258/1272915272
## 6 China        2000 213766/1280428583

Để thực hiện việc tách cột trước tiên chúng ta cần khai báo dữ liệu đầu vào là table3, chọn cột cần tách trong tham số col là cột rate, ở tham số into ta có thể đặt tên cho các cột mới là “case” và “population”, tiếp theo sep chỉ ra ký tự dùng để phân tách trong dữ liệu của chúng ta đó là “/”.

separate(data = table3, col= rate, into= c("case","population"),sep = "/")
## # A tibble: 6 × 4
##   country      year case   population
##   <chr>       <dbl> <chr>  <chr>     
## 1 Afghanistan  1999 745    19987071  
## 2 Afghanistan  2000 2666   20595360  
## 3 Brazil       1999 37737  172006362 
## 4 Brazil       2000 80488  174504898 
## 5 China        1999 212258 1272915272
## 6 China        2000 213766 1280428583

Kết quả từ câu lệnh trên sẽ tạo ra hai cột mới là case và population dựa vào cột rate ban đầu. Điều này sẽ giúp ta quan sát được số trường hợp mắc bệnh và dân số của một quốc gia một cách chi tiết hơn và sau đó có thể dễ dàng dùng nó trong các công việc khác.

separate(data = table3 , col = rate, into = c("case", "population"), remove = FALSE, convert = TRUE )
## # A tibble: 6 × 5
##   country      year rate                case population
##   <chr>       <dbl> <chr>              <int>      <int>
## 1 Afghanistan  1999 745/19987071         745   19987071
## 2 Afghanistan  2000 2666/20595360       2666   20595360
## 3 Brazil       1999 37737/172006362    37737  172006362
## 4 Brazil       2000 80488/174504898    80488  174504898
## 5 China        1999 212258/1272915272 212258 1272915272
## 6 China        2000 213766/1280428583 213766 1280428583

Ngoài ra, ta có thể thêm vào tham số remove là FALSE để giữ nguyên cột rate ban đầu và tham số convert bằng TRUE để xác định chuyển đổi thành kiểu dữ liệu phù hợp

2.3 Kết hợp cột

Ở bước làm sạch dữ liệu, chúng ta thường xuyên gặp phải các cột dữ liệu được tách ra riêng biệt và khi kết hợp chúng lại với nhau thì có thể được một cột dữ liệu hoàn chỉnh và gọn gàng hơn trước rất nhiều. Gói Tidyr bao gồm hàm unite() có thể dùng để kết hợp nhiều cột thành một cột bằng cách ghép các giá trị của chúng lại với nhau. Cấu trúc của dữ liệu sau khi biến đổi sẽ trở nên đơn giản, ít cột và mang ý nghĩa tổng quan hơn so với dữ liệu ban đầu. Những tham số chính trong hàm unite() được giải thích dưới đây:

  • data: Khung dữ liệu

  • col : Tên của cột mới được tạo, tên của các cột được hợp nhất sắp xếp theo trật tự

  • sep: Dấu phân cách giữa hai giá trị

  • remove: Nếu là TRUE sẽ xóa bỏ các cột dữ liệu ban đầu sau khi gộp lại thành cột mới

  • na.rm: Nếu là TRUE thì sẽ loại bỏ các giá trị bị thiếu trước khi kết hợp

Bảng dữ liệu table5 bên dưới có hai cột riêng biệt chứa giá trị về thế kỉ và năm, chúng ta kết hợp hai cột này thành một để có được số liệu năm hoàn chỉnh.

table5
## # A tibble: 6 × 4
##   country     century year  rate             
##   <chr>       <chr>   <chr> <chr>            
## 1 Afghanistan 19      99    745/19987071     
## 2 Afghanistan 20      00    2666/20595360    
## 3 Brazil      19      99    37737/172006362  
## 4 Brazil      20      00    80488/174504898  
## 5 China       19      99    212258/1272915272
## 6 China       20      00    213766/1280428583

Trong hàm unite() khung dữ liệu được khai báo là table5, tên của cột mới sau khi kết hợp lại được đặt là “newyear” và các cột dùng để ghép lại được chỉ định lần lượt là cột century, year. Đối số sep yêu cầu dấu phân cách sau khi ghép các giá trị lại, trong trường hợp này tôi sử dụng “” là không có khoảng cách sau khi kết hợp hai dữ liệu. remove cho bằng FALSE là sẽ không loại bỏ các cột ban đầu sau khi kết hợp cột.

unite(data = table5, col= newyear , century , year, sep="",remove = FALSE)
## # A tibble: 6 × 5
##   country     newyear century year  rate             
##   <chr>       <chr>   <chr>   <chr> <chr>            
## 1 Afghanistan 1999    19      99    745/19987071     
## 2 Afghanistan 2000    20      00    2666/20595360    
## 3 Brazil      1999    19      99    37737/172006362  
## 4 Brazil      2000    20      00    80488/174504898  
## 5 China       1999    19      99    212258/1272915272
## 6 China       2000    20      00    213766/1280428583

Sau khi kết hợp century và year ta được cột mới tên là newyear chứa các giá trị năm được ghép từ các giá trị trong hai cột trước đó. Từ đó, ta có thể sử dụng cột mới được tạo ra để làm các thao tác khác, chẳng hạn như vẽ đồ thị hay dùng để tính toán dựa vào từng năm.

2.4 Nest

Lệnh nest() không phải là một lệnh tích hợp trong R. Tuy nhiên, trong gói tidyr, có hàm nest() cho phép chúng ta tạo một cột mới trong một dataframe và lồng dữ liệu thành các danh sách dựa trên một hoặc nhiều biến. Các tham số chính trong hàm nest() được trình bày dưới đây

  • .data: Đối số này là dữ liệu gốc mà bạn muốn tạo khung dữ liệu lồng nhau từ đó

  • …: Đây là một đối số kiểu tidy-select, cho phép chọn các cột mà ta muốn lồng vào các khung dữ liệu con

  • .by: Đối số này cho phép chọn các cột dùng để nhóm dữ liệu

  • .key: là một đối số cho phép bạn chỉ định tên cho cột danh sách được tạo ra sau khi lồng dữ liệu. Nếu không chỉ định tên cho tham số này thì tên mặc định sẽ là “data”

Dưới đây là một ví dụ về dữ liệu của một bộ phận đang nghiên cứu về tình hình thời tiết trong các thành phố khác nhau. Chúng ta có một dataframe chứa thông tin về tên thành phố, ngày và giờ, nhiệt độ và độ ẩm.

# Tạo dataframe chứa dữ liệu về thời tiết
data <- data.frame(
  ThanhPho = c("Hanoi", "Hanoi", "Hanoi", "HoChiMinh", "HoChiMinh", "HoChiMinh"),
  Ngay = c("2023-01-01", "2023-01-02", "2023-01-03", "2023-01-01", "2023-01-02", "2023-01-03"),
  Gio = c("12:00", "12:00", "12:00", "12:00", "12:00", "12:00"),
  NhietDo = c(20.5, 22.3, 21.8, 30.2, 31.5, 30.9),
  DoAm = c(60, 65, 62, 70, 68, 72)
)
print(data)
##    ThanhPho       Ngay   Gio NhietDo DoAm
## 1     Hanoi 2023-01-01 12:00    20.5   60
## 2     Hanoi 2023-01-02 12:00    22.3   65
## 3     Hanoi 2023-01-03 12:00    21.8   62
## 4 HoChiMinh 2023-01-01 12:00    30.2   70
## 5 HoChiMinh 2023-01-02 12:00    31.5   68
## 6 HoChiMinh 2023-01-03 12:00    30.9   72
# Lồng dữ liệu thành danh sách theo tên thành phố 
nested_data <- data %>%group_by(ThanhPho) %>% nest()

# Lồng dữ liệu bằng .by 
nested_data <- nest(data, .by = ThanhPho, .key = "DuLieu")

# In dữ liệu lồng
print(nested_data)
## # A tibble: 2 × 2
##   ThanhPho  DuLieu          
##   <chr>     <list>          
## 1 Hanoi     <tibble [3 × 4]>
## 2 HoChiMinh <tibble [3 × 4]>
nested_data$DuLieu <- lapply(nested_data$DuLieu, as.data.frame)
lapply(nested_data$DuLieu, print)
##         Ngay   Gio NhietDo DoAm
## 1 2023-01-01 12:00    20.5   60
## 2 2023-01-02 12:00    22.3   65
## 3 2023-01-03 12:00    21.8   62
##         Ngay   Gio NhietDo DoAm
## 1 2023-01-01 12:00    30.2   70
## 2 2023-01-02 12:00    31.5   68
## 3 2023-01-03 12:00    30.9   72
## [[1]]
##         Ngay   Gio NhietDo DoAm
## 1 2023-01-01 12:00    20.5   60
## 2 2023-01-02 12:00    22.3   65
## 3 2023-01-03 12:00    21.8   62
## 
## [[2]]
##         Ngay   Gio NhietDo DoAm
## 1 2023-01-01 12:00    30.2   70
## 2 2023-01-02 12:00    31.5   68
## 3 2023-01-03 12:00    30.9   72

Trong ví dụ này, chúng ta sử dụng hàm nest() trong gói tidyr và hàm group_by trong package dplyr để lồng dữ liệu theo tên thành phố. Bằng cách sử dụng chuỗi dòng lệnh trong gói tidyr và dplyr, chúng ta nhóm dữ liệu theo cột ThanhPho bằng hàm group_by() và sau đó sử dụng hàm nest() để tạo một cột mới chứa dữ liệu được lồng thành danh sách. Hoặc sử dụng tham số .by chọn cột ThanhPho để nhóm dữ liệu và sau đó dùng tham số .key để đặt tên cột danh sách tạo ra sau khi lồng dữ liệu.

Kết quả là một dataframe mới nested_data chứa hai cột: ThanhPho và DuLieu, trong đó cột hai chứa dữ liệu được lồng thành danh sách dựa trên tên thành phố. Các phần tử trong cột “DuLieu” là các danh sách dữ liệu con, mỗi danh sách chứa thông tin về ngày, giờ, nhiệt độ và độ ẩm tương ứng cho từng thành phố.

Lệnh nest() trong ví dụ này giúp chúng ta lồng dữ liệu theo tên thành phố, giúp tổ chức và xử lý dữ liệu thời tiết một cách trực quan và thuận tiện hơn

Sau đó, chúng ta tiếp tục sử dụng hàm lapply() để áp dụng hàm print() cho mỗi tibble trong danh sách nested_data$DuLieu. Kết quả là cả hai dữ liệu bảng từ các tibble sẽ được hiển thị trên màn hình, mỗi tibble đi kèm với tên cột và các giá trị tương ứng.

Kết quả hiện thị lần lượt là bảng về thới tiết ở Hà Nội và bảng sau đó là bảng thời tiết ở Hồ chí Minh. Đó là ví dụ về hàm nest() được sử dụng kết hợp với hàm group_by() và hàm lapply để cho ra được kết quả là các dữ liệu bảng được lồng vào nhau theo các biến chúng ta cần thống kê

2.5 Unnest

Trong ngôn ngữ lập trình R, lệnh unnest() được sử dụng để tách dữ liệu trong một cột chứa các đối tượng lồng nhau thành các cột riêng biệt. Điều này giúp chúng ta phân tách và truy cập dễ dàng vào các thành phần của các đối tượng được lồng nhau. Các tham số chính trong hàm unnest() gồm có:

  • data: Đối số này là dữ liệu gốc chứa cột danh sách mà chúng ta muốn giải nén. Đây là một đối số bắt buộc và phải là một khung dữ liệu (data frame).

  • col: Đây là đối số dùng để xác định tên của cột danh sách cần giải nén. Nó cũng là một đối số bắt buộc và phải là một chuỗi ký tự.

  • .drop: Một giá trị logical (TRUE hoặc FALSE) xác định xem liệu có nên loại bỏ cột danh sách sau khi giải nén hay không. Giá trị mặc định là TRUE, nghĩa là cột danh sách sẽ bị loại bỏ.

Dưới đây là ví dụ về lệnh unnest(), đầu tiên chúng tôi sẽ tạo dataframe chứa dữ liệu về sản phẩm và đặc điểm

data1 <- data.frame(
  SanPham = c("SP1", "SP2", "SP3"),
  MauSac = I(list(
    rep(c("Đỏ", "Xanh", "Vàng"), each = 3),
    rep(c("Trắng", "Đen"), each = 2),
    rep("Cam", 3)
  )),
  KichThuoc = I(list(
    rep(c("S", "M", "L"), each = 3),
    rep(c("M", "L"), each = 2),
    rep("S", 3)
  )),
  Gia = c(100, 200, 150)
)
print(data1)  
##   SanPham       MauSac    KichThuoc Gia
## 1     SP1 Đỏ, Đỏ, .... S, S, S,.... 100
## 2     SP2 Trắng, T....   M, M, L, L 200
## 3     SP3 Cam, Cam....      S, S, S 150
# Tách danh sách đặc điểm thành các cột riêng biệt
data_split <- unnest(data = data1, cols = c(MauSac,KichThuoc))


# In kết quả sau khi tách
datatable(data_split)

Trong ví dụ này, chúng ta có một dataframe data chứa thông tin về sản phẩm và đặc điểm của chúng. Cột MauSac và KichThuoc là các cột chứa danh sách các đặc điểm tương ứng với mỗi sản phẩm.

Sử dụng lệnh unnest() trong gói tidyr, chúng ta tách danh sách đặc điểm (MauSac và KichThuoc) thành các cột riêng biệt. Kết quả là một dataframe mới data_split với các cột SanPham, MauSac, KichThuoc và Gia, trong đó các cột MauSac và KichThuoc đã được tách thành các cột riêng biệt.

2.6 complete()

Hàm complete() trong R làm một công cụ mạnh mẽ để điền các giá trị thiếu và tạo ra các hàng hoàn chỉnh trong một dataframe, . Hàm complete() cho phép chúng ta điền các giá trị thiếu trong dataframe bằng cách tạo ra tất cả các kết hợp có thể của các giá trị trong các cột được chỉ định. Các giá trị đã có sẽ được giữ nguyên, trong khi các giá trị thiếu sẽ được điền bằng NA trong kết quả hoàn chỉnh. Những đối số có trong hàm complete()

  • data: Là data frame chứa dữ liệu cần mở rộng hoặc hoàn chỉnh.

  • …: Được sử dụng để chỉ định các cột cần mở rộng hoặc hoàn chỉnh. Các cột này có thể là các vectors hoặc danh sách (lists).

  • fill: Đối số này cho phép chúng ta cung cấp một giá trị duy nhất cho mỗi biến để điền vào thay vì giá trị NA cho các kết hợp bị thiếu.

  • explicit: Nếu tham số này bằng TRUE tất cả giá trị NA đều sẽ được điền, còn nếu bằng FALSE chỉ các giá trị NA được tạo ra bởi hàm mới được điền.

Ví dụ: Giả sử chúng ta có một bảng dữ liệu về các sản phẩm có thông tin về tên sản phẩm, loại sản phẩm và giá tiền. Tuy nhiên, bảng dữ liệu thiếu một số giá trị hoặc có các sản phẩm không có giá tiền. Chúng ta muốn điền các giá trị thiếu và tạo ra các sản phẩm hoàn chỉnh với tất cả các cột.

# Tạo dataframe chứa thông tin về sản phẩm
data2 <- data.frame(
  TenSanPham = c("SP1", "SP2", "SP3", "SP4"),
  LoaiSanPham = c("A", NA, "B", "C"),
  GiaTien = c(100, NA, 200, NA)
)
print(data2)
##   TenSanPham LoaiSanPham GiaTien
## 1        SP1           A     100
## 2        SP2        <NA>      NA
## 3        SP3           B     200
## 4        SP4           C      NA
# Điền các giá trị thiếu và tạo ra các sản phẩm hoàn chỉnh
data_complete <- complete(data2, TenSanPham, LoaiSanPham, GiaTien)

# In kết quả sau khi điền giá trị thiếu và tạo hàng hoàn chỉnh
options(max.print= 100)
print(data_complete, n = nrow(data_complete))
## # A tibble: 48 × 3
##    TenSanPham LoaiSanPham GiaTien
##    <chr>      <chr>         <dbl>
##  1 SP1        A               100
##  2 SP1        A               200
##  3 SP1        A                NA
##  4 SP1        B               100
##  5 SP1        B               200
##  6 SP1        B                NA
##  7 SP1        C               100
##  8 SP1        C               200
##  9 SP1        C                NA
## 10 SP1        <NA>            100
## 11 SP1        <NA>            200
## 12 SP1        <NA>             NA
## 13 SP2        A               100
## 14 SP2        A               200
## 15 SP2        A                NA
## 16 SP2        B               100
## 17 SP2        B               200
## 18 SP2        B                NA
## 19 SP2        C               100
## 20 SP2        C               200
## 21 SP2        C                NA
## 22 SP2        <NA>            100
## 23 SP2        <NA>            200
## 24 SP2        <NA>             NA
## 25 SP3        A               100
## 26 SP3        A               200
## 27 SP3        A                NA
## 28 SP3        B               100
## 29 SP3        B               200
## 30 SP3        B                NA
## 31 SP3        C               100
## 32 SP3        C               200
## 33 SP3        C                NA
## 34 SP3        <NA>            100
## 35 SP3        <NA>            200
## 36 SP3        <NA>             NA
## 37 SP4        A               100
## 38 SP4        A               200
## 39 SP4        A                NA
## 40 SP4        B               100
## 41 SP4        B               200
## 42 SP4        B                NA
## 43 SP4        C               100
## 44 SP4        C               200
## 45 SP4        C                NA
## 46 SP4        <NA>            100
## 47 SP4        <NA>            200
## 48 SP4        <NA>             NA

Trong ví dụ trên, chúng ta đã sử dụng hàm complete() để điền các giá trị thiếu và tạo ra các hàng hoàn chỉnh trong dataframe data. Các cột TenSanPham, LoaiSanPham và GiaTien đã được chỉ định là các cột cần hoàn chỉnh. Hàm complete() đã tạo ra tất cả các kết hợp có thể của các giá trị trong các cột được chỉ định và điền các giá trị thiếu bằng NA để tạo ra các hàng hoàn chỉnh. Kết quả được in ra màn hình để hiển thị dữ liệu đã được điền và tạo hàng hoàn chỉnh.

Trong kết quả, chúng ta có các hàng hoàn chỉnh với tất cả các kết hợp của các giá trị trong các cột TenSanPham, LoaiSanPham và GiaTien. Các giá trị thiếu được điền bằng NA để tạo ra các hàng hoàn chỉnh.

# Thêm vào tham số fill 
data_complete <- complete(data2, TenSanPham, LoaiSanPham, GiaTien, fill = list(LoaiSanPham="C",GiaTien=150) )
datatable(data_complete)

Tuy nhiên, chúng ta có thể áp dụng tham số fill để cung cấp một giá trị cho mỗi cột dữ liệu thay cho giá trị NA. Ở cột LoaiSanPham ta có thể chọn “C” để thay thế cho những giá trị NA, tương tự trong cột GiaTien chọn giá trị là 150.

Tóm lại, việc sử dụng hàm complete() sẽ giúp ta quản lý dữ liệu thiếu và chuẩn bị dữ liệu cho phân tích và khám phá dữ liệu một cách dễ dàng và hiệu quả.

2.7 Các hàm xử lý giá trị NA

Trong package tidyr, chúng ta có thể sử dụng các hàm như drop_na(), fill(), vàreplace_na() để xử lý các giá trị NA trong dữ liệu của mình. Thao tác này rất cần thiết đối vì dữ liệu được đem vào phân tích phải đầy đủ và độ chính xác cao thì kết quả thu được sẽ phản ánh đúng nhất với thực tế. Do đó, việc sử dụng thành thạo các công cụ trên sẽ giúp chúng ta tối ưu hóa thời gian làm việc của mình cũng như là đạt được kết quả tốt hơn ở những bước tiếp theo.

Chúng tôi sẽ thực hiện các ví dụ dựa trên dữ liệu có cấu trúc khá đơn giản nhằm mục đích giới thiệu những hàm xử lý các giá trị bị thiếu, ngoài ra cũng giúp người đọc có thể dễ dàng nhận ra được mức độ hiệu quả của nó khi được áp dụng lên bộ dữ liệu đơn giản. Sau đó, chương tiếp theo chúng tôi sẽ sử dụng lên dữ liệu phức tạp hơn và kết hợp thêm một số hàm khác để biến đổi về dạng dữ liệu sạch.

Để thực hiện các lệnh chúng tôi sẽ tạo một dataframe có tên là df gồm có cột date chứa chuỗi ngày bắt đầu từ “2023-07-01” đến “2023-07-10” và cột sales chứa số lượng sản phẩm được bán hàng ngày, trong đó có một số giá trị NA (thiếu thông tin) để đại diện cho các ngày không có dữ liệu.

# Tạo dữ liệu ví dụ
df <- data.frame(
  date = seq(as.Date("2023-07-01"), as.Date("2023-07-10"), by = "day"),
  sales = c(100, NA, 120, 80, NA, 90, NA, NA, 110, 95)
)
print(df)
##          date sales
## 1  2023-07-01   100
## 2  2023-07-02    NA
## 3  2023-07-03   120
## 4  2023-07-04    80
## 5  2023-07-05    NA
## 6  2023-07-06    90
## 7  2023-07-07    NA
## 8  2023-07-08    NA
## 9  2023-07-09   110
## 10 2023-07-10    95
  1. Xóa các dòng chứa giá trị NA “drop_na()”

Hàm drop_na(df) sẽ xóa các dòng trong dataframe df chứa giá trị NA. Kết quả được gán vào dataframe df_cleaned được thể hiện bên dưới. Chúng ta thấy rằng cả 4 dòng có giá trị NA đã bị xóa đi mất bây giờ dữ liệu chỉ còn lại 6 dòng.

# Xóa các dòng chứa giá trị NA
df_cleaned <- drop_na(df)
##         date sales
## 1 2023-07-01   100
## 2 2023-07-03   120
## 3 2023-07-04    80
## 4 2023-07-06    90
## 5 2023-07-09   110
## 6 2023-07-10    95
  1. Điền các giá trị NA bằng giá trị cụ thể “fill()”

Ngoài ra, chúng ta có thể điền hoặc thay thế các giá trị mới cho các dòng bị NA trong cột dữ liệu bằng hàm fill(). Điền giá trị sẽ dựa vào các dòng dữ liệu ở phía trên hoặc phía dưới để hoàn thiện các dòng NA trong cột.

Để sử dụng hàm fill() thì trước tiên ta cần khai báo bộ dữ liệu cần xử lý dữ liệu thiếu trong trường hợp này là df, sau đó chọn cột chứa các giá trị là sales và đối số .direction giúp ta chọn hướng để điền giá trị thiếu, mặc định sẽ là “down” điền từ trên xuống.

Dựa vào bảng kết quả ta có thể thấy ở ngày 2 thì số lượng sản phẩm được bán trong ngày sẽ được điền là 100 dựa vào dòng dữ liệu ở trước đó, tương tự cho các ngày bên dưới.

df_filled <- fill(data=df,sales,.direction = "down")
##          date sales
## 1  2023-07-01   100
## 2  2023-07-02   100
## 3  2023-07-03   120
## 4  2023-07-04    80
## 5  2023-07-05    80
## 6  2023-07-06    90
## 7  2023-07-07    90
## 8  2023-07-08    90
## 9  2023-07-09   110
## 10 2023-07-10    95

Tùy vào mục đích chúng ta có thể điền giá trị bị thiếu theo điều hướng từ phía dưới lên như bảng kết quả bên dưới ở ngày 7 và 8 giá trị NA được thay thế bằng 110 dựa vào số lượng bán hàng của ngày 9

df_filled2 <- fill(data=df,sales,.direction = "up")
##          date sales
## 1  2023-07-01   100
## 2  2023-07-02   120
## 3  2023-07-03   120
## 4  2023-07-04    80
## 5  2023-07-05    90
## 6  2023-07-06    90
## 7  2023-07-07   110
## 8  2023-07-08   110
## 9  2023-07-09   110
## 10 2023-07-10    95
  1. Thay thế các giá trị NA bằng giá trị khác “replace_na()”

Một cách khác dùng để xử lý giá trị thiếu là thay thế nó bằng một giá trị cụ thể mà chúng ta xác định, giá trị được dùng thay thế có thể là một con số, một vector và nó thay thế cho tất cả giá trị thiếu trong cột dữ liệu mà chúng ta chỉ định.

Trong ví dụ chúng tôi tính giá trị trung bình của cột sales trong dataframe df và loại bỏ các giá trị NA bằng đối số na.rm = TRUE . Tiếp theo, sử dụng hàm replace_na() để thay thế các giá trị NA trong cột sales của dataframe df bằng giá trị trung bình và kết quả được gán vào dataframe df_replaced

# Thay thế các giá trị NA bằng giá trị trung bình của sales
mean_sales <- mean(df$sales, na.rm = TRUE)
df_replaced <- replace_na(data=df, replace =  list(sales = mean_sales))
##          date     sales
## 1  2023-07-01 100.00000
## 2  2023-07-02  99.16667
## 3  2023-07-03 120.00000
## 4  2023-07-04  80.00000
## 5  2023-07-05  99.16667
## 6  2023-07-06  90.00000
## 7  2023-07-07  99.16667
## 8  2023-07-08  99.16667
## 9  2023-07-09 110.00000
## 10 2023-07-10  95.00000

3 CHƯƠNG 3: ỨNG DỤNG CỦA TIDYR

Trong chương này chúng tôi sẽ ứng dụng các hàm được giới thiệu ở chương 2 vào phân tích một số bộ dữ liệu để mọi người nhận thấy được sự hiệu quả của gói Tidyr trong giai đoạn xử lý dữ liệu chưa sạch. Ngoài ra, chúng tôi kết hợp một số gói khác chẳng hạn như dplyr, ggplot, tidyverse… để thuận tiện trong các thao tác phân tích cũng như trực quan hóa dữ liệu từ đó thu được kết quả tốt nhất.

3.1 Bộ dữ liệu gapminder

Trước khi phân tích thì chúng tôi sẽ giới thiệu bộ dữ liệu “gapminder” trong package gapminder gồm có những thông tin và biến nào để người đọc có sự nhìn nhận tổng quát về nó, điều này sẽ hữu ích trong việc hiểu rõ các lệnh được áp dụng sẽ mang lại kết quả như thế nào.

Bộ dữ liệu “gapminder” cung cấp thông tin về tuổi thọ trung bình, dân số và GDP per capita của các quốc gia từ năm 1952 đến 2007 với chu kỳ là 5 năm sẽ thu thập dữ liệu một lần. Nó giúp ta nắm bắt được sự thay đổi và sự phát triển của các quốc gia theo thời gian. Dữ liệu này gồm 1704 quan sát và có 6 biến trong đó:

  • country: Tên quốc gia.

  • continent: Lục địa nơi quốc gia thuộc về. Có 5 giá trị: Africa, Americas, Asia, Europe, và Oceania.

  • year: Năm ghi nhận dữ liệu.

  • lifeExp: Tuổi thọ trung bình của dân số trong quốc gia, tính bằng đơn vị năm.

  • population: Dân số của quốc gia trong năm cụ thể.

  • gdpPercap: GDP trên mỗi người dân của một quốc gia trong năm cụ thể.

Đầu tiên, chúng ta cần gọi dữ liệu “gapminder” bằng lệnh data sau khi đã cài đặt package gapminder và tải thư viện của nó lên, dữ liệu sẽ được gán vào biến “g” giúp việc nhập lệnh trở nên dễ dàng hơn so với tên ban đầu.

Bảng dữ liệu bên dưới, mỗi quan sát sẽ cho biết thông tin về tên quốc gia, châu lục của quốc gia, năm khảo sát và các chỉ số về tuổi thọ trung bình, dân số, GDP trên mỗi cá nhân tương ứng. Do đó, nó thuộc dạng dữ liệu “rộng” điều này sẽ giúp việc nhập dữ liệu hoặc trình bày bảng tốt hơn, người đọc báo cáo có thể hiểu rõ được nội dung mà không mất quá nhiều thời gian. Tuy nhiên dạng dữ liệu “rộng” sẽ gặp khó khăn trong việc phân tích vì vậy chúng ta cần phải chuyển sang dạng “dài”.

library(gapminder)
data("gapminder")
g <- gapminder
datatable(g)

Hàm pivot_longer()sẽ chuyển dữ liệu “g” sang dạng dài bằng cách chuyển đổi ba cột lifeExp, pop, gdpPercap thành hai cột mới là chiso chứa tên các chỉ số và giatri chứa các giá trị của các biến ban đầu. Sau đó sẽ gán dữ liệu được chuyển đổi vào “g2”, dữ liệu này sẽ có số quan sát là 5112 tuy nhiên thì số lượng biến sẽ ít hơn dữ liệu ban đầu (5 cột so với 6 cột).

g2 <- pivot_longer(data = g , cols = c(lifeExp,pop,gdpPercap), names_to = "chiso", values_to = "giatri")
head(g2)
## # A tibble: 6 × 5
##   country     continent  year chiso        giatri
##   <fct>       <fct>     <int> <chr>         <dbl>
## 1 Afghanistan Asia       1952 lifeExp        28.8
## 2 Afghanistan Asia       1952 pop       8425333  
## 3 Afghanistan Asia       1952 gdpPercap     779. 
## 4 Afghanistan Asia       1957 lifeExp        30.3
## 5 Afghanistan Asia       1957 pop       9240934  
## 6 Afghanistan Asia       1957 gdpPercap     821.

Nếu ta muốn tính trung bình của các chỉ số này theo từng châu lục khác nhau nhằm mục đích đánh giá tổng thể sự phát triển giữa các châu với nhau, ta có thể sử dụng thêm hàm group_by để nhóm dữ liệu theo cột continent, chiso và hàm summarise để thực hiện phép tính trung bình cho cột giatri của các nhóm dữ liệu. Cả hai hàm trên đều nằm trong gói dplyr có thể kết hợp với gói tidyr để biến đổi dữ liệu chưa sạch rất hiệu quả.

Kết quả thu được sẽ được gán vào “mean_g2” trong đó sẽ có cột continent chứa thông tin về các châu lục. Cột chiso gồm giá trị là GDP, tuổi thọ, dân số. Cột trungbinh sẽ chứa giá trị trung bình của các chỉ số tương ứng với mỗi châu lục.

mean_g2 <- g2 %>% group_by(continent,chiso) %>% summarise(trungbinh=mean(giatri))
datatable(mean_g2)

Từ đó, chúng ta trực quan hóa bộ dữ liệu vừa được tính trung bình bằng cách vẽ biểu đồ cột cho ba chỉ số với các màu sắc khác nhau. Các cột trên đồ thị sẽ tương ứng với các châu lục trong dữ liệu.

Biểu đồ có các cột màu đỏ là biểu đồ về GDP trên mỗi cá nhân trung bình của 5 châu lục. Dựa vào biểu đồ ta có thể thấy Châu Đại Đương có GDP cao nhất trong 5 châu lục (khoảng 18621 đô), ngược lại thì Châu Phi có GDP trung bình thấp với con số khiêm tốn là khoảng 2193 đô trên mỗi cá nhân.

Biểu đồ cột màu xanh lá đại diện cho tuổi thọ trung bình của người dân ở mỗi châu lục, nhìn tổng thể thì các châu lục có tuổi thọ trung bình không chênh lệch nhiều, ngoại trừ Châu Phi có tuổi thọ trung bình là khoảng 49 tuổi khá thấp so với Châu Âu (72 tuổi) và Châu Đại Đương (74 tuổi).

Cuối cùng, biểu đồ có cột màu xanh dương cho biết thông tin về dân số trung bình của các quốc gia trong một châu lục cụ thể. Ta nhận thấy rằng các quốc gia Châu Á có dân số trung bình cao vượt trội so với các châu lục còn lại( khoảng 77 triệu người). Tuy nhiên thì các quốc gia thuộc Châu Đại Đương và Châu Phi có dân số thấp (dưới mức 10 triệu người).

ggplot(mean_g2, aes(x = continent, y = trungbinh, fill = chiso)) +
  geom_col() +
  facet_grid(chiso ~ ., scales = "free_y") +
  labs(x = "ChauLuc", y = "GiaTri") +
  theme_minimal() +
  scale_y_continuous(expand = expansion(mult = c(0.1, 0.1)))

Trong một vài tình huống nhu cầu của người phân tích chỉ cần chọn một số quốc gia cụ thể để đánh giá sự phát triển của nó bằng các chỉ số thì chúng ta cũng có để kết hợp thêm hàm select()filter thuộc gói dplyr, sau đó thể hiện dữ liệu ở dạng đồ thị bằng các công cụ mạnh mẽ từ gói ggplot2.

Dưới đây chúng tôi chọn các cột country, lifeExp, year bằng hàm select() để dữ liệu đầu trong hàm phía sau sẽ nhỏ hơn bộ dữ liệu ban đầu. Phép toán tử %>% giúp dữ liệu sau khi được chọn đưa vào đối số đầu tiên của hàm filter để thực hiện lọc một số quốc gia trong cột country. Cuối cùng sử dụng hàm ggplot để vẽ đồ thị đường về tuổi thọ trung bình của ba quốc gia China, Vietnam, United States.

g %>% select(country,lifeExp,year) %>%  filter(country %in% c("China","Vietnam","United States"))%>% 
  ggplot(aes(x = year , y = lifeExp, color=country))+
      geom_line()+
      labs(x= "NĂM", y= "TUỔI THỌ", title = "BIỂU ĐỒ TUỔI THỌ TRUNG BÌNH", color = "QUỐC GIA")

Để biết thêm thông tin về sự thay đổi tổng dân số trong châu lục qua các năm, chúng tôi đã tính tổng dân số được nhóm theo biến continent, year. Kết quả sẽ được gán vào “g3” để thuận tiện thực hiện các lệnh tiếp theo.

Dữ liệu sau khi tính tổng dân số đã thuộc dạng dữ liệu dài, điều này sẽ khiến việc thực hiện trực quan hóa một cách rất dễ dàng. Do đó chúng ta có thể sử dụng nó biểu diễn đồ thị cột về sự thay đổi tổng dân số của các châu lục này qua các năm ngay lập tức.

g3 <- g %>% group_by(continent,year) %>% 
  summarise(spop=sum(pop))
head(g3)
## # A tibble: 6 × 3
## # Groups:   continent [1]
##   continent  year      spop
##   <fct>     <int>     <dbl>
## 1 Africa     1952 237640501
## 2 Africa     1957 264837738
## 3 Africa     1962 296516865
## 4 Africa     1967 335289489
## 5 Africa     1972 379879541
## 6 Africa     1977 433061021
ggplot(g3)+
  geom_col(
    aes(x= year, y = spop, fill= continent ),
    width = 2
  )

Để phù hợp cho việc thực hiện các báo cáo và trình bày bảng chúng ta có thể dùng hàm pivot_wider() để chuyển g3 sang dạng rộng như bên dưới đây. Bảng này sẽ giúp ta quan sát tổng dân số của từng lục địa qua các năm một cách thuận tiện hơn.

wider_g3<- pivot_wider(g3 ,names_from = continent, values_from = spop)
datatable(wider_g3)
  • Sau đó vẽ đồ thị cột thể hiện tổng dân số thay đổi qua các năm cho châu Âu
ggplot(wider_g3, aes(x = year, y= Europe ,fill= "Europe" ))+
  geom_col()+
  scale_fill_manual(values = "blue") +
  theme_minimal()+
   labs(x = "Năm",y="Dân số", title =  "BIỂU ĐỒ DÂN SỐ CHÂU ÂU ", fill = "Châu")

  • Dựa vào đồ thị, tổng dân số của Châu Âu có sự gia tăng qua các năm và tốc độ tăng này khá đồng đều nhau. Năm 1952 tổng dân số của châu lục này chỉ có khoảng 400 triệu người và tăng dần đến năm 2007 thì có khoảng 600 triệu người.

    Tiếp theo, chúng tôi sử dụng hàm nest() để gom các cột pop, gdpPercap và lifeExp thành một cột dạng nested list. Điều này giúp giảm sự phức tạp của dữ liệu và thực hiện các tính toán linh hoạt hơn theo nhóm đã được gộp.

# Sử dụng hàm nest() để gom các năm và chỉ số tương ứng thành cột dạng nested list
nested <- g %>%  nest(.by  = c(country, continent,year),.key = "chiso")
## # A tibble: 1,704 × 4
##    country     continent  year chiso           
##    <fct>       <fct>     <int> <list>          
##  1 Afghanistan Asia       1952 <tibble [1 × 3]>
##  2 Afghanistan Asia       1957 <tibble [1 × 3]>
##  3 Afghanistan Asia       1962 <tibble [1 × 3]>
##  4 Afghanistan Asia       1967 <tibble [1 × 3]>
##  5 Afghanistan Asia       1972 <tibble [1 × 3]>
##  6 Afghanistan Asia       1977 <tibble [1 × 3]>
##  7 Afghanistan Asia       1982 <tibble [1 × 3]>
##  8 Afghanistan Asia       1987 <tibble [1 × 3]>
##  9 Afghanistan Asia       1992 <tibble [1 × 3]>
## 10 Afghanistan Asia       1997 <tibble [1 × 3]>
## # ℹ 1,694 more rows
  • Như kết quả hiển thị bên trên, cột chiso nằm ở dạng danh sách lồng nhau ( nested list), mỗi phần tử sẽ chứa thông tin về pop, gdp, lifeExp của mỗi quốc gia theo từng năm.

Hơn thế, nếu chúng ta cần thông tin về các chỉ số của một quốc gia cụ thể chẳng hạn như United States ta có thể dùng hàm filter() để lọc nó ra và hiển thị kết quả về những chỉ số đã được gom.

nested$chiso <- lapply(nested$chiso, as.data.frame)
US <- nested %>%  filter(country == "United States")
## [[1]]
##   lifeExp       pop gdpPercap
## 1   68.44 157553000  13990.48
## 
## [[2]]
##   lifeExp       pop gdpPercap
## 1   69.49 171984000  14847.13
## 
## [[3]]
##   lifeExp       pop gdpPercap
## 1   70.21 186538000  16173.15
## 
## [[4]]
##   lifeExp       pop gdpPercap
## 1   70.76 198712000  19530.37
## 
## [[5]]
##   lifeExp       pop gdpPercap
## 1   71.34 209896000  21806.04
## 
## [[6]]
##   lifeExp       pop gdpPercap
## 1   73.38 220239000  24072.63
## 
## [[7]]
##   lifeExp       pop gdpPercap
## 1   74.65 232187835  25009.56
## 
## [[8]]
##   lifeExp       pop gdpPercap
## 1   75.02 242803533  29884.35
## 
## [[9]]
##   lifeExp       pop gdpPercap
## 1   76.09 256894189  32003.93
## 
## [[10]]
##   lifeExp       pop gdpPercap
## 1   76.81 272911760  35767.43
## 
## [[11]]
##   lifeExp       pop gdpPercap
## 1   77.31 287675526   39097.1
## 
## [[12]]
##   lifeExp       pop gdpPercap
## 1  78.242 301139947  42951.65
  • Để giải nén dữ liệu ở dạng list nested thì ta dùng hàm unnest(), kết quả thu được sẽ tương tự dữ liệu ban đầu ban đầu.
# Sử dụng hàm unnest() để giải nén dữ liệu
unnest <- nested %>% unnest(chiso)
## # A tibble: 1,704 × 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1952    28.8  8425333      779.
##  2 Afghanistan Asia       1957    30.3  9240934      821.
##  3 Afghanistan Asia       1962    32.0 10267083      853.
##  4 Afghanistan Asia       1967    34.0 11537966      836.
##  5 Afghanistan Asia       1972    36.1 13079460      740.
##  6 Afghanistan Asia       1977    38.4 14880372      786.
##  7 Afghanistan Asia       1982    39.9 12881816      978.
##  8 Afghanistan Asia       1987    40.8 13867957      852.
##  9 Afghanistan Asia       1992    41.7 16317921      649.
## 10 Afghanistan Asia       1997    41.8 22227415      635.
## # ℹ 1,694 more rows
# Vẽ biểu đồ cột cho tổng dân số (pop) của từng quốc gia trong năm 2007
 unnest %>% 
  filter(year == 2007 & country %in% c("Vietnam", "China", "Korea, Rep.", "Japan","Indonesia","Thailand","Malaysia","India")) %>% 
  ggplot( aes(x = reorder(country, pop), y = pop,fill = country)) +
  geom_bar(stat = "identity") +
  labs(title = "Dân số của một quốc gia Asia trong năm 2007",
       x = "Quốc gia",
       y = "Tổng dân số")

  • Biểu đồ cho thấy rằng dân số của India (Khoảng 1,1 tỷ người), China (khoảng 1,3 tỷ người) trong năm 2007 cao hơn rất nhiều so với một số quốc gia trong khu vực Châu Á. Quốc gia có dân số thấp nhất trong các quốc gia trên là Malaysia chỉ có khoảng 25 triệu người

Việc sử dụng nest() và unnest() cho bộ dữ liệu gapminder cho phép ta chuyển đổi dữ liệu từ dạng bảng thông thường thành dạng nested list và ngược lại. Điều này có thể hữu ích trong việc thao tác và xử lý dữ liệu, đặc biệt là khi làm việc với dữ liệu có cấu trúc phức tạp hơn và có nhiều cấp độ lồng nhau.

3.2 WHO

Trong phần này chúng tôi sẽ làm việc trên bộ dữ liệu who, đây là bộ dữ liệu con được thu thập từ báo cáo về bệnh lao toàn cầu của Tổ chức Y tế Thế giới. Nó gồm có 60 cột và 7240 quan sát, tuy nhiên thì từ cột thứ 5 đến cột 60 có ký tự “new_” được kết nối với các thông tin khác.

  • country là tên của các quốc gia được thu thập.

  • ios2, ios3 lần lượt là mã quốc gia 2 ký tự và 3 ký tự.

  • year là năm thu thập dữ liệu.

  • Phương pháp chẩn đoán nếu là rel nghĩa là tái phát, sn là bệnh nhân không có vi khuẩn lao , sp là bệnh nhân có vi khuẩn lao, ep bệnh nhân lao ngoài phổi.

  • Ký tự f đại diện cho giới tính nữ và m là giới tính nam

  • Số trong mỗi cột được dùng để thể hiện nhóm tuổi ví dụ 014 là 0-14 tuổi, 1524 là 15-24 tuổi, 2534 là 25-34 tuổi, 3544 là 35-44 tuổi, 4554 là 45-54 tuổi, 5564 là 55-64 tuổi và 65 là 65 tuổi trở lên.

Ví dụ tên cột thứ 5 là “new_sp_m014” đại diện cho những bệnh nhân có kết quả chuẩn đoán có vi khuẩn lao lao dương tính, giới tính nam và thuộc nhóm tuổi từ 0 đến 14 tuổi.

data("who")
## # A tibble: 6 × 60
##   country   iso2  iso3   year new_sp_m014 new_sp_m1524 new_sp_m2534 new_sp_m3544
##   <chr>     <chr> <chr> <dbl>       <dbl>        <dbl>        <dbl>        <dbl>
## 1 Afghanis… AF    AFG    1980          NA           NA           NA           NA
## 2 Afghanis… AF    AFG    1981          NA           NA           NA           NA
## 3 Afghanis… AF    AFG    1982          NA           NA           NA           NA
## 4 Afghanis… AF    AFG    1983          NA           NA           NA           NA
## 5 Afghanis… AF    AFG    1984          NA           NA           NA           NA
## 6 Afghanis… AF    AFG    1985          NA           NA           NA           NA
## # ℹ 52 more variables: new_sp_m4554 <dbl>, new_sp_m5564 <dbl>,
## #   new_sp_m65 <dbl>, new_sp_f014 <dbl>, new_sp_f1524 <dbl>,
## #   new_sp_f2534 <dbl>, new_sp_f3544 <dbl>, new_sp_f4554 <dbl>,
## #   new_sp_f5564 <dbl>, new_sp_f65 <dbl>, new_sn_m014 <dbl>,
## #   new_sn_m1524 <dbl>, new_sn_m2534 <dbl>, new_sn_m3544 <dbl>,
## #   new_sn_m4554 <dbl>, new_sn_m5564 <dbl>, new_sn_m65 <dbl>,
## #   new_sn_f014 <dbl>, new_sn_f1524 <dbl>, new_sn_f2534 <dbl>, …

Ta thực hiện chuyển dữ liệu sang dạng long bằng hàm pivot_longer() như đã được giới thiệu ở phần trước, các cột chuyển đổi được chọn bằng starts_with bắt đầu với ký tự “new”. Tên biến chứa các cột sau khi chuyển sang dạng long là method và giá trị tương ứng được chứa trong cột values. Sau đó chúng ta có thể dùng hàm drop_na() để loại bỏ đi các giá trị NA.

#Chuyển dữ liệu sang dạng dài 
longer <- pivot_longer(data = who,cols = starts_with("new"), names_to = "method", values_to = "values")
longer <- drop_na(longer)
## # A tibble: 6 × 6
##   country     iso2  iso3   year method       values
##   <chr>       <chr> <chr> <dbl> <chr>         <dbl>
## 1 Afghanistan AF    AFG    1997 new_sp_m014       0
## 2 Afghanistan AF    AFG    1997 new_sp_m1524     10
## 3 Afghanistan AF    AFG    1997 new_sp_m2534      6
## 4 Afghanistan AF    AFG    1997 new_sp_m3544      3
## 5 Afghanistan AF    AFG    1997 new_sp_m4554      5
## 6 Afghanistan AF    AFG    1997 new_sp_m5564      2

Chúng ta thấy rằng trong cột method chứa các thông tin về dữ liệu khảo sát bệnh lao dưới dạng chuỗi khá phức tạp, chính vì thế chúng ta cần kết hợp thêm hàm gsub để có thể loại bỏ cũng như là thêm vào một số chuỗi cần thiết. Hàm mutate() sẽ giúp cập nhập các giá trị vừa được thay đổi ở cột method trong trường hợp này chúng tôi tạo cột mới trùng với tên cột cũ.

  • Loại bỏ chuỗi “new_” trong cột method bằng các thay thế nó bằng ““, tuy nhiên một số chuỗi chỉ xuất hiện”new” chứ không phải là “new_” cho nên chúng ta cần khai báo cho hàm gsub() các chuỗi cần thay thế là “new_?”.
longer <- longer %>% mutate(method = gsub("new_?","",method))
## # A tibble: 6 × 6
##   country     iso2  iso3   year method   values
##   <chr>       <chr> <chr> <dbl> <chr>     <dbl>
## 1 Afghanistan AF    AFG    1997 sp_m014       0
## 2 Afghanistan AF    AFG    1997 sp_m1524     10
## 3 Afghanistan AF    AFG    1997 sp_m2534      6
## 4 Afghanistan AF    AFG    1997 sp_m3544      3
## 5 Afghanistan AF    AFG    1997 sp_m4554      5
## 6 Afghanistan AF    AFG    1997 sp_m5564      2
  • Tiếp theo, chúng ta thêm vào ký tự “_” sau ký “f” hoặc “m” để có thể phân cách giới tính và nhóm tuổi
longer <- longer %>% mutate(method = gsub("(f|m)(\\d+)","\\1_\\2",method))
## # A tibble: 6 × 6
##   country     iso2  iso3   year method    values
##   <chr>       <chr> <chr> <dbl> <chr>      <dbl>
## 1 Afghanistan AF    AFG    1997 sp_m_014       0
## 2 Afghanistan AF    AFG    1997 sp_m_1524     10
## 3 Afghanistan AF    AFG    1997 sp_m_2534      6
## 4 Afghanistan AF    AFG    1997 sp_m_3544      3
## 5 Afghanistan AF    AFG    1997 sp_m_4554      5
## 6 Afghanistan AF    AFG    1997 sp_m_5564      2
  • Thực hiện tác cột method thành ba cột mt, gender, age bằng hàm separate()
longer <- longer %>% separate(col = method,into = c("mt","gender","age"), sep = "_")
## # A tibble: 6 × 8
##   country     iso2  iso3   year mt    gender age   values
##   <chr>       <chr> <chr> <dbl> <chr> <chr>  <chr>  <dbl>
## 1 Afghanistan AF    AFG    1997 sp    m      014        0
## 2 Afghanistan AF    AFG    1997 sp    m      1524      10
## 3 Afghanistan AF    AFG    1997 sp    m      2534       6
## 4 Afghanistan AF    AFG    1997 sp    m      3544       3
## 5 Afghanistan AF    AFG    1997 sp    m      4554       5
## 6 Afghanistan AF    AFG    1997 sp    m      5564       2
  • Chuyển đổi các giá trị viết tắt trong cột agegender về nhóm tuổi, giới tính cụ thể.
longer <- mutate(longer, age = case_when(
 age == "014" ~ "0-14 years",
    age == "1524" ~ "15-24 years",
    age == "2534" ~ "25-34 years",
    age == "3544" ~ "35-44 years",
    age == "4554" ~ "45-54 years",
    age == "5564" ~ "55-64 years",
    age == "65" ~ "65 years or older",
))

longer <- longer %>%  mutate(gender = case_when(
  gender == "m" ~ "male",
  gender == "f" ~ "female"
))

Qua nhiều thao tác xử lý và biến đổi từ dữ liệu who ban đầu chúng ta đã có được bộ dữ liệu mới gọn gàng hơn rất nhiều. Việc làm sạch dữ liệu chưa hoàn chỉnh rất quan trọng trong quá trình phân tích, nó giúp chúng ta dễ dàng trực quan hóa bằng các hình ảnh, đồ thị cũng như là tính toán các số liệu thống kê.

longer %>% group_by(gender,year) %>% summarise(case= sum(values)) %>% 
  ggplot(aes(x=year, y = case , color=gender ))+
  geom_line()+
  scale_color_manual(values = c("blue", "red")) +
  theme_minimal() +
  labs(title = "TỔNG SỐ CA BỆNH THEO GIỚI TÍNH"  )

  • Dựa vào biểu đồ đường ở trên, tổng trường hợp mắc bệnh lao qua các năm ở hai giới tính có xu hướng tăng lên từ những năm 1995. Xu hướng tăng có tự tương đồng với nhau giữa hai nhóm giới tính tuy nhiên ở nam giới sự gia tăng tổng số ca mắc bệnh nhiều hơn ở nữ giới. Cụ thể, năm 2010 tổng các trường hợp mắc bệnh lao ở nam giới là 2,5 triệu người còn ở nữ giới chỉ có khoảng 1,5 triệu người.
# tính tổng số người bệnh theo giới tính và phương pháp chuẩn đoán (mt)
 df1 <- longer %>% group_by(gender,mt) %>% summarise(sum= sum(values))
## # A tibble: 8 × 3
## # Groups:   gender [2]
##   gender mt         sum
##   <chr>  <chr>    <dbl>
## 1 female ep      941049
## 2 female rel    1197703
## 3 female sn     2437544
## 4 female sp    11292279
## 5 male   ep     1043265
## 6 male   rel    2013437
## 7 male   sn     3838291
## 8 male   sp    20542472
  • Tính tổng số ca mắc bệnh theo giới tính và phương pháp chuẩn đoán bằng hàm group_by()summarise(), sau đó vẽ đồ thị cột đôi để đánh giá kết quả.
# Đồ thị 
  ggplot( df1,aes(x = mt, y = sum, fill = gender)) +
  geom_col(position = "dodge") +
  labs(title = "Tổng số ca theo phương pháp và giới tính",
       x = "Phương pháp",
       y = "Số lượng",
       fill = "Giới tính") +
  theme_minimal()

  • Đồ thị bên trên cho chúng ta thấy số người được chuẩn đoán là sp (có vi khuẩn lao) có số lượng cao nhất trong 4 nhóm cụ thể có 20542472 nam và 11292279 nữ trong trường hợp này. Chuẩn đoán là bệnh lao ngoài phổi (ep) có số lượng thấp nhất, trong đó ở nữ giới có 941049 người và nam giới có 1043265 người thuộc chuẩn đoán này.
longer %>% group_by(age)%>%  summarise(total=sum(values)) %>% 
  mutate(p = total/sum(total)) %>%
  ggplot(aes(x="", y= p, fill = age))+
  geom_bar(stat = "identity",width = 1)+
  scale_fill_brewer(palette = "Set3") +
  coord_polar("y",start = 0)+
  geom_text(aes(label = scales::percent(p)),position = position_stack(vjust = 0.5), size = 3) +
  theme_void() +
  labs(title= "Tình trạng bệnh lao ở các nhóm tuổi")

  • Nhóm từ 25 đến 34 tuổi có tỷ lệ mắc bệnh lớn nhất trong tất cả nhóm tuổi (khoảng 22.2%), ở nhóm từ 45 đến 54 tuổi cũng đạt tỷ lệ khá cao là 20.2%. Ngược lại thì nhóm 0-14 tuổi chiếm tỷ lệ mắc bệnh lao thấp nhất chỉ khoảng 3.9%. Nhìn chung tỷ lệ mắc bệnh cao sẽ thuộc các nhóm tuổi trung niên.

Để gom các biến thành một danh sách lồng nhau theo mỗi quốc gia ta áp dụng hàm nest(), dữ liệu mới này gọn gàng hơn rất nhiều so với ban đầu nếu chúng ta cần khai thác thông tin của quốc gia thì chỉ cần mở danh sách dữ liệu của nó mà không cần phải nhìn toàn bộ thông tin như ban đầu.

nested_data <- nest(longer, .by = country, .key = "year")
## # A tibble: 218 × 2
##    country             year              
##    <chr>               <list>            
##  1 Afghanistan         <tibble [244 × 7]>
##  2 Albania             <tibble [448 × 7]>
##  3 Algeria             <tibble [224 × 7]>
##  4 American Samoa      <tibble [172 × 7]>
##  5 Andorra             <tibble [387 × 7]>
##  6 Angola              <tibble [270 × 7]>
##  7 Anguilla            <tibble [155 × 7]>
##  8 Antigua and Barbuda <tibble [346 × 7]>
##  9 Argentina           <tibble [448 × 7]>
## 10 Armenia             <tibble [461 × 7]>
## # ℹ 208 more rows

Hàm filter() trong trường hợp bên dưới được sử dụng để lọc Việt Nam ra khỏi bộ dữ liệu trên và sau đó ta hiển thị thông tin về các trường hợp mắc bệnh lao của nó như bên dưới đây.

nested_data$year <- lapply(nested_data$year, as.data.frame)
VN <-  nested_data %>% filter(country== "Viet Nam")
## # A tibble: 1 × 2
##   country  year          
##   <chr>    <list>        
## 1 Viet Nam <df [252 × 7]>
## [[1]]
##    iso2 iso3 year mt gender               age values
## 1    VN  VNM 1996 sp   male        0-14 years     92
## 2    VN  VNM 1996 sp   male       15-24 years   1994
## 3    VN  VNM 1996 sp   male       25-34 years   5716
## 4    VN  VNM 1996 sp   male       35-44 years   7137
## 5    VN  VNM 1996 sp   male       45-54 years   5170
## 6    VN  VNM 1996 sp   male       55-64 years   5839
## 7    VN  VNM 1996 sp   male 65 years or older   6292
## 8    VN  VNM 1996 sp female        0-14 years     91
## 9    VN  VNM 1996 sp female       15-24 years   1127
## 10   VN  VNM 1996 sp female       25-34 years   2606
## 11   VN  VNM 1996 sp female       35-44 years   3045
## 12   VN  VNM 1996 sp female       45-54 years   2504
## 13   VN  VNM 1996 sp female       55-64 years   3360
## 14   VN  VNM 1996 sp female 65 years or older   3938
##  [ reached 'max' / getOption("max.print") -- omitted 238 rows ]

Giải nén dữ liệu ở dạng nested ta cần sử dụng hàm unnest() dữ liệu được trả về sẽ bao gồm các thông tin như dữ liệu ban đầu.

# Sử dụng hàm unnest()
unnest_data <- unnest(nested_data,cols = year)
## # A tibble: 75,752 × 8
##    country     iso2  iso3   year mt    gender age               values
##    <chr>       <chr> <chr> <dbl> <chr> <chr>  <chr>              <dbl>
##  1 Afghanistan AF    AFG    1997 sp    male   0-14 years             0
##  2 Afghanistan AF    AFG    1997 sp    male   15-24 years           10
##  3 Afghanistan AF    AFG    1997 sp    male   25-34 years            6
##  4 Afghanistan AF    AFG    1997 sp    male   35-44 years            3
##  5 Afghanistan AF    AFG    1997 sp    male   45-54 years            5
##  6 Afghanistan AF    AFG    1997 sp    male   55-64 years            2
##  7 Afghanistan AF    AFG    1997 sp    male   65 years or older      0
##  8 Afghanistan AF    AFG    1997 sp    female 0-14 years             5
##  9 Afghanistan AF    AFG    1997 sp    female 15-24 years           38
## 10 Afghanistan AF    AFG    1997 sp    female 25-34 years           36
## # ℹ 75,742 more rows

4 CHƯƠNG 4: KẾT LUẬN

4.1 Kết luận

Bài tiểu luận của chúng tôi đã trình bày các chức năng quan trọng của gói Tidyr trong ngôn ngữ lập trình R, nó chính là công cụ mạnh mẽ giúp mọi người xử lý những bộ dữ liệu chưa được chuẩn hóa về dạng dữ liệu sạch và sau đó đưa vào phân tích và trực quan hóa dữ liệu. Bên cạnh việc giới thiệu về gói này chúng tôi cũng đã thực hiện các thao tác hướng dẫn chi tiết dựa trên dữ liệu mẫu để làm nổi bật sự hiệu quả của gói Tidyr trong việc làm sạch dữ liệu. Những dữ liệu thô ban đầu thường có cấu trúc phức tạp, nhiều biến kết hợp với nhau bằng các ký tự phân cách hoặc thậm chí lồng ghép với nhau thành các danh sách. Vì vậy, chúng tôi đã thực hiện các hàm xử lý dữ liệu bị thiếu, biến đổi cấu trúc, tách ghép và lồng ghép danh sách sao cho phù hợp từng dữ liệu.

Gói Tidyr có thể kết hợp với một số gói khác chẳng hạn như là dplyr, ggplot2, stringr để tối ưu và tiết kiệm nhiều thời gian, tuy nhiên chúng ta cũng cần nghiên cứu rất nhiều để có thể kết hợp với các hàm trong gói Tidyr. Nhìn chung những hàm trong gói tidyr có tính ứng dụng rất cao trong nhiều lĩnh vực nhưng sử dụng thì khá đơn giản chỉ cần khai báo một vài đối số. Chẳng hạn hàm pivot_longer biến đổi dữ liệu rộng sang dạng dài giúp ta trực hóa dữ liệu tốt hơn trước, hàm separate có chức năng tách thành các cột dựa vào các ký tự phân cách ngược lại thì unite giúp kết hợp các cột lại với nhau và một số hàm xử lý dữ liệu khác.

Ngoài ra, ngôn ngữ R sẽ phát triển gói này theo thời gian chính vì vậy những nhược điểm của nó sẽ được cải thiện bởi chính những người dùng, một số chức năng mới có thể được thêm vào khiến cho Tidyr trở nên linh hoạt và đa dạng hơn. Trong quá trình thực hành các hàm nếu gặp phải những vấn đề khó khăn thì cộng đồng R có các bài hướng dẫn giúp ta giải quyết nó.

Tóm lại, gói tidyr là công cụ giúp cho chúng ta biến đổi cấu trúc dữ liệu, tách, ghép và xử lý dữ liệu bị thiếu một cách đơn giản nhưng nó lại giúp giai đoạn xử lý dữ liệu đầu vào của mọi người sẽ tiết kiệm nhiều thời gian và đạt kết quả cao hơn. Hơn thế, gói này còn kết hợp với hệ sinh thái Tidyverse và nhiều packages khác nhằm đáp ứng các nhu cầu khác nhau của người phân tích. Bởi vì những chức năng nổi bật đó mà gói tidyr được áp dụng trong nhiều lĩnh vực tài chính, bảo hiểm, y học.

4.2 Hạn chế và phương hướng tiếp theo của đề tài

Trong thời gian nghiên cứu đề tài về gói tidyr chúng tôi đã gặp một số khó khăn trong việc tìm kiếm nguồn tài liệu tham khảo vì cần phải có một lượng lớn kiến thức cũng như hiểu rõ một số khái niệm để hoàn thành nó. Một số hàm cần phải xem qua nhiều tài liệu hướng dẫn, ví dụ cụ thể thì chúng ta mới có thể hiểu nó và trình bày chức năng của hàm đó. Hơn thế, chúng tôi cũng mất nhiều thời gian để chọn ra những dữ liệu thích hợp cho việc áp dụng các hàm minh họa. Việc hiểu cấu trúc của một bộ dữ liệu phức tạp sẽ giúp ta dùng những hàm phù hợp để biến đổi nó về dữ liệu sạch.

Chúng tôi muốn đề xuất một số phương hướng cho những nghiên cứu tiếp theo ở đề tài này. Gói này có thể sử dụng để phân tích những bộ dữ liệu nhiều biến và nhiều dòng dữ liệu hơn. Chúng ta nên kết hợp với các gói có khả năng trực quan hóa dữ liệu vừa xử lí bằng các đồ thị hay thậm chí là đồ thị 3D để trình bày kết quả. Ngoài ra những hàm xử lý chuỗi trong gói stringr sẽ giúp người sử dụng phát huy được các chức năng của gói tidyr khi sử dụng đồng thời chúng với nhau

LS0tDQp0aXRsZTogIlRp4buDdSBsdeG6rW4gcGFja2FnZSBUaWR5ciINCmF1dGhvcjogIkzDqiBUaMOgbmggxJDhurduZyAtIENow6J1IEEgS2nhu4d0Ig0KZGF0ZTogIjIwMjMtMDYtMjgiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2RlcHRoOiA1DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IHllcw0KICAgICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgdGhlbWU6IHVuaXRlZA0KDQogIHdvcmRfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQpgYGB7Y3NzLGVjaG8gPSBGQUxTRX0NCmgxIHsNCiAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogIGZvbnQtc2l6ZTogMzJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQNCiAgfQ0KDQpoMiB7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBmb250LXNpemU6IDI4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KIA0KfQ0KDQpoMyB7DQogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICBmb250LXNpemU6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXN0eWxlOiBpdGFsaWM7DQp9DQoNCmg0IHtmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgZm9udC1zaXplOiAyMHB4Ow0KICBmb250LXN0eWxlOiBpdGFsaWN9DQoNCmJvZHkgew0KICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgZm9udC1zaXplOiAxOHB4Ow0KICANCn0NCnA6bm90KGgxKTpub3QoaDIpOm5vdChoMyk6bm90KGg0KTpub3QoaDUpIHsNCiAgdGV4dC1pbmRlbnQ6IDJlbTt9DQpwIHsNCiAgdGV4dC1hbGlnbjoganVzdGlmeTsNCiAgfQ0KLnRvY2lmeS1oZWFkZXIgew0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KYGBgDQoNCiFbXShpbWFnZXMvMThmMmNkZDQ5ZDc2NGUyODE3NjctMDEuanBnKQ0KDQojIENIxq/GoE5HIDE6IEdJ4buaSSBUSEnhu4ZVIMSQ4buAIFTDgEkNCg0KIyMgxJDhurd0IHbhuqVuIMSR4buBIG5naGnDqm4gY+G7qXUNCg0KSGnhu4duIG5heSwgbmhp4buBdSBsxKluaCB24buxYyDEkcOjIMOhcCBk4bulbmcgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgdsOgbyB0cm9uZyBxdcOhIHRyw6xuaCBuZ2hpw6puIGPhu6l1IMSR4buDIGPDsyB0aOG7gyDEkeG6oXQgxJHGsOG7o2Mga+G6v3QgcXXhuqMgdOG7kXQgaMahbiB2w6AgxJHhu5kgY2jDrW5oIHjDoWMgY2FvIGjGoW4uIFR1eSBuaGnDqm4sIGThu68gbGnhu4d1IMSRxrDhu6NjIHRodSB0aOG6rXAgdGjGsOG7nW5nIHLhuqV0IGzhu5tuLCBwaOG7qWMgdOG6oXAsIGPhuqV1IHRyw7pjIGtow7RuZyBwaMO5IGjhu6NwIGhv4bq3YyBjw7MgdGjhu4MgYuG7iyB0aGnhur91IGThu68gbGnhu4d1IGNobyBuw6puIGtow7RuZyB0aOG7gyBuw6BvIMSRxrBhIHbDoG8gbcO0IGjDrG5oIHBow6JuIHTDrWNoIG5nYXkgbOG6rXAgdOG7qWMuIERvIMSRw7MsIGPDoWMgbmjDoCBuZ2hpw6puIGPhu6l1IGPhuqduIHBo4bqjaSB44butIGzDrSB2w6AgYmnhur9uIMSR4buVaSBj4bqldSB0csO6YyBk4buvIGxp4buHdSBzYW8gY2hvIHBow7kgaOG7o3AgduG7m2kgbeG7pWMgdGnDqnUgbmdoacOqbiBj4bupdSwgY8OzIHRo4buDIG7Ds2kgxJHDonkgY2jDrW5oIGzDoCBt4buZdCBwaOG6p24ga2jDoSBwaOG7qWMgdOG6oXAgdsOgIG3huqV0IG5oaeG7gXUgdGjhu51pIGdpYW4gdHJvbmcgbeG7mXQgY8O0bmcgdHLDrG5oIG5naGnDqm4gY+G7qXUgYuG7n2kgdsOsIGLhu5kgZOG7ryBsaeG7h3UgcXXDoSBs4bubbiB2w6AgY2jhu6lhIG5oaeG7gXUgYmnhur9uIGtow6FjIG5oYXUgY2jGsGEgxJHDoXAg4bupbmcgxJHGsOG7o2Mgbmh1IGPhuqd1IGPhu6dhIG5nxrDhu51pIHPhu60gZOG7pW5nLiBDaMOtbmggdsOsIHRo4bq/LCBo4buNIGx1w7RuIHTDrG0ga2nhur9tIGNobyBtw6xuaCBt4buZdCBjw7RuZyBj4bulIHThu5FpIMawdSDEkeG7gyBk4buFIGTDoG5nIGNodeG6qW4gaMOzYSB2w6AgbMOgbSBz4bqhY2ggZOG7ryBsaeG7h3UgxJHhu5NuZyB0aOG7nWkgdGnhur90IGtp4buHbSB0aOG7nWkgZ2lhbiwgY8O0bmcgc+G7qWMgbcOgIHbhuqtuIMSR4bqhdCBoaeG7h3UgcXXhuqMgY2FvLg0KDQpOaOG6rW4gdGjhuqV5IHbhuqVuIMSR4buBIMSRxrDhu6NjIG7Ds2kgdHLDqm4gY2jDum5nIGVtIHRo4buxYyBoaeG7h24gbmdoacOqbiBj4bupdSB24buBIGfDs2kgIlRpZHlyIiwgxJHDonkgbMOgIG3hu5l0IGPDtG5nIGPhu6UgbcOjbmggbeG6vSBo4buXIHRy4bujIG3hu41pIG5nxrDhu51pIGPDsyB0aOG7gyBjaHXhuqluIGjDs2EsIGJp4bq/biDEkeG7lWkgY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UgZOG7sWEgdsOgbyDEkeG7i25oIGThuqFuZyB0aWR5IGRhdGEsIHRyb25nIMSRw7MgdGjDrCBt4buXaSBj4buZdCBk4buvIGxp4buHdSDEkeG6oWkgZGnhu4duIGNobyBt4buZdCBiaeG6v24sIG3hu5dpIGjDoG5nIMSR4bqhaSBkaeG7h24gY2hvIG3hu5l0IHF1YW4gc8OhdCB2w6AgbeG7l2kgw7QgdGjDrCBjaOG7qWEgbeG7mXQgZ2nDoSB0cuG7iyBj4bulIHRo4buDIMSRaeG7gXUgbsOgeSBz4bq9IGdpw7pwIHZp4buHYyBwaMOibiB0w61jaCB2w6AgdHLhu7FjIHF1YW4gaMOzYSBk4buvIGxp4buHdSB0cuG7nyBuw6puIGThu4UgZMOgbmcgaMahbi4gSMahbiB0aOG6vywgbsOzIGPFqW5nIGPDsyB0aOG7gyBo4buXIHRy4bujIHTDoWNoLCBnaMOpcCB2w6AgaG/DoG4gY2jhu4luaCBk4buvIGxp4buHdSBjw7JuIHRoaeG6v3UgYuG6sW5nIG5o4buvbmcgY8O6IHBow6FwIMSRxqFuIGdp4bqjbiwgcsO1IHLDoG5nIHThu6sgxJHDsyBt4buNaSBuZ8aw4budaSBjw7MgdGjhu4MgdGnhur9uIGjDoG5oIHBow6JuIHTDrWNoIGPDoWMgbcO0IGjDrG5oLiBHw7NpIFRpZHlyIGzDoCBt4buZdCBjw7RuZyBj4bulIHThu5FpIMawdSwgxJFhIG7Eg25nLCBjw7ogcGjDoXAgxJHGoW4gZ2nhuqNuIHbDoCBuaOG6rW4gxJHGsOG7o2Mgc+G7rSBo4buXIHRy4bujIHBow6F0IHRyaeG7g24gdOG7qyBj4buZbmcgxJHhu5NuZyBSLCB2w6wgdGjhur8gbsOzIGPDsyB0aOG7gyBnaeG6o2kgcXV54bq/dCBuaGnhu4F1IHbhuqVuIMSR4buBIHRyb25nIHF1w6EgdHLDrG5oIHjhu60gbMO9IGThu68gbGnhu4d1IHRyb25nIG5oaeG7gXUgbMSpbmggduG7sWMuIENo4bqzbmcgaOG6oW4gbmjGsCB0cm9uZyB0w6BpIGNow61uaCBnw7NpIHRpZHlyIGPDsyB0aOG7gyBnacO6cCBjaMO6bmcgdGEgdOG7lSBjaOG7qWMgdsOgIHPhuq9wIHjhur9wIGzhuqFpIGThu68gbGnhu4d1IHbhu4EgY+G7lSBwaGnhu4N1IGPhu6dhIG3hu5l0IG5nw6BuaCDEkeG7gyDEkcOhbmggZ2nDoSB0w6xuaCBow6xuaCBob+G6oXQgxJHhu5luZyB2w6AgeMOieSBk4buxbmcgbcO0IGjDrG5oIGThu7EgYsOhby4gVHJvbmcgbMSpbmggduG7sWMga2luaCB04bq/IHRow6wgbsOzIGdpw7pwIGJp4bq/biDEkeG7lWkgZOG7ryBsaeG7h3UgduG7gSBHRFAsIHRoxrDGoW5nIG3huqFpLCBz4bqjbiB4deG6pXQgdsOgIG3hu5l0IHPhu5EgY2jhu4kgc+G7kSBraW5oIHThur8ga2jDoWMgY+G7p2EgY8OhYyBxdeG7kWMgZ2lhIHRoZW8gbsSDbSDEkeG7gyDEkcOhbmggZ2nDoSB04buRYyDEkeG7mSBwaMOhdCB0cmnhu4NuIHbDoCB04buVbmcgcXVhbiB24buBIG3hu5FpIHF1YW4gaOG7hyBraW5oIHThur8gZ2nhu69hIGPDoWMgcXXhu5FjIGdpYS4gUXVhIMSRw7MsIHRhIHRo4bqleSBy4bqxbmcgbOG7o2kgw61jaCBtw6AgZ8OzaSBUaWR5ciBtYW5nIGzhuqFpIHRyb25nIGdpYWkgxJFv4bqhbiBjaHXhuqluIGjDs2EgZOG7ryBsaeG7h3UgbMOgIHbDtCBjw7luZyB0byBs4bubbiwgdGnhur90IGtp4buHbSDEkcaw4bujYyBy4bqldCBuaGnhu4F1IHRo4budaSBnaWFuIHbDoCBjdW5nIGPhuqVwIGvhur90IHF14bqjIHBow6JuIHTDrWNoIGPDsyDEkeG7mSBjaMOtbmggeMOhYyBjYW8gaMahbi4NCg0KIyMgTMO9IGRvIGNo4buNbiDEkeG7gSB0w6BpDQoNClRyb25nIHF1w6EgdHLDrG5oIHRo4buxYyBow6BuaCB24bubaSBuaGnhu4F1IGThu68gbGnhu4d1IHBo4bupYyB04bqhcCBuaMOzbSBlbSBuaOG6rW4gdGjhuqV5IHZp4buHYyB44butIGzDvSBk4buvIGxp4buHdSBn4bq3cCBuaGnhu4F1IGtow7Mga2jEg24sIOG6o25oIGjGsOG7n25nIMSR4bq/biBr4bq/dCBxdeG6oyBjxaluZyBuaMawIGzDoCB0aOG7nWkgZ2lhbiB0aOG7sWMgaGnhu4duLiBOZ2hpw6puIGPhu6l1IHbhu4EgZ8OzaSBUaWR5ciBz4bq9IGdpw7pwIHZp4buHYyBjaHXhuqluIGjDs2EgdsOgIGJp4bq/biDEkeG7lWkgY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UgdHLhu58gbsOqbiBk4buFIGTDoG5nIGjGoW4sIGPDoWMgY8O6IHBow6FwIHTGsMahbmcgxJHhu5FpIMSRxqFuIGdp4bqjbiB2w6AgcsO1IHLDoG5nIGtow7RuZyDEkcOyaSBo4buPaSBraeG6v24gdGjhu6ljIGNodXnDqm4gc8OidS4gTmdvw6BpIHJhLCBUaWR5ciBjdW5nIGPhuqVwIGNobyBuZ8aw4budaSBz4butIGThu6VuZyBy4bqldCBuaGnhu4F1IGNo4bupYyBuxINuZyBraMOhYyBuaGF1LCBuw7MgZ2nDunAgbmfGsOG7nWkgZMO5bmcgZOG7hSBkw6BuZyB44butIGzDvSBk4buvIGxp4buHdSBraMO0bmcgxJHhu5NuZyBuaOG6pXQsIGtow7RuZyBj4bqldSB0csO6YyBob+G6t2MgdGhp4bq/dSBk4buvIGxp4buHdSwgdOG6oW8gxJFp4buBdSBraeG7h24gdGh14bqtbiBs4bujaSBjaG8gdmnhu4djIHBow6JuIHTDrWNoIHbDoCB0cuG7sWMgcXVhbiBow7NhIGThu68gbGnhu4d1LiBD4buZbmcgxJHhu5NuZyBSIGzDoCBt4buZdCBj4buZbmcgxJHhu5NuZyBs4bubbiB24buBIG5nw7RuIG5n4buvIGzhuq1wIHRyw6xuaCwgaOG7jSB0aMaw4budbmcgeHV5w6puIGPhuq1wIG5o4bqtcCwgcGjDoXQgdHJp4buDbiBnw7NpIFRpZHlyIG5nw6B5IGPDoG5nIHThu5FpIMawdSBoxqFuLCDEkWnhu4F1IG7DoHkga2hp4bq/biBjaG8gbmjDs20gZW0gaOG7jWMgdOG6rXAgdGjDqm0gbmhp4buBdSBraeG6v24gdGjhu6ljIHbhu4EgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UgdsOgIHPhu60gZOG7pW5nIGfDs2kgbsOgeSBt4buZdCBjw6FjaCBoaeG7h3UgcXXhuqMgbmjhuqV0IHRyb25nIGPDtG5nIHZp4buHYyB0cm9uZyB0xrDGoW5nIGxhaS4gSMahbiB0aOG6vywgVGlkeXIgxJHGsOG7o2MgdGhp4bq/dCBr4bq/IGTDuW5nIMSR4buDIGdp4bqjaSBxdXnhur90IGPDoWMgduG6pW4gxJHhu4EgcGjhu5UgYmnhur9uIHbDoCB0aOG7sWMgdOG6vyDhu58gbmhp4buBdSBsxKluaCB24buxYyBraMOhYyBuaGF1LCBt4bq3YyBkw7kgZOG7ryBsaeG7h3UgbmdoacOqbiBj4bupdSBrw61jaCB0aMaw4bubYyBs4bubbiB0aMOsIG7DsyB24bqrbiB44butIGzDvSBoaeG7h3UgcXXhuqMgdsOgIHRp4bq/dCBraeG7h20gxJHGsOG7o2Mgbmhp4buBdSB0aOG7nWkgZ2lhbi4gVsOsIHRo4bq/LCBuaMOzbSBlbSB0aW4gcuG6sW5nIHTDrG0gaGnhu4N1IHbhu4EgZ8OzaSBUaWR5ciBsw6AgY2jhu6cgxJHhu4EgaOG7r3Ugw61jaCBjw7MgdGjhu4MgaOG7lyB0cuG7oyBt4buNaSBuZ8aw4budaSDEkWFuZyBn4bq3cCBraMOzIGtoxINuIHRyb25nIHZp4buHYyB44butIGzDvSBk4buvIGxp4buHdS4NCg0KIyMgR2nhu5tpIHRoaeG7h3UgduG7gSBnw7NpIFRpZHlyDQoNCiMjIyBOZ3Xhu5NuIGfhu5FjDQoNCkfDs2kgdGlkeXIgbMOgIG3hu5l0IHBo4bqnbiBj4bunYSBUaWR5dmVyc2UsIG3hu5l0IGLhu5kgc8awdSB04bqtcCBjw6FjIGfDs2kgUiDEkcaw4bujYyB0aGnhur90IGvhur8gY2hvIHZp4buHYyB44butIGzDvSB2w6AgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UuIEfDs2kgdGlkeXIgdOG6rXAgdHJ1bmcgY2jhu6cgeeG6v3UgdsOgbyBjw6FjIGhv4bqhdCDEkeG7mW5nIGzDoG0gZ+G7jW4gZ8OgbmcgdsOgIGPhuqV1IHRyw7pjIGzhuqFpIGThu68gbGnhu4d1LCBnacO6cCBk4buFIGTDoG5nIGNodXnhu4NuIMSR4buVaSB04bqtcCBk4buvIGxp4buHdSB0aMOgbmggxJHhu4tuaCBk4bqhbmcgdGlkeSAoZ+G7jW4gZ8OgbmcpIHRodeG6rW4gdGnhu4duIGjGoW4gY2hvIHBow6JuIHTDrWNoIHbDoCB0cuG7sWMgcXVhbiBow7NhLg0KDQpHw7NpIHRpZHlyIMSRxrDhu6NjIHBow6F0IHRyaeG7g24gYuG7n2kgSGFkbGV5IFdpY2toYW0sIG3hu5l0IG5ow6AgdGjhu5FuZyBrw6ogdsOgIG5ow6Aga2hvYSBo4buNYyBk4buvIGxp4buHdSBu4buVaSB0aeG6v25nIHbhu5tpIMSRw7NuZyBnw7NwIGNobyBuZ8O0biBuZ+G7ryBs4bqtcCB0csOsbmggUiB2w6Aga2jDoWkgbmnhu4dtIGThu68gbGnhu4d1IHRpZHkuIEhhZGxleSBXaWNraGFtIGPFqW5nIGzDoCBuZ8aw4budaSBzw6FuZyB04bqhbyByYSBjw6FjIGfDs2kgcGjhu5UgYmnhur9uIGtow6FjIG5oxrAgZ2dwbG90MiB2w6AgZHBseXIuIMOUbmcgxJHDoyBwaMOhdCB0cmnhu4NuIHRpZHlyIG5oxrAgbeG7mXQgcGjhuqduIGPhu6dhIG7hu5cgbOG7sWMgY+G7p2EgbcOsbmggxJHhu4MgdGjDumMgxJHhuql5IG5ndXnDqm4gdOG6r2MgY+G7p2EgZOG7ryBsaeG7h3UgdGlkeSwgbmjhuqVuIG3huqFuaCB2aeG7h2MgdOG7lSBjaOG7qWMgdsOgIHPhuq9wIHjhur9wIGThu68gbGnhu4d1IHRoZW8gbeG7mXQgY+G6pXUgdHLDumMgbmjhuqV0IHF1w6FuIMSR4buDIHThuqFvIHRodeG6rW4gbOG7o2kgY2hvIHBow6JuIHTDrWNoIHbDoCB0cnV54buBbiB04bqjaSB0aMO0bmcgdGluLg0KDQojIyMgQ2jhu6ljIG7Eg25nDQoNCkfDs2kgdGlkeXIgY3VuZyBj4bqlcCBt4buZdCBsb+G6oXQgY8OhYyBow6BtIGjhu5cgdHLhu6MgY2jDum5nIHRhIHRyb25nIHZp4buHYyBsw6BtIGfhu41uIHbDoCB0w6FpIGPhuqV1IHRyw7pjIGThu68gbGnhu4d1LiBDw6FjIGjDoG0gbsOgeSBjw7MgdGjhu4MgxJHGsOG7o2MgbmjDs20gdGjDoG5oIG3hu5l0IHPhu5EgZGFuaCBt4bulYyBjaMOtbmgsIG3hu5dpIGRhbmggbeG7pWMgcGjhu6VjIHbhu6UgY2hvIG3hu5l0IG3hu6VjIMSRw61jaCBj4bulIHRo4buDIHRyb25nIHZp4buHYyBjaOG7iW5oIHPhu61hIHbDoCB04buVIGNo4bupYyBk4buvIGxp4buHdS4NCg0KIyMjIyBUw6FjaCBk4buvIGxp4buHdQ0KDQpUcm9uZyBnw7NpIHRpZHlyIGjhu5cgdHLhu6MgbmfGsOG7nWkgZMO5bmcgdMOhY2ggZOG7ryBsaeG7h3UgbeG7mXQgY+G7mXQgdGjDoG5oIG5oaeG7gXUgY+G7mXQgZOG7sWEgdHLDqm4gbmjhu69uZyBrw70gdOG7sSBwaMOibiB0w6FjaCBob+G6t2MgY8OhYyBt4bqrdSBi4bqxbmcgaMOgbSBgc2VwYXJhdGVgLCDEkWnhu4F1IG7DoHkgdGjhu7FjIHPhu7EgaOG7r3Ugw61jaCBraGkgYuG6oW4gY8OzIG3hu5l0IGPhu5l0IGNo4bupYSBjw6FjIGdpw6EgdHLhu4sga+G6v3QgaOG7o3AgduG7m2kgbmhhdSBsw6BtIGNobyB2aeG7h2MgcGjDom4gdMOtY2ggZ+G6t3Agbmhp4buBdSBraMOzIGtoxINuIHbDoCBi4bqhbiBtdeG7kW4gcGjDom4gdMOhY2ggbsOzIHJhIHRow6BuaCBuaOG7r25nIGPhu5l0IHJpw6puZyBiaeG7h3QuIENo4bqzbmcgaOG6oW4sIG3hu5l0IGPhu5l0IGNo4bupYSB0aMO0bmcgdGluIHbhu4EgbmfDoHkgdGjDoW5nIG7Eg20gc2luaCDEkeG7gyBiaeG6v3QgY2hpIHRp4bq/dCBoxqFuIHRhIGPDsyB0aOG7gyBz4butIGThu6VuZyBow6BtIHNlcGFyYXRlIMSR4buDIHTDoWNoIHJpw6puZyBsw6BtIGJhIGPhu5l0IG5nw6B5LCB0aMOhbmcsIG7Eg20gxJHhu4MgcGjhu6VjIHbhu6UgY2hvIG3hu6VjIMSRw61jaCBjw7RuZyB2aeG7h2MgY+G7pSB0aOG7gy4gTmdvw6BpIHJhLCBjaOG7qWMgbsSDbmcgbsOgeSBraMO0bmcgbMOgbSB0aGF5IMSR4buVaSBk4buvIGxp4buHdSBn4buRYyBtw6AgY2jhu4kgdOG6oW8gcmEgY8OhYyBj4buZdCBt4bubaSB04burIGThu68gbGnhu4d1IGJhbiDEkeG6p3UsIMSRaeG7gXUgbsOgeSBjaG8gcGjDqXAgY2jDum5nIHRhIGJp4bq/biDEkeG7lWkgduG7gSBk4buvIGxp4buHdSBn4buRYyBk4buFIGTDoG5nIGjGoW4gbuG6v3UgbXXhu5FuLg0KDQojIyMjIEvhur90IGjhu6NwIGPhu5l0DQoNClRyw6FpIG5nxrDhu6NjIHbhu5tpIGNo4bupYyBuxINuZyB0w6FjaCBj4buZdCwgZ8OzaSBUaWR5ciBz4bq9IGdpw7pwIGNow7puZyB0YSBr4bq/dCBo4bujcCBjw6FjIGPhu5l0IGzhuqFpIHRow6BuaCBt4buZdCBj4buZdCBi4bqxbmcgY8OhY2ggZ2jDqXAgY8OhYyBnacOhIHRy4buLIGPhu6dhIGNow7puZyBs4bqhaSB24bubaSBuaGF1LiBHaeG6oyBz4butIHRhIGPDsyBt4buZdCBj4buZdCBjaOG7qWEgaOG7jSB2w6AgbeG7mXQgY+G7mXQgY2jhu6lhIHTDqm4gdGjDrCBjw7MgdGjhu4MgZ2jDqXAgaGFpIGPhu5l0IG7DoHkgdGjDoG5oIG3hu5l0IGPhu5l0IGjhu40gdsOgIHTDqm4gaG/DoG4gY2jhu4luaCBi4bqxbmcgaMOgbSBgdW5pdGVgLCDEkWnhu4F1IG7DoHkgc+G6vSBnacO6cCBk4buvIGxp4buHdSB0cuG7nyBuw6puIGfhu41uIGfDoG5nIHbDoCBwaMO5IGjhu6NwIMSR4buDIHPhu60gZOG7pW5nLiDEkMOieSBsw6AgbeG7mXQgY2jhu6ljIG7Eg25nIGThu4UgZMOgbmcgc+G7rSBk4bulbmcgdHV5IG5oacOqbiB04bqhbyByYSBj4buZdCBt4bubaSBjw7MgxJHhu5kgbGluaCBob+G6oXQgY2FvLCB0aHXhuq1uIHRp4buHbiB0cm9uZyBxdcOhIHRyw6xuaCB44butIGzDvS4NCg0KIyMjIyBQaXZvdGluZyhCaeG6v24gxJHhu5VpKQ0KDQotICAgIlBpdm90aW5nIiAoQ2h1eeG7g24gxJHhu5VpKTogY2h1eeG7g24gxJHhu5VpIGdp4buvYSBjw6FjIGThuqFuZyBk4buvIGxp4buHdSBy4buZbmcgdsOgIGTDoGkuIHRpZHlyIGdp4bubaSB0aGnhu4d1IHBpdm90X2xvbmdlcigpIHbDoCBwaXZvdF93aWRlcigpLCB0aGF5IHRo4bq/IGPDoWMgaMOgbSBzcHJlYWQoKSB2w6AgZ2F0aGVyKCkuIFF1w6EgdHLDrG5oIGJp4bq/biDEkeG7lWkgbsOgeSDEkeG6t2MgYmnhu4d0IGjhu691IMOtY2gga2hpIGLhuqFuIGPhuqduIHRoYXkgxJHhu5VpIGPhuqV1IHRyw7pjIGThu68gbGnhu4d1IMSR4buDIHBow7kgaOG7o3AgaMahbiB24bubaSBt4bulYyDEkcOtY2ggcGjDom4gdMOtY2ggaG/hurdjIHRy4buxYyBxdWFuIGjDs2EuDQoNCi0gICBCaeG6v24gxJHhu5VpIHThu6sgZOG6oW5nIETDoGkgc2FuZyBS4buZbmc6IEtoaSBk4buvIGxp4buHdSDhu58gxJHhu4tuaCBk4bqhbmcgZMOgaSwgbeG7l2kgcXVhbiBzw6F0IMSRxrDhu6NjIGJp4buDdSBkaeG7hW4gYuG6sW5nIG5oaeG7gXUgaMOgbmcgdsOgIGPDsyBjw6FjIGPhu5l0IHjDoWMgxJHhu4tuaCByacOqbmcgYmnhu4d0IGxpw6puIGvhur90IG5o4buvbmcgaMOgbmcgbsOgeSBs4bqhaSB24bubaSBuaGF1LiBEbyDEkcOzLCBow6BtIHBpdm90X3dpZGVyKCkgc+G6vSBnacO6cCB0YSBjaHV54buDbiDEkeG7lWkgZOG7ryBsaeG7h3UgdOG7qyDEkeG7i25oIGThuqFuZyBkw6BpIHNhbmcgxJHhu4tuaCBk4bqhbmcgcuG7mW5nIGLhurFuZyBjw6FjaCBwaMOibiBy4bqjaSBnacOhIHRy4buLLCDEkWnhu4F1IG7DoHkgcGjhu6UgdGh14buZYyB2w6BvIG3hu6VjIHRpw6p1IHBow6JuIHTDrWNoIGLhu5kgZOG7ryBsaeG7h3UgY+G7p2EgbmfGsOG7nWkgc+G7rSBk4bulbmcuDQoNCi0gICBCaeG6v24gxJHhu5VpIHThu6sgZOG6oW5nIFLhu5luZyBzYW5nIETDoGk6IE5nxrDhu6NjIGzhuqFpLCBraGkgZOG7ryBsaeG7h3Ug4bufIMSR4buLbmggZOG6oW5nIHLhu5luZywgbeG7l2kgcXVhbiBzw6F0IMSRxrDhu6NjIGJp4buDdSBkaeG7hW4gYuG6sW5nIG3hu5l0IGjDoG5nIMSRxqFuIHbDoCBjw6FjIGJp4bq/biBraMOhYyBuaGF1IMSRxrDhu6NjIGzGsHUgdHLhu68gdHJvbmcgY8OhYyBj4buZdCByacOqbmcgYmnhu4d0LiBIw6BtIHBpdm90X2xvbmdlcigpIHPhur0gZ2nDunAgQ2h1eeG7g24gxJHhu5VpIGThu68gbGnhu4d1IHThu6sgxJHhu4tuaCBk4bqhbmcgcuG7mW5nIHNhbmcgxJHhu4tuaCBk4bqhbmcgZMOgaSBi4bqxbmcgY8OhY2ggZ29tIGzhuqFpIGPDoWMgY+G7mXQgxJHhu4MgY8OzIHRo4buDIHBow7kgaOG7o3AgduG7m2kgbmh1IGPhuqd1IGPhu6dhIG5nxrDhu51pIHRo4buxYyBoaeG7h24uDQoNCiMjIyMgWOG7rSBsw60gZ2nDoSB0cuG7iyB0aGnhur91DQoNClZp4buHYyBwaMOibiB0w61jaCBk4buvIGxp4buHdSBz4bq9IGtow7RuZyDEkeG6oXQgxJHGsOG7o2Mga+G6v3QgcXXhuqMgY2jDrW5oIHjDoWMgbuG6v3UgZOG7ryBsaeG7h3UgZ+G6t3AgcGjhuqNpIG5o4buvbmcgZ2nDoSB0cuG7iyBi4buLIHRoaeG6v3Ugc8OzdCwgxJHhu4Mga2jhuq9jIHBo4bulYyB0w6xuaCB0cuG6oW5nIG5oxrAgduG6rXkgdGjDrCBnw7NpIG7DoHkgZ2nDunAgbmfGsOG7nWkgc+G7rSBk4bulbmcgeOG7rSBsw70gbmjhu69uZyBkw7JuZyBi4buLIHRoaeG6v3UgZ2nDoSB0cuG7iyBi4bqxbmcgaMOgbSBgY29tcGxldGVgLCBow6BtIG7DoHkgc+G6vSBr4bq/dCBo4bujcCBjw6FjIGdpw6EgdHLhu4sga2jDtG5nIGLhu4sgdGhp4bq/dSB0cm9uZyBjw6FjIGPhu5l0IGNo4buJIMSR4buLbmggdOG7qyDEkcOzIMSRaeG7gW4gdsOgbyBuaOG7r25nIGTDsm5nIGLhu4sgdGhp4bq/dS4gSMahbiBu4buvYSwgdGEgY8OzIHRo4buDIGxv4bqhaSBi4buPIGPDoWMgZ2nDoSB0cuG7iyB0aGnhur91IGLhurFuZyBow6BtIGRyb3BfbmEgaG/hurdjIHRoYXkgdGjhur8gY8OhYyBnacOhIHRy4buLIGLhu4sgdGhp4bq/dSBi4bqxbmcgaMOgbSBgZmlsbGAsIGByZXBsYWNlX25hYC4NCg0KIyMjIyBOZXN0aW5nKEfhu5lwKSB2w6AgVW5uZXN0aW5nKGtow7RpIHBo4bulYykNCg0KTmVzdCgpIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIHThuqFvIG3hu5l0IGtodW5nIGThu68gbGnhu4d1IGzhu5NuZyBuaGF1IGLhurFuZyBjw6FjaCBuaMOzbSBk4buvIGxp4buHdSBk4buxYSB0csOqbiBjw6FjIGJp4bq/biBj4bulIHRo4buDLiBOw7MgY2hvIHBow6lwIGLhuqFuIG5ow7NtIGPDoWMgcXVhbiBzw6F0IGxpw6puIHF1YW4gduG7m2kgbmhhdSB0cm9uZyBt4buZdCBj4buZdCBkdXkgbmjhuqV0Lg0KDQpVbm5lc3QoKSDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyBt4bufIHLhu5luZyBt4buZdCBraHVuZyBk4buvIGxp4buHdSBs4buTbmcgbmhhdSB0aMOgbmggbeG7mXQga2h1bmcgZOG7ryBsaeG7h3UgdGjDtG5nIHRoxrDhu51uZywgdHJvbmcgxJHDsyBt4buXaSBxdWFuIHPDoXQgbOG7k25nIG5oYXUgdHLhu58gdGjDoG5oIG3hu5l0IGTDsm5nIHJpw6puZy4gTsOzIHRyw61jaCB4deG6pXQgZOG7ryBsaeG7h3UgbOG7k25nIG5oYXUgdsOgIG3hu58gcuG7mW5nIGNow7puZyB0aMOgbmggbmhp4buBdSBkw7JuZy4NCg0KIyMjIE3hu6VjIHRpw6p1DQoNCk3hu6VjIHRpw6p1IGNow61uaCBj4bunYSB0aWR5ciBsw6AgY3VuZyBj4bqlcCBt4buZdCBi4buZIGPDtG5nIGPhu6UgduG7m2kgY8OhYyBjaOG7qWMgbsSDbmcgxJHGoW4gZ2nhuqNuIGjDs2EgcXXDoSB0csOsbmggY+G6pXUgdHLDumMgbOG6oWkgdsOgIGzDoG0gZ+G7jW4gZOG7ryBsaeG7h3UuIEfDs2kgbsOgeSBjdW5nIGPhuqVwIGPDoWMgY2jhu6ljIG7Eg25nIG5oxrAgZ2F0aGVyKCksIHNwcmVhZCgpLCBzZXBhcmF0ZSgpLCB1bml0ZSgpLCBwaXZvdF9sb25nZXIoKSB2w6AgcGl2b3Rfd2lkZXIoKSwgY2hvIHBow6lwIG5nxrDhu51pIGTDuW5nIGNodXnhu4NuIMSR4buVaSBk4buvIGxp4buHdSBnaeG7r2EgY8OhYyDEkeG7i25oIGThuqFuZyBy4buZbmcgdsOgIGTDoGksIHBow6JuIHTDoWNoIHbDoCBr4bq/dCBo4bujcCBj4buZdCwgdsOgIGNodXnhu4NuIMSR4buVaSBk4buvIGxp4buHdSDEkeG7gyB04bqhbyBi4bqjbmcgdMOzbSB04bqvdC4gQ8OhYyBob+G6oXQgxJHhu5luZyBuw6B5IGzDoCBj4bqnbiB0aGnhur90IMSR4buDIHThu5UgY2jhu6ljIHbDoCB44butIGzDvSBk4buvIGxp4buHdSBt4buZdCBjw6FjaCBk4buFIGTDoG5nIHbDoCB0csOtY2ggeHXhuqV0IHRow7RuZyB0aW4uDQoNCkfDs2kgdGlkeXIgxJHDoyB0aHUgaMO6dCBz4buxIHF1YW4gdMOibSDEkcOhbmcga+G7gyB0cm9uZyBj4buZbmcgxJHhu5NuZyBSIG5o4budIGPDuiBwaMOhcCBk4buFIGhp4buDdSB2w6AgbmjhuqV0IHF1w6FuLCBwaMO5IGjhu6NwIHbhu5tpIG5ndXnDqm4gdOG6r2MgY+G7p2EgVGlkeXZlcnNlLiBOw7MgxJHDoyB0cuG7nyB0aMOgbmggbeG7mXQgY8O0bmcgY+G7pSDEkcaw4bujYyBz4butIGThu6VuZyBy4buZbmcgcsOjaSDEkeG7gyBsw6BtIHPhuqFjaCBk4buvIGxp4buHdSwgdGnhu4FuIHjhu60gbMO9IHbDoCBj4bqldSB0csO6YyBs4bqhaSB0cm9uZyBxdXkgdHLDrG5oIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IGLhurFuZyBSLg0KDQojIyMgTOG7o2kgw61jaA0KDQpDw6FjIGzhu6NpIMOtY2ggY+G7p2Egdmnhu4djIHPhu60gZOG7pW5nIGfDs2kgdGlkeXIgYmFvIGfhu5NtOg0KDQotICAgROG7hSBkw6BuZyBsw6BtIHPhuqFjaCBk4buvIGxp4buHdTogR8OzaSB0aWR5ciBjdW5nIGPhuqVwIGPDoWMgaMOgbSDEkcahbiBnaeG6o24gdsOgIGThu4UgaGnhu4N1IMSR4buDIGPhuqV1IHRyw7pjIGzhuqFpIHbDoCBsw6BtIGfhu41uIGThu68gbGnhu4d1LiBOw7MgY3VuZyBj4bqlcCBjw6FjIGNo4bupYyBuxINuZyBuaMawIGdhdGhlcigpLCBzcHJlYWQoKSwgc2VwYXJhdGUoKSwgdW5pdGUoKSwgcGl2b3RfbG9uZ2VyKCksIHbDoCBwaXZvdF93aWRlcigpIGNobyBwaMOpcCBuZ8aw4budaSBkw7luZyBk4buFIGTDoG5nIGNodXnhu4NuIMSR4buVaSBk4buvIGxp4buHdSBnaeG7r2EgY8OhYyDEkeG7i25oIGThuqFuZyBy4buZbmcgdsOgIGTDoGksIHBow6JuIHTDoWNoIHbDoCBr4bq/dCBo4bujcCBj4buZdCwgdsOgIGJp4bq/biDEkeG7lWkgZOG7ryBsaeG7h3UgxJHhu4MgdOG6oW8gYuG6o25nIHTDs20gdOG6r3QuIE5o4buvbmcgdGhhbyB0w6FjIG7DoHkgbMOgIGPhuqduIHRoaeG6v3QgxJHhu4MgdOG7lSBjaOG7qWMgdsOgIHjhu60gbMO9IGThu68gbGnhu4d1IG3hu5l0IGPDoWNoIGhp4buHdSBxdeG6oy4NCg0KLSAgIFTDrWNoIGjhu6NwIHbhu5tpIHRpZHl2ZXJzZTogR8OzaSB0aWR5ciBsw6AgbeG7mXQgcGjhuqduIGPhu6dhIGjhu4cgc2luaCB0aMOhaSB0aWR5dmVyc2UsIGzDoCBt4buZdCBi4buZIHPGsHUgdOG6rXAgY8OhYyBnw7NpIFIgxJHGsOG7o2MgdGhp4bq/dCBr4bq/IGNobyB2aeG7h2MgbMOgbSBz4bqhY2ggdsOgIHBow6JuIHTDrWNoIGThu68gbGnhu4d1LiBOw7MgdMOtY2ggaOG7o3AgbeG7mXQgY8OhY2ggbcaw4bujdCBtw6AgduG7m2kgY8OhYyBnw7NpIHRpZHl2ZXJzZSBraMOhYyBuaMawIGRwbHlyIHbDoCBnZ3Bsb3QyLCBjaG8gcGjDqXAgcXV5IHRyw6xuaCBsw6BtIHZp4buHYyBtxrDhu6N0IG3DoCB2w6AgY8O6IHBow6FwIG5o4bqldCBxdcOhbi4gVMOtY2ggaOG7o3AgbsOgeSBjaG8gcGjDqXAgbmfGsOG7nWkgZMO5bmcgdGjhu7FjIGhp4buHbiBjw6FjIHRoYW8gdMOhYyBwaOG7qWMgdOG6oXAgdHLDqm4gZOG7ryBsaeG7h3UgdsOgIHThuqFvIGJp4buDdSDEkeG7kyBt4buZdCBjw6FjaCBuaOG6pXQgcXXDoW4gdsOgIGhp4buHdSBxdeG6oy4NCg0KLSAgIFTGsMahbmcgdGjDrWNoIHbhu5tpIG5ndXnDqm4gdOG6r2MgZOG7ryBsaeG7h3UgdGlkeTogR8OzaSB0aWR5ciB0dcOibiB0aOG7pyBuZ3V5w6puIHThuq9jIGPhu6dhIGThu68gbGnhu4d1IHRpZHksIG5o4bqlbiBt4bqhbmggdmnhu4djIHThu5UgY2jhu6ljIGThu68gbGnhu4d1IHRoZW8gbeG7mXQgY+G6pXUgdHLDumMgbmjhuqV0IHF1w6FuLiBC4bqxbmcgY8OhY2ggdHXDom4gdGjhu6cgbmd1ecOqbiB04bqvYyBk4buvIGxp4buHdSB0aWR5LCBuZ8aw4budaSBkw7luZyBjw7MgxJHGsOG7o2MgZOG7ryBsaeG7h3UgcsO1IHLDoG5nIGjGoW4sIGThu4Uga2jDoW0gcGjDoSBoxqFuIHbDoCBr4bq/dCBxdeG6oyBwaMOibiB0w61jaCDEkcOhbmcgdGluIGPhuq15IGjGoW4uIEThu68gbGnhu4d1IHRpZHkgxJHhuqNtIGLhuqNvIG3hu5dpIGJp4bq/biBjw7MgbeG7mXQgY+G7mXQgcmnDqm5nLCBt4buXaSBxdWFuIHPDoXQgY8OzIG3hu5l0IGjDoG5nIHJpw6puZyB2w6AgbeG7l2kgw7QgY2jhu6lhIG3hu5l0IGdpw6EgdHLhu4sgZHV5IG5o4bqldC4NCg0KLSAgIEjhu5cgdHLhu6MgcGjDom4gdMOtY2ggdsOgIHRy4buxYyBxdWFuIGjDs2EgZOG7ryBsaeG7h3U6IEThu68gbGnhu4d1IHRpZHkgxJHGoW4gZ2nhuqNuIGjDs2EgcXXDoSB0csOsbmggcGjDom4gdMOtY2ggdsOgIHRy4buxYyBxdWFuIGjDs2EgZOG7ryBsaeG7h3UuIELhurFuZyBjw6FjaCBjaHV54buDbiDEkeG7lWkgZOG7ryBsaeG7h3UgdGjDoG5oIMSR4buLbmggZOG6oW5nIHRpZHksIHZp4buHYyB0aOG7sWMgaGnhu4duIGPDoWMgdMOhYyB24bulIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IHRow7RuZyB0aMaw4budbmcsIMOhcCBk4bulbmcgcGjDom4gdMOtY2ggdGjhu5FuZyBrw6ogdsOgIHThuqFvIGJp4buDdSDEkeG7kyB0aMO0bmcgdGluIHRy4bufIG7Dqm4gZOG7hSBkw6BuZyBoxqFuLiBE4buvIGxp4buHdSB0aWR5IGdp4bqjbSB0aGnhu4N1IHZp4buHYyBwaOG6o2kgbMOgbSB2aeG7h2MgcGjhu6ljIHThuqFwIHbhu5tpIGThu68gbGnhu4d1LCBjaG8gcGjDqXAgY8OhYyBuaMOgIHBow6JuIHTDrWNoIHThuq1wIHRydW5nIG5oaeG7gXUgaMahbiB2w6BvIHZp4buHYyB0csOtY2ggeHXhuqV0IHRow7RuZyB0aW4gdsOgIMSRxrBhIHJhIHF1eeG6v3QgxJHhu4tuaCBk4buxYSB0csOqbiBk4buvIGxp4buHdS4NCg0KVMOzbSBs4bqhaSwgbeG7pWMgdGnDqnUgY2jDrW5oIGPhu6dhIGfDs2kgdGlkeXIgbMOgIGN1bmcgY+G6pXAgY8OhYyBjw7RuZyBj4bulIMSR4buDIGzDoG0gc+G6oWNoIHbDoCBj4bqldSB0csO6YyBs4bqhaSBk4buvIGxp4buHdSwgduG7m2kgbOG7o2kgw61jaCBsw6AgZ2nDunAgbmfGsOG7nWkgZMO5bmcgZOG7hSBkw6BuZyBjaHV54buDbiDEkeG7lWkgZOG7ryBsaeG7h3UgdGjDoG5oIMSR4buLbmggZOG6oW5nIHRpZHkuIMSQaeG7gXUgbsOgeSBo4buXIHRy4bujIHBow6JuIHTDrWNoIGThu68gbGnhu4d1LCB0w61jaCBo4bujcCB24bubaSBjw6FjIGfDs2kgdGlkeXZlcnNlIGtow6FjIHbDoCBo4buXIHRy4bujIG5ndXnDqm4gdOG6r2MgZOG7ryBsaeG7h3UgdGlkeSDEkeG7gyBoaeG7g3UgZOG7ryBsaeG7h3UgdOG7kXQgaMahbiB2w6AgdOG6oW8gcXV5IHRyw6xuaCBsw6BtIHZp4buHYyBoaeG7h3UgcXXhuqMNCg0KIyMjIMavdSB2w6AgbmjGsOG7o2MgxJFp4buDbSBj4bunYSBnw7NpIHRpZHlyDQoNCiMjIyMgxq91IMSRaeG7g20gY+G7p2EgZ8OzaSB0aWR5cg0KDQrEkMahbiBnaeG6o24gaMOzYSB2aeG7h2MgeOG7rSBsw70gZOG7ryBsaeG7h3U6IHRpZHlyIGN1bmcgY+G6pXAgbeG7mXQgYuG7mSBjw7RuZyBj4bulIHbhu5tpIGPDoWMgaMOgbSBk4buFIGhp4buDdSBnacO6cCDEkcahbiBnaeG6o24gaMOzYSBjw7RuZyB2aeG7h2MgY+G6pXUgdHLDumMgbOG6oWkgdsOgIGzDoG0gc+G6oWNoIGThu68gbGnhu4d1LiBOw7MgY3VuZyBj4bqlcCBjw6FjIGjDoG0gbmjGsCBnYXRoZXIoKSwgc3ByZWFkKCksIHNlcGFyYXRlKCksIHVuaXRlKCksIHBpdm90X2xvbmdlcigpIHbDoCBwaXZvdF93aWRlcigpIGNobyBwaMOpcCBuZ8aw4budaSBkw7luZyBk4buFIGTDoG5nIGNodXnhu4NuIMSR4buVaSBk4buvIGxp4buHdSBnaeG7r2EgY8OhYyDEkeG7i25oIGThuqFuZyBy4buZbmcgdsOgIGTDoGksIHBow6JuIHTDoWNoIHbDoCBr4bq/dCBo4bujcCBj4buZdCwgdsOgIGJp4bq/biDEkeG7lWkgZOG7ryBsaeG7h3UgxJHhu4MgdOG6oW8gYuG6o25nIHTDs20gdOG6r3QuIE5o4buvbmcgaG/huqF0IMSR4buZbmcgbsOgeSBsw6AgY+G6p24gdGhp4bq/dCDEkeG7gyB04buVIGNo4bupYyB2w6AgeOG7rSBsw70gZOG7ryBsaeG7h3UgbeG7mXQgY8OhY2ggaGnhu4d1IHF14bqjLg0KDQpUw61jaCBo4bujcCB24bubaSB0aWR5dmVyc2U6IHRpZHlyIGzDoCBt4buZdCBwaOG6p24gY+G7p2EgaOG7hyBzaW5oIHRow6FpIHRpZHl2ZXJzZSwgbeG7mXQgYuG7mSBzxrB1IHThuq1wIGPDoWMgZ8OzaSBSIMSRxrDhu6NjIHRoaeG6v3Qga+G6vyDEkeG7gyBsw6BtIHPhuqFjaCB2w6AgcGjDom4gdMOtY2ggZOG7ryBsaeG7h3UuIE7DsyB0w61jaCBo4bujcCBt4buZdCBjw6FjaCBtxrDhu6N0IG3DoCB24bubaSBjw6FjIGfDs2kgdGlkeXZlcnNlIGtow6FjIG5oxrAgZHBseXIgdsOgIGdncGxvdDIsIGNobyBwaMOpcCBxdXkgdHLDrG5oIGzDoG0gdmnhu4djIHRyxqFuIHRydSB2w6AgY8OzIGPDuiBwaMOhcCBuaOG6pXQgcXXDoW4uIFTDrWNoIGjhu6NwIG7DoHkgY2hvIHBow6lwIG5nxrDhu51pIGTDuW5nIHRo4buxYyBoaeG7h24gY8OhYyBwaMOpcCB0b8OhbiBwaOG7qWMgdOG6oXAgdHLDqm4gZOG7ryBsaeG7h3UgdsOgIHThuqFvIGJp4buDdSDEkeG7kyBt4buZdCBjw6FjaCBuaOG6pXQgcXXDoW4gdsOgIGhp4buHdSBxdeG6oy4NCg0KVHXDom4gdGjhu6cgbmd1ecOqbiB04bqvYyBk4buvIGxp4buHdSB0aWR5OiB0aWR5ciB0dcOibiB0aOG7pyBjw6FjIG5ndXnDqm4gdOG6r2MgY+G7p2EgZOG7ryBsaeG7h3UgdGlkeSwgbmjhuqVuIG3huqFuaCB2aeG7h2MgdOG7lSBjaOG7qWMgZOG7ryBsaeG7h3UgdGjDoG5oIG3hu5l0IGPhuqV1IHRyw7pjIG5o4bqldCBxdcOhbi4gQuG6sW5nIHZp4buHYyB0dcOibiB0aOG7pyBuZ3V5w6puIHThuq9jIGThu68gbGnhu4d1IHRpZHksIG5nxrDhu51pIGTDuW5nIGPDsyBk4buvIGxp4buHdSByw7UgcsOgbmcgaMahbiwga2jDoW0gcGjDoSBk4buvIGxp4buHdSBoaeG7h3UgcXXhuqMgaMahbiB2w6Aga+G6v3QgcXXhuqMgcGjDom4gdMOtY2ggxJHDoW5nIHRpbiBj4bqteSBoxqFuLiBE4buvIGxp4buHdSB0aWR5IMSR4bqjbSBi4bqjbyBy4bqxbmcgbeG7l2kgYmnhur9uIGPDsyBt4buZdCBj4buZdCByacOqbmcsIG3hu5dpIHF1YW4gc8OhdCBjw7MgbeG7mXQgaMOgbmcgcmnDqm5nLCB2w6AgbeG7l2kgw7QgY2jhu6lhIG3hu5l0IGdpw6EgdHLhu4sgZHV5IG5o4bqldC4NCg0KIyMjIyBOaMaw4bujYyDEkWnhu4NtIGPhu6dhIGfDs2kgdGlkeXINCg0KR2nhu5tpIGjhuqFuIGNo4bupYyBuxINuZzogTeG6t2MgZMO5IHRpZHlyIGN1bmcgY+G6pXAgbeG7mXQgdOG6rXAgaOG7o3AgaOG7r3Ugw61jaCBjw6FjIGjDoG0gxJHhu4MgY+G6pXUgdHLDumMgbOG6oWkgdsOgIGzDoG0gc+G6oWNoIGThu68gbGnhu4d1LCBuaMawbmcgbsOzIGPDsyB0aOG7gyBraMO0bmcgxJHDoXAg4bupbmcgxJHGsOG7o2MgdOG6pXQgY+G6oyBjw6FjIHTDrG5oIGh14buRbmcgeOG7rSBsw70gZOG7ryBsaeG7h3Uga2jDoWMgbmhhdS4gQ8OzIHRo4buDIGPDsyBuaOG7r25nIHRyxrDhu51uZyBo4bujcCB5w6p1IGPhuqd1IGPDoWMgcGjDqXAgdG/DoW4gcGjhu6ljIHThuqFwIGhv4bq3YyDEkeG6t2MgdGjDuSBoxqFuIHbDoCB0aWR5ciBjw7MgdGjhu4Mga2jDtG5nIGPDsyBjw6FjIGjDoG0gZMOgbmggcmnDqm5nIGNobyBuaOG7r25nIG5oaeG7h20gduG7pSDEkcOzLg0KDQpLaMOzIGtoxINuIHRyb25nIHF1w6EgdHLDrG5oIGjhu41jIHThuq1wOiBHaeG7kW5nIG5oxrAgYuG6pXQga+G7syBnw7NpIGhheSBjw7RuZyBj4bulIG3hu5tpIG7DoG8sIHZp4buHYyBz4butIGThu6VuZyB0aWR5ciBt4buZdCBjw6FjaCBoaeG7h3UgcXXhuqMgY8WpbmcgY8OzIHRo4buDIGfhurdwIGtow7Mga2jEg24gYmFuIMSR4bqndS4gTmfGsOG7nWkgZMO5bmcgY+G6p24gbMOgbSBxdWVuIHbhu5tpIGPDuiBwaMOhcCB2w6AgY8OhYyBow6BtIGPhu6UgdGjhu4MgY+G7p2EgdGlkeXIgxJHhu4MgdOG6rW4gZOG7pW5nIHThu5FpIMSRYSBraOG6oyBuxINuZyBj4bunYSBuw7MuIFF1w6EgdHLDrG5oIGjhu41jIG7DoHkgY8OzIHRo4buDIHnDqnUgY+G6p3UgbeG7mXQga2hv4bqjbmcgdGjhu51pIGdpYW4gdsOgIG7hu5cgbOG7sWMgbmjhuqV0IMSR4buLbmguDQoNClBo4bulIHRodeG7mWMgdsOgbyB0aWR5dmVyc2U6IE3hurdjIGTDuSB2aeG7h2MgbMOgIG3hu5l0IHBo4bqnbiBj4bunYSB0aWR5dmVyc2UgbWFuZyBs4bqhaSBuaGnhu4F1IGzhu6NpIMOtY2gsIG5oxrBuZyDEkeG7k25nIHRo4budaSBjxaluZyBjw7MgdGjhu4MgbMOgIG3hu5l0IGjhuqFuIGNo4bq/IMSR4buRaSB24bubaSBuaOG7r25nIG5nxrDhu51pIGTDuW5nIMawYSB0aMOtY2ggaG/hurdjIHBo4bulIHRodeG7mWMgdsOgbyBjw6FjIGfDs2kgeOG7rSBsw70gZOG7ryBsaeG7h3Uga2jDoWMgbuG6sW0gbmdvw6BpIGjhu4cgc2luaCB0aMOhaSB0aWR5dmVyc2UuIFPhu60gZOG7pW5nIHRpZHlyIHRyb25nIHF1eSB0csOsbmggbMOgbSB2aeG7h2MgZOG7sWEgdHLDqm4gdGlkeXZlcnNlIGPDsyB0aOG7gyB5w6p1IGPhuqd1IHPhu7EgY2h1eeG7g24gxJHhu5VpIHNhbmcgY8OhYyBnw7NpIHRpZHl2ZXJzZSBraMOhYywgxJFp4buBdSBuw6B5IGPDsyB0aOG7gyBraMO0bmcgcGjDuSBo4bujcCB24bubaSBt4buNaSBuZ8aw4budaS4NCg0KIyMgxJDDs25nIGfDs3AgY+G7p2EgxJHhu4EgdMOgaQ0KDQpCw6BpIHRp4buDdSBsdeG6rW4gY+G7p2EgbmjDs20gZW0gxJHDs25nIGfDs3AgY2hvIGPhu5luZyDEkeG7k25nIHPhu60gZOG7pW5nIFIgdHJvbmcgdmnhu4djIMOhcCBk4bulbmcgZ8OzaSBUaWR5ciB2w6BvIHZp4buHYyBwaMOibiB0w61jaCBk4buvIGxp4buHdSDhu58gbeG7mXQgc+G7kSBraMOtYSBj4bqhbmggcXVhbiB0cuG7jW5nLg0KDQrEkOG6p3UgdGnDqm4sIGNow7puZyBlbSDEkcOjIGdp4bubaSB0aGnhu4d1IGNoaSB0aeG6v3QgduG7gSBnw7NpIFRpZHlyLCBiYW8gZ+G7k20gY8OhYyBjaOG7qWMgbsSDbmcsIGzhu6NpIMOtY2gsIHBoxrDGoW5nIHBow6FwIHbDoCBjw6FjaCB0aOG7qWMgdGjhu7FjIGhp4buHbiBjw6FjIGjDoG0gcXVhbiB0cuG7jW5nIHRyb25nIGfDs2kgVGlkeXIsIMSRaeG7gXUgbsOgeSBnacO6cCBjaG8gbeG7jWkgbmfGsOG7nWkgY8OzIGPDoWkgbmjDrG4gdOG7lW5nIHF1YW4gbmjhuqV0IHbhu4EgbsOzLg0KDQpUaOG7qSBoYWksIGNow7puZyBlbSDDoXAgZOG7pW5nIHbDoG8gdmnhu4djIHBow6JuIHTDrWNoIGThu68gbGnhu4d1IHTDoGkgY2jDrW5oIHF1YSDEkcOzIGzDoG0gbuG7lWkgYuG6rXQgdMOtbmgg4bupbmcgZOG7pW5nIGPhu6dhIFRpZHlyIHRyb25nIGPDoWMgbMSpbmggduG7sWMsIGPFqW5nIG5oxrAgbmjhuqVuIG3huqFuaCBz4buxIHRp4buHbiDDrWNoIHbDoCBoaeG7h3UgcXXhuqMgY+G7p2EgbsOzIHRyb25nIHZp4buHYyBnacO6cCBuZ8aw4budaSBkw7luZyB0aeG6v3Qga2nhu4dtIHRo4budaSBnaWFuIHbDoCBu4buXIGzhu7FjIHRyb25nIGPDtG5nIHZp4buHYyB44butIGzDvSBk4buvIGxp4buHdS4NCg0KQ3Xhu5FpIGPDuW5nLCBuaMOzbSBwaMOibiB0w61jaCDEkcaw4bujYyB0aeG7gW0gbsSDbmcgdsOgIGjhuqFuIGNo4bq/IGPhu6dhIFRpZHlyLCBxdWEgxJHDsyBnacO6cCBjaG8gbmjhu69uZyBuZ8aw4budaSBwaMOibiB0w61jaCBk4buvIGxp4buHdSBz4butIGThu6VuZyBoaeG7h3UgcXXhuqMgbmjhuqV0IGfDs2kgbsOgeSB2w6BvIHRyb25nIGPDtG5nIHZp4buHYyBj4bunYSBo4buNLg0KDQojIyBL4bq/dCBj4bqldQ0KDQoqKkNoxrDGoW5nIDE6IEdp4bubaSB0aGnhu4d1IMSR4buBIHTDoGkqKg0KDQpHaeG7m2kgdGhp4buHdSB04buVbmcgcXVhbiB24buBIHThuqdtIHF1YW4gdHLhu41uZyBj4bunYSB2aeG7h2MgdGjhu7FjIGhp4buHbiDEkeG7gSB0w6BpIG5naGnDqm4gY+G7qXUgZ8OzaSB0aWR5ciB0cm9uZyBSLCDEkcawYSByYSBuaOG7r25nIGzDvSBkbyDEkeG7gyBjaOG7jW4gY2jhu6cgxJHhu4EgbsOgeSB2w6AgbsOqdSBuaOG7r25nIG7hu5lpIGR1bmcgcXVhbiB0cuG7jW5nIGPhu6dhIGfDs2kgdGlkeXIuDQoNCioqQ2jGsMahbmcgMjogVGjhu7FjIGjDoG5oIGPDoWMgaMOgbSB0cm9uZyB0aWR5cioqDQoNCkNoxrDGoW5nIGhhaSBz4bq9IHRyw6xuaCBiw6B5IGPhu6UgdGjhu4MgY2jhu6ljIG7Eg25nIGPDoWMgaMOgbSB0cm9uZyBnw7NpIHRpZHlyIHbDoCDEkcawYSByYSBuaOG7r25nIHbDrSBk4bulIGPhu6UgdGjhu4MgxJHhu4MgaMaw4bubbmcgZOG6q24gdGjhu7FjIGjDoG5oLg0KDQoqKkNoxrDGoW5nIDM6IOG7qG5nIGThu6VuZyBj4bunYSB0aWR5cioqDQoNCkThu7FhIHbDoG8gY8OhYyBjaOG7qWMgbsSDbmcgY+G7p2EgY8OhYyBow6BtIMSRxrDhu6NjIHRyw6xuaCBiw6B5IHRyb25nIGNoxrDGoW5nIDIgc2F1IMSRw7MgxJHGsOG7o2Mgw6FwIGThu6VuZyBsw6puIG5o4buvbmcgZOG7ryBsaeG7h3UgbOG7m24gaMahbiB2w6AgY8OzIGPhuqV1IHRyw7pjIGtow7MgaMahbiBi4bqxbmcgY8OhY2gga+G6v3QgaOG7o3AgdGjDqm0gbeG7mXQgc+G7kSBnw7NpIGtow6FjIG5oxrAgZHBseXIuIFNhdSBraGkgY2h14bqpbiBow7NhIGThu68gbGnhu4d1IHRow6wgdGjhu7FjIGhp4buHbiB0w61uaCB0aMOzYSB2w6AgdHLhu7FjIHF1YW4gaMOzYSBk4buvIGxp4buHdQ0KDQoqKkNoxrDGoW5nIDQ6IEvhur90IGx14bqtbioqDQoNCkNoxrDGoW5nIGN14buRaSBz4bq9IGvhur90IGx14bqtbiBuaOG7r25nIGvhur90IHF14bqjIHRodSDEkcaw4bujYyB0cm9uZyBiw6BpIG7DoHksIMSRxrBhIHJhIG5o4buvbmcgaOG6oW4gY2jhur8gdHJvbmcgcXXDoSB0csOsbmggbmdoacOqbiBj4bupdSB2w6AgxJHhu4EgeHXhuqV0IHBoxrDGoW5nIGjGsOG7m25nIGzDoG0gdGnhur9wIHRoZW8uDQoNCiMgQ0jGr8agTkcgMjogVEjhu7BDIEjDgE5IIEPDgUMgSMOATSBUUk9ORyBUSURZUg0KDQpgYGB7cixlY2hvPUZBTFNFLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCmxpYnJhcnkoRFQpDQpgYGANCg0KVHJvbmcgY2jGsMahbmcgaGFpIG5ow7NtIGNow7puZyB0w7RpIHRo4buxYyBoaeG7h24gY8OhYyBs4buHbmggdHJvbmcgZ8OzaSBUaWR5ciDEkeG7gyBnacO6cCBuZ8aw4budaSDEkeG7jWMgY8OzIHRo4buDIGhp4buDdSByw7UgY8OhYyBjaOG7qWMgbsSDbmcgdHJvbmcgZ8OzaSBuw6B5LiBU4burIMSRw7MsIG5o4buvbmcgbmfGsOG7nWkgcXVhbiB0w6JtIMSR4bq/biBnw7NpIFRpZHlyIMOhcCBk4bulbmcgY8OhYyBow6BtIHbDoG8gY8O0bmcgdmnhu4djIHjhu60gbMOtIGLhu5kgZOG7ryBsaeG7h3UgY+G7p2EgaOG7jSBuaGFuaCBjaMOzbmcgaMahbi4gVmnhu4djIGdp4bubaSB0aGnhu4d1IGNoaSB0aeG6v3QgduG7gSBz4butIGThu6VuZyBnw7NpIFRpZHlyIHRow7RuZyBxdWEgdmnhu4djIHRo4buxYyBow6BuaCB0csOqbiBk4buvIGxp4buHdSBt4bqrdSBsw6AgbuG7gW4gdOG6o25nIHF1YW4gdHLhu41uZyDEkeG7gyBuaMOzbSBjaMO6bmcgdMO0aSBjw7MgdGjhu4Mg4bupbmcgZOG7pW5nIFRpZHlyIOG7nyBjw6FjIHBo4bqnbiBzYXUNCg0KIyMgQmnhur9uIMSR4buVaSBk4buvIGxp4buHdSAoUGl2b3RpbmcpDQoNCiMjIyBDaHV54buDbiBk4buvIGxp4buHdSBzYW5nIGThuqFuZyBkw6BpDQoNCkjDoG0gcGl2b3RfbG9uZ2VyIGjhu5cgdHLhu6MgY2jDum5nIHRhIGNodXnhu4NuIMSR4buVaSBk4buvIGxp4buHdSB04burIGThuqFuZyBy4buZbmcgKHdpZGUgZm9ybWF0KSBzYW5nIGThuqFuZyBkw6BpIChsb25nIGZvcm1hdCkuIFZp4buHYyBiaeG6v24gxJHhu5VpIGPhuqV1IHRyw7pjIGThu68gbGnhu4d1IGPDsyDDvSBuZ2jEqWEga2hpIG5nxrDhu51pIHBow6JuIHTDrWNoIG114buRbiB44butIGzDvSB0csOqbiBk4buvIGxp4buHdSBk4bqhbmcgZMOgaSDEkeG7gyBjw7MgdGjhu4MgdGhhbyB0w6FjIGThu4UgZMOgbmcgdsOgIMSR4bqhdCBuaGnhu4F1IGhp4buHdSBxdeG6oyBoxqFuIGThuqFuZyBy4buZbmcuDQoNCkNo4bupYyBuxINuZyBwaXZvdF9sb25nZXIoKSBjw7MgbeG7mXQgc+G7kSB0aGFtIHPhu5EgcXVhbiB0cuG7jW5nIG5oxrAgc2F1Og0KDQotICAgZGF0YTogVGhhbSBz4buRIG7DoHkgecOqdSBj4bqndSBk4buvIGxp4buHdSBtw6AgY2jDum5nIHRhIG114buRbiBjaHV54buDbiDEkeG7lWkgdOG7qyBk4bqhbmcgcuG7mW5nIHNhbmcgZOG6oW5nIGTDoGkuDQoNCi0gICBjb2xzOiB0aGFtIHPhu5EgbsOgeSBsw6AgZGFuaCBzw6FjaCBjw6FjIGPhu5l0IG3DoCB0YSBtdeG7kW4gY2h1eeG7g24gxJHhu5VpLiBUYSBjw7MgdGjhu4MgY2jhu4kgxJHhu4tuaCB0w6puIGPhu5l0IGPhu6UgdGjhu4MgdHJvbmcgZGF0YSBob+G6t2Mgc+G7rSBk4bulbmcgY8OhYyBow6BtIMSR4buDIGzhu7FhIGNo4buNbiBjw6FjIGPhu5l0IHRoZW8gbmjhu69uZyB0acOqdSBjaMOtIG3DoCBjaMO6bmcgdGEgbXXhu5FuDQoNCi0gICBuYW1lc190bzogVMOqbiBj4bunYSBj4buZdCBt4bubaSBz4bq9IGzGsHUgdHLhu68gY8OhYyB0w6puIGJp4bq/biBzYXUga2hpIGNodXnhu4NuIMSR4buVaSBzYW5nIGThuqFuZyBk4buvIGxp4buHdSBkw6BpLg0KDQotICAgdmFsdWVzX3RvOiBUw6puIGPhu6dhIGPhu5l0IG3hu5tpIG3DoCBz4bq9IGNo4bupYSBjw6FjIGdpw6EgdHLhu4sgYmnhur9uIHNhdSBraGkgY2h1eeG7g24gxJHhu5VpLg0KDQpUcsaw4bubYyBraGkgdGjhu7FjIGjDoG5oIGjDoG0gcGl2b3RfbG9uZ2VyIHTDtGkgc+G6vSBn4buNaSBt4buZdCBk4buvIGxp4buHdSBt4bqrdSB0cm9uZyBnw7NpIFRpZHlyIMSRw7MgY2jDrW5oIGzDoCB0YWJsZTRiLCBk4buvIGxp4buHdSBuw6B5IGfhu5NtIGTDom4gc+G7kSBj4bunYSAzIHF14buRYyBnaWEgQWZnaGFuaXN0YW4sIEJyYXppbCwgQ2hpbmEgdHJvbmcgaGFpIG7Eg20gMTk5OSwyMDAwLg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkodGlkeXZlcnNlKQ0KdGFibGU0Yg0KDQpgYGANCg0KVOG7qyB0YWJsZTRiIHbhu5tpIG3hu6VjIMSRw61jaCBiaeG6v24gxJHhu5VpIGPDoWMgbsSDbSB24buBIGPDuW5nIG3hu5l0IGPhu5l0IHbDoCBnacOhIHRy4buLIHbhu4EgbeG7mXQgY+G7mXQgY2h1bmcgduG7m2kgbmhhdSwgdGEgY8OzIHRo4buDIHRo4buxYyBoaeG7h24gbOG7h25oIHBpdm90X2xvbmdlciB24bubaSBk4buvIGxp4buHdSBiYW4gxJHhuqd1IG114buRbiBjaHV54buDbiDEkeG7lWkgc2FuZyBk4bqhbmcgZMOgaSBsw6AgdGFibGU0YiwgdGhhbSBz4buRICdjb2xzJyBjaOG7iSDEkeG7i25oIGPDoWMgY+G7mXQgbXXhu5FuIGNodXnhu4NuIMSR4buVaSBsw6AgY+G7mXQgdOG7qyAiMTk5OSIgxJHhur9uICIyMDAwIiwgdGhhbSBz4buRIGBuYW1lc190b2AgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgxJHhurd0IHTDqm4gY+G7mXQgbeG7m2kgY2jhu6lhIGPDoWMgYmnhur9uIHbhu5tpIGzDoCAieWVhciIgdsOgIHRoYW0gc+G7kSBgdmFsdWVzX3RvYCDEkeG6t3QgdMOqbiBjaG8gY+G7mXQgY2jhu6lhIGPDoWMgZ2nDoSB0cuG7iyBiaeG6v24gdMawxqFuZyDhu6luZyBsw6AgdmFsdWVzLg0KDQpgYGB7cn0NCnBpdm90X2xvbmdlcih0YWJsZTRiLGNvbHM9ICcxOTk5JzonMjAwMCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAieWVhciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInZhbHVlcyIpDQpgYGANCg0KTmjGsCBr4bq/dCBxdeG6oyBzYXUga2hpIGNodXnhu4NuIMSR4buVaSBiw6puIHRyw6puIHRhIHPhur0gY8OzIMSRxrDhu6NjIG3hu5l0IGThu68gbGnhu4d1IGThuqFuZyBkw6BpIHbhu5tpIG3hu5dpIGTDsm5nIGNobyBiaeG6v3QgduG7gSB0w6puIHF14buRYyBnaWEsIG7Eg20ga2jhuqNvIHPDoXQgdsOgIGTDom4gc+G7kSB0xrDGoW5nIOG7qW5nLg0KDQojIyMgQ2h1eeG7g24gZOG7ryBsaeG7h3Ugc2FuZyBk4bqhbmcgcuG7mW5nDQoNCkjDoG0gYHBpdm90X3dpZGVyYCBjw7MgY2jhu6ljIG7Eg25nIGJp4bq/biDEkeG7lWkgZOG6oW5nIGThu68gbGnhu4d1IGTDoGkgc2FuZyBk4buvIGxp4buHdSBy4buZbmcgc2FvIGNobyBwaMO5IGjhu6NwIHbhu5tpIG3hu6VjIHRpw6p1IGPhu6dhIG5nxrDhu51pIHPhu60gZOG7pW5nLiBIw6BtIG7DoHkgY8OzIHRoYW8gdMOhYyBraMOhIMSRxqFuIGdp4bqjbiB0dXkgbmhpw6puIG1hbmcgbOG6oWkgcuG6pXQgbmhp4buBdSBs4bujaSDDrWNoIHRyb25nIHF1w6EgdHLDrG5oIGzDoG0gdmnhu4djIGPhu6dhIG3hu41pIG5nxrDhu51pLiBQaXZvdF93aWRlciBjw7MgY8OhYyB0aGFtIHPhu5EgY2jDrW5oIG5oxrAgc2F1Og0KDQotICAgZGF0YTogROG7ryBsaeG7h3UgZMO5bmcgxJHhu4MgY2h1eeG7g24gc2FuZyBk4buvIGxp4buHdSBk4bqhbmcgcuG7mW5nDQoNCi0gICBuYW1lc19mcm9tOiBUw6puIGPhu5l0IGhv4bq3YyBiaeG6v24gbcOgIHRhIG114buRbiBiaeG6v24gxJHhu5VpIHRow6BuaCBjw6FjIGPhu5l0IG3hu5tpLg0KDQotICAgdmFsdWVzX2Zyb206IFTDqm4gY+G7mXQgaG/hurdjIGJp4bq/biBjaOG7qWEgY8OhYyBnacOhIHRy4buLIHTGsMahbmcg4bupbmcgduG7m2kgY8OhYyBj4buZdCBt4bubaS4NCg0KROG7ryBsaeG7h3UgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdGjhu7FjIGhp4buHbiBow6BtIGBwaXZvdF93aWRlcmAgbMOgIHRhYmxlMiwgxJHDonkgbMOgIGThu68gbGnhu4d1IG3huqt1IHRyb25nIGfDs2kgVGlkeXIgY2jhu6lhIHRow7RuZyB0aW4gduG7gSBxdeG7kWMgZ2lhLCBuxINtLCBsb+G6oWkgc+G7kSBsaeG7h3UgduG7gSBkw6JuIHPhu5EsIHRyxrDhu51uZyBo4bujcCBt4bqvYyBi4buHbmggdsOgIHPhu5EgbmfGsOG7nWkgdMawxqFuZyDhu6luZy4NCg0KYGBge3J9DQp0YWJsZTINCmBgYA0KDQrEkOG6p3UgdGnDqm4sIHRhIGPhuqduIGtoYWkgYsOhbyBk4buvIGxp4buHdSBkw7luZyDEkeG7gyBjaHV54buDbiDEkeG7lWkgbMOgIHRhYmxlMiwgcGjDqXAgdG/DoW4gdOG7rSBnacO6cCB0cnV54buBbiBr4bq/dCBxdeG6oyBj4bunYSB0YWJsZTIgcGjDrWEgdHLGsOG7m2MgdGjDoG5oIMSR4buRaSB0xrDhu6NuZyDEkeG6p3UgdsOgbyBj4bunYSBow6BtIHBpdm90X3dpZGVyLiBUaGFtIHPhu5EgYG5hbWVzX2Zyb21gIHRyb25nIHRyxrDhu51uZyBo4bujcCBuw6B5IMSRxrDhu6NjIGtoYWkgYsOhbyBsw6AgdHlwZSDEkeG7gyBjaOG7iSByYSB0w6puIGPhu5l0IGTDuW5nIMSR4buDIGJp4bq/biDEkeG7lWkgdGjDoG5oIGPDoWMgY+G7mXQgbeG7m2kgdHJvbmcgZOG7ryBsaeG7h3UgcuG7mW5nLCBt4buXaSBnacOhIHRy4buLIHRyb25nIGJp4bq/biB0eXBlIHPhur0gbMOgIG3hu5l0IGPhu5l0IG3hu5tpLiBgdmFsdWVzX2Zyb21gIMSRxrDhu6NjIGNo4buJIMSR4buLbmggbMOgIGJp4bq/biBjb3VudCDEkeG7gyBjaOG7iSByYSBjw6FjIGdpw6EgdHLhu4sgdMawxqFuZyDhu6luZyB24bubaSBjw6FjIGPhu5l0IG3hu5tpDQoNCmBgYHtyfQ0KdGFibGUyICU+JSBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdHlwZSwgdmFsdWVzX2Zyb20gPSBjb3VudCkNCmBgYA0KDQpDaHV54buDbiDEkeG7lWkgY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UgdGFibGUyIHNhbmcgZOG6oW5nIGThu68gbGnhu4d1IHLhu5luZyBnacO6cCB0YSBk4buFIGTDoG5nIMSRw6FuaCBnacOhIGPDoWMgdHLGsOG7nW5nIGjhu6NwIG3huq9jIGLhu4duaCB2w6AgZMOibiBz4buRIGPhu6dhIGPDoWMgcXXhu5FjIGdpYSBxdWEgdOG7q25nIG7Eg20uIE5nb8OgaSByYSwgdmnhu4djIGNodXnhu4NuIMSR4buVaSBj4bqldSB0csO6YyBjxaluZyBnacO6cCB0aOG7sWMgaGnhu4duIHBow6JuIHTDrWNoIHRoZW8gdOG7q25nIGJp4bq/biB2w6AgdHLhu7FjIHF1YW4gaMOzYSBk4buvIGxp4buHdSB04buRdCBoxqFuLg0KDQojIyBUw6FjaCBj4buZdA0KDQpDaOG7qWMgbsSDbmcgdMOhY2ggbeG7mXQgY+G7mXQgdGjDoG5oIG5oaeG7gXUgY+G7mXQgZOG7sWEgdHLDqm4gbmjhu69uZyBrw70gdOG7sSBwaMOibiB0w6FjaCBz4bq9IGzDoCBt4buZdCBjw7RuZyBj4bulIHThu5F0IMSR4buDIGNow7puZyB0YSBjw7MgdGjhu4MgeOG7rSBsw70gZOG7ryBsaeG7h3UgY+G7p2EgbcOsbmgga2hpIG3DoCBt4buZdCBj4buZdCBjaOG7qWEgbmhp4buBdSBnacOhIHRy4buLIGvhur90IGjhu6NwIHbhu5tpIG5oYXUuIFZp4buHYyBwaMOibiB0w6FjaCBj4buZdCBraMO0bmcgecOqdSBj4bqndSBuaGnhu4F1IHRoYW8gdMOhYyBuaMawbmcgduG6q24gxJHhuqNtIGLhuqNvIMSRxrDhu6NjIMSR4buZIGNow61uaCB4w6FjIHNvIHbhu5tpIGThu68gbGnhu4d1IGJhbiDEkeG6p3UsIHRoYW8gdMOhYyBuw6B5IGPDsyB0aOG7gyDEkcaw4bujYyBjb2kgbMOgIG3hu5l0IHRyb25nIG5o4buvbmcgYsaw4bubYyB44butIGzDvSBjaHXhu5dpIHBo4bupYyB04bqhcC4gROG7ryBsaeG7h3Ugc2F1IGtoaSDEkcaw4bujYyB0w6FjaCBj4buZdCBz4bq9IMSRZW0gbOG6oWkgdGjDtG5nIHRpbiBjaGkgdGnhur90IGjGoW4gxJHhu4MgY8OzIHRo4buDIHBow6JuIHTDrWNoLCBzbyBzw6FuaCwgdHLhu7FjIHF1YW4gaMOzYSBk4buvIGxp4buHdS4gVHJvbmcgVGlkeXIgxJHhu4MgdMOhY2ggY+G7mXQgdGjDrCB0YSBkw7luZyBow6BtIGBzZXBhcmF0ZSgpYCB24bubaSBuaOG7r25nIHRoYW0gc+G7kSBjaMOtbmggY+G6p24gcGjhuqNpIGzGsHUgw70gbmjGsA0KDQotICAgZGF0YTogROG7ryBsaeG7h3UgYmFuIMSR4bqndS4NCg0KLSAgIGNvbDogVMOqbiBj4buZdCBj4bqnbiB0w6FjaC4NCg0KLSAgIGludG86IFTDqm4gY8OhYyBj4buZdCBt4bubaSDEkcaw4bujYyB04bqhbyByYSBzYXUga2hpIHTDoWNoLg0KDQotICAgc2VwOiBLw70gdOG7sSBwaMOibiB0w6FjaCBob+G6t2MgbeG6q3UgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdMOhY2ggY+G7mXQuDQoNCi0gICByZW1vdmU6IFjDoWMgxJHhu4tuaCB4ZW0gY+G7mXQgYmFuIMSR4bqndSBj4bqnbiDEkcaw4bujYyBsb+G6oWkgYuG7jyBzYXUga2hpIHTDoWNoIGhheSBraMO0bmcsIG3hurdjIMSR4buLbmggbMOgIFRSVUUuDQoNCi0gICBjb252ZXJ0OiBYw6FjIMSR4buLbmggeGVtIGPDoWMgY+G7mXQgbeG7m2kgY+G6p24gxJHGsOG7o2MgY2h1eeG7g24gxJHhu5VpIHRow6BuaCBraeG7g3UgZOG7ryBsaeG7h3UgcGjDuSBo4bujcCBoYXkga2jDtG5nLCBt4bq3YyDEkeG7i25oIGzDoCBGQUxTRS4NCg0KROG7ryBsaeG7h3UgxJHhuqd1IHbDoG8gZMO5bmcgxJHhu4MgdMOhY2ggY+G7mXQgbMOgIHRhYmxlMywgZOG7ryBsaeG7h3UgbsOgeSBjw7MgY+G7mXQgcmF0ZSBkw7luZyBrw70gdOG7sSAvIMSR4buDIHTDrW5oIHThu7cgbOG7hyBuZ8aw4budaSBt4bqvYyBi4buHbmggdHLDqm4gZMOibiBz4buRIGPhu6dhIG3hu5l0IHF14buRYyBnaWEuIFRhIGPDsyB0aOG7gyBkw7luZyBow6BtIGBzZXBhcmF0ZSgpYCDEkeG7gyB0w6FjaCBj4buZdCByYXRlIHRow6BuaCBt4buZdCBj4buZdCBjaOG7qWEgc+G7kSBsaeG7h3UgduG7gSBz4buRIG5nxrDhu51pIG3huq9jIGLhu4duaCB2w6AgbeG7mXQgY+G7mXQgY2jhu6lhIHPhu5EgbGnhu4d1IHbhu4EgZMOibiBz4buRLg0KDQpgYGB7cn0NCnRhYmxlMw0KYGBgDQoNCsSQ4buDIHRo4buxYyBoaeG7h24gdmnhu4djIHTDoWNoIGPhu5l0IHRyxrDhu5tjIHRpw6puIGNow7puZyB0YSBj4bqnbiBraGFpIGLDoW8gZOG7ryBsaeG7h3UgxJHhuqd1IHbDoG8gbMOgIHRhYmxlMywgY2jhu41uIGPhu5l0IGPhuqduIHTDoWNoIHRyb25nIHRoYW0gc+G7kSBgY29sYCBsw6AgY+G7mXQgcmF0ZSwg4bufIHRoYW0gc+G7kSBgaW50b2AgdGEgY8OzIHRo4buDIMSR4bq3dCB0w6puIGNobyBjw6FjIGPhu5l0IG3hu5tpIGzDoCAiY2FzZSIgdsOgICJwb3B1bGF0aW9uIiwgdGnhur9wIHRoZW8gYHNlcGAgY2jhu4kgcmEga8O9IHThu7EgZMO5bmcgxJHhu4MgcGjDom4gdMOhY2ggdHJvbmcgZOG7ryBsaeG7h3UgY+G7p2EgY2jDum5nIHRhIMSRw7MgbMOgICIvIi4NCg0KYGBge3J9DQpzZXBhcmF0ZShkYXRhID0gdGFibGUzLCBjb2w9IHJhdGUsIGludG89IGMoImNhc2UiLCJwb3B1bGF0aW9uIiksc2VwID0gIi8iKQ0KYGBgDQoNCkvhur90IHF14bqjIHThu6sgY8OidSBs4buHbmggdHLDqm4gc+G6vSB04bqhbyByYSBoYWkgY+G7mXQgbeG7m2kgbMOgIGNhc2UgdsOgIHBvcHVsYXRpb24gZOG7sWEgdsOgbyBj4buZdCByYXRlIGJhbiDEkeG6p3UuIMSQaeG7gXUgbsOgeSBz4bq9IGdpw7pwIHRhIHF1YW4gc8OhdCDEkcaw4bujYyBz4buRIHRyxrDhu51uZyBo4bujcCBt4bqvYyBi4buHbmggdsOgIGTDom4gc+G7kSBj4bunYSBt4buZdCBxdeG7kWMgZ2lhIG3hu5l0IGPDoWNoIGNoaSB0aeG6v3QgaMahbiB2w6Agc2F1IMSRw7MgY8OzIHRo4buDIGThu4UgZMOgbmcgZMO5bmcgbsOzIHRyb25nIGPDoWMgY8O0bmcgdmnhu4djIGtow6FjLg0KDQpgYGB7cn0NCnNlcGFyYXRlKGRhdGEgPSB0YWJsZTMgLCBjb2wgPSByYXRlLCBpbnRvID0gYygiY2FzZSIsICJwb3B1bGF0aW9uIiksIHJlbW92ZSA9IEZBTFNFLCBjb252ZXJ0ID0gVFJVRSApDQoNCmBgYA0KDQpOZ2/DoGkgcmEsIHRhIGPDsyB0aOG7gyB0aMOqbSB2w6BvIHRoYW0gc+G7kSBgcmVtb3ZlYCBsw6AgRkFMU0UgxJHhu4MgZ2nhu68gbmd1ecOqbiBj4buZdCByYXRlIGJhbiDEkeG6p3UgdsOgIHRoYW0gc+G7kSBgY29udmVydGAgYuG6sW5nIFRSVUUgxJHhu4MgeMOhYyDEkeG7i25oIGNodXnhu4NuIMSR4buVaSB0aMOgbmgga2nhu4N1IGThu68gbGnhu4d1IHBow7kgaOG7o3ANCg0KIyMgS+G6v3QgaOG7o3AgY+G7mXQNCg0K4bueIGLGsOG7m2MgbMOgbSBz4bqhY2ggZOG7ryBsaeG7h3UsIGNow7puZyB0YSB0aMaw4budbmcgeHV5w6puIGfhurdwIHBo4bqjaSBjw6FjIGPhu5l0IGThu68gbGnhu4d1IMSRxrDhu6NjIHTDoWNoIHJhIHJpw6puZyBiaeG7h3QgdsOgIGtoaSBr4bq/dCBo4bujcCBjaMO6bmcgbOG6oWkgduG7m2kgbmhhdSB0aMOsIGPDsyB0aOG7gyDEkcaw4bujYyBt4buZdCBj4buZdCBk4buvIGxp4buHdSBob8OgbiBjaOG7iW5oIHbDoCBn4buNbiBnw6BuZyBoxqFuIHRyxrDhu5tjIHLhuqV0IG5oaeG7gXUuIEfDs2kgVGlkeXIgYmFvIGfhu5NtIGjDoG0gYHVuaXRlKClgIGPDsyB0aOG7gyBkw7luZyDEkeG7gyBr4bq/dCBo4bujcCBuaGnhu4F1IGPhu5l0IHRow6BuaCBt4buZdCBj4buZdCBi4bqxbmcgY8OhY2ggZ2jDqXAgY8OhYyBnacOhIHRy4buLIGPhu6dhIGNow7puZyBs4bqhaSB24bubaSBuaGF1LiBD4bqldSB0csO6YyBj4bunYSBk4buvIGxp4buHdSBzYXUga2hpIGJp4bq/biDEkeG7lWkgc+G6vSB0cuG7nyBuw6puIMSRxqFuIGdp4bqjbiwgw610IGPhu5l0IHbDoCBtYW5nIMO9IG5naMSpYSB04buVbmcgcXVhbiBoxqFuIHNvIHbhu5tpIGThu68gbGnhu4d1IGJhbiDEkeG6p3UuIE5o4buvbmcgdGhhbSBz4buRIGNow61uaCB0cm9uZyBow6BtIGB1bml0ZSgpYCDEkcaw4bujYyBnaeG6o2kgdGjDrWNoIGTGsOG7m2kgxJHDonk6DQoNCi0gICBkYXRhOiBLaHVuZyBk4buvIGxp4buHdQ0KDQotICAgY29sIDogVMOqbiBj4bunYSBj4buZdCBt4bubaSDEkcaw4bujYyB04bqhbywgdMOqbiBj4bunYSBjw6FjIGPhu5l0IMSRxrDhu6NjIGjhu6NwIG5o4bqldCBz4bqvcCB44bq/cCB0aGVvIHRy4bqtdCB04buxDQoNCi0gICBzZXA6IEThuqV1IHBow6JuIGPDoWNoIGdp4buvYSBoYWkgZ2nDoSB0cuG7iw0KDQotICAgcmVtb3ZlOiBO4bq/dSBsw6AgVFJVRSBz4bq9IHjDs2EgYuG7jyBjw6FjIGPhu5l0IGThu68gbGnhu4d1IGJhbiDEkeG6p3Ugc2F1IGtoaSBn4buZcCBs4bqhaSB0aMOgbmggY+G7mXQgbeG7m2kNCg0KLSAgIG5hLnJtOiBO4bq/dSBsw6AgVFJVRSB0aMOsIHPhur0gbG/huqFpIGLhu48gY8OhYyBnacOhIHRy4buLIGLhu4sgdGhp4bq/dSB0csaw4bubYyBraGkga+G6v3QgaOG7o3ANCg0KQuG6o25nIGThu68gbGnhu4d1IHRhYmxlNSBiw6puIGTGsOG7m2kgY8OzIGhhaSBj4buZdCByacOqbmcgYmnhu4d0IGNo4bupYSBnacOhIHRy4buLIHbhu4EgdGjhur8ga+G7iSB2w6AgbsSDbSwgY2jDum5nIHRhIGvhur90IGjhu6NwIGhhaSBj4buZdCBuw6B5IHRow6BuaCBt4buZdCDEkeG7gyBjw7MgxJHGsOG7o2Mgc+G7kSBsaeG7h3UgbsSDbSBob8OgbiBjaOG7iW5oLg0KDQpgYGB7cn0NCnRhYmxlNQ0KYGBgDQoNClRyb25nIGjDoG0gYHVuaXRlKClgIGtodW5nIGThu68gbGnhu4d1IMSRxrDhu6NjIGtoYWkgYsOhbyBsw6AgdGFibGU1LCB0w6puIGPhu6dhIGPhu5l0IG3hu5tpIHNhdSBraGkga+G6v3QgaOG7o3AgbOG6oWkgxJHGsOG7o2MgxJHhurd0IGzDoCAibmV3eWVhciIgdsOgIGPDoWMgY+G7mXQgZMO5bmcgxJHhu4MgZ2jDqXAgbOG6oWkgxJHGsOG7o2MgY2jhu4kgxJHhu4tuaCBs4bqnbiBsxrDhu6N0IGzDoCBj4buZdCBjZW50dXJ5LCB5ZWFyLiDEkOG7kWkgc+G7kSBgc2VwYCB5w6p1IGPhuqd1IGThuqV1IHBow6JuIGPDoWNoIHNhdSBraGkgZ2jDqXAgY8OhYyBnacOhIHRy4buLIGzhuqFpLCB0cm9uZyB0csaw4budbmcgaOG7o3AgbsOgeSB0w7RpIHPhu60gZOG7pW5nICIiIGzDoCBraMO0bmcgY8OzIGtob+G6o25nIGPDoWNoIHNhdSBraGkga+G6v3QgaOG7o3AgaGFpIGThu68gbGnhu4d1LiBgcmVtb3ZlYCBjaG8gYuG6sW5nIEZBTFNFIGzDoCBz4bq9IGtow7RuZyBsb+G6oWkgYuG7jyBjw6FjIGPhu5l0IGJhbiDEkeG6p3Ugc2F1IGtoaSBr4bq/dCBo4bujcCBj4buZdC4NCg0KYGBge3J9DQp1bml0ZShkYXRhID0gdGFibGU1LCBjb2w9IG5ld3llYXIgLCBjZW50dXJ5ICwgeWVhciwgc2VwPSIiLHJlbW92ZSA9IEZBTFNFKQ0KYGBgDQoNClNhdSBraGkga+G6v3QgaOG7o3AgY2VudHVyeSB2w6AgeWVhciB0YSDEkcaw4bujYyBj4buZdCBt4bubaSB0w6puIGzDoCBuZXd5ZWFyIGNo4bupYSBjw6FjIGdpw6EgdHLhu4sgbsSDbSDEkcaw4bujYyBnaMOpcCB04burIGPDoWMgZ2nDoSB0cuG7iyB0cm9uZyBoYWkgY+G7mXQgdHLGsOG7m2MgxJHDsy4gVOG7qyDEkcOzLCB0YSBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgY+G7mXQgbeG7m2kgxJHGsOG7o2MgdOG6oW8gcmEgxJHhu4MgbMOgbSBjw6FjIHRoYW8gdMOhYyBraMOhYywgY2jhurNuZyBo4bqhbiBuaMawIHbhur0gxJHhu5MgdGjhu4sgaGF5IGTDuW5nIMSR4buDIHTDrW5oIHRvw6FuIGThu7FhIHbDoG8gdOG7q25nIG7Eg20uDQoNCiMjIE5lc3QNCg0KTOG7h25oIG5lc3QoKSBraMO0bmcgcGjhuqNpIGzDoCBt4buZdCBs4buHbmggdMOtY2ggaOG7o3AgdHJvbmcgUi4gVHV5IG5oacOqbiwgdHJvbmcgZ8OzaSB0aWR5ciwgY8OzIGjDoG0gbmVzdCgpIGNobyBwaMOpcCBjaMO6bmcgdGEgdOG6oW8gbeG7mXQgY+G7mXQgbeG7m2kgdHJvbmcgbeG7mXQgZGF0YWZyYW1lIHbDoCBs4buTbmcgZOG7ryBsaeG7h3UgdGjDoG5oIGPDoWMgZGFuaCBzw6FjaCBk4buxYSB0csOqbiBt4buZdCBob+G6t2Mgbmhp4buBdSBiaeG6v24uIEPDoWMgdGhhbSBz4buRIGNow61uaCB0cm9uZyBow6BtIGBuZXN0KClgIMSRxrDhu6NjIHRyw6xuaCBiw6B5IGTGsOG7m2kgxJHDonkNCg0KLSAgIC5kYXRhOiDEkOG7kWkgc+G7kSBuw6B5IGzDoCBk4buvIGxp4buHdSBn4buRYyBtw6AgYuG6oW4gbXXhu5FuIHThuqFvIGtodW5nIGThu68gbGnhu4d1IGzhu5NuZyBuaGF1IHThu6sgxJHDsw0KDQotICAgLi4uOiDEkMOieSBsw6AgbeG7mXQgxJHhu5FpIHPhu5Ega2nhu4N1IHRpZHktc2VsZWN0LCBjaG8gcGjDqXAgY2jhu41uIGPDoWMgY+G7mXQgbcOgIHRhIG114buRbiBs4buTbmcgdsOgbyBjw6FjIGtodW5nIGThu68gbGnhu4d1IGNvbg0KDQotICAgLmJ5OiDEkOG7kWkgc+G7kSBuw6B5IGNobyBwaMOpcCBjaOG7jW4gY8OhYyBj4buZdCBkw7luZyDEkeG7gyBuaMOzbSBk4buvIGxp4buHdQ0KDQotICAgLmtleTogbMOgIG3hu5l0IMSR4buRaSBz4buRIGNobyBwaMOpcCBi4bqhbiBjaOG7iSDEkeG7i25oIHTDqm4gY2hvIGPhu5l0IGRhbmggc8OhY2ggxJHGsOG7o2MgdOG6oW8gcmEgc2F1IGtoaSBs4buTbmcgZOG7ryBsaeG7h3UuIE7hur91IGtow7RuZyBjaOG7iSDEkeG7i25oIHTDqm4gY2hvIHRoYW0gc+G7kSBuw6B5IHRow6wgdMOqbiBt4bq3YyDEkeG7i25oIHPhur0gbMOgICJkYXRhIg0KDQpExrDhu5tpIMSRw6J5IGzDoCBt4buZdCB2w60gZOG7pSB24buBIGThu68gbGnhu4d1IGPhu6dhIG3hu5l0IGLhu5kgcGjhuq1uIMSRYW5nIG5naGnDqm4gY+G7qXUgduG7gSB0w6xuaCBow6xuaCB0aOG7nWkgdGnhur90IHRyb25nIGPDoWMgdGjDoG5oIHBo4buRIGtow6FjIG5oYXUuIENow7puZyB0YSBjw7MgbeG7mXQgZGF0YWZyYW1lIGNo4bupYSB0aMO0bmcgdGluIHbhu4EgdMOqbiB0aMOgbmggcGjhu5EsIG5nw6B5IHbDoCBnaeG7nSwgbmhp4buHdCDEkeG7mSB2w6AgxJHhu5kg4bqpbS4NCg0KYGBge3J9DQojIFThuqFvIGRhdGFmcmFtZSBjaOG7qWEgZOG7ryBsaeG7h3UgduG7gSB0aOG7nWkgdGnhur90DQpkYXRhIDwtIGRhdGEuZnJhbWUoDQogIFRoYW5oUGhvID0gYygiSGFub2kiLCAiSGFub2kiLCAiSGFub2kiLCAiSG9DaGlNaW5oIiwgIkhvQ2hpTWluaCIsICJIb0NoaU1pbmgiKSwNCiAgTmdheSA9IGMoIjIwMjMtMDEtMDEiLCAiMjAyMy0wMS0wMiIsICIyMDIzLTAxLTAzIiwgIjIwMjMtMDEtMDEiLCAiMjAyMy0wMS0wMiIsICIyMDIzLTAxLTAzIiksDQogIEdpbyA9IGMoIjEyOjAwIiwgIjEyOjAwIiwgIjEyOjAwIiwgIjEyOjAwIiwgIjEyOjAwIiwgIjEyOjAwIiksDQogIE5oaWV0RG8gPSBjKDIwLjUsIDIyLjMsIDIxLjgsIDMwLjIsIDMxLjUsIDMwLjkpLA0KICBEb0FtID0gYyg2MCwgNjUsIDYyLCA3MCwgNjgsIDcyKQ0KKQ0KcHJpbnQoZGF0YSkNCmBgYA0KDQpgYGB7cn0NCiMgTOG7k25nIGThu68gbGnhu4d1IHRow6BuaCBkYW5oIHPDoWNoIHRoZW8gdMOqbiB0aMOgbmggcGjhu5EgDQpuZXN0ZWRfZGF0YSA8LSBkYXRhICU+JWdyb3VwX2J5KFRoYW5oUGhvKSAlPiUgbmVzdCgpDQoNCiMgTOG7k25nIGThu68gbGnhu4d1IGLhurFuZyAuYnkgDQpuZXN0ZWRfZGF0YSA8LSBuZXN0KGRhdGEsIC5ieSA9IFRoYW5oUGhvLCAua2V5ID0gIkR1TGlldSIpDQoNCiMgSW4gZOG7ryBsaeG7h3UgbOG7k25nDQpwcmludChuZXN0ZWRfZGF0YSkNCg0KbmVzdGVkX2RhdGEkRHVMaWV1IDwtIGxhcHBseShuZXN0ZWRfZGF0YSREdUxpZXUsIGFzLmRhdGEuZnJhbWUpDQpsYXBwbHkobmVzdGVkX2RhdGEkRHVMaWV1LCBwcmludCkNCg0KYGBgDQoNClRyb25nIHbDrSBk4bulIG7DoHksIGNow7puZyB0YSBz4butIGThu6VuZyBow6BtIG5lc3QoKSB0cm9uZyBnw7NpIHRpZHlyIHbDoCBow6BtIGdyb3VwX2J5IHRyb25nIHBhY2thZ2UgZHBseXIgxJHhu4MgbOG7k25nIGThu68gbGnhu4d1IHRoZW8gdMOqbiB0aMOgbmggcGjhu5EuIELhurFuZyBjw6FjaCBz4butIGThu6VuZyBjaHXhu5dpIGTDsm5nIGzhu4duaCB0cm9uZyBnw7NpIHRpZHlyIHbDoCBkcGx5ciwgY2jDum5nIHRhIG5ow7NtIGThu68gbGnhu4d1IHRoZW8gY+G7mXQgVGhhbmhQaG8gYuG6sW5nIGjDoG0gZ3JvdXBfYnkoKSB2w6Agc2F1IMSRw7Mgc+G7rSBk4bulbmcgaMOgbSBuZXN0KCkgxJHhu4MgdOG6oW8gbeG7mXQgY+G7mXQgbeG7m2kgY2jhu6lhIGThu68gbGnhu4d1IMSRxrDhu6NjIGzhu5NuZyB0aMOgbmggZGFuaCBzw6FjaC4gSG/hurdjIHPhu60gZOG7pW5nIHRoYW0gc+G7kSBgLmJ5YCBjaOG7jW4gY+G7mXQgVGhhbmhQaG8gxJHhu4MgbmjDs20gZOG7ryBsaeG7h3UgdsOgIHNhdSDEkcOzIGTDuW5nIHRoYW0gc+G7kSBgLmtleWAgxJHhu4MgxJHhurd0IHTDqm4gY+G7mXQgZGFuaCBzw6FjaCB04bqhbyByYSBzYXUga2hpIGzhu5NuZyBk4buvIGxp4buHdS4NCg0KS+G6v3QgcXXhuqMgbMOgIG3hu5l0IGRhdGFmcmFtZSBt4bubaSBuZXN0ZWRfZGF0YSBjaOG7qWEgaGFpIGPhu5l0OiBUaGFuaFBobyB2w6AgRHVMaWV1LCB0cm9uZyDEkcOzIGPhu5l0IGhhaSBjaOG7qWEgZOG7ryBsaeG7h3UgxJHGsOG7o2MgbOG7k25nIHRow6BuaCBkYW5oIHPDoWNoIGThu7FhIHRyw6puIHTDqm4gdGjDoG5oIHBo4buRLiBDw6FjIHBo4bqnbiB04butIHRyb25nIGPhu5l0ICJEdUxpZXUiIGzDoCBjw6FjIGRhbmggc8OhY2ggZOG7ryBsaeG7h3UgY29uLCBt4buXaSBkYW5oIHPDoWNoIGNo4bupYSB0aMO0bmcgdGluIHbhu4EgbmfDoHksIGdp4budLCBuaGnhu4d0IMSR4buZIHbDoCDEkeG7mSDhuqltIHTGsMahbmcg4bupbmcgY2hvIHThu6tuZyB0aMOgbmggcGjhu5EuDQoNCkzhu4duaCBuZXN0KCkgdHJvbmcgdsOtIGThu6UgbsOgeSBnacO6cCBjaMO6bmcgdGEgbOG7k25nIGThu68gbGnhu4d1IHRoZW8gdMOqbiB0aMOgbmggcGjhu5EsIGdpw7pwIHThu5UgY2jhu6ljIHbDoCB44butIGzDvSBk4buvIGxp4buHdSB0aOG7nWkgdGnhur90IG3hu5l0IGPDoWNoIHRy4buxYyBxdWFuIHbDoCB0aHXhuq1uIHRp4buHbiBoxqFuDQoNClNhdSDEkcOzLCBjaMO6bmcgdGEgdGnhur9wIHThu6VjIHPhu60gZOG7pW5nIGjDoG0gbGFwcGx5KCkgxJHhu4Mgw6FwIGThu6VuZyBow6BtIHByaW50KCkgY2hvIG3hu5dpIHRpYmJsZSB0cm9uZyBkYW5oIHPDoWNoIG5lc3RlZF9kYXRhXCREdUxpZXUuIEvhur90IHF14bqjIGzDoCBj4bqjIGhhaSBk4buvIGxp4buHdSBi4bqjbmcgdOG7qyBjw6FjIHRpYmJsZSBz4bq9IMSRxrDhu6NjIGhp4buDbiB0aOG7iyB0csOqbiBtw6BuIGjDrG5oLCBt4buXaSB0aWJibGUgxJFpIGvDqG0gduG7m2kgdMOqbiBj4buZdCB2w6AgY8OhYyBnacOhIHRy4buLIHTGsMahbmcg4bupbmcuDQoNCkvhur90IHF14bqjIGhp4buHbiB0aOG7iyBs4bqnbiBsxrDhu6N0IGzDoCBi4bqjbmcgduG7gSB0aOG7m2kgdGnhur90IOG7nyBIw6AgTuG7mWkgdsOgIGLhuqNuZyBzYXUgxJHDsyBsw6AgYuG6o25nIHRo4budaSB0aeG6v3Qg4bufIEjhu5MgY2jDrSBNaW5oLiDEkMOzIGzDoCB2w60gZOG7pSB24buBIGjDoG0gbmVzdCgpIMSRxrDhu6NjIHPhu60gZOG7pW5nIGvhur90IGjhu6NwIHbhu5tpIGjDoG0gZ3JvdXBfYnkoKSB2w6AgaMOgbSBsYXBwbHkgxJHhu4MgY2hvIHJhIMSRxrDhu6NjIGvhur90IHF14bqjIGzDoCBjw6FjIGThu68gbGnhu4d1IGLhuqNuZyDEkcaw4bujYyBs4buTbmcgdsOgbyBuaGF1IHRoZW8gY8OhYyBiaeG6v24gY2jDum5nIHRhIGPhuqduIHRo4buRbmcga8OqDQoNCiMjIFVubmVzdA0KDQpUcm9uZyBuZ8O0biBuZ+G7ryBs4bqtcCB0csOsbmggUiwgbOG7h25oIGB1bm5lc3QoKWAgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdMOhY2ggZOG7ryBsaeG7h3UgdHJvbmcgbeG7mXQgY+G7mXQgY2jhu6lhIGPDoWMgxJHhu5FpIHTGsOG7o25nIGzhu5NuZyBuaGF1IHRow6BuaCBjw6FjIGPhu5l0IHJpw6puZyBiaeG7h3QuIMSQaeG7gXUgbsOgeSBnacO6cCBjaMO6bmcgdGEgcGjDom4gdMOhY2ggdsOgIHRydXkgY+G6rXAgZOG7hSBkw6BuZyB2w6BvIGPDoWMgdGjDoG5oIHBo4bqnbiBj4bunYSBjw6FjIMSR4buRaSB0xrDhu6NuZyDEkcaw4bujYyBs4buTbmcgbmhhdS4gQ8OhYyB0aGFtIHPhu5EgY2jDrW5oIHRyb25nIGjDoG0gYHVubmVzdCgpYCBn4buTbSBjw7M6DQoNCi0gICBkYXRhOiDEkOG7kWkgc+G7kSBuw6B5IGzDoCBk4buvIGxp4buHdSBn4buRYyBjaOG7qWEgY+G7mXQgZGFuaCBzw6FjaCBtw6AgY2jDum5nIHRhIG114buRbiBnaeG6o2kgbsOpbi4gxJDDonkgbMOgIG3hu5l0IMSR4buRaSBz4buRIGLhuq90IGJ14buZYyB2w6AgcGjhuqNpIGzDoCBt4buZdCBraHVuZyBk4buvIGxp4buHdSAoZGF0YSBmcmFtZSkuDQoNCi0gICBjb2w6IMSQw6J5IGzDoCDEkeG7kWkgc+G7kSBkw7luZyDEkeG7gyB4w6FjIMSR4buLbmggdMOqbiBj4bunYSBj4buZdCBkYW5oIHPDoWNoIGPhuqduIGdp4bqjaSBuw6luLiBOw7MgY8WpbmcgbMOgIG3hu5l0IMSR4buRaSBz4buRIGLhuq90IGJ14buZYyB2w6AgcGjhuqNpIGzDoCBt4buZdCBjaHXhu5dpIGvDvSB04buxLg0KDQotICAgLmRyb3A6IE3hu5l0IGdpw6EgdHLhu4sgbG9naWNhbCAoVFJVRSBob+G6t2MgRkFMU0UpIHjDoWMgxJHhu4tuaCB4ZW0gbGnhu4d1IGPDsyBuw6puIGxv4bqhaSBi4buPIGPhu5l0IGRhbmggc8OhY2ggc2F1IGtoaSBnaeG6o2kgbsOpbiBoYXkga2jDtG5nLiBHacOhIHRy4buLIG3hurdjIMSR4buLbmggbMOgIFRSVUUsIG5naMSpYSBsw6AgY+G7mXQgZGFuaCBzw6FjaCBz4bq9IGLhu4sgbG/huqFpIGLhu48uDQoNCkTGsOG7m2kgxJHDonkgbMOgIHbDrSBk4bulIHbhu4EgbOG7h25oIHVubmVzdCgpLCDEkeG6p3UgdGnDqm4gY2jDum5nIHTDtGkgc+G6vSB04bqhbyBkYXRhZnJhbWUgY2jhu6lhIGThu68gbGnhu4d1IHbhu4Egc+G6o24gcGjhuqltIHbDoCDEkeG6t2MgxJFp4buDbQ0KDQpgYGB7cn0NCmRhdGExIDwtIGRhdGEuZnJhbWUoDQogIFNhblBoYW0gPSBjKCJTUDEiLCAiU1AyIiwgIlNQMyIpLA0KICBNYXVTYWMgPSBJKGxpc3QoDQogICAgcmVwKGMoIsSQ4buPIiwgIlhhbmgiLCAiVsOgbmciKSwgZWFjaCA9IDMpLA0KICAgIHJlcChjKCJUcuG6r25nIiwgIsSQZW4iKSwgZWFjaCA9IDIpLA0KICAgIHJlcCgiQ2FtIiwgMykNCiAgKSksDQogIEtpY2hUaHVvYyA9IEkobGlzdCgNCiAgICByZXAoYygiUyIsICJNIiwgIkwiKSwgZWFjaCA9IDMpLA0KICAgIHJlcChjKCJNIiwgIkwiKSwgZWFjaCA9IDIpLA0KICAgIHJlcCgiUyIsIDMpDQogICkpLA0KICBHaWEgPSBjKDEwMCwgMjAwLCAxNTApDQopDQpwcmludChkYXRhMSkgIA0KYGBgDQoNCmBgYHtyfQ0KIyBUw6FjaCBkYW5oIHPDoWNoIMSR4bq3YyDEkWnhu4NtIHRow6BuaCBjw6FjIGPhu5l0IHJpw6puZyBiaeG7h3QNCmRhdGFfc3BsaXQgPC0gdW5uZXN0KGRhdGEgPSBkYXRhMSwgY29scyA9IGMoTWF1U2FjLEtpY2hUaHVvYykpDQoNCg0KIyBJbiBr4bq/dCBxdeG6oyBzYXUga2hpIHTDoWNoDQpkYXRhdGFibGUoZGF0YV9zcGxpdCkNCmBgYA0KDQpUcm9uZyB2w60gZOG7pSBuw6B5LCBjaMO6bmcgdGEgY8OzIG3hu5l0IGRhdGFmcmFtZSBkYXRhIGNo4bupYSB0aMO0bmcgdGluIHbhu4Egc+G6o24gcGjhuqltIHbDoCDEkeG6t2MgxJFp4buDbSBj4bunYSBjaMO6bmcuIEPhu5l0IE1hdVNhYyB2w6AgS2ljaFRodW9jIGzDoCBjw6FjIGPhu5l0IGNo4bupYSBkYW5oIHPDoWNoIGPDoWMgxJHhurdjIMSRaeG7g20gdMawxqFuZyDhu6luZyB24bubaSBt4buXaSBz4bqjbiBwaOG6qW0uDQoNClPhu60gZOG7pW5nIGzhu4duaCB1bm5lc3QoKSB0cm9uZyBnw7NpIHRpZHlyLCBjaMO6bmcgdGEgdMOhY2ggZGFuaCBzw6FjaCDEkeG6t2MgxJFp4buDbSAoTWF1U2FjIHbDoCBLaWNoVGh1b2MpIHRow6BuaCBjw6FjIGPhu5l0IHJpw6puZyBiaeG7h3QuIEvhur90IHF14bqjIGzDoCBt4buZdCBkYXRhZnJhbWUgbeG7m2kgZGF0YV9zcGxpdCB24bubaSBjw6FjIGPhu5l0IFNhblBoYW0sIE1hdVNhYywgS2ljaFRodW9jIHbDoCBHaWEsIHRyb25nIMSRw7MgY8OhYyBj4buZdCBNYXVTYWMgdsOgIEtpY2hUaHVvYyDEkcOjIMSRxrDhu6NjIHTDoWNoIHRow6BuaCBjw6FjIGPhu5l0IHJpw6puZyBiaeG7h3QuDQoNCiMjIGNvbXBsZXRlKCkNCg0KSMOgbSBjb21wbGV0ZSgpIHRyb25nIFIgbMOgbSBt4buZdCBjw7RuZyBj4bulIG3huqFuaCBt4bq9IMSR4buDIMSRaeG7gW4gY8OhYyBnacOhIHRy4buLIHRoaeG6v3UgdsOgIHThuqFvIHJhIGPDoWMgaMOgbmcgaG/DoG4gY2jhu4luaCB0cm9uZyBt4buZdCBkYXRhZnJhbWUsIC4gSMOgbSBjb21wbGV0ZSgpIGNobyBwaMOpcCBjaMO6bmcgdGEgxJFp4buBbiBjw6FjIGdpw6EgdHLhu4sgdGhp4bq/dSB0cm9uZyBkYXRhZnJhbWUgYuG6sW5nIGPDoWNoIHThuqFvIHJhIHThuqV0IGPhuqMgY8OhYyBr4bq/dCBo4bujcCBjw7MgdGjhu4MgY+G7p2EgY8OhYyBnacOhIHRy4buLIHRyb25nIGPDoWMgY+G7mXQgxJHGsOG7o2MgY2jhu4kgxJHhu4tuaC4gQ8OhYyBnacOhIHRy4buLIMSRw6MgY8OzIHPhur0gxJHGsOG7o2MgZ2nhu68gbmd1ecOqbiwgdHJvbmcga2hpIGPDoWMgZ2nDoSB0cuG7iyB0aGnhur91IHPhur0gxJHGsOG7o2MgxJFp4buBbiBi4bqxbmcgTkEgdHJvbmcga+G6v3QgcXXhuqMgaG/DoG4gY2jhu4luaC4gTmjhu69uZyDEkeG7kWkgc+G7kSBjw7MgdHJvbmcgaMOgbSBgY29tcGxldGUoKWAgbMOgDQoNCi0gICBkYXRhOiBMw6AgZGF0YSBmcmFtZSBjaOG7qWEgZOG7ryBsaeG7h3UgY+G6p24gbeG7nyBy4buZbmcgaG/hurdjIGhvw6BuIGNo4buJbmguDQoNCi0gICAuLi46IMSQxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIGNo4buJIMSR4buLbmggY8OhYyBj4buZdCBj4bqnbiBt4bufIHLhu5luZyBob+G6t2MgaG/DoG4gY2jhu4luaC4gQ8OhYyBj4buZdCBuw6B5IGPDsyB0aOG7gyBsw6AgY8OhYyB2ZWN0b3JzIGhv4bq3YyBkYW5oIHPDoWNoIChsaXN0cykuDQoNCi0gICBmaWxsOiDEkOG7kWkgc+G7kSBuw6B5IGNobyBwaMOpcCBjaMO6bmcgdGEgY3VuZyBj4bqlcCBt4buZdCBnacOhIHRy4buLIGR1eSBuaOG6pXQgY2hvIG3hu5dpIGJp4bq/biDEkeG7gyDEkWnhu4FuIHbDoG8gdGhheSB2w6wgZ2nDoSB0cuG7iyBOQSBjaG8gY8OhYyBr4bq/dCBo4bujcCBi4buLIHRoaeG6v3UuDQoNCi0gICBleHBsaWNpdDogTuG6v3UgdGhhbSBz4buRIG7DoHkgYuG6sW5nIFRSVUUgdOG6pXQgY+G6oyBnacOhIHRy4buLIE5BIMSR4buBdSBz4bq9IMSRxrDhu6NjIMSRaeG7gW4sIGPDsm4gbuG6v3UgYuG6sW5nIEZBTFNFIGNo4buJIGPDoWMgZ2nDoSB0cuG7iyBOQSDEkcaw4bujYyB04bqhbyByYSBi4bufaSBow6BtIG3hu5tpIMSRxrDhu6NjIMSRaeG7gW4uDQoNClbDrSBk4bulOiBHaeG6oyBz4butIGNow7puZyB0YSBjw7MgbeG7mXQgYuG6o25nIGThu68gbGnhu4d1IHbhu4EgY8OhYyBz4bqjbiBwaOG6qW0gY8OzIHRow7RuZyB0aW4gduG7gSB0w6puIHPhuqNuIHBo4bqpbSwgbG/huqFpIHPhuqNuIHBo4bqpbSB2w6AgZ2nDoSB0aeG7gW4uIFR1eSBuaGnDqm4sIGLhuqNuZyBk4buvIGxp4buHdSB0aGnhur91IG3hu5l0IHPhu5EgZ2nDoSB0cuG7iyBob+G6t2MgY8OzIGPDoWMgc+G6o24gcGjhuqltIGtow7RuZyBjw7MgZ2nDoSB0aeG7gW4uIENow7puZyB0YSBtdeG7kW4gxJFp4buBbiBjw6FjIGdpw6EgdHLhu4sgdGhp4bq/dSB2w6AgdOG6oW8gcmEgY8OhYyBz4bqjbiBwaOG6qW0gaG/DoG4gY2jhu4luaCB24bubaSB04bqldCBj4bqjIGPDoWMgY+G7mXQuDQoNCmBgYHtyfQ0KIyBU4bqhbyBkYXRhZnJhbWUgY2jhu6lhIHRow7RuZyB0aW4gduG7gSBz4bqjbiBwaOG6qW0NCmRhdGEyIDwtIGRhdGEuZnJhbWUoDQogIFRlblNhblBoYW0gPSBjKCJTUDEiLCAiU1AyIiwgIlNQMyIsICJTUDQiKSwNCiAgTG9haVNhblBoYW0gPSBjKCJBIiwgTkEsICJCIiwgIkMiKSwNCiAgR2lhVGllbiA9IGMoMTAwLCBOQSwgMjAwLCBOQSkNCikNCnByaW50KGRhdGEyKQ0KYGBgDQoNCmBgYHtyfQ0KIyDEkGnhu4FuIGPDoWMgZ2nDoSB0cuG7iyB0aGnhur91IHbDoCB04bqhbyByYSBjw6FjIHPhuqNuIHBo4bqpbSBob8OgbiBjaOG7iW5oDQpkYXRhX2NvbXBsZXRlIDwtIGNvbXBsZXRlKGRhdGEyLCBUZW5TYW5QaGFtLCBMb2FpU2FuUGhhbSwgR2lhVGllbikNCg0KIyBJbiBr4bq/dCBxdeG6oyBzYXUga2hpIMSRaeG7gW4gZ2nDoSB0cuG7iyB0aGnhur91IHbDoCB04bqhbyBow6BuZyBob8OgbiBjaOG7iW5oDQpvcHRpb25zKG1heC5wcmludD0gMTAwKQ0KcHJpbnQoZGF0YV9jb21wbGV0ZSwgbiA9IG5yb3coZGF0YV9jb21wbGV0ZSkpDQoNCmBgYA0KDQpUcm9uZyB2w60gZOG7pSB0csOqbiwgY2jDum5nIHRhIMSRw6Mgc+G7rSBk4bulbmcgaMOgbSBjb21wbGV0ZSgpIMSR4buDIMSRaeG7gW4gY8OhYyBnacOhIHRy4buLIHRoaeG6v3UgdsOgIHThuqFvIHJhIGPDoWMgaMOgbmcgaG/DoG4gY2jhu4luaCB0cm9uZyBkYXRhZnJhbWUgZGF0YS4gQ8OhYyBj4buZdCBUZW5TYW5QaGFtLCBMb2FpU2FuUGhhbSB2w6AgR2lhVGllbiDEkcOjIMSRxrDhu6NjIGNo4buJIMSR4buLbmggbMOgIGPDoWMgY+G7mXQgY+G6p24gaG/DoG4gY2jhu4luaC4gSMOgbSBjb21wbGV0ZSgpIMSRw6MgdOG6oW8gcmEgdOG6pXQgY+G6oyBjw6FjIGvhur90IGjhu6NwIGPDsyB0aOG7gyBj4bunYSBjw6FjIGdpw6EgdHLhu4sgdHJvbmcgY8OhYyBj4buZdCDEkcaw4bujYyBjaOG7iSDEkeG7i25oIHbDoCDEkWnhu4FuIGPDoWMgZ2nDoSB0cuG7iyB0aGnhur91IGLhurFuZyBOQSDEkeG7gyB04bqhbyByYSBjw6FjIGjDoG5nIGhvw6BuIGNo4buJbmguIEvhur90IHF14bqjIMSRxrDhu6NjIGluIHJhIG3DoG4gaMOsbmggxJHhu4MgaGnhu4NuIHRo4buLIGThu68gbGnhu4d1IMSRw6MgxJHGsOG7o2MgxJFp4buBbiB2w6AgdOG6oW8gaMOgbmcgaG/DoG4gY2jhu4luaC4NCg0KVHJvbmcga+G6v3QgcXXhuqMsIGNow7puZyB0YSBjw7MgY8OhYyBow6BuZyBob8OgbiBjaOG7iW5oIHbhu5tpIHThuqV0IGPhuqMgY8OhYyBr4bq/dCBo4bujcCBj4bunYSBjw6FjIGdpw6EgdHLhu4sgdHJvbmcgY8OhYyBj4buZdCBUZW5TYW5QaGFtLCBMb2FpU2FuUGhhbSB2w6AgR2lhVGllbi4gQ8OhYyBnacOhIHRy4buLIHRoaeG6v3UgxJHGsOG7o2MgxJFp4buBbiBi4bqxbmcgTkEgxJHhu4MgdOG6oW8gcmEgY8OhYyBow6BuZyBob8OgbiBjaOG7iW5oLg0KDQpgYGB7cn0NCiMgVGjDqm0gdsOgbyB0aGFtIHPhu5EgZmlsbCANCmRhdGFfY29tcGxldGUgPC0gY29tcGxldGUoZGF0YTIsIFRlblNhblBoYW0sIExvYWlTYW5QaGFtLCBHaWFUaWVuLCBmaWxsID0gbGlzdChMb2FpU2FuUGhhbT0iQyIsR2lhVGllbj0xNTApICkNCmRhdGF0YWJsZShkYXRhX2NvbXBsZXRlKQ0KYGBgDQoNClR1eSBuaGnDqm4sIGNow7puZyB0YSBjw7MgdGjhu4Mgw6FwIGThu6VuZyB0aGFtIHPhu5EgZmlsbCDEkeG7gyBjdW5nIGPhuqVwIG3hu5l0IGdpw6EgdHLhu4sgY2hvIG3hu5dpIGPhu5l0IGThu68gbGnhu4d1IHRoYXkgY2hvIGdpw6EgdHLhu4sgTkEuIOG7niBj4buZdCBMb2FpU2FuUGhhbSB0YSBjw7MgdGjhu4MgY2jhu41uICJDIiDEkeG7gyB0aGF5IHRo4bq/IGNobyBuaOG7r25nIGdpw6EgdHLhu4sgTkEsIHTGsMahbmcgdOG7sSB0cm9uZyBj4buZdCBHaWFUaWVuIGNo4buNbiBnacOhIHRy4buLIGzDoCAxNTAuDQoNClTDs20gbOG6oWksIHZp4buHYyBz4butIGThu6VuZyBow6BtIGNvbXBsZXRlKCkgc+G6vSBnacO6cCB0YSBxdeG6o24gbMO9IGThu68gbGnhu4d1IHRoaeG6v3UgdsOgIGNodeG6qW4gYuG7iyBk4buvIGxp4buHdSBjaG8gcGjDom4gdMOtY2ggdsOgIGtow6FtIHBow6EgZOG7ryBsaeG7h3UgbeG7mXQgY8OhY2ggZOG7hSBkw6BuZyB2w6AgaGnhu4d1IHF14bqjLg0KDQojIyBDw6FjIGjDoG0geOG7rSBsw70gZ2nDoSB0cuG7iyBOQQ0KDQpUcm9uZyBwYWNrYWdlIHRpZHlyLCBjaMO6bmcgdGEgY8OzIHRo4buDIHPhu60gZOG7pW5nIGPDoWMgaMOgbSBuaMawIGBkcm9wX25hKClgLCBgZmlsbCgpYCwgdsOgYHJlcGxhY2VfbmEoKWAgxJHhu4MgeOG7rSBsw70gY8OhYyBnacOhIHRy4buLIE5BIHRyb25nIGThu68gbGnhu4d1IGPhu6dhIG3DrG5oLiBUaGFvIHTDoWMgbsOgeSBy4bqldCBj4bqnbiB0aGnhur90IMSR4buRaSB2w6wgZOG7ryBsaeG7h3UgxJHGsOG7o2MgxJFlbSB2w6BvIHBow6JuIHTDrWNoIHBo4bqjaSDEkeG6p3kgxJHhu6cgdsOgIMSR4buZIGNow61uaCB4w6FjIGNhbyB0aMOsIGvhur90IHF14bqjIHRodSDEkcaw4bujYyBz4bq9IHBo4bqjbiDDoW5oIMSRw7puZyBuaOG6pXQgduG7m2kgdGjhu7FjIHThur8uIERvIMSRw7MsIHZp4buHYyBz4butIGThu6VuZyB0aMOgbmggdGjhuqFvIGPDoWMgY8O0bmcgY+G7pSB0csOqbiBz4bq9IGdpw7pwIGNow7puZyB0YSB04buRaSDGsHUgaMOzYSB0aOG7nWkgZ2lhbiBsw6BtIHZp4buHYyBj4bunYSBtw6xuaCBjxaluZyBuaMawIGzDoCDEkeG6oXQgxJHGsOG7o2Mga+G6v3QgcXXhuqMgdOG7kXQgaMahbiDhu58gbmjhu69uZyBixrDhu5tjIHRp4bq/cCB0aGVvLg0KDQpDaMO6bmcgdMO0aSBz4bq9IHRo4buxYyBoaeG7h24gY8OhYyB2w60gZOG7pSBk4buxYSB0csOqbiBk4buvIGxp4buHdSBjw7MgY+G6pXUgdHLDumMga2jDoSDEkcahbiBnaeG6o24gbmjhurFtIG3hu6VjIMSRw61jaCBnaeG7m2kgdGhp4buHdSBuaOG7r25nIGjDoG0geOG7rSBsw70gY8OhYyBnacOhIHRy4buLIGLhu4sgdGhp4bq/dSwgbmdvw6BpIHJhIGPFqW5nIGdpw7pwIG5nxrDhu51pIMSR4buNYyBjw7MgdGjhu4MgZOG7hSBkw6BuZyBuaOG6rW4gcmEgxJHGsOG7o2MgbeG7qWMgxJHhu5kgaGnhu4d1IHF14bqjIGPhu6dhIG7DsyBraGkgxJHGsOG7o2Mgw6FwIGThu6VuZyBsw6puIGLhu5kgZOG7ryBsaeG7h3UgxJHGoW4gZ2nhuqNuLiBTYXUgxJHDsywgY2jGsMahbmcgdGnhur9wIHRoZW8gY2jDum5nIHTDtGkgc+G6vSBz4butIGThu6VuZyBsw6puIGThu68gbGnhu4d1IHBo4bupYyB04bqhcCBoxqFuIHbDoCBr4bq/dCBo4bujcCB0aMOqbSBt4buZdCBz4buRIGjDoG0ga2jDoWMgxJHhu4MgYmnhur9uIMSR4buVaSB24buBIGThuqFuZyBk4buvIGxp4buHdSBz4bqhY2guDQoNCsSQ4buDIHRo4buxYyBoaeG7h24gY8OhYyBs4buHbmggY2jDum5nIHTDtGkgc+G6vSB04bqhbyBt4buZdCBkYXRhZnJhbWUgY8OzIHTDqm4gbMOgICpkZiogZ+G7k20gY8OzIGPhu5l0ICpkYXRlKiBjaOG7qWEgY2h14buXaSBuZ8OgeSBi4bqvdCDEkeG6p3UgdOG7qyAiMjAyMy0wNy0wMSIgxJHhur9uICIyMDIzLTA3LTEwIiB2w6AgY+G7mXQgKnNhbGVzKiBjaOG7qWEgc+G7kSBsxrDhu6NuZyBz4bqjbiBwaOG6qW0gxJHGsOG7o2MgYsOhbiBow6BuZyBuZ8OgeSwgdHJvbmcgxJHDsyBjw7MgbeG7mXQgc+G7kSBnacOhIHRy4buLIE5BICh0aGnhur91IHRow7RuZyB0aW4pIMSR4buDIMSR4bqhaSBkaeG7h24gY2hvIGPDoWMgbmfDoHkga2jDtG5nIGPDsyBk4buvIGxp4buHdS4NCg0KYGBge3J9DQojIFThuqFvIGThu68gbGnhu4d1IHbDrSBk4bulDQpkZiA8LSBkYXRhLmZyYW1lKA0KICBkYXRlID0gc2VxKGFzLkRhdGUoIjIwMjMtMDctMDEiKSwgYXMuRGF0ZSgiMjAyMy0wNy0xMCIpLCBieSA9ICJkYXkiKSwNCiAgc2FsZXMgPSBjKDEwMCwgTkEsIDEyMCwgODAsIE5BLCA5MCwgTkEsIE5BLCAxMTAsIDk1KQ0KKQ0KcHJpbnQoZGYpDQoNCg0KYGBgDQoNCjEuICBYw7NhIGPDoWMgZMOybmcgY2jhu6lhIGdpw6EgdHLhu4sgTkEgImRyb3BfbmEoKSINCg0KSMOgbSBgZHJvcF9uYShkZilgIHPhur0geMOzYSBjw6FjIGTDsm5nIHRyb25nIGRhdGFmcmFtZSBkZiBjaOG7qWEgZ2nDoSB0cuG7iyBOQS4gS+G6v3QgcXXhuqMgxJHGsOG7o2MgZ8OhbiB2w6BvIGRhdGFmcmFtZSAqZGZfY2xlYW5lZCogxJHGsOG7o2MgdGjhu4MgaGnhu4duIGLDqm4gZMaw4bubaS4gQ2jDum5nIHRhIHRo4bqleSBy4bqxbmcgY+G6oyA0IGTDsm5nIGPDsyBnacOhIHRy4buLIE5BIMSRw6MgYuG7iyB4w7NhIMSRaSBt4bqldCBiw6J5IGdp4budIGThu68gbGnhu4d1IGNo4buJIGPDsm4gbOG6oWkgNiBkw7JuZy4NCg0KYGBge3J9DQojIFjDs2EgY8OhYyBkw7JuZyBjaOG7qWEgZ2nDoSB0cuG7iyBOQQ0KZGZfY2xlYW5lZCA8LSBkcm9wX25hKGRmKQ0KYGBgDQoNCmBgYHtyLGVjaG89RkFMU0V9DQpwcmludChkZl9jbGVhbmVkKQ0KYGBgDQoNCjIuICDEkGnhu4FuIGPDoWMgZ2nDoSB0cuG7iyBOQSBi4bqxbmcgZ2nDoSB0cuG7iyBj4bulIHRo4buDICJmaWxsKCkiDQoNCk5nb8OgaSByYSwgY2jDum5nIHRhIGPDsyB0aOG7gyDEkWnhu4FuIGhv4bq3YyB0aGF5IHRo4bq/IGPDoWMgZ2nDoSB0cuG7iyBt4bubaSBjaG8gY8OhYyBkw7JuZyBi4buLIE5BIHRyb25nIGPhu5l0IGThu68gbGnhu4d1IGLhurFuZyBow6BtIGBmaWxsKClgLiDEkGnhu4FuIGdpw6EgdHLhu4sgc+G6vSBk4buxYSB2w6BvIGPDoWMgZMOybmcgZOG7ryBsaeG7h3Ug4bufIHBow61hIHRyw6puIGhv4bq3YyBwaMOtYSBkxrDhu5tpIMSR4buDIGhvw6BuIHRoaeG7h24gY8OhYyBkw7JuZyBOQSB0cm9uZyBj4buZdC4NCg0KxJDhu4Mgc+G7rSBk4bulbmcgaMOgbSBgZmlsbCgpYCB0aMOsIHRyxrDhu5tjIHRpw6puIHRhIGPhuqduIGtoYWkgYsOhbyBi4buZIGThu68gbGnhu4d1IGPhuqduIHjhu60gbMO9IGThu68gbGnhu4d1IHRoaeG6v3UgdHJvbmcgdHLGsOG7nW5nIGjhu6NwIG7DoHkgbMOgICpkZiosIHNhdSDEkcOzIGNo4buNbiBj4buZdCBjaOG7qWEgY8OhYyBnacOhIHRy4buLIGzDoCAqc2FsZXMqIHbDoCDEkeG7kWkgc+G7kSBgLmRpcmVjdGlvbmAgZ2nDunAgdGEgY2jhu41uIGjGsOG7m25nIMSR4buDIMSRaeG7gW4gZ2nDoSB0cuG7iyB0aGnhur91LCBt4bq3YyDEkeG7i25oIHPhur0gbMOgICJkb3duIiDEkWnhu4FuIHThu6sgdHLDqm4geHXhu5FuZy4NCg0KROG7sWEgdsOgbyBi4bqjbmcga+G6v3QgcXXhuqMgdGEgY8OzIHRo4buDIHRo4bqleSDhu58gbmfDoHkgMiB0aMOsIHPhu5EgbMaw4bujbmcgc+G6o24gcGjhuqltIMSRxrDhu6NjIGLDoW4gdHJvbmcgbmfDoHkgc+G6vSDEkcaw4bujYyDEkWnhu4FuIGzDoCAxMDAgZOG7sWEgdsOgbyBkw7JuZyBk4buvIGxp4buHdSDhu58gdHLGsOG7m2MgxJHDsywgdMawxqFuZyB04buxIGNobyBjw6FjIG5nw6B5IGLDqm4gZMaw4bubaS4NCg0KYGBge3J9DQpkZl9maWxsZWQgPC0gZmlsbChkYXRhPWRmLHNhbGVzLC5kaXJlY3Rpb24gPSAiZG93biIpDQpgYGANCg0KYGBge3IsZWNobz1GQUxTRX0NCnByaW50KGRmX2ZpbGxlZCkNCmBgYA0KDQpUw7l5IHbDoG8gbeG7pWMgxJHDrWNoIGNow7puZyB0YSBjw7MgdGjhu4MgxJFp4buBbiBnacOhIHRy4buLIGLhu4sgdGhp4bq/dSB0aGVvIMSRaeG7gXUgaMaw4bubbmcgdOG7qyBwaMOtYSBkxrDhu5tpIGzDqm4gbmjGsCBi4bqjbmcga+G6v3QgcXXhuqMgYsOqbiBkxrDhu5tpIOG7nyBuZ8OgeSA3IHbDoCA4IGdpw6EgdHLhu4sgTkEgxJHGsOG7o2MgdGhheSB0aOG6vyBi4bqxbmcgMTEwIGThu7FhIHbDoG8gc+G7kSBsxrDhu6NuZyBiw6FuIGjDoG5nIGPhu6dhIG5nw6B5IDkNCg0KYGBge3J9DQpkZl9maWxsZWQyIDwtIGZpbGwoZGF0YT1kZixzYWxlcywuZGlyZWN0aW9uID0gInVwIikNCg0KYGBgDQoNCmBgYHtyLGVjaG89RkFMU0V9DQpwcmludChkZl9maWxsZWQyKQ0KYGBgDQoNCjMuICBUaGF5IHRo4bq/IGPDoWMgZ2nDoSB0cuG7iyBOQSBi4bqxbmcgZ2nDoSB0cuG7iyBraMOhYyAicmVwbGFjZV9uYSgpIg0KDQpN4buZdCBjw6FjaCBraMOhYyBkw7luZyDEkeG7gyB44butIGzDvSBnacOhIHRy4buLIHRoaeG6v3UgbMOgIHRoYXkgdGjhur8gbsOzIGLhurFuZyBt4buZdCBnacOhIHRy4buLIGPhu6UgdGjhu4MgbcOgIGNow7puZyB0YSB4w6FjIMSR4buLbmgsIGdpw6EgdHLhu4sgxJHGsOG7o2MgZMO5bmcgdGhheSB0aOG6vyBjw7MgdGjhu4MgbMOgIG3hu5l0IGNvbiBz4buRLCBt4buZdCB2ZWN0b3IgdsOgIG7DsyB0aGF5IHRo4bq/IGNobyB04bqldCBj4bqjIGdpw6EgdHLhu4sgdGhp4bq/dSB0cm9uZyBj4buZdCBk4buvIGxp4buHdSBtw6AgY2jDum5nIHRhIGNo4buJIMSR4buLbmguDQoNClRyb25nIHbDrSBk4bulIGNow7puZyB0w7RpIHTDrW5oIGdpw6EgdHLhu4sgdHJ1bmcgYsOsbmggY+G7p2EgY+G7mXQgc2FsZXMgdHJvbmcgZGF0YWZyYW1lICpkZiogdsOgIGxv4bqhaSBi4buPIGPDoWMgZ2nDoSB0cuG7iyBOQSBi4bqxbmcgxJHhu5FpIHPhu5EgYG5hLnJtID0gVFJVRWAgLiBUaeG6v3AgdGhlbywgc+G7rSBk4bulbmcgaMOgbSBgcmVwbGFjZV9uYSgpYCDEkeG7gyB0aGF5IHRo4bq/IGPDoWMgZ2nDoSB0cuG7iyBOQSB0cm9uZyBj4buZdCAqc2FsZXMqIGPhu6dhIGRhdGFmcmFtZSBkZiBi4bqxbmcgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCB2w6Aga+G6v3QgcXXhuqMgxJHGsOG7o2MgZ8OhbiB2w6BvIGRhdGFmcmFtZSBkZl9yZXBsYWNlZA0KDQpgYGB7cn0NCiMgVGhheSB0aOG6vyBjw6FjIGdpw6EgdHLhu4sgTkEgYuG6sW5nIGdpw6EgdHLhu4sgdHJ1bmcgYsOsbmggY+G7p2Egc2FsZXMNCm1lYW5fc2FsZXMgPC0gbWVhbihkZiRzYWxlcywgbmEucm0gPSBUUlVFKQ0KZGZfcmVwbGFjZWQgPC0gcmVwbGFjZV9uYShkYXRhPWRmLCByZXBsYWNlID0gIGxpc3Qoc2FsZXMgPSBtZWFuX3NhbGVzKSkNCmBgYA0KDQpgYGB7cixlY2hvPUZBTFNFfQ0KIyBJbiBk4buvIGxp4buHdSDEkcOjIHjhu60gbMO9DQpwcmludChkZl9yZXBsYWNlZCkNCg0KYGBgDQoNCiMgQ0jGr8agTkcgMzog4buoTkcgROG7pE5HIEPhu6ZBIFRJRFlSDQoNClRyb25nIGNoxrDGoW5nIG7DoHkgY2jDum5nIHTDtGkgc+G6vSDhu6luZyBk4bulbmcgY8OhYyBow6BtIMSRxrDhu6NjIGdp4bubaSB0aGnhu4d1IOG7nyBjaMawxqFuZyAyIHbDoG8gcGjDom4gdMOtY2ggbeG7mXQgc+G7kSBi4buZIGThu68gbGnhu4d1IMSR4buDIG3hu41pIG5nxrDhu51pIG5o4bqtbiB0aOG6pXkgxJHGsOG7o2Mgc+G7sSBoaeG7h3UgcXXhuqMgY+G7p2EgZ8OzaSBUaWR5ciB0cm9uZyBnaWFpIMSRb+G6oW4geOG7rSBsw70gZOG7ryBsaeG7h3UgY2jGsGEgc+G6oWNoLiBOZ2/DoGkgcmEsIGNow7puZyB0w7RpIGvhur90IGjhu6NwIG3hu5l0IHPhu5EgZ8OzaSBraMOhYyBjaOG6s25nIGjhuqFuIG5oxrAgZHBseXIsIGdncGxvdCwgdGlkeXZlcnNlLi4uIMSR4buDIHRodeG6rW4gdGnhu4duIHRyb25nIGPDoWMgdGhhbyB0w6FjIHBow6JuIHTDrWNoIGPFqW5nIG5oxrAgdHLhu7FjIHF1YW4gaMOzYSBk4buvIGxp4buHdSB04burIMSRw7MgdGh1IMSRxrDhu6NjIGvhur90IHF14bqjIHThu5F0IG5o4bqldC4NCg0KIyMgQuG7mSBk4buvIGxp4buHdSBnYXBtaW5kZXINCg0KVHLGsOG7m2Mga2hpIHBow6JuIHTDrWNoIHRow6wgY2jDum5nIHTDtGkgc+G6vSBnaeG7m2kgdGhp4buHdSBi4buZIGThu68gbGnhu4d1ICJnYXBtaW5kZXIiIHRyb25nIHBhY2thZ2UgZ2FwbWluZGVyIGfhu5NtIGPDsyBuaOG7r25nIHRow7RuZyB0aW4gdsOgIGJp4bq/biBuw6BvIMSR4buDIG5nxrDhu51pIMSR4buNYyBjw7Mgc+G7sSBuaMOsbiBuaOG6rW4gdOG7lW5nIHF1w6F0IHbhu4EgbsOzLCDEkWnhu4F1IG7DoHkgc+G6vSBo4buvdSDDrWNoIHRyb25nIHZp4buHYyBoaeG7g3UgcsO1IGPDoWMgbOG7h25oIMSRxrDhu6NjIMOhcCBk4bulbmcgc+G6vSBtYW5nIGzhuqFpIGvhur90IHF14bqjIG5oxrAgdGjhur8gbsOgby4NCg0KQuG7mSBk4buvIGxp4buHdSAiZ2FwbWluZGVyIiBjdW5nIGPhuqVwIHRow7RuZyB0aW4gduG7gSB0deG7lWkgdGjhu40gdHJ1bmcgYsOsbmgsIGTDom4gc+G7kSB2w6AgR0RQIHBlciBjYXBpdGEgY+G7p2EgY8OhYyBxdeG7kWMgZ2lhIHThu6sgbsSDbSAxOTUyIMSR4bq/biAyMDA3IHbhu5tpIGNodSBr4buzIGzDoCA1IG7Eg20gc+G6vSB0aHUgdGjhuq1wIGThu68gbGnhu4d1IG3hu5l0IGzhuqduLiBOw7MgZ2nDunAgdGEgbuG6r20gYuG6r3QgxJHGsOG7o2Mgc+G7sSB0aGF5IMSR4buVaSB2w6Agc+G7sSBwaMOhdCB0cmnhu4NuIGPhu6dhIGPDoWMgcXXhu5FjIGdpYSB0aGVvIHRo4budaSBnaWFuLiBE4buvIGxp4buHdSBuw6B5IGfhu5NtIDE3MDQgcXVhbiBzw6F0IHbDoCBjw7MgNiBiaeG6v24gdHJvbmcgxJHDszoNCg0KLSAgIGNvdW50cnk6IFTDqm4gcXXhu5FjIGdpYS4NCg0KLSAgIGNvbnRpbmVudDogTOG7pWMgxJHhu4thIG7GoWkgcXXhu5FjIGdpYSB0aHXhu5ljIHbhu4EuIEPDsyA1IGdpw6EgdHLhu4s6IEFmcmljYSwgQW1lcmljYXMsIEFzaWEsIEV1cm9wZSwgdsOgIE9jZWFuaWEuDQoNCi0gICB5ZWFyOiBOxINtIGdoaSBuaOG6rW4gZOG7ryBsaeG7h3UuDQoNCi0gICBsaWZlRXhwOiBUdeG7lWkgdGjhu40gdHJ1bmcgYsOsbmggY+G7p2EgZMOibiBz4buRIHRyb25nIHF14buRYyBnaWEsIHTDrW5oIGLhurFuZyDEkcahbiB24buLIG7Eg20uDQoNCi0gICBwb3B1bGF0aW9uOiBEw6JuIHPhu5EgY+G7p2EgcXXhu5FjIGdpYSB0cm9uZyBuxINtIGPhu6UgdGjhu4MuDQoNCi0gICBnZHBQZXJjYXA6IEdEUCB0csOqbiBt4buXaSBuZ8aw4budaSBkw6JuIGPhu6dhIG3hu5l0IHF14buRYyBnaWEgdHJvbmcgbsSDbSBj4bulIHRo4buDLg0KDQpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KERUKQ0KYGBgDQoNCsSQ4bqndSB0acOqbiwgY2jDum5nIHRhIGPhuqduIGfhu41pIGThu68gbGnhu4d1ICJnYXBtaW5kZXIiIGLhurFuZyBs4buHbmggYGRhdGFgIHNhdSBraGkgxJHDoyBjw6BpIMSR4bq3dCBwYWNrYWdlICpnYXBtaW5kZXIqIHbDoCB04bqjaSB0aMawIHZp4buHbiBj4bunYSBuw7MgbMOqbiwgZOG7ryBsaeG7h3Ugc+G6vSDEkcaw4bujYyBnw6FuIHbDoG8gYmnhur9uICJnIiBnacO6cCB2aeG7h2Mgbmjhuq1wIGzhu4duaCB0cuG7nyBuw6puIGThu4UgZMOgbmcgaMahbiBzbyB24bubaSB0w6puIGJhbiDEkeG6p3UuDQoNCkLhuqNuZyBk4buvIGxp4buHdSBiw6puIGTGsOG7m2ksIG3hu5dpIHF1YW4gc8OhdCBz4bq9IGNobyBiaeG6v3QgdGjDtG5nIHRpbiB24buBIHTDqm4gcXXhu5FjIGdpYSwgY2jDonUgbOG7pWMgY+G7p2EgcXXhu5FjIGdpYSwgbsSDbSBraOG6o28gc8OhdCB2w6AgY8OhYyBjaOG7iSBz4buRIHbhu4EgdHXhu5VpIHRo4buNIHRydW5nIGLDrG5oLCBkw6JuIHPhu5EsIEdEUCB0csOqbiBt4buXaSBjw6EgbmjDom4gdMawxqFuZyDhu6luZy4gRG8gxJHDsywgbsOzIHRodeG7mWMgZOG6oW5nIGThu68gbGnhu4d1ICJy4buZbmciIMSRaeG7gXUgbsOgeSBz4bq9IGdpw7pwIHZp4buHYyBuaOG6rXAgZOG7ryBsaeG7h3UgaG/hurdjIHRyw6xuaCBiw6B5IGLhuqNuZyB04buRdCBoxqFuLCBuZ8aw4budaSDEkeG7jWMgYsOhbyBjw6FvIGPDsyB0aOG7gyBoaeG7g3UgcsO1IMSRxrDhu6NjIG7hu5lpIGR1bmcgbcOgIGtow7RuZyBt4bqldCBxdcOhIG5oaeG7gXUgdGjhu51pIGdpYW4uIFR1eSBuaGnDqm4gZOG6oW5nIGThu68gbGnhu4d1ICJy4buZbmciIHPhur0gZ+G6t3Aga2jDsyBraMSDbiB0cm9uZyB2aeG7h2MgcGjDom4gdMOtY2ggdsOsIHbhuq15IGNow7puZyB0YSBj4bqnbiBwaOG6o2kgY2h1eeG7g24gc2FuZyBk4bqhbmcgImTDoGkiLg0KDQpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KGdhcG1pbmRlcikNCmRhdGEoImdhcG1pbmRlciIpDQpnIDwtIGdhcG1pbmRlcg0KZGF0YXRhYmxlKGcpDQoNCmBgYA0KDQpIw6BtIGBwaXZvdF9sb25nZXIoKWBz4bq9IGNodXnhu4NuIGThu68gbGnhu4d1ICJnIiBzYW5nIGThuqFuZyBkw6BpIGLhurFuZyBjw6FjaCBjaHV54buDbiDEkeG7lWkgYmEgY+G7mXQgKmxpZmVFeHAsIHBvcCwgZ2RwUGVyY2FwKiB0aMOgbmggaGFpIGPhu5l0IG3hu5tpIGzDoCAqY2hpc28qIGNo4bupYSB0w6puIGPDoWMgY2jhu4kgc+G7kSB2w6AgKmdpYXRyaSogY2jhu6lhIGPDoWMgZ2nDoSB0cuG7iyBj4bunYSBjw6FjIGJp4bq/biBiYW4gxJHhuqd1LiBTYXUgxJHDsyBz4bq9IGfDoW4gZOG7ryBsaeG7h3UgxJHGsOG7o2MgY2h1eeG7g24gxJHhu5VpIHbDoG8gImcyIiwgZOG7ryBsaeG7h3UgbsOgeSBz4bq9IGPDsyBz4buRIHF1YW4gc8OhdCBsw6AgNTExMiB0dXkgbmhpw6puIHRow6wgc+G7kSBsxrDhu6NuZyBiaeG6v24gc+G6vSDDrXQgaMahbiBk4buvIGxp4buHdSBiYW4gxJHhuqd1ICg1IGPhu5l0IHNvIHbhu5tpIDYgY+G7mXQpLg0KDQpgYGB7cn0NCmcyIDwtIHBpdm90X2xvbmdlcihkYXRhID0gZyAsIGNvbHMgPSBjKGxpZmVFeHAscG9wLGdkcFBlcmNhcCksIG5hbWVzX3RvID0gImNoaXNvIiwgdmFsdWVzX3RvID0gImdpYXRyaSIpDQpoZWFkKGcyKQ0KYGBgDQoNCk7hur91IHRhIG114buRbiB0w61uaCB0cnVuZyBiw6xuaCBj4bunYSBjw6FjIGNo4buJIHPhu5EgbsOgeSB0aGVvIHThu6tuZyBjaMOidSBs4bulYyBraMOhYyBuaGF1IG5o4bqxbSBt4bulYyDEkcOtY2ggxJHDoW5oIGdpw6EgdOG7lW5nIHRo4buDIHPhu7EgcGjDoXQgdHJp4buDbiBnaeG7r2EgY8OhYyBjaMOidSB24bubaSBuaGF1LCB0YSBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgdGjDqm0gaMOgbSBgZ3JvdXBfYnlgIMSR4buDIG5ow7NtIGThu68gbGnhu4d1IHRoZW8gY+G7mXQgKmNvbnRpbmVudCwgY2hpc28qIHbDoCBow6BtIGBzdW1tYXJpc2VgIMSR4buDIHRo4buxYyBoaeG7h24gcGjDqXAgdMOtbmggdHJ1bmcgYsOsbmggY2hvIGPhu5l0ICpnaWF0cmkqIGPhu6dhIGPDoWMgbmjDs20gZOG7ryBsaeG7h3UuIEPhuqMgaGFpIGjDoG0gdHLDqm4gxJHhu4F1IG7hurFtIHRyb25nIGfDs2kgKipkcGx5cioqIGPDsyB0aOG7gyBr4bq/dCBo4bujcCB24bubaSBnw7NpICoqdGlkeXIqKiDEkeG7gyBiaeG6v24gxJHhu5VpIGThu68gbGnhu4d1IGNoxrBhIHPhuqFjaCBy4bqldCBoaeG7h3UgcXXhuqMuDQoNCkvhur90IHF14bqjIHRodSDEkcaw4bujYyBz4bq9IMSRxrDhu6NjIGfDoW4gdsOgbyAibWVhbl9nMiIgdHJvbmcgxJHDsyBz4bq9IGPDsyBj4buZdCAqY29udGluZW50KiBjaOG7qWEgdGjDtG5nIHRpbiB24buBIGPDoWMgY2jDonUgbOG7pWMuIEPhu5l0ICpjaGlzbyogZ+G7k20gZ2nDoSB0cuG7iyBsw6AgR0RQLCB0deG7lWkgdGjhu40sIGTDom4gc+G7kS4gQ+G7mXQgKnRydW5nYmluaCogc+G6vSBjaOG7qWEgZ2nDoSB0cuG7iyB0cnVuZyBiw6xuaCBj4bunYSBjw6FjIGNo4buJIHPhu5EgdMawxqFuZyDhu6luZyB24bubaSBt4buXaSBjaMOidSBs4bulYy4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0V9DQptZWFuX2cyIDwtIGcyICU+JSBncm91cF9ieShjb250aW5lbnQsY2hpc28pICU+JSBzdW1tYXJpc2UodHJ1bmdiaW5oPW1lYW4oZ2lhdHJpKSkNCmRhdGF0YWJsZShtZWFuX2cyKQ0KYGBgDQoNClThu6sgxJHDsywgY2jDum5nIHRhIHRy4buxYyBxdWFuIGjDs2EgYuG7mSBk4buvIGxp4buHdSB24burYSDEkcaw4bujYyB0w61uaCB0cnVuZyBiw6xuaCBi4bqxbmcgY8OhY2ggduG6vSBiaeG7g3UgxJHhu5MgY+G7mXQgY2hvIGJhIGNo4buJIHPhu5EgduG7m2kgY8OhYyBtw6B1IHPhuq9jIGtow6FjIG5oYXUuIEPDoWMgY+G7mXQgdHLDqm4gxJHhu5MgdGjhu4sgc+G6vSB0xrDGoW5nIOG7qW5nIHbhu5tpIGPDoWMgY2jDonUgbOG7pWMgdHJvbmcgZOG7ryBsaeG7h3UuDQoNCkJp4buDdSDEkeG7kyBjw7MgY8OhYyBj4buZdCBtw6B1IMSR4buPIGzDoCBiaeG7g3UgxJHhu5MgduG7gSBHRFAgdHLDqm4gbeG7l2kgY8OhIG5ow6JuIHRydW5nIGLDrG5oIGPhu6dhIDUgY2jDonUgbOG7pWMuIEThu7FhIHbDoG8gYmnhu4N1IMSR4buTIHRhIGPDsyB0aOG7gyB0aOG6pXkgQ2jDonUgxJDhuqFpIMSQxrDGoW5nIGPDsyBHRFAgY2FvIG5o4bqldCB0cm9uZyA1IGNow6J1IGzhu6VjIChraG/huqNuZyAxODYyMSDEkcO0KSwgbmfGsOG7o2MgbOG6oWkgdGjDrCBDaMOidSBQaGkgY8OzIEdEUCB0cnVuZyBiw6xuaCB0aOG6pXAgduG7m2kgY29uIHPhu5Ega2hpw6ptIHThu5FuIGzDoCBraG/huqNuZyAyMTkzIMSRw7QgdHLDqm4gbeG7l2kgY8OhIG5ow6JuLg0KDQpCaeG7g3UgxJHhu5MgY+G7mXQgbcOgdSB4YW5oIGzDoSDEkeG6oWkgZGnhu4duIGNobyB0deG7lWkgdGjhu40gdHJ1bmcgYsOsbmggY+G7p2EgbmfGsOG7nWkgZMOibiDhu58gbeG7l2kgY2jDonUgbOG7pWMsIG5ow6xuIHThu5VuZyB0aOG7gyB0aMOsIGPDoWMgY2jDonUgbOG7pWMgY8OzIHR14buVaSB0aOG7jSB0cnVuZyBiw6xuaCBraMO0bmcgY2jDqm5oIGzhu4djaCBuaGnhu4F1LCBuZ2/huqFpIHRy4burIENow6J1IFBoaSBjw7MgdHXhu5VpIHRo4buNIHRydW5nIGLDrG5oIGzDoCBraG/huqNuZyA0OSB0deG7lWkga2jDoSB0aOG6pXAgc28gduG7m2kgQ2jDonUgw4J1ICg3MiB0deG7lWkpIHbDoCBDaMOidSDEkOG6oWkgxJDGsMahbmcgKDc0IHR14buVaSkuDQoNCkN14buRaSBjw7luZywgYmnhu4N1IMSR4buTIGPDsyBj4buZdCBtw6B1IHhhbmggZMawxqFuZyBjaG8gYmnhur90IHRow7RuZyB0aW4gduG7gSBkw6JuIHPhu5EgdHJ1bmcgYsOsbmggY+G7p2EgY8OhYyBxdeG7kWMgZ2lhIHRyb25nIG3hu5l0IGNow6J1IGzhu6VjIGPhu6UgdGjhu4MuIFRhIG5o4bqtbiB0aOG6pXkgcuG6sW5nIGPDoWMgcXXhu5FjIGdpYSBDaMOidSDDgSBjw7MgZMOibiBz4buRIHRydW5nIGLDrG5oIGNhbyB2xrDhu6N0IHRy4buZaSBzbyB24bubaSBjw6FjIGNow6J1IGzhu6VjIGPDsm4gbOG6oWkoIGtob+G6o25nIDc3IHRyaeG7h3UgbmfGsOG7nWkpLiBUdXkgbmhpw6puIHRow6wgY8OhYyBxdeG7kWMgZ2lhIHRodeG7mWMgQ2jDonUgxJDhuqFpIMSQxrDGoW5nIHbDoCBDaMOidSBQaGkgY8OzIGTDom4gc+G7kSB0aOG6pXAgKGTGsOG7m2kgbeG7qWMgMTAgdHJp4buHdSBuZ8aw4budaSkuDQoNCmBgYHtyfQ0KZ2dwbG90KG1lYW5fZzIsIGFlcyh4ID0gY29udGluZW50LCB5ID0gdHJ1bmdiaW5oLCBmaWxsID0gY2hpc28pKSArDQogIGdlb21fY29sKCkgKw0KICBmYWNldF9ncmlkKGNoaXNvIH4gLiwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgbGFicyh4ID0gIkNoYXVMdWMiLCB5ID0gIkdpYVRyaSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjEsIDAuMSkpKQ0KDQoNCmBgYA0KDQpUcm9uZyBt4buZdCB2w6BpIHTDrG5oIGh14buRbmcgbmh1IGPhuqd1IGPhu6dhIG5nxrDhu51pIHBow6JuIHTDrWNoIGNo4buJIGPhuqduIGNo4buNbiBt4buZdCBz4buRIHF14buRYyBnaWEgY+G7pSB0aOG7gyDEkeG7gyDEkcOhbmggZ2nDoSBz4buxIHBow6F0IHRyaeG7g24gY+G7p2EgbsOzIGLhurFuZyBjw6FjIGNo4buJIHPhu5EgdGjDrCBjaMO6bmcgdGEgY8WpbmcgY8OzIMSR4buDIGvhur90IGjhu6NwIHRow6ptIGjDoG0gYHNlbGVjdCgpYCB2w6AgYGZpbHRlcmAgdGh14buZYyBnw7NpICoqZHBseXIqKiwgc2F1IMSRw7MgdGjhu4MgaGnhu4duIGThu68gbGnhu4d1IOG7nyBk4bqhbmcgxJHhu5MgdGjhu4sgYuG6sW5nIGPDoWMgY8O0bmcgY+G7pSBt4bqhbmggbeG6vSB04burIGfDs2kgKipnZ3Bsb3QyKiouDQoNCkTGsOG7m2kgxJHDonkgY2jDum5nIHTDtGkgY2jhu41uIGPDoWMgY+G7mXQgKmNvdW50cnksIGxpZmVFeHAsIHllYXIqIGLhurFuZyBow6BtIGBzZWxlY3QoKWAgxJHhu4MgZOG7ryBsaeG7h3UgxJHhuqd1IHRyb25nIGjDoG0gcGjDrWEgc2F1IHPhur0gbmjhu48gaMahbiBi4buZIGThu68gbGnhu4d1IGJhbiDEkeG6p3UuIFBow6lwIHRvw6FuIHThu60gKiVcPiUqIGdpw7pwIGThu68gbGnhu4d1IHNhdSBraGkgxJHGsOG7o2MgY2jhu41uIMSRxrBhIHbDoG8gxJHhu5FpIHPhu5EgxJHhuqd1IHRpw6puIGPhu6dhIGjDoG0gYGZpbHRlcmAgxJHhu4MgdGjhu7FjIGhp4buHbiBs4buNYyBt4buZdCBz4buRIHF14buRYyBnaWEgdHJvbmcgY+G7mXQgKmNvdW50cnkqLiBDdeG7kWkgY8O5bmcgc+G7rSBk4bulbmcgaMOgbSBgZ2dwbG90YCDEkeG7gyB24bq9IMSR4buTIHRo4buLIMSRxrDhu51uZyB24buBIHR14buVaSB0aOG7jSB0cnVuZyBiw6xuaCBj4bunYSBiYSBxdeG7kWMgZ2lhIENoaW5hLCBWaWV0bmFtLCBVbml0ZWQgU3RhdGVzLg0KDQpgYGB7cn0NCmcgJT4lIHNlbGVjdChjb3VudHJ5LGxpZmVFeHAseWVhcikgJT4lICBmaWx0ZXIoY291bnRyeSAlaW4lIGMoIkNoaW5hIiwiVmlldG5hbSIsIlVuaXRlZCBTdGF0ZXMiKSklPiUgDQogIGdncGxvdChhZXMoeCA9IHllYXIgLCB5ID0gbGlmZUV4cCwgY29sb3I9Y291bnRyeSkpKw0KICAgICAgZ2VvbV9saW5lKCkrDQogICAgICBsYWJzKHg9ICJOxIJNIiwgeT0gIlRV4buUSSBUSOG7jCIsIHRpdGxlID0gIkJJ4buCVSDEkOG7kiBUVeG7lEkgVEjhu4wgVFJVTkcgQsOMTkgiLCBjb2xvciA9ICJRVeG7kEMgR0lBIikNCg0KYGBgDQoNCsSQ4buDIGJp4bq/dCB0aMOqbSB0aMO0bmcgdGluIHbhu4Egc+G7sSB0aGF5IMSR4buVaSB04buVbmcgZMOibiBz4buRIHRyb25nIGNow6J1IGzhu6VjIHF1YSBjw6FjIG7Eg20sIGNow7puZyB0w7RpIMSRw6MgdMOtbmggdOG7lW5nIGTDom4gc+G7kSDEkcaw4bujYyBuaMOzbSB0aGVvIGJp4bq/biAqY29udGluZW50LCB5ZWFyKi4gS+G6v3QgcXXhuqMgc+G6vSDEkcaw4bujYyBnw6FuIHbDoG8gImczIiDEkeG7gyB0aHXhuq1uIHRp4buHbiB0aOG7sWMgaGnhu4duIGPDoWMgbOG7h25oIHRp4bq/cCB0aGVvLg0KDQpE4buvIGxp4buHdSBzYXUga2hpIHTDrW5oIHThu5VuZyBkw6JuIHPhu5EgxJHDoyB0aHXhu5ljIGThuqFuZyBk4buvIGxp4buHdSBkw6BpLCDEkWnhu4F1IG7DoHkgc+G6vSBraGnhur9uIHZp4buHYyB0aOG7sWMgaGnhu4duIHRy4buxYyBxdWFuIGjDs2EgbeG7mXQgY8OhY2ggcuG6pXQgZOG7hSBkw6BuZy4gRG8gxJHDsyBjaMO6bmcgdGEgY8OzIHRo4buDIHPhu60gZOG7pW5nIG7DsyBiaeG7g3UgZGnhu4VuIMSR4buTIHRo4buLIGPhu5l0IHbhu4Egc+G7sSB0aGF5IMSR4buVaSB04buVbmcgZMOibiBz4buRIGPhu6dhIGPDoWMgY2jDonUgbOG7pWMgbsOgeSBxdWEgY8OhYyBuxINtIG5nYXkgbOG6rXAgdOG7qWMuDQoNCmBgYHtyLG1lc3NhZ2UgPSBGQUxTRX0NCmczIDwtIGcgJT4lIGdyb3VwX2J5KGNvbnRpbmVudCx5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZShzcG9wPXN1bShwb3ApKQ0KaGVhZChnMykNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChnMykrDQogIGdlb21fY29sKA0KICAgIGFlcyh4PSB5ZWFyLCB5ID0gc3BvcCwgZmlsbD0gY29udGluZW50ICksDQogICAgd2lkdGggPSAyDQogICkNCmBgYA0KDQrEkOG7gyBwaMO5IGjhu6NwIGNobyB2aeG7h2MgdGjhu7FjIGhp4buHbiBjw6FjIGLDoW8gY8OhbyB2w6AgdHLDrG5oIGLDoHkgYuG6o25nIGNow7puZyB0YSBjw7MgdGjhu4MgZMO5bmcgaMOgbSBgcGl2b3Rfd2lkZXIoKWAgxJHhu4MgY2h1eeG7g24gKmczKiBzYW5nIGThuqFuZyBy4buZbmcgbmjGsCBiw6puIGTGsOG7m2kgxJHDonkuIELhuqNuZyBuw6B5IHPhur0gZ2nDunAgdGEgcXVhbiBzw6F0IHThu5VuZyBkw6JuIHPhu5EgY+G7p2EgdOG7q25nIGzhu6VjIMSR4buLYSBxdWEgY8OhYyBuxINtIG3hu5l0IGPDoWNoIHRodeG6rW4gdGnhu4duIGjGoW4uDQoNCmBgYHtyfQ0Kd2lkZXJfZzM8LSBwaXZvdF93aWRlcihnMyAsbmFtZXNfZnJvbSA9IGNvbnRpbmVudCwgdmFsdWVzX2Zyb20gPSBzcG9wKQ0KZGF0YXRhYmxlKHdpZGVyX2czKQ0KYGBgDQoNCi0gICBTYXUgxJHDsyB24bq9IMSR4buTIHRo4buLIGPhu5l0IHRo4buDIGhp4buHbiB04buVbmcgZMOibiBz4buRIHRoYXkgxJHhu5VpIHF1YSBjw6FjIG7Eg20gY2hvIGNow6J1IMOCdQ0KDQpgYGB7cn0NCg0KZ2dwbG90KHdpZGVyX2czLCBhZXMoeCA9IHllYXIsIHk9IEV1cm9wZSAsZmlsbD0gIkV1cm9wZSIgKSkrDQogIGdlb21fY29sKCkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9ICJibHVlIikgKw0KICB0aGVtZV9taW5pbWFsKCkrDQogICBsYWJzKHggPSAiTsSDbSIseT0iRMOibiBz4buRIiwgdGl0bGUgPSAgIkJJ4buCVSDEkOG7kiBEw4JOIFPhu5AgQ0jDglUgw4JVICIsIGZpbGwgPSAiQ2jDonUiKQ0KDQpgYGANCg0KLSAgIEThu7FhIHbDoG8gxJHhu5MgdGjhu4ssIHThu5VuZyBkw6JuIHPhu5EgY+G7p2EgQ2jDonUgw4J1IGPDsyBz4buxIGdpYSB0xINuZyBxdWEgY8OhYyBuxINtIHbDoCB04buRYyDEkeG7mSB0xINuZyBuw6B5IGtow6EgxJHhu5NuZyDEkeG7gXUgbmhhdS4gTsSDbSAxOTUyIHThu5VuZyBkw6JuIHPhu5EgY+G7p2EgY2jDonUgbOG7pWMgbsOgeSBjaOG7iSBjw7Mga2hv4bqjbmcgNDAwIHRyaeG7h3UgbmfGsOG7nWkgdsOgIHTEg25nIGThuqduIMSR4bq/biBuxINtIDIwMDcgdGjDrCBjw7Mga2hv4bqjbmcgNjAwIHRyaeG7h3UgbmfGsOG7nWkuDQoNCiAgICBUaeG6v3AgdGhlbywgY2jDum5nIHTDtGkgc+G7rSBk4bulbmcgaMOgbSBgbmVzdCgpYCDEkeG7gyBnb20gY8OhYyBj4buZdCBwb3AsIGdkcFBlcmNhcCB2w6AgbGlmZUV4cCB0aMOgbmggbeG7mXQgY+G7mXQgZOG6oW5nIG5lc3RlZCBsaXN0LiDEkGnhu4F1IG7DoHkgZ2nDunAgZ2nhuqNtIHPhu7EgcGjhu6ljIHThuqFwIGPhu6dhIGThu68gbGnhu4d1IHbDoCB0aOG7sWMgaGnhu4duIGPDoWMgdMOtbmggdG/DoW4gbGluaCBob+G6oXQgaMahbiB0aGVvIG5ow7NtIMSRw6MgxJHGsOG7o2MgZ+G7mXAuDQoNCmBgYHtyfQ0KIyBT4butIGThu6VuZyBow6BtIG5lc3QoKSDEkeG7gyBnb20gY8OhYyBuxINtIHbDoCBjaOG7iSBz4buRIHTGsMahbmcg4bupbmcgdGjDoG5oIGPhu5l0IGThuqFuZyBuZXN0ZWQgbGlzdA0KbmVzdGVkIDwtIGcgJT4lICBuZXN0KC5ieSAgPSBjKGNvdW50cnksIGNvbnRpbmVudCx5ZWFyKSwua2V5ID0gImNoaXNvIikNCmBgYA0KDQpgYGB7cixlY2hvPUZBTFNFfQ0KcHJpbnQobmVzdGVkKQ0KYGBgDQoNCi0gICBOaMawIGvhur90IHF14bqjIGhp4buDbiB0aOG7iyBiw6puIHRyw6puLCBj4buZdCAqY2hpc28qIG7hurFtIOG7nyBk4bqhbmcgZGFuaCBzw6FjaCBs4buTbmcgbmhhdSAoIG5lc3RlZCBsaXN0KSwgbeG7l2kgcGjhuqduIHThu60gc+G6vSBjaOG7qWEgdGjDtG5nIHRpbiB24buBICpwb3AsIGdkcCwgbGlmZUV4cCogY+G7p2EgbeG7l2kgcXXhu5FjIGdpYSB0aGVvIHThu6tuZyBuxINtLg0KDQpIxqFuIHRo4bq/LCBu4bq/dSBjaMO6bmcgdGEgY+G6p24gdGjDtG5nIHRpbiB24buBIGPDoWMgY2jhu4kgc+G7kSBj4bunYSBt4buZdCBxdeG7kWMgZ2lhIGPhu6UgdGjhu4MgY2jhurNuZyBo4bqhbiBuaMawIFVuaXRlZCBTdGF0ZXMgdGEgY8OzIHRo4buDIGTDuW5nIGjDoG0gYGZpbHRlcigpYCDEkeG7gyBs4buNYyBuw7MgcmEgdsOgIGhp4buDbiB0aOG7iyBr4bq/dCBxdeG6oyB24buBIG5o4buvbmcgY2jhu4kgc+G7kSDEkcOjIMSRxrDhu6NjIGdvbS4NCg0KYGBge3J9DQpuZXN0ZWQkY2hpc28gPC0gbGFwcGx5KG5lc3RlZCRjaGlzbywgYXMuZGF0YS5mcmFtZSkNClVTIDwtIG5lc3RlZCAlPiUgIGZpbHRlcihjb3VudHJ5ID09ICJVbml0ZWQgU3RhdGVzIikNCmBgYA0KDQpgYGB7cixlY2hvPUZBTFNFfQ0KcHJpbnQoVVMkY2hpc28pDQpgYGANCg0KLSAgIMSQ4buDIGdp4bqjaSBuw6luIGThu68gbGnhu4d1IOG7nyBk4bqhbmcgbGlzdCBuZXN0ZWQgdGjDrCB0YSBkw7luZyBow6BtIGB1bm5lc3QoKWAsIGvhur90IHF14bqjIHRodSDEkcaw4bujYyBz4bq9IHTGsMahbmcgdOG7sSBk4buvIGxp4buHdSBiYW4gxJHhuqd1IGJhbiDEkeG6p3UuDQoNCmBgYHtyfQ0KIyBT4butIGThu6VuZyBow6BtIHVubmVzdCgpIMSR4buDIGdp4bqjaSBuw6luIGThu68gbGnhu4d1DQp1bm5lc3QgPC0gbmVzdGVkICU+JSB1bm5lc3QoY2hpc28pDQpgYGANCg0KYGBge3IsZWNobz1GQUxTRX0NCnByaW50KHVubmVzdCkNCmBgYA0KDQpgYGB7cn0NCiMgVuG6vSBiaeG7g3UgxJHhu5MgY+G7mXQgY2hvIHThu5VuZyBkw6JuIHPhu5EgKHBvcCkgY+G7p2EgdOG7q25nIHF14buRYyBnaWEgdHJvbmcgbsSDbSAyMDA3DQogdW5uZXN0ICU+JSANCiAgZmlsdGVyKHllYXIgPT0gMjAwNyAmIGNvdW50cnkgJWluJSBjKCJWaWV0bmFtIiwgIkNoaW5hIiwgIktvcmVhLCBSZXAuIiwgIkphcGFuIiwiSW5kb25lc2lhIiwiVGhhaWxhbmQiLCJNYWxheXNpYSIsIkluZGlhIikpICU+JSANCiAgZ2dwbG90KCBhZXMoeCA9IHJlb3JkZXIoY291bnRyeSwgcG9wKSwgeSA9IHBvcCxmaWxsID0gY291bnRyeSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJEw6JuIHPhu5EgY+G7p2EgbeG7mXQgcXXhu5FjIGdpYSBBc2lhIHRyb25nIG7Eg20gMjAwNyIsDQogICAgICAgeCA9ICJRdeG7kWMgZ2lhIiwNCiAgICAgICB5ID0gIlThu5VuZyBkw6JuIHPhu5EiKQ0KDQpgYGANCg0KLSAgIEJp4buDdSDEkeG7kyBjaG8gdGjhuqV5IHLhurFuZyBkw6JuIHPhu5EgY+G7p2EgSW5kaWEgKEtob+G6o25nIDEsMSB04bu3IG5nxrDhu51pKSwgQ2hpbmEgKGtob+G6o25nIDEsMyB04bu3IG5nxrDhu51pKSB0cm9uZyBuxINtIDIwMDcgY2FvIGjGoW4gcuG6pXQgbmhp4buBdSBzbyB24bubaSBt4buZdCBz4buRIHF14buRYyBnaWEgdHJvbmcga2h1IHbhu7FjIENow6J1IMOBLiBRdeG7kWMgZ2lhIGPDsyBkw6JuIHPhu5EgdGjhuqVwIG5o4bqldCB0cm9uZyBjw6FjIHF14buRYyBnaWEgdHLDqm4gbMOgIE1hbGF5c2lhIGNo4buJIGPDsyBraG/huqNuZyAyNSB0cmnhu4d1IG5nxrDhu51pDQoNClZp4buHYyBz4butIGThu6VuZyBuZXN0KCkgdsOgIHVubmVzdCgpIGNobyBi4buZIGThu68gbGnhu4d1IGdhcG1pbmRlciBjaG8gcGjDqXAgdGEgY2h1eeG7g24gxJHhu5VpIGThu68gbGnhu4d1IHThu6sgZOG6oW5nIGLhuqNuZyB0aMO0bmcgdGjGsOG7nW5nIHRow6BuaCBk4bqhbmcgbmVzdGVkIGxpc3QgdsOgIG5nxrDhu6NjIGzhuqFpLiDEkGnhu4F1IG7DoHkgY8OzIHRo4buDIGjhu691IMOtY2ggdHJvbmcgdmnhu4djIHRoYW8gdMOhYyB2w6AgeOG7rSBsw70gZOG7ryBsaeG7h3UsIMSR4bq3YyBiaeG7h3QgbMOgIGtoaSBsw6BtIHZp4buHYyB24bubaSBk4buvIGxp4buHdSBjw7MgY+G6pXUgdHLDumMgcGjhu6ljIHThuqFwIGjGoW4gdsOgIGPDsyBuaGnhu4F1IGPhuqVwIMSR4buZIGzhu5NuZyBuaGF1Lg0KDQojIyBXSE8NCg0KVHJvbmcgcGjhuqduIG7DoHkgY2jDum5nIHTDtGkgc+G6vSBsw6BtIHZp4buHYyB0csOqbiBi4buZIGThu68gbGnhu4d1ICoqd2hvKiosIMSRw6J5IGzDoCBi4buZIGThu68gbGnhu4d1IGNvbiDEkcaw4bujYyB0aHUgdGjhuq1wIHThu6sgYsOhbyBjw6FvIHbhu4EgYuG7h25oIGxhbyB0b8OgbiBj4bqndSBj4bunYSBU4buVIGNo4bupYyBZIHThur8gVGjhur8gZ2nhu5tpLiBOw7MgZ+G7k20gY8OzIDYwIGPhu5l0IHbDoCA3MjQwIHF1YW4gc8OhdCwgdHV5IG5oacOqbiB0aMOsIHThu6sgY+G7mXQgdGjhu6kgNSDEkeG6v24gY+G7mXQgNjAgY8OzIGvDvSB04buxICJuZXdcXyIgxJHGsOG7o2Mga+G6v3QgbuG7kWkgduG7m2kgY8OhYyB0aMO0bmcgdGluIGtow6FjLg0KDQotICAgKipjb3VudHJ5KiogbMOgIHTDqm4gY+G7p2EgY8OhYyBxdeG7kWMgZ2lhIMSRxrDhu6NjIHRodSB0aOG6rXAuDQoNCi0gICAqKmlvczIsIGlvczMqKiBs4bqnbiBsxrDhu6N0IGzDoCBtw6MgcXXhu5FjIGdpYSAyIGvDvSB04buxIHbDoCAzIGvDvSB04buxLg0KDQotICAgKip5ZWFyKiogbMOgIG7Eg20gdGh1IHRo4bqtcCBk4buvIGxp4buHdS4NCg0KLSAgIFBoxrDGoW5nIHBow6FwIGNo4bqpbiDEkW/DoW4gbuG6v3UgbMOgICoqcmVsKiogbmdoxKlhIGzDoCB0w6FpIHBow6F0LCAqKnNuKiogbMOgIGLhu4duaCBuaMOibiBraMO0bmcgY8OzIHZpIGtodeG6qW4gbGFvICwgKipzcCoqIGzDoCBi4buHbmggbmjDom4gY8OzIHZpIGtodeG6qW4gbGFvLCAqKmVwKiogYuG7h25oIG5ow6JuIGxhbyBuZ2/DoGkgcGjhu5VpLg0KDQotICAgS8O9IHThu7EgKipmKiogxJHhuqFpIGRp4buHbiBjaG8gZ2nhu5tpIHTDrW5oIG7hu68gdsOgICoqbSoqIGzDoCBnaeG7m2kgdMOtbmggbmFtDQoNCi0gICBT4buRIHRyb25nIG3hu5dpIGPhu5l0IMSRxrDhu6NjIGTDuW5nIMSR4buDIHRo4buDIGhp4buHbiBuaMOzbSB0deG7lWkgdsOtIGThu6UgMDE0IGzDoCAwLTE0IHR14buVaSwgMTUyNCBsw6AgMTUtMjQgdHXhu5VpLCAyNTM0IGzDoCAyNS0zNCB0deG7lWksIDM1NDQgbMOgIDM1LTQ0IHR14buVaSwgNDU1NCBsw6AgNDUtNTQgdHXhu5VpLCA1NTY0IGzDoCA1NS02NCB0deG7lWkgdsOgIDY1IGzDoCA2NSB0deG7lWkgdHLhu58gbMOqbi4NCg0KVsOtIGThu6UgdMOqbiBj4buZdCB0aOG7qSA1IGzDoCAibmV3X3NwX20wMTQiIMSR4bqhaSBkaeG7h24gY2hvIG5o4buvbmcgYuG7h25oIG5ow6JuIGPDsyBr4bq/dCBxdeG6oyBjaHXhuqluIMSRb8OhbiBjw7Mgdmkga2h14bqpbiBsYW8gbGFvIGTGsMahbmcgdMOtbmgsIGdp4bubaSB0w61uaCBuYW0gdsOgIHRodeG7mWMgbmjDs20gdHXhu5VpIHThu6sgMCDEkeG6v24gMTQgdHXhu5VpLg0KDQpgYGB7cn0NCmRhdGEoIndobyIpDQpgYGANCg0KYGBge3IsZWNobz1GQUxTRX0NCmhlYWQod2hvKQ0KYGBgDQoNClRhIHRo4buxYyBoaeG7h24gY2h1eeG7g24gZOG7ryBsaeG7h3Ugc2FuZyBk4bqhbmcgbG9uZyBi4bqxbmcgaMOgbSBgcGl2b3RfbG9uZ2VyKClgIG5oxrAgxJHDoyDEkcaw4bujYyBnaeG7m2kgdGhp4buHdSDhu58gcGjhuqduIHRyxrDhu5tjLCBjw6FjIGPhu5l0IGNodXnhu4NuIMSR4buVaSDEkcaw4bujYyBjaOG7jW4gYuG6sW5nIGBzdGFydHNfd2l0aGAgYuG6r3QgxJHhuqd1IHbhu5tpIGvDvSB04buxICJuZXciLiBUw6puIGJp4bq/biBjaOG7qWEgY8OhYyBj4buZdCBzYXUga2hpIGNodXnhu4NuIHNhbmcgZOG6oW5nIGxvbmcgbMOgICptZXRob2QqIHbDoCBnacOhIHRy4buLIHTGsMahbmcg4bupbmcgxJHGsOG7o2MgY2jhu6lhIHRyb25nIGPhu5l0ICp2YWx1ZXMqLiBTYXUgxJHDsyBjaMO6bmcgdGEgY8OzIHRo4buDIGTDuW5nIGjDoG0gYGRyb3BfbmEoKWAgxJHhu4MgbG/huqFpIGLhu48gxJFpIGPDoWMgZ2nDoSB0cuG7iyBOQS4NCg0KYGBge3IsbWVzc2FnZT1GQUxTRX0NCiNDaHV54buDbiBk4buvIGxp4buHdSBzYW5nIGThuqFuZyBkw6BpIA0KbG9uZ2VyIDwtIHBpdm90X2xvbmdlcihkYXRhID0gd2hvLGNvbHMgPSBzdGFydHNfd2l0aCgibmV3IiksIG5hbWVzX3RvID0gIm1ldGhvZCIsIHZhbHVlc190byA9ICJ2YWx1ZXMiKQ0KbG9uZ2VyIDwtIGRyb3BfbmEobG9uZ2VyKQ0KYGBgDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0NCmhlYWQobG9uZ2VyKQ0KYGBgDQoNCkNow7puZyB0YSB0aOG6pXkgcuG6sW5nIHRyb25nIGPhu5l0ICoqbWV0aG9kKiogY2jhu6lhIGPDoWMgdGjDtG5nIHRpbiB24buBIGThu68gbGnhu4d1IGto4bqjbyBzw6F0IGLhu4duaCBsYW8gZMaw4bubaSBk4bqhbmcgY2h14buXaSBraMOhIHBo4bupYyB04bqhcCwgY2jDrW5oIHbDrCB0aOG6vyBjaMO6bmcgdGEgY+G6p24ga+G6v3QgaOG7o3AgdGjDqm0gaMOgbSBgZ3N1YmAgxJHhu4MgY8OzIHRo4buDIGxv4bqhaSBi4buPIGPFqW5nIG5oxrAgbMOgIHRow6ptIHbDoG8gbeG7mXQgc+G7kSBjaHXhu5dpIGPhuqduIHRoaeG6v3QuIEjDoG0gYG11dGF0ZSgpYCBz4bq9IGdpw7pwIGPhuq1wIG5o4bqtcCBjw6FjIGdpw6EgdHLhu4sgduG7q2EgxJHGsOG7o2MgdGhheSDEkeG7lWkg4bufIGPhu5l0IG1ldGhvZCB0cm9uZyB0csaw4budbmcgaOG7o3AgbsOgeSBjaMO6bmcgdMO0aSB04bqhbyBj4buZdCBt4bubaSB0csO5bmcgduG7m2kgdMOqbiBj4buZdCBjxakuDQoNCi0gICBMb+G6oWkgYuG7jyBjaHXhu5dpICJuZXdcXyIgdHJvbmcgY+G7mXQgbWV0aG9kIGLhurFuZyBjw6FjIHRoYXkgdGjhur8gbsOzIGLhurFuZyAiIiwgdHV5IG5oacOqbiBt4buZdCBz4buRIGNodeG7l2kgY2jhu4kgeHXhuqV0IGhp4buHbiJuZXciIGNo4bupIGtow7RuZyBwaOG6o2kgbMOgICJuZXdcXyIgY2hvIG7Dqm4gY2jDum5nIHRhIGPhuqduIGtoYWkgYsOhbyBjaG8gaMOgbSBgZ3N1YigpYCBjw6FjIGNodeG7l2kgY+G6p24gdGhheSB0aOG6vyBsw6AgIm5ld1xfPyIuDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZyA9RkFMU0V9DQpsb25nZXIgPC0gbG9uZ2VyICU+JSBtdXRhdGUobWV0aG9kID0gZ3N1YigibmV3Xz8iLCIiLG1ldGhvZCkpDQpgYGANCg0KYGBge3IsbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQ0KaGVhZChsb25nZXIpDQpgYGANCg0KLSAgIFRp4bq/cCB0aGVvLCBjaMO6bmcgdGEgdGjDqm0gdsOgbyBrw70gdOG7sSAiXF8iIHNhdSBrw70gImYiIGhv4bq3YyAibSIgxJHhu4MgY8OzIHRo4buDIHBow6JuIGPDoWNoIGdp4bubaSB0w61uaCB2w6AgbmjDs20gdHXhu5VpDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZyA9RkFMU0V9DQpsb25nZXIgPC0gbG9uZ2VyICU+JSBtdXRhdGUobWV0aG9kID0gZ3N1YigiKGZ8bSkoXFxkKykiLCJcXDFfXFwyIixtZXRob2QpKQ0KYGBgDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0NCmhlYWQobG9uZ2VyKQ0KYGBgDQoNCi0gICBUaOG7sWMgaGnhu4duIHTDoWMgY+G7mXQgKm1ldGhvZCogdGjDoG5oIGJhIGPhu5l0ICptdCwgZ2VuZGVyLCBhZ2UqIGLhurFuZyBow6BtIGBzZXBhcmF0ZSgpYA0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmcgPUZBTFNFfQ0KbG9uZ2VyIDwtIGxvbmdlciAlPiUgc2VwYXJhdGUoY29sID0gbWV0aG9kLGludG8gPSBjKCJtdCIsImdlbmRlciIsImFnZSIpLCBzZXAgPSAiXyIpDQpgYGANCg0KYGBge3IsbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQ0KaGVhZChsb25nZXIpDQpgYGANCg0KLSAgIENodXnhu4NuIMSR4buVaSBjw6FjIGdpw6EgdHLhu4sgdmnhur90IHThuq90IHRyb25nIGPhu5l0ICphZ2UqIHbDoCAqZ2VuZGVyKiB24buBIG5ow7NtIHR14buVaSwgZ2nhu5tpIHTDrW5oIGPhu6UgdGjhu4MuDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZyA9RkFMU0V9DQpsb25nZXIgPC0gbXV0YXRlKGxvbmdlciwgYWdlID0gY2FzZV93aGVuKA0KIGFnZSA9PSAiMDE0IiB+ICIwLTE0IHllYXJzIiwNCiAgICBhZ2UgPT0gIjE1MjQiIH4gIjE1LTI0IHllYXJzIiwNCiAgICBhZ2UgPT0gIjI1MzQiIH4gIjI1LTM0IHllYXJzIiwNCiAgICBhZ2UgPT0gIjM1NDQiIH4gIjM1LTQ0IHllYXJzIiwNCiAgICBhZ2UgPT0gIjQ1NTQiIH4gIjQ1LTU0IHllYXJzIiwNCiAgICBhZ2UgPT0gIjU1NjQiIH4gIjU1LTY0IHllYXJzIiwNCiAgICBhZ2UgPT0gIjY1IiB+ICI2NSB5ZWFycyBvciBvbGRlciIsDQopKQ0KDQpsb25nZXIgPC0gbG9uZ2VyICU+JSAgbXV0YXRlKGdlbmRlciA9IGNhc2Vfd2hlbigNCiAgZ2VuZGVyID09ICJtIiB+ICJtYWxlIiwNCiAgZ2VuZGVyID09ICJmIiB+ICJmZW1hbGUiDQopKQ0KYGBgDQoNClF1YSBuaGnhu4F1IHRoYW8gdMOhYyB44butIGzDvSB2w6AgYmnhur9uIMSR4buVaSB04burIGThu68gbGnhu4d1ICoqd2hvKiogYmFuIMSR4bqndSBjaMO6bmcgdGEgxJHDoyBjw7MgxJHGsOG7o2MgYuG7mSBk4buvIGxp4buHdSBt4bubaSBn4buNbiBnw6BuZyBoxqFuIHLhuqV0IG5oaeG7gXUuIFZp4buHYyBsw6BtIHPhuqFjaCBk4buvIGxp4buHdSBjaMawYSBob8OgbiBjaOG7iW5oIHLhuqV0IHF1YW4gdHLhu41uZyB0cm9uZyBxdcOhIHRyw6xuaCBwaMOibiB0w61jaCwgbsOzIGdpw7pwIGNow7puZyB0YSBk4buFIGTDoG5nIHRy4buxYyBxdWFuIGjDs2EgYuG6sW5nIGPDoWMgaMOsbmgg4bqjbmgsIMSR4buTIHRo4buLIGPFqW5nIG5oxrAgbMOgIHTDrW5oIHRvw6FuIGPDoWMgc+G7kSBsaeG7h3UgdGjhu5FuZyBrw6ouDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0Usd2FybmluZyA9RkFMU0UsZWNobz1GQUxTRX0NCmRhdGF0YWJsZShsb25nZXIpDQpgYGANCg0KYGBge3IsbWVzc2FnZT1GQUxTRX0NCg0KbG9uZ2VyICU+JSBncm91cF9ieShnZW5kZXIseWVhcikgJT4lIHN1bW1hcmlzZShjYXNlPSBzdW0odmFsdWVzKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9eWVhciwgeSA9IGNhc2UgLCBjb2xvcj1nZW5kZXIgKSkrDQogIGdlb21fbGluZSgpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYmx1ZSIsICJyZWQiKSkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBsYWJzKHRpdGxlID0gIlThu5RORyBT4buQIENBIELhu4ZOSCBUSEVPIEdJ4buaSSBUw41OSCIgICkNCmBgYA0KDQotICAgROG7sWEgdsOgbyBiaeG7g3UgxJHhu5MgxJHGsOG7nW5nIOG7nyB0csOqbiwgdOG7lW5nIHRyxrDhu51uZyBo4bujcCBt4bqvYyBi4buHbmggbGFvIHF1YSBjw6FjIG7Eg20g4bufIGhhaSBnaeG7m2kgdMOtbmggY8OzIHh1IGjGsOG7m25nIHTEg25nIGzDqm4gdOG7qyBuaOG7r25nIG7Eg20gMTk5NS4gWHUgaMaw4bubbmcgdMSDbmcgY8OzIHThu7EgdMawxqFuZyDEkeG7k25nIHbhu5tpIG5oYXUgZ2nhu69hIGhhaSBuaMOzbSBnaeG7m2kgdMOtbmggdHV5IG5oacOqbiDhu58gbmFtIGdp4bubaSBz4buxIGdpYSB0xINuZyB04buVbmcgc+G7kSBjYSBt4bqvYyBi4buHbmggbmhp4buBdSBoxqFuIOG7nyBu4buvIGdp4bubaS4gQ+G7pSB0aOG7gywgbsSDbSAyMDEwIHThu5VuZyBjw6FjIHRyxrDhu51uZyBo4bujcCBt4bqvYyBi4buHbmggbGFvIOG7nyBuYW0gZ2nhu5tpIGzDoCAyLDUgdHJp4buHdSBuZ8aw4budaSBjw7JuIOG7nyBu4buvIGdp4bubaSBjaOG7iSBjw7Mga2hv4bqjbmcgMSw1IHRyaeG7h3UgbmfGsOG7nWkuDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0V9DQojIHTDrW5oIHThu5VuZyBz4buRIG5nxrDhu51pIGLhu4duaCB0aGVvIGdp4bubaSB0w61uaCB2w6AgcGjGsMahbmcgcGjDoXAgY2h14bqpbiDEkW/DoW4gKG10KQ0KIGRmMSA8LSBsb25nZXIgJT4lIGdyb3VwX2J5KGdlbmRlcixtdCkgJT4lIHN1bW1hcmlzZShzdW09IHN1bSh2YWx1ZXMpKQ0KYGBgDQoNCmBgYHtyLGVjaG89RkFMU0V9DQpwcmludChkZjEpDQpgYGANCg0KLSAgIFTDrW5oIHThu5VuZyBz4buRIGNhIG3huq9jIGLhu4duaCB0aGVvIGdp4bubaSB0w61uaCB2w6AgcGjGsMahbmcgcGjDoXAgY2h14bqpbiDEkW/DoW4gYuG6sW5nIGjDoG0gYGdyb3VwX2J5KClgIHbDoCBgc3VtbWFyaXNlKClgLCBzYXUgxJHDsyB24bq9IMSR4buTIHRo4buLIGPhu5l0IMSRw7RpIMSR4buDIMSRw6FuaCBnacOhIGvhur90IHF14bqjLg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFfQ0KIyDEkOG7kyB0aOG7iyANCiAgZ2dwbG90KCBkZjEsYWVzKHggPSBtdCwgeSA9IHN1bSwgZmlsbCA9IGdlbmRlcikpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGxhYnModGl0bGUgPSAiVOG7lW5nIHPhu5EgY2EgdGhlbyBwaMawxqFuZyBwaMOhcCB2w6AgZ2nhu5tpIHTDrW5oIiwNCiAgICAgICB4ID0gIlBoxrDGoW5nIHBow6FwIiwNCiAgICAgICB5ID0gIlPhu5EgbMaw4bujbmciLA0KICAgICAgIGZpbGwgPSAiR2nhu5tpIHTDrW5oIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQotICAgxJDhu5MgdGjhu4sgYsOqbiB0csOqbiBjaG8gY2jDum5nIHRhIHRo4bqleSBz4buRIG5nxrDhu51pIMSRxrDhu6NjIGNodeG6qW4gxJFvw6FuIGzDoCBzcCAoY8OzIHZpIGtodeG6qW4gbGFvKSBjw7Mgc+G7kSBsxrDhu6NuZyBjYW8gbmjhuqV0IHRyb25nIDQgbmjDs20gY+G7pSB0aOG7gyBjw7MgMjA1NDI0NzIgbmFtIHbDoCAxMTI5MjI3OSBu4buvIHRyb25nIHRyxrDhu51uZyBo4bujcCBuw6B5LiBDaHXhuqluIMSRb8OhbiBsw6AgYuG7h25oIGxhbyBuZ2/DoGkgcGjhu5VpIChlcCkgY8OzIHPhu5EgbMaw4bujbmcgdGjhuqVwIG5o4bqldCwgdHJvbmcgxJHDsyDhu58gbuG7ryBnaeG7m2kgY8OzIDk0MTA0OSBuZ8aw4budaSB2w6AgbmFtIGdp4bubaSBjw7MgMTA0MzI2NSBuZ8aw4budaSB0aHXhu5ljIGNodeG6qW4gxJFvw6FuIG7DoHkuDQoNCmBgYHtyLG1lc3NhZ2U9RkFMU0V9DQogICAgICAgIA0KbG9uZ2VyICU+JSBncm91cF9ieShhZ2UpJT4lICBzdW1tYXJpc2UodG90YWw9c3VtKHZhbHVlcykpICU+JSANCiAgbXV0YXRlKHAgPSB0b3RhbC9zdW0odG90YWwpKSAlPiUNCiAgZ2dwbG90KGFlcyh4PSIiLCB5PSBwLCBmaWxsID0gYWdlKSkrDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLHdpZHRoID0gMSkrDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIpICsNCiAgY29vcmRfcG9sYXIoInkiLHN0YXJ0ID0gMCkrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBzY2FsZXM6OnBlcmNlbnQocCkpLHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLCBzaXplID0gMykgKw0KICB0aGVtZV92b2lkKCkgKw0KICBsYWJzKHRpdGxlPSAiVMOsbmggdHLhuqFuZyBi4buHbmggbGFvIOG7nyBjw6FjIG5ow7NtIHR14buVaSIpDQoNCmBgYA0KDQotICAgTmjDs20gdOG7qyAyNSDEkeG6v24gMzQgdHXhu5VpIGPDsyB04bu3IGzhu4cgbeG6r2MgYuG7h25oIGzhu5tuIG5o4bqldCB0cm9uZyB04bqldCBj4bqjIG5ow7NtIHR14buVaSAoa2hv4bqjbmcgMjIuMiUpLCDhu58gbmjDs20gdOG7qyA0NSDEkeG6v24gNTQgdHXhu5VpIGPFqW5nIMSR4bqhdCB04bu3IGzhu4cga2jDoSBjYW8gbMOgIDIwLjIlLiBOZ8aw4bujYyBs4bqhaSB0aMOsIG5ow7NtIDAtMTQgdHXhu5VpIGNoaeG6v20gdOG7tyBs4buHIG3huq9jIGLhu4duaCBsYW8gdGjhuqVwIG5o4bqldCBjaOG7iSBraG/huqNuZyAzLjklLiBOaMOsbiBjaHVuZyB04bu3IGzhu4cgbeG6r2MgYuG7h25oIGNhbyBz4bq9IHRodeG7mWMgY8OhYyBuaMOzbSB0deG7lWkgdHJ1bmcgbmnDqm4uDQoNCsSQ4buDIGdvbSBjw6FjIGJp4bq/biB0aMOgbmggbeG7mXQgZGFuaCBzw6FjaCBs4buTbmcgbmhhdSB0aGVvIG3hu5dpIHF14buRYyBnaWEgdGEgw6FwIGThu6VuZyBow6BtIGBuZXN0KClgLCBk4buvIGxp4buHdSBt4bubaSBuw6B5IGfhu41uIGfDoG5nIGjGoW4gcuG6pXQgbmhp4buBdSBzbyB24bubaSBiYW4gxJHhuqd1IG7hur91IGNow7puZyB0YSBj4bqnbiBraGFpIHRow6FjIHRow7RuZyB0aW4gY+G7p2EgcXXhu5FjIGdpYSB0aMOsIGNo4buJIGPhuqduIG3hu58gZGFuaCBzw6FjaCBk4buvIGxp4buHdSBj4bunYSBuw7MgbcOgIGtow7RuZyBj4bqnbiBwaOG6o2kgbmjDrG4gdG/DoG4gYuG7mSB0aMO0bmcgdGluIG5oxrAgYmFuIMSR4bqndS4NCg0KYGBge3J9DQpuZXN0ZWRfZGF0YSA8LSBuZXN0KGxvbmdlciwgLmJ5ID0gY291bnRyeSwgLmtleSA9ICJ5ZWFyIikNCmBgYA0KDQpgYGB7cixlY2hvPUZBTFNFfQ0KcHJpbnQobmVzdGVkX2RhdGEpDQpgYGANCg0KSMOgbSBgZmlsdGVyKClgIHRyb25nIHRyxrDhu51uZyBo4bujcCBiw6puIGTGsOG7m2kgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgbOG7jWMgVmnhu4d0IE5hbSByYSBraOG7j2kgYuG7mSBk4buvIGxp4buHdSB0csOqbiB2w6Agc2F1IMSRw7MgdGEgaGnhu4NuIHRo4buLIHRow7RuZyB0aW4gduG7gSBjw6FjIHRyxrDhu51uZyBo4bujcCBt4bqvYyBi4buHbmggbGFvIGPhu6dhIG7DsyBuaMawIGLDqm4gZMaw4bubaSDEkcOieS4NCg0KYGBge3J9DQpuZXN0ZWRfZGF0YSR5ZWFyIDwtIGxhcHBseShuZXN0ZWRfZGF0YSR5ZWFyLCBhcy5kYXRhLmZyYW1lKQ0KVk4gPC0gIG5lc3RlZF9kYXRhICU+JSBmaWx0ZXIoY291bnRyeT09ICJWaWV0IE5hbSIpDQpgYGANCg0KYGBge3IsZWNobz1GQUxTRX0NCnByaW50KFZOKQ0KcHJpbnQoVk4keWVhcikNCmBgYA0KDQpHaeG6o2kgbsOpbiBk4buvIGxp4buHdSDhu58gZOG6oW5nIG5lc3RlZCB0YSBj4bqnbiBz4butIGThu6VuZyBow6BtIGB1bm5lc3QoKWAgZOG7ryBsaeG7h3UgxJHGsOG7o2MgdHLhuqMgduG7gSBz4bq9IGJhbyBn4buTbSBjw6FjIHRow7RuZyB0aW4gbmjGsCBk4buvIGxp4buHdSBiYW4gxJHhuqd1Lg0KDQpgYGB7cn0NCiMgU+G7rSBk4bulbmcgaMOgbSB1bm5lc3QoKQ0KdW5uZXN0X2RhdGEgPC0gdW5uZXN0KG5lc3RlZF9kYXRhLGNvbHMgPSB5ZWFyKQ0KYGBgDQoNCmBgYHtyLGVjaG89RkFMU0V9DQpwcmludCh1bm5lc3RfZGF0YSkNCmBgYA0KDQojIENIxq/GoE5HIDQ6IEvhur5UIExV4bqsTg0KDQojIyBL4bq/dCBsdeG6rW4NCg0KQsOgaSB0aeG7g3UgbHXhuq1uIGPhu6dhIGNow7puZyB0w7RpIMSRw6MgdHLDrG5oIGLDoHkgY8OhYyBjaOG7qWMgbsSDbmcgcXVhbiB0cuG7jW5nIGPhu6dhIGfDs2kgVGlkeXIgdHJvbmcgbmfDtG4gbmfhu68gbOG6rXAgdHLDrG5oIFIsIG7DsyBjaMOtbmggbMOgIGPDtG5nIGPhu6UgbeG6oW5oIG3hur0gZ2nDunAgbeG7jWkgbmfGsOG7nWkgeOG7rSBsw70gbmjhu69uZyBi4buZIGThu68gbGnhu4d1IGNoxrBhIMSRxrDhu6NjIGNodeG6qW4gaMOzYSB24buBIGThuqFuZyBk4buvIGxp4buHdSBz4bqhY2ggdsOgIHNhdSDEkcOzIMSRxrBhIHbDoG8gcGjDom4gdMOtY2ggdsOgIHRy4buxYyBxdWFuIGjDs2EgZOG7ryBsaeG7h3UuIELDqm4gY+G6oW5oIHZp4buHYyBnaeG7m2kgdGhp4buHdSB24buBIGfDs2kgbsOgeSBjaMO6bmcgdMO0aSBjxaluZyDEkcOjIHRo4buxYyBoaeG7h24gY8OhYyB0aGFvIHTDoWMgaMaw4bubbmcgZOG6q24gY2hpIHRp4bq/dCBk4buxYSB0csOqbiBk4buvIGxp4buHdSBt4bqrdSDEkeG7gyBsw6BtIG7hu5VpIGLhuq10IHPhu7EgaGnhu4d1IHF14bqjIGPhu6dhIGfDs2kgVGlkeXIgdHJvbmcgdmnhu4djIGzDoG0gc+G6oWNoIGThu68gbGnhu4d1LiBOaOG7r25nIGThu68gbGnhu4d1IHRow7QgYmFuIMSR4bqndSB0aMaw4budbmcgY8OzIGPhuqV1IHRyw7pjIHBo4bupYyB04bqhcCwgbmhp4buBdSBiaeG6v24ga+G6v3QgaOG7o3AgduG7m2kgbmhhdSBi4bqxbmcgY8OhYyBrw70gdOG7sSBwaMOibiBjw6FjaCBob+G6t2MgdGjhuq1tIGNow60gbOG7k25nIGdow6lwIHbhu5tpIG5oYXUgdGjDoG5oIGPDoWMgZGFuaCBzw6FjaC4gVsOsIHbhuq15LCBjaMO6bmcgdMO0aSDEkcOjIHRo4buxYyBoaeG7h24gY8OhYyBow6BtIHjhu60gbMO9IGThu68gbGnhu4d1IGLhu4sgdGhp4bq/dSwgYmnhur9uIMSR4buVaSBj4bqldSB0csO6YywgdMOhY2ggZ2jDqXAgdsOgIGzhu5NuZyBnaMOpcCBkYW5oIHPDoWNoIHNhbyBjaG8gcGjDuSBo4bujcCB04burbmcgZOG7ryBsaeG7h3UuDQoNCkfDs2kgVGlkeXIgY8OzIHRo4buDIGvhur90IGjhu6NwIHbhu5tpIG3hu5l0IHPhu5EgZ8OzaSBraMOhYyBjaOG6s25nIGjhuqFuIG5oxrAgbMOgIGRwbHlyLCBnZ3Bsb3QyLCBzdHJpbmdyIMSR4buDIHThu5FpIMawdSB2w6AgdGnhur90IGtp4buHbSBuaGnhu4F1IHRo4budaSBnaWFuLCB0dXkgbmhpw6puIGNow7puZyB0YSBjxaluZyBj4bqnbiBuZ2hpw6puIGPhu6l1IHLhuqV0IG5oaeG7gXUgxJHhu4MgY8OzIHRo4buDIGvhur90IGjhu6NwIHbhu5tpIGPDoWMgaMOgbSB0cm9uZyBnw7NpIFRpZHlyLiBOaMOsbiBjaHVuZyBuaOG7r25nIGjDoG0gdHJvbmcgZ8OzaSB0aWR5ciBjw7MgdMOtbmgg4bupbmcgZOG7pW5nIHLhuqV0IGNhbyB0cm9uZyBuaGnhu4F1IGzEqW5oIHbhu7FjIG5oxrBuZyBz4butIGThu6VuZyB0aMOsIGtow6EgxJHGoW4gZ2nhuqNuIGNo4buJIGPhuqduIGtoYWkgYsOhbyBt4buZdCB2w6BpIMSR4buRaSBz4buRLiBDaOG6s25nIGjhuqFuIGjDoG0gYHBpdm90X2xvbmdlcmAgYmnhur9uIMSR4buVaSBk4buvIGxp4buHdSBy4buZbmcgc2FuZyBk4bqhbmcgZMOgaSBnacO6cCB0YSB0cuG7sWMgaMOzYSBk4buvIGxp4buHdSB04buRdCBoxqFuIHRyxrDhu5tjLCBow6BtIGBzZXBhcmF0ZWAgY8OzIGNo4bupYyBuxINuZyB0w6FjaCB0aMOgbmggY8OhYyBj4buZdCBk4buxYSB2w6BvIGPDoWMga8O9IHThu7EgcGjDom4gY8OhY2ggbmfGsOG7o2MgbOG6oWkgdGjDrCBgdW5pdGVgIGdpw7pwIGvhur90IGjhu6NwIGPDoWMgY+G7mXQgbOG6oWkgduG7m2kgbmhhdSB2w6AgbeG7mXQgc+G7kSBow6BtIHjhu60gbMO9IGThu68gbGnhu4d1IGtow6FjLg0KDQpOZ2/DoGkgcmEsIG5nw7RuIG5n4buvIFIgc+G6vSBwaMOhdCB0cmnhu4NuIGfDs2kgbsOgeSB0aGVvIHRo4budaSBnaWFuIGNow61uaCB2w6wgduG6rXkgbmjhu69uZyBuaMaw4bujYyDEkWnhu4NtIGPhu6dhIG7DsyBz4bq9IMSRxrDhu6NjIGPhuqNpIHRoaeG7h24gYuG7n2kgY2jDrW5oIG5o4buvbmcgbmfGsOG7nWkgZMO5bmcsIG3hu5l0IHPhu5EgY2jhu6ljIG7Eg25nIG3hu5tpIGPDsyB0aOG7gyDEkcaw4bujYyB0aMOqbSB2w6BvIGtoaeG6v24gY2hvIFRpZHlyIHRy4bufIG7Dqm4gbGluaCBob+G6oXQgdsOgIMSRYSBk4bqhbmcgaMahbi4gVHJvbmcgcXXDoSB0csOsbmggdGjhu7FjIGjDoG5oIGPDoWMgaMOgbSBu4bq/dSBn4bq3cCBwaOG6o2kgbmjhu69uZyB24bqlbiDEkeG7gSBraMOzIGtoxINuIHRow6wgY+G7mW5nIMSR4buTbmcgUiBjw7MgY8OhYyBiw6BpIGjGsOG7m25nIGThuqtuIGdpw7pwIHRhIGdp4bqjaSBxdXnhur90IG7Dsy4NCg0KVMOzbSBs4bqhaSwgZ8OzaSB0aWR5ciBsw6AgY8O0bmcgY+G7pSBnacO6cCBjaG8gY2jDum5nIHRhIGJp4bq/biDEkeG7lWkgY+G6pXUgdHLDumMgZOG7ryBsaeG7h3UsIHTDoWNoLCBnaMOpcCB2w6AgeOG7rSBsw70gZOG7ryBsaeG7h3UgYuG7iyB0aGnhur91IG3hu5l0IGPDoWNoIMSRxqFuIGdp4bqjbiBuaMawbmcgbsOzIGzhuqFpIGdpw7pwIGdpYWkgxJFv4bqhbiB44butIGzDvSBk4buvIGxp4buHdSDEkeG6p3UgdsOgbyBj4bunYSBt4buNaSBuZ8aw4budaSBz4bq9IHRp4bq/dCBraeG7h20gbmhp4buBdSB0aOG7nWkgZ2lhbiB2w6AgxJHhuqF0IGvhur90IHF14bqjIGNhbyBoxqFuLiBIxqFuIHRo4bq/LCBnw7NpIG7DoHkgY8OybiBr4bq/dCBo4bujcCB24bubaSBo4buHIHNpbmggdGjDoWkgVGlkeXZlcnNlIHbDoCBuaGnhu4F1IHBhY2thZ2VzIGtow6FjIG5o4bqxbSDEkcOhcCDhu6luZyBjw6FjIG5odSBj4bqndSBraMOhYyBuaGF1IGPhu6dhIG5nxrDhu51pIHBow6JuIHTDrWNoLiBC4bufaSB2w6wgbmjhu69uZyBjaOG7qWMgbsSDbmcgbuG7lWkgYuG6rXQgxJHDsyBtw6AgZ8OzaSB0aWR5ciDEkcaw4bujYyDDoXAgZOG7pW5nIHRyb25nIG5oaeG7gXUgbMSpbmggduG7sWMgdMOgaSBjaMOtbmgsIGLhuqNvIGhp4buDbSwgeSBo4buNYy4NCg0KIyMgSOG6oW4gY2jhur8gdsOgIHBoxrDGoW5nIGjGsOG7m25nIHRp4bq/cCB0aGVvIGPhu6dhIMSR4buBIHTDoGkNCg0KVHJvbmcgdGjhu51pIGdpYW4gbmdoacOqbiBj4bupdSDEkeG7gSB0w6BpIHbhu4EgZ8OzaSB0aWR5ciBjaMO6bmcgdMO0aSDEkcOjIGfhurdwIG3hu5l0IHPhu5Ega2jDsyBraMSDbiB0cm9uZyB2aeG7h2MgdMOsbSBraeG6v20gbmd14buTbiB0w6BpIGxp4buHdSB0aGFtIGto4bqjbyB2w6wgY+G6p24gcGjhuqNpIGPDsyBt4buZdCBsxrDhu6NuZyBs4bubbiBraeG6v24gdGjhu6ljIGPFqW5nIG5oxrAgaGnhu4N1IHLDtSBt4buZdCBz4buRIGtow6FpIG5p4buHbSDEkeG7gyBob8OgbiB0aMOgbmggbsOzLiBN4buZdCBz4buRIGjDoG0gY+G6p24gcGjhuqNpIHhlbSBxdWEgbmhp4buBdSB0w6BpIGxp4buHdSBoxrDhu5tuZyBk4bqrbiwgdsOtIGThu6UgY+G7pSB0aOG7gyB0aMOsIGNow7puZyB0YSBt4bubaSBjw7MgdGjhu4MgaGnhu4N1IG7DsyB2w6AgdHLDrG5oIGLDoHkgY2jhu6ljIG7Eg25nIGPhu6dhIGjDoG0gxJHDsy4gSMahbiB0aOG6vywgY2jDum5nIHTDtGkgY8WpbmcgbeG6pXQgbmhp4buBdSB0aOG7nWkgZ2lhbiDEkeG7gyBjaOG7jW4gcmEgbmjhu69uZyBk4buvIGxp4buHdSB0aMOtY2ggaOG7o3AgY2hvIHZp4buHYyDDoXAgZOG7pW5nIGPDoWMgaMOgbSBtaW5oIGjhu41hLiBWaeG7h2MgaGnhu4N1IGPhuqV1IHRyw7pjIGPhu6dhIG3hu5l0IGLhu5kgZOG7ryBsaeG7h3UgcGjhu6ljIHThuqFwIHPhur0gZ2nDunAgdGEgZMO5bmcgbmjhu69uZyBow6BtIHBow7kgaOG7o3AgxJHhu4MgYmnhur9uIMSR4buVaSBuw7MgduG7gSBk4buvIGxp4buHdSBz4bqhY2guDQoNCkNow7puZyB0w7RpIG114buRbiDEkeG7gSB4deG6pXQgbeG7mXQgc+G7kSBwaMawxqFuZyBoxrDhu5tuZyBjaG8gbmjhu69uZyBuZ2hpw6puIGPhu6l1IHRp4bq/cCB0aGVvIOG7nyDEkeG7gSB0w6BpIG7DoHkuIEfDs2kgbsOgeSBjw7MgdGjhu4Mgc+G7rSBk4bulbmcgxJHhu4MgcGjDom4gdMOtY2ggbmjhu69uZyBi4buZIGThu68gbGnhu4d1IG5oaeG7gXUgYmnhur9uIHbDoCBuaGnhu4F1IGTDsm5nIGThu68gbGnhu4d1IGjGoW4uIENow7puZyB0YSBuw6puIGvhur90IGjhu6NwIHbhu5tpIGPDoWMgZ8OzaSBjw7Mga2jhuqMgbsSDbmcgdHLhu7FjIHF1YW4gaMOzYSBk4buvIGxp4buHdSB24burYSB44butIGzDrSBi4bqxbmcgY8OhYyDEkeG7kyB0aOG7iyBoYXkgdGjhuq1tIGNow60gbMOgIMSR4buTIHRo4buLIDNEIMSR4buDIHRyw6xuaCBiw6B5IGvhur90IHF14bqjLiBOZ2/DoGkgcmEgbmjhu69uZyBow6BtIHjhu60gbMO9IGNodeG7l2kgdHJvbmcgZ8OzaSBzdHJpbmdyIHPhur0gZ2nDunAgbmfGsOG7nWkgc+G7rSBk4bulbmcgcGjDoXQgaHV5IMSRxrDhu6NjIGPDoWMgY2jhu6ljIG7Eg25nIGPhu6dhIGfDs2kgdGlkeXIga2hpIHPhu60gZOG7pW5nIMSR4buTbmcgdGjhu51pIGNow7puZyB24bubaSBuaGF1DQo=