네이버 카페 크롤러 만들기

# from selenium import webdriver
# from selenium.webdriver.common.by import By
# from selenium.webdriver.support.ui import WebDriverWait
# from selenium.webdriver.support import expected_conditions as EC
# import pandas as pd
# import openpyxl
# import time
# 
# def collect_article_content():
#     try:
#         main_element = WebDriverWait(driver, 10).until(
#             EC.presence_of_element_located((By.XPATH, '//*[@id="app"]/div/div/div[2]/div[2]/div[2]/div/div/div/div/div'))
#         )
#         return main_element.get_attribute('innerText')
#     except:
#         try:
#             main_element = WebDriverWait(driver, 10).until(
#                 EC.presence_of_element_located((By.XPATH, '//*[@id="app"]/div/div/div[2]/div[2]/div[1]/div/div/div'))
#             )
#             return main_element.get_attribute('innerText')
#         except:
#             return None
# 
# # 크롬 드라이버 실행
# driver = webdriver.Chrome()
# 
# url = "카페 페이지 url을 입력하세요"
# driver.get(url)
# time.sleep(3)
# 
# # 로그인 - 시간 내 직접하는 방식
# time.sleep(12)
# 
# # 로그인 완료 후 다시 카페 페이지로 이동
# driver.get(url)
# time.sleep(3)
# 
# try:
#     # 텍스트가 있는 iframe으로 전환
#     element = WebDriverWait(driver, 20).until(
#         EC.presence_of_element_located((By.ID, "cafe_main"))
#     )
#     driver.switch_to.frame(element)
#     
#     # 모든 텍스트 수집
#     all_text = collect_article_content()
#     df = pd.DataFrame([all_text], columns=['content'])
#     df.to_excel('저장할 파일명.xlsx', index=False, engine='openpyxl')
# 
# except Exception as e:
#     print(f"An error occurred: {e}")
# 
# finally:
#     driver.quit()

크롤러는 vscode-python을 사용하여 제작했습니다.


카페 글 중 로그인을 해야 볼 수 있는 글과 전체 공개 글의 XPATH가 달라서 두 가지 모두 보도록 설정했습니다. 해당 XPATH경로는 언제든 바뀔 수 있습니다.


시간상 간단히 만든 크롤러라 로그인은 직접하는 방식으로 설정했고, 타자 속도에 따라 로그인 시간은 조정할 필요가 있습니다. 또한 글의 본문에 있는 모든 텍스트를 수집하도록 설정하였기에 동영상이 있는 경우 ‘동영상’, ‘재생’ 등의 단어도 함께 수집될 수 있습니다(코드 수정 혹은 전처리가 필요합니다). 저의 경우 텍스트마이닝을 하며 전처리도 했고, 빈도분석이나 tf-idf에서 걸러질 것으로 보아 그냥 두었습니다.


네이버 카페는 마우스로 긁어서 복사가 안되는 경우가 있는데, iframe으로 이동 후 텍스트를 수집하면 잘 됩니다.




R에서 간단한 텍스트 분석

필요한 패키지 불러오기




파일 읽어오기

folder_path <- "크롤링 한 xlsx파일들이 존재하는 폴더 경로를 입력해주세요"

file_list <- list.files(path = folder_path, pattern = "*.xlsx", full.names = TRUE)

data_list <- lapply(file_list, function(file) {
  read_excel(file)
})

result_df <- bind_rows(data_list)

result_df

저는 네이버 카페 중 ’클라이밍’카페를 예시로 크롤링했습니다. 모든 xlsx파일을 읽어와서 하나의 df로 정리하는 과정입니다. 크롤링한 파일 형태에 따라 조금씩 수정될 수 있습니다.




기초 전처리 과정

clean_text <- function(x) {
  str_trim(str_replace_all(x, "\n", " "))
}

dt_pp <- result_df %>% 
  mutate(across(everything(), ~ clean_text(.)))

dt_pp

모든 줄넘김을 공백 한 칸으로 대체하는 함수를 만들고 모든 값에 적용했습니다.




한글 전처리 및 빈도분석

pre_dt <- dt_pp$content %>% 
  str_replace_all('[^가-힣]', ' ') %>% 
  str_squish() %>% 
  as_tibble() %>% 
  filter(value != "")

token_dt <- pre_dt %>% 
  unnest_tokens(input = value,
                output = word,
                token = extractNoun)

token_dt <- token_dt %>% 
  filter(!word %in% c("재생", "해서", "너무", "들이", "서울특별시", "부산", "사진", "영상", "이번", "하시", "하기", "비슷",
                      "여기", "장님", "만원", "하면", "강남", "클라이밍을", "오버", "다이", "서울", "일산", "재밌게", "마곡",
                      "마지막", "얼마", "오랜만", "하루", "논현", "어제", "카페", "홍대"))


token_dt <- token_dt %>%
  count(word, sort = T) %>% 
  filter(str_count(word) > 1) %>% 
  filter(n >= 20)

token_dt

저는 클라이밍 카페를 예시로 크롤링했기 때문에 다음과 같은 결과를 얻었습니다.


