From 61251547a048e8f1ddea23bd277418661f4e546a Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Thu, 5 Dec 2024 12:11:28 +0800 Subject: [PATCH 1/9] first commit for V0.3.22 --- Dockerfile | 16 +- README.md | 8 +- compose.yaml | 7 +- core/agents/__init__.py | 0 core/agents/get_info.py | 195 +++++++++++++++ core/agents/insights.py | 0 core/agents/seeact.py | 5 + core/backend.py | 45 ---- core/docker_entrypoint.sh | 4 - core/insights/__init__.py | 162 ------------- core/insights/get_info.py | 151 ------------ core/llms/openai_wrapper.py | 38 +-- core/pb/pb_hooks/main.pb.js | 74 ------ .../1712449900_created_article_translation.js | 55 ----- .../1712450012_created_articles.js | 154 ------------ .../1712450207_updated_article_translation.js | 52 ---- .../1712450442_created_insights.js | 73 ------ .../pb_migrations/1713322324_created_sites.js | 54 ----- .../pb_migrations/1713328405_updated_sites.js | 74 ------ .../pb_migrations/1713329959_updated_sites.js | 27 --- .../1714803585_updated_articles.js | 44 ---- .../1714835361_updated_insights.js | 31 --- .../1714955881_updated_articles.js | 31 --- .../pb_migrations/1715823361_created_tags.js | 51 ---- .../1715824265_updated_insights.js | 52 ---- .../1715852342_updated_insights.js | 16 -- .../1715852638_updated_insights.js | 16 -- .../pb_migrations/1715852847_updated_users.js | 33 --- .../1715852924_updated_articles.js | 33 --- .../1715852932_updated_articles.js | 18 -- .../1715852952_updated_article_translation.js | 33 --- .../1715852974_updated_article_translation.js | 18 -- .../pb_migrations/1716165809_updated_tags.js | 44 ---- .../1716168332_updated_insights.js | 48 ---- .../pb_migrations/1717321896_updated_tags.js | 18 -- .../pb_migrations/1725263585_updated_tags.js | 31 --- core/scrapers/README.md | 56 ----- core/scrapers/README_CN.md | 56 ----- core/scrapers/README_de.md | 56 ----- core/scrapers/README_fr.md | 56 ----- core/scrapers/README_jp.md | 56 ----- core/scrapers/__init__.py | 4 - core/scrapers/general_crawler.py | 228 ------------------ core/scrapers/mp_crawler.py | 129 ---------- core/scripts/start_backend.sh | 2 +- core/scripts/start_tasks.sh | 2 +- core/tasks.py | 2 +- core/utils/general_utils.py | 34 ++- core/utils/pb_api.py | 4 +- dashboard/README.md | 77 +----- dashboard/__init__.py | 8 +- 51 files changed, 266 insertions(+), 2215 deletions(-) create mode 100644 core/agents/__init__.py create mode 100644 core/agents/get_info.py create mode 100644 core/agents/insights.py create mode 100644 core/agents/seeact.py delete mode 100644 core/backend.py delete mode 100755 core/docker_entrypoint.sh delete mode 100644 core/insights/__init__.py delete mode 100644 core/insights/get_info.py delete mode 100644 core/pb/pb_hooks/main.pb.js delete mode 100644 core/pb/pb_migrations/1712449900_created_article_translation.js delete mode 100644 core/pb/pb_migrations/1712450012_created_articles.js delete mode 100644 core/pb/pb_migrations/1712450207_updated_article_translation.js delete mode 100644 core/pb/pb_migrations/1712450442_created_insights.js delete mode 100644 core/pb/pb_migrations/1713322324_created_sites.js delete mode 100644 core/pb/pb_migrations/1713328405_updated_sites.js delete mode 100644 core/pb/pb_migrations/1713329959_updated_sites.js delete mode 100644 core/pb/pb_migrations/1714803585_updated_articles.js delete mode 100644 core/pb/pb_migrations/1714835361_updated_insights.js delete mode 100644 core/pb/pb_migrations/1714955881_updated_articles.js delete mode 100644 core/pb/pb_migrations/1715823361_created_tags.js delete mode 100644 core/pb/pb_migrations/1715824265_updated_insights.js delete mode 100644 core/pb/pb_migrations/1715852342_updated_insights.js delete mode 100644 core/pb/pb_migrations/1715852638_updated_insights.js delete mode 100644 core/pb/pb_migrations/1715852847_updated_users.js delete mode 100644 core/pb/pb_migrations/1715852924_updated_articles.js delete mode 100644 core/pb/pb_migrations/1715852932_updated_articles.js delete mode 100644 core/pb/pb_migrations/1715852952_updated_article_translation.js delete mode 100644 core/pb/pb_migrations/1715852974_updated_article_translation.js delete mode 100644 core/pb/pb_migrations/1716165809_updated_tags.js delete mode 100644 core/pb/pb_migrations/1716168332_updated_insights.js delete mode 100644 core/pb/pb_migrations/1717321896_updated_tags.js delete mode 100644 core/pb/pb_migrations/1725263585_updated_tags.js delete mode 100644 core/scrapers/README.md delete mode 100644 core/scrapers/README_CN.md delete mode 100644 core/scrapers/README_de.md delete mode 100644 core/scrapers/README_fr.md delete mode 100644 core/scrapers/README_jp.md delete mode 100644 core/scrapers/__init__.py delete mode 100644 core/scrapers/general_crawler.py delete mode 100644 core/scrapers/mp_crawler.py diff --git a/Dockerfile b/Dockerfile index 114bc4b..dc9f761 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,19 @@ FROM python:3.10-slim RUN apt-get update && \ - apt-get install -yq tzdata build-essential unzip && \ - apt-get clean + apt-get install -y tzdata build-essential unzip + +COPY core/requirements.txt /tmp/requirements.txt +RUN pip install --no-cache-dir -r /tmp/requirements.txt WORKDIR /app -COPY core/requirements.txt requirements.txt -RUN pip install --no-cache-dir -r requirements.txt - -COPY core . - # download and unzip PocketBase -ADD https://github.com/pocketbase/pocketbase/releases/download/v0.22.13/pocketbase_0.22.13_linux_amd64.zip /tmp/pb.zip +ADD https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/pocketbase_0.23.4_linux_amd64.zip /tmp/pb.zip # for arm device -# ADD https://github.com/pocketbase/pocketbase/releases/download/v0.22.13/pocketbase_0.22.13_linux_arm64.zip /tmp/pb.zip +# ADD https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/pocketbase_0.23.4_linux_arm64.zip /tmp/pb.zip RUN unzip /tmp/pb.zip -d /app/pb/ +RUN apt-get clean && rm -rf /var/lib/apt/lists/* EXPOSE 8090 EXPOSE 8077 diff --git a/README.md b/README.md index 02f267a..3f2374d 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,11 @@ https://github.com/TeamWiseFlow/wiseflow/assets/96130569/bd4b2091-c02d-4457-9ec6 但我们也注意到部分关注者对 wiseflow 的功能定位存在一些理解偏差,为免误会,我们制作了如下表格,清晰展示 wiseflow 与爬虫、AI搜索、知识库(RAG)类项目的对比: -| | **首席情报官(Wiseflow)** | +| | 与 **首席情报官(Wiseflow)** 的比较说明| |-------------|-----------------| -| **爬虫类工具** | wiseflow 集成了很多优秀的开源爬虫工具,并增加了基于 LLM 的自动化信息过滤、筛选与分类能力,所以可以简单认为 wiseflow = 爬虫工具 + AI | -| **AI搜索** | AI搜索主要的应用场景是**具体问题的即时问答**,举例:”XX公司的创始人是谁“、“xx品牌下的xx产品哪里有售” ;wiseflow主要的应用场景是**某一方面信息的持续采集**,比如XX公司的关联信息追踪,XX品牌市场行为的持续追踪……在这些场景下,用户只能提供关注点(某公司、某品牌),但无法提出具体搜索问题,且并不是一次检索,而是需要持续追踪,或者自动化进行关联追踪,您可以简单的把wiseflow理解为一个可持续自动进行 ai 搜索的“智能体”,即 “AI 情报官” | -| **知识库(RAG)类项目** | 知识库(RAG)类项目一般是基于已有信息的下游任务,并且一般面向的是私有知识(比如企业内的操作手册、产品手册、政府部门的文件等);wiseflow 目前并未整合下游任务,同时面向的是互联网上的公开信息 | +| **爬虫类工具** | 首先 wiseflow 是基于爬虫工具的项目(以目前的版本而言,wiseflow 集成了优秀的开源爬虫项目 Crwalee,而 Crawlee 的底层又是基于 beautifulsoup\playwright\httpx等大家耳熟能详的流行库)……但传统的爬虫工具都是面向开发者的,需要开发者手动去探索目标站点的结构,分析出要提取元素的 xpath 等,这不仅阻挡了普通用户,同时也毫无通用性可言,即对于不同网站(包括已有网站升级)都需要重做分析和探索。这个问题在 LLM 出现之前是无解的,而wiseflow致力的方向即是使用 LLM 自动化目标站点的分析和探索工作,从而实现“普通用户也可使用的通用爬虫”,从这个角度来说,你可以简单理解 wiseflow 为 “能自动使用爬虫工具的 AI 智能体” | +| **AI搜索** | AI搜索主要的应用场景是**具体问题的即时问答**,举例:”XX公司的创始人是谁“、“xx品牌下的xx产品哪里有售” ,用户要的是**一个答案**;wiseflow主要的应用场景是**某一方面信息的持续采集**,比如XX公司的关联信息追踪,XX品牌市场行为的持续追踪……在这些场景下,用户能提供关注点(某公司、某品牌)、甚至能提供信源(站点 url 等),但无法提出具体搜索问题,用户要的是**一系列相关信息**| +| **知识库(RAG)类项目** | 知识库(RAG)类项目一般是基于已有信息的下游任务,并且一般面向的是私有知识(比如企业内的操作手册、产品手册、政府部门的文件等);wiseflow 目前并未整合下游任务,同时面向的是互联网上的公开信息,如果从“智能体”的角度来看,二者属于为不同目的而构建的智能体,RAG 类项目是“(内部)知识助理智能体”,而 wiseflow 则是“(外部)信息采集智能体”| ## 🔄 V0.3.1 更新 diff --git a/compose.yaml b/compose.yaml index 5decf91..38c30cd 100755 --- a/compose.yaml +++ b/compose.yaml @@ -5,12 +5,9 @@ services: image: wiseflow:latest tty: true stdin_open: true - entrypoint: bash docker_entrypoint.sh - env_file: - - .env + entrypoint: ["bash", "/app/run_all.sh"] ports: - 8090:8090 - 8077:8077 volumes: - - ./${PROJECT_DIR}/pb_data:/app/pb/pb_data - - ./${PROJECT_DIR}:/app/${PROJECT_DIR} \ No newline at end of file + - ./core:/app \ No newline at end of file diff --git a/core/agents/__init__.py b/core/agents/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/agents/get_info.py b/core/agents/get_info.py new file mode 100644 index 0000000..b1279d4 --- /dev/null +++ b/core/agents/get_info.py @@ -0,0 +1,195 @@ +from core.llms.openai_wrapper import openai_llm as llm +# from core.llms.siliconflow_wrapper import sfa_llm +import re +from core.utils.general_utils import is_chinese, extract_and_convert_dates, extract_urls +from loguru import logger +from core.utils.pb_api import PbTalker +import os +from datetime import datetime, date +from urllib.parse import urlparse +import json_repair + + +class GeneralInfoExtractor: + def __init__(self, pb: PbTalker, _logger: logger) -> None: + self.pb = pb + self.logger = _logger + self.model = os.environ.get("PRIMARY_MODEL", "Qwen/Qwen2.5-7B-Instruct") # better to use "Qwen/Qwen2.5-14B-Instruct" + self.secondary_model = os.environ.get("SECONDARY_MODEL", "THUDM/glm-4-9b-chat") + + # collect tags user set in pb database and determin the system prompt language based on tags + focus_data = pb.read(collection_name='focus_points', filter=f'activated=True') + if not focus_data: + self.logger.info('no activated tag found, will ask user to create one') + focus = input('It seems you have not set any focus point, WiseFlow need the specific focus point to guide the following info extract job.' + 'so please input one now. describe what info you care about shortly: ') + explanation = input('Please provide more explanation for the focus point (if not necessary, pls just type enter: ') + focus_data.append({"name": focus, "explaination": explanation, + "id": pb.add('focus_points', {"focuspoint": focus, "explanation": explanation})}) + + self.focus_list = [item["focuspoint"] for item in focus_data] + self.focus_dict = {item["focuspoint"]: item["id"] for item in focus_data} + focus_statement = '' + for item in focus_data: + tag = item["name"] + expl = item["explaination"] + focus_statement = f"{focus_statement}#{tag}\n" + if expl: + focus_statement = f"{focus_statement}解释:{expl}\n" + + if is_chinese(focus_statement): + self.get_info_prompt = f'''作为信息提取助手,你的任务是从给定的网页文本中提取与以下用户兴趣点相关的内容。兴趣点列表及其解释如下: + +{focus_statement}\n +在进行信息提取时,请遵循以下原则: + +- 理解每个兴趣点的含义,确保提取的内容与之相关。 +- 如果兴趣点有进一步的解释,确保提取的内容符合这些解释的范围。 +- 忠于原文,你的任务是从网页文本中识别和提取与各个兴趣点相关的信息,并不是总结和提炼。 +- 不管给定的原文是何种语言,请保证使用中文输出你的提取结果。 + +另外请注意给定的网页文本是通过爬虫程序从html代码中提取出来的,所以请忽略里面不必要的空格、换行符等。''' + self.get_info_suffix = '''如果上述网页文本中包含兴趣点相关的内容,请按照以下json格式输出提取的信息(文本中可能包含多条有用信息,请不要遗漏): +[{"focus": 兴趣点名称, "content": 提取的内容}] + +示例: +[{"focus": "旅游景点", "content": "北京故宫,地址:北京市东城区景山前街4号,开放时间:8:30-17:00"}, {"focus": "美食推荐", "content": "来王府井小吃街必吃北京烤鸭、炸酱面"}] + +如果网页文本中不包含任何与兴趣点相关的信息,请仅输出:[]。''' + self.get_more_link_prompt = f"作为一位高效的信息筛选助手,你的任务是根据给定的兴趣点,从给定的文本及其对应的URL中挑选出最值得关注的URL。兴趣点及其解释如下:\n\n{focus_statement}" + self.get_more_link_suffix = "请逐条分析上述 文本:url 对。首先输出你的分析依据,然后给出是否挑选它的结论,如果决定挑选该条,在结论后复制输出该条的 url,否则的话直接进入下一条的分析。请一条一条的分析,不要漏掉任何一条。" + else: + self.get_info_prompt = f'''As an information extraction assistant, your task is to extract content related to the following user focus points from the given web page text. The list of focus points and their explanations is as follows: + +{focus_statement}\n +When extracting information, please follow the principles below: + +- Understand the meaning of each focus point and ensure that the extracted content is relevant to it. +- If a focus point has further explanations, ensure that the extracted content conforms to the scope of these explanations. +- Stay true to the original text; your task is to identify and extract information related to each focus point from the web page text, not to summarize or refine it. + +Please note that the given web page text is extracted from HTML code via a crawler, so please ignore any unnecessary spaces, line breaks, etc.''' + self.get_info_suffix = '''If the above webpage text contains content related to points of interest, please output the extracted information in the following JSON format (the text may contain multiple useful pieces of information, do not miss any): +[{"focus": "Point of Interest Name", "content": "Extracted Content"}] + +Example: +[{"focus": "Tourist Attraction", "content": "The Forbidden City, Beijing, Address: No. 4 Jingshan Front Street, Dongcheng District, Opening Hours: 8:30-17:00"}, {"focus": "Food Recommendation", "content": "Must-try at Wangfujing Snack Street: Beijing Roast Duck, Noodles with Soybean Paste"}] + +If the webpage text does not contain any information related to points of interest, please output only: []''' + self.get_more_link_prompt = f"As an efficient information filtering assistant, your task is to select the most noteworthy URLs from a set of texts and their corresponding URLs based on the given focus points. The focus points and their explanations are as follows:\n\n{focus_statement}" + self.get_more_link_suffix = "Please analyze the above text: URL pairs. First, output your analysis basis, and then give the conclusion on whether to select it. If you decide to select this item, then copy and output the URL of this item following the conclusion; otherwise, proceed directly to the analysis of the next item. Analyze one by one, do not miss any one." + + async def get_author_and_publish_date(self, text: str) -> tuple[str, str]: + system_prompt = "As an information extraction assistant, your task is to accurately extract the source (or author) and publication date from the given webpage text. It is important to adhere to extracting the information directly from the original text. If the original text does not contain a particular piece of information, please replace it with NA" + suffix = '''Please output the extracted information in the following JSON format: +{"source": source or article author (use "NA" if this information cannot be extracted), "publish_date": extracted publication date (keep only the year, month, and day; use "NA" if this information cannot be extracted)}''' + + content = f'\n{text}\n\n\n{suffix}' + llm_output = await llm([{'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': content}], + model=self.secondary_model, max_tokens=50, temperature=0.1, response_format={"type": "json_object"}) + + self.logger.debug(f'get_author_and_publish_date llm output:\n{llm_output}') + if not llm_output: + return '', '' + result = json_repair.repair_json(llm_output, return_objects=True) + self.logger.debug(f"decoded_object: {result}") + if not isinstance(result, dict): + self.logger.debug("failed to parse from llm output") + return '', '' + if 'source' not in result or 'publish_date' not in result: + self.logger.debug("failed to parse from llm output") + return '', '' + + return result['source'], result['publish_date'] + + async def get_more_related_urls(self, link_dict: dict) -> set[str]: + if not link_dict: + return set() + content = '' + for key, value in link_dict.items(): + content = f"{content}{key}: {value}\n" + result = await llm([{'role': 'system', 'content': self.get_more_link_prompt}, {'role': 'user', 'content': f'{content}\n{self.get_more_link_suffix}'}], + model=self.secondary_model, temperature=0.1) + + self.logger.debug(f'get_more_related_urls llm output:\n{result}') + urls = extract_urls(result) + raw_urls = list(link_dict.values()) + for url in urls: + if url not in raw_urls: + self.logger.debug(f"{url} not in link_dict, it's model's Hallucination") + urls.remove(url) + return urls + + async def get_info(self, text: str, domain: str) -> list[dict]: + # logger.debug(f'receive new article_content:\n{article_content}') + content = f'\n{text}\n\n\n{self.get_info_suffix}' + result = await llm([{'role': 'system', 'content': self.get_info_prompt}, {'role': 'user', 'content': content}], + model=self.model, temperature=0.1, response_format={"type": "json_object"}) + + + + + + + + + + + + + +domain = urlparse(url).netloc + +def get_info(article_content: str) -> list[dict]: + # logger.debug(f'receive new article_content:\n{article_content}') + result = openai_llm([{'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': article_content}], + model=get_info_model, logger=logger, temperature=0.1) + + # results = pattern.findall(result) + texts = result.split('') + texts = [_.strip() for _ in texts if '' in _.strip()] + if not texts: + logger.debug(f'can not find info, llm result:\n{result}') + return [] + + cache = [] + for text in texts: + try: + strings = text.split('') + tag = strings[0] + tag = tag.strip() + if tag not in focus_list: + logger.info(f'tag not in focus_list: {tag}, aborting') + continue + info = strings[1] + info = info.split('\n\n') + info = info[0].strip() + except Exception as e: + logger.info(f'parse error: {e}') + tag = '' + info = '' + + if not info or not tag: + logger.info(f'parse failed-{text}') + continue + + if len(info) < 7: + logger.info(f'info too short, possible invalid: {info}') + continue + + if info.startswith('无相关信息') or info.startswith('该新闻未提及') or info.startswith('未提及'): + logger.info(f'no relevant info: {text}') + continue + + while info.endswith('"'): + info = info[:-1] + info = info.strip() + + # 拼接下来源信息 + sources = re.findall(r'\[from (.*?)]', article_content) + if sources and sources[0]: + info = f"[from {sources[0]}] {info}" + + cache.append({'content': info, 'tag': focus_dict[tag]}) + + return cache diff --git a/core/agents/insights.py b/core/agents/insights.py new file mode 100644 index 0000000..e69de29 diff --git a/core/agents/seeact.py b/core/agents/seeact.py new file mode 100644 index 0000000..6ef168a --- /dev/null +++ b/core/agents/seeact.py @@ -0,0 +1,5 @@ +# future plan +# inspired by https://github.com/OSU-NLP-Group/SeeAct +# use a visual-llm to extract the main content and determine next action + +# input a playwright page object \ No newline at end of file diff --git a/core/backend.py b/core/backend.py deleted file mode 100644 index 298d55d..0000000 --- a/core/backend.py +++ /dev/null @@ -1,45 +0,0 @@ -from fastapi import FastAPI, BackgroundTasks -from pydantic import BaseModel -from typing import Literal, Optional -from fastapi.middleware.cors import CORSMiddleware -from insights import message_manager - - -class Request(BaseModel): - """ - Input model - input = {'user_id': str, 'type': str, 'content':str, 'addition': Optional[str]} - Type is one of "text", "publicMsg", "site" and "url"; - """ - user_id: str - type: Literal["text", "publicMsg", "file", "image", "video", "location", "chathistory", "site", "attachment", "url"] - content: str - addition: Optional[str] = None - - -app = FastAPI( - title="WiseFlow Union Backend", - description="From Wiseflow Team.", - version="0.3.1", - openapi_url="/openapi.json" -) - -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], - ) - - -@app.get("/") -def read_root(): - msg = "Hello, this is Wise Union Backend, version 0.3.1" - return {"msg": msg} - - -@app.post("/feed") -async def call_to_feed(background_tasks: BackgroundTasks, request: Request): - background_tasks.add_task(message_manager, _input=request.model_dump()) - return {"msg": "received well"} diff --git a/core/docker_entrypoint.sh b/core/docker_entrypoint.sh deleted file mode 100755 index 8a0d57d..0000000 --- a/core/docker_entrypoint.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -exec pb/pocketbase serve --http=0.0.0.0:8090 & -exec python tasks.py & -exec uvicorn backend:app --reload --host 0.0.0.0 --port 8077 \ No newline at end of file diff --git a/core/insights/__init__.py b/core/insights/__init__.py deleted file mode 100644 index 9da29ff..0000000 --- a/core/insights/__init__.py +++ /dev/null @@ -1,162 +0,0 @@ -# -*- coding: utf-8 -*- - -from scrapers.general_crawler import general_crawler -from utils.general_utils import extract_urls, compare_phrase_with_list -from .get_info import get_info, pb, project_dir, logger, info_rewrite -import os -import json -from datetime import datetime, timedelta -import re -import asyncio -from typing import Dict - - -# The XML parsing scheme is not used because there are abnormal characters in the XML code extracted from the weixin public_msg -item_pattern = re.compile(r'(.*?)', re.DOTALL) -url_pattern = re.compile(r'') -summary_pattern = re.compile(r'', re.DOTALL) -extensions = ('.pdf', '.docx', '.xlsx', '.doc', '.ppt', '.pptx', '.xls', '.txt', '.jpg', '.jpeg', '.png', '.gif', '.bmp', - '.tiff', '.mp4', '.avi', '.wmv', '.mkv', '.flv', '.wav', '.mp3', '.avi', '.mov', '.wmv', '.mpeg', '.mpg', - '.3gp', '.ogg', '.webm', '.m4a', '.aac', '.flac', '.wma', '.amr', '.ogg', '.m4v', '.m3u8', '.m3u', '.ts', - '.mts') -expiration_days = 3 -existing_urls = {url['url'] for url in pb.read(collection_name='articles', fields=['url']) if url['url']} - - -async def pipeline(url: str, cache: Dict[str, str] = {}): - working_list = {url} - while working_list: - url = working_list.pop() - existing_urls.add(url) - if any(url.endswith(ext) for ext in extensions): - logger.info(f"{url} is a file, skip") - continue - logger.debug(f"start processing {url}") - - # get article process - flag, result = await general_crawler(url, logger) - if flag == 1: - logger.info('get new url list, add to work list') - new_urls = result - existing_urls - working_list.update(new_urls) - continue - elif flag <= 0: - logger.error("got article failed, pipeline abort") - continue - - expiration = datetime.now() - timedelta(days=expiration_days) - expiration_date = expiration.strftime('%Y-%m-%d') - article_date = int(result['publish_time']) - if article_date < int(expiration_date.replace('-', '')): - logger.info(f"publish date is {article_date}, too old, skip") - continue - - for k, v in cache.items(): - if v: - result[k] = v - - # get info process - logger.debug(f"article: {result['title']}") - article_id = pb.add(collection_name='articles', body=result) - if not article_id: - logger.error('add article failed, writing to cache_file') - with open(os.path.join(project_dir, 'cache_articles.json'), 'a', encoding='utf-8') as f: - json.dump(result, f, ensure_ascii=False, indent=4) - continue - - insights = get_info(f"title: {result['title']}\n\ncontent: {result['content']}") - if not insights: - continue - - # post process - article_tags = set() - old_insights = pb.read(collection_name='insights', filter=f"updated>'{expiration_date}'", - fields=['id', 'tag', 'content', 'articles']) - for insight in insights: - article_tags.add(insight['tag']) - insight['articles'] = [article_id] - old_insight_dict = {i['content']: i for i in old_insights if i['tag'] == insight['tag']} - - # the result wanted is whether the extracted information phrases are talking about the same thing, - # it may not be suitable and too heavy to calculate the similarity with a vector model - # Therefore, a simplified solution is used here, directly using jieba to calculate whether the overlap between the two phrases exceeds. - similar_insights = compare_phrase_with_list(insight['content'], list(old_insight_dict.keys()), 0.65) - if similar_insights: - to_rewrite = similar_insights + [insight['content']] - new_info_content = info_rewrite(to_rewrite) - if not new_info_content: - continue - insight['content'] = new_info_content - # Merge related articles and delete old insights - for old_insight in similar_insights: - insight['articles'].extend(old_insight_dict[old_insight]['articles']) - if not pb.delete(collection_name='insights', id=old_insight_dict[old_insight]['id']): - logger.error('delete insight failed') - old_insights.remove(old_insight_dict[old_insight]) - - insight['id'] = pb.add(collection_name='insights', body=insight) - if not insight['id']: - logger.error('add insight failed, writing to cache_file') - with open(os.path.join(project_dir, 'cache_insights.json'), 'a', encoding='utf-8') as f: - json.dump(insight, f, ensure_ascii=False, indent=4) - - _ = pb.update(collection_name='articles', id=article_id, body={'tag': list(article_tags)}) - if not _: - logger.error(f'update article failed - article_id: {article_id}') - result['tag'] = list(article_tags) - with open(os.path.join(project_dir, 'cache_articles.json'), 'a', encoding='utf-8') as f: - json.dump(result, f, ensure_ascii=False, indent=4) - - -async def message_manager(_input: dict): - source = _input['user_id'] - logger.debug(f"received new task, user: {source}, Addition info: {_input['addition']}") - if _input['type'] == 'publicMsg': - items = item_pattern.findall(_input["content"]) - # Iterate through all < item > content, extracting < url > and < summary > - for item in items: - url_match = url_pattern.search(item) - url = url_match.group(1) if url_match else None - if not url: - logger.warning(f"can not find url in \n{item}") - continue - # URL processing, http is replaced by https, and the part after chksm is removed. - url = url.replace('http://', 'https://') - cut_off_point = url.find('chksm=') - if cut_off_point != -1: - url = url[:cut_off_point-1] - if url in existing_urls: - logger.debug(f"{url} has been crawled, skip") - continue - summary_match = summary_pattern.search(item) - summary = summary_match.group(1) if summary_match else None - cache = {'source': source, 'abstract': summary} - await pipeline(url, cache) - - elif _input['type'] == 'text': - urls = extract_urls(_input['content']) - if not urls: - logger.debug(f"can not find any url in\n{_input['content']}\npass...") - # todo get info from text process - return - await asyncio.gather(*[pipeline(url) for url in urls if url not in existing_urls]) - - elif _input['type'] == 'url': - # this is remained for wechat shared mp_article_card - item = re.search(r'(.*?)&chksm=', _input["content"], re.DOTALL) - if not item: - logger.debug("shareUrlOpen not find") - item = re.search(r'(.*?)&chksm=', _input["content"], re.DOTALL) - if not item: - logger.debug("shareUrlOriginal not find") - item = re.search(r'(.*?)&chksm=', _input["content"], re.DOTALL) - if not item: - logger.warning(f"cannot find url in \n{_input['content']}") - return - extract_url = item.group(1).replace('amp;', '') - summary_match = re.search(r'(.*?)', _input["content"], re.DOTALL) - summary = summary_match.group(1) if summary_match else None - cache = {'source': source, 'abstract': summary} - await pipeline(extract_url, cache) - else: - return diff --git a/core/insights/get_info.py b/core/insights/get_info.py deleted file mode 100644 index e70b3aa..0000000 --- a/core/insights/get_info.py +++ /dev/null @@ -1,151 +0,0 @@ -from llms.openai_wrapper import openai_llm -# from llms.siliconflow_wrapper import sfa_llm -import re -from utils.general_utils import get_logger_level, is_chinese -from loguru import logger -from utils.pb_api import PbTalker -import os - - -get_info_model = os.environ.get("GET_INFO_MODEL", "gpt-4o-mini-2024-07-18") -rewrite_model = os.environ.get("REWRITE_MODEL", "gpt-4o-mini-2024-07-18") - -project_dir = os.environ.get("PROJECT_DIR", "") -if project_dir: - os.makedirs(project_dir, exist_ok=True) -logger_file = os.path.join(project_dir, 'wiseflow.log') -dsw_log = get_logger_level() -logger.add( - logger_file, - level=dsw_log, - backtrace=True, - diagnose=True, - rotation="50 MB" -) - -pb = PbTalker(logger) - -focus_data = pb.read(collection_name='tags', filter=f'activated=True') -if not focus_data: - logger.error('no activated tag found, please set at least one') - exit(1) - -focus_list = [item["name"] for item in focus_data if item["name"]] -focus_dict = {item["name"]: item["id"] for item in focus_data if item["name"]} -lang_term = ''.join([f'{item["name"]}{item["explaination"]}' for item in focus_data if item["name"]]) -focus_statement = '\n'.join([f'{item["name"]}{item["explaination"]}' for item in focus_data if item["name"] and item["explaination"]]) - -if is_chinese(lang_term): - if focus_statement: - system_prompt = f'''请仔细阅读用户输入的新闻内容,并根据所提供的类型标签列表进行分析。类型标签列表如下: -{focus_list} - -各标签的含义如下: -{focus_statement} - -如果新闻中包含上述任何类型的信息,请使用以下格式标记信息的类型标签,并提供仅包含时间、地点、人物和事件的一句话信息摘要: -类型名称仅包含时间、地点、人物和事件的一句话信息摘要 - -务必注意:1、严格忠于新闻原文,不得提供原文中不包含的信息;2、对于同一事件,仅选择一个最贴合的标签,不要重复输出;3、如果新闻中包含多个信息,请逐一分析并按一条一行的格式输出,如果新闻不涉及任何类型的信息,则直接输出:无。''' - else: - system_prompt = f'''请仔细阅读用户输入的新闻内容,并根据所提供的类型标签列表进行分析。类型标签列表如下: -{focus_list} - -如果新闻中包含上述任何类型的信息,请使用以下格式标记信息的类型标签,并提供仅包含时间、地点、人物和事件的一句话信息摘要: -类型名称仅包含时间、地点、人物和事件的一句话信息摘要 - -务必注意:1、严格忠于新闻原文,不得提供原文中不包含的信息;2、对于同一事件,仅选择一个最贴合的标签,不要重复输出;3、如果新闻中包含多个信息,请逐一分析并按一条一行的格式输出,如果新闻不涉及任何类型的信息,则直接输出:无。''' - - rewrite_prompt = '''请综合给到的内容,提炼总结为一个新闻摘要。给到的内容会用XML标签分隔。请仅输出总结出的摘要,不要输出其他的信息。''' - -else: - if focus_statement: - system_prompt = f'''Please carefully read the news content provided by the user and analyze it according to the list of type labels given below: -{focus_list} - -The meanings of each label are as follows: -{focus_statement} - -If the news contains any information of the aforementioned types, please mark the type label of the information using the following format and provide a one-sentence summary containing only the time, location, people involved, and event: -TypeLabelA one-sentence summary containing only the time, location, people involved, and event - -Please be sure to: 1. Strictly adhere to the original text and do not provide information not contained in the original; 2. For the same event, choose only one most appropriate label and do not repeat the output; 3. If the news contains multiple pieces of information, analyze them one by one and output them in a one-line-per-item format. If the news does not involve any of the types of information, simply output: None.''' - else: - system_prompt = f'''Please carefully read the news content provided by the user and analyze it according to the list of type labels given below: -{focus_list} - -If the news contains any information of the aforementioned types, please mark the type label of the information using the following format and provide a one-sentence summary containing only the time, location, people involved, and event: -TypeLabelA one-sentence summary containing only the time, location, people involved, and event - -Please be sure to: 1. Strictly adhere to the original text and do not provide information not contained in the original; 2. For the same event, choose only one most appropriate label and do not repeat the output; 3. If the news contains multiple pieces of information, analyze them one by one and output them in a one-line-per-item format. If the news does not involve any of the types of information, simply output: None.''' - - rewrite_prompt = "Please synthesize the content provided, which will be segmented by XML tags, into a news summary. Output only the summarized abstract without including any additional information." - - -def get_info(article_content: str) -> list[dict]: - # logger.debug(f'receive new article_content:\n{article_content}') - result = openai_llm([{'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': article_content}], - model=get_info_model, logger=logger, temperature=0.1) - - # results = pattern.findall(result) - texts = result.split('') - texts = [_.strip() for _ in texts if '' in _.strip()] - if not texts: - logger.debug(f'can not find info, llm result:\n{result}') - return [] - - cache = [] - for text in texts: - try: - strings = text.split('') - tag = strings[0] - tag = tag.strip() - if tag not in focus_list: - logger.info(f'tag not in focus_list: {tag}, aborting') - continue - info = strings[1] - info = info.split('\n\n') - info = info[0].strip() - except Exception as e: - logger.info(f'parse error: {e}') - tag = '' - info = '' - - if not info or not tag: - logger.info(f'parse failed-{text}') - continue - - if len(info) < 7: - logger.info(f'info too short, possible invalid: {info}') - continue - - if info.startswith('无相关信息') or info.startswith('该新闻未提及') or info.startswith('未提及'): - logger.info(f'no relevant info: {text}') - continue - - while info.endswith('"'): - info = info[:-1] - info = info.strip() - - # 拼接下来源信息 - sources = re.findall(r'\[from (.*?)]', article_content) - if sources and sources[0]: - info = f"[from {sources[0]}] {info}" - - cache.append({'content': info, 'tag': focus_dict[tag]}) - - return cache - - -def info_rewrite(contents: list[str]) -> str: - context = f"{''.join(contents)}" - try: - result = openai_llm([{'role': 'system', 'content': rewrite_prompt}, {'role': 'user', 'content': context}], - model=rewrite_model, temperature=0.1, logger=logger) - return result.strip() - except Exception as e: - if logger: - logger.warning(f'rewrite process llm generate failed: {e}') - else: - print(f'rewrite process llm generate failed: {e}') - return '' diff --git a/core/llms/openai_wrapper.py b/core/llms/openai_wrapper.py index ceb7a4e..0457d28 100644 --- a/core/llms/openai_wrapper.py +++ b/core/llms/openai_wrapper.py @@ -1,7 +1,7 @@ import os from openai import OpenAI from openai import RateLimitError -import time +import asyncio base_url = os.environ.get('LLM_API_BASE', "") @@ -10,34 +10,36 @@ token = os.environ.get('LLM_API_KEY', "") if not base_url and not token: raise ValueError("LLM_API_BASE or LLM_API_KEY must be set") elif base_url and not token: - client = OpenAI(base_url=base_url) + client = OpenAI(base_url=base_url, api_key="not_use") elif not base_url and token: client = OpenAI(api_key=token) else: client = OpenAI(api_key=token, base_url=base_url) +llm_lock = asyncio.Lock() -def openai_llm(messages: list, model: str, logger=None, **kwargs) -> str: +async def openai_llm(messages: list, model: str, logger=None, **kwargs) -> str: if logger: logger.debug(f'messages:\n {messages}') logger.debug(f'model: {model}') logger.debug(f'kwargs:\n {kwargs}') - try: - response = client.chat.completions.create(messages=messages, model=model, **kwargs) - except RateLimitError as e: - logger.warning(f'{e}\nRetrying in 60 second...') - time.sleep(60) - response = client.chat.completions.create(messages=messages, model=model, **kwargs) - if response and response.choices: - return response.choices[0].message.content - else: - logger.error(f'after many try, llm error: {response}') - return "" - except Exception as e: - if logger: - logger.error(f'openai_llm error: {e}') - return '' + async with llm_lock: + try: + response = client.chat.completions.create(messages=messages, model=model, **kwargs) + except RateLimitError as e: + logger.warning(f'{e}\nRetrying in 60 second...') + await asyncio.sleep(60) + response = client.chat.completions.create(messages=messages, model=model, **kwargs) + if response.status_code == 200 and response.choices: + return response.choices[0].message.content + else: + logger.error(f'after many try, llm error: {response}') + return "" + except Exception as e: + if logger: + logger.error(f'openai_llm error: {e}') + return '' if logger: logger.debug(f'result:\n {response.choices[0]}') diff --git a/core/pb/pb_hooks/main.pb.js b/core/pb/pb_hooks/main.pb.js deleted file mode 100644 index 7f585e8..0000000 --- a/core/pb/pb_hooks/main.pb.js +++ /dev/null @@ -1,74 +0,0 @@ -routerAdd( - "POST", - "/save", - (c) => { - const data = $apis.requestInfo(c).data - // console.log(data) - - let dir = $os.getenv("PROJECT_DIR") - if (dir) { - dir = dir + "/" - } - // console.log(dir) - - const collection = $app.dao().findCollectionByNameOrId("documents") - const record = new Record(collection) - const form = new RecordUpsertForm($app, record) - - // or form.loadRequest(request, "") - form.loadData({ - workflow: data.workflow, - insight: data.insight, - task: data.task, - }) - - // console.log(dir + data.file) - const f1 = $filesystem.fileFromPath(dir + data.file) - form.addFiles("files", f1) - - form.submit() - - return c.json(200, record) - }, - $apis.requireRecordAuth() -) - -routerAdd( - "GET", - "/insight_dates", - (c) => { - let result = arrayOf( - new DynamicModel({ - created: "", - }) - ) - - $app.dao().db().newQuery("SELECT DISTINCT DATE(created) as created FROM insights").all(result) - - return c.json( - 200, - result.map((r) => r.created) - ) - }, - $apis.requireAdminAuth() -) - -routerAdd( - "GET", - "/article_dates", - (c) => { - let result = arrayOf( - new DynamicModel({ - created: "", - }) - ) - - $app.dao().db().newQuery("SELECT DISTINCT DATE(created) as created FROM articles").all(result) - - return c.json( - 200, - result.map((r) => r.created) - ) - }, - $apis.requireAdminAuth() -) diff --git a/core/pb/pb_migrations/1712449900_created_article_translation.js b/core/pb/pb_migrations/1712449900_created_article_translation.js deleted file mode 100644 index e968bfe..0000000 --- a/core/pb/pb_migrations/1712449900_created_article_translation.js +++ /dev/null @@ -1,55 +0,0 @@ -/// -migrate((db) => { - const collection = new Collection({ - "id": "bc3g5s66bcq1qjp", - "created": "2024-04-07 00:31:40.644Z", - "updated": "2024-04-07 00:31:40.644Z", - "name": "article_translation", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "t2jqr7cs", - "name": "title", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "dr9kt3dn", - "name": "abstract", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - } - ], - "indexes": [], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - }); - - return Dao(db).saveCollection(collection); -}, (db) => { - const dao = new Dao(db); - const collection = dao.findCollectionByNameOrId("bc3g5s66bcq1qjp"); - - return dao.deleteCollection(collection); -}) diff --git a/core/pb/pb_migrations/1712450012_created_articles.js b/core/pb/pb_migrations/1712450012_created_articles.js deleted file mode 100644 index 3a3048b..0000000 --- a/core/pb/pb_migrations/1712450012_created_articles.js +++ /dev/null @@ -1,154 +0,0 @@ -/// -migrate((db) => { - const collection = new Collection({ - "id": "lft7642skuqmry7", - "created": "2024-04-07 00:33:32.746Z", - "updated": "2024-04-07 00:33:32.746Z", - "name": "articles", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "yttga2xi", - "name": "title", - "type": "text", - "required": true, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "99dnnabt", - "name": "url", - "type": "url", - "required": true, - "presentable": false, - "unique": false, - "options": { - "exceptDomains": [], - "onlyDomains": [] - } - }, - { - "system": false, - "id": "itplfdwh", - "name": "abstract", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "iorna912", - "name": "content", - "type": "text", - "required": true, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "judmyhfm", - "name": "publish_time", - "type": "number", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "noDecimal": false - } - }, - { - "system": false, - "id": "um6thjt5", - "name": "author", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "kvzodbm3", - "name": "images", - "type": "json", - "required": false, - "presentable": false, - "unique": false, - "options": { - "maxSize": 2000000 - } - }, - { - "system": false, - "id": "eviha2ho", - "name": "snapshot", - "type": "file", - "required": false, - "presentable": false, - "unique": false, - "options": { - "mimeTypes": [], - "thumbs": [], - "maxSelect": 1, - "maxSize": 5242880, - "protected": false - } - }, - { - "system": false, - "id": "tukuros5", - "name": "translation_result", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "bc3g5s66bcq1qjp", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": 1, - "displayFields": null - } - } - ], - "indexes": [], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - }); - - return Dao(db).saveCollection(collection); -}, (db) => { - const dao = new Dao(db); - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7"); - - return dao.deleteCollection(collection); -}) diff --git a/core/pb/pb_migrations/1712450207_updated_article_translation.js b/core/pb/pb_migrations/1712450207_updated_article_translation.js deleted file mode 100644 index 09c03b7..0000000 --- a/core/pb/pb_migrations/1712450207_updated_article_translation.js +++ /dev/null @@ -1,52 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("bc3g5s66bcq1qjp") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "tmwf6icx", - "name": "raw", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "lft7642skuqmry7", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": 1, - "displayFields": null - } - })) - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "hsckiykq", - "name": "content", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("bc3g5s66bcq1qjp") - - // remove - collection.schema.removeField("tmwf6icx") - - // remove - collection.schema.removeField("hsckiykq") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1712450442_created_insights.js b/core/pb/pb_migrations/1712450442_created_insights.js deleted file mode 100644 index 0ddac56..0000000 --- a/core/pb/pb_migrations/1712450442_created_insights.js +++ /dev/null @@ -1,73 +0,0 @@ -/// -migrate((db) => { - const collection = new Collection({ - "id": "h3c6pqhnrfo4oyf", - "created": "2024-04-07 00:40:42.781Z", - "updated": "2024-04-07 00:40:42.781Z", - "name": "insights", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "5hp4ulnc", - "name": "content", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "gsozubhx", - "name": "articles", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "lft7642skuqmry7", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": null, - "displayFields": null - } - }, - { - "system": false, - "id": "iiwkyzr2", - "name": "docx", - "type": "file", - "required": false, - "presentable": false, - "unique": false, - "options": { - "mimeTypes": [], - "thumbs": [], - "maxSelect": 1, - "maxSize": 5242880, - "protected": false - } - } - ], - "indexes": [], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - }); - - return Dao(db).saveCollection(collection); -}, (db) => { - const dao = new Dao(db); - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf"); - - return dao.deleteCollection(collection); -}) diff --git a/core/pb/pb_migrations/1713322324_created_sites.js b/core/pb/pb_migrations/1713322324_created_sites.js deleted file mode 100644 index 2672a1b..0000000 --- a/core/pb/pb_migrations/1713322324_created_sites.js +++ /dev/null @@ -1,54 +0,0 @@ -/// -migrate((db) => { - const collection = new Collection({ - "id": "sma08jpi5rkoxnh", - "created": "2024-04-17 02:52:04.291Z", - "updated": "2024-04-17 02:52:04.291Z", - "name": "sites", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "6qo4l7og", - "name": "url", - "type": "url", - "required": false, - "presentable": false, - "unique": false, - "options": { - "exceptDomains": null, - "onlyDomains": null - } - }, - { - "system": false, - "id": "lgr1quwi", - "name": "per_hours", - "type": "number", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": 1, - "max": 24, - "noDecimal": false - } - } - ], - "indexes": [], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - }); - - return Dao(db).saveCollection(collection); -}, (db) => { - const dao = new Dao(db); - const collection = dao.findCollectionByNameOrId("sma08jpi5rkoxnh"); - - return dao.deleteCollection(collection); -}) diff --git a/core/pb/pb_migrations/1713328405_updated_sites.js b/core/pb/pb_migrations/1713328405_updated_sites.js deleted file mode 100644 index f1f8417..0000000 --- a/core/pb/pb_migrations/1713328405_updated_sites.js +++ /dev/null @@ -1,74 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("sma08jpi5rkoxnh") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "6qo4l7og", - "name": "url", - "type": "url", - "required": true, - "presentable": false, - "unique": false, - "options": { - "exceptDomains": null, - "onlyDomains": null - } - })) - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "lgr1quwi", - "name": "per_hours", - "type": "number", - "required": true, - "presentable": false, - "unique": false, - "options": { - "min": 1, - "max": 24, - "noDecimal": false - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("sma08jpi5rkoxnh") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "6qo4l7og", - "name": "url", - "type": "url", - "required": false, - "presentable": false, - "unique": false, - "options": { - "exceptDomains": null, - "onlyDomains": null - } - })) - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "lgr1quwi", - "name": "per_hours", - "type": "number", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": 1, - "max": 24, - "noDecimal": false - } - })) - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1713329959_updated_sites.js b/core/pb/pb_migrations/1713329959_updated_sites.js deleted file mode 100644 index a49e806..0000000 --- a/core/pb/pb_migrations/1713329959_updated_sites.js +++ /dev/null @@ -1,27 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("sma08jpi5rkoxnh") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "8x8n2a47", - "name": "activated", - "type": "bool", - "required": false, - "presentable": false, - "unique": false, - "options": {} - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("sma08jpi5rkoxnh") - - // remove - collection.schema.removeField("8x8n2a47") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1714803585_updated_articles.js b/core/pb/pb_migrations/1714803585_updated_articles.js deleted file mode 100644 index 453e21f..0000000 --- a/core/pb/pb_migrations/1714803585_updated_articles.js +++ /dev/null @@ -1,44 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "iorna912", - "name": "content", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "iorna912", - "name": "content", - "type": "text", - "required": true, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1714835361_updated_insights.js b/core/pb/pb_migrations/1714835361_updated_insights.js deleted file mode 100644 index eb29b5b..0000000 --- a/core/pb/pb_migrations/1714835361_updated_insights.js +++ /dev/null @@ -1,31 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "d13734ez", - "name": "tag", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - // remove - collection.schema.removeField("d13734ez") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1714955881_updated_articles.js b/core/pb/pb_migrations/1714955881_updated_articles.js deleted file mode 100644 index 1989cb4..0000000 --- a/core/pb/pb_migrations/1714955881_updated_articles.js +++ /dev/null @@ -1,31 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "pwy2iz0b", - "name": "source", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - // remove - collection.schema.removeField("pwy2iz0b") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715823361_created_tags.js b/core/pb/pb_migrations/1715823361_created_tags.js deleted file mode 100644 index d252a58..0000000 --- a/core/pb/pb_migrations/1715823361_created_tags.js +++ /dev/null @@ -1,51 +0,0 @@ -/// -migrate((db) => { - const collection = new Collection({ - "id": "nvf6k0yoiclmytu", - "created": "2024-05-16 01:36:01.108Z", - "updated": "2024-05-16 01:36:01.108Z", - "name": "tags", - "type": "base", - "system": false, - "schema": [ - { - "system": false, - "id": "0th8uax4", - "name": "name", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - }, - { - "system": false, - "id": "l6mm7m90", - "name": "activated", - "type": "bool", - "required": false, - "presentable": false, - "unique": false, - "options": {} - } - ], - "indexes": [], - "listRule": null, - "viewRule": null, - "createRule": null, - "updateRule": null, - "deleteRule": null, - "options": {} - }); - - return Dao(db).saveCollection(collection); -}, (db) => { - const dao = new Dao(db); - const collection = dao.findCollectionByNameOrId("nvf6k0yoiclmytu"); - - return dao.deleteCollection(collection); -}) diff --git a/core/pb/pb_migrations/1715824265_updated_insights.js b/core/pb/pb_migrations/1715824265_updated_insights.js deleted file mode 100644 index dd7d152..0000000 --- a/core/pb/pb_migrations/1715824265_updated_insights.js +++ /dev/null @@ -1,52 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - // remove - collection.schema.removeField("d13734ez") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "j65p3jji", - "name": "tag", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "nvf6k0yoiclmytu", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": null, - "displayFields": null - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "d13734ez", - "name": "tag", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - // remove - collection.schema.removeField("j65p3jji") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715852342_updated_insights.js b/core/pb/pb_migrations/1715852342_updated_insights.js deleted file mode 100644 index 6a6f8c2..0000000 --- a/core/pb/pb_migrations/1715852342_updated_insights.js +++ /dev/null @@ -1,16 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - collection.listRule = "@request.auth.id != \"\" && @request.auth.tag:each ?~ tag:each" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - collection.listRule = null - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715852638_updated_insights.js b/core/pb/pb_migrations/1715852638_updated_insights.js deleted file mode 100644 index 42efa86..0000000 --- a/core/pb/pb_migrations/1715852638_updated_insights.js +++ /dev/null @@ -1,16 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - collection.viewRule = "@request.auth.id != \"\" && @request.auth.tag:each ?~ tag:each" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - collection.viewRule = null - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715852847_updated_users.js b/core/pb/pb_migrations/1715852847_updated_users.js deleted file mode 100644 index bfe64a3..0000000 --- a/core/pb/pb_migrations/1715852847_updated_users.js +++ /dev/null @@ -1,33 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("_pb_users_auth_") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "8d9woe75", - "name": "tag", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "nvf6k0yoiclmytu", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": null, - "displayFields": null - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("_pb_users_auth_") - - // remove - collection.schema.removeField("8d9woe75") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715852924_updated_articles.js b/core/pb/pb_migrations/1715852924_updated_articles.js deleted file mode 100644 index ff0501c..0000000 --- a/core/pb/pb_migrations/1715852924_updated_articles.js +++ /dev/null @@ -1,33 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "famdh2fv", - "name": "tag", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "nvf6k0yoiclmytu", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": null, - "displayFields": null - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - // remove - collection.schema.removeField("famdh2fv") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715852932_updated_articles.js b/core/pb/pb_migrations/1715852932_updated_articles.js deleted file mode 100644 index 29b0cca..0000000 --- a/core/pb/pb_migrations/1715852932_updated_articles.js +++ /dev/null @@ -1,18 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - collection.listRule = "@request.auth.id != \"\" && @request.auth.tag:each ?~ tag:each" - collection.viewRule = "@request.auth.id != \"\" && @request.auth.tag:each ?~ tag:each" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("lft7642skuqmry7") - - collection.listRule = null - collection.viewRule = null - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715852952_updated_article_translation.js b/core/pb/pb_migrations/1715852952_updated_article_translation.js deleted file mode 100644 index f960931..0000000 --- a/core/pb/pb_migrations/1715852952_updated_article_translation.js +++ /dev/null @@ -1,33 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("bc3g5s66bcq1qjp") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "lbxw5pra", - "name": "tag", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "nvf6k0yoiclmytu", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": null, - "displayFields": null - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("bc3g5s66bcq1qjp") - - // remove - collection.schema.removeField("lbxw5pra") - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1715852974_updated_article_translation.js b/core/pb/pb_migrations/1715852974_updated_article_translation.js deleted file mode 100644 index b597bea..0000000 --- a/core/pb/pb_migrations/1715852974_updated_article_translation.js +++ /dev/null @@ -1,18 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("bc3g5s66bcq1qjp") - - collection.listRule = "@request.auth.id != \"\" && @request.auth.tag:each ?~ tag:each" - collection.viewRule = "@request.auth.id != \"\" && @request.auth.tag:each ?~ tag:each" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("bc3g5s66bcq1qjp") - - collection.listRule = null - collection.viewRule = null - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1716165809_updated_tags.js b/core/pb/pb_migrations/1716165809_updated_tags.js deleted file mode 100644 index 7a9baf6..0000000 --- a/core/pb/pb_migrations/1716165809_updated_tags.js +++ /dev/null @@ -1,44 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("nvf6k0yoiclmytu") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "0th8uax4", - "name": "name", - "type": "text", - "required": true, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("nvf6k0yoiclmytu") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "0th8uax4", - "name": "name", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1716168332_updated_insights.js b/core/pb/pb_migrations/1716168332_updated_insights.js deleted file mode 100644 index aa03a18..0000000 --- a/core/pb/pb_migrations/1716168332_updated_insights.js +++ /dev/null @@ -1,48 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "j65p3jji", - "name": "tag", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "nvf6k0yoiclmytu", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": 1, - "displayFields": null - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("h3c6pqhnrfo4oyf") - - // update - collection.schema.addField(new SchemaField({ - "system": false, - "id": "j65p3jji", - "name": "tag", - "type": "relation", - "required": false, - "presentable": false, - "unique": false, - "options": { - "collectionId": "nvf6k0yoiclmytu", - "cascadeDelete": false, - "minSelect": null, - "maxSelect": null, - "displayFields": null - } - })) - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1717321896_updated_tags.js b/core/pb/pb_migrations/1717321896_updated_tags.js deleted file mode 100644 index 9ddbbf8..0000000 --- a/core/pb/pb_migrations/1717321896_updated_tags.js +++ /dev/null @@ -1,18 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("nvf6k0yoiclmytu") - - collection.listRule = "@request.auth.id != \"\"" - collection.viewRule = "@request.auth.id != \"\"" - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("nvf6k0yoiclmytu") - - collection.listRule = null - collection.viewRule = null - - return dao.saveCollection(collection) -}) diff --git a/core/pb/pb_migrations/1725263585_updated_tags.js b/core/pb/pb_migrations/1725263585_updated_tags.js deleted file mode 100644 index fb293e2..0000000 --- a/core/pb/pb_migrations/1725263585_updated_tags.js +++ /dev/null @@ -1,31 +0,0 @@ -/// -migrate((db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("nvf6k0yoiclmytu") - - // add - collection.schema.addField(new SchemaField({ - "system": false, - "id": "vkgtujiz", - "name": "explaination", - "type": "text", - "required": false, - "presentable": false, - "unique": false, - "options": { - "min": null, - "max": null, - "pattern": "" - } - })) - - return dao.saveCollection(collection) -}, (db) => { - const dao = new Dao(db) - const collection = dao.findCollectionByNameOrId("nvf6k0yoiclmytu") - - // remove - collection.schema.removeField("vkgtujiz") - - return dao.saveCollection(collection) -}) diff --git a/core/scrapers/README.md b/core/scrapers/README.md deleted file mode 100644 index 3e04db0..0000000 --- a/core/scrapers/README.md +++ /dev/null @@ -1,56 +0,0 @@ -We provide a general page parser that can intelligently retrieve article lists from sources. For each article URL, it first attempts to use `gne` for parsing, and if that fails, it will try using `llm`. - -This solution allows scanning and extracting information from most general news and portal sources. - -**However, we strongly recommend that users develop custom parsers for specific sources tailored to their actual business scenarios for more ideal and efficient scanning.** - -We also provide a parser specifically for WeChat public articles (mp.weixin.qq.com). - -**If you are willing to contribute your custom source-specific parsers to this repository, we would greatly appreciate it!** - -## Custom Source Parser Development Specifications - -### Specifications - -**Remember It should be an asynchronous function** - -1. **The parser should be able to intelligently distinguish between article list pages and article detail pages.** -2. **The parser's input parameters should only include `url` and `logger`:** - - `url` is the complete address of the source (type `str`). - - `logger` is the logging object (please do not configure a separate logger for your custom source parser). -3. **The parser's output should include `flag` and `result`, formatted as `tuple[int, Union[set, dict]]`:** - - If the `url` is an article list page, `flag` returns `1`, and `result` returns a tuple of all article page URLs (`set`). - - If the `url` is an article page, `flag` returns `11`, and `result` returns all article details (`dict`), in the following format: - - ```python - {'url': str, 'title': str, 'author': str, 'publish_time': str, 'content': str, 'abstract': str, 'images': [str]} - ``` - - _Note: `title` and `content` cannot be empty._ - - **Note: `publish_time` should be in the format `"%Y%m%d"` (date only, no `-`). If the scraper cannot fetch it, use the current date.** - - - If parsing fails, `flag` returns `0`, and `result` returns an empty dictionary `{}`. - - _`pipeline` will try other parsing solutions (if any) upon receiving `flag` 0._ - - - If page retrieval fails (e.g., network issues), `flag` returns `-7`, and `result` returns an empty dictionary `{}`. - - _`pipeline` will not attempt to parse again in the same process upon receiving `flag` -7._ - -### Registration - -After writing your scraper, place the scraper program in this folder and register the scraper in `scraper_map` under `__init__.py`, similar to: - -```python -{'domain': 'crawler def name'} -``` - -It is recommended to use urllib.parse to get the domain: - -```python -from urllib.parse import urlparse - -parsed_url = urlparse("site's url") -domain = parsed_url.netloc -``` \ No newline at end of file diff --git a/core/scrapers/README_CN.md b/core/scrapers/README_CN.md deleted file mode 100644 index 3e39510..0000000 --- a/core/scrapers/README_CN.md +++ /dev/null @@ -1,56 +0,0 @@ -我们提供了一个通用页面解析器,该解析器可以智能获取信源文章列表。对于每个文章 URL,会先尝试使用 `gne` 进行解析,如果失败,再尝试使用 `llm` 进行解析。 - -通过这个方案,可以实现对大多数普通新闻类、门户类信源的扫描和信息提取。 - -**然而,我们依然强烈建议用户根据实际业务场景编写针对特定信源的专有解析器,以实现更理想且高效的扫描。** - -此外,我们提供了一个专门针对微信公众号文章(mp.weixin.qq.com)的解析器。 - -**如果您愿意将您撰写的特定信源专有解析器贡献至本代码仓库,我们将不胜感激!** - -## 专有信源解析器开发规范 - -### 规范 - -**记住:这应该是一个异步函数** - -1. **解析器应能智能区分文章列表页面和文章详情页面。** -2. **解析器入参只包括 `url` 和 `logger` 两项:** - - `url` 是信源完整地址(`str` 类型) - - `logger` 是日志对象(请勿为您的专有信源解析器单独配置 `logger`) -3. **解析器出参包括 `flag` 和 `result` 两项,格式为 `tuple[int, Union[set, dict]]`:** - - 如果 `url` 是文章列表页面,`flag` 返回 `1`,`result` 返回解析出的全部文章页面 URL 集合(`set`)。 - - 如果 `url` 是文章页面,`flag` 返回 `11`,`result` 返回解析出的全部文章详情(`dict`),格式如下: - - ```python - {'url': str, 'title': str, 'author': str, 'publish_time': str, 'content': str, 'abstract': str, 'images': [str]} - ``` - - _注意:`title` 和 `content` 两项不能为空。_ - - **注意:`publish_time` 格式为 `"%Y%m%d"`(仅日期,没有 `-`),如果爬虫抓不到可以用当天日期。** - - - 如果解析失败,`flag` 返回 `0`,`result` 返回空字典 `{}`。 - - _`pipeline` 收到 `flag` 0 会尝试其他解析方案(如有)。_ - - - 如果页面获取失败(如网络问题),`flag` 返回 `-7`,`result` 返回空字典 `{}`。 - - _`pipeline` 收到 `flag` -7, 同一进程内不会再次尝试解析。_ - -### 注册 - -写好爬虫后,将爬虫程序放在该文件夹,并在 `__init__.py` 下的 `scraper_map` 中注册爬虫,类似: - -```python -{'domain': 'crawler def name'} -``` - -建议使用 urllib.parse 获取 domain: - -```python -from urllib.parse import urlparse - -parsed_url = urlparse("site's url") -domain = parsed_url.netloc -``` \ No newline at end of file diff --git a/core/scrapers/README_de.md b/core/scrapers/README_de.md deleted file mode 100644 index 4200859..0000000 --- a/core/scrapers/README_de.md +++ /dev/null @@ -1,56 +0,0 @@ -Wir bieten einen allgemeinen Seitenparser an, der intelligent Artikellisten von Quellen abrufen kann. Für jede Artikel-URL wird zuerst versucht, `gne` zur Analyse zu verwenden. Falls dies fehlschlägt, wird `llm` als Alternative genutzt. - -Diese Lösung ermöglicht das Scannen und Extrahieren von Informationen aus den meisten allgemeinen Nachrichtenquellen und Portalen. - -**Wir empfehlen jedoch dringend, benutzerdefinierte Parser für spezifische Quellen zu entwickeln, die auf Ihre tatsächlichen Geschäftsszenarien abgestimmt sind, um eine idealere und effizientere Erfassung zu erreichen.** - -Wir stellen auch einen speziellen Parser für WeChat-Artikel (mp.weixin.qq.com) bereit. - -**Falls Sie bereit sind, Ihre speziell entwickelten Parser für bestimmte Quellen zu diesem Code-Repository beizutragen, wären wir Ihnen sehr dankbar!** - -## Entwicklungsspezifikationen für benutzerdefinierte Quellparser - -### Spezifikationen - -**Denken Sie daran: Es sollte eine asynchrone Funktion sein** - -1. **Der Parser sollte in der Lage sein, intelligent zwischen Artikel-Listen-Seiten und Artikel-Detailseiten zu unterscheiden.** -2. **Die Eingabeparameter des Parsers sollten nur `url` und `logger` umfassen:** - - `url` ist die vollständige Adresse der Quelle (Typ `str`). - - `logger` ist das Protokollierungsobjekt (bitte konfigurieren Sie keinen separaten Logger für Ihren benutzerdefinierten Quellparser). -3. **Die Ausgabe des Parsers sollte `flag` und `result` umfassen, im Format `tuple[int, Union[set, dict]]`:** - - Wenn die `url` eine Artikellisten-Seite ist, gibt `flag` `1` zurück, und `result` gibt eine satz aller Artikel-URLs (`set`) zurück. - - Wenn die `url` eine Artikelseite ist, gibt `flag` `11` zurück, und `result` gibt alle Artikeldetails (`dict`) zurück, im folgenden Format: - - ```python - {'url': str, 'title': str, 'author': str, 'publish_time': str, 'content': str, 'abstract': str, 'images': [str]} - ``` - - _Hinweis: `title` und `content` dürfen nicht leer sein._ - - **Hinweis: Das `publish_time`-Format muss `"%Y%m%d"` (nur Datum, ohne `-`) sein. Wenn der Scraper es nicht erfassen kann, verwenden Sie das aktuelle Datum.** - - - Wenn die Analyse fehlschlägt, gibt `flag` `0` zurück, und `result` gibt ein leeres Wörterbuch `{}` zurück. - - _Der `pipeline` versucht andere Analysemethoden (falls vorhanden), wenn `flag` 0 zurückgegeben wird._ - - - Wenn das Abrufen der Seite fehlschlägt (z. B. aufgrund von Netzwerkproblemen), gibt `flag` `-7` zurück, und `result` gibt ein leeres Wörterbuch `{}` zurück. - - _Der `pipeline` wird im gleichen Prozess keine weiteren Versuche zur Analyse unternehmen, wenn `flag` -7 zurückgegeben wird._ - -### Registrierung - -Nach dem Schreiben Ihres Scrapers platzieren Sie das Scraper-Programm in diesem Ordner und registrieren den Scraper in `scraper_map` in `__init__.py`, wie folgt: - -```python -{'domain': 'Crawler-Funktionsname'} -``` - -Es wird empfohlen, urllib.parse zur Ermittlung der domain zu verwenden: - -```python -from urllib.parse import urlparse - -parsed_url = urlparse("l'URL du site") -domain = parsed_url.netloc -``` \ No newline at end of file diff --git a/core/scrapers/README_fr.md b/core/scrapers/README_fr.md deleted file mode 100644 index d96583f..0000000 --- a/core/scrapers/README_fr.md +++ /dev/null @@ -1,56 +0,0 @@ -Nous proposons un analyseur de pages général capable de récupérer intelligemment les listes d'articles de sources d'information. Pour chaque URL d'article, il tente d'abord d'utiliser `gne` pour l'analyse, et en cas d'échec, il essaie d'utiliser `llm`. - -Cette solution permet de scanner et d'extraire des informations de la plupart des sources de nouvelles générales et des portails d'information. - -**Cependant, nous recommandons vivement aux utilisateurs de développer des analyseurs personnalisés pour des sources spécifiques en fonction de leurs scénarios d'affaires réels afin d'obtenir une analyse plus idéale et plus efficace.** - -Nous fournissons également un analyseur spécialement conçu pour les articles publics WeChat (mp.weixin.qq.com). - -**Si vous êtes disposé à contribuer vos analyseurs spécifiques à certaines sources à ce dépôt de code, nous vous en serions très reconnaissants !** - -## Spécifications pour le Développement d'Analyseurs Spécifiques - -### Spécifications - -**N'oubliez pas : il devrait s'agir d'une fonction asynchrone** - -1. **L'analyseur doit être capable de distinguer intelligemment entre les pages de liste d'articles et les pages de détail des articles.** -2. **Les paramètres d'entrée de l'analyseur doivent uniquement inclure `url` et `logger` :** - - `url` est l'adresse complète de la source (type `str`). - - `logger` est l'objet de journalisation (ne configurez pas de logger séparé pour votre analyseur spécifique). -3. **Les paramètres de sortie de l'analyseur doivent inclure `flag` et `result`, formatés comme `tuple[int, Union[set, dict]]` :** - - Si l'URL est une page de liste d'articles, `flag` renvoie `1` et `result` renvoie la set de toutes les URL des pages d'articles (`set`). - - Si l'URL est une page d'article, `flag` renvoie `11` et `result` renvoie tous les détails de l'article (`dict`), au format suivant : - - ```python - {'url': str, 'title': str, 'author': str, 'publish_time': str, 'content': str, 'abstract': str, 'images': [str]} - ``` - - _Remarque : `title` et `content` ne peuvent pas être vides._ - - **Remarque : `publish_time` doit être au format `"%Y%m%d"` (date uniquement, sans `-`). Si le scraper ne peut pas le récupérer, utilisez la date du jour.** - - - En cas d'échec de l'analyse, `flag` renvoie `0` et `result` renvoie un dictionnaire vide `{}`. - - _Le `pipeline` essaiera d'autres solutions d'analyse (si disponibles) après avoir reçu `flag` 0._ - - - En cas d'échec de la récupération de la page (par exemple, problème réseau), `flag` renvoie `-7` et `result` renvoie un dictionnaire vide `{}`. - - _Le `pipeline` n'essaiera pas de réanalyser dans le même processus après avoir reçu `flag` -7._ - -### Enregistrement - -Après avoir écrit votre scraper, placez le programme du scraper dans ce dossier et enregistrez le scraper dans `scraper_map` sous `__init__.py`, de manière similaire : - -```python -{'domain': 'nom de la fonction de crawler'} -``` - -Il est recommandé d'utiliser urllib.parse pour obtenir le domain : - -```python -from urllib.parse import urlparse - -parsed_url = urlparse("l'URL du site") -domain = parsed_url.netloc -``` \ No newline at end of file diff --git a/core/scrapers/README_jp.md b/core/scrapers/README_jp.md deleted file mode 100644 index d5c6bc0..0000000 --- a/core/scrapers/README_jp.md +++ /dev/null @@ -1,56 +0,0 @@ -汎用ページパーサーを提供しており、このパーサーは信頼できるソースから記事リストをインテリジェントに取得します。各記事URLに対して、まず `gne` を使用して解析を試み、失敗した場合は `llm` を使用して解析します。 - -このソリューションにより、ほとんどの一般的なニュースサイトやポータルサイトからの情報をスキャンして抽出することができます。 - -**しかし、より理想的かつ効率的なスキャンを実現するために、ユーザー自身のビジネスシナリオに応じた特定のソース専用のパーサーを開発することを強くお勧めします。** - -また、WeChat 公共アカウントの記事(mp.weixin.qq.com)に特化したパーサーも提供しています。 - -**特定のソース専用に開発したパーサーをこのリポジトリに貢献していただける場合は、大変感謝いたします!** - -## 特定ソースパーサー開発規範 - -### 規範 - -**覚えておいてください:それは非同期関数でなければなりません** - -1. **パーサーは、記事リストページと記事詳細ページをインテリジェントに区別できる必要があります。** -2. **パーサーの入力パラメーターは `url` と `logger` のみを含むべきです:** - - `url` はソースの完全なアドレス(`str` タイプ) - - `logger` はロギングオブジェクト(専用のロガーを構成しないでください) -3. **パーサーの出力は `flag` と `result` を含み、形式は `tuple[int, Union[set, dict]]`:** - - `url` が記事リストページの場合、`flag` は `1` を返し、`result` はすべての記事ページURLのコレクション(`set`)を返します。 - - `url` が記事ページの場合、`flag` は `11` を返し、`result` はすべての記事詳細(`dict`)を返します。形式は以下の通りです: - - ```python - {'url': str, 'title': str, 'author': str, 'publish_time': str, 'content': str, 'abstract': str, 'images': [str]} - ``` - - _注意:`title` と `content` は空であってはなりません。_ - - **注意:`publish_time` の形式は `"%Y%m%d"`(日付のみ、`-` はなし)である必要があります。スクレイパーが取得できない場合は、当日の日付を使用してください。** - - - 解析に失敗した場合、`flag` は `0` を返し、`result` は空の辞書 `{}` を返します。 - - _`pipeline` は `flag` 0 を受け取ると他の解析ソリューション(存在する場合)を試みます。_ - - - ページの取得に失敗した場合(例えば、ネットワークの問題)、`flag` は `-7` を返し、`result` は空の辞書 `{}` を返します。 - - _`pipeline` は `flag` -7 を受け取ると、同一プロセス内では再解析を試みません。_ - -### 登録 - -スクレイパーを作成したら、このフォルダにプログラムを配置し、`__init__.py` の `scraper_map` にスクレイパーを次のように登録してください: - -```python -{'domain': 'スクレイパー関数名'} -``` - -domain の取得には urllib.parse を使用することをお勧めします: - -```python -from urllib.parse import urlparse - -parsed_url = urlparse("l'URL du site") -domain = parsed_url.netloc -``` \ No newline at end of file diff --git a/core/scrapers/__init__.py b/core/scrapers/__init__.py deleted file mode 100644 index 8e7a776..0000000 --- a/core/scrapers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .mp_crawler import mp_crawler - - -scraper_map = {'mp.weixin.qq.com': mp_crawler} diff --git a/core/scrapers/general_crawler.py b/core/scrapers/general_crawler.py deleted file mode 100644 index 46766e8..0000000 --- a/core/scrapers/general_crawler.py +++ /dev/null @@ -1,228 +0,0 @@ -# -*- coding: utf-8 -*- -# when you use this general crawler, remember followings -# When you receive flag -7, it means that the problem occurs in the HTML fetch process. -# When you receive flag 0, it means that the problem occurred during the content parsing process. -# when you receive flag 1, the result would be a tuple, means that the input url is possible a article_list page -# and the set contains the url of the articles. -# when you receive flag 11, you will get the dict contains the title, content, url, date, and the source of the article. - -from gne import GeneralNewsExtractor -import httpx -from bs4 import BeautifulSoup -from datetime import datetime -from urllib.parse import urlparse -from llms.openai_wrapper import openai_llm -# from llms.siliconflow_wrapper import sfa_llm -from bs4.element import Comment -from utils.general_utils import extract_and_convert_dates -import asyncio -import json_repair -import os -from typing import Union -from requests.compat import urljoin -from scrapers import scraper_map - - -model = os.environ.get('HTML_PARSE_MODEL', 'gpt-4o-mini-2024-07-18') -header = { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/604.1 Edg/112.0.100.0'} -extractor = GeneralNewsExtractor() - - -def tag_visible(element: Comment) -> bool: - if element.parent.name in ["style", "script", "head", "title", "meta", "[document]"]: - return False - if isinstance(element, Comment): - return False - return True - - -def text_from_soup(soup: BeautifulSoup) -> str: - res = [] - texts = soup.find_all(string=True) - visible_texts = filter(tag_visible, texts) - for v in visible_texts: - res.append(v) - text = "\n".join(res) - return text.strip() - - -sys_info = '''Your task is to operate as an HTML content extractor, focusing on parsing a provided HTML segment. Your objective is to retrieve the following details directly from the raw text within the HTML, without summarizing or altering the content: - -- The document's title -- The complete main content, as it appears in the HTML, comprising all textual elements considered part of the core article body -- The publication time in its original format found within the HTML - -Ensure your response fits the following JSON structure, accurately reflecting the extracted data without modification: - -```json -{ - "title": "The Document's Exact Title", - "content": "All the unaltered primary text content from the article", - "publish_time": "Original Publication Time as per HTML" -} -``` - -It is essential that your output adheres strictly to this format, with each field filled based on the untouched information extracted directly from the HTML source.''' - - -async def general_crawler(url: str, logger) -> tuple[int, Union[set, dict]]: - """ - Return article information dict and flag, negative number is error, 0 is no result, 1 is for article_list page, - 11 is success - - main work flow: - (for weixin public account articles, which startswith mp.weixin.qq use mp_crawler) - first get the content with httpx - then judge is article list (return all article url and flag 1) or article detail page - then try to use gne to extract the information - when fail, try to use a llm to analysis the html - """ - - # 0. if there's a scraper for this domain, use it (such as mp.weixin.qq.com) - parsed_url = urlparse(url) - domain = parsed_url.netloc - base_url = f"{parsed_url.scheme}://{domain}" - if domain in scraper_map: - return await scraper_map[domain](url, logger) - - # 1. get the content with httpx - async with httpx.AsyncClient() as client: - for retry in range(2): - try: - response = await client.get(url, headers=header, timeout=30) - response.raise_for_status() - break - except Exception as e: - if retry < 1: - logger.info(f"can not reach\n{e}\nwaiting 1min") - await asyncio.sleep(60) - else: - logger.error(e) - return -7, {} - - # 2. judge is article list (return all article url and flag 1) or article detail page - page_source = response.text - if page_source: - text = page_source - else: - try: - text = response.content.decode('utf-8') - except UnicodeDecodeError: - try: - text = response.content.decode('gbk') - except Exception as e: - logger.error(f"can not decode html {e}") - return -7, {} - - soup = BeautifulSoup(text, "html.parser") - # Note: The scheme used here is very crude, - # it is recommended to write a separate parser for specific business scenarios - # Parse all URLs - if len(url) < 50: - urls = set() - for link in soup.find_all("a", href=True): - absolute_url = urljoin(base_url, link["href"]) - format_url = urlparse(absolute_url) - # only record same domain links - if not format_url.netloc or format_url.netloc != domain: - continue - # remove hash fragment - absolute_url = f"{format_url.scheme}://{format_url.netloc}{format_url.path}{format_url.params}{format_url.query}" - if absolute_url != url: - urls.add(absolute_url) - - if len(urls) > 24: - logger.info(f"{url} is more like an article list page, find {len(urls)} urls with the same netloc") - return 1, urls - - # 3. try to use gne to extract the information - try: - result = extractor.extract(text) - if 'meta' in result: - del result['meta'] - - if result['title'].startswith('服务器错误') or result['title'].startswith('您访问的页面') or result[ - 'title'].startswith('403') \ - or result['content'].startswith('This website uses cookies') or result['title'].startswith('出错了'): - logger.warning(f"can not get {url} from the Internet") - return -7, {} - - if len(result['title']) < 4 or len(result['content']) < 24: - logger.info(f"gne extract not good: {result}") - result = None - except Exception as e: - logger.info(f"gne extract error: {e}") - result = None - - # 4. try to use a llm to analysis the html - if not result: - html_text = text_from_soup(soup) - html_lines = html_text.split('\n') - html_lines = [line.strip() for line in html_lines if line.strip()] - html_text = "\n".join(html_lines) - if len(html_text) > 29999: - logger.info(f"{url} content too long for llm parsing") - return 0, {} - - if not html_text or html_text.startswith('服务器错误') or html_text.startswith( - '您访问的页面') or html_text.startswith('403') \ - or html_text.startswith('出错了'): - logger.warning(f"can not get {url} from the Internet") - return -7, {} - - messages = [ - {"role": "system", "content": sys_info}, - {"role": "user", "content": html_text} - ] - llm_output = openai_llm(messages, model=model, logger=logger, temperature=0.01) - result = json_repair.repair_json(llm_output, return_objects=True) - logger.debug(f"decoded_object: {result}") - - if not isinstance(result, dict): - logger.debug("failed to parse from llm output") - return 0, {} - - if 'title' not in result or 'content' not in result: - logger.debug("llm parsed result not good") - return 0, {} - - # Extract the picture link, it will be empty if it cannot be extracted. - image_links = [] - images = soup.find_all("img") - for img in images: - try: - image_links.append(urljoin(base_url, img["src"])) - except KeyError: - continue - result["images"] = image_links - - # Extract the author information, if it cannot be extracted, it will be empty. - author_element = soup.find("meta", {"name": "author"}) - if author_element: - result["author"] = author_element["content"] - else: - result["author"] = "" - - # 5. post process - date_str = extract_and_convert_dates(result.get('publish_time', '')) - if date_str: - result['publish_time'] = date_str - else: - result['publish_time'] = datetime.strftime(datetime.today(), "%Y%m%d") - - from_site = domain.replace('www.', '') - from_site = from_site.split('.')[0] - result['content'] = f"[from {from_site}] {result['content']}" - - try: - meta_description = soup.find("meta", {"name": "description"}) - if meta_description: - result['abstract'] = f"[from {from_site}] {meta_description['content'].strip()}" - else: - result['abstract'] = '' - except Exception: - result['abstract'] = '' - - result['url'] = url - return 11, result diff --git a/core/scrapers/mp_crawler.py b/core/scrapers/mp_crawler.py deleted file mode 100644 index f7d666c..0000000 --- a/core/scrapers/mp_crawler.py +++ /dev/null @@ -1,129 +0,0 @@ -# -*- coding: utf-8 -*- - -from typing import Union -import httpx -from bs4 import BeautifulSoup -from datetime import datetime -import re -import asyncio - - -header = { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/604.1 Edg/112.0.100.0'} - - -async def mp_crawler(url: str, logger) -> tuple[int, Union[set, dict]]: - if not url.startswith('https://mp.weixin.qq.com') and not url.startswith('http://mp.weixin.qq.com'): - logger.warning(f'{url} is not a mp url, you should not use this function') - return -5, {} - - url = url.replace("http://", "https://", 1) - - async with httpx.AsyncClient() as client: - for retry in range(2): - try: - response = await client.get(url, headers=header, timeout=30) - response.raise_for_status() - break - except Exception as e: - if retry < 1: - logger.info(f"{e}\nwaiting 1min") - await asyncio.sleep(60) - else: - logger.warning(e) - return -7, {} - - soup = BeautifulSoup(response.text, 'html.parser') - - if url.startswith('https://mp.weixin.qq.com/mp/appmsgalbum'): - # 文章目录 - urls = {li.attrs['data-link'].replace("http://", "https://", 1) for li in soup.find_all('li', class_='album__list-item')} - simple_urls = set() - for url in urls: - cut_off_point = url.find('chksm=') - if cut_off_point != -1: - url = url[:cut_off_point - 1] - simple_urls.add(url) - return 1, simple_urls - - # Get the original release date first - pattern = r"var createTime = '(\d{4}-\d{2}-\d{2}) \d{2}:\d{2}'" - match = re.search(pattern, response.text) - - if match: - date_only = match.group(1) - publish_time = date_only.replace('-', '') - else: - publish_time = datetime.strftime(datetime.today(), "%Y%m%d") - - # Get description content from < meta > tag - try: - meta_description = soup.find('meta', attrs={'name': 'description'}) - summary = meta_description['content'].strip() if meta_description else '' - # card_info = soup.find('div', id='img-content') - # Parse the required content from the < div > tag - rich_media_title = soup.find('h1', id='activity-name').text.strip() \ - if soup.find('h1', id='activity-name') \ - else soup.find('h1', class_='rich_media_title').text.strip() - profile_nickname = soup.find('div', class_='wx_follow_nickname').text.strip() - except Exception as e: - logger.warning(f"not mp format: {url}\n{e}") - # For mp.weixin.qq.com types, mp_crawler won't work, and most likely neither will the other two - return -7, {} - - if not rich_media_title or not profile_nickname: - logger.warning(f"failed to analysis {url}, no title or profile_nickname") - return -7, {} - - # Parse text and image links within the content interval - # Todo This scheme is compatible with picture sharing MP articles, but the pictures of the content cannot be obtained, - # because the structure of this part is completely different, and a separate analysis scheme needs to be written - # (but the proportion of this type of article is not high). - texts = [] - images = set() - content_area = soup.find('div', id='js_content') - if content_area: - # 提取文本 - for section in content_area.find_all(['section', 'p'], recursive=False): # 遍历顶级section - text = section.get_text(separator=' ', strip=True) - if text and text not in texts: - texts.append(text) - - for img in content_area.find_all('img', class_='rich_pages wxw-img'): - img_src = img.get('data-src') or img.get('src') - if img_src: - images.add(img_src) - cleaned_texts = [t for t in texts if t.strip()] - content = '\n'.join(cleaned_texts) - else: - logger.warning(f"failed to analysis contents {url}") - return 0, {} - if content: - content = f"[from {profile_nickname}]{content}" - else: - # If the content does not have it, but the summary has it, it means that it is an mp of the picture sharing type. - # At this time, you can use the summary as the content. - content = f"[from {profile_nickname}]{summary}" - - # Get links to images in meta property = "og: image" and meta property = "twitter: image" - og_image = soup.find('meta', property='og:image') - twitter_image = soup.find('meta', property='twitter:image') - if og_image: - images.add(og_image['content']) - if twitter_image: - images.add(twitter_image['content']) - - if rich_media_title == summary or not summary: - abstract = '' - else: - abstract = f"[from {profile_nickname}]{rich_media_title}——{summary}" - - return 11, { - 'title': rich_media_title, - 'author': profile_nickname, - 'publish_time': publish_time, - 'abstract': abstract, - 'content': content, - 'images': list(images), - 'url': url, - } diff --git a/core/scripts/start_backend.sh b/core/scripts/start_backend.sh index 9963617..f00cef6 100644 --- a/core/scripts/start_backend.sh +++ b/core/scripts/start_backend.sh @@ -1,5 +1,5 @@ #!/bin/bash set -o allexport -source ../.env +source .env set +o allexport exec uvicorn backend:app --reload --host localhost --port 8077 \ No newline at end of file diff --git a/core/scripts/start_tasks.sh b/core/scripts/start_tasks.sh index 164f3ca..34613d0 100644 --- a/core/scripts/start_tasks.sh +++ b/core/scripts/start_tasks.sh @@ -1,5 +1,5 @@ #!/bin/bash set -o allexport -source ../.env +source .env set +o allexport exec python tasks.py \ No newline at end of file diff --git a/core/tasks.py b/core/tasks.py index f8248db..8ec9c34 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -1,5 +1,5 @@ import asyncio -from insights import pipeline, pb, logger +from agents import pipeline, pb, logger counter = 1 diff --git a/core/utils/general_utils.py b/core/utils/general_utils.py index 4840ed1..903cf4e 100644 --- a/core/utils/general_utils.py +++ b/core/utils/general_utils.py @@ -1,7 +1,8 @@ from urllib.parse import urlparse import os import re -import jieba +# import jieba +from loguru import logger def isURL(string): @@ -72,35 +73,27 @@ def extract_and_convert_dates(input_string): break if matches: return ''.join(matches[0]) - return None + return '' -def get_logger_level() -> str: - level_map = { - 'silly': 'CRITICAL', - 'verbose': 'DEBUG', - 'info': 'INFO', - 'warn': 'WARNING', - 'error': 'ERROR', - } - level: str = os.environ.get('WS_LOG', 'info').lower() - if level not in level_map: - raise ValueError( - 'WiseFlow LOG should support the values of `silly`, ' - '`verbose`, `info`, `warn`, `error`' - ) - return level_map.get(level, 'info') - +def get_logger(logger_name: str, logger_file_path: str): + level = 'DEBUG' if os.environ.get("VERBOSE", "").lower() in ["true", "1"] else 'INFO' + logger_file = os.path.join(logger_file_path, f"{logger_name}.log") + if not os.path.exists(logger_file_path): + os.makedirs(logger_file_path) + logger.add(logger_file, level=level, backtrace=True, diagnose=True, rotation="50 MB") + return logger +""" def compare_phrase_with_list(target_phrase, phrase_list, threshold): - """ + Compare the similarity of a target phrase to each phrase in the phrase list. : Param target_phrase: target phrase (str) : Param phrase_list: list of str : param threshold: similarity threshold (float) : Return: list of phrases that satisfy the similarity condition (list of str) - """ + if not target_phrase: return [] # The target phrase is empty, and the empty list is returned directly. @@ -112,3 +105,4 @@ def compare_phrase_with_list(target_phrase, phrase_list, threshold): if len(target_tokens & tokens) / min(len(target_tokens), len(tokens)) > threshold] return similar_phrases +""" \ No newline at end of file diff --git a/core/utils/pb_api.py b/core/utils/pb_api.py index 0346efe..7a07160 100644 --- a/core/utils/pb_api.py +++ b/core/utils/pb_api.py @@ -29,7 +29,8 @@ class PbTalker: def read(self, collection_name: str, fields: Optional[List[str]] = None, filter: str = '', skiptotal: bool = True) -> list: results = [] - for i in range(1, 10): + i = 1 + while True: try: res = self.client.collection(collection_name).get_list(i, 500, {"filter": filter, @@ -44,6 +45,7 @@ class PbTalker: for _res in res.items: attributes = vars(_res) results.append(attributes) + i += 1 return results def add(self, collection_name: str, body: Dict) -> str: diff --git a/dashboard/README.md b/dashboard/README.md index 644c128..687c586 100644 --- a/dashboard/README.md +++ b/dashboard/README.md @@ -1,71 +1,12 @@ -**Included Web Dashboard Example**: This is optional. If you only use the data processing functions or have your own downstream task program, you can ignore everything in this folder! +**预计在 V0.3.9 版本提供完整的用户侧api,目前这里只是参考** -## Main Features +API 并不直接与 Core 关联,api 也是针对数据存储(包含用户设置存储)进行操作,所以这里并不影响你直接使用 core。 -1.Daily Insights Display -2.Daily Article Display -3.Appending Search for Specific Hot Topics (using Sogou engine) -4.Generating Word Reports for Specific Hot Topics +初始版本 API 预计包含: -**Note: The code here cannot be used directly. It is adapted to an older version of the backend. You need to study the latest backend code in the `core` folder and make changes, especially in parts related to database integration!** - ------------------------------------------------------------------ - -附带的web Dashboard 示例,并非必须,如果你只是使用数据处理功能,或者你有自己的下游任务程序,可以忽略这个文件夹内的一切! - -## 主要功能 - -1. 每日insights展示 -2. 每日文章展示 -3. 指定热点追加搜索(使用sougou引擎) -4. 指定热点生成word报告 - -**注意:这里的代码并不能直接使用,它适配的是旧版本的后端程序,你需要研究core文件夹下的最新后端代码,进行更改,尤其是跟数据库对接的部分!** - ------------------------------------------------------------------ - -**付属のWebダッシュボードのサンプル**:これは必須ではありません。データ処理機能のみを使用する場合、または独自の下流タスクプログラムを持っている場合は、このフォルダ内のすべてを無視できます! - -## 主な機能 - -1. 毎日のインサイト表示 - -2. 毎日の記事表示 - -3. 特定のホットトピックの追加検索(Sogouエンジンを使用) - -4. 特定のホットトピックのWordレポートの生成 - -**注意:ここにあるコードは直接使用できません。古いバージョンのバックエンドに適合しています。`core`フォルダ内の最新のバックエンドコードを調べ、特にデータベースとの連携部分について変更を行う必要があります!** - ------------------------------------------------------------------ - -**Exemple de tableau de bord Web inclus** : Ceci est facultatif. Si vous n'utilisez que les fonctions de traitement des données ou si vous avez votre propre programme de tâches en aval, vous pouvez ignorer tout ce qui se trouve dans ce dossier ! - -## Fonctions principales - -1. Affichage des insights quotidiens - -2. Affichage des articles quotidiens - -3. Recherche supplémentaire pour des sujets populaires spécifiques (en utilisant le moteur Sogou) - -4. Génération de rapports Word pour des sujets populaires spécifiques - -**Remarque : Le code ici ne peut pas être utilisé directement. Il est adapté à une version plus ancienne du backend. Vous devez étudier le code backend le plus récent dans le dossier `core` et apporter des modifications, en particulier dans les parties relatives à l'intégration de la base de données !** - ------------------------------------------------------------------ - -**Beispiel eines enthaltenen Web-Dashboards**: Dies ist optional. Wenn Sie nur die Datenverarbeitungsfunktionen verwenden oder Ihr eigenes Downstream-Aufgabenprogramm haben, können Sie alles in diesem Ordner ignorieren! - -## Hauptfunktionen - -1. Tägliche Einblicke anzeigen - -2. Tägliche Artikel anzeigen - -3. Angehängte Suche nach spezifischen Hot Topics (unter Verwendung der Sogou-Suchmaschine) - -4. Erstellen von Word-Berichten für spezifische Hot Topics - -**Hinweis: Der Code hier kann nicht direkt verwendet werden. Er ist an eine ältere Version des Backends angepasst. Sie müssen den neuesten Backend-Code im `core`-Ordner studieren und Änderungen vornehmen, insbesondere in den Teilen, die die Datenbankintegration betreffen!** +- 信源的增删改查; +- 兴趣点的增删改查; +- insights 的读取和查找; +- 文章的读取和查找; +- 简单的报告生成功能; +- 原始资料的翻译等。 \ No newline at end of file diff --git a/dashboard/__init__.py b/dashboard/__init__.py index ced14f9..059593d 100644 --- a/dashboard/__init__.py +++ b/dashboard/__init__.py @@ -22,7 +22,7 @@ class BackendService: def report(self, insight_id: str, topics: list[str], comment: str) -> dict: logger.debug(f'got new report request insight_id {insight_id}') - insight = pb.read('insights', filter=f'id="{insight_id}"') + insight = pb.read('agents', filter=f'id="{insight_id}"') if not insight: logger.error(f'insight {insight_id} not found') return self.build_out(-2, 'insight not found') @@ -52,7 +52,7 @@ class BackendService: if flag: file = open(docx_file, 'rb') - message = pb.upload('insights', insight_id, 'docx', f'{insight_id}.docx', file) + message = pb.upload('agents', insight_id, 'docx', f'{insight_id}.docx', file) file.close() if message: logger.debug(f'report success finish and update to: {message}') @@ -143,7 +143,7 @@ class BackendService: def more_search(self, insight_id: str) -> dict: logger.debug(f'got search request for insight: {insight_id}') - insight = pb.read('insights', filter=f'id="{insight_id}"') + insight = pb.read('agents', filter=f'id="{insight_id}"') if not insight: logger.error(f'insight {insight_id} not found') return self.build_out(-2, 'insight not found') @@ -169,7 +169,7 @@ class BackendService: with open(os.path.join(self.cache_url, 'cache_articles.json'), 'a', encoding='utf-8') as f: json.dump(item, f, ensure_ascii=False, indent=4) - message = pb.update(collection_name='insights', id=insight_id, body={'articles': article_ids}) + message = pb.update(collection_name='agents', id=insight_id, body={'articles': article_ids}) if message: logger.debug(f'insight search success finish and update to: {message}') return self.build_out(11, insight_id) From f18d9ba084e9de278d9019cbf3d673ca9e66b0ab Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Thu, 5 Dec 2024 20:45:39 +0800 Subject: [PATCH 2/9] first commit for V0.3.22 --- core/custom_process/README.md | 30 ++++ core/custom_process/__init__.py | 4 + core/custom_process/mp_process.py | 109 ++++++++++++ core/general_process.py | 155 ++++++++++++++++++ .../1733204939_created_articles.js | 121 ++++++++++++++ .../1733234529_created_focus_points.js | 94 +++++++++++ .../1733234644_updated_focus_points.js | 42 +++++ core/run_all.sh | 24 +++ dashboard/backend.py | 48 ++++++ general_crawler_test.py | 13 ++ 10 files changed, 640 insertions(+) create mode 100644 core/custom_process/README.md create mode 100644 core/custom_process/__init__.py create mode 100644 core/custom_process/mp_process.py create mode 100644 core/general_process.py create mode 100644 core/pb/pb_migrations/1733204939_created_articles.js create mode 100644 core/pb/pb_migrations/1733234529_created_focus_points.js create mode 100644 core/pb/pb_migrations/1733234644_updated_focus_points.js create mode 100755 core/run_all.sh create mode 100644 dashboard/backend.py create mode 100644 general_crawler_test.py diff --git a/core/custom_process/README.md b/core/custom_process/README.md new file mode 100644 index 0000000..c5952ca --- /dev/null +++ b/core/custom_process/README.md @@ -0,0 +1,30 @@ +wiseflow 致力于通过一套通用流程(使用视觉大模型驱动的可以自主使用爬虫工具的智能体)处理所有页面。 + +不过我们也为客户保留自定义处理的灵活性。 + +为添加自定义处理逻辑单元请遵照如下规范: + +1、逻辑处理单元应该是一个函数(而不是类); + +2、入参只接受两个:url(要处理的 url,请只提供一个 url,而不是列表,因为主函数会处理队列逻辑) 和 logger 对象(这意味着不要为你的自定义处理单元添加日志对象); + +3、出参需要返回解析后的文章详情(dict),和信息列表(list),以及解析出来的需要添加到工作队列的 url 结合(元组)。出参必须同时返回这三个结果,没有的话,可以分别传出 {} [] set() + +article 的字典必须包括 'url'(str), 'title'(str), 'author'(str), 'publish_date'(date 日期对象,注意是日期)四个键值,额外可以添加一个 'sceenshort' 值是一个 png 文件的路径。 + +4、在 core/custom_crawlers/__init__.py 中注册,参考: + +```pyhton +from .mp_crawler import mp_crawler + +customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} +``` + +注意键使用域名,可以使用 urllib.parse获取: + +```pyhton +from urllib.parse import urlparse + +parsed_url = urlparse("site's url") +domain = parsed_url.netloc +``` \ No newline at end of file diff --git a/core/custom_process/__init__.py b/core/custom_process/__init__.py new file mode 100644 index 0000000..48289f3 --- /dev/null +++ b/core/custom_process/__init__.py @@ -0,0 +1,4 @@ +from .mp_process import mp_crawler + +customer_crawler_map = {} +# customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} diff --git a/core/custom_process/mp_process.py b/core/custom_process/mp_process.py new file mode 100644 index 0000000..e31085b --- /dev/null +++ b/core/custom_process/mp_process.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +# warining: the mp_crawler will be deprecated in future version, we try to use general_process handle mp articles + +from core.agents import get_info +import httpx +from bs4 import BeautifulSoup +from datetime import datetime, date +import re +import asyncio + + +header = { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/604.1 Edg/112.0.100.0'} + + +async def mp_crawler(url: str, logger) -> tuple[dict, list, set]: + if not url.startswith('https://mp.weixin.qq.com') and not url.startswith('http://mp.weixin.qq.com'): + logger.warning(f'{url} is not a mp url, you should not use this function') + return {}, [], set() + + url = url.replace("http://", "https://", 1) + + async with httpx.AsyncClient() as client: + for retry in range(2): + try: + response = await client.get(url, headers=header, timeout=30) + response.raise_for_status() + break + except Exception as e: + if retry < 1: + logger.info(f"{e}\nwaiting 1min") + await asyncio.sleep(60) + else: + logger.warning(e) + return {}, [], set() + + soup = BeautifulSoup(response.text, 'html.parser') + + if url.startswith('https://mp.weixin.qq.com/mp/appmsgalbum'): + # 文章目录 + urls = {li.attrs['data-link'].replace("http://", "https://", 1) for li in soup.find_all('li', class_='album__list-item')} + simple_urls = set() + for url in urls: + cut_off_point = url.find('chksm=') + if cut_off_point != -1: + url = url[:cut_off_point - 1] + simple_urls.add(url) + return {}, [], simple_urls + + # Get the original release date first + pattern = r"var createTime = '(\d{4}-\d{2}-\d{2}) \d{2}:\d{2}'" + match = re.search(pattern, response.text) + + if match: + date_only = match.group(1) + publish_time = datetime.strptime(date_only, "%Y-%m-%d") + else: + publish_time = date.today() + + # Get description content from < meta > tag + try: + meta_description = soup.find('meta', attrs={'name': 'description'}) + summary = meta_description['content'].strip() if meta_description else '' + # card_info = soup.find('div', id='img-content') + # Parse the required content from the < div > tag + rich_media_title = soup.find('h1', id='activity-name').text.strip() \ + if soup.find('h1', id='activity-name') \ + else soup.find('h1', class_='rich_media_title').text.strip() + profile_nickname = soup.find('div', class_='wx_follow_nickname').text.strip() + except Exception as e: + logger.warning(f"not mp format: {url}\n{e}") + # For mp.weixin.qq.com types, mp_crawler won't work, and most likely neither will the other two + return {}, [], set() + + if not rich_media_title or not profile_nickname: + logger.warning(f"failed to analysis {url}, no title or profile_nickname") + return {}, [], set() + + # Parse text and image links within the content interval + # Todo This scheme is compatible with picture sharing MP articles, but the pictures of the content cannot be obtained, + # because the structure of this part is completely different, and a separate analysis scheme needs to be written + # (but the proportion of this type of article is not high). + texts = [] + content_area = soup.find('div', id='js_content') + if content_area: + # 提取文本 + for section in content_area.find_all(['section', 'p'], recursive=False): # 遍历顶级section + text = section.get_text(separator=' ', strip=True) + if text and text not in texts: + texts.append(text) + cleaned_texts = [t for t in texts if t.strip()] + content = '\n'.join(cleaned_texts) + else: + logger.warning(f"failed to analysis contents {url}") + return {}, [], set() + if content: + content = f"[from {profile_nickname}]{content}" + else: + # If the content does not have it, but the summary has it, it means that it is an mp of the picture sharing type. + # At this time, you can use the summary as the content. + content = f"[from {profile_nickname}]{summary}" + + infos = get_info(content, logger) + article = {'url': url, + 'title': rich_media_title, + 'author': profile_nickname, + 'publish_date': publish_time} + + return article, infos, set() diff --git a/core/general_process.py b/core/general_process.py new file mode 100644 index 0000000..c1b7a54 --- /dev/null +++ b/core/general_process.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +from utils.pb_api import PbTalker +from utils.general_utils import get_logger +from agents.get_info import GeneralInfoExtractor +from bs4 import BeautifulSoup +import os +import json +import asyncio +from custom_process import customer_crawler_map +from urllib.parse import urlparse, urljoin +import hashlib +from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext + + +project_dir = os.environ.get("PROJECT_DIR", "") +if project_dir: + os.makedirs(project_dir, exist_ok=True) +os.environ['CRAWLEE_STORAGE_DIR'] = os.path.join(project_dir, 'crawlee_storage') +screenshot_dir = os.path.join(project_dir, 'crawlee_storage', 'screenshots') + +wiseflow_logger = get_logger('general_process', f'{project_dir}/general_process.log') +pb = PbTalker(wiseflow_logger) +ie = GeneralInfoExtractor(pb, wiseflow_logger) + +# Global variables +working_list = set() +existing_urls = {url['url'] for url in pb.read(collection_name='articles', fields=['url']) if url['url']} +lock = asyncio.Lock() + +async def save_to_pb(article: dict, infos: list): + # saving to pb process + screenshot = article.pop('screenshot') if 'screenshot' in article else None + article_id = pb.add(collection_name='articles', body=article) + if not article_id: + wiseflow_logger.error('add article failed, writing to cache_file') + with open(os.path.join(project_dir, 'cache_articles.json'), 'a', encoding='utf-8') as f: + json.dump(article, f, ensure_ascii=False, indent=4) + return + if screenshot: + file = open(screenshot, 'rb') + file_name = os.path.basename(screenshot) + message = pb.upload('articles', article_id, 'screenshot', file_name, file) + file.close() + if not message: + wiseflow_logger.warning(f'{article_id} upload screenshot failed, file location: {screenshot}') + + for info in infos: + info['articles'] = [article_id] + _ = pb.add(collection_name='agents', body=info) + if not _: + wiseflow_logger.error('add insight failed, writing to cache_file') + with open(os.path.join(project_dir, 'cache_insights.json'), 'a', encoding='utf-8') as f: + json.dump(info, f, ensure_ascii=False, indent=4) + + +async def pipeline(url: str): + global working_list, existing_urls + working_list.add(url) + crawler = PlaywrightCrawler( + # Limit the crawl to max requests. Remove or increase it for crawling all links. + max_requests_per_crawl=100, + ) + # Define the default request handler, which will be called for every request. + @crawler.router.default_handler + async def request_handler(context: PlaywrightCrawlingContext) -> None: + context.log.info(f'Processing {context.request.url} ...') + # Handle dialogs (alerts, confirms, prompts) + async def handle_dialog(dialog): + context.log.info(f'Closing dialog: {dialog.message}') + await dialog.accept() + + context.page.on('dialog', handle_dialog) + + # Extract data from the page. + # future work: try to use a visual-llm do all the job... + text = await context.page.inner_text('body') + wiseflow_logger.debug(f"got text: {text}") + + html = await context.page.inner_html('body') + soup = BeautifulSoup(html, 'html.parser') + links = soup.find_all('a', href=True) + base_url = context.request.url + link_dict = {} + for a in links: + new_url = a.get('href') + text = a.text.strip() + if new_url and text: + absolute_url = urljoin(base_url, new_url) + link_dict[text] = absolute_url + wiseflow_logger.debug(f'found {len(link_dict)} more links') + + screenshot_file_name = f"{hashlib.sha256(context.request.url.encode()).hexdigest()}.png" + await context.page.screenshot(path=os.path.join(screenshot_dir, screenshot_file_name), full_page=True) + wiseflow_logger.debug(f'screenshot saved to {screenshot_file_name}') + + # get infos by llm + infos, author, publish_date, related_urls = await ie(text, link_dict, base_url, wiseflow_logger) + if infos: + # get author and publish date by llm + wiseflow_logger.debug(f'LLM result -- author: {author}, publish_date: {publish_date}') + article = { + 'url': context.request.url, + 'title': await context.page.title(), + 'author': author, + 'publish_date': publish_date, + 'screenshot': os.path.join(screenshot_dir, screenshot_file_name), + 'tags': [info['name'] for info in infos] + } + await save_to_pb(article, infos) + + # find any related urls + related_urls = await get_more_related_urls(html, wiseflow_logger) + wiseflow_logger.debug(f'got {len(related_urls)} more urls') + if related_urls: + async with lock: + new_urls = related_urls - existing_urls + working_list.update(new_urls) + + # todo: use llm to determine next action + + while working_list: + async with lock: + if not working_list: + break + url = working_list.pop() + existing_urls.add(url) + parsed_url = urlparse(url) + domain = parsed_url.netloc + if domain in customer_crawler_map: + wiseflow_logger.debug(f'routed to customer process for {domain}') + try: + article, infos, related_urls = await customer_crawler_map[domain](url, wiseflow_logger) + except Exception as e: + wiseflow_logger.error(f'error occurred in crawling {url}: {e}') + continue + + if infos and article: + wiseflow_logger.debug("receiving new infos from customer crawler, saving to pb") + article['tags'] = [info['name'] for info in infos] + await save_to_pb(article, infos) + if related_urls: + wiseflow_logger.debug('receiving new related_urls from customer crawler, adding to working_list') + new_urls = related_urls - existing_urls + working_list.update(new_urls) + continue + try: + await crawler.run([url]) + except Exception as e: + wiseflow_logger.error(f'error occurred in crawling {url}: {e}') + + +if __name__ == '__main__': + import asyncio + + asyncio.run(pipeline()) diff --git a/core/pb/pb_migrations/1733204939_created_articles.js b/core/pb/pb_migrations/1733204939_created_articles.js new file mode 100644 index 0000000..a2816a1 --- /dev/null +++ b/core/pb/pb_migrations/1733204939_created_articles.js @@ -0,0 +1,121 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "exceptDomains": null, + "hidden": false, + "id": "url4101391790", + "name": "url", + "onlyDomains": null, + "presentable": false, + "required": false, + "system": false, + "type": "url" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text724990059", + "max": 0, + "min": 0, + "name": "title", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text3182418120", + "max": 0, + "min": 0, + "name": "author", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "date2025149370", + "max": "", + "min": "", + "name": "publish_date", + "presentable": false, + "required": false, + "system": false, + "type": "date" + }, + { + "hidden": false, + "id": "file1486429761", + "maxSelect": 1, + "maxSize": 0, + "mimeTypes": [], + "name": "screenshot", + "presentable": false, + "protected": false, + "required": false, + "system": false, + "thumbs": [], + "type": "file" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_4287850865", + "indexes": [], + "listRule": null, + "name": "articles", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_4287850865"); + + return app.delete(collection); +}) diff --git a/core/pb/pb_migrations/1733234529_created_focus_points.js b/core/pb/pb_migrations/1733234529_created_focus_points.js new file mode 100644 index 0000000..eb6b8c2 --- /dev/null +++ b/core/pb/pb_migrations/1733234529_created_focus_points.js @@ -0,0 +1,94 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text2695655862", + "max": 0, + "min": 0, + "name": "focuspoint", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text2284106510", + "max": 0, + "min": 0, + "name": "explanation", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + }, + { + "hidden": false, + "id": "bool806155165", + "name": "activated", + "presentable": false, + "required": false, + "system": false, + "type": "bool" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_3385864241", + "indexes": [], + "listRule": null, + "name": "focus_points", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3385864241"); + + return app.delete(collection); +}) diff --git a/core/pb/pb_migrations/1733234644_updated_focus_points.js b/core/pb/pb_migrations/1733234644_updated_focus_points.js new file mode 100644 index 0000000..1fce9b3 --- /dev/null +++ b/core/pb/pb_migrations/1733234644_updated_focus_points.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3385864241") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text2695655862", + "max": 0, + "min": 0, + "name": "focuspoint", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3385864241") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text2695655862", + "max": 0, + "min": 0, + "name": "focuspoint", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": false, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/core/run_all.sh b/core/run_all.sh new file mode 100755 index 0000000..a90f212 --- /dev/null +++ b/core/run_all.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# 从 .env 文件中加载环境变量 +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) +fi + +# 启动 PocketBase +pb/pocketbase serve --http=0.0.0.0:8090 & +pocketbase_pid=$! + +# 启动 Python 任务 +python tasks.py & +python_pid=$! + +# 启动 Uvicorn +# uvicorn backend:app --reload --host 0.0.0.0 --port 8077 & +# uvicorn_pid=$! + +# 定义信号处理函数 +trap 'kill $pocketbase_pid $python_pid' SIGINT SIGTERM + +# 等待所有进程结束 +wait \ No newline at end of file diff --git a/dashboard/backend.py b/dashboard/backend.py new file mode 100644 index 0000000..8eb3105 --- /dev/null +++ b/dashboard/backend.py @@ -0,0 +1,48 @@ +from fastapi import FastAPI, BackgroundTasks +from pydantic import BaseModel +from typing import Literal, Optional +from fastapi.middleware.cors import CORSMiddleware + + +# backend的操作也应该是针对 pb 操作的,即添加信源、兴趣点等都应该存入 pb,而不是另起一个进程实例 +# 当然也可以放弃 pb,但那是另一个问题,数据和设置的管理应该是一套 +# 简单说用户侧(api dashboard等)和 core侧 不应该直接对接,都应该通过底层的data infrastructure 进行 + +class Request(BaseModel): + """ + Input model + input = {'user_id': str, 'type': str, 'content':str, 'addition': Optional[str]} + Type is one of "text", "publicMsg", "site" and "url"; + """ + user_id: str + type: Literal["text", "publicMsg", "file", "image", "video", "location", "chathistory", "site", "attachment", "url"] + content: str + addition: Optional[str] = None + + +app = FastAPI( + title="WiseFlow Union Backend", + description="From Wiseflow Team.", + version="0.3.1", + openapi_url="/openapi.json" +) + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + +@app.get("/") +def read_root(): + msg = "Hello, this is Wise Union Backend, version 0.3.1" + return {"msg": msg} + + +@app.post("/feed") +async def call_to_feed(background_tasks: BackgroundTasks, request: Request): + background_tasks.add_task(message_manager, _input=request.model_dump()) + return {"msg": "received well"} diff --git a/general_crawler_test.py b/general_crawler_test.py new file mode 100644 index 0000000..b818596 --- /dev/null +++ b/general_crawler_test.py @@ -0,0 +1,13 @@ +from core.custom_process import crawler as general_crawler +from pprint import pprint +import asyncio + +test_list = ['http://society.people.com.cn/n1/2024/1202/c1008-40373268.html'] + +async def crawler_test(): + for test in test_list: + data = await general_crawler.run([test]) + print(type(data)) + +if __name__ == '__main__': + asyncio.run(crawler_test()) From b83ca2369a1f252162be19aa7056805abbb79836 Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Fri, 6 Dec 2024 11:42:22 +0800 Subject: [PATCH 3/9] second commit for V0.3.22 --- CHANGELOG.md | 20 +++ core/agents/get_info.py | 132 +++++++++--------- core/custom_crawlers/README.md | 43 ++++++ core/custom_crawlers/README_EN.md | 45 ++++++ .../__init__.py | 2 +- .../mp_process.py => custom_crawlers/mp.py} | 47 +++---- core/custom_process/README.md | 30 ---- core/general_process.py | 85 +++++++---- core/requirements.txt | 7 +- core/utils/general_utils.py | 4 +- general_crawler_test.py | 13 -- version | 2 +- 12 files changed, 260 insertions(+), 170 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 core/custom_crawlers/README.md create mode 100644 core/custom_crawlers/README_EN.md rename core/{custom_process => custom_crawlers}/__init__.py (70%) rename core/{custom_process/mp_process.py => custom_crawlers/mp.py} (76%) delete mode 100644 core/custom_process/README.md delete mode 100644 general_crawler_test.py diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cdaa1e6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# V0.3.2 +- 引入 Crawlee(playwrigt模块),大幅提升通用爬取能力,适配实际项目场景; + + Introduce Crawlee (playwright module), significantly enhancing general crawling capabilities and adapting to practical project scenarios; + +- 完全重写了信息提取模块,引入“爬-查一体”策略,你关注的才是你想要的; + + Completely rewrote the information extraction module, introducing an "integrated crawl-search" strategy, focusing on what you care about; + +- 新策略下放弃了 gne、jieba 等模块,去除了安装包; + + Under the new strategy, modules such as gne and jieba have been abandoned, reducing the installation package size; + +- 重写了 pocketbase 的表单结构; + + Rewrote the PocketBase form structure; + +- 进一步简化部署操作步骤。 + + Further simplified deployment steps. diff --git a/core/agents/get_info.py b/core/agents/get_info.py index b1279d4..366543d 100644 --- a/core/agents/get_info.py +++ b/core/agents/get_info.py @@ -1,11 +1,10 @@ from core.llms.openai_wrapper import openai_llm as llm # from core.llms.siliconflow_wrapper import sfa_llm -import re from core.utils.general_utils import is_chinese, extract_and_convert_dates, extract_urls from loguru import logger from core.utils.pb_api import PbTalker import os -from datetime import datetime, date +from datetime import datetime from urllib.parse import urlparse import json_repair @@ -27,7 +26,7 @@ class GeneralInfoExtractor: focus_data.append({"name": focus, "explaination": explanation, "id": pb.add('focus_points', {"focuspoint": focus, "explanation": explanation})}) - self.focus_list = [item["focuspoint"] for item in focus_data] + # self.focus_list = [item["focuspoint"] for item in focus_data] self.focus_dict = {item["focuspoint"]: item["id"] for item in focus_data} focus_statement = '' for item in focus_data: @@ -80,6 +79,8 @@ If the webpage text does not contain any information related to points of intere self.get_more_link_suffix = "Please analyze the above text: URL pairs. First, output your analysis basis, and then give the conclusion on whether to select it. If you decide to select this item, then copy and output the URL of this item following the conclusion; otherwise, proceed directly to the analysis of the next item. Analyze one by one, do not miss any one." async def get_author_and_publish_date(self, text: str) -> tuple[str, str]: + if not text: + return "NA", "NA" system_prompt = "As an information extraction assistant, your task is to accurately extract the source (or author) and publication date from the given webpage text. It is important to adhere to extracting the information directly from the original text. If the original text does not contain a particular piece of information, please replace it with NA" suffix = '''Please output the extracted information in the following JSON format: {"source": source or article author (use "NA" if this information cannot be extracted), "publish_date": extracted publication date (keep only the year, month, and day; use "NA" if this information cannot be extracted)}''' @@ -94,13 +95,13 @@ If the webpage text does not contain any information related to points of intere result = json_repair.repair_json(llm_output, return_objects=True) self.logger.debug(f"decoded_object: {result}") if not isinstance(result, dict): - self.logger.debug("failed to parse from llm output") + self.logger.warning("failed to parse from llm output") return '', '' if 'source' not in result or 'publish_date' not in result: - self.logger.debug("failed to parse from llm output") + self.logger.warning("failed to parse from llm output") return '', '' - return result['source'], result['publish_date'] + return result['source'], extract_and_convert_dates(result['publish_date']) async def get_more_related_urls(self, link_dict: dict) -> set[str]: if not link_dict: @@ -116,80 +117,79 @@ If the webpage text does not contain any information related to points of intere raw_urls = list(link_dict.values()) for url in urls: if url not in raw_urls: - self.logger.debug(f"{url} not in link_dict, it's model's Hallucination") + self.logger.warning(f"{url} not in link_dict, it's model's Hallucination") urls.remove(url) return urls - async def get_info(self, text: str, domain: str) -> list[dict]: - # logger.debug(f'receive new article_content:\n{article_content}') + async def get_info(self, text: str, info_pre_fix: str) -> list[dict]: + if not text: + return [] content = f'\n{text}\n\n\n{self.get_info_suffix}' result = await llm([{'role': 'system', 'content': self.get_info_prompt}, {'role': 'user', 'content': content}], model=self.model, temperature=0.1, response_format={"type": "json_object"}) + self.logger.debug(f'get_info llm output:\n{result}') + if not result: + return [] + result = json_repair.repair_json(result, return_objects=True) + if not isinstance(result, list): + self.logger.warning("failed to parse from llm output") + return [] + if not result: + self.logger.info("no info found") + return [] + system = '''判断给定的信息是否与网页文本相符。信息将用标签包裹,网页文本则用包裹。请遵循如下工作流程: +1、尝试找出网页文本中所有与信息对应的文本片段(可能有多处); +2、基于这些片段给出是否相符的最终结论,最终结论仅为“是”或“否”''' + suffix = '先输出找到的所有文本片段,再输出最终结论(仅为是或否)' - - - - - - - - - - -domain = urlparse(url).netloc - -def get_info(article_content: str) -> list[dict]: - # logger.debug(f'receive new article_content:\n{article_content}') - result = openai_llm([{'role': 'system', 'content': system_prompt}, {'role': 'user', 'content': article_content}], - model=get_info_model, logger=logger, temperature=0.1) - - # results = pattern.findall(result) - texts = result.split('') - texts = [_.strip() for _ in texts if '' in _.strip()] - if not texts: - logger.debug(f'can not find info, llm result:\n{result}') - return [] - - cache = [] - for text in texts: - try: - strings = text.split('') - tag = strings[0] - tag = tag.strip() - if tag not in focus_list: - logger.info(f'tag not in focus_list: {tag}, aborting') + final = [] + for item in result: + if 'focus' not in item or 'content' not in item: + self.logger.warning(f"not quality item: {item}, it's model's Hallucination") + continue + if item['focus'] not in self.focus_dict: + self.logger.warning(f"{item['focus']} not in focus_list, it's model's Hallucination") + continue + judge = await llm([{'role': 'system', 'content': system}, + {'role': 'user', 'content': f'\n{item["content"]}\n\n\n\n{text}\n\n\n{suffix}'}], + model=self.secondary_model, temperature=0.1) + self.logger.debug(f'judge llm output:\n{judge}') + if not judge: + self.logger.warning("failed to parse from llm output, skip checking") + final.append({'tag': self.focus_dict[item['focus']], 'content': f"{info_pre_fix}{item['content']}"}) continue - info = strings[1] - info = info.split('\n\n') - info = info[0].strip() - except Exception as e: - logger.info(f'parse error: {e}') - tag = '' - info = '' - if not info or not tag: - logger.info(f'parse failed-{text}') - continue + to_save = False + for i in range(min(7, len(judge))): + char = judge[-1 - i] + if char == '是': + to_save = True + break + elif char == '否': + break + if not to_save: + self.logger.info(f"secondary model judge {item} not faithful to article text, aborting") + continue + final.append({'tag': self.focus_dict[item['focus']], 'content': f"{info_pre_fix}{item['content']}"}) - if len(info) < 7: - logger.info(f'info too short, possible invalid: {info}') - continue + if not final: + self.logger.info("no quality result from llm output") + return final - if info.startswith('无相关信息') or info.startswith('该新闻未提及') or info.startswith('未提及'): - logger.info(f'no relevant info: {text}') - continue + async def __call__(self, text: str, link_dict: dict, base_url: str, author: str = None, publish_date: str = None) -> tuple[list, set, str, str]: + if not author and not publish_date and text: + author, publish_date = await self.get_author_and_publish_date(text) - while info.endswith('"'): - info = info[:-1] - info = info.strip() + if not author or author.lower() == 'na': + author = urlparse(base_url).netloc - # 拼接下来源信息 - sources = re.findall(r'\[from (.*?)]', article_content) - if sources and sources[0]: - info = f"[from {sources[0]}] {info}" + if not publish_date or publish_date.lower() == 'na': + publish_date = datetime.now().strftime('%Y-%m-%d') - cache.append({'content': info, 'tag': focus_dict[tag]}) + related_urls = await self.get_more_related_urls(link_dict) + info_prefix = f"//{author} {publish_date}//" + infos = await self.get_info(text, info_prefix) - return cache + return infos, related_urls, author, publish_date diff --git a/core/custom_crawlers/README.md b/core/custom_crawlers/README.md new file mode 100644 index 0000000..fd7c7a0 --- /dev/null +++ b/core/custom_crawlers/README.md @@ -0,0 +1,43 @@ +wiseflow 致力于通过一套通用流程(使用大模型驱动的可以自主使用爬虫工具的智能体)处理所有页面。 + +不过我们也为客户保留自定义处理的灵活性。您可以在这里添加并注册针对特定域名的自定义爬虫。 + +请遵照如下规范: + +1、爬虫应该是一个函数(而不是类); + +2、入参只接受两个:**url**(要处理的 url,请只提供一个 url,而不是列表,因为主函数会处理队列逻辑) 和 **logger** 对象(这意味着不要为你的自定义爬虫添加日志对象,wiseflow 会统一管理); + +3、出参必须为两个,一个是解析后的文章详情 article,类型为 dict,另一个是从页面解析出的外链字典 link_dict,类型也是 dict。 + +article 的字典格式如下(注意,'content' 是必须的,其他也可以没有,另外额外的键值信息会被忽略): + +`{'url': ..., 'title': ..., 'author': ..., 'publish_date': ..., 'screenshot': ..., 'content': ...(not empty)}` + +上述值的类型都要求为 **str**, 日期格式为 **YYYY-MM-DD**,screenshot 为**文件路径**,可以是相对于 core目录的相对路径也可以是绝对路径,文件类型为 **png**。 + +**注意:** +- 'content' 要有且不为空,不然无法触发后续的提取,文章也会被舍弃。这是唯一要求不为空的项; +- 'author' 和 'publish_date' 尽量有,不然 wiseflow 会自动用域名对应 demain 和 当日日期代替。 + +link_dict 的格式如下: +`{'text': 外链对应的文字信息, 'url': 外链对应的 url}` + +wiseflow 会以这个为输入,使用 llm 判断值得继续爬取的链接。 + +4、在 core/custom_crawlers/__init__.py 中注册,参考: + +```pyhton +from .mp import mp_crawler + +customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} +``` + +注意键使用域名,可以使用 urllib.parse获取: + +```pyhton +from urllib.parse import urlparse + +parsed_url = urlparse("site's url") +domain = parsed_url.netloc +``` \ No newline at end of file diff --git a/core/custom_crawlers/README_EN.md b/core/custom_crawlers/README_EN.md new file mode 100644 index 0000000..8370131 --- /dev/null +++ b/core/custom_crawlers/README_EN.md @@ -0,0 +1,45 @@ +wiseflow is dedicated to processing all pages through a set of general workflows (llm-agent that can autonomously use crawling tools). + +However, we also reserve the flexibility for customers to handle custom processing. You can add and register custom crawlers for specific domains here. + +Please follow the guidelines below: + +1. The crawler should be a function (not a class); + +2. It only accepts two parameters: **url** (the URL to process, please provide only one URL, not a list, as the main function will handle queue logic) and **logger** object (which means you should not add a logging object to your custom crawler, wiseflow will manage it uniformly); + +3. The output must be two items: one is the parsed article details `article`, which is a dict object, and the other is a dictionary of external links `link_dict`, which is also a dict object. + +The format for `article` is as follows (note that 'content' is required and cannot be empty, other fields can be omitted, and any additional key-value information will be ignored): + +`{'url': ..., 'title': ..., 'author': ..., 'publish_date': ..., 'screenshot': ..., 'content': ...(not empty)}` + +All values in the above dictionary should be of type **str**, the date format should be **YYYY-MM-DD**, and the screenshot should be a **file path**, which can be a relative path to the core directory or an absolute path, with the file type being **png**. + +**Note:** +- 'content' must exist and not be empty, otherwise it will not trigger subsequent extraction, and the article will be discarded. This is the only required non-empty item; +- 'author' and 'publish_date' are strongly recommended, otherwise wiseflow will automatically use the domain name corresponding to the domain and the current date as substitutes. + +The format for `link_dict` is as follows: + +`{'text': text information corresponding to the external link, 'url': URL corresponding to the external link}` + +wiseflow will use this as input and use LLM to determine which links are worth further crawling. + +4. Register in `core/custom_crawlers/__init__.py`, refer to: + + +```pyhton +from .mp import mp_crawler + +customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} +``` + +Note that the key should be the domain name, which can be obtained using `urllib.parse`: + +```pyhton +from urllib.parse import urlparse + +parsed_url = urlparse("site's url") +domain = parsed_url.netloc +``` diff --git a/core/custom_process/__init__.py b/core/custom_crawlers/__init__.py similarity index 70% rename from core/custom_process/__init__.py rename to core/custom_crawlers/__init__.py index 48289f3..3e87354 100644 --- a/core/custom_process/__init__.py +++ b/core/custom_crawlers/__init__.py @@ -1,4 +1,4 @@ -from .mp_process import mp_crawler +from .mp import mp_crawler customer_crawler_map = {} # customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} diff --git a/core/custom_process/mp_process.py b/core/custom_crawlers/mp.py similarity index 76% rename from core/custom_process/mp_process.py rename to core/custom_crawlers/mp.py index e31085b..af2450f 100644 --- a/core/custom_process/mp_process.py +++ b/core/custom_crawlers/mp.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- # warining: the mp_crawler will be deprecated in future version, we try to use general_process handle mp articles -from core.agents import get_info import httpx from bs4 import BeautifulSoup -from datetime import datetime, date +from datetime import datetime import re import asyncio @@ -13,10 +12,10 @@ header = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/604.1 Edg/112.0.100.0'} -async def mp_crawler(url: str, logger) -> tuple[dict, list, set]: +async def mp_crawler(url: str, logger) -> tuple[dict, dict]: if not url.startswith('https://mp.weixin.qq.com') and not url.startswith('http://mp.weixin.qq.com'): logger.warning(f'{url} is not a mp url, you should not use this function') - return {}, [], set() + return {}, {} url = url.replace("http://", "https://", 1) @@ -32,30 +31,31 @@ async def mp_crawler(url: str, logger) -> tuple[dict, list, set]: await asyncio.sleep(60) else: logger.warning(e) - return {}, [], set() + return {}, {} soup = BeautifulSoup(response.text, 'html.parser') if url.startswith('https://mp.weixin.qq.com/mp/appmsgalbum'): # 文章目录 - urls = {li.attrs['data-link'].replace("http://", "https://", 1) for li in soup.find_all('li', class_='album__list-item')} - simple_urls = set() - for url in urls: - cut_off_point = url.find('chksm=') + links = soup.find_all('li', class_='album__list-item') + link_dict = {} + for li in links: + u = li.attrs['data-link'].replace("http://", "https://", 1) + t = li.text.strip() + cut_off_point = u.find('chksm=') if cut_off_point != -1: - url = url[:cut_off_point - 1] - simple_urls.add(url) - return {}, [], simple_urls + u = u[:cut_off_point - 1] + if t and u: + link_dict[t] = u + return {}, link_dict # Get the original release date first pattern = r"var createTime = '(\d{4}-\d{2}-\d{2}) \d{2}:\d{2}'" match = re.search(pattern, response.text) - if match: - date_only = match.group(1) - publish_time = datetime.strptime(date_only, "%Y-%m-%d") + publish_time = match.group(1) else: - publish_time = date.today() + publish_time = datetime.strftime(datetime.today(), "%Y-%m-%d") # Get description content from < meta > tag try: @@ -70,14 +70,13 @@ async def mp_crawler(url: str, logger) -> tuple[dict, list, set]: except Exception as e: logger.warning(f"not mp format: {url}\n{e}") # For mp.weixin.qq.com types, mp_crawler won't work, and most likely neither will the other two - return {}, [], set() + return {}, {} if not rich_media_title or not profile_nickname: logger.warning(f"failed to analysis {url}, no title or profile_nickname") - return {}, [], set() + return {}, {} # Parse text and image links within the content interval - # Todo This scheme is compatible with picture sharing MP articles, but the pictures of the content cannot be obtained, # because the structure of this part is completely different, and a separate analysis scheme needs to be written # (but the proportion of this type of article is not high). texts = [] @@ -92,18 +91,18 @@ async def mp_crawler(url: str, logger) -> tuple[dict, list, set]: content = '\n'.join(cleaned_texts) else: logger.warning(f"failed to analysis contents {url}") - return {}, [], set() + return {}, {} if content: content = f"[from {profile_nickname}]{content}" else: - # If the content does not have it, but the summary has it, it means that it is an mp of the picture sharing type. + # If the content does not have it, but the summary has it, it means that it is a mp of the picture sharing type. # At this time, you can use the summary as the content. content = f"[from {profile_nickname}]{summary}" - infos = get_info(content, logger) article = {'url': url, 'title': rich_media_title, 'author': profile_nickname, - 'publish_date': publish_time} + 'publish_date': publish_time, + 'content': content} - return article, infos, set() + return article, {} diff --git a/core/custom_process/README.md b/core/custom_process/README.md deleted file mode 100644 index c5952ca..0000000 --- a/core/custom_process/README.md +++ /dev/null @@ -1,30 +0,0 @@ -wiseflow 致力于通过一套通用流程(使用视觉大模型驱动的可以自主使用爬虫工具的智能体)处理所有页面。 - -不过我们也为客户保留自定义处理的灵活性。 - -为添加自定义处理逻辑单元请遵照如下规范: - -1、逻辑处理单元应该是一个函数(而不是类); - -2、入参只接受两个:url(要处理的 url,请只提供一个 url,而不是列表,因为主函数会处理队列逻辑) 和 logger 对象(这意味着不要为你的自定义处理单元添加日志对象); - -3、出参需要返回解析后的文章详情(dict),和信息列表(list),以及解析出来的需要添加到工作队列的 url 结合(元组)。出参必须同时返回这三个结果,没有的话,可以分别传出 {} [] set() - -article 的字典必须包括 'url'(str), 'title'(str), 'author'(str), 'publish_date'(date 日期对象,注意是日期)四个键值,额外可以添加一个 'sceenshort' 值是一个 png 文件的路径。 - -4、在 core/custom_crawlers/__init__.py 中注册,参考: - -```pyhton -from .mp_crawler import mp_crawler - -customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} -``` - -注意键使用域名,可以使用 urllib.parse获取: - -```pyhton -from urllib.parse import urlparse - -parsed_url = urlparse("site's url") -domain = parsed_url.netloc -``` \ No newline at end of file diff --git a/core/general_process.py b/core/general_process.py index c1b7a54..530c353 100644 --- a/core/general_process.py +++ b/core/general_process.py @@ -1,26 +1,27 @@ # -*- coding: utf-8 -*- from utils.pb_api import PbTalker -from utils.general_utils import get_logger +from utils.general_utils import get_logger, extract_and_convert_dates from agents.get_info import GeneralInfoExtractor from bs4 import BeautifulSoup import os import json import asyncio -from custom_process import customer_crawler_map +from custom_crawlers import customer_crawler_map from urllib.parse import urlparse, urljoin import hashlib from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext +from datetime import datetime project_dir = os.environ.get("PROJECT_DIR", "") if project_dir: os.makedirs(project_dir, exist_ok=True) + os.environ['CRAWLEE_STORAGE_DIR'] = os.path.join(project_dir, 'crawlee_storage') screenshot_dir = os.path.join(project_dir, 'crawlee_storage', 'screenshots') - wiseflow_logger = get_logger('general_process', f'{project_dir}/general_process.log') pb = PbTalker(wiseflow_logger) -ie = GeneralInfoExtractor(pb, wiseflow_logger) +gie = GeneralInfoExtractor(pb, wiseflow_logger) # Global variables working_list = set() @@ -33,7 +34,8 @@ async def save_to_pb(article: dict, infos: list): article_id = pb.add(collection_name='articles', body=article) if not article_id: wiseflow_logger.error('add article failed, writing to cache_file') - with open(os.path.join(project_dir, 'cache_articles.json'), 'a', encoding='utf-8') as f: + timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + with open(os.path.join(project_dir, f'{timestamp}_cache_article.json'), 'w', encoding='utf-8') as f: json.dump(article, f, ensure_ascii=False, indent=4) return if screenshot: @@ -46,10 +48,11 @@ async def save_to_pb(article: dict, infos: list): for info in infos: info['articles'] = [article_id] - _ = pb.add(collection_name='agents', body=info) + _ = pb.add(collection_name='infos', body=info) if not _: - wiseflow_logger.error('add insight failed, writing to cache_file') - with open(os.path.join(project_dir, 'cache_insights.json'), 'a', encoding='utf-8') as f: + wiseflow_logger.error('add info failed, writing to cache_file') + timestamp = datetime.now().strftime("%Y%m%d%H%M%S") + with open(os.path.join(project_dir, f'{timestamp}_cache_infos.json'), 'w', encoding='utf-8') as f: json.dump(info, f, ensure_ascii=False, indent=4) @@ -75,7 +78,6 @@ async def pipeline(url: str): # future work: try to use a visual-llm do all the job... text = await context.page.inner_text('body') wiseflow_logger.debug(f"got text: {text}") - html = await context.page.inner_html('body') soup = BeautifulSoup(html, 'html.parser') links = soup.find_all('a', href=True) @@ -83,34 +85,36 @@ async def pipeline(url: str): link_dict = {} for a in links: new_url = a.get('href') - text = a.text.strip() - if new_url and text: - absolute_url = urljoin(base_url, new_url) - link_dict[text] = absolute_url + t = a.text.strip() + if new_url and t: + link_dict[t] = urljoin(base_url, new_url) wiseflow_logger.debug(f'found {len(link_dict)} more links') + publish_date = soup.find('div', class_='date').get_text(strip=True) if soup.find('div', class_='date') else None + if publish_date: + publish_date = extract_and_convert_dates(publish_date) + author = soup.find('div', class_='author').get_text(strip=True) if soup.find('div', class_='author') else None + if not author: + author = soup.find('div', class_='source').get_text(strip=True) if soup.find('div', + class_='source') else None + screenshot_file_name = f"{hashlib.sha256(context.request.url.encode()).hexdigest()}.png" await context.page.screenshot(path=os.path.join(screenshot_dir, screenshot_file_name), full_page=True) wiseflow_logger.debug(f'screenshot saved to {screenshot_file_name}') # get infos by llm - infos, author, publish_date, related_urls = await ie(text, link_dict, base_url, wiseflow_logger) + infos, related_urls, author, publish_date = await gie(text, link_dict, base_url, author, publish_date) if infos: - # get author and publish date by llm - wiseflow_logger.debug(f'LLM result -- author: {author}, publish_date: {publish_date}') article = { 'url': context.request.url, 'title': await context.page.title(), 'author': author, 'publish_date': publish_date, 'screenshot': os.path.join(screenshot_dir, screenshot_file_name), - 'tags': [info['name'] for info in infos] + 'tags': [info['tag'] for info in infos] } await save_to_pb(article, infos) - # find any related urls - related_urls = await get_more_related_urls(html, wiseflow_logger) - wiseflow_logger.debug(f'got {len(related_urls)} more urls') if related_urls: async with lock: new_urls = related_urls - existing_urls @@ -127,22 +131,47 @@ async def pipeline(url: str): parsed_url = urlparse(url) domain = parsed_url.netloc if domain in customer_crawler_map: - wiseflow_logger.debug(f'routed to customer process for {domain}') + wiseflow_logger.info(f'routed to customer crawler for {domain}') try: - article, infos, related_urls = await customer_crawler_map[domain](url, wiseflow_logger) + article, more_urls = await customer_crawler_map[domain](url, wiseflow_logger) except Exception as e: wiseflow_logger.error(f'error occurred in crawling {url}: {e}') continue - if infos and article: - wiseflow_logger.debug("receiving new infos from customer crawler, saving to pb") - article['tags'] = [info['name'] for info in infos] + if not article and not more_urls: + wiseflow_logger.info(f'no content found in {url} by customer crawler') + continue + + text = article.pop('content') if 'content' in article else None + author = article.get('author', None) + publish_date = article.get('publish_date', None) + title = article.get('title', "") + screenshot = article.get('screenshot', '') + + # get infos by llm + try: + infos, related_urls, author, publish_date = await gie(text, more_urls, url, author, publish_date) + except Exception as e: + wiseflow_logger.error(f'gie error occurred in processing {article}: {e}') + continue + + if infos: + article = { + 'url': url, + 'title': title, + 'author': author, + 'publish_date': publish_date, + 'screenshot': screenshot, + 'tags': [info['tag'] for info in infos] + } await save_to_pb(article, infos) + if related_urls: - wiseflow_logger.debug('receiving new related_urls from customer crawler, adding to working_list') - new_urls = related_urls - existing_urls - working_list.update(new_urls) + async with lock: + new_urls = related_urls - existing_urls + working_list.update(new_urls) continue + try: await crawler.run([url]) except Exception as e: diff --git a/core/requirements.txt b/core/requirements.txt index 167f0c7..501e168 100644 --- a/core/requirements.txt +++ b/core/requirements.txt @@ -1,12 +1,9 @@ openai loguru -gne -jieba httpx pocketbase pydantic -uvicorn json_repair==0.* beautifulsoup4 -fastapi -requests \ No newline at end of file +requests +crawlee[playwright] \ No newline at end of file diff --git a/core/utils/general_utils.py b/core/utils/general_utils.py index 903cf4e..2e04e98 100644 --- a/core/utils/general_utils.py +++ b/core/utils/general_utils.py @@ -72,8 +72,8 @@ def extract_and_convert_dates(input_string): if matches: break if matches: - return ''.join(matches[0]) - return '' + return '-'.join(matches[0]) + return None def get_logger(logger_name: str, logger_file_path: str): diff --git a/general_crawler_test.py b/general_crawler_test.py deleted file mode 100644 index b818596..0000000 --- a/general_crawler_test.py +++ /dev/null @@ -1,13 +0,0 @@ -from core.custom_process import crawler as general_crawler -from pprint import pprint -import asyncio - -test_list = ['http://society.people.com.cn/n1/2024/1202/c1008-40373268.html'] - -async def crawler_test(): - for test in test_list: - data = await general_crawler.run([test]) - print(type(data)) - -if __name__ == '__main__': - asyncio.run(crawler_test()) diff --git a/version b/version index 937cd78..7becae1 100644 --- a/version +++ b/version @@ -1 +1 @@ -v0.3.1 +v0.3.2 From 3e4454a33b4e946f6f4b3d834fa17eeb52e87e51 Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Fri, 6 Dec 2024 12:16:02 +0800 Subject: [PATCH 4/9] add batch process --- core/agents/get_info.py | 43 +++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/core/agents/get_info.py b/core/agents/get_info.py index 366543d..affb5e6 100644 --- a/core/agents/get_info.py +++ b/core/agents/get_info.py @@ -81,6 +81,10 @@ If the webpage text does not contain any information related to points of intere async def get_author_and_publish_date(self, text: str) -> tuple[str, str]: if not text: return "NA", "NA" + + if len(text) > 1024: + text = f'{text[:500]}......{text[-500:]}' + system_prompt = "As an information extraction assistant, your task is to accurately extract the source (or author) and publication date from the given webpage text. It is important to adhere to extracting the information directly from the original text. If the original text does not contain a particular piece of information, please replace it with NA" suffix = '''Please output the extracted information in the following JSON format: {"source": source or article author (use "NA" if this information cannot be extracted), "publish_date": extracted publication date (keep only the year, month, and day; use "NA" if this information cannot be extracted)}''' @@ -106,14 +110,26 @@ If the webpage text does not contain any information related to points of intere async def get_more_related_urls(self, link_dict: dict) -> set[str]: if not link_dict: return set() + + urls = set() content = '' for key, value in link_dict.items(): content = f"{content}{key}: {value}\n" - result = await llm([{'role': 'system', 'content': self.get_more_link_prompt}, {'role': 'user', 'content': f'{content}\n{self.get_more_link_suffix}'}], - model=self.secondary_model, temperature=0.1) + if len(content) > 512: + result = await llm([{'role': 'system', 'content': self.get_more_link_prompt}, + {'role': 'user', 'content': f'{content}\n{self.get_more_link_suffix}'}], + model=self.secondary_model, temperature=0.1) + self.logger.debug(f'get_more_related_urls llm output:\n{result}') + urls.update(extract_urls(result)) + content = '' + + if content: + result = await llm([{'role': 'system', 'content': self.get_more_link_prompt}, + {'role': 'user', 'content': f'{content}\n{self.get_more_link_suffix}'}], + model=self.secondary_model, temperature=0.1) + self.logger.debug(f'get_more_related_urls llm output:\n{result}') + urls.update(extract_urls(result)) - self.logger.debug(f'get_more_related_urls llm output:\n{result}') - urls = extract_urls(result) raw_urls = list(link_dict.values()) for url in urls: if url not in raw_urls: @@ -121,9 +137,10 @@ If the webpage text does not contain any information related to points of intere urls.remove(url) return urls - async def get_info(self, text: str, info_pre_fix: str) -> list[dict]: + async def get_info(self, text: str, info_pre_fix: str, link_dict: dict) -> list[dict]: if not text: return [] + content = f'\n{text}\n\n\n{self.get_info_suffix}' result = await llm([{'role': 'system', 'content': self.get_info_prompt}, {'role': 'user', 'content': content}], model=self.model, temperature=0.1, response_format={"type": "json_object"}) @@ -152,6 +169,10 @@ If the webpage text does not contain any information related to points of intere if item['focus'] not in self.focus_dict: self.logger.warning(f"{item['focus']} not in focus_list, it's model's Hallucination") continue + if item['content'] in link_dict: + self.logger.debug(f"{item['content']} in link_dict, aborting") + continue + judge = await llm([{'role': 'system', 'content': system}, {'role': 'user', 'content': f'\n{item["content"]}\n\n\n\n{text}\n\n\n{suffix}'}], model=self.secondary_model, temperature=0.1) @@ -189,7 +210,17 @@ If the webpage text does not contain any information related to points of intere publish_date = datetime.now().strftime('%Y-%m-%d') related_urls = await self.get_more_related_urls(link_dict) + info_prefix = f"//{author} {publish_date}//" - infos = await self.get_info(text, info_prefix) + lines = text.split('\n') + text = '' + infos = [] + for line in lines: + text = f'{text}{line}' + if len(text) > 2048: + infos.extend(await self.get_info(text, info_prefix, link_dict)) + text = '' + if text: + infos.extend(await self.get_info(text, info_prefix, link_dict)) return infos, related_urls, author, publish_date From 8c64749ba71b300e69c19526ffc79cd775e869e1 Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Fri, 6 Dec 2024 14:14:28 +0800 Subject: [PATCH 5/9] feat(core): update pb data sheet structure --- core/agents/get_info.py | 2 +- core/general_process.py | 15 +-- .../pb_migrations/1733465276_created_sites.js | 89 ++++++++++++++ .../1733465426_updated_articles.js | 28 +++++ .../pb_migrations/1733465563_created_infos.js | 111 ++++++++++++++++++ core/tasks.py | 8 +- env_sample | 16 +-- 7 files changed, 249 insertions(+), 20 deletions(-) create mode 100644 core/pb/pb_migrations/1733465276_created_sites.js create mode 100644 core/pb/pb_migrations/1733465426_updated_articles.js create mode 100644 core/pb/pb_migrations/1733465563_created_infos.js diff --git a/core/agents/get_info.py b/core/agents/get_info.py index affb5e6..7cc677c 100644 --- a/core/agents/get_info.py +++ b/core/agents/get_info.py @@ -23,7 +23,7 @@ class GeneralInfoExtractor: focus = input('It seems you have not set any focus point, WiseFlow need the specific focus point to guide the following info extract job.' 'so please input one now. describe what info you care about shortly: ') explanation = input('Please provide more explanation for the focus point (if not necessary, pls just type enter: ') - focus_data.append({"name": focus, "explaination": explanation, + focus_data.append({"name": focus, "explanation": explanation, "id": pb.add('focus_points', {"focuspoint": focus, "explanation": explanation})}) # self.focus_list = [item["focuspoint"] for item in focus_data] diff --git a/core/general_process.py b/core/general_process.py index 530c353..3fd034e 100644 --- a/core/general_process.py +++ b/core/general_process.py @@ -23,10 +23,6 @@ wiseflow_logger = get_logger('general_process', f'{project_dir}/general_process. pb = PbTalker(wiseflow_logger) gie = GeneralInfoExtractor(pb, wiseflow_logger) -# Global variables -working_list = set() -existing_urls = {url['url'] for url in pb.read(collection_name='articles', fields=['url']) if url['url']} -lock = asyncio.Lock() async def save_to_pb(article: dict, infos: list): # saving to pb process @@ -57,7 +53,9 @@ async def save_to_pb(article: dict, infos: list): async def pipeline(url: str): - global working_list, existing_urls + working_list = set() + existing_urls = {url['url'] for url in pb.read(collection_name='articles', fields=['url']) if url['url']} + lock = asyncio.Lock() working_list.add(url) crawler = PlaywrightCrawler( # Limit the crawl to max requests. Remove or increase it for crawling all links. @@ -179,6 +177,9 @@ async def pipeline(url: str): if __name__ == '__main__': - import asyncio + sites = pb.read('sites', filter='activated=True') + wiseflow_logger.info('execute all sites one time') + async def run_all_sites(): + await asyncio.gather(*[pipeline(site['url'].rstrip('/')) for site in sites]) - asyncio.run(pipeline()) + asyncio.run(run_all_sites()) diff --git a/core/pb/pb_migrations/1733465276_created_sites.js b/core/pb/pb_migrations/1733465276_created_sites.js new file mode 100644 index 0000000..164ff9b --- /dev/null +++ b/core/pb/pb_migrations/1733465276_created_sites.js @@ -0,0 +1,89 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "exceptDomains": [], + "hidden": false, + "id": "url4101391790", + "name": "url", + "onlyDomains": [], + "presentable": false, + "required": true, + "system": false, + "type": "url" + }, + { + "hidden": false, + "id": "number1152796692", + "max": null, + "min": null, + "name": "per_hours", + "onlyInt": false, + "presentable": false, + "required": false, + "system": false, + "type": "number" + }, + { + "hidden": false, + "id": "bool806155165", + "name": "activated", + "presentable": false, + "required": false, + "system": false, + "type": "bool" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_2001081480", + "indexes": [], + "listRule": null, + "name": "sites", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_2001081480"); + + return app.delete(collection); +}) diff --git a/core/pb/pb_migrations/1733465426_updated_articles.js b/core/pb/pb_migrations/1733465426_updated_articles.js new file mode 100644 index 0000000..588a62c --- /dev/null +++ b/core/pb/pb_migrations/1733465426_updated_articles.js @@ -0,0 +1,28 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_4287850865") + + // add field + collection.fields.addAt(6, new Field({ + "cascadeDelete": false, + "collectionId": "pbc_3385864241", + "hidden": false, + "id": "relation1874629670", + "maxSelect": 999, + "minSelect": 0, + "name": "tags", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_4287850865") + + // remove field + collection.fields.removeById("relation1874629670") + + return app.save(collection) +}) diff --git a/core/pb/pb_migrations/1733465563_created_infos.js b/core/pb/pb_migrations/1733465563_created_infos.js new file mode 100644 index 0000000..73d9085 --- /dev/null +++ b/core/pb/pb_migrations/1733465563_created_infos.js @@ -0,0 +1,111 @@ +/// +migrate((app) => { + const collection = new Collection({ + "createRule": null, + "deleteRule": null, + "fields": [ + { + "autogeneratePattern": "[a-z0-9]{15}", + "hidden": false, + "id": "text3208210256", + "max": 15, + "min": 15, + "name": "id", + "pattern": "^[a-z0-9]+$", + "presentable": false, + "primaryKey": true, + "required": true, + "system": true, + "type": "text" + }, + { + "autogeneratePattern": "", + "hidden": false, + "id": "text4274335913", + "max": 0, + "min": 0, + "name": "content", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_3385864241", + "hidden": false, + "id": "relation59357059", + "maxSelect": 1, + "minSelect": 0, + "name": "tag", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "cascadeDelete": false, + "collectionId": "pbc_4287850865", + "hidden": false, + "id": "relation3218944360", + "maxSelect": 999, + "minSelect": 0, + "name": "articles", + "presentable": false, + "required": false, + "system": false, + "type": "relation" + }, + { + "hidden": false, + "id": "file3291445124", + "maxSelect": 1, + "maxSize": 0, + "mimeTypes": [], + "name": "report", + "presentable": false, + "protected": false, + "required": false, + "system": false, + "thumbs": [], + "type": "file" + }, + { + "hidden": false, + "id": "autodate2990389176", + "name": "created", + "onCreate": true, + "onUpdate": false, + "presentable": false, + "system": false, + "type": "autodate" + }, + { + "hidden": false, + "id": "autodate3332085495", + "name": "updated", + "onCreate": true, + "onUpdate": true, + "presentable": false, + "system": false, + "type": "autodate" + } + ], + "id": "pbc_629947526", + "indexes": [], + "listRule": null, + "name": "infos", + "system": false, + "type": "base", + "updateRule": null, + "viewRule": null + }); + + return app.save(collection); +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_629947526"); + + return app.delete(collection); +}) diff --git a/core/tasks.py b/core/tasks.py index 8ec9c34..b5e2a7a 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -1,5 +1,5 @@ import asyncio -from agents import pipeline, pb, logger +from general_process import pipeline, pb, wiseflow_logger counter = 1 @@ -8,7 +8,7 @@ async def process_site(site, counter): if not site['per_hours'] or not site['url']: return if counter % site['per_hours'] == 0: - logger.info(f"applying {site['url']}") + wiseflow_logger.info(f"applying {site['url']}") await pipeline(site['url'].rstrip('/')) @@ -16,11 +16,11 @@ async def schedule_pipeline(interval): global counter while True: sites = pb.read('sites', filter='activated=True') - logger.info(f'task execute loop {counter}') + wiseflow_logger.info(f'task execute loop {counter}') await asyncio.gather(*[process_site(site, counter) for site in sites]) counter += 1 - logger.info(f'task execute loop finished, work after {interval} seconds') + wiseflow_logger.info(f'task execute loop finished, work after {interval} seconds') await asyncio.sleep(interval) diff --git a/env_sample b/env_sample index db77214..33ba638 100755 --- a/env_sample +++ b/env_sample @@ -1,10 +1,10 @@ export LLM_API_KEY="" -export LLM_API_BASE="https://api.siliconflow.cn/v1" ##for local model services or calling non-OpenAI services with openai_wrapper -##strongly recommended to use the following model provided by siliconflow (consider both effect and price) -export GET_INFO_MODEL="THUDM/glm-4-9b-chat" ## -export REWRITE_MODEL="Qwen/Qwen2-7B-Instruct" -export HTML_PARSE_MODEL="aQwen/Qwen2-7B-Instruct" +export LLM_API_BASE="https://api.siliconflow.cn/v1" +export PB_API_AUTH="test@example.com|1234567890" ##your pb superuser account and password +export VERBOSE="true" ##for detail log info. If not need, remove this item. + +##belowing is optional, go as you need +#export PRIMARY_MODEL="Qwen/Qwen2.5-14B-Instruct" +#export SECONDARY_MODEL="THUDM/glm-4-9b-chat" export PROJECT_DIR="work_dir" -export PB_API_AUTH="test@example.com|1234567890" -# export "PB_API_BASE"="" ##only use if your pb not run on 127.0.0.1:8090 -export WS_LOG="verbose" ##for detail log info. If not need, just delete this item. \ No newline at end of file +#export "PB_API_BASE"="" ##only use if your pb not run on 127.0.0.1:8090 \ No newline at end of file From ec514b49ddcb164db49ac33c51a4a9b97b915d3f Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Sun, 8 Dec 2024 18:03:34 +0800 Subject: [PATCH 6/9] refactor(core): the new general crawler --- .dockerignore | 20 -- CHANGELOG.md | 2 +- core/README.md | 54 ------ core/agents/get_info.py | 20 +- core/custom_crawlers/README_EN.md | 45 ----- core/custom_crawlers/__init__.py | 4 - core/custom_crawlers/mp.py | 108 ----------- .../README.md | 0 core/custom_scraper/__init__.py | 3 + core/custom_scraper/mp.py | 90 +++++++++ core/general_process.py | 175 ++++++++---------- core/requirements.txt | 1 - core/run.sh | 18 ++ core/run_all.sh | 7 +- core/scripts/start_backend.sh | 5 - core/scripts/start_pb.sh | 1 - core/scripts/start_tasks.sh | 5 - 17 files changed, 200 insertions(+), 358 deletions(-) delete mode 100644 .dockerignore delete mode 100644 core/README.md delete mode 100644 core/custom_crawlers/README_EN.md delete mode 100644 core/custom_crawlers/__init__.py delete mode 100644 core/custom_crawlers/mp.py rename core/{custom_crawlers => custom_scraper}/README.md (100%) create mode 100644 core/custom_scraper/__init__.py create mode 100644 core/custom_scraper/mp.py create mode 100755 core/run.sh delete mode 100644 core/scripts/start_backend.sh delete mode 100644 core/scripts/start_pb.sh delete mode 100644 core/scripts/start_tasks.sh diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index abf0f8c..0000000 --- a/.dockerignore +++ /dev/null @@ -1,20 +0,0 @@ -.git -.vscode -.dockerignore -.gitignore -.env -config -build -web/dist -web/node_modules -docker-compose.yaml -Dockerfile -README.md -core/__pycache__ -core/work_dir -env_sample -core/pb/pb_data -core/pb/CHANGELOG.md -core/pb/LICENSE.md -core/pb/pocketbase -work_dir \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index cdaa1e6..48965c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # V0.3.2 - 引入 Crawlee(playwrigt模块),大幅提升通用爬取能力,适配实际项目场景; - Introduce Crawlee (playwright module), significantly enhancing general crawling capabilities and adapting to practical project scenarios; + Introduce Crawlee (playwright module), significantly enhancing general crawling capabilities and adapting to real-world task; - 完全重写了信息提取模块,引入“爬-查一体”策略,你关注的才是你想要的; diff --git a/core/README.md b/core/README.md deleted file mode 100644 index ae5aefc..0000000 --- a/core/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# For Developer Only - -```bash -conda create -n wiseflow python=3.10 -conda activate wiseflow -cd core -pip install -r requirements.txt -``` - -- tasks.py background task circle process -- backend.py main process pipeline service (based on fastapi) - -### WiseFlow fastapi detail - -- api address http://127.0.0.1:8077/feed -- request method : post -- body : - -```python -{'user_id': str, 'type': str, 'content':str, 'addition': Optional[str]} -# Type is one of "text", "publicMsg", "site" and "url"; -# user_id: str -type: Literal["text", "publicMsg", "file", "image", "video", "location", "chathistory", "site", "attachment", "url"] -content: str -addition: Optional[str] = None -``` - -see more (when backend started) http://127.0.0.1:8077/docs - -### WiseFlow Repo File Structure - -``` -wiseflow -|- dockerfiles -|- ... -|- core - |- tasks.py - |- backend.py - |- insights - |- __init__.py # main process - |- get_info.py # module use llm to get a summary of information and match tags - |- llms # llm service wrapper - |- pb # pocketbase filefolder - |- scrapers - |- __init__.py # You can register a proprietary site scraper here - |- general_scraper.py # module to get all possible article urls for general site - |- general_crawler.py # module for general article sites - |- mp_crawler.py # module for mp article (weixin public account) sites - |- utils # tools -``` - -Although the general_scraper included in wiseflow can be applied to the parsing of most static pages, for actual business, we still recommend that customers to write their own crawlers aiming the actual info source. - -See core/scrapers/README.md for integration instructions for proprietary crawlers diff --git a/core/agents/get_info.py b/core/agents/get_info.py index 7cc677c..d8769c2 100644 --- a/core/agents/get_info.py +++ b/core/agents/get_info.py @@ -1,8 +1,8 @@ -from core.llms.openai_wrapper import openai_llm as llm +from llms.openai_wrapper import openai_llm as llm # from core.llms.siliconflow_wrapper import sfa_llm -from core.utils.general_utils import is_chinese, extract_and_convert_dates, extract_urls +from utils.general_utils import is_chinese, extract_and_convert_dates, extract_urls from loguru import logger -from core.utils.pb_api import PbTalker +from utils.pb_api import PbTalker import os from datetime import datetime from urllib.parse import urlparse @@ -30,8 +30,8 @@ class GeneralInfoExtractor: self.focus_dict = {item["focuspoint"]: item["id"] for item in focus_data} focus_statement = '' for item in focus_data: - tag = item["name"] - expl = item["explaination"] + tag = item["focuspoint"] + expl = item["explanation"] focus_statement = f"{focus_statement}#{tag}\n" if expl: focus_statement = f"{focus_statement}解释:{expl}\n" @@ -56,7 +56,7 @@ class GeneralInfoExtractor: 如果网页文本中不包含任何与兴趣点相关的信息,请仅输出:[]。''' self.get_more_link_prompt = f"作为一位高效的信息筛选助手,你的任务是根据给定的兴趣点,从给定的文本及其对应的URL中挑选出最值得关注的URL。兴趣点及其解释如下:\n\n{focus_statement}" - self.get_more_link_suffix = "请逐条分析上述 文本:url 对。首先输出你的分析依据,然后给出是否挑选它的结论,如果决定挑选该条,在结论后复制输出该条的 url,否则的话直接进入下一条的分析。请一条一条的分析,不要漏掉任何一条。" + self.get_more_link_suffix = "请逐条分析:对于每一条,首先复制文本,然后给出分析依据,最后给出结论。如果决定挑选该条,在结论后复制对应的url,否则的话直接进入下一条的分析。请一条一条的分析,不要漏掉任何一条。" else: self.get_info_prompt = f'''As an information extraction assistant, your task is to extract content related to the following user focus points from the given web page text. The list of focus points and their explanations is as follows: @@ -76,7 +76,7 @@ Example: If the webpage text does not contain any information related to points of interest, please output only: []''' self.get_more_link_prompt = f"As an efficient information filtering assistant, your task is to select the most noteworthy URLs from a set of texts and their corresponding URLs based on the given focus points. The focus points and their explanations are as follows:\n\n{focus_statement}" - self.get_more_link_suffix = "Please analyze the above text: URL pairs. First, output your analysis basis, and then give the conclusion on whether to select it. If you decide to select this item, then copy and output the URL of this item following the conclusion; otherwise, proceed directly to the analysis of the next item. Analyze one by one, do not miss any one." + self.get_more_link_suffix = "Please analyze each item one by one: For each item, first copy the text, then provide the analysis basis, and finally give the conclusion. If the decision is to select the item, copy the corresponding URL after the conclusion; otherwise, proceed directly to the analysis of the next item. Analyze each item one by one, without missing any." async def get_author_and_publish_date(self, text: str) -> tuple[str, str]: if not text: @@ -218,9 +218,11 @@ If the webpage text does not contain any information related to points of intere for line in lines: text = f'{text}{line}' if len(text) > 2048: - infos.extend(await self.get_info(text, info_prefix, link_dict)) + cache = await self.get_info(text, info_prefix, link_dict) + infos.extend(cache) text = '' if text: - infos.extend(await self.get_info(text, info_prefix, link_dict)) + cache = await self.get_info(text, info_prefix, link_dict) + infos.extend(cache) return infos, related_urls, author, publish_date diff --git a/core/custom_crawlers/README_EN.md b/core/custom_crawlers/README_EN.md deleted file mode 100644 index 8370131..0000000 --- a/core/custom_crawlers/README_EN.md +++ /dev/null @@ -1,45 +0,0 @@ -wiseflow is dedicated to processing all pages through a set of general workflows (llm-agent that can autonomously use crawling tools). - -However, we also reserve the flexibility for customers to handle custom processing. You can add and register custom crawlers for specific domains here. - -Please follow the guidelines below: - -1. The crawler should be a function (not a class); - -2. It only accepts two parameters: **url** (the URL to process, please provide only one URL, not a list, as the main function will handle queue logic) and **logger** object (which means you should not add a logging object to your custom crawler, wiseflow will manage it uniformly); - -3. The output must be two items: one is the parsed article details `article`, which is a dict object, and the other is a dictionary of external links `link_dict`, which is also a dict object. - -The format for `article` is as follows (note that 'content' is required and cannot be empty, other fields can be omitted, and any additional key-value information will be ignored): - -`{'url': ..., 'title': ..., 'author': ..., 'publish_date': ..., 'screenshot': ..., 'content': ...(not empty)}` - -All values in the above dictionary should be of type **str**, the date format should be **YYYY-MM-DD**, and the screenshot should be a **file path**, which can be a relative path to the core directory or an absolute path, with the file type being **png**. - -**Note:** -- 'content' must exist and not be empty, otherwise it will not trigger subsequent extraction, and the article will be discarded. This is the only required non-empty item; -- 'author' and 'publish_date' are strongly recommended, otherwise wiseflow will automatically use the domain name corresponding to the domain and the current date as substitutes. - -The format for `link_dict` is as follows: - -`{'text': text information corresponding to the external link, 'url': URL corresponding to the external link}` - -wiseflow will use this as input and use LLM to determine which links are worth further crawling. - -4. Register in `core/custom_crawlers/__init__.py`, refer to: - - -```pyhton -from .mp import mp_crawler - -customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} -``` - -Note that the key should be the domain name, which can be obtained using `urllib.parse`: - -```pyhton -from urllib.parse import urlparse - -parsed_url = urlparse("site's url") -domain = parsed_url.netloc -``` diff --git a/core/custom_crawlers/__init__.py b/core/custom_crawlers/__init__.py deleted file mode 100644 index 3e87354..0000000 --- a/core/custom_crawlers/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .mp import mp_crawler - -customer_crawler_map = {} -# customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} diff --git a/core/custom_crawlers/mp.py b/core/custom_crawlers/mp.py deleted file mode 100644 index af2450f..0000000 --- a/core/custom_crawlers/mp.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- coding: utf-8 -*- -# warining: the mp_crawler will be deprecated in future version, we try to use general_process handle mp articles - -import httpx -from bs4 import BeautifulSoup -from datetime import datetime -import re -import asyncio - - -header = { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/604.1 Edg/112.0.100.0'} - - -async def mp_crawler(url: str, logger) -> tuple[dict, dict]: - if not url.startswith('https://mp.weixin.qq.com') and not url.startswith('http://mp.weixin.qq.com'): - logger.warning(f'{url} is not a mp url, you should not use this function') - return {}, {} - - url = url.replace("http://", "https://", 1) - - async with httpx.AsyncClient() as client: - for retry in range(2): - try: - response = await client.get(url, headers=header, timeout=30) - response.raise_for_status() - break - except Exception as e: - if retry < 1: - logger.info(f"{e}\nwaiting 1min") - await asyncio.sleep(60) - else: - logger.warning(e) - return {}, {} - - soup = BeautifulSoup(response.text, 'html.parser') - - if url.startswith('https://mp.weixin.qq.com/mp/appmsgalbum'): - # 文章目录 - links = soup.find_all('li', class_='album__list-item') - link_dict = {} - for li in links: - u = li.attrs['data-link'].replace("http://", "https://", 1) - t = li.text.strip() - cut_off_point = u.find('chksm=') - if cut_off_point != -1: - u = u[:cut_off_point - 1] - if t and u: - link_dict[t] = u - return {}, link_dict - - # Get the original release date first - pattern = r"var createTime = '(\d{4}-\d{2}-\d{2}) \d{2}:\d{2}'" - match = re.search(pattern, response.text) - if match: - publish_time = match.group(1) - else: - publish_time = datetime.strftime(datetime.today(), "%Y-%m-%d") - - # Get description content from < meta > tag - try: - meta_description = soup.find('meta', attrs={'name': 'description'}) - summary = meta_description['content'].strip() if meta_description else '' - # card_info = soup.find('div', id='img-content') - # Parse the required content from the < div > tag - rich_media_title = soup.find('h1', id='activity-name').text.strip() \ - if soup.find('h1', id='activity-name') \ - else soup.find('h1', class_='rich_media_title').text.strip() - profile_nickname = soup.find('div', class_='wx_follow_nickname').text.strip() - except Exception as e: - logger.warning(f"not mp format: {url}\n{e}") - # For mp.weixin.qq.com types, mp_crawler won't work, and most likely neither will the other two - return {}, {} - - if not rich_media_title or not profile_nickname: - logger.warning(f"failed to analysis {url}, no title or profile_nickname") - return {}, {} - - # Parse text and image links within the content interval - # because the structure of this part is completely different, and a separate analysis scheme needs to be written - # (but the proportion of this type of article is not high). - texts = [] - content_area = soup.find('div', id='js_content') - if content_area: - # 提取文本 - for section in content_area.find_all(['section', 'p'], recursive=False): # 遍历顶级section - text = section.get_text(separator=' ', strip=True) - if text and text not in texts: - texts.append(text) - cleaned_texts = [t for t in texts if t.strip()] - content = '\n'.join(cleaned_texts) - else: - logger.warning(f"failed to analysis contents {url}") - return {}, {} - if content: - content = f"[from {profile_nickname}]{content}" - else: - # If the content does not have it, but the summary has it, it means that it is a mp of the picture sharing type. - # At this time, you can use the summary as the content. - content = f"[from {profile_nickname}]{summary}" - - article = {'url': url, - 'title': rich_media_title, - 'author': profile_nickname, - 'publish_date': publish_time, - 'content': content} - - return article, {} diff --git a/core/custom_crawlers/README.md b/core/custom_scraper/README.md similarity index 100% rename from core/custom_crawlers/README.md rename to core/custom_scraper/README.md diff --git a/core/custom_scraper/__init__.py b/core/custom_scraper/__init__.py new file mode 100644 index 0000000..ded2693 --- /dev/null +++ b/core/custom_scraper/__init__.py @@ -0,0 +1,3 @@ +from .mp import mp_scraper + +custom_scraper_map = {'mp.weixin.qq.com': mp_scraper} diff --git a/core/custom_scraper/mp.py b/core/custom_scraper/mp.py new file mode 100644 index 0000000..618656d --- /dev/null +++ b/core/custom_scraper/mp.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- + +from bs4 import BeautifulSoup +from datetime import datetime +import os, re +from utils.general_utils import get_logger + + +project_dir = os.environ.get("PROJECT_DIR", "") +if project_dir: + os.makedirs(project_dir, exist_ok=True) + +mp_logger = get_logger('mp_scraper', project_dir) + +async def mp_scraper(html: str, url: str) -> tuple[dict, set, list]: + if not url.startswith('https://mp.weixin.qq.com') and not url.startswith('http://mp.weixin.qq.com'): + mp_logger.warning(f'{url} is not a mp url, you should not use this function') + return {}, set(), [] + + url = url.replace("http://", "https://", 1) + soup = BeautifulSoup(html, 'html.parser') + + if url.startswith('https://mp.weixin.qq.com/mp/appmsgalbum'): + # 文章目录 + urls = {li.attrs['data-link'].replace("http://", "https://", 1) for li in soup.find_all('li', class_='album__list-item')} + simple_urls = set() + for url in urls: + cut_off_point = url.find('chksm=') + if cut_off_point != -1: + url = url[:cut_off_point - 1] + simple_urls.add(url) + return {}, simple_urls, [] + + # Get the original release date first + pattern = r"var createTime = '(\d{4}-\d{2}-\d{2}) \d{2}:\d{2}'" + match = re.search(pattern, html) + if match: + publish_time = match.group(1) + else: + publish_time = datetime.strftime(datetime.today(), "%Y-%m-%d") + + # Get description content from < meta > tag + try: + meta_description = soup.find('meta', attrs={'name': 'description'}) + summary = meta_description['content'].strip() if meta_description else '' + # card_info = soup.find('div', id='img-content') + # Parse the required content from the < div > tag + rich_media_title = soup.find('h1', id='activity-name').text.strip() \ + if soup.find('h1', id='activity-name') \ + else soup.find('h1', class_='rich_media_title').text.strip() + profile_nickname = soup.find('div', class_='wx_follow_nickname').text.strip() + except Exception as e: + mp_logger.warning(f"not mp format: {url}\n{e}") + # For mp.weixin.qq.com types, mp_crawler won't work, and most likely neither will the other two + return {}, set(), [] + + if not rich_media_title or not profile_nickname: + mp_logger.warning(f"failed to analysis {url}, no title or profile_nickname") + return {}, set(), [] + + # Parse text and image links within the content interval + # because the structure of this part is completely different, and a separate analysis scheme needs to be written + # (but the proportion of this type of article is not high). + texts = [] + content_area = soup.find('div', id='js_content') + if content_area: + # 提取文本 + for section in content_area.find_all(['section', 'p'], recursive=False): # 遍历顶级section + text = section.get_text(separator=' ', strip=True) + if text and text not in texts: + texts.append(text) + cleaned_texts = [t for t in texts if t.strip()] + content = '\n'.join(cleaned_texts) + else: + mp_logger.warning(f"failed to analysis contents {url}") + return {}, set(), [] + if content: + content = f"[from {profile_nickname}]{content}" + else: + # If the content does not have it, but the summary has it, it means that it is a mp of the picture sharing type. + # At this time, you can use the summary as the content. + content = f"[from {profile_nickname}]{summary}" + + article = {'url': url, + 'title': rich_media_title, + 'author': profile_nickname, + 'publish_date': publish_time, + 'content': content} + + return article, set(), [] diff --git a/core/general_process.py b/core/general_process.py index 3fd034e..199d48d 100644 --- a/core/general_process.py +++ b/core/general_process.py @@ -6,7 +6,7 @@ from bs4 import BeautifulSoup import os import json import asyncio -from custom_crawlers import customer_crawler_map +from custom_scraper import custom_scraper_map from urllib.parse import urlparse, urljoin import hashlib from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext @@ -19,7 +19,7 @@ if project_dir: os.environ['CRAWLEE_STORAGE_DIR'] = os.path.join(project_dir, 'crawlee_storage') screenshot_dir = os.path.join(project_dir, 'crawlee_storage', 'screenshots') -wiseflow_logger = get_logger('general_process', f'{project_dir}/general_process.log') +wiseflow_logger = get_logger('general_process', project_dir) pb = PbTalker(wiseflow_logger) gie = GeneralInfoExtractor(pb, wiseflow_logger) @@ -52,31 +52,64 @@ async def save_to_pb(article: dict, infos: list): json.dump(info, f, ensure_ascii=False, indent=4) -async def pipeline(url: str): - working_list = set() - existing_urls = {url['url'] for url in pb.read(collection_name='articles', fields=['url']) if url['url']} - lock = asyncio.Lock() - working_list.add(url) - crawler = PlaywrightCrawler( - # Limit the crawl to max requests. Remove or increase it for crawling all links. - max_requests_per_crawl=100, - ) - # Define the default request handler, which will be called for every request. - @crawler.router.default_handler - async def request_handler(context: PlaywrightCrawlingContext) -> None: - context.log.info(f'Processing {context.request.url} ...') - # Handle dialogs (alerts, confirms, prompts) - async def handle_dialog(dialog): - context.log.info(f'Closing dialog: {dialog.message}') - await dialog.accept() +crawler = PlaywrightCrawler( + # Limit the crawl to max requests. Remove or increase it for crawling all links. + # max_requests_per_crawl=1, + headless=False if os.environ.get("VERBOSE", "").lower() in ["true", "1"] else True +) +@crawler.router.default_handler +async def request_handler(context: PlaywrightCrawlingContext) -> None: + context.log.info(f'Processing {context.request.url} ...') + # Handle dialogs (alerts, confirms, prompts) + async def handle_dialog(dialog): + context.log.info(f'Closing dialog: {dialog.message}') + await dialog.accept() - context.page.on('dialog', handle_dialog) + context.page.on('dialog', handle_dialog) + await context.page.wait_for_load_state('networkidle') + html = await context.page.inner_html('body') + context.log.info('successfully finish fetching') + parsed_url = urlparse(context.request.url) + domain = parsed_url.netloc + if domain in custom_scraper_map: + context.log.info(f'routed to customer scraper for {domain}') + try: + article, more_urls, infos = await custom_scraper_map[domain](html, context.request.url) + except Exception as e: + context.log.error(f'error occurred: {e}') + wiseflow_logger.warning(f'handle {parsed_url} failed by customer scraper, this url will be skipped') + return + + if not article and not infos and not more_urls: + wiseflow_logger.warning(f'{parsed_url} handled by customer scraper, bot got nothing') + return + + title = article.get('title', "") + link_dict = more_urls if isinstance(more_urls, dict) else None + related_urls = more_urls if isinstance(more_urls, set) else set() + if not infos and not related_urls: + text = article.pop('content') if 'content' in article else None + if not text: + wiseflow_logger.warning(f'no content found in {parsed_url} by customer scraper, cannot use llm GIE') + author, publish_date = '', '' + else: + author = article.get('author', '') + publish_date = article.get('publish_date', '') + # get infos by llm + try: + infos, related_urls, author, publish_date = await gie(text, link_dict, context.request.url, author, publish_date) + except Exception as e: + wiseflow_logger.error(f'gie error occurred in processing: {e}') + infos = [] + author, publish_date = '', '' + else: + author = article.get('author', '') + publish_date = article.get('publish_date', '') + else: # Extract data from the page. # future work: try to use a visual-llm do all the job... text = await context.page.inner_text('body') - wiseflow_logger.debug(f"got text: {text}") - html = await context.page.inner_html('body') soup = BeautifulSoup(html, 'html.parser') links = soup.find_all('a', href=True) base_url = context.request.url @@ -86,100 +119,40 @@ async def pipeline(url: str): t = a.text.strip() if new_url and t: link_dict[t] = urljoin(base_url, new_url) - wiseflow_logger.debug(f'found {len(link_dict)} more links') - publish_date = soup.find('div', class_='date').get_text(strip=True) if soup.find('div', class_='date') else None if publish_date: publish_date = extract_and_convert_dates(publish_date) author = soup.find('div', class_='author').get_text(strip=True) if soup.find('div', class_='author') else None if not author: - author = soup.find('div', class_='source').get_text(strip=True) if soup.find('div', - class_='source') else None - - screenshot_file_name = f"{hashlib.sha256(context.request.url.encode()).hexdigest()}.png" - await context.page.screenshot(path=os.path.join(screenshot_dir, screenshot_file_name), full_page=True) - wiseflow_logger.debug(f'screenshot saved to {screenshot_file_name}') - + author = soup.find('div', class_='source').get_text(strip=True) if soup.find('div', class_='source') else None # get infos by llm infos, related_urls, author, publish_date = await gie(text, link_dict, base_url, author, publish_date) - if infos: - article = { - 'url': context.request.url, - 'title': await context.page.title(), - 'author': author, - 'publish_date': publish_date, - 'screenshot': os.path.join(screenshot_dir, screenshot_file_name), - 'tags': [info['tag'] for info in infos] - } - await save_to_pb(article, infos) + title = await context.page.title() - if related_urls: - async with lock: - new_urls = related_urls - existing_urls - working_list.update(new_urls) + screenshot_file_name = f"{hashlib.sha256(context.request.url.encode()).hexdigest()}.png" + await context.page.screenshot(path=os.path.join(screenshot_dir, screenshot_file_name), full_page=True) + wiseflow_logger.debug(f'screenshot saved to {screenshot_file_name}') - # todo: use llm to determine next action + if infos: + article = { + 'url': context.request.url, + 'title': title, + 'author': author, + 'publish_date': publish_date, + 'screenshot': os.path.join(screenshot_dir, screenshot_file_name), + 'tags': [info['tag'] for info in infos] + } + await save_to_pb(article, infos) - while working_list: - async with lock: - if not working_list: - break - url = working_list.pop() - existing_urls.add(url) - parsed_url = urlparse(url) - domain = parsed_url.netloc - if domain in customer_crawler_map: - wiseflow_logger.info(f'routed to customer crawler for {domain}') - try: - article, more_urls = await customer_crawler_map[domain](url, wiseflow_logger) - except Exception as e: - wiseflow_logger.error(f'error occurred in crawling {url}: {e}') - continue - - if not article and not more_urls: - wiseflow_logger.info(f'no content found in {url} by customer crawler') - continue - - text = article.pop('content') if 'content' in article else None - author = article.get('author', None) - publish_date = article.get('publish_date', None) - title = article.get('title', "") - screenshot = article.get('screenshot', '') - - # get infos by llm - try: - infos, related_urls, author, publish_date = await gie(text, more_urls, url, author, publish_date) - except Exception as e: - wiseflow_logger.error(f'gie error occurred in processing {article}: {e}') - continue - - if infos: - article = { - 'url': url, - 'title': title, - 'author': author, - 'publish_date': publish_date, - 'screenshot': screenshot, - 'tags': [info['tag'] for info in infos] - } - await save_to_pb(article, infos) - - if related_urls: - async with lock: - new_urls = related_urls - existing_urls - working_list.update(new_urls) - continue - - try: - await crawler.run([url]) - except Exception as e: - wiseflow_logger.error(f'error occurred in crawling {url}: {e}') + if related_urls: + await context.add_requests(list(related_urls)) + # todo: use llm to determine next action if __name__ == '__main__': sites = pb.read('sites', filter='activated=True') wiseflow_logger.info('execute all sites one time') async def run_all_sites(): - await asyncio.gather(*[pipeline(site['url'].rstrip('/')) for site in sites]) + await crawler.run([site['url'].rstrip('/') for site in sites]) asyncio.run(run_all_sites()) diff --git a/core/requirements.txt b/core/requirements.txt index 501e168..4381b02 100644 --- a/core/requirements.txt +++ b/core/requirements.txt @@ -1,6 +1,5 @@ openai loguru -httpx pocketbase pydantic json_repair==0.* diff --git a/core/run.sh b/core/run.sh new file mode 100755 index 0000000..220523f --- /dev/null +++ b/core/run.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -o allexport +source .env +set +o allexport + +if ! pgrep -x "pocketbase" > /dev/null; then + if ! netstat -tuln | grep ":8090" > /dev/null && ! lsof -i :8090 > /dev/null; then + echo "Starting PocketBase..." + pb/pocketbase serve --http=0.0.0.0:8090 & + else + echo "Port 8090 is already in use." + fi +else + echo "PocketBase is already running." +fi + +python general_process.py \ No newline at end of file diff --git a/core/run_all.sh b/core/run_all.sh index a90f212..0ae42aa 100755 --- a/core/run_all.sh +++ b/core/run_all.sh @@ -1,9 +1,8 @@ #!/bin/bash -# 从 .env 文件中加载环境变量 -if [ -f .env ]; then - export $(grep -v '^#' .env | xargs) -fi +set -o allexport +source .env +set +o allexport # 启动 PocketBase pb/pocketbase serve --http=0.0.0.0:8090 & diff --git a/core/scripts/start_backend.sh b/core/scripts/start_backend.sh deleted file mode 100644 index f00cef6..0000000 --- a/core/scripts/start_backend.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -o allexport -source .env -set +o allexport -exec uvicorn backend:app --reload --host localhost --port 8077 \ No newline at end of file diff --git a/core/scripts/start_pb.sh b/core/scripts/start_pb.sh deleted file mode 100644 index c577224..0000000 --- a/core/scripts/start_pb.sh +++ /dev/null @@ -1 +0,0 @@ -pb/pocketbase serve \ No newline at end of file diff --git a/core/scripts/start_tasks.sh b/core/scripts/start_tasks.sh deleted file mode 100644 index 34613d0..0000000 --- a/core/scripts/start_tasks.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -o allexport -source .env -set +o allexport -exec python tasks.py \ No newline at end of file From de549c6334e7908ed78622aa72a23619604faa5c Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Sun, 8 Dec 2024 21:30:39 +0800 Subject: [PATCH 7/9] fix: erros --- README.md | 2 +- core/agents/get_info.py | 53 +- core/custom_scraper/README.md | 80 ++- core/custom_scraper/README_EN.md | 85 +++ core/custom_scraper/mp.py | 31 +- core/general_process.py | 12 +- core/pb/CHANGELOG.md | 1016 ------------------------------ core/pb/README.md | 2 +- 8 files changed, 216 insertions(+), 1065 deletions(-) create mode 100644 core/custom_scraper/README_EN.md delete mode 100644 core/pb/CHANGELOG.md diff --git a/README.md b/README.md index 3f2374d..6174e4e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ **我们缺的不是信息,而是从海量信息中过滤噪音,从而让有价值的信息显露出来** -## 🔥 V0.3.8版本预告 +## 🔥 隆重介绍精准产品定位下的全新架构 V0.3.2版本 wiseflow 预计将在2024.12月底前正式升级到0.3.8版本,这也将是 V0.3.x 架构下的最终版本(除非有足够多的小修改,否则不会有 V0.3.9版本) diff --git a/core/agents/get_info.py b/core/agents/get_info.py index d8769c2..6f81eee 100644 --- a/core/agents/get_info.py +++ b/core/agents/get_info.py @@ -3,7 +3,7 @@ from llms.openai_wrapper import openai_llm as llm from utils.general_utils import is_chinese, extract_and_convert_dates, extract_urls from loguru import logger from utils.pb_api import PbTalker -import os +import os, re from datetime import datetime from urllib.parse import urlparse import json_repair @@ -56,7 +56,12 @@ class GeneralInfoExtractor: 如果网页文本中不包含任何与兴趣点相关的信息,请仅输出:[]。''' self.get_more_link_prompt = f"作为一位高效的信息筛选助手,你的任务是根据给定的兴趣点,从给定的文本及其对应的URL中挑选出最值得关注的URL。兴趣点及其解释如下:\n\n{focus_statement}" - self.get_more_link_suffix = "请逐条分析:对于每一条,首先复制文本,然后给出分析依据,最后给出结论。如果决定挑选该条,在结论后复制对应的url,否则的话直接进入下一条的分析。请一条一条的分析,不要漏掉任何一条。" + self.get_more_link_suffix = '''请逐条分析,先逐一给出分析依据,最终将挑选出的 url 按一行一条的格式输出,最终输出的 url 列表整体用三引号包裹,三引号内不要有其他内容,如下是输出格式示例: +""" +url1 +url2 +... +"""''' else: self.get_info_prompt = f'''As an information extraction assistant, your task is to extract content related to the following user focus points from the given web page text. The list of focus points and their explanations is as follows: @@ -76,7 +81,12 @@ Example: If the webpage text does not contain any information related to points of interest, please output only: []''' self.get_more_link_prompt = f"As an efficient information filtering assistant, your task is to select the most noteworthy URLs from a set of texts and their corresponding URLs based on the given focus points. The focus points and their explanations are as follows:\n\n{focus_statement}" - self.get_more_link_suffix = "Please analyze each item one by one: For each item, first copy the text, then provide the analysis basis, and finally give the conclusion. If the decision is to select the item, copy the corresponding URL after the conclusion; otherwise, proceed directly to the analysis of the next item. Analyze each item one by one, without missing any." + self.get_more_link_suffix = '''Please analyze one by one, first give the analysis basis one by one, and finally output the selected URLs in a row-by-row format. The final output URL list is wrapped in three quotes as a whole, and there should be no other content in the three quotes. Here is an example of the output format: +""" +url1 +url2 +... +"""''' async def get_author_and_publish_date(self, text: str) -> tuple[str, str]: if not text: @@ -107,10 +117,10 @@ If the webpage text does not contain any information related to points of intere return result['source'], extract_and_convert_dates(result['publish_date']) - async def get_more_related_urls(self, link_dict: dict) -> set[str]: + async def get_more_related_urls(self, link_dict: dict, og_url: str) -> set[str]: if not link_dict: return set() - + self.logger.debug(f'{len(link_dict)} items to analyze') urls = set() content = '' for key, value in link_dict.items(): @@ -118,24 +128,33 @@ If the webpage text does not contain any information related to points of intere if len(content) > 512: result = await llm([{'role': 'system', 'content': self.get_more_link_prompt}, {'role': 'user', 'content': f'{content}\n{self.get_more_link_suffix}'}], - model=self.secondary_model, temperature=0.1) + model=self.model, temperature=0.1) self.logger.debug(f'get_more_related_urls llm output:\n{result}') - urls.update(extract_urls(result)) + result = re.findall(r'"""(.*?)"""', result, re.DOTALL) + if result: + result = result[0].strip() + self.logger.debug(f"cleaned output: {result}") + urls.update(extract_urls(result)) content = '' if content: result = await llm([{'role': 'system', 'content': self.get_more_link_prompt}, {'role': 'user', 'content': f'{content}\n{self.get_more_link_suffix}'}], - model=self.secondary_model, temperature=0.1) + model=self.model, temperature=0.1) self.logger.debug(f'get_more_related_urls llm output:\n{result}') - urls.update(extract_urls(result)) + result = re.findall(r'"""(.*?)"""', result, re.DOTALL) + if result: + result = result[0].strip() + self.logger.debug(f"cleaned output: {result}") + urls.update(extract_urls(result)) - raw_urls = list(link_dict.values()) - for url in urls: - if url not in raw_urls: - self.logger.warning(f"{url} not in link_dict, it's model's Hallucination") - urls.remove(url) - return urls + raw_urls = set(link_dict.values()) + urls.discard(og_url) + hallucination_urls = urls - raw_urls + if hallucination_urls: + self.logger.warning(f"{hallucination_urls} not in link_dict, it's model's Hallucination") + + return urls & raw_urls async def get_info(self, text: str, info_pre_fix: str, link_dict: dict) -> list[dict]: if not text: @@ -153,7 +172,7 @@ If the webpage text does not contain any information related to points of intere self.logger.warning("failed to parse from llm output") return [] if not result: - self.logger.info("no info found") + self.logger.debug("no info found") return [] system = '''判断给定的信息是否与网页文本相符。信息将用标签包裹,网页文本则用包裹。请遵循如下工作流程: @@ -209,7 +228,7 @@ If the webpage text does not contain any information related to points of intere if not publish_date or publish_date.lower() == 'na': publish_date = datetime.now().strftime('%Y-%m-%d') - related_urls = await self.get_more_related_urls(link_dict) + related_urls = await self.get_more_related_urls(link_dict, base_url) info_prefix = f"//{author} {publish_date}//" lines = text.split('\n') diff --git a/core/custom_scraper/README.md b/core/custom_scraper/README.md index fd7c7a0..98d0e60 100644 --- a/core/custom_scraper/README.md +++ b/core/custom_scraper/README.md @@ -1,41 +1,83 @@ +# wiseflow 自定义解析器说明 + +## 概述 wiseflow 致力于通过一套通用流程(使用大模型驱动的可以自主使用爬虫工具的智能体)处理所有页面。 -不过我们也为客户保留自定义处理的灵活性。您可以在这里添加并注册针对特定域名的自定义爬虫。 +目前在页面获取方面我们使用流行的爬虫框架 Crawlee(playwright)进行统一管理,经过实测 Crawlee 在速度和兼容性方面都非常不错,且有着完善的任务队列管理模块,因此网页获取方面一般无需自定义。 -请遵照如下规范: +对于页面信息的解析,wiseflow 默认使用大模型,但用户可以为特定域名配置自定义解析器。 -1、爬虫应该是一个函数(而不是类); +## 自定义解析器配置说明 -2、入参只接受两个:**url**(要处理的 url,请只提供一个 url,而不是列表,因为主函数会处理队列逻辑) 和 **logger** 对象(这意味着不要为你的自定义爬虫添加日志对象,wiseflow 会统一管理); +### 1. Scraper 函数定义 +Scraper 应该是一个函数(而不是类)。 -3、出参必须为两个,一个是解析后的文章详情 article,类型为 dict,另一个是从页面解析出的外链字典 link_dict,类型也是 dict。 +### 2. 函数参数 +该函数接收两个入参(wiseflow 框架传入): +- `html`:这是 wiseflow 通过 Crawlee 的 playwright_crawler 获取到的渲染后的页面 html 代码,类型为 `str`,scraper 可以直接使用 `bs` `parsel`等库进行解析; +- `url`:当前页面的 url 地址,类型为 `str`(仅是为了特殊操作,用不到的话可以直接忽略)。 -article 的字典格式如下(注意,'content' 是必须的,其他也可以没有,另外额外的键值信息会被忽略): +### 3. 函数返回值 +Scraper 出参限定为三个: -`{'url': ..., 'title': ..., 'author': ..., 'publish_date': ..., 'screenshot': ..., 'content': ...(not empty)}` +#### 3.1 `article` +解析出的页面详情,类型为 `dict`,格式如下(**注意,'content' 是必须的,其他可以没有,额外的键值信息会被忽略**): -上述值的类型都要求为 **str**, 日期格式为 **YYYY-MM-DD**,screenshot 为**文件路径**,可以是相对于 core目录的相对路径也可以是绝对路径,文件类型为 **png**。 +```python +{ + 'url': ..., + 'author': ..., + 'publish_date': ..., + 'screenshot': ..., + 'content': ...(not empty) +} +``` + +- 上述值的类型都要求为 `str`,日期格式为 `YYYY-MM-DD`,screenshot 为**文件路径**,可以是相对于 core 目录的相对路径也可以是绝对路径,文件类型为 `png`。 **注意:** -- 'content' 要有且不为空,不然无法触发后续的提取,文章也会被舍弃。这是唯一要求不为空的项; -- 'author' 和 'publish_date' 尽量有,不然 wiseflow 会自动用域名对应 demain 和 当日日期代替。 +1. `'content'` 要有且不为空,不然无法触发后续的提取,文章也会被舍弃。这是唯一要求不为空的项; +2. `'author'` 和 `'publish_date'` 尽量有,不然 wiseflow 会自动用域名对应 demain 和 当日日期代替。 -link_dict 的格式如下: -`{'text': 外链对应的文字信息, 'url': 外链对应的 url}` +#### 3.2 `links` +对应页面解析出的链接,类型可以是 `set`,也可以是 `dict`: + +- 如果是 `set`,则会全部被加入任务队列。 +- 如果是 `dict`,则会调用 llm 从中挑取值得加入任务队列的 url(根据你的 focus point),`dict` 的格式如下: + +```python +{ + 'text': 外链对应的文字信息, + 'url': 外链对应的 url +} +``` wiseflow 会以这个为输入,使用 llm 判断值得继续爬取的链接。 -4、在 core/custom_crawlers/__init__.py 中注册,参考: +#### 3.3 `infos` +对应页面抽取出的值得关注的信息列表,类型是 `list`,元素为 `dict`,格式为: -```pyhton -from .mp import mp_crawler - -customer_crawler_map = {'mp.weixin.qq.com': mp_crawler} +```python +{ + 'tag': focuspoint 的 id, + 'content': 具体 info 内容 +} ``` -注意键使用域名,可以使用 urllib.parse获取: +**注意,focuspoint 的 id 要和 pb 中 focus_points 表一致** -```pyhton +### 4. 注册自定义解析器 +在 `core/custom_scraper/__init__.py` 中注册,参考: + +```python +from .mp import mp_scarper + +customer_crawler_map = {'mp.weixin.qq.com': mp_scarper} +``` + +注意键使用域名,可以使用 `urllib.parse` 获取: + +```python from urllib.parse import urlparse parsed_url = urlparse("site's url") diff --git a/core/custom_scraper/README_EN.md b/core/custom_scraper/README_EN.md new file mode 100644 index 0000000..595477c --- /dev/null +++ b/core/custom_scraper/README_EN.md @@ -0,0 +1,85 @@ +# wiseflow Custom Parser Instructions + +## Overview +wiseflow is committed to processing all pages through a universal process (an intelligent agent driven by large models that can autonomously use web scraping tools). + +Currently, we use the popular web scraping framework Crawlee (playwright) for unified management in page acquisition. After practical testing, Crawlee performs well in terms of speed and compatibility, and has a robust task queue management module, so customizations are generally unnecessary for web page acquisition. + +For page information parsing, wiseflow uses large models by default, but users can configure custom parsers for specific domains. + +## Custom Parser Configuration Instructions + +### 1. Scraper Function Definition +The Scraper should be a function (not a class). + +### 2. Function Parameters +The function receives two input parameters (passed by the wiseflow framework): +- `html`: This is the rendered page HTML code obtained by wiseflow through Crawlee's playwright_crawler, of type `str`. The scraper can directly use libraries like `bs` and `parsel` for parsing; +- `url`: The URL address of the current page, of type `str` (only for special operations, can be ignored if not needed). + +### 3. Function Return Values +The Scraper output is limited to three: + +#### 3.1 `article` +The parsed page details, of type `dict`, with the following format (**note that 'content' is mandatory, others can be omitted, and extra key-value information will be ignored**): + +```python +{ + 'url': ..., + 'author': ..., + 'publish_date': ..., + 'screenshot': ..., + 'content': ...(not empty) +} +``` + +- The types of the above values are all required to be `str`, with the date format being `YYYY-MM-DD`, and the screenshot being a **file path**, which can be a relative path to the core directory or an absolute path, with the file type being `png`. + +**Note:** +1. `'content'` must be present and not empty, otherwise subsequent extraction cannot be triggered, and the article will be discarded. This is the only non-empty requirement; +2. `'author'` and `'publish_date'` should be included if possible, otherwise wiseflow will automatically use the domain corresponding to the demain and the current date. + +#### 3.2 `links` +The links parsed from the corresponding page, the type can be `set` or `dict`: + +- If it is a `set`, all will be added to the task queue. +- If it is a `dict`, llm will be called to select URLs worth adding to the task queue (based on your focus point), with the format of the `dict` as follows: + +```python +{ + 'text': text information corresponding to the external link, + 'url': url corresponding to the external link +} +``` + +wiseflow will use this as input to determine the links worth continuing to crawl using llm. + +#### 3.3 `infos` +The list of noteworthy information extracted from the corresponding page, of type `list`, with elements being `dict`, in the following format: + +```python +{ + 'tag': id of the focuspoint, + 'content': specific info content +} +``` + +**Note that the id of the focuspoint must match the focus_points table in pb** + +### 4. Register Custom Parser +Register in `core/custom_scraper/__init__.py`, for reference: + +```python +from .mp import mp_scarper + +customer_crawler_map = {'mp.weixin.qq.com': mp_scarper} +``` + +Note that the key uses the domain name, which can be obtained using `urllib.parse`: + +```python +from urllib.parse import urlparse + +parsed_url = urlparse("site's url") +domain = parsed_url.netloc +``` \ No newline at end of file diff --git a/core/custom_scraper/mp.py b/core/custom_scraper/mp.py index 618656d..5fd51a4 100644 --- a/core/custom_scraper/mp.py +++ b/core/custom_scraper/mp.py @@ -3,18 +3,37 @@ from bs4 import BeautifulSoup from datetime import datetime import os, re -from utils.general_utils import get_logger +import logging project_dir = os.environ.get("PROJECT_DIR", "") if project_dir: os.makedirs(project_dir, exist_ok=True) -mp_logger = get_logger('mp_scraper', project_dir) +log_formatter = logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +# create logger and set level to debug +logger = logging.getLogger('mp_scraper') +logger.handlers = [] +logger.setLevel('DEBUG') +logger.propagate = False + +# create file handler and set level to debug +file = os.path.join(project_dir, 'mp_scraper.log') +file_handler = logging.FileHandler(file, 'a', encoding='utf-8') +file_handler.setLevel('INFO') +file_handler.setFormatter(log_formatter) +logger.addHandler(file_handler) + +# create console handler and set level to info +console_handler = logging.StreamHandler() +console_handler.setLevel('DEBUG') +console_handler.setFormatter(log_formatter) +logger.addHandler(console_handler) async def mp_scraper(html: str, url: str) -> tuple[dict, set, list]: if not url.startswith('https://mp.weixin.qq.com') and not url.startswith('http://mp.weixin.qq.com'): - mp_logger.warning(f'{url} is not a mp url, you should not use this function') + logger.warning(f'{url} is not a mp url, you should not use this function') return {}, set(), [] url = url.replace("http://", "https://", 1) @@ -50,12 +69,12 @@ async def mp_scraper(html: str, url: str) -> tuple[dict, set, list]: else soup.find('h1', class_='rich_media_title').text.strip() profile_nickname = soup.find('div', class_='wx_follow_nickname').text.strip() except Exception as e: - mp_logger.warning(f"not mp format: {url}\n{e}") + logger.warning(f"not mp format: {url}\n{e}") # For mp.weixin.qq.com types, mp_crawler won't work, and most likely neither will the other two return {}, set(), [] if not rich_media_title or not profile_nickname: - mp_logger.warning(f"failed to analysis {url}, no title or profile_nickname") + logger.warning(f"failed to analysis {url}, no title or profile_nickname") return {}, set(), [] # Parse text and image links within the content interval @@ -72,7 +91,7 @@ async def mp_scraper(html: str, url: str) -> tuple[dict, set, list]: cleaned_texts = [t for t in texts if t.strip()] content = '\n'.join(cleaned_texts) else: - mp_logger.warning(f"failed to analysis contents {url}") + logger.warning(f"failed to analysis contents {url}") return {}, set(), [] if content: content = f"[from {profile_nickname}]{content}" diff --git a/core/general_process.py b/core/general_process.py index 199d48d..c21e53e 100644 --- a/core/general_process.py +++ b/core/general_process.py @@ -10,7 +10,7 @@ from custom_scraper import custom_scraper_map from urllib.parse import urlparse, urljoin import hashlib from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext -from datetime import datetime +from datetime import datetime, timedelta project_dir = os.environ.get("PROJECT_DIR", "") @@ -55,6 +55,8 @@ async def save_to_pb(article: dict, infos: list): crawler = PlaywrightCrawler( # Limit the crawl to max requests. Remove or increase it for crawling all links. # max_requests_per_crawl=1, + max_request_retries=2, + request_handler_timeout=timedelta(minutes=5), headless=False if os.environ.get("VERBOSE", "").lower() in ["true", "1"] else True ) @crawler.router.default_handler @@ -85,8 +87,8 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None: wiseflow_logger.warning(f'{parsed_url} handled by customer scraper, bot got nothing') return - title = article.get('title', "") - link_dict = more_urls if isinstance(more_urls, dict) else None + #title = article.get('title', "") + link_dict = more_urls if isinstance(more_urls, dict) else {} related_urls = more_urls if isinstance(more_urls, set) else set() if not infos and not related_urls: text = article.pop('content') if 'content' in article else None @@ -127,7 +129,7 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None: author = soup.find('div', class_='source').get_text(strip=True) if soup.find('div', class_='source') else None # get infos by llm infos, related_urls, author, publish_date = await gie(text, link_dict, base_url, author, publish_date) - title = await context.page.title() + # title = await context.page.title() screenshot_file_name = f"{hashlib.sha256(context.request.url.encode()).hexdigest()}.png" await context.page.screenshot(path=os.path.join(screenshot_dir, screenshot_file_name), full_page=True) @@ -136,7 +138,7 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None: if infos: article = { 'url': context.request.url, - 'title': title, + # 'title': title, 'author': author, 'publish_date': publish_date, 'screenshot': os.path.join(screenshot_dir, screenshot_file_name), diff --git a/core/pb/CHANGELOG.md b/core/pb/CHANGELOG.md deleted file mode 100644 index ab2136a..0000000 --- a/core/pb/CHANGELOG.md +++ /dev/null @@ -1,1016 +0,0 @@ -## v0.22.12 - -- Fixed calendar picker grid layout misalignment on Firefox ([#4865](https://github.com/pocketbase/pocketbase/issues/4865)). - -- Updated Go deps and bumped the min Go version in the GitHub release action to Go 1.22.3 since it comes with [some minor security fixes](https://github.com/golang/go/issues?q=milestone%3AGo1.22.3). - - -## v0.22.11 - -- Load the full record in the relation picker edit panel ([#4857](https://github.com/pocketbase/pocketbase/issues/4857)). - - -## v0.22.10 - -- Updated the uploaded filename normalization to take double extensions in consideration ([#4824](https://github.com/pocketbase/pocketbase/issues/4824)) - -- Added Collection models cache to help speed up the common List and View requests execution with ~25%. - _This was extracted from the ongoing work on [#4355](https://github.com/pocketbase/pocketbase/discussions/4355) and there are many other small optimizations already implemented but they will have to wait for the refactoring to be finalized._ - - -## v0.22.9 - -- Fixed Admin UI OAuth2 "Clear all fields" btn action to properly unset all form fields ([#4737](https://github.com/pocketbase/pocketbase/issues/4737)). - - -## v0.22.8 - -- Fixed '~' auto wildcard wrapping when the param has escaped `%` character ([#4704](https://github.com/pocketbase/pocketbase/discussions/4704)). - -- Other minor UI improvements (added `aria-expanded=true/false` to the dropdown triggers, added contrasting border around the default mail template btn style, etc.). - -- Updated Go deps and bumped the min Go version in the GitHub release action to Go 1.22.2 since it comes with [some `net/http` security and bug fixes](https://github.com/golang/go/issues?q=milestone%3AGo1.22.2). - - -## v0.22.7 - -- Replaced the default `s3blob` driver with a trimmed vendored version to reduce the binary size with ~10MB. - _It can be further reduced with another ~10MB once we replace entirely the `aws-sdk-go-v2` dependency but I stumbled on some edge cases related to the headers signing and for now is on hold._ - -- Other minor improvements (updated GitLab OAuth2 provider logo [#4650](https://github.com/pocketbase/pocketbase/pull/4650), normalized error messages, updated npm dependencies, etc.) - - -## v0.22.6 - -- Admin UI accessibility improvements: - - Fixed the dropdowns tab/enter/space keyboard navigation ([#4607](https://github.com/pocketbase/pocketbase/issues/4607)). - - Added `role`, `aria-label`, `aria-hidden` attributes to some of the elements in attempt to better assist screen readers. - - -## v0.22.5 - -- Minor test helpers fixes ([#4600](https://github.com/pocketbase/pocketbase/issues/4600)): - - Call the `OnTerminate` hook on `TestApp.Cleanup()`. - - Automatically run the DB migrations on initializing the test app with `tests.NewTestApp()`. - -- Added more elaborate warning message when restoring a backup explaining how the operation works. - -- Skip irregular files (symbolic links, sockets, etc.) when restoring a backup zip from the Admin UI or calling `archive.Extract(src, dst)` because they come with too many edge cases and ambiguities. -
- More details - - This was initially reported as security issue (_thanks Harvey Spec_) but in the PocketBase context it is not something that can be exploited without an admin intervention and since the general expectations are that the PocketBase admins can do anything and they are the one who manage their server, this should be treated with the same diligence when using `scp`/`rsync`/`rclone`/etc. with untrusted file sources. - - It is not possible (_or at least I'm not aware how to do that easily_) to perform virus/malicious content scanning on the uploaded backup archive files and some caution is always required when using the Admin UI or running shell commands, hence the backup-restore warning text. - - **Or in other words, if someone sends you a file and tell you to upload it to your server (either as backup zip or manually via scp) obviously you shouldn't do that unless you really trust them.** - - PocketBase is like any other regular application that you run on your server and there is no builtin "sandbox" for what the PocketBase process can execute. This is left to the developers to restrict on application or OS level depending on their needs. If you are self-hosting PocketBase you usually don't have to do that, but if you are offering PocketBase as a service and allow strangers to run their own PocketBase instances on your server then you'll need to implement the isolation mechanisms on your own. -
- - -## v0.22.4 - -- Removed conflicting styles causing the detailed codeblock log data preview to not visualize properly ([#4505](https://github.com/pocketbase/pocketbase/pull/4505)). - -- Minor JSVM improvements: - - Added `$filesystem.fileFromUrl(url, optSecTimeout)` helper. - - Implemented the `FormData` interface and added support for sending `multipart/form-data` requests with `$http.send()` ([#4544](https://github.com/pocketbase/pocketbase/discussions/4544)). - - -## v0.22.3 - -- Fixed the z-index of the current admin dropdown on Safari ([#4492](https://github.com/pocketbase/pocketbase/issues/4492)). - -- Fixed `OnAfterApiError` debug log `nil` error reference ([#4498](https://github.com/pocketbase/pocketbase/issues/4498)). - -- Added the field name as part of the `@request.data.someRelField.*` join to handle the case when a collection has 2 or more relation fields pointing to the same place ([#4500](https://github.com/pocketbase/pocketbase/issues/4500)). - -- Updated Go deps and bumped the min Go version in the GitHub release action to Go 1.22.1 since it comes with [some security fixes](https://github.com/golang/go/issues?q=milestone%3AGo1.22.1). - - -## v0.22.2 - -- Fixed a small regression introduced with v0.22.0 that was causing some missing unknown fields to always return an error instead of applying the specific `nullifyMisingField` resolver option to the query. - - -## v0.22.1 - -- Fixed Admin UI record and collection panels not reinitializing properly on browser back/forward navigation ([#4462](https://github.com/pocketbase/pocketbase/issues/4462)). - -- Initialize `RecordAuthWithOAuth2Event.IsNewRecord` for the `OnRecordBeforeAuthWithOAuth2Request` hook ([#4437](https://github.com/pocketbase/pocketbase/discussions/4437)). - -- Added error checks to the autogenerated Go migrations ([#4448](https://github.com/pocketbase/pocketbase/issues/4448)). - - -## v0.22.0 - -- Added Planning Center OAuth2 provider ([#4393](https://github.com/pocketbase/pocketbase/pull/4393); thanks @alxjsn). - -- Admin UI improvements: - - Autosync collection changes across multiple open browser tabs. - - Fixed vertical image popup preview scrolling. - - Added options to export a subset of collections. - - Added option to import a subset of collections without deleting the others ([#3403](https://github.com/pocketbase/pocketbase/issues/3403)). - -- Added support for back/indirect relation `filter`/`sort` (single and multiple). - The syntax to reference back relation fields is `yourCollection_via_yourRelField.*`. - ⚠️ To avoid excessive joins, the nested relations resolver is now limited to max 6 level depth (the same as `expand`). - _Note that in the future there will be also more advanced and granular options to specify a subset of the fields that are filterable/sortable._ - -- Added support for multiple back/indirect relation `expand` and updated the keys to use the `_via_` reference syntax (`yourCollection_via_yourRelField`). - _To minimize the breaking changes, the old parenthesis reference syntax (`yourCollection(yourRelField)`) will still continue to work but it is soft-deprecated and there will be a console log reminding you to change it to the new one._ - -- ⚠️ Collections and fields are no longer allowed to have `_via_` in their name to avoid collisions with the back/indirect relation reference syntax. - -- Added `jsvm.Config.OnInit` optional config function to allow registering custom Go bindings to the JSVM. - -- Added `@request.context` rule field that can be used to apply a different set of constraints based on the API rule execution context. - For example, to disallow user creation by an OAuth2 auth, you could set for the users Create API rule `@request.context != "oauth2"`. - The currently supported `@request.context` values are: - ``` - default - realtime - protectedFile - oauth2 - ``` - -- Adjusted the `cron.Start()` to start the ticker at the `00` second of the cron interval ([#4394](https://github.com/pocketbase/pocketbase/discussions/4394)). - _Note that the cron format has only minute granularity and there is still no guarantee that the scheduled job will be always executed at the `00` second._ - -- Fixed auto backups cron not reloading properly after app settings change ([#4431](https://github.com/pocketbase/pocketbase/discussions/4431)). - -- Upgraded to `aws-sdk-go-v2` and added special handling for GCS to workaround the previous [GCS headers signature issue](https://github.com/pocketbase/pocketbase/issues/2231) that we had with v2. - _This should also fix the SVG/JSON zero response when using Cloudflare R2 ([#4287](https://github.com/pocketbase/pocketbase/issues/4287#issuecomment-1925168142), [#2068](https://github.com/pocketbase/pocketbase/discussions/2068), [#2952](https://github.com/pocketbase/pocketbase/discussions/2952))._ - _⚠️ If you are using S3 for uploaded files or backups, please verify that you have a green check in the Admin UI for your S3 configuration (I've tested the new version with GCS, MinIO, Cloudflare R2 and Wasabi)._ - -- Added `:each` modifier support for `file` and `relation` type fields (_previously it was supported only for `select` type fields_). - -- Other minor improvements (updated the `ghupdate` plugin to use the configured executable name when printing to the console, fixed the error reporting of `admin update/delete` commands, etc.). - - -## v0.21.3 - -- Ignore the JS required validations for disabled OIDC providers ([#4322](https://github.com/pocketbase/pocketbase/issues/4322)). - -- Allow `HEAD` requests to the `/api/health` endpoint ([#4310](https://github.com/pocketbase/pocketbase/issues/4310)). - -- Fixed the `editor` field value when visualized inside the View collection preview panel. - -- Manually clear all TinyMCE events on editor removal (_workaround for [tinymce#9377](https://github.com/tinymce/tinymce/issues/9377)_). - - -## v0.21.2 - -- Fixed `@request.auth.*` initialization side-effect which caused the current authenticated user email to not being returned in the user auth response ([#2173](https://github.com/pocketbase/pocketbase/issues/2173#issuecomment-1932332038)). - _The current authenticated user email should be accessible always no matter of the `emailVisibility` state._ - -- Fixed `RecordUpsert.RemoveFiles` godoc example. - -- Bumped to `NumCPU()+2` the `thumbGenSem` limit as some users reported that it was too restrictive. - - -## v0.21.1 - -- Small fix for the Admin UI related to the _Settings > Sync_ menu not being visible even when the "Hide controls" toggle is off. - - -## v0.21.0 - -- Added Bitbucket OAuth2 provider ([#3948](https://github.com/pocketbase/pocketbase/pull/3948); thanks @aabajyan). - -- Mark user as verified on confirm password reset ([#4066](https://github.com/pocketbase/pocketbase/issues/4066)). - _If the user email has changed after issuing the reset token (eg. updated by an admin), then the `verified` user state remains unchanged._ - -- Added support for loading a serialized json payload for `multipart/form-data` requests using the special `@jsonPayload` key. - _This is intended to be used primarily by the SDKs to resolve [js-sdk#274](https://github.com/pocketbase/js-sdk/issues/274)._ - -- Added graceful OAuth2 redirect error handling ([#4177](https://github.com/pocketbase/pocketbase/issues/4177)). - _Previously on redirect error we were returning directly a standard json error response. Now on redirect error we'll redirect to a generic OAuth2 failure screen (similar to the success one) and will attempt to auto close the OAuth2 popup._ - _The SDKs are also updated to handle the OAuth2 redirect error and it will be returned as Promise rejection of the `authWithOAuth2()` call._ - -- Exposed `$apis.gzip()` and `$apis.bodyLimit(bytes)` middlewares to the JSVM. - -- Added `TestMailer.SentMessages` field that holds all sent test app emails until cleanup. - -- Optimized the cascade delete of records with multiple `relation` fields. - -- Updated the `serve` and `admin` commands error reporting. - -- Minor Admin UI improvements (reduced the min table row height, added option to duplicate fields, added new TinyMCE codesample plugin languages, hide the collection sync settings when the `Settings.Meta.HideControls` is enabled, etc.) - - -## v0.20.7 - -- Fixed the Admin UI auto indexes update when renaming fields with a common prefix ([#4160](https://github.com/pocketbase/pocketbase/issues/4160)). - - -## v0.20.6 - -- Fixed JSVM types generation for functions with omitted arg types ([#4145](https://github.com/pocketbase/pocketbase/issues/4145)). - -- Updated Go deps. - - -## v0.20.5 - -- Minor CSS fix for the Admin UI to prevent the searchbar within a popup from expanding too much and pushing the controls out of the visible area ([#4079](https://github.com/pocketbase/pocketbase/issues/4079#issuecomment-1876994116)). - - -## v0.20.4 - -- Small fix for a regression introduced with the recent `json` field changes that was causing View collection column expressions recognized as `json` to fail to resolve ([#4072](https://github.com/pocketbase/pocketbase/issues/4072)). - - -## v0.20.3 - -- Fixed the `json` field query comparisons to work correctly with plain JSON values like `null`, `bool` `number`, etc. ([#4068](https://github.com/pocketbase/pocketbase/issues/4068)). - Since there are plans in the future to allow custom SQLite builds and also in some situations it may be useful to be able to distinguish `NULL` from `''`, - for the `json` fields (and for any other future non-standard field) we no longer apply `COALESCE` by default, aka.: - ``` - Dataset: - 1) data: json(null) - 2) data: json('') - - For the filter "data = null" only 1) will resolve to TRUE. - For the filter "data = ''" only 2) will resolve to TRUE. - ``` - -- Minor Go tests improvements - - Sorted the record cascade delete references to ensure that the delete operation will preserve the order of the fired events when running the tests. - - Marked some of the tests as safe for parallel execution to speed up a little the GitHub action build times. - - -## v0.20.2 - -- Added `sleep(milliseconds)` JSVM binding. - _It works the same way as Go `time.Sleep()`, aka. it pauses the goroutine where the JSVM code is running._ - -- Fixed multi-line text paste in the Admin UI search bar ([#4022](https://github.com/pocketbase/pocketbase/discussions/4022)). - -- Fixed the monospace font loading in the Admin UI. - -- Fixed various reported docs and code comment typos. - - -## v0.20.1 - -- Added `--dev` flag and its accompanying `app.IsDev()` method (_in place of the previously removed `--debug`_) to assist during development ([#3918](https://github.com/pocketbase/pocketbase/discussions/3918)). - The `--dev` flag prints in the console "everything" and more specifically: - - the data DB SQL statements - - all `app.Logger().*` logs (debug, info, warning, error, etc.), no matter of the logs persistence settings in the Admin UI - -- Minor Admin UI fixes: - - Fixed the log `error` label text wrapping. - - Added the log `referer` (_when it is from a different source_) and `details` labels in the logs listing. - - Removed the blank current time entry from the logs chart because it was causing confusion when used with custom time ranges. - - Updated the SQL syntax highlighter and keywords autocompletion in the Admin UI to recognize `CAST(x as bool)` expressions. - -- Replaced the default API tests timeout with a new `ApiScenario.Timeout` option ([#3930](https://github.com/pocketbase/pocketbase/issues/3930)). - A negative or zero value means no tests timeout. - If a single API test takes more than 3s to complete it will have a log message visible when the test fails or when `go test -v` flag is used. - -- Added timestamp at the beginning of the generated JSVM types file to avoid creating it everytime with the app startup. - - -## v0.20.0 - -- Added `expand`, `filter`, `fields`, custom query and headers parameters support for the realtime subscriptions. - _Requires JS SDK v0.20.0+ or Dart SDK v0.17.0+._ - - ```js - // JS SDK v0.20.0 - pb.collection("example").subscribe("*", (e) => { - ... - }, { - expand: "someRelField", - filter: "status = 'active'", - fields: "id,expand.someRelField.*:excerpt(100)", - }) - ``` - - ```dart - // Dart SDK v0.17.0 - pb.collection("example").subscribe("*", (e) { - ... - }, - expand: "someRelField", - filter: "status = 'active'", - fields: "id,expand.someRelField.*:excerpt(100)", - ) - ``` - -- Generalized the logs to allow any kind of application logs, not just requests. - - The new `app.Logger()` implements the standard [`log/slog` interfaces](https://pkg.go.dev/log/slog) available with Go 1.21. - ``` - // Go: https://pocketbase.io/docs/go-logging/ - app.Logger().Info("Example message", "total", 123, "details", "lorem ipsum...") - - // JS: https://pocketbase.io/docs/js-logging/ - $app.logger().info("Example message", "total", 123, "details", "lorem ipsum...") - ``` - - For better performance and to minimize blocking on hot paths, logs are currently written with - debounce and on batches: - - 3 seconds after the last debounced log write - - when the batch threshold is reached (currently 200) - - right before app termination to attempt saving everything from the existing logs queue - - Some notable log related changes: - - - ⚠️ Bumped the minimum required Go version to 1.21. - - - ⚠️ Removed `_requests` table in favor of the generalized `_logs`. - _Note that existing logs will be deleted!_ - - - ⚠️ Renamed the following `Dao` log methods: - ```go - Dao.RequestQuery(...) -> Dao.LogQuery(...) - Dao.FindRequestById(...) -> Dao.FindLogById(...) - Dao.RequestsStats(...) -> Dao.LogsStats(...) - Dao.DeleteOldRequests(...) -> Dao.DeleteOldLogs(...) - Dao.SaveRequest(...) -> Dao.SaveLog(...) - ``` - - ⚠️ Removed `app.IsDebug()` and the `--debug` flag. - This was done to avoid the confusion with the new logger and its debug severity level. - If you want to store debug logs you can set `-4` as min log level from the Admin UI. - - - Refactored Admin UI Logs: - - Added new logs table listing. - - Added log settings option to toggle the IP logging for the activity logger. - - Added log settings option to specify a minimum log level. - - Added controls to export individual or bulk selected logs as json. - - Other minor improvements and fixes. - -- Added new `filesystem/System.Copy(src, dest)` method to copy existing files from one location to another. - _This is usually useful when duplicating records with `file` field(s) programmatically._ - -- Added `filesystem.NewFileFromUrl(ctx, url)` helper method to construct a `*filesystem.BytesReader` file from the specified url. - -- OAuth2 related additions: - - - Added new `PKCE()` and `SetPKCE(enable)` OAuth2 methods to indicate whether the PKCE flow is supported or not. - _The PKCE value is currently configurable from the UI only for the OIDC providers._ - _This was added to accommodate OIDC providers that may throw an error if unsupported PKCE params are submitted with the auth request (eg. LinkedIn; see [#3799](https://github.com/pocketbase/pocketbase/discussions/3799#discussioncomment-7640312))._ - - - Added new `displayName` field for each `listAuthMethods()` OAuth2 provider item. - _The value of the `displayName` property is currently configurable from the UI only for the OIDC providers._ - - - Added `expiry` field to the OAuth2 user response containing the _optional_ expiration time of the OAuth2 access token ([#3617](https://github.com/pocketbase/pocketbase/discussions/3617)). - - - Allow a single OAuth2 user to be used for authentication in multiple auth collection. - _⚠️ Because now you can have more than one external provider with `collectionId-provider-providerId` pair, `Dao.FindExternalAuthByProvider(provider, providerId)` method was removed in favour of the more generic `Dao.FindFirstExternalAuthByExpr(expr)`._ - -- Added `onlyVerified` auth collection option to globally disallow authentication requests for unverified users. - -- Added support for single line comments (ex. `// your comment`) in the API rules and filter expressions. - -- Added support for specifying a collection alias in `@collection.someCollection:alias.*`. - -- Soft-deprecated and renamed `app.Cache()` with `app.Store()`. - -- Minor JSVM updates and fixes: - - - Updated `$security.parseUnverifiedJWT(token)` and `$security.parseJWT(token, key)` to return the token payload result as plain object. - - - Added `$apis.requireGuestOnly()` middleware JSVM binding ([#3896](https://github.com/pocketbase/pocketbase/issues/3896)). - -- Use `IS NOT` instead of `!=` as not-equal SQL query operator to handle the cases when comparing with nullable columns or expressions (eg. `json_extract` over `json` field). - _Based on my local dataset I wasn't able to find a significant difference in the performance between the 2 operators, but if you stumble on a query that you think may be affected negatively by this, please report it and I'll test it further._ - -- Added `MaxSize` `json` field option to prevent storing large json data in the db ([#3790](https://github.com/pocketbase/pocketbase/issues/3790)). - _Existing `json` fields are updated with a system migration to have a ~2MB size limit (it can be adjusted from the Admin UI)._ - -- Fixed negative string number normalization support for the `json` field type. - -- Trigger the `app.OnTerminate()` hook on `app.Restart()` call. - _A new bool `IsRestart` field was also added to the `core.TerminateEvent` event._ - -- Fixed graceful shutdown handling and speed up a little the app termination time. - -- Limit the concurrent thumbs generation to avoid high CPU and memory usage in spiky scenarios ([#3794](https://github.com/pocketbase/pocketbase/pull/3794); thanks @t-muehlberger). - _Currently the max concurrent thumbs generation processes are limited to "total of logical process CPUs + 1"._ - _This is arbitrary chosen and may change in the future depending on the users feedback and usage patterns._ - _If you are experiencing OOM errors during large image thumb generations, especially in container environment, you can try defining the `GOMEMLIMIT=500MiB` env variable before starting the executable._ - -- Slightly speed up (~10%) the thumbs generation by changing from cubic (`CatmullRom`) to bilinear (`Linear`) resampling filter (_the quality difference is very little_). - -- Added a default red colored Stderr output in case of a console command error. - _You can now also silence individually custom commands errors using the `cobra.Command.SilenceErrors` field._ - -- Fixed links formatting in the autogenerated html->text mail body. - -- Removed incorrectly imported empty `local('')` font-face declarations. - - -## v0.19.4 - -- Fixed TinyMCE source code viewer textarea styles ([#3715](https://github.com/pocketbase/pocketbase/issues/3715)). - -- Fixed `text` field min/max validators to properly count multi-byte characters ([#3735](https://github.com/pocketbase/pocketbase/issues/3735)). - -- Allowed hyphens in `username` ([#3697](https://github.com/pocketbase/pocketbase/issues/3697)). - _More control over the system fields settings will be available in the future._ - -- Updated the JSVM generated types to use directly the value type instead of `* | undefined` union in functions/methods return declarations. - - -## v0.19.3 - -- Added the release notes to the console output of `./pocketbase update` ([#3685](https://github.com/pocketbase/pocketbase/discussions/3685)). - -- Added missing documentation for the JSVM `$mails.*` bindings. - -- Relaxed the OAuth2 redirect url validation to allow any string value ([#3689](https://github.com/pocketbase/pocketbase/pull/3689); thanks @sergeypdev). - _Note that the redirect url format is still bound to the accepted values by the specific OAuth2 provider._ - - -## v0.19.2 - -- Updated the JSVM generated types ([#3627](https://github.com/pocketbase/pocketbase/issues/3627), [#3662](https://github.com/pocketbase/pocketbase/issues/3662)). - - -## v0.19.1 - -- Fixed `tokenizer.Scan()/ScanAll()` to ignore the separators from the default trim cutset. - An option to return also the empty found tokens was also added via `Tokenizer.KeepEmptyTokens(true)`. - _This should fix the parsing of whitespace characters around view query column names when no quotes are used ([#3616](https://github.com/pocketbase/pocketbase/discussions/3616#discussioncomment-7398564))._ - -- Fixed the `:excerpt(max, withEllipsis?)` `fields` query param modifier to properly add space to the generated text fragment after block tags. - - -## v0.19.0 - -- Added Patreon OAuth2 provider ([#3323](https://github.com/pocketbase/pocketbase/pull/3323); thanks @ghostdevv). - -- Added mailcow OAuth2 provider ([#3364](https://github.com/pocketbase/pocketbase/pull/3364); thanks @thisni1s). - -- Added support for `:excerpt(max, withEllipsis?)` `fields` modifier that will return a short plain text version of any string value (html tags are stripped). - This could be used to minimize the downloaded json data when listing records with large `editor` html values. - ```js - await pb.collection("example").getList(1, 20, { - "fields": "*,description:excerpt(100)" - }) - ``` - -- Several Admin UI improvements: - - Count the total records separately to speed up the query execution for large datasets ([#3344](https://github.com/pocketbase/pocketbase/issues/3344)). - - Enclosed the listing scrolling area within the table so that the horizontal scrollbar and table header are always reachable ([#2505](https://github.com/pocketbase/pocketbase/issues/2505)). - - Allowed opening the record preview/update form via direct URL ([#2682](https://github.com/pocketbase/pocketbase/discussions/2682)). - - Reintroduced the local `date` field tooltip on hover. - - Speed up the listing loading times for records with large `editor` field values by initially fetching only a partial of the records data (the complete record data is loaded on record preview/update). - - Added "Media library" (collection images picker) support for the TinyMCE `editor` field. - - Added support to "pin" collections in the sidebar. - - Added support to manually resize the collections sidebar. - - More clear "Nonempty" field label style. - - Removed the legacy `.woff` and `.ttf` fonts and keep only `.woff2`. - -- Removed the explicit `Content-Type` charset from the realtime response due to compatibility issues with IIS ([#3461](https://github.com/pocketbase/pocketbase/issues/3461)). - _The `Connection:keep-alive` realtime response header was also removed as it is not really used with HTTP2 anyway._ - -- Added new JSVM bindings: - - `new Cookie({ ... })` constructor for creating `*http.Cookie` equivalent value. - - `new SubscriptionMessage({ ... })` constructor for creating a custom realtime subscription payload. - - Soft-deprecated `$os.exec()` in favour of `$os.cmd()` to make it more clear that the call only prepares the command and doesn't execute it. - -- ⚠️ Bumped the min required Go version to 1.19. - - -## v0.18.10 - -- Added global `raw` template function to allow outputting raw/verbatim HTML content in the JSVM templates ([#3476](https://github.com/pocketbase/pocketbase/discussions/3476)). - ``` - {{.description|raw}} - ``` - -- Trimmed view query semicolon and allowed single quotes for column aliases ([#3450](https://github.com/pocketbase/pocketbase/issues/3450#issuecomment-1748044641)). - _Single quotes are usually [not a valid identifier quote characters](https://www.sqlite.org/lang_keywords.html), but for resilience and compatibility reasons SQLite allows them in some contexts where only an identifier is expected._ - -- Bumped the GitHub action to use [min Go 1.21.2](https://github.com/golang/go/issues?q=milestone%3AGo1.21.2) (_the fixed issues are not critical as they are mostly related to the compiler/build tools_). - - -## v0.18.9 - -- Fixed empty thumbs directories not getting deleted on Windows after deleting a record img file ([#3382](https://github.com/pocketbase/pocketbase/issues/3382)). - -- Updated the generated JSVM typings to silent the TS warnings when trying to access a field/method in a Go->TS interface. - - -## v0.18.8 - -- Minor fix for the View collections API Preview and Admin UI listings incorrectly showing the `created` and `updated` fields as `N/A` when the view query doesn't have them. - - -## v0.18.7 - -- Fixed JS error in the Admin UI when listing records with invalid `relation` field value ([#3372](https://github.com/pocketbase/pocketbase/issues/3372)). - _This could happen usually only during custom SQL import scripts or when directly modifying the record field value without data validations._ - -- Updated Go deps and the generated JSVM types. - - -## v0.18.6 - -- Return the response headers and cookies in the `$http.send()` result ([#3310](https://github.com/pocketbase/pocketbase/discussions/3310)). - -- Added more descriptive internal error message for missing user/admin email on password reset requests. - -- Updated Go deps. - - -## v0.18.5 - -- Fixed minor Admin UI JS error in the auth collection options panel introduced with the change from v0.18.4. - - -## v0.18.4 - -- Added escape character (`\`) support in the Admin UI to allow using `select` field values with comma ([#2197](https://github.com/pocketbase/pocketbase/discussions/2197)). - - -## v0.18.3 - -- Exposed a global JSVM `readerToString(reader)` helper function to allow reading Go `io.Reader` values ([#3273](https://github.com/pocketbase/pocketbase/discussions/3273)). - -- Bumped the GitHub action to use [min Go 1.21.1](https://github.com/golang/go/issues?q=milestone%3AGo1.21.1+label%3ACherryPickApproved) for the prebuilt executable since it contains some minor `html/template` and `net/http` security fixes. - - -## v0.18.2 - -- Prevent breaking the record form in the Admin UI in case the browser's localStorage quota has been exceeded when uploading or storing large `editor` values ([#3265](https://github.com/pocketbase/pocketbase/issues/3265)). - -- Updated docs and missing JSVM typings. - -- Exposed additional crypto primitives under the `$security.*` JSVM namespace ([#3273](https://github.com/pocketbase/pocketbase/discussions/3273)): - ```js - // HMAC with SHA256 - $security.hs256("hello", "secret") - - // HMAC with SHA512 - $security.hs512("hello", "secret") - - // compare 2 strings with a constant time - $security.equal(hash1, hash2) - ``` - - -## v0.18.1 - -- Excluded the local temp dir from the backups ([#3261](https://github.com/pocketbase/pocketbase/issues/3261)). - - -## v0.18.0 - -- Simplified the `serve` command to accept domain name(s) as argument to reduce any additional manual hosts setup that sometimes previously was needed when deploying on production ([#3190](https://github.com/pocketbase/pocketbase/discussions/3190)). - ```sh - ./pocketbase serve yourdomain.com - ``` - -- Added `fields` wildcard (`*`) support. - -- Added option to upload a backup file from the Admin UI ([#2599](https://github.com/pocketbase/pocketbase/issues/2599)). - -- Registered a custom Deflate compressor to speedup (_nearly 2-3x_) the backups generation for the sake of a small zip size increase. - _Based on several local tests, `pb_data` of ~500MB (from which ~350MB+ are several hundred small files) results in a ~280MB zip generated for ~11s (previously it resulted in ~250MB zip but for ~35s)._ - -- Added the application name as part of the autogenerated backup name for easier identification ([#3066](https://github.com/pocketbase/pocketbase/issues/3066)). - -- Added new `SmtpConfig.LocalName` option to specify a custom domain name (or IP address) for the initial EHLO/HELO exchange ([#3097](https://github.com/pocketbase/pocketbase/discussions/3097)). - _This is usually required for verification purposes only by some SMTP providers, such as on-premise [Gmail SMTP-relay](https://support.google.com/a/answer/2956491)._ - -- Added `NoDecimal` `number` field option. - -- `editor` field improvements: - - Added new "Strip urls domain" option to allow controlling the default TinyMCE urls behavior (_default to `false` for new content_). - - Normalized pasted text while still preserving links, lists, tables, etc. formatting ([#3257](https://github.com/pocketbase/pocketbase/issues/3257)). - -- Added option to auto generate admin and auth record passwords from the Admin UI. - -- Added JSON validation and syntax highlight for the `json` field in the Admin UI ([#3191](https://github.com/pocketbase/pocketbase/issues/3191)). - -- Added datetime filter macros: - ``` - // all macros are UTC based - @second - @now second number (0-59) - @minute - @now minute number (0-59) - @hour - @now hour number (0-23) - @weekday - @now weekday number (0-6) - @day - @now day number - @month - @now month number - @year - @now year number - @todayStart - beginning of the current day as datetime string - @todayEnd - end of the current day as datetime string - @monthStart - beginning of the current month as datetime string - @monthEnd - end of the current month as datetime string - @yearStart - beginning of the current year as datetime string - @yearEnd - end of the current year as datetime string - ``` - -- Added cron expression macros ([#3132](https://github.com/pocketbase/pocketbase/issues/3132)): - ``` - @yearly - "0 0 1 1 *" - @annually - "0 0 1 1 *" - @monthly - "0 0 1 * *" - @weekly - "0 0 * * 0" - @daily - "0 0 * * *" - @midnight - "0 0 * * *" - @hourly - "0 * * * *" - ``` - -- ⚠️ Added offset argument `Dao.FindRecordsByFilter(collection, filter, sort, limit, offset, [params...])`. - _If you don't need an offset, you can set it to `0`._ - -- To minimize the footguns with `Dao.FindFirstRecordByFilter()` and `Dao.FindRecordsByFilter()`, the functions now supports an optional placeholder params argument that is safe to be populated with untrusted user input. - The placeholders are in the same format as when binding regular SQL parameters. - ```go - // unsanitized and untrusted filter variables - status := "..." - author := "..." - - app.Dao().FindFirstRecordByFilter("articles", "status={:status} && author={:author}", dbx.Params{ - "status": status, - "author": author, - }) - - app.Dao().FindRecordsByFilter("articles", "status={:status} && author={:author}", "-created", 10, 0, dbx.Params{ - "status": status, - "author": author, - }) - ``` - -- Added JSVM `$mails.*` binds for the corresponding Go [mails package](https://pkg.go.dev/github.com/pocketbase/pocketbase/mails) functions. - -- Added JSVM helper crypto primitives under the `$security.*` namespace: - ```js - $security.md5(text) - $security.sha256(text) - $security.sha512(text) - ``` - -- ⚠️ Deprecated `RelationOptions.DisplayFields` in favor of the new `SchemaField.Presentable` option to avoid the duplication when a single collection is referenced more than once and/or by multiple other collections. - -- ⚠️ Fill the `LastVerificationSentAt` and `LastResetSentAt` fields only after a successfull email send ([#3121](https://github.com/pocketbase/pocketbase/issues/3121)). - -- ⚠️ Skip API `fields` json transformations for non 20x responses ([#3176](https://github.com/pocketbase/pocketbase/issues/3176)). - -- ⚠️ Changes to `tests.ApiScenario` struct: - - - The `ApiScenario.AfterTestFunc` now receive as 3rd argument `*http.Response` pointer instead of `*echo.Echo` as the latter is not really useful in this context. - ```go - // old - AfterTestFunc: func(t *testing.T, app *tests.TestApp, e *echo.Echo) - - // new - AfterTestFunc: func(t *testing.T, app *tests.TestApp, res *http.Response) - ``` - - - The `ApiScenario.TestAppFactory` now accept the test instance as argument and no longer expect an error as return result ([#3025](https://github.com/pocketbase/pocketbase/discussions/3025#discussioncomment-6592272)). - ```go - // old - TestAppFactory: func() (*tests.TestApp, error) - - // new - TestAppFactory: func(t *testing.T) *tests.TestApp - ``` - _Returning a `nil` app instance from the factory results in test failure. You can enforce a custom test failure by calling `t.Fatal(err)` inside the factory._ - -- Bumped the min required TLS version to 1.2 in order to improve the cert reputation score. - -- Reduced the default JSVM prewarmed pool size to 25 to reduce the initial memory consumptions (_you can manually adjust the pool size with `--hooksPool=50` if you need to, but the default should suffice for most cases_). - -- Update `gocloud.dev` dependency to v0.34 and explicitly set the new `NoTempDir` fileblob option to prevent the cross-device link error introduced with v0.33. - -- Other minor Admin UI and docs improvements. - - -## v0.17.7 - -- Fixed the autogenerated `down` migrations to properly revert the old collection rules in case a change was made in `up` ([#3192](https://github.com/pocketbase/pocketbase/pull/3192); thanks @impact-merlinmarek). - _Existing `down` migrations can't be fixed but that should be ok as usually the `down` migrations are rarely used against prod environments since they can cause data loss and, while not ideal, the previous old behavior of always setting the rules to `null/nil` is safer than not updating the rules at all._ - -- Updated some Go deps. - - -## v0.17.6 - -- Fixed JSVM `require()` file path error when using Windows-style path delimiters ([#3163](https://github.com/pocketbase/pocketbase/issues/3163#issuecomment-1685034438)). - - -## v0.17.5 - -- Added quotes around the wrapped view query columns introduced with v0.17.4. - - -## v0.17.4 - -- Fixed Views record retrieval when numeric id is used ([#3110](https://github.com/pocketbase/pocketbase/issues/3110)). - _With this fix we also now properly recognize `CAST(... as TEXT)` and `CAST(... as BOOLEAN)` as `text` and `bool` fields._ - -- Fixed `relation` "Cascade delete" tooltip message ([#3098](https://github.com/pocketbase/pocketbase/issues/3098)). - -- Fixed jsvm error message prefix on failed migrations ([#3103](https://github.com/pocketbase/pocketbase/pull/3103); thanks @nzhenev). - -- Disabled the initial Admin UI admins counter cache when there are no initial admins to allow detecting externally created accounts (eg. with the `admin` command) ([#3106](https://github.com/pocketbase/pocketbase/issues/3106)). - -- Downgraded `google/go-cloud` dependency to v0.32.0 until v0.34.0 is released to prevent the `os.TempDir` `cross-device link` errors as too many users complained about it. - - -## v0.17.3 - -- Fixed Docker `cross-device link` error when creating `pb_data` backups on a local mounted volume ([#3089](https://github.com/pocketbase/pocketbase/issues/3089)). - -- Fixed the error messages for relation to views ([#3090](https://github.com/pocketbase/pocketbase/issues/3090)). - -- Always reserve space for the scrollbar to reduce the layout shifts in the Admin UI records listing due to the deprecated `overflow: overlay`. - -- Enabled lazy loading for the Admin UI thumb images. - - -## v0.17.2 - -- Soft-deprecated `$http.send({ data: object, ... })` in favour of `$http.send({ body: rawString, ... })` - to allow sending non-JSON body with the request ([#3058](https://github.com/pocketbase/pocketbase/discussions/3058)). - The existing `data` prop will still work, but it is recommended to use `body` instead (_to send JSON you can use `JSON.stringify(...)` as body value_). - -- Added `core.RealtimeConnectEvent.IdleTimeout` field to allow specifying a different realtime idle timeout duration per client basis ([#3054](https://github.com/pocketbase/pocketbase/discussions/3054)). - -- Fixed `apis.RequestData` deprecation log note ([#3068](https://github.com/pocketbase/pocketbase/pull/3068); thanks @gungjodi). - - -## v0.17.1 - -- Use relative path when redirecting to the OAuth2 providers page in the Admin UI to support subpath deployments ([#3026](https://github.com/pocketbase/pocketbase/pull/3026); thanks @sonyarianto). - -- Manually trigger the `OnBeforeServe` hook for `tests.ApiScenario` ([#3025](https://github.com/pocketbase/pocketbase/discussions/3025)). - -- Trigger the JSVM `cronAdd()` handler only on app `serve` to prevent unexpected (and eventually duplicated) cron handler calls when custom console commands are used ([#3024](https://github.com/pocketbase/pocketbase/discussions/3024#discussioncomment-6592703)). - -- The `console.log()` messages are now written to the `stdout` instead of `stderr`. - - -## v0.17.0 - -- New more detailed guides for using PocketBase as framework (both Go and JS). - _If you find any typos or issues with the docs please report them in https://github.com/pocketbase/site._ - -- Added new experimental JavaScript app hooks binding via [goja](https://github.com/dop251/goja). - They are available by default with the prebuilt executable if you create `*.pb.js` file(s) in the `pb_hooks` directory. - Lower your expectations because the integration comes with some limitations. For more details please check the [Extend with JavaScript](https://pocketbase.io/docs/js-overview/) guide. - Optionally, you can also enable the JS app hooks as part of a custom Go build for dynamic scripting but you need to register the `jsvm` plugin manually: - ```go - jsvm.MustRegister(app core.App, config jsvm.Config{}) - ``` - -- Added Instagram OAuth2 provider ([#2534](https://github.com/pocketbase/pocketbase/pull/2534); thanks @pnmcosta). - -- Added VK OAuth2 provider ([#2533](https://github.com/pocketbase/pocketbase/pull/2533); thanks @imperatrona). - -- Added Yandex OAuth2 provider ([#2762](https://github.com/pocketbase/pocketbase/pull/2762); thanks @imperatrona). - -- Added new fields to `core.ServeEvent`: - ```go - type ServeEvent struct { - App App - Router *echo.Echo - // new fields - Server *http.Server // allows adjusting the HTTP server config (global timeouts, TLS options, etc.) - CertManager *autocert.Manager // allows adjusting the autocert options (cache dir, host policy, etc.) - } - ``` - -- Added `record.ExpandedOne(rel)` and `record.ExpandedAll(rel)` helpers to retrieve casted single or multiple expand relations from the already loaded "expand" Record data. - -- Added rule and filter record `Dao` helpers: - ```go - app.Dao().FindRecordsByFilter("posts", "title ~ 'lorem ipsum' && visible = true", "-created", 10) - app.Dao().FindFirstRecordByFilter("posts", "slug='test' && active=true") - app.Dao().CanAccessRecord(record, requestInfo, rule) - ``` - -- Added `Dao.WithoutHooks()` helper to create a new `Dao` from the current one but without the create/update/delete hooks. - -- Use a default fetch function that will return all relations in case the `fetchFunc` argument of `Dao.ExpandRecord(record, expands, fetchFunc)` and `Dao.ExpandRecords(records, expands, fetchFunc)` is `nil`. - -- For convenience it is now possible to call `Dao.RecordQuery(collectionModelOrIdentifier)` with just the collection id or name. - In case an invalid collection id/name string is passed the query will be resolved with cancelled context error. - -- Refactored `apis.ApiError` validation errors serialization to allow `map[string]error` and `map[string]any` when generating the public safe formatted `ApiError.Data`. - -- Added support for wrapped API errors (_in case Go 1.20+ is used with multiple wrapped errors, the first `apis.ApiError` takes precedence_). - -- Added `?download=1` file query parameter to the file serving endpoint to force the browser to always download the file and not show its preview. - -- Added new utility `github.com/pocketbase/pocketbase/tools/template` subpackage to assist with rendering HTML templates using the standard Go `html/template` and `text/template` syntax. - -- Added `types.JsonMap.Get(k)` and `types.JsonMap.Set(k, v)` helpers for the cases where the type aliased direct map access is not allowed (eg. in [goja](https://pkg.go.dev/github.com/dop251/goja#hdr-Maps_with_methods)). - -- Soft-deprecated `security.NewToken()` in favor of `security.NewJWT()`. - -- `Hook.Add()` and `Hook.PreAdd` now returns a unique string identifier that could be used to remove the registered hook handler via `Hook.Remove(handlerId)`. - -- Changed the after* hooks to be called right before writing the user response, allowing users to return response errors from the after hooks. - There is also no longer need for returning explicitly `hook.StopPropagtion` when writing custom response body in a hook because we will skip the finalizer response body write if a response was already "committed". - -- ⚠️ Renamed `*Options{}` to `Config{}` for consistency and replaced the unnecessary pointers with their value equivalent to keep the applied configuration defaults isolated within their function calls: - ```go - old: pocketbase.NewWithConfig(config *pocketbase.Config) *pocketbase.PocketBase - new: pocketbase.NewWithConfig(config pocketbase.Config) *pocketbase.PocketBase - - old: core.NewBaseApp(config *core.BaseAppConfig) *core.BaseApp - new: core.NewBaseApp(config core.BaseAppConfig) *core.BaseApp - - old: apis.Serve(app core.App, options *apis.ServeOptions) error - new: apis.Serve(app core.App, config apis.ServeConfig) (*http.Server, error) - - old: jsvm.MustRegisterMigrations(app core.App, options *jsvm.MigrationsOptions) - new: jsvm.MustRegister(app core.App, config jsvm.Config) - - old: ghupdate.MustRegister(app core.App, rootCmd *cobra.Command, options *ghupdate.Options) - new: ghupdate.MustRegister(app core.App, rootCmd *cobra.Command, config ghupdate.Config) - - old: migratecmd.MustRegister(app core.App, rootCmd *cobra.Command, options *migratecmd.Options) - new: migratecmd.MustRegister(app core.App, rootCmd *cobra.Command, config migratecmd.Config) - ``` - -- ⚠️ Changed the type of `subscriptions.Message.Data` from `string` to `[]byte` because `Data` usually is a json bytes slice anyway. - -- ⚠️ Renamed `models.RequestData` to `models.RequestInfo` and soft-deprecated `apis.RequestData(c)` in favor of `apis.RequestInfo(c)` to avoid the stuttering with the `Data` field. - _The old `apis.RequestData()` method still works to minimize the breaking changes but it is recommended to replace it with `apis.RequestInfo(c)`._ - -- ⚠️ Changes to the List/Search APIs - - Added new query parameter `?skipTotal=1` to skip the `COUNT` query performed with the list/search actions ([#2965](https://github.com/pocketbase/pocketbase/discussions/2965)). - If `?skipTotal=1` is set, the response fields `totalItems` and `totalPages` will have `-1` value (this is to avoid having different JSON responses and to differentiate from the zero default). - With the latest JS SDK 0.16+ and Dart SDK v0.11+ versions `skipTotal=1` is set by default for the `getFirstListItem()` and `getFullList()` requests. - - - The count and regular select statements also now executes concurrently, meaning that we no longer perform normalization over the `page` parameter and in case the user - request a page that doesn't exist (eg. `?page=99999999`) we'll return empty `items` array. - - - Reverted the default `COUNT` column to `id` as there are some common situations where it can negatively impact the query performance. - Additionally, from this version we also set `PRAGMA temp_store = MEMORY` so that also helps with the temp B-TREE creation when `id` is used. - _There are still scenarios where `COUNT` queries with `rowid` executes faster, but the majority of the time when nested relations lookups are used it seems to have the opposite effect (at least based on the benchmarks dataset)._ - -- ⚠️ Disallowed relations to views **from non-view** collections ([#3000](https://github.com/pocketbase/pocketbase/issues/3000)). - The change was necessary because I wasn't able to find an efficient way to track view changes and the previous behavior could have too many unexpected side-effects (eg. view with computed ids). - There is a system migration that will convert the existing view `relation` fields to `json` (multiple) and `text` (single) fields. - This could be a breaking change if you have `relation` to view and use `expand` or some of the `relation` view fields as part of a collection rule. - -- ⚠️ Added an extra `action` argument to the `Dao` hooks to allow skipping the default persist behavior. - In preparation for the logs generalization, the `Dao.After*Func` methods now also allow returning an error. - -- Allowed `0` as `RelationOptions.MinSelect` value to avoid the ambiguity between 0 and non-filled input value ([#2817](https://github.com/pocketbase/pocketbase/discussions/2817)). - -- Fixed zero-default value not being used if the field is not explicitly set when manually creating records ([#2992](https://github.com/pocketbase/pocketbase/issues/2992)). - Additionally, `record.Get(field)` will now always return normalized value (the same as in the json serialization) for consistency and to avoid ambiguities with what is stored in the related DB table. - The schema fields columns `DEFAULT` definition was also updated for new collections to ensure that `NULL` values can't be accidentally inserted. - -- Fixed `migrate down` not returning the correct `lastAppliedMigrations()` when the stored migration applied time is in seconds. - -- Fixed realtime delete event to be called after the record was deleted from the DB (_including transactions and cascade delete operations_). - -- Other minor fixes and improvements (typos and grammar fixes, updated dependencies, removed unnecessary 404 error check in the Admin UI, etc.). - - -## v0.16.10 - -- Added multiple valued fields (`relation`, `select`, `file`) normalizations to ensure that the zero-default value of a newly created multiple field is applied for already existing data ([#2930](https://github.com/pocketbase/pocketbase/issues/2930)). - - -## v0.16.9 - -- Register the `eagerRequestInfoCache` middleware only for the internal `api` group routes to avoid conflicts with custom route handlers ([#2914](https://github.com/pocketbase/pocketbase/issues/2914)). - - -## v0.16.8 - -- Fixed unique validator detailed error message not being returned when camelCase field name is used ([#2868](https://github.com/pocketbase/pocketbase/issues/2868)). - -- Updated the index parser to allow no space between the table name and the columns list ([#2864](https://github.com/pocketbase/pocketbase/discussions/2864#discussioncomment-6373736)). - -- Updated go deps. - - -## v0.16.7 - -- Minor optimization for the list/search queries to use `rowid` with the `COUNT` statement when available. - _This eliminates the temp B-TREE step when executing the query and for large datasets (eg. 150k) it could have 10x improvement (from ~580ms to ~60ms)._ - - -## v0.16.6 - -- Fixed collection index column sort normalization in the Admin UI ([#2681](https://github.com/pocketbase/pocketbase/pull/2681); thanks @SimonLoir). - -- Removed unnecessary admins count in `apis.RequireAdminAuthOnlyIfAny()` middleware ([#2726](https://github.com/pocketbase/pocketbase/pull/2726); thanks @svekko). - -- Fixed `multipart/form-data` request bind not populating map array values ([#2763](https://github.com/pocketbase/pocketbase/discussions/2763#discussioncomment-6278902)). - -- Upgraded npm and Go dependencies. - - -## v0.16.5 - -- Fixed the Admin UI serialization of implicit relation display fields ([#2675](https://github.com/pocketbase/pocketbase/issues/2675)). - -- Reset the Admin UI sort in case the active sort collection field is renamed or deleted. - - -## v0.16.4 - -- Fixed the selfupdate command not working on Windows due to missing `.exe` in the extracted binary path ([#2589](https://github.com/pocketbase/pocketbase/discussions/2589)). - _Note that the command on Windows will work from v0.16.4+ onwards, meaning that you still will have to update manually one more time to v0.16.4._ - -- Added `int64`, `int32`, `uint`, `uint64` and `uint32` support when scanning `types.DateTime` ([#2602](https://github.com/pocketbase/pocketbase/discussions/2602)) - -- Updated dependencies. - - -## v0.16.3 - -- Fixed schema fields sort not working on Safari/Gnome Web ([#2567](https://github.com/pocketbase/pocketbase/issues/2567)). - -- Fixed default `PRAGMA`s not being applied for new connections ([#2570](https://github.com/pocketbase/pocketbase/discussions/2570)). - - -## v0.16.2 - -- Fixed backups archive not excluding the local `backups` directory on Windows ([#2548](https://github.com/pocketbase/pocketbase/discussions/2548#discussioncomment-5979712)). - -- Changed file field to not use `dataTransfer.effectAllowed` when dropping files since it is not reliable and consistent across different OS and browsers ([#2541](https://github.com/pocketbase/pocketbase/issues/2541)). - -- Auto register the initial generated snapshot migration to prevent incorrectly reapplying the snapshot on Docker restart ([#2551](https://github.com/pocketbase/pocketbase/discussions/2551)). - -- Fixed missing view id field error message typo. - - -## v0.16.1 - -- Fixed backup restore not working in a container environment when `pb_data` is mounted as volume ([#2519](https://github.com/pocketbase/pocketbase/issues/2519)). - -- Fixed Dart SDK realtime API preview example ([#2523](https://github.com/pocketbase/pocketbase/pull/2523); thanks @xFrann). - -- Fixed typo in the backups create panel ([#2526](https://github.com/pocketbase/pocketbase/pull/2526); thanks @dschissler). - -- Removed unnecessary slice length check in `list.ExistInSlice` ([#2527](https://github.com/pocketbase/pocketbase/pull/2527); thanks @KunalSin9h). - -- Avoid mutating the cached request data on OAuth2 user create ([#2535](https://github.com/pocketbase/pocketbase/discussions/2535)). - -- Fixed Export Collections "Download as JSON" ([#2540](https://github.com/pocketbase/pocketbase/issues/2540)). - -- Fixed file field drag and drop not working in Firefox and Safari ([#2541](https://github.com/pocketbase/pocketbase/issues/2541)). - - -## v0.16.0 - -- Added automated backups (_+ cron rotation_) APIs and UI for the `pb_data` directory. - The backups can be also initialized programmatically using `app.CreateBackup("backup.zip")`. - There is also experimental restore method - `app.RestoreBackup("backup.zip")` (_currently works only on UNIX systems as it relies on execve_). - The backups can be stored locally or in external S3 storage (_it has its own configuration, separate from the file uploads storage filesystem_). - -- Added option to limit the returned API fields using the `?fields` query parameter. - The "fields picker" is applied for `SearchResult.Items` and every other JSON response. For example: - ```js - // original: {"id": "RECORD_ID", "name": "abc", "description": "...something very big...", "items": ["id1", "id2"], "expand": {"items": [{"id": "id1", "name": "test1"}, {"id": "id2", "name": "test2"}]}} - // output: {"name": "abc", "expand": {"items": [{"name": "test1"}, {"name": "test2"}]}} - const result = await pb.collection("example").getOne("RECORD_ID", { - expand: "items", - fields: "name,expand.items.name", - }) - ``` - -- Added new `./pocketbase update` command to selfupdate the prebuilt executable (with option to generate a backup of your `pb_data`). - -- Added new `./pocketbase admin` console command: - ```sh - // creates new admin account - ./pocketbase admin create test@example.com 123456890 - - // changes the password of an existing admin account - ./pocketbase admin update test@example.com 0987654321 - - // deletes single admin account (if exists) - ./pocketbase admin delete test@example.com - ``` - -- Added `apis.Serve(app, options)` helper to allow starting the API server programmatically. - -- Updated the schema fields Admin UI for "tidier" fields visualization. - -- Updated the logs "real" user IP to check for `Fly-Client-IP` header and changed the `X-Forward-For` header to use the first non-empty leftmost-ish IP as it the closest to the "real IP". - -- Added new `tools/archive` helper subpackage for managing archives (_currently works only with zip_). - -- Added new `tools/cron` helper subpackage for scheduling task using cron-like syntax (_this eventually may get exported in the future in a separate repo_). - -- Added new `Filesystem.List(prefix)` helper to retrieve a flat list with all files under the provided prefix. - -- Added new `App.NewBackupsFilesystem()` helper to create a dedicated filesystem abstraction for managing app data backups. - -- Added new `App.OnTerminate()` hook (_executed right before app termination, eg. on `SIGTERM` signal_). - -- Added `accept` file field attribute with the field MIME types ([#2466](https://github.com/pocketbase/pocketbase/pull/2466); thanks @Nikhil1920). - -- Added support for multiple files sort in the Admin UI ([#2445](https://github.com/pocketbase/pocketbase/issues/2445)). - -- Added support for multiple relations sort in the Admin UI. - -- Added `meta.isNew` to the OAuth2 auth JSON response to indicate a newly OAuth2 created PocketBase user. diff --git a/core/pb/README.md b/core/pb/README.md index f4efbef..516f57e 100755 --- a/core/pb/README.md +++ b/core/pb/README.md @@ -1,4 +1,4 @@ -download https://pocketbase.io/docs/ +download https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/ ```bash cd pb From cad383b0fe6e8391b2a11b7a8ce0a233fddd3c52 Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Mon, 9 Dec 2024 18:18:10 +0800 Subject: [PATCH 8/9] feat:docker file --- .gitignore | 10 +- CHANGELOG.md | 4 + Dockerfile | 8 +- README.md | 138 ++++++++++-------- README_KR.md | 2 +- compose.yaml | 6 +- core/agents/get_info.py | 4 +- core/custom_scraper/README.md | 10 +- core/custom_scraper/README_EN.md | 8 +- core/custom_scraper/mp.py | 8 +- core/{run_all.sh => docker_entrypoint.sh} | 2 +- core/general_process.py | 18 ++- core/run.sh | 2 +- core/tasks.py | 30 ++-- env_sample | 4 +- {core/pb => pb}/LICENSE.md | 0 {core/pb => pb}/README.md | 0 .../1733204939_created_articles.js | 0 .../1733234529_created_focus_points.js | 0 .../1733234644_updated_focus_points.js | 0 .../pb_migrations/1733465276_created_sites.js | 0 .../1733465426_updated_articles.js | 0 .../pb_migrations/1733465563_created_infos.js | 0 23 files changed, 135 insertions(+), 119 deletions(-) rename core/{run_all.sh => docker_entrypoint.sh} (89%) rename {core/pb => pb}/LICENSE.md (100%) rename {core/pb => pb}/README.md (100%) rename {core/pb => pb}/pb_migrations/1733204939_created_articles.js (100%) rename {core/pb => pb}/pb_migrations/1733234529_created_focus_points.js (100%) rename {core/pb => pb}/pb_migrations/1733234644_updated_focus_points.js (100%) rename {core/pb => pb}/pb_migrations/1733465276_created_sites.js (100%) rename {core/pb => pb}/pb_migrations/1733465426_updated_articles.js (100%) rename {core/pb => pb}/pb_migrations/1733465563_created_infos.js (100%) diff --git a/.gitignore b/.gitignore index 07236d6..0ca3b9f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,7 @@ __pycache__ .env .venv/ -core/pb/pb_data/ -core/pb/CHANGELOG.md -core/pb/LICENSE.md -core/pb/pocketbase -core/work_dir/ -/work_dir \ No newline at end of file +pb/pb_data/ +pb/pocketbase +/work_dir/ +/docker_dir/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 48965c3..9a49097 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ Rewrote the PocketBase form structure; +- llm wrapper引入异步架构、自定义页面提取器规范优化(含 微信公众号文章提取优化); + + llm wrapper introduces asynchronous architecture, customized page extractor specifications optimization (including WeChat official account article extraction optimization); + - 进一步简化部署操作步骤。 Further simplified deployment steps. diff --git a/Dockerfile b/Dockerfile index dc9f761..b35991b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,17 +5,19 @@ RUN apt-get update && \ COPY core/requirements.txt /tmp/requirements.txt RUN pip install --no-cache-dir -r /tmp/requirements.txt - +RUN playwright install +RUN playwright install-deps WORKDIR /app # download and unzip PocketBase ADD https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/pocketbase_0.23.4_linux_amd64.zip /tmp/pb.zip # for arm device # ADD https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/pocketbase_0.23.4_linux_arm64.zip /tmp/pb.zip -RUN unzip /tmp/pb.zip -d /app/pb/ +RUN unzip /tmp/pb.zip -d /pb/ +COPY pb/pb_migrations /pb/pb_migrations RUN apt-get clean && rm -rf /var/lib/apt/lists/* EXPOSE 8090 -EXPOSE 8077 +# EXPOSE 8077 CMD tail -f /dev/null \ No newline at end of file diff --git a/README.md b/README.md index 6174e4e..be528a8 100644 --- a/README.md +++ b/README.md @@ -6,41 +6,40 @@ **我们缺的不是信息,而是从海量信息中过滤噪音,从而让有价值的信息显露出来** -## 🔥 隆重介绍精准产品定位下的全新架构 V0.3.2版本 - -wiseflow 预计将在2024.12月底前正式升级到0.3.8版本,这也将是 V0.3.x 架构下的最终版本(除非有足够多的小修改,否则不会有 V0.3.9版本) - -计划中的升级内容包括: - -- 大幅升级 general_crawler(引入诸多最新开源技术方案), 进一步提升页面适配覆盖度以及实现完全的本地 CPU 计算(意味着无需再为此配置 LLM 选项); -- 改进general_crawler 从列表页面提取 url 的能力,以及列表页面与普通文章页面的区分能力; -- 尝试引入新的 mp_crawler, 公众号文章监控无需wxbot; -- 测试并推荐新的信息提取 llm model,并微调提取策略。 - -视情况可能添加的特性: - -- 引入对 RSS 信息源的支持; -- 引入对社交平台的支持(初期这一块会十分简陋,请不要太多期待) - -上述内容会逐步提前释放到 dev 分支,欢迎切换尝鲜,并积极反馈 issue。 - ------------------------------ - 🌱看看首席情报官是如何帮您节省时间,过滤无关信息,并整理关注要点的吧!🌱 -- ✅ 通用网页内容解析器,综合使用统计学习(依赖开源项目GNE)和LLM,适配90%以上的新闻页面; -- ✅ 异步任务架构; -- ✅ 使用LLM进行信息提取和标签分类(最低只需使用9B大小的LLM就可完美执行任务)! - https://github.com/TeamWiseFlow/wiseflow/assets/96130569/bd4b2091-c02d-4457-9ec6-c072d8ddfb16 + +## 🔥 隆重介绍 V0.3.2 版本 + +在充分听取社区反馈意见基础之上,我们重新提炼了 wiseflow 的产品定位,新定位更加精准也更加聚焦,V0.3.2版本即是该定位下的全新架构版本,相对于之前版本如下改进: + +- 引入 [Crawlee](https://github.com/apify/crawlee-python) 基础爬虫架构,大幅提升页面获取能力。实测之前获取不到(包括获取为乱码的)页面目前都可以很好的获取了,后续大家碰到不能很好获取的页面,欢迎在 [issue #136](https://github.com/TeamWiseFlow/wiseflow/issues/136) 中进行反馈; +- 新产品定位下全新的信息提取策略——“爬查一体”,放弃文章详细提取,全面使用 llm 直接从页面中提取用户感兴趣的信息(infos),同时自动判断值得跟进爬取的链接; +- 适配最新版本(v0.23.4)的 Pocketbase,同时更新表单配置。另外新架构已经无需 GNE 等模块,requirement 依赖项目降低到8个; +- 新架构部署方案也更加简便,docker 模式支持代码仓热更新,这意味着后续升级就无需再重复docker build了。 +- 更多细节,参考 [CHANGELOG](CHANGELOG.md) + +🌟 注意: + +V0.3.2 架构和依赖上都较之前版本有诸多变化,因此请务必重新拉取代码仓,并参考最新的部署方案重新部署,V0.3.2支持python 环境源码使用、docker 容器部署,同时我们也即将上线免部署的服务网站,注册账号就可以直接使用,敬请期待! + +V0.3.2 版本效果截图: + sample.png -## ✋ wiseflow 与常见的爬虫工具、AI搜索、知识库(RAG)项目有何不同? +V0.3.x 后续计划中的升级内容还有: + +- 尝试引入新的 mp_crawler, 公众号文章监控无需wxbot; +- 引入对 RSS 信息源的支持; +- 引入 [SeeAct](https://github.com/OSU-NLP-Group/SeeAct) 方案,通过视觉大模型提升 wiseflow 自主深入挖掘能力。 + +## ✋ wiseflow 与传统的爬虫工具、AI搜索、知识库(RAG)项目有何不同? 承蒙大家的厚爱,wiseflow自2024年6月底发布 V0.3.0版本来受到了开源社区的广泛关注,甚至吸引了不少自媒体的主动报道,在此首先表示感谢! -但我们也注意到部分关注者对 wiseflow 的功能定位存在一些理解偏差,为免误会,我们制作了如下表格,清晰展示 wiseflow 与爬虫、AI搜索、知识库(RAG)类项目的对比: +但我们也注意到部分关注者对 wiseflow 的功能定位存在一些理解偏差,如下表格列出了 wiseflow 与传统爬虫工具、AI搜索、知识库(RAG)类项目的对比: | | 与 **首席情报官(Wiseflow)** 的比较说明| |-------------|-----------------| @@ -48,29 +47,6 @@ https://github.com/TeamWiseFlow/wiseflow/assets/96130569/bd4b2091-c02d-4457-9ec6 | **AI搜索** | AI搜索主要的应用场景是**具体问题的即时问答**,举例:”XX公司的创始人是谁“、“xx品牌下的xx产品哪里有售” ,用户要的是**一个答案**;wiseflow主要的应用场景是**某一方面信息的持续采集**,比如XX公司的关联信息追踪,XX品牌市场行为的持续追踪……在这些场景下,用户能提供关注点(某公司、某品牌)、甚至能提供信源(站点 url 等),但无法提出具体搜索问题,用户要的是**一系列相关信息**| | **知识库(RAG)类项目** | 知识库(RAG)类项目一般是基于已有信息的下游任务,并且一般面向的是私有知识(比如企业内的操作手册、产品手册、政府部门的文件等);wiseflow 目前并未整合下游任务,同时面向的是互联网上的公开信息,如果从“智能体”的角度来看,二者属于为不同目的而构建的智能体,RAG 类项目是“(内部)知识助理智能体”,而 wiseflow 则是“(外部)信息采集智能体”| -## 🔄 V0.3.1 更新 - -dashboard 部分已经删除,如果您有dashboard需求,请下载 [V0.2.1版本](https://github.com/TeamWiseFlow/wiseflow/releases/tag/V0.2.1) - -👏 虽然部分9b大小的LLM(THUDM/glm-4-9b-chat)已经可以实现稳定的信息提取输出,但是我们发现对于复杂含义的tag(比如“党建”)或者需要特指的tag(比如仅需采集“居民区活动”,而不希望包括诸如演唱会这样的大型活动信息), -使用目前的prompt还是不能进行准确的提取,因此我们在这一版本中为每个tag增加了explaination字段,可以通过输入该字段进行更加清晰的tag指定。 - - _注:复杂explaination需要更大规模的模型才能准确理解,具体见 [模型推荐 2024-09-03](###-4. 模型推荐 [2024-09-03])_ - -👏 另外针对上一版本prompt语言选择的问题(虽然这并不影响输出结果),我们在目前版本中进一步简化了方案,用户无需指定系统语言(这在docker中并不那么直观),系统会根据tag以及tag的explaination判断选择何种语言的 -prompt(也就决定了info的输出语言),这进一步简化了wiseflow的部署和使用。【不过目前wiseflow仅支持简体中文和英文两种语言,其他语言的需求可以通过更改 core/insights/get_info.py 中的prompt实现】 - -## 🌟 如何在您的应用中整合wiseflow - -wiseflow是一个原生的LLM应用,仅需7B~9B大小LLM就可以很好的执行信息挖掘、过滤与分类任务,且无需向量模型,系统开销很小,适合各种硬件环境下的本地化以及私有化部署。 - -wiseflow将挖掘出的信息存储于自带的Pocketbase数据库中,这意味着这种情况下您无需了解wiseflow的代码,只需要对数据库进行读取操作即可! - -PocketBase作为流行的轻量级数据库,目前已有 Go/Javascript/Python 等语言的SDK。 - - Go : https://pocketbase.io/docs/go-overview/ - - Javascript : https://pocketbase.io/docs/js-overview/ - - python : https://github.com/vaphes/pocketbase - ## 📥 安装与使用 ### 1. 克隆代码仓库 @@ -79,33 +55,53 @@ PocketBase作为流行的轻量级数据库,目前已有 Go/Javascript/Python ```bash git clone https://github.com/TeamWiseFlow/wiseflow.git -cd wiseflow ``` -### 2. 推荐使用docker运行 +### 2. 参考env_sample 配置 .env文件放置在 core 目录下 -**中国区用户使用前请合理配置网络,或者指定docker hub镜像** +🌟 **这里与之前版本不同**,V0.3.2开始需要把 .env 放置在 core文件夹中。 + +另外 V0.3.2 起,env 配置也大幅简化了,必须的配置项目只有三项,具体如下: + +- LLM_API_KEY="" # 这还是你的大模型服务key,这是必须的 +- LLM_API_BASE="https://api.siliconflow.cn/v1" # 服务接口地址,任何支持 openai sdk 的服务商都可以(推荐 siliconflow),如果直接使用openai 的服务,这一项也可以不填 +- PB_API_AUTH="test@example.com|1234567890" # pocketbase 数据库的 superuser 用户名和密码,记得用 | 分隔 + +下面的都是可选配置: +- #VERBOSE="true" # 是否开启观测模式,开启的话,不仅会把 debug log信息记录在 logger 文件上(模式仅是输出在 console 上),同时会开启 playwright 的浏览器窗口,方便你观察抓取过程,但同时会增加抓取速度; +- #PRIMARY_MODEL="Qwen/Qwen2.5-7B-Instruct" # 主模型选择,在使用 siliconflow 服务的情况下,这一项不填就会默认调用Qwen2.5-7B-Instruct,实测基本也够用,但我更加**推荐 Qwen2.5-14B-Instruct** +- #SECONDARY_MODEL="THUDM/glm-4-9b-chat" # 副模型选择,在使用 siliconflow 服务的情况下,这一项不填就会默认调用glm-4-9b-chat。 +- #PROJECT_DIR="work_dir" # 项目运行数据目录,不配置的话,默认在 `core/work_dir` ,注意:目前整个 core 目录是挂载到 container 下的,所以意味着你可以直接访问这里。 +- #PB_API_BASE"="" # 只有当你的 pocketbase 不运行在默认ip 或端口下才需要配置,默认情况下忽略就行。 + + +### 3.1 使用docker构筑 image 运行 + +对于国内用户,可以先配置镜像源: + +最新可用 docker 镜像加速地址参考:[参考1](https://github.com/dongyubin/DockerHub) [参考2](https://www.coderjia.cn/archives/dba3f94c-a021-468a-8ac6-e840f85867ea) + +🌟 **三方镜像,风险自担。** ```bash +cd wiseflow docker compose up ``` **注意:** - - 在wiseflow代码仓根目录下运行上述命令; - - 运行前先创建并编辑.env文件放置在Dockerfile同级目录(wiseflow代码仓根目录),.env文件可以参考env_sample - - 第一次运行docker container时会遇到报错,这其实是正常现象,因为你尚未为pb仓库创建admin账号。 + +第一次运行docker container时可能会遇到报错,这其实是正常现象,因为你尚未为pb仓库创建 super user 账号。 -此时请保持container不关闭状态,浏览器打开`http://127.0.0.1:8090/_/ `,按提示创建admin账号(一定要使用邮箱),然后将创建的admin邮箱(再次强调,一定要用邮箱)和密码填入.env文件,重启container即可。 +此时请保持container不关闭状态,浏览器打开`http://127.0.0.1:8090/_/ `,按提示创建 super user 账号(一定要使用邮箱),然后将创建的用户名密码填入.env文件,重启container即可。 -_如您想更改container的时区和语言,请仿照如下命令运行image_ - -```bash -docker run -e LANG=zh_CN.UTF-8 -e LC_CTYPE=zh_CN.UTF-8 your_image -``` - -### 2.【备选】直接使用python运行 +🌟 docker运行默认进入 task + +### 3.2 使用python环境运行 + +推荐使用 conda 构建虚拟环境 ```bash +cd wiseflow conda create -n wiseflow python=3.10 conda activate wiseflow cd core @@ -117,7 +113,7 @@ pip install -r requirements.txt **注意:** - 一定要先启动pb,至于task和backend是独立进程,先后顺序无所谓,也可以按需求只启动其中一个; - 需要先去这里 https://pocketbase.io/docs/ 下载对应自己设备的pocketbase客户端,并放置在 /core/pb 目录下 - - pb运行问题(包括首次运行报错等)参考 [core/pb/README.md](/core/pb/README.md) + - pb运行问题(包括首次运行报错等)参考 [core/pb/README.md](/pb/README.md) - 使用前请创建并编辑.env文件,放置在wiseflow代码仓根目录(core目录的上级),.env文件可以参考env_sample,详细配置说明见下 📚 for developer, see [/core/README.md](/core/README.md) for more @@ -194,6 +190,20 @@ sites 字段说明: 注:若需让7b~9b规模的LLM可以实现对tag explaination的准确理解,推荐使用dspy进行prompt优化,但这需要累积约50条人工标记数据。详见 [DSPy](https://dspy-docs.vercel.app/) +## 🔄 如何在您自己的程序中使用 wiseflow 抓取出的数据 + +1、参考 [dashbord](dashboard) 部分源码二次开发。 + +注意 wiseflow 的 core 部分并不需要 dashboard,目前产品也未集成 dashboard,如果您有dashboard需求,请下载 [V0.2.1版本](https://github.com/TeamWiseFlow/wiseflow/releases/tag/V0.2.1) + +2、直接从 Pocketbase 中获取数据 + +wiseflow 所有抓取数据都会即时存入 pocketbase,因此您可以直接操作 pocketbase 数据库来获取数据。 + +PocketBase作为流行的轻量级数据库,目前已有 Go/Javascript/Python 等语言的SDK。 + - Go : https://pocketbase.io/docs/go-overview/ + - Javascript : https://pocketbase.io/docs/js-overview/ + - python : https://github.com/vaphes/pocketbase ## 🛡️ 许可协议 diff --git a/README_KR.md b/README_KR.md index fb7b881..e504349 100644 --- a/README_KR.md +++ b/README_KR.md @@ -117,7 +117,7 @@ pip install -r requirements.txt **주의:** - 반드시 pb를 먼저 시작해야 하며, task와 backend는 독립적인 프로세스이므로 순서는 상관없고, 필요에 따라 하나만 시작해도 됩니다. - 먼저 여기를 방문하여 https://pocketbase.io/docs/ 본인의 장치에 맞는 pocketbase 클라이언트를 다운로드하고 /core/pb 디렉토리에 배치해야 합니다. - - pb 실행 문제(처음 실행 시 오류 포함)에 대해서는 [core/pb/README.md](/core/pb/README.md)를 참조하십시오. + - pb 실행 문제(처음 실행 시 오류 포함)에 대해서는 [core/pb/README.md](/pb/README.md)를 참조하십시오. - 사용 전에 .env 파일을 생성하고 편집하여 wiseflow 코드 저장소의 루트 디렉토리(core 디렉토리의 상위)에 배치하십시오. .env 파일은 env_sample을 참고하고, 자세한 설정 설명은 아래를 참조하십시오. 📚 개발자를 위한 더 많은 정보는 [/core/README.md](/core/README.md)를 참조하십시오. diff --git a/compose.yaml b/compose.yaml index 38c30cd..1f71625 100755 --- a/compose.yaml +++ b/compose.yaml @@ -5,9 +5,9 @@ services: image: wiseflow:latest tty: true stdin_open: true - entrypoint: ["bash", "/app/run_all.sh"] + entrypoint: ["bash", "/app/docker_entrypoint.sh"] ports: - 8090:8090 - - 8077:8077 volumes: - - ./core:/app \ No newline at end of file + - ./core:/app + - ./pb/pb_data:/pb/pb_data \ No newline at end of file diff --git a/core/agents/get_info.py b/core/agents/get_info.py index 6f81eee..bb00fd6 100644 --- a/core/agents/get_info.py +++ b/core/agents/get_info.py @@ -133,7 +133,7 @@ url2 result = re.findall(r'"""(.*?)"""', result, re.DOTALL) if result: result = result[0].strip() - self.logger.debug(f"cleaned output: {result}") + # self.logger.debug(f"cleaned output: {result}") urls.update(extract_urls(result)) content = '' @@ -145,7 +145,7 @@ url2 result = re.findall(r'"""(.*?)"""', result, re.DOTALL) if result: result = result[0].strip() - self.logger.debug(f"cleaned output: {result}") + # self.logger.debug(f"cleaned output: {result}") urls.update(extract_urls(result)) raw_urls = set(link_dict.values()) diff --git a/core/custom_scraper/README.md b/core/custom_scraper/README.md index 98d0e60..e16ff2c 100644 --- a/core/custom_scraper/README.md +++ b/core/custom_scraper/README.md @@ -21,22 +21,20 @@ Scraper 应该是一个函数(而不是类)。 Scraper 出参限定为三个: #### 3.1 `article` -解析出的页面详情,类型为 `dict`,格式如下(**注意,'content' 是必须的,其他可以没有,额外的键值信息会被忽略**): +解析出的页面详情,类型为 `dict`,格式如下: ```python { - 'url': ..., 'author': ..., 'publish_date': ..., - 'screenshot': ..., - 'content': ...(not empty) + 'content': ... } ``` -- 上述值的类型都要求为 `str`,日期格式为 `YYYY-MM-DD`,screenshot 为**文件路径**,可以是相对于 core 目录的相对路径也可以是绝对路径,文件类型为 `png`。 +- 上述值的类型都要求为 `str`,日期格式为 `YYYY-MM-DD`。 **注意:** -1. `'content'` 要有且不为空,不然无法触发后续的提取,文章也会被舍弃。这是唯一要求不为空的项; +1. `'content'` 要有且不为空,不然无法触发后续的提取; 2. `'author'` 和 `'publish_date'` 尽量有,不然 wiseflow 会自动用域名对应 demain 和 当日日期代替。 #### 3.2 `links` diff --git a/core/custom_scraper/README_EN.md b/core/custom_scraper/README_EN.md index 595477c..a8e3559 100644 --- a/core/custom_scraper/README_EN.md +++ b/core/custom_scraper/README_EN.md @@ -21,22 +21,20 @@ The function receives two input parameters (passed by the wiseflow framework): The Scraper output is limited to three: #### 3.1 `article` -The parsed page details, of type `dict`, with the following format (**note that 'content' is mandatory, others can be omitted, and extra key-value information will be ignored**): +The parsed page details, of type `dict`, with the following format: ```python { - 'url': ..., 'author': ..., 'publish_date': ..., - 'screenshot': ..., - 'content': ...(not empty) + 'content': ... } ``` - The types of the above values are all required to be `str`, with the date format being `YYYY-MM-DD`, and the screenshot being a **file path**, which can be a relative path to the core directory or an absolute path, with the file type being `png`. **Note:** -1. `'content'` must be present and not empty, otherwise subsequent extraction cannot be triggered, and the article will be discarded. This is the only non-empty requirement; +1. `'content'` must be present and not empty, otherwise subsequent extraction cannot be triggered; 2. `'author'` and `'publish_date'` should be included if possible, otherwise wiseflow will automatically use the domain corresponding to the demain and the current date. #### 3.2 `links` diff --git a/core/custom_scraper/mp.py b/core/custom_scraper/mp.py index 5fd51a4..21f6e8d 100644 --- a/core/custom_scraper/mp.py +++ b/core/custom_scraper/mp.py @@ -100,10 +100,8 @@ async def mp_scraper(html: str, url: str) -> tuple[dict, set, list]: # At this time, you can use the summary as the content. content = f"[from {profile_nickname}]{summary}" - article = {'url': url, - 'title': rich_media_title, - 'author': profile_nickname, - 'publish_date': publish_time, - 'content': content} + article = {'author': profile_nickname, + 'publish_date': publish_time, + 'content': content} return article, set(), [] diff --git a/core/run_all.sh b/core/docker_entrypoint.sh similarity index 89% rename from core/run_all.sh rename to core/docker_entrypoint.sh index 0ae42aa..0f03100 100755 --- a/core/run_all.sh +++ b/core/docker_entrypoint.sh @@ -5,7 +5,7 @@ source .env set +o allexport # 启动 PocketBase -pb/pocketbase serve --http=0.0.0.0:8090 & +/pb/pocketbase serve --http=0.0.0.0:8090 & pocketbase_pid=$! # 启动 Python 任务 diff --git a/core/general_process.py b/core/general_process.py index c21e53e..5d65813 100644 --- a/core/general_process.py +++ b/core/general_process.py @@ -9,7 +9,7 @@ import asyncio from custom_scraper import custom_scraper_map from urllib.parse import urlparse, urljoin import hashlib -from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext +from crawlee.playwright_crawler import PlaywrightCrawler, PlaywrightCrawlingContext, PlaywrightPreNavigationContext from datetime import datetime, timedelta @@ -22,6 +22,7 @@ screenshot_dir = os.path.join(project_dir, 'crawlee_storage', 'screenshots') wiseflow_logger = get_logger('general_process', project_dir) pb = PbTalker(wiseflow_logger) gie = GeneralInfoExtractor(pb, wiseflow_logger) +existing_urls = {url['url'] for url in pb.read(collection_name='articles', fields=['url']) if url['url']} async def save_to_pb(article: dict, infos: list): @@ -59,9 +60,14 @@ crawler = PlaywrightCrawler( request_handler_timeout=timedelta(minutes=5), headless=False if os.environ.get("VERBOSE", "").lower() in ["true", "1"] else True ) + +@crawler.pre_navigation_hook +async def log_navigation_url(context: PlaywrightPreNavigationContext) -> None: + context.log.info(f'Navigating to {context.request.url} ...') + @crawler.router.default_handler async def request_handler(context: PlaywrightCrawlingContext) -> None: - context.log.info(f'Processing {context.request.url} ...') + # context.log.info(f'Processing {context.request.url} ...') # Handle dialogs (alerts, confirms, prompts) async def handle_dialog(dialog): context.log.info(f'Closing dialog: {dialog.message}') @@ -114,13 +120,17 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None: text = await context.page.inner_text('body') soup = BeautifulSoup(html, 'html.parser') links = soup.find_all('a', href=True) - base_url = context.request.url + parsed_url = urlparse(context.request.url) + domain = parsed_url.netloc + base_url = f"{parsed_url.scheme}://{domain}" + link_dict = {} for a in links: new_url = a.get('href') t = a.text.strip() - if new_url and t: + if new_url and t and new_url != base_url and new_url not in existing_urls: link_dict[t] = urljoin(base_url, new_url) + existing_urls.add(new_url) publish_date = soup.find('div', class_='date').get_text(strip=True) if soup.find('div', class_='date') else None if publish_date: publish_date = extract_and_convert_dates(publish_date) diff --git a/core/run.sh b/core/run.sh index 220523f..e2ab4b6 100755 --- a/core/run.sh +++ b/core/run.sh @@ -7,7 +7,7 @@ set +o allexport if ! pgrep -x "pocketbase" > /dev/null; then if ! netstat -tuln | grep ":8090" > /dev/null && ! lsof -i :8090 > /dev/null; then echo "Starting PocketBase..." - pb/pocketbase serve --http=0.0.0.0:8090 & + ../pb/pocketbase serve --http=0.0.0.0:8090 & else echo "Port 8090 is already in use." fi diff --git a/core/tasks.py b/core/tasks.py index b5e2a7a..e6ccef3 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -1,27 +1,25 @@ import asyncio -from general_process import pipeline, pb, wiseflow_logger +from general_process import crawler, pb, wiseflow_logger counter = 1 -async def process_site(site, counter): - if not site['per_hours'] or not site['url']: - return - if counter % site['per_hours'] == 0: - wiseflow_logger.info(f"applying {site['url']}") - await pipeline(site['url'].rstrip('/')) - - async def schedule_pipeline(interval): global counter - while True: - sites = pb.read('sites', filter='activated=True') - wiseflow_logger.info(f'task execute loop {counter}') - await asyncio.gather(*[process_site(site, counter) for site in sites]) + wiseflow_logger.info(f'task execute loop {counter}') + sites = pb.read('sites', filter='activated=True') + todo_urls = set() + for site in sites: + if not site['per_hours'] or not site['url']: + continue + if counter % site['per_hours'] == 0: + wiseflow_logger.info(f"applying {site['url']}") + todo_urls.add(site['url'].rstrip('/')) - counter += 1 - wiseflow_logger.info(f'task execute loop finished, work after {interval} seconds') - await asyncio.sleep(interval) + counter += 1 + await crawler.run(list[todo_urls]) + wiseflow_logger.info(f'task execute loop finished, work after {interval} seconds') + await asyncio.sleep(interval) async def main(): diff --git a/env_sample b/env_sample index 33ba638..23313d8 100755 --- a/env_sample +++ b/env_sample @@ -1,10 +1,10 @@ export LLM_API_KEY="" export LLM_API_BASE="https://api.siliconflow.cn/v1" export PB_API_AUTH="test@example.com|1234567890" ##your pb superuser account and password -export VERBOSE="true" ##for detail log info. If not need, remove this item. ##belowing is optional, go as you need +#export VERBOSE="true" ##for detail log info. If not need, remove this item. #export PRIMARY_MODEL="Qwen/Qwen2.5-14B-Instruct" #export SECONDARY_MODEL="THUDM/glm-4-9b-chat" export PROJECT_DIR="work_dir" -#export "PB_API_BASE"="" ##only use if your pb not run on 127.0.0.1:8090 \ No newline at end of file +#export PB_API_BASE="" ##only use if your pb not run on 127.0.0.1:8090 \ No newline at end of file diff --git a/core/pb/LICENSE.md b/pb/LICENSE.md similarity index 100% rename from core/pb/LICENSE.md rename to pb/LICENSE.md diff --git a/core/pb/README.md b/pb/README.md similarity index 100% rename from core/pb/README.md rename to pb/README.md diff --git a/core/pb/pb_migrations/1733204939_created_articles.js b/pb/pb_migrations/1733204939_created_articles.js similarity index 100% rename from core/pb/pb_migrations/1733204939_created_articles.js rename to pb/pb_migrations/1733204939_created_articles.js diff --git a/core/pb/pb_migrations/1733234529_created_focus_points.js b/pb/pb_migrations/1733234529_created_focus_points.js similarity index 100% rename from core/pb/pb_migrations/1733234529_created_focus_points.js rename to pb/pb_migrations/1733234529_created_focus_points.js diff --git a/core/pb/pb_migrations/1733234644_updated_focus_points.js b/pb/pb_migrations/1733234644_updated_focus_points.js similarity index 100% rename from core/pb/pb_migrations/1733234644_updated_focus_points.js rename to pb/pb_migrations/1733234644_updated_focus_points.js diff --git a/core/pb/pb_migrations/1733465276_created_sites.js b/pb/pb_migrations/1733465276_created_sites.js similarity index 100% rename from core/pb/pb_migrations/1733465276_created_sites.js rename to pb/pb_migrations/1733465276_created_sites.js diff --git a/core/pb/pb_migrations/1733465426_updated_articles.js b/pb/pb_migrations/1733465426_updated_articles.js similarity index 100% rename from core/pb/pb_migrations/1733465426_updated_articles.js rename to pb/pb_migrations/1733465426_updated_articles.js diff --git a/core/pb/pb_migrations/1733465563_created_infos.js b/pb/pb_migrations/1733465563_created_infos.js similarity index 100% rename from core/pb/pb_migrations/1733465563_created_infos.js rename to pb/pb_migrations/1733465563_created_infos.js From 7752b4b3b404eaa809128960f0fcd61c7e175ddb Mon Sep 17 00:00:00 2001 From: bigbrother666sh Date: Tue, 10 Dec 2024 14:18:03 +0800 Subject: [PATCH 9/9] V0.3.5 --- CHANGELOG.md | 2 +- Dockerfile | 1 - README.md | 190 +++++++++--------- asset/sample.png | Bin 545971 -> 0 bytes compose.yaml | 3 +- core/agents/get_info.py | 5 +- core/docker_entrypoint.sh | 2 +- core/general_process.py | 82 +++----- core/run.sh | 2 +- core/run_task.sh | 18 ++ core/tasks.py | 27 +-- pb/README.md | 2 +- .../1733204939_created_articles.js | 121 ----------- .../1733465426_updated_articles.js | 28 --- pb/pb_migrations/1733465563_created_infos.js | 13 -- pb/pb_migrations/1733753289_updated_infos.js | 39 ++++ .../1733753354_updated_focus_points.js | 42 ++++ version | 2 +- 18 files changed, 247 insertions(+), 332 deletions(-) delete mode 100644 asset/sample.png create mode 100755 core/run_task.sh delete mode 100644 pb/pb_migrations/1733204939_created_articles.js delete mode 100644 pb/pb_migrations/1733465426_updated_articles.js create mode 100644 pb/pb_migrations/1733753289_updated_infos.js create mode 100644 pb/pb_migrations/1733753354_updated_focus_points.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a49097..49308d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# V0.3.2 +# V0.3.5 - 引入 Crawlee(playwrigt模块),大幅提升通用爬取能力,适配实际项目场景; Introduce Crawlee (playwright module), significantly enhancing general crawling capabilities and adapting to real-world task; diff --git a/Dockerfile b/Dockerfile index b35991b..6bc63dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,6 @@ ADD https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/pocketbas # for arm device # ADD https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/pocketbase_0.23.4_linux_arm64.zip /tmp/pb.zip RUN unzip /tmp/pb.zip -d /pb/ -COPY pb/pb_migrations /pb/pb_migrations RUN apt-get clean && rm -rf /var/lib/apt/lists/* EXPOSE 8090 diff --git a/README.md b/README.md index be528a8..885ab22 100644 --- a/README.md +++ b/README.md @@ -8,42 +8,34 @@ 🌱看看首席情报官是如何帮您节省时间,过滤无关信息,并整理关注要点的吧!🌱 -https://github.com/TeamWiseFlow/wiseflow/assets/96130569/bd4b2091-c02d-4457-9ec6-c072d8ddfb16 -## 🔥 隆重介绍 V0.3.2 版本 +## 🔥 隆重介绍 V0.3.5 版本 -在充分听取社区反馈意见基础之上,我们重新提炼了 wiseflow 的产品定位,新定位更加精准也更加聚焦,V0.3.2版本即是该定位下的全新架构版本,相对于之前版本如下改进: +在充分听取社区反馈意见基础之上,我们重新提炼了 wiseflow 的产品定位,新定位更加聚焦,V0.3.5版本即是该定位下的全新架构版本: -- 引入 [Crawlee](https://github.com/apify/crawlee-python) 基础爬虫架构,大幅提升页面获取能力。实测之前获取不到(包括获取为乱码的)页面目前都可以很好的获取了,后续大家碰到不能很好获取的页面,欢迎在 [issue #136](https://github.com/TeamWiseFlow/wiseflow/issues/136) 中进行反馈; -- 新产品定位下全新的信息提取策略——“爬查一体”,放弃文章详细提取,全面使用 llm 直接从页面中提取用户感兴趣的信息(infos),同时自动判断值得跟进爬取的链接; +- 引入 [Crawlee](https://github.com/apify/crawlee-python) 作为基础爬虫和任务管理框架,大幅提升页面获取能力。实测之前获取不到(包括获取为乱码的)页面目前都可以很好的获取了,后续大家碰到不能很好获取的页面,欢迎在 [issue #136](https://github.com/TeamWiseFlow/wiseflow/issues/136) 中进行反馈; +- 新产品定位下全新的信息提取策略——“爬查一体”,放弃文章详细提取,爬取过程中即使用 llm 直接提取用户感兴趣的信息(infos),同时自动判断值得跟进爬取的链接,**你关注的才是你需要的**; - 适配最新版本(v0.23.4)的 Pocketbase,同时更新表单配置。另外新架构已经无需 GNE 等模块,requirement 依赖项目降低到8个; - 新架构部署方案也更加简便,docker 模式支持代码仓热更新,这意味着后续升级就无需再重复docker build了。 - 更多细节,参考 [CHANGELOG](CHANGELOG.md) -🌟 注意: +🌟 **V0.3.x 后续计划** -V0.3.2 架构和依赖上都较之前版本有诸多变化,因此请务必重新拉取代码仓,并参考最新的部署方案重新部署,V0.3.2支持python 环境源码使用、docker 容器部署,同时我们也即将上线免部署的服务网站,注册账号就可以直接使用,敬请期待! - -V0.3.2 版本效果截图: - -sample.png - -V0.3.x 后续计划中的升级内容还有: - -- 尝试引入新的 mp_crawler, 公众号文章监控无需wxbot; -- 引入对 RSS 信息源的支持; -- 引入 [SeeAct](https://github.com/OSU-NLP-Group/SeeAct) 方案,通过视觉大模型提升 wiseflow 自主深入挖掘能力。 +- 引入 [SeeAct](https://github.com/OSU-NLP-Group/SeeAct) 方案,通过视觉大模型指导复杂页面的操作,如滚动、点击后出现信息等情况(V0.3.6); +- 尝试支持微信公众号免wxbot订阅(V0.3.7); +- 引入对 RSS 信息源的支持(V0.3.8); +- 尝试引入 LLM 驱动的轻量级知识图谱,帮助用户从 infos 中建立洞察(V0.3.9)。 ## ✋ wiseflow 与传统的爬虫工具、AI搜索、知识库(RAG)项目有何不同? -承蒙大家的厚爱,wiseflow自2024年6月底发布 V0.3.0版本来受到了开源社区的广泛关注,甚至吸引了不少自媒体的主动报道,在此首先表示感谢! +wiseflow自2024年6月底发布 V0.3.0版本来受到了开源社区的广泛关注,甚至吸引了不少自媒体的主动报道,在此首先表示感谢! -但我们也注意到部分关注者对 wiseflow 的功能定位存在一些理解偏差,如下表格列出了 wiseflow 与传统爬虫工具、AI搜索、知识库(RAG)类项目的对比: +但我们也注意到部分关注者对 wiseflow 的功能定位存在一些理解偏差,如下表格通过与传统爬虫工具、AI搜索、知识库(RAG)类项目的对比,代表了我们目前对于 wiseflow 产品最新定位思考。 | | 与 **首席情报官(Wiseflow)** 的比较说明| |-------------|-----------------| -| **爬虫类工具** | 首先 wiseflow 是基于爬虫工具的项目(以目前的版本而言,wiseflow 集成了优秀的开源爬虫项目 Crwalee,而 Crawlee 的底层又是基于 beautifulsoup\playwright\httpx等大家耳熟能详的流行库)……但传统的爬虫工具都是面向开发者的,需要开发者手动去探索目标站点的结构,分析出要提取元素的 xpath 等,这不仅阻挡了普通用户,同时也毫无通用性可言,即对于不同网站(包括已有网站升级)都需要重做分析和探索。这个问题在 LLM 出现之前是无解的,而wiseflow致力的方向即是使用 LLM 自动化目标站点的分析和探索工作,从而实现“普通用户也可使用的通用爬虫”,从这个角度来说,你可以简单理解 wiseflow 为 “能自动使用爬虫工具的 AI 智能体” | +| **爬虫类工具** | 首先 wiseflow 是基于爬虫工具的项目(以目前版本而言,我们基于爬虫框架 Crawlee),但传统的爬虫工具在信息提取方面需要人工的介入,提供明确的 Xpath 等信息……这不仅阻挡了普通用户,同时也毫无通用性可言,对于不同网站(包括已有网站升级后)都需要人工重做分析,并更新提取代码。wiseflow致力于使用 LLM 自动化网页的分析和提取工作,用户只要告诉程序他的关注点即可,从这个角度来说,可以简单理解 wiseflow 为 “能自动使用爬虫工具的 AI 智能体” | | **AI搜索** | AI搜索主要的应用场景是**具体问题的即时问答**,举例:”XX公司的创始人是谁“、“xx品牌下的xx产品哪里有售” ,用户要的是**一个答案**;wiseflow主要的应用场景是**某一方面信息的持续采集**,比如XX公司的关联信息追踪,XX品牌市场行为的持续追踪……在这些场景下,用户能提供关注点(某公司、某品牌)、甚至能提供信源(站点 url 等),但无法提出具体搜索问题,用户要的是**一系列相关信息**| | **知识库(RAG)类项目** | 知识库(RAG)类项目一般是基于已有信息的下游任务,并且一般面向的是私有知识(比如企业内的操作手册、产品手册、政府部门的文件等);wiseflow 目前并未整合下游任务,同时面向的是互联网上的公开信息,如果从“智能体”的角度来看,二者属于为不同目的而构建的智能体,RAG 类项目是“(内部)知识助理智能体”,而 wiseflow 则是“(外部)信息采集智能体”| @@ -57,31 +49,56 @@ V0.3.x 后续计划中的升级内容还有: git clone https://github.com/TeamWiseFlow/wiseflow.git ``` -### 2. 参考env_sample 配置 .env文件放置在 core 目录下 +### 2. 参考 env_sample 配置 .env 文件放置在 core 目录下 -🌟 **这里与之前版本不同**,V0.3.2开始需要把 .env 放置在 core文件夹中。 +🌟 **这里与之前版本不同**,V0.3.5开始需要把 .env 放置在 core文件夹中。 -另外 V0.3.2 起,env 配置也大幅简化了,必须的配置项目只有三项,具体如下: +另外 V0.3.5 起,env 配置也大幅简化了,必须的配置项目只有三项,具体如下: -- LLM_API_KEY="" # 这还是你的大模型服务key,这是必须的 -- LLM_API_BASE="https://api.siliconflow.cn/v1" # 服务接口地址,任何支持 openai sdk 的服务商都可以(推荐 siliconflow),如果直接使用openai 的服务,这一项也可以不填 -- PB_API_AUTH="test@example.com|1234567890" # pocketbase 数据库的 superuser 用户名和密码,记得用 | 分隔 +- LLM_API_KEY="" + + 大模型服务key,这是必须的 + +- LLM_API_BASE="https://api.siliconflow.cn/v1" + + 服务接口地址,任何支持 openai sdk 的服务商都可以,如果直接使用openai 的服务,这一项也可以不填 + +- PB_API_AUTH="test@example.com|1234567890" + + pocketbase 数据库的 superuser 用户名和密码,记得用 | 分隔 下面的都是可选配置: -- #VERBOSE="true" # 是否开启观测模式,开启的话,不仅会把 debug log信息记录在 logger 文件上(模式仅是输出在 console 上),同时会开启 playwright 的浏览器窗口,方便你观察抓取过程,但同时会增加抓取速度; -- #PRIMARY_MODEL="Qwen/Qwen2.5-7B-Instruct" # 主模型选择,在使用 siliconflow 服务的情况下,这一项不填就会默认调用Qwen2.5-7B-Instruct,实测基本也够用,但我更加**推荐 Qwen2.5-14B-Instruct** -- #SECONDARY_MODEL="THUDM/glm-4-9b-chat" # 副模型选择,在使用 siliconflow 服务的情况下,这一项不填就会默认调用glm-4-9b-chat。 -- #PROJECT_DIR="work_dir" # 项目运行数据目录,不配置的话,默认在 `core/work_dir` ,注意:目前整个 core 目录是挂载到 container 下的,所以意味着你可以直接访问这里。 -- #PB_API_BASE"="" # 只有当你的 pocketbase 不运行在默认ip 或端口下才需要配置,默认情况下忽略就行。 +- #VERBOSE="true" + 是否开启观测模式,开启的话,不仅会把 debug log信息记录在 logger 文件上(默认仅输出在 console 上),同时会开启 playwright 的浏览器窗口,方便观察抓取过程; -### 3.1 使用docker构筑 image 运行 +- #PRIMARY_MODEL="Qwen/Qwen2.5-7B-Instruct" + + 主模型选择,在使用 siliconflow 服务的情况下,这一项不填就会默认调用Qwen2.5-7B-Instruct,实测基本也够用,但我更加**推荐 Qwen2.5-14B-Instruct** + +- #SECONDARY_MODEL="THUDM/glm-4-9b-chat" + + 副模型选择,在使用 siliconflow 服务的情况下,这一项不填就会默认调用glm-4-9b-chat。 + +- #PROJECT_DIR="work_dir" + + 项目运行数据目录,不配置的话,默认在 `core/work_dir` ,注意:目前整个 core 目录是挂载到 container 下的,所以意味着你可以直接访问这里。 + +- #PB_API_BASE="" + + 只有当你的 pocketbase 不运行在默认ip 或端口下才需要配置,默认情况下忽略就行。 + +### 3.1 使用docker运行 + +✋ V0.3.5版本架构和依赖与之前版本有较大不同,请务必重新拉取代码,删除旧版本镜像(包括外挂的 pb_data 文件夹),重新build! 对于国内用户,可以先配置镜像源: 最新可用 docker 镜像加速地址参考:[参考1](https://github.com/dongyubin/DockerHub) [参考2](https://www.coderjia.cn/archives/dba3f94c-a021-468a-8ac6-e840f85867ea) -🌟 **三方镜像,风险自担。** +**三方镜像,风险自担。** + +之后 ```bash cd wiseflow @@ -90,14 +107,14 @@ docker compose up **注意:** -第一次运行docker container时可能会遇到报错,这其实是正常现象,因为你尚未为pb仓库创建 super user 账号。 - -此时请保持container不关闭状态,浏览器打开`http://127.0.0.1:8090/_/ `,按提示创建 super user 账号(一定要使用邮箱),然后将创建的用户名密码填入.env文件,重启container即可。 +第一次运行docker container时程序可能会报错,这是正常现象,请按屏幕提示创建 super user 账号(一定要使用邮箱),然后将创建的用户名密码填入.env文件,重启container即可。 -🌟 docker运行默认进入 task +🌟 docker方案默认运行 task.py ,即会周期性执行爬取-提取任务(启动时会立即先执行一次,之后每隔一小时启动一次) ### 3.2 使用python环境运行 +✋ V0.3.5版本架构和依赖与之前版本有较大不同,请务必重新拉取代码,删除(或重建)pb_data + 推荐使用 conda 构建虚拟环境 ```bash @@ -108,89 +125,65 @@ cd core pip install -r requirements.txt ``` -之后可以参考core/scripts 中的脚本分别启动pb、task和backend (将脚本文件移动到core目录下) - -**注意:** - - 一定要先启动pb,至于task和backend是独立进程,先后顺序无所谓,也可以按需求只启动其中一个; - - 需要先去这里 https://pocketbase.io/docs/ 下载对应自己设备的pocketbase客户端,并放置在 /core/pb 目录下 - - pb运行问题(包括首次运行报错等)参考 [core/pb/README.md](/pb/README.md) - - 使用前请创建并编辑.env文件,放置在wiseflow代码仓根目录(core目录的上级),.env文件可以参考env_sample,详细配置说明见下 +之后去这里 [下载](https://pocketbase.io/docs/) 对应的 pocketbase 客户端,放置到 [/pb](/pb) 目录下。然后 -📚 for developer, see [/core/README.md](/core/README.md) for more - -通过 pocketbase 访问获取的数据: - - http://127.0.0.1:8090/_/ - Admin dashboard UI - - http://127.0.0.1:8090/api/ - REST API - +```bash +chmod +x run.sh +./run_task.sh # if you just want to scan sites one-time (no loop), use ./run.sh +``` -### 3. 配置 +这个脚本会自动判断 pocketbase 是否已经在运行,如果未运行,会自动拉起。但是请注意,当你 ctrl+c 或者 ctrl+z 终止进程时,pocketbase 进程不会被终止,直到你关闭terminal。 -复制目录下的env_sample,并改名为.env, 参考如下 填入你的配置信息(LLM服务token等) - -**windows用户如果选择直接运行python程序,可以直接在 “开始 - 设置 - 系统 - 关于 - 高级系统设置 - 环境变量“ 中设置如下项目,设置后需要重启终端生效** +另外与 docker 部署一样,第一次运行时可能会出现报错,请按屏幕提示创建 super user 账号(一定要使用邮箱),然后将创建的用户名密码填入.env文件,再次运行即可。 - - LLM_API_KEY # 大模型推理服务API KEY - - LLM_API_BASE # 本项目依赖openai sdk,只要模型服务支持openai接口,就可以通过配置该项正常使用,如使用openai服务,删除这一项即可 - - WS_LOG="verbose" # 设定是否开始debug观察,如无需要,删除即可 - - GET_INFO_MODEL # 信息提炼与标签匹配任务模型,默认为 gpt-4o-mini-2024-07-18 - - REWRITE_MODEL # 近似信息合并改写任务模型,默认为 gpt-4o-mini-2024-07-18 - - HTML_PARSE_MODEL # 网页解析模型(GNE算法效果不佳时智能启用),默认为 gpt-4o-mini-2024-07-18 - - PROJECT_DIR # 数据、缓存以及日志文件存储位置,相对于代码仓的相对路径,默认不填就在代码仓 - - PB_API_AUTH='email|password' # pb数据库admin的邮箱和密码(注意一定是邮箱,可以是虚构的邮箱) - - PB_API_BASE # 正常使用无需这一项,只有当你不使用默认的pocketbase本地接口(8090)时才需要 - - -### 4. 模型推荐 [2024-09-03] +当然你也可以在另一个 terminal 提前运行并设定 pocketbase(这会避免第一次的报错),具体可以参考 [pb/README.md](/pb/README.md) -经过反复测试(中英文任务)**GET_INFO_MODEL**、**REWRITE_MODEL**、**HTML_PARSE_MODEL** 三项最小可用模型分别为:**"THUDM/glm-4-9b-chat"**、**"Qwen/Qwen2-7B-Instruct"**、**"Qwen/Qwen2-7B-Instruct"** - -目前,SiliconFlow已经官宣Qwen2-7B-Instruct、glm-4-9b-chat在线推理服务免费,这意味着您可以“零成本”使用wiseflow啦! +### 4. 模型推荐 [2024-12-09] + +虽然参数量越大的模型意味着更佳的性能,但经过实测,**使用 Qwen2.5-7b-Instruct 和 glm-4-9b-chat 模型,即可以达到基本的效果**。不过综合考虑成本、速度和效果,我更加推荐主模型 +**(PRIMARY_MODEL)使用Qwen2.5-14B-Instruct**。 + +这里依然强烈推荐使用 siliconflow(硅基流动)的 MaaS 服务,提供多个主流开源模型的服务,量大管饱,Qwen2.5-7b-Instruct 和 glm-4-9b-chat 目前提供免费服务。(主模型使用Qwen2.5-14B-Instruct情况下,爬取374个网页,有效抽取43条 info,总耗费¥3.07) -😄 如果您愿意,可以使用我的[siliconflow邀请链接](https://cloud.siliconflow.cn?referrer=clx6wrtca00045766ahvexw92),这样我也可以获得更多token奖励 😄 +😄 如果您愿意,可以使用我的[siliconflow邀请链接](https://cloud.siliconflow.cn?referrer=clx6wrtca00045766ahvexw92),这样我也可以获得更多token奖励 🌹 -⚠️ **V0.3.1更新** - -如果您使用带explaination的复杂tag,那么glm-4-9b-chat规模的模型是无法保证准确理解的,目前测试下来针对该类型任务效果比较好的模型为 **Qwen/Qwen2-72B-Instruct** 和 **gpt-4o-mini-2024-07-18** 。 +**如果您的信源多为非中文页面,且也不要求提取出的 info 为中文,那么更推荐您使用 openai 或者 claude 等海外厂家的模型。** -针对有需求使用 `gpt-4o-mini-2024-07-18` 的用户,可以尝试第三方代理 **AiHubMix**,支持国内网络环境直连、支付宝充值(实际费率相当于官网86折) +您可以尝试第三方代理 **AiHubMix**,支持国内网络环境直连、支付宝便捷支付,免去封号风险; -🌹 欢迎使用如下邀请链接 [AiHubMix邀请链接](https://aihubmix.com?aff=Gp54) 注册 🌹 +😄 欢迎使用如下邀请链接 [AiHubMix邀请链接](https://aihubmix.com?aff=Gp54) 注册 🌹 -🌍 上述两个平台的在线推理服务均兼容openai SDK,配置`.env `的`LLM_API_BASE`和`LLM_API_KEY`后即可使用。 +🌟 **请注意 wiseflow 本身并不限定任何模型服务,只要服务兼容 openAI SDK 即可,包括本地部署的 ollama、Xinference 等服务** ### 5. **关注点和定时扫描信源添加** 启动程序后,打开pocketbase Admin dashboard UI (http://127.0.0.1:8090/_/) -#### 5.1 打开 tags表单 +#### 5.1 打开 focus_point 表单 通过这个表单可以指定你的关注点,LLM会按此提炼、过滤并分类信息。 -tags 字段说明: - - name, 关注点名称 - - explaination,关注点的详细解释或具体约定,如 “仅限上海市官方发布的初中升学信息”(tag name为 上海初中升学信息) - - activated, 是否激活。如果关闭则会忽略该关注点,关闭后可再次开启。开启和关闭无需重启docker容器,会在下一次定时任务时更新。 +字段说明: +- focuspoint, 关注点描述(必填),如”上海小升初信息“、”加密货币价格“ +- explanation,关注点的详细解释或具体约定,如 “仅限上海市官方发布的初中升学信息”、“BTC、ETH 的现价、涨跌幅数据“等 +- activated, 是否激活。如果关闭则会忽略该关注点,关闭后可再次开启。 + +注意:focus_point 更新设定(包括 activated 调整)后,**需要重启程序才会生效。** #### 5.2 打开 sites表单 通过这个表单可以指定自定义信源,系统会启动后台定时任务,在本地执行信源扫描、解析和分析。 sites 字段说明: - - url, 信源的url,信源无需给定具体文章页面,给文章列表页面即可。 - - per_hours, 扫描频率,单位为小时,类型为整数(1~24范围,我们建议扫描频次不要超过一天一次,即设定为24) - - activated, 是否激活。如果关闭则会忽略该信源,关闭后可再次开启。开启和关闭无需重启docker容器,会在下一次定时任务时更新。 +- url, 信源的url,信源无需给定具体文章页面,给文章列表页面即可。 +- per_hours, 扫描频率,单位为小时,类型为整数(1~24范围,我们建议扫描频次不要超过一天一次,即设定为24) +- activated, 是否激活。如果关闭则会忽略该信源,关闭后可再次开启。 + +**sites 的设定调整,无需重启程序。** -### 6. 本地部署 - -如您所见,本项目最低仅需使用7b\9b大小的LLM,且无需任何向量模型,这就意味着仅仅需要一块3090RTX(24G显存)就可以完全的对本项目进行本地化部署。 - -请保证您的本地化部署LLM服务兼容openai SDK,并配置 LLM_API_BASE 即可。 - -注:若需让7b~9b规模的LLM可以实现对tag explaination的准确理解,推荐使用dspy进行prompt优化,但这需要累积约50条人工标记数据。详见 [DSPy](https://dspy-docs.vercel.app/) - -## 🔄 如何在您自己的程序中使用 wiseflow 抓取出的数据 +## 📚 如何在您自己的程序中使用 wiseflow 抓取出的数据 1、参考 [dashbord](dashboard) 部分源码二次开发。 @@ -211,19 +204,22 @@ PocketBase作为流行的轻量级数据库,目前已有 Go/Javascript/Python 商用以及定制合作,请联系 **Email:35252986@qq.com** - - 商用客户请联系我们报备登记,产品承诺永远免费。 +- 商用客户请联系我们报备登记,产品承诺永远免费。 ## 📬 联系方式 -有任何问题或建议,欢迎通过 [issue](https://github.com/TeamWiseFlow/wiseflow/issues) 与我们联系。 +有任何问题或建议,欢迎通过 [issue](https://github.com/TeamWiseFlow/wiseflow/issues) 留言。 ## 🤝 本项目基于如下优秀的开源项目: -- GeneralNewsExtractor ( General Extractor of News Web Page Body Based on Statistical Learning) https://github.com/GeneralNewsExtractor/GeneralNewsExtractor +- crawlee-python (A web scraping and browser automation library for Python to build reliable crawlers. Works with BeautifulSoup, Playwright, and raw HTTP. Both headful and headless mode. With proxy rotation.) https://github.com/apify/crawlee-python - json_repair(Repair invalid JSON documents ) https://github.com/josdejong/jsonrepair/tree/main - python-pocketbase (pocketBase client SDK for python) https://github.com/vaphes/pocketbase +- SeeAct(a system for generalist web agents that autonomously carry out tasks on any given website, with a focus on large multimodal models (LMMs) such as GPT-4Vision.) https://github.com/OSU-NLP-Group/SeeAct + +同时受 [GNE](https://github.com/GeneralNewsExtractor/GeneralNewsExtractor)、[AutoCrawler](https://github.com/kingname/AutoCrawler) 启发。 ## Citation @@ -233,4 +229,4 @@ PocketBase作为流行的轻量级数据库,目前已有 Go/Javascript/Python Author:Wiseflow Team https://github.com/TeamWiseFlow/wiseflow Licensed under Apache2.0 -``` +``` \ No newline at end of file diff --git a/asset/sample.png b/asset/sample.png deleted file mode 100644 index 5fc04ea3bb0f8d24f409fbc79a0a2c4d6d2b01d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 545971 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�kL`w-+R0Y40p7Uim|7_dpCC{+5V_e130@Z0ZhnukOz^! zaEhK`7n1KtnqY;kBcL115abuSxSBYympkC)JW#h>U0m?)1NU-$M7AEhIO*~KRMvzxa9w)jjt zJ?Y_D*N5YCq4j6fmmH>i#0_qrJ#Jbpp@Y`n{Kw-89ZP{00!P7+t~I{U0K4o-*+ku9 z{=~CWQC_Dt34>CfU;d5I0q?oVF~lVT@+i)UR%K)T`=yKG>l>)BV0_~F7|3f;K1{RC zH~138kqIZC@1uG8i%h;0MnY6_$`gb%oRiT59M1eq-(;VAH7DED8-B?_rg`K zwBzN7?N6J9sfj%Gd!Dk%so-+4R#8&2i5kyE`7d)rp4iT$k_2oU0&)Y3B&TEj-fb^r zWEZ7r$&M*xX17q-9)0u3ZJZH7pQ~4H2aAYwy$7_0!qsTedd)~$OuF*M0DxQNcr5~J z8VpwqXqN=%4P()HC~o6LO>33v1yY5f=6LjDZms+#s&^*RhU4)$dNNh2PbC?TLdYrB zi0XE=W38_VzrXAB5tkGfsmcTz&q6kTgC=qy;3>+PzU69NVY;iuU}G~~hxoR368i=H z#oaYBLrMuG3x<%h5-#e-#5Bh>mLm0RjiKkujOS5)Y|rGgZ)+o|$c^s%8tu;*M{4Nx z@Vg@knV(F$0Wg(^=ZJ_Pn}QPj9lC>q@_ZQEG!Po6Sria*ARSArsr=@r2ci|Eh(RRO z^tc!9XNOoYA!m{4XhyS6tI%8cZxsbus#K-I@Sp$P3n0&ENE&_EIvNr2k(Lhj+q?cW zf`^BP0z<>6Ra*;ln$nJ3+a_H6oQNI$VnaeRD@LV zC-ogBR;#dYhRRZFN!A zwHlINq1vAb{ij}PHow;p9b6{p!%|>n>Rqmzuxp%ARq*9M)r4QPcweHHl$N@dWj|4~ zyK~_jQlR`g!JhsRF^db`Pl^J@x6Cf6GePBHc zLU)+@p^b(UpX2*t37V%^y1cd)&aB_KmDb`7u>~{yToK799h}p?{6F0c36*2@wTc8|K9k_e}R4uQBgw!kCh6zhzA~Bzk zW!mx+5rHfqX+}nFJcYQ4$Y{EupXg`i*prMNvY5|e{6XRci5-XQi2$qI{0z{JzkLv_6rM?dQ9=3qhW)_QnJ8LLe+W(x2V(mSm%O06t@8Q)4ssdWM=2hT&K`uFZ7% zd2XEhS$Ot)i#gdR40=EGn|)+Ab^L@)av`0jDdsI2(XvKmr`W6Y6z%erw(7*@qi9JI zb2}BE$VIyCFZ8e(HDoq@%FfLJ77ycVBw?tF_(mK~``|MF?tN{G8K7=7s0T-EZ?^s^ z^5$^&$z(##pN{GsWp2AH?L#4}ISNtv<6-Wl=j0(TsdTw}ja#6^XAX{{c|%`}$6Khl zB+8{Fbm(ViW(zkRo5dz^-pbwgIC}_#TOeR_8d1tuzt!B8J^-7vi_`DdA4%8)ioVVA zR%izvL2FylFC6-Js`&eSO$g=;y}Pd#<28lUHyAxmH=Pb@(k zGTum^yT_j{*{Znp+2(0}&UTiTz5-bFBvk0xxH6d1hl!;j79B|ojRL#uxcA0&OoxP& zb{B>yHCCtAkLfY*3!wqAmw3Ts+K}XsGYvvsbR${#S>+ z1NwgDvV_hKE#r-nH%FQ52mokC(jFq@G(s zLoWZ>flXA7Cgkj)cL=8@RnEAhy=8s5e6aX~>j z4%zj0KX2Qwt2No>hY+93;1+zGx(ot+<4N{di0@?ns8_v{Rk%!#J?fL;aXE+vBd8r6 zVxJ}GXhx~O_d1n=GNmo3N?((`q9kf?)6*l?)4vhZHB-8+Tk})izW;W1<>k8Dxv+pz z<5t5U$SK+TDvK&eS(f9wve7q=9z8l|^=O)hdx&A;CWVYF|3+F4vj1|s9s--+F2C>F zDkj$awW-?jukNxJ!S7JBtQLkd{S)!;dr32ItcBGNuQL~Oomybux;Yo1{0dyDj%89oI0OJE{-9U4pZhUt!^CnK4CA3o9YaPx|S zziM|L=hI8;@J~WrLK}qrI{tj_@ADHG8G1`%-+~%`%!kiHYm2{kczdxhS$~zHHRUO( zYtGI<+OAKJj#hl9XWiTJ2-yGJR2LUO(R#S8En5b!1=GAQFttl`aD&AWPzy}Y)*|3M zp_CAN)}5kP+RUpE1T>Xq^HTpcrIywb;2b#qSZlGQj<;DX5NhCYgY?hfH^etuv%JCk zSTUqAPHHhEJZb+6T}e=1(cl%GJIQ*pekC95wfYlGh27nqwS&34#+j#u`+-R%aR&>n zaVV8U@w>N&s&x(+6z1=IJFBg=+m}+1H|=G=TB=gzb@EqlU(BPSJZ>lPsuJ#HI zq)E&2(VbS_XX4I5HBRWkv3MDqL8olEd~83eVC8r_Lb5ECVI%kDwS|~D(*`zef_xG^ zLv%D$Q3MHjJaI1G8NeE;lE;$q(*}OGQxa5Y@ZbONaJP!~;@~j$x7lEOk(s>cW-|R7 zr0;S>=8JScA}_lT-`kFp0&lz1M%d7peS7WK6tTe56o~RLWS9OhVDtGsC1mS?j21;4}5Z;~b@g>LAo>42OD0uSAL+dA`@7nVR zqSU%NTfZR5Af}K7fVq0p*`I}0FpQa^gSe%D2E9|Fp9(&{!!aRAzr{y2G96naGUp&G z?R2ewTq56@@fDZTn#`v+vE8puH{gxRpgu3~mzfn>kOD%Z6sopHzOXCn`00B$7MaRz z?}kpF_a&~&b68DFw6W~Z&Cnvt7^_7F5ELQAkO{+-Lw%S`mo!8M4w}7PCRonwL81sE zBg12f9$)1-D3yMg@lbDPch6>IzWf_NOfIT*p$sp5HVJtakbA{eC$ zuy4YAZ{2o>)CHN4hHi3elVvGs!Y!jK9R&rUD-laO@i>gO<_mXuV8RxF~zQMsQ%7yLRw1pJ1 zw+ttvED8y!{mQdvETZHwT516(ojyFMq|+>tng$=6%?vE33lPn(6s6PopwaLO*R=7* zUVo?`>3VcGLhBzM0J>t1OVp)4V11pQnO)K8VB_o;-;fA$?2EiR=|+Axm_Y*kH%VXP z#XHYGSR8FoMVL`^}zSIFZCeI;S#z40V$2og@x_1)!CCQ{$Wwz!n(_b|*l zy4ykbXT2{2aZIISCR9nrghQ=}BgK$lIuvvmlF`Y^ojnqABooflPc+iK&cQU>vtN(( z<)M_F51`4T&3pC*j!4JSl$4ZF&5{eKPLl2O%?{vePN+6q?nMB=*DQZ~yl7%})LnpS zgd{_;Rhn;#=W;mqR5B7btoTPRHJ9J*zI)w;tNLxd&9;fE5*7J6XfHYWf5~`Ejdyqmal5sRszTGK01r)014^nV(m9h=Hf89$>^zNCpbsA08Xs3^x ze3tQ37?lj+ww3G zx6F7JHaj`ZdC!-^TV;b|^}gIK?+sI2-4>r?%+Ji}+AN+|%M^P{jR?pef{wfK7)&?m zZVRH+x$98ygF%d7Iyyq~-gF!lkOl_(hPmOhc}4Gi_x1HbuNRWSmJ$z2UIqX4;tvw0dyT245RF$`+>`kN2c~#;bO=1M2bW3n zgJHzC_AqKmEs_!va$_wNB1jQ~_z1rDH%xr9Zt>OfZ9(u`hX)zqI@{t0oHU!?Kp1*w z5JxKLqLHoc#B^^8I`ks&Mh&w7d=;6m&rbRMgRKZsd8_9sE;ft7nIU}6mlGeglTty~ z9qd@rDCyn{5^CeU8a0ifG6BWd}G{z(Z*43oiE`G^6`gI|wS7>!SZYP<7>0;}-$7W6%OFKs)5vWz+31>cO zU{Hr^cDwGwt+GojReVoNxjX(hk){Sl_IE&~(Px4M_x%W36xiZDmv3?T>bC7%4$u+F z4AAr4CseK@P||)cB+ST$)i}e8t&|AnkLt*G!(v-M)=3jf?+?n5<5n{&ku@07MFxnA zN0X!?KU7KG8TVPK@UKDscyKk;OIRM-V+Yj9n`@u zF_`#pFu{Mt*%X)lo*qUNk4Yw4c#LE*QakNV;}ZBpl%UD#VDhQRXa)>iq$sgysv>Ag zPUZ;5h7He#)?Gx4pMegEd@2P`XV z*Eg7dAri(f{;+Z|>I-~C??7znyTduV;thii%&eZ>@pRbiBLO*+(dff@$H#so#q>Xk zWk!EP8{VrBHGocIN3()5{935sBLdM6)lqHF&Kd~J_%-Y%QtXn(#(8ktP0^?5krg_B zRlB|56|;GyO0`qV@ed0M5=bQM>}*ww!dOv=Bfr?pP2=YIf?-?a=Hgjz z_E(olBU73CF)=VaP>Em=5g|n?FNUk8r#W3`gynL70BbPAFm?h0iyY2sL(q(OP(?wB zF>IH<{yESC-zm{>nxa|HRif{bDZ>QheUU727emC4d!H-~?WSfIxPiw6?^xLmWIq2u z2#4vdY$7xx>O!-1m5EG&urJtd_)vA{#~xMiU>B zDCC7@+tG8?+5T%zp|Sq>{0J4-G&U`mi7kdat2$S0@Mb^`Xzj0+n28m7Q(^olZAf&& zbUHs!^uWJ*^;3D!oePe zs~e{DLiK9)nRm55g>m4a=>VYO1Gsuqm zq6??>5g(&5)#h6`80h!r*0v=VF^$}VDj zYEgj_MEPZl%awvY1#ItNwN_GfcrmiMYAYchDuEoOmdOi;Z z=quf>3KIjZ7$i}4dS&FFyjliEnO z=PREY0ME1V^D(i#;V|_%1(t{y5a~bi@^((*f_QN5>!?z2lYBB0kp|WrLeX>$An%j= zzUsF*hi5h|ce@_)_&ndyYgFmtF;|v2>L;pFf6ft-*tj}~6;-PFL%PvaN~G2s;QdatvkyUuA$XB2owu&+TuwVZ%Bk=yg_Ch|6$nU151-wq2E@Y z(PGjuIVnv0F~9#0KO4K~cvjst->mOv{_DF=@CPftRNT`tjGdz5|Aw0zoez<>Ut#i= zJIJ{jT4`(8HSeBG)Pfb6%;3%}Tcq74CUf5$L>u8}FjHH{_zR7Pde_rvUgBeO$D-3} zMY+^s1C~o%mxJet^jj})G|L!Xd~eo-D|I>$SiAJMggMP0o5}dSUIA5l@MG?N0MFjd zS*_~PV$*wN3vs^7E3P><00kp=xY?$*R(cc2xST9WEg46P?Oj+bbU;$eoLwAUBo>{v zw}p;BbJ>uY&een##7WSdg@FjUof$^1dRrzYL=8jpE{Sa>O{w33-e`JtB%ty*?jAa| z+g{+C^4z<#bOC{znKpxMh@~ysw>kxh+-Q!&Z3wSCpJ1*C1@^^ch2A7BdKO$;*IbyrtMkLd_4WV znD=L?3jM)yuL8c=uR*loG)n3(SNoA6(V4@q<<#QeUVGt@3tsPqw>4PywOhQ=`A(!; zgH_hyaxT$t7bg7-1ONNyyl{K~ia!kXP?VNG(x}o!dQfQ9yLi(9i!8^<*C+h=fCa;p zlBk}u`?1d$QPO`oB{VKk4KOLZ`F$ne*F55@R+ zdq0)s{~U-|Xe^H6fx1UOU?M5~C7_(z5ND9u^6~>C*)GCM-`!=vIEbSs+8IBS{Cx9l zwbGCM9RclKy3;nzt>jL{nd{;C*s;;OZs&*^@{1iXukt$~XXN5H@?q8(_546$qD3gO z+A?gTa3p5O%rxbdWe>|di*d`Q;Zto_)B!?~)J%q~j=naJUCeUNiu4s2qSBO-s@@YI z_S>y9`d>>TUPrzj>&wI3AF9D1{{zmKG=A?4c3Ow`9``eHYWz9`9Y|v-tP+E4oJfb< zy#9&aB}l&r>{La0b!Zsns8|bP==&ohke5Hkg^3((Z!tWHy8SJ~Jw1R`Z%t>`Xk|Y- z;vT6iV)kyIiWgOh*+N%n=&^xS|HCs--s{9F)+h0O#^)_Nr}GX8<3_c{d6%i*bu=E6 zhHPn^@E30`ItYZg>!zmX@%6I1?d)B4lrW24V{hl(a{+@BNRbMXc~|C#iywZv(qur$ zf)|Wi><_B2P&TLqzI2s&SuKM+KlWAk5C){UU{SLW)Nm*Qp&Y32D-MnYOdOVSDAa}7 zN;MR5aq-)_(b%6f{%Cf(EdaQ(V>kH&hg6Wntb;!{H?gsO3~#i)U)$V_z34VDtS=>J z3*!~yfjUt9Ce_j5#Rs&)Ns4`7cD2V>^hnSZ zs~C;x%h5tUlJ0tsJNZ~@P5(Flrovf zP%;VLOMCW7M>E%1*kl2HMaSXQ+Vd6uDE}P$__(-P}y{y>9%|lqb4%Q@g7bQ zCI(|JlQr$i5tzTQd40N}J7P#pEbRU@LYlRoy2znpQ4IWn&_Pg%@C3@NfA8{2VoxtB z=Kqfc$f&Mn-J4#+2k)v-@G-$;3|a6s7B%d71`h!^l~sF1P%9m6nf!2j_I&_a#_F^? zL0j1g*gi?HwVWQvuaNV@?G{y>bZtB?b4#9Tw99l0i-`C(uZw;37tQ9Gu`x0d!zM3X7g>FX^roObK82efyR4 z=~^|6esLW|m)6u;fe20~GocboW`J=@XPfh8sMj40^rUC<%VtCJ9i5P(Qjl|J^NydZ~JKnYK+)40&ScBPU5aO%EA+ zZ_`V%q@vCcrx*{Lv50_s{ZPxg&zmRnvj`hFJHOpQCCB=~r@Hzbh}H0`6=Rr4B+-G^ z>q0IsGX=EP;A^G1%3A9m>QD?xo}#`dm44NkdY7Mf#fk;ibs9iBs1zfdX+CD+>&Y(t zTK5~}EjDdgzjq&%bFsInyr~zqI!>J^EWL4co2{t_2mrAU>rcT|VzI~d}U6yVpLrR5Doo;}^PO&7S@TqUvfJnBBC zV*27j+>WswS_;tTKW`WdL7q_yL(!zHwsdvI(vW5EX67efk_i_7OAr6Uh5yHB<6M9H zeQWkATDC);@t^LC#`^v`cXU>rI<}qp*7(w_{ymOkCWLlzCK}dc_-nB&pe+azE9feY0z0SIkxk;BZh0V(pzG!fz(>m zo!|^@o&mn8_yls3%D{&wrdb=={BzXxuMDbrd1a8F5~-nnQh&2MT;gGHn9>CJ+z5>Q zzVcHPhq2PQ;34a3)9|PLcbNFutfZ$FUZUohIXVF+r>(;+Blb-qJUw1JpbnwD>CIqI z!*H6TY_Zk)+8REbhbn1wPb{H`zGh14#Rrdft^L$ZO8lwvMjCNiNwXhn&}Y@k99)j5 z-tloY<2{fU??2vMj$C^?n*|0P zF3C2W*GgBs_l-(=O8%r~gI5Q0coZ139m|UgquSk`4|EX(EFpMrQV*l}Vfes8I1+D6 za`t287J&!Fll;I#dV?h$k}Q}qk{s=9SLocQmPjqp8zLnE|Di#qHFJu9M#fxsROI!m zBJ~Y;MKNqSl3>tqP|GDZKP@u}%PHsSie}tb(e4?0D{|>W+R8rSXo$amb$h$+ABm3) zjkOMuJ(odk?@6xo|~RVKn9 z>B@M*{ojFzj)!woWgoiefMgZAuxAA=!EgtWT(=t3AaX8w{SG*F>zJ)L>Oa0H&p{yz z^3B5?>+1HJ-O5t7(J-o2@bC!0xiYUjKDDeDx%ppj&l|}(c3ud-ZALKef-~zEhTIIC z-+CM^H=s1^B1Y&oU-RCFKHmK(Pp6fRCXNNBWt2NwaY`1@;ShZ(4>1-WJrp&kgn?x9xpL#Q4$eilSCAd|_dE=i}TZ zmNz`IiIf*1t-Ym7I$cI71~S7_e-zpf*seCoIPIY~lhRlk<{4A&^V%>mX;h-Vr2FvY z#QB*}3!nd)Rd~ERNG>b4f>nYe%3j?Yh#>dh`QBY#nuo$q^0Pd1BpF z0nEvdlS8gtx#0&%5toxc3`MnEH_(Bg-P*bE8L%kqTM9c|3FY}}Yie^7}eKDyjY zvW4k)y#^iH$=rNMcBF#t*b*GwGS3Z-M_C^8H)e zyK6suy6#gtqV?nUxn4Tpu3&giyVLUtA$zGs98nOmj{(g%I7mJ_66RO!|$->oC-*+&L=hOqYN|f2t2+dgON%4(=kBeEy zwYsspn&&FhQe^VTf9AsP>tUhm;e5WsZz>76@`cD$ws_hGgd$l%*LyC|^@n_dhz4K> zy&e-YA==(xXLo2lnwA`P9s-6#q{9@JU}I|AZKuUTR3Z*}r=@JcW*PDupE84%oXYGn zKlucw?e_6~;*3Bd0(J!1-&qZx%$QSH^`T%$bjZc(rK@QhdwkzW1SIIg5*@rf^k`pj z4O;et25I5=RNu8I1(@W$ie@66svi!I^}vn@=jt_=ycZkM@%`G4&{&xk^CbC>@i zCeZ6a5@6<$TLy-9F~N3G~2Pb50NtZb;u+BwMtPNE-#Mj?06MkHNWEz|Q8-E76RMVB&F- z@`6j7!eoGNiqH4` zMEY7z)9BijI9FZ4MGng?2c00S;7aD}Jpw8Z((Es<8hB8y07F41?Gb}_4GXR&u!bpU z2Vb48N`$;3z1B0Gv@?XHiQ}9uGy+DizZ1X?*r}iz*E|+|+4m2qRn5U)^Jh$xHM(+WM3#N~pfV zk8oB9HS}Y|!q4r1YBid(&a63$DymQkFJ0EMRhok2tg~29)?x zD3FDGU#))NG#lZe7CvB%5ig}PB~?dJMO zdw8_o21aqi`7_|-;RUxnUvB5BcdJ6kXG++Vp%E;na<^XH)m zK6tY`m7NM<)GL7*MjrOTjO*JvxJAOz@WUB`@ki1q+h1xD%!0TK?fobW5)L$Op3rNN z?~99&sUzkY=2IQCk{=AX=G(XfW+%AYA}IB}OyI7iX0?Z9M%D`}N1ru|qLq5jiIB={ z7y#HKv(XvGg*tC~uni0cwW*_7If5#zCL2d{Rm9fwUjyUfFrhP9jOr9|rL5pEgF`~{ zI}*(bZnQec9|tkx)Z3hB?-~-KG@!&EGesz*)I#^?YskNJ!B%mJui#zSp7*wzr&)5DTUagApI zms`vu+vAz)A@azf#C2bp#E?N)N%Ii7Fwqd{l+*P^fOjc4CZ4KsP)4{mi;WxsTGc6end2NPxqV+Fg*!{{kPb=H|D=gge$O?93w1wOk&5_| zl$T$?B|!n+UBHcoFNIxfM|bielvN8QO8tP>Ff)Ak&e^iiB=M%Z+vPV5pg1_nKltVj z7u7V;Zjl3LrQ#O5*xhwB9afk54~e_X2|>KUzeJqnBf4}v9fAuc$02-jP)t!mh&QL- zcUt+Pa*t?7swrXbk@yC1ACl%LOIC942>)xk{QqzEFPVt;PZua44*%od=2)7nZ@~&$ z#RDFf+i*L*X=X!Ta^EyAz7 z4``%f5eX0fiY1mFLp?&^J%HVeCnJ(b$d<;|PS<3n6)B;CauH9bO>kjJ?mYBs8`%Kw zIHFFIRX)B2!^8OS702*h7ac~vf$EU2&2F$Zp9~Cbc@MixzxPc!_aTSpqc-CgT7I}_ z8q`$QoKzvCWYIQXS8{gMiHfuYSa~Fh;CaO{h&XuvJ}AJu1G`tFb@4e7$_$YLoe4ft zVVd4o{e2lOyCp@9fv?CMVQ}bEIROL8@|_Cdlo$HtdT-~ttI%skPJkg5}Z9v9BwPX?=x)(pERDeO<$+9 z!zL?G^w$77i@{NN@a?gn`(Pe4tnvDy2o{Bf*b8)CEaA&!{HEY|jxgfoE=!y~+NH1D zo%lKF;t~O?E`?{{&V=^2XTmWpW*OkqgMa0CxWf{}Y*cce!9>>m%bS+0#aNsIpG`Li zc#SqcKhn-0u5}3_pc484Cx2eBtHSL>8Y>eAoHDZkHZz(~7TfnwdQnXcd&))@991yticfQf zoi0eblexi4nKxT@4;Unv1asAz3a%D2_Y6s_nh3OO+qZv*(8Y1!R2evQBr6aG2|)u* z)OikdF;q5(kxyy)Y#FT|^y}q(C&V75h^OVhTtFAU~yge?ft_HGD@@aZLHvo*n<4r8&C#0wdwOO0 z@l@$J+FUeEi`Vm2!Jhso`DGs&yl0G3&ra{BZk9hcD8yIH&wOI4E33O&$~Lk$ds=Er z+j^@hrWg`+ND8BQ>t!`jS!I#MbV$eaMKzw@R5J~k;*Vn`??@)EXgfcD@4{8Zhl-T4 zno7BIBTR;GC?cg-HuJBDMerU_?;^LV2G?NAM+h%1)VaAL$N^mTM&78B)YS1Uo?Hkd zCO-FW+)mJ4y6YazqDn^Uier<0^t1H*(7O37(a`<#$x1#csLGB}0DFy` zaNpchL^F8HW3Pxe-@(7*z*kAc6P1}fh36V{rE|8YDNrgW4|%L!CFoX>ip0ZF)hHZP z+ImoisXtoxi3DsoGR45cV*%7QE-m@{9fsxs$HC8Vr?K5djH5#LHZF5|o`2oHFQr9a zJmc(fPuL{LkJ?y0tM8C?Yi$mB^i{oxQNr*H{JdyiN_x(W<$zFd3xhpB1D`oj2De>= zP#gE?7mcJ$LEoIMA-twm0CO8(rm*a-P5iJTXxi1aV4X%NB8+5YKs%_h_}gPJ-gB>% z88CcBY|aW+pRw`|WsUjX2FEc6Q@w*wj6$I_AtH%`W3E=CSw&tI$=oXHHWb^CisfAg z0Fh}OH>k(TldEYaMAW|Bok$gykslX2E$-LbF`EEpZi=ce8}BCz)1Vo@@|7zZbe<)A zjhFplgz1pq8y!>dr#DZDZC-?`;%iSY!L-aYHaFB;mkp@+QcYY<;0kOVc5-#X{iG30 zs^FN*Ar^r>ZhTHOtA%^bRv!&FnM)sqx`MjiprcE zqnSJOzSAV6)63wp2`Qho&a4o(1x&E*iRlQFl z5LxoWrG={Sonl5lIaz=OCR#i2lJo(us|?ZLtynvO@Ws*frQTOpTDO-# z&;@OmT(;Ay3nlpDxi#fp4D%N3kADUftfp)IAH#pPYH(-p*kwS`rC}OR=LTmtg6I!< zj@AO~{KoI^G>0!RH7d*0Ec396`U)P4w6BT8L|yhUVPLp|uS;In$XHf_J-U^V*=W+& zg(hcuQ=a~^Z&2|4bpXg!bD!pgL4M6uS%Xl4RFK9sLJZcfVmpejjr%}Eh7`1z?XdApT%+oO`e4>3iH0J0S6x15lZBZXRj0uM4=+9J>{XV~SEQs*dfktr#)GJ$ zS1PDZ4<3+w$IY8l*2ucCB-R>dgC{pYI5Xain5E5>s~4AN9G#O0>%xS}=>YT%RYWW1 zhoLa!&(_yOYf9l|lfEzt96RH*pWQIBj?RZ~Zknwe^ZdLXcW*1k9pH)p2}E;huB}~` zB`=2TAHCdiiam|D{t;fR|ITDTp*W3aLIpSA6$OAtHSlyg1{DgU*Iwka4SRO z>6@{Eh!_PHk@(u}T!ebf{a+&_N<se@+I*5UQ1h6c8YE# zuj6(&-EmgxX(Mgsnv!5-(IZ(Aa!sE>q3A9p^&APak5?+?d1lUJA zJtDxdiiKX2o_SAZIYojuJ4YSI?eEaXvdSy(UpI*9UD_VMYSnOre4q7wM80fc{)r_M zC+9`8VR3XfcPQjo;QoBA*pv?3sq$E;7N=LyHZ6?5J_gwOT$8TRzeiH0grZ5r4~%xI z_D-#~TK}OumjV}bMq0x4SWUVNzcIm0K6`~*SR{-C;1reZ>wBl z@I;jK6+TSgNagNyT^BMK_v>B*-ZG`F>bm+OI<_ zp4yp+J;5gWC^n%-O^p39GhZUH=t9E0-17WW2m0#(LVT>4*MjI8hK%MWlo0dR;aDJU z2({%I78P7oMxdX3;fmPpi^?9D$|-(us9Cf6aaiG>Cu;0%M-r47cJVa!qDJ*xySr@PYAL@V1h1SEXEhllWJ6~8aW0q-$a?HKhm_xt zVB~P&F$Z_wXxyr4x|obddeR+xrE-8LQ^-zt8L<1S463TBd-4zd967$fAK}Ak6OT$| zrg8|`^L*>4#6Jb*y&C+22TwGp^j+fn#^z=r&J7udX%S`)R$M_EgCDt2Se0J0=|qMr zALJw{%^76WOdfg#|JfIJ|G6|io^-XxDtnZ;2 zD%L9p5?G3E{LDBYd3p zKJZI=xFI)IntA=#%~5mn_}&kfl3JfI?3(9T>TWg8Q;CHBK$qETp4W%|s|LkZlEv7c zGyf+CVs=@-*!y+H02U-^%6ytgb{z$=*@*h>Q4>iQE{VPmkqLoypShqJnJrO4n#jSq zMgqW5V%hC%mPc@q(gZv?pS_;wR}j&qVTDa;@f$x*5Za~ zP1CKpFmfljIdZJ46G=XrT;u0|;?3?7R0<`b6Ki6&iu!h!fmE>)G!}y$&K_nP z6RI;TcThYRzDNDeA4%|1lo?B6Y$&H2y8d_UOP}SilP%wz3@NUEy-;kdG7Lm0*pU!@ z_j!r=kkRg!&)Q%P+pa2%dL#7P!8sciy%sEs%i%Kzt|n_%sr#jOUpjgGVUXFyI@sXGauALtkw-J2^^EFxzOKnjad=>v>he zaZMH{JD0|mSdssG!Q5`bo!^N{W-<#V;t#J5v^XuiEQec<#aPNbxEq>f-&m=&zKR(j z$K%F_X_xh@@MB1l*dbkRHXW!p{@P19!aP3(&=mzZS-J4_riTJ3bw2#-<5iX>a=T^s zICnYdB0^$cjj116vTENLJ43EXioKPd9Hsl}!H{j@z4E~`wrTx^CG*b)w~1Flo9R$@ zV5`$zLhqe|9)H-BV?<5vj9pD@upD$M@g}=z3oTDasmpG7$eUi|W zGC5H8-=W( zZha!4t8hfRGfY3?S8=qy!$*)(pZh$izu3r#L~$JXhM5Xfe@W~xr%PGq82f?rgrWN6 zisIVOVn$kxcI#?sFbpHh?VdQdlUaf47A~-1E1jRiBa;VEiQeNziaHVQ|0)giPPJ!R z7E^y^B8hSQJ~iYQLJ_;CYRei#6Jw1Hg_x*z>_yUNJdNK#JI88sD0&EN3?28T#Z7#F z@&t%W#}Ecj*Cqq%Mmga#b+S@G3c?{Soeevjy`~q$r!Fe#m)PB08G~+N%K>CC@jIssv|pmoMYXS1>*bvJ1O-jMeS^l1v*>C2L8XwS zu3fXvcE7qbDzDl4`{~zB#doa=c^GDUBm7Q9c&}Tf8_5%)wsRtp??A`@{rk6nS{h+% zn+*?8k7P~qMN!t?n#+c6SoHFJ*}4!FKqgr}h=?Y9Vcoz5elM0` z&|DTf+yjXr3!hs5ng<&12-hv=8K7#77kYcepO=T05j9GFr%@V*GDA+DR#aJN|C%Q#tlp7K5gf8b|7hM--F?YNuqs^qKyYURU}=Gr0(!Q@7yyBN(g02egXI@%o0 zD`V>6{AHG;&k&cjb_kvvn>kp~!Rjf&yu6!5ryjRdIVb7Ha9I($NHrvf0=xT{dE5iB z*vs=19OgSCRhE(b2H1ajFB?SAj34GcFlf|Ll(oMzj%YsbI{jJvwv4CIV(bI6E^b-O z{%QwTFh8?$o~T}vy?+EAm$fW2@<+<9zD~6sac|N=VM#w+kyK!ih!lwGyG|YEC%;9c zBbdq-u5soW66pm20JuNz1c%ZKk_sPaY5D|ZLPX(MbPAl&#oq&l<)C%j zz2Hle?%7o~Oo#F*${`xCf9SU{DJB4icRuh*fiMNebeu-P0eAcLZrHGx7;NKMu=`ct zIodoFHKI@VcouW_{rd~J)TBR$0V_Jc+9l~j2Dqvos4AqeN>obf@6c)SJc4wIffzl~TYHjkGNsRB6#psu8TbTV!v5nLyOrRWkAKUt3 zq^X@Vzg2ESWCOl+Ho+tGdj=a@sZq61&_ zyxnSNI{PDC|Ik}!`YzMm!t{x9<3KX=UMA)&L~!+CAoP7;9W_;*yiz37f?DN0`E`nMjH z`yWw_-D%E2Ceq4gectHlY^m_r3W?20;I&$5Y#SY~UfBk|c6QUUQ2E*`6)490wluZx zLI9GWf_eP-6;hbA^<_ckgi#ow72tF{O@0etd~!3=7SacPH=HSkjaFecGruPhDCIF&0Z`88qto!!%=%l_6EkURG6V{T9ETdgWxcyQ#*K`S%d z>>RD&Oy!6KX6lgx5N_ij`Ayg|ZfW;Nup&X$`4y2ordpFDO{u$ns}JG;#m}Sz5w0-X zo$wCkDgv>nL+Bq!2%WdOrk9%SqAv+pWyzB7m}8=0A8rmAa)1~ud)DuJy4*wVMk+`p zIT)38A_zOA(y#ENv6+KRrjN$=r7b})jT;hDj$BPLRJT}P+*H=UAZ?Kh(ijw=-v4() zDY>Z&`44e$Q{)%i*-1D0FkiDS1}rkTXvEyO7ZpWb-&=R}Up%$D1Ym%u*IT*xHhz=T zGsY>p5m}bwN^gvBtAI9gy00DnqUU|uG-A<8rz=VwvDuFb88*su4)fm?5_QhYJmYBk zS$l*`A2H*w8>tk6O=bSIkFc>e;g+^O-;8_D%Oxy_+J zJ1V?qL*%{@0>nKH$Vddxm6ZyuUi%4{!E=>WnHb9GaRoD;0B^wB#>D2XGtN2RWj3-@ zhAW^L`D6nEQM^kdCVYrtifX5BPFAoeP;(j09^_Ya+qC9Tw7KoW_@SYhMoKR--MS*` zc5Pn8nc8-hG(K!Rd*3QuieDeC)4`k;A%G>_6&kd?*<6j})`8~6O_}oQ7l-3zl>@D) zI|ZFUA{gNro9XGYe^*6*-)rU&^aG4j_bc8`^zha}Gqp3D=DbzhKZ^LafV z5&g?9!#XsJ=Xa+2yT2cWT`V6inwG0dcuK&EmeNy$t`}~jRZR$2RMdaEbeRAn`^k2Z z1k@bIbuwu}X;q=B{Zr_TtbuOKO<7KbMN*0;Yl3b)9+n>#v08-fTmMqo!p`H%XjbKv z%w#oN!m{%)HF%*J|7Wv^xvHij@u>4orU6kT08!C^oHmP(6~eaDerLx6CmXJh6W%8k zk>@0(gqA}202ERX0T(?94}5)Tslqv!H9Og8RpJR5flX%EAWdyxT^$S7flQ7sC5{F} z1xKdR)%XJd0Pg2ntB)rJszwKg~R_X$NC2)WEqPl%qf zy&{QZ=8T^f+pA~{GIVtc9e($zj}Jv-E#~NPH}toTtbyFyatcVtf-4+vs8nQXoPDiv zbg&J!c^0?ibTfL)YP=zG7^BHcP8StpFs_AUv+=n)BNYk1IpzV66^;587oGHEjsT0T zfm=2yoLGaSWMf&XYCt9`@*}SfUJMyO^MLP)Uo{Kq(&)E3PWa%knrq5e8m9 zWvF+VJfA--M~25p?f;~8(Vh|(LQu&6e7w{&yZK7sHz9*=Bg3QRq=q;NGXg#4zP3aF z!^@uD-+L?D^=<>?U&qISg<3T^FzQ5HR<#Ty=8sg=FgtADdILjUq1Z!m;7{{G`aj5o z3CZB*{yB`gwCwIA)?k^k_oE@SSEd!TF9ZcK6O1f?F+D*oyV4oV784zc>mh?G_88q_x=JhSOF!ysZD z<0R8bKBLc=?*Bf;@bRXAzW~VzN-mu(Q|62myMpPA@98ir#l<2-;=Tb)OA`fH0x|LM z&;&bT2nFq2+^of(X+iv< zb9k8h7Vse&An;SeSG2R;uEPOtx;@v(lto#946W4DYNBd2>+FhlJiycf*Oop|P zpYf)NytfW_OJU>G#b{Gma}j&BiFxfMy6)SdxUbLqJkeAs8Te$6>zz&p6n5V^N-Qt6 z9EK@p+s@W0NDJI&n~8D2s5jd$2Vv84ty6kuii(QO@Pq02m0v->&>~XP1XvwMAIuiB zB{OLzLDiqme5D`^GHdjxQ}6S-+359VjNA2gL@!{HZ?II_?pbbX5&u=9v|SIHtfdtd zE7^zRtJnnuq~VLKZr-pvP!`NpOU<-1%xWpGW~-Jc5}^_a^lv=9@k>HLd!46!Zkj-1 zM&99i90QDZ6-PeOh#QEH--_VUFL9+X1MZlS38d*+zP%bs@hM;xc?RJ~3sk>v)%1IO zNXY_2WwG^^hsi#DoR=eQF@Lwx;m+24x=?~s#0@8FA_&*1QLX_^EfWonV{#BV?7h_L zNd2Xw9SI6JoSZH`fCo-#@z@1`;DCh&2x5+~cLZyUvOu>gw$}ZTD;OmDZhsWU0Wa*#S1pVIh2+7N z^taRFORwFoU)Sbzb3pIz8HcKE(v@wX(2)$qk};yDKOxY5*!z7ok|yP6IX?PN^)2XR4eGz|t0977)&*^DY6S_Tykdx5FW^P2kvN9O&S{DJW^oz>ibbLlY z86ZV9!CmR)=4i=3@Zm;*>R9rr1Oq${@!l43pG!`;#;nK-K1l$HTOujoFY$4e~TB@nv6U?tF9yrwi135q3cy{#SCAU~-(b0P&L3(%J zo%MgO*Z(aYwaJVX10JC8^)gxPAb#@xE0RuAe_vLAe!&i&8Up!yU24_`&xu-!(L%^K z?=E-82LpvYCwEK|4Bjfe|qw(^U-k_eHi2;X? zgTp#m6cInR_?r*%E0TgYCbE=LP8@-u!-n!B1C4c`5b+cFU5+Sd5UyVHsB6lqCmiM* zU7xN}Z^Q+QQyv5Yl9MBez|?3Mj_h?ks>rXWqG>orMCd}i+!F&}oI+`Bs-Nz?$Bk!Z-s zpMiq3UXEOF8Vx$iS#hmSX(7t?I%?#5!E0Ux2EGsfU86%Blf~~uvyX`F^7LK|c_alG z0eUA5mg7%e76eiD7!p{Kjr0RLIy%PwoSZ~8V?mf zH+iqz)@ZI2N42h1t)a8n2$K9wE|ysl6~Bj~#5R6ri0n^UDHzf~ zJ%_HSg)n1GM+gS-K6Qe8Pxq6CUSrvuDe-tFFI&6IafEWVz!J0Ud6kL}lKSI8!#P_@ znEY!l+n`ZUG|@E%@X9wF5j1*>AiSS2n)oT^9_`?bjOL(RO#tr8@A-_eG4IZh`4`xfQUqg6?u)+1x4g7*TiVawG-W zu)*(iea<$zFSb~Ce0r#ghVOzox8LM_$o_KRK2>LAbOoWALbmDo5spKziA99ZViXQS z!X$!7D^l3rVim~-9bN8D7Pu_dgCeEK2z_Dq-=^kc=f4aY5tnFTI^VTTgJvo$N?$KM zSiZltGM%^Q)5Ur!{o%yK_84U44H!E;KQfHXA9B1A@(V^f@iOI9AYS*kSi~*-cMd*# zsT5M939?qM#9Z%^%V*hrCzzu&2}HlU@#3>T;-wVw5epeWYL?H*37@q?~gAe|`u zaEnhlp!=kr=NW{{@3m5H2f<~~7~b+Zk52s@A5dAB)Hg9TO{m3ilN%Z;NOFJ8>&5(I zejw-9L#z*70B&0k{&;rbj$hWLPRp0#fvfYX%#wJKaq?FgP>Mo}Ha{Rmq+_Y9{@zoD zW$R@eTpWWtq#dXqo%?+lu+;m}>y|$WmW*dr9I?zTnS^&Z>T!ujWCdbphAz-Dg;__4rj`0Z*O)97JZe!;f>hMEVKk&WPe%Z7nzv)@<%$TW&-l~MP(v7YlQINhYwh7iJGHO!;3&dn)bHOoHypd!_zep}lVP~Mkq%3? zxp~!P`83b1YCH|`KjR+@x_vN=*p|8;xZHK<+An9V(QK(+g5z^>5dFYxP+-WuO|i6v zw0Q^32n8EwVXl&Ry!JEc>*F@FH#i2eDoes2WMOR@nOB|M@y z@#fGiQ%U#J&9BQVc~dJwYve;(uvnEfiAQ4aIDzzYwKUNbjrq+rhQzWThEbTTTKMwM zu;CPY+qy8L78Kjo1-$NDGVBi1IcAm+d8hh2TAC;TX2ea*=)yBke`rV8~+B}#-M^$U|J(q793i|CKX(_5; z7=@gEoGLuRWTD&{i3CctD=65KKhr%-jH8gI7K~iz5eG6}9Y`cW(}XOu&P_)-?SwKJ zn+LB1q*1*^+taOQo4*pjo#;eka$IFt-mY1jZFJ_wWJs-wh)Ax|k{@G`oT=0asGcIt z$DW~q#=%O4qy2ST7@2nbb#jqOJzP+yP?))^D^DVW?)~v?&P88 zwedSvxm8{{__9t|#r!e3EIx%UZJ-|Tl;5-4eoUJ`EeHAzU3RP2k{Bgo($6vS(_LM} zGTtLpTQ;H9nvR+LRMLc^(RdVjMsCn>z}-lj7u?qN+F@%5?(FWjR!khD_xts+EZr&3 z!+rHX_t&9JYxRorhY7M2;%C_}&@bQ97KFVhoCb z;=>p0*NBI#EsDKts5@f0P#N5=qm+VSZjkHioxD(Hg*Oe95_3(qUGq@1nvLbaAc(2| z^mc}&&RJX_ZPb4-05W#X&ZLKVMY&scjV=wD^sg3iM%sfqJow5v3t}p#z&o~ zcH2W`vg_ZO9FW^yXiFA7a<0Ac0lX6*uz95_2q?bKH+uC+4Q7%hf8WdsVJeix4?g1W z^c2TGIhGH?4#lS={LNmjoj099Dw{-}reUd4(G5@|3iY$LgK1sQfHGr1MH)v=)f%xd z8t99GW0tj8GE>Cg?e+xXNCe+vdx8^Ut3^tF?zYhDnDkYbQiR5lj`4)PD0Z()Jf--K zs~jGayOC^~UoJ=yrm=uXfFf`6#8)lyyj-OYGkq+xzmh=qOOspZe6MDM7uRpXCDovC z#0pKlxn1WF0xCw_nX=EFFJIHxnj65xwMO2NS|^P46_bIjD1NS{Cs-j{UVnWsMcSPM zZRKizXL4f9KIU|tN)peOh505?=x%fyxm9}P~wY!bVNZ=zO^205HJmdaHTJY0^; zM^tjv7K>s;80@ycyUAY!lt)s)Uvec&TktAS`|2ps>Q1k}pVR%)WQ6l(b0h$@&+C0G zm)kk^XhxS_Go|&el9^gl)0omRkjX`QSdZhQlZTQqi3Mj7KcmG2%SOeS-i=Qh7eD^qeF=}au(Sv?&u89 z%bvAG?!+p$SpQ<(woPA^FQj7VTuP7Y-&wWA#3rEQ{S&%9!>+gPS(*2#PZ2pCwvmlZ zkxfZYsZ{o7cX=fcQ-7qeC=>idZxj3j1BH<7-7XV znjNL1@+!sQBic;NFQ^B)o#?!SEW`?6-5m}oe97OC##&o!yXt(SNI&=K51GWoU7MZ& z6iuzKW}XKF1tt&|VqRxH&lVJpAroic2>kwY#q&{2VrQv?4rFj&Zk;jOZ79ysnwsJ?}7kf}?xeTnTAYdA~hp zv-~AiKFc!IStO#z<#}0Ni#F(I?kE`c8?EGHLC-!Hs{+VRH25HU7Gl;2%x{5+=aLbi zG=ifD7IJj%JwmWqP%#-a0&R7>^#5Gj53NXoXl%UInGT=ZMazEgXG6S3dx-A6P!(Ow@6r9Lu(?AX);U$w} zTd)@g5Ob7Jx&~ZIhIdg1+cuElU}90UfCzjx{Egw{o_RJ)7Vlg7{kgTk^10d+JMWuQ ziqkDRqt#{cJGTFR_?S&*x1RTJIWwX23>8s{LZ0wMn&w~!wXVI1fReV$N89WE79kRk zO>D|y$_pbu#9Q)qs#@WtZ~}2nbSPRqA#W=kUz|uWoAD`n0|(>8Tmb3KR+Gvu|JFWy zG92TOyYa44iE=z4pTozcuV+9$)BlwZ;bznHlBerYF}2aDC!ORayyxXkSvtzaj()W3 z(Gsc5yi*7!!}}rS@{l3rvXV2n%~%rh)wca9srt8Ec1)6&nte1I2{?7Jw9XbpT@wz? z3h9c4(#eFJo;nw5$jxVPtcW~ZaX zujiYr-gyTnKzf2?Qq|D&%`Bg-u?7Fi>e3^D$76$TvRQf;8bdsm*2s`r!Y;uVx*XFb zAjo-+mwo9^A!!u)%X~7sYYmxbkO5XvHj5`G-JDUgLuDh``N#gwM`fb6%k7*?^T<~; z8+6KVIWgWYbxqMuLeZT1nj21AagCQNOUD;eX%Nh_p6TGY(KHl-ghFCLR)|o8{BX)-^tsioV8INvOgT1#-n^7gGYsukG)X5 z(KZK%NvhZ@L22lq2jSaz=6rgdvU~dZY*WamOLS1L!Uu&Y1x|7OPdI)dhDqF8(~&|b zV$_m;TqeljOH29!t25SjoA;O`vNfpuW1Q(+&TqUuuX_Cqsea{b1a&<|#T5({o9)~a zc$5ulqEd7Su0a?oqjfvH%)kBcGO!RTOR`?bk!ic!wM;3?Ae&M&*vJc@>;uA}i>Sht8e@8ADfWz?lx#H0rX*HVW;6Sv_&|JCg z7}na!v9(qC27iT+I(o@EkG|prO(Wtz;cYqnxTT%a@~EQ6=;H8 zvaY%8fKuAEm3|}%;t<$tQ*Uw?qatnYsksa%^GP!MT#;S+t&Tg_sk(BF#L}QT&gs+x zUBNJyXiZPdFZ^=7g^NW+9r_t$?6ab0o28J4cjl7@0Hknydj5{5&D#?il|8if-?ad` zZ4R%r-`Dq)-@wJNs@lXeerJ^sDHs591AB!&FJIqW-`6=K82vW6@y=j(f6-_?m%AHp zW_@all0V4R1#8$o*7W_zt&0DFIdt75k}J!z5h9YbPdz_1AeYfUfmU>~Gii!Wr-+O( z><(8)PjSZU2Dw~}tZFhLVjitC81cB!fwb4So~tuVM6KR;E*~CNTFF*69g(QViI^!> zA)-=Anc1h)&ov}fYDEGd0M2PLtq#2Co78!s^$z2*NgLy{Fgz;uR5qJW8cgFfP%$ zd2@X-#?OZsp-J~q2fybtQW4@3v~yfvzc>?9@AcIy?XsioSYfrBEk!h2-O~*EBp_>A zMA|i*YLo{VWeh?}thGWNGAR?8f+)Si2d473J*rYdp2(&%qZEy%fAzaxDs|Wi4`Ih-Os&eLpN*@RakF02 zZ4+y^SRcK2oHz!@mJ;DyvweuKKxA16J2Zlel760eB<|MXuyMv2ea+%a$#~C%mqU^iIXS#9tmxuFxgbS{J3L?1U zdSepa8o%jTaYUg^fit47N!SzpLl*0}4mN&wQ?I*A8CXStYm4Hv_ZH(o%^S@cPP#$P zHv^)mcMtc_wDzCKxw0WOhT=+#C6NvpZ1F>1(i@ z`2b{X<)sf5SjMdvJGG~nCRB{ldtux*PL(4FSrtVWpM()lOA9HUl2wJEmO!JOqS1OG zX!a3n1skrH{LRO*X>0igDU9&gk5(A@zq@>qfEZQ(yt8HEiDDck%i3XwCS~vuSi9k{ z=zAAEuRhGDu?Ry`SRmVvmBdrYK+%vol;~DHA4+Bl2S|l)i}wgRK-!z53PNpb1e6KB zUF=oPc8HTori59(cis=o;JzxZ!Fm}Ka=AVSShuCfW#h0>Q_OoqCa~Z3qEu)!DP2Wg z{_sBT9_bCwWEjK$ZYUWO$1O)lbk$_PchBm@64t zN|xD4{=Hqd_FC>j6CHn#!P0Oq%eg#Z<>DmowD|f@pQD?*JE?wduS7B>!q0+>8!y(X zkL`+~dKwV~wOo|_yeO=ARPNK#2?z{AVdZy}(L{N@y{Ml>6oFihe2o;FNGSfRS{?L> z5NviTxwI0VG0C6b?!r(6poU;kDT3URCBHD|oW7xvY_Bp~+U~szPX##d5=cT_k(}Yg zA1)PJ*nu1}Vg=3K9)n6A_ZW6-kM#HUAKW4F!p^k{B@`oPQxWcPpL`#_7GCTf4?GjU zxR_>0lW*{l>8Ud+UVFAtB6ql9UbjgqI+QS!mh9UiIp?4!fk+o>PbFUYdoY8lYGph= z;?AF|uEuA?!nxaGefDHXV0HEp38P@3#|!#w4y#^@Q9g_XM`c<@*vwPVGF@#{RC}x34I1E1oJtx#HlYrkE6Z-wR!2WE_FP(U7XiC|vipw^Qcjh72 zC#x&HJFF5Zq_5uQpXp%j(2VG|;seel1;Ym8JK6jXvG5hC>|ceO#D{kL$mhDWS`8wH zJ{B6;$8QdE=1Zl#NO_w-ka-_`yno}!`LN>6{4ow&QB3CC<(%34oLM9aFve$7pp@>< zJ3d3$^AL|qOd!)#QGQ%kKN~MpNAtS5ePzjRB{;y&5JM4P!ivC>PcEGbuVNd9^|3TO!b3t%_fedNGUc1G zH;RFi7impS3}Ue-dBlC|?6(Dv|D1#ls15L9u6U$(hLf3gKc#Y#Gs~W~{GlB5vEG4% zQG;9pMI(jx%^!6Fy$H<3cT&|1Gter8n)^aO`MFfHxnL%DF##1<3xj8w-;@rG_|cL7 zG!%_te-yxJFIm2vv#oDBGC}Rrx{UE~IttALnLeJ{WNw$=Y7JQAE{Q^~!dI7b?gwK? zI&PO#!0u#SrZO`1P?PU*VPW|D+Mc$xy`Yxj+h;GT*ml>W`A7gQ>^Yc_n<(Qv`FTqQ zkxS>q`5sRND*VKiZvbFH6l zr`Ks;-8+gY7$#DwOZHm%p#l(r%mqmtuJXu`vP##xN}B)7|Mus`F_BpyUEsT59k}ep zE3DqM8gP?Ea@x0@&AS8%lNmt6gJ=ytvk&c0*KBU<&;%l*O?8j{+6gcf$s;b3hX#<=h(9zq*D2q{*%Q4u zwFUPp78^if`VEJcZ85cA-1@TdH2qx6_>a&$-GkU3SyW>ZhXm@Na)%fNL~)Hff<~3X zKZs?JpJq$4^pWwGc-AE!xB?lEJV@#5lGfn^-xm`?bxrOfdo|ms3@6>MyVsc*{16FM zynK1I)G5q#$GE+792`bV=8d`af;5O)>zt!2M)UsR%=Cr<$ricgizzy^Lax|JV!UqR zI8>nDK25v(y@n{-gvc+S3l8E7 zvzftGt?8M~V9gC5JKr_G=9BiVko;_mVBalB)%nbP11WTv4OY)Od@RElljcJ1m2*SI zy&fMb4E>7-ZKChCKc*~IPu6$PFuqHSMo>tn!gJMb9kaca(yQml9(!SacIQgC>u$rK z?g?E6Nga$Wuf$vD_{}KxK{rG3wgI~K7iEbm)LPOdp~!abZv9C)1&E7B_$*x#pib6k zOl3d{La@vv@^Nvv(_kt#u7KCg^6qexq0WS8{4~SfrN8t-Glo;&E8g4pCetN>(!%?l z$xo+z$&44qQs@I0X_XSm>yTIkp!D&YCSi`!8rtdjh;WJwQ~BRgapGX$Se#yv22$>UY0wdA~UYV zLs!na?%~Cyio1*&r!6A>!*&(o^5#P*PWe(kTt`*$$s?E=i7fJZ@eN3meM*q$tYbBM&|#0-N;7N1-qM&6x8 zD)#NGI4bGFhYV_aQfK0PgU_@9uc|phsDbEP@GCe>{khWuXr^1m z6l@MqitPtT%W#A$(pcjo_e9~6i5(Ionq4kR!;V+$C%^X&cVb&_j%w>Qza#cXNAdqv zrK($#pwwVNp;W2`3$iZn+~VV8HZS%#iY1sx(HGimqdm;G*N$ILS6y9_llNCoTWgT1 zGTI`s8GPFPT|$>D7U>TVp4kFlh4^xhp6)e1wqa|R7qDAv&{ip)3eA?Mlq~l(dCJVw zkZksSR0dn&%J_hw=roF8*bj5_EO*qG=`~*kNc(@JaU+dobuq)l<#z$q^^b(-#yYmY zt5E=xyJ}D~g)|l(JfDWPV(<@j9C4Hl5W|U#(4eIBh7!DH(5Poep&3c#f&&}~ss^|$ zdZAy3JJXtSdNk&N7C{sdKVp-3bb=~3iu3oNj^6`7l%WBeB2OmGh1NgJt>~`83^t%f z3SMbgrCcECLyEW3)%Bx-0FXq~2MHl~1_SiF3N;pVMlEb0P|OU|xz5F^|3~CUT9bUD z=|efPU>NrA`a!16#HG%Iu-1!RoItA7!4jW4SM?T)Z$K50 z3bYVQ@6ef5cehW_Hj9R5#4DPlenG?&Car3Tkyj|Y7cSTCb{0Uk7Ms_iy!AtbJ579% z2+&kY#L`Atl^{nu$#&h}w%=cDT3FZ7ZE#2oYjqmE;lT&jtL-PDE7F_wN$)09U@H8~JEMDxaQH2sA{|R&Sw|iXe{p4RGAxhXtVnsJ0^qX=Lnpi zBntl5QZc6&d#dG-b_|T6B(dB;SZ2p1q4gh`7zNT_4)tX+Szgc88VMzaEd{UO2S*Dw z&|(~G=J*HE-oMQcQFWGFCGfm%{*KL6Ol0urS$$i$$M8eF9o{eqQHd0r7aVx`g(C>= zJ)J+ISiD0S{Ke8E(=PzUMkSXennk$yYhE^YCd6JOkgQ)4iVvi;`x01srUYr#9p%2T zqoJyAT<b+ z_Fn&ZB<5$c4}oy3v`V?k>*|P(=E#(H2tWiB`L?+fVo;m& z(6o-S{H8428?RMkP}Q6trMPlN7}0T;UV#kVA679^MC2L+c}@zH0ou5AZC>iQ{i?o@ zowH|gZtRKP0nPTlhe(5t+I&ro(Rj1?MlzJSuMPb^v%Iu7qqKhO%43o)j<5Hfuw_3> zyeYhL+Wqe8AUJOgxmk;|C=dn|a@3zHJ$?(m(w{+*RjkDSc43Rko#rOcuz4(lm_OK= z*KlM^^wA1l!wK2)Vpykub65(Qzq88y-XdD1llEweZiD$d&zwe3L*wm~X^ZS-?uL9M zXGol@ABXKycAK{=2!ZpzNC}n)!%@Z(PPo);)4wga%LNdgc9<9 zHX}|V$m_Pd?l|T$+Bv5X6oDH}n>dtXCO8Qby6J*$>3KX2(p3l4H3og>Q+&jTW%&f3 z;nu+^=<1$9;)ZEffl;^3FVfd~AVl!~!)U~Jdgi7)wOUKb&O>hkmh5ESI7+t2d2=gq z9A5i3K6F|VT=4N%SA0=D2_H+&%_lV)da%bt<`t~En5@6!XzWwBqUCF~`^dRNQ-7h$ zlL=0wM+m}ieeZhHc=|1dDh;BOYK$zu}9d>yCd#tfmv!b1JSEAG;g zq&S0L%|gHF?JQT>IxY{ckWuTjH-Cq2!N%!zY^$eHuU!usF6eOh0+7V?Luth)B+e{x z?VeYJp^peGl!W!U;!SYXRGeI98D!#!BH^0{uyTQ~H~T49R(CdxCs<>!8NFC#y#NP4 zht2QqqUbDSIv0AQ(e%0e3WsjMs9Rv6pIrcG|8RK%Z?-xe>{~v$*{>D9EHQXjmy|zZ zgR}_mPa0ZH5>aP7Y%ziDviU=O@T+R5P#l{jW`Mjnoo>H0{EO+$NZ;FKRUMWWUbou? z?VE6IY-KaK;PwI&ArMq93f4e;Sg{q?3FjI-n@(Gq2-idevPErJDphYu9XmuqQ7K1a zYtU^=HiNSxSid{tyfv!cP3*3ExVh{QAw&&Gr|22V6ZfUFRSZR?@W&q?d$1*cnSyq@ zs%LK1`-#d>wPtm!N7uj(jVxAIr&`2_(tyJq6PpSpK9O4e=lZ9vlPd?N!JI9x8{da% z$#;mBtL!Z*xtImg$4{rL8$-$~oP!gaW*_G3KJcX8Q1ykNX!E|zzyBt`8BcD0baTeYx0@{Ei~=!RqKMp! zliy)v+?o<+G3ZtDW??_QDbn`YNc3Dt%~9!>Cf!gfS7VVtM7^GB?0(Rx+MDe@q#B;& z_p7dUndUccjCtA%z7ak@DNUreC;e5dq3&!mIZfd9xY7~Uo>L$!9=-B|3+vo0R*wL9F3Wc?+#WSPk_GC?4{>BnmwH z9L^WP>VdyuI;N}lV}0ifyG_1E58MJ@K#<|}C%&M7^4j1D+d+wX%ei0386pt`K(JnD z&tz#8nMsa`$Ih`QsLO@expY0qp3h?y9g&bL%7$RUp!fPav|w0>u+36y04!OsUK+T% z)oqSIr->8f=}M$kQ4&q$x_jg;)AmF%*#5*f%jZKB>?n*5I|KiReB@*}Qrnl|;jb~sSMC3p`# zL?fH>vp}KLX}eMT##iO@A|22_i*B@@@45Md(_l;ElGft51-LC=aeA#IoBa6ld2hys zSofhFGvobd?YB8?rl{7%9v7wCQ*Ft+gOh;pw?xqx9-9+cCiNZSV#ZnC#qYhTt7ED4 zV^HF=a#LqIm`(w=`^z@uLkg?mT%0JX79N}BjPhvM7a^?YTXm*2rcG!zi%z2RPCE*P zT3iXVAKB%(QIf!Ej20WyM2PrZc^Q`xIWj6#Gv6E7-LD_1z!Au?(L~&QB0qM%?Qo)n zfRNuk2qf)E3~!xwf5){D^vx5tH+Z`ma!buCm3TEEN!%ICi;CYmnJ2QcoOQU*E8H&s zQa9ysf54{*!&H#11D9~tc1k8z;x#5SsCUv;&xK>SgRfF*K^aN5#MeK&kbW0*nljIKytg}^sm{{8Lq$_y@6Fh9WSg_M8@VN0#4@Xgz$*TNZ>`#l}6 zk@O)o895T69*V0?xz`odu12UQ>lgit+My`*k5}6q68CLpIe*NQni^4M$|1GNq90>x zlPYv9k@F?^SPFZ?@lQik(p+AXwjF2#1NBx;^?9;cuewzZiN;UDf9L_`GmLI|K(!46hW$R?FMd zMKsK4X=TNBv860`B7%rzmiU+N-63zTXrzJNI58=HQOE0qEBh99^Eh(5E4OfzHOd^* znWzv9GU%YF3^U~X!M3phxhxcJl@ICfw<5~GcytUp=k&Ry=UM9Pu^Z@oOEPY|O>H!m zieqm$popSkFh8e%EVH1|0C#!nfk zyQpkzqLqTlX)6o1i+!$=xXvX6@UPDII0Qr+fU4kYfGm6ydd};9YGm{sKrxAU8Zx65H3k#J6Jn!^k$w5dE6||2fSC7F6g18{0`rg8i+C(tu21rbyPegg`9&y2f19X zIA{xZG#QCF3{cIn4)NT}B0k{9;JerIS(04qNbgL~-k{xy)AqC=$&i8h(d#;8*2k&b{&suqLMd>Si)5nACd$PvuMUJ+>`5H9x!{7x?FOoJG;?yzlF>E!@7Q#T|T& zT>bp%C&;C+KQvFN6v<_Rc9m&MeXN!ap+Z|t@fGqOk0-EyH({YtO6WCI8ECm*?sIK2 z>I4bhoRP{M;(uYbW(Op=`GIsrW0}GUg9`F3Lh9>-NmCYFSXEkmaTu1&=D*}Aa_#Q! zY}4&KKPl0~t$f>{qb+y;?AynxI2fK>#cZ*v6oK=8e0fAlggK8&hBbtiJZn?NYCYR0 zgn%xo)EAON#_4{WPEs43`C4%{D&=jDcp&;3HJbso`_%*Qe1qAhr7EBAgMZI}T(|j{ zPoMirZKB)le#;vYCKLiBLf$Bg#GyQpmJG2mb@x3CD58Q!Bnn`()+CkQ{4n&)@$?)= zBn)32XI{&8QS54z;KO{)@fe0hMC!X@%WJQ%S#$}{i)AlLgT{K()WE&bM0-usvBc0G zuO7_&J6r$sM=`>wGqoD)!hfy!pIP70qb#@Sso{={L$G9=$PLI)2v|NNyg*I72fCaR zu{?BOZU-WW1hjPQFc4CnL@+PihbH6Tj2a0q~&#Z^0*Y>;R z4O{&%7zKmAkf?mvwV*H9qG{MlQ$e3K$(OyeUvMn%yHPwn;L}TB5Ow)IyV1=fmgUy` zO&90xKI_x_P>g;EzSaT31Df@=Q(74GL9q$n<8nApFb@@(O6_oMxoLhj!F3^J%hXoNMe$v zdJeWGlI{+j(U(tq6wDn|b0y-P;SWM+#^;sMFOp3q68g7v=EbKJ|6L2vU94G`_Y}Py z)VW$ia8p=KKJBMn;W9%ZF1{ymE=>p;YTTbSpZsT=w!HLH2)HvmYa|Hr=vAMo+hS5C zzYB7<#N#U>FvgC;=MO!@V#?92It&|*()P5!dhkBq{yEXT^HrE5?Lfm55noY3Q4E1l z?`=s?bVi^+ONj|)l7haSU)Tmsxu-G>w7K8cL4XmSWj?eDsL?x3$+ zb&k(((UV&HI!@d9tWsbKTEEi%#5e6xkz z5|S(mkOgz49QhJ?1o6#Qo)ingVj_&f=YAgDbTnSPBxe|@18sL2!3DUTU_ohP0Jv4^ z2Bmbfu2!aII*&PdP9*_PxAh~L>wmzC_4OyN2Dj^pziICMHCWNFnZ(Vq8gC`>k57^0$^pGDF`aVcmSwOhjcZ_ZXP z7d^i;=)vOebCWp_p;K;){3eGq*i2)$)Ef7hZ=I<%x#QvAor|oBz#_PVJVoVVbLfq< zYPL_sF0~Rd5l~+Wz_6Uo(=OYTK<3ZX2?{x=77&Q`PpEz;@AU{TooBA8d(CKuN3}@` z2CZK=X*XoPoAkTGQ`97&3&!pAj9WEZPB=KP=UBGaPoK72S*~rS5s2m%g+%7a)KNA& zUA$MZosIaO7hF=jno2<7KjE&n#(Qn6+o`eW+7wQ>s3#t~ec?0rIzQN8Y|eKZ2LEyU zAg|}qnLBKAUAkAeM3Hg_L`Kr_)UW+ zTfL5qpcHdtI=ul8zt7jAG2LU37&cZid4mT-JH+>Y;YIb@BN}I6x zxSdDUt#hS~P^#pzs-609+r93^yova2w7^iw>m}%ywEjI1R`4wgNT5RZ^vj5WL_#dZ zM@o9#I@!;$$>@`#V8Yi6{>+!OTlr}W-hB@7{Ue_RbhuxXD1HgUUr%j1TGF52f8};? zSUDt-$b-}BVigW9HgQw4VHJA~zrYyQukY-H_6@79jNS+D=Bcq5QnN(1d=Wyb+nhVY z`tsJ2kk9)eVtXQ&WQ92vQxYvWWNZQ4-xS&in$_Dt*BX0*P6rXf=?ZhllE+8D#!EBtcN%1 z@~uSHT5dzwSVuPz5r_@JDe^;F+p{s9cBQ+`5!|VdvUw2))cu#JYrJmu^~Tna#n~uQ zl>Yl#B#G#;_icKRoF0I=s?U4&ba%6Pz@6w#>KwMdJzYbPD-sGn67}=+s-F^VV7BsN z`~c-at6@|xSSp_O)%zyv0{migmjwHs*DIg^b= zq`0M)AzdC!vHs{C(Z~zp|Bmwh73=-?uX<>H(OG;XTFrJLxD;VBH+_Ssi;S%#RUza) zUUxR9DYmadk$Xo+M`JeH9Hh=BMCeI%r6kTkfQ`aEEr$}?;7}m5LMB$-g4Dku@e4Eb z*x)y1ngEnzq3^@ZYg?8~T9S&uuNpKbKkp_EkVHW!%4_l>hl_ApG+;ib6r$ zmK0AT=0Cm0`N40V^NU%L{Cmp(Ppt~TpkxzM1a{YH{HON*`Lso}Y+}(X;a=#!8;bs9 zXc*7l-wow{GL%oqis-L~hCCVCJ6>n-S3@(N4BdL!yBYgGJ@voe55#{mG>X@f@;|y0 zJpMSxlcBtPRs?@F6b2O-3bj&a@mE8&pA4Pp=>f$3e`z(4{K?QbzP-O2%KBs|&wDGp zzcd*m5b|WG$Vr{UUkxRAGISuIr||EF(mxrR#BcdeocNy_9%p(ol$+fO=dXssfRCpL zeEn%E{%?NTPI~r=rj-DfJ>vf{Z~u>(Oq>r3KyW|Fx^Mr(O#jzkoP%W>y(0>K;a~gY ze_z)AukVppp}=H5A<=vJe|*;eZv_EAb$V(v0}(#$?~R^5HG0FM2lv-T&m}>l-cfLx ze{D4T)=zr^|XRv|De)KzWWvRAHp7=rxdJX?| z>i@so^xyxRE%zcKCU?wUzwED1=Opk6MbU{F#_Gl24Ee+eIyZM%UqA1!jh+htm+?lt zSorTo{Xf6Y7JqV?z0&NzlXL&`8mx^B<_lI&x7dH3JpbomyBz}t?0bB4_Rzl#SOFq1 z3?>FRt1&){kxwLFW&+zXq6?qz^ksZJu13mZK;9cb9@l54|H2W|BGgrU~W!C&nQw^jV&cph7$+Msw5s>YySWvy`5W`eLe_UfRV+ynkS_0m%Eh)=T4kyA zp~PW};7*_WFaVqRb}#`M%;G0{gGp}|H*=7aX7G5hz>z?$fN%b@@B$+$;tudpC^T4L zfC&B}dFaipf*!&H1sE#6p)CCWbN_!@g1K%OkmU~J6N_*`@3MY-i%rw`?F(@7*LOsn zAj2~jt$Vz4hV_Kkf^koGWY7>V3o2?*Q$8hQV}`-7Mo z){X!#!RgV{*m3a>1kdsE%hMe25ASZQSQxL+MEYebj|JeweW7bbfM~)aU{G(WR2eW? zBhNS31`x=~QY+_@Q_7}3b9HqEKnfgEe`>{i=0;mc5FnK?+$hDMlmWt&ykYk$@Pvd% z_DdV|sFWYfYAlnPbj2<#8pewiUh;Tt2e}^cRO_!n17!Qh4ba)o#iDV;gAn$50L+4i zm$#8wLah{4f`8 z#`qsW$pw-Y&=@ivPV9^8^EH@1rzzHKiW>4g{LS^NY(XA24U}{bOjj&;6I=}?(yrY) zt2!TKv{i=SbJgbPJSJffSGQ9SK1E;aA%@!x zk3`it1T?H^alEFpQ4xDu z3iMOEQ&>$=Kt=$Frm9|?Me})2K}g@^|F&xMRCCbgNM}$(zw7~(duSi6P z(AAo3cvIh*my1BnyNX88fOw+(WxT|Yid-rIhD0bqDji!s}4PvDRd(%i=t*bj{wc z;oH}y`901!mcJ z?C{8uNt-U+rjjEh1JxQTHGtI=iE(SJ=W9+?DDeg$$bMjyt}?vRwZ(cxBgp;o`T?ij zE1=G)bL|zC_4GgSXCvCOZN)+Pm-wd%BlPllWt(shbxouPRrf{glKA$_{J>Veu}^*8 zcoZpXfJ=g|XXmlS9+VS}1aLKLW~b9Y8?ZP!)V)4lL8cRPBA3C&n#dJBnQ8FL zxarsuZ+Gw|n(eD?mlq)x{QV`w9E$ZBd*LfZD4aP-6d)!TtJdb3_$|YaQ|+ zd9lkbP%wl6a4{pP?Bc-jUiA?Eja`x|t|QD5&0P5$|80{a0-Q}yB4f7HjzP%N9)7&i zllE@TEn)*M6n8RT^5YW z-$z7JkqAB3LNqGbY{@kfz^lUWKFoKxwnfndp8bUf`qN#fRnJ)13xQ8ZZqGmUOaC*! zLSXEwI6}H>)t)xD@#mnIoI!{!R7~D|p-_z9_>3)eOcGKv5rvv)-!j}_Y5K|M_n)nvcZ0 z)oJ@+d?DXG^?Lp11|03_V4Lfae5a7;pNXPqRH+1Nop~^_Z_co&)v}opiMT#F?ffip zP_5AV4781xt15hRRL68AzA%#*^o6}jhQm_m1RQE58n5iv`Y$kITZlz(liw@9k09cQ zu57Yd0Vv^O^*YL-1e%K6u)sp2(KfBQH`_lOSa+w&%3AI3Z=IDYl@L@bbwohXEP^&G zk>QO{ZW+B!JvOkaHzYO>8Km>e{1Ybf#Cm$xD#Eh!3Y2Ij4W>#r+-}cl!0PzPWW;x1 zG@~t+)fDkpx%x{0JvhOrpb#9ob>4faq+*8K^C+cx@l?gJ(e?IB$d&&l3afP>x&j=m zVep`uXYknjV>|wd?jc}>9JvvE@jwP9)}!0!&%eE7H3&uL6@%T^6U10>h zYN((W%H(l>aib{>bR${aFsFKmpB5e$7Z(^T#`Lb#Gr(dJ2uHLOTqNU*kvsY0tqw?h zv72lAL%|}mStw;Ra_+NB_X|CI@pNiv7yzQrqJc0d_q<)!43H+TpNAm&AQpmJ;O&7H z>v*8)>FIfCzuJ2;M$tNaN0+|Ag-K!{vUnkRgz(d6(&~Qkn#peSy~eR*2X z19eUC)4`#BONaN-sT!$tvwD{p_%W!b8A zJqJAh-GDGnzD3bktLre#=l+&h`_}0Tzb)Teqrni#c&b&fs0O)!MIIY)L%sb2(TX|U z9I;>}Wor@7<5?b$gCuI1uqQCPx_H#(D3N#=98md%0CdwXj)T=u1_r3LO?(9I=dt z69%}pSSdgJ7*Ola1;T~1t=4d$p@4_`*Vs@rOgin|XIoA=+Ny%IUn(T2d;+8E`UI^!X(MZ!F2_W^ z$4>a40Y(8Y*T_80*17h%=DD%!(_)SB{O}^Ebj85%DLJy73`bxLj}8$)%(+ zt(KNx0_eQ&FA;qCJ<+tLYBIsHEgI*xt0!b8fHa`f~FW{TLQKZ3qmMSkBeQ5(+vg~$YzDg(Yj>3LXD#6APL4!(L!D@W?BNNsFX+; z`uF3-gzq1ZH}+J|k04{>4;#ZtYo{A@yVx>@q$)K`;y^IvdJh-dWGX9^N>KBEGXVLB`=AE)WID&A z$)f1v^Yd?es#SL2B%xZV)t549%3^hmj83mMEHa-J^p=_}c z+-8@9_Zm&+d5BS=+v`BpzF4isUy>UrDeS*R~!G z_c+Ue!uhGPndSZc^24L4GF6h+jEt;wW5TNg?(Q+jbAGrtx$vtUx6ypQKwZp57gv>G zfA3diWZpm&Zm*mJCyP6{GWl8Hh}`hjEgWIgc^|m-1n?N}b5oD0w_z`x$sE$PFm?Id zgxNy6O1k)cAE2%{s!nb%@Bn-WS2XM)XrIebgTZyIGGo`>0Fp_CV$S&-Dobg>x~mnrwNGn-<9U)lI)AXGNTVugha zI>5!1d@Sm}yE>}b7Zm(oya3*5Xdv7Q1z0}4yC?!q*XcWNZr_LYZ4(Frz(V!^7fsT| z4G@z0<@skwnQpw(TO44NhKOBaU2{B~@m34>*y=6j#5#JUEv8y2ECAfmtPJekfj`YB zO_Ww)5AMwlf4g%!pDKNVybf@Zr$@I5Z89p;E@Q`Kw+exzJyce9f{=Q{y)7uHETQV7Xl3H!nwZnA$r&j|My=dXgFNZubu1h)m3*sQ`1w=etAN zV%;6q2+_uh#x@i3Oa^ffFzjN>=;B^LyhLLGLpdzi9CbLjX$ey*Va;zC>J&!lQ4;hG|+zjNYFwo|uS&J_d=tBcwJwZtMs~mv-rf5hbea3cx8;kUPMl3^9=%d z;n_wHBqGtbCmq3c5)+%P8c>~!cBqC>{r0KX4ek!tPk7bx<(gJGV3CTW)}_z5KW8Xt zB{msB76*_lQx9Y{xz3$Ig1~d!I)L_QzAzh)PtF@elxdSG2imQ>N z*7J|Zr-0Fr3{Y{bML_8Kbb$klK_AX$Do@)x&>H|X``1M4zZp!{+t!d;9)j6kP*-}c znl`CC_t*7Ssb=Hf!KR@YA}kcLPjmuo(>cUGB0gtm;E}7SN5Johz1i+ETsBW-V0!GO zzoEI-Y5ASU@g#DWEZFcQc2~W{tm|&Tg26n*jK}4PpV=rIh+6romZuZ|cJ1J5?Wy)$ z=gS;IC2&%SxPC@JC+L~oAFi?caHl|=>qs05LjyiuV_~2$9w7F9E0oQ^Tm?Lrz}HkZ z{a5K9ltP(oR2Z~$?<$kERtF?R!i^Ak95#s2hZNz*AULf4qH!$b?^V}v>;sn8z^@zt z`J03uug(>Xsb?m%JM)rwJXxLbqTrx2s;Cp3RRiQ`9{mo}XB&DALpKzy8huc!wT@ne zsw0kHh>QTN2167Ut9K%e4KVJ~m_3i4anLDrxZ0I_a@ubB1JkblWcs2vYho*tuA}Gz zfWL@tvD+6yyJWXm5F~itYIEWRpqzf1PG^7b!Z98(b#SO|DJx*+pRP6mT>x?BN@JAj z9$5N}&zRMs@wsEUrGFa(Z99u46eyY>Y7G#KI?jqY?R<{Pxszlke!sP#H*vgNLjaOLN>Edt(m+iGCknE;+oA7FW~;;P#i)Et>zWJjkqI?fX(aW~ z0(~~r>cj$jLvL=OUZ-;cwRZiK7k}1%lfGkrxA{?}+ZqnM2J)1Tqs?Y^j;~*<{{WCN z{vr9)P_*F~qnlWgzuLDK?e;;3EZbfCOu(+B<#c>BnK6<|0^Y&z9r%Xl5-=j4y-dLC z_;Wh@3258qN$0TL4G@hZ4N`3R^YdUd18OiFLs=1M>TU_uEAEOS<&JRl%I)F2@gNi?u-^^hh!gd zfRPr!fcHJuDkz-G`GA>HHp4GaOo+9TWV`!I@J(&<*5e-Y?*%~4?CVk%CzroscuFLn z9pf5m0?#i?4Tsv7TVG2*8hCxY>WV>ss)G^(z$2$9d$4^dECY};)HlIgk ze|(D>9&Tz2kd$hzpS>xnzRQE|QVONn6^Olzx*vZE*VIQ;i8S^@@scVPh5}um(8cm; zfq;xb-5Z1HR0&kY0dRqsGs}PQIKW%c@_lyR5rJvD@p48n%t7i)4TATXfIT$gJsqfe z+`Rbp^}_c*GN0fKN{ihG53TCoVBOBPf?wCV!QsXPI(5bx_#p&$pMEhHkJHmu z=?jYZ^RN<^3yv>Ap|#I2_{#{;mG(F{iu z!YOF@1*Q)|kb-u?D4B`Ba<_P|DuUIe_?+g$p;F2DlS?L)g(DKI!~g{6JpEnLQjPUv z-Oz(L(;1-LYSAP9op7XG0_xne=^+5L``;q^+LTLkJZ?zP4@wGV)q z-VY3gGFJ3MCU1{k`i=dX+;v3R|0QRTxk}FxShng-V`z0Rh}`ZDVE+CUD%{xFGm}1^ zI8KDF8gvU^kxYFT?-B6mRH|Dq5N~n*NGHM7-x~-6$a9>9QYL5gGd`6!dRIGKbi{~$ z9Uc5-UNbeZkv=Mk>`BybI2 zpdp^Vxi((*JJXCu`5uAu0s!^U^ZM=vfE;Ugf5_e$k1o2Q*!k~kp_T*z?bo7P?~otb z4iFD~T3-zxHhH$)d`<7puQ~zK_?~j^YigVcHR&olI_;R z&V@2*s5p~|Q=RUQxFON_Lg&eqV6{O@5vT!UQwvC0$y%F7i~sr@PT777CKOLr z5=u1`#q$F3t=o4u*N-y_TD7v`NLgTV9vXT)|MUFB@Zf-NCCw82BTvKJl3qeGo}MKd zpTDppNK@KgVtLfOBqy7D5|U=5lG1Zn!rScGER&ZF3V37m~#lrD& z4kLw8j}?2nApnFovx#)M8%kGnfYp2t-6v}O6Wqg7qJYZRYA~}#jt#{w(U?zGZ?(XYN~SlzITuw z6=0QYHrs;k4rzC{KD5*z#fBWD(F(DjWdpfM1+iHS*^8%B4Y~Bm-JE&2^OQ?$fNYf( zb3CaDEEf-=$`Gn#`L9YfMIo_B?5a;9eoqKAgUACq-F)(3c)|+!P`Y0gDznsL(YRs2 z(WC!0v;MBsGSmD0#Sf6~arlAqm_7hbT5Ei2nBWO$8l0~2NlXXKveVg}3e7eImM6V-xI8a)l~d-cvhm~tw=^*3MsmYAlsjkf1cy>JA8M>O6LH$E z=Ie%wMH5=HegWc4^jED5fr6rrjtdoKQ>kKty5TbUlWr|tIOO0~&37wwI!yGR7oiBT z7Q#PK%EDI$w`!kpIhI7CB-trhUh9#z?67|a|D43y7ci}?80m1IZol62nCAAdUAN(r zJ@xPVU5>;pdx$~H7H6HZ{W6ipx(l>9+*L9c-wk+MDwZG)@$kZVu*4Lh?DTqU)j82! zZFf^ej;&p1ffaUC<+vf#K>!O>2D+@Sv_j8- zlYNO{T@d+Ka7?@jDNK*OqoZpA6u_>X))w>({m5fN45(O}Ppcqdl>-gJYP30tf zE{(M%^}6VCME8V~g&-Lu-g5<9W^viTuen^&`l8bk+g}w~A5Z6qdTP^)amUEtzLjtb zETSXWfyW?dG(l*6r_}Gw2a(hctcHaIrPYP=R5+l>RmlnjiGJ11R&V6Q{od8dc)y=C zp4{*7Nf-22O)Xg+6SoSqko;;TT2POu0$Pu5Gy!;lvh0%S! z?0;Wjw+&XcEQn?Ba84^p%MX6i%l`gF$5i{8{~IZlPyfkx6&#GzY`cqZESU}p2?nG4;C-e+L$0BKOJ8PhsO67)G?M)2*IHe-@wm zlNxC(EoAK+COvP*vlSTNsgJId*pOZ8+&>(J7lXfAkM|IgzMn8sD2s;&Y&}22M_~j_ z`{vtB=-6$y;GF|51X<%?&?s>r5EU<knMY~vSRuFJ#Q}9`HiE!C1 zBC9q%pv%Oy&X0sr6-xCjB})~@!T8=Dk{&4*`NVnP*}_2d zzq0v&&m0Wk8jAt6U5J5r-F==;xz2B91|L#`;|mTQOqM@}EV(&lGx&8Rn#hL@_BL7txaXIiCA zm7RSqz0glWxl4fY{Y+JYYA4x^<;X3Y-wP;^vCK8C&c3Vak{(KB+@FW_o%Ha~@-}`? zl3H)8RgC|>SgAEky_%fIe|U7nSjc{VH0_bHLH*qKN^WErUURO~*833M$m>k`pUz9I zb%X(OI247)?Q~H@+4hBA{JKjwM;Z`vKWnvq^BF?S=gq zdd-OK_y_Qa;J}6QPVkVOuHCxt2;7NH=JViGsnSGn77i{-$2!eUu&i5}OgGHS$pO)i zn&cxT>$5vrplOjyOV8Hwxb!M3yz0~^+{-UG#HaYA^mQP-_E$2A4}+Vx^l-WEOM!&5 zI6|n9e%M_P2q=g`VzT+J(yQj^ zb)cvN+((ay9!cw?*v7+hxSQ$zs`&`{K5T-}_0;cSBIatdJLd8B90;xvqBH3Vh2m() z+XKq#A3TTMjo%}wbT;$(+@4@yid{miZlxq12~JPlkAE7w7j5m4){J6oK1|*B2u?dg zzOJ`N8w@Xwen`1{EC|$hbH^C|pt_%S{n+F`_o0X}{8rd8=>70gQsVlsKTVlsw;p}D z(-#W)oK|lvhFK}3Lm4NXOivLR`2{Bki-s~^EED|ppfU0^O2y@>Pt^8&7BP;s?Ij4C zATUK1Vq|^ce)|^ucy1ggl{=C)UxM6Z$c-6NF;J3&`%8G{d1j%{D>ML&_E#Bf^(q@= zY@bLXjU>I-@x-G!=fTA1be&1+0;rx5m9=1a{XI1TI8}s?hHsVSZuzhM|JIbOi*yS- zaA*~lJRGpX3z-cVC@3g)^EDN95vPEs=c_H@$FoNL^-eli&sU20`1n5$CyMa+T+D-y zRXW|#hN2Pq&em`$m1?r;3V;lbw0eA&RNf~dr5gY5@!T(nLYut?TXbDr@MAZGsMsQ; zE#w8kj#{tFGyKwWSM5T;L1j|l?(saS#6**S^535>JLV^ zW2Aj!7XH>?vx)2F{=C@k17Kj;d+>|q{sX~0oPSyPWGr1W8y@^&w@8fVU~nj=FWaIK zo>~V^Ma3;1*pP+Hpxnkc$oO2YAoIm?;#V832U>@_EPRkPkurmfj8*wNeaE>75^e+n z_t|cjAYXz&<{orXs{vUwrdYP(=G=A~rHcoi?pJW0^*U#|Em}@c`y0AjGQ=&1^&A8* zs!M46EHH&}z{c_1=UGhGFDZ#&94TPbYZAuA%W4)i{8td3*Kz5<{MwKsWFx!Y&etqr@stsazgE370#G(z zU^Yv7C+i8Y)sfkI3%A-{xIh^jtn&1nWH>^4V3%R`l}n>fIFl^!rAUI#e#4K@Nb}f} z4_?W9dZx3vb^U7g_HsN)d?#pgJVia4O83KJ`s{gFb>IL&wTaNg^MllN5Xq|cDwzT+ zRy?Ej`UVd`l!A7-R^))#Q(W9PP?}6O#FI^MuYb?tVbxu|x!#?#1ujJIFZ*clxI8ir zIpZl1(qB}>L8GcEc1AOK%J#j1-PKI_%Tzs8dQ6~HN3Ps1oesympw*?uGVUKk4rsBc zwLI`2P@Q1IC;!r6nPFr5z$Sp|r&C$PZ?A8Xs47^ohNT&IX_s5Abc4Ua{1-Mh)t^6^ zrZc|8t1Dkw|KE7TL%8Ek?(HQ++l_22^f(TnDn@zs=ZePj53tek>4W^GibS3T{ZpM5 z#n6cy$+A_*>^m?zy;uX$owdRDJp9ZO$T~n%zrPEH8P*l3Fa+?V}UCw`p^n%akIbfkP zDT3wE2|?5dcrKJbR`JWT`3Q5AMC-JXaMGe~3%L58*7M!=LJ?V1nP0%vnibo+Xt^>x z^j=TrNb{Q|FMB2~hMAWN%qr|e>51gP|v?fPo6`e4KrH&oM`~D!ei?(8QgKpjU2p1Pco>dRQ(rG!wb6=2=@ z!0x}t%N&2R3u{m%f3N^#G_({c*>qnBDsd>sYn#*_*+x~Yg9k=%B``2ByQuIfHq&>s zn6s#ROgV;>vjU@?c8psqz%{l2?Qy3E!CzFV^YyyKVJjbxpo0U%$#ew|hJ@wl!GZZ-FXF zyd<)jGCo|)BLPE>sDf|zK<1+McPixk5Y% zGWK{-9syK(zu2g;%DJJ@pTj$f$qr^dUvxtGoccd@2dM`v;Vc1i)>=jnE4QVp?Q-c3 zV%FW=avlva28dHtwzgKAjpBEVbSX@tvE2ek?r&0^Lq!o-EPdY4OV(?o_Zm}KuRge= z^?e0K6glR!#G;+z6MTV{VIo5^X}NF`lI8MqdYimXf>+c00gbYFogh}1wpkX}?a&f# zdPkeKYe1(??!F+IK(k=1fsnqAUj|1VLtK3n} z?Z0-fr7tPML0~|S_&B+Gj=8;9Hl}=UusXdnDOGBPweO_QRDRoTaRWyp;uD(0<(P*k zR3QEA4R}+U=x~}BTdZ|JCqx@p%Ak zaT@GaRxlwbWN|dgzkz!s_;@nJ{!UkCsY(&-MM#Xu699p)GdB{c+$M%>2X@UruS)jF zg1lja`Fzb`Xfu`KOe*Esny)|GnT$s>QC|7w1-K|HKOeeRst_b@k#0oClShM!f%7#6 zMZkl4Om34u-5>_*_NCO+@G(9c!05n{_ron;e5ed+A z>9d6Jmjk7g#W$(zqh^a;Iv$BkdZ5`3zsE`7!^FshAq2ba+8cn#< z>2+$#1YNMFoD<-AQu3!zU$9i9(`en71)*76Cbwv_Gx`|Bw$Dm|uQ^NoDiR7OK@KI! zQG7g}=><jIAWwpsxtAlT%{u#@Glvg*O~q9Xq+lU z=_7nl7Q&kTA-e>$=KXX1+HARsjNLbp*9CZ}&BS8YLq$LGdI^@i?%3s!fQj4C53!%fdef_{MAOIS$n3Li#i8>QAGjjjMrQ%Pjyl#(aLf`{I^)dM% zFQ=aEh|U>pXg0n@1?^O*44AMlna=d<_5oqkZ3(Q>;q6~v$75vt&uv+C^!Bq!!@HhR zK09z&fPcvUbxR$s78h1sTw$8|%|IQaNy-;%j8V5MP%no+={m0Ng1fGN+BS}Pg|(&9 zlK$lDaoLp1@dmkgGSzP-)r_W;3M3YO!B&ZQ_!<$81NczrKFUS!G0m*ZY4m|Zxm+0T zWY=fv5~&7_h3FBjkz?9XbO8`{xy8pFLYWf881W;iV7aSG63 z{TboOJiY!)ZnTHscmwFl9DajZ0+d0N=FY!k{+i6>5%nyH?776}=9dNK zN!#JkI2wc~kHKS;>JcO|8S#ZN5;Kn`^B|6@a2~__2RXv~bTW%nM(9#DXL2)q&15Xs zX>x4y!}A4v#Muaz_^|tjt@p65?fvEdm6?7cow)j*6Hc)t_H7Cr60=e|Z05@|#NVHU zAQ5$8a2^6;9GpaI&&l&BcC$g|VU7(}*mpucZ{r({Kc8v$^O?3q-5rw-o$}M^*4(ZK z(0!zaTmL)6Wc}|D6FGRN;b^&Dn+3urmjy`i9*QhQj%jn$I>q>6NG=egwy6QBJ7>v; z1fqwsto-s>r!d~5Z2<#Ze|N5c{!r{6xkRYXm&1TZ+n=Mn zuZGSpge!v^ul$H1kSotl2Mz-871Qd5nhQTHeD~_KJL&P(07t~N zh+%?57nE7h#OHNKznYJaD3;{xx$WOF=bB3}HO!L%UYx@&%{J!t^bvUJO*An1+m4r09r=i_nt&SyxIR;?lw2p)vZv0yCG09lm-wU%`N0WRZA;&b2eP7{TRq#-9E4k8Ui9sYH=~u_U&y z_HnN$!u9=xg;s?=Cp>c~mdLex%q0`5W|N{@(grSu+xenp;Hv9o4^DQOG`6p|m+ys$Dq3H+qcI~{Z}kV=dL2CgoZs&4$)!}ODEx<>$*Fa- z`xE)a>t7L=gXQqvGH1o!%v+^@DBM z(bP0I)GuQrPaj7wiKBD9oDW(Ei80rW=k2dpQs?)bUT{V6{ImBFMY6+mTGRU{v594Y zgfb(Bv_9|vu-QB>sDts0_f0P6y_WZG`@w@B)0-a8$T%14={-h1@3$yJtu2Nd zCn&(pT3{@Z4(jOrw|qvpdHoUbvuUf{pD*u=?Pe%BGI41w=(^l^ux%Pz<8oZM=zfSU zd~QcU^q+uqE;^;%YEt2KcOb6a?XGG#ic))?nLi+WFVk`&?Yc6oe>(jLbi8;{351PHAg|5z+8ewuOJxEY zPJ@vawZbSYJk)o6!MrYNXPY5|bHqV^D}?_jGr|FTlT>HwTrH$3ww6LZyF`8*jDr zO|Q1Cfb4ps3vq7XK$*%+Aujx}-38gdBNspK2xQzk?S+l*7g8jvwdUbH5TEyd7ik+` z$WY?I|5uWry{Np;qAS0T1*1EW0ZOa5x3{M?j)%HS+A}ZmF;xdK;jX!WtL z`>NG!9TLr?y1AOu{q+gj<#W@yK*(WZ5%lRCpoBa?3z=wQP#);pZ+=32Fq(n{0FUGO zYfa|G+?Z0~cE27o8soH8`zl zeJxRwPr(bZ&k}whZF{7!6cl-fe#j8H0&_xm-m~iCC1#~2nZ0bw0?#Z~R-1Fe??3z_ z+&o@mT>|cza9uPSbA?@%Z#v$8&XeAmklj>G+VBs?tZC<^TNkxN#^E?L$mZxgrl#;d4l+rxt*Y(_m<0}0 zPBzhAZI3w>=8I7-CmE)v<GlP}LWnl0M#uWJ>{xO1sMu)SI7Qz0MFo+R>4WM&_E3#4{VzGyyGUs4vR7Xk+%A zbyof@ClbJJhJ?a${wJ>D+sD695ei)$`NWFD9LAgA*tiBLVN z=N~qE7*Xf_;twmXD5NQi+_#w zgI(!i9zvFd^!_vEq*m4co+R}nPG1+n0v$l6?~~kkbvS0W*)#s(^^Xm6>akDXL!8~* z0+Lk$u;n0SwK*o`JC4P%?q2R5(RSeKk%RWUy5CPKJS^lpqxNqzRJpwP{aP--QT<9GIQ8q^PYi z5C$uDmr2oqQJ8I-(5N4~pKUBGkThFw3MlRoVED58dHrJuCoYbKSozd6hl&aUpFm81 z;RJ;`AH(c-9=9sJqxIT?d8ke^;`#ERWNcb5MTBN!t>dW@pqi>Wo9^UC$!Zzgx#a9I z{v`jaQPbnK_F#VVkQo3tk8=U{c=~)oZ$kWvY-PIPLn(_s%gbk{$Iqe^AU#mH*nqy? z3Zm45&Yxg77!PNz2Nm1bcZJfQ0H@>zd<8$jvQxQcF}y#4UTZB*+uot+zT4b zQwAMCJ`#DoJtdnu+%L&Gp05ep=Aiow4dqJgl5#noAV(7jL<7{Oh?t6W4m6W*U`jmB zz@We{@BOUdijIt&`L~<3*4k)Z3|$TIf95I5o~}0|{bxiAOQ0m-p=C`<7j$%NAdiMd zHTufiz9i7aa6rraiO1teZMC*C(j8`&bAA|9yFcV_AreC}tMU5N)q0dr5Uj;Qw5KPgnF?&^@6*+Kq#wm?B}zNF z_9zKF#@qHT_kzYM5XCaLg13f)HFo=y7i*2fJM-ksX77QwTmW}=M6;s2B~BMm>W9T0 z7cfIPfqUXGdd#mK!YzeX`$LM`fk5R&S`G*Z@!-Rs0pEJuD%b#1GnAg5o_3on_uxl! zgN+~HG#kD5KoelnJP0uvPcaf5v6nRDv=vJV@2hDh3RbJs8g(5IAp@m7-`g`VUsVuv zkV$3(U2d^63ao+`mA15$Rf>CaX}*jGYKGu4$kub|?Zio=3HkgL3&btG3;g8+f)OB) z2SggGoX(dt{;~WdiU>#xb0$^sT(V5{#3QZ2Qful6wEj+aXq9F{6rz7$EaE6qu@u3ZKJVmmL& z`L1@Lg*P60Z7Obx(zD-cYQCgyyQJ6d{g%zI1-v3@?$tqk|1tPmFWazQ=hrd^Py26^ znBZ|zj^H<2Bpuu;m5MqY^)|8?(=5KX=3@5KnJbZajHpnLh38L3Lp2|jQ;jDmhe(#|S4O;skBFyG0{q1b7E9+Zq-z!yudvkX?Bp4@HO0fR@5W?xV z!pNM1a4<+Xe@O5_Y4Vs=nJEUnI`xEiiRx`vL@*_1N}G^~^YS+&jW+Z&RulA{D1K$u z5pA+kQp~Gnb}k82uO-gWeVEGx`MQX&_-Op0ssRznAGA(fA-iO^_e=st`S;j?l~M7n zk!66wch~WnH`W`iBhpCg&Sx`=AXzT*p@}bVdgpE1XEqimhvHiXCDd~L9qEqokYhW zvtc5-T3t_dK~!TbtwLU+8?J7GTcn?thcu`jaGI?(@WPiPYj)L@)1GgH{h7 zdLO^a;w|bt9c9BAuPs~@-b&%fW+WEPa4ZLMkf=~bc0Li9le@=Q(5NJF>i)ICzbAER z)bF2HPN-=Tf90YMEkNJs>jte4M-h}O?if}X%MRcs&e0YYPcPQ0{A=@iYZ5Et{qaL) zq-Nm>2pQ_X-X-0ox>mh(?>k4H-np|CPbaQi-tG?{ywIxB`UjGe8!GyuWq<8%vl!EM z+-~g|8bLS~z)2YFdb_M=qp}@1x$-+Pbv(7!nfF-M$k z*5B1u^i_Lfqbfz8Z1M6R=L&Ngf1Jt^W-Cv&pYCws2YR9nz(h!9{GMF*`mdUfcWxwh=5c3VKkEE_MgjEfu}Hq9HrnpcuwSqgdK=QNuUlo&KqVcPr7 z>)p@u>an%qhD!B(|BO~-?ZvP1?0h@Njj$5^+M~7YMMW+GkDCf#n9mX-HUIk^5gHa9jI`_dpA3fiuX07@y^u9n1K7gRjgeA2GzGw} z5?H04OnW_DtAZDsuS0ip6GAl8=^!39jmfBlu3KMhlsf-Mr9wsY?rS(9zHleu5djT5 zBr-IStDKcXjOvOv7gWFw5ALPRd8p+O9?1orMpMRu$gqHn#pTILCWAw3$aOmi4nljj zQXGjU+Vs+IKU7hI$6ci7+c~E-MmNIMHWmkiMgLz>xWJIg#JxAd&NqvpHNeA=8>Y$z zno6r2^pLPoV)hSzwCA_0%+G~3*ViX(-0gbfNkin=zP1=b9iF`IEP}CL6_Gun{M70# zu>+y9=9XCNgzo2TD_zb@lO}{pd4?1S3Y?q<1qWJ*wZ4h^kw*-bc8_-^B7xPY+fCOi z8t+{r9)7;cW|4YmnZ0euI->B_g0OyYR|%AcPaAGv54YLJ6vj#rg*99*=fx0_E>6Rf zc-ycz37jt@sRAmpGUGtgX|WDe1*{H<_j2V&%k5?J$!cT$K)1*9dCVP#E-05|&mo@= zqc){HsHI79OPjvz1kd~XyuACd3psxV*A$N0q}JH0{oz>Dp|pP>^i-3n?I|w|-jXG- z4(4zybSF+@+=R1uf#Gm9n{)v+_VluwNXL=Eo<*1E1nW(GmP_zlQMlmo5O>=ZDF#(y zlLR3=Joz%K_Ngp`1YS^Ud8gx^4Q)j2U7a(Xzlat}%}IQjQS}*MZc^N;yQ^b-`8DPX zDj|gDwEUHRySwj>`$JO1Ot@5;)f!^6*?5M#L|?aGc?`Td6Rq2XuD8JWe7sVvHCXvY zt)uq3465fGxIuFndJi{=Gm)%>hiy}bo30Jn>f~0(EYQ;Iw+!%4d|FxYXLCzan!}w_ ze1j+SPZ*BrHSP7R(8QwvNesI0ARlJezfr*FwTJLy+x&gmdN4v2(HlNfS{7k0!xzM{$e*KC)38or95U;sh7Mla$i~<>YBFr zalTYgGEx7q=z6w3WJg!oI&_uQE@&tm?FG19rEe=KW4DW2lP0wI-`*WS>78q8F&~>N za*SEHT=rbFqxcYTIpkEoMqhI%w+xK&*;TI1D~{8<6RxK{tZl+p!M}+3ZmNzICwvo| zSLmuY+idSvx70`vfdEn6NO2Sqo0NK6%O4}(8mD^7R91(knslwDaCFL9Wed3+EnfJ^&Fxu2fPx^4FtC0r*%SbHF7 zPy{b#70XC29mC&)D~u77#Dq>?>D1iWr21ngb?g?d8KNAYI4EHP{2&&i;E;@9lQdBe z;~L6svbCmeR6WX5E2qyQL*D$mSYGOlRsN(1M;N9-SevY2%}hk_V2 zMzDRAeG_e^l7`w+&FEn@tx(~xr;CroOg4bhP{~nB?o7sJ0Vs(|twxN-P#~K? zYNI0q`v`WqPsryP8jexEH?#YJIzmo{_2uC5EI3OV1bNX5w*NB#D%@gZRGCUyXQ_8f z5o}n7_5>GaqcLCr{s1s%4g($EwlK@%RT0LJD2nCHK-RDXQ( z_@YztXl!&^9y0YuO85etc;0+E}Knv5%J*>POl*lI5grlP|3>=AcS)p z1FGcuwe6{ci$*1j+%v!152b{@a<;_;iqIc|gr$l?C=CL--fX@vrnp5cXd=GHsR)%H z4jqw|gi@HNQ##eXI(>H_`P*jS0Rbsy21Mz_#n_l!EQT-wkzmbmWQL?pPhSw(8^|vz zR_4k+rcz4w0?uFwp@eYa_oeT(4XDHzpfp*$PNLt}8PfytV~kkCU_@!XfhhAPb$L0M z)Qwkzg+&lhCm<2WAMsMA-3Kww{C4nGu2)Ui=2*Mfun&Mpz#ir}{t}}w$7xZSE!Y2I zQgkN~wmOtryt#}j2Q0s#rP2#!!lx(3hf$(k5fJYzuO>oK-6mtHiYg({;qDJ727fKv zWN!tv@bC=o=Q+PQI;n=icM9{mT=k*5AX%+<4enSD`Ld|Sq{{H8J5odP=G3~}%f8D% zq9wJE6CVz3!|HiFebg5pyLPbftEAHIxCtF&F8B+kB}+7Qy<7;cL7Jd*}{s_zsJ@25|(XC&fjhf5^?Cn*biex((x+=d_Z4& z;czei+vvFI^z|IzR@iOqfr5m?7)qO`sx>@S0_~!5RWz+5de1B?98N!E%1+v zjQ^dP`?ep%DCbHCxsm^8ym$D|=nA_GRMf!Rt0$LjgNB3vayQx9ud|NT#HO@omjB<3 z{VCwSvvj#mBZ2Jb^@sYDYf7&p5>pm8FGw}PWlZ$9;MlqcesP7s;^LMXVURESrn_pKZ3McFib%kzn~OdMpJyiO*%KS|d{ozgLCzs|D(NS;4P4Ur-;2s$gYt4@)Ov zsbmKSJxr9B`YWg=o?H_7R(E}VW1z>&lYM(a71qGVrsmG0pcA54Hjv6LlS=w4=0IQk z5c_NpRRT=4?PZZH*8dykp*QM{0pe^0*ftg+H;#zZz^7#S-J7&d@u`jmo@bgz~8b`26bcxs0b0VYc|; zIF7I8OQ^Id+o0KOv(}t;c-&ZdoG)@|K6AcrOWUJP=rvf+>pEP+;sf6?`_TkuwT;Oo zOtQ>O^5{}H!aw$o@%~@AJNllVucqoX`XrdI|MmyM3i=FfCy>TmjKh)O?^3W0?|(y> z@%4o#(EafT-9F)@S1R5og}yxGW=pbQlMD++sOx{?d#iOCr?iq=A=Z~&LO6I~hhjCIB7KDJv~D+C zSh33|?DfAZq7x2Mkf33%2n)kdEme%}M{cwU7^r5_>k3?*{}I>`YIGUwWOrvfSW$H) z3#vq`S``?Hlc1{X{dW1wfY8){>i$RYkPDa)JWZj9SRffcquh`??&44U5cu9=0&=Fc zxZhfCHYRP;=63oZ*`IgyKa4PkY@|Y$2dWoYDv-Dvd;|cMoJ`6=r3r`M9eyqD<%$E8 z1_C~X;TNLHL|$!_sT{@f7_taD9tOn@oHcWN8Pm93tO@Sp}!zSBa z6@33g_(S?FYtKnKg@#N-g}lB<3Qn?DC5{!aKY12yro3E}ibh0$AxBv}h$9lAtMYHQ zk|jar2z;puYOaaZK;AQ|!hAzO2r7S50WD@mV(oP+{2?B}NL0z1NvmNj6=~ z+iu8pkYKDYy3xJe;|Da1Rut)Acv$%g6g0W*%8JritG}>XxZxHcXp{IPc)AWZF^Ii6 z!CXVn=Bu12H0avHlIf5>?$!+5@(j-qvPWY4xp%m7II*DcQLPUixR>qb`p&CqFT0xUjM^LMdsz>n}7={>5X7f3TfQ~Uyga~0x9`*2Y^`G3NWm}$?%lVr}-SyyI62*E}i z1Iz&XfD%1syN`ypdqDO^IR;I)c*B zOPw#(b~1Z;`FwR{CPX-6B8d$Qz?4HqMPdOaBw+xvcC)`vq}U>X5}Cu!jX@mr#%fmM z@ryJZgNY=Z5r75(4WpIHvU{n_q|`wX!i-8~zV<+5-vE~69wLAaVg!O-gORn3t+*vm zDanF$RLQ=kL%uE-7^Kr_eIL3QK7kRs-T7Lg$T@dY_gjb0=c%bo20zB*+4mk5BqVi> zPFnwktzTHNeby>K6LNbtIuHj)kC`iy&I9@pv01IuX@e5+wzmW~+Yk;CjonDwJL|$2 ztEg4a@S^%a13t5OoIy3(lIan|I@=JGOI2#F84(fZd}Y-CT$~)l0{%mCBn&cKP7CT3 zAoY?~iaVLjrv(BJ0aIg^5|qV`>4rt83lG`2;`+jirb zLO0oG&Po2`0!6WX11svsweg{(4ysd`IZ|L#vF6}PEz=PKpT0?|aFK-lBD+j0$V5!6 zM-<^c0UuCLBh4v;H}r`y(a~u7Xsa`&RRHCO!oZsDiM3_GrOc~+D!uEN19&In9x7*=rd@2#pcp)CZFD)YufMkXF*OA=vOuz^hE za`{A8tJV#0FrCg59Y1REx$c7Ke_`h!7 z9@?(!G*(l&yx6=a1Eo^&XTnro+p313FxEAotu&CM3h0wbUnl%-Q$c>e0##<5Zy6TW zE_lS_PtsVa{c8WmSq|}lw%z@awyX2g`mX~y1;wa?M$L{YXxmzuU@zFqQHCvf+D1`* zC3(Q>RRV#-*XIJQ+#1#OTq7JIzh@{gE$lnJcTjpF*lcx#VflQ*5M7HBw;KRCaD*q5 ze{xvH`L?F~Apq5@02oi>t@vC%J1&wF9c92u*N%yMf<~or*Lg>#W( z75LGc-H^K~lpCe>e8MX2&QyPm$(<;?)t-aFiM0Ay$9FDh9!I-0;_YP^pYr5ecS2=8 zc5%Sv+5wo%u?L<3nU9XkZLiQ*vB?^MJ#akQ0J$%GAS)|sW>yM_xzA5$jg~i$k8wt; z*W*c*p?n_ButxJfvodMJbvZAPFA^n=+9}lic-a?uH8}*ZV8*(%k9`|qpW=|h9s>-fQ0t8Cqw9Uyg zN#?L43M6(y6Q1)-owZM4C~G?27g=genUKrwjT6*W-X$jzF^k8N@$mY*Tv3ALJgIz~ ztK(%~UZqq8MN&M*Fg^pS%Eto%IF|H55qT5CK>TC!`2=HKHbJ%q{CX1)QlCTYwi|+| zEcAv-qXg4#aDVn*>_n;&h8NOCAwf!hY`Di0ZqWCGkpEx9bNXg}fLe2)@DTm^&#FPRb6pE8s@ ztlczE?G0NP4$RC9NNLR(|0h88|E$7a3`kZRbqE>F*X*wInQRW784Q+ck$8up_)JEY z*FtoFYqj|qT}H#_Z+U0s4_KU-Mx$4Hn|=3M`^CSdnw7z&Sv7)D=Qv>EiGVjv5cWFe zT)Zx-UOn5A)5{lq2wu|pXR>KTo0BqE9Q_Ey*u>*g0tYo5M%nwQ;mX|M*e+oB!=*eE z__6WrZNaM$4O?(XhRNU+A;-3jjQ?(Po3-JQGtbLu|bx>b2h zrAX7gd#<_0H$EUG(pUOzNMSAyNoO!B`0y?0>3r!hjd$W860Y}qWyhvbtoGaiLjmW_ zOrQ92jc+*hY~4FAk+XCw7oM;u! zDL8Us+MH&2U*+@+Cku2@TOC12sbugIJH*CR9@!nb>Qc%i>`KQ?TiB})$+@Nf`FMXF zVW|Doo-d>O!vt9pvpf_-guO@37$`NJ*+xEO;8770O=#sra=J8Re1zh?-s~ycczRLg zBn=05dTkhtEJ_e0MMTb@k6QgR$PO)tDcbdU*0dZ!mt;+)Qi`UP@n8TyP6_sqAK;^$ zqQs-C&14~ce4lJ3N)PfHFSok%=MN-f+z!qp!wQR=Hh8gq$pYSufnV=1)ds(i)hhI8 zMC5IjqN9n7H{bR-arX{^Uf$lG-`*5OcCayd=Z`V}NMMolB6QpIBUgeei{CGR7h>*e zhlU?cMM53;WoisXr^DJpp*`5smVT2kk|Cj}a6bkjA;4|v7m2ba|1Ex-jYeH3Jo50r znsv~$2~`=pd@S>ngAJ0^BDFk&LvXW3^!ns_B(-uG1)0$9}h}vFt-_?a#Nl_R$xxni$_ljaoriyo(B(`WS>Ki(eT-y7<3;A22=T zu%X`mvQZNTnFX1zkSdHL86i<5$q23LoM5|Ai(^PK234PHg~@KS@$37!mT|6rK#3#0 z#(oGpL)uu4N(LpdC`N+wnVrrO1f5z{Y)e0@dy`5Z3H*LO85ye-Rx3}*PcIC-12-ra z65@YHv3+7g?!p1+FZ9|E_}E65#K|h6rQz!3B8&8zh5UUQ+Q(GFQ(+%2*sLfs*LY0c zgDNV273oxW_`zw&o6a`u19YsKP06TOmIezRt>Mf=U96VEcD<*Zb~i{bYb^SJQs4krCv+y6)a z+gCa0L-%9w0*5T~5`Ra+(v4!^_Qz;2!xKU*Dk2<9iQzm?Pq=gTLfQt|+VNywn(|x) zbfSU-iqMG96A&-gqY%-CJhZ^OOzj5D2Y=zou)84Rt^lX2;$5h*f>=#DfOCIo+Qj1K(-Y#QJW{Lum3dTN`)CA>JrQdm@ z;mi;zB~QIv%{9->vTKbrokYA@R*{gMs0u?~-*w?N+R+E3&^cC{5M5^<4L5DCpjho0 zy|>x;46NvlHeOt*HA;wS)ywJCXJI6`+;&sI{%JRPsb&{>Yk!T2yWWd{wq}<+Ft^B* z?LDKs*B?OLWw#T1lsiZC%a#;-;%3Vl$H5DyINHqq?lJuzLUP$$3XH*f+kmiBdBIz0 zgN^|}G5$aEWup5YMI?n%6eYocI)&8sS&Q@0T3d7v4=bCZLaCIhAs#WFddt@ln`@EK zI0B>YoE{5}wj}yt*!8EqXsqgTb?yDVhIky_U^w_db9EqwVU zosm~me>Q?)82AhG50mSQqb>j?&Nt!g`i#^{qkk?DkzB=+dd!w6dD?e zB1TtB0;m8qyW!HCY?wd@&CInzR? zEIosAsUXUqJ_DX}TQDUb-wvohb;I_t=+$$Zs)Ap!6ikwFSRII8kdKg|j8>cc-DzWD zZgSa)gSKItM(maWb0#}^d5CQjVP1sbA}fSof)Psi^Ygh8>CD0cl)hgoQ6vL{Xljs+ zTS7!AmN-aEImC#Fc! zSSbjl0n?3E51Xw<#2Ka;uLV{QL|ehpAoyfPk6{$>o+}<3Q_~=|3av0H)I^_kN_jCL zg6Htok7{UKP&2(XSd|v^=G+&$lMkuDVznOd^A0DQDA9(VfdTO%pIu>qjGHz!Om3|t26z*h z&X=jOEHtv)YQu-)z7E7ujERDWSP@((Q|_Im*3}AVZgqaV&^;qr;jPR95NiQ=0RT#S z@+bO`we1YyuoSfpZFYDS!ejRsIJLQDI=qa-0hUwbVxT}UGL5FkSVh2~4N!EJE3O&} z_KL}XPofS{`%`{lZH$cNsz*5G8-*6IOOSkxO1{#eRH}0 z@$|FvR&mCfRgkkxR@Tim`FtWxJJ<4?v<6$<&j*{8{U-5fB6vm+eb{O@W|S%L(2Syp zii+ZNy!q2E@BMK0pIwE`zsqv%BXUnRb7-(apUO%Q^G9k2aD;=rqSvd11SlB6&Gul` zofPb|)efFY-42j}zrg;CQC-~O<8BaRF^$1pop~2159Z@V8ts?K%IW-snvSRfOX^t( zw1inH0+Cra)(?2Zgdg(n@8#=MEe4JfB>^<0&9&Sv6la-Yq5JL3v~l$CNP>}Ct_qz- zP(JUnGyo++$ii2YV;yaBz?QaDo|wYm( zw{^hfhV6h^{zc!!ipfdS@J(;2$de^zBYM2e2b0#bG|C*J*e6J;+Nab>c(M9{fJZV` zb$GV07bFJVfJ1n(i^W`1DnhUVHdhPK3tSbA|L>4!hFtIfmZs~emXI25q_uf`bp995+$Qyf&a2JCf|OMMMavf=9VkG%3ZTcjov zX;6G#kG^Drpicbo+^n0<{}~A_upZ<0Ed~8~!rByP0*h2gCHCX#%qLZHP{#&kXPWHo z5s6J7Y~+Cqyr>}YY7ufwUIJf9;QLaxe-Sswo+Xg_j9X6T?}iJjD4CsjYU(_P$MQ0^ z?biaQv#_VqRBk9^L&e3+Qw%bvZ?}j=OJOoD>$i${27FAd-3Wt(_UrAX;0277OMlh% ze+MM!`#s|nN+*gNUQapN;G`%P8ex zz|->cPb6HLhnH3Wx-04dd68^p6b9W-p?_#)9Wm6_Q=1(}v!(I<&W9e8i5gD;Gm~`T z2Dm~Y;SZ+7PZ!xslo~+&lgSMF5kO|W*a{0S6_>sG&uB;rgv1Vio!QhPN%cU8h@FghS*7FNpQ?)G$L7|D$gT}=D*9|9rjyEhn#ZNi~)8_@vHZrLHN?|YwE zvi|1}Jw{;es4A`W>fQYKwFQtRh->6*Hd@@5c{9rM!yw+#MX}!f+Js&fFW78cc z#^^+2jMHR#msq2zUMx4cz^gSNA-&0t#7~$P`hkcVOv-mK!_4DI>Iv#c>;xnSzu%n% z7+EXu74GS;%37sO*L@x9Xo5ku&FH@==;r+ZpHr#$r~>b!>1;pSSBFn)L#0qTCK92Eow^ zZH@wut?4IVHm-GgR$^S7crBvo8nRs{e;%!0wL0Uv_7R4@6V3(@XI>{rqg{?71*Su{ zja~njGTHDVhpg>D;CeVDeT)-v+jwb`K%>DZ=#EI2$hs+7ifxgdUCI6D9CQJ7Ha`&g z*Q+xpRbCeTokP^AO*>lr9C7NwW zu!AKUrC*aEVRlBMqftBDD#T*NUf&rDV&Vt|zh$*7N{`&S+Wc0fgN4Vvqz*>gAx$`W3-v8BuHaxO7g0tpi{F-ICSl52!3how7+>} zzFg$lPVr~;-bUm#IC-N!eqz$}W?Guy2J;O_Xo$52+^ldar3tl|BCiiX0@c6s2jZd) zb95O`@{FGO?doXBq|w=H`D+D7!{F`lT()eM^_8AW*TTtVb*MzCFa-|muV3Td=I`X; zLX1Ct1r6{=obsi{vzr}U?&Gyf90*Sk0&}GPV|QDYIMWxUO(U$9*LP#y*L#lm zNelYeTIqTu7xK_X*~QXi~YR38^q8!e|iCcu4RqLp;|!+piXEGa)8G zEGY@%D{vi8_>Wdau*QgjabN+8u8-`>a#Ba5!3oOkQU*x>HKGH{*P$IokC;t^@C)a$ zI4-gqU%Ql%&4S6>ALj*#5~JVS&^8q?A5Q4m>hSsJ*43s%^DYG7y#rJA~ zPLePSi9ycGTV$O3$Xjo_rdBnilFO{B(fL*zaAsWg6Z8OgxzRx-`n+SU*3ZY?Mm&pxvn#6uHw+2?Aq21I^sxM%(*{*miv!yBsqNc&;3s(KBW+kX7 z19WRTi=k=0%u{Gc2pDV&KHDh~ked9H5)l^-3=0LM-8*Xf*s*-|b9t5CTf@-=-UjUIfNOI&T1)J5%BCPIEP7=?eJsZ%|7+!XE+{i9M z6;O*}74qg*%A1DI7E1LD3}7sEbp!$$DKbh*=x>w};!Tx}p#bzg@HLSFZs3uXp7pK* zINfzhya7()AesxpBv zp2Bazz^jS@T)uU~{8*5hkBq`+!ZiUe07aIv8$H2#M#+ej3nVJ7Ez$0S0F=d4dB0*EYxwN=Ff2}<@%aA`DPs9VvltI~35cC@8 zF=pAHfK6b|Cc_h^4rUy9gm#~S*TH-UA)_phwY*Se``jSw4fvci?SRul)e5T8D0D_T zf2dDgS5he+sj~o;5cl7em$KV;*GBU*_{=SET>2Z+n^(I_(b;>n6O|_@ndA_M8^dUmn@!aD(we}@Zd??h(ZLL< z{#_qDks8qQQI4;-Bf&LltgAIUFwq>OaG106cf-`m&41@KMD1uuqzGPK%a?77l31?R zOJLF@AKi;XA`+_LcHK`AdVl>&qY21_<`5-f@y8?%QY(QVn~H(t7yz_x0=E-Ke*tB) zH9GwfT^VsSA)i`8RjFC-U!xn!fCM1bV&v#hjZz#Fr1!XP4;V>WP>i>n+j#->78|}& zBbW3A8Jn1Pv_2f`M_!mIi-=f74_3Cn-8?e+k(aU{2qbVRu^x;7?1YzC5|C$9(RSW% znt+CboqPnMom2ZxF+d6XXGcGkN${)jHK;l46_9l6z@}i6@q4kt0csO#6{!;FpZC{G z;04r5oU~mrF_ORhfJLW>s3`mjdRTG7@ry2AOx)sq{gy8<4$aKWI5^>_LgWlA-~EQ! z3fGEc3QDNoq7B$+gf|NR{E=fHA zf)YT_m3$A-HRBF5RxEuXJ`dOCSQho#UH;RrBOROhQ^VJ0W_#o~~j8_%%Wd zz7hv<$ThGI@)l2|{r(vQPxV{IY+}A7(}5_E8e96@YV8X_o6A5(>ReFyP?4@T%{T|N z1j(^Z6O!#roxK1cAV&4y`Jt#cn*2GYVqDQkHV09FVq#_CGnL4b9AIHRUyA}pf5==c zpB2M}43~Dq0-@ANqx#iv6W-)ZEhqPX2f7a&7QGr5xUcB+38Z$FtAn@BlhbYb0?(Cz zsFOftKPogVUPtP6aS;|tljfc=evk)VD3KqSm0msGt_#Q<(z(B6zhx$yWCd(lG$uQ@ z*h?j0=9M(;{B_*F5>ouGXf{sN3f2CCuEaU$$ge(@$DYmax)nZW zeVH`NWdtc+^F~uGnr33E>bEG)9~id|`7I%=7AnL2zML!Fn**CmD9F8c#mGZ|W8a!o6f; zN1ZJ)kjyD`EVdnbz-IIa6(h;Qn}sOAPLBqJM5XmXIpqfo+J=`GA~LuFdYiwix<0f{ zTAcio@PyApe!p%ue^j7U7cMm2`=)Fqdp>^pT(Rn3bvy=?-jW^ost1LPU{CsRbj^_C zPb9K<>Q=iBxvh6N<88Dq<3gS~2|!8E=(YcuNt2aj$cH<%G2Sx2uaLKoJhbn6w{xk? z2_d$q2ZSvaGqbqh;XWcY^c?``^CE9MfF-4x#{CniBi=%Oebq7=9bHQ zV0E|o{#wmMdRjDD3NMjcKn8z`gOZD?DBv)SVn|a||F`Xw94>7dUn~N>(F_;MM5mgF z+XDymX=r=l7ztp3h+;)elwrSh=qEa$Ei~+lflVfYbL(j`Wr&;;@Jsk*>kKK zPO#bBcz2EROoikyz`ujh0l)+ei`mYcyz?lRIM<5xGUM*j0Ex>pGrcAbbgjkhrYAC+ zwdVFf_79PV_-_Qzq;8k%L6{ZgGtFTbMKVsY&dEO{f?hYG_WQ8lg68 z`7l6U1zLV;CGV}ruh#sL(C}xPfIwOgF$jN(bmifk8&n1^L@*|tgsalc2=MniHx=4Vf`v%|0RbvjWM#U%;+LDg zR|`w}VcY?Yr9Y3z#F4G`w-?-0%R2#V$n|6%6KAiKkT3s)mh&t9xc@auGRaYQE=+9p7-MA-8B`UpTU0(KjZG4DLBMRZl;G$F)%TRQ{ z?&nNc8YP$;^=}M#qaAK76_sd`_yW(q1ei9bv+GuVY*u7J1tl-Q$<9A{?v`pb;tJQ{DR2% zuHK11navZf%j0HXzKfK)w`e`B&>aCJX{CEiq!R%Zh+Q~DPTJ$mTfJ^rSSc9I*^dM- zD$cU54dPgDe}XQimQl|JK$-*OsKEgJC)-JAE(r;cUSOjE)t;`wkM;FJg>Ezm<8jKT zP!kJM_IlVBGM8k*_}iP#si7;C7&P-Rp)Od>i?rNeh%7LY_!0PE(RXVkhgm#3+2&_) z{Q76P;_tbcp|&=@_TTaSe`ilFWPCn1{8O|>iM(przXv5Mo%nVeosrX54W-{#>#U2> zzaq#8DnP$F%)+J0&zET7Or)_U?b-Rc<1wA?UTB9%XBPx|QD_&O!t-St6(v4Oaq( z&v%)r0S7S)sDS1gx|3EBov+PB41mc|32}a(a@ZAcYSxej&9wMR)uIYd^)0i^^OxcS z6-GeDFdFo4EJw2MW%ymG;chyXoZMz5Dq7$JHVN@G*Q~*Wjm!2HQ7aJQ`8MD7uR2pK zus$W;8^SSEtiwH^zneRafg>Y`{h_ai&*_7X$8I~YM*jE+0>0rsaTTZ z{`#=tu7o4XC&NNa;d|Lq(=k`~;iK)DP;d0C;-rsGYl-OOYcqVuJG^Z;_Djs$ zr|=FIQcd;aO9LbGNLp%<6MZoDZNu6Vu*%f~varowr)sw3A*`M^cs`2$IX6C$;#fB?jl!hfQxL4;Z*$fZ#q{P5Fxgs*PKEqsnD;v$8yj!;KA=8 z!EbU^shGh6dWfHGZUjQi9E0XSItAL^p6G0&4hASw5eA&<>l^FjepBtUcgJ(61O$)3 zvbWF!jgT<-E5;ZZs|yAYSLVSA5)(>qh zN$YJ7R{CHnl>OS=moYpbeOT~$f~%@ll7oha^;-sq1w@OyRW+&0ZK)Dig1^r_0-%ck z-xjOP*u}ME{e69XgOyg(-abK=U)gI=>%#xZep+<4h8%El;saF`vCcl;x53rF)k}3m zZ`uZB^kdl*QIO6y5I?s~EmW3%et9!!cN>Ql@9^{&Zh#n5uj*Np#oKAy#^^R!wUNi! zy8~CkWpAAC_g?T-Ch)R!AkJH=j7?$2XntKmM7xnQRXIsvwacJ%YjqtnbI`d*M2Jf% zCJ_YTUaHzc4H>5OU7`bI zXNr!@nu_@5os4z%wZKAH==Q2xUkJ}?%JIT;V3 zv$;>tk*%zox;oZvi}I*d zeaj?{dE+)HBXn66rhtVA}ux2^Q^g- zxj(vSPipDOc3UqTl+i>Xd?8V^zcO2_nSr(?iz5YXD1~oAp=$lvw^N_Kk7yd|bVXUN z-;3qStnF7$8p_gIURAyQhU>)Jg718(oVKEI+0lWKT5(CC69S6K=S~9_xvSFF_#)SI z^L#IG7l!;Q9kM)?D2&MS@Ip5fn+amJP&T^X&CTk^VaKa`$L|5PQY+@GiVu`~D4Ndm zmHGp|wWhvFwoo6y2XNBbAGBP{2SU&urPMz@Uw&91M6 zXJ{0HrMm+$Jmzk{jgQ5zk;+dmE-HQGIPABCYsuX#G?u`_{3q`tJ;$;NJpCDjfAO{` z=A}IP4N%aj?+uKpx0dy`I)Dr7hnC0NY_z~s9)2g*Tj#V`Ea8tMZ&beJaqeV&?>rWN zo*??3-zN+r3JOdBt8Wtt{Wx5~3)fn2Fy}Bq9aS00poy5HIa@g- zR`GS$!SY*^vY6}zouy2}`wU{^8YdJQlm)wH~MYtQw+TngIMXT4Joz|4^aT zsI-ptT`Lr*`Vp#CFd0vQ17f+tJH0`%oRUU9Z%?T4RPsIg;mJm0Ns$2Wl?}8#0hO(Z zmZI$Uqh=Rn3uR>5N%U4i)XqkZ8C=oa*aAMM@6q6p}C12|4(eeaxB7S7B0}Qx-Z(Z?JLif&0 z{*cGj5qK7#XC>ysP}F;ag5yrFXuZu01O}bjY~fRqYM-;n%FtZh#V|e=ls7S5?HK%!}n)&8QEl%ydH~ z^hv;vr{_)t;Fb_odY!E4i9%0)4|gh2V9KH%1l;xda6a{<>D@f;C!kJW?|kh?JIpO^ zQn|PYt~k@ac}ho1iHpY`IpJ#iExmG$mY=$0yX(zP_q2eyDFV<2lllhVJzc-U0Nv9e z;9oKro#q|ttrnDYo%6*#!zF+Qx+1*fkRfrCnyFk74AN&&MNfqJf11X8}%$L_h}sT#Kps|`wA_s1sMx-ibB{vE1+s|(hE zg{k%X@1Zyf>FdM!QmHf2N9z@*e+fCZr;8Omv=XQxb7z{)<7N`EueRrD4V*4d)n1DQ zlJQ@GV}J-Kfo8g165eLBmJm=L5A?wxCo0?iSDoBuk5y|jlJ~9PDWr~Z{>)`?L9=5% zEaqg(|6>5K=+1PAyYEjZ3z|~Ko|&UTT^%rR=tI%enN9Wr3~;sgl-)fZ-K0jCpkk+w z=a)KZ*7{QAqGJ&Wx!=%#6P5-*Si+m_p0Q-!?7W^Y2*3)pXOf_eL~e#uv_s!a1icA> zRe<=R(0hew-8Yhn7sSo*`lJNiHaEk!W;l0IEd!8+!q_QgW0;)}5Hffjm3(~; zCkYatk0RUJ&^jd-$r!#iaAr}EroBxLL=mXFM>z?E8I*Y57Gbk2YLin>mXZdA8y_i9 z)uqF;VJTSQIi^Qt?yinxWvewW29kWQbR%9Wr*a>PueR~3U(>Ss!% zNPlGcNf+lRUu$E5qh#V}Kl-NzP5#T$dv!1w3YVqLJbNp;qji-v5Jp}tu74Rz#31Dyth`%2kT(0WepvTh@Q~xo!=;B3Exkmm; z0*&Un!PCLnPC8-(^!_R~lU*%ZdZ>o^>Ey=AhE6}v>}P`J?R1f*vCsPhhBdp55WsmF zWREc7)^jSwQOH7soOJcy(=C>(yV)xgV|KocTeUfzLu0%*Ir?6XgOjRtc|4b)VX>7f z!$05b_i8^jasKndZ1}4RR~LxBv+uT-Bpa^S?}uIhxvt!w_BgeDlOO5<{6?Ai|2*SD zd5U8Y{pp+%Wd9*`fVwA>y%_V&A7r!5_@F3(r{CrCtDSBr^w=Gm-uVN6<%kj|mm=`^ z5*;V}$xsB{*bw66ha~;A&GpnOX5bBYRvgWAPytVc+!!v-`F>#YGjAXB zB=;4QIuCx5VoN)XM3hG@u$*4E^=AWvb@?7ugt~Qk(dxxkRo9Cggzx!Ehq&p}A_VTp zbsT{<57D#VYypi#7B3D^=T@|uY_qL(g(0gmeGsii%NhM7D;7zZ|Hh*Pw9Ezp9Sui5 zVx5kR19FSQM0|eb+FSfiPq2X4rvk64I%#|Y&<8Eub9hhMG(eM!)+TX2T;wl)77XKF zygfT7ewyqLE7BT_%$F*=B-fanEY}~~{~ps?MBo7uh5Rg360t2QKMC&E8pKgsBtyMZ_Qyqdaiu5%*bcr$#qj08d;H_p5}b@Gncs`oVr+M zg_(a+T03NcnJ@fDy?At%)w|lD6Hu*{K%=|3ot8*Xxi=`U@CzYv!uMF7C<#_c1mW&c zO*q)euhwm|S<+ZlSA;35{fda2E} z5_v#EMpdW4bd@ujzUd-8mkJme19jH*tsFDR{dgVde%4Wa+#oI%8cuE^ez|uRS+dhr zb%mQJ2R|~K%E}GYl$@#Ue(P{$0bW<*b(?@U+X?%M#axrp7QfrpQ8N-zc0IG2DUe8* zACwS$OwYSbKSx(ri=T)OF?a}hN|8y-m3%Bazu%j|P1B;lc`CPWqo_F1M}!_nu=GS(TxG0!BKkz?sumvHuzYD!*;*xX8va%vf9OGSJrePZi+y?d@p z%a)97y|CXT)$^HqNZ=NLt&vxy0l<$tuDDq_1_Dax99*%e;-LDBWT`XRN| zIcI*bwy8igMVD{h5FzR3Pr*5NiT?hcoitfDe*VbH5mo(>!FnhznL^A@t}&MusXbk$ znV)UFqCO6-gvQi&B)J)QJz^Y8=2Rddl~L<`Da2Z$tQ;cXy-3e5V>l@QjOi>NzBlL; zAdJCCZTD*1B|VICX#qUmcj`!zrMKmgxmZfquL(4Y_;wt2q`IrD!{tp|N<^(s%9Hx7 zAZ7|sZ*Fi?O8Zt!EVXtmwi5XxQahy)=15AZepI&0AP}pZY0mlr{MB-ZqDZ`pKmJ*~ zY^Tz50$F|uTb{TtyzB)}iqsNt8f|+6>5o@ecXFn9YT*SAnXGQClrot`d2Twb4uoG` zIE@xwA{`w0gVH(Hw^?08V)mE{R}n{r`a=mZ+^&sbOq0P^lWT}YG3T0WU-7WMXNePp zK%;~R1HgpO#vOh5g)XErGUavk5F>r&hSj1 zm80HlCGg4pCY}6UEtM*b-8L5=j#R_Jp`?&mF!amz@{Dl|tmrQF@%i#MKJN!c15)@= zrqAqIb-FZSQBsplPQ1@ zB1fx%_GmLd{k!r&Yr|=^K@TYrj&6So6M(ulH*=<=4-8|Q?s(1gcA;=dk?XX1slqwA zU96U}^IC{zU^yRtpMF0l5&|Xt)SDeMAC3V}XSWN?Hx|%M-({WtLHhk@xh7L9VCirz zUz_7gO~k{7zd&bSPi`l&5Xk38`rcT=cUxwPRvMl#SfG46Za9gr&582ZUW}vi2cBZl zI~O7_Q1ZhjlcORQnAydA>zde)foCrURw7xz@>qw9cZlCXzEP z%H|0)%Fx2WNHeD2V>Rl1iq4M35AnoFla>F(80*GBj$q8 zI^|jopctDPJiUdK6l}zaa>ib-3lfPd^LdK`_g7*K`^{h)c~c->3k^Zp{bGTN2V;3y%M!By9hZzP4fBU-iD zk?0|t^%v;pR+|b0j;du)sCyA=FNb80g0Xo6+sl8GL4w5_&fg~|haXv-f2--^BWpL= zEx{?tIL4YA4}cOCcR%q4`{DQux&;$y{=Gd*w+@G`I^MjY{Zh*A^etzKFQc0@@|;XX zYaGQUx2^PRB<3p8oIBty?phY_ccqX*SBI#r_Y0+F6#{X(4Mk@k9eRWyaPy+n^s7_7||BOS!mOBZms?)B8|XML9I zr&ikMV3$IlLqb7SmMn8~R^*l;@qRx^Osj)dK^+RTL1)A86~%XT`<%+zS4R~ibxRD@ zNxL2IS~tm0pkZqLz%DqaR?I&+8Obx>&tAFE>-5O2G&RPPbYTq3vz**1;cWNIUk1fr zY`iu}q)bmv)eJZPd}&|#@p|KpMhuQd{HvR!+H~kUukQnX=9-uIN(R3^aX{RueEF$?_P%2e(!eR(3W!>v?lb1Zrw zxUv1Xlvs<$PC4uujo#2BaM$%sU*nzj4j9HY+YyXI5P!;i6Jmo1Y5vqo9M9c7!=C>8 zcT^!iOz;Drr?(rLw1n%Q6SS|Fi>eI8ZW5<>1cAoO1LNj+u6^Iw()#?pVyO$Bc%zV_G8S_AI;Q|p=(y%&`0_b6L!$IA=b zM8t%F7(olKAr=aWn!(LovRF2TEeH(Fxhy~36$g6J&4n-d!<6MIHSJ&ejjr^X*7iOt`r(h}vIa5dK=gNZU+pGzCed|HN7NpXX+djSN`wK-B4&4u*`#ts@o3D6 z^2?Ft$gT6K`IPZ%#?GStLz16P@2`}^l_Xn}lKnEk=W3{E;#4uGyNavr+H?3#|Bt?t zZz!J$qV8MN%W1olEcO<>lic-gYNr5wO*VzA&3)5iTuoh+?Khw~Hs)(%0);k`%h@hN zrx6J_+Er$NV{l>jE=JnH#;<|U^I%&DAvOVS7Xtw?1e}O>@#xP+!9JyM9P_tXfyt&z zdRu||`8{W}tBGi4mpe$6QWYf8uh?c1tPlCa-qZb-EF>!v^3BaBkTft+_V+Ln^va|A8k?P;mn0g>Ira5 zFKdhj@RcTp28x+Vc^;m<=Q{IY8++ssFGL`7Z`Pc}6$wyNd0rE%Lj3E1D^*CzUHWBn zo0>$|kPgr1@W&H{6-qD?QiG}q{t}D1tK!wW5go1U2)Pk$I0&Ck?pxR-MIPESQ=8*^ zFerc|_4gger4%=lrcctRv_ar2Lkd*(Mj72XyFRECYw`}H1A=jW3=8`U>?8aT9m4u_uv+%B+O z&Iha`>QS+m@R;-#4xMooVzvI|S{=Q#L!et4b98!*?xA2(=R-Q0Sr*e#lN)O;_nmUl z;ui16tWoF~c3Z74Lh;uwE!pJOV!1z|Cej2+%||X%DOs6R6$j%u zYciu9fg(>G(fEnD0YW!7x1=;pE;x6atzX=(Cr@4ieEuH@ILsz0zUj2P65PNJqL(CN zG{We@kAtHcKzg=;yY^v#^BFaXUH%TI*XdPCDlajZ{PsM-6Hp*Kl1K6r!TL4PI5Sh1 z_%V|6MkK?mLRdbds`gqt%kV{%v~2^ZN)Ai&ORnSWrI^w{e#arbz-`h_bT zb;kAP;s6qsAyu_N;`6kV9IUqy!=dYUY;)h@2QoEd>N|g6m-jWvr<@%3M?EO;lH8Et zlC784r(0$5%C*~8<(WbUu&RkLg2LC6<8Xur&17S}&w(-zweXDc<37w2Cqip@wQcM_ zf)d#rbD;kY_JR;S!h(5L6w)>!xTHc#F#O2tx@s|)=kk*7RQ z4zt5X-g%JMGdXg$5)Tn2GkImOwMs>kY2mD;$~d8DenYXfkKH609S$?%i%Huxe=a-t zy+0s~i)DuDuk+`K3{S}_W?P)21r^jrz~Iv%Who^86r_Cb4vAGlxg*k%=xU zdLdy4%GpMWZMFSh7C?(MyyKV+R=XZ&XkWH_5t8OEA96DB8R*9zPve(0Elw!UD9Xc3 zKk?jYZ}GT&!8qZtif}phH}yx#Pz-KY6Q1MAf>k2dum~b(Clk6oJDE`lE2Rs z5lm+BR4mR9*t57_@X~8kgQ3ye4n}CwDkyLIcrqFYepbU!M`YC4B*cv`JDW`n>9YKYR7K^VGaBQexaCZ9u2$Q{Oeq6!AVH8sTO%=kaXIlFUXCVBl|drl`&CKs z(LD^O>=K9$H|zS)Yg!-?ixB5ns8T~po8Hz*L}6Q|()j|julx3qKg8*@OMbECzc1_} zBp^k^naveWHITD12>I;n4qv)N;c!DJkTxyZtxby&KziD~ zhO1f^c-oU7MAL#JkHCVjG1AED1sLKOl)ltBA}&QX4OqDqn zx$JJo0rh0U)AcTnjmlgGX-AujLT|kFlD)x490s*o37B4o=WifapC_25W3l<9eh{(c zSRg?ejZ8?$PZ|w{uo7VVZ}S}{h25RROa?#SS|iU9ZVr89!;AE2E_*x9v*`_70w9xEBDQP!2EwfGwpKb_p4#vF%(JJjitAgQeZ$xB zGj-B1{ZTmI`UYiZ;gm9Tr*=;oPKPr{_~e>1de+=8nR-jJSMds-6)yxlj{f=!-VzOK zXtP&F`*=Fx>5$*$yYysz32~S>r$nQW39y*S+x_SpI-2YFrc@{a?kh0*!k|sEV%sm? zXmhWXNjxw%20wR5FIbteLh``tHwwk}SMBHXEQKl<(?m3>A6|tnQ}6z9T`ZNmTmqfy zPu*_^K9*@cN8)g;hv^LWCeDEg^4Xo+2k-u>NeNptaRe03tNWpt6RohzU30}BHTD7? zz3-XsUN%Y9vc!5BDWQ0DUdzGVbyUDe|380VnIJi%5t)jSy2V?ox z@<>lN|Ner;8=Nn}WeE9XsG_FrWiZdgBhn-AS88(<`CvBGqd%Tuil_7h%g{$0c5W~d z7u$Q~uOn2vu5U2JmgW;? zZ%7&sI-YNh#>JCYu_U4b(vh4}oBmG$jSOketF2t#PiDgJ&{z!mVg8@K!9DL@$4YDA zUk(z+EJZ;0np~=Oo2`)-nX7ma#yhhZqhgW3Rf%t>!SUCBU`{1^s*kB6-@?&pNYglO zFbO5SJ7ADR(+?tJ`>4qZ6R|bynpnIE5$Se_yi(Szw17?c5UG+z=T=nnQG~^9Rm1$ruyQidO1X!G^|E zWe7C8Z641jiD)Gf)6}R57NR21^4Waisc{29O}jWgw;RL)ZK8NsZx9OKVAXpK5g#w3 zMZbp2M?S?F%jYPjU6{WhGfYDyB2yFBjOXTH$PyHXl-U6!1 zZR;OCq;!{pv~(lgjR;61-CY7w(jna~AyU%a-QCii(%sFsxaXexj`4o~_c{i{!FKE1 z`&rL=)|zY1U$`RU>9=|gX5~?7)RPBe9fOoMfymz@cJ%nX@{zz&Hj*@lcsMqPaq;9a zGiS0L3q1ooIIrJfb|JDe2OGoYn-{eZi_D`dP5ZNloVrPZmGOCTv_xCs1w_Ny_~Ga? zV~ujy9^vOHM-tQO-%_)BFz;kKonHrPf1z2@@mOpH%JQD?r^4z&;`MiHqhM#H2U8E4 zMI=_-ZVOSP0&s5fv<80ii^8l?eFJ@r&e>lzCLE&SSbY*_cK4BE>m=ws=eUnX>lz~v zBA-!+xQ>5KT70a~L+p+?9-bowg^u5w2Rw;QpWx5MURRro(IW;aE`OIyp+c7ydz<{$ zisE#mKX1TseZKD67}cIV_7WH$d$|XM>;Eu7oq5ATFQ;DS$d@4==6_pdfrq3w^5_e| zR}_GcKIP8uwok5<_YvposcTMkfGhl?;UqKXK__Kwaxq+pu9Rp&xp(DD=r5NI!*IA}lmf5`33745Ek-bOk zbH)~mt2I|8z8U(GxH%kbnC)d25?Qiw3e&yuuN#zznX1@tZbJIAqFG&W;;i^p1{3SQ z*trqqteTG1HmmPV2fulQC^|gnI*X!HQ4*w#iDnyJ2@fL?T(EU`F}M(l)WOs};StH%8}?-mq!!SE}r?Lo%JC z+R+Zfef`tdiRdRU(sc%J^tL6+4onPm!-gqfsJ$J^+r|z#7#V9@uKWVFwpO;kyTf97 zym)%A(#0Nke~%a@c>r2ksKj+4Ez?9#YA z%lf_6E*=8<*?-kY;ATmGmwxSbyU%60+%%#qua#l;n){0;JPHZ{U-9lc!)Kv5-R=dL z()Y1&GP~1l_iqNCi=)xxvPjeRxTSUv6oEfTg&LjFUW8|{d`Kkr#vop3bjJ-}GE(=jF0kyv7}6rLE9!ERvNKALYP(iuTSBoUF;33ipSQfsT0RT$eaYSv9+wQ_O* zRDz(Lwr-ujI#Ql*ynO4hz2& z;DP*mpQ~`b5n0y#3u&1asg{{MnIjL#bloEv0{(+hrsOSD_~ zPaatHR)bqvW_P!n5>flq<>E`Alcrg}>pzLlZqT2&8dbE7ix#VqOhS0X!FK#iQO|t@9>GAZ*zm)yo6(mDAM661LllO1IP8ZVwChAGJ!dj zke>(qo(C3vZ$e-I*n7i+#*N8r4heGQvoYQZNKMgQ!Vbn4X@|^|>9?hev+WDGVabz< z36HhI#98HxXnE0nW63b<_yX&J1-}cD+&9=0d-vG`G|ovgx2;hI#t%%lslOsH>eI?L zhr@khiOU}V?d2qDqQ{3L)!FFKo)VP_!DH{sY(1NHCl|DMx+ zE|4ib{x|Q51tC5y5&Yns#rxMAUg!|$0R#dL>h9{*hPD&MhpDf{`jWf>Y@pQq~Fs74EloEoNsQ!ZnZlp7P%{h0C}?PxpUyKdxv^-!TU~#F)9nR@qJg< zbAFilatFR<#o2tU8VryT#X8%aq@~lT5PD5SD~|N}Iuk}An+c1n*ZXLxrKfTh@px`g zt15=Zh2`_k@rw+xuzU+u%&bsC7C|nw%C*&1Z-DJt9exPd%>?6@Z^_)PkDyU&`kl|y zJFjAM^(=ugkdQtJ!yTjvf*h5H4=JCcW-3wdkY5H_sfBw#>#x_?Ty9)vLZIE;dd&4E69D5iVe?8 zh-^B3%}8ukPXF&od0&L=*1hljye&ccf*smhD9$R{ivwafLbxZcbt~()Bk1UyoF8{q z)*&A6cfGILTrAYn!hS2Y96@SvpboG%r0P+E8p%%k?bNuci%E6YGN)TZ1}hR#Nb8&T zP+JU|O5SOmHpFjSRa`60=Xxb5zTC=tty89!x!f^yaXSQWY|o|BXNU$N4MqGae@Etv zC=9Ql-{UWGk^kJ1jxScvITOi#7YCX8XqpX~YvvJqLI%4&kWiAyWkW*va3`vTYL&zx z9&V|oJmqTdfwx`|>47zHG%%_V;}bio|L*&Xf7Z|cETsSZ;%5t)#_uU!`)L)8O$sYS zGBD;1s20}OukBy2UM#M#-kbver4Dc=h#e&Z6~_8oQs^M`4j%kq8!?3>&+Bb(a4rav z9GpyG{u+VTwq`$S(=#ye-pIMkP}(Dmi>YPWxjPJVKEt}Rm=t476n}G{Bl`()EmI_&OGt56`hJ225wJm@XMcpWZ`6~f@HTOukXRhsMt^>>o`|NIl~ zFUaN_dHyfXxq=F}9%u#v!F432dzWi3#&mQzE;Fw;iLQ@NG7-+n)rQ<@^%f&Y`2i4# z|K+t$=mS;rNlg9qk-!_#v0!R};2DwP7X||UTsld%X)Ln0@{lV(kx69aA~A%Ky7c~M z3;Ji|{=Fmp^Aeg50ztv&JC`f@KRNaP^XopZf-j*#i|wW38rAa(`Cos0y#IosZu=`$ z>yIDr2L~p&9~`S~5T@takE{Pzx zRk|iQ|NXO{6Fe_)O(d<71f>7xr2O~L3Lc~VAb#UqTcP@=kB6A26chq*u0XOsk3Plo zN`UF?`2G*WM6P=V?o*iyrmfc>uc=M!c}Ph|JpMSOmZ{+CtF1}GBmQvfC5dO?z}&Ok zo@M^iIC+I({vht^M($jV`e!!&ugUqJm(WDdvowMaC_VjQOiQi6I014tC-)!zA-MPC z;NCN}n@s<4oY-Z&e6W()QC~>>Y4Fifo*xp~+x_G}jZCh!}q6; z_Zq@rLd%-jr{ZGzFk=EZlM6eKAS+2kE{i2C!?Vudi4 zgg1sN{kv26-!3uvc_4<8{Gt9l5Z2EFQ3Eq0@W+8D0{5Xyg}%e~&)<~i`5{<@Civ4V zi1Z434l0h^q4(#Y0?$F0VF@7q_)V>zgR&pA%l|Rx%wNybuoaE~@{d7fo`X^hwF~_@ z=<}*>*@i#>^~a#}&p~mD+L`|x6#6-6I}!o(AA=%42Zar5C;4+w*yo@fCQ^1|511x+&cb@#mlj&q2E|2>$O(>)&gzSJ89ODZ2KP|18S? z*Do_j&q2Gf2;lzsO~ampb|bZ~{$H{F^Y=3-&p~@|2>v;L{O6tj{fn2?bI|Jjwz2>H z&j0VZnL&FF+KWek@W*c|^BnZ&U|ZXtgJL`f?R!Ol_{X61&q3o0+sghN6ze%?KLG*K zAA=%42lWqaOaCuHuOnK4WYX&Xz7HHa=?}NBc7a3!-a;a$i(MhOQ4})fN`-O|=%nIG z%bqu>WU9tA0qz(Uc7AAOSNMoX#(pTeKC@$G;Az}gSy96Zcc#kt667< zy)&L8QCDvCd22(!N60=_r%|WHBh2>&%35Z?3s6b_T4^@E1G||Jmc8awax~Lqf(m52 zgHpKcllby%mYemSn%$kxuZcDW5^!M^^w7_7N&RA|CcSLTC%l-&GA;=vcvp5^ZFpB4Een+*6s5)pRu=^ zoPhg3$7bBd<|nv}@3UcVph?ByA|#_oNzG$>1JUVONFNp=b^FQ+MgAv$NdNZNR$2ON zeampz*=nht$@e$Uch=7sa=zMHWV)D7uEgUtaQeie{J?22zInkN)dsY_nLf4ZR$5KN z@;Dxf=3%^f?jF=OG-Qh0$)cf)0)9rR`yKnn;5S5C)gq?W3*eK3MXQcvv+U7YcV-ev zB~Kc|35rLdyOZYWzyb(#ZPAxnJVTK2IfzvXKjuH)-ykv>pL4!7l|u!R9{vFVFC6z5 z{6DR>-H=% zHe9p<4;{H`O||9aX~EnM1WN9zs;U!3(|Y`Uz!F``Y?t;^$fR=V86)hj^TN^?%)JcuV|J_owIQ$#a2@Uy6eM z@Q819^=5X>;3M-j{4;9sL|-C@>CLrF8~T5qHfT)HQ}cyy4EsEAQyPZn)A9G|qcpK~ zXWRshT7i6HC|Tn5c+Cfa3s3Y^x7&00uLwBpGq&q;O<&j+8k|sp*j-1u$Xyhv5kjFx z4Ph8QhXN_&K|^K_$}7W7U={=?n`+kv3e9fV6rcA;(E$nokIS5#-1i+2D;h1*P@S-m zBLcK zT(9=!U#b8QEgZU_KP$i#xNW-85C#gT}@f%9ftM+fGc-~_=D?WWP6 zG8U8PF_cfFYULZoW{XX(sNn1R0^A{#P(KhuEwrW$lxaVt1L=A2*B|$4VMl3?(72E& z>kUS5Oc()@0MAbW2g-BOiQg#SffopHpB@PiLVFdTyFmg7%s)@31#fuS!oobTZsj-n ze-L%)L|_vdLO>*AWr5*_`Jhw3{vh$;{`w>hCg-F;>iT#UjmP*ixeOL6Sk20IXS|B< z+tx9)>pbDMjc2vdFeLF9aX^<4$B(a^_J6WfI1f+&gKa^!G=fe+oezG)iSqY*7VvbM zrD)0QR_))LTt6M|b8&J`bc7{Oqw#(DJgEe<4@UvB^sU9x;19ERzTcUB`QjOMe0~{8 z6&#V@Nsd#{mzrPLU3l8RRA}~i2u9jrHCVi5qf*E!<#s&H>Z^4sPhEC?ky zwXu*|+IeTt=Ih2(#W+KY!Ew(rviQZddIV2B>VGT z`L{Mp2&jZhV&LMD{R?djZiLIb-&!wV0WVjtoGr@EK=j2zVzF?5_#mFL`B*TAb@HJ& z#U&1{dwg8PNTSa3358TNRG0ZDV1i}XW*Wo#Jo93ztkf2$X<=VNXkcZ5X13v`i3Eh8 z*HJvgUr{p8&xe-){HLPnv=!%n)e51>AcoU?(fJ!tFrV)mrm+fT-&WpH^-rQVh6{-2 znSMw-wy|EI7v33UclOw#f+!yvM%^AeXcqG#nd*#;~HE4dbeC3>Q6b!<6voh0zes_5wK_nre3G@ay zN*T23N!{x|Zy(Ie>y{>6Z~Xd=NORT;Agc1s!eZwK;}Y;-H(|6=i97{MC04HvoJ2UG zX#M9MrG^5P;&y*z{Nt;smazg8&|i#&1O7bSH;A~vQ$bBBPaWoDt?LXs5rB(_86EOJ zCo<{Lfkxif1V)_7ee ze$Fwre7;cyblR18K+3hfS3VP+M}@A!Czd(0X9X+?G``^~3fa;j$_4T3U_<>_V-1zW zX5*vPa7io?z7N#gVFCPWomL%G$S?M$?h1+`4LeF%R6rvK+%A>k#!-jwZZ$|+mm9Os zdl3?(<{t7t1)o+daJO8vA_Z5_R_>`j)y~-!xP4EmMtPvBcAI<^9_A4nX;4tguaJzH zwcvUVHXYYi1|fnhS?hp6714A|gD)=bJsqApD_wg|f%rVI03M66!TvLty*KK`mjI;! zNEUdP(~Y3p7L~Q0h>{RGb4x!U>$K8BB!EVu-?>~qa&@$fPU3T88ViK2RPeb-#e&Z@ z9um2)=WA@de_4B>PISMDwb)qpd}6~>Zuf&nXERsA$Img@x z`qz`~El6H!eDUi1NC57i^{v_gUp(S<2y2ek=cdcUgFxt$^$xSrm_t?<)I#kdSQ_R0 z+`9#{QQb!88;rB9f8k<~p{c>8bo4|J?p|+?84xRU22yD^#un?`xOLnjCvw<8pb*YQ z{Jq6d++H2|e%=|^du+VvjU*wX`0&k-R<(G$ThAl`F9>sf=aC&JtI_4`6@WCVE`La4 z#s(b8w%RfS=Fc-s69uXqXnnAj<3F9Z2BRyd;4$g`kc~WD>q6x9eAMK)Cg8Hu9VMm|g(D)&6p#4j&fpU(7J|D1 zoL3Y1EEsktOMJnmpTD;SGOFFPX&dc3)AtswvBXC0enH0bf_4woTCXwgEoB;9ts8x~#qg4XToRQMaq@6k*XRILr^gS+QU7RWntx=tyJ z2_G!fVH$RL#{xSsl6PyJreoz_Bg$U$f5t1AE)?rQIbd?!hb~+$RiO-w%KfQUVWfzU z@7HsnQRB{6qm-veA|9Gp>vTkz@_{S!-8jWAff4IhOMNC~yUjuG!Eda0F5ljfkCYn? zWJr#Y<{tu_ztY5%xhgll%{0$P?@uR1v9vlkfOe~@ zEGjzj!-K50{`=(X)2rp=NDdwCkZxndxQ)32g=}tMSH5ootz^+nE1b$|GJO3-5~#bN zgH_HViB01Qz_?~wJX=bv#DWN3Di^reoJW!3Cj$XA3)`o$Oo{PDjd%jA2_!@52FC-R zEXMPqSVkQ}AR1S`f#p`TzP}GyXRb;~ z$#A~Aq`y28&@C?kgwY@1-~hWUlgfgv)8gLY1@YicPyv*1HJjbUtn64-4SnZ{JS%@` zA(ltwtJ+9#rt!ktCui}yU3*!o*{|)_jqehK4iu=Cd|K;-PvP{yAd^6mILBjlGum1< zDa;c$V$}h=?@+kR6P^p@T8IewIa!A za%$_v#-OGK#~&Ju5^TIT4D#)wlHX|JZZ(!rL7wyjzkZ=)u2Jt{Zn8JAkI?1x)#Gq4 zPun67zh}Yk8N~iBy`lh$c2TT1qt5p2&4>H^;ed2Ss^}D^a!!en(txd1?(ZkdP}B zrS`qb;s9;U)yCQF$s8h5jpIApqwl;4%{SXL){V82DKk#Yo*&atpDrVy@&8Ui;V>Y# zMsx%Z)E$^i4(U>Jg+d4~wolv_@ziU~!`j7ye~1KJ?p7RWFOOAea4fVqp=vxX`2YwI zbyVOWZ3s4_51^`vc(l~m%)`G3NCKw-KA`gnG0nPk)O>ULTL@6PqWClz_7`gq!RX1S zF>2o@e96(SGl!Y0+VcX4$(>Gy;^N|5jT{K;g+_lB`uW@|GwLGs8qu&xRT$CgpSUr-F!S2Pw~j{2Iy*k{x(~E`g`Q60nfz^ z4WpDz2;qTB$kfdddj+g!FIOaIiJuP{*TiTO7EN#eE~E*r0NfVW@l5&eQZcZcl^WS7 znhb31Fw&f7jz$OzAfyF(3$+3+<5tNR8z1`U>BpMk>6?3G2e+mD9nXT-7N{O4n|!>y z0vc{J>0}Zsn~p<<4}b`isr~v0xrn5x(HYqPuv>M4Q~aoBB<5Oo$kTkz`SlnXkPSeY z^$14tXb=*36^PD9v%eOwXbIo#6PqrQI$EuzQ87V>oz?5_?do)t{^aFhZjfhrxILR$ zGwaBx)$9fMY)p23PS68@(z;fWLm7-ipZ{3A{DXgUL<0^tVZ1kqjTHfh4xGB|GbE$h zX=w6e0ltUW>{nL34CQSq07FY!A?Q@QQNLn04Q0^c$yCaV&hH1ubY_nQ(Puv{P+$;w zbo&}fuBOlHy7tgUoASG`%6vpJ+Kbz z_P9bS-jFbK9`}K%01^@Qip>*Vu+q21(|*Jrur0nqFA!8>=iJR_ZO;$3RfgWS-I>t zybB5t_c7*$zNeuQ@+ys-TTBh6Is=d|@O#B(K`fiXnQwK&7X>#Q?b5lp_!{K6 zifMOOFYoqeS=}B^CtIZj9`C$ik@3^ReW8-xTJLxGv1rp<#E7~BI|6b*{4|pLU{Gqk zXr6j~H2rXk4L(Q^km-&$`dR{U=<5%83+uEki;CIKfEmTo+QQA5^W*+YUS7U9Dr&2w z%HAlx22}67x--pYL*{3g!1r)>639p+Px|iI9oE&y?$>~n+?`qXGP%!Gx5Cu$ij$aL_4Nix-&CyR-m7%Ge*o@lz zJ)wDu6IX!yAa=-GhtA*5h<>&%fr`$hU`Q^TgmtM_zT3%|lbXtGKBH?0WUu$LSKLmq zHW{@c?+VpUPC6twFPuaxx5t=Gx8byKN?a;TR?jFu0Cn~cWg)oBci*E)mtW7+NL)D` za66n_ZOZf}QnNNTyW~-w81={XWCoyu9pc^nShH_Qf)UsR=I8hZPX4Y?T$6uV972wx zQ5GrDUK}fMV$}Nj0^p;-F`m=9054AJ&0Se;T;=2yHD#qvgO8s;uTiZ#Gpbkn>BJ}BX}ud6 zlq_L#MpD{S=ba{8Q|B*ecbmjmwts#|=o`7fRP@0*cs({(ZP_ME;7jrhTpNuz9pLxg zk%+n)lG&Ty^`T6xX9OAn!Qe&a`zyjmD>`zt=wrJj#`AKHuKgA9g>gYLxl_iOt;XhVP(UQ5JUo#iiX^k5} zNvCi!mmBp3D+xfs!W_*)dmNQVkhuFJ^?n<8y1JTphdEj)_FlmE5&CiV-UC(LD|e<0 z%G1WLGyy52&TgwqAc9C_YO7+4sm1v5&cwt8@s=H%NF3zmpWBM*Y`W@`o*u5CC?kj@ zzBk^W^ND|!PUC(llUyTA+91lgw;OEo;YsWwsjA50Ez(5up(CyKrA z19-H{n{iMlFyo)mmeVdFae2I-@79GPNAr5t4g!|n*d{=FP~hpYV17K3SIrKqH|+yV z+euOH(Kc`|i=@WKb`AXc(1rXCrRKJT zi8VxQOWdSVB1Et~H?03^WVp}FTC6tUQTQnx6uN`Vaoham;uUZV6W@z3x+h2v2%w}0 z!}pEOexGUSa+Dj`{d=*&=_8W~PO)~K4@S0Breo?C$;4isimtJafKt7KS5@E2{Y9)| zfs}@OGZ3W)vVC&XNT@<$Oc~A$W)ZB%FEwlK)Y?K1l z6@K)GRNft^)vt)SW!8(_p+o}1Jx=f#6vBY>L-GwH7>faj50sN>H`eAa#Zt$hGe=)h z41)zYU2Qxb%y`wG$g{Qk0LBE!!)tSs1yq-;bJuYL3FusQhDrt6Ky2KxyVV;i4zE*b z3^yyVL;vjOP`x?8k92?*2t{>UF}PXOl^q z$o-fONqRr1Pp-yqI38&k%b-z=^y?>ED*b!*5J~pev%MwQR%@voHVmDiJE_d;cM(TY zOj%Fg+`hL6dYtd?99Z%@T@rlfb$3$TgP5?U{K_NL7L0%vrNdK#_nON+}wQr6j%CrF3jrZ^`sUc>S z03Pn1pZe_uR9Ktui(PKCDDe}Ft|*4obiOWs{eg)*g=DO_UN&x%OX-b~BSl{Ft8mda zWGbQH<64J398jw9Zu5oJyFLGg$73Bjcg$`vWm%|MCVb&^(+?w=wE#*V89FV^2$_va zPDfK(%u99lIT0q_hECDzsD#|6#OiZZ_LRVoI{&+dfe$HwmG$nSWIQfA zzgr%+Yq)xo;(I>BW3@d$8diZ z8W$?fqGHhxIA8J^Sv7&OI+3L4r6wauMHW(>Qtg6%stV-qRY1-bt6L;;H;mR6ejI{E z67AjFlTYQ$clrl9gEnUXPmN81=X*yqHPc`HYcOXgs}DS%j}~!>_!~Ps z1w3+Z4C5_l<;#_*KU+`Z7*NQtKP?D&AoWDNW~P;llF7>SM+W;--dOHC#n0yRu;C9c zwh5xvdqPFW^t*tDYe`_yszB3gR4ECY zx{PR67}En8FJxAeK{>T8ZpZDcUAz*mnYpUd^&V6mm-q3wYBsaY>oyk*3N701m8N5w zFk&YI-M3rZfX3b#jy*t!Dx)i)*ZvVu2{EBwpeXExypLy)KQf-oS5aNNy?i}aa1{%5 z*r}MCsaGQ#d0O1>P)xK&@-2bz$!pQ`ZRRLIpPaOsO=|Md=k57Wms@8R7yR2dgU9nq zNGP~v?1pnR>FUG5iq~=G^%j!#Qmyx8k;YnX#f?Ki@^ne2d$LON6!T<_rJY8V8_Q^g1Nu$Me4 zFvn$p5w!6xrp#kq{H@h5Xf_KKjs^;JJZYn1xm-DB0?t}h7+Lu3j3V!E8UmMlcV2`M zwytm9#|nc^>gW$WU%>+@%-4OdJ_DqzjB%cJtuD#oQbSI66t5bKgFphKs>)Uc+yq3q zEd~>*?t#t0YNo`et3xfrf!p_9r`uy>n)dc0;8Y<0Gq$E=T$9Uj1I-_aVB7rx=sywE z*`*sLS9>?xE;DvqZ7&E7jVBacqQI?ayyX4CC>2ZNE2W%&t30`JRbH%FZ>mS9R)??? zdg*SdS%agTKYea5lJC*MsM9Feq|R1q@kCNZ@;Hz%vOSy4ihxBE%6=gI0_}XdRfd2Z z-ylckdscH0HZ4W{#i6fMoO|#+RK9>7qgq>mQUMCQzQfL%Sk)8Rk6_KTz3IZX!W+aQ z^ItPRwRkE;#@619X1O31%rPsgJ$;Wldef_1Q2km7$JvFkNInnJcrdl#9wR#hr|opo zB8uBe-BPm!g~O({%`CU3Wu)YkXZrh8HC&bXWS;M2XyTYH9w9eC(l)I)_VgNQ+a9Ix z^8V~j-<C+QG=fnldg2&;$+WFy>7zZvwuRZ+Uh+@ms%#H+nZ^6)$)mX$@ z!-wuCLy^NMlCB70A*sK#4gO7!nlNtZZ|evkMuf+Zp*F9~4a8x~KSZ-7H5s-nA!Sh~ zmHftP?>{#Skwg^v`}mtWc@1{soRP?}5=Gyl=;?TIH7VW#DyX{m+w$Hl)IonYX|$U5DSx1;3+Y7uDoM*^fCLgB zS4#27>!9XrUt6~bj#K<%C>W_NKuM3L{WnPAY)?CF7mW?gav}_L3Uyk>B$C0AcTB9R z(Qyb_nMPI72W>WR?5B)IEQ2xzy?V9aZ>czD!)-LM@(fDggZ7HbgH+Zd;8?G>di$cC zNGDG%tufZ@O*4D8K}tWJeON3jFXIMjtvQ+GFT*}!d}L8LikAv>=viizI^5Nyd(ff1C`_-_IO4w=4x$0H8IJLECBUoAaRz^ z%MKu9&1}67y=@qE&we$n0v;X78Xg}*;jhnX!E+nLpeISHF4j*L%Y zGOQ^XNz7kuIqTmh0-NrB=Lox=5Vkd$Kcy5dB124yz9=d^QK`myezg2SRj1(*m53|w zd`BikL)6P27-oX1tGLs`pc?CEHIfYx3n1vpj8^szGzun-Y0)t(7wfUv%qQOVrkwEj zV0~Kv66Ls{cig^7kN;dGcF>Mq&GBgRrx26&ZWAo0ud<%R0ctD$q3`zd(%wm88uZRc z&#LjGN(luoWMX7*gPkF+C|7e90S8e*^ds3?f#;*kzJZ=S;L_r;ej&i2*Y*m=M()Z1 zEpMUxSZa5}^S*CnIsN_mn&)Y3r17*GKO2M3X_K?b8+>BnF)4B_>5Gd^$_#f%{hp}F zv6)xF?Uvikfs&d_*q2+ZcMxevyGjh)B>$og#3$X(4}czkOfoxdS%xO#YaT~Iuth5I zJ@Fen+*QzAT>vS>vWugl-FlVwberW*zjxVcIUA^=-j8VekI8^Sc#en0hSLwT7~@Z` z_Or^RkqCJw_9=v)!WnZTDn1k50igh(8c8^rucW9iSZ59Dw14q5h#sHbh9B_MkVtJ% z8%le^)?M({JqcoeW*Sc;oWQc_XKgx<=q0GW<%rqgYSk3tHH8|>bMYl|BsZU|q zhMPStxnAdDm@YIs3=k_^P7dJ4U3Y2v$3D1T>2}ObnogBtlZu6gUc+PN^BaY`ba#mb znPsQVl&$|T{8qj_)5Swtry_+-o%J0e8eNRmPI}oJ%3YKmQ%I_1iBEZh&t8nB9Eb&O zJi6TtzXmnDuQ>sfps^OXwAhd#`vA)=f13_<7dPs*+4vR6z_x$jCz5N@cOl^QkaAZk zQE|XxP*4)PU8=CaeZ^+w4^l1?i|TzGc!l;;H_qIn_m_X8Wp!VB1E(p2t?)&D6pW~M zziHx5u1^F^C(El4gh}jYfPY7x?o0J}jCCln#6qLrqs`->D#}cD<3*tR}ObY4Fl-aWhCUVxz zb2G)b>+blFH;rQC{Ce$%4zEy9*qCj9iC)O=CWKv#Xh2hMvWJ>qR1&{FtudU%W)3!- zh_idRbvWOheP3kNcfsP)k41E(ug-(9-^n>&LSTQ>Z&WZ}ZZr=wHKVCHqBqn{pQ~A1 zDHEaqpg^^>t-r25>@X8QP(5<_wqj)k){2&wAQAD&!Z?5AbV5-nUWP8Q(V1+}p4#V< z%l_hkjsCX69mlXQX=s@r|0%^)mk3i~nO-dNSA!}McB~X_`Qvnkk$t7*%^ki{(QjEH zsZltEw+)svrSevDL`IKC)(#d)3XLl-)ijkxi-FwxR%6E)(^wBSy(?#g3 zmW9dI#XnstTkp(c@&!x@OyP~djhrK9b)B~$f z>~h^@_0eL<)NAYIMtJxXHrw4aseQc=u}do@dY$gwyTNPCP7{_~8zOApDvgn)-K)Ff zRgr#5GDthcH$O^Lm#_UNZYt=tSqT(p$aQz_CBMVas+Rb;Zw^u^)CPXRdA!>Q!bpAJ zYGs0Jf{j$E7V{JKZXq;J{k8!e1BUwX#+}(=a)-6v=_>p*dEj22HlC&OG8pBb&ARL| z7$M~rfQJra;0boC7tJM4G65XkYkI6g)#hZU!s)GDOMkS{`zVeN+MOYLso27_5rhKm zfJcu-^RbsyD0qId0B`rLpqK#~NeG+*`E7<})_`G}n332^0T-Ihq3_x3$=Hl)Qq+!j z7rW^mouCUDuoFYML+Ts)ieJe{4t=$^R-P=fMVCY=S7}x^G^Qs)Sw6R5G8g`xgn)i2 zruc_MKWKQ2)(PjSLd|ecRxE(YL5R!GrJ5;EoXq+TwaaE1N}IsA15K^1t^Kjy8U1p9 zE}i|fYH#8tC@iXedkOxVHxMJv?Ij2H0N!VLin}niT0OF`>oM&8aa8^=@8e0V0D@wy zF0<{bXue8SK3^5c*plLdA}8jMdUZ9`g+*mOuB#v3 ztSGb`ck5Dxt~ZbY-4+) z_EG=nmFrRW676O9Yit--7;IM}KBHo_V?KNhA?WZhDWW&<{!XB~PL16+oec&sOlVZPMcmGQD%$ z`32+b>Y53v8L&fVQ0Bl_Z_UYvlftDI(Ko6b00#7BBm=wh7CNWc5#&UuSB_g5A+kmV z8rjQxf5D=RLWsg~uU4IMap|pz0_>j-K2g4=-0A5`x`^p7QA*XpwX1i8gflHpC9u_c z5DpJtkgF^dfE9Z(P>uEPBaAt|%&doYTC>lVYs(0nK?~oX6@ZZah$iwEM3I(;>qL?2 z3#)nY61k3c3Io@(!y+v5*IZvD6c|r0nnjDzGpyw`KfJfMQM1#2N7N5i4cUP_d5uQj6IZ#>?!Rz-SKRi#hO^<&V z{zj!z5CD--f4SHX`Z<&&20>_>=7|_7?4{Nv6(RQf;x2S#p!Q#R&;&Ut_EE zESL@aDev!bNZ(I=I9tEH*gH|c zl$4b+yx-hEPGQqhjJE;o5)kvc%+~*0yYn(3*ZaL$h?H0mgQ^EI{{`vp0ZacZ>zDW6;^MnXixWnbH!Pe zE2Ttift>u*53^s{F``2OS45?sylcpzXjJljAcozU%;u27APNc$T;;yWJS`@b2nx}A zcUKi$EvO}OO>5K(!eBL2AD~mp5}a@EQ>`QbXI5Pi(b`J2LT7k4TuPMTR4!jd%5V$a zmy@2bE8X=Ch-B5}7ZxJ&jfU@HykaAjX;&s}yt=-%W%Zz*tQ$Oi=fh(e6`L9oz-9D~ z5_$2Ch=ALv3oKPa? zH>fJN;W~J{E!Wge{HL@~>5WjA`|;_nYb3Tztqr3GgEoPd>v{Y_PpN$IT#bQguX*F` z!JGZLDv6DBk&m37gw{*fFxdm~m@ITOS%ruizGo&Q`mK?AKkDH_#FMHl!^nd$LxiOg z4j08H{g!{oKD_uL+82GwSFOK;LCum?Wwi`Z#m^ENBY*RIV0pA6A_l8AQaQCNpSNV1 z?gQO1YAk1I^S6OnxeFG$jTi*y{E563b`K2F_Ks2#UV`Zot*=@QD8iQQr za$L>D;y{%PIIXjxtsDiQ7aJUp_i&Ex#aTSPz0Vdl@yZ{5vTxKt}{)jRb`=m zn|1?JnjLznUff}w$VTzv1^-SW-pkIQm_S^P;&Ux6o{*+*p3f()a6&GBpaC@S#mglu z1ebx-B^WCyNobgW%ZMKBHF37-7-`Zk&Y+N2?AD=4>}+o_@&N2>9UviU?YG#2aTys5 z3Z*Xs@*BvScTf*LoMm*dNld2Id}29@W0gSh<;8RF zVV)3REJ@&k9d@mjfK1t9)c)}~FB*22jUag-fzkKsEkr*6ImOjw!1X#a+G+NN%NS*q zEb8ADzfruthdCQ7G-J*BkRZ#jHxsme`lK)B8UM80;7L@VQX)Lfp!J)d#pox(*swjx!M)+RMK)cAxACziw*5d>12=(?!TM*8U^-VnxY;qPA@TAAj0 z3nL&--d*mJoTx`*7=c`bOsl8YVJMmPee5WxZG~C$xk|{#jJ?Pz)WP+SjB88W+AHa* z8@lnIHqCG8pLW21+nJ9&aI*5qCtqeZHaDy*sa7-AprMKus+&^6@3O|J^5R8@!-6xH z|9ZX4`WF&UeRnCZ7RGYpq2N+BlGAc7#V{1*M!nDhk~^SOq! zBhXiG5>C39k_DiMUlMSw&eVmR7m4HyC-NE8Q$>GruhadWa80uQK|rrHay0|P*i81L zI@x&5NZM2I9%z9N{0xIbLGI~7G?5vG`aO~krB!M(LRdG#{dwPyW-{Nxpw;~qdl>*4 z7a2M!9>m~8yq%zliHmdfSv&}rqz&JGaU zUPYp3KC2A&+21*j#F)HEQ$8Tz&QLPbN+nqKrB=+2KRQI*8tzZ>vA|bkHhORhJvkft zWk3Ckz1m=BF?Y$6T!2z-4O|)06#IiFte&m_rF065vS1wfM*{X<7)3r4GQD;`oarz5 zR?R&N;wTAM?%qBydWr?r*CyQ)eTn=Q;nzDyg@|D<`fho{W*1F{GCK!9Jnc0Vy2L(R zz}+`&J>i^EsR&BZ4F@GV5v@jC5$R8mVp1E1v&Vlj_>|;5m-v^$$A!7BGN>#imOA< z!VO{+yB0Un%TZK#402(hqAT|DD@z_ybDm&l(lPSKjRrwTF6pGiJyd~(8}yGk+I&iR z#$-ep;}jpFQBU1&&V1h?ziHsMxK$$H`GV!^kJ3}XQF3w!)=ow>1R4B^uLCRT(dV4N zeI2+8btO&GiXngX#$O~oMpa9(42A1C$&`4bC-V6;I|SG84ipYbxt;5Oz23v$9oq#jr=lTdFG{lk~Yam4|ZEW$&YimewNqj|ISq7);%Rc@hhe%he^BovJCpd^KSc zy4Rv9q&WW*U}_qe@_yx7k2N=ueYxCa*rfrPy7`7_EWN4<p(pgPs%!1UEr9L$TABRM=PNm|5Cu37ZmP+ zGP54W`KG&Ov8BuP%}u&!AI2~Kka2ttbJ7)@8fI&t#m5H9M}EK^#o*rWB$3x8_%HYK zdCFt2mDHpv^I-0wu7QNCzY^)Rp;O(%Pcq+A2Qr<+@-;BroW1eFT0c`b^#GtvNKsA< z7g2=0IAN5lH?5t+#n^MRo(ME&SD6yw8Si3@fk`AB=m}B}$)>RbuRTj&UlG^AWDXrg zc3rOor2MF;C{qIybz7+x9dz`)w+=68&N#0e#1H1GvLk0>ZBdY4u|Rtu;)>7S?@ybQ zS}YF#6{+9%qI;g*dchCWHdpUmD6Bt22*Uuh9331yKTXOukrVJ_0S$8k4r^^z({PMX zrEcO+AwQMaubrCRU?Ry(9N!_OaJwL^?oFEs)p>Tj06rTr8~USbtyJz5WTj;oC{Am4 zkzR4aU*54h90v$IiB|li7h;OBEkCv2Y@WLUqD7|5OF~|Dz^G|7H@%3;W&!kBlsG74 z>=N$QHu4OPuXM=U0)%{FgLiuaSINo%`-=_%P7o9pg_L7kTe|@4I=A%1csK<<1P4ZU zVFn(UaA02^B$1NJzO zxQsZ&vHZl@t~G~}aWqxrQmLsa@-0G8v2<#{8sb*J-S6a;ZZ`(;SNQLn^hxW(2RzZ8 z>&;4XB+2cSd5X-=y}J7gWtc!I3o|aZNFFq)7EJ)NHj2jb~p z#QoSD{D$mymFhM4Q~JBl!yT%AWr6HB-)=Usbm6ZXPtw&}0|~0F0v^qefTm?oh?VQ! zml9HBpkE%IJ+kRMB$hnoD0y?@(oafIj2;_|aaZ9X;#X+<9&5TOIW){tIRN!FaJj4# z%`2JexhkBC_zTTPATiKTA)x%+jVKJCPs)+Y;gmccxC~ibAQem~<7V z&dUJT+~d&?9tX<}_zt_%5s;FrC(z%{9S<1=@$A_xvkIm>am1s-=yZ4NB4s#)eEcNi zdGi)3+&q~{?)G;urSaDNy^LrDyKr$7qR=Dz#|5pCH%&v>Y@2eji zu~?L4UAR+E$W{yK=<)|UG(!|h;;&XwnzVF=*eLtU0V`}4zj;E$N`RwqSA|JShG&}g z$0qBhNLQ_9H~7^3dA&iuplfDZjKPZ(h%_-FIApaqKVp-rc2_P_=cyE{Q*c~a6Dn3+ zuA8KOPq#6+!(9LRRs7m`D3K;O>0LBM*ReO$=y>1D?EYAxqI_k)(U1+42qHe=asLbS zYQ0RV5yi1)HAJm8?Ev z=zc-%4swlYv2{-^Z=0C&0G8}S=V9V8QU0vf@H_?&3eO>%tPz9l0Ra`!kD;t&0j!Z!D6LCmje{FDUq<%&=Y^*X<9cWL7cQtmm}OVQ@6^0wBEKTN(wkxr3wSFR+ao z%?SZ09_u@NYLGE^O<;86Af=T=K!8K8PEBEGa@Z9Y$;!kEcOU{B1jAb9U{BCwrI%No zjSbpPJ6>i%38^YVah{ctk&&&%+d%{Cj=ddHLM7xqqIVG=09{R$Xlha@?lh zj*gzJe8&PWway;lEjJ5=UX`?77&aLF4j1SC-rM*ipGblH6S+-$tL?$AZ>}T-{9x1f zO&n;P=&YY1uj>zH`!1+N2jl2!qvTS4G!Vir;D4Z^Q)|6DXLW;c+#xV098x^|GHUsC zrdOkK0o!2n_v3cS45tY498$#b5y#rl`0)~pML!4Fqf06@*l|V74`4r8ad=cLCT(g$Z{ZJ0aIn3!n)z+=xnQo!JxpS`$PQyNC%R06rRErn65@}A8djJOl1)R4 z(IqDkdJ-?^6UFo(Z!F*Y6z-Bpp(pLnrSio4XkC%a9|D6HEk1jbf@1c7@xN{x8pf1h zqe~8_U-ETmI<2ZsVuvWp28klqUNAKI)0kh5@L?x6hi^W_@ib6cxsY68<&iAP{2(vb z_B%c;)Q9JmLe~tv9cJ#_^GIa z1m=g1KH0o-d}RUKi(aIwqs_39MCMM58_PQc1ZgJf)%UPT55AhEE6xv`2OeB%4^ z{&(#MgrkeR|6U?@a{_1eyNYGraT;mJbJl`C?JTOJrI5}pd(!#21Dt#TQYJDyJXudh zpV^OgbCOPUw$Ueh{{Fmx9(Wuku`6Et#}Fo%^dmE@_UB?H zs&cF0^O-VDW#oB$mkz)b!>vC(K4LU~4L@?;T@jR?XTdiaLVP`S%PC4BC-kHvf*hJ< zl{zoevG4*UWh3uU6!{FkVy8m&%9ZY)GpqR>qPW<1{vzZAnq>!b7XD0MxHpy;9L}!N z%Au8}eOjE4`_IeZ^Kg8!@$76YdfBu zkuxTpGBNr<`u$_6M37@Ojg47MKzQO$a3(L&5dKZ!G}xQW7W_6-_Rc#FkQ*Zpp=8|3 z;Cm^A4I7nQs4=NFKF55#7(oTtsLqZc{#{%&ag|#G2_Ad@ClQ-rM3IGG9-;lZ105FA zb)t)P=Ek@yt0Rf8EP$M#0O8@ymb@jw)tCh2-rgp47B5f0*u3otLSsjnRhm1?pU@ytuqDx*N5C<#rSmaxg+Y#W{e>?3RkGsVMBZgr)(7l zzzUzwYJ!RAxV8pe2N`7UlZ_O>3^oPP-+?PBBXP2W#@s*dJ~QDL-SAe~RKh(KhvkGF zin8^vm`g@UpQW&9H#tgkIee0W`d)3=4EOOSjWJ=?(ZdGqh4@FTjQzf8L)E8lZX|b z7k5aD{NKC7^7=|yKbzq9S>ibt&n zpW_wJxL#{mGiOP*bvc2a>T0=n+&p1KlDk()Z68>Ai>IA?{$x0albKnc^nq1E?_Nge zNY+~5>M9`S5BTJ9dh%BbBZdBrF*IB_JSJnDN%YPd#=A~29@VSt8w2JX-LV6)ysS70 zsU6$x3#!I9r1V+nIL>T0T%An~Sm+lIVeo};bya3o%Dq46e#ymf1k={RF=_^uE!6fX zjR!t$-kvvic*9)cK=6Ct-wA%I@troGl7T+Mx)}c9?Ao6h~`Pb)7X27JHcu;iB3*qNZz)1vZnu@{+w~E81(RhS~(^=V|dzRA)}J5 zS4pyFQ;o&5&h>&UW*8+Z#ji_>m+H;^Jjcg#C~aO#kvE}w)O8NL0$c9x(c}ymL^4gR z-C8PP+SPpNSRBAd#llSU)g$fv2P-K3OSO!yF zTKMg!hnrm0QZ635m=N-2qTjnPN?5jra}`#DF`Nvb_BHTerX+;z6;fk&Pmjr)$@xsc zArIBF-5l3;zRJkR;PKqx5ps92xzP&2Wne!4N^hdfnemM*jGb`z4DpOC8hZu>v8q%f zn__1){av*ZXM|4k_wK6f4|!f)48H3dY*L|Am#1JINc&MS;U?7jS*O(ngVXYx(MGSG z*-{0QZigomymd0$ld)YzFIJRNqb)f!+4;gm(i713K5C{lB}7CJD}r#-tHV`=5&YtL zzTh;e=7DNO5AC`^+?f*fKhLu?2%&A<#z*y7f1Hm4LUHYGmhtDgW_?=CK$c1Di#n~I z?gJAg2ORtb?nm9WZmXx26qr2AWpp2LA(SfPZ5sIZnERh+EP5cj*J*_YDp63#FveUVJxx$uNUnj zQ|Moqbz)BFzYNB?cOYL%9L-_%VV6vv5JXuSA#>b9?-CH;4W;$HqllU!QoY3jLdmGX z{^=UsLMcpDC~U&&O;pW~ZR9ioPcda<^1*#zuE_B=P%efEvydG9D+;;%6Z0a?X7X?1 zb-lTw3nO5cmp>GAexu`H);RU$%M)YJKCUMV6*H-qo=&SPy%qnVaEBCpJ@Fwb9bgcEP`R$e^Nw z(2z&k?H(XPxiLeP6B!{CIn~8>igV+~5GZ=(O@krfr3UL?Jf1r{mko_zXU+6~ch=Ef zofOj*swntEnB*}~;OD{{L#qDG&iV9jU;n4nwaIqBg^|zRU^P@T>?Ye0QLUG$n*$|g zi1KucLYSLEKO-V17|JNPI@(8lx9oBL*tB5E=5y)(lKdt0EDhglxC}!PuS4(d34@rd zZ(8fUPV*JQ+_?KgZ*|35ZCZhsV8X1>?{bv#i9cQs^0gTg|27?lJ+Q0xBz?$I!QuF4 z)!|9Zx{VL3pYp0Y$J?D`qp3cnGM878#;Rt!ma2iO(d;fUUpcflR>zd0F-&f6Ml*Pc z)tPk?A{#+{sV^zN5zP-o9^+-bE?b#?Iy&ublJ>iymHZeqQ~7kUiHh`kG$Yw310@M) zrQ!HW#Fm|3v}!qUpv@-ya(8@V^7*N|DwMl)aSDxMG*~zUlK~XPW zRJRAxH(mz_Tp$_&ZIPy`rBq;~o3qV`6Q;?CHx4W;Xe$@Z?hdGCW|T`RsQo&Ea~yV8 z>AAHJtMvVNg+!cQ8~eWH^`7Ze5O64Tk#=+2`hpBd%zv4#Vbk^Ev#cNk?sf*NCv&Fkg2Te%?<_(_E^F+o8=w2ds2Lt+N; zDpXk%ZV^Y|!W=8gFBbt1hp@JrDGbkvq-6d(Cjjno3||!=@yFRk3gNL}P6zD7K=)M# zij+YYPx8>s@ha0C77jrm;7}1uvumE8bUv#326LL2j;D!(jF|OWTOsi7q8k$OH3oxM zxO_Ulj|i!QHR7Bi*8vU>uJb^tY= z;sQCMYj!>~!HF_Ff}MeiwM^x<>dKeJ1;y30|A2jqFVITNIzl#Cx>?^puTdF^gcKjv z7V9d{Z-?PeUfn(wx{CnQ%<~gG7RLLPTbK-5&8g4N9DE|f%e=KYL_O^cRGITiQi{)O zf>KZlZOy13$BesOoLvKF%D>=>hhm8rj;B+(_L(AKE5!+VK;$~DjMG8{h|F(1WkFr* z1uiYwQgO!BS{JOpzkl|(nc)~RV)pN^k#QlKc(4HPWPY$Cd22SXtJ)tXjKn~ii7&T2 zRp=gQ`(`SMatw4AQbt+K7WsKTrLApkQFh`9`FY?%3@>-ay0=U%mJt8CIZF0I5EWl* z5@S+?k<0BQ$Hs6v8+h&Fx42&7JU*Y4_nBgK)$`hKvCI#E12x#khnbn+bIdR^_ON<) zy+vY&D;1W*n~;AKCc*ntSF@Ee-l>A$(CKo}O0$8LeG0-R5_WCQ;l-CVjro$Mk{p&f zvO9DwuA6*-XZQvswf@kqGqRJ!;z}Qg>IllBW`1fE!V*|7qLW{8Dy+C)I0q}`i>fhD z)6JE=<}!N#mmQbuC0V+P>|`aW?CB~2V12>GUl;OtFq$|?k3pw|;sfR5QmKKj3;6=D zd^Nx>i`)w6p^_Snh;U8d7?+8s3kNXj=A_RP%*XrnAQvse-_Bj`iYJEW(NsnhWnUEj zw$a`0Mu5a=IUr!O1jI9|kFT9Y#WPgXGis|CnzdFEOqckSx7?a5O|gBSt2Em4enyZs z2qpf#bf>3-HZUzb`}E&n#{b^Q%DL(H?3B;fSruyDo~3R+1)=@xGYD+tAvecNw?CZI z2YT93xR_kK@XW%qHA%p6RhGj=@43?6KfJxJ`qWz(dVaPv9K0oiyOA`z?>!{5Bx3T0 z>TFm5CxU{iIW0r&yrXW`FHZVc?z)MfG^kY}Mg<3XIDn!KKwe*KZzJHp%sV&Acd5$P z`Ql%O+^?;mz=)>l$62bj4%98BHK_s{7?r7lPc)!u>}y(Wlk@ExEzbJB)`0dwy{xRG zW~-5}a7-78M3_kZ8t4jB)jdIPkQMPmeKfU|>VKfpNz5Qi&z28>7CqbJVeE3mejb|M zn{scgzdw@zm(=%#j+Y@nsH&b^OIx>CEDAl;?kAfGJ))0NMr7Yg*eBlWlk#GpNCIBu z$V>rNGL`iv)vk``YD%yTsYR>MZleuo>9>mgN%f?c_o1R9Hy27qrEJ>mSv%N>09M{* ze7#3v?R--*$1uA?hgi069dNlJHsG6Qg3}MheT66za6r5BC}L09Pv>@fLUm8zR6(PV zY37QA35crSU*2i3t?2cgN&R}e`@mDAQ<_oqgBBaLf6Bplf;mqe&Re_PQ4>~!wwpG8 zuRBRSKSZ_KdDU7mHrs=lOxy?mY9OduH3rver4AqP>|M#VG*l8J&ySEJ{DO(e?KfC^ z8*5!{E;omjIF;a&cUuOjVE^(v@@25$KN}89Jvu%wyAEBCrtvBpPLGdM(u9aKR0yJC z?MqYM?i_#N;k`~MAQ5s$40@CPI&Sa2CI2ZYvYO)sFEO3RE(iJ?Zz=2~qsilt>tNQ( zdk;%VibXBQSQ=KH#Z>Ht0h^?RAX=)-!%Z?x&{<|MDTzCW9_>kiow@@zf0Y}&a~7P$TlR)$qBfv5kp3A~9q zJ%$~jKi}QEp!{)KblmqhN$rGx>UM*9ubHOXX2|=Q%9j&v^RISpqsvmp6G-C|jdSK# zMUTUrbaUI;PpstFq(N4Uwe`7*k6q++Q&m5sQ!UIdM*+c&U41-2@C99cytWHlx!E zRG~Vwn`<`|3;}b*3I#Hm$>NrDPG@=Ccv$+=)sV7_+n88yvn}+BZ5vj)SO`pB6;nM) z$>-vjK8IA;Jlm&!f;S$e+Vv$+EOIjuNiC$;yMPV|4FyQnu)7IuW&o^s)10CzhVD&X4<9I{aooFQ|>;f_gg~$#IpOZ zov)*={g9R!*xzns1&6snl%Y`Gk)u_sOXB#39A$sh%L+ZrZ8D8_|>; z8r;k^Lz%SMVGBJRSLwaz-lfU%T-(hlv8K=IJT&F80< zuMZ#8-os1Lsg^K4;xJF9e1#@aRRfk%(Mz@OQ|}etzrWw(;$oKje!A%MyC)Di6e*S( zf=mZ_h;$;R@`iB>is11$p#0%j8C zrn8((gv+b5`okr&rV)+;+X$TXtWbGr0NM##Vk{SE3z zwsvdF!^i1TJ<`*cJ6I57gDz1zIQUMZfs5!v;A=5of26$0#`y`VYPX3ubXQ!jqzuGT zyEcFwP^Ov(Tj64B{QcB^u4H)sR6fJ&ysa50#y47FGo^E#7Ar*1c_6NjaWA&e#k=bf zR5{8(-!4|!!ol5{Lt#=Ifz-_iQNLH@rV&SYd@2KF=MSf+;-dZ`1SPg^XKP)w>MK=^ z(|4X4d$s6YU0vN-eK6-hj*(V`6pRs$;dqyBVPU`B8B1kgbX9pCOn!$}WZ1cu*sfjm z%nKYv)bO>~^q!El->bSk{nRp<@jqa0ANalFawQ{?7*Y-Cjod&UqQnx{F>0J35iybC zFKu4O!vf`P@=ewB=4-{4ub;w*xz#)`Z}t2Y-|76WF>&Y($Hi5z)b8J8wFsfoLzW_k+Mmq+fKa%WM$M3E_+16Cm!zgy6nUPJR-{!rLX{pKPb?1ouNC#z zh}3R4p_PjCl?uOmC~6pXAY;>$9r+$S8+Y@%d%*n*zeuqsn$-wFrJ*|7lwcr??Jo!0Cg2ey zDmK&ifu*8m=MOrPG|)SK{6eP zAbaxo}x(wn8u<+{29P_?DJ&)5B4eXi4BRjDub3Edq(IPqahjiz(J z*&0e!f0oanpgNc?wV47b5|Dew$$4u4R0^1Zn^n%&ZU@C#&%8st(Ih@iZ^{vzSKZaI zCxW?9baM3nu+eyigly4VYM7rp1iTai+L(#0w}^SvEORT>?BD|CbJ`y27i{!*3#4A2 z!9G8p(fqPp@&3YXJ$(I-F6el)Cth&ailgw2@nUtJLTm?|Cp-j=gdVCao&T3~jO=QX z<+)y~05VyC2)>Y{>+9p~P~4cu{2UY}qyEwE2*UrrxDIZ3tJR&t=s-;qKeZ-~KF<|9 zOl-hwk<An?vH|8+wqOvIK&TB1@b zdJLYDaxu;D^7LK%lLb`3@x`3}(&7JQ1OSn#Al0ss0FBVq0!Tq-ZT7|Xqz`j9+}~Vh z(uGf~ofEg$k}Hq*)$aR-+HLNdA?kPyrJDIM+8=O(ZuAXMLdngIuXh^gQ7$y#O6Oa{ z9mIsGpD~_MJkIvkVNvVY1{?~CT&rxk_#OZnYg7`IgI1E&?X)Ye6Yx6po|8bj670}H z@@`Kwh3f^a_ygrDd&i?J@c3NGZ=m>!T#aFoiPO0e@wJkAdETMtAN#-}kc;}>VX||> z^N@Fb?d}cEAu#;bQn<@l_F6Ysr^T7TlE&bT19fO3oEdUoSg`R(iZT`pNOQ6HjizG7 zjgTal#)83Zy)q3&hs=|Om=JdRa@>$Om|4lPGjS`HcG{76xiGKN=WHibtiaB-nk#ur z3xy7;HyRk%PXnR`i3SGIKVQf@!w>#yMK4X>SePoje2zGiNZ8s%XQMpEr8rEKBpfCe z97Oyi!79Z{;`mPu>4I+K8}%%@hnuzN?I^f1tQTobwYj|_yzc=}5XfdS zf>exQ)D=&!-Wx^k_bGyXcP(^PH|ukk7=pw2*qAEpo~>X0lS?KcKuUH=9khTseOASA zIyk4r6i+e~iAN!@u;t9N!JrAy}}|8(8b| zqdeU?K7J>&1^K#KQGWDLuO+uyKic+QqY>)*a7J<`63!XOCaDe9`l>Wi693DNW8)S8Fhv#wq`OMwtD=HwB5#G zdpvZ?#3=+z^4+^?n+axAx#86$6tX-0u@ZfMt9f6=9)$I~-??HxrwiSVF(G8Y`=RQ)|u#itzDJiO9gA@{S-BE{~Jln~bJ zE`l{+QHiO1>2}KA-!&&P9@oE1dpV$~s`vXhz3E?fN}{dok)YbBwTgJ!I6mIQn$` z(9?lUmT!;Uv$hQGs(B(d2cw$yB+MBx)Ut1OpJBx#9ze3^U@}8uQG-gkE-{EJ`;dO1 zx>m1G4va^I&`N`Aiem)@SZpy!qZO{oqL}JM8b~@s{N6D+;Z{yvaXfb3?QK7@w8B%& zESFv%^_+G28Nx|PC#}88Qz(z!d9F+rA~RX$;jWuws40Bk4i}ZrTUP^R)<~Y`G!L%BYYcQbPWz` zZ8B?fPet>9wTf*JM5oQG!xHaNYw=eNk`po=zLeGLCL%%x*e}!)hN!OKA+#F?=M(L! zT8n^j9XT45WV8FH^!?p0A|gMomF6uLpSB#Wo7e7EK*7Hldj zSzj7j(r9kq`iJ99BH9}V*4IQlpHol4Otl)htFX(D<^^oQ7ctrf@Wi#A4jt{ zsosW#p+Ia_`hI_btx~D>E(9_<2Pc(XdB-|t_f@RIE>?n8?Z}h~qqM@LKP>rf^LCY0 ze+}wB7zqdFK<@8*{apJaybn!@cjgS52@_eu?}>~`Tc+S8+uF0 zOVy<9t3W>M#cgD8tb~EE$_Wi2Ni3SNVs0`_p6!EgWQaZ^fnirKh)p&2MBfrHo40kn z!K{j_6oHmTh#?-&Hp2BU*JSc^Ia?EwC*luDsdvgcEt#=`6REM3Mwe&`@5#JV)^Jia z1UEIeJ>yjzT_I2XjWFpv5*Jc+GiA8Ljw`AH%CjjOk@FTDS!E$5p7!m z#S0Q?Idz|JQaNsch2bAtICp+>!TmN>MrU%$@#&vc>SAerQSg6hz`d~A>X&X|@Lg&T z&4Oo3HXYKB${urGf7_l+-EQk?6kV?WZQ{m!{xiXKcUOmFU=)2dde@f&@^i$&X*)Sw z!Q|QW9hKSR0dZ(xxXLz|^nx&?2`1(%HmwR=`(<0cM*QpCuq6(w&kD%HcUDbCOKKog z1tS0(=R3N$*!H1_mlvJ24v@&aMJlx0eSaGbtb?c(y!kn4Bkt3Kc@i#8i(K(TE|40l zUT5`Nu6;u4;x`arMla9dQJw;=iFmZC`eHl?9<$nK8a_}i>uKHlXruYirA9o@V} z8?)F7iuJpo&>!5;bR3xPwOj1*|3Q>Iw?m6ir8%E`t+`I;14u#mRO;KDj-4Oly#jh( zicb5hg@x#meQ;41fRXeB14v&@A~T9u05W#(97957r#G~pc(iW`UcdN**Q+QthXNWL z$lY4+&|5a<1Sn`d7%2myg!2J9Wg0>#d^}RM;YpRhS#$wWs-@~=pAM$Q?hMD#!dPE) zM21(|+zjTLiHjVcJd&z4vPIdJ)?2B*ksI+zM>-;Lnqa7Hbg}dKJ~( z_$xhKKHgLOjEzyJ`L*9GRCsI!P_u!E`HQn?l}ExGt3QfKC-i^}<>(a}fiEcS@Es-{ zj{ET`l0*k2Mt{CfrZfikU*I0W7ci?Ts(^!IuDOG$s>`J71dy`{kW=Uh7j^fbHs3swJs0L1&y%uL~g_g|<1lXgYGY3YwiC9|03{Qc$vd)$2cb2JKi7xb)X8Tix+z-~K9a!Fm0P-8Wi)D6xSbGLxLsN(& z>OpJwm$)u3&uHWy`Mhozo1N_AZvQ6ze)qZA(iJ-6?5~&Yi>_RzAR0pg0@C?p64J?F z3R7wsX^rs+eaXTYA-8{RXeh1s>1r(sFxUj>O&S6mMb-ghjsn$Uu6NJwt-s@5Lt^FU zjs(;nS0_yMC>Sb6Nqpj=k)^QMU_lC#6@n#EQ_ zoiSiThs*0BNEC3reD`UQL!-$(Im(OfGv`uBc~hZRM=Fd-BhM{H|4T;O1JJFF8||KO zHG4|B_a=1S5yDE0j={oTn7o8R(?N_xt|=R$dp`ei7k50GnxP;IfMOj#6!v_99cPA( z;`>CPNcjV@#R?#pFqpEb)6%AMmfioF50}=z=m@{C+wfVG0@$$qm0`2c2EX(E1=X5c z{Jr%oih#!r7G2C?JIXK1)q+x4%b9*gjl>5!5gD*z>N16vCcCpV2&e8UR{r_}B+;_L zNRbyU7YjG&^i+v5i?#oq|79K*T6g7Md$ml}`A2(s<8R9<7!tvMx&IWmeU%TWY6VPM zIo55Evkd+((=9@{Q5PfEhoCz}=I2y$?X0>xIq!aA8Oqog=Hcbl0r?do`u z)+KFb|G}5R|62RG*a*6vBP)1$;OF8bOVNEPU{pGQXLDV<)~ncj_IqV!EIKZuGOH`1BtO)>yz@8#j*)hMW zEg9+i&@0_NF8)VdO7R;RF<;#W;NP$X-+S11rw__szKo``qbV1DN_YTib>%~#K}l-QFji?wyIj*^fj5#0e(~q*)*^~mjaID&RNJ+7Of2EwkQ!WiJ^bxn~k3$4yd(yOGzYs8Hu_3zzEq#Jk zV!YQEKa(*)JDh8%tXiwod`mBch>C)7273&yIR*Wh(vt=~K_Br=>)*fSdGSXB;%@{9 zJIHZ$NY@$!`!)V^14<4t@rHrKzO_D>#36ZxoJic@O6;fcSZtFxIV+MkT9; zgbb32P!cP(6S|XuFL<FWiB_fYXTrz%8n?=# zTvSqle-==<1?JQS%K*&$VKUW{>G=j{+!~XSh(~x7S+-~&F*c6_zpZIk4-cF{twvK) z9Rq(l5o9k@HvRc5pU-kNuN^<(ZHC0rDgR6Ni9!6Mer*JE5qaBT(bIG7a#oX%xBhid zKb6mkfCakyh8vihHy|lUioW?n5|Z(qVDY>DJ2z;)$)lwx*7f}rE*CST%pvHz+0qI$ z7{m-;Rs=OzCQwibxVe&W*bC+RN~&yKxzRhts2Xy-e7KT7e(es2qF5aJ!p+iU#nFm$ zXFfn9n=vZlF+A=504C6v;)jXFiW%7dzDJ83xvmWYZlADPa~3+BaJp+E0A+nPonNEX z-6Sq{zQGzp+-Lo{C+MfZ52C_}j1Q|Be=&sH<>SwHj`=lefuTkdi%A=bvqUYy$*21K z@yqw4?#tcxCLO>vhRos*pJLJd4&8N&XDa_wIPklZeNp>xqjvMhsGmrV__U-vKjR5P zl-sY+-TS*|jj#?Yu|hl4e%$x|GAGr@4Vd_`9}^gRwi)KOT6jRbqEb~Hr$fQKgDqoy z@3mBCjlOn^Cv21bS3i%^gpI@P(%CggI3a@RPzEQ87MGRb8R1+YAQ=XpKSU2E^5d4M z&K5VtG?E+s!66d*0V7N;<2{T$k}EfasrZ9wvx$ocWM503q%A16NN^etCn?_WW4U5s zq&AR)bl9q5t)Z=R2b{Z&LSO*R^LgVgmy3CgcJ3+C#74#1_h%%pF!0(LMwJkaNXYk^ zuwiZCa<@jWuO@%8RXX>DktIMHD~9ZElf!ALiiDz{IecF46s$KT%ZnjNK;Hr-pS~jF zB`KpE)tO!&qMPH%PrzH6563=cq_NJx8jzFQcRk8)c4%_&&-4(l4g~wP!y>HzU1|{X z@3UC|k?%|guLc-NMq+xu!JfR=1Nm-~*+y5$ zbgKsq+lf$0cb?zov#QIGBqB+IcPBE9dVebBlnDHBC>Ywf2WLKzl*J0=i7{NaXtg1? zl0dYk#0BgXSpgWM`$pm!f+nl#G5u~dc}PK^VDHY@7s^cg<3%dEi%gCo*ib)T7LR^M z<1yg$yhsh$(`M)L685{y3+%zQctBB7EMOxVpdM_%;tG9ZQ8V z36HH&gsj_WYd}863bf_61i&7RCiA0kam`S9eo#etx>IuWjw{ow&5})IZgf2?==~ub zhSM%2H{SGZ=38S^v&_1%(GX48ca@XRE+1IWR+nEeLsDz}1?%Z2&WXedZ*h z6tD9M(YLu08e;{@-dtbTi%w}?ZmPhmM`%}PVVj z%OupzTdi#73j3ztjngUC#L?#DDP)R97|DJAEk^2!3*bn+!@0na;XpgP7Q?YOS|p5l zf??Gc#HAN6qvzmX2RB+g9%h+x*6PiM*!+avB5HLg8W|7Xy%i9O>5uMeS?%=6LGLyk z0cn`QAq1;UKu?#9Tp1VR;Fxo0#!{DzRto7m(kJiMXRxe~)p=MB-;MwHBDHpo$!)lMx5ryCCm@a5!(6lZ5$ zpzqs!rKG;M|I>A%H#CgWUB%9i04|q1#Ne?*!p&s|)3MIkvF28~2X4o_QVA&Wn90eR z(mvcWS#t9!%TstQkC1PAUV?f33(HOTl7)N_1R?ghfMBn{Nc-5!KLZY558@8ZHU+8Q zsg`h1TSy`nn521Jge9kR6GpNkc-f|n-mgw2X#xHcUF@Q~t4A`07}ldNJPAe#E=^!k z9163w0-W{PrgP&-$AWs#pJFs1DZFU6#eb+Ob8M z=_$E5X&B3+KhY&6rM!aNj@opziM0{TRIxdx-}&8kmEkL6)F|Pil+0y8L(m8)PMu_t z>6R1M67c^BRM8pw5dqh-?rY+0aEKtjp%3z=8iBL@@W;ktVS_Ao(_mbfC>1P=^;w|Z zOAk#q538Q7t~+0bVKZxm42eIw^!~UPnur#p0S7-reVTfu4u(@L#OYAlDwzs6Qv}=~ zaMs`px#cZa=y;AfEI5Cp`#58|iDqwo8qSJ1yV`lAMHlf_9 zLLz=|G4TvLUw`ZE4y#7{1-ahRv6E5xm&Jt8kuVWbqLAP=Ap|6uYG9YV^HJk!%&cJk zusXW^3Q<4wsnhD0LZo_DO5ZwMd9WRfInkVeVj4*Q0bHxO$mHe2Tq zM=F!qD(sSFRv@IQa5C}fxqR!N(dj**UaTZ5i`U^wEM9%1=La~AEVJQ@ouRizCUJP_ zN1O8QuEK7RQkJ)S>@2qIqyik9-4NmDJ6QL5hNhbd-qqEGMA9E}k1-yy_+Iaf$na~- zAFDcS*VAyK)@)vH(flM`UE^_h()VG+wO||%EjE$K#Ek2Dc%K5mfw{`c@ve?|0tEa7 zxdmXRH0e6peJS3HemLKr0qLKuFPpGnhaC!}cQV5siN*+$cQps`r78)X?8%3c;RHws zE8s^M%2$7gVlf4B{>8~n6umoGgsm3qFa+JM#Xw|h9wFdMp2vKZaK_n?R4T0n=a-gp zoetGp9!`kG)PnT)CNU6SUk%(4^ZWM&!7t1D`sRIZlZ?#B>FwSMh{;)TRsdJ6aw;5F` ze?fleoQ?KC8~^R^@pe>dIlRjBO_1ZbH`xx{HYH4DCLB0#6mF8jo2`+-bn znM4;RU5A~l-hrGPih$5T&OO2|6DBS97(C#jo=YK%HWwj3B?P{@W~X&fTEmU-<|tA~ z-h*)*?I~Q;M-&kmS*$k@@t)S`LPIZppfP*J;|I{Ky?IN1VCWm0&S|N5BEC_S===l> zL7&09{g`{D!T2_>T142Zy_-xwie5%kG?c|;n4?UGFtDoXGo1*yVF`ic2fq`+X2RCf zYrrg_ZH;{S925O7a%`a%7tUqCRCilurpnkn%lpcV9^bSqs@wQvQ!$#LH6y*_a6NWB4`U7DkafI~f3BOTg2=&TBez@tc*EW+z~z`?Bd z03W+7fhdizWS`0--iZX~>>nsO_#;Ih%>z8f=`7nzDy3mt(y@lWW3XwJXoW2aX9vJt zquOXrmuGQly*qzozTM)z#GCJ;HF=pTyt%S@Rkpq&Z)>{cQ&#Zp*NJ7g`bJ}K_FnqAxUVKlhTNj0(vEY2haziTcdMWVw?Cji#QMa0)=hcmP zGe=-B-b)|g{2i#bhT`86Hdqd{J>0Uo>wEFOOfOtcR;LrMJUzdW_4_bcZsfK#aw%OM z;h|4KWfXW-Wp!pwjML~CfYnfExu{_%SC?hdmBVH}CpKV~#3BkqB?z(&RtC0jWLE$7Gu+uRVoP)5X zY`LZj1l&Pwxa9Nur(0eLn5sPKWUu?UB2(SK)iTKLtWE3y&|B@|T45hcfcJ=y;P6` z-vGke5eO-`eh$}ox+k5hISDQcxn8I|UMWi)%~#7Vs*AroHiV#kKiVRL(;77Z5Ee;0 z%9F|JMqg<6pFhgeer5@e`oqp}>dTF;Z*@uIEwS%JuM^t~LLLEsR(Cm;%r7}oFW`EC z$NcmPk;OlO=?e}BaFk{?8cnLk^qWyvKACIC6m3l(h{}`RP6aYFE$O)cm2AAfa^}k5 zO|@Bk6Bed9u@Dj6eb|ZMk4}%AR}q;%KMuzg=Uhn^`yVZJ5GJ#k_%>OPn=jqjy{%h@ z+uTLjamzJR{E+VeV+gr+`aSkOwL}aOPbG^3QVj>U1lBxNSU~iQ=7oG6C?t_2*Qu?` zEN&_nesN)x_Cr7;DCnC^9sr4zc;IF{dL-Dhi3myB5|XxurObXf1}D4&HE^Z4;^!Vu zH-&1;f=U~GBV|-j3mCJEJ`=&9T9Knevs6e*FTh( zaBw0djd&`b$(t?sO1egzETJ8SdzXG_B+MaiCnMVH_IAQ`uEaqQ)K}~>r^PPQh6g0x zUt)`-a1_5-J8!w*guV427ptG(R6dnaKE0VRPZZw}rk2OtY!#jW>HG|ovR^ga3I2H6 zS^-u4^tC;E!7OT~1M2eJGGBLN2SL=olo1X(Pv1M70pCMZdW7iezw?N?+w7F`X$ptL z9^EP>Wez%7vm~s%+$c^+C!7@q>rK+rA30gA=Y$LGjuAUTgWepW6?(#QI1$M{bL_q( zMVLDpnOKj1bWS_}uKRMSmr3D@tkeGCz|8X}4KGXuF47=}>Pzn8ec?`qov>@O$$_QDa;zU-(@MgL$o&?u8t466=ydR7OOc(`kxK>S@DIRE#1x7x2z7d-# zm1`=n;y1PZXOBxBK zySux)K^p1q_!jT~oO|v!?!B*LY#j`??!A6<#q+Eu<_sv?l50K}H@U5~B8|`kagD>; z^|qMp>w`Gy{%O;v6ll;2MZjnUIBf+7rqhET4w#*m2;zs290*3pT=udn1di|fp zK+h%yZ)ZdRQ;rO=es?I$Q^;njFnWIi`RQp=$-@IFDC%*~uI6<;7u#S+BzerC1}!}~ z47ZSA^l`p=>m+pBdW+6BtA{*eKav&MvDo!UzyU$rg3sQ#Z-4X{&L53wJ<6lT+O@Baz&;}Ky{h4JIA2BR=tMSWG??FPDe{>ifh*AvfLk# z`1trF($PYo99!xbP(`)>;*a|YN>M*^9Z8OSDXprC^MEngT^hhbKsbmZ)PH@R9j#hr z3S`!^2Swk{Rl_Vc05T~e7Qgi#e1})?x8AYf-jVTX+tOqkWqP{{yN zPLe3QL&;U0Lkp~=;vgC2BCbcJV6o%0tWhq1kmZe|eHv9jr1L;h z@i^TE^CvvFe&Ny=pEuEO>*}~BF@dgui!}ywOM;8S%Y6Q^`tmyP8 zzca0%iZ}XWwnL&D#xw`KJh*XEy$TnK{^3{!tvru4crdCpc%bc3bYwVuJSx$yDT>M% zL5@PMJ2MGce`$5LxC(0fh}SugX2B`bq2fdPu9VyL4sy4vPBJ(Bk#49hr&9$g)cUX)dFEF3`R~``5VZ4gVbFUD@?b_Sg|il8dqT=XYd+C zew>#@4l4nbunI;5+RKY3w+ts|RiOh<<@hNR)KHu5*GWUbVOkoyscGgNx=3n$3Pawr zSzT0hzPT1vmqck$v9dT&f2?MHC3cg7Y?$I>W3Q0Emp&1m=OO-CP=TSPWg+e4gt}di zdV+0Ok_hKzvsn4h&=H46%kYnE)en5-=@@ir$zixmtX({1frBZUO|D9M<$Kdbf|>a5 zV0}j8ht%oaugP(^9Y5<8g5Cs%3s!#iz8KP{HFy6yvsKK|l3%v(@~svFW`qfZCBw|9 zx-Hq`eK7a#_2SU-a|sr454WuPDSf;Y{N2>>81pKFKCXeH9uMVd7O4cs$)-y zIGo5Ns#tN+H|R{g&8z>dKcU9$;x^7l1}kL4$@kG?_|AvK{?_I^A-wJT;Z=+0jOUk@ zqMipPJo=yJ$jQdzboL)DuhMyHI9ArYUo?7Lq2qEo1r2?wsJ{4ySISJ*T-x_^t{e1@ zlrQPYx@g?X^|%NFzW`85PKzpXJ7BZFOm;eaTzC`qtn*U9_C1$6`ZM*Sn|AIT=oERVlwyOuPA8yeJYfc`Uu^5W9cQdKQ#PA&S?+95*M z>XV04`!Dh2%DnMd3tT@-goDuXp^0!tC=5`-UoWN3Q0YZy<>{++ zKn?`4I`2uTB6&35lLTU@(24z-tiZpucMw|Z3<~Y;9}Q>JTNFa2jnsbiHm1t<%JZv| zY#yMP!=4*_dqD3WHx{n<2Ya!6y|61BW$jsYc3DnNmC5PoziR;yPUn8H=D}1!wPcIh zH8?8>i}faUU6BvPPk#Bs;HfmJrbZWWMnVt@efbBphfZWjH@z+mTIXgIl|8dsQ&H^pFN-y6k2;=bM^SS`RDDG4mNn9t;IE6~9(VKmCpE!}D zn@k*VE6tc9HXR2Fs(u*sp@^jj<;rUBV zV#&-Ob!B+08N){qD5WTps8Fo+9!<59WrOv_y&uV8xAj)yJ1uUc5jD@16@BDzU44D~^z<}|y32>n zyZf6nY^<=988-c)q^i$lwu$MPy1}|E@*BOk#?s5LPScnTH{P{<9dy}fA`+owFfkrU z(>#fFifG(+r;H*JVYZze507)2$&1O6Ep%qE${A?bJ5OYyOpa7`JX-z=^o(<<2~Y2z z?oT?hZIp)}ZuW8*lltzo<{6wu`kP1{#Dm^{3>Fq3dTQ4H3D5BQaJdTm0((b(A&K&I zIokg0SFK6Ur`N^QUY(KcPxm)(`g0S3H%lUEz%dcoh3Jij)9X@*_I6zRaIJ+0|8d}Y zj_X+tIntXBiX>k-+7DK?sGPRo_wCTa@yUc}oQojU9U^YGcumF5!KA7ONoK%D>}nlr zE3(d;^&ch@k$SV0lQze_ux}3+1nCgIe6ERK76VQ<1iOH@D_aOrB*Cn?B&1BOP(%U~1 znn%5qX2)8P0U1(f-M9NBdi%Xe?2u|KC#V4lDA^`6bZ0I(&0iInYjEbuDQ$W|(v045 zmd_!O?ftUb@e4Cn3&DO=@hJ~mP+Ge`dl1a;QD30%xW8OLY2(BFXV~KMA5B%J}Y^_s0?%!>3}))cVo_ z&4m#k^ZWL|p4Yq(G&-Yyn8@NRM9s-7jE1@w>+Ed!%6Ftw!wXc337yh3c9t4cj-4WD zUSmPPQaU}}3m2+YX&lsq40UIG{aT(bPS0gVv$$6^9rY&3Gla%`{JP9!z7cJWjDDB^ z3zJ6T_!nrYXv>JPEVB6QTW?WB)1f2nVr5j zQ4i&q)8}^*{>9M}q*DGAAE@tpSQht6Tb*$Geq?~FC~lO@Ot_M>wNF0uepF zXgA|)9)wE@YUi8hp$!`GcwO=tyCU!=WnP7i!X1z=Dfvf}0Un;u8NSXyHpq6nKLb(G z$V3!*VW1URUv8zi9&Q$mN#rf581mhx86LXrnSaR)OP;eU;sMIc19hlASCZZ?XZ#g}PwvA^bR;N=^(SnHrJeDI#h-aBpY z4iO)j)RrVG*B6Wd0hisMhSO31x|JsohawsU2wva9m+9>i`Gy4c7+&%Cy}?$lN@bHH zLgUMx`LPOi8nL-vm*Uuxo=}KC^4HJ`h`X7{)58Zh!xy^~LvmF;dYVuINd(^XB5=fZGO%DG5vtdziHzME9PD-y}Uv%fGXS zs-NeIzy#*=-95WWZmBZLF)ze$#Qn(d{75JU*=s$apGP_DoWTZB-v>|1@zXvyNNCu# z?f6M+F{yhgEZLFxD4ltacVNQpbu!IfEe`4;{MV3JwGD>1Z>Bf(rNLmN=_K zgAMw0Ohj##Yq6r2M9d97DHl(_ktewuj7_wQ>R`b(;6lXb^x2K0`eEL;CgO-%wqSD6 zPY{~UC}@~Xr_j#CR<6Psx~cF16M&W11_olZgwCFsXSl) z$yMDEk7xJ7RsH!a^|Vy$2W9)t@YTG^%EJQPBk_Nh^D|Jb#xGNPP7zKdyw7x(-;waW z1g~j6zPG4-C}jLo5}Qg+tmY0r28R=jreY$Y%Yq_0d?Ur+k<#Wqor*^iy$l4BEg4=T z#UCnun#OtFpTiE!6n5l9;E!d6WZho3Wr?!6+~NR*P+vO?y1dG*&Bs9FjXMlFZQbiy zaZL8y5}u?u%r_#T>4mI2y*6shWx5Y;gvx^n`G?$hh-K+Jkyy08P;TYrHSs4Rs|`wtzRI1Odg`Q(%11*| zg?x*#=07m6N{csx7c!?F+6PYKHP0&AYwen5_}G zWzL)0ChnFJ`V-wHN1jeA7;NQ;IWH%$+(6IfiV9p$+c7;!m)lbs9{1aQW8GjFIgtAa z?mV%0Ou`h#X3IDIx{i)8&w^<|U~*IL_|M_^d_G2sd!NllveSBHsiYu2!S9;KJfE#% zt-Mgvmh-+&N6T3jA-{I*8A3^9qA{lm6y=}37h+dz(RFvq30|nON>=GhN0#efY3)05 z2l7a#MiDf-@P{aGgKQdu?yY$!);PXgrn89FJGpl6)ht5fp0})zq*X58mm$wz94xV1@iv823>Z6KC5*RqXa+$Jg&T zLKrFWOM9CQ5Qq-G{s$Clh{KE1t$zez_lR3>DlWpX+{`th*m%o}PvFF?Zg@WaG9C_> zFR~S`k~ti$CT09369C#`GR)F_taq>R<$sA4ml&*9A5bDC%qQR9N*T(R4aH+!9GDV` zobTMOZ`>a~yv|bXs5dRqrfQypW>yy+=)MRWo*2%-HKa!XvKUO;bU##Pq~QjtaT{#z z4mGpP8Ltj`W!q{iZO^7P{a~?QqxHuMl(oMKvkca}yDXrl=zupCkF!A zFsp}?PDqbtOBze~@w2+%F?*8-Tu0!ed{Oth{xog#dOmh8Af~UL+?biv7s`6kjAe@W zOAY1*BJsHAwkT^6{NsTFC-enu0#U2Wev5~;HP5|O1aC>&^TH{NYE5mpqPG}+83(bs zU9v*CAQmxz9f>oiy}2}@mrUa4F-dUi$v*W;CqRpW7sOBE3w*S zF6F!asCBa6jW$&K>dgE}iWEv7(NcoJnARk5bq43w+|EKl1RD(($<=FvHzAY_K|&9= z=QkA`PFKwj;GAK5ec{N6k}swSw12*f|HKzl7jPW2y9tDlntLi^Q0%tVP#`t~` z>lzRhsxcQw00Q^lzgM&R$z@v{hmcrP-u)UDiY5sf{ozPMt=)uv#N#geWxZ$%iGpzC{mt1ksBU#!s(&K?q}v)_!ebI226~IgG&-F3$-J<7bS} zu60MFnz3y4L;k9yYy%uWkIL zg%i!~4b4I0@p$?MO&Db;o)GnK5s_-t9tWa|8;6Ybw^)jf`ML)=lM9z;V{*E@w%r~K zH;tog9Szs(HSg=63dACQZK_n@3rrD_ydMm?27Sx>1&WF-B0K+c6OESe<#738MOd-O z>WOXITmlPYIt|6P34=l)R%|qlpg;TJfV}N-{tYs`d?bow2SE&G1l`KX#e&oQ^@##j zoT>nV&+%$I5wJGE-6F~q4iY1j=*4<}>G#iR2oA*Gbnkw1UD6@)(SIDdv8MMiV)~DH z=9l0LeIF2!s%Q~QtA+ZpV7EL=Y_4hsZJSm@z$$0>b|kzZRXKSlT9w50d}jwZkaADa zB$D2i;Rj6~w9r$z^2l}N#$CV1-i_9#;g%Z?`;iu;*gSO8D2aB$AdmiX(KqOi!~-AJ zIj&@OvUg?G8Hf&lpvEc~Y|u>v&Att2d=j|yX|-BB3U8s4e#Z{{F2X3+6P1^&NNyI*mrn?}4NDR8Qy+57X%O_|8l=9SA1->T@M)By3z)_+CNu=U6#?T zPP9OZTf|B<>h1d0J|wWaooC-m!e~i6<|jqk3O7E@%XxQ*M(B4;9|Sw}8;FmUX=0Nu zGE`<^`YQUyCNRhW|7FqZ7%4=haBLw%{->BfhymxmFipZWJdb?5zC7UkHIx$F91N>cLmzZc;DauWahhew;2+RdIyi3~)* zk41)MC>IJtpUTvi!X*)iG#ShM(-Lh?n$E?AL}etI)j^uo(<5_QmlN2jku{!Ey4s=Y z4)1><7LO4mYdA~hrLBRKcHQ#yfOy2~F0}u-J7w@A#X2Ps@>4L2fktO-;Sz@09nm5z zHcO#gh2AJiSwy^UmqxmQBq>vPXq8n@Qoi8uRQWL!p{X*i*z;tOL>Bu0KL;-My9DL9 zFP!KS9+t$g*2*#uS9rk*gEMe7txknASo;9-m(If;@U~^drkw@VBenO*ZK)rxcu9rE zg2DUlk0%pk4!qYhEP|Z<+8&c%n{43ZeR0{bNq{@^udh<{m#EpF2gJ(K|Fd=f3jJTaqEKd1+$aAZ!}uJd`9EKL^zVKUkS6$4u>WP81Q2_KeEh)| zp=fRr&x`!uUPz74aBD4_hy7)oVy(e2vXOeiU%QH<|Ie}g|9=BT1py#MW5ot0;xCYX zc!qSsq^#uM2Kmn;w241M`d>G~e}^>q8Pbm$`_%t882|U7^3kIJNHKLQDE=}|04WiG z)FBMR?bE;F`FxDHKSRnhZ65SjNc*25HH7Rw{5z!B&yd1@#3uSHq%6;nE(Dgf{2fx^ zXGn>L9RGcZKD%Y%&yWJnRrdWIBl*!hNPi5n{2kKhXGq!2_nH3= zDH1(OHk6>7x$oZ|AIy|L-!EoyCGC4gnv(1U;Y8e?=kw<)f#;#zx)4VZBWH+tU&3fXPKU51o7YH^{u> zz{c*9fDT{!@VCi@u?3S0#jeNl?*}D#SEmT9!m{Zo{g%Ii>YD^6mtQL3;;*alGYwdU zg^oM3Hh+bb-~)gZ3DW4|U%>p&ThpJOA;smqO!+IMCeM&ox~p>j6;d={e!7C8BQ(kW z3aR`vq!e1p(tq37Iz!KpZjI@${2kKg{lYK)-Qn+$etd@1^?KIj?~sx_L)vaQ^>;{t zMMvGkL~W+s!V@{H0~MFe(1=hzeCFS3@MhH@?XzNor7mcFOdzN z{toH0q2w2izxb>9`ON(csV9sJ#9x8p7Xl|B!OH>DzkYpTI{5l&UjN3If1Rfvz@d>C zwKgpJ>(^&^gAdKnL2`lp>p$fecphn6zr??c)HkNJslmzS{u0W0Gq7aR@j|(+cY&Q2$#SIO_R%u*-%Oxkj!>kTeqb!y*WSQ5MgFtTZ z+@}VIJr)E!uD}Eay&vXvwxwl3MZA|lf3y~89GTKdFV=!a{K~N_Evg4l92btq4SE9Q zi2zBOi1vUJAg=5N!lO|v7HY8+ni5`8ZGB567B}5@7ke|H-w>b2#rcO~9*S5hM_4oL zO7~}k`-?LS$Nj}1&|BRBGMeUBpo-FmyTNH4bc^)Hkg=X_4j9|-f4xIQy-Vly%KTiG z`7FH>@ttzr^WoM(u~-9Ex5FP^R@2k4fBkFP^I926p!vUervGhSp=cmhE@!`p!m2&S zPfK$KAF*J4Qa!Ex4eY!Gec9v585vizd(Vv33gEz%xxc^QOi(jof*?iW(fBMBh=dnK zEG$$>j*Pq-Q6a#$w|VnF6Q~0Z#THTJFQEB*r9Ve+y}uRRcB?m+$TfWcbU?wNf=GX99)7mU zjg!%M`0d)EVaR{i0)RQ)YcKyfFj}(0cYmd=ets}BV=(e~)$)`Pqi?KHYYhQpM7rBw zg)q4E3(d|=$@etW)n!y`a+8_|qkp7iv0C0;uT?3OMOG=PFR-&(aun?hM7}tWMQ+WJHO@{PVyqcEoTEapFipyr*R5f7O9 z2N`}my};pge93CHd@7f4tljYRT$1n>mjyMtE!({g&f0!Iu>N9qZ9lOhSG9tr+I%Sx zOz|3Eym!7hMFZqACa1fdJIA2)j?I4OMZb^*4rNh13}CD{B$mtP!jRzq%POH zOWYK0yVugv++Zk2D=k-cnuHGfj~AYDz@$69m`Ud!V9hn%b|uX1E!TQJV`1Duybj*| zS7Fq%Um)-vVt7PwKCqORF!jZ@D4~a+}S)0eNLsFRl=$L~9yxnnfC4AZoVz z%_+Q$c5_#NOgi8|d%9=#1ZM;P;Er4rTQfY!h;8K9LEin2z|%h7J?LpIj=%VZ^q;J2 zB{^X>>;CKiv4v205X1VA5u|2BKBIizX6d8!!Hus`uCHJQlQ}`Vdr8l*Ca2BTIo4#p z67f%rGZ+ulBtw?6g&f7zyPSNJBv_99Ix(!&o=9s{a!*6kq|V0{{IJ-J@q$ zgP;_|Qt@VmRJBb=T5qB*A}CiJe3<;fe?#c`QT)v@_Q!|8TgVW;KoE*T?s_=X=Y1pB z_!3!HqI**ODT#b@sb|Fb?omM}?A;!029&v;uqdER6@88VKXw=9`Gkds&+0WJ@M$G$ zt&;i8WEcjv9=|9bgF{)S7hEBI#%bBR8+wwPnwt1}Fp zZ6GqkVa}%49jL1u$*6Y?)97}kWjHz}5xkLCrq?CU<#CG&*lqzWUs$QfowUJ78vIm& ziXf19aThX^h+J#zp3`uJbE|?{!wBng zx&gakRRj!%D8B0C-iyb_2kfW22kh1M0L0PR$J>iHtL=#qA~%4UX|orZP{8j+mHzGq zuyau2O+L$GNXi+D#1Z(sEW1j8qX!A_<0DNgJUR5#xQ%;Ny&h8aJOGHsV>N57`{2<`8rE-> zbUxDJQJEbUY5R7&jL?u|77+y|5$Z9nN~Sk^Lu;_3aRs9VD%v=lo|t{nq#gg1 zI&O#o^;rRJsTxb^Kx{IE+l!-|C&^ASr2<94Z*ZFz=~sIT_;gy$ohj@U$H%LJ#Qb23 zIUWCr3E<#0ois7!Rsu>~9u22AYTH!_+-|g&b%*?2aA-Cc`JAp7yWyZnPG@+ZUFJsOT8VOc2ah^0a2R}Qhc35+Ok(t#%K z1Jdcsf6fd(kXJ-R;z`4icuvIJzK%cQc#5DnAb&K*NHGRcVi)wg-#8f6hDpz>Fr~#+ z)KIj~IC*(Q5A^^=ICjnPKP0hu@^D)Ym?2>t z|B38j9ebd^Rmbo5`d5Fm#~r=Fu`CXU`=}^2@QT`J8P-dO3`1B&SE#<1`~Vh11X&WE z>h9u<3>0F21>KE%#Kxv8A^Hy>g=c+RnH=mlpCRZL*x?gfrr$#-*Y0OB-I!R@eBiVc z5m%tR-r{HhPF+m463rrvPBFy^YSjwLp4Y23XWdfxB{ahQsDbD-9H4^z>v~UkmfX6? z?)$DpffP(hH1&o3-UNoMlA36tQ^3H*42MRW9j;m78Wuc1KiynZvfU2>6f^v@^f4rp zS+G8uP9LA7h(_S?*Iq03$I^rWbDJ+H1SMBu30Yg0I-OqrWx^H6oGoNFV}-8{Vlj=? zioe^mKLrGETqi{K4Egkun1E4|KkR!!0Tq#Oupju7E9mz`%(NX(p#W#I);Xneu{%Wt zWCPLmW{Lz)H~JbcRB;qFu8xH3?Z1RID_C&3`T<`gf5d5j79uFztXQ!`OR4Ja&jeX0 zJ}(3=Cr5%uT6XwamxRt>!q_dt_mRcL#n@|69EXjYM(fqL2sm7UK&CQFHp91nPCTW6 zgtF91_!jh=IS!_Am0fG3A;_GL=8Ls9kWxu33gPDEYy;nUTWZ|eN|ONTWbPBV2Z@FC1R@hh zl3C$}G(4NyP+U$t+Jzc5_wX6WO^*aZ45u_HV^*RG}PaDMFk*yA=HYBikY1 z{=Od|*d^58l5{@Xg4ej(=Qq1^Y>rkfv!}=ujtEY2ba3aMUXOwP5Q_UMC(Yw`y%nPT zFNs$RIP6ksWC9I@khglXxePGxJ`_G;BDWQPuE$KRf4>6#i?Yt;?8D{Ze9$E>ZW*XQ zj4hCb6?b=j+|W9lso?CEPSR7}r#k4h8A;>0xNwaj{S<&)*0MB5BWlO7$RF_b+gvnzfCM{vsx{BFZ8`LnVh`CnLGCL z(ml}c^XS!oc2H@3fI3Wu5j^K$%12E))6q;(Zf9qem6LeD<^^b)OlF3)JU$3)hlhvP zx@{w{Sk4EM%Vm;Bi2-j>F584KTQU*l)UC!LrYVT1~E|h{F9h zXWMd3YBYo%BeTQZw2^5NR;?=XPdFEY5oi2NE%r1x4D@Ypk(DQb)D zQwW_V98aIjo6zkLG1h2yM=MY%@*Qx*sOmYM>wpA}gdN>sd&g^=Z>${pTt$N^`1{wo zJ`GN9ey_?i|l2WQ7T8FI@%En6(CZW%w?=c)cEj zLBj9xj2edE9O?Hx*Lf&u3CV9@KH%6oBGn*Q96a%{=H*O8GjO|(M&L(|Q~$9TP44O! z^|FVO%~#6-#Np{p#mz&hL$kVUd~s^lry;EPzfW!oUWx7^*l=6FP$|)3aB*3hOlBo=1oUkk6JW5=>C}8lKVbm*J%8(+SqM^zox_Jj zCS%?6+_D5NL!w}G8sA12I0Ct7Kj%v!3_~WM+vj|BnDtm;IDnod)Q7_6wnYs(TEoz3 zlJtK6fOx*ug3@wq%`72xZVZ73QAQ%L4~#4y}PgRl7299U>n4>NqrC z_K2MA{&ro<#OXUz~>^+DX12u4~>8s%5Gt&d=@aC+0uJl|0eW&c>LMDI{+BvnZM-Mv#J!S!6viW#AaE4AJ()! z+p?h6te!2@A@K6?OI9YwI&_5hu$Rz<0C)j;G_>^@sI@d{j;TEV3d)cy&<_=n4? zJ&`6IcEcw(Y7T=NHVDQ@f>_7-Wh%_~M!3=E>%l5=?gdv3O{fmZ=0T0 zhINq77V|Oai=nXTpUhK`D_0c9Plsr6r;yeJTBIGf@McqA4i67=)pLqb`um)+M8Z!T zpUf^ooPU}p!rj6&G5SB#&-uK(nIa^5M1l}4{9HB&ID-$smd-Wl-wLK^`+?J-v&t1q zrGl>A?9Si)Ry8z}8GHKY;Y7gIlqiTS$sg(1n1{UUvD@Eh01-#G255st&dQ^}7_x{p zP_Ie(zA}$!q<}t#XpPKe<`Z&{b6tSj`HoNdW`7bFD<~T2A5+8W98P8R4Bzz2Q}{*I zb2nY2{yr7|wQdxZ6RpXxt`=2|Uy)-t3@AQ*2nG}!e1~RESJ=0^^VMIz0)dRI9sE@l zph|My!s=N!BhX&vnb_0p_Jm+OoYr+_JOZ{k6AFo#_hgQTpkt~c?qt^R(q*lD95$)sW#OIu*Kj9M0Dz&H*CxzgexSQp)8^Ly5Ym_Im> zsKLpxv)=*R9k)0HV_3hh{Z#_J;d`OUQr9k9$z*O7Lx+iA-RZj21bG3w@ zhTH75D`@K?VSFs=>J=Vrp68e!h7$79BUW16FtSA7Du6bBB9YEJr=#Pw8>UzqZHSY1 zB=UB*_J1Y-iKczNbPz3%!y44ZQ3YtdG%iko!5&s{emHLP5DG;?hJ8l{&T`e!;;&yh zE;mlrFRoRygwG=kj zx9cBdPO9(@yx(k(=&dfYCooPJBO7ib9E|oir+TImnBy!|b;YN;Nx?}lU{wJm489EmqkA(Iy9v zQ%<7f%?@aI`ugbrM7&&vp%|H~yUaLw!+{Kgyz$$o8q;}9Kn>L1?s66yj?H0<3LKt{ zPHuHpi*uVLVzS3KX80jiAMnIL(t8a?qrnvoNJ{h16sL|>sjGNAZ7iuZI)B08*vR)g zVhk8gr9$iu#RW1mloW)$tq@;J9rn=8SIRVb)7?%t7{YPS2J?xCZlZ`q^jp1~LA$N* zn40|in3XG>YIb^q9i++ppYNPG9ryiePu3`-ZaZP$0Y91o?Oq@l=8#G$AC9%=omc{S zhHBb#(BKCQE1(H15Tcilr_uCxIorB>k4ZxEHi>{uPBWL8V>g`gOd<$SdAxh9 z&th{t@=dw#t z6Pv|c2sk$90>6Kl%5*z}=H&caaDovVOHc4izpU`6s|HME361G#yl&y2%k*y&;+E;I zx>xW-Kh*{u-}a2)lWS=hm%KS7;@2ZF)0#4!($Uv%w8C5TD68ad*}srTMa1Lj1WjJ& zb1y)7e_&x^1^L}4YqUAC7;Z*8AHSF5h&N65=YO)s9?ki7W9r&mx2LT4ce8zGak$+v z>uk5Dpkd*}mbh50VN)FKIx2D^?2S}%Wz2J#%dXw(%`SNUDP(rg@TgN0Fmf`^}+|%#!#>JZ606QbVTYF2C*VDb{ z50kOtZ;+W;q2$fZ7LTUnMThlWS4Uo`9<(@IYJv=q)|^~fbIO}@_u%BEZ)QEeI?vN= zxmSKI(jqyf%T{wLgY7TD1WYTc{ zJh6Fy32Sn_cz=g@C_1o3GgwVG>`oO=+XgYy)SE!@&U7j-;4Qj=a^$yzGGbB1^97KD z$rWoauT5hgYIyfuG8hC1!Yu*YTXPSZT$V6@U;DRG`%TmAbCfzQj`TN)bnDo(%-nH@yJ{jymssQu8ec4Xf0q0znz$!{%@QXI%IQvqX5TM74?I_Hxf`l7_(u5N5nyZTIhp1~*aK#*w`4 z*9e%oMAWWW>QjRyv^w<)`DK1K#laqN4ShbyUS`EAgLhjNvaN;;B%qi3}QAwJMe;Z2eiEZ*S1`XJ|2c-4v+Q zV%1b;xW&Hnq_Xk{yRQ^}VUkQ|(DbtE1Hu&{7?k-%^dUGDDAFlhK_}}UZpmv$8Qnp@ z@~ryhI}j_|#TrUxO|RJ=-v6qziZO2a=zhZhbi6$#b#3JHRcg|-G|C(XltE|$BbmjD z&kqJU)YNh+AAW6iR_ET&X4g)TKbWm`pkW7e(oo)(S3?kBIa5pxXO4r@08j}8r0Gf=|N7^r$A+i zQ11h>d?Fhe<4ob72Hg(57j5=G zw71G;inV)uzCuS*D2M=BczHvO$RW0?y_rcn*(wPoeE2mht(LYlO->{xW$M8MMp!BJ zolGBl8Dks-{Kf90Zz!6SgDRbqEI7lk`vY@XRYQ1>hVsooKAPgmcRQP!F(BlM@ z_r}H8YR!i@Oy)@6-WigMMUCW0C3)LpG45_BLti%N$*%CAM;ykdHpDqgK~c1~=NVg7 zZ1*ot7i&R+CJOfRgXFZAl0is4MehmH%x*s8D8ow>~wx50=3Q^!iJCxDk&VCnHCL~uE3o$G|K)*{TmtXL=o}j&3*#2|CvNA z>Q>-xzGp2U1{xGy_>sRPA}Xz@5S%ujqc@+Wf573i$@B|+Pm`o3`b#|Ky`VpWf5n*^ zTHx>7i-BEkUi%&T-g@K1MOCqM{_nUf^4WpQe%73TBcAK$|x;XDjgPsnPPq*(4`e%lsA1EwoHcX ziNI;wPn;OD8byj*;;0XDh_Om#FqAnxNEvO^8ugtD#blR1_z8H=Vb^=Y0?z6kOcryI zNvNu;t@g2VTCcUX;9kL@wk>-!DE>%qrHy{onCbzIX_Uxh-cfS|*}$u{7o#H_?b4|A z;L1NA`+)=HBo9hwcS)V>$5b#B0jJwATV(KMYG7>D3t`Vc*&6DAl31~orXv#;dHvDw zziR;uaXG3*OSHI$l>dBpTephHBGoXUdzk2vxovX%Gz>eaU+LhzUzQ`DRRRBPV{K+- z9&}XwzC2g}=19T&6i6{^)VZR4nfN7~hqCq6yYEq}LZqJho7O-+xJC`WKe%w7gQQZ< zM5R>B$H{dze6l!oPE8fLM8a)w5d9V$XT3Kq)#!PH@~Y9`U3Iq2O<0Z991f^PSKJFU zMeEnyEmSpv)KQb)9>AcJ%@O%nMW@*)MBxx@pi(SXhvIn1iDY6I*owpSsd!+Lp~3O6 z^_PR$#oaXuU#`O4Wk0^~%g7*)Vu3uA&lPetwCA6qnubaGqW^eB%&?dE++7qb`|7w9 zDO}2sMPNh1A}AI}<5rsMmt1b#ogb$$Xqv;SDO==ik3y)t-C3_&p>1PSue1zlym5f= zGvHO<@{LZMFXcU)DQ;_43gK&tsN9R*Kj*Bja~4$T7)H=+xH=x&?!mFDo4Goe3sb8K ztC)Toa_ir7#=g|-)LWCO`qJUr1fSvb~SAjbHuBvxZeCw94YlG=oc!xgnqg6cR~? zqG)h5SBYYMjfnpf=S7#QW!;%;%$O@YXO+{4WeS%kYJ<~$XSl~*9P-`3HeIbvheD~% z={0Qcn#EyeSHClnoFIv5CG|WtTDI7Rp6c(1nK35QDg#1fLaB*c2iZac3ZR*Ys4ogH zijjlILwn!p-C}Ee4HNXqG4fHoI+zesjechn0gwHylm=Ch&pe^7PP1VWQkVcFM?4i){4SIFdS6j4IuNB3gTx0L!l7YME=iVhNs;svjirm;(nnFw7zm8 zBILPNnG_P(&au{x^@{#Ty&wYNS@G;g&}o^!Eyk!~BAmj5i-QAdK`c|)T!gS*dr+d> zP--{(TF*7VnyWBo<*;9>zrf_Q#Odr)O29<_)6wYiMv()GXi@hIk0tT2)^oImtq@Pup?uu^vJ^cGh%r(N8cTu>a7Oa zvcN%3u9S~jZZrS~9S~mYu@~<;ogMgDvbexxtR1LHp@Z9?$PrJIVpB&z*yNiCX8vGy z!OWRGR8dbs{{974D?sq+5lgO$0|~vGS&3}~TmUl=FZu$_5bWTz>u>6T+Jz|(k7&GSolcv8 zWFi-q+vUEGfk!lv^wmVpP$!TfJ)a6B_GlLhI?qJA5y-s0+?~Sck--_`EHU#%4Vs@B zYeSx~s?`ULvHjLXXu3@%C+-i%J>hsAm0u>xOskByux?rg(MaA!$OzxYam0Oz3JTm6 z>Ln3AJOVnSR6SI7KMh0Tb2aM9wIVYOMWPt;RB8}d%onr$=!gT64@X?r}dq z)nO!1QFEd@W=o>TfGs2@r_=T5EJ7mg;^t6=0{#1*@gd*c?r#kT{rza#luD2~kUYwK zv-MLVT%|kwQ%i@faB+Bo;u3sOfoa0~A>R=ZDhiqTYS1HLsZ_5k7(h*26CIdm-5_8w zug)Zs7F}i_;41g1GtFXE>kmb$5}iyMjF~2A9PsF|2N;V?ifC0*;eT#}Fx({3;LXL7 zEcDR`jDMF!67}HUlj~GJV9~0nY0VW6pNEYhm5rs>yfKNeen1%2l?-MN72A7EW6YK~ z{5FU;3}zJm-~w7nz0xlq8UDrfd^JF7#)8;((c$4~H)?bWi=?n@n86b`TXmw|DZ|~J zns8>N&Qb*$Fnoy|15uP!SR?Mnn&jJt)q>}9g}O*`fp3h zDFLGM;$2U87N`-Q1Ow2KM_gtr^$3&-k2rPm_P0|Dcz{*&!*$S#XAy$IaFKMjHi!HJy%XMYgf_P-#>%B>hi2&_X^g61@ z3$5Ry1wLgwg*p8DdkkLruFpjJH7?-m=kJ< z`7>o`qWlhy*imf#O4#iBkNj zAr@~uYBYO+%ODx%O_?EUCRaTETC3LyH-boeY}amp42|W!OV=m=!~B_J4E->zL*!}^ zR&7JREvF9@DM}5pBkvic3y3K$&LCtK^8OebE-FDSJ8i(wG!A+{Jw%{KFzMGr9I}~; z!Vk&QRz>>!Hg`B!Rg1VnJ9SgjQfF846M8mt?>6sAm_+`^phdIs!=vbg>5ZZEM5=oZ zD{}#fRPu1Xxf4;kB!#u)cY)S*spYyZ&U<3+C<9UWx5G4h5!j9Hdxb1t9;!AN8tpvt zhh*+kFRbF>?CrBPucLZAHVe`(9XHe(`WEoRd4hR8tZnHS#gaLV|8hybeE#%H!MC03 z?T%ZUbr0;8h>Tq0_PoqTuFal~S^pyxJY9Vx0#!*G{q)d>SWn zc@^PC?UjFJZ%lofFUo-;@ub2$S+jLfBW&h0J%Ku0tB$A3YP*U(F4vT+-7Yf*JxTgG zlqi0FuiwT)heqF=UbQ)9eNUwKZ>`Z-s9|UVc+B6r)MGZ*zeps<^AVOY}R^{9C{Yd+Ax>h;6QOUGOlv)$dtA70Nyoo-*lV0f1gJr()kL+`_Qgd=CM zaPJf5sg}a9d(t(S49YDG$3tVnv3O$+%ET{6hwk zjA7|k(IBZ^C~_O4R(|eb<51WDscSR`0T*4Cn_=1%pCFp8dNtDxdcCtRIp^vwod&VW z;QuH$mxFv>{vsq&N)_7v1ZTjIi<=v})$F29uksg9Qt|4U{DQZ8YUYhgUpxw#<=g)$ z!8VwD>i;hGzAwJevp}$V=okWMv)RX>C+cM-@0Jl5j(_o*J4_%V7F}WKO$S z%J2sYnPjB|HVXc(@(m8~t7(1zKw+&4ER{7oFO+0I}L zF1thgs4Q`UDaB3%rDTF*GE1lXWnwEb&2*uJ#1iZ7RJkKriW-USVtwU#|D@T9Ycwtg zA{e0bcX^=!W8i!CudABpC+kIC3adXn0EBbYm?cSL(48F_+Tl1u3C>Bp1mCq~m&&ug zFK}6=-;IAE+O9WYB{K8@n&s){FwSvDoJ{$zq-MJ@2Y_(RIkRGJZf~o&j@D-)xeFo{ zr7=EO=7D}I93$h3<7O`j=my!+?~bN~6q!&_sDCK)Fyb=1Qtc{G4gO3>_;J>)^ka5Y zM~Q$3w&-6DpF!jl8u7wTPP;#<{1Tztlpm-i;RqZ9@mbw*K?qgg5zx9dBvjK}{lHBH z4FwwbPa|)}nkUu^AS@0Pl^@Q-ZfQIeYbWhMF4l;TLcrNCS+!w)V@n8PNyJkH&&?iD;`iyruKwb(so!TYc$-h8mo~0FsDteEDA0E|*=NM@ z$sxV40m(R{%Phvl_sA%3Mpd_83WfeoK7Q zps`o#5I~2bs{BhW|Mraf>C3~#R`S8lY6hER3S|sBwig4SNR^#_68St;c<3kXF{p`0 z8wJ5_`d86;-kp}Q=1YFCAfc)CaxF5`@mid#ut+A-+AG?X#vTeV8H$P4+m@Z}`c9@^ zdp%Z7c`NA}`#X*CpwszkfTd{I1oSDCGG>cKqp%4dk+5e!RhijmbXrEBZ%N__dXj@g zw^ ztSZ%Cfjr-*O1u<6LukXa6oLxhl(r4vJ;BlW@40tV(1d1tLLF(G0Y;uA*GD9-!?2HQ-QIx&df5YVrpF z3`f|P&gZv0{uELQ@<-Ba&av2vIhyI30bxyF9BA!*|^ErY6A0JX#Zr6?R2ggCpE|EqtaS32xoAXUxq!uOq z2Qr9PJDuP`m}dVK$FXA3H?e95{j$AvbcSZL9q~oC2kKNt?RQJx9S>%g2>7&+q}5YY zsA8*bH9JuW=R8I4tO);omnf;6t6%p((dY9E-K$y7{~8oJ8cXWr)zB(A#nfOkTe|?^ zalNae)Jn1Z{YLot9#9l4&i-E~b>`u~x1?`|N@4o0=dR-xh?$(vx5Gb}3|9HfMC^#~ zJWQL=4*Q2g0K}_oIb}PEe`Gf211J;0xEZ~?*rCAqV4){&G@8NdZ=)M^Z15*RZ`D}o zL^F-_(evBg-)Xbj^fIYqqgFbR*yWN?AEXRPmTX26zBKAf41xKiT4*zfHS|Cdq1eZd zM4kPYC!i9mvfSNhv=&FiKNtjmucnB_u+z$&+vE37cuDx{s>6S4R0(VrsILMMl&Wn$ z`*4hU9ntm%J)}B!woe>2G$cVUE$eL_(C5HyY8QKQ#KTIz$34t~&zk{1>|!yN--*p5 zal+9kXqR3hFG>&_OQ;0=lx+rX8m=fKd#BA^NH~n7A`cgp=gZAeJFScAz=st4-C}~o zDRs#L;Ee12%AokC0zSLUCTm7Rd7y{X@9IENY?CB$KHPph`R)6|RDR|T3NZT> zP_U(v86r8>N4Yc_EkBe(F&z<~HqJMWKJw@{?u~q+>3Gk-S1Z1l6zqPK3R zBFFFe&JN`2s4s;zZv#T_n)Z=wiI;palsW!nFR_nTr^WV(r+A+~SJJGZp&_E^tO&r~ zJHY(k;YFEaQEL8$QF*`QciIKuugq-X`CY+{v)xm!3*+CQMe5spq(bkihm+DuEhjp~ z>{8K$9(Uc_L<(8i(=!Nf)9f+gKUrC>+8-`s^%*sFvA6U}Yg}kGI@P}Iq!WV@K3i%g z?0QB~eS^2rs1ps9&0ulcbB-nw{7|LAxL_gKzI7H`fiYwYj>YXjjuu!_^GI^FJTLFb$Um1OAc?-mq5{o zczUgG9QO%63K?!zUJc6+NLAJxHU$%T$n*O9<|$QkiqA#gCMD|&8{GK<3M1Dff%>}lN(c^So0Nr(HAq4!Del$(TPGT&P#{gzMZ z(|NHXw~2gc0oOG5uDHKBynYk5E}uqTs->dThtqoet(A{{C-bnOww=qx)5+Q#*@@{A`Hey8LH!em52V3iU&?CNb6G}iR(=(9 zjZTo6-8$xG{e)+m%l=1h45^8QVZnYq6&@Wy;8gU(EBc=&RV zoJEi;;1h^HXH)+D*In1L2MYddRh{ofvF&;zUIYe}urC`Vod$zJW#HP#bA@h*bh&1G zWWYwr*R_o%F}mFu%Lmld4zuni*IPv0Zg-_ub17E_k3qAuzdx*D0s9oG_B)l-s_`$a zko&Upp<13PQIqo}luPcI%4gnNMOW$ZjhWSFz2Kxh7@9w&3vN9y*GX>#-95W*{j;k> ztpZtDIwQA|c`X3+{j||TXB4NG)6u;?2^fvYVFmc9*lj9Zzf(i7n}h$<^QWHU|K7=T zcD80T9v)?I2>V(|Lop*ho^pg_*~X=fjI!t<>{F58qQk)VX+cEq2UM*04HEoOSh1&VbNjk|OeBdNB?!<2z70mNBK7=zL3vD(W#K@!me0Y1;O ze{IeROP-v&S+#iF?%4Mxb4vu$VuFsaejER7L$D^HnNUNw({bXqQ5{06NlBd@H0n=i)R)`(kXjH_5kV&8uL7u?p z*h`4u-Rbr=e-Aq8guHq;1XFuYJ6XhH6TCjlC~=?om7oI1BhU*JxB6*+wY?)V4VsxJ zh8`Xq&th?(5(1UI-0obJbF5F}k`GvBSzJ0K)s-PkqLf!f{nWVSbF#=X5SRBJEa3h+ z;rT4#zSNc)o_4ytWU@D=C4F(>ccKTci8XZ3A2F?2G`;9`u2-}OLVoMr6dUMVm0*Nb zF~!7w#ZrgEc7}HuYt*+cdf7IJtH?g?ukKer6P+u~zW7CW+&^EzZk$a_OpHxTta?rI z{EEaM{OJ$*I$dt00>WIdQ14I=mcExUSNuuGU9U*O@Vq~yIif|3-`*0y$Fif1oLROj z?j(Q3U}iDwg_teZf>z}y2t;DARLbXmLqN?p7C)Y6*y6M6C;$k+!lk4 zFNDB2T5KpMTWm1tg!`{o!=bCUCd7g8^*|)>%hu+UECdZ(>14b`@rNI*MuBMMu54?5 zpFxP84eB=)A;dXi%4fO0BMzJQEynHCA&R%gv(#ue2V3<14BCIY*YZK2A04rwdGs6k zfxJEPEQYs;xsjlt0g8XG(?j-J$LApBQ-B|15eFzUX!m^Of4U_gHmsv4kQr+z`2A9E!xEV;=O1R^kUg)WQa;J~!&&wH5LEy?qQog4){NE~J2C`EWdzG4t@aZ$Lg( z71)7*Kj81reS*(E%Q*9$6vNx`c9{e0%%B+2^&6K*f}92%urxFJ`uJ9EbEsLPI4!Oj z-|2i9o$!^cIX|b{7e=lgg~xuHh~JYqde~H6U0i&hDb zUvH*VuIX~XHJil*?oM3Xx|gJTApi+_M-`vPVH0Ax{u&%CmAvMIdzBI@Q%L8W(FIKZ&UVmmm_UpDAlP~ zn#{geJN`~(q2^A<&w1H8p6|7|QoT9&gEwO_j+IKw+FgU7!x$lCx8fEYmSvMo>w+vh z@ruOVD=G$6&-Mc)`zlwpirCP<&jyYXLDHxn<#$O?R3$b{LwY8nsssOsC|M7Jz&Av$ zYvdMYcOjek!je*fg3-<9*wdB%ZZVmU0?vwwIHM{5uuT|5?aU@nX${JHt&)7)*eCA+CiTpR}}iMMqYP`%Vh z0+5H{qy=WG@7+;2aMu2qpIwkJ>4O2LmM__`{fDZ#axuIEF{sCx6#hZsSAV?X=_6ja z=haU%beNKcNy^x3&d*`bDU^5P972ebCh^JnnMp%M6qlq5-QJo#<}o)_P_^Y*$b_4L z0OcLU%|BB39(qdw;jur@FouvGp>DTAi5q`aaqcsQs(2hXk6qv5-wa#LU}y(vgY;6v z;6P4`FQf71l%fnm9^)2XFPHo(JAIb(1e9^d0DI6|&XdCNi*`+NvicBDy}CLLXm=tsbUOKWdw41vSbfD{Z|7&yh5LTWN? zoLeyr(k--{ueQlOj=XL1LeOXNg5EhFTAG< z1~MY=e0)xMdAD1+dI~KT7#F+U@*axcIa3|t?a<2_k0){vEV~@gkCd{XowmglP+-Pi z(VXLefbd9&s8dn1hdCSdKw^Za1Yp~zf)OE4ZSy_FKbrH}xBq*7yiofgF9Zs;$!-M^ z25t&xc&GMfm<^)t&2>l(GMlpY9{*gk>Qjf?d2VTS>1@K>SJ*ihOWeNdZU0omd9|1BrgE{V= zJz&P~g@3oGN>c@ltVd%V-{XLYf>sD~Fyes9ST@v*O@4r%N3E_(t%~%L06))Xw=(65 zv4@E`M8IH>ThdqT`aX}5C3-Xd*RoT3Y(|I65qMpp^K)3)#(~#Pp?OW_)vC|)op9BB z&47khov%-^bb|D@F<@Z_*1Nn0(hLej%odmDdna_ysaSA?4w{nT=-MAyG00$VA49lzY5J=bOZl!U%^76G^Yn?S`*U4wqC; z$cI=*xBi%kW7AyoAc-ECfK$~N_H@}b-ez&(Wbz_rYdC|gELw>+7h@6A<%Ak6)xr$s zN>={zHTQ0C%M(~mS2`78)&zW_s9r+1$6FoJ=FBo)UwSC@4{ zDATG{AeN!pacm+;d78^+LA6eskkdFuhY|G8hnVc&*z--=}mGl1S; z6m;`xW7-HB{+(i|VSWq4$M-E?`PW~b#NP!=jwX{?Fh0nAj1ypl1{ZP`Zgy*bz#HcS z^ojf10Wm&TGftzjnQEfV#)#6HShHxQFH<(Jgb?A4R;gryZlX)Z^A^{%1iH;3!QO^y ze$l@bXS+cUhvZ}C*&2JQ?tk8oNQS3JDUH6zYdwOIm<(`vEczm z{~WS+$5QCTbt+i$RTXZi-fyxq8B)S^#tz)ypBX-HOe?+9X~EpmaSNCJ9c|?cB~QtdyD~-6=*y^5%hzHX+1u~ow8_OUWGs5fhHKp7 z8TBun^#>OWT;tk1*{j=2&Q407*Qb;v$5hT!E|#Y(n{W7YaUISl#L~xLe?)B|IGQd{ zkD+E7;d4|~-Q8)-fMncs;hzCV(=$R|$CoyLWlGtrFR8XmrZJXQJtAtjiB~`!BJOXH z&9*~&{XnWjYC35voA?lrhkv{~kNvRFEabf)aXep_)YU9t5HsLDlGGJtmn+~T{*I>Y zj>CeS$5i%vcMf6YLKBwA$(i2An0XXfB&=lIGGEla>D{jpBclgD+j=+`}i!R4t!}T3U=xRw}-DImq1%o%hHP**4?DL432lqj@IX2D5ZW z8zfDg&7K*ke>dEbSn*dMhPH2c(RTEfhu#%4$1@L<)N#`fBg(mcXoOP~$(?{qIS_5} zf9vuzIzH>dr!%pIgkg-tXSXf)8DoG{ZZw~ST&YZ9b~@u*;+t-JtT9y4f}nAxoo?5t z7L~G%36F;rF&tL5T|p;7CH&fGB^yjITgS!ubtS^lM4Zg+?8o+dC3&1?DOE#U{V&CK z7GU|x)~Fvl2Z}+v^$S~PN4av>=StO@*ur1Zl8q_rG(vDJU#CPgYX9Jp-k?IHjuRs< z!L?bM{7K&kzGO+SXK-;ovt{90yClN=cY$&1pR7_AXEP>Kxomo>-DTZ;hq>Y7CY8Ou z*4g7^Y(AcF^_VJ zFY|uW2ZH8E;A961_G$$>koL+D3S|{w{AF$+NB%UG2q=@O$Et!qG((+XzjWHHV(x^VT8eaDA zKAU{z3Ek`F-&ryA+pwFOki4=mrOlRS{xmADAt{ry@4AhJZhcNi zcj?kU+u>_BTf^Qfory~;z@%}M8=%psl&~X77DyxEp&~fo3#_WumK27b4@hyl(vMOT zTi5y`%gg7nU_EZIYJCI|8Q0kKLW+j@u1`QQOm0=+_s{o=fDjU9$APiNOb6-i4sHmZ z@Y-2~Sy8{t)dzCf(VO}G0hd`L+zTB>%2fy0Gc-P$Jw$i+zTVS_#yzCnjl(q1xn;VF$m({#*dxGQdCQrvz%zt&TYBJPYk-#7X@h zLZ_``&ZW1Mnqbvyw$0-e-_>@5R<_wRS*w8_vqU#SN+MewE=QUcg}f*faN?sZ}7gEcK;;egYjURnR$UPX@mD4Povh=|aEn%)Uv z>i(D8;cyLu$Yc<&BB!3d@#e!v<;mIt2rM{MywF@d!UpF#Z8A6kI1z+m0YKB2j=k&M zkw6P6i4kwc2y7cklqd?4tEh}u+ILrFw?3Rz>F#tF&W@KmLD|&B-|+eTerdi;K3iy9 zy9M2ugm;2n&_MR)8poW|?8RKa%UcV*vh8iH)2r+wX>WmWQE2~qWwfDli`iQsEJa4; zhR~P(z77r;b-oYHu{vBaeX&oj6B%@IS{&H97&ycsLnFFFEUXrNq)LQ4-_he6E&KS8 z@$b%f(>{+cWRfCcG^SQ-Ml@NWK&F9BUE`5$vGfBA$)-ZsiM*gyk1K0L8fRoDheDh(!+zf*mhm>p2gZLE?_##Z5Qe=VkzVOia5S16y^?wq=wPz+T{5V0B4nS@PY z1&o#uV2j@m$lgiLAMXCf;da}L{vo&u&x&BS5NpTkdf-qRiGy)~`(gnR3%LQbYSNp6 z%%%v1aYR_Dle+Cr;1<;1;Wz5_={3Fi&F;V3kETxVGSq(;qTV5!0N(qvtv6tXN8GSyv?ej*mP}`>CWA?joCr z_cpRHMvcV32?eY%rBhk!E9u@x629GTeDl1y;7Eqz}bVa4sF^4z*Y>0U$T;tHcpF@UXGKU@O zt5BIPWXIIuEpH(!dj0X}1lsqkvvmtX;Ry$ErAHy1o$!F@F@gD;&*b{&uhe!GKqDBj z$MWJZsN^>lUP$hpoSiY1ixvdC#J_ZkXBs3s7KQ{wG27h9vU?u?oJ?!Y7k4i5&MT8w zQ3D^*r5lv;;(6ton$C^eVO*tJrR2+?Suce1>9QDs35X}x9BewA3Be8NHh6MRpRF1U zE$LoBBcJgtR$%mq#6(xgM+dS9wfD?)Lfg`+{uP>+I>`8ZlF7SaC#l(OE5_?^k^j>3tweg+-e#dr4EPF_ z>V+VSc!qC2okL4%H4Es1IjRM^=ps@9U9N)R)x?B0y1WFn&WrGjQPdLo&CTMs1kbdv|t_oL50 zxYTlgqtoN!BcjzcG*T9Ra{XH`+=%_XLRaic;Xp;5*1n*xFZ{Es=sYb<@xg+5wID#I zlr=_q`1W74erm^xm)Ht?O7g!QblHC4fz<4@P8p!;;J#M>To`%=*R@H9$`yR5SvWAuwsYoc!#pJ-*~PsEE& zf2`jS$~>7V1Kc76%Vt4lEXgUl#1Umr`&glfwn!v ziSaBlPUGLDa!{yh?O9%^M2X%*U*PYev{x%{2^!4jq(3g=RMe=bmfSq%K1F6uoTp+c zyT=@^*6oRM_*FH>wl`1SyPYEv4|?Y?)YT-{g&3+mF`*mJw=rPBhb4fVJj>PhmvsD zD{Ir5#y@{z&YlxoGtjA|NKbH%x$NePPe5bBXNGmDLuqaKT{@RRV$1!>YVF7_YlCgz zJuak=LqZb;=|>Z9O5=Of&*rX@4ib1coM2b}r=|khY^{buu{AjOB5SfZ3%v5W`-gi? zs{yo902Ho(j%uF{q~oT32in>!-cC`Zb%vc{veK3) zUgaciC40A;ChJlWgs2H1~ABiKx+*or@a>qB?V0eW&bm9`gq@>V%{7;5$liH#d4?zsqA{T8Y9r-#Z*Yf16ikl|?Z5)*R69Bak(E-kxNlyI1Q2AnJDC=~)~8o*_s| z7{UMLIM`x+Hl+;OIv?$jH^Ljueup2Fhn1COH(b$Upp!31(xcwJ*hgdjBy}0rprXutlr+8cJ zECh{e$w&^bV9VE)V1i^(j-vQ}p1^Yw=v0{EYOPLuGwC#VXg?4goMcG9Pbo8a`5lCi zU^1A$OIOSoS@FvLU>IgCWlEv!kC{94j9!j~*N(*Nc8X1`cfA+7i3}Z-MEPiC_I{O} zmsm(e-Sd-BBx3J};sT9)Rv$(g|74joMk)00_0Mic!CODWqGnqgXDfOVyXOeYEob1aJ@@GGgGQHO$*4_ zYAReDUFTK#sSOl_5SR36BD%pYXfmyyIGv7Pjq-#^y!lQG;j&vwUoPkAvdl%;7<(3H zsEN_Aa*;n~hOVcJQ-9zu68DFTg3@eZsap`(Y*cPW>A@>ou!Uxp~d9`|VN6i|fgO5oEyqk%^+#;|Uw_8W-H0K*?}H z?&Vg{^PfGK<_zu7XgnCrOTZefc6rJ4(j_P59&m~I+b`7Wi#;N482kMd0QLk)D0`_y z@_DEXFjGjfXYRXdz?)O|yg4(uOKyXp`4N7~S8rfnl#c^RQ}r{|1~Ixcge@NH6T$Xp z5$NK0Ecd{?trgWCbr*zSK;=NuZt_@F3d-m3MKo8bTR!7|PV>4wjkD$XmM`_%vDjk4 zMB2~gzY{Sz)@ykF2CXPhwIvsl3G1|vA7J3F02{isal%&O-G6^EcBs-Xok=NY9S<9O zQg&?)`)-ExUIqpyhtKh2OxBW&VwyNJ24wZ|e08cJBP3tb5>g-#&tcIKQwTs0c*g$! zsmK4+{hwB$Kn~DAi=G!l>d$7>dwrTDs<7kDw+C9aO0@3%A=+L<$wy5FgaM0x6=!!W z+tl7?Jy>?A$&iXzt*s43e#U zYLoH?|G_x-c7^_{MN~(sb+n^&rY`1%_8rcL!6n|M|5TU4j+S<7{FB{w1iSr{Q3-kT zpLH(6m0_3OcdK9jPV%p^nCun_znwW=C^Qu|(|;1Ny4korU%{ad+XDlsPq};%1^zWc z@J}{U7orA_b2e$@G>c6qx%{4_DtluhP$r0?ik16L`{U?lwlh1`NC+Oj4_gh?e~#m- zY$UuoY*BI#jI%i7y=e)_(X*vZM{3>ZxuY-k5{2)y1j%|3(W7lQ$%~ zKOB^{MQ+yIPUle=8DE8WZRTl=RobFupajLe+yjpGV4iOeXCxqmZ{jGM1huFply07Z zVB~oM)9h>FB#n?XFe5hDF0p>(b5`8Ov|d$G`mwj-z6x%I^(=fMN9DOOFczZ{f50+~ z(zC0Z+n2dYHRE`s3Rchp`jC$;7X#lVf(S|T^i6O*?dqpYj|*h zZd+kXYwjf1Xf^b;sl`6}@cVxMZy(GTi*f9!*xWW%1FjhXlPfw%g8j*yF93OOaQq1e z!=zI{6RH@Iaj6Am`;Mq6FKhn*Y;@y8b&yyc4K$cs9%mU$yY&*I5EoADdPcVsn~kPo z7-}B7p2F&Gu2!YR*RY;bsFaTV`A4=Yfdq*bbG@GL>r=nKX;iI`M;W;p`7UK>98&pa z9{_2x;bF<15mp9z+-|6#5|jXc%z#GqScw}NcayCh_KmR6Xyxv2(X|lqUPl0!O*eZf zD2Yi?6N|-=mHZfIMab{)J?-%KlfBlF>I0v6Qg<@_wg6+)@IjT{~mw#3AjFs`$!BBBig{@s4Jw@rCmTFtC?hfQQtw zjayws5v4wi`hn;+Vl9#aoNrNc3-3hq(KgjP}&*cP>ha zOlm463%n$c<54igE&-QkT9o0kuOp-~{dk|Q2@FFz-G)zPv$9#lF@=i52%zSeorU}$ z*B#}Fg>#_nD?8HlO{{zupp|D^bIl&)GblZrJedm*v)#drDe4$wPoCNgH?^$J>BOc= zu)%0eTlO-CdH}>U|NaEetj+)3rS^Gt!}R!C3pCrOq5kdtzh=9o_wJhe??ot@>7gPZ zEYr{Kae$Q18UOv9I9_SK8`*zTg&x+9aH631vRVvgw-DqY- z5gvI)WXn_t8iNvfGDLDGZ2H-Bae7E)-{(^|C8o;@qOgI8B*W}9c=cMOG+;{nA%!cP z4gm}|Z~UE6q6~PyJ#SrDe!uS@sI|)?BR@QPyT6|TL*rLCRAX!wTJ=ig)~zo}RjzhM z{YtXt-q_`8#n%#aA>N=ot`1@B&{}T`Q`I??Cxp``{9!s zK+7G-(}SXBfT~Fb>RZZaiejZRjqFtp{YaPR6w>ZCmF&fb5JbulgC7q$%-UjNVo@eb zb1t|*m`{t4T_Th6v-{NxhTT|-Bm~lq)f4dgP$ob4#V(75-ui(K8cN(Nda%*VNL=~q zs6Zqw*mykCC7qv22!iJBPA-^3SCzr{A0Z^<_h3kR?=LWcK|$;g2!x9qHuL=;=`5a0 z;cGN5%b$7=kLynI8x;zF)_!(M(_>-yJ$!ZtVPf@K-H7n;caA6aYaJ-E${Q^{RqC;a zF0>Fzov{o+z(f(T3PbsKTt!F~;ecKR)nmpcC&x=N&}x@9RH(XQuBACfX&(%-BfNP} zzkuoy1&dzueF!2}f3-iv5AR3BuIHOX)90bMPXMNZ0965+POB{&6sh8Pk#x!tx4UH? zwW^QRrQrXv0KqT>y><$@d|0VGUCT0xQzBA@T~7P4!=KLAyKsO5N@AflmUT#<+fNu% zSvrN44=pC*h{IZS0ey4s+*4>2XtiLc`h!j8>-1kc5`TEn(;_myKK(+JH1hBk2u!yu zMWlI&5l%OeC^ALnu(Mt~QT`)fIFD@fcc)Xi!x<0K&e67tMO+M{wUu?+oOgCC4#wwz zVjqh*q}oy{$v1*QrzL_miULqXw)3?t)Mp1Vi15jsb($>ZjSe&BG1J{XUMTVX`Raqw zp_?Q@#4n-o715k#N0?1^Gej-THU$!KZlki7J_1hr2?=s&k|ek_UvuEvTwl?Fj@Ae} zzHn5@ACtD2Iep~vmq0d)k7u@jGN?&Od_19}1fkypTV7y}9)C^bkV39#7#QV2&;T`2 zaN0gD=(ubM$0!fWC#=8+ka(*ap#}Gx`u;NQA35I5)tSE ziZE+z_J>%WP3d|W$mONT(x^frqzj<1?TtZWojlyXi1o3WXV`AEO1P213qUWoeqCp# zjXcMOHb2u3?VchCVuE3u#w0E=+Mx`6H2yPy>z_Q#->KMcjl$=5hdiP}F42`a$I*hV z|D{EDp%0qHy_`-r40S%;WR8EtL1r#l_@^%Hfrue2mU0`Bg-GJcg%NN75r!hWVPNYu zjwmVnyrfS9M{@~8Mand!Mu)A(;*qN2EDK!fa+7@=U@?sPvX_)Y*W0j3;#FY3`8^$4 z@cF%|&JQCCee0TQwBv36d-*f$V5X>(*)73?YkEH-I40gUiGZv6XJ!4a#mpe4P}08;CvCaoC@?<92nyHrxlo zA<=-~K6ZZMF9!d>{nNdpz0i5d?NqZ{L@b6R*2{nED-nKgc;8gW_1>ty2;S23!?>AY z(sLfqcXR9LUfDBnMS|NG??jOZla~j1_8BK;n4LsH12g6m*oIj5<~beQGKQ|_XL^O% zB5=YbZ{=saMyt4(jLNbq>h12AP%l&p{U@+U%^fjBJWvcPEh*>kGS;}^c1&Q1Xy#<0 zlpofrjdXON+L7;SQFTa!m1F&CU8K_(qApx)C=5TQ`5bxWwdHPjuKwQ^`2S;q0^&BH zdb&M=9-~AY?$7QIR*H}sUsC8_6<9$BeCJl&`#$f-PS~K5CL99G=T@7L?DlUmSFEpZ z(Rpp1sK1uO8J5?T_(`+|2so_*)$NeI%D^!TbIw&?Q$Zn%F0@hLB6AYHie`}4K&_bn zUc1GLZr8!USf#y^yoGrr5yBPf4v)70o&Vlkb%r&T^ndosgTyWgc96J<9|~XW=bSo%56VV~Kdl zX>&@!vu-z&cg#P(LcbX-&~YgsP>64gTF&hAgj}uNF8vb!v_rmcI7aSlRbM(K|49UB zwYGNH)V)#3aT;e)RqeQ7nIEF>`)XEN0lYQh_1WcH<2%VMTt?k;?!ED>m`MzZ#OI~u z`S;)O%x=(tG(g4s_y$@ohf|GL+{N}u>;M{BryX6RP8ZnTvzpxxHxMMJf9_pKwTtWdE>_zS&GhpMqP2ubJzZ5-GGmL>bdCC|aRynq0tEkQece6Fv7tY*Ir zH~srGo46H01y&eS>Gm+_Lao(U9N+J-$}%XdW$4SHA>O^q;SFEJgxs&4 zzz!g)oG;ykOB|lED8ob~y+0dljDLUWm0@zS*P2-Qafj-$z+jR{6SoltEZE=(X4$Ph zW!5QdNCS~V-*zu-xmsCmd{YMc7PD32C^zkSz}pYX+hY=HXPUdyB|A`{)pR>SnQsr? zR%I$Tf)nDkS@luTg=?Xxx-72_t^4gWLuhBaP1yk?O$53RBTVK;ua`TF_$xet@0y$@ z=BnX`2M57F;n9qLoRhQHYQX#G!XdVojS{fb#98Gjc?9g8?J_uW*D3+N_BdSl)iX+= zLutkws)J$))n{&0&{|tyXt8^kKi^L!Z=wG>S)og$WE5(&Al9nP;F6VWU zBbl^RyT`SedVK2KDt7wy3nWc7!OGj+sSf^>7$oNnt?QEo2W;^L?uZ$l8&!h}80J`i zgdNKXGp3Lpty$zEuQF@A1mBa#-30?NNQd=)F>1}Wdg>K}&TqS2kTj`-$vmLC{okq< z;cv5CvdoQ7>i-tCw?|yb_pIGMW)=M4PTO#*G3(?&M9Gk$5o;cC`C4!-E-tC)U;9@hH}g7m^uQpHD*4d-Pg{8}$O& z*_}uisec2yvO5P6BuRMgBX*R;rOT@0e7j1%NsN!5Kb_O~V3H%3I@&Aj_JcQv^zGd0 zG8N~0Ia?dLxzw9>#jUSvM=6W-W?}CG2F&vsnYMeL*0u9i{(FUmFa3XPMB?;yXcC-* zJ%d#Ppqx#3CQaaRqV!HWBUn`R9tyVCc5o|`udh)-V_0eW36$;A-DXbiu~`tGm(m9$ zhC~8HLYTcmd&o;GiYXaWiPn4KTp6-Vex};}x8b-aR2WRKgmrVGJ?Nh-s8pmZruaFw znhPA(QpN-sz7Ydd>A|)inr)8_OaEbVyE=)3Yddg)QObVgQa3$FqEdhi6Gz$PnTH3` zQ*^kfP`OM*UKp->n3ey-*jqq#8FbsjG$KeN-Hp;xBHi86`J`Sq4h2LyrMtVk zJEa?>>l@yC-}}GsEx)yXi>0_6hW*SlbLO0V_EuC@O3AcDc?okC7|>&)gha0#863v&ZfFF;>hI-Q+(s|kxXNK1O~J4dBE zFeQ*{L621j8RjH7`!2VL&XF{ck~QWy7(a!N8-4Wo3~^TZYo~D`Fp?BxS;oDXPaKa} zvG*xTHW?)jTO{@a!zuNGs`7`+-gMDh#*S$!9tSt)+#j#dn;sv2NRHD;$4Wxca#&78 zyT8xX5K3N<9V=EZ4$rmQ4$G&6MMM=nCqM|AZFHv`Efq1-X>fTTT@z>j4(pl2_VEK= zK3#klM%??pgyOF_hW$V!RPveWVq)kppnObC?q?xyG7H+-Jv-ePW)7W;@$f8tY=O?h zRYRStvJSHuS{%^p7eofm-kNrHEOkx?`PBIZ4yp!zk6!wKL_x7Xe1Chnw&uKyM3$v@ zf3tnKZR&xzXT>>ecDZD(=E1u`y zW9o@ey#t~wxcEc46-x6}BwE!rL7?{l0{>pK@beegY@b+qFBOo}cZDWliOj-Q<`y8C z@kUqc$&T+qUjVfQ)sszdHdfQ?HPH1nstK=L*%NZW@GR#qM9PJS+Nz3-X%{Wj!ewTK zLh|j>gtzC5nV+5JX=czgG&YXrDp5kWD~Ww2qb4|NHQ@4Zcmtyx&y3bSk>~X?$-F1h z(0sPcHS{uBS{;=3j~CxLKM04qAIvnV_!xZ{#~0M-1NKT^fu{$-z4(a8^~Vj4PJEC> zQP}iQxDbJtc1f+;NCev9wJeVqk!^0WKi=R2nu{=a5Sj9+&&jBp_B8w=g%g46`*PepC&*xP72?VMGSLf%D+u-Jv&4IB7_lEp&%5xvCHLy(`>D&{84@(|vj5 z9Wiw=SdqzA#9q^_h-5@0z^vCG3aAEJ7)0*GTJ~sL87bWcoc?joCEH?Z^*p;Lj`w+w<4171y&@x$qz&COmh_2`(+*t&T&M$b21P$6?_Zerca zNiR{u_NiLqta{v?4mt*Ek*TV%z}^$HGgocp`v-q4Lu*hgdPNwLj?xR)=SiqC$yMbN zouzaF2|9l@^t6vJk5X?}J4GP;edL{U~I8VM$>mPcBo#Ti}uHcK^^XJU-k; zph~9cb2}gEz`Pxyy>&=Vc&((YGPdHtuzaw~VJP`H$W>Ye>p4vNTry3d+Byk!rqPTR z)AQlm!mzSc8xh%;WwXEj1)engvhz2Iv4 zg&4EqV5t(Bu#M~MQNnr=ka)B6Dv-`hO&Wk!p0K|e4M20~Y;<2H>{M`R@M^p9aRnEtxizTIsg@vWGLOTE*6OZ-W|O{9DCp=Y zY{gFF^ax@xphuZ|qJuZjm^h5=~ga{|@Q_-&miTVuH zZy(J^`&euRu2+%v2{|Gc2;fmChB=-`vO$J)PM}i-+{M?3miYN|-)F>Q_guM&>|K zc~wdB(U(#Qxsf81&Yt`cS*|T(iEN0Hr4=-4RHoVMp@RD3pj{EU8#PYPBj<|JyVZ}| zVe`#Y5lW2XL*GW)35ohHF;}&?Spy}xCyur|x+tgHz6<%Eo0D#J)5}-*>?UnfgGox` zQ}3TGy%P@?EXAZY>TvyYK<02m`=j6ZreVrkTf0RExx?906n(7>N2XJt#f59DE@$}1 z+Fo_ODX-HJ=GuPMuldgBQ%_-X-KXWRTA0)Fz^m(JoC-r>S5~Aj`n(T+BV1&k?e9Dl zTE!9r!-ZN$6%{%qK`y|wewa6&bINvT-nk6k($-4tKma*t>&~O~qvpqeHnHI6r6v(Y z@~qDu2hK|!i^`jBkv>3M5>b=?I&bEiCXjHQes~P{x7_b?f*G^^`i=vnRzs$fJyN+; zSS)jrht2gcEQ#xQWmV)&kl2)5oK&_c+VrZ+$yzNp1)c8vF9~Kt-E6;SzI1mfrzRPV z-60Ml)H6GKCMvbjoBKb1&$ix2i4UQT!^3?0=Iwr#)H8q9E?_JuP^$m}h7-A)KV{c| zP%EYIDn6jER5ef8D0T}^i8+l`D1^=SO_@M__-W*eabW9U;vm1y5gT$e*O+jZYBlxg z`$%s3>LCZ}awZqmuQ5&Gt=5ai+e{*XWu%!Br(f~t**_9|@f*{Tz0Lg8(?#_ShKqDR zYN;S1)}XA}rqVu(JaycSm5k}*KG~y0Eq-)WdMbx-CPx0M1}$43W^&W09`tKJ!Y454 z3SI1LQnM&*dcXbo!FsL=$Ih+-673(bzA`|)%a+A7GoEG|`gpKPdCLm)#|^t_2@{{2vPg;| zP{Sy{?zP8?WCLBJa^#)8qe$1M8~*d!rudUiAS@c0U9K&s1i>w$!tkiL=TD8v^z;aG z%s;zuSufcDXYI*E7u?!fG;D2UPtHVOd3k}YCDx0B?*<$BIHmbqiG*MGLrC~iD*2VS z6gxZn`=LZ#!0FS9LaXp2`a~Rk%&$2)&hS-2cWwZJBo7WFM3^;=@mX>pAOPZ}q@oKx z7vfb-1CcowC<6vT@d8WA0N6m(G}%05HvaxNW?BZ43cz#75V{Y*JWlfq2Jz?ti$RN^ zlKE&g$8s@7kxhDE8Pyw&zATKwRsKF=5S`(~#X!1IDIwXRb7#jqDMa)XIp!Ns|tp1tJo1vIvOk`HNOm>-ow_ zC=28JvkMZlmnH44Ch13_?_5tsW3>Sb!MFbMaINJ*WNb?+#v@4SFyk}Qaa$+5WE4eK zh5Dh+b&1)LJQBgkGs)SC4>3`GaUXb3^qicWNZ}*foU+cACV&dyI_B1L{YnB%yT{}adG za}lo_F0}gdXJ`7Am>FM~(5No2Go($F^uaQnI=d*%ge2vD3u>y zpxR!k7n4D{LUSS7ya?@uANYrSICmThKq;1 zw-)8;$o`1)>Ek}bo@JQ>D|%l`G#mJ@-rgr`U*0YMOrxawDMLw?r4*Ch6S}3APwqk45%g6FSiN@lM@qrO~WNR;D5{0Pd`l>(T+8-)^X3Ybz zs#!?{ygoP9JBQ58EwqTiXr);^^JR9UEZ7LzrYpD73tz13*PvWKZt-fYd{{e&_L_9ckZ_-J)0!}5{@=BI$`T8+E6M?r1cFs;2wngbRqZ4;Pp2E_iRwKfUA>Vc0q5I?SqBcE8`1_;VxtZsxd3qujCSRW8Vwly!WWKST6vxAhp^-yK5b_U$(nm=? zT&UvEdrqHvvqW3OYRqTzk2X&SZ8FeP`Pp`f$w7Zy{9GyDg>|9U87=MA`_9}?-JFaN zI+k}Xf1W9IE3EBbBjb(K=R`J**eo{&IuddreG>yjZpC_W4k;8)jwSEzACkb#Gb4Gr zM349d-YHNDEex3nJz~-qiI>G6sjKB-Hm;(u)_oM-9MqY zvFN$89sitaQ^^(x-}T)R%uD09sl|x$))Tbr%hMT zxLM>oO|~~SinyI21TA-cFq_PxQv=^d_nF&>P00J(KNEFl3-ieSAc^_yyA?(>K?)ew z9jlPhnF>e5AB`^L3F>(oB#hrVu7_b%@I=XZ#v0u(AEWx{@*@CQBZAAH%J}g*%{~^` z(>-II2A!-_U4oH4$=}8?2&#Z;xGwJ6D@?5sV9HF_n*<8{ai2BwBU!`^RkDKjRTlZW z6Xo2DDf&QxJd3DHl1A=a0`Pd?KezF!~drcqmjrR5mG6*WxR0r1Uw0ly=3DkNk z_u4FAMMr+&T(HL8C*X)rlt>>Iz%_Vr2|pyCGFqqW&I5K3BUC(v&50IQhYHSBzFdOg zOf7!qUk0lbcyB({&}B~LDGlbHou5$2WUQ$yF+Yh3Ea!BEeee5j@WVX;225>mk4I8<-}H*vT`aAH?N$+nLfQ4ev~zWJ1;@nJ z@#$$-2<~u4PQEHFKQgH`@>-xC11zWDOt;pvG@z+QD{eaX{Jns*G(dA`c}6#<7$C~$LM1-fp4 z7UlB-edkp^xwH_Dc()xg(SMk(Fc{&N6RyT;LpxDR#{FBJylUGB%MK7waoo(sze z3mY%6{^*`TS#JVIe^^?iu>Ql{wXfa&0{(|4c}h4(v!Ub=XmD%erh0=NLwlVLREXEK z^-7JhHr2ThKN<4c1b=M-&CiwG(DyUI?65n=N8;{;PH<~xkCiw}QyFP2A%$+X@Hy*5LV0}hV) zg03zrtz8~b#K&`5VXM$V;aH2oY7A52%TgmB^#%SZC^-tN00C3tcCVp@FF^=#CSO?soh zf&Sh0Vk4pHP)guC*RzaDzBubTKuE3vi)N~~zg@RKVu#Bv5+RZ`C$jCbBUw6t;$qDI zgRGFMG;{z1=eKg>&Jo}HjV7W3)&86Nh-G-Y!9Be3nQAWOo7m=WS{~i17euoVI#?~O z7-jsf1@85m*@|X|EzS=94~4dNBf_o`GpHV<-x5@_v>d67bvmoW6YP_Gn#%r!Z}faq z*?i`=K6_|5{ap6&pIiXTcKhr45Y~%VPGLztpKX&kZ6;3hB;kN@`u;9$>gmn9s-x)h z#7g)-jFFM&qadzBFLjOit-sluf{V{?9H|3z1dD_FKC~k^MQguI0$up&u^lxtS;SsmbMjHx5D4u#piI4Qy3Ts{3?qYE=a; z(MWk1y6&t$cz)bj6FYc#t)Ra(Gxa{y|E7t$apR89Zd*|)EUdrKL05 zC+1=!{;)$2w&Rx90Gy0Ng6&+Hrt#-N%~lwABQ#(=T1UX{$)!RDo_6VtM?XsC!S zNQWzdKQr?W0kQAJFMORJl2GI=M2eVwu*T2K6r$eBeaG9M(%EnDy6?;Ng3D7}s+2rg zYcnqc;>EK%OnMfQf@Y`uSf?tP9yu%+W?$A_Vf?wR*c-7u-!aFHmzhWtW}snyycf9F z;UoLvI9cFuyxd1FKSkvro@et`$L}RPKJg~rhv_0dug3#4sr+T2E6r&;`+Rs5BKp1& zsHkIR(kZeCynD9*N;0NTtlaZGjtO&Lznp)RgX$m{FC41;kX2(2oRiHAaC=( z4fK#j>caAV+MmI&o~uCEFq3fkxpQu-paH8V7n}O^HoTYVMnzr@AEMKBMQoU%-9b5PFGFV?qgyD*L~W2 z2rJ9R&IWlX;wPr%8ZVW;;qQzE?__wcrMlO_a#LY|*bw0p*{bD<}K@Wh5p7E+?XJQUQ3-{iRVsC;D*2)*|N6pj4X$ zNTQ~#45g?vf`aChIub@_@z0mOn*!F~vz(iGC8ye4$P<^W}T^NrCWAOi2O_b!lJkE5;G7?MD=nqkt zXFx21$>iqd?(rb0wdDdzKUC-MfS*p4%`D9k<3W<`m@n#)ZoN}$se^jP(Z*V5s~sta zmTKy=+;rBfMi#p$F&~J|!9{5}tub-Gd(*=X?T1T5G}0b7CeMJ-o|sp-r`yT*@w;8W zam(f^E#^_r_X*a{hWRCCPEFFo+l>zGIciMLF8;Lq zO5&onS1R5&JNy9(K9qr|&&@?_8BWZn!w(WU+Vx{a@$eRF42d@flA*Ws8b@1-q9#IK z`@)&A_|k&%Ik*%Pu2+FF(B`f-`>iq4^PNJx5jotKO|lJ$R-LmZTk#QtZ^Y#_gV1BT~@c0hg)O z@;A#1yYwHQp<`prhSvJdlM=T%qIFQlD>S4H$ZE=KkYAWQ?=DD zCm8cM$9c*8LL|uOi{Ww&dC%QjuQGv;8v_B~)e2VbI*%f0otd!jLac-}b$qdD=F!cC zyJmyNO^tpV;AYC-$6ck@JbwR8O6K66Q}rv7$y$qu+XHU4+(e}5UBJ<;K<_33Jn|0g zt%da!P_BuG2Zipn&0q5_*BQ{ZO(WjtxB3aqN^V1GDM0>oOPCS4!#LSk9~nAWItZrZl_kkiG!yJ56YMQrnkO zJr8G)E~VFezFAk#u^50?FY&AOJO-6cA=Lp=ZsTrinrwCCF5`LNWctIedsnJlg8uUxxB=L{dDKp={xq-ro6s*LZ?b5wL6EyzqbsfZSoQlL>mTdrYTD@UiVtI)w z^)shaom@<}z$2rf%Js}Nk;UGR&OGUrJ7~!IXcc;iN3KQAy*72={8RmAd*TeZT1k1O zk2IPoWKIk&dS+&e+8-_H2HAev*`_zAf|0%BAATKQAjPiZZ)z*bg-5vX#tER zR`-k7^bx=LQr_}>I5*K&5%ZcYV>$4GE{CbmKyF3!M|{x=lzV==6zTA=I3HS(6A`d? z5z4-yY!RAmfrc%0t0ZUoX_c8&@Y2=|{Lf9EFxe(Wbg>0r$Gg+Z66bu1L;r2~f>s{fvSuO-Y zDVxJdA;9FB;QZDf5pA?yos@{z^eZdt61%4x6a}R-($&a9J-cC>D0wrl`(f^TL$%-TQ(hzXU|?Mr>T51 zw6<&8wBE1n>aN0G%Gk%+j%9U@=B{g0SuhguR=Do<^FyK} zgA4*nV^Dtn?p=QuMP+XUony6BhXr;G^EmqVnRcPUn!#ut@43{za)gg@>YdPdX0Vfd zyqnORDAbZ#Q>!pMgeVqhnHcw5knK{q65z0(R~@yGf3}?suVUP{znl0#E_-(JDJFRy z5aB+2a zm%%6YWW9^>?agPF*QE<g>Eeg!wP|6JoU4V_}z z+|9*2iShV`w>9)bEdI47`U&op^=q?4FNx_wkypi(?M zJ(Ze;Jg-wi3MLEQLjXVf`0NaH2@b-qs8-wPKK1Y8)rg1U(M#j>xuBUaaCfwHfL0$k zbB8}OkWo8i%L13|cUl#8E#?u<_rJWW+|KtbpvYhb zxH;qO!#TMdRVtH?IEJpx#81)VdPpXDISXOuwccQFQLFa}3{gPUAhJJ=+dM!18vx z2SzCM{ta(e;y)1Q(sdY=6h;Z$4s72;1P`Xdk|cqf9I#`?+~U4s-uGOa5Bz@tY2jiG z((fv#i_X=W{J|oXQOd$!$}G5-D07k*!opmhIV$SBGOJD8wUZwDM0@N~?J6 z7BymO4K*Y6acb~D$wpKf**(Nt+V=jgpBZ!C zj(A2L+v1ti{X#S_>~)`~$K`Jca!l z^GK=OtApy3n4C1l);l{F!mI0?KmCtoBt+xQcc(Hao#~GzDFci1pdqw|@AR?q@vf%w z;Z}y-q#%4RT-AZc{@ruE!wevf*XT2OU9B7)vFApzMbhXggXj{L`V~|pgUYgU=AV7q zSrWnKz_Lia@oFU^qb9c&U8A}gJ(mhVs^zb8kW!S$kUm{Dlx>s##$b9%fB*5%ad>q1B; z#kuaROIPh^3SU?xNsHOkarsG)I=#XMNyQaaPJh#{sgXK(>D`dknvFD{Sy|F-V+o!( z&v~zE%QSDL`QKu!97Q}yLKIF|0BwcHmp_*;>t%44=WT)7%0sdKZRvC-X*nNOo%mzo zsWU;tuYf2{Kn4e#yD9yg^W6JkI^x z^SEi;)Mt0|7L9ZqkP#!AJQy zed|&JIzFKwDvuJ-Co#UFNkNd@5g2$uiEx3nX4SZ}PPa}YCzSPk`MDvUCxOVqyDzG{ z)A~yWOX=uWVVBX32U98a_M7{zV6{P1<2k}HA1~SX%^tMZ=pMNR`+Co&MeQ>@g6@t| z5=CfMAUVu3ZE|@OM^yOhLEq;Aa$2X1V-F(=o*Pu3+94haoIt87Qv#M{;c z4r(8f>9pS}Zw5j-3=*3+pEv7PZ1&)0Kd#xcw$ znoN8R4;BuJrryAVhE~<(@!Z7*ra4T#4sY_K=w7m_EphFPA#t})Z2!zD|JH@J6(R6o z9*f=w1)nm;V4s*zA#IU-V1IbWgUzTlQ3$ym%aVa%GHChoTH83osIi7Fqnw8+qkK`7 zoVv(z!oJKJXsgL0zhj}Fdeb8Iv#(&fc(BZr4hLW662hwss_z1if7qL(?{S{Ld~N15oxR?FqM_*3heJYpo8jQTeV-x~3zmfG2W>OdS8Wd)rTSj? z)Kl7QD+ct6B4R;AJY`97bsL_E9Rrsu3$qSANzBDc+9e0Qb7Hd<0uNWZH>vWk2(S{7 zP*zT-K8(FN&) z3+DY>CY^?_nff$hwWk|vIK~t#d5UR%;=NNI`ZkSn9;UNaxH8bM@}=zx?FxZ()VnDk z)LT2--+HR~#s=Lv_9)qsKZGIED#LA6yq~rsq592%>T`)vr}Ss07eVSHlFNF=LLuSd z!sok_RNSf5GVe1kGKCS;EM!ojwBW)iW%wZVS|le{+Qs=QDN2 zK@FJ!R`T1W?Jic>{@C*H11-Nl;2N;!cDDIK$y4zxvFXuvxz;~l?ZpbUgSZ`PF||X| z68F|eFZC8$l6BhzW_?VPG~qAEolt_Bb%>K9R@RoCxv6hcj}%l@vHRi~EuFl6)5MeE zH8I1PZ49OK)1?hAc&^V^5!rg*Js_Uq_AvX1j&p`O`d#A^R}?`W#ZpXu0;wY#2kEYu+k-y9_9JxZ#w>25?sQ=H7E zs2QeHsWV1d=?R2Wt~#9gl8Z&l5f_1G-qn0Rc8f-0)Q~EWEq5I6$QSb`AoSF4`YXAX zAI&{dJ72@-F9&yQ1_Q-DNQr-_w)|uFlBS?U)F-7Yro+Rcka}JrSUBV&A%78#cfKo! zhlfb$3yd}O^;mB->}DRl;|>gIzDd!LBeC1Bkv*cp2D6xeKzT`i$-&*3UDPH_Kkr!RC_j~hTK9S#yyw2Go zP-eP_+%j9X4*SoIfuE&h6f4j9VW1NuQ6zQwV`G?N;4rFJuum3}vbn@{-cH4gzsV8g zE>X#RZ3G6`pqVGCO5dgIc+e`fHG-fC6);Xu)9D7q>pq5} zL6|fdGOFoJP}u%iG%8Yd6luQate+YPM_F~Ug?@!KB>~JV2!7C~I&Ka((DO=9p(se!)A+Up%QotNBTf7v{M**!qtYfUr^GSNuiqfY9Z~0oMS46_vp?oapN)Iwd1r zPTGD_RtZU%=6I;-(&l&pcUou}+7@S0nN;%d2)G9;nDuN~i6JXZrJ*h^_O)zlUc0>^ z-A@+d(uk(NucYXdDxL+uJbe*QE)UP#*chiI`U)CYKlyj9U_g}0TrhOAU$AC(gb=FJ zz9bcJL;$3X2;j2NmY0$dT*BBE6p~OxVd!_oP@m+n+~~jy6q<#nkB0G-snjmDNlCq< zx?i6J*Ersy(#WQUNo54=2GEYyxV?1*cPGCvoqBr}u>%60+|=;BJuX`e4ryb59~AJ@ zFNnE6pKDh^zFLxs1`%oUSa@GuA(cX|O_^~phO-aq(fM__C##J`CQvL(jk*N$W9jWy z$8aVp3Nk5tb`n+yl=T|DexV3@KI~-PKuVcl;%Ow)h&$_wQUy#ZyxVU5?tU!PJL}8k z8Fz+}E_12yhMZ$XzGi52J8uOyjz~%gCr~(o25YzttnH^d(n6DiL`tTp15WF6WF!q( z=)-fZ_Sg2IPmclJ4esIdx$E{Qq`&zUbWwy?^S6z1CUXZ1VA-Vko7%x+V0$!*$=U+2 zQgrY2*~a$fl^XOLyMAIoRwmNI`t+8(ugp`(HjYoQYV1zf*i0lNU?sv=C-=DUw#TrP zGDMZqu}d?+&!5ip6fDbyGhI(3&VsEvT(BNn%CwcRKhwx5oBtYSwOWSrRw&r`B$?a# zCCJU9ejC0I4F9RM5lp9Em+4C^w$FLvRLF{zlOOs=pWi!R#_nykgDP$++|7432a>J` zJS#iav2e@^_cP}_YkR*~G*bT6-Ge{|nZ9A{-tcI8>yM&g1a&($a$zTv^Owh72T3GJ z8<*7RTuvw*LHGxkd_q6)ks_h~@o6EI@Y$OYu<3JcqcV62-E^DyB`6LUxO$QM;-9@F z6B{!wDNq#(Ga3w#V;E11R}x_}`a{BveedQZ*7jJIML=jH2z=25-+63*Y2vFV7>v)a zyu4WCeXUvh{OBR|x-3wIwsQ7yEsHC8u3AY`D3chY6+HPu!nSdNZk#uu6oT!YoI@F4cL^0DWvj4j(q)RDy(U{PU_UdFQ7kLyC@8=dcE851Q1eh=;9c_{Qd(M+b%b?A9^AxW*PCs(&h*2&+}- zS;U2@BD9e%O6&3Pu@{6@HfR$|nMlsTxb(SJN)qA362B#*47Hn3%FG6h>{bhP8eekR zF8ew-)A|qBUmONrgfm96>S~=|kBqJ>W`C0Mxc-ALp^&Uv#Y~^Tq~GdiVpF&OM~ku| z1MdFejySx8TPRo%2hz80w&Zel=o$Hiol+fW!U#GKQu&G>h3oJzt$*Mwpi*lBm?zS_sA z*13ANe$C?)r5ejp*ROCg{|vSs!-32l>10fLWh$L!N5UAh0oI;PiUX^~Qe<3aeX;7H z1IIyBJWhf*hFGDryQaK@tSjKmYDU>5FA7A%MryoL^xwelbJoDUmW!m=65^G%GmGi| z@&>wz`STm4DhU{{eUZ!fxHppb$NYN2(kBaRpYP?=Z2U8YNa z^+C9^j1!zmC9R$1*3%?$)FzV6{0OONMEnRQGPn{a6kl*IL98@dmF3@;US{`=P#kTi z*vh*8@}RqPJ!hm|8`ppRg9OqNpT&WMW+qwZT-t8LWB+vVvDX<1|B=9he9pN~mA zC3LR$Z$v}US0grCVxHcre|)YQk?e?X-G`Zn!{G+V!5Qj6SBmc64&H3C5Zr9D^KAZF)rjEoI z2CIDH=vQaif5L!8rGGi&l=J#^1HCMycZI^N@PPBFwy`Sw) zlz?Jftz&ACk|>m3HXAN)=xbm#JtOPy#04JMvW@;YTR@F;bPC&@#vQu zBlY4J`*d^98XEP}9*;-+5Khm}08O9@#?kV6e`5HBi~Tj1=^tOxaAP^O!&`dQe}%BOyL?QJHS;a2JB z6nn~G_5>uR=HUuvfE%oGN+zhY=)bQgp3;hK@AFrab8o_~R328J#JRQCBZFX1& z)jyZ@GjbSU^NB9WDFX9e(C3K%J&P0(1yZD-4_rrX>Eno!T8?b*TCU+%60ulc6-Y|l z?7RBY$puEFDkg15Yf^zs^!AeTPodjhOxiYql)39$9R{^xqmXwzWri(ZOU+fMNoLE9 zyV^EvYCawWSWqf=d^O(~dG_sbDEDE>`bZ)zvq2YNy8ABiYpH;z8*J8NjiWg%Sbo*VWaP0dN+pvA-?4p?g1o$Dl2{8%zKC zF#p8u6ni~;pruuA+;v@fEPS!dRCQ^|6)f3j){V0l$k;@=YjC}mISD2iFi-yV@=%CGe}?f>CzS-h@Ih!bA~5=IIp`^s*cck@&?1T zj|GEQel!?vPOIFW9mF(6^X$0wQV$KTAcrTDLM+A>ifBywtfwpET!uIJ!#^%Hk9|sh zu^Od{<3((TOZ5@(GU~hgiXW7-1nc7m(Se3T3b9E?OVbr#vC<4DhPk7W=Iy14#US)V zF&0={{F!w~Z2pvW<2*M(KiXQFRTgy3SdsDh?%r~TQ906RhrQ$E-w)(}JC^_TYogdn zdv^o_yLfC*)L=fdc)a;&#y7QT4QdQO(FhXV%Q)j#u3PK=z@hcJfJu{&DkRX$6Jp($ z*e3SO_JU`-np{(l-}46BoV1mH75(k;viD=>(~W_)%3HpxF47gpU))ZNkd4_$XQ~MK zmp8`YXJp(V{RB47-U>{`sO#7PZnkMH&iJ2zGf?^Zoe)pBqxTE&XuMuHUr0aU|381w z%iv(jGQN6>_;KtUB_&x(j9x67*y?%@FBB6~lim8%a{drl3^y8B!p7zep6G0TWFQZI ze>bP}`>gtCDQ~Z}*jjv7+MpPmgCpUXWz{)q)#5_IY6_%?3jfOw{EvyCe}@BJ>~eKh zNpK)?{=Ysg-;op}jRwoROJn{O@qdrT|I;@=Gk{-N7>AkgKaRV9JM{kh*AgQb>`aZ5 z-}c-8Gcf-#&!;=Pk6-M_M*kGpegCg{`oI+?K*7^b@j4Un{PU*ppXT;2vlXPn`bkC| z3tjH|@5l0gpW#2hQ$Q^!6g(+Uj41zCNavm)wQjRY{mVQhTeO}a{l(sG|942=K0!*% z%KOjx{I3%(QGSASr^9~c?~p1yL25QY@_*wA{)#>80FZ_XmJ|NhiT$?; z7f?Q}QaOA?*}p>i{t41oWBY-Bg>>#2fYh43>jW5M|I6$1-~Rd;{|QnQ4ql4CLdph% z;D`N+kT+1~Z!-n2zBHLb-S7PSSJfl|76Mkuf15E_uVGN^nHuw<_6>i3V&Xpd|G(!9 zmci_2`2AytDN0%YgoA8DMkqQvP)rP&~a^qsI2Re~0vG|1a4XT>3kt z!0Um2id~(E{_l`J?f;>^<-C7~l>F(g2R{%`O8zyAs)m`{-QirOds9nz=$zr<{aLB|9w#3r2VTNt~KIjiH=t}`H zBC`K|P(cGY;3^W<9vDI9adk|m-t>B{GsM>JtB3RE06wt$Ccx=Skhpq=F>#s7@7WgB zE@8K^tM+?1;Yr8-z4a9%P{wSZe5I~bxgWcr zZdd~NISciVP=MGY<_iOlvb$98u2A}TbN&kO<-^~67)SUjw|U6;c*8!Ao*!@Qsb6_qg+`?E z109^=tD6INyz>DYVZZ-!Nfz#SBzh^FZe1nx|BkwNkV@2$`9Zu#NH{(DA5nk?vhVrc zR0gD*DOb0f1fbQ`3L9AJ7M3J$T=Hp0`OnTG?k}zCmM*y@#e7kzP!jg%OG``U>ocen zesnrD=$uv>5y?CbhP`8*2suweYuK-}P>S^$J9|~SBUucEGt7a3Ct^LrBxvyVWpM5Y#aEe3<#Bi!fQlbp=V-aU)OdS*a?;u*w|6qF?|p4)dzLL{K3|n_(_kxL z#{ITxY7%2q%(9ykR1#qN5*P!4@KgqHDBGTDOcGPjG-%kk-JP@`a}EA2`TY(3``Y5x zs)M8`YMGaCoZWLl%z71gOiV>!JdR}DAzk0{y1#ck{~3c5j^kWwk2&Y2JBbY<4b%tL0LVI)OnmB^V5Wh=1M+pF zTR8@uGk*Mb{O9IVnaAeiMitq(_rGt<1{}o8+@;n3PE2@tNWH6ID*Xl`9q1-OM8+D@ zX{IcC(jH}N%AW#mOUfci?hd+nM3fHcat@1^O%tH*mpQl$WYB3_ZwnrOjLuoXNJo{0 zoXis!UeTJQkwcI@_`l1OL=KGg2nw5C7si?@UrdUAQ2*C1kSc6|y-f%%3)$t~Xx`H4 zWP8y=XNZE}x4Z8mFi1uV=bJxk%lvd3?Q&d7Y8Ki(;Z*YFd=u$cC$fdTD9I)|u2vd{ zN!TPiJDwd5CeVP>l>DQS$TFub*vgRs4Ig}5cfQDd*a6T_9?n$wt5PfGNJQ#rb#_C6 z0FHh@F+G1;bf!>CDYWK+gI-?!;-(N&R1Ga<~CbBOy&hkB{4Kh zBXZfV{VIv4o~+PS1Rv&TzRG_^13t%`jZ_ZYOz&V1i+DPGf|v|tZ8OjOlX%$(aS&p< z&ZNF~)^~1~UuOKP1iCH}97gT$o&Qot#~hI#Wq1i{dfTm8O6CxWSCT9#d!Gt!O%@_( z<&*681S@`d8X>S>YX?zKudttAeg!@vRU3K7Y1P-e6gBSiea^Yn=yqSD0Y2dOSRK15}ie}8!W|Bhuy>JOfCHsJ5Z2g2~a zK@4i;T60^yW)HN{c*r?z|d%6l#C?{oUJyIi0&TMZ3JPR>?0{Gs%ASeK5zvyHC6s$4OnlX zX(I_Zd@F3leYR0$T9cIKna>L42|>aNgv;?xI$pnX6?Gc>=O8|JdoqwU0V_I}WpXc4 z)6Z@>0pIMj+x2)${7%4wJ>CzK$88`=-@(~1X9@E{5#)a+zT12DBu*sSy*VL(CnjxM zOhI|i9|C(#Kme~&cT6K}JAAC5%`yV7l}i%nmhd6n+YNIF`c4pc==&l+cuvHMVC3)f zMEUW}ze41E7(A!f;iB(Q=c3=igX*NX(?dw*$tR*TCgEe_>FQ6fM--Q{IpqDZtZC$W(cmblEGD9t zKR40c=NuP6=erw^QxTAasMac*%mDaY zd~=n$;gt&dvEX>^4Z}hzQpgf+t}#<8aiZ*vB;fiO;0;6Tb+@UhHGZS36hT}CrV{W?Yxly8`9lij0F-R+^~3@OeO2B z)MKgS)80(tW8^ngxFBih&ansk3~4dS$B6I^WjXCW^Xw1ab_-clek}w~$>`sf#%MUb z{eJ_t6sj%`p(+$v(yr^+f|1_wX#erVEE6fdq45i(;XJVX0DZ%e1-w=U$?lv0bDPJu zzu1Kdx$C7^$h!a<7s#!ndHbfvbJ`yrUn04ybIJ8fDTI2cwFXqg2^efNye6`;TN1^8 z1G_uP>%0s|VsMESe^%JIJzKvxyFCLh+%Lt^6L5IF6KwlqnE>hmr6@w+m3%7kjv#v4 z9ZpvI%+(8LWrRG$ae2Ne>aR>G74t?pSFHMHEUZ1ZuYP>DHHT?5;t+1d3GeIOMV?=Q zkAO6$9<6Ywo;8Z&*C^=#6L22s9r-+8C-ca6-=^MG*+mGalGpOWcgy@@%h!fwZ>uuw z1SJx@dF|ijqzEp(JBMz;H9{9wAJ+N3u|^(S9V?`1wkat2Y`4mB~xrB`frRtfsm^nJdHTA_jZP^O(Hn~K=jDc8>g)X_jMM&5RYw;0 zXF@^mr-03#pzeAfpP5Siqj_IcOW^%g?k^;a%Hp=_>OCVI z)=Qw%#y*F6D3NimOGyWyVZ~?HNQ`h1m%w|tu4+tZ7%?c+m8(Y!l1_xH5 zLTc2K>#=fyjG5~*z#K_>y=?6w`PhC&#>L2wAmkY`)it_b!|E+DawY$_KosFaWS(A+ zeX|bdGoZc81Kz|Z8OW8R=fuB@T>qWH-&w!~4k(zj;QD@;WqWt|eASHptq^Q_v-Gvz zOY?=@YajPG87w3_LSj=(@i_lU8j4aOvFIlWSFTgVR35r;o+s5-ak99Ml)%;41sl6B z8`rGmEha+PVkF{mUxqF=+!?n%WH6nq!xp(8{&ftQ=+auOx5oL05A=EzfD+sK(~O!Y z5!DaMqi3E6gEj{=WPJ7yA)iXu7aFS!jZ9Rr^)p%y$SkbZ!>1pBQ`~W@*AWY$-s{or zT`&}FoA>t7s?l!s*QRLjB!IfQMs3NFD!lEN0VQw@t!m*%X7bP-?Ls*`Oj;eWS^Z|? zg0Q8frE1sg0hvHo>-ij2YHGP3{1CI&YN+QaaH#J;HbJWmCDHqv4#t(yZCM&NDtHkJ zd5gIJUaBvP0$? zPk`XclKo2Z7WW_wn=uVeOLL6F{s$zt=MBYHf4IfiPghs4KPrL#oXO{|l68Hsh5>`P zBf09~I%*{;CM%!L-jh_3etvzVsa9VWRWOWAE*R5tqN!^pr|2C8SV39XDebxT(~hE0!DR9A(mG{vc<}$RSUFi&-KP z-(NnRE5#M1pKkE_+P$BF``gZ&IO^MWMR_c=MYWm==mAdKPxgk><$`c;aYKN;tE<0X zLLfK-%LtpzTrO`tl9=l~crp5SXyZo?6+7ejahy!YBWJBwlt6kE2@x@7Lp-&-#%+Pv z{2cQozx_fn8pz=^e^^@4LnYCrq zpKsUCa97r`GBa98?f73~r~G?Pz{C3DaORy|&So)MI3`(n?d5sfRcQ0o|7sfl%l#H5 zz`lpkCo|_dOm6*7;Bn5jMSZ^!cG{kS#!>opYi8X`pNQsz#{bIxJ6gyhg-nUa!kcZiSh~cr9IXp7sZ3su zwGOXvnE}Y5G1apf*(4^3 zqdD6cDp$J91@Sdf>&5xL#4?=8k(@w}tfZ;(W~fq)`sv8oDiZM<(W%1G;$93ax&+N@ zAZyH7^TJ^?xKn-lb@<7ot>6rQ);im6wZ#fmd+k1*Ci>t28Z_hpuawl!fe|fk>{8}fJ`D?NyiT`-H>=o9EgB1kn`oj_;*&-yEqEjw^foI%ADK1 zp`n^pYlnimZC@Z{5}5-3|LzXJMiKNLZ~eIoTPs}HxFtgyJkGm}$OYsxHKDOU_(bzq6dniyI#=JMs))8%N62o9C7YsyS^bN3pWQMYdH zV)lzH@e+TAfIFh&c7I?2QzvYe1m9#qBfn2#c4*$XBC@44VN~)NGvWt6pC;Pr0Jjk z9v&t!t^qHSY5ZU^7crGw#&?lG#8Q?czBFk#C#H5!9+P$7XTZS3n<~7<>IWtHUHeT0 zveM~Ew|{V{W@sH=+KuW6!3Uw*zrw$GCLBh*>F5lsHg*^$7XuW$)XASW@Zur&z`T- z?l7JJC%7Yrj0_2T0VKUGdiT3DMp5zlX%ZtcjFt~6AxOK=gBI&HDT3@jGNQnBcl6_Ku-q9~G?xO=SV{9!i)9UV4OOFE` zUahfIw%{NdPp8iE2rgDDiSxj5KA9&b;4B{i@C?_ZW&p$3n#dv6Ru`KQvN?eNd$b<` z>M;B^Ss9DV)?|7MrhhT)9M%trZG5iB5qAh%CSBiOaR23(5b_lI8A`=|Bm^#;&ASV7 zsf^ygeBt1gC8Ylq`7a$GEh3>W9NXmPn8z0uwmRURvro65>g=0J-7R0}6qPXn<3?x+ zPtvD<(aO8S-=HGc?KiXc7VIz1&p-Oizi@l))s+^t6B7%#!E;rvf6SARcl>kt_4i{) z8&aX-t$X$(bw4yM@bIE)=q7zoB=jf!-?egS;_YWG8H@dXrLzi>*mT_JVKw2_j})R> zsKU`*@=+n^>^q1Pomz)$Z#OhLGg#k{N7teQPWTwFV-Q19MxqAnDjf71YEl<*UYyY! z?_~lAX1;4FX7fZ`u#su(stu7bbpKMePc!+H zvXzX~%8U#)nzK%HA#I630!Ps|Te(PJb&d|fq*X~-%`5CjOWUX6EQUrvC)2*%8H$!= zJq#QDov=P13gXwVQQl|^I?yri9m$R$G&R;JJxHK5_{Y)fL zw$DaVC#I?yfnzu(45ER2JhjHy50|vzoqeHNMYaolrohKHKD{ zQfbiar*1dwcrv7p$!Gv6pI-lQ#1tkXV3^5ijz8S4W**-$7w!g{N2L|B4ytk(h z2}h~?i=+DOQ?s)bTW*-XS)KLrdq62xHhyO!ZU}Un;T&c22c-hu#|2`DV1yq0qznD# zYHwWKR(7(NaO;a-*#kI<{8U z>OMPXem7n3@Cv(#D?n1N$*(%^w?`9}X*?BpOL%>K6w>p$z>)`M6_@SYtL3`;>9eHV zV3epZX8kJw0Zi-#JZ=s{#gTC62Z$W||16flG3hmZ*IZk3u-Oi=(RRi+eRyY)putGw zs&M~c(&2f_RJx=t4xqe~e>&e1mv-8(e^PCUC@rYY2B7kp7SK4e@b$^d& zq-G`0V;YB%VHvibUIrRVZdJBer=>A@JkE%Zp<0!JdUCt*$5)6U(*2`GdtTw8#aavH z*-F^b1@%jduAyYED)caEGz%uic!f{EJ|Hb+PI$t5cRtBA92#DWG-dJoQ_Qn?%`Yj; z?e13|AIV5`aRl@H-`6~jPj?>!S<$7NfS>A+H~FY*dK$wZx_zRxF&v%RY%l}Q{cKe- zz8~dawWx^q7ASE`j>G~m!4PnYCu7i+4@4^4ELTH$-X2S2t$Cf_U0_fqU?i#Rti|j{ z@J~}Iq-A5sOToT(mI0HX$s7|nb#=~)GlD_ycS6GaloTGXFHpd(;ottF)dl7Ha%4(O z%6J9*m#JCJ*-v|!y?#489xo`jG$)Ls5ORb3g0xTl5wyj61z|0Q;`yJ-10Ii~vo*75a9_(&=nse0*5 z2p&1W+qZh`)_BY%ra&b(Om2*2j;kH~K+g|D%EVsfPAI)h7aSVR{a`k{p8bj!^ zJ49)t(}}X`al>Ls?v}A26~~@>%Ese1>GyS^*%gUOA-yDm4>XH`@M`@E8GbXbp?vjF zVqGjo$CeC+yS|?8XB(@njaoIINF@~SE?TWMa~QB0^h+@Ef42)-A7U~XG|TX?4f5*D z9fCG~I?`nF>1zlUeG+=UR8lO_a>J*k9cjxy2gMNpgEHIQe|@yk@eL1r#%UtzBelU6 zGRoqWnf8`(j31uvJ$B$SVm|bK_EE%bX&#W8BK=+ zU74S4A6*Lf=L|$|7N=gC3~tAv{5Q`Rd6IW8XPpi^Yr9;h>iTrb1C3yetCkcI3vrR;&bDa3_|vgsDXUzyHEQT1t*|m=y2U7K9a}Bvm_A%`w7W>{*fue$f zXXn6@k-_aPVwQKk(ug#f+oyC^Cu~dqwyX7b{X~s=I-gRtkn7PD8bRY3 z;@=o|fMFcWg&8uZfS@has498PL_YW=>rLF|ab5ag8~6QVO>z>jghk*9z}l5*E$tG};r=WWOsWu?`do3^UrVw9VOS>NFe1u5+|OeP(ce=s`Jte8=7QCY?q*7n9fR z_>2lL_%MnV6!zC zJ)KJ*1*to|{bkoX4%gAh#gy<+#AncFMwZOoExWP&A9Py>oS6aTCe%jT2VMz;Jp_j* zGm(P3?kDZ8^%1-J&Bl}?|I!q{2y;gwZkxt9z4y*zP{SI zift&hSfVlLG(eV2r&$oZjqqKlwNk5A_w7(Al={q0qWQ@ddf)SFa-~l7lj7sj!L8T* zmiR~-3v!Xd-9xBaL#?U^(;{l@)X#=?rte8^D>BipQlJcRP#~Q!5!oiJSKw>-T=6ZB zLMm-#y-y}Vq=3$i>bXOsxuSQLJ{hv^9@;|$Td6y4{t5eguqZqXq_8$IpiE;DaDnUu zvCtSMeGjaZ3m}4May_Ej;j0cDc8B;^fz4O_^8^=>z?>l=KvOGbbO~khLND2W9LM_l za(i3B~mvwcXQVhDE=6G4- z+2->@rZ(g0QZ2#w55Yh&)i87p#NMwO^u}Ui3AD9gzj0$o#0eLAX}PQ$j~szM=TF`vmwhAo?82;{J5i zqifVQv6HipRxjKN_&zAXpfwkowB}+WSDZe9NgZ9DDD786F5^Sn&GXpO+^*B3>5|gujf;YM#>K{o{*(urFj__2(;(9k3tFUIJM&ELMLl zci&Xm_FH0^z6INZzH=k;MCW#I7p2gk*&HwGM3#cj@l-F+ENPZGK0fP_-#X1Ux=3GG z^QDMJL&aW*2!+FNQ4QL@+=Iaai^YvzEi^6J!@Im_T*awEX%hzpFj_CxXb&0^ zBvTN65Q*F#h|Wv$(%XbsaCFXNDqwRms zq+7`UL*Qz(j$EAeoj4F}vR4n)A0^N7TPd4E5$3NYKWJOC z3y1A@cs045v`kX5nmrIu$|g*Jch|c_vyt@Mx3$uJEdbe?05GqSOg^0G_W~+gNVLOA zl}fpBn6#=S25n#HJcBgEX2`~@&{-5~LiAcaut1@#)_>^J=>vj4^(TBj3b}fPD=UTv zkmiQoBkj?cG$e?^p&Ef1jaG+oYNhSH?i^y~buXwfajEZa^aVyU76VE}Mlq0|Xp8%~HaR0+L^d zn)`yV+LBN2Nq(s_iiYtUnvxsPr=f{F>dy66zj`WQF>9mOAKoGI0;oikBYE)la$^-P zr&Wf+N3wO$$wq~m3=|hv-nbr?u0t{M$<%68#E_ZMx!4_r2tGfUoE*+l!O+$O+3Zf> zj_NdsJ-qeFlShJMce4zduUgNR_cYv0NdS!5Vg_?Eso3il*|YcmK$s79{WB%!3r#Rl zjA^-FLgPZPmTyxZ?=D0s4JI@4{D$P0-ffpYhM8F|?gexAGg}Y70nVP@&nmq?yd&$J zMvn2O(S(E{ef%(0;~AYB)}6Du=gHu~e8uEbG~(0P(cwqMA6Wm>l=_Kh>$l!4)H#NC znuwbk>keYyo(X+q3*M8lVLa0ULsI2#);b1CZ&b|9+9YriD1bROuh)v<&Bux;Q<|s! zEW4KK->ojg8jP-^!+dueq@rpK>W-$FZ0?29lEjX^SC8J@ZY!2EC91jz(~?nyfuB_^ ziW}&cG`e~bwiE99JH<)waROR2j^vq66ZQ8*&j5P>-T*_?On^PxrPTN&LXe)k-X2J!(#I+iBe#VKq? znH&p}$sF+cO5Ih`C~pN^Qf7uBKo<`!-*QTC?FikyBSmrjTidi0G=HEAR9 zUwgdW{~_>msz)=s(RSDzOWCU{W|NMj_xR8B&tBX5CHo&Nu83d@gE-(ubbi_AT(4-M zyXgK(moKYC7(g9O9G+5b+*2s0O~~6sOfXkD8_ARHsD1gE4X^U@XGtHXU@GkRgwxd$ z5-zxqG?H)P1_);fgu^(|PEX4croGSBI`CHi%1%?E9FAMfmX!#YR^Ll$9O}2aKiAPv z=0nqNiBY>%FzRxW>AJmYuhr8u*X%QTwyXF&-AOOhxMI|p4dWkNi_P87H?_UNI}40C71>X7VXJ@d1~H0N%Nh_1^UR25UQRkZun>2K zqcb2(Td-SqO0kAnzV^$tU3y2J=yH{P z*S&XRvq$--gK{F?lJhvzjP=4!krxakUt^3z!&_V7A(HtHn$M~d_i;Z1-uq6x%MaPU zIPZoUS@J>s!-j-lNMI|6`fBfv!6%!JlBqP=fWFq@84L>RVvg4Gz@A{#;HB9Uwf={; zdms39zsEL~WO1n7MdGf4HK3aQC7}jZ0?G4I4>i&5_z9vqHVu z%#)P*!H|0S2P_&tRO+>d^&=DDAtRP4BOqt>ZoK2#U&M+5a*k1ggZpUJ;@5_NUi{E; ztgFhHuA7C=k}T0Cmh-tpl%LY&EUy}SZz}qtM1*DF4Fn9v4L5rR#?9-weKsL?M&ofD zU!60iQNW7ry@7{ko>I4nFQUp{zPN;1Tiu4Pv1d5PqX*YS(gIho61@sF%{zEfbl(}y zA|6g=P(iWZg4gIUrra6LBA)(_4IK^@aYu@lKmLO!umcJ<&wAkIfbY{g5T}_FL^Ad* zOVInHf4>mtGNp{uB6{Bk>lcwPo!@-hJ>7B|!^=vAT&Ki(qlp!%?fy*X5dc(kxR>Y6 z$A}vuUU!yHG~ulZwnUTJju<1E9IE1#XH)ILON41$&akZJLjjy8e5II4Q*${`a0yBS zIpVTd-Oc_cvObe7PfjsXW>dknM{j1w{-_px@VbQ7Yj?r|rI5(oIod>n$-u|jBC$wx z1Zngqy%w8VrffqcX+yvT+f&<3AykTmmjT+i%l)<-B65^L5Sk`hf=;P?&`EO@OD--l zYo(spE#w$S0pzN2l}Lk#WXiM!hKt|ULGo^k`&l5Ttxm~X7@(naaQlOd7R`P8$A5~G zlP)gWJGOz+IWz>KmnBWG-kJ&@Di+ccfjbB;iZHOUd~kkB z^0Wb+T$txrM)L=!8F(nTO|YXfstA_+ex;vhF7FfDT=$mS>5~IA?fdud56+eh&8Xgy z2Ac9uLesKFvswT!>1{G8rAGuVjb;NsKBrZ24PC&aVkFfQr|n8aPERnoO#bgCz;6wD zi&q=~n^xNjF9UvgP`|u)$XV~ESZ9Q`(vTY@l`f=OhA?76moM>i=m0;>jic9)#f1qOY}igZ7&E)9)Bk z*oZ!w4<0j?40=t_u19kcSuJFkDW^q+f2O%@HGS zAcFO%gba_4)%)ANIjhspBR4%K)ScWD&6kJ!Al#%WSLXL=@IkX|q`4dx_yY z*X0Y97$Tf-{8^=Fz!&O=RN~SHy5tb5zsP=ZvzF%@Ik0H)!67%hV8$vSd^#~s`*jUlD$vkbY;EVN9Au_Dv2*r z%9CKUS#6M>FVv$(KIBr-<_kh0*s>?=HY(#FQzilO+KL~1m&d1PhoxY0bJacSg|#=D zj&b1nX%K5ff1vV0%YUY1x_BL*maL!0^M%lcUQNv>oW|^CWwF?xJ`G(Vm5!`@VZV8v zMCTYBxN3D}oJ72bDB%RuOl0Cw<&Tdb!&Ixm62erqRAbd+q0I=&rfk9JbmWi2;Tpz0 zBIZoR=VT_G0PX3bT-#t2ZugsV52|~{8U?|xPbm*y77nTp*Ykpq#oL1-)so_=M$^cZ zw|d`o2bD9|J6-i7mm73SBj~x=tp_2PNR(VRaKkSqF#Z#kY`?U70t1M-T)N*yycdjb zT#ne>Y235z-9dGWH&X^*_`UN!F1!jThB9&_-s0siSc>;i zh`*MU2>=&}(;@VPa&-w;2VJCfqa?aE7MKtu z&dSt8jJxXnW6kyxc13wN_jLMYo`#^5_UQkQ^y@dlf`z zd>S_TL6~?)y^bd86jli4RQt5b7XlhpBA_vvd90wiiM6cTmBH+JqLfwV9Qz(d*@^mq zl`oYYmn$yQRbWq?K(DEAvL41LoYLlXrNKidourSZF?4nvh_sJJt72+8nkJr{D&l=+ zx84yMfyY+*I&2^dMuBP@IQI7TiAIcyKloq#ln_L{gu@;ltCO8F(9?r3pBsqzzl3<+ zo|b0Q>Gaz-n^R^7EeKcYw}t`Z137@Swrud|z$T6` zAI+Z+Jz_cS4dwVbAK<7G=127_%t1J*nY2Fgj5J0GT$FLTWNUrVptZY76wczqws6*=tNkbLXIp=bPNF@wa*-%lw$7rL&mY zb&#N`qy`h|idy^CqEPgd^of; zYeP`%rx2%#0;yO+Ad^tPqP=oDpAcrZ+xgxni@kN$$#xjfw6uVTO#@FrKme5Q1{RuV zx+&1=Q(+Oi{iEqXq}`6VQHT{;#2-JFB~-O1UDJDjqfI>AlqVi;r?x?M^?KedYC8S{ z8H-+BqUwi$E1rs6^|ZZVtqGHM%R5Th2iW0hzZm&U-oY+A^4p{c)iHS_lmZ{*p?0I= zv^WyWI2gs@7y6rI)H9*G<$ct1QXE*rv`1a~@jdNYi<~4cMhfZU#}#g`n}`RWA9~HR zukAnhy8#n+b74t&Rk9yA_fuJ&8yc;a_eX$*%k6rSHkY{%Ok}sJ@7W;U$ zUG{{0xEXBfwVvlf-*tKQsa*3h?~|sYnA(!;_Ewvu@L9v2uD6E!1%}gHl#Aq547$$kn#$Pn%{W@iXQ13- zn0peZ@Yjy6%w+jCq6O5inr5Nyr;G9xcu5R;*{lO0%+kLCLN^vVpeU|xQxM`^A5Q^C zLSpd}3z>C;A5?PN6470o{=qYXEl;P3w3_c-54pZ`3i1?{0yu-)s)v;~o;Ual?HY-P3c)Hex2orYft2;0hwm8C;(j1TeSUgY$Ne@XgrKWFkFnaij9p_%lP zdXDKKwysQH?T!3Oiad&CRkz}9I4foy$4fUE{B$^z(|*Y^3CUk^rR5Jo`ILG(q9)zy znrA_;Gfj4bp4!=hjGt@w90XxN;Is||k@)U*t11l$x31|k&lKGbt$eN;H}mC-H6<*e zoqZXpY%|Z4S7f>SkN|y9Y4Pm39Ks^x=L%cr&Dnqgroo|O^Ag?!y=R5ewb)kew45@7 z6ozf4w6pdf=fnCXqT)aLEVZZ$&O=Tz>2#==wc`lOWO+j+peB@{PdwWU5g#1QpGlmV zojhPv`ex>FzSkb+vYkT*Z)PxbEFp&rd{7jj|CfvH&4bMz?r#TgGFq-DDslp2oBc2c zO(~A#ziJFR=SUJ;tg=Z~K7Ot3h1-BFo%<;%JJ1mFjFEdT&Y9VvR_D>T=cB$I zXz0s8%Bp*RPX+$58ibTqL0-2fZlHM&IGiml!$4oYMQltgHf;QHYM|5TO%z8ZALIuU z@yKy^EuHWk4WmCw!_DaAtMMVvXDj)f6K&J6G-M!X6uHEtO(ZsXc#Aj7&8*+_T^wnz zv_7PqtHtFg=UYjgH2jGNuA zG128&e=^~$mx#NHWwF&d@@38vD$72)sXv1D@V#h8r^zKz&nBXjYVy`L1FjUj2g9jq zjs<1V?{>>>zijUV^H{4kV;HG8ndGDVCRO@$jk0wmn8aoRi&kaEIjh-VVFa2^5a!~+ zPg-4+BLR)=-iT}Z#<0Fi%8&Xf6@&rQ+PUxe#TGNX$kO!RLIoL z^thf4Z!-;zMJ{!=7^eyDjx`zBJd@Kt?>(wsQYz7_Z#ir={Y;QJW>8ao;4GEKP{Kr6 z+V(MtSsxuVg(Q+u83#ai<#Au7QXgb@wKzi|2~Uhd8;{TRDc#jb%YhQyOgxh@kf63J zkueVrMtx7~`>}>XS}EUB`S0PZDgwEwKUG=}R(_e$HiDQ-!IpDK_AW;>7&zmMfs5%qoB4wTGSP=m*-Mu8)BR{5{#Da2_;|6V z>?|XLx2ICZb*0%8;z147LaPo_o5jN0j`qzTtFxWmCwaZz3;`Tj6{ub`-q_~~?8CHD05MvD|OV0ab{B#~*l1pV( z7l)Z13dJY_L5G}B!eM%?#&4!FZVD=K!vIV$7_bx3(JaN^cGIflD~a%4pF@d6oX^%2$`Zr>|F}sg^^D%;9Mq)?NLDbwd(c6Lqw(sCW?!+BKi{-Wpy6 zRZr!bA(?d%@LPUJs?y5A=nt8YWgQPG?o}I1qYNM7rx1TzxjVeL)jwK>%VpQb>Zehu zh5+=yBAdSgmD|41Qm$Ff)^Gs)Z79IsmK4{JOT5(_2ro7n+$uPHKUtFvHR1_Nz!Y>cs>ZZ04MZ#9z`6TJ0XlExh;mM7tf+KlsRs<2+qK zusfKTh<%_QXQYkekt8FN-7&3@5(5!tFOvxW>CM4E_KuI4k?br_5>>fL$x*N6n*m-8 zrPX#!j(=i^LRiV$kKP1?d~ONd^^EJ`la(^NR$xRO%KD}1TFcrYg?}FakSi;j4`<8% zMB$(f1L`7as`U;ZtrL(Ba&b+_k?ZtlY?23Mi(R09dETpMbqE)}0zZ_(WlvgHJo(@c zL?B9wLl-)jHutw<`par=t?SA$#$&u1a~7&air{!bPUzMRvoRPHV1T8n0MrWc3dgJG zeYx$kt*6(sdU&p01gVH&omhB!Ah}lSXQ&A2Rw49$9r_D*($nC(UA>vn(BZQX@$;YJN1$kQ1>m=#jYFO0XEE zg@gOr=;BCJTwA7AVW1Bqn8ND_$)w*_OxRSjKZG#9Ca}r-r5Lf8G`2^4g!Bdh!G5L}9?d6U{K@~!mIzO!dAjmXa4`hW zJRo}>nDOdP_kLm?=AV8oEixTV$om_6xoz~?vtHtMnnSTx2|BQ@Mf&i%D!BpyYf(+5 z6k2d2$0>dFj2B1Sdx1F~_$vKc#P?+yMh_WZ4+WHl<7gpJopweF2$kz{d8qBzs&&nN zq84j`NirzrvERs!NwW4-8Em7VN&glErli^!3T?CVD)Or&&E)L zTO^REi%1D)p0|eu!(Eh~I(Daauu)f2MQ-J$4{_y$I_4aVd^I=irV%k+5-Rx>z?@OW zFgLXhmT(CU8zZUHhhGM<86l)80IHZf_QtToqky$-aAB@0enddpWqrNXN4K8w(K!;I zQ+W&PkL1$y_)NLk#>Adsmj5@ZV~T?m)B1^_ok5HQY6 zrZ2&EZvaVEZ@Vnv#q2qaMX#n|l2koRSfSM{w}{lIK*6a|Jt(zoOda=JWYC_Wu3@t{ zpFp;M`ttgyZIdjFmjBzJ4k!RyzjF_VeaJNnPYOY2OhZh$zPO@hND)$mSw^t=@r0;? z&7c+HXfjaR6;zW|X;?R6i|>Q*lih5Hg3_*3sl(5hW}S!o4z_A4tYO^q?l(jpUZk1f zPv;^gAm{R5I!ol48z*7rCl>q`P`f{NxK}Eh9QA5)#@kie)Nm@JX(F3Tb+hJ)?kRpu z2$W6+i{zh`s{U2=Dx)9 zn32j;duw3*c|HY$S2ARGMsM_o0JX^eNCMf{y|{;)lW?wKCg8~ z2$iPHugrp;`(x?kt?_S1XA2s8SMaRQ=Gwz|sAeP5kF?e^;1U`borzjhx&W?k_EjkW}Z?6$Zg#MLGOmRoVJT^4&-sNfq zR_q_c?jI%Uh1+$P`1r_ux_?13NF|fDx6O}Q!)m=zF!7{IVDgO_RAqnT*P+OO{<@oN z4OABanBl=yI+Ps9?ALP~XeE%tOOeJHtt_zM?(oPVat0&g z1@zHtY(LDFiF}gzrTAcA$Sl&Oeo~rP{mr$h*r-gzrz20AhJB$zh)%PD$S#R< zomzRw(C#ooGp#k3R=i4;26DL$4y`qntQXlq?zcho%ZM#KlNFz(;+>8k-B3b4G7i;$4y+g0iAKnuw1TuG`@O@=LRgMof zq619&j(^WdBT(_fVPuoHABj~4Jl5GiuR&tbYYKyIbSDAOv|{ifAxq&sHWuXZi5X1w z^*x)me%;rmaC`Fu&kTLvaKoH!!`yh%T(@*Q)ufdztLYHUE7hMe*(yP9m-Fx6vos~` z5+3`P^ptOD9=A3H-w5F_2JtEsKA@U`CN)Pqy@5t|O!y6L{SmM48HP@p%b)!5o0aju ziS-`Y9P~X5Yr`Jm=?f3VOCP2@X~33&!P&%Yfi>ddswYI*`|@d<3jsoYr4TM>0ZD4J zcG~tQ+*E;L^dRZB8OrUSvmnDtL&+-%WQwdrQWGlZh|5^~GQU7M3TJlfYXiMjUB0=w zZ=rjCxu4Lo=ARr7f~t?;b|5_GCFwOPKLT%3-fWown0kh~^ac+^5f2o|;uJ8A#HG$t zfcd1>+Awr}>3(Saet!LJq=&nDm9{E8C-z7>`8ti)Dy)n`t2SsErrP0T5^3qJaRo)I z^jgaGxf(c9!y*qJdqi$st$SEZhA5z+gHzsI(5m)+As$E0r2Tq{lG(a-?hCbmR*xl& zL1pcTEo<9QFJV0TaT$A*#rg%3G^zb!*foKXxYa5BLht^&om5^)5ZqhTwtBcN&-Zr+CmHS-|sZ5h0xzAsR#AX4X z@_2TCJX17yj>-(8lf{=tBR8L+&D)j{|nS5){8&qXqw1%sHGA1S_z4WjeiEuDnViP!p(C`!x03nWHeD6s%d*{ zz4hXh*^(kidhOw4&Eo4sFfNo&){wnT^1?82&Gxf&>YFURPz5rHaUY$1A@A$`JnR6N_UY+~a$!AJ+?kt)1KR%t zpMeK&h=fyS92(_hvFYDwMWN5%6TlFo+iT+^?QtD|i*l5xeDH92vs7;z z4#e@{TaxJww#Gj{R%l}|Au`9t9_3ccR_Ilu3wZn$yIWGvEf+R<<1<&TRBqVGgs-|E zOD?I@nuG!DC_zaTI*87=sm&=Lx8Ts?->PvaN$_+4XH<@X05!r>mVmoP90{An*sme1 z!mZ2nMtj*`L4!295}#rqnH@TTH%{7k%k~ZJAupjxjjMjUhx{AbX$v{=HGY_nuK19I zxZesqP<;42{*u5;<)CHMT27(^$1@UOg$cLboJ{6RZ(Bk*j~!L}3WFqMxFkm1!h6S; zwtH@ebCUiDmg*UhSE7X}1Mi^h_OyV2Nqecv{!wPSa5P}mfH=U+Seo)M#Zsl8B|FR? za{R-lN~f@ZbeEDZDJv_wda0UlwK0{1Cu|6U8_9;%+S6B7R4u&<%uhBbBS(>P_$&)W zHvb=4Z`qXv7j|pYT_O$A-6`GDAq|3*q_lLGgmgCo(%s$N-O}CN?Oyluj%U1kjQs=P z!*#)0=Q`({$Ml$WHe9JORpWaEA29|N5oODyKJdn4C-UmAE619j&DWJYFgZHYM!w{T zi0np`ezE`cG|;b*M)_BE5=DV7@?^C^Zt-R~u?)gN1nIm%py}G^Ixzz3ioL-FGMDvB z?~YMyMcm-`OaU))qn>~wCK1_))H%w(X+mD^50M0c+FX{ymvT5PiDr1pU)^_w50F+oYPt4XW_ua2`P*q z{iVgZEWg$GyU>3Rs-;4BohdUAI*)@Xd&4gk&Ug(8N0GAO=%e@loUE2B9RHioN#i=? zsmwJ5^Wy3%e4esCbAz2A&L1X@?VaR&8*uQ1vh+u#VTk+fS$mFH!bBo|GBBv5r2Y4D zO|=5wJoFfhdX1^HGNfAYV`~SI)5iSU?!n&~btCTD{q}H{=f#@H-Ij36#WUTO?-Q6% z&UYuPKl>vHEOmM9E+B}7yu(BJ=6SEZWAXPU{eBiI6~)#co}|oFN0ybzvD=|>@Ju*u zPW1$DDs?H(ryINB6K(`6LyA7^EpuC93O$1sYnBkar3#m_lDmWD-u)E%Ut|tkyBpB{ z{S>-SC_HXkc%ZVDt`paUi-G^!e5(YeW86LnS(z_q(|Nu?1zehdutPGNQ#BSD-S$%h z*w=OI70e&Yeh(1Ap?*Q&EFcfz#ZnTt$R6nbPHH@2RsjRo4WpY*7H-?E zyHkFRmiqI_cj>$?kaP5W|Fr{L4#UEc?!KZ13$AA#S)5ZuVQPvD&-M!|(9@@E!J%Et`2s^Rz-#RCtEP)wLLW{Z5pVSHje{viK%->W8?v57-LF%b*nZ4 z`)C=YS6-e?X1xDAZ!J?UbGKtXh&Tp@XWO0->6GXX8!nEr#F+RhyGTDwgbx3|H z=&WXEL^~r%=)}b07bCa&wOc+Ij@0?fuS1!7tjY1NtYz8vBz})xm8|X?t1rv zZ=qIE)F+Wblgj3mm~SAqZak8zO3|!bHIXxbW*NX&1*rm@z)|1&!a}=4$tfwmyx-nu zyb|(x%kF)~FR)#x|A2%=OB$eNK~xqIM;t9?>eg@E)17GX$;3h>dbG?w&*Fku2#YC| z`@ITt|4A~T;b<%pk@tGZ&0v@*x zq1z9CAXHAg7BU1~&;TbUK=s4>!LWLV1?ESeqFAcB^=^$Ivd?F&gOAM@tDfE%(d_O! z2!`AFp-%w8HkqYNQR{Gq8F3QR7psOO6T_a+%77rv>$Jragu+3W@i_wns@Sjcmo8nd zmiv0)F^f*MGz105-e_DVf;Wg}z{cp*%e2SczAH8r`5?}P(GLCPrUG6u^*-d3lr`Ju zT#q0*?z}0xPfqroKtv~WF^E2E5(_o599bOCmt&J6Cr|@by4+6<(R2G*b?!&uaq6?= ztD=T;tXE{FfJA2oXT3PsY#`q^NfzmqB+{l9b!!smSkNw>SG=dGN0K%SPv^oiCg1nS z?AJ!7_r5upljVRoXN@kU`}S-3x$#aUBsPz7pnHkjKTw)SvP7k=IT1JX)H}ah z-s)ClZ<{DdsQ6f_JS!%ZN60R`>mGF@e3Ze43YP*3d=Vh$F9X&=qum0(`<93>^1F5in$3YX7r*{rsMoBenyKOtmrHulgG^VTW-$nD!HZ_&8P8S>gZD_t5=Da;2@x+WEBl9@y~_thqh&~-*JE&f>g+3Lwr03&o};_ zr{+Yr^&p%sW}B%Dx~{Z4$w3J+@==Qf zZXkQH5kUVm#xk5t67>Z!*c5*(%lU7|dl8MEm)WE?32dzPSG~$8N9&(4s*S@9MEqj& z5izMdGg5!T^i>thGRmto zj8Kr2%HlZ@Ph~k&u;}x;9?q)cR;&LC_1qQG0*4Lk;f&d*daEy!^}0Hv z8C*J8BA|Fa|96-OdNo!RX=>k^8swiJdew!zs`)5a_p}|#23>sbF;GqhK$3ZOQPK$_WnFxLt9*UYg55`W;xRg37J)N?|Pb6k} zgGwc>p@8@1(Y$hdcqdx&k%8lg5`V;~i>wJm=}`$kegZYJW%b|hPLu%E2mU>cV&(qF z$vb6<{c|YkKe7EjB8X36P|}AhefTzK(1BjjGO+*;kfZ<4`(VCKic5zi71BtJ6*5O zg^vWZ-LHHuhXG&(A_kEl>gSiO*KHg_e2}fCJqk%DZxd4}HieOpz9v6wFxrhcctGULqq6eCtn7xgwlE3FbQUD zebwkxWpTkmPb0WOa;f(4GUrU!=q&1oALL-FAUqMhTJKE3XOrtUFAqC|e?pFjrr*k_ zydzPpIpJEw{MV%WK{J>Rk{!Z0djt47VgvBPJX1fq#>rFh1RjsW@WBx}F{W%4z706B zK$2xD-!h9!TCKLqESh@-xrf43Rm+f(rHUc_tqnr4?^*Y06Y~>;{c*4%>gwvYJv=wk z?fN)WkSTo;@h111ugo_eAA(Xf-PRXzN2N}T7reDL3u5ix{6u-ct=*l-9LvSSRPMda z29p~wo*wCry6zjK1%rjfN&pRqI`111(ymD9>tyo2A2vs%%m2#r(hHT5^S-X&-p+6_ zhwZ!T%fUNC2g|j}cDQ20ttfg)c~=ZZ#UQ~xdc0+?D=>Z=9XC|1Uikjs1NcRiyTNLZ zf>wuH+T7WXu~FNK-Vn^LvMA(OYPNT>z3?0mbmz8MCy#GxnjR!>@r_U_YJRkkWbZ6B zEMY&W(kNirCoAfTstm%|gcn5}KXN>xBW>(8#l zZuHzFhkEg1vpf?6G)gT9dNE@hPQ}4K@`dt1hlaCm^WpkvwQvhmIUJ^VFN9BjwhA$l zc1MESTAXEV0xa@4*`3zgouJn!UMbK1AZb5XkDQ-SF=+T5<#1km7ymF$JE-`Jj1$He zCWxco0e=dcTWkIoYP_P0LKfS2?ueC%`7=~G2=B;^K0MZ#(Q1^&(_Zhn>Yj`}{Fb{v z+i){iYi@V>CnP48T|&u_<^QIIDZr-TeL2lbC&DSrJy+x-{agE6{hlvop1Y9SFpOG> z22;Oty~$)}SEI{0w{p-tNk!!C&6UXW-D&PBx6KL$6eukhgUu34z_au=5QwYV27|6l zyQJ>%+s|ihJ^uhb-4;h&f3noaw}py-{wh=>(w?_76GGTd@hLU=GVLLfcA|-+DO4E> z5PgByxSZJ^`je1xUSw1qm5YbmFC?vev6?z8=R0lh&o(>#eq!!t%Q}Ki(Aw{xD`91R z#Ur7pJ26J&c&E=g-v$1d5b}D?zO__$czxxxT@z?*LB+v#@TZ$yF(mf8bk^~W2R&X! zSD^dRrOE_Gjg7g*?4DTpG~fQ?(B{E}6gmmHT`8USK&x1t1y_~JxnhK8#L=#qVrI-& zRV5{iC6@yTO-)=f?Qb5hQqSL$Ol^i{M&!bNIQ*nqKU}szjTTdB@qS$~UW*PNU0A?% z*dLoiZ~;Gr;3F&ysrxroHT zEOYE4hjdNt*e_%kVU?Xb;`(IxeXn+?(dRs)6}Q1Q4096Ek`n9`sgL1Pc}e?HZPi-T zbbE*E-buejghYQvm)=bE|6$+ObaNKr`G}-dhC8HRsgw>uH(GUfF#FDM^LT^Xp2wS6 zn@GL5eQ5J~38w$z!+NVaVK_Qc{GxlX;%}3&o+@e`eg!%Q+f|cc*l-d;+Ny7NMV^77 zP_&ivH1p9I(b+Vbb0w=O6J$Eq+vmdnLN`fv#pltAx4bz+26DGbViK)ze!eyRdHz<3qO#Z&~clgZEUe<)e-Y5+$#R-)ervif8^iVzmQGFM(m~_2HBtGk zoL}L#)v+qrYOHHHR=PS-q*_p~jc#n64$kt@+o_i~-IgE71pISi7rjGxM{Iat5ga;= z(dFRzuZ@9JLXbwQqmN5CQ^%b_r@a-TH2zD;{g$B7sg}-l-x0)O66n zq=(VFl7&)95I9t7G%!5OqY@bgZWmZu{gS;jZ5W57UO4HhJCv$BB6j$s=+PGa&$y*u zI%L`#niQ2Fl;&`*jZWMeZjKL&z1}}W;4?TmfVsB#^~lR;?H^d|4nL{rcNE*!lyPA$ zWQJRYUlInsz#{#cPE~;kvp&L~NLUmww&MP8*CBq<8JsS~2F}zUL4O&}`{kBobBP2T zG5%JY_7%+(Ow~IPwrCF~{dkP+3setd|M7&|{Ou|EqeoLuyW=P8RsWbbYHSFc zaJEjcFYXh8{sJ{`y%ZV{f;k-g?e7&@_uD9x5Zu7n*s|p>tlI{w8ASlE;4U9X()SLO zR7l+fsJ=$Kx7NxG$D?^&OcshDHy}=bHDAmvN)ILBqLNL3%v-+c3IuDwN(DwmGtqQ# zsf)6#oIlMmxL$7MRsO0Rb61D7{CUMT(s2l865@EeXG!2*ASKOntJ&*jH6ALw02bm< zb6+gDt|p$}>?Xxnq)8wg8Hj}I-?45^ceeYYEZOABE~EShSS8=Ofde9NDpd59tE6Xh zZ(bkbGvin0uLovU>s9I^6!Q>t^5z_kqvV%{YkJxC(G(swh_fDOm%aY5VL38GCC&ia zg#KShyjO+{O8SR=G1GObpFP}+xEM78^x~2FCIag3B1q}v@E>-Cq=65hJS?cC1+iBm z4~G7i5|s!Qf>!j{mYYuhPA8aDFo=nn11G==x{LhwmXN&eI+>&*76+Sw_uF(XB9yN| z74sZp;cTZb8~zs4mw`w|^0rWwJUN{ey{RcS$uyvB{(^c`Ao&gkSu%54v+?w7B{nij z7~qbTSg_Hhe0RBQ+hO?ffDz*#^|e8WfK;N&{B)^J7fWg{AV^l{Y~6>H(ZRhg349*E zs)t!RUdX5Wbn2~o^5l}H+Pw%3ANakFYH4$^=#7uiBLa^A%5(;4gZC|k!=z_#jF2+M zbEoi7&-Lzx?&WnL%jchv^utm|k?OxJx^I=qt0OaNpC%km)_p|!DO7{FuQN$e=|y*j z6Qu60Z*DL;p~9XTthuo5S>N>@gMkb>5GhqFR_oJfw`JdKXD@DCYI+X9w>R+hwLjnK zK$f$L4w#kGUlm;SUhNwG(jp|=2nQ^9#O2ic%1x+3QoF$GXp%gbbNOUeWnXgRbyXZz zK8TLDJ3>Ae`+5ZF!<`ja>*cz4K|(WvS2QoL+0frc6Z9CJ0!XR+an|6X#q5&qS#6C+ z5>eOIgtVceyb8o*uYo)ht0qKd5F(U!6r<-R4XJ`)vE54lB^%|AWHIc#<15(E{VE>{}% zNCG@A9)G>mke4DCA$>I6MLaL7Le=_@$S)jF|Dd2=I0LbSW`^(vvUWk}i4xL!s1#C# z@pQylA(Ks4)uw7Gd4cfZYq8ptGUlwYEoGKO+fT+K__he!p(B9T{f-~J@AKjZFnk6> zu_ld-Ebmk-BxJb%j&$u5EW5@VOVfY+n5+vlW{9do5f> z)#WnRdr-LNQv)qND8G?&MQ67+csrgh&S$)kZgX|ge2oONV*bG~P8cCyFG zXDQzndcLW_D>WU6`p~BoC7Mjk_gRZjBE)v>tE0;)m4(=Fp)|YYk})9LAUz`Eh};o1 z0aH8vgFCu-91b(c;c*(9bCR?; zp9ai-Nar$5(X4pODf(ULPg|Y%fzM8)UyRCmPNtANxkH33A}<_LmKs(ro;hMNg@bCd zzmvw~@GuEDWx_n`D(;mGZNtWd_MDuoytwNL|7VBX`M)#mTLiJ|<9=o`pCuZo7YIE2 zy+k%9+&6tWgd#HhOo-~yA?((7A0w5*o;@f~8)eA#!wf zYnKsR)2;Zi^9LB;itrz5P8CKfsY_H(sZsNoQxhFqJDbe$ExF(w9>dbCFiA zJ+?IXn;#wMBH489$H=<2>&+qkx9O8PnzoM_%zD*WaHt2tNZ1Uash{HZm;$*{eB)Cb za1s8-=&b9}?r+e-_R>U>h;#2pYGKu@P^c<`g%o^f6xXgh6Z$jDcch(S$kxxNgX*$Hd-QS4D&U!d4& zO`^P>UABcQ^!j*Q01Q5cv`aJF!WvE5a2YS>8lP9i7dx>Y9zLpPno5oet!Ul*{!Di$ zWi*YXxKBo%$Z=1{?}62>DW4V1lw zX`yv+aDc~lkU-p@XZns_X0y5kfMDS}Mhg<!j#3Oh%Ra;c7Cd0XSZgTy5 zfC^d>BlzPV>@}`Ir>|e5`za=~e!G=AS>O?kLRxL5Y-t}rstG}h8VzJ?FulK2ugLIX zwY+mAgJXx!rM*DD<~W?rdmnhE_?u5=c_fJ??C}~WTmJ8~odcn7v3hZ~MV&?VR<=C) ze@>BCj$W{XidL-wF|%%? z0XJ#iG%$P^o}Hu^2xwOMF?>8#KPJC?G}G6D$-U5OKh`?2(W@P@R%6R@L%GHACo7Hv zL(7j+HGD;`;%sXvGcv*KW|ySMQ>uCe`$>STu?Qu90^d;u)q0^&F<+F-j4A28B|D2C z7?B|dhSj;|aGcT~nT0rtd=mG&^7zz&%t6ownmu_OO=PE zS2fH=C9HH6m$1!xs|j{=_S4PrY74>zVTf(}BTn0M%a;#EXTnBDSjr4!7Y*)X+G3*? zhXOFgv^BFN#b>k5_F`)|H}|<A5tGOH`Tk6F<3UDyTnt;FNMGsdh%L1A zCP%K}sv4`JdN0AV5F`ClEyW13-_HQw9Z953L8;V|J`$N=iKgnD4$`aVl~ zOp}}lQXB-6PD-fs&>)xVq=D5^EjG}NqdPg&6+!9=8Hg{ihhrO#i^B=o7k0<<3NcZy zCp8l=j2poC_O(Xq@>}dze7@25K)c7xid!p8pDfX2iFmYFuBWZFnj(ayHfb?Sp zK!G)7HZce+PgS!fXyuwd;7p&zd8E1 z21>d}rH($G-#I*ABx{x|l9-=zn2ZyO1emvjfP*dPHUu%nX4PZS_=#L@-tQ+oo2fhm zV64#=)6oFCEQrn4IY>xKZh;;b@s2ky34gu1ge+>Pp!ss$;OgCM=muBT_e!;ZV$y$c z+qm%~nZuSC1ZuO2RzZaTzO{Bkl3OaTgJT}TDg*Oj948vyZd5i8FcFXS4uqFS(Wkd@tH}J zffd>EmD_d)IQF}YS6Uw(DBq1oDUEObr;LjBz_G>Jfm2y?;q2j!%W@kazytcmzLH7k z#%1MHn-G12P|^O#U4#gdR_YmYZua{)&f{W*hu72bWh(J&68uicBO zqO2b1vF`!wKdhcb6kWob*&pbzAq0tF`@w(h_W4d6Do(9q`$(r6X}&_AM72O3TLfvD zZOMldlSamW{I|l@JP9&s-#Cb@9#6aBPPJ0+h~6|rPUL~iV@dP#F>eAK#5 z(XFwUh)!X!ST+S0IHGo~4WTvn+VULH2VhTJ8vKS=(FJ|kgI=VZ>RY+u#wuhNK3K(V zWAWuM?065r0F1Ksl~6sqj7t^_Tv8|m-P`D}lomE`hm0iyV}YzL7slCx!DF^#dCwOeIi4471C` zj}s48eIOz~2>M6F#7v{=|AT=1J)v9sDcNm2oi8wC`zHoxS1zZ?$p1TF`ng;}Y(s~0 zRW2@7KAb|*!(KiAJ}UX=9Cj{)6&VF7?dDT6yLSFr?^5@gRsg;ugc=6ka60@;HqLsB zlqRS7%1s$0-MDTuDLXk7T4bac47+g_{}nbZ#%Y@4{v9o&esk})82n{p1+u`$wD$7V zz%RdxPcvJ+g*;!K$boABc0g8rvQmZvG$%;M)3r%HgjSoRnJP>ce&LucRF^^`uh4JF zrn9criu&l8n~4QgLwh#D(vIcijzd#@ak3Q{mIbw!z>pMZnBYb>5SlPqWo1j7 zPB6&3nC@UUF8dY&YuoYf4F-hydXzGiyA`eV3Y~9>ooa5hYbBR(rQNG8Bps4kmB}%+=iMQV zy`W_iq5}l%^2jv}(umXzc0}A}7zdPN5a$0rtD4AYwyoHMG z=9}F-kSfxWyJu(Ayp=L>;+)eAPQrnKfn9TXE}WC-6(a)uD{c-}^tsV5#{=CGtlxTB znKJvYV_8FunTbYZu}ea?P_Vbu!-{zKnflI40<)MiIQ+Ql`9NFMKa>* z{p}Mh@}6ZB9GIzcMdv*Wd=j;wa#=MLG5Ilr*qqBfjWbGA_t`RkS}4-(I`z-LzFO!r zx&N;hz-y{8L?&cWoA~Ipjcff({)gK_2EPw+T7y+$w%l3)C0sU@e6q-3Um}x!5E2?T zC9d(9+G;0|y)OaAku2Boco}|;LW*2wdIwxdG`Em1ie%rF0EXcN?tjF5=jeb!4;nMK z^}WFa5D0;|thF$l!VBc7@#;P8XL~8M};- zU$sX#r-#$k@O@1lA+@>rrnjPFEl|$P3@nyBpoy4@Tw-VsL{3bkV{w7EaB19fq2 zVg5)$o7>Xg9hLBp_ANoOfMIK)AFW8}`7cB1gd_Oc(@Eu#CN@a{vptktg(M;E^sjYs zPPpK?);l2)CV5@g?&XOB%D@*ho zcj|Tqg_%tXH_Tt6#SUCzy`Hj2wy3=I=bIBUgVnr}?m&U*X}7|YauS`pf`6T&h1zZZ zSr?GdU0hP6MpG6&)(@7;!Q1>^s9aE<6cpV3*uA1^bUgH*678Z@sZCZ839Y+zICef| zEdNQ!_1yvt^Gjc+?tem9&$F`Gsx^2+lbvOUdZpGLQfi8A6EtY9ztP@o69!^E>7u7o zG!9L_rjtv^hTV$DnhZ_1y#QgYKF%Ti&1$+7mVncSyjX@3vgB0lGqlCw!XzaevvzC1 z%KH9z26iP5cHqrU)989>6v9BEFDak^a=&;Jtv3--SK!G_WD^C$}J$|b&k>cSrm!*E#8gxpFe3R5XzxaIjlh-&g3v8UV4dh zl>^!~`6Ks`9boPjiPp`T>HuEwzqhw%mYwl9P5Y7GOAT`ts@7x3+f7&P=c!T8o|447 zJ^1<*QCFs=LIDDy;0TVopYNfWxY$s3lu@%RFeA@%t=f9HbK0z3Iv<{6Xmq$|wiu`u z*@rSe%!Z9+RAMjnT3y-g31D%AbBLw-%zVQ4qGei5ws737`kEcQkmo*xC#=u=`4I^l ztncdajwaR zrMB#!5N3;}w^gM}y$F0wkH4F_lllaT~CWIn;dLa991$`zBtqqA#npS%v#sZT2%M$*h)5snh}?*leHPnP8El2)~2%mX)bf7QWkQ_e@pBQ1aSAhZw6KJ84TfmW6Pik0x# z5B2Z6YJt&ZY#>`|0i;SKaXjxIt&)6&On=beD6uTe?2F~^TqsrpsFy1(F8Ud4`0Tko zI8wQ7BmdTjSGi7M22|)qL|>A*UOk`3%Cm7(A12#z!sps4qLK(f zS@!fuJTq}~pChHuDNK{4_*=u5zf>nH=B`Q~b z5JjaG=+L3FP=2-YIqf48AD@d@bM1G|T?Fb21Ony2=cjG;W$?ZAC7PB+c;WzGE2M6V z6OMr|{gQIX1fP>d7sz~?8{mL@M#R5Ezb*8KdvR0rpRqd43Ud)EIp6qSznqf!=G3Ie zo?CnocU}aB(N{|{pNQL8&>pZ>F73y>gsNFc^duE)UI;%x7j+5R(9(D zbKy!v$2ZefsJFS_-a~=d!OdISGuzWlSsF3|UiMb_T5>wOW(2tsC9P|EK9mt+v{#lmaR@IOHrjck(|a_XR|l&@9+FUc z%lkT?>EZ*IN@vtReVinxlU)YQO2ch9L&ouFvYea1tX5=P7KDwGSR)Bk1mhy%;{}Od z_QY{4psb|tFpfqdM$y(s;Gg*7e7snwH{n9ia!!4hZLgj6hf%1M(1a3F+jgiae;*iq zn5XBhb4{N#EGc54Uck!|!De9>Wct!5GT*Ltp2b#JXRt;Dlz)66l6>0C^p*r+nkwKv zyCLD!vXqQc{E)Xn4T?{A9G#e%#%XBC=)$+f(MIS~M`xwWoOD14J=?)Q%+`5x2 zoY{M8&(43pY(gQQfWx8o1gw23vriQy8gF1_4D}&k47xyKlhH1@=UeB zR2^$L6TM@lHN-6}vH!q(gc{X|mUZRvR+EUw5rziz;Y^fMerM~eEnja8!M2=7N|ES# zaZ{@D{Nnk1+Q2qGbZomq5I7L!lk{q#R+I}VPAuT+i@o`d$Kwri`Xw4E;+TKaL)Q>% z`H=e~3?xNsZQX2-R1}+WFKze@(Jy=l+>MvM5w`LaZWl#R%zy-lqdlXK$Uio>Odii< zQYqQ^>c5ACA1YW*Js87q1~Y&4AJHr))0vky|JxYz;67E2-I%S4XOPBWHtH*Rdn9Qo zG=v$MDfDyo8I4r)&dQF~@>}L^gGTRD1mOA7wkyU%n8+o4s><{UopQpTnA>dpag0`N zHWp5g{UMrJf#7e{x;(@Dr;UrM?QAjK5^a;62}`JJ2ILezXmH+0uBOh_uJ18^WrSU$ z3VjWq>Uz)A>|tPw`*P89zgY8+bY9Y?w`U;Aq+_}-EK78C>7TX%QXH+?WQ*IibE}%9 z^3U%ODr@Vil+5dy=c!VLC6A~Fr@S!mcc*dR6yK6Kzpy`|P1pFQ;>ubrRfw*T z%Dms@6%X15_7<%c(}*4P>0E`dm>lTKRTt_y9fB{RNz7l2v7@`8_*l;0K_Mt3B^VP% zg(D2~UT$aerY&gIc)w@<$`eIq0}XiK6puLh_Fln?x&aZ-(|yR<)Wfbi`3t;w^-&|eHjrLlet}(p$6c{0XPfq^qj?Fg3;YLrjSY4PNfx< zG!W*ic(D5>pfus}%@Ts9*!W~2AxMjb;;`JISn2eP9Rc9P5Pt)=JM9d3Rr1L9qkO?& zHzXqZz<_}8lULdc(i~VQ`mbA@kLd$M2O^2ZJG^Z`C(nlbuXB6`z zyHA2l!jC*T3;|D&U^zScVvO5X`U;SY{kHmKb0kJg4_3f(&*s+gv<#9q-eL%(p#vYr zRuEz@iP*8gah$C-6g$24M^DduEgRPR=}<~p^GmI{5E9mCl-o6qL1ROdE)pF~ZuCW- zb=pVJi;G%syH0i;^us$cLgkihG6%G|frNO(Xbs3bVlLN#%p-{!aa>b7z^HF`KVFOF z-wur65+EjDDT5nnYU(fky4N$R^ZDPLz6V}--hyOH<24!K0-@&@4h*8}jV|#aalplf z8XwpFbSd#J=Q6_}((LA7ilB(V=&xqQ*S=0s=(;_2jo;)ZvbEo5o?hDwoXkQ;S`vd# z{}u2&O>T%V1jC!nGb1nW_ek`Z*Q!3-T&85!L zXThcGG(F3p=MA5`(lscz>Du}ihC43T)fAek?Y73f8fuI|r+PNSA^ zqst29S%9G>CkRp2R>P6nU=ilk;)2+P7V!ggZQOm6w?hE^(Rew&nHKZA3_P+{ZvC}I zAfJ_5ii*$;&e*(GhA%U0A3Hy_kS5)>npYSvR z^}(x$v+U}hEdv-Je@)TPX;22|_t6TP$?QzvVAa+a>pGH<(6=%#-}VYv{6d$0kz?{Z z9+0{_9V0~LA-=iYLCpXlwX^dxu z%J+|^)H+4hT^GKpqssTut8@C(V9PadagUx8z8WM$t00`<@%4(I2@|Ma7al0q?EF<)%R!%POeP;#W^?e0N#kGr;ifW%TVat+)Om$v3loZ#FGu`!Z=?W z9A4XPW;9wcG4<(7YsI%sZ4v(Rz&iutM2RMI7&;O*bATa*lnirN{+aDu)4Y;?YQ8 zC!9nG3BA|Et5?9@wO9LbZ9JBjq5X4$tOYNNZaeKcs7EW7vrb_O`_D-tUfO0mx~^;C zl{GIr+NGGrsjS0-a(~+cSi)RDI&c{o+8&siYl80ooI$?+;=X+yWzclGoZWf;2nh{8 z;7W45PWTo1MJ<=MHRyQ*#QdhPhHn0gE0V|5W=0jwhfg%=y*~Z15qz&4#Ke)oP~~N9%Q=cw{4RIklx6GojTzNK<# z_oiN+S#57${v`{-20}M1)p7cI&$zWiN~7PLMju15m;>1JU<_n`M}a(grlX+=Xu(Upwzw;yE_`wQ_LRv_||#}a0sL) zO+B4q_NVSQqO=${kLiaW7wuRB_@Pkm71-1(}D}0H+5Rd-{}x;Z99Vz z_;jYk;legANHmB-&iUyEKP6{R;vv0fER|~j_%DH>qyPiI3GLl6`Q|RKyz$&fA_Id= zC=qXs+@z4x(JYVC5mvEAkssh+0M7pJ>}Ym=M;y2tm!7BFn1iLVG!2Lf_}ofe6w(^I zM42q`$Cd+h1@q}#HbBP?soXWRb0G-_fPKS}`LgZ+r;ACl(M*0#2vXfFTZlvjAsQ^+Meydu&6doGQD;^$8Nd8<~T; z1Z}QZ9iM-H#8)rw{YtBKR08F%^q2hJa+2`g!|tCD5{_q$k{h^ZGhrpduo8B#A!T54 zX=OYtz4y~eNdsZ;)Pi~JCb0~R_!E>3e-34U{z>zWDul29x}-&hu67xW`LVHux@hn= z&La8hEM&-|5TmyTq6~8@Sdeg;DW8=!GGql{3NBpN-jAhnhfU3bn#E0k`p^jb_jexH z)eYo3wN4iaxJtT)h7e7Lr{B4wz2fu-@LH!%WC-JStT%bU z14gODu-ZC>T)zC^H}N5vx&&DwD%m8-zxHTQ(uVBx4PRo`!Je2(1`igv8aWN((F@O{ zurakyn-zh}5U%~{ih;H8^CSYYIaGh-dkoHqP7L}THn&e3UqjW_f1a>|Vp80vKAVf|O8ve4?SdYx)>kkkHpDx;C|~(iKIDu15hGo6zaKyC_8-XRgQHKld|a#b z)`j_;3iYxttX1#&?x_hqc8sAX@sIo1k~aCcLo`3y**Z<Xpb(XC9|KnV{V~Gh+1KQSxhm(i#jgMLr>qS_ zgYG%MiDZM>ay9U%zEC}Ok!DGLo@rVjs`xccG=8>FvBt1Gfr=@TJ0UK<$oxoda69}AzeyQqA=`)x`^F9fGMx_p6J6cx!ZJZvY-zeU{9kKXmed$ z?aDobqlx8*A8sh+b1MGk4Pyi~Is3xK?}xw1TuFq$dsyDnCy)zzpHnb(F^V3}Un&Ea&G!gW6IT{K7Y zPinccIgCU7m4Z~Pb(%ZxFxs4E{o3k@EsQf-0IA`8x*E0WaoBuPQ1sY7b*Jc zzV#eGg&$)!rsIopI722?U;1mM5f*T#y0X0Uvz2fZUhKE23Fch7d*IP8AMV#T&GWs7 zKY$f_ilkgslQylvdM2~ zJsuATAx=|;K}1AErF~sik6p3ng{D5IPfqgb=AmQJtp(~O_1YeXmc@fCT9sNYdV>KN zObhn^-UM$BS8>xmS|^;Qu$y!OpbV7;uT^pbMk1}crA9dx53=oB{K@#Zh#jJioCCDtD1Q=$p;Aw^mqtfijbkJv>g=tWou-F5+at z#aNQ05k*j|bdie~FTtUgjtP=UTLGIBTO;J6}&OdKwnG4%EF<|g(* zIN}k*zeu~`JCoZx5UGs9-q+t7wN(?i+Mft!H<8QHX(*qPE_H49_Ij3C`?RO~cN(+~ z`JeRgCa{~(pRC&sGyOn2-p4|mSb;;q`iI4$hk{M?q0(}n85Ni`5D_mF(*=qJRry_x z7&}V=72MJdLN6GJZI5@xJnsC%+pm!p4c#DFzJiI2#1-0zz@#RJT~QEYU;9I4i?-{L zEL5L}?3NT(Iqvt#$@ZE!hujs!y0YiKTzr^tP@$q`mc&5uyJPI<;HGC`_4#C%(e!sa zO|wGl{T0T#r)87rPiybDmy~+6N!+sPsGEqU^OT&oow(0TnD*_SmtxY*YQ%@&1~b=c z_=u3jWefd0->7G;6cKofr}o#d3>JI6`HmHv^h$dtEG+Ev*fUmA)vr4%*RaQ~OPa|T z#`BvPc3|^<#iux!ts@Lgpe;JJJrzjY8_+~-4`p*XNg=#@2;6|)Be;1)@`$Xd_x4_P zsuXnSYt=OzN&NP-6M~S+iuk2E^&9OEw@9t#OrsL`YA2TE?FN_CU=i|IbceG`J>&M1 z<6bs(J8Qw`S&pCkk2k6#620?F-zTbwvQ#m{6EDkq?riRWhI7s% z&)fUjp@S<8zT+*`nqToHdacmMV0NMOyeb^o=19420__yTPWICdHD|G=j-`CNK$8*Y zsJ3^f#`3I8xPYu`%awwA0SAfw!2u#qJRRL5y|z!3VWCoee6-?>bcSS~e4F)p6Jg1M zwa5&dB9G%uGDd#H4FM%r!<&UqM@kmDChn=hBb^>I;Ck@xNtvnSJ^RdC!-~kLsm}nV!D&a^XL0{VrF1BfqYg9`s z^i*omum-=V9*qgAeh_OT7m|{MqqkuF}rHMe9y^b z3W0;LkC|AX$0F+(OXAXC_bcej*chp3?;Lth1A0sd0xD3W`cEc4P4$MT*7mFe!!Z{M zwJ#bmA1w(NOfF0WYJYDC8Czvu z|CFP*M@?(3QdxX71DjriMp#%_txQARdwk{Q*18u9Z{&9md-lxi+56hpHM)op;~-?a0u8{yR5Ga4UA*=t;qNNV z3@X85pv>X_e1;2(po%Ra z;A#^8bvB7(Ie}YG*+NBV#?g2aIY+HN&a3-C$Sok^c-7(y7M%9>NK*zTQ~|s$)qWTf zh>QDFAr=8cAm&fm_=%`w)mCo%E!wMsj2$G)>k}4dm(S^QLc#=c*eoAk<*15(fKJ1L z{{B*@?)5>gKZ^W!+93|3o$B|E+9UZ+%)y(6-z(A$sPHgO4HCzI;z8+n3xhZE?Ilr! zJ6w%csXi9CIXx**OBxucc*P*^&uS5+)q;wmbf%s0h4rc*Qo^h2!70BX6%m=M@JuJaGdCHY#Fwa&}#>z2I@CHf4Wmk@%-KvCK9~j>$zv9%rudaG5 zo+!QX!lnwvdrdcb~dp*aBhLb!h1^q4RBCQYaA1uJRJXHfI0YIO2#F?zrHp@l`&xXq&KWBP8KhSY0 zN(vuko-7VNiK?W`xmsRuKi&tOOvhWtVwuvB^b=JhTqL)3yj92lMnkvEx{z87zMHFa zht=V$h{b@GPYAJiTOJ@ASl0Y-gW%KXK3XM#0pT-Od&|ISHSI@zzWXAdE40PKx>*>U zev4GAn#nk8C`gD%Jc=z~*YpmQkk^za0jp zxNt2?)}10@Z){PgY&Uy6p>Y9 zU9c#U2ra}a4cUls4kwJoa|n+5i#;*j$%C>gt!lk!N~tsW0@ELMk*{o5OkU96l%62L zi7tyif73Y%(XH?;>bli)S3YzTH|@uVSs3JV?|3be;1}FG+yM7Tjg(UHdpLoeMAz+@ z2e5o(-fysfW&~1}Ocv>WiTo`*@?KnXavto>+7aYf@&w)PI0xoDDNTkT}6w<0Bq_nSetTjv`f5dv(c2yRX`K8;&QUler~R@%+W)% zpTZZIcin9T%_S~b&^i4(o5gmf;PG?hiT~bkbt1!E7tIfB_+EgrC+j<#*Kuu%CRnH< z-b!UMBP1MzI(8qlMx5;4g)neGI}R&6)-Lt5uv}O219J6dYJ^JZ()PaMr~EG#hdm6s z1M9BC1a3k7Z+vxFx8W<(V}$xv=%P1$c+@LX^!#gYwcUyCq*c}vS~1(bHPifS>Qnx{ zM7vE^%L{(P;kf6y%5I?Ct9^s=#kH7NI`zii#Ng*}M#vF~PgG~n3q9OspIhV;bmiQ5 z=7)}$w|1yY?5a)X6kL|A#~9fola*Q(c6ctBw}*1B7k6(?XpfO2KCO*Wq1x(X3Om*Z z#WEtn1Q%V9@G(mtin^3dvA;jGOsgR`Tb%U`#c0$(i70eEJeaSsyX6F2_0O|mLL(@Q z2iiW}O9(k;zVyk7&TfFfEjd(BaNxj#gwaJI;-`FuC@0C80i+a{Hq#2(7f)*}XVc%5 z8N!22yKexSR`X32E3N!^tbtT`y4&?9{C=Ks=`y4KJPz+oIZ)t%9Ae>u8B<$IV^)Bv zKbL5G{f0%j$Ri_9x^D7Q=~;KL3QZ)J_50vXN`T-L%TvvzTo#QhT=b}?*{6uf#?~r$BQQH``D@__X5F zI+ujf+2;9fGpT!B1zY?}s-3N2P>3b7oUxyA?~cwlgqgK2e3oo?0622l)F(prLFF0$ zedCQ5I^CkjseFY#>FFvQ+bW^j4jmx@WCr(Q53!`n27fINvGo|l9-fojEo#8g{bg=C zm0v+>aNwkC^ZcadCERy6mJB(;D#?D!O;Sz;}Kf?83e6jdwN2oZHj&ULjO*q^0BB46^5-149A7@(;vzMj_ zihWL&xP;yw{go-h5QL&p{Js@MC^HO3bk(tJT<38eCx%X?YX^0Iu2vDSj{p#$*j{ARWc4()U)oII6pyIE!6t3Q3b66$jMcyO)G9oq?1gh zI3P=a@((wmCwa8?`Oxiay;zHo=0zHEejeu_&}@2(OdRy%z`ZhE&_e?WcO?|LFquLF z8Ka*gn#gd@Y<49SJr@kX407_u9p>|kWUW>=7ZIBt&_lDdX-WPaw7ubhgsC4D!vv{; zUj>^Y)BC27z~3J;tizeO9S#Uj)&_EAMt18jssb^qanhAc=W6x4IQMMQO8Xx( zU{?r8J9{$jgcM*_e?6+9bX*>aKq}*Nngo14-);Zl<`To8d(gatvby%jhw`NCzCY{G z;qBu}Rozb5*AW;EI#V!#z|8a3)>Ye`HPgE*6}_5Tq^m`aftp{BV^GkU_J<2dq4>=Z zn2(ACN5sq@J3cRF0E#6QrQD=G^m*;qi%r(%l=v^;k;UUIrr*?C2?Xyj^IrmHUDR48 z!p)%+i4DfL%S&4UpOCQ@F3L#8Y|D*bXOPxi`9rJtO<%Os4`8`YUGJYi&W=G%yIL7E zPYIwdPTrMXwoI*xoqLrE-n@}wx^N@_t*Gvq7bS60rsEZ*9YBr4z9lrdnu_V0fH`)q z4BK#q`2Jkz;H=|!*X#>iPI_Ue%z_u;E#B?jKx-8LjqOkET=evfBI&9GsooSapYgkv z6|8)N!DC#Pn5L=5L$7hSXuc?5yYS zbloEZN(i11+VhhQ5eZloJrn0O811@GSOUBbBS|duEVxEFHg5;S<3vVI?_p6W>Cy+V zNqt}7FEl~WYSn$ss%SNQ0dXHhO3Gpgnv)vCNR)qy4>Jw5mB=r3^r{#~vUNIv8oIZ| z;qI^Jc<-a%AI%&_N&is2jLudxU0bm;$IlWNEzbUlJHrmMM}AlH5qjGxztymjsL>q{EHv&&K#J* z;E_X&=#bZ}Ab)i}0vCx5bdk3lwZN`>%YgPVot;-XZwt#RT(5U*z_m_VW$Zh--|Pt5 z(bggYKvb8^aA|pALXv_YEwuIC^{uL$8jU-Ev?bJ=(0O>CK;M79i1_f>c#ASpZcd~0 zeAxx=i*4Rp9rLH^VY|(v@Rc+2*qBNJBQERbg1C|8p&_8$zHj93=Yu z1fLX>{{S--%d zQ&Mb+^myG%ebI@NmSKc}(awqC)Hv_|U8g^*=kc8$#{x>is4$2-0fq6JQb_N0sY}Zh z@!gc;CnQ_@~t%{?XYnhHp$kBD+|BG~y|$a3EV0$9$c;6hMmbUlS!~IDVIm4Wd

d@V;7b!Yvx|Acjdv^^=n8 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 diff --git a/compose.yaml b/compose.yaml index 1f71625..09033f6 100755 --- a/compose.yaml +++ b/compose.yaml @@ -10,4 +10,5 @@ services: - 8090:8090 volumes: - ./core:/app - - ./pb/pb_data:/pb/pb_data \ No newline at end of file + - ./pb/pb_data:/pb/pb_data + - ./pb/pb_migrations:/pb/pb_migrations \ No newline at end of file diff --git a/core/agents/get_info.py b/core/agents/get_info.py index bb00fd6..5922bc4 100644 --- a/core/agents/get_info.py +++ b/core/agents/get_info.py @@ -23,7 +23,7 @@ class GeneralInfoExtractor: focus = input('It seems you have not set any focus point, WiseFlow need the specific focus point to guide the following info extract job.' 'so please input one now. describe what info you care about shortly: ') explanation = input('Please provide more explanation for the focus point (if not necessary, pls just type enter: ') - focus_data.append({"name": focus, "explanation": explanation, + focus_data.append({"focuspoint": focus, "explanation": explanation, "id": pb.add('focus_points', {"focuspoint": focus, "explanation": explanation})}) # self.focus_list = [item["focuspoint"] for item in focus_data] @@ -188,6 +188,9 @@ url2 if item['focus'] not in self.focus_dict: self.logger.warning(f"{item['focus']} not in focus_list, it's model's Hallucination") continue + if not item['content']: + continue + if item['content'] in link_dict: self.logger.debug(f"{item['content']} in link_dict, aborting") continue diff --git a/core/docker_entrypoint.sh b/core/docker_entrypoint.sh index 0f03100..5ff5654 100755 --- a/core/docker_entrypoint.sh +++ b/core/docker_entrypoint.sh @@ -5,7 +5,7 @@ source .env set +o allexport # 启动 PocketBase -/pb/pocketbase serve --http=0.0.0.0:8090 & +/pb/pocketbase serve --http=127.0.0.1:8090 & pocketbase_pid=$! # 启动 Python 任务 diff --git a/core/general_process.py b/core/general_process.py index 5d65813..da6931a 100644 --- a/core/general_process.py +++ b/core/general_process.py @@ -22,29 +22,13 @@ screenshot_dir = os.path.join(project_dir, 'crawlee_storage', 'screenshots') wiseflow_logger = get_logger('general_process', project_dir) pb = PbTalker(wiseflow_logger) gie = GeneralInfoExtractor(pb, wiseflow_logger) -existing_urls = {url['url'] for url in pb.read(collection_name='articles', fields=['url']) if url['url']} +existing_urls = {url['url'] for url in pb.read(collection_name='infos', fields=['url'])} -async def save_to_pb(article: dict, infos: list): +async def save_to_pb(url: str, infos: list): # saving to pb process - screenshot = article.pop('screenshot') if 'screenshot' in article else None - article_id = pb.add(collection_name='articles', body=article) - if not article_id: - wiseflow_logger.error('add article failed, writing to cache_file') - timestamp = datetime.now().strftime("%Y%m%d%H%M%S") - with open(os.path.join(project_dir, f'{timestamp}_cache_article.json'), 'w', encoding='utf-8') as f: - json.dump(article, f, ensure_ascii=False, indent=4) - return - if screenshot: - file = open(screenshot, 'rb') - file_name = os.path.basename(screenshot) - message = pb.upload('articles', article_id, 'screenshot', file_name, file) - file.close() - if not message: - wiseflow_logger.warning(f'{article_id} upload screenshot failed, file location: {screenshot}') - for info in infos: - info['articles'] = [article_id] + info['url'] = url _ = pb.add(collection_name='infos', body=info) if not _: wiseflow_logger.error('add info failed, writing to cache_file') @@ -84,23 +68,25 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None: context.log.info(f'routed to customer scraper for {domain}') try: article, more_urls, infos = await custom_scraper_map[domain](html, context.request.url) + if not article and not infos and not more_urls: + wiseflow_logger.warning(f'{parsed_url} handled by customer scraper, bot got nothing') except Exception as e: context.log.error(f'error occurred: {e}') - wiseflow_logger.warning(f'handle {parsed_url} failed by customer scraper, this url will be skipped') - return + wiseflow_logger.warning(f'handle {parsed_url} failed by customer scraper, so no info can be found') + article, infos, more_urls = {}, [], set() - if not article and not infos and not more_urls: - wiseflow_logger.warning(f'{parsed_url} handled by customer scraper, bot got nothing') - return - - #title = article.get('title', "") link_dict = more_urls if isinstance(more_urls, dict) else {} related_urls = more_urls if isinstance(more_urls, set) else set() if not infos and not related_urls: - text = article.pop('content') if 'content' in article else None + try: + text = article.get('content', '') + except Exception as e: + wiseflow_logger.warning(f'customer scraper output article is not valid dict: {e}') + text = '' + if not text: - wiseflow_logger.warning(f'no content found in {parsed_url} by customer scraper, cannot use llm GIE') - author, publish_date = '', '' + wiseflow_logger.warning(f'no content found in {parsed_url} by customer scraper, cannot use llm GIE, aborting') + infos, related_urls = [], set() else: author = article.get('author', '') publish_date = article.get('publish_date', '') @@ -109,28 +95,28 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None: infos, related_urls, author, publish_date = await gie(text, link_dict, context.request.url, author, publish_date) except Exception as e: wiseflow_logger.error(f'gie error occurred in processing: {e}') - infos = [] - author, publish_date = '', '' - else: - author = article.get('author', '') - publish_date = article.get('publish_date', '') + infos, related_urls = [], set() else: # Extract data from the page. # future work: try to use a visual-llm do all the job... text = await context.page.inner_text('body') soup = BeautifulSoup(html, 'html.parser') links = soup.find_all('a', href=True) - parsed_url = urlparse(context.request.url) - domain = parsed_url.netloc base_url = f"{parsed_url.scheme}://{domain}" - link_dict = {} for a in links: new_url = a.get('href') + if new_url.startswith('javascript:') or new_url.startswith('#') or new_url.startswith('mailto:'): + continue + if new_url in [context.request.url, base_url]: + continue + if new_url in existing_urls: + continue t = a.text.strip() - if new_url and t and new_url != base_url and new_url not in existing_urls: + if new_url and t: link_dict[t] = urljoin(base_url, new_url) existing_urls.add(new_url) + publish_date = soup.find('div', class_='date').get_text(strip=True) if soup.find('div', class_='date') else None if publish_date: publish_date = extract_and_convert_dates(publish_date) @@ -139,27 +125,19 @@ async def request_handler(context: PlaywrightCrawlingContext) -> None: author = soup.find('div', class_='source').get_text(strip=True) if soup.find('div', class_='source') else None # get infos by llm infos, related_urls, author, publish_date = await gie(text, link_dict, base_url, author, publish_date) - # title = await context.page.title() - - screenshot_file_name = f"{hashlib.sha256(context.request.url.encode()).hexdigest()}.png" - await context.page.screenshot(path=os.path.join(screenshot_dir, screenshot_file_name), full_page=True) - wiseflow_logger.debug(f'screenshot saved to {screenshot_file_name}') if infos: - article = { - 'url': context.request.url, - # 'title': title, - 'author': author, - 'publish_date': publish_date, - 'screenshot': os.path.join(screenshot_dir, screenshot_file_name), - 'tags': [info['tag'] for info in infos] - } - await save_to_pb(article, infos) + await save_to_pb(context.request.url, infos) if related_urls: await context.add_requests(list(related_urls)) # todo: use llm to determine next action + """ + screenshot_file_name = f"{hashlib.sha256(context.request.url.encode()).hexdigest()}.png" + await context.page.screenshot(path=os.path.join(screenshot_dir, screenshot_file_name), full_page=True) + wiseflow_logger.debug(f'screenshot saved to {screenshot_file_name}') + """ if __name__ == '__main__': sites = pb.read('sites', filter='activated=True') diff --git a/core/run.sh b/core/run.sh index e2ab4b6..d7668cf 100755 --- a/core/run.sh +++ b/core/run.sh @@ -7,7 +7,7 @@ set +o allexport if ! pgrep -x "pocketbase" > /dev/null; then if ! netstat -tuln | grep ":8090" > /dev/null && ! lsof -i :8090 > /dev/null; then echo "Starting PocketBase..." - ../pb/pocketbase serve --http=0.0.0.0:8090 & + ../pb/pocketbase serve --http=127.0.0.1:8090 & else echo "Port 8090 is already in use." fi diff --git a/core/run_task.sh b/core/run_task.sh new file mode 100755 index 0000000..db1f993 --- /dev/null +++ b/core/run_task.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -o allexport +source .env +set +o allexport + +if ! pgrep -x "pocketbase" > /dev/null; then + if ! netstat -tuln | grep ":8090" > /dev/null && ! lsof -i :8090 > /dev/null; then + echo "Starting PocketBase..." + ../pb/pocketbase serve --http=127.0.0.1:8090 & + else + echo "Port 8090 is already in use." + fi +else + echo "PocketBase is already running." +fi + +python tasks.py \ No newline at end of file diff --git a/core/tasks.py b/core/tasks.py index e6ccef3..f214a59 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -6,20 +6,21 @@ counter = 1 async def schedule_pipeline(interval): global counter - wiseflow_logger.info(f'task execute loop {counter}') - sites = pb.read('sites', filter='activated=True') - todo_urls = set() - for site in sites: - if not site['per_hours'] or not site['url']: - continue - if counter % site['per_hours'] == 0: - wiseflow_logger.info(f"applying {site['url']}") - todo_urls.add(site['url'].rstrip('/')) + while True: + wiseflow_logger.info(f'task execute loop {counter}') + sites = pb.read('sites', filter='activated=True') + todo_urls = set() + for site in sites: + if not site['per_hours'] or not site['url']: + continue + if counter % site['per_hours'] == 0: + wiseflow_logger.info(f"applying {site['url']}") + todo_urls.add(site['url'].rstrip('/')) - counter += 1 - await crawler.run(list[todo_urls]) - wiseflow_logger.info(f'task execute loop finished, work after {interval} seconds') - await asyncio.sleep(interval) + counter += 1 + await crawler.run(list(todo_urls)) + wiseflow_logger.info(f'task execute loop finished, work after {interval} seconds') + await asyncio.sleep(interval) async def main(): diff --git a/pb/README.md b/pb/README.md index 516f57e..4cdf40c 100755 --- a/pb/README.md +++ b/pb/README.md @@ -4,6 +4,6 @@ download https://github.com/pocketbase/pocketbase/releases/download/v0.23.4/ cd pb xattr -d com.apple.quarantine pocketbase # for Macos ./pocketbase migrate up # for first run -./pocketbase --dev admin create test@example.com 123467890 # If you don't have an initial account, please use this command to create it +./pocketbase --dev admin create test@example.com 1234567890 # If you don't have an initial account, please use this command to create it ./pocketbase serve ``` \ No newline at end of file diff --git a/pb/pb_migrations/1733204939_created_articles.js b/pb/pb_migrations/1733204939_created_articles.js deleted file mode 100644 index a2816a1..0000000 --- a/pb/pb_migrations/1733204939_created_articles.js +++ /dev/null @@ -1,121 +0,0 @@ -/// -migrate((app) => { - const collection = new Collection({ - "createRule": null, - "deleteRule": null, - "fields": [ - { - "autogeneratePattern": "[a-z0-9]{15}", - "hidden": false, - "id": "text3208210256", - "max": 15, - "min": 15, - "name": "id", - "pattern": "^[a-z0-9]+$", - "presentable": false, - "primaryKey": true, - "required": true, - "system": true, - "type": "text" - }, - { - "exceptDomains": null, - "hidden": false, - "id": "url4101391790", - "name": "url", - "onlyDomains": null, - "presentable": false, - "required": false, - "system": false, - "type": "url" - }, - { - "autogeneratePattern": "", - "hidden": false, - "id": "text724990059", - "max": 0, - "min": 0, - "name": "title", - "pattern": "", - "presentable": false, - "primaryKey": false, - "required": false, - "system": false, - "type": "text" - }, - { - "autogeneratePattern": "", - "hidden": false, - "id": "text3182418120", - "max": 0, - "min": 0, - "name": "author", - "pattern": "", - "presentable": false, - "primaryKey": false, - "required": false, - "system": false, - "type": "text" - }, - { - "hidden": false, - "id": "date2025149370", - "max": "", - "min": "", - "name": "publish_date", - "presentable": false, - "required": false, - "system": false, - "type": "date" - }, - { - "hidden": false, - "id": "file1486429761", - "maxSelect": 1, - "maxSize": 0, - "mimeTypes": [], - "name": "screenshot", - "presentable": false, - "protected": false, - "required": false, - "system": false, - "thumbs": [], - "type": "file" - }, - { - "hidden": false, - "id": "autodate2990389176", - "name": "created", - "onCreate": true, - "onUpdate": false, - "presentable": false, - "system": false, - "type": "autodate" - }, - { - "hidden": false, - "id": "autodate3332085495", - "name": "updated", - "onCreate": true, - "onUpdate": true, - "presentable": false, - "system": false, - "type": "autodate" - } - ], - "id": "pbc_4287850865", - "indexes": [], - "listRule": null, - "name": "articles", - "system": false, - "type": "base", - "updateRule": null, - "viewRule": null - }); - - return app.save(collection); -}, (app) => { - const collection = app.findCollectionByNameOrId("pbc_4287850865"); - - return app.delete(collection); -}) diff --git a/pb/pb_migrations/1733465426_updated_articles.js b/pb/pb_migrations/1733465426_updated_articles.js deleted file mode 100644 index 588a62c..0000000 --- a/pb/pb_migrations/1733465426_updated_articles.js +++ /dev/null @@ -1,28 +0,0 @@ -/// -migrate((app) => { - const collection = app.findCollectionByNameOrId("pbc_4287850865") - - // add field - collection.fields.addAt(6, new Field({ - "cascadeDelete": false, - "collectionId": "pbc_3385864241", - "hidden": false, - "id": "relation1874629670", - "maxSelect": 999, - "minSelect": 0, - "name": "tags", - "presentable": false, - "required": false, - "system": false, - "type": "relation" - })) - - return app.save(collection) -}, (app) => { - const collection = app.findCollectionByNameOrId("pbc_4287850865") - - // remove field - collection.fields.removeById("relation1874629670") - - return app.save(collection) -}) diff --git a/pb/pb_migrations/1733465563_created_infos.js b/pb/pb_migrations/1733465563_created_infos.js index 73d9085..4ef607a 100644 --- a/pb/pb_migrations/1733465563_created_infos.js +++ b/pb/pb_migrations/1733465563_created_infos.js @@ -45,19 +45,6 @@ migrate((app) => { "system": false, "type": "relation" }, - { - "cascadeDelete": false, - "collectionId": "pbc_4287850865", - "hidden": false, - "id": "relation3218944360", - "maxSelect": 999, - "minSelect": 0, - "name": "articles", - "presentable": false, - "required": false, - "system": false, - "type": "relation" - }, { "hidden": false, "id": "file3291445124", diff --git a/pb/pb_migrations/1733753289_updated_infos.js b/pb/pb_migrations/1733753289_updated_infos.js new file mode 100644 index 0000000..2e98dbb --- /dev/null +++ b/pb/pb_migrations/1733753289_updated_infos.js @@ -0,0 +1,39 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_629947526") + + // add field + collection.fields.addAt(4, new Field({ + "exceptDomains": [], + "hidden": false, + "id": "url4101391790", + "name": "url", + "onlyDomains": [], + "presentable": false, + "required": true, + "system": false, + "type": "url" + })) + + // add field + collection.fields.addAt(5, new Field({ + "hidden": false, + "id": "file1486429761", + "maxSelect": 1, + "maxSize": 0, + "mimeTypes": [], + "name": "screenshot", + "presentable": false, + "protected": false, + "required": false, + "system": false, + "thumbs": [], + "type": "file" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_629947526") + + return app.save(collection) +}) diff --git a/pb/pb_migrations/1733753354_updated_focus_points.js b/pb/pb_migrations/1733753354_updated_focus_points.js new file mode 100644 index 0000000..9f64fc8 --- /dev/null +++ b/pb/pb_migrations/1733753354_updated_focus_points.js @@ -0,0 +1,42 @@ +/// +migrate((app) => { + const collection = app.findCollectionByNameOrId("pbc_3385864241") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text2695655862", + "max": 0, + "min": 0, + "name": "focuspoint", + "pattern": "", + "presentable": true, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + })) + + return app.save(collection) +}, (app) => { + const collection = app.findCollectionByNameOrId("pbc_3385864241") + + // update field + collection.fields.addAt(1, new Field({ + "autogeneratePattern": "", + "hidden": false, + "id": "text2695655862", + "max": 0, + "min": 0, + "name": "focuspoint", + "pattern": "", + "presentable": false, + "primaryKey": false, + "required": true, + "system": false, + "type": "text" + })) + + return app.save(collection) +}) diff --git a/version b/version index 7becae1..03f2afa 100644 --- a/version +++ b/version @@ -1 +1 @@ -v0.3.2 +v0.3.5