1 Package dplyr

2 Văn phạm dplyr

Một số “động từ” chính của package dplyr bao gồm

2.0.1 Một số đặc điểm chức năng chung của dplyr()

  1. Đối số đầu tiên là data frame.
  2. Những đối số tiếp theo mô tả hành động thực hiện với data frame, và ta có thể truy xuất cột bằng tên mà không cần sử dụng toán tử $.
  3. Kết quả trả về là một data frame mới.
  4. Data frame phải được định dạng và ghi chú phù hợp. Cụ thể, bộ dữ liệu phải gọn gàng. Tức là một quan sát ở mỗi hàng, và mỗi cột nên là một đặc điểm của quan sát đó.

3 select()

Ở phần này, chúng ta sẽ sử dụng bộ dữ liệu về ô nhiễm không khí và nhiệt độ tại thành phố Chicago, Mỹ.

Ta tải package dplyr().

Hàm select() được sử dụng để lựa chọn cột trong data frame. Giả sử chúng ta chỉ muốn làm việc với 3 cột đầu.

Lưu ý rằng dấu : không thể sử dụng cho tên hoặc character. Tuy nhiên, trong hàm select() ta có thể dùng nó để xác định một chuỗi tên biến số.

Ta cũng có thể dấu - trong select() để loại biến số ta không muốn.

Trong R, nếu ta muốn sử dụng

Ta cũng có thể sử dụng cú pháp để xác định nhiều biến số có cùng quy tắc đặt tên. Ví dụ, nếu ta muốn giữ những biến số có tên kết thúc với 2

Hoặc nếu ta muốn giữ các biến số bắt đầu với “d”, ta có thể

4 filter()

Hàm filter() được sử dụng để trích xuất tập hợp con các hàng từ một data frame. Hàm này tương tự như subset() trong R nhưng nhanh hơn.

Giả sử ta muốn trích xuất các hàng của data frame chicago ở mức PM2.5 > 30, ta có thể

'data.frame':   194 obs. of  8 variables:
 $ city      : chr  "chic" "chic" "chic" "chic" ...
 $ tmpd      : num  23 28 55 59 57 57 75 61 73 78 ...
 $ dptp      : num  21.9 25.8 51.3 53.7 52 56 65.8 59 60.3 67.1 ...
 $ date      : Date, format: "1998-01-17" ...
 $ pm25tmean2: num  38.1 34 39.4 35.4 33.3 ...
 $ pm10tmean2: num  32.5 38.7 34 28.5 35 ...
 $ o3tmean2  : num  3.18 1.75 10.79 14.3 20.66 ...
 $ no2tmean2 : num  25.3 29.4 25.3 31.4 26.8 ...

Ta thấy rằng chỉ có 194 hàng trong data frame và phân bố của pm25.

Ta có thể truyền điều kiện vào filter().

5 arrange()

Hàm arrange() được sử dụng để sắp xếp lại hàng của data frame theo các biến số (cột). Theo thứ tự, hàng được xếp theo cột đầu tiên rồi lần lượt theo các cột sau.

Các cột có thể được sắp xếp theo thứ tự giảm dần với hàm desc().

6 rename()

7 mutate()

Hàm mutate() giúp tạo hoặc thay đổi biến số trong data frame.

Ví dụ, để biết liệu mức ô nhiễm cao hơn hay thấp hơn mức trung bình, ta trừ số liệu của các quan sát cho số trung bình.

Ta tạo một biến số mới là pm25new.

8 transmute()

transmute() hoạt động như mutate(), nhưng bỏ đi những biến số không được thay đổi.

9 group_by()

Hàm group_by() được sử dụng để tính số thống kê theo phân tầng. Ví dụ, ta có thể muốn biết số PM2.5 trung bình hàng năm. Do đó, dữ liệu được phân tầng theo năm, và đây là thông tin ta lấy được từ biến date. Kết hợp với group_by(), ta sử dụng hàm summarise().

Các thức hoạt động là ta phân tách data frame thành những phần riêng biệt theo một hay nhiều biến số (group_by()), và áp dụng hàm summarise() vào những phần riêng biệt này.