기본적인 한글 전처리를 하고 토크나이징을 진행했고, 불용어를 제거했습니다. 필요에 따라 지역과 관련된 단어도 제거하였습니다.


클라이밍은 경로를 ’문제’라는 단어로 사용하는 것을 알 수 있었습니다. 또한 암장의 종류도 (지구력, 볼더링, 스트레칭, 트레이닝, 리드, 빌레이 등) 다양하게 존재하는 것으로 보입니다. 난이도는 주로 색상으로 나타납니다(주로 흰색~붉은 색 또는 어두운 색). 유저들이 주로 신경쓰는 요소는 (공간, 사람, 주차 시설, 샤워 시설, 탈의실, 세족실) 정도로 보입니다. 유저들은 타 지역에 갈 때 ’원정’이라고 하고 본인 지역에서 주로 가는 곳을 ’홈짐’이라고 합니다. 또한 새로 오픈하는 클라이밍장을 오픈런 하는 경향도 보였습니다.




하나의 글 내에서 자주 등장하는 단어

마찬가지로 적당히 전처리를 하고, 각각의 글마다 id를 부여하여 하나의 글에서 함께 사용되는 단어를 살펴보았습니다. 당연하게도 빈도분석과 비슷한 결과를 보였으나, 링크의 짙은 정도를 통해 그 빈도를 볼 수 있었습니다.




bigram, 2-gram

다음은 n-gram 분석도 해보았습니다. 이 이미지는 앞선 pairwise와는 달리, 모든 글에서 붙어서 나타나는 단어를 분석한 것입니다. 역시 빈도가 높은 경우로 필터링하였습니다. 후기 글이므로 주로 센터 이름들이 많이 나타나고 있습니다. 빈도분석에서 본 것처럼 난이도와 관련된 색깔 단어도 눈에 띄고, 새로 오픈한 곳을 다녀온 후기도 많았다는 것을 알 수 있었습니다.

