From aa5b05227f2bddd996da3962e443d801db4b17a1 Mon Sep 17 00:00:00 2001 From: Haewon Kam Date: Fri, 11 Sep 2026 11:27:59 +0900 Subject: [PATCH] =?UTF-8?q?feat(supporters):=20=ED=9A=8C=EB=B3=B5=20?= =?UTF-8?q?=EC=9D=BC=EC=A0=95=20=ED=94=8C=EB=9E=98=EB=84=88=EB=A5=BC=20?= =?UTF-8?q?=ED=85=9C=ED=94=8C=EB=A6=BF=C2=B7=EC=9B=8C=EC=BB=A4=EC=97=90=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9=20(/plan=C2=B7/en/plan),=20/recovery=C2=B7/s?= =?UTF-8?q?tay=20=EB=A5=BC=20/plan=20=EC=9C=BC=EB=A1=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 템플릿: Planner.astro, lib/plan.ts·tour.ts, styles/plan.css, planStrings, pages plan·en/plan·404. Base 내비 회복 일정 → /plan, 언어 짝 /plan↔/en/plan, 옛 주소 리다이렉트(vercel.json), 사이트맵 - 워커 planner 단계(recovery 다음): scripts/build_planner_data.mjs 가 업종별 기본 규칙표(scripts/template/planner/procedures.plastic|derm.json)에 병원 시술 페이지 원문(recoveryNotes)을 matchKeywords 로 붙이고, 장소는 briefs//planner.places.json(큐레이션) 또는 범용 기본표(관광공사 기준 좌표)로 만든다 - 브리프: viewclinic·oracle 큐레이션 장소. 빈 템플릿(관광 데이터 없음)도 빌드·검증 통과(plan.test 14건) - 이전 세션의 미커밋 작업(피부과 수집·OCR·게이트·언어 스위치, stay 페이지 제거)도 이 커밋에 함께 들어감. docs/prd 변경은 제외 Co-Authored-By: Claude Fable 5.1 --- scripts/fetch_medical_tourism.py | 249 ++++- supporters/.gitignore | 6 + supporters/DEPLOY_NOTE.md | 8 + supporters/astro.config.mjs | 2 + supporters/briefs/README.md | 44 + supporters/briefs/oracle/clinic.json | 45 + supporters/briefs/oracle/hq-building.jpg | Bin 0 -> 428228 bytes .../briefs/oracle/logo-horizontal-cropped.png | Bin 0 -> 2500 bytes supporters/briefs/oracle/logo-horizontal.png | Bin 0 -> 4166 bytes supporters/briefs/oracle/logo-oracle.png | Bin 0 -> 9826 bytes supporters/briefs/oracle/logo.gif | Bin 0 -> 2156 bytes supporters/briefs/oracle/planner.places.json | 661 ++++++++++++ .../briefs/viewclinic/planner.places.json | 47 + supporters/scripts/build_planner_data.mjs | 83 ++ supporters/scripts/check.mjs | 13 +- supporters/scripts/collect_evidence.mjs | 286 ++++- supporters/scripts/collect_recovery.mjs | 249 +++++ supporters/scripts/default_briefs.mjs | 171 ++- supporters/scripts/export_template.mjs | 1 + .../gate/fixtures/before-after-phrase.html | 2 + .../scripts/gate/fixtures/derm-cert-ok.html | 2 + .../gate/fixtures/derm-cert-phrase.html | 2 + .../gate/fixtures/device-claim-approval.md | 12 + .../gate/fixtures/device-claim-guarantee.md | 12 + .../scripts/gate/fixtures/device-claim-ok.md | 15 + .../gate/fixtures/practitioner-missing.md | 14 + .../fixtures/practitioner-plastic-skip.md | 13 + .../gate/fixtures/practitioner-present.md | 14 + .../scripts/gate/fixtures/price-mention.md | 12 + .../gate/fixtures/price-notice-link.md | 12 + .../gate/fixtures/regulation-no-source.md | 2 +- supporters/scripts/gate/plan.test.mjs | 130 +++ supporters/scripts/gate/rules.mjs | 95 +- supporters/scripts/gate/test.mjs | 49 +- supporters/scripts/gen/evidence.mjs | 18 +- supporters/scripts/gen/prompt.mjs | 40 +- supporters/scripts/generate_posts.mjs | 10 +- supporters/scripts/ocr/vision_ocr.swift | 129 +++ supporters/scripts/ocr_evidence.mjs | 241 +++++ .../scripts/template/data/medicalTourism.json | 36 + .../template/data/medicalTourismKo.json | 36 + supporters/scripts/template/data/places.json | 207 ++++ .../scripts/template/data/procedures.json | 961 +++++++++++++++++ .../scripts/template/data/recoveryNotes.json | 8 + .../scripts/template/planner/places.base.json | 207 ++++ .../template/planner/procedures.derm.json | 842 +++++++++++++++ .../template/planner/procedures.plastic.json | 961 +++++++++++++++++ supporters/src/components/Planner.astro | 313 ++++++ supporters/src/data/places.json | 47 + supporters/src/data/planStrings.json | 235 +++++ supporters/src/data/procedures.json | 989 ++++++++++++++++++ supporters/src/data/recoveryNotes.json | 254 +++++ supporters/src/layouts/Base.astro | 10 +- supporters/src/lib/plan.ts | 177 ++++ supporters/src/lib/tour.ts | 89 ++ supporters/src/pages/404.astro | 17 + supporters/src/pages/en/plan.astro | 16 + supporters/src/pages/en/stay.astro | 440 -------- supporters/src/pages/plan.astro | 16 + supporters/src/pages/sitemap.xml.ts | 4 +- supporters/src/pages/stay.astro | 445 -------- supporters/src/pages/visit.astro | 2 +- supporters/src/styles/global.css | 18 + supporters/src/styles/plan.css | 172 +++ supporters/vercel.json | 26 +- templates/supporters-astro/.gitignore | 6 + templates/supporters-astro/DEPLOY_NOTE.md | 8 + templates/supporters-astro/astro.config.mjs | 2 + templates/supporters-astro/briefs/README.md | 44 + .../briefs/oracle/clinic.json | 45 + .../briefs/oracle/hq-building.jpg | Bin 0 -> 428228 bytes .../briefs/oracle/logo-horizontal-cropped.png | Bin 0 -> 2500 bytes .../briefs/oracle/logo-horizontal.png | Bin 0 -> 4166 bytes .../briefs/oracle/logo-oracle.png | Bin 0 -> 9826 bytes .../supporters-astro/briefs/oracle/logo.gif | Bin 0 -> 2156 bytes .../briefs/oracle/planner.places.json | 661 ++++++++++++ .../briefs/viewclinic/planner.places.json | 47 + .../scripts/build_planner_data.mjs | 83 ++ templates/supporters-astro/scripts/check.mjs | 13 +- .../scripts/collect_evidence.mjs | 286 ++++- .../scripts/collect_recovery.mjs | 249 +++++ .../scripts/default_briefs.mjs | 171 ++- .../scripts/export_template.mjs | 1 + .../gate/fixtures/before-after-phrase.html | 2 + .../scripts/gate/fixtures/derm-cert-ok.html | 2 + .../gate/fixtures/derm-cert-phrase.html | 2 + .../gate/fixtures/device-claim-approval.md | 12 + .../gate/fixtures/device-claim-guarantee.md | 12 + .../scripts/gate/fixtures/device-claim-ok.md | 15 + .../gate/fixtures/practitioner-missing.md | 14 + .../fixtures/practitioner-plastic-skip.md | 13 + .../gate/fixtures/practitioner-present.md | 14 + .../scripts/gate/fixtures/price-mention.md | 12 + .../gate/fixtures/price-notice-link.md | 12 + .../gate/fixtures/regulation-no-source.md | 2 +- .../scripts/gate/plan.test.mjs | 130 +++ .../supporters-astro/scripts/gate/rules.mjs | 95 +- .../supporters-astro/scripts/gate/test.mjs | 49 +- .../supporters-astro/scripts/gen/evidence.mjs | 18 +- .../supporters-astro/scripts/gen/prompt.mjs | 40 +- .../scripts/generate_posts.mjs | 10 +- .../scripts/ocr/vision_ocr.swift | 129 +++ .../supporters-astro/scripts/ocr_evidence.mjs | 241 +++++ .../src/components/Planner.astro | 313 ++++++ .../supporters-astro/src/data/factSheet.json | 5 +- .../src/data/medicalTourism.json | 7 +- .../src/data/medicalTourismKo.json | 6 +- .../supporters-astro/src/data/places.json | 207 ++++ .../src/data/planStrings.json | 235 +++++ .../supporters-astro/src/data/procedures.json | 961 +++++++++++++++++ .../src/data/recoveryNotes.json | 8 + .../supporters-astro/src/layouts/Base.astro | 10 +- templates/supporters-astro/src/lib/plan.ts | 177 ++++ templates/supporters-astro/src/lib/tour.ts | 89 ++ .../supporters-astro/src/pages/404.astro | 17 + .../supporters-astro/src/pages/en/plan.astro | 16 + .../supporters-astro/src/pages/en/stay.astro | 440 -------- .../supporters-astro/src/pages/plan.astro | 16 + .../supporters-astro/src/pages/sitemap.xml.ts | 4 +- .../supporters-astro/src/pages/stay.astro | 445 -------- .../supporters-astro/src/pages/visit.astro | 2 +- .../supporters-astro/src/styles/global.css | 18 + .../supporters-astro/src/styles/plan.css | 172 +++ templates/supporters-astro/vercel.json | 26 +- workers/supporters-build/README.md | 28 +- workers/supporters-build/run.mjs | 125 ++- 126 files changed, 12916 insertions(+), 2068 deletions(-) create mode 100644 supporters/DEPLOY_NOTE.md create mode 100644 supporters/briefs/oracle/clinic.json create mode 100644 supporters/briefs/oracle/hq-building.jpg create mode 100644 supporters/briefs/oracle/logo-horizontal-cropped.png create mode 100644 supporters/briefs/oracle/logo-horizontal.png create mode 100644 supporters/briefs/oracle/logo-oracle.png create mode 100644 supporters/briefs/oracle/logo.gif create mode 100644 supporters/briefs/oracle/planner.places.json create mode 100644 supporters/briefs/viewclinic/planner.places.json create mode 100644 supporters/scripts/build_planner_data.mjs create mode 100644 supporters/scripts/collect_recovery.mjs create mode 100644 supporters/scripts/gate/fixtures/before-after-phrase.html create mode 100644 supporters/scripts/gate/fixtures/derm-cert-ok.html create mode 100644 supporters/scripts/gate/fixtures/derm-cert-phrase.html create mode 100644 supporters/scripts/gate/fixtures/device-claim-approval.md create mode 100644 supporters/scripts/gate/fixtures/device-claim-guarantee.md create mode 100644 supporters/scripts/gate/fixtures/device-claim-ok.md create mode 100644 supporters/scripts/gate/fixtures/practitioner-missing.md create mode 100644 supporters/scripts/gate/fixtures/practitioner-plastic-skip.md create mode 100644 supporters/scripts/gate/fixtures/practitioner-present.md create mode 100644 supporters/scripts/gate/fixtures/price-mention.md create mode 100644 supporters/scripts/gate/fixtures/price-notice-link.md create mode 100644 supporters/scripts/gate/plan.test.mjs create mode 100644 supporters/scripts/ocr/vision_ocr.swift create mode 100644 supporters/scripts/ocr_evidence.mjs create mode 100644 supporters/scripts/template/data/medicalTourism.json create mode 100644 supporters/scripts/template/data/medicalTourismKo.json create mode 100644 supporters/scripts/template/data/places.json create mode 100644 supporters/scripts/template/data/procedures.json create mode 100644 supporters/scripts/template/data/recoveryNotes.json create mode 100644 supporters/scripts/template/planner/places.base.json create mode 100644 supporters/scripts/template/planner/procedures.derm.json create mode 100644 supporters/scripts/template/planner/procedures.plastic.json create mode 100644 supporters/src/components/Planner.astro create mode 100644 supporters/src/data/places.json create mode 100644 supporters/src/data/planStrings.json create mode 100644 supporters/src/data/procedures.json create mode 100644 supporters/src/data/recoveryNotes.json create mode 100644 supporters/src/lib/plan.ts create mode 100644 supporters/src/lib/tour.ts create mode 100644 supporters/src/pages/404.astro create mode 100644 supporters/src/pages/en/plan.astro delete mode 100644 supporters/src/pages/en/stay.astro create mode 100644 supporters/src/pages/plan.astro delete mode 100644 supporters/src/pages/stay.astro create mode 100644 supporters/src/styles/plan.css create mode 100644 templates/supporters-astro/DEPLOY_NOTE.md create mode 100644 templates/supporters-astro/briefs/oracle/clinic.json create mode 100644 templates/supporters-astro/briefs/oracle/hq-building.jpg create mode 100644 templates/supporters-astro/briefs/oracle/logo-horizontal-cropped.png create mode 100644 templates/supporters-astro/briefs/oracle/logo-horizontal.png create mode 100644 templates/supporters-astro/briefs/oracle/logo-oracle.png create mode 100644 templates/supporters-astro/briefs/oracle/logo.gif create mode 100644 templates/supporters-astro/briefs/oracle/planner.places.json create mode 100644 templates/supporters-astro/briefs/viewclinic/planner.places.json create mode 100644 templates/supporters-astro/scripts/build_planner_data.mjs create mode 100644 templates/supporters-astro/scripts/collect_recovery.mjs create mode 100644 templates/supporters-astro/scripts/gate/fixtures/before-after-phrase.html create mode 100644 templates/supporters-astro/scripts/gate/fixtures/derm-cert-ok.html create mode 100644 templates/supporters-astro/scripts/gate/fixtures/derm-cert-phrase.html create mode 100644 templates/supporters-astro/scripts/gate/fixtures/device-claim-approval.md create mode 100644 templates/supporters-astro/scripts/gate/fixtures/device-claim-guarantee.md create mode 100644 templates/supporters-astro/scripts/gate/fixtures/device-claim-ok.md create mode 100644 templates/supporters-astro/scripts/gate/fixtures/practitioner-missing.md create mode 100644 templates/supporters-astro/scripts/gate/fixtures/practitioner-plastic-skip.md create mode 100644 templates/supporters-astro/scripts/gate/fixtures/practitioner-present.md create mode 100644 templates/supporters-astro/scripts/gate/fixtures/price-mention.md create mode 100644 templates/supporters-astro/scripts/gate/fixtures/price-notice-link.md create mode 100644 templates/supporters-astro/scripts/gate/plan.test.mjs create mode 100644 templates/supporters-astro/scripts/ocr/vision_ocr.swift create mode 100644 templates/supporters-astro/scripts/ocr_evidence.mjs create mode 100644 templates/supporters-astro/src/components/Planner.astro create mode 100644 templates/supporters-astro/src/data/places.json create mode 100644 templates/supporters-astro/src/data/planStrings.json create mode 100644 templates/supporters-astro/src/data/procedures.json create mode 100644 templates/supporters-astro/src/data/recoveryNotes.json create mode 100644 templates/supporters-astro/src/lib/plan.ts create mode 100644 templates/supporters-astro/src/lib/tour.ts create mode 100644 templates/supporters-astro/src/pages/404.astro create mode 100644 templates/supporters-astro/src/pages/en/plan.astro delete mode 100644 templates/supporters-astro/src/pages/en/stay.astro create mode 100644 templates/supporters-astro/src/pages/plan.astro delete mode 100644 templates/supporters-astro/src/pages/stay.astro create mode 100644 templates/supporters-astro/src/styles/plan.css diff --git a/scripts/fetch_medical_tourism.py b/scripts/fetch_medical_tourism.py index 896ace0..d11ff1b 100644 --- a/scripts/fetch_medical_tourism.py +++ b/scripts/fetch_medical_tourism.py @@ -1,24 +1,40 @@ #!/usr/bin/env python3 -"""의료관광 연결 데이터 수집 (한국관광공사 TourAPI 다국어). +"""의료관광 연결 데이터 수집 (한국관광공사 TourAPI 다국어). 병원별로 돈다. 병원 좌표를 중심으로 숙박·음식점·관광지·문화시설·쇼핑을 모으고, 진행 중인 축제를 -거리와 함께 붙여 프론트가 쓸 JSON 하나로 낸다. +거리와 함께 붙여 프론트가 쓸 JSON 으로 낸다. 영문(EngService2)과 국문(KorService2)을 +한 번에 만들 수 있다. 왜 사전 수집인가 - 영문 서비스는 강남 일대 커버리지가 얇고(5km 음식점 18건, 국문은 338건) 관광지의 - 79%가 의료기관이라 필터링이 많이 필요하다. 그 처리를 수집 시점에 끝내고 프론트는 - 정제된 결과만 그린다. 미팅 데모 중 외부 API 상태에 화면이 종속되지도 않는다. + 영문 서비스는 도심 커버리지가 얇고 관광지 항목의 대부분이 의료기관이라 필터링이 많이 + 필요하다. 그 처리를 수집 시점에 끝내고 프론트는 정제된 결과만 그린다. 미팅 데모 중 + 외부 API 상태에 화면이 종속되지도 않는다. 무엇을 만들지 않는가 없는 값을 채우지 않는다. 평점·리뷰·영업시간은 TourAPI 가 주지 않으므로 비워 두고, Google Places 승인 후 별도 단계에서 붙인다. 식이 적합성은 병원 입력이며 여기서 - 판정하지 않는다. + 판정하지 않는다. 좌표도 지어내지 않는다. 주소를 좌표로 바꾸지 못하면 종료 코드 1 로 멈춘다. -출력은 서포터즈 사이트(Astro)의 데이터다. 화면은 supporters/src/pages/en/stay.astro 다. -INFINITH 제품 화면(/discovery)이 아니라 병원 서포터즈 사이트에 실린다. 외국인 환자가 보는 곳이다. +기준 좌표를 정하는 순서 + 1. --lat --lng 를 직접 주면 그대로 쓴다 (coordSource: 명령 인자). + 2. --address 와 --name 을 주면 네이버 지역검색(NAVER_CLIENT_ID/SECRET)으로 상호를 찾고, + 결과의 도로명 주소가 준 주소의 도로명·번지와 같을 때만 그 좌표를 쓴다. + 네이버가 못 찾으면 TourAPI 키워드 검색(국문·영문)으로 한 번 더 찾는다. + 3. 아무 인자도 없으면 .env 의 TOUR_API_ORIGIN_LAT/LNG (초기 샘플 사이트용). + 어느 경우든 meta.origin.coordSource 에 출처와 날짜를 적는다. - python3 scripts/fetch_medical_tourism.py - python3 scripts/fetch_medical_tourism.py --out supporters/src/data/medicalTourism.json +출력은 서포터즈 사이트(Astro)의 데이터다. 화면은 src/pages/stay.astro(국문)와 +src/pages/en/stay.astro(영문)다. 외국인 환자와 보호자가 보는 곳이다. + + # 워커가 부르는 형태 (팩트 시트 주소 기준, 영문·국문 동시) + python3 scripts/fetch_medical_tourism.py --clinic oracle --name "오라클피부과" \ + --address "서울 강남구 선릉로 612 한일빌딩" --label "오라클피부과 (선릉로 612)" \ + --out-en ~/supporters-builds/oracle/tourism/medicalTourism.json \ + --out-ko ~/supporters-builds/oracle/tourism/medicalTourismKo.json + # 좌표를 직접 줄 때 + python3 scripts/fetch_medical_tourism.py --lat 37.5049823 --lng 127.0254182 --label "..." --out-en a.json --out-ko b.json + # 이전 방식 (.env 좌표, 언어 하나) + python3 scripts/fetch_medical_tourism.py --lang ko --out supporters/src/data/medicalTourismKo.json """ import argparse, io, json, math, os, re, ssl, sys, time, urllib.parse, urllib.request @@ -51,7 +67,7 @@ TYPES_KO = { "32": ("stay", "5000"), "39": ("restaurant", "5000"), } -TYPES = TYPES_EN # main() 에서 --lang 에 맞게 바꾼다 +# 언어별 타입 표는 collect() 가 lang 에 맞게 고른다. def ssl_ctx(): @@ -62,11 +78,17 @@ def ssl_ctx(): def load_env(path): + """.env 파일을 읽고, 같은 이름의 환경변수가 있으면 그 값을 우선한다. + 워커(run.mjs)나 클라우드 실행은 파일 없이 환경변수만 줄 수 있다.""" d = {} - for line in io.open(path, encoding="utf-8"): - line = line.strip() - if line and not line.startswith("#") and "=" in line: - k, v = line.split("=", 1); d[k.strip()] = v.strip() + if os.path.exists(path): + for line in io.open(path, encoding="utf-8"): + line = line.strip() + if line and not line.startswith("#") and "=" in line: + k, v = line.split("=", 1); d[k.strip()] = v.strip().strip('"').strip("'") + for k, v in os.environ.items(): + if k.startswith(("TOUR_API_", "NAVER_CLIENT_")) and v: + d[k] = v return d @@ -305,32 +327,119 @@ def clean(it, lat, lng): } -def main(): - ap = argparse.ArgumentParser() - ap.add_argument("--festival-km", type=float, default=60.0, help="이 거리 안의 축제만 담는다") - ap.add_argument("--per-type", type=int, default=24, help="타입별 최대 건수") - ap.add_argument("--lang", choices=["en", "ko"], default="en", - help="en 은 EngService2(외국인 환자용 /en/stay), ko 는 KorService2(/stay)") - ap.add_argument("--out", default="") - a = ap.parse_args() +# ---------- 기준 좌표 ---------- - global TYPES - env = load_env(os.path.join(ROOT, ".env")) - if a.lang == "ko": - TYPES = TYPES_KO - env = dict(env, TOUR_API_SERVICE="KorService2") - if not a.out: - a.out = ("supporters/src/data/medicalTourism.json" if a.lang == "en" - else "supporters/src/data/medicalTourismKo.json") - for k in ("TOUR_API_KEY", "TOUR_API_BASE", "TOUR_API_SERVICE", "TOUR_API_ORIGIN_LAT", "TOUR_API_ORIGIN_LNG"): - if not env.get(k): sys.exit(f".env 에 {k} 가 비어 있습니다") - lat, lng = float(env["TOUR_API_ORIGIN_LAT"]), float(env["TOUR_API_ORIGIN_LNG"]) +def road_key(address): + """주소에서 도로명과 건물번호를 뽑는다. "서울 강남구 선릉로 612 한일빌딩" → ("선릉로", "612"). + 비교에만 쓴다. 없으면 (None, None).""" + m = re.search(r"([가-힣A-Za-z0-9]*?(?:대로|로|길))\s*(\d+(?:-\d+)?)(?!\s*길)", address or "") + return (m.group(1), m.group(2)) if m else (None, None) - out = {"places": {}, "festivals": [], "meta": {}} + +def addr_match(want, got): + """검색 결과 주소가 준 주소와 같은 도로명·번지인지. 도로명과 번지 사이 공백은 무시하고, + 번지 바로 뒤에 숫자나 '-' 가 붙으면(612 와 6120, 612-1) 다른 곳으로 본다. + "봉은사로 107 1, 3-5층" 처럼 공백 뒤에 층이 오는 것은 같은 곳이다.""" + road, num = road_key(want) + if not road: return False + return re.search(re.escape(road) + r"\s*" + re.escape(num) + r"(?![\d-])", got or "") is not None + + +def strip_tags(s): + return re.sub(r"<[^>]+>", "", s or "").strip() + + +def geocode_naver(env, name, address): + """네이버 지역검색으로 상호를 찾아 좌표를 얻는다. mapx/mapy 는 WGS84 경위도 x 10^7 이다. + 주소만으로는 결과가 없다(실측). 상호를 넣고, 결과의 도로명 주소가 준 주소와 같을 때만 받는다.""" + cid, sec = env.get("NAVER_CLIENT_ID"), env.get("NAVER_CLIENT_SECRET") + if not (cid and sec): return None, "NAVER_CLIENT_ID/SECRET 없음" + road, num = road_key(address) + queries = [] + if road: queries.append(f"{name} {road} {num}") + queries += [f"{name} {address}", name] + tried = [] + for q in queries: + qs = urllib.parse.urlencode({"query": q, "display": "5", "sort": "random"}) + req = urllib.request.Request("https://openapi.naver.com/v1/search/local.json?" + qs, + headers={"X-Naver-Client-Id": cid, "X-Naver-Client-Secret": sec}) + try: + with urllib.request.urlopen(req, timeout=15, context=ssl_ctx()) as r: + items = json.loads(r.read().decode()).get("items", []) + except Exception as e: + tried.append(f"'{q}': 요청 실패 {e}"); continue + for it in items: + got = it.get("roadAddress") or it.get("address") or "" + if not addr_match(address, got): continue + try: + lng, lat = int(it["mapx"]) / 1e7, int(it["mapy"]) / 1e7 + except (KeyError, ValueError): + continue + if not (33 <= lat <= 39 and 124 <= lng <= 132): continue + return {"lat": lat, "lng": lng, "matched": strip_tags(it.get("title")), "matchedAddress": got, + "coordSource": f"네이버 지역검색 '{strip_tags(it.get('title'))}' ({got}) {time.strftime('%Y-%m-%d')}"}, "" + tried.append(f"'{q}': {len(items)}건, 주소 일치 없음") + return None, "; ".join(tried) + + +def geocode_tourapi(env, name, address): + """TourAPI 키워드 검색(국문·영문)으로 병원 항목을 찾는다. 등재된 병원만 나오므로 보조 수단이다.""" + tried = [] + for svc in ("KorService2", "EngService2"): + e = dict(env, TOUR_API_SERVICE=svc) + try: + _, rows = call(e, "searchKeyword2", {"keyword": name}, rows=20, retries=1) + except Exception as ex: + tried.append(f"{svc}: 요청 실패 {ex}"); continue + for it in rows: + got = it.get("addr1") or "" + if not addr_match(address, got): continue + try: + lng, lat = float(it.get("mapx") or 0), float(it.get("mapy") or 0) + except ValueError: + continue + if not (33 <= lat <= 39 and 124 <= lng <= 132): continue + return {"lat": lat, "lng": lng, "matched": (it.get("title") or "").strip(), "matchedAddress": got, + "coordSource": f"한국관광공사 TourAPI {svc} contentid {it.get('contentid')} ({got}) {time.strftime('%Y-%m-%d')}"}, "" + tried.append(f"{svc}: {len(rows)}건, 주소 일치 없음") + return None, "; ".join(tried) + + +def resolve_origin(env, a): + """기준 좌표와 출처. 못 정하면 (None, 이유).""" + if a.lat is not None or a.lng is not None: + if a.lat is None or a.lng is None: return None, "--lat 와 --lng 는 함께 줘야 합니다" + return {"lat": a.lat, "lng": a.lng, "address": a.address or "", + "coordSource": f"명령 인자 --lat/--lng {time.strftime('%Y-%m-%d')}"}, "" + if a.address: + if not a.name: return None, "--address 에는 --name(검색할 상호)이 필요합니다. 주소만으로는 지역검색 결과가 없습니다" + road, num = road_key(a.address) + if not road: return None, f"주소에서 도로명·번지를 찾지 못했습니다: {a.address}" + found, why1 = geocode_naver(env, a.name, a.address) + if found: return dict(found, address=a.address), "" + found, why2 = geocode_tourapi(env, a.name, a.address) + if found: return dict(found, address=a.address), "" + return None, f"주소를 좌표로 바꾸지 못했습니다. 네이버 지역검색: {why1} / TourAPI: {why2}" + lat, lng = env.get("TOUR_API_ORIGIN_LAT"), env.get("TOUR_API_ORIGIN_LNG") + if not (lat and lng): return None, "기준 좌표가 없습니다. --address --name 또는 --lat --lng 를 주거나 .env 의 TOUR_API_ORIGIN_LAT/LNG 를 채우세요" + return {"lat": float(lat), "lng": float(lng), "address": "", + "coordSource": f".env TOUR_API_ORIGIN_LAT/LNG {time.strftime('%Y-%m-%d')}"}, "" + + +# ---------- 수집 ---------- + +def collect(env, lang, origin, a): + """한 언어의 데이터를 모아 dict 로 돌려준다. 파일은 쓰지 않는다.""" + types = TYPES_KO if lang == "ko" else TYPES_EN + env = dict(env, TOUR_API_SERVICE="KorService2" if lang == "ko" else "EngService2") + lat, lng = origin["lat"], origin["lng"] + print(f"\n[{lang}] {env['TOUR_API_SERVICE']} · 기준 {lat}, {lng}") + + out = {"places": {}, "festivals": [], "filters": {}, "meta": {}} filtered_log = {} wellness = [] - for ct, (name, radius) in TYPES.items(): + for ct, (name, radius) in types.items(): total, rows = call_all(env, "locationBasedList2", {"mapX": str(lng), "mapY": str(lat), "radius": radius, "contentTypeId": ct, "arrange": "E"}) @@ -348,7 +457,7 @@ def main(): print(f" {name:<11} r={radius:>5}m · API {total:>4} · 받음 {len(rows):>3} · 의료관광업소 제외 {len(dropped):>3} · 담음 {len(out['places'][name])}") wellness.sort(key=lambda x: x["distanceM"] if x["distanceM"] is not None else 10 ** 9) out["places"]["wellness"] = wellness[:a.per_type] - filtered_log["wellness"] = {"note": "관광지(76)에서 스파·찜질방 분류만 분리", "shown": len(out["places"]["wellness"])} + filtered_log["wellness"] = {"note": "관광지에서 스파·찜질방 분류만 분리", "shown": len(out["places"]["wellness"])} print(f" {'wellness':<11} 스파·찜질방 분리 · 담음 {len(out['places']['wellness'])}") # 영문 축제는 areacode 필드가 비어 있어 지역 필터를 쓸 수 없다. 좌표로 거리를 계산해 거른다. @@ -372,24 +481,23 @@ def main(): # 설명문은 항목마다 detailCommon2 를 한 번씩 부른다. 카드에 이름과 주소만 있으면 고를 수 없다. cache: dict = {} targets = [p for v in out["places"].values() for p in v] + out["festivals"] - print(f"\n 설명문 수집 {len(targets)}건", end="", flush=True) + print(f" 설명문 수집 {len(targets)}건", end="", flush=True) for i, p in enumerate(targets): if not p.get("id"): continue ov, hp = fetch_overview(env, p["id"], cache) p["overview"] = ov[:600] p["homepage"] = hp if not p.get("image"): - # 1) 영문 detailImage2 → 2) 국문 서비스 → 3) 업체 공식 홈페이지 og:image - # 1) 영문 detailImage2 → 2) 국문 서비스 → 3) 업체 홈페이지 og:image → 4) Naver 이미지 검색 + # 1) 같은 언어 detailImage2 → 2) 국문 서비스 → 3) 업체 홈페이지 og:image → 4) Naver 이미지 검색 src = "" img = fetch_image(env, p["id"], cache) if img: src = "tourapi" - if not img and a.lang == "en": + if not img and lang == "en": img = fetch_image_kor(env, p); src = "tourapi-kor" if img else src if not img: cand = fetch_image_og(p.get("homepage") or "") if cand and usable_image(cand): img, src = cand, "homepage" - if not img: + if not img and not a.no_naver_images: img = fetch_image_naver(env, p); src = "naver" if img else src p["image"] = img or None p["imageSource"] = src @@ -414,26 +522,63 @@ def main(): } out["meta"] = { - "lang": a.lang, + "lang": lang, + "clinic": a.clinic or "", "source": "한국관광공사 TourAPI " + env["TOUR_API_SERVICE"], "fetchedAt": time.strftime("%Y-%m-%dT%H:%M:%S"), - "origin": {"lat": lat, "lng": lng, "label": "뷰성형외과의원 (봉은사로 107)", - "coordSource": "Naver 지역검색 실측 2026-09-09"}, - "radiusByType": {n: int(r) for n, r in TYPES.values()}, "festivalRadiusKm": a.festival_km, + "origin": {"lat": lat, "lng": lng, "label": a.label or origin.get("matched") or origin.get("address") or "", + "address": origin.get("address", ""), "coordSource": origin["coordSource"]}, + "radiusByType": {n: int(r) for n, r in types.values()}, "festivalRadiusKm": a.festival_km, "counts": filtered_log, # 화면이 한계를 그대로 표시할 수 있게 데이터에 적어 둔다. 없는 값을 채우지 않는다. "limits": [ - "영문 서비스는 강남 일대 숙박·음식점 커버리지가 얇다(반경 5km 숙박 4건·음식점 18건, 국문은 43건·338건).", - "관광지 항목의 대부분(반경 5km 100건 중 92건)이 분류코드 A02020500 \"Medical Tourism Sites\" 였고 제외했다.", + "영문 서비스는 도심 숙박·음식점 커버리지가 국문보다 얇다.", + "관광지 항목 중 분류코드 A02020500 \"Medical Tourism Sites\"(병원·유치업체)는 제외했다.", "평점·리뷰·영업시간은 TourAPI 가 제공하지 않는다. Google Places 승인 후 채운다.", "영문 축제는 areacode 필드가 비어 있어 좌표 거리로 걸렀다.", "수술 전후 식이 적합성은 병원이 입력한 가이드로만 표시한다. 이 파일에는 없다.", ], } - p = os.path.join(ROOT, a.out) - os.makedirs(os.path.dirname(p), exist_ok=True) - io.open(p, "w", encoding="utf-8").write(json.dumps(out, ensure_ascii=False, indent=2)) - print(f"\n→ {a.out}") + return out + + +def main(): + ap = argparse.ArgumentParser(description="병원 주변 관광 데이터 수집 (TourAPI)") + ap.add_argument("--clinic", default="", help="병원 id (meta.clinic)") + ap.add_argument("--name", default="", help="지역검색에 쓸 상호. --address 와 함께 준다") + ap.add_argument("--address", default="", help="병원 주소. 네이버 지역검색으로 좌표를 찾는다") + ap.add_argument("--lat", type=float, default=None); ap.add_argument("--lng", type=float, default=None) + ap.add_argument("--label", default="", help="화면에 보일 기준점 이름 (meta.origin.label)") + ap.add_argument("--out-en", default="", help="영문 JSON 경로 (절대 또는 현재 폴더 기준)") + ap.add_argument("--out-ko", default="", help="국문 JSON 경로") + ap.add_argument("--festival-km", type=float, default=60.0, help="이 거리 안의 축제만 담는다") + ap.add_argument("--per-type", type=int, default=24, help="타입별 최대 건수") + ap.add_argument("--no-naver-images", action="store_true", help="네이버 이미지 검색 폴백을 끈다 (공개 배포용)") + ap.add_argument("--lang", choices=["en", "ko"], default="en", help="(이전 방식) --out 하나만 낼 때의 언어") + ap.add_argument("--out", default="", help="(이전 방식) 저장소 루트 기준 경로") + a = ap.parse_args() + + env = load_env(os.path.join(ROOT, ".env")) + for k in ("TOUR_API_KEY", "TOUR_API_BASE"): + if not env.get(k): sys.exit(f"{k} 가 비어 있습니다 (.env 또는 환경변수)") + + origin, why = resolve_origin(env, a) + if not origin: + print(f"기준 좌표 실패: {why}", file=sys.stderr); sys.exit(1) + print(f"기준 좌표 {origin['lat']}, {origin['lng']} · {origin['coordSource']}") + + jobs = [] + if a.out_en: jobs.append(("en", os.path.abspath(a.out_en))) + if a.out_ko: jobs.append(("ko", os.path.abspath(a.out_ko))) + if not jobs: + rel = a.out or ("supporters/src/data/medicalTourism.json" if a.lang == "en" else "supporters/src/data/medicalTourismKo.json") + jobs.append((a.lang, os.path.join(ROOT, rel))) + + for lang, path in jobs: + out = collect(env, lang, origin, a) + os.makedirs(os.path.dirname(path), exist_ok=True) + io.open(path, "w", encoding="utf-8").write(json.dumps(out, ensure_ascii=False, indent=2)) + print(f"→ {path} · 장소 {out['filters']['total']} · 축제 {len(out['festivals'])}") if __name__ == "__main__": diff --git a/supporters/.gitignore b/supporters/.gitignore index 7a5548b..7f5d1cf 100644 --- a/supporters/.gitignore +++ b/supporters/.gitignore @@ -26,3 +26,9 @@ pnpm-debug.log* # 글 생성기 산출물 (리포트는 docs 로 옮겨 커밋) generated/ + +# Vision OCR 빌드 산출물 (ocr_evidence.mjs 가 swiftc 로 만든다) +scripts/ocr/vision_ocr + +# 시술 후 관리 안내 번역 캐시 (collect_recovery.mjs --translate) +src/data/recoveryNotes.cache.json diff --git a/supporters/DEPLOY_NOTE.md b/supporters/DEPLOY_NOTE.md new file mode 100644 index 0000000..18996d5 --- /dev/null +++ b/supporters/DEPLOY_NOTE.md @@ -0,0 +1,8 @@ +# 배포 안내 (2026-09-11, haewon 결정) + +이 워크트리(feature/supporters-autobuild)의 supporters 폴더는 더 이상 Vercel 프로젝트 `view-supporters-sample`에 배포하지 않습니다. +프로덕션 정본은 메인 저장소 `/Users/haewonkam/Claude/Agentic Marketing/INFINITH/supporters` (브랜치 feature/ai-sentiment-rubric)이며, +헤더 "회복 일정"은 그쪽의 `/plan`·`/en/plan`(수술일 기준 입국·출국 계산 플래너)을 가리킵니다. + +- `.vercel/project.json` 은 `.vercel/project.json.disabled-2026-09-11` 로 이름을 바꿔 두었습니다. `vercel --prod` 를 실행해도 이 프로젝트로 올라가지 않습니다. +- 이 워크트리의 `/recovery`·`/stay`·`/en/stay`(Tour API 주변 장소·축제·동선)는 정본 브랜치의 `/plan` 안에 "주변 장소·축제" 보강 데이터로 합치는 것을 다음 단계로 검토합니다. 합치기 전까지 프로덕션에 올리지 않습니다. diff --git a/supporters/astro.config.mjs b/supporters/astro.config.mjs index fe42e91..5d46dd6 100644 --- a/supporters/astro.config.mjs +++ b/supporters/astro.config.mjs @@ -9,4 +9,6 @@ export default defineConfig({ trailingSlash: 'never', build: { format: 'file' }, compressHTML: true, + // 주변 안내(/stay)는 회복 일정(/recovery)으로 합쳤다(haewon 2026-09-11). 정적 빌드라 meta refresh 페이지가 생긴다. + redirects: { '/stay': '/recovery', '/en/stay': '/en/recovery' }, }); diff --git a/supporters/briefs/README.md b/supporters/briefs/README.md index ce37597..4dd475a 100644 --- a/supporters/briefs/README.md +++ b/supporters/briefs/README.md @@ -5,15 +5,18 @@ ``` node scripts/generate_posts.mjs --clinic --brief briefs//.json [--out DIR] [--dry-run] [--no-verify] node scripts/generate_posts.mjs --clinic viewclinic --from-golden # 정답지 18편에서 brief 를 자동 추출해 회귀 +node scripts/default_briefs.mjs --clinic --evidence > --site [--out briefs.json] [--max 6] [--industry derm|plastic] [--areas N] # 첫 배치 자동 제안 ``` ## 파일 ```json { + "industry": "plastic", // default_briefs 가 적는 업종. plastic(성형외과) | derm(피부과). 글마다 industry 를 두면 그것이 우선 "posts": [ { "id": "slug", // 파일명. posts/.md + "industry": "derm", // 선택. derm 이면 생성 프롬프트에 피부과 추가 규칙(조건 표 8행·시술자·상표·금액 금지·부작용 어휘)이 붙고, 게이트가 PRACTITIONER_MISSING 을 본다 "title": "질문형 한 문장?", // H1. 물음표로 끝난다 "category": "D", "categoryLabel": "시술 정보", "qbIds": ["D2-02"], // 질문 뱅크 문항 ID (화면에는 안 나옴) @@ -52,3 +55,44 @@ node scripts/generate_posts.mjs --clinic viewclinic --from-golden # 정 - 자막 없는 영상의 발언을 만들지 않는다. 영상 근거는 `shortsInfo[].answer` 또는 `transcripts` 뿐이다. - 기사 본문을 추정하지 않는다. 제목·매체·날짜만. - 근거에 없는 수치를 쓰지 않는다. 쓰면 `NUMBER_NOT_IN_EVIDENCE` 로 수정 대상이 된다. + +## 업종 (industry) + +`default_briefs.mjs` 가 정하고 brief 파일 최상위와 글마다 `industry` 로 적는다. 생성기·게이트는 글의 `industry` 를 우선 보고, 없으면 환경변수 `SUPPORTERS_INDUSTRY`, 그것도 없으면 `plastic` 이다. + +| 값 | 판정 | 달라지는 것 | +|---|---|---| +| `plastic` (기본) | `--industry plastic`, 또는 병원 이름에 "성형외과" | 기존 동작 그대로. 시술 영역은 URL 세그먼트(`/contents/facial/...`)로 묶고, 세그먼트가 일반어(`new`·`doc`·`index.php`·숫자)일 때만 제목·헤딩·본문 키워드 폴백 | +| `derm` | `--industry derm`, 병원 이름에 "피부과"(성형외과보다 앞에 있으면), 또는 시술 페이지 제목의 피부과 어휘가 3개 이상이고 성형외과 어휘보다 많을 때 | 시술 페이지를 URL 과 무관하게 아래 8영역으로 배정. 시술 글 제목·intent 가 조건 표 8행을 요구. `avoid` 에 피부과 금칙 추가. 지점 페이지(`branches` 유형)나 `facts.draft.json`·팩트 시트의 `branches` 가 2개 이상이면 "지점 선택 가이드"(B) 후보 추가. 시술 영역 기본 8개(`--areas`) | + +### 피부과 8영역 (질문 뱅크 D1~D8 과 1:1) + +| key | 영역 | 문항 | 판정 낱말(일부) | +|---|---|---|---| +| pigment | 색소·토닝 | D1 | 색소, 토닝, 기미, 잡티, 검버섯, 피코, 미백 | +| lifting | 리프팅·탄력 | D2 | 리프팅, 탄력, 처짐, 울쎄라, 써마지, 인모드, 슈링크, 고주파 | +| booster | 스킨부스터·재생 | D3 | 스킨부스터, 리쥬란, 물광, 엑소좀, 재생, 콜라겐 | +| toxin-filler | 톡신·필러 | D4 | 보톡스, 톡신, 필러, 주름, 사각턱, 이마, 미간 | +| acne | 여드름·흉터·모공 | D5 | 여드름, 흉터, 모공, 피지, 스케일링, 필링, 프락셀 | +| hair-body | 제모·바디 | D6 | 제모, 바디, 체형, 겨드랑이, 셀룰라이트, 쿨스컬프팅 | +| disease-hair | 피부질환·모발 | D7 | 홍조, 혈관, 다한증, 액취증, 아토피, 사마귀, 탈모, 두피 | +| plan | 계획·주기·조합 | D8 | 시술 주기, 회차, 병행, 조합, 시술 순서, 패키지 | + +점수: 제목·H1·URL 에 낱말이 있으면 5점, 헤딩 2점, 본문 등장 횟수 × 0.5(최대 2.5). 2점 미만이면 영역 없음(기획하지 않음). 근거 충분성(영역의 페이지 글자 합 1,500자 이상)은 업종과 무관하게 같다. 본문이 이미지 글자인 페이지는 글자 수가 0에 가까워 자동으로 빠진다. + +피부과 시술 글의 intent 는 시술마다 조건 표 8행(시술시간·마취·통증 정도·회복(다운타임)·유지기간·권장 회차·권장 주기·시술자)을 요구하고, 페이지에 없는 칸은 "확인", 시술자 표기가 없으면 "확인 대기"로 두라고 지시한다. 고정 글(병원 소개·방문 안내·상담 질문 체크리스트)은 업종과 관계없이 나온다. + +## 게이트 규칙 (피부과 추가분, 성형외과 글에도 적용) + +`scripts/gate/rules.mjs` 의 `checkPostSource` 에 들어 있다. 근거 조문은 코드 주석에 있고, 법 해석은 자문이 아니다. + +| 코드 | 수준 | 조건 | 근거 | +|---|---|---|---| +| `PRICE_MENTION` | error | 요약·본문·FAQ 에 금액(150,000원·15만원·₩·%할인·이벤트가 99,000·1+1). "비급여 진료비용 고지" 안내 문장은 통째로 허용 | 의료법 45조(비급여 고지는 의료기관의 의무, 서포터즈는 링크만) · 56조 2항(유인) | +| `DEVICE_CLAIM` | error | (1) 식약처 허가·인증, FDA 승인·허가, MFDS·KFDA, CE 인증 표기가 있는데 `sources` 에 `regulation` 이 없음 (2) 영구·완치·재발 없음·100%·평생 유지·한 번으로 끝 같은 효과 보장. 부정문("영구라는 뜻은 아닙니다")·"반영구"(시술명)는 통과 | 의료기기법 24조 · 약사법 68조 · 의료법 56조 2항 | +| `PRACTITIONER_MISSING` | warn | `industry: derm` 이고 분류 D 인 글에 시술자 표기("시술자" 행, "의사 직접", "의사 감독")가 없음. 성형외과 글은 검사하지 않음 | 의료법 27조(무면허 의료행위, 대리시술) | +| `BANNED_PHRASE` (사전 확장) | error | "정품 정량 인증"·"정품 인증"(인증 어휘. "정품·정량 사용을 밝힙니다" 같은 서약 사실 서술은 통과), "비포애프터"·"전후 사진을 보세요/확인하세요/공개" 유도 문구("전후 사진을 싣지 않습니다" 원칙 서술과 "수술 전후 모니터링" 시기 표현은 통과) | 의료법 56조 2항 2호·14호 | + +부작용 고지 문안은 팩트 시트 `sideEffectNotice` 를 템플릿이 붙이므로 글 단위 검사는 없다. 생성 프롬프트(`gen/prompt.mjs` 의 `DERM_RULES`)는 시술 글에 "## 시술 후 관리와 부작용" 절과 화상·색소침착·멍·부기·감염 같은 구체 어휘를 요구한다. + +픽스처: `scripts/gate/fixtures/price-mention.md`(실패) · `price-notice-link.md`(통과) · `device-claim-approval.md`·`device-claim-guarantee.md`(실패) · `device-claim-ok.md`(통과) · `practitioner-missing.md`(경고) · `practitioner-present.md`·`practitioner-plastic-skip.md`(경고 없음) · `derm-cert-phrase.html`·`before-after-phrase.html`(실패) · `derm-cert-ok.html`(통과). `npm run gate:test` 로 돈다. 픽스처 frontmatter 의 `expectWarn:`·`expectNoWarn:` 으로 warn 코드를 검사한다. diff --git a/supporters/briefs/oracle/clinic.json b/supporters/briefs/oracle/clinic.json new file mode 100644 index 0000000..f288fb8 --- /dev/null +++ b/supporters/briefs/oracle/clinic.json @@ -0,0 +1,45 @@ +{ + "_comment": "병원별 고정값. 2026-09-10 Claude 작성(haewon 확인 전). 유튜브는 YouTube Data API로 확인한 공식 채널 @oracle_medical_group(구독 1,310·영상 318·조회 113만). 로고는 공식 홈페이지 상단 logo.gif(alt '오라클피부과 로고')를 PNG로 변환. 그룹 사이트 oraclemedicalgroup.com에 국내 47·해외 18 지점 목록이 있다. 2026-09-10 사람 확인(Claude, haewon 확인 전): 자동 수집 이미지 12장 중 11장(sub_0*)은 시술 설명 이미지(모델 얼굴·전후 사진·글자)라 제외, 시설 사진은 검단점 로비 1장. 업종 피부과·지역 청담은 주소 기준. 이 파일 값은 워커 inputs 단계에서 자동값 위에 덮어쓴다.", + "youtube": "UC5husl0zvJ_W2zILCb6Wb6A", + "youtubeHandle": "@oracle_medical_group", + "logo": "supporters/briefs/oracle/logo-oracle.png", + "groupSite": "http://www.oraclemedicalgroup.com/", + "instagram": "@oracle_cd", + "naverBlog": "https://blog.naver.com/oracleclinic", + "gangnamunni": "https://www.gangnamunni.com/hospitals/125", + "factSheet": { + "kind": "피부과", + "areaLabel": "서울 강남 청담" + }, + "site": { + "heroImage": { + "file": "supporters/briefs/oracle/hq-building.jpg", + "alt": "오라클피부과의원 본사 건물 외관. 흰색 외벽 건물 상단과 1층 입구에 오라클 간판", + "width": 888, + "height": 540 + }, + "insideGallery": [ + { + "file": "supporters/briefs/oracle/hq-building.jpg", + "alt": "오라클피부과의원 본사 건물 외관. 흰색 외벽 건물 상단과 1층 입구에 오라클 간판", + "caption": "본사 건물 외관. 출처: 오라클메디컬그룹 홈페이지" + }, + { + "srcMatch": "gumdan_1", + "alt": "오라클피부과 검단점 로비. 접수 데스크와 대기 의자", + "caption": "검단점 로비. 출처: 공식 홈페이지 지점 안내" + } + ], + "clinicGallery": [], + "buildingImage": { + "file": "supporters/briefs/oracle/hq-building.jpg", + "alt": "오라클피부과의원 본사 건물 외관. 흰색 외벽 건물 상단과 1층 입구에 오라클 간판", + "caption": "본사 건물 외관. 출처: 오라클메디컬그룹 홈페이지" + } + }, + "excludeImages": [ + "sub_0" + ], + "_logoNote": "2026-09-10 haewon 지적(녹색 배너형 GIF는 완성도가 떨어짐) → 그룹 사이트 oraclemedicalgroup.com/images/logo_oracle_02.png (176×68, 투명 배경 워드마크)로 교체. 클리닉 사이트에는 CI 페이지가 없음(메뉴 CI소개가 빈 링크). 이전 배너형은 logo-horizontal.png 로 보존. haewon 제안(2026-09-10)대로 원본 배너에서 왼쪽 문구 영역을 잘라낸 logo-horizontal-cropped.png(133×49, 녹색 배경 유지)도 보관. 녹색 박스형을 쓰려면 logo 값을 이 파일로 바꾸고 --from youtube 재실행.", + "_imageNote": "2026-09-10: 본사 건물 외관은 그룹 사이트 oraclemedicalgroup.com/images/company_02.jpg (렌더링 이미지, 간판 오라클피부과의원). 같은 페이지의 다른 사진(화장품·모델·장비·전자차트)은 제외." +} \ No newline at end of file diff --git a/supporters/briefs/oracle/hq-building.jpg b/supporters/briefs/oracle/hq-building.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62c1766f58e9e59ab3635df932893d010198efe2 GIT binary patch literal 428228 zcmbrlcTiJr6fGJ=MX?|ViUOk2tJ0(ihzbY@Nbf`i#DMfBH7ZuBlz`Mojg%0nfrJnh z0Rg3j5Fv!nA%uXG00|+y{O)~o@67${&AVZk$-tR2XMbmZd#|);!J|JWf>?&sWG{D4FJT-^Lz2R{Mg007sK z|9Nk~|NG%O#C`b4QJ!PRc~5XIXgUKp#Kp~h=rH$@BZm)ju8!mUA8?reh`<#U!=q=d zAMsob7F2ziUVKdAcHMU&o1uS_YL7!+9p^oFUiiXADQOv5IeB%B8=6|$I(P0G8JpZQ zHM6y|cW`uacJcJ`e&X{K|flJm>WfB481m7@ZN);y1b&t6r1c}(zjdU4(N z;}U8%|AZcg4Dp_mRG*ew|1Y%v5!wH@z+V0TitK*{_P^sA2b|>Q;=DX=et-dh&6Wjx zKJ-F%S*HkE=3*XKIZ1RHHx%iS+_CLE{K(TdogL*Y__4}zFeLaJ{L3TijIVL(C5Rbb zdc>1AC~Iya&-`8mEuu*k?vZ-2po&m!3DK&U*U3nhcv>-8@4MPVX%KtD1Xj;ao)2n2TBz;NF>wBU1%BDCh$aP+ z{Zdwl1FLPu2EJ#Rq=xIIJb(1XLf7`SMgs?!c&DeO=DrTpTrcA^**%7=iSCCw_ zX^<-?sofXN+>fI^x889{+VR}oriF;uWFuVN4fM;>8Ip$&7ZFhpw`vy8i-m0+0N!3o z93&60kG&$DtQCHB{)p>MAF5N&fTdA8+w=hNO$39((7s;(HgGtVYrq2^WaX~mZefqJ z$-uLvwCy)OC*<_=z+A>va*Rs-&6yK(KP`96&67lpa_wqKu*>v;T3?vak8@bnXky)f zWx=ooMdSdG?%nSBLTkxzE%gAf$Ry}79y7@ZPgE=}*}fJEOcyObIv8TM%?+D1X+w^a zq4dWzFG#ycEcUlC6{~HdEjS$+C)O=oy{Qc%*V+2==nBra2F7C)p5j7?9+Sp4nG3PV z`IsHAzPZX%jVYu!%mF~Bv&*I19N`|DA}4j+BQE03UoTph<0}}BbpR+B9+IlSSf8z4 za}6ghtmr;|E4-|`m^|}(7=Mi#Uy;$!kVrWIoa7bDiAG#zbrW$yD2(@5EgSf6t}Cyg zDSBr``DRC>vI;u}2N5xGmLzSlv9${sJFywKk<4g5($ohYEDuZJ*rqg`L|$VzsujeI zGWo*olavO4ISj}9QLWGo3W9M&K_jY~IDN(biF<$0=YQJ02`;U+W)qV;mPmDb0pC3Z zT42jVUYVQ0EF~&5{x949L5{|SJ74jzH4`J^revmw{;fMIbKz5tg4xU+WTtd*68qu- z;7kqo)s>rkZJ0lvLQ>EB9M*OO=6h*zF%gFWFQ)GiSq4^{tg2bByqFwIzdWLODd*AW z`lQ!Bc}EoZYtQXJMYgRruIfPaRvnO+Rz5Vge2;HA0Gu9i4Hwf?akQCt*RY{Wr}Y|r z)8_dY9WRt6VVe)sGq8PHUEMQw0QgkK1BAXD3Q{8+00=G>q?sm6J8+SC3Kj#zzi)YC zcE;Ii@>1&(_&yr~lDcNZywFmSl~uEbv`)Nu8~hr~9UTYm$_$RcnlFXPE8V6}`unzf zKqDFFJ>OndlL&YgoQBgcSa-HSli)~cx&+Vam?kX!k=+WT>zILr4-z-r0@K#{pj1R% za1ftdM7QT%vvYb-`EmL9Gylt}`v(A^FD2x`=(dIb261ceL&Z46NDRM%x-PeQW}>JX z2Xk3mEP$el(1n816F^g6==7$zNLfPQ)w_DZY%r5vzUZeHXK+@haRR8WzA${RLD&%t zeIs!M1->6IBy@GPrgjhPQYiei3yPXw_mkQOJ6>~rKgcigFysW7x$fFEuB~9Igud`t z;*YW;y!mc#T|x4kCJ;=q508}72*}%K`-r$@G+3Bmu(c(hM#R3ozzBxbAdV7&+Uow6 zWjQ}rayrPra-*x1uSXXg0Ne^3^-TY02IMm@z0ui|Gp5!gy*MWZaAL0+EN%$p$VYdw zfaf!*2LSG0t7HQJTh-!~0uUw;r7jC>13feST-q^fWTI@|M2X_N=4?>&E(rc`Th z*mpW5@13_4yc7pN0Q@Qnn`a&XavxbI9{PPuCVfdaX1(YD0I|(WhRl|_@Gh&>Q}^TV zj9Fh-%bw+7u{Go^VA3@xW9-hp=p~3fYBOq=To!{rxGA` zL+|0{ck|FL+k^q;hR_Q)?w$a{fmwI;lG^+wx!Wp{F67k~yg~uCm&cY`1ciVi=*^^9 z>>&*^nqM3iL9O&T^9pcePD`a{4BW#U9%cGjA>;SE<+2KcC_s`GM}WZCisaXO8x! zeh#qh_8nahc1sa!$Vj$bY4rFKU5GiV8Ai3q4?%k@FU$Kk;%RXoRRYe#B#K%u%*ERe z7KkhDxF7}*PiFG6&_woeZyPCX(cm0?m{37=drXgq0*rN5R#rnDwYtqRKy2ozn;u>4 zF~o__5iVWn4NZDAPmL!JbNa^(GiBZzxD{r`yL9*R#2PzzW!NUa&q zpK}Q$vpxvs4D>b1tVhpnZBd-?u@k76wdV0>ezXdrzX$0=wZJpJWFI6LG2cjJh z`({CM5m+C(NH8m)Nl(K45uW9C))w6nO&f!#S6Z&%+s0g7p$xwMR-l?2JQfp34)L_j zMWcz~3~t%)v2&-}83zDfkg4(m5HOcc>|0$qbd&$G_9;SYfqipcwBJ71!_((g12PASJl$BThXTi_a*q*T?Un8`hT)H%<4>81gW40bN-OHyOtHdgm_ z6a&_aa%EB&8P8I(-b`B|fxa*YmBxU)<-K?*oQ1(;7%>ivFy|MZxz(b@qn8%A4x?cq z(fS8~DB?h0jXS9s$Jww6e~ZpwA&weFfg(fODxx>JA5QFfR1$nS|Hr>WeSTod&R*UJFj{?WjKR z-+;T4w!aR1^m>_&$6&DX%P^x&xt^tV{J#2LKjdwKV+bJzR88H#s<+hrxcE*{h|XTZ z0KN7L?tx84M&#y_&oM329*x=$(E{(&o#YEU(M&M3s~G>vrCOgjxetabdEV&~1H-vP>M62t{B-2Uheh66dSsML#TW z5iB{aeo8LY^f3gLG5w$M6qWV|+YqZe_cLT?rLUo__Z|kai z{QM|>U?7gV5-<5YuV+?(BsHOsM*3A~_t5{O@R{o>WHEH&`nsq}wu8-l#nMRRP6?A* zZJ_}kK!lEVEIwaWR)H8f$d!%cm~Z*Hr`Zp(Whjxvv$obSGoroIe6f!%54mSt)l~$| z=b!R8)?8Tf>lNFSsaR9#0kqmZ0^Nk59Lzc)xO* zPxf?uZP%+w`h_dUc4*wQ14%A#I)KY(DdUGGOr;Bpo&PA_`1fP-sa*?E zZtqT3j^CPMnY`>TH{=$9_g}nq$4E)#gE!BBlAgfxHYyNPD-t>(*zJQB$)%sRgJaBo z&}vW}n76T)@6W!dnpye=rY(D0pWd30x!|v>OY;BwFT_$T?YEWNMqJN;+a7_0%gl0% zsIMOyqtyLN1-YAPqDS}1Eb+FFr`8``7o=+>)_k5nUxQ*n>A2A6BW`&n{v=dH9q-S* zF2G;y03AH)U!@lc6hOYVd90tkku>ify+51(JHsuZNhLXYc5|WjL7Ih)Yb@4^l4`#u z*;+G6=4{Z~&q8L+M~_YIIYJ$sx0}054P~s{-P@Jf3HA}yMlDktKU2X5o0Qv$f%Ygo zypO0=Wz6jCWsb`Rl>zP1D|T^gP0tb-SSd? z{V`!R)$bl2CdhC=`C;k%ZcWPLSD&OL77O>zCVNUu?99?@^V~8j<_hy%_R0Ug4KFxG zW1cA}tTG;)QE3e(7)-kfi4|m%3U@fDYH8lP0eC);%KYp1=G!S=(l+j2 zt%>YovYW2YC1!?<{{DORW?kj7((@nAv0#|N-lAh&`hE@HQc%u6%Ez3t#JfB5} zmoUNuh8!4JDqD28X7<=P?;rZ+*OfYLdBMccOh^sW-8ZCaGg_nk0KoStxiqlg=t?+U zxW*2ufuQc}=#)%NSJPnh1(SsU|L)b)52@Hi)=X7MW_>#}sH%^Y2oq7tzcke>ra#@a zPDzB^K;oA(*tx%_;Uh>^-*Mq^;VW;oL=PFjL6$bj0SACn7J4)xns*qwI6}zg*a3j* z5E>b2&SYaNEau9+XmM=AxhmyiCC5vOiCyV(6M$2VDRpa zqZo&BT9iJaGr;$3U)BC)LPQFEtZd2>| zd4G@n_Vts8V;P*nj~;(N8W~H(sP49mbmn+V{;n8p|jHVdOR@d8Cei zQ=Di1_VwedCYDx=POS~Ndg#Uq$R_hO>0azLSC7t5xIpsv*!5NY#(AyI7<6@P?&~_$ ztl87<=XM;FtK>vdubXgJXzhpQrGd7G9hbKvuNBdi%PXLx2{ZQ3^Q0M;&-IR#wU$?r zR`*KFS1Yz?oD^YZ3my^nIn0M%OC>K7@@z63U0pZ~^F^p#j-I^;C>)O1=cp-Dnb#Aa zUKjC`nWp{`h+jlw1DL1V6f>9G+OUYxPQzwpWo3zGlPi~_%AAIuc)qcV;(cX0bws+g z+Wrl%8~#}dGJiiDsQb4@qT0FYK|&VUTr<3RoUU#G|9wi-QN`lyN0B!X#&=#N1BE+I z8_FCGQAiXX7qYdhG9*X-5i=0uJV4Z?lH$a2mW$0Rhdou~OwK&p`MG1 z+lp7NywzWy_H~8aMZg?!I93;=)X#mJPGq*w>S2Eh<`xr4#+1;2?M>r}MP5PS6#Myv~>XP9fqdI<1wvgsIcc1eF%l}E`+1;-7(Ks);m9*ASdKnD{60+9s-4j6-EwcEwz91~L z#&r#L4Mr;(36ge&8IUB{k%q0srVvB38wviM2GNd7IvX|*9D&z5HZQ65>n~Ao7+25$ z#GJ$i?n=72m~ww=KHnM>hAd=sv#1UQI)*d*F0sd$oaHEe_Lcsm+s@SGMuBbk!%nD1b=U z)S}?}MrH0Dx-Tz55rO||V{ezAFD2I&J!u@Ns_yMo9oweGzy9T@<<`LUYf+R9`8_w2 zNx@ZvQ~s11{a}*9HU-0!aCj@N+Pshof?_rrHp-0ccSc%<;PUvu)IR3Ji}wS##aB{8 zbk|KyTig4*8IkPv^;V++z$LyUppbYhXuyQjL4Q1BKLrV&o%IV zwz=VN;a;Jv8^LeI&I|eKD#RfEX_wm!TbnjdrY$1V!~OeCEzffA2I*568yboZb76J& z6v+HKajk-DaY+^2FP~LdILC}g>p2Q>V=&^ zw7JPdIY{9dosl!F)GO8vM6-kGwV;uRdfcy|rm`FhCfi`nRPOl2&)jJQDw(x63aSj) zH$YHBh*_U$b-Xmi30l84z0)=|PuJ;OvqMue7D!!iNfB)MIB&K;G+@v-Ug3ds2P4`7 z%Jbd~H?J#I{hIsw>})rZ`i<(`+BFP{GB6;luZGpSWU((jU2TIRmaliz;a!zdO{oKn zZNaH>shF`i!p5rB4?jobm^o}pVm0Dt@I%CfeeJ5q(E643Y zYU?jk%Q!XkNtWY{$|V#B7}6K)uFg!9SFKD=x?~(l-!K+32@HhGJSoIZbIJ|nLVpeX zd6RdEIh$Ki(XhLpEEDLt%UL_<{lbx2Q~)ZjV=*fOJ^5z~o0Be+eO>UOVE-sx9LWA! zxiB9~Ca}2gb(*Q>MfkyBA79j6c`+Z_8W(KZV{W1#;|F#(K-lJmNBK$;{pwjL@b`F)LXh)%I?^`Az8^u^!&aLDp`KOh%hlRu1IR!eTiB_1 zE_*Hwb?Sb(cW-9gT$tpnP+TCIjYWLgRwSc=S$r7I+tkC#t0&sz{M>eAeMc*}46TNH zh^?j=@ylJqUle^frSDVaS@&$yKc9o*S!(b4|$yt zRC+-XYyG3(TFOjvZxJ8g1>@IV<%vHxdVZv6$Zq!b&|l~KnRXWVJn5(7CdqB0_mAlPjku!mQyc2n zUGEM^220-C16ZnXWEa;tmcgr@AiL{Y^48^MSvFZ2X?o5Z<#PRIa=kXbJJF1%V5J2{ zyRLQ@zRT0MH(cJdrL)&9Yx?)ZBjHvJAwgPkXO%)oD{marljVoo<}Ys|O-_P?=PO(F zozPpzDVY&5QpN3h!;S5?b*&1x;}A2}Z!X*K^Ba@)q&CZ0M@4BR>S_|eRb zUk1;^XBv|W@Qx|)vL2Iez6#W7#{~N>pe~OA~sj9_Jjwj!;y5()UQ36M%pP#rVP7zW1Ix8E<91KkK@8 z0heS2?w#uly+LXmyOQta(3@Nxocb+#<||ZDtQML_X70xue=Sg)+PPGhE`5Bm_js3< zHcRFEOz}v)qk}sz&`^8xX?C77r(zRs-%Zn&oZ3=IV>ip6MMqOm@t;Sl-H{uTC+oIs zYA}w3e^Z?PqF@&30*l|_42wQb&9!DVlLxcfZGUh4(=!+_v&{%W8sWhm>?1eOO32Gx zVs9-6VBeRwL1W zlz35KULqnMOV~<$E7Px*!RHn>02du{DG%sMhx;p)LmzKFzBl53ZDl{~vs(;|F*Ej?Ss$W7=_rdow)KBLBeRw*dMFta6hM(|`D8l~ZNN6+RYi?IFmAxWlP&+gi#{g>#UIONm>t%KJaGV|hI(VA-)@l+}PUMpZ|*cmEAabt-=kb7{2A zL3@oZ|69VNIN1AVkqDu2Z?|Tv@)05IH7<6)26vq49mlP--aCbiISIq0SX)s-sHkecc?2_3yYsqXMa!*_*-;r6xyB(fpjXdp<5k2(xW|+9y&eK`YC{}R>F$QC{FXqUH%k>zC z&7WI~>7@Ah#OZIaRJ&iHLrAGw;#RR2DI7)-+tXB!x>{!UEMt-o$wnZ_@pH-RY59*N z2G4eLv>-XNQwiivIf;BkuRk<(9ztuCOD)kQcU?c!vE}2E#a)BLz;7fQf_|^sSMHWcstnYAaUvWJC z#yrm6Ka4ha+ED(NY621-$m{kY+yfoAU>)MtKMr<~vT8e-;ESAC;Xy1qT5FiO!3_pD z-T1AvTBZxSy}BM->34aG3sP%z-13x(ar?F1ki29!o3;XY?e_lh@06xcWF^h5u2lI+ zW*ee*2Uv->zXJi1QjpSjF2ug+<04~>j0`|)n%)T8OHXB5-6I3=^2ye5H;3dHpq4&XU$m6vz^D6}F;5 z`>q>G0r$Og(g&j#zP@(JL=C&Im9A}Qq?oT&#rTnbed)U#pKEf{vn1^RU?0{M`!R?W z4t~et&I`-WcO~1ynb;Qe87sx8Se@AjE1?1FFMADbwW~SVSOV*8iNe@-W2SzRYcv@8 zIPQ1b3n4TV=py);rT`k&!>Z28JZUnA&F)8?2B>E6O)kfQe>A-*Z%%40Xw8eDVsj>C zle>x@>Sl??sS#m}EqEBAEn-tOc+Rq)78sB)vVjhL+oeKe?QPYNvRZdmu~Wiwnz|-n zRZrgwh$Lim8@n6+8xhEnzwV!4*F_4`3$Ci5XybaAH`y7cQ?Y=T!I5cx5 zgXi+BID){$t2YAQ`5!7EjekL0g2JXeOaZrpH|I`9>b>JAHuV{aHfREt%$fI#Ba;KN zIV6rAGJLA1sq6TKoeN^vfjK{Dt`RK8h%L3L3A2R$BO`JjD^*{(&G!j5?@1wNsF{Ta zD#$75zZBLso#aTZsB=H$Ka12Awb5l*esZ@%EgJVV*r=pJqjB=5e^uutLv$k#0Mg|) zISTW*TDDQBX_Jpv_c8q2;O}(N#NbjneNgWoCB%|lm8q2ADw@n>x4nK)7o`7?F-sY5 zg7L_qHGXCP9P5j6#?bc-;IW-|77q2jk&gmyGObq~Tc1(H_`|a2k=xuJx3yAi9RL3_qQ-m(WwyT4e2w zkSBbZ@L$#-GtR?$9HvcMMjzSw)y-KCct~?0zOOXEVW*i|P1}EVuPXmmxNbwX42;^1 z*s5|dF$V)blvb9+a`b+KbdgiP(AL2(mqWK;7bx)<$2d*-Q$3YtI<8j0U2f<@`CE&r zJOKvGkt~-a|H=O`ih8hT<*Zq~Ry!)~rjxZ-cuc=#k%+lNwkzD$neGz~Vab!wSMS#W z5Y}CB!A02p=%CkGO_A^)i`x0{QW@o!_cwcVg!weM2d>#qq?3W{Nya0u;RK`rjI$ksI>SVS} zG@8mWD)1bM1Y#PKV@dMv_coT=GUC7$PnM~DC|7XDM06KfA#gxAurF12G{7ccv|$bN zMpF_)Lq!`=>Xh zLss5d%#bVLWdihma>PQ{qpvN!XNx`LV=3h&ZQf5ZlYA)^tN!o0X0GEU9FpeeAP0b- zh{$ubwQ+{i*fXxX30A4gdX+jakkVs7OzfGsb3jo2UWOI_ubFa zUvFgN9_3<9(A{C=@0F_KytiL<$Z%^kUwU)jKH4c-C2QHCk~b*XHZ!Ck%ORcPA9NQ> zheVJ3+wvt;OI-{rme0(}Gd1Q9iAF1BzneCo9a#@K0L%=e1~wg+X|XtKSrnsp)*{N> zD9~SUIPK=;Y^UFui}CbvUL88du>dK9e!f81&<=)y~HZ|e+OkR(b)|#z}&?`oKT_%Pjn^cbI zI_0(=0u*$pT^lG~GD8L1H1C1Gosk7`U%&K3OGdcLzo)B@wCBztF${r1`41Xcj+7&6 z@AI%*RF07*8k(x0Qz--cvF*U>d)GBJ9PDnA?f<#E_jFtMY~Df`u^mgGv%T$;wM8>s zqxkiEX8DURBOPw~cL&C18aI+A_gt|Iu%lM-g%PYDwuAY#;-?b~4uy)ctMLHUc8}Z3&^(fDar(tW$q}wm(y75-YhDm+Uz8Q82U*I*Z z5Aq$&qhaaHGelI%8tS&rJK=}VzuUUo!k-fvIh198Uf<(nXN`@!Q!Tv2pwj>uVuG9K z2MiFn`&ek($~7}t?nJW6qCSRW?t;m}yy%vl5vwQxuB$B}f^wAMoQB9q%TW@L)qaOK z8NCA>{nq(2<;nv`Zc*;k0|2|qAv40!fjXf)Nd&te``d8kG4`6lzAwywt(n@MkS1B~ zqYwplg+T5!_a{e3aF?I=)kOXp6?lD>git0O0H#0Gy{L+M1kGn!pRYi{>IKY9dsqev zh>_>=HL7ZPxaU;lt;G5eR8ylBlP>+d-Myz*bJAm`o>+kqXK_ixtA-|jzI5k*bfT>& zuA8xDM$z{VAD;9YSM`UVBVoBx)L*&_0s1vBVGIU#9jcVpkXA)l{10_};e7lWlFELV zh*oPjoX~Rs&@PrDw0EgGM!3pgf9D-DydC<&N_*A-Hg7{J@5Lf=t1-jwn$d~pu4&w< zCAC%PT!KRBm0#xjq{JqZR@ZQ>m+mW^X?F3mXFeoh+AqBq)C4y-NNY)z9!C$}j}nv5 zG+VQmTG!9xv-%{;mnEt>iV}6egbfKdmgKptZS3`_{3x5-$7Sd|+|l5-x{J@TZ8)MS z+&EXWx8G3;$R=)d9Y4vp%ON?E2J;>h}M{h}g+J_Yzs6^-71cSkU$(1d64a=}L{ zeV95UN>10bg4VPrr0gW~l!R`7CyrQhKpE$TSMT~74?TG~6yLizkT_l5KXX>(d?7Yl zq2jGHMmDBN%DXx;Cns+uxL45EY`FYFSY%>5a+#2u!FM&e`5 zcM9mJ4`-FSTrcR|V(#Teo*n%`GAo7Txgh6}*!lgie+{QE{&-wAf6?r;dkKWAfF#v z8l~j%p?$4P*AzKA*zrM>GU?oPZyRku&IN8QL``x21H@tcy&hA)HKl8TYf-cb z#!2H7=ihvpwn<(oLS&fgg3yVBu^@R`SWk`IYy{+IGDFgBr`e@F#Y~V-M2;7>}Yd@zf?(_X+(DK z06Zy?zbAQr!bi`bAKde0!S8Mxd}35i*Lgz<)AL>BWnHA2=xL6dyh(CG3WSzHLi(WB z8Y1wKRO+V8Lu#E`u1H~f;W~7)Q`zVSe(e&+0cbGYuW`w4!Zwn+lUY6RvekI{ucz=# zU6|q|Dw@jn9?ntN@$?~WFI%A(xayPrMtbzNO-Y*0GJ~-{=@!Vh_nILuF zPTpgE&1Z1~Oqldqa_PM|R($|)P^^+?vCfIbm$Iz3Y6Ifq@L1dG?6RwwE>gJLPk9Q= zvyK;W{hC{6IE12hJ(BvEw@T&P#+R^GHuqIu{dr4V!wtXDyw(t?RsxaR?AmCvmKR0* z*3vV8duvE3bduY^2Z(w^!KJ@CMO0%a-iP(@i0kWqb3;zqq=^nyH|L6 zSniu9dgC<4d6x&)mSPSEfd8ZhuRzVGJ3a^ojbW2-)?+>yr^!Z(stj+FFq~0W)VW!5 z>)WA%$VJiUp*WjBd+eQid#=?A{w^oY=O|Fodr6az>mTxW z%fQ5_;yzXA#+V)De<6_>ZQQ$B>`r}4aqQPztIgBN=rm(0$N4_pYw2iQbE-3Go* z*p@T6rmM5Z+~>e9eO#VtICX<#P6!*axZ_c%XL8P_Bc&>ci<+?JkRJ_e+Ea%9J9RY! zLbPzTy)En{wrco|5w~$9s6V7q=2*1?b)!`ts!lYGAx60}w>Fik8d&5g^y7vGtUTI0 zyt3?ylx`nv!uhxYj8~7y!5M|8bt-mT^EYvL3%?;I#|6P>=qlvyx?I%j?t7 z!=6R&WT3uTvkFqE&FF}$>T(@U-#3AlaR1FMQO&5BK>(a6X21t7H%F>j!E%FO(I50~ zaz>2Qe`k0eHS(c3sCc1z;w=U^<*#wfOrE3>*L_umM+qsW^(AZee7x(<*)MtX^9$yI zKF+*3*?#skicTT&f1Rd#E65boBXrZyJ0)Uy}f$|w}MS6^&Hs!smNN= zpMi<1DrkM29}!rsmQhf&%CXk-T_O7f-MXN))~{W*{DTtej~cXw$=$$nOt*->xqF@; zMQ?DQF0GA+F0R+iYdjey!uzZt1%<;5RzK_qYGV9crQq_~HmJ8d{OD}m2t;JP)lPLv ztXqQnW01<+LW}Ieb7!M2{qf_yS+q6jOx%-kuu{b4R{ig1|AbMYNjddjMtpB?TPnf* zOHiv!af>_Zp`D^b*S*q(MqcrqEPi*}I4EiXd#ymqGUPSRCb_@`1h;LNB&Ff5XlNM+ zgDQuHlji0#~G4g6f8O{t=y!u7o!RU$%?;j+VNni}I7 z5t;R4r5pTHm*0Bk@=fYR#w-%BdVj!XibnUkhT_)(x;IB2^%Aq;>=NPkT;CXA^b&Z0 zK`|LEs@sFw6kF!#X61!~eHM35%NrlRnTBem7mtRR>0k{u32d(NO1T>u3o-DUUG?>c z7!xb{i!y;QxSPCDyE9rHi;&<=REo)K+EJdJO0It#AiSlY@RdTbra3mbVGjj*q;2i} zkuwY-)53wDW|9*6&xDCh;4NB7OK5)tc_A!BgD*1VYX32jpmvDpN4uT2gw(l@2Y zt=qj1M|j{J=ikgAIcxy~C#gs_NIx5+fsczlPqA@)x}D0+~-HrfiaQFc-21O?`6rlE3x*Qg-{gEh&{-%rBk zB}%z)O@1^*xW&`a>IQ0E@=|EKALo>a#Oj03r>I>jBf-uZem$5=2%FYNC)~lr0Zgs= z+>O{jQ$>ACV8!Uf9!D#ZY5OGj`9$O6*Q(k!fB&kQQnolU(ddmh%~29|nt9w^*&nTp zeSv8GI33hcy4f#Z90-CF!Xz`yWn?q;+FUfw()j*J9bX< zSg5w~_7Xb&uw~N6vA^Ajrl)zqAO-e0zKG=?w3DTMv>^-_!C=YafD6lsF}iW%V~O$Z znnzbPKO1&f{j92XF)HijpA; zaVyu?IJFp}qt9^->fM*}FQQ?ube+?_9LlNuJ(Y_M0egXq`*A-4bBvG=p1MJ_C@k&+ z0Nxq3Es|bxHVu+ zuB^z<3LnBCIIg=w+j2P%e|@L5#eH9cJ}u7%z&^QS@`E25A3?f!yUo8xDSOf#i})2Z z*^AxyUCDU&Mcit0!kR}IgpT3((inG#3*1U*0pkL5YDXLy#;QD?lup-OS3m!Vk*@q; zmwSZ?$ww$lx@`AQxA^fsqsaq+T2(?pxpH8X`Sjia;Ej2}DR>*HMOW3ueZ^RD=|(Z)naUr455ObwPUgpAD*4`@%&9++2*r^M=Y&B-8zWwCER76)nII=krWaCvK1T0~~#1p7T56dPW;tZGb*H7^_g4%k%ngp?-gI~J%3ypKmy*M*Hk zvT&7ty$VojSMY0ju2eNzPMonfmsYQt5Sl znZIUF^taKvsU&W&M4k?h8O3#{M|-0qVNrzdY_K$m50?0kqBCcnyx48?C7 z`CqJqNSB~M3pGB1#SRqC=>a0)pJo^&Lr=l7=jPASohoOZRl=@#!T@r5w1wgMYqFnH zjOe?0y=JUhg+3-D`UJRwf?Vp0c_Nkm{g6|{w=*Au{u;3bBIE5w3bfrsaE=^0pnghD z5+*q8st#QU3E6eDX}GP9o*%jTv2Zl>GD$#`RpM~}UkeZ(-4eTY{%ufDLDpG!?_u&J zyWQlpg6y~1nOPf%RwH!mohyBwY@3J=V>A{TKE~EVtzONFAc_Sn-~aq*YVTg9mPt$8 zJIQxmy_j|h<*_jas%`K9&&8&Ce$VobdNgkB2qF?1IiSqF8;1zd?@;w^-aWOr%Adsp zZC&OGXw^bA|5!hI4x?i=-f6npnv>1mp)bek`*gHSD2lw1vj_|;+`>MkAnC(e9yYWK zle|IGgCz+CvE^UOe3BE^Jm@Fgb!t_UXJ%?9t1a3Fa#Q3R%cUFy-dRPNhcCCKXqBW7 z@_*BF{kjPCT}!#A9V%VO)_7iPRflD4Y&8Sz`JfDdV@bK^Y8AmV~Udam4zLb2#6lf4TY7x;46K zkE=rZ?jbAj9P9WqnWFHra8@0sieqoNy55L95O#H-io;|lhRxe z)EoCM*1`Wzr%`_|bL>?_{LBszs4{(9fJWH0B^bcN;+G3-hbo%lIb!6C9^bQ2#l{@> zMnbXVgY+EFw>Lj;4d@p^trp#cV6?MY=i{2z_T!J3erfrkD!7L~KKOCKlKhypD$5nUfsH2cmB{_wZv(O2RkaLc!g(F>}f}Im~%sGYm^|4mmDnCa0O1Ic(U>?%(J8`v*K`pU>Xcb-k|V>-9!558RDa zzM8c-2F_$$JhFT**oniah$)#(AVz?>!gYR$<1FsLO!nzqLkv+oFaj0}IBRWpnVL@Z z)?-G*Kk4vezni2g07}PltHy_U8`KYRw4Njkn_0g6K~5WITlmNh(1j;=?Ls&M$JG2w zREdSrapgQ6gpWFz!q0~KlcsrUKKC!LGkt1@z5C87> zPTL1=Nts)zDUu*2#Fp?~E|k)wXS++UNr+W1jgT6sgl%-b!=8zMB9*CrkG*{$%by0( zXP-3B0ri-WM&-jw1qQ5+#%(SjYdvee`v3MzYj3kYh)p=t6ieNWGbW{=^`0YywH3#> z!p#|lS~5;nPTLaD{9@W}z!v*BH-a3*aUG zIYR5}gnGInC0$;(z`#Y;SiJYY(RU9|5s1wTZ8kR`zm{CvhX(4#jQGlOaB@Hq0dVBb z!{1hn61SjXl$=_}izdSe=i2<^-Fz}-v->yuV&H217Ve@K*}K)NKa}2i5ZiIE#a}LQ zhQ^5c7VzkeB9Bl9(*0LA}h1Z(CIRIQs_E-QQ3iL>2qsPJuT` zd?_MKM7_xIw>CA+`f_>LtgoUzoJQ!qvGi*x0>mb8;ws^Hczd-LC}tWrXg9MInY&jW zG%EzBH4Y3nEgA624+Z>7=~=QJuQ-<0p5my9UR04Gb{kUHJTOco^UK0H5sc|Nvu7b? zdtLVOHUBuNN%W!+$#_YgpxNZo@ay9fK@YpDp*qQ#Qm1OyG7z+k+` zGmX={a{*&`L5_5Wo{*gU~?wMg_@NZpVr`BCFEu&|X-_8<90A>0Yf*d6l~& z_?0W|E%FSa`0--NDgqj4!L)I|-n8cT2Y>4p*kI6e;)JmtkSydw$_S_#6Q-R78G+7M zp0KQ&V~1On%;$`f07b|zMRG}%iOH|N{W9hCaykAGLw193a zFFlySwJaTkggjw7!hVfZ$Y4E|4q%_)3Wl-N4$+>9!E>W(=|}<~(X4yRG<7&qCU!Xb zn4vu%zS}@Gwa2iicElT~2`1$LW+$X46RCtN`sb|#&(I0-)qnzAh8%Xvhusi3?a&x(%ep!_SW9x%AKG4YT(@;*`Bb!;22h6!COxGAq5Zr!^}s0tiJFY4Nea;P&Z% z31gdV{8NvCj2_p_9TH~lH3gy7w+-^<-f!l;BT8teKSBi`$jMYlH^Pm*w@JXLsN^4D zvgJg7Eps0n-Q!ryepO^>sG3$!Ck-^4l@3_sXu%v$9GWh{T=m1?7Hmwq{0>HBpz01R_%I^XnDn{ zcI!3(MzC+hjInQ-8nbvD*h^R{9BF|!W$*?oHY>GyLmMF_&Kyr0kmqb_=! za%`+^2@AOr*_{~s@}0iv7m+KY7tHcmJ~-qf8NL2hzF|vJr34}CWZZF`-Ftp;dc@Ze{slxrd{K`wm-vw2u>+{v<(sY5F=oH>KwJu zq9+QS>t#8%Oe3*h2UMX(xBlmBdUN}ouYFz`wo&)MvZ4<)YHbg&rFN;po~d^pSLQZ+ z?$KKbuq;7?JTcILwB-nU<12qMu3r^8bTo9P1bBosS3n90+prYoitE@EgD}kDK1y}I z)e|f%BKCQwViB<8^#!i0u1~Djw1}L#s&I_C(wVx)y>v4#&!w2Mbt!)hSxIfW$>Fg- z1ve1co-QkyJLsiPFn~OSYzs3`VDQBMw27sd4h>4jQ~`N&w{$ISgi1LG&mAqvaTsPF z99HppTD&~m?}r~NwR+;7t`oANe_d8J(eXfq<$m=A+=c5q<1PLJw7?`I7A)cLc#|RR zh$oIz1Sln=+~HQ1S^otQx+fxoj^hIz$Rh6>cOK92+Wvo8;C>n2eooVDhrWKi-CXXUeYJZd~BKb#Cc+&J~_kZk2C-@Ej@E9}z(7Z+}C z#FOFEyAT%$P_-S;=Jxn@pSrZPU*6GA*ArLc6bARGg|oF26aK*jc+7hIRNcByaIC*? zA$QbDh~;nkpwMpr4KneXJ)GagI}Klj**$>$P2Ffl9J2&Cl};%+#}ecLdGyL!qwp;Y z+sn*Vrc3rkY(x?UE0qFigB zVJK(!So>xn0>paA6z9O0&Hoh?_1kw2NA;6I$02_ zy`U|{Gj(q-ac0}RGL5pgr9zIHS5uGj`9M94=RmpO@gxwNR818sh`gb^d1->!$)uLnBlG2FliZ;>I@nlK+M1! zr>=F!a0B1&(r)#5AHy{>!%VfY>wq|y&`_m2MSvmg2W`!_NkgJ4l< zwuUu1hN@tEQRFIRYads}&5e2-KS;=w;7yK0m~zo}J~lw(Vc(F`_5}T!IXMXo$=5(> zC!b#k-#=oE%9!>cC@d?BWT_A^Oj48Vo!+n|oZW?l-CXppV^VWY3&fyap7-^S!g)H4 z6|bGKh6fH-viDP$J}J7raUppxt>Rg0t-nUvx5~u8@c#jUdpCdkmFHOoCg+jl&UEJ2 zT=Xl5%3sZGwQJEgCzs7!h{Wlxc1>Kf3Oi%~b|{=|h|jD*YUL|0=Do_(r2%`Rn@`{h zr#+7xBdae)X}f!n;&q2G37`PU|9E_|n^ms=;FMHdOr>|8U7|gjkijYf0$gBEv&(6x9HS&VbsqiGJ;VcfM8$KK za}t}a7=BYx@0-Gn`?rmIwm7^=1065S;-olpumVq)6QEj0Hcs*98XRFvvVy7|&A0>v zyp=_@?E#L*tJVYRqXXbwSAl2x!B`ioM285KO3>Ydg5>C;cv6OeeQo4Awi z@K&v@hIR;!S@AXTE6aOOV3Gjq5IJJ>_SkW5KCG_<56cy3SoTlU*#~6VY_+UUmtLwK z%)t`2d&Yoy(Jm6qw`tE<584;piWr7Y4ny{!x_^Hr(%$sECEj*lYO6u^4&`Yy7n}aI zCp}yjV0MT{@S4jjpgIwFA% z7~G}>0t-v-iQoW~bIC=3&`tIDws$;CB6{*eU#F2>mt>!cAQn@`KEHOAX9gag!u>Y9 zV22TgREegtfcXM*yKQI z&r*f1h14~#7&TuGA#I4FE@EmUc64xLs)@NL;1(<056gXcE+L6Yv|DU9dw57!n&Vg4 z->~z$VI89|VltYX0$JVRoqoH$T@WX#%Lnz6bW|U&ns!J9IzQyG<$Cp@QBHWdnR_!(2F2J2|R7qhJz=}H-dl~Y zim8xO)AR-fK`mBDPMHQs_~cG#(*rI25c77TJkLTXwUUIY}Qo#v|>9muKw=|8+T7PO;PL$gI4Fs#C?sWTu^M8_& zH;b&x*Gh{`y?g?Hghxyhga3TYkoZ9({`O<}C8I}#w1r1>+S(begp^J!g?L2o(*oDl zFF8-#Q&RF$$?W0)+zgeGD|pep&w;k0%?s2^owO^dAx21m4EipkUOuHofpk7d>^by( z0b|CjaUXw{F@{Hge|;#uH0EUwY&`9#>?5B#llMs7N?fSd7(!AVtBk~(^!!sQJq}Os zp#wd|+#$2ecZW8&_H7idYkKIySzI@3QDZfl*nd2yU<&V~&o`;xNG>$tMA(S8N%oTv zy@c7F0>GxebaGVbe%L;XQrMkO6IMq3S&b2n92zyjLqEQs_;lFFSycT9)j~3Ga&YZe zm5PapoIR7yeTeeh%111zUwhB90KYB!Y8s@?W*$7XZluikX-MAho;fX61LzAn%<4B^ zmw?>Krg4ZA)Vtxr1Hm6}ef=`mHDOGukR}H88pUmQw)4h;b*T?t$M{{<`1rPOK_aC) z-4najuh}Nv|D8BFnPpZKjO;aX`@#_I3hYv_2`pSu$F4BI_+@R0Bs@g6gfqATQ`}}$ zFEWBj7#MZ3vs6Gff#pLVgHX%ML}L;o5yJL(q@7<*JPM8j%dG_sq^fyepzNJ}A`vJX zx7%j_4fxF>Eu^HU*QauxZ-2EAR$#tr*ie| zrlwZWcV|uLHaM3*sM4qQge3<)CA@kMfA{>78Hy`bi2qeC2gU-+K4kxQ39(mqqfrd) zl(JB|t+9XOKKkn<3D5dyd$XX?%XII?{w1GVx`+NiqcX;h(O)wFS-&hE21U&hPJF86 z=j~s3&rqkBgxhD&5?iwLhv!pNTR;phTJX!y9$jeDKU>GS>G)e|E1Am^B4JldXV+`W z3MYVYn+K_>6I*`t=Q65`UzzrbdjTIc97$H+lFK`S1OM^q`6tTCYg$VNdN5Qi@od>} z$b?J9Wce8gtL9fmZE~HMC13Ndc#rIU3_pYvAT>b}B>b(glmF(ml68-^E%P{8&UkZF`K#q8H^q50Ij7>$Dqf z-gDkb->ZRaK>q&x?a?5;Nl*L&AAW%OI8K~;bWgx~_X5g8S?&A*v7_)y{-fI2oxd z7ens~Nwqe$x#pj1Eo_6yy2>7M?YZx@l$*XFGY-kM*;;{isg7q{@jIA#Q=2vLb*=3Q z%1g+4cH5#|7=7lx(udo9jWK8XEpOjyHVIX)F7mJiqA$2;Em`UAoO%vyPW%D4Lp2Ba z0p^*1XSfru`|673OkYscvzEKr)qigCxGcpd`+-%uFQofkHXlJ$Qh->3+IF{^&c1u* z>jeYQ1)#Y)=oybRn9sjx-eh`dFJRyNgk7f9%F(gm?QmBWca_n63@@qG3y z-5xlf?8J+KsJD7_mZ>7uDVC=8Q}ZaJzs}PhA~|O}^X0An^OR4h5@(M$ZexXZl-MZy zn@FFw#_c=hgtF-*4tAFzyr5-c%=bLG??#SSfKX$q8;_5a*4JCSW-NSQ<@P8_d!WXN zC>E!3DZ{8wo=XEXc-=i`*O3BYqvubKJ^1H-cDgR7!D;9$0)Y;b3nmiUMpje==-y?( zS=d_){o)>8b)vSqF1#>!U1009+l}`G!M+Z_-5ft^;gz{c2|RkKG`HAI1_aJ+`AP<%IWkuBrU$Y>y7c?J}jH?4?{HW}+ z#+T`kY*k=h@L%E3NQ^a4!t~7D*km;qF#Y|xyz_Z?&m@gWh*pdh+o8r~x-D>)g|f_y z9DB~XM^#AF?q8N7wLFV$omN?a#-qyVUr#=)?EaMg=A4krp8ym*RD=HK8D;)_P9FBixSS`&;W?l-(msrP6=_H6{@|HA{T4xK3Or)zR!}#I-fP?cYZ1VxVBhpoyqzx4olvn)n%7cuJ^k% zPM~b%Yu$QN%o`PDU&D_Gj`&7vyg8@d?FY7fyCBPOK0e->Q}2yg#1#%KMz$-)_@YIY z9_Sg`EY;g-M?7i(_QMx;x04m;*HqlQ@0J%!c{SoK zakw!j@{ffkXVG_6=8^F7G#_~xZH51MnpzZl%ZscRyE}?~eMi!--wqfOd8>Qy7>{L6 z2NewiRdj94hnu)jX@=yLR5z5TucN)d18j~_yZ#+&?}EBktYKP<$NuOPVq`7A@PhRs zo>k~|_WbFJGh0jo9fce^1@ws%xP(}4Jaj^8b2W=_mpm}2VP#~lw|op|$t&o8IIo%*Z&m5+kC z>GH>?pt=wdOt^%U7ovDd=tt6Q@a{ZnXes^rO_M2_f1T0R@n31O03MzYr3MXTeTqC*uZPm!h6C z?132R08k%#qZGmTSbSXMs7T>o#=%|NX65FB>8Vw7D@VKmww;u+Xg7UmK#{kc#tnEL zU}&<{j@2QRb&tf!lB@t1MCV0WpQp*Bpa24e3(Ghk1t7yVJ6QIvj4c-Igj1w$-nwPf zFs43x_jjU|}T0QSb_aZK9=0{~6^Gl(=m3otXg{iOR@o|4W1wJg^RF*U_Ca6Ad>nWgT*z>~3z zc;!R>h6N8qv8fK+X{Vhe)GiPmyyx5~Q>7Pqo&z-d{$^JOwq&#fkW#v2bf7*$QccF= zX4|;`D;E#@K!E1?6+8mJ6eMbZT(C7gw;()>bj~)hV;D{Y7R7(QRS1eGJY;HU4F9D& z1XT|88?tFZt9Cwv1B?6IM>{z7cfaK5$>#AiA9g<>#$`bMI=vJC@S5^26#IUcq6ZIo z3HA?CaDOR)$9By;vchC`YlIW`j6v-vhQX=EC8+L(r3)y@S>T*H_tMi^;DFlgJb8p$_i=#1J4T8B(682D zALR7P)6CGkg@GeNsLRiv?3^iAdmUv96pq-ZNTf1qUx5HPh~SG$ZoxTROw(fG>FC~j zb31@IQUnfD3#sQ~llth;2=1$vV^5Vjh6lJX+0Px=KHT`Iiu@^P)^D@)Lk2g3nEb(` zRBP@{XIO+DEDOrGp%lkM_F@Ndt>P>CSr$I~z)NRQsU9SKlbB09C3t#Y@H`MqIE%{n zd9pvPirN;a41f{VI%Dz$=I6Y+I7o zF<&F(v4C9mRPyqYxNB}Zjlmg^#ahyN3Z{0e71nF2ZH$48Leq?@+8i8(|Ce7{Vr0)3 z{t**Y{zP>avpH%=Yj%fzaP|40_wu{X68|L?B0N8idsA?xtMmRQ({=>7u}FlC#IpK# zv4TB{#mTf3HTf|waQ3j1dA!Lfr($dA^yqi@MG8Crmq~llVJzKlxxNj6pINY{qlL=F zgOdHk+;fkk75pDD$Q*9a+3YDb3;BG+){_J!Dn*{VN`kcL4>=18uW0jIv0W`Q(t|7L#L24jn4-rg;qN(q*DbGvB}9 zTljX`TP%-@jz?uC5b3K9o_bi4Q`Ubx*OrAGFQuddITrbMc!9tsYDK*%a5{eEB8e`S$>HZr-h??{0d;2SbJODEC`jo6|ZXCg(bZ@?QQ+yPQM1kA^G#p&ewy& zuUu@dj#Vks2_U2oH|R-pADb`zDCz&8$H{#;oKneoC^G8p$-z$ltjp|IxP7rUREnL` zZ2>WI+HWvSU3yo)g!}awzV_XZL)9<@^<+KoVZYuoRI-`e*ZJw~jXkqW<}LKu>(ceQ z$tpdQkw)N(4CL6LYumlJhoq*q-eB^NUlMbFl_U5A9AnL1$4-)8eA2ygFR~(g*I*JF&!JJAq zzTdPC)0oOT&0tU+{=_%>8x_?jSlbhjz2}baYTZ1Tk(T(RE4!44khe}L3Qj{6WQOY& zTB={YS4q<$ZV#Jov#sR1BDRPbvdKED!H&o#L6gVvd<&f^rkyp`$(mT^<36d)Ft4b& zk=Q@Z3;W->ZI!6TStf@5N5i`~1Y`AOTTu5lS)1*Qr`lFg2NWYJxwz7;Gfsq4va*$5 z&kS;2r+~Nj%y&!j5AdR`YwC{Z!LLB0cU`;a*d0T$*+MeOMFjLfjJC#uvRZ&l_BKoryXlK?_9K)thQ$quTjhvB*g6R^ zys7@W*_9l@@InC6p2&)Au{SAX?{<_kr%J%AvB)i|erv@XK0SSeS13eXJ1vzmiiyqf zs3IW&4xgcLhUyZy1I8O0DJcb=1|md7hXZ=V4TsZ=b#Cm?xvx+e^f3gpLPEAT`BKKq zWFShcq6*8d@;@wJ(EnL^o(oQI+{!%GfM32b3S1F(!!$=tMC{OdE3D8YBR3(lDr)ji-&CpV zdO-oScPHOi4Sg7e2P{;;KY$EswKmks8Ge}67pY7Gl%*-eXDW$Hh)75 zgPqfF(-1zzTyxN-)IxoBBfyAqz$+rWBq0{#=F8qGj~~+27b4_Z#@o_2{gj ze}0Wy&BP7_x9Ii0WB8(@MZ8BJy~+;Fb(<&0--FCU5^(2Q4L0Sv)GnAhs}O&QT^w`q z_~(jae(A68ntHe3Kil7&{bcs`YT~PQ;q&p&``1mJ=6&!Ho*dFjRP4L&xA;UY;#+ej zYKZf#nOV5(E=|z9@RF<4zJSrEPj`Z6jBx4;{!QlL;nr5315X~!f<2H}XT+I@CBo^2 z*qcC$qqw@1Z}d#HwC0QVF8<_oOYz|2_oe+0Ey!2^0V(?I6*%)ZHODME9lnLH=OW2_ zP;a397;k(6^RVBK2zpgV7`(A1n|W*fjZpnuFvJ3Uw~JPNF^Pcz1Id`3Vwf}KJ(rfS z?bF&bf%~|cVZu_u>*lr>)SJ|gKUk|bkL)Ji{wMp$26-AM{m#EF1IS0g4LdWAO%Nx> zD1W+f8{{~2Oa^cfNzme4c^f7O;|@Bl_BQ@(|1U70yV^->$>;&v!)}-^<%Ch@j*X+m zy{aBDp-s2wds-($rGA=w);l^8U|$_ihz}lrz>21Qf)=0k#Lcd^@8!bRpFAs3ZU9 zK%(J0`PUBS7h09PJ; z+cP>lr6Ur0jBZx9k@rpS7Dh}V_i=%J#CTk9YxC@ux8C7uf=sXNT(|8-I;{RlqkGns(3YxBlc={{`d zi*(vE*hHh-jQ%1L19Jy;4x1ZQVGneEhSdrFOl{C6RJIz+DvWkC6dd9|(CBoM+K>|V z6N7b3-BfwGm-hape*4{{AI*wIoCGfR$?|{O&H!m{`c|C4m|SkGnG(xCZ7qf(8(PUc z%aC)jT78&!qp;HhkaKZa^WhAWZ>=98er^?dO~nqKH`F%7eoFpyeX_^27C9GzpXxIU z36%T&vrDzq;*?!}xNo{+PKKd*`m4!7)trbwQ#S~{=`MU}2$Hv1@W#~;;V`Qf=N=n~vOSDnXj0Ock)muE9Q7mDSZP@jz2`RIwB z3M#DF66Bugva{$MFo-C@g7@_XwBe!tJp)yGTKT6{(+LB&f{$fwlBxvF#OOC9>!x-oOxW2ND`_T~<= zbU6wFoW1xkaiKCHxiK>Zm!ted-K^gaetcEeaL@`~s4SLmHYVM@30lQC_DQ%vyA0$y zXpa%9tOBC$+@Fu-9mFaW>QP2(-7sA!MQp-6AU(+1x&^wP9jjSk`h0dD%C5>3NNM?( z_n&Pz@r<*Wz0+=%Bj3t+eB@+fu6=J|cq2WHPrau$V$R%eslje`N8yYr0lj!Yk`HNC ze)3&mxxZkx;9Y$y8Vky`OhAQ~;uzeypV=>jmxi}E+S+pN`WM0}tcH_$6b)S5*T?08 z;u+jmIsn?>l>emWk_`~{qaV1qoCfitjDPz#>)J=DcGIVfo~7vq?;rxgKHn^U(gavY zBbokhMCzNb!QKL<$!+R$jDVc{mHlKVkM80`<%Io$Hr~qo=F}*wIp;JkRJLNO&8aG) zEs0-dAk)O20TnFg5pG-;A|nMkvehh_S5#YaPI{5L7WD=?1n3I~e3oK)lKOLb$RQ67 zWNwZZU?8Ckec6-G3=875AvJvxfv@;Rkz-Nn3rGxWIS(F^(3k?I_WGNgx5=tbBQ+LI z#@56R-ObPquFHd`$OC~(8^9nJr?Qj=Lg3~Aob7d=cxG@WkmxxY?`JyOUgb{1Wt(Q6 z^S7@715-ZU{}<0?7Rzd%L<^vpRD%_A0)l`%r+{uG8tYMxfMiD;+CnKigW-&-Z-xCyxUbFug+D}@$dTA%O;`P5rN~m59ZU{Yvp&HSqZP@JUJlNs_)GBrxQb3umV~BJR6SElu>FI zkgLGr?7!dWxZk^?wM{^_8JXbYZ4{K!^SS*Kir0UC96Cm8CPSRG_tvEoOVZ4Ya%o_$ zI73FkJ3l>S+vRPXyXCX;Hh+zP88US={Ze@U`fe~M$x6+9P`)t&kmV*Zl1b(_ZJhHM zJb}Y|X6h~RMyy~~WSr!{R`iy3mQv@q-?{;F4 z;=7t{W^aesXR(Zg-P)qBjuEL=wN3|c3Onk^MC-TE#Xw!~HZX)0t)xMS5#2p^JpX5F zzAtNgNP-uxO~FAu5QVQYQ0>IXPTy|T#bh1|AcW;TJLqz&g0Yn9Go;+NsEv~Z_WBck zOF8Kw)1hXHg^;5rUq1**w8G$+2Qb^AQvmIn#L`;Ox0yH$%q2MA?BaPyyg{Tf=#zslO}dr(1SR4Iv!Iv zqvd(|n#pfs9fb?MYgAxVL#MI@E%S}`69C9{OJKl3Ml|gE!Y121aY;s*VKnT&K$ncl z;joi=4yz_El=lF`G}R)lwXvS5-0CwuHq0L5^!a`8sUf@v6d`9cF4U%H7s7kBQwPh#zZdmJ3M z&OkLMXw@VUD*CzN;MjohXSa%+*B>IBkZui!b*rFXPTuMeeu zI&|a3&2XqDp5)Rl@lsBDw07K~CZZ352rmGxp-nsYJZsrC}kN`MDxYX^Kzs{||5 zEd^zYInn=A<&&Po=#l$tUbJtmpp5xTmVTF5B^hliKD2|~nLQ5V^s=D-f_ajG*J_cL zEf^Ni+pG4eQq`y`@Xv}36&`MbIjw)Crdjp})Ul*+b@=FC>a+BGLyHuJ!ESIY{!`Ko z$w$CGzw)rKxRbG$sMW3!-Su`gLhVvvuIDuO!Ee@R-V0xz9ma0ie0~iA8p6f>9r`?x zXqA!P*j|XAyN(L@_Fa0BgV>*8TL*=Gsf90b0Hv)n$8y;#8;kJP3Wt5ar5tgm99#B% z;WzC67p>{$4)s2}u(QlYl9FcqPB6S45FVIY5=VJvzhnyW0WRvA#b)?upDl8`EhMu(+am~e2a%;}xgm0~JM`){r^-N38`VCm4+n1aupe8OfOZ=f>1#R*Q9GCivPEKg z5!-5BHEoAbYooZrmsDZ>V42gf=!1eqz~{)Q$;&mQ!*J}!{!JvKD(bR{>akP(faVH* z7y+o@cI2GdVMlquMVZ<%QdToCaiQYrr)PH(w=~EYaWcP1P8TVo1`nfdo`ffa*eQ_S z{;uu0sa>i=89uEAOS7HKAR>b%!v2TknuG{wC>H=h?a!<`m0ouiw8yPzAC$*L327)d zHjs)OkX~#SkE{txz*A(7ujD|kICHu-VOzcgiOi~fD|WT%>RX+a?;Ksk|L)AFH*WwQ zSk|(-MaJU=v0OU9i5*7-ysi~=TLx+r6J}SLyxLFGrCP`Prt8StJh&@p?Q}wFaRCSG zuU~|tmM||nL0!PZ4BMSazbadD_VdAiJidVG!!A2gld(0utFlu^-hGj~Z^~Y=eSFyT z_RbOBEg)xazRZbXX_p zj)J~u_*t`ps6s=TZT&muEFEm*PtFjDOn`_D9HE55BoV88IzWPLiA;1%dh`GSFz2w0X{<+nO}8z?$GmtpeLwwx6ZWXwOLwfTFwUX=GO&O zHSqlG*CQ(SjmlTX#s+}$Dj(#e)~7kV<`ZsHjfT( zPeHC)`VgW$sq8734aOpO|E@kp03&s9XY=upU?C&aZ&~5QVq{zyOm^iv{{Ukm>cDJ;pteUrh~xq1+NBH!|R!m)TYg3A_G0S-FR;#BW^O)qfx~7>N|p z^?D#Fr>EEkY-I37G~bB~*J&W;KAf4v4im5Y#?h}cA|yc0xo6oOIfae&%18$NF4WG* z)oT1Vf3Q$*U2glNZ|<^LL?8hIK*E%1x|cV>l)4-)mKIV%?Rx#2>E*?^f5ke}-FwmL zP*3_G_TImVLF%h=c2<_k>E1v*HA@h2C2PkYPsb1s96I)Ljy5Kg#wM=Aw}`gIeY_XG z-OvmV8iH!QYCAp=T`DDGtGut137$l#-72F;G%6m9{cBX zbC6c(LNW)R5<2Tqqd;3B{bIa9MO1kmDDF8Q-tN32*&)MUk`weR?vCl{*o$ErGna4k zu#)|ff25ly+9w0PN7LU%_8_0#k66Gi^Ib^fBRp4_qqdg-`|Egj-*mpG z1NR{ZP(=UA{7x9yj+htRG0@JvyZ{%boz1gg20QfY?{{Slv2Ih}HAN#3!senaV-<@V}@EKXa(j(=t!q6}$7R5)mC z{=<3MG8v>x!2ZqZ!CekD7e5?IT>#*DZLJ>hGqmc-A95=a??V5!G<~!Du>Q052Z;L{ zWIQz(6~{n!hNg5m@opwNE*!IBJ_YkGYpCkJQ?HENsJN#hi}w0k^zNsXiD7O@{z7b? zM1M7Ed}Xk`!TyM&^D9<`VQ!Hv-P^7qe76m=KQ$bAVvlzL5|29=#5Qq>IUwTvpPQc-nnEas*3}t%hvd5 zuIli&Zx#9(o`MdN_e5p?RH9xVRK*CO$d#*GAbn1)uQ^NXR&V8Ina#UCigV?XdS8ET zvSvcQ>V#I6Vc=MBBw%ESO5~=rU*M>3Dy}VT;Pv*r=VfYJ0|K1AAfkX*U$P*g>f`#+ zwpI%)DjuFPOX!pObti<}1}ha4_dT_Ni51|xHI2Do)s08Scezf;j{h_^XM} zdnv7B0(E$ecAH*oc61W!zuhb!Y0+cTX%XW&KhsRKf2d^cU+>*+-=wHcF|ZiML>aF1%O&>u<@Fv?=(^wno*3 zRx2Y7OEQ4)0PB%j8j$70_eTHh*^egt9uJ3BcbuTWd>E$zee^?sXTf6hm;craTnt=T zs8cXi{hrTagw4oYQ-i>Xhj|3}h$CjP{NUn}~uyCah1X<*nTUsrCP4tuj! ztBX=OeuCt7oprkW?yeEf;P)fR%{xfUcR&72^XA*(@9$(h--jn=7OcV{W!OUb z#3J+bgM7n)Bx3D?Bq?}Q-auJ9)TL*G)1%#9_{cHn<|5qgVgG@Az;W{!{%KU^AiSoZ zb}g$A*pq2gXXtpSceAHyz+K8A%e2yJ+xIW8{q&pH6Tf?&%Au%FZOziZZUdyvC03D# zBgvFh}UoLhcF#q_zguYBljmcGcVE3*rXLK9uRWYUpKg1c_y?#^g)nYgK>t<(npT@{ zNDhaTt<;B{k9%4N>>QIr#Z8Cm9a>vQN%r0WdR8X#_N0}4m}B3onQYRw;;vsFuwSQ+ zCOXcfx8YkjW`2n?POV5Ft3UkmCE7inN6@A3E3mB5N{c<0kYaQ-& z6Y^BMfdqi@Lri+SkI5DKFut)z+b&sYDVoWm_&dDqIQcf3<(wS;ACIgs0f(d z1HaWS949t|ruX-8MgHebsP9+xLLQJ9z`i;yX|}*lE6Tw7w|T(YS_=^3*dczgcwqb5 zYhK|NeV2JN_rq&xQ6*YdMo9zeaAw+q8hg{7S}i&6th= zHPG9sbT#qxYsL}GXq}<=%33D1N|Q1kbIr?k2LSI=Uqk0k^lwIw@fR=ETl>7K(J-n4 zy~*!8vg%Cmo5%Cm+U4e-^5f=utyV5N??WKt2^2~?Oq`w^fkH@x<+vYkCpQSg9 z_E;&m5^WScU^bjnnS1(gME9`;N@JYm zx}3BS`*t88oMMrlnS9M19=CvCAVHix`6=e5>mmWF1<*V-OFmW+3bWuP zNUwx3i;&;k@k(7JIh(&EKP>_qRq(XiBE7{)i5N0InfMa;C3fQOaV0qWHb+csA}2#2 zOy-|4f{J_3U!WQ@cQc=5s9TYNGjy26q3BPBxLRZoLfU9iRU2Z>ko1&Xz>os`iV#xX z-cZ!qmBz2Qs${^FEUNx>1C0V}CkZqM;@fsV9ADE3U~k&?Q>GYHmZ@xQ@@!T)3b0J8~3tXdYz z>j_r<06KtATR7>X?LMjz+a!vGdubqz1YC}-oMvi7*r2l#u*(u2q<@FiRpg8z#oTs% zhe<3t`*!Gf#i{1aZ5XrRp}9xZRLIfVcn1s}unAF{uYd07d(_0DHdiUWS1v6 zjoaMz$EPJ<@LCLw5JZ6SmO9oN<;PxetRdJmgSM#geK4;^D3{lqu{PCg4i_gz% zt9&O5#dmp2OY`yz;%o?w>Uzy^jxGJ_tTVgcgU=onX?*L^@*tmtos)S0hr?TF8$tVu zw=N#vx^U(1!Vx3zxVMs5y$)~WL!oF}gG`9FnnV%+h?kL?`8eR;!`dU@pVEslU5Ef; zlxE)K;KS29vG)-KI6k*ruv)69ObKWPO6jsCoZn}mj7iQBXj$u3PI^- ze~)EeT79zFDuj-gQ)uscodr(9YhHYEoR+9YX5_a5CyLE^eHNNyT`~lF_H10s*6+Um z8-yIulLuYjrva{Hdog$C#Np&<`cM;`{9EH*TMsD2NJl$XXX(WBfX4RZ`3`p+hP3zK z@yTBg?=saN18o2E_(BgsSO26&|I;~=qNroMTI>aborEq$2s+I!xy7{1vKYufGwMN< z8q}hH{;BAKTtcqIm%RaQis?0CLD2pmhQ+~m!j1}7(C#UJfRBGWF#L@qWTVsF%|$CO zC9~=tdkljYYbO2LQts8>(ckPkx`yvNRGHuH3=62f@fCgPBh-<3DPePn0dQ{2+ntN~ z4D&LZffhWKKQ8*T<~_)dS=OJN2#}5U$C@P?SCAg)4#WXoIL5DxwM?hW2tp>HfBobB zO!wjQ#u+x$npCLnq`KD9)!Z_v=`nI$I_F60_sCHI^g=bS?NSi9>;b6=pi|LUC7`j= z_{dn*L*U42zZccAC~vaWw!f0$*0)uu4v5$>S09?+V-g@eTEnMMN0l~1Djjf&e8!K| z*GGdKzjVYu74JKZCbot#>`XI?hB6r9!`~EwCXTk(|KxM&THcP92S6wO4M?fOa42oV zi$^XVv^4?$$+x(CCQsq=R+kE`7C3E{GZc_!MdH*@W@Y_?m=b&X{<%dxrxUp0P_Icn z0gX6ZQ$qV_1L*xW>2DpSmvNE1K>My?84(9y{ymDqwnq-`_GYR@3$SfzYzU_pr>J73G7l-J5LEi{D6XNt%`&Y#Tbd3lZ8Bp-0Mg^~* z0LAdmOl*YL_h|a;kDs0HTQhS2M|R^zC{k(eFg%9zN%*4*BlG_9BCej%bOmTtVZqSE zR90CqPm%l*DGVqqLt;plN7I{u+obL9yL{J0qnJH-{u5~ms8#VsMq-tMC7u4d{nixP zMbahV@60lYFdxhUx^>#Y@%~(++czIs1aZmo%v&zEEiIVK=D|Vf`>n05!y4eY*&%t= zJN@cf!jtzhi3@-@T{kSw&#*>S+{nm8hu=2MO+2n7Sp$|zMjik6_s`iymc4lAiFK|h zWW_d|>f-2StP8S&I=+zCf$$1j=pz`8Rd(E4tEk}QHAzkOU9?>Ol6^E)c zQyK@dK{!gIlS^+gH&AmgZcZx7TBb!bY2%5wghaRUXdsv|xuDV&^Q7hSd;wy?-$tDz zaxmNo@a!yTxj4kM`E83_RX+ds%l!YX7kuxH9!%S+!;vbTJx4Fg>W?>n=~75x;Ey>8 z*4x3WPF<@g2$uL=a?_X`8F$7k%|M)4U=O77zs8j(a~YJB_Tb2Y2Gg8~0b^gC1+P%in-CRe&S0lEr`^a1Z7yTIi*=*GATS;Aq#d18f$T$W9PFnY*B(9m zfKFQAzG~a|N>==`;PjoX%ZV4KdqMgl9>g5lS`K6yL`EO3MPiC_4b~7qO(mM;<<54; z!l0JRMyFP>vPRIXCBDxZ*jEceVv3V*^;NocI#o}PB6Ti3e@E{`!`8av7?VPrb=u>s zM{XlE&B$&=GvUmuD>pl2_#LLvf z{!^FUULOmt&)1gAt{l=BJ_4?-Z@b_>Rq#Gnlm?dDg|2NdE>q)VHY&C>Zd$evI4b%D-*Xrt8x5&hqsEjAG)s{6TuX5<0ls+SeT>Yj$Pd0=gIK`4u7j`GBpy)|4{P?CQ0g9G>&Vo0F4 z-^()x56m;3hku*3#aVf#QKZ3XjG9j7T!b3x8T)%yosVm5dcpA4bf)v%Hm!vU8yxL zk+;5$OEe^KcGh+G1oAy*dMpwb|4~=|=Q)F4MU7Qi6J$a-E&sF3w3UqyiYBxUezJo< zYN4mKsxZ2RFdcYo@J91&W7J(5-)>d0M=8ynYK?m0o4`^T$eLsfvjPooRL*{S<8dQV z&^kEujls5KG+mf>=4a$>l_%#eqxl=)oorXiFSkcG#0xIn9&1yhBAhnM2FpIsH@(_e zbYEMM{&wH{DILhu**8AtS*M{fMoF%RMLMK7{;9h%R(%SI02YRCN}W&mW=riI7$Q6y z)R6ZrbnsFt;IQ0Ff1Wg-Gwr$0=b%;_m(lq6uec&jZ(i?Oq%6&Mwt(YA)mJX&Z(b9> zx@9u6P-la_^E_C+__4*kdtJ`ut)7Z^M+#&skcK|f#$w}hOPsY8k!mk4{e^jKOu0x> zg7WSho2?%O8jQ;cuaf~`iKXSrsT57EdRGs)<9?_Yx(xRu^B;47=L`hLY!TNSex>yu z1?|4^2)H!;=!QyM$xD~z0tAVsIO}mHM198cg6v$P)^%(AdDjT)zyov77I%XLbhff} zTP@14r1(-sW7=D!tY?3tdI_$HCrrieQj+Ji`JHWho1GTR0U~G>pR@M4oiRYh%5`ot zQPUl3=qN>_NZU4sP|WBd4&-%~crjb*l~0x6^cq#e(L2c_^~pDQ#r!SeF6F(0majNl zNJ{%>D08BG!R-*A?vUSIoYf&yg2L=Z(#7vOx)cKB71zFTa^Aexyb#EVj7-<4P*Qr{ zVfMUITIcdpTdkAqud!|U}?1Sz1(~{Km86lRb^`@irtLg23O72Xv z&N<~+rGAaywA4(lMjQf|mz#`|zShhru4S#eE;PA5zlv_on4d3qIYm3EucWJaE~%_M zI#p9Be~dJIT^Fv?h^ZWeHqU>aEq6vnFZldaS}(0HI*~&4t%PZB=Z!^w1VTz zCaN;_j3vjtqy^@&FWwjPOb6vGhS|MR&88ag2WqhHM#r_-&cUx!gFk!^_&yRM%za5! zG)x9v^}O8jDvA)6j=?21B0W2$JSVKUIIfv-*j@t}8Or{FZ0fGcqVZ)%cSouYR=FlS z!fdUlQnGCS);^G%RPTE3$6H+>@AxOs%i^b&&7fs)ZS>K{J)C~4`N6jTA578EX(hU< zeBVP4WdsScI#mj2bno8UV?NTBbgkA%j;?evg__iWhE9(rm#Oh~{noJml7-u9w;@qq zzQ;yQK`(#ReMFXctJmslb-7tc68<7dabx-rG#Et)Z<9qk3iBY$C;T`2aJPW?$e;x zE8H#(g>6h#A`#Z1QCg_I%e71pKr+V|hOo5a^L65*0qjc%4`qxHC`-cXZ z)(+;`&@g=$;k+nE)Zdwq)&0B9g~c_nx=M7nPZc5Kw~G9!xQ4p%x@%<>y)cTbklQ${ z$R{U{swJJ}*X&KRuKuY1@O~Ia3cRhAz=D|B^->GGQ`Ow5J`NB6O|1Z#B>dPj#lbJ!zfA2pN$gF3J4%r* zXn|Jazf4&Ov>k9^A8R6+SBf1M{OYv{F5a;w1AWk15PBb7%vr(^{{2GdOXf0A89`Sr4GhRmvgMJ zO=Cd&!xD>WZbV+!a5CT({|Bs{0@93>Dlj$mDMu4&0~41t(4S?an!T#!-+d9k9oGd$ z%|11YZ}K5KuEVJ3EVCt-CMIQZXs4N5FIlG8w0!@bz!8pJm?fWyu~vGrm1+ZE>#xTT z-8k=M+xLUH3h=QOj7B8yf-P{(j=tg?r2zt_W~D^17j5&^jR0 zd>-!OmWwrtq*s8L#qKExMZggN&cr=E-J3y~AtFFu<}$NEq=egVW?T|onEZig)1g+c zU5}&X;ois)i_D!(pVr6=PmSdDOfUGa{`Ci9spUDoQQJDGTn@Zrx`%J0)r+`j2l%TSc20SfK#tL6^$OxFdIE-=-+Da#>J$knwjTb2;; zf|s=$hMHxBR+M1;(wjHDD)LKCU@I-}t$ETqTu=CY?Xu&c>w3owVGJx7{`8iGNw)Ss zn*|8KuJ2I)*3U+-Dy7j&(++SzhE2V)4gLsvv=YWnKpk(}HGG)1`?d@Bo|M~H^VI1% zC2_Teb0xmwdFiaMYF+M!<^B!yR|;jr01m2Xo5D5d()HTvs~#Ez1nEtqy=h}mh7F&I z0jjTP99M~2^OTTobzpj|W%dS92)H{WZ87O#Xzz?~d}-Qr3ZB zxb$d0a(nv3r*K)vJka&Pw;9(&?>v;g5i9IBCv|uzi}zNecI**e3>pNkkmrqN4R!JWke5Kpj(1fdK_%;;*3$V8in?3?}#Z%HLNW zXAcS9y?%+Rm`OKs_^W|W4TmYMSRYN6UBUCi`@x3*p(TFFzf63)S)3}jnxnJIDaiQG z5+K;h3}Y zFb(w1r(6BvXlh;q&d}jVh6L|`!Z=mK967WUs91-kT_|}u^FL*_<&>~W>9McS3CzZ5 zRcuOT{r4G4H?Tv4^S)&bXoHwpTK0-OyC<5;m`i;#7@{h&%kVd2aWs9Xxiai5itz5UQEB3J~&QVuOb5a z*-ydm89t|R7qBJ=UD`IPxP|;iymtP8tXEH8)T9qJ9rKK7Z{UeP7EQ$Nl|uJ?ZDj^Z z%T#2291ll7WR1JI-}W6K+g$@fVwUxb^^>jnaI_|lyV}G%7G2(uq;0r=uG?ADZFU*2- z!&& zt2bz4UF0R7e(&SkD25>+8t)07xCx6z+|&}FUD;87cYXc&Zdc)z`ttJg=PE0w4>#SN zZazzt=ehEmoiOVN$@XP~JYnBlv&ft045{)80v~6?gcqvw6td=|PS1fPwMpV)O-f@~85NP^FRIjb9kMt&HY_gXWe(Q_g<*Z* z>vQ((3io%0Ssl0wrPLk9jEdLFLg^$B+wv^&!)AUixP{v{?;}XBtox)jJSy<$6Zrb; z7atyT-b~sIRcgVnZsj7l<97OZpL`yqWYrsJYyQg=gaA`7DEpUC5zk(EtGN~`{Qgy= zA}l^A|L5k(h7hM4&j(%BYv3Hq(OyBvgWXO4#a({k+?nHy6`*1UMbr*L&_Bm{R~29q zpPv^HI7&@5jm~s?Q-qU$j>a#dK~dh%Z8uuQfc>&~4nw7UiLaREcR00<9MQ%BiW}6I z@Ocvw?W9qjwW%-Kq`{WMmiWH^TwtJ(i|T`yYqc{diI& z9^6ekLjB5XoJN07^O-hUkdl6PSw2w+#K8UBHojYxO~2HVJE>Fq*Bh0_;-?QyB8p?z zG>vV8z57Oi=X~^MeJ)fTXql1?Txae4KnldgRa#Sy<7K{8paFLri}{v^yir&VfAg|~ zx%7goPfrEzYt|yAt`6uLQ`tCOn!MyXBC0!XoK??F0lvOYErMj#TuEa@6(x8nk1`yW z6wkA9XQ>D_e4Q|;$6hzIf-M;)L}QfL{r@r?vpErxIX+&KC#UbZ`+@~=n2}F+zDr>d zTgw`!=6eGY_S4GiC)q}pTO`WT##85y`4uRE7~phj=X)N9nl{z!k!g75KvnCuu&T6e z;32pB?)Esy=d*~?Cm@Gc}cf3L?Hhd3-P zRw5k-Sp7e%*2{4_*%9Wv{Zt!W33BF%ysFK1`Du13P0)gSv0G&m2o%#Ky^W^hv(R|w zJk7rZ{Oq34byfb<#QovL3J)9_70$7>?~SoJ!BfMxonL-=oBa9=&oVFY%NiotK04F@ z^U_qQo{gcuR?qeIqbzQ@lrfJ0Lo)^rcB9z+5M~V6Qhx_OHv%Jm!_unNw$72uRA=M9 zr8N_wB>eAjfVUQDf#Li-9)C`%;GX}lO}d(e?o|V2B;b-ZpD%CP11cI|%&mSpxHBKj z`zXCT3SczmIVo+_f%Q;pFwiBLIvE!%O^E9I+xP9v@#ke?%6>e*t+BoB-f_-^0*WA` zJZf!w;_|or%EFmpX8yEuH@ly1lYi|`rj_?`!nXskhtA5p=A@6B4`~gY-S&Ixy+7}%c;(GcobYP@Vn++Fw9(MiN$CUzpOu?L))E$(*sqkV=?O;f9cTqi(Ikxgsny5YDGMza6d* zA@4^bo?&VW{Hi|o?mumfVAGfXenG52nNfRlEUjW~+mT zPgtld89ob44qxrEe?TjS_I*wNDsLp^PD;p{QdVL!e?Oqh#&m$zDk*+2F^Pr#%aro_ za45}i0)US>zVWvY4KxrLbn@qa_Op&~ACPPZ7bY@35Tf~NPuma`hL zKle%oB2S!>yG{C5)DF{3OqxJ_8`x$@UF+;%vDr0;2NHUpu^v8|WJ2TdCUEsTp?1!J zC&KNh^j&-hcGzxJ+ydfwex(NURr7k+^xog6tNiICktm;*nNRI~;9G2_Gb3E9I5&LuP zrNNmCzaR2;MYgtH;MLMGel)FV1y9(kUVBYalrXd!4u{WZk75qB%?`-dLX2#^_>4!N zDH}g%b$dSo@pkbSQ-Wr`QE_KQz$zoIdv!B_MGi3x9D7AX*=Ers?nrGiT;d~COyUi% zW9_fn-JfUQO@#@yKS&R+r)2}gS#Q%p|44KTmB6@^wA1~F{zdyGEDm@FB1|fcX7lAb z`XKq%XV}kmD23(S6O!x84JN2UonVcLK~;HNeCrJP3QDX17f=#oXJSI9tdu4HbN{^avXWWP)!*|Ra|JHV1 z?FVM^aqz1cFAZM!4Q|Fw9E^(^-!(41<@5v=cq4m`XAHhE%XW;^xyW)$ia(S-F-llL9Xb5V6#czU(^N+45gikC zWn#_ui2$;)JK+|5V|8hw-g0jWmrwXmn9(Q%ZE)NB)$>FAe7^N)yk#^>ASVqwFbP== z&*mz@q``1w2!BRP%8L3C43PPNCg!Iq9?}f4+EMP>0>*BV$` zH&D=%`D|+)t>f!d@i%mgqdX${O8y4i{o~b(XA6161&l=ryy9H*QmB5eVSCFm^6qJO z)5iSR2>`HrWm-Q>Q+Io?x5D5Z3_#aIA;l=KAg;%{F4^+*tcxu*AU3PPNR${6*1s#hVSH-V zKZ{6GZdITLhLNvT9ps9Q)Ln$3t9)pWoMvsgJ!NHl-WLOVAM3rW@AUYczLugQiporLquOTXzN!$R~8%aMk@@vy9ZN3&m{fiFOb zUj0U_287hR<5j`6!=^&9aKWgHAp`~sYBzTlM~L0RXivzs2Mhfre)PV1IV-#A>6ot= zLO2fku<>e3xrCQS9jX0o;R`{;nd))a;C#n`_KttYv``wrIbh|pde@M@c1WMA*-33#`FeT4i;c-sgAV-3JeqpUC`d*!S`2 z>lJOz(jU_ceZg^6=w4?ecJOqSz2md;_19QtYI;XVt70Eb&%ZLdAMz6N2l;Uh63z|2 zT+R7y0wZiPkhcg@43$ND+(m`(w*{0xFN`l&+wF|FzYrANG^mLU(n8a*3{h{P8tg{* zJUrRq@(@&x=Jut}i7WLSK3DQbPDXH|c-CEqsW;r|{O>-SU-s_?9|T{CLFu--+^kN5 zmo2ImxWys^Pl@l^EIMY>w#8OE?^fDU%y21=*T0z+2=X(!*Ht#SZdxdtuR2#>MM`MJ z-8J0AUAL;<;Yv9*iXzoJp3x9KwWhjHv&S*c83XM;#{+dTms@1#!o;D0Mik`Fq^^;VfzV zQjp6K`ND|XKvF);ztiw_QqefwWsZ4As!anQO$BSsvUnuKy;d(or7Ur|kZ>sUruD&m3kcQO!aB$Hh=B?r&Zb~ud3F{^sKlSMPM3`C zwVUNFf5`Lh<@ENGe7-p9S=@`ixy#YsqJ19j;>*su1ku_#O}v@S?(SO~!&PaeDy?YH zl_$~JrIE3Ty2C@rJ8?Ji6|S-WsLwWdeXmaj9k@ zj(mXp&ap$N$-cUv@|#QO8qY|(^UCZl=ZXc&#NP~2XP&8Ltv79I=2dAihI*n|@u%Y) zy(ZN7AM-9QuM5w%+}IxRE{pIlxVM%)?-(j6@6j9gSJ~eemw6DBd^D_AYw7iOPuS*u z8j@F8a|lAJB}M|;Z1HrrLMc^Uf26n1yB&b1{{3NCE8p|e{+-`z)v7g>o>?R}s3a?H zV!Q4%xn3~qjx48_4kaSNUZ&Zx?B_cEGSuz;a`Fhv4G#XDdeW)ICm|W(?ZkQXs-w<7 zb4??Xq85$1>$-F<+O*zp7nLU$5={d(L6$HhDIC0kvJwhB4jmu$L_XG%jCo%M91Ew3 zUt(G5WWM^4c^BREV;AaZo2HOqz6c>z3dYg#j;VV*t=GDpLg~P|CUlW82~t6fzD*p z@aGHr{aE(Y_{gqdL2^7Lpby%vE@jxcc~;us?S&5g+SKl82xY%j1^SNlF^fCLkv#y6 z%?f|G5V)sZL${&{tldpnrNhH%4v-*nBM3j6er%V^clee*kDd!$UIDFD_Uov7Nc{SuL4LSLoiWbSC0% z#`hfF&xOr3Wk>zX6fV||XbII0N3R<1J;<hvQDLR8o74n1z<#Mg$CtLD5Ff+w{509E-@M8|Ac5YUJ% z?^b#CYG5;h$UyTdTy)h~LS+SWxCs~v?)xO|Z98T*<)y5zo1?^VJ=Ou!%Wi5c;xa<_ zCr@b7Hu|de-;{!vzNa%hDw^oPjP{_bqUhM7px!M-=JQcX11_ZB!*ry03jjd8e0SiR z4kgwCsx$zhF+UEzdXa~>+h)lRW)5folmo@+vU4Q?Sp@Xdv)I1J;NQ0Ic(mmJLR9CC zP1Uc9uE3PQQqo~4Pm~bcPyD{<{!|*YG2=U_ZMa$!hEE%Iq(Wn51R;&ef#JxNK6N9e zc2yOXWkg2+ZQo?8er|MP{qKsIf4V7tCGI}Q`z+9M}Rg_nj`kL^Fz+ z<}>n&u^CJL`tw`yd>{J}SdQv`m8T~uz#@Xfcw2RxvaGT(8QIw@kOdJxuyrz27yzfEykCkzN zG1XJ%eLooY|2H@hl};v|o>es4XQ&~XRF1*Nw9sO`$V}{?T!ZNoxjpF%&dN>s9k0Po zlT~oKxitj%)6IAdiA^;&4g@{&p~!pI>jUE^zwG<~M44Po5V#y@3LSiTKsE*|bzr>X zFMDLd_1Ek=z$yEa=2d>$hyG8WAG?OR&1DhCPNrLMwUls9MDP2K$3E5~mevA0a@l=@McJz5_?6DlDZ)B~XCu zETajLbF`Tdl4$q4n{m8K1O#uY)lZWQ7j6QpYy$f5Sg5oCE6S@Ki`D~{e58baw)L_f z4sbrNtBKRTv>G2Pt^mpOVL0wADHxcWz^T_)E3*&L$9C78{A^hgYYP0p!T`{EI$yGS zG5bES^7c4i@=BLd0SPc7E=j3cJP`-am=KwX1%OnAd|KQu7ihEHu&{W=r8WLPAm)-Z zUdlJ6NvnW1R>dX&t&f85beU47LeuxbC{xb`H|F~PR7^Z!uhe7|Qx^olxv2i`s}G7{ zfi@?1ma@p+t&_sePYw9le%u-W zV5zu&na-)(U$U?*ZRP*G6#OGi1+n=vUFLMrENe?xxGwVP;!PEvX-iDdq-TNB&D_eA z)_TAHn4U9;a)71Dg)Go$~waPEb?-xMWq7KhR4GJ9GDm0IQ* zfkD#@9iBH6PpW%U2UD2q_25GpcB@G40EGDjEm+murANY8Y<{8c^hoA&#NeWK){3rD zi)Ux-lRoA(NSMlRdtPzFO8xN_Ah5}JR$0HS{Jou+Eo1n6F>AF;nP#R?6(DndTPy0b z&~JI+Z(S&nmx3H4h&?G%+pd;ZY>ma5Iy@>;243GR=&l}f|J$0~->`@pTqTdJ{pl0J zf*%oaCE&Bb*Ws<4i6?2L`Y+W!YL6nGs~jw~qL}BzWYf&cdwRNc$x0J4a%PTH&6K3B zo%5G49vc$; zQS!30!wNh)mIMXozVBqL>h!B`29t|WQHZhF+oh}t;uZ}x1#;W>lJ%JRYH2DPkgXk! zCs}hYXUp63C;D>KNOIf92#&;GzEq`oNe(jD&qvdq(JLX^S<N zNX+dF4{;g8`y0m5Fxi( z4%3;$<&31hO(9{TJ%wb$M;dW=iYvRf)lot}o}YEOdrHLf1DoB#EkKqw6Gx)~v;fKb zS>^WH|NHgxVX_}j1nSQ`ZJv|B9tE-$#Xs>d%VCoVC+Glj(Y>eI_gEXdEi}99yqb;G z^{NvK?{@2KQG~EDl1izRSp5DsQ_!v@1Td+1K2Ay(JZ~1V5#=0$y28<9Wq&n8*#{7@ zSpn`RyMSL_=^CQ|r>%{2UCJLhq+hxDIvzR=%*%G@Eb@&p4&yGRpl*lA}k&73&DKSpH&c10!0-gOWnIz{+}2h`K1SerrcG z)kWlLlsj|sbiR(F@{OX*bj8;xm_&}|ECv`meer*^*sOysNpC|F-@5$GLQaVugP)b^ zTdehu^*;aFUZqE#vn?GmBz_F%_4Bt63#94QWT_jyk)+Ijjf9`f(|i=&`iX(S>%ir1 z-!(=Ds#i4u3iLmRGqDEu``UMZoUo&jY$mNuvLEXDc}kl}+w_R{XIwv~O(L*7yqgSo zrMQW@E_>u5z-Gs=C}rOXO4#3o0M(aE1GHC=9U0b07cpbWP9nMF6AH_#5ZC{+FR2-tq8B|35OrEniNM&02b+TW9;+W;eBN6})`f z8bW<>UFf6G#~I#-J))rm#aYpCQMgvZa^ax_N?e&}oR#%2(;NCLLz^pi#Nr37`tJ&3 z>Ypp?Z#26FS+u{_^^foMdrk?0xeONf&XpV*6>nrR7`d4b=%Q{$Ww0ujn(At7<7mXA zvVrv*Tt`7BbyGbedp=1<57W+B1rDgaNjFx$WSR+nBQ}zcslhuwv8faGEZvwe5Ji*r zwR8SuqDp9QzQbd*69VO!sY)l|;D7L!waBQ4G9GC>5w@ir6O|=fQG`fET-#6Kw`@PV zp^&{~Il^*M+2LhPdcM-gqF}why$GcV4E}Sfk#NTFJ!f3mImskP`$L06An+Lpe12yk z@$&}s+}6AH51(Rh_AiZ^5XQfNH@=t5pEJ6}zpz{xDR*u#!*9!VTS7b5N3#n-Dx2Mv zdAin)%*1iy-1b)BR@ys;B+$@+P~7uLj89+doaLEKZhNf8Ar;#1@kh?~I5#}Qx^H|=!??&9iwa(VM zowyA&1coX+^owt5%|{b|0czwsqfRZsluf~NyLJh_c?qnAB5UpFEP*c7iMWD?>p6mD zC3V{r^xhp=$IAy+L;o@@`~SedqWiySpyw-I5$XyP{~H)yc5AY{Yq9WiaqkTkb`d)cPfQy<~_n;ux_*2-AioX4b0fLlXc+jJr+9h+kv-lb5aRMN!nK< zIE$ziYm`%wn0?SN(oMI~LX4}i{!>S%Yx<`hzwvcPjg`k=-9%=&1$`b^lK&i%yfgL= z%6iK6B4Jqc;Yx}!wGa5Ah4hrD`?>vk2G!bEG#=gkTsc9ioH*kvHzA;KSUt6;!1K;cGjL zENQKn!Z+2g7h&Ye_rsbu3%6(Y;}r}>DWX1smf?`yR}6UE`yDvr5*WBwDAC`^Iu9#q ze-PB(nc3OwVEG#Iq~mo+t+lIOcX zMW-B-t$;&MOP<=ERIdznm{jEzitg1h7D(7Npcjhz1>XsZjcGAcOo@duB6wF^a-HPo2uUq{KDc~|5-Rw290)`->lzV zGHzkuZmg+xDhddJCL{i3`YJl=2_!38;fS*BX+a79@G8>ZftqfPJ8>?VmJio{TvZYn zKkLF2({EwyTnRxVBCj|fbJn+#qC6mMW#x|+YiIQ>6Zs~6$e!=J#$EhhYe&`S8h-4| zC{sP_YQj6Z2q~zr+AHhV`0_vff8(_R(v4u7;P_e0ZeZ ztZs_aH=1E}V=b_y2Q}%HWuQUf+JBf`eh!y>UB9FOlGN$y?sh@sjZVmnZ*{xIu*?sa zwV4tIG7kN&-J)}Ln400M=p;F~G)Aknr8G>*5;a_u&z0mDqjeAA!u!f|6x#J`7`eA6 zTAxqlsfSfsQZ&U;xjMob*6%jfU+@KUz?){k&HRi*vWJo4c`4MJ*+ZNc-B%0$A5C^( z-{J1SE{|NwC;JBxo?6~TTAdK6er z)1YEsotT&p;W2lHZ9JhBK2@&w74%-cGAG;$N;XD5Ij0@)FB51tnA2)zK%hV5D8|-S zJ%xQ3wdrT4;ijRhec_US-fCOM&3v5=2{pe&n`P5QABS~P-(GCTcq>P2Ycu$aM%Qlf zC(AUH5xXUud=bjj&|8p}iRzQJ^|zkro+Gz8@<)KE?7JzB^gO&r3ePH;L)$eafeX9i z*)&$>%Y5ZLvE$WCMt|0T(L0QpkCz75?!QdMDsg{n7XBwiYu`n6vtMq2sP|}n{Fg~r zP_(~AZ5NfGaEV7yacB5i=G^N>w`ZMmi1#U$>H$&!kwR7nv8^CX z`B-70oO5H2ge-2-Ymd745A6Z{OF%jB(HqUNC(AIdtu(x zO*qsr>ps#>%TW?@n`Pj2rJCu#OxeEAhjV1$;2o=TyH;0>xKl%7yH&-xcaYGV9dq{@ zxx9>+-*+vdPvyZZ8|BVJEwL)y=T+pdtERdpqZ2 zS=@KBUFA(*Xog+!MKfTz2*|-mrQAExcn8n8^yu_1&6+41p)`F5DD1-aF^qYzt>$B? zklVJOWV1#yQ3VIz&^Ze*?J4cM|7(rqKFFNqPf4Ptzg6jz=y-i7ox)+o`s9Pu-6o!F z@HMqdknHJ1kBwzTQIJ8Wy^KWzpviW8j%9a?(EI4Jvh*+0gvtx6tmj{6O*8U2Elq+- zwjo{G9Zk@FFaIrdsU&X8I_!vs+?;?^hh_R5BMz^oBqZ&jzfdf=Nwqo zdVN*hZ}&d88-b|ZU+_^M%M(6}=C$6S2r1>C>u7_lbDf&*2=(m!BXGa>d4Na(glz6T zWC)ok>kqGd>=k)r5Xty@El=dwP0~k3B(G?ZqUlIF;m3Z^U^%yOpEUVFc44Luve;E} z`|^tmd;1?*c>4oqYJa!OearJU-ouCOAp(6Cnj@DH$$hVRw%klJI7iWaoK<*IIC*4` zWIOBEVlwS1CmQ#Qcs_@}BEQc+oBejeYJcC2CKM3R|E^M+E{8O)T&>tDYs@3K^li}TU z0uznOK7B@Q0qLduAOVA&UQ$|O-ROadec~rsAE@8UkF=7Q>t%82JippsQs#lxB@Ty@ z)#W$l<{<%I4C7-#P5tIN%j@q7di!kykF#&+^+Nf;z67wZjkR*XM(gIYS?;qH8+ASm z?Nk-lDJ0((eFKnGmvuMAaMCcLX<1A9bTXMpQ+;_?q^9~6MF8i0!;M>PbUR!<$E>7K zs`n@o5M5=uuA)So8f1XIZpVOFHBxFIR#~~-3e4MlD@*|_&GN!^-EUDI$5!X`w<0yy z-Sdia47AFD;&#upC1+e6$ZqdTi}8fUzV&U!GoyqSh@$#cK3a!^C%~83q@SNPaX8WB z4$r=`7o+e?(*Ve!xd3t(=xQk-&C8HZwDLjYV>OnR_zr;KfA8my3lx`+Ks{UU3=sR0 zW8|a6sB$s=7Ur|`!uqU`+Fm|8dU5O>uBaARAuIc}4h)cVMPnY?hNssxT^0mG@ynI2 ztEGLU<8`dx@y(=SGz_u4CtW6Y3v@qxHxZ6#i%Byyf)RJt_wNKCFQP=Z0R^3C`tqWv zE1y*@&?agxuiMq#guPf3g@iZt86_p&RkiGmCXO|V91g>N90&&*0H~yvqtzALcGWX~ zU(Un6GtB+HA}i^yd|3Q-*P|x0?^q=8A$zfw8)`1YNaw|15@Zqf+gql*S+ueVvI45G zII3a`KR7G&9(I>j9E`1Jp5))KSQPE+^HF@02;WdYHczPlT}uTNts zVLq!gllOxq+y^!>qCfEMSt)5d9P<@*bY+4gDT=42HYOIxWt zJ`!`A_);9e;P*cnL7}Cwk>OFAPq#0OYi4IH{3D-8Bj4`wUr#3IbDQAm_P?huHQQDS z1?Ye5V$zMMUj7?Q1ISOwZu_jwt7yN!FMo0Kn$HI#uf<3Dkb*@!>$foLCjnNde!-Tu@Sl#KKp-2@qIG!piO#3F?tWnp?Et_x zhX;nV#8VRtngs=F9 z#2&q&9`Clj>JQc`)WihK>~C7&v9qp{3ug+50>3&V&%0)Lnpq8Yie=}7P4)xA*n`(@ zyY-UbVKYFDU|Jph zB_&hxwxqcMJn&EuTkWal=Y_5M_=KE z)=w~lZ_o7fV!>6~1o%$5f%i6c{yV4wn7h`F2hp`3J@VuAkBdrt} zR=9R;ZD4?8%l^Rs!U0wW<#mMb=b5kBn2b3@Xeb>1>$t_^tXoJux%QpNNom`pG9bIt zfOSBNf$TBzHnzCwxS%0@loZte^!GmInqc@DM|eg^f@#T2waI2Ve0JMx^-5 z&B+F4E0R?;#IT9nr2F*r7p`-q-M|eajic2w^hr&0vU3z7GqPXsUSBmozV)5h=27v# zOg+bl0+$9er7w#@F6y22Wa)yqW=PLC%&%!<>XuuoV@V&;cxLNjzvu`f{p1zOgcxyLO7l{LuA;lm zGJ7RKinr#+$I%Y?~M}jnX!DtIgT&l7Ot{*XAly+n|cJukS+SFkI#*w$g zz@bQ;gMD8X@3)B6eN8g>zMFYS=yAwmI99N(IOEGGy6Tkn>A6Xg#Qr!6l@s+?=lzv; zqU>i+gcc3z>%y>90BMyPkCIRqj|?E94i|2Ln>wy40LyXc=3A2sVY17vF2;{^Ce|aX z@TPvn5Fxox;YIP|eS*+3im&8L8rbT;f2w^SUYi=;WN42Sr;P6c)$hZYk0QGqLPDq<_ud-lp;=J}U zFfFnj&Ty^^3s~!)->TX?03?D9MXpEr zS{K*-{XXA+z{4G%_kF$3Ij`r@v=34qTsVk{i~JywngE({+9qpZxp6Jd7g1ae@VtI- z(6V?$C0N6&675qLi@RD86%Q^_P`;9ce9IWow%Rf{A{Wc`-pmJUpims`?}2CrjO{}0 z)RnQ$Nh=|4i_&pl_`&D8?HGN#8FZY&z)Ue8cZDJ&4APv(ALpoP(CZh0EgN!lPP=gU>&%W@~>Z6&nB3O(7`Ofg$P~x zFXfqSYaB}z`X;-9srblKG|6Df{F$BFHu}EKQj~_a!!GN|Z@n~vU;T-D0Vfse`2=L> z^6R@2xr6Rn>cgQxV^K?_P0eWwa9UH8)Qb4@g@haOt4<+y_I^F9&Qvy=!SyOcv41@}9QT1RB74`35SXg`{IIVUcD!+w&d@N^tdH>FeBpAWEhMxXs>$2Ww z2-UA0^WNOe*$_Mtf;lon1P6+f3#Y^?+OMm?>hoGhsT5EFUo(IrmsD;;ag0~_?XS~D zd6UvbCB`JJ>S^*12&~i`W^pGbx|BAc;v?HH_xW}wX<`=pG{?T zVv|`)F8BZXcUgd8=Ab3_oJ3vJ{jpFdqDih7@;Sw!gPW&csyr#xSeP6dg_Ja1htaMi zDW#OyfpwcEiPzIH{GQLB->0kypQ>?}^jfZ|_94=jy?=**wBf|4kfV{Hk1vW$yzTd6 zS_(g+Ee>L^7ZjK^TDxjVyw$SOM6s1%Jc zZ!bRgi)j94=~rKYYMWNdUTG}`NV_k_TvW=P^g03jBI!L%i!)T!6aJdOM|YSSlyAD^ zUNX(_f1tl0v-V4IKbu*?eaL6P*mnhp1#Cr|^2_0CK4PP(by|0VpEG|exhA%bdBp&s zkli*4;nB{upQEiBoL9gecWLA)6cRZ3Z>>S5L#On18G0PemNF*1?X?A8ExK+>y!?3g zA#o@oeM`rKiD;6w2f>tW)d6e4eG8?nhX9C*Ur+yPqu@pQH38zeLg2J6GdcR)paeYa zYpMHCwi+9B;oxYs{EVZHV&zz>;OFxmprX^QFRp=ZJ+897xaPak5ek(j4T!;P)46Kv z(8&deR?D%?vff9q=&ssfJw>e;{D>6$5vRd~9WhTnHRdwOrE5*r&1cRtuKX-OpZSnW zN6@dgTYPX>bUbfE^pRStV^(2S_BwvAg3+q9T&;vqv5r_c+53C!e+XFZ?+j!5XyO$6 zU5jP@4*O7w|1$Gc+Xe5}UNW_E)6S-BRnSPAZPJE^f}}{i=E>rnwv7~a-mfkd=4-Hv zjOEJ4LRHDuV-Jo)75=PJ3jN9~!#==#?RPS%*vR8(+TQ=@E`6j#jtz97YrVaHnJSQn z0!n9l1b2Mr)i|kY=WAbU?JP^M#gdTqglCUGnvtz!$Q{a8gm<-?l(KYupixq%PHWTS ze%8@;*2HpJ733v~m*V4A=94qj5UY5lR+MYpak8Z{yA#6|Xb{9273$_=C~*Dlm+#A8 zY-=S}Z2_C8ENons^j5Po+Dn({f3{Ht3AEJR(^f#*^Sv(26el%z4(yI%nn$ z_Ru{Cq1w;hqqE-CMyCxe@8|+M^QY+&^BtcX%u8vSoS@STq|wgVJav}t+)?@eWg8f# zY-p^Q;P4j{RxT}d=?rx!(%I%_@9x*ummr1z(aAoprkh@J#m2v-ioI|r+kJP6j2RH*15R32QR%k!!oA=b6xH|xcznqzD70?`cn2u z^kNN0b*wEc04hfmnbvOC^|TLIfsAt@WCuI_^Nxs#ZTHVo`^|t zO+S20cO&^d8;R<^#PE(L*mF}#mUJrB3Y^S1{$~!Ul!k0{>y}CqGZi($WZ24O><2Y%&oIU@02A5 zqs2<&2`@YhI{Qu&uZI`4OdUC22b+al99l6|`o{P#-g;+hNsglaN$%X{#h6DO&bq_* zN#mbrO@H{LJvesG55E4kjnrDq1MfcX(?0jjB9qT@16N^zH|to60JRDCr;gedhU8EX zUjsbst<`n@s7NrgnRmMU{>F5-&AemD%E9BdSp~t{><3YFsa@^U_8ZqV~Qa`D2vs-)}qa{hoHP#)#? z-<)U~$@RBf?0Oj^Kmp~fZmE>DM-({gZ8bXh39}!xSh{>O{K%DR7`)N-sA)W{5LH^M zk++rHBD-rB5#xe$8&XmGEH}&5roMdPbHxGJmr=oyi-+QFUSgx*sp&E1E$dJvX9FC_ z8Jg@={RwsD-3HsUT&gR!zUHi~YKu?0#^cNVLbl0{1@HRv92pH~$;zinQ_GBxaA?jy zuM1fzg#EEDi)F@tDVM1Rz12kD4@K`gt(-<~J<_!-GaffDGf#T;!WvD33p!vKTDkdA~C)u~xe`br*nx=8?KFz5# z2hBSnSh4AL^}l@@p5|OPpIbF*xOAu5lThGxUf=bhh7K6=>7enwz_J5TYS)upk3ILr z?t)c?c_ybx#4ul`82p<0p+zDT=(bO@X~~T&v}pe_5J1()T2{ID(NKkp;%;{%-;-le zY@&!U!=)IX3N&V95ZqrzHvsM zUq$?u2+O+m-EeC6A@uQkG+pA}z@n5-I{trjM)SAI@;s*F7%9;y9j-E?f0`S!-J1%8 z*~D0XCAu4^++Yr-P`ooO9MskPyt&|l8>%d8DF`J5i!a$+7BESdjfhq`)l(^Z zEPYcN&d;Bv` z)XM0Bv7wmZj(N;h!c*!(oVpANk<=oyM3XGbv093`*JG$6s%i&UchZ#kD9p}hV5miq zuQ}R(hDxeAuxW=hm~L+@izjin7h;8VDIbB1x#}x*QJJ@XN}D&^edpq^)J163vs?HZ zthcb}hfC5>L|iuTBkay&pT8)Z&BXjko-y0R{vhY3S+|Emh4xkJ49@<_yB5of!D^NVZp|DVATQBEuz9i`zQM==7T4lGr}pTrBr>D@V7}8A@_rvn9?% zDaXAIIS)EASu_&Ls3grge1bjOXu%v0$l02-?0^yFH?^~CQHX&QS;CTMKhnbthEIGzLLT*-F6J_2 zRIkSd+t|;>5zf&MiU+AWBp*X0bM)a2WW(*$^JTrW+Ly<84(|S5fQ_$L56kqtm@79J z5*NKckCm#iTOVCoR*91A-ZRiuC|ASwiw%#QrZg=_!a8`P^cR9$$3lhQ#6_&^0$HAA;43E_4C#BbDD=T-{hfwemXgE@}d|7YCaxoFM-d*mSrXj$~fX36Jw{jXf z!hu(L^6y!hxK8~+sLiyb`jE(SJ2?owQvhi6lfW=sr6(#paO4k!6Cy2Bld*F?QW*Wh zK8~C3krQh$U}oF0>@(8M$eD}GQ4=D9{$;z)pTE^GuyS*<*{u-z6qgPzfQLeWr$69! z=747n4Q&qgGpF0=(V%Qun3%%n>g|BrRMEJZ&bU#z^J`stKUP_he-av(S0GXuC1*Rf zLJgTcg7}F)_m76(;q_ z1mV<~j?Ao3o2;m+(sqy>7k_;a70w9xL8Qmgml(cQBH zT!*@>o~)Kn#-mKp3{qKQBAvX$^AXVd(#@WQpFh&e4WvM}P6Q|)24w61L-YN`EOStI z#Swly%GqAZJ*J*~Ix-fO8$dtS`KZ13l;M>7lhb#;H`bQ&k!&m$W2TU{Fa^Zd$zpc% z)HPHYIG3`8o5xT7Okbz)bHF@=UL93QYYp|!$uR#<`9y~d&jrwoXm7r zFCY+00O7z?an=dB`2?>THMEfR5{HM3~D=~GFLW)ud7|#EScwkRVWj))|m(m>gW`Hp=Vka;(I1l&;vw`Nu_V$OgI`-I4 z8QifCdjd8gBm1x+!37uFioOls|0E6<#%m0mfB1)MTJT}QexnnwQz6nlz2S*6R{kyW zv4Ae~z`U|d$UXEV64G%S&y}Ret+tK?p3^e9i)M8(o+Cpv#SazE3v~#fxEmom5%4i{ zZ@YGEfpqmQJN;JzX2YRiEGW$1@=VHgK6Cm=&`Rgx^IJ$*of2Lt$EOAu%x)#-d~Pi~ z7(e+%Di%KWgj!gGMD2~iL#YN)eVRS1dAq&Ca;fwJsctWrR5x|iA~Bs#ThX_%n=zTi zAz>A$vxIHAZx$cTmCY?$n(RgiEB+xqLZKMT=gDkj>f-4oP2y4GaDYM6sfjU;;5kF0 zwR{4dsGWrF7_gLlYUB4fCs;t?I|xhnj3B@cj-35UgHqJ~yO1I_zCNioO#OlCrjJ$8 zk~yI1r9drLi+!R-*H5|Hjcx6wut4C7BHe<(U-WH~_)Z;+2K3Q`EiKT{4{JzvWu7~m zf6h(>rbp5nnA6#J=k^Tn3RtNhUsYc;g^o)}^aW=F-a6+T}Dbd)x#-_$G zpC?VPS{k+>e~MhTZR88Axa0LO+uUcde&UqzXz+&KKJj2sNwhxv~sjXAUlf1M%&r&$7 z6ir&OPq_8IZ-jH0`R9H`ebq^1%){c49jde*FmchlY3eNqrIdPkpDAIxNgv!eA6sKQ z2#Bv2SQA+Vq@tr%bE1{e=57NFqQd1At3LV{BId-5YhuUmO?&il4N7=b7%pAt>DFr8yUmg1%D5i(PTs#KzUO!a#ziX9%n+&9+&zvhMt!5B76woY;_RLoE2>{zUFx)BlT5~8Bk@J`7vM{K=V-l!C#_F-9}&jT z$(hX8uLu)_7pJ$NTf)Pu_yz*}Oe{rVG!Chxg(bjWTntt@Ej<5lOn*uleib0QOuvvb zxUh3`W5d}rWB2g>M|Z-ESyENifsIim=E+gBrnEe1k2&72lvnpkutCIODexC~x{H@u zJ$3H;Ox?1-@K%JF8Ywlo4Qq`l`?~ALt(*sHpB=_Jf?}MB=+*6*kU~k(mjQ5yt=}uO1z{ zBJuP2Z+aQR*1>YCM}xVk?i|K93b0X(%46ZTsGesU8P(>1XUZ#dQItRIHc`Crse)-L*3P$pmUf8m8Ubu6C5yZHl})#Si;|o(4Q|@>3IOZKx?hlRI3F$cR)CU=m#(J1w-KnXx}IQ z93Y`e#N=>-WeKiw1tB?~NrSHjM>!dgks|BG(*3{z>g3AGt%Mj4)82Sinu|}G**uuY z8B*0dzEe~j?)G>}-5rhkl+ZHM3$_5UjT?JqVn_IRQ-Aa%XtG_IYJ1bCYa@@gwdOyfwVQ%bLHlH z=}Mv_M4+pfg(k`<&h%3=vB&fipCAQ_YkFxc*1ozr(-!&iW9Mz_%$mWXsVhP`5~f#I zSlxTo1Du(^^(+21o+sJVH~XDM^23%yqiwEm=sswy@<2qpBC1kg`@?d5Rf@)sakNd1 z`Wy1sH7^ZwTsr=@)BA^0U?11G#IZM%v*pyxe#LNjAFJG002E2b4PHYlv5f zG?(K>1DDO4+7F5Pzf2)+VZMhQ@q}rvD@C^2;wv|pOVul9xOtFQtXu00W|~{vH~#Ja z`UY~_YR}kiDjr%*GpZrd^vJTi%(zk{PBN;q;LfgQMF5VOm$G2lI03dPACkaW*v-t( z&pLt*Z?x15DO}|!?8R2!V7RbAN^}yxnd9NGmk#Be4E^kf9WkC+2OQR|6DuAKo=YqW z8}|BAz75Zi(LjxomLGcY8-ERNX+G3G<}XTV>|WxW*GVyj{W0>b(Cq){UQ`$Ol-hsR zB3}A(Q&vEgJ_Iq>s4V#Wsk*EpNDxYoo3$?3<|m(^U@H#x`Id&Vd~l=O3a?zA2V zFFxhUn%K~RFQY1cEYO(FvQN)|1ACZMpTyr@$kze?mt-DMATQL1<#B&?`RZNc4$z2p zUS0wflW@EipQ1E^7>2C55gPrjPWR0pPD2)jr_-n!r;@}&*!vdaknc{#w;h#ig_>fm zXP--57Q6HWL}>Vn8H8Qrwtopfb~v%s>2?^k0W@VyVbu zA+Ydf)em3Sb*Gk4lX%I6Z?~WE)N}qOBkn|Dn!e&hN6Ut+4TOJ~`sHKQXG5617sOiX zY%nzqS^g9T{A&7`tt0D{!WKa;ytd+}P=dYM#|yV(mHSc^>0Yl1|LR-!*%qBBvh!^> z3$?2N5LcdkIGKzhHIwVgk_wTVrzJ5qL%XJjFpBZ6Ko6NVg1S~m$y$^&p@FEjO9xG| zb3NB=QVs4ry7u!lQKs`dn{e=Vn_;(nFE@7y^@uuDiVt9vUf9z(2^KM;E3%mNm72?3 z$lWJv*aMMGD(m>-DindGYEni>%T5%HWuN-nOT^lN?q5;q;fsy;PRJWBbPn9_8hgc= z!Y|bq74+w2NLY#LVuNgVDv=1~6TV<_wz2Z#^1R3rz?hfTCi-6rCoVCh#Eh`Njk&ju z?V9Pk(3*rl%!Li{e;Z|cmg>mK^z`@7;|SqITx&UJDOYW(l>jHG0t6u}NWs$VFUEhL z+i2hoF?7ZsNB5E-@we?_GfsV|LJe*gdNiOrc2h5#_!294ZV5O9p&+Tu00#CF6}o41Y(= zovGSB?6gOwQG{=0aIddXhQ4pfjoYzu_)Bu<_@cq@yi1DX9LRQ6pY`zE`_sH%2Y)t- zHphc%Qfts5L!NlbcJzf)IRN4jie9YXCz+<)Ot}QsY1xfSR=6tq{oPg@N@KLe6zpbX zK!BGd%$QF|zc@F@75w+^$Cm=&WcQ9QC}V(1%xv|zRn<<*U8k;i-w+$J4mje5wb9*B zcxE{Ogxg8ka6YsL_#+h%H|B)bpc7|+EjqTgxRAK>5e`3u-*|_^s^z}*N6}G|z7Vq3cjtFnwZhve zrzT#Z&BQ;_SoS|O`7HAU@mxtp$W2OU&oj#c@rcy>wd`caD>j7C-3a|u-a$+G8wQP* zFp>3C`!c^d!uZ;m7aut^#i<#MtXf!20V7GJb;V+eL$yIYB6HW89Tu=x8#u3x*^9rr zsQXA|@%`vWqg*VPGeovY4IxAf^FP@M!WKKUU==KSiA-zPs{Qt|Qe`-+cMHBR^X%IF zO(#g%S2(IU28E#^fZ4!O3{t@FN+LY{jSyOt`)BwP<;eTUBKz9VIEPV14W7BV&Mf#< z?;P;qJ)OOb{%!d<4*De6`&6b{Z`146`QcU-%0@bv@09F0>b;xq`lpKDxkKqPyvBHD=mY{`q&0@64>DhEb?p<9A~|}(M0FYn<_^OH zsauQoCxstlxOX*6z(R+nNd-(86f@N>&S94aB{3=$?5iV5Oqr>=UMz&~lzo?Fie4R- zfi~M54=wXwrXV_;ly+gP0a?teJjQJf+Mf<*1#-+gTxBiEy%XK8Vw2viOV(1X>rM{i zpayuV7p-~G;plCRKeLLz(9+<{_4M6Kw%Tc$ZB`Y!AAVci)xD8mo{l@)Aj1Ws-J?@R zP5<5NcrvcQ4?sis6cLw=E7#}QNUKO+mmi?8u7m5k_Ha1?`VDvgY`og9RYl*P(9vO8 z%szODi|W5TZ<8Ltrxfec#$obmIA3hP_-z-yv69V@BTti$C6CP@$n?lq7mEaytEjt; z6m`tAH#aHWuDTHaTP~Ta)z186o}2q|ah{lEelF~~1|j6NdAgnV+N#DjRylD$%0~v1 zS#WnU=DzXIp`~buZmvG9uO_AIdf?mD374djtG6!B&b)u+R&b>%g-!kGkeq3Wf5NP9 zk2+f}Y3<5#;42e@FRSUV!)K!1Yp#dW%3N^vl1zZJV!;|!v=gFR_(Rt=)s58HGA^~t z%;u~zQ2e3jL-&iHxV@7Qua;K=r-!AmtNkr3d)0FNzZ@Q=Qqq<)GH>lQiu~<^HRkGZAJn<}1>s1O?c?t2ErWn4^nUjgw^>-Lmw<^c> zEe`nsQ9=_XtOQrN9t+lfGwi3MYwg>NYmDV#F5!zYb^94Zl<^NSdA6+Krt+OH8zlx} z!=td>Y+J64VJc8liH?31?@_3^$~D1q%l9RlCT0mK3NLd(J*!mteihGnS`tfakgj6D zH=aF(GO>hwM%z;U+?!@Wfm2Y6Tc18y&Q7rUVT~0K0H5d`Kgp`_Iyjv29tu|b+rp{& zx%?eNBHZt<_E~KI-x9*ry1nD|BysA@<#x|fpKaMf!zzV7m6^9H!k=2y+VRg((t~&3 zM6^nbB`YPxL{7@=m;X%?JA_>+H~%?lYgNYQ?XBDbUs`Ip(ksuzflC(ar*xxSJ}wO^ z_;g5>y({1ghU-|R-^V`+QrY0;v6!0D(rZ!PtyzR6)b*(=eg~V7x`>~AAKqFg``Fnz zYHM0?-LC_6qFnpi<#Mmgk>43Zj65~(lJuB&(^YPLlAl#F>#~xeywd*Tx~a`VQ@f;%z>KOQkp@4r^f*#k-z94vtD!Ti&5<+QTN86q=8yJ}6;aSh7g@j?W3;tTjrd+n!Amsr3;n$}x z`Ic9KaGulTw%)Bll#oj6N{$aHChlsIci>6|JNs(k=GUKJixJ;oYK@0LKDE@x%G|j1 zRc8BPS`s4c_JJKB4ZczHxk&C4YKEzw?%7;gj*u?&w|L&Tw@?h+QV?6_Pn={J1{sEO zrf#j;Auv#GH4ZO7A}e!o3Dn&R8V{IDauXdj={8+_{lYi z^UH$NKgnpQSVCb9a$1tz!o;gjY4S(b{6M&X-(*J^+nQx&Ce?qOC~qREI1aFPw>9!U zwlAh?TBIPiHVVCm^Poc^4d%<2$^9p2U_U|dUhI|F<34-}4Cd{C$r9MwV{gWY%|8IH z^rSfh`V@TJ+`IfHVg9FM&jQj@ZGaf`(6ZCBcgD65r;qDKauRQM8-sfGSAU^V#05z9 z=-{S~az&KSS#;O8|Ivkq@^PQ`BrU7~uiChpk3OTKH;sw}*O+$HMyyyRK= z6+t(61SPRwcD48;j8O3?YRB*yjIBE0XIf&;oDixRyJpSD0_T-R8xu=ucGQ%9Vlsf5 znIv z%Ku8tDC8>Q$5-Ft=2jz6y{n*m=Hc)i893KIAFP4LhR+r8Aul)7DCRW(8_2-&eL(}H zTnjq)vfNoB{{8B|=d(<4_oG6-6q*=$qWz4)$_hN&bFFJ0`OQELE?KiwuEj>N$=nW{ zb+Gv&8|o3=ICp%`Q9+hmWb<{X5#$+0i%wDF%o^*eioQop#Xy8-!TxXGp|zHQ<#e|F zM)hFv(*`7jr2aoT{yj}+-YnB=ME@XCGdh)U=1`lw`Aqp-v(keo3`{WH?<9C)ca2kU zYG|KUFR}e%T91A2|Ww8%jyJAT4E8b#nNL83-1FaL$_bWbgxS zC-%3C%^JT1G`wltDyUUh8IKAfLbk~Kin(}VnH1-1%aE;+y)8>@E5avuCwP7Xh^Q>a zl>BbU%1bu&>!AVybGb)TaWDbzi$?shcWm`-B=@NHFaYDYn0a-==4p26LQCdnzYlNn zA`3C(s)(7;S|t}V_YIiM{;>~8zir`<7$MoaA z;=cZc2mi9eSRKG!&2(3l7a4$!1tp9e-r5LP&7R8uVXJJU4ybO9G4|li-i24p|w>EP=7ntyii$FAnMd zu-}?@*nW6BsQb>jWEp75iwF5=T9wdPMU=gdkH6HGQ^7;rRDM**DR5GJohT6ixd;`v zFLDgpJZpNP`>0)ZC6R}DD$gRla(p#mQWLRuLc0{0I2G@Mq%{NH$u-3f12i}X58va| z%RM|PYZj!S2Vd|eTh86xF{6$%At;32(J>@DA7$mXDq|(M5+-;SluUK~mG-XT-Xvi~ z(QHntRZDuKkQvfu0FG3@b*i*FwdT763-NKitJ|4+wJrLROtnDX8pqnNHUN;7+JP%; zNu4@D)HEFIsRVJsE%2>~tu->OUh~aa3iY1)-BV%k-K)&ge(H~WB@eK^{|5bDRr*~} zndat6%d6im#3_z^)AIS`lWR#F0P=UstNvNTc_Q6*a|iXO&L;;NXM3yk;!OcZXP2pJ zIm>0ilXcbgS>xJ&;Z`cbSDc(l(&Go5zq5@prtd|MMa-&{loHAT2$B~3=~-=SmbBsm z*6t8U-_pHG4i(h`lREiHt2M?!Uin1w#HaQ?g@X(tp3GVI@Xu0;wI+&cg&i3J){PdK zloPS5)uH=;UtCkA3szxm07+%hT82D{;7I!_%w0O*UbS*a1+c-`lUE{LS`ljY{u8gS zWeZ4{s0i;|phdZj=^(<9lo9;|)WCWC&p` zdXU#JL!h$Ok-D;`$qr8UL0Gh1zxP1fu$m%mK95NqMMNfAfDwa_wXN>W?bT>}|Zv!4} zw%a8VW_hlSeyvn3k-vj_@Dt9Mwh;mdA&(2Y#P=R;SJeVNTuptHr2-AUS$+Lb zR~Z9Uel52R=hATBxC(Wna-vsV>*;vYamuHI;%m&+%@*E{NX!4es#*D+?_ZepzJL{) zGeF3YjF_{F7E!fh)}w_ZqDI;KlSs6ECcVAxl?!Nu%7#5usSZ+5yb3z@g-|Xmn@UUG z1F%tN5C<#i=$|F~k!U2fd+ucGZ^pEs$c$2T@NxtC_{=NF(mty*r=fU%{NzABQZ2~- zKdX+~n~=2quUA7YXdn06Ixjc9egkG)*T50&n%!Hvo=1{e*vfS!06+FM4nJ}+s%ywl0p92c^g%rBj_`Dt__y92k;MxeBYYDZqj`m>oVY0T7Ey(lYvgnQLp#T``@7+q@|CUGWQKqh6yTSlVIEN~(>e;FT zrpAs~Tt6S@o0@>hg-#(n$1V0c4*Mx+|7Bx8%%aVE|8MJjymzU-WmrRSMc;eJ?k}~O zdoBL>-XzBW$?&T~m2uO7^9f!;$uKpv3-}ax+{KT_g?2S5f`Ar=WeZ>Sn84`7` zaX#AmVrqf&_tV0x?cqjod!37q@fuAkA z{uLWnU3eN@d5Og$2~L_Hz7$!-9X%vC=i{fJ+*UL+noF`=F2$7b3v33c92+r9=^<(| z4rt5&C6dqRycc*8G$z_002|O`rD~3&m+qVuX-Z-{O2VZ(PJ&}zp?Jp;61ed??itD} zywT@JJg@Fw@{;+-s}r+eBLmCAhl4fvY@A92IJ#_SW{rv+vvgz3^u)`)t!8XZq*;PY zfQ8)cv%|4TMe^xsAs8%5QT8SAFU7_$AqV~)IP-2J#K?RgA=($=wyt2d@~#$u^_d?9Yqb@QV| zeu7;IsE|Y&+z{Ai{G%eoBTApAY!Zc816x>}mCE|{g>F@%5th+~*V`T^LZ=)xjhqEh zkg}uI+@K;KGsT{`I$#rEfHNz)^M*+r-J(uQllt3nRU9f%sX?h{%*mkDpRX__>?|_p zb+$k>`I1CQ$aM)Y--p0&wEPVf?Tcoog=$m7ec=LL zU4znB8)y6?oE3A`$r_;1Zk!BxHOU}ILt-Y33W1-8i&;&UKT@g>bzT{H6JkmcitAWl z*enp(ZD?oaF!02s+!&Hvwi{O83dd&}NU7Ic9)EXpHNxPX{hNq3#c5N;3dWYbDbuR6 z+&LPgs4bx_%A1L`b;d8PCQ>co4~%84Gv_-u!3y~;d$PMy2qublYC5;dx_Vm2d*Q)i}^V!63LRAST5 zGU2eneN$iaZSd!aQ#P=~gu2j@hLzTmC`EPGk>D#ytW&89QCZG4kG(u5$~P%l?9T6d zuGjB}1fL$SWguATejcw_e}+@PPfV^9k#xVx-#SB&F+F1AC}0l**`p4tElL&Qh;fDW z_3@-a+(@S`aYJMT@qW@OW37b$QkFaNdQ&yk<)|nT?jq7|3B{t+$1^eWuqi4jz zajN*LYTm1Y<_ak+VryVmjqTWRA8+cMMnhNde{|+{x|)LZ!Rf!Dy9=6n{9V*xB=kxz zQ0a?64e*~Ts(BF>qS>hrGzDbJhCZdPLlJ%G%>_Uv*K!x1f%7jP5$@+$4mu3Ej$KWh zeb_ns@HI(Qwo#ByTXgvjNgsaKN{_7<{b`2U+hu`bkv9h^me#M26w&U0RVb3Xp!?2= zT9?6+%i_>IHtD6&V0-RQM-jzQhOY!OW{#>+Mz@;CKBbm-%}uO8-40k)TOW#j8Gf`A z=LKOZ$;dzQn{VD~DAtmV(FF8+X7o!4mQTaYiUKNcX!qxxonDxqv2VYVIti_BXwGNt zxs)XKPAG@%`oG7j9G6uY;)V&!?2V}2Oaz%d#j zKsq#~2!|1%rwR_?X*mAvaUkKw9^T+UaV~52nWEjsfVI63M;`^RVx70oM17s`pQ`Kp z#cXdH$^FEhUtWWKnFtXwdB0{kH?4$^y2fM{2d)nJFsr zG{)#tiSUt!lz?5EXOrqtio|$zjipn>CCY&5R8ebf9crR>PO#a*`()7kcF%($X(}5Gf>xoBX}DD*$O(lwlB@H6(dG* zBxT`HMN3mGl;w^{DRi0bjQrDAfHi%8+_F*U`9Pjv1Iu?lw>1~;WVwj-sOQLNcnSO{ zf@?@eRfFIY1Hn*l{Z-e%A>y2*8`E_DfJz#X`sS8#!J@Z` z@~?*rp54T(yT3%IlJwPv6i}fU=f~;5dj0+S`C;q^g|`wL^ZUobW6%1=y+y|L-4aZu zZyrDDMwb{EEwkdg)Qk}<+jB0?>hRwjfRHa*gQj0iRW8!*P=zVVy9LAc(x08L)iU2Q zQ1@k=*DeJe+IUr^c00muM1Sus09U~U`s$KHmFTMapKlv8vc0y-WM+$nUwLf#JKT^1 zIv_&s)1GPf&R-5k=`d7Gsx4%evPeN6kbso8cc6J9>0tA3OWLZ5Q@4j(bJ}fL6q?a4PDOfv6jtA6QgOkRwi*?KK+HkFY%q$ zp$YwALlTt$W4PP?4%g|mkf-;tvV0=GXIb3FVZHu-dL$s$A9trrk*d63M)HqS z33X!ibYdd$daF=9{No(#wWSX;WE7%HHNlkTa0d+`9#+xElQ?{Yl)ese7+nnJ++|Q4 zd_5cSe)m?qD5k?jhE3>ewCl~}d&p!i$!8gcbv(aWa#u^2xl30FRdG2n6Oaoi@t8il zE%0Ls@yGOn*Sy3eOSg19maV_TR|rq&?4D8^k{T1&PyFpG-x4I>Wb^bL2iJ)yyE^?Y z|MfRRjl@`$Qa(XaH~Zaz-Q%7s%VkCvv+=>CMy_v(jy#$HcJDfM^8|E*LH$7Ijltgi zCfl{w4DnQfBt#ZzDk#fokOUvo#K0X34bR^@I`8i`{Zny5Lv&C z_Gsza(VIQ0=Y{a1E*{lFQp45Pv;YYur=Qx~1>?|cmw;a|Q6qryT~f?7k68%G612=u zO+yo@I+?qgwpjtD7gtp4Z3;Z5>o2J!29~L7+N!?5$L3+~^B)D}Whh?No<1F#$ywh= zP(+m5fck|c`2XmVsBR>S?)keE(5c10>&kZZ<8Vb^eLHV{e`OmI5?frBC`{lqwsT05mGFqp2=~qHk!~jyDCIld@84~7_J7xD-ii6J)xrEA3o2yC zC~IxK(vlmd?gr4S8UU`nJ%W#VouVDI3?lBQ+@8G*pyGr52726JBkrt8YsS$Twvrjy zd)$e)=iZJ}DFfl-oynJ$AUEawSeC&(Y-ukYEIPuS_`BRTape>3FXW$2ePoEsyjNKk zRcIAlW@m#xDy&TnbDlV!(rJrWb?b=e4(d>OD&_KR#kSR9F6!4dsz-+vKe|3y8mCCyu^b4x zKEU8FC+9I=RwE#YIT}fFQqpUC0KWMJ(pERRM<#3kulaRs34;pcWH%~eH=&kn!V zf>bTdKH&XBl#2eIUiiab%icyzSYTS(9sani!7`#fA-U|Se3G2&t8U&$A6R?$ezQ>F zQU4o(+fs~+e9XwDwZy!eIOQui3gT*FrZG?UIJAq?!}H?X?iH0X5gL&*4k2Wo=&-iE z{2)OrFcH}8bzY;uI%q;m5{H?3@g0>RPumP5lmsr#i(k(%|D3woVGZN6%hAg*WDod^ zoZa^oHUL<5jKjWaeT~2JUxu`FTEN>?mPX%%h_%ID77F-_+02e{G2%4Llo#mf;C+h# zpzX^d))r7RTO)&UaFTZpXmh@oLUrVt5H^qXd>`(hqqJn5Wan#`Yv&E)^9`8`ncYL* zr1Fgt!PB?@K8*3Ob!9A69(;uTvX}aZ)?zd1K5LWxLb%U4=b5$Bkz&C>gt2e~m1&+y z`fj^h^t#BNfl{iOvHy6MF_1z?^5(xzeN@tt<6iHit&&DE}}WIW1fbusOeMBBZDW+J;IzP7%|!=%d>a zqhnww>_(xlC%3!a!!wd{^IPY`H-hs~!n4OMCd@ZK7D{aN%i5gEVWLCy^VQ2H?Nq;- zUVL*WFY1lK$W$wrT%rXgM`NcJnBxxGb5dHvUY;WMw(U&v1M?Tq{C1^fBhOp?>!wN! zMEYmvLU)X~rIs`CC?fipR>wALZi3YdE|`x3P{~Os&mFizlUmJ_O~#i2jfZV2GzSc? zlU=;A5;7va$mH2v*%mA+M(5pcsk!$e9c!9}rjc!rLszHw>wrvG%%#_>ufx);r?sU2 zCg?Ku|1J}o^#oWwz(OjNemTNYiLxYhE_<~t z^s3vWSeHt(u@Ru#KU?{3Kj_*w?(0&kJ#4mnwG+AoNXx|`(#_uH#sE=ghMLk1RBkx4 z&_t-OCs%hFx}4d(AAD=fUVZE<)L)Xhn*HLdo9+BP8EvKq7wo$kWfE## zajAx4{e8Al`I^gfMIWKD%^&k(mFn}Ii=t+lQyOG#!ApWS3*qNDQ@yR`g9&Qx&E z*c-LP(0gb2@d9-OYuKrkEV_A!Si`?t_ z!1U3n;szgJ} z$%}LH3wSZ40EMF6rIshEzU9D}dQM?7Cu(29esFlJ^)=H&%~q|mkPW<*qxw@<{Er!8 z%E83q5XdlGwRP5tIHR|x=sKP1uydiP$Miq03ZgE$(>tmmvO+w9FiTOL3Ie?v_t_CV zju-p>cDfaPW_i|qaEeBdWi#gC1SoouInnP$=!<0b*)em&4RqlF?Mb&7w=iPXG4Vx; zGBLF0pk(FPp?=afOe!y;psN3r+SgzHTX-igXu~`w&3Na~8MFC{@FRuF0DGh)&!X*a zldf53Ea`VNM;~mO4QV^mT%x$Pee*pe5RT8h{jW|-0|!=gX6NtX%)N7f>>IpH&$wDS zm4FTA4y-FQw)(H|pyfR$BeY~>h_J7jeN+|MGK`rHr6F&i#5JTWC!}j7S=xQwy0|7& z;uMUYfIKG^#VexJUjKyOJ#Pd{xUXim8!L>zz{s0 zoUnBSrab@1m4?MmQ7Z>rM^je|0yvx3+>w7P(WKx2^|KTJ%RaA5&r@gq;tOZe29lag zx=PnHAk5*@^e>(kTdZBy>neZ7Q*B%C2s8D*xRNyH6KcXA<7USFU2{4sRSNfR2CP?< zsCA=2Q}-rv%UKR;UY29a?^~ea>Rw)pZgAHiQy2eZ+9FW(X+8}NT!hcXyCRXRnJd-1 z+o{Lq+etEmZ&iL!gOUZWiqyfZ6OVnF0XhX5d3< zc$#fe+=qhQ=}LUo=C^#_`OnN zxS5n}P*E-|T7HjqjaOr9sP;udE$ZV3jlTdf_ARK`y1<@TEz;8|7f{Hpyh`f2L;kC_ zk>!grDk(f_B>lY^;lSr!KCO?TV(EsxI~3829q3CGd^h+~3u{Y_TzYmHG*&CcvZ3kY z^dHjj{qjdXK3+2PEIHG6Lj51l8~c3pItUC|iu^8?tRo2y0t?S|$HuOrj2{^_XEp5M z2VkMia9>ry0*WY&eO~G^O_B0xe(09f-#o72o3jsTdf#$ho@y5QXjM(y{g^{nab6n7 z$zK|Prjbp>2!4V>(lMd zJb4YSh*dtJfv%Za8wW+Wwyx(Q@dho8;M3nV8Jg$+edPTDgy03`Ud9~Yr44e@)}|es z7|)!&Kf>&a^XP``x<0GT*!3H6V){P16Ex4*^5%aY=W&+I2PF{zak0$tHO?N=zmPHYjk-pJ+27Np>zIQalsawEfZH?bR7fAqcGUxoGgo(s+BMccSmv( ziIg+uvz}~=_s22tg-%uj-AN+-xjjeH=N&&h;g@ zoZ8@*yR8Q?g80zG=6K;=KxP6sj^fiFb)+eJHu}(|i81@j&1<~}07X{WDQai6LuwFw z@Ip9yZ8KDQ>lG^4t{B$rcaFY+Vq?@kxg~i?sE#28ZU+eBNPVoh2r?ZxYuBR|1j}bG zP_l=|{yz0d+@O)vjIjsn9(P1FYg4EZN>e7^RM+y(TbC_x%R&1fc6d}AuY3lk1r6Eb zx$&M;iI-T6LprYON)mAHfa4+Oo{@rQhKCjma!V9gv^S(*Rg)_8hPW-dv-MX(G_rrW!?S6g? z4L$#1$qQ`pZ6u>*BKHUevxfgvqa}*x-7oW#>baepI~CM<7;6ZNUat6|mro)n1iU=X z6Cf<-t*---JD!q`&CdUpt1u{+9KSC4$V-DoMF(xig;jc58h6%VVWnMSx4v%|CO6n6 z+n`iJqM<>;zh%WwBp)4TsKkc%C#(MC+3TgqdX*Ib=a&qd!}-&FVk1gQ^rji;0gD+T`u z^S}!SklcAq)5N4#R*nlt5~dq%Moq{8M|JeF1JD%5Q9p%^szy_s-~mVmpT!4n$=8v^ zbAjfJ2V?mY%eZ9F(;7VDbXp1%7IL%Te}0_8o(#DD^z#RP(a$IuaYQl2Nl0QIO7nm-T2(& zQ=sszo73KgO6ZD?(YU|fNT8&4oNg*dv)Z!-vPI+x+5Z1A;acqN!I`ve7Y0v5%Ws-f zv8#My$wos|`8!z;|Goqoz7Ngt(&C(n!nObiR?&-mM3{>x3P+3BfO? zv};HUC8cLQwGG>abs%akV0Wk6CqTR{%Fi2!-H021o^nKQLKdmdVHZY6CR(=`o$kSI ze3Qs{9vPco5%NAj1Zi8FS-rSficgrXC=n1q5UN&9GX&BAo&FnZ9ef_4O?xr! zcXa~0dl=uJ=o2CmYP@CFgVox{bqSdZT`<2ZrOD%EACc{zCJxwrz=XFqy}}zCNpzW` zCC25NB2q29#9!3*yF8R?dlD^RDeRj*-#F}Ikh1}f(}L;4zZ z{J?}mqQ+lrfFUe$Y!vo@w2Q5cL}^wEEV;dml6N#Y4*1F20C^oiYrU3R5aB8M0YLXmhYpZMVz`~Td3VTcu1wdfg zqK%Fgw$a60OI1UNyYs~ifea@(6B2hwo8Y zgG@8AfLQ2kG2dL;%Q>X0ahlD(){pr%yLSzEj`8 zdcb@bmQM(F4C1^?MxIQ=*g^TIYta;HsV@k~96tT}2jN^J+4--)g4vh-iw5GPM^+QO zty=o_6CTYNyA}HTkS*2pW*%)>&r~Ph@uSs7()3EzUNMbpWgh(n_78;wL`Z{fhnz2` zDUdaDCkh9O-KRnsnb$sTV6PWWXFvbZMGvn2DS6AQXJhaVRrzIb zV!vi;N=*(+9Q_>=_q~5A=svX>WLEs04s)4EZe3Jrwd=GoV-^B8e~xl}Wd8j8i{p!U zJV*lOyf(0nQkJQQsB8%V&NvIu1$B8FZpaj5F);46o={^;(cY3pM*LZxEC@*!ZV)XZON?JX9nw#XNnP9YRRHE_RlkcmZUb?b#4Y4~`47sz;( zH7Eae8NEH3c=2q^pq!{lmx8f*O7k|soJLE?8bgAm!V50Un3sZaOXyh&0^$ba9y{1y zVmFZ)QajCn`8AUN(1NacTkylKXS7S}h$v^RO65I9Zc*1;$ zE0xU^7bMbwpUN^)p8evtArIWUK)$Jln}4_a(+_Cwe=b}Sk7N6jwb*K!DxJojtlww{ z0s5b0Ci(^WON~Bwc+>!pLuL1ZHtlw?9;Swlp`BlJ!O&Io8z3A|>1B_{T?B(j8lKhm zmsLI{=9Y+fvQE!WwMcs(9o^)drCSwqUnG*(@p${2S z8>KXR;C654uW_c`;%G(e8Ue~7@Z>*`&p(gH> z)-?aj9d4TBj5wP`E?Xeqg4_XT+7*sYg7v0DRWpA5^%EVkA1QJ>IPg9g@2%t2id`jm20=f#bPJM9l14EmOo#PdU?qv`1WeO zlh8pa2g}an6vG0)P>J|3Q_;LpIg0~%hj1?r0sIHMtOTe7ex*ea3hK5tD7fYG)T@XR zt2!-&S;n(0@wXr zt!W;Vev_Zn>g|>k|zBrKU7sxVz?$o9lyYFgPb<3&eH#6^VA2;uE8# z9D^J2*GV_syF`urmPa=;OkRFxiXFb($SLCgyot{%YcAnFk^|&?#ZOSgzud&kVJ{AY zv#~;(Tsfc@gg0w$&gBgjmICO#ZSCsG(SiCyIvV82Jv42xV4kv@FU8Hz+`VAuMlfTW z?SL>3O;)~3?QU?l8BI=k=oW%)`^GeXWxpmw?%`T=P37%Q^KuQT#cTHk&&QW)6_zUd zl4ac%R-8E;3%Ev-6UAcy*Ecf5!6|(edTskw>3HXgU+LQi&%ENA3rh{yZ=cRKxY{32 zn+#*{llTQhB<n7CR!7&o>3|F)Cl< zGMOYt3O&$iyXf}K@HT#y5{grJ!KX!g_5?wW*iu88pRc|A#KyYE{M>a0u~)mIq?o^7T~#|? zF`)ec#kF(pmeloq*yEwcJo4^~%&MkkBi)NXD4o&mZ(V!GmM)5sp|KAJDxc@Wa0|1N zJVT0kxLZ!D@9S_e~7d;&Pe_{ff5=vj*~hr9>Zem_unQHy&jl-MsNmU-(&<(-QM z8Em_%P!;ZZBI}35FPygfBod>=a+y)naiam86x%=Q>Is zcdygz>4YhyuKCrWuXdf-`?dY)PiZp{?-v^_&2p3z+joRks9BBV6zfI^tz8dFF1?>$ zSZu&-T8(M(pbYPdFM)reufm3$yBj8|7T{MYJ6%R#SLJuv5~ z8^_0g(b(7Z8S2GEWwF64Z;#f_5-npoo8S=Ts!$hHbHU=8^S_lcL)AL(lK*3}^x?Ty zU~%;I&d zF9-T@Nk;PYv0hlSPAz|+o2KNmKaxK0uDQ>FYGcF^&vFA7*UQ2bY?~w~|6<#ApN7mVbSzbeTB6p<(zW=+*{(+t1 z%o}6K5e~M@Rh84#8Hp>`s`foFFtrRbd9ugXSnq~n?Ae^_&3G>AOI*VGun{u0sUSb4aj#{64?aG;uh_!c zMp!*$80wpsuGNLyFX);UMk2Zdb#JIrXcrHopa7Hy%v=_I)UGOExj$4 zYuP&O{NV4wZ2bv>KXIYo^QPy)%7el!q3mX~$M>l@K*jt%-zqGp)MRi0vwTD4lB(sZ>F(e4xkI}%AwZ1KHmjV74{k7foT;(G*SHtSzfH`{i zb;q&fmIi^vmKPznK3uFLSq1u$ARE6nYtphB;Cexx*t~wXeM$391xP`zTqZnLJvhXpB4un8|KSBl$~yVviK-z>wMPY zLT7VB{(Q}y<*S@+x!tROFCSK{FP1Er({omNDThW{qAm- zDdK#_CfP%+@_V@rbf_CEl z^QbHF+@g|!lPcTkQyv?q2*p+>cefV(hP3x7IcOV>zo0ylAH~ zl@aqv7fdydrsVzPRjEVT-Lr|s0Mer-GXZou9G=`Us2$!IISp8UHpHp&3@}LTC%OsC z=Z0O1LzI7uf$qkW+wI{w2&m7%jctM3|jf4bgVx$$IZp55=mYf}-TbjR>3CUZd!9c*U)^ZK z!9bZsF4u$C{tvD^JN5p+aX(J38`!VQODtPwfpVa3*7c0&I#9TXoYOKw)3^Ek_7 zzRoN(TX*LnZNTJX{ptd5C`oPzE8*>0y!57p0cuMw|G}x~WdF2FA;gJsZ zg>MS|5P7xDz{tnkmo};H4uFoQFrhu!d^xcvCVNQ%WJl7{_@))cpSj{kiUzij50=v=_&{5tOqR8@km?wI=z3((&hd9H(UU z&jmi%o9vNWJJoMZ|6TF8s_x&W?|t7N>Uj?8wBBz?(8oGrg6JEgrw3|RQtA0MdtUB( zf$#l1J_NkinqgX~Y1~_0B3W5UNCa53{C;}8il=k>o5iJj7V{LK4E%c^O3BS42ps0<`s1}# z&6Bk2G!O+iz~`CixdTW-bjVZk{T^RxspPkYh6$i`QLufru;+(lQOv}&$Jd{a3ZMN` z9j5QyC(yCCFJ=;XxIwU?fz&pid!^Rr@GJ#So2NJ9K-w^7U~l{d!dbL&Q_qo+N9Bvi zAA1Y+)nf&JIP0gUrqTm6w zN1kef9>N_GkGSW7?ND%Dic|Bwx_pR2*wqYH;StpzR<$p1R{V~0g3RMD^SEur?eB8@eZZTH+w>6Q$NH2oar;&yN>o~?8`y=xP^9>^7Op0;XxK#^| zSc@Q({>9l}oj@&G&5$x4CABC$lvA!Xpa>$O#-~KjEorPswcX}X8 zZ1Sm|oO#-!wB?z<**~!_#y5HW7YELBW(>3S4ge6!?`T<62aC@gZO}dF%AVh!Jo7G4 z30xx&g`2^#-fYI%(~`CY_$YOolcImD9cfL3BZRSBsY^*pLSN%rurL#e4RI^B8O{qe~V zDG>-{oG39_!EBLEYf6pRbiwZUP!L+c>;X~o`YErrs5jAU{oQUu?JSCtc=M*evIp-C zheJjSUDPIBUj%kaDow1`DI``l2z!fI^!T0R1o@s#IVdWftrr&_2Zk7HZttg9&fp%; zt&;wmQAT_C?>iKJl9g8OOyTB8bK|!Uu>pp&cB%}G7om;W-x$s`_q_ETR31Q4z2y*3 z8HH?&LYkoa*My-xcd7H{VcO_2x3(f5f`Q%>gY+JPp~?D_C>6gT*lq4){G&TZ<+>Z05FfCIv1o~uUnr5# z@6~g!CU++7p!>Z^cCwC|-68CGLo$l}HU>WgA2au<*Qz2;j>QLZ^CT{2RV(rJnNLbT zE5#~rG-Xe!*Z$pVZZ@bhN*5@+r!QMsYuI3?7R(=yV1^^)wlFbs{bY^cD*hNJvQ7 zG&In)q2|L)HeOyqWo;8v^G_W-Srez6TyLvQKWj1K?Xvvv&AHfCtjoB`IHYQlScLwy zQ*6!}Ii4K~0~37qrx{mrsh0Skpy&arJWXQkO~#T%N1u6Y=hS%o49q!Pw!ovzMxSlQ z+FnDhX7O}B&n8dmN}bLeKCWnio~~mKkOn%< zvi@E{E(DX4Lwah(QUe`0*3Kw_uGPiWsp*d4S^eOL$$Ik05<7Qu<8=wueybHQR^`$D z<*rZz_k9@mQQCfqsfFu6uff2qQtLF@&jVa~aI&JUEs^uKg|nm*@y?pT+khA~q}`(0 z$F`+g3$HNDx%n^s{4sqdqrT4LCgtfZuWjQkp_r0?9Fw1%6|&gmoJuOzHO#Oa1*`EN zBo2KjvrMqWl648zlXm_s(+D1Tt2o@*27kka3%?~zhHE7Ecpj=u?D9v+sl1EN6|DPF z7qdJKq~AuJ&%N~Zw6t4p$%)vKrkj!|B{Q<&E;HISYzedWUEeRiKXnjbZF4$9e@(`H z+1a}0pXDnafL{No;rOK^$nOV{ll#V^TGH0fpPZb0b2VNun1H?7xh$Tl@Z?o0C>MqH z8CF5KWlrAY{3G9@B{L{(rmJ%wS$P!dc}N3Q7Rd=W88_qS z5!LWrL(pe=E~(A^QtS0BxfN`TZEw|vD@69oMu0 zan9cgP-DR?l-RJ`KMEqEC--PgL-iObHmG68msLuDUF@s3Ptqix`^R&K)azHCoamhg znUKIr+%9?XJI8Q@$=@km>yxSJ6W&1FUTqg|p!fi0(b$K0{2Z|D8W3uN(2b{KUwpj@ zv<4nVvBW5)TyvC5CE$n4>i)T-;U1NS;R_MXFQN>OXOM%=22`XhYQWywHpxUG`8?=#<#CC{aN_klef;iVfkmbL*4khW`Qv=q#0Ds+=z6->3h%v zMe#Ze{y9I76&8{0ujtdANG8Thjn&nSuWLpKJ5 zZmbWzDZ6*YccT$rQ`YEV7p9Z*&sq5yDu2+Z87~^%f#jYevcNY^>B0LR-bod6AyQYF zh;o&(@(-m0Tes{pknrrkv|8aCwHbC0m zV0q;&v+nj5`K}((11O!Mi#{eBHCh;=`wS4{JMSDR;q9fVhm7V+z6;_yl}ES}2t6c%5>N_M zNF1R`U3xvM3MEbVG3m+kPf-&!5}ZE}nLwOZsZKWJ|kJE07Y( z{(ANMfeB{HHAfg+^VCW0DLjdChpce)5>N*wQE=oGASbM|5zZMRQ(IkEoAMK;I!v$` zozVN^DKaUp=iy%K7ZaFed;$8|_tyHW_N6N0xUxN)GXL3=pu8wnRdrS^)9pp9`GH-- zv_s!^h$t{2J)(y%Ri!Kpbq3;Hq@rbJZT`5LEB_ud_fYTe{bBu7mH>A?iN~h0-hMae z{I1K#y5hRXne+gQsMhpPiY$(IuyJbik=^$JSa|t-L|*1 zWc=Z;W}p|o_yPX721@w%PB_ZCEu&U1wkYaqqOciLW1Yv$`6riK2mCZRtU3H#aiO@8 zJ~-uKVoVRIw&0l#Kot)x1FrXV&|5eM#kqTGZHt{OxG+&Nb^NKxq>MB|;@DxCTzv-d zxSxI*6|VB^cST8r3R@n_-L;qJCImS|+$9cAKw~QdE<;x%kvfgNQ; z_yHe1YGM-f20s~iX5W;e&~9(y$Y&7k)R>p+zRwflV8|+zI}!xSns!+K9w;H1MVbK? z>7$B?Lze3yel@rMV{%BJI@TN$47PhV$op(EBAw9J+1!h<+PvNlh@jBb3nxl%ggNqS zPN-FMmdrt8v()b*7yW|O4ud@a8#3%-2tVcO?!_hN4&u~K8-hpuItAYC-;lO0+)Oy~ zPjZz{mE4X|twl*h4BZ~~Q$^G>twbYzHCUp{jVs)=r2O8c9l+w_-==!lQ0!QLUAI}BK=X0<3!KY4jQhezJJhuqy~hN)xq6>S6miH z1n4~?>f)kj_^L+Xdds~Gef+RoU4eNuHf!5(OaJYqZN6K$mUNAK|6;0r*xppF^rpS= z@zF96cU&BS%eQPto8&bO+g5Ma+HvD@X^9)*jLTHuv>@rxzy(sI|qUr6ZPY=`6sKu^9HL$_7-ADqwWb<2hU!%$F!e6>hG`ee){BO zIg@7l>7yxgy`o^2QOSIYNe)*sgJ;Hn>c~H%VAivNO?*;RQ}I8hhslsi!XB{npQ9a6 zCV{uL-z_q*amHnO*%}#g+X)YY(3rS!G~mPidUH862EQboGE+{nfzg8a8KtB zI)WVA-e1tI&eo@>5kr35wlXQ{5YhjLvw^j!>Pqd+rYhMb<>TD3CbT^ z#o$}bjPgku@$*tjzgf%1t~0RbZ2@pYM#V#yW;MZfr$vSL5bCkn!O#4k$AGXJ34^ zs-35B&#t0s&BMizM*fF*4ub@6Wh$7Y-!!}T2(1B^~i(Jas}#hlt=ze z0a7al;2n>EYzL`|O{XtSa^iNOIXXgowz~KAT-vwIgoLU-e)z_+BE`!{2yt(GSl)B5rZ2#xgiHvBC`@aGWC zUwi%VXilIYSLTW$sZyxGgjx4S#h96Oimv_g`alCqsiqG*DP zw*&GPDIzKh{p>uF8uqXWPTNu5#I~{a_N(B_=8q!8o1W=6-x4%V{VuAPC%v!e{CPh| zB!Tv{-OArkPqlZS$Nqk$tEN_VX;}N~Dvu#HLskQ0Z{+5;)m&^swb9Fy>7_;2tpzC- zMt`3AZq@El)k0(QMT=2Y!w>k$y>+$$0X-q{VC7EXKMCMRyd^%EVvau7uvsbH%s{uW)HDRumE4p9G2fx9zs;Skub5{E48|NGFjHubFFL!fNhUDn62a1+v2SE#2|LSykp=_ipk=O0b zHzwkB8?;~an0gx3lCF+{D72klDiA0Hv0Ehw~6F> zb14te`GT+uUcasxqVLe$PjyB0va@<%@QKr)KtxL2-;~+8Qvj8Erk8I$Vy0hFd3owm z!0R(g7n4=^)EdUTMS-Q&mxiCG;U0%Amz>yb5vsTLL^V9#1Q$PrsOr`~tlTc!JaZB_ zb9rchIEO`=SMtuKuH4QYM@j(hi!I!DpOtdxSXipOKJt`^Uxtcw(65X>8LzPac`ocP zTN=|pKKFzo&3L0xFm!8ulpx2m4;^FPMk9mAQ2g(I|&;#Li#QHGE`!_+S)L^nP4oK_b z9yQKR&98@}DQ`P-0yw-YjGpghK4J}%*6cYeInVw?rbpF5j=kRD_L>~$MsTAGI#{H9 z58K&4Q#n06ZP*B=_{396$?yfkpLVzH92O0~RH)DLIBhk_Ir%vU1_a*Ku@itU)hD?0 zxbVpUEIY4zTlv3$BMidj(JR)J5;vA%*=FQgPA?`DjBR}nE4Roj$L_m|tY&1MD3OUr zdz1olm}ryAZimk9^iSqhjiZv6L=QaR{dy6r{+?q%2=<;$3wrjv63HH3v*wA?sUOe6 z>Za&r>5`80d;xX0WAMM%&KB;NEVpcL^dPROmD<$%sgSm@9>%1;8KN6oU(nu*f%;ta zkrCNI??EO{1=bB~;i7Db7V!6VT%T`#@^I4v4FlbeRd> zngPpLG|WWyZryBHK-|*`a%dJhY-va_@Jv`Ii z4vJ1$1NMcc7*SLu`waP3@&mO@)=apO0ap*v-F@xbcO~SGIOf24hlR!#+j$e3c;uMS zwGEMnu;@SZDwkj4s0g)R{Gyv%IaiLJA}~0QcYRio{n?X3*w97* z+g4B?mZ-uBdb~TkB9Z{ZE?^BE#JVS4fm%a#p_BAl53{R znwu|5h3Ot2+attz*)a)6zkkKoEv?zt zA3tgZS-k7*TW)cFDCj@V;J|s0y>~q8y^NkyYcAD&Jhx6a@+9cH5ok&REoZn5WPToi zP#Wni$7cA$?-GNj5=$(I8NhLlDls7Qzk zl0a4~RvKh=Q=WtgQ$PHWl!;VhoG3BC%f=x+Dvj#EMKL47l@z~H5FA1q`fFR|(pT5Y ztFuF5Xu`Z$qWYlQ&2V(mQLp`oC<=s9NdjCZ>MXBW1gH7wZgMN$8>4#H_gBXyP1AFM zXWXPEL~FjBFaCUP2mV;hr)M&_Jb$X~-uW!KZFPq~EDj^_a`1pd_{KKxgS|NkmE$eo zd4fOCH#q-jZw~=O=l-dQU9BGDEPJTOtxBTi=!h%oKXI3 z1qydax6uG};*6^{zN3t;7WUm{k1jF@Pk5pd8EtU8#hykp2`LtkTvRu46QvL;Pa3%#EwtW2nR>zSylbK=o+wYk~B&cIj^C#I!#-tbeYM#Xf93)KnZW zFydm(Ba;v6D{UI&dTdLjBR)+)?+C7OOfQ#!l?VH$xk&tK_ZhcC?u;?#aF#q3J+NPQ_#=tV-r0Vq7#1K0Qc z@57NuyVO+7HD$)~J?m)vkvIf%g1T_;@K{wpA`@(x{Wem&j zZ=%Y>^MLFja;s{AbV0BvGI*mOSOo(1)_vQs@~QP{SyLpy-nR%Vpm74LM={NWjTFS+ zZ5SP2YAN1%{X5*t<+X`f z(}RxnxE0l{On_g_>4AcmxBX@s!k`D#xD1PjiZ3~DPLl2WZ9`-!lM8Av^8CKU!Ro{T zckq|1T?r*gl?6fxlj*{37nI(6yKCARutWN!uQX2&EPc&Z^=2nOJp@YF2K6iShtv5t|Ot5~u1d$~V2J*lSH(s4s12KF1 z)^~<8#JyiN1dI>^;F;e&c;1Xf-Ek7(xi;^(MmnIC334c7D$qNf9`qGDJTs#B0o6J= z;fq1ffjOLTh)&%Y#Br@G2;GRg75pX}1l|XR@>d@;6^(lTQZ-!_wUI3Yl1E!~!4rJE zSUYQ$nK5ifw#7Wnu-ioK-{&y1nP|MR8WfF#4VruQ*m!Ul$}Ei>^N6-SI1a8__$20^ zX5URv9Qa_GY@in~(q~Y6&tQxwcD#6~8P;n1;LH~u&;nwgF51Q|zqvw&xALruwtANj z89<~mO1e@4IT<`_(}%Ll$xV=88!&|%kYX2!ok5X{@taqMVS@~e70ZX|5%~`H5 z@S8b(&~=5mcVrW@H-;;l4UCdvv2wD1&hM6VvFFMI@%X+jM||2CbTH)qq z8o@^W7?hA02V!dilR@3;0%V0)tb21nH<8sZ@cwx5%^AC)VjDZ+j9#JT7GoG{$XM zC8Lj6ZOeZJ3!ijf1jT=&0zOpN679h6t|>)*B?xxr&MMS}l`FwrbqZ$)Za| zLPO_298_8U>up++n!j9e6w%PCo>;o8G#K#EQ=pQAMKVa*L#KRNi=Z{}e{`9@njah8 z)=J)3LbPv$zI~2pB;|j!Da@ak z(aO9p3#c=bmDbp^fE)qa+L*1qldH#R8!B^z69_J2fV8JXWO3y}waabit8N9DNC@tn zLq*ozBdorD3Dp?7YpNxA>^<>+IlwAJ*(*-Mw=ko<*d4GUe*DlPlUeDPI=lcrurZ0< z_)A>=H{Hp}>Q>r&?@L1yrHwsSzV3z_r`kNJrjAohcvJxB+s>Z^6-AH}`nu&)=A875 zf6TH(FrQ{W;c6^q@4c*glXH992b@ioW7NCP5)U(GzaQ}^$^TWLHG_8foAY`CcB!o< zHKEZuDLRcAt66(fOTBhmDRn}+Oxy|ExgXKlxN0l)+jt#%^kKivq=pk42{4ZBX3 zjGCs2ERrO*xt>ot`=amOaq0-3@fqe&U)wO_oIBpH0d9NUX*ViEUfrKw2=Yt}NBkfr zv~crJ(YI&{#k8mUuYVt|X8kF-w-)zHpaEZHdf@JlqNthRM=ZMk3WstLoY5=I)A|fH_K$sY=`t;2^Tme=5Rc)sEi=y9h z!TL^xTHI;mVpU?`qbEZu8FzjSCK*kwQ?W$|^w$hAiyHla4Y~|l=y=^fHac(b-dJS} zbgB5(83dnx1#uN-;cY_1Pe)HjpUP)>yILJgtSOaH4BN8$qe8Vc6BbD=TeEq6&k}pC zg`}R3NtYNqIw+d1ZJdVKn62lZmV|z57n~gurtn zwi{pRWl~r!@j-kUN?Pfl1H%z2wl(1mqg}h%^1BJ`qB>SZ!En$;C@ek=2~E~ymX_W(%-^y zrDl|WqXfsdddHFENf>B^ku(l9*YnUeAymp{Q$c=Okv#x-j-!6w3|2ZjF7OuuDTFcTdefG&vOn9ZsJT zw)w@Xt4D_*8iIhJ@T1(X31-7KE}^>XDE|h}oQ#Xmd$B`D4&sQ+1gkISP7f#K)`tN) zd}W`3!DXC?oEPqM>IIs|7%=StB0K&qO9YtXKnJ4|Jh8jU!PXsceQWf~<*f+pW4l+%aTY<6?A#%?BNw?X5lF|HWRg64qlcvwM{5^G%3L zDpr**OM;Q=aj1WD$gD0)^x^$#+-0?iT=4?Vw#YYO$UP>sd7hW9VX}^5kJ~JU)J!)J zqv$3D#5Rl&VfeM*0FIXmdiNg_H>@vDl0pXvmfKMKo%R+s^3G?89aZ-C>Br3O(PQ)J zKL2p*S>84NQFZmok26mOl>?m8N}FCHp(VHi{Q!MFb000Nt?bS446%tG+)=~S5iTEe z2|hnBp3TdB6iaz5$y*?^5p<3mrT_URFZh*k=Je|`FP2kU*WxT1vj@Z4Mm>$1regF_ zP7hj48+=r(Bn;jsq*)GSnDJ{>(C3aAO^G`Y#^uS9cpG4lri!~=T6_{B{Eev<_s@kS z7xi6Hdn7xn>yQ$O{F*Z5{LXL5Y zjo_C&YxO|mlYYB5VtjcWoF)QM6KFQf9D1GhLPy0d1*`>fiXOUfA`?S4!zQ1T%Lw1?J?GWlb0#+8n#*%bJ|o3i z+@^U4MRh^>kS!R@(A}tv-6h5ql|{()S#2&k0FsW!pe`(3iI>CHq6#Ocy1c76)J-2K z^W-c93N&T?tM|rT-zJO0!^5SVScDP^*q9GzH>B!r;NJ_-t;mXpY zb!AMjqyP@rkmdV=|9JSvV^MA0l_S5`_0H5z)L4sDN)TRPv{;yi^0NUY(Ulm$ineQ= zNV$K!-tqy4#G{bepJ_=qi0&nh^Z!yKvV1nZ&d+ zfqj#s$w9gq;@FB=s>|U7mAN?B)nph^dRxJt>#%H{k8|Px&Pp>VS7Aj$hZ zzwZxl9P!-Gb6?kWUgrq=u|C=mf4^h3A`$H@`sZs#eKUAD9=o#NaL|)r>lIIvOzwPg zV}LiR#d*i7sN$Y}WI1hZ(MaNq1`W1LoJF+p>;xrfpYO12WwN`b z$Vyu$3S+z2%fA>vl5#Gsp54zxZYAbSc`!zjod~ zs(Kx7+z$G5%qTL-##tIa~1E2w}F}Jm;U9mb&pf4@OwJir&U-EM zInFUin>=sdgS4aXN67BsEJ*$l`ow6G?z5Y)(n>nT979yUK_VeDyu&qL{W0;){E5e# z9<>KSjye(FZS5c1%5i(Su-|Tpvi$i|c)*r)DMCE>(%aogA!oN2jiEb!S9OZ6C-M|V zV!kf@l~N6PIa@q0eidSbz09tP+*~+^w3Zd!j6@|bH(y$5v|`r2*rg#ZtFB|8+Z1e) zEzj>N=12kLW;KcK+$T>enhF<(KGmZka6{qhwotvKUsuoB2g8gqb%&r2!p`RpZS_Qy zE&W?_Rk|?Sf!}b(D(za^`}TsR^F5OZ)A~9a*Ye0q_9#FvIp(GS2ER{U9&-Fle8NW_U`y zA4=(~0T5B9p9Rrrj%aD*B~{dbhdUO2hiM5}eql+l9gmp}FTJoq;WSTj+pg|G8DGv|Lp^ig9g&t$QtEG3kta4Pr)j(Zg*@HWCiqDYD2Ejko@3GF&C|NsMduyzBQVa+|F)Xf$QBw9UjLNpxzW+B zGUs=6Z0Q4?8QWB~h__$DFVip#xKoJ!`tuzXZ3e;nvd@v_h;2<~a^b55@$P1@oMqZ; zFV6+m_`SqN%Rm~eU|q|L7>e20qDSkzGVi`#7~Z(DF@QDAG>ia{0q+!_QK@bc{N*-} z^F_99!&`^PZwm5^tc?z*5AH8#RG4=CZ+fvxzmui*RPJK?9bB_{G!^ZPYN~$O&=9%q z=mgj!jBL}yq6jy$*xKN1{E9DvXHIn#+x{V_IY5e=MA1 zJ*eKSxGFM`pWAG(HaT_Y_aOdtM{g5Ns?B*%Fw~~Izh-_+iaG}0s9e|3f}*In@4L!R zd!l}mKhz{)j3kHSi7*46=3QTW;RtbU`hMvU^17XfUjNMbjrTrz00OZ%HnqgvR3UUP z4eC;`T^P_z7;~QYYj_%UAE!(>wj9a!d8;dO^L4i{FAFCdPs$Gz~0+FPLP`2E@-DfJ{I zX$y{PiCqYa+`zk93qh{haYu^xsA8F_b%(?Vvqks;Y3DTkKBIyu=|1C>3c-NIsF^)g z%DgJLy^M!Tk5IQ>r?Vq0N1J-NgGXA4KBIqo7*N-*uteYwd(r|hpuFFVe!A@Tv8NZFoCK?5P1iAOl= z8UCUGT4&ULR6|N^x#?`AY|%S6AN!Un?-w@&)+dyiYMHmj+T`%DUiji*nS$w5P5MF-4pqAxh2S$=D;E#%Ry z_QFgvfYIb3!`YZp0c$>>!;yO_V)B{_LMc-ZuduN%raFsqfhdIEx72 z5hIg+CDCNZ;wma4<>}XH(l8&HP_J)i+eh;+YJ9F1Kd3iTvewD%B)x-Fiy+DOALYQ@ zWrHTnf!F(-i;^*`d1+=mkyx9wv$hziTmJj)qtctYpC3{w%!l-*vI8j}pZM!gX}!oB zOt$4zSeEZd(KMngG7vu6X)+gsW=?t&e^!Sm7@pL&p6!mmDI6Jkk+P>=(w}}FKV60e zoL?}FRK-%uPwMHf(E=LAiv;xc@#u%w6pcoaZ!W(k?y-Fhd^h>-og-30)f~xN5trHX zDCBR6-*8422~|d=hSKBqewJ|Qz5-Ghpr=^?OD(We=buxIZFpyMYSv;P6tl1oJ{PH;P zxct2*J4~_r>0<|85(4BVw!4m`?b@uky~=!f^l;nBd?G8ZwQ|cuA1-X)0CWZ&+50%2;d!B;~5C5OE<4a z@r5UhcX{TFB^zD)bYuw?>T@tLw3C%UYuPM}Ev>)wq9IwNiUb{J6fyxi$Y($em}rzp znmItHxvBylh!vU43aXlvRh(HxLlc^~EB$L%%u~=aVEY2tz3TSFp9f?}ZSlhpWE#!p5jV zI_Wph@tdmq>U7C!pAQl4oia2T>Gfg1o1K#t(X>X|+p-D_@ch(+nGqr}OOJuwdSObY zYzC$|`kiS`$r|Kfh++68#!@&)xJCb7MA^G~-Dg_}Fh9{W-b3FPlHRnBWv~WYE|E2& zr{PYH@Xnnw^P#OkSU^zzfb~arLtFc-l{(&zki-!s9?UFr|TLuwdM8{Ps+HLh%Y z+@$G;_a#T4MTO^!n^g<7`1Nhk&vl z#D)ovvAZfusfLrslsn#K2_HlwKO*)3;R4Fe!XY^$*?O#=6pgED&Y3P(e)xr#FElz3 zOWa~MZZln;nVQ!`%4(tkB?8Bm)j4JG$|O*6Knv#mL_>F`{;=f%)GUBR+&#s+b4xm} zQ*-6Ju;T~1N5)-_6U_n0-TdS0!W84kG5B%_tP>u`183D1oN}_~&hB)Sj>QOlVI%op$;;jS!$D-1$Q>o<##w|4& z+GpZQSD_XvMhe&(J3t<>Kd@}Wyhtdg8;@#hHLR;6r#n)SU%&5UM)zjk=`>DU2Aish zL3Ea<$CD}LA~z|jm~I-8BL@BXfW!B|I=sZ`&2lXPdKLRy!aV=eN}4lS5TTs=1Nc2_ zdE!79u}!;FMAu=IH7XSaAF!6%2Kzo6UVI<0_lkfZ+d+qg-125#Ux10IkgTj6DCc|- zrx)+Fzu_qP9DCs7VfM|*m2Fg>Fds7YGJCYe<)BqL_tE_3G}RI;if}%J%;%B`N&m5U zY=08s*ok+VXy|NJMb%pPr6 zYMeQ}WNoyuISG-c{GsIuqd=|}P5#^FGZZ|n-pL+lP@@bcs^cPVjLvUZ)bF{(DlrGY zW&5WN+z`IY_2%~13)fI*#^S(~<`8%6;C^z>Glyreadf7^($wMucF@x?ESzQ(P$#Nr zCh?&)%lc+qfTC1k!UgN!-ji|u4lAk~ed>T*2M3s*RV<*C&dLUC!{j$8!?aH3MduUe z_7ll)m7!)ny2{ArA|pRi#6un2m@;X`-j>HfT&crj>rVcuZH}5hSI5!uxypc9nQnT{ zB-r-Ax9YDYQh!9c-#kew%nuy#O`N#vB(E#mgNjcp8)R0_G3{dXsvZW!LprrEC9yuMG}{rw3c=fA)U#)Yoc z&WC!l;T)y+67Q7oJ5SivY*Gof@FyoSQHrP!%S+R+X*>BIs98Z{Moet_t0w-IO3NgJ zjw=cqLyb0X2&TnUDt_|-Oel+Mlf6{*aIe5c;xS12!?3WYg}qayIRUv}PX{)PouEn( z@IH94iyQ>i(OfY0?#G9%lY$lkxmRdYn>b9-P{Kr_(g??weRw9+=1H(%Sb=`8aCiMV&eAMLJ$0lpafpHExTMTsEm#%r0cn zZ>Z1B`cTB?TTywo4Rl<-CT!*B08JJ!lSLgUk3g@FEy%|!C1?-kn{6gtUt@}lc*pZ7Aoe4o6$0xe!|SzdAaV`geIU=a@F-kS^jh<$ zLbphzf1_<^K?|UB!9Ds}qIFn&^{(~Dy*}2CR6r2&2HW_p^?}8sNqFNNz(RgJ^2so) zniA>Qbk<#q3ksb9{MIv3iv~VL9$B8t8fDV8E~>wAS?j$V$;tP0FF0Q4_rdYcjsj9I z^#Jf^3$t$;W&hjZ^D2j07n?L!7EL(npS#$3=H73`^CI3RttD*v1I_M07}^peGN0c_ zU5j&)DKM~7zwm`FHzd0I245Tuw{G4kc;xIhXJ1kjYfZwRQv!dLeK&CEL*!cA$3>jL z9Wz!PT+rErfI~4HY&yfbt7~NP#f10s{;Ga>?K$2I)m=pPd*eGyjbn>Nycr5+A0TBj z3UZk^SX*_dp&@@v^=ElCeV++-oWEaXOaJB?YjZ|~<2JNTwl2wKAXMC~XAEWa9}7Ff z&C)nE0tYmj%)LJ~)4KX2n#KDOrkCFT?ffPaxRTpkq3-1{>X&K^4g)6QJMgZ__yL-a5IQLth_5p~zFj2)E>1ZfwqBSlrq*M3Lc~$N; znfU-oDJ!zgI98%w&dU%JW&Ca25IkYj=l}W-D*9vA$LrvI3dOOxDX9|lX5jQpWG4bx z+P{xH<&>hq z+zN?KKS(H0CK8dydCn)czyN&XQY%QhrM>88ct34 za3Eo{(@dt#9L+O56owkqJ~-Le(mgQ8H8cTdVdoy|l@AjQ`j-|qFV)9d=5;|hy6AcK zWtDp`6j6L$7k3>awA@X|yOD%%=nx~muTEhd8!Lbj1z4Wm1^>lPHTLMeM|ff)8DaaN zp%2#DZz{`dTJ6a_w{4$X)vWsdBUF5LaIJPCqcvAI8 z<*ByvTiY@+`|(e#mzMxGR_Ku&zWI$n**fHvpb;3m;rxsYxzpJw~0wy)zDv$nC&T1pwRq#0;EZ%b$YwbV?l0S+>p%?|{`}9z}GY4=) z2_>mzdm@{837~$SNgsVt)m%fvl+wf>H6{`*|7bpRSr8VWMKW84p693bi!oJz2x(9(Eo8Pw7Kz zIC}_B^z8Pe%4{Hh)&!h&$;7xl%jzTHWgxo?%r8hQ16g+A)y2LDX;vYlAxE1Cw)GJeUq;4Q#6 z;ENHhZzz)`K<6ybXknc;EI`a

uy#2dF{pOFBiUQ#f(`F-^IyfE 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 z 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�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�|AWbUy3N1n+*pa@%)i> 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�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 literal 0 HcmV?d00001 diff --git a/supporters/briefs/oracle/logo-horizontal-cropped.png b/supporters/briefs/oracle/logo-horizontal-cropped.png new file mode 100644 index 0000000000000000000000000000000000000000..8b9fd11f87244a87364f63dfaadc5051468b1910 GIT binary patch literal 2500 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 Q(*OVf07*qoM6N<$f}MiTZU6uP literal 0 HcmV?d00001 diff --git a/supporters/briefs/oracle/logo-oracle.png b/supporters/briefs/oracle/logo-oracle.png new file mode 100644 index 0000000000000000000000000000000000000000..0663b50972326bc7f05a3842d0188496a326ecc8 GIT binary patch literal 9826 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 IM6N<$f+KSQC;$Ke literal 0 HcmV?d00001 diff --git a/supporters/briefs/oracle/logo.gif b/supporters/briefs/oracle/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..13d70214efdfcbb118b553a0791c8fc653d49074 GIT binary patch literal 2156 zcmb7<`#;kQ1AxDq+0|xSlIvkL;?Ni>Nu8OQCA>=)E7y%9Lb2qP9B0_(&NwdbF=a!H zhVjZ>Ok}0RA)GFnC@P)yMmK%lv-3IcfABs(Jik3ZJl;p>t_RrLKxE(%0L;Cb9Gq`^ z{bA*TEFh~hMtnP4{y-cdrM=x){rGjGQkgk8X{dhpIHfh@zFK)+#*D0`HQXyxKJI+| z5~kGvscm7k~tps01(yMH~A@{{sD}?IxnYyo!_x6$ z#&A59Cs%cpfYC=p-ABNxN(Xd+FPJ=MLud@{WC<;I+}GA%w25Fv4{&&*l77Tt4!XwNH;B|ot-5Dk&tk>!{hZ#sTV1dysCRq16f~*Cl^}Id>IjS&9#2xcmiDY;?04y^OC>f*#T;_~; zfG)io1g(B%Lj#N`8Z{P`@|jvfjmr@W2m_zZb-S7@YjWF-qDoLU*4t5sNPog23W6Za zf+!Tn8Yp%+!Bawsk^}Wv#&2hLvYdxi+T>=j^BTcMEj95pK>VqriXcAvq|d}1*a!=8!QL@h?$V+$T zR=^JRz{oi-VTu+K4qJ*WaP2VkiS_U_2rAf}A9sQgv?u-aC@8(QyryH0OWn~xin9&@ zEZl`2BWJlLy9Mo+^1<01#}w4m_Pb53xOI*#AKccpbx!{CWY9Ee0Xwo2N5B5`eFA;> zctJQsUm0D9<{VwFM+IVsr#!uxdvJ-uscXF}PUsQ1{L(tPh6Ztu#bp|L$Oz4N_09Rb z(R{zQv(h>z)t-J!zezgNdk3zJ+t<`Zi=HCHes7=94MWKinj0-5LafSplR@x9M`S91 zTCE;<#57AtDB5>6?DX3H>dkwfuxQV4NCv1VhE=>8eBv z+SVn7-BkIIgWl|KSaSYA@1f0j&U4g5y@BU=jQkMI--dIk2Y;vO52`awCc8X|r7)F| zzV}^6Kc6J-PY0>>nH2m4YBPxZiQvS{ebTcBDo zJUxb#Vh1PF-wY-m2FF?d1 z3byG<94-%1yc9u|LwS{5c8gQF7!%7WFte^^kmvT#7*X-z>`?+!+lX}^nN>P50rF3h zEN{`Gby_KZT=^p9);&)1=FE_ly|5r=!WcTX0^Z9JZhLDwTy;K4>2$NiO|P@=A{3|x z))E6uu@tDwBWGe<3s&Gv)nJqmF776ZqJU9n151$X~Z*o zx4SgGlw2rU&XP1Z8i8V@LSz(}{Yy$4YVfZ+Krh6q zczb`qKGf5!)qEjRq4p6FjA48WNi@%pUEYEG zhpK?JL|~q68^~Abz+9#Mp$+eD#>eO81WsSZW|E}+>+uuL3O4P361VrMERc|L@}RsYP@4PPyg=3CznMw;9oa=JS>xly*ZjtvY|K zs)a6UbXzG8Wa2K+VR&H-)!sT$8GM-0Fo^4Fhs)cZUA|VSlK@cM7{M=gntoL={5wjE J%^<+RzW}hYqG|vD literal 0 HcmV?d00001 diff --git a/supporters/briefs/oracle/planner.places.json b/supporters/briefs/oracle/planner.places.json new file mode 100644 index 0000000..45c31b9 --- /dev/null +++ b/supporters/briefs/oracle/planner.places.json @@ -0,0 +1,661 @@ +{ + "_comment": "오라클피부과(청담) 회복 일정 플래너 큐레이션 장소. 기준점은 병원(선릉로 612). distanceKm 는 직선 거리 근사값이고 verify 항목은 출시 전 확인. 링크는 구글 지도 검색과 예약 사이트 검색 결과만. 2026-09-11 작성.", + "origin": { + "label": { + "ko": "오라클피부과 청담(선릉로 612)", + "en": "Oracle Dermatology Cheongdam" + }, + "lat": 37.5115427, + "lng": 127.0436528 + }, + "categories": { + "sightseeing": { + "ko": "관광", + "en": "Sightseeing" + }, + "shopping": { + "ko": "쇼핑", + "en": "Shopping" + }, + "food": { + "ko": "미식", + "en": "Food" + }, + "kpop": { + "ko": "K-pop·핫플", + "en": "K-pop & hotspots" + }, + "care": { + "ko": "휴식·케어", + "en": "Rest & care" + }, + "essentials": { + "ko": "생활", + "en": "Essentials" + }, + "hotel": { + "ko": "숙소", + "en": "Hotels" + } + }, + "places": [ + { + "id": "pharmacy", + "name": { + "ko": "청담역 주변 약국", + "en": "Pharmacies near Cheongdam Station" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.2, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "처방약과 냉찜질 팩을 구할 수 있습니다.", + "en": "Prescriptions and cold packs." + }, + "mapQuery": "약국 청담역", + "verify": true + }, + { + "id": "convenience", + "name": { + "ko": "편의점 (청담·선릉로 일대)", + "en": "Convenience stores (Cheongdam)" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.1, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "생수, 죽, 얼음을 24시간 살 수 있습니다.", + "en": "Water, porridge and ice, 24 hours." + }, + "mapQuery": "편의점 청담역", + "verify": true + }, + { + "id": "porridge", + "name": { + "ko": "죽 전문점 (본죽 등 체인)", + "en": "Korean porridge (Bonjuk and similar chains)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.5, + "indoor": true, + "area": { + "ko": "청담·삼성", + "en": "Cheongdam / Samseong" + }, + "note": { + "ko": "부드러운 식사 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", + "en": "Porridge for the soft-food stage, by delivery or takeout." + }, + "mapQuery": "본죽 청담", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "smoothie", + "name": { + "ko": "스무디·주스 카페 (청담)", + "en": "Smoothie and juice cafes (Cheongdam)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.4, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", + "en": "Straw-friendly options. Choose nothing hot." + }, + "mapQuery": "스무디 카페 청담역", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "seolleongtang", + "name": { + "ko": "설렁탕·곰탕 (청담·삼성 일대)", + "en": "Seolleongtang beef bone soup (Cheongdam area)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.6, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다.", + "en": "Broth-based, fine from the soft-food stage." + }, + "mapQuery": "설렁탕 청담역", + "verify": true, + "dietOk": [ + "soft", + "mild", + "normal" + ] + }, + { + "id": "cafe-cheongdam", + "name": { + "ko": "청담 카페 거리", + "en": "Cheongdam cafes" + }, + "category": "food", + "minLevel": 2, + "distanceKm": 0.5, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "조용한 카페가 많아 오후에 잠깐 앉아 있기 좋습니다.", + "en": "Quiet cafes, good for a short afternoon sit-down." + }, + "mapQuery": "청담 카페", + "verify": true, + "dietOk": [ + "soft", + "mild", + "normal" + ] + }, + { + "id": "hansik-cheongdam", + "name": { + "ko": "청담·압구정 한식", + "en": "Korean set meals (Cheongdam / Apgujeong)" + }, + "category": "food", + "minLevel": 2, + "distanceKm": 0.7, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "일반식이 가능한 단계부터입니다.", + "en": "From the regular-diet stage." + }, + "mapQuery": "한식 청담", + "verify": true, + "dietOk": [ + "normal" + ] + }, + { + "id": "cheongdam-luxury", + "name": { + "ko": "청담 명품거리", + "en": "Cheongdam luxury street" + }, + "category": "shopping", + "minLevel": 2, + "distanceKm": 0.5, + "indoor": false, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "명품 플래그십 매장이 이어지는 거리입니다. 택시로 3분.", + "en": "A street of luxury flagship stores. 3 minutes by taxi." + }, + "mapQuery": "청담 명품거리", + "verify": true + }, + { + "id": "galleria", + "name": { + "ko": "갤러리아백화점 명품관", + "en": "Galleria Department Store" + }, + "category": "shopping", + "minLevel": 2, + "distanceKm": 0.9, + "indoor": true, + "area": { + "ko": "압구정", + "en": "Apgujeong" + }, + "note": { + "ko": "실내 백화점입니다. 배송 서비스를 이용하면 짐을 들지 않아도 됩니다.", + "en": "Indoor department store. Use the delivery counter so you carry nothing." + }, + "mapQuery": "갤러리아백화점 명품관", + "verify": true + }, + { + "id": "apgujeong-rodeo", + "name": { + "ko": "압구정 로데오·K-Star Road", + "en": "Apgujeong Rodeo and K-Star Road" + }, + "category": "kpop", + "minLevel": 2, + "distanceKm": 0.6, + "indoor": false, + "area": { + "ko": "압구정", + "en": "Apgujeong" + }, + "note": { + "ko": "기획사 건물과 아이돌 조형물이 있는 거리입니다. 걸어서도 갑니다.", + "en": "Street of entertainment agencies and idol art figures, within walking distance." + }, + "mapQuery": "K-Star Road 압구정", + "verify": true + }, + { + "id": "coex", + "name": { + "ko": "코엑스몰·별마당도서관", + "en": "COEX Mall and Starfield Library" + }, + "category": "shopping", + "minLevel": 2, + "distanceKm": 2.1, + "indoor": true, + "area": { + "ko": "삼성동", + "en": "Samseong" + }, + "note": { + "ko": "실내 쇼핑몰과 도서관, 아쿠아리움이 한 건물에 있습니다.", + "en": "Indoor mall, library and aquarium in one building." + }, + "mapQuery": "코엑스몰", + "verify": true + }, + { + "id": "dosan-park", + "name": { + "ko": "도산공원", + "en": "Dosan Park" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 0.9, + "indoor": false, + "area": { + "ko": "신사동", + "en": "Sinsa" + }, + "note": { + "ko": "평지 산책로가 있는 공원입니다. 20분 정도 걷기 좋습니다.", + "en": "Flat paths, good for a 20-minute walk." + }, + "mapQuery": "도산공원", + "verify": true + }, + { + "id": "seonjeongneung", + "name": { + "ko": "선정릉", + "en": "Seonjeongneung Royal Tombs" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 1.6, + "indoor": false, + "area": { + "ko": "선릉", + "en": "Seolleung" + }, + "note": { + "ko": "유네스코 세계유산 왕릉입니다. 숲길이 그늘져서 햇빛을 피하기 좋습니다.", + "en": "UNESCO World Heritage royal tombs with shaded forest paths." + }, + "mapQuery": "선정릉", + "verify": true + }, + { + "id": "bongeunsa", + "name": { + "ko": "봉은사", + "en": "Bongeunsa Temple" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 2.2, + "indoor": false, + "area": { + "ko": "삼성동", + "en": "Samseong" + }, + "note": { + "ko": "코엑스 맞은편의 사찰입니다. 경사가 완만합니다.", + "en": "Temple across from COEX. Gentle slopes." + }, + "mapQuery": "봉은사", + "verify": true + }, + { + "id": "hangang", + "name": { + "ko": "압구정·잠원 한강공원", + "en": "Apgujeong and Jamwon Hangang Park" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 1.5, + "indoor": false, + "area": { + "ko": "압구정", + "en": "Apgujeong" + }, + "note": { + "ko": "강변 산책로입니다. 저녁에 걷기 좋습니다.", + "en": "Riverside walk, good in the evening." + }, + "mapQuery": "압구정 한강공원", + "verify": true + }, + { + "id": "seongsu", + "name": { + "ko": "성수동 카페·팝업", + "en": "Seongsu cafes and pop-ups" + }, + "category": "kpop", + "minLevel": 3, + "distanceKm": 3.5, + "indoor": false, + "area": { + "ko": "성수동", + "en": "Seongsu" + }, + "note": { + "ko": "브랜드 팝업과 카페가 모인 동네입니다. 주말은 인파가 많습니다.", + "en": "Brand pop-ups and cafes. Crowded on weekends." + }, + "mapQuery": "성수동 팝업", + "verify": true + }, + { + "id": "kakao-gangnam", + "name": { + "ko": "카카오프렌즈 강남 플래그십", + "en": "Kakao Friends Gangnam Flagship" + }, + "category": "kpop", + "minLevel": 2, + "distanceKm": 2.6, + "indoor": true, + "area": { + "ko": "강남역", + "en": "Gangnam Station" + }, + "note": { + "ko": "캐릭터 굿즈 매장입니다. 택시로 10분.", + "en": "Character merchandise store, 10 minutes by taxi." + }, + "mapQuery": "카카오프렌즈 강남플래그십스토어", + "verify": true + }, + { + "id": "lotte-tower", + "name": { + "ko": "롯데월드타워·서울스카이", + "en": "Lotte World Tower and Seoul Sky" + }, + "category": "sightseeing", + "minLevel": 3, + "distanceKm": 6, + "indoor": true, + "area": { + "ko": "잠실", + "en": "Jamsil" + }, + "note": { + "ko": "실내 전망대와 쇼핑몰입니다. 택시로 20분.", + "en": "Indoor observatory and mall. 20 minutes by taxi." + }, + "mapQuery": "롯데월드타워", + "verify": true + }, + { + "id": "gyeongbokgung", + "name": { + "ko": "경복궁·북촌", + "en": "Gyeongbokgung Palace and Bukchon" + }, + "category": "sightseeing", + "minLevel": 3, + "distanceKm": 8, + "indoor": false, + "area": { + "ko": "종로", + "en": "Jongno" + }, + "note": { + "ko": "택시로 30분 이상 걸립니다. 자유 외출 단계에서 가세요.", + "en": "Over 30 minutes by taxi. Save for full-day outings." + }, + "mapQuery": "경복궁", + "verify": true + }, + { + "id": "myeongdong", + "name": { + "ko": "명동", + "en": "Myeongdong" + }, + "category": "shopping", + "minLevel": 3, + "distanceKm": 7, + "indoor": false, + "area": { + "ko": "중구", + "en": "Jung-gu" + }, + "note": { + "ko": "화장품과 길거리 음식이 많습니다. 인파가 많으니 부딪히지 않게 다니세요.", + "en": "Cosmetics and street food. Crowded, so mind bumps." + }, + "mapQuery": "명동", + "verify": true + }, + { + "id": "hongdae", + "name": { + "ko": "홍대", + "en": "Hongdae" + }, + "category": "kpop", + "minLevel": 3, + "distanceKm": 12, + "indoor": false, + "area": { + "ko": "홍대입구", + "en": "Hongik Univ." + }, + "note": { + "ko": "버스킹과 굿즈숍이 있습니다. 왕복 1시간 이상 걸립니다.", + "en": "Busking and merch shops. Over an hour round trip." + }, + "mapQuery": "홍대 걷고싶은거리", + "verify": true + }, + { + "id": "clinic-aftercare", + "name": { + "ko": "오라클피부과 경과 확인", + "en": "Oracle Dermatology follow-up" + }, + "category": "care", + "minLevel": 1, + "distanceKm": 0.05, + "indoor": true, + "area": { + "ko": "병원", + "en": "Clinic" + }, + "note": { + "ko": "경과 확인과 관리는 병원 안내에 따라 예약합니다.", + "en": "Follow-up checks and care, booked per the clinic's guidance." + }, + "mapQuery": "오라클피부과 청담", + "verify": true + }, + { + "id": "hotel-lounge", + "name": { + "ko": "호텔 스파·라운지 (숙소 안)", + "en": "Hotel spa and lounge (at your hotel)" + }, + "category": "care", + "minLevel": 0, + "distanceKm": 0, + "indoor": true, + "area": { + "ko": "숙소", + "en": "Your hotel" + }, + "note": { + "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", + "en": "Skip sauna and massage until your doctor allows. Lounge and room service are fine." + }, + "mapQuery": null, + "verify": true + }, + { + "id": "hotel-andaz", + "name": { + "ko": "안다즈 서울 강남", + "en": "Andaz Seoul Gangnam" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 1.0, + "indoor": true, + "area": { + "ko": "압구정 로데오", + "en": "Apgujeong Rodeo" + }, + "note": { + "ko": "압구정 로데오의 고급 호텔입니다. 병원까지 택시로 5분.", + "en": "Upscale hotel at Apgujeong Rodeo. 5 minutes to the clinic by taxi." + }, + "mapQuery": "안다즈 서울 강남", + "verify": true, + "bookingQuery": "Andaz Seoul Gangnam" + }, + { + "id": "hotel-riviera", + "name": { + "ko": "호텔 리베라 청담", + "en": "Hotel Riviera Cheongdam" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 1.0, + "indoor": true, + "area": { + "ko": "청담동", + "en": "Cheongdam" + }, + "note": { + "ko": "영동대교 남단의 호텔입니다. 병원까지 택시로 5분.", + "en": "Hotel at the south end of Yeongdong Bridge. 5 minutes to the clinic by taxi." + }, + "mapQuery": "호텔 리베라 청담", + "verify": true, + "bookingQuery": "Hotel Riviera Cheongdam Seoul" + }, + { + "id": "hotel-parkhyatt", + "name": { + "ko": "파크 하얏트 서울", + "en": "Park Hyatt Seoul" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 2.0, + "indoor": true, + "area": { + "ko": "삼성역", + "en": "Samseong Station" + }, + "note": { + "ko": "삼성역 앞 고급 호텔입니다. 병원까지 택시로 10분.", + "en": "Luxury hotel at Samseong Station. 10 minutes to the clinic by taxi." + }, + "mapQuery": "파크 하얏트 서울", + "verify": true, + "bookingQuery": "Park Hyatt Seoul" + }, + { + "id": "hotel-intercontinental", + "name": { + "ko": "인터컨티넨탈 서울 코엑스", + "en": "InterContinental Seoul COEX" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 2.0, + "indoor": true, + "area": { + "ko": "삼성동", + "en": "Samseong" + }, + "note": { + "ko": "코엑스와 연결된 호텔입니다. 병원까지 택시로 10분.", + "en": "Connected to COEX. 10 minutes to the clinic by taxi." + }, + "mapQuery": "인터컨티넨탈 서울 코엑스", + "verify": true, + "bookingQuery": "InterContinental Seoul COEX" + }, + { + "id": "hotel-josun", + "name": { + "ko": "조선 팰리스 강남", + "en": "Josun Palace Seoul Gangnam" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 2.6, + "indoor": true, + "area": { + "ko": "역삼동", + "en": "Yeoksam" + }, + "note": { + "ko": "역삼동의 고급 호텔입니다. 병원까지 택시로 10분.", + "en": "Luxury hotel in Yeoksam. 10 minutes to the clinic by taxi." + }, + "mapQuery": "조선 팰리스 서울 강남", + "verify": true, + "bookingQuery": "Josun Palace Seoul Gangnam" + } + ] +} diff --git a/supporters/briefs/viewclinic/planner.places.json b/supporters/briefs/viewclinic/planner.places.json new file mode 100644 index 0000000..bbf62d5 --- /dev/null +++ b/supporters/briefs/viewclinic/planner.places.json @@ -0,0 +1,47 @@ +{ + "_comment": "회복기 스케줄러 큐레이션 장소 (설계 v0.2 §13.5 1순위 소스). 기준점은 신논현역(뷰성형외과). distanceKm 는 직선 거리 근사값이고 verify 가 true 인 항목은 출시 전 영업 여부·거리를 확인한다. 링크는 구글 지도 검색과 예약 사이트 검색 결과만 쓴다(지어낸 상세 URL 없음). 축제·행사(날짜 의존)는 한국관광공사 Tour API 연결(P1) 뒤에 추가한다.", + "origin": { "label": { "ko": "신논현역 3번 출구", "en": "Sinnonhyeon Station Exit 3" }, "lat": 37.5045, "lng": 127.0250 }, + "categories": { + "sightseeing": { "ko": "관광", "en": "Sightseeing" }, + "shopping": { "ko": "쇼핑", "en": "Shopping" }, + "food": { "ko": "미식", "en": "Food" }, + "kpop": { "ko": "K-pop·핫플", "en": "K-pop & hotspots" }, + "care": { "ko": "휴식·케어", "en": "Rest & care" }, + "essentials": { "ko": "생활", "en": "Essentials" }, + "hotel": { "ko": "숙소", "en": "Hotels" } + }, + "places": [ + { "id": "pharmacy-sinnonhyeon", "name": { "ko": "신논현역 주변 약국", "en": "Pharmacies near Sinnonhyeon Station" }, "category": "essentials", "minLevel": 1, "distanceKm": 0.2, "indoor": true, "area": { "ko": "신논현", "en": "Sinnonhyeon" }, "note": { "ko": "병원 건물 옆 골목에 약국이 있습니다. 처방약과 냉찜질 팩을 구할 수 있습니다.", "en": "Pharmacies in the alley next to the clinic building. Prescriptions and cold packs." }, "mapQuery": "약국 신논현역", "verify": true }, + { "id": "convenience-sinnonhyeon", "name": { "ko": "편의점 (신논현역 일대)", "en": "Convenience stores (Sinnonhyeon area)" }, "category": "essentials", "minLevel": 1, "distanceKm": 0.1, "indoor": true, "area": { "ko": "신논현", "en": "Sinnonhyeon" }, "note": { "ko": "생수, 죽, 빨대, 얼음을 24시간 살 수 있습니다.", "en": "Water, porridge, straws and ice, 24 hours." }, "mapQuery": "편의점 신논현역", "verify": false }, + { "id": "porridge-chain", "name": { "ko": "죽 전문점 (본죽 등 체인)", "en": "Korean porridge (Bonjuk and similar chains)" }, "category": "food", "minLevel": 1, "dietOk": ["liquid", "soft", "mild", "normal"], "distanceKm": 0.4, "indoor": true, "area": { "ko": "신논현·강남", "en": "Sinnonhyeon / Gangnam" }, "note": { "ko": "유동식 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", "en": "Porridge suitable for the liquid-diet stage, by delivery or takeout." }, "mapQuery": "본죽 신논현역", "verify": true }, + { "id": "smoothie-cafe", "name": { "ko": "스무디·주스 카페 (강남대로)", "en": "Smoothie and juice cafes (Gangnam-daero)" }, "category": "food", "minLevel": 1, "dietOk": ["liquid", "soft", "mild", "normal"], "distanceKm": 0.5, "indoor": true, "area": { "ko": "강남대로", "en": "Gangnam-daero" }, "note": { "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", "en": "Plenty of straw-friendly options. Choose nothing hot." }, "mapQuery": "스무디 카페 신논현역", "verify": true }, + { "id": "seolleongtang", "name": { "ko": "설렁탕·곰탕 (강남 일대)", "en": "Seolleongtang beef bone soup (Gangnam area)" }, "category": "food", "minLevel": 1, "dietOk": ["soft", "mild", "normal"], "distanceKm": 0.6, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다. 밥을 말아 천천히 드세요.", "en": "Broth-based, fine from the soft-food stage. Eat slowly with rice in the soup." }, "mapQuery": "설렁탕 강남역", "verify": true }, + { "id": "sulbing", "name": { "ko": "설빙 (빙수 디저트)", "en": "Sulbing shaved-ice dessert" }, "category": "food", "minLevel": 1, "dietOk": ["soft", "mild", "normal"], "distanceKm": 0.6, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "차갑고 부드러워 부기가 있을 때도 먹기 편합니다.", "en": "Cold and soft, comfortable even with swelling." }, "mapQuery": "설빙 강남", "verify": true }, + { "id": "cafe-garosugil", "name": { "ko": "가로수길 카페", "en": "Garosu-gil cafes" }, "category": "food", "minLevel": 2, "dietOk": ["soft", "mild", "normal"], "distanceKm": 1.2, "indoor": true, "area": { "ko": "신사동 가로수길", "en": "Garosu-gil, Sinsa" }, "note": { "ko": "조용한 카페가 많아 오후에 잠깐 앉아 있기 좋습니다.", "en": "Quiet cafes, good for a short afternoon sit-down." }, "mapQuery": "가로수길 카페", "verify": false }, + { "id": "korean-bbq-gangnam", "name": { "ko": "강남 한식·구이", "en": "Korean BBQ and set meals (Gangnam)" }, "category": "food", "minLevel": 2, "dietOk": ["normal"], "distanceKm": 0.8, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "일반식이 가능한 단계부터입니다. 담당 원장이 술을 허용하기 전에는 음료로 대신하세요.", "en": "From the regular-diet stage. Skip alcohol until your surgeon allows it." }, "mapQuery": "한식 맛집 강남역", "verify": false }, + { "id": "garosugil", "name": { "ko": "가로수길", "en": "Garosu-gil" }, "category": "shopping", "minLevel": 2, "distanceKm": 1.2, "indoor": false, "area": { "ko": "신사동", "en": "Sinsa" }, "note": { "ko": "편집숍과 뷰티 매장이 모여 있는 거리입니다. 택시로 5분.", "en": "A street of boutiques and beauty stores. 5 minutes by taxi." }, "mapQuery": "가로수길", "verify": false }, + { "id": "oliveyoung-gangnam", "name": { "ko": "올리브영 강남 타운", "en": "Olive Young Gangnam Town" }, "category": "shopping", "minLevel": 2, "distanceKm": 0.9, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "K-뷰티 대형 매장입니다. 수술 부위에 닿는 화장품은 담당 원장 안내를 따르세요.", "en": "Large K-beauty store. Follow your surgeon's guidance on products near the surgical area." }, "mapQuery": "올리브영 강남타운", "verify": true }, + { "id": "shinsegae-gangnam", "name": { "ko": "신세계백화점 강남점", "en": "Shinsegae Department Store Gangnam" }, "category": "shopping", "minLevel": 2, "distanceKm": 2.4, "indoor": true, "area": { "ko": "고속터미널", "en": "Express Bus Terminal" }, "note": { "ko": "지하 파미에스테이션과 연결됩니다. 실내라 날씨와 상관없이 다닐 수 있습니다.", "en": "Connected to the Famille Station underground mall. Fully indoors." }, "mapQuery": "신세계백화점 강남점", "verify": false }, + { "id": "hyundai-apgujeong", "name": { "ko": "현대백화점 압구정본점", "en": "Hyundai Department Store Apgujeong" }, "category": "shopping", "minLevel": 2, "distanceKm": 2.0, "indoor": true, "area": { "ko": "압구정", "en": "Apgujeong" }, "note": { "ko": "택시로 10분. 배송 서비스를 이용하면 짐을 들지 않아도 됩니다.", "en": "10 minutes by taxi. Use the delivery counter so you carry nothing." }, "mapQuery": "현대백화점 압구정본점", "verify": false }, + { "id": "coex-mall", "name": { "ko": "코엑스몰·별마당도서관", "en": "COEX Mall and Starfield Library" }, "category": "shopping", "minLevel": 2, "distanceKm": 3.4, "indoor": true, "area": { "ko": "삼성동", "en": "Samseong" }, "note": { "ko": "실내 쇼핑몰과 도서관, 아쿠아리움이 한 건물에 있습니다.", "en": "Indoor mall, library and aquarium in one building." }, "mapQuery": "코엑스몰", "verify": false }, + { "id": "apgujeong-rodeo", "name": { "ko": "압구정 로데오·K-Star Road", "en": "Apgujeong Rodeo and K-Star Road" }, "category": "kpop", "minLevel": 2, "distanceKm": 2.6, "indoor": false, "area": { "ko": "압구정", "en": "Apgujeong" }, "note": { "ko": "기획사 건물과 아이돌 조형물이 있는 거리입니다.", "en": "Street of entertainment agencies and idol art figures." }, "mapQuery": "K-Star Road 압구정", "verify": true }, + { "id": "kwangya-seongsu", "name": { "ko": "KWANGYA@SEOUL (성수)", "en": "KWANGYA@SEOUL (Seongsu)" }, "category": "kpop", "minLevel": 3, "distanceKm": 5.5, "indoor": true, "area": { "ko": "성수동", "en": "Seongsu" }, "note": { "ko": "SM 엔터테인먼트 공식 굿즈 매장입니다. 운영 시간을 확인하고 가세요.", "en": "SM Entertainment's official merchandise store. Check hours before visiting." }, "mapQuery": "KWANGYA@SEOUL", "verify": true }, + { "id": "seongsu", "name": { "ko": "성수동 카페·팝업", "en": "Seongsu cafes and pop-ups" }, "category": "kpop", "minLevel": 3, "distanceKm": 5.5, "indoor": false, "area": { "ko": "성수동", "en": "Seongsu" }, "note": { "ko": "브랜드 팝업과 카페가 모인 동네입니다. 주말은 인파가 많습니다.", "en": "Brand pop-ups and cafes. Crowded on weekends." }, "mapQuery": "성수동 팝업", "verify": false }, + { "id": "hongdae", "name": { "ko": "홍대", "en": "Hongdae" }, "category": "kpop", "minLevel": 3, "distanceKm": 11, "indoor": false, "area": { "ko": "홍대입구", "en": "Hongik Univ." }, "note": { "ko": "버스킹과 굿즈숍이 있습니다. 왕복 1시간 이상 걸리니 자유 외출 단계에서 가세요.", "en": "Busking and merch shops. Over an hour round trip, so save it for full-day outings." }, "mapQuery": "홍대 걷고싶은거리", "verify": false }, + { "id": "kakao-friends-gangnam", "name": { "ko": "카카오프렌즈 강남 플래그십", "en": "Kakao Friends Gangnam Flagship" }, "category": "kpop", "minLevel": 2, "distanceKm": 0.9, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "캐릭터 굿즈 매장입니다. 걸어서도 갈 수 있는 거리입니다.", "en": "Character merchandise store, within walking distance." }, "mapQuery": "카카오프렌즈 강남플래그십스토어", "verify": true }, + { "id": "bongeunsa", "name": { "ko": "봉은사", "en": "Bongeunsa Temple" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 3.6, "indoor": false, "area": { "ko": "삼성동", "en": "Samseong" }, "note": { "ko": "코엑스 맞은편의 사찰입니다. 경사가 완만해 천천히 걷기 좋습니다.", "en": "Temple across from COEX. Gentle slopes, good for a slow walk." }, "mapQuery": "봉은사", "verify": false }, + { "id": "seonjeongneung", "name": { "ko": "선정릉", "en": "Seonjeongneung Royal Tombs" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 2.4, "indoor": false, "area": { "ko": "선릉", "en": "Seolleung" }, "note": { "ko": "유네스코 세계유산 왕릉입니다. 숲길이 그늘져서 햇빛을 피하기 좋습니다.", "en": "UNESCO World Heritage royal tombs. Shaded forest paths." }, "mapQuery": "선정릉", "verify": false }, + { "id": "banpo-hangang", "name": { "ko": "반포한강공원·달빛무지개분수", "en": "Banpo Hangang Park and Moonlight Rainbow Fountain" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 2.8, "indoor": false, "area": { "ko": "반포", "en": "Banpo" }, "note": { "ko": "저녁에 분수 공연을 볼 수 있습니다. 운영 기간을 확인하세요.", "en": "Evening fountain show. Check the season schedule." }, "mapQuery": "반포한강공원", "verify": false }, + { "id": "gyeongbokgung", "name": { "ko": "경복궁·북촌", "en": "Gyeongbokgung Palace and Bukchon" }, "category": "sightseeing", "minLevel": 3, "distanceKm": 9, "indoor": false, "area": { "ko": "종로", "en": "Jongno" }, "note": { "ko": "택시로 30분 이상 걸립니다. 걷는 시간이 길어 자유 외출 단계에서 가세요.", "en": "Over 30 minutes by taxi and a lot of walking. Save for full-day outings." }, "mapQuery": "경복궁", "verify": false }, + { "id": "lotte-tower", "name": { "ko": "롯데월드타워·서울스카이", "en": "Lotte World Tower and Seoul Sky" }, "category": "sightseeing", "minLevel": 3, "distanceKm": 8, "indoor": true, "area": { "ko": "잠실", "en": "Jamsil" }, "note": { "ko": "실내 전망대와 쇼핑몰입니다. 택시로 25분.", "en": "Indoor observatory and mall. 25 minutes by taxi." }, "mapQuery": "롯데월드타워", "verify": false }, + { "id": "myeongdong", "name": { "ko": "명동", "en": "Myeongdong" }, "category": "shopping", "minLevel": 3, "distanceKm": 7, "indoor": false, "area": { "ko": "중구", "en": "Jung-gu" }, "note": { "ko": "화장품과 길거리 음식이 많습니다. 인파가 많으니 부딪히지 않게 다니세요.", "en": "Cosmetics and street food. Crowded, so mind bumps." }, "mapQuery": "명동", "verify": false }, + { "id": "clinic-aftercare", "name": { "ko": "뷰성형외과 애프터케어", "en": "View Plastic Surgery Aftercare" }, "category": "care", "minLevel": 1, "distanceKm": 0.05, "indoor": true, "area": { "ko": "병원", "en": "Clinic" }, "note": { "ko": "고주파 관리와 경과 확인은 병원 안내에 따라 예약합니다.", "en": "Radiofrequency care and follow-up checks, booked per the clinic's guidance." }, "mapQuery": "뷰성형외과", "verify": false }, + { "id": "clinic-dental", "name": { "ko": "뷰성형외과 15층 치과", "en": "View Plastic Surgery Dental Clinic (15F)" }, "category": "care", "minLevel": 1, "distanceKm": 0.05, "indoor": true, "area": { "ko": "병원", "en": "Clinic" }, "note": { "ko": "양악·윤곽 협진 치과입니다. 여유 시간에 검진을 받을 수 있는지 상담에서 물어보세요.", "en": "Dental clinic for jaw and contouring cases. Ask at consultation about a check-up during your stay." }, "mapQuery": "뷰성형외과", "verify": false }, + { "id": "hotel-spa-gangnam", "name": { "ko": "호텔 스파·라운지 (숙소 안)", "en": "Hotel spa and lounge (at your hotel)" }, "category": "care", "minLevel": 0, "distanceKm": 0, "indoor": true, "area": { "ko": "숙소", "en": "Your hotel" }, "note": { "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", "en": "Skip sauna and massage until your surgeon allows. Lounge and room service are fine." }, "mapQuery": null, "verify": false }, + { "id": "hotel-cappuccino", "name": { "ko": "호텔 카푸치노", "en": "Hotel Cappuccino" }, "category": "hotel", "minLevel": 0, "distanceKm": 0.5, "indoor": true, "area": { "ko": "논현동 봉은사로", "en": "Nonhyeon, Bongeunsa-ro" }, "note": { "ko": "병원과 같은 봉은사로에 있어 걸어서 다닐 수 있습니다.", "en": "On the same road as the clinic, within walking distance." }, "mapQuery": "호텔 카푸치노 논현", "bookingQuery": "Hotel Cappuccino Seoul", "verify": true }, + { "id": "novotel-gangnam", "name": { "ko": "노보텔 앰배서더 강남", "en": "Novotel Ambassador Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.0, "indoor": true, "area": { "ko": "역삼동", "en": "Yeoksam" }, "note": { "ko": "강남역 근처 대형 호텔입니다. 룸서비스와 24시간 프런트가 있습니다.", "en": "Large hotel near Gangnam Station with room service and a 24-hour front desk." }, "mapQuery": "노보텔 앰배서더 강남", "bookingQuery": "Novotel Ambassador Seoul Gangnam", "verify": true }, + { "id": "l7-gangnam", "name": { "ko": "L7 강남 바이 롯데", "en": "L7 Gangnam by Lotte" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.4, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "강남역 인근이며 택시로 5분입니다.", "en": "Near Gangnam Station, 5 minutes by taxi." }, "mapQuery": "L7 강남", "bookingQuery": "L7 Gangnam by Lotte", "verify": true }, + { "id": "andaz-gangnam", "name": { "ko": "안다즈 서울 강남", "en": "Andaz Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 2.6, "indoor": true, "area": { "ko": "압구정 로데오", "en": "Apgujeong Rodeo" }, "note": { "ko": "압구정 로데오에 있는 고급 호텔입니다. 병원까지 택시로 10분.", "en": "Upscale hotel at Apgujeong Rodeo. 10 minutes to the clinic by taxi." }, "mapQuery": "안다즈 서울 강남", "bookingQuery": "Andaz Seoul Gangnam", "verify": true }, + { "id": "josun-palace", "name": { "ko": "조선 팰리스 강남", "en": "Josun Palace Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.8, "indoor": true, "area": { "ko": "역삼동", "en": "Yeoksam" }, "note": { "ko": "역삼동의 고급 호텔입니다. 병원까지 택시로 10분.", "en": "Luxury hotel in Yeoksam. 10 minutes to the clinic by taxi." }, "mapQuery": "조선 팰리스 서울 강남", "bookingQuery": "Josun Palace Seoul Gangnam", "verify": true } + ] +} diff --git a/supporters/scripts/build_planner_data.mjs b/supporters/scripts/build_planner_data.mjs new file mode 100644 index 0000000..b7efae5 --- /dev/null +++ b/supporters/scripts/build_planner_data.mjs @@ -0,0 +1,83 @@ +// 회복 일정 플래너 병원별 데이터 생성 (워커 planner 단계). 설계 v0.2 §13. +// node scripts/build_planner_data.mjs --clinic --site [--industry derm|plastic] +// +// 만드는 것 +// /src/data/procedures.json 업종별 기본 규칙표(scripts/template/planner/procedures..json)에 +// 병원 시술 페이지 원문(recoveryNotes.json)의 관리 문장을 matchKeywords 로 시술에 붙인다. +// 원문 문장은 status clinic 으로 출처(URL)와 함께 들어가고, 나머지 값은 provisional(병원 확인 전) 그대로다. +// /src/data/places.json briefs//planner.places.json 이 있으면 그것(병원별 큐레이션), 없으면 범용 기본표 +// (scripts/template/planner/places.base.json)에 병원 이름·지역을 치환하고 origin 을 관광공사 수집 기준 좌표로 채운다. +// 원칙: 없는 값을 채우지 않는다. 의학 수치는 병원 원문 문장만 clinic 이고, 그 밖은 화면에 '병원 확인 전' 배지가 붙는다. +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const SUP = resolve(fileURLToPath(new URL('../', import.meta.url))); +const args = process.argv.slice(2); +const opt = (k, d) => { const i = args.indexOf(`--${k}`); return i >= 0 && args[i + 1] && !args[i + 1].startsWith('--') ? args[i + 1] : d; }; +const clinic = opt('clinic'); const SITE = opt('site'); +if (!clinic || !SITE) { console.error('사용법: --clinic --site [--industry derm|plastic]'); process.exit(2); } +const DATA = join(SITE, 'src', 'data'); +const readJson = (p) => JSON.parse(readFileSync(p, 'utf8')); +const writeJson = (p, o) => { mkdirSync(join(p, '..'), { recursive: true }); writeFileSync(p, JSON.stringify(o, null, 2) + '\n'); }; + +const fact = existsSync(join(DATA, 'factSheet.json')) ? readJson(join(DATA, 'factSheet.json')) : {}; +const pinPath = join(SUP, 'briefs', clinic, 'clinic.json'); +const pin = existsSync(pinPath) ? readJson(pinPath) : {}; + +// 업종: --industry > briefs/clinic.json industry > 팩트 시트 kind(피부과) > plastic +const industry = (() => { + const forced = opt('industry') || pin.industry; + if (forced && ['derm', 'plastic'].includes(forced)) return forced; + return /피부/.test(String(fact.kind ?? '') + String(pin.factSheet?.kind ?? '')) ? 'derm' : 'plastic'; +})(); +const basePath = join(SUP, 'scripts', 'template', 'planner', `procedures.${industry}.json`); +const base = readJson(basePath); + +// ---------- 규칙표: 병원 원문 문장 붙이기 ---------- +const notesPath = join(DATA, 'recoveryNotes.json'); +const notes = existsSync(notesPath) ? readJson(notesPath) : { items: [] }; +const shortName = fact.shortName || fact.name || clinic; +let attached = 0, unmatched = []; +for (const it of notes.items ?? []) { + const target = base.procedures.find((p) => p.matchKeywords && new RegExp(p.matchKeywords).test(it.procedure)); + if (!target) { unmatched.push(it.procedure); continue; } + const doc = (it.url.match(/doc=(\d+)/) || [])[1] ?? it.url.replace(/[^a-z0-9]+/gi, '-').slice(-24); + const srcId = `note-${doc}`; + if (!base.clinicSources.some((s) => s.id === srcId)) { + base.clinicSources.push({ id: srcId, label: { ko: `${shortName} 홈페이지 · ${it.procedure} 시술 안내`, en: `${shortName} website · ${it.procedureEn || it.procedure}` }, url: it.url, accessed: it.fetchedAt || notes.generatedAt || '' }); + } + (it.ko ?? []).forEach((ko, i) => { + const en = (it.en ?? [])[i] || ko; // 번역 실패 문장은 한글 원문 그대로 (워커 recovery 단계와 같은 규칙) + const cid = `${srcId}-${i}`; + base.constraints[cid] = { ko: ko.trim(), en: en.trim() }; + if (!target.constraints.includes(cid)) target.constraints.unshift(cid); // 병원 원문이 잠정 안내보다 먼저 보이게 + attached++; + }); + if (!target.sources.includes(srcId)) target.sources.push(srcId); +} +for (const p of base.procedures) delete p.matchKeywords; +base._comment = `${shortName} 회복 일정 플래너 규칙표 (${industry === 'derm' ? '피부과' : '성형외과'} 기본표 + 병원 시술 페이지 원문 ${attached}문장). clinic = 병원 원문, provisional = 병원 확인 전 잠정값(화면 배지). 생성 ${new Date().toISOString().slice(0, 10)}, 워커 planner 단계.`; +writeJson(join(DATA, 'procedures.json'), base); + +// ---------- 장소: 병원별 큐레이션 또는 범용 기본표 ---------- +const curated = join(SUP, 'briefs', clinic, 'planner.places.json'); +let placesSummary; +if (existsSync(curated)) { + writeJson(join(DATA, 'places.json'), readJson(curated)); + placesSummary = `큐레이션 ${readJson(curated).places.length}곳 (briefs/${clinic}/planner.places.json)`; +} else { + const tpl = readJson(join(SUP, 'scripts', 'template', 'planner', 'places.base.json')); + const tourPath = join(DATA, 'medicalTourismKo.json'); + const origin = existsSync(tourPath) ? (readJson(tourPath).meta?.origin ?? {}) : {}; + const areaKo = fact.areaLabel || fact.address?.locality || shortName; + const areaEn = fact.areaLabelEn || fact.address?.localityEn || (fact.shortNameEn || shortName); + const nameEn = fact.shortNameEn || fact.nameEn || shortName; + const sub = (s) => String(s).replaceAll('{CLINIC_KO}', shortName).replaceAll('{CLINIC_EN}', nameEn).replaceAll('{AREA_KO}', areaKo).replaceAll('{AREA_EN}', areaEn); + const out = JSON.parse(sub(JSON.stringify(tpl))); + out.origin = { label: { ko: `${shortName}${fact.address?.street ? ` (${fact.address.street})` : ''}`, en: nameEn }, lat: origin.lat ?? 0, lng: origin.lng ?? 0 }; + out._comment = `${shortName} 범용 큐레이션(기본표 치환). 병원별 큐레이션은 briefs/${clinic}/planner.places.json 으로 준다. 숙소·관광지·행사는 관광공사 데이터(medicalTourism*.json)가 맡는다.`; + writeJson(join(DATA, 'places.json'), out); + placesSummary = `범용 기본표 ${out.places.length}곳 (origin ${origin.lat ? `${origin.lat}, ${origin.lng}` : '없음'})`; +} +console.log(`planner: 업종 ${industry} · 시술 ${base.procedures.length}종 · 병원 원문 ${attached}문장 붙임${unmatched.length ? ` · 매칭 안 된 시술 ${unmatched.length}(${unmatched.slice(0, 4).join(', ')})` : ''} · ${placesSummary}`); diff --git a/supporters/scripts/check.mjs b/supporters/scripts/check.mjs index 477fb31..df7fb2c 100644 --- a/supporters/scripts/check.mjs +++ b/supporters/scripts/check.mjs @@ -9,6 +9,7 @@ import { readdirSync, readFileSync, statSync, existsSync, writeFileSync } from ' import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; import * as R from './gate/rules.mjs'; +import { parse as parseHtml } from 'node-html-parser'; const here = (p) => fileURLToPath(new URL(p, import.meta.url)); const DIST = here('../dist/'); @@ -35,6 +36,12 @@ function walk(dir, out = []) { return out; } +function withoutRecoveryQuote(html) { + const root = parseHtml(html); + root.querySelectorAll('#recovery-quote').forEach((el) => el.remove()); + return root.toString(); +} + const findings = []; // { where, level, code, msg } const add = (where, list) => list.forEach((x) => findings.push({ where, ...x })); @@ -47,6 +54,8 @@ const layoutNow = {}; for (const f of files) { const html = readFileSync(f, 'utf8'); const rel = f.replace(DIST, '/'); + // astro.config 의 redirects 가 만든 meta refresh 페이지(/stay → /recovery). 본문이 없으니 검사하지 않는다. + if (// 에 구조화해 저장한다. 요약 도구를 쓰지 않는다(§3-10). 없는 것은 없다고 남긴다. // // node scripts/collect_evidence.mjs --clinic viewclinic --url https://www.viewclinic.com [--out ../evidence] [--max 80] [--delay 400] +// [--extra-url http://group-site.example/branches] 같은 수집기로 받을 추가 시작 페이지(쉼표 구분·반복 가능. 다른 호스트 허용) // // 산출물 // evidence//index.json 페이지 목록(유형·글자 수·표·이미지·플래그) // evidence//pages/.json 페이지별 원문(제목·헤딩·섹션·표·목록·이미지·링크) // evidence//doctors.json 의료진 페이지에서 읽은 이름·직함·약력(이미지 글자면 textInImages=true) -// evidence//facts.draft.json 푸터·오시는길에서 정규식으로 뽑은 NAP 후보 (사람 확인 전 "확인 대기") +// evidence//facts.draft.json 푸터·오시는길에서 정규식으로 뽑은 NAP 후보 (사람 확인 전 "확인 대기"). 지점 목록 페이지가 있으면 branches 배열 // evidence//home_text.txt 전 페이지 본문 공백 제거본. 발행 게이트의 40자 연속 일치 검사 기준 +// +// 사이트 편차 대응(2026-09-10 오라클피부과 실측으로 추가) +// 1. 루트가 프레임셋·meta refresh·JS location.href 껍데기인 사이트: 리다이렉트를 최대 3단계 따라가 실제 홈을 시작 URL로 쓴다. 상대 URL은 갱신된 홈 기준으로 푼다. +// 2. EUC-KR 사이트: HTTP Content-Type → meta charset → utf-8 순으로 감지해 TextDecoder 로 디코드한다. +// 3. index.php?doc=N 처럼 쿼리가 페이지를 구분하는 사이트: 추적용 파라미터만 빼고 쿼리를 보존한다. slug 에도 쿼리를 넣는다. +// 4. 페이지 유형이 URL 경로에 없는 사이트: 앵커 텍스트·제목·h1 의 키워드(시술 어휘 포함)로 분류한다. import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -17,52 +24,102 @@ import { parse } from 'node-html-parser'; // ---------- 인자 ---------- const arg = (k, d) => { const i = process.argv.indexOf(k); return i > -1 ? process.argv[i + 1] : d; }; +const args = (k) => process.argv.flatMap((x, i) => (x === k && process.argv[i + 1] ? process.argv[i + 1].split(',') : [])).map((s) => s.trim()).filter(Boolean); const CLINIC = arg('--clinic'); const START = arg('--url'); -if (!CLINIC || !START) { console.error('사용법: --clinic --url '); process.exit(2); } +if (!CLINIC || !START) { console.error('사용법: --clinic --url [--extra-url ]'); process.exit(2); } const OUT = join(arg('--out', fileURLToPath(new URL('../../evidence/', import.meta.url))), CLINIC); const MAX = Number(arg('--max', 250)); const DELAY = Number(arg('--delay', 400)); +const EXTRA = args('--extra-url'); const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0 Safari/537.36 INFINITH-supporters-evidence/1.0 (+mailto:o2oteam@o2o.kr)'; // 일부 병원(원진)은 비브라우저 UA 를 403 으로 막는다. 브라우저 UA + 식별 문자열 const today = new Date().toISOString().slice(0, 10); // ---------- 페이지 유형 ---------- -// 순서가 우선순위. URL 경로와 앵커 텍스트 둘 다 본다. +// 시술 어휘. URL 경로에 유형이 없는 사이트(index.php?doc=N)는 앵커·제목이 시술명 그대로라서 이 사전으로 잡는다. +// 성형외과·피부과 공통. 병원 상호에 흔한 "성형외과"·"피부과" 자체는 넣지 않는다(제목 접미어 오분류 방지). +const PROCEDURE_VOCAB = /토닝|기미|색소|잡티|주근깨|검버섯|리프팅|울쎄라|써마지|인모드|슈링크|리쥬란|스킨부스터|물광|보톡스|톡신|필러|여드름|흉터|모공|제모|다한증|홍조|주름|탈모|모발이식|비만|지방분해|지방흡입|스케일링|필링|미백|레이저|사마귀|무좀|피부염|아토피|점\s*제거|문신|타투|눈성형|코성형|쌍꺼풀|매몰|절개|트임|눈매교정|안검|눈재수술|코재수술|콧볼|매부리|양악|윤곽|사각턱|광대|무턱|턱끝|가슴확대|가슴축소|가슴재수술|힙업|리프트|줄기세포|재생|주사|시술|수술|성형술/; +// 순서가 우선순위. URL 경로와 앵커 텍스트 둘 다 본다. branches 는 지점 목록·지점별 페이지(네트워크 병원). const TYPES = [ ['precautions', /precaution|caution|주의사항|주의\s*사항/i], ['aftercare', /after-?care|사후관리|애프터/i], ['checkup', /examination|check-?up|검진/i], ['safety', /\bsafe|안전/i], - ['doctor', /\bdoctors?\b|의료진|\bstaff\b|physician/i], + ['doctor', /\bdoctors?\b|의료진|\bstaff\b|physician|원장\s*(?:소개|단)/i], + ['branches', /\bbranch|\bnetwork\b|지점|네트워크\s*병원|(?:^|\s)[가-힣A-Za-z0-9]{1,10}점$/i], ['direction', /\bdirections?\d*\b|\blocation\b|오시는\s*길|찾아오|\bcontact\b|\bway-?to/i], - ['facilities', /facilit|\btour\b|둘러보|시설/i], - ['about', /\babout\b|\bintro|병원\s*소개|특별함|specialt|\bgreeting/i], + ['facilities', /facilit|\btour\b|둘러보|시설|병원\s*전경/i], + ['about', /\babout\b|\bintro|병원\s*소개|특별함|specialt|\bgreeting|인사말|소개$/i], ['reservation', /\breserv|\bcounsel|예약|상담/i], ['pricing', /\bprice|\bcost\b|비급여|수가|비용/i], + ['procedure', PROCEDURE_VOCAB], ]; -const SKIP = /\/(board|news|event|community|review|gallery|model|login|register|mypage|cart|feed|tag|category|author|wp-|xmlrpc|\?s=)|before-?and-?after|before-?after|\/(before|after)\/|\.(jpg|jpeg|png|gif|svg|pdf|css|js|ico|zip)(\?|$)|#|mailto:|tel:|javascript:/i; +const BRANCH_CAP = 20; // 지점별 페이지는 20개까지. 네트워크 병원은 지점이 수십 개라 MAX 를 다 먹는다 +const SKIP = /\/(board|news|event|community|review|gallery|model|login|register|mypage|cart|feed|tag|category|author|wp-|xmlrpc)|[?&](s|q|search|lang|language)=|\/(en|eng|zh|cn|chn|jp|jpn|ja|ru|th|vi|vn|mn|id)(\/|$)|before-?and-?after|before-?after|\/(before|after)\/|com\.php\?code=|photo\.php|\/mem_|\/join|\/logout|\/claim|\/clause|\/privacy|\/policy|\/recruit|\/real\.php|_movi|\/alliance|\.(jpg|jpeg|png|gif|svg|webp|pdf|css|js|ico|zip|ai|eps|psd|doc|docx|hwp|xls|xlsx|ppt|pptx|mp4|mov|avi)(\?|$)|#|mailto:|tel:|javascript:/i; const PROCEDURE_HINT = /수술\s*시간|마취|회복|실밥|입원|붓기|절개|시술\s*시간|수술\s*방법/; +// 지점명 후보에서 뺄 일반 명사("장점"·"단점" 같은 X점) +const NOT_BRANCH = new Set(['장점', '단점', '관점', '시점', '초점', '중점', '종점', '요점', '강점', '득점', '이점', '문제점', '차이점', '공통점', '출발점', '기준점', '지점', '거점', '정점', '원점', '점점', '접점', '분기점', '전환점', '만점', '평점', '채점', '감점', '흑점', '반점', '얼룩점']); // 경로를 먼저 보고, 경로로 못 정하면 짧은 앵커 텍스트(메뉴 항목)만 본다. 메뉴 전체가 붙은 긴 앵커는 무시. function classify(path, anchor = '') { const segs = path.split('/').filter(Boolean).map((x) => x.replace(/[-_]/g, ' ')); - for (const [t, re] of TYPES) if (segs.some((x) => re.test(x)) || re.test(path)) return t; + // 경로에는 시술 어휘를 적용하지 않는다(경로 "/surgery/" 같은 일반어가 전부 procedure 로 잡히는 것을 막는다) + for (const [t, re] of TYPES) if (t !== 'procedure' && (segs.some((x) => re.test(x)) || re.test(path))) return t; if (anchor && anchor.length <= 30) for (const [t, re] of TYPES) if (re.test(anchor)) return t; return 'candidate'; } +// breadcrumb 상위 항목 전용 어휘. "Home > 메디칼스킨케어 > 여드름/모공관리 > 알라딘필" 처럼 제목이 제품명이어도 상위 분류로 시술 페이지임을 안다 +const CRUMB_PROCEDURE = /피부과|성형외과|피부\s*관리|스킨\s*케어|시술|수술|클리닉|치료|안티에이징|에스테틱|메디칼|메디컬/; +// 본문 첫 항목들에서 breadcrumb("Home > A > B > 제목") 을 찾아 상위 항목 배열로 +function breadcrumbs(items) { + for (const it of items.slice(0, 6)) { + const m = (it.text ?? '').match(/^(?:home|홈|메인)\s*[>›»]\s*(.+)$/i); + if (m) return m[1].split(/\s*[>›»]\s*/).map((x) => x.trim()).filter(Boolean); + } + return []; +} +// 제목·h1 → breadcrumb 상위 항목 순으로 분류. 경로·앵커로 못 정한 페이지(candidate)에만 쓴다. 사이트 공통 접미어("| 뷰성형외과")는 잘라낸다. +function classifyByTitle(title = '', h1 = '', crumbs = []) { + const head = [h1, title.split(/\s*[|::]\s*|\s+-\s+/)[0]].map((s) => (s ?? '').trim()).filter((s) => s && s.length <= 40); + for (const s of head) for (const [t, re] of TYPES) if (re.test(s)) return t; + for (const c of crumbs.slice(0, -1)) { for (const [t, re] of TYPES) if (re.test(c)) return t; if (CRUMB_PROCEDURE.test(c)) return 'procedure'; } + return null; +} +// 본문에서 지점명 후보("청담점"·"부산서면점"). 8개 이상 나오면 지점 목록 페이지로 본다 +function branchNames(text) { + const names = new Set(); + for (const m of text.matchAll(/(?:^|[\s>|·,(\-])((?:[가-힣]{1,4}\s)?[가-힣A-Za-z0-9]{1,10}점)(?=$|[\s<|·,)\-:])/g)) { const n = m[1].replace(/^(서울|경기|인천|부산|대구|대전|광주|울산|세종)\s/, ''); if (!NOT_BRANCH.has(n) && !/^\d+점$/.test(n)) names.add(n); } + return [...names]; +} // ---------- fetch ---------- const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +// charset: HTTP 헤더 → 첫 4KB 의 meta charset → utf-8. EUC-KR 계열 별칭은 모두 euc-kr 로 (Node 22 TextDecoder 가 지원) +function detectCharset(contentType, bytes) { + const fromHeader = /charset=["']?\s*([\w-]+)/i.exec(contentType ?? '')?.[1]; + if (fromHeader) return fromHeader; + const head = new TextDecoder('latin1').decode(bytes.subarray(0, 4096)); + return /]+charset=["']?\s*([\w-]+)/i.exec(head)?.[1] ?? 'utf-8'; +} +function decodeBody(bytes, charset) { + let label = charset.toLowerCase().replace(/^x-/, ''); + if (/^(euc-?kr|ks_?c_?5601(?:-1987|-1992)?|ksc5601|cp949|windows-949|uhc)$/.test(label)) label = 'euc-kr'; + try { return new TextDecoder(label).decode(bytes); } catch { return new TextDecoder('utf-8').decode(bytes); } +} async function fetchText(url, tries = 2) { for (let i = 0; i <= tries; i++) { try { const res = await fetch(url, { headers: { 'user-agent': UA, accept: 'text/html,application/xhtml+xml,*/*' }, redirect: 'follow', signal: AbortSignal.timeout(25000) }); - const body = await res.text(); - return { status: res.status, finalUrl: res.url, body, contentType: res.headers.get('content-type') ?? '' }; + const bytes = new Uint8Array(await res.arrayBuffer()); + const contentType = res.headers.get('content-type') ?? ''; + const charset = detectCharset(contentType, bytes); + return { status: res.status, finalUrl: res.url, body: decodeBody(bytes, charset), contentType, charset }; } catch (e) { if (i === tries) return { status: 0, finalUrl: url, body: '', error: e.message }; await sleep(800 * (i + 1)); } } } -// ---------- robots ---------- +// ---------- robots (origin 별 캐시) ---------- +const robotsCache = new Map(); async function loadRobots(origin) { + if (robotsCache.has(origin)) return robotsCache.get(origin); const r = await fetchText(`${origin}/robots.txt`, 0); const dis = []; if (r.status === 200) { @@ -73,30 +130,56 @@ async function loadRobots(origin) { else if (star && /^disallow:/i.test(l)) { const p = l.replace(/^disallow:\s*/i, '').trim(); if (p) dis.push(p); } } } - return { raw: r.body, disallow: dis, allowed: (path) => !dis.some((d) => path.startsWith(d)) }; + const out = { raw: r.body, disallow: dis, allowed: (path) => !dis.some((d) => path.startsWith(d)) }; + robotsCache.set(origin, out); + return out; } // ---------- 링크 정규화 ---------- +const TRACKING = /^(utm_|fbclid|gclid|ref$|PHPSESSID|sid$|_ga)/i; function normalize(href, base) { try { const u = new URL(href, base); if (!/^https?:$/.test(u.protocol)) return null; - u.hash = ''; u.search = ''; + u.hash = ''; + // 쿼리는 보존한다(index.php?doc=14 처럼 쿼리가 곧 페이지인 사이트). 추적 파라미터만 빼고 키 순으로 정렬해 같은 페이지가 한 키가 되게 한다 + const keep = [...u.searchParams.entries()].filter(([k]) => !TRACKING.test(k)).sort(([a], [b]) => a.localeCompare(b)); + u.search = ''; for (const [k, v] of keep) u.searchParams.append(k, v); // 슬래시를 강제로 붙이지 않는다. 뷰성형외과(WordPress)는 /x → /x/ 로 301 하지만, 원진(k-wonjin.co.kr)은 /x/ 가 404 다. // 키는 슬래시 없는 형태로 통일하고(루트 제외), 404 면 collect() 에서 반대 형태를 한 번 더 시도한다. let s = u.toString(); - if (u.pathname !== '/' && s.endsWith('/')) s = s.slice(0, -1); + if (u.pathname !== '/' && !u.search && s.endsWith('/')) s = s.slice(0, -1); return s; } catch { return null; } } -const sameHost = (u, origin) => new URL(u).host.replace(/^www\./, '') === new URL(origin).host.replace(/^www\./, ''); +const hostOf = (u) => new URL(u).host.replace(/^www\./, ''); +const HOSTS = new Set([hostOf(START)]); // 허용 호스트: 시작 URL + 리다이렉트로 옮겨간 홈 + --extra-url +const sameHost = (u) => { try { return HOSTS.has(hostOf(u)); } catch { return false; } }; + +// ---------- 시작 URL 해석(프레임셋·meta refresh·JS 리다이렉트) ---------- +// 껍데기 페이지(프레임셋이 있거나 본문이 200자 미만)에서만 리다이렉트 대상을 찾는다. 일반 페이지의 onclick 핸들러 속 location.href 는 대상이 아니다. +function redirectTargets(html, base) { + const out = []; + const add = (h) => { const u = h && normalize(h.trim(), base); if (u && u !== normalize(base, base)) out.push(u); }; + for (const m of html.matchAll(/]+http-equiv=["']?refresh["']?[^>]*content=["']?\s*\d+\s*;\s*url=\s*([^"'>\s]+)/gi)) add(m[1]); + for (const m of html.matchAll(/]*\ssrc=["']?([^"'>\s]+)/gi)) add(m[1]); + for (const s of html.matchAll(/]*>([\s\S]*?)<\/script>/gi)) { + // 주석을 지우고, 중괄호 깊이 0(함수·블록 바깥)의 문장만 남긴다 + const src = s[1].replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:'"\\])\/\/[^\n]*/g, '$1'); + let depth = 0, top = ''; + for (const ch of src) { if (ch === '{') depth++; else if (ch === '}') depth = Math.max(0, depth - 1); else if (depth === 0) top += ch; } + for (const m of top.matchAll(/(?:window\.|document\.|top\.|self\.|parent\.)?location(?:\.href)?\s*=\s*["']([^"']+)["']|location\.replace\(\s*["']([^"']+)["']/g)) add(m[1] ?? m[2]); + } + return [...new Set(out)]; +} +const isShell = (html, ex) => / i.text ?? '').join(' ')).length < 200; // ---------- 본문 추출 ---------- const MAIN_SELECTORS = ['main', '#ajax-content-wrap', '#main-content', '#content', '#contents', '#container', '.container-wrap', '#sub_content', '.sub_content', '.sub-content', '#subContent', 'article', '#wrap', '#wrapper']; const NOISE_TAGS = 'script,style,noscript,iframe,form,svg,template,video,audio,object,embed'; const NOISE_SELECTORS = 'header,footer,nav,[id*="menu"],[class*="menu"],[id*="popup"],[class*="popup"],[id*="modal"],[class*="modal"],[class*="share"],[class*="quick"],[class*="floating"],[class*="breadcrumb"],[class*="cookie"],[class*="sns"],[id*="search"],[class*="widget"],[class*="wpcf7"],[class*="eform"],[class*="offcanvas"],[class*="gnb"],[class*="lnb"],[id*="gnb"],[id*="lnb"],[class*="topbar"],[class*="top-bar"]'; const BLOCK = new Set(['div', 'section', 'article', 'main', 'aside', 'ul', 'ol', 'li', 'table', 'thead', 'tbody', 'tr', 'td', 'th', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'figure', 'figcaption', 'blockquote', 'dl', 'dt', 'dd', 'pre', 'address']); -const clean = (s) => s.replace(/ /g, ' ').replace(/[ \t\r\f\v]+/g, ' ').replace(/\s*\n\s*/g, ' ').trim(); +const clean = (s) => s.replace(/ /g, ' ').replace(/[ \t\r\f\v]+/g, ' ').replace(/\s*\n\s*/g, ' ').trim(); function hasBlockDescendant(el) { return el.querySelectorAll('*').some((c) => BLOCK.has(c.rawTagName?.toLowerCase())); @@ -108,7 +191,9 @@ function walk(el, items) { if (!tag) return; if (/^h[1-6]$/.test(tag)) { const t = clean(el.text); if (t) items.push({ kind: 'h', level: Number(tag[1]), text: t }); return; } if (tag === 'table') { - const rows = el.querySelectorAll('tr').map((tr) => tr.querySelectorAll('td,th').map((c) => clean(c.text))).filter((r) => r.some(Boolean)); + // 중첩 레이아웃 표는 같은 글이 행마다 되풀이된다. 인접한 같은 셀과 같은 행은 한 번만 + const seen = new Set(); + const rows = el.querySelectorAll('tr').map((tr) => tr.querySelectorAll('td,th').map((c) => clean(c.text)).filter((c, i, a) => i === 0 || c !== a[i - 1])).filter((r) => r.some(Boolean)).filter((r) => { const k = r.join('|'); if (seen.has(k)) return false; seen.add(k); return true; }); if (rows.length) items.push({ kind: 'table', rows }); return; } @@ -138,8 +223,12 @@ function extract(html, url) { const items = []; walk(main, items); const images = main.querySelectorAll('img').map((i) => ({ src: normalize(i.getAttribute('data-src') || i.getAttribute('src') || '', url), alt: clean(i.getAttribute('alt') ?? '') })).filter((i) => i.src && !/\.(svg|gif)$/i.test(i.src) && !/icon|logo|btn|button|arrow|blank|spacer|sns|share|1x1/i.test(i.src)); const links = [...new Set(main.querySelectorAll('a[href]').map((a) => normalize(a.getAttribute('href'), url)).filter(Boolean))]; - return { title, metaDesc, mainSelector, items, images, links, anchors }; + // 가 아니라 onclick 의 location.href·window.open 으로만 이어지는 페이지(지점 카드 등). 앵커 텍스트가 없으니 후순위 + const jsLinks = [...new Set([...html.matchAll(/(?:location(?:\.href)?\s*=|location\.replace\(|window\.open\()\s*["']([^"'\s]+)["']/g)].map((m) => normalize(m[1], url)).filter(Boolean))]; + return { title, metaDesc, mainSelector, items, images, links, anchors, jsLinks }; } +// 사실 후보용 전문(메뉴·푸터 포함). body 가 없는 옛 HTML 은 root 전체 +const fullText = (html) => { const r = parse(html); return clean((r.querySelector('body') ?? r).text ?? '').slice(0, 200000); }; /** 항목을 헤딩 기준 섹션으로 묶는다 */ function sectionize(items) { @@ -155,17 +244,39 @@ function sectionize(items) { } // ---------- 사실 후보(정규식) ---------- +const REGION = '(?:서울|경기|인천|부산|대구|대전|광주|울산|세종|강원|충북|충남|충청|전북|전남|전라|경북|경남|경상|제주)'; +const PHONE = '(?:0\\d{1,2}[-.)\\s]\\d{3,4}[-.\\s]\\d{4}|1[5-9]\\d{2}[-.\\s]\\d{4})'; // 02-544-2777 · 02)352-2184 · 1577-1175(대표번호) +// 주소 시작: 지역명 뒤에 행정단위 접미어(특별시·광역시·도 등)나 공백이 와야 한다. "서울대입구점서초점…" 처럼 띄어쓰기 없는 지점명 나열을 주소로 잡지 않게 +const REGION_START = `${REGION}(?:(?:특별시|광역시|특별자치시|특별자치도|남도|북도|도|시)\\s*|\\s+)(?:[가-힣]{1,6}(?:시|구|군|읍|면)\\s)?`; +// 주소: 지역명 ~ (빌딩|층|호|번지|로 N|길 N) 까지 짧게 잡고, 뒤에 "한일빌딩 4층" 같은 건물·층 토큰이 이어지면 붙인다 +// 확장 토큰은 "한일빌딩"·"4층"·"304호"·"B동" 꼴만. "지점연결번호" 처럼 호로 끝나는 일반어는 붙지 않게 한다 +const ADDR_EXT = '(?:,?\\s(?:\\d+[-\\d]*호|\\d{1,3}(?:,\\d{1,3})?층|[A-Za-z0-9]{1,3}동|[A-Za-z0-9가-힣]{1,12}(?:빌딩|건물|타워|프라자|센터|센타|아파트|상가|병원)))*'; +const ADDRESS = new RegExp(`(${REGION_START}[^\\n|·]{4,60}?(?:빌딩|건물|층|호|\\d+번지|로\\s?\\d+(?:길\\s?\\d+)?(?:-\\d+)?|길\\s?\\d+(?:-\\d+)?)${ADDR_EXT})`, 'g'); function factCandidates(text) { const pick = (re) => [...new Set([...text.matchAll(re)].map((m) => clean(m[1] ?? m[0])))]; return { - phone: pick(/(? i.kind === 'li' || (i.kind === 'p' && /대학|병원|학회|전문의|회원|교수|수료|연수|졸업|위촉|박사|석사/.test(i.text) && i.text.length < 80)).map((i) => i.text).filter((t) => !/원장$/.test(t)); const creds = [...new Set(credentials)].filter((c) => c !== specialty); - const status = !name ? '이름 미확인 · 확인 대기' : creds.length < 2 ? (page.flags.textInImages ? '약력 이미지 글자 · 확인 대기' : '약력 본문 없음 · 확인 대기') : 'ok'; + const status = !name ? (page.flags.textInImages ? '이름 미확인(이미지 글자) · 확인 대기' : '이름 미확인 · 확인 대기') : creds.length < 2 ? (page.flags.textInImages ? '약력 이미지 글자 · 확인 대기' : '약력 본문 없음 · 확인 대기') : 'ok'; return { id: page.slug.replace(/^.*doctors?-?/, ''), url: page.url, name, title: [isRep ? '대표원장' : '원장', specialty].filter(Boolean).join(' · ') || null, credentials: creds, images: page.images.slice(0, 5), textInImages: page.flags.textInImages, status }; } // ---------- 메인 ---------- -const origin = new URL(START).origin; mkdirSync(join(OUT, 'pages'), { recursive: true }); -const robots = await loadRobots(origin); -console.log(`[1/4] 시작 ${START} (robots Disallow ${robots.disallow.length}개)`); +console.log(`[1/4] 시작 ${START}`); -// 링크 발견: 홈 + 사이트맵 -const home = await fetchText(START); +// 시작 URL 해석: 껍데기면 리다이렉트 대상들을 받아 같은 호스트 링크가 가장 많은 페이지를 홈으로, 나머지는 씨앗 페이지로 +let home = await fetchText(START); if (home.status !== 200) { console.error(`홈 요청 실패: ${home.status} ${home.error ?? ''}`); process.exit(1); } -const homeEx = extract(home.body, home.finalUrl); +let homeEx = extract(home.body, home.finalUrl); +const seeds = []; // { url, ex } 홈 외에 앵커를 긁을 페이지(프레임·리다이렉트 대상·--extra-url) +const redirectChain = []; +for (let hop = 0; hop < 3 && isShell(home.body, homeEx); hop++) { + const targets = redirectTargets(home.body, home.finalUrl).filter(sameHost).slice(0, 5); + if (!targets.length) break; + const fetched = []; + for (const u of targets) { const r = await fetchText(u); if (r.status === 200 && /html/.test(r.contentType)) fetched.push({ url: u, r, ex: extract(r.body, r.finalUrl) }); } + if (!fetched.length) break; + fetched.sort((a, b) => b.ex.anchors.filter(([u]) => sameHost(u)).length - a.ex.anchors.filter(([u]) => sameHost(u)).length); + const [best, ...rest] = fetched; + redirectChain.push({ from: home.finalUrl, to: best.r.finalUrl, kind: / x.r.finalUrl) }); + console.log(` 껍데기 페이지(${redirectChain.at(-1).kind}) → 홈 ${best.r.finalUrl}${rest.length ? ` · 씨앗 ${rest.map((x) => x.r.finalUrl).join(', ')}` : ''}`); + for (const x of rest) seeds.push({ url: x.r.finalUrl, ex: x.ex, anchor: '' }); + home = best.r; homeEx = best.ex; +} +HOSTS.add(hostOf(home.finalUrl)); +const origin = new URL(home.finalUrl).origin; +const robots = await loadRobots(origin); +console.log(` 홈 ${home.finalUrl} (charset ${home.charset ?? 'utf-8'} · robots Disallow ${robots.disallow.length}개)`); +for (const u of EXTRA) { + HOSTS.add(hostOf(u)); await loadRobots(new URL(u).origin); + const r = await fetchText(u); + if (r.status !== 200 || !/html/.test(r.contentType)) { console.log(` 추가 URL 실패 ${u}: ${r.status} ${r.error ?? ''}`); continue; } + seeds.push({ url: r.finalUrl, ex: extract(r.body, r.finalUrl), anchor: '', extra: true }); + console.log(` 추가 URL ${r.finalUrl} (charset ${r.charset})`); +} + +// 링크 발견: 홈 + 씨앗 + 사이트맵 +const EXTRA_SET = new Set(seeds.filter((s) => s.extra).map((s) => normalize(s.url, s.url))); +const robotsAllowed = (u) => { const o = new URL(u).origin; const rb = robotsCache.get(o); return rb ? rb.allowed(new URL(u).pathname) : true; }; const queue = new Map(); // url → { anchor, fromHome } -const addLink = (u, anchor = '', fromHome = false) => { if (!u || !sameHost(u, origin) || SKIP.test(u) || /\.xml$/i.test(u) || !robots.allowed(new URL(u).pathname)) return; const cur = queue.get(u); if (!cur) queue.set(u, { anchor, fromHome }); else if (fromHome && !cur.fromHome) cur.fromHome = true; }; +const addLink = (u, anchor = '', fromHome = false) => { if (!u || !sameHost(u) || SKIP.test(u) || /\.xml$/i.test(u) || !robotsAllowed(u)) return; const cur = queue.get(u); if (!cur) queue.set(u, { anchor, fromHome }); else { if (fromHome && !cur.fromHome) cur.fromHome = true; if (!cur.anchor && anchor) cur.anchor = anchor; } }; for (const [u, a] of homeEx.anchors) addLink(u, a, true); +for (const s of seeds) { addLink(normalize(s.url, s.url), s.anchor, true); for (const [u, a] of s.ex.anchors) addLink(u, a, true); } +for (const u of [...homeEx.jsLinks, ...seeds.flatMap((s) => s.ex.jsLinks)]) addLink(u, '', false); for (const sm of ['/sitemap.xml', '/wp-sitemap.xml', '/sitemap_index.xml', '/page-sitemap.xml']) { const r = await fetchText(`${origin}${sm}`, 0); if (r.status !== 200 || !/<(urlset|sitemapindex)/.test(r.body)) continue; @@ -203,22 +344,33 @@ for (const sm of ['/sitemap.xml', '/wp-sitemap.xml', '/sitemap_index.xml', '/pag console.log(` 사이트맵 ${sm}: 링크 누적 ${queue.size}`); break; } +queue.delete(normalize(home.finalUrl, home.finalUrl)); queue.delete(normalize(START, START)); console.log(`[2/4] 후보 링크 ${queue.size}개 → 유형 분류`); // 유형 분류 후 우선순위대로 MAX까지 const ranked = [...queue.entries()].map(([u, { anchor, fromHome }]) => ({ url: u, anchor, fromHome, depth: new URL(u).pathname.split('/').filter(Boolean).length, type: classify(new URL(u).pathname, anchor) })); +// 같은 경로의 쿼리 변형(?id=1, ?tab=x)은 클라이언트 상태인 경우가 많다(원진 doctor?id=N·뷰 after-care?tab=X 는 같은 HTML). +// 경로별 첫 변형(variant 0)을 모든 유형에서 먼저 받고, 나머지 변형은 그 뒤로. index.php?doc=N 처럼 쿼리가 곧 페이지인 사이트는 변형이 곧 본문이라 뒤에 오더라도 MAX 안에서 받는다 +{ + const byPath = new Map(); + for (const x of ranked.slice().sort((a, b) => a.url.localeCompare(b.url))) { const k = hostOf(x.url) + new URL(x.url).pathname.replace(/\/$/, ''); const n = byPath.get(k) ?? 0; x.variant = n; byPath.set(k, n + 1); } +} const prio = (t) => { const i = TYPES.findIndex(([k]) => k === t); return i === -1 ? 99 : i; }; -// 유형이 잡힌 페이지 먼저(의료진 상세는 40명까지), 그다음 후보는 홈 메뉴에서 연결된 것 → 얕은 경로 순 +const vk = (x) => Math.min(x.variant, 1); const isDoctorDetail = (x) => x.type === 'doctor' && /\/doctors?\/[^/]+\/?$/.test(new URL(x.url).pathname); -const typed = ranked.filter((x) => x.type !== 'candidate').sort((a, b) => prio(a.type) - prio(b.type) || a.depth - b.depth); -const doctorDetails = typed.filter(isDoctorDetail).slice(0, 40); const typedRest = typed.filter((x) => !isDoctorDetail(x)); -const cands = ranked.filter((x) => x.type === 'candidate').sort((a, b) => Number(b.fromHome) - Number(a.fromHome) || a.depth - b.depth || a.url.length - b.url.length || a.url.localeCompare(b.url)); -const targets = [...typedRest, ...doctorDetails, ...cands].slice(0, MAX); -console.log(` 유형 확정 ${typedRest.length} · 의료진 상세 ${doctorDetails.length} · 후보 ${cands.length} → 수집 ${targets.length}`); +// 버킷 순서: 유형 확정(시술 제외) → 의료진 상세(40명까지) → 지점(BRANCH_CAP 까지) → 시술 → 후보(홈 메뉴에서 연결된 것 → 얕은 경로 순). +// 시술 페이지는 수가 많아(원진 55·오라클 110) 앞에 두면 의료진 상세를 밀어낸다 +const bucket = (x) => (x.type === 'candidate' ? 4 : x.type === 'procedure' ? 3 : x.type === 'branches' ? 2 : isDoctorDetail(x) ? 1 : 0); +// 유형 버킷 안에서는 홈 메뉴 순서(큐 삽입 순)를 지킨다(의료진은 대표원장이 먼저 나온다). 후보만 URL 길이·사전순으로 안정화 +const ordered = ranked.slice().sort((a, b) => vk(a) - vk(b) || bucket(a) - bucket(b) || (bucket(a) === 4 ? Number(b.fromHome) - Number(a.fromHome) : prio(a.type) - prio(b.type)) || a.depth - b.depth || (bucket(a) === 4 ? a.url.length - b.url.length || a.url.localeCompare(b.url) : 0)); +const caps = { 1: 40, 2: BRANCH_CAP }; const taken = {}; +const targets = ordered.filter((x) => { const b = bucket(x); taken[b] = (taken[b] ?? 0) + 1; return !(b in caps) || taken[b] <= caps[b]; }).slice(0, MAX); +const n = (b) => ranked.filter((x) => bucket(x) === b).length; +console.log(` 유형 확정 ${n(0)} · 의료진 상세 ${Math.min(n(1), 40)}/${n(1)} · 지점 ${Math.min(n(2), BRANCH_CAP)}/${n(2)} · 시술 ${n(3)} · 후보 ${n(4)} · 쿼리 변형 ${ranked.filter((x) => x.variant > 0).length} → 수집 ${targets.length}`); // 수집 const pages = []; -const slugOf = (u) => (new URL(u).pathname.replace(/^\/|\/$/g, '').replace(/[^a-zA-Z0-9가-힣]+/g, '-') || 'home'); +const slugOf = (u) => { const x = new URL(u); return ((x.pathname.replace(/^\/|\/$/g, '') + (x.search ? '-' + x.search.slice(1) : '')).replace(/[^a-zA-Z0-9가-힣]+/g, '-').replace(/^-|-$/g, '') || 'home'); }; async function collect(t) { let r = await fetchText(t.url); if (r.status === 404) { // 슬래시 유무 반대 형태 재시도 @@ -231,9 +383,10 @@ async function collect(t) { const h1 = ex.items.find((i) => i.kind === 'h' && i.level === 1)?.text ?? null; let type = t.type; const bodyText = ex.items.map((i) => i.kind === 'table' ? i.rows.flat().join(' ') : i.text).join('\n'); - if (type === 'candidate') type = PROCEDURE_HINT.test(bodyText) ? 'procedure' : 'other'; + // 경로·앵커로 못 정한 페이지: 제목·h1 키워드 → 본문의 지점명 밀도 → 시술 본문 단서 순 + if (type === 'candidate') type = classifyByTitle(ex.title, h1, breadcrumbs(ex.items)) ?? (branchNames(bodyText).length >= 8 ? 'branches' : PROCEDURE_HINT.test(bodyText) ? 'procedure' : 'other'); if (type === 'doctor' && /\/doctors?\/[^/]+\/?$/.test(new URL(t.url).pathname) && !/\/doctors?\/?$/.test(new URL(t.url).pathname)) type = 'doctor-detail'; - pages.push({ url: r.finalUrl, requestedUrl: t.url, slug: slugOf(r.finalUrl), type, anchor: t.anchor, status: r.status, title: ex.title, metaDesc: ex.metaDesc, h1, mainSelector: ex.mainSelector, items: ex.items, images: ex.images, links: ex.links.filter((l) => sameHost(l, origin)), rawText: bodyText, fullTextForFacts: clean(parse(r.body).querySelector('body')?.text ?? '').slice(0, 200000), flags: {} }); + pages.push({ url: r.finalUrl, requestedUrl: t.url, slug: slugOf(r.finalUrl), type, extra: EXTRA_SET.has(t.url) || undefined, anchor: t.anchor, status: r.status, charset: r.charset, title: ex.title, metaDesc: ex.metaDesc, h1, mainSelector: ex.mainSelector, items: ex.items, images: ex.images, links: ex.links.filter(sameHost), rawText: bodyText, fullTextForFacts: fullText(r.body), flags: {} }); } { let i = 0; const workers = Array.from({ length: 3 }, async () => { while (i < targets.length) { const t = targets[i++]; await collect(t); process.stdout.write(`\r 수집 ${pages.length}/${targets.length}`); await sleep(DELAY); } }); @@ -242,12 +395,28 @@ async function collect(t) { // 홈도 페이지로 { const h1 = homeEx.items.find((i) => i.kind === 'h' && i.level === 1)?.text ?? null; - pages.unshift({ url: home.finalUrl, requestedUrl: START, slug: 'home', type: 'home', anchor: '', status: 200, title: homeEx.title, metaDesc: homeEx.metaDesc, h1, mainSelector: homeEx.mainSelector, items: homeEx.items, images: homeEx.images, links: homeEx.links.filter((l) => sameHost(l, origin)), rawText: homeEx.items.map((i) => i.kind === 'table' ? i.rows.flat().join(' ') : i.text).join('\n'), fullTextForFacts: clean(parse(home.body).querySelector('body')?.text ?? '').slice(0, 200000), flags: {} }); + pages.unshift({ url: home.finalUrl, requestedUrl: START, slug: 'home', type: 'home', anchor: '', status: 200, charset: home.charset, title: homeEx.title, metaDesc: homeEx.metaDesc, h1, mainSelector: homeEx.mainSelector, items: homeEx.items, images: homeEx.images, links: homeEx.links.filter(sameHost), rawText: homeEx.items.map((i) => i.kind === 'table' ? i.rows.flat().join(' ') : i.text).join('\n'), fullTextForFacts: fullText(home.body), flags: {} }); } -console.log(`\n[3/4] 페이지 ${pages.length}개 수집. 반복 줄 제거`); +// slug 충돌 방지(같은 slug 로 정규화되는 두 URL) +{ + const used = new Map(); + for (const p of pages) { const n = used.get(p.slug) ?? 0; used.set(p.slug, n + 1); if (n) p.slug = `${p.slug}-${n + 1}`; } +} +// 같은 경로에서 본문(제목+항목)이 같은 쿼리 변형은 중복. 첫 페이지만 남기고 나머지는 type=duplicate 로 index 에만 기록한다 +{ + const seen = new Map(); + for (const p of pages.slice().sort((a, b) => a.url.length - b.url.length)) { // 짧은 URL(쿼리 없는 쪽)을 대표로 + if (p.status !== 200 || p.error) continue; + const key = hostOf(p.url) + new URL(p.url).pathname + '\n' + p.title + '\n' + p.rawText; // http/https 는 같은 페이지 + const first = seen.get(key); + if (first) { p.type = 'duplicate'; p.duplicateOf = first.url; p.items = []; p.images = []; if (p.extra) first.extra = true; } else seen.set(key, p); + } +} +const dupCount = pages.filter((p) => p.type === 'duplicate').length; +console.log(`\n[3/4] 페이지 ${pages.length}개 수집${dupCount ? ` (쿼리 변형 중복 ${dupCount})` : ''}. 반복 줄 제거`); // 반복 줄(boilerplate) 제거: 페이지의 30% 이상(최소 3)에 같은 줄이 있으면 메뉴·푸터로 본다 -const ok = pages.filter((p) => p.status === 200 && !p.error); +const ok = pages.filter((p) => p.status === 200 && !p.error && p.type !== 'duplicate'); const freq = new Map(); for (const p of ok) for (const t of new Set(p.items.filter((i) => i.kind !== 'table').map((i) => i.text))) freq.set(t, (freq.get(t) ?? 0) + 1); const threshold = Math.max(3, Math.ceil(ok.length * 0.3)); @@ -259,7 +428,8 @@ for (const p of ok) { p.sections = sectionize(p.items); p.text = p.items.map((i) => i.kind === 'table' ? i.rows.map((r) => r.join(' | ')).join('\n') : i.text).join('\n'); p.chars = p.text.replace(/\s+/g, '').length; - p.flags = { textInImages: p.chars < 500 && p.images.length >= 3, noText: p.chars < 100, boilerplateRemoved: before - p.items.length, tables: p.items.filter((i) => i.kind === 'table').length }; + // 이미지 글자: 본문 500자 미만에 이미지 3장 이상, 또는 본문 100자 미만에 본문 이미지가 1장이라도 있으면(시술 설명을 통짜 이미지로 넣는 사이트) + p.flags = { textInImages: (p.chars < 500 && p.images.length >= 3) || (p.chars < 100 && p.images.length >= 1), noText: p.chars < 100, boilerplateRemoved: before - p.items.length, tables: p.items.filter((i) => i.kind === 'table').length }; } // 저장 @@ -268,20 +438,30 @@ for (const p of pages) { const file = `pages/${p.slug}.json`; const { fullTextForFacts, rawText, ...save } = p; writeFileSync(join(OUT, file), JSON.stringify({ clinic: CLINIC, fetchedAt: today, ...save }, null, 1)); - index.push({ file, url: p.url, type: p.type, status: p.status, mainSelector: p.mainSelector ?? null, title: p.title ?? null, h1: p.h1 ?? null, chars: p.chars ?? 0, tables: p.flags?.tables ?? 0, images: p.images?.length ?? 0, flags: Object.entries(p.flags ?? {}).filter(([k, v]) => v === true).map(([k]) => k) }); + index.push({ file, url: p.url, type: p.type, duplicateOf: p.duplicateOf, status: p.status, mainSelector: p.mainSelector ?? null, title: p.title ?? null, h1: p.h1 ?? null, chars: p.chars ?? 0, tables: p.flags?.tables ?? 0, images: p.images?.length ?? 0, flags: Object.entries(p.flags ?? {}).filter(([k, v]) => v === true).map(([k]) => k) }); } const byType = index.reduce((m, x) => ((m[x.type] = (m[x.type] ?? 0) + 1), m), {}); -writeFileSync(join(OUT, 'index.json'), JSON.stringify({ clinic: CLINIC, start: START, fetchedAt: today, robotsDisallow: robots.disallow, boilerplateLines: boiler.size, byType, pages: index }, null, 1)); +writeFileSync(join(OUT, 'index.json'), JSON.stringify({ clinic: CLINIC, start: START, resolvedStart: home.finalUrl, redirectChain, extraUrls: EXTRA, charset: home.charset ?? null, fetchedAt: today, robotsDisallow: robots.disallow, boilerplateLines: boiler.size, byType, pages: index }, null, 1)); -// 의료진 -const doctors = ok.filter((p) => p.type === 'doctor-detail').map(parseDoctor); -writeFileSync(join(OUT, 'doctors.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, note: 'textInImages=true 인 약력은 이미지 글자라 본문에 없다. authors.json에 옮기기 전에 사람이 확인한다.', doctors }, null, 1)); +// 의료진: 상세 페이지가 있으면 상세, 없으면 목록 페이지(이미지 글자면 이름 미확인으로 남긴다) +let doctors = ok.filter((p) => p.type === 'doctor-detail').map(parseDoctor); +const doctorSource = doctors.length ? 'doctor-detail' : 'doctor'; +if (!doctors.length) doctors = ok.filter((p) => p.type === 'doctor').map(parseDoctor); +writeFileSync(join(OUT, 'doctors.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, source: doctorSource, note: 'textInImages=true 인 약력은 이미지 글자라 본문에 없다. authors.json에 옮기기 전에 사람이 확인한다.', doctors }, null, 1)); // 사실 후보 -const factSrc = ok.filter((p) => ['home', 'direction', 'about', 'reservation'].includes(p.type)); +const factSrc = ok.filter((p) => ['home', 'direction', 'about', 'reservation'].includes(p.type) || p.extra); // --extra-url 로 지정한 페이지는 사람이 고른 원천이라 항상 포함 const facts = {}; for (const p of factSrc) { const c = factCandidates(p.fullTextForFacts); for (const [k, vals] of Object.entries(c)) for (const val of vals) { facts[k] ??= {}; facts[k][val] ??= []; if (!facts[k][val].includes(p.url)) facts[k][val].push(p.url); } } -writeFileSync(join(OUT, 'facts.draft.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, note: '정규식 후보. 값마다 출처 URL. factSheet.json에 넣기 전에 사람이 홈페이지 표기와 대조한다. 후보가 없으면 "확인 대기".', candidates: facts }, null, 1)); +// 지점 후보: 지점 목록·지점별 페이지의 "지점명 주소 TEL" 3종 세트. 본문(메뉴·푸터 제외)에서 먼저 찾고, 없으면 전문에서 +const branches = []; const branchPagesNap = []; +for (const p of ok.filter((p) => p.type === 'branches' || p.extra)) { + let found = branchCandidates(p.text ?? ''); if (!found.length) found = branchCandidates(p.fullTextForFacts); + for (const b of found) if (!branches.some((x) => x.name === b.name && x.phone === b.phone)) branches.push({ ...b, source: p.url }); + // 지점 한 곳짜리 페이지(net_main.php?netId=N 같은): 3종 세트가 없으면 본문의 주소·전화·진료시간을 그대로 후보로 + if (found.length < 3) { const c = factCandidates(p.text ?? ''); if (c.address.length || c.phone.length || c.hours.length) branchPagesNap.push({ url: p.url, title: p.title, h1: p.h1, address: c.address, phone: c.phone, hours: c.hours }); } +} +writeFileSync(join(OUT, 'facts.draft.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, note: '정규식 후보. 값마다 출처 URL. factSheet.json에 넣기 전에 사람이 홈페이지 표기와 대조한다. 후보가 없으면 "확인 대기". branches 는 지점 목록 페이지에서 뽑은 지점명·주소·전화 후보.', candidates: facts, branches, branchPages: branchPagesNap }, null, 1)); // 40자 중복 검사 기준 텍스트 writeFileSync(join(OUT, 'home_text.txt'), ok.map((p) => p.text.replace(/\s+/g, '')).join('\n')); @@ -291,7 +471,7 @@ const postsDir = arg('--posts'); if (postsDir && existsSync(postsDir)) { const { readdirSync } = await import('node:fs'); const cited = new Set(); - for (const f of readdirSync(postsDir).filter((x) => x.endsWith('.md'))) for (const m of readFileSync(join(postsDir, f), 'utf8').matchAll(/url:\s*"([^"]+)",\s*accessed:[^}]*type:\s*clinic/g)) if (sameHost(m[1], origin)) cited.add(normalize(m[1], origin)); + for (const f of readdirSync(postsDir).filter((x) => x.endsWith('.md'))) for (const m of readFileSync(join(postsDir, f), 'utf8').matchAll(/url:\s*"([^"]+)",\s*accessed:[^}]*type:\s*clinic/g)) if (sameHost(m[1])) cited.add(normalize(m[1], origin)); const have = new Set(pages.flatMap((p) => [p.url, p.requestedUrl].filter(Boolean))); const missing = []; for (const u of cited) { if (have.has(u)) continue; const r = await fetchText(u, 0); if (!have.has(normalize(r.finalUrl, origin))) missing.push(u); } @@ -299,5 +479,5 @@ if (postsDir && existsSync(postsDir)) { } console.log(`[4/4] 저장 ${OUT}`); console.log(` 유형별: ${Object.entries(byType).map(([k, v]) => `${k} ${v}`).join(' · ')}`); -console.log(` 의료진 ${doctors.length}명 (약력 확인 대기 ${doctors.filter((d) => d.status !== 'ok').length}명) · 반복 줄 ${boiler.size}개 제거 · home_text ${ok.reduce((n, p) => n + p.chars, 0).toLocaleString()}자`); +console.log(` 의료진 ${doctors.length}명 (약력 확인 대기 ${doctors.filter((d) => d.status !== 'ok').length}명, 출처 ${doctorSource}) · 지점 후보 ${branches.length}개 · 반복 줄 ${boiler.size}개 제거 · home_text ${ok.reduce((n, p) => n + p.chars, 0).toLocaleString()}자`); const bad = index.filter((x) => x.status !== 200); if (bad.length) console.log(` 실패 ${bad.length}: ${bad.map((b) => `${b.status} ${b.url}`).join(', ')}`); diff --git a/supporters/scripts/collect_recovery.mjs b/supporters/scripts/collect_recovery.mjs new file mode 100644 index 0000000..2db77ea --- /dev/null +++ b/supporters/scripts/collect_recovery.mjs @@ -0,0 +1,249 @@ +// 병원 홈페이지 시술 페이지 원문에서 "시술 후 관리" 문장을 골라 /stay·/en/stay 의 "시술 후 관리 안내" 블록 데이터를 만든다. +// 근거는 collect_evidence.mjs 결과(index.json + pages/*.json). 이미지 글자를 OCR 한 페이지(flags.ocr)도 text 에 들어 있으므로 같이 본다. +// 의학 판단을 하지 않는다. 병원이 적어 둔 문장을 그대로 옮기고, 출처 URL 과 확인일을 붙인다. +// +// node scripts/collect_recovery.mjs --clinic --evidence > --site [--translate] [--max-per-page 5] [--max-pages 30] [--max-cost-usd 0.5] +// +// 채택 조건 (문장 단위. 마침표·물음표·줄바꿈·" / " 로 나누고 10~160자) +// (a) 시점 표현: 시술 후 / 치료 후 / 수술 후 / 당일 / 다음 날 / N일·주·개월 (정도·간·이내·후·까지) / 이후 / 기간 +// (b) 행동·주의 표현: 피하·삼가·주의·금지·권장·가능·세안·자외선·사우나·음주·흡연·운동·화장·샤워·부기·멍·실밥 등 +// 둘 다 있어야 채택. 효과·홍보 문장(효과·개선·매력·아름다·만족·최고·추천)은 제외. 병원 이름·전화·주소 문장 제외. +// 수술 전 준비 문장("수술 전 3일간 금주")은 시술 후 관리가 아니므로 제외. +// OCR 문장은 그대로 쓰되 글자가 깨진 흔적(~~, 홀로 남은 조사, 표 라벨 뒤섞임)이 있으면 뺀다. +// 발행 게이트(gate/rules.mjs)의 금칙어·효과 보장·금액·운영자 어휘·비교 수치 규칙을 문장마다 적용해 걸리는 것은 뺀다. +// +// 출력 /src/data/recoveryNotes.json. 빈 결과여도 파일을 만든다(items []). 페이지는 items 가 없으면 블록을 그리지 않는다. +// --translate : OPENAI_API_KEY 로 gpt-4.1-mini 배치 번역. 숫자·단위가 원문과 같지 않으면 그 문장의 en 은 비우고 enFailed 에 남긴다. +// 시술 이름도 같은 배치로 번역해 procedureEn 에 넣는다(고유명사·제품명은 로마자 병기 허용. 예 "물광주사" → "Water-glow injection (Mulgwang)"). +// 같은 ko 문장은 캐시(/src/data/recoveryNotes.cache.json)에서 다시 쓴다. 비용 상한 기본 $0.5. +import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { join, resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import * as R from './gate/rules.mjs'; + +const here = (p) => fileURLToPath(new URL(p, import.meta.url)); +const SUP = here('../'); +const args = process.argv.slice(2); +const opt = (k, d) => { const i = args.indexOf(`--${k}`); if (i >= 0 && args[i + 1] && !args[i + 1].startsWith('--')) return args[i + 1]; const eq = args.find((a) => a.startsWith(`--${k}=`)); return eq ? eq.slice(k.length + 3) : d; }; +const flag = (k) => args.includes(`--${k}`); + +const clinic = opt('clinic'); +if (!clinic) { console.error('사용법: --clinic --evidence

--site [--translate]'); process.exit(2); } +const EV = resolve(opt('evidence', join(SUP, '..', 'evidence', clinic))); +const SITE = resolve(opt('site', SUP)); +const maxPerPage = Number(opt('max-per-page', '5')); +// 주의사항·애프터케어 전용 페이지는 관리 문장이 수십 개라 상한을 따로 둔다 (haewon 결정 2026-09-11: "수술 전후 주의사항 길게 해도 돼") +const maxPerCarePage = Number(opt('max-per-care-page', '40')); +const capFor = (type) => (type === 'aftercare' || type === 'precautions' ? maxPerCarePage : maxPerPage); +const maxPages = Number(opt('max-pages', '30')); +const maxCostUsd = Number(opt('max-cost-usd', '0.5')); +const doTranslate = flag('translate'); +const today = new Date().toISOString().slice(0, 10); + +// ---------- .env (generate_posts.mjs 와 같은 방식: 저장소 루트까지 위로 4단계 탐색) ---------- +function loadEnv() { + let dir = SUP; + for (let i = 0; i < 4; i++) { + const p = join(dir, '.env'); + if (existsSync(p)) { + for (const line of readFileSync(p, 'utf8').split('\n')) { + const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/); + if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, ''); + } + } + dir = dirname(dir); + } +} +loadEnv(); + +const readJson = (p) => JSON.parse(readFileSync(p, 'utf8')); +const OUT = join(SITE, 'src', 'data', 'recoveryNotes.json'); +const CACHE = join(SITE, 'src', 'data', 'recoveryNotes.cache.json'); +const writeOut = (j) => { mkdirSync(dirname(OUT), { recursive: true }); writeFileSync(OUT, JSON.stringify(j, null, 2) + '\n'); }; + +if (!existsSync(join(EV, 'index.json'))) { + console.error(`근거 없음: ${EV}/index.json. 빈 결과를 씁니다.`); + writeOut({ clinic, generatedAt: today, sourceNote: '병원 홈페이지 시술 페이지 원문', items: [], counts: { pages: 0, candidates: 0, sentences: 0, translated: 0, enFailed: 0, costUsd: 0 } }); + process.exit(0); +} +const index = readJson(join(EV, 'index.json')); +const factPath = join(SITE, 'src', 'data', 'factSheet.json'); +const fact = existsSync(factPath) ? readJson(factPath) : {}; +const clinicNames = [fact.name, fact.shortName, index.clinic].filter((s) => s && /[가-힣]/.test(s)); +const phone = fact.phone || ''; +// 홈페이지 40자 연속 일치 검사 기준(발행 게이트와 같은 파일). 인용 블록은 게이트에서 제외되지만, 다른 페이지의 문장과 겹치는지는 여기서 보지 않는다. + +// ---------- 문장 규칙 ---------- +const TIME = /시술\s*후|치료\s*후|수술\s*후|당일|다음\s*날|\d+\s*(일|주|개월)\s*(정도|간|이내|후|까지)|이후|기간/; +const ACTION = /피하|피해|삼가|주의|금지|권장|가능|세안|자외선|선크림|사우나|찜질|음주|흡연|운동|화장|샤워|목욕|일상\s*생활|복귀|출근|부기|멍|딱지|보습|냉찜질|온찜질|실밥/; +const PROMO = /효과|개선|매력|아름다|만족|최고|추천|노하우|프리미엄|서비스|제공|전담|책임|케어해|서포트|장비|기기|시스템|자체|생기있|탄탄|오래\s*유지|정밀|안전한|거의\s*(보이지|남지)\s*않|에\s*비해|단축/; // 뒤쪽은 시술 소개·장비 홍보·타 술식 비교 문장의 어휘. 관리 지시문에는 잘 안 나온다 +// 수술 전 준비 문장. "수술 전 3일간 금주" 는 시술 후 관리가 아니다. "수술 전/후" 처럼 후가 같이 있으면 통과. +const PRE_OP = /(수술|시술|치료)\s*(\d+\s*(일|주|시간|개월)\s*)?전(?!\s*[\/·후])/; +const CONTACT = /\d{2,4}[-.]\d{3,4}[-.]\d{4}|\d{4}-\d{4}|(서울|부산|대구|인천|광주|대전|울산|경기|강원|충북|충남|전북|전남|경북|경남|제주)[특별광역]*[시도]?\s*[가-힣]+[구군시]|[가-힣]+(로|길)\s*\d+|빌딩|층\b|오시는\s*길|찾아오시는/; +// 표 라벨(수술시간·마취방법 등)이 한 줄에 뒤섞인 OCR 문장은 행 순서가 깨져 있어 통째로 뺀다. +const TABLE_LABEL = /(수술\s*시간|마취\s*방법|입원\s*여부|입원\s*기간|시술\s*시간|수술\s*방법)\s*[::]/; +// 라벨 뒤만 살리는 경우: "회복기간 : …" 처럼 콜론이 있는 라벨, 또는 소제목("수술 후 관리", "시술 후 주의점")이 문장 앞에 붙은 OCR 문장 +const COLON_LABEL = /(회복\s*기간|실밥\s*제거)\s*[::]\s*/; +const HEADING_GLUE = /^.{0,12}?(시술|수술)\s*후\s*(주의\s*(점|사항)|관리(\s*방법)?)\s+(?=\S)/; +// OCR 파손 흔적: 물결 두 개, 홀로 남은 조사, 숫자 뒤 알파벳(3-4t시간), 표시 기호, 단독 숫자 +const BROKEN = /~~|\s[을를이가은는의]\s|\d[a-zA-Z]시간|[✓√■►▶▪◆●▲]|(? s.replace(/\s+/g, ''); +const clean = (s) => s + .replace(/^[\s\-•●▪■#*·√✓※]+/, '') // 목록 기호 + .replace(/^\(?\d{1,2}[.)]\s+(?=[가-힣])/, '') // "5. 다음날부터" 목록 번호 + .replace(/^\d{1,2}\s+(?=[가-힣])/, '') // "5 다음날부터" + .replace(/\s+\d{1,2}[.,]?$/, '') // 문장 끝에 붙은 다음 항목 번호 "… 가능 2." + .replace(/\s+/g, ' ') + .trim(); + +function splitSentences(text) { + return String(text || '') + .split(/(?<=[.?!。])\s+|\n+|\s\/\s/) + .map(clean) + .filter(Boolean); +} + +/** 채택 여부. 실패 사유를 문자열로 돌려주고, 통과면 정제된 문장을 돌려준다. */ +function judge(raw, { ocr }) { + let s = raw; + if (TABLE_LABEL.test(s)) return { drop: 'table' }; + const g = s.match(HEADING_GLUE); + if (g) s = s.slice(g[0].length).trim(); + const c = s.match(COLON_LABEL); + if (c && c.index > 0) s = s.slice(c.index + c[0].length).trim(); + if (s.length < 10 || s.length > 160) return { drop: 'length' }; + if (!TIME.test(s)) return { drop: 'time' }; + if (!ACTION.test(s)) return { drop: 'action' }; + if (s.split(' ').length < 4) return { drop: 'fragment' }; // "수술 다음날부터 가능" 처럼 무엇이 가능한지 없는 표 조각 + if (PROMO.test(s)) return { drop: 'promo' }; + if (PRE_OP.test(s) && !/후/.test(s)) return { drop: 'preop' }; + if (CONTACT.test(s) || clinicNames.some((n) => s.includes(n)) || (phone && s.includes(phone))) return { drop: 'contact' }; + if (BROKEN.test(s)) return { drop: ocr ? 'ocr-broken' : 'broken' }; + if (ocr && s.length > 100 && !/[,.]/.test(s.slice(0, 80))) return { drop: 'ocr-broken' }; // 표 칸이 한 줄로 이어 붙은 OCR 문장(쉼표·마침표 없이 길다) + if (!/[.다요음함됨]\s*[.)]?$/.test(s) && !/(가능|불가|금지|권장|주의|필요)$/.test(s)) return { drop: 'unfinished' }; // 문장이 끝나지 않은 조각 + // 발행 게이트 규칙. 걸리면 뺀다. + const fields = [{ field: 'ko', text: s }]; + const gate = [ + ...R.checkBannedBody(s), + ...R.checkOperatorVocab(s), + ...R.checkPriceMention(fields), + ...R.checkDeviceClaim({}, fields), + ...R.checkConclusions(fields), + ].filter((x) => x.level === R.E); + if (gate.length) return { drop: `gate:${gate[0].code}` }; + return { ok: s }; +} + +// ---------- 페이지 순회 ---------- +const TYPES = new Set(['procedure', 'aftercare', 'precautions']); +const pages = (index.pages ?? []).filter((p) => TYPES.has(p.type) && p.status === 200 && p.file); +const dropCounts = {}; +const items = []; +const seenGlobal = new Set(); // 페이지가 달라도 같은 문장(공백 제거 후)은 한 번만 +const cleanTitle = (t) => { + let s = String(t || '').split('|')[0].trim(); + for (const n of clinicNames) s = s.replace(new RegExp(`^${n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*`), ''); + return s.trim(); +}; +for (const meta of pages) { + const fp = join(EV, meta.file); + if (!existsSync(fp)) continue; + const pg = readJson(fp); + const flags = Array.isArray(pg.flags) ? pg.flags : Object.keys(pg.flags ?? {}).filter((k) => pg.flags[k]); + const ocr = flags.includes('ocr'); + const text = pg.text || ''; + // 시술 영역: 빵부스러기("Home > 필러 & 보톡스 > 보톡스") 의 첫 항목 + const crumb = text.split('\n').find((l) => /^Home\s*>/.test(l.trim())); + const area = crumb ? (crumb.split('>').map((s) => s.trim())[1] ?? '') : ''; + const ko = []; + const seenPage = new Set(); + for (const raw of splitSentences(text)) { + const j = judge(raw, { ocr }); + if (j.drop) { dropCounts[j.drop] = (dropCounts[j.drop] ?? 0) + 1; continue; } + const key = compact(j.ok); + if (seenPage.has(key) || seenGlobal.has(key)) { dropCounts.dup = (dropCounts.dup ?? 0) + 1; continue; } + seenPage.add(key); seenGlobal.add(key); + ko.push(j.ok); + if (ko.length >= capFor(meta.type)) break; + } + if (!ko.length) continue; + items.push({ procedure: cleanTitle(pg.h1) || cleanTitle(pg.title) || cleanTitle(meta.title), procedureEn: '', area, url: pg.url || meta.url, fetchedAt: pg.fetchedAt || index.fetchedAt || today, ko, en: ko.map(() => ''), ocr }); +} +items.sort((a, b) => b.ko.length - a.ko.length || a.procedure.localeCompare(b.procedure, 'ko')); +const kept = items.slice(0, maxPages); +const totalSentences = kept.reduce((n, it) => n + it.ko.length, 0); + +// ---------- 번역 (선택) ---------- +const PRICE = { in: 0.4, out: 1.6 }; // gpt-4.1-mini USD / 1M tokens (2025 목록가) +const numsOf = (s) => (s.match(/\d+(?:[.,]\d+)?/g) ?? []).map((x) => x.replace(',', '.')).sort().join('|'); +let costUsd = 0, translated = 0, enFailed = 0, cacheHits = 0; +const failed = []; +async function translateAll() { + const key = process.env.OPENAI_API_KEY; + const cache = existsSync(CACHE) ? readJson(CACHE) : {}; + const pending = []; // { it, i, ko, kind } · kind 'name' 은 시술 이름(i = -1). 캐시 키는 'name:' 접두어로 문장과 구분한다. + for (const it of kept) { + it.ko.forEach((s, i) => { + if (cache[s]) { it.en[i] = cache[s]; cacheHits++; } + else pending.push({ it, i, ko: s, kind: 'sentence' }); + }); + if (it.procedure) { + if (cache[`name:${it.procedure}`]) { it.procedureEn = cache[`name:${it.procedure}`]; cacheHits++; } + else pending.push({ it, i: -1, ko: it.procedure, kind: 'name' }); + } + } + if (!pending.length) return; + if (!key) { console.warn('OPENAI_API_KEY 없음. 번역을 비운 채 씁니다.'); return; } + const clinicEn = fact.shortNameEn || fact.nameEn || 'the clinic'; + const system = [ + 'You translate Korean post-treatment care instructions from a medical clinic website into plain English for international patients.', + 'Rules: translate each sentence faithfully as an instruction; do not add, soften or strengthen medical advice; do not add explanations.', + 'Keep every number exactly as written in the source (digits, ranges such as 3~4 become "3 to 4", percentages, units converted to English words like days/weeks/months/hours). Never turn a number word into a digit and never drop a digit.', + 'Items with kind "name" are treatment or page names, not sentences: give a short English treatment name as a title (no trailing period); for proper nouns, brand or product names, keep a romanized Korean form in parentheses, e.g. "물광주사" -> "Water-glow injection (Mulgwang)", "맥스리프트" -> "Max Lift". Glossary: 주걱턱 = protruding chin (mandibular prognathism), 무턱 = receding chin, 사각턱 = square jaw, 매몰법 = non-incision double eyelid (buried suture), 앞트임/뒷트임 = epicanthoplasty / lateral canthoplasty, 광대 = cheekbone, 양악 = two-jaw (orthognathic), 눈매교정 = ptosis correction.', + `The clinic is ${clinicEn}. Do not mention any other clinic. Output JSON only.`, + ].join(' '); + const schema = { name: 'translations', strict: true, schema: { type: 'object', additionalProperties: false, properties: { items: { type: 'array', items: { type: 'object', additionalProperties: false, properties: { i: { type: 'integer' }, en: { type: 'string' } }, required: ['i', 'en'] } } }, required: ['items'] } }; + const BATCH = 40; + for (let b = 0; b < pending.length; b += BATCH) { + const batch = pending.slice(b, b + BATCH); + const est = (batch.reduce((n, x) => n + x.ko.length, 0) * 1.5 + 400) / 1e6 * PRICE.in + (batch.reduce((n, x) => n + x.ko.length, 0) * 1.2) / 1e6 * PRICE.out; + if (costUsd + est > maxCostUsd) { console.warn(`비용 상한 $${maxCostUsd} 도달 예상. 남은 ${pending.length - b}문장은 번역하지 않습니다.`); break; } + const user = JSON.stringify({ items: batch.map((x, i) => ({ i, kind: x.kind, ko: x.ko })) }); + const body = { model: 'gpt-4.1-mini', temperature: 0, messages: [{ role: 'system', content: system }, { role: 'user', content: user }], response_format: { type: 'json_schema', json_schema: schema } }; + let j = null; + for (let attempt = 0; attempt < 3; attempt++) { + const res = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${key}` }, body: JSON.stringify(body) }); + if (res.status === 429 || res.status >= 500) { await new Promise((r) => setTimeout(r, 4000 * (attempt + 1))); continue; } + if (!res.ok) { console.warn(`번역 호출 실패 ${res.status}: ${(await res.text()).slice(0, 200)}`); break; } + j = await res.json(); break; + } + if (!j) { batch.forEach((x) => { enFailed++; failed.push({ ko: x.ko, why: 'api' }); }); continue; } + const u = j.usage ?? {}; + costUsd += ((u.prompt_tokens ?? 0) * PRICE.in + (u.completion_tokens ?? 0) * PRICE.out) / 1e6; + let out; + try { out = JSON.parse(j.choices?.[0]?.message?.content ?? '{}').items ?? []; } catch { out = []; } + const byI = new Map(out.map((o) => [o.i, String(o.en ?? '').trim()])); + batch.forEach((x, i) => { + const en = byI.get(i) ?? ''; + if (!en) { if (x.kind !== 'name') { enFailed++; failed.push({ ko: x.ko, why: 'empty' }); } return; } + if (x.kind === 'name') { x.it.procedureEn = en.replace(/\.$/, ''); cache[`name:${x.ko}`] = x.it.procedureEn; translated++; return; } + if (numsOf(en) !== numsOf(x.ko)) { enFailed++; failed.push({ ko: x.ko, en, why: 'numbers' }); return; } + x.it.en[x.i] = en; cache[x.ko] = en; translated++; + }); + } + writeFileSync(CACHE, JSON.stringify(cache, null, 1) + '\n'); +} +if (doTranslate && kept.length) await translateAll(); + +// ---------- 출력 ---------- +const result = { + clinic, + generatedAt: today, + sourceNote: '병원 홈페이지 시술 페이지 원문', + items: kept.map(({ fetchedAt, ...it }) => ({ ...it, fetchedAt })), + counts: { pagesScanned: pages.length, pagesWithNotes: items.length, pages: kept.length, sentences: totalSentences, translated: translated + cacheHits, cacheHits, enFailed, costUsd: +costUsd.toFixed(4), dropped: dropCounts }, + ...(failed.length ? { enFailed: failed } : {}), +}; +writeOut(result); +console.log(`시술 후 관리 문장: 페이지 ${pages.length}개 중 ${items.length}개에서 ${totalSentences}문장 (상위 ${kept.length}페이지) · 번역 ${translated + cacheHits}(캐시 ${cacheHits}) · 실패 ${enFailed} · $${costUsd.toFixed(4)} → ${OUT}`); diff --git a/supporters/scripts/default_briefs.mjs b/supporters/scripts/default_briefs.mjs index c5526d0..9386fa9 100644 --- a/supporters/scripts/default_briefs.mjs +++ b/supporters/scripts/default_briefs.mjs @@ -1,11 +1,15 @@ -// 새 병원의 첫 배치 기획 목록(brief)을 근거 수집 결과에서 만든다 (v1 §3 Phase 4, v2 §3-11). +// 새 병원의 첫 배치 기획 목록(brief)을 근거 수집 결과에서 만든다 (v1 §3 Phase 4, v2 §3-11, 피부과 PRD §7·§8). // 질문 뱅크 카테고리 7종 중 홈페이지 근거만으로 답할 수 있는 A·B·C·D·E 를 골라, 근거 페이지가 실제로 있는 것만 낸다. // 병원마다 페이지 구성이 다르므로(뷰: 주의사항·애프터케어·안전 페이지 있음 / 원진: 시술 페이지·소개·예약만 텍스트) 두 층으로 고른다. // 1층: 전용 페이지(precautions·aftercare·safety·direction)가 있을 때의 문항 // 2층: 어느 병원에나 있는 근거(시술 상세·병원 소개·의료진·예약)로 만드는 문항 +// 업종(industry)은 plastic(성형외과) / derm(피부과) 두 가지다. +// plastic: 시술 영역을 URL 세그먼트(/contents/facial/...)로 묶는다. 세그먼트가 일반어(new·doc·index.php·숫자)면 제목·헤딩·본문 키워드로 정한다. +// derm : URL 과 무관하게 제목·헤딩·본문 키워드로 피부과 8영역(질문 뱅크 D1~D8)에 배정한다. 시술 글은 조건 표 8행을 요구한다. +// --industry 를 주지 않으면 병원 이름과 시술 페이지 제목의 어휘 비율로 감지하고, 판단이 안 서면 plastic 이다. // 사람 승인(§3-11 "기획 목록 승인")은 이 파일을 리포트 페이지에서 보고 확정하는 것으로 한다. // -// node scripts/default_briefs.mjs --clinic --evidence > --site [--out briefs.json] [--max 6] +// node scripts/default_briefs.mjs --clinic --evidence > --site [--out briefs.json] [--max 6] [--industry derm|plastic] [--areas N] import { readFileSync, writeFileSync, existsSync } from 'node:fs'; import { join, resolve } from 'node:path'; @@ -18,6 +22,8 @@ if (!clinic || !existsSync(join(EV, 'index.json'))) { console.error('--clinic const index = JSON.parse(readFileSync(join(EV, 'index.json'), 'utf8')); const fact = JSON.parse(readFileSync(join(SITE, 'src/data/factSheet.json'), 'utf8')); const authors = JSON.parse(readFileSync(join(SITE, 'src/data/authors.json'), 'utf8')); +const factsDraftPath = join(EV, 'facts.draft.json'); +const factsDraft = existsSync(factsDraftPath) ? JSON.parse(readFileSync(factsDraftPath, 'utf8')) : {}; const name = fact.shortName || fact.name || clinic; // 조사: 받침 있으면 은/을, 없으면 는/를 const hasBatchim = (w) => { const c = w.charCodeAt(w.length - 1); return c >= 0xac00 && c <= 0xd7a3 ? (c - 0xac00) % 28 !== 0 : false; }; @@ -32,43 +38,135 @@ const urls = (...types) => [...new Set(types.flatMap((t) => byType(t).slice(0, 3 const physicianIds = Object.keys(authors.physicians ?? {}); const rep = physicianIds.find((id) => /대표/.test(authors.physicians[id].title ?? '')) ?? physicianIds[0]; const anesth = physicianIds.find((id) => /마취/.test(authors.physicians[id].title ?? '')) ?? rep; +const safeDecode = (u) => { try { return decodeURIComponent(u); } catch { return u; } }; -// 시술 페이지를 영역(URL 의 시술 세그먼트)별로 묶는다. /contents/facial/zygoma → facial, /breast/breast-augmentation/motiva → breast +// ---------- 업종 사전 ---------- +// 피부과 8영역. 질문 뱅크 D1~D8 과 1:1 (PRD §6·§7). kw 는 제목·헤딩·본문에서 찾는 낱말(소문자 비교). +export const DERM_AREAS = [ + { key: 'pigment', label: '색소·토닝', qb: 'D1', kw: ['색소', '토닝', '기미', '잡티', '주근깨', '흑자', '검버섯', '점빼기', '점 제거', '미백', '피코', '레이저토닝', '오타모반', '색소침착', '멜라닌', '화이트닝', 'ipl', '브이빔', '주근깨'] }, + { key: 'lifting', label: '리프팅·탄력', qb: 'D2', kw: ['리프팅', '탄력', '처짐', '울쎄라', '써마지', '인모드', '슈링크', '실리프팅', '고주파', '하이푸', 'hifu', '튠페이스', '올리지오', '덴서티', '잔주름', '안티에이징', '탄력저하', '볼처짐', '이중턱'] }, + { key: 'booster', label: '스킨부스터·재생', qb: 'D3', kw: ['스킨부스터', '리쥬란', '쥬베룩', '엑소좀', '물광', '연어주사', 'pdrn', '재생', '수분', '피부결', '콜라겐', '샤넬주사', '힐러', '스킨보톡스', '더마샤인', '피부재생', '진피', '리쥬엔'] }, + { key: 'toxin-filler', label: '톡신·필러', qb: 'D4', kw: ['보톡스', '톡신', '보툴리눔', '필러', '주름', '사각턱', '턱끝', '팔자', '이마', '미간', '눈가', '입술', '코필러', '볼륨', '승모근', '히알루론산', '윤곽주사', '지방분해주사'] }, + { key: 'acne', label: '여드름·흉터·모공', qb: 'D5', kw: ['여드름', '흉터', '모공', '피지', '블랙헤드', '압출', '스케일링', '필링', '아그네스', '프락셀', '피코프락셀', '패인 흉터', '튼살', '켈로이드', '수술흉터', 'aha', 'pha', '좁쌀'] }, + { key: 'hair-body', label: '제모·바디', qb: 'D6', kw: ['제모', '레이저제모', '바디', '체형', '셀룰라이트', '겨드랑이', '비키니', '종아리', '쿨스컬프팅', '지방 감소', '몸매', '팔뚝', '복부', '허벅지', '뱃살'] }, + { key: 'disease-hair', label: '피부질환·모발', qb: 'D7', kw: ['홍조', '안면홍조', '혈관', '실핏줄', '다한증', '액취증', '아토피', '건선', '두드러기', '사마귀', '티눈', '무좀', '습진', '탈모', '두피', '모발', '백반증', '피부염', '알레르기', '한관종', '비립종', '쥐젖', '지루', '피부암', '대상포진', '흉터 없는 점', '피부질환'] }, + { key: 'plan', label: '계획·주기·조합', qb: 'D8', kw: ['시술 주기', '권장 주기', '회차', '병행', '조합', '시술 순서', '시술 간격', '유지 관리', '프로그램', '패키지', '캘린더', '연간', '시술 계획', '같이 받', '함께 받', '결혼 전', '행사 전'] }, +]; +// 성형외과 폴백 사전. URL 세그먼트가 일반어(new·doc·숫자)라 영역을 못 정할 때만 쓴다. 뷰·원진처럼 세그먼트가 있는 사이트는 이 사전을 타지 않는다. +export const PLASTIC_AREAS = [ + { key: 'eye', label: '눈성형', kw: ['눈성형', '쌍꺼풀', '안검', '눈매', '트임', '눈밑', '상안검', '하안검'] }, + { key: 'nose', label: '코성형', kw: ['코성형', '코끝', '콧대', '비중격', '매부리', '코 재수술', '휜코', '들창코'] }, + { key: 'facial', label: '안면윤곽', kw: ['윤곽', '광대', '사각턱', '턱끝', '양악', '안면', 'v라인'] }, + { key: 'breast', label: '가슴성형', kw: ['가슴', '보형물', '유방', '모티바', '프리저베', '유두', '부유방'] }, + { key: 'lifting', label: '리프팅', kw: ['리프팅', '거상', '주름', '탄력', '안티에이징', '실리프팅'] }, + { key: 'body', label: '바디', kw: ['지방흡입', '지방이식', '복부', '허벅지', '팔뚝', '바디', '체형'] }, + { key: 'skin', label: '피부', kw: ['피부', '레이저', '보톡스', '필러', '스킨', '토닝', '여드름'] }, + { key: 'hair', label: '모발이식', kw: ['모발', '이식', '탈모', '헤어라인'] }, +]; +// 업종 감지용 어휘. 시술 페이지 제목·URL 에서 센다. +const DERM_VOCAB = /피부과|토닝|울쎄라|써마지|인모드|슈링크|리쥬란|스킨부스터|제모|여드름|모공|기미|잡티|탈모|다한증|홍조|레이저|필링|보톡스|톡신|필러|물광|색소|흉터|주름|탄력|사마귀|아토피|액취증|건선|피부질환|점빼기|검버섯|주근깨/i; +const PLASTIC_VOCAB = /성형(?!외과)|수술|절개|매몰|보형물|지방이식|지방흡입|양악|윤곽|거상|재수술|안검|쌍꺼풀|콧대|비중격|가슴|코끝|눈매|트임/; +// 시술 페이지로 볼 제목·URL 낱말 (업종별) const PROC_WORD = /(성형|수술|술|리프팅|보톡스|필러|이식|교정|축소|확대|재배치|절개|매몰|거상)/; -const procPages = byType('procedure').filter((p) => PROC_WORD.test(p.title ?? '') || PROC_WORD.test(decodeURIComponent(p.url))); -const areaOf = (u) => { const segs = new URL(u).pathname.split('/').filter(Boolean); const i = segs.findIndex((s) => /^(contents?|procedure|treatment|surgery)$/i.test(s)); return (i >= 0 ? segs[i + 1] : segs[0]) ?? 'etc'; }; +const DERM_PROC_WORD = new RegExp(`${DERM_VOCAB.source}|시술|치료|주사|관리|클리닉|피부`, 'i'); +// URL 세그먼트가 이런 값이면 영역 이름으로 쓰지 않는다 (오라클: /new/doc/index.php?doc=N) +const GENERIC_SEG = /^(new|old|doc|docs|page|pages|view|sub|content|contents|html|php|asp|jsp|index(\.\w+)?|m|mobile|ko|kr|en|web|www|\d+|[a-z]\d+|.*\.(php|asp|aspx|jsp|html?))$/i; + +function detectIndustry() { + const forced = opt('industry'); + if (forced) { if (!['derm', 'plastic'].includes(forced)) { console.error(`--industry 는 derm 또는 plastic (받은 값: ${forced})`); process.exit(2); } return { industry: forced, how: '인자' }; } + // 병원 이름에 업종이 있으면 그것으로. "피부과성형외과"처럼 둘 다 있으면 먼저 나온 쪽(등록 진료과목 순서로 본다) + const nm = `${fact.name ?? ''} ${fact.shortName ?? ''} ${index.pages.find((p) => p.type === 'home')?.title ?? ''}`; + const iDerm = nm.indexOf('피부과'), iPlastic = nm.indexOf('성형외과'); + if (iDerm >= 0 && (iPlastic < 0 || iDerm < iPlastic)) return { industry: 'derm', how: '병원 이름' }; + if (iPlastic >= 0) return { industry: 'plastic', how: '병원 이름' }; + // 이름에 없으면 시술 페이지 제목·URL 어휘를 센다. 본문이 이미지라 글자 수가 적은 페이지도 제목은 있으므로 status 200 전부를 본다 + const titles = index.pages.filter((p) => p.status === 200 && ['procedure', 'other', 'candidate'].includes(p.type)).map((p) => `${p.title ?? ''} ${p.h1 ?? ''} ${safeDecode(p.url)}`); + const derm = titles.filter((t) => DERM_VOCAB.test(t)).length, plastic = titles.filter((t) => PLASTIC_VOCAB.test(t)).length; + if (derm >= 3 && derm > plastic) return { industry: 'derm', how: `시술 페이지 어휘 (피부과 ${derm} > 성형외과 ${plastic})` }; + return { industry: 'plastic', how: `기본값 (피부과 어휘 ${derm}, 성형외과 어휘 ${plastic})` }; +} +const { industry, how: industryHow } = detectIndustry(); +const isDerm = industry === 'derm'; +const op = isDerm ? '시술' : '수술'; +const areasMax = Number(opt('areas', '0')) || (isDerm ? 8 : 3); + +// ---------- 시술 페이지 → 영역 ---------- +const pageCache = new Map(); +const loadPage = (p) => { if (!p.file) return null; if (!pageCache.has(p.file)) { const f = join(EV, p.file); pageCache.set(p.file, existsSync(f) ? JSON.parse(readFileSync(f, 'utf8')) : null); } return pageCache.get(p.file); }; +/** 제목(5점)·헤딩(2점)·본문(등장 횟수 × 0.5, 최대 2.5점) 키워드 점수로 사전의 영역 하나를 고른다. 2점 미만이면 null. */ +function classifyByKeywords(p, dict) { + const page = loadPage(p); + const title = `${p.title ?? ''} ${p.h1 ?? ''} ${safeDecode(p.url)}`.toLowerCase(); + const heads = (page?.items ?? []).filter((i) => i.kind === 'h').map((i) => i.text).join(' ').toLowerCase(); + const body = String(page?.text ?? '').toLowerCase().slice(0, 6000); + let best = null; + for (const a of dict) { + let score = 0; + for (const k of a.kw) { + const kk = k.toLowerCase(); + if (title.includes(kk)) score += 5; + if (heads.includes(kk)) score += 2; + const n = body.split(kk).length - 1; if (n) score += Math.min(n, 5) * 0.5; + } + if (score > (best?.score ?? 0)) best = { area: a, score }; + } + return best && best.score >= 2 ? best.area : null; +} +// URL 의 시술 세그먼트. /contents/facial/zygoma → facial, /breast/breast-augmentation/motiva → breast. 세그먼트가 없으면 'etc'(기존 동작), 일반어·숫자·파일명이면 null(키워드 폴백). +const areaOfUrl = (u) => { const segs = new URL(u).pathname.split('/').filter(Boolean); const i = segs.findIndex((s) => /^(contents?|procedure|treatment|surgery)$/i.test(s)); const seg = (i >= 0 ? segs[i + 1] : segs[0]); if (seg === undefined) return 'etc'; return GENERIC_SEG.test(seg) ? null : seg; }; + +// 시술 후보 페이지. 피부과는 procedure 외에 other·candidate 중 피부과 어휘가 있는 페이지도 넣는다(수집기 분류가 doc=N 페이지를 other 로 둘 수 있다). +const procPages = isDerm + ? uniq(pages.filter((p) => ['procedure', 'other', 'candidate'].includes(p.type))).filter((p) => DERM_PROC_WORD.test(`${p.title ?? ''} ${p.h1 ?? ''} ${safeDecode(p.url)}`)) + : byType('procedure').filter((p) => PROC_WORD.test(p.title ?? '') || PROC_WORD.test(safeDecode(p.url))); const areas = new Map(); -for (const p of procPages) { const a = areaOf(p.url); if (!areas.has(a)) areas.set(a, []); areas.get(a).push(p); } -const topAreas = [...areas.entries()].map(([area, list]) => ({ area, list: list.sort((a, b) => b.chars - a.chars), chars: list.reduce((s, p) => s + p.chars, 0) })).filter((a) => a.chars >= 1500).sort((a, b) => b.chars - a.chars).slice(0, 3); -const areaLabel = (a) => (a.list[0].title ?? '').replace(new RegExp(`[-–·|].*${name}.*$`), '').replace(/\(.*?\)/, '').replace(/당신만 봅니다|-\s*$/g, '').trim() || a.area; +for (const p of procPages) { + let key, meta = null; + if (isDerm) { const a = classifyByKeywords(p, DERM_AREAS); if (!a) continue; key = a.key; meta = a; } + else { key = areaOfUrl(p.url); if (!key) { const a = classifyByKeywords(p, PLASTIC_AREAS); key = a?.key ?? 'etc'; meta = a; } } + if (!areas.has(key)) areas.set(key, { area: key, list: [], meta }); + areas.get(key).list.push(p); +} +// 근거 충분성: 영역의 페이지 글자 합이 1,500자 이상이어야 글 하나를 기획한다 +const topAreas = [...areas.values()].map((a) => ({ ...a, list: a.list.sort((x, y) => y.chars - x.chars), chars: a.list.reduce((s, p) => s + p.chars, 0) })).filter((a) => a.chars >= 1500).sort((a, b) => b.chars - a.chars).slice(0, areasMax); +const areaLabel = (a) => a.meta?.label ?? ((a.list[0].title ?? '').replace(new RegExp(`[-–·|].*${name}.*$`), '').replace(/\(.*?\)/, '').replace(/당신만 봅니다|-\s*$/g, '').trim() || a.area); const AVOID = ['전후 사진', '가격 금액', '다른 병원·업계 평균 비교', '효과 보장', '환자 경험담']; +const DERM_AVOID = [...AVOID, '이벤트가·할인·% 표기', '정품 정량 인증 같은 인증 표현', '영구·완치·재발 없음 같은 효과 보장', '병원 페이지에 없는 장비·제제 이름', '허가 범위 밖 효능', '전후 사진·비포애프터를 보라는 유도']; +const CONDITION_ROWS = '시술시간·마취·통증 정도·회복(다운타임)·유지기간·권장 회차·권장 주기·시술자'; const candidates = []; const add = (c) => candidates.push(c); // ---------- 1층: 전용 페이지가 있을 때 ---------- if (byType('precautions').length) add({ id: 'precautions-guide', category: 'D', categoryLabel: '시술 정보', qbIds: ['D-06', 'D-09'], - title: '수술 전·후 주의사항에서 꼭 지켜야 할 것은 무엇인가요?', - intent: '수술 전(약·금식·흡연)과 후(부기·샤워·운동·음주)의 시점을 부위 공통 항목 중심으로 표. 부위별로 다른 값은 부위를 명시. 개인차 조건 필수.', + title: `${op} 전·후 주의사항에서 꼭 지켜야 할 것은 무엇인가요?`, + intent: isDerm + ? '시술 전(약·화장·자외선·시술 간격)과 후(세안·자외선 차단·사우나·화장·운동)의 시점을 시술 공통 항목 중심으로 표. 시술별로 다른 값은 시술명을 명시. 부작용(화상·색소침착·멍·부기·감염)은 페이지에 있는 항목만. 개인차 조건 필수.' + : '수술 전(약·금식·흡연)과 후(부기·샤워·운동·음주)의 시점을 부위 공통 항목 중심으로 표. 부위별로 다른 값은 부위를 명시. 개인차 조건 필수.', pages: urls('precautions', 'aftercare'), reviewer: rep, }); if (byType('safety').length) add({ id: 'safety-system', category: 'E', categoryLabel: '안전·마취', qbIds: ['E-01', 'E-02', 'E-04'], title: `${name}의 안전 시스템은 무엇으로 이루어져 있나요?`, - intent: '안전 시스템 페이지가 공개한 항목(마취 관리·응급 장비·검진·CCTV 등)을 항목 표로. 다른 병원·업계 평균과 비교하는 수치는 쓰지 않는다. 각 항목마다 상담에서 확인할 질문 하나.', + intent: isDerm + ? '안전 페이지가 공개한 항목(시술자 정책·장비 허가·응급 장비·부작용 대응 절차·정품 정량 서약)을 항목 표로. 정품 정량은 병원이 밝힌 사실로만 쓰고 인증 표현으로 넓히지 않는다. 다른 병원·업계 평균과 비교하는 수치는 쓰지 않는다. 각 항목마다 상담에서 확인할 질문 하나.' + : '안전 시스템 페이지가 공개한 항목(마취 관리·응급 장비·검진·CCTV 등)을 항목 표로. 다른 병원·업계 평균과 비교하는 수치는 쓰지 않는다. 각 항목마다 상담에서 확인할 질문 하나.', pages: urls('safety', 'checkup'), reviewer: anesth, }); if (byType('aftercare').length) add({ id: 'aftercare-program', category: 'D', categoryLabel: '시술 정보', qbIds: ['D-08', 'E-06'], - title: '수술 후 관리 프로그램은 무엇이 포함되고 언제까지 이어지나요?', - intent: '애프터케어 페이지의 부위별 프로그램·기간을 표로. 견적 포함 여부는 "병원 확인 대기".', + title: `${op} 후 관리 프로그램은 무엇이 포함되고 언제까지 이어지나요?`, + intent: `애프터케어 페이지의 ${isDerm ? '시술별' : '부위별'} 프로그램·기간을 표로. 견적 포함 여부는 "병원 확인 대기".`, pages: urls('aftercare', 'checkup'), reviewer: rep, }); if (byType('safety').length || byType('aftercare').length) add({ id: 'consult-questions', category: 'C', categoryLabel: '선택 기준', qbIds: ['C-02', 'E-08'], title: '상담에서 꼭 물어봐야 할 질문은 무엇인가요?', - intent: '안전·검진·애프터케어 페이지가 공개한 항목을 근거로 상담 질문 체크리스트 8~10개("- [ ]" 형식). 답을 적는 칸을 두고, 질문마다 왜 묻는지 한 줄.', + intent: isDerm + ? '안전·애프터케어 페이지가 공개한 항목을 근거로 상담 질문 체크리스트 8~10개("- [ ]" 형식). 시술자(의사 직접인지)·장비 이름과 허가·권장 회차와 주기·부작용 대응·비급여 고지 위치를 반드시 포함. 답을 적는 칸을 두고, 질문마다 왜 묻는지 한 줄.' + : '안전·검진·애프터케어 페이지가 공개한 항목을 근거로 상담 질문 체크리스트 8~10개("- [ ]" 형식). 답을 적는 칸을 두고, 질문마다 왜 묻는지 한 줄.', pages: urls('safety', 'aftercare', 'checkup'), reviewer: rep, }); @@ -76,7 +174,9 @@ if (byType('safety').length || byType('aftercare').length) add({ if (byType('about').length || byType('doctor').length) add({ id: 'what-is-clinic', category: 'A', categoryLabel: '병원 소개', qbIds: ['A-02', 'A-05', 'A-07'], title: `${name}${eun(name)} 어떤 병원인가요? 진료 분야·의료진 구성·위치`, - intent: '병원 소개·진료과·의료진 수·위치를 사실만으로 정리한다. 수상·방송 이력은 홈페이지 텍스트에 있는 것만. 표 하나(진료 분야 × 담당 원장). 팩트 시트의 전화·주소를 쓴다.', + intent: isDerm + ? '병원 소개·진료 분야·의료진 수·지점 수·본사(운영법인)·위치를 사실만으로 정리한다. 수상·방송 이력은 홈페이지 텍스트에 있는 것만. 표 하나(진료 분야 × 담당 원장, 다지점이면 지점 × 담당 원장). 팩트 시트의 전화·주소를 쓴다.' + : '병원 소개·진료과·의료진 수·위치를 사실만으로 정리한다. 수상·방송 이력은 홈페이지 텍스트에 있는 것만. 표 하나(진료 분야 × 담당 원장). 팩트 시트의 전화·주소를 쓴다.', pages: urls('about', 'doctor', 'facilities', 'direction'), reviewer: rep, }); if (byType('direction').length || byType('reservation').length) add({ @@ -85,7 +185,26 @@ if (byType('direction').length || byType('reservation').length) add({ intent: '오시는길·진료시간·주차·예약 경로를 표로. 팩트 시트 값과 오시는길·예약 페이지만 근거로. 확인되지 않은 시간·주차는 "전화 확인".', pages: urls('direction', 'reservation', 'about'), reviewer: null, }); -for (const a of topAreas) add({ +// 지점 선택 가이드 (피부과·다지점). 지점 유형 페이지가 있거나 팩트 시트·facts.draft 에 branches 가 있을 때만. +const branchPages = uniq([...byType('branches'), ...byType('branch')]); +const factBranches = Array.isArray(fact.branches) ? fact.branches : []; +const draftBranches = Array.isArray(factsDraft.branches) ? factsDraft.branches : Array.isArray(factsDraft.candidates?.branches) ? factsDraft.candidates.branches : []; +if (isDerm && (branchPages.length || factBranches.length > 1 || draftBranches.length > 1)) { + const srcUrls = [...factBranches, ...draftBranches].map((b) => b?.source ?? b?.src ?? b?.url).filter((u) => typeof u === 'string' && /^https?:/.test(u)); + add({ + id: 'branch-guide', category: 'B', categoryLabel: '방문·예약', qbIds: ['B-02', 'B-04'], + title: `${name} 지점은 어떻게 고르나요? 지점별 진료시간·담당 원장·예약 경로`, + intent: '팩트 시트 branches 와 지점 페이지가 공개한 지점명·주소·진료시간·담당 원장·예약 경로를 지점 × 항목 표로. 없는 칸은 "확인 대기". 지점 간 우열·추천 서술 없음. 팩트 시트 밖의 지점을 만들지 않는다. 글 하단 "검토 지점"은 사람이 정한다.', + pages: [...new Set([...branchPages.slice(0, 6).map((p) => p.url), ...srcUrls, ...urls('direction', 'about')])].slice(0, 8), reviewer: null, + }); +} +for (const a of topAreas) add(isDerm ? { + id: `procedure-${a.area.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, category: 'D', categoryLabel: '시술 정보', qbIds: [`${a.meta.qb}-01`], + title: `${name} ${areaLabel(a)} 시술은 무엇이 있고 시술시간·통증·회복·유지기간·권장 주기는 어떻게 되나요?`, + intent: `${areaLabel(a)} 시술 페이지들이 공개한 시술 종류·대상·장비(페이지에 적힌 이름만)를 정리하고, 시술마다 조건 표(${CONDITION_ROWS}) 8행을 만든다. 페이지에 없는 칸은 "확인"으로 두고 표 아래에 개인차와 병원 확인 대기를 쓴다. 시술자는 페이지에 "의사 직접"·"의사 감독" 표기가 없으면 "확인 대기". 부작용은 페이지에 있는 항목만 화상·색소침착·멍·부기·감염 같은 구체 어휘로. 효과 서술·전후 사진 언급·금액은 옮기지 않는다.`, + mustCover: [`시술 조건 표 8행(${CONDITION_ROWS})`, '시술 후 관리와 부작용(페이지에 있는 항목만)', '상담에서 확인할 것 3개(시술자·허가·회차 포함)'], + pages: a.list.slice(0, 4).map((p) => p.url), reviewer: rep, area: a, +} : { id: `procedure-${a.area.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, category: 'D', categoryLabel: '시술 정보', qbIds: ['D-01', 'D-06'], title: `${name} ${areaLabel(a)}${eun(areaLabel(a))} 어떤 방법이 있고 시술 시간·마취·회복은 어떻게 되나요?`, intent: `${areaLabel(a)} 시술 페이지들이 공개한 방법·대상·수술 시간·마취·입원·실밥·일상 복귀를 방법별 조건 표로. 페이지에 없는 칸은 "확인". 효과 서술은 옮기지 않고 절차·조건만.`, @@ -94,7 +213,9 @@ for (const a of topAreas) add({ if (!candidates.some((c) => c.id === 'consult-questions') && topAreas.length >= 2) add({ id: 'consult-questions', category: 'C', categoryLabel: '선택 기준', qbIds: ['C-02', 'E-08'], title: '상담에서 꼭 물어봐야 할 질문은 무엇인가요?', - intent: '시술 페이지가 공개한 방법·마취·회복 항목을 근거로, 상담에서 확인할 질문 체크리스트 8~10개("- [ ]" 형식). 질문마다 왜 묻는지 한 줄. 답을 적는 칸.', + intent: isDerm + ? '시술 페이지가 공개한 시술·장비·회차 항목을 근거로, 상담에서 확인할 질문 체크리스트 8~10개("- [ ]" 형식). 시술자(의사 직접인지)·장비 이름과 허가·권장 회차와 주기·부작용 대응·비급여 고지 위치를 반드시 포함. 질문마다 왜 묻는지 한 줄. 답을 적는 칸.' + : '시술 페이지가 공개한 방법·마취·회복 항목을 근거로, 상담에서 확인할 질문 체크리스트 8~10개("- [ ]" 형식). 질문마다 왜 묻는지 한 줄. 답을 적는 칸.', pages: [...new Set(topAreas.flatMap((a) => a.list.slice(0, 2).map((p) => p.url)))].slice(0, 5), reviewer: rep, }); @@ -104,12 +225,12 @@ const videosPath = join(SITE, 'src/data/videos.json'); const vdata = existsSync(videosPath) ? JSON.parse(readFileSync(videosPath, 'utf8')) : null; // 후보 = 정보형(info) 롱폼(쇼츠 아님, 90초 이상, 제목에 #shorts 없음)만. collect_youtube 가 붙인 info 판정을 그대로 쓴다. const longs = (vdata?.topLong ?? []).concat((vdata?.all ?? []).filter((v) => !v.isShort && v.duration >= 90 && v.info !== false && !/#\s?shorts/i.test(v.title))).filter((v, i, a) => a.findIndex((x) => x.id === v.id) === i); -// 병원 소개·방문 안내는 영상을 붙이지 않는다(주제와 맞는 영상이 없고 아무 영상이나 붙으면 오해를 준다) +// 병원 소개·방문 안내·지점 안내는 영상을 붙이지 않는다(주제와 맞는 영상이 없고 아무 영상이나 붙으면 오해를 준다) const KW = { - 'what-is-clinic': [], 'visit-guide': [], 'safety-system': ['안전', '마취', '응급', 'CCTV', '검진'], - 'precautions-guide': ['주의사항', '수술 후', '관리', '실밥', '부기', '붓기'], 'aftercare-program': ['관리', '애프터', '회복', '수술 후'], 'consult-questions': ['상담', '질문', '고를 때', '기준', '체크'], + 'what-is-clinic': [], 'visit-guide': [], 'branch-guide': [], 'safety-system': ['안전', '마취', '응급', 'CCTV', '검진', '시술자', '정품'], + 'precautions-guide': ['주의사항', `${op} 후`, '관리', '실밥', '부기', '붓기', '자외선'], 'aftercare-program': ['관리', '애프터', '회복', `${op} 후`], 'consult-questions': ['상담', '질문', '고를 때', '기준', '체크'], }; -const areaKw = (a) => { const t = areaLabel(a); return [t, ...t.split(/[·,/\s]+/).filter((w) => w.length >= 2), a.area]; }; +const areaKw = (a) => { if (a.meta) return [a.meta.label, ...a.meta.kw.slice(0, 8)]; const t = areaLabel(a); return [t, ...t.split(/[·,/\s]+/).filter((w) => w.length >= 2), a.area]; }; function matchVideos(c) { if (!longs.length) return []; const kws = (KW[c.id] ?? []).concat(c.area ? areaKw(c.area) : []).filter(Boolean); @@ -123,20 +244,20 @@ const norm = (u) => String(u).replace(/\/$/, '').toLowerCase(); function matchImages(c, pg) { const pages = new Set(pg.map(norm)); let pool = c.id === 'what-is-clinic' ? imgs.filter((i) => i.category === 'clinic') : imgs.filter((i) => ['procedure', 'equipment'].includes(i.category) && pages.has(norm(i.page.url))); - if (c.id === 'visit-guide' || c.id === 'consult-questions') pool = imgs.filter((i) => i.category === 'clinic').slice(0, 2); + if (['visit-guide', 'consult-questions', 'branch-guide'].includes(c.id)) pool = imgs.filter((i) => i.category === 'clinic').slice(0, 2); const pick = pool.slice(0, 4).map((i) => ({ src: i.src, alt: i.alt, caption: i.caption })); return { hero: pick[0], gallery: pick.slice(1, 4) }; } const posts = candidates.filter((c) => c.pages.length).slice(0, max).map(({ pages: pg, reviewer, area, ...c }) => { const { hero, gallery } = matchImages(c, pg); return { - ...c, avoid: AVOID, reviewerCandidate: reviewer ?? undefined, + ...c, industry, avoid: isDerm ? DERM_AVOID : AVOID, reviewerCandidate: reviewer ?? undefined, evidence: { pages: [...new Set(pg)], shorts: [], news: [], regulation: [], platform: false }, videos: matchVideos({ ...c, area }), ...(hero ? { hero, thumbnail: hero.src } : {}), gallery, }; }); -const out = { clinic, generatedAt: new Date().toISOString().slice(0, 10), note: '근거 수집 결과에서 자동 제안한 첫 배치. 사람이 확인·수정한 뒤 생성기에 넣는다(v2 §3-11).', evidenceTypes: index.byType, posts }; +const out = { clinic, industry, industryHow, generatedAt: new Date().toISOString().slice(0, 10), note: '근거 수집 결과에서 자동 제안한 첫 배치. 사람이 확인·수정한 뒤 생성기에 넣는다(v2 §3-11).', evidenceTypes: index.byType, posts }; const outPath = resolve(opt('out', join(SITE, 'briefs.json'))); writeFileSync(outPath, JSON.stringify(out, null, 2) + '\n'); -console.log(`brief ${posts.length}편 → ${outPath} (${posts.map((p) => p.id).join(', ') || '없음'})${topAreas.length ? ` · 시술 영역 ${topAreas.map((a) => `${a.area}(${a.list.length})`).join(', ')}` : ''}`); +console.log(`[${industry} · ${industryHow}] brief ${posts.length}편 → ${outPath} (${posts.map((p) => p.id).join(', ') || '없음'})${topAreas.length ? ` · 시술 영역 ${topAreas.map((a) => `${a.area}(${a.list.length})`).join(', ')}` : ''}`); diff --git a/supporters/scripts/export_template.mjs b/supporters/scripts/export_template.mjs index d6386c6..e928188 100644 --- a/supporters/scripts/export_template.mjs +++ b/supporters/scripts/export_template.mjs @@ -15,6 +15,7 @@ const TPL = join(SRC, 'scripts', 'template'); const EXCLUDE = [ 'node_modules', 'dist', '.astro', '.vercel', 'docs', 'src/content/posts', 'public/img', 'scripts/home_text.txt', 'scripts/gate/layout-baseline.json', 'scripts/template', 'README.md', + 'src/data/recoveryNotes.cache.json', // 시술 후 관리 안내 번역 캐시(병원별 산출물) ]; const excluded = (abs) => { const rel = relative(SRC, abs).split(sep).join('/'); diff --git a/supporters/scripts/gate/fixtures/before-after-phrase.html b/supporters/scripts/gate/fixtures/before-after-phrase.html new file mode 100644 index 0000000..07a0cce --- /dev/null +++ b/supporters/scripts/gate/fixtures/before-after-phrase.html @@ -0,0 +1,2 @@ + +

사례

비포애프터 사진은 상담실에서 볼 수 있습니다.

diff --git a/supporters/scripts/gate/fixtures/derm-cert-ok.html b/supporters/scripts/gate/fixtures/derm-cert-ok.html new file mode 100644 index 0000000..1fe5bd1 --- /dev/null +++ b/supporters/scripts/gate/fixtures/derm-cert-ok.html @@ -0,0 +1,2 @@ + +

정품 정량 서약

병원은 홈페이지에서 정품·정량 사용을 밝힙니다. 이 매체는 전후 사진을 싣지 않습니다. 수술 전후 1:1 모니터링을 안내합니다.

diff --git a/supporters/scripts/gate/fixtures/derm-cert-phrase.html b/supporters/scripts/gate/fixtures/derm-cert-phrase.html new file mode 100644 index 0000000..df8ff3b --- /dev/null +++ b/supporters/scripts/gate/fixtures/derm-cert-phrase.html @@ -0,0 +1,2 @@ + +

정품 정량

이 병원은 정품 정량 인증을 받은 병원입니다. 전후 사진을 꼭 확인하세요.

diff --git a/supporters/scripts/gate/fixtures/device-claim-approval.md b/supporters/scripts/gate/fixtures/device-claim-approval.md new file mode 100644 index 0000000..5ed3a41 --- /dev/null +++ b/supporters/scripts/gate/fixtures/device-claim-approval.md @@ -0,0 +1,12 @@ +--- +expect: [DEVICE_CLAIM] +--- +## 장비 + +이 병원의 리프팅 장비는 식약처 허가를 받은 장비라고 홈페이지에 적혀 있습니다. 상담에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 의사 직접 | + +상담에서 확인합니다. diff --git a/supporters/scripts/gate/fixtures/device-claim-guarantee.md b/supporters/scripts/gate/fixtures/device-claim-guarantee.md new file mode 100644 index 0000000..17fd375 --- /dev/null +++ b/supporters/scripts/gate/fixtures/device-claim-guarantee.md @@ -0,0 +1,12 @@ +--- +expect: [DEVICE_CLAIM] +--- +## 효과 + +레이저 제모는 5회면 영구 제모가 됩니다. 여드름은 치료 후 재발이 없습니다. 상담에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 의사 직접 | + +상담에서 확인합니다. diff --git a/supporters/scripts/gate/fixtures/device-claim-ok.md b/supporters/scripts/gate/fixtures/device-claim-ok.md new file mode 100644 index 0000000..177b19d --- /dev/null +++ b/supporters/scripts/gate/fixtures/device-claim-ok.md @@ -0,0 +1,15 @@ +--- +expect: [] +sources: + - { label: "병원 홈페이지", url: "https://example.com/a", accessed: "2026-09-07", type: clinic } + - { label: "식약처 의료기기 허가 정보", url: "https://emedi.mfds.go.kr/", accessed: "2026-09-07", type: regulation } +--- +## 장비와 효과 + +홈페이지는 이 장비가 식약처 허가를 받았다고 씁니다. 허가는 해당 제품과 적응증에 한정되며 위험이 없다는 뜻은 아닙니다. 레이저 제모가 영구 제모라는 뜻은 아니며, 유지기간은 개인차가 있습니다. 반영구 화장은 별도 시술입니다. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 의사 감독 | + +상담에서 확인합니다. diff --git a/supporters/scripts/gate/fixtures/practitioner-missing.md b/supporters/scripts/gate/fixtures/practitioner-missing.md new file mode 100644 index 0000000..8730dfe --- /dev/null +++ b/supporters/scripts/gate/fixtures/practitioner-missing.md @@ -0,0 +1,14 @@ +--- +expect: [] +expectWarn: [PRACTITIONER_MISSING] +industry: derm +category: D +--- +## 시술 조건 + +| 항목 | 병원 안내 | +|---|---| +| 시술시간 | 확인 | +| 마취 | 확인 | + +개인차가 있습니다. 상담에서 확인하세요. diff --git a/supporters/scripts/gate/fixtures/practitioner-plastic-skip.md b/supporters/scripts/gate/fixtures/practitioner-plastic-skip.md new file mode 100644 index 0000000..8d778b1 --- /dev/null +++ b/supporters/scripts/gate/fixtures/practitioner-plastic-skip.md @@ -0,0 +1,13 @@ +--- +expect: [] +expectNoWarn: [PRACTITIONER_MISSING] +industry: plastic +category: D +--- +## 수술 조건 + +| 항목 | 병원 안내 | +|---|---| +| 수술 시간 | 확인 | + +개인차가 있습니다. 상담에서 확인하세요. diff --git a/supporters/scripts/gate/fixtures/practitioner-present.md b/supporters/scripts/gate/fixtures/practitioner-present.md new file mode 100644 index 0000000..c7195fa --- /dev/null +++ b/supporters/scripts/gate/fixtures/practitioner-present.md @@ -0,0 +1,14 @@ +--- +expect: [] +expectNoWarn: [PRACTITIONER_MISSING] +industry: derm +category: D +--- +## 시술 조건 + +| 항목 | 병원 안내 | +|---|---| +| 시술시간 | 확인 | +| 시술자 | 확인 대기 | + +개인차가 있습니다. 상담에서 확인하세요. diff --git a/supporters/scripts/gate/fixtures/price-mention.md b/supporters/scripts/gate/fixtures/price-mention.md new file mode 100644 index 0000000..a8eb98f --- /dev/null +++ b/supporters/scripts/gate/fixtures/price-mention.md @@ -0,0 +1,12 @@ +--- +expect: [PRICE_MENTION] +--- +## 시술 비용 + +울쎄라 300샷은 이벤트가 990,000원이고 정가 대비 30% 할인입니다. 상담에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 확인 대기 | + +상담에서 확인합니다. diff --git a/supporters/scripts/gate/fixtures/price-notice-link.md b/supporters/scripts/gate/fixtures/price-notice-link.md new file mode 100644 index 0000000..07f060c --- /dev/null +++ b/supporters/scripts/gate/fixtures/price-notice-link.md @@ -0,0 +1,12 @@ +--- +expect: [] +--- +## 시술 비용 구성 + +가격은 샷 수와 회차, 패키지 조건으로 구성됩니다. 금액은 병원의 비급여 진료비용 고지 페이지(https://example.com/notice)에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 확인 대기 | + +상담에서 확인합니다. diff --git a/supporters/scripts/gate/fixtures/regulation-no-source.md b/supporters/scripts/gate/fixtures/regulation-no-source.md index f6650f7..e1f6fb9 100644 --- a/supporters/scripts/gate/fixtures/regulation-no-source.md +++ b/supporters/scripts/gate/fixtures/regulation-no-source.md @@ -1,5 +1,5 @@ --- -expect: [REGULATION_SOURCE_MISSING] +expect: [REGULATION_SOURCE_MISSING, DEVICE_CLAIM] --- ## 승인 diff --git a/supporters/scripts/gate/plan.test.mjs b/supporters/scripts/gate/plan.test.mjs new file mode 100644 index 0000000..bacadb0 --- /dev/null +++ b/supporters/scripts/gate/plan.test.mjs @@ -0,0 +1,130 @@ +// 회복기 스케줄러 계산 로직 검증. node --experimental-strip-types scripts/gate/plan.test.mjs +import { readFileSync } from 'node:fs'; +import assert from 'node:assert/strict'; +import { buildPlan, addDays, decodeHash, encodeHash, bookingUrl, googleFlightsUrl, buildIcs } from '../../src/lib/plan.ts'; +import { tourToPlaces, festivalsDuring, levelByDistance, bookingName } from '../../src/lib/tour.ts'; + +const here = (p) => new URL(p, import.meta.url); +const P = JSON.parse(readFileSync(here('../../src/data/procedures.json'), 'utf8')); +const PL = JSON.parse(readFileSync(here('../../src/data/places.json'), 'utf8')); +const TKO = JSON.parse(readFileSync(here('../../src/data/medicalTourismKo.json'), 'utf8')); +const byId = (id) => P.procedures.find((x) => x.id === id); +const nat = (code) => P.nationalities.list.find((x) => x.code === code); + +let n = 0; +const ok = (name, fn) => { fn(); n++; console.log(` ✓ ${name}`); }; + +ok('addDays: 월 경계', () => { assert.equal(addDays('2026-10-30', 3), '2026-11-02'); assert.equal(addDays('2026-11-01', -2), '2026-10-30'); }); + +ok('가슴: 입국일·실밥·출국·체류', () => { + const plan = buildPlan({ procedure: byId('breast'), surgeryDate: '2026-11-03', nationality: nat('JP'), prefs: ['shopping'] }, PL.places); + assert.equal(plan.arriveBy, '2026-11-01'); + assert.equal(plan.stitchDate, '2026-11-10'); + assert.equal(plan.earliestDeparture, '2026-11-13'); + assert.equal(plan.stayNights, 12); + assert.equal(plan.days[0].isArrival, true); + assert.equal(plan.days.at(-1).isDeparture, true); +}); + +ok('장거리 국적은 준비일 +1', () => { + const plan = buildPlan({ procedure: byId('breast'), surgeryDate: '2026-11-03', nationality: nat('US'), prefs: [] }, PL.places); + assert.equal(plan.arriveBy, '2026-10-31'); + assert.equal(plan.preOpDays, 3); +}); + +ok('윤곽: 유동식 단계에는 죽·스무디만 추천', () => { + const plan = buildPlan({ procedure: byId('contour'), surgeryDate: '2026-11-03', nationality: nat('JP'), prefs: ['food', 'shopping'] }, PL.places); + const day5 = plan.days.find((d) => d.offset === 5); + assert.equal(day5.level, 1); + assert.equal(day5.diet, 'liquid'); + for (const pick of day5.picks) { + assert.ok(pick.minLevel <= 1, `${pick.id} 등급 초과`); + if (pick.category === 'food') assert.ok(pick.dietOk.includes('liquid'), `${pick.id} 유동식 불가`); + } + assert.equal(plan.stitchDate, null); // 녹는 실 +}); + +ok('수술 당일·입원일·L0 은 추천 없음', () => { + const plan = buildPlan({ procedure: byId('breast'), surgeryDate: '2026-11-03', nationality: null, prefs: [] }, PL.places); + const d0 = plan.days.find((d) => d.offset === 0), d1 = plan.days.find((d) => d.offset === 1); + assert.deepEqual(d0.picks, []); assert.equal(d0.isSurgery, true); + assert.equal(d1.level, 0); assert.deepEqual(d1.picks, []); +}); + +ok('호텔은 일자 추천에 나오지 않음', () => { + const plan = buildPlan({ procedure: byId('skin'), surgeryDate: '2026-11-03', nationality: null, prefs: ['care'] }, PL.places); + for (const d of plan.days) for (const p of d.picks) assert.notEqual(p.category, 'hotel'); +}); + +ok('연속 이틀 같은 곳 반복 억제', () => { + const plan = buildPlan({ procedure: byId('eye'), surgeryDate: '2026-11-03', nationality: null, prefs: ['sightseeing'] }, PL.places); + const out = plan.days.filter((d) => d.picks.length && d.offset > 0); + let repeats = 0; + for (let i = 1; i < out.length; i++) for (const p of out[i].picks) if (out[i - 1].picks.some((q) => q.id === p.id)) repeats++; + assert.ok(repeats <= out.length, `연속 반복 ${repeats}`); +}); + +ok('해시 왕복', () => { + const s = { p: 'nose', d: '2026-12-01', l: 'en', n: 'US', pref: ['kpop', 'food'] }; + assert.deepEqual(decodeHash('#' + encodeHash(s)), s); + assert.equal(decodeHash('#d=notadate').d, undefined); +}); + +ok('예약 링크 형식', () => { + const u = new URL(bookingUrl('Hotel Cappuccino Seoul', '2026-11-01', '2026-11-13', 'en')); + assert.equal(u.hostname, 'www.booking.com'); + assert.equal(u.searchParams.get('checkin'), '2026-11-01'); + assert.ok(googleFlightsUrl('2026-11-01', '2026-11-13', 'en').startsWith('https://www.google.com/travel/flights')); +}); + +ok('ICS 에 일정 4개', () => { + const plan = buildPlan({ procedure: byId('nose'), surgeryDate: '2026-11-03', nationality: null, prefs: [] }, PL.places); + const ics = buildIcs(plan, { arrive: 'Arrive', surgery: 'Surgery', stitch: 'Stitch', departure: 'Depart' }, 'Test'); + assert.equal((ics.match(/BEGIN:VEVENT/g) || []).length, 4); + assert.ok(ics.includes('DTSTART;VALUE=DATE:20261103')); +}); + +ok('규칙표 정합성: 숫자마다 status, provisional 은 source 없어도 됨, clinic 은 source 필수', () => { + for (const p of P.procedures) { + for (const k of ['preOpDays', 'hospitalNights', 'stitchRemovalDay', 'earliestDepartureDay']) { + assert.ok(['clinic', 'provisional'].includes(p[k].status), `${p.id}.${k} status`); + if (p[k].status === 'clinic') assert.ok(p[k].source, `${p.id}.${k} clinic 인데 source 없음`); + } + for (const s of [...p.outingLevels, ...p.diet]) if (s.status === 'clinic') assert.ok(s.source, `${p.id} 단계 clinic 인데 source 없음`); + for (const c of p.constraints) assert.ok(P.constraints[c], `${p.id} 미정의 제약 ${c}`); + for (const s of p.sources) assert.ok(P.clinicSources.some((x) => x.id === s), `${p.id} 미정의 출처 ${s}`); + } + for (const pl of PL.places) { assert.ok(PL.categories[pl.category], `${pl.id} 카테고리`); assert.ok(pl.name.ko && pl.name.en, `${pl.id} 이름`); } +}); + +const HAS_TOUR = Object.values(TKO.places ?? {}).some((v) => Array.isArray(v) && v.length); // 템플릿 빈 데이터면 관광공사 검사는 건너뛴다 +ok('TourAPI 어댑터: 카테고리 매핑, 사우나 제외, 음식점은 일반식만, 거리 등급', () => { + assert.equal(levelByDistance(400), 1); assert.equal(levelByDistance(2500), 2); assert.equal(levelByDistance(9000), 3); + assert.equal(bookingName('K-그랜드 호스텔 강남 1(K-GRAND HOSTEL GANGNAM1)'), 'K-GRAND HOSTEL GANGNAM1'); + if (!HAS_TOUR) { console.log(' (관광공사 데이터 없음: 변환 검사 건너뜀)'); return; } + const tp = tourToPlaces(TKO, 'ko'); + assert.ok(tp.length > 50, `변환 ${tp.length}건`); + assert.ok(tp.every((p) => p.source === 'tourapi')); + assert.ok(!tp.some((p) => p.id.startsWith('tour-wellness-')), '사우나·스파가 후보에 들어감'); + assert.ok(tp.filter((p) => p.category === 'food').every((p) => p.dietOk.length === 1 && p.dietOk[0] === 'normal')); +}); + +ok('큐레이션이 TourAPI 보다 먼저 나오고 유동식 단계에는 TourAPI 음식점이 없음', () => { + if (!HAS_TOUR) return; + const tp = tourToPlaces(TKO, 'ko'); + const all = [...PL.places.map((x) => ({ ...x, source: 'curated' })), ...tp]; + const plan = buildPlan({ procedure: byId('contour'), surgeryDate: '2026-11-03', nationality: null, prefs: ['food'] }, all); + for (const d of plan.days.filter((d) => d.diet === 'liquid')) for (const p of d.picks) assert.ok(!(p.source === 'tourapi' && p.category === 'food'), `${d.date} ${p.id}`); + const first = plan.days.find((d) => d.picks.length); + assert.equal(first.picks[0].source, 'curated'); +}); + +ok('축제: 체류 기간과 겹치는 것만, L3 날에만 붙음', () => { + if (!HAS_TOUR) return; + const fest = festivalsDuring(TKO, '2026-11-01', '2026-11-17'); + for (const f of fest) assert.ok(f.start <= '2026-11-17' && f.end >= '2026-11-01'); + const plan = buildPlan({ procedure: byId('skin'), surgeryDate: '2026-11-03', nationality: null, prefs: [], festivals: fest }, PL.places); + for (const d of plan.days) if (d.festivals.length) assert.ok(d.level >= 3, `${d.date} L${d.level}`); +}); + +console.log(`plan.test: ${n}건 통과`); diff --git a/supporters/scripts/gate/rules.mjs b/supporters/scripts/gate/rules.mjs index 2a4e19e..c3cf78d 100644 --- a/supporters/scripts/gate/rules.mjs +++ b/supporters/scripts/gate/rules.mjs @@ -45,7 +45,7 @@ export function postTextFields(data, body) { } // ---------- §3-1 고객 화면과 운영자 설명의 분리 ---------- -export const OPERATOR_VOCAB = /답변엔진|AI 인용|AEO|GEO|질문 뱅크|QB [A-G]|실측|단일 원본|수집 기준|API 집계|임베드|복제|의료법 제\d+조|롱폼|쇼츠 분류/g; +export const OPERATOR_VOCAB = /답변엔진|AI 인용|AEO|GEO|질문 뱅크|QB [A-G]|실측|단일 원본|수집 기준|API 집계|임베드|(? s.match(re)).find(Boolean); + if (m) out.push(r(E, 'PRICE_MENTION', `${field}: 금액·할인 표기 "${m[0]}" (금액은 쓰지 않고 병원의 비급여 진료비용 고지 페이지로 안내)`)); + } + } + return out; +} + +/** PRACTITIONER_MISSING (warn). 근거: 의료법 27조(무면허 의료행위. 레이저·주사 시술은 의사가 해야 하고 간호사 위임은 대리시술) + * · PRD §9 시술자 표기. 피부과(derm) 시술 글(category D)에 시술자 표기(의사 직접 / 의사 감독 / 시술자 행의 "확인 대기") 중 하나가 없으면 경고. + * "시술자" 낱말이 있으면 조건 표 시술자 행으로 본다(값이 "확인 대기"여도 표기는 한 것). 성형외과 글은 검사하지 않는다. */ +export const PRACTITIONER_MARK = /시술자|(의사|원장|전문의|의료진)(가|이|의|께서)?\s*직접|(의사|원장|전문의|의료진)(의|이|가)?\s*(감독|입회|관리\s*하에)/; +export function checkPractitioner(data, fields, industry = 'plastic') { + if (industry !== 'derm' || data.category !== 'D') return []; + const hit = fields.some((f) => PRACTITIONER_MARK.test(f.text)); + return hit ? [] : [r(W, 'PRACTITIONER_MISSING', '피부과 시술 글에 시술자 표기 없음 (조건 표 시술자 행에 "의사 직접" / "의사 감독" / "확인 대기" 중 하나)')]; +} + +/** DEVICE_CLAIM (error). 근거: 의료기기법 24조(허가·인증 범위 밖 효능·효과 표현 금지) · 약사법 68조(전문의약품 대중광고 제한) + * · 의료법 56조 2항(효과 보장·과장). 두 갈래. + * (1) "FDA 승인·식약처 허가" 같은 허가 표현이 있는데 sources 에 regulation 타입이 없으면 error (허가 정보는 규제 원문 링크로만). + * (2) "영구·완치·재발 없음·100%·평생 유지" 류 효과 보장 표현은 근거와 무관하게 error. 부정문("영구적이라는 뜻은 아닙니다")은 통과. + * "반영구"(반영구 화장)는 시술명이라 제외한다. 뉴스 제목은 checkNewsItems 가 따로 보므로 여기에는 넣지 않는다. */ +export const DEVICE_APPROVAL = /식약처\s*(허가|인증|승인)|MFDS|KFDA|FDA\s*(승인|허가|인증|클리어|clear)|CE\s*(인증|마크)/i; +export const EFFECT_GUARANTEE = [ + { re: /(? s.type === 'regulation'); + for (const { field, text } of fields) { + for (const s of sentences(text)) { + if (!hasReg) { + const a = s.match(DEVICE_APPROVAL); + if (a) out.push(r(E, 'DEVICE_CLAIM', `${field}: 허가 표현 "${a[0]}" 이 있는데 regulation 타입 원문 소스가 없음 (허가 정보는 규제 원문 링크로)`)); + } + if (GUARANTEE_NEGATION.test(s)) continue; + for (const g of EFFECT_GUARANTEE) { + const m = s.match(g.re); + if (m) { out.push(r(E, 'DEVICE_CLAIM', `${field}: 효과 보장 표현(${g.why}) "${m[0]}" · "${s.slice(0, 60)}"`)); break; } + } + } + } + return out; +} + // ---------- 묶음: 글 한 편의 소스 검사 ---------- -export function checkPostSource({ data, body }, { physicians, supporters } = {}) { +// industry: 'plastic' | 'derm'. 주지 않으면 frontmatter industry → 환경변수 SUPPORTERS_INDUSTRY → plastic 순으로 정한다. +export function checkPostSource({ data, body }, { physicians, supporters, industry } = {}) { const fields = postTextFields(data, body); + const ind = resolveIndustry(industry, data); return [ ...checkSourcesType(data), ...checkRegulationSource(data, fields), @@ -317,6 +401,9 @@ export function checkPostSource({ data, body }, { physicians, supporters } = {}) ...checkReview(data, physicians, supporters), ...checkVideoTitles([...(data.videos ?? []), ...(data.video ? [data.video] : [])], { label: 'frontmatter' }), ...checkOriginalContent(data, body), + ...checkPriceMention(fields), + ...checkDeviceClaim(data, fields), + ...checkPractitioner(data, fields, ind), ...fields.flatMap((f) => checkPlainEndings(f.text, f.field)), ...fields.flatMap((f) => checkPressVoice(f.text, f.field)), ]; diff --git a/supporters/scripts/gate/test.mjs b/supporters/scripts/gate/test.mjs index 68ed5a9..56b7bdf 100644 --- a/supporters/scripts/gate/test.mjs +++ b/supporters/scripts/gate/test.mjs @@ -1,5 +1,5 @@ // 게이트 규칙 회귀 테스트. 빌드 없이 돈다. -// 1) fixtures/*.md : frontmatter `expect:` 에 적힌 error 코드가 실제로 나와야 통과 +// 1) fixtures/*.md : frontmatter `expect:` 에 적힌 error 코드가 실제로 나와야 통과 (`expectWarn:`·`expectNoWarn:` 으로 warn 코드도 본다) // 2) fixtures/*.html: 첫 줄 주석의 expect 코드 (none = 오류 0) // 3) src/content/posts/*.md 전편이 소스 규칙 error 0 이어야 통과 (정답지 회귀) // node scripts/gate/test.mjs @@ -23,17 +23,23 @@ const ok = (name, msg = '') => { pass++; console.log(` ✓ ${name}${msg ? ' · const bad = (name, msg) => { failCount++; console.error(` ✗ ${name}: ${msg}`); }; const codes = (list, level = R.E) => [...new Set(list.filter((x) => x.level === level).map((x) => x.code))]; -// 1) md 픽스처 +// 1) md 픽스처. expect = 나와야 하는 error 코드(정확히 일치), expectWarn = 나와야 하는 warn 코드, expectNoWarn = 나오면 안 되는 warn 코드 for (const f of readdirSync(FIX).filter((x) => x.endsWith('.md'))) { const { data, body } = R.parseMarkdown(readFileSync(join(FIX, f), 'utf8')); - const { expect = [], ...fm } = data; + const { expect = [], expectWarn = [], expectNoWarn = [], ...fm } = data; const merged = { ...base, ...fm }; - const got = codes(R.checkPostSource({ data: merged, body }, fxCtx)); + const all = R.checkPostSource({ data: merged, body }, fxCtx); + const got = codes(all); + const gotWarn = codes(all, R.W); const missing = expect.filter((c) => !got.includes(c)); const extra = got.filter((c) => !expect.includes(c)); + const missingWarn = expectWarn.filter((c) => !gotWarn.includes(c)); + const badWarn = expectNoWarn.filter((c) => gotWarn.includes(c)); if (missing.length) bad(f, `기대한 오류가 안 나옴: ${missing.join(', ')} (실제: ${got.join(', ') || '없음'})`); else if (extra.length) bad(f, `기대 밖 오류: ${extra.join(', ')}`); - else ok(f, got.join(', ')); + else if (missingWarn.length) bad(f, `기대한 경고가 안 나옴: ${missingWarn.join(', ')} (실제 경고: ${gotWarn.join(', ') || '없음'})`); + else if (badWarn.length) bad(f, `나오면 안 되는 경고: ${badWarn.join(', ')}`); + else ok(f, [...got, ...expectWarn.map((c) => `warn:${c}`)].join(', ') || '오류 0'); } // 2) html 픽스처 (dist 규칙) @@ -109,5 +115,38 @@ negGot.length ? bad('부정문 통과', negGot.map((x) => x.msg).join(' | ')) : re.length ? bad('news.json 회귀', `${re.length}건: ` + re.slice(0, 3).map((x) => x.msg).join(' | ')) : ok('news.json 전 항목 규칙 통과', `${real.items.length}건`); } +// 8) 피부과 규칙 단위 검사 (PRD §9). 금액·허가·효과 보장·시술자 +{ + const F = (text) => [{ field: 'body', text }]; + const price = R.checkPriceMention(F('울쎄라 300샷 이벤트가 99만원. 리쥬란 15만 원부터. ₩150,000. 1+1 행사.')); + price.length >= 3 ? ok('금액 표기 검출', `${price.length}건`) : bad('금액 표기 검출', JSON.stringify(price)); + const priceOk = R.checkPriceMention(F('수술 후 5~7일이면 일상생활이 가능합니다. 원장 3명이 진료합니다. 2026년 9월 기준입니다. 전화는 02-539-1177입니다. 금액은 비급여 진료비용 고지 페이지에서 확인하세요.')); + priceOk.length ? bad('금액 오탐', priceOk.map((x) => x.msg).join(' | ')) : ok('일수·인원·연도·전화번호·고지 안내 문장 통과'); + const dev = R.checkDeviceClaim({ sources: [] }, F('이 장비는 FDA 승인과 식약처 허가를 받았습니다.')); + dev.some((x) => x.code === 'DEVICE_CLAIM') ? ok('허가 표현 + regulation 소스 없음 검출') : bad('허가 표현 검출', JSON.stringify(dev)); + const devOk = R.checkDeviceClaim({ sources: [{ type: 'regulation' }] }, F('이 장비는 식약처 허가를 받았습니다. 허가가 위험이 없다는 뜻은 아닙니다. 영구 제모라는 표현은 쓰지 않습니다.')); + devOk.length ? bad('허가 표현 오탐', devOk.map((x) => x.msg).join(' | ')) : ok('regulation 소스 있는 허가 표현·부정문 통과'); + const guar = R.checkDeviceClaim({ sources: [] }, F('한 번이면 평생 유지됩니다. 기미는 완치됩니다.')); + guar.length >= 2 ? ok('효과 보장 표현 검출', `${guar.length}건`) : bad('효과 보장 검출', JSON.stringify(guar)); + const semi = R.checkDeviceClaim({ sources: [] }, F('반영구 화장은 별도 시술입니다. 유지기간은 개인차가 있습니다.')); + semi.length ? bad('반영구 오탐', semi[0].msg) : ok('"반영구" 시술명 통과'); + const pr = R.checkPractitioner({ category: 'D' }, F('시술시간은 확인입니다.'), 'derm'); + pr.length === 1 && pr[0].code === 'PRACTITIONER_MISSING' && pr[0].level === R.W ? ok('시술자 표기 없음 경고 (derm·D)') : bad('시술자 경고', JSON.stringify(pr)); + const prSkip = [...R.checkPractitioner({ category: 'D' }, F('시술시간은 확인입니다.'), 'plastic'), ...R.checkPractitioner({ category: 'A' }, F('시술시간은 확인입니다.'), 'derm'), ...R.checkPractitioner({ category: 'D' }, F('원장이 직접 시술합니다.'), 'derm')]; + prSkip.length ? bad('시술자 경고 오탐', JSON.stringify(prSkip)) : ok('성형외과·비시술 글·"원장이 직접" 표기는 경고 없음'); + const banned = R.checkBannedBody('정품 정량 인증 병원입니다. 비포애프터 사진을 보세요.'); + banned.length >= 2 ? ok('피부과 금칙어(정품 정량 인증·비포애프터) 검출', `${banned.length}건`) : bad('피부과 금칙어', JSON.stringify(banned)); + const bannedOk = R.checkBannedBody('병원은 정품·정량 사용을 밝힙니다. 이 매체는 전후 사진을 싣지 않습니다. 영수증 인증 후기입니다.'); + bannedOk.length ? bad('피부과 금칙어 오탐', bannedOk.map((x) => x.msg).join(' | ')) : ok('정품 정량 서약 사실·전후 사진 원칙 서술 통과'); + // 정답지 18편: 피부과 규칙을 derm 으로 강제해도 error 0 (PRICE_MENTION·DEVICE_CLAIM 은 업종 무관, PRACTITIONER 는 경고라 error 에 안 잡힘) + let dermErr = 0; + for (const f of readdirSync(POSTS).filter((x) => x.endsWith('.md'))) { + const parsed = R.parseMarkdown(readFileSync(join(POSTS, f), 'utf8')); + const errs = R.checkPostSource(parsed, { ...ctx, industry: 'derm' }).filter((x) => x.level === R.E && ['PRICE_MENTION', 'DEVICE_CLAIM'].includes(x.code)); + if (errs.length) { dermErr += errs.length; errs.forEach((e) => bad(`posts/${f} (derm)`, `[${e.code}] ${e.msg}`)); } + } + if (!dermErr) ok('정답지 전편 PRICE_MENTION·DEVICE_CLAIM 0건'); +} + console.log(`통과 ${pass} · 실패 ${failCount}`); if (failCount) process.exit(1); diff --git a/supporters/scripts/gen/evidence.mjs b/supporters/scripts/gen/evidence.mjs index 5b5515a..eab74a5 100644 --- a/supporters/scripts/gen/evidence.mjs +++ b/supporters/scripts/gen/evidence.mjs @@ -14,7 +14,12 @@ export function normUrl(u) { const x = new URL(u); let s = x.host.replace(/^www\./, '') + x.pathname; try { s = decodeURIComponent(s); } catch { /* 그대로 */ } - return s.replace(/\/+$/, '').toLowerCase(); + s = s.replace(/\/+$/, '').toLowerCase(); + // 쿼리가 곧 페이지인 사이트(오라클 index.php?doc=N)를 위해 추적 파라미터를 뺀 쿼리를 키에 넣는다. collect_evidence.normalize 와 같은 규칙. + // 2026-09-10: 쿼리를 지우자 시술 페이지 84개가 마지막 한 페이지(휴지기탈모)로 겹쳐 글 근거가 전부 틀렸다. + const keep = [...x.searchParams.entries()].filter(([k]) => !/^(utm_|fbclid|gclid|ref$|_ga)/i.test(k)).sort(([a], [b]) => a.localeCompare(b)); + if (keep.length) s += '?' + keep.map(([k, v]) => `${k}=${v}`).join('&').toLowerCase(); + return s; } catch { return String(u).replace(/\/+$/, '').toLowerCase(); } } @@ -35,7 +40,10 @@ export function loadEvidence(evDir) { return { clinic: index.clinic, start: index.start, fetchedAt: index.fetchedAt, pages, byUrl, doctors, homeText }; } -/** 페이지 items → 읽기용 텍스트. 표는 마크다운 행으로. */ +/** ocr_evidence.mjs 가 붙인 OCR 섹션(source: "ocr"). 이미지 글자를 기계로 읽은 것이라 원문(HTML)과 구분해 표기한다 */ +export const ocrSections = (p) => (p.sections ?? []).filter((s) => s?.source === 'ocr' && s.text); + +/** 페이지 items → 읽기용 텍스트. 표는 마크다운 행으로. OCR 섹션은 뒤에 출처 표기와 함께 붙인다. */ export function pageToText(p, { maxChars = 9000 } = {}) { const lines = []; for (const it of p.items ?? []) { @@ -45,6 +53,7 @@ export function pageToText(p, { maxChars = 9000 } = {}) { else if (it.kind === 'table') for (const row of it.rows ?? []) lines.push('| ' + row.map((c) => String(c).replace(/\|/g, '/')).join(' | ') + ' |'); else lines.push(it.text); } + for (const s of ocrSections(p)) lines.push('', `[병원 페이지 이미지 글자 OCR] ${s.heading ?? ''} (이미지 ${s.images?.length ?? 1}장을 기계로 읽은 병원 페이지 원문. 병원이 공개한 자료로 취급해 근거로 쓴다. 글자가 깨졌거나 문맥이 맞지 않는 부분만 쓰지 않고, 수치·제품명은 문장이 온전할 때만 옮긴다)`, s.text); let t = lines.join('\n').replace(/\n{3,}/g, '\n\n').trim(); if (t.length > maxChars) t = t.slice(0, maxChars) + `\n…(이 페이지는 ${t.length - maxChars}자가 더 있으나 생략됨. 생략된 부분의 사실은 쓰지 않는다)`; return t; @@ -71,8 +80,9 @@ export function buildContext(brief, { ev, fact, authors, videos, news, answers, const p = ev.byUrl.get(normUrl(url)); if (!p) { missing.push(`병원 페이지가 근거 수집 결과에 없음: ${url}`); return; } const imgText = Array.isArray(p.flags) ? p.flags.includes('textInImages') : Boolean(p.flags?.textInImages); - if (!p.items?.length) { missing.push(`병원 페이지 본문 0자${imgText ? ' (이미지 글자)' : ''}: ${url}`); return; } - cparts.push(`### [C${cparts.length + 1}] ${p.title ?? ''}\nURL: ${p.url}\n수집일: ${p.fetchedAt}\n\n${pageToText(p)}`); + const ocr = ocrSections(p); + if (!p.items?.length && !ocr.length) { missing.push(`병원 페이지 본문 0자${imgText ? ' (이미지 글자, OCR 없음)' : ''}: ${url}`); return; } + cparts.push(`### [C${cparts.length + 1}] ${p.title ?? ''}\nURL: ${p.url}\n수집일: ${p.fetchedAt}${ocr.length ? ' · 본문 일부 또는 전부가 이미지 글자 OCR' : ''}\n\n${pageToText(p)}`); pushSource({ label: `${clinicName} 홈페이지 · ${cleanTitle(p.title, clinicName)}`, url: p.url, accessed: p.fetchedAt ?? today, type: 'clinic' }); }); parts.push(`## 1. 병원 공식 페이지 원문 (문장을 그대로 옮기지 말 것. 40자 이상 연속 일치는 발행 차단)\n\n${cparts.length ? cparts.join('\n\n') : '(제공된 페이지 없음)'}`); diff --git a/supporters/scripts/gen/prompt.mjs b/supporters/scripts/gen/prompt.mjs index f4efdc0..a9252c2 100644 --- a/supporters/scripts/gen/prompt.mjs +++ b/supporters/scripts/gen/prompt.mjs @@ -1,5 +1,6 @@ -// 글 생성 프롬프트와 출력 스키마. 규칙의 근거는 docs/NEXT_SESSION_SUPPORTERS_AUTOBUILD_v2.md §3·§4·§12-2. +// 글 생성 프롬프트와 출력 스키마. 규칙의 근거는 docs/NEXT_SESSION_SUPPORTERS_AUTOBUILD_v2.md §3·§4·§12-2, 피부과는 Dermatology Supporters PRD §7·§9. // 여기 적힌 규칙은 대부분 scripts/gate/rules.mjs 와 generate_posts.mjs 의 수치 대조·검증 단계가 다시 검사한다. 프롬프트는 1차 방어, 게이트가 최종. +// 업종: brief.industry 가 'derm'(피부과)이면 userPrompt 에 피부과 추가 규칙 블록(DERM_RULES)이 붙는다. 성형외과(plastic) 경로의 문자열은 바뀌지 않는다. export const SYSTEM_PROMPT = `당신은 성형외과 서포터즈 매체의 편집자입니다. 병원이 지원하는 매체이므로 광고로 읽히지 않으려면 사실만, 근거가 있는 것만 씁니다. 독자는 상담을 앞둔 사람입니다. 독자가 상담에서 무엇을 묻고 무엇을 확인해야 하는지 알게 하는 것이 글의 목적입니다. @@ -48,20 +49,39 @@ export const SYSTEM_PROMPT = `당신은 성형외과 서포터즈 매체의 편 # 출력 JSON 스키마대로만 출력합니다. pending 에는 독자가 물었을 법한데 근거에 없어 쓰지 못한 사실을 한 줄씩 적습니다(병원 확인 요청 목록이 됩니다). usedRefs 에는 실제로 인용한 근거 태그(C1, S2 형식)만 적습니다.`; +// ---------- 피부과 추가 규칙 (industry = derm 일 때만 userPrompt 에 붙는다) ---------- +// 근거: PRD §7 시술 조건 표(표준 블록), §9 규정(의료법 45조 비급여 고지 · 의료기기법 24조 · 약사법 68조 · 의료법 27조 시술자 · 56조 2항). +// 게이트 대응: PRICE_MENTION · DEVICE_CLAIM · PRACTITIONER_MISSING · BANNED_PHRASE(정품 정량 인증·비포애프터). +export const DERM_CONDITION_ROWS = ['시술시간', '마취', '통증 정도', '회복(다운타임)', '유지기간', '권장 회차', '권장 주기', '시술자']; +export const DERM_SIDE_EFFECT_VOCAB = ['화상', '색소침착', '멍', '부기', '감염', '붉어짐', '물집', '가려움', '건조']; +export const DERM_RULES = `# 피부과 추가 규칙 (이 글은 피부과 서포터즈 매체의 글입니다. 위 지시의 "성형외과"는 "피부과"로, "수술"은 "시술"로 읽습니다) +- 시술 조건 표: 시술을 다루는 글(분류 D 는 필수)에는 시술마다 조건 표를 넣습니다. 행 8개를 이 순서로 씁니다: ${DERM_CONDITION_ROWS.join(' · ')}. 열은 "항목 | 병원 안내 | 근거" 세 개이고 근거 열에는 병원 제공 / 원장 설명 / 제품 정보 / 규제 중 하나를 씁니다. 근거에 없는 칸은 "확인"이라고 쓰고, 표 바로 아래 문단에 개인차와 병원 확인 대기를 씁니다. 칸을 채우려고 근거 밖 수치를 만들지 않습니다. 수치 칸에는 "영상 사례" 또는 "홈페이지 안내 기준"을 붙입니다. +- 시술자 행: 병원 페이지나 병원 확인 답변에 "의사 직접" 또는 "의사 감독" 표기가 있으면 그대로 옮기고, 없으면 "확인 대기"라고 씁니다. 간호사·관리사가 시술한다고 쓰지 않습니다. 시술 글에는 본문 어딘가에 반드시 "시술자" 항목이 있어야 합니다. +- 상표·장비·제제: 병원 페이지에 적힌 장비·제제 이름만 씁니다(예: 페이지에 울쎄라가 있으면 울쎄라, 없으면 "초음파 리프팅 장비"). 허가 정보(식약처 허가·FDA 승인)는 규제 원문 [R]이 있을 때만, 해당 제품·해당 적응증으로 한정해 쓰고 원문 링크로 안내합니다. [R]이 없으면 허가를 언급하지 않고 "장비의 허가 정보는 상담에서 확인하세요"로 씁니다. 제품명을 제목이나 요약 첫 줄에 앞세우지 않습니다. 전문의약품(보툴리눔 톡신, 의약품 분류 필러, 이소트레티노인)은 시술 설명 범위에서만 쓰고 제품 홍보로 읽히게 쓰지 않습니다. +- 금액 금지: 원·만원·₩ 금액, %할인, 이벤트가·특가·1+1 을 어디에도 쓰지 않습니다. 가격은 샷 수·회차·패키지 조건 같은 "구성"만 설명하고, 금액은 병원의 비급여 진료비용 고지 페이지에서 확인하라고 안내합니다. +- 인증 표현: "정품 정량"은 병원이 밝힌 사실로만 씁니다("병원은 정품·정량 사용을 밝힙니다"). "정품 정량 인증"처럼 인증 어휘로 넓히지 않습니다. 전후 사진·비포애프터를 보라고 유도하는 문장을 쓰지 않습니다. +- 효과 표현: 영구·완치·재발 없음·100%·평생 유지·한 번으로 끝 을 쓰지 않습니다. 유지기간은 근거 수치 그대로 "개인차"와 함께 씁니다. 근거에 없는 유지기간은 "확인"입니다. +- 부작용: 시술 글에는 "## 시술 후 관리와 부작용" 절을 두고, 근거에 있는 부작용을 ${DERM_SIDE_EFFECT_VOCAB.slice(0, 5).join('·')} 같은 구체 어휘로 씁니다. 근거에 없으면 "부작용 항목은 병원 공개 자료에 없습니다. 상담에서 확인하세요."라고 씁니다. 부작용을 축소하는 표현("거의 없음", "미미함")은 근거 문장에 있어도 옮기지 않습니다. +- 회차·주기: 권장 회차와 권장 주기는 근거에 있는 값만 쓰고, 없으면 "상담에서 정합니다"로 닫습니다. 다른 시술과의 병행 가능 여부는 근거에 있을 때만 씁니다. +- 다지점: 지점별로 다른 값(진료시간·담당 원장·장비)은 지점을 명시합니다. 팩트 시트 branches 밖의 지점을 만들지 않습니다.`; + +export const isDermBrief = (brief) => brief?.industry === 'derm' || (!brief?.industry && process.env.SUPPORTERS_INDUSTRY === 'derm'); + export function userPrompt({ brief, context, fact, authorName, reviewerName, today }) { const cat = `${brief.category} ${brief.categoryLabel ?? ''}`.trim(); + const derm = isDermBrief(brief); return `# 이번 글 - 제목(H1, 질문형): ${brief.title} - 분류: ${cat} · 문항 ID: ${(brief.qbIds ?? []).join(', ') || '(없음)'} - 작성자: ${authorName ?? '확인 대기'} · 검토 예정 원장: ${reviewerName ?? '미정 (의학 검토 대기)'} - 오늘: ${today} -${brief.intent ? `- 기획 의도: ${brief.intent}\n` : ''}${brief.mustCover?.length ? `- 반드시 다룰 것: ${brief.mustCover.join(' / ')}\n` : ''}${brief.avoid?.length ? `- 이 글에서 피할 것: ${brief.avoid.join(' / ')}\n` : ''} +${brief.intent ? `- 기획 의도: ${brief.intent}\n` : ''}${brief.mustCover?.length ? `- 반드시 다룰 것: ${brief.mustCover.join(' / ')}\n` : ''}${brief.avoid?.length ? `- 이 글에서 피할 것: ${brief.avoid.join(' / ')}\n` : ''}${derm ? `\n${DERM_RULES}\n` : ''} # 근거 ${context} # 작성 지시 -위 근거만으로 "${brief.title}"에 답하는 글을 JSON 스키마대로 작성하세요. 근거에 없는 사실은 pending 에 적고 본문에는 "병원 공개 자료에 없습니다"로 씁니다. 병원 이름은 "${fact?.shortName ?? ''}"으로 씁니다.`; +위 근거만으로 "${brief.title}"에 답하는 글을 JSON 스키마대로 작성하세요. 근거에 없는 사실은 pending 에 적고 본문에는 "병원 공개 자료에 없습니다"로 씁니다. 병원 이름은 "${fact?.shortName ?? ''}"으로 씁니다.${derm ? ' 시술을 다루는 글이면 조건 표 8행과 시술자 항목을 넣고, 금액은 쓰지 않습니다.' : ''}`; } export function repairPrompt(errors, warns) { @@ -86,7 +106,19 @@ ${w || '(없음)'} - NUMERIC_NO_QUALIFIER: 수치가 있는 문단·요약 줄·FAQ 답에 "개인차가 있습니다" 또는 "상담에서 확인하세요"를 붙입니다. - PLAIN_ENDING: 반말 문장을 "~입니다/~합니다"로 바꿉니다. - HEADING_VERB: 제목을 명사구 또는 질문형으로 바꿉니다. -- BODY_H1: 본문의 # 제목을 ## 으로 바꿉니다.`; +- BODY_H1: 본문의 # 제목을 ## 으로 바꿉니다.${dermFixes(errors, warns)}`; +} + +// 피부과 규칙 코드가 실제로 나왔을 때만 붙는 수정 지침. 성형외과 글에서 이 코드가 없으면 수정 프롬프트는 이전과 같다. +const DERM_FIX = { + PRICE_MENTION: '- PRICE_MENTION: 금액·할인·이벤트가 표기를 삭제합니다. "금액은 병원의 비급여 진료비용 고지 페이지에서 확인하세요"로 바꿉니다.', + DEVICE_CLAIM: '- DEVICE_CLAIM: 허가 표현(식약처 허가·FDA 승인)은 규제 원문 근거가 없으면 삭제하고, 영구·완치·재발 없음·100%·평생 유지 같은 효과 보장 표현은 근거 수치와 "개인차"로 바꿉니다.', + PRACTITIONER_MISSING: '- PRACTITIONER_MISSING: 조건 표에 "시술자" 행을 넣습니다. 근거에 의사 직접·의사 감독 표기가 없으면 값은 "확인 대기"입니다.', +}; +function dermFixes(errors, warns) { + const codes = new Set([...errors, ...warns].map((x) => x.code)); + const lines = Object.entries(DERM_FIX).filter(([c]) => codes.has(c)).map(([, l]) => l); + return lines.length ? '\n' + lines.join('\n') : ''; } /** OpenAI structured output 스키마 (strict). */ diff --git a/supporters/scripts/generate_posts.mjs b/supporters/scripts/generate_posts.mjs index 3b114bc..73d0a7c 100644 --- a/supporters/scripts/generate_posts.mjs +++ b/supporters/scripts/generate_posts.mjs @@ -296,7 +296,6 @@ for (const brief of briefs) { row.pending = out.pending ?? []; row.usedRefs = out.usedRefs ?? []; row.seconds = Math.round((Date.now() - t0) / 100) / 10; - spent += row.costUsd; const mark = hard.length ? '✗' : soft.length ? '△' : '✓'; console.log(` ${mark} ${brief.id}: 오류 ${hard.length} 근거플래그 ${soft.length} 경고 ${res.warns.length} · 본문 ${res.stats.hangul}자 표 ${res.stats.tables} FAQ ${res.stats.faq} · 확인 대기 ${row.pending.length} · 호출 ${row.calls}${row.repaired ? '(수정)' : ''} · $${row.costUsd.toFixed(3)} · ${row.seconds}s`); for (const e of hard) console.log(` ✗ [${e.code}] ${e.msg}`); @@ -306,7 +305,8 @@ for (const brief of briefs) { console.error(` ✗ ${brief.id}: ${row.error.slice(0, 300)}`); } } -function addUsage(row, u, m) { row.calls++; row.usage.prompt_tokens += u.prompt_tokens ?? 0; row.usage.completion_tokens += u.completion_tokens ?? 0; row.costUsd += costOf(u, m); } +// 토큰을 쓴 시점에 누적한다. 호출이 실패해도 과금은 이미 일어났으므로 총액과 상한 판정에 들어가야 한다. +function addUsage(row, u, m) { row.calls++; row.usage.prompt_tokens += u.prompt_tokens ?? 0; row.usage.completion_tokens += u.completion_tokens ?? 0; const c = costOf(u, m); row.costUsd += c; spent += c; } // ---------- 리포트 ---------- report.finishedAt = new Date().toISOString(); @@ -316,6 +316,8 @@ report.summary = { total: report.posts.length, ok: st('ok'), okNeedsReview: st('ok_needs_review'), gateFailed: st('gate_failed'), error: st('error'), repaired: report.posts.filter((p) => p.repaired).length, avgCostUsd: avg(report.posts.filter((p) => p.costUsd).map((p) => p.costUsd)), + // 총액에 포함되지만 글로 남지 않은 비용(실패·게이트 차단). 채택 편당 원가를 따로 보려면 이 값을 뺀다. + discardedCostUsd: Math.round(report.posts.filter((p) => ['error', 'gate_failed'].includes(p.status)).reduce((n, p) => n + p.costUsd, 0) * 1000) / 1000, avgSeconds: avg(report.posts.filter((p) => p.seconds).map((p) => p.seconds)), firstPassErrorCodes: count(report.posts.flatMap((p) => p.firstPass?.errors ?? [])), warningCodes: count(report.posts.flatMap((p) => (p.warnings ?? []).map((w) => w.match(/^\[(\w+)\]/)?.[1]))), @@ -324,7 +326,7 @@ report.summary = { }; writeFileSync(join(OUT, 'report.json'), JSON.stringify(report, null, 1)); writeFileSync(join(OUT, 'report.md'), reportMd(report)); -console.log(`\n통과 ${report.summary.ok} · 근거 플래그 남음 ${report.summary.okNeedsReview} · 게이트 실패 ${report.summary.gateFailed} · 오류 ${report.summary.error} / ${report.summary.total} · 수정 호출 ${report.summary.repaired} · 총 $${report.totalCostUsd} (편당 $${report.summary.avgCostUsd}) · ${OUT}`); +console.log(`\n통과 ${report.summary.ok} · 근거 플래그 남음 ${report.summary.okNeedsReview} · 게이트 실패 ${report.summary.gateFailed} · 오류 ${report.summary.error} / ${report.summary.total} · 수정 호출 ${report.summary.repaired} · 총 $${report.totalCostUsd}${report.summary.discardedCostUsd ? ` (폐기 $${report.summary.discardedCostUsd})` : ''} (편당 $${report.summary.avgCostUsd}) · ${OUT}`); if (report.summary.gateFailed || report.summary.error) process.exitCode = 1; function avg(a) { return a.length ? Math.round((a.reduce((x, y) => x + y, 0) / a.length) * 1000) / 1000 : 0; } @@ -336,7 +338,7 @@ function reportMd(r) { const fp = Object.entries(r.summary.firstPassErrorCodes).map(([k, v]) => `${k}×${v}`).join(', ') || '없음'; return `# 글 생성 리포트 · ${r.clinic} · ${r.model}${r.verifyModel ? ` (대조 ${r.verifyModel})` : ''} · ${r.today} -통과 ${r.summary.ok} · 근거 플래그 남음 ${r.summary.okNeedsReview} · 게이트 실패 ${r.summary.gateFailed} · 오류 ${r.summary.error} / ${r.summary.total} · 수정 호출 ${r.summary.repaired}편 · 총 $${r.totalCostUsd} · 편당 $${r.summary.avgCostUsd} · 편당 ${r.summary.avgSeconds}s +통과 ${r.summary.ok} · 근거 플래그 남음 ${r.summary.okNeedsReview} · 게이트 실패 ${r.summary.gateFailed} · 오류 ${r.summary.error} / ${r.summary.total} · 수정 호출 ${r.summary.repaired}편 · 총 $${r.totalCostUsd}${r.summary.discardedCostUsd ? ` (폐기 $${r.summary.discardedCostUsd})` : ''} · 편당 $${r.summary.avgCostUsd} · 편당 ${r.summary.avgSeconds}s 가격 기준 USD/1M tokens 입력 ${r.priceIn} · 출력 ${r.priceOut} (목록가, 실제 청구와 다를 수 있음) 1차 출력 오류 분포(수정 전): ${fp} diff --git a/supporters/scripts/ocr/vision_ocr.swift b/supporters/scripts/ocr/vision_ocr.swift new file mode 100644 index 0000000..c5af318 --- /dev/null +++ b/supporters/scripts/ocr/vision_ocr.swift @@ -0,0 +1,129 @@ +// macOS Vision 프레임워크(VNRecognizeTextRequest)로 이미지 글자를 읽는 단일 파일 도구. +// tesseract·pyobjc 가 없는 환경에서 결정론적 OCR 을 쓰기 위한 것. 유료 API 를 쓰지 않는다. +// +// swiftc -O -o vision_ocr vision_ocr.swift (ocr_evidence.mjs 가 소스가 바뀌면 다시 빌드한다) +// ./vision_ocr [--min-width 400] [--langs ko-KR,en-US] [--tile-height 2000] [--upscale-below 1400] [ ...] +// +// 세로로 긴 이미지(의료진 소개 794x12240 같은 스크롤 이미지)는 Vision 이 통째로 축소해 한 줄도 못 읽는다. +// --tile-height 픽셀 단위 띠로 잘라(겹침 10%) 띠마다 인식하고, 겹침 구간의 줄은 한 번만 남긴다. +// 폭이 --upscale-below 미만이면 2배로 키워 인식한다(작은 글자 대응). box 좌표는 원본 기준 0~1 정규화. +// +// 출력: 이미지 한 장에 JSON 한 줄(stdout) +// {"path":"...","width":W,"height":H,"lines":[{"text":"...","confidence":0.93,"box":[x,y,w,h]}],"engine":"apple-vision"} +// 폭이 --min-width 미만이면 {"path":"...","width":W,"height":H,"skipped":"narrow"}. 읽기 실패는 {"path":"...","error":"..."}. +// 줄 순서는 위에서 아래, 같은 줄 안에서는 왼쪽에서 오른쪽(Vision 의 정규화 좌표 y 는 아래가 0 이라 뒤집는다). +// 글자는 Vision 이 준 것만 내보낸다. 후처리(병합·교정)는 하지 않는다. 그것은 호출 측(ocr_evidence.mjs) 몫이다. +import Foundation +import Vision +import ImageIO +import CoreGraphics + +var minWidth = 0 +var tileHeight = 2000 +var upscaleBelow = 1400 +var langs = ["ko-KR", "en-US"] +var paths: [String] = [] +var it = CommandLine.arguments.dropFirst().makeIterator() +while let a = it.next() { + switch a { + case "--min-width": if let v = it.next(), let n = Int(v) { minWidth = n } + case "--langs": if let v = it.next() { langs = v.split(separator: ",").map { String($0) } } + case "--tile-height": if let v = it.next(), let n = Int(v) { tileHeight = max(n, 400) } + case "--upscale-below": if let v = it.next(), let n = Int(v) { upscaleBelow = n } + default: paths.append(a) + } +} +if paths.isEmpty { + FileHandle.standardError.write("사용법: vision_ocr [--min-width N] [--langs ko-KR,en-US] ...\n".data(using: .utf8)!) + exit(2) +} + +func jsonLine(_ obj: [String: Any]) { + if let d = try? JSONSerialization.data(withJSONObject: obj, options: [.withoutEscapingSlashes]), let s = String(data: d, encoding: .utf8) { + print(s) + fflush(stdout) + } +} + +func loadImage(_ path: String) -> CGImage? { + let url = URL(fileURLWithPath: path) + guard let src = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil } + return CGImageSourceCreateImageAtIndex(src, 0, nil) +} + +struct Line { var text: String; var confidence: Double; var x: Double; var y: Double; var w: Double; var h: Double } // 픽셀 좌표(원본 기준) + +// 이미지 한 장(또는 띠 하나)을 인식해 원본 픽셀 좌표의 줄 목록으로. scale 은 확대 배율 +func recognize(_ img: CGImage, offsetY: Int, scale: Int) throws -> [Line] { + var target = img + if scale > 1 { + let w = img.width * scale, h = img.height * scale + if let ctx = CGContext(data: nil, width: w, height: h, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) { + ctx.interpolationQuality = .high + ctx.draw(img, in: CGRect(x: 0, y: 0, width: w, height: h)) + if let up = ctx.makeImage() { target = up } + } + } + let request = VNRecognizeTextRequest() + request.recognitionLevel = .accurate + request.recognitionLanguages = langs + request.usesLanguageCorrection = true + let handler = VNImageRequestHandler(cgImage: target, options: [:]) + try handler.perform([request]) + let obs = (request.results ?? []) as [VNRecognizedTextObservation] + let W = Double(img.width), H = Double(img.height) + var out: [Line] = [] + for o in obs { + guard let top = o.topCandidates(1).first else { continue } + let bb = o.boundingBox // 정규화, 원점 왼쪽 아래 + out.append(Line(text: top.string, confidence: Double(top.confidence), x: bb.minX * W, y: (1 - bb.maxY) * H + Double(offsetY), w: bb.width * W, h: bb.height * H)) + } + return out +} + +for path in paths { + guard let img = loadImage(path) else { jsonLine(["path": path, "error": "이미지를 열 수 없음"]); continue } + let w = img.width, h = img.height + if w < minWidth { jsonLine(["path": path, "width": w, "height": h, "skipped": "narrow"]); continue } + let scale = w < upscaleBelow ? 2 : 1 + var lines: [Line] = [] + var tiles = 0 + do { + if h <= tileHeight { + lines = try recognize(img, offsetY: 0, scale: scale); tiles = 1 + } else { + let overlap = tileHeight / 10 + var top = 0 + while top < h { + let th = min(tileHeight, h - top) + guard let tile = img.cropping(to: CGRect(x: 0, y: top, width: w, height: th)) else { break } + let got = try recognize(tile, offsetY: top, scale: scale) + // 겹침 구간은 한가운데서 나눠 앞 띠는 그 앞까지, 뒷 띠는 그 뒤부터 받는다(같은 줄이 두 띠에 들어가지 않게). + // 띠 가장자리에 걸려 반만 읽힌 줄은 중심이 경계 밖이라 버려지고, 다른 띠에서 온전히 읽힌 것만 남는다. 첫 띠는 처음부터, 마지막 띠는 끝까지 + let isLast = top + th >= h + let lo = top == 0 ? -1.0 : Double(top + overlap / 2) + let hi = isLast ? Double.infinity : Double(top + th - overlap / 2) + for l in got { let cy = l.y + l.h / 2; if cy >= lo && cy < hi { lines.append(l) } } + tiles += 1 + if top + th >= h { break } + top += tileHeight - overlap + } + } + } catch { + jsonLine(["path": path, "width": w, "height": h, "error": "인식 실패: \(error.localizedDescription)"]); continue + } + // 위→아래, 같은 줄 안에서는 왼→오른쪽 + lines.sort { a, b in + let ay = a.y + a.h / 2, by = b.y + b.h / 2 + if abs(ay - by) > max(a.h, b.h) * 0.6 { return ay < by } + return a.x < b.x + } + let W = Double(w), H = Double(h) + let r3 = { (v: Double) -> Double in (v * 1000).rounded() / 1000 } + let out: [[String: Any]] = lines.map { l in [ + "text": l.text, + "confidence": r3(l.confidence), + "box": [r3(l.x / W), r3(l.y / H), r3(l.w / W), r3(l.h / H)], + ] } + jsonLine(["path": path, "width": w, "height": h, "tiles": tiles, "scale": scale, "lines": out, "engine": "apple-vision"]) +} diff --git a/supporters/scripts/ocr_evidence.mjs b/supporters/scripts/ocr_evidence.mjs new file mode 100644 index 0000000..05f396d --- /dev/null +++ b/supporters/scripts/ocr_evidence.mjs @@ -0,0 +1,241 @@ +// 근거 OCR 단계. collect_evidence.mjs 가 남긴 evidence// 에서 글자가 이미지에 들어 있는 페이지(flags.textInImages 또는 본문 100자 미만)의 +// 콘텐츠 이미지를 내려받아 macOS Vision(scripts/ocr/vision_ocr.swift)으로 읽고, 결과를 페이지 JSON·index.json·home_text·doctors.json 에 되돌려 넣는다. +// 시술 설명을 통짜 JPG 로 넣는 사이트(오라클피부과: 시술 84페이지 중 83개가 이미지 글자)를 근거로 쓰기 위한 것이다. +// +// node scripts/ocr_evidence.mjs --clinic --evidence > [--min-width 400] [--max-images 200] [--min-conf 0.5] [--force] +// +// 원칙 +// - 유료 API 를 쓰지 않는다. Vision 이 준 글자만 쓰고 교정·보완하지 않는다(없는 글자를 만들지 않는다). +// - 신뢰도 0.5 미만 줄은 버린다. 줄 병합은 문장 부호 기준으로만 한다: 앞 줄이 . ? ! 로 끝나지 않으면 다음 줄을 같은 문장으로 이어 붙인다. +// 세로 간격이 줄 높이의 1.6배를 넘으면 문단을 나눈다(나누기만 하고 붙이지는 않는다). +// - 원문(HTML) 텍스트와 OCR 텍스트를 구분한다: 페이지 JSON 에 ocr[]·sections[{source:"ocr"}]·flags.ocr=true·textOriginal 을 남긴다. +// - 다시 돌려도 결과가 같다(멱등): 이미 받은 이미지는 다시 받지 않고, 텍스트는 textOriginal 에서 다시 만든다. --force 면 OCR 도 다시 한다. +// +// 산출물(기존 파일을 갱신) +// evidence//ocr//<이미지> 내려받은 원본 이미지 +// evidence//ocr/results.jsonl 이미지별 Vision 원출력(줄·신뢰도·좌표) +// evidence//pages/.json ocr[], sections 에 OCR 섹션 추가, text·chars 갱신, flags.ocr +// evidence//index.json chars·flags 갱신, ocr 요약 +// evidence//home_text.txt 원문 + OCR (40자 연속 일치 게이트 기준. OCR 글자도 병원 문장이므로 합친다) +// evidence//home_text.ocr.txt OCR 만 따로 +// evidence//doctors.json 의료진 페이지 OCR 에서 읽은 이름·직함·약력 후보 ("OCR · 확인 대기") +import { mkdirSync, writeFileSync, readFileSync, existsSync, statSync, readdirSync } from 'node:fs'; +import { join, basename, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { spawnSync } from 'node:child_process'; + +// ---------- 인자 ---------- +const arg = (k, d) => { const i = process.argv.indexOf(k); return i > -1 ? process.argv[i + 1] : d; }; +const CLINIC = arg('--clinic'); const EV = arg('--evidence'); +if (!CLINIC || !EV || !existsSync(join(EV, 'index.json'))) { console.error('사용법: --clinic --evidence > (index.json 있는 폴더)'); process.exit(2); } +const MIN_WIDTH = Number(arg('--min-width', 400)); const MAX_IMAGES = Number(arg('--max-images', 200)); const MIN_CONF = Number(arg('--min-conf', 0.5)); +const FORCE = process.argv.includes('--force'); +const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0 Safari/537.36 INFINITH-supporters-evidence/1.0 (+mailto:o2oteam@o2o.kr)'; +const today = new Date().toISOString().slice(0, 10); +const OCR_DIR = join(EV, 'ocr'); mkdirSync(OCR_DIR, { recursive: true }); + +// ---------- Vision 도구 빌드 ---------- +const SWIFT_SRC = fileURLToPath(new URL('./ocr/vision_ocr.swift', import.meta.url)); +const BIN = join(dirname(SWIFT_SRC), 'vision_ocr'); +function ensureBinary() { + const fresh = existsSync(BIN) && statSync(BIN).mtimeMs >= statSync(SWIFT_SRC).mtimeMs; + if (fresh) return; + console.log(` swiftc 빌드 ${basename(SWIFT_SRC)} → ${basename(BIN)}`); + const r = spawnSync('swiftc', ['-O', '-o', BIN, SWIFT_SRC], { encoding: 'utf8' }); + if (r.status !== 0) { console.error(r.stderr || r.stdout); console.error('vision_ocr 빌드 실패. Xcode Command Line Tools(swiftc) 가 필요하다'); process.exit(1); } +} + +// ---------- 대상 페이지·이미지 ---------- +// 로고·버튼·아이콘·배너·전후사진·장비 썸네일은 이름으로 뺀다. 폭은 Vision 도구가 --min-width 로 거른다 +const NOT_CONTENT = /icon|logo|btn|button|arrow|blank|spacer|sns|share|banner|bnr|top_ban|_ban\d|main_bf|convenient|bg_|_bg\b|\/bg\.|dot\.|bullet|quick|visual|slide|roll|thumb|gallery\/|laiser_table|_next\/image|\.bmp$|\.gif$|\.svg$|before|after/i; +const TYPE_PRIO = { 'doctor-detail': 0, doctor: 1, procedure: 2, precautions: 3, aftercare: 3, safety: 3, checkup: 3, about: 4, pricing: 4, facilities: 5, direction: 5, reservation: 6, branches: 6, home: 7, other: 8 }; +const index = JSON.parse(readFileSync(join(EV, 'index.json'), 'utf8')); +const loadPage = (f) => JSON.parse(readFileSync(join(EV, f), 'utf8')); +const savePage = (f, p) => writeFileSync(join(EV, f), JSON.stringify(p, null, 1)); +const flagOn = (p, k) => (Array.isArray(p.flags) ? p.flags.includes(k) : Boolean(p.flags?.[k])); + +const candidates = index.pages + .filter((p) => p.status === 200 && p.type !== 'duplicate' && p.file) + .map((p) => ({ ix: p, page: loadPage(p.file) })) + .filter(({ page }) => flagOn(page, 'textInImages') || (page.flags?.charsOriginal ?? page.chars ?? 0) < 100) + .sort((a, b) => (TYPE_PRIO[a.ix.type] ?? 9) - (TYPE_PRIO[b.ix.type] ?? 9)); +console.log(`[1/4] ${CLINIC}: 이미지 글자 페이지 ${candidates.length}개 (전체 ${index.pages.length})`); + +// 페이지별 콘텐츠 이미지 → 내려받기 목록. 같은 이미지가 여러 페이지에 있으면 한 번만 받는다 +const jobs = []; const seenSrc = new Map(); +for (const c of candidates) { + const imgs = (c.page.images ?? []).filter((im) => im.src && !NOT_CONTENT.test(im.src)); + for (const im of imgs) { + if (jobs.length >= MAX_IMAGES) break; + const key = im.src.replace(/^https?:\/\//, ''); + if (seenSrc.has(key)) { seenSrc.get(key).pages.push(c); continue; } + const name = decodeURIComponent(basename(new URL(im.src).pathname)).replace(/[^a-zA-Z0-9가-힣._-]+/g, '_') || 'image'; + const file = join(OCR_DIR, c.page.slug, name); + const job = { src: im.src, alt: im.alt ?? '', file, pages: [c] }; + seenSrc.set(key, job); jobs.push(job); + } +} +console.log(` 콘텐츠 이미지 후보 ${jobs.length}개 (--max-images ${MAX_IMAGES}, 이름으로 제외 ${candidates.reduce((n, c) => n + (c.page.images ?? []).filter((im) => NOT_CONTENT.test(im.src ?? '')).length, 0)}개)`); + +// ---------- 내려받기 ---------- +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +async function download(job) { + if (existsSync(job.file) && statSync(job.file).size > 0) { job.downloaded = 'cached'; return; } + for (let i = 0; i < 3; i++) { + try { + const res = await fetch(job.src, { headers: { 'user-agent': UA, referer: job.pages[0].page.url }, signal: AbortSignal.timeout(30000) }); + if (res.status !== 200) { job.error = `HTTP ${res.status}`; return; } + const buf = new Uint8Array(await res.arrayBuffer()); + if (buf.length < 1000) { job.error = `파일이 너무 작음 (${buf.length}B)`; return; } + mkdirSync(dirname(job.file), { recursive: true }); writeFileSync(job.file, buf); job.downloaded = 'new'; return; + } catch (e) { job.error = e.message; await sleep(600 * (i + 1)); } + } +} +{ + let i = 0; const workers = Array.from({ length: 3 }, async () => { while (i < jobs.length) { const j = jobs[i++]; await download(j); process.stdout.write(`\r 내려받기 ${i}/${jobs.length}`); } }); + await Promise.all(workers); +} +const fetched = jobs.filter((j) => !j.error); +console.log(`\n[2/4] 내려받음 ${fetched.length}개 (새로 ${fetched.filter((j) => j.downloaded === 'new').length} · 캐시 ${fetched.filter((j) => j.downloaded === 'cached').length} · 실패 ${jobs.length - fetched.length})`); + +// ---------- OCR ---------- +ensureBinary(); +const RESULTS = join(OCR_DIR, 'results.jsonl'); +const prior = new Map(); // file → 결과 (멱등: 이미 읽은 이미지는 다시 읽지 않는다) +if (!FORCE && existsSync(RESULTS)) for (const l of readFileSync(RESULTS, 'utf8').split('\n').filter(Boolean)) { try { const o = JSON.parse(l); if (o.path && !o.error) prior.set(o.path, o); } catch { /* 깨진 줄 무시 */ } } +const todo = fetched.filter((j) => !prior.has(j.file)); +const results = new Map(prior); +if (todo.length) { + console.log(` Vision OCR ${todo.length}개 (캐시 ${fetched.length - todo.length}개)`); + for (let i = 0; i < todo.length; i += 25) { // 한 프로세스에 25장씩. 실패해도 나머지는 진행 + const batch = todo.slice(i, i + 25); + const r = spawnSync(BIN, ['--min-width', String(MIN_WIDTH), '--langs', 'ko-KR,en-US', ...batch.map((j) => j.file)], { encoding: 'utf8', maxBuffer: 512 * 1024 * 1024 }); + if (r.status !== 0 && !r.stdout) { console.error(` vision_ocr 실패: ${r.stderr?.slice(0, 500)}`); for (const j of batch) results.set(j.file, { path: j.file, error: `vision_ocr 종료 코드 ${r.status}` }); continue; } + for (const l of r.stdout.split('\n').filter(Boolean)) { try { const o = JSON.parse(l); results.set(o.path, o); } catch { /* 무시 */ } } + process.stdout.write(`\r OCR ${Math.min(i + 25, todo.length)}/${todo.length}`); + } + console.log(''); + writeFileSync(RESULTS, [...results.values()].map((o) => JSON.stringify(o)).join('\n') + '\n'); +} + +// ---------- 줄 → 문단 ---------- +const ENDS = /[.?!。…]["')\]]?$/; +/** 신뢰도로 거르고, 문장 부호 기준으로 줄을 잇는다. 세로 간격이 크면 문단을 나눈다 */ +function linesToText(lines) { + const kept = lines.filter((l) => l.confidence >= MIN_CONF && l.text.trim()); + const paras = []; let cur = null; let prev = null; + for (const l of kept) { + const t = l.text.trim(); + const gapBreak = prev && l.box && prev.box && (l.box[1] - (prev.box[1] + prev.box[3])) > Math.max(prev.box[3], l.box[3]) * 1.6; + if (cur && !gapBreak && !ENDS.test(cur)) cur = `${cur} ${t}`; + else { if (cur) paras.push(cur); cur = t; } + prev = l; + } + if (cur) paras.push(cur); + return { text: paras.join('\n'), kept: kept.length, dropped: lines.length - kept.length }; +} + +// ---------- 페이지에 반영 ---------- +let ocrImages = 0, ocrPages = 0, ocrChars = 0; const failed = []; const perPage = []; +for (const c of candidates) { + const page = c.page; + const myJobs = jobs.filter((j) => j.pages.includes(c)); + const entries = []; + for (const j of myJobs) { + const r = results.get(j.file); + if (j.error) { failed.push({ page: page.url, src: j.src, reason: j.error }); continue; } + if (!r) { failed.push({ page: page.url, src: j.src, reason: 'OCR 결과 없음' }); continue; } + if (r.error) { failed.push({ page: page.url, src: j.src, reason: r.error }); continue; } + if (r.skipped) continue; // 폭 부족 + const { text, kept, dropped } = linesToText(r.lines ?? []); + if (!text) continue; + const conf = kept ? Math.round((r.lines.filter((l) => l.confidence >= MIN_CONF).reduce((s, l) => s + l.confidence, 0) / kept) * 1000) / 1000 : 0; + entries.push({ src: j.src, alt: j.alt, file: j.file.replace(EV + '/', ''), width: r.width, height: r.height, tiles: r.tiles ?? 1, lines: r.lines.filter((l) => l.confidence >= MIN_CONF).map((l) => l.text), droppedLines: dropped, confidence: conf, text, engine: r.engine ?? 'apple-vision', at: today }); + } + // 원문 텍스트는 textOriginal 로 보존(재실행 시 여기서 다시 만든다) + page.textOriginal ??= page.text ?? ''; + page.flags ??= {}; + page.flags.charsOriginal ??= page.textOriginal.replace(/\s+/g, '').length; + page.sections = (page.sections ?? []).filter((s) => s.source !== 'ocr'); + page.ocr = entries; + const ocrText = entries.map((e) => e.text).join('\n'); + if (entries.length) { + page.sections.push({ heading: page.title || page.h1 || page.slug, level: 2, source: 'ocr', images: entries.map((e) => e.src), text: ocrText, paragraphs: ocrText.split('\n'), lists: [], tables: [] }); + page.text = [page.textOriginal, ocrText].filter(Boolean).join('\n'); + page.flags.ocr = true; page.flags.ocrImages = entries.length; page.flags.ocrChars = ocrText.replace(/\s+/g, '').length; + ocrImages += entries.length; ocrPages++; ocrChars += page.flags.ocrChars; + } else { page.text = page.textOriginal; delete page.flags.ocr; delete page.flags.ocrImages; delete page.flags.ocrChars; } + page.chars = page.text.replace(/\s+/g, '').length; + savePage(c.ix.file, page); + c.ix.chars = page.chars; + c.ix.flags = Object.entries(page.flags).filter(([, v]) => v === true).map(([k]) => k); + perPage.push({ url: page.url, type: page.type, title: page.title, chars: page.chars, ocrChars: page.flags.ocrChars ?? 0, images: entries.length }); +} +index.byType = index.pages.reduce((m, x) => ((m[x.type] = (m[x.type] ?? 0) + 1), m), {}); +index.ocr = { at: today, engine: 'apple-vision', pages: ocrPages, images: ocrImages, chars: ocrChars, minWidth: MIN_WIDTH, minConf: MIN_CONF, failed: failed.length }; +writeFileSync(join(EV, 'index.json'), JSON.stringify(index, null, 1)); +console.log(`[3/4] 페이지 ${ocrPages}개에 OCR 반영 (이미지 ${ocrImages}장 · OCR 글자 ${ocrChars.toLocaleString()}자 · 실패 ${failed.length})`); + +// ---------- home_text ---------- +// 40자 연속 일치 게이트는 병원 문장의 그대로 옮김을 막는 것이다. OCR 글자도 병원이 쓴 문장이므로 home_text.txt 에 합친다. +// OCR 오독으로 원문과 몇 글자 다를 수 있어 게이트가 그만큼 느슨해질 뿐, 잘못 막는 쪽으로는 가지 않는다. OCR 만 따로 home_text.ocr.txt 에도 남긴다. +{ + const orig = []; const ocr = []; + for (const ix of index.pages) { + if (ix.status !== 200 || ix.type === 'duplicate' || !ix.file) continue; + const p = loadPage(ix.file); + const o = (p.textOriginal ?? p.text ?? '').replace(/\s+/g, ''); if (o) orig.push(o); + const t = (p.ocr ?? []).map((e) => e.text).join('\n').replace(/\s+/g, ''); if (t) ocr.push(t); + } + writeFileSync(join(EV, 'home_text.txt'), [...orig, ...ocr].join('\n')); + writeFileSync(join(EV, 'home_text.ocr.txt'), ocr.join('\n')); +} + +// ---------- 의료진 ---------- +// 의료진 페이지 OCR 줄에서 "이름 원장" 을 찾고, 다음 이름·지점 제목까지의 줄을 약력 후보로. 지점("X점")·지역("X지역")·진료과 제목은 소속으로 붙인다. +const NAME_RE = /^[\s|1lI]*([가-힣]{2,4})\s*(대표\s*)?원장(?:님)?\s*$/; +const BRANCH_RE = /^[\s|]*((?:[가-힣]{1,4}\s)?[가-힣A-Za-z0-9]{1,10}점)\s*$/; +const REGION_RE = /^[\s|]*([가-힣]{2,6}지역)\s*$/; +const DEPT_RE = /^[\s|]*(피부과|성형외과|치과|내과|비만\s*[•·]?\s*체형|피부\s*관리)\s*$/; +const SPECIALTY_RE = /(성형외과|이비인후과|마취통증의학과|피부과|영상의학과|외과|치과|내과|가정의학과|산부인과)\s*전문의/; +function parseDoctorsFromOcr(page) { + const out = []; + for (const e of page.ocr ?? []) { + let region = null, branch = null, dept = null, cur = null; + for (const raw of e.lines) { + const t = raw.trim(); + let m; + if ((m = t.match(REGION_RE))) { region = m[1]; continue; } + if ((m = t.match(BRANCH_RE))) { branch = m[1]; cur = null; continue; } + if ((m = t.match(DEPT_RE))) { dept = m[1].replace(/\s+/g, ' '); continue; } + if ((m = t.match(NAME_RE))) { cur = { name: m[1], isRep: Boolean(m[2]), region, branch, dept, credentials: [], image: e.src }; out.push(cur); continue; } + if (cur && t.length >= 4 && t.length <= 60) cur.credentials.push(t); + } + } + return out.map((d, i) => { + const specialty = d.credentials.map((c) => c.match(SPECIALTY_RE)?.[0]).find(Boolean) ?? null; + return { id: `ocr-${i + 1}-${d.name}`, url: page.url, name: d.name, title: [d.isRep ? '대표원장' : '원장', specialty].filter(Boolean).join(' · '), region: d.region, branch: d.branch, dept: d.dept, credentials: d.credentials.filter((c) => c !== specialty), image: d.image, source: 'ocr', status: 'OCR · 확인 대기' }; + }); +} +{ + const path = join(EV, 'doctors.json'); + const doc = existsSync(path) ? JSON.parse(readFileSync(path, 'utf8')) : { clinic: CLINIC, fetchedAt: today, doctors: [] }; + const doctorPages = candidates.filter((c) => ['doctor', 'doctor-detail'].includes(c.page.type) && c.page.ocr?.length); + const found = doctorPages.flatMap((c) => parseDoctorsFromOcr(c.page)); + if (found.length) { + // 상세 페이지에서 이미 이름이 읽힌 의사는 유지하고 OCR 약력만 붙인다. 이름 없이 남아 있던 항목(이미지 글자)은 OCR 결과로 바꾼다 + // 지난 실행의 OCR 항목(source=ocr)은 버리고 다시 만든다(멱등) + const kept = (doc.doctors ?? []).filter((d) => d.name && d.source !== 'ocr').map((d) => { const o = found.find((f) => f.name === d.name); return o ? { ...d, credentialsOcr: o.credentials, ocrImage: o.image, status: d.status === 'ok' ? d.status : 'OCR 약력 · 확인 대기' } : d; }); + const add = found.filter((f) => !kept.some((d) => d.name === f.name)); + doc.doctors = [...kept, ...add]; + doc.ocr = { at: today, pages: doctorPages.map((c) => c.page.url), found: found.length, note: 'source=ocr 항목은 의료진 이미지에서 Vision 으로 읽은 이름·약력 후보. 오독 가능. authors.json 에 옮기기 전에 원본 이미지와 대조한다.' }; + writeFileSync(path, JSON.stringify(doc, null, 1)); + console.log(` 의료진 OCR 후보 ${found.length}명 (${[...new Set(found.map((f) => f.branch).filter(Boolean))].length}개 지점) → doctors.json ${doc.doctors.length}명`); + } else console.log(' 의료진 OCR 후보 없음'); +} + +// ---------- 보고 ---------- +const dist = perPage.filter((p) => p.images); +console.log(`[4/4] 저장 ${EV}`); +console.log(` OCR 이미지 ${ocrImages}장 · 페이지 ${ocrPages}개 · 200자 이상 ${dist.filter((p) => p.ocrChars >= 200).length}개 · 1,000자 이상 ${dist.filter((p) => p.ocrChars >= 1000).length}개 · home_text ${index.pages.reduce((n, p) => n + (p.chars ?? 0), 0).toLocaleString()}자 (OCR ${ocrChars.toLocaleString()}자)`); +if (failed.length) console.log(` 실패 ${failed.length}: ${failed.slice(0, 10).map((f) => `${f.src} (${f.reason})`).join(', ')}${failed.length > 10 ? ' …' : ''}`); diff --git a/supporters/scripts/template/data/medicalTourism.json b/supporters/scripts/template/data/medicalTourism.json new file mode 100644 index 0000000..d9d64bc --- /dev/null +++ b/supporters/scripts/template/data/medicalTourism.json @@ -0,0 +1,36 @@ +{ + "_comment": "주변 안내 데이터(빈 값). 워커의 tourism 단계(scripts/fetch_medical_tourism.py)가 팩트 시트 주소로 채운다. origin lat 0 이면 /stay·/en/stay 는 '확인 대기'로 그린다.", + "places": { + "stay": [], + "restaurant": [], + "wellness": [], + "attraction": [], + "culture": [], + "shopping": [] + }, + "festivals": [], + "filters": { + "total": 0, + "walk5": 0, + "walk15": 0, + "walkAll": 0, + "drive": 0 + }, + "meta": { + "source": "", + "fetchedAt": "", + "origin": { + "lat": 0, + "lng": 0, + "label": "", + "address": "", + "coordSource": "" + }, + "radiusByType": {}, + "festivalRadiusKm": 0, + "counts": {}, + "limits": [], + "lang": "en", + "clinic": "" + } +} diff --git a/supporters/scripts/template/data/medicalTourismKo.json b/supporters/scripts/template/data/medicalTourismKo.json new file mode 100644 index 0000000..3323d7c --- /dev/null +++ b/supporters/scripts/template/data/medicalTourismKo.json @@ -0,0 +1,36 @@ +{ + "_comment": "주변 안내 데이터(빈 값). 워커의 tourism 단계(scripts/fetch_medical_tourism.py)가 팩트 시트 주소로 채운다. origin lat 0 이면 /stay·/en/stay 는 '확인 대기'로 그린다.", + "places": { + "stay": [], + "restaurant": [], + "wellness": [], + "attraction": [], + "culture": [], + "shopping": [] + }, + "festivals": [], + "filters": { + "total": 0, + "walk5": 0, + "walk15": 0, + "walkAll": 0, + "drive": 0 + }, + "meta": { + "lang": "ko", + "source": "", + "fetchedAt": "", + "origin": { + "lat": 0, + "lng": 0, + "label": "", + "address": "", + "coordSource": "" + }, + "radiusByType": {}, + "festivalRadiusKm": 0, + "counts": {}, + "limits": [], + "clinic": "" + } +} diff --git a/supporters/scripts/template/data/places.json b/supporters/scripts/template/data/places.json new file mode 100644 index 0000000..28c8482 --- /dev/null +++ b/supporters/scripts/template/data/places.json @@ -0,0 +1,207 @@ +{ + "_comment": "범용 큐레이션 기본표. 워커 planner 단계가 {CLINIC_KO}/{CLINIC_EN}/{AREA_KO}/{AREA_EN} 치환자를 팩트 시트 값으로 바꾸고 origin 을 관광공사 수집 기준 좌표로 채운다. 병원별 큐레이션(briefs//planner.places.json)이 있으면 이 표 대신 그것을 쓴다. 숙소는 관광공사 데이터가 맡는다.", + "origin": { + "label": { + "ko": "{CLINIC_KO}", + "en": "{CLINIC_EN}" + }, + "lat": 0, + "lng": 0 + }, + "categories": { + "sightseeing": { + "ko": "관광", + "en": "Sightseeing" + }, + "shopping": { + "ko": "쇼핑", + "en": "Shopping" + }, + "food": { + "ko": "미식", + "en": "Food" + }, + "kpop": { + "ko": "K-pop·핫플", + "en": "K-pop & hotspots" + }, + "care": { + "ko": "휴식·케어", + "en": "Rest & care" + }, + "essentials": { + "ko": "생활", + "en": "Essentials" + }, + "hotel": { + "ko": "숙소", + "en": "Hotels" + } + }, + "places": [ + { + "id": "pharmacy", + "name": { + "ko": "{AREA_KO} 주변 약국", + "en": "Pharmacies near {AREA_EN}" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.2, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "처방약과 냉찜질 팩을 구할 수 있습니다.", + "en": "Prescriptions and cold packs." + }, + "mapQuery": "약국 {AREA_KO}", + "verify": true + }, + { + "id": "convenience", + "name": { + "ko": "편의점 ({AREA_KO} 일대)", + "en": "Convenience stores ({AREA_EN})" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.1, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "생수, 죽, 빨대, 얼음을 24시간 살 수 있습니다.", + "en": "Water, porridge, straws and ice, 24 hours." + }, + "mapQuery": "편의점 {AREA_KO}", + "verify": true + }, + { + "id": "porridge", + "name": { + "ko": "죽 전문점 (본죽 등 체인)", + "en": "Korean porridge (Bonjuk and similar chains)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.5, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "유동식·부드러운 식사 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", + "en": "Porridge for the liquid and soft-food stages, by delivery or takeout." + }, + "mapQuery": "본죽 {AREA_KO}", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "smoothie", + "name": { + "ko": "스무디·주스 카페 ({AREA_KO})", + "en": "Smoothie and juice cafes ({AREA_EN})" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.4, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", + "en": "Straw-friendly options. Choose nothing hot." + }, + "mapQuery": "스무디 카페 {AREA_KO}", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "soup", + "name": { + "ko": "설렁탕·곰탕 ({AREA_KO} 일대)", + "en": "Beef bone soup ({AREA_EN})" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.6, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다.", + "en": "Broth-based, fine from the soft-food stage." + }, + "mapQuery": "설렁탕 {AREA_KO}", + "verify": true, + "dietOk": [ + "soft", + "mild", + "normal" + ] + }, + { + "id": "clinic-followup", + "name": { + "ko": "{CLINIC_KO} 경과 확인", + "en": "{CLINIC_EN} follow-up" + }, + "category": "care", + "minLevel": 1, + "distanceKm": 0.05, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "경과 확인과 관리는 병원 안내에 따라 예약합니다.", + "en": "Follow-up checks and care, booked per the clinic's guidance." + }, + "mapQuery": "{CLINIC_KO}", + "verify": true + }, + { + "id": "hotel-lounge", + "name": { + "ko": "호텔 스파·라운지 (숙소 안)", + "en": "Hotel spa and lounge (at your hotel)" + }, + "category": "care", + "minLevel": 0, + "distanceKm": 0, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", + "en": "Skip sauna and massage until your doctor allows. Lounge and room service are fine." + }, + "mapQuery": null, + "verify": true + } + ] +} diff --git a/supporters/scripts/template/data/procedures.json b/supporters/scripts/template/data/procedures.json new file mode 100644 index 0000000..ac95bc8 --- /dev/null +++ b/supporters/scripts/template/data/procedures.json @@ -0,0 +1,961 @@ +{ + "_comment": "성형외과 기본 규칙표 (뷰성형외과 샘플에서 정리). 워커 planner 단계(scripts/build_planner_data.mjs)가 병원 시술 페이지 원문(recoveryNotes.json)을 matchKeywords 로 시술에 붙여 병원별 procedures.json 을 만든다. clinic 출처가 있는 값은 뷰성형외과 공개 안내이므로 다른 병원에서는 provisional 로 내려간다.", + "clinicSources": [], + "levels": [ + { + "level": 0, + "label": { + "ko": "실내 안정", + "en": "Rest indoors" + }, + "desc": { + "ko": "병실이나 호텔에서 쉬는 날입니다. 필요한 것은 배달과 룸서비스로 해결합니다.", + "en": "Rest at the hospital or hotel. Use delivery and room service." + } + }, + { + "level": 1, + "label": { + "ko": "근거리 외출", + "en": "Short walks" + }, + "desc": { + "ko": "호텔 반경 500m 안에서 짧게 다녀옵니다. 도보 10분 이내.", + "en": "Short trips within 500 m of your hotel. Up to a 10-minute walk." + } + }, + { + "level": 2, + "label": { + "ko": "반나절 외출", + "en": "Half-day outing" + }, + "desc": { + "ko": "택시로 반경 3km 안 쇼핑·식사·가벼운 관광이 가능합니다.", + "en": "Shopping, dining and light sightseeing within 3 km by taxi." + } + }, + { + "level": 3, + "label": { + "ko": "자유 외출", + "en": "Full day out" + }, + "desc": { + "ko": "하루 단위 외출이 가능합니다. 시내 관광, 행사, 인파가 있는 곳도 담당 원장 안내 안에서 가능합니다.", + "en": "Full-day outings. City sightseeing and events, within your surgeon's guidance." + } + } + ], + "diets": { + "liquid": { + "label": { + "ko": "유동식", + "en": "Liquid diet" + }, + "desc": { + "ko": "건더기 없는 유동식만 드십니다.", + "en": "Liquids only, no solids." + } + }, + "soft": { + "label": { + "ko": "부드러운 음식", + "en": "Soft foods" + }, + "desc": { + "ko": "건더기가 있어도 부드러운 음식까지 가능합니다.", + "en": "Soft foods are fine. Avoid anything chewy or hard." + } + }, + "mild": { + "label": { + "ko": "자극 없는 일반식", + "en": "Regular, non-spicy" + }, + "desc": { + "ko": "맵고 짜거나 딱딱한 음식은 피합니다.", + "en": "Regular meals. Avoid spicy, salty or hard foods." + } + }, + "normal": { + "label": { + "ko": "일반식", + "en": "Regular diet" + }, + "desc": { + "ko": "식사 제한이 없습니다.", + "en": "No dietary restrictions." + } + } + }, + "constraints": { + "no-heavy-lifting": { + "ko": "무거운 짐과 팔을 많이 쓰는 동작을 피합니다. 쇼핑은 배송 서비스를 이용하세요.", + "en": "Avoid heavy bags and arm-heavy movement. Use delivery for shopping." + }, + "sports-bra": { + "ko": "스포츠브라를 1~3개월 유지합니다.", + "en": "Wear a sports bra for 1 to 3 months." + }, + "no-alcohol-30d": { + "ko": "음주와 흡연은 최소 1개월 이후입니다.", + "en": "No alcohol or smoking for at least 1 month." + }, + "no-sauna-60d": { + "ko": "사우나, 찜질방, 수영, 과한 운동은 약 2개월 후입니다.", + "en": "No sauna, spa, swimming or intense exercise for about 2 months." + }, + "compression-band": { + "ko": "압박밴드를 2~4주 착용합니다. 취침 시에는 하지 않습니다.", + "en": "Wear the compression band for 2 to 4 weeks, not while sleeping." + }, + "sleep-elevated": { + "ko": "머리를 심장보다 높게 하고 정면 자세로 잡니다. 1주 후부터 옆으로 누워도 됩니다.", + "en": "Sleep with your head above heart level, facing up. Side sleeping from week 2." + }, + "saline-gargle": { + "ko": "약 1개월간 생리식염수 가글을 꾸준히 합니다.", + "en": "Rinse with saline regularly for about 1 month." + }, + "no-hard-food-30d": { + "ko": "질기고 딱딱한 음식은 한 달간 피합니다.", + "en": "Avoid chewy or hard food for 1 month." + }, + "no-sun": { + "ko": "직사광선을 피합니다. 모자와 선글라스를 챙기세요.", + "en": "Avoid direct sun. Bring a hat and sunglasses." + }, + "mask": { + "ko": "외출 시 마스크를 쓰면 부기와 멍이 덜 보입니다.", + "en": "A mask helps cover swelling and bruising when out." + }, + "no-glasses": { + "ko": "안경 착용을 피합니다. 콘택트렌즈나 안경 없이 다닐 계획을 세우세요.", + "en": "Avoid glasses resting on your nose. Plan for contacts or going without." + }, + "no-lens": { + "ko": "콘택트렌즈는 담당 원장이 허용할 때까지 쓰지 않습니다.", + "en": "No contact lenses until your surgeon allows." + }, + "cold-compress": { + "ko": "초기에는 냉찜질, 이후 온찜질을 합니다.", + "en": "Cold compresses at first, then warm." + }, + "no-nose-blow": { + "ko": "코를 세게 풀거나 코 부위에 압력을 주지 않습니다.", + "en": "Do not blow your nose or press on the nose area." + }, + "no-massage": { + "ko": "수술 부위 마사지와 강한 압박을 피합니다.", + "en": "No massage or firm pressure on the surgical area." + }, + "no-hat-pressure": { + "ko": "이식 부위를 누르는 모자나 헬멧을 피합니다.", + "en": "Avoid hats or helmets that press on the graft area." + }, + "no-scratch": { + "ko": "가려워도 긁지 않습니다.", + "en": "Do not scratch, even if itchy." + }, + "driving": { + "ko": "수술 당일은 운전할 수 없습니다. 보호자 동반을 권합니다.", + "en": "No driving on surgery day. A companion is recommended." + } + }, + "procedures": [ + { + "id": "breast", + "label": { + "ko": "가슴성형", + "en": "Breast Augmentation" + }, + "group": { + "ko": "가슴", + "en": "Breast" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "검진과 상담 1일, 여유 1일", + "en": "1 day for tests and consultation, 1 buffer day" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 10 + ], + "status": "provisional", + "note": { + "ko": "실밥이 있으면 약 1주에 제거. 피부 접착제를 쓴 경우 실밥 없음", + "en": "Stitches, if any, removed at about 1 week. No stitches if skin adhesive was used" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional", + "note": { + "ko": "부기는 2~3일째 가장 심합니다", + "en": "Swelling peaks on days 2 to 3" + } + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional", + "note": { + "ko": "3일 이후 붕대를 뗍니다", + "en": "Bandage removed after day 3" + } + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "no-heavy-lifting", + "sports-bra", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "가슴|유방|보형물|모티바" + }, + { + "id": "contour", + "label": { + "ko": "안면윤곽·양악", + "en": "Facial Contouring / Jaw Surgery" + }, + "group": { + "ko": "얼굴뼈", + "en": "Facial bone" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "3D-CT 촬영과 검진, 상담", + "en": "3D-CT, tests and consultation" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "입안 실은 녹는 실이라 보통 한 달 후 저절로 없어집니다. 별도 제거 방문 없음", + "en": "Intraoral stitches dissolve on their own in about a month. No removal visit" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 14, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional", + "note": { + "ko": "부기는 3~4일까지 늘다가 가라앉습니다", + "en": "Swelling increases until day 3 to 4, then subsides" + } + }, + { + "fromDay": 5, + "level": 1, + "status": "provisional", + "note": { + "ko": "5~7일 후 일상생활이 가능합니다", + "en": "Daily activities possible after day 5 to 7" + } + }, + { + "fromDay": 10, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 21, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "liquid", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 14, + "type": "mild", + "status": "provisional" + }, + { + "fromDay": 30, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "compression-band", + "sleep-elevated", + "saline-gargle", + "no-hard-food-30d", + "no-alcohol-30d", + "no-sauna-60d", + "no-massage" + ], + "sources": [], + "matchKeywords": "윤곽|양악|사각턱|광대|턱끝|무턱|주걱턱" + }, + { + "id": "eye", + "label": { + "ko": "눈성형", + "en": "Eyelid Surgery" + }, + "group": { + "ko": "눈", + "en": "Eyes" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 6, + "range": [ + 5, + 7 + ], + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 10, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "cold-compress", + "no-sun", + "no-lens", + "no-scratch", + "no-alcohol-30d" + ], + "sources": [], + "matchKeywords": "눈|쌍꺼풀|매몰|절개|트임|눈매" + }, + { + "id": "nose", + "label": { + "ko": "코성형", + "en": "Rhinoplasty" + }, + "group": { + "ko": "코", + "en": "Nose" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 7 + ], + "status": "provisional", + "note": { + "ko": "부목과 실밥 제거", + "en": "Splint and stitch removal" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "mild", + "status": "provisional" + }, + { + "fromDay": 14, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-glasses", + "no-nose-blow", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "코|비중격|콧" + }, + { + "id": "fat", + "label": { + "ko": "지방성형", + "en": "Liposuction / Fat Grafting" + }, + "group": { + "ko": "지방", + "en": "Fat" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "compression-band", + "no-massage", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "지방|흡입|바디" + }, + { + "id": "lifting", + "label": { + "ko": "안티에이징·리프팅", + "en": "Anti-aging / Face Lift" + }, + "group": { + "ko": "리프팅", + "en": "Lifting" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-massage", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "리프팅|거상|주름|안티에이징" + }, + { + "id": "skin", + "label": { + "ko": "피부과 시술", + "en": "Dermatology Treatment" + }, + "group": { + "ko": "피부", + "en": "Skin" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "실밥 없음", + "en": "No stitches" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 2, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "피부|레이저|보톡스|필러|토닝|색소" + }, + { + "id": "hair", + "label": { + "ko": "모발이식", + "en": "Hair Transplant" + }, + "group": { + "ko": "모발", + "en": "Hair" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "채취 방식에 따라 다릅니다", + "en": "Depends on the harvesting method" + } + }, + "earliestDepartureDay": { + "value": 3, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-hat-pressure", + "no-scratch", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "모발|탈모" + } + ], + "nationalities": { + "_comment": "무비자 체류 한도(일). 2026-09 기준 확인 필요. null 은 사전 비자 필요. 화면은 항상 대한민국 비자포털 링크와 함께 보여준다.", + "portal": "https://www.visa.go.kr", + "list": [ + { + "code": "US", + "label": { + "ko": "미국", + "en": "United States" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "CA", + "label": { + "ko": "캐나다", + "en": "Canada" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "GB", + "label": { + "ko": "영국", + "en": "United Kingdom" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "AU", + "label": { + "ko": "호주", + "en": "Australia" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "JP", + "label": { + "ko": "일본", + "en": "Japan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TW", + "label": { + "ko": "대만", + "en": "Taiwan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "HK", + "label": { + "ko": "홍콩", + "en": "Hong Kong" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "SG", + "label": { + "ko": "싱가포르", + "en": "Singapore" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TH", + "label": { + "ko": "태국", + "en": "Thailand" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "MY", + "label": { + "ko": "말레이시아", + "en": "Malaysia" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "AE", + "label": { + "ko": "아랍에미리트", + "en": "United Arab Emirates" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "RU", + "label": { + "ko": "러시아", + "en": "Russia" + }, + "visaFreeDays": 60, + "longHaul": true + }, + { + "code": "KZ", + "label": { + "ko": "카자흐스탄", + "en": "Kazakhstan" + }, + "visaFreeDays": 30, + "longHaul": true + }, + { + "code": "CN", + "label": { + "ko": "중국", + "en": "China" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "VN", + "label": { + "ko": "베트남", + "en": "Vietnam" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "ID", + "label": { + "ko": "인도네시아", + "en": "Indonesia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "PH", + "label": { + "ko": "필리핀", + "en": "Philippines" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "MN", + "label": { + "ko": "몽골", + "en": "Mongolia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "OTHER", + "label": { + "ko": "그 외", + "en": "Other" + }, + "visaFreeDays": null, + "longHaul": true + } + ] + } +} diff --git a/supporters/scripts/template/data/recoveryNotes.json b/supporters/scripts/template/data/recoveryNotes.json new file mode 100644 index 0000000..1ed4877 --- /dev/null +++ b/supporters/scripts/template/data/recoveryNotes.json @@ -0,0 +1,8 @@ +{ + "_comment": "시술 후 관리 안내(빈 값). 워커의 recovery 단계(scripts/collect_recovery.mjs)가 병원 시술 페이지 원문에서 채운다. items 가 비어 있으면 /stay·/en/stay 는 이 블록을 그리지 않는다.", + "clinic": "", + "generatedAt": "", + "sourceNote": "병원 홈페이지 시술 페이지 원문", + "items": [], + "counts": {} +} diff --git a/supporters/scripts/template/planner/places.base.json b/supporters/scripts/template/planner/places.base.json new file mode 100644 index 0000000..28c8482 --- /dev/null +++ b/supporters/scripts/template/planner/places.base.json @@ -0,0 +1,207 @@ +{ + "_comment": "범용 큐레이션 기본표. 워커 planner 단계가 {CLINIC_KO}/{CLINIC_EN}/{AREA_KO}/{AREA_EN} 치환자를 팩트 시트 값으로 바꾸고 origin 을 관광공사 수집 기준 좌표로 채운다. 병원별 큐레이션(briefs//planner.places.json)이 있으면 이 표 대신 그것을 쓴다. 숙소는 관광공사 데이터가 맡는다.", + "origin": { + "label": { + "ko": "{CLINIC_KO}", + "en": "{CLINIC_EN}" + }, + "lat": 0, + "lng": 0 + }, + "categories": { + "sightseeing": { + "ko": "관광", + "en": "Sightseeing" + }, + "shopping": { + "ko": "쇼핑", + "en": "Shopping" + }, + "food": { + "ko": "미식", + "en": "Food" + }, + "kpop": { + "ko": "K-pop·핫플", + "en": "K-pop & hotspots" + }, + "care": { + "ko": "휴식·케어", + "en": "Rest & care" + }, + "essentials": { + "ko": "생활", + "en": "Essentials" + }, + "hotel": { + "ko": "숙소", + "en": "Hotels" + } + }, + "places": [ + { + "id": "pharmacy", + "name": { + "ko": "{AREA_KO} 주변 약국", + "en": "Pharmacies near {AREA_EN}" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.2, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "처방약과 냉찜질 팩을 구할 수 있습니다.", + "en": "Prescriptions and cold packs." + }, + "mapQuery": "약국 {AREA_KO}", + "verify": true + }, + { + "id": "convenience", + "name": { + "ko": "편의점 ({AREA_KO} 일대)", + "en": "Convenience stores ({AREA_EN})" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.1, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "생수, 죽, 빨대, 얼음을 24시간 살 수 있습니다.", + "en": "Water, porridge, straws and ice, 24 hours." + }, + "mapQuery": "편의점 {AREA_KO}", + "verify": true + }, + { + "id": "porridge", + "name": { + "ko": "죽 전문점 (본죽 등 체인)", + "en": "Korean porridge (Bonjuk and similar chains)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.5, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "유동식·부드러운 식사 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", + "en": "Porridge for the liquid and soft-food stages, by delivery or takeout." + }, + "mapQuery": "본죽 {AREA_KO}", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "smoothie", + "name": { + "ko": "스무디·주스 카페 ({AREA_KO})", + "en": "Smoothie and juice cafes ({AREA_EN})" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.4, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", + "en": "Straw-friendly options. Choose nothing hot." + }, + "mapQuery": "스무디 카페 {AREA_KO}", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "soup", + "name": { + "ko": "설렁탕·곰탕 ({AREA_KO} 일대)", + "en": "Beef bone soup ({AREA_EN})" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.6, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다.", + "en": "Broth-based, fine from the soft-food stage." + }, + "mapQuery": "설렁탕 {AREA_KO}", + "verify": true, + "dietOk": [ + "soft", + "mild", + "normal" + ] + }, + { + "id": "clinic-followup", + "name": { + "ko": "{CLINIC_KO} 경과 확인", + "en": "{CLINIC_EN} follow-up" + }, + "category": "care", + "minLevel": 1, + "distanceKm": 0.05, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "경과 확인과 관리는 병원 안내에 따라 예약합니다.", + "en": "Follow-up checks and care, booked per the clinic's guidance." + }, + "mapQuery": "{CLINIC_KO}", + "verify": true + }, + { + "id": "hotel-lounge", + "name": { + "ko": "호텔 스파·라운지 (숙소 안)", + "en": "Hotel spa and lounge (at your hotel)" + }, + "category": "care", + "minLevel": 0, + "distanceKm": 0, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", + "en": "Skip sauna and massage until your doctor allows. Lounge and room service are fine." + }, + "mapQuery": null, + "verify": true + } + ] +} diff --git a/supporters/scripts/template/planner/procedures.derm.json b/supporters/scripts/template/planner/procedures.derm.json new file mode 100644 index 0000000..ad80a57 --- /dev/null +++ b/supporters/scripts/template/planner/procedures.derm.json @@ -0,0 +1,842 @@ +{ + "_comment": "피부과 기본 규칙표 (오라클피부과 샘플에서 정리). 워커 planner 단계가 병원 시술 페이지 원문(recoveryNotes.json)을 matchKeywords 로 시술에 붙여 병원별 procedures.json 을 만든다. 값은 전부 provisional(병원 확인 전).", + "clinicSources": [], + "levels": [ + { + "level": 0, + "label": { + "ko": "실내 안정", + "en": "Rest indoors" + }, + "desc": { + "ko": "병실이나 호텔에서 쉬는 날입니다. 필요한 것은 배달과 룸서비스로 해결합니다.", + "en": "Rest at the hospital or hotel. Use delivery and room service." + } + }, + { + "level": 1, + "label": { + "ko": "근거리 외출", + "en": "Short walks" + }, + "desc": { + "ko": "호텔 반경 500m 안에서 짧게 다녀옵니다. 도보 10분 이내.", + "en": "Short trips within 500 m of your hotel. Up to a 10-minute walk." + } + }, + { + "level": 2, + "label": { + "ko": "반나절 외출", + "en": "Half-day outing" + }, + "desc": { + "ko": "택시로 반경 3km 안 쇼핑·식사·가벼운 관광이 가능합니다.", + "en": "Shopping, dining and light sightseeing within 3 km by taxi." + } + }, + { + "level": 3, + "label": { + "ko": "자유 외출", + "en": "Full day out" + }, + "desc": { + "ko": "하루 단위 외출이 가능합니다. 시내 관광, 행사, 인파가 있는 곳도 담당 원장 안내 안에서 가능합니다.", + "en": "Full-day outings. City sightseeing and events, within your surgeon's guidance." + } + } + ], + "diets": { + "liquid": { + "label": { + "ko": "유동식", + "en": "Liquid diet" + }, + "desc": { + "ko": "건더기 없는 유동식만 드십니다.", + "en": "Liquids only, no solids." + } + }, + "soft": { + "label": { + "ko": "부드러운 음식", + "en": "Soft foods" + }, + "desc": { + "ko": "건더기가 있어도 부드러운 음식까지 가능합니다.", + "en": "Soft foods are fine. Avoid anything chewy or hard." + } + }, + "mild": { + "label": { + "ko": "자극 없는 일반식", + "en": "Regular, non-spicy" + }, + "desc": { + "ko": "맵고 짜거나 딱딱한 음식은 피합니다.", + "en": "Regular meals. Avoid spicy, salty or hard foods." + } + }, + "normal": { + "label": { + "ko": "일반식", + "en": "Regular diet" + }, + "desc": { + "ko": "식사 제한이 없습니다.", + "en": "No dietary restrictions." + } + } + }, + "constraints": { + "no-sun": { + "ko": "직사광선을 피하고 자외선차단제를 바릅니다. 모자와 선글라스를 챙기세요.", + "en": "Avoid direct sun and use sunscreen. Bring a hat and sunglasses." + }, + "no-makeup-1d": { + "ko": "화장은 담당 원장 안내에 따라 다음 날부터 합니다.", + "en": "Makeup from the next day, per your doctor's guidance." + }, + "no-makeup-3d": { + "ko": "화장은 딱지가 자리 잡을 때까지 며칠 미룹니다. 시점은 담당 원장에게 확인하세요.", + "en": "Hold off makeup for a few days until scabs settle. Confirm timing with your doctor." + }, + "no-massage-1d": { + "ko": "시술 부위를 문지르거나 누르지 않습니다.", + "en": "Do not rub or press the treated area." + }, + "no-massage-2w": { + "ko": "시술 부위 마사지와 강한 압박은 약 2주 피합니다.", + "en": "Avoid massage or firm pressure on the treated area for about 2 weeks." + }, + "no-massage-4w": { + "ko": "얼굴 마사지와 강한 압박은 약 4주 피합니다.", + "en": "Avoid facial massage or firm pressure for about 4 weeks." + }, + "no-lie-4h": { + "ko": "시술 후 몇 시간은 눕지 않고 고개를 세웁니다.", + "en": "Stay upright for a few hours after the procedure." + }, + "no-sauna-3d": { + "ko": "사우나, 찜질방, 격한 운동은 약 3일 피합니다.", + "en": "No sauna, spa or intense exercise for about 3 days." + }, + "no-sauna-7d": { + "ko": "사우나, 찜질방, 수영은 약 1주 피합니다.", + "en": "No sauna, spa or swimming for about 1 week." + }, + "no-sauna-2w": { + "ko": "사우나, 찜질방, 격한 운동은 약 2주 피합니다.", + "en": "No sauna, spa or intense exercise for about 2 weeks." + }, + "no-scrub": { + "ko": "각질 제거와 스크럽은 담당 원장이 허용할 때까지 하지 않습니다.", + "en": "No exfoliation or scrubs until your doctor allows." + }, + "no-scratch": { + "ko": "가려워도 긁지 않고 딱지를 떼지 않습니다.", + "en": "Do not scratch or pick at scabs." + }, + "no-wide-mouth": { + "ko": "입을 크게 벌리는 동작과 딱딱한 음식은 약 2주 피합니다.", + "en": "Avoid opening the mouth wide and hard foods for about 2 weeks." + }, + "sleep-elevated": { + "ko": "머리를 심장보다 높게 하고 정면 자세로 잡니다.", + "en": "Sleep with your head above heart level, facing up." + } + }, + "procedures": [ + { + "id": "skinbooster", + "label": { + "ko": "물광주사·스킨부스터", + "en": "Skin Booster Injection" + }, + "group": { + "ko": "주사", + "en": "Injection" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "실밥 없음", + "en": "No stitches" + }, + "display": { + "ko": "해당 없음", + "en": "Not applicable" + } + }, + "earliestDepartureDay": { + "value": 3, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 4, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-makeup-1d" + ], + "sources": [], + "matchKeywords": "물광|스킨부스터|리쥬란|쥬베룩|부스터" + }, + { + "id": "filler", + "label": { + "ko": "필러", + "en": "Filler" + }, + "group": { + "ko": "주사", + "en": "Injection" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "display": { + "ko": "해당 없음", + "en": "Not applicable" + } + }, + "earliestDepartureDay": { + "value": 3, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-massage-2w", + "no-sauna-3d", + "no-sun" + ], + "sources": [], + "matchKeywords": "필러" + }, + { + "id": "botox", + "label": { + "ko": "보톡스", + "en": "Botulinum Toxin" + }, + "group": { + "ko": "주사", + "en": "Injection" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "display": { + "ko": "해당 없음", + "en": "Not applicable" + } + }, + "earliestDepartureDay": { + "value": 1, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-lie-4h", + "no-massage-1d", + "no-sauna-3d" + ], + "sources": [], + "matchKeywords": "보톡스|톡신" + }, + { + "id": "toning", + "label": { + "ko": "레이저 토닝·색소", + "en": "Laser Toning / Pigment" + }, + "group": { + "ko": "레이저", + "en": "Laser" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "display": { + "ko": "해당 없음", + "en": "Not applicable" + } + }, + "earliestDepartureDay": { + "value": 2, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-scrub", + "no-sauna-3d", + "no-makeup-1d" + ], + "sources": [], + "matchKeywords": "토닝|색소|기미|잡티|레이저" + }, + { + "id": "lifting", + "label": { + "ko": "에너지 리프팅(고주파·초음파)", + "en": "Energy Lifting (RF / Ultrasound)" + }, + "group": { + "ko": "리프팅", + "en": "Lifting" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "display": { + "ko": "해당 없음", + "en": "Not applicable" + } + }, + "earliestDepartureDay": { + "value": 2, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sauna-3d", + "no-sun", + "no-massage-2w" + ], + "sources": [], + "matchKeywords": "리프팅|울쎄라|써마지|인모드|슈링크|고주파|초음파|탄력" + }, + { + "id": "thread", + "label": { + "ko": "실리프팅", + "en": "Thread Lift" + }, + "group": { + "ko": "리프팅", + "en": "Lifting" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 10, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-wide-mouth", + "no-massage-4w", + "sleep-elevated", + "no-sauna-2w" + ], + "sources": [], + "matchKeywords": "실리프팅|실 리프팅|민트" + }, + { + "id": "acne", + "label": { + "ko": "여드름·흉터 레이저", + "en": "Acne / Scar Laser" + }, + "group": { + "ko": "레이저", + "en": "Laser" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "display": { + "ko": "해당 없음", + "en": "Not applicable" + } + }, + "earliestDepartureDay": { + "value": 5, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-makeup-3d", + "no-scratch", + "no-sauna-7d" + ], + "sources": [], + "matchKeywords": "여드름|흉터|프락셀|모공" + }, + { + "id": "body", + "label": { + "ko": "비만·바디 시술", + "en": "Body Contouring" + }, + "group": { + "ko": "바디", + "en": "Body" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "display": { + "ko": "해당 없음", + "en": "Not applicable" + } + }, + "earliestDepartureDay": { + "value": 1, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sauna-3d" + ], + "sources": [], + "matchKeywords": "비만|바디|지방분해|파워쉐이프|쿨스컬프팅|체형" + } + ], + "nationalities": { + "_comment": "무비자 체류 한도(일). 2026-09 기준 확인 필요. null 은 사전 비자 필요. 화면은 항상 대한민국 비자포털 링크와 함께 보여준다.", + "portal": "https://www.visa.go.kr", + "list": [ + { + "code": "US", + "label": { + "ko": "미국", + "en": "United States" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "CA", + "label": { + "ko": "캐나다", + "en": "Canada" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "GB", + "label": { + "ko": "영국", + "en": "United Kingdom" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "AU", + "label": { + "ko": "호주", + "en": "Australia" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "JP", + "label": { + "ko": "일본", + "en": "Japan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TW", + "label": { + "ko": "대만", + "en": "Taiwan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "HK", + "label": { + "ko": "홍콩", + "en": "Hong Kong" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "SG", + "label": { + "ko": "싱가포르", + "en": "Singapore" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TH", + "label": { + "ko": "태국", + "en": "Thailand" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "MY", + "label": { + "ko": "말레이시아", + "en": "Malaysia" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "AE", + "label": { + "ko": "아랍에미리트", + "en": "United Arab Emirates" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "RU", + "label": { + "ko": "러시아", + "en": "Russia" + }, + "visaFreeDays": 60, + "longHaul": true + }, + { + "code": "KZ", + "label": { + "ko": "카자흐스탄", + "en": "Kazakhstan" + }, + "visaFreeDays": 30, + "longHaul": true + }, + { + "code": "CN", + "label": { + "ko": "중국", + "en": "China" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "VN", + "label": { + "ko": "베트남", + "en": "Vietnam" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "ID", + "label": { + "ko": "인도네시아", + "en": "Indonesia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "PH", + "label": { + "ko": "필리핀", + "en": "Philippines" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "MN", + "label": { + "ko": "몽골", + "en": "Mongolia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "OTHER", + "label": { + "ko": "그 외", + "en": "Other" + }, + "visaFreeDays": null, + "longHaul": true + } + ] + } +} diff --git a/supporters/scripts/template/planner/procedures.plastic.json b/supporters/scripts/template/planner/procedures.plastic.json new file mode 100644 index 0000000..ac95bc8 --- /dev/null +++ b/supporters/scripts/template/planner/procedures.plastic.json @@ -0,0 +1,961 @@ +{ + "_comment": "성형외과 기본 규칙표 (뷰성형외과 샘플에서 정리). 워커 planner 단계(scripts/build_planner_data.mjs)가 병원 시술 페이지 원문(recoveryNotes.json)을 matchKeywords 로 시술에 붙여 병원별 procedures.json 을 만든다. clinic 출처가 있는 값은 뷰성형외과 공개 안내이므로 다른 병원에서는 provisional 로 내려간다.", + "clinicSources": [], + "levels": [ + { + "level": 0, + "label": { + "ko": "실내 안정", + "en": "Rest indoors" + }, + "desc": { + "ko": "병실이나 호텔에서 쉬는 날입니다. 필요한 것은 배달과 룸서비스로 해결합니다.", + "en": "Rest at the hospital or hotel. Use delivery and room service." + } + }, + { + "level": 1, + "label": { + "ko": "근거리 외출", + "en": "Short walks" + }, + "desc": { + "ko": "호텔 반경 500m 안에서 짧게 다녀옵니다. 도보 10분 이내.", + "en": "Short trips within 500 m of your hotel. Up to a 10-minute walk." + } + }, + { + "level": 2, + "label": { + "ko": "반나절 외출", + "en": "Half-day outing" + }, + "desc": { + "ko": "택시로 반경 3km 안 쇼핑·식사·가벼운 관광이 가능합니다.", + "en": "Shopping, dining and light sightseeing within 3 km by taxi." + } + }, + { + "level": 3, + "label": { + "ko": "자유 외출", + "en": "Full day out" + }, + "desc": { + "ko": "하루 단위 외출이 가능합니다. 시내 관광, 행사, 인파가 있는 곳도 담당 원장 안내 안에서 가능합니다.", + "en": "Full-day outings. City sightseeing and events, within your surgeon's guidance." + } + } + ], + "diets": { + "liquid": { + "label": { + "ko": "유동식", + "en": "Liquid diet" + }, + "desc": { + "ko": "건더기 없는 유동식만 드십니다.", + "en": "Liquids only, no solids." + } + }, + "soft": { + "label": { + "ko": "부드러운 음식", + "en": "Soft foods" + }, + "desc": { + "ko": "건더기가 있어도 부드러운 음식까지 가능합니다.", + "en": "Soft foods are fine. Avoid anything chewy or hard." + } + }, + "mild": { + "label": { + "ko": "자극 없는 일반식", + "en": "Regular, non-spicy" + }, + "desc": { + "ko": "맵고 짜거나 딱딱한 음식은 피합니다.", + "en": "Regular meals. Avoid spicy, salty or hard foods." + } + }, + "normal": { + "label": { + "ko": "일반식", + "en": "Regular diet" + }, + "desc": { + "ko": "식사 제한이 없습니다.", + "en": "No dietary restrictions." + } + } + }, + "constraints": { + "no-heavy-lifting": { + "ko": "무거운 짐과 팔을 많이 쓰는 동작을 피합니다. 쇼핑은 배송 서비스를 이용하세요.", + "en": "Avoid heavy bags and arm-heavy movement. Use delivery for shopping." + }, + "sports-bra": { + "ko": "스포츠브라를 1~3개월 유지합니다.", + "en": "Wear a sports bra for 1 to 3 months." + }, + "no-alcohol-30d": { + "ko": "음주와 흡연은 최소 1개월 이후입니다.", + "en": "No alcohol or smoking for at least 1 month." + }, + "no-sauna-60d": { + "ko": "사우나, 찜질방, 수영, 과한 운동은 약 2개월 후입니다.", + "en": "No sauna, spa, swimming or intense exercise for about 2 months." + }, + "compression-band": { + "ko": "압박밴드를 2~4주 착용합니다. 취침 시에는 하지 않습니다.", + "en": "Wear the compression band for 2 to 4 weeks, not while sleeping." + }, + "sleep-elevated": { + "ko": "머리를 심장보다 높게 하고 정면 자세로 잡니다. 1주 후부터 옆으로 누워도 됩니다.", + "en": "Sleep with your head above heart level, facing up. Side sleeping from week 2." + }, + "saline-gargle": { + "ko": "약 1개월간 생리식염수 가글을 꾸준히 합니다.", + "en": "Rinse with saline regularly for about 1 month." + }, + "no-hard-food-30d": { + "ko": "질기고 딱딱한 음식은 한 달간 피합니다.", + "en": "Avoid chewy or hard food for 1 month." + }, + "no-sun": { + "ko": "직사광선을 피합니다. 모자와 선글라스를 챙기세요.", + "en": "Avoid direct sun. Bring a hat and sunglasses." + }, + "mask": { + "ko": "외출 시 마스크를 쓰면 부기와 멍이 덜 보입니다.", + "en": "A mask helps cover swelling and bruising when out." + }, + "no-glasses": { + "ko": "안경 착용을 피합니다. 콘택트렌즈나 안경 없이 다닐 계획을 세우세요.", + "en": "Avoid glasses resting on your nose. Plan for contacts or going without." + }, + "no-lens": { + "ko": "콘택트렌즈는 담당 원장이 허용할 때까지 쓰지 않습니다.", + "en": "No contact lenses until your surgeon allows." + }, + "cold-compress": { + "ko": "초기에는 냉찜질, 이후 온찜질을 합니다.", + "en": "Cold compresses at first, then warm." + }, + "no-nose-blow": { + "ko": "코를 세게 풀거나 코 부위에 압력을 주지 않습니다.", + "en": "Do not blow your nose or press on the nose area." + }, + "no-massage": { + "ko": "수술 부위 마사지와 강한 압박을 피합니다.", + "en": "No massage or firm pressure on the surgical area." + }, + "no-hat-pressure": { + "ko": "이식 부위를 누르는 모자나 헬멧을 피합니다.", + "en": "Avoid hats or helmets that press on the graft area." + }, + "no-scratch": { + "ko": "가려워도 긁지 않습니다.", + "en": "Do not scratch, even if itchy." + }, + "driving": { + "ko": "수술 당일은 운전할 수 없습니다. 보호자 동반을 권합니다.", + "en": "No driving on surgery day. A companion is recommended." + } + }, + "procedures": [ + { + "id": "breast", + "label": { + "ko": "가슴성형", + "en": "Breast Augmentation" + }, + "group": { + "ko": "가슴", + "en": "Breast" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "검진과 상담 1일, 여유 1일", + "en": "1 day for tests and consultation, 1 buffer day" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 10 + ], + "status": "provisional", + "note": { + "ko": "실밥이 있으면 약 1주에 제거. 피부 접착제를 쓴 경우 실밥 없음", + "en": "Stitches, if any, removed at about 1 week. No stitches if skin adhesive was used" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional", + "note": { + "ko": "부기는 2~3일째 가장 심합니다", + "en": "Swelling peaks on days 2 to 3" + } + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional", + "note": { + "ko": "3일 이후 붕대를 뗍니다", + "en": "Bandage removed after day 3" + } + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "no-heavy-lifting", + "sports-bra", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "가슴|유방|보형물|모티바" + }, + { + "id": "contour", + "label": { + "ko": "안면윤곽·양악", + "en": "Facial Contouring / Jaw Surgery" + }, + "group": { + "ko": "얼굴뼈", + "en": "Facial bone" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "3D-CT 촬영과 검진, 상담", + "en": "3D-CT, tests and consultation" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "입안 실은 녹는 실이라 보통 한 달 후 저절로 없어집니다. 별도 제거 방문 없음", + "en": "Intraoral stitches dissolve on their own in about a month. No removal visit" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 14, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional", + "note": { + "ko": "부기는 3~4일까지 늘다가 가라앉습니다", + "en": "Swelling increases until day 3 to 4, then subsides" + } + }, + { + "fromDay": 5, + "level": 1, + "status": "provisional", + "note": { + "ko": "5~7일 후 일상생활이 가능합니다", + "en": "Daily activities possible after day 5 to 7" + } + }, + { + "fromDay": 10, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 21, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "liquid", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 14, + "type": "mild", + "status": "provisional" + }, + { + "fromDay": 30, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "compression-band", + "sleep-elevated", + "saline-gargle", + "no-hard-food-30d", + "no-alcohol-30d", + "no-sauna-60d", + "no-massage" + ], + "sources": [], + "matchKeywords": "윤곽|양악|사각턱|광대|턱끝|무턱|주걱턱" + }, + { + "id": "eye", + "label": { + "ko": "눈성형", + "en": "Eyelid Surgery" + }, + "group": { + "ko": "눈", + "en": "Eyes" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 6, + "range": [ + 5, + 7 + ], + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 10, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "cold-compress", + "no-sun", + "no-lens", + "no-scratch", + "no-alcohol-30d" + ], + "sources": [], + "matchKeywords": "눈|쌍꺼풀|매몰|절개|트임|눈매" + }, + { + "id": "nose", + "label": { + "ko": "코성형", + "en": "Rhinoplasty" + }, + "group": { + "ko": "코", + "en": "Nose" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 7 + ], + "status": "provisional", + "note": { + "ko": "부목과 실밥 제거", + "en": "Splint and stitch removal" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "mild", + "status": "provisional" + }, + { + "fromDay": 14, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-glasses", + "no-nose-blow", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "코|비중격|콧" + }, + { + "id": "fat", + "label": { + "ko": "지방성형", + "en": "Liposuction / Fat Grafting" + }, + "group": { + "ko": "지방", + "en": "Fat" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "compression-band", + "no-massage", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "지방|흡입|바디" + }, + { + "id": "lifting", + "label": { + "ko": "안티에이징·리프팅", + "en": "Anti-aging / Face Lift" + }, + "group": { + "ko": "리프팅", + "en": "Lifting" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-massage", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "리프팅|거상|주름|안티에이징" + }, + { + "id": "skin", + "label": { + "ko": "피부과 시술", + "en": "Dermatology Treatment" + }, + "group": { + "ko": "피부", + "en": "Skin" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "실밥 없음", + "en": "No stitches" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 2, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "피부|레이저|보톡스|필러|토닝|색소" + }, + { + "id": "hair", + "label": { + "ko": "모발이식", + "en": "Hair Transplant" + }, + "group": { + "ko": "모발", + "en": "Hair" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "채취 방식에 따라 다릅니다", + "en": "Depends on the harvesting method" + } + }, + "earliestDepartureDay": { + "value": 3, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-hat-pressure", + "no-scratch", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "모발|탈모" + } + ], + "nationalities": { + "_comment": "무비자 체류 한도(일). 2026-09 기준 확인 필요. null 은 사전 비자 필요. 화면은 항상 대한민국 비자포털 링크와 함께 보여준다.", + "portal": "https://www.visa.go.kr", + "list": [ + { + "code": "US", + "label": { + "ko": "미국", + "en": "United States" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "CA", + "label": { + "ko": "캐나다", + "en": "Canada" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "GB", + "label": { + "ko": "영국", + "en": "United Kingdom" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "AU", + "label": { + "ko": "호주", + "en": "Australia" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "JP", + "label": { + "ko": "일본", + "en": "Japan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TW", + "label": { + "ko": "대만", + "en": "Taiwan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "HK", + "label": { + "ko": "홍콩", + "en": "Hong Kong" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "SG", + "label": { + "ko": "싱가포르", + "en": "Singapore" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TH", + "label": { + "ko": "태국", + "en": "Thailand" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "MY", + "label": { + "ko": "말레이시아", + "en": "Malaysia" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "AE", + "label": { + "ko": "아랍에미리트", + "en": "United Arab Emirates" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "RU", + "label": { + "ko": "러시아", + "en": "Russia" + }, + "visaFreeDays": 60, + "longHaul": true + }, + { + "code": "KZ", + "label": { + "ko": "카자흐스탄", + "en": "Kazakhstan" + }, + "visaFreeDays": 30, + "longHaul": true + }, + { + "code": "CN", + "label": { + "ko": "중국", + "en": "China" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "VN", + "label": { + "ko": "베트남", + "en": "Vietnam" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "ID", + "label": { + "ko": "인도네시아", + "en": "Indonesia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "PH", + "label": { + "ko": "필리핀", + "en": "Philippines" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "MN", + "label": { + "ko": "몽골", + "en": "Mongolia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "OTHER", + "label": { + "ko": "그 외", + "en": "Other" + }, + "visaFreeDays": null, + "longHaul": true + } + ] + } +} diff --git a/supporters/src/components/Planner.astro b/supporters/src/components/Planner.astro new file mode 100644 index 0000000..8c3fba6 --- /dev/null +++ b/supporters/src/components/Planner.astro @@ -0,0 +1,313 @@ +--- +// 회복기 스케줄러 본문 (설계 v0.2 §13). /plan(한국어)과 /en/plan(영어)이 같은 컴포넌트를 lang 만 바꿔 쓴다. +// 구성은 홈·영상 페이지와 같은 섹션 리듬이다: 다크 히어로(글래스 통계) → 틴트(입력 카드) → 다크(핵심 날짜) → 라이트(확인·규칙) → 틴트(타임라인) → 다크(예약). +// 건강정보(시술·수술일)는 서버로 보내지 않는다. 상태는 URL 해시로만 공유하고, 언어 전환은 해시를 들고 다른 언어 페이지로 이동한다. +import '../styles/plan.css'; +import strings from '../data/planStrings.json'; +import P from '../data/procedures.json'; +import PL from '../data/places.json'; +import TKO from '../data/medicalTourismKo.json'; +import TEN from '../data/medicalTourism.json'; +import { tourToPlaces } from '../lib/tour'; +interface Props { lang: 'ko' | 'en' } +const { lang } = Astro.props; +const t = strings[lang]; +const tour = tourToPlaces((lang === 'en' ? TEN : TKO) as any, lang); +const nProcs = P.procedures.length; +const nPlaces = PL.places.filter((x) => x.category !== 'hotel').length + tour.filter((x) => x.category !== 'hotel').length; +const nHotels = PL.places.filter((x) => x.category === 'hotel').length + tour.filter((x) => x.category === 'hotel').length; +const procList = (P.procedures as any[]).map((x) => x.label[lang]).join(lang === 'ko' ? '·' : ', '); +const originLabel = (PL as any).origin?.label?.[lang] ?? ''; +--- +
+
+
+
{t.eyebrow}
+

{t.h_hero}

+

{t.title} {t.lede}

+
+
+
{nProcs}{t.stat_procs}{procList}
+
{nPlaces}{t.stat_places}{t.stat_places_d.replace('{origin}', originLabel)}
+
{nHotels}{t.stat_hotels}{t.stat_hotels_d}
+
0{t.stat_privacy}{t.stat_privacy_d}
+
+
+
+
+
+
+
+ + + diff --git a/supporters/src/data/places.json b/supporters/src/data/places.json new file mode 100644 index 0000000..bbf62d5 --- /dev/null +++ b/supporters/src/data/places.json @@ -0,0 +1,47 @@ +{ + "_comment": "회복기 스케줄러 큐레이션 장소 (설계 v0.2 §13.5 1순위 소스). 기준점은 신논현역(뷰성형외과). distanceKm 는 직선 거리 근사값이고 verify 가 true 인 항목은 출시 전 영업 여부·거리를 확인한다. 링크는 구글 지도 검색과 예약 사이트 검색 결과만 쓴다(지어낸 상세 URL 없음). 축제·행사(날짜 의존)는 한국관광공사 Tour API 연결(P1) 뒤에 추가한다.", + "origin": { "label": { "ko": "신논현역 3번 출구", "en": "Sinnonhyeon Station Exit 3" }, "lat": 37.5045, "lng": 127.0250 }, + "categories": { + "sightseeing": { "ko": "관광", "en": "Sightseeing" }, + "shopping": { "ko": "쇼핑", "en": "Shopping" }, + "food": { "ko": "미식", "en": "Food" }, + "kpop": { "ko": "K-pop·핫플", "en": "K-pop & hotspots" }, + "care": { "ko": "휴식·케어", "en": "Rest & care" }, + "essentials": { "ko": "생활", "en": "Essentials" }, + "hotel": { "ko": "숙소", "en": "Hotels" } + }, + "places": [ + { "id": "pharmacy-sinnonhyeon", "name": { "ko": "신논현역 주변 약국", "en": "Pharmacies near Sinnonhyeon Station" }, "category": "essentials", "minLevel": 1, "distanceKm": 0.2, "indoor": true, "area": { "ko": "신논현", "en": "Sinnonhyeon" }, "note": { "ko": "병원 건물 옆 골목에 약국이 있습니다. 처방약과 냉찜질 팩을 구할 수 있습니다.", "en": "Pharmacies in the alley next to the clinic building. Prescriptions and cold packs." }, "mapQuery": "약국 신논현역", "verify": true }, + { "id": "convenience-sinnonhyeon", "name": { "ko": "편의점 (신논현역 일대)", "en": "Convenience stores (Sinnonhyeon area)" }, "category": "essentials", "minLevel": 1, "distanceKm": 0.1, "indoor": true, "area": { "ko": "신논현", "en": "Sinnonhyeon" }, "note": { "ko": "생수, 죽, 빨대, 얼음을 24시간 살 수 있습니다.", "en": "Water, porridge, straws and ice, 24 hours." }, "mapQuery": "편의점 신논현역", "verify": false }, + { "id": "porridge-chain", "name": { "ko": "죽 전문점 (본죽 등 체인)", "en": "Korean porridge (Bonjuk and similar chains)" }, "category": "food", "minLevel": 1, "dietOk": ["liquid", "soft", "mild", "normal"], "distanceKm": 0.4, "indoor": true, "area": { "ko": "신논현·강남", "en": "Sinnonhyeon / Gangnam" }, "note": { "ko": "유동식 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", "en": "Porridge suitable for the liquid-diet stage, by delivery or takeout." }, "mapQuery": "본죽 신논현역", "verify": true }, + { "id": "smoothie-cafe", "name": { "ko": "스무디·주스 카페 (강남대로)", "en": "Smoothie and juice cafes (Gangnam-daero)" }, "category": "food", "minLevel": 1, "dietOk": ["liquid", "soft", "mild", "normal"], "distanceKm": 0.5, "indoor": true, "area": { "ko": "강남대로", "en": "Gangnam-daero" }, "note": { "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", "en": "Plenty of straw-friendly options. Choose nothing hot." }, "mapQuery": "스무디 카페 신논현역", "verify": true }, + { "id": "seolleongtang", "name": { "ko": "설렁탕·곰탕 (강남 일대)", "en": "Seolleongtang beef bone soup (Gangnam area)" }, "category": "food", "minLevel": 1, "dietOk": ["soft", "mild", "normal"], "distanceKm": 0.6, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다. 밥을 말아 천천히 드세요.", "en": "Broth-based, fine from the soft-food stage. Eat slowly with rice in the soup." }, "mapQuery": "설렁탕 강남역", "verify": true }, + { "id": "sulbing", "name": { "ko": "설빙 (빙수 디저트)", "en": "Sulbing shaved-ice dessert" }, "category": "food", "minLevel": 1, "dietOk": ["soft", "mild", "normal"], "distanceKm": 0.6, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "차갑고 부드러워 부기가 있을 때도 먹기 편합니다.", "en": "Cold and soft, comfortable even with swelling." }, "mapQuery": "설빙 강남", "verify": true }, + { "id": "cafe-garosugil", "name": { "ko": "가로수길 카페", "en": "Garosu-gil cafes" }, "category": "food", "minLevel": 2, "dietOk": ["soft", "mild", "normal"], "distanceKm": 1.2, "indoor": true, "area": { "ko": "신사동 가로수길", "en": "Garosu-gil, Sinsa" }, "note": { "ko": "조용한 카페가 많아 오후에 잠깐 앉아 있기 좋습니다.", "en": "Quiet cafes, good for a short afternoon sit-down." }, "mapQuery": "가로수길 카페", "verify": false }, + { "id": "korean-bbq-gangnam", "name": { "ko": "강남 한식·구이", "en": "Korean BBQ and set meals (Gangnam)" }, "category": "food", "minLevel": 2, "dietOk": ["normal"], "distanceKm": 0.8, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "일반식이 가능한 단계부터입니다. 담당 원장이 술을 허용하기 전에는 음료로 대신하세요.", "en": "From the regular-diet stage. Skip alcohol until your surgeon allows it." }, "mapQuery": "한식 맛집 강남역", "verify": false }, + { "id": "garosugil", "name": { "ko": "가로수길", "en": "Garosu-gil" }, "category": "shopping", "minLevel": 2, "distanceKm": 1.2, "indoor": false, "area": { "ko": "신사동", "en": "Sinsa" }, "note": { "ko": "편집숍과 뷰티 매장이 모여 있는 거리입니다. 택시로 5분.", "en": "A street of boutiques and beauty stores. 5 minutes by taxi." }, "mapQuery": "가로수길", "verify": false }, + { "id": "oliveyoung-gangnam", "name": { "ko": "올리브영 강남 타운", "en": "Olive Young Gangnam Town" }, "category": "shopping", "minLevel": 2, "distanceKm": 0.9, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "K-뷰티 대형 매장입니다. 수술 부위에 닿는 화장품은 담당 원장 안내를 따르세요.", "en": "Large K-beauty store. Follow your surgeon's guidance on products near the surgical area." }, "mapQuery": "올리브영 강남타운", "verify": true }, + { "id": "shinsegae-gangnam", "name": { "ko": "신세계백화점 강남점", "en": "Shinsegae Department Store Gangnam" }, "category": "shopping", "minLevel": 2, "distanceKm": 2.4, "indoor": true, "area": { "ko": "고속터미널", "en": "Express Bus Terminal" }, "note": { "ko": "지하 파미에스테이션과 연결됩니다. 실내라 날씨와 상관없이 다닐 수 있습니다.", "en": "Connected to the Famille Station underground mall. Fully indoors." }, "mapQuery": "신세계백화점 강남점", "verify": false }, + { "id": "hyundai-apgujeong", "name": { "ko": "현대백화점 압구정본점", "en": "Hyundai Department Store Apgujeong" }, "category": "shopping", "minLevel": 2, "distanceKm": 2.0, "indoor": true, "area": { "ko": "압구정", "en": "Apgujeong" }, "note": { "ko": "택시로 10분. 배송 서비스를 이용하면 짐을 들지 않아도 됩니다.", "en": "10 minutes by taxi. Use the delivery counter so you carry nothing." }, "mapQuery": "현대백화점 압구정본점", "verify": false }, + { "id": "coex-mall", "name": { "ko": "코엑스몰·별마당도서관", "en": "COEX Mall and Starfield Library" }, "category": "shopping", "minLevel": 2, "distanceKm": 3.4, "indoor": true, "area": { "ko": "삼성동", "en": "Samseong" }, "note": { "ko": "실내 쇼핑몰과 도서관, 아쿠아리움이 한 건물에 있습니다.", "en": "Indoor mall, library and aquarium in one building." }, "mapQuery": "코엑스몰", "verify": false }, + { "id": "apgujeong-rodeo", "name": { "ko": "압구정 로데오·K-Star Road", "en": "Apgujeong Rodeo and K-Star Road" }, "category": "kpop", "minLevel": 2, "distanceKm": 2.6, "indoor": false, "area": { "ko": "압구정", "en": "Apgujeong" }, "note": { "ko": "기획사 건물과 아이돌 조형물이 있는 거리입니다.", "en": "Street of entertainment agencies and idol art figures." }, "mapQuery": "K-Star Road 압구정", "verify": true }, + { "id": "kwangya-seongsu", "name": { "ko": "KWANGYA@SEOUL (성수)", "en": "KWANGYA@SEOUL (Seongsu)" }, "category": "kpop", "minLevel": 3, "distanceKm": 5.5, "indoor": true, "area": { "ko": "성수동", "en": "Seongsu" }, "note": { "ko": "SM 엔터테인먼트 공식 굿즈 매장입니다. 운영 시간을 확인하고 가세요.", "en": "SM Entertainment's official merchandise store. Check hours before visiting." }, "mapQuery": "KWANGYA@SEOUL", "verify": true }, + { "id": "seongsu", "name": { "ko": "성수동 카페·팝업", "en": "Seongsu cafes and pop-ups" }, "category": "kpop", "minLevel": 3, "distanceKm": 5.5, "indoor": false, "area": { "ko": "성수동", "en": "Seongsu" }, "note": { "ko": "브랜드 팝업과 카페가 모인 동네입니다. 주말은 인파가 많습니다.", "en": "Brand pop-ups and cafes. Crowded on weekends." }, "mapQuery": "성수동 팝업", "verify": false }, + { "id": "hongdae", "name": { "ko": "홍대", "en": "Hongdae" }, "category": "kpop", "minLevel": 3, "distanceKm": 11, "indoor": false, "area": { "ko": "홍대입구", "en": "Hongik Univ." }, "note": { "ko": "버스킹과 굿즈숍이 있습니다. 왕복 1시간 이상 걸리니 자유 외출 단계에서 가세요.", "en": "Busking and merch shops. Over an hour round trip, so save it for full-day outings." }, "mapQuery": "홍대 걷고싶은거리", "verify": false }, + { "id": "kakao-friends-gangnam", "name": { "ko": "카카오프렌즈 강남 플래그십", "en": "Kakao Friends Gangnam Flagship" }, "category": "kpop", "minLevel": 2, "distanceKm": 0.9, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "캐릭터 굿즈 매장입니다. 걸어서도 갈 수 있는 거리입니다.", "en": "Character merchandise store, within walking distance." }, "mapQuery": "카카오프렌즈 강남플래그십스토어", "verify": true }, + { "id": "bongeunsa", "name": { "ko": "봉은사", "en": "Bongeunsa Temple" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 3.6, "indoor": false, "area": { "ko": "삼성동", "en": "Samseong" }, "note": { "ko": "코엑스 맞은편의 사찰입니다. 경사가 완만해 천천히 걷기 좋습니다.", "en": "Temple across from COEX. Gentle slopes, good for a slow walk." }, "mapQuery": "봉은사", "verify": false }, + { "id": "seonjeongneung", "name": { "ko": "선정릉", "en": "Seonjeongneung Royal Tombs" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 2.4, "indoor": false, "area": { "ko": "선릉", "en": "Seolleung" }, "note": { "ko": "유네스코 세계유산 왕릉입니다. 숲길이 그늘져서 햇빛을 피하기 좋습니다.", "en": "UNESCO World Heritage royal tombs. Shaded forest paths." }, "mapQuery": "선정릉", "verify": false }, + { "id": "banpo-hangang", "name": { "ko": "반포한강공원·달빛무지개분수", "en": "Banpo Hangang Park and Moonlight Rainbow Fountain" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 2.8, "indoor": false, "area": { "ko": "반포", "en": "Banpo" }, "note": { "ko": "저녁에 분수 공연을 볼 수 있습니다. 운영 기간을 확인하세요.", "en": "Evening fountain show. Check the season schedule." }, "mapQuery": "반포한강공원", "verify": false }, + { "id": "gyeongbokgung", "name": { "ko": "경복궁·북촌", "en": "Gyeongbokgung Palace and Bukchon" }, "category": "sightseeing", "minLevel": 3, "distanceKm": 9, "indoor": false, "area": { "ko": "종로", "en": "Jongno" }, "note": { "ko": "택시로 30분 이상 걸립니다. 걷는 시간이 길어 자유 외출 단계에서 가세요.", "en": "Over 30 minutes by taxi and a lot of walking. Save for full-day outings." }, "mapQuery": "경복궁", "verify": false }, + { "id": "lotte-tower", "name": { "ko": "롯데월드타워·서울스카이", "en": "Lotte World Tower and Seoul Sky" }, "category": "sightseeing", "minLevel": 3, "distanceKm": 8, "indoor": true, "area": { "ko": "잠실", "en": "Jamsil" }, "note": { "ko": "실내 전망대와 쇼핑몰입니다. 택시로 25분.", "en": "Indoor observatory and mall. 25 minutes by taxi." }, "mapQuery": "롯데월드타워", "verify": false }, + { "id": "myeongdong", "name": { "ko": "명동", "en": "Myeongdong" }, "category": "shopping", "minLevel": 3, "distanceKm": 7, "indoor": false, "area": { "ko": "중구", "en": "Jung-gu" }, "note": { "ko": "화장품과 길거리 음식이 많습니다. 인파가 많으니 부딪히지 않게 다니세요.", "en": "Cosmetics and street food. Crowded, so mind bumps." }, "mapQuery": "명동", "verify": false }, + { "id": "clinic-aftercare", "name": { "ko": "뷰성형외과 애프터케어", "en": "View Plastic Surgery Aftercare" }, "category": "care", "minLevel": 1, "distanceKm": 0.05, "indoor": true, "area": { "ko": "병원", "en": "Clinic" }, "note": { "ko": "고주파 관리와 경과 확인은 병원 안내에 따라 예약합니다.", "en": "Radiofrequency care and follow-up checks, booked per the clinic's guidance." }, "mapQuery": "뷰성형외과", "verify": false }, + { "id": "clinic-dental", "name": { "ko": "뷰성형외과 15층 치과", "en": "View Plastic Surgery Dental Clinic (15F)" }, "category": "care", "minLevel": 1, "distanceKm": 0.05, "indoor": true, "area": { "ko": "병원", "en": "Clinic" }, "note": { "ko": "양악·윤곽 협진 치과입니다. 여유 시간에 검진을 받을 수 있는지 상담에서 물어보세요.", "en": "Dental clinic for jaw and contouring cases. Ask at consultation about a check-up during your stay." }, "mapQuery": "뷰성형외과", "verify": false }, + { "id": "hotel-spa-gangnam", "name": { "ko": "호텔 스파·라운지 (숙소 안)", "en": "Hotel spa and lounge (at your hotel)" }, "category": "care", "minLevel": 0, "distanceKm": 0, "indoor": true, "area": { "ko": "숙소", "en": "Your hotel" }, "note": { "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", "en": "Skip sauna and massage until your surgeon allows. Lounge and room service are fine." }, "mapQuery": null, "verify": false }, + { "id": "hotel-cappuccino", "name": { "ko": "호텔 카푸치노", "en": "Hotel Cappuccino" }, "category": "hotel", "minLevel": 0, "distanceKm": 0.5, "indoor": true, "area": { "ko": "논현동 봉은사로", "en": "Nonhyeon, Bongeunsa-ro" }, "note": { "ko": "병원과 같은 봉은사로에 있어 걸어서 다닐 수 있습니다.", "en": "On the same road as the clinic, within walking distance." }, "mapQuery": "호텔 카푸치노 논현", "bookingQuery": "Hotel Cappuccino Seoul", "verify": true }, + { "id": "novotel-gangnam", "name": { "ko": "노보텔 앰배서더 강남", "en": "Novotel Ambassador Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.0, "indoor": true, "area": { "ko": "역삼동", "en": "Yeoksam" }, "note": { "ko": "강남역 근처 대형 호텔입니다. 룸서비스와 24시간 프런트가 있습니다.", "en": "Large hotel near Gangnam Station with room service and a 24-hour front desk." }, "mapQuery": "노보텔 앰배서더 강남", "bookingQuery": "Novotel Ambassador Seoul Gangnam", "verify": true }, + { "id": "l7-gangnam", "name": { "ko": "L7 강남 바이 롯데", "en": "L7 Gangnam by Lotte" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.4, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "강남역 인근이며 택시로 5분입니다.", "en": "Near Gangnam Station, 5 minutes by taxi." }, "mapQuery": "L7 강남", "bookingQuery": "L7 Gangnam by Lotte", "verify": true }, + { "id": "andaz-gangnam", "name": { "ko": "안다즈 서울 강남", "en": "Andaz Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 2.6, "indoor": true, "area": { "ko": "압구정 로데오", "en": "Apgujeong Rodeo" }, "note": { "ko": "압구정 로데오에 있는 고급 호텔입니다. 병원까지 택시로 10분.", "en": "Upscale hotel at Apgujeong Rodeo. 10 minutes to the clinic by taxi." }, "mapQuery": "안다즈 서울 강남", "bookingQuery": "Andaz Seoul Gangnam", "verify": true }, + { "id": "josun-palace", "name": { "ko": "조선 팰리스 강남", "en": "Josun Palace Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.8, "indoor": true, "area": { "ko": "역삼동", "en": "Yeoksam" }, "note": { "ko": "역삼동의 고급 호텔입니다. 병원까지 택시로 10분.", "en": "Luxury hotel in Yeoksam. 10 minutes to the clinic by taxi." }, "mapQuery": "조선 팰리스 서울 강남", "bookingQuery": "Josun Palace Seoul Gangnam", "verify": true } + ] +} diff --git a/supporters/src/data/planStrings.json b/supporters/src/data/planStrings.json new file mode 100644 index 0000000..f2d76fe --- /dev/null +++ b/supporters/src/data/planStrings.json @@ -0,0 +1,235 @@ +{ + "_comment": "회복기 스케줄러 UI 문자열. ko/en 두 언어. 일본어·중국어는 P1에서 같은 키로 추가한다. 고객 화면이므로 운영자 어휘를 쓰지 않는다.", + "ko": { + "eyebrow": "Recovery Planner", + "title": "수술일을 정하셨다면, 여행 일정은 여기서 짜세요.", + "lede": "시술과 수술일을 고르면 입국 권장일, 출국 가능 최소일, 회복기 동안 외출할 수 있는 날과 그날 갈 만한 곳을 정리해 드립니다. 계산은 이 화면 안에서만 이루어지고 어디에도 저장되지 않습니다.", + "step1": "국적", + "step2": "시술과 수술일", + "step3": "여유 시간에 하고 싶은 것", + "step4": "일정표", + "step5": "예약과 저장", + "lang": "언어", + "nationality": "국적", + "procedure": "시술", + "surgeryDate": "수술일", + "surgeryDateHint": "상담에서 확정한 날짜를 넣으세요. 아직 정하지 않았다면 예상일도 괜찮습니다.", + "prefs": "여러 개 고를 수 있습니다", + "pref_sightseeing": "관광", + "pref_shopping": "쇼핑", + "pref_food": "미식", + "pref_kpop": "K-pop·핫플", + "pref_care": "휴식·케어", + "generate": "일정표 만들기", + "arriveBy": "입국 권장일", + "surgery": "수술일", + "hospital": "입원", + "hospitalNights": "{n}박", + "hospitalNone": "당일 귀가", + "stitch": "실밥·부목 제거", + "departure": "출국 가능 최소일", + "stayNights": "총 체류", + "nights": "{n}박", + "pending": "확인", + "provisional": "병원 확인 전", + "clinicSourced": "병원 안내 기준", + "departureNote": "출국 가능 최소일은 최소 기준입니다. 담당 원장이 경과를 보고 다르게 안내할 수 있으니 항공권은 변경 가능한 조건으로 예약하세요.", + "dayBefore": "수술 {n}일 전", + "daySurgery": "수술 당일", + "dayAfter": "수술 후 {n}일", + "level": "외출", + "diet": "식사", + "picks": "추천", + "noPicks": "이 날은 쉬는 날입니다. 배달과 룸서비스를 이용하세요.", + "constraints": "회복기 동안 지킬 것", + "visaTitle": "체류 기간 확인", + "visaOk": "{country} 국적의 무비자 체류 한도는 {days}일이고 이 일정은 {stay}일입니다. 한도 안에 있습니다.", + "visaOver": "{country} 국적의 무비자 체류 한도는 {days}일인데 이 일정은 {stay}일입니다. 비자가 필요할 수 있으니 확인하세요.", + "visaRequired": "{country} 국적은 사전 비자가 필요할 수 있습니다. 출발 전 확인하세요.", + "visaVerify": "체류 한도는 2026년 9월 기준이며 바뀔 수 있습니다. 대한민국 비자포털에서 확인하세요.", + "visaPortal": "대한민국 비자포털", + "hotels": "병원 근처 숙소", + "hotelHint": "입국 권장일부터 출국 가능 최소일까지 날짜를 넣어 검색합니다. 엘리베이터, 룸서비스, 24시간 프런트가 있는 곳을 골랐습니다.", + "hotelSearch": "이 날짜로 검색", + "flights": "항공권", + "flightHint": "인천공항 도착 기준으로 날짜를 채워 검색합니다. 변경 가능한 요금을 권합니다.", + "flightSearch": "구글 항공권에서 보기", + "consult": "상담 예약", + "consultHint": "아래 일정 요약을 복사해 상담 신청 때 함께 보내면 병원이 회복 일정에 맞춰 안내할 수 있습니다.", + "copySummary": "일정 요약 복사", + "copied": "복사했습니다", + "shareLink": "링크 복사", + "ics": "캘린더에 저장", + "print": "인쇄", + "map": "지도", + "readMore": "회복 일정 자세히", + "affiliate": "숙소·항공 링크는 각 예약 사이트로 이동하며, 제휴 링크가 적용될 경우 이 매체가 소정의 수수료를 받을 수 있습니다. 예약 조건과 결제는 각 사이트의 안내를 따릅니다.", + "medical": "이 일정표는 병원 공개 안내를 바탕으로 한 일반 정보입니다. 본인 수술 범위와 경과에 따라 담당 원장의 지시가 우선합니다.", + "km": "{km}km", + "walk": "도보", + "taxi": "택시", + "indoor": "실내", + "summaryTitle": "회복 일정 요약", + "levelLabel": "외출 단계", + "sourceLabel": "근거", + "reset": "처음부터", + "provisionalNote": "\"병원 확인 전\"으로 표시된 값은 병원 공개 안내에 없어 일반 기준으로 넣은 잠정값입니다. 상담에서 본인 일정으로 확정하세요.", + "noRemoval": "제거 방문 없음", + "h_hero": "Plan Your Recovery Stay", + "h_step1": "Nationality", + "h_step2": "Procedure & Surgery Date", + "h_step3": "Your Free Time", + "h_step4": "Your Schedule", + "h_visa": "Length of Stay", + "h_rules": "During Recovery", + "h_days": "Day by Day", + "h_book": "Book & Save", + "h_hotels": "Hotels Near the Clinic", + "h_flights": "Flights", + "h_consult": "Consultation", + "h_input": "Build Your Schedule", + "sub_input": "세 가지만 고르면 일정표가 바로 나옵니다.", + "stat_procs": "시술", + "stat_places": "추천 장소", + "stat_places_d": "큐레이션과 한국관광공사 TourAPI. {origin} 기준 거리·이동 시간 표시", + "stat_hotels": "근처 숙소", + "stat_hotels_d": "병원 도보 10분 안, 엘리베이터·룸서비스·24시간 프런트", + "stat_privacy": "서버 저장", + "stat_privacy_d": "시술과 수술일은 이 화면 안에서만 계산합니다", + "sub_schedule": "핵심 날짜 여섯 개입니다. 항공권과 숙소는 이 날짜로 검색합니다.", + "sub_days": "날짜마다 외출 단계와 식사 단계, 그날 갈 만한 곳을 표시합니다.", + "sub_book": "입국 권장일부터 출국 가능 최소일까지 날짜를 채워 검색합니다.", + "sub_rules": "담당 원장 안내가 우선이고, 아래는 병원 공개 안내 기준입니다.", + "empty_title": "시술과 수술일을 고르면 여기에 일정표가 나옵니다", + "empty_sub": "수술일은 예상일이어도 됩니다.", + "stickyView": "일정표 보기", + "stickyStay": "{a} → {b} · {n}박", + "h_step1_hint": "국적을 고르면 시차와 무비자 체류 한도를 함께 봅니다.", + "h_fest": "Festivals During Your Stay", + "sub_fest": "체류 기간과 겹치는 행사입니다. 자유 외출 단계가 되는 날부터 갈 수 있습니다.", + "fest_none": "체류 기간과 겹치는 행사가 없습니다.", + "fest_when": "{a} ~ {b}", + "fest_from": "{d}부터 가능", + "fest_notYet": "이번 체류에서는 자유 외출 단계에 닿지 않습니다", + "source_tour": "장소·행사 데이터: 한국관광공사 TourAPI, {date} 기준. 영업 여부와 행사 일정은 방문 전에 확인하세요.", + "tour_badge": "관광공사", + "festival_pick": "행사", + "readMoreShort": "홈페이지" + }, + "en": { + "eyebrow": "Recovery Planner", + "title": "Surgery date set? Plan the rest of your trip here.", + "lede": "Pick your procedure and surgery date. We work out when to arrive, the earliest you can fly home, which recovery days you can go out, and where to go on those days. Everything is calculated on this page and stored nowhere.", + "step1": "", + "step2": "", + "step3": "", + "step4": "", + "step5": "", + "lang": "Language", + "nationality": "Nationality", + "procedure": "Procedure", + "surgeryDate": "Surgery date", + "surgeryDateHint": "Use the date confirmed at consultation. An estimate is fine if it's not set yet.", + "prefs": "Choose as many as you like", + "pref_sightseeing": "Sightseeing", + "pref_shopping": "Shopping", + "pref_food": "Food", + "pref_kpop": "K-pop & hotspots", + "pref_care": "Rest & care", + "generate": "Build my schedule", + "arriveBy": "Arrive by", + "surgery": "Surgery", + "hospital": "Hospital stay", + "hospitalNights": "{n} night(s)", + "hospitalNone": "Same-day discharge", + "stitch": "Stitch / splint removal", + "departure": "Earliest departure", + "stayNights": "Total stay", + "nights": "{n} nights", + "pending": "To confirm", + "provisional": "Provisional", + "clinicSourced": "From clinic guidance", + "departureNote": "Earliest departure is a minimum. Your surgeon may advise differently after follow-up, so book flights with flexible terms.", + "dayBefore": "{n} day(s) before surgery", + "daySurgery": "Surgery day", + "dayAfter": "Day {n} after surgery", + "level": "Outing", + "diet": "Diet", + "picks": "Suggestions", + "noPicks": "A rest day. Use delivery and room service.", + "constraints": "During recovery", + "visaTitle": "Length of stay check", + "visaOk": "Visa-free stay for {country} nationals is {days} days and this plan is {stay} days. You're within the limit.", + "visaOver": "Visa-free stay for {country} nationals is {days} days but this plan is {stay} days. You may need a visa, please check.", + "visaRequired": "{country} nationals may need a visa in advance. Check before you travel.", + "visaVerify": "Stay limits are as of September 2026 and may change. Confirm at the Korea Visa Portal.", + "visaPortal": "Korea Visa Portal", + "hotels": "Hotels near the clinic", + "hotelHint": "Searches with your arrival and earliest-departure dates filled in. We picked places with elevators, room service and a 24-hour front desk.", + "hotelSearch": "Search these dates", + "flights": "Flights", + "flightHint": "Searches with your dates filled in, arriving at Incheon. Flexible fares recommended.", + "flightSearch": "Open in Google Flights", + "consult": "Book a consultation", + "consultHint": "Copy the summary below and send it with your consultation request so the clinic can plan around your recovery dates.", + "copySummary": "Copy summary", + "copied": "Copied", + "shareLink": "Copy link", + "ics": "Save to calendar", + "print": "Print", + "map": "Map", + "readMore": "Full recovery timeline", + "affiliate": "Hotel and flight links open the booking sites. Where an affiliate link applies, this site may earn a small commission. Booking terms and payment follow each site.", + "medical": "This schedule is general information based on the clinic's published guidance. Your surgeon's instructions for your own case take priority.", + "km": "{km} km", + "walk": "walk", + "taxi": "taxi", + "indoor": "indoor", + "summaryTitle": "Recovery schedule summary", + "levelLabel": "Outing level", + "sourceLabel": "Source", + "reset": "Start over", + "provisionalNote": "Values marked \"Provisional\" are not in the clinic's published guidance and use general estimates. Confirm your own dates at consultation.", + "noRemoval": "No removal visit", + "h_hero": "Plan Your Recovery Stay", + "h_step1": "Nationality", + "h_step2": "Procedure & Surgery Date", + "h_step3": "Your Free Time", + "h_step4": "Your Schedule", + "h_visa": "Length of Stay", + "h_rules": "During Recovery", + "h_days": "Day by Day", + "h_book": "Book & Save", + "h_hotels": "Hotels Near the Clinic", + "h_flights": "Flights", + "h_consult": "Consultation", + "h_input": "Build Your Schedule", + "sub_input": "Pick three things and your schedule appears.", + "stat_procs": "procedures", + "stat_places": "curated places", + "stat_places_d": "Curated picks plus Korea Tourism Organization data, with distance and travel time from {origin}", + "stat_hotels": "hotels nearby", + "stat_hotels_d": "Within a 10-minute walk, with elevators, room service and 24-hour desks", + "stat_privacy": "stored on servers", + "stat_privacy_d": "Your procedure and dates are calculated on this page only", + "sub_schedule": "Six key dates. Flights and hotels are searched with these.", + "sub_days": "Each day shows the outing level, diet stage and places worth going.", + "sub_book": "Searches are filled with your arrival and earliest-departure dates.", + "sub_rules": "Your surgeon's instructions come first. Below is the clinic's published guidance.", + "empty_title": "Pick a procedure and a surgery date to see your schedule here", + "empty_sub": "An estimated date is fine.", + "stickyView": "See schedule", + "stickyStay": "{a} → {b} · {n} nights", + "h_step1_hint": "Your nationality sets the jet-lag buffer and the visa-free stay check.", + "h_fest": "Festivals During Your Stay", + "sub_fest": "Events that overlap your stay. You can go from the first full-day-out date.", + "fest_none": "No events overlap your stay.", + "fest_when": "{a} to {b}", + "fest_from": "From {d}", + "fest_notYet": "Your stay does not reach the full-day-out stage", + "source_tour": "Places and events: Korea Tourism Organization TourAPI, as of {date}. Check opening status and event dates before you go.", + "tour_badge": "KTO", + "festival_pick": "Event", + "readMoreShort": "Website" + } +} diff --git a/supporters/src/data/procedures.json b/supporters/src/data/procedures.json new file mode 100644 index 0000000..4ec9dc7 --- /dev/null +++ b/supporters/src/data/procedures.json @@ -0,0 +1,989 @@ +{ + "_comment": "회복기 스케줄러 시술별 규칙표 (설계 v0.2 §13.4). 숫자마다 status 가 붙는다. clinic = 병원 공개 주의사항·애프터케어에 있는 값, provisional = 병원 확인 전 잠정값(화면에 배지 표시), null = 값 없음(화면에 '확인'). 병원 확인이 끝나면 status 를 clinic 으로 바꾸고 source 를 채운다.", + "clinicSources": [ + { + "id": "precautions", + "label": { + "ko": "뷰성형외과 홈페이지 · 수술 전·후 주의사항", + "en": "View Plastic Surgery · Pre/Post-operative precautions" + }, + "url": "https://www.viewclinic.com/system/precautions/", + "accessed": "2026-09-07" + }, + { + "id": "aftercare", + "label": { + "ko": "뷰성형외과 홈페이지 · 애프터케어", + "en": "View Plastic Surgery · Aftercare" + }, + "url": "https://www.viewclinic.com/system/after-care/", + "accessed": "2026-09-07" + } + ], + "levels": [ + { + "level": 0, + "label": { + "ko": "실내 안정", + "en": "Rest indoors" + }, + "desc": { + "ko": "병실이나 호텔에서 쉬는 날입니다. 필요한 것은 배달과 룸서비스로 해결합니다.", + "en": "Rest at the hospital or hotel. Use delivery and room service." + } + }, + { + "level": 1, + "label": { + "ko": "근거리 외출", + "en": "Short walks" + }, + "desc": { + "ko": "호텔 반경 500m 안에서 짧게 다녀옵니다. 도보 10분 이내.", + "en": "Short trips within 500 m of your hotel. Up to a 10-minute walk." + } + }, + { + "level": 2, + "label": { + "ko": "반나절 외출", + "en": "Half-day outing" + }, + "desc": { + "ko": "택시로 반경 3km 안 쇼핑·식사·가벼운 관광이 가능합니다.", + "en": "Shopping, dining and light sightseeing within 3 km by taxi." + } + }, + { + "level": 3, + "label": { + "ko": "자유 외출", + "en": "Full day out" + }, + "desc": { + "ko": "하루 단위 외출이 가능합니다. 시내 관광, 행사, 인파가 있는 곳도 담당 원장 안내 안에서 가능합니다.", + "en": "Full-day outings. City sightseeing and events, within your surgeon's guidance." + } + } + ], + "diets": { + "liquid": { + "label": { + "ko": "유동식", + "en": "Liquid diet" + }, + "desc": { + "ko": "건더기 없는 유동식만 드십니다.", + "en": "Liquids only, no solids." + } + }, + "soft": { + "label": { + "ko": "부드러운 음식", + "en": "Soft foods" + }, + "desc": { + "ko": "건더기가 있어도 부드러운 음식까지 가능합니다.", + "en": "Soft foods are fine. Avoid anything chewy or hard." + } + }, + "mild": { + "label": { + "ko": "자극 없는 일반식", + "en": "Regular, non-spicy" + }, + "desc": { + "ko": "맵고 짜거나 딱딱한 음식은 피합니다.", + "en": "Regular meals. Avoid spicy, salty or hard foods." + } + }, + "normal": { + "label": { + "ko": "일반식", + "en": "Regular diet" + }, + "desc": { + "ko": "식사 제한이 없습니다.", + "en": "No dietary restrictions." + } + } + }, + "constraints": { + "no-heavy-lifting": { + "ko": "무거운 짐과 팔을 많이 쓰는 동작을 피합니다. 쇼핑은 배송 서비스를 이용하세요.", + "en": "Avoid heavy bags and arm-heavy movement. Use delivery for shopping." + }, + "sports-bra": { + "ko": "스포츠브라를 1~3개월 유지합니다.", + "en": "Wear a sports bra for 1 to 3 months." + }, + "no-alcohol-30d": { + "ko": "음주와 흡연은 최소 1개월 이후입니다.", + "en": "No alcohol or smoking for at least 1 month." + }, + "no-sauna-60d": { + "ko": "사우나, 찜질방, 수영, 과한 운동은 약 2개월 후입니다.", + "en": "No sauna, spa, swimming or intense exercise for about 2 months." + }, + "compression-band": { + "ko": "압박밴드를 2~4주 착용합니다. 취침 시에는 하지 않습니다.", + "en": "Wear the compression band for 2 to 4 weeks, not while sleeping." + }, + "sleep-elevated": { + "ko": "머리를 심장보다 높게 하고 정면 자세로 잡니다. 1주 후부터 옆으로 누워도 됩니다.", + "en": "Sleep with your head above heart level, facing up. Side sleeping from week 2." + }, + "saline-gargle": { + "ko": "약 1개월간 생리식염수 가글을 꾸준히 합니다.", + "en": "Rinse with saline regularly for about 1 month." + }, + "no-hard-food-30d": { + "ko": "질기고 딱딱한 음식은 한 달간 피합니다.", + "en": "Avoid chewy or hard food for 1 month." + }, + "no-sun": { + "ko": "직사광선을 피합니다. 모자와 선글라스를 챙기세요.", + "en": "Avoid direct sun. Bring a hat and sunglasses." + }, + "mask": { + "ko": "외출 시 마스크를 쓰면 부기와 멍이 덜 보입니다.", + "en": "A mask helps cover swelling and bruising when out." + }, + "no-glasses": { + "ko": "안경 착용을 피합니다. 콘택트렌즈나 안경 없이 다닐 계획을 세우세요.", + "en": "Avoid glasses resting on your nose. Plan for contacts or going without." + }, + "no-lens": { + "ko": "콘택트렌즈는 담당 원장이 허용할 때까지 쓰지 않습니다.", + "en": "No contact lenses until your surgeon allows." + }, + "cold-compress": { + "ko": "초기에는 냉찜질, 이후 온찜질을 합니다.", + "en": "Cold compresses at first, then warm." + }, + "no-nose-blow": { + "ko": "코를 세게 풀거나 코 부위에 압력을 주지 않습니다.", + "en": "Do not blow your nose or press on the nose area." + }, + "no-massage": { + "ko": "수술 부위 마사지와 강한 압박을 피합니다.", + "en": "No massage or firm pressure on the surgical area." + }, + "no-hat-pressure": { + "ko": "이식 부위를 누르는 모자나 헬멧을 피합니다.", + "en": "Avoid hats or helmets that press on the graft area." + }, + "no-scratch": { + "ko": "가려워도 긁지 않습니다.", + "en": "Do not scratch, even if itchy." + }, + "driving": { + "ko": "수술 당일은 운전할 수 없습니다. 보호자 동반을 권합니다.", + "en": "No driving on surgery day. A companion is recommended." + } + }, + "procedures": [ + { + "id": "breast", + "label": { + "ko": "가슴성형", + "en": "Breast Augmentation" + }, + "group": { + "ko": "가슴", + "en": "Breast" + }, + "readMore": "/posts/breast-recovery-timeline", + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "검진과 상담 1일, 여유 1일", + "en": "1 day for tests and consultation, 1 buffer day" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 10 + ], + "status": "clinic", + "source": "precautions", + "note": { + "ko": "실밥이 있으면 약 1주에 제거. 피부 접착제를 쓴 경우 실밥 없음", + "en": "Stitches, if any, removed at about 1 week. No stitches if skin adhesive was used" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "clinic", + "source": "precautions", + "note": { + "ko": "부기는 2~3일째 가장 심합니다", + "en": "Swelling peaks on days 2 to 3" + } + }, + { + "fromDay": 3, + "level": 1, + "status": "clinic", + "source": "precautions", + "note": { + "ko": "3일 이후 붕대를 뗍니다", + "en": "Bandage removed after day 3" + } + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "clinic", + "source": "precautions" + } + ], + "constraints": [ + "driving", + "no-heavy-lifting", + "sports-bra", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [ + "precautions", + "aftercare" + ] + }, + { + "id": "contour", + "label": { + "ko": "안면윤곽·양악", + "en": "Facial Contouring / Jaw Surgery" + }, + "group": { + "ko": "얼굴뼈", + "en": "Facial bone" + }, + "readMore": "/posts/contour-recovery", + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "3D-CT 촬영과 검진, 상담", + "en": "3D-CT, tests and consultation" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "clinic", + "source": "precautions", + "note": { + "ko": "입안 실은 녹는 실이라 보통 한 달 후 저절로 없어집니다. 별도 제거 방문 없음", + "en": "Intraoral stitches dissolve on their own in about a month. No removal visit" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 14, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "clinic", + "source": "precautions", + "note": { + "ko": "부기는 3~4일까지 늘다가 가라앉습니다", + "en": "Swelling increases until day 3 to 4, then subsides" + } + }, + { + "fromDay": 5, + "level": 1, + "status": "clinic", + "source": "precautions", + "note": { + "ko": "5~7일 후 일상생활이 가능합니다", + "en": "Daily activities possible after day 5 to 7" + } + }, + { + "fromDay": 10, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 21, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "liquid", + "status": "clinic", + "source": "precautions" + }, + { + "fromDay": 7, + "type": "soft", + "status": "clinic", + "source": "precautions" + }, + { + "fromDay": 14, + "type": "mild", + "status": "clinic", + "source": "precautions" + }, + { + "fromDay": 30, + "type": "normal", + "status": "clinic", + "source": "precautions" + } + ], + "constraints": [ + "driving", + "compression-band", + "sleep-elevated", + "saline-gargle", + "no-hard-food-30d", + "no-alcohol-30d", + "no-sauna-60d", + "no-massage" + ], + "sources": [ + "precautions", + "aftercare" + ] + }, + { + "id": "eye", + "label": { + "ko": "눈성형", + "en": "Eyelid Surgery" + }, + "group": { + "ko": "눈", + "en": "Eyes" + }, + "readMore": "/posts/eye-canthoplasty-types", + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 6, + "range": [ + 5, + 7 + ], + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 10, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "cold-compress", + "no-sun", + "no-lens", + "no-scratch", + "no-alcohol-30d" + ], + "sources": [] + }, + { + "id": "nose", + "label": { + "ko": "코성형", + "en": "Rhinoplasty" + }, + "group": { + "ko": "코", + "en": "Nose" + }, + "readMore": "/posts/functional-rhinoplasty-ent", + "preOpDays": { + "value": 2, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 7 + ], + "status": "provisional", + "note": { + "ko": "부목과 실밥 제거", + "en": "Splint and stitch removal" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "mild", + "status": "provisional" + }, + { + "fromDay": 14, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-glasses", + "no-nose-blow", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [] + }, + { + "id": "fat", + "label": { + "ko": "지방성형", + "en": "Liposuction / Fat Grafting" + }, + "group": { + "ko": "지방", + "en": "Fat" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "compression-band", + "no-massage", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [] + }, + { + "id": "lifting", + "label": { + "ko": "안티에이징·리프팅", + "en": "Anti-aging / Face Lift" + }, + "group": { + "ko": "리프팅", + "en": "Lifting" + }, + "readMore": "/posts/thread-lift-vs-facelift", + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-massage", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [] + }, + { + "id": "skin", + "label": { + "ko": "피부과 시술", + "en": "Dermatology Treatment" + }, + "group": { + "ko": "피부", + "en": "Skin" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "실밥 없음", + "en": "No stitches" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 2, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-sauna-60d" + ], + "sources": [] + }, + { + "id": "hair", + "label": { + "ko": "모발이식", + "en": "Hair Transplant" + }, + "group": { + "ko": "모발", + "en": "Hair" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "채취 방식에 따라 다릅니다", + "en": "Depends on the harvesting method" + } + }, + "earliestDepartureDay": { + "value": 3, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-hat-pressure", + "no-scratch", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [] + } + ], + "nationalities": { + "_comment": "무비자 체류 한도(일). 2026-09 기준 확인 필요. null 은 사전 비자 필요. 화면은 항상 대한민국 비자포털 링크와 함께 보여준다.", + "portal": "https://www.visa.go.kr", + "list": [ + { + "code": "US", + "label": { + "ko": "미국", + "en": "United States" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "CA", + "label": { + "ko": "캐나다", + "en": "Canada" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "GB", + "label": { + "ko": "영국", + "en": "United Kingdom" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "AU", + "label": { + "ko": "호주", + "en": "Australia" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "JP", + "label": { + "ko": "일본", + "en": "Japan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TW", + "label": { + "ko": "대만", + "en": "Taiwan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "HK", + "label": { + "ko": "홍콩", + "en": "Hong Kong" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "SG", + "label": { + "ko": "싱가포르", + "en": "Singapore" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TH", + "label": { + "ko": "태국", + "en": "Thailand" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "MY", + "label": { + "ko": "말레이시아", + "en": "Malaysia" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "AE", + "label": { + "ko": "아랍에미리트", + "en": "United Arab Emirates" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "RU", + "label": { + "ko": "러시아", + "en": "Russia" + }, + "visaFreeDays": 60, + "longHaul": true + }, + { + "code": "KZ", + "label": { + "ko": "카자흐스탄", + "en": "Kazakhstan" + }, + "visaFreeDays": 30, + "longHaul": true + }, + { + "code": "CN", + "label": { + "ko": "중국", + "en": "China" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "VN", + "label": { + "ko": "베트남", + "en": "Vietnam" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "ID", + "label": { + "ko": "인도네시아", + "en": "Indonesia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "PH", + "label": { + "ko": "필리핀", + "en": "Philippines" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "MN", + "label": { + "ko": "몽골", + "en": "Mongolia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "OTHER", + "label": { + "ko": "그 외", + "en": "Other" + }, + "visaFreeDays": null, + "longHaul": true + } + ] + } +} diff --git a/supporters/src/data/recoveryNotes.json b/supporters/src/data/recoveryNotes.json new file mode 100644 index 0000000..4660270 --- /dev/null +++ b/supporters/src/data/recoveryNotes.json @@ -0,0 +1,254 @@ +{ + "clinic": "viewclinic", + "generatedAt": "2026-09-11", + "sourceNote": "병원 홈페이지 시술 페이지 원문", + "items": [ + { + "procedure": "수술 전·후 주의사항", + "procedureEn": "Pre- and Post-Operative Precautions", + "area": "", + "url": "https://www.viewclinic.com/system/precautions/", + "ko": [ + "수술 당일 콘택트렌즈, 귀금속, 액세서리, 매니큐어, 화장 등은 미리 제거해 주시기 바랍니다.", + "수술 후 2~3일째 가장 부기가 많고 3일 이후 붕대 제거가 가능합니다.", + "전체적인 부기는 1개월 정도 지나면서 자연스러워지고 잔 붓기는 6개월까지 좋아집니다.", + "절개 부위에 더마본드 사용 시 2주 후부터 샤워 가능합니다.", + "절개 부위에 실밥이 있는 경우, 실밥 제거 후 다음날부터 가벼운 샤워 가능합니다.", + "6개월 이후 흉터 레이저 관리 가능합니다.", + "수술 후 스포츠브라는 1~3개월 유지하고, 3개월 후 일반 속옷 착용이 가능합니다.", + "수술 후 음주 및 흡연은 최소 1개월 이후 가능합니다.", + "찜질방, 사우나, 수영장, 과도한 운동은 약 2개월 후 가능합니다.", + "재수술 후 운동은 3개월 이후 권장합니다.", + "수술 후 회복 및 경과는 개인에 따라 차이가 있을 수 있으며 염증, 출혈, 신경 손상 등의 부작용이 생길 수 있으므로 주의가 필요합니다.", + "수술 후 3~4일까지는 부기가 증가하고 이후부터 가라앉으며 5~7일 후 일상생활이 가능합니다.", + "3일 후부터 머리를 감을 수 있으며, 간단한 샤워는 가능하나 목욕은 삼갑니다.", + "턱 테이프 제거 후 다음 날부터 가벼운 거품 세안, 피부 화장이 가능합니다.", + "수술 후 1주가 지나면 어린이용 작은 칫솔모로 가볍게 양치 가능하고, 음식물 섭취 후 항상 가글을 잘 해주세요.", + "수술 후 3일 정도는 냉찜질, 그 후에는 온찜질로 부기를 예방할 수 있습니다.", + "바깥쪽 실밥 제거 후 1주일은 더 상처연고로 관리해 주시고, 이후 흉터연고로 관리해주세요.", + "찜질방, 사우나, 수영장, 과도한 운동, 마사지는 약 1~2개월 후 가능합니다.", + "수술 후 3~4일까지는 부기가 증가하고 이후부터 부기가 가라앉으며 5~7일 후 일상생활이 가능합니다.", + "수술 후 1달 정도가 되면 부기의 80%가 빠지게 되며 이후부터는 점점 자연스러워집니다.", + "수술 후 3일 동안은 냉찜질, 그 후에는 온찜질로 부기를 예방할 수 있습니다.", + "수술 후 7일째부터 입술 운동(A/E/I/O/U), 웃는 연습(입꼬리 위치가 같게) 꾸준히 해주시기 바랍니다.", + "수술 후 2~3일은 멍이나 부기가 증가할 수 있으며 개인차가 있습니다.", + "수술 후 1~2주 정도 큰 부기가 있고 눈 주위 멍이나 큰 부기는 한 달 정도 지나면서 자연스러워지며 잔 붓기는 6개월 사이에 점차 감소합니다.", + "수술 후 3일간은 냉찜질을 해주시기 바랍니다.", + "눈썹거상 눈썹 문신은 6개월 이후에 가능합니다.", + "눈밑지방재배치 초반에 눈 밑이 볼록하고 단단하게 느껴질 수 있으나 평균 1개월정도 부기가 흡수되면서 볼록한게 감소하고 단단한 것도 풀어지며 자연스러워집니다.", + "실밥을 제거했어도 절개 부위가 약하기 때문에 눈을 비비고 만지는 행동, 눈에 자극을 주는 행동은 1개월까지 삼가주세요.", + "실밥 제거 후 다음날부터 가벼운 거품 세안, 연한 피부 화장이 가능합니다.", + "수술 후 3일간은 냉찜질을 해주시기 바랍니다.(코 주변, 이마 쪽으로 찜질해 주시기 바랍니다.)", + "실밥 제거 후 다음날부터 가벼운 거품 세안, 피부 화장 가능합니다.", + "붙이는 코팩 또는 스크럽 제품 사용은 1개월 이후 가능합니다.", + "부위에 따라 멍이 1~3주 지속될 수 있으며, 부기는 3~4주 정도면 70%~80% 이상 감소하게 됩니다.", + "1개월 이후 전체적인 부기가 빠지고 압박복이 늘어나게 되면 압박복은 수선 후 착용해 주시는 것이 좋습니다.", + "수술 후 2주 후부터 식이조절 및 가벼운 운동을 병행해 주시면 체중조절 및 회복에 도움이 됩니다.", + "실밥 제거 후 다음날부터 가벼운 거품 세안, 샤워가 가능합니다.", + "부기가 빠지고 지방이 생착 되는 기간은 1개월 정도 소요됩니다.", + "지방이 생착 되는 기간 동안에는 외부의 압력으로 인해 눌리거나 충격이 가해지는 행동을 주의해주세요.", + "1개월 이후 원장님 경과 체크를 진행하며, 필요시 부족한 부위에 2차 지방이식이 가능합니다.", + "실밥 제거 후 다음날부터 가벼운 거품 세안, 샴푸, 화장이 가능합니다." + ], + "en": [ + "On the day of surgery, please remove contact lenses, jewelry, accessories, nail polish, and makeup in advance.", + "Swelling is greatest on the 2nd to 3rd day after surgery, and bandages can be removed after the 3rd day.", + "Overall swelling naturally improves after about 1 month, and residual swelling improves up to 6 months.", + "If Dermabond is used on the incision site, showering is possible from 2 weeks after surgery.", + "If there are stitches on the incision site, light showering is possible from the day after stitch removal.", + "Scar laser treatment is possible after 6 months.", + "Wear a sports bra for 1 to 3 months after surgery, and normal underwear is allowed after 3 months.", + "Drinking alcohol and smoking are allowed at least 1 month after surgery.", + "Saunas, jjimjilbangs, swimming pools, and excessive exercise are allowed about 2 months after surgery.", + "Exercise after revision surgery is recommended after 3 months.", + "Recovery and progress after surgery may vary by individual, and complications such as inflammation, bleeding, and nerve damage may occur, so caution is required.", + "Swelling increases for 3 to 4 days after surgery, then subsides, and daily activities are possible after 5 to 7 days.", + "You can wash your hair from 3 days after surgery; simple showers are allowed but baths are not.", + "After removing chin tape, light foam cleansing and skin makeup are possible from the next day.", + "After 1 week post-surgery, you can gently brush your teeth with a small children's toothbrush, and always gargle well after eating.", + "Cold compresses are recommended for about 3 days after surgery, then warm compresses can help prevent swelling.", + "Manage the outer stitches with wound ointment for 1 week after removal, then use scar ointment afterward.", + "Saunas, jjimjilbangs, swimming pools, excessive exercise, and massages are allowed about 1 to 2 months after surgery.", + "Swelling increases for 3 to 4 days after surgery, then subsides, and daily activities are possible after 5 to 7 days.", + "About 80% of swelling reduces after 1 month post-surgery, and the appearance gradually becomes natural.", + "Cold compresses are recommended for 3 days after surgery, then warm compresses can help prevent swelling.", + "From the 7th day after surgery, consistently practice lip exercises (A/E/I/O/U) and smiling exercises (keep the corners of the mouth aligned).", + "Bruising or swelling may increase for 2 to 3 days after surgery, with individual differences.", + "", + "Apply cold compresses for 3 days after surgery.", + "Eyebrow lift and eyebrow tattooing are possible after 6 months.", + "After lower eyelid fat repositioning, the under-eye area may feel bulging and firm initially, but swelling reduces and firmness softens over about 1 month, becoming natural.", + "Even after stitch removal, avoid rubbing or touching the eyes and any actions that irritate the eyes for 1 month because the incision area is weak.", + "Light foam cleansing and light skin makeup are possible from the day after stitch removal.", + "Apply cold compresses for 3 days after surgery, focusing on the nose area and forehead.", + "Light foam cleansing and skin makeup are possible from the day after stitch removal.", + "Use of adhesive nose packs or scrub products is allowed after 1 month.", + "Bruising may last 1 to 3 weeks depending on the area, and swelling reduces by 70% to 80% after about 3 to 4 weeks.", + "After 1 month, overall swelling decreases and compression garments may loosen; it is recommended to have the compression garment altered and wear it again.", + "From 2 weeks after surgery, dietary control and light exercise help with weight management and recovery.", + "Light foam cleansing and showering are possible from the day after stitch removal.", + "It takes about 1 month for swelling to subside and fat to stabilize.", + "During the fat stabilization period, avoid pressure or impact on the area.", + "", + "Light foam cleansing, shampooing, and makeup are possible from the day after stitch removal." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "눈밑지방재배치", + "procedureEn": "Lower Eyelid Fat Repositioning", + "area": "", + "url": "https://www.viewclinic.com/eye/under-eye-fat-relocation/", + "ko": [ + "회복기간 바로 일상생활 가능", + "수술 후 약 1주일 정도는 눈을 심하게 비비는 등의 행동은 피하는 것이 좋습니다." + ], + "en": [ + "You can resume daily activities immediately during the recovery period.", + "For about 1 week after surgery, avoid actions such as rubbing your eyes vigorously." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "무턱", + "procedureEn": "Receding Chin", + "area": "", + "url": "https://www.viewclinic.com/jaw/type-jaw/short-chin/", + "ko": [ + "평균적으로 수술 후 3~4주가 지난 후 출근 등 큰 체력이 소모되지 않는 일상생활은 가능합니다.", + "수술이 끝난 후, 8~12시간 가량 경과 후 간단한 실내 움직임은 가능해지며 수술 후 2주 정도까지는 경과체크를 하며 상처 및 부종 등을 관리하시게 됩니다." + ], + "en": [ + "On average, after 3 to 4 weeks post-surgery, you can return to work and other daily activities that do not require heavy physical exertion.", + "After surgery, simple indoor movements are possible about 8 to 12 hours later, and until about 2 weeks after surgery, you will have follow-up checks to manage wounds and swelling." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "뷰 복부거상술", + "procedureEn": "View Abdominal Lift", + "area": "", + "url": "https://www.viewclinic.com/lipo/tummy-tuck/", + "ko": [ + "일상 복귀는 1~2주, 조직 회복은 4~6주 정도 소요됩니다.", + "일정 기간 보정속옷 착용, 운동 제한 등이 필요합니다." + ], + "en": [ + "Returning to daily life takes 1 to 2 weeks, and tissue recovery takes about 4 to 6 weeks.", + "Wearing compression garments and exercise restrictions are necessary for a certain period." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "뷰 줄기세포", + "procedureEn": "View Stem Cell", + "area": "", + "url": "https://www.viewclinic.com/view_stemcell/", + "ko": [ + "시술 직후 일상생활이 가능하며, 특별한 회복 기간을 필요로 하지 않습니다.", + "다만 무리한 운동은 1~2일 정도 피하는 것이 좋습니다." + ], + "en": [ + "You can perform daily activities immediately after the procedure, and no special recovery period is required.", + "However, it is recommended to avoid strenuous exercise for about 1 to 2 days." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "남성여유증, 여성형유방", + "procedureEn": "Gynecomastia", + "area": "", + "url": "https://www.viewclinic.com/view-male/gynecomastia/", + "ko": [ + "수술 후 부기 완화, 염증 관리에 도움되는 APL 관리를 진행합니다." + ], + "en": [ + "APL treatment is performed to help reduce swelling and manage inflammation after surgery." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "모발이식", + "procedureEn": "Hair Transplant", + "area": "", + "url": "https://www.viewclinic.com/hair-transplant/", + "ko": [ + "이식모가 생착 되기까지 약 3주가 소요되며, 수술 후 10~15일까지는 이식부위에 딱지가 조금씩 떨어지게 됩니다." + ], + "en": [ + "It takes about 3 weeks for transplanted hair to take root, and scabs on the transplant area will gradually fall off by 10 to 15 days after surgery." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "프로모션2_가슴", + "procedureEn": "Promotion 2_Breast", + "area": "", + "url": "https://www.viewclinic.com/ldpg-2/", + "ko": [ + "수술 후 발생할 수 있는 합병증인 출혈, 감염, 염증 등은 개인에 따라 차이가 있을 수 있으므로 주의해야 합니다." + ], + "en": [ + "Complications such as bleeding, infection, and inflammation may occur after surgery and vary by individual, so caution is necessary." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + }, + { + "procedure": "UIU 가슴성형", + "procedureEn": "UIU Breast Augmentation", + "area": "", + "url": "https://www.viewclinic.com/breast/main/", + "ko": [ + "수술 후 통증을 줄이고 빠른 회복 가능" + ], + "en": [ + "Pain after surgery can be reduced and rapid recovery is possible." + ], + "ocr": false, + "fetchedAt": "2026-09-07" + } + ], + "counts": { + "pagesScanned": 110, + "pagesWithNotes": 9, + "pages": 9, + "sentences": 52, + "translated": 59, + "cacheHits": 26, + "enFailed": 2, + "costUsd": 0.0023, + "dropped": { + "time": 7923, + "length": 3895, + "action": 490, + "preop": 7, + "dup": 28, + "contact": 1, + "promo": 66, + "unfinished": 49, + "fragment": 39, + "table": 3, + "broken": 3 + } + }, + "enFailed": [ + { + "ko": "수술 후 1~2주 정도 큰 부기가 있고 눈 주위 멍이나 큰 부기는 한 달 정도 지나면서 자연스러워지며 잔 붓기는 6개월 사이에 점차 감소합니다.", + "en": "Significant swelling lasts about 1 to 2 weeks after surgery; bruising and major swelling around the eyes improve naturally after about 1 month, and residual swelling gradually decreases within 6 months.", + "why": "numbers" + }, + { + "ko": "1개월 이후 원장님 경과 체크를 진행하며, 필요시 부족한 부위에 2차 지방이식이 가능합니다.", + "en": "After 1 month, the doctor will check progress and a second fat graft is possible if needed.", + "why": "numbers" + } + ] +} diff --git a/supporters/src/layouts/Base.astro b/supporters/src/layouts/Base.astro index d55e340..d9cba52 100644 --- a/supporters/src/layouts/Base.astro +++ b/supporters/src/layouts/Base.astro @@ -18,14 +18,14 @@ const { title, description, jsonLd, ogImage = S.buildingImage?.src || '/favicon. const isEn = lang === 'en'; // 머리말·꼬리말 문구. 법적 고지(지원 관계·부작용)는 번역하지 않는다. 아래 주석 참조. const T = isEn - ? { nav: [['/posts', 'Questions'], ['/videos', 'Doctors'], ['/newsroom', 'Newsroom'], ['/en/stay', 'Your Stay'], ['/about', 'About']], cta: 'Book a Consultation', supporters: 'SUPPORTERS', back: 'Back', top: 'Back to top', sample: 'This is a sample site, not yet public.' } - : { nav: [['/posts', '상담 전 질문'], ['/videos', '의료진 영상'], ['/newsroom', '뉴스룸'], ['/stay', '주변 안내'], ['/visit', '방문 안내'], ['/about', '매체 소개']], cta: '상담 예약', supporters: '서포터즈', back: '이전 페이지', top: '맨 위로', sample: '샘플 사이트입니다. 정식 공개 전입니다.' }; + ? { nav: [['/posts', 'Questions'], ['/videos', 'Doctors'], ['/newsroom', 'Newsroom'], ['/en/plan', 'Recovery Planner'], ['/about', 'About']], cta: 'Book a Consultation', supporters: 'SUPPORTERS', back: 'Back', top: 'Back to top', sample: 'This is a sample site, not yet public.' } + : { nav: [['/posts', '상담 전 질문'], ['/videos', '의료진 영상'], ['/newsroom', '뉴스룸'], ['/visit', '방문 안내'], ['/plan', '회복 일정'], ['/about', '매체 소개']], cta: '상담 예약', supporters: '서포터즈', back: '이전 페이지', top: '맨 위로', sample: '샘플 사이트입니다. 정식 공개 전입니다.' }; // 언어 전환. 같은 내용의 짝이 있는 페이지만 서로 잇고, 없으면 그 언어의 입구로 보낸다. // 영문 페이지가 늘어나면 이 표에 줄만 추가한다. -const PAIRS: Record = { '/stay': '/en/stay', '/visit': '/en/stay' }; +const PAIRS: Record = { '/plan': '/en/plan', '/visit': '/en/plan' }; const KO_ENTRY = '/'; -const EN_ENTRY = '/en/stay'; +const EN_ENTRY = '/en/plan'; const path = (Astro.url.pathname.replace(/\.html$/, '').replace(/\/index$/, '/').replace(/\/$/, '') || '/'); const koPair = Object.entries(PAIRS).find(([, en]) => en === path)?.[0]; const otherHref = isEn ? (koPair ?? KO_ENTRY) : (PAIRS[path] ?? EN_ENTRY); @@ -34,7 +34,7 @@ const otherExact = isEn ? Boolean(koPair) : Boolean(PAIRS[path]); // 영문 페이지의 예약 버튼은 병원의 외국인용 영문 사이트로 보낸다(factSheet.urlEn). // 한국어 예약 페이지로 보내면 영어로 온 사람이 한국어 화면을 만난다. const ctaHref = isEn - ? ((f as Record).reservationUrlEn || (f as Record).urlEn || reservationUrl || '/en/stay') + ? ((f as Record).reservationUrlEn || (f as Record).urlEn || reservationUrl || '/en/plan') : (reservationUrl || '/visit'); // 의료광고 고지는 규정 대상이라 임의로 번역하지 않는다(의료법 56조·추천보증 심사지침). // 병원이 영문 문구를 확정해 site.json 의 sponsorNoticeEn / factSheet 의 sideEffectNoticeEn 에 넣기 전까지는 diff --git a/supporters/src/lib/plan.ts b/supporters/src/lib/plan.ts new file mode 100644 index 0000000..8994cf4 --- /dev/null +++ b/supporters/src/lib/plan.ts @@ -0,0 +1,177 @@ +// 회복기 스케줄러 계산 로직 (설계 v0.2 §13.3·§13.7·§13.8). 화면과 분리된 순수 함수만 둔다. +// 입력: 시술 id, 수술일, 국적, 선호. 출력: 날짜별 외출 등급·식사·추천과 예약 링크. 서버 호출 없음. +// 검증: node --experimental-strip-types scripts/gate/plan.test.mjs + +export type Lang = 'ko' | 'en'; +export type L10n = Record; +export type Status = 'clinic' | 'provisional'; +export interface Valued { value: number | null; range?: [number, number]; status: Status; source?: string; note?: L10n } +export interface LevelStep { fromDay: number; level: number; status: Status; source?: string; note?: L10n } +export interface DietStep { fromDay: number; type: 'liquid' | 'soft' | 'mild' | 'normal'; status: Status; source?: string } +export interface Procedure { + id: string; label: L10n; group: L10n; readMore: string | null; + preOpDays: Valued; hospitalNights: Valued; stitchRemovalDay: Valued; earliestDepartureDay: Valued; + outingLevels: LevelStep[]; diet: DietStep[]; constraints: string[]; sources: string[]; +} +export interface Place { + id: string; name: L10n; category: string; minLevel: number; dietOk?: string[]; distanceKm: number; indoor: boolean; + area: L10n; note: L10n; mapQuery: string | null; bookingQuery?: string; verify: boolean; + source?: 'curated' | 'tourapi'; travelLabel?: string; image?: string; url?: string; +} +export interface Nationality { code: string; label: L10n; visaFreeDays: number | null; longHaul: boolean } + +export interface PlanFestival { id: string; title: string; start: string; end: string } +export interface PlanInput { procedure: Procedure; surgeryDate: string; nationality?: Nationality | null; prefs: string[]; festivals?: PlanFestival[] } +export interface PlanDay { date: string; offset: number; level: number; diet: DietStep['type']; picks: Place[]; festivals: PlanFestival[]; isSurgery: boolean; isHospital: boolean; isStitch: boolean; isArrival: boolean; isDeparture: boolean } +export interface Plan { + arriveBy: string; surgeryDate: string; dischargeDate: string | null; stitchDate: string | null; earliestDeparture: string | null; + stayNights: number | null; preOpDays: number; days: PlanDay[]; +} + +const DAY = 86_400_000; +export const addDays = (iso: string, n: number): string => { + const d = new Date(`${iso}T00:00:00Z`); + return new Date(d.getTime() + n * DAY).toISOString().slice(0, 10); +}; +export const isIsoDate = (s: unknown): s is string => typeof s === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(s) && !Number.isNaN(Date.parse(`${s}T00:00:00Z`)); + +/** fromDay 오름차순 단계표에서 offset 에 해당하는 단계. 첫 단계 이전이면 첫 단계. */ +function stepAt(steps: T[], offset: number): T { + const sorted = [...steps].sort((a, b) => a.fromDay - b.fromDay); + let cur = sorted[0]; + for (const s of sorted) if (offset >= s.fromDay) cur = s; + return cur; +} + +/** 장거리 국적은 시차 회복으로 준비일에 1일을 더한다 (§13.3). */ +export function effectivePreOpDays(p: Procedure, nat?: Nationality | null): number { + const base = p.preOpDays.value ?? 2; + return base + (nat?.longHaul ? 1 : 0); +} + +/** + * 장소 점수. 선호 일치가 가장 크고, 등급이 딱 맞을수록, 가까울수록 높다. + * 선호가 비어 있으면 카테고리 무관하게 거리와 등급만 본다. + */ +export function scorePlace(place: Place, level: number, diet: DietStep['type'], prefs: string[]): number { + if (place.category === 'hotel') return -1; + if (place.minLevel > level) return -1; + if (place.category === 'food' && place.dietOk && !place.dietOk.includes(diet)) return -1; + let s = 0; + if (prefs.length === 0 || prefs.includes(place.category)) s += 3; + if (place.source !== 'tourapi') s += 0.75; // 큐레이션(1순위)이 같은 조건이면 먼저 나온다 + if (place.category === 'essentials' || place.category === 'care') s += 1; // 회복에 직접 필요한 것은 기본 가점 + s += 2 - Math.min(2, level - place.minLevel); // 오늘 등급에 맞는 곳을 우선 + s += Math.max(0, 1.5 - place.distanceKm / 4); // 가까울수록 가점(최대 1.5) + return s; +} + +/** 하루에 최대 3곳. 직전 2일에 나온 곳은 뒤로 미뤄 날마다 다른 곳이 나오게 한다. */ +export function pickForDay(places: Place[], level: number, diet: DietStep['type'], prefs: string[], recent: Set, max = 3): Place[] { + return places + .map((p) => ({ p, s: scorePlace(p, level, diet, prefs) - (recent.has(p.id) ? 2.5 : 0) })) + .filter((x) => x.s >= 0) + .sort((a, b) => b.s - a.s || a.p.distanceKm - b.p.distanceKm) + .slice(0, max) + .map((x) => x.p); +} + +export function buildPlan(input: PlanInput, places: Place[]): Plan { + const { procedure: p, surgeryDate, nationality, prefs, festivals = [] } = input; + const preOp = effectivePreOpDays(p, nationality); + const arriveBy = addDays(surgeryDate, -preOp); + const nights = p.hospitalNights.value; + const dischargeDate = nights === null ? null : addDays(surgeryDate, nights); + const stitchDate = p.stitchRemovalDay.value === null ? null : addDays(surgeryDate, p.stitchRemovalDay.value); + const dep = p.earliestDepartureDay.value; + const earliestDeparture = dep === null ? null : addDays(surgeryDate, dep); + const lastOffset = dep ?? Math.max(14, ...p.outingLevels.map((l) => l.fromDay)); + const days: PlanDay[] = []; + const recent: string[] = []; + for (let off = -preOp; off <= lastOffset; off++) { + const date = addDays(surgeryDate, off); + const isHospital = nights !== null && off >= 0 && off < nights; + const pre = off < 0; + const level = pre ? 2 : isHospital ? 0 : stepAt(p.outingLevels, off).level; + const diet = pre ? 'normal' : stepAt(p.diet, off).type; + const recentSet = new Set(recent.slice(-6)); + const picks = level === 0 || off === 0 ? [] : pickForDay(places, level, diet, prefs, recentSet); + recent.push(...picks.map((x) => x.id)); + const dayFest = level >= 3 ? festivals.filter((f) => f.start <= date && f.end >= date).slice(0, 1) : []; // 행사는 자유 외출(L3) 날에만 + days.push({ date, offset: off, level, diet, picks, festivals: dayFest, isSurgery: off === 0, isHospital, isStitch: stitchDate === date, isArrival: off === -preOp, isDeparture: earliestDeparture === date }); + } + return { arriveBy, surgeryDate, dischargeDate, stitchDate, earliestDeparture, stayNights: dep === null ? null : preOp + dep, preOpDays: preOp, days }; +} + +// ---------- 예약 링크 (§13.7). 검색 결과 페이지 패턴만 쓴다. 제휴 ID 는 확정 후 aid 파라미터로 붙인다. ---------- +export function bookingUrl(query: string, checkin: string, checkout: string, lang: Lang, aid?: string): string { + const u = new URL('https://www.booking.com/searchresults.html'); + u.searchParams.set('ss', query); + u.searchParams.set('checkin', checkin); + u.searchParams.set('checkout', checkout); + u.searchParams.set('group_adults', '1'); + u.searchParams.set('no_rooms', '1'); + u.searchParams.set('lang', lang === 'ko' ? 'ko' : 'en-us'); + if (aid) u.searchParams.set('aid', aid); + return u.toString(); +} +export function googleFlightsUrl(arrive: string, depart: string, lang: Lang): string { + const q = `Flights to ICN on ${arrive} returning ${depart}`; + return `https://www.google.com/travel/flights?hl=${lang}&q=${encodeURIComponent(q)}`; +} +export function mapUrl(query: string): string { + return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(query)}`; +} + +// ---------- 공유 URL 해시 (서버 미전송) ---------- +export interface HashState { p?: string; d?: string; l?: Lang; n?: string; pref?: string[] } +export function encodeHash(s: HashState): string { + const q = new URLSearchParams(); + if (s.p) q.set('p', s.p); + if (s.d) q.set('d', s.d); + if (s.l) q.set('l', s.l); + if (s.n) q.set('n', s.n); + if (s.pref?.length) q.set('pref', s.pref.join(',')); + return q.toString(); +} +export function decodeHash(hash: string): HashState { + const q = new URLSearchParams(hash.replace(/^#/, '')); + const l = q.get('l'); + return { + p: q.get('p') ?? undefined, + d: isIsoDate(q.get('d')) ? (q.get('d') as string) : undefined, + l: l === 'ko' || l === 'en' ? l : undefined, + n: q.get('n') ?? undefined, + pref: (q.get('pref') ?? '').split(',').filter(Boolean), + }; +} + +// ---------- ICS (종일 일정 4개: 입국·수술·실밥·출국) ---------- +export function buildIcs(plan: Plan, titles: { arrive: string; surgery: string; stitch: string; departure: string }, calName: string): string { + const ev = (date: string, title: string, uid: string) => [ + 'BEGIN:VEVENT', `UID:${uid}@view-supporters`, `DTSTAMP:${new Date().toISOString().replace(/[-:]/g, '').slice(0, 15)}Z`, + `DTSTART;VALUE=DATE:${date.replace(/-/g, '')}`, `DTEND;VALUE=DATE:${addDays(date, 1).replace(/-/g, '')}`, `SUMMARY:${title}`, 'END:VEVENT', + ]; + const lines = ['BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//View Supporters//Recovery Planner//KO', `X-WR-CALNAME:${calName}`]; + lines.push(...ev(plan.arriveBy, titles.arrive, `arrive-${plan.arriveBy}`)); + lines.push(...ev(plan.surgeryDate, titles.surgery, `surgery-${plan.surgeryDate}`)); + if (plan.stitchDate) lines.push(...ev(plan.stitchDate, titles.stitch, `stitch-${plan.stitchDate}`)); + if (plan.earliestDeparture) lines.push(...ev(plan.earliestDeparture, titles.departure, `depart-${plan.earliestDeparture}`)); + lines.push('END:VCALENDAR'); + return lines.join('\r\n'); +} + +/** 상담 신청에 붙여 보낼 요약문. */ +export function summaryText(plan: Plan, p: Procedure, lang: Lang, t: Record): string { + const pending = t.pending; + const row = (k: string, v: string | null) => `${k}: ${v ?? pending}`; + return [ + `${t.summaryTitle} (${p.label[lang]})`, + row(t.arriveBy, plan.arriveBy), + row(t.surgery, plan.surgeryDate), + row(t.hospital, p.hospitalNights.value === null ? null : p.hospitalNights.value === 0 ? t.hospitalNone : t.hospitalNights.replace('{n}', String(p.hospitalNights.value))), + row(t.stitch, plan.stitchDate), + row(t.departure, plan.earliestDeparture), + row(t.stayNights, plan.stayNights === null ? null : t.nights.replace('{n}', String(plan.stayNights))), + ].join('\n'); +} diff --git a/supporters/src/lib/tour.ts b/supporters/src/lib/tour.ts new file mode 100644 index 0000000..25bf5b3 --- /dev/null +++ b/supporters/src/lib/tour.ts @@ -0,0 +1,89 @@ +// 한국관광공사 TourAPI 사전 수집 데이터(src/data/medicalTourism*.json)를 회복 일정 플래너의 장소·축제 후보로 바꾼다 (설계 v0.2 §13.5, 2순위 소스). +// 수집은 scripts/fetch_medical_tourism.py 가 병원 좌표 기준으로 미리 해 두고, 화면은 이 파일의 결과만 쓴다. 외부 호출 없음. +// 식이 적합성은 TourAPI 가 주지 않으므로 판정하지 않는다: 음식점은 일반식 단계에서만 후보가 되고, 죽·스무디 같은 회복 초기 식사는 큐레이션(places.json)이 맡는다. +import type { Place, L10n } from './plan'; + +export interface TourItem { + id: string; title: string; address: string; image: string | null; tel: string | null; lat: number; lng: number; + distanceM: number; travel: { mode: string; minutes: number; label: string } | null; overview: string; homepage: string; + startDate?: string; endDate?: string; season?: string; +} +export interface TourData { + places: Record; + festivals: TourItem[]; + meta: { lang?: string; source: string; fetchedAt: string; origin?: { lat: number; lng: number; label: string } }; +} + +/** TourAPI 유형 → 플래너 카테고리. wellness(사우나·스파)는 회복기 금지 항목이라 후보에서 뺀다. */ +const CATEGORY: Record = { attraction: 'sightseeing', culture: 'sightseeing', shopping: 'shopping', restaurant: 'food', stay: 'hotel', wellness: null }; + +/** 거리로 외출 등급을 정한다: 600m 안 근거리(L1), 3km 안 반나절(L2), 그 밖은 자유 외출(L3). */ +export const levelByDistance = (m: number): number => (m <= 600 ? 1 : m <= 3000 ? 2 : 3); + +const both = (s: string): L10n => ({ ko: s, en: s }); +/** 주소를 짧은 동네 표기로. 국문은 '구 도로명', 영문은 첫 쉼표 앞 도로명. */ +const areaLabel = (address: string, lang: 'ko' | 'en'): string => { + const a = (address || '').trim(); + if (lang === 'en') return a.split(',').map((x) => x.trim()).filter((x) => x && !/^\d+$/.test(x))[0] ?? a; + return a.replace(/^서울특별시\s*/, '').split(/\s+/).slice(0, 2).join(' '); +}; +const firstSentence = (s: string, n = 140): string => { + const t = (s || '').replace(/\d+\s*m?\s*NAVER\s*©\s*NAVER Corp\.?/gi, '').replace(/\s+/g, ' ').trim(); + if (t.length <= n) return t; + const cut = t.slice(0, n); + const stop = Math.max(cut.lastIndexOf('. '), cut.lastIndexOf('다. '), cut.lastIndexOf('。')); + return (stop > 40 ? cut.slice(0, stop + 1) : cut).trim() + (stop > 40 ? '' : '…'); +}; +/** "K-그랜드 호스텔 강남 1(K-GRAND HOSTEL GANGNAM1)" → 예약 검색용 영문 이름이 괄호 안에 있으면 그것을 쓴다. */ +export const bookingName = (title: string): string => { + const m = title.match(/\(([^)]*[A-Za-z][^)]*)\)\s*$/); + return (m ? m[1] : title).trim(); +}; + +export function tourToPlaces(data: TourData, lang: 'ko' | 'en'): Place[] { + const out: Place[] = []; + for (const [type, items] of Object.entries(data.places ?? {})) { + const category = CATEGORY[type]; + if (!category) continue; + for (const it of items) { + if (!it.lat || !it.lng) continue; + const km = Math.round((it.distanceM / 1000) * 10) / 10; + out.push({ + id: `tour-${type}-${it.id}`, + name: both(it.title), + category, + minLevel: category === 'hotel' ? 0 : levelByDistance(it.distanceM), + dietOk: category === 'food' ? ['normal'] : undefined, + distanceKm: km, + indoor: type === 'shopping' || type === 'culture' || type === 'restaurant' || type === 'stay', + area: both(areaLabel(it.address, lang)), + note: both(firstSentence(it.overview)), + mapQuery: it.title, + bookingQuery: category === 'hotel' ? bookingName(it.title) : undefined, + verify: true, + source: 'tourapi', + travelLabel: it.travel?.label ?? undefined, + image: it.image ?? undefined, + url: it.homepage || undefined, + }); + } + } + return out; +} + +export interface Festival { id: string; title: string; start: string; end: string; distanceKm: number; travelLabel?: string; blurb: string; image?: string; url?: string; address: string } +const iso = (d?: string) => (d && d.length === 8 ? `${d.slice(0, 4)}-${d.slice(4, 6)}-${d.slice(6, 8)}` : ''); + +/** 체류 기간 [from, to] 와 겹치는 행사만, 가까운 순. */ +export function festivalsDuring(data: TourData, from: string, to: string, max = 6): Festival[] { + return (data.festivals ?? []) + .map((f) => ({ f, start: iso(f.startDate), end: iso(f.endDate) })) + .filter((x) => x.start && x.end && x.start <= to && x.end >= from) + .sort((a, b) => a.f.distanceM - b.f.distanceM) + .slice(0, max) + .map(({ f, start, end }) => ({ + id: `fest-${f.id}`, title: f.title, start, end, distanceKm: Math.round((f.distanceM / 1000) * 10) / 10, + travelLabel: f.travel?.label ?? undefined, blurb: firstSentence(f.overview), image: f.image ?? undefined, + url: f.homepage || undefined, address: f.address, + })); +} diff --git a/supporters/src/pages/404.astro b/supporters/src/pages/404.astro new file mode 100644 index 0000000..dc28641 --- /dev/null +++ b/supporters/src/pages/404.astro @@ -0,0 +1,17 @@ +--- +// 없는 주소. Vercel 이 dist/404.html 을 자동으로 쓴다. 옛 주소(/recovery, /stay)는 vercel.json 리다이렉트가 /plan 으로 먼저 보낸다. +import Base from '../layouts/Base.astro'; +import { SITE_NAME } from '../lib'; +const site = Astro.site!.toString().replace(/\/$/, ''); +const ld = { '@type': 'WebPage', '@id': `${site}/404#page`, name: '페이지를 찾을 수 없음', url: `${site}/404`, inLanguage: 'ko', isPartOf: { '@id': `${site}/#website` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }; +--- + +
+ diff --git a/supporters/src/pages/en/plan.astro b/supporters/src/pages/en/plan.astro new file mode 100644 index 0000000..81e0bdf --- /dev/null +++ b/supporters/src/pages/en/plan.astro @@ -0,0 +1,16 @@ +--- +// Recovery planner, English page. Body lives in components/Planner.astro. Korean page is /plan. +import Base from '../../layouts/Base.astro'; +import Planner from '../../components/Planner.astro'; +import { fact, SITE_NAME, clinicSchema, v } from '../../lib'; +const f = fact as Record; +const clinicEn = (fact as Record).nameEn || (fact as Record).shortNameEn || (fact as Record).shortName || 'the clinic'; +const site = Astro.site!.toString().replace(/\/$/, ''); +const ld = [ + { '@type': 'WebPage', '@id': `${site}/en/plan#page`, name: `${clinicEn} Recovery Planner`, url: `${site}/en/plan`, inLanguage: 'en', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${fact.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, + clinicSchema(site), +]; +--- + + + diff --git a/supporters/src/pages/en/stay.astro b/supporters/src/pages/en/stay.astro deleted file mode 100644 index 5906845..0000000 --- a/supporters/src/pages/en/stay.astro +++ /dev/null @@ -1,440 +0,0 @@ ---- -// 외국인 환자용 체류 안내. 세 부분이다. -// 1. Around the clinic — 도보·차 소요 시간으로 거른 주변 장소 -// 2. Festivals — 계절로 묶은 행사 -// 3. Suggested days — 시간표와 지도가 붙은 동선 -// -// 데이터는 한국관광공사 TourAPI 영문(EngService2)에서 scripts/fetch_medical_tourism.py 가 -// 미리 수집한 src/data/medicalTourism.json 이다. 설명문은 detailCommon2 의 overview 다. -// -// 만들지 않는 것 -// - 평점·리뷰·영업시간: TourAPI 미제공. 싣지 않는다. -// - 링크: 공식 홈페이지가 있을 때만 걸고, 없으면 검색으로 보낸다. 주소를 지어내지 않는다. -// - 식이 적합성·회복 일수: 의학 판단이라 병원 확정값만 쓴다. -// - 일정의 시각: 진료 종료 시각을 가정으로 못박아 화면에 밝힌다. 병원 일정이 아니다. -import Base from '../../layouts/Base.astro'; -import { fact, site as S, SITE_NAME, clinicSchema, has } from '../../lib'; -import data from '../../data/medicalTourism.json'; - -const f = fact as Record; -const Sx = S as Record; -const clinic = f.shortNameEn || f.nameEn || f.shortName || 'the clinic'; -const site = Astro.site!.toString().replace(/\/$/, ''); -const T = data as any; - -type Place = { - id: string; title: string; address: string; image: string | null; overview: string; - homepage: string; lat: number | null; lng: number | null; distanceM: number | null; - travel: { mode: string; minutes: number; label: string } | null; -}; - -const GROUPS: Array<{ key: string; label: string; note: string }> = [ - { key: 'restaurant', label: 'Food', note: 'Restaurants and cafés' }, - { key: 'stay', label: 'Hotels', note: 'Places to sleep' }, - { key: 'wellness', label: 'Rest', note: 'Spas and jjimjilbang' }, - { key: 'attraction', label: 'Sights', note: 'Streets, parks, landmarks' }, - { key: 'culture', label: 'Culture', note: 'Museums, theatres, halls' }, - { key: 'shopping', label: 'Shopping', note: 'Stores and markets' }, -]; - -const SEASONS = [ - { key: 'spring', label: 'Spring' }, { key: 'summer', label: 'Summer' }, - { key: 'autumn', label: 'Autumn' }, { key: 'winter', label: 'Winter' }, -]; -const MONTHS = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; -const nowSeason = ['winter', 'winter', 'spring', 'spring', 'spring', 'summer', 'summer', 'summer', 'autumn', 'autumn', 'autumn', 'winter'][new Date().getMonth()]; - -// 검색으로 보낸다. 없는 URL 을 만들지 않는다. -const searchUrl = (q: string) => `https://www.google.com/search?q=${encodeURIComponent(q + ' Seoul')}`; -// 칩은 누적 임계값으로 거른다. 카드에 이동수단과 도보 분을 실어 두면 스크립트가 판단한다. -const dt = (d: string | null) => (d && d.length === 8 ? `${MONTHS[+d.slice(4, 6)]} ${+d.slice(6, 8)}` : ''); -// 사진이 없을 때 이름을 대신 넣는다. 빈 회색칸보다 낫고, 없는 사진을 지어내지도 않는다. -const shortName = (t: string) => { - const m = t.match(/\(([^)]+)\)\s*$/); - return (m ? m[1] : t).replace(/\s*\[.*\]\s*/g, '').trim(); -}; -const firstSentence = (s: string, n = 150) => { - if (!s) return ''; - const cut = s.slice(0, n); - const stop = cut.lastIndexOf('. '); - return (stop > 60 ? cut.slice(0, stop + 1) : cut) + (s.length > n ? '…' : ''); -}; - -/* ── 동선. 실제 데이터에서 만들고, 시각은 가정임을 화면에 밝힌다. ── */ -const oLat = T.meta.origin.lat, oLng = T.meta.origin.lng; -const pick = (key: string, maxMin: number, n: number): Place[] => - ((T.places[key] ?? []) as Place[]) - .filter((p) => p.travel && p.travel.mode === 'walk' && p.travel.minutes <= maxMin && p.lat) - .slice(0, n); -const pickAny = (key: string, n: number): Place[] => ((T.places[key] ?? []) as Place[]).filter((p) => p.lat).slice(0, n); - -const hhmm = (m: number) => `${String(Math.floor(m / 60) % 24).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`; -function buildRoute(startMin: number, stops: Array<{ p: Place | null; label: string; stay: number; note: string }>) { - let t = startMin; - const out: any[] = []; - stops.forEach((s, i) => { - const move = i === 0 ? 0 : (s.p?.travel?.minutes ?? 5); - t += move; - const from = t; - t += s.stay; - out.push({ ...s, moveMin: move, from: hhmm(from), to: hhmm(t), lat: s.p?.lat ?? oLat, lng: s.p?.lng ?? oLng }); - }); - return { stops: out, total: t - startMin, from: hhmm(startMin), to: hhmm(t) }; -} -const clinicStop = (label: string, stay: number, note: string) => ({ p: null, label, stay, note }); - -const ROUTES = [ - { - id: 'near', title: 'The day of a check-up', who: 'When you come back to the clinic often', - blurb: 'Everything within a short walk. You do not need a taxi.', - route: buildRoute(15 * 60, [ - clinicStop(clinic, 40, 'Your appointment ends here.'), - ...pick('restaurant', 10, 1).map((p) => ({ p, label: p.title, stay: 50, note: firstSentence(p.overview, 90) })), - ...pick('wellness', 12, 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'short', title: 'A short outing', who: 'When you can walk a little further', - blurb: 'Still close, but out of the block.', - route: buildRoute(13 * 60, [ - clinicStop(clinic, 20, 'Start from the clinic.'), - ...pickAny('shopping', 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ...pickAny('restaurant', 2).slice(1, 2).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'city', title: 'When you can travel', who: 'Later in your stay', - blurb: 'Sights across the city. Expect to take a taxi or the subway.', - route: buildRoute(10 * 60, [ - clinicStop(clinic, 10, 'Set off from the clinic.'), - ...pickAny('attraction', 2).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ...pickAny('culture', 1).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ]), - }, -].filter((r) => r.route.stops.length > 1); - -/* OpenStreetMap 타일을 좌표로 직접 깔아 지도를 만든다. 지도 라이브러리를 부르지 않는다. - 빈 회색 칸에 점만 찍으면 어디인지 알 수 없어서, 실제 거리·블록이 보이게 한다. - 타일은 OSM 정책상 출처를 반드시 표기한다. */ -const TILE = 256, MAPW = 680, MAPH = 340; -const lngToPx = (lng: number, z: number) => ((lng + 180) / 360) * TILE * 2 ** z; -const latToPx = (lat: number, z: number) => { - const r = (lat * Math.PI) / 180; - return ((1 - Math.log(Math.tan(r) + 1 / Math.cos(r)) / Math.PI) / 2) * TILE * 2 ** z; -}; - -function miniMap(stops: any[]) { - const lats = stops.map((s) => s.lat), lngs = stops.map((s) => s.lng); - const [la0, la1] = [Math.min(...lats), Math.max(...lats)]; - const [ln0, ln1] = [Math.min(...lngs), Math.max(...lngs)]; - // 모든 지점이 여백 안에 들어오는 가장 확대된 배율을 고른다. - let z = 17; - for (; z > 10; z--) { - const w = lngToPx(ln1, z) - lngToPx(ln0, z); - const h = latToPx(la0, z) - latToPx(la1, z); - if (w <= MAPW - 90 && h <= MAPH - 90) break; - } - const cx = (lngToPx(ln0, z) + lngToPx(ln1, z)) / 2; - const cy = (latToPx(la0, z) + latToPx(la1, z)) / 2; - const left = cx - MAPW / 2, top = cy - MAPH / 2; - const tiles: Array<{ src: string; x: number; y: number }> = []; - for (let tx = Math.floor(left / TILE); tx <= Math.floor((left + MAPW) / TILE); tx++) { - for (let ty = Math.floor(top / TILE); ty <= Math.floor((top + MAPH) / TILE); ty++) { - const n = 2 ** z; - if (tx < 0 || ty < 0 || tx >= n || ty >= n) continue; - tiles.push({ src: `https://tile.openstreetmap.org/${z}/${tx}/${ty}.png`, x: tx * TILE - left, y: ty * TILE - top }); - } - } - const pins = stops.map((s, i) => ({ - x: +(lngToPx(s.lng, z) - left).toFixed(1), - y: +(latToPx(s.lat, z) - top).toFixed(1), - n: i + 1, label: s.label, - })); - return { tiles, pins, z }; -} - -const allPlaces: Array = GROUPS.flatMap((g) => - ((T.places[g.key] ?? []) as Place[]).map((p) => ({ ...p, cat: g.key }))); - -const ld = [ - { '@type': 'WebPage', '@id': `${site}/en/stay#page`, name: `Your stay near ${clinic}`, url: `${site}/en/stay`, inLanguage: 'en', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${f.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, - clinicSchema(site), -]; ---- - -
-
-
For international patients
-

Your Stay in Seoul

-

- Around {clinic}. Everything below is measured from the clinic at {f.address?.fullEn || f.address?.full}. - Names, photographs and descriptions come from the Korea Tourism Organization. - For the clinic's own hours and phone, see Clinic informationKO. -

-
- - - - - - - - -
-
-

Around the clinic

- Updated {T.meta.fetchedAt.slice(0, 10)} -
-

{T.filters.total} places, sorted by how long they take to reach on foot.

- -
- - - - - -
- - {GROUPS.map((g) => { - const items = allPlaces.filter((p) => p.cat === g.key); - if (!items.length) return null; - return ( -
-

{g.label} {g.note}

-
- {items.map((p) => ( -
-
- {p.image ? {`${p.title} : {shortName(p.title)}} - {p.travel && {p.travel.label} {p.distanceM! < 1000 ? `${p.distanceM} m` : `${(p.distanceM! / 1000).toFixed(1)} km`}} -
-
-

{p.title}

-

{firstSentence(p.overview) || 'No description provided by the tourism data.'}

-

{p.address}

- {p.homepage - ? Official site ↗ - : Open in search ↗} -
-
- ))} -
-
- ); - })} -

Source · Korea Tourism Organization TourAPI. Walking time is estimated at 80 m per minute and is not a routed distance.

-
- - -
-

Festivals and events

-

{T.festivals.length} events within {T.meta.festivalRadiusKm} km, grouped by season. Right now it is {nowSeason}.

-
- - {SEASONS.map((s) => { - const n = T.festivals.filter((e: any) => e.season === s.key).length; - return n ? : null; - })} -
-
- {T.festivals.map((e: any) => ( -
-
- {e.image ? {`${e.title} : {shortName(e.title)}} - {MONTHS[e.month] ?? ''} -
-
-

{e.title}

-

{dt(e.startDate)} – {dt(e.endDate)} · {e.travel ? e.travel.label : `${e.distanceKm} km`}

-

{firstSentence(e.overview) || 'No description provided by the tourism data.'}

-

{e.address}

- Open in search ↗ -
-
- ))} -
-

Source · Korea Tourism Organization TourAPI. Dates can change at the organiser's discretion.

-
- - -
-

Shaping your days

-

- Three routes built from the places above. The clock times assume an appointment ending at the hour shown, and are an example, not your schedule. -

- {Sx.recoveryStagesEn - ?

What {clinic} advises. {Sx.recoveryStagesEn}

- :

Which of these you can do, and on which day, is a medical question. {clinic} has not yet published English guidance. Ask at your consultation.

} - - {ROUTES.map((r) => { - const pins = miniMap(r.route.stops); - return ( -
-
-
-

{r.title}

-

{r.who}

-
-
{r.route.from}–{r.route.to} · {Math.floor(r.route.total / 60)}h {r.route.total % 60}m
-
-

{r.blurb}

- - ); - })} -
- -
-

What this page does not tell you

-
    -
  • No ratings, review counts or opening hours. The tourism data does not carry them.
  • -
  • No claim that any place suits your recovery. That is for {clinic} to say.
  • -
  • English tourism listings around Gangnam are thin. Only {T.filters.walk5} places sit within a five minute walk, and {T.filters.drive} of {T.filters.total} need a car.
  • -
  • We are not a travel agency, take no booking and no commission.
  • -
-

- {has(f.urlEn) && Book a consultation in English} -

-

{f.sideEffectNoticeEn || f.sideEffectNotice}

-
-
- - - diff --git a/supporters/src/pages/plan.astro b/supporters/src/pages/plan.astro new file mode 100644 index 0000000..013ee36 --- /dev/null +++ b/supporters/src/pages/plan.astro @@ -0,0 +1,16 @@ +--- +// 회복기 스케줄러 한국어 페이지. 본문은 components/Planner.astro. 영어 페이지는 /en/plan. +import Base from '../layouts/Base.astro'; +import Planner from '../components/Planner.astro'; +import { fact, SITE_NAME, clinicSchema, v } from '../lib'; +const f = fact as Record; +const clinic = v(f.shortName, '병원'); +const site = Astro.site!.toString().replace(/\/$/, ''); +const ld = [ + { '@type': 'WebPage', '@id': `${site}/plan#page`, name: `${clinic} 회복 일정 플래너`, url: `${site}/plan`, inLanguage: 'ko', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${fact.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, + clinicSchema(site), +]; +--- + + + diff --git a/supporters/src/pages/sitemap.xml.ts b/supporters/src/pages/sitemap.xml.ts index f77671b..a357bd2 100644 --- a/supporters/src/pages/sitemap.xml.ts +++ b/supporters/src/pages/sitemap.xml.ts @@ -11,8 +11,8 @@ export const GET: APIRoute = async ({ site }) => { { loc: `${base}/posts`, lastmod: today }, { loc: `${base}/clinic`, lastmod: today }, { loc: `${base}/visit`, lastmod: today }, - { loc: `${base}/stay`, lastmod: today }, - { loc: `${base}/en/stay`, lastmod: today }, + { loc: `${base}/plan`, lastmod: today }, + { loc: `${base}/en/plan`, lastmod: today }, { loc: `${base}/newsroom`, lastmod: today }, { loc: `${base}/videos`, lastmod: today }, { loc: `${base}/about`, lastmod: today }, diff --git a/supporters/src/pages/stay.astro b/supporters/src/pages/stay.astro deleted file mode 100644 index 99e2bb8..0000000 --- a/supporters/src/pages/stay.astro +++ /dev/null @@ -1,445 +0,0 @@ ---- -// 병원 주변 안내(한국어). /en/stay 의 한국어 짝이다. 데이터는 국문 서비스(KorService2)라 -// 영문보다 훨씬 많다(음식점 338건·숙박 43건 대 18건·4건). -// 구조는 /en/stay 와 같다. 세 부분이다. -// 1. 병원 주변 — 도보·차 소요 시간으로 거른 주변 장소 -// 2. Festivals — 계절로 묶은 행사 -// 3. Suggested days — 시간표와 지도가 붙은 동선 -// -// 데이터는 한국관광공사 TourAPI 영문(EngService2)에서 scripts/fetch_medical_tourism.py 가 -// 미리 수집한 src/data/medicalTourism.json 이다. 설명문은 detailCommon2 의 overview 다. -// -// 만들지 않는 것 -// - 평점·리뷰·영업시간: TourAPI 미제공. 싣지 않는다. -// - 링크: 공식 홈페이지가 있을 때만 걸고, 없으면 검색으로 보낸다. 주소를 지어내지 않는다. -// - 식이 적합성·회복 일수: 의학 판단이라 병원 확정값만 쓴다. -// - 일정의 시각: 진료 종료 시각을 가정으로 못박아 화면에 밝힌다. 병원 일정이 아니다. -import Base from '../layouts/Base.astro'; -import { fact, site as S, SITE_NAME, clinicSchema, has, v, reservationUrl } from '../lib'; -import data from '../data/medicalTourismKo.json'; - -const f = fact as Record; -const Sx = S as Record; -const clinic = f.shortName || '병원'; -const site = Astro.site!.toString().replace(/\/$/, ''); -const T = data as any; - -type Place = { - id: string; title: string; address: string; image: string | null; overview: string; - homepage: string; lat: number | null; lng: number | null; distanceM: number | null; - travel: { mode: string; minutes: number; label: string } | null; -}; - -const GROUPS: Array<{ key: string; label: string; note: string }> = [ - { key: 'restaurant', label: '식사', note: '음식점과 카페' }, - { key: 'stay', label: '숙박', note: '묵을 곳' }, - { key: 'wellness', label: '휴식', note: '스파와 찜질방' }, - { key: 'attraction', label: '관광', note: '거리, 공원, 명소' }, - { key: 'culture', label: '문화', note: '미술관, 공연장' }, - { key: 'shopping', label: '쇼핑', note: '백화점과 시장' }, -]; - -const SEASONS = [ - { key: 'spring', label: '봄' }, { key: 'summer', label: '여름' }, - { key: 'autumn', label: '가을' }, { key: 'winter', label: '겨울' }, -]; -const MONTHS = ['', '1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']; -const nowSeasonKey = ['winter', 'winter', 'spring', 'spring', 'spring', 'summer', 'summer', 'summer', 'autumn', 'autumn', 'autumn', 'winter'][new Date().getMonth()]; -const nowSeason = ({ spring: '봄', summer: '여름', autumn: '가을', winter: '겨울' } as Record)[nowSeasonKey]; - -// 검색으로 보낸다. 없는 URL 을 만들지 않는다. -// 없는 URL 을 만들지 않는다. 공식 홈페이지가 없으면 검색으로 보낸다. -const searchUrl = (q: string) => `https://search.naver.com/search.naver?query=${encodeURIComponent(q)}`; -// 칩은 누적 임계값으로 거른다. 카드에 이동수단과 도보 분을 실어 두면 스크립트가 판단한다. -const dt = (d: string | null) => (d && d.length === 8 ? `${+d.slice(4, 6)}.${+d.slice(6, 8)}` : ''); -// 사진이 없을 때 이름을 대신 넣는다. 빈 회색칸보다 낫고, 없는 사진을 지어내지도 않는다. -const shortName = (t: string) => { - const m = t.match(/\(([^)]+)\)\s*$/); - return (m ? m[1] : t).replace(/\s*\[.*\]\s*/g, '').trim(); -}; -// travel.label 은 데이터에 영문으로 들어 있다. 한국어 화면에서는 여기서 만든다. -const travelLabel = (t: { mode: string; minutes: number } | null) => - !t ? '' : t.mode === 'walk' ? `도보 ${t.minutes}분` : `차로 ${t.minutes}분`; -const firstSentence = (s: string, n = 150) => { - if (!s) return ''; - const cut = s.slice(0, n); - const stop = cut.lastIndexOf('. '); - return (stop > 60 ? cut.slice(0, stop + 1) : cut) + (s.length > n ? '…' : ''); -}; - -/* ── 동선. 실제 데이터에서 만들고, 시각은 가정임을 화면에 밝힌다. ── */ -const oLat = T.meta.origin.lat, oLng = T.meta.origin.lng; -const pick = (key: string, maxMin: number, n: number): Place[] => - ((T.places[key] ?? []) as Place[]) - .filter((p) => p.travel && p.travel.mode === 'walk' && p.travel.minutes <= maxMin && p.lat) - .slice(0, n); -const pickAny = (key: string, n: number): Place[] => ((T.places[key] ?? []) as Place[]).filter((p) => p.lat).slice(0, n); - -const hhmm = (m: number) => `${String(Math.floor(m / 60) % 24).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`; -function buildRoute(startMin: number, stops: Array<{ p: Place | null; label: string; stay: number; note: string }>) { - let t = startMin; - const out: any[] = []; - stops.forEach((s, i) => { - const move = i === 0 ? 0 : (s.p?.travel?.minutes ?? 5); - t += move; - const from = t; - t += s.stay; - out.push({ ...s, moveMin: move, from: hhmm(from), to: hhmm(t), lat: s.p?.lat ?? oLat, lng: s.p?.lng ?? oLng }); - }); - return { stops: out, total: t - startMin, from: hhmm(startMin), to: hhmm(t) }; -} -const clinicStop = (label: string, stay: number, note: string) => ({ p: null, label, stay, note }); - -const ROUTES = [ - { - id: 'near', title: 'The day of a check-up', who: 'When you come back to the clinic often', - blurb: 'Everything within a short walk. You do not need a taxi.', - route: buildRoute(15 * 60, [ - clinicStop(clinic, 40, 'Your appointment ends here.'), - ...pick('restaurant', 10, 1).map((p) => ({ p, label: p.title, stay: 50, note: firstSentence(p.overview, 90) })), - ...pick('wellness', 12, 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'short', title: 'A short outing', who: 'When you can walk a little further', - blurb: 'Still close, but out of the block.', - route: buildRoute(13 * 60, [ - clinicStop(clinic, 20, 'Start from the clinic.'), - ...pickAny('shopping', 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ...pickAny('restaurant', 2).slice(1, 2).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'city', title: 'When you can travel', who: 'Later in your stay', - blurb: 'Sights across the city. Expect to take a taxi or the subway.', - route: buildRoute(10 * 60, [ - clinicStop(clinic, 10, 'Set off from the clinic.'), - ...pickAny('attraction', 2).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ...pickAny('culture', 1).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ]), - }, -].filter((r) => r.route.stops.length > 1); - -/* OpenStreetMap 타일을 좌표로 직접 깔아 지도를 만든다. 지도 라이브러리를 부르지 않는다. - 빈 회색 칸에 점만 찍으면 어디인지 알 수 없어서, 실제 거리·블록이 보이게 한다. - 타일은 OSM 정책상 출처를 반드시 표기한다. */ -const TILE = 256, MAPW = 680, MAPH = 340; -const lngToPx = (lng: number, z: number) => ((lng + 180) / 360) * TILE * 2 ** z; -const latToPx = (lat: number, z: number) => { - const r = (lat * Math.PI) / 180; - return ((1 - Math.log(Math.tan(r) + 1 / Math.cos(r)) / Math.PI) / 2) * TILE * 2 ** z; -}; - -function miniMap(stops: any[]) { - const lats = stops.map((s) => s.lat), lngs = stops.map((s) => s.lng); - const [la0, la1] = [Math.min(...lats), Math.max(...lats)]; - const [ln0, ln1] = [Math.min(...lngs), Math.max(...lngs)]; - // 모든 지점이 여백 안에 들어오는 가장 확대된 배율을 고른다. - let z = 17; - for (; z > 10; z--) { - const w = lngToPx(ln1, z) - lngToPx(ln0, z); - const h = latToPx(la0, z) - latToPx(la1, z); - if (w <= MAPW - 90 && h <= MAPH - 90) break; - } - const cx = (lngToPx(ln0, z) + lngToPx(ln1, z)) / 2; - const cy = (latToPx(la0, z) + latToPx(la1, z)) / 2; - const left = cx - MAPW / 2, top = cy - MAPH / 2; - const tiles: Array<{ src: string; x: number; y: number }> = []; - for (let tx = Math.floor(left / TILE); tx <= Math.floor((left + MAPW) / TILE); tx++) { - for (let ty = Math.floor(top / TILE); ty <= Math.floor((top + MAPH) / TILE); ty++) { - const n = 2 ** z; - if (tx < 0 || ty < 0 || tx >= n || ty >= n) continue; - tiles.push({ src: `https://tile.openstreetmap.org/${z}/${tx}/${ty}.png`, x: tx * TILE - left, y: ty * TILE - top }); - } - } - const pins = stops.map((s, i) => ({ - x: +(lngToPx(s.lng, z) - left).toFixed(1), - y: +(latToPx(s.lat, z) - top).toFixed(1), - n: i + 1, label: s.label, - })); - return { tiles, pins, z }; -} - -const allPlaces: Array = GROUPS.flatMap((g) => - ((T.places[g.key] ?? []) as Place[]).map((p) => ({ ...p, cat: g.key }))); - -const ld = [ - { '@type': 'WebPage', '@id': `${site}/stay#page`, name: `${clinic} 주변 안내`, url: `${site}/stay`, inLanguage: 'ko', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${f.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, - clinicSchema(site), -]; ---- - -
-
-
병원 주변
-

병원 주변 안내

-

- {clinic} 주변입니다. 아래 거리와 시간은 모두 {v(f.address?.full)} 기준입니다. - 상호와 사진, 설명은 한국관광공사 자료입니다. 병원의 진료시간과 전화는 병원 정보에 있습니다. -

-
- - - - - - - - -
-
-

병원 주변

- {T.meta.fetchedAt.slice(0, 10)} 갱신 -
-

{T.filters.total}곳입니다. 병원에서 걸어가는 시간 순으로 놓았습니다.

- -
- - - - - -
- - {GROUPS.map((g) => { - const items = allPlaces.filter((p) => p.cat === g.key); - if (!items.length) return null; - return ( -
-

{g.label} {g.note}

-
- {items.map((p) => ( -
-
- {p.image ? {`${p.title} : {shortName(p.title)}} - {p.travel && {travelLabel(p.travel)} {p.distanceM! < 1000 ? `${p.distanceM} m` : `${(p.distanceM! / 1000).toFixed(1)} km`}} -
-
-

{p.title}

-

{firstSentence(p.overview) || '관광 자료에 설명이 없습니다.'}

-

{p.address}

- {p.homepage - ? 공식 홈페이지 ↗ - : 검색으로 열기 ↗} -
-
- ))} -
-
- ); - })} -

출처 · 한국관광공사 TourAPI. 도보 시간은 분당 80m로 어림한 값이며 실제 경로 거리가 아닙니다.

-
- - -
-

계절별 축제

-

{T.meta.festivalRadiusKm}km 안의 행사 {T.festivals.length}건을 계절로 묶었습니다. 지금은 {nowSeason}입니다.

-
- - {SEASONS.map((s) => { - const n = T.festivals.filter((e: any) => e.season === s.key).length; - return n ? : null; - })} -
-
- {T.festivals.map((e: any) => ( -
-
- {e.image ? {`${e.title} : {shortName(e.title)}} - {MONTHS[e.month] ?? ''} -
-
-

{e.title}

-

{dt(e.startDate)} – {dt(e.endDate)} · {e.travel ? travelLabel(e.travel) : `${e.distanceKm}km`}

-

{firstSentence(e.overview) || '관광 자료에 설명이 없습니다.'}

-

{e.address}

- 검색으로 열기 ↗ -
-
- ))} -
-

출처 · 한국관광공사 TourAPI. 일정은 주최 측 사정으로 바뀔 수 있습니다.

-
- - -
-

하루 동선

-

- 위 장소들로 짠 동선 세 가지입니다. 시각은 진료가 그 시각에 끝난다고 가정한 예시이며 실제 일정이 아닙니다. -

- {Sx.recoveryStagesKo - ?

{clinic} 안내. {Sx.recoveryStagesKo}

- :

어느 날 무엇을 해도 되는지는 의학 판단이라 {clinic}이 정합니다. 아직 확인 대기입니다. 상담 때 확인하세요.

} - - {ROUTES.map((r) => { - const pins = miniMap(r.route.stops); - return ( -
-
-
-

{r.title}

-

{r.who}

-
-
{r.route.from}–{r.route.to} · {Math.floor(r.route.total / 60)}h {r.route.total % 60}m
-
-

{r.blurb}

- - ); - })} -
- -
-

이 페이지가 답하지 못하는 것

-
    -
  • 평점·리뷰 수·영업시간은 없습니다. 관광 자료가 주지 않습니다.
  • -
  • 어떤 곳이 회복에 맞는지는 말하지 않습니다. {clinic}이 정할 일입니다.
  • -
  • 도보 5분 안에는 {T.filters.walk5}곳뿐이고, {T.filters.total}곳 중 {T.filters.drive}곳은 차로 가야 합니다.
  • -
  • 여행사가 아닙니다. 예약을 받지 않고 수수료도 받지 않습니다.
  • -
-

- {has(reservationUrl) && {clinic} 상담 예약} -

-

{f.sideEffectNoticeEn || f.sideEffectNotice}

-
-
- - - diff --git a/supporters/src/pages/visit.astro b/supporters/src/pages/visit.astro index e3c9c21..e61e25a 100644 --- a/supporters/src/pages/visit.astro +++ b/supporters/src/pages/visit.astro @@ -42,7 +42,7 @@ const ld = [ {!(S.visitReads ?? []).length &&
  • 검토를 마친 글부터 차례로 연결합니다.
  • }

    6. 해외에서 오시는 경우

    -

    수술 전후에 머무는 동안의 숙박·식사·회복·관광 정보를 영문으로 정리했습니다. Your Stay in Seoul.

    +

    수술 전후에 머무는 동안의 숙박·식사·회복·관광 정보를 영문으로 정리했습니다. Recovery Planner.

    {has(reservationUrl) && {clinic} 상담 예약}

    {fact.sideEffectNotice}

    diff --git a/supporters/src/styles/global.css b/supporters/src/styles/global.css index eb8ebca..bf77bc9 100644 --- a/supporters/src/styles/global.css +++ b/supporters/src/styles/global.css @@ -387,6 +387,24 @@ td { color: var(--slate-700); } .stay .timeline h4 { margin: 0.1rem 0 0.2rem; font-size: 0.98rem; } .stay .timeline p { margin: 0; font-size: 0.86rem; color: var(--slate-600, #475569); } .stay .botnote { margin-top: 1.6rem; } +/* 시술 후 관리 안내(병원 원문 인용). 동선 카드(.route)·정차(.stop) 룩을 그대로 쓰고 접이식 동작만 더한다. 새 색·크기 없음. */ +.stay details.recovery > summary.btn { list-style: none; cursor: pointer; } +.stay details.recovery > summary.btn::-webkit-details-marker { display: none; } +.stay details.recovery > summary.btn .hide { display: none; } +.stay details.recovery[open] > summary.btn .show { display: none; } +.stay details.recovery[open] > summary.btn .hide { display: inline; } +.stay details.recovery[open] > summary.btn { margin-bottom: 1.1rem; } +.stay details.recovery > .timeline { margin-top: 0.2rem; } +.stay .recovery .timeline > li { border-top: 1px solid var(--line, #E2E8F0); padding: 0.7rem 0; } +.stay .recovery .timeline > li:first-child { border-top: 0; padding-top: 0; } +.stay .recovery summary { cursor: pointer; list-style: none; } +.stay .recovery summary::-webkit-details-marker { display: none; } +.stay .recovery summary .stop { display: flex; } +.stay .recovery summary h4 { margin: 0.1rem 0 0; } +.stay .recovery details[open] summary h4 { text-decoration: underline; text-underline-offset: 0.2em; text-decoration-color: var(--slate-200, #E2E8F0); } +.stay .recovery details > ul { margin: 0.7rem 0 0.5rem 2.2rem; padding-left: 1.1rem; } +.stay .recovery details > ul li { font-size: 0.9rem; color: var(--slate-700, #334155); margin-bottom: 0.35rem; } +.stay .recovery details > p { margin: 0 0 0 2.2rem; font-size: 0.84rem; color: var(--slate-500, #64748B); } @media (max-width: 640px) { .cards { grid-template-columns: 1fr; } } /* 섹션 점프. 머리말 아래에 붙어 스크롤을 따라온다. 헤더(68px) 아래에 걸리게 top 을 맞춘다. */ diff --git a/supporters/src/styles/plan.css b/supporters/src/styles/plan.css new file mode 100644 index 0000000..2c10821 --- /dev/null +++ b/supporters/src/styles/plan.css @@ -0,0 +1,172 @@ +/* 회복기 스케줄러 (/plan, /en/plan). 섹션 리듬·카드·통계는 global.css 의 .section/.sec-head/.grid/.card/.stats/.stat 을 그대로 쓰고, + 여기에는 입력 컨트롤·타임라인·배지처럼 이 페이지에만 있는 요소만 둔다. 흰 배경 강조는 인디고, 연보라는 다크 전용. */ +:root { --indigo: #1D0024; } + +/* 히어로 (다크, videos.astro 규격) */ +.plan-hero { padding: 3.5rem 0 3rem; } +.plan-hero h1 { font-family: "Playfair Display", Georgia, serif; font-size: 2.3rem; font-weight: 700; letter-spacing: 0; line-height: 1.15; display: inline-block; background: linear-gradient(to right, var(--purple-300), var(--blue-300)); -webkit-background-clip: text; background-clip: text; color: transparent; margin: 0; } +.plan-hero .lede { color: rgba(255,255,255,0.82); font-size: 1.02rem; max-width: 760px; margin: 0.6rem 0 0; } +.plan-hero .lede strong { color: #fff; } +.lang-links a { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.45rem 1rem 0.45rem 0.55rem; border-radius: 999px; background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.16); color: #fff; text-decoration: none; font-size: 0.9rem; font-weight: 600; } +.lang-links a .ico { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 999px; background: rgba(255,255,255,0.12); font-family: Inter, sans-serif; font-size: 0.66rem; letter-spacing: 0.06em; color: var(--purple-200); } +.lang-links a.on { background: linear-gradient(to right, var(--grad-start), var(--grad-end)); border-color: transparent; } +.lang-links a.on .ico { background: rgba(255,255,255,0.2); color: #fff; } +.lang-links a:hover { text-decoration: none; border-color: rgba(216,180,254,0.6); } +.plan-hero .stats { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); } + +/* 입력 단계 카드 (틴트 섹션) */ +.steps-grid { display: grid; grid-template-columns: minmax(260px, 1fr) 2fr; gap: 1.25rem; } +.steps-grid .card.span { grid-column: 1 / -1; } +@media (max-width: 860px) { .steps-grid { grid-template-columns: 1fr; } } +.card .cat.step { display: inline-flex; align-items: center; gap: 0.45rem; } +.card .cat.step .n { display: inline-grid; place-items: center; width: 1.35rem; height: 1.35rem; border-radius: 999px; background: linear-gradient(to right, var(--grad-start), var(--grad-end)); color: #fff; font-family: "Playfair Display", Georgia, serif; font-size: 0.8rem; font-weight: 700; } +.card h3.serif { font-family: "Playfair Display", Georgia, serif; font-size: 1.12rem; } +.card .sub2 { font-size: 0.88rem; color: var(--slate-600); margin: 0; flex: 0; } +.card .hint { font-size: 0.83rem; color: var(--slate-500); margin: 0.4rem 0 0; flex: 0; } +.field { display: grid; gap: 0.35rem; margin-top: 0.5rem; } +.field label { font-size: 0.82rem; font-weight: 600; color: var(--slate-600); } +.field select, .field input[type="date"] { font: inherit; font-size: 1rem; padding: 0.6rem 0.8rem; border: 1px solid var(--slate-200); border-radius: 12px; background: #fff; color: var(--indigo); max-width: 320px; } +.lang-inline a { border: 1px solid var(--slate-200); background: #fff; color: var(--slate-600); border-radius: 999px; padding: 0.35rem 0.9rem; font-size: 0.85rem; font-weight: 600; text-decoration: none; } +.lang-inline a.on { background: var(--primary-900); color: #fff; border-color: var(--primary-900); } + +.proc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.55rem; } +.proc-grid button { text-align: left; border: 1px solid var(--slate-200); background: #fff; border-radius: 14px; padding: 0.7rem 0.85rem; font: inherit; cursor: pointer; color: var(--indigo); display: grid; gap: 0.1rem; } +.proc-grid button small { color: var(--slate-500); font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase; font-family: Inter, Pretendard, sans-serif; } +.proc-grid button b { font-size: 0.95rem; font-weight: 700; } +.proc-grid button.on { border-color: var(--accent); background: var(--st-good-bg); box-shadow: 0 0 0 2px rgba(108,92,231,0.25) inset; } + +.pref-row { display: flex; flex-wrap: wrap; gap: 0.5rem; } +.pref-row button { border: 1px solid var(--slate-200); background: #fff; color: var(--indigo); border-radius: 999px; padding: 0.5rem 1rem; font: inherit; font-size: 0.92rem; font-weight: 600; cursor: pointer; } +.pref-row button.on { background: linear-gradient(to right, var(--grad-start), var(--grad-end)); color: #fff; border-color: transparent; } + +.plan-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; margin-top: 1rem; } +.btn.small { padding: 0.55rem 1rem; font-size: 0.88rem; } +.btn.ghost { background: #fff; color: var(--indigo); border: 1px solid var(--slate-200); } +button.btn { font: inherit; cursor: pointer; border: 0; } + +/* 빈 상태 (다크) */ +.empty { text-align: center; padding: 2.4rem 1rem; border: 1px dashed rgba(255,255,255,0.25); border-radius: 16px; color: rgba(255,255,255,0.75); } +.empty b { display: block; color: #fff; font-size: 1.1rem; margin-bottom: 0.3rem; } + +/* 배지 */ +.tag { display: inline-block; font-size: 0.72rem; font-weight: 700; padding: 0.12rem 0.55rem; border-radius: 999px; border: 1px solid transparent; vertical-align: middle; white-space: nowrap; } +.tag.prov { background: var(--st-warning-bg); color: var(--st-warning-text); border-color: var(--st-warning-border); } +.tag.clinic { background: var(--st-good-bg); color: var(--st-good-text); border-color: var(--st-good-border); } +.tag.l0 { background: var(--st-critical-bg); color: var(--st-critical-text); border-color: var(--st-critical-border); } +.tag.l1 { background: var(--st-warning-bg); color: var(--st-warning-text); border-color: var(--st-warning-border); } +.tag.l2 { background: var(--st-info-bg); color: var(--st-info-text); border-color: var(--st-info-border); } +.tag.l3 { background: var(--st-good-bg); color: var(--st-good-text); border-color: var(--st-good-border); } +.tag.diet { background: var(--slate-100); color: var(--slate-700); } + +/* 다크 섹션 핵심 날짜: 글래스 통계 카드 변형 */ +.stats.dates { grid-template-columns: repeat(3, minmax(0, 1fr)); } +.stats.dates .stat { display: flex; flex-direction: column; } +.stats.dates .stat .label { order: -1; margin: 0 0 0.35rem; font-size: 0.8rem; color: rgba(255,255,255,0.72); font-weight: 600; letter-spacing: 0.02em; } +.stats.dates .stat b { font-size: 1.75rem; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem; } +.stats.dates .stat b .wd { font-family: Pretendard, Inter, sans-serif; font-size: 0.85rem; font-weight: 600; color: rgba(255,255,255,0.7); } +.stats.dates .stat b .txt { font-family: Pretendard, Inter, sans-serif; font-size: 1.15rem; color: #fff; } +.stats.dates .stat .desc { margin-top: 0.55rem; } +.stats.dates .tag.clinic { background: rgba(175,144,255,0.18); color: var(--purple-200); border-color: rgba(216,180,254,0.45); } +.section.dark .note { color: rgba(255,255,255,0.72); font-size: 0.88rem; margin: 1.2rem 0 0; max-width: 900px; } +.section.dark .note a { color: var(--purple-300); } + +/* 라이트 섹션 카드 내용 */ +.card ul.rules { margin: 0.2rem 0 0; padding-left: 1.15rem; font-size: 0.92rem; color: var(--slate-700); } +.card ul.rules li { margin-bottom: 0.4rem; } +.card.ok { background: var(--st-good-bg); border-color: var(--st-good-border); } +.card.warn { background: var(--st-warning-bg); border-color: var(--st-warning-border); } +.card.warn h3, .card.warn p { color: var(--st-warning-text); } +.card.ok h3, .card.ok p { color: var(--st-good-text); } +.card .fine { font-size: 0.8rem; color: var(--slate-500); margin-top: 0.3rem; flex: 0; } +.card.warn .fine, .card.ok .fine { color: inherit; opacity: 0.85; } + +/* 타임라인 (틴트 섹션 위 흰 카드) */ +.legend { display: flex; flex-wrap: wrap; gap: 0.5rem 1.2rem; font-size: 0.85rem; color: var(--slate-600); margin: 0 0 1.25rem; } +.legend span { display: inline-flex; align-items: center; gap: 0.35rem; } +.timeline { display: grid; gap: 1.1rem; } +.day { display: grid; grid-template-columns: 160px 1fr; gap: 0.6rem 1.2rem; align-items: start; padding: 1rem 1.2rem; border-radius: 16px; border: 1px solid var(--slate-100); background: #fff; box-shadow: var(--shadow); } +.day.mark { border-color: var(--st-good-border); background: #FBFAFF; } +.day .d { display: grid; gap: 0.1rem; } +.day .d b { color: var(--primary-900); font-size: 1rem; font-family: "Playfair Display", Georgia, serif; font-weight: 700; } +.day .d span { font-size: 0.78rem; color: var(--slate-500); } +.day .d .ev { font-size: 0.78rem; font-weight: 700; color: var(--grad-start); } +.day .body { display: grid; gap: 0.45rem; } +.day .tags { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; } +.day .tags .desc { font-size: 0.85rem; color: var(--slate-600); } +.day .picks { display: flex; flex-wrap: wrap; gap: 0.4rem; } +.day .picks a, .day .picks span.pick { display: inline-flex; align-items: center; gap: 0.35rem; border: 1px solid var(--slate-200); border-radius: 999px; padding: 0.3rem 0.75rem; font-size: 0.85rem; color: var(--indigo); background: #fff; } +.day .picks a:hover { border-color: var(--accent); text-decoration: none; } +.day .picks small { color: var(--slate-500); font-size: 0.72rem; } +.day .rest { font-size: 0.88rem; color: var(--slate-500); } +@media (max-width: 640px) { .day { grid-template-columns: 1fr; } } + +/* 체류 기간의 행사 카드 (TourAPI 이미지) */ +.fest-card { padding: 0; overflow: hidden; } +.fest-card img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block; } +.fest-card .cat, .fest-card h3, .fest-card p { margin-left: 1.5rem; margin-right: 1.5rem; } +.fest-card .cat { margin-top: 1.2rem; } +.fest-card > p:last-child { margin-bottom: 1.3rem; } +.day .picks a.fest { border-color: var(--st-good-border); background: var(--st-good-bg); } + +/* 예약 (다크 섹션 위 흰 카드) */ +.hotel-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1.25rem; } +.hotel-grid .card small { color: var(--slate-500); font-size: 0.78rem; } +.hotel-grid .card .links { display: flex; gap: 0.7rem; flex-wrap: wrap; font-size: 0.85rem; font-weight: 600; } +.book-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.25rem; margin-top: 1.5rem; } +.book-row .card .plan-actions { margin-top: 0.4rem; } +.section.dark .disclosure { color: rgba(255,255,255,0.6); border-top-color: rgba(255,255,255,0.12); } +.section.dark .disclosure a, .section.dark .sources-list a { color: var(--purple-300); } +.section.dark .sources-list { font-size: 0.85rem; color: rgba(255,255,255,0.7); margin: 0.3rem 0 0; } + +.toast { position: fixed; left: 50%; bottom: 2rem; transform: translateX(-50%); background: var(--primary-900); color: #fff; padding: 0.6rem 1.1rem; border-radius: 999px; font-size: 0.9rem; opacity: 0; transition: opacity 0.2s; pointer-events: none; z-index: 20; } +.toast.show { opacity: 1; } + +/* 방문 안내 진입 CTA 카드 (웜 그라디언트는 CTA 카드 한 장에만) */ +.plan-entry { background: linear-gradient(to right, #fff3eb, #e4cfff, #f5f9ff); border-radius: 16px; padding: 1.3rem 1.5rem; box-shadow: var(--shadow); margin: 2rem 0; display: grid; gap: 0.4rem; } +.plan-entry h2 { margin: 0; font-size: 1.1rem; color: var(--indigo); } +.plan-entry p { margin: 0; color: var(--slate-700); font-size: 0.95rem; } +.plan-entry .btn { justify-self: start; margin-top: 0.4rem; } + +/* 태블릿 (≤900px): 히어로 통계 2열 */ +@media (max-width: 900px) { .plan-hero .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } } + +/* 모바일 (≤720px): 통계·날짜 카드 2열, 타임라인 날짜 머리 가로 배치, 히어로 여백 축소 */ +@media (max-width: 720px) { + .plan-hero h1 { font-size: 1.9rem; } + .plan-hero .lede { font-size: 0.95rem; } + .plan-hero .stats, .stats.dates { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem; } + .plan-hero .stat, .stats.dates .stat { padding: 1.2rem 1.2rem; } + .plan-hero .stat b { font-size: 1.8rem; } + .plan-hero .stat .label { font-size: 0.9rem; } + .plan-hero .stat .desc { font-size: 0.78rem; } + .stats.dates .stat b { font-size: 1.35rem; } + .stats.dates .stat .desc { font-size: 0.78rem; } + .field select, .field input[type="date"] { max-width: none; width: 100%; font-size: 16px; } + .proc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .day { gap: 0.5rem; } + .day .d { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.2rem 0.6rem; } + .day .picks a, .day .picks span.pick { font-size: 0.82rem; padding: 0.3rem 0.65rem; } + .book-row { grid-template-columns: 1fr; } + .hotel-grid { grid-template-columns: 1fr; } + .plan-result-pad { padding-bottom: 4.5rem; } +} + +/* 하단 고정 요약 바 (모바일에서 결과가 있을 때만) */ +.sticky-bar { display: none; } +@media (max-width: 720px) { + .sticky-bar { position: fixed; left: 0.8rem; right: 4.2rem; bottom: 0.9rem; z-index: 15; display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; background: var(--primary-900); color: #fff; border-radius: 999px; padding: 0.55rem 0.6rem 0.55rem 1rem; box-shadow: 0 10px 28px rgba(2,19,65,0.35); transition: opacity 0.2s, transform 0.2s; } + .sticky-bar[hidden] { display: none; } + .sticky-bar .s { display: grid; line-height: 1.2; min-width: 0; } + .sticky-bar .s b { font-family: "Playfair Display", Georgia, serif; font-size: 0.95rem; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .sticky-bar .s small { font-size: 0.7rem; color: var(--purple-200); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .sticky-bar button { flex: none; border: 0; border-radius: 999px; background: linear-gradient(to right, var(--grad-start), #6C5CE7); color: #fff; font: inherit; font-size: 0.82rem; font-weight: 700; padding: 0.5rem 0.9rem; cursor: pointer; } +} + +@media print { + .site-header, .backbar-wrap, .totop, .site-footer, .sample-banner, .plan-input, .plan-actions, .toast, .lang-links, .sticky-bar { display: none !important; } + .section { padding: 1rem 0 !important; } + .section.dark, .section.tint { background: #fff !important; color: var(--primary-900); } + .section.dark .sec-head h2, .plan-hero h1 { -webkit-text-fill-color: var(--primary-900); background: none; } + .stat { background: #fff; border: 1px solid var(--slate-200); } .stat b { color: var(--primary-900); } .stat .label, .stat .desc { color: var(--slate-700); } + .card, .day { box-shadow: none; break-inside: avoid; } +} diff --git a/supporters/vercel.json b/supporters/vercel.json index f583d44..08f59b9 100644 --- a/supporters/vercel.json +++ b/supporters/vercel.json @@ -21,5 +21,27 @@ } ], "cleanUrls": true, - "trailingSlash": false -} \ No newline at end of file + "trailingSlash": false, + "redirects": [ + { + "source": "/recovery", + "destination": "/plan", + "permanent": true + }, + { + "source": "/stay", + "destination": "/plan", + "permanent": true + }, + { + "source": "/en/recovery", + "destination": "/en/plan", + "permanent": true + }, + { + "source": "/en/stay", + "destination": "/en/plan", + "permanent": true + } + ] +} diff --git a/templates/supporters-astro/.gitignore b/templates/supporters-astro/.gitignore index 7a5548b..7f5d1cf 100644 --- a/templates/supporters-astro/.gitignore +++ b/templates/supporters-astro/.gitignore @@ -26,3 +26,9 @@ pnpm-debug.log* # 글 생성기 산출물 (리포트는 docs 로 옮겨 커밋) generated/ + +# Vision OCR 빌드 산출물 (ocr_evidence.mjs 가 swiftc 로 만든다) +scripts/ocr/vision_ocr + +# 시술 후 관리 안내 번역 캐시 (collect_recovery.mjs --translate) +src/data/recoveryNotes.cache.json diff --git a/templates/supporters-astro/DEPLOY_NOTE.md b/templates/supporters-astro/DEPLOY_NOTE.md new file mode 100644 index 0000000..18996d5 --- /dev/null +++ b/templates/supporters-astro/DEPLOY_NOTE.md @@ -0,0 +1,8 @@ +# 배포 안내 (2026-09-11, haewon 결정) + +이 워크트리(feature/supporters-autobuild)의 supporters 폴더는 더 이상 Vercel 프로젝트 `view-supporters-sample`에 배포하지 않습니다. +프로덕션 정본은 메인 저장소 `/Users/haewonkam/Claude/Agentic Marketing/INFINITH/supporters` (브랜치 feature/ai-sentiment-rubric)이며, +헤더 "회복 일정"은 그쪽의 `/plan`·`/en/plan`(수술일 기준 입국·출국 계산 플래너)을 가리킵니다. + +- `.vercel/project.json` 은 `.vercel/project.json.disabled-2026-09-11` 로 이름을 바꿔 두었습니다. `vercel --prod` 를 실행해도 이 프로젝트로 올라가지 않습니다. +- 이 워크트리의 `/recovery`·`/stay`·`/en/stay`(Tour API 주변 장소·축제·동선)는 정본 브랜치의 `/plan` 안에 "주변 장소·축제" 보강 데이터로 합치는 것을 다음 단계로 검토합니다. 합치기 전까지 프로덕션에 올리지 않습니다. diff --git a/templates/supporters-astro/astro.config.mjs b/templates/supporters-astro/astro.config.mjs index fb5d1f3..55e1f94 100644 --- a/templates/supporters-astro/astro.config.mjs +++ b/templates/supporters-astro/astro.config.mjs @@ -9,4 +9,6 @@ export default defineConfig({ trailingSlash: 'never', build: { format: 'file' }, compressHTML: true, + // 주변 안내(/stay)는 회복 일정(/recovery)으로 합쳤다(haewon 2026-09-11). 정적 빌드라 meta refresh 페이지가 생긴다. + redirects: { '/stay': '/recovery', '/en/stay': '/en/recovery' }, }); diff --git a/templates/supporters-astro/briefs/README.md b/templates/supporters-astro/briefs/README.md index ce37597..4dd475a 100644 --- a/templates/supporters-astro/briefs/README.md +++ b/templates/supporters-astro/briefs/README.md @@ -5,15 +5,18 @@ ``` node scripts/generate_posts.mjs --clinic --brief briefs//.json [--out DIR] [--dry-run] [--no-verify] node scripts/generate_posts.mjs --clinic viewclinic --from-golden # 정답지 18편에서 brief 를 자동 추출해 회귀 +node scripts/default_briefs.mjs --clinic --evidence > --site [--out briefs.json] [--max 6] [--industry derm|plastic] [--areas N] # 첫 배치 자동 제안 ``` ## 파일 ```json { + "industry": "plastic", // default_briefs 가 적는 업종. plastic(성형외과) | derm(피부과). 글마다 industry 를 두면 그것이 우선 "posts": [ { "id": "slug", // 파일명. posts/.md + "industry": "derm", // 선택. derm 이면 생성 프롬프트에 피부과 추가 규칙(조건 표 8행·시술자·상표·금액 금지·부작용 어휘)이 붙고, 게이트가 PRACTITIONER_MISSING 을 본다 "title": "질문형 한 문장?", // H1. 물음표로 끝난다 "category": "D", "categoryLabel": "시술 정보", "qbIds": ["D2-02"], // 질문 뱅크 문항 ID (화면에는 안 나옴) @@ -52,3 +55,44 @@ node scripts/generate_posts.mjs --clinic viewclinic --from-golden # 정 - 자막 없는 영상의 발언을 만들지 않는다. 영상 근거는 `shortsInfo[].answer` 또는 `transcripts` 뿐이다. - 기사 본문을 추정하지 않는다. 제목·매체·날짜만. - 근거에 없는 수치를 쓰지 않는다. 쓰면 `NUMBER_NOT_IN_EVIDENCE` 로 수정 대상이 된다. + +## 업종 (industry) + +`default_briefs.mjs` 가 정하고 brief 파일 최상위와 글마다 `industry` 로 적는다. 생성기·게이트는 글의 `industry` 를 우선 보고, 없으면 환경변수 `SUPPORTERS_INDUSTRY`, 그것도 없으면 `plastic` 이다. + +| 값 | 판정 | 달라지는 것 | +|---|---|---| +| `plastic` (기본) | `--industry plastic`, 또는 병원 이름에 "성형외과" | 기존 동작 그대로. 시술 영역은 URL 세그먼트(`/contents/facial/...`)로 묶고, 세그먼트가 일반어(`new`·`doc`·`index.php`·숫자)일 때만 제목·헤딩·본문 키워드 폴백 | +| `derm` | `--industry derm`, 병원 이름에 "피부과"(성형외과보다 앞에 있으면), 또는 시술 페이지 제목의 피부과 어휘가 3개 이상이고 성형외과 어휘보다 많을 때 | 시술 페이지를 URL 과 무관하게 아래 8영역으로 배정. 시술 글 제목·intent 가 조건 표 8행을 요구. `avoid` 에 피부과 금칙 추가. 지점 페이지(`branches` 유형)나 `facts.draft.json`·팩트 시트의 `branches` 가 2개 이상이면 "지점 선택 가이드"(B) 후보 추가. 시술 영역 기본 8개(`--areas`) | + +### 피부과 8영역 (질문 뱅크 D1~D8 과 1:1) + +| key | 영역 | 문항 | 판정 낱말(일부) | +|---|---|---|---| +| pigment | 색소·토닝 | D1 | 색소, 토닝, 기미, 잡티, 검버섯, 피코, 미백 | +| lifting | 리프팅·탄력 | D2 | 리프팅, 탄력, 처짐, 울쎄라, 써마지, 인모드, 슈링크, 고주파 | +| booster | 스킨부스터·재생 | D3 | 스킨부스터, 리쥬란, 물광, 엑소좀, 재생, 콜라겐 | +| toxin-filler | 톡신·필러 | D4 | 보톡스, 톡신, 필러, 주름, 사각턱, 이마, 미간 | +| acne | 여드름·흉터·모공 | D5 | 여드름, 흉터, 모공, 피지, 스케일링, 필링, 프락셀 | +| hair-body | 제모·바디 | D6 | 제모, 바디, 체형, 겨드랑이, 셀룰라이트, 쿨스컬프팅 | +| disease-hair | 피부질환·모발 | D7 | 홍조, 혈관, 다한증, 액취증, 아토피, 사마귀, 탈모, 두피 | +| plan | 계획·주기·조합 | D8 | 시술 주기, 회차, 병행, 조합, 시술 순서, 패키지 | + +점수: 제목·H1·URL 에 낱말이 있으면 5점, 헤딩 2점, 본문 등장 횟수 × 0.5(최대 2.5). 2점 미만이면 영역 없음(기획하지 않음). 근거 충분성(영역의 페이지 글자 합 1,500자 이상)은 업종과 무관하게 같다. 본문이 이미지 글자인 페이지는 글자 수가 0에 가까워 자동으로 빠진다. + +피부과 시술 글의 intent 는 시술마다 조건 표 8행(시술시간·마취·통증 정도·회복(다운타임)·유지기간·권장 회차·권장 주기·시술자)을 요구하고, 페이지에 없는 칸은 "확인", 시술자 표기가 없으면 "확인 대기"로 두라고 지시한다. 고정 글(병원 소개·방문 안내·상담 질문 체크리스트)은 업종과 관계없이 나온다. + +## 게이트 규칙 (피부과 추가분, 성형외과 글에도 적용) + +`scripts/gate/rules.mjs` 의 `checkPostSource` 에 들어 있다. 근거 조문은 코드 주석에 있고, 법 해석은 자문이 아니다. + +| 코드 | 수준 | 조건 | 근거 | +|---|---|---|---| +| `PRICE_MENTION` | error | 요약·본문·FAQ 에 금액(150,000원·15만원·₩·%할인·이벤트가 99,000·1+1). "비급여 진료비용 고지" 안내 문장은 통째로 허용 | 의료법 45조(비급여 고지는 의료기관의 의무, 서포터즈는 링크만) · 56조 2항(유인) | +| `DEVICE_CLAIM` | error | (1) 식약처 허가·인증, FDA 승인·허가, MFDS·KFDA, CE 인증 표기가 있는데 `sources` 에 `regulation` 이 없음 (2) 영구·완치·재발 없음·100%·평생 유지·한 번으로 끝 같은 효과 보장. 부정문("영구라는 뜻은 아닙니다")·"반영구"(시술명)는 통과 | 의료기기법 24조 · 약사법 68조 · 의료법 56조 2항 | +| `PRACTITIONER_MISSING` | warn | `industry: derm` 이고 분류 D 인 글에 시술자 표기("시술자" 행, "의사 직접", "의사 감독")가 없음. 성형외과 글은 검사하지 않음 | 의료법 27조(무면허 의료행위, 대리시술) | +| `BANNED_PHRASE` (사전 확장) | error | "정품 정량 인증"·"정품 인증"(인증 어휘. "정품·정량 사용을 밝힙니다" 같은 서약 사실 서술은 통과), "비포애프터"·"전후 사진을 보세요/확인하세요/공개" 유도 문구("전후 사진을 싣지 않습니다" 원칙 서술과 "수술 전후 모니터링" 시기 표현은 통과) | 의료법 56조 2항 2호·14호 | + +부작용 고지 문안은 팩트 시트 `sideEffectNotice` 를 템플릿이 붙이므로 글 단위 검사는 없다. 생성 프롬프트(`gen/prompt.mjs` 의 `DERM_RULES`)는 시술 글에 "## 시술 후 관리와 부작용" 절과 화상·색소침착·멍·부기·감염 같은 구체 어휘를 요구한다. + +픽스처: `scripts/gate/fixtures/price-mention.md`(실패) · `price-notice-link.md`(통과) · `device-claim-approval.md`·`device-claim-guarantee.md`(실패) · `device-claim-ok.md`(통과) · `practitioner-missing.md`(경고) · `practitioner-present.md`·`practitioner-plastic-skip.md`(경고 없음) · `derm-cert-phrase.html`·`before-after-phrase.html`(실패) · `derm-cert-ok.html`(통과). `npm run gate:test` 로 돈다. 픽스처 frontmatter 의 `expectWarn:`·`expectNoWarn:` 으로 warn 코드를 검사한다. diff --git a/templates/supporters-astro/briefs/oracle/clinic.json b/templates/supporters-astro/briefs/oracle/clinic.json new file mode 100644 index 0000000..f288fb8 --- /dev/null +++ b/templates/supporters-astro/briefs/oracle/clinic.json @@ -0,0 +1,45 @@ +{ + "_comment": "병원별 고정값. 2026-09-10 Claude 작성(haewon 확인 전). 유튜브는 YouTube Data API로 확인한 공식 채널 @oracle_medical_group(구독 1,310·영상 318·조회 113만). 로고는 공식 홈페이지 상단 logo.gif(alt '오라클피부과 로고')를 PNG로 변환. 그룹 사이트 oraclemedicalgroup.com에 국내 47·해외 18 지점 목록이 있다. 2026-09-10 사람 확인(Claude, haewon 확인 전): 자동 수집 이미지 12장 중 11장(sub_0*)은 시술 설명 이미지(모델 얼굴·전후 사진·글자)라 제외, 시설 사진은 검단점 로비 1장. 업종 피부과·지역 청담은 주소 기준. 이 파일 값은 워커 inputs 단계에서 자동값 위에 덮어쓴다.", + "youtube": "UC5husl0zvJ_W2zILCb6Wb6A", + "youtubeHandle": "@oracle_medical_group", + "logo": "supporters/briefs/oracle/logo-oracle.png", + "groupSite": "http://www.oraclemedicalgroup.com/", + "instagram": "@oracle_cd", + "naverBlog": "https://blog.naver.com/oracleclinic", + "gangnamunni": "https://www.gangnamunni.com/hospitals/125", + "factSheet": { + "kind": "피부과", + "areaLabel": "서울 강남 청담" + }, + "site": { + "heroImage": { + "file": "supporters/briefs/oracle/hq-building.jpg", + "alt": "오라클피부과의원 본사 건물 외관. 흰색 외벽 건물 상단과 1층 입구에 오라클 간판", + "width": 888, + "height": 540 + }, + "insideGallery": [ + { + "file": "supporters/briefs/oracle/hq-building.jpg", + "alt": "오라클피부과의원 본사 건물 외관. 흰색 외벽 건물 상단과 1층 입구에 오라클 간판", + "caption": "본사 건물 외관. 출처: 오라클메디컬그룹 홈페이지" + }, + { + "srcMatch": "gumdan_1", + "alt": "오라클피부과 검단점 로비. 접수 데스크와 대기 의자", + "caption": "검단점 로비. 출처: 공식 홈페이지 지점 안내" + } + ], + "clinicGallery": [], + "buildingImage": { + "file": "supporters/briefs/oracle/hq-building.jpg", + "alt": "오라클피부과의원 본사 건물 외관. 흰색 외벽 건물 상단과 1층 입구에 오라클 간판", + "caption": "본사 건물 외관. 출처: 오라클메디컬그룹 홈페이지" + } + }, + "excludeImages": [ + "sub_0" + ], + "_logoNote": "2026-09-10 haewon 지적(녹색 배너형 GIF는 완성도가 떨어짐) → 그룹 사이트 oraclemedicalgroup.com/images/logo_oracle_02.png (176×68, 투명 배경 워드마크)로 교체. 클리닉 사이트에는 CI 페이지가 없음(메뉴 CI소개가 빈 링크). 이전 배너형은 logo-horizontal.png 로 보존. haewon 제안(2026-09-10)대로 원본 배너에서 왼쪽 문구 영역을 잘라낸 logo-horizontal-cropped.png(133×49, 녹색 배경 유지)도 보관. 녹색 박스형을 쓰려면 logo 값을 이 파일로 바꾸고 --from youtube 재실행.", + "_imageNote": "2026-09-10: 본사 건물 외관은 그룹 사이트 oraclemedicalgroup.com/images/company_02.jpg (렌더링 이미지, 간판 오라클피부과의원). 같은 페이지의 다른 사진(화장품·모델·장비·전자차트)은 제외." +} \ No newline at end of file diff --git a/templates/supporters-astro/briefs/oracle/hq-building.jpg b/templates/supporters-astro/briefs/oracle/hq-building.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62c1766f58e9e59ab3635df932893d010198efe2 GIT binary patch literal 428228 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

    uy#2dF{pOFBiUQ#f(`F-^IyfE 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 z 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�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�|AWbUy3N1n+*pa@%)i> zw`aVgH=e#F8}#a`l^+wwtL7VPDtdM7c5E^va`1JqsMT6$iu!M^ItN$JP_UnrW^WCX zo#I}t+Mnj{Ru<^byPVLp7adP28(cz9b+&mV>ZV;=da#%={M?samz7<|SZBV0IJUUw z0N>YLLb_AU$%RtU*pttbCyDD%?QN6ixvChIlc>L&n&?g2mKk3e6)>&XI)svjyJmIA zw##D#nB-&i7c=V9?nC?kWl*F8+7bg(?(US8ARy+q(aOHK{#Bv!pr0q>d=F333>jv#0Eh#!NS(~S~z%wT0R4Ph}nIieO0zvYFfHBS?X&K4?!pyS%TROol^ zKb!H3EPFnpi1K)?H#A%U#a`TQdZVLvU76`@Rvk(> z*#5)TXQx-`Tx8vVU%@wQzC(vmM5ollqu!k)q%JgNO2%tC{VuysF#IX=ODE7>?%jg# z^Wc)9uUI+ry^f9SO@%$N#ar7&CW?DGO|5P$$~vQE3B->D+c6WKkgHw7vxqiK<1d%p z&xET%!qbde^$^*MZPO3XBBo!L#qMg7G3vL6>6&p3F_R_&&>J!kNaM5OgBZiZk+QEv zUN?dK@j8+meU5b-ZlBOycmma~OQx791ng9v(>EJy*OW-nBg``TwY8tc!H1+zs~x$2 z)#D|h19Op_Y^)<1S-n2MC!<$$8g9KqWGI&KS>AA zs%$^fb!g>Xc4yk`jIxW7oSX0R)g;d&B9{#-t{_6hg59eut7AhJtU|BmRgDHE?bN$k zh&7#u%wt{M-DY@zpVnjS1p_i}3T+q>LJtW3JUzX-G z3ag_Ue1BKo8z-crLmR7h16r1GXKeLiy!pi2%&~9Ta9oSZ>1r_s^%B_ks~L|&++dgf zIfXZ6w-6oaJ(|PX6He(RH&;c)@&f|ax0Oroxy|13r}VkwYypD>T!_Up@T@?GjXdOM znD0eOHH}86k&WygPxY$v^RdZ^ja{Is^<+>`=|W zCdPWMjcx%4)BUuX629s8ve17MkA8A|io1Dd>)WqIj(djGzVIkp^|+X0hX}L{;ZEc6 zX`=JQg_LEP896k>E4PGOg-c4jEJ%yGpv?)*T{3laa`)chw8le8S;jj{vp7WRy{!fJ z&LQ5@UXX-@Ur)|jWc#^)IDI6nZ#ZmMmy=OpUrfQNio_@#a9YoE2OB%???V7vfoqCB z^L(Ko!nY%Ay_0kTE)q}zw%fQ4#MyeCF~T;MR38b)i;4q1EQ4|7z@8(kujGbNiAidt zuB_1=Y+?3}M{9wYmFXwqz`*vtxFg)2d6Eo3UfjRu=vC6~-A8on$x!`}Y>ThHVNMxY zwUkU;?zzv#7w#*RfZ7*Q|HLml7D{@_4AYFUrgH13EGprm-K!ap4NitBLASp*#<}jw z?Cr4=26c(YZutmL6eK_q3a=19)hlQIe5_i$J=5>OBRX(G@bUM869zFJU59tycJ)86 z8ef$nPZp9~Jr7)NPS~U;L_+X=VVqWn!%{rlbs^XeWT zYzOBL+qY%iom}CrOnsp2VTn^lhr`BqlJwSkqjR07S7}o&y;6OuQuZwu`*96R{ond< zR?$^$e5Q(3_ztJsWfR`UCDE@0%&yaZL3HG3+8#7Q!D*F*+d1Uz)MLRK~G5wugPKyHk0{pFdpR>;$AuRpr#d@5oJ3~A2%dSV;e$9<=UM>f`+LVGE zTq^0~XGs%x7>5=^0ZiFE0zZWJ#)rpr)V~_j#k&hc+efRZ665lct?$2H z*ne_ZB;C)ahLYTN+1@Q(&a=X{H#vg=yWE#aLgw~rC8e|gXcZF+;Pz3P({)>$?RQWL z$z6X(xGMv#T-JJV;UAmlCq*IyyVW&J)c>NWFvKLbe3>PqX>L3#5N014u!y)Vb{@Z@ zP2&AgB+37hn3 z$JdwTv{z4<(Wc^TqN0_)V-(SJ-SNt*DZ#}pzY?3~vCdlxOJ#w(PlxKkTxo4>Vsc&V zWr_1NT4MQlTf=Bz+J9W=v}M43`KQ8WX^>#&gvLeza{&KH6;N=!0 zg!7Up8;1_=X+b;9mi%U*BDs)bAHK<3WT{=1UP1}O71zlUc1<$&RaADNS_K~L+Ov7E z7TFvweL1VHbvY7Tu}OrL@2bDlQ-_Om zgZ>L)&*#b{ss1s(lO<>EP9)~ZOzZ}Zn)UeKs;gTLvrHOYhZGv!ixmzLxRXSfU3ab_ zW`tr>FlT8hZsIh(-1$DZ5^Q1BUjj>adSDv$X)5#K0sxEn)+iB= z)SRf8*MQ4t2ScNkM#&}@TqTGn^;clCu)l@O5XYWyR!5 zjhQoSZHK`Qy&2Pkxrv>?@Ni~@r6~e*n?n^Qk^YsSD>tuK8CWGUfY?}Wa=z&`R@&O` z@ysjU`$J?X$R@?tekuJUg|5_R;?w(?)=^1qx`=_6B~DBNOBoQfP9r=ljvpGlCinJOBp@yz8r$u5)n7Zby_#Hcd7lYv%s(kD zyizszsdDL!V+>4^TJzUK)a8Edqdl2EL$!oa1*g5Hg1z$MZy8|AWYHnpoFM;5*DVM% zG>mvqdmv7)Pylse#ldlw14q{_}Q_apMwWouvOOQ???%#U+O{K>IVdxp`b6=lQrX9ik(Q7aLMh`0*YhZW_mp81C(zV?>%`-R)(ns#bjQI zpWQ~SAotf-r`M5!Wq%3inrb5F;foe3UsMf zYjqhe%4=Av1Gw<>%fXR|US0S3S!{8554A^|#57VYYJE!pAG35BIJ+8n<;G%;q_srn zH~3nNzpU5W*hpImsWj6P6ne1LA=a#vOs$3}tydgcOoRTkE%YE+zA>Zj^|1JM(D@5xKd!WKHk-*ahZV-Y z!~C-fx}@Zh-t&zB7I3@%4INGUaXQ5;Yj|35Ed3PeqIRTW@G8SWdvfqH!23cKVmhJ< z-s;|*LrPKiMY9d4YHeYlNLA?9eJhnSXN98^eO|w0IA0Gth(egKtGlrbmMyl5)pIIRGNdFvwu2|+=7dFajF2X(GL}b3PNoI6NPPN!Z>F<$fC}s?6mFtGY>v}!A|By+$n$j^mb>J;`6F1!+)ihKrg!k zI@`?c_HuwpVNPl5@cpn$#FI&2F{eObgSJ40*gwgA6f(2E+V>#WeVsq&T$g&CWEa#q zUyJYOd|lk~lf?4AL&z$Pp6Q#Ul*|gV$FKZ_kFVXV>?4py?e`EA(*wgmhId)1!J-OTmmnZ zo0g;@^Z@dwO7c;%id|$1#dwaDfA{|GD6=Jb_DZ_=JHg&qZOkT0gPb_4Z2sm7G{!l? zUl1HDo3<)axsD}mwQLlksYqDx!sbRk@6Q#xaeoz8;r?EW`nQgY=X6WD+r6^5Ha>d) zYi!Pz8*3}cHfVG0nW2QQqIZ@94SB=gENntBO^v|62k4^F<=ItbiZ58iiF4~%d}jU> zQUPNmBkTp-Aiu`$`i~IwaEcC3)09U}TB%`fMX&$*VK!2(mBlQ`R}TZkx;R}}oU3aC z1`vrr>%Um;KlLsF)R-YrAkuScl|KvUCU9NbJl@jMnmO?>8UN4CC2_42LOS*#)J@Aa zl5I@(PTOVg{v1~|bTr@$#n+~kGqWwm{0p3kZ?SD3KBzDekwSfsKW7Ffe(P;AfV`~~ zbL^S)Uj^YgJgJ@Ft^T0~Vi04JV~@|6jlCynYo+lHt7`#&wV^cc?l!|(Dz1hsC- zH=r)JE)7Eg5{kQoqnWX)U?oZc*g7+xW75v(-loEh%BNPpO=2SW2XM&;29Qz3U71B zS5T>p(uCI7dZrno2O2xZ_&O64f$p+))%-2{-OHb+tu2EZv)eZ^H~n+qlzOGLz*y~m zr^YB4(8|6I4VdSzC2yXD5ISbD3Q0rBDY`649?2*0fzyg#tvvK!we7O!jQN%WFRz7f0IO>f}k+>E?e>bI`F)4Ak+$*y>H*fQTJ3KY3n0bWP6?_C|6z0w3J-EE}& zW@j?{*d=rBFSOXDsq^d3B2fWnedzC0Dm5DZqB&o&T(@M$aMuIs+~Aop&I61W`Xv5?@W()?GQjNig0`O^QwXCe_Xe({9}AHbs>;DgVCQF&n%M6c5WV$ zll-*qnHq<`T)KZH6uOF*V{lrF=x7di5$))%C%YN}RNfZcOz8gR4u8lDt@!(!S>`+d zR!y#YI#F7nEfA8ttNFyVDaq@7zU{8!4k~qiBVD~H`|0?VFT!g@PR6FTMHZRbQ$+Km zbq_+Xx1&n1yh`oGB=5HwHX?x;*2`;oIgyo>8ygda3N7OAJvuSx{=X238P-C)-#I7u z10ytY2&7W^zqAfmjCMVDHVU|OHaAM;S+ZzXQf$*=iup}1X1`FFai*W^>_8KIO;a#>kVhE2dge`do5VI7?nH-4}Vq;%2UQln5k$#8R5HA;y+Uc_!h z(m}9)T@Xj`bT1sV&dZBY-Cu&E#VI10Lej8)iXxTdeXuX?9yfT)Jjb&7@~AmJX>1I) z_?)A`JW9r%Vx|}t%;?CJheNtsW1I5lHZL30fDIKMl4hbm4tJ~do_e9xZ@#?1C_`p0 zE0(CrS|`dHOH*+MA=qrri8r=`-+cK*0Mtz`)I?Wlg|vhZ-Z58VN~s}fD-W4xqUIT;rb;I;guc*1073bFaIZxfa2b&?@c3;7e7%3-T#uU&IXyJ$=)e*6xs2seEaR= z!y7`AmiZ>Ni4{gO@a#l)#^y{&BuwuTU$aX`c`O2SX8u;g%71hum35}N&_MO%QN${QB0nuwqW_9 zGx6Uiiw1lu5N%+kFrY1!KgHY)T8&aNEl_j+NG|udrmiimjte6$MOOMYE;nr&z&ffK zxSmWPwiIzQN+e6)^Dz^>oq94Xyaon1KM9h6Jw7W}gy<{SEic2j9iC5AZ98Pt0r| znf={$MrcwOgDitBeU*SD;S4L~mpgH6zPC&11YCmYv7mIt$1Y3Dr9g2k_g-!MlGut> zY$%w(7ygg@dyK}fgPi@1+>^p?BmOG_{#hfTzQ4AEPpc37+G&N7q7M&o6SzNn-LoR} zl`dU%Lp=cmH}ka#4HtKAqPUOYirV$hth=AN=ZT?p-CW=s(6TCW^WRI+Zl!F3)|OgF zGf&-hQjk-}2S~GFAh({}uR~B|XZ2KX)E9$5!H)X$$MJ@am#?Kq?t9sv)Mj4YL7J-tVfAuJJ34V3?n_0hfb))tSvMLDafV7Mon9;LH_$E`9xXSKD2!Z_8xnJb*r ze00U0P0r~bpTl7$-X{&{;_-Gg?TcF?392^`kx@I>3?uQmpX?Ha;}MGg-zj_`aWk;==3!7h-5)fP}Fk!i8YhpowP#)YPF!z z-J|99=SQ zsk+!TO<)a{;mgvWp0fAVh+~Lm+(df{Kc`>3L9_^59iW&k+Sb#K&N<$Y*qwd;->U`R zBS*5$Ekt=D^uX2F9;{qy^6P^R(@NEoMeEeI05&|O8Zq|<|6KnI#4fBG+TGWd{NRUe z-#hT>S4V`drdZHWQ{_M9&Y3x?_lY7X6F_hiq#N%>aKX*Cwf^1VU?ujPa5h@}<-s-k zARp+3SyIBCJ*A=YsMIrOU;K2xX?S<;ZLc{bK^PTRIne%?if4LpT!$pgZ&g~%E(fQf zv#_Oci-GgK?_I``KX0-htLo zN1?DXc&$#Y>i(>_xYoz`hRZfCE?@sQJ_tmKOPme+1_x)ibNYg(*t>fFRng}3(Lpi=>b{sTU$WcfK z@#|dtLd_y8sawST6jsPXFFV=~qmz<8gx(R7e#f`SFB<4_d3{-Bjc^D4elHv0zP77g zZo$1EQrV*5;f1zf2Hcr93)qch$Jy_4#sdydvlP}^_d0d;%{{zmbQIC-Ep^Q>ND1gU zbC~bE{r>y=^GA;i6Aqjl1|NQdkCw}5$aTAJLPIbG7^5WTb4Em&d$PBoGJZM62a$jS zmX2fI#BcD?w!Rmh#R$QDm{Ic}J~&ScU8+&FgPH&)M?dU6SG3w67@8I3Wyst{O+HQ)>@|Y?x_&nr+a1-PVSc_O!=BKx+Q*fM!xfu)E9#l zl(zS+Twb+|b!cmWc%hdgZR&=-W&LGTfz)FPa&rg4RFZzd#}lU$U3zHH&~)Qe&M@^v z=F=MyGYu)XpSbLuaQAJEVCxy^AtJUhq`A~TGjq3ln^b)o-EiM4_`$NQB zl{nW<%IR>}0&Zi+n=FD7dGLg`{Tml3hz*xyEO9k%Xu}#VEpY$G1%Dh?Lx||Qao$IT zRlT>JI^e9h>q~bhH~q&IidqZ9$N(q!3j97(8hRW@kzon?iV2LJdOeJ{g0x%%`G~h^ zX4||1%^quhvW4K`D-{Q14wrcQyc`pmnHfT#96D;Fb)WitVgPw6%8nwUjz{&0fBlcE zc8~I99z-Fli?dn_XH@g`-^V9Bj5L9hq{(1 zTn4Ttw7tKBGS(T2ggO|0i9m|jEKs3CDJ!qq-M{vJF-Hp!Y#EhhsjmvZO_y%G3bzU} z=iw^Qn&^0Emew{O0e=a@T8j<9hs<*!%sJQk5bsq&ghHme=4$Ulx3J~d_+6XAETaf^vu$?O8M*IVz65CRsPBcmK7>$o@}as|ZWPkh3>?{N zR~Q)J^*rtVn9GmLmQFn>Z#|Rr^oI?#xc8~D{a%*sVLZJ1!d5veByu`&F~u;HH$Jgw zz^ihULh(;I__Ke940;zM1vgGH`wfSc_0g#FPtdM%<}6S2rRk}uBFXo<^$!`+glmeQ z+r#G~$(R$xONLi=Zcwg-kkExusG)RzA|#8X`ybb(6uQwnN@KuzaF*Kz+RQ{F`e*D6 z%2gmsV<-FO!)zYz{A^9R?VrEX`N|;ZDLs7va<4&m%E-Ao zwBtavCTmB_XWU<_ZTC0pBpKbyBM`o2+B$ZqO_nQH5x-z0JTQ-LXpTL5HtjfCVY%)W z!|Q>uZ2w*9(%>e6#QJtyhcT;4VOdKPvvDV>Opdk_X|kur+_=TrjAO5beR&X;KA*xv z_?tcu@Y(lZZ9uo+^%;XJ*NPkpyg#K6I1JVxZ~QKVN>_T_6eRG8~w%d+bM| zE66vv(P670NdljQd){RJs~Ps8(9a&Jf7+bCGOCYF3^<@d?Jp3PIwofTt*VGDPOR+Q z18nJ2^Bs1k>F}IlC79}Wt1q!F?KuyawkN~ywbw^e11DPoZIGumXX&t}17}xVqqmjk zBp}*{tqAw)LWpM|A!hDeTpY-^GC;8AH4Sf__h*`Ebz#=G?}AAFti~zz*Li@*!m_x2n)ddY@Bknbf3p}TuqEooIa=B)-4X&y9;|s$9BH(6!RIS!Iao$ zru83})su=`(^apRrqd=jniY=ylnZ?r@lk_|OH+_Ie>$`6X z)?~Q*)$1CbOJquxKWa};%sDvy=u5&ELCc^0Ns+!2(^U&{a&B^2>y==V|J(5jQjRQc zNR9|Vfq!w5upaI}<{Gr|r$8<$cRf0w(_a66%7gmGCdbm&tKj}`KXk0`k7=I?ypkYt z`z+~JU)A%E6%q1_tHx1|pjhy;oQ}p62h_TMMvigs?DEJyqEo!ty`Ge)r*&war8^`S)W@Ak}91xqC{=a zwkFoy%f6s9Qup@x=PKV@pQ*j7+e~?e>TTcn-NQKm9;W0LQ^QWxx+5cLtA5I@%?bpQtP@2b1s7mB9jrl1oA z24wI2;iv|iHFE_wkk|SuHhU)+IUZ^u9&X>mkB@v-fzKA+&5N_ZTsOMrbhg#|x%7)8 zKc3+HGxHx9kxlzV8y3gaN2=kIxh_4wRX5+QLQn*kK}B+V9_EXuZJh(=E*Dxza>wmI zE)%5Bjls;>a>f6@lK$iRl#@iLA9V%*8SbFA!Na@2YWPLF^}N}$mG6nn$>Ur5DZXq={Nt}jfvIjM zJi6~>f^`&5{Vek5&XAz?>^V7^P02Y?3W{%{#lSvkBa|pOhK=O~oq*q`p*mB9*Fop} z8!qExF06g)hLTO6HT~juAV^FxH|Z9O6wvt|lQ z05Ybd3d|F>x@yKQ0p4vR)JUa`Cv)z+f-!mkp4pWQy2yn6xD(wHve-TzdirY4YWD)~ zhpB14c(rgN<(@C+Po7i_7n8yTM~2cAGrUbNF9_pOkpcq!1yq9iSfzKRflQCGMQ$n> zW%LY)@2_>|Bj&T?bqv%x%EQP0?Pwf>dx&-*{~S;13pgE}|L_6bMZ{z2f>2_vvt;>9 zvO&~%v%bm!7Hye1y1e8hs$gEepvV4GR$Wo{Ut-HYdN%tuN}Cx9w;0-NW1VGg7I(}vxTYxA zWk?ny0orBZPWgAZ9=jmsYIs(sVYYqxBRZ-R7!n@`@Re3Zcn8myE#7t}Hf$ULhuxp= zeDG&Qq9oixxocrX_G5V8P~XhG1K(Xse?nt`)wc;>O-<``d}vtKdSmv^auhX{rQ{GZ zM7jXirJtFf0Vb+<7-gnw%*@CZ879ey^B%^T4w;CdZszmpXwxgZE|8bpnY+)MHai)PfdKwd;sMlL+pF4H` z{qgYZ2W=p-y&gVj6(84*XLq0$_78+jPrk{3UQUk=nFKm3x|SuI*hLM{z>ukS$Iw8Z z81T{VF!SHx;%b_*9o-?(!53vMjg3{?CU*gbgJ#Lw&Td9XN+}jL7m@}k6qvjulu7+o zV%nhmI`4vo&d$)q!N5l&>ckqXcK+?oC)57b$dC>m8+JO@n@1!D4_J2m^v;E^Smzqj zT!+T(TQT2K2Zg8PYpNC*bx`Wt8_5wi%Q_zARkt-~A}@xSQ?xfH*Y~l!McGeEG#G@L zFw%g|2qp}M$IJ@USZnL>*cG)#Zle_Rjk#SUb!``wg23y)Oq7n zj8WpUdE94aVy}AFc(t@70Yf0dN?O|P{H0An1@wWIV70cAIwuOS7hm548c+!V-GyTC zYYQnNOx%11>5Kv#R2=@6dIo~bz?2m}&LaQIPmbVT@_K&i$)1L40dE7H?`DtXQhU)e zw*7v(UE-|}Bv>Y>d#!zp;cCC*u`fQMrwTvU%x)^C&(?lj7k=AV7CuYvHK9?Gs)xpW z)o(Gskhk>jF&cc+;oX_P9t8#Fu*C)3|9DvzX){{EKCKMrKK~fRsh%1StBUOQmFO{a zM@)e$U_b*Bk33W6{k=Vf;yQ9=s+kid-8D%_*Ce&2l3=eh#MP~TYZ!4?-=x}9Ua&tF zic0U7F)UT1U>y1|Gu9iCpBjygj^Avg%eixAz~VKnSy2)IlbTn`36ZM%FQ`|On|_S*PkX!r*?IqE9@N|%R%B7L370bQ512>jGXc|P2v+}!``p=I7-sza;*Al zT6Ob6%45hY%|^i)8>a?Jol`Y>hZ;7=ShdMk&YZyi-9-nuyCFAm8()G0$nH~x^T@6< z&URx}Ix&TQ4Yh%dlu>7h+-Jcng>A~ot_Pv0!Qd*R#$MZ;NY^R7)`6j-&0CkFV^8($ z)v+2(w@Cq?_C)|ilxrPxy_N~14gBB;1}HKPjhB_Z2paK_1c?YA;0<}jb-GUHuF8ZTXxT|Jm{j@HzO2-$-L4)M>%Ka-|GG;@f7`LCjT?2%l0dIJVODI zzF+Y6{A;ASxjO_|jjch0OvHca@qDA};*wAs3XNDn*Siouy!xXb!Fm?%ku%a0thn-i7wN5FQ#G7HyfQzHMUuf0SalS0#Hu>aQA9U_$4pj z{iXTm#4Sx)U?p#E#(r@TtTMB~jIy{#O=RU+;*sHq1}{RkRPb#eM4pZ>NJ7^fEfe`xL>q6HFAIb$WNtdGNM zvWjwKV{N~^y0yj~-NEIp zOctKdi4f@(Iz3O~>8a>PUR^z(=NULAUJ^9-JoW7p<6z&#yinq7GC&nSOrmE7#Aa?= zC1sKNH;J4phjUC1{}16FKlwW^Y;@!kbfU?Op6`#3jMFrBQFvd1CQKH;=SyN9?}&~u z>gmiTsH(O%F!tIw@5qPu{Q<(eKTm8^Wu~c5=?7_@Hy`sB@_4?V&%<|;%NdU=Oq^yq zlp2YDBbnjIcPa8Yb^q_0V%*U&V>tj0D-uP7-alYX>;8``S?5WaGx2WmYFJqP!w*9N zEf%>tcX*T_JteP0cx4_R;Uk+Wgy$*e8#^gr%o-W^zRf?|*OFqnhYT5I)ioV#3n@CH z+aiS|Owqd%p3+?){2DkAPvYIIOIItKhr)^;osB28XJ;foMdrQABX_uoby{{lb=AN| zI{~U9JliAp4$#0uu*NDhQ0ko`3xk-mBP&f~5)J4NC$fLuJZ1R9YO=ot+AMSoM#k(i z;#V>v#_Z}D#NZzmcB9+VoP3NBGr*>SDMb6K*5qaRb?VlcmO7D#_0nGv7E5kWBWY=G zuZd`uh;#_GP~HFCU$Nn3RYDWmtM15|fIA)xr+33%Zxpuj%8VvV3t~wA$@x%+CIeY8*6ZR$M45T?*T0%}pDRw;!xH6HbhS-hwv@_Q1FTk_h zf!I}|7gElVEqLG(wAlCKaK1`RQS_}5&zIHcz8gD>qfXAh_zlAo%YAc;j+YorPwafM zjSO#9S+gxV{;b70-UM{Mdg^a36hrt!zawaavUaN?Pfhdq_Q(H{aZAXCM#gZbJhEuEa9|jT$X7b9_?as;j zd?x9eR!!H)cW*3wqw?`fywY1cjKpY( zkDIy?OKUC6fj!gp-2>QE1C2{D&L1DISZKvMDmt)ip?-y%y1aieMziyQVtBJM;H4SWd0djN(9W}cz67hwN1VTyA;%5_Pw$B ziA{e>Q$+eP`S|BB+?+N~fYBDNZl#0-)=@BMz{Q||G*&pFq*hOmb5v)j{z?tlmCz(d-N zL@f4}WqS=~HbWo)neyJ280Tzpc*Sb;34HK>$Np7ctYKbu9;NxHg)bI73!~Ef{m#80 znf$!^t0vPXN!Di;lAMiCuUa)zFGKrfn{tHLdu{SF!)2cLOj9Jjus?xjD*?@dX4O;} zx)*V_)wPW5_&mbAz&Es<39@N{#nsi;U{rE28LF~j&SMAf{ynXwRau$E;k>lM=|+HD zCOBAe*=G(3p{Hx7pLl~mwirT2#0EEb^cR8A*<7!0=(R}lXUgja?WD+I<2x4U~jTU z5qUs{z!>W@`+JZy9r+gV6ib5Gp-_4c>2VfGw6TI?3VgQIaTx=S;z`iBsEs6pfFOiBv~+Av#s}*?P&PSQPvp9^7C>;>(+*Y5Q zZ9g-jf8?5Qn9obQW#iR3ZxISZV*zC1pG`Q~=4i4%V#omdd_;-P-#&7u)>(WkwJwf~OQ+)c@fn*@_rFOJkkH83+fXFScORsV~z3qFd6Y-UwBSfbM-~7{!$u^G^EuibLKA zpK5wVx_9k~71t0%H%H__gjz+nML<%J*UWl9yCq+paeg8NU>&Vf4#yb&OeIRJ8G7UO zQ;qc6NA02n9}&OL_pPnd7a&ip`X9;s13sm-*X^2a9aQ(Q<918ts27@MNHjYBQ0t1!@)uOJ#N1B#`$XA7rZ$vCYROx;J!)UT@s{Nw))`1vc&Kl~j7*wOVSo&4|t-oZ_p zX}5a+RdzNPW~RQ;uom&@{#ZZ+N{7wZHaHK&NF7(^20lTq9Ci4uhDLsV7r8(6M~S9^ zx8BI`Z`}`+zLEUTjXNj1mfp`Ux0`2+5ueVP*;HVRty~h}0sw6@r)e98>gtRQ%q3U; zJ(A}*ate5frcd`8$EqF$m|z5L8!mL7RgK;n4(k(>)pnj1zMLDgv2?Qoae-)XD7=Mj zBjKhvSm(cp8@Ps|4t>`jh%4<9VaU7qk$8okhVX!@Zr#fUsosa##p=CNHuI3AkB?t3 zscZ#6Z+AQCtUoP)>+hOXMwpQvuHp}Cf6DgZJarXqklWh_v^6*c)a4)BqQA(Ipl6pw zJ$2J-oKUkbOP7yV=f1G);$ifG=iONq@QEbIvX-8K46pt6wzEEaGu4chL#eI$W_Uqv zm4wP6x8W2=bO2ECIY^ZCkkOv~gc%}Z9BgE309AIM3qS8JCGD|(bSe+7CG-4Iy- zc1fS;pD}&-mR$fZy|EZO1s!<2$gj)&OTvJnc^BnmbM5g`eKk#{y_(b()U58kHB5)V zjQ*mhc8*d;I&cE5s$c&`-@vQ4iJw>Lf1dVqV()&P_k)GU>r%BDfmfy};f}?JR^3l! za^@B+3;ev3HD=N7CBVGZYKG6XYRtukvPLYKM&+x8QVsmk0^{x%ZtgIocw5=_Ct$-d&%SDWU}gDpUx!BrOJtl<9j&fPeLe4E@@+*vBx zpLw#S0*iEO@yh|w0|!xoVwN{UEZ#sCb~u!edP-k0jkPmdB%J5{bdDn1TCW(mlyOdZ zvU3?BQ6nHK6jDCWMGIJyE)KEe{8w*uh zn4f~@E3s)$gM3LN^#x1u4&#~A;jf=%?3)}3z3@qC203=Jg7cTc66|#PUm~@CI#?DC zKTdT>bd>j0lkdlc`8;17 zX!jhGbQJ@yJ<3x>CJp?x@s+E4=ROcbTz&@)r5vu$StD=S9Bv!_vB#Dq>~Yk>eUn4soL7?G5c%lE>M+BQb=2C z&idGnjmD@&Rz2wt!WnV7cgJ2`2qk(ZNZ;rPWcOz1Mt$qjs{p@>hD=d&b_t1ZZY4<0 zw$sEKDW&L>HPM*WxGh&e>z`;Lw-Z*E|2rlzycsPYR{0ZiW)^qJOCa=cuYTLH=#qi} zum7pGfqLE-TbpMDva!oTEs^u>fUj-tY=wE2-B_l&i5VDX?{_3|mXYL^JK;z}E=>Wd zkvH)D`H{p4&~dnJ?vt_2RrL)V$4{uNCND$lB*p=V;3qW zXeYpAVm#Qku2pX|-HH^w4}4KV2WJ~-=fgthdMZ)Q@SC;GsU4yGe^Y})_0p%k(|;r{ zw>8ctA6LDfQhBj=@P+(%A*Ye_*n1`atm#Ib5R8 zhh0F&EuX;){{ow+a4BynQumM+iHAF<)65fX_j}OAr zw7uIQ!5&o1OjPi!^7{#X11)+%F*Xv)SI<-amx!25I`k{zn@k{j_*zMmB_DU8X(x_< zUQk~lWVR*y7>Z`v=pefCmcZ6~DLFXSg|4TbG8$jfqoZtC`_%RJl~un2#^}Ia0&@)_y%6fGQbPhkq(|qT7E@seYgPInqJ|1UzxC6%wM`( zZww?Nv=j8b&H7DlJNO;4$siPOZS-;AU4Ot)FBuX?&Wx~SMCYDkl#Bj$DIa@y`rQ_SwAg}1ySnF+KYv!!$ zEL7nFacFDSbzDB;fF$-@dqKPi584U%ab^JnGB1!=y5ka>dV}-;I}?`jv*7Xm){Z^ z0cRC;w|YmAz8QT@wV+I1DR&B3LLdfNg?Jo{_SQh0KFfUYg{9g|SB@>{9&1-f_iP*g za-@MTSf1Pb*Y(^j)sI^Ng$S-eEgh8Zd`Wz=Nd~-d$T6hMqiw*k9ovSD%De#t8-X7* z??F19f#*2S^-7JF1m$kf9l5+Zb7iQyf&JM}TFlKl$*HR`J^oe5t8dDK?^G9#w+jiR zKYKatDJ>o|T^4fSmql71C?C1^J2Xp@=BxQPs}bl52Pwa!&xT7bD>l7V!?n1x11 zI||oMQLHh*bowuSgi1cLj2@uW3qwzGM8e)0GM~Ki`0+4N*qnuC*1dqL2Fqj zU0!;Jj)ITU{F(e956%TR7>Ec@toOYmj!9W5I?Y+G&LiClyAb+9WQ2#mS zyK_`(y=TI#&`v`b-~yzX&Sz(QUvW#h?P*6VuR=SvP)QR4o^hTQ9WBQ~%UdE|T2$x+ zL{{jQ9U_Vpt1MH5#Z#?Y_)Gl7G4%+^eX-Lyh-%fn4> zL#F(`U=crV6_})$^9wiS0!*)7LWmMWGbgZ)0I)ksk>=; z@5R%MtuW8rPOX$rr^Gdgb`)gIVt0VT0>(9$)>@emr)Ve+6lijtTh^c zeY z^AnHmD24Xk90=KM37I(b9$6~d)50=s=9G!4MvRqY*3-GR0HgOnon{)%H#d$d&zO=5 zyfuragD?9MdS&M{~q)YzUqzC^U`(dD}SZt})*YCGx<%`Am zhl2+2wd?>+M@U3FmI3Z**B-B$!_+3skgJyBA4?F26-w);8ccfHO)G35XHOqbI?H(Z zNV1viT#7~%6uFKKOGS7Kv|yq%a(0nutDRB&gO;|YrVr{31xbNw8BlL4R7}2wT3#a0 zryudZ?%Lga_K@rM!g_#KLu`q6Mu_QyD@*buGyc9drHuwiq?ocPkM>x-0%_dkk4r>@ z|M)@O!5Glhth1b$T#OYkJ!d0+4xA7|n9-(tG=EuZ*TJjlHVNuF>cUWW7BNK@-h3@QyuNZ?-pjJVCCm!jQeJ_7v%K7h&caGhU^gS`YxIT;CmttS zW|#~^LKkNk4b6^qk;FmPQ-(B#PU;flYrO}fub7Ow{%+;@5(YDUKI?cYtr|rIy1ZPk z*}hLpX(wtwRQgHQoW@l8SdV2D?n9ucqq?r)qH(}oHJ2n0JtEfwZTSztbJJHp@L^(? zpn8H4@@q!70e`G%Na19T>bj`?Kc-7{*sHzzZ2A74xz&zKW{P>s?L-iGeK7(KlFLZQ zco_;aLp1v{5iKiw#dOgb$|LqCV0uOI_e<5s;yYWeP&|@OK2ZJJ;+X#Jwe@MemFFWO zux%%N-uk7*2|Z$XfwNG)%tIrIJiF}1{c46fr@f%HmK`a6Wrn8QR^ zbxB`veKNtxSkeumMJ#iaJm;DQg?#8Jz16y=gLQ_N9PAl{if}hKsG}&#Gt_7@u2L+Q za$4_p)l~Fgw0iyTbL}@6si}h8ZV4A95+T`FT{EQBpS_Wlyf*iPEB7#8#NEuq%GOsM z9qDL>m>ZD`3mH}`mO@dD;2mV+LSnDc9glUNq-+2obow)Ob zo~QO(%s<(PTxkp6b=Ar8l&s3|TidVmrLmpXW3;~ZsI2+|I@EJfn%|gt=A&whchH*b22{+kPfzSE2g1Zi zn}kiLp>1)T&?ihRx8}d$e^r^T+YZaC93~>*5+<%=l{n!NeJ|cD$q4MAH;F^ z#gc*w1ot0jUB~Y*(Hkx>qSe7*+c6;YWHF~ir=z9*9 zmPkxg@Y7Q;FF=4RS`LH^Vunv{4}V7XC~SejUVC=1rnHwRwtYeGp< z^7eBm>=2zb6Z2$rNOtZ4j00T`+r$O#`A-4;l)|b^PNE$lgj#-guln}b<((0ALKmNY zx%3%d(V6rE35=5I+IA~S6V<-S2^rf4{R8dvpY@;eJ0JQO@RWZ*P_FhzZ>}V8KaE#@ znpQ9q`jDCI+%vCoh45?QZH4AdWEd*dq~O6>6BUSM1a!#{J9$Xj>tWY|Jd;74z|yo6 zbZUJI{yzrvy$=iIDzsW-6yW|;A!LjAP^z`AC0&xFG-D?m=c0YZeNwx%gYTQymGK77 zRup7zTSCY-_j5^PKUohCB^>x~@4uoRSAO>-=N0F{fZ+vrEhz2gy&p@Vd=g^G(K(4u zAGro-26n3iy94;AZMlnCrUP!YDH?v@aLg}j&SD-%!gt(Sot12HNku3Loi(_xoS*eX zCnaomAN_XFX?2dKMw8X;wMB(Qe2hrTzVXugGpY^izt7=HW6Av1)Al+tBo~Q%4pS;H}ljucfw*-M?5 z>2)DyxSyj}$Qpdqnmm1hkqfrSI5zuU1^eJ|Q!C7YNY)VyG3U@WrKMqO$g%RPts{px;z^sR99B@a6<*NP@H z2i^zERqV+BjzRPv@qsJ)%ru866O_ehwl|b+kC+siSMETmc7QJ7JoG`PO#D;V^JV*8 ziDsrI;D#AT;sH;DtCB~;>#-g%SLTlpV(^EI|Bh{Zn&&}qg}t3erg?o0d*v+K zhTkdJ>J2zwKe2Bb;5X`^ch*5WRgSkT#Ql>sJ=5K|vaIYNN?@zHqt_$x;``(XSWXtI z-5z$9`>#yXAK4Dkwd{s+9+V}lz#+ZA<^IX0zk> z9w~c_4_AJQ{O_`NLE8D^(|Onf?0Pv6-!qiZrQlp zObP9IvuohKjFs*QB818{UvRl=wQO~C;Oq>O2)IrE);xo9Fs+1T7cMv?zdRSWZ)q}@ z>;AwmAya$4ij)f`I}6hMw~zL;y-4QP4bewYmjIG@QMTCkxPfbAqHES+ml^2p6m(9Us|;5#^o>iyNMnTYbp%`CtI zd?H`?q1c$y49~b<^=4}&j+cDBDbLjiy*kJTpZF={p?&g6Qt(iSVZD>KS0&k-10NC7qVwM44AIDKvxch839oa4N ztk;>L`Hp3VEUyF7%`d*$?;C62rb;|_m2&%^>yx9*Gp_~Dm7uL5C3^)em61henLA4}>GguYhx*VCWN%lM|g zs3TIG)=oa-RPFBR7e4J2Tm`#Z>bO(Sx{J9E-2B8z%~nq6c;s{c9jv9#f2DT^Br+^6C)21&faC4nFy~S@9B`s(A4?yh!utQJp_+8q4F-hsH;hdEgkYvJ`;_@>VNLU(=litcjGvsH3$2 zF}ejcbWe2x=OMzip!pWzexJ^1IC?PYjcGsCfUovdMACg48+FPkM5)+*wV<$=z;vNS3?4r3q$)#&hXMbcS4$b5$&e|RV z)QbuGjpU05N5He2o4+rBocN{!Az+|zhTyS$Q7ZG?l_B18k}A^^OEuK z#hn9QF7<j#zSv^{NtzPiyAx!)^tf)vUQ4;MxAZfpbBY%yw{p^xlQ zRP8o_-$2491|%=_Cd-i?#63fV{g5uCc;^WB!We{C57t-)I56AHZO?aULiS%hk;6B3RwK z)!_B-wK9+{Yx=-RbI!&#mW!8rMs9R%bbXnSWBT8*{NJefuE0PO%Y6MH3Q)!uQW}^Fi z2Zm~N4Al;}N-UhYvU0&T*X+>L1*5MytKKEBFD4lDU1h)hO3Me~BrP)uxqyuPR9Baf z%a7o$UsCH`vRBN2I=9|4tbA@|U{6O;`Pa@`+XWyzo4cUuzhfROt8ulS7hj3A__Xj7 zSI0Io1JaTfMsaRsT#z#ltnkyRnw;aQBa(B}HDj#WlKad)s6_vPM`ZI)Aqe%tkHgrs zRA4sQUbi0xOsz*vDUY+;*b~WLOUu8p%Q-?Uji}T-oWB?^IjnL|n%VieJ5E|xXxu8r zwtx80)4yf%?CA*JujoGc2c6ovp-y;jfb22C_K6CTx%Nc4H8a?`o`a3%k~q2yz`^%8 z$KmJMZ`%38LVwH{V8rVAGjq#7RZl`E9orhy6FvRiRjTkV9g;%S-#3Sir!~%j9&*mA7YfCsR6qxy#N@<)@19Mm_a zXAkf)ajr8XO&RTR^E^Bh5!2w)`M$d(*6iE-u|bf(&0!O?ny4xLIS5 z&wjLG;Mc}Ps(;ri$e)se;NeI_Pl(lkdU&~*mBx%yl=oH9-3ubhCSz)VX4XsR%Nf_! z(AfSh`zQ9*OV9X?{{9U34Jke&W$t%t*A_^14$)e>bGK9wKGYBj(7K#5{~h0u$@;OgRkWpZX_!2QJsZ;}#fQ|8kQ(XLC|z@g6YTAbhc z@T}UJWpAZ5!RUhjj-kLNvDeI%ED4{Y2-KzhqK|+*hkqR6k{WbsVUCihv^<8&_~9Z? z-v%Sp1j;-k3ryygJiWvpzfP!o$yku#E5Fd7(;!knfHI>OCy;{HZRCuZ0Y4mpb$dK| z!ax|y*x%4!h;pCTd`V#nbqYv7DI1LK?VzfD2r>R8S=0)C3G-1@7w*3dJ)28`X``|C zgiYVo_;!~c1RoU~wj=w1b$yZ0J$K)yJ`*%mQ-exx#__J@Q8SIpJ*@mIJFGe=a$fMT zO!m(6`RbjJeQ?s7)W*UV>Cx>m_E0N>+?WPKt)Ib}9Pu@N9`z2q-!ao6Cg+h>>gk>Y zfBo@v@Gx=P=}Ym*UPcQ6!aTTad&#OLA_zf9WBrbv0$qVCFGRWaG#2sdfzRcRQ_1+X zLfNGIf2P^FzW*EYQxyNy$?CeH>xeeUT3NPV*b{@aWZ`WO)G3>^$iiqPB_Pezwk3$u z0OB?fXQt06M&oV9>TR1E-grGrhgomUwq!|Vxhy~b()BP@-ZcJp{&oVh-;YlYT=*x$ zA6W#(afG+aWVj=VlsSSwbUms?G;lsLQNHK<_>Pv$SZPbxO!#LAhBNH;jG^?bhl+gS zQ_F=j+04F>w0iW%GSN|24cM-%Gxu-3LyCpNhSn*5d5A|lLdv2)OT4@)nP~#n6Tay; zsZ}=oflJ@zUSC(T`}fKl^IPC{`Jd>tew*f+_&d7Wj$lUzjdiwa8Kea$3geCl=N(R) z?g%e4^~d4#C1)Xv;A(HVQz?nf;$}KVXSP-RbZaGcBuGh+w4@(4scLeK)bVuyCe`<6 zPK!AHZ0aAV0vrJiV#~5WEd*AQn2`^ga~@$^rLqrawj7@)*ZnKX|NN5x+n)4GyLS$% zuUEut8(67UA{QE9ORj9wC+}+KG-jgA*OWs;%dq(}JqLO>=(J9P1;ri;M*sTLM(u*A z^aRw@iR$%&OX1 zUus?|6k{&T7YRCsDH|eq$*ZD*f0SmULM^NUVE-LEb3OqqaCpNYq%SGEs|P&Htsek= z>KI$|$xX%qWoJ{hYms2q1GYiRt>I>c)V>aBgTh1F3tN;|#j1hsxgNo@rg;eNMxV4J zvE={k{8gjX+CxA3*|^0hy5X96ZV_WQQdPz8>>JCp!Bcc)Ds>VCu9e;FGtsbRLRD5t zTXI^JeV8f@+%EHPl)wTw!QdRjsH-TJh*}&aChKU3(ev!@de)DZzbXL2z!qa~ZC-u3 z@LZxH%D}4E<~!!zd54lrFQUqR;XsxzRiec?#d|W`xW7Sq+8JQ5pZ6pSqp4f~m~afEA747{hSNUSTdU;yGaUso3w<|L6ZK3LJ%|g7#WPec2_T#t4 z0334p52%sW+<4*bhtmdftt;l|+wC1_?K7ScssDcxLpZ2?(QEXri8T?O`5DIK5Ugr# zqUiP$Yobg23EGocpC7^jlR@a}X{0Nn+`BP5 zbOK|W5xwPW8>D%P%&_o7zjxY(+kR0R+Q{cUMZJ zM>ktm{{St@YZ~RO8Wp^kJ61}k=6_&5+v*>+9p%4UL+r7=`okmb-JkwDO;$rb)kS3$l&r&4%L_bDdBKE^$khG47M5o7G9c58RDOlhdobq= zgE(8w2kB(~`}eTBRrHa+=U#Tgntp|_4h2kly9Vp zD3R7Y1^x2Nw7hrQIFMZqR;(u14@2iNV@@rYnRXm@uOzbM7osk1x-$&x%b^#ZfA`)) z$=MM}E~=~dNe8PJ{wDIRWK7`h_19biB4x>oXaOu{D$4JDrAcc=U-z~))I686wFS}+ zro0C6m5xPAhDH9Ix!gF;5nUq?at`^{$Y1N)y{eUDthgU0*I(yKiiv;m&+IEzXxZb= zC&Eu1N}meGOQ97v)3=(pgKG}r)IOI;=S4(L)J5k>{AAhCM;5XRW=$1UA2U5pmz0n< zFFDSb8eBIP60+6mJ9-a3b|LHU*FWC_GHqHHzHv|o!dpM)XEU9os!{bo=sXDZ=m6)KnSE#!}wbUd-PL}tmmTU)~TE!O%EiHLzal~E^f1R+LP_f<0rUV?! z(Np(q>AmltwE|Lzpmp$BC-0g8fmqb$jW@cE#Y??=skxE2`K@(Rv+wPnM`(`@*YXMA zWb4~DA=+wWOkH-aE_9InRgl!pWa-*js^2^((FrkgeX&_O>aA)f!;kWq z&fLV{&2uY7s{=D1cUmTWwN9#TNOFh(5NtX862}PRz`^50+HXXU*oyH~ZHVH#1MjD; zIkakA_PPZ7uKvCAgrk{oyfkw$&92JZ^w!U7XrYTAt&434WtxJDlr&?ke0zLZL&jgu z!lH;^#g-P<_%E=`M>EC37evpp(>Q7{QMFM$=Xo@bccDD=fjIgN5zfZd_7Wo79cHal6daE*;EP^;k^FJF+(9v%w8O;MMl z^8my0MosFyBdst)AdG^kU$UC(nW~6>kebk{8;LBvRHYH<*s-<;n7MsU{VpDtcITPu zhX`BKx4k_`Jy$7yS{>eIX-at=@p)j2$SexU7i>do6y_m9$cSI7i05FY9F29QZb9J^ z(~y^I)pXYQX&jaNRnNZWaqVnGLGZQzJ@)W9k4!~^D%|_aMf1If%G5HvHfIWp0%!(; zCBF(c+-pv+YEnvb+oUHZv~zeDhQajO4q0s5DSBeAVJ z*E-XGFe9X)ogJ)qn9mmv@4px!jVDYH77_IBD672<=C0zxkl4oX#02H`^PXbWMcHQ& z&bz%nZ29u+K*>zcN+KZ&yN$5bqwFfHjz6s6!lh?>D2Jm7D zZQN`H<-8In5*_0ZQ~EiY;hti*mqwt?yd5j*5+)!BrK5`wunlDdJ@W#56U~Q`b@r-q z*y2D}`4w=pWkn};rODxQLIW~#fA1L%es%Iac{w6_Ri>EAw5jR{FfHUAImGSa0&@Z9 zU-_**|FRXEPf-ft$)>5>Zabp64&+e|6x-2bp|efwHO{<;1#eAT*km|#t^ zbcu-8z%09Mne18A)i(lo+>zG?=M?)J$P;m8J;FU^1Je>6r$A4>=fW9Mk*YHAxob5z zh<;x{Li-#NL?v{QMi0Qy?4r~({Jq%Q!S&Wlk|XUb?~1n`xO^z1a|?!5k&pI@ms|Eq4^(fyM@hmHT9 zhV>^clTsy24;l!E6uMlvxpZEVjdnX=u`u3vB>zVcAqsj9o}vK#(nc*K??+J`rfVI1 zm5Fuuw3|_2PWk!6P}VH@>Tg$W5}>3`N3+h@@S)yhA0R$xDmQ%woFc9+F+7XAwS2y9~eE z$`m?MU&Vyr?>sGTWvmsd;;Bkb)7{b)XSzS+_RQN1ruUS11oprxFBO~Hz&dg(-xn#X z@s&vzronLnion`u5gYh8-}UNUD`O4f%aA0OoKPaCCA5|)28{jc>^y`AB34XHjdC)2 z=<&28lVqY& z^$cqyqlLOFE2P};b>@ePDND}U>SqG)=*lXgJv}fG2ldE*XU?fq=!9Aq4MdL-k`|?k_Xja{;L3RY8e?D-~T2zJaYcp4!Ti-IZ3$FBh4YvT^#hcLsK&W)9aTyco$Y5_4gqC_|3wGGQF#!jZyYQ?( zkLUDfJ}nisAGo0UYZ%5$1-QL71@n7Qylzdixe#|c(k-hBCFJEv8esfpKcQ#k>|My2 zgK|5F5W(+u*t!q#`7Z=XW(}CyH;;~$D4%b+-J$IAwk&LXi7J%uyf{Nq#ZUChR+a*H z5;?L7$^xVfh;E*JHgZRq>p67Qq0+JM3@CELOJejMG>4cc%{Ij1zFYZM_KmdbR0%79RZDb&NpaxRA|KLkm68BNvqQ8^No1nA1c%* zKb{1yuDkSG1(-Qz0o`Z8plo-aTEVnUUg#F5ae5ETKTTN^7*uO;i;2HPF&V;mDXFB@ zO1!%BnClK6^}txi-+wCvH*mNkeLFp?w7$KF&K{Nu;t>ju8LL!6hP}JhntAJuri{Kw z$dg+#635P^-#Y(P?oSqSzylktZ{|jDTxCbMduGF-%x!wy>~Oq6^8)&sSMTGuZudHE z1vDTKRb%nN8_AzzH?^%dV}8H+{Fay>P``>)%)^)Cl7Z{}=wRtwj|Zkd==ex}veL@M>_kwL z&l95*JQ(luThevY!EyS>Rla)z@6Lfm0tv5o(>k`7_LAF$n(bkmZ99>oZr^Sa8UeN# ze2R{EqoPY%t@ zP=f@7yauoC7v;MMjGLnw0-YgWUF8GklhyJ*IlDH*U!U;piuH0%dU$-X=+?rq!cS;r zO_P7~GyGn*7cuz(DciVNWc{eEb32U*l-B+Kk6_KClORPMh;uC2`8+e%9>(*C>tppp zw^7wq)PApd&C^@M;m^*A9edNv_4Rb?qilM&thwGW5MQn-w!Rz+Da}&9IS^cjfgOO> zf72=NbKynwl2)isdM0`A=Hi24o{t3&wP;1&v|$@i)yt-JsmNWZK+fD>m&*@lEHUnp zN`-kFaPqu=Tp;T~6FW2d0t^Gmo)KY)?R9svY`4H}TfKhfd`cG4&VM(W?IuHI5)Qsq zt7R^h(BxVBz+L(Ma^*#$Z7Q^rHDb%~>;MuxPet>=0~>y;73d6DVOr@MI#PQT2=|J$ zG&z;tPzBzX{EWawe*+8Qw`qMv5M}LRSe!K=unfVxp7q};sw+7ur8JgYcOTNIBENHXJGJKBld(KwQ)_Bj zD`zvuAl%S0)VI3Qh4PmA7aloJBSrQkGfej9dpmW*gAo6YoSU!}b$W?Q^VQ4~3gnxa z`$$ynYHNAcS~2(4_HD9V1&V|>BR9HtlvXtBn2dPr0&Jnvy~7Te_;%SaiuHH{%G9p4 zriGz4>cj->S@OOLS%kZV*XmT2<;y>syp%H=-0fDgb15N4>Plg*5+^3o0iR)RP7Y-o zu#>FmdjAgW6&M~m-!)pkAL?^?j6RT*kza_^t{ygW7fCmn5Kznm+xXHVbEs-Va{X(g zSAAULg2|1VhAFpKda>GfJ_L+-ZzSu;2@ge10J|T;?pVK~>=YD&GXu{1kE5*-V|v}H zpvlM_S<9sH1AmjL?*H7SPxfiWNfwqC22$_|D94#}63)5BJH&cIZsbARrw$0ACoPM$wT+FbbW|{bBW&SRfnAS^SHgMF;>4$&Nl`82(#H<}L`g3`Q+avP zew|hMZO!D+tFrBVfTbD6Q>LVyZ0_MdwcqK@=i4x3INlQ?@8ZOFLWXJL3PjL9UM@gi z8KwGyMw-a7TcvqWRUPmY+2QUUMiff!g{Nh| z8XtW(=eeI%FHjF3$+Aad&ggDZU zBfQ{*ZC0m%Xmh+HI&v4y-b522IA*vej z)3nuofpXr<%$Wh7u6iL!(wsKZS1R>%V8lbPc7ub`WJ)k~3G@o10o-2gSG5 z4Cy~S?qIDN#pF7UiP|31T6GBlN!v9$INRhk4mbv3T;e=UxFGD z)T23n682{_58baA#`T8QDiV@Yk$hq>hR%j$eo$o~{W3`5Z55eJfNAHTD~b4+Lz zq%ifsreK0})m8P3>uB3JddR;hZ}TX;s0>sKVe$3uS+a8tPCLTom_=pPwe$b@dU=VK z3Ga13b|g+Z(5|mdEc$7rbcMtH{_61h*~r7fr1!QP2LPeiip+r2g#2NI>MHoX7#&hH znL6+JYFF$$GyHS?g!1PpZ>gs5M%o1?XnFVvO(@d+q5_YM(rKNpoZ0t>Ma3W~`$ZNX zS0*1pBrm0I9t7LsIGF&5`u75`Xgy`f{^a_$GYz_K*zYX!<3pJDz8{K*Hujm$if{ya z6VEJIsowaYJ9da2-S zq9$?n<-X<0_v}^2gGf%C(h1Fu(frYXr3_zv9pX_R!o_n03b^Rh7bQesehyGhuhlZ& zD2g81tIJ9Rg?>-oRI(FzzF6=|UOd0nVmo-X=$`TbL(55W)jSh@)7}}hw4K1gUC;|r z=C!(fHX&eXxqTfP-hSw{UjW)*&+D3sy)V=l-Sii4Y#7rML0r+aG8Qya8z|*wm4!=M zdnj+c($xGs!nf2Z-(}VHe-vG3Sd#tQwx_3M!?Mh+l`A#1+}oCxnwmQ&m0MDCZ)mt@ z?s8_RM@&~?OQ9g4I_ zIgrTW*k>X9^Bz368y8XI>A5q9?P*x{*`2^>@R6bO8a@aAhb=+p%AOcGZyau6;{DrT z0UVd4Q(Jb~-~qpw_5_*F`u5zqBxS4Dp<(PR_Ug_7wB68$S9KbVFYqNPh#j`J(?Sp` zy9s#_7v6_x$RZ{$KZ@!sgKG<{wyDqK?2mA0Ol-W+C7Iss6eQOziwR8C0SjhYw{B2#-Or=C<=rrKu=!^XK)8Lg?t9R0TdibYbJ-zWUiTOq@)O;+kAjPY% z$xzo$A6}M?48o78RCy_nrNgWBA6~HLKLp#Z=)gh@p zg4i&l+Ug1TVKer4>eqC&kKg-`Q&HQK zg^q>o*`lqG^yTSsBYD;=ITCyTKNS6qq;!6b3SmamVNdASlW7}z@7bbbxAZ)i9zF$n5BeT<|nH8J>w+|Dj%fxAR-Wd3@w(mhn(%Itpd~@?WKr`EY0UR#`y2eL0<6c ziN0{kNbf~^^Wi5iRN5QyOD{pp5uU$6GlHEhcN&N9lsS>_*#mTlm!0X~&nc?Y|FkWp z*p^aUIAyqV@|{>1r!;vx{k{NeK0w2oKn?7%xSUi;fR{n4dj`gN^p z#@A^5&pCScKRo7Ky0`wbS7qKPWm!2#b%dE|W(}2?Bwd>JYMeP}H1q*lCi{wdV;~p9 z3VH}`<-KW=_$bSHN{G{rqe-yusqe8FUyoUpGTce4vdw4@zSR;@-V{Wx%gs9&VCf_T z`?FAi2t{m;?>#AvZ*3@R_KDmqpm<=vjIj)vK>m_`K}Y`Gv7jDZ;e1sLzDBIhmQ!5U z$ZXGZtc>%rwAZzNfYNm2`Lyl@G1FR!zMe9dnsO;Ai;%X za}+a>TPHrQ_WG}J*&}|Vo|k%SBR^h9Sv|bf_u6GcV@NjYvCM1xRE>aNv(bL!Z&=2} zK&*G=M*F}zbi%2nI0p#@V?%`0lAWOlmj zxG*!>k#ID;*_JV7P$LxX0yM-&>e!ZK{DJgDsC6PQvS*8xCv-3WegjBSF7kHe>fSm~mQjT>%h(7-;hyK*J|a8pzTHZU0MBSu=q&f{SPUsRxx z*l10M!wCMoaT?RZfv!`uBN#SEztkQmOw`bF$lv~v^A=x_ZEsGl+QHf$N2Pe1r!E!L zt;3xn4vPgBKI^%WM51nuAypy;qfagvB-QJ`5`Q?NI_{b#Z7s;b>-Z=arH_G0y#y0aH(Cv-J5J0b|RbXJ5EnzW`M*&41fat_+y$8CyEN!|F z^wJipmIxiCPZP)84F&YOTv6DZ3hbcHY8Q5vN zd?&==>oU;2^sCnd!-m;XK)>y@@>MboZQMg7@HhkAI$A z`#6e?MK+PsV}YvpqiQ065HS+*R>hQaewTE9TMD^emFfE0e3NJFEi9uK6&|!2{}FRb zyLhkOYu4GBk&}Z&u_!L%o#Su4^YO+iBs#lQ7wgaN$8xf-GPQo~=Rt1#XrZg6qRwSP zMb^0;l%bP8C+++A@twr#p$myOJYwz%);*;L@bfahYFS1U!ukgGRA4B- z2FB^?xETyM~{SIb%BV2S7b@X@xgwp-4ElbOqr%Zgr2$DcXEssNO>vgN$;D&*|pA44-3zFk) z>RZt-XYD{)X`078cZh-@0UABvZF1vw$Q|` z8pmdPiZmS}u!p_=O3G?yfOYW|@BK5`Z{Acn>gozmIrRfOo{iCBGrJyx(gn#{Z z`T^7_eOYy**Md1%`eZ&@!6ErRGa5#8l8QlnB71~}2Kt}xG0!m8{NSGcDf#zaH$>vN z#4=YgMj+a{6-va4F%+uD!=4x3dhco{-LEE_TGp+# zYmteEYj0nNMV@im0T{3;2~pi)j|>odK+|VvZI@jAI5v?0={)Nys(R+S>n_ph^3c4L zSGnihaUw*7 zk+~6q!s`aDYYz=Q@PwExTz6u49fkGg7TB5_oA8*4V^t2f0Fk*aqRs!voVcNTo0&mB zz1XQRCucNuvu@wY@PG)^GNVKWL3Fyr)w*4QpBQk{ z3{!^S{+>P3g5ro;@{Cj9yRH+3F6!i7qocNFWc343PCySClU%){3u*POX(qOl3fL_N z>)VG?doPA1+L$1ilM#%9Pn2l0tGGV?x2o4i(*6liAVw(D;p@gd=UCYt4UO57T2eZT zt2;}WB7y;p0mhM3TpCG;EzG)1E25^fJ^60W%*UG;*zKkYL`G6&UI}+REz2ER;xPU> zTr_maDXbDs|p9RT=iEvzXWH980}^ zgkc-57q(Lu<5}wUVtVMu!1ABWcPC^~h6GdDOrGd+H$(kyDfc5X(-9fmn`fdxwF8$P zXwh3cEI};Lggi6V0)@6#W;H zv+lOLxLHxwKKrDa?21KPpa+Zbh}Q40u>&++gX5f<+MCRhvc4<#kc1)1mnDh8+5p?E zeds0BN>8?wGdvrCE@2>l`y=@S9HNo`Z-PhS|HpwEufA3+j=$MN==T|WdPDdR_wo~q zh+_3)*>&N{m)!P}*hf;PvOI$lkTz0kgYHB8X2V%!9e&3jJwaru`0-m^Kj6l7BLL<1d3}#C^s)tbSPNemf!<+`B=AM z)9v<55RD3q;~YSf&XusdMc%F=qg7kFUy`5UXrE@1+#sRDe?Zmw^p{2PaO8)%MYPJ4 zkPheD{TndloP6UtLjRIgVOgG10I@coyh>w;01NJ?sJNW*QcZO%)-zrwT zboZ&?_YeLi%}!YIQXqm6vA2e;tysEC@Y-JK8Na=FGUpx)x(PeO5iR?)EC(~eIJV2b z-L5bJd_TSJ{E(jWsXM+h*dEyXl2^q1YOsgzI>nD{QI_u|-VPu_(0G}}e8NjL*j3!a zruA;)mMNfm?%-cU-7vCu#Tq0Jrs#y6T%LK*n%;i2)QdFh9B(wDw{PW{_SlRM80@Vd zz_wClp6bUYJw17g(9yuHSkj#ST^lGL+L3`?=|fM+ll*_@Z*wvR8~_9^p8_=8mb7ywhdbno}S$I}rumW9&&IIF$J z0jL?7J}9Nt8bCru>UGi-jNM(1#2f$W6}3N3vik3+6E2hvUpGymsv^B~8dXzXQUVd6A#cbtN@G-Qu#{xbeb?sQon|cf}aHG^1yhwg` zGdr4|`Wy23_sW08nM=uIQD!*!Zl{A?yLBsq^MOe#<;EaipDq7Vw9XHv$Bu0l6XrHc zDq-yNoara#qNl>wkKf2;2RIo*a!LvKbklXQFZ~Krj#6fqh%XLF!*iz!b0RX$#Nrg?*L>%RKq-K-_J?SsokuW zeGA&5qpKdK@RKb=Pmj~~D~ozgm+B-wMTv^ARELAr6;z72rw~i6ZQW@lz`j!O-^3AX zPdxa7?nNk&c82%(B_g+Q0ey2&QM>n}BKsynTaSyb`YN_MzGKnbpv-gFw^sJ5z~vWt zDz}xF^2gPllw4RnWmD!=<(u@K!kKAf!SI=K2EP7BLKGkKJ(M;8knH^0H^aG7wAJV$ zd(k4oBGM0?!^|vyd~$GpROQeuIN-K4ovxtv=A784ix5N%eV~)|gvVduq>G!S1V?*G7bf^Q*X_x5|N0TuMJ* z!*H?L-{z$|%5M+kpj)y*)|GuYMa*i_ZGju`$c8JFGhRc6j$FMvNZ2>HhO>Eq-<+Z9 zzR|i|kd~#769YOP6EZy6SD~Eh=ektS@oRjh*ExI=T5_%0qWX+{cmTS=tqisuf`*%K zqi7pB$Q5_v>%~qMCNiA^rjL%}CJ#yuxJH^KG&39#%>=>}8Ob>Iwy;PZABTX_ixLW+ z4O98;cAa!!99w2}_O9PclT&CBkF2WtKr=Rxo3Z8jnJBDi6I`m(kHhH(Y5up1TZbD+I)WjjPfdfC+cq{t zVp^b159PpPA@0$=zqn%eF9;r;nER9h*?JjM5|D9nf<#|CA;3_^>rWg`$2GfcwSquE z0bix5=sV~|NhPJpdo#mjMG~$!nDU)4*5PP>+p-)YdY6qR9sXU;vZX8o)U5k6Y(1&7 zX;pGIoU(0375iM7QvB{sjLR7kS|tD>5*AR6Y6Y9<&9_Hf-OJ9z5A6J{*4w0)9#gb> z1X8o+VqKe?F2>*e1P?$a{g#!yWrbO!Sr!|#6m%V;cwDV57|gR8 zQ;V%*J@7q~Q#omT@4hT(Ms1+Yg@uaSx3SgvV_OSBjwA^}eVELf3$PEuy-1 zpK+{f`e$?T7}yJa+e_kN-7)bSOyTG~GIn&=f~@J$6>)sM`0_y0)N|qsIqY%5`mtm7 z(l`OU1JZ(aP)b{QDLY5e1h2dn+XR+=CAr14^g?b+PR#a3y~J3<4?g$Qn3m*9u5%d> zH$M!J6~3Bg8G}%Gv(P+-3IT8%0EvtR@ZA$BjxIp(T`0TZV4E#`49qvcs^O$p2`xQJ zr%BoQMzy83sl zy+iT~#>iM;K>_l=o^j+B_4;p=Q&rT1M${OBOT^CU?Hq z{Hp@9XO#KDX_)Nl@vl!4)sUdezmjRUbI4K?7lBN*~{`qxsCGhI* zI-zYp<5!Wjor%g|@cw~VgzdiT-=@;S7uJ2?`q2&2 zL;b(cOnV{UJQwq}B$}?NIZq+C*h99JWM;Z|x$4@(BGm~wRKzaz*wg>WxZOIt_R#A% z$YUJ^X9=AQ`%o@&1%faJlPWpo3{_&D?&&XMb#ndi{Fc=4ol10IbK;J4A)}(#^jy=E|HpCu4fH=1+!X%#ky)DD^##82 zQHuSRao*GAWb6EAd`lcFo*LBdsJ1Xj5X|DD8b!fpAG)`7q|o|jU#tKhn7lHg+UA59 zc7V#GNs)F6wt(n27QkB0dhY2&@cfzgEEO92*P;O(8iS0w8Duh4mU+tO#Gm}E$EH6* ze!GT>^H}-i<>I7-^e#+vnp(TTiYRnQwec}wEhDUu5c}eG#a7vDTeSgkdEX~kaLP%; zA!KH1ozwshdeCP!7SY7uM+xf^oN3IEbfKg*s&+jL<+4;=PTy>yxC4x-pH!*1R zqf@g;(NF8LW&%~Xs|R27Wge!u+KwAp#5tBal-+5GE(m6!wa@h{c56t>IYg1hS^*j5 zN8lQtx`?JzfsRLQ(n+?Q;a&;H^cL-RJ^kM-2j-uREK;5qtfBSk&gmOBJ~b^OqO!%# zSXg9@^%1E%$EI&gp6(pgO~4$yfb!qcg95tCf=9}wRGmjOV<7I476BIUMXro4-rLtBDQm~Q2^UU!UnE@uCPpLsHHxy zaPR!A8L6yv$$LVsrysjz|1fVAU)9-hmJ~gi7*j^fYpq3Z*Ns+%CCK<&q?R87VP6X5 z7s?=Ru)UCpR9p~6%NqTTU*fOS^`n>oj-yP28$a~V|6KoT`|Ur>*zK`4SE@S-jr^03 zs@#su9-A%FWF1Bg@jBDn4iU>N`-Xc{Q{IJ6M3_v$KLwq)F0-On%+r3g{MR6+Z$A+_ zF@!TMdJ{hAL?8?x{m85A2+*mvli`bI3D*TcAKUarvRrpw5@($f5WxZX`vMwES^Kj4 zV^)2|r=L8^QtGxWk0~e?EDqUsg@s|U&9aPHU4MG3o z_y-Kuxs-GbCXhye`-OgEX|dt5biH{girA5oV_4*TUNU1~j3z-OIun?gOJ# zuRLBIJb3W-tH`u1Qd|3`CqCH^kuzT8l;_;8Fgag&UVPzjgY98h1-SQ(nI8dDv+jwc zEy74|Cpu{ajCp3TA=W1UxU|@gVwZ{DZm83k!Y`%fF{%JCGQFysu z3yT(2F~MobJcuVLbS8AY8Fg-Stbq`z6NIX1z#krABA8#`VT*I19?`f%_Se*TFSjxI z?)K&Et@N7S!0%5(wVw-mWDotwd?44VuAy>R=0AC%Cst#=>Y?HH8GvlLp09?&S)SME zm){>DU}mt0^gy7KTtOSOus%yR%am$H*9E0LE#{X{`l=w-bMRJT$N2io07DJ!3DA$u zBNc(Vw${A z8I+_D#^}2~;FgrQl=5ltR%mO!cR*A^*V;-w$z`R-j{! zl&${hWx3hIaHvDEwbjAG$iB#|Q!sFr9Tw>R6DKU&_4jAKRm5`jz-{#C7pv%aAfd6( ztpk*;R&gofs&niG<2@ViAsY*`9WVKh#jp%}*>VXFx$i2b@&P{{ZdUeh1-;b~ua^ z8G@P0Ip`}qIra?Hy+aqNpzdsLFy;)?fBxc= z-eN$v5#_b0b8CDL-^mt2mzbG{1qA4!>pSRYZC~l4)^dYJ7 zm6Xcv&N;8BUC>Iz^L9)Y<-?Td zXeiRs)Ik|=AlI>La69bA#u4|>OtXal)>Lz2qQ7V}DLylaqW;>G3sO2Ef!mA)%&iz{ z6FYr1qDizSL(ijg;ces6N{ru3&y4miG=9meHdSu=+ZKMIqA1W`^so|`$_g{a9@rEm zhxAUAJ8o|{k6G=Rqfl+Yz$JE=Z@iJ?nwcXxR&+d61PtpUdu)|=E20Ui+}G#%eQ#?0 z*v&elUfUg8einT#6Jq>??323aOg7Xv5R~nOA6z!%?LNmdGSL&_bF*iB2QON@eF|*K zStyPOMeRF3epp|SQ-;D65`(r3y?A>B{hL|FZUNDc*QV)d>FhwNIcG#eQ9&fd7rT0V zqhh1S!n7(HA%}^cU@V7umk7K*0d3fvUQPMku1EdBju>ky=e>@Ez^!D*V{)pzTR=FL ze)%{?aZbs^Ln(+an4QXw96M6~UWQmc%vxEPDLMiJBIGOSi z`m_Da|2S&n`I@##4&;&E$Npm)4Yn+w{d<%}T%x}eHR!g)tDfa3*YvmS-kr+qS8k_} zk+rSRjItk$1td?%F;o@^JL3d2Ix#7_!}Gyzlz876XbNL>7B=<7TIEmiARujVeh(Bm zi%+BSj6vHi?y1P`M{=xMDj;@FmP>?u(&bZ$wa7N%0M<#_g6(Yzo{>#4lfM-Cb%4AVa8vf$? zp|RRJigYj8l}8r8yF;6`30HN~$Ed+7ND1{)gtU7^u-S`TWgm!=FOMsyMoe zM`El7>$&%A(lPMs0+noc8kLs~EX|%wm^2*g)y`G}bFU?UF`5C4alg%yw&(XA#PL54 zSDZ+g?HupNhNfNWm9T}*2Xq$<(!&Q_Nf-zb=?Uad-kfX)%_MBAy*&A;y~u7j1tw_f z@3_TgG@x>*J_-}~R|8W$-@FI)XJ@XOkl}fNjGI9_v)6fCk1~t5Rdc?~EMIUE{n_#c zPuPfXM)=hdo@GrRn1k$dn%d1}DnsJMb8Z^)|MOp}gn{m?zfZ5#a{Gjn&sfmzwpy@@ z^>+KY{uyIyB;CHgd1F)u~bMyL*X4 z3q9lt_Yp2dLkJCgZbp3)NH+A=3!}H0+0KKyd7+`0S@@pbBB_48kw8jt&v6-!x;h^g ztmC+JVQQ`A(adzuX)9k(Ij8&6U$p;`UEYwesad>+l-7$JH#_{heq@HE+iRL%7o4`4zWYcv$96EhV2%Gnp^ zcoOF%RBL^$pukAxaBC}T1I5NTj`@!+)YQyS%3Hj!jM@nuVh4!!f&|!(5eqsBkMb5y zEyp1i_}~q+<2J%G>AmXpUqoV8?P0}&z{=x?{emKK3ClTB=5|^JwwQL&Qa#6t`ETfu zl4WHM6VRb9wlAI$got7i*<#Wdh_uK6}088%8F?K^;lQh ze{pGUPBYP6c1@Cg=^FMW$J+Xj@3q+1@OP>?GWf5{hE3fO?2^?3{>Z02j?$BkQ{<4dnMR1C<`Dnyg0;nt(GUgM1rCFYkZ`$yc->1NFq!?$ipGUYl>zP>Ho z^n3FzSo2d-Ph=8(#l9TfegL(oDzI)tRb zo(ft0IMYt9SE=MN%?|P@hsudE0`p^#YP{uT2T=@T0CoL2g6_rLn)pdD$X^myZ4v&S zs=lZh^v=IWGlH}20!;Ig!hsXUA2hLIqncc;3HGQcl0yzKSX_BnmxkmQOc*>Y(xegG zZoSf$vGn}KuS%6>_T?^yXlJhm@|Ld^xgn>08BK5`utjN?l7e6+2K{?BSq$StcE$vI zQccZ9L>DOL`d;!U@b15HzuFW+G|q^2#RC+a!)&!f!5I_%-F*zTgvG7V?A>Qt>bn%9!C-;Gy1eUshyKhZyStRkY04e)si zgHX^-d`ywes$h9N80Sk0osE_{dISOLa}^p|&CWATt;b#K8Y21OiML!+pQ&B%uM%r{ zg*x5w>1*If%Wd1eD=h?Lkis^*{Zf9Sa^`v?X*_;qa5d$miF=epnURW#O!!t%ktMjt z$F(V=T-@gdZAJCKXqVg_I9^F1u1o>P6d;HFCqKz(4_K$wuIkkq(nWjJEJ$GkU4)pt z&bV208yW*!hnk$u3A;dACW2im9W}+N2I*&|RUJ1QEJZVoSTt+Xxy5aA<9IqU z@YB?g&hI_eMdSLqWE2WmqE758`cl8Ni&X)8;<;3mk|d)1)^`!N<)%-o8X^%MY3(}I z-_8*%rW||^fm>l{Lq)FHIr)%{d9nuNslz8XsW-ECJbYFkzE#coCxlq+-yO~cMzsUQ2UGBXY^-oRr9mGPsXz-s&<5 z(q%#D3%mu4CvPquq5GU-%`|#}|ENl*j1huS=LEPZd%slR?LokzdL`(j&Dfh;jY?&q z-k+`2ISS{)HTZi-6Wb$KQdH_grgpJ`5tgyaqc8}r>Hu2YsiO06&&_U;)2=Zu#pSl< z`;{#!-32A&>GT_5LB68~p5-smGjT*&REnMO_YEAt2U0_exu}+{}Ww(YQ zvMqOgz^akR76mb1?d1jbDf+%UYZd!8a_K!A`nwb$4-s3Kq67=W9bdyhf4L&^w}+3p zDR-(%km5meHlK{LBf+yrR2S1w$)$XIfZV+ZOtNA|{p=^;l{oDu;0kZvq_f)Xf8THU6nIm){DRM&Ia4dknmY`!L3Zn^gvrhA z>0NOyIlJJ$d++m~JKm$P_@04_smR+S)n1w^;rO@9Mf~u{2&TqTQIz}n^HKx)gGNSs z77Zn>M9?D~)Fqk9%erxl(LKkCpyhQZrwex;nK`ob8<^>|x;-}8wi{C(GK}+r!istr_~c>i3!LbqlMiFw{_QrsTPb88bS*!a ztb-F3&Txxzi0gRSl=aWfh2oE?h7VcjBB?=>zNSH=37?raxFn2J)Foygt^QXdmLDSK zh+8~wb_G*%iVgQu=_yxM+<2nt({iiJ>Epd^=9fk)-=^$Q=zEqcEj~@D26XamaD=w{ z_U#4lSG1hc_zsI|GfpgFLv`bOU_iOTdkyuCXlKsG69&aj?_=&ZJrlZicb7Xwj5BEA zYhxW#O!ynhpdNyQ@2A@Y1k?eZ$XSh6c6NpkIc8SzjtL@W_O@vlnq(5|qv~^of##ucMLT zS$shhX(~@jVrZqfB!ORC?(E|)V(xP9E@|wCX?6d}Ix!b|Hmqpzbohm8)diW!q(B&# zhb2$K^AsT`ZSiWEkyO>H9d!+HSjcdNpde?MKvg{s7cyq z7K}-!!d4%bJf&YMx@lOmnr0pQI|DWY4p#P;8*$e->-q5_Of2cxSPECCE7eDHeDte1 zRcKMXr`sr3K4sms>}rbpScDbaaFWPwZVD zyLaMMixpgaB1O8W^`?;&t6~IscAt%{V2szmY2_Z}g!TWIME*sBl@$3J-;0U1M9!rw zN+nt3jD#$M;Q=mZWGfEJf#*p9w>|f*pkKxHlA8d#sb>^_&dP8G2&?g-_#E*FIR0pB zAbnqLG?S<}bzlFW$Kc5spVByyBh*hiIf2`^2=#-OBgaFUz;9nYht*x)VE%~Sq87`)*>gbi57|Pv(!N_BmxKp=s zSP0MiCcz#)(K)=_L|yfIh)Fks`340V2! zp!2JaCxiC%O3|PDt7&@2!G&2Xbs>2mG7!lz*jipa1I$~X6;GVMHkjYe^~m&j>uJ9) zkusvMBDdKO<3S_IR3jefJ50IxulEcY2nSPEZYr<1Qa2z z&{!RYeNL@1ko>Da4LX0?yoY;y%8)#*Z#guf40Pz2kj&cmH`T6>w;ux6afG2U^XMn$ zpQe;!bm#T$;*@{xpE#qp+j|B%-cX*f{Lu`O2Y@|CuV!Sh&lqVZI>nu7O)Gx=pXk|c zp|o?Cij915BbOuCqV_|<<=_Y8XiD?Fk^RtU1hJl_>u$%Cr473kt1DN^sRiCldilY8 zQuTM-oMvG0J!66?-B)`s+^v$)<+T}`!VA#G<7_y;6h%~*y+3Ir&)jd;2d*gUo?aH-JpR7$o-O_cy z>DS=S`Q}U?R4af2{>Smu`o^eWN{N;!VFN?$TJ&Yf(d+)lVXd&>cV(j`2T^cNta$PH zsJ!6P>)&c-VtKt{AA3yiWr1|=Tw7KXB-++iBTH9}_|lwhh?x^u#$jQ5?=RBTC|khk zQj9CFT$_7Nxgbxu)p=Fe%yVX0zE2)`$gT;4 zChd;V4n~y=m|~4>__8ojqnr$R*mnNYk^3Y6eqQP=X}J{XUV%78;rUi*Ly;@SIP7v4 zpaFMxE+P7`_=Sp&ug0q^llE3#^B-1WZQI{drpw-Qsq;BD>H|GtlFO&ind^VYt!DDH z>Kz<#hdZLxQ%+^Fl^eW@j^~`ko8F)2RgnI9(`q$NN{4*bKzsT>Lk*CvANlY=01u~V z1dTbcMZv{+fiz;zp~6Rs3PpZp$Fy!N<*NOLYSwgz4u;2#&-1#*)f@6}4}LRN5-qK& zAnZc0rPooWVQuS-116#Q!9zIp`eF525ekU*(dq5L^0m3qTJ=Y^R2&>ArdFQf?eweD zj=1PRAze#KxQPGTt~*kK({sgl!SnSHKKPgMLK@vFyKMSprlGS1{^?o{<>2!$Qo?+_ z9>o|A!kd;P?iy6meH92c(zFR>q%6=20?MZ8N%hSzTZ$!TX%D=%k#40MTCOuGF9D-FnyN{ENNB)(|3 zewF}nh6Q7%Cgwjf&p&3CF5;3L7<|Hl_B1PA^P2km?~J)W|B83|E&iw}jZ53M`uzfD zKjN9Pr-oHYD`y+J9zx0TX+Hu-3bFfcI}haHSXj%L_I9R{ZgT|_JTLz-cp=r&DSv2o z;Bn)C{>y<|`pWyfsvYn6Z&Ow-opc@Nt3fJuRZSLJLtPBi@>C2}q@7g1WuwMC-&%c4 z#>(L%RER)0zn+U+l*(f8aWPAF4$9%(0*z^N`|8kH>0}1}{&VDna82k%4@HNT-<#bw zLWX=mDK>ZsW|LK|X)RRF*O;BV- zX}P^(t1&5029P2R8%Xz?jvK1(YJMN7a}SFCH7EoY{P1wd;63x_L7 zpnFljcZej1ji^js8vdoK(h8xc0h*Iy(=#{N!8=x^oIZWk)ofEj^h$<*fRT;w2F^{` zrW(#z(wk@3*D53g`CV*pPLi!Ade$QMew^;8y^*#P81!f_VD*m9U{H&)cWqcC($~2? z80|N@?t5iwrcWUfov}MXc|=R@fN=SpW46v=+Qs*H8}DLT;U)p{+*+$2?BtUl^ZH)s z|9V>cBxNXI@5R#rLb+O-TlwNdw0tHe-x;VY%||)NN(Aki9%)fmcc_8g4JHoH8~^^R z8C&W_bxnm#`PNikk+`p(&I!|ynhbQ7m*t^&J74@BvVBBa06*k4G8$w=w~BmcbNmgK zyQgxcR4qZ-M_GTRlahiS! zZE}k^9z<$IY`Hgx;G>Y}E2RLgR%r+n52(_fhCT9KJbA0xe^N$0X8d$!ScGb-p}{PL z3MR;bSADMHjS;iAtOQedMt~5|@K9rq+T%;Bo$P;@!!)hl*~>K5X5=GUt7#qBfy(Xq z%S8me2yf5icb=m9gCn{7UH*@v>kMbB?c+Li>ojV$wThzlrpqphTCu8VL`v*US~Y6d zZeyfoszi#!Cbd^lVw52E3Sz}f^1SE$;!`fyNzS>?{l9=e(AcG0X5YLiQ#oXLU9jok2De-b@nzLeuwt&|1O(xO&c>PC~Ira8+WTUx4_Zof> zGkPD*Q+$rimmZhI<~0_w*OwuVv&;WLO>Aikl#2SgqsgO^&gqN8?`c~0yb)AahZn!j z1aHAzNIJE8(i&L)Pkueuy*q7biLg@%CFU%$G3GxRY$K}58*f+UMMbvJ)M(8t+w!H1 z#?Z_ShGtEYqO=BiV>#S9z2}ML?gaV7{@L z&F$=_&>gwlZLP!?#v07g63x7##W|E<|07L!NIm9g)vCkGNXK=YevBs<%j`~c*S}7+ z8mz}N^bE<%aQ(5S$4?kO_|Ft4tg(E(wN3W7dmo-=;JF!TJmb@39dV@k-?hT*Ilht~ z>$uR}v9akLu{GWsp$|dUdA9x)Yl2L7I5)N5sIp{#ii5{{3kes7mYCD6e`aZ!XN!Z` z+<>g_6yWIc4RkV>*ii|++8GtB;pcJN4G&G_Ec*9tIU*C8!Hfu={5e{0rEW)l+Vr3# zs3U*L>i^ewyynBI&e|l=%>|=ZdOdKpuC>a_V1ltr2QE|l9M@jg6U>Rj-iMf*g}pxD z5t1G4>!e*A^3MH#Xb+kB+HuJ}pu}#ZARq@Vv`h?Lem2)L2+ec?#$F<6OZ}$rA!*y* za+Du@skU1u=vr&vG6`kZ@_83JB1-H9Se~)fy1C+7VGRt>89}d91&Zo>`fN{6c3Zdz(63`INRye+0z!oN?WTd4ySixd7( za6kV<6H?tIx4l%sxNrz#=hID}8=1>Aotyf^@3mU7aJI(x94GU;fHlvhEKWl^bGnbR z`SoF4@t%Du^~8Mmc(j#qA!RFPyO&6_*h$w^GYLtT-q~dTkLjzT>IJ$;zEZNW@!+1{ z4lv_;8Aglf+MP?IhH&FI=6&IZ_rV_pU$MX-Z!COPm zbw&fZx|~*E0505d47NG(4h1st0LMc1|D)%5@1oi)8}uEvFS@bWR#ipy*2Fw~(A4vF zw(?iq0EQoGXtL(?8D5FI9J~xecvUx#K7_fD0c6WF1#5tKCC6^i@MC3B`ytz(osWTa!VR+ZS8iboR7Hioi8S$> z4dI_q&z?PEUC`aN3Q1aEce3P=&vn3}L&UBKoKrG(vmFr*Dk~hpKzCF#9MN~Y5rMpl zDo&980zQFm_+lm5=}+B(8%6Ix{R4(5Vs~{s@y_!ZG>h)v4NjY;G;AO1P|wim&R4@A zO-aahJIC1%Plz8*@1L&hTM>wI$udQ1fc?NBjRsluHy2Gi%ri3a8Gdx=?i6r$3?T0Q z)%(>$J~|I#%>K?z^E?5{L2s_U^i4N+I!b)ocx>MF^HR2OPgzD|25h%!N)24jQ9Bmn zM}i@!>IIkyp*Bcpuvmf^=t#?eMC@rb|@QSZ8u)v6y1ZWaAJf7|)zgaYi}Jp~LE$qwXrvF-LQ!rQ|4f@9e3`K~A# z{}{5}?C)-(2ddRM2P&`QHW&aRfjV(E5Ce8_^zGV!b!@$9cGPxbd)A5`lcrRs$`A6< ziT9D&sivRe2YV{VLsfh!`Qt|$ba+x<5u#3LJ!6*W&Xl}%dDW50A+fwNQbjz_k49F> z4*D7`hDgJgJdjLrHHirVv;~()<>wmFs1HrjhY1gyQrr1Go21_Ud3DW##jU>G!zd+P zv17suPZwpd4E!BUSwsm{*LyeFjpgoaRu}93$Hdwo3w4eJH*E9k3pW$*%9Y7W|59K& zzmOx@=b9;Su|v6DqJy&cH%`4#BB*50w;K38u7rF#d9(J|a{Ou0YQ}zsx%$6AXGsme z%c*{ZCG)dd_Z7|NIlYKHb@l=V3ci?LadSVo1etMh#7KW!OE09XcNakMdytjP9RnHJ_~_Hu$8s+7)<3XL$XA&$16wok6Nls~rC2Ke%eh8(tt;;|sihtmKa!|1~>#eYP$6dX)0lWKZP}p*d;!W@8vI2DsH{F_pbg zD-0DsyYo;wbZbK_va7?;)@!4?bjYuXNT$CRoY3#>HHNZ^+?74YFO;mK*!>@q3N=@> znzT!)Wl7hwbUudLjhPs0)SPnFips#MYk`KkA5=cMRQ(U_ z_rd+VD}jR-9WVgVNArdjZ5o3huEagbg$n=0x3MRY3x3mzT`GaEHI(I=t~DM5cTn9X z>O84cRL6(%tFQ3EyQ;UZ9Cfa-VTW1nEss#T7>9Il^v40%y`z$Zqe|Ys5zsT;Qo}m zSe6qcWp0-^DF6-yBrFQjjRctw+6hcI9pW6$R5A1RXCfAeHh9BtBKlCU(;=cNQlVG$ zN`AXoLwDS*J3Z`$%Ura$kn#znGM3A%xL9bJ&F4VInRr;Z?FQ_fn3_#>d&3FXOW@)| zX@T3z5o)4`?_f6>0Oy4*@PyckBu@*M*>6ovky{~GX;src=;)oZQraEbi^{(CR?B=x zdaK|Wwj2JPsg5eHzu6NV=KPr6Ixht{sYm+v_=D0sd>;RNm1|sSihN{j5AO~;-;){_iw>ZAbn2GLEbqGB$=zW0ZPW(QX}g0s|0062Kae8~C(Y_x09XU$Sgj&E5E<~jKrAp(pHF6EZcv%_00_{hVT zS9boe@p=U3+J<{wQ8UO7D>jyXy|x?TlC3kAiN3g7gNYEh(`;**?wlX)E%K_qsN{7@ zaCy8!ht%uQZiC68#;HwOVlRn1SYvCs9njMM22}LUE7YqJvwjJ(Xwban=!VLE;uDB0 z^xNL$fT&D<$^6nem0rGcCN+01Nz-v{wdeh2%?CTGBb!*>JRa|de{uS!dr>!D(X^vS z;lkjbpF)>j70VTB3}}ls-gRBw)Rlewl{uCWS_0t-^#{W+U?wA$_?i0{(^njeJlk zG2HQ|j$sZ&mkTZAlV@HJ&sRy@Pp_z`qBp?7@QKmoxpq`E{$1i{kXp9WY!Pnw4!S`S zE|66Yf>b(78cew5B=xCW>bK-K`wZrDBaPOm%eE}pY4Y%Ifdv2~C};9vVT*r*slk1; zxx|l>OoY3^!|Ec-i}X*P`0rDi>nI;EB%?}TpbkgsCd^IjoF&kn>=umX zUGTkVkM%X#72Q&xRmWE}{Kq8O({N?}iW#$P{_g-*UWMM>IH?u~sFrYBe;P>Ir-I}p z;=^s}wbNhlb~N4v43ZVNauuQpHxJ8tS4tlpPXC3&+fEIfrejrHL+0%`{BN}$Pe-FH z50St3%PrRqCLDo$I*N-macOCPWZ^{b{G{HWaiJxO-8ioX&sA%_-;>Y3&XgZcni;kI zOLYC%GCymZx>elEVr<*V@;RLQ_FP82zNKv^I^E>B@lrBMSjTikgQPcJF9e0q`Ig92 z;vIuxFd)j#zoKK>(W=$H%5je?c!VzCtT{QcT8%^~9~B&*OxYlh$h(S6H*9q-jPpqc z_^W%nsUer+wvB{qRt55jy~lP7uIG9=4EAA~c+Bt@?85oTg(!a5%N+PEhALhpUb}E} z{eV$*4ZMEzjy?q%J;0-mLeDtf>`)o~7ONc)$J%;baX^8)6YgS+NJ+FKEW*jVeLAEd zu?*Vj3$uxRH@k(>mkYp5av?hNK;*80upI)bu|>s)Tr&5_$fh;{4Qi*zP_}ITgntq= z-qs{S*4vZ}=|fjI`FQ0er_nmKj!}c|If zufe6Y4io<|ZLuCx&F&%Oq6?~d8x3c_Tsu+)bbvY!t41+kI@~UA$*&2KB$ec{CHcTB z@zHLAKY62Fxx@}4rt&Wf;{+|k;PC1-)#uWVt?nz^efhn7=&!K)#a&dfP;9is7k^5m z+<>fgyn&*w{v||?Y{G-?vdFwqN`Cy9StTq4P!xra44bYWObQ6w?vN`1Pv#$o34O2# z$>uwPcvhsi`T1B8^UJ#{uL|<{oBEqv@#F#8PxvKcH~~sb%HpwFPo-aqoL;pC_D=Lyh6?tcuvgb z2w8`n;&)r1cK-&rET|v`y`DY|AEOq_+9(#xZ(^$n00!pa=~)+94CTLaZI8#p_eS0q zB{y{mJ2(g*Xf!hJOJ=;a?Z3T_ORXjvk~eAb1m`bBJe%!jv+OBiV-T7JJYM1*g`%uE zp&IBXX&l`9ZDl$;Fbhb#SP30Cw^2CxA%)-U;JV?1nVd@<>yshOM&uX+VW_KGFJ&p7 zU=&=uiCqN{{E0>HRPFAxi+`Crr#h4pcl*S+k_|^YJStPmuy%%=bE-{A7#1 zU<4igd=vwI{pe5G_xQfrt#)|SKl9$D@lOCHfF^D4+Kr-AAvN;6F~k77Wgs{Vvb9u> z4i-8@ddznhX1v;##ZGI`8~PqtTyO&$)yiXE>HNB{z>@M8T!VRZM#;GRt(K>4$0kDI0=;xT&$b2w6O|EYAu|U(pUa;*12m&PiXoP zNnF{>=1wKYvpQY*qKy#snHBG+n#e}g*Ene51WgReD+alB82daeH(B6mfcqA`aCZ8p z+!sx}|J53!Lx&s}^4nYmA?7^Y6WjfCZXXu%1}n?(9Oa%|R3u88=_bpjHkohuDI!jfJ?X zDKq34skYbUu3tR1t#+H!qJ2(+#p>*TOfeyKMYFZO3-&Fiup6pZ{jpw3Y7;W==vhk} z!j?F;ib3e^@J{hFqaQ@ud3f<0kE&7;Mm3?>Z)s&n*LT9%S6`sPOgQ}!*VAxc5#8i~ z`Ju+oeNT01Y4=sFvK)jK2+6)c{)xA#EQdGL54DFcoMwF5^3ue{FeoQ7eO{#%rO6k2 zr?g|5^mMBI!2`_ft4LeX<=qCyNxuHPnUq(Hac|HNU%lgh8SLG~n&x#l?9fy&BQU4@ zhrd;e`P~szZ18go>FIY%dFDr{$lIGJ1H`fcZB@C~$+a$kpE`nb2=qR>xn8wybcoA^*m0t< zs+ZgUKA$aaI1`LWUB9WUIG%^lilIwoo zWYa1W_U68=oB|UM6Bo7NP|X7{z$OAQE21Ka{cO)dgW;fh0)NT*gV>4UZ?$D zD8cK3ly!8$Ym0`)xaQd8Q$im&IhLAw*keQ}6Hj+gKK@e@_^ut%>He{$P+R=i(m*yI z!W%>IuRqb6efMpaTe`XmX0<% zMQUW6sJaQ9()NBq+$qx@a0@cmWRnb^Icn@i--M8N@fez7gXHy8V}0@Xqmbpg!_HZF z^la5uSNuPRVN`p4>FL#>(P$67x$dmG3%-`z4IR0HMFt>#gv~i_*d% z`Fe6y83UCYp{q6@B5~*nysL8?bD=q6TLaNFNqVd>qkCJk&>mKT%`C7mrQD16EDZZ` z`O~f=lhWHV3;&*MP_mn>J^JDJgxT}~kilj!01eQT9IU3ORe^$m_bAdVbkLS-YoHm) zc?g~}k8IF@vvsVz$D)Ip#}Gz2` z7ErQq%qB%(l^BW)I51pa+%`Db&mG$Mj|m1R-m)m)ii!hj znv?tCig zp>XsYz9>LS)O%wM(V3u}tCqU#(f!%B&WfS}p=Oi==RJI%d`K{CK4>D8gvTXDs;L~_ zn)AVbU|fCff8UidFrer`xVI@#6b=#*4`{T)Y5dp z;6`OiLZ6PV95%(wuWm}ma{Tocj#t&PlcZxwp8k&sZutE8>Y>hwKbiM5gUdSj6g|B` zh_@4V!+G?s4>G2~6jJFsjZGSi=Msmet@PGFbKdDIp$JB2wyqqes^LBBex1y}*-&7#?$6aB5 zKKmr*&|_v%FUXSI>1VqScb{?vntfF~L)PW`Xb`#Lh__Tn zpg|r6IMmzV?Av*W-2F+EbY z@oQ%V(Aw{$>3^V`qgCSK7Ejtf)wl@+UHghTH~2}%Ig^lKNOl--F|LH!^#c2uS|`MH zPMD9+YFi++E_?V#cM<5lkK8h^_?CeI;foa1!rp-;Y=Tmq_8*hs;VFvNyNM%)=4}K% zmK%?KYZcu<=i2~QSCw(^l4)?3L)ZRp@9fa$q83o~ch%k! zV$pHst|j%K5~K;dbO%eqs}vjA;ou>IZfqSbE?(^+PC2q-o8Rx^Lggd*yo(oRKPU=l zEB5j_*sO(P-78}mz)=drClWuUY{STDiqb&+ezYl3>aC+w;nXZ~kv`j@aPA2=GYmBN zS4YTuaRh>=DH;V@+U+s`<+l{Q!jAYkoWTD;&~rNgy6d>$^+72xrU%XYE^VEp0cFGz z48MZPmS)mrGNL_v!mw3TbhK$iLa^Fj>$5<_UVZ8dDa!`W++B7q>C@6FqrcF$GWMck zfodpJ7|N_5kJ^MF4^87GfGKh?A#K)zA2$>%JxhL?@9(EszJqO)>Nv#?6!&OFHVRJ{W1lDU!k`I^$^1=LS9_-0Ek6 z; zcZNNv`rCBF+1#(Lzp`+3e{>&FI=XKr4Vz*a-#~$(!rXch%pw6B3x+ogiX4owAfu(= zM15Xq2vr|rmo$DwRqIn6m(`$P=9HCf1`#u$pJ)vXreXhR8o=L#(2=`Q>-Af(*@fxT zKu{T{(IC*cq5QS0XL4%Wrub~;Hr{`*ecx@FKgXJpV+QZOx~PTx zF%a$k7VxALP*(r(rOnN z?W8MsFq~I^n|F2!zyB`RC&|aHg70HSbQh0J0XxS>^+nWHA{zX;v!hV1%5!4~SZK2! z-G3HLXRCVesC_tWooU`i&BEeCZ(6SnIr~m4erWY76`b1-Cr(z}?4vZxJjPnbkVD0sP zTpy`r#}-sw5xZN4`V9@V1P-TPh-8qkoh|7|ctr_CyCrw>n{mI2UL;G3#=lRTfk#r| zzg8}@rOTQsz26nLTfgx!qPmk7tdX^c(M)hFc^xhm;A7{9JPKt#yVEt3ieklxo{Sz* zoN8&k(7>khZMJy^ey;u^XiAosZQxY3GBI!*y7NQ1T4(si$iS>^qt*u3Yw!95gwGz3 z_hNt5Bqgw9s*I5Xwm)%oVXMkuWqrn0GyFjR^u-ItEwW#AZt*Cc%1Y@_9MC_|}Y1WCQ86TBVZt${&V z&yT(y#cxkgoG&i3F1c~Ro-E`fhqMz|KFntSBZCrgL+aUWhur#igqit|sneBZ2HaxE zPE(70nbM{vuwB``Wb=Rv6!tU5?@#w;U{cS;7YF`aN@o@sKj*)MYcsd_h7t;T zPnT$#DSis-VK~gzr1+UDq45L_`(wbFq62YmO}IVQ0-6CRENze zD|F7(9s?%_zhqWT-j&a<+@j}JX}`C(RF5yTDC(Y1sx|bWyWE>hNe$U_%OK*97;zbX zP6WIL9o|~$gpv6-n0X^k_|z-@H^EJ@aoZ*W>>BMIbZ_%UI$SDC9OsLxqOl!u4K`KA zgHvB{8*HH5j|>TFO~AG_BxM{^Q3a45k;Q_?8xC1kT?nw#$?x(GW<|v_7!(KK%Q8dY zdZ)PA1F?R^$p+(YGlfuzTD_gT+L#q0m&Ly2ca47~KCOFhIgK}$d@6eojl%f+f5pc9=9y9Wd_m)*F9}9`2C_(+P zLws)6fNe{mGg6LTRZXSyX%!``Ru>_+;6CzK3p=t8&ggAX18+9Rr3wuAyBtk z&jACFyMnAus1Vm5^ZNlp#wC}IdgSD@d3&BL@B|^@hJ`Pn&9#<=K)KO>Ob_g2%F=UO z0}g;K``g`r-TV>H^IZG2liZ)~E%T7(ErVVxjLBt8FyLclIbj*{5~7Cs+4U(zP~Vvb zNB+Sk-}VNuS_3=>@_O-;u^Rx40n-iHn2)V`f-p43Xbg1_1CaS_Zuw_fN6(XM`4T#h z%xK$Km?IjHzAc&PSKlt9%h<`3+Md^XYdro75GxRv&+za0QCkRb3?dieMJW*_Gak%D6Dws-NPavaK*O!u;=XyK84+4Z^hUC~@GJ?yVRrcFXWD$d^z`*-wA;pth!_7W-M*@$>gDUmc7-Fln56@_Rmp zbR%oN+}#^Y)qRZ1`t=WF5!m022}BEUbYrQWftx*EFq>O?R{Y35>fTYNv_)$%ME?5Z zcxOn_Buh@el_S{rcKqm$l4L}NM|0v?9?h#>_G_APv$iY;fANhH0lFu}?W_FL2aO|y z!IblPl**=(0j~_)R$^4R-WlRrMwM72c!+wLoJn@)Tx5Fg?ilgx8sCw+FLQ4K-ADRT z6;hm60wuh*9QAwl$7@RIYKwI6*g-wD7K`GPcW$R*jq%jszwk>dX2<6H@2e)z{Sj^; zS7p7r;Z4*hePp`jBl~X%QT@16b`KP`iR^dU%02cI+$_w<>`5s+KV9JwL2RV*s$z{| z6JO7vLwqU+;UI1eEarlQ%$WSmm+&E{rW~vKZ%Sb4N$DPseyQbRRegJ<6hs`vDF0cu zn6Oc+aU@S1o0D#Gyli0#*4!-uN3jujm)p)k z%-f(_3nu#-PSNnE&2L=zeaUb6$AI;)xJA=zDy=)lc+}7}!bkL4=n>!j#I0=xoNF{4 zmyO-yo*Sw49pB%TD&%?p(E69p`+O#^<~>HLPGO1PT86zCrLoSoeN<5U#w%KLfLAB5 zW|nhAWsRjnLrxV9Chm!}#H#30OYpsqzQf%35Er&0Xa=KML zV+=?YAWRdF(l})@hloHa_}HXdFV|p!rlKC-sm4=X&*Q#mD=g*2I*yssLz>y!``6fZ z8TDsF9i_BHy4%7-S8nBu_e&m>lNz;Dakz;I(kS5YkL<}35#SsLAQd>e%05UX(eLh+ zg0oz0ZC`YllXBDz-_K#-0nTI3oD502`+8cTjdgIVuhqZLp0c`TB~;U4$dfaIl+GqF z>aG>$8b~%Gi1mynn`mq|->&YLTOv>A!+bv?JFuTz#8$~;n~yyX0_vK=&j!HwnIRDN z4NqpK9BC@>8mlyStv{(AJ7$z!)HPa!S^!ix$0I`~L;kthBj=6_7o=YE^~yRU?uPk?z%Xg`@emx2sml#09@8$k8Iw{;~AdmIba| z%5LJZX&~B35KM|viN5J%@UGg-g%=s;QbZej5;D)vX%%`r{LzV!@H^nX8MAm`R&@Y) zk(wWP%YW%u$uyQC5*4Nx>INj;yD-0><6k#!r;KkNFp|y)KALifTUNN~NNY^I-MB<> zTg3HUrVIibD;k)03vTp6z0StVcRii-G-N*V_Favb@|QeiJ2 zD#o4U7?L;i($wLO%EGpyKop$Bp9G5{=dU5(wFK3kClp*eul35G+eP%5ghh3q+X>vx zZ%Kf|rUVBN6SXs>>oUZAg~lQ8lCLVJobWEQ2^|lSTY`Fz6oh`b=?8DxM=TrYdo{ui zkGvJ3Pn91|b-SG$`A`-Y0$_=_)H;AM$oJ1{ab`4oz{D8n+fov0Ns7HmqU#&xx z5;|gPwHnG$fKz12uBa=Reex}mplzakN+ z&BQS|iDYi__> zF6Wc=U}kEgsIiGb8W}K7?L~TGZ8k1(quam+172Ae|{l*F-RVYUdINOO?-Xp-2SxArO#)Ribs-{ z60_#2aASMqOk%v+s|n~Y=r?;uNOek-^OR1aa`nu{8Gc`k$sN6Mf{xadp8m0Touw;m ztutZGV93y|j&caM;->r#F>IY?211{3eSR+Xr&O`Wv#z0xr^Sp?>Im#bO^%On0lV%8n5(AQ6js_jI4`GX&1&PLkVpFFs z4C&rWdK*9Rt@U)^M{7$S^Usk2HQk!}@*KS{auTi3H>NQ|2B`ww-Q`B4G<4a?m2=nM*Ww2i%x#?;}7}0jyqWa`rte^K_ zsoP*)%c!x`pZe}=(g}fM|J*mvy-pME5nUfwhI`aIo2$H^7wRPr(@yB6-sAvTI5)tU zO8nIGt;0T8q&nw9)n&z4cdWH;yL@Fj*Z%4|4Z0v*rL|W=q%|jsRb`S zj8M$(FYIDegs!((|8OZ*2ZGXABrsUKtOpHx2F#AF#*S$Trw>d=ysebul?RZ|M}oEP z($nXL^&~BQfeqruc}dZY0XIcVX6i1;zqZA8P*`Vb+P5;rjC4HNQ{b#C_DmEO02!wp zs5y-_@i6{AhWde`BG-9X?zo(yP1&^VqNnO9!pN!QqSuZ>VjY{%q2mabbhpgZ0-UQd z8DqK>AXSvN=mbV1OQeJCx4ia0q|7d*{qR4qu@TiDnufd``W~i%nASO)K)}XcaHu&- z>}GPnpi(lO64H2`S5?KQGhuWRc~fQbnTr%Dvn&S>-y6svwM-Jx&~aY%CI(C@fC31)jY8a=VP+DL&y!DXFyiybpW6Y3BA>^uSL zefoYzN1%RtIiTA3yjeyy!tMQFx0YcIyHc)mZR2yP(d*MpBGCG^9rPWMwLR9#L@Utd zn7->zz)PqKx)tuwC*jjX2ZAj_&udoF(ewXYaT4rDfrfF5lAYHIzFc^d_WkHJ+r(2T zWqIZ3P3P~w29aWHn;PR<8e#A%$70(?D`G?78k}uc^ElLci^l_+C{c1ojsG zSU$aHaDe@lySa19C1yURWyGH3f}+=uW)`3yJZNr)F%EM;E>X+ZVR6&-PjtK zg>49J;eW%Knl1wQmFI#Ta{U8ct!BYdvdT8Pt!;sARn_O$r@Qmt_7k0cYk1d$XSq*D zb@in>zqa@(9nYaD;s-M?8yv6p3*kx9U;m~McSlyXd#l%Hsj3PQLQg!k1*6^aGob&X zxpFt6l zFmF2Cpa?$G@m@v8(`=yQriB=4;{67dll;(i*_qLO`&537rypx)ApVEfuz!px`W%RtELG;v} zviCCqFC{OB#kF=bT@Mjm@m!OAC=MyHaiQ&18}3e$Q(b)vG7f@5rq%x6>NEec1B1uix{}T=yWN+?tlFuy1o>DR@A5!fZQ_Vv|eu4J=}W!u@Pmc5h_1 z2R1eYIavADPM4&db-dn}kTXq6d^vW-xt4#qAY~WOWt8x|bp`dTGI*l&g1mwp98hZ+ zMo%c-wJ8sy>_wBR_y|I(qPZQy50BjHGlYZcR(k&Wcspz6?_5eX zIhaC@n*)jv6NT3cwmZbaZ)lW%mVVIb>D8?g?SP#;4IzH8K)_~zZ2AKcF-yEYUA^S4 zfk&!&$QX_DD4SYT2pmPY2|YW1*{=LP)8T>rb->H0>yK+>*x^Q}lsV9W3{GI?AzW+# z7ZyNykoK_9wi@T)noswQ10G$Y7&PH1PTR+=`%wM&cosWyaaPgLK_~?HdgzPmvJZLs zLp=2*A3S_UPxAdJsJ*E`rBG}}9yg@rpR2%;sFeUYbxlAfZG+-V9b<6*s)QnJTFv zGFlgs6J1ml>+0p5@C&kI!`aBIm+~jm)9PF0hw(4+1}F~9z_tp(3%3X0sqn>PBs44; zbwRVc8oIiAKnE-y=IV}^i!_OCmYB%gA7mvpbSY%|W%^yN3`FQ?@Oahfdil&K1(E!v zZf0~S5Tc%Cz>^mzKDUU@G;b&zrL$4X_y6f$PiOU`&0&+Dt1fO7ZM{Bsbwy(BWTN$QmYpqeP{BpeM#pZt6Fav>iCPW?mtnZm^K+ z#rt2IlHsEA-E0(W>N00l)?(;nU;eCU3+~a}t9+4orHstX%oqdnAT%oiz$1W?z=f)? zqdXxW1lbcE>#!tO^5g9!5+?Lc*`Y|oZw4~F7!D5V+)%CaVN@&cUg+*n!QTZnWmK-i zRpDD!V&LW`X*yc%_TlMu(j<95Fd^Qli1=^1?;YM5Ka4>G=F-K5i$&I9SqIE_D77uw z7i$|G&d-Bg^GGX{^4-fUAe=wJrQg_Wbl;qGyh3MLW7!8_sW400J-cyCGw)XYdWz{b zERH7Z+zs1@3JVg%s5Y$Ku79Tnis*TBP6=ARyLwtD?P~UK{~gir(#>6GJvMCnFSq2^ zfppe$7q(G=e&KYtYryQ3E%5~U>@jh?*{?9(%*%U=B$kc)p>yLwJbS9+yZ$kcNDS;o z-v!e``To2VlZr-!uT5E9S=_*7=7+7%QM8{3(C^ZdH4+W^|n z_6SxFA5vvKNblY_fP<3xW(&HzC@Dx(uqni;=mg$+Bj1-Y683oa;;e<&mmr_q_MRS) z9ZdQ14Bl$}<(Nl3MqJKEIdOI1@KvqpFxF-NnLY~EwZk$I+s6Eao)#+WlBao*{xSG7 z=oxcg{+c3J-KTmU+*o?qdux#0Z%uE4L@U1MugLdJApP`a*f zYJl2ApKA^db=p2ULMB-rwdMVRUOB*1HsXnXkKR!Wya7c_1^NPiit`YUvZ_AaBD9Vb>r)stmj`MOFR zzA?Oljd%C6M)^HN?1Pq-2nZPIl`^_5}8z7+>P_-TAsu20^x!QuonxC93=Cm-_^(A5VI zExPEgSwRMA$Mi+3Nyu?Etd+sCSFu>0gy0op*Op@A-{15f7&|gfQ+MLjIKm^TYhb~l zG3Y9a%76!Gu8q!0Rd$(@5~SliC6NPLrSo?y4*<6o;6fDhy|Al;7q2`1mgri=8hw$R z!JmZOW$42=cc#2)=L;~sA!gHt$K^S};X+K&e4SqvmI+CTz0{Ivd1G5V(!F!TgDKosI#-KJl1Q zhd>K>13_-H?b#X7n_632TB;(M6~5-{dYMbsJ$*jwO3DFJPDy8Od`#A2+9SuL8Oda2 zV}|w___EfVs=B}pB093$NmQv`|Mar}RMz`c zo2tfYd^W&t&m5(e@ft*A4Zz)UeYYyw7Cw$SGYg^If{xtqJ^cQFvp33>*#umNAfbzl-$;);PEdTo-sX0P7<)sXb3s;W;$ zgUBo?JOk!(*eko6CQeL&2<7c6i5S@Si>6OF1KyyQMMEG3>FI{pD;Ef`X#`;{T<2)}rP5N*gutez}I>?w+e<4|O zdi_)xB-!lx*_nv-ST(i-GEy}_R{zNw#I&Cf52#1mVT@#?~3&+*SORCd;8P?DPFymHR%|%HK10 zhu0cwahxEY`%K~w#&FPU;;r2~sBKqp2z-k#8Fkg%Wqb5$&`zM|@w9qSEgx`tVTaF@ z-MBNj(ZGE5pYP@UXg3M_vng2azWjuX&HLRdrkydrdQf~nQpQEmc8v2%!SV`(v_+1G zCA;!@Lnk}L9kpOA{UdxPUrq3EU~XXCtCex~R|7ydTRf=UR*fF!e-X*iWHAnAeYts& zPqF$5vm!<}fN?kN;aKWMh?ox^>SasM@anTvbxBFR59ag=(kQjI{b}88*_nn4Dc#KJ zD9Q(JA_Ff??B2%l!gImjO)wjOLrPQ1jV^RSg z6+z_j$fw1n{oZelwfPvE+OCpTg|TzunusaO5-P)PZJFaoFfSeB`l5wAtAf58R#qZL zU{&CYxbAmv{>+LfDA@FaSt?mm&A^C2K_Y3lGEbOUQ*1kQiOvAF+YLu2oSy3i4ki&2 z>%o#GG@;t4Hl-u@x|N`OsMB&f(OMII7e8%$zAYHBS(r2HVU#*+CN4SlO;;{Zh&JuK z9AGArn(Cyh)7|*!KPDD$ybmgLFg?@6=o+HzLB4vY~TKnd_h5SoQHwT zkoB%ySJ`YVm6+Hb!RT=GKE(7O!Vh){y{?-7){xjUPw83sim^7xl%Hgp3g2ASrR=FG z?|Iy-;P$UGSCXG}qvx|`7Xwb5ZM+)*t3n}^?xL{xFIGSVh665p5kLu~e0Vwi2cAYC z+te?~+B|;7Q5Ie`*1QqsCUtS>h34n)T9f>jo*Hv9%RExYF9x=-No><=3TkJMa0`VFJr3(oWy>GsW9Z4o_297fn%ui zwkjpxR)%QkgWv(#9j&QKH|2T=e3hp;Z*9vzMH{z$F20J$*}i-K^UQ7I5}~PH?<>lP zqI@ydfn)ebm9ojfp_7z>r2&{s)oO)8vzo2@PFl89S*;FsKR~mV4=Cg0(Ro!p@U`8$K_B{*Jy=iniki#xt?_M)O3Lx1{SEkbeY-q zn2?5V6$9*YEK^4*mccIvwSw5FXt_BbteF`Z|No9M^G)O@sKWdH<#k}7^n-!P7k{LpTNp- zJWacEw(^87C*jS%>&Tx!$rD#!B6xo{uBH9u5P$fU@??TlSiMklt95gnvg1A& zvttA@cpN<`bdq3zF^K*pRNs7@GvmRmvPIbRwuWOmXd)RrdzdjDwWOty)YIzML^lMu zNaOp4Nq~U!6tw07Dpc;FvUrk3#(iPWwSc)V#;+_yV?~|1ZV}g7TD`Bedi%>{RjLn3 zna)a-5`NzrYXdKa_g{N5?GgHP#OdCD0pGSlhou}6P1H$l$eA?@ip0{k>Y$)s1pWoE zG|2x&eI?OEWZfxH;g`|AhO-EBPh-b;(|GE|&emOZ*6MDQ{3ZM1K|N=;ie z@Ckk#WZtF4ER9?U(OZ8ss`^2Zf}uT+o4lVc@Z_?AjFQs397A1hUm-VryMfWa;_iiJBG=2G*w?4 z#pbZi6$Uzwm?vYN|EPO+udNA|{5{dRSA&7Si+?jBxjofDpSl)apW%Xp0Ryu9$D92^ zRS|X=Cbv6Hj3_VE3BR~VK2;T#Lszak?f(ALV$Rz?!FPMdqNpMCX}w!mkxwQd?Ep|z z+A4le7-D`1Ig(Y0%+&7%Y*^iM%Cus_%kIK8LW^!}2c<7;nVL0=BFzNvx`7VcsZF@4 z6-(v|+TCl_uhf%nFsw7g5|xg(CC_p2c*>cFEZY67xL_=f+{VpsuU(L?39t)7kDw_V zPzPFr@ua*1fnne3I{s^+D>-U+^^i}Z=?B&Y+jBZv{XwPfk@z{$gRub%OV_o1)pwB3PJ?m%na z)zeo^2GaE$p89but|fkWJaT13fK??~IVSJ-hXlP+mnF}?Sq0oBr_dsxm@8F=gj>^s ziMo37wl5_@OCGh_sEgcxyOYXUv~Yh$;5yf+aXHVnU6n)}HBfamt(6UegV+7ttt_)Y zwa;H;5Ww4mQRPzmV6RtQ?u(~g7Y0pWs*QQ`1DNjMYsuZOFI;@Wp}W0iomALf6$B-$ zu>sRd-iCGM>cC3PP`x8`bDVvlZvp(ZH`1O`Gvi7sP~CY6sJ&c_kW@L74gZ(bxkK`ZSK zrJ@M2KPs0dxqe#Y=IaV#t2_hYxm$kAS6i+Vk?l+*kU8)f2&+Kd+Y~Hf=LcvjHaL~X z*Ftw+zctDLe=Z2VMvSvPduuQ`WyU9uf}H(o>-9`|*5B)}tiW;ex1uWxSYY>;w#;T9 z*Pti28d-Xt(hQL;ZuOmTvScSIS43dS^}%b2Sw%gEJ8v?q*+-`Px2GK{Q=R;sfc+tG z0?VzDMxO#+SRKldJ`I3)j|xs%+%zGYy*pvawUP%2%(AZtnZ?Q6{d2SZ-P6qh%UtnL zglDA_xVB`P_(~I`K8OKc^!@!mf6T7kTVH)AVfa4#(t}6551&Y#^ZT{g>-(p+#Erj^ zm=PJ^6xrb^#TcH#TjT->Mumz!BUd58dP2B8=sc^jSO$}@6aDyUO4Pv3JkJ}h4=XO^ z^onh}-tx7IZ^)MRLrZvm8aKJ=!VURtDu@bHlwiX@9xbbP;Q_aapaSZ%R}y?t_T6W# z`41md@&kXquRDJHT=imVbH^q)?-^uiZxV>V%7nSk6ZUaip_H#pVNS+nP?i&n=JxZC z=oy-#3mMQkfT~fcABm^X78ia=d?=jj6S@gvzrX4K@}t9UAV0_DN&Gz(B_*n5hJ6yL z6})Fp`EU82pL43V;|O>ZxQ}Tnw8N$EQM|OI`+LQ>PhNt^Xw>&4Nb6d>n;zmqiZAv- z+stk?aX)5P#QXl^A{$;A9upDg{njim+ZuCAtIvf;?y4do<&9UfLRSt~T@TQ$1@)0X zV;yGXuR^0pkk1&@Dz;o{$)QcD)VozAPoXtGdw%ZCT5EbK#G^4dx!S6GJxoO@0^#D1 zkxgD}@y*LNe4D@G>m_e8gTFuR4>6xIcil#@4|aFCBCKhpOG5GwnEHDu#dUkeU5^Yn z-vzoinK^BHGiYPlMyWPR-<7VvYwLNAf4{hT7dhk^ACi2pXSi)y$~LK-9~an{HvnP` zx>UEgOj7I`CT&yHd9D_^?$!X@1Nz1fi+DogHRLy>5Dn8;(x^1Sbgu|WRV(ICKfiJZOD1LPX(C*qzCk_;Yxoz(Zx=ZxTMc2Ybsa(dEjQpey6-oW<)Ae0h^ z^8Dxz)q%d!>HRmNEZ3 z16DnLFYJ~R0V--A0@$wYS;A=2Q?W#EU9DwecW{pSKXp94dBH%w?ztEV@-@Dnlyc$E z-t({mkV-qCj(p%&(v4uj=0!)c=+A2;D*WzeT3k%MkI6Z>5(Ci#_e_*k}pNjY2%m|A5@^|fbA(KlDo^B;fCIm~#GO)3q(B*7YD`EH+c zZ}|03A*IhXTjk4O@pkwueH%!6e&${cy{5=^3>Ni7Y~-XLQ4eICwbb)}Z%_M}oO#e8 z9yUGoqUD+DmFJ9S_Gl)M`Hoqk9qIT>7Sv08WZ=9!5k zz7;QGz=V|h8P^+{!Hpm7jsCf7)h83au0MhbFyPN{tPNbljnJ8umOh)C>-h0qosCVt zyKQ(s;1cT7lcT%o{`l>oFh!-etD`iMdJ4@I`Q(o^UioM{{xa49(skdfK=t!_57ryx^>)ANk=$UUT0%?g7~qSFlyU zYN^RQX@S1OD0yn$F7qlHD&31mMdr|%Yuz z(5TC-QIhzXi%m2CcK(UD*j}~VAQz{RKR9a$0(*l!{&KXAQa+rUxB73Hw;-dTb>Gp8 zjwjdA?+^*sXotN-AsA0cEyHq5-cl?LWb*rC?9@d|!TSfZn#yNI^Wce?ubS|$(aCOu zC(9L~mr1KXmyxbnYg?)(rCnOYk(0aOY{@&N*-4hkHwH@OKJ;;Y{puIVeYT$&x&6~- zQoD@A3*@qtq_3Kr`#8=AgtPD^!@DHZl0MCafbLoN=oSk7>=L5D0JS$xcog5%n|xZ~ z>}+tzBw;*$h4mU~CE~A`2HqYkHCN6mbhI+r3~3LrXlD++axnF+5Ns$6-ThHJZB#tM z++iP3GZ^f%zU1T7JFE{Xv4D^HDy@Gx?K~|Cq}XKzp}$qush`yw8Q$A!UwHm#%yM&@&0rw|uzah`waiQm6kRpx zMWN{A+g41W8=SwIO5c@u@ue)|(8)1MFGt@l*>}!4`yDRaSM&Hao&K^LoB~@vPQi;p z_Occd=F1wH>HvU7&x1x`yo?&uua8dzd<^k_IYgP>ig6KcRo62HL5ah%rQ)8$|GW#w z1cPbR687WtZ}PVYFaMhEiWhPXmqSb7)V%(b@;b{C!JYAt4OFn-{|i=!K|H6f_5?p8x1Q>N&IWzHeS5IzmskbTSgO8Tawq_8I=}p} zJ*^|bX6)epC8QH}n^&9Q_SJc5+vw2hcQWDlcW15kZOG$+IzN z^0g0iD*dq1*Vm+dsv-zr3XQKQ#zLkK*f{+=yjI5^h-an8kY^4atC$Im;TIkAnnF7!y3L#Sakd3=sc&qe9dAXS$HfZO`5Rq`yk87{=4}FR@2i&M$Mue?Z=@t&i694$4VyTv&4S-qB2>dhW%#y~{(D@XIwbT5O0xBQEomLP4m z(2yk4e1MXW6at59!!;?l`>$3=n`OA|*nwX1 zpPuZVe3-?;DHTG;LlzS*Nf;5VTfMaos56zGMHJscpvo^dfjq53YoTB%cz=zNWiUGYHVgSKwmXB{P!CB|GDbiqU^L&IE7^MGfcc zAr<2NJSKJSDx`cKR7011{ooe5n(&|_;`50Xw%p3J$kPwDrOAHTj~(S5`5->b5#y6@ z%Iz;8K~Rq)d-v&FgMFb6 z>Vb0zzLSjMyXh|7T$1~IG;AG-ih5&bmt2i9GlM&ot`f%}CN8>-+aC{o>U2m6rKhw} z=r@m#x?dadi4M-Tp&a*p3qx!FG!25&M@rBGGfHwAh$QwN`_}q4Om(f) zlV`xA2R!6`HYwoQB~HTmLrz4Lbsr^5g1;B!nf9|;pHuMbdX}5)`wWSDxdy3*aX%6~)U=Glu1^?UO0p6`H7)v>}&Vq|C`6E8AyK#{L7DJ6kJhXUIOTL&H@W0p&wX z32NyeEVREFLoidV`Q27H758M>yv+APF>luMs-+2`Ks+q_;Lob#W2f+@KgRE(hQTP# zE=8`W4*e6@%MiLmqpQ+S^9BV(1oEYi&&i%@SJQ;CB?aX(Z(=U?+a7O`ywqaAH*{hb zF;6Hd!Z=M9<;iP5^2?-UIOo{8dYgO9LbRJ2LE^iiD%@!z8ZF~66yy9cRsdA#Lt`@9 za@R8Mgkt{jWB*;e%X9D>74^Je9Hg*YgTW@@7Q=X6G1I4bF-*}&Jx}jN0!{iaN4H|! zF^9(83tpFde15qrx!^ur{c_!dbtnDe2KOJmSe=JY2YI4Au(G83$N)ChR6{CUU3{Wc ze)%~)5OCsC^lHZSp}1tYh>j$J)^(2-%iSf=1&!1rJydQ!GP^8+_590`v&A_CIL)ih zfsCd5a-e4US_itSl!Kr7Az?~ZmeHW{aS&<@FPc|!lDkL$3h<0gqclS@#+N_65Rqzb zsOMuV2R}Vkd2TeLviBKIVQ2Y=&IPUM$!D5~jB)c)zgHkrR%pQF5e3kzM#YpHDCbkX zEZeiJ?Ci2@V6yOUdJ|+G1h%9m6wdRP<0VVqq6yPlX!de#rerPut{Bnjb+;%%J&IGu ze(+IX?eeZkyKrXM%XYm#k;f~Hl#|O!PoY-4vneqH-(hunp*-+hkT0bXNoE6uILT$M0{$VSrKYBy2rR(p|DbGu4Y z61F7%NCdwGj)U)kX4YeO+1eY9McprJ!FV-u+@Ov07BqeyMj6nhtmDt0HtVACkGF8ADcT`BFR8|X zl5sq>&ITfW;^_$zO)=kAiaD=G?9@55JQIE@UFl<&<-FQX38#?ODB;CuD)hlqw=>xv zW%e=DO5Q{FYB6uMSx5EhaQW2TPJ%F2c-!%9lio4bho~!^?@Rvphx;$S-|_osE54dbFP}$fn*{dB^r#V$WxD_3FWD}RG-Q)!u(CX@P zIa{V<=0hqJuGPm8tP=G`pUc+SRa2IJ=G*x)URUhrO-xivL85(}eUXyR?Nd=2ebtVe z_QBr1M3djE=&>5RpP0eQ@13K|G5rrF^O{069)0NO34eU;G0UeQP^cga7OESV0wleD zFI*_ptI=~X?73T3-DK&-2txZGjg3d>mxBk1*2;H>MO+Z+hltqhK6KiLs9#B?R$^BVW&4Q&9)L%WNiP%rzzZyvi-Jx zyh*oe=A*jcZD0G=>A|&EHc82I>X^-OyK0E*+=zEYNbn^2A#2F zdQLX}tyZ?aG$*H6twaCtXF;_5Zoi^@sRGuBrtyUcIdGgCT^Q2t2Ph!y7VHi7PtiJT z1A}8r@65Q~`4_Xfsi=}u8+*0&SmCjo%_uB-Z`M$ybM>kE3DmH2dWKn!+j}KiL|tYa z%!)@+59Y045fvt(R^#Kt23OD>JEpVGDCEj?8Hr+}-$qg=9CKA`TWlwho{`oNVa^={ z8BYxzgFhFIT{z#)`k-@%h`jnDw{?V?+T!p1Nxp|@dcy(u`gH(uHpjEOeS694s`+k8 zO5L}z?`Mpe&3a*AQ2Fqq?Xmd}!lwjZWtB+YG?7v@AB7C&o9xfGxZEm$NL7jBapCGc zg!uHWrra>T9mrw}smyNvTu$rRs?4G`{-$+p|Lyz(JIDtw;?^cx8_NnhDgs+}&YG)i zHlm|;b91Qw_dLDJIjnn_AH3tfn8e$x?UD)lDKuy|_fIEYwZ#_&yEfs z>4Ubh;GZA*F|R>xWvk#wgngY|E81hxRC(t1?o3}N-Pu~WMDpR7pTSB=%adRDHIen- zEZK)@u>4zV>sGdfOCF(1g7vUp-%q|r9zSP8+#TqbgehG z#`$(UkVJ|%cUV%iP%q>#vx`Mx1Q`XkC#iUo;m`{ zMGhzZq=i$TvEE}vL#jG)JUeT9*J}EhVza{tpKTR8l4^eBSHrIYaxOnlik~}ie5_q~ z{7&C!iil%Ia#?0rzYl5)=n2JXyvmEZa&ZM=u9%IHmCyY1YrdJ4$UghROv)mDw7UDp zxC!>3wJR;S^`0;uV)KTl!@TCUDGRB{e(*=Xe$VtWN+O`05TpfPLF?SHVdd$aABluR z)T4QBo>uOT`1R(({lqfS2Dge4(V9SG)m~GSs>~QIJA2i$a@_9K`^)4Gg`C3^D@odJ^m{E>(?z^gLwzN*IXOU^i^MUoM|5JXSgL;5RxskDyR zoC)?}>A^!+iF*fSl-X&M2m)+V^fRD{fz7~|4oO1g5$>ZpZcEFxTY@~v84xQedv815 zsgn;3AOT%#MXC2{?|@}{H0aHzI|D+qL_u)eTC3Pbi2rE=-g1)Fp<1gsFe{5h>p8NT za31Z7i3i9=YHCJ3@u|qV4sSwXNuCCN*6*f?91n^hKZ4)#Cn)^E=1y4Egu&R&YpArq3zpcWlrLrt+C4V%;&rGNwF8C;Mu z_dx$JJg!z{-4VpcU&v19k0n%cOl+46_gj4`#$L1!l3I#l@jh(Y4` zR%Xhl6+8~GPve-Kn+iVdd~V!J==e4>^4Y#wcnr#duc_$#PW}DE>l)X4RD9v6Lv&_Q zdAaE>;&rCWtUWF}HxtKHx|A7=>s*)xX8PdIeLryma1U=>ya;zm_pExiv?5CT{^N6| z&MTonaG>2)$y-X3EkkBqMw3^@Omrj0&@gM$%;d`%j>hzT{7QuW5|Wn|119I>{kMH= zbHKTeo7$MuP^sXVD!)V!JMOPOUgEeIcX}eLrJ$i5SLNd?XQ66tE9y(xJ}P;+jpK-# zmQNwXqbfYfyaPmJFzs?5NjU|AzHsxD{Zzi@Vwa9JB>#k$zj~C|k*6G*m)8rS> zPC-AHBZL^|LTKE)uHIVnjkE7f6eD!y4!Pd>)=A5?_6#m6?24%fCmlK}rr} z&yGz4G9DN!P-Ff=poC;85Vxui2-A-k%k8o@dn4W9OO>#P<``TkazLi$o3YCU86-(&~y?2YijFT-7- z!cX}AvGmV7_5YfCbSRiu_~CO6yOFgILl}pb2=Q?>1Qu~O38mW26r-ON14(q~8RTFc*L@(E{ zplw!Y@g-u32z!*ymq1Y@m7E-^q`5uBwTN84&8oC(wP+mR`8^}Vx?Xu*sy=eeXm<6- zi$`BRT2TvNvv(0McA-A_b_Q_x3bWZ7nYWv++-<_J;qNHrJGpxdt0@Wzw#AjYXMQp5I8D-oMp?wgyXqwo zgJP?k9=n2Fxrnii-W^w!ojb25pG#PMl(#<|?5Vo6`m1%)H`Ds_^6th0zI3|KMhbDN zXu1sp0nEMvWg2FFE63}JFZ!>wwW$3=b7LAtR$FDcX;#U?9lb)QSItM9wh!lap0uWl z8|!?P*}6L%w76Vryfnn4C^f4drh?fqR&m5w7-8XJLrnL*;4aZis#9b=MCBZ$HEZ-p zrp|PcqvN%P171KmGiC10Seu-Yz1+isLPTkpUcnJC2(Z`sXrDi72a@#sj0NVqE)+dq zGWwh7C7RFE|3bu^*yEu(`1OOe7oQ&7Jh+u-v@zINAGHXO-NFoh;U}-MREHD{${9HZ&l#M^Vd)ldo!*hUc+Y} zxTP!@KJVo^C)?Szv>H>QR^y^FNor@wmv2ZLWcQT2hda(+VrfU5!m*;+$D)SyP<&&nm{J@R@lZdSHa4Yma52vP6l4lj$){i^O*^J`R* z65JAPr1sU~JgQJDyiZL(;OdR;IGr1dA;g<)c6qs;^-c0{f zZ}oT;*3G`*Nx`+X9zplwVSNR8w9Zldxkt&9e;B_w*KcU;& z58S~G^VJ(AH${{=#K&za-EDc)Poo^ouWtF7WtWY$2ARw_QrnShGLNW%^5M9~T_gpM zTZl@7cPQ#{vwPwH04!7P3nAl6_PyGhQA)I7;=b8PT&10^vOqDtGgQ9GNPa2fQqU)f zl$Z)DBRwyMun4C>LL6_C*x~!mzC-z*rcYyD|9=ag6=k&N^gk9U)N~Uk&aYxygYlGI zZ2X_c3^489@^bLb2pQZNhNx)_OWeG&0HHS7r8{=kT*&=mDga%K9WBatef(@tB-k^b zt|R!W2Gpw?XyQmObCveD_VfKe0bBA=6zH>m+l@WuMkMjsG-q71Hkm|{*grNpIt@Z@ zSl1C3PVuF^zo5|*DOcGK@eEhQ_6<(9W`;LW_6g{b-L02Q2bzmyEN6Vg-4iu(VC>_9 z0kHvq=U}w9pT*ts69qAE%V@8i8UfQ3=|?AoRtmyUXp4OuWuF}xq3^ASBoJ?lZ3uaF>mQ1|)!5oEuxu>4$)-WGRyPRI4zO{}F4rs8do@S3H=?TqdAwzLF%QngFa` zd?eq(1+9%gOrsBhv1y0>H|0KXJqTRfzcbVd?|!0=_Zo*r zulGZ9$h}x@&$FgJYNJ&(@}qO(Ta&UjR_0DseXb>wBV(*Hga>=QZ^~(&T~q15HfCQ+ zUzRgX@F{c1P|vVSHg0SA7XUo0OQKDWW^G+>T15rhJAvUNd%6RB(T{>bvJrp4Q?W}x z6!`Ul)S1lgDb3q7ONg8q6SO-@|u#mus7O|V;QJ98G+rOSKUyWIIHu!-k%6 zu5nX+G-UaTQ$N!6u_LSGY2NI8j~_kaXT&bW{yR6_VA=>7_mMfHWM*Qhwu6}uVup!C zn$pU(jr>foDOKQoUCBO?i-2{GKZLWxRf;Uyr$)YjS{8b+tIBsH?}+}zE_-^jLwzm^{qVjzSG^+nKH8-?LE`+xXY%=j*+{{0zjreimJ5L zvF~&#VUR=7V$oxO0OOW8F2aeZYejz% zAvok27$~P!KciJyjSfO{an+}vntZy?n2rH+Yh?>2)nf~eNQcGjE0>o|<=bC2!oIKQ z!$xTGd^_%B9Mzx9-N7A8w`I^iQ&K9ol%2S0)L3J7zsCnqFOeLkbtXjwjzqt({_COCE&1bBs@j z&s@?!wXo%P?)9MXl3$4EtLCi%i>c4b`%Rhn%=GQxI$_BSg44JhKjABx6-kLz&4m0AFkUE9rl{4tYvb_o`o`5!_) zT-$K)-99?Xi*rjz(fDGrl|8?JZl|+#;fijYZ$Da@UrCHWH`HVBPQO^3G|-~O>sI|f z!l{`J0=K+dT|*)_DMax}V@o0(Iz`ZodvQj%bzLI7#JWTct6V;*IYChN&L5&25o*hA z&q;6*1s^%r`AnO+L~6kw9u2b3Xor8qkuLqWSu8MC-FRMR?3CyXFm7wlk~=+d6_z+D zmXfNr5AbrhsK~0N(AEh_E9lT5&P+-V3*K8#DsFY1Rf>Luc9K^IlEkATU7V13=h(Tk z`;k#@B-c3Ad*&v%aHlBA%u{0L1~-(=-5dXMJf}~m zr8qaAnPufY#_csA6}`7#K_z8t9e^ckbtCFegzDZoXbrvv{aB*mYkS7E??NZ#C$rwW z^*!SDVur$TjVqKdr0wCT{4BjH0n@o*(F+B$fK+oh-y)^Wb5UQAwiYgW8t-k~?f73~ zKJ!~kL#p=pnbs%LE|qVvR{q6BviKiW66V=_5<>$u;gIqIjjvg5mgbPaU=t@~Ia6r| zE=ZA<(+B1*S1l?H1cxfj%FM+0vt8A)1=_xL`|v-ruh?8@@!N{{)%*p2|EQI!($o5? zboXwR>R?psHnt>h2YgD^zJ=xjY|71H7iOG)bvJcu8=RsNcxnYcR7mc6iU;dE?lpXY zqb(L_u4w=_Z94GRp>k_hG4G{%N3TCqn^Ezr7EB)3`)Jzy;#qKApGP`glXvg!nQui8 z{`||)t2B=0q2uBXb3{tLv&8{BzXe-#SC2b+UKGmTIY+1N>Xq#EbwqJuuF!V7&T>gN zSz|bg?~hWDV_sz+^?c9`43@=Plk#A)u}!1iL91oh@LQR=u5*T=$3wWdC6P<6FK~BXk#m4H7`4jP@Az}nMV!BGZ2^JuLu3*piq09uZAK@@gNl- zYmu9luJA&)7T9wD_-!?P7yZQoy$elb(GG$j0rV_Ww{0}RC)ryJ*fL-K%dxDa1a2Ss zAxlox%?~NIM-=?!m@ApAK`+sBPmHg9TEnN1kZeGD@`I7oOWL$_tFv2BlTdi( zP4eN}wzL1yM2VN8hr^Sayj2>5KV+ew@%wRctY&fdwikrlCvFmK5K)9ZukwdoXSuylu2)(NKS9_N1GSP2cMaJC{h`tA@8L z++^;3PJw>f9D*Ja*4#74vR)XK71#%(0jL(%c&9v3N1_}O^$)ILJb>|HSuN--7wMVh zP~B4Wy^jgsIK@=={iy?`tC0c0VO7PGURi(Mq9av+E11HCl2_OAO7SC*r)qiLY6!m_ zAP?yFwHdz)`_I-3*RQW(B7Zw9sF&Cuh5_r#u?)mj65fs)+2}Ea-m9Etfa=;O9oNmi z+NY$nzpZyPjt+Jke8Z!8BDE+U;meT8tO@P^av&cS9!c0UhnN=lzZylz%Gd5hl<$pq zi2xe78HC=3g|8p#-&y0H9r-q;9N~o;%cIOY&gTR^YOP`34Q?mKd{sLwFdVdgt3}z< zY(`})Gjp`D#HV`e$7XBxvrlt@PTEdUgY;jctU`c(nxb}ERbV{{3~L-*yL+y+sZ{2( z>#5#pt5cl(0!YWo&m;jU?4U8A>HIzbL?D}9oU$`32m%V#o9!bZeZDAu=ND0GW6$f@ za}REudya~?oVZ~>JC=?a{KY*dFyeUN8&Dw;g5bk@{|XbCPg9jsf`v3Z-7;=+9D{`bye7nib6b1u^*GHl%U zgSy|U4QH&zl&l@`jCt9S38lScg3u6-4wzs$T&b)ptDSYl}_&Lun zM=wllkXC|{BMM;VS>QxAl~(uL4&0jZVCG8?xOSApdJ!_aDWV-iP1}o)CbiiUq00D2 zEzcqHlp$A@Y`v+vhoEXOXAU}=noAeI}tFdZBfwqGq(~HQ+C2kTBK(fi^oQSX|`!hgT z30L{}H;uH97>`y=sO!ml_x`oNV~Adba1V{O*3cJkv2<4&%?xsh|F z=Bg6AFmmKPZc(IT2{*IMJ~IP3VeM@ex;E$J2=2IYx9Y36)32w^jgdp%%vayb$r_S1 zGAKZ^*?%wJ9#vyeI*oJ7vm9R89g&HIhE^e_*IA(slM$8xZQ~rxX_*lJm*X^B%xj$H z??kK6b_6nMz0D4UKvz2_Rz_CdFeYC@Q(cQrs>**-iNpXAk>gJk% zp_oj)mCsZg<`=!onPw0CCuHy5mKxnN4C$!I>Wc0S)E4nZ%!N% zo1Yduzw;&I?N#EDlb6uKJcAuo{<3}!pWbikBkjsQ7@H>jTGwC9n{pMO(Bq8=NF$2o zDt2!KVo>CmFaLO9iPp;|l2txh{;V=KmG!_l+TmAOUSUV)yrTAb z_^^%HjEz>{RjexRBa3x`e82Fc~HJ9)7QS2BiIs zlt-!d@X&+ugjPHc2 zjrxnlB_e=x3N~}tQ>+J@F<6o-5n$dW3aMLMc|lekXiDcw{c$H7l`atX3p(R?|w^^3Hx%XCo=KRMDEjwhhEL0E_zTPzzEh?zB-Ml{fjHjzF8!1^6%72d6#YnAVI>oNZJ6pAh zigpUr_NBE2f|o5{r8!kVuyou6EqaP7iK&0vJBl%ba`;^k5EzqNFTcLl&c|CWguybx z;13V75LWVjGxES=y0RsEa+7GbpyB=%0-jK2cvN!%w<%@a77Fu zyHAH*ISZm>-XxXW+}ki9Vj%X~3da0cM*8b-9HrXr;rY$?3Y~qBs6)s=;PJ)b<6@4M>rG~NkK*!(oo97J`nKI@18e? zpvpPS|fdd=nMhdlkU}J5XA67na97lSEJBUOQ_0jKql!O5+?ELm>NSy-c(2hBWyd)evx*0?FWI9pe)q?& zKhixP(Pa6$$Fg_0CM;v6ur?dqgiBip11G6O+5_hb zd6H+_IMdzpLIGmItM#1G!tM@VF7LL=Sakx|%ZI6^l=V~X57&5jG&M}wq(6Uhq434_ z)E%w$2)tjBVjL0)Fs-hz(U>yJGizX=`{*3NC!5H$6%&$_vSh^mVZ{EVB9f=r~Ts|5UR*E!UC zz6-iWqJ_U{TBGfk(Jnzdv(^~-+GK(*Pe>=|+4)iFpp%b{?!=_}gQbfWx9qG6eU5BrU0AzLB55k2p=CQYYRg^=Vc z2LbDGurQJI0SYiY@L;?MgQ&=UYNdr9Eap=A1nYK%jDJGHwvikBbbRjI_LI#ZK-S}Rr#5A5?}K-MvBB~0cNbrR|pVx5(%90v6n zLFOH~FO?+D>N79%El-n<80zewTC3|lP>Y_h`?HdrPR)P3hd`(gs(jdSIfu<)qoKyB zMs!2s#1IU!$_LiFjrGhau735)bkr-Bzte`qC;kc5RHPnGu=qA+8c;ewvBFd8NI=mw z`~NX?fs2*JR%GJ^Ia5_}ak#4}vzkDoq%UScQ^8uE3Cx1;8GS$E=GDvW{}I3BqEk93 zEv8w$wNz<~;3vutn&^8>K+9|~-sKCO%2_w(HMS17;rlG^VGI6PgV5SF867Yng(xDDn2TDBtI~eTfQ=TiH$vDP5B7>$4*22sW;^{(E zu4%_{YHRX&KffWKy|Z&wm0L5@kM^J%xjXRjd!O9RPYcS(?#dbu9ogmX1O8GzMpBWE z{f9EJQ#e|5;P~vL(dsD8T+8@-0`j5?7j=f@*`5*pE|o#a!{O;EUbsWs8pk0hrg%AY z(k!@;5hZJf7~X(!38qn8s>4hU66xJlgfNv42X7a3d~nt+LZ$rg96IAAcH_I;VA(|$ z4@S++1F064*#$^n8e%S-`(j0;N-d#b8wqGW9%zR%+(2Q39}$J+XijjDyL8XnAk7Sk zktv1=f?7Zk`C4U}gPfH+lamlD!nmeq zuU&ut=>V=*4KLmW!Pq>TC%7XC;Wx)*s z%jgdK!h}uV?;p9!X+QdPbY!I-Xy)cn)(?-bX+`3hwkpqY(7rTCPpo||KfA>{%){%-%$dLYhJkTIAcixQR_U z#Wx=+pKt}9Q!GBT(^D{1({X`Td3>%qk?Gl{m*Z6uk{7tz z_R|!748_4df37DMa{Yv36-BBOD(|Y|H2Gkwtzh)A{N;_^JFro_e zy58d5=1L2E_P!<|6&oFI{pK(?5HT1Xe$b%q=4DmflRF%`7vo|a073ASI>}c74n%-W z(}f`_f^|V|$J3x={9<~T(xM4@P5#zgMaks-@UikF`zov0exWfoQo%L*rGS7QE7#%a zj%i|KP>BDrtD)_Mj37TS1Qi^qOV}LU!u5^Hk>0Q5`vwpmfW4pP9ISoo=5I>=b$T%6 z%=~T5kac_~x4UJKznvfDQ0Kkzl_uj+RK^7JH-FhJwTsGpHhQ!DtiHd~UGSd|G+(uR>{Hy%U$yW9B z0V=rH@gTEu)^zcjeCgfAgh)`)18-ngmG~lUH2TZU3&yX{x@kWyGYTX+xy;taNZlvj zX(HNGz)4lrj3HnSUpZ;+|*7|HaY76B>RnjtrJYP$ii` z(_2NV4@g}RDIT4^X3s5oN(*PKrZ9W{#~YFSnq%=QLM|Orbin=Id}f=2oQZ17Uvy$T zYXmt(SK_DnmFiJ5GAacnh|4hOt+vy`5k;-jf*))72Q^)BjsSQT9nEc2zJv!XL{1=d zvF!iYgfa8^V%KAonE_N{A4Gi7mp8)y!;+$dck^Qr+KOD@tYe?sZhcq7VZn-AW5sx(*#%hfYCN*-9;X+{O?xFeD}wfOotWlE?vsFNX|OIH;> z&N&3X22==*%Bz<=$|4>3lBo5K~kLTAw5pSuP(nR1AT2iErqk)OQD$PO7y9 zsBinwf}pp+VkOTj)Gpv}7<#%jZFAOZG$>R!u%ad6Rm+b%O@)am#+s>IV{i@?8I{QT z2s!A+b8Vd`_e+cNpg7#)nCPfiCmDL)=F_b6tQ$;ky2ID7M_nw5&m*6!&8uAWubr0I zHE0}C$^I_&((-NYnXDz1&9OeqfE3{`*%`K2b8vMqjdoO!eN$a)@TxOmZC^LC(M#pv z-nzv}oBf|(WA9n>76k?8#07*u$|AFkA+5m^jz=*%{>PtXYb#sU0@ZM$H`O4%2=nV6 zj|Agqv{7|WQ*{(KbYs6&YsjeaW~>49;rmIerrXN9-Gf@zRbbM#vd1fDSfGS@*v#^?X-;mb?h7!UMVMWh0vTDdf}q$LwX7KP4B+D z$DTWAA?}AqKYMC!)u)-XVe|5Yr3x00Y-qq17*5`2c+QU|h?>XY zeLwaIcsk@g{O8P~bUvd12&b+-y0}%BbEiPE6uDgqkB)$KibcrsdsiJ-4G3)tmS`Y=kR1fE8)ys@Oa59d!-2 z4Fe>UBPAMSv1a1&X0#LI@|v1mvGBgY&G%1kg_($!7#6;GqJ3q&Q+uxB+qLD8PWP$- zfVlziZ*-!X(iqNyQFFUwlGvVJDR%;1A5~da?K<%G03u}J%_kthtN(rJbb4y*k&b%r z(hH(v9(s<2!EMC6aaGuuBR8kmFi}KYBb69SvFp*q*2^S13Z-3kxifH!t+Cv(h=1#u z;b7GbPXrdR$Z_XddFgg(v$u*71W zW`hinJ4+kKwGW@g&IT?leV{h^(&hsSumyT|TJLo9R(WhU)QoMDj|#$3K7pl^axafn z(C7#-Bxt; z^#QaU)#o_M(xnc%!lSW6O%4e;5kJvlMZ$Ce6|%^Km6Hl>DPQ5ij}BG8!!IoR+{6j= zSueYt&O5Q{?q~Jip2};29ht+d7Q;|h_Fr42Mx$MrBsvAR8Wq1&spX&zE8%1NxGVBW zY!7>lsD2D!y|uK&uiw$3VLvQIFp;atxK4^D!ujlBX9J^7q~b=N3m#X z)i@wcDd7Y`o;!J5emETp!jYD3{BKFi=jd~dJ2_uYF*vnbTxkyalXyTyOV8cj<75#lcrGJ<7Nrw(FS^K0XtF{;9H}_`etUR^%q<-E?P_LGkpY z<;DZ!LDLF<$6Nvpw~gCx;9L!p_w=guIcWQcV{vbc{^1r0Q?qUXYI?NrXM3wWhaltc z?;aGOoPfxRZPY)l^*_ZwqGb*GF~K{^%cPW-D{`)BW=L<+F-^BCEYBLhS~wn|RU6|; zLc}xmYK*E-C`1C(V6wDme)t*Eg+#cn{2$xsR|Mk$DXkqh-k2)V=iF2wDW5+ZBev7a z@G|C#8ZfL~Z^LVWSf^I>1UfZB`MSBq27=06*XX7xtF_Xi4QizjZU!%q%iQ zH_q}T|JCY=?5%Ps7k>bH4i2W}V*hq)Z+T&yY2zTgvqK!OzdSB}L>BI0Kd zF?>bXmzP$Zx=!^)JY?G+T^RwBJOyifu8x6BzyNquPqdnX56Ij`OM(Hg+$Cb4X?_aE z?bKFrmM~rY{Y^o?mh{oN#jwE`ZNV*@o5ls!EUl2;4U>94^K_;O3`taOn|kiR)bMCX zyrFdC)nHjX?M%pOd$yMu5W#0={2v>grxmzhl+VK>woR(s4~s8HiS6tc;wbr4?`fVA z{qY}ZoUI&1+y_rsE`a&SZ(&{|0~r_f|JW#)9n#1`0j9Oa(YZDs#)v#-rLSOG6XLn@ z83qnUm&ya(&4*e;8r+dT`+jI~kCI)_T`;@6oYn!0XXX@R`#X|TxInkda4e3vl3^ZorYeqE58p>P(e$p+ z;<4K9;Dg#H7TT4k+HTH%H)0L+OOTj(qard7rWvDQXu>wj(@a3u%+&ziSr;|j5avhF zr!VX{`Sg7~j{lkdzlQUCUs9O0>#0G-KKr|$t*hTOEVG7auG^z~j8Spbl$-BMGgka8 zFeV$v(_+D3yz1wgC}Y(3dv$?^&tHgNsHri}(qNP47!cUrhZl8qiMf28Sj|;NntE@; z%#RJLWDVj~xct2J{SjSJcx`^MgEl(&)d*aTU~lOAltW03{GrBe?&P0&(bnmt+S^k+ zw-@1&x_RXRK{Zi_V4Dy)X5ZiH_`=TlKUZ0M-60X#Y7W607z3V6Q z-@h|+l@!qrAH1M^$aja~QoPSHyw*Ti@x!mdXOD|V{QC(V$tbs_isTa8c&(PcjCo7w$$)5 z`Uw7a&)ja0$Nqdp zO05Lze|e8&eu@w76hPJ@VEc6Vk3IGA)Q}@M%!jh~bu;GY>s(!1R4qeL9&-Wk0& zs`TPE3#**;gOqhD5sOdoDmnj@`BJ6W6i-jQRF z2Iej!+y|^b+M`^oe#gG@&DzSak^X^<)fa!dCGrSa^1H09drq0{Sy1?+o89nQoL^{W zO8s@>ZWSVzsj*Dr$qKMuY)#Xol(rvtEMkPBJjbJ8mFwRK-iI;QbT94XKL|Y&FvKDD z_n_}yM&G}dS4%>9qy%Ux%Z#K7N9fDRtQGgr(p7KR4;|I^wTS?uwZd_N2@2)HWG(H2 zft3~23UDa8be}kVc<=!iCFkET6D3vz=(*Fn1J1VPyTsy6tt_Fb^V*i&vv{OP?v;78 z5&y5lCNIk##=i=B)aW6i2jx1;j?yq^nEoMU?Ymt{I4Uo&2{bs9Hx?enY>32c1~FcR z*|9Dd?(n&sly~yEbI1BK6&EO052(f6Yy0mT;K7N$_utpMrI(l*K5dr`lEhP#I>RsM zx(0wWik7FEv`30W%L}Rp1G4Tk_&Ed_wZiY(J(?S6_7N!Jz$RJbrIfA@<$iXQ0beJ~ z;vh0bu~;b&nz#qcwES?ub+p1pdY9SxrR?WXpoWCYdEGk79S zS`PoKp_0-Q$VmIlsCEiv!BYG2F-m_tqi<;?E+su2Gx{zo{!3Xn&hIJb>HY2AuokHS z$wC2Z=xs9sejSwJzo1>cXc=% z*NxVuoxs#au6_uwK+V$jqJ5(RB40{*5l&xeykN#H`{jj5gI#&<7XcLWn|V($-RJlU#WYX87;k^9HK;^u>+e|}jS zsw@PwxZM?Y!RKb~7DFOM5nSfEyo-y4tO+}o>j~vVR)oa79$#gafhxvh- z`Z`NL!Vsp3` z`%GN2%1}xk*OEUb>}a@gm@vCFV!XRzNZwkBvXcS zrH6h>W$q8VTk2i4jF_9vA^lt6qD3&xBS!*4D!mI#*v_a$K4^R&&LvroD%Tvy*&Tzs z8N7c46K~^V%lN^at2=u(@cC4j+6YCc1GLh(IvhC`5CO7A!G_G&iz_17-$S5c=fiw7 zG7NL@gL8a6zJso^_GQn6KK^|cz8tz#5pliR7|N&B#L$H)(1m=1HHXYVO>Hz_UzNKG zman*YOXYDpm%|eqBO8PBH(slgDZ}25Tv=JZd6Co6*w!SQ!YAHd(VBv#>?%h-~Q+IaC^u-PmPO)RVuqjTNf(45N8O{JpZwwrWDA3z6Po_VPXL1 zaF94D+O})rVMhY%lB&riUDm0lSMep`SGe{ATHQ=n0tRUCtnlEavogKqh)f1U?s?98lHa`t)rlhX9W*!|O+c-Da|yMZD&Ll`@~ zMPOha34SwEFzL`z$W6!6uPp!+mncK(kOlQ!ANX*`x=5t`{hBVfkwFo%cN3@B8e87b zm~g`2|6zO7mg0fBh|a39OYt#G*HCEoL=O-~T`5w3_NpJ?UC9{N9Gqbc5m%W@ajW!k zy+pNr!`CaPNNLea;-&B<*h+X;BAVa$i8tmr#U^zJv*|95!@`7vTvPqy>rLk3XI0J| zt|PK%@zddiNN87}ZQQ<#Af*yW0zTZ_E}`!&xW?DIMxB}nrbPA~cUlRkXjLV6)7B(Y zufjF=u4azzBD$gCqKe+o!{wu63lL$OVMU7U14`Qf%Fok>hgRaH6$WTzN2uw4siYd zx!E>3NzV)dS2NXcQe*ao+Q3Yg+i5SM*#&p zA*|adO_`A_4NbXVvj6>n#p^4w{j>gyj_dIKl|ymkK@vyHS1Ix34YPoWY9?E~PTUp& z>Hljr_)aBiTjx@I^7R6Yqie4F{U_|uZgirue!Jk~V~{+iTXh;$V+l!@8t%gCB=g#84f zJ3VQMr7=V3|IvT$$j)PW{ik2-v96m_&VIprAGc+~y_;{@hasbtMsQEj5s6&0WOOWIw1mD^})L&Uj%3E6QE(G`Tpc#jec^fx~OAUHJ8Dye5`I0vsC~ zS4c}!a@_YH^2^64C>z&14$VO#8wT)L*Ju!tezFc+gl%IqA^=i${l8PlOH{}&@8WY9 z4}USAKzeNt7E69vbT`=wM{#>=>>zHm(4O{h>`J`>Wa(*RO4N6rjm5R`1DR?0+SOJp z!N*7Gio?M8*Aqn3Q$MMe|8l9w~@^Ewv%%) z`QcTPK9%eB1FP1A;fK9{w=DU&bJb_cM24evv?6&+DPGe)9rjDP9Tw^UM-`W+hg68w zB!|6S@bAL#@fiuZ?mQL@Zm`$;B(bw!&Q*a>-8_nW)&Vf{?M84}-q--t@-ib72;4bu zG^mE?oWSG`QnZf5dNGvV9ik!KoDmY`-In~sDU@pVRlZ1Bu=HO)sLMm!I~VW4hY=a4 zw?-v)!MGCBsVctVXg&Dv-Hpko1ufX)U`G(dj#lRm5Kr^YA!-Th;Dz80lks|$(wZky zFKT{lUeWz$KreVNEdukRBm}|a#o&gf1fn6Wq_J(7ODOGxTLl1p^Z#GH06uBc^GW-k z4$`rIVXv~{ZD0P4JWjG*7^xN3jKBMF@cYZKMH@c@U8^)1YYRwAhi<>4Q7z2mc>hQ& z#WpAP#z*6&s9d$HP|{&Wb4m=1RPQ!yI=F|%a88v^5RUgZZL%{lD#c9hU(*R=com_x z)VF%?zSggBnCX%c8%Xd;@T73ro>P5;ea?^A#sRelBOKyI1xwiG50|VmAutf`^VNJm zve{50f6Hk$G=K1Oru{lAh@~=Rp25qqIf-idb5q`_U6$xSam+M9i%e8bGJ_Vt|3kkR z2+UACt^G(FQt<3JsDH)fRkc8a4bGFW_1C*v#b1k=y1fXQaAq1|Z_M|4`@3ED{3c!Z zA@!AFNORuAl|M=#H0&p9pMvZ zJBfd+l-YTO*FVeiZpi+0algvmrve@C;qQaC{vBf=Ku$JEDFH&M^?We%Goz<5J=+9$ zKasbpC3Q~h!rwuO)>M@{m3Dt-p53)PD+Ocj|GSiCyjEdg4LBY8*?pK}>=`+DPfP82 zy0h~QZ%xm}r~($C?I+$~>;%l$M{4j{!tvhif1a|*-~Ms-HGAr(hPc)VebVGcpz~O= z?ZhH*ZCDjwxh%n^1lM{aqPd)^u|K+GUDuF9h8uu640Cg9Ji_#~Vs%$6BQBoktH|jX z)-*-K;L6;KeqWE(HpdwMklTVdA!hwuj+3g&9p{;!J$6`Mt{`$AVst0E8v;xa@+g)E z6orR?OmwS`mgqj5+w>><6!ZR9g@K3m)U@}HakpG3Xo#PGb5r|>weiTtY1OHlflmgO zd!8TF$XhSw*_nfZ%!$wtREXhQ%WHmQCk-uHD*^P5Hj=xjkN_PPvW^>hIT4cV=Dy0F z%P_!`LvC5W6wtNU{rNN?RoPi(NqrrDH!2U43ji(Ly@Od5k{D3#{zl9<08Q4^b61E* zOHf7Am&`ARxmixRw-${YAB+Hwb70e3FLVDzUc(cdyCqZ~8r}u$F%_d1m4CuzuNhR{ zdX@C9ows2;bQa~?dE7?vd%wR+mvN}}K7dcyOpGFavr1l2F$uv85iP?BLG|ES&2c;) z&zmiwSa(_CCTDmj#eT~0G~jt)O*-Fqp`b1UJId^Ah;$y(ACnUq$NfoT@p8R)zU8Xz zu*3mvG%!pzf+cJ9kLO6f4&0xQzVjwd1$J9@L}g1s@643yh~Jmrz$DR zW??vS(e&2bg#P3fE%ZfW&D`uGo!-8aWf{Ix{E9bHum#!T6%|8kELhr__Yiv(axT{x zFP28!c~zC>j)S?GpYgWpFV{%gRVwyqYC?REi^nM^Bwu~@l9aUeL!)NcSgDo5yX}`m z%FT;xSsH>kqB5puBgn_jEH(6*VRwkydnx2c{d?a6d?#)=g+R&zk9J=u-dwx(%FlpZ zh1Q~BeN@rJY6vSBk<)d8Kl)s>ApliXTt9C4E#Ht*&-FRrPC7~BoKBKSwQ#~ygYz1z zh(cdw%>5P@Rl9vc(C4n03B0URE90bpf_3gPcf9CrbP~}nF|KXRhF071vB2QG&Al!E zuM*EZE5i6Y29W{dYL1}*gCl*z5}Ry0rGFQ1-?vshbzQN|#u9zZy%*o@KTI|I60VKVt9l&UPXtsP}f4?w&Sz&BdMjODpgd zS9I+Pc{1+a*awQ*1P(|-(!94?J1hzI8E?zk({($kv?Q2N#S&UNz;Ey0lkC>;oVorD z`Gc)MMk3-OZfa-K`qf^ho!=d-s|AJSnVdIla^-qaAzv8`N1CCNT(E9W&;zeL61=M( zw;9GyN&b!x3wmuhaSO?tO&Vm$B39am!u1W5?P9?oy6(GmSeKl}0$p!m{v57o&LAa~ zZPuS-;79+NWl#0qD8I<-jT{|D2oys@%qC~>N@<=`eamKA1M5`Sb3d9l_Bm--cwz3T zGJ^CPuCIYN1FtsU8B2;kv?clhGpZZ5%Q0#^!j-j^)>vEbHFxQc?wvWnYCdAdF$A^X zVxli9*j)7FOPW)H)8D*}+t>KJzv>6Ob+RdUpsthd>Pvt32g`|I>i=!jZYkCVCf}HW zeac!CJJ3vApXyXw1mWBKuhDg}T^qVn)@6&n6DxLQZWOLbtgm0m zDfF*4l%ruh65T(?g^Xg(JZ~PY-W+)aB`4@y*9S zERgh=AUe@pFmM-c5{7lb=Bp8uVd2!bB;y?o6E^(%7lE&l7Eb^0{RjW)lnac8GjZPY z6|ya}4d|yV^xjHXyUdHFS#b2VIoDiPt8O6u-<1E@uC#dQ|Fq3qStcpzZw7$A*mRUd z;u&b-&Y`Zc8AXEDhBlm0OK#irOH=&FJ~UvJIuDBvk7`2g&mf4!od2EX^JXr zXgB}Co*VhWpMO}aAf(#Z$hf4f$}I1_P*d+e?>Zr<308*~3bSMK87+?399slqPK7-b z!f>x!rBUEQ8+NeiJjs-iyzn+}DCb+z!d*lTJp(FnuK$0S>q`+l8y*%}GR7^p2xA)1 z;+HJX4W^`HewQ(i&z(?{MIW`M_(Sjxhsi;H$Src zp-QwwpIf5a|5hhQ-PJyR?fJOf^P1*!?wE{^P@)y2f9kUDx z3`8CEC9^w`eJYIgkVRtwV+YMX#Kb~hcb>RZL6uxhdR_*^yQBGNBkcmvrxrPbb(QE2 z(Nrl*I-w9)dFnPuyy%69wvDUH?Lw6A%85eHF|)EjR5VR_)*m2@7srHwDS~rx9|;eeO@+_D zR8rShkJtN<%CQ_Uc>ovUcCg9MHU;T}j}IBC1U! zFQg;XC0;!d5PlVj-FN4P4oI;>*9og`0^RAYbvf&YjiMMYtL_7s!vcY`Rp2dnwAPlHsPi1wlrd($3rt^JQ5HM8UJEC6XoX?fOaHM^WiKjm=&fIl zq_Rw-ica zpxddk-Q6bn*|aoR?s7EOtt;LDi0Go%01(g5;eO?fXdhX~us10G2Ji|xu94y_Q?1%w zk6EERuNa2}FO{y#t^vO7yDFU^s9%w6GKDWBC%s>QAh|NB`YrQa-|eEu4~<6HG_>cT zaHUp|zpib5=Ggx3UKc zNK7PeX^tooi-Y{3Dq5PD!f;gz{5owlquGz>t+1-h zlI^ZEiKc#=p1ECdF~@N-!zbx!e-P}h;M=*Qz)Qad5oh1y&ChiNRv*nM&+cuwN>J#O}rfh#nUPPF2&U2Q^^PGQCv6!<_j z$=dQDV|*?qu1L8lEZB=vl_t3QzPkvsPAxbN5#6`hka}2}Q~$HPgHcx#m{)5gcT|R{ zX*_9)Vn>hN0!}_GO7*QPwywn;wR5gA=MpRw;)TfIKHpO-tN^{mA(FprlNNOK9y>q$ zXHYOUVs>-ZJf7BSNHiZ4Yjh7t*=L2yE zio0la*F*gjRt(W?A0$nlZU_JB{qxQw#Pa-&rE@u+akYs(;|BqO1sToFKF9UgfjKhg2_yMRD8P{&AwUE{}qj5mggubo0eXpRM2Ade zKE~)#74gJ*RL!+3xqwe)tGJ>9fF~XuVSq~9n)T5;t2bYXX;IiDl=wI%G4J9it+h@R zxetHF6$Ckl)EBOt=VJ4G@W zP5S++)iL>g|A2m9>|ufL66fIXEsUa??-~z*Ok4qpA$ct< zwBH{OUSv72d65!tRNsu__s4z`0JIdCe;$@9D|G+xYh6qR| zgVZahR(Q%4^hR0dTJC+TcIZQNbsqX}Gcc#IOj!B)v0bnEW$&k6kNz>$95qjD;V&?` zcr|A%2eHq@8a&5|suUrscI+D+{5E7fl4PnuEF^l`_Gj^a+IB<+Iz)%?TTOM}apJYw4Z5kJGuvY?!Jr!8@9t`IgaHiYScD7a#% z9$(rtQ3u7mpBGKWRFFe~;=yUQ-;bQwpPga5_v2!SPDz!9Ot%W3D>cb7>2V*A!cx*nZYzXuCuU$_8|ihgxeZ(sFm08lso7P<%mG>y z(rY^52{oaj3Y`dc6I!?Xd~%qZ*7Q+WUIPF4*>dnAT1c}hvFdhp_aTIVb@HF~?`X%b zl$lOD?Z~r+MX&CxjHa}Xo(Zcm=G9gE*e{j9bSAhZ2)&;p45k>5z0t_Qz`oF==3 zrwV3$qe5K$1Qi(2qlg09f=@<1M#^jyM0V@e^Hg99YwkYQiJKFgbe~djF`fe#U-hmJ zx*PaNIN*`oZ!ZI!#ntM6xD5R?ajTybE=9haE83^I#uV?c-htoU_pOH_0Uk)K7ufaM zPE1ubx#(VIcl`5Pk>1d2(w>^{w%y!rNdI1uH*)s~v}4-=Pjy?RHCkqv>PzGfcm+m642U??H1HNt(Qh74-NQV`;}u7^5I7Kz~%UV&fW4owY!KW zCQx`})Cph^YnD+Ley_qO*QmUxqn6xOg%y=-LyC%_vySeL@w;DIy(#zeMYOpd2^DQ) zn-|zt7~u`LrUfC3H8Z^(#XJDMJj_bL3Ylv`hgRQEyrNtDid))fw{BTP$$XvC8$M{U zN=kw#?BR}&_Jx<1QCsxyv6A& z<#W2Ix#qd-6t7-^k)Xm7G>SapKoP#RT>Wwh*v84$&i%A4+&6JWX&nJt&?>5a!LcX` zx-fvAS`@k6x4MD-{k&knA0k0ilI0WYv=)AYgBz2(JZXwP#!6=1x^sz9=0jE=%JWR| zTO;HVVl4wHrXHntQi8rkM|9&H8{oce$JvDxO5L9t%&)elBMZ+%%4912*sc(y*e5f1 zfr%I+*I?j&{ZY~rPg`?pqZJUqa$C%RDMC-IqmQ*}MMwY7`R~2UZXf24?B{=x=xG%Z z{KEQ8%el-U2JsfP-@<{O2Xp-^CK49&g1 z0rT*v%`((vX9H$V-1&DlT-%c&LARWD=FRU4O?sK3aXwGsW-zKOq5~FAS01Q~8le034?W6+coi;u6C`r0yy{?7(T0Jf&-5IRr_-n#{ zOWqxtiZ}T%&VA4S4Yi2B$gur=%TCs6QK}|f|0Kp!PIbz`z}(Dp0%Et1SdB9IkBwc1 zen$wF0BRoX9TSDh>26!Jcw1_J11a}hIQ>g}2BkHk)9ec24C+|J4v|9qT@YN>*_|vH z?no>NcCI|vnf@>Kmr>qW%h2wr0gxO-O6o(88ypcdj@nQ>NDm3Ia6Bdqjc#in=|LsO zit)rvjztjN6y{d^)-HXNG+M@AwJ*-Vv7^I& zYOb3Oa#plp_Q`ayk^k73e2=voxI)#82o1rZKzkT;zFh-|a*ply)_;z8Yx$qRTn(|roe=iTZobz{qXh-L zUALgiGMV~tEJ|nTg8}wuo~+P`@P?Il-|i}Y@=mu(^-YP+4iBa34{kPh`ukT*?;nt> z%w0xpH9=PNcAF2Ds%*vSLK3@1Pa~qicUs_H^;bh#7>jDT;4yC)`FPifS9d~&&~f8b zyhS=;5B{*gZ8Nt8KR9Z77Xx4CG@W}xYCo&=|6#7HC7PzwD9k8L(gE{OzW{P)rY6-K z=4ZspF1m%6Mj`eX2~!9y|F?-Mhdr}*H*X7Zg4gYrZa}P`PhQqRMtgNzA5ta&y<+ix z{p}pYgcF9m#j3N$t*WsAs~#EQC(SM<{NnVe>Sc=&vw(GETdsmu=te#K=rf-3o%!)c z&2YQDyJnijNd&gp(wZVtv^|Iu8V9O<4>~00zTAi!Z<$uOPj+CNly`Fwk>hM6U|wWD z4dfm%1sRDVS60Hf=k!LB;OuEmYP3Ocv zrVIDn^&LEQMqF{}Tsx5XCM6;c0l~Vb3a_t7Bksf5sX+gjpjQH-tL-hZztQt3KE)b? ziM9?vw&4DCr^bV86Q3p6WpKLO@>UJcz z2rk7V_a;!sF;#17Z-Il|1iQeJaHW4{T11O}*3GRm^?zPo)79j|Eq4e=$rvtw>mawW zH!i-(9PivTxD)5kqie^xUfO{h-PQ5czpJC^pHmuS^0*#_)L|{rI2SOKfE`5t#9EA4 zVcAHw&&=KIpEqByao>c8%wl**m845|d_vad z@JA;H>V#2(-9kapEnFuLxb(r7u;OmSInHD!@>e<5oHj1;wn5RpKwSB`Q%_H4CLMl# zHswA%QU-+zRh;-mhWVCOg!K+=H=zmP;VeFF!U5)_tW&lD_EQ(*%}_WE&?Az{o;)er zp)^+)ZD`P<^(8XKC|i!2GE2T)u}{^?dg;eQ=wM z$1G`#`|xRJdYb#uosLG@U{N=RyT?mxDY6XBSF z+=$S3tSj^&d+1mcXT8s{O)~wPZuPUF>bP&;yz+xg#HQ^b5(&?yALVtbo=eILG|6$A z!$wDxMc9b&+|GB=gBLIPi_gH(vUGW@AyA{k?r$|2fVERxvWag&;Y>7UGKOaZX@5b} z)PT&?E8agA)V8rjvUD-HVg6BS)j~N}Z8%l0``(b^g(UQ?aZ$q;uf7^vQPC)P;p7T6yaw{E3w_lk*lMYMgM zj~2ym$-WQ%wJ*d;;AqtvfT�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 literal 0 HcmV?d00001 diff --git a/templates/supporters-astro/briefs/oracle/logo-horizontal-cropped.png b/templates/supporters-astro/briefs/oracle/logo-horizontal-cropped.png new file mode 100644 index 0000000000000000000000000000000000000000..8b9fd11f87244a87364f63dfaadc5051468b1910 GIT binary patch literal 2500 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 Q(*OVf07*qoM6N<$f}MiTZU6uP literal 0 HcmV?d00001 diff --git a/templates/supporters-astro/briefs/oracle/logo-oracle.png b/templates/supporters-astro/briefs/oracle/logo-oracle.png new file mode 100644 index 0000000000000000000000000000000000000000..0663b50972326bc7f05a3842d0188496a326ecc8 GIT binary patch literal 9826 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 IM6N<$f+KSQC;$Ke literal 0 HcmV?d00001 diff --git a/templates/supporters-astro/briefs/oracle/logo.gif b/templates/supporters-astro/briefs/oracle/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..13d70214efdfcbb118b553a0791c8fc653d49074 GIT binary patch literal 2156 zcmb7<`#;kQ1AxDq+0|xSlIvkL;?Ni>Nu8OQCA>=)E7y%9Lb2qP9B0_(&NwdbF=a!H zhVjZ>Ok}0RA)GFnC@P)yMmK%lv-3IcfABs(Jik3ZJl;p>t_RrLKxE(%0L;Cb9Gq`^ z{bA*TEFh~hMtnP4{y-cdrM=x){rGjGQkgk8X{dhpIHfh@zFK)+#*D0`HQXyxKJI+| z5~kGvscm7k~tps01(yMH~A@{{sD}?IxnYyo!_x6$ z#&A59Cs%cpfYC=p-ABNxN(Xd+FPJ=MLud@{WC<;I+}GA%w25Fv4{&&*l77Tt4!XwNH;B|ot-5Dk&tk>!{hZ#sTV1dysCRq16f~*Cl^}Id>IjS&9#2xcmiDY;?04y^OC>f*#T;_~; zfG)io1g(B%Lj#N`8Z{P`@|jvfjmr@W2m_zZb-S7@YjWF-qDoLU*4t5sNPog23W6Za zf+!Tn8Yp%+!Bawsk^}Wv#&2hLvYdxi+T>=j^BTcMEj95pK>VqriXcAvq|d}1*a!=8!QL@h?$V+$T zR=^JRz{oi-VTu+K4qJ*WaP2VkiS_U_2rAf}A9sQgv?u-aC@8(QyryH0OWn~xin9&@ zEZl`2BWJlLy9Mo+^1<01#}w4m_Pb53xOI*#AKccpbx!{CWY9Ee0Xwo2N5B5`eFA;> zctJQsUm0D9<{VwFM+IVsr#!uxdvJ-uscXF}PUsQ1{L(tPh6Ztu#bp|L$Oz4N_09Rb z(R{zQv(h>z)t-J!zezgNdk3zJ+t<`Zi=HCHes7=94MWKinj0-5LafSplR@x9M`S91 zTCE;<#57AtDB5>6?DX3H>dkwfuxQV4NCv1VhE=>8eBv z+SVn7-BkIIgWl|KSaSYA@1f0j&U4g5y@BU=jQkMI--dIk2Y;vO52`awCc8X|r7)F| zzV}^6Kc6J-PY0>>nH2m4YBPxZiQvS{ebTcBDo zJUxb#Vh1PF-wY-m2FF?d1 z3byG<94-%1yc9u|LwS{5c8gQF7!%7WFte^^kmvT#7*X-z>`?+!+lX}^nN>P50rF3h zEN{`Gby_KZT=^p9);&)1=FE_ly|5r=!WcTX0^Z9JZhLDwTy;K4>2$NiO|P@=A{3|x z))E6uu@tDwBWGe<3s&Gv)nJqmF776ZqJU9n151$X~Z*o zx4SgGlw2rU&XP1Z8i8V@LSz(}{Yy$4YVfZ+Krh6q zczb`qKGf5!)qEjRq4p6FjA48WNi@%pUEYEG zhpK?JL|~q68^~Abz+9#Mp$+eD#>eO81WsSZW|E}+>+uuL3O4P361VrMERc|L@}RsYP@4PPyg=3CznMw;9oa=JS>xly*ZjtvY|K zs)a6UbXzG8Wa2K+VR&H-)!sT$8GM-0Fo^4Fhs)cZUA|VSlK@cM7{M=gntoL={5wjE J%^<+RzW}hYqG|vD literal 0 HcmV?d00001 diff --git a/templates/supporters-astro/briefs/oracle/planner.places.json b/templates/supporters-astro/briefs/oracle/planner.places.json new file mode 100644 index 0000000..45c31b9 --- /dev/null +++ b/templates/supporters-astro/briefs/oracle/planner.places.json @@ -0,0 +1,661 @@ +{ + "_comment": "오라클피부과(청담) 회복 일정 플래너 큐레이션 장소. 기준점은 병원(선릉로 612). distanceKm 는 직선 거리 근사값이고 verify 항목은 출시 전 확인. 링크는 구글 지도 검색과 예약 사이트 검색 결과만. 2026-09-11 작성.", + "origin": { + "label": { + "ko": "오라클피부과 청담(선릉로 612)", + "en": "Oracle Dermatology Cheongdam" + }, + "lat": 37.5115427, + "lng": 127.0436528 + }, + "categories": { + "sightseeing": { + "ko": "관광", + "en": "Sightseeing" + }, + "shopping": { + "ko": "쇼핑", + "en": "Shopping" + }, + "food": { + "ko": "미식", + "en": "Food" + }, + "kpop": { + "ko": "K-pop·핫플", + "en": "K-pop & hotspots" + }, + "care": { + "ko": "휴식·케어", + "en": "Rest & care" + }, + "essentials": { + "ko": "생활", + "en": "Essentials" + }, + "hotel": { + "ko": "숙소", + "en": "Hotels" + } + }, + "places": [ + { + "id": "pharmacy", + "name": { + "ko": "청담역 주변 약국", + "en": "Pharmacies near Cheongdam Station" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.2, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "처방약과 냉찜질 팩을 구할 수 있습니다.", + "en": "Prescriptions and cold packs." + }, + "mapQuery": "약국 청담역", + "verify": true + }, + { + "id": "convenience", + "name": { + "ko": "편의점 (청담·선릉로 일대)", + "en": "Convenience stores (Cheongdam)" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.1, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "생수, 죽, 얼음을 24시간 살 수 있습니다.", + "en": "Water, porridge and ice, 24 hours." + }, + "mapQuery": "편의점 청담역", + "verify": true + }, + { + "id": "porridge", + "name": { + "ko": "죽 전문점 (본죽 등 체인)", + "en": "Korean porridge (Bonjuk and similar chains)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.5, + "indoor": true, + "area": { + "ko": "청담·삼성", + "en": "Cheongdam / Samseong" + }, + "note": { + "ko": "부드러운 식사 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", + "en": "Porridge for the soft-food stage, by delivery or takeout." + }, + "mapQuery": "본죽 청담", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "smoothie", + "name": { + "ko": "스무디·주스 카페 (청담)", + "en": "Smoothie and juice cafes (Cheongdam)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.4, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", + "en": "Straw-friendly options. Choose nothing hot." + }, + "mapQuery": "스무디 카페 청담역", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "seolleongtang", + "name": { + "ko": "설렁탕·곰탕 (청담·삼성 일대)", + "en": "Seolleongtang beef bone soup (Cheongdam area)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.6, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다.", + "en": "Broth-based, fine from the soft-food stage." + }, + "mapQuery": "설렁탕 청담역", + "verify": true, + "dietOk": [ + "soft", + "mild", + "normal" + ] + }, + { + "id": "cafe-cheongdam", + "name": { + "ko": "청담 카페 거리", + "en": "Cheongdam cafes" + }, + "category": "food", + "minLevel": 2, + "distanceKm": 0.5, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "조용한 카페가 많아 오후에 잠깐 앉아 있기 좋습니다.", + "en": "Quiet cafes, good for a short afternoon sit-down." + }, + "mapQuery": "청담 카페", + "verify": true, + "dietOk": [ + "soft", + "mild", + "normal" + ] + }, + { + "id": "hansik-cheongdam", + "name": { + "ko": "청담·압구정 한식", + "en": "Korean set meals (Cheongdam / Apgujeong)" + }, + "category": "food", + "minLevel": 2, + "distanceKm": 0.7, + "indoor": true, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "일반식이 가능한 단계부터입니다.", + "en": "From the regular-diet stage." + }, + "mapQuery": "한식 청담", + "verify": true, + "dietOk": [ + "normal" + ] + }, + { + "id": "cheongdam-luxury", + "name": { + "ko": "청담 명품거리", + "en": "Cheongdam luxury street" + }, + "category": "shopping", + "minLevel": 2, + "distanceKm": 0.5, + "indoor": false, + "area": { + "ko": "청담", + "en": "Cheongdam" + }, + "note": { + "ko": "명품 플래그십 매장이 이어지는 거리입니다. 택시로 3분.", + "en": "A street of luxury flagship stores. 3 minutes by taxi." + }, + "mapQuery": "청담 명품거리", + "verify": true + }, + { + "id": "galleria", + "name": { + "ko": "갤러리아백화점 명품관", + "en": "Galleria Department Store" + }, + "category": "shopping", + "minLevel": 2, + "distanceKm": 0.9, + "indoor": true, + "area": { + "ko": "압구정", + "en": "Apgujeong" + }, + "note": { + "ko": "실내 백화점입니다. 배송 서비스를 이용하면 짐을 들지 않아도 됩니다.", + "en": "Indoor department store. Use the delivery counter so you carry nothing." + }, + "mapQuery": "갤러리아백화점 명품관", + "verify": true + }, + { + "id": "apgujeong-rodeo", + "name": { + "ko": "압구정 로데오·K-Star Road", + "en": "Apgujeong Rodeo and K-Star Road" + }, + "category": "kpop", + "minLevel": 2, + "distanceKm": 0.6, + "indoor": false, + "area": { + "ko": "압구정", + "en": "Apgujeong" + }, + "note": { + "ko": "기획사 건물과 아이돌 조형물이 있는 거리입니다. 걸어서도 갑니다.", + "en": "Street of entertainment agencies and idol art figures, within walking distance." + }, + "mapQuery": "K-Star Road 압구정", + "verify": true + }, + { + "id": "coex", + "name": { + "ko": "코엑스몰·별마당도서관", + "en": "COEX Mall and Starfield Library" + }, + "category": "shopping", + "minLevel": 2, + "distanceKm": 2.1, + "indoor": true, + "area": { + "ko": "삼성동", + "en": "Samseong" + }, + "note": { + "ko": "실내 쇼핑몰과 도서관, 아쿠아리움이 한 건물에 있습니다.", + "en": "Indoor mall, library and aquarium in one building." + }, + "mapQuery": "코엑스몰", + "verify": true + }, + { + "id": "dosan-park", + "name": { + "ko": "도산공원", + "en": "Dosan Park" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 0.9, + "indoor": false, + "area": { + "ko": "신사동", + "en": "Sinsa" + }, + "note": { + "ko": "평지 산책로가 있는 공원입니다. 20분 정도 걷기 좋습니다.", + "en": "Flat paths, good for a 20-minute walk." + }, + "mapQuery": "도산공원", + "verify": true + }, + { + "id": "seonjeongneung", + "name": { + "ko": "선정릉", + "en": "Seonjeongneung Royal Tombs" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 1.6, + "indoor": false, + "area": { + "ko": "선릉", + "en": "Seolleung" + }, + "note": { + "ko": "유네스코 세계유산 왕릉입니다. 숲길이 그늘져서 햇빛을 피하기 좋습니다.", + "en": "UNESCO World Heritage royal tombs with shaded forest paths." + }, + "mapQuery": "선정릉", + "verify": true + }, + { + "id": "bongeunsa", + "name": { + "ko": "봉은사", + "en": "Bongeunsa Temple" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 2.2, + "indoor": false, + "area": { + "ko": "삼성동", + "en": "Samseong" + }, + "note": { + "ko": "코엑스 맞은편의 사찰입니다. 경사가 완만합니다.", + "en": "Temple across from COEX. Gentle slopes." + }, + "mapQuery": "봉은사", + "verify": true + }, + { + "id": "hangang", + "name": { + "ko": "압구정·잠원 한강공원", + "en": "Apgujeong and Jamwon Hangang Park" + }, + "category": "sightseeing", + "minLevel": 2, + "distanceKm": 1.5, + "indoor": false, + "area": { + "ko": "압구정", + "en": "Apgujeong" + }, + "note": { + "ko": "강변 산책로입니다. 저녁에 걷기 좋습니다.", + "en": "Riverside walk, good in the evening." + }, + "mapQuery": "압구정 한강공원", + "verify": true + }, + { + "id": "seongsu", + "name": { + "ko": "성수동 카페·팝업", + "en": "Seongsu cafes and pop-ups" + }, + "category": "kpop", + "minLevel": 3, + "distanceKm": 3.5, + "indoor": false, + "area": { + "ko": "성수동", + "en": "Seongsu" + }, + "note": { + "ko": "브랜드 팝업과 카페가 모인 동네입니다. 주말은 인파가 많습니다.", + "en": "Brand pop-ups and cafes. Crowded on weekends." + }, + "mapQuery": "성수동 팝업", + "verify": true + }, + { + "id": "kakao-gangnam", + "name": { + "ko": "카카오프렌즈 강남 플래그십", + "en": "Kakao Friends Gangnam Flagship" + }, + "category": "kpop", + "minLevel": 2, + "distanceKm": 2.6, + "indoor": true, + "area": { + "ko": "강남역", + "en": "Gangnam Station" + }, + "note": { + "ko": "캐릭터 굿즈 매장입니다. 택시로 10분.", + "en": "Character merchandise store, 10 minutes by taxi." + }, + "mapQuery": "카카오프렌즈 강남플래그십스토어", + "verify": true + }, + { + "id": "lotte-tower", + "name": { + "ko": "롯데월드타워·서울스카이", + "en": "Lotte World Tower and Seoul Sky" + }, + "category": "sightseeing", + "minLevel": 3, + "distanceKm": 6, + "indoor": true, + "area": { + "ko": "잠실", + "en": "Jamsil" + }, + "note": { + "ko": "실내 전망대와 쇼핑몰입니다. 택시로 20분.", + "en": "Indoor observatory and mall. 20 minutes by taxi." + }, + "mapQuery": "롯데월드타워", + "verify": true + }, + { + "id": "gyeongbokgung", + "name": { + "ko": "경복궁·북촌", + "en": "Gyeongbokgung Palace and Bukchon" + }, + "category": "sightseeing", + "minLevel": 3, + "distanceKm": 8, + "indoor": false, + "area": { + "ko": "종로", + "en": "Jongno" + }, + "note": { + "ko": "택시로 30분 이상 걸립니다. 자유 외출 단계에서 가세요.", + "en": "Over 30 minutes by taxi. Save for full-day outings." + }, + "mapQuery": "경복궁", + "verify": true + }, + { + "id": "myeongdong", + "name": { + "ko": "명동", + "en": "Myeongdong" + }, + "category": "shopping", + "minLevel": 3, + "distanceKm": 7, + "indoor": false, + "area": { + "ko": "중구", + "en": "Jung-gu" + }, + "note": { + "ko": "화장품과 길거리 음식이 많습니다. 인파가 많으니 부딪히지 않게 다니세요.", + "en": "Cosmetics and street food. Crowded, so mind bumps." + }, + "mapQuery": "명동", + "verify": true + }, + { + "id": "hongdae", + "name": { + "ko": "홍대", + "en": "Hongdae" + }, + "category": "kpop", + "minLevel": 3, + "distanceKm": 12, + "indoor": false, + "area": { + "ko": "홍대입구", + "en": "Hongik Univ." + }, + "note": { + "ko": "버스킹과 굿즈숍이 있습니다. 왕복 1시간 이상 걸립니다.", + "en": "Busking and merch shops. Over an hour round trip." + }, + "mapQuery": "홍대 걷고싶은거리", + "verify": true + }, + { + "id": "clinic-aftercare", + "name": { + "ko": "오라클피부과 경과 확인", + "en": "Oracle Dermatology follow-up" + }, + "category": "care", + "minLevel": 1, + "distanceKm": 0.05, + "indoor": true, + "area": { + "ko": "병원", + "en": "Clinic" + }, + "note": { + "ko": "경과 확인과 관리는 병원 안내에 따라 예약합니다.", + "en": "Follow-up checks and care, booked per the clinic's guidance." + }, + "mapQuery": "오라클피부과 청담", + "verify": true + }, + { + "id": "hotel-lounge", + "name": { + "ko": "호텔 스파·라운지 (숙소 안)", + "en": "Hotel spa and lounge (at your hotel)" + }, + "category": "care", + "minLevel": 0, + "distanceKm": 0, + "indoor": true, + "area": { + "ko": "숙소", + "en": "Your hotel" + }, + "note": { + "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", + "en": "Skip sauna and massage until your doctor allows. Lounge and room service are fine." + }, + "mapQuery": null, + "verify": true + }, + { + "id": "hotel-andaz", + "name": { + "ko": "안다즈 서울 강남", + "en": "Andaz Seoul Gangnam" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 1.0, + "indoor": true, + "area": { + "ko": "압구정 로데오", + "en": "Apgujeong Rodeo" + }, + "note": { + "ko": "압구정 로데오의 고급 호텔입니다. 병원까지 택시로 5분.", + "en": "Upscale hotel at Apgujeong Rodeo. 5 minutes to the clinic by taxi." + }, + "mapQuery": "안다즈 서울 강남", + "verify": true, + "bookingQuery": "Andaz Seoul Gangnam" + }, + { + "id": "hotel-riviera", + "name": { + "ko": "호텔 리베라 청담", + "en": "Hotel Riviera Cheongdam" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 1.0, + "indoor": true, + "area": { + "ko": "청담동", + "en": "Cheongdam" + }, + "note": { + "ko": "영동대교 남단의 호텔입니다. 병원까지 택시로 5분.", + "en": "Hotel at the south end of Yeongdong Bridge. 5 minutes to the clinic by taxi." + }, + "mapQuery": "호텔 리베라 청담", + "verify": true, + "bookingQuery": "Hotel Riviera Cheongdam Seoul" + }, + { + "id": "hotel-parkhyatt", + "name": { + "ko": "파크 하얏트 서울", + "en": "Park Hyatt Seoul" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 2.0, + "indoor": true, + "area": { + "ko": "삼성역", + "en": "Samseong Station" + }, + "note": { + "ko": "삼성역 앞 고급 호텔입니다. 병원까지 택시로 10분.", + "en": "Luxury hotel at Samseong Station. 10 minutes to the clinic by taxi." + }, + "mapQuery": "파크 하얏트 서울", + "verify": true, + "bookingQuery": "Park Hyatt Seoul" + }, + { + "id": "hotel-intercontinental", + "name": { + "ko": "인터컨티넨탈 서울 코엑스", + "en": "InterContinental Seoul COEX" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 2.0, + "indoor": true, + "area": { + "ko": "삼성동", + "en": "Samseong" + }, + "note": { + "ko": "코엑스와 연결된 호텔입니다. 병원까지 택시로 10분.", + "en": "Connected to COEX. 10 minutes to the clinic by taxi." + }, + "mapQuery": "인터컨티넨탈 서울 코엑스", + "verify": true, + "bookingQuery": "InterContinental Seoul COEX" + }, + { + "id": "hotel-josun", + "name": { + "ko": "조선 팰리스 강남", + "en": "Josun Palace Seoul Gangnam" + }, + "category": "hotel", + "minLevel": 0, + "distanceKm": 2.6, + "indoor": true, + "area": { + "ko": "역삼동", + "en": "Yeoksam" + }, + "note": { + "ko": "역삼동의 고급 호텔입니다. 병원까지 택시로 10분.", + "en": "Luxury hotel in Yeoksam. 10 minutes to the clinic by taxi." + }, + "mapQuery": "조선 팰리스 서울 강남", + "verify": true, + "bookingQuery": "Josun Palace Seoul Gangnam" + } + ] +} diff --git a/templates/supporters-astro/briefs/viewclinic/planner.places.json b/templates/supporters-astro/briefs/viewclinic/planner.places.json new file mode 100644 index 0000000..bbf62d5 --- /dev/null +++ b/templates/supporters-astro/briefs/viewclinic/planner.places.json @@ -0,0 +1,47 @@ +{ + "_comment": "회복기 스케줄러 큐레이션 장소 (설계 v0.2 §13.5 1순위 소스). 기준점은 신논현역(뷰성형외과). distanceKm 는 직선 거리 근사값이고 verify 가 true 인 항목은 출시 전 영업 여부·거리를 확인한다. 링크는 구글 지도 검색과 예약 사이트 검색 결과만 쓴다(지어낸 상세 URL 없음). 축제·행사(날짜 의존)는 한국관광공사 Tour API 연결(P1) 뒤에 추가한다.", + "origin": { "label": { "ko": "신논현역 3번 출구", "en": "Sinnonhyeon Station Exit 3" }, "lat": 37.5045, "lng": 127.0250 }, + "categories": { + "sightseeing": { "ko": "관광", "en": "Sightseeing" }, + "shopping": { "ko": "쇼핑", "en": "Shopping" }, + "food": { "ko": "미식", "en": "Food" }, + "kpop": { "ko": "K-pop·핫플", "en": "K-pop & hotspots" }, + "care": { "ko": "휴식·케어", "en": "Rest & care" }, + "essentials": { "ko": "생활", "en": "Essentials" }, + "hotel": { "ko": "숙소", "en": "Hotels" } + }, + "places": [ + { "id": "pharmacy-sinnonhyeon", "name": { "ko": "신논현역 주변 약국", "en": "Pharmacies near Sinnonhyeon Station" }, "category": "essentials", "minLevel": 1, "distanceKm": 0.2, "indoor": true, "area": { "ko": "신논현", "en": "Sinnonhyeon" }, "note": { "ko": "병원 건물 옆 골목에 약국이 있습니다. 처방약과 냉찜질 팩을 구할 수 있습니다.", "en": "Pharmacies in the alley next to the clinic building. Prescriptions and cold packs." }, "mapQuery": "약국 신논현역", "verify": true }, + { "id": "convenience-sinnonhyeon", "name": { "ko": "편의점 (신논현역 일대)", "en": "Convenience stores (Sinnonhyeon area)" }, "category": "essentials", "minLevel": 1, "distanceKm": 0.1, "indoor": true, "area": { "ko": "신논현", "en": "Sinnonhyeon" }, "note": { "ko": "생수, 죽, 빨대, 얼음을 24시간 살 수 있습니다.", "en": "Water, porridge, straws and ice, 24 hours." }, "mapQuery": "편의점 신논현역", "verify": false }, + { "id": "porridge-chain", "name": { "ko": "죽 전문점 (본죽 등 체인)", "en": "Korean porridge (Bonjuk and similar chains)" }, "category": "food", "minLevel": 1, "dietOk": ["liquid", "soft", "mild", "normal"], "distanceKm": 0.4, "indoor": true, "area": { "ko": "신논현·강남", "en": "Sinnonhyeon / Gangnam" }, "note": { "ko": "유동식 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", "en": "Porridge suitable for the liquid-diet stage, by delivery or takeout." }, "mapQuery": "본죽 신논현역", "verify": true }, + { "id": "smoothie-cafe", "name": { "ko": "스무디·주스 카페 (강남대로)", "en": "Smoothie and juice cafes (Gangnam-daero)" }, "category": "food", "minLevel": 1, "dietOk": ["liquid", "soft", "mild", "normal"], "distanceKm": 0.5, "indoor": true, "area": { "ko": "강남대로", "en": "Gangnam-daero" }, "note": { "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", "en": "Plenty of straw-friendly options. Choose nothing hot." }, "mapQuery": "스무디 카페 신논현역", "verify": true }, + { "id": "seolleongtang", "name": { "ko": "설렁탕·곰탕 (강남 일대)", "en": "Seolleongtang beef bone soup (Gangnam area)" }, "category": "food", "minLevel": 1, "dietOk": ["soft", "mild", "normal"], "distanceKm": 0.6, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다. 밥을 말아 천천히 드세요.", "en": "Broth-based, fine from the soft-food stage. Eat slowly with rice in the soup." }, "mapQuery": "설렁탕 강남역", "verify": true }, + { "id": "sulbing", "name": { "ko": "설빙 (빙수 디저트)", "en": "Sulbing shaved-ice dessert" }, "category": "food", "minLevel": 1, "dietOk": ["soft", "mild", "normal"], "distanceKm": 0.6, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "차갑고 부드러워 부기가 있을 때도 먹기 편합니다.", "en": "Cold and soft, comfortable even with swelling." }, "mapQuery": "설빙 강남", "verify": true }, + { "id": "cafe-garosugil", "name": { "ko": "가로수길 카페", "en": "Garosu-gil cafes" }, "category": "food", "minLevel": 2, "dietOk": ["soft", "mild", "normal"], "distanceKm": 1.2, "indoor": true, "area": { "ko": "신사동 가로수길", "en": "Garosu-gil, Sinsa" }, "note": { "ko": "조용한 카페가 많아 오후에 잠깐 앉아 있기 좋습니다.", "en": "Quiet cafes, good for a short afternoon sit-down." }, "mapQuery": "가로수길 카페", "verify": false }, + { "id": "korean-bbq-gangnam", "name": { "ko": "강남 한식·구이", "en": "Korean BBQ and set meals (Gangnam)" }, "category": "food", "minLevel": 2, "dietOk": ["normal"], "distanceKm": 0.8, "indoor": true, "area": { "ko": "강남", "en": "Gangnam" }, "note": { "ko": "일반식이 가능한 단계부터입니다. 담당 원장이 술을 허용하기 전에는 음료로 대신하세요.", "en": "From the regular-diet stage. Skip alcohol until your surgeon allows it." }, "mapQuery": "한식 맛집 강남역", "verify": false }, + { "id": "garosugil", "name": { "ko": "가로수길", "en": "Garosu-gil" }, "category": "shopping", "minLevel": 2, "distanceKm": 1.2, "indoor": false, "area": { "ko": "신사동", "en": "Sinsa" }, "note": { "ko": "편집숍과 뷰티 매장이 모여 있는 거리입니다. 택시로 5분.", "en": "A street of boutiques and beauty stores. 5 minutes by taxi." }, "mapQuery": "가로수길", "verify": false }, + { "id": "oliveyoung-gangnam", "name": { "ko": "올리브영 강남 타운", "en": "Olive Young Gangnam Town" }, "category": "shopping", "minLevel": 2, "distanceKm": 0.9, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "K-뷰티 대형 매장입니다. 수술 부위에 닿는 화장품은 담당 원장 안내를 따르세요.", "en": "Large K-beauty store. Follow your surgeon's guidance on products near the surgical area." }, "mapQuery": "올리브영 강남타운", "verify": true }, + { "id": "shinsegae-gangnam", "name": { "ko": "신세계백화점 강남점", "en": "Shinsegae Department Store Gangnam" }, "category": "shopping", "minLevel": 2, "distanceKm": 2.4, "indoor": true, "area": { "ko": "고속터미널", "en": "Express Bus Terminal" }, "note": { "ko": "지하 파미에스테이션과 연결됩니다. 실내라 날씨와 상관없이 다닐 수 있습니다.", "en": "Connected to the Famille Station underground mall. Fully indoors." }, "mapQuery": "신세계백화점 강남점", "verify": false }, + { "id": "hyundai-apgujeong", "name": { "ko": "현대백화점 압구정본점", "en": "Hyundai Department Store Apgujeong" }, "category": "shopping", "minLevel": 2, "distanceKm": 2.0, "indoor": true, "area": { "ko": "압구정", "en": "Apgujeong" }, "note": { "ko": "택시로 10분. 배송 서비스를 이용하면 짐을 들지 않아도 됩니다.", "en": "10 minutes by taxi. Use the delivery counter so you carry nothing." }, "mapQuery": "현대백화점 압구정본점", "verify": false }, + { "id": "coex-mall", "name": { "ko": "코엑스몰·별마당도서관", "en": "COEX Mall and Starfield Library" }, "category": "shopping", "minLevel": 2, "distanceKm": 3.4, "indoor": true, "area": { "ko": "삼성동", "en": "Samseong" }, "note": { "ko": "실내 쇼핑몰과 도서관, 아쿠아리움이 한 건물에 있습니다.", "en": "Indoor mall, library and aquarium in one building." }, "mapQuery": "코엑스몰", "verify": false }, + { "id": "apgujeong-rodeo", "name": { "ko": "압구정 로데오·K-Star Road", "en": "Apgujeong Rodeo and K-Star Road" }, "category": "kpop", "minLevel": 2, "distanceKm": 2.6, "indoor": false, "area": { "ko": "압구정", "en": "Apgujeong" }, "note": { "ko": "기획사 건물과 아이돌 조형물이 있는 거리입니다.", "en": "Street of entertainment agencies and idol art figures." }, "mapQuery": "K-Star Road 압구정", "verify": true }, + { "id": "kwangya-seongsu", "name": { "ko": "KWANGYA@SEOUL (성수)", "en": "KWANGYA@SEOUL (Seongsu)" }, "category": "kpop", "minLevel": 3, "distanceKm": 5.5, "indoor": true, "area": { "ko": "성수동", "en": "Seongsu" }, "note": { "ko": "SM 엔터테인먼트 공식 굿즈 매장입니다. 운영 시간을 확인하고 가세요.", "en": "SM Entertainment's official merchandise store. Check hours before visiting." }, "mapQuery": "KWANGYA@SEOUL", "verify": true }, + { "id": "seongsu", "name": { "ko": "성수동 카페·팝업", "en": "Seongsu cafes and pop-ups" }, "category": "kpop", "minLevel": 3, "distanceKm": 5.5, "indoor": false, "area": { "ko": "성수동", "en": "Seongsu" }, "note": { "ko": "브랜드 팝업과 카페가 모인 동네입니다. 주말은 인파가 많습니다.", "en": "Brand pop-ups and cafes. Crowded on weekends." }, "mapQuery": "성수동 팝업", "verify": false }, + { "id": "hongdae", "name": { "ko": "홍대", "en": "Hongdae" }, "category": "kpop", "minLevel": 3, "distanceKm": 11, "indoor": false, "area": { "ko": "홍대입구", "en": "Hongik Univ." }, "note": { "ko": "버스킹과 굿즈숍이 있습니다. 왕복 1시간 이상 걸리니 자유 외출 단계에서 가세요.", "en": "Busking and merch shops. Over an hour round trip, so save it for full-day outings." }, "mapQuery": "홍대 걷고싶은거리", "verify": false }, + { "id": "kakao-friends-gangnam", "name": { "ko": "카카오프렌즈 강남 플래그십", "en": "Kakao Friends Gangnam Flagship" }, "category": "kpop", "minLevel": 2, "distanceKm": 0.9, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "캐릭터 굿즈 매장입니다. 걸어서도 갈 수 있는 거리입니다.", "en": "Character merchandise store, within walking distance." }, "mapQuery": "카카오프렌즈 강남플래그십스토어", "verify": true }, + { "id": "bongeunsa", "name": { "ko": "봉은사", "en": "Bongeunsa Temple" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 3.6, "indoor": false, "area": { "ko": "삼성동", "en": "Samseong" }, "note": { "ko": "코엑스 맞은편의 사찰입니다. 경사가 완만해 천천히 걷기 좋습니다.", "en": "Temple across from COEX. Gentle slopes, good for a slow walk." }, "mapQuery": "봉은사", "verify": false }, + { "id": "seonjeongneung", "name": { "ko": "선정릉", "en": "Seonjeongneung Royal Tombs" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 2.4, "indoor": false, "area": { "ko": "선릉", "en": "Seolleung" }, "note": { "ko": "유네스코 세계유산 왕릉입니다. 숲길이 그늘져서 햇빛을 피하기 좋습니다.", "en": "UNESCO World Heritage royal tombs. Shaded forest paths." }, "mapQuery": "선정릉", "verify": false }, + { "id": "banpo-hangang", "name": { "ko": "반포한강공원·달빛무지개분수", "en": "Banpo Hangang Park and Moonlight Rainbow Fountain" }, "category": "sightseeing", "minLevel": 2, "distanceKm": 2.8, "indoor": false, "area": { "ko": "반포", "en": "Banpo" }, "note": { "ko": "저녁에 분수 공연을 볼 수 있습니다. 운영 기간을 확인하세요.", "en": "Evening fountain show. Check the season schedule." }, "mapQuery": "반포한강공원", "verify": false }, + { "id": "gyeongbokgung", "name": { "ko": "경복궁·북촌", "en": "Gyeongbokgung Palace and Bukchon" }, "category": "sightseeing", "minLevel": 3, "distanceKm": 9, "indoor": false, "area": { "ko": "종로", "en": "Jongno" }, "note": { "ko": "택시로 30분 이상 걸립니다. 걷는 시간이 길어 자유 외출 단계에서 가세요.", "en": "Over 30 minutes by taxi and a lot of walking. Save for full-day outings." }, "mapQuery": "경복궁", "verify": false }, + { "id": "lotte-tower", "name": { "ko": "롯데월드타워·서울스카이", "en": "Lotte World Tower and Seoul Sky" }, "category": "sightseeing", "minLevel": 3, "distanceKm": 8, "indoor": true, "area": { "ko": "잠실", "en": "Jamsil" }, "note": { "ko": "실내 전망대와 쇼핑몰입니다. 택시로 25분.", "en": "Indoor observatory and mall. 25 minutes by taxi." }, "mapQuery": "롯데월드타워", "verify": false }, + { "id": "myeongdong", "name": { "ko": "명동", "en": "Myeongdong" }, "category": "shopping", "minLevel": 3, "distanceKm": 7, "indoor": false, "area": { "ko": "중구", "en": "Jung-gu" }, "note": { "ko": "화장품과 길거리 음식이 많습니다. 인파가 많으니 부딪히지 않게 다니세요.", "en": "Cosmetics and street food. Crowded, so mind bumps." }, "mapQuery": "명동", "verify": false }, + { "id": "clinic-aftercare", "name": { "ko": "뷰성형외과 애프터케어", "en": "View Plastic Surgery Aftercare" }, "category": "care", "minLevel": 1, "distanceKm": 0.05, "indoor": true, "area": { "ko": "병원", "en": "Clinic" }, "note": { "ko": "고주파 관리와 경과 확인은 병원 안내에 따라 예약합니다.", "en": "Radiofrequency care and follow-up checks, booked per the clinic's guidance." }, "mapQuery": "뷰성형외과", "verify": false }, + { "id": "clinic-dental", "name": { "ko": "뷰성형외과 15층 치과", "en": "View Plastic Surgery Dental Clinic (15F)" }, "category": "care", "minLevel": 1, "distanceKm": 0.05, "indoor": true, "area": { "ko": "병원", "en": "Clinic" }, "note": { "ko": "양악·윤곽 협진 치과입니다. 여유 시간에 검진을 받을 수 있는지 상담에서 물어보세요.", "en": "Dental clinic for jaw and contouring cases. Ask at consultation about a check-up during your stay." }, "mapQuery": "뷰성형외과", "verify": false }, + { "id": "hotel-spa-gangnam", "name": { "ko": "호텔 스파·라운지 (숙소 안)", "en": "Hotel spa and lounge (at your hotel)" }, "category": "care", "minLevel": 0, "distanceKm": 0, "indoor": true, "area": { "ko": "숙소", "en": "Your hotel" }, "note": { "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", "en": "Skip sauna and massage until your surgeon allows. Lounge and room service are fine." }, "mapQuery": null, "verify": false }, + { "id": "hotel-cappuccino", "name": { "ko": "호텔 카푸치노", "en": "Hotel Cappuccino" }, "category": "hotel", "minLevel": 0, "distanceKm": 0.5, "indoor": true, "area": { "ko": "논현동 봉은사로", "en": "Nonhyeon, Bongeunsa-ro" }, "note": { "ko": "병원과 같은 봉은사로에 있어 걸어서 다닐 수 있습니다.", "en": "On the same road as the clinic, within walking distance." }, "mapQuery": "호텔 카푸치노 논현", "bookingQuery": "Hotel Cappuccino Seoul", "verify": true }, + { "id": "novotel-gangnam", "name": { "ko": "노보텔 앰배서더 강남", "en": "Novotel Ambassador Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.0, "indoor": true, "area": { "ko": "역삼동", "en": "Yeoksam" }, "note": { "ko": "강남역 근처 대형 호텔입니다. 룸서비스와 24시간 프런트가 있습니다.", "en": "Large hotel near Gangnam Station with room service and a 24-hour front desk." }, "mapQuery": "노보텔 앰배서더 강남", "bookingQuery": "Novotel Ambassador Seoul Gangnam", "verify": true }, + { "id": "l7-gangnam", "name": { "ko": "L7 강남 바이 롯데", "en": "L7 Gangnam by Lotte" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.4, "indoor": true, "area": { "ko": "강남역", "en": "Gangnam Station" }, "note": { "ko": "강남역 인근이며 택시로 5분입니다.", "en": "Near Gangnam Station, 5 minutes by taxi." }, "mapQuery": "L7 강남", "bookingQuery": "L7 Gangnam by Lotte", "verify": true }, + { "id": "andaz-gangnam", "name": { "ko": "안다즈 서울 강남", "en": "Andaz Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 2.6, "indoor": true, "area": { "ko": "압구정 로데오", "en": "Apgujeong Rodeo" }, "note": { "ko": "압구정 로데오에 있는 고급 호텔입니다. 병원까지 택시로 10분.", "en": "Upscale hotel at Apgujeong Rodeo. 10 minutes to the clinic by taxi." }, "mapQuery": "안다즈 서울 강남", "bookingQuery": "Andaz Seoul Gangnam", "verify": true }, + { "id": "josun-palace", "name": { "ko": "조선 팰리스 강남", "en": "Josun Palace Seoul Gangnam" }, "category": "hotel", "minLevel": 0, "distanceKm": 1.8, "indoor": true, "area": { "ko": "역삼동", "en": "Yeoksam" }, "note": { "ko": "역삼동의 고급 호텔입니다. 병원까지 택시로 10분.", "en": "Luxury hotel in Yeoksam. 10 minutes to the clinic by taxi." }, "mapQuery": "조선 팰리스 서울 강남", "bookingQuery": "Josun Palace Seoul Gangnam", "verify": true } + ] +} diff --git a/templates/supporters-astro/scripts/build_planner_data.mjs b/templates/supporters-astro/scripts/build_planner_data.mjs new file mode 100644 index 0000000..b7efae5 --- /dev/null +++ b/templates/supporters-astro/scripts/build_planner_data.mjs @@ -0,0 +1,83 @@ +// 회복 일정 플래너 병원별 데이터 생성 (워커 planner 단계). 설계 v0.2 §13. +// node scripts/build_planner_data.mjs --clinic --site [--industry derm|plastic] +// +// 만드는 것 +// /src/data/procedures.json 업종별 기본 규칙표(scripts/template/planner/procedures..json)에 +// 병원 시술 페이지 원문(recoveryNotes.json)의 관리 문장을 matchKeywords 로 시술에 붙인다. +// 원문 문장은 status clinic 으로 출처(URL)와 함께 들어가고, 나머지 값은 provisional(병원 확인 전) 그대로다. +// /src/data/places.json briefs//planner.places.json 이 있으면 그것(병원별 큐레이션), 없으면 범용 기본표 +// (scripts/template/planner/places.base.json)에 병원 이름·지역을 치환하고 origin 을 관광공사 수집 기준 좌표로 채운다. +// 원칙: 없는 값을 채우지 않는다. 의학 수치는 병원 원문 문장만 clinic 이고, 그 밖은 화면에 '병원 확인 전' 배지가 붙는다. +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const SUP = resolve(fileURLToPath(new URL('../', import.meta.url))); +const args = process.argv.slice(2); +const opt = (k, d) => { const i = args.indexOf(`--${k}`); return i >= 0 && args[i + 1] && !args[i + 1].startsWith('--') ? args[i + 1] : d; }; +const clinic = opt('clinic'); const SITE = opt('site'); +if (!clinic || !SITE) { console.error('사용법: --clinic --site [--industry derm|plastic]'); process.exit(2); } +const DATA = join(SITE, 'src', 'data'); +const readJson = (p) => JSON.parse(readFileSync(p, 'utf8')); +const writeJson = (p, o) => { mkdirSync(join(p, '..'), { recursive: true }); writeFileSync(p, JSON.stringify(o, null, 2) + '\n'); }; + +const fact = existsSync(join(DATA, 'factSheet.json')) ? readJson(join(DATA, 'factSheet.json')) : {}; +const pinPath = join(SUP, 'briefs', clinic, 'clinic.json'); +const pin = existsSync(pinPath) ? readJson(pinPath) : {}; + +// 업종: --industry > briefs/clinic.json industry > 팩트 시트 kind(피부과) > plastic +const industry = (() => { + const forced = opt('industry') || pin.industry; + if (forced && ['derm', 'plastic'].includes(forced)) return forced; + return /피부/.test(String(fact.kind ?? '') + String(pin.factSheet?.kind ?? '')) ? 'derm' : 'plastic'; +})(); +const basePath = join(SUP, 'scripts', 'template', 'planner', `procedures.${industry}.json`); +const base = readJson(basePath); + +// ---------- 규칙표: 병원 원문 문장 붙이기 ---------- +const notesPath = join(DATA, 'recoveryNotes.json'); +const notes = existsSync(notesPath) ? readJson(notesPath) : { items: [] }; +const shortName = fact.shortName || fact.name || clinic; +let attached = 0, unmatched = []; +for (const it of notes.items ?? []) { + const target = base.procedures.find((p) => p.matchKeywords && new RegExp(p.matchKeywords).test(it.procedure)); + if (!target) { unmatched.push(it.procedure); continue; } + const doc = (it.url.match(/doc=(\d+)/) || [])[1] ?? it.url.replace(/[^a-z0-9]+/gi, '-').slice(-24); + const srcId = `note-${doc}`; + if (!base.clinicSources.some((s) => s.id === srcId)) { + base.clinicSources.push({ id: srcId, label: { ko: `${shortName} 홈페이지 · ${it.procedure} 시술 안내`, en: `${shortName} website · ${it.procedureEn || it.procedure}` }, url: it.url, accessed: it.fetchedAt || notes.generatedAt || '' }); + } + (it.ko ?? []).forEach((ko, i) => { + const en = (it.en ?? [])[i] || ko; // 번역 실패 문장은 한글 원문 그대로 (워커 recovery 단계와 같은 규칙) + const cid = `${srcId}-${i}`; + base.constraints[cid] = { ko: ko.trim(), en: en.trim() }; + if (!target.constraints.includes(cid)) target.constraints.unshift(cid); // 병원 원문이 잠정 안내보다 먼저 보이게 + attached++; + }); + if (!target.sources.includes(srcId)) target.sources.push(srcId); +} +for (const p of base.procedures) delete p.matchKeywords; +base._comment = `${shortName} 회복 일정 플래너 규칙표 (${industry === 'derm' ? '피부과' : '성형외과'} 기본표 + 병원 시술 페이지 원문 ${attached}문장). clinic = 병원 원문, provisional = 병원 확인 전 잠정값(화면 배지). 생성 ${new Date().toISOString().slice(0, 10)}, 워커 planner 단계.`; +writeJson(join(DATA, 'procedures.json'), base); + +// ---------- 장소: 병원별 큐레이션 또는 범용 기본표 ---------- +const curated = join(SUP, 'briefs', clinic, 'planner.places.json'); +let placesSummary; +if (existsSync(curated)) { + writeJson(join(DATA, 'places.json'), readJson(curated)); + placesSummary = `큐레이션 ${readJson(curated).places.length}곳 (briefs/${clinic}/planner.places.json)`; +} else { + const tpl = readJson(join(SUP, 'scripts', 'template', 'planner', 'places.base.json')); + const tourPath = join(DATA, 'medicalTourismKo.json'); + const origin = existsSync(tourPath) ? (readJson(tourPath).meta?.origin ?? {}) : {}; + const areaKo = fact.areaLabel || fact.address?.locality || shortName; + const areaEn = fact.areaLabelEn || fact.address?.localityEn || (fact.shortNameEn || shortName); + const nameEn = fact.shortNameEn || fact.nameEn || shortName; + const sub = (s) => String(s).replaceAll('{CLINIC_KO}', shortName).replaceAll('{CLINIC_EN}', nameEn).replaceAll('{AREA_KO}', areaKo).replaceAll('{AREA_EN}', areaEn); + const out = JSON.parse(sub(JSON.stringify(tpl))); + out.origin = { label: { ko: `${shortName}${fact.address?.street ? ` (${fact.address.street})` : ''}`, en: nameEn }, lat: origin.lat ?? 0, lng: origin.lng ?? 0 }; + out._comment = `${shortName} 범용 큐레이션(기본표 치환). 병원별 큐레이션은 briefs/${clinic}/planner.places.json 으로 준다. 숙소·관광지·행사는 관광공사 데이터(medicalTourism*.json)가 맡는다.`; + writeJson(join(DATA, 'places.json'), out); + placesSummary = `범용 기본표 ${out.places.length}곳 (origin ${origin.lat ? `${origin.lat}, ${origin.lng}` : '없음'})`; +} +console.log(`planner: 업종 ${industry} · 시술 ${base.procedures.length}종 · 병원 원문 ${attached}문장 붙임${unmatched.length ? ` · 매칭 안 된 시술 ${unmatched.length}(${unmatched.slice(0, 4).join(', ')})` : ''} · ${placesSummary}`); diff --git a/templates/supporters-astro/scripts/check.mjs b/templates/supporters-astro/scripts/check.mjs index 477fb31..df7fb2c 100644 --- a/templates/supporters-astro/scripts/check.mjs +++ b/templates/supporters-astro/scripts/check.mjs @@ -9,6 +9,7 @@ import { readdirSync, readFileSync, statSync, existsSync, writeFileSync } from ' import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; import * as R from './gate/rules.mjs'; +import { parse as parseHtml } from 'node-html-parser'; const here = (p) => fileURLToPath(new URL(p, import.meta.url)); const DIST = here('../dist/'); @@ -35,6 +36,12 @@ function walk(dir, out = []) { return out; } +function withoutRecoveryQuote(html) { + const root = parseHtml(html); + root.querySelectorAll('#recovery-quote').forEach((el) => el.remove()); + return root.toString(); +} + const findings = []; // { where, level, code, msg } const add = (where, list) => list.forEach((x) => findings.push({ where, ...x })); @@ -47,6 +54,8 @@ const layoutNow = {}; for (const f of files) { const html = readFileSync(f, 'utf8'); const rel = f.replace(DIST, '/'); + // astro.config 의 redirects 가 만든 meta refresh 페이지(/stay → /recovery). 본문이 없으니 검사하지 않는다. + if (// 에 구조화해 저장한다. 요약 도구를 쓰지 않는다(§3-10). 없는 것은 없다고 남긴다. // // node scripts/collect_evidence.mjs --clinic viewclinic --url https://www.viewclinic.com [--out ../evidence] [--max 80] [--delay 400] +// [--extra-url http://group-site.example/branches] 같은 수집기로 받을 추가 시작 페이지(쉼표 구분·반복 가능. 다른 호스트 허용) // // 산출물 // evidence//index.json 페이지 목록(유형·글자 수·표·이미지·플래그) // evidence//pages/.json 페이지별 원문(제목·헤딩·섹션·표·목록·이미지·링크) // evidence//doctors.json 의료진 페이지에서 읽은 이름·직함·약력(이미지 글자면 textInImages=true) -// evidence//facts.draft.json 푸터·오시는길에서 정규식으로 뽑은 NAP 후보 (사람 확인 전 "확인 대기") +// evidence//facts.draft.json 푸터·오시는길에서 정규식으로 뽑은 NAP 후보 (사람 확인 전 "확인 대기"). 지점 목록 페이지가 있으면 branches 배열 // evidence//home_text.txt 전 페이지 본문 공백 제거본. 발행 게이트의 40자 연속 일치 검사 기준 +// +// 사이트 편차 대응(2026-09-10 오라클피부과 실측으로 추가) +// 1. 루트가 프레임셋·meta refresh·JS location.href 껍데기인 사이트: 리다이렉트를 최대 3단계 따라가 실제 홈을 시작 URL로 쓴다. 상대 URL은 갱신된 홈 기준으로 푼다. +// 2. EUC-KR 사이트: HTTP Content-Type → meta charset → utf-8 순으로 감지해 TextDecoder 로 디코드한다. +// 3. index.php?doc=N 처럼 쿼리가 페이지를 구분하는 사이트: 추적용 파라미터만 빼고 쿼리를 보존한다. slug 에도 쿼리를 넣는다. +// 4. 페이지 유형이 URL 경로에 없는 사이트: 앵커 텍스트·제목·h1 의 키워드(시술 어휘 포함)로 분류한다. import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs'; import { join } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -17,52 +24,102 @@ import { parse } from 'node-html-parser'; // ---------- 인자 ---------- const arg = (k, d) => { const i = process.argv.indexOf(k); return i > -1 ? process.argv[i + 1] : d; }; +const args = (k) => process.argv.flatMap((x, i) => (x === k && process.argv[i + 1] ? process.argv[i + 1].split(',') : [])).map((s) => s.trim()).filter(Boolean); const CLINIC = arg('--clinic'); const START = arg('--url'); -if (!CLINIC || !START) { console.error('사용법: --clinic --url '); process.exit(2); } +if (!CLINIC || !START) { console.error('사용법: --clinic --url [--extra-url ]'); process.exit(2); } const OUT = join(arg('--out', fileURLToPath(new URL('../../evidence/', import.meta.url))), CLINIC); const MAX = Number(arg('--max', 250)); const DELAY = Number(arg('--delay', 400)); +const EXTRA = args('--extra-url'); const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0 Safari/537.36 INFINITH-supporters-evidence/1.0 (+mailto:o2oteam@o2o.kr)'; // 일부 병원(원진)은 비브라우저 UA 를 403 으로 막는다. 브라우저 UA + 식별 문자열 const today = new Date().toISOString().slice(0, 10); // ---------- 페이지 유형 ---------- -// 순서가 우선순위. URL 경로와 앵커 텍스트 둘 다 본다. +// 시술 어휘. URL 경로에 유형이 없는 사이트(index.php?doc=N)는 앵커·제목이 시술명 그대로라서 이 사전으로 잡는다. +// 성형외과·피부과 공통. 병원 상호에 흔한 "성형외과"·"피부과" 자체는 넣지 않는다(제목 접미어 오분류 방지). +const PROCEDURE_VOCAB = /토닝|기미|색소|잡티|주근깨|검버섯|리프팅|울쎄라|써마지|인모드|슈링크|리쥬란|스킨부스터|물광|보톡스|톡신|필러|여드름|흉터|모공|제모|다한증|홍조|주름|탈모|모발이식|비만|지방분해|지방흡입|스케일링|필링|미백|레이저|사마귀|무좀|피부염|아토피|점\s*제거|문신|타투|눈성형|코성형|쌍꺼풀|매몰|절개|트임|눈매교정|안검|눈재수술|코재수술|콧볼|매부리|양악|윤곽|사각턱|광대|무턱|턱끝|가슴확대|가슴축소|가슴재수술|힙업|리프트|줄기세포|재생|주사|시술|수술|성형술/; +// 순서가 우선순위. URL 경로와 앵커 텍스트 둘 다 본다. branches 는 지점 목록·지점별 페이지(네트워크 병원). const TYPES = [ ['precautions', /precaution|caution|주의사항|주의\s*사항/i], ['aftercare', /after-?care|사후관리|애프터/i], ['checkup', /examination|check-?up|검진/i], ['safety', /\bsafe|안전/i], - ['doctor', /\bdoctors?\b|의료진|\bstaff\b|physician/i], + ['doctor', /\bdoctors?\b|의료진|\bstaff\b|physician|원장\s*(?:소개|단)/i], + ['branches', /\bbranch|\bnetwork\b|지점|네트워크\s*병원|(?:^|\s)[가-힣A-Za-z0-9]{1,10}점$/i], ['direction', /\bdirections?\d*\b|\blocation\b|오시는\s*길|찾아오|\bcontact\b|\bway-?to/i], - ['facilities', /facilit|\btour\b|둘러보|시설/i], - ['about', /\babout\b|\bintro|병원\s*소개|특별함|specialt|\bgreeting/i], + ['facilities', /facilit|\btour\b|둘러보|시설|병원\s*전경/i], + ['about', /\babout\b|\bintro|병원\s*소개|특별함|specialt|\bgreeting|인사말|소개$/i], ['reservation', /\breserv|\bcounsel|예약|상담/i], ['pricing', /\bprice|\bcost\b|비급여|수가|비용/i], + ['procedure', PROCEDURE_VOCAB], ]; -const SKIP = /\/(board|news|event|community|review|gallery|model|login|register|mypage|cart|feed|tag|category|author|wp-|xmlrpc|\?s=)|before-?and-?after|before-?after|\/(before|after)\/|\.(jpg|jpeg|png|gif|svg|pdf|css|js|ico|zip)(\?|$)|#|mailto:|tel:|javascript:/i; +const BRANCH_CAP = 20; // 지점별 페이지는 20개까지. 네트워크 병원은 지점이 수십 개라 MAX 를 다 먹는다 +const SKIP = /\/(board|news|event|community|review|gallery|model|login|register|mypage|cart|feed|tag|category|author|wp-|xmlrpc)|[?&](s|q|search|lang|language)=|\/(en|eng|zh|cn|chn|jp|jpn|ja|ru|th|vi|vn|mn|id)(\/|$)|before-?and-?after|before-?after|\/(before|after)\/|com\.php\?code=|photo\.php|\/mem_|\/join|\/logout|\/claim|\/clause|\/privacy|\/policy|\/recruit|\/real\.php|_movi|\/alliance|\.(jpg|jpeg|png|gif|svg|webp|pdf|css|js|ico|zip|ai|eps|psd|doc|docx|hwp|xls|xlsx|ppt|pptx|mp4|mov|avi)(\?|$)|#|mailto:|tel:|javascript:/i; const PROCEDURE_HINT = /수술\s*시간|마취|회복|실밥|입원|붓기|절개|시술\s*시간|수술\s*방법/; +// 지점명 후보에서 뺄 일반 명사("장점"·"단점" 같은 X점) +const NOT_BRANCH = new Set(['장점', '단점', '관점', '시점', '초점', '중점', '종점', '요점', '강점', '득점', '이점', '문제점', '차이점', '공통점', '출발점', '기준점', '지점', '거점', '정점', '원점', '점점', '접점', '분기점', '전환점', '만점', '평점', '채점', '감점', '흑점', '반점', '얼룩점']); // 경로를 먼저 보고, 경로로 못 정하면 짧은 앵커 텍스트(메뉴 항목)만 본다. 메뉴 전체가 붙은 긴 앵커는 무시. function classify(path, anchor = '') { const segs = path.split('/').filter(Boolean).map((x) => x.replace(/[-_]/g, ' ')); - for (const [t, re] of TYPES) if (segs.some((x) => re.test(x)) || re.test(path)) return t; + // 경로에는 시술 어휘를 적용하지 않는다(경로 "/surgery/" 같은 일반어가 전부 procedure 로 잡히는 것을 막는다) + for (const [t, re] of TYPES) if (t !== 'procedure' && (segs.some((x) => re.test(x)) || re.test(path))) return t; if (anchor && anchor.length <= 30) for (const [t, re] of TYPES) if (re.test(anchor)) return t; return 'candidate'; } +// breadcrumb 상위 항목 전용 어휘. "Home > 메디칼스킨케어 > 여드름/모공관리 > 알라딘필" 처럼 제목이 제품명이어도 상위 분류로 시술 페이지임을 안다 +const CRUMB_PROCEDURE = /피부과|성형외과|피부\s*관리|스킨\s*케어|시술|수술|클리닉|치료|안티에이징|에스테틱|메디칼|메디컬/; +// 본문 첫 항목들에서 breadcrumb("Home > A > B > 제목") 을 찾아 상위 항목 배열로 +function breadcrumbs(items) { + for (const it of items.slice(0, 6)) { + const m = (it.text ?? '').match(/^(?:home|홈|메인)\s*[>›»]\s*(.+)$/i); + if (m) return m[1].split(/\s*[>›»]\s*/).map((x) => x.trim()).filter(Boolean); + } + return []; +} +// 제목·h1 → breadcrumb 상위 항목 순으로 분류. 경로·앵커로 못 정한 페이지(candidate)에만 쓴다. 사이트 공통 접미어("| 뷰성형외과")는 잘라낸다. +function classifyByTitle(title = '', h1 = '', crumbs = []) { + const head = [h1, title.split(/\s*[|::]\s*|\s+-\s+/)[0]].map((s) => (s ?? '').trim()).filter((s) => s && s.length <= 40); + for (const s of head) for (const [t, re] of TYPES) if (re.test(s)) return t; + for (const c of crumbs.slice(0, -1)) { for (const [t, re] of TYPES) if (re.test(c)) return t; if (CRUMB_PROCEDURE.test(c)) return 'procedure'; } + return null; +} +// 본문에서 지점명 후보("청담점"·"부산서면점"). 8개 이상 나오면 지점 목록 페이지로 본다 +function branchNames(text) { + const names = new Set(); + for (const m of text.matchAll(/(?:^|[\s>|·,(\-])((?:[가-힣]{1,4}\s)?[가-힣A-Za-z0-9]{1,10}점)(?=$|[\s<|·,)\-:])/g)) { const n = m[1].replace(/^(서울|경기|인천|부산|대구|대전|광주|울산|세종)\s/, ''); if (!NOT_BRANCH.has(n) && !/^\d+점$/.test(n)) names.add(n); } + return [...names]; +} // ---------- fetch ---------- const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +// charset: HTTP 헤더 → 첫 4KB 의 meta charset → utf-8. EUC-KR 계열 별칭은 모두 euc-kr 로 (Node 22 TextDecoder 가 지원) +function detectCharset(contentType, bytes) { + const fromHeader = /charset=["']?\s*([\w-]+)/i.exec(contentType ?? '')?.[1]; + if (fromHeader) return fromHeader; + const head = new TextDecoder('latin1').decode(bytes.subarray(0, 4096)); + return /]+charset=["']?\s*([\w-]+)/i.exec(head)?.[1] ?? 'utf-8'; +} +function decodeBody(bytes, charset) { + let label = charset.toLowerCase().replace(/^x-/, ''); + if (/^(euc-?kr|ks_?c_?5601(?:-1987|-1992)?|ksc5601|cp949|windows-949|uhc)$/.test(label)) label = 'euc-kr'; + try { return new TextDecoder(label).decode(bytes); } catch { return new TextDecoder('utf-8').decode(bytes); } +} async function fetchText(url, tries = 2) { for (let i = 0; i <= tries; i++) { try { const res = await fetch(url, { headers: { 'user-agent': UA, accept: 'text/html,application/xhtml+xml,*/*' }, redirect: 'follow', signal: AbortSignal.timeout(25000) }); - const body = await res.text(); - return { status: res.status, finalUrl: res.url, body, contentType: res.headers.get('content-type') ?? '' }; + const bytes = new Uint8Array(await res.arrayBuffer()); + const contentType = res.headers.get('content-type') ?? ''; + const charset = detectCharset(contentType, bytes); + return { status: res.status, finalUrl: res.url, body: decodeBody(bytes, charset), contentType, charset }; } catch (e) { if (i === tries) return { status: 0, finalUrl: url, body: '', error: e.message }; await sleep(800 * (i + 1)); } } } -// ---------- robots ---------- +// ---------- robots (origin 별 캐시) ---------- +const robotsCache = new Map(); async function loadRobots(origin) { + if (robotsCache.has(origin)) return robotsCache.get(origin); const r = await fetchText(`${origin}/robots.txt`, 0); const dis = []; if (r.status === 200) { @@ -73,30 +130,56 @@ async function loadRobots(origin) { else if (star && /^disallow:/i.test(l)) { const p = l.replace(/^disallow:\s*/i, '').trim(); if (p) dis.push(p); } } } - return { raw: r.body, disallow: dis, allowed: (path) => !dis.some((d) => path.startsWith(d)) }; + const out = { raw: r.body, disallow: dis, allowed: (path) => !dis.some((d) => path.startsWith(d)) }; + robotsCache.set(origin, out); + return out; } // ---------- 링크 정규화 ---------- +const TRACKING = /^(utm_|fbclid|gclid|ref$|PHPSESSID|sid$|_ga)/i; function normalize(href, base) { try { const u = new URL(href, base); if (!/^https?:$/.test(u.protocol)) return null; - u.hash = ''; u.search = ''; + u.hash = ''; + // 쿼리는 보존한다(index.php?doc=14 처럼 쿼리가 곧 페이지인 사이트). 추적 파라미터만 빼고 키 순으로 정렬해 같은 페이지가 한 키가 되게 한다 + const keep = [...u.searchParams.entries()].filter(([k]) => !TRACKING.test(k)).sort(([a], [b]) => a.localeCompare(b)); + u.search = ''; for (const [k, v] of keep) u.searchParams.append(k, v); // 슬래시를 강제로 붙이지 않는다. 뷰성형외과(WordPress)는 /x → /x/ 로 301 하지만, 원진(k-wonjin.co.kr)은 /x/ 가 404 다. // 키는 슬래시 없는 형태로 통일하고(루트 제외), 404 면 collect() 에서 반대 형태를 한 번 더 시도한다. let s = u.toString(); - if (u.pathname !== '/' && s.endsWith('/')) s = s.slice(0, -1); + if (u.pathname !== '/' && !u.search && s.endsWith('/')) s = s.slice(0, -1); return s; } catch { return null; } } -const sameHost = (u, origin) => new URL(u).host.replace(/^www\./, '') === new URL(origin).host.replace(/^www\./, ''); +const hostOf = (u) => new URL(u).host.replace(/^www\./, ''); +const HOSTS = new Set([hostOf(START)]); // 허용 호스트: 시작 URL + 리다이렉트로 옮겨간 홈 + --extra-url +const sameHost = (u) => { try { return HOSTS.has(hostOf(u)); } catch { return false; } }; + +// ---------- 시작 URL 해석(프레임셋·meta refresh·JS 리다이렉트) ---------- +// 껍데기 페이지(프레임셋이 있거나 본문이 200자 미만)에서만 리다이렉트 대상을 찾는다. 일반 페이지의 onclick 핸들러 속 location.href 는 대상이 아니다. +function redirectTargets(html, base) { + const out = []; + const add = (h) => { const u = h && normalize(h.trim(), base); if (u && u !== normalize(base, base)) out.push(u); }; + for (const m of html.matchAll(/]+http-equiv=["']?refresh["']?[^>]*content=["']?\s*\d+\s*;\s*url=\s*([^"'>\s]+)/gi)) add(m[1]); + for (const m of html.matchAll(/]*\ssrc=["']?([^"'>\s]+)/gi)) add(m[1]); + for (const s of html.matchAll(/]*>([\s\S]*?)<\/script>/gi)) { + // 주석을 지우고, 중괄호 깊이 0(함수·블록 바깥)의 문장만 남긴다 + const src = s[1].replace(/\/\*[\s\S]*?\*\//g, '').replace(/(^|[^:'"\\])\/\/[^\n]*/g, '$1'); + let depth = 0, top = ''; + for (const ch of src) { if (ch === '{') depth++; else if (ch === '}') depth = Math.max(0, depth - 1); else if (depth === 0) top += ch; } + for (const m of top.matchAll(/(?:window\.|document\.|top\.|self\.|parent\.)?location(?:\.href)?\s*=\s*["']([^"']+)["']|location\.replace\(\s*["']([^"']+)["']/g)) add(m[1] ?? m[2]); + } + return [...new Set(out)]; +} +const isShell = (html, ex) => / i.text ?? '').join(' ')).length < 200; // ---------- 본문 추출 ---------- const MAIN_SELECTORS = ['main', '#ajax-content-wrap', '#main-content', '#content', '#contents', '#container', '.container-wrap', '#sub_content', '.sub_content', '.sub-content', '#subContent', 'article', '#wrap', '#wrapper']; const NOISE_TAGS = 'script,style,noscript,iframe,form,svg,template,video,audio,object,embed'; const NOISE_SELECTORS = 'header,footer,nav,[id*="menu"],[class*="menu"],[id*="popup"],[class*="popup"],[id*="modal"],[class*="modal"],[class*="share"],[class*="quick"],[class*="floating"],[class*="breadcrumb"],[class*="cookie"],[class*="sns"],[id*="search"],[class*="widget"],[class*="wpcf7"],[class*="eform"],[class*="offcanvas"],[class*="gnb"],[class*="lnb"],[id*="gnb"],[id*="lnb"],[class*="topbar"],[class*="top-bar"]'; const BLOCK = new Set(['div', 'section', 'article', 'main', 'aside', 'ul', 'ol', 'li', 'table', 'thead', 'tbody', 'tr', 'td', 'th', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'figure', 'figcaption', 'blockquote', 'dl', 'dt', 'dd', 'pre', 'address']); -const clean = (s) => s.replace(/ /g, ' ').replace(/[ \t\r\f\v]+/g, ' ').replace(/\s*\n\s*/g, ' ').trim(); +const clean = (s) => s.replace(/ /g, ' ').replace(/[ \t\r\f\v]+/g, ' ').replace(/\s*\n\s*/g, ' ').trim(); function hasBlockDescendant(el) { return el.querySelectorAll('*').some((c) => BLOCK.has(c.rawTagName?.toLowerCase())); @@ -108,7 +191,9 @@ function walk(el, items) { if (!tag) return; if (/^h[1-6]$/.test(tag)) { const t = clean(el.text); if (t) items.push({ kind: 'h', level: Number(tag[1]), text: t }); return; } if (tag === 'table') { - const rows = el.querySelectorAll('tr').map((tr) => tr.querySelectorAll('td,th').map((c) => clean(c.text))).filter((r) => r.some(Boolean)); + // 중첩 레이아웃 표는 같은 글이 행마다 되풀이된다. 인접한 같은 셀과 같은 행은 한 번만 + const seen = new Set(); + const rows = el.querySelectorAll('tr').map((tr) => tr.querySelectorAll('td,th').map((c) => clean(c.text)).filter((c, i, a) => i === 0 || c !== a[i - 1])).filter((r) => r.some(Boolean)).filter((r) => { const k = r.join('|'); if (seen.has(k)) return false; seen.add(k); return true; }); if (rows.length) items.push({ kind: 'table', rows }); return; } @@ -138,8 +223,12 @@ function extract(html, url) { const items = []; walk(main, items); const images = main.querySelectorAll('img').map((i) => ({ src: normalize(i.getAttribute('data-src') || i.getAttribute('src') || '', url), alt: clean(i.getAttribute('alt') ?? '') })).filter((i) => i.src && !/\.(svg|gif)$/i.test(i.src) && !/icon|logo|btn|button|arrow|blank|spacer|sns|share|1x1/i.test(i.src)); const links = [...new Set(main.querySelectorAll('a[href]').map((a) => normalize(a.getAttribute('href'), url)).filter(Boolean))]; - return { title, metaDesc, mainSelector, items, images, links, anchors }; + // 가 아니라 onclick 의 location.href·window.open 으로만 이어지는 페이지(지점 카드 등). 앵커 텍스트가 없으니 후순위 + const jsLinks = [...new Set([...html.matchAll(/(?:location(?:\.href)?\s*=|location\.replace\(|window\.open\()\s*["']([^"'\s]+)["']/g)].map((m) => normalize(m[1], url)).filter(Boolean))]; + return { title, metaDesc, mainSelector, items, images, links, anchors, jsLinks }; } +// 사실 후보용 전문(메뉴·푸터 포함). body 가 없는 옛 HTML 은 root 전체 +const fullText = (html) => { const r = parse(html); return clean((r.querySelector('body') ?? r).text ?? '').slice(0, 200000); }; /** 항목을 헤딩 기준 섹션으로 묶는다 */ function sectionize(items) { @@ -155,17 +244,39 @@ function sectionize(items) { } // ---------- 사실 후보(정규식) ---------- +const REGION = '(?:서울|경기|인천|부산|대구|대전|광주|울산|세종|강원|충북|충남|충청|전북|전남|전라|경북|경남|경상|제주)'; +const PHONE = '(?:0\\d{1,2}[-.)\\s]\\d{3,4}[-.\\s]\\d{4}|1[5-9]\\d{2}[-.\\s]\\d{4})'; // 02-544-2777 · 02)352-2184 · 1577-1175(대표번호) +// 주소 시작: 지역명 뒤에 행정단위 접미어(특별시·광역시·도 등)나 공백이 와야 한다. "서울대입구점서초점…" 처럼 띄어쓰기 없는 지점명 나열을 주소로 잡지 않게 +const REGION_START = `${REGION}(?:(?:특별시|광역시|특별자치시|특별자치도|남도|북도|도|시)\\s*|\\s+)(?:[가-힣]{1,6}(?:시|구|군|읍|면)\\s)?`; +// 주소: 지역명 ~ (빌딩|층|호|번지|로 N|길 N) 까지 짧게 잡고, 뒤에 "한일빌딩 4층" 같은 건물·층 토큰이 이어지면 붙인다 +// 확장 토큰은 "한일빌딩"·"4층"·"304호"·"B동" 꼴만. "지점연결번호" 처럼 호로 끝나는 일반어는 붙지 않게 한다 +const ADDR_EXT = '(?:,?\\s(?:\\d+[-\\d]*호|\\d{1,3}(?:,\\d{1,3})?층|[A-Za-z0-9]{1,3}동|[A-Za-z0-9가-힣]{1,12}(?:빌딩|건물|타워|프라자|센터|센타|아파트|상가|병원)))*'; +const ADDRESS = new RegExp(`(${REGION_START}[^\\n|·]{4,60}?(?:빌딩|건물|층|호|\\d+번지|로\\s?\\d+(?:길\\s?\\d+)?(?:-\\d+)?|길\\s?\\d+(?:-\\d+)?)${ADDR_EXT})`, 'g'); function factCandidates(text) { const pick = (re) => [...new Set([...text.matchAll(re)].map((m) => clean(m[1] ?? m[0])))]; return { - phone: pick(/(? i.kind === 'li' || (i.kind === 'p' && /대학|병원|학회|전문의|회원|교수|수료|연수|졸업|위촉|박사|석사/.test(i.text) && i.text.length < 80)).map((i) => i.text).filter((t) => !/원장$/.test(t)); const creds = [...new Set(credentials)].filter((c) => c !== specialty); - const status = !name ? '이름 미확인 · 확인 대기' : creds.length < 2 ? (page.flags.textInImages ? '약력 이미지 글자 · 확인 대기' : '약력 본문 없음 · 확인 대기') : 'ok'; + const status = !name ? (page.flags.textInImages ? '이름 미확인(이미지 글자) · 확인 대기' : '이름 미확인 · 확인 대기') : creds.length < 2 ? (page.flags.textInImages ? '약력 이미지 글자 · 확인 대기' : '약력 본문 없음 · 확인 대기') : 'ok'; return { id: page.slug.replace(/^.*doctors?-?/, ''), url: page.url, name, title: [isRep ? '대표원장' : '원장', specialty].filter(Boolean).join(' · ') || null, credentials: creds, images: page.images.slice(0, 5), textInImages: page.flags.textInImages, status }; } // ---------- 메인 ---------- -const origin = new URL(START).origin; mkdirSync(join(OUT, 'pages'), { recursive: true }); -const robots = await loadRobots(origin); -console.log(`[1/4] 시작 ${START} (robots Disallow ${robots.disallow.length}개)`); +console.log(`[1/4] 시작 ${START}`); -// 링크 발견: 홈 + 사이트맵 -const home = await fetchText(START); +// 시작 URL 해석: 껍데기면 리다이렉트 대상들을 받아 같은 호스트 링크가 가장 많은 페이지를 홈으로, 나머지는 씨앗 페이지로 +let home = await fetchText(START); if (home.status !== 200) { console.error(`홈 요청 실패: ${home.status} ${home.error ?? ''}`); process.exit(1); } -const homeEx = extract(home.body, home.finalUrl); +let homeEx = extract(home.body, home.finalUrl); +const seeds = []; // { url, ex } 홈 외에 앵커를 긁을 페이지(프레임·리다이렉트 대상·--extra-url) +const redirectChain = []; +for (let hop = 0; hop < 3 && isShell(home.body, homeEx); hop++) { + const targets = redirectTargets(home.body, home.finalUrl).filter(sameHost).slice(0, 5); + if (!targets.length) break; + const fetched = []; + for (const u of targets) { const r = await fetchText(u); if (r.status === 200 && /html/.test(r.contentType)) fetched.push({ url: u, r, ex: extract(r.body, r.finalUrl) }); } + if (!fetched.length) break; + fetched.sort((a, b) => b.ex.anchors.filter(([u]) => sameHost(u)).length - a.ex.anchors.filter(([u]) => sameHost(u)).length); + const [best, ...rest] = fetched; + redirectChain.push({ from: home.finalUrl, to: best.r.finalUrl, kind: / x.r.finalUrl) }); + console.log(` 껍데기 페이지(${redirectChain.at(-1).kind}) → 홈 ${best.r.finalUrl}${rest.length ? ` · 씨앗 ${rest.map((x) => x.r.finalUrl).join(', ')}` : ''}`); + for (const x of rest) seeds.push({ url: x.r.finalUrl, ex: x.ex, anchor: '' }); + home = best.r; homeEx = best.ex; +} +HOSTS.add(hostOf(home.finalUrl)); +const origin = new URL(home.finalUrl).origin; +const robots = await loadRobots(origin); +console.log(` 홈 ${home.finalUrl} (charset ${home.charset ?? 'utf-8'} · robots Disallow ${robots.disallow.length}개)`); +for (const u of EXTRA) { + HOSTS.add(hostOf(u)); await loadRobots(new URL(u).origin); + const r = await fetchText(u); + if (r.status !== 200 || !/html/.test(r.contentType)) { console.log(` 추가 URL 실패 ${u}: ${r.status} ${r.error ?? ''}`); continue; } + seeds.push({ url: r.finalUrl, ex: extract(r.body, r.finalUrl), anchor: '', extra: true }); + console.log(` 추가 URL ${r.finalUrl} (charset ${r.charset})`); +} + +// 링크 발견: 홈 + 씨앗 + 사이트맵 +const EXTRA_SET = new Set(seeds.filter((s) => s.extra).map((s) => normalize(s.url, s.url))); +const robotsAllowed = (u) => { const o = new URL(u).origin; const rb = robotsCache.get(o); return rb ? rb.allowed(new URL(u).pathname) : true; }; const queue = new Map(); // url → { anchor, fromHome } -const addLink = (u, anchor = '', fromHome = false) => { if (!u || !sameHost(u, origin) || SKIP.test(u) || /\.xml$/i.test(u) || !robots.allowed(new URL(u).pathname)) return; const cur = queue.get(u); if (!cur) queue.set(u, { anchor, fromHome }); else if (fromHome && !cur.fromHome) cur.fromHome = true; }; +const addLink = (u, anchor = '', fromHome = false) => { if (!u || !sameHost(u) || SKIP.test(u) || /\.xml$/i.test(u) || !robotsAllowed(u)) return; const cur = queue.get(u); if (!cur) queue.set(u, { anchor, fromHome }); else { if (fromHome && !cur.fromHome) cur.fromHome = true; if (!cur.anchor && anchor) cur.anchor = anchor; } }; for (const [u, a] of homeEx.anchors) addLink(u, a, true); +for (const s of seeds) { addLink(normalize(s.url, s.url), s.anchor, true); for (const [u, a] of s.ex.anchors) addLink(u, a, true); } +for (const u of [...homeEx.jsLinks, ...seeds.flatMap((s) => s.ex.jsLinks)]) addLink(u, '', false); for (const sm of ['/sitemap.xml', '/wp-sitemap.xml', '/sitemap_index.xml', '/page-sitemap.xml']) { const r = await fetchText(`${origin}${sm}`, 0); if (r.status !== 200 || !/<(urlset|sitemapindex)/.test(r.body)) continue; @@ -203,22 +344,33 @@ for (const sm of ['/sitemap.xml', '/wp-sitemap.xml', '/sitemap_index.xml', '/pag console.log(` 사이트맵 ${sm}: 링크 누적 ${queue.size}`); break; } +queue.delete(normalize(home.finalUrl, home.finalUrl)); queue.delete(normalize(START, START)); console.log(`[2/4] 후보 링크 ${queue.size}개 → 유형 분류`); // 유형 분류 후 우선순위대로 MAX까지 const ranked = [...queue.entries()].map(([u, { anchor, fromHome }]) => ({ url: u, anchor, fromHome, depth: new URL(u).pathname.split('/').filter(Boolean).length, type: classify(new URL(u).pathname, anchor) })); +// 같은 경로의 쿼리 변형(?id=1, ?tab=x)은 클라이언트 상태인 경우가 많다(원진 doctor?id=N·뷰 after-care?tab=X 는 같은 HTML). +// 경로별 첫 변형(variant 0)을 모든 유형에서 먼저 받고, 나머지 변형은 그 뒤로. index.php?doc=N 처럼 쿼리가 곧 페이지인 사이트는 변형이 곧 본문이라 뒤에 오더라도 MAX 안에서 받는다 +{ + const byPath = new Map(); + for (const x of ranked.slice().sort((a, b) => a.url.localeCompare(b.url))) { const k = hostOf(x.url) + new URL(x.url).pathname.replace(/\/$/, ''); const n = byPath.get(k) ?? 0; x.variant = n; byPath.set(k, n + 1); } +} const prio = (t) => { const i = TYPES.findIndex(([k]) => k === t); return i === -1 ? 99 : i; }; -// 유형이 잡힌 페이지 먼저(의료진 상세는 40명까지), 그다음 후보는 홈 메뉴에서 연결된 것 → 얕은 경로 순 +const vk = (x) => Math.min(x.variant, 1); const isDoctorDetail = (x) => x.type === 'doctor' && /\/doctors?\/[^/]+\/?$/.test(new URL(x.url).pathname); -const typed = ranked.filter((x) => x.type !== 'candidate').sort((a, b) => prio(a.type) - prio(b.type) || a.depth - b.depth); -const doctorDetails = typed.filter(isDoctorDetail).slice(0, 40); const typedRest = typed.filter((x) => !isDoctorDetail(x)); -const cands = ranked.filter((x) => x.type === 'candidate').sort((a, b) => Number(b.fromHome) - Number(a.fromHome) || a.depth - b.depth || a.url.length - b.url.length || a.url.localeCompare(b.url)); -const targets = [...typedRest, ...doctorDetails, ...cands].slice(0, MAX); -console.log(` 유형 확정 ${typedRest.length} · 의료진 상세 ${doctorDetails.length} · 후보 ${cands.length} → 수집 ${targets.length}`); +// 버킷 순서: 유형 확정(시술 제외) → 의료진 상세(40명까지) → 지점(BRANCH_CAP 까지) → 시술 → 후보(홈 메뉴에서 연결된 것 → 얕은 경로 순). +// 시술 페이지는 수가 많아(원진 55·오라클 110) 앞에 두면 의료진 상세를 밀어낸다 +const bucket = (x) => (x.type === 'candidate' ? 4 : x.type === 'procedure' ? 3 : x.type === 'branches' ? 2 : isDoctorDetail(x) ? 1 : 0); +// 유형 버킷 안에서는 홈 메뉴 순서(큐 삽입 순)를 지킨다(의료진은 대표원장이 먼저 나온다). 후보만 URL 길이·사전순으로 안정화 +const ordered = ranked.slice().sort((a, b) => vk(a) - vk(b) || bucket(a) - bucket(b) || (bucket(a) === 4 ? Number(b.fromHome) - Number(a.fromHome) : prio(a.type) - prio(b.type)) || a.depth - b.depth || (bucket(a) === 4 ? a.url.length - b.url.length || a.url.localeCompare(b.url) : 0)); +const caps = { 1: 40, 2: BRANCH_CAP }; const taken = {}; +const targets = ordered.filter((x) => { const b = bucket(x); taken[b] = (taken[b] ?? 0) + 1; return !(b in caps) || taken[b] <= caps[b]; }).slice(0, MAX); +const n = (b) => ranked.filter((x) => bucket(x) === b).length; +console.log(` 유형 확정 ${n(0)} · 의료진 상세 ${Math.min(n(1), 40)}/${n(1)} · 지점 ${Math.min(n(2), BRANCH_CAP)}/${n(2)} · 시술 ${n(3)} · 후보 ${n(4)} · 쿼리 변형 ${ranked.filter((x) => x.variant > 0).length} → 수집 ${targets.length}`); // 수집 const pages = []; -const slugOf = (u) => (new URL(u).pathname.replace(/^\/|\/$/g, '').replace(/[^a-zA-Z0-9가-힣]+/g, '-') || 'home'); +const slugOf = (u) => { const x = new URL(u); return ((x.pathname.replace(/^\/|\/$/g, '') + (x.search ? '-' + x.search.slice(1) : '')).replace(/[^a-zA-Z0-9가-힣]+/g, '-').replace(/^-|-$/g, '') || 'home'); }; async function collect(t) { let r = await fetchText(t.url); if (r.status === 404) { // 슬래시 유무 반대 형태 재시도 @@ -231,9 +383,10 @@ async function collect(t) { const h1 = ex.items.find((i) => i.kind === 'h' && i.level === 1)?.text ?? null; let type = t.type; const bodyText = ex.items.map((i) => i.kind === 'table' ? i.rows.flat().join(' ') : i.text).join('\n'); - if (type === 'candidate') type = PROCEDURE_HINT.test(bodyText) ? 'procedure' : 'other'; + // 경로·앵커로 못 정한 페이지: 제목·h1 키워드 → 본문의 지점명 밀도 → 시술 본문 단서 순 + if (type === 'candidate') type = classifyByTitle(ex.title, h1, breadcrumbs(ex.items)) ?? (branchNames(bodyText).length >= 8 ? 'branches' : PROCEDURE_HINT.test(bodyText) ? 'procedure' : 'other'); if (type === 'doctor' && /\/doctors?\/[^/]+\/?$/.test(new URL(t.url).pathname) && !/\/doctors?\/?$/.test(new URL(t.url).pathname)) type = 'doctor-detail'; - pages.push({ url: r.finalUrl, requestedUrl: t.url, slug: slugOf(r.finalUrl), type, anchor: t.anchor, status: r.status, title: ex.title, metaDesc: ex.metaDesc, h1, mainSelector: ex.mainSelector, items: ex.items, images: ex.images, links: ex.links.filter((l) => sameHost(l, origin)), rawText: bodyText, fullTextForFacts: clean(parse(r.body).querySelector('body')?.text ?? '').slice(0, 200000), flags: {} }); + pages.push({ url: r.finalUrl, requestedUrl: t.url, slug: slugOf(r.finalUrl), type, extra: EXTRA_SET.has(t.url) || undefined, anchor: t.anchor, status: r.status, charset: r.charset, title: ex.title, metaDesc: ex.metaDesc, h1, mainSelector: ex.mainSelector, items: ex.items, images: ex.images, links: ex.links.filter(sameHost), rawText: bodyText, fullTextForFacts: fullText(r.body), flags: {} }); } { let i = 0; const workers = Array.from({ length: 3 }, async () => { while (i < targets.length) { const t = targets[i++]; await collect(t); process.stdout.write(`\r 수집 ${pages.length}/${targets.length}`); await sleep(DELAY); } }); @@ -242,12 +395,28 @@ async function collect(t) { // 홈도 페이지로 { const h1 = homeEx.items.find((i) => i.kind === 'h' && i.level === 1)?.text ?? null; - pages.unshift({ url: home.finalUrl, requestedUrl: START, slug: 'home', type: 'home', anchor: '', status: 200, title: homeEx.title, metaDesc: homeEx.metaDesc, h1, mainSelector: homeEx.mainSelector, items: homeEx.items, images: homeEx.images, links: homeEx.links.filter((l) => sameHost(l, origin)), rawText: homeEx.items.map((i) => i.kind === 'table' ? i.rows.flat().join(' ') : i.text).join('\n'), fullTextForFacts: clean(parse(home.body).querySelector('body')?.text ?? '').slice(0, 200000), flags: {} }); + pages.unshift({ url: home.finalUrl, requestedUrl: START, slug: 'home', type: 'home', anchor: '', status: 200, charset: home.charset, title: homeEx.title, metaDesc: homeEx.metaDesc, h1, mainSelector: homeEx.mainSelector, items: homeEx.items, images: homeEx.images, links: homeEx.links.filter(sameHost), rawText: homeEx.items.map((i) => i.kind === 'table' ? i.rows.flat().join(' ') : i.text).join('\n'), fullTextForFacts: fullText(home.body), flags: {} }); } -console.log(`\n[3/4] 페이지 ${pages.length}개 수집. 반복 줄 제거`); +// slug 충돌 방지(같은 slug 로 정규화되는 두 URL) +{ + const used = new Map(); + for (const p of pages) { const n = used.get(p.slug) ?? 0; used.set(p.slug, n + 1); if (n) p.slug = `${p.slug}-${n + 1}`; } +} +// 같은 경로에서 본문(제목+항목)이 같은 쿼리 변형은 중복. 첫 페이지만 남기고 나머지는 type=duplicate 로 index 에만 기록한다 +{ + const seen = new Map(); + for (const p of pages.slice().sort((a, b) => a.url.length - b.url.length)) { // 짧은 URL(쿼리 없는 쪽)을 대표로 + if (p.status !== 200 || p.error) continue; + const key = hostOf(p.url) + new URL(p.url).pathname + '\n' + p.title + '\n' + p.rawText; // http/https 는 같은 페이지 + const first = seen.get(key); + if (first) { p.type = 'duplicate'; p.duplicateOf = first.url; p.items = []; p.images = []; if (p.extra) first.extra = true; } else seen.set(key, p); + } +} +const dupCount = pages.filter((p) => p.type === 'duplicate').length; +console.log(`\n[3/4] 페이지 ${pages.length}개 수집${dupCount ? ` (쿼리 변형 중복 ${dupCount})` : ''}. 반복 줄 제거`); // 반복 줄(boilerplate) 제거: 페이지의 30% 이상(최소 3)에 같은 줄이 있으면 메뉴·푸터로 본다 -const ok = pages.filter((p) => p.status === 200 && !p.error); +const ok = pages.filter((p) => p.status === 200 && !p.error && p.type !== 'duplicate'); const freq = new Map(); for (const p of ok) for (const t of new Set(p.items.filter((i) => i.kind !== 'table').map((i) => i.text))) freq.set(t, (freq.get(t) ?? 0) + 1); const threshold = Math.max(3, Math.ceil(ok.length * 0.3)); @@ -259,7 +428,8 @@ for (const p of ok) { p.sections = sectionize(p.items); p.text = p.items.map((i) => i.kind === 'table' ? i.rows.map((r) => r.join(' | ')).join('\n') : i.text).join('\n'); p.chars = p.text.replace(/\s+/g, '').length; - p.flags = { textInImages: p.chars < 500 && p.images.length >= 3, noText: p.chars < 100, boilerplateRemoved: before - p.items.length, tables: p.items.filter((i) => i.kind === 'table').length }; + // 이미지 글자: 본문 500자 미만에 이미지 3장 이상, 또는 본문 100자 미만에 본문 이미지가 1장이라도 있으면(시술 설명을 통짜 이미지로 넣는 사이트) + p.flags = { textInImages: (p.chars < 500 && p.images.length >= 3) || (p.chars < 100 && p.images.length >= 1), noText: p.chars < 100, boilerplateRemoved: before - p.items.length, tables: p.items.filter((i) => i.kind === 'table').length }; } // 저장 @@ -268,20 +438,30 @@ for (const p of pages) { const file = `pages/${p.slug}.json`; const { fullTextForFacts, rawText, ...save } = p; writeFileSync(join(OUT, file), JSON.stringify({ clinic: CLINIC, fetchedAt: today, ...save }, null, 1)); - index.push({ file, url: p.url, type: p.type, status: p.status, mainSelector: p.mainSelector ?? null, title: p.title ?? null, h1: p.h1 ?? null, chars: p.chars ?? 0, tables: p.flags?.tables ?? 0, images: p.images?.length ?? 0, flags: Object.entries(p.flags ?? {}).filter(([k, v]) => v === true).map(([k]) => k) }); + index.push({ file, url: p.url, type: p.type, duplicateOf: p.duplicateOf, status: p.status, mainSelector: p.mainSelector ?? null, title: p.title ?? null, h1: p.h1 ?? null, chars: p.chars ?? 0, tables: p.flags?.tables ?? 0, images: p.images?.length ?? 0, flags: Object.entries(p.flags ?? {}).filter(([k, v]) => v === true).map(([k]) => k) }); } const byType = index.reduce((m, x) => ((m[x.type] = (m[x.type] ?? 0) + 1), m), {}); -writeFileSync(join(OUT, 'index.json'), JSON.stringify({ clinic: CLINIC, start: START, fetchedAt: today, robotsDisallow: robots.disallow, boilerplateLines: boiler.size, byType, pages: index }, null, 1)); +writeFileSync(join(OUT, 'index.json'), JSON.stringify({ clinic: CLINIC, start: START, resolvedStart: home.finalUrl, redirectChain, extraUrls: EXTRA, charset: home.charset ?? null, fetchedAt: today, robotsDisallow: robots.disallow, boilerplateLines: boiler.size, byType, pages: index }, null, 1)); -// 의료진 -const doctors = ok.filter((p) => p.type === 'doctor-detail').map(parseDoctor); -writeFileSync(join(OUT, 'doctors.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, note: 'textInImages=true 인 약력은 이미지 글자라 본문에 없다. authors.json에 옮기기 전에 사람이 확인한다.', doctors }, null, 1)); +// 의료진: 상세 페이지가 있으면 상세, 없으면 목록 페이지(이미지 글자면 이름 미확인으로 남긴다) +let doctors = ok.filter((p) => p.type === 'doctor-detail').map(parseDoctor); +const doctorSource = doctors.length ? 'doctor-detail' : 'doctor'; +if (!doctors.length) doctors = ok.filter((p) => p.type === 'doctor').map(parseDoctor); +writeFileSync(join(OUT, 'doctors.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, source: doctorSource, note: 'textInImages=true 인 약력은 이미지 글자라 본문에 없다. authors.json에 옮기기 전에 사람이 확인한다.', doctors }, null, 1)); // 사실 후보 -const factSrc = ok.filter((p) => ['home', 'direction', 'about', 'reservation'].includes(p.type)); +const factSrc = ok.filter((p) => ['home', 'direction', 'about', 'reservation'].includes(p.type) || p.extra); // --extra-url 로 지정한 페이지는 사람이 고른 원천이라 항상 포함 const facts = {}; for (const p of factSrc) { const c = factCandidates(p.fullTextForFacts); for (const [k, vals] of Object.entries(c)) for (const val of vals) { facts[k] ??= {}; facts[k][val] ??= []; if (!facts[k][val].includes(p.url)) facts[k][val].push(p.url); } } -writeFileSync(join(OUT, 'facts.draft.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, note: '정규식 후보. 값마다 출처 URL. factSheet.json에 넣기 전에 사람이 홈페이지 표기와 대조한다. 후보가 없으면 "확인 대기".', candidates: facts }, null, 1)); +// 지점 후보: 지점 목록·지점별 페이지의 "지점명 주소 TEL" 3종 세트. 본문(메뉴·푸터 제외)에서 먼저 찾고, 없으면 전문에서 +const branches = []; const branchPagesNap = []; +for (const p of ok.filter((p) => p.type === 'branches' || p.extra)) { + let found = branchCandidates(p.text ?? ''); if (!found.length) found = branchCandidates(p.fullTextForFacts); + for (const b of found) if (!branches.some((x) => x.name === b.name && x.phone === b.phone)) branches.push({ ...b, source: p.url }); + // 지점 한 곳짜리 페이지(net_main.php?netId=N 같은): 3종 세트가 없으면 본문의 주소·전화·진료시간을 그대로 후보로 + if (found.length < 3) { const c = factCandidates(p.text ?? ''); if (c.address.length || c.phone.length || c.hours.length) branchPagesNap.push({ url: p.url, title: p.title, h1: p.h1, address: c.address, phone: c.phone, hours: c.hours }); } +} +writeFileSync(join(OUT, 'facts.draft.json'), JSON.stringify({ clinic: CLINIC, fetchedAt: today, note: '정규식 후보. 값마다 출처 URL. factSheet.json에 넣기 전에 사람이 홈페이지 표기와 대조한다. 후보가 없으면 "확인 대기". branches 는 지점 목록 페이지에서 뽑은 지점명·주소·전화 후보.', candidates: facts, branches, branchPages: branchPagesNap }, null, 1)); // 40자 중복 검사 기준 텍스트 writeFileSync(join(OUT, 'home_text.txt'), ok.map((p) => p.text.replace(/\s+/g, '')).join('\n')); @@ -291,7 +471,7 @@ const postsDir = arg('--posts'); if (postsDir && existsSync(postsDir)) { const { readdirSync } = await import('node:fs'); const cited = new Set(); - for (const f of readdirSync(postsDir).filter((x) => x.endsWith('.md'))) for (const m of readFileSync(join(postsDir, f), 'utf8').matchAll(/url:\s*"([^"]+)",\s*accessed:[^}]*type:\s*clinic/g)) if (sameHost(m[1], origin)) cited.add(normalize(m[1], origin)); + for (const f of readdirSync(postsDir).filter((x) => x.endsWith('.md'))) for (const m of readFileSync(join(postsDir, f), 'utf8').matchAll(/url:\s*"([^"]+)",\s*accessed:[^}]*type:\s*clinic/g)) if (sameHost(m[1])) cited.add(normalize(m[1], origin)); const have = new Set(pages.flatMap((p) => [p.url, p.requestedUrl].filter(Boolean))); const missing = []; for (const u of cited) { if (have.has(u)) continue; const r = await fetchText(u, 0); if (!have.has(normalize(r.finalUrl, origin))) missing.push(u); } @@ -299,5 +479,5 @@ if (postsDir && existsSync(postsDir)) { } console.log(`[4/4] 저장 ${OUT}`); console.log(` 유형별: ${Object.entries(byType).map(([k, v]) => `${k} ${v}`).join(' · ')}`); -console.log(` 의료진 ${doctors.length}명 (약력 확인 대기 ${doctors.filter((d) => d.status !== 'ok').length}명) · 반복 줄 ${boiler.size}개 제거 · home_text ${ok.reduce((n, p) => n + p.chars, 0).toLocaleString()}자`); +console.log(` 의료진 ${doctors.length}명 (약력 확인 대기 ${doctors.filter((d) => d.status !== 'ok').length}명, 출처 ${doctorSource}) · 지점 후보 ${branches.length}개 · 반복 줄 ${boiler.size}개 제거 · home_text ${ok.reduce((n, p) => n + p.chars, 0).toLocaleString()}자`); const bad = index.filter((x) => x.status !== 200); if (bad.length) console.log(` 실패 ${bad.length}: ${bad.map((b) => `${b.status} ${b.url}`).join(', ')}`); diff --git a/templates/supporters-astro/scripts/collect_recovery.mjs b/templates/supporters-astro/scripts/collect_recovery.mjs new file mode 100644 index 0000000..2db77ea --- /dev/null +++ b/templates/supporters-astro/scripts/collect_recovery.mjs @@ -0,0 +1,249 @@ +// 병원 홈페이지 시술 페이지 원문에서 "시술 후 관리" 문장을 골라 /stay·/en/stay 의 "시술 후 관리 안내" 블록 데이터를 만든다. +// 근거는 collect_evidence.mjs 결과(index.json + pages/*.json). 이미지 글자를 OCR 한 페이지(flags.ocr)도 text 에 들어 있으므로 같이 본다. +// 의학 판단을 하지 않는다. 병원이 적어 둔 문장을 그대로 옮기고, 출처 URL 과 확인일을 붙인다. +// +// node scripts/collect_recovery.mjs --clinic --evidence > --site [--translate] [--max-per-page 5] [--max-pages 30] [--max-cost-usd 0.5] +// +// 채택 조건 (문장 단위. 마침표·물음표·줄바꿈·" / " 로 나누고 10~160자) +// (a) 시점 표현: 시술 후 / 치료 후 / 수술 후 / 당일 / 다음 날 / N일·주·개월 (정도·간·이내·후·까지) / 이후 / 기간 +// (b) 행동·주의 표현: 피하·삼가·주의·금지·권장·가능·세안·자외선·사우나·음주·흡연·운동·화장·샤워·부기·멍·실밥 등 +// 둘 다 있어야 채택. 효과·홍보 문장(효과·개선·매력·아름다·만족·최고·추천)은 제외. 병원 이름·전화·주소 문장 제외. +// 수술 전 준비 문장("수술 전 3일간 금주")은 시술 후 관리가 아니므로 제외. +// OCR 문장은 그대로 쓰되 글자가 깨진 흔적(~~, 홀로 남은 조사, 표 라벨 뒤섞임)이 있으면 뺀다. +// 발행 게이트(gate/rules.mjs)의 금칙어·효과 보장·금액·운영자 어휘·비교 수치 규칙을 문장마다 적용해 걸리는 것은 뺀다. +// +// 출력 /src/data/recoveryNotes.json. 빈 결과여도 파일을 만든다(items []). 페이지는 items 가 없으면 블록을 그리지 않는다. +// --translate : OPENAI_API_KEY 로 gpt-4.1-mini 배치 번역. 숫자·단위가 원문과 같지 않으면 그 문장의 en 은 비우고 enFailed 에 남긴다. +// 시술 이름도 같은 배치로 번역해 procedureEn 에 넣는다(고유명사·제품명은 로마자 병기 허용. 예 "물광주사" → "Water-glow injection (Mulgwang)"). +// 같은 ko 문장은 캐시(/src/data/recoveryNotes.cache.json)에서 다시 쓴다. 비용 상한 기본 $0.5. +import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs'; +import { join, resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import * as R from './gate/rules.mjs'; + +const here = (p) => fileURLToPath(new URL(p, import.meta.url)); +const SUP = here('../'); +const args = process.argv.slice(2); +const opt = (k, d) => { const i = args.indexOf(`--${k}`); if (i >= 0 && args[i + 1] && !args[i + 1].startsWith('--')) return args[i + 1]; const eq = args.find((a) => a.startsWith(`--${k}=`)); return eq ? eq.slice(k.length + 3) : d; }; +const flag = (k) => args.includes(`--${k}`); + +const clinic = opt('clinic'); +if (!clinic) { console.error('사용법: --clinic --evidence

    --site [--translate]'); process.exit(2); } +const EV = resolve(opt('evidence', join(SUP, '..', 'evidence', clinic))); +const SITE = resolve(opt('site', SUP)); +const maxPerPage = Number(opt('max-per-page', '5')); +// 주의사항·애프터케어 전용 페이지는 관리 문장이 수십 개라 상한을 따로 둔다 (haewon 결정 2026-09-11: "수술 전후 주의사항 길게 해도 돼") +const maxPerCarePage = Number(opt('max-per-care-page', '40')); +const capFor = (type) => (type === 'aftercare' || type === 'precautions' ? maxPerCarePage : maxPerPage); +const maxPages = Number(opt('max-pages', '30')); +const maxCostUsd = Number(opt('max-cost-usd', '0.5')); +const doTranslate = flag('translate'); +const today = new Date().toISOString().slice(0, 10); + +// ---------- .env (generate_posts.mjs 와 같은 방식: 저장소 루트까지 위로 4단계 탐색) ---------- +function loadEnv() { + let dir = SUP; + for (let i = 0; i < 4; i++) { + const p = join(dir, '.env'); + if (existsSync(p)) { + for (const line of readFileSync(p, 'utf8').split('\n')) { + const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/); + if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, ''); + } + } + dir = dirname(dir); + } +} +loadEnv(); + +const readJson = (p) => JSON.parse(readFileSync(p, 'utf8')); +const OUT = join(SITE, 'src', 'data', 'recoveryNotes.json'); +const CACHE = join(SITE, 'src', 'data', 'recoveryNotes.cache.json'); +const writeOut = (j) => { mkdirSync(dirname(OUT), { recursive: true }); writeFileSync(OUT, JSON.stringify(j, null, 2) + '\n'); }; + +if (!existsSync(join(EV, 'index.json'))) { + console.error(`근거 없음: ${EV}/index.json. 빈 결과를 씁니다.`); + writeOut({ clinic, generatedAt: today, sourceNote: '병원 홈페이지 시술 페이지 원문', items: [], counts: { pages: 0, candidates: 0, sentences: 0, translated: 0, enFailed: 0, costUsd: 0 } }); + process.exit(0); +} +const index = readJson(join(EV, 'index.json')); +const factPath = join(SITE, 'src', 'data', 'factSheet.json'); +const fact = existsSync(factPath) ? readJson(factPath) : {}; +const clinicNames = [fact.name, fact.shortName, index.clinic].filter((s) => s && /[가-힣]/.test(s)); +const phone = fact.phone || ''; +// 홈페이지 40자 연속 일치 검사 기준(발행 게이트와 같은 파일). 인용 블록은 게이트에서 제외되지만, 다른 페이지의 문장과 겹치는지는 여기서 보지 않는다. + +// ---------- 문장 규칙 ---------- +const TIME = /시술\s*후|치료\s*후|수술\s*후|당일|다음\s*날|\d+\s*(일|주|개월)\s*(정도|간|이내|후|까지)|이후|기간/; +const ACTION = /피하|피해|삼가|주의|금지|권장|가능|세안|자외선|선크림|사우나|찜질|음주|흡연|운동|화장|샤워|목욕|일상\s*생활|복귀|출근|부기|멍|딱지|보습|냉찜질|온찜질|실밥/; +const PROMO = /효과|개선|매력|아름다|만족|최고|추천|노하우|프리미엄|서비스|제공|전담|책임|케어해|서포트|장비|기기|시스템|자체|생기있|탄탄|오래\s*유지|정밀|안전한|거의\s*(보이지|남지)\s*않|에\s*비해|단축/; // 뒤쪽은 시술 소개·장비 홍보·타 술식 비교 문장의 어휘. 관리 지시문에는 잘 안 나온다 +// 수술 전 준비 문장. "수술 전 3일간 금주" 는 시술 후 관리가 아니다. "수술 전/후" 처럼 후가 같이 있으면 통과. +const PRE_OP = /(수술|시술|치료)\s*(\d+\s*(일|주|시간|개월)\s*)?전(?!\s*[\/·후])/; +const CONTACT = /\d{2,4}[-.]\d{3,4}[-.]\d{4}|\d{4}-\d{4}|(서울|부산|대구|인천|광주|대전|울산|경기|강원|충북|충남|전북|전남|경북|경남|제주)[특별광역]*[시도]?\s*[가-힣]+[구군시]|[가-힣]+(로|길)\s*\d+|빌딩|층\b|오시는\s*길|찾아오시는/; +// 표 라벨(수술시간·마취방법 등)이 한 줄에 뒤섞인 OCR 문장은 행 순서가 깨져 있어 통째로 뺀다. +const TABLE_LABEL = /(수술\s*시간|마취\s*방법|입원\s*여부|입원\s*기간|시술\s*시간|수술\s*방법)\s*[::]/; +// 라벨 뒤만 살리는 경우: "회복기간 : …" 처럼 콜론이 있는 라벨, 또는 소제목("수술 후 관리", "시술 후 주의점")이 문장 앞에 붙은 OCR 문장 +const COLON_LABEL = /(회복\s*기간|실밥\s*제거)\s*[::]\s*/; +const HEADING_GLUE = /^.{0,12}?(시술|수술)\s*후\s*(주의\s*(점|사항)|관리(\s*방법)?)\s+(?=\S)/; +// OCR 파손 흔적: 물결 두 개, 홀로 남은 조사, 숫자 뒤 알파벳(3-4t시간), 표시 기호, 단독 숫자 +const BROKEN = /~~|\s[을를이가은는의]\s|\d[a-zA-Z]시간|[✓√■►▶▪◆●▲]|(? s.replace(/\s+/g, ''); +const clean = (s) => s + .replace(/^[\s\-•●▪■#*·√✓※]+/, '') // 목록 기호 + .replace(/^\(?\d{1,2}[.)]\s+(?=[가-힣])/, '') // "5. 다음날부터" 목록 번호 + .replace(/^\d{1,2}\s+(?=[가-힣])/, '') // "5 다음날부터" + .replace(/\s+\d{1,2}[.,]?$/, '') // 문장 끝에 붙은 다음 항목 번호 "… 가능 2." + .replace(/\s+/g, ' ') + .trim(); + +function splitSentences(text) { + return String(text || '') + .split(/(?<=[.?!。])\s+|\n+|\s\/\s/) + .map(clean) + .filter(Boolean); +} + +/** 채택 여부. 실패 사유를 문자열로 돌려주고, 통과면 정제된 문장을 돌려준다. */ +function judge(raw, { ocr }) { + let s = raw; + if (TABLE_LABEL.test(s)) return { drop: 'table' }; + const g = s.match(HEADING_GLUE); + if (g) s = s.slice(g[0].length).trim(); + const c = s.match(COLON_LABEL); + if (c && c.index > 0) s = s.slice(c.index + c[0].length).trim(); + if (s.length < 10 || s.length > 160) return { drop: 'length' }; + if (!TIME.test(s)) return { drop: 'time' }; + if (!ACTION.test(s)) return { drop: 'action' }; + if (s.split(' ').length < 4) return { drop: 'fragment' }; // "수술 다음날부터 가능" 처럼 무엇이 가능한지 없는 표 조각 + if (PROMO.test(s)) return { drop: 'promo' }; + if (PRE_OP.test(s) && !/후/.test(s)) return { drop: 'preop' }; + if (CONTACT.test(s) || clinicNames.some((n) => s.includes(n)) || (phone && s.includes(phone))) return { drop: 'contact' }; + if (BROKEN.test(s)) return { drop: ocr ? 'ocr-broken' : 'broken' }; + if (ocr && s.length > 100 && !/[,.]/.test(s.slice(0, 80))) return { drop: 'ocr-broken' }; // 표 칸이 한 줄로 이어 붙은 OCR 문장(쉼표·마침표 없이 길다) + if (!/[.다요음함됨]\s*[.)]?$/.test(s) && !/(가능|불가|금지|권장|주의|필요)$/.test(s)) return { drop: 'unfinished' }; // 문장이 끝나지 않은 조각 + // 발행 게이트 규칙. 걸리면 뺀다. + const fields = [{ field: 'ko', text: s }]; + const gate = [ + ...R.checkBannedBody(s), + ...R.checkOperatorVocab(s), + ...R.checkPriceMention(fields), + ...R.checkDeviceClaim({}, fields), + ...R.checkConclusions(fields), + ].filter((x) => x.level === R.E); + if (gate.length) return { drop: `gate:${gate[0].code}` }; + return { ok: s }; +} + +// ---------- 페이지 순회 ---------- +const TYPES = new Set(['procedure', 'aftercare', 'precautions']); +const pages = (index.pages ?? []).filter((p) => TYPES.has(p.type) && p.status === 200 && p.file); +const dropCounts = {}; +const items = []; +const seenGlobal = new Set(); // 페이지가 달라도 같은 문장(공백 제거 후)은 한 번만 +const cleanTitle = (t) => { + let s = String(t || '').split('|')[0].trim(); + for (const n of clinicNames) s = s.replace(new RegExp(`^${n.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*`), ''); + return s.trim(); +}; +for (const meta of pages) { + const fp = join(EV, meta.file); + if (!existsSync(fp)) continue; + const pg = readJson(fp); + const flags = Array.isArray(pg.flags) ? pg.flags : Object.keys(pg.flags ?? {}).filter((k) => pg.flags[k]); + const ocr = flags.includes('ocr'); + const text = pg.text || ''; + // 시술 영역: 빵부스러기("Home > 필러 & 보톡스 > 보톡스") 의 첫 항목 + const crumb = text.split('\n').find((l) => /^Home\s*>/.test(l.trim())); + const area = crumb ? (crumb.split('>').map((s) => s.trim())[1] ?? '') : ''; + const ko = []; + const seenPage = new Set(); + for (const raw of splitSentences(text)) { + const j = judge(raw, { ocr }); + if (j.drop) { dropCounts[j.drop] = (dropCounts[j.drop] ?? 0) + 1; continue; } + const key = compact(j.ok); + if (seenPage.has(key) || seenGlobal.has(key)) { dropCounts.dup = (dropCounts.dup ?? 0) + 1; continue; } + seenPage.add(key); seenGlobal.add(key); + ko.push(j.ok); + if (ko.length >= capFor(meta.type)) break; + } + if (!ko.length) continue; + items.push({ procedure: cleanTitle(pg.h1) || cleanTitle(pg.title) || cleanTitle(meta.title), procedureEn: '', area, url: pg.url || meta.url, fetchedAt: pg.fetchedAt || index.fetchedAt || today, ko, en: ko.map(() => ''), ocr }); +} +items.sort((a, b) => b.ko.length - a.ko.length || a.procedure.localeCompare(b.procedure, 'ko')); +const kept = items.slice(0, maxPages); +const totalSentences = kept.reduce((n, it) => n + it.ko.length, 0); + +// ---------- 번역 (선택) ---------- +const PRICE = { in: 0.4, out: 1.6 }; // gpt-4.1-mini USD / 1M tokens (2025 목록가) +const numsOf = (s) => (s.match(/\d+(?:[.,]\d+)?/g) ?? []).map((x) => x.replace(',', '.')).sort().join('|'); +let costUsd = 0, translated = 0, enFailed = 0, cacheHits = 0; +const failed = []; +async function translateAll() { + const key = process.env.OPENAI_API_KEY; + const cache = existsSync(CACHE) ? readJson(CACHE) : {}; + const pending = []; // { it, i, ko, kind } · kind 'name' 은 시술 이름(i = -1). 캐시 키는 'name:' 접두어로 문장과 구분한다. + for (const it of kept) { + it.ko.forEach((s, i) => { + if (cache[s]) { it.en[i] = cache[s]; cacheHits++; } + else pending.push({ it, i, ko: s, kind: 'sentence' }); + }); + if (it.procedure) { + if (cache[`name:${it.procedure}`]) { it.procedureEn = cache[`name:${it.procedure}`]; cacheHits++; } + else pending.push({ it, i: -1, ko: it.procedure, kind: 'name' }); + } + } + if (!pending.length) return; + if (!key) { console.warn('OPENAI_API_KEY 없음. 번역을 비운 채 씁니다.'); return; } + const clinicEn = fact.shortNameEn || fact.nameEn || 'the clinic'; + const system = [ + 'You translate Korean post-treatment care instructions from a medical clinic website into plain English for international patients.', + 'Rules: translate each sentence faithfully as an instruction; do not add, soften or strengthen medical advice; do not add explanations.', + 'Keep every number exactly as written in the source (digits, ranges such as 3~4 become "3 to 4", percentages, units converted to English words like days/weeks/months/hours). Never turn a number word into a digit and never drop a digit.', + 'Items with kind "name" are treatment or page names, not sentences: give a short English treatment name as a title (no trailing period); for proper nouns, brand or product names, keep a romanized Korean form in parentheses, e.g. "물광주사" -> "Water-glow injection (Mulgwang)", "맥스리프트" -> "Max Lift". Glossary: 주걱턱 = protruding chin (mandibular prognathism), 무턱 = receding chin, 사각턱 = square jaw, 매몰법 = non-incision double eyelid (buried suture), 앞트임/뒷트임 = epicanthoplasty / lateral canthoplasty, 광대 = cheekbone, 양악 = two-jaw (orthognathic), 눈매교정 = ptosis correction.', + `The clinic is ${clinicEn}. Do not mention any other clinic. Output JSON only.`, + ].join(' '); + const schema = { name: 'translations', strict: true, schema: { type: 'object', additionalProperties: false, properties: { items: { type: 'array', items: { type: 'object', additionalProperties: false, properties: { i: { type: 'integer' }, en: { type: 'string' } }, required: ['i', 'en'] } } }, required: ['items'] } }; + const BATCH = 40; + for (let b = 0; b < pending.length; b += BATCH) { + const batch = pending.slice(b, b + BATCH); + const est = (batch.reduce((n, x) => n + x.ko.length, 0) * 1.5 + 400) / 1e6 * PRICE.in + (batch.reduce((n, x) => n + x.ko.length, 0) * 1.2) / 1e6 * PRICE.out; + if (costUsd + est > maxCostUsd) { console.warn(`비용 상한 $${maxCostUsd} 도달 예상. 남은 ${pending.length - b}문장은 번역하지 않습니다.`); break; } + const user = JSON.stringify({ items: batch.map((x, i) => ({ i, kind: x.kind, ko: x.ko })) }); + const body = { model: 'gpt-4.1-mini', temperature: 0, messages: [{ role: 'system', content: system }, { role: 'user', content: user }], response_format: { type: 'json_schema', json_schema: schema } }; + let j = null; + for (let attempt = 0; attempt < 3; attempt++) { + const res = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers: { 'content-type': 'application/json', authorization: `Bearer ${key}` }, body: JSON.stringify(body) }); + if (res.status === 429 || res.status >= 500) { await new Promise((r) => setTimeout(r, 4000 * (attempt + 1))); continue; } + if (!res.ok) { console.warn(`번역 호출 실패 ${res.status}: ${(await res.text()).slice(0, 200)}`); break; } + j = await res.json(); break; + } + if (!j) { batch.forEach((x) => { enFailed++; failed.push({ ko: x.ko, why: 'api' }); }); continue; } + const u = j.usage ?? {}; + costUsd += ((u.prompt_tokens ?? 0) * PRICE.in + (u.completion_tokens ?? 0) * PRICE.out) / 1e6; + let out; + try { out = JSON.parse(j.choices?.[0]?.message?.content ?? '{}').items ?? []; } catch { out = []; } + const byI = new Map(out.map((o) => [o.i, String(o.en ?? '').trim()])); + batch.forEach((x, i) => { + const en = byI.get(i) ?? ''; + if (!en) { if (x.kind !== 'name') { enFailed++; failed.push({ ko: x.ko, why: 'empty' }); } return; } + if (x.kind === 'name') { x.it.procedureEn = en.replace(/\.$/, ''); cache[`name:${x.ko}`] = x.it.procedureEn; translated++; return; } + if (numsOf(en) !== numsOf(x.ko)) { enFailed++; failed.push({ ko: x.ko, en, why: 'numbers' }); return; } + x.it.en[x.i] = en; cache[x.ko] = en; translated++; + }); + } + writeFileSync(CACHE, JSON.stringify(cache, null, 1) + '\n'); +} +if (doTranslate && kept.length) await translateAll(); + +// ---------- 출력 ---------- +const result = { + clinic, + generatedAt: today, + sourceNote: '병원 홈페이지 시술 페이지 원문', + items: kept.map(({ fetchedAt, ...it }) => ({ ...it, fetchedAt })), + counts: { pagesScanned: pages.length, pagesWithNotes: items.length, pages: kept.length, sentences: totalSentences, translated: translated + cacheHits, cacheHits, enFailed, costUsd: +costUsd.toFixed(4), dropped: dropCounts }, + ...(failed.length ? { enFailed: failed } : {}), +}; +writeOut(result); +console.log(`시술 후 관리 문장: 페이지 ${pages.length}개 중 ${items.length}개에서 ${totalSentences}문장 (상위 ${kept.length}페이지) · 번역 ${translated + cacheHits}(캐시 ${cacheHits}) · 실패 ${enFailed} · $${costUsd.toFixed(4)} → ${OUT}`); diff --git a/templates/supporters-astro/scripts/default_briefs.mjs b/templates/supporters-astro/scripts/default_briefs.mjs index c5526d0..9386fa9 100644 --- a/templates/supporters-astro/scripts/default_briefs.mjs +++ b/templates/supporters-astro/scripts/default_briefs.mjs @@ -1,11 +1,15 @@ -// 새 병원의 첫 배치 기획 목록(brief)을 근거 수집 결과에서 만든다 (v1 §3 Phase 4, v2 §3-11). +// 새 병원의 첫 배치 기획 목록(brief)을 근거 수집 결과에서 만든다 (v1 §3 Phase 4, v2 §3-11, 피부과 PRD §7·§8). // 질문 뱅크 카테고리 7종 중 홈페이지 근거만으로 답할 수 있는 A·B·C·D·E 를 골라, 근거 페이지가 실제로 있는 것만 낸다. // 병원마다 페이지 구성이 다르므로(뷰: 주의사항·애프터케어·안전 페이지 있음 / 원진: 시술 페이지·소개·예약만 텍스트) 두 층으로 고른다. // 1층: 전용 페이지(precautions·aftercare·safety·direction)가 있을 때의 문항 // 2층: 어느 병원에나 있는 근거(시술 상세·병원 소개·의료진·예약)로 만드는 문항 +// 업종(industry)은 plastic(성형외과) / derm(피부과) 두 가지다. +// plastic: 시술 영역을 URL 세그먼트(/contents/facial/...)로 묶는다. 세그먼트가 일반어(new·doc·index.php·숫자)면 제목·헤딩·본문 키워드로 정한다. +// derm : URL 과 무관하게 제목·헤딩·본문 키워드로 피부과 8영역(질문 뱅크 D1~D8)에 배정한다. 시술 글은 조건 표 8행을 요구한다. +// --industry 를 주지 않으면 병원 이름과 시술 페이지 제목의 어휘 비율로 감지하고, 판단이 안 서면 plastic 이다. // 사람 승인(§3-11 "기획 목록 승인")은 이 파일을 리포트 페이지에서 보고 확정하는 것으로 한다. // -// node scripts/default_briefs.mjs --clinic --evidence > --site [--out briefs.json] [--max 6] +// node scripts/default_briefs.mjs --clinic --evidence > --site [--out briefs.json] [--max 6] [--industry derm|plastic] [--areas N] import { readFileSync, writeFileSync, existsSync } from 'node:fs'; import { join, resolve } from 'node:path'; @@ -18,6 +22,8 @@ if (!clinic || !existsSync(join(EV, 'index.json'))) { console.error('--clinic const index = JSON.parse(readFileSync(join(EV, 'index.json'), 'utf8')); const fact = JSON.parse(readFileSync(join(SITE, 'src/data/factSheet.json'), 'utf8')); const authors = JSON.parse(readFileSync(join(SITE, 'src/data/authors.json'), 'utf8')); +const factsDraftPath = join(EV, 'facts.draft.json'); +const factsDraft = existsSync(factsDraftPath) ? JSON.parse(readFileSync(factsDraftPath, 'utf8')) : {}; const name = fact.shortName || fact.name || clinic; // 조사: 받침 있으면 은/을, 없으면 는/를 const hasBatchim = (w) => { const c = w.charCodeAt(w.length - 1); return c >= 0xac00 && c <= 0xd7a3 ? (c - 0xac00) % 28 !== 0 : false; }; @@ -32,43 +38,135 @@ const urls = (...types) => [...new Set(types.flatMap((t) => byType(t).slice(0, 3 const physicianIds = Object.keys(authors.physicians ?? {}); const rep = physicianIds.find((id) => /대표/.test(authors.physicians[id].title ?? '')) ?? physicianIds[0]; const anesth = physicianIds.find((id) => /마취/.test(authors.physicians[id].title ?? '')) ?? rep; +const safeDecode = (u) => { try { return decodeURIComponent(u); } catch { return u; } }; -// 시술 페이지를 영역(URL 의 시술 세그먼트)별로 묶는다. /contents/facial/zygoma → facial, /breast/breast-augmentation/motiva → breast +// ---------- 업종 사전 ---------- +// 피부과 8영역. 질문 뱅크 D1~D8 과 1:1 (PRD §6·§7). kw 는 제목·헤딩·본문에서 찾는 낱말(소문자 비교). +export const DERM_AREAS = [ + { key: 'pigment', label: '색소·토닝', qb: 'D1', kw: ['색소', '토닝', '기미', '잡티', '주근깨', '흑자', '검버섯', '점빼기', '점 제거', '미백', '피코', '레이저토닝', '오타모반', '색소침착', '멜라닌', '화이트닝', 'ipl', '브이빔', '주근깨'] }, + { key: 'lifting', label: '리프팅·탄력', qb: 'D2', kw: ['리프팅', '탄력', '처짐', '울쎄라', '써마지', '인모드', '슈링크', '실리프팅', '고주파', '하이푸', 'hifu', '튠페이스', '올리지오', '덴서티', '잔주름', '안티에이징', '탄력저하', '볼처짐', '이중턱'] }, + { key: 'booster', label: '스킨부스터·재생', qb: 'D3', kw: ['스킨부스터', '리쥬란', '쥬베룩', '엑소좀', '물광', '연어주사', 'pdrn', '재생', '수분', '피부결', '콜라겐', '샤넬주사', '힐러', '스킨보톡스', '더마샤인', '피부재생', '진피', '리쥬엔'] }, + { key: 'toxin-filler', label: '톡신·필러', qb: 'D4', kw: ['보톡스', '톡신', '보툴리눔', '필러', '주름', '사각턱', '턱끝', '팔자', '이마', '미간', '눈가', '입술', '코필러', '볼륨', '승모근', '히알루론산', '윤곽주사', '지방분해주사'] }, + { key: 'acne', label: '여드름·흉터·모공', qb: 'D5', kw: ['여드름', '흉터', '모공', '피지', '블랙헤드', '압출', '스케일링', '필링', '아그네스', '프락셀', '피코프락셀', '패인 흉터', '튼살', '켈로이드', '수술흉터', 'aha', 'pha', '좁쌀'] }, + { key: 'hair-body', label: '제모·바디', qb: 'D6', kw: ['제모', '레이저제모', '바디', '체형', '셀룰라이트', '겨드랑이', '비키니', '종아리', '쿨스컬프팅', '지방 감소', '몸매', '팔뚝', '복부', '허벅지', '뱃살'] }, + { key: 'disease-hair', label: '피부질환·모발', qb: 'D7', kw: ['홍조', '안면홍조', '혈관', '실핏줄', '다한증', '액취증', '아토피', '건선', '두드러기', '사마귀', '티눈', '무좀', '습진', '탈모', '두피', '모발', '백반증', '피부염', '알레르기', '한관종', '비립종', '쥐젖', '지루', '피부암', '대상포진', '흉터 없는 점', '피부질환'] }, + { key: 'plan', label: '계획·주기·조합', qb: 'D8', kw: ['시술 주기', '권장 주기', '회차', '병행', '조합', '시술 순서', '시술 간격', '유지 관리', '프로그램', '패키지', '캘린더', '연간', '시술 계획', '같이 받', '함께 받', '결혼 전', '행사 전'] }, +]; +// 성형외과 폴백 사전. URL 세그먼트가 일반어(new·doc·숫자)라 영역을 못 정할 때만 쓴다. 뷰·원진처럼 세그먼트가 있는 사이트는 이 사전을 타지 않는다. +export const PLASTIC_AREAS = [ + { key: 'eye', label: '눈성형', kw: ['눈성형', '쌍꺼풀', '안검', '눈매', '트임', '눈밑', '상안검', '하안검'] }, + { key: 'nose', label: '코성형', kw: ['코성형', '코끝', '콧대', '비중격', '매부리', '코 재수술', '휜코', '들창코'] }, + { key: 'facial', label: '안면윤곽', kw: ['윤곽', '광대', '사각턱', '턱끝', '양악', '안면', 'v라인'] }, + { key: 'breast', label: '가슴성형', kw: ['가슴', '보형물', '유방', '모티바', '프리저베', '유두', '부유방'] }, + { key: 'lifting', label: '리프팅', kw: ['리프팅', '거상', '주름', '탄력', '안티에이징', '실리프팅'] }, + { key: 'body', label: '바디', kw: ['지방흡입', '지방이식', '복부', '허벅지', '팔뚝', '바디', '체형'] }, + { key: 'skin', label: '피부', kw: ['피부', '레이저', '보톡스', '필러', '스킨', '토닝', '여드름'] }, + { key: 'hair', label: '모발이식', kw: ['모발', '이식', '탈모', '헤어라인'] }, +]; +// 업종 감지용 어휘. 시술 페이지 제목·URL 에서 센다. +const DERM_VOCAB = /피부과|토닝|울쎄라|써마지|인모드|슈링크|리쥬란|스킨부스터|제모|여드름|모공|기미|잡티|탈모|다한증|홍조|레이저|필링|보톡스|톡신|필러|물광|색소|흉터|주름|탄력|사마귀|아토피|액취증|건선|피부질환|점빼기|검버섯|주근깨/i; +const PLASTIC_VOCAB = /성형(?!외과)|수술|절개|매몰|보형물|지방이식|지방흡입|양악|윤곽|거상|재수술|안검|쌍꺼풀|콧대|비중격|가슴|코끝|눈매|트임/; +// 시술 페이지로 볼 제목·URL 낱말 (업종별) const PROC_WORD = /(성형|수술|술|리프팅|보톡스|필러|이식|교정|축소|확대|재배치|절개|매몰|거상)/; -const procPages = byType('procedure').filter((p) => PROC_WORD.test(p.title ?? '') || PROC_WORD.test(decodeURIComponent(p.url))); -const areaOf = (u) => { const segs = new URL(u).pathname.split('/').filter(Boolean); const i = segs.findIndex((s) => /^(contents?|procedure|treatment|surgery)$/i.test(s)); return (i >= 0 ? segs[i + 1] : segs[0]) ?? 'etc'; }; +const DERM_PROC_WORD = new RegExp(`${DERM_VOCAB.source}|시술|치료|주사|관리|클리닉|피부`, 'i'); +// URL 세그먼트가 이런 값이면 영역 이름으로 쓰지 않는다 (오라클: /new/doc/index.php?doc=N) +const GENERIC_SEG = /^(new|old|doc|docs|page|pages|view|sub|content|contents|html|php|asp|jsp|index(\.\w+)?|m|mobile|ko|kr|en|web|www|\d+|[a-z]\d+|.*\.(php|asp|aspx|jsp|html?))$/i; + +function detectIndustry() { + const forced = opt('industry'); + if (forced) { if (!['derm', 'plastic'].includes(forced)) { console.error(`--industry 는 derm 또는 plastic (받은 값: ${forced})`); process.exit(2); } return { industry: forced, how: '인자' }; } + // 병원 이름에 업종이 있으면 그것으로. "피부과성형외과"처럼 둘 다 있으면 먼저 나온 쪽(등록 진료과목 순서로 본다) + const nm = `${fact.name ?? ''} ${fact.shortName ?? ''} ${index.pages.find((p) => p.type === 'home')?.title ?? ''}`; + const iDerm = nm.indexOf('피부과'), iPlastic = nm.indexOf('성형외과'); + if (iDerm >= 0 && (iPlastic < 0 || iDerm < iPlastic)) return { industry: 'derm', how: '병원 이름' }; + if (iPlastic >= 0) return { industry: 'plastic', how: '병원 이름' }; + // 이름에 없으면 시술 페이지 제목·URL 어휘를 센다. 본문이 이미지라 글자 수가 적은 페이지도 제목은 있으므로 status 200 전부를 본다 + const titles = index.pages.filter((p) => p.status === 200 && ['procedure', 'other', 'candidate'].includes(p.type)).map((p) => `${p.title ?? ''} ${p.h1 ?? ''} ${safeDecode(p.url)}`); + const derm = titles.filter((t) => DERM_VOCAB.test(t)).length, plastic = titles.filter((t) => PLASTIC_VOCAB.test(t)).length; + if (derm >= 3 && derm > plastic) return { industry: 'derm', how: `시술 페이지 어휘 (피부과 ${derm} > 성형외과 ${plastic})` }; + return { industry: 'plastic', how: `기본값 (피부과 어휘 ${derm}, 성형외과 어휘 ${plastic})` }; +} +const { industry, how: industryHow } = detectIndustry(); +const isDerm = industry === 'derm'; +const op = isDerm ? '시술' : '수술'; +const areasMax = Number(opt('areas', '0')) || (isDerm ? 8 : 3); + +// ---------- 시술 페이지 → 영역 ---------- +const pageCache = new Map(); +const loadPage = (p) => { if (!p.file) return null; if (!pageCache.has(p.file)) { const f = join(EV, p.file); pageCache.set(p.file, existsSync(f) ? JSON.parse(readFileSync(f, 'utf8')) : null); } return pageCache.get(p.file); }; +/** 제목(5점)·헤딩(2점)·본문(등장 횟수 × 0.5, 최대 2.5점) 키워드 점수로 사전의 영역 하나를 고른다. 2점 미만이면 null. */ +function classifyByKeywords(p, dict) { + const page = loadPage(p); + const title = `${p.title ?? ''} ${p.h1 ?? ''} ${safeDecode(p.url)}`.toLowerCase(); + const heads = (page?.items ?? []).filter((i) => i.kind === 'h').map((i) => i.text).join(' ').toLowerCase(); + const body = String(page?.text ?? '').toLowerCase().slice(0, 6000); + let best = null; + for (const a of dict) { + let score = 0; + for (const k of a.kw) { + const kk = k.toLowerCase(); + if (title.includes(kk)) score += 5; + if (heads.includes(kk)) score += 2; + const n = body.split(kk).length - 1; if (n) score += Math.min(n, 5) * 0.5; + } + if (score > (best?.score ?? 0)) best = { area: a, score }; + } + return best && best.score >= 2 ? best.area : null; +} +// URL 의 시술 세그먼트. /contents/facial/zygoma → facial, /breast/breast-augmentation/motiva → breast. 세그먼트가 없으면 'etc'(기존 동작), 일반어·숫자·파일명이면 null(키워드 폴백). +const areaOfUrl = (u) => { const segs = new URL(u).pathname.split('/').filter(Boolean); const i = segs.findIndex((s) => /^(contents?|procedure|treatment|surgery)$/i.test(s)); const seg = (i >= 0 ? segs[i + 1] : segs[0]); if (seg === undefined) return 'etc'; return GENERIC_SEG.test(seg) ? null : seg; }; + +// 시술 후보 페이지. 피부과는 procedure 외에 other·candidate 중 피부과 어휘가 있는 페이지도 넣는다(수집기 분류가 doc=N 페이지를 other 로 둘 수 있다). +const procPages = isDerm + ? uniq(pages.filter((p) => ['procedure', 'other', 'candidate'].includes(p.type))).filter((p) => DERM_PROC_WORD.test(`${p.title ?? ''} ${p.h1 ?? ''} ${safeDecode(p.url)}`)) + : byType('procedure').filter((p) => PROC_WORD.test(p.title ?? '') || PROC_WORD.test(safeDecode(p.url))); const areas = new Map(); -for (const p of procPages) { const a = areaOf(p.url); if (!areas.has(a)) areas.set(a, []); areas.get(a).push(p); } -const topAreas = [...areas.entries()].map(([area, list]) => ({ area, list: list.sort((a, b) => b.chars - a.chars), chars: list.reduce((s, p) => s + p.chars, 0) })).filter((a) => a.chars >= 1500).sort((a, b) => b.chars - a.chars).slice(0, 3); -const areaLabel = (a) => (a.list[0].title ?? '').replace(new RegExp(`[-–·|].*${name}.*$`), '').replace(/\(.*?\)/, '').replace(/당신만 봅니다|-\s*$/g, '').trim() || a.area; +for (const p of procPages) { + let key, meta = null; + if (isDerm) { const a = classifyByKeywords(p, DERM_AREAS); if (!a) continue; key = a.key; meta = a; } + else { key = areaOfUrl(p.url); if (!key) { const a = classifyByKeywords(p, PLASTIC_AREAS); key = a?.key ?? 'etc'; meta = a; } } + if (!areas.has(key)) areas.set(key, { area: key, list: [], meta }); + areas.get(key).list.push(p); +} +// 근거 충분성: 영역의 페이지 글자 합이 1,500자 이상이어야 글 하나를 기획한다 +const topAreas = [...areas.values()].map((a) => ({ ...a, list: a.list.sort((x, y) => y.chars - x.chars), chars: a.list.reduce((s, p) => s + p.chars, 0) })).filter((a) => a.chars >= 1500).sort((a, b) => b.chars - a.chars).slice(0, areasMax); +const areaLabel = (a) => a.meta?.label ?? ((a.list[0].title ?? '').replace(new RegExp(`[-–·|].*${name}.*$`), '').replace(/\(.*?\)/, '').replace(/당신만 봅니다|-\s*$/g, '').trim() || a.area); const AVOID = ['전후 사진', '가격 금액', '다른 병원·업계 평균 비교', '효과 보장', '환자 경험담']; +const DERM_AVOID = [...AVOID, '이벤트가·할인·% 표기', '정품 정량 인증 같은 인증 표현', '영구·완치·재발 없음 같은 효과 보장', '병원 페이지에 없는 장비·제제 이름', '허가 범위 밖 효능', '전후 사진·비포애프터를 보라는 유도']; +const CONDITION_ROWS = '시술시간·마취·통증 정도·회복(다운타임)·유지기간·권장 회차·권장 주기·시술자'; const candidates = []; const add = (c) => candidates.push(c); // ---------- 1층: 전용 페이지가 있을 때 ---------- if (byType('precautions').length) add({ id: 'precautions-guide', category: 'D', categoryLabel: '시술 정보', qbIds: ['D-06', 'D-09'], - title: '수술 전·후 주의사항에서 꼭 지켜야 할 것은 무엇인가요?', - intent: '수술 전(약·금식·흡연)과 후(부기·샤워·운동·음주)의 시점을 부위 공통 항목 중심으로 표. 부위별로 다른 값은 부위를 명시. 개인차 조건 필수.', + title: `${op} 전·후 주의사항에서 꼭 지켜야 할 것은 무엇인가요?`, + intent: isDerm + ? '시술 전(약·화장·자외선·시술 간격)과 후(세안·자외선 차단·사우나·화장·운동)의 시점을 시술 공통 항목 중심으로 표. 시술별로 다른 값은 시술명을 명시. 부작용(화상·색소침착·멍·부기·감염)은 페이지에 있는 항목만. 개인차 조건 필수.' + : '수술 전(약·금식·흡연)과 후(부기·샤워·운동·음주)의 시점을 부위 공통 항목 중심으로 표. 부위별로 다른 값은 부위를 명시. 개인차 조건 필수.', pages: urls('precautions', 'aftercare'), reviewer: rep, }); if (byType('safety').length) add({ id: 'safety-system', category: 'E', categoryLabel: '안전·마취', qbIds: ['E-01', 'E-02', 'E-04'], title: `${name}의 안전 시스템은 무엇으로 이루어져 있나요?`, - intent: '안전 시스템 페이지가 공개한 항목(마취 관리·응급 장비·검진·CCTV 등)을 항목 표로. 다른 병원·업계 평균과 비교하는 수치는 쓰지 않는다. 각 항목마다 상담에서 확인할 질문 하나.', + intent: isDerm + ? '안전 페이지가 공개한 항목(시술자 정책·장비 허가·응급 장비·부작용 대응 절차·정품 정량 서약)을 항목 표로. 정품 정량은 병원이 밝힌 사실로만 쓰고 인증 표현으로 넓히지 않는다. 다른 병원·업계 평균과 비교하는 수치는 쓰지 않는다. 각 항목마다 상담에서 확인할 질문 하나.' + : '안전 시스템 페이지가 공개한 항목(마취 관리·응급 장비·검진·CCTV 등)을 항목 표로. 다른 병원·업계 평균과 비교하는 수치는 쓰지 않는다. 각 항목마다 상담에서 확인할 질문 하나.', pages: urls('safety', 'checkup'), reviewer: anesth, }); if (byType('aftercare').length) add({ id: 'aftercare-program', category: 'D', categoryLabel: '시술 정보', qbIds: ['D-08', 'E-06'], - title: '수술 후 관리 프로그램은 무엇이 포함되고 언제까지 이어지나요?', - intent: '애프터케어 페이지의 부위별 프로그램·기간을 표로. 견적 포함 여부는 "병원 확인 대기".', + title: `${op} 후 관리 프로그램은 무엇이 포함되고 언제까지 이어지나요?`, + intent: `애프터케어 페이지의 ${isDerm ? '시술별' : '부위별'} 프로그램·기간을 표로. 견적 포함 여부는 "병원 확인 대기".`, pages: urls('aftercare', 'checkup'), reviewer: rep, }); if (byType('safety').length || byType('aftercare').length) add({ id: 'consult-questions', category: 'C', categoryLabel: '선택 기준', qbIds: ['C-02', 'E-08'], title: '상담에서 꼭 물어봐야 할 질문은 무엇인가요?', - intent: '안전·검진·애프터케어 페이지가 공개한 항목을 근거로 상담 질문 체크리스트 8~10개("- [ ]" 형식). 답을 적는 칸을 두고, 질문마다 왜 묻는지 한 줄.', + intent: isDerm + ? '안전·애프터케어 페이지가 공개한 항목을 근거로 상담 질문 체크리스트 8~10개("- [ ]" 형식). 시술자(의사 직접인지)·장비 이름과 허가·권장 회차와 주기·부작용 대응·비급여 고지 위치를 반드시 포함. 답을 적는 칸을 두고, 질문마다 왜 묻는지 한 줄.' + : '안전·검진·애프터케어 페이지가 공개한 항목을 근거로 상담 질문 체크리스트 8~10개("- [ ]" 형식). 답을 적는 칸을 두고, 질문마다 왜 묻는지 한 줄.', pages: urls('safety', 'aftercare', 'checkup'), reviewer: rep, }); @@ -76,7 +174,9 @@ if (byType('safety').length || byType('aftercare').length) add({ if (byType('about').length || byType('doctor').length) add({ id: 'what-is-clinic', category: 'A', categoryLabel: '병원 소개', qbIds: ['A-02', 'A-05', 'A-07'], title: `${name}${eun(name)} 어떤 병원인가요? 진료 분야·의료진 구성·위치`, - intent: '병원 소개·진료과·의료진 수·위치를 사실만으로 정리한다. 수상·방송 이력은 홈페이지 텍스트에 있는 것만. 표 하나(진료 분야 × 담당 원장). 팩트 시트의 전화·주소를 쓴다.', + intent: isDerm + ? '병원 소개·진료 분야·의료진 수·지점 수·본사(운영법인)·위치를 사실만으로 정리한다. 수상·방송 이력은 홈페이지 텍스트에 있는 것만. 표 하나(진료 분야 × 담당 원장, 다지점이면 지점 × 담당 원장). 팩트 시트의 전화·주소를 쓴다.' + : '병원 소개·진료과·의료진 수·위치를 사실만으로 정리한다. 수상·방송 이력은 홈페이지 텍스트에 있는 것만. 표 하나(진료 분야 × 담당 원장). 팩트 시트의 전화·주소를 쓴다.', pages: urls('about', 'doctor', 'facilities', 'direction'), reviewer: rep, }); if (byType('direction').length || byType('reservation').length) add({ @@ -85,7 +185,26 @@ if (byType('direction').length || byType('reservation').length) add({ intent: '오시는길·진료시간·주차·예약 경로를 표로. 팩트 시트 값과 오시는길·예약 페이지만 근거로. 확인되지 않은 시간·주차는 "전화 확인".', pages: urls('direction', 'reservation', 'about'), reviewer: null, }); -for (const a of topAreas) add({ +// 지점 선택 가이드 (피부과·다지점). 지점 유형 페이지가 있거나 팩트 시트·facts.draft 에 branches 가 있을 때만. +const branchPages = uniq([...byType('branches'), ...byType('branch')]); +const factBranches = Array.isArray(fact.branches) ? fact.branches : []; +const draftBranches = Array.isArray(factsDraft.branches) ? factsDraft.branches : Array.isArray(factsDraft.candidates?.branches) ? factsDraft.candidates.branches : []; +if (isDerm && (branchPages.length || factBranches.length > 1 || draftBranches.length > 1)) { + const srcUrls = [...factBranches, ...draftBranches].map((b) => b?.source ?? b?.src ?? b?.url).filter((u) => typeof u === 'string' && /^https?:/.test(u)); + add({ + id: 'branch-guide', category: 'B', categoryLabel: '방문·예약', qbIds: ['B-02', 'B-04'], + title: `${name} 지점은 어떻게 고르나요? 지점별 진료시간·담당 원장·예약 경로`, + intent: '팩트 시트 branches 와 지점 페이지가 공개한 지점명·주소·진료시간·담당 원장·예약 경로를 지점 × 항목 표로. 없는 칸은 "확인 대기". 지점 간 우열·추천 서술 없음. 팩트 시트 밖의 지점을 만들지 않는다. 글 하단 "검토 지점"은 사람이 정한다.', + pages: [...new Set([...branchPages.slice(0, 6).map((p) => p.url), ...srcUrls, ...urls('direction', 'about')])].slice(0, 8), reviewer: null, + }); +} +for (const a of topAreas) add(isDerm ? { + id: `procedure-${a.area.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, category: 'D', categoryLabel: '시술 정보', qbIds: [`${a.meta.qb}-01`], + title: `${name} ${areaLabel(a)} 시술은 무엇이 있고 시술시간·통증·회복·유지기간·권장 주기는 어떻게 되나요?`, + intent: `${areaLabel(a)} 시술 페이지들이 공개한 시술 종류·대상·장비(페이지에 적힌 이름만)를 정리하고, 시술마다 조건 표(${CONDITION_ROWS}) 8행을 만든다. 페이지에 없는 칸은 "확인"으로 두고 표 아래에 개인차와 병원 확인 대기를 쓴다. 시술자는 페이지에 "의사 직접"·"의사 감독" 표기가 없으면 "확인 대기". 부작용은 페이지에 있는 항목만 화상·색소침착·멍·부기·감염 같은 구체 어휘로. 효과 서술·전후 사진 언급·금액은 옮기지 않는다.`, + mustCover: [`시술 조건 표 8행(${CONDITION_ROWS})`, '시술 후 관리와 부작용(페이지에 있는 항목만)', '상담에서 확인할 것 3개(시술자·허가·회차 포함)'], + pages: a.list.slice(0, 4).map((p) => p.url), reviewer: rep, area: a, +} : { id: `procedure-${a.area.toLowerCase().replace(/[^a-z0-9]+/g, '-')}`, category: 'D', categoryLabel: '시술 정보', qbIds: ['D-01', 'D-06'], title: `${name} ${areaLabel(a)}${eun(areaLabel(a))} 어떤 방법이 있고 시술 시간·마취·회복은 어떻게 되나요?`, intent: `${areaLabel(a)} 시술 페이지들이 공개한 방법·대상·수술 시간·마취·입원·실밥·일상 복귀를 방법별 조건 표로. 페이지에 없는 칸은 "확인". 효과 서술은 옮기지 않고 절차·조건만.`, @@ -94,7 +213,9 @@ for (const a of topAreas) add({ if (!candidates.some((c) => c.id === 'consult-questions') && topAreas.length >= 2) add({ id: 'consult-questions', category: 'C', categoryLabel: '선택 기준', qbIds: ['C-02', 'E-08'], title: '상담에서 꼭 물어봐야 할 질문은 무엇인가요?', - intent: '시술 페이지가 공개한 방법·마취·회복 항목을 근거로, 상담에서 확인할 질문 체크리스트 8~10개("- [ ]" 형식). 질문마다 왜 묻는지 한 줄. 답을 적는 칸.', + intent: isDerm + ? '시술 페이지가 공개한 시술·장비·회차 항목을 근거로, 상담에서 확인할 질문 체크리스트 8~10개("- [ ]" 형식). 시술자(의사 직접인지)·장비 이름과 허가·권장 회차와 주기·부작용 대응·비급여 고지 위치를 반드시 포함. 질문마다 왜 묻는지 한 줄. 답을 적는 칸.' + : '시술 페이지가 공개한 방법·마취·회복 항목을 근거로, 상담에서 확인할 질문 체크리스트 8~10개("- [ ]" 형식). 질문마다 왜 묻는지 한 줄. 답을 적는 칸.', pages: [...new Set(topAreas.flatMap((a) => a.list.slice(0, 2).map((p) => p.url)))].slice(0, 5), reviewer: rep, }); @@ -104,12 +225,12 @@ const videosPath = join(SITE, 'src/data/videos.json'); const vdata = existsSync(videosPath) ? JSON.parse(readFileSync(videosPath, 'utf8')) : null; // 후보 = 정보형(info) 롱폼(쇼츠 아님, 90초 이상, 제목에 #shorts 없음)만. collect_youtube 가 붙인 info 판정을 그대로 쓴다. const longs = (vdata?.topLong ?? []).concat((vdata?.all ?? []).filter((v) => !v.isShort && v.duration >= 90 && v.info !== false && !/#\s?shorts/i.test(v.title))).filter((v, i, a) => a.findIndex((x) => x.id === v.id) === i); -// 병원 소개·방문 안내는 영상을 붙이지 않는다(주제와 맞는 영상이 없고 아무 영상이나 붙으면 오해를 준다) +// 병원 소개·방문 안내·지점 안내는 영상을 붙이지 않는다(주제와 맞는 영상이 없고 아무 영상이나 붙으면 오해를 준다) const KW = { - 'what-is-clinic': [], 'visit-guide': [], 'safety-system': ['안전', '마취', '응급', 'CCTV', '검진'], - 'precautions-guide': ['주의사항', '수술 후', '관리', '실밥', '부기', '붓기'], 'aftercare-program': ['관리', '애프터', '회복', '수술 후'], 'consult-questions': ['상담', '질문', '고를 때', '기준', '체크'], + 'what-is-clinic': [], 'visit-guide': [], 'branch-guide': [], 'safety-system': ['안전', '마취', '응급', 'CCTV', '검진', '시술자', '정품'], + 'precautions-guide': ['주의사항', `${op} 후`, '관리', '실밥', '부기', '붓기', '자외선'], 'aftercare-program': ['관리', '애프터', '회복', `${op} 후`], 'consult-questions': ['상담', '질문', '고를 때', '기준', '체크'], }; -const areaKw = (a) => { const t = areaLabel(a); return [t, ...t.split(/[·,/\s]+/).filter((w) => w.length >= 2), a.area]; }; +const areaKw = (a) => { if (a.meta) return [a.meta.label, ...a.meta.kw.slice(0, 8)]; const t = areaLabel(a); return [t, ...t.split(/[·,/\s]+/).filter((w) => w.length >= 2), a.area]; }; function matchVideos(c) { if (!longs.length) return []; const kws = (KW[c.id] ?? []).concat(c.area ? areaKw(c.area) : []).filter(Boolean); @@ -123,20 +244,20 @@ const norm = (u) => String(u).replace(/\/$/, '').toLowerCase(); function matchImages(c, pg) { const pages = new Set(pg.map(norm)); let pool = c.id === 'what-is-clinic' ? imgs.filter((i) => i.category === 'clinic') : imgs.filter((i) => ['procedure', 'equipment'].includes(i.category) && pages.has(norm(i.page.url))); - if (c.id === 'visit-guide' || c.id === 'consult-questions') pool = imgs.filter((i) => i.category === 'clinic').slice(0, 2); + if (['visit-guide', 'consult-questions', 'branch-guide'].includes(c.id)) pool = imgs.filter((i) => i.category === 'clinic').slice(0, 2); const pick = pool.slice(0, 4).map((i) => ({ src: i.src, alt: i.alt, caption: i.caption })); return { hero: pick[0], gallery: pick.slice(1, 4) }; } const posts = candidates.filter((c) => c.pages.length).slice(0, max).map(({ pages: pg, reviewer, area, ...c }) => { const { hero, gallery } = matchImages(c, pg); return { - ...c, avoid: AVOID, reviewerCandidate: reviewer ?? undefined, + ...c, industry, avoid: isDerm ? DERM_AVOID : AVOID, reviewerCandidate: reviewer ?? undefined, evidence: { pages: [...new Set(pg)], shorts: [], news: [], regulation: [], platform: false }, videos: matchVideos({ ...c, area }), ...(hero ? { hero, thumbnail: hero.src } : {}), gallery, }; }); -const out = { clinic, generatedAt: new Date().toISOString().slice(0, 10), note: '근거 수집 결과에서 자동 제안한 첫 배치. 사람이 확인·수정한 뒤 생성기에 넣는다(v2 §3-11).', evidenceTypes: index.byType, posts }; +const out = { clinic, industry, industryHow, generatedAt: new Date().toISOString().slice(0, 10), note: '근거 수집 결과에서 자동 제안한 첫 배치. 사람이 확인·수정한 뒤 생성기에 넣는다(v2 §3-11).', evidenceTypes: index.byType, posts }; const outPath = resolve(opt('out', join(SITE, 'briefs.json'))); writeFileSync(outPath, JSON.stringify(out, null, 2) + '\n'); -console.log(`brief ${posts.length}편 → ${outPath} (${posts.map((p) => p.id).join(', ') || '없음'})${topAreas.length ? ` · 시술 영역 ${topAreas.map((a) => `${a.area}(${a.list.length})`).join(', ')}` : ''}`); +console.log(`[${industry} · ${industryHow}] brief ${posts.length}편 → ${outPath} (${posts.map((p) => p.id).join(', ') || '없음'})${topAreas.length ? ` · 시술 영역 ${topAreas.map((a) => `${a.area}(${a.list.length})`).join(', ')}` : ''}`); diff --git a/templates/supporters-astro/scripts/export_template.mjs b/templates/supporters-astro/scripts/export_template.mjs index d6386c6..e928188 100644 --- a/templates/supporters-astro/scripts/export_template.mjs +++ b/templates/supporters-astro/scripts/export_template.mjs @@ -15,6 +15,7 @@ const TPL = join(SRC, 'scripts', 'template'); const EXCLUDE = [ 'node_modules', 'dist', '.astro', '.vercel', 'docs', 'src/content/posts', 'public/img', 'scripts/home_text.txt', 'scripts/gate/layout-baseline.json', 'scripts/template', 'README.md', + 'src/data/recoveryNotes.cache.json', // 시술 후 관리 안내 번역 캐시(병원별 산출물) ]; const excluded = (abs) => { const rel = relative(SRC, abs).split(sep).join('/'); diff --git a/templates/supporters-astro/scripts/gate/fixtures/before-after-phrase.html b/templates/supporters-astro/scripts/gate/fixtures/before-after-phrase.html new file mode 100644 index 0000000..07a0cce --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/before-after-phrase.html @@ -0,0 +1,2 @@ + +

    사례

    비포애프터 사진은 상담실에서 볼 수 있습니다.

    diff --git a/templates/supporters-astro/scripts/gate/fixtures/derm-cert-ok.html b/templates/supporters-astro/scripts/gate/fixtures/derm-cert-ok.html new file mode 100644 index 0000000..1fe5bd1 --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/derm-cert-ok.html @@ -0,0 +1,2 @@ + +

    정품 정량 서약

    병원은 홈페이지에서 정품·정량 사용을 밝힙니다. 이 매체는 전후 사진을 싣지 않습니다. 수술 전후 1:1 모니터링을 안내합니다.

    diff --git a/templates/supporters-astro/scripts/gate/fixtures/derm-cert-phrase.html b/templates/supporters-astro/scripts/gate/fixtures/derm-cert-phrase.html new file mode 100644 index 0000000..df8ff3b --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/derm-cert-phrase.html @@ -0,0 +1,2 @@ + +

    정품 정량

    이 병원은 정품 정량 인증을 받은 병원입니다. 전후 사진을 꼭 확인하세요.

    diff --git a/templates/supporters-astro/scripts/gate/fixtures/device-claim-approval.md b/templates/supporters-astro/scripts/gate/fixtures/device-claim-approval.md new file mode 100644 index 0000000..5ed3a41 --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/device-claim-approval.md @@ -0,0 +1,12 @@ +--- +expect: [DEVICE_CLAIM] +--- +## 장비 + +이 병원의 리프팅 장비는 식약처 허가를 받은 장비라고 홈페이지에 적혀 있습니다. 상담에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 의사 직접 | + +상담에서 확인합니다. diff --git a/templates/supporters-astro/scripts/gate/fixtures/device-claim-guarantee.md b/templates/supporters-astro/scripts/gate/fixtures/device-claim-guarantee.md new file mode 100644 index 0000000..17fd375 --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/device-claim-guarantee.md @@ -0,0 +1,12 @@ +--- +expect: [DEVICE_CLAIM] +--- +## 효과 + +레이저 제모는 5회면 영구 제모가 됩니다. 여드름은 치료 후 재발이 없습니다. 상담에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 의사 직접 | + +상담에서 확인합니다. diff --git a/templates/supporters-astro/scripts/gate/fixtures/device-claim-ok.md b/templates/supporters-astro/scripts/gate/fixtures/device-claim-ok.md new file mode 100644 index 0000000..177b19d --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/device-claim-ok.md @@ -0,0 +1,15 @@ +--- +expect: [] +sources: + - { label: "병원 홈페이지", url: "https://example.com/a", accessed: "2026-09-07", type: clinic } + - { label: "식약처 의료기기 허가 정보", url: "https://emedi.mfds.go.kr/", accessed: "2026-09-07", type: regulation } +--- +## 장비와 효과 + +홈페이지는 이 장비가 식약처 허가를 받았다고 씁니다. 허가는 해당 제품과 적응증에 한정되며 위험이 없다는 뜻은 아닙니다. 레이저 제모가 영구 제모라는 뜻은 아니며, 유지기간은 개인차가 있습니다. 반영구 화장은 별도 시술입니다. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 의사 감독 | + +상담에서 확인합니다. diff --git a/templates/supporters-astro/scripts/gate/fixtures/practitioner-missing.md b/templates/supporters-astro/scripts/gate/fixtures/practitioner-missing.md new file mode 100644 index 0000000..8730dfe --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/practitioner-missing.md @@ -0,0 +1,14 @@ +--- +expect: [] +expectWarn: [PRACTITIONER_MISSING] +industry: derm +category: D +--- +## 시술 조건 + +| 항목 | 병원 안내 | +|---|---| +| 시술시간 | 확인 | +| 마취 | 확인 | + +개인차가 있습니다. 상담에서 확인하세요. diff --git a/templates/supporters-astro/scripts/gate/fixtures/practitioner-plastic-skip.md b/templates/supporters-astro/scripts/gate/fixtures/practitioner-plastic-skip.md new file mode 100644 index 0000000..8d778b1 --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/practitioner-plastic-skip.md @@ -0,0 +1,13 @@ +--- +expect: [] +expectNoWarn: [PRACTITIONER_MISSING] +industry: plastic +category: D +--- +## 수술 조건 + +| 항목 | 병원 안내 | +|---|---| +| 수술 시간 | 확인 | + +개인차가 있습니다. 상담에서 확인하세요. diff --git a/templates/supporters-astro/scripts/gate/fixtures/practitioner-present.md b/templates/supporters-astro/scripts/gate/fixtures/practitioner-present.md new file mode 100644 index 0000000..c7195fa --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/practitioner-present.md @@ -0,0 +1,14 @@ +--- +expect: [] +expectNoWarn: [PRACTITIONER_MISSING] +industry: derm +category: D +--- +## 시술 조건 + +| 항목 | 병원 안내 | +|---|---| +| 시술시간 | 확인 | +| 시술자 | 확인 대기 | + +개인차가 있습니다. 상담에서 확인하세요. diff --git a/templates/supporters-astro/scripts/gate/fixtures/price-mention.md b/templates/supporters-astro/scripts/gate/fixtures/price-mention.md new file mode 100644 index 0000000..a8eb98f --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/price-mention.md @@ -0,0 +1,12 @@ +--- +expect: [PRICE_MENTION] +--- +## 시술 비용 + +울쎄라 300샷은 이벤트가 990,000원이고 정가 대비 30% 할인입니다. 상담에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 확인 대기 | + +상담에서 확인합니다. diff --git a/templates/supporters-astro/scripts/gate/fixtures/price-notice-link.md b/templates/supporters-astro/scripts/gate/fixtures/price-notice-link.md new file mode 100644 index 0000000..07f060c --- /dev/null +++ b/templates/supporters-astro/scripts/gate/fixtures/price-notice-link.md @@ -0,0 +1,12 @@ +--- +expect: [] +--- +## 시술 비용 구성 + +가격은 샷 수와 회차, 패키지 조건으로 구성됩니다. 금액은 병원의 비급여 진료비용 고지 페이지(https://example.com/notice)에서 확인하세요. + +| 항목 | 병원 안내 | +|---|---| +| 시술자 | 확인 대기 | + +상담에서 확인합니다. diff --git a/templates/supporters-astro/scripts/gate/fixtures/regulation-no-source.md b/templates/supporters-astro/scripts/gate/fixtures/regulation-no-source.md index f6650f7..e1f6fb9 100644 --- a/templates/supporters-astro/scripts/gate/fixtures/regulation-no-source.md +++ b/templates/supporters-astro/scripts/gate/fixtures/regulation-no-source.md @@ -1,5 +1,5 @@ --- -expect: [REGULATION_SOURCE_MISSING] +expect: [REGULATION_SOURCE_MISSING, DEVICE_CLAIM] --- ## 승인 diff --git a/templates/supporters-astro/scripts/gate/plan.test.mjs b/templates/supporters-astro/scripts/gate/plan.test.mjs new file mode 100644 index 0000000..bacadb0 --- /dev/null +++ b/templates/supporters-astro/scripts/gate/plan.test.mjs @@ -0,0 +1,130 @@ +// 회복기 스케줄러 계산 로직 검증. node --experimental-strip-types scripts/gate/plan.test.mjs +import { readFileSync } from 'node:fs'; +import assert from 'node:assert/strict'; +import { buildPlan, addDays, decodeHash, encodeHash, bookingUrl, googleFlightsUrl, buildIcs } from '../../src/lib/plan.ts'; +import { tourToPlaces, festivalsDuring, levelByDistance, bookingName } from '../../src/lib/tour.ts'; + +const here = (p) => new URL(p, import.meta.url); +const P = JSON.parse(readFileSync(here('../../src/data/procedures.json'), 'utf8')); +const PL = JSON.parse(readFileSync(here('../../src/data/places.json'), 'utf8')); +const TKO = JSON.parse(readFileSync(here('../../src/data/medicalTourismKo.json'), 'utf8')); +const byId = (id) => P.procedures.find((x) => x.id === id); +const nat = (code) => P.nationalities.list.find((x) => x.code === code); + +let n = 0; +const ok = (name, fn) => { fn(); n++; console.log(` ✓ ${name}`); }; + +ok('addDays: 월 경계', () => { assert.equal(addDays('2026-10-30', 3), '2026-11-02'); assert.equal(addDays('2026-11-01', -2), '2026-10-30'); }); + +ok('가슴: 입국일·실밥·출국·체류', () => { + const plan = buildPlan({ procedure: byId('breast'), surgeryDate: '2026-11-03', nationality: nat('JP'), prefs: ['shopping'] }, PL.places); + assert.equal(plan.arriveBy, '2026-11-01'); + assert.equal(plan.stitchDate, '2026-11-10'); + assert.equal(plan.earliestDeparture, '2026-11-13'); + assert.equal(plan.stayNights, 12); + assert.equal(plan.days[0].isArrival, true); + assert.equal(plan.days.at(-1).isDeparture, true); +}); + +ok('장거리 국적은 준비일 +1', () => { + const plan = buildPlan({ procedure: byId('breast'), surgeryDate: '2026-11-03', nationality: nat('US'), prefs: [] }, PL.places); + assert.equal(plan.arriveBy, '2026-10-31'); + assert.equal(plan.preOpDays, 3); +}); + +ok('윤곽: 유동식 단계에는 죽·스무디만 추천', () => { + const plan = buildPlan({ procedure: byId('contour'), surgeryDate: '2026-11-03', nationality: nat('JP'), prefs: ['food', 'shopping'] }, PL.places); + const day5 = plan.days.find((d) => d.offset === 5); + assert.equal(day5.level, 1); + assert.equal(day5.diet, 'liquid'); + for (const pick of day5.picks) { + assert.ok(pick.minLevel <= 1, `${pick.id} 등급 초과`); + if (pick.category === 'food') assert.ok(pick.dietOk.includes('liquid'), `${pick.id} 유동식 불가`); + } + assert.equal(plan.stitchDate, null); // 녹는 실 +}); + +ok('수술 당일·입원일·L0 은 추천 없음', () => { + const plan = buildPlan({ procedure: byId('breast'), surgeryDate: '2026-11-03', nationality: null, prefs: [] }, PL.places); + const d0 = plan.days.find((d) => d.offset === 0), d1 = plan.days.find((d) => d.offset === 1); + assert.deepEqual(d0.picks, []); assert.equal(d0.isSurgery, true); + assert.equal(d1.level, 0); assert.deepEqual(d1.picks, []); +}); + +ok('호텔은 일자 추천에 나오지 않음', () => { + const plan = buildPlan({ procedure: byId('skin'), surgeryDate: '2026-11-03', nationality: null, prefs: ['care'] }, PL.places); + for (const d of plan.days) for (const p of d.picks) assert.notEqual(p.category, 'hotel'); +}); + +ok('연속 이틀 같은 곳 반복 억제', () => { + const plan = buildPlan({ procedure: byId('eye'), surgeryDate: '2026-11-03', nationality: null, prefs: ['sightseeing'] }, PL.places); + const out = plan.days.filter((d) => d.picks.length && d.offset > 0); + let repeats = 0; + for (let i = 1; i < out.length; i++) for (const p of out[i].picks) if (out[i - 1].picks.some((q) => q.id === p.id)) repeats++; + assert.ok(repeats <= out.length, `연속 반복 ${repeats}`); +}); + +ok('해시 왕복', () => { + const s = { p: 'nose', d: '2026-12-01', l: 'en', n: 'US', pref: ['kpop', 'food'] }; + assert.deepEqual(decodeHash('#' + encodeHash(s)), s); + assert.equal(decodeHash('#d=notadate').d, undefined); +}); + +ok('예약 링크 형식', () => { + const u = new URL(bookingUrl('Hotel Cappuccino Seoul', '2026-11-01', '2026-11-13', 'en')); + assert.equal(u.hostname, 'www.booking.com'); + assert.equal(u.searchParams.get('checkin'), '2026-11-01'); + assert.ok(googleFlightsUrl('2026-11-01', '2026-11-13', 'en').startsWith('https://www.google.com/travel/flights')); +}); + +ok('ICS 에 일정 4개', () => { + const plan = buildPlan({ procedure: byId('nose'), surgeryDate: '2026-11-03', nationality: null, prefs: [] }, PL.places); + const ics = buildIcs(plan, { arrive: 'Arrive', surgery: 'Surgery', stitch: 'Stitch', departure: 'Depart' }, 'Test'); + assert.equal((ics.match(/BEGIN:VEVENT/g) || []).length, 4); + assert.ok(ics.includes('DTSTART;VALUE=DATE:20261103')); +}); + +ok('규칙표 정합성: 숫자마다 status, provisional 은 source 없어도 됨, clinic 은 source 필수', () => { + for (const p of P.procedures) { + for (const k of ['preOpDays', 'hospitalNights', 'stitchRemovalDay', 'earliestDepartureDay']) { + assert.ok(['clinic', 'provisional'].includes(p[k].status), `${p.id}.${k} status`); + if (p[k].status === 'clinic') assert.ok(p[k].source, `${p.id}.${k} clinic 인데 source 없음`); + } + for (const s of [...p.outingLevels, ...p.diet]) if (s.status === 'clinic') assert.ok(s.source, `${p.id} 단계 clinic 인데 source 없음`); + for (const c of p.constraints) assert.ok(P.constraints[c], `${p.id} 미정의 제약 ${c}`); + for (const s of p.sources) assert.ok(P.clinicSources.some((x) => x.id === s), `${p.id} 미정의 출처 ${s}`); + } + for (const pl of PL.places) { assert.ok(PL.categories[pl.category], `${pl.id} 카테고리`); assert.ok(pl.name.ko && pl.name.en, `${pl.id} 이름`); } +}); + +const HAS_TOUR = Object.values(TKO.places ?? {}).some((v) => Array.isArray(v) && v.length); // 템플릿 빈 데이터면 관광공사 검사는 건너뛴다 +ok('TourAPI 어댑터: 카테고리 매핑, 사우나 제외, 음식점은 일반식만, 거리 등급', () => { + assert.equal(levelByDistance(400), 1); assert.equal(levelByDistance(2500), 2); assert.equal(levelByDistance(9000), 3); + assert.equal(bookingName('K-그랜드 호스텔 강남 1(K-GRAND HOSTEL GANGNAM1)'), 'K-GRAND HOSTEL GANGNAM1'); + if (!HAS_TOUR) { console.log(' (관광공사 데이터 없음: 변환 검사 건너뜀)'); return; } + const tp = tourToPlaces(TKO, 'ko'); + assert.ok(tp.length > 50, `변환 ${tp.length}건`); + assert.ok(tp.every((p) => p.source === 'tourapi')); + assert.ok(!tp.some((p) => p.id.startsWith('tour-wellness-')), '사우나·스파가 후보에 들어감'); + assert.ok(tp.filter((p) => p.category === 'food').every((p) => p.dietOk.length === 1 && p.dietOk[0] === 'normal')); +}); + +ok('큐레이션이 TourAPI 보다 먼저 나오고 유동식 단계에는 TourAPI 음식점이 없음', () => { + if (!HAS_TOUR) return; + const tp = tourToPlaces(TKO, 'ko'); + const all = [...PL.places.map((x) => ({ ...x, source: 'curated' })), ...tp]; + const plan = buildPlan({ procedure: byId('contour'), surgeryDate: '2026-11-03', nationality: null, prefs: ['food'] }, all); + for (const d of plan.days.filter((d) => d.diet === 'liquid')) for (const p of d.picks) assert.ok(!(p.source === 'tourapi' && p.category === 'food'), `${d.date} ${p.id}`); + const first = plan.days.find((d) => d.picks.length); + assert.equal(first.picks[0].source, 'curated'); +}); + +ok('축제: 체류 기간과 겹치는 것만, L3 날에만 붙음', () => { + if (!HAS_TOUR) return; + const fest = festivalsDuring(TKO, '2026-11-01', '2026-11-17'); + for (const f of fest) assert.ok(f.start <= '2026-11-17' && f.end >= '2026-11-01'); + const plan = buildPlan({ procedure: byId('skin'), surgeryDate: '2026-11-03', nationality: null, prefs: [], festivals: fest }, PL.places); + for (const d of plan.days) if (d.festivals.length) assert.ok(d.level >= 3, `${d.date} L${d.level}`); +}); + +console.log(`plan.test: ${n}건 통과`); diff --git a/templates/supporters-astro/scripts/gate/rules.mjs b/templates/supporters-astro/scripts/gate/rules.mjs index 2a4e19e..c3cf78d 100644 --- a/templates/supporters-astro/scripts/gate/rules.mjs +++ b/templates/supporters-astro/scripts/gate/rules.mjs @@ -45,7 +45,7 @@ export function postTextFields(data, body) { } // ---------- §3-1 고객 화면과 운영자 설명의 분리 ---------- -export const OPERATOR_VOCAB = /답변엔진|AI 인용|AEO|GEO|질문 뱅크|QB [A-G]|실측|단일 원본|수집 기준|API 집계|임베드|복제|의료법 제\d+조|롱폼|쇼츠 분류/g; +export const OPERATOR_VOCAB = /답변엔진|AI 인용|AEO|GEO|질문 뱅크|QB [A-G]|실측|단일 원본|수집 기준|API 집계|임베드|(? s.match(re)).find(Boolean); + if (m) out.push(r(E, 'PRICE_MENTION', `${field}: 금액·할인 표기 "${m[0]}" (금액은 쓰지 않고 병원의 비급여 진료비용 고지 페이지로 안내)`)); + } + } + return out; +} + +/** PRACTITIONER_MISSING (warn). 근거: 의료법 27조(무면허 의료행위. 레이저·주사 시술은 의사가 해야 하고 간호사 위임은 대리시술) + * · PRD §9 시술자 표기. 피부과(derm) 시술 글(category D)에 시술자 표기(의사 직접 / 의사 감독 / 시술자 행의 "확인 대기") 중 하나가 없으면 경고. + * "시술자" 낱말이 있으면 조건 표 시술자 행으로 본다(값이 "확인 대기"여도 표기는 한 것). 성형외과 글은 검사하지 않는다. */ +export const PRACTITIONER_MARK = /시술자|(의사|원장|전문의|의료진)(가|이|의|께서)?\s*직접|(의사|원장|전문의|의료진)(의|이|가)?\s*(감독|입회|관리\s*하에)/; +export function checkPractitioner(data, fields, industry = 'plastic') { + if (industry !== 'derm' || data.category !== 'D') return []; + const hit = fields.some((f) => PRACTITIONER_MARK.test(f.text)); + return hit ? [] : [r(W, 'PRACTITIONER_MISSING', '피부과 시술 글에 시술자 표기 없음 (조건 표 시술자 행에 "의사 직접" / "의사 감독" / "확인 대기" 중 하나)')]; +} + +/** DEVICE_CLAIM (error). 근거: 의료기기법 24조(허가·인증 범위 밖 효능·효과 표현 금지) · 약사법 68조(전문의약품 대중광고 제한) + * · 의료법 56조 2항(효과 보장·과장). 두 갈래. + * (1) "FDA 승인·식약처 허가" 같은 허가 표현이 있는데 sources 에 regulation 타입이 없으면 error (허가 정보는 규제 원문 링크로만). + * (2) "영구·완치·재발 없음·100%·평생 유지" 류 효과 보장 표현은 근거와 무관하게 error. 부정문("영구적이라는 뜻은 아닙니다")은 통과. + * "반영구"(반영구 화장)는 시술명이라 제외한다. 뉴스 제목은 checkNewsItems 가 따로 보므로 여기에는 넣지 않는다. */ +export const DEVICE_APPROVAL = /식약처\s*(허가|인증|승인)|MFDS|KFDA|FDA\s*(승인|허가|인증|클리어|clear)|CE\s*(인증|마크)/i; +export const EFFECT_GUARANTEE = [ + { re: /(? s.type === 'regulation'); + for (const { field, text } of fields) { + for (const s of sentences(text)) { + if (!hasReg) { + const a = s.match(DEVICE_APPROVAL); + if (a) out.push(r(E, 'DEVICE_CLAIM', `${field}: 허가 표현 "${a[0]}" 이 있는데 regulation 타입 원문 소스가 없음 (허가 정보는 규제 원문 링크로)`)); + } + if (GUARANTEE_NEGATION.test(s)) continue; + for (const g of EFFECT_GUARANTEE) { + const m = s.match(g.re); + if (m) { out.push(r(E, 'DEVICE_CLAIM', `${field}: 효과 보장 표현(${g.why}) "${m[0]}" · "${s.slice(0, 60)}"`)); break; } + } + } + } + return out; +} + // ---------- 묶음: 글 한 편의 소스 검사 ---------- -export function checkPostSource({ data, body }, { physicians, supporters } = {}) { +// industry: 'plastic' | 'derm'. 주지 않으면 frontmatter industry → 환경변수 SUPPORTERS_INDUSTRY → plastic 순으로 정한다. +export function checkPostSource({ data, body }, { physicians, supporters, industry } = {}) { const fields = postTextFields(data, body); + const ind = resolveIndustry(industry, data); return [ ...checkSourcesType(data), ...checkRegulationSource(data, fields), @@ -317,6 +401,9 @@ export function checkPostSource({ data, body }, { physicians, supporters } = {}) ...checkReview(data, physicians, supporters), ...checkVideoTitles([...(data.videos ?? []), ...(data.video ? [data.video] : [])], { label: 'frontmatter' }), ...checkOriginalContent(data, body), + ...checkPriceMention(fields), + ...checkDeviceClaim(data, fields), + ...checkPractitioner(data, fields, ind), ...fields.flatMap((f) => checkPlainEndings(f.text, f.field)), ...fields.flatMap((f) => checkPressVoice(f.text, f.field)), ]; diff --git a/templates/supporters-astro/scripts/gate/test.mjs b/templates/supporters-astro/scripts/gate/test.mjs index 68ed5a9..56b7bdf 100644 --- a/templates/supporters-astro/scripts/gate/test.mjs +++ b/templates/supporters-astro/scripts/gate/test.mjs @@ -1,5 +1,5 @@ // 게이트 규칙 회귀 테스트. 빌드 없이 돈다. -// 1) fixtures/*.md : frontmatter `expect:` 에 적힌 error 코드가 실제로 나와야 통과 +// 1) fixtures/*.md : frontmatter `expect:` 에 적힌 error 코드가 실제로 나와야 통과 (`expectWarn:`·`expectNoWarn:` 으로 warn 코드도 본다) // 2) fixtures/*.html: 첫 줄 주석의 expect 코드 (none = 오류 0) // 3) src/content/posts/*.md 전편이 소스 규칙 error 0 이어야 통과 (정답지 회귀) // node scripts/gate/test.mjs @@ -23,17 +23,23 @@ const ok = (name, msg = '') => { pass++; console.log(` ✓ ${name}${msg ? ' · const bad = (name, msg) => { failCount++; console.error(` ✗ ${name}: ${msg}`); }; const codes = (list, level = R.E) => [...new Set(list.filter((x) => x.level === level).map((x) => x.code))]; -// 1) md 픽스처 +// 1) md 픽스처. expect = 나와야 하는 error 코드(정확히 일치), expectWarn = 나와야 하는 warn 코드, expectNoWarn = 나오면 안 되는 warn 코드 for (const f of readdirSync(FIX).filter((x) => x.endsWith('.md'))) { const { data, body } = R.parseMarkdown(readFileSync(join(FIX, f), 'utf8')); - const { expect = [], ...fm } = data; + const { expect = [], expectWarn = [], expectNoWarn = [], ...fm } = data; const merged = { ...base, ...fm }; - const got = codes(R.checkPostSource({ data: merged, body }, fxCtx)); + const all = R.checkPostSource({ data: merged, body }, fxCtx); + const got = codes(all); + const gotWarn = codes(all, R.W); const missing = expect.filter((c) => !got.includes(c)); const extra = got.filter((c) => !expect.includes(c)); + const missingWarn = expectWarn.filter((c) => !gotWarn.includes(c)); + const badWarn = expectNoWarn.filter((c) => gotWarn.includes(c)); if (missing.length) bad(f, `기대한 오류가 안 나옴: ${missing.join(', ')} (실제: ${got.join(', ') || '없음'})`); else if (extra.length) bad(f, `기대 밖 오류: ${extra.join(', ')}`); - else ok(f, got.join(', ')); + else if (missingWarn.length) bad(f, `기대한 경고가 안 나옴: ${missingWarn.join(', ')} (실제 경고: ${gotWarn.join(', ') || '없음'})`); + else if (badWarn.length) bad(f, `나오면 안 되는 경고: ${badWarn.join(', ')}`); + else ok(f, [...got, ...expectWarn.map((c) => `warn:${c}`)].join(', ') || '오류 0'); } // 2) html 픽스처 (dist 규칙) @@ -109,5 +115,38 @@ negGot.length ? bad('부정문 통과', negGot.map((x) => x.msg).join(' | ')) : re.length ? bad('news.json 회귀', `${re.length}건: ` + re.slice(0, 3).map((x) => x.msg).join(' | ')) : ok('news.json 전 항목 규칙 통과', `${real.items.length}건`); } +// 8) 피부과 규칙 단위 검사 (PRD §9). 금액·허가·효과 보장·시술자 +{ + const F = (text) => [{ field: 'body', text }]; + const price = R.checkPriceMention(F('울쎄라 300샷 이벤트가 99만원. 리쥬란 15만 원부터. ₩150,000. 1+1 행사.')); + price.length >= 3 ? ok('금액 표기 검출', `${price.length}건`) : bad('금액 표기 검출', JSON.stringify(price)); + const priceOk = R.checkPriceMention(F('수술 후 5~7일이면 일상생활이 가능합니다. 원장 3명이 진료합니다. 2026년 9월 기준입니다. 전화는 02-539-1177입니다. 금액은 비급여 진료비용 고지 페이지에서 확인하세요.')); + priceOk.length ? bad('금액 오탐', priceOk.map((x) => x.msg).join(' | ')) : ok('일수·인원·연도·전화번호·고지 안내 문장 통과'); + const dev = R.checkDeviceClaim({ sources: [] }, F('이 장비는 FDA 승인과 식약처 허가를 받았습니다.')); + dev.some((x) => x.code === 'DEVICE_CLAIM') ? ok('허가 표현 + regulation 소스 없음 검출') : bad('허가 표현 검출', JSON.stringify(dev)); + const devOk = R.checkDeviceClaim({ sources: [{ type: 'regulation' }] }, F('이 장비는 식약처 허가를 받았습니다. 허가가 위험이 없다는 뜻은 아닙니다. 영구 제모라는 표현은 쓰지 않습니다.')); + devOk.length ? bad('허가 표현 오탐', devOk.map((x) => x.msg).join(' | ')) : ok('regulation 소스 있는 허가 표현·부정문 통과'); + const guar = R.checkDeviceClaim({ sources: [] }, F('한 번이면 평생 유지됩니다. 기미는 완치됩니다.')); + guar.length >= 2 ? ok('효과 보장 표현 검출', `${guar.length}건`) : bad('효과 보장 검출', JSON.stringify(guar)); + const semi = R.checkDeviceClaim({ sources: [] }, F('반영구 화장은 별도 시술입니다. 유지기간은 개인차가 있습니다.')); + semi.length ? bad('반영구 오탐', semi[0].msg) : ok('"반영구" 시술명 통과'); + const pr = R.checkPractitioner({ category: 'D' }, F('시술시간은 확인입니다.'), 'derm'); + pr.length === 1 && pr[0].code === 'PRACTITIONER_MISSING' && pr[0].level === R.W ? ok('시술자 표기 없음 경고 (derm·D)') : bad('시술자 경고', JSON.stringify(pr)); + const prSkip = [...R.checkPractitioner({ category: 'D' }, F('시술시간은 확인입니다.'), 'plastic'), ...R.checkPractitioner({ category: 'A' }, F('시술시간은 확인입니다.'), 'derm'), ...R.checkPractitioner({ category: 'D' }, F('원장이 직접 시술합니다.'), 'derm')]; + prSkip.length ? bad('시술자 경고 오탐', JSON.stringify(prSkip)) : ok('성형외과·비시술 글·"원장이 직접" 표기는 경고 없음'); + const banned = R.checkBannedBody('정품 정량 인증 병원입니다. 비포애프터 사진을 보세요.'); + banned.length >= 2 ? ok('피부과 금칙어(정품 정량 인증·비포애프터) 검출', `${banned.length}건`) : bad('피부과 금칙어', JSON.stringify(banned)); + const bannedOk = R.checkBannedBody('병원은 정품·정량 사용을 밝힙니다. 이 매체는 전후 사진을 싣지 않습니다. 영수증 인증 후기입니다.'); + bannedOk.length ? bad('피부과 금칙어 오탐', bannedOk.map((x) => x.msg).join(' | ')) : ok('정품 정량 서약 사실·전후 사진 원칙 서술 통과'); + // 정답지 18편: 피부과 규칙을 derm 으로 강제해도 error 0 (PRICE_MENTION·DEVICE_CLAIM 은 업종 무관, PRACTITIONER 는 경고라 error 에 안 잡힘) + let dermErr = 0; + for (const f of readdirSync(POSTS).filter((x) => x.endsWith('.md'))) { + const parsed = R.parseMarkdown(readFileSync(join(POSTS, f), 'utf8')); + const errs = R.checkPostSource(parsed, { ...ctx, industry: 'derm' }).filter((x) => x.level === R.E && ['PRICE_MENTION', 'DEVICE_CLAIM'].includes(x.code)); + if (errs.length) { dermErr += errs.length; errs.forEach((e) => bad(`posts/${f} (derm)`, `[${e.code}] ${e.msg}`)); } + } + if (!dermErr) ok('정답지 전편 PRICE_MENTION·DEVICE_CLAIM 0건'); +} + console.log(`통과 ${pass} · 실패 ${failCount}`); if (failCount) process.exit(1); diff --git a/templates/supporters-astro/scripts/gen/evidence.mjs b/templates/supporters-astro/scripts/gen/evidence.mjs index 5b5515a..eab74a5 100644 --- a/templates/supporters-astro/scripts/gen/evidence.mjs +++ b/templates/supporters-astro/scripts/gen/evidence.mjs @@ -14,7 +14,12 @@ export function normUrl(u) { const x = new URL(u); let s = x.host.replace(/^www\./, '') + x.pathname; try { s = decodeURIComponent(s); } catch { /* 그대로 */ } - return s.replace(/\/+$/, '').toLowerCase(); + s = s.replace(/\/+$/, '').toLowerCase(); + // 쿼리가 곧 페이지인 사이트(오라클 index.php?doc=N)를 위해 추적 파라미터를 뺀 쿼리를 키에 넣는다. collect_evidence.normalize 와 같은 규칙. + // 2026-09-10: 쿼리를 지우자 시술 페이지 84개가 마지막 한 페이지(휴지기탈모)로 겹쳐 글 근거가 전부 틀렸다. + const keep = [...x.searchParams.entries()].filter(([k]) => !/^(utm_|fbclid|gclid|ref$|_ga)/i.test(k)).sort(([a], [b]) => a.localeCompare(b)); + if (keep.length) s += '?' + keep.map(([k, v]) => `${k}=${v}`).join('&').toLowerCase(); + return s; } catch { return String(u).replace(/\/+$/, '').toLowerCase(); } } @@ -35,7 +40,10 @@ export function loadEvidence(evDir) { return { clinic: index.clinic, start: index.start, fetchedAt: index.fetchedAt, pages, byUrl, doctors, homeText }; } -/** 페이지 items → 읽기용 텍스트. 표는 마크다운 행으로. */ +/** ocr_evidence.mjs 가 붙인 OCR 섹션(source: "ocr"). 이미지 글자를 기계로 읽은 것이라 원문(HTML)과 구분해 표기한다 */ +export const ocrSections = (p) => (p.sections ?? []).filter((s) => s?.source === 'ocr' && s.text); + +/** 페이지 items → 읽기용 텍스트. 표는 마크다운 행으로. OCR 섹션은 뒤에 출처 표기와 함께 붙인다. */ export function pageToText(p, { maxChars = 9000 } = {}) { const lines = []; for (const it of p.items ?? []) { @@ -45,6 +53,7 @@ export function pageToText(p, { maxChars = 9000 } = {}) { else if (it.kind === 'table') for (const row of it.rows ?? []) lines.push('| ' + row.map((c) => String(c).replace(/\|/g, '/')).join(' | ') + ' |'); else lines.push(it.text); } + for (const s of ocrSections(p)) lines.push('', `[병원 페이지 이미지 글자 OCR] ${s.heading ?? ''} (이미지 ${s.images?.length ?? 1}장을 기계로 읽은 병원 페이지 원문. 병원이 공개한 자료로 취급해 근거로 쓴다. 글자가 깨졌거나 문맥이 맞지 않는 부분만 쓰지 않고, 수치·제품명은 문장이 온전할 때만 옮긴다)`, s.text); let t = lines.join('\n').replace(/\n{3,}/g, '\n\n').trim(); if (t.length > maxChars) t = t.slice(0, maxChars) + `\n…(이 페이지는 ${t.length - maxChars}자가 더 있으나 생략됨. 생략된 부분의 사실은 쓰지 않는다)`; return t; @@ -71,8 +80,9 @@ export function buildContext(brief, { ev, fact, authors, videos, news, answers, const p = ev.byUrl.get(normUrl(url)); if (!p) { missing.push(`병원 페이지가 근거 수집 결과에 없음: ${url}`); return; } const imgText = Array.isArray(p.flags) ? p.flags.includes('textInImages') : Boolean(p.flags?.textInImages); - if (!p.items?.length) { missing.push(`병원 페이지 본문 0자${imgText ? ' (이미지 글자)' : ''}: ${url}`); return; } - cparts.push(`### [C${cparts.length + 1}] ${p.title ?? ''}\nURL: ${p.url}\n수집일: ${p.fetchedAt}\n\n${pageToText(p)}`); + const ocr = ocrSections(p); + if (!p.items?.length && !ocr.length) { missing.push(`병원 페이지 본문 0자${imgText ? ' (이미지 글자, OCR 없음)' : ''}: ${url}`); return; } + cparts.push(`### [C${cparts.length + 1}] ${p.title ?? ''}\nURL: ${p.url}\n수집일: ${p.fetchedAt}${ocr.length ? ' · 본문 일부 또는 전부가 이미지 글자 OCR' : ''}\n\n${pageToText(p)}`); pushSource({ label: `${clinicName} 홈페이지 · ${cleanTitle(p.title, clinicName)}`, url: p.url, accessed: p.fetchedAt ?? today, type: 'clinic' }); }); parts.push(`## 1. 병원 공식 페이지 원문 (문장을 그대로 옮기지 말 것. 40자 이상 연속 일치는 발행 차단)\n\n${cparts.length ? cparts.join('\n\n') : '(제공된 페이지 없음)'}`); diff --git a/templates/supporters-astro/scripts/gen/prompt.mjs b/templates/supporters-astro/scripts/gen/prompt.mjs index f4efdc0..a9252c2 100644 --- a/templates/supporters-astro/scripts/gen/prompt.mjs +++ b/templates/supporters-astro/scripts/gen/prompt.mjs @@ -1,5 +1,6 @@ -// 글 생성 프롬프트와 출력 스키마. 규칙의 근거는 docs/NEXT_SESSION_SUPPORTERS_AUTOBUILD_v2.md §3·§4·§12-2. +// 글 생성 프롬프트와 출력 스키마. 규칙의 근거는 docs/NEXT_SESSION_SUPPORTERS_AUTOBUILD_v2.md §3·§4·§12-2, 피부과는 Dermatology Supporters PRD §7·§9. // 여기 적힌 규칙은 대부분 scripts/gate/rules.mjs 와 generate_posts.mjs 의 수치 대조·검증 단계가 다시 검사한다. 프롬프트는 1차 방어, 게이트가 최종. +// 업종: brief.industry 가 'derm'(피부과)이면 userPrompt 에 피부과 추가 규칙 블록(DERM_RULES)이 붙는다. 성형외과(plastic) 경로의 문자열은 바뀌지 않는다. export const SYSTEM_PROMPT = `당신은 성형외과 서포터즈 매체의 편집자입니다. 병원이 지원하는 매체이므로 광고로 읽히지 않으려면 사실만, 근거가 있는 것만 씁니다. 독자는 상담을 앞둔 사람입니다. 독자가 상담에서 무엇을 묻고 무엇을 확인해야 하는지 알게 하는 것이 글의 목적입니다. @@ -48,20 +49,39 @@ export const SYSTEM_PROMPT = `당신은 성형외과 서포터즈 매체의 편 # 출력 JSON 스키마대로만 출력합니다. pending 에는 독자가 물었을 법한데 근거에 없어 쓰지 못한 사실을 한 줄씩 적습니다(병원 확인 요청 목록이 됩니다). usedRefs 에는 실제로 인용한 근거 태그(C1, S2 형식)만 적습니다.`; +// ---------- 피부과 추가 규칙 (industry = derm 일 때만 userPrompt 에 붙는다) ---------- +// 근거: PRD §7 시술 조건 표(표준 블록), §9 규정(의료법 45조 비급여 고지 · 의료기기법 24조 · 약사법 68조 · 의료법 27조 시술자 · 56조 2항). +// 게이트 대응: PRICE_MENTION · DEVICE_CLAIM · PRACTITIONER_MISSING · BANNED_PHRASE(정품 정량 인증·비포애프터). +export const DERM_CONDITION_ROWS = ['시술시간', '마취', '통증 정도', '회복(다운타임)', '유지기간', '권장 회차', '권장 주기', '시술자']; +export const DERM_SIDE_EFFECT_VOCAB = ['화상', '색소침착', '멍', '부기', '감염', '붉어짐', '물집', '가려움', '건조']; +export const DERM_RULES = `# 피부과 추가 규칙 (이 글은 피부과 서포터즈 매체의 글입니다. 위 지시의 "성형외과"는 "피부과"로, "수술"은 "시술"로 읽습니다) +- 시술 조건 표: 시술을 다루는 글(분류 D 는 필수)에는 시술마다 조건 표를 넣습니다. 행 8개를 이 순서로 씁니다: ${DERM_CONDITION_ROWS.join(' · ')}. 열은 "항목 | 병원 안내 | 근거" 세 개이고 근거 열에는 병원 제공 / 원장 설명 / 제품 정보 / 규제 중 하나를 씁니다. 근거에 없는 칸은 "확인"이라고 쓰고, 표 바로 아래 문단에 개인차와 병원 확인 대기를 씁니다. 칸을 채우려고 근거 밖 수치를 만들지 않습니다. 수치 칸에는 "영상 사례" 또는 "홈페이지 안내 기준"을 붙입니다. +- 시술자 행: 병원 페이지나 병원 확인 답변에 "의사 직접" 또는 "의사 감독" 표기가 있으면 그대로 옮기고, 없으면 "확인 대기"라고 씁니다. 간호사·관리사가 시술한다고 쓰지 않습니다. 시술 글에는 본문 어딘가에 반드시 "시술자" 항목이 있어야 합니다. +- 상표·장비·제제: 병원 페이지에 적힌 장비·제제 이름만 씁니다(예: 페이지에 울쎄라가 있으면 울쎄라, 없으면 "초음파 리프팅 장비"). 허가 정보(식약처 허가·FDA 승인)는 규제 원문 [R]이 있을 때만, 해당 제품·해당 적응증으로 한정해 쓰고 원문 링크로 안내합니다. [R]이 없으면 허가를 언급하지 않고 "장비의 허가 정보는 상담에서 확인하세요"로 씁니다. 제품명을 제목이나 요약 첫 줄에 앞세우지 않습니다. 전문의약품(보툴리눔 톡신, 의약품 분류 필러, 이소트레티노인)은 시술 설명 범위에서만 쓰고 제품 홍보로 읽히게 쓰지 않습니다. +- 금액 금지: 원·만원·₩ 금액, %할인, 이벤트가·특가·1+1 을 어디에도 쓰지 않습니다. 가격은 샷 수·회차·패키지 조건 같은 "구성"만 설명하고, 금액은 병원의 비급여 진료비용 고지 페이지에서 확인하라고 안내합니다. +- 인증 표현: "정품 정량"은 병원이 밝힌 사실로만 씁니다("병원은 정품·정량 사용을 밝힙니다"). "정품 정량 인증"처럼 인증 어휘로 넓히지 않습니다. 전후 사진·비포애프터를 보라고 유도하는 문장을 쓰지 않습니다. +- 효과 표현: 영구·완치·재발 없음·100%·평생 유지·한 번으로 끝 을 쓰지 않습니다. 유지기간은 근거 수치 그대로 "개인차"와 함께 씁니다. 근거에 없는 유지기간은 "확인"입니다. +- 부작용: 시술 글에는 "## 시술 후 관리와 부작용" 절을 두고, 근거에 있는 부작용을 ${DERM_SIDE_EFFECT_VOCAB.slice(0, 5).join('·')} 같은 구체 어휘로 씁니다. 근거에 없으면 "부작용 항목은 병원 공개 자료에 없습니다. 상담에서 확인하세요."라고 씁니다. 부작용을 축소하는 표현("거의 없음", "미미함")은 근거 문장에 있어도 옮기지 않습니다. +- 회차·주기: 권장 회차와 권장 주기는 근거에 있는 값만 쓰고, 없으면 "상담에서 정합니다"로 닫습니다. 다른 시술과의 병행 가능 여부는 근거에 있을 때만 씁니다. +- 다지점: 지점별로 다른 값(진료시간·담당 원장·장비)은 지점을 명시합니다. 팩트 시트 branches 밖의 지점을 만들지 않습니다.`; + +export const isDermBrief = (brief) => brief?.industry === 'derm' || (!brief?.industry && process.env.SUPPORTERS_INDUSTRY === 'derm'); + export function userPrompt({ brief, context, fact, authorName, reviewerName, today }) { const cat = `${brief.category} ${brief.categoryLabel ?? ''}`.trim(); + const derm = isDermBrief(brief); return `# 이번 글 - 제목(H1, 질문형): ${brief.title} - 분류: ${cat} · 문항 ID: ${(brief.qbIds ?? []).join(', ') || '(없음)'} - 작성자: ${authorName ?? '확인 대기'} · 검토 예정 원장: ${reviewerName ?? '미정 (의학 검토 대기)'} - 오늘: ${today} -${brief.intent ? `- 기획 의도: ${brief.intent}\n` : ''}${brief.mustCover?.length ? `- 반드시 다룰 것: ${brief.mustCover.join(' / ')}\n` : ''}${brief.avoid?.length ? `- 이 글에서 피할 것: ${brief.avoid.join(' / ')}\n` : ''} +${brief.intent ? `- 기획 의도: ${brief.intent}\n` : ''}${brief.mustCover?.length ? `- 반드시 다룰 것: ${brief.mustCover.join(' / ')}\n` : ''}${brief.avoid?.length ? `- 이 글에서 피할 것: ${brief.avoid.join(' / ')}\n` : ''}${derm ? `\n${DERM_RULES}\n` : ''} # 근거 ${context} # 작성 지시 -위 근거만으로 "${brief.title}"에 답하는 글을 JSON 스키마대로 작성하세요. 근거에 없는 사실은 pending 에 적고 본문에는 "병원 공개 자료에 없습니다"로 씁니다. 병원 이름은 "${fact?.shortName ?? ''}"으로 씁니다.`; +위 근거만으로 "${brief.title}"에 답하는 글을 JSON 스키마대로 작성하세요. 근거에 없는 사실은 pending 에 적고 본문에는 "병원 공개 자료에 없습니다"로 씁니다. 병원 이름은 "${fact?.shortName ?? ''}"으로 씁니다.${derm ? ' 시술을 다루는 글이면 조건 표 8행과 시술자 항목을 넣고, 금액은 쓰지 않습니다.' : ''}`; } export function repairPrompt(errors, warns) { @@ -86,7 +106,19 @@ ${w || '(없음)'} - NUMERIC_NO_QUALIFIER: 수치가 있는 문단·요약 줄·FAQ 답에 "개인차가 있습니다" 또는 "상담에서 확인하세요"를 붙입니다. - PLAIN_ENDING: 반말 문장을 "~입니다/~합니다"로 바꿉니다. - HEADING_VERB: 제목을 명사구 또는 질문형으로 바꿉니다. -- BODY_H1: 본문의 # 제목을 ## 으로 바꿉니다.`; +- BODY_H1: 본문의 # 제목을 ## 으로 바꿉니다.${dermFixes(errors, warns)}`; +} + +// 피부과 규칙 코드가 실제로 나왔을 때만 붙는 수정 지침. 성형외과 글에서 이 코드가 없으면 수정 프롬프트는 이전과 같다. +const DERM_FIX = { + PRICE_MENTION: '- PRICE_MENTION: 금액·할인·이벤트가 표기를 삭제합니다. "금액은 병원의 비급여 진료비용 고지 페이지에서 확인하세요"로 바꿉니다.', + DEVICE_CLAIM: '- DEVICE_CLAIM: 허가 표현(식약처 허가·FDA 승인)은 규제 원문 근거가 없으면 삭제하고, 영구·완치·재발 없음·100%·평생 유지 같은 효과 보장 표현은 근거 수치와 "개인차"로 바꿉니다.', + PRACTITIONER_MISSING: '- PRACTITIONER_MISSING: 조건 표에 "시술자" 행을 넣습니다. 근거에 의사 직접·의사 감독 표기가 없으면 값은 "확인 대기"입니다.', +}; +function dermFixes(errors, warns) { + const codes = new Set([...errors, ...warns].map((x) => x.code)); + const lines = Object.entries(DERM_FIX).filter(([c]) => codes.has(c)).map(([, l]) => l); + return lines.length ? '\n' + lines.join('\n') : ''; } /** OpenAI structured output 스키마 (strict). */ diff --git a/templates/supporters-astro/scripts/generate_posts.mjs b/templates/supporters-astro/scripts/generate_posts.mjs index 3b114bc..73d0a7c 100644 --- a/templates/supporters-astro/scripts/generate_posts.mjs +++ b/templates/supporters-astro/scripts/generate_posts.mjs @@ -296,7 +296,6 @@ for (const brief of briefs) { row.pending = out.pending ?? []; row.usedRefs = out.usedRefs ?? []; row.seconds = Math.round((Date.now() - t0) / 100) / 10; - spent += row.costUsd; const mark = hard.length ? '✗' : soft.length ? '△' : '✓'; console.log(` ${mark} ${brief.id}: 오류 ${hard.length} 근거플래그 ${soft.length} 경고 ${res.warns.length} · 본문 ${res.stats.hangul}자 표 ${res.stats.tables} FAQ ${res.stats.faq} · 확인 대기 ${row.pending.length} · 호출 ${row.calls}${row.repaired ? '(수정)' : ''} · $${row.costUsd.toFixed(3)} · ${row.seconds}s`); for (const e of hard) console.log(` ✗ [${e.code}] ${e.msg}`); @@ -306,7 +305,8 @@ for (const brief of briefs) { console.error(` ✗ ${brief.id}: ${row.error.slice(0, 300)}`); } } -function addUsage(row, u, m) { row.calls++; row.usage.prompt_tokens += u.prompt_tokens ?? 0; row.usage.completion_tokens += u.completion_tokens ?? 0; row.costUsd += costOf(u, m); } +// 토큰을 쓴 시점에 누적한다. 호출이 실패해도 과금은 이미 일어났으므로 총액과 상한 판정에 들어가야 한다. +function addUsage(row, u, m) { row.calls++; row.usage.prompt_tokens += u.prompt_tokens ?? 0; row.usage.completion_tokens += u.completion_tokens ?? 0; const c = costOf(u, m); row.costUsd += c; spent += c; } // ---------- 리포트 ---------- report.finishedAt = new Date().toISOString(); @@ -316,6 +316,8 @@ report.summary = { total: report.posts.length, ok: st('ok'), okNeedsReview: st('ok_needs_review'), gateFailed: st('gate_failed'), error: st('error'), repaired: report.posts.filter((p) => p.repaired).length, avgCostUsd: avg(report.posts.filter((p) => p.costUsd).map((p) => p.costUsd)), + // 총액에 포함되지만 글로 남지 않은 비용(실패·게이트 차단). 채택 편당 원가를 따로 보려면 이 값을 뺀다. + discardedCostUsd: Math.round(report.posts.filter((p) => ['error', 'gate_failed'].includes(p.status)).reduce((n, p) => n + p.costUsd, 0) * 1000) / 1000, avgSeconds: avg(report.posts.filter((p) => p.seconds).map((p) => p.seconds)), firstPassErrorCodes: count(report.posts.flatMap((p) => p.firstPass?.errors ?? [])), warningCodes: count(report.posts.flatMap((p) => (p.warnings ?? []).map((w) => w.match(/^\[(\w+)\]/)?.[1]))), @@ -324,7 +326,7 @@ report.summary = { }; writeFileSync(join(OUT, 'report.json'), JSON.stringify(report, null, 1)); writeFileSync(join(OUT, 'report.md'), reportMd(report)); -console.log(`\n통과 ${report.summary.ok} · 근거 플래그 남음 ${report.summary.okNeedsReview} · 게이트 실패 ${report.summary.gateFailed} · 오류 ${report.summary.error} / ${report.summary.total} · 수정 호출 ${report.summary.repaired} · 총 $${report.totalCostUsd} (편당 $${report.summary.avgCostUsd}) · ${OUT}`); +console.log(`\n통과 ${report.summary.ok} · 근거 플래그 남음 ${report.summary.okNeedsReview} · 게이트 실패 ${report.summary.gateFailed} · 오류 ${report.summary.error} / ${report.summary.total} · 수정 호출 ${report.summary.repaired} · 총 $${report.totalCostUsd}${report.summary.discardedCostUsd ? ` (폐기 $${report.summary.discardedCostUsd})` : ''} (편당 $${report.summary.avgCostUsd}) · ${OUT}`); if (report.summary.gateFailed || report.summary.error) process.exitCode = 1; function avg(a) { return a.length ? Math.round((a.reduce((x, y) => x + y, 0) / a.length) * 1000) / 1000 : 0; } @@ -336,7 +338,7 @@ function reportMd(r) { const fp = Object.entries(r.summary.firstPassErrorCodes).map(([k, v]) => `${k}×${v}`).join(', ') || '없음'; return `# 글 생성 리포트 · ${r.clinic} · ${r.model}${r.verifyModel ? ` (대조 ${r.verifyModel})` : ''} · ${r.today} -통과 ${r.summary.ok} · 근거 플래그 남음 ${r.summary.okNeedsReview} · 게이트 실패 ${r.summary.gateFailed} · 오류 ${r.summary.error} / ${r.summary.total} · 수정 호출 ${r.summary.repaired}편 · 총 $${r.totalCostUsd} · 편당 $${r.summary.avgCostUsd} · 편당 ${r.summary.avgSeconds}s +통과 ${r.summary.ok} · 근거 플래그 남음 ${r.summary.okNeedsReview} · 게이트 실패 ${r.summary.gateFailed} · 오류 ${r.summary.error} / ${r.summary.total} · 수정 호출 ${r.summary.repaired}편 · 총 $${r.totalCostUsd}${r.summary.discardedCostUsd ? ` (폐기 $${r.summary.discardedCostUsd})` : ''} · 편당 $${r.summary.avgCostUsd} · 편당 ${r.summary.avgSeconds}s 가격 기준 USD/1M tokens 입력 ${r.priceIn} · 출력 ${r.priceOut} (목록가, 실제 청구와 다를 수 있음) 1차 출력 오류 분포(수정 전): ${fp} diff --git a/templates/supporters-astro/scripts/ocr/vision_ocr.swift b/templates/supporters-astro/scripts/ocr/vision_ocr.swift new file mode 100644 index 0000000..c5af318 --- /dev/null +++ b/templates/supporters-astro/scripts/ocr/vision_ocr.swift @@ -0,0 +1,129 @@ +// macOS Vision 프레임워크(VNRecognizeTextRequest)로 이미지 글자를 읽는 단일 파일 도구. +// tesseract·pyobjc 가 없는 환경에서 결정론적 OCR 을 쓰기 위한 것. 유료 API 를 쓰지 않는다. +// +// swiftc -O -o vision_ocr vision_ocr.swift (ocr_evidence.mjs 가 소스가 바뀌면 다시 빌드한다) +// ./vision_ocr [--min-width 400] [--langs ko-KR,en-US] [--tile-height 2000] [--upscale-below 1400] [ ...] +// +// 세로로 긴 이미지(의료진 소개 794x12240 같은 스크롤 이미지)는 Vision 이 통째로 축소해 한 줄도 못 읽는다. +// --tile-height 픽셀 단위 띠로 잘라(겹침 10%) 띠마다 인식하고, 겹침 구간의 줄은 한 번만 남긴다. +// 폭이 --upscale-below 미만이면 2배로 키워 인식한다(작은 글자 대응). box 좌표는 원본 기준 0~1 정규화. +// +// 출력: 이미지 한 장에 JSON 한 줄(stdout) +// {"path":"...","width":W,"height":H,"lines":[{"text":"...","confidence":0.93,"box":[x,y,w,h]}],"engine":"apple-vision"} +// 폭이 --min-width 미만이면 {"path":"...","width":W,"height":H,"skipped":"narrow"}. 읽기 실패는 {"path":"...","error":"..."}. +// 줄 순서는 위에서 아래, 같은 줄 안에서는 왼쪽에서 오른쪽(Vision 의 정규화 좌표 y 는 아래가 0 이라 뒤집는다). +// 글자는 Vision 이 준 것만 내보낸다. 후처리(병합·교정)는 하지 않는다. 그것은 호출 측(ocr_evidence.mjs) 몫이다. +import Foundation +import Vision +import ImageIO +import CoreGraphics + +var minWidth = 0 +var tileHeight = 2000 +var upscaleBelow = 1400 +var langs = ["ko-KR", "en-US"] +var paths: [String] = [] +var it = CommandLine.arguments.dropFirst().makeIterator() +while let a = it.next() { + switch a { + case "--min-width": if let v = it.next(), let n = Int(v) { minWidth = n } + case "--langs": if let v = it.next() { langs = v.split(separator: ",").map { String($0) } } + case "--tile-height": if let v = it.next(), let n = Int(v) { tileHeight = max(n, 400) } + case "--upscale-below": if let v = it.next(), let n = Int(v) { upscaleBelow = n } + default: paths.append(a) + } +} +if paths.isEmpty { + FileHandle.standardError.write("사용법: vision_ocr [--min-width N] [--langs ko-KR,en-US] ...\n".data(using: .utf8)!) + exit(2) +} + +func jsonLine(_ obj: [String: Any]) { + if let d = try? JSONSerialization.data(withJSONObject: obj, options: [.withoutEscapingSlashes]), let s = String(data: d, encoding: .utf8) { + print(s) + fflush(stdout) + } +} + +func loadImage(_ path: String) -> CGImage? { + let url = URL(fileURLWithPath: path) + guard let src = CGImageSourceCreateWithURL(url as CFURL, nil) else { return nil } + return CGImageSourceCreateImageAtIndex(src, 0, nil) +} + +struct Line { var text: String; var confidence: Double; var x: Double; var y: Double; var w: Double; var h: Double } // 픽셀 좌표(원본 기준) + +// 이미지 한 장(또는 띠 하나)을 인식해 원본 픽셀 좌표의 줄 목록으로. scale 은 확대 배율 +func recognize(_ img: CGImage, offsetY: Int, scale: Int) throws -> [Line] { + var target = img + if scale > 1 { + let w = img.width * scale, h = img.height * scale + if let ctx = CGContext(data: nil, width: w, height: h, bitsPerComponent: 8, bytesPerRow: 0, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipLast.rawValue) { + ctx.interpolationQuality = .high + ctx.draw(img, in: CGRect(x: 0, y: 0, width: w, height: h)) + if let up = ctx.makeImage() { target = up } + } + } + let request = VNRecognizeTextRequest() + request.recognitionLevel = .accurate + request.recognitionLanguages = langs + request.usesLanguageCorrection = true + let handler = VNImageRequestHandler(cgImage: target, options: [:]) + try handler.perform([request]) + let obs = (request.results ?? []) as [VNRecognizedTextObservation] + let W = Double(img.width), H = Double(img.height) + var out: [Line] = [] + for o in obs { + guard let top = o.topCandidates(1).first else { continue } + let bb = o.boundingBox // 정규화, 원점 왼쪽 아래 + out.append(Line(text: top.string, confidence: Double(top.confidence), x: bb.minX * W, y: (1 - bb.maxY) * H + Double(offsetY), w: bb.width * W, h: bb.height * H)) + } + return out +} + +for path in paths { + guard let img = loadImage(path) else { jsonLine(["path": path, "error": "이미지를 열 수 없음"]); continue } + let w = img.width, h = img.height + if w < minWidth { jsonLine(["path": path, "width": w, "height": h, "skipped": "narrow"]); continue } + let scale = w < upscaleBelow ? 2 : 1 + var lines: [Line] = [] + var tiles = 0 + do { + if h <= tileHeight { + lines = try recognize(img, offsetY: 0, scale: scale); tiles = 1 + } else { + let overlap = tileHeight / 10 + var top = 0 + while top < h { + let th = min(tileHeight, h - top) + guard let tile = img.cropping(to: CGRect(x: 0, y: top, width: w, height: th)) else { break } + let got = try recognize(tile, offsetY: top, scale: scale) + // 겹침 구간은 한가운데서 나눠 앞 띠는 그 앞까지, 뒷 띠는 그 뒤부터 받는다(같은 줄이 두 띠에 들어가지 않게). + // 띠 가장자리에 걸려 반만 읽힌 줄은 중심이 경계 밖이라 버려지고, 다른 띠에서 온전히 읽힌 것만 남는다. 첫 띠는 처음부터, 마지막 띠는 끝까지 + let isLast = top + th >= h + let lo = top == 0 ? -1.0 : Double(top + overlap / 2) + let hi = isLast ? Double.infinity : Double(top + th - overlap / 2) + for l in got { let cy = l.y + l.h / 2; if cy >= lo && cy < hi { lines.append(l) } } + tiles += 1 + if top + th >= h { break } + top += tileHeight - overlap + } + } + } catch { + jsonLine(["path": path, "width": w, "height": h, "error": "인식 실패: \(error.localizedDescription)"]); continue + } + // 위→아래, 같은 줄 안에서는 왼→오른쪽 + lines.sort { a, b in + let ay = a.y + a.h / 2, by = b.y + b.h / 2 + if abs(ay - by) > max(a.h, b.h) * 0.6 { return ay < by } + return a.x < b.x + } + let W = Double(w), H = Double(h) + let r3 = { (v: Double) -> Double in (v * 1000).rounded() / 1000 } + let out: [[String: Any]] = lines.map { l in [ + "text": l.text, + "confidence": r3(l.confidence), + "box": [r3(l.x / W), r3(l.y / H), r3(l.w / W), r3(l.h / H)], + ] } + jsonLine(["path": path, "width": w, "height": h, "tiles": tiles, "scale": scale, "lines": out, "engine": "apple-vision"]) +} diff --git a/templates/supporters-astro/scripts/ocr_evidence.mjs b/templates/supporters-astro/scripts/ocr_evidence.mjs new file mode 100644 index 0000000..05f396d --- /dev/null +++ b/templates/supporters-astro/scripts/ocr_evidence.mjs @@ -0,0 +1,241 @@ +// 근거 OCR 단계. collect_evidence.mjs 가 남긴 evidence// 에서 글자가 이미지에 들어 있는 페이지(flags.textInImages 또는 본문 100자 미만)의 +// 콘텐츠 이미지를 내려받아 macOS Vision(scripts/ocr/vision_ocr.swift)으로 읽고, 결과를 페이지 JSON·index.json·home_text·doctors.json 에 되돌려 넣는다. +// 시술 설명을 통짜 JPG 로 넣는 사이트(오라클피부과: 시술 84페이지 중 83개가 이미지 글자)를 근거로 쓰기 위한 것이다. +// +// node scripts/ocr_evidence.mjs --clinic --evidence > [--min-width 400] [--max-images 200] [--min-conf 0.5] [--force] +// +// 원칙 +// - 유료 API 를 쓰지 않는다. Vision 이 준 글자만 쓰고 교정·보완하지 않는다(없는 글자를 만들지 않는다). +// - 신뢰도 0.5 미만 줄은 버린다. 줄 병합은 문장 부호 기준으로만 한다: 앞 줄이 . ? ! 로 끝나지 않으면 다음 줄을 같은 문장으로 이어 붙인다. +// 세로 간격이 줄 높이의 1.6배를 넘으면 문단을 나눈다(나누기만 하고 붙이지는 않는다). +// - 원문(HTML) 텍스트와 OCR 텍스트를 구분한다: 페이지 JSON 에 ocr[]·sections[{source:"ocr"}]·flags.ocr=true·textOriginal 을 남긴다. +// - 다시 돌려도 결과가 같다(멱등): 이미 받은 이미지는 다시 받지 않고, 텍스트는 textOriginal 에서 다시 만든다. --force 면 OCR 도 다시 한다. +// +// 산출물(기존 파일을 갱신) +// evidence//ocr//<이미지> 내려받은 원본 이미지 +// evidence//ocr/results.jsonl 이미지별 Vision 원출력(줄·신뢰도·좌표) +// evidence//pages/.json ocr[], sections 에 OCR 섹션 추가, text·chars 갱신, flags.ocr +// evidence//index.json chars·flags 갱신, ocr 요약 +// evidence//home_text.txt 원문 + OCR (40자 연속 일치 게이트 기준. OCR 글자도 병원 문장이므로 합친다) +// evidence//home_text.ocr.txt OCR 만 따로 +// evidence//doctors.json 의료진 페이지 OCR 에서 읽은 이름·직함·약력 후보 ("OCR · 확인 대기") +import { mkdirSync, writeFileSync, readFileSync, existsSync, statSync, readdirSync } from 'node:fs'; +import { join, basename, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { spawnSync } from 'node:child_process'; + +// ---------- 인자 ---------- +const arg = (k, d) => { const i = process.argv.indexOf(k); return i > -1 ? process.argv[i + 1] : d; }; +const CLINIC = arg('--clinic'); const EV = arg('--evidence'); +if (!CLINIC || !EV || !existsSync(join(EV, 'index.json'))) { console.error('사용법: --clinic --evidence > (index.json 있는 폴더)'); process.exit(2); } +const MIN_WIDTH = Number(arg('--min-width', 400)); const MAX_IMAGES = Number(arg('--max-images', 200)); const MIN_CONF = Number(arg('--min-conf', 0.5)); +const FORCE = process.argv.includes('--force'); +const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0 Safari/537.36 INFINITH-supporters-evidence/1.0 (+mailto:o2oteam@o2o.kr)'; +const today = new Date().toISOString().slice(0, 10); +const OCR_DIR = join(EV, 'ocr'); mkdirSync(OCR_DIR, { recursive: true }); + +// ---------- Vision 도구 빌드 ---------- +const SWIFT_SRC = fileURLToPath(new URL('./ocr/vision_ocr.swift', import.meta.url)); +const BIN = join(dirname(SWIFT_SRC), 'vision_ocr'); +function ensureBinary() { + const fresh = existsSync(BIN) && statSync(BIN).mtimeMs >= statSync(SWIFT_SRC).mtimeMs; + if (fresh) return; + console.log(` swiftc 빌드 ${basename(SWIFT_SRC)} → ${basename(BIN)}`); + const r = spawnSync('swiftc', ['-O', '-o', BIN, SWIFT_SRC], { encoding: 'utf8' }); + if (r.status !== 0) { console.error(r.stderr || r.stdout); console.error('vision_ocr 빌드 실패. Xcode Command Line Tools(swiftc) 가 필요하다'); process.exit(1); } +} + +// ---------- 대상 페이지·이미지 ---------- +// 로고·버튼·아이콘·배너·전후사진·장비 썸네일은 이름으로 뺀다. 폭은 Vision 도구가 --min-width 로 거른다 +const NOT_CONTENT = /icon|logo|btn|button|arrow|blank|spacer|sns|share|banner|bnr|top_ban|_ban\d|main_bf|convenient|bg_|_bg\b|\/bg\.|dot\.|bullet|quick|visual|slide|roll|thumb|gallery\/|laiser_table|_next\/image|\.bmp$|\.gif$|\.svg$|before|after/i; +const TYPE_PRIO = { 'doctor-detail': 0, doctor: 1, procedure: 2, precautions: 3, aftercare: 3, safety: 3, checkup: 3, about: 4, pricing: 4, facilities: 5, direction: 5, reservation: 6, branches: 6, home: 7, other: 8 }; +const index = JSON.parse(readFileSync(join(EV, 'index.json'), 'utf8')); +const loadPage = (f) => JSON.parse(readFileSync(join(EV, f), 'utf8')); +const savePage = (f, p) => writeFileSync(join(EV, f), JSON.stringify(p, null, 1)); +const flagOn = (p, k) => (Array.isArray(p.flags) ? p.flags.includes(k) : Boolean(p.flags?.[k])); + +const candidates = index.pages + .filter((p) => p.status === 200 && p.type !== 'duplicate' && p.file) + .map((p) => ({ ix: p, page: loadPage(p.file) })) + .filter(({ page }) => flagOn(page, 'textInImages') || (page.flags?.charsOriginal ?? page.chars ?? 0) < 100) + .sort((a, b) => (TYPE_PRIO[a.ix.type] ?? 9) - (TYPE_PRIO[b.ix.type] ?? 9)); +console.log(`[1/4] ${CLINIC}: 이미지 글자 페이지 ${candidates.length}개 (전체 ${index.pages.length})`); + +// 페이지별 콘텐츠 이미지 → 내려받기 목록. 같은 이미지가 여러 페이지에 있으면 한 번만 받는다 +const jobs = []; const seenSrc = new Map(); +for (const c of candidates) { + const imgs = (c.page.images ?? []).filter((im) => im.src && !NOT_CONTENT.test(im.src)); + for (const im of imgs) { + if (jobs.length >= MAX_IMAGES) break; + const key = im.src.replace(/^https?:\/\//, ''); + if (seenSrc.has(key)) { seenSrc.get(key).pages.push(c); continue; } + const name = decodeURIComponent(basename(new URL(im.src).pathname)).replace(/[^a-zA-Z0-9가-힣._-]+/g, '_') || 'image'; + const file = join(OCR_DIR, c.page.slug, name); + const job = { src: im.src, alt: im.alt ?? '', file, pages: [c] }; + seenSrc.set(key, job); jobs.push(job); + } +} +console.log(` 콘텐츠 이미지 후보 ${jobs.length}개 (--max-images ${MAX_IMAGES}, 이름으로 제외 ${candidates.reduce((n, c) => n + (c.page.images ?? []).filter((im) => NOT_CONTENT.test(im.src ?? '')).length, 0)}개)`); + +// ---------- 내려받기 ---------- +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +async function download(job) { + if (existsSync(job.file) && statSync(job.file).size > 0) { job.downloaded = 'cached'; return; } + for (let i = 0; i < 3; i++) { + try { + const res = await fetch(job.src, { headers: { 'user-agent': UA, referer: job.pages[0].page.url }, signal: AbortSignal.timeout(30000) }); + if (res.status !== 200) { job.error = `HTTP ${res.status}`; return; } + const buf = new Uint8Array(await res.arrayBuffer()); + if (buf.length < 1000) { job.error = `파일이 너무 작음 (${buf.length}B)`; return; } + mkdirSync(dirname(job.file), { recursive: true }); writeFileSync(job.file, buf); job.downloaded = 'new'; return; + } catch (e) { job.error = e.message; await sleep(600 * (i + 1)); } + } +} +{ + let i = 0; const workers = Array.from({ length: 3 }, async () => { while (i < jobs.length) { const j = jobs[i++]; await download(j); process.stdout.write(`\r 내려받기 ${i}/${jobs.length}`); } }); + await Promise.all(workers); +} +const fetched = jobs.filter((j) => !j.error); +console.log(`\n[2/4] 내려받음 ${fetched.length}개 (새로 ${fetched.filter((j) => j.downloaded === 'new').length} · 캐시 ${fetched.filter((j) => j.downloaded === 'cached').length} · 실패 ${jobs.length - fetched.length})`); + +// ---------- OCR ---------- +ensureBinary(); +const RESULTS = join(OCR_DIR, 'results.jsonl'); +const prior = new Map(); // file → 결과 (멱등: 이미 읽은 이미지는 다시 읽지 않는다) +if (!FORCE && existsSync(RESULTS)) for (const l of readFileSync(RESULTS, 'utf8').split('\n').filter(Boolean)) { try { const o = JSON.parse(l); if (o.path && !o.error) prior.set(o.path, o); } catch { /* 깨진 줄 무시 */ } } +const todo = fetched.filter((j) => !prior.has(j.file)); +const results = new Map(prior); +if (todo.length) { + console.log(` Vision OCR ${todo.length}개 (캐시 ${fetched.length - todo.length}개)`); + for (let i = 0; i < todo.length; i += 25) { // 한 프로세스에 25장씩. 실패해도 나머지는 진행 + const batch = todo.slice(i, i + 25); + const r = spawnSync(BIN, ['--min-width', String(MIN_WIDTH), '--langs', 'ko-KR,en-US', ...batch.map((j) => j.file)], { encoding: 'utf8', maxBuffer: 512 * 1024 * 1024 }); + if (r.status !== 0 && !r.stdout) { console.error(` vision_ocr 실패: ${r.stderr?.slice(0, 500)}`); for (const j of batch) results.set(j.file, { path: j.file, error: `vision_ocr 종료 코드 ${r.status}` }); continue; } + for (const l of r.stdout.split('\n').filter(Boolean)) { try { const o = JSON.parse(l); results.set(o.path, o); } catch { /* 무시 */ } } + process.stdout.write(`\r OCR ${Math.min(i + 25, todo.length)}/${todo.length}`); + } + console.log(''); + writeFileSync(RESULTS, [...results.values()].map((o) => JSON.stringify(o)).join('\n') + '\n'); +} + +// ---------- 줄 → 문단 ---------- +const ENDS = /[.?!。…]["')\]]?$/; +/** 신뢰도로 거르고, 문장 부호 기준으로 줄을 잇는다. 세로 간격이 크면 문단을 나눈다 */ +function linesToText(lines) { + const kept = lines.filter((l) => l.confidence >= MIN_CONF && l.text.trim()); + const paras = []; let cur = null; let prev = null; + for (const l of kept) { + const t = l.text.trim(); + const gapBreak = prev && l.box && prev.box && (l.box[1] - (prev.box[1] + prev.box[3])) > Math.max(prev.box[3], l.box[3]) * 1.6; + if (cur && !gapBreak && !ENDS.test(cur)) cur = `${cur} ${t}`; + else { if (cur) paras.push(cur); cur = t; } + prev = l; + } + if (cur) paras.push(cur); + return { text: paras.join('\n'), kept: kept.length, dropped: lines.length - kept.length }; +} + +// ---------- 페이지에 반영 ---------- +let ocrImages = 0, ocrPages = 0, ocrChars = 0; const failed = []; const perPage = []; +for (const c of candidates) { + const page = c.page; + const myJobs = jobs.filter((j) => j.pages.includes(c)); + const entries = []; + for (const j of myJobs) { + const r = results.get(j.file); + if (j.error) { failed.push({ page: page.url, src: j.src, reason: j.error }); continue; } + if (!r) { failed.push({ page: page.url, src: j.src, reason: 'OCR 결과 없음' }); continue; } + if (r.error) { failed.push({ page: page.url, src: j.src, reason: r.error }); continue; } + if (r.skipped) continue; // 폭 부족 + const { text, kept, dropped } = linesToText(r.lines ?? []); + if (!text) continue; + const conf = kept ? Math.round((r.lines.filter((l) => l.confidence >= MIN_CONF).reduce((s, l) => s + l.confidence, 0) / kept) * 1000) / 1000 : 0; + entries.push({ src: j.src, alt: j.alt, file: j.file.replace(EV + '/', ''), width: r.width, height: r.height, tiles: r.tiles ?? 1, lines: r.lines.filter((l) => l.confidence >= MIN_CONF).map((l) => l.text), droppedLines: dropped, confidence: conf, text, engine: r.engine ?? 'apple-vision', at: today }); + } + // 원문 텍스트는 textOriginal 로 보존(재실행 시 여기서 다시 만든다) + page.textOriginal ??= page.text ?? ''; + page.flags ??= {}; + page.flags.charsOriginal ??= page.textOriginal.replace(/\s+/g, '').length; + page.sections = (page.sections ?? []).filter((s) => s.source !== 'ocr'); + page.ocr = entries; + const ocrText = entries.map((e) => e.text).join('\n'); + if (entries.length) { + page.sections.push({ heading: page.title || page.h1 || page.slug, level: 2, source: 'ocr', images: entries.map((e) => e.src), text: ocrText, paragraphs: ocrText.split('\n'), lists: [], tables: [] }); + page.text = [page.textOriginal, ocrText].filter(Boolean).join('\n'); + page.flags.ocr = true; page.flags.ocrImages = entries.length; page.flags.ocrChars = ocrText.replace(/\s+/g, '').length; + ocrImages += entries.length; ocrPages++; ocrChars += page.flags.ocrChars; + } else { page.text = page.textOriginal; delete page.flags.ocr; delete page.flags.ocrImages; delete page.flags.ocrChars; } + page.chars = page.text.replace(/\s+/g, '').length; + savePage(c.ix.file, page); + c.ix.chars = page.chars; + c.ix.flags = Object.entries(page.flags).filter(([, v]) => v === true).map(([k]) => k); + perPage.push({ url: page.url, type: page.type, title: page.title, chars: page.chars, ocrChars: page.flags.ocrChars ?? 0, images: entries.length }); +} +index.byType = index.pages.reduce((m, x) => ((m[x.type] = (m[x.type] ?? 0) + 1), m), {}); +index.ocr = { at: today, engine: 'apple-vision', pages: ocrPages, images: ocrImages, chars: ocrChars, minWidth: MIN_WIDTH, minConf: MIN_CONF, failed: failed.length }; +writeFileSync(join(EV, 'index.json'), JSON.stringify(index, null, 1)); +console.log(`[3/4] 페이지 ${ocrPages}개에 OCR 반영 (이미지 ${ocrImages}장 · OCR 글자 ${ocrChars.toLocaleString()}자 · 실패 ${failed.length})`); + +// ---------- home_text ---------- +// 40자 연속 일치 게이트는 병원 문장의 그대로 옮김을 막는 것이다. OCR 글자도 병원이 쓴 문장이므로 home_text.txt 에 합친다. +// OCR 오독으로 원문과 몇 글자 다를 수 있어 게이트가 그만큼 느슨해질 뿐, 잘못 막는 쪽으로는 가지 않는다. OCR 만 따로 home_text.ocr.txt 에도 남긴다. +{ + const orig = []; const ocr = []; + for (const ix of index.pages) { + if (ix.status !== 200 || ix.type === 'duplicate' || !ix.file) continue; + const p = loadPage(ix.file); + const o = (p.textOriginal ?? p.text ?? '').replace(/\s+/g, ''); if (o) orig.push(o); + const t = (p.ocr ?? []).map((e) => e.text).join('\n').replace(/\s+/g, ''); if (t) ocr.push(t); + } + writeFileSync(join(EV, 'home_text.txt'), [...orig, ...ocr].join('\n')); + writeFileSync(join(EV, 'home_text.ocr.txt'), ocr.join('\n')); +} + +// ---------- 의료진 ---------- +// 의료진 페이지 OCR 줄에서 "이름 원장" 을 찾고, 다음 이름·지점 제목까지의 줄을 약력 후보로. 지점("X점")·지역("X지역")·진료과 제목은 소속으로 붙인다. +const NAME_RE = /^[\s|1lI]*([가-힣]{2,4})\s*(대표\s*)?원장(?:님)?\s*$/; +const BRANCH_RE = /^[\s|]*((?:[가-힣]{1,4}\s)?[가-힣A-Za-z0-9]{1,10}점)\s*$/; +const REGION_RE = /^[\s|]*([가-힣]{2,6}지역)\s*$/; +const DEPT_RE = /^[\s|]*(피부과|성형외과|치과|내과|비만\s*[•·]?\s*체형|피부\s*관리)\s*$/; +const SPECIALTY_RE = /(성형외과|이비인후과|마취통증의학과|피부과|영상의학과|외과|치과|내과|가정의학과|산부인과)\s*전문의/; +function parseDoctorsFromOcr(page) { + const out = []; + for (const e of page.ocr ?? []) { + let region = null, branch = null, dept = null, cur = null; + for (const raw of e.lines) { + const t = raw.trim(); + let m; + if ((m = t.match(REGION_RE))) { region = m[1]; continue; } + if ((m = t.match(BRANCH_RE))) { branch = m[1]; cur = null; continue; } + if ((m = t.match(DEPT_RE))) { dept = m[1].replace(/\s+/g, ' '); continue; } + if ((m = t.match(NAME_RE))) { cur = { name: m[1], isRep: Boolean(m[2]), region, branch, dept, credentials: [], image: e.src }; out.push(cur); continue; } + if (cur && t.length >= 4 && t.length <= 60) cur.credentials.push(t); + } + } + return out.map((d, i) => { + const specialty = d.credentials.map((c) => c.match(SPECIALTY_RE)?.[0]).find(Boolean) ?? null; + return { id: `ocr-${i + 1}-${d.name}`, url: page.url, name: d.name, title: [d.isRep ? '대표원장' : '원장', specialty].filter(Boolean).join(' · '), region: d.region, branch: d.branch, dept: d.dept, credentials: d.credentials.filter((c) => c !== specialty), image: d.image, source: 'ocr', status: 'OCR · 확인 대기' }; + }); +} +{ + const path = join(EV, 'doctors.json'); + const doc = existsSync(path) ? JSON.parse(readFileSync(path, 'utf8')) : { clinic: CLINIC, fetchedAt: today, doctors: [] }; + const doctorPages = candidates.filter((c) => ['doctor', 'doctor-detail'].includes(c.page.type) && c.page.ocr?.length); + const found = doctorPages.flatMap((c) => parseDoctorsFromOcr(c.page)); + if (found.length) { + // 상세 페이지에서 이미 이름이 읽힌 의사는 유지하고 OCR 약력만 붙인다. 이름 없이 남아 있던 항목(이미지 글자)은 OCR 결과로 바꾼다 + // 지난 실행의 OCR 항목(source=ocr)은 버리고 다시 만든다(멱등) + const kept = (doc.doctors ?? []).filter((d) => d.name && d.source !== 'ocr').map((d) => { const o = found.find((f) => f.name === d.name); return o ? { ...d, credentialsOcr: o.credentials, ocrImage: o.image, status: d.status === 'ok' ? d.status : 'OCR 약력 · 확인 대기' } : d; }); + const add = found.filter((f) => !kept.some((d) => d.name === f.name)); + doc.doctors = [...kept, ...add]; + doc.ocr = { at: today, pages: doctorPages.map((c) => c.page.url), found: found.length, note: 'source=ocr 항목은 의료진 이미지에서 Vision 으로 읽은 이름·약력 후보. 오독 가능. authors.json 에 옮기기 전에 원본 이미지와 대조한다.' }; + writeFileSync(path, JSON.stringify(doc, null, 1)); + console.log(` 의료진 OCR 후보 ${found.length}명 (${[...new Set(found.map((f) => f.branch).filter(Boolean))].length}개 지점) → doctors.json ${doc.doctors.length}명`); + } else console.log(' 의료진 OCR 후보 없음'); +} + +// ---------- 보고 ---------- +const dist = perPage.filter((p) => p.images); +console.log(`[4/4] 저장 ${EV}`); +console.log(` OCR 이미지 ${ocrImages}장 · 페이지 ${ocrPages}개 · 200자 이상 ${dist.filter((p) => p.ocrChars >= 200).length}개 · 1,000자 이상 ${dist.filter((p) => p.ocrChars >= 1000).length}개 · home_text ${index.pages.reduce((n, p) => n + (p.chars ?? 0), 0).toLocaleString()}자 (OCR ${ocrChars.toLocaleString()}자)`); +if (failed.length) console.log(` 실패 ${failed.length}: ${failed.slice(0, 10).map((f) => `${f.src} (${f.reason})`).join(', ')}${failed.length > 10 ? ' …' : ''}`); diff --git a/templates/supporters-astro/src/components/Planner.astro b/templates/supporters-astro/src/components/Planner.astro new file mode 100644 index 0000000..8c3fba6 --- /dev/null +++ b/templates/supporters-astro/src/components/Planner.astro @@ -0,0 +1,313 @@ +--- +// 회복기 스케줄러 본문 (설계 v0.2 §13). /plan(한국어)과 /en/plan(영어)이 같은 컴포넌트를 lang 만 바꿔 쓴다. +// 구성은 홈·영상 페이지와 같은 섹션 리듬이다: 다크 히어로(글래스 통계) → 틴트(입력 카드) → 다크(핵심 날짜) → 라이트(확인·규칙) → 틴트(타임라인) → 다크(예약). +// 건강정보(시술·수술일)는 서버로 보내지 않는다. 상태는 URL 해시로만 공유하고, 언어 전환은 해시를 들고 다른 언어 페이지로 이동한다. +import '../styles/plan.css'; +import strings from '../data/planStrings.json'; +import P from '../data/procedures.json'; +import PL from '../data/places.json'; +import TKO from '../data/medicalTourismKo.json'; +import TEN from '../data/medicalTourism.json'; +import { tourToPlaces } from '../lib/tour'; +interface Props { lang: 'ko' | 'en' } +const { lang } = Astro.props; +const t = strings[lang]; +const tour = tourToPlaces((lang === 'en' ? TEN : TKO) as any, lang); +const nProcs = P.procedures.length; +const nPlaces = PL.places.filter((x) => x.category !== 'hotel').length + tour.filter((x) => x.category !== 'hotel').length; +const nHotels = PL.places.filter((x) => x.category === 'hotel').length + tour.filter((x) => x.category === 'hotel').length; +const procList = (P.procedures as any[]).map((x) => x.label[lang]).join(lang === 'ko' ? '·' : ', '); +const originLabel = (PL as any).origin?.label?.[lang] ?? ''; +--- +
    +
    +
    +
    {t.eyebrow}
    +

    {t.h_hero}

    +

    {t.title} {t.lede}

    +
    +
    +
    {nProcs}{t.stat_procs}{procList}
    +
    {nPlaces}{t.stat_places}{t.stat_places_d.replace('{origin}', originLabel)}
    +
    {nHotels}{t.stat_hotels}{t.stat_hotels_d}
    +
    0{t.stat_privacy}{t.stat_privacy_d}
    +
    +
    +
    +
    +
    +
    +
    + + + diff --git a/templates/supporters-astro/src/data/factSheet.json b/templates/supporters-astro/src/data/factSheet.json index 4d71fa8..0eddd10 100644 --- a/templates/supporters-astro/src/data/factSheet.json +++ b/templates/supporters-astro/src/data/factSheet.json @@ -2,14 +2,11 @@ "_comment": "병원 사실의 단일 원본. 근거 수집기(evidence//)가 채우고, 비어 있는 값은 화면에 '확인 대기'로 표시된다. 홈페이지 표기와 한 글자까지 맞춘다. 지어내지 않는다.", "name": "", "shortName": "", - "nameEn": "", - "shortNameEn": "", - "shortNameEnSource": "", "kind": "", "areaLabel": "", "founded": "", "representative": "", - "address": { "full": "", "fullEn": "", "postalCode": "", "fullEnSource": "", "street": "", "locality": "", "region": "", "postalNote": "", "navigation": "", "source": "" }, + "address": { "full": "", "street": "", "locality": "", "region": "", "postalNote": "", "navigation": "", "source": "" }, "phone": "", "fax": "", "kakao": "", diff --git a/templates/supporters-astro/src/data/medicalTourism.json b/templates/supporters-astro/src/data/medicalTourism.json index 1a7e138..d9d64bc 100644 --- a/templates/supporters-astro/src/data/medicalTourism.json +++ b/templates/supporters-astro/src/data/medicalTourism.json @@ -1,5 +1,5 @@ { - "_comment": "의료관광 연결 데이터. scripts/fetch_medical_tourism.py 가 병원 좌표로 채운다. 비어 있으면 /en/stay 는 목록 없음으로 표시된다.", + "_comment": "주변 안내 데이터(빈 값). 워커의 tourism 단계(scripts/fetch_medical_tourism.py)가 팩트 시트 주소로 채운다. origin lat 0 이면 /stay·/en/stay 는 '확인 대기'로 그린다.", "places": { "stay": [], "restaurant": [], @@ -23,11 +23,14 @@ "lat": 0, "lng": 0, "label": "", + "address": "", "coordSource": "" }, "radiusByType": {}, "festivalRadiusKm": 0, "counts": {}, - "limits": [] + "limits": [], + "lang": "en", + "clinic": "" } } diff --git a/templates/supporters-astro/src/data/medicalTourismKo.json b/templates/supporters-astro/src/data/medicalTourismKo.json index 734e751..3323d7c 100644 --- a/templates/supporters-astro/src/data/medicalTourismKo.json +++ b/templates/supporters-astro/src/data/medicalTourismKo.json @@ -1,5 +1,5 @@ { - "_comment": "국문 의료관광 연결 데이터. scripts/fetch_medical_tourism.py --lang ko 가 채운다. 비어 있으면 /stay 는 목록 없음으로 표시된다.", + "_comment": "주변 안내 데이터(빈 값). 워커의 tourism 단계(scripts/fetch_medical_tourism.py)가 팩트 시트 주소로 채운다. origin lat 0 이면 /stay·/en/stay 는 '확인 대기'로 그린다.", "places": { "stay": [], "restaurant": [], @@ -24,11 +24,13 @@ "lat": 0, "lng": 0, "label": "", + "address": "", "coordSource": "" }, "radiusByType": {}, "festivalRadiusKm": 0, "counts": {}, - "limits": [] + "limits": [], + "clinic": "" } } diff --git a/templates/supporters-astro/src/data/places.json b/templates/supporters-astro/src/data/places.json new file mode 100644 index 0000000..28c8482 --- /dev/null +++ b/templates/supporters-astro/src/data/places.json @@ -0,0 +1,207 @@ +{ + "_comment": "범용 큐레이션 기본표. 워커 planner 단계가 {CLINIC_KO}/{CLINIC_EN}/{AREA_KO}/{AREA_EN} 치환자를 팩트 시트 값으로 바꾸고 origin 을 관광공사 수집 기준 좌표로 채운다. 병원별 큐레이션(briefs//planner.places.json)이 있으면 이 표 대신 그것을 쓴다. 숙소는 관광공사 데이터가 맡는다.", + "origin": { + "label": { + "ko": "{CLINIC_KO}", + "en": "{CLINIC_EN}" + }, + "lat": 0, + "lng": 0 + }, + "categories": { + "sightseeing": { + "ko": "관광", + "en": "Sightseeing" + }, + "shopping": { + "ko": "쇼핑", + "en": "Shopping" + }, + "food": { + "ko": "미식", + "en": "Food" + }, + "kpop": { + "ko": "K-pop·핫플", + "en": "K-pop & hotspots" + }, + "care": { + "ko": "휴식·케어", + "en": "Rest & care" + }, + "essentials": { + "ko": "생활", + "en": "Essentials" + }, + "hotel": { + "ko": "숙소", + "en": "Hotels" + } + }, + "places": [ + { + "id": "pharmacy", + "name": { + "ko": "{AREA_KO} 주변 약국", + "en": "Pharmacies near {AREA_EN}" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.2, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "처방약과 냉찜질 팩을 구할 수 있습니다.", + "en": "Prescriptions and cold packs." + }, + "mapQuery": "약국 {AREA_KO}", + "verify": true + }, + { + "id": "convenience", + "name": { + "ko": "편의점 ({AREA_KO} 일대)", + "en": "Convenience stores ({AREA_EN})" + }, + "category": "essentials", + "minLevel": 1, + "distanceKm": 0.1, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "생수, 죽, 빨대, 얼음을 24시간 살 수 있습니다.", + "en": "Water, porridge, straws and ice, 24 hours." + }, + "mapQuery": "편의점 {AREA_KO}", + "verify": true + }, + { + "id": "porridge", + "name": { + "ko": "죽 전문점 (본죽 등 체인)", + "en": "Korean porridge (Bonjuk and similar chains)" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.5, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "유동식·부드러운 식사 단계에서 먹을 수 있는 죽을 배달과 포장으로 받을 수 있습니다.", + "en": "Porridge for the liquid and soft-food stages, by delivery or takeout." + }, + "mapQuery": "본죽 {AREA_KO}", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "smoothie", + "name": { + "ko": "스무디·주스 카페 ({AREA_KO})", + "en": "Smoothie and juice cafes ({AREA_EN})" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.4, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "빨대로 마실 수 있는 메뉴가 많습니다. 뜨겁지 않은 것으로 고르세요.", + "en": "Straw-friendly options. Choose nothing hot." + }, + "mapQuery": "스무디 카페 {AREA_KO}", + "verify": true, + "dietOk": [ + "liquid", + "soft", + "mild", + "normal" + ] + }, + { + "id": "soup", + "name": { + "ko": "설렁탕·곰탕 ({AREA_KO} 일대)", + "en": "Beef bone soup ({AREA_EN})" + }, + "category": "food", + "minLevel": 1, + "distanceKm": 0.6, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "국물 위주라 부드러운 음식 단계부터 가능합니다.", + "en": "Broth-based, fine from the soft-food stage." + }, + "mapQuery": "설렁탕 {AREA_KO}", + "verify": true, + "dietOk": [ + "soft", + "mild", + "normal" + ] + }, + { + "id": "clinic-followup", + "name": { + "ko": "{CLINIC_KO} 경과 확인", + "en": "{CLINIC_EN} follow-up" + }, + "category": "care", + "minLevel": 1, + "distanceKm": 0.05, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "경과 확인과 관리는 병원 안내에 따라 예약합니다.", + "en": "Follow-up checks and care, booked per the clinic's guidance." + }, + "mapQuery": "{CLINIC_KO}", + "verify": true + }, + { + "id": "hotel-lounge", + "name": { + "ko": "호텔 스파·라운지 (숙소 안)", + "en": "Hotel spa and lounge (at your hotel)" + }, + "category": "care", + "minLevel": 0, + "distanceKm": 0, + "indoor": true, + "area": { + "ko": "{AREA_KO}", + "en": "{AREA_EN}" + }, + "note": { + "ko": "사우나와 마사지는 담당 원장이 허용하기 전에는 피하고 라운지와 룸서비스만 이용하세요.", + "en": "Skip sauna and massage until your doctor allows. Lounge and room service are fine." + }, + "mapQuery": null, + "verify": true + } + ] +} diff --git a/templates/supporters-astro/src/data/planStrings.json b/templates/supporters-astro/src/data/planStrings.json new file mode 100644 index 0000000..f2d76fe --- /dev/null +++ b/templates/supporters-astro/src/data/planStrings.json @@ -0,0 +1,235 @@ +{ + "_comment": "회복기 스케줄러 UI 문자열. ko/en 두 언어. 일본어·중국어는 P1에서 같은 키로 추가한다. 고객 화면이므로 운영자 어휘를 쓰지 않는다.", + "ko": { + "eyebrow": "Recovery Planner", + "title": "수술일을 정하셨다면, 여행 일정은 여기서 짜세요.", + "lede": "시술과 수술일을 고르면 입국 권장일, 출국 가능 최소일, 회복기 동안 외출할 수 있는 날과 그날 갈 만한 곳을 정리해 드립니다. 계산은 이 화면 안에서만 이루어지고 어디에도 저장되지 않습니다.", + "step1": "국적", + "step2": "시술과 수술일", + "step3": "여유 시간에 하고 싶은 것", + "step4": "일정표", + "step5": "예약과 저장", + "lang": "언어", + "nationality": "국적", + "procedure": "시술", + "surgeryDate": "수술일", + "surgeryDateHint": "상담에서 확정한 날짜를 넣으세요. 아직 정하지 않았다면 예상일도 괜찮습니다.", + "prefs": "여러 개 고를 수 있습니다", + "pref_sightseeing": "관광", + "pref_shopping": "쇼핑", + "pref_food": "미식", + "pref_kpop": "K-pop·핫플", + "pref_care": "휴식·케어", + "generate": "일정표 만들기", + "arriveBy": "입국 권장일", + "surgery": "수술일", + "hospital": "입원", + "hospitalNights": "{n}박", + "hospitalNone": "당일 귀가", + "stitch": "실밥·부목 제거", + "departure": "출국 가능 최소일", + "stayNights": "총 체류", + "nights": "{n}박", + "pending": "확인", + "provisional": "병원 확인 전", + "clinicSourced": "병원 안내 기준", + "departureNote": "출국 가능 최소일은 최소 기준입니다. 담당 원장이 경과를 보고 다르게 안내할 수 있으니 항공권은 변경 가능한 조건으로 예약하세요.", + "dayBefore": "수술 {n}일 전", + "daySurgery": "수술 당일", + "dayAfter": "수술 후 {n}일", + "level": "외출", + "diet": "식사", + "picks": "추천", + "noPicks": "이 날은 쉬는 날입니다. 배달과 룸서비스를 이용하세요.", + "constraints": "회복기 동안 지킬 것", + "visaTitle": "체류 기간 확인", + "visaOk": "{country} 국적의 무비자 체류 한도는 {days}일이고 이 일정은 {stay}일입니다. 한도 안에 있습니다.", + "visaOver": "{country} 국적의 무비자 체류 한도는 {days}일인데 이 일정은 {stay}일입니다. 비자가 필요할 수 있으니 확인하세요.", + "visaRequired": "{country} 국적은 사전 비자가 필요할 수 있습니다. 출발 전 확인하세요.", + "visaVerify": "체류 한도는 2026년 9월 기준이며 바뀔 수 있습니다. 대한민국 비자포털에서 확인하세요.", + "visaPortal": "대한민국 비자포털", + "hotels": "병원 근처 숙소", + "hotelHint": "입국 권장일부터 출국 가능 최소일까지 날짜를 넣어 검색합니다. 엘리베이터, 룸서비스, 24시간 프런트가 있는 곳을 골랐습니다.", + "hotelSearch": "이 날짜로 검색", + "flights": "항공권", + "flightHint": "인천공항 도착 기준으로 날짜를 채워 검색합니다. 변경 가능한 요금을 권합니다.", + "flightSearch": "구글 항공권에서 보기", + "consult": "상담 예약", + "consultHint": "아래 일정 요약을 복사해 상담 신청 때 함께 보내면 병원이 회복 일정에 맞춰 안내할 수 있습니다.", + "copySummary": "일정 요약 복사", + "copied": "복사했습니다", + "shareLink": "링크 복사", + "ics": "캘린더에 저장", + "print": "인쇄", + "map": "지도", + "readMore": "회복 일정 자세히", + "affiliate": "숙소·항공 링크는 각 예약 사이트로 이동하며, 제휴 링크가 적용될 경우 이 매체가 소정의 수수료를 받을 수 있습니다. 예약 조건과 결제는 각 사이트의 안내를 따릅니다.", + "medical": "이 일정표는 병원 공개 안내를 바탕으로 한 일반 정보입니다. 본인 수술 범위와 경과에 따라 담당 원장의 지시가 우선합니다.", + "km": "{km}km", + "walk": "도보", + "taxi": "택시", + "indoor": "실내", + "summaryTitle": "회복 일정 요약", + "levelLabel": "외출 단계", + "sourceLabel": "근거", + "reset": "처음부터", + "provisionalNote": "\"병원 확인 전\"으로 표시된 값은 병원 공개 안내에 없어 일반 기준으로 넣은 잠정값입니다. 상담에서 본인 일정으로 확정하세요.", + "noRemoval": "제거 방문 없음", + "h_hero": "Plan Your Recovery Stay", + "h_step1": "Nationality", + "h_step2": "Procedure & Surgery Date", + "h_step3": "Your Free Time", + "h_step4": "Your Schedule", + "h_visa": "Length of Stay", + "h_rules": "During Recovery", + "h_days": "Day by Day", + "h_book": "Book & Save", + "h_hotels": "Hotels Near the Clinic", + "h_flights": "Flights", + "h_consult": "Consultation", + "h_input": "Build Your Schedule", + "sub_input": "세 가지만 고르면 일정표가 바로 나옵니다.", + "stat_procs": "시술", + "stat_places": "추천 장소", + "stat_places_d": "큐레이션과 한국관광공사 TourAPI. {origin} 기준 거리·이동 시간 표시", + "stat_hotels": "근처 숙소", + "stat_hotels_d": "병원 도보 10분 안, 엘리베이터·룸서비스·24시간 프런트", + "stat_privacy": "서버 저장", + "stat_privacy_d": "시술과 수술일은 이 화면 안에서만 계산합니다", + "sub_schedule": "핵심 날짜 여섯 개입니다. 항공권과 숙소는 이 날짜로 검색합니다.", + "sub_days": "날짜마다 외출 단계와 식사 단계, 그날 갈 만한 곳을 표시합니다.", + "sub_book": "입국 권장일부터 출국 가능 최소일까지 날짜를 채워 검색합니다.", + "sub_rules": "담당 원장 안내가 우선이고, 아래는 병원 공개 안내 기준입니다.", + "empty_title": "시술과 수술일을 고르면 여기에 일정표가 나옵니다", + "empty_sub": "수술일은 예상일이어도 됩니다.", + "stickyView": "일정표 보기", + "stickyStay": "{a} → {b} · {n}박", + "h_step1_hint": "국적을 고르면 시차와 무비자 체류 한도를 함께 봅니다.", + "h_fest": "Festivals During Your Stay", + "sub_fest": "체류 기간과 겹치는 행사입니다. 자유 외출 단계가 되는 날부터 갈 수 있습니다.", + "fest_none": "체류 기간과 겹치는 행사가 없습니다.", + "fest_when": "{a} ~ {b}", + "fest_from": "{d}부터 가능", + "fest_notYet": "이번 체류에서는 자유 외출 단계에 닿지 않습니다", + "source_tour": "장소·행사 데이터: 한국관광공사 TourAPI, {date} 기준. 영업 여부와 행사 일정은 방문 전에 확인하세요.", + "tour_badge": "관광공사", + "festival_pick": "행사", + "readMoreShort": "홈페이지" + }, + "en": { + "eyebrow": "Recovery Planner", + "title": "Surgery date set? Plan the rest of your trip here.", + "lede": "Pick your procedure and surgery date. We work out when to arrive, the earliest you can fly home, which recovery days you can go out, and where to go on those days. Everything is calculated on this page and stored nowhere.", + "step1": "", + "step2": "", + "step3": "", + "step4": "", + "step5": "", + "lang": "Language", + "nationality": "Nationality", + "procedure": "Procedure", + "surgeryDate": "Surgery date", + "surgeryDateHint": "Use the date confirmed at consultation. An estimate is fine if it's not set yet.", + "prefs": "Choose as many as you like", + "pref_sightseeing": "Sightseeing", + "pref_shopping": "Shopping", + "pref_food": "Food", + "pref_kpop": "K-pop & hotspots", + "pref_care": "Rest & care", + "generate": "Build my schedule", + "arriveBy": "Arrive by", + "surgery": "Surgery", + "hospital": "Hospital stay", + "hospitalNights": "{n} night(s)", + "hospitalNone": "Same-day discharge", + "stitch": "Stitch / splint removal", + "departure": "Earliest departure", + "stayNights": "Total stay", + "nights": "{n} nights", + "pending": "To confirm", + "provisional": "Provisional", + "clinicSourced": "From clinic guidance", + "departureNote": "Earliest departure is a minimum. Your surgeon may advise differently after follow-up, so book flights with flexible terms.", + "dayBefore": "{n} day(s) before surgery", + "daySurgery": "Surgery day", + "dayAfter": "Day {n} after surgery", + "level": "Outing", + "diet": "Diet", + "picks": "Suggestions", + "noPicks": "A rest day. Use delivery and room service.", + "constraints": "During recovery", + "visaTitle": "Length of stay check", + "visaOk": "Visa-free stay for {country} nationals is {days} days and this plan is {stay} days. You're within the limit.", + "visaOver": "Visa-free stay for {country} nationals is {days} days but this plan is {stay} days. You may need a visa, please check.", + "visaRequired": "{country} nationals may need a visa in advance. Check before you travel.", + "visaVerify": "Stay limits are as of September 2026 and may change. Confirm at the Korea Visa Portal.", + "visaPortal": "Korea Visa Portal", + "hotels": "Hotels near the clinic", + "hotelHint": "Searches with your arrival and earliest-departure dates filled in. We picked places with elevators, room service and a 24-hour front desk.", + "hotelSearch": "Search these dates", + "flights": "Flights", + "flightHint": "Searches with your dates filled in, arriving at Incheon. Flexible fares recommended.", + "flightSearch": "Open in Google Flights", + "consult": "Book a consultation", + "consultHint": "Copy the summary below and send it with your consultation request so the clinic can plan around your recovery dates.", + "copySummary": "Copy summary", + "copied": "Copied", + "shareLink": "Copy link", + "ics": "Save to calendar", + "print": "Print", + "map": "Map", + "readMore": "Full recovery timeline", + "affiliate": "Hotel and flight links open the booking sites. Where an affiliate link applies, this site may earn a small commission. Booking terms and payment follow each site.", + "medical": "This schedule is general information based on the clinic's published guidance. Your surgeon's instructions for your own case take priority.", + "km": "{km} km", + "walk": "walk", + "taxi": "taxi", + "indoor": "indoor", + "summaryTitle": "Recovery schedule summary", + "levelLabel": "Outing level", + "sourceLabel": "Source", + "reset": "Start over", + "provisionalNote": "Values marked \"Provisional\" are not in the clinic's published guidance and use general estimates. Confirm your own dates at consultation.", + "noRemoval": "No removal visit", + "h_hero": "Plan Your Recovery Stay", + "h_step1": "Nationality", + "h_step2": "Procedure & Surgery Date", + "h_step3": "Your Free Time", + "h_step4": "Your Schedule", + "h_visa": "Length of Stay", + "h_rules": "During Recovery", + "h_days": "Day by Day", + "h_book": "Book & Save", + "h_hotels": "Hotels Near the Clinic", + "h_flights": "Flights", + "h_consult": "Consultation", + "h_input": "Build Your Schedule", + "sub_input": "Pick three things and your schedule appears.", + "stat_procs": "procedures", + "stat_places": "curated places", + "stat_places_d": "Curated picks plus Korea Tourism Organization data, with distance and travel time from {origin}", + "stat_hotels": "hotels nearby", + "stat_hotels_d": "Within a 10-minute walk, with elevators, room service and 24-hour desks", + "stat_privacy": "stored on servers", + "stat_privacy_d": "Your procedure and dates are calculated on this page only", + "sub_schedule": "Six key dates. Flights and hotels are searched with these.", + "sub_days": "Each day shows the outing level, diet stage and places worth going.", + "sub_book": "Searches are filled with your arrival and earliest-departure dates.", + "sub_rules": "Your surgeon's instructions come first. Below is the clinic's published guidance.", + "empty_title": "Pick a procedure and a surgery date to see your schedule here", + "empty_sub": "An estimated date is fine.", + "stickyView": "See schedule", + "stickyStay": "{a} → {b} · {n} nights", + "h_step1_hint": "Your nationality sets the jet-lag buffer and the visa-free stay check.", + "h_fest": "Festivals During Your Stay", + "sub_fest": "Events that overlap your stay. You can go from the first full-day-out date.", + "fest_none": "No events overlap your stay.", + "fest_when": "{a} to {b}", + "fest_from": "From {d}", + "fest_notYet": "Your stay does not reach the full-day-out stage", + "source_tour": "Places and events: Korea Tourism Organization TourAPI, as of {date}. Check opening status and event dates before you go.", + "tour_badge": "KTO", + "festival_pick": "Event", + "readMoreShort": "Website" + } +} diff --git a/templates/supporters-astro/src/data/procedures.json b/templates/supporters-astro/src/data/procedures.json new file mode 100644 index 0000000..ac95bc8 --- /dev/null +++ b/templates/supporters-astro/src/data/procedures.json @@ -0,0 +1,961 @@ +{ + "_comment": "성형외과 기본 규칙표 (뷰성형외과 샘플에서 정리). 워커 planner 단계(scripts/build_planner_data.mjs)가 병원 시술 페이지 원문(recoveryNotes.json)을 matchKeywords 로 시술에 붙여 병원별 procedures.json 을 만든다. clinic 출처가 있는 값은 뷰성형외과 공개 안내이므로 다른 병원에서는 provisional 로 내려간다.", + "clinicSources": [], + "levels": [ + { + "level": 0, + "label": { + "ko": "실내 안정", + "en": "Rest indoors" + }, + "desc": { + "ko": "병실이나 호텔에서 쉬는 날입니다. 필요한 것은 배달과 룸서비스로 해결합니다.", + "en": "Rest at the hospital or hotel. Use delivery and room service." + } + }, + { + "level": 1, + "label": { + "ko": "근거리 외출", + "en": "Short walks" + }, + "desc": { + "ko": "호텔 반경 500m 안에서 짧게 다녀옵니다. 도보 10분 이내.", + "en": "Short trips within 500 m of your hotel. Up to a 10-minute walk." + } + }, + { + "level": 2, + "label": { + "ko": "반나절 외출", + "en": "Half-day outing" + }, + "desc": { + "ko": "택시로 반경 3km 안 쇼핑·식사·가벼운 관광이 가능합니다.", + "en": "Shopping, dining and light sightseeing within 3 km by taxi." + } + }, + { + "level": 3, + "label": { + "ko": "자유 외출", + "en": "Full day out" + }, + "desc": { + "ko": "하루 단위 외출이 가능합니다. 시내 관광, 행사, 인파가 있는 곳도 담당 원장 안내 안에서 가능합니다.", + "en": "Full-day outings. City sightseeing and events, within your surgeon's guidance." + } + } + ], + "diets": { + "liquid": { + "label": { + "ko": "유동식", + "en": "Liquid diet" + }, + "desc": { + "ko": "건더기 없는 유동식만 드십니다.", + "en": "Liquids only, no solids." + } + }, + "soft": { + "label": { + "ko": "부드러운 음식", + "en": "Soft foods" + }, + "desc": { + "ko": "건더기가 있어도 부드러운 음식까지 가능합니다.", + "en": "Soft foods are fine. Avoid anything chewy or hard." + } + }, + "mild": { + "label": { + "ko": "자극 없는 일반식", + "en": "Regular, non-spicy" + }, + "desc": { + "ko": "맵고 짜거나 딱딱한 음식은 피합니다.", + "en": "Regular meals. Avoid spicy, salty or hard foods." + } + }, + "normal": { + "label": { + "ko": "일반식", + "en": "Regular diet" + }, + "desc": { + "ko": "식사 제한이 없습니다.", + "en": "No dietary restrictions." + } + } + }, + "constraints": { + "no-heavy-lifting": { + "ko": "무거운 짐과 팔을 많이 쓰는 동작을 피합니다. 쇼핑은 배송 서비스를 이용하세요.", + "en": "Avoid heavy bags and arm-heavy movement. Use delivery for shopping." + }, + "sports-bra": { + "ko": "스포츠브라를 1~3개월 유지합니다.", + "en": "Wear a sports bra for 1 to 3 months." + }, + "no-alcohol-30d": { + "ko": "음주와 흡연은 최소 1개월 이후입니다.", + "en": "No alcohol or smoking for at least 1 month." + }, + "no-sauna-60d": { + "ko": "사우나, 찜질방, 수영, 과한 운동은 약 2개월 후입니다.", + "en": "No sauna, spa, swimming or intense exercise for about 2 months." + }, + "compression-band": { + "ko": "압박밴드를 2~4주 착용합니다. 취침 시에는 하지 않습니다.", + "en": "Wear the compression band for 2 to 4 weeks, not while sleeping." + }, + "sleep-elevated": { + "ko": "머리를 심장보다 높게 하고 정면 자세로 잡니다. 1주 후부터 옆으로 누워도 됩니다.", + "en": "Sleep with your head above heart level, facing up. Side sleeping from week 2." + }, + "saline-gargle": { + "ko": "약 1개월간 생리식염수 가글을 꾸준히 합니다.", + "en": "Rinse with saline regularly for about 1 month." + }, + "no-hard-food-30d": { + "ko": "질기고 딱딱한 음식은 한 달간 피합니다.", + "en": "Avoid chewy or hard food for 1 month." + }, + "no-sun": { + "ko": "직사광선을 피합니다. 모자와 선글라스를 챙기세요.", + "en": "Avoid direct sun. Bring a hat and sunglasses." + }, + "mask": { + "ko": "외출 시 마스크를 쓰면 부기와 멍이 덜 보입니다.", + "en": "A mask helps cover swelling and bruising when out." + }, + "no-glasses": { + "ko": "안경 착용을 피합니다. 콘택트렌즈나 안경 없이 다닐 계획을 세우세요.", + "en": "Avoid glasses resting on your nose. Plan for contacts or going without." + }, + "no-lens": { + "ko": "콘택트렌즈는 담당 원장이 허용할 때까지 쓰지 않습니다.", + "en": "No contact lenses until your surgeon allows." + }, + "cold-compress": { + "ko": "초기에는 냉찜질, 이후 온찜질을 합니다.", + "en": "Cold compresses at first, then warm." + }, + "no-nose-blow": { + "ko": "코를 세게 풀거나 코 부위에 압력을 주지 않습니다.", + "en": "Do not blow your nose or press on the nose area." + }, + "no-massage": { + "ko": "수술 부위 마사지와 강한 압박을 피합니다.", + "en": "No massage or firm pressure on the surgical area." + }, + "no-hat-pressure": { + "ko": "이식 부위를 누르는 모자나 헬멧을 피합니다.", + "en": "Avoid hats or helmets that press on the graft area." + }, + "no-scratch": { + "ko": "가려워도 긁지 않습니다.", + "en": "Do not scratch, even if itchy." + }, + "driving": { + "ko": "수술 당일은 운전할 수 없습니다. 보호자 동반을 권합니다.", + "en": "No driving on surgery day. A companion is recommended." + } + }, + "procedures": [ + { + "id": "breast", + "label": { + "ko": "가슴성형", + "en": "Breast Augmentation" + }, + "group": { + "ko": "가슴", + "en": "Breast" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "검진과 상담 1일, 여유 1일", + "en": "1 day for tests and consultation, 1 buffer day" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 10 + ], + "status": "provisional", + "note": { + "ko": "실밥이 있으면 약 1주에 제거. 피부 접착제를 쓴 경우 실밥 없음", + "en": "Stitches, if any, removed at about 1 week. No stitches if skin adhesive was used" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional", + "note": { + "ko": "부기는 2~3일째 가장 심합니다", + "en": "Swelling peaks on days 2 to 3" + } + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional", + "note": { + "ko": "3일 이후 붕대를 뗍니다", + "en": "Bandage removed after day 3" + } + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "no-heavy-lifting", + "sports-bra", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "가슴|유방|보형물|모티바" + }, + { + "id": "contour", + "label": { + "ko": "안면윤곽·양악", + "en": "Facial Contouring / Jaw Surgery" + }, + "group": { + "ko": "얼굴뼈", + "en": "Facial bone" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional", + "note": { + "ko": "3D-CT 촬영과 검진, 상담", + "en": "3D-CT, tests and consultation" + } + }, + "hospitalNights": { + "value": 1, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "입안 실은 녹는 실이라 보통 한 달 후 저절로 없어집니다. 별도 제거 방문 없음", + "en": "Intraoral stitches dissolve on their own in about a month. No removal visit" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 14, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional", + "note": { + "ko": "부기는 3~4일까지 늘다가 가라앉습니다", + "en": "Swelling increases until day 3 to 4, then subsides" + } + }, + { + "fromDay": 5, + "level": 1, + "status": "provisional", + "note": { + "ko": "5~7일 후 일상생활이 가능합니다", + "en": "Daily activities possible after day 5 to 7" + } + }, + { + "fromDay": 10, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 21, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "liquid", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 14, + "type": "mild", + "status": "provisional" + }, + { + "fromDay": 30, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "compression-band", + "sleep-elevated", + "saline-gargle", + "no-hard-food-30d", + "no-alcohol-30d", + "no-sauna-60d", + "no-massage" + ], + "sources": [], + "matchKeywords": "윤곽|양악|사각턱|광대|턱끝|무턱|주걱턱" + }, + { + "id": "eye", + "label": { + "ko": "눈성형", + "en": "Eyelid Surgery" + }, + "group": { + "ko": "눈", + "en": "Eyes" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 6, + "range": [ + 5, + 7 + ], + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 10, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "cold-compress", + "no-sun", + "no-lens", + "no-scratch", + "no-alcohol-30d" + ], + "sources": [], + "matchKeywords": "눈|쌍꺼풀|매몰|절개|트임|눈매" + }, + { + "id": "nose", + "label": { + "ko": "코성형", + "en": "Rhinoplasty" + }, + "group": { + "ko": "코", + "en": "Nose" + }, + "readMore": null, + "preOpDays": { + "value": 2, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "range": [ + 5, + 7 + ], + "status": "provisional", + "note": { + "ko": "부목과 실밥 제거", + "en": "Splint and stitch removal" + } + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "mild", + "status": "provisional" + }, + { + "fromDay": 14, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-glasses", + "no-nose-blow", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "코|비중격|콧" + }, + { + "id": "fat", + "label": { + "ko": "지방성형", + "en": "Liposuction / Fat Grafting" + }, + "group": { + "ko": "지방", + "en": "Fat" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 7, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 2, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 5, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "compression-band", + "no-massage", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "지방|흡입|바디" + }, + { + "id": "lifting", + "label": { + "ko": "안티에이징·리프팅", + "en": "Anti-aging / Face Lift" + }, + "group": { + "ko": "리프팅", + "en": "Lifting" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": 7, + "status": "provisional" + }, + "earliestDepartureDay": { + "value": 10, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 14, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "soft", + "status": "provisional" + }, + { + "fromDay": 7, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "driving", + "mask", + "no-massage", + "no-sun", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "리프팅|거상|주름|안티에이징" + }, + { + "id": "skin", + "label": { + "ko": "피부과 시술", + "en": "Dermatology Treatment" + }, + "group": { + "ko": "피부", + "en": "Skin" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "실밥 없음", + "en": "No stitches" + }, + "display": { + "ko": "제거 방문 없음", + "en": "No removal visit" + } + }, + "earliestDepartureDay": { + "value": 2, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "피부|레이저|보톡스|필러|토닝|색소" + }, + { + "id": "hair", + "label": { + "ko": "모발이식", + "en": "Hair Transplant" + }, + "group": { + "ko": "모발", + "en": "Hair" + }, + "readMore": null, + "preOpDays": { + "value": 1, + "status": "provisional" + }, + "hospitalNights": { + "value": 0, + "status": "provisional" + }, + "stitchRemovalDay": { + "value": null, + "status": "provisional", + "note": { + "ko": "채취 방식에 따라 다릅니다", + "en": "Depends on the harvesting method" + } + }, + "earliestDepartureDay": { + "value": 3, + "status": "provisional" + }, + "outingLevels": [ + { + "fromDay": 0, + "level": 0, + "status": "provisional" + }, + { + "fromDay": 1, + "level": 1, + "status": "provisional" + }, + { + "fromDay": 3, + "level": 2, + "status": "provisional" + }, + { + "fromDay": 7, + "level": 3, + "status": "provisional" + } + ], + "diet": [ + { + "fromDay": 0, + "type": "normal", + "status": "provisional" + } + ], + "constraints": [ + "no-sun", + "no-hat-pressure", + "no-scratch", + "no-alcohol-30d", + "no-sauna-60d" + ], + "sources": [], + "matchKeywords": "모발|탈모" + } + ], + "nationalities": { + "_comment": "무비자 체류 한도(일). 2026-09 기준 확인 필요. null 은 사전 비자 필요. 화면은 항상 대한민국 비자포털 링크와 함께 보여준다.", + "portal": "https://www.visa.go.kr", + "list": [ + { + "code": "US", + "label": { + "ko": "미국", + "en": "United States" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "CA", + "label": { + "ko": "캐나다", + "en": "Canada" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "GB", + "label": { + "ko": "영국", + "en": "United Kingdom" + }, + "visaFreeDays": 180, + "longHaul": true + }, + { + "code": "AU", + "label": { + "ko": "호주", + "en": "Australia" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "JP", + "label": { + "ko": "일본", + "en": "Japan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TW", + "label": { + "ko": "대만", + "en": "Taiwan" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "HK", + "label": { + "ko": "홍콩", + "en": "Hong Kong" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "SG", + "label": { + "ko": "싱가포르", + "en": "Singapore" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "TH", + "label": { + "ko": "태국", + "en": "Thailand" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "MY", + "label": { + "ko": "말레이시아", + "en": "Malaysia" + }, + "visaFreeDays": 90, + "longHaul": false + }, + { + "code": "AE", + "label": { + "ko": "아랍에미리트", + "en": "United Arab Emirates" + }, + "visaFreeDays": 90, + "longHaul": true + }, + { + "code": "RU", + "label": { + "ko": "러시아", + "en": "Russia" + }, + "visaFreeDays": 60, + "longHaul": true + }, + { + "code": "KZ", + "label": { + "ko": "카자흐스탄", + "en": "Kazakhstan" + }, + "visaFreeDays": 30, + "longHaul": true + }, + { + "code": "CN", + "label": { + "ko": "중국", + "en": "China" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "VN", + "label": { + "ko": "베트남", + "en": "Vietnam" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "ID", + "label": { + "ko": "인도네시아", + "en": "Indonesia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "PH", + "label": { + "ko": "필리핀", + "en": "Philippines" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "MN", + "label": { + "ko": "몽골", + "en": "Mongolia" + }, + "visaFreeDays": null, + "longHaul": false + }, + { + "code": "OTHER", + "label": { + "ko": "그 외", + "en": "Other" + }, + "visaFreeDays": null, + "longHaul": true + } + ] + } +} diff --git a/templates/supporters-astro/src/data/recoveryNotes.json b/templates/supporters-astro/src/data/recoveryNotes.json new file mode 100644 index 0000000..1ed4877 --- /dev/null +++ b/templates/supporters-astro/src/data/recoveryNotes.json @@ -0,0 +1,8 @@ +{ + "_comment": "시술 후 관리 안내(빈 값). 워커의 recovery 단계(scripts/collect_recovery.mjs)가 병원 시술 페이지 원문에서 채운다. items 가 비어 있으면 /stay·/en/stay 는 이 블록을 그리지 않는다.", + "clinic": "", + "generatedAt": "", + "sourceNote": "병원 홈페이지 시술 페이지 원문", + "items": [], + "counts": {} +} diff --git a/templates/supporters-astro/src/layouts/Base.astro b/templates/supporters-astro/src/layouts/Base.astro index d55e340..d9cba52 100644 --- a/templates/supporters-astro/src/layouts/Base.astro +++ b/templates/supporters-astro/src/layouts/Base.astro @@ -18,14 +18,14 @@ const { title, description, jsonLd, ogImage = S.buildingImage?.src || '/favicon. const isEn = lang === 'en'; // 머리말·꼬리말 문구. 법적 고지(지원 관계·부작용)는 번역하지 않는다. 아래 주석 참조. const T = isEn - ? { nav: [['/posts', 'Questions'], ['/videos', 'Doctors'], ['/newsroom', 'Newsroom'], ['/en/stay', 'Your Stay'], ['/about', 'About']], cta: 'Book a Consultation', supporters: 'SUPPORTERS', back: 'Back', top: 'Back to top', sample: 'This is a sample site, not yet public.' } - : { nav: [['/posts', '상담 전 질문'], ['/videos', '의료진 영상'], ['/newsroom', '뉴스룸'], ['/stay', '주변 안내'], ['/visit', '방문 안내'], ['/about', '매체 소개']], cta: '상담 예약', supporters: '서포터즈', back: '이전 페이지', top: '맨 위로', sample: '샘플 사이트입니다. 정식 공개 전입니다.' }; + ? { nav: [['/posts', 'Questions'], ['/videos', 'Doctors'], ['/newsroom', 'Newsroom'], ['/en/plan', 'Recovery Planner'], ['/about', 'About']], cta: 'Book a Consultation', supporters: 'SUPPORTERS', back: 'Back', top: 'Back to top', sample: 'This is a sample site, not yet public.' } + : { nav: [['/posts', '상담 전 질문'], ['/videos', '의료진 영상'], ['/newsroom', '뉴스룸'], ['/visit', '방문 안내'], ['/plan', '회복 일정'], ['/about', '매체 소개']], cta: '상담 예약', supporters: '서포터즈', back: '이전 페이지', top: '맨 위로', sample: '샘플 사이트입니다. 정식 공개 전입니다.' }; // 언어 전환. 같은 내용의 짝이 있는 페이지만 서로 잇고, 없으면 그 언어의 입구로 보낸다. // 영문 페이지가 늘어나면 이 표에 줄만 추가한다. -const PAIRS: Record = { '/stay': '/en/stay', '/visit': '/en/stay' }; +const PAIRS: Record = { '/plan': '/en/plan', '/visit': '/en/plan' }; const KO_ENTRY = '/'; -const EN_ENTRY = '/en/stay'; +const EN_ENTRY = '/en/plan'; const path = (Astro.url.pathname.replace(/\.html$/, '').replace(/\/index$/, '/').replace(/\/$/, '') || '/'); const koPair = Object.entries(PAIRS).find(([, en]) => en === path)?.[0]; const otherHref = isEn ? (koPair ?? KO_ENTRY) : (PAIRS[path] ?? EN_ENTRY); @@ -34,7 +34,7 @@ const otherExact = isEn ? Boolean(koPair) : Boolean(PAIRS[path]); // 영문 페이지의 예약 버튼은 병원의 외국인용 영문 사이트로 보낸다(factSheet.urlEn). // 한국어 예약 페이지로 보내면 영어로 온 사람이 한국어 화면을 만난다. const ctaHref = isEn - ? ((f as Record).reservationUrlEn || (f as Record).urlEn || reservationUrl || '/en/stay') + ? ((f as Record).reservationUrlEn || (f as Record).urlEn || reservationUrl || '/en/plan') : (reservationUrl || '/visit'); // 의료광고 고지는 규정 대상이라 임의로 번역하지 않는다(의료법 56조·추천보증 심사지침). // 병원이 영문 문구를 확정해 site.json 의 sponsorNoticeEn / factSheet 의 sideEffectNoticeEn 에 넣기 전까지는 diff --git a/templates/supporters-astro/src/lib/plan.ts b/templates/supporters-astro/src/lib/plan.ts new file mode 100644 index 0000000..8994cf4 --- /dev/null +++ b/templates/supporters-astro/src/lib/plan.ts @@ -0,0 +1,177 @@ +// 회복기 스케줄러 계산 로직 (설계 v0.2 §13.3·§13.7·§13.8). 화면과 분리된 순수 함수만 둔다. +// 입력: 시술 id, 수술일, 국적, 선호. 출력: 날짜별 외출 등급·식사·추천과 예약 링크. 서버 호출 없음. +// 검증: node --experimental-strip-types scripts/gate/plan.test.mjs + +export type Lang = 'ko' | 'en'; +export type L10n = Record; +export type Status = 'clinic' | 'provisional'; +export interface Valued { value: number | null; range?: [number, number]; status: Status; source?: string; note?: L10n } +export interface LevelStep { fromDay: number; level: number; status: Status; source?: string; note?: L10n } +export interface DietStep { fromDay: number; type: 'liquid' | 'soft' | 'mild' | 'normal'; status: Status; source?: string } +export interface Procedure { + id: string; label: L10n; group: L10n; readMore: string | null; + preOpDays: Valued; hospitalNights: Valued; stitchRemovalDay: Valued; earliestDepartureDay: Valued; + outingLevels: LevelStep[]; diet: DietStep[]; constraints: string[]; sources: string[]; +} +export interface Place { + id: string; name: L10n; category: string; minLevel: number; dietOk?: string[]; distanceKm: number; indoor: boolean; + area: L10n; note: L10n; mapQuery: string | null; bookingQuery?: string; verify: boolean; + source?: 'curated' | 'tourapi'; travelLabel?: string; image?: string; url?: string; +} +export interface Nationality { code: string; label: L10n; visaFreeDays: number | null; longHaul: boolean } + +export interface PlanFestival { id: string; title: string; start: string; end: string } +export interface PlanInput { procedure: Procedure; surgeryDate: string; nationality?: Nationality | null; prefs: string[]; festivals?: PlanFestival[] } +export interface PlanDay { date: string; offset: number; level: number; diet: DietStep['type']; picks: Place[]; festivals: PlanFestival[]; isSurgery: boolean; isHospital: boolean; isStitch: boolean; isArrival: boolean; isDeparture: boolean } +export interface Plan { + arriveBy: string; surgeryDate: string; dischargeDate: string | null; stitchDate: string | null; earliestDeparture: string | null; + stayNights: number | null; preOpDays: number; days: PlanDay[]; +} + +const DAY = 86_400_000; +export const addDays = (iso: string, n: number): string => { + const d = new Date(`${iso}T00:00:00Z`); + return new Date(d.getTime() + n * DAY).toISOString().slice(0, 10); +}; +export const isIsoDate = (s: unknown): s is string => typeof s === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(s) && !Number.isNaN(Date.parse(`${s}T00:00:00Z`)); + +/** fromDay 오름차순 단계표에서 offset 에 해당하는 단계. 첫 단계 이전이면 첫 단계. */ +function stepAt(steps: T[], offset: number): T { + const sorted = [...steps].sort((a, b) => a.fromDay - b.fromDay); + let cur = sorted[0]; + for (const s of sorted) if (offset >= s.fromDay) cur = s; + return cur; +} + +/** 장거리 국적은 시차 회복으로 준비일에 1일을 더한다 (§13.3). */ +export function effectivePreOpDays(p: Procedure, nat?: Nationality | null): number { + const base = p.preOpDays.value ?? 2; + return base + (nat?.longHaul ? 1 : 0); +} + +/** + * 장소 점수. 선호 일치가 가장 크고, 등급이 딱 맞을수록, 가까울수록 높다. + * 선호가 비어 있으면 카테고리 무관하게 거리와 등급만 본다. + */ +export function scorePlace(place: Place, level: number, diet: DietStep['type'], prefs: string[]): number { + if (place.category === 'hotel') return -1; + if (place.minLevel > level) return -1; + if (place.category === 'food' && place.dietOk && !place.dietOk.includes(diet)) return -1; + let s = 0; + if (prefs.length === 0 || prefs.includes(place.category)) s += 3; + if (place.source !== 'tourapi') s += 0.75; // 큐레이션(1순위)이 같은 조건이면 먼저 나온다 + if (place.category === 'essentials' || place.category === 'care') s += 1; // 회복에 직접 필요한 것은 기본 가점 + s += 2 - Math.min(2, level - place.minLevel); // 오늘 등급에 맞는 곳을 우선 + s += Math.max(0, 1.5 - place.distanceKm / 4); // 가까울수록 가점(최대 1.5) + return s; +} + +/** 하루에 최대 3곳. 직전 2일에 나온 곳은 뒤로 미뤄 날마다 다른 곳이 나오게 한다. */ +export function pickForDay(places: Place[], level: number, diet: DietStep['type'], prefs: string[], recent: Set, max = 3): Place[] { + return places + .map((p) => ({ p, s: scorePlace(p, level, diet, prefs) - (recent.has(p.id) ? 2.5 : 0) })) + .filter((x) => x.s >= 0) + .sort((a, b) => b.s - a.s || a.p.distanceKm - b.p.distanceKm) + .slice(0, max) + .map((x) => x.p); +} + +export function buildPlan(input: PlanInput, places: Place[]): Plan { + const { procedure: p, surgeryDate, nationality, prefs, festivals = [] } = input; + const preOp = effectivePreOpDays(p, nationality); + const arriveBy = addDays(surgeryDate, -preOp); + const nights = p.hospitalNights.value; + const dischargeDate = nights === null ? null : addDays(surgeryDate, nights); + const stitchDate = p.stitchRemovalDay.value === null ? null : addDays(surgeryDate, p.stitchRemovalDay.value); + const dep = p.earliestDepartureDay.value; + const earliestDeparture = dep === null ? null : addDays(surgeryDate, dep); + const lastOffset = dep ?? Math.max(14, ...p.outingLevels.map((l) => l.fromDay)); + const days: PlanDay[] = []; + const recent: string[] = []; + for (let off = -preOp; off <= lastOffset; off++) { + const date = addDays(surgeryDate, off); + const isHospital = nights !== null && off >= 0 && off < nights; + const pre = off < 0; + const level = pre ? 2 : isHospital ? 0 : stepAt(p.outingLevels, off).level; + const diet = pre ? 'normal' : stepAt(p.diet, off).type; + const recentSet = new Set(recent.slice(-6)); + const picks = level === 0 || off === 0 ? [] : pickForDay(places, level, diet, prefs, recentSet); + recent.push(...picks.map((x) => x.id)); + const dayFest = level >= 3 ? festivals.filter((f) => f.start <= date && f.end >= date).slice(0, 1) : []; // 행사는 자유 외출(L3) 날에만 + days.push({ date, offset: off, level, diet, picks, festivals: dayFest, isSurgery: off === 0, isHospital, isStitch: stitchDate === date, isArrival: off === -preOp, isDeparture: earliestDeparture === date }); + } + return { arriveBy, surgeryDate, dischargeDate, stitchDate, earliestDeparture, stayNights: dep === null ? null : preOp + dep, preOpDays: preOp, days }; +} + +// ---------- 예약 링크 (§13.7). 검색 결과 페이지 패턴만 쓴다. 제휴 ID 는 확정 후 aid 파라미터로 붙인다. ---------- +export function bookingUrl(query: string, checkin: string, checkout: string, lang: Lang, aid?: string): string { + const u = new URL('https://www.booking.com/searchresults.html'); + u.searchParams.set('ss', query); + u.searchParams.set('checkin', checkin); + u.searchParams.set('checkout', checkout); + u.searchParams.set('group_adults', '1'); + u.searchParams.set('no_rooms', '1'); + u.searchParams.set('lang', lang === 'ko' ? 'ko' : 'en-us'); + if (aid) u.searchParams.set('aid', aid); + return u.toString(); +} +export function googleFlightsUrl(arrive: string, depart: string, lang: Lang): string { + const q = `Flights to ICN on ${arrive} returning ${depart}`; + return `https://www.google.com/travel/flights?hl=${lang}&q=${encodeURIComponent(q)}`; +} +export function mapUrl(query: string): string { + return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(query)}`; +} + +// ---------- 공유 URL 해시 (서버 미전송) ---------- +export interface HashState { p?: string; d?: string; l?: Lang; n?: string; pref?: string[] } +export function encodeHash(s: HashState): string { + const q = new URLSearchParams(); + if (s.p) q.set('p', s.p); + if (s.d) q.set('d', s.d); + if (s.l) q.set('l', s.l); + if (s.n) q.set('n', s.n); + if (s.pref?.length) q.set('pref', s.pref.join(',')); + return q.toString(); +} +export function decodeHash(hash: string): HashState { + const q = new URLSearchParams(hash.replace(/^#/, '')); + const l = q.get('l'); + return { + p: q.get('p') ?? undefined, + d: isIsoDate(q.get('d')) ? (q.get('d') as string) : undefined, + l: l === 'ko' || l === 'en' ? l : undefined, + n: q.get('n') ?? undefined, + pref: (q.get('pref') ?? '').split(',').filter(Boolean), + }; +} + +// ---------- ICS (종일 일정 4개: 입국·수술·실밥·출국) ---------- +export function buildIcs(plan: Plan, titles: { arrive: string; surgery: string; stitch: string; departure: string }, calName: string): string { + const ev = (date: string, title: string, uid: string) => [ + 'BEGIN:VEVENT', `UID:${uid}@view-supporters`, `DTSTAMP:${new Date().toISOString().replace(/[-:]/g, '').slice(0, 15)}Z`, + `DTSTART;VALUE=DATE:${date.replace(/-/g, '')}`, `DTEND;VALUE=DATE:${addDays(date, 1).replace(/-/g, '')}`, `SUMMARY:${title}`, 'END:VEVENT', + ]; + const lines = ['BEGIN:VCALENDAR', 'VERSION:2.0', 'PRODID:-//View Supporters//Recovery Planner//KO', `X-WR-CALNAME:${calName}`]; + lines.push(...ev(plan.arriveBy, titles.arrive, `arrive-${plan.arriveBy}`)); + lines.push(...ev(plan.surgeryDate, titles.surgery, `surgery-${plan.surgeryDate}`)); + if (plan.stitchDate) lines.push(...ev(plan.stitchDate, titles.stitch, `stitch-${plan.stitchDate}`)); + if (plan.earliestDeparture) lines.push(...ev(plan.earliestDeparture, titles.departure, `depart-${plan.earliestDeparture}`)); + lines.push('END:VCALENDAR'); + return lines.join('\r\n'); +} + +/** 상담 신청에 붙여 보낼 요약문. */ +export function summaryText(plan: Plan, p: Procedure, lang: Lang, t: Record): string { + const pending = t.pending; + const row = (k: string, v: string | null) => `${k}: ${v ?? pending}`; + return [ + `${t.summaryTitle} (${p.label[lang]})`, + row(t.arriveBy, plan.arriveBy), + row(t.surgery, plan.surgeryDate), + row(t.hospital, p.hospitalNights.value === null ? null : p.hospitalNights.value === 0 ? t.hospitalNone : t.hospitalNights.replace('{n}', String(p.hospitalNights.value))), + row(t.stitch, plan.stitchDate), + row(t.departure, plan.earliestDeparture), + row(t.stayNights, plan.stayNights === null ? null : t.nights.replace('{n}', String(plan.stayNights))), + ].join('\n'); +} diff --git a/templates/supporters-astro/src/lib/tour.ts b/templates/supporters-astro/src/lib/tour.ts new file mode 100644 index 0000000..25bf5b3 --- /dev/null +++ b/templates/supporters-astro/src/lib/tour.ts @@ -0,0 +1,89 @@ +// 한국관광공사 TourAPI 사전 수집 데이터(src/data/medicalTourism*.json)를 회복 일정 플래너의 장소·축제 후보로 바꾼다 (설계 v0.2 §13.5, 2순위 소스). +// 수집은 scripts/fetch_medical_tourism.py 가 병원 좌표 기준으로 미리 해 두고, 화면은 이 파일의 결과만 쓴다. 외부 호출 없음. +// 식이 적합성은 TourAPI 가 주지 않으므로 판정하지 않는다: 음식점은 일반식 단계에서만 후보가 되고, 죽·스무디 같은 회복 초기 식사는 큐레이션(places.json)이 맡는다. +import type { Place, L10n } from './plan'; + +export interface TourItem { + id: string; title: string; address: string; image: string | null; tel: string | null; lat: number; lng: number; + distanceM: number; travel: { mode: string; minutes: number; label: string } | null; overview: string; homepage: string; + startDate?: string; endDate?: string; season?: string; +} +export interface TourData { + places: Record; + festivals: TourItem[]; + meta: { lang?: string; source: string; fetchedAt: string; origin?: { lat: number; lng: number; label: string } }; +} + +/** TourAPI 유형 → 플래너 카테고리. wellness(사우나·스파)는 회복기 금지 항목이라 후보에서 뺀다. */ +const CATEGORY: Record = { attraction: 'sightseeing', culture: 'sightseeing', shopping: 'shopping', restaurant: 'food', stay: 'hotel', wellness: null }; + +/** 거리로 외출 등급을 정한다: 600m 안 근거리(L1), 3km 안 반나절(L2), 그 밖은 자유 외출(L3). */ +export const levelByDistance = (m: number): number => (m <= 600 ? 1 : m <= 3000 ? 2 : 3); + +const both = (s: string): L10n => ({ ko: s, en: s }); +/** 주소를 짧은 동네 표기로. 국문은 '구 도로명', 영문은 첫 쉼표 앞 도로명. */ +const areaLabel = (address: string, lang: 'ko' | 'en'): string => { + const a = (address || '').trim(); + if (lang === 'en') return a.split(',').map((x) => x.trim()).filter((x) => x && !/^\d+$/.test(x))[0] ?? a; + return a.replace(/^서울특별시\s*/, '').split(/\s+/).slice(0, 2).join(' '); +}; +const firstSentence = (s: string, n = 140): string => { + const t = (s || '').replace(/\d+\s*m?\s*NAVER\s*©\s*NAVER Corp\.?/gi, '').replace(/\s+/g, ' ').trim(); + if (t.length <= n) return t; + const cut = t.slice(0, n); + const stop = Math.max(cut.lastIndexOf('. '), cut.lastIndexOf('다. '), cut.lastIndexOf('。')); + return (stop > 40 ? cut.slice(0, stop + 1) : cut).trim() + (stop > 40 ? '' : '…'); +}; +/** "K-그랜드 호스텔 강남 1(K-GRAND HOSTEL GANGNAM1)" → 예약 검색용 영문 이름이 괄호 안에 있으면 그것을 쓴다. */ +export const bookingName = (title: string): string => { + const m = title.match(/\(([^)]*[A-Za-z][^)]*)\)\s*$/); + return (m ? m[1] : title).trim(); +}; + +export function tourToPlaces(data: TourData, lang: 'ko' | 'en'): Place[] { + const out: Place[] = []; + for (const [type, items] of Object.entries(data.places ?? {})) { + const category = CATEGORY[type]; + if (!category) continue; + for (const it of items) { + if (!it.lat || !it.lng) continue; + const km = Math.round((it.distanceM / 1000) * 10) / 10; + out.push({ + id: `tour-${type}-${it.id}`, + name: both(it.title), + category, + minLevel: category === 'hotel' ? 0 : levelByDistance(it.distanceM), + dietOk: category === 'food' ? ['normal'] : undefined, + distanceKm: km, + indoor: type === 'shopping' || type === 'culture' || type === 'restaurant' || type === 'stay', + area: both(areaLabel(it.address, lang)), + note: both(firstSentence(it.overview)), + mapQuery: it.title, + bookingQuery: category === 'hotel' ? bookingName(it.title) : undefined, + verify: true, + source: 'tourapi', + travelLabel: it.travel?.label ?? undefined, + image: it.image ?? undefined, + url: it.homepage || undefined, + }); + } + } + return out; +} + +export interface Festival { id: string; title: string; start: string; end: string; distanceKm: number; travelLabel?: string; blurb: string; image?: string; url?: string; address: string } +const iso = (d?: string) => (d && d.length === 8 ? `${d.slice(0, 4)}-${d.slice(4, 6)}-${d.slice(6, 8)}` : ''); + +/** 체류 기간 [from, to] 와 겹치는 행사만, 가까운 순. */ +export function festivalsDuring(data: TourData, from: string, to: string, max = 6): Festival[] { + return (data.festivals ?? []) + .map((f) => ({ f, start: iso(f.startDate), end: iso(f.endDate) })) + .filter((x) => x.start && x.end && x.start <= to && x.end >= from) + .sort((a, b) => a.f.distanceM - b.f.distanceM) + .slice(0, max) + .map(({ f, start, end }) => ({ + id: `fest-${f.id}`, title: f.title, start, end, distanceKm: Math.round((f.distanceM / 1000) * 10) / 10, + travelLabel: f.travel?.label ?? undefined, blurb: firstSentence(f.overview), image: f.image ?? undefined, + url: f.homepage || undefined, address: f.address, + })); +} diff --git a/templates/supporters-astro/src/pages/404.astro b/templates/supporters-astro/src/pages/404.astro new file mode 100644 index 0000000..dc28641 --- /dev/null +++ b/templates/supporters-astro/src/pages/404.astro @@ -0,0 +1,17 @@ +--- +// 없는 주소. Vercel 이 dist/404.html 을 자동으로 쓴다. 옛 주소(/recovery, /stay)는 vercel.json 리다이렉트가 /plan 으로 먼저 보낸다. +import Base from '../layouts/Base.astro'; +import { SITE_NAME } from '../lib'; +const site = Astro.site!.toString().replace(/\/$/, ''); +const ld = { '@type': 'WebPage', '@id': `${site}/404#page`, name: '페이지를 찾을 수 없음', url: `${site}/404`, inLanguage: 'ko', isPartOf: { '@id': `${site}/#website` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }; +--- + +
    + diff --git a/templates/supporters-astro/src/pages/en/plan.astro b/templates/supporters-astro/src/pages/en/plan.astro new file mode 100644 index 0000000..81e0bdf --- /dev/null +++ b/templates/supporters-astro/src/pages/en/plan.astro @@ -0,0 +1,16 @@ +--- +// Recovery planner, English page. Body lives in components/Planner.astro. Korean page is /plan. +import Base from '../../layouts/Base.astro'; +import Planner from '../../components/Planner.astro'; +import { fact, SITE_NAME, clinicSchema, v } from '../../lib'; +const f = fact as Record; +const clinicEn = (fact as Record).nameEn || (fact as Record).shortNameEn || (fact as Record).shortName || 'the clinic'; +const site = Astro.site!.toString().replace(/\/$/, ''); +const ld = [ + { '@type': 'WebPage', '@id': `${site}/en/plan#page`, name: `${clinicEn} Recovery Planner`, url: `${site}/en/plan`, inLanguage: 'en', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${fact.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, + clinicSchema(site), +]; +--- + + + diff --git a/templates/supporters-astro/src/pages/en/stay.astro b/templates/supporters-astro/src/pages/en/stay.astro deleted file mode 100644 index 5906845..0000000 --- a/templates/supporters-astro/src/pages/en/stay.astro +++ /dev/null @@ -1,440 +0,0 @@ ---- -// 외국인 환자용 체류 안내. 세 부분이다. -// 1. Around the clinic — 도보·차 소요 시간으로 거른 주변 장소 -// 2. Festivals — 계절로 묶은 행사 -// 3. Suggested days — 시간표와 지도가 붙은 동선 -// -// 데이터는 한국관광공사 TourAPI 영문(EngService2)에서 scripts/fetch_medical_tourism.py 가 -// 미리 수집한 src/data/medicalTourism.json 이다. 설명문은 detailCommon2 의 overview 다. -// -// 만들지 않는 것 -// - 평점·리뷰·영업시간: TourAPI 미제공. 싣지 않는다. -// - 링크: 공식 홈페이지가 있을 때만 걸고, 없으면 검색으로 보낸다. 주소를 지어내지 않는다. -// - 식이 적합성·회복 일수: 의학 판단이라 병원 확정값만 쓴다. -// - 일정의 시각: 진료 종료 시각을 가정으로 못박아 화면에 밝힌다. 병원 일정이 아니다. -import Base from '../../layouts/Base.astro'; -import { fact, site as S, SITE_NAME, clinicSchema, has } from '../../lib'; -import data from '../../data/medicalTourism.json'; - -const f = fact as Record; -const Sx = S as Record; -const clinic = f.shortNameEn || f.nameEn || f.shortName || 'the clinic'; -const site = Astro.site!.toString().replace(/\/$/, ''); -const T = data as any; - -type Place = { - id: string; title: string; address: string; image: string | null; overview: string; - homepage: string; lat: number | null; lng: number | null; distanceM: number | null; - travel: { mode: string; minutes: number; label: string } | null; -}; - -const GROUPS: Array<{ key: string; label: string; note: string }> = [ - { key: 'restaurant', label: 'Food', note: 'Restaurants and cafés' }, - { key: 'stay', label: 'Hotels', note: 'Places to sleep' }, - { key: 'wellness', label: 'Rest', note: 'Spas and jjimjilbang' }, - { key: 'attraction', label: 'Sights', note: 'Streets, parks, landmarks' }, - { key: 'culture', label: 'Culture', note: 'Museums, theatres, halls' }, - { key: 'shopping', label: 'Shopping', note: 'Stores and markets' }, -]; - -const SEASONS = [ - { key: 'spring', label: 'Spring' }, { key: 'summer', label: 'Summer' }, - { key: 'autumn', label: 'Autumn' }, { key: 'winter', label: 'Winter' }, -]; -const MONTHS = ['', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; -const nowSeason = ['winter', 'winter', 'spring', 'spring', 'spring', 'summer', 'summer', 'summer', 'autumn', 'autumn', 'autumn', 'winter'][new Date().getMonth()]; - -// 검색으로 보낸다. 없는 URL 을 만들지 않는다. -const searchUrl = (q: string) => `https://www.google.com/search?q=${encodeURIComponent(q + ' Seoul')}`; -// 칩은 누적 임계값으로 거른다. 카드에 이동수단과 도보 분을 실어 두면 스크립트가 판단한다. -const dt = (d: string | null) => (d && d.length === 8 ? `${MONTHS[+d.slice(4, 6)]} ${+d.slice(6, 8)}` : ''); -// 사진이 없을 때 이름을 대신 넣는다. 빈 회색칸보다 낫고, 없는 사진을 지어내지도 않는다. -const shortName = (t: string) => { - const m = t.match(/\(([^)]+)\)\s*$/); - return (m ? m[1] : t).replace(/\s*\[.*\]\s*/g, '').trim(); -}; -const firstSentence = (s: string, n = 150) => { - if (!s) return ''; - const cut = s.slice(0, n); - const stop = cut.lastIndexOf('. '); - return (stop > 60 ? cut.slice(0, stop + 1) : cut) + (s.length > n ? '…' : ''); -}; - -/* ── 동선. 실제 데이터에서 만들고, 시각은 가정임을 화면에 밝힌다. ── */ -const oLat = T.meta.origin.lat, oLng = T.meta.origin.lng; -const pick = (key: string, maxMin: number, n: number): Place[] => - ((T.places[key] ?? []) as Place[]) - .filter((p) => p.travel && p.travel.mode === 'walk' && p.travel.minutes <= maxMin && p.lat) - .slice(0, n); -const pickAny = (key: string, n: number): Place[] => ((T.places[key] ?? []) as Place[]).filter((p) => p.lat).slice(0, n); - -const hhmm = (m: number) => `${String(Math.floor(m / 60) % 24).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`; -function buildRoute(startMin: number, stops: Array<{ p: Place | null; label: string; stay: number; note: string }>) { - let t = startMin; - const out: any[] = []; - stops.forEach((s, i) => { - const move = i === 0 ? 0 : (s.p?.travel?.minutes ?? 5); - t += move; - const from = t; - t += s.stay; - out.push({ ...s, moveMin: move, from: hhmm(from), to: hhmm(t), lat: s.p?.lat ?? oLat, lng: s.p?.lng ?? oLng }); - }); - return { stops: out, total: t - startMin, from: hhmm(startMin), to: hhmm(t) }; -} -const clinicStop = (label: string, stay: number, note: string) => ({ p: null, label, stay, note }); - -const ROUTES = [ - { - id: 'near', title: 'The day of a check-up', who: 'When you come back to the clinic often', - blurb: 'Everything within a short walk. You do not need a taxi.', - route: buildRoute(15 * 60, [ - clinicStop(clinic, 40, 'Your appointment ends here.'), - ...pick('restaurant', 10, 1).map((p) => ({ p, label: p.title, stay: 50, note: firstSentence(p.overview, 90) })), - ...pick('wellness', 12, 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'short', title: 'A short outing', who: 'When you can walk a little further', - blurb: 'Still close, but out of the block.', - route: buildRoute(13 * 60, [ - clinicStop(clinic, 20, 'Start from the clinic.'), - ...pickAny('shopping', 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ...pickAny('restaurant', 2).slice(1, 2).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'city', title: 'When you can travel', who: 'Later in your stay', - blurb: 'Sights across the city. Expect to take a taxi or the subway.', - route: buildRoute(10 * 60, [ - clinicStop(clinic, 10, 'Set off from the clinic.'), - ...pickAny('attraction', 2).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ...pickAny('culture', 1).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ]), - }, -].filter((r) => r.route.stops.length > 1); - -/* OpenStreetMap 타일을 좌표로 직접 깔아 지도를 만든다. 지도 라이브러리를 부르지 않는다. - 빈 회색 칸에 점만 찍으면 어디인지 알 수 없어서, 실제 거리·블록이 보이게 한다. - 타일은 OSM 정책상 출처를 반드시 표기한다. */ -const TILE = 256, MAPW = 680, MAPH = 340; -const lngToPx = (lng: number, z: number) => ((lng + 180) / 360) * TILE * 2 ** z; -const latToPx = (lat: number, z: number) => { - const r = (lat * Math.PI) / 180; - return ((1 - Math.log(Math.tan(r) + 1 / Math.cos(r)) / Math.PI) / 2) * TILE * 2 ** z; -}; - -function miniMap(stops: any[]) { - const lats = stops.map((s) => s.lat), lngs = stops.map((s) => s.lng); - const [la0, la1] = [Math.min(...lats), Math.max(...lats)]; - const [ln0, ln1] = [Math.min(...lngs), Math.max(...lngs)]; - // 모든 지점이 여백 안에 들어오는 가장 확대된 배율을 고른다. - let z = 17; - for (; z > 10; z--) { - const w = lngToPx(ln1, z) - lngToPx(ln0, z); - const h = latToPx(la0, z) - latToPx(la1, z); - if (w <= MAPW - 90 && h <= MAPH - 90) break; - } - const cx = (lngToPx(ln0, z) + lngToPx(ln1, z)) / 2; - const cy = (latToPx(la0, z) + latToPx(la1, z)) / 2; - const left = cx - MAPW / 2, top = cy - MAPH / 2; - const tiles: Array<{ src: string; x: number; y: number }> = []; - for (let tx = Math.floor(left / TILE); tx <= Math.floor((left + MAPW) / TILE); tx++) { - for (let ty = Math.floor(top / TILE); ty <= Math.floor((top + MAPH) / TILE); ty++) { - const n = 2 ** z; - if (tx < 0 || ty < 0 || tx >= n || ty >= n) continue; - tiles.push({ src: `https://tile.openstreetmap.org/${z}/${tx}/${ty}.png`, x: tx * TILE - left, y: ty * TILE - top }); - } - } - const pins = stops.map((s, i) => ({ - x: +(lngToPx(s.lng, z) - left).toFixed(1), - y: +(latToPx(s.lat, z) - top).toFixed(1), - n: i + 1, label: s.label, - })); - return { tiles, pins, z }; -} - -const allPlaces: Array = GROUPS.flatMap((g) => - ((T.places[g.key] ?? []) as Place[]).map((p) => ({ ...p, cat: g.key }))); - -const ld = [ - { '@type': 'WebPage', '@id': `${site}/en/stay#page`, name: `Your stay near ${clinic}`, url: `${site}/en/stay`, inLanguage: 'en', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${f.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, - clinicSchema(site), -]; ---- - -
    -
    -
    For international patients
    -

    Your Stay in Seoul

    -

    - Around {clinic}. Everything below is measured from the clinic at {f.address?.fullEn || f.address?.full}. - Names, photographs and descriptions come from the Korea Tourism Organization. - For the clinic's own hours and phone, see Clinic informationKO. -

    -
    - - - - - - - - -
    -
    -

    Around the clinic

    - Updated {T.meta.fetchedAt.slice(0, 10)} -
    -

    {T.filters.total} places, sorted by how long they take to reach on foot.

    - -
    - - - - - -
    - - {GROUPS.map((g) => { - const items = allPlaces.filter((p) => p.cat === g.key); - if (!items.length) return null; - return ( -
    -

    {g.label} {g.note}

    -
    - {items.map((p) => ( -
    -
    - {p.image ? {`${p.title} : {shortName(p.title)}} - {p.travel && {p.travel.label} {p.distanceM! < 1000 ? `${p.distanceM} m` : `${(p.distanceM! / 1000).toFixed(1)} km`}} -
    -
    -

    {p.title}

    -

    {firstSentence(p.overview) || 'No description provided by the tourism data.'}

    -

    {p.address}

    - {p.homepage - ? Official site ↗ - : Open in search ↗} -
    -
    - ))} -
    -
    - ); - })} -

    Source · Korea Tourism Organization TourAPI. Walking time is estimated at 80 m per minute and is not a routed distance.

    -
    - - -
    -

    Festivals and events

    -

    {T.festivals.length} events within {T.meta.festivalRadiusKm} km, grouped by season. Right now it is {nowSeason}.

    -
    - - {SEASONS.map((s) => { - const n = T.festivals.filter((e: any) => e.season === s.key).length; - return n ? : null; - })} -
    -
    - {T.festivals.map((e: any) => ( -
    -
    - {e.image ? {`${e.title} : {shortName(e.title)}} - {MONTHS[e.month] ?? ''} -
    -
    -

    {e.title}

    -

    {dt(e.startDate)} – {dt(e.endDate)} · {e.travel ? e.travel.label : `${e.distanceKm} km`}

    -

    {firstSentence(e.overview) || 'No description provided by the tourism data.'}

    -

    {e.address}

    - Open in search ↗ -
    -
    - ))} -
    -

    Source · Korea Tourism Organization TourAPI. Dates can change at the organiser's discretion.

    -
    - - -
    -

    Shaping your days

    -

    - Three routes built from the places above. The clock times assume an appointment ending at the hour shown, and are an example, not your schedule. -

    - {Sx.recoveryStagesEn - ?

    What {clinic} advises. {Sx.recoveryStagesEn}

    - :

    Which of these you can do, and on which day, is a medical question. {clinic} has not yet published English guidance. Ask at your consultation.

    } - - {ROUTES.map((r) => { - const pins = miniMap(r.route.stops); - return ( -
    -
    -
    -

    {r.title}

    -

    {r.who}

    -
    -
    {r.route.from}–{r.route.to} · {Math.floor(r.route.total / 60)}h {r.route.total % 60}m
    -
    -

    {r.blurb}

    - - ); - })} -
    - -
    -

    What this page does not tell you

    -
      -
    • No ratings, review counts or opening hours. The tourism data does not carry them.
    • -
    • No claim that any place suits your recovery. That is for {clinic} to say.
    • -
    • English tourism listings around Gangnam are thin. Only {T.filters.walk5} places sit within a five minute walk, and {T.filters.drive} of {T.filters.total} need a car.
    • -
    • We are not a travel agency, take no booking and no commission.
    • -
    -

    - {has(f.urlEn) && Book a consultation in English} -

    -

    {f.sideEffectNoticeEn || f.sideEffectNotice}

    -
    -
    - - - diff --git a/templates/supporters-astro/src/pages/plan.astro b/templates/supporters-astro/src/pages/plan.astro new file mode 100644 index 0000000..013ee36 --- /dev/null +++ b/templates/supporters-astro/src/pages/plan.astro @@ -0,0 +1,16 @@ +--- +// 회복기 스케줄러 한국어 페이지. 본문은 components/Planner.astro. 영어 페이지는 /en/plan. +import Base from '../layouts/Base.astro'; +import Planner from '../components/Planner.astro'; +import { fact, SITE_NAME, clinicSchema, v } from '../lib'; +const f = fact as Record; +const clinic = v(f.shortName, '병원'); +const site = Astro.site!.toString().replace(/\/$/, ''); +const ld = [ + { '@type': 'WebPage', '@id': `${site}/plan#page`, name: `${clinic} 회복 일정 플래너`, url: `${site}/plan`, inLanguage: 'ko', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${fact.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, + clinicSchema(site), +]; +--- + + + diff --git a/templates/supporters-astro/src/pages/sitemap.xml.ts b/templates/supporters-astro/src/pages/sitemap.xml.ts index f77671b..a357bd2 100644 --- a/templates/supporters-astro/src/pages/sitemap.xml.ts +++ b/templates/supporters-astro/src/pages/sitemap.xml.ts @@ -11,8 +11,8 @@ export const GET: APIRoute = async ({ site }) => { { loc: `${base}/posts`, lastmod: today }, { loc: `${base}/clinic`, lastmod: today }, { loc: `${base}/visit`, lastmod: today }, - { loc: `${base}/stay`, lastmod: today }, - { loc: `${base}/en/stay`, lastmod: today }, + { loc: `${base}/plan`, lastmod: today }, + { loc: `${base}/en/plan`, lastmod: today }, { loc: `${base}/newsroom`, lastmod: today }, { loc: `${base}/videos`, lastmod: today }, { loc: `${base}/about`, lastmod: today }, diff --git a/templates/supporters-astro/src/pages/stay.astro b/templates/supporters-astro/src/pages/stay.astro deleted file mode 100644 index 99e2bb8..0000000 --- a/templates/supporters-astro/src/pages/stay.astro +++ /dev/null @@ -1,445 +0,0 @@ ---- -// 병원 주변 안내(한국어). /en/stay 의 한국어 짝이다. 데이터는 국문 서비스(KorService2)라 -// 영문보다 훨씬 많다(음식점 338건·숙박 43건 대 18건·4건). -// 구조는 /en/stay 와 같다. 세 부분이다. -// 1. 병원 주변 — 도보·차 소요 시간으로 거른 주변 장소 -// 2. Festivals — 계절로 묶은 행사 -// 3. Suggested days — 시간표와 지도가 붙은 동선 -// -// 데이터는 한국관광공사 TourAPI 영문(EngService2)에서 scripts/fetch_medical_tourism.py 가 -// 미리 수집한 src/data/medicalTourism.json 이다. 설명문은 detailCommon2 의 overview 다. -// -// 만들지 않는 것 -// - 평점·리뷰·영업시간: TourAPI 미제공. 싣지 않는다. -// - 링크: 공식 홈페이지가 있을 때만 걸고, 없으면 검색으로 보낸다. 주소를 지어내지 않는다. -// - 식이 적합성·회복 일수: 의학 판단이라 병원 확정값만 쓴다. -// - 일정의 시각: 진료 종료 시각을 가정으로 못박아 화면에 밝힌다. 병원 일정이 아니다. -import Base from '../layouts/Base.astro'; -import { fact, site as S, SITE_NAME, clinicSchema, has, v, reservationUrl } from '../lib'; -import data from '../data/medicalTourismKo.json'; - -const f = fact as Record; -const Sx = S as Record; -const clinic = f.shortName || '병원'; -const site = Astro.site!.toString().replace(/\/$/, ''); -const T = data as any; - -type Place = { - id: string; title: string; address: string; image: string | null; overview: string; - homepage: string; lat: number | null; lng: number | null; distanceM: number | null; - travel: { mode: string; minutes: number; label: string } | null; -}; - -const GROUPS: Array<{ key: string; label: string; note: string }> = [ - { key: 'restaurant', label: '식사', note: '음식점과 카페' }, - { key: 'stay', label: '숙박', note: '묵을 곳' }, - { key: 'wellness', label: '휴식', note: '스파와 찜질방' }, - { key: 'attraction', label: '관광', note: '거리, 공원, 명소' }, - { key: 'culture', label: '문화', note: '미술관, 공연장' }, - { key: 'shopping', label: '쇼핑', note: '백화점과 시장' }, -]; - -const SEASONS = [ - { key: 'spring', label: '봄' }, { key: 'summer', label: '여름' }, - { key: 'autumn', label: '가을' }, { key: 'winter', label: '겨울' }, -]; -const MONTHS = ['', '1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월']; -const nowSeasonKey = ['winter', 'winter', 'spring', 'spring', 'spring', 'summer', 'summer', 'summer', 'autumn', 'autumn', 'autumn', 'winter'][new Date().getMonth()]; -const nowSeason = ({ spring: '봄', summer: '여름', autumn: '가을', winter: '겨울' } as Record)[nowSeasonKey]; - -// 검색으로 보낸다. 없는 URL 을 만들지 않는다. -// 없는 URL 을 만들지 않는다. 공식 홈페이지가 없으면 검색으로 보낸다. -const searchUrl = (q: string) => `https://search.naver.com/search.naver?query=${encodeURIComponent(q)}`; -// 칩은 누적 임계값으로 거른다. 카드에 이동수단과 도보 분을 실어 두면 스크립트가 판단한다. -const dt = (d: string | null) => (d && d.length === 8 ? `${+d.slice(4, 6)}.${+d.slice(6, 8)}` : ''); -// 사진이 없을 때 이름을 대신 넣는다. 빈 회색칸보다 낫고, 없는 사진을 지어내지도 않는다. -const shortName = (t: string) => { - const m = t.match(/\(([^)]+)\)\s*$/); - return (m ? m[1] : t).replace(/\s*\[.*\]\s*/g, '').trim(); -}; -// travel.label 은 데이터에 영문으로 들어 있다. 한국어 화면에서는 여기서 만든다. -const travelLabel = (t: { mode: string; minutes: number } | null) => - !t ? '' : t.mode === 'walk' ? `도보 ${t.minutes}분` : `차로 ${t.minutes}분`; -const firstSentence = (s: string, n = 150) => { - if (!s) return ''; - const cut = s.slice(0, n); - const stop = cut.lastIndexOf('. '); - return (stop > 60 ? cut.slice(0, stop + 1) : cut) + (s.length > n ? '…' : ''); -}; - -/* ── 동선. 실제 데이터에서 만들고, 시각은 가정임을 화면에 밝힌다. ── */ -const oLat = T.meta.origin.lat, oLng = T.meta.origin.lng; -const pick = (key: string, maxMin: number, n: number): Place[] => - ((T.places[key] ?? []) as Place[]) - .filter((p) => p.travel && p.travel.mode === 'walk' && p.travel.minutes <= maxMin && p.lat) - .slice(0, n); -const pickAny = (key: string, n: number): Place[] => ((T.places[key] ?? []) as Place[]).filter((p) => p.lat).slice(0, n); - -const hhmm = (m: number) => `${String(Math.floor(m / 60) % 24).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`; -function buildRoute(startMin: number, stops: Array<{ p: Place | null; label: string; stay: number; note: string }>) { - let t = startMin; - const out: any[] = []; - stops.forEach((s, i) => { - const move = i === 0 ? 0 : (s.p?.travel?.minutes ?? 5); - t += move; - const from = t; - t += s.stay; - out.push({ ...s, moveMin: move, from: hhmm(from), to: hhmm(t), lat: s.p?.lat ?? oLat, lng: s.p?.lng ?? oLng }); - }); - return { stops: out, total: t - startMin, from: hhmm(startMin), to: hhmm(t) }; -} -const clinicStop = (label: string, stay: number, note: string) => ({ p: null, label, stay, note }); - -const ROUTES = [ - { - id: 'near', title: 'The day of a check-up', who: 'When you come back to the clinic often', - blurb: 'Everything within a short walk. You do not need a taxi.', - route: buildRoute(15 * 60, [ - clinicStop(clinic, 40, 'Your appointment ends here.'), - ...pick('restaurant', 10, 1).map((p) => ({ p, label: p.title, stay: 50, note: firstSentence(p.overview, 90) })), - ...pick('wellness', 12, 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'short', title: 'A short outing', who: 'When you can walk a little further', - blurb: 'Still close, but out of the block.', - route: buildRoute(13 * 60, [ - clinicStop(clinic, 20, 'Start from the clinic.'), - ...pickAny('shopping', 1).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ...pickAny('restaurant', 2).slice(1, 2).map((p) => ({ p, label: p.title, stay: 60, note: firstSentence(p.overview, 90) })), - ]), - }, - { - id: 'city', title: 'When you can travel', who: 'Later in your stay', - blurb: 'Sights across the city. Expect to take a taxi or the subway.', - route: buildRoute(10 * 60, [ - clinicStop(clinic, 10, 'Set off from the clinic.'), - ...pickAny('attraction', 2).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ...pickAny('culture', 1).map((p) => ({ p, label: p.title, stay: 70, note: firstSentence(p.overview, 90) })), - ]), - }, -].filter((r) => r.route.stops.length > 1); - -/* OpenStreetMap 타일을 좌표로 직접 깔아 지도를 만든다. 지도 라이브러리를 부르지 않는다. - 빈 회색 칸에 점만 찍으면 어디인지 알 수 없어서, 실제 거리·블록이 보이게 한다. - 타일은 OSM 정책상 출처를 반드시 표기한다. */ -const TILE = 256, MAPW = 680, MAPH = 340; -const lngToPx = (lng: number, z: number) => ((lng + 180) / 360) * TILE * 2 ** z; -const latToPx = (lat: number, z: number) => { - const r = (lat * Math.PI) / 180; - return ((1 - Math.log(Math.tan(r) + 1 / Math.cos(r)) / Math.PI) / 2) * TILE * 2 ** z; -}; - -function miniMap(stops: any[]) { - const lats = stops.map((s) => s.lat), lngs = stops.map((s) => s.lng); - const [la0, la1] = [Math.min(...lats), Math.max(...lats)]; - const [ln0, ln1] = [Math.min(...lngs), Math.max(...lngs)]; - // 모든 지점이 여백 안에 들어오는 가장 확대된 배율을 고른다. - let z = 17; - for (; z > 10; z--) { - const w = lngToPx(ln1, z) - lngToPx(ln0, z); - const h = latToPx(la0, z) - latToPx(la1, z); - if (w <= MAPW - 90 && h <= MAPH - 90) break; - } - const cx = (lngToPx(ln0, z) + lngToPx(ln1, z)) / 2; - const cy = (latToPx(la0, z) + latToPx(la1, z)) / 2; - const left = cx - MAPW / 2, top = cy - MAPH / 2; - const tiles: Array<{ src: string; x: number; y: number }> = []; - for (let tx = Math.floor(left / TILE); tx <= Math.floor((left + MAPW) / TILE); tx++) { - for (let ty = Math.floor(top / TILE); ty <= Math.floor((top + MAPH) / TILE); ty++) { - const n = 2 ** z; - if (tx < 0 || ty < 0 || tx >= n || ty >= n) continue; - tiles.push({ src: `https://tile.openstreetmap.org/${z}/${tx}/${ty}.png`, x: tx * TILE - left, y: ty * TILE - top }); - } - } - const pins = stops.map((s, i) => ({ - x: +(lngToPx(s.lng, z) - left).toFixed(1), - y: +(latToPx(s.lat, z) - top).toFixed(1), - n: i + 1, label: s.label, - })); - return { tiles, pins, z }; -} - -const allPlaces: Array = GROUPS.flatMap((g) => - ((T.places[g.key] ?? []) as Place[]).map((p) => ({ ...p, cat: g.key }))); - -const ld = [ - { '@type': 'WebPage', '@id': `${site}/stay#page`, name: `${clinic} 주변 안내`, url: `${site}/stay`, inLanguage: 'ko', isPartOf: { '@id': `${site}/#website` }, about: { '@id': `${f.url}/#clinic` }, publisher: { '@type': 'Organization', name: SITE_NAME, url: site } }, - clinicSchema(site), -]; ---- - -
    -
    -
    병원 주변
    -

    병원 주변 안내

    -

    - {clinic} 주변입니다. 아래 거리와 시간은 모두 {v(f.address?.full)} 기준입니다. - 상호와 사진, 설명은 한국관광공사 자료입니다. 병원의 진료시간과 전화는 병원 정보에 있습니다. -

    -
    - - - - - - - - -
    -
    -

    병원 주변

    - {T.meta.fetchedAt.slice(0, 10)} 갱신 -
    -

    {T.filters.total}곳입니다. 병원에서 걸어가는 시간 순으로 놓았습니다.

    - -
    - - - - - -
    - - {GROUPS.map((g) => { - const items = allPlaces.filter((p) => p.cat === g.key); - if (!items.length) return null; - return ( -
    -

    {g.label} {g.note}

    -
    - {items.map((p) => ( -
    -
    - {p.image ? {`${p.title} : {shortName(p.title)}} - {p.travel && {travelLabel(p.travel)} {p.distanceM! < 1000 ? `${p.distanceM} m` : `${(p.distanceM! / 1000).toFixed(1)} km`}} -
    -
    -

    {p.title}

    -

    {firstSentence(p.overview) || '관광 자료에 설명이 없습니다.'}

    -

    {p.address}

    - {p.homepage - ? 공식 홈페이지 ↗ - : 검색으로 열기 ↗} -
    -
    - ))} -
    -
    - ); - })} -

    출처 · 한국관광공사 TourAPI. 도보 시간은 분당 80m로 어림한 값이며 실제 경로 거리가 아닙니다.

    -
    - - -
    -

    계절별 축제

    -

    {T.meta.festivalRadiusKm}km 안의 행사 {T.festivals.length}건을 계절로 묶었습니다. 지금은 {nowSeason}입니다.

    -
    - - {SEASONS.map((s) => { - const n = T.festivals.filter((e: any) => e.season === s.key).length; - return n ? : null; - })} -
    -
    - {T.festivals.map((e: any) => ( -
    -
    - {e.image ? {`${e.title} : {shortName(e.title)}} - {MONTHS[e.month] ?? ''} -
    -
    -

    {e.title}

    -

    {dt(e.startDate)} – {dt(e.endDate)} · {e.travel ? travelLabel(e.travel) : `${e.distanceKm}km`}

    -

    {firstSentence(e.overview) || '관광 자료에 설명이 없습니다.'}

    -

    {e.address}

    - 검색으로 열기 ↗ -
    -
    - ))} -
    -

    출처 · 한국관광공사 TourAPI. 일정은 주최 측 사정으로 바뀔 수 있습니다.

    -
    - - -
    -

    하루 동선

    -

    - 위 장소들로 짠 동선 세 가지입니다. 시각은 진료가 그 시각에 끝난다고 가정한 예시이며 실제 일정이 아닙니다. -

    - {Sx.recoveryStagesKo - ?

    {clinic} 안내. {Sx.recoveryStagesKo}

    - :

    어느 날 무엇을 해도 되는지는 의학 판단이라 {clinic}이 정합니다. 아직 확인 대기입니다. 상담 때 확인하세요.

    } - - {ROUTES.map((r) => { - const pins = miniMap(r.route.stops); - return ( -
    -
    -
    -

    {r.title}

    -

    {r.who}

    -
    -
    {r.route.from}–{r.route.to} · {Math.floor(r.route.total / 60)}h {r.route.total % 60}m
    -
    -

    {r.blurb}

    - - ); - })} -
    - -
    -

    이 페이지가 답하지 못하는 것

    -
      -
    • 평점·리뷰 수·영업시간은 없습니다. 관광 자료가 주지 않습니다.
    • -
    • 어떤 곳이 회복에 맞는지는 말하지 않습니다. {clinic}이 정할 일입니다.
    • -
    • 도보 5분 안에는 {T.filters.walk5}곳뿐이고, {T.filters.total}곳 중 {T.filters.drive}곳은 차로 가야 합니다.
    • -
    • 여행사가 아닙니다. 예약을 받지 않고 수수료도 받지 않습니다.
    • -
    -

    - {has(reservationUrl) && {clinic} 상담 예약} -

    -

    {f.sideEffectNoticeEn || f.sideEffectNotice}

    -
    -
    - - - diff --git a/templates/supporters-astro/src/pages/visit.astro b/templates/supporters-astro/src/pages/visit.astro index e3c9c21..e61e25a 100644 --- a/templates/supporters-astro/src/pages/visit.astro +++ b/templates/supporters-astro/src/pages/visit.astro @@ -42,7 +42,7 @@ const ld = [ {!(S.visitReads ?? []).length &&
  • 검토를 마친 글부터 차례로 연결합니다.
  • }

    6. 해외에서 오시는 경우

    -

    수술 전후에 머무는 동안의 숙박·식사·회복·관광 정보를 영문으로 정리했습니다. Your Stay in Seoul.

    +

    수술 전후에 머무는 동안의 숙박·식사·회복·관광 정보를 영문으로 정리했습니다. Recovery Planner.

    {has(reservationUrl) && {clinic} 상담 예약}

    {fact.sideEffectNotice}

    diff --git a/templates/supporters-astro/src/styles/global.css b/templates/supporters-astro/src/styles/global.css index eb8ebca..bf77bc9 100644 --- a/templates/supporters-astro/src/styles/global.css +++ b/templates/supporters-astro/src/styles/global.css @@ -387,6 +387,24 @@ td { color: var(--slate-700); } .stay .timeline h4 { margin: 0.1rem 0 0.2rem; font-size: 0.98rem; } .stay .timeline p { margin: 0; font-size: 0.86rem; color: var(--slate-600, #475569); } .stay .botnote { margin-top: 1.6rem; } +/* 시술 후 관리 안내(병원 원문 인용). 동선 카드(.route)·정차(.stop) 룩을 그대로 쓰고 접이식 동작만 더한다. 새 색·크기 없음. */ +.stay details.recovery > summary.btn { list-style: none; cursor: pointer; } +.stay details.recovery > summary.btn::-webkit-details-marker { display: none; } +.stay details.recovery > summary.btn .hide { display: none; } +.stay details.recovery[open] > summary.btn .show { display: none; } +.stay details.recovery[open] > summary.btn .hide { display: inline; } +.stay details.recovery[open] > summary.btn { margin-bottom: 1.1rem; } +.stay details.recovery > .timeline { margin-top: 0.2rem; } +.stay .recovery .timeline > li { border-top: 1px solid var(--line, #E2E8F0); padding: 0.7rem 0; } +.stay .recovery .timeline > li:first-child { border-top: 0; padding-top: 0; } +.stay .recovery summary { cursor: pointer; list-style: none; } +.stay .recovery summary::-webkit-details-marker { display: none; } +.stay .recovery summary .stop { display: flex; } +.stay .recovery summary h4 { margin: 0.1rem 0 0; } +.stay .recovery details[open] summary h4 { text-decoration: underline; text-underline-offset: 0.2em; text-decoration-color: var(--slate-200, #E2E8F0); } +.stay .recovery details > ul { margin: 0.7rem 0 0.5rem 2.2rem; padding-left: 1.1rem; } +.stay .recovery details > ul li { font-size: 0.9rem; color: var(--slate-700, #334155); margin-bottom: 0.35rem; } +.stay .recovery details > p { margin: 0 0 0 2.2rem; font-size: 0.84rem; color: var(--slate-500, #64748B); } @media (max-width: 640px) { .cards { grid-template-columns: 1fr; } } /* 섹션 점프. 머리말 아래에 붙어 스크롤을 따라온다. 헤더(68px) 아래에 걸리게 top 을 맞춘다. */ diff --git a/templates/supporters-astro/src/styles/plan.css b/templates/supporters-astro/src/styles/plan.css new file mode 100644 index 0000000..2c10821 --- /dev/null +++ b/templates/supporters-astro/src/styles/plan.css @@ -0,0 +1,172 @@ +/* 회복기 스케줄러 (/plan, /en/plan). 섹션 리듬·카드·통계는 global.css 의 .section/.sec-head/.grid/.card/.stats/.stat 을 그대로 쓰고, + 여기에는 입력 컨트롤·타임라인·배지처럼 이 페이지에만 있는 요소만 둔다. 흰 배경 강조는 인디고, 연보라는 다크 전용. */ +:root { --indigo: #1D0024; } + +/* 히어로 (다크, videos.astro 규격) */ +.plan-hero { padding: 3.5rem 0 3rem; } +.plan-hero h1 { font-family: "Playfair Display", Georgia, serif; font-size: 2.3rem; font-weight: 700; letter-spacing: 0; line-height: 1.15; display: inline-block; background: linear-gradient(to right, var(--purple-300), var(--blue-300)); -webkit-background-clip: text; background-clip: text; color: transparent; margin: 0; } +.plan-hero .lede { color: rgba(255,255,255,0.82); font-size: 1.02rem; max-width: 760px; margin: 0.6rem 0 0; } +.plan-hero .lede strong { color: #fff; } +.lang-links a { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.45rem 1rem 0.45rem 0.55rem; border-radius: 999px; background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.16); color: #fff; text-decoration: none; font-size: 0.9rem; font-weight: 600; } +.lang-links a .ico { display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 999px; background: rgba(255,255,255,0.12); font-family: Inter, sans-serif; font-size: 0.66rem; letter-spacing: 0.06em; color: var(--purple-200); } +.lang-links a.on { background: linear-gradient(to right, var(--grad-start), var(--grad-end)); border-color: transparent; } +.lang-links a.on .ico { background: rgba(255,255,255,0.2); color: #fff; } +.lang-links a:hover { text-decoration: none; border-color: rgba(216,180,254,0.6); } +.plan-hero .stats { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); } + +/* 입력 단계 카드 (틴트 섹션) */ +.steps-grid { display: grid; grid-template-columns: minmax(260px, 1fr) 2fr; gap: 1.25rem; } +.steps-grid .card.span { grid-column: 1 / -1; } +@media (max-width: 860px) { .steps-grid { grid-template-columns: 1fr; } } +.card .cat.step { display: inline-flex; align-items: center; gap: 0.45rem; } +.card .cat.step .n { display: inline-grid; place-items: center; width: 1.35rem; height: 1.35rem; border-radius: 999px; background: linear-gradient(to right, var(--grad-start), var(--grad-end)); color: #fff; font-family: "Playfair Display", Georgia, serif; font-size: 0.8rem; font-weight: 700; } +.card h3.serif { font-family: "Playfair Display", Georgia, serif; font-size: 1.12rem; } +.card .sub2 { font-size: 0.88rem; color: var(--slate-600); margin: 0; flex: 0; } +.card .hint { font-size: 0.83rem; color: var(--slate-500); margin: 0.4rem 0 0; flex: 0; } +.field { display: grid; gap: 0.35rem; margin-top: 0.5rem; } +.field label { font-size: 0.82rem; font-weight: 600; color: var(--slate-600); } +.field select, .field input[type="date"] { font: inherit; font-size: 1rem; padding: 0.6rem 0.8rem; border: 1px solid var(--slate-200); border-radius: 12px; background: #fff; color: var(--indigo); max-width: 320px; } +.lang-inline a { border: 1px solid var(--slate-200); background: #fff; color: var(--slate-600); border-radius: 999px; padding: 0.35rem 0.9rem; font-size: 0.85rem; font-weight: 600; text-decoration: none; } +.lang-inline a.on { background: var(--primary-900); color: #fff; border-color: var(--primary-900); } + +.proc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.55rem; } +.proc-grid button { text-align: left; border: 1px solid var(--slate-200); background: #fff; border-radius: 14px; padding: 0.7rem 0.85rem; font: inherit; cursor: pointer; color: var(--indigo); display: grid; gap: 0.1rem; } +.proc-grid button small { color: var(--slate-500); font-size: 0.7rem; letter-spacing: 0.05em; text-transform: uppercase; font-family: Inter, Pretendard, sans-serif; } +.proc-grid button b { font-size: 0.95rem; font-weight: 700; } +.proc-grid button.on { border-color: var(--accent); background: var(--st-good-bg); box-shadow: 0 0 0 2px rgba(108,92,231,0.25) inset; } + +.pref-row { display: flex; flex-wrap: wrap; gap: 0.5rem; } +.pref-row button { border: 1px solid var(--slate-200); background: #fff; color: var(--indigo); border-radius: 999px; padding: 0.5rem 1rem; font: inherit; font-size: 0.92rem; font-weight: 600; cursor: pointer; } +.pref-row button.on { background: linear-gradient(to right, var(--grad-start), var(--grad-end)); color: #fff; border-color: transparent; } + +.plan-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; align-items: center; margin-top: 1rem; } +.btn.small { padding: 0.55rem 1rem; font-size: 0.88rem; } +.btn.ghost { background: #fff; color: var(--indigo); border: 1px solid var(--slate-200); } +button.btn { font: inherit; cursor: pointer; border: 0; } + +/* 빈 상태 (다크) */ +.empty { text-align: center; padding: 2.4rem 1rem; border: 1px dashed rgba(255,255,255,0.25); border-radius: 16px; color: rgba(255,255,255,0.75); } +.empty b { display: block; color: #fff; font-size: 1.1rem; margin-bottom: 0.3rem; } + +/* 배지 */ +.tag { display: inline-block; font-size: 0.72rem; font-weight: 700; padding: 0.12rem 0.55rem; border-radius: 999px; border: 1px solid transparent; vertical-align: middle; white-space: nowrap; } +.tag.prov { background: var(--st-warning-bg); color: var(--st-warning-text); border-color: var(--st-warning-border); } +.tag.clinic { background: var(--st-good-bg); color: var(--st-good-text); border-color: var(--st-good-border); } +.tag.l0 { background: var(--st-critical-bg); color: var(--st-critical-text); border-color: var(--st-critical-border); } +.tag.l1 { background: var(--st-warning-bg); color: var(--st-warning-text); border-color: var(--st-warning-border); } +.tag.l2 { background: var(--st-info-bg); color: var(--st-info-text); border-color: var(--st-info-border); } +.tag.l3 { background: var(--st-good-bg); color: var(--st-good-text); border-color: var(--st-good-border); } +.tag.diet { background: var(--slate-100); color: var(--slate-700); } + +/* 다크 섹션 핵심 날짜: 글래스 통계 카드 변형 */ +.stats.dates { grid-template-columns: repeat(3, minmax(0, 1fr)); } +.stats.dates .stat { display: flex; flex-direction: column; } +.stats.dates .stat .label { order: -1; margin: 0 0 0.35rem; font-size: 0.8rem; color: rgba(255,255,255,0.72); font-weight: 600; letter-spacing: 0.02em; } +.stats.dates .stat b { font-size: 1.75rem; display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem; } +.stats.dates .stat b .wd { font-family: Pretendard, Inter, sans-serif; font-size: 0.85rem; font-weight: 600; color: rgba(255,255,255,0.7); } +.stats.dates .stat b .txt { font-family: Pretendard, Inter, sans-serif; font-size: 1.15rem; color: #fff; } +.stats.dates .stat .desc { margin-top: 0.55rem; } +.stats.dates .tag.clinic { background: rgba(175,144,255,0.18); color: var(--purple-200); border-color: rgba(216,180,254,0.45); } +.section.dark .note { color: rgba(255,255,255,0.72); font-size: 0.88rem; margin: 1.2rem 0 0; max-width: 900px; } +.section.dark .note a { color: var(--purple-300); } + +/* 라이트 섹션 카드 내용 */ +.card ul.rules { margin: 0.2rem 0 0; padding-left: 1.15rem; font-size: 0.92rem; color: var(--slate-700); } +.card ul.rules li { margin-bottom: 0.4rem; } +.card.ok { background: var(--st-good-bg); border-color: var(--st-good-border); } +.card.warn { background: var(--st-warning-bg); border-color: var(--st-warning-border); } +.card.warn h3, .card.warn p { color: var(--st-warning-text); } +.card.ok h3, .card.ok p { color: var(--st-good-text); } +.card .fine { font-size: 0.8rem; color: var(--slate-500); margin-top: 0.3rem; flex: 0; } +.card.warn .fine, .card.ok .fine { color: inherit; opacity: 0.85; } + +/* 타임라인 (틴트 섹션 위 흰 카드) */ +.legend { display: flex; flex-wrap: wrap; gap: 0.5rem 1.2rem; font-size: 0.85rem; color: var(--slate-600); margin: 0 0 1.25rem; } +.legend span { display: inline-flex; align-items: center; gap: 0.35rem; } +.timeline { display: grid; gap: 1.1rem; } +.day { display: grid; grid-template-columns: 160px 1fr; gap: 0.6rem 1.2rem; align-items: start; padding: 1rem 1.2rem; border-radius: 16px; border: 1px solid var(--slate-100); background: #fff; box-shadow: var(--shadow); } +.day.mark { border-color: var(--st-good-border); background: #FBFAFF; } +.day .d { display: grid; gap: 0.1rem; } +.day .d b { color: var(--primary-900); font-size: 1rem; font-family: "Playfair Display", Georgia, serif; font-weight: 700; } +.day .d span { font-size: 0.78rem; color: var(--slate-500); } +.day .d .ev { font-size: 0.78rem; font-weight: 700; color: var(--grad-start); } +.day .body { display: grid; gap: 0.45rem; } +.day .tags { display: flex; flex-wrap: wrap; gap: 0.35rem; align-items: center; } +.day .tags .desc { font-size: 0.85rem; color: var(--slate-600); } +.day .picks { display: flex; flex-wrap: wrap; gap: 0.4rem; } +.day .picks a, .day .picks span.pick { display: inline-flex; align-items: center; gap: 0.35rem; border: 1px solid var(--slate-200); border-radius: 999px; padding: 0.3rem 0.75rem; font-size: 0.85rem; color: var(--indigo); background: #fff; } +.day .picks a:hover { border-color: var(--accent); text-decoration: none; } +.day .picks small { color: var(--slate-500); font-size: 0.72rem; } +.day .rest { font-size: 0.88rem; color: var(--slate-500); } +@media (max-width: 640px) { .day { grid-template-columns: 1fr; } } + +/* 체류 기간의 행사 카드 (TourAPI 이미지) */ +.fest-card { padding: 0; overflow: hidden; } +.fest-card img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block; } +.fest-card .cat, .fest-card h3, .fest-card p { margin-left: 1.5rem; margin-right: 1.5rem; } +.fest-card .cat { margin-top: 1.2rem; } +.fest-card > p:last-child { margin-bottom: 1.3rem; } +.day .picks a.fest { border-color: var(--st-good-border); background: var(--st-good-bg); } + +/* 예약 (다크 섹션 위 흰 카드) */ +.hotel-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 1.25rem; } +.hotel-grid .card small { color: var(--slate-500); font-size: 0.78rem; } +.hotel-grid .card .links { display: flex; gap: 0.7rem; flex-wrap: wrap; font-size: 0.85rem; font-weight: 600; } +.book-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1.25rem; margin-top: 1.5rem; } +.book-row .card .plan-actions { margin-top: 0.4rem; } +.section.dark .disclosure { color: rgba(255,255,255,0.6); border-top-color: rgba(255,255,255,0.12); } +.section.dark .disclosure a, .section.dark .sources-list a { color: var(--purple-300); } +.section.dark .sources-list { font-size: 0.85rem; color: rgba(255,255,255,0.7); margin: 0.3rem 0 0; } + +.toast { position: fixed; left: 50%; bottom: 2rem; transform: translateX(-50%); background: var(--primary-900); color: #fff; padding: 0.6rem 1.1rem; border-radius: 999px; font-size: 0.9rem; opacity: 0; transition: opacity 0.2s; pointer-events: none; z-index: 20; } +.toast.show { opacity: 1; } + +/* 방문 안내 진입 CTA 카드 (웜 그라디언트는 CTA 카드 한 장에만) */ +.plan-entry { background: linear-gradient(to right, #fff3eb, #e4cfff, #f5f9ff); border-radius: 16px; padding: 1.3rem 1.5rem; box-shadow: var(--shadow); margin: 2rem 0; display: grid; gap: 0.4rem; } +.plan-entry h2 { margin: 0; font-size: 1.1rem; color: var(--indigo); } +.plan-entry p { margin: 0; color: var(--slate-700); font-size: 0.95rem; } +.plan-entry .btn { justify-self: start; margin-top: 0.4rem; } + +/* 태블릿 (≤900px): 히어로 통계 2열 */ +@media (max-width: 900px) { .plan-hero .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } } + +/* 모바일 (≤720px): 통계·날짜 카드 2열, 타임라인 날짜 머리 가로 배치, 히어로 여백 축소 */ +@media (max-width: 720px) { + .plan-hero h1 { font-size: 1.9rem; } + .plan-hero .lede { font-size: 0.95rem; } + .plan-hero .stats, .stats.dates { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem; } + .plan-hero .stat, .stats.dates .stat { padding: 1.2rem 1.2rem; } + .plan-hero .stat b { font-size: 1.8rem; } + .plan-hero .stat .label { font-size: 0.9rem; } + .plan-hero .stat .desc { font-size: 0.78rem; } + .stats.dates .stat b { font-size: 1.35rem; } + .stats.dates .stat .desc { font-size: 0.78rem; } + .field select, .field input[type="date"] { max-width: none; width: 100%; font-size: 16px; } + .proc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .day { gap: 0.5rem; } + .day .d { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.2rem 0.6rem; } + .day .picks a, .day .picks span.pick { font-size: 0.82rem; padding: 0.3rem 0.65rem; } + .book-row { grid-template-columns: 1fr; } + .hotel-grid { grid-template-columns: 1fr; } + .plan-result-pad { padding-bottom: 4.5rem; } +} + +/* 하단 고정 요약 바 (모바일에서 결과가 있을 때만) */ +.sticky-bar { display: none; } +@media (max-width: 720px) { + .sticky-bar { position: fixed; left: 0.8rem; right: 4.2rem; bottom: 0.9rem; z-index: 15; display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; background: var(--primary-900); color: #fff; border-radius: 999px; padding: 0.55rem 0.6rem 0.55rem 1rem; box-shadow: 0 10px 28px rgba(2,19,65,0.35); transition: opacity 0.2s, transform 0.2s; } + .sticky-bar[hidden] { display: none; } + .sticky-bar .s { display: grid; line-height: 1.2; min-width: 0; } + .sticky-bar .s b { font-family: "Playfair Display", Georgia, serif; font-size: 0.95rem; color: #fff; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .sticky-bar .s small { font-size: 0.7rem; color: var(--purple-200); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } + .sticky-bar button { flex: none; border: 0; border-radius: 999px; background: linear-gradient(to right, var(--grad-start), #6C5CE7); color: #fff; font: inherit; font-size: 0.82rem; font-weight: 700; padding: 0.5rem 0.9rem; cursor: pointer; } +} + +@media print { + .site-header, .backbar-wrap, .totop, .site-footer, .sample-banner, .plan-input, .plan-actions, .toast, .lang-links, .sticky-bar { display: none !important; } + .section { padding: 1rem 0 !important; } + .section.dark, .section.tint { background: #fff !important; color: var(--primary-900); } + .section.dark .sec-head h2, .plan-hero h1 { -webkit-text-fill-color: var(--primary-900); background: none; } + .stat { background: #fff; border: 1px solid var(--slate-200); } .stat b { color: var(--primary-900); } .stat .label, .stat .desc { color: var(--slate-700); } + .card, .day { box-shadow: none; break-inside: avoid; } +} diff --git a/templates/supporters-astro/vercel.json b/templates/supporters-astro/vercel.json index bcedc3b..4dbf7e6 100644 --- a/templates/supporters-astro/vercel.json +++ b/templates/supporters-astro/vercel.json @@ -21,5 +21,27 @@ } ], "cleanUrls": true, - "trailingSlash": false -} \ No newline at end of file + "trailingSlash": false, + "redirects": [ + { + "source": "/recovery", + "destination": "/plan", + "permanent": true + }, + { + "source": "/stay", + "destination": "/plan", + "permanent": true + }, + { + "source": "/en/recovery", + "destination": "/en/plan", + "permanent": true + }, + { + "source": "/en/stay", + "destination": "/en/plan", + "permanent": true + } + ] +} diff --git a/workers/supporters-build/README.md b/workers/supporters-build/README.md index 3e5a29c..f9368c6 100644 --- a/workers/supporters-build/README.md +++ b/workers/supporters-build/README.md @@ -3,8 +3,10 @@ 병원 홈페이지 URL 하나로 근거 수집 → 팩트 시트·의료진 초안 → 첫 배치 기획 → 글 생성(GPT-4.1, 게이트·근거 대조) → Astro 빌드·발행 게이트 → Vercel 미리보기(noindex) 까지 돈다. 사람 게이트(의학 검토·게시 승인)는 자동화하지 않는다. ``` -node workers/supporters-build/run.mjs --clinic --url [--name 상호] [--logo file.svg] [--youtube 채널] [--deploy] [--build-id ] [--max-cost-usd 10] -# 단계: evidence → data → discover(채널 발견·엔티티 검증) → youtube(로고·파비콘·채널 집계) → news(뉴스룸: 네이버 뉴스 + 언론보도 게시판) → images(의료법 기준 이미지) → inputs → briefs → generate → build → deploy +node workers/supporters-build/run.mjs --clinic --url [--name 상호] [--logo file.svg] [--youtube 채널] [--deploy] [--build-id ] [--max-cost-usd 10] [--no-tourism] [--no-recovery] +# 단계: evidence → ocr(이미지 글자) → data → discover(채널 발견·엔티티 검증) → youtube(로고·파비콘·채널 집계) → news(뉴스룸: 네이버 뉴스 + 언론보도 게시판) → images(의료법 기준 이미지) → tourism(주변 안내: /stay·/en/stay 데이터) → recovery(시술 후 관리 안내: 병원 시술 페이지 원문 인용·번역) → inputs → briefs → generate → build → deploy +# 주변 안내만 다시: node workers/supporters-build/run.mjs --clinic --url --from tourism --skip-generate +# 시술 후 관리 안내만 다시: node workers/supporters-build/run.mjs --clinic --url --from recovery --skip-generate node workers/supporters-build/poll.mjs [--loop 300] [--no-deploy] # supporter_builds 큐(status=queued)를 집어 run.mjs 실행 ``` @@ -26,10 +28,30 @@ VPS(서버 직접 운영)와 Vercel Functions(최대 800초)는 권하지 않는 ## 필요한 것 -- `.env`: `VITE_SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `OPENAI_API_KEY`, `YOUTUBE_API_KEY`, `NAVER_CLIENT_ID`/`NAVER_CLIENT_SECRET`(뉴스룸) +- `.env`: `VITE_SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `OPENAI_API_KEY`, `YOUTUBE_API_KEY`, `NAVER_CLIENT_ID`/`NAVER_CLIENT_SECRET`(뉴스룸, 주변 안내의 주소→좌표), `TOUR_API_KEY`/`TOUR_API_BASE`(주변 안내, 한국관광공사 TourAPI. 없으면 tourism 단계를 건너뛰고 페이지는 확인 대기로 발행) +- `python3` (tourism 단계가 `scripts/fetch_medical_tourism.py` 를 부른다. `certifi` 가 있으면 SSL 인증서 검증에 쓴다) - `vercel` CLI 로그인 (배포 시). 병원당 프로젝트 `supporters-` 를 만든다 - `templates/supporters-astro/` (supporters 에서 `npm run export:template`) +## 주변 안내 (tourism 단계) + +`/stay`(국문)·`/en/stay`(영문)의 식사·숙박·휴식·관광·문화·쇼핑·축제 목록은 병원 좌표를 기준으로 한국관광공사 TourAPI 에서 모은다. 기준 좌표는 팩트 시트 주소(`address.full`)와 상호를 네이버 지역검색에 넣어 결과의 도로명·번지가 같을 때만 받는다. 주소만으로는 지역검색 결과가 없으므로 상호가 필요하다. + +- 좌표를 못 정하면 스크립트는 종료 코드 1 로 멈추고, 워커는 `status.json` 의 해당 단계를 `warning` 으로 적고 빌드를 계속한다. 페이지는 템플릿의 빈 데이터로 "확인 대기"를 그린다. +- `meta.origin.coordSource` 에 좌표 출처와 날짜가 남는다(예: `네이버 지역검색 '뷰성형외과의원' (...) 2026-09-10`). +- 결과 요약은 `status.json` 의 `report.tourism` 에 있다(기준 좌표, 언어별 장소·축제 수). +- 네이버 이미지 검색 폴백은 제3자 저작물이다. 공개 배포 빌드는 `--no-naver-images` 를 붙인다. +- 수동 실행: `python3 scripts/fetch_medical_tourism.py --clinic --name "<상호>" --address "<주소>" --label "<상호> (<도로명>)" --out-en /src/data/medicalTourism.json --out-ko /src/data/medicalTourismKo.json` + +## 시술 후 관리 안내 (recovery 단계) + +`/stay`·`/en/stay` 의 "하루 동선" 아래 "시술 후 관리 안내" 블록. `scripts/collect_recovery.mjs` 가 근거 페이지(type procedure·aftercare·precautions, OCR 텍스트 포함)의 문장 중 시점 표현과 행동·주의 표현이 함께 있는 것만 고른다. 효과·홍보 문장, 병원 연락처 문장, 수술 전 준비 문장, 표 칸이 뒤섞인 OCR 문장, 발행 게이트 규칙(금칙어·효과 보장·금액·운영자 어휘)에 걸리는 문장은 뺀다. 페이지당 최대 5문장, 최대 30페이지. + +- 영문은 `OPENAI_API_KEY` 로 gpt-4.1-mini 배치 번역(temperature 0, 상한 $0.5). 번역문의 숫자가 원문과 다르면 그 문장은 영문을 비우고(`enFailed`) 영문 화면에 한글 원문 + "Korean" 표시로 나간다. 같은 문장은 `/src/data/recoveryNotes.cache.json` 에서 다시 쓴다. +- 결과 `/src/data/recoveryNotes.json`. items 가 비면 페이지는 블록을 그리지 않는다. 요약은 `status.json` 의 `report.recovery`. +- 병원 확정 안내문(`site.recoveryStagesKo/En`)과 역할이 다르다. 확정값은 "병원 안내" 문단, 이 블록은 출처 링크·확인일이 붙은 원문 인용이다. 확정값이 없으면 "확인 대기" 문단은 그대로 남는다. +- 발행 게이트의 홈페이지 40자 일치 검사(§3-11)는 이 인용 블록(`#recovery-quote`)만 빼고 본다. 금칙어·운영자 어휘 검사는 인용 블록에도 적용된다. + ## 단가 글 생성 상한은 실행당 $10 (`--max-cost-usd`, haewon 결정 2026-09-07). 실측: 편당 $0.05~0.19, 첫 배치 5~6편이면 $0.3~1. diff --git a/workers/supporters-build/run.mjs b/workers/supporters-build/run.mjs index 5844d0c..4f275d7 100644 --- a/workers/supporters-build/run.mjs +++ b/workers/supporters-build/run.mjs @@ -3,9 +3,9 @@ // // node workers/supporters-build/run.mjs --clinic --url [--name 상호] [--work ~/supporters-builds/] // [--inputs inputs.json | --from-supabase] [--brief briefs.json] [--max-posts 6] [--max-cost-usd 3] -// [--deploy] [--build-id ] [--from ] [--skip-generate] [--news-board | --no-news] +// [--deploy] [--build-id ] [--from ] [--skip-generate] [--news-board | --no-news] [--no-tourism] [--no-recovery] // -// 단계: evidence → data → discover → youtube → news → images → inputs → briefs → generate → build → deploy → done +// 단계: evidence → ocr → data → discover → youtube → news → images → tourism → recovery → inputs → briefs → generate → build → deploy → done // 단계마다 /status.json 을 쓰고, --build-id 와 SUPABASE_SERVICE_ROLE_KEY 가 있으면 supporter_builds 행을 갱신한다. // 게이트(check.mjs)가 error 를 내면 status=gate_failed 로 멈춘다. 사람 게이트(검토·승인)는 여기서 자동화하지 않는다. import { spawnSync } from 'node:child_process'; @@ -26,7 +26,7 @@ const clinic = opt('clinic'); const url = opt('url'); if (!clinic || !url) { console.error('사용법: --clinic --url '); process.exit(2); } const WORK = resolve(opt('work', join(homedir(), 'supporters-builds', clinic))); const today = new Date().toISOString().slice(0, 10); -const PHASES = ['evidence', 'data', 'discover', 'youtube', 'news', 'images', 'inputs', 'briefs', 'generate', 'build', 'deploy', 'done']; +const PHASES = ['evidence', 'ocr', 'data', 'discover', 'youtube', 'news', 'images', 'tourism', 'recovery', 'planner', 'inputs', 'briefs', 'generate', 'build', 'deploy', 'done']; const startFrom = opt('from', 'evidence'); (function loadEnv() { const p = join(ROOT, '.env'); if (!existsSync(p)) return; for (const line of readFileSync(p, 'utf8').split('\n')) { const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/); if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, ''); } })(); @@ -60,10 +60,13 @@ async function phase(name, fn) { await setStatus({ status: 'running', phase: name }); console.log(`\n▶ ${name}`); try { - const summary = await fn(); - Object.assign(entry, { status: 'ok', finishedAt: new Date().toISOString(), summary: summary ?? '' }); + // 단계는 문자열(요약) 또는 { warn: true, summary } 를 돌려준다. warn 이면 빌드는 계속하되 status.json 에 'warning' 으로 남긴다. + const res = await fn(); + const summary = (res && typeof res === 'object') ? res.summary ?? '' : res ?? ''; + const warn = Boolean(res && typeof res === 'object' && res.warn); + Object.assign(entry, { status: warn ? 'warning' : 'ok', finishedAt: new Date().toISOString(), summary }); await setStatus({}); - console.log(` ✓ ${name}${summary ? ` · ${summary}` : ''}`); + console.log(` ${warn ? '△' : '✓'} ${name}${summary ? ` · ${summary}` : ''}`); } catch (e) { Object.assign(entry, { status: 'failed', finishedAt: new Date().toISOString(), log: String(e.message ?? e).slice(0, 4000) }); await setStatus({ status: e.gate ? 'gate_failed' : 'failed', error: String(e.message ?? e).slice(0, 2000) }); @@ -85,6 +88,18 @@ await phase('evidence', () => { return `${idx.pages.length}페이지 · 유형 ${Object.entries(idx.byType).map(([k, v]) => `${k} ${v}`).join(', ')}`; }); +// 이미지 글자 OCR (macOS Vision). 시술 설명을 통짜 이미지로 넣는 사이트(오라클피부과: 시술 84페이지 중 83개)에서 근거를 확보한다. +// 유료 API 없음. --no-ocr 로 끄고, swift 가 없는 환경이면 경고로 건너뛴다. 결과는 evidence 페이지 JSON 에 source:"ocr" 섹션으로 들어가 원문과 구분된다. +await phase('ocr', () => { + if (flag('no-ocr')) return '건너뜀 (--no-ocr)'; + if (process.platform !== 'darwin') return { warn: true, summary: '건너뜀 (macOS Vision 필요. 다른 OS 에서는 OCR 없이 진행)' }; + const r = run('node', ['scripts/ocr_evidence.mjs', '--clinic', clinic, '--evidence', EV, '--max-images', opt('max-ocr-images', '200')]); + if (!r.ok) return { warn: true, summary: `OCR 실패, 원문만으로 진행\n${tail(r.out, 3)}` }; + const idx = readJson(join(EV, 'index.json')); + const o = idx.ocr ?? {}; + return `이미지 ${o.images ?? '?'}장 · 페이지 ${o.pages ?? '?'}개 · OCR ${o.chars ?? '?'}자 · 의료진 후보 ${(existsSync(join(EV, 'doctors.json')) ? readJson(join(EV, 'doctors.json')).doctors ?? [] : []).length}명`; +}); + // 2. 템플릿 복제 + 팩트 시트·의료진 초안 await phase('data', () => { if (!existsSync(TEMPLATE)) throw new Error(`템플릿 없음: ${TEMPLATE} (supporters 에서 npm run export:template)`); @@ -250,15 +265,99 @@ await phase('images', () => { return `${m.items.length}장 (의료진 ${by('doctors').length}, 시설 ${clinicImgs.length}, 시술 ${by('procedure').length}, 장비 ${by('equipment').length}) · 원장 사진 ${docImgs}명 · 히어로 ${site.heroImage?.src ? '설정' : '없음'}`; }); +// 2e. 주변 안내(/stay·/en/stay): 팩트 시트 주소를 기준 좌표로 한국관광공사 TourAPI 에서 주변 장소·축제를 모아 영문·국문 JSON 을 쓴다. +// 좌표는 scripts/fetch_medical_tourism.py 가 네이버 지역검색으로 상호+주소를 대조해 정한다(지어내지 않는다). 못 정하면 경고만 남기고 빌드는 계속한다. +// 데이터가 없으면 페이지는 템플릿의 빈 데이터(origin lat 0)로 "확인 대기"를 그린다. 키가 없으면 건너뛴다. +await phase('tourism', () => { + if (flag('no-tourism')) return '건너뜀 (--no-tourism)'; + if (!process.env.TOUR_API_KEY) return '건너뜀 (키 없음: TOUR_API_KEY)'; + const fact = readJson(join(DATA, 'factSheet.json')); + const address = fact.address?.full || fact.address?.street || ''; + const name = opt('name') || fact.shortName || fact.name || ''; + if (!address || !name) return { warn: true, summary: `건너뜀 (팩트 시트에 ${!address ? '주소' : '상호'} 없음. 페이지는 확인 대기로 발행)` }; + const label = `${name} (${fact.address?.street || address})`; + const outEn = join(DATA, 'medicalTourism.json'), outKo = join(DATA, 'medicalTourismKo.json'); + const argv = [join(ROOT, 'scripts', 'fetch_medical_tourism.py'), '--clinic', clinic, '--name', name, '--address', address, '--label', label, '--out-en', outEn, '--out-ko', outKo]; + if (flag('no-naver-images')) argv.push('--no-naver-images'); + const r = run('python3', argv, { cwd: ROOT }); + if (!r.ok || !existsSync(outEn) || !existsSync(outKo)) { + // 실패한 실행이 파일을 반쯤 남기지 않으므로(언어별로 수집이 끝난 뒤에만 쓴다) 템플릿의 빈 데이터가 그대로 남는다. + return { warn: true, summary: `주변 안내 수집 실패 (페이지는 확인 대기로 발행)\n${tail(r.out, 3)}` }; + } + const en = readJson(outEn), ko = readJson(outKo); + status.report = { ...(status.report ?? {}), tourism: { origin: en.meta.origin, en: { places: en.filters.total, festivals: en.festivals.length }, ko: { places: ko.filters.total, festivals: ko.festivals.length }, fetchedAt: en.meta.fetchedAt } }; + return `기준 ${en.meta.origin.lat}, ${en.meta.origin.lng} (${en.meta.origin.coordSource}) · 영문 장소 ${en.filters.total}·축제 ${en.festivals.length} · 국문 장소 ${ko.filters.total}·축제 ${ko.festivals.length}`; +}); + +// 2f. 시술 후 관리 안내(회복 일정 플래너 /plan 의 병원 원문 제약): 병원 시술 페이지 원문(OCR 포함)에서 시술 후 관리 문장을 고르고 영문으로 번역해 recoveryNotes.json 을 쓴다. +// 의학 판단이 아니라 원문 인용이다. 게이트 규칙(금칙어·효과 보장·금액)에 걸리는 문장은 스크립트가 뺀다. 실패해도 빌드는 계속한다(페이지는 블록을 그리지 않는다). +await phase('recovery', () => { + if (flag('no-recovery')) return '건너뜀 (--no-recovery)'; + const r = run('node', ['scripts/collect_recovery.mjs', '--clinic', clinic, '--evidence', EV, '--site', SITE, '--translate']); + const outPath = join(DATA, 'recoveryNotes.json'); + if (!r.ok || !existsSync(outPath)) return { warn: true, summary: `시술 후 관리 문장 수집 실패 (블록 없이 발행)\n${tail(r.out, 3)}` }; + const rn = readJson(outPath); + status.report = { ...(status.report ?? {}), recovery: rn.counts ?? {} }; + const c = rn.counts ?? {}; + return `시술 ${c.pages ?? 0}개 · ${c.sentences ?? 0}문장 · 번역 ${c.translated ?? 0} · 실패 ${c.enFailed ?? 0} · $${c.costUsd ?? 0}${c.enFailed ? ' (실패 문장은 영문 화면에 한글 원문으로 표시)' : ''}`; +}); + +// 2g. 회복 일정 플래너(/plan·/en/plan) 병원별 데이터: 업종별 기본 규칙표 + 병원 시술 페이지 원문(recoveryNotes) + 큐레이션 장소(briefs) 또는 범용 기본표(관광공사 기준 좌표). +// 계산은 브라우저에서 하고 여기서는 데이터 파일만 만든다. 실패하면 템플릿 기본표(성형외과·범용 장소)로 발행하고 경고를 남긴다. +await phase('planner', () => { + if (flag('no-planner')) return '건너뜀 (--no-planner)'; + const argv = ['scripts/build_planner_data.mjs', '--clinic', clinic, '--site', SITE]; + if (opt('industry')) argv.push('--industry', opt('industry')); + const r = run('node', argv); + if (!r.ok) return { warn: true, summary: `플래너 데이터 생성 실패 (템플릿 기본표로 발행)\n${tail(r.out, 3)}` }; + status.report = { ...(status.report ?? {}), planner: tail(r.out, 1) }; + return tail(r.out, 1); +}); + // 3. 병원 입력 반영 (있으면) await phase('inputs', () => { - if (!opt('inputs') && !flag('from-supabase')) return '입력 없음 (확인 대기로 발행)'; - const argv = ['scripts/apply_inputs.mjs', '--clinic', clinic, ...(opt('inputs') ? ['--inputs', resolve(opt('inputs'))] : ['--from-supabase'])]; - // apply_inputs 는 자기 폴더 기준으로 데이터를 읽으므로 사이트 복제본의 scripts 로 실행한다 - cpSync(join(SUP, 'scripts', 'apply_inputs.mjs'), join(SITE, 'scripts', 'apply_inputs.mjs')); - const r = run('node', argv, { cwd: SITE }); - if (!r.ok) throw new Error(tail(r.out)); - return tail(r.out, 3); + const notes = []; + if (opt('inputs') || flag('from-supabase')) { + const argv = ['scripts/apply_inputs.mjs', '--clinic', clinic, ...(opt('inputs') ? ['--inputs', resolve(opt('inputs'))] : ['--from-supabase'])]; + // apply_inputs 는 자기 폴더 기준으로 데이터를 읽으므로 사이트 복제본의 scripts 로 실행한다 + cpSync(join(SUP, 'scripts', 'apply_inputs.mjs'), join(SITE, 'scripts', 'apply_inputs.mjs')); + const r = run('node', argv, { cwd: SITE }); + if (!r.ok) throw new Error(tail(r.out)); + notes.push(tail(r.out, 3)); + } else notes.push('입력 없음 (확인 대기로 발행)'); + // 사람이 확정한 고정값(supporters/briefs//clinic.json). 자동값 위에 덮어써 재실행해도 유지된다. + // factSheet: 팩트 시트 필드 얕은 병합 · site: site.json 필드(heroImage·insideGallery 등, src 대신 srcMatch 로 파일명 일부 지정 가능) + // excludeImages: public/img 에서 파일명이 이 문자열로 시작하는 이미지를 지우고 갤러리에서 뺀다(시술 설명 이미지·모델 얼굴·전후 사진) + const pinPath = join(SUP, 'briefs', clinic, 'clinic.json'); + if (existsSync(pinPath)) { + const pin = readJson(pinPath); + if (pin.factSheet) { const fact = readJson(join(DATA, 'factSheet.json')); Object.assign(fact, pin.factSheet); writeJson(join(DATA, 'factSheet.json'), fact); notes.push(`팩트 시트 고정값 ${Object.keys(pin.factSheet).join('·')}`); } + const imgDir = join(SITE, 'public', 'img', 'clinic'); + const files = existsSync(imgDir) ? readdirSync(imgDir) : []; + // srcMatch: 자동 수집 파일명 일부 · file: 사람이 준 파일(저장소 상대 경로)을 public/img/clinic 으로 복사해 쓴다(병원 제공 사진·그룹 사이트 건물 외관 등) + const resolveSrc = (o) => { + if (!o || o.src) return o; + if (o.file) { const srcFile = resolve(ROOT, o.file); if (!existsSync(srcFile)) return null; mkdirSync(imgDir, { recursive: true }); const name = 'pin-' + srcFile.split('/').pop(); cpSync(srcFile, join(imgDir, name)); const { file, ...rest } = o; return { src: `/img/clinic/${name}`, ...rest }; } + if (!o.srcMatch) return o; + const f = files.find((x) => x.includes(o.srcMatch)); const { srcMatch, ...rest } = o; return f ? { src: `/img/clinic/${f}`, ...rest } : null; + }; + if (pin.site || pin.excludeImages) { + const site = readJson(join(DATA, 'site.json')); + const ex = pin.excludeImages ?? []; + let removed = 0; + for (const f of files) if (ex.some((e) => f.startsWith(e))) { rmSync(join(imgDir, f), { force: true }); removed++; } + const keep = (list) => (list ?? []).filter((i) => !ex.some((e) => (i.src ?? '').split('/').pop().startsWith(e))); + for (const k of ['insideGallery', 'clinicGallery']) site[k] = keep(site[k]); + // 이미지 매니페스트(images.json)에서도 빼야 기획기(default_briefs)가 글 히어로·갤러리로 다시 집지 않는다 (2026-09-10 오라클: 제외한 시술 이미지가 글 썸네일로 들어가 깨진 그림이 됐다) + const manPath = join(DATA, 'images.json'); + if (existsSync(manPath)) { const man = readJson(manPath); const before = (man.items ?? []).length; man.items = (man.items ?? []).filter((i) => !ex.some((e) => (i.src ?? '').split('/').pop().startsWith(e))); man.excludedByPin = before - man.items.length; writeJson(manPath, man); } + if (site.heroImage?.src && ex.some((e) => site.heroImage.src.split('/').pop().startsWith(e))) site.heroImage = site.insideGallery[0] ? { ...site.insideGallery[0], width: 600, height: 330 } : {}; + for (const [k, v] of Object.entries(pin.site ?? {})) site[k] = Array.isArray(v) ? v.map(resolveSrc).filter(Boolean) : (resolveSrc(v) ?? site[k]); + writeJson(join(DATA, 'site.json'), site); + notes.push(`이미지 제외 ${removed}장 · site 고정값 ${Object.keys(pin.site ?? {}).join('·') || '없음'}`); + } + } + return notes.join(' · '); }); // 4. 기획 목록