`summarise()` ungrouping output (override with `.groups` argument)

summarise() trả về data frame với year là cột đầu tiên, và sau đó là số trung bình hàng năm của pm25, o3, và no2.

10 %>%

Toán tử %>% rất hữu ích trong việc xâu chuỗi các hàm của dplyr.

Như ở ví dụ trên, chúng ta muốn tính trung bình o3, no2pm25 theo năm, ta phải:

  1. Tạo biến year
  2. Phân tách data frame theo year
  3. Tính toán trung bình o3, no2, và pm25 theo year.

Với %>%, ta có thể thực hiện trong một câu lệnh.

Lưu ý rằng, khi gọi hàm mutate() ta có truyền data frame chicago, nhưng ở những lần gọi hàm sau, ta không cần phải truyền data frame vào đối số đầu tiên nữa. Khi sử dụng %>%, đầu ra ở lần gọi trước đã được ngầm đưa vào đối số đầu tiên ở lần gọi tiếp theo.

LS0tDQp0aXRsZTogJ0LDoGkgNjogTMOgbSBz4bqhY2ggZOG7ryBsaeG7h3UnDQphdXRob3I6ICJLaW0gVsSDbiBUaMOgbmgsIE0uRC4iDQpkYXRlOiAiMTcvMTAvMjAyMCINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0aGVtZTogY2VydWxlYW4NCiAgICB0b2M6IHllcw0KLS0tDQoNClBhY2thZ2UgYGRwbHlyYA0KPT09PT09PT09PT09PT0NCg0KLSBUw6FjIGdp4bqjOiBIYWRsZXkgV2lja2hhbSBj4bunYSBSU3R1ZGlvLiAgDQotIFBoacOqbiBi4bqjbiBj4bqjaSB0aeG6v24gY+G7p2EgYHBseXJgLiAgDQotIEtow7RuZyBjdW5nIGPhuqVwIHRow6ptIGNo4bupYyBuxINuZyBjaG8gUiwgbmjGsG5nIGzDoG0gxJHGoW4gZ2nhuqNuIG5o4buvbmcgY2jhu6ljIG7Eg25nIGhp4buHbiBjw7MuICANCi0gQ3VuZyBj4bqlcCAidsSDbiBwaOG6oW0iIMSR4buDIHRoYW8gdMOhYyB24bubaSBkYXRhIGZyYW1lLiAgDQotIEThu4UgaGnhu4N1LiAgDQotIENo4bqheSBuaGFuaCBoxqFuLCBkbyDEkcaw4bujYyBjb2RlIHF1YSBDKysuIA0KDQpWxINuIHBo4bqhbSBgZHBseXJgDQo9PT09PT09PT09PT09PT0NCg0KTeG7mXQgc+G7kSAixJHhu5luZyB04burIiBjaMOtbmggY+G7p2EgcGFja2FnZSBgZHBseXJgIGJhbyBn4buTbQ0KDQotIGBzZWxlY3RgOiB0cuG6oyB24buBIG3hu5l0IHThuq1wIGjhu6NwIGNvbiBjw6FjIGPhu5l0IHRyb25nIGRhdGEgZnJhbWUuICANCi0gYGZpbHRlcigpYDogdHLDrWNoIHh14bqldCBt4buZdCB04bqtcCBo4bujcCBjb24gY8OhYyBow6BuZyB0cm9uZyBkYXRhIGZyYW1lIGThu7FhIHRyw6puIMSRaeG7gXUga2nhu4duIGxvZ2ljLiAgDQotIGBhcnJhbmdlKClgOiBz4bqvcCB44bq/cCBs4bqhaSBow6BuZyB0cm9uZyBkYXRhIGZyYW1lLiAgDQotIGByZW5hbWUoKWA6IMSR4buVaSB0w6puIGJp4bq/biBz4buRIHRyb25nIGRhdGEgZnJhbWUuICANCi0gYG11dGF0ZSgpYDogdGjDqm0gYmnhur9uL2Phu5l0IGhv4bq3YyB0aGF5IMSR4buVaSBiaeG6v24gaGnhu4duIGPDsy4gIA0KLSBgc3VtbWFyaXNlKCkvc3VtbWFyaXplKClgOiB0w61uaCB0b8OhbiBz4buRIHRo4buRbmcga8OqIMSR4bqhaSBkaeG7h24gY2hvIG5o4buvbmcgYmnhur9uIHPhu5Ega2jDoWMgbmhhdSB0cm9uZyBkYXRhIGZyYW1lLiBDw7MgdGjhu4MgbMOgbSB0aGVvIGThuqFuZyBwaMOibiB04bqnbmcuICANCi0gYCU+JWA6IFRvw6FuIHThu60gInBpcGUiIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIGvhur90IG7hu5FpIG5oaeG7gXUgxJHhu5luZyB04burIHRow6BuaCBt4buZdCDEkcaw4budbmcg4buRbmcgKHBpcGVsaW5lKS4gIA0KDQojIyMgTeG7mXQgc+G7kSDEkeG6t2MgxJFp4buDbSBjaOG7qWMgbsSDbmcgY2h1bmcgY+G7p2EgYGRwbHlyKClgDQoNCjEuIMSQ4buRaSBz4buRIMSR4bqndSB0acOqbiBsw6AgZGF0YSBmcmFtZS4gIA0KMi4gTmjhu69uZyDEkeG7kWkgc+G7kSB0aeG6v3AgdGhlbyBtw7QgdOG6oyBow6BuaCDEkeG7mW5nIHRo4buxYyBoaeG7h24gduG7m2kgZGF0YSBmcmFtZSwgdsOgIHRhIGPDsyB0aOG7gyB0cnV5IHh14bqldCBj4buZdCBi4bqxbmcgdMOqbiBtw6Aga2jDtG5nIGPhuqduIHPhu60gZOG7pW5nIHRvw6FuIHThu60gYCRgLiAgDQozLiBL4bq/dCBxdeG6oyB0cuG6oyB24buBIGzDoCBt4buZdCBkYXRhIGZyYW1lIG3hu5tpLiAgDQo0LiBEYXRhIGZyYW1lIHBo4bqjaSDEkcaw4bujYyDEkeG7i25oIGThuqFuZyB2w6AgZ2hpIGNow7ogcGjDuSBo4bujcC4gQ+G7pSB0aOG7gywgYuG7mSBk4buvIGxp4buHdSBwaOG6o2kgZ+G7jW4gZ8OgbmcuIFThu6ljIGzDoCBt4buZdCBxdWFuIHPDoXQg4bufIG3hu5dpIGjDoG5nLCB2w6AgbeG7l2kgY+G7mXQgbsOqbiBsw6AgbeG7mXQgxJHhurdjIMSRaeG7g20gY+G7p2EgcXVhbiBzw6F0IMSRw7MuIA0KDQpgc2VsZWN0KClgDQo9PT09PT09PT0NCg0K4bueIHBo4bqnbiBuw6B5LCBjaMO6bmcgdGEgc+G6vSBz4butIGThu6VuZyBi4buZIGThu68gbGnhu4d1IHbhu4Egw7Qgbmhp4buFbSBraMO0bmcga2jDrSB2w6Agbmhp4buHdCDEkeG7mSB04bqhaSB0aMOgbmggcGjhu5EgQ2hpY2FnbywgTeG7uS4NCg0KYGBge3J9DQpjaGljYWdvIDwtIHJlYWRSRFMoImRhdGFzZXQvY2hpY2Fnby5yZHMiKQ0KYGBgDQoNClRhIHThuqNpIHBhY2thZ2UgYGRwbHlyKClgLg0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpgYGANCg0KSMOgbSBgc2VsZWN0KClgIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIGzhu7FhIGNo4buNbiBj4buZdCB0cm9uZyBkYXRhIGZyYW1lLiBHaeG6oyBz4butIGNow7puZyB0YSBjaOG7iSBtdeG7kW4gbMOgbSB2aeG7h2MgduG7m2kgMyBj4buZdCDEkeG6p3UuIA0KDQpgYGB7cn0NCnN1YnNldDEgPC0gY2hpY2Fnb1sxOjNdDQpzdWJzZXQyIDwtIHNlbGVjdChjaGljYWdvLCBjaXR5OmRwdHApDQpoZWFkKHN1YnNldDIpDQpgYGANCg0KTMawdSDDvSBy4bqxbmcgZOG6pXUgYDpgIGtow7RuZyB0aOG7gyBz4butIGThu6VuZyBjaG8gdMOqbiBob+G6t2MgY2hhcmFjdGVyLiBUdXkgbmhpw6puLCB0cm9uZyBow6BtIGBzZWxlY3QoKWAgdGEgY8OzIHRo4buDIGTDuW5nIG7DsyDEkeG7gyB4w6FjIMSR4buLbmggbeG7mXQgY2h14buXaSB0w6puIGJp4bq/biBz4buRLg0KDQpUYSBjxaluZyBjw7MgdGjhu4MgZOG6pXUgYC1gIHRyb25nIGBzZWxlY3QoKWAgxJHhu4MgbG/huqFpIGJp4bq/biBz4buRIHRhIGtow7RuZyBtdeG7kW4uIA0KDQpgYGB7cn0NCnN1YnNldDMgPC0gc2VsZWN0KGNoaWNhZ28sIC0oY2l0eTpkcHRwKSkNCmBgYA0KDQpUcm9uZyBSLCBu4bq/dSB0YSBtdeG7kW4gc+G7rSBk4bulbmcgDQoNCmBgYHtyfQ0KaSA8LSBtYXRjaCgiY2l0eSIsIG5hbWVzKGNoaWNhZ28pKQ0KaiA8LSBtYXRjaCgiZHB0cCIsIG5hbWVzKGNoaWNhZ28pKQ0KaGVhZChjaGljYWdvWywtKGk6aildKQ0KYGBgDQoNClRhIGPFqW5nIGPDsyB0aOG7gyBz4butIGThu6VuZyBjw7ogcGjDoXAgxJHhu4MgeMOhYyDEkeG7i25oIG5oaeG7gXUgYmnhur9uIHPhu5EgY8OzIGPDuW5nIHF1eSB04bqvYyDEkeG6t3QgdMOqbi4gVsOtIGThu6UsIG7hur91IHRhIG114buRbiBnaeG7ryBuaOG7r25nIGJp4bq/biBz4buRIGPDsyB0w6puIGvhur90IHRow7pjIHbhu5tpIGAyYA0KDQpgYGB7cn0NCnN1YnNldDQgPC0gc2VsZWN0KGNoaWNhZ28sIGVuZHNfd2l0aCgiMiIpKQ0Kc3RyKHN1YnNldDQpDQpgYGANCg0KSG/hurdjIG7hur91IHRhIG114buRbiBnaeG7ryBjw6FjIGJp4bq/biBz4buRIGLhuq90IMSR4bqndSB24bubaSAiZCIsIHRhIGPDsyB0aOG7gw0KDQpgYGB7cn0NCnN1YnNldDUgPC0gc2VsZWN0KGNoaWNhZ28sIHN0YXJ0c193aXRoKCJkIikpDQpzdHIoc3Vic2V0NSkNCmBgYA0KDQpgZmlsdGVyKClgDQo9PT09PT09PT09DQoNCkjDoG0gYGZpbHRlcigpYCDEkcaw4bujYyBz4butIGThu6VuZyDEkeG7gyB0csOtY2ggeHXhuqV0IHThuq1wIGjhu6NwIGNvbiBjw6FjIGjDoG5nIHThu6sgbeG7mXQgZGF0YSBmcmFtZS4gSMOgbSBuw6B5IHTGsMahbmcgdOG7sSBuaMawIGBzdWJzZXQoKWAgdHJvbmcgUiBuaMawbmcgbmhhbmggaMahbi4NCg0KR2nhuqMgc+G7rSB0YSBtdeG7kW4gdHLDrWNoIHh14bqldCBjw6FjIGjDoG5nIGPhu6dhIGRhdGEgZnJhbWUgYGNoaWNhZ29gIOG7nyBt4bupYyBQTTIuNSA+IDMwLCB0YSBjw7MgdGjhu4MNCg0KYGBge3J9DQpjaGljLmYgPC0gZmlsdGVyKGNoaWNhZ28sIHBtMjV0bWVhbjIgPiAzMCkNCnN0cihjaGljLmYpDQpgYGANCg0KVGEgdGjhuqV5IHLhurFuZyBjaOG7iSBjw7MgMTk0IGjDoG5nICB0cm9uZyBkYXRhIGZyYW1lIHbDoCBwaMOibiBi4buRIGPhu6dhIHBtMjUuDQoNCmBgYHtyfQ0Kc3VtbWFyeShjaGljLmYkcG0yNXRtZWFuMikNCmBgYA0KDQpUYSBjw7MgdGjhu4MgdHJ1eeG7gW4gxJFp4buBdSBraeG7h24gdsOgbyBgZmlsdGVyKClgLg0KDQpgYGB7cn0NCmNoaWMuZiA8LSBmaWx0ZXIoY2hpY2FnbywgcG0yNXRtZWFuMiA+IDMwICYgdG1wZCA+IDgwKQ0Kc2VsZWN0KGNoaWMuZiwgZGF0ZSwgdG1wZCwgcG0yNXRtZWFuMikNCmBgYA0KDQpgYXJyYW5nZSgpYA0KPT09PT09PT09PQ0KDQpIw6BtIGBhcnJhbmdlKClgIMSRxrDhu6NjIHPhu60gZOG7pW5nIMSR4buDIHPhuq9wIHjhur9wIGzhuqFpIGjDoG5nIGPhu6dhIGRhdGEgZnJhbWUgdGhlbyBjw6FjIGJp4bq/biBz4buRIChj4buZdCkuIFRoZW8gdGjhu6kgdOG7sSwgaMOgbmcgxJHGsOG7o2MgeOG6v3AgdGhlbyBj4buZdCDEkeG6p3UgdGnDqm4gcuG7k2kgbOG6p24gbMaw4bujdCB0aGVvIGPDoWMgY+G7mXQgc2F1Lg0KDQpgYGB7cn0NCmNoaWNhZ28gPC0gYXJyYW5nZShjaGljYWdvLCBkYXRlKQ0KYGBgDQoNCkPDoWMgY+G7mXQgY8OzIHRo4buDIMSRxrDhu6NjIHPhuq9wIHjhur9wIHRoZW8gdGjhu6kgdOG7sSBnaeG6o20gZOG6p24gduG7m2kgaMOgbSBgZGVzYygpYC4NCg0KYGBge3J9DQpjaGljYWdvIDwtIGFycmFuZ2UoY2hpY2FnbywgZGVzYyhkYXRlKSkNCmBgYA0KDQpgcmVuYW1lKClgDQo9PT09PT09PT09DQoNCg0KYGBge3J9DQpjaGljYWdvIDwtIHJlbmFtZShjaGljYWdvLCBkZXdwb2ludCA9IGRwdHAsIHBtMjUgPSBwbTI1dG1lYW4yKQ0KaGVhZChjaGljYWdvWywxOjVdLCAzKQ0KYGBgDQoNCmBtdXRhdGUoKWANCj09PT09PT09PT0NCg0KSMOgbSBgbXV0YXRlKClgIGdpw7pwIHThuqFvIGhv4bq3YyB0aGF5IMSR4buVaSBiaeG6v24gc+G7kSB0cm9uZyBkYXRhIGZyYW1lLiANCg0KVsOtIGThu6UsIMSR4buDIGJp4bq/dCBsaeG7h3UgbeG7qWMgw7Qgbmhp4buFbSBjYW8gaMahbiBoYXkgdGjhuqVwIGjGoW4gbeG7qWMgdHJ1bmcgYsOsbmgsIHRhIHRy4burIHPhu5EgbGnhu4d1IGPhu6dhIGPDoWMgcXVhbiBzw6F0IGNobyBz4buRIHRydW5nIGLDrG5oLg0KDQpUYSB04bqhbyBt4buZdCBiaeG6v24gc+G7kSBt4bubaSBsw6AgYHBtMjVuZXdgLg0KDQpgYGB7cn0NCmNoaWNhZ28gPC0gbXV0YXRlKGNoaWNhZ28sIHBtMjVuZXcgPSBwbTI1IC0gbWVhbihwbTI1LCBuYS5ybSA9IFRSVUUpKQ0KaGVhZChjaGljYWdvKQ0KYGBgDQoNCmB0cmFuc211dGUoKWANCj09PT09PT09PT09PQ0KDQpgdHJhbnNtdXRlKClgIGhv4bqhdCDEkeG7mW5nIG5oxrAgYG11dGF0ZSgpYCwgbmjGsG5nIGLhu48gxJFpIG5o4buvbmcgYmnhur9uIHPhu5Ega2jDtG5nIMSRxrDhu6NjIHRoYXkgxJHhu5VpLg0KDQpgYGB7cn0NCmhlYWQodHJhbnNtdXRlKGNoaWNhZ28sDQogICAgICAgICAgICAgICBwbTEwbmV3ID0gcG0xMHRtZWFuMiAtIG1lYW4ocG0xMHRtZWFuMiwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgICAgIG8zbmV3ID0gbzN0bWVhbjIgLSBtZWFuKG8zdG1lYW4yLCBuYS5ybSA9IFRSVUUpKSkNCmBgYA0KDQpgZ3JvdXBfYnkoKWANCj09PT09PT09PT09PT0NCg0KSMOgbSBgZ3JvdXBfYnkoKWAgxJHGsOG7o2Mgc+G7rSBk4bulbmcgxJHhu4MgdMOtbmggc+G7kSB0aOG7kW5nIGvDqiB0aGVvIHBow6JuIHThuqduZy4gVsOtIGThu6UsIHRhIGPDsyB0aOG7gyBtdeG7kW4gYmnhur90IHPhu5EgUE0yLjUgdHJ1bmcgYsOsbmggaMOgbmcgbsSDbS4gRG8gxJHDsywgZOG7ryBsaeG7h3UgxJHGsOG7o2MgcGjDom4gdOG6p25nIHRoZW8gbsSDbSwgdsOgIMSRw6J5IGzDoCB0aMO0bmcgdGluIHRhIGzhuqV5IMSRxrDhu6NjIHThu6sgYmnhur9uIGBkYXRlYC4gS+G6v3QgaOG7o3AgduG7m2kgYGdyb3VwX2J5KClgLCB0YSBz4butIGThu6VuZyBow6BtIGBzdW1tYXJpc2UoKWAuDQoNCkPDoWMgdGjhu6ljIGhv4bqhdCDEkeG7mW5nIGzDoCB0YSBwaMOibiB0w6FjaCBkYXRhIGZyYW1lIHRow6BuaCBuaOG7r25nIHBo4bqnbiByacOqbmcgYmnhu4d0IHRoZW8gbeG7mXQgaGF5IG5oaeG7gXUgYmnhur9uIHPhu5EgKGBncm91cF9ieSgpYCksIHbDoCDDoXAgZOG7pW5nIGjDoG0gYHN1bW1hcmlzZSgpYCB2w6BvIG5o4buvbmcgcGjhuqduIHJpw6puZyBiaeG7h3QgbsOgeS4NCg0KDQpgYGB7cn0NCmNoaWNhZ28gPC0gbXV0YXRlKGNoaWNhZ28sIHllYXIgPSBhcy5QT1NJWGx0KGRhdGUpJHllYXIgKyAxOTAwKQ0KYGBgDQoNCmBgYHtyfQ0KeWVhcnMgPC0gZ3JvdXBfYnkoY2hpY2FnbywgeWVhcikNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcmlzZSh5ZWFycywgcG0yNSA9IG1lYW4ocG0yNSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICBvMyA9IG1heChvM3RtZWFuMiwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICBubzIgPSBtZWRpYW4obm8ydG1lYW4yLCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCmBzdW1tYXJpc2UoKWAgdHLhuqMgduG7gSBkYXRhIGZyYW1lIHbhu5tpIGB5ZWFyYCBsw6AgY+G7mXQgxJHhuqd1IHRpw6puLCB2w6Agc2F1IMSRw7MgbMOgIHPhu5EgdHJ1bmcgYsOsbmggaMOgbmcgbsSDbSBj4bunYSBwbTI1LCBvMywgdsOgIG5vMi4NCg0KYCU+JWANCj09PT09DQoNClRvw6FuIHThu60gYCU+JWAgcuG6pXQgaOG7r3Ugw61jaCB0cm9uZyB2aeG7h2MgeMOidSBjaHXhu5dpIGPDoWMgaMOgbSBj4bunYSBgZHBseXJgLg0KDQpOaMawIOG7nyB2w60gZOG7pSB0csOqbiwgY2jDum5nIHRhIG114buRbiB0w61uaCB0cnVuZyBiw6xuaCBgbzNgLCBgbm8yYCB2w6AgYHBtMjVgIHRoZW8gbsSDbSwgdGEgcGjhuqNpOg0KDQoxLiBU4bqhbyBiaeG6v24gYHllYXJgICANCjIuIFBow6JuIHTDoWNoIGRhdGEgZnJhbWUgdGhlbyBgeWVhcmAgIA0KMy4gVMOtbmggdG/DoW4gdHJ1bmcgYsOsbmggYG8zYCwgYG5vMmAsIHbDoCBgcG0yNWAgdGhlbyBgeWVhcmAuDQoNClbhu5tpIGAlPiVgLCB0YSBjw7MgdGjhu4MgdGjhu7FjIGhp4buHbiB0cm9uZyBt4buZdCBjw6J1IGzhu4duaC4NCg0KYGBge3J9DQptdXRhdGUoY2hpY2FnbywgeWVhciA9IGFzLlBPU0lYbHQoZGF0ZSkkeWVhciArIDE5MDApICU+JQ0KICBncm91cF9ieSh5ZWFyKSAlPiUNCiAgc3VtbWFyaXNlKHBtMjUgPSBtZWFuKHBtMjUsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgbzMgPSBtYXgobzN0bWVhbjIsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgbm8yID0gbWVkaWFuKG5vMnRtZWFuMiwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQpMxrB1IMO9IHLhurFuZywga2hpIGfhu41pIGjDoG0gYG11dGF0ZSgpYCB0YSBjw7MgdHJ1eeG7gW4gZGF0YSBmcmFtZSBgY2hpY2Fnb2AsIG5oxrBuZyDhu58gbmjhu69uZyBs4bqnbiBn4buNaSBow6BtIHNhdSwgdGEga2jDtG5nIGPhuqduIHBo4bqjaSB0cnV54buBbiBkYXRhIGZyYW1lIHbDoG8gxJHhu5FpIHPhu5EgxJHhuqd1IHRpw6puIG7hu69hLiBLaGkgc+G7rSBk4bulbmcgYCU+JWAsIMSR4bqndSByYSDhu58gbOG6p24gZ+G7jWkgdHLGsOG7m2MgxJHDoyDEkcaw4bujYyBuZ+G6p20gxJHGsGEgdsOgbyDEkeG7kWkgc+G7kSDEkeG6p3UgdGnDqm4g4bufIGzhuqduIGfhu41pIHRp4bq/cCB0aGVvLg0KDQpgYGB7cn0NCm11dGF0ZShjaGljYWdvLCBtb250aCA9IGFzLlBPU0lYbHQoZGF0ZSkkbW9uICsgMSkgJT4lIA0KICBncm91cF9ieShtb250aCkgJT4lIA0KICBzdW1tYXJpc2UocG0yNSA9IG1lYW4ocG0yNSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIG8zID0gbWF4KG8zdG1lYW4yLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgbm8yID0gbWVkaWFuKG5vMnRtZWFuMiwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQoNCg0K