LS0tDQp0aXRsZTogIk5BVkVSIGNsaW1iaW5nIGNhZmUgY3Jhd2xpbmciDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIOuEpOydtOuyhCDsubTtjpgg7YGs66Gk65+sIOunjOuTpOq4sA0KYGBge3J9DQojIGZyb20gc2VsZW5pdW0gaW1wb3J0IHdlYmRyaXZlcg0KIyBmcm9tIHNlbGVuaXVtLndlYmRyaXZlci5jb21tb24uYnkgaW1wb3J0IEJ5DQojIGZyb20gc2VsZW5pdW0ud2ViZHJpdmVyLnN1cHBvcnQudWkgaW1wb3J0IFdlYkRyaXZlcldhaXQNCiMgZnJvbSBzZWxlbml1bS53ZWJkcml2ZXIuc3VwcG9ydCBpbXBvcnQgZXhwZWN0ZWRfY29uZGl0aW9ucyBhcyBFQw0KIyBpbXBvcnQgcGFuZGFzIGFzIHBkDQojIGltcG9ydCBvcGVucHl4bA0KIyBpbXBvcnQgdGltZQ0KIyANCiMgZGVmIGNvbGxlY3RfYXJ0aWNsZV9jb250ZW50KCk6DQojICAgICB0cnk6DQojICAgICAgICAgbWFpbl9lbGVtZW50ID0gV2ViRHJpdmVyV2FpdChkcml2ZXIsIDEwKS51bnRpbCgNCiMgICAgICAgICAgICAgRUMucHJlc2VuY2Vfb2ZfZWxlbWVudF9sb2NhdGVkKChCeS5YUEFUSCwgJy8vKltAaWQ9ImFwcCJdL2Rpdi9kaXYvZGl2WzJdL2RpdlsyXS9kaXZbMl0vZGl2L2Rpdi9kaXYvZGl2L2RpdicpKQ0KIyAgICAgICAgICkNCiMgICAgICAgICByZXR1cm4gbWFpbl9lbGVtZW50LmdldF9hdHRyaWJ1dGUoJ2lubmVyVGV4dCcpDQojICAgICBleGNlcHQ6DQojICAgICAgICAgdHJ5Og0KIyAgICAgICAgICAgICBtYWluX2VsZW1lbnQgPSBXZWJEcml2ZXJXYWl0KGRyaXZlciwgMTApLnVudGlsKA0KIyAgICAgICAgICAgICAgICAgRUMucHJlc2VuY2Vfb2ZfZWxlbWVudF9sb2NhdGVkKChCeS5YUEFUSCwgJy8vKltAaWQ9ImFwcCJdL2Rpdi9kaXYvZGl2WzJdL2RpdlsyXS9kaXZbMV0vZGl2L2Rpdi9kaXYnKSkNCiMgICAgICAgICAgICAgKQ0KIyAgICAgICAgICAgICByZXR1cm4gbWFpbl9lbGVtZW50LmdldF9hdHRyaWJ1dGUoJ2lubmVyVGV4dCcpDQojICAgICAgICAgZXhjZXB0Og0KIyAgICAgICAgICAgICByZXR1cm4gTm9uZQ0KIyANCiMgIyDtgazroawg65Oc65287J2067KEIOyLpO2WiQ0KIyBkcml2ZXIgPSB3ZWJkcml2ZXIuQ2hyb21lKCkNCiMgDQojIHVybCA9ICLsubTtjpgg7Y6Y7J207KeAIHVybOydhCDsnoXroKXtlZjshLjsmpQiDQojIGRyaXZlci5nZXQodXJsKQ0KIyB0aW1lLnNsZWVwKDMpDQojIA0KIyAjIOuhnOq3uOyduCAtIOyLnOqwhCDrgrQg7KeB7KCR7ZWY64qUIOuwqeyLnQ0KIyB0aW1lLnNsZWVwKDEyKQ0KIyANCiMgIyDroZzqt7jsnbgg7JmE66OMIO2bhCDri6Tsi5wg7Lm07Y6YIO2OmOydtOyngOuhnCDsnbTrj5kNCiMgZHJpdmVyLmdldCh1cmwpDQojIHRpbWUuc2xlZXAoMykNCiMgDQojIHRyeToNCiMgICAgICMg7YWN7Iqk7Yq46rCAIOyeiOuKlCBpZnJhbWXsnLzroZwg7KCE7ZmYDQojICAgICBlbGVtZW50ID0gV2ViRHJpdmVyV2FpdChkcml2ZXIsIDIwKS51bnRpbCgNCiMgICAgICAgICBFQy5wcmVzZW5jZV9vZl9lbGVtZW50X2xvY2F0ZWQoKEJ5LklELCAiY2FmZV9tYWluIikpDQojICAgICApDQojICAgICBkcml2ZXIuc3dpdGNoX3RvLmZyYW1lKGVsZW1lbnQpDQojICAgICANCiMgICAgICMg66qo65OgIO2FjeyKpO2KuCDsiJjsp5ENCiMgICAgIGFsbF90ZXh0ID0gY29sbGVjdF9hcnRpY2xlX2NvbnRlbnQoKQ0KIyAgICAgZGYgPSBwZC5EYXRhRnJhbWUoW2FsbF90ZXh0XSwgY29sdW1ucz1bJ2NvbnRlbnQnXSkNCiMgICAgIGRmLnRvX2V4Y2VsKCfsoIDsnqXtlaAg7YyM7J2866qFLnhsc3gnLCBpbmRleD1GYWxzZSwgZW5naW5lPSdvcGVucHl4bCcpDQojIA0KIyBleGNlcHQgRXhjZXB0aW9uIGFzIGU6DQojICAgICBwcmludChmIkFuIGVycm9yIG9jY3VycmVkOiB7ZX0iKQ0KIyANCiMgZmluYWxseToNCiMgICAgIGRyaXZlci5xdWl0KCkNCmBgYA0K7YGs66Gk65+s64qUIHZzY29kZS1weXRob27snYQg7IKs7Jqp7ZWY7JesIOygnOyeke2WiOyKteuLiOuLpC4NCg0KPGJyPg0KDQrsubTtjpgg6riAIOykkSDroZzqt7jsnbjsnYQg7ZW07JW8IOuzvCDsiJgg7J6I64qUIOq4gOqzvCDsoITssrQg6rO16rCcIOq4gOydmCBYUEFUSOqwgCDri6zrnbzshJwg65GQIOqwgOyngCDrqqjrkZAg67O064+E66GdIOyEpOygle2WiOyKteuLiOuLpC4g7ZW064u5IFhQQVRI6rK966Gc64qUIOyWuOygnOuToCDrsJTrgJQg7IiYIOyeiOyKteuLiOuLpC4NCg0KPGJyPg0KDQrsi5zqsITsg4Eg6rCE64uo7Z6IIOunjOuToCDtgazroaTrn6zrnbwg66Gc6re47J247J2AIOyngeygke2VmOuKlCDrsKnsi53snLzroZwg7ISk7KCV7ZaI6rOgLCDtg4DsnpAg7IaN64+E7JeQIOuUsOudvCDroZzqt7jsnbgg7Iuc6rCE7J2AIOyhsOygle2VoCDtlYTsmpTqsIAg7J6I7Iq164uI64ukLiDrmJDtlZwg6riA7J2YIOuzuOusuOyXkCDsnojripQg66qo65OgIO2FjeyKpO2KuOulvCDsiJjsp5HtlZjrj4TroZ0g7ISk7KCV7ZWY7JiA6riw7JeQIOuPmeyYgeyDgeydtCDsnojripQg6rK97JqwICfrj5nsmIHsg4EnLCAn7J6s7IOdJyDrk7HsnZgg64uo7Ja064+EIO2VqOq7mCDsiJjsp5HrkKAg7IiYIOyeiOyKteuLiOuLpCjsvZTrk5wg7IiY7KCVIO2YueydgCDsoITsspjrpqzqsIAg7ZWE7JqU7ZWp64uI64ukKS4g7KCA7J2YIOqyveyasCDthY3siqTtirjrp4jsnbTri53snYQg7ZWY66mwIOyghOyymOumrOuPhCDtlojqs6AsIOu5iOuPhOu2hOyEneydtOuCmCB0Zi1pZGbsl5DshJwg6rG465+s7KeIIOqyg+ycvOuhnCDrs7TslYQg6re464OlIOuRkOyXiOyKteuLiOuLpC4NCg0KPGJyPg0KDQrrhKTsnbTrsoQg7Lm07Y6Y64qUIOuniOyasOyKpOuhnCDquIHslrTshJwg67O17IKs6rCAIOyViOuQmOuKlCDqsr3smrDqsIAg7J6I64qU642wLCBpZnJhbWXsnLzroZwg7J2064+ZIO2bhCDthY3siqTtirjrpbwg7IiY7KeR7ZWY66m0IOyemCDrkKnri4jri6QuDQoNCjxicj4NCjxicj4NCjxicj4NCg0KIyBS7JeQ7IScIOqwhOuLqO2VnCDthY3siqTtirgg67aE7ISdDQojIyDtlYTsmpTtlZwg7Yyo7YKk7KeAIOu2iOufrOyYpOq4sA0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZWFkeGwpDQpsaWJyYXJ5KEtvTkxQKQ0KbGlicmFyeSh3aWR5cikNCmxpYnJhcnkodGlkeXRleHQpDQpsaWJyYXJ5KHRtKQ0KbGlicmFyeShpZ3JhcGgpDQpsaWJyYXJ5KGdncmFwaCkNCg0KdXNlTklBRGljKCkNCmBgYA0KDQo8YnI+DQo8YnI+DQo8YnI+DQoNCiMjIO2MjOydvCDsnb3slrTsmKTquLANCmBgYHtyfQ0KZm9sZGVyX3BhdGggPC0gIu2BrOuhpOungSDtlZwgeGxzeO2MjOydvOuTpOydtCDsobTsnqztlZjripQg7Y+0642UIOqyveuhnOulvCDsnoXroKXtlbTso7zshLjsmpQiDQoNCmZpbGVfbGlzdCA8LSBsaXN0LmZpbGVzKHBhdGggPSBmb2xkZXJfcGF0aCwgcGF0dGVybiA9ICIqLnhsc3giLCBmdWxsLm5hbWVzID0gVFJVRSkNCg0KZGF0YV9saXN0IDwtIGxhcHBseShmaWxlX2xpc3QsIGZ1bmN0aW9uKGZpbGUpIHsNCiAgcmVhZF9leGNlbChmaWxlKQ0KfSkNCg0KcmVzdWx0X2RmIDwtIGJpbmRfcm93cyhkYXRhX2xpc3QpDQoNCnJlc3VsdF9kZg0KYGBgDQrsoIDripQg64Sk7J2067KEIOy5tO2OmCDspJEgJ+2BtOudvOydtOuwjSfsubTtjpjrpbwg7JiI7Iuc66GcIO2BrOuhpOunge2WiOyKteuLiOuLpC4g66qo65OgIHhsc3jtjIzsnbzsnYQg7J297Ja07JmA7IScIO2VmOuCmOydmCBkZuuhnCDsoJXrpqztlZjripQg6rO87KCV7J6F64uI64ukLiDtgazroaTrp4HtlZwg7YyM7J28IO2Yle2DnOyXkCDrlLDrnbwg7KGw6riI7JSpIOyImOygleuQoCDsiJgg7J6I7Iq164uI64ukLg0KDQo8YnI+DQo8YnI+DQo8YnI+DQoNCiMjIOq4sOy0iCDsoITsspjrpqwg6rO87KCVDQpgYGB7cn0NCmNsZWFuX3RleHQgPC0gZnVuY3Rpb24oeCkgew0KICBzdHJfdHJpbShzdHJfcmVwbGFjZV9hbGwoeCwgIlxuIiwgIiAiKSkNCn0NCg0KZHRfcHAgPC0gcmVzdWx0X2RmICU+JSANCiAgbXV0YXRlKGFjcm9zcyhldmVyeXRoaW5nKCksIH4gY2xlYW5fdGV4dCguKSkpDQoNCmR0X3BwDQpgYGANCuuqqOuToCDspITrhJjquYDsnYQg6rO167CxIO2VnCDsubjsnLzroZwg64yA7LK07ZWY64qUIO2VqOyImOulvCDrp4zrk6Tqs6Ag66qo65OgIOqwkuyXkCDsoIHsmqntlojsirXri4jri6QuDQoNCjxicj4NCjxicj4NCjxicj4NCg0KIyMg7ZWc6riAIOyghOyymOumrCDrsI8g67mI64+E67aE7ISdDQpgYGB7cn0NCnByZV9kdCA8LSBkdF9wcCRjb250ZW50ICU+JSANCiAgc3RyX3JlcGxhY2VfYWxsKCdbXuqwgC3tnqNdJywgJyAnKSAlPiUgDQogIHN0cl9zcXVpc2goKSAlPiUgDQogIGFzX3RpYmJsZSgpICU+JSANCiAgZmlsdGVyKHZhbHVlICE9ICIiKQ0KDQp0b2tlbl9kdCA8LSBwcmVfZHQgJT4lIA0KICB1bm5lc3RfdG9rZW5zKGlucHV0ID0gdmFsdWUsDQogICAgICAgICAgICAgICAgb3V0cHV0ID0gd29yZCwNCiAgICAgICAgICAgICAgICB0b2tlbiA9IGV4dHJhY3ROb3VuKQ0KDQp0b2tlbl9kdCA8LSB0b2tlbl9kdCAlPiUgDQogIGZpbHRlcighd29yZCAlaW4lIGMoIuyerOyDnSIsICLtlbTshJwiLCAi64SI66y0IiwgIuuTpOydtCIsICLshJzsmrjtirnrs4Tsi5wiLCAi67aA7IKwIiwgIuyCrOynhCIsICLsmIHsg4EiLCAi7J2067KIIiwgIu2VmOyLnCIsICLtlZjquLAiLCAi67mE7Iq3IiwNCiAgICAgICAgICAgICAgICAgICAgICAi7Jes6riwIiwgIuyepeuLmCIsICLrp4zsm5AiLCAi7ZWY66m0IiwgIuqwleuCqCIsICLtgbTrnbzsnbTrsI3snYQiLCAi7Jik67KEIiwgIuuLpOydtCIsICLshJzsmrgiLCAi7J287IKwIiwgIuyerOuwjOqyjCIsICLrp4jqs6EiLA0KICAgICAgICAgICAgICAgICAgICAgICLrp4jsp4Drp4kiLCAi7Ja866eIIiwgIuyYpOuenOunjCIsICLtlZjro6giLCAi64W87ZiEIiwgIuyWtOygnCIsICLsubTtjpgiLCAi7ZmN64yAIikpDQoNCg0KdG9rZW5fZHQgPC0gdG9rZW5fZHQgJT4lDQogIGNvdW50KHdvcmQsIHNvcnQgPSBUKSAlPiUgDQogIGZpbHRlcihzdHJfY291bnQod29yZCkgPiAxKSAlPiUgDQogIGZpbHRlcihuID49IDIwKQ0KDQp0b2tlbl9kdA0KYGBgDQrsoIDripQg7YG065287J2067CNIOy5tO2OmOulvCDsmIjsi5zroZwg7YGs66Gk66eB7ZaI6riwIOuVjOusuOyXkCDri6TsnYzqs7wg6rCZ7J2AIOqysOqzvOulvCDslrvsl4jsirXri4jri6QuDQoNCjxicj4NCg0K6riw67O47KCB7J24IO2VnOq4gCDsoITsspjrpqzrpbwg7ZWY6rOgIO2GoO2BrOuCmOydtOynleydhCDsp4Ttlontlojqs6AsIOu2iOyaqeyWtOulvCDsoJzqsbDtlojsirXri4jri6QuIO2VhOyalOyXkCDrlLDrnbwg7KeA7Jet6rO8IOq0gOugqOuQnCDri6jslrTrj4Qg7KCc6rGw7ZWY7JiA7Iq164uI64ukLg0KDQo8YnI+DQoNCu2BtOudvOydtOuwjeydgCDqsr3roZzrpbwg4oCY66y47KCc4oCZ652864qUIOuLqOyWtOuhnCDsgqzsmqntlZjripQg6rKD7J2EIOyVjCDsiJgg7J6I7JeI7Iq164uI64ukLiDrmJDtlZwg7JWU7J6l7J2YIOyiheulmOuPhCAo7KeA6rWs66ClLCDrs7zrjZTrp4EsIOyKpO2KuOugiOy5rSwg7Yq466CI7J2064udLCDrpqzrk5wsIOu5jOugiOydtCDrk7EpIOuLpOyWke2VmOqyjCDsobTsnqztlZjripQg6rKD7Jy866GcIOuztOyeheuLiOuLpC4g64Kc7J2064+E64qUIOyjvOuhnCDsg4nsg4HsnLzroZwg64KY7YOA64Kp64uI64ukKOyjvOuhnCDtnbDsg4l+67aJ7J2AIOyDiSDrmJDripQg7Ja065GQ7Jq0IOyDiSkuIOycoOyggOuTpOydtCDso7zroZwg7Iug6rK97JOw64qUIOyalOyGjOuKlCAo6rO16rCELCDsgqzrnowsIOyjvOywqCDsi5zshKQsIOyDpOybjCDsi5zshKQsIO2DiOydmOyLpCwg7IS47KGx7IukKSDsoJXrj4TroZwg67O07J6F64uI64ukLiDsnKDsoIDrk6TsnYAg7YOAIOyngOyXreyXkCDqsIgg65WMICfsm5DsoJUn7J2065286rOgIO2VmOqzoCDrs7jsnbgg7KeA7Jet7JeQ7IScIOyjvOuhnCDqsIDripQg6rOz7J2EICftmYjsp5An7J2065286rOgIO2VqeuLiOuLpC4g65iQ7ZWcIOyDiOuhnCDsmKTtlIjtlZjripQg7YG065287J2067CN7J6l7J2EIOyYpO2UiOufsCDtlZjripQg6rK97Zal64+EIOuztOyYgOyKteuLiOuLpC4NCg0KPGJyPg0KPGJyPg0KPGJyPg0KDQojIyDtlZjrgpjsnZgg6riAIOuCtOyXkOyEnCDsnpDso7wg65Ox7J6l7ZWY64qUIOuLqOyWtA0KYGBge3J9DQp0aWR5X2NvbnRlbnQgPC0gZHRfcHAgJT4lDQogIG11dGF0ZShkb2NfaWQgPSByb3dfbnVtYmVyKCkpICU+JQ0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIGNvbnRlbnQpDQoNCnRpZHlfY29udGVudCA8LSB0aWR5X2NvbnRlbnQgJT4lDQogIGZpbHRlcighd29yZCAlaW4lIGMoIm5hdmVyIiwgImNvcnAiLCAiNTBtIiwgIuOFjuOFjiIsICLshJzsmrjtirnrs4Tsi5wiLCAi7KGw6riIIiwgIuu2gOyCsCIsICIwMCIsICLsnqzsg50iLCAi44Wg44WgIiwgIuy4teyXkCIsDQogICAgICAgICAgICAgICAgICAgICAgIuyeiOuKlCIsICLsnojslrTshJwiLCAi6rCZ7JWE7JqUIiwgIuyeiOyKteuLiOuLpCIsICLrhIjrrLQiLCAi7J6I6rOgIiwgIuunjuydtCIsICLsnojsl4jsirXri4jri6QiLCAi6re464OlIiwgIuuwlOuhnCIsDQogICAgICAgICAgICAgICAgICAgICAgIu2VmOqzoCIsICLtlanri4jri6QiLCAi7JqU7KaYIiwgIuyXhOyyrSIsICLqt7jrpqzqs6AiLCAi44WL44WLIiwgIuuLpOuluCIsICLri6TrhYDsmZTsirXri4jri6QiLCAi6re4656Y64+EIiwgIu2VmOyngOunjCIsDQogICAgICAgICAgICAgICAgICAgICAgIuqwmeydgCIsICLsl4bslrTshJwiLCAi65Sw66GcIiwgIuuyveydtCIsICLtlanri4jri6QiLCAiMTAiLCAi6rCA7J6lIiwgIuyeiOuKlOuNsCIsICLsg53qsIHrs7Tri6QiLCAi6rCZ7Iq164uI64ukIiwNCiAgICAgICAgICAgICAgICAgICAgICAi66eO7JWE7IScIiwgIu2VmOyngOunjCIsICLsoJXrp5AiLCAi7ZWc67KIIiwgIuyXhuuKlCIsICLqsIDshJwiLCAi7ZW07IScIiwgIuyggOuKlCIsICLsnpHsnYAiLCAi6re4656Y7IScIiwgIuygnOqwgCIsDQogICAgICAgICAgICAgICAgICAgICAgIuqxsOydmCIsICLsoJXrj4QiLCAi7KCR6riwIiwgIu2OtOq4sCIpKSAlPiUgDQogIG11dGF0ZSh3b3JkID0gaWZlbHNlKHdvcmQgJWluJSBjKCLqs7XqsITsnbQiKSwgIuqzteqwhCIsIHdvcmQpKSAlPiUgDQogIG11dGF0ZSh3b3JkID0gaWZlbHNlKHdvcmQgJWluJSBjKCLrrLjsoJzripQiLCAi66y47KCc6rCAIiksICLrrLjsoJwiLCB3b3JkKSkgJT4lIA0KICBtdXRhdGUod29yZCA9IGlmZWxzZSh3b3JkICVpbiUgYygi64Kc7J2064+E64qUIiksICLrgpzsnbTrj4QiLCB3b3JkKSkgJT4lIA0KICBtdXRhdGUod29yZCA9IGlmZWxzZSh3b3JkICVpbiUgYygi7IKs656M7J20IiksICLsgqzrnowiLCB3b3JkKSkgJT4lIA0KICBmaWx0ZXIoc3RyX2NvdW50KHdvcmQpID4gMSkNCg0Kd29yZF9wYWlycyA8LSB0aWR5X2NvbnRlbnQgJT4lDQogIHBhaXJ3aXNlX2NvdW50KHdvcmQsIGRvY19pZCwgc29ydCA9IFRSVUUpDQoNCndvcmRfcGFpcnNfZ3JhcGggPC0gd29yZF9wYWlycyAlPiUNCiAgZmlsdGVyKG4gPj0gMTUpICU+JQ0KICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKQ0KDQpzZXQuc2VlZCgxMjM0KQ0KZ2dyYXBoKHdvcmRfcGFpcnNfZ3JhcGgsIGxheW91dCA9ICJmciIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAibGlnaHRibHVlIiwgc2l6ZSA9IDUpICsNCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHZqdXN0ID0gMS44LCBzaXplID0gNSkgKw0KICB0aGVtZV92b2lkKCkNCmBgYA0K66eI7LCs6rCA7KeA66GcIOyggeuLue2eiCDsoITsspjrpqzrpbwg7ZWY6rOgLCDqsIHqsIHsnZgg6riA66eI64ukIGlk66W8IOu2gOyXrO2VmOyXrCDtlZjrgpjsnZgg6riA7JeQ7IScIO2VqOq7mCDsgqzsmqnrkJjripQg64uo7Ja066W8IOyCtO2OtOuztOyVmOyKteuLiOuLpC4g64u57Jew7ZWY6rKM64+EIOu5iOuPhOu2hOyEneqzvCDruYTsirftlZwg6rKw6rO866W8IOuztOyYgOycvOuCmCwg66eB7YGs7J2YIOynmeydgCDsoJXrj4Trpbwg7Ya17ZW0IOq3uCDruYjrj4Trpbwg67O8IOyImCDsnojsl4jsirXri4jri6QuDQoNCjxicj4NCjxicj4NCjxicj4NCg0KIyMgYmlncmFtLCAyLWdyYW0NCmBgYHtyfQ0KIyAyLWdyYW0g7LaU7LacIOuwjyDrrLjshJwgSUQg67aA7JesDQp0aWR5X2JpZ3JhbXMgPC0gZHRfcHAgJT4lDQogIG11dGF0ZShkb2NfaWQgPSByb3dfbnVtYmVyKCkpICU+JQ0KICB1bm5lc3RfdG9rZW5zKGJpZ3JhbSwgY29udGVudCwgdG9rZW4gPSAibmdyYW1zIiwgbiA9IDIpDQoNCiMgMi1ncmFtIOu5iOuPhCDqs4TsgrANCmJpZ3JhbV9jb3VudHMgPC0gdGlkeV9iaWdyYW1zICU+JQ0KICBjb3VudChiaWdyYW0sIHNvcnQgPSBUUlVFKQ0KDQojIOuLqOyWtCDsjI0g67aE66asDQpiaWdyYW1fc2VwYXJhdGVkIDwtIHRpZHlfYmlncmFtcyAlPiUNCiAgc2VwYXJhdGUoYmlncmFtLCBpbnRvID0gYygid29yZDEiLCAid29yZDIiKSwgc2VwID0gIiAiKQ0KDQpiaWdyYW1fc2VwYXJhdGVkIDwtIGJpZ3JhbV9zZXBhcmF0ZWQgJT4lIA0KICBmaWx0ZXIoIXdvcmQxICVpbiUgYygibmF2ZXIiLCAiY29ycCIsICI1MG0iLCAi44WO44WOIiwgIuyEnOyauO2KueuzhOyLnCIsICLsobDquIgiLCAi67aA7IKwIiwgIjAwIiwgIuyerOyDnSIsICLjhaDjhaAiLCAi7Li17JeQIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIuyeiOuKlCIsICLsnojslrTshJwiLCAi6rCZ7JWE7JqUIiwgIuyeiOyKteuLiOuLpCIsICLrhIjrrLQiLCAi7J6I6rOgIiwgIuunjuydtCIsICLsnojsl4jsirXri4jri6QiLCAi6re464OlIiwgIuuwlOuhnCIsDQogICAgICAgICAgICAgICAgICAgICAgICLtlZjqs6AiLCAi7ZWp64uI64ukIiwgIuyalOymmCIsICLsl4Tssq0iLCAi6re466as6rOgIiwgIuOFi+OFiyIsICLri6TrpbgiLCAi64uk64WA7JmU7Iq164uI64ukIiwgIuq3uOuemOuPhCIsICLtlZjsp4Drp4wiLA0KICAgICAgICAgICAgICAgICAgICAgICAi6rCZ7J2AIiwgIuyXhuyWtOyEnCIsICLrlLDroZwiLCAi67K97J20IiwgIu2VqeuLiOuLpCIsICIxMCIsICLqsIDsnqUiLCAi7J6I64qU642wIiwgIuyDneqwgeuztOuLpCIsICLqsJnsirXri4jri6QiLA0KICAgICAgICAgICAgICAgICAgICAgICAi66eO7JWE7IScIiwgIu2VmOyngOunjCIsICLsoJXrp5AiLCAi7ZWc67KIIiwgIuyXhuuKlCIsICLqsIDshJwiLCAi7ZW07IScIiwgIuyggOuKlCIsICLsnpHsnYAiLCAi6re4656Y7IScIiwgIuygnOqwgCIsDQogICAgICAgICAgICAgICAgICAgICAgICLqsbDsnZgiLCAi7KCV64+EIiwgImh0dHAiLCAibmF2ZXIubWUiLCAi7KCR6riwIiwgIu2OtOq4sCIsICLtgazqsozrs7TquLAiLCAi6ri47LC+6riwIiwgInlvdXR1LmJlIiwgImh0dHBzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIuu2gOyCsOynhOq1rCIsICLrhIjrrLTrhIjrrLTrhIjrrLTrhIjrrLTrhIjrrLTrhIjrrLTrhIjrrLTrhIjrrLTrhIjrrLTrhIjrrLQiKSkgJT4lIA0KICBmaWx0ZXIoc3RyX2NvdW50KHdvcmQxKSA+IDEpDQoNCmJpZ3JhbV9zZXBhcmF0ZWQgPC0gYmlncmFtX3NlcGFyYXRlZCAlPiUgDQogIGZpbHRlcighd29yZDIgJWluJSBjKCJuYXZlciIsICJjb3JwIiwgIjUwbSIsICLjhY7jhY4iLCAi7ISc7Jq47Yq567OE7IucIiwgIuyhsOq4iCIsICLrtoDsgrAiLCAiMDAiLCAi7J6s7IOdIiwgIuOFoOOFoCIsICLsuLXsl5AiLA0KICAgICAgICAgICAgICAgICAgICAgICAi7J6I64qUIiwgIuyeiOyWtOyEnCIsICLqsJnslYTsmpQiLCAi7J6I7Iq164uI64ukIiwgIuuEiOustCIsICLsnojqs6AiLCAi66eO7J20IiwgIuyeiOyXiOyKteuLiOuLpCIsICLqt7jrg6UiLCAi67CU66GcIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIu2VmOqzoCIsICLtlanri4jri6QiLCAi7JqU7KaYIiwgIuyXhOyyrSIsICLqt7jrpqzqs6AiLCAi44WL44WLIiwgIuuLpOuluCIsICLri6TrhYDsmZTsirXri4jri6QiLCAi6re4656Y64+EIiwgIu2VmOyngOunjCIsDQogICAgICAgICAgICAgICAgICAgICAgICLqsJnsnYAiLCAi7JeG7Ja07IScIiwgIuuUsOuhnCIsICLrsr3snbQiLCAi7ZWp64uI64ukIiwgIjEwIiwgIuqwgOyepSIsICLsnojripTrjbAiLCAi7IOd6rCB67O064ukIiwgIuqwmeyKteuLiOuLpCIsDQogICAgICAgICAgICAgICAgICAgICAgICLrp47slYTshJwiLCAi7ZWY7KeA66eMIiwgIuygleunkCIsICLtlZzrsogiLCAi7JeG64qUIiwgIuqwgOyEnCIsICLtlbTshJwiLCAi7KCA64qUIiwgIuyekeydgCIsICLqt7jrnpjshJwiLCAi7KCc6rCAIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIuqxsOydmCIsICLsoJXrj4QiLCAiaHR0cCIsICJuYXZlci5tZSIsICLsoJHquLAiLCAi7Y606riwIiwgIu2BrOqyjOuztOq4sCIsICLquLjssL7quLAiLCAieW91dHUuYmUiLCAiaHR0cHMiLA0KICAgICAgICAgICAgICAgICAgICAgICAi67aA7IKw7KeE6rWsIiwgIuuEiOustOuEiOustOuEiOustOuEiOustOuEiOustOuEiOustOuEiOustOuEiOustOuEiOustOuEiOustCIpKSAlPiUgDQogIGZpbHRlcihzdHJfY291bnQod29yZDIpID4gMSkNCg0KIyDqt7jrnpjtlIQg642w7J207YSwIOyDneyEsQ0KYmlncmFtX2dyYXBoIDwtIGJpZ3JhbV9zZXBhcmF0ZWQgJT4lDQogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpICU+JQ0KICBmaWx0ZXIobiA+PSA1KSAlPiUNCiAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKCkNCg0KIyDri6jslrQg7IyNIOyLnOqwge2ZlA0Kc2V0LnNlZWQoMTIzNCkNCmdncmFwaChiaWdyYW1fZ3JhcGgsIGxheW91dCA9ICJmciIpICsNCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSBuKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBnZW9tX25vZGVfcG9pbnQoY29sb3IgPSAic2t5Ymx1ZSIsIHNpemUgPSA0KSArDQogIGdlb21fbm9kZV90ZXh0KGFlcyhsYWJlbCA9IG5hbWUpLCB2anVzdCA9IDEuOCwgc2l6ZSA9IDQpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCuuLpOydjOydgCBuLWdyYW0g67aE7ISd64+EIO2VtOuztOyVmOyKteuLiOuLpC4g7J20IOydtOuvuOyngOuKlCDslZ7shKAgcGFpcndpc2XsmYDripQg64us66asLCDrqqjrk6Ag6riA7JeQ7IScIOu2meyWtOyEnCDrgpjtg4DrgpjripQg64uo7Ja066W8IOu2hOyEne2VnCDqsoPsnoXri4jri6QuIOyXreyLnCDruYjrj4TqsIAg64aS7J2AIOqyveyasOuhnCDtlYTthLDrp4HtlZjsmIDsirXri4jri6QuIO2bhOq4sCDquIDsnbTrr4DroZwg7KO866GcIOyEvO2EsCDsnbTrpoTrk6TsnbQg66eO7J20IOuCmO2DgOuCmOqzoCDsnojsirXri4jri6QuIOu5iOuPhOu2hOyEneyXkOyEnCDrs7gg6rKD7LKY65+8IOuCnOydtOuPhOyZgCDqtIDroKjrkJwg7IOJ6rmUIOuLqOyWtOuPhCDriIjsl5Ag652E6rOgLCDsg4jroZwg7Jik7ZSI7ZWcIOqzs+ydhCDri6TrhYDsmKgg7ZuE6riw64+EIOunjuyVmOuLpOuKlCDqsoPsnYQg7JWMIOyImCDsnojsl4jsirXri4jri6QuDQo=