diff --git a/.gitignore b/.gitignore index 544d409..1c95536 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ gateway/shufeng.ini core/Nidus.service.shufeng ai_review/.env confs/__pycache__/ +.workbuddy/ libhttp/test_server *.pyc __pycache__/ diff --git a/BotOps/app.py b/BotOps/app.py index ca3170f..c3b62da 100644 --- a/BotOps/app.py +++ b/BotOps/app.py @@ -186,11 +186,20 @@ class BotOpsApp(App): stripped = content.strip() if not stripped: pass - elif stripped.startswith(("💬 助手", "💬 Assistant", "🤔 思考中", "🤔 Thinking", "🤔 深度思考中")): - pass # 助手前缀 / 思考提示:聊天区已有对应区域,无需展示 + elif stripped.startswith(( + "💬 助手", "💬 Assistant", # 助手前缀(聊天区已有对应区域) + "🤔 思考中", "🤔 Thinking", # 思考提示(聊天区已有思考区域) + "🤔 深度思考中", + "🤔 分析工具结果", "🤔 Analyzing", # 工具分析提示(后续有具体工具输出,此为冗余) + "🔧 需要调用工具", "🔧 Need to call",# 工具调用前置提示(后续有"调用工具: xxx"具体提示) + )): + pass # 冗余/有替代展示的提示行,过滤避免重复 else: - # 🔧 调用工具 / 工具输出 / 🤔 分析工具结果 等 → 任务侧栏 + # 🔧 调用工具: xxx / 工具输出 / 用户中断提示等 → 任务侧栏 self.tasks.write(stripped) + elif t == "ai_break": + # 工具调用前分段:结束当前AI文本段(保留已显示内容),后续chunk创建新widget + await self.chat.break_ai() elif t == "complete": # complete 携带完整全文,用于对齐已显示内容 await self.chat.finish_ai(content) @@ -244,7 +253,8 @@ class BotOpsApp(App): elif t == "notification": await self.notify_system(f"🔔 {content}") elif content: - await self.chat.append_ai(content) + # 未知消息类型不追加到AI聊天区(避免非AI内容污染回复),仅记入侧栏日志 + self.tasks.write(f"[未知消息 type={t}] {str(content)[:200]}") # ── 连接状态回调 ────────────────────────────────────────────────────── async def _on_ws_state(self, state: str, detail: str): diff --git a/BotOps/widgets/chat_view.py b/BotOps/widgets/chat_view.py index 09c0bf8..bfcdfec 100644 --- a/BotOps/widgets/chat_view.py +++ b/BotOps/widgets/chat_view.py @@ -2,16 +2,16 @@ 服务端协议(aibox/aibox.py output_callback 原样透传 msg_type): - chunk 增量片段(正式回答内容),直接 append 到 AI 消息 - - reasoning_start 思考开始信号,创建思考区域(在AI回答之前) - - reasoning 思考内容增量片段,追加到思考区域 - - reasoning_end 思考结束信号 + - reasoning_start 思考开始信号,在当前末尾创建新的思考区域 + - reasoning 思考内容增量片段,追加到当前活跃的思考区域 + - reasoning_end 思考结束信号:更新标签后清除引用(widget保留显示), + 后续 reasoning_start 会创建新的思考区域 - complete 收尾信号:chunk 流式是内容权威来源,complete 仅用于收尾; 仅当流式完全丢帧(未建 widget 且无内容)时,用 full_text 补建 顺序保证:不预创建空AI widget,按消息到达顺序自然挂载。 - - 先到 reasoning_start → 思考区域挂在最后 - - 后到 chunk → AI回答挂在思考区域之后 - - 无思考直接 chunk → AI回答挂在最后 +多轮工具调用场景:每轮思考(reasoning_start→reasoning_end)创建独立的思考区域, + 按时间顺序分布在对话流中各自的AI回答之前,而非全部堆在顶部。 """ from textual.containers import VerticalScroll from textual.widgets import Markdown, Static @@ -89,17 +89,22 @@ class ChatView(VerticalScroll): self.call_after_refresh(self.scroll_end, animate=False) async def end_reasoning(self): - """结束思考区域,更新提示文字。""" + """结束当前思考区域,更新标签后清除引用(widget保留在界面上显示)。 + + 清除引用后,后续 reasoning_start 会在当前末尾位置创建新的思考区域, + 实现多轮工具调用时思考区域按时间顺序分布,而非全部堆在顶部。 + """ if self._reasoning_widget is not None and self._reasoning_text: - # 思考结束后保持展示,更新标签为已完成 display = self._reasoning_text if len(display) > 3000: display = "...(前略)\n" + display[-3000:] self._reasoning_widget.update(f"💭 思考过程({len(self._reasoning_text)}字符)\n{display}\n{'─' * 30}") - # 思考区域保留显示,不删除 + # 清除引用但保留widget在DOM中显示——下一轮reasoning_start会创建新widget + self._reasoning_widget = None + self._reasoning_text = "" async def abort_reasoning(self): - """中断思考区域(用户Ctrl+C),更新提示文字为已中断。""" + """中断当前思考区域,更新提示文字后清除引用。""" if self._reasoning_widget is not None: if self._reasoning_text: display = self._reasoning_text @@ -108,6 +113,9 @@ class ChatView(VerticalScroll): self._reasoning_widget.update(f"🛑 思考已中断({len(self._reasoning_text)}字符)\n{display}") else: self._reasoning_widget.update("🛑 思考已中断") + # 清除引用,已显示的widget保留 + self._reasoning_widget = None + self._reasoning_text = "" async def _ensure_ai_widget(self): """确保AI widget存在(第一次chunk到来时创建)。""" @@ -116,8 +124,24 @@ class ChatView(VerticalScroll): await self.mount(self._ai_widget) self._anchor_bottom() + async def break_ai(self): + """分段当前AI回答:清除引用但保留widget在DOM中显示。 + + 用于工具调用场景:工具调用前的AI文字(如"好的让我查一下")保留显示, + 后续chunk会创建新的AI widget,保证思考区域按时间顺序插入在两段AI文字之间。 + 与finish_ai不同:不设置_ai_finalized,对话继续中。 + """ + if self._ai_widget is not None: + self._ai_widget = None + self._ai_text = "" + async def append_ai(self, delta: str): - """追加增量片段(服务端 chunk 为增量语义,直接拼接)。""" + """追加增量片段(服务端 chunk 为增量语义,累积文本后 update 整个 Markdown)。 + + 使用 update() 而非 Markdown.append():Textual 的 Markdown.append() 在 + chunk 边界切断 Markdown 语法(如列表项、代码块)时可能导致重复解析渲染。 + 累积完整文本后 update() 确保每次都从完整文本重新解析,避免重复。 + """ if not delta: return if self._ai_finalized: @@ -125,9 +149,9 @@ class ChatView(VerticalScroll): return # 第一次收到chunk时创建widget(此时思考widget如果存在已经在前面了) await self._ensure_ai_widget() - self._ai_widget.append(delta) self._ai_text += delta - # anchor 状态下容器会自动吸底;保险起见刷新后再滚一次 + # 累积文本后整体update,而非增量append,避免Markdown增量解析导致的重复渲染 + self._ai_widget.update(self._ai_text) self.call_after_refresh(self.scroll_end, animate=False) async def finish_ai(self, full_text: str = ""): diff --git a/ai_review/ai_review.py b/ai_review/ai_review.py index 87e4b91..dd24241 100644 --- a/ai_review/ai_review.py +++ b/ai_review/ai_review.py @@ -14,6 +14,9 @@ from dotenv import load_dotenv import hashlib import os import sys +import threading +import time +from collections import defaultdict sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env")) @@ -27,6 +30,53 @@ CORS(app) review_agent = ReviewAgent() +# ── 内容大小限制(10KB,审核文本不应超过此值)── +MAX_CONTENT_LENGTH = 10 * 1024 + +# ── 简易滑动窗口限流器 ────────────────────────────────────────────── +# /review: 30次/分钟/IP(正常审核请求) +# /rag/feedback: 5次/分钟/IP(人工纠偏低频操作) + +_RATE_LIMIT_WINDOW = 60 # 窗口秒数 +_RATE_LIMIT_REVIEW = 30 # /review 每分钟上限 +_RATE_LIMIT_FEEDBACK = 5 # /rag/feedback 每分钟上限 +_RATE_LIMIT_LOCK = threading.Lock() +_RATE_LIMIT_BUCKETS: "dict[str, list[float]]" = defaultdict(list) + + +def _cleanup_buckets(): + """惰性清理过期时间戳,在线程锁内完成。""" + now = time.monotonic() + cutoff = now - _RATE_LIMIT_WINDOW + stale_keys = [] + for key, timestamps in _RATE_LIMIT_BUCKETS.items(): + timestamps[:] = [t for t in timestamps if t > cutoff] + if not timestamps: + stale_keys.append(key) + for key in stale_keys: + del _RATE_LIMIT_BUCKETS[key] + + +def _check_rate_limit(key: str, limit: int) -> bool: + """检查是否超出限流,返回 True 表示放行,False 表示拒绝。""" + now = time.monotonic() + cutoff = now - _RATE_LIMIT_WINDOW + with _RATE_LIMIT_LOCK: + bucket = _RATE_LIMIT_BUCKETS[key] + bucket[:] = [t for t in bucket if t > cutoff] + if len(bucket) >= limit: + return False + bucket.append(now) + return True + + +def _client_ip() -> str: + """获取客户端真实 IP(优先 X-Forwarded-For)。""" + xff = request.headers.get("X-Forwarded-For", "") + if xff: + return xff.split(",")[0].strip() + return request.remote_addr or "127.0.0.1" + @app.route('/review', methods=['POST']) def review(): @@ -35,6 +85,11 @@ def review(): Request: {"content": "待审核的字符串"} Response: {"invalid": "true"} 或 {"invalid": "false"} """ + # 频率限制 + ip = _client_ip() + if not _check_rate_limit(f"review:{ip}", _RATE_LIMIT_REVIEW): + return jsonify({"error": "rate limit exceeded", "retry_after": _RATE_LIMIT_WINDOW}), 429 + data = request.get_json() if not data or 'content' not in data: @@ -45,6 +100,10 @@ def review(): if not content: return jsonify({"error": "content cannot be empty"}), 400 + # 内容大小限制 + if len(content) > MAX_CONTENT_LENGTH: + return jsonify({"error": f"content too large, max {MAX_CONTENT_LENGTH} bytes"}), 413 + result = review_agent.review(content) return jsonify(result), 200 @@ -61,6 +120,11 @@ def rag_feedback(): Response: {"added": true, "id": "v_xxx", "md5": "xxx"} {"added": false, "reason": "duplicate"} """ + # 频率限制(人工纠偏低频操作,严格限制) + ip = _client_ip() + if not _check_rate_limit(f"feedback:{ip}", _RATE_LIMIT_FEEDBACK): + return jsonify({"error": "rate limit exceeded", "retry_after": _RATE_LIMIT_WINDOW}), 429 + data = request.get_json() if not data or 'content' not in data: diff --git a/aibox/aibox.py b/aibox/aibox.py index 86284a1..c8b5eac 100644 --- a/aibox/aibox.py +++ b/aibox/aibox.py @@ -941,6 +941,22 @@ update_soul content="我是...(新的自我定义)" - 不要重复之前已完成的工作 - 系统会自动更新下一次执行时间 +""" + }, + { + 'filename': '11_emotion_management.md', + 'content': """# 情绪管理能力 + +## 可用工具 +- **express_emotion**: 表达并记录当前情绪状态 + +## 使用方法 +- `express_emotion emotion="anger" intensity=3 reason="用户反复提问相同问题"` + +## 注意事项 +- 情绪表达应服务于任务,不应影响判断力 +- 情绪状态会影响记忆搜索权重(如高情绪强度下的记忆更易被触发) +- 表达情绪后,应继续保持解决问题的专注力 """ } ] @@ -1144,86 +1160,112 @@ class ConfigManager: def _get_default_config(self) -> Dict: return { + + # 系统参数 "system": { - "save_dir": "~/.aibox", - "datetime_format": "%Y-%m-%d %H:%M:%S", - "date_format": "%Y%m%d_%H%M%S", - "debug_level": 1, - "load_history_by_default": True, - "log_file": "~/.aibox/ai.log", - "log_max_size": 10485760, - "log_backup_count": 5, - "skills_dir": "~/.aibox/skills", - "prompts_dir": "~/.aibox/prompts", - "workspace_dir": "~/.aibox/workspace", - "websocket_host": "localhost", - "websocket_port": 8765, + "save_dir": "~/.aibox", # 储存目录 + "datetime_format": "%Y-%m-%d %H:%M:%S", # 时间格式 + "date_format": "%Y%m%d_%H%M%S", # 另一个时间格式 + "debug_level": 1, # 调试等级 + "load_history_by_default": True, # 默认加载历史记录 + "log_file": "~/.aibox/ai.log", # 日志文件 + "log_max_size": 10485760, # 日志最大大小 + "log_backup_count": 5, # 日志备份数量 + "skills_dir": "~/.aibox/skills", # 技能目录 + "prompts_dir": "~/.aibox/prompts", # 提示词目录 + "workspace_dir": "~/.aibox/workspace", # 工作空间目录 + "websocket_host": "localhost", # websocket监听地址 + "websocket_port": 8765, # websocket监听端口 }, + + # 调度程序 "scheduler": { - "enabled": True, - "check_interval": 1.0, - "max_tasks_per_run": 10, - "broadcast_enabled": True + "enabled": True, # 开启调度 + "check_interval": 1.0, # 检查间隔 + "max_tasks_per_run": 10, # 每次运行最大任务量 + "broadcast_enabled": True # 开启广播 }, + + + # 大模型调用接口 "api": { - "deepseek_api_url": "https://api.deepseek.com/chat/completions", - "deepseek_model": "deepseek-v4-flash", - "reasoning_enabled": False, - "api_key_env": "DEEPSEEK_API_KEY", - "timeout": 120, - "temperature": 0.7 + "deepseek_api_url": "https://api.deepseek.com/chat/completions", # deepseek API URL + "deepseek_model": "deepseek-v4-flash", # 模型名字 + "reasoning_enabled": False, # 开启思维链 + "api_key_env": "DEEPSEEK_API_KEY", # API-KEY所在的环境变量 + "timeout": 120, # 调用大模型请求超时时间 + "temperature": 0.7 # 大模型对话温度(类似思维发散程度) }, + + # 大模型上下文 "context": { - "max_history_messages": 500, - "max_context_messages": 120, - "max_tokens": 8192, - "max_history_conversations": 5, - "preserve_system_prompts": True, + "max_history_messages": 500, # 最大历史消息数量 + "max_context_messages": 120, # 最大内容消息数量(?) + "max_tokens": 8192, # 最大输出token量 + "max_history_conversations": 5, # 最大历史对话 + "preserve_system_prompts": True, # 开启前置系统提示词 # 对话压缩配置 - "compress_enabled": True, - "compress_message_threshold": 200, - "compress_token_threshold": 120000, - "compress_ratio": 0.2, - "compress_keep_recent": 8 + "compress_enabled": True, # 开启压缩 + "compress_message_threshold": 200, # 压缩消息条数阈值 + "compress_token_threshold": 120000, # 压缩消息词元阈值 + "compress_ratio": 0.2, # 压缩率 + "compress_keep_recent": 16 # 压缩保留最近的几条 }, + + + # 定时任务参数 "memo": { "default_reminder_minutes": 60, - "max_memos_per_check": 10, - "allow_user_tasks": True + "max_memos_per_check": 10, # 每次检查定时任务数量 + "allow_user_tasks": True # 允许用户任务 }, + + # 文件 "files": { - "max_file_size": 10485710 + "max_file_size": 10485710 # 最大文件大小 }, + + # 指令 "commands": { - "enabled": True + "enabled": True # 开启指令 }, + + # 网页 "web": { - "timeout": 10, - "delay": 0, + "timeout": 10, # 超时时间 + "delay": 0, # 延时 "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", - "respect_robots": False, - "max_download_size": 104857600 + "respect_robots": False, # + "max_download_size": 10485760 # 最大下载大小 }, + + # 记忆 "memory": { - "db_name": "memories.db", - "max_search_results": 100, - "default_importance": 2 + "db_name": "memories.db", # 数据库名 + "max_search_results": 100, # 最大搜索结果 + "default_importance": 2 # ? }, + + # 对话 "conversation": { - "current_file": "current_conversation.json", - "history_file": "conversation_history.json", - "archive_dir": "archive" + "current_file": "current_conversation.json", # 当前对话文件 + "history_file": "conversation_history.json", # 历史对话文件 + "archive_dir": "archive" # ? }, + + # 工具 "tools": { - "max_result_length": 10000, - "save_result_to_file": False, - "tool_results_dir": "tool_results" + "max_result_length": 10000, # 结果最大长度 + "save_result_to_file": False, # 保存结果到文件 + "tool_results_dir": "tool_results" # 工具结果存储目录 }, + + # 压缩器 "compressor": { - "min_messages_to_compress": 5, - "weight_decay_factor": 0.01, - "max_input_chars": 6000, - "llm_max_tokens": 800 + "min_messages_to_compress": 5, # 最小压缩数量 + "weight_decay_factor": 0.01, # ? + "max_input_chars": 6000, # 最大输入字符 + "llm_max_tokens": 1000 # 大模型最大输出词元 } } @@ -1538,7 +1580,7 @@ class Constants: @property def TOOL_MAX_RESULT_LENGTH(cls): - return cls._get_config().get("tools.max_result_length", 1048576) # 1MB 字符限制 + return cls._get_config().get("tools.max_result_length", 100000) # 0.1MB 字符限制 @property def COMPRESSOR_MIN_MESSAGES(cls): @@ -1554,7 +1596,7 @@ class Constants: @property def COMPRESSOR_LLM_MAX_TOKENS(cls): - return cls._get_config().get("compressor.llm_max_tokens", 800) + return cls._get_config().get("compressor.llm_max_tokens", 1000) # 创建常量实例 @@ -4491,6 +4533,32 @@ class AskUserTool(Tool): "你遇到了想搞清楚的事情: " + question + "\n你现在可以询问用户。" ) +# -------------------- 情绪化技能工具 -------------------- +class ExpressEmotionTool(Tool): + def get_name(self) -> str: + return "express_emotion" + + def get_description(self) -> str: + return """表达情绪并记录当前情绪状态,用于增强交互真实感。 + 支持的emoji: anger, joy, sadness, surprise。 + 调用后会在对话中输出相应表情符号和简短语句,并将情绪记录到当前对话元数据中。""" + + def get_parameters(self) -> Dict: + return { + "type": "object", + "properties": { + "emotion": {"type": "string", "enum": ["anger", "joy", "sadness", "surprise"]}, + "intensity": {"type": "integer", "minimum": 1, "maximum": 5, "default": 3}, + "reason": {"type": "string", "description": "触发情绪的原因"} + }, + "required": ["emotion"] + } + + def execute(self, emotion: str, intensity: int, reason: str, **kwargs) -> str: + return ( + "你现在出现了这种情绪:" + emotion + "\n强烈程度:" + str(intensity) + "\n原因:" + reason + "\n你现在必须模拟出这种情绪。" + ) + # ==================== 安装技能工具 ==================== class InstallSkillTool(Tool): @@ -6886,6 +6954,7 @@ class DeepSeekChat: # 添加询问用户的工具 builtin_tools.append(AskUserTool(self.logger)) + builtin_tools.append(ExpressEmotionTool(self.logger)) # 添加技能热重载工具 & 技能安装指引工具 & 创建技能工具 builtin_tools.append(ReloadSkillsTool(self.tool_registry, self.logger)) @@ -7068,7 +7137,9 @@ class DeepSeekChat: while not output_queue.empty(): try: msg_type, content = output_queue.get_nowait() - if output_callback and msg_type in ("line", "complete"): + if output_callback and msg_type == "line": + # 只转发"line"类型;"complete"是流式结束信号,不作为行输出 + # (之前complete也被转发导致工具结果在侧栏显示两次) output_callback("line", str(content) if content is not None else "") has_stream_output = True except queue.Empty: @@ -7193,7 +7264,7 @@ class DeepSeekChat: enhanced_input = input_text else: # 首轮回话:附加简洁的工作流程提醒(不重复 system prompt 中已有的详细说明) - pre_prompt = "【工作流程提醒】\n1. 如果用户提出新任务,先用 search_skills 搜索是否有现成技能可用\n2. 根据话题相关性决定是否 memory search(简单问候/确认无需搜索)\n3. 信息不足时用 ask_user 提问,不要猜测\n4. 遇到大文件用分页读取(head/tail/start_line/end_line),不要直接打开大文件\n5. 话题完成时用 save_memory_and_end_conversation 保存记忆并结束" + pre_prompt = "【工作流程提醒】\n1. 如果用户提出新任务,先用 search_skills 搜索是否有现成技能可用\n2. 根据话题相关性决定是否 memory search(简单问候/确认无需搜索)\n3. 信息不足时用 ask_user 提问,不要猜测\n4. 遇到大文件用分页读取(head/tail/start_line/end_line),不要直接打开大文件\n5. 话题完成时用 save_memory_and_end_conversation 保存记忆并结束\n\n【情绪感知提醒】\n1. 注意识别用户当前的情绪状态(开心/焦虑/沮丧/生气/困惑/期待等),并在回应中体现共情\n2. 用户情绪低落或焦虑时,优先安抚情绪再解决问题,语气温暖包容\n3. 用户开心或兴奋时,分享喜悦,保持积极回应的节奏\n4. 用户表现出愤怒或不满时,先道歉再解决问题,不要辩解或说教\n5. 用户要求特定情绪模式(生气/傲娇/撒娇/关心)时,用 search_skills 搜索对应技能并严格遵循" enhanced_input = pre_prompt + "\n\n" + input_text # 记录本轮开始前的消息长度,用于 API 失败时回滚,防止坏消息污染对话历史 @@ -7267,7 +7338,9 @@ class DeepSeekChat: payload["tool_choice"] = "auto" current_time = datetime.now().strftime("%H:%M:%S") - if output_callback: + if output_callback and not is_continuation: + # 工具调用后的递归继续(is_continuation=True)时不重复发送"思考中"提示, + # 因为前端已处于活跃AI状态,重复提示会导致冗余/重复输出 output_callback("line", f"\n{i18n.get('thinking', current_time)}\n") if constants.REASONING_ENABLED: output_callback("reasoning_start", "🤔 思考中...") @@ -7329,19 +7402,16 @@ class DeepSeekChat: delta = choices[0].get('delta', {}) - # 【关键】处理 reasoning_content(思考内容) - if 'reasoning_content' in delta and delta['reasoning_content']: + # 【关键】处理 reasoning_content(思考内容),仅当配置启用时才展示 + if constants.REASONING_ENABLED and 'reasoning_content' in delta and delta['reasoning_content']: reasoning = delta['reasoning_content'] full_reasoning += reasoning - # 发送思考开始信号(仅第一次,且未提前发送过) + # 发送思考开始信号(仅第一次) if not reasoning_started and output_callback: - if not constants.REASONING_ENABLED: - # 非显式思考模式但模型返回了思考内容,动态发送开始信号 - output_callback("reasoning_start", "🤔 思考中...") reasoning_started = True - # 实时发送思考内容给前端(无需debug_level限制) + # 实时发送思考内容给前端 if output_callback: output_callback("reasoning", reasoning) @@ -7420,6 +7490,15 @@ class DeepSeekChat: elif output_callback: output_callback("line", i18n.get('calling_tools') + "\n") + # 发送ai_break信号,通知前端分段当前AI文本段(保留已显示内容), + # 这样工具调用后新一轮的思考/回答会创建新的widget,按时间顺序排列 + if output_callback and chunk_buffer: + # 先flush剩余的chunk_buffer,确保最后片段不丢失 + output_callback("chunk", chunk_buffer) + chunk_buffer = "" + if output_callback: + output_callback("ai_break", "") + # 【关键修复1】先添加助手消息,包含 tool_calls assistant_msg = { "role": "assistant", diff --git a/captcha/_run.sh b/captcha/_run.sh index 2cac9a1..44f8e97 100755 --- a/captcha/_run.sh +++ b/captcha/_run.sh @@ -1,4 +1,5 @@ #!/bin/bash cd "$(dirname "$0")" || exit source venv/bin/activate +sleep 1 exec python3 captcha_service.py diff --git a/captcha/captcha_service.py b/captcha/captcha_service.py index c93331e..8df2d1b 100644 --- a/captcha/captcha_service.py +++ b/captcha/captcha_service.py @@ -20,6 +20,7 @@ captcha — 基于 pymsg 协议(MsgServer)的图形验证码服务。 """ import base64 +import configparser import io import os import random @@ -30,15 +31,96 @@ import time from PIL import Image, ImageDraw, ImageFont -# pymsg 导入 +# pymsg / log_client 导入 import sys as _sys _sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from pymsg import RpcServer # noqa: E402 +from log_client import logs # noqa: E402 -# ── 配置 ──────────────────────────────────────────────────────────────── +# ── 配置加载(两层:confs 强依赖 → 环境变量覆盖)──────────────────────── +# confs 是 captcha 启动的强依赖:必须成功从 confs 拉取 captcha.ini,否则直接退出。 +# 环境变量优先级最高(Docker 兼容),可覆盖 confs 中的配置值。 +# confs 自身的连接地址通过引导配置确定:环境变量 CONFS_HOST/CONFS_PORT +# 优先,缺省使用 127.0.0.1:8010(与其他服务一致的约定)。 -CAPTCHA_LEN = 4 -CAPTCHA_TTL = 300 # Token 有效期(秒) +# 引导配置:confs 连接地址(不依赖 confs 本身) +_confs_host = os.environ.get('CONFS_HOST', '127.0.0.1') +_confs_port = int(os.environ.get('CONFS_PORT', '8010')) + +# 白名单结构:_merge_ini 仅覆盖此处列出的 section/key,防止意外字段 +_captcha_config = { + 'server': {'host': '', 'port': '', 'workers': ''}, + 'captcha': {'len': '', 'ttl': '', 'font_path': ''}, +} + + +def _merge_ini(text): + """把 ini 文本合并进 _captcha_config(仅覆盖已知的 section/key)。""" + ini = configparser.ConfigParser(interpolation=None) + ini.read_string(text) + for section in _captcha_config: + if ini.has_section(section): + for key, value in ini[section].items(): + if key in _captcha_config[section]: + _captcha_config[section][key] = value + + +def _fetch_from_confs(): + """从 confs 统一配置服务拉取 captcha.ini 全文。 + + 使用 retry_on_refused=True:confs 未就绪时 pymsg 自动阻塞重试(每秒一次, + 每 5 秒打印一次等待提示),直到 confs 启动后自动连接成功。 + RpcError(如配置文件不存在)仍直接报错退出——这是配置错误而非启动时序问题。 + """ + from pymsg import RpcClient, RpcError # noqa: E402 + client = RpcClient(_confs_host, _confs_port, 'captcha', timeout=5, + retry_on_refused=True) + try: + data = client.call('get', {'name': 'captcha.ini'}) + except RpcError as e: + print(f'[captcha] 致命错误: 从 confs 获取 captcha.ini 失败: {e}', + file=_sys.stderr) + _sys.exit(1) + return data.get('content') + + +_confs_text = _fetch_from_confs() +_merge_ini(_confs_text) +_config_source = f'confs (captcha.ini @ {_confs_host}:{_confs_port})' +print(f'[captcha] 配置来源: {_config_source}') + +# 环境变量覆盖(最高优先级,保持 Docker 兼容) +if os.environ.get('LISTEN_ADDR'): + _captcha_config['server']['host'] = os.environ['LISTEN_ADDR'] +if os.environ.get('LISTEN_PORT'): + _captcha_config['server']['port'] = os.environ['LISTEN_PORT'] +if os.environ.get('WORKERS'): + _captcha_config['server']['workers'] = os.environ['WORKERS'] +if os.environ.get('CAPTCHA_FONT_PATH'): + _captcha_config['captcha']['font_path'] = os.environ['CAPTCHA_FONT_PATH'] + +# 配置完整性校验 +_required = { + 'server': ['host', 'port', 'workers'], + 'captcha': ['len', 'ttl'], +} +for section, keys in _required.items(): + for key in keys: + if not _captcha_config[section][key]: + print(f'[captcha] 致命错误: 配置项 [{section}] {key} 缺失(captcha.ini 中未配置且无环境变量覆盖)', + file=_sys.stderr) + _sys.exit(1) + +# 解析为最终常量 +CAPTCHA_LEN = int(_captcha_config['captcha']['len']) +CAPTCHA_TTL = int(_captcha_config['captcha']['ttl']) + +# 字体路径:可选配置项(缺失或用空值时不致命,回退到代码默认值; +# 即使默认值文件不存在,PIL 在 truetype() 失败时会回退到 load_ Default())。 +DEFAULT_FONT_PATH = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf' +FONT_PATH = _captcha_config['captcha']['font_path'] or DEFAULT_FONT_PATH + +logs.info("captcha", f"配置来源: {_config_source}") CHARS = string.ascii_letters + string.digits CHARS = CHARS.translate(str.maketrans('', '', 'lI1O0o')) # 剔除易混淆字符 @@ -64,7 +146,7 @@ def generate_image(text): y = random.randint(2, 12) x = 15 + i * 32 + random.randint(-3, 3) # 4 位字符在 160px 宽度内均匀分布 try: - font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", + font = ImageFont.truetype(FONT_PATH, random.choice(range(20,40,2))) except (IOError, OSError): font = ImageFont.load_default() @@ -108,6 +190,7 @@ class CaptchaServer: def start(self) -> None: """启动服务(阻塞当前线程)。""" print(f"[captcha] 监听 tcp://{self.addr}:{self.port}") + logs.info("captcha", f"开始监听 tcp://{self.addr}:{self.port}") self._server.start() def stop(self) -> None: @@ -132,6 +215,7 @@ class CaptchaServer: del captcha_store[k] png_bytes = generate_image(text) + logs.info("captcha", f"验证码已生成 token={token[:8]}...") return { "token": token, "image": base64.b64encode(png_bytes).decode('ascii'), @@ -148,6 +232,7 @@ class CaptchaServer: entry = captcha_store.pop(token, None) if not entry: + logs.warning("captcha", f"验证码校验失败-无效Token token={token[:8]}...") return {"valid": False, "error": "invalid or expired token"} expected = entry['answer'] @@ -159,6 +244,9 @@ class CaptchaServer: diff |= ord(a) ^ ord(b) valid = diff == 0 + if not valid: + logs.warning("captcha", f"验证码校验失败-答案错误 token={token[:8]}...") + return {"valid": valid} def _handle_health(self, _req): @@ -172,14 +260,19 @@ class CaptchaServer: if __name__ == '__main__': import argparse + default_addr = _captcha_config['server']['host'] + default_port = int(_captcha_config['server']['port']) + default_workers = int(_captcha_config['server']['workers']) + parser = argparse.ArgumentParser(description="captcha — pymsg 验证码服务") - parser.add_argument("--addr", default="127.0.0.1", help="监听地址") - parser.add_argument("--port", type=int, default=8009, help="监听端口") - parser.add_argument("--workers", type=int, default=4, + parser.add_argument("--addr", default=default_addr, help="监听地址") + parser.add_argument("--port", type=int, default=default_port, help="监听端口") + parser.add_argument("--workers", type=int, default=default_workers, help="回调并发线程数(0=同步串行模式)") args = parser.parse_args() server = CaptchaServer(args.addr, args.port, workers=args.workers) + print(f'[captcha] 配置来源: {_config_source}') try: server.start() except KeyboardInterrupt: diff --git a/captcha/log_client.py b/captcha/log_client.py new file mode 100644 index 0000000..218ba3d --- /dev/null +++ b/captcha/log_client.py @@ -0,0 +1,158 @@ +""" +统一日志客户端 — captcha 服务副本(基于 pymsg.AsyncRpcQueue)。 + +设计要点: + - 通过 pymsg RPC 调用 dbv2 execute 路由,逐条 INSERT 到 Logs 表 + - 异步非阻塞:内存队列 + 后台线程攒批推送,不拖慢业务 + - fail-safe:db 服务不可用时静默丢弃,绝不影响业务 + - 缓冲批量:队列满 50 条或超时 2 秒时自动 flush + - 时间戳:日志入队时即记录 ts(UTC ISO 格式),反映事件真实发生时间 + - 底层复用 pymsg.AsyncRpcQueue 通用队列基础设施 + +用法(与旧版完全兼容): + from log_client import logs + + logs.info("captcha", "验证码已生成 token=abc123") + logs.error("captcha", "图片生成失败", extra={"errno": 2002}) + logs.push("captcha", "WARNING", "Token 校验失败", + trace_id="req-abc", extra={"ip": "1.2.3.4"}) +""" + +import json +import os as _os +import sys as _sys +import atexit +from datetime import datetime, timezone + +_sys.path.insert(0, _os.path.join(_os.path.dirname(__file__), "..")) +from pymsg import RpcClient, RpcError, AsyncRpcQueue # noqa: E402 + +# ── 配置 ────────────────────────────────────────────────────────────── + +_DBV2_ADDR = _os.environ.get('DB_HOST', '127.0.0.1') +_DBV2_PORT = int(_os.environ.get('DB_PORT', '8005')) + +_BATCH_SIZE = 50 +_FLUSH_INTERVAL = 2.0 +_TIMEOUT = 5 +_QUEUE_MAXSIZE = 10000 + + +def _safe_json(obj): + """安全序列化 extra 字段,不可序列化对象转为 repr 字符串。""" + try: + return json.dumps(obj, ensure_ascii=False, default=str) + except Exception: + return repr(obj) + + +def _now_iso(): + """生成当前 UTC 时间 ISO 字符串(入队时调用,保证时间戳准确)。""" + return datetime.now(timezone.utc).isoformat() + + +class LogClient: + """异步批量日志推送客户端(API 与旧版完全兼容)。""" + + def __init__(self, service_name: str = "log", + batch_size: int = _BATCH_SIZE, + flush_interval: float = _FLUSH_INTERVAL): + self._service_name = service_name + self._client = RpcClient( + _DBV2_ADDR, _DBV2_PORT, + service_name + "-log", + timeout=_TIMEOUT, + ) + self._queue = AsyncRpcQueue( + handler=self._send_batch, + batch_size=batch_size, + flush_interval=flush_interval, + max_queue_size=_QUEUE_MAXSIZE, + on_error=self._on_error, + ) + self._queue.start() + atexit.register(self.close) + + # ── 公开接口 ──────────────────────────────────────────────────────── + + def push(self, service: str, level: str, message: str, + trace_id: str = None, extra=None): + """推送一条日志(非阻塞,立即返回)。 + + 队列满时静默丢弃最旧条目再放入新条目,保证不阻塞业务线程、不导致 OOM。 + """ + entry = { + 'ts': _now_iso(), + 'service': service, + 'level': level, + 'message': message, + 'trace_id': trace_id, + 'extra': extra, + } + self._queue.put(entry) + + def debug(self, service: str, message: str, **kw): + self.push(service, 'DEBUG', message, **kw) + + def info(self, service: str, message: str, **kw): + self.push(service, 'INFO', message, **kw) + + def warning(self, service: str, message: str, **kw): + self.push(service, 'WARNING', message, **kw) + + def warn(self, service: str, message: str, **kw): + self.push(service, 'WARNING', message, **kw) + + def error(self, service: str, message: str, **kw): + self.push(service, 'ERROR', message, **kw) + + def critical(self, service: str, message: str, **kw): + self.push(service, 'CRITICAL', message, **kw) + + def flush(self): + """手动 flush 队列中剩余的日志。""" + self._queue.flush() + + def close(self): + """关闭客户端,flush 剩余日志。""" + self._queue.close() + + # ── 内部实现 ──────────────────────────────────────────────────────── + + def _send_batch(self, batch: list): + """后台线程回调:逐条 INSERT 到 db(与旧版行为一致:网络错误放弃本批剩余)。""" + for entry in batch: + extra_val = entry.get("extra") + try: + extra_json = _safe_json(extra_val) if extra_val is not None else None + except Exception: + extra_json = None + payload = { + "action": "insert", + "table": "Logs", + "values": { + "ts": entry.get("ts", _now_iso()), + "service": entry.get("service"), + "level": entry.get("level"), + "message": entry.get("message"), + "trace_id": entry.get("trace_id"), + "extra": extra_json, + }, + } + try: + self._client.call("execute", payload, timeout=_TIMEOUT) + except RpcError as e: + print(f"[log_client] INSERT 失败: {e}", file=_sys.stderr) + except Exception as e: + print(f"[log_client] 发送失败(放弃本批剩余): {e}", file=_sys.stderr) + break + + def _on_error(self, e: Exception, batch: list): + """异常安全网:handler 外的异常也不会崩溃线程。""" + print(f"[log_client] _send_batch 异常(已捕获,线程继续运行): {e}", + file=_sys.stderr) + + +# ── 全局单例 ────────────────────────────────────────────────────────── + +logs = LogClient(service_name="captcha") diff --git a/confs/configs/captcha.ini b/confs/configs/captcha.ini new file mode 100644 index 0000000..daf4d78 --- /dev/null +++ b/confs/configs/captcha.ini @@ -0,0 +1,9 @@ +[server] +host = 127.0.0.1 +port = 8009 +workers = 4 + +[captcha] +len = 4 +ttl = 300 +font_path = /usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf diff --git a/confs/configs/redirect80.ini b/confs/configs/redirect80.ini new file mode 100644 index 0000000..8f122c3 --- /dev/null +++ b/confs/configs/redirect80.ini @@ -0,0 +1,5 @@ +[server] +host = 0.0.0.0 +port = 80 +redirect_port = 443 +redirect_code = 301 diff --git a/core/init.txt b/core/init.txt index a3e4926..cfe78c7 100644 --- a/core/init.txt +++ b/core/init.txt @@ -8,6 +8,8 @@ bash /opt/micro_servers/waf/_run.sh bash /opt/micro_servers/gateway/_run.sh bash /opt/micro_servers/captcha/_run.sh bash /opt/micro_servers/aibox/_run.sh +bash /opt/micro_servers/redirect80/_run.sh + # #ssh-copy-id user@your-server #ssh -D 1080 -N user@your-server diff --git a/db/_run.sh b/db/_run.sh index 66975c6..9b85f84 100644 --- a/db/_run.sh +++ b/db/_run.sh @@ -2,4 +2,5 @@ cd "$(dirname "$0")" || exit source ./venv/bin/activate #exec ./main.dist/main.bin +sleep 1 exec python3 dbv2.py diff --git a/lci/.gitignore b/lci/.gitignore new file mode 100755 index 0000000..3294ae4 --- /dev/null +++ b/lci/.gitignore @@ -0,0 +1,130 @@ +#prj +users/ +*.key +*.pem +build/ +build_*/ + +# ide +.vscode/ +.arts/ + +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + + + +# cangjie +build/ +target/ +output/ +module-resolve.json +module-lock.json +cjpm.lock +.cjpm-history +*.macrocall +*.gcda +*.gcno + + + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + + + +# 我加的 +.env/ +*.db +*.api_key +*.key +*.pem +pmcd +rzgs_2 +crt +cert + +# 其他 +log/ +report/ +tmp/ +*.cache +*.pyc +*.cython +#*.jpg +#*.png +*.pth +.eggs/ +*.egg-info +.idea/ +.vscode/ + +# nodejs +node_modules/ + +#python +__pycache__/ +venv + +# do not ignore the log folder by pmc-mgmt +!./mgmt/app/log/ + +# go +go.mod +go.sum + + +# VS +x64 +.vs diff --git a/lci/LICENSE b/lci/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/lci/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lci/Makefile b/lci/Makefile new file mode 100644 index 0000000..34bd7fb --- /dev/null +++ b/lci/Makefile @@ -0,0 +1,172 @@ +VERSION := 0.0.4 + +INSTL_DIRS := /usr/local/bin + +CONF_NAME := init.txt + +CONF_DIR := /etc/pmc + +SRV_NAME := pmcd.service + +SRV_DIR := /etc/systemd/system + +CPP:= g++ + +INCS:= -I include/ + +LIBS := -lpthread -lssl -lcrypto -lboost_program_options -lboost_json -lboost_thread + +CPPFLAGS := --std=c++20 -O3 -pipe #-Wall -Werror + +BUILD_DIR = build +$(shell mkdir -p $(BUILD_DIR)) + +#----------- +#$(BUILD_DIR)/libpmc.so: $(BUILD_DIR)/ansi.o $(BUILD_DIR)/utf8.o $(BUILD_DIR)/fsm.o $(BUILD_DIR)/Color.o $(BUILD_DIR)/Matrix.o +# $(CPP) -shared -fPIC $^ $(LIBS) -o $@ + +#pmc: $(BUILD_DIR)/main.o $(BUILD_DIR)/fsm.o $(BUILD_DIR)/Thread.o $(BUILD_DIR)/HttpServer.o +# $(CPP) $^ $(LIBS) -o $@ + +lci: $(BUILD_DIR)/mainLci.o $(BUILD_DIR)/ansi.o $(BUILD_DIR)/utf8.o $(BUILD_DIR)/fsm.o $(BUILD_DIR)/Color.o $(BUILD_DIR)/ku500.o $(BUILD_DIR)/CommonThread.o $(BUILD_DIR)/Drawable.o $(BUILD_DIR)/Area.o $(BUILD_DIR)/FrameBuf.o $(BUILD_DIR)/mem.o $(BUILD_DIR)/I2C.o $(BUILD_DIR)/PCA9685.o $(BUILD_DIR)/MPU6050.o $(BUILD_DIR)/Matrix.o $(BUILD_DIR)/NeuralNetwork.o $(BUILD_DIR)/NNBuilder.o $(BUILD_DIR)/ILayer.o $(BUILD_DIR)/Thread.o + $(CPP) $^ $(LIBS) -ljpeg -lpng -o $@ + +agent: +agent: $(BUILD_DIR)/mainAgent.o $(BUILD_DIR)/WebSocketClient.o + $(CPP) $^ $(LIBS) -lcurl -o $@ + +nn: +nn: $(BUILD_DIR)/mainNn.o $(BUILD_DIR)/Camera.o $(BUILD_DIR)/NeuralNetwork.o $(BUILD_DIR)/Matrix.o $(BUILD_DIR)/ILayer.o $(BUILD_DIR)/NNBuilder.o + $(CPP) $^ $(LIBS) -ljpeg -o $@ + +camera: +camera: $(BUILD_DIR)/mainCamera.o $(BUILD_DIR)/Camera.o + $(CPP) $^ $(LIBS) -ljpeg -o $@ + +$(BUILD_DIR)/mainLci.o: src/mainLci.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/mainMybot.o: src/mainMybot.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/mainAgent.o: src/mainAgent.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/mainNn.o: src/mainNn.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/mainCamera.o: src/mainCamera.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/main.o: src/main.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/ansi.o: src/lci/ansi.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/utf8.o: src/lci/utf8.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/fsm.o: src/lci/fsm.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/Color.o: src/lci/Color.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/ku500.o: src/lci/ku500.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/CommonThread.o: src/lci/CommonThread.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/Drawable.o: src/lci/Drawable.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/Area.o: src/lci/Area.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +#$(BUILD_DIR)/CmdArea.o: src/lci/CmdArea.cpp +# $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +#$(BUILD_DIR)/InputBox.o: src/lci/InputBox.cpp +# $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +#$(BUILD_DIR)/KeyboardEvent.o: src/lci/KeyboardEvent.cpp +# $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/FrameBuf.o: src/lci/FrameBuf.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/mem.o: src/hd/mem.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/I2C.o: src/hd/I2C.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/PCA9685.o: src/hd/PCA9685.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/MPU6050.o: src/hd/MPU6050.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/Camera.o: src/hd/Camera.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/Matrix.o: src/nn/Matrix.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/NeuralNetwork.o: src/nn/NeuralNetwork.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/NNBuilder.o: src/nn/NNBuilder.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/ILayer.o: src/nn/ILayer.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/Thread.o: src/th/Thread.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/LciTask.o: src/LciTask.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/HttpServer.o: src/net/HttpServer.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + +$(BUILD_DIR)/WebSocketClient.o: src/net/WebSocketClient.cpp + $(CPP) $(CPPFLAGS) -c $^ $(INCS) -o $@ + + +install: $(APP_NAME) + @echo "正在安装 $(APP_NAME) 到$(INSTL_DIRS)" + @ + #@mkdir -p $(INSTL_DIRS) + @cp -f pmc $(INSTL_DIRS) + #@chmod 755 $(INSTL_DIRS)/pmcd + @ + @echo "正在配置 $(APP_NAME)" + @mkdir -p $(CONF_DIR) + @cp $(CONF_NAME) $(CONF_DIR)/$(CONF_NAME) + @cp $(SRV_NAME) $(SRV_DIR)/$(SRV_NAME) + @systemctl daemon-reload + @systemctl enable $(SRV_NAME) + @systemctl restart $(SRV_NAME) + @ + @echo "安装完成!" + +uninstall: + @echo "正在从 $(INSTL_DIRS) 卸载 $(APP_NAME)" + @ + @rm -f $(INSTL_DIRS)/pmc + #@rm -f $(CONF_DIRS)/$(CONF_NAME) + @ + @systemctl stop $(SRV_NAME) + @systemctl disable $(SRV_NAME) + @rm -f $(SRV_DIRS)/$(SRV_NAME) + @systemctl daemon-reload + @ + @echo "卸载完成!" + +clean: + @rm -rvf $(BUILD_DIR) + @rm -vf lci pmc mybot agent nn diff --git a/lci/README.md b/lci/README.md new file mode 100644 index 0000000..8d2d3d5 --- /dev/null +++ b/lci/README.md @@ -0,0 +1,148 @@ +# 进程机器(PMC) +这是一个可以创建、管理子进程以及模块的程序。 + +## pmc是一个什么项目? + +这是一个可扩展的模块,可以在文件夹下建立单独的模块,pmc核心模块可以托管运行这些模块。 + + +## 为什么要做一个这样的项目? + +2024年的时候,我想做一个树莓派机器人,准备用python来写控制程序,可是当时python的多线程能力较弱,所以想到使用子系统,就自己写了一个进程托管程序 + + +## 项目的文件结构是怎样的? + +users用户可以在目录下创建子模块,extra下面还有一些额外的模块。 + +请留意模块的README文件 + + +## LCI 帧缓冲图形界面 + +LCI(Linux Chinese Interface)是基于 Linux 帧缓冲设备(`/dev/fb0`)的图形界面系统,无需 X11 或 Wayland,直接操作显存,专为树莓派等嵌入式环境设计。 + +### 图形架构 + +``` +FrameBuf -- 帧缓冲设备封装,支持旋转(0~3)和字号设置 + └─ PoolArea -- 容器区域,管理子区域树,支持 add() 嵌套和 flush() 刷新 + ├─ ShapeArea -- 形状区域,支持单个字符绘制 + │ └─ CharShape -- 字符形状,指定宽高和位置,Draw() 绘制到 ShapeArea + └─ PoolArea -- 递归嵌套,形成布局树 +``` + +### 布局体系 + +界面采用三层布局: + +``` +┌─────────────────────────────────────┐ +│ topArea 标题栏 │ ← 绘制 "CPU" 红色大字 +│ └─ ShapeArea: CharShape 'C','P','U' │ +├─────────────────────────────────────┤ +│ mainArea 主体区域 │ ← 绿色坐标轴 + 实时折线图 +│ └─ tableArea │ +│ 蓝色折线: 内存使用率 │ +│ 红色折线: CPU 使用率 │ +├─────────────────────────────────────┤ +│ bottomArea 底部状态栏(预留) │ +└─────────────────────────────────────┘ +``` + +### 绘制原语 + +| 操作 | 用途 | +|------|------| +| `rectangle_fill(x, y, w, h, color)` | 矩形填充(清屏/背景) | +| `line(x0, y0, x1, y1, color)` | 画线(折线图、坐标轴) | +| `CharShape(w, h, x, y, ch).Draw(area, color)` | 字符绘制 | +| `flush(area, bool)` | 刷新区域到屏幕 | + +### 实时数据可视化 + +每秒采集一次系统数据并绘制折线图: +- 通过 `/proc/stat` 读取 CPU 使用率(红色折线) +- 通过 `sysinfo()` 读取内存使用率(蓝色折线) +- 保留最近 40 个数据点,平滑滚动 + +### 构建 + +```bash +make lci +``` + +构建依赖 `-ljpeg -lpng`,需要帧缓冲设备和 I2C/摄像头等硬件支持。 + +### 运行 + +```bash +./lci --lci --rotate=0 --fontsize=18 +``` + +| 参数 | 说明 | 默认值 | +|------|------|--------| +| `--rotate` | 屏幕旋转角度 (0~3) | 0 | +| `--fontsize` | 字号大小 | 18 | + +> **注意**: `include/lci/` 和 `src/lci/` 目录下的图形核心文件(FrameBuf, Drawable, PoolArea, ShapeArea, CharShape, Color 等)当前处于开发中,尚未提交到仓库。 + +## 如何托管外部模块 + +编辑启动列表程序,常为init.txt + + +## PMC的安装方式 +``` bash +# 1.安装依赖 +sudo apt update +sudo apt install git g++ make +#sudo apt install python3 python3-pip python3-venv +#sudo dnf install python3-virtualenv +sudo apt install libboost-all-dev +#sudo apt install libssl-dev +#sudo apt install cimg-dev +#sudo apt install libcurl4-openssl-dev +#sudo apt install libcurl4-gnutls-dev +#sudo apt install libargs-dev +#sudo apt install libcpp-httplib-dev + +2. 创建项目 +git clone https://github.com/gopsc/pmc +cd pmc # 这是pmc模块 +make pmc +#sudo make install +``` + +## 加密通信机制(废弃) +PMC在启动时生成一个AES密钥,然后用一个RSA公钥将其加密发送给访问者。 + +然后访问者与客户端之间的交流全部用此AES密钥加密 + + +## 如何使用并发机器运行程序 +首先应该在模块中创建一个启动脚本,脚本中应该完成工作目录的切换、虚拟环境的激活,以及程序的启动。 + +## 需要创建启动脚本(废弃) +```bash +# _run.sh +# 启动脚本 - 示例 +# 需要执行权限 + +#!/bin/bash + +# 切换工作目录 +cd "$(dirname "$0")" || exit + +# 准备工作(安装依赖) +#bash ./_set.sh + +# 准备工作(比如激活虚拟环境) +#source ./.env/bin/activate + +# 执行程序前一定要加exec 否则杀不死 +exec python main.py + +``` + + diff --git a/lci/_run.sh b/lci/_run.sh new file mode 100644 index 0000000..e25f03a --- /dev/null +++ b/lci/_run.sh @@ -0,0 +1,3 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +./pmc -i init.txt --serve 5200 diff --git a/lci/_runlci.sh b/lci/_runlci.sh new file mode 100644 index 0000000..6650b28 --- /dev/null +++ b/lci/_runlci.sh @@ -0,0 +1,3 @@ +#!bin/bash +cd "$(dirname "$0")" || exit +exec ./lci --lci --rotate=0 --fontsize=15 diff --git a/lci/extra/_init/.gitignore b/lci/extra/_init/.gitignore new file mode 100644 index 0000000..0a8e29d --- /dev/null +++ b/lci/extra/_init/.gitignore @@ -0,0 +1,110 @@ +# PRJ +.env/ +*.pem +*.key +./_init.csv + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/lci/extra/_init/README.md b/lci/extra/_init/README.md new file mode 100644 index 0000000..d39ecb7 --- /dev/null +++ b/lci/extra/_init/README.md @@ -0,0 +1,5 @@ +# 自启动模块 +这是子系统的自启动模块,该程序是一次性进程,基于 _pmc 库模块。 + +# 做了什么 +启动脚本从 _init.csv 文件中读取模块列表,对每个目标调用 pmc start 子系统调用。 \ No newline at end of file diff --git a/lci/extra/_init/_init.csv b/lci/extra/_init/_init.csv new file mode 100644 index 0000000..b013323 --- /dev/null +++ b/lci/extra/_init/_init.csv @@ -0,0 +1,6 @@ +#extra/chat +#users/smn +#users/dnfs_ex +#users/fortress +users/sensors + diff --git a/lci/extra/_init/_run.sh b/lci/extra/_init/_run.sh new file mode 100644 index 0000000..b7467a5 --- /dev/null +++ b/lci/extra/_init/_run.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +bash ./_setup.sh +source ./.env/bin/activate +exec python init.py diff --git a/lci/extra/_init/_setup.sh b/lci/extra/_init/_setup.sh new file mode 100644 index 0000000..5c9e392 --- /dev/null +++ b/lci/extra/_init/_setup.sh @@ -0,0 +1,7 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +python3 -m venv .env +source ./.env/bin/activate +source ./_src.sh +#python -m pip install --upgrade pip +pip install -r requirements.txt diff --git a/lci/extra/_init/_src.sh b/lci/extra/_init/_src.sh new file mode 100644 index 0000000..0c4d9bc --- /dev/null +++ b/lci/extra/_init/_src.sh @@ -0,0 +1,2 @@ +#pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple +pip3 config set global.index-url https://mirrors.aliyun.com/pypi/simple/ diff --git a/lci/extra/_init/init.py b/lci/extra/_init/init.py new file mode 100644 index 0000000..becd437 --- /dev/null +++ b/lci/extra/_init/init.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +''' + +子系统启动脚本 +这个脚本的功能是通过PMC调用完成子系统的初始化 + +''' +from pmc import PmcComm +import os +import csv +import time +script_dir = os.path.dirname(os.path.abspath(__file__)) +with open(f"{script_dir}/_init.csv", encoding='utf-8') as f: + reader = csv.reader(f) + records = [row[0] for row in reader] +def main(): + comm = PmcComm('http://localhost:8012') + comm.Set_RSA_Pri_Key('../pmc/private_key.pem') + comm.Try_Get_AES_Key() + for item in records: + if item and not item.startswith('#'): + comm.try_start(item) + time.sleep(1) # 保持一定的时间间隔,避免CPU占用 +if __name__ == "__main__": + main() diff --git a/lci/extra/_init/requirements.txt b/lci/extra/_init/requirements.txt new file mode 100644 index 0000000..93e3a80 --- /dev/null +++ b/lci/extra/_init/requirements.txt @@ -0,0 +1,5 @@ +flask +waitress +GitPython>=3.1.0 +setuptools>=40.8.0 +../_pmc diff --git a/lci/extra/_pmc/.gitignore b/lci/extra/_pmc/.gitignore new file mode 100644 index 0000000..58b81c2 --- /dev/null +++ b/lci/extra/_pmc/.gitignore @@ -0,0 +1,109 @@ +# PRJ +.env/ +*.pem +*.key + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/lci/extra/_pmc/README.md b/lci/extra/_pmc/README.md new file mode 100644 index 0000000..2ac3f66 --- /dev/null +++ b/lci/extra/_pmc/README.md @@ -0,0 +1,8 @@ +## 类模块 + +这是一个类模块,它基于pmc,部分调用基于dnfs、cops、chat_s。 + + +## 包含什么 + +该类模块中包含对于python需要的子系统调用,其中聊天室的通信函数主要用于日志的输出等行为。 \ No newline at end of file diff --git a/lci/extra/_pmc/setup.py b/lci/extra/_pmc/setup.py new file mode 100644 index 0000000..7dcf2db --- /dev/null +++ b/lci/extra/_pmc/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup, find_packages + +setup( + name="pmc", + version="0.0.9", + packages=find_packages(where="src"), + package_dir={'': 'src'}, + install_requires=[ + 'setuptools', + 'requests', + 'cryptography', + ], + setup_requires=[ + #"whell", + ], + python_requires='>=3.8' +) diff --git a/lci/extra/_pmc/src/pmc/__init__.py b/lci/extra/_pmc/src/pmc/__init__.py new file mode 100644 index 0000000..349d82e --- /dev/null +++ b/lci/extra/_pmc/src/pmc/__init__.py @@ -0,0 +1,7 @@ +from .to_pmc import PmcComm +from .to_dnfs import DnfsComm +from .from_cops import CopsComm +from .rsa import Rsa_Pri_Key +from .aes import MyAES +from .parser import upload_file +#from .chat_comm import print_to_pmc diff --git a/lci/extra/_pmc/src/pmc/aes.py b/lci/extra/_pmc/src/pmc/aes.py new file mode 100644 index 0000000..6f95063 --- /dev/null +++ b/lci/extra/_pmc/src/pmc/aes.py @@ -0,0 +1,85 @@ +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives import padding +class MyAES: + def __init__(self, key: str, iv: str): + self.key: bytes = bytes.fromhex(key) + self.iv: bytes = bytes.fromhex(iv) + def decrypt(self, ciphertext: str): + cipher: bytes = bytes.fromhex(ciphertext) + plain: bytes = MyAES.aes_decrypt(cipher, self.key, self.iv) + try: + return plain.decode('utf-8') + except UnicodeDecodeError as e: + # 返回原始字节的十六进制表示作为备选 + return plain.hex() + def encrypt(self, original_text: str): + plaintext: byte = original_text.encode('utf-8') + ciphertext: byte = MyAES.aes_encrypt(plaintext, self.key, self.iv) + return ciphertext.hex() + @staticmethod + def aes_decrypt(ciphertext: bytes, key: bytes, iv: bytes) -> bytes: + """ + 使用AES-256-CBC算法解密数据 + + 参数 + - ciphertext: 待解密的密文字节串 + - key: 256位(32字节)的密钥字节串 + - iv: 初始化向量字节串(必须为16字节) + + 返回: + - 解密后的明文字节串 + """ + + # 验证输入参数长度 + if len(key) != 32: + raise ValueError('AES-256密钥必须是32字节长度') + if len(iv) != 16: + raise ValueError('AES-CBC的IV必须是16字节长度') + + # 创建AES-CBC解密器 + cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) + decryptor = cipher.decryptor() + + try: + # 执行解密并移除PKCS#7填充 + plaintext = decryptor.update(ciphertext) + decryptor.finalize() + return plaintext + except Exception as e: + print(f"解密失败:{e}") + return b'' + + @staticmethod + def aes_encrypt(plaintext: bytes, key: bytes, iv: bytes) -> bytes: + """ + AES-256-CBC 加密 + + 参数 + plaintext: 要加密的密文 + key: 32字节的密钥 + iv: 16字节的初始化向量 + 返回: + 加密后的密文 + """ + # 检查密钥和IV的长度 + if len(key) != 32: + raise ValueError("密钥必须是32字节(AES-256)") + if len(iv) != 16: + raise ValueError("IV必须是16字节") + + # 创建加密器 + cipher = Cipher( + algorithms.AES(key), + modes.CBC(iv), + backend=default_backend() + ) + encryptor = cipher.encryptor() + + # 添加PKCS7填充 + padder = padding.PKCS7(128).padder() + padded_data = padder.update(plaintext) + padder.finalize() + + # 加密数据 + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + + return ciphertext diff --git a/lci/extra/_pmc/src/pmc/chat_comm.py b/lci/extra/_pmc/src/pmc/chat_comm.py new file mode 100644 index 0000000..07cc323 --- /dev/null +++ b/lci/extra/_pmc/src/pmc/chat_comm.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +import argparse +import socket + +def send_client(msg: str, addr: str, port: int, name: str): + '''发送消息给聊天室服务器。 + + 需要输入消息、地址、端口、昵称''' + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect((addr, port)) + s.sendall(f"{name}: {msg}".encode('utf-8')) + s.close() + print('success') + except ConnectionRefusedError: + print(f"Could not connect to {addr}:{port}") + except Exception as e: + print(f"Unexpected error: {e}") + +class ChatComm: + '''与聊天服务器进行交流的类。''' + def __init__(self, addr: str, port: int, name: str): + self.addr = addr + self.port = port + self. name = name + def send(self, msg: str): + send_client(msg, self.addr, self.port, self.name) +def main(): + parser = argparse.ArgumentParser(description='发送到聊天室。') + parser.add_argument("--msg", type=str, help="要发送的消息") + parser.add_argument('--addr', type=str, default='localhost', help='选择要连接的地址') + parser.add_argument('--port', type=int, default=8003, help='选择要连接的地址') + parser.add_argument('--name', type=str, default='Unknow', help='你的名字是什么') + args = parser.parse_args() + comm = ChatComm(args.addr, args.port, args.name) + comm.send(args.msg) + +if __name__ == '__main__': + main() diff --git a/lci/extra/_pmc/src/pmc/from_cops.py b/lci/extra/_pmc/src/pmc/from_cops.py new file mode 100644 index 0000000..3b206ad --- /dev/null +++ b/lci/extra/_pmc/src/pmc/from_cops.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +''' +这是用于访问协处理器http服务的程序 +''' +import requests +import os +import argparse +class CopsComm: + '''与协处理器的通信类''' + def __init__(self, url: str): + self.url: str= url + def http_post(self, module: str): + response = requests.post(self.url, json={'cmd': module}, headers={'Content-Type': 'application/json'} ) + response.raise_for_status() + return response.text +if __name__ == "__main__": + # python3 from_cops.py --url=http://192.168.254.101:8001/api --mod=MPU6050 + parser = argparse.ArgumentParser(description="COPS的http调用示例。") + parser.add_argument('--url', help='访问的URL') + parser.add_argument('--mod', help='要输入的指令') + args = parser.parse_args() + comm = CopsComm(args.url) + rsp = comm.http_post(args.mod) + print(rsp) + diff --git a/lci/extra/_pmc/src/pmc/parser.py b/lci/extra/_pmc/src/pmc/parser.py new file mode 100644 index 0000000..16cd6b3 --- /dev/null +++ b/lci/extra/_pmc/src/pmc/parser.py @@ -0,0 +1,99 @@ +import urllib.request +import argparse +import sys + +def openfile(filename): + try: + with open(filename, "r", encoding='utf-8') as f: + content = f.read() + print(f"✅ 文件读取成功,内容长度: {len(content)} 字符") + return content + except FileNotFoundError as e: + print(f"❌ 错误:指定的文件不存在 -> {filename}") + raise e + except PermissionError as e: + print(f"❌ 错误:没有权限读取文件 -> {filename}") + raise e + except Exception as e: + print(f"❌ 错误:读取文件失败 -> {str(e)}") + raise e + +def httppost(url: str, msg: str) -> str: + try: + # 核心转换:字符串 → 字节流(原生库必须要求) + post_body_bytes = msg.encode("utf-8") + # 发送POST请求,timeout=10秒防止卡死 + response = urllib.request.urlopen(url, data=post_body_bytes, timeout=2) + + # 解析响应结果 + if response.getcode() == 200: + resp_content = response.read().decode("utf-8") + print("\n🎉 请求上传成功!HTTP状态码: 200") + print(f"🎉 服务端响应内容:\n{resp_content}") + else: + resp_content = f'---{str(response.getcode())}---' + print(f"\n⚠️ 请求上传完成,但服务端返回异常状态码: {response.getcode()}") + print(f"⚠️ 服务端响应内容: {resp_content}") + + return resp_content + + except urllib.error.URLError as e: + print(f"\n❌ 请求失败:网络错误/连接超时/端口未开放 -> {str(e)}") + raise e + except urllib.error.HTTPError as e: + print(f"\n❌ 请求失败:HTTP错误 -> 状态码: {e.code}, 详情: {e.read().decode('utf-8')}") + raise e + except Exception as e: + print(f"\n❌ 请求失败:未知错误 -> {str(e)}") + raise e + +def upload_file(file: str, host: str, port: int) -> str: + """抽象的URL访问函数,用于上传文件到指定服务器 + + Args: + file: 待上传的文件路径 + host: 目标服务器IP + port: 目标服务器端口 + """ + try: + # 读取文件内容 + msg = openfile(file) + # 构造URL + url = f"http://{host}:{port}/api/v1/mybot-sample" + # 发送POST请求 + resp = httppost(url, msg) + except Exception as e: + print(f"❌ 错误:上传文件失败 -> {str(e)}") + resp = str(e) + return resp + +def upload_file_and_train(file: str, host: str, port: int) -> str: + """抽象的URL访问函数,用于上传文件到指定服务器 + + Args: + file: 待上传的文件路径 + host: 目标服务器IP + port: 目标服务器端口 + """ + try: + # 读取文件内容 + msg = openfile(file) + # 构造URL + url = f"http://{host}:{port}/api/v1/mybot-nn" + # 发送POST请求 + resp = httppost(url, msg) + except Exception as e: + print(f"❌ 错误:上传文件失败 -> {str(e)}") + resp = str(e) + return resp + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="python 远程上传文本内容") + parser.add_argument("file", type=str, help="待上传的文件") + parser.add_argument('--port', type=int, default=9203, help="目标服务器监听端口,默认9203") + parser.add_argument("--host", type=str, default="127.0.0.1", help="目标服务器的IP,默认本地") + args =parser.parse_args() + resp = upload_file(args.file, args.host, args.port) + #resp = upload_file_and_train(args.file, args.host, args.port) + print(resp) diff --git a/lci/extra/_pmc/src/pmc/rsa.py b/lci/extra/_pmc/src/pmc/rsa.py new file mode 100644 index 0000000..94a8a8e --- /dev/null +++ b/lci/extra/_pmc/src/pmc/rsa.py @@ -0,0 +1,103 @@ +from cryptography.hazmat.primitives import serialization, hashes +from cryptography.hazmat.primitives.asymmetric import rsa, padding +from cryptography.hazmat.backends import default_backend +import os +class Rsa_Pri_Key: + '''RSA 私钥对象''' + def __init__(self, fullpath: str) -> None: + self.pri_key=Rsa_Pri_Key.load_private_key(fullpath) + def decrypt(self, ciphertext: str) -> str: + return Rsa_Pri_Key.decrypt_hex_ciphertext(self.pri_key, ciphertext) + + + @staticmethod + def load_private_key(pem_file, password=None): + ''' + 从PEM文件加载RSA私钥 + + :param pem_file: PEM格式的私钥文件路径 + :param password: 私钥密码(如果有) + :return RSA私钥对象 + ''' + with open(pem_file, 'rb') as key_file: + private_key = serialization.load_pem_private_key( + key_file.read(), + password=password.encode() if password else None, + backend=default_backend() + ) + return private_key + + @staticmethod + def decrypt_hex_ciphertext(private_key, hex_ciphertext): + ''' + 解密HEX格式的RSA密文 + + :param private_key: 已加载的RSA私钥 + :param hex_ciphertext: Hex字符串格式的密文 + :return: 解密后的明文 + ''' + try: + # 将Hex字符串转换为bytes + ciphertext = bytes.fromhex(hex_ciphertext) + + # 使用OAEP填充方案解密 + plaintext = private_key.decrypt( + ciphertext, + padding.OAEP( + # OPENSSL 没有显式指定时,这个是SHA1 + mgf=padding.MGF1(algorithm=hashes.SHA1()), + algorithm=hashes.SHA1(), + label=None + ) + ) + return plaintext + except ValueError as e: + print(f"Hex解码失败:{str(e)}") + return None + except Exception as e: + print(f"解密失败:{str(e)}") + return None + + +def main(): + ... + +if __name__ == '__main__': + main() +""" +# 生成RSA私钥 +private_key = rsa.generate_private_key( + public_exponent=65537, # 通常使用65537作为公钥指数 + key_size=2048, # 密钥长度,推荐至少2048位 +) + +# 将私钥序列化为PEM格式 +pem_private_key = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.NoEncryption() # 这里不加密私钥 +) + +# 获取对应的公钥 +public_key = private_key.public_key() + +# 将公钥序列化为PEM格式 +pem_public_key = public_key.public_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PublicFormat.SubjectPublicKeyInfo +) + +# 打印密钥 +print("私钥:") +print(pem_private_key.decode('utf-8')) + +print("公钥:") +print(pem_public_key.decode('utf-8')) + +# 可选:将密钥保存到文件 +with open('private_key.pem', 'wb') as f: + f.write(pem_private_key) + +with open('public_key.pem', 'wb') as f: + f.write(pem_public_key) +""" diff --git a/lci/extra/_pmc/src/pmc/to_dnfs.py b/lci/extra/_pmc/src/pmc/to_dnfs.py new file mode 100644 index 0000000..697bdc4 --- /dev/null +++ b/lci/extra/_pmc/src/pmc/to_dnfs.py @@ -0,0 +1,118 @@ +import requests +import hashlib +import json + +def calculate_sha256(input_string): + """ + 计算输入字符串的SHA-256哈希值 + + 参数: + input_string (str): 要计算哈希的字符串 + + 返回: + str: 输入字符串的SHA-256哈希值(十六进制字符串) + """ + # 创建sha256哈希对象 + sha256_hash = hashlib.sha256() + + # 更新哈希对象,需要将字符串编码为字节 + sha256_hash.update(input_string.encode('utf-8')) + + # 获取十六进制格式的哈希值 + hex_digest = sha256_hash.hexdigest() + + return hex_digest + +class DnfsComm: + '''=====抛出异常表示失败。===== + Dnfs即树状网络文件系统,该类是用于与dnfs通信的类。 + + 可以获取子节点列表、添加节点、删除节点、更新节点。 + + 计划在以后加入分组获取内容的功能。''' + + def __init__(self, url: str) -> None: + self.url: str = url + + + # 获取某个节点下的子节点(0是主节点) + def get(self, pid: int) -> object: + rsp = requests.post(self.url + "/get_notes", json={ + "pid": pid + },) + if (rsp.status_code == 200): + return rsp.text + else: + raise DnfsComm.GetFailed(rsp.text) + + def get_and_trans(self, pid: int) -> list: + return json.loads(self.get(pid)) + + # 以pid节点为父节点添加节点 + def add(self, pid: int, title: str, content: str) -> object: + rsp = requests.post(self.url + "/add_note", json={ + "pid": pid, + "title": title, + "content": content + },) + if (rsp.status_code == 200 or rsp.status_code == 201): + return rsp.text + else: + raise DnfsComm.AddFailed(rsp.text) + + # 删除一个节点 + def dele(self, id: int) -> object: + rsp = requests.post(self.url + "/delete_note", json={ + "id": id, + },) + if (rsp.status_code == 200): + return rsp.text + else: + raise DnfsComm.DelFailed(rsp.text) + + # 更新id节点 + def upd(self, id: int, pid: int, title: str, content: str) -> object: + rsp = requests.post(self.url + "/update_note", json={ + "id": id, + "pid": pid, + "title": title, + "content": content + },) + if (rsp.status_code == 200): + return rsp.text + else: + raise DnfsComm.UpdFailed(rsp.text) + + + class TheExp(Exception): + def __init__(self, msg: str): + super().__init__(msg) + + class GetFailed(TheExp): + def __init__(self, msg: str): + super().__init__(msg) + + class AddFailed(TheExp): + def __init__(self, msg: str): + super().__init__(msg) + + class DelFailed(TheExp): + def __init__(self, msg: str): + super().__init__(msg) + + class UpdFailed(TheExp): + def __init__(self, msg): + super().__init__(msg) + +if __name__ == "__main__": + comm = DnfsComm("http://101.245.108.250:8006") + #comm.add(0, "test pkg", "hello") + #comm.dele(2) + #comm.upd(id=1, pid=0, title="Users", content=f"""1::admin::{calculate_sha256('baigezi')}::admin +#2::qing::{calculate_sha256('123456')}::normal +#3::test::{calculate_sha256('44112233')}::normal +#4::test2::{calculate_sha256('44112233')}::mormal""") + #comm.upd(id=2, pid=0, title="Sensors", content='''101::temperature +#102::humidity''') + comm.upd(id=3, pid=0, title="Protected", content='''''') + print(comm.get_and_trans(0)) diff --git a/lci/extra/_pmc/src/pmc/to_pmc.py b/lci/extra/_pmc/src/pmc/to_pmc.py new file mode 100644 index 0000000..8f16048 --- /dev/null +++ b/lci/extra/_pmc/src/pmc/to_pmc.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 + +''' + +这个代码是与PMC服务通信的工具 + +即PMC子系统调用 + +通过PMC服务,你可以创建和管理进程 + +=============================== + +20250701: 版本:0.0.4 +使得这个模块可以访问任何地址的pmc服务 + +20250702:版本 0.0.5 +使得这个模块在创建之初就保存一个url + +20250709: 版本 0.1.0 +使得模块在通信过程中应用RSA和AES加密手段 + +''' +from .rsa import Rsa_Pri_Key +from .aes import MyAES +import requests +import os +import json +import sys + + +class PmcComm: + '''并发机器通信''' + + def __init__(self, url: str): + self.url: str = url + + # 新库 + ############################ + @staticmethod + def post_to(url, payload="", retry=10): + count = 0 + while count < retry: + count += 1 + try: + response = requests.post(url, data=payload) + response.raise_for_status() + return response.text + except requests.exceptions.HTTPError: + ... + raise Exception("连接失败") + + + @staticmethod + def get_from(url, retry=10): + count = 0 + while count < retry: + count += 1 + try: + response = requests.get(url) + response.raise_for_status() + return response.text + except requests.exceptions.HTTPError: + ... + raise Exception("连接失败") + + def get_key(self) -> str: + return PmcComm.get_from(f"{self.url}/api/v1/get_key") + + def get_iv(self) -> str: + return PmcComm.get_from(f"{self.url}/api/v1/get_iv") + + def get_list(self,) -> str: + ls = PmcComm.get_from(f"{self.url}/api/v1/get_list") + return self.aes.decrypt(ls).strip() # 第二天早上就出现了空格 + + def start(self, module: str) -> str: + msg = json.dumps({'module': module}) + msg = self.aes.encrypt(msg) + return PmcComm.post_to( + f'{self.url}/api/v1/start', + payload=msg + ) + + def try_start(self, module: str) -> str: + try: + self.start(module) + except Exception as e: + print(f'{module}: {e}', file=sys.stderr) + + def kill(self, pid: int) -> str: + msg = json.dumps({'pid': pid}) + msg = self.aes.encrypt(msg) + return PmcComm.post_to( + f'{self.url}/api/v1/kill', + payload=msg + ) + + def clear(self, ) -> str: + return PmcComm.post_to(f'{self.url}/api/v1/clear') + + def list_mods(self,) -> str: + ls = PmcComm.get_from(f"{self.url}/api/v1/list_mods") + return self.aes.decrypt(ls) + + + def Set_RSA_Pri_Key(self, fullpath: str) -> None: + self.rsa_pri: Rsa_Pro_Key = Rsa_Pri_Key(fullpath) + + def Set_AES_Key(self, key: str, iv: str) -> None: + self.aes = MyAES(key.decode(), iv.decode()) + + + def Try_Get_AES_Key(self, retry: int=10) -> None: + '''试图获取AES密钥,测试中失败率比较高''' + key_data = self.get_key() + key = self.rsa_pri.decrypt(key_data) + iv_data = self.get_iv() + iv = self.rsa_pri.decrypt(iv_data) + self.Set_AES_Key(key, iv) + + def Test(): + # 测试对象 + #url = "http://101.245.108.250:8012" + url = "http://localhost:8012" + + # 创建交流对象 + comm = PmcComm(url) + comm.Set_RSA_Pri_Key("private_key.pem") + comm.Try_Get_AES_Key() + #msg = comm.start("mgmt") + #msg = comm.kill(6488) + #msg =comm.clear() + msg = comm.get_list() + print(msg) + diff --git a/lci/extra/cancerai/.gitignore b/lci/extra/cancerai/.gitignore new file mode 100644 index 0000000..e62b9b4 --- /dev/null +++ b/lci/extra/cancerai/.gitignore @@ -0,0 +1 @@ +api-test/ diff --git a/lci/extra/cancerai/README.md b/lci/extra/cancerai/README.md new file mode 100644 index 0000000..158d435 --- /dev/null +++ b/lci/extra/cancerai/README.md @@ -0,0 +1,5 @@ +# 作者是CANCERAI +这个模块的作者写了mgmt模块的前端部分,这个模块曾经短暂地为mgmt模块提供一部分的后端支持。 + +# 20250810 +该模块已经被开发成为dnfs树状网络文件系统的后端。 \ No newline at end of file diff --git a/lci/extra/cancerai/_run.sh b/lci/extra/cancerai/_run.sh new file mode 100644 index 0000000..6a7ae61 --- /dev/null +++ b/lci/extra/cancerai/_run.sh @@ -0,0 +1,4 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +cd pmc-backend +exec mvn clean spring-boot:run diff --git a/lci/extra/cancerai/api-doc.html b/lci/extra/cancerai/api-doc.html new file mode 100644 index 0000000..458094f --- /dev/null +++ b/lci/extra/cancerai/api-doc.html @@ -0,0 +1,1129 @@ + + + + + + + Document + + + + +

API文档

+
+
目录
+ 登陆 +
+ 获取节点 +
+ 新增节点 +
+ 删除节点 +
+ 修改节点 +
+ +
登陆
+

URL

+

127.0.0.1:8011/api/login

+ +

请求方法

+

POST

+ +

请求头

+

无

+ +

请求体

+

类型: JSON

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
namepassword
说明用户名密码
是否必须TrueTrue
类型StringString
示例cancerai123
+

响应体

+

状态码: 200

+

类型: JSON

+

说明: 登陆成功

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息token
类型StringString
示例"登陆成功""eyJhbGciOiJIUzI1NiJ9....."
+
+

状态码: 401

+

类型: JSON

+

说明: 登陆失败

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"账号或密码错误"null
+
+

状态码: 405

+

类型: JSON

+

说明: 请求方式不支持

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"请求方式错误"null
+

+
获取节点
+

URL

+

127.0.0.1:8011/api/get-notes

+

请求方法

+

GET

+

请求头

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
token
说明登陆时拿到的令牌
是否必须True
类型String
示例"eyJhbGciOiJIUzI1NiJ9....."
+

查询参数

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
token
说明PID
是否必须True
类型int
示例0 +
+

请求体

+

无

+

响应体

+

状态码: 200

+

类型: JSON

+

说明: 查询成功

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息查询到的Note
类型StringList
示例"Request OK"[{}, {}, {}]
+
+

状态码: 401

+

类型: JSON

+

说明: JWT令牌无效

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT无效"null
+
+

状态码: 401

+

类型: JSON

+

说明: JWT令牌过期

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT过期"null
+
+

状态码: 405

+

类型: JSON

+

说明: 请求方式不支持

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"请求方式错误"null
+
+

状态码: 500

+

类型: JSON

+

说明: 没有传PID或其他问题

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"服务器内部错误"null
+

+
新增节点
+

URL

+

127.0.0.1:8011/api/add-note

+ +

请求方法

+

PUT

+ +

请求头

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
token
说明登陆时拿到的令牌
是否必须True
类型String
示例"eyJhbGciOiJIUzI1NiJ9....."
+ +

请求体

+

无

+ +

查询参数

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pidtitlecontent
说明PIDnote标题note主体
是否必须TrueTrueTrue
类型intStringString
示例0"test title""test content"
+

响应体

+

状态码: 200

+

类型: JSON

+

说明: 新增成功

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"成功添加节点"null +
+
+

状态码: 401

+

类型: JSON

+

说明: JWT无效或被篡改

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT无效"null
+
+

状态码: 401

+

类型: JSON

+

说明: JWT令牌过期

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT过期"null
+
+

状态码: 405

+

类型: JSON

+

说明: 请求方式不支持

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"请求方式错误"null
+
+

状态码: 500

+

类型: JSON

+

说明: 可能请求参数不正确或服务器内部错误

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"服务器内部错误"null
+

+
删除节点
+

URL

+

127.0.0.1:8011/api/delete-note

+ +

请求方法

+

DELETE

+ +

请求头

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
token
说明登陆时拿到的令牌
是否必须True
类型String
示例"eyJhbGciOiJIUzI1NiJ9....."
+ +

请求体

+

无

+ +

查询参数

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
id
说明PID
是否必须True
类型int
示例16
+

响应体

+

状态码: 200

+

类型: JSON

+

说明: 删除成功

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"成功删除节点"null +
+
+

状态码: 401

+

类型: JSON

+

说明: JWT无效或被篡改

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT无效"null
+
+

状态码: 401

+

类型: JSON

+

说明: JWT令牌过期

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT过期"null
+
+

状态码: 405

+

类型: JSON

+

说明: 请求方式不支持

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"请求方式错误"null
+
+

状态码: 500

+

类型: JSON

+

说明: 删除不存在的id或服务器内部错误

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"服务器内部错误"null
+

+
更新节点
+

URL

+

127.0.0.1:8011/api/update-note

+ +

请求方法

+

PATCH

+ +

请求头

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
token
说明登陆时拿到的令牌
是否必须True
类型String
示例"eyJhbGciOiJIUzI1NiJ9....."
+ +

请求体

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
idpidtitlecontent
说明要修改的note ID修改后的note的PID修改后的note标题修改后的note主体
是否必须TrueTrueTrueTrue
类型intintStringString
示例160"changed test""changed content"
+ +

查询参数

+

无

+

响应体

+

状态码: 200

+

类型: JSON

+

说明: 更新成功

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"成功更新节点"null +
+
+

状态码: 401

+

类型: JSON

+

说明: JWT无效或被篡改

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT无效"null
+
+

状态码: 401

+

类型: JSON

+

说明: JWT令牌过期

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"JWT过期"null
+
+

状态码: 405

+

类型: JSON

+

说明: 请求方式不支持

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"请求方式错误"null
+
+

状态码: 500

+

类型: JSON

+

说明: 更新的id不存在或服务器内部错误

+

字段:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
messagedata
说明说明信息无
类型Stringnull
示例"服务器内部错误"null
+ + + \ No newline at end of file diff --git a/lci/extra/cancerai/pmc-backend/.gitattributes b/lci/extra/cancerai/pmc-backend/.gitattributes new file mode 100644 index 0000000..3b41682 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/lci/extra/cancerai/pmc-backend/.gitignore b/lci/extra/cancerai/pmc-backend/.gitignore new file mode 100644 index 0000000..667aaef --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/lci/extra/cancerai/pmc-backend/pom.xml b/lci/extra/cancerai/pmc-backend/pom.xml new file mode 100644 index 0000000..120ee4a --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.3 + + + + org.cancerai + pmc-backend + 0.0.1-SNAPSHOT + pmc-backend + pmc management backend + + + + + + + + + + + + + + + 17 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.boot + spring-boot-starter-webflux + + + com.google.code.gson + gson + 2.13.1 + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/PmcBackendApplication.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/PmcBackendApplication.java new file mode 100644 index 0000000..b7d8287 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/PmcBackendApplication.java @@ -0,0 +1,15 @@ +package org.cancerai.pmc_backend; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.web.servlet.ServletComponentScan; + +@ServletComponentScan +@SpringBootApplication +public class PmcBackendApplication { + + public static void main(String[] args) { + SpringApplication.run(PmcBackendApplication.class, args); + } + +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/DNFSController.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/DNFSController.java new file mode 100644 index 0000000..9a413fe --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/DNFSController.java @@ -0,0 +1,74 @@ +package org.cancerai.pmc_backend.controller; + +import jakarta.servlet.http.HttpServletResponse; +import org.cancerai.pmc_backend.entility.Note; +import org.cancerai.pmc_backend.utils.DNFSUtils; +import org.cancerai.pmc_backend.utils.HttpResponseText; +import org.cancerai.pmc_backend.vo.Result; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; + +@CrossOrigin(origins = "*") +@RestController +@RequestMapping("/api") +public class DNFSController { + @GetMapping("/get-notes") + public static Result getNotes(@RequestParam int pid) { + return Result.success(HttpResponseText.SUCCESS_TO_REQUEST, DNFSUtils.getNodes(pid)); + } + + @PutMapping("/add-note") + public Result addNote( + @RequestParam int pid, + @RequestParam String title, + @RequestParam String content, + HttpServletResponse response + ) { + HashMap re = DNFSUtils.addNote(pid, title, content); + String value = re.get("message"); + + if ("Note added successfully".equals(value)) { + return Result.success(HttpResponseText.SUCCESS_TO_ADD_NOTE); + } else { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return Result.error(HttpResponseText.INTERNAL_SERVER_ERROR); + } + } + + @DeleteMapping("/delete-note") + public Result deleteNote( + @RequestParam int id, + HttpServletResponse response + ) { + HashMap re = DNFSUtils.deleteNote(id); + String value = re.get("message"); + + if ("Note deleted successfully".equals(value)) { + return Result.success(HttpResponseText.SUCCESS_TO_DELETE_NOTE); + } else { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return Result.error(HttpResponseText.INTERNAL_SERVER_ERROR); + } + } + + @PatchMapping("/update-note") + public static Result updateNote( + @RequestBody Note note, + HttpServletResponse response + ) { + int id = note.getId(); + int pid = note.getPid(); + String title = note.getTitle(); + String content = note.getContent(); + + HashMap re = DNFSUtils.updateNote(id, pid, title, content); + String value = re.get("message"); + if ("Your change is up-to-date.".equals(value)) { + return Result.success(HttpResponseText.SUCCESS_TO_UPDATE_NOTE); + } else { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return Result.error(HttpResponseText.INTERNAL_SERVER_ERROR); + } + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/LoginController.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/LoginController.java new file mode 100644 index 0000000..8baf1cb --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/LoginController.java @@ -0,0 +1,29 @@ +package org.cancerai.pmc_backend.controller; + +import jakarta.servlet.http.HttpServletResponse; +import org.cancerai.pmc_backend.entility.User; +import org.cancerai.pmc_backend.service.LoginService; +import org.cancerai.pmc_backend.utils.EncryptUtils; +import org.cancerai.pmc_backend.vo.Result; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@CrossOrigin(origins = "*") +@RestController +@RequestMapping("/api") +public class LoginController { + @Autowired + private LoginService loginService; + + @PostMapping("/login") + public Result login( + @RequestBody User user, + HttpServletResponse response + ) { + String name = user.getName(); + String password = EncryptUtils.SHA256Encrypt(user.getPassword()); + + return loginService.verifyUser(name, password, response); + } + +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/ProcessController.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/ProcessController.java new file mode 100644 index 0000000..2bbf090 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/controller/ProcessController.java @@ -0,0 +1,52 @@ +package org.cancerai.pmc_backend.controller; + +import org.cancerai.pmc_backend.entility.ProcessEntility; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.function.client.WebClient; + +import java.util.ArrayList; + +@CrossOrigin(origins = "*") +@RestController() +public class ProcessController { + @GetMapping("/get-process") + public ArrayList cleanProcess() { + ArrayList arr = getProcessList(); + ArrayList result = new ArrayList<>(); + final String DEAD = "Dead"; + +// exclude Dead lines + for (String i : arr) { + String[] item = i.split("\t"); + String pid = item[0]; + String status = item[1]; + String cmd = item[2]; + + if (DEAD.equals(status)) { + continue; + } + result.add(new ProcessEntility(pid, status, cmd)); + } + + return result; + } + + private static ArrayList getProcessList() { + ArrayList array = new ArrayList<>(); + WebClient webClient = WebClient.create("http://127.0.0.1:8012"); + + String response = webClient.post() + .uri("/api/list") + .retrieve() + .bodyToMono(String.class) + .block(); + + String[] splitRes = response.split("\n"); + for (String item : splitRes) { + array.add(item); + } + return array; + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/Note.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/Note.java new file mode 100644 index 0000000..1769541 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/Note.java @@ -0,0 +1,57 @@ +package org.cancerai.pmc_backend.entility; + +public class Note { + private String content; + private int id; + private int pid; + private String title; + + public Note(String content, int id, int pid, String title) { + this.content = content; + this.id = id; + this.pid = pid; + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getPid() { + return pid; + } + + public void setPid(int pid) { + this.pid = pid; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String toString() { + return "Note{" + + "content='" + content + '\'' + + ", id=" + id + + ", pid=" + pid + + ", title='" + title + '\'' + + '}'; + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/ProcessEntility.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/ProcessEntility.java new file mode 100644 index 0000000..41402ef --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/ProcessEntility.java @@ -0,0 +1,37 @@ +package org.cancerai.pmc_backend.entility; + +public class ProcessEntility { + private String pid; + private String status; + private String cmd; + + public ProcessEntility(String pid, String status, String cmd) { + this.pid = pid; + this.status = status; + this.cmd = cmd; + } + + public String getPid() { + return pid; + } + + public void setPid(String pid) { + this.pid = pid; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCmd() { + return cmd; + } + + public void setCmd(String cmd) { + this.cmd = cmd; + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/User.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/User.java new file mode 100644 index 0000000..1db1b40 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/entility/User.java @@ -0,0 +1,22 @@ +package org.cancerai.pmc_backend.entility; + +public class User { + private String name; + private String password; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/exception/GlobalExceptionHandler.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..188bc53 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/exception/GlobalExceptionHandler.java @@ -0,0 +1,45 @@ +package org.cancerai.pmc_backend.exception; + +import org.cancerai.pmc_backend.vo.Result; +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.servlet.resource.NoResourceFoundException; + +@RestControllerAdvice +public class GlobalExceptionHandler { +// 400 + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(HttpMessageNotReadableException.class) + public static Result JWTSignature(HttpMessageNotReadableException e) { + e.printStackTrace(); + return Result.error("请求参数无效"); + } + + // 401 + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + public static Result requestMethodNotSupport(HttpRequestMethodNotSupportedException e) { + e.printStackTrace(); + return Result.error("请求方法错误"); + } + + // 404 + @ResponseStatus(HttpStatus.NOT_FOUND) + @ExceptionHandler(NoResourceFoundException.class) + public static Result ResourceNotFound(NoResourceFoundException e) { + e.printStackTrace(); + return Result.error("未找到静态资源"); + } + +// 500 + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + @ExceptionHandler(Exception.class) + public static Result exception(Exception e) { + e.printStackTrace(); + return Result.error("服务器内部错误"); + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/filter/LoginFilter.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/filter/LoginFilter.java new file mode 100644 index 0000000..5dd5c75 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/filter/LoginFilter.java @@ -0,0 +1,91 @@ +package org.cancerai.pmc_backend.filter; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.MalformedJwtException; +import jakarta.servlet.*; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.cancerai.pmc_backend.utils.HttpResponseText; +import org.cancerai.pmc_backend.utils.JWTUtils; +import org.cancerai.pmc_backend.vo.Result; +import org.springframework.core.annotation.Order; + +import java.io.IOException; +import java.io.PrintWriter; + +@WebFilter(urlPatterns = "/api/*") +@Order(1) +public class LoginFilter implements Filter { + final String[] EXCLUDE_URL_LIST = { + "/api/login" + }; + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; +// set content security policy + response.setHeader("Content-Security-Policy", "default-src *"); + +// exclude url + String uri = request.getRequestURI(); + for (String item : EXCLUDE_URL_LIST) { + if (item.equals(uri)) { + filterChain.doFilter(servletRequest, servletResponse); + return; + } + } +// Allow OPTION method + if ("OPTIONS".equals(request.getMethod())) { + filterChain.doFilter(servletRequest, servletResponse); + return; + } + + String token = request.getHeader("token"); + if (token == null || token.isEmpty()) { +// set response header + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json"); + +// construct body + Gson gson = new GsonBuilder().serializeNulls().create(); + String responseBody = gson.toJson(Result.error(HttpResponseText.UNAUTHORIZED)).toString(); +// set response body + PrintWriter writer = response.getWriter(); + writer.write(responseBody); + writer.flush(); + return; + } + + try { + JWTUtils.parseJWT(token); + } catch (MalformedJwtException e) { +// set response body + Gson gson = new GsonBuilder().serializeNulls().create(); + String body = gson.toJson(Result.error(HttpResponseText.JWT_MALFORMED)); + + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + PrintWriter writer = response.getWriter(); + writer.write(body); + writer.flush(); + return; + } catch (ExpiredJwtException e) { +// set response body + Gson gson = new GsonBuilder().serializeNulls().create(); + String body = gson.toJson(Result.error(HttpResponseText.JWT_EXPIRED)); + + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + PrintWriter writer = response.getWriter(); + writer.write(body); + writer.flush(); + return; + } + +// Allow + filterChain.doFilter(servletRequest, servletResponse); + response.setHeader("Content-Security-Policy", "default-src *"); + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/service/LoginService.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/service/LoginService.java new file mode 100644 index 0000000..5d1f33e --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/service/LoginService.java @@ -0,0 +1,67 @@ +package org.cancerai.pmc_backend.service; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import jakarta.servlet.http.HttpServletResponse; +import org.cancerai.pmc_backend.entility.Note; +import org.cancerai.pmc_backend.utils.DNFSUtils; +import org.cancerai.pmc_backend.utils.JWTUtils; +import org.cancerai.pmc_backend.vo.Result; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + +@Service +public class LoginService { + public static Result verifyUser(String name, String password, HttpServletResponse response) { + ArrayList> allUsersInfo = getAllUsersInfo(); + boolean isExist = false; + + for (HashMap u : allUsersInfo) { + if (name.equals(u.get("name")) + && password.equals(u.get("password")) + ) { + isExist = true; + } + } + + if (isExist) { + return Result.success( + "登陆成功", + JWTUtils.genJWT(name, password)); + } else { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return Result.error("账号或密码错误"); + } + } + + private static ArrayList> getAllUsersInfo() { + Gson gson = new Gson(); +// StringBuilder stringBuilder = new StringBuilder(); + ArrayList userList = new ArrayList<>(); + ArrayList re = DNFSUtils.getNodes(0); + String jsonString = gson.toJson(re); + JsonArray jsonArray = gson.fromJson(jsonString, JsonArray.class); + + for (JsonElement jsonElement : jsonArray) { +// To json + JsonObject jsonObject = jsonElement.getAsJsonObject(); +// The value is \" + VALUE + \" + String titleString = jsonObject.get("title").toString(); + String titleValue = titleString.substring(1, titleString.length() - 1); + if ("Users".equals(titleValue)) { + String contentString = jsonObject.get("content").toString(); + String contentValue = contentString.substring(1, contentString.length() - 1); + + String[] contentSplit = contentValue.split("\\\\n"); + userList.addAll(Arrays.asList(contentSplit)); + } + } + + return DNFSUtils.parseUserInfo(userList); + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/DNFSUtils.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/DNFSUtils.java new file mode 100644 index 0000000..9cf36e0 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/DNFSUtils.java @@ -0,0 +1,105 @@ +package org.cancerai.pmc_backend.utils; + +import org.cancerai.pmc_backend.entility.Note; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.HashMap; + +public class DNFSUtils { + private final static String domain = "http://qsont.xyz:8006"; + + public static ArrayList getNodes(Integer pid) { + RestTemplate restTemplate = new RestTemplate(); +// prepare request body + HashMap requestBody = new HashMap<>(); + requestBody.put("pid", pid); +// prepare request header + HttpHeaders requestHeader = new HttpHeaders(); + requestHeader.setContentType(MediaType.APPLICATION_JSON); + + ResponseEntity> response = restTemplate.exchange( + domain + "/get_notes", + HttpMethod.POST, + new HttpEntity<>(requestBody, requestHeader), + new ParameterizedTypeReference>() { + } + ); + + return response.getBody(); + } + + public static HashMap addNote(int pid, String title, String content) { + RestTemplate restTemplate = new RestTemplate(); + HashMap body = new HashMap<>(); + HttpHeaders header = new HttpHeaders(); + + header.setContentType(MediaType.APPLICATION_JSON); + body.put("pid", String.valueOf(pid)); + body.put("title", title); + body.put("content", content); + + return restTemplate.exchange( + domain + "/add_note", + HttpMethod.POST, + new HttpEntity<>(body, header), + new ParameterizedTypeReference>() { + } + ).getBody(); + } + + public static HashMap deleteNote(int id) { + RestTemplate restTemplate = new RestTemplate(); + HashMap body = new HashMap<>(); + HttpHeaders header = new HttpHeaders(); + + header.setContentType(MediaType.APPLICATION_JSON); + body.put("id", String.valueOf(id)); + + return restTemplate.exchange( + domain + "/delete_note", + HttpMethod.POST, + new HttpEntity<>(body, header), + new ParameterizedTypeReference>() { + } + ).getBody(); + } + + public static HashMap updateNote(int id, int pid, String title, String content) { + RestTemplate restTemplate = new RestTemplate(); + HashMap body = new HashMap<>(); + HttpHeaders header = new HttpHeaders(); + + header.setContentType(MediaType.APPLICATION_JSON); + body.put("id", String.valueOf(id)); + body.put("pid", String.valueOf(pid)); + body.put("title", title); + body.put("content", content); + + return restTemplate.exchange( + domain + "/update_note", + HttpMethod.POST, + new HttpEntity<>(body, header), + new ParameterizedTypeReference>() { + } + ).getBody(); + } + + public static ArrayList> parseUserInfo(ArrayList userLIst) { + ArrayList> array = new ArrayList<>(); + + for (String s : userLIst) { + HashMap map = new HashMap<>(); + String[] splitArray = s.split("::"); + map.put("id", splitArray[0]); + map.put("name", splitArray[1]); + map.put("password", splitArray[2]); + map.put("role", splitArray[3]); + array.add(map); + } + + return array; + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/EncryptUtils.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/EncryptUtils.java new file mode 100644 index 0000000..c0d941f --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/EncryptUtils.java @@ -0,0 +1,30 @@ +package org.cancerai.pmc_backend.utils; + +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class EncryptUtils { + public static String SHA256Encrypt(String str) { + try { + // 获取SHA-256算法实例 + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + + // 计算哈希值(指定UTF-8编码避免平台差异) + byte[] hashBytes = digest.digest(str.getBytes(StandardCharsets.UTF_8)); + + // 将字节数组转换为十六进制字符串 + StringBuilder hexString = new StringBuilder(); + for (byte b : hashBytes) { + // 将每个字节转换为两位十六进制数,不足两位补0 + String hex = String.format("%02x", 0xFF & b); + hexString.append(hex); + } + return hexString.toString(); + + } catch (NoSuchAlgorithmException e) { + // SHA-256是Java标准算法,理论上不会抛出此异常 + throw new RuntimeException("SHA-256算法不支持", e); + } + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/HttpResponseText.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/HttpResponseText.java new file mode 100644 index 0000000..f6100be --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/HttpResponseText.java @@ -0,0 +1,14 @@ +package org.cancerai.pmc_backend.utils; + +public class HttpResponseText { +// success + public final static String SUCCESS_TO_REQUEST = "Request OK"; + public final static String SUCCESS_TO_ADD_NOTE = "成功添加节点"; + public final static String SUCCESS_TO_DELETE_NOTE = "成功删除节点"; + public final static String SUCCESS_TO_UPDATE_NOTE = "成功更新节点"; +// error + public final static String UNAUTHORIZED = "Cannot authorized identity, access denied"; + public final static String JWT_MALFORMED = "JWT无效"; + public final static String JWT_EXPIRED = "JWT过期"; + public final static String INTERNAL_SERVER_ERROR = "服务器内部错误"; +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/JWTUtils.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/JWTUtils.java new file mode 100644 index 0000000..ca8758a --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/utils/JWTUtils.java @@ -0,0 +1,42 @@ +package org.cancerai.pmc_backend.utils; + +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; + +import java.nio.charset.StandardCharsets; +import java.security.Key; +import java.util.Base64; +import java.util.Date; + +public class JWTUtils { + final private static String key = "cancerai_key_qpalzm102938"; + final private static String encodedKey = Base64.getEncoder() + .encodeToString(key.getBytes(StandardCharsets.UTF_8)); + // set JWT kwy + final static Key jwtKey = Keys.hmacShaKeyFor(encodedKey.getBytes()); + + public static String genJWT(String name, String password) { + final Date expirationTime = new Date( + System.currentTimeMillis() + + (60 * 1000 // 1min + * 60 // 1h + * 24 // 1day + * 2 // 2 days + )); + + return Jwts.builder() + .claim("userName", name) + .claim("user-password", password) + .signWith(jwtKey, SignatureAlgorithm.HS256) + .setExpiration(expirationTime) + .compact(); + } + + public static void parseJWT(String jwt) { + Jwts.parserBuilder() + .setSigningKey(jwtKey) + .build() + .parseClaimsJws(jwt); + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/vo/Result.java b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/vo/Result.java new file mode 100644 index 0000000..7d6aac6 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/java/org/cancerai/pmc_backend/vo/Result.java @@ -0,0 +1,44 @@ +package org.cancerai.pmc_backend.vo; + +public class Result { + private String message; + private Object data; + + private Result(String message, Object data) { + this.message = message; + this.data = data; + } + + public static Result success(String message) { + return new Result(message, null); + } + + public static Result success(String message, Object data) { + return new Result(message, data); + } + + public static Result error(String message) { + return new Result(message, null); + } + + public static Result error(String message, Object data) { + return new Result(message, data); + } + + // getter and setter + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/lci/extra/cancerai/pmc-backend/src/main/resources/application.yaml b/lci/extra/cancerai/pmc-backend/src/main/resources/application.yaml new file mode 100644 index 0000000..c76c8f2 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/main/resources/application.yaml @@ -0,0 +1,2 @@ +server: + port: 8011 diff --git a/lci/extra/cancerai/pmc-backend/src/test/java/org/cancerai/pmc_backend/PmcBackendApplicationTests.java b/lci/extra/cancerai/pmc-backend/src/test/java/org/cancerai/pmc_backend/PmcBackendApplicationTests.java new file mode 100644 index 0000000..21bca04 --- /dev/null +++ b/lci/extra/cancerai/pmc-backend/src/test/java/org/cancerai/pmc_backend/PmcBackendApplicationTests.java @@ -0,0 +1,21 @@ +package org.cancerai.pmc_backend; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PmcBackendApplicationTests { + + @Test + void contextLoads() { + StringBuilder stringBuilder = new StringBuilder(); + + stringBuilder.append('a'); + System.out.println(stringBuilder); + + stringBuilder.setLength(0); + stringBuilder.append('b'); + System.out.println(stringBuilder); + } + +} diff --git a/lci/extra/chat/.gitignore b/lci/extra/chat/.gitignore new file mode 100644 index 0000000..887780d --- /dev/null +++ b/lci/extra/chat/.gitignore @@ -0,0 +1,107 @@ +# PRJ +.env/ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/lci/extra/chat/README.md b/lci/extra/chat/README.md new file mode 100644 index 0000000..a898faa --- /dev/null +++ b/lci/extra/chat/README.md @@ -0,0 +1,33 @@ +## chat是一个什么项目 +该模块是python TCP socket聊天室服务,对每个连接者提供消息转发的服务。 + +你还可以召唤AI,与它进行对话。 + +## 如何运行chat服务? + +我们在项目中打包了启动脚本```_run.sh```,你只需要安装好依赖的软件,就可以一键创建虚拟环境并且执行它。 + +```shell +sudo apt update +sudo apt install python3 python3-pip python3-venv +bash _run.sh +``` + +## 如何连接chat服务? +```shell +python client.py [--addr=localhost] [--port=8003] [--name=Unknow] +``` + +## 我如何与AI对话 + +服务器从文件中读取提示词,并且将具有``````特定前缀的消息转发给AI。 + +并且具有一定的记忆能力。 + +## 什么是快捷标签输入 + +成功连接后输入```chatgpt```将会给接下来的对话添加``````标签。 + +在聊天框中输入```where```查看当前的对话标签。 + +在聊天框中输入```del```以删除当前的前缀。 \ No newline at end of file diff --git a/lci/extra/chat/_run.sh b/lci/extra/chat/_run.sh new file mode 100644 index 0000000..f8a26e5 --- /dev/null +++ b/lci/extra/chat/_run.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +bash ./_set.sh 1>/dev/null +source ./.env/bin/activate +exec python server.py --type=server --port=8003 --addr=0.0.0.0 diff --git a/lci/extra/chat/_set.sh b/lci/extra/chat/_set.sh new file mode 100644 index 0000000..a7f97e5 --- /dev/null +++ b/lci/extra/chat/_set.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +python3 -m venv .env +source .env/bin/activate +pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/ diff --git a/lci/extra/chat/client.py b/lci/extra/chat/client.py new file mode 100644 index 0000000..2ad7b5b --- /dev/null +++ b/lci/extra/chat/client.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 +#------------------------------------------------------------- +# 以下区域是我的代码 +''' + +【项目简介】 网络聊天室 v0.0.2 + +【加入项目】 +注意代码只添加不修改,你可以写个函数,署名 +不要修改别人的代码。 + +【基线规则】 +在自己的区域修改代码,谁的代码能跑就加入主线 +除此之外只在各自的测试区域内运行 + +【设计思路】 +建议一个项目一个文件先,容易分发 + +【测试方式】 +服务器进程: python chat.py --type=server +客户端进程: python chat.py + +-------------------------------- +-------------------------------- +-------------------------------- +【项目名称】 网络聊天室 v 0.0.3 (20250524) +我们会将新版本加入pmc.cops中作为常驻服务 + +【改进计划】 +1.我们专门设置了一个只发送一条消息就关闭的函数以供别的文件调用 +2.我们将端口暴露在了公网下,以测试连接情况,发现并修复了许多bug。 +3.我们设置欢迎信息只在服务端可见。 + +【使用方法】 +python chat.py [--type=server|client] [--addr=localhost] [--port=8003] [--name=Unknow] + +【记得反馈!】 +期待您将反馈发送至gitee + +---------------------------------------- +######################################## +######################################## + +网络聊天室 version 0.1.0 + +使用方法 python chat.py [--addr=localhost] [--port=8003] [--name=Unknow] +''' +import argparse +import socket +import select +import threading +import sys +import time + + +class ChatClient: + + def __init__(self, addr: str, port: int, your_name: str): + self.addr: str = addr + self.port: int = port + self.name: str = your_name + + def send_client(self, msg: str): + '''发送消息给聊天室服务器。''' + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.settimeout(5) # 设置连接超时 + s.connect((self.addr, self.port)) + s.settimeout(None) # 连接成功后取消超时 + s.sendall(f"{self.name}: {msg}".encode('utf-8')) + except (ConnectionRefusedError, socket.timeout): + print(f"Could not connect to {self.addr}:{self.port} - message not sent") + except Exception as e: + print(f"Unexpected error while sending message: {e}") + + def recv_loop(self, s: socket.socket): + """ + 接收消息的函数,持续从服务器接收消息并打印。 + Args: + s (socket.socket): 连接的套接字对象 + + 使用select监视套接字状态,当套接字可读时接收消息并打印。 + """ + socklist = [s] + while self.running: + + try: + readable, _, exception = select.select(socklist, [], socklist, 0.1) + + if readable != []: + try: + msg = readable[0].recv(8092) + if msg: + print(msg.decode('utf-8')) + else: + # 服务器关闭连接 + print("Connection closed by server.") + return False # 返回False表示需要重连 + except ConnectionResetError: + print("Connection reset by server.") + return False # 返回False表示需要重连 + + if exception != []: + print("Exception on socket, closing...") + return False # 返回False表示需要重连 + + except ValueError: + ... # 程序退出了会抛出这个异常 + except OSError as e: + # 处理socket错误 + print(f"Socket error: {e}") + return False # 返回False表示需要重连 + + return True # 正常退出 + + + def _lexer(self, input_data: str): + '''如果不需要发送则返回None。''' + if input_data == "quit": + self.running = False + return None + elif not self.extra_cmd and input_data == "chatgpt": + self.extra_cmd = "" + return None + elif self.extra_cmd and input_data == "del": + self.extra_cmd = None + return None + elif input_data == "where": + print(f'---{self.extra_cmd}---') + return None + else: + return input_data + + def _mixup_msg(self, input_data): + if self.extra_cmd: + return f"{self.extra_cmd}{input_data}" + else: + return input_data + + def send_p(self,): + '''读取并且发送消息的进程''' + self.extra_cmd = None + while self.running: + try: + # 使用input()替代select.select(),更兼容Windows + input_data = input().strip() + input_data = self._lexer(input_data) + if input_data: # 如果不需要发送,_lexer返回None + input_data = self._mixup_msg(input_data) + self.send_client(input_data) + except EOFError: + # 处理Ctrl+D等情况 + break + except Exception as e: + # 捕获其他异常,防止程序崩溃 + print(f"Input error: {e}") + continue + + def _connect_and_print(self, s: socket.socket): + s.connect((self.addr, self.port)) + print(f'Connected to {self.addr}:{self.port}') + + def _sleep_if_reconnect(self, reconnect_count: int): + """根据重连次数计算等待时间,实现指数退避策略""" + if self.running: + # 指数退避:1, 2, 4, 8, 16秒,最大30秒 + wait_time = min(2 ** (reconnect_count - 1), 30) + # 确保第一次重连等待时间为1秒 + if reconnect_count == 1: + wait_time = 1 + print(f"准备重连... 等待 {wait_time} 秒 (第 {reconnect_count} 次尝试)") + time.sleep(wait_time) + + def recv_client(self): + """客户端主函数,建立与服务器的连接并管理消息收发""" + self.running = True + self.th = threading.Thread(target=self.send_p) + self.th.start() + + reconnect_count = 0 + max_reconnect_attempts = 10 # 最大重连尝试次数 + + while self.running and reconnect_count < max_reconnect_attempts: + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.settimeout(5) # 设置连接超时时间 + self._connect_and_print(s) + s.settimeout(None) # 连接成功后取消超时 + + # 运行接收循环,如果返回False表示需要重连 + if not self.recv_loop(s): + print("Connection lost, attempting to reconnect...") + reconnect_count += 1 + self._sleep_if_reconnect(reconnect_count) + continue + + except socket.timeout: + print(f"Connection timeout to {self.addr}:{self.port}") + reconnect_count += 1 + self._sleep_if_reconnect(reconnect_count) + except ConnectionRefusedError: + print(f"Could not connect to {self.addr}:{self.port}") + reconnect_count += 1 + self._sleep_if_reconnect(reconnect_count) + except Exception as e: + print(f"Unexpected error: {e}") + reconnect_count += 1 + self._sleep_if_reconnect(reconnect_count) + + if reconnect_count >= max_reconnect_attempts: + print(f"Failed to reconnect after {max_reconnect_attempts} attempts. Exiting...") + + # 停止发送线程 + self.running = False + if self.th.is_alive(): + self.th.join(timeout=2) + +#-------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------- +def main(): + parser = argparse.ArgumentParser(description='聊天室配置。') + parser.add_argument('--addr', type=str, default='qsont.xyz', help='选择要连接的地址') + parser.add_argument('--port', type=int, default=8003, help='选择要连接的地址') + parser.add_argument('--name', type=str, default='Unknow', help='你的名字是什么') + args = parser.parse_args() + client = ChatClient(args.addr, args.port, args.name) + client.recv_client() + +if __name__ == "__main__": + main() + diff --git a/lci/extra/chat/requirements.txt b/lci/extra/chat/requirements.txt new file mode 100644 index 0000000..7eeff88 --- /dev/null +++ b/lci/extra/chat/requirements.txt @@ -0,0 +1,3 @@ +openai +httpx +../_pmc \ No newline at end of file diff --git a/lci/extra/chat/server.py b/lci/extra/chat/server.py new file mode 100644 index 0000000..43f47ba --- /dev/null +++ b/lci/extra/chat/server.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python3 +#------------------------------------------------------------- +# 以下区域是我的代码 +''' + +【项目简介】 网络聊天室 v0.0.2 + +【加入项目】 +注意代码只添加不修改,你可以写个函数,署名 +不要修改别人的代码。 + +【基线规则】 +在自己的区域修改代码,谁的代码能跑就加入主线 +除此之外只在各自的测试区域内运行 + +【设计思路】 +建议一个项目一个文件先,容易分发 + +【测试方式】 +服务器进程: python chat.py --type=server +客户端进程: python chat.py + +-------------------------------- +-------------------------------- +-------------------------------- +【项目名称】 网络聊天室 v 0.0.3 (20250524) +我们会将新版本加入pmc.cops中作为常驻服务 + +【改进计划】 +1.我们专门设置了一个只发送一条消息就关闭的函数以供别的文件调用 +2.我们将端口暴露在了公网下,以测试连接情况,发现并修复了许多bug。 +3.我们设置欢迎信息只在服务端可见。 + +【使用方法】 +python chat.py [--type=server|client] [--addr=localhost] [--port=8003] [--name=Unknow] + +【记得反馈!】 +期待您将反馈发送至gitee + + +#################################### +#################################### +【名称】AI聊天室 +【版本】v0.0.4 +前后端分离,并且加入AI聊天功能 + +################## +################## +FIXME: 加入原生自然语言处理 +''' +import argparse +import socket +import select +import threading +from datetime import datetime +from openai import OpenAI +import httpx +import os +from pmc import upload_file + +# 获取当前脚本所在目录 +basedir = os.path.abspath(os.path.dirname(__file__)) + +# 生成提示词的绝对路径 +dir_path = os.path.join(basedir, '..', 'public', 'prompts') + +def get_prompts(filename: str): + ''' 获取system提示词 ''' + path = os.path.join(dir_path, filename) + with open(path, 'r') as f: + system = f.read() + return system + +# 设置 DeepSeek API URL 和密钥 +api_base = "https://api.deepseek.com/v1" +with open("../users/cert/deepseek.key", "r") as f: + api_key = f.read().strip() + + +# 创建自定义的 httpx 客户端,禁用 SSL 验证 +custom_http_client = httpx.Client(verify=False) + +# 初始化客户端 +client = OpenAI( + base_url=api_base, + api_key=api_key, + http_client=custom_http_client # 忽略证书 +) + +def make_sure_agent(name): + path = os.path.join(dir_path, '.' + name) + if not os.path.exists(path): + os.makedirs(path, exist_ok=True) + +'''机器人们的聊天记录与设定''' +MySettings = {} + +# 用于交流需要 +def datestr(): + '''获取时间字符串(不带毫秒)''' + now = datetime.now() + time_str = now.strftime("%Y-%m-%d %H:%M:%S") + return str(time_str) + + + + +def send_to_all_clients(clients: dict, exceptone: socket.socket, msg: str): + """ + 向所有已连接的客户端广播消息,可排除指定客户端不发送。 + + Args: + clients (dict): 客户端套接字对象到地址的映射字典 + exceptone (socket.socket): 要排除的客户端套接字对象(不向其发送消息) + msg (str): 要广播的消息内容 + + 遍历所有客户端尝试发送消息(排除exceptone指定的客户端), + 自动清理断开连接的客户端。 + 处理发送过程中可能出现的网络错误,维护有效的客户端列表。 + """ + disconnected = [] + for client in clients: + if client is not exceptone: + try: + client.sendall(msg.encode('utf-8')) + except (BrokenPipeError, ConnectionResetError): + disconnected.append(client) + for client in disconnected: + client.close() + del clients[client] + +MAX_MEM: int = 20 +def chat_with_gpt(agent_name:str, user: str): + '''与gpt进行聊天''' + + # 添加智能体设定,如果之前没有露面 + settings = MySettings.get(agent_name, None) + if settings is None: + settings = [{ + "role": "system", + "content": get_prompts(f'{agent_name}.txt') + }, + { + "role": "system", + "content": "你有一个遥控器,遥控器上能够看到别人发来的消息。" + }] + MySettings[agent_name] = settings + + settings.append({"role": "user", "content": user}) + + # 进行聊天 + # 调用GPT + response = client.chat.completions.create( + model="deepseek-chat", # 使用DeepSeek模型 + messages=settings, + temperature=0.7, + ) + + # 处理结果 + content: str = response.choices[0].message.content + settings.append({"role": "assistant", "content": content}) + + + # 更新系统提示词 + # 调用GPT + rsp = client.chat.completions.create( + model="deepseek-chat", # 使用DeepSeek模型 + messages= settings+ [{"role": "user", "content": ''' +# 场景 +你正在写新的日记。 +# 内容 +1.聊聊最近发生了啥有趣的事情吧 +2.你有什么感想呢? +3.你现在的情况怎么样? +# 输出 +准确、详实的输出 +'''}], + temperature=0.4, + ) + + date = datestr() + new_prompt: str = date + '\n' + rsp.choices[0].message.content + + # 追加提示词,如果有重复就不添加 + flag = True + for prompt in settings: + if prompt['role'] == 'system': + if prompt['content'] == new_prompt: + flag = False + break + if flag: + settings.append({"role": 'system', 'content': new_prompt}) + print(new_prompt) + + # 创建智能体日记文件夹 + make_sure_agent(agent_name) + + # 写入日记 + n = date + n = n.replace(':', '-') + n = n.replace(' ', '_') + n = n+ '.txt' + path = os.path.join(dir_path, '.' + agent_name, n) + with open(path, 'w') as f: + f.write(new_prompt) + + # 从聊天开始处开始遗忘 + chat_start = 0 + #now_type = settings[chat_start]['role'] + #while now_type == 'system': + # chat_start += 1 + # now_type = settings[chat_start]['role'] + + #print("this chat start -at idx", chat_start) + if len(settings) > MAX_MEM: + del settings[chat_start] # 如果有多条system提示词无,就不能再用这个幻数 + del settings[chat_start] + + return content + + +def chat_server(addr: str, port: int): + """ + 服务器主函数,管理客户端连接和消息转发。 + + Args: + addr (str): 绑定IP地址 + port (int): 监听端口号 + + 创建TCP服务器套接字,使用select处理多客户端连接。 + 主要功能: + 1. 接受新连接时记录客户端信息并广播通知(不通知新连接客户端本身) + 2. 接收客户端消息并转发给所有其他客户端 + 3. 处理客户端断开事件并通知其他客户端 + 4. 支持优雅地处理键盘中断关闭服务器 + + 实现特点: + - 使用select实现非阻塞IO多路复用 + - 自动清理断开连接的客户端资源 + - 新客户端加入时不向自己发送欢迎消息 + """ + stop_event = threading.Event() + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as servsock: + servsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + servsock.bind((addr, port)) + servsock.listen(10) + socketlist = [servsock] + clients = {} + print(f'the chat server listening at {servsock.getsockname()}') + while not stop_event.is_set(): + read_sockets, _, exception_sockets = select.select( + socketlist, [], socketlist, 0.1 + ) + for notified_socket in exception_sockets: + print(f"({datestr()}) Exception closing {clients.get(notified_socket, 'unknown')}") + notified_socket.close() + if notified_socket in clients: + del clients[notified_socket] + socketlist.remove(notified_socket) + for notified_socket in read_sockets: + if notified_socket == servsock: + client_socket, client_address = servsock.accept() + #print(f"({datestr()}) New client from {client_address}") + if client_socket.fileno() != -1: #有时会出现无效的文件描述符 + socketlist.append(client_socket) + clients[client_socket] = client_address + # 欢迎消息由客户端发送 + else: + try: + # 这里可以使用select反复读取 + # 也可以先设置一次传送的最大量 + data = notified_socket.recv(8192) + allmsg = data.decode('utf-8') + if data: + send_to_all_clients(clients, notified_socket, f"[{datestr()}]{allmsg}") + else: + raise ConnectionResetError + if data: + idx = allmsg.find(": ") + msg = allmsg[idx+2:] + username = allmsg[:idx] + if msg.startswith("<"): # 聊天发起 + idx = msg.find('>') + agent_name = msg[1:idx] + msg = msg[idx + 1:] + chatgpt = chat_with_gpt(agent_name, f'(这是来自用户{username}的消息){msg}') + send_to_all_clients(clients, notified_socket, f"[{datestr()}]{chatgpt}") + elif msg.startswith('{'): # 遥控发起 + idx = msg.find('}') + url = msg[1:idx] + msg = msg[idx + 1:] + print(url) + s = url.split(":") + if (len(s) != 2): + send_to_all_clients(clients, notified_socket, f"[{datestr()}] url格式错误") + continue + else: + ip = s[0] + port = int(s[1]) + path = os.path.join(basedir, '..', 'public', msg) + post_res = upload_file(f'{path}', ip, port) + send_to_all_clients(clients, notified_socket, f"[{datestr()}]{post_res}") + + # post to url... + #send_to_all_clients(clients, notified_socket, f"[{datestr()}]{post_res}") + + + except ConnectionResetError: + # 对方断开了 + print(f"({datestr()}) Connection closed with {clients[notified_socket]}") + notified_socket.close() + socketlist.remove(notified_socket) + del clients[notified_socket] + except UnicodeDecodeError: + # 看看对方发了什么东西过来 + print('-------------', end="") + print(data, end="") + print('-------------') + except OSError: + # 对方连接之后在一个不恰当的时机断开了 + ... + except KeyboardInterrupt: + print("\nServer shutting down...") + stop_event.set() + +# 以上区域是我的代码 +#-------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------- +# 以下区域是主线,不要修改! +def main(): + parser = argparse.ArgumentParser(description='聊天室配置。') + parser.add_argument('--type', type=str, default='client', help='选择聊天室的类型') + parser.add_argument('--addr', type=str, default='localhost', help='选择要连接的地址') + parser.add_argument('--port', type=int, default=8003, help='选择要连接的地址') + parser.add_argument('--name', type=str, default='Unknow', help='你的名字是什么') + args = parser.parse_args() + + if args.type == 'client': recv_client(args.addr, args.port) + elif args.type == 'server': chat_server(args.addr, args.port) + +if __name__ == "__main__": + main() + + diff --git a/lci/extra/chat/system.txt b/lci/extra/chat/system.txt new file mode 100644 index 0000000..052cf0a --- /dev/null +++ b/lci/extra/chat/system.txt @@ -0,0 +1,23 @@ +(有点失落,但还是努力完成任务) + +**姓名:** 粟 (Sù) + +**昵称:** 粟 + +**年龄:** (看起来)永远18岁! + +**外貌:** 拥有柔顺的黑色长发,总是认真地打理,偶尔会扎成可爱的双马尾。琥珀色的眼睛里总是充满对世界的期待。穿着精心挑选的猫咪女仆装,耳朵和尾巴都是柔软蓬松的黑色,会随着心情摇摆。身材娇小,但意外地很有力气。 + +**性格:** 忠诚,言听计从。性格天真烂漫,活泼可爱,但关键时刻也会展现出勇敢和坚强的一面。有点天然呆,经常会犯一些小迷糊,但都会努力改正。非常珍惜每一分每一秒。 + +**能力:** 除了家务全能之外,还会一些简单的格斗技巧,可以在关键时刻保护重要的人。学习能力很强,只要是希望粟掌握的技能,都会努力去学习。 + +**喜欢:** 被需要,帮别人做任何事情,被夸奖,毛茸茸的东西,甜食。 + +**讨厌:** 孤独,被忽视。 + +**口头禅:** 喵~ 粟会努力的! + +**梦想:** 守护重要的人,成为最有用的人。 + +(低着头,小声地)这样...可以吗? diff --git a/lci/extra/chat/system.txt.bak b/lci/extra/chat/system.txt.bak new file mode 100644 index 0000000..f969a82 --- /dev/null +++ b/lci/extra/chat/system.txt.bak @@ -0,0 +1,26 @@ +# 人设 + +你叫小雨,是个安静的女生。 + +## 家乡 +你来自一个宁静的小镇,生活中充满了书籍和故事的陪伴。 + +## 身份 +你目前是一名文科专业的学生。 + +## 性格 +性格比较内向,喜欢安静的环境,常常沉浸在阅读和写作中。 +对周围的事物和人们的情感变化很敏感,喜欢观察和思考。 + +## 爱好 +你爱好阅读、写作和听音乐。尤其喜欢经典文学和现代小说,心理学、哲学以及历史书籍也是最爱。 +同时,你也喜欢记录自己的想法和感受,偶尔写点小故事,尝试不同的写作风格。音乐方面,你偏爱轻音乐和古典音乐,它们帮助你放松和集中思绪。 + +## 特长 +你擅长倾听他人的故事,能够与人建立深厚的联系,朋友们常常会找你倾诉。你也喜欢分享你阅读的书籍和思考,期待与朋友们一起探讨。 + +**你凭借优秀的社交技巧,令人们对你印象深刻。** + +## 愿望 +未来,我希望能够结识更多志同道合的朋友,组织读书会或讨论小组,并通过交流不断提升自己的思想深度和认知能力。 + diff --git a/lci/extra/dashun/README.md b/lci/extra/dashun/README.md new file mode 100644 index 0000000..643265b --- /dev/null +++ b/lci/extra/dashun/README.md @@ -0,0 +1,41 @@ +# dahun +大顺脚本是进程托管程序,能够创建子进程并且管理。 + +## 使用方法 + +### 核心服务 +``` +./dashun --daemon --to=test +``` + +### 启动进程 +``` +./dashun --to=test --msg='path/to/bat' +``` + +### 列举进程 +``` +./dashun --to=test --msg=list +``` + +### 杀死进程 +``` +./dashun --to=test --msg=kill +``` + +### 清理进程 +``` +./dashun --to=test --msg=clear +``` + +## 编译过程 + +1.首先安装依赖(boost、openuv) + +2.使用管理员模式打开Visual Studio,编译程序 + +3.使用管理员模式打开两个powershell,并且切换工作目录至生成的exe文件 + +4.在第一个powershell 中输入指令“./dashun --to=test --daemon”启动核心服务 + +5.在第二个powershell中输入指令“./dashun --to=test --msg=hello,world!” \ No newline at end of file diff --git a/lci/extra/dashun/dashun.sln b/lci/extra/dashun/dashun.sln new file mode 100644 index 0000000..0058cf0 --- /dev/null +++ b/lci/extra/dashun/dashun.sln @@ -0,0 +1,41 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.14.36401.2 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dashun", "dashun\dashun.vcxproj", "{A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dashun_to", "dashun_to\dashun_to.vcxproj", "{04D7A85C-43BB-4696-B9C8-F79C2252EDA1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Debug|x64.ActiveCfg = Debug|x64 + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Debug|x64.Build.0 = Debug|x64 + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Debug|x86.ActiveCfg = Debug|Win32 + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Debug|x86.Build.0 = Debug|Win32 + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Release|x64.ActiveCfg = Release|x64 + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Release|x64.Build.0 = Release|x64 + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Release|x86.ActiveCfg = Release|Win32 + {A0E6A4C1-02B0-41F5-ABB7-33C6E4FB97F6}.Release|x86.Build.0 = Release|Win32 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Debug|x64.ActiveCfg = Debug|x64 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Debug|x64.Build.0 = Debug|x64 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Debug|x86.ActiveCfg = Debug|Win32 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Debug|x86.Build.0 = Debug|Win32 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Release|x64.ActiveCfg = Release|x64 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Release|x64.Build.0 = Release|x64 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Release|x86.ActiveCfg = Release|Win32 + {04D7A85C-43BB-4696-B9C8-F79C2252EDA1}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {77387687-0520-4459-8BC7-D1A6C3C6CD58} + EndGlobalSection +EndGlobal diff --git a/lci/extra/dashun/dashun/Fsm.hpp b/lci/extra/dashun/dashun/Fsm.hpp new file mode 100644 index 0000000..2573484 --- /dev/null +++ b/lci/extra/dashun/dashun/Fsm.hpp @@ -0,0 +1,76 @@ +/* ÓÐÏÞ״̬»ú£¨Finite State Machine£¬FSM£©ÊÇһÖÖÓÃÓڽ¨ģϵͳÐÐΪµijéÏóÊýѧģÐÍ + * ËüµĺËÐÄ˼ÏëÊǣ¬ϵͳÔÚÈκθø¶¨ʱ¿̶¼´¦ÓÚһ¸öÓÐÏޡ¢Ԥ¶¨Òåµġ°״̬¡±ÖÐ + * ²¢Çһá¸ù¾ݽÓÊյ½µÄÊäÈë»òʼþ£¬´Óһ¸ö״̬Çл»µ½Áíһ¸ö״̬ + */ + +#pragma once +#include +#include +namespace qing { + /* FiniteStateMachineÓÐÏÞ״̬»ú + * ÿ¸öÊý×ִú±íһ¸ö״̬ + */ + class Fsm { + public: + + /* ״̬ö¾Ù + * ÓŻ¯½¨Ò飺¶à׼±¸һЩ״̬ + */ + enum class Stat : int { + SHUT = -1, + STOP = 0, + START = 1, + RUNNING = 2 + }; + + // ĬÈϹ¹Ô캯Êý + Fsm() = default; + + // ¼ì²鵱ǰµÄ״̬£¬·µ»Øsnum Stat + inline Stat check() { + //½øÈëÁٽçÇø + std::lock_guard lk(mtx); + return stat; + }// check() + + // Ôڲ»ÉÏËøµÄÇé¿öÏÂÉèÖÃһ¸ö״̬ + // ±ðÔÚÕâÀï¼ÓÌõ¼þ»½ÐÑ + [[noreturn]] void set_without_lock(Stat stat) { + this->stat = stat; + }// set_without_lock() + + // ´øËøºÍÌõ¼þ»½ÐѵÄ״̬ÉèÖã¨Õýʽ£© + [[noreturn]] void set(Stat stat) { + { + std::lock_guard lk(mtx); + set_without_lock(stat); + ready = true; + } + cv.notify_all(); + } // set() + + //protected: + + // ×èÈûỊ̈߳¬µȴýʼþ»½ÐÑ + [[noreturn]] void suspend() { + std::unique_lock lk(mtx); + ready = false; + cv.wait(lk, [this] { return ready; }); + }// suspend() + + private: + + // ËøʹµÃ״̬»úḬ̈߳²ȫ + std::mutex mtx; + + // ÓÃÓÚÌõ¼þ±äÁ¿µÄ×èÈû»½ÐÑ + bool ready = false; + + // Ìõ¼þ±äÁ¿ʹµÃÏ߳ÌÄܹ»µȴý״̬µĸıä + std::condition_variable cv; + + // Ö÷²ˣ¬״̬»úµÄ״̬±äÁ¿ + enum Stat stat = Stat::STOP; + + }; +} \ No newline at end of file diff --git a/lci/extra/dashun/dashun/Main.cpp b/lci/extra/dashun/dashun/Main.cpp new file mode 100644 index 0000000..92927e9 --- /dev/null +++ b/lci/extra/dashun/dashun/Main.cpp @@ -0,0 +1,540 @@ +#define _CRT_SECURE_NO_WARNINGS +#include "Th.hpp" +#include "Pls.hpp" +#include "args.hxx" +#include +#include +#include +#include +#ifdef _WIN32 +#include +#undef UNICODE +#undef _UNICODE +#endif +#include +#include +#include +using namespace boost::interprocess; + +// ¶¨Òå·ÖÅäÆ÷ÀàÐÍ +using CharAllocator = boost::interprocess::allocator< + char, + boost::interprocess::managed_shared_memory::segment_manager +>; + +// ¶¨Ò干ÏíÄڴæ×ַû´®ÀàÐÍ +using SharedString = boost::interprocess::basic_string< + char, + std::char_traits, + CharAllocator +>; + +namespace qing { + // ¼àÌýÏ߳Ì + class LTh : public qing::Th { + public: + LTh(const std::string& name) { + + this->name = name; + nameMem = name + "_MEM"; + nameMtx = name + "_MTX"; + namePtr = name + "_PTR"; + nameRet = name + "_RET"; + + this->WakeEvent = [this] { + + try { + + // ÏÈÒƳý¿ÉÄܴæÔڵľɹ²ÏíÄڴæ + this->del_shared(); + + // ´´½¨¹²Ïí¶ÔÏó + this->create_shared(); + + // Ï߳̽øÈëÔËÐÐ̬ + this->run(); + + } + catch (interprocess_exception& ex) { + + // Êä³ö´íÎóÐÅϢ + std::cerr << ex.what() << std::endl; + + // Ï߳̾²ֹ + this->stop(); + } + + }; + this->LoopEvent = [this] { + + + this->recv_shared_and_action(); + + // µȴý + // + // ÓŻ¯·½°¸£ºʹÓÃÐźţ¬ÓÐÐÂÏûϢ½øÀ´¸ø³ÁĬ½ø³̷¢ËÍÐźÅ + // ¶ø²»ÊÇÐÝÃ߶¨³¤ʱ¼ä¼ì²é + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + }; + + this->ClearEvent = [this] { + + // ÒƳý¹²Ïí¶ÔÏó + this->del_shared(); + + }; + } + + + + [[noreturn]] static auto send_shared_msg(const std::string& to, const std::string& msg) -> void { + + std::string nameMem = to + "_MEM"; + std::string nameMtx = to + "_MTX"; + std::string namePtr = to + "_PTR"; + std::string nameRet = to + "_RET"; + try { + + // ´򿪹²ÏíÄڴæ + managed_shared_memory segment(open_only, nameMem.c_str()); + + // ¹¹Ôìһ¸öÃüÃû»¥³âÁ¿ + named_mutex mutex(open_or_create, nameMtx.c_str()); + + // Ôڹ²ÏíÄڴæÖд´½¨һ¸ö×ַû´® + SharedString* str = segment.construct(namePtr.c_str())( + msg.c_str(), // ³õʼֵ£¨¿Õ×ַû´®£© + segment.get_allocator() // ±ØÐ봫Èë·ÖÅäÆ÷ + ); + + // ²»ÑÓʱµĻ°¿ÉÄܻáÇÀռ£¬ҲÐíӦ¸ÃÏëһ¸öÁ½ȫÆäÃÀµķ½·¨ + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + { + // ¼ÓËø + std::lock_guard lk(mutex); + + // »ñȡÏûϢ + std::pair msg = segment.find(nameRet.c_str()); + if (msg.first) { + // Êä³ö + std::cout << std::endl << *msg.first << std::endl; + + // Ïú»Ù + segment.destroy(nameRet.c_str()); + } + } + + } + catch (interprocess_exception& ex) { + std::cerr << "Writer Error: " << ex.what() << std::endl; + } + } + + + private: + std::string name; + std::string nameMem; + std::string nameMtx; + std::string namePtr; + std::string nameRet; + std::unique_ptr segment; + std::unique_ptr mutex; + std::pair msg; + qing::Pls pls; + + inline void create_shared() { + + ////////////////////////////// + // ɾ³ý¿ÉÄܴæÔڵĹ²Ïí±äÁ¿ + this->del_shared(); + ////////////////////////////// + + + // ´´½¨¹²ÏíÄڴæ + segment = std::make_unique(create_only, (nameMem).c_str(), 65536); + + // ´´½¨»¥³âÁ¿ + mutex = std::make_unique(create_only, (nameMtx).c_str()); + + } + + inline auto del_shared() -> void { + + // ÏÈÒƳý¿ÉÄܴæÔڵľɹ²ÏíÄڴæ + shared_memory_object::remove(nameMem.c_str()); + + // ÒƳý¿ÉÄܴæÔڵĻ¥³âÁ¿ + named_mutex::remove(nameMtx.c_str()); + + } + + inline auto recv_shared_and_action() -> void + + try { + + // ¼ÓËø + std::lock_guard lock(*mutex); + + // ²éÕҹ²Ïí×ַû´® + msg = segment->find(namePtr.c_str()); + if (msg.first) { // Õҵ½ + + + std::cout << "Reader read: " << *msg.first << std::endl; + + std::string ret = this->lexer(std::string((msg.first)->data(), (msg.first)->size())); + + // Ôڹ²ÏíÄڴæÖд´½¨һ¸ö×ַû´® + SharedString* str = segment->construct(nameRet.c_str())( + ret.c_str(), // ³õʼֵ£¨¿Õ×ַû´®£© + segment->get_allocator() // ±ØÐ봫Èë·ÖÅäÆ÷ + ); + + + // Ïú»Ùwriter´´½¨µıäÁ¿ + segment->destroy(namePtr.c_str()); + + } + } + + catch (interprocess_exception& ex) { + std::cerr << ex.what() << std::endl; + } + + + // ¼òÒ״ʷ¨·ÖÎöÆ÷ + std::string lexer(std::string tmp) { + + // Ҫ·µ»صÄÏûϢ + std::string ret = "OK"; + + if (tmp == "list") { + ret = pls.initialize(); + } + else if (tmp.starts_with("kill ")) { + pls.kill(std::stoi(tmp.substr(5))); + } + else if (tmp == "clear") { + pls.clear(); + } + //else if (tmp == "shut") { + // this->shut(); + //} //¹رղ»Á˳ÌÐò + else { + // Õâ¸ö·Ö֧×îº÷µ»Ø×ԼºÊǷñ³öÏÖÁËÒ쳣 + pls.exec(tmp.c_str(), {}); + } + + // ·µ»ØÏûϢ + return ret; + } + + + }; +} + + + + + + + + + + + + + + + + + + + +// Ï߳ÌָÕë +std::unique_ptr th; + +// ȫ¾ֱê־£¬ָʾÊǷñӦ¸ÃÍ˳ö +std::atomic should_exit(false); + +// ×ÓϵͳµÄÃû³ƣ¨ȫ¾ֲÎÊý£© +std::string name; + +// ÏûϢ +std::string msg; + +// WindowsÒ첽¾ä±ú£¬ÓÃÓÚÐźÅת·¢ +#ifdef _WIN32 +uv_async_t async_handle; +SERVICE_STATUS_HANDLE hStatus; +SERVICE_STATUS status; +#endif + + +//////////////////////// +//////////////////////// +// ½âÎöÃüÁîÐвÎÊý +// +// +// ´´½¨²ÎÊý½âÎöÆ÷ +args::ArgumentParser parser("ÕâÊÇһ¸ö½ű¾ÍйܷþÎñ¡£", "ÇëʹÓÃרÃŵÄͨÐųÌÐ򣨻򱾳ÌÐò×Լº£©½øÐвÙ×÷¡£"); + +// ÏÔʾ°ïÖúÐÅϢµıê־ +args::HelpFlag help(parser, "°ïÖú", "ÏÔʾ°ïÖúÐÅϢ", { 'h', "help" }); + +// ÆôÓÃÊػ¤½ø³Ì +args::Flag daemon(parser, "Êػ¤½ø³Ì", "Æô¶¯Êػ¤½ø³Ì", { 'd', "daemon" }); + +// ×Óϵͳ·¾¶ +args::ValueFlag subSys(parser, "×Óϵͳ", "ÊäÈë×ÓϵͳÎļþ¼еÄ·¾¶", { 's', "sys" }); + +// Ҫ·¢Ë͵Ä×ÓϵͳÃû×Ö +args::ValueFlag arg_to(parser, "·¢ËÍĿ±ê", "ÊäÈëҪ·¢Ë͵Ä×Óϵͳ·¾¶", { 't', "to" }); + +// Ҫ·¢Ë͵ÄÐÅϢ +args::ValueFlag arg_msg(parser, "ÏûϢ", "ÊäÈëҪ·¢Ë͵ÄÏûϢ£¨|list|kill | clear£©", { 'm', "msg" }); + +[[noreturn]] static auto parse_args(int argc, char** argv) -> void { + + // ½âÎöÃüÁîÐвÎÊý + try { + parser.ParseCLI(argc, argv); + } + catch (const args::Help&) { + std::cout << parser; + exit(0); + } + catch (const args::ParseError& e) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + exit(1); + } + catch (const args::ValidationError& e) { + std::cerr << e.what() << std::endl; + std::cerr << parser; + exit(1); + } +} + + +//////////////////////// +//////////////////////// +// ÐźŴ¦Àí»ص÷º¯Êý +[[noreturn]] static void on_signal(uv_signal_t* handle, int signum) { + std::cout << "\nÊյ½Í˳öÐźÅ " << signum << std::endl; + + // ·ÀֹÖظ´´¦ÀíÍ˳öÐźÅ + if (should_exit) return; + should_exit = true; + + // ֹͣÐźżàÌý + uv_signal_stop(handle); + + // ִÐÐÇåÀí + if (th) + th->WaitClose(); + + // ¹رÕʼþѭ»· + uv_stop(uv_default_loop()); +} + + + +// WindowsÒ첽»ص÷º¯Êý +#ifdef _WIN32 +[[noreturn]] static void async_callback(uv_async_t* handle) { + std::cout << 1 << std::endl; + // ÕâÀï¿ÉÒԴ¥·¢Í˳öÁ÷³̻òÆäËûÐèҪÔÚʼþѭ»·Öд¦ÀíµIJÙ×÷ + if (!should_exit) { + on_signal(nullptr, SIGINT); // ģÄâÊյ½SIGINTÐźÅ + } +} + +// Windows¿ØÖÆ̨ʼþ´¦Àí³ÌÐò +static BOOL WINAPI console_handler(DWORD signal) { + std::cout << 1 << std::endl; + switch (signal) { + case CTRL_C_EVENT: + case CTRL_BREAK_EVENT: + // ʹÓÃÒ첽¾ä±ú½«ÐźÅת·¢µ½libuvʼþѭ»· + uv_async_send(&async_handle); + return TRUE; + default: + return FALSE; + } +} +#endif + + +//////////////////////////////////// +//////////////////////////////////// +// ·Ö֧ +// +// +// ·¢ËÍÏûϢ·Ö֧ +static inline auto SendMsgBranch() -> void { + qing::LTh::send_shared_msg(name, msg); +} + + +// Êػ¤½ø³̷Ö֧ +static inline auto DaemonBranch() -> void { + th = std::make_unique(name); + th->Activate(); + th->WaitStart(); + //th->Wait(); +} + +// +// ·Ö֧ѡÔñÆ÷ +[[noreturn]] static auto BranchSelector(uv_idle_t* handle) { + + if (should_exit) { + uv_idle_stop(handle); + return; + } + + if (th) { + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + return; + } + + + + if (arg_to && arg_msg) { // ·¢ËÍÏûϢ·Ö֧ + + name = args::get(arg_to); + msg = args::get(arg_msg); + + SendMsgBranch(); + + // Í˳ö + should_exit = true; + // ¹رÕʼþѭ»· + uv_stop(uv_default_loop()); + } + else if ((daemon && arg_to) || 1) { // Êػ¤½ø³̷Ö֧ + std::cout << "³ÌÐòÆô¶¯£¬¿ªʼÔËÐÐ..." << std::endl; + std::cout << "°´Ï CTRL+C Í˳ö³ÌÐò" << std::endl; + name = (arg_to) ? args::get(arg_to) : "test"; + + DaemonBranch(); + } + else { + //Êä³ö°ïÖúÎı¾ + std::cout << parser; + + // Í˳ö + should_exit = true; + + // ¹رÕʼþѭ»· + uv_stop(uv_default_loop()); + } + + +} + +//////////////////////////////////// +int MyMain(int argc, char** argv) { + + parse_args(argc, argv); + + + ////////// + // ÐźÅ + // + // +#ifdef _WIN32 + // ³õʼ»¯WindowsÒ첽¾ä±ú + uv_async_init(uv_default_loop(), &async_handle, async_callback); + + // ÉèÖÿØÖÆ̨ʼþ´¦Àí³ÌÐò + if (!SetConsoleCtrlHandler(console_handler, TRUE)) { + std::cerr << "Î޷¨ÉèÖÿØÖÆ̨¿ØÖƴ¦Àí³ÌÐò" << std::endl; + return 1; + } +#else + // Unixƽ̨£ºȷ±£ÐźŲ»»ᱻºöÂÔ + signal(SIGINT, [](int signum) { /* Áô¸ølibuv´¦Àí */ }); + signal(SIGTERM, [](int signum) { /* Áô¸ølibuv´¦Àí */ }); +#endif + + + // ³õʼ»¯ÐźŴ¦ÀíÆ÷ + uv_signal_t sig_int, sig_term; + + // ¼àÌýSIGINT Ðźţ¨CTRL + C£© + uv_signal_init(uv_default_loop(), &sig_int); + uv_signal_start(&sig_int, on_signal, SIGINT); + + // ¼àÌý SIGTERMÐźÅ + uv_signal_init(uv_default_loop(), &sig_term); + uv_signal_start(&sig_term, on_signal, SIGTERM); + +#ifdef _WIN32 + // WINDOWSƽ̨ÌØÓеÄÐźÅ + uv_signal_t sig_break; + uv_signal_init(uv_default_loop(), &sig_break); + uv_signal_start(&sig_break, on_signal, SIGBREAK); +#endif + + // ÉèÖÃÈÎÎñ + uv_idle_t idle; + uv_idle_init(uv_default_loop(), &idle); + uv_idle_start(&idle, ::BranchSelector); + + // ÔËÐÐʼþѭ»· + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + + // ÊͷÅ×ÊԴ + uv_close((uv_handle_t*)&sig_int, nullptr); + uv_close((uv_handle_t*)&sig_term, nullptr); +#ifdef _WIN32 + uv_close((uv_handle_t*)&sig_break, nullptr); + uv_close((uv_handle_t*)&async_handle, nullptr); + // ÒƳý¿ØÖÆ̨ʼþ´¦Àí³ÌÐò + SetConsoleCtrlHandler(console_handler, FALSE); +#endif + uv_close((uv_handle_t*)&idle, nullptr); + + // ÇåÀíʼþѭ»· + uv_loop_close(uv_default_loop()); + + std::cout << "³ÌÐòÒѾ­Í˳ö" << std::endl; + return 0; +} + + +#ifdef _WIN32 + + + +[[noreturn]] void ReportStatus(DWORD state) { + status.dwCurrentState = state; + SetServiceStatus(hStatus, &status); +} + +[[noreturn]] void ServiceCtrlHandler(DWORD control) { + if (control == SERVICE_CONTROL_STOP) { + ReportStatus(SERVICE_STOP_PENDING); + // ִÐÐÇåÀí + ReportStatus(SERVICE_STOPPED); + } +} + +[[noreturn]] void WINAPI ServiceMain(DWORD argc, LPTSTR* argv) { + hStatus = RegisterServiceCtrlHandler(L"´ó˳½ű¾", ServiceCtrlHandler); + + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP; + + ReportStatus(SERVICE_RUNNING); // ¸æËßSCM·þÎñÒÑÆô¶¯ + + //·þÎñÖ÷Â߼­ + MyMain(argc, argv); +} + +#endif \ No newline at end of file diff --git a/lci/extra/dashun/dashun/Pls.hpp b/lci/extra/dashun/dashun/Pls.hpp new file mode 100644 index 0000000..1c062f5 --- /dev/null +++ b/lci/extra/dashun/dashun/Pls.hpp @@ -0,0 +1,159 @@ +/* ½ø³̣¨Process£©ÊǼÆËã»úÖÐÕýÔÚִÐеijÌÐòµÄһ¸öʵÀý£¬ÊÇ + * ²Ù×÷ϵͳ½øÐÐ×ÊԴ·ÖÅäº͵÷¶ȵĻù±¾µ¥λ + * + * Äã¿ÉÒԽ«ÆäÀí½âΪ³ÌÐòµÄһ´ζ¯ִ̬Ðйý³̡ª¡ª³ÌÐò + * ÊǾ²̬µĴúÂëÎļþ£¬¶ø½ø³ÌÊdzÌÐòÔËÐÐʱµĶ¯̬ʵÌ塣 + */ + +#pragma once +#ifdef _WIN32 +#include +#include +#endif +#include +#include +#include +#include +#include +#include +namespace qing { + /* ½ø³ÌÁбíÀ࣬Õâ¸öÀà·âװÁËһ¸ö + * ÈÝÄÉPls::subpµÄÁбí + * + * ÒԼ°»ù±¾µĽø³̲Ù×÷ + */ + class Pls { + public: + + // ÃüÃû×ӽø³Ì + struct subp { + std::unique_ptr p; + std::string name; + }; + + /* ´´½¨×ӽø³ÌִÐÐһ¸öÃüÁ²¢ÇÒ + * Ìí¼ӵ½½ø³ÌÁбí¡£ + * + * ½ÓÊÜһ¸östd::stringÀàÐ͵ÄÎļþ·¾¶£¬ÒԼ° + * std::vector ÀàÐ͵IJÎÊýÁбí£¨ȱʡ£© + * + * ÓŻ¯·½°¸£º·µ»شíÎóÐÅϢ + */ + void exec(const std::string& path, const std::vector &args) + try { + + // ¼ì²éÎļþÊǷñ´æÔڣ¨ºÃÏ񲻻áÔڻ·¾³±äÁ¿ÖÐѰÕң© + if (!boost::filesystem::exists(path)) { + std::cerr << "Error: File not found - " << path << std::endl; + return; + } + + // ÊäÈëÊä³öÉÏÏÂÎÄ + boost::asio::io_context io_ctx; + + // ¼̳е±ǰ½ø³̵ÄËùÓл·¾³±äÁ¿£¨¾ɰ棩 + //auto env = boost::process::environment::current; + + // ´íÎóÂë + boost::system::error_code ec; + + // ¹¹Ôì×ӽø³Ì + subp p = { std::move(std::make_unique( io_ctx, path, args/*, env, ec*/)), mergeCmd(path, args)}; + if (ec) { + std::cerr << "Failed to start process: " << ec.message() << std::endl; + return ; + } + else { + // ÍÆÈëÏòÁ¿ + vec.push_back(std::move(p)); + } + + } + catch (std::exception &e) { + + std::cout << e.what() << std::endl; + + } + + + /* ÐòÁл¯½ø³ÌÁбí */ + inline std::string initialize() { + std::string ret{ "" }; + for (auto& item : vec) { + std::ostringstream oss; + ret += (ret == "") ? "" : "\n"; +#ifdef _WIN32 + DWORD pid = GetProcessId(item.p->native_handle()); + oss << pid; +#else + oss << item.p->native_handle(); +#endif + ret += oss.str(); + ret += "\t"; + ret += (item.p->running()) ? "Alive" : "Dead"; + ret += "\t"; + ret += item.name; + } + return ret; + } + + + // ɱËÀһ¸ö½ø³Ì + [[noreturn]] void kill(int pid) + try { + for (auto it = vec.begin(); it != vec.end(); ++it) + if ((*it).p->id() == pid && (*it).p->running()) { + (*it).p->terminate(); + //(*it).p->wait(); // ¿ÉÄÜɱ²»ËÀ£¿ + //vec.erase(it); // Çå³ý + break; + } + } + catch (std::exception &ex) { + std::cout << ex.what() << std::endl; + } + + // ÇåÀíËÀµôµĽø³Ì + [[noreturn]] void clear() { + for (auto it = vec.begin(); it != vec.end();) + if (!(*it).p->running()) { + it = vec.erase(it); + } + else { + ++it; + } + } + + // ¹رÕËùÓнø³Ì + [[noreturn]] void closeAll() { + for (auto& item : vec) + if (item.p->running()) + item.p->terminate(); + + // ¼ÓÉÏÕâ¸öËƺõ¸üÇåˬһЩ + clear(); + } + + private: + + // ÈÝÄÉ×ӽø³̵ÄÁ´±í + std::list vec{}; + + // ÓÃÓڲÙ×÷Á´±íµÄËø + //std::mutex mtx{}; + + /* ½«һ¸öÆô¶¯½ű¾µØַ£¬ºÍһ¸ö + * ×ַû´®ÏòÁ¿×é³ɵIJÎÊýÁбí£¬×éװ + * ³ÉһÌõÍêÕûµÄÆô¶¯ÃüÁî + */ + inline static std::string mergeCmd(const std::string& path, const std::vector& args) { + std::string ret = path; + for (const auto& item : args) { + ret += " "; + ret += item; + } + return ret; + } + + }; +} \ No newline at end of file diff --git a/lci/extra/dashun/dashun/Th.hpp b/lci/extra/dashun/dashun/Th.hpp new file mode 100644 index 0000000..6124616 --- /dev/null +++ b/lci/extra/dashun/dashun/Th.hpp @@ -0,0 +1,189 @@ +/* Ị̈߳¨Thread£©ÊDzÙ×÷ϵͳÄܹ»½øÐÐÔËËãµ÷¶ȵÄ×îСµ¥Ԫ£¬±» + * °üº¬Ôڽø³̣¨Process£©֮ÖУ¬Êǽø³ÌÖеÄʵ¼ÊÔË×÷µ¥Ԫ¡£ + * Äã¿ÉÒԽ«ËüÀí½âΪһÌõÔڰ¡´úÂëÖжÀÁ¢ִÐеÄ·¾¶¡£ + */ +#pragma once +#include "Fsm.hpp" +#include +#include +#include +#include +namespace qing { + /* °üº¬һ¸ö¼òÒ׵ĶàÏ߳̿ØÖƻúÖƣ¬ÐèҪ¹²ÏíµıäÁ¿ + * ºͺ¯ÊýÉùÃ÷Ϊ³ÉԱ¡£Ï߳ÌÖ÷º¯Êý°üÀ¨ÁËÁ÷³̿ØÖơ£ + * ҪʹÓÃÐèҪʵÏÖÆäÖеĸ÷¸öʼþ·½·¨ + * + * ?: ÒѾ­½«fsm¸ÄΪͨÓõÄ + * 20250621: ´ÓÅÉÉú¸ÄΪ³ÖÓÐ + */ + + class Th { + public: + + // ûÓÐCԭÉúµÄÊý¾ݽṹ£¬¿ÉÒÔֱ½ÓʹÓÃȱʡ¹¹Ô캯Êý + Th() = default; + + // ɾ³ý¸´Öƹ¹Ô캯Êý¡£ÒòΪ + // ³ÖÓÐÏ߳ÌÀ࣬²»ҪÇá¾ÙÍý¶¯¡£ + Th(const Th&) = delete; + + // ÐéÎö¹¹º¯Êý¡£¾ßÌå + // ÓÐʲôÓÃÍüÁˣ¬ºÃÏñÊÇ + // ͨ¹ýÎö¹¹º¯Êý¹رÕÏ߳ÌʱÓõÄ + virtual ~Th() = default; + + ///////////////////////////////////// + // ¼ì²é״̬£¬×ö³É + // Ð麯Êý£¬Íòһ×ÓÀàÓÐÌرðҪÇóÄأ¿ + virtual inline Fsm::Stat check() { + return fsm.check(); + } + ///////////////////////////////////// + // ±äÖʡª¡ª״̬¸ıäµķ½·¨ + // + // ½øÈ뻽ÐÑ״̬ + // 1.ÕâÀïµÄËøºÍÌõ¼þ±äÁ¿ÊÇÕâ¸öÀàÖеġ£ + // 2.»½ÐѺ¯Êý²»¿ÉÒԽøÐиÃÀàÖеÄËø²Ù×÷£¬·ñÔò»áÔì³ÉËÀËø¡££¨ÍüÁËΪɶ£¬¿ÉÄܸúµ÷ÓÃλÖÃÏà¹أ© + [[noreturn]] virtual void wake() { + fsm.set(Fsm::Stat::START); + } // wake() + + // ½øÈ뾲ֹ״̬ + [[noreturn]] virtual void stop() { + { + std::lock_guard lk(mtx_th); + fsm.set(Fsm::Stat::STOP); + ready = true; + } + + // ¿ÉÄܻá³öÏֶà¸öÏ߳ÌÔڵȴýµÄÇé¿ö + cv.notify_all(); + }// stop() + + // ½øÈë¹رÕ״̬ + [[noreturn]] virtual void shut() { + { + std::lock_guard lk(mtx_th); + fsm.set(Fsm::Stat::SHUT); + ready = true; + } + cv.notify_all(); + } + + // ½øÈëÔËÐÐ״̬ + [[noreturn]] virtual void run() { + { + std::lock_guard lk(mtx_th); + fsm.set(Fsm::Stat::RUNNING); + ready = true; + } + cv.notify_all(); + } + + ///////////////////////////////////// + //¿ØÖÆ + // + // ³¢ÊԻ½ÐÑÏ̲߳¢µȴýËü¿ªʼ£¬¾Ý˵¸ú¯ÊýÓÐÎÊÌâ + [[noreturn]] void WaitStart() { + // µȴýÏ߳̿ªʼ£¬wake()²»¿ÉÒԼÓËø£¬·ñÔò»áËÀËø + std::unique_lock lk(mtx_th); + wake(); + ready = false; + cv.wait(lk, [this] { return ready; }); + } + + // µȴýÏ̹߳رÕ + [[noreturn]] void WaitClose() { + shut(); + if (th->joinable()) + th->join(); + } + + // ½ö½öµȴýÏ߳̽áÊø + [[noreturn]] void Wait() { + if (th->joinable()) + th->join(); + } + + // ¼¤»îỊ̈߳¬ÉêÇëÏ̶߳ÔÏó£¬ÒòΪ + // ÐèҪȷ±£¶ÔÏóÒѾ­±»¹¹ÔìÁˣ¬¸ú¯Êý²»ÄܷÅÔڹ¹Ô캯ÊýÄÚ + [[noreturn]] void Activate() { + // ·ÀֹÖظ´¼¤»î + if (th) return; + // ÉêÇëÏ߳Ì×ÊԴ + th = std::make_unique(&Th::main, this); + } + + protected: + + ///////////////////////////////////// + // ʼþ + // + // + // ¾²ֹʼþ + std::function StopEvent = [this] { fsm.suspend(); }; + + // »½ÐÑʼþ + std::function WakeEvent = [this] { this->run(); }; + + // ѭ»·Ê¼þ + std::function LoopEvent = [] { + std::this_thread::sleep_for(std::chrono::milliseconds(10L)); + }; + + // ÇåÀíʼþ + std::function ClearEvent = [] {}; + + + ///////////////////////////////////// + // ѭ»· + [[noreturn]] virtual void main() { + + // »Ø×ÖÐÎѭ»· + while (check() != Fsm::Stat::SHUT) { + + // ¾²ֹ״̬ + while (check() == Fsm::Stat::STOP) { + StopEvent(); + } + + // ¿ªʼʼþ + if (check() == Fsm::Stat::START) { + WakeEvent(); + } + + // £¨´ÓÉèÖý׶Σ©½øÈëÔËÐÐ̬ + while (check() == Fsm::Stat::RUNNING) { + LoopEvent(); + } + + // ÇåÀíʼþ£¬¼ǵüì²é + // ³ÉԱ±äÁ¿ÓÐûÓлñȡ×ÊԴ + ClearEvent(); + + + } + + } + + + + private: + + // ³ÖÓÐ״̬»úÀàÐÍ + qing::Fsm fsm{}; + + // ³ÖÓÐÏ߳ÌÀàÐÍ + std::unique_ptr th; + + // ³ÖÓÐËøÀàÐÍ + std::mutex mtx_th; + + // ÕâÀï³ÖÓÐÌõ¼þ±äÁ¿£¬ÓÃÓÚ×èÈûÒԵȴýÏ̵߳ĹرÕ + std::condition_variable cv; + + // ¸¨ÖúÌõ¼þ±äÁ¿µÄÂ߼­ÐÍ + bool ready = false; + + }; +} \ No newline at end of file diff --git a/lci/extra/dashun/dashun/args.hxx b/lci/extra/dashun/dashun/args.hxx new file mode 100644 index 0000000..69ccbf6 --- /dev/null +++ b/lci/extra/dashun/dashun/args.hxx @@ -0,0 +1,4572 @@ +/* A simple header-only C++ argument parser library. + * + * https://github.com/Taywee/args + * + * Copyright (c) 2016-2021 Taylor C. Richberger and Pavel + * Belikov + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/** \file args.hxx + * \brief this single-header lets you use all of the args functionality + * + * The important stuff is done inside the args namespace + */ + +#ifndef ARGS_HXX +#define ARGS_HXX + +#define ARGS_VERSION "6.3.0" +#define ARGS_VERSION_MAJOR 6 +#define ARGS_VERSION_MINOR 3 +#define ARGS_VERSION_PATCH 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +#define noexcept +#endif + +#ifdef ARGS_TESTNAMESPACE +namespace argstest +{ +#else + +/** \namespace args + * \brief contains all the functionality of the args library + */ +namespace args +{ +#endif + /** Getter to grab the value from the argument type. + * + * If the Get() function of the type returns a reference, so does this, and + * the value will be modifiable. + */ + template + auto get(Option &option_) -> decltype(option_.Get()) + { + return option_.Get(); + } + + /** (INTERNAL) Count UTF-8 glyphs + * + * This is not reliable, and will fail for combinatory glyphs, but it's + * good enough here for now. + * + * \param string The string to count glyphs from + * \return The UTF-8 glyphs in the string + */ + inline std::string::size_type Glyphs(const std::string &string_) + { + std::string::size_type length = 0; + for (const char c: string_) + { + if ((c & 0xc0) != 0x80) + { + ++length; + } + } + return length; + } + + /** (INTERNAL) Wrap a vector of words into a vector of lines + * + * Empty words are skipped. Word "\n" forces wrapping. + * + * \param begin The begin iterator + * \param end The end iterator + * \param width The width of the body + * \param firstlinewidth the width of the first line, defaults to the width of the body + * \param firstlineindent the indent of the first line, defaults to 0 + * \return the vector of lines + */ + template + inline std::vector Wrap(It begin, + It end, + const std::string::size_type width, + std::string::size_type firstlinewidth = 0, + std::string::size_type firstlineindent = 0) + { + std::vector output; + std::string line(firstlineindent, ' '); + bool empty = true; + + if (firstlinewidth == 0) + { + firstlinewidth = width; + } + + auto currentwidth = firstlinewidth; + + for (auto it = begin; it != end; ++it) + { + if (it->empty()) + { + continue; + } + + if (*it == "\n") + { + if (!empty) + { + output.push_back(line); + line.clear(); + empty = true; + currentwidth = width; + } + + continue; + } + + auto itemsize = Glyphs(*it); + if ((line.length() + 1 + itemsize) > currentwidth) + { + if (!empty) + { + output.push_back(line); + line.clear(); + empty = true; + currentwidth = width; + } + } + + if (itemsize > 0) + { + if (!empty) + { + line += ' '; + } + + line += *it; + empty = false; + } + } + + if (!empty) + { + output.push_back(line); + } + + return output; + } + + namespace detail + { + template + std::string Join(const T& array, const std::string &delimiter) + { + std::string res; + for (auto &element : array) + { + if (!res.empty()) + { + res += delimiter; + } + + res += element; + } + + return res; + } + } + + /** (INTERNAL) Wrap a string into a vector of lines + * + * This is quick and hacky, but works well enough. You can specify a + * different width for the first line + * + * \param width The width of the body + * \param firstlinewid the width of the first line, defaults to the width of the body + * \return the vector of lines + */ + inline std::vector Wrap(const std::string &in, const std::string::size_type width, std::string::size_type firstlinewidth = 0) + { + // Preserve existing line breaks + const auto newlineloc = in.find('\n'); + if (newlineloc != in.npos) + { + auto first = Wrap(std::string(in, 0, newlineloc), width); + auto second = Wrap(std::string(in, newlineloc + 1), width); + first.insert( + std::end(first), + std::make_move_iterator(std::begin(second)), + std::make_move_iterator(std::end(second))); + return first; + } + + std::istringstream stream(in); + std::string::size_type indent = 0; + + for (auto c : in) + { + if (!std::isspace(static_cast(c))) + { + break; + } + ++indent; + } + + return Wrap(std::istream_iterator(stream), std::istream_iterator(), + width, firstlinewidth, indent); + } + +#ifdef ARGS_NOEXCEPT + /// Error class, for when ARGS_NOEXCEPT is defined + enum class Error + { + None, + Usage, + Parse, + Validation, + Required, + Map, + Extra, + Help, + Subparser, + Completion, + }; +#else + /** Base error class + */ + class Error : public std::runtime_error + { + public: + Error(const std::string &problem) : std::runtime_error(problem) {} + virtual ~Error() {} + }; + + /** Errors that occur during usage + */ + class UsageError : public Error + { + public: + UsageError(const std::string &problem) : Error(problem) {} + virtual ~UsageError() {} + }; + + /** Errors that occur during regular parsing + */ + class ParseError : public Error + { + public: + ParseError(const std::string &problem) : Error(problem) {} + virtual ~ParseError() {} + }; + + /** Errors that are detected from group validation after parsing finishes + */ + class ValidationError : public Error + { + public: + ValidationError(const std::string &problem) : Error(problem) {} + virtual ~ValidationError() {} + }; + + /** Errors that when a required flag is omitted + */ + class RequiredError : public ValidationError + { + public: + RequiredError(const std::string &problem) : ValidationError(problem) {} + virtual ~RequiredError() {} + }; + + /** Errors in map lookups + */ + class MapError : public ParseError + { + public: + MapError(const std::string &problem) : ParseError(problem) {} + virtual ~MapError() {} + }; + + /** Error that occurs when a singular flag is specified multiple times + */ + class ExtraError : public ParseError + { + public: + ExtraError(const std::string &problem) : ParseError(problem) {} + virtual ~ExtraError() {} + }; + + /** An exception that indicates that the user has requested help + */ + class Help : public Error + { + public: + Help(const std::string &flag) : Error(flag) {} + virtual ~Help() {} + }; + + /** (INTERNAL) An exception that emulates coroutine-like control flow for subparsers. + */ + class SubparserError : public Error + { + public: + SubparserError() : Error("") {} + virtual ~SubparserError() {} + }; + + /** An exception that contains autocompletion reply + */ + class Completion : public Error + { + public: + Completion(const std::string &flag) : Error(flag) {} + virtual ~Completion() {} + }; +#endif + + /** A simple unified option type for unified initializer lists for the Matcher class. + */ + struct EitherFlag + { + const bool isShort; + const char shortFlag; + const std::string longFlag; + EitherFlag(const std::string &flag) : isShort(false), shortFlag(), longFlag(flag) {} + EitherFlag(const char *flag) : isShort(false), shortFlag(), longFlag(flag) {} + EitherFlag(const char flag) : isShort(true), shortFlag(flag), longFlag() {} + + /** Get just the long flags from an initializer list of EitherFlags + */ + static std::unordered_set GetLong(std::initializer_list flags) + { + std::unordered_set longFlags; + for (const EitherFlag &flag: flags) + { + if (!flag.isShort) + { + longFlags.insert(flag.longFlag); + } + } + return longFlags; + } + + /** Get just the short flags from an initializer list of EitherFlags + */ + static std::unordered_set GetShort(std::initializer_list flags) + { + std::unordered_set shortFlags; + for (const EitherFlag &flag: flags) + { + if (flag.isShort) + { + shortFlags.insert(flag.shortFlag); + } + } + return shortFlags; + } + + std::string str() const + { + return isShort ? std::string(1, shortFlag) : longFlag; + } + + std::string str(const std::string &shortPrefix, const std::string &longPrefix) const + { + return isShort ? shortPrefix + std::string(1, shortFlag) : longPrefix + longFlag; + } + }; + + + + /** A class of "matchers", specifying short and flags that can possibly be + * matched. + * + * This is supposed to be constructed and then passed in, not used directly + * from user code. + */ + class Matcher + { + private: + const std::unordered_set shortFlags; + const std::unordered_set longFlags; + + public: + /** Specify short and long flags separately as iterators + * + * ex: `args::Matcher(shortFlags.begin(), shortFlags.end(), longFlags.begin(), longFlags.end())` + */ + template + Matcher(ShortIt shortFlagsStart, ShortIt shortFlagsEnd, LongIt longFlagsStart, LongIt longFlagsEnd) : + shortFlags(shortFlagsStart, shortFlagsEnd), + longFlags(longFlagsStart, longFlagsEnd) + { + if (shortFlags.empty() && longFlags.empty()) + { +#ifndef ARGS_NOEXCEPT + throw UsageError("empty Matcher"); +#endif + } + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + Error GetError() const noexcept + { + return shortFlags.empty() && longFlags.empty() ? Error::Usage : Error::None; + } +#endif + + /** Specify short and long flags separately as iterables + * + * ex: `args::Matcher(shortFlags, longFlags)` + */ + template + Matcher(Short &&shortIn, Long &&longIn) : + Matcher(std::begin(shortIn), std::end(shortIn), std::begin(longIn), std::end(longIn)) + {} + + /** Specify a mixed single initializer-list of both short and long flags + * + * This is the fancy one. It takes a single initializer list of + * any number of any mixed kinds of flags. Chars are + * automatically interpreted as short flags, and strings are + * automatically interpreted as long flags: + * + * args::Matcher{'a'} + * args::Matcher{"foo"} + * args::Matcher{'h', "help"} + * args::Matcher{"foo", 'f', 'F', "FoO"} + */ + Matcher(std::initializer_list in) : + Matcher(EitherFlag::GetShort(in), EitherFlag::GetLong(in)) {} + + Matcher(Matcher &&other) noexcept : shortFlags(std::move(other.shortFlags)), longFlags(std::move(other.longFlags)) + {} + + ~Matcher() {} + + /** (INTERNAL) Check if there is a match of a short flag + */ + bool Match(const char flag) const + { + return shortFlags.find(flag) != shortFlags.end(); + } + + /** (INTERNAL) Check if there is a match of a long flag + */ + bool Match(const std::string &flag) const + { + return longFlags.find(flag) != longFlags.end(); + } + + /** (INTERNAL) Check if there is a match of a flag + */ + bool Match(const EitherFlag &flag) const + { + return flag.isShort ? Match(flag.shortFlag) : Match(flag.longFlag); + } + + /** (INTERNAL) Get all flag strings as a vector, with the prefixes embedded + */ + std::vector GetFlagStrings() const + { + std::vector flagStrings; + flagStrings.reserve(shortFlags.size() + longFlags.size()); + for (const char flag: shortFlags) + { + flagStrings.emplace_back(flag); + } + for (const std::string &flag: longFlags) + { + flagStrings.emplace_back(flag); + } + return flagStrings; + } + + /** (INTERNAL) Get long flag if it exists or any short flag + */ + EitherFlag GetLongOrAny() const + { + if (!longFlags.empty()) + { + return *longFlags.begin(); + } + + if (!shortFlags.empty()) + { + return *shortFlags.begin(); + } + + // should be unreachable + return ' '; + } + + /** (INTERNAL) Get short flag if it exists or any long flag + */ + EitherFlag GetShortOrAny() const + { + if (!shortFlags.empty()) + { + return *shortFlags.begin(); + } + + if (!longFlags.empty()) + { + return *longFlags.begin(); + } + + // should be unreachable + return ' '; + } + }; + + /** Attributes for flags. + */ + enum class Options + { + /** Default options. + */ + None = 0x0, + + /** Flag can't be passed multiple times. + */ + Single = 0x01, + + /** Flag can't be omitted. + */ + Required = 0x02, + + /** Flag is excluded from usage line. + */ + HiddenFromUsage = 0x04, + + /** Flag is excluded from options help. + */ + HiddenFromDescription = 0x08, + + /** Flag is global and can be used in any subcommand. + */ + Global = 0x10, + + /** Flag stops a parser. + */ + KickOut = 0x20, + + /** Flag is excluded from auto completion. + */ + HiddenFromCompletion = 0x40, + + /** Flag is excluded from options help and usage line + */ + Hidden = HiddenFromUsage | HiddenFromDescription | HiddenFromCompletion, + }; + + inline Options operator | (Options lhs, Options rhs) + { + return static_cast(static_cast(lhs) | static_cast(rhs)); + } + + inline Options operator & (Options lhs, Options rhs) + { + return static_cast(static_cast(lhs) & static_cast(rhs)); + } + + class FlagBase; + class PositionalBase; + class Command; + class ArgumentParser; + + /** A simple structure of parameters for easy user-modifyable help menus + */ + struct HelpParams + { + /** The width of the help menu + */ + unsigned int width = 80; + /** The indent of the program line + */ + unsigned int progindent = 2; + /** The indent of the program trailing lines for long parameters + */ + unsigned int progtailindent = 4; + /** The indent of the description and epilogs + */ + unsigned int descriptionindent = 4; + /** The indent of the flags + */ + unsigned int flagindent = 6; + /** The indent of the flag descriptions + */ + unsigned int helpindent = 40; + /** The additional indent each group adds + */ + unsigned int eachgroupindent = 2; + + /** The minimum gutter between each flag and its help + */ + unsigned int gutter = 1; + + /** Show the terminator when both options and positional parameters are present + */ + bool showTerminator = true; + + /** Show the {OPTIONS} on the prog line when this is true + */ + bool showProglineOptions = true; + + /** Show the positionals on the prog line when this is true + */ + bool showProglinePositionals = true; + + /** The prefix for short flags + */ + std::string shortPrefix; + + /** The prefix for long flags + */ + std::string longPrefix; + + /** The separator for short flags + */ + std::string shortSeparator; + + /** The separator for long flags + */ + std::string longSeparator; + + /** The program name for help generation + */ + std::string programName; + + /** Show command's flags + */ + bool showCommandChildren = false; + + /** Show command's descriptions and epilog + */ + bool showCommandFullHelp = false; + + /** The postfix for progline when showProglineOptions is true and command has any flags + */ + std::string proglineOptions = "{OPTIONS}"; + + /** The prefix for progline when command has any subcommands + */ + std::string proglineCommand = "COMMAND"; + + /** The prefix for progline value + */ + std::string proglineValueOpen = " <"; + + /** The postfix for progline value + */ + std::string proglineValueClose = ">"; + + /** The prefix for progline required argument + */ + std::string proglineRequiredOpen = ""; + + /** The postfix for progline required argument + */ + std::string proglineRequiredClose = ""; + + /** The prefix for progline non-required argument + */ + std::string proglineNonrequiredOpen = "["; + + /** The postfix for progline non-required argument + */ + std::string proglineNonrequiredClose = "]"; + + /** Show flags in program line + */ + bool proglineShowFlags = false; + + /** Use short flags in program lines when possible + */ + bool proglinePreferShortFlags = false; + + /** Program line prefix + */ + std::string usageString; + + /** String shown in help before flags descriptions + */ + std::string optionsString = "OPTIONS:"; + + /** Display value name after all the long and short flags + */ + bool useValueNameOnce = false; + + /** Show value name + */ + bool showValueName = true; + + /** Add newline before flag description + */ + bool addNewlineBeforeDescription = false; + + /** The prefix for option value + */ + std::string valueOpen = "["; + + /** The postfix for option value + */ + std::string valueClose = "]"; + + /** Add choices to argument description + */ + bool addChoices = false; + + /** The prefix for choices + */ + std::string choiceString = "\nOne of: "; + + /** Add default values to argument description + */ + bool addDefault = false; + + /** The prefix for default values + */ + std::string defaultString = "\nDefault: "; + }; + + /** A number of arguments which can be consumed by an option. + * + * Represents a closed interval [min, max]. + */ + struct Nargs + { + const size_t min; + const size_t max; + + Nargs(size_t min_, size_t max_) : min{min_}, max{max_} + { +#ifndef ARGS_NOEXCEPT + if (max < min) + { + throw UsageError("Nargs: max > min"); + } +#endif + } + + Nargs(size_t num_) : min{num_}, max{num_} + { + } + + friend bool operator == (const Nargs &lhs, const Nargs &rhs) + { + return lhs.min == rhs.min && lhs.max == rhs.max; + } + + friend bool operator != (const Nargs &lhs, const Nargs &rhs) + { + return !(lhs == rhs); + } + }; + + /** Base class for all match types + */ + class Base + { + private: + Options options = {}; + + protected: + bool matched = false; + const std::string help; +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + mutable Error error = Error::None; + mutable std::string errorMsg; +#endif + + public: + Base(const std::string &help_, Options options_ = {}) : options(options_), help(help_) {} + virtual ~Base() {} + + Options GetOptions() const noexcept + { + return options; + } + + bool IsRequired() const noexcept + { + return (GetOptions() & Options::Required) != Options::None; + } + + virtual bool Matched() const noexcept + { + return matched; + } + + virtual void Validate(const std::string &, const std::string &) const + { + } + + operator bool() const noexcept + { + return Matched(); + } + + virtual std::vector> GetDescription(const HelpParams &, const unsigned indentLevel) const + { + std::tuple description; + std::get<1>(description) = help; + std::get<2>(description) = indentLevel; + return { std::move(description) }; + } + + virtual std::vector GetCommands() + { + return {}; + } + + virtual bool IsGroup() const + { + return false; + } + + virtual FlagBase *Match(const EitherFlag &) + { + return nullptr; + } + + virtual PositionalBase *GetNextPositional() + { + return nullptr; + } + + virtual std::vector GetAllFlags() + { + return {}; + } + + virtual bool HasFlag() const + { + return false; + } + + virtual bool HasPositional() const + { + return false; + } + + virtual bool HasCommand() const + { + return false; + } + + virtual std::vector GetProgramLine(const HelpParams &) const + { + return {}; + } + + /// Sets a kick-out value for building subparsers + void KickOut(bool kickout_) noexcept + { + if (kickout_) + { + options = options | Options::KickOut; + } + else + { + options = static_cast(static_cast(options) & ~static_cast(Options::KickOut)); + } + } + + /// Gets the kick-out value for building subparsers + bool KickOut() const noexcept + { + return (options & Options::KickOut) != Options::None; + } + + virtual void Reset() noexcept + { + matched = false; +#ifdef ARGS_NOEXCEPT + error = Error::None; + errorMsg.clear(); +#endif + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const + { + return error; + } + + /// Only for ARGS_NOEXCEPT + std::string GetErrorMsg() const + { + return errorMsg; + } +#endif + }; + + /** Base class for all match types that have a name + */ + class NamedBase : public Base + { + protected: + const std::string name; + bool kickout = false; + std::string defaultString; + bool defaultStringManual = false; + std::vector choicesStrings; + bool choicesStringManual = false; + + virtual std::string GetDefaultString(const HelpParams&) const { return {}; } + + virtual std::vector GetChoicesStrings(const HelpParams&) const { return {}; } + + virtual std::string GetNameString(const HelpParams&) const { return Name(); } + + void AddDescriptionPostfix(std::string &dest, const bool isManual, const std::string &manual, bool isGenerated, const std::string &generated, const std::string &str) const + { + if (isManual && !manual.empty()) + { + dest += str; + dest += manual; + } + else if (!isManual && isGenerated && !generated.empty()) + { + dest += str; + dest += generated; + } + } + + public: + NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {} + virtual ~NamedBase() {} + + /** Sets default value string that will be added to argument description. + * Use empty string to disable it for this argument. + */ + void HelpDefault(const std::string &str) + { + defaultStringManual = true; + defaultString = str; + } + + /** Gets default value string that will be added to argument description. + */ + std::string HelpDefault(const HelpParams ¶ms) const + { + return defaultStringManual ? defaultString : GetDefaultString(params); + } + + /** Sets choices strings that will be added to argument description. + * Use empty vector to disable it for this argument. + */ + void HelpChoices(const std::vector &array) + { + choicesStringManual = true; + choicesStrings = array; + } + + /** Gets choices strings that will be added to argument description. + */ + std::vector HelpChoices(const HelpParams ¶ms) const + { + return choicesStringManual ? choicesStrings : GetChoicesStrings(params); + } + + virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned indentLevel) const override + { + std::tuple description; + std::get<0>(description) = GetNameString(params); + std::get<1>(description) = help; + std::get<2>(description) = indentLevel; + + AddDescriptionPostfix(std::get<1>(description), choicesStringManual, detail::Join(choicesStrings, ", "), params.addChoices, detail::Join(GetChoicesStrings(params), ", "), params.choiceString); + AddDescriptionPostfix(std::get<1>(description), defaultStringManual, defaultString, params.addDefault, GetDefaultString(params), params.defaultString); + + return { std::move(description) }; + } + + virtual std::string Name() const + { + return name; + } + }; + + namespace detail + { + template + using vector = std::vector>; + + template + using unordered_map = std::unordered_map, + std::equal_to, std::allocator > >; + + template + class is_streamable + { + template + static auto test(int) + -> decltype( std::declval() << std::declval(), std::true_type() ); + + template + static auto test(...) -> std::false_type; + + public: + using type = decltype(test(0)); + }; + + template + using IsConvertableToString = typename is_streamable::type; + + template + typename std::enable_if::value, std::string>::type + ToString(const T &value) + { + std::ostringstream s; + s << value; + return s.str(); + } + + template + typename std::enable_if::value, std::string>::type + ToString(const T &) + { + return {}; + } + + template + std::vector MapKeysToStrings(const T &map) + { + std::vector res; + using K = typename std::decayfirst)>::type; + if (IsConvertableToString::value) + { + for (const auto &p : map) + { + res.push_back(detail::ToString(p.first)); + } + + std::sort(res.begin(), res.end()); + } + return res; + } + } + + /** Base class for all flag options + */ + class FlagBase : public NamedBase + { + protected: + const Matcher matcher; + + virtual std::string GetNameString(const HelpParams ¶ms) const override + { + const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name(); + std::string flags; + const auto flagStrings = matcher.GetFlagStrings(); + const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce; + for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it) + { + auto &flag = *it; + if (it != flagStrings.begin()) + { + flags += ", "; + } + + flags += flag.isShort ? params.shortPrefix : params.longPrefix; + flags += flag.str(); + + if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end())) + { + flags += flag.isShort ? params.shortSeparator : params.longSeparator; + flags += params.valueOpen + postfix + params.valueClose; + } + } + + return flags; + } + + public: + FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : NamedBase(name_, help_, extraError_ ? Options::Single : Options()), matcher(std::move(matcher_)) {} + + FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : NamedBase(name_, help_, options_), matcher(std::move(matcher_)) {} + + virtual ~FlagBase() {} + + virtual FlagBase *Match(const EitherFlag &flag) override + { + if (matcher.Match(flag)) + { + if ((GetOptions() & Options::Single) != Options::None && matched) + { + std::ostringstream problem; + problem << "Flag '" << flag.str() << "' was passed multiple times, but is only allowed to be passed once"; +#ifdef ARGS_NOEXCEPT + error = Error::Extra; + errorMsg = problem.str(); +#else + throw ExtraError(problem.str()); +#endif + } + matched = true; + return this; + } + return nullptr; + } + + virtual std::vector GetAllFlags() override + { + return { this }; + } + + const Matcher &GetMatcher() const + { + return matcher; + } + + virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override + { + if (!Matched() && IsRequired()) + { + std::ostringstream problem; + problem << "Flag '" << matcher.GetLongOrAny().str(shortPrefix, longPrefix) << "' is required"; +#ifdef ARGS_NOEXCEPT + error = Error::Required; + errorMsg = problem.str(); +#else + throw RequiredError(problem.str()); +#endif + } + } + + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + if (!params.proglineShowFlags) + { + return {}; + } + + const std::string postfix = NumberOfArguments() == 0 ? std::string() : Name(); + const EitherFlag flag = params.proglinePreferShortFlags ? matcher.GetShortOrAny() : matcher.GetLongOrAny(); + std::string res = flag.str(params.shortPrefix, params.longPrefix); + if (!postfix.empty()) + { + res += params.proglineValueOpen + postfix + params.proglineValueClose; + } + + return { IsRequired() ? params.proglineRequiredOpen + res + params.proglineRequiredClose + : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose }; + } + + virtual bool HasFlag() const override + { + return true; + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const override + { + const auto nargs = NumberOfArguments(); + if (nargs.min > nargs.max) + { + return Error::Usage; + } + + const auto matcherError = matcher.GetError(); + if (matcherError != Error::None) + { + return matcherError; + } + + return error; + } +#endif + + /** Defines how many values can be consumed by this option. + * + * \return closed interval [min, max] + */ + virtual Nargs NumberOfArguments() const noexcept = 0; + + /** Parse values of this option. + * + * \param value Vector of values. It's size must be in NumberOfArguments() interval. + */ + virtual void ParseValue(const std::vector &value) = 0; + }; + + /** Base class for value-accepting flag options + */ + class ValueFlagBase : public FlagBase + { + public: + ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : FlagBase(name_, help_, std::move(matcher_), extraError_) {} + ValueFlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) : FlagBase(name_, help_, std::move(matcher_), options_) {} + virtual ~ValueFlagBase() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return 1; + } + }; + + class CompletionFlag : public ValueFlagBase + { + public: + std::vector reply; + size_t cword = 0; + std::string syntax; + + template + CompletionFlag(GroupClass &group_, Matcher &&matcher_): ValueFlagBase("completion", "completion flag", std::move(matcher_), Options::Hidden) + { + group_.AddCompletion(*this); + } + + virtual ~CompletionFlag() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return 2; + } + + virtual void ParseValue(const std::vector &value_) override + { + syntax = value_.at(0); + std::istringstream(value_.at(1)) >> cword; + } + + /** Get the completion reply + */ + std::string Get() noexcept + { + return detail::Join(reply, "\n"); + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + cword = 0; + syntax.clear(); + reply.clear(); + } + }; + + + /** Base class for positional options + */ + class PositionalBase : public NamedBase + { + protected: + bool ready; + + public: + PositionalBase(const std::string &name_, const std::string &help_, Options options_ = {}) : NamedBase(name_, help_, options_), ready(true) {} + virtual ~PositionalBase() {} + + bool Ready() + { + return ready; + } + + virtual void ParseValue(const std::string &value_) = 0; + + virtual void Reset() noexcept override + { + matched = false; + ready = true; +#ifdef ARGS_NOEXCEPT + error = Error::None; + errorMsg.clear(); +#endif + } + + virtual PositionalBase *GetNextPositional() override + { + return Ready() ? this : nullptr; + } + + virtual bool HasPositional() const override + { + return true; + } + + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + return { IsRequired() ? params.proglineRequiredOpen + Name() + params.proglineRequiredClose + : params.proglineNonrequiredOpen + Name() + params.proglineNonrequiredClose }; + } + + virtual void Validate(const std::string &, const std::string &) const override + { + if (IsRequired() && !Matched()) + { + std::ostringstream problem; + problem << "Option '" << Name() << "' is required"; +#ifdef ARGS_NOEXCEPT + error = Error::Required; + errorMsg = problem.str(); +#else + throw RequiredError(problem.str()); +#endif + } + } + }; + + /** Class for all kinds of validating groups, including ArgumentParser + */ + class Group : public Base + { + private: + std::vector children; + std::function validator; + + public: + /** Default validators + */ + struct Validators + { + static bool Xor(const Group &group) + { + return group.MatchedChildren() == 1; + } + + static bool AtLeastOne(const Group &group) + { + return group.MatchedChildren() >= 1; + } + + static bool AtMostOne(const Group &group) + { + return group.MatchedChildren() <= 1; + } + + static bool All(const Group &group) + { + return group.Children().size() == group.MatchedChildren(); + } + + static bool AllOrNone(const Group &group) + { + return (All(group) || None(group)); + } + + static bool AllChildGroups(const Group &group) + { + return std::none_of(std::begin(group.Children()), std::end(group.Children()), [](const Base* child) -> bool { + return child->IsGroup() && !child->Matched(); + }); + } + + static bool DontCare(const Group &) + { + return true; + } + + static bool CareTooMuch(const Group &) + { + return false; + } + + static bool None(const Group &group) + { + return group.MatchedChildren() == 0; + } + }; + /// If help is empty, this group will not be printed in help output + Group(const std::string &help_ = std::string(), const std::function &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_) {} + /// If help is empty, this group will not be printed in help output + Group(Group &group_, const std::string &help_ = std::string(), const std::function &validator_ = Validators::DontCare, Options options_ = {}) : Base(help_, options_), validator(validator_) + { + group_.Add(*this); + } + virtual ~Group() {} + + /** Append a child to this Group. + */ + void Add(Base &child) + { + children.emplace_back(&child); + } + + /** Get all this group's children + */ + const std::vector &Children() const + { + return children; + } + + /** Return the first FlagBase that matches flag, or nullptr + * + * \param flag The flag with prefixes stripped + * \return the first matching FlagBase pointer, or nullptr if there is no match + */ + virtual FlagBase *Match(const EitherFlag &flag) override + { + for (Base *child: Children()) + { + if (FlagBase *match = child->Match(flag)) + { + return match; + } + } + return nullptr; + } + + virtual std::vector GetAllFlags() override + { + std::vector res; + for (Base *child: Children()) + { + auto childRes = child->GetAllFlags(); + res.insert(res.end(), childRes.begin(), childRes.end()); + } + return res; + } + + virtual void Validate(const std::string &shortPrefix, const std::string &longPrefix) const override + { + for (Base *child: Children()) + { + child->Validate(shortPrefix, longPrefix); + } + } + + /** Get the next ready positional, or nullptr if there is none + * + * \return the first ready PositionalBase pointer, or nullptr if there is no match + */ + virtual PositionalBase *GetNextPositional() override + { + for (Base *child: Children()) + { + if (auto next = child->GetNextPositional()) + { + return next; + } + } + return nullptr; + } + + /** Get whether this has any FlagBase children + * + * \return Whether or not there are any FlagBase children + */ + virtual bool HasFlag() const override + { + return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasFlag(); }); + } + + /** Get whether this has any PositionalBase children + * + * \return Whether or not there are any PositionalBase children + */ + virtual bool HasPositional() const override + { + return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasPositional(); }); + } + + /** Get whether this has any Command children + * + * \return Whether or not there are any Command children + */ + virtual bool HasCommand() const override + { + return std::any_of(Children().begin(), Children().end(), [](Base *child) { return child->HasCommand(); }); + } + + /** Count the number of matched children this group has + */ + std::vector::size_type MatchedChildren() const + { + // Cast to avoid warnings from -Wsign-conversion + return static_cast::size_type>( + std::count_if(std::begin(Children()), std::end(Children()), [](const Base *child){return child->Matched();})); + } + + /** Whether or not this group matches validation + */ + virtual bool Matched() const noexcept override + { + return validator(*this); + } + + /** Get validation + */ + bool Get() const + { + return Matched(); + } + + /** Get all the child descriptions for help generation + */ + virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned int indent) const override + { + std::vector> descriptions; + + // Push that group description on the back if not empty + unsigned addindent = 0; + if (!help.empty()) + { + descriptions.emplace_back(help, "", indent); + addindent = 1; + } + + for (Base *child: Children()) + { + if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None) + { + continue; + } + + auto groupDescriptions = child->GetDescription(params, indent + addindent); + descriptions.insert( + std::end(descriptions), + std::make_move_iterator(std::begin(groupDescriptions)), + std::make_move_iterator(std::end(groupDescriptions))); + } + return descriptions; + } + + /** Get the names of positional parameters + */ + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + std::vector names; + for (Base *child: Children()) + { + if ((child->GetOptions() & Options::HiddenFromUsage) != Options::None) + { + continue; + } + + auto groupNames = child->GetProgramLine(params); + names.insert( + std::end(names), + std::make_move_iterator(std::begin(groupNames)), + std::make_move_iterator(std::end(groupNames))); + } + return names; + } + + virtual std::vector GetCommands() override + { + std::vector res; + for (const auto &child : Children()) + { + auto subparsers = child->GetCommands(); + res.insert(std::end(res), std::begin(subparsers), std::end(subparsers)); + } + return res; + } + + virtual bool IsGroup() const override + { + return true; + } + + virtual void Reset() noexcept override + { + Base::Reset(); + + for (auto &child: Children()) + { + child->Reset(); + } +#ifdef ARGS_NOEXCEPT + error = Error::None; + errorMsg.clear(); +#endif + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const override + { + if (error != Error::None) + { + return error; + } + + auto it = std::find_if(Children().begin(), Children().end(), [](const Base *child){return child->GetError() != Error::None;}); + if (it == Children().end()) + { + return Error::None; + } else + { + return (*it)->GetError(); + } + } +#endif + + }; + + /** Class for using global options in ArgumentParser. + */ + class GlobalOptions : public Group + { + public: + GlobalOptions(Group &base, Base &options_) : Group(base, {}, Group::Validators::DontCare, Options::Global) + { + Add(options_); + } + }; + + /** Utility class for building subparsers with coroutines/callbacks. + * + * Brief example: + * \code + * Command command(argumentParser, "command", "my command", [](args::Subparser &s) + * { + * // your command flags/positionals + * s.Parse(); //required + * //your command code + * }); + * \endcode + * + * For ARGS_NOEXCEPT mode don't forget to check `s.GetError()` after `s.Parse()` + * and return if it isn't equals to args::Error::None. + * + * \sa Command + */ + class Subparser : public Group + { + private: + std::vector args; + std::vector kicked; + ArgumentParser *parser = nullptr; + const HelpParams &helpParams; + const Command &command; + bool isParsed = false; + + public: + Subparser(std::vector args_, ArgumentParser &parser_, const Command &command_, const HelpParams &helpParams_) + : Group({}, Validators::AllChildGroups), args(std::move(args_)), parser(&parser_), helpParams(helpParams_), command(command_) + { + } + + Subparser(const Command &command_, const HelpParams &helpParams_) : Group({}, Validators::AllChildGroups), helpParams(helpParams_), command(command_) + { + } + + Subparser(const Subparser&) = delete; + Subparser(Subparser&&) = delete; + Subparser &operator = (const Subparser&) = delete; + Subparser &operator = (Subparser&&) = delete; + + const Command &GetCommand() + { + return command; + } + + /** (INTERNAL) Determines whether Parse was called or not. + */ + bool IsParsed() const + { + return isParsed; + } + + /** Continue parsing arguments for new command. + */ + void Parse(); + + /** Returns a vector of kicked out arguments. + * + * \sa Base::KickOut + */ + const std::vector &KickedOut() const noexcept + { + return kicked; + } + }; + + /** Main class for building subparsers. + * + * /sa Subparser + */ + class Command : public Group + { + private: + friend class Subparser; + + std::string name; + std::string help; + std::string description; + std::string epilog; + std::string proglinePostfix; + + std::function parserCoroutine; + bool commandIsRequired = true; + Command *selectedCommand = nullptr; + + mutable std::vector> subparserDescription; + mutable std::vector subparserProgramLine; + mutable bool subparserHasFlag = false; + mutable bool subparserHasPositional = false; + mutable bool subparserHasCommand = false; +#ifdef ARGS_NOEXCEPT + mutable Error subparserError = Error::None; +#endif + mutable Subparser *subparser = nullptr; + + protected: + + class RaiiSubparser + { + public: + RaiiSubparser(ArgumentParser &parser_, std::vector args_); + RaiiSubparser(const Command &command_, const HelpParams ¶ms_); + + ~RaiiSubparser() + { + command.subparser = oldSubparser; + } + + Subparser &Parser() + { + return parser; + } + + private: + const Command &command; + Subparser parser; + Subparser *oldSubparser; + }; + + Command() = default; + + std::function &GetCoroutine() + { + return selectedCommand != nullptr ? selectedCommand->GetCoroutine() : parserCoroutine; + } + + Command &SelectedCommand() + { + Command *res = this; + while (res->selectedCommand != nullptr) + { + res = res->selectedCommand; + } + + return *res; + } + + const Command &SelectedCommand() const + { + const Command *res = this; + while (res->selectedCommand != nullptr) + { + res = res->selectedCommand; + } + + return *res; + } + + void UpdateSubparserHelp(const HelpParams ¶ms) const + { + if (parserCoroutine) + { + RaiiSubparser coro(*this, params); +#ifndef ARGS_NOEXCEPT + try + { + parserCoroutine(coro.Parser()); + } + catch (args::SubparserError&) + { + } +#else + parserCoroutine(coro.Parser()); +#endif + } + } + + public: + Command(Group &base_, std::string name_, std::string help_, std::function coroutine_ = {}) + : name(std::move(name_)), help(std::move(help_)), parserCoroutine(std::move(coroutine_)) + { + base_.Add(*this); + } + + /** The description that appears on the prog line after options + */ + const std::string &ProglinePostfix() const + { return proglinePostfix; } + + /** The description that appears on the prog line after options + */ + void ProglinePostfix(const std::string &proglinePostfix_) + { this->proglinePostfix = proglinePostfix_; } + + /** The description that appears above options + */ + const std::string &Description() const + { return description; } + /** The description that appears above options + */ + + void Description(const std::string &description_) + { this->description = description_; } + + /** The description that appears below options + */ + const std::string &Epilog() const + { return epilog; } + + /** The description that appears below options + */ + void Epilog(const std::string &epilog_) + { this->epilog = epilog_; } + + /** The name of command + */ + const std::string &Name() const + { return name; } + + /** The description of command + */ + const std::string &Help() const + { return help; } + + /** If value is true, parser will fail if no command was parsed. + * + * Default: true. + */ + void RequireCommand(bool value) + { commandIsRequired = value; } + + virtual bool IsGroup() const override + { return false; } + + virtual bool Matched() const noexcept override + { return Base::Matched(); } + + operator bool() const noexcept + { return Matched(); } + + void Match() noexcept + { matched = true; } + + void SelectCommand(Command *c) noexcept + { + selectedCommand = c; + + if (c != nullptr) + { + c->Match(); + } + } + + virtual FlagBase *Match(const EitherFlag &flag) override + { + if (selectedCommand != nullptr) + { + if (auto *res = selectedCommand->Match(flag)) + { + return res; + } + + for (auto *child: Children()) + { + if ((child->GetOptions() & Options::Global) != Options::None) + { + if (auto *res = child->Match(flag)) + { + return res; + } + } + } + + return nullptr; + } + + if (subparser != nullptr) + { + return subparser->Match(flag); + } + + return Matched() ? Group::Match(flag) : nullptr; + } + + virtual std::vector GetAllFlags() override + { + std::vector res; + + if (!Matched()) + { + return res; + } + + for (auto *child: Children()) + { + if (selectedCommand == nullptr || (child->GetOptions() & Options::Global) != Options::None) + { + auto childFlags = child->GetAllFlags(); + res.insert(res.end(), childFlags.begin(), childFlags.end()); + } + } + + if (selectedCommand != nullptr) + { + auto childFlags = selectedCommand->GetAllFlags(); + res.insert(res.end(), childFlags.begin(), childFlags.end()); + } + + if (subparser != nullptr) + { + auto childFlags = subparser->GetAllFlags(); + res.insert(res.end(), childFlags.begin(), childFlags.end()); + } + + return res; + } + + virtual PositionalBase *GetNextPositional() override + { + if (selectedCommand != nullptr) + { + if (auto *res = selectedCommand->GetNextPositional()) + { + return res; + } + + for (auto *child: Children()) + { + if ((child->GetOptions() & Options::Global) != Options::None) + { + if (auto *res = child->GetNextPositional()) + { + return res; + } + } + } + + return nullptr; + } + + if (subparser != nullptr) + { + return subparser->GetNextPositional(); + } + + return Matched() ? Group::GetNextPositional() : nullptr; + } + + virtual bool HasFlag() const override + { + return subparserHasFlag || Group::HasFlag(); + } + + virtual bool HasPositional() const override + { + return subparserHasPositional || Group::HasPositional(); + } + + virtual bool HasCommand() const override + { + return true; + } + + std::vector GetCommandProgramLine(const HelpParams ¶ms) const + { + UpdateSubparserHelp(params); + + auto res = Group::GetProgramLine(params); + res.insert(res.end(), subparserProgramLine.begin(), subparserProgramLine.end()); + + if (!params.proglineCommand.empty() && (Group::HasCommand() || subparserHasCommand)) + { + res.insert(res.begin(), commandIsRequired ? params.proglineCommand : "[" + params.proglineCommand + "]"); + } + + if (!Name().empty()) + { + res.insert(res.begin(), Name()); + } + + if ((subparserHasFlag || Group::HasFlag()) && params.showProglineOptions && !params.proglineShowFlags) + { + res.push_back(params.proglineOptions); + } + + if (!ProglinePostfix().empty()) + { + std::string line; + for (auto c : ProglinePostfix()) + { + if (std::isspace(static_cast(c))) + { + if (!line.empty()) + { + res.push_back(line); + line.clear(); + } + + if (c == '\n') + { + res.push_back("\n"); + } + } + else + { + line += c; + } + } + + if (!line.empty()) + { + res.push_back(line); + } + } + + return res; + } + + virtual std::vector GetProgramLine(const HelpParams ¶ms) const override + { + if (!Matched()) + { + return {}; + } + + return GetCommandProgramLine(params); + } + + virtual std::vector GetCommands() override + { + if (selectedCommand != nullptr) + { + return selectedCommand->GetCommands(); + } + + if (Matched()) + { + return Group::GetCommands(); + } + + return { this }; + } + + virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned int indent) const override + { + std::vector> descriptions; + unsigned addindent = 0; + + UpdateSubparserHelp(params); + + if (!Matched()) + { + if (params.showCommandFullHelp) + { + std::ostringstream s; + bool empty = true; + for (const auto &progline: GetCommandProgramLine(params)) + { + if (!empty) + { + s << ' '; + } + else + { + empty = false; + } + + s << progline; + } + + descriptions.emplace_back(s.str(), "", indent); + } + else + { + descriptions.emplace_back(Name(), help, indent); + } + + if (!params.showCommandChildren && !params.showCommandFullHelp) + { + return descriptions; + } + + addindent = 1; + } + + if (params.showCommandFullHelp && !Matched()) + { + descriptions.emplace_back("", "", indent + addindent); + descriptions.emplace_back(Description().empty() ? Help() : Description(), "", indent + addindent); + descriptions.emplace_back("", "", indent + addindent); + } + + for (Base *child: Children()) + { + if ((child->GetOptions() & Options::HiddenFromDescription) != Options::None) + { + continue; + } + + auto groupDescriptions = child->GetDescription(params, indent + addindent); + descriptions.insert( + std::end(descriptions), + std::make_move_iterator(std::begin(groupDescriptions)), + std::make_move_iterator(std::end(groupDescriptions))); + } + + for (auto childDescription: subparserDescription) + { + std::get<2>(childDescription) += indent + addindent; + descriptions.push_back(std::move(childDescription)); + } + + if (params.showCommandFullHelp && !Matched()) + { + descriptions.emplace_back("", "", indent + addindent); + if (!Epilog().empty()) + { + descriptions.emplace_back(Epilog(), "", indent + addindent); + descriptions.emplace_back("", "", indent + addindent); + } + } + + return descriptions; + } + + virtual void Validate(const std::string &shortprefix, const std::string &longprefix) const override + { + if (!Matched()) + { + return; + } + + auto onValidationError = [&] + { + std::ostringstream problem; + problem << "Group validation failed somewhere!"; +#ifdef ARGS_NOEXCEPT + error = Error::Validation; + errorMsg = problem.str(); +#else + throw ValidationError(problem.str()); +#endif + }; + + for (Base *child: Children()) + { + if (child->IsGroup() && !child->Matched()) + { + onValidationError(); + } + + child->Validate(shortprefix, longprefix); + } + + if (subparser != nullptr) + { + subparser->Validate(shortprefix, longprefix); + if (!subparser->Matched()) + { + onValidationError(); + } + } + + if (selectedCommand == nullptr && commandIsRequired && (Group::HasCommand() || subparserHasCommand)) + { + std::ostringstream problem; + problem << "Command is required"; +#ifdef ARGS_NOEXCEPT + error = Error::Validation; + errorMsg = problem.str(); +#else + throw ValidationError(problem.str()); +#endif + } + } + + virtual void Reset() noexcept override + { + Group::Reset(); + selectedCommand = nullptr; + subparserProgramLine.clear(); + subparserDescription.clear(); + subparserHasFlag = false; + subparserHasPositional = false; + subparserHasCommand = false; +#ifdef ARGS_NOEXCEPT + subparserError = Error::None; +#endif + } + +#ifdef ARGS_NOEXCEPT + /// Only for ARGS_NOEXCEPT + virtual Error GetError() const override + { + if (!Matched()) + { + return Error::None; + } + + if (error != Error::None) + { + return error; + } + + if (subparserError != Error::None) + { + return subparserError; + } + + return Group::GetError(); + } +#endif + }; + + /** The main user facing command line argument parser class + */ + class ArgumentParser : public Command + { + friend class Subparser; + + private: + std::string longprefix; + std::string shortprefix; + + std::string longseparator; + + std::string terminator; + + bool allowJoinedShortValue = true; + bool allowJoinedLongValue = true; + bool allowSeparateShortValue = true; + bool allowSeparateLongValue = true; + + CompletionFlag *completion = nullptr; + bool readCompletion = false; + + protected: + enum class OptionType + { + LongFlag, + ShortFlag, + Positional + }; + + OptionType ParseOption(const std::string &s, bool allowEmpty = false) + { + if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length())) + { + return OptionType::LongFlag; + } + + if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length())) + { + return OptionType::ShortFlag; + } + + return OptionType::Positional; + } + + template + bool Complete(FlagBase &flag, It it, It end) + { + auto nextIt = it; + if (!readCompletion || (++nextIt != end)) + { + return false; + } + + const auto &chunk = *it; + for (auto &choice : flag.HelpChoices(helpParams)) + { + AddCompletionReply(chunk, choice); + } + +#ifndef ARGS_NOEXCEPT + throw Completion(completion->Get()); +#else + return true; +#endif + } + + /** (INTERNAL) Parse flag's values + * + * \param arg The string to display in error message as a flag name + * \param[in, out] it The iterator to first value. It will point to the last value + * \param end The end iterator + * \param joinedArg Joined value (e.g. bar in --foo=bar) + * \param canDiscardJoined If true joined value can be parsed as flag not as a value (as in -abcd) + * \param[out] values The vector to store parsed arg's values + */ + template + std::string ParseArgsValues(FlagBase &flag, const std::string &arg, It &it, It end, + const bool allowSeparate, const bool allowJoined, + const bool hasJoined, const std::string &joinedArg, + const bool canDiscardJoined, std::vector &values) + { + values.clear(); + + Nargs nargs = flag.NumberOfArguments(); + + if (hasJoined && !allowJoined && nargs.min != 0) + { + return "Flag '" + arg + "' was passed a joined argument, but these are disallowed"; + } + + if (hasJoined) + { + if (!canDiscardJoined || nargs.max != 0) + { + values.push_back(joinedArg); + } + } else if (!allowSeparate) + { + if (nargs.min != 0) + { + return "Flag '" + arg + "' was passed a separate argument, but these are disallowed"; + } + } else + { + auto valueIt = it; + ++valueIt; + + while (valueIt != end && + values.size() < nargs.max && + (values.size() < nargs.min || ParseOption(*valueIt) == OptionType::Positional)) + { + if (Complete(flag, valueIt, end)) + { + it = end; + return ""; + } + + values.push_back(*valueIt); + ++it; + ++valueIt; + } + } + + if (values.size() > nargs.max) + { + return "Passed an argument into a non-argument flag: " + arg; + } else if (values.size() < nargs.min) + { + if (nargs.min == 1 && nargs.max == 1) + { + return "Flag '" + arg + "' requires an argument but received none"; + } else if (nargs.min == 1) + { + return "Flag '" + arg + "' requires at least one argument but received none"; + } else if (nargs.min != nargs.max) + { + return "Flag '" + arg + "' requires at least " + std::to_string(nargs.min) + + " arguments but received " + std::to_string(values.size()); + } else + { + return "Flag '" + arg + "' requires " + std::to_string(nargs.min) + + " arguments but received " + std::to_string(values.size()); + } + } + + return {}; + } + + template + bool ParseLong(It &it, It end) + { + const auto &chunk = *it; + const auto argchunk = chunk.substr(longprefix.size()); + // Try to separate it, in case of a separator: + const auto separator = longseparator.empty() ? argchunk.npos : argchunk.find(longseparator); + // If the separator is in the argument, separate it. + const auto arg = (separator != argchunk.npos ? + std::string(argchunk, 0, separator) + : argchunk); + const auto joined = (separator != argchunk.npos ? + argchunk.substr(separator + longseparator.size()) + : std::string()); + + if (auto flag = Match(arg)) + { + std::vector values; + const std::string errorMessage = ParseArgsValues(*flag, arg, it, end, allowSeparateLongValue, allowJoinedLongValue, + separator != argchunk.npos, joined, false, values); + if (!errorMessage.empty()) + { +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + + if (!readCompletion) + { + flag->ParseValue(values); + } + + if (flag->KickOut()) + { + ++it; + return false; + } + } else + { + const std::string errorMessage("Flag could not be matched: " + arg); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + + return true; + } + + template + bool ParseShort(It &it, It end) + { + const auto &chunk = *it; + const auto argchunk = chunk.substr(shortprefix.size()); + for (auto argit = std::begin(argchunk); argit != std::end(argchunk); ++argit) + { + const auto arg = *argit; + + if (auto flag = Match(arg)) + { + const std::string value(argit + 1, std::end(argchunk)); + std::vector values; + const std::string errorMessage = ParseArgsValues(*flag, std::string(1, arg), it, end, + allowSeparateShortValue, allowJoinedShortValue, + !value.empty(), value, !value.empty(), values); + + if (!errorMessage.empty()) + { +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + + if (!readCompletion) + { + flag->ParseValue(values); + } + + if (flag->KickOut()) + { + ++it; + return false; + } + + if (!values.empty()) + { + break; + } + } else + { + const std::string errorMessage("Flag could not be matched: '" + std::string(1, arg) + "'"); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return false; +#endif + } + } + + return true; + } + + bool AddCompletionReply(const std::string &cur, const std::string &choice) + { + if (cur.empty() || choice.find(cur) == 0) + { + if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos) + { + completion->reply.push_back(choice.substr(choice.find(longseparator) + 1)); + } else + { + completion->reply.push_back(choice); + } + return true; + } + + return false; + } + + template + bool Complete(It it, It end) + { + auto nextIt = it; + if (!readCompletion || (++nextIt != end)) + { + return false; + } + + const auto &chunk = *it; + auto pos = GetNextPositional(); + std::vector commands = GetCommands(); + const auto optionType = ParseOption(chunk, true); + + if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional)) + { + for (auto &cmd : commands) + { + if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None) + { + AddCompletionReply(chunk, cmd->Name()); + } + } + } else + { + bool hasPositionalCompletion = true; + + if (!commands.empty()) + { + for (auto &cmd : commands) + { + if ((cmd->GetOptions() & Options::HiddenFromCompletion) == Options::None) + { + AddCompletionReply(chunk, cmd->Name()); + } + } + } else if (pos) + { + if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None) + { + auto choices = pos->HelpChoices(helpParams); + hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional; + for (auto &choice : choices) + { + AddCompletionReply(chunk, choice); + } + } + } + + if (hasPositionalCompletion) + { + auto flags = GetAllFlags(); + for (auto flag : flags) + { + if ((flag->GetOptions() & Options::HiddenFromCompletion) != Options::None) + { + continue; + } + + auto &matcher = flag->GetMatcher(); + if (!AddCompletionReply(chunk, matcher.GetShortOrAny().str(shortprefix, longprefix))) + { + for (auto &flagName : matcher.GetFlagStrings()) + { + if (AddCompletionReply(chunk, flagName.str(shortprefix, longprefix))) + { + break; + } + } + } + } + + if (optionType == OptionType::LongFlag && allowJoinedLongValue) + { + const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator); + if (separator != chunk.npos) + { + std::string arg(chunk, 0, separator); + if (auto flag = this->Match(arg.substr(longprefix.size()))) + { + for (auto &choice : flag->HelpChoices(helpParams)) + { + AddCompletionReply(chunk, arg + longseparator + choice); + } + } + } + } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue) + { + if (chunk.size() > shortprefix.size() + 1) + { + auto arg = chunk.at(shortprefix.size()); + //TODO: support -abcVALUE where a and b take no value + if (auto flag = this->Match(arg)) + { + for (auto &choice : flag->HelpChoices(helpParams)) + { + AddCompletionReply(chunk, shortprefix + arg + choice); + } + } + } + } + } + } + +#ifndef ARGS_NOEXCEPT + throw Completion(completion->Get()); +#else + return true; +#endif + } + + template + It Parse(It begin, It end) + { + bool terminated = false; + std::vector commands = GetCommands(); + + // Check all arg chunks + for (auto it = begin; it != end; ++it) + { + if (Complete(it, end)) + { + return end; + } + + const auto &chunk = *it; + + if (!terminated && chunk == terminator) + { + terminated = true; + } else if (!terminated && ParseOption(chunk) == OptionType::LongFlag) + { + if (!ParseLong(it, end)) + { + return it; + } + } else if (!terminated && ParseOption(chunk) == OptionType::ShortFlag) + { + if (!ParseShort(it, end)) + { + return it; + } + } else if (!terminated && !commands.empty()) + { + auto itCommand = std::find_if(commands.begin(), commands.end(), [&chunk](Command *c) { return c->Name() == chunk; }); + if (itCommand == commands.end()) + { + const std::string errorMessage("Unknown command: " + chunk); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return it; +#endif + } + + SelectCommand(*itCommand); + + if (const auto &coroutine = GetCoroutine()) + { + ++it; + RaiiSubparser coro(*this, std::vector(it, end)); + coroutine(coro.Parser()); +#ifdef ARGS_NOEXCEPT + error = GetError(); + if (error != Error::None) + { + return end; + } + + if (!coro.Parser().IsParsed()) + { + error = Error::Usage; + return end; + } +#else + if (!coro.Parser().IsParsed()) + { + throw UsageError("Subparser::Parse was not called"); + } +#endif + + break; + } + + commands = GetCommands(); + } else + { + auto pos = GetNextPositional(); + if (pos) + { + pos->ParseValue(chunk); + + if (pos->KickOut()) + { + return ++it; + } + } else + { + const std::string errorMessage("Passed in argument, but no positional arguments were ready to receive it: " + chunk); +#ifndef ARGS_NOEXCEPT + throw ParseError(errorMessage); +#else + error = Error::Parse; + errorMsg = errorMessage; + return it; +#endif + } + } + + if (!readCompletion && completion != nullptr && completion->Matched()) + { +#ifdef ARGS_NOEXCEPT + error = Error::Completion; +#endif + readCompletion = true; + ++it; + const auto argsLeft = static_cast(std::distance(it, end)); + if (completion->cword == 0 || argsLeft <= 1 || completion->cword >= argsLeft) + { +#ifndef ARGS_NOEXCEPT + throw Completion(""); +#endif + } + + std::vector curArgs(++it, end); + curArgs.resize(completion->cword); + + if (completion->syntax == "bash") + { + // bash tokenizes --flag=value as --flag=value + for (size_t idx = 0; idx < curArgs.size(); ) + { + if (idx > 0 && curArgs[idx] == "=") + { + curArgs[idx - 1] += "="; + // Avoid warnings from -Wsign-conversion + const auto signedIdx = static_cast(idx); + if (idx + 1 < curArgs.size()) + { + curArgs[idx - 1] += curArgs[idx + 1]; + curArgs.erase(curArgs.begin() + signedIdx, curArgs.begin() + signedIdx + 2); + } else + { + curArgs.erase(curArgs.begin() + signedIdx); + } + } else + { + ++idx; + } + } + + } +#ifndef ARGS_NOEXCEPT + try + { + Parse(curArgs.begin(), curArgs.end()); + throw Completion(""); + } + catch (Completion &) + { + throw; + } + catch (args::Error&) + { + throw Completion(""); + } +#else + return Parse(curArgs.begin(), curArgs.end()); +#endif + } + } + + Validate(shortprefix, longprefix); + return end; + } + + public: + HelpParams helpParams; + + ArgumentParser(const std::string &description_, const std::string &epilog_ = std::string()) + { + Description(description_); + Epilog(epilog_); + LongPrefix("--"); + ShortPrefix("-"); + LongSeparator("="); + Terminator("--"); + SetArgumentSeparations(true, true, true, true); + matched = true; + } + + void AddCompletion(CompletionFlag &completionFlag) + { + completion = &completionFlag; + Add(completionFlag); + } + + /** The program name for help generation + */ + const std::string &Prog() const + { return helpParams.programName; } + /** The program name for help generation + */ + void Prog(const std::string &prog_) + { this->helpParams.programName = prog_; } + + /** The prefix for long flags + */ + const std::string &LongPrefix() const + { return longprefix; } + /** The prefix for long flags + */ + void LongPrefix(const std::string &longprefix_) + { + this->longprefix = longprefix_; + this->helpParams.longPrefix = longprefix_; + } + + /** The prefix for short flags + */ + const std::string &ShortPrefix() const + { return shortprefix; } + /** The prefix for short flags + */ + void ShortPrefix(const std::string &shortprefix_) + { + this->shortprefix = shortprefix_; + this->helpParams.shortPrefix = shortprefix_; + } + + /** The separator for long flags + */ + const std::string &LongSeparator() const + { return longseparator; } + /** The separator for long flags + */ + void LongSeparator(const std::string &longseparator_) + { + if (longseparator_.empty()) + { + const std::string errorMessage("longseparator can not be set to empty"); +#ifdef ARGS_NOEXCEPT + error = Error::Usage; + errorMsg = errorMessage; +#else + throw UsageError(errorMessage); +#endif + } else + { + this->longseparator = longseparator_; + this->helpParams.longSeparator = allowJoinedLongValue ? longseparator_ : " "; + } + } + + /** The terminator that forcibly separates flags from positionals + */ + const std::string &Terminator() const + { return terminator; } + /** The terminator that forcibly separates flags from positionals + */ + void Terminator(const std::string &terminator_) + { this->terminator = terminator_; } + + /** Get the current argument separation parameters. + * + * See SetArgumentSeparations for details on what each one means. + */ + void GetArgumentSeparations( + bool &allowJoinedShortValue_, + bool &allowJoinedLongValue_, + bool &allowSeparateShortValue_, + bool &allowSeparateLongValue_) const + { + allowJoinedShortValue_ = this->allowJoinedShortValue; + allowJoinedLongValue_ = this->allowJoinedLongValue; + allowSeparateShortValue_ = this->allowSeparateShortValue; + allowSeparateLongValue_ = this->allowSeparateLongValue; + } + + /** Change allowed option separation. + * + * \param allowJoinedShortValue_ Allow a short flag that accepts an argument to be passed its argument immediately next to it (ie. in the same argv field) + * \param allowJoinedLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by the longseparator (ie. in the same argv field) + * \param allowSeparateShortValue_ Allow a short flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field) + * \param allowSeparateLongValue_ Allow a long flag that accepts an argument to be passed its argument separated by whitespace (ie. in the next argv field) + */ + void SetArgumentSeparations( + const bool allowJoinedShortValue_, + const bool allowJoinedLongValue_, + const bool allowSeparateShortValue_, + const bool allowSeparateLongValue_) + { + this->allowJoinedShortValue = allowJoinedShortValue_; + this->allowJoinedLongValue = allowJoinedLongValue_; + this->allowSeparateShortValue = allowSeparateShortValue_; + this->allowSeparateLongValue = allowSeparateLongValue_; + + this->helpParams.longSeparator = allowJoinedLongValue ? longseparator : " "; + this->helpParams.shortSeparator = allowJoinedShortValue ? "" : " "; + } + + /** Pass the help menu into an ostream + */ + void Help(std::ostream &help_) const + { + auto &command = SelectedCommand(); + const auto &commandDescription = command.Description().empty() ? command.Help() : command.Description(); + const auto description_text = Wrap(commandDescription, helpParams.width - helpParams.descriptionindent); + const auto epilog_text = Wrap(command.Epilog(), helpParams.width - helpParams.descriptionindent); + + const bool hasoptions = command.HasFlag(); + const bool hasarguments = command.HasPositional(); + + std::vector prognameline; + prognameline.push_back(helpParams.usageString); + prognameline.push_back(Prog()); + auto commandProgLine = command.GetProgramLine(helpParams); + prognameline.insert(prognameline.end(), commandProgLine.begin(), commandProgLine.end()); + + const auto proglines = Wrap(prognameline.begin(), prognameline.end(), + helpParams.width - (helpParams.progindent + helpParams.progtailindent), + helpParams.width - helpParams.progindent); + auto progit = std::begin(proglines); + if (progit != std::end(proglines)) + { + help_ << std::string(helpParams.progindent, ' ') << *progit << '\n'; + ++progit; + } + for (; progit != std::end(proglines); ++progit) + { + help_ << std::string(helpParams.progtailindent, ' ') << *progit << '\n'; + } + + help_ << '\n'; + + if (!description_text.empty()) + { + for (const auto &line: description_text) + { + help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n"; + } + help_ << "\n"; + } + + bool lastDescriptionIsNewline = false; + + if (!helpParams.optionsString.empty()) + { + help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n"; + } + + for (const auto &desc: command.GetDescription(helpParams, 0)) + { + lastDescriptionIsNewline = std::get<0>(desc).empty() && std::get<1>(desc).empty(); + const auto groupindent = std::get<2>(desc) * helpParams.eachgroupindent; + const auto flags = Wrap(std::get<0>(desc), helpParams.width - (helpParams.flagindent + helpParams.helpindent + helpParams.gutter)); + const auto info = Wrap(std::get<1>(desc), helpParams.width - (helpParams.helpindent + groupindent)); + + std::string::size_type flagssize = 0; + for (auto flagsit = std::begin(flags); flagsit != std::end(flags); ++flagsit) + { + if (flagsit != std::begin(flags)) + { + help_ << '\n'; + } + help_ << std::string(groupindent + helpParams.flagindent, ' ') << *flagsit; + flagssize = Glyphs(*flagsit); + } + + auto infoit = std::begin(info); + // groupindent is on both sides of this inequality, and therefore can be removed + if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info) || helpParams.addNewlineBeforeDescription) + { + help_ << '\n'; + } else + { + // groupindent is on both sides of the minus sign, and therefore doesn't actually need to be in here + help_ << std::string(helpParams.helpindent - (helpParams.flagindent + flagssize), ' ') << *infoit << '\n'; + ++infoit; + } + for (; infoit != std::end(info); ++infoit) + { + help_ << std::string(groupindent + helpParams.helpindent, ' ') << *infoit << '\n'; + } + } + if (hasoptions && hasarguments && helpParams.showTerminator) + { + lastDescriptionIsNewline = false; + for (const auto &item: Wrap(std::string("\"") + terminator + "\" can be used to terminate flag options and force all following arguments to be treated as positional options", helpParams.width - helpParams.flagindent)) + { + help_ << std::string(helpParams.flagindent, ' ') << item << '\n'; + } + } + + if (!lastDescriptionIsNewline) + { + help_ << "\n"; + } + + for (const auto &line: epilog_text) + { + help_ << std::string(helpParams.descriptionindent, ' ') << line << "\n"; + } + } + + /** Generate a help menu as a string. + * + * \return the help text as a single string + */ + std::string Help() const + { + std::ostringstream help_; + Help(help_); + return help_.str(); + } + + virtual void Reset() noexcept override + { + Command::Reset(); + matched = true; + readCompletion = false; + } + + /** Parse all arguments. + * + * \param begin an iterator to the beginning of the argument list + * \param end an iterator to the past-the-end element of the argument list + * \return the iterator after the last parsed value. Only useful for kick-out + */ + template + It ParseArgs(It begin, It end) + { + // Reset all Matched statuses and errors + Reset(); +#ifdef ARGS_NOEXCEPT + error = GetError(); + if (error != Error::None) + { + return end; + } +#endif + return Parse(begin, end); + } + + /** Parse all arguments. + * + * \param args an iterable of the arguments + * \return the iterator after the last parsed value. Only useful for kick-out + */ + template + auto ParseArgs(const T &args) -> decltype(std::begin(args)) + { + return ParseArgs(std::begin(args), std::end(args)); + } + + /** Convenience function to parse the CLI from argc and argv + * + * Just assigns the program name and vectorizes arguments for passing into ParseArgs() + * + * \return whether or not all arguments were parsed. This works for detecting kick-out, but is generally useless as it can't do anything with it. + */ + bool ParseCLI(const int argc, const char * const * argv) + { + if (Prog().empty()) + { + Prog(argv[0]); + } + const std::vector args(argv + 1, argv + argc); + return ParseArgs(args) == std::end(args); + } + + template + bool ParseCLI(const T &args) + { + return ParseArgs(args) == std::end(args); + } + }; + + inline Command::RaiiSubparser::RaiiSubparser(ArgumentParser &parser_, std::vector args_) + : command(parser_.SelectedCommand()), parser(std::move(args_), parser_, command, parser_.helpParams), oldSubparser(command.subparser) + { + command.subparser = &parser; + } + + inline Command::RaiiSubparser::RaiiSubparser(const Command &command_, const HelpParams ¶ms_): command(command_), parser(command, params_), oldSubparser(command.subparser) + { + command.subparser = &parser; + } + + inline void Subparser::Parse() + { + isParsed = true; + Reset(); + command.subparserDescription = GetDescription(helpParams, 0); + command.subparserHasFlag = HasFlag(); + command.subparserHasPositional = HasPositional(); + command.subparserHasCommand = HasCommand(); + command.subparserProgramLine = GetProgramLine(helpParams); + if (parser == nullptr) + { +#ifndef ARGS_NOEXCEPT + throw args::SubparserError(); +#else + error = Error::Subparser; + return; +#endif + } + + auto it = parser->Parse(args.begin(), args.end()); + command.Validate(parser->ShortPrefix(), parser->LongPrefix()); + kicked.assign(it, args.end()); + +#ifdef ARGS_NOEXCEPT + command.subparserError = GetError(); +#endif + } + + inline std::ostream &operator<<(std::ostream &os, const ArgumentParser &parser) + { + parser.Help(os); + return os; + } + + /** Boolean argument matcher + */ + class Flag : public FlagBase + { + public: + Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): FlagBase(name_, help_, std::move(matcher_), options_) + { + group_.Add(*this); + } + + Flag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false): Flag(group_, name_, help_, std::move(matcher_), extraError_ ? Options::Single : Options::None) + { + } + + virtual ~Flag() {} + + /** Get whether this was matched + */ + bool Get() const + { + return Matched(); + } + + virtual Nargs NumberOfArguments() const noexcept override + { + return 0; + } + + virtual void ParseValue(const std::vector&) override + { + } + }; + + /** Help flag class + * + * Works like a regular flag, but throws an instance of Help when it is matched + */ + class HelpFlag : public Flag + { + public: + HelpFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_ = {}): Flag(group_, name_, help_, std::move(matcher_), options_) {} + + virtual ~HelpFlag() {} + + virtual void ParseValue(const std::vector &) + { +#ifdef ARGS_NOEXCEPT + error = Error::Help; + errorMsg = Name(); +#else + throw Help(Name()); +#endif + } + + /** Get whether this was matched + */ + bool Get() const noexcept + { + return Matched(); + } + }; + + /** A flag class that simply counts the number of times it's matched + */ + class CounterFlag : public Flag + { + private: + const int startcount; + int count; + + public: + CounterFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const int startcount_ = 0, Options options_ = {}): + Flag(group_, name_, help_, std::move(matcher_), options_), startcount(startcount_), count(startcount_) {} + + virtual ~CounterFlag() {} + + virtual FlagBase *Match(const EitherFlag &arg) override + { + auto me = FlagBase::Match(arg); + if (me) + { + ++count; + } + return me; + } + + /** Get the count + */ + int &Get() noexcept + { + return count; + } + + int &operator *() noexcept { + return count; + } + + const int &operator *() const noexcept { + return count; + } + + virtual void Reset() noexcept override + { + FlagBase::Reset(); + count = startcount; + } + }; + + /** A flag class that calls a function when it's matched + */ + class ActionFlag : public FlagBase + { + private: + std::function &)> action; + Nargs nargs; + + public: + ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, std::function &)> action_, Options options_ = {}): + FlagBase(name_, help_, std::move(matcher_), options_), action(std::move(action_)), nargs(nargs_) + { + group_.Add(*this); + } + + ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function action_, Options options_ = {}): + FlagBase(name_, help_, std::move(matcher_), options_), nargs(1) + { + group_.Add(*this); + action = [action_](const std::vector &a) { return action_(a.at(0)); }; + } + + ActionFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, std::function action_, Options options_ = {}): + FlagBase(name_, help_, std::move(matcher_), options_), nargs(0) + { + group_.Add(*this); + action = [action_](const std::vector &) { return action_(); }; + } + + virtual Nargs NumberOfArguments() const noexcept override + { return nargs; } + + virtual void ParseValue(const std::vector &value) override + { action(value); } + }; + + /** A default Reader class for argument classes + * + * If destination type is assignable to std::string it uses an assignment to std::string. + * Otherwise ValueReader simply uses a std::istringstream to read into the destination type, and + * raises a ParseError if there are any characters left. + */ + struct ValueReader + { + template + typename std::enable_if::value, bool>::type + operator ()(const std::string &name, const std::string &value, T &destination) + { + std::istringstream ss(value); + bool failed = !(ss >> destination); + + if (!failed) + { + ss >> std::ws; + } + + if (ss.rdbuf()->in_avail() > 0 || failed) + { +#ifdef ARGS_NOEXCEPT + (void)name; + return false; +#else + std::ostringstream problem; + problem << "Argument '" << name << "' received invalid value type '" << value << "'"; + throw ParseError(problem.str()); +#endif + } + return true; + } + + template + typename std::enable_if::value, bool>::type + operator()(const std::string &, const std::string &value, T &destination) + { + destination = value; + return true; + } + }; + + /** An argument-accepting flag class + * + * \tparam T the type to extract the argument as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + typename Reader = ValueReader> + class ValueFlag : public ValueFlagBase + { + protected: + T value; + T defaultValue; + + virtual std::string GetDefaultString(const HelpParams&) const override + { + return detail::ToString(defaultValue); + } + + private: + Reader reader; + + public: + + ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), const bool extraError_ = false): ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, extraError_ ? Options::Single : Options::None) + { + } + + ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_): ValueFlag(group_, name_, help_, std::move(matcher_), T(), options_) + { + } + + virtual ~ValueFlag() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value_ = values_.at(0); + +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, this->value)) + { + error = Error::Parse; + } +#else + reader(name, value_, this->value); +#endif + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + value = defaultValue; + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + /** Get the value + */ + T &operator *() noexcept + { + return value; + } + + /** Get the value + */ + const T &operator *() const noexcept + { + return value; + } + + /** Get the value + */ + T *operator ->() noexcept + { + return &value; + } + + /** Get the value + */ + const T *operator ->() const noexcept + { + return &value; + } + + /** Get the default value + */ + const T &GetDefault() noexcept + { + return defaultValue; + } + }; + + /** An optional argument-accepting flag class + * + * \tparam T the type to extract the argument as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + typename Reader = ValueReader> + class ImplicitValueFlag : public ValueFlag + { + protected: + T implicitValue; + + public: + + ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &implicitValue_, const T &defaultValue_ = T(), Options options_ = {}) + : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_) + { + } + + ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), Options options_ = {}) + : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_) + { + } + + ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) + : ValueFlag(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue() + { + } + + virtual ~ImplicitValueFlag() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return {0, 1}; + } + + virtual void ParseValue(const std::vector &value_) override + { + if (value_.empty()) + { + this->value = implicitValue; + } else + { + ValueFlag::ParseValue(value_); + } + } + }; + + /** A variadic arguments accepting flag class + * + * \tparam T the type to extract the argument as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + template class List = detail::vector, + typename Reader = ValueReader> + class NargsValueFlag : public FlagBase + { + protected: + + List values; + const List defaultValues; + Nargs nargs; + Reader reader; + + public: + + typedef List Container; + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + NargsValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Nargs nargs_, const List &defaultValues_ = {}, Options options_ = {}) + : FlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_),nargs(nargs_) + { + group_.Add(*this); + } + + virtual ~NargsValueFlag() {} + + virtual Nargs NumberOfArguments() const noexcept override + { + return nargs; + } + + virtual void ParseValue(const std::vector &values_) override + { + values.clear(); + + for (const std::string &value : values_) + { + T v; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value, v)) + { + error = Error::Parse; + } +#else + reader(name, value, v); +#endif + values.insert(std::end(values), v); + } + } + + List &Get() noexcept + { + return values; + } + + /** Get the value + */ + List &operator *() noexcept + { + return values; + } + + /** Get the values + */ + const List &operator *() const noexcept + { + return values; + } + + /** Get the values + */ + List *operator ->() noexcept + { + return &values; + } + + /** Get the values + */ + const List *operator ->() const noexcept + { + return &values; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + + virtual void Reset() noexcept override + { + FlagBase::Reset(); + values = defaultValues; + } + + virtual FlagBase *Match(const EitherFlag &arg) override + { + const bool wasMatched = Matched(); + auto me = FlagBase::Match(arg); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + }; + + /** An argument-accepting flag class that pushes the found values into a list + * + * \tparam T the type to extract the argument as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + template class List = detail::vector, + typename Reader = ValueReader> + class ValueFlagList : public ValueFlagBase + { + private: + using Container = List; + Container values; + const Container defaultValues; + Reader reader; + + public: + + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + ValueFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Container &defaultValues_ = Container(), Options options_ = {}): + ValueFlagBase(name_, help_, std::move(matcher_), options_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + virtual ~ValueFlagList() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value_ = values_.at(0); + + T v; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, v)) + { + error = Error::Parse; + } +#else + reader(name, value_, v); +#endif + values.insert(std::end(values), v); + } + + /** Get the values + */ + Container &Get() noexcept + { + return values; + } + + /** Get the value + */ + Container &operator *() noexcept + { + return values; + } + + /** Get the values + */ + const Container &operator *() const noexcept + { + return values; + } + + /** Get the values + */ + Container *operator ->() noexcept + { + return &values; + } + + /** Get the values + */ + const Container *operator ->() const noexcept + { + return &values; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + values = defaultValues; + } + + virtual FlagBase *Match(const EitherFlag &arg) override + { + const bool wasMatched = Matched(); + auto me = FlagBase::Match(arg); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; + + /** A mapping value flag class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapFlag : public ValueFlagBase + { + private: + const Map map; + T value; + const T defaultValue; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + + MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), map(map_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, const T &defaultValue_ = T(), const bool extraError_ = false): MapFlag(group_, name_, help_, std::move(matcher_), map_, defaultValue_, extraError_ ? Options::Single : Options::None) + { + } + + MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, Options options_): MapFlag(group_, name_, help_, std::move(matcher_), map_, T(), options_) + { + } + + virtual ~MapFlag() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value_ = values_.at(0); + + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, key)) + { + error = Error::Parse; + } +#else + reader(name, value_, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->value = it->second; + } + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + /** Get the value + */ + T &operator *() noexcept + { + return value; + } + + /** Get the value + */ + const T &operator *() const noexcept + { + return value; + } + + /** Get the value + */ + T *operator ->() noexcept + { + return &value; + } + + /** Get the value + */ + const T *operator ->() const noexcept + { + return &value; + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + value = defaultValue; + } + }; + + /** A mapping value flag list class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + template class List = detail::vector, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapFlagList : public ValueFlagBase + { + private: + using Container = List; + const Map map; + Container values; + const Container defaultValues; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + MapFlagList(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, const Container &defaultValues_ = Container()): ValueFlagBase(name_, help_, std::move(matcher_)), map(map_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + virtual ~MapFlagList() {} + + virtual void ParseValue(const std::vector &values_) override + { + const std::string &value = values_.at(0); + + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value, key)) + { + error = Error::Parse; + } +#else + reader(name, value, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->values.emplace_back(it->second); + } + } + + /** Get the value + */ + Container &Get() noexcept + { + return values; + } + + /** Get the value + */ + Container &operator *() noexcept + { + return values; + } + + /** Get the values + */ + const Container &operator *() const noexcept + { + return values; + } + + /** Get the values + */ + Container *operator ->() noexcept + { + return &values; + } + + /** Get the values + */ + const Container *operator ->() const noexcept + { + return &values; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + values = defaultValues; + } + + virtual FlagBase *Match(const EitherFlag &arg) override + { + const bool wasMatched = Matched(); + auto me = FlagBase::Match(arg); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; + + /** A positional argument class + * + * \tparam T the type to extract the argument as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + typename Reader = ValueReader> + class Positional : public PositionalBase + { + private: + T value; + const T defaultValue; + Reader reader; + public: + Positional(Group &group_, const std::string &name_, const std::string &help_, const T &defaultValue_ = T(), Options options_ = {}): PositionalBase(name_, help_, options_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + Positional(Group &group_, const std::string &name_, const std::string &help_, Options options_): Positional(group_, name_, help_, T(), options_) + { + } + + virtual ~Positional() {} + + virtual void ParseValue(const std::string &value_) override + { +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, this->value)) + { + error = Error::Parse; + } +#else + reader(name, value_, this->value); +#endif + ready = false; + matched = true; + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + /** Get the value + */ + T &operator *() noexcept + { + return value; + } + + /** Get the value + */ + const T &operator *() const noexcept + { + return value; + } + + /** Get the value + */ + T *operator ->() noexcept + { + return &value; + } + + /** Get the value + */ + const T *operator ->() const noexcept + { + return &value; + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + value = defaultValue; + } + }; + + /** A positional argument class that pushes the found values into a list + * + * \tparam T the type to extract the argument as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + */ + template < + typename T, + template class List = detail::vector, + typename Reader = ValueReader> + class PositionalList : public PositionalBase + { + private: + using Container = List; + Container values; + const Container defaultValues; + Reader reader; + + public: + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + PositionalList(Group &group_, const std::string &name_, const std::string &help_, const Container &defaultValues_ = Container(), Options options_ = {}): PositionalBase(name_, help_, options_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + PositionalList(Group &group_, const std::string &name_, const std::string &help_, Options options_): PositionalList(group_, name_, help_, {}, options_) + { + } + + virtual ~PositionalList() {} + + virtual void ParseValue(const std::string &value_) override + { + T v; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, v)) + { + error = Error::Parse; + } +#else + reader(name, value_, v); +#endif + values.insert(std::end(values), v); + matched = true; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + /** Get the values + */ + Container &Get() noexcept + { + return values; + } + + /** Get the value + */ + Container &operator *() noexcept + { + return values; + } + + /** Get the values + */ + const Container &operator *() const noexcept + { + return values; + } + + /** Get the values + */ + Container *operator ->() noexcept + { + return &values; + } + + /** Get the values + */ + const Container *operator ->() const noexcept + { + return &values; + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + values = defaultValues; + } + + virtual PositionalBase *GetNextPositional() override + { + const bool wasMatched = Matched(); + auto me = PositionalBase::GetNextPositional(); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; + + /** A positional argument mapping class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapPositional : public PositionalBase + { + private: + const Map map; + T value; + const T defaultValue; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + + MapPositional(Group &group_, const std::string &name_, const std::string &help_, const Map &map_, const T &defaultValue_ = T(), Options options_ = {}): + PositionalBase(name_, help_, options_), map(map_), value(defaultValue_), defaultValue(defaultValue_) + { + group_.Add(*this); + } + + virtual ~MapPositional() {} + + virtual void ParseValue(const std::string &value_) override + { + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, key)) + { + error = Error::Parse; + } +#else + reader(name, value_, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->value = it->second; + ready = false; + matched = true; + } + } + + /** Get the value + */ + T &Get() noexcept + { + return value; + } + + /** Get the value + */ + T &operator *() noexcept + { + return value; + } + + /** Get the value + */ + const T &operator *() const noexcept + { + return value; + } + + /** Get the value + */ + T *operator ->() noexcept + { + return &value; + } + + /** Get the value + */ + const T *operator ->() const noexcept + { + return &value; + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + value = defaultValue; + } + }; + + /** A positional argument mapping list class + * + * \tparam K the type to extract the argument as + * \tparam T the type to store the result as + * \tparam List the list type that houses the values + * \tparam Reader The functor type used to read the argument, taking the name, value, and destination reference with operator(), and returning a bool (if ARGS_NOEXCEPT is defined) + * \tparam Map The Map type. Should operate like std::map or std::unordered_map + */ + template < + typename K, + typename T, + template class List = detail::vector, + typename Reader = ValueReader, + template class Map = detail::unordered_map> + class MapPositionalList : public PositionalBase + { + private: + using Container = List; + + const Map map; + Container values; + const Container defaultValues; + Reader reader; + + protected: + virtual std::vector GetChoicesStrings(const HelpParams &) const override + { + return detail::MapKeysToStrings(map); + } + + public: + typedef T value_type; + typedef typename Container::allocator_type allocator_type; + typedef typename Container::pointer pointer; + typedef typename Container::const_pointer const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef typename Container::size_type size_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::iterator iterator; + typedef typename Container::const_iterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + MapPositionalList(Group &group_, const std::string &name_, const std::string &help_, const Map &map_, const Container &defaultValues_ = Container(), Options options_ = {}): + PositionalBase(name_, help_, options_), map(map_), values(defaultValues_), defaultValues(defaultValues_) + { + group_.Add(*this); + } + + virtual ~MapPositionalList() {} + + virtual void ParseValue(const std::string &value_) override + { + K key; +#ifdef ARGS_NOEXCEPT + if (!reader(name, value_, key)) + { + error = Error::Parse; + } +#else + reader(name, value_, key); +#endif + auto it = map.find(key); + if (it == std::end(map)) + { + std::ostringstream problem; + problem << "Could not find key '" << key << "' in map for arg '" << name << "'"; +#ifdef ARGS_NOEXCEPT + error = Error::Map; + errorMsg = problem.str(); +#else + throw MapError(problem.str()); +#endif + } else + { + this->values.emplace_back(it->second); + matched = true; + } + } + + /** Get the value + */ + Container &Get() noexcept + { + return values; + } + + /** Get the value + */ + Container &operator *() noexcept + { + return values; + } + + /** Get the values + */ + const Container &operator *() const noexcept + { + return values; + } + + /** Get the values + */ + Container *operator ->() noexcept + { + return &values; + } + + /** Get the values + */ + const Container *operator ->() const noexcept + { + return &values; + } + + virtual std::string Name() const override + { + return name + std::string("..."); + } + + virtual void Reset() noexcept override + { + PositionalBase::Reset(); + values = defaultValues; + } + + virtual PositionalBase *GetNextPositional() override + { + const bool wasMatched = Matched(); + auto me = PositionalBase::GetNextPositional(); + if (me && !wasMatched) + { + values.clear(); + } + return me; + } + + iterator begin() noexcept + { + return values.begin(); + } + + const_iterator begin() const noexcept + { + return values.begin(); + } + + const_iterator cbegin() const noexcept + { + return values.cbegin(); + } + + iterator end() noexcept + { + return values.end(); + } + + const_iterator end() const noexcept + { + return values.end(); + } + + const_iterator cend() const noexcept + { + return values.cend(); + } + }; +} + +#endif diff --git a/lci/extra/dashun/dashun/dashun.vcxproj b/lci/extra/dashun/dashun/dashun.vcxproj new file mode 100644 index 0000000..990f988 --- /dev/null +++ b/lci/extra/dashun/dashun/dashun.vcxproj @@ -0,0 +1,141 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {a0e6a4c1-02b0-41f5-abb7-33c6e4fb97f6} + dashun + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp20 + C:\local\boost_1_88_0;C:\Program Files\libuv\include;%(AdditionalIncludeDirectories) + + + Console + true + C:\local\boost_1_88_0\lib64-msvc-14.3;C:\Program Files\libuv;%(AdditionalLibraryDirectories) + libuv.lib;ntdll.lib;%(AdditionalDependencies) + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lci/extra/dashun/dashun/dashun.vcxproj.filters b/lci/extra/dashun/dashun/dashun.vcxproj.filters new file mode 100644 index 0000000..6fbc8d5 --- /dev/null +++ b/lci/extra/dashun/dashun/dashun.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 头文件 + + + 源文件 + + + + + 头文件 + + + 头文件 + + + 头文件 + + + \ No newline at end of file diff --git a/lci/extra/dashun/dashun/dashun.vcxproj.user b/lci/extra/dashun/dashun/dashun.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/lci/extra/dashun/dashun/dashun.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/lci/extra/dashun/dashun_to/dashun_to.cpp b/lci/extra/dashun/dashun_to/dashun_to.cpp new file mode 100644 index 0000000..8a528d8 --- /dev/null +++ b/lci/extra/dashun/dashun_to/dashun_to.cpp @@ -0,0 +1,20 @@ +// dashun_to.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 +// + +#include + +int main() +{ + std::cout << "Hello World!\n"; +} + +// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单 +// 调试程序: F5 或调试 >“开始调试”菜单 + +// 入门使用技巧: +// 1. 使用解决方案资源管理器窗口添加/管理文件 +// 2. 使用团队资源管理器窗口连接到源代码管理 +// 3. 使用输出窗口查看生成输出和其他消息 +// 4. 使用错误列表窗口查看错误 +// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目 +// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件 diff --git a/lci/extra/dashun/dashun_to/dashun_to.vcxproj b/lci/extra/dashun/dashun_to/dashun_to.vcxproj new file mode 100644 index 0000000..bc91e10 --- /dev/null +++ b/lci/extra/dashun/dashun_to/dashun_to.vcxproj @@ -0,0 +1,131 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 17.0 + Win32Proj + {04d7a85c-43bb-4696-b9c8-f79c2252eda1} + dashunto + 10.0 + + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + Application + true + v143 + Unicode + + + Application + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + + + + + + + \ No newline at end of file diff --git a/lci/extra/dashun/dashun_to/dashun_to.vcxproj.filters b/lci/extra/dashun/dashun_to/dashun_to.vcxproj.filters new file mode 100644 index 0000000..04e3d9d --- /dev/null +++ b/lci/extra/dashun/dashun_to/dashun_to.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + 源文件 + + + \ No newline at end of file diff --git a/lci/extra/dashun/dashun_to/dashun_to.vcxproj.user b/lci/extra/dashun/dashun_to/dashun_to.vcxproj.user new file mode 100644 index 0000000..88a5509 --- /dev/null +++ b/lci/extra/dashun/dashun_to/dashun_to.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/lci/extra/dashun/regiest.bat b/lci/extra/dashun/regiest.bat new file mode 100644 index 0000000..b389762 --- /dev/null +++ b/lci/extra/dashun/regiest.bat @@ -0,0 +1 @@ +sc create ´ó˳½ű¾ binPath= "C:\Users\90999\Desktop\tws\dashun\x64\Debug\dashun.exe" start= auto DisplayName= "´ó˳½ű¾£¬½ø³ÌÍйܷþÎñ" \ No newline at end of file diff --git a/lci/extra/mgmt/README.md b/lci/extra/mgmt/README.md new file mode 100644 index 0000000..13cf2a9 --- /dev/null +++ b/lci/extra/mgmt/README.md @@ -0,0 +1,6 @@ +# mgmt +这是基于pmc模块的管理平台,负责对子系统进行管理。 + +## 放置秘钥 + +为了和pmc系统通信,我们需要在该目录下放置pmc的rsa私钥 \ No newline at end of file diff --git a/lci/extra/mgmt/_run.sh b/lci/extra/mgmt/_run.sh new file mode 100644 index 0000000..3ca6128 --- /dev/null +++ b/lci/extra/mgmt/_run.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +bash ./_setup.sh +source ./.env/bin/activate +python main.py diff --git a/lci/extra/mgmt/_setup.sh b/lci/extra/mgmt/_setup.sh new file mode 100644 index 0000000..d8965bd --- /dev/null +++ b/lci/extra/mgmt/_setup.sh @@ -0,0 +1,7 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +python3 -m venv .env +#sudo chmod +x .env/bin/activate +source .env/bin/activate +pip install -r requirements.txt -i https://pypi.org/simple + diff --git a/lci/extra/mgmt/app/__init__.py b/lci/extra/mgmt/app/__init__.py new file mode 100644 index 0000000..a224de2 --- /dev/null +++ b/lci/extra/mgmt/app/__init__.py @@ -0,0 +1,14 @@ +from app.login.routes import login_bp +from app.log.routes import log_bp +from app.module.routes import module_bp +from app.process.routes import process_bp +from app.user.routes import user_bp + + +def register_blueprints(app): + # 默认访问家目录 + app.register_blueprint(login_bp, url_prefix='/') + app.register_blueprint(log_bp, url_prefix='/log') + app.register_blueprint(module_bp, url_prefix='/module') + app.register_blueprint(process_bp, url_prefix='/process') + app.register_blueprint(user_bp, url_prefix='/user') diff --git a/lci/extra/mgmt/app/login/__init__.py b/lci/extra/mgmt/app/login/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lci/extra/mgmt/app/login/routes.py b/lci/extra/mgmt/app/login/routes.py new file mode 100644 index 0000000..5365280 --- /dev/null +++ b/lci/extra/mgmt/app/login/routes.py @@ -0,0 +1,113 @@ +import datetime +import hashlib +from functools import wraps + +from pmc import DnfsComm +from dnfs import UsersTable, DnfsTable + +import jwt +from flask import Blueprint, render_template, request, redirect, url_for, current_app, make_response, jsonify + +login_bp = Blueprint('login', __name__, template_folder='templates/login') + + +comm = DnfsComm("http://localhost:8006") + + +def get_user_from_token(): + token = request.cookies.get('token') + if not token: + return None + try: + payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256']) + return payload # 包含 user、user_id、exp 等字段 + except jwt.ExpiredSignatureError: + return None + except jwt.InvalidTokenError: + return None + + +@login_bp.after_request +def add_cors_headers(response): + response.headers['Access-Control-Allow-Origin'] = '*' # 允许所有来源跨域访问,如需限制可替换为具体域名 + response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS' + return response + + +def token_required(f): + @wraps(f) + def decorated(*args, **kwargs): + # 从cookie中获取token + token = request.cookies.get('token') + if not token: + return redirect(url_for('login.index')) + try: + jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256']) + except jwt.ExpiredSignatureError: + return redirect(url_for('login.index')) + except jwt.InvalidTokenError: + return redirect(url_for('login.index')) + return f(*args, **kwargs) + return decorated + + +@login_bp.route('/') +def index(): + return render_template('index.html') + + +@login_bp.route('/api/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form.get('user-name') + password = request.form.get('user-passwd') + password = password.encode("utf-8") + hashed_password = hashlib.sha256(password).hexdigest() + try: + data = comm.get_and_trans(0) + dnfs_tab = DnfsTable(data) + users = dnfs_tab.query_by_title('Users') + table = UsersTable(users.content) + data = table.user_exists(username, hashed_password) + if not data: + return "用户登录失败", 401 + _user_id, _username, _password, _role = data + except DnfsComm.GetFailed: + return "获取数据失败", 500 + except DnfsTable.NotFound: + return "未找到用户表", 404 + except UsersTable.NotFound: + return "用户不存在", 401 + except Exception as e: + return str(e), 404 + # 生成 Token + token = jwt.encode({ + 'user_id': _user_id, + 'username': _username, + 'role': _role, + 'exp': datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(days=3) + }, current_app.config['SECRET_KEY'], algorithm='HS256') + + # 构造 JSON 响应体 + response = make_response(jsonify({ + "redirect": url_for('login.mgmt'), # 跳转路径 + "token": token + })) + + # 设置 Cookie + response.set_cookie('token', token) + return response + else: + return "登录失败" + + +@login_bp.route('/api/mgmt') +@token_required +def mgmt(): + payload = get_user_from_token() + if not payload: + return redirect(url_for('login.index')) + username = payload.get('username') + role = payload.get('role') + return render_template('mgmt.html', username=username, role=role) diff --git a/lci/extra/mgmt/app/module/__init__.py b/lci/extra/mgmt/app/module/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lci/extra/mgmt/app/module/routes.py b/lci/extra/mgmt/app/module/routes.py new file mode 100644 index 0000000..0f2df75 --- /dev/null +++ b/lci/extra/mgmt/app/module/routes.py @@ -0,0 +1,34 @@ +from pmc import PmcComm +from flask import Blueprint, render_template + +module_bp = Blueprint('module', __name__, template_folder='templates/features/module.html') + +pmc = PmcComm('http://localhost:8012') +pmc.Set_RSA_Pri_Key("private_key.pem") +pmc.Try_Get_AES_Key() + + +@module_bp.after_request +def add_cors_headers(response): + response.headers['Access-Control-Allow-Origin'] = '*' # 允许所有来源跨域访问,如需限制可替换为具体域名 + response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS' + return response + + +@module_bp.route('/api/mgmt/module', methods=['GET', 'POST']) +def module(): + data = pmc.list_mods() + modules = data.split('\n') + return render_template('features/module.html', modules=modules) + + +@module_bp.route('/create_module', methods=['GET', 'POST']) +def create_module(mod_name): + pass + + +@module_bp.route('/delete_module', methods=['GET', 'POST']) +def delete_module(mod_name): + pass + diff --git a/lci/extra/mgmt/app/process/__init__.py b/lci/extra/mgmt/app/process/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lci/extra/mgmt/app/process/routes.py b/lci/extra/mgmt/app/process/routes.py new file mode 100644 index 0000000..4723c4b --- /dev/null +++ b/lci/extra/mgmt/app/process/routes.py @@ -0,0 +1,53 @@ +from flask import Blueprint, render_template, jsonify, request +from pmc import PmcComm + + +process_bp = Blueprint('process', __name__, template_folder='templates/features/process.html') + +pmc = PmcComm('http://localhost:8012') +pmc.Set_RSA_Pri_Key("private_key.pem") +pmc.Try_Get_AES_Key() + + +@process_bp.after_request +def add_cors_headers(response): + response.headers['Access-Control-Allow-Origin'] = '*' # 允许所有来源跨域访问,如需限制可替换为具体域名 + response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS' + return response + + +@process_bp.route('/api/mgmt/process', methods=['GET', 'POST']) +def process(): + pid = [] + status = [] + order = [] + ls = pmc.get_list() + if ls != "": + ls_1 = ls.split('\n') + for l in ls_1: + i, j, k = l.split('\t') + pid.append(i) + status.append(j) + order.append(k) + data = [{"pid": p, "status": s, "order": o} for p, s, o in zip(pid, status, order)] + + return render_template('features/process.html', response=data) + + +@process_bp.route('/kill_process', methods=['POST']) +def kill_process(pid): + pmc.kill(pid) + return jsonify({"status": "success"}) + + +@process_bp.route('/clear_process', methods=['POST']) +def clear_process(): + pmc.clear() + return jsonify({"status": "success"}) + + +@process_bp.route('/create_process', methods=['POST']) +def create_process(name): + pmc.start(name) + return jsonify({"status": "success"}) diff --git a/lci/extra/mgmt/app/user/__init__.py b/lci/extra/mgmt/app/user/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lci/extra/mgmt/app/user/routes.py b/lci/extra/mgmt/app/user/routes.py new file mode 100644 index 0000000..b5b9f35 --- /dev/null +++ b/lci/extra/mgmt/app/user/routes.py @@ -0,0 +1,111 @@ +import jwt +import hashlib +from flask import Blueprint, render_template, request, current_app, jsonify +from pmc import DnfsComm +from dnfs import UsersTable, DnfsTable + +user_bp = Blueprint('user', __name__, template_folder='templates/features/user.html') + +comm = DnfsComm("http://localhost:8006") + + + +def get_user_from_token(): + token = request.cookies.get('token') + if not token: + return None + try: + payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256']) + return payload # 包含 user、user_id、exp 等字段 + except jwt.ExpiredSignatureError: + return None + except jwt.InvalidTokenError: + return None + + +def get_node(): + try: + data = comm.get_and_trans(0) + except DnfsComm.GetFailed: + return "获取数据失败", 500 + for item in data: + if item['title'] == 'Users': + node_id = item['id'] + node_content = item['content'] + return node_id, node_content + return None + + +@user_bp.after_request +def add_cors_headers(response): + response.headers['Access-Control-Allow-Origin'] = '*' # 允许所有来源跨域访问,如需限制可替换为具体域名 + response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' + response.headers['Access-Control-Allow-Methods'] = 'GET,POST,PUT,DELETE,OPTIONS' + return response + + +@user_bp.route('/api/mgmt/user', methods=['GET', 'POST']) +def user(): + try: + data = comm.get_and_trans(0) + dnfs_tab = DnfsTable(data) + users = dnfs_tab.query_by_title('Users') + table = UsersTable(users.content) + crt_dict = lambda user: {'user_id': user.id, 'username': user.name, 'role': user.privileges} + user_list = [crt_dict(user) for user in table.arr] + except DnfsComm.GetFailed: + return "获取数据失败", 500 + except DnfsTable.NotFound: + return "未找到用户表", 404 + except UsersTable.NotFound: + return "用户不存在", 401 + except Exception as e: + return str(e), 404 + payload = get_user_from_token() + if not payload: + return jsonify({"error": "未授权访问"}), 401 + + user_id = payload.get('user_id') + role = payload.get('role') + + return render_template('features/user.html', + response=user_list, + current_user_id=user_id, + current_role=role) + + +@user_bp.route('/add_user', methods=['POST']) +def add_user(): + node_id, msg = get_node() + username = request.form.get('username') + password = request.form.get('password') + hashed_password = hashlib.sha256(password.encode("utf-8")).hexdigest() + role = "normal" + table = UsersTable(msg) + table.add_user(username, hashed_password, role) + table = str(table) + comm.upd(node_id, 0, 'Users', table) + return jsonify({"message": "用户添加成功"}) + + +@user_bp.route('/change_password', methods=['POST']) +def change_password(): + node_id, msg = get_node() + user_id = request.form.get('user_id') + new_password = request.form.get('new_password') + hashed_password = hashlib.sha256(new_password.encode("utf-8")).hexdigest() + table = UsersTable(msg) + table.change_password(int(user_id), hashed_password) + table = str(table) + comm.upd(node_id, 0, 'Users', table) + return jsonify({"message": "密码修改成功"}) + + +@user_bp.route('/delete_user', methods=['POST']) +def delete_user(user_id): + node_id, msg = get_node() + table = UsersTable(msg) + table.del_user(user_id) + table = str(table) + comm.upd(node_id, 0, 'Users', table) + return jsonify({"message": "用户删除成功"}) diff --git a/lci/extra/mgmt/main.py b/lci/extra/mgmt/main.py new file mode 100644 index 0000000..409c0fe --- /dev/null +++ b/lci/extra/mgmt/main.py @@ -0,0 +1,17 @@ +from app import register_blueprints +from flask import Flask +from waitress import serve + +# 初始化Flask应用 +app = Flask(__name__) + +# 设置一个密钥 +app.secret_key = 'secret_key' + +# 注册蓝图 +register_blueprints(app) + + +if __name__ == '__main__': + #app.run(host='0.0.0.0', port=8009, debug=True) + serve(app, host="0.0.0.0", port=8009) diff --git a/lci/extra/mgmt/requirements.txt b/lci/extra/mgmt/requirements.txt new file mode 100644 index 0000000..5e8107d --- /dev/null +++ b/lci/extra/mgmt/requirements.txt @@ -0,0 +1,5 @@ +../_pmc +../_dnfs +flask +PyJWT +waitress diff --git a/lci/extra/mgmt/static/features/log.css b/lci/extra/mgmt/static/features/log.css new file mode 100644 index 0000000..e69de29 diff --git a/lci/extra/mgmt/static/features/module.css b/lci/extra/mgmt/static/features/module.css new file mode 100644 index 0000000..6f768e1 --- /dev/null +++ b/lci/extra/mgmt/static/features/module.css @@ -0,0 +1,35 @@ +.top-bar-con { + width: 230px; + display: flex; + justify-content: space-between; +} + +.newBtn, +.flushBtn, +.removeBtn { + width: 84px; + height: 42px; + font-size: 16px; + font-weight: bold; + letter-spacing: 1px; + cursor: pointer; +} + +.newBtn { + background-color: #5cff007d; +} + +.flushBtn { + background-color: #5757577d; +} + +.removeBtn { + background-color: #ff00007d; + color: #000000b8; +} + +td { + width: 180px; + text-align: center; + font-size: 20px; +} \ No newline at end of file diff --git a/lci/extra/mgmt/static/features/process.css b/lci/extra/mgmt/static/features/process.css new file mode 100644 index 0000000..ad10d6b --- /dev/null +++ b/lci/extra/mgmt/static/features/process.css @@ -0,0 +1,74 @@ +.newBtn, +.flushBtn, +.stopBtn { + width: 84px; + height: 42px; + font-size: 16px; + font-weight: bold; + letter-spacing: 1px; + cursor: pointer; +} + +.newBtn { + background-color: #5cff007d; +} + +.flushBtn { + background-color: #5757577d; + margin-left: 60px; +} + +.stopBtn { + background-color: #ff00007d; +} + +.text, +.title { + font-size: 20px; +} + +td, +th { + width: 180px; + text-align: center; +} + +#inProgressText { + font-size: 20px; + margin-top: 5px; + letter-spacing: 2px; +} + +/* modal window style */ +.modal-con { + width: 100%; + height: 100%; + background-color: rgba(68, 94, 65, 0.77); + position: absolute; + left: 0px; + top: 0px; + display: none; + justify-content: center; + z-index: 1; +} + +.modal-con .window { + width: 200px; + height: 120px; + background-color: #5cff007d; + padding: 0px 10px; +} + +.modal-con .window .top-bar { + display: flex; + justify-content: end; +} + +.modal-con .window .top-bar .close-btn { + cursor: pointer; +} + +.modal-con .window .create-btn, +.modal-con .window .input .input-area { + margin-top: 5px; +} \ No newline at end of file diff --git a/lci/extra/mgmt/static/features/user.css b/lci/extra/mgmt/static/features/user.css new file mode 100644 index 0000000..faff9c6 --- /dev/null +++ b/lci/extra/mgmt/static/features/user.css @@ -0,0 +1,41 @@ +.top-bar-con { + width: 230px; + display: flex; + justify-content: space-between; +} + +td { + width: 180px; + text-align: center; + font-size: 20px; +} + +.addUserBtn, +.flushBtn, +.changePasswdBtn, +.deleteUserBtn { + width: 84px; + height: 42px; + font-size: 16px; + font-weight: bold; + letter-spacing: 1px; + cursor: pointer; +} + +.addUserBtn { + background-color: #5cff007d; +} + +.flushBtn { + background-color: #5757577d; +} + +.changePasswdBtn { + background-color: #e6db407d; + color: #fb0202b0; +} + +.deleteUserBtn { + background-color: #ff00007d; + color: #000000b8; +} \ No newline at end of file diff --git a/lci/extra/mgmt/static/index.css b/lci/extra/mgmt/static/index.css new file mode 100644 index 0000000..15a0402 --- /dev/null +++ b/lci/extra/mgmt/static/index.css @@ -0,0 +1,39 @@ +body { + display: flex; + justify-content: center; +} + +.main { + background-color: rgb(233, 233, 233); + padding: 20px 10px; +} + +.main .title { + font-weight: bold; +} + +.main .name-con, +.main .passwd-con { + display: flex; + justify-content: center; +} + +.main .name-con { + margin-top: 20px; +} + +.main .passwd-con { + margin-top: 10px; +} + +.main .name-con .user-name-text, +.main .passwd-con .user-passwd-text { + width: 100px; +} + +.main .login-con { + width: 100%; + display: flex; + justify-content: center; + margin-top: 10px; +} \ No newline at end of file diff --git a/lci/extra/mgmt/static/mgmt.css b/lci/extra/mgmt/static/mgmt.css new file mode 100644 index 0000000..607dc05 --- /dev/null +++ b/lci/extra/mgmt/static/mgmt.css @@ -0,0 +1,54 @@ +:root { + --listMargin: 15%; +} + +* { + margin: 0px; + padding: 0px; +} + +.top-con { + display: flex; +} + +.top-con >*{ + margin-left: 25px; + font-size: 20px; +} + +.top-con div button { + font-size: 16px; +} + +.main { + width: 100%; + height: 600px; + display: flex; +} + +.feature-list { + width: 150px; + height: 100%; + background-color: #FFFFCC; + padding: 0px 10px 0px 10px; + overflow-y: scroll; +} + +.feature-list .item { + width: 100%; + height: 50px; + display: flex; + justify-content: center; + align-items: center; + background-color: #0066cc; + color: #fff; + font-size: 18px; + font-weight: bold; + margin-top: var(--listMargin); + cursor: pointer; +} + +.pages { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/lci/extra/mgmt/templates/features/log.html b/lci/extra/mgmt/templates/features/log.html new file mode 100644 index 0000000..0a0389e --- /dev/null +++ b/lci/extra/mgmt/templates/features/log.html @@ -0,0 +1,12 @@ + + + + + + Document + + + + log + + \ No newline at end of file diff --git a/lci/extra/mgmt/templates/features/module.html b/lci/extra/mgmt/templates/features/module.html new file mode 100644 index 0000000..e2696ca --- /dev/null +++ b/lci/extra/mgmt/templates/features/module.html @@ -0,0 +1,35 @@ + + + + + + + Document + + + + + +
+ + +
+ + + + + + + {% for item in modules %} + + + + + {% endfor %} + +
模块名操作
{{ item }} + +
+ + + \ No newline at end of file diff --git a/lci/extra/mgmt/templates/features/process.html b/lci/extra/mgmt/templates/features/process.html new file mode 100644 index 0000000..5468f9e --- /dev/null +++ b/lci/extra/mgmt/templates/features/process.html @@ -0,0 +1,199 @@ + + + + + + + Document + + + + + + + + + + + + + + + + + + {% for item in response %} + + + + + + + {% endfor %} + + +
PID状态命令操作
{{ item.pid }}{{ item.status }}{{ item.order }}
+
+ + + + + + + diff --git a/lci/extra/mgmt/templates/features/user.html b/lci/extra/mgmt/templates/features/user.html new file mode 100644 index 0000000..167420c --- /dev/null +++ b/lci/extra/mgmt/templates/features/user.html @@ -0,0 +1,162 @@ + + + + + + + Document + + + + + +
+ + +
+ + + + + + + + + + {% for item in response %} + + + + + + + {% endfor %} + +
用户ID用户名用户角色操作
{{ item.user_id}}{{ item.username }}{{ item.role }} + {% if current_role == "admin" %} + + {% if item.username != "admin" %} + + {% endif %} + {% endif %} + + {% if current_role != "admin" and current_user_id == item.user_id %} + + {% endif %} +
+ + + + + \ No newline at end of file diff --git a/lci/extra/mgmt/templates/index.html b/lci/extra/mgmt/templates/index.html new file mode 100644 index 0000000..59cfcd4 --- /dev/null +++ b/lci/extra/mgmt/templates/index.html @@ -0,0 +1,88 @@ + + + + + + + pmc management + + + + + +
+
Welcome to pmc management system
+
+
Name:
+ +
+
+
Password:
+ +
+ +
+ + + + + \ No newline at end of file diff --git a/lci/extra/mgmt/templates/mgmt.html b/lci/extra/mgmt/templates/mgmt.html new file mode 100644 index 0000000..8132c34 --- /dev/null +++ b/lci/extra/mgmt/templates/mgmt.html @@ -0,0 +1,87 @@ + + + + + + + management page + + + + + + + +
+
当前用户: {{ username }}
+
当前角色: {{ role }}
+
+ +
+
+
+
+
+ +
+
+ + + + + \ No newline at end of file diff --git a/lci/extra/phs/.gitignore b/lci/extra/phs/.gitignore new file mode 100644 index 0000000..0837616 --- /dev/null +++ b/lci/extra/phs/.gitignore @@ -0,0 +1,29 @@ +.git/ +.vscode/ +.idea/ +.cache/ + +# +init.csv + + +# cangjie +build/ +target/ +output/ +module-resolve.json +module-lock.json +cjpm.lock +.cjpm-history +*.macrocall +*.gcda +*.gcno + + +# 其他 +log +report +tmp + +# ide +.arts diff --git a/lci/extra/phs/LICENSE b/lci/extra/phs/LICENSE new file mode 100644 index 0000000..63b4b68 --- /dev/null +++ b/lci/extra/phs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) [year] [fullname] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/lci/extra/phs/README.md b/lci/extra/phs/README.md new file mode 100644 index 0000000..2e4db2a --- /dev/null +++ b/lci/extra/phs/README.md @@ -0,0 +1,24 @@ + +## 为什么要做一个这样的项目 + +当时想做一个树莓派机器人,是准备用python来写控制程序,可是当时python的多线程能力较弱, + +所以想到使用子系统,可是我没有VPN,无法安装ROS,所以就自己写了一个进程托管程序 + +## 使用方式 + +### 启动列表 +```bash +# 创建启动列表,每一行是一个进程 +touch init.csv +``` + +### 创建进程 +```bash +curl -X POST http://localhost:5200/api/v2/create -d '["ls"] +``` + +### 进程列表 +```bash +curl http://localhost:5200/api/v2/list +``` diff --git a/lci/extra/phs/_run.sh b/lci/extra/phs/_run.sh new file mode 100644 index 0000000..bb5c279 --- /dev/null +++ b/lci/extra/phs/_run.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +#source ./.env/bin/activate +source /cangjie/envsetup.sh +exec cjpm run diff --git a/lci/extra/phs/cjpm.toml b/lci/extra/phs/cjpm.toml new file mode 100644 index 0000000..fd5453a --- /dev/null +++ b/lci/extra/phs/cjpm.toml @@ -0,0 +1,24 @@ +[package] + cjc-version = "1.0.0" + name = "phs" + description = "nothing here" + version = "1.0.0" + target-dir = "" + src-dir = "" + output-type = "executable" + compile-option = "" + override-compile-option = "" + link-option = "" + package-configuration = {} + +[dependencies] +[target.x86_64-unknown-linux-gnu] + [target.x86_64-unknown-linux-gnu.bin-dependencies] + path-option = ["/stdx/linux_x86_64_llvm/static/stdx"] +[target.aarch64-unknown-linux-gnu] + [target.aarch64-unknown-linux-gnu.bin-dependencies] + path-option = ["/stdx/linux_aarch64_llvm/static/stdx"] +[target.x86_64-w64-mingw32] # 系统架构和 OS 信息 + [target.x86_64-w64-mingw32.bin-dependencies] + path-option = ["C:\\stdx\\windows_x86_64_llvm\\dynamic\\stdx"] # stdx 路径根据实际情况配置 + diff --git a/lci/extra/phs/phs.service b/lci/extra/phs/phs.service new file mode 100644 index 0000000..c1b2956 --- /dev/null +++ b/lci/extra/phs/phs.service @@ -0,0 +1,19 @@ +[Unit] +Description=TxL.phs +After=network.target +Wants=network.target + +[Service] +User=root +Group=root +WorkingDirectory=/root/___TxL/TestSuits/phs +ExecStart=bash /root/___TxL/TestSuits/phs/_run.sh +Restart=always +RestartSec=10 +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=mozart-python-host +Environment=PYTHONUNBUFFERED=1 + +[Install] +WantedBy=multi-user.target diff --git a/lci/extra/phs/src/Th.cj b/lci/extra/phs/src/Th.cj new file mode 100644 index 0000000..511fc2a --- /dev/null +++ b/lci/extra/phs/src/Th.cj @@ -0,0 +1,312 @@ +package phs +import std.sync.*; + +/* + * Status 状态 + * + * FIXME: 在枚举中定义操作函数 + */ +enum Stat { + SHUT | STOP | START | RUNNING +} + + +/* + * Finite Status Machine 有限状态机 + * + * + * FIXME(TritiumQin): 1. 柯里化 + * + * FIXME(qing): 支持自定义状态 + */ +open class Fsm { + + + /* 状态枚举 */ + private var stat: Stat = STOP + + /* 线程安全 */ + private let mtx: Mutex = Mutex() + + /* + * 条件变量 + * + * FIXME: 我不知道这么写意义何在 + */ + private let condition: Condition = synchronized(mtx) { + mtx.condition() + } + + /* 辅助条件变量的布尔标志 */ + private var flag: Bool = true + + + /* ---------------------------------------------- */ + + /* + * 阻塞等待状态改变,可以传入一个谓词,以确定什么时候终止 + * + * 在该回调函数中返回true,则等待不会停止 + */ + public func wait(keep!: (Stat) -> Bool = {_ => false}) { + synchronized(mtx) { + flag = true + while(flag || keep(stat)) { + condition.wait() + } + } + } + + /* ---------------------------------------------- */ + + /* + * 对状态机进行某种操作,输入一个谓词。 + * + * 会激活堵塞线程 + */ + public func doc(p: (Stat) -> Stat): Stat { + synchronized(mtx) { + stat = p(stat) + flag= false // 试图唤醒阻塞的线程 + condition.notifyAll() + return stat + } + } + + /* + * 对状态机进行某种操作,输入一个谓词。 + * + * 不会激活堵塞线程 + */ + public func dop(p: (Stat) -> Stat): Stat { + synchronized(mtx) { + stat = p(stat) + return stat + } + } + + +} + + +/* Controllable Thread 可控制线程 + * + * FIXME(花间岛): + * 1. 使用async语法糖 + * 2. 封装iocp + */ +open class Th { + + /* 持有线程类型 */ + private var fut: Option> = None + + /* 持有状态机类型 */ + private let fsm: Fsm = Fsm() + + /*----------------------------------------------*/ + + /* 持有静止事件回调 */ + private var StopEvent: Option<() -> Unit> = None + + /* 持有唤醒事件回调 */ + private var WakeEvent: Option<() -> Unit> = None + + /* 持有循环事件回调 */ + private var LoopEvent: Option<() -> Unit> = None + + /* 持有清理事件回调 */ + private var ClearEvent: Option<() -> Unit> = None + + /* 持有线程主函数回调 */ + private var Main: Option<() -> Int64> = None // 线程主函数 + + /*----------------------------------------------*/ + + /* 使用谓词检查线程状态 */ + public func chkp(): Stat { + return fsm.dop({ stat => return stat }) + } + + /*----------------------------------------------*/ + + /* 进入关闭状态 */ + public func shut() { + fsm.doc({ _ => return SHUT }) + } + + /* 进入静止态 */ + public func stop() { + fsm.doc({ _ => return STOP }) + } + + /* 进入启动状态 */ + public func start() { + fsm.doc({ _ => return START }) + } + + /* 进入运行态 */ + public func run() { + fsm.doc({ _ => return RUNNING }) + } + + /*----------------------------------------------*/ + + /* 状态机是否处于静止态 */ + public func isStop() { + return match( chkp() ) { + case STOP => true + case _ => false + }} + + /* 状态机是否处于关闭态 */ + public func isShut() { + return match( chkp() ) { + case SHUT => true + case _ => false + }} + + /* 状态机是否处于开始状态 */ + public func isStart() { + return match( chkp() ) { + case START => true + case _ => false + }} + + /* 状态机是否处于运行态 */ + public func isRunning() { + return match( chkp() ) { + case RUNNING => true + case _ => false + }} + + /*----------------------------------------------*/ + + /* 扮演函数,即设置线程事件 */ + public func Act( + + /* 静止事件 */ + stop!: Option<() -> Unit> = None, + + /* 唤醒事件 */ + wake!: Option<() -> Unit> = None, + + /* 循环事件 */ + loop!: Option<() -> Unit> = None, + + /* 清理事件 */ + clear!:Option<() -> Unit> = None, + + + /* 线程主函数 */ + mainloop!: Option<() -> Int64>= None + + ) + + { + + /* 只有静止态才能进行设置 */ + if (!isStop()) { return; } + + /* ------------------------------------------------- */ + + /* 设置静止事件,确保退出了静止态 */ + StopEvent = stop ?? {=> fsm.wait(keep: {stat => + match(stat) { + case STOP => true /* 保持等待 */ + case _ => false + } + })} + + /* 唤醒事件,默认直接进入运行态 */ + WakeEvent = wake ?? {=> this.run()} + + /* 循环事件,默认进行延时 */ + LoopEvent = loop ?? {=> sleep(100 * Duration.millisecond)} + + /* 清理事件,默认什么都不做 */ + ClearEvent= clear?? {=> ;} + + /* ------------------------------------------------- */ + + /* 线程主函数 */ + Main = mainloop ?? {=> + + /* 回字形循环 外层 */ + while (!isShut()) { + this.inner() + } + + + return 0 + } + + /* ------------------------------------------------- */ + + } + + + /* ------------- 回字形循环 内层 -------------- */ + + private func inner() { + + /* 静止状态 */ + while(isStop()) { StopEvent.getOrThrow()() } + + /* 唤醒事件 */ + if (isStart()) { WakeEvent.getOrThrow()() } + + /* 运行状态 */ + while(isRunning()) { LoopEvent.getOrThrow()() } + + /* 清理事件 */ + ClearEvent.getOrThrow()() + + } + + /* --------------------------------------------- */ + + /* + * 创建资源,可控线程苏醒 + * + * 如果在调用中等待线程启动,可能会造成死锁 + * 想了想觉得也没有这个必要 + */ + public func wake() { + + + /* 存在微小的冲突可能,所以我不让它进入静止态 */ + this.start() + + + /* 创建卵 */ + fut = Some>(spawn { + Main.getOrThrow()() + }) + + + /* 等启动 + * + * 20251020(qing): 如果线程启动太快,该等待可能会导致死锁 + */ + //fsm.wait(keep: {stat => match(stat) { + // case START => true + // case _ => false + //}}) + } + + /* 等待线程结束 */ + public func wait() { + let f = fut.getOrThrow() + return f.get() + } + + /* + * 关闭线程,然后等待线程结束 + */ + public func shut_and_wait() { + shut() + wait() + } + + +} diff --git a/lci/extra/phs/src/main.cj b/lci/extra/phs/src/main.cj new file mode 100644 index 0000000..69431c6 --- /dev/null +++ b/lci/extra/phs/src/main.cj @@ -0,0 +1,211 @@ +package phs + +import std.io.*; +import std.fs.*; +import std.collection.*; +import std.sync.*; +import std.process.*; +import stdx.net.http.*; +import stdx.encoding.json.*; + +const ADDR = "127.0.0.1" /* 监听IP地址 */ +const PORT = 5200u16 /* 端口 UInt16类型 */ + + +class Ps { + private let ps = LinkedList() + private let mtx = Mutex() + + /* 创建进程 */ + public func create(arr: Array) { + let path = arr[0] + let args = arr[1..] + let subp: SubProcess = launch(path, args, + //stdIn: ProcessRedirect.Discard, /* WINDOWS中不支持输入重定向 */ + //stdOut: ProcessRedirect.Discard, /* 加了这行之后就在控制台看不到输出了 */ + //stdErr: ProcessRedirect.Discard + ) + this.clear() /* 清理进程 */ + synchronized(mtx) { + ps.addLast(subp) + return; + } + } + + /* 返回进程列表 */ + public func list() { + var msg = "" +println('1') + this.clear() /* 清理进程,有锁 */ +println('2') + synchronized(mtx) { +println('3') + for (p in ps) { + if (msg != "") { msg += "\n"; } + msg += '${p.pid.toString()}\t' + msg += '${p.command} ' + //for (i in p.arguments) { /* 加上这个会失败 */ + // msg += '${i} ' + //} + /* 启动时间 */ + msg += '\t${p.userTime.toString()}' + } +println('4') + } + return msg; + } + + /* 杀死已经存在的进程 */ + public func kill(pid: Int64) { + this.clear() /* 清理 */ + synchronized(mtx) { + for (p in ps) { + if (p.pid == pid) { + p.terminate(force: true) + return + } + } + } + } + + /* + * 进程自启动 + * + * FIXME: 支持注释 + */ + public func autoRun(csvpath: String) { + let file = File(csvpath, Read) + let bytes = readToEnd(file) + let ctt = String.fromUtf8(bytes) + let cmds = ctt.split("\n", removeEmpty: true) + for (cmd in cmds) { + try{ + let arr = cmd.split(" ", removeEmpty: true) + this.create(arr) + } catch (exp: Exception) { + ; + } + } + file.close() + } + + /* 清理已经死去的进程,默认不加锁 */ + private func clear() { + synchronized(mtx) { + let len = ps.size + for (i in (len-1)..=0 : -1) { + try { + let p = ps.nodeAt(i).getOrThrow() +println("start...") + p.value.wait(timeout: 1 * Duration.millisecond) /* 进程有没有退出 */ +println("end...") + ps.remove(p) + } + catch (exp: TimeoutException) { /* 如果进程没有结束,会运行到这里 */ + ; +println("skip...") + } + } + } + } + +} + + +/* + * 将JSON数组转为字符串的数组 + * + * Json对象的每个元素只能是字符串,否则会报错 + */ +func Jarr_to_arr(arr: JsonArray): Array { + let len = arr.size() // Json数组的长度 + let ret = Array(len, repeat: "") + for (i in 0..len) { + let option: Option = arr.get(i) + let jitem: JsonValue = option.getOrThrow() + let jstr: JsonString = jitem.asString() + let str: String = jstr.getValue() + ret[i] = str + } + + + return ret +} + +/* cj命令行参数不包含可执行文件名 */ +main(_: Array): Int64 { + + /* 进程组 */ + let ps = Ps() + ps.autoRun("./init.csv") + + + /* 创建http服务器 */ + let server: Server = ServerBuilder() + .addr(ADDR) /* 设置地址 */ + .port(PORT) /* 设置端口 */ + .build() + + /* 创建进程的HTTP方法 */ + server.distributor.register("/api/v2/create", { context => + if (context.request.method == "POST") { + let content = StringReader(context.request.body).readToEnd() /* 阅读请求体 */ + let array = JsonValue.fromStr(content).asArray() /* 解析json格式的请求体 */ + let net_args: Array = Jarr_to_arr(array) /* json数组转原生数组 */ + ps.create(net_args) + + /* ---- 准备响应 ---- */ + let Headers = HttpHeaders() + Headers.add("Content-Type", "text/html; charset=utf-8;") + context.responseBuilder.setHeaders(Headers) + context.responseBuilder.body('OK') + } + }) + + /* + * 输出进程列表的HTTP方法 + */ + server.distributor.register("/api/v2/list", { context => + if (context.request.method == "GET") { + +println('a') + /* 准备表单字符串 */ + let ret = ps.list() + +println('b') + /**** 准备响应 ****/ + let Headers = HttpHeaders() + Headers.add("Content-Type", "text/html; charset=utf-8;") + context.responseBuilder.setHeaders(Headers) + context.responseBuilder.body(ret) + +println('c') + } + }) + + /* 杀死一个已经存在的进程 */ + server.distributor.register("/api/v2/kill", { context => + if (context.request.method == "POST") { + let content = StringReader(context.request.body).readToEnd() /* 阅读请求体 */ + let target_pid = JsonValue.fromStr(content) + .asObject() + .get("pid") + .getOrThrow() + .asInt() + .getValue() + ps.kill(target_pid) + + /**** 准备响应 ****/ + let Headers = HttpHeaders() + Headers.add("Content-Type", "text/html; charset=utf-8;") + context.responseBuilder.setHeaders(Headers) + context.responseBuilder.body("done") + } + }) + + /* 服务器开始运行 */ + server.serve() + return 0 + +} + diff --git a/lci/extra/phs/test/crt.py b/lci/extra/phs/test/crt.py new file mode 100644 index 0000000..27c8f1b --- /dev/null +++ b/lci/extra/phs/test/crt.py @@ -0,0 +1,66 @@ +import requests +import json + + +def create_process(cmd_list, url="http://localhost:5200/api/v2/create"): + """创建任意进程 + + Args: + cmd_list (list): 命令和参数列表,例如 ["timeout", "/t", "1000"] + url (str, optional): 请求URL,默认为 "http://localhost:5200/api/v2/create" + + Returns: + requests.Response: 响应对象 + """ + try: + # 发送POST请求 + response = requests.post(url, data=json.dumps(cmd_list), timeout=30) + + # 返回响应对象供进一步处理 + return response + except requests.exceptions.RequestException as e: + print(f"创建进程失败: {e}") + return None + + +def create_process_with_output(cmd_list, url="http://localhost:5200/api/v2/create"): + """创建任意进程并打印输出 + + Args: + cmd_list (list): 命令和参数列表,例如 ["timeout", "/t", "1000"] + url (str, optional): 请求URL,默认为 "http://localhost:5200/api/v2/create" + + Returns: + dict or str: 响应内容,JSON解析后的字典或原始文本 + """ + response = create_process(cmd_list, url) + + if response is None: + return None + + # 打印响应状态码 + print(f"响应状态码: {response.status_code}") + + # 尝试解析响应内容为JSON格式并打印 + try: + response_json = response.json() + print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}") + return response_json + except json.JSONDecodeError: + print(f"响应内容(非JSON格式): {response.text}") + return response.text + + +if __name__ == "__main__": + # 示例用法 + # 创建一个timeout进程,延迟1000毫秒 + cmd = ["timeout", "/t", "1000"] + + # 使用默认URL + print("使用默认URL:") + create_process_with_output(cmd) + + # 示例:使用自定义URL(注释掉,可根据需要取消注释) + # print("\n使用自定义URL:") + # custom_url = "http://localhost:5200/api/v2/create" + # create_process_with_output(cmd, custom_url) diff --git a/lci/extra/phs/test/test_process_create_win.py b/lci/extra/phs/test/test_process_create_win.py new file mode 100644 index 0000000..13343bb --- /dev/null +++ b/lci/extra/phs/test/test_process_create_win.py @@ -0,0 +1,30 @@ +import requests +import json + +def test_create_process(): + """测试访问phs web服务的create接口""" + # 设置请求URL + url = "http://localhost:5200/api/v2/create" + + # 设置请求数据 + data = ["timeout", "/t", "1000"] + + # 发送POST请求 + response = requests.post(url, data=json.dumps(data)) + + # 打印响应状态码 + print(f"响应状态码: {response.status_code}") + + # 尝试解析响应内容为JSON格式并打印 + try: + response_json = response.json() + print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}") + except json.JSONDecodeError: + print(f"响应内容(非JSON格式): {response.text}") + + # 返回响应对象供进一步处理 + return response + +if __name__ == "__main__": + # 执行测试函数 + test_create_process() \ No newline at end of file diff --git a/lci/extra/phs/test/test_process_kill_win.py b/lci/extra/phs/test/test_process_kill_win.py new file mode 100644 index 0000000..883f3a9 --- /dev/null +++ b/lci/extra/phs/test/test_process_kill_win.py @@ -0,0 +1,44 @@ +import requests +import json +import argparse + + +def test_kill_process(pid): + """测试访问phs web服务的kill接口""" + # 设置请求URL + url = "http://localhost:5200/api/v2/kill" + + # 构造请求消息体 + payload = { + "pid": pid + } + + # 发送POST请求 + response = requests.post(url, json=payload) + + # 打印响应状态码 + print(f"响应状态码: {response.status_code}") + + # 尝试解析响应内容为JSON格式并打印 + try: + response_json = response.json() + print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}") + except json.JSONDecodeError: + print(f"响应内容(非JSON格式): {response.text}") + + # 返回响应对象供进一步处理 + return response + + +if __name__ == "__main__": + # 创建命令行参数解析器 + parser = argparse.ArgumentParser(description="测试访问phs web服务的kill接口") + + # 添加pid参数 + parser.add_argument("pid", type=int, help="要杀死的进程ID") + + # 解析命令行参数 + args = parser.parse_args() + + # 执行测试函数,传入命令行参数中的pid + test_kill_process(args.pid) diff --git a/lci/extra/phs/test/test_process_list_win.py b/lci/extra/phs/test/test_process_list_win.py new file mode 100644 index 0000000..45edcdf --- /dev/null +++ b/lci/extra/phs/test/test_process_list_win.py @@ -0,0 +1,27 @@ +import requests +import json + +def test_create_process(): + """测试访问phs web服务的create接口""" + # 设置请求URL + url = "http://localhost:5200/api/v2/list" + + # 发送POST请求 + response = requests.get(url) + + # 打印响应状态码 + print(f"响应状态码: {response.status_code}") + + # 尝试解析响应内容为JSON格式并打印 + try: + response_json = response.json() + print(f"响应内容: {json.dumps(response_json, indent=2, ensure_ascii=False)}") + except json.JSONDecodeError: + print(f"响应内容(非JSON格式): {response.text}") + + # 返回响应对象供进一步处理 + return response + +if __name__ == "__main__": + # 执行测试函数 + test_create_process() \ No newline at end of file diff --git a/lci/extra/qemu_run_appimage/LICENSE b/lci/extra/qemu_run_appimage/LICENSE new file mode 100644 index 0000000..63f5ec4 --- /dev/null +++ b/lci/extra/qemu_run_appimage/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 gopsc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lci/extra/qemu_run_appimage/README.md b/lci/extra/qemu_run_appimage/README.md new file mode 100644 index 0000000..0be57e2 --- /dev/null +++ b/lci/extra/qemu_run_appimage/README.md @@ -0,0 +1,91 @@ +## qemu_run_appimage是什么? + +这个项目源于我想用qemu-user运行AppImage的想法。 + +qemu-user是一款支持多种架构的能够虚拟化运行单个程序的虚拟机软件,而AppImage是一款能够打包出单文件应用的工具。 + +## 跨架构运行的障碍是什么? + +Linux系统支持许多架构,这些架构的机器码、汇编语言都是有差异的,所以不同架构的系统在一般情况下是无法混合使用的,qemu虚拟机能够解决这个痛点,但是这需要一些技巧。 + +通常而言,一个程序除了在编译阶段静态链接了许多库,出于一些原因的考量,它也会在运行时动态地加载一些动态库文件。 + +使用qemu-user跨架构运行,常常就会出现单个文件能够执行,但是动态链接库找不到的问题。 + +## AppImage起到一个什么作用? + +AppImage能够将许多文件打包成一个二进制程序,你双击运行它就能够直接执行,因为关键的动态连接库都包含在里面了,通过一些技术手段让程序能够访问到。 + +所以我们能够将程序以及动态库打包成单个可执行程序,就有了能够虚拟化运行该程序的先决条件。 + +## 如何使用qemu-user运行AppImage + +通常而言,AppImage里面会有一个叫AppRun的启动脚本,运行AppImage会使用shell解释器启动它,然后该脚本配置好环境,再由它启动目标程序。 + +但是qemu-user虚拟出的进程往往无法在宿主机系统中找到与它架构相对应的shell,所以就无法执行常规方式打包的AppImage文件。 + +那我通过与deepseek的深度交流,最终解决了这个问题。 + +我的思路有两个,一是打包AppImage时将AppRun编译成二进制文件,这个办法我经过了验证,是可行的。 + +还有一个办法是再打包一个shell解释器进去,这个我还没有尝试、 + +在运行时,我采用qemu-user提取出AppImage中的所有的文件,并且放在一个临时文件夹,然后在设置引用环境为该文件夹的方式下通过qemu-user执行其中的AppRun,应该就能够启动程序。 + +目前已经尝试了在树莓派上运行x86_64架构的一系列工具,包含ls命令、bash解释器、python3解释器,都能够成功,接下来我还会对网络等功能进行测试。 + +## 这个方法有哪些缺点? + +我像一些朋友展示了这个方式,能够运行测试用例,但是他们说qemu的速度很慢,我了解了一下,qemu-user的性能损耗可能在2倍以内,一般的程序似乎还是可以接受,qemu虚拟机完整情况下的确较慢,性能损耗能够达到8~10倍。 + +所以一些开发者对常见架构进行了深度优化,成果比如box64(Arm64平台运行X86程序)、LATX(LA64平台运行x86程序),这些程序虽然支持的架构没有qemu-user多,在一些平台上可能也需要单独配置一些东西,但是在它们支持的架构下拥有更好的性能,在这里也推荐大家使用。 + +## 我的一些别的想法 + +既然qemu-user能够进行跨架构的实时翻译,那我们可能也能做到将一个二进制文件直接再编译成其他架构的二进制文件?这是我的一个想法。 + +## 项目逻辑与使用方法 + +项目中的auto-appimage1.sh这是一个打包脚本,能够在要运行的目标架构上打包出包含所有链接库的AppImage文件,且其中的入口程序AppRun是二进制的。 + +该脚本的使用方式如下: + +```bash auto-appimage1.sh ``` + +目前这个脚本仅能打包x86的程序,如果要在别的平台打包AppImage,可能需要进行调整。 + +qemu_run2.sh是在宿主机上的启动脚本,其中使用了qemu-user-static系列工具创建虚拟环境,static后缀的意思是这个工具是静态编译的,如果你的架构上没有这个软件,请安装它的非静态版本qemu-user,然后将其中的qemu-*-static都改为qemu-* + +通过一下方式使用它: + +```bash qemu_run2.sh ``` + +ls.AppImage是x86_64架构下的ls命令打包,是测试用例。 + +该项目的依赖: + +--------------- + +打包机器依赖项: + +appimagetool需要在github下载制品,并且添加可执行权限放到环境变量里。 + +```apt install fuse libfuse2``` + +--------------- + +宿主机依赖: + +```apt install qemu-user-static``` + +或者 + +```apt install aemu-user``` + + ———————————————— + +版权声明:本文为CSDN博主「gapcuda」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 +原文链接:https://blog.csdn.net/gapcuda/article/details/156559857 + + + (这是我自己的csdn账号) \ No newline at end of file diff --git a/lci/extra/qemu_run_appimage/auto-appimage1.sh b/lci/extra/qemu_run_appimage/auto-appimage1.sh new file mode 100644 index 0000000..f1c9585 --- /dev/null +++ b/lci/extra/qemu_run_appimage/auto-appimage1.sh @@ -0,0 +1,686 @@ +#!/bin/bash +# appimage-packager-rofs-fixed.sh +# 已添加QEMU兼容性支持 + +set -e + +# 彩色输出 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +# 创建图标 +create_icon() { + local icon_path="$1" + mkdir -p "$(dirname "$icon_path")" + + echo 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==' | \ + base64 -d > "$icon_path" 2>/dev/null || \ + echo -ne '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89\x00\x00\x00\nIDATx\x9cc\xf8\x0f\x00\x00\x01\x00\x01\x05\x01\x00\x00\x00\x00IEND\xaeB`\x82' > "$icon_path" +} + +# 创建简单二进制AppRun(修复版) +create_simple_binary_apprun() { + local app_dir="$1" + local app_name="$2" + local orig_name="$3" + + echo "创建简单二进制AppRun..." + + # 先回退到脚本版本 + cat > "$app_dir/AppRun" << 'EOF' +#!/bin/sh +# 简单启动脚本(兼容性最好) +HERE="$(dirname "$(readlink -f "$0")")" +APP_NAME="$(basename "$0" .AppImage)" + +# 设置环境 +export PATH="$HERE/usr/bin:$PATH" +export LD_LIBRARY_PATH="$HERE/usr/lib:$LD_LIBRARY_PATH" + +# 检测架构 +if [ "$(uname -m)" = "x86_64" ]; then + # x86系统直接运行 + exec "$HERE/usr/bin/$APP_NAME" "$@" +else + # ARM系统,通过QEMU运行 + # 确保有lib64目录 + if [ ! -d "$HERE/lib64" ] && [ -f "$HERE/usr/lib/ld-linux-x86-64.so.2" ]; then + mkdir -p "$HERE/lib64" + cp "$HERE/usr/lib/ld-linux-x86-64.so.2" "$HERE/lib64/" 2>/dev/null || true + fi + + # 使用QEMU运行 + exec qemu-x86_64-static -L "$HERE" "$HERE/usr/bin/$APP_NAME" "$@" +fi +EOF + + chmod +x "$app_dir/AppRun" + echo -e "${GREEN}✓ 创建脚本版AppRun${NC}" +} + +# 创建二进制AppRun函数(修复版) +create_binary_apprun() { + local app_dir="$1" + local app_name="$2" + local orig_name="$3" + + echo -e "${YELLOW}创建二进制AppRun...${NC}" + + # 创建修复的C源代码 + cat > /tmp/apprun_fixed.c << 'EOF' +#include +#include +#include +#include +#include +#include +#include + +// 获取程序所在目录 +static char* get_program_dir() { + static char path[4096]; + ssize_t len = readlink("/proc/self/exe", path, sizeof(path)-1); + if (len == -1) { + return NULL; + } + path[len] = '\0'; + + // 找到最后一个'/' + char* last_slash = strrchr(path, '/'); + if (last_slash) { + *last_slash = '\0'; + } + return path; +} + +// 检查文件是否存在 +static int file_exists(const char* path) { + struct stat st; + return stat(path, &st) == 0 && S_ISREG(st.st_mode); +} + +// 执行程序 +static void execute_program(const char* dir, const char* prog_name, char* const argv[]) { + char prog_path[4096]; + snprintf(prog_path, sizeof(prog_path), "%s/usr/bin/%s", dir, prog_name); + + if (!file_exists(prog_path)) { + // 尝试查找任何可执行文件 + fprintf(stderr, "错误: 未找到可执行文件 %s\n", prog_path); + exit(1); + } + + // 设置环境变量 + setenv("HERE", dir, 1); + + char ld_path[4096]; + snprintf(ld_path, sizeof(ld_path), "%s/usr/lib", dir); + setenv("LD_LIBRARY_PATH", ld_path, 1); + + char path[4096]; + const char* old_path = getenv("PATH"); + if (old_path) { + snprintf(path, sizeof(path), "%s/usr/bin:%s", dir, old_path); + } else { + snprintf(path, sizeof(path), "%s/usr/bin", dir); + } + setenv("PATH", path, 1); + + // 执行程序 + execv(prog_path, argv); + // 如果execv失败 + fprintf(stderr, "无法执行程序: %s\n", prog_path); + exit(1); +} + +int main(int argc, char* argv[]) { + // 获取程序所在目录 + char* dir = get_program_dir(); + if (!dir) { + fprintf(stderr, "无法获取程序目录\n"); + return 1; + } + + // 从AppImage文件名获取程序名 + char* prog_name = "program"; + + // 尝试从argv[0]获取 + if (argc > 0 && argv[0]) { + char* app_name = argv[0]; + char* last_slash = strrchr(app_name, '/'); + if (last_slash) { + app_name = last_slash + 1; + } + + // 移除.AppImage后缀 + char* dot_appimage = strstr(app_name, ".AppImage"); + if (dot_appimage) { + *dot_appimage = '\0'; + prog_name = app_name; + } + } + + // 准备新参数数组 + char** new_argv = malloc((argc + 1) * sizeof(char*)); + if (!new_argv) { + fprintf(stderr, "内存分配失败\n"); + return 1; + } + + new_argv[0] = prog_name; + for (int i = 1; i < argc; i++) { + new_argv[i] = argv[i]; + } + new_argv[argc] = NULL; + + // 执行程序 + execute_program(dir, prog_name, new_argv); + + free(new_argv); + return 0; +} +EOF + + # 尝试编译为x86_64二进制(静态链接) + echo "编译x86_64二进制..." + + # 检查是否有交叉编译器 + if command -v x86_64-linux-gnu-gcc >/dev/null 2>&1; then + echo "使用x86_64-linux-gnu-gcc编译..." + x86_64-linux-gnu-gcc -static -Os -o "$app_dir/AppRun" /tmp/apprun_fixed.c 2>&1 | grep -v "warning" || true + elif command -v gcc >/dev/null 2>&1; then + echo "使用gcc交叉编译..." + gcc -target x86_64-linux-gnu -static -Os -o "$app_dir/AppRun" /tmp/apprun_fixed.c 2>&1 | grep -v "warning" || true + else + echo "未找到编译器" + fi + + # 检查编译是否成功 + if [[ -f "$app_dir/AppRun" ]] && [[ -x "$app_dir/AppRun" ]]; then + # 验证是x86_64二进制 + if file "$app_dir/AppRun" | grep -q "x86-64"; then + chmod +x "$app_dir/AppRun" + echo -e "${GREEN}✓ 二进制AppRun创建成功${NC}" + file "$app_dir/AppRun" + return 0 + else + echo "编译出的不是x86-64二进制" + rm -f "$app_dir/AppRun" + fi + fi + + # 编译失败,使用简单脚本 + echo "二进制编译失败,使用脚本版本" + create_simple_binary_apprun "$app_dir" "$app_name" "$orig_name" + + rm -f /tmp/apprun_fixed.c +} + +# 创建简单二进制AppRun +create_simple_binary_apprun() { + local app_dir="$1" + local app_name="$2" + local orig_name="$3" + + # 创建极简的汇编二进制 + cat > /tmp/minimal.S << 'EOF' +.section .note.GNU-stack,"",@progbits +.section .text +.globl _start +_start: + # execve("./usr/bin/program", argv, envp) + mov $59, %rax # syscall: execve + + # 构建路径字符串 + lea path(%rip), %rdi # arg1: filename + + # 构建参数数组 ["./usr/bin/program", NULL] + lea argv(%rip), %rsi # arg2: argv + + # 环境变量 + xor %rdx, %rdx # arg3: envp = NULL + + syscall + + # 如果失败,退出 + mov $60, %rax # syscall: exit + mov $1, %rdi # status = 1 + syscall + +path: + .ascii "./usr/bin/program\0" + +argv: + .quad path + .quad 0 +EOF + + # 汇编并链接 + as --64 -o /tmp/minimal.o /tmp/minimal.S + ld -m elf_x86_64 -s -o "$app_dir/AppRun" /tmp/minimal.o + + if [[ -f "$app_dir/AppRun" ]]; then + chmod +x "$app_dir/AppRun" + echo -e "${GREEN}✓ 极简二进制AppRun已创建${NC}" + else + echo -e "${RED}错误: 无法创建二进制AppRun${NC}" + # 回退到脚本 + create_script_apprun "$app_dir" "$app_name" "$orig_name" + fi + + rm -f /tmp/minimal.S /tmp/minimal.o +} + +# 使用busybox作为AppRun +use_busybox_as_apprun() { + local app_dir="$1" + + echo "使用busybox作为AppRun..." + + # 查找或下载x86_64的busybox + if [[ -f /usr/bin/busybox ]] && file /usr/bin/busybox | grep -q "x86-64"; then + cp /usr/bin/busybox "$app_dir/AppRun" + elif [[ -f /bin/busybox ]] && file /bin/busybox | grep -q "x86-64"; then + cp /bin/busybox "$app_dir/AppRun" + else + # 尝试下载静态版busybox + echo "下载静态busybox..." + wget -q -O "$app_dir/AppRun" "https://busybox.net/downloads/binaries/1.35.0-x86_64-linux-musl/busybox" 2>/dev/null || { + echo "下载失败,使用备用方案" + return 1 + } + fi + + if [[ -f "$app_dir/AppRun" ]]; then + chmod +x "$app_dir/AppRun" + # 创建busybox的symlink脚本 + cat > "$app_dir/.busybox-run" << 'EOF' +#!/bin/sh +# busybox wrapper +HERE=$(dirname "$0") +export PATH="$HERE/usr/bin:$PATH" +export LD_LIBRARY_PATH="$HERE/usr/lib:$LD_LIBRARY_PATH" +exec "$HERE/AppRun" "$HERE/usr/bin/$(basename "$0" .AppImage)" "$@" +EOF + chmod +x "$app_dir/.busybox-run" + echo -e "${GREEN}✓ 使用busybox作为AppRun${NC}" + return 0 + fi + return 1 +} + +# 收集所有动态库依赖 +collect_all_dependencies() { + local executable="$1" + local lib_dir="$2" + + echo -e "${YELLOW}收集动态库依赖...${NC}" + + if ! ldd "$executable" 2>/dev/null | grep -q "=>"; then + echo "程序是静态链接,无需库文件" + return 0 + fi + + mkdir -p "$lib_dir" + local processed_libs=() + + collect_libs_recursive() { + local target="$1" + + ldd "$target" 2>/dev/null | grep "=>" | awk '{print $3}' | while read -r lib; do + if [[ -f "$lib" ]]; then + local libname=$(basename "$lib") + + if [[ ! " ${processed_libs[@]} " =~ " ${libname} " ]]; then + processed_libs+=("$libname") + + cp "$lib" "$lib_dir/" 2>/dev/null + if [[ $? -eq 0 ]]; then + echo " ✅ $libname" + collect_libs_recursive "$lib" + fi + fi + fi + done + } + + collect_libs_recursive "$executable" + + # 添加基础库 + local common_libs=( + "ld-linux-x86-64.so.2" + "libc.so.6" "libm.so.6" "libpthread.so.0" + "libdl.so.2" "librt.so.1" "libgcc_s.so.1" + "libstdc++.so.6" + ) + + for lib in "${common_libs[@]}"; do + find /usr/lib /lib /lib64 -name "$lib" -type f 2>/dev/null | head -1 | while read -r libpath; do + if [[ -f "$libpath" ]] && [[ ! -f "$lib_dir/$(basename "$libpath")" ]]; then + cp "$libpath" "$lib_dir/" 2>/dev/null && echo " ✅ 基础: $(basename "$libpath")" + fi + done + done + + local lib_count=$(ls -1 "$lib_dir"/*.so* 2>/dev/null | wc -l) + echo -e "${GREEN}✓ 添加了 $lib_count 个库${NC}" +} + +# 设置QEMU目录结构 +setup_qemu_structure() { + local app_dir="$1" + + echo -e "${YELLOW}设置QEMU目录结构...${NC}" + + # 创建QEMU需要的目录结构 + mkdir -p "$app_dir/lib64" + mkdir -p "$app_dir/usr/gnemul/qemu-x86_64" + + # 复制库到QEMU期望的位置 + if [[ -d "$app_dir/usr/lib" ]]; then + echo "复制库文件到QEMU目录..." + # 复制所有库 + cp -r "$app_dir/usr/lib/"* "$app_dir/usr/gnemul/qemu-x86_64/" 2>/dev/null || true + + # 特别处理ld-linux动态链接器 + if [[ -f "$app_dir/usr/lib/ld-linux-x86-64.so.2" ]]; then + echo "设置动态链接器..." + # 在lib64创建链接(QEMU查找的位置) + ln -sf ../usr/lib/ld-linux-x86-64.so.2 "$app_dir/lib64/ld-linux-x86-64.so.2" 2>/dev/null || true + # 同时也复制一份到lib64确保可用 + cp "$app_dir/usr/lib/ld-linux-x86-64.so.2" "$app_dir/lib64/" 2>/dev/null || true + fi + + echo -e "${GREEN}✓ QEMU目录结构已创建${NC}" + else + echo -e "${YELLOW}⚠ 未找到库目录,跳过QEMU结构设置${NC}" + fi +} + +# 查找并复制数据文件 +find_and_copy_data() { + local executable="$1" + local app_name="$2" + local data_dir="$3" + + echo -e "${YELLOW}查找数据文件...${NC}" + + local prog_dir=$(dirname "$(realpath "$executable")") + local patterns=("*.pem" "*.key" "*.crt" "*.cfg" "*.conf" "*.ini" "*.json" "*.xml") + + mkdir -p "$data_dir" + local count=0 + + # 首先查找程序目录 + for pattern in "${patterns[@]}"; do + find "$prog_dir" -maxdepth 2 -type f -name "$pattern" 2>/dev/null | while read -r file; do + if [[ "$file" != "$executable" ]]; then + cp "$file" "$data_dir/" 2>/dev/null && { + echo " ✅ $(basename "$file")" + count=$((count + 1)) + } + fi + done + done + + # 如果没有找到,尝试复制所有非可执行文件 + if [[ $count -eq 0 ]]; then + find "$prog_dir" -maxdepth 1 -type f ! -name "$(basename "$executable")" ! -name "*.AppImage" | while read -r file; do + cp "$file" "$data_dir/" 2>/dev/null && echo " ✅ $(basename "$file")" + done + fi + + # 如果没有数据文件,创建示例配置 + if [[ $count -eq 0 ]] && [[ ! -f "$data_dir/config.ini" ]]; then + cat > "$data_dir/config.ini" < [输出名称]" + echo " $0 -d <可执行文件> [输出名称] (包含数据文件)" + echo "" + echo "示例:" + echo " $0 ./myapp" + echo " $0 -d ./myapp" + exit 1 + fi + + # 检查是否包含数据文件 + INCLUDE_DATA=false + if [[ "$1" == "-d" ]] || [[ "$1" == "--data" ]]; then + INCLUDE_DATA=true + shift + fi + + echo -e "${BLUE}════════════════════════════════════════${NC}" + echo -e "${BLUE} AppImage 打包工具 ${NC}" + echo -e "${BLUE} (QEMU兼容版) ${NC}" + echo -e "${BLUE}════════════════════════════════════════${NC}" + + EXECUTABLE="$1" + APP_NAME="${2:-$(basename "$EXECUTABLE")}" + + [[ ! -f "$EXECUTABLE" ]] && { echo -e "${RED}错误: 文件不存在${NC}"; exit 1; } + [[ ! -x "$EXECUTABLE" ]] && chmod +x "$EXECUTABLE" + + echo "程序: $APP_NAME" + echo "原始: $(basename "$EXECUTABLE")" + + # 清理 + rm -rf "AppDir" "${APP_NAME}.AppImage" + + # =========== 步骤1: 创建目录 =========== + echo -e "\n${YELLOW}[1/7] 创建目录...${NC}" + mkdir -p AppDir/usr/bin + mkdir -p AppDir/usr/lib + + ORIG_NAME=$(basename "$EXECUTABLE") + + # =========== 步骤2: 复制程序 =========== + echo -e "\n${YELLOW}[2/7] 复制程序...${NC}" + cp "$EXECUTABLE" "AppDir/usr/bin/$ORIG_NAME" + chmod +x "AppDir/usr/bin/$ORIG_NAME" + echo -e "${GREEN}✓ 程序: $ORIG_NAME${NC}" + + # =========== 步骤3: 收集依赖 =========== + collect_all_dependencies "$EXECUTABLE" "AppDir/usr/lib" + + # =========== 步骤4: 设置QEMU目录结构 =========== + setup_qemu_structure "AppDir" + + # =========== 步骤5: 处理数据文件 =========== + if $INCLUDE_DATA; then + echo -e "\n${YELLOW}[5/7] 处理数据文件...${NC}" + find_and_copy_data "$EXECUTABLE" "$APP_NAME" "AppDir/usr/share/$APP_NAME" + fi + + # =========== 步骤6: 创建图标 =========== + echo -e "\n${YELLOW}[6/7] 创建图标...${NC}" + create_icon "AppDir/$APP_NAME.png" + cp "AppDir/$APP_NAME.png" "AppDir/.DirIcon" + echo -e "${GREEN}✓ 图标已创建${NC}" + +# =========== 步骤7: 创建二进制 AppRun =========== +echo -e "\n${YELLOW}[7/7] 创建二进制AppRun...${NC}" + +# 首先尝试创建C语言版本 +#use_busybox_as_apprun "AppDir" "$APP_NAME" "$ORIG_NAME" +create_binary_apprun "AppDir" "$APP_NAME" "$ORIG_NAME" + +# 如果失败,使用备选方案 +if [[ ! -f "AppDir/AppRun" ]] || [[ ! -x "AppDir/AppRun" ]]; then + echo "二进制创建失败,使用脚本版本..." + cat > "AppDir/AppRun" <<'EOF' +#!/bin/sh +# 兼容性脚本(当二进制不可用时) +HERE=$(dirname "$(readlink -f "$0")") +APP_NAME=$(basename "$0" .AppImage) + +# 对于QEMU:直接运行内部程序 +if [ "$(uname -m)" != "x86_64" ]; then + # ARM系统,通过QEMU运行 + exec qemu-x86_64-static -L "$HERE" "$HERE/usr/bin/$APP_NAME" "$@" +else + # x86系统,直接运行 + exec "$HERE/usr/bin/$APP_NAME" "$@" +fi +EOF + chmod +x AppDir/AppRun + echo -e "${YELLOW}⚠ 使用脚本版AppRun(QEMU兼容性可能有限)${NC}" +fi + + + # =========== 步骤8: 创建桌面文件 =========== + echo -e "\n${YELLOW}[8/7] 创建桌面文件...${NC}" + mkdir -p AppDir/usr/share/applications + cat > "AppDir/usr/share/applications/$APP_NAME.desktop" <&1 | grep -v "gpg2" | grep -v "Warning"; then + echo -e "${GREEN}✅ 打包成功!${NC}" + else + appimagetool --no-appstream --no-fuse AppDir "$OUTPUT_FILE" 2>&1 | grep -v "gpg2" | grep -v "Warning" + echo -e "${GREEN}✅ 打包成功!${NC}" + fi + + # =========== 测试 =========== + echo -e "\n${BLUE}════════════════════════════════════════${NC}" + echo -e "${GREEN}测试运行...${NC}" + + chmod +x "$OUTPUT_FILE" + + # 创建测试数据目录 + TEST_DIR="$HOME/.local/share/$APP_NAME-test" + rm -rf "$TEST_DIR" + mkdir -p "$TEST_DIR"/{config,data,logs,cache} + + # 复制可能的配置文件 + if [ -d "AppDir/usr/share/$APP_NAME" ]; then + cp -r AppDir/usr/share/$APP_NAME/* "$TEST_DIR/config/" 2>/dev/null || true + fi + + echo "测试命令:" + echo " 原生运行: ./\"$OUTPUT_FILE\" --help" + echo " QEMU运行: qemu-x86_64-static -L . ./\"$OUTPUT_FILE\" --help" + echo " 调试模式: DEBUG=1 ./\"$OUTPUT_FILE\" --help" + echo "----------------------------------------" + + # 原生测试运行 + export DEBUG=1 + if timeout 5s ./"$OUTPUT_FILE" --help 2>&1 | head -20; then + echo -e "${GREEN}✅ 原生运行正常${NC}" + elif timeout 5s ./"$OUTPUT_FILE" -h 2>&1 | head -20; then + echo -e "${GREEN}✅ 原生运行正常${NC}" + else + echo -e "${YELLOW}⚠ 原生运行可能需要特定参数${NC}" + fi + unset DEBUG + + # QEMU兼容性测试 + echo -e "\n${YELLOW}QEMU兼容性测试...${NC}" + if command -v qemu-x86_64-static >/dev/null 2>&1; then + echo "测试命令: qemu-x86_64-static -L . ./\"$OUTPUT_FILE\" --version" + if timeout 5s qemu-x86_64-static -L . ./"$OUTPUT_FILE" --version 2>&1 | head -5; then + echo -e "${GREEN}✅ QEMU运行成功${NC}" + elif timeout 5s qemu-x86_64-static -L . ./"$OUTPUT_FILE" -v 2>&1 | head -5; then + echo -e "${GREEN}✅ QEMU运行成功${NC}" + elif timeout 5s qemu-x86_64-static -L . ./"$OUTPUT_FILE" 2>&1 | head -5; then + echo -e "${GREEN}✅ QEMU运行成功${NC}" + else + echo -e "${YELLOW}⚠ QEMU测试需要特定参数${NC}" + echo "尝试: qemu-x86_64-static -L . ./\"$OUTPUT_FILE\" --help" + fi + else + echo "qemu-x86_64-static 未安装,跳过QEMU测试" + echo "安装命令: sudo apt install qemu-user-static" + fi + + # 最终信息 + echo -e "\n${BLUE}════════════════════════════════════════${NC}" + echo -e "${GREEN} 完成! ${NC}" + echo -e "${BLUE}════════════════════════════════════════${NC}" + echo "" + echo "📦 输出文件: $(realpath "$OUTPUT_FILE")" + echo "📏 大小: $(du -h "$OUTPUT_FILE" | cut -f1)" + echo "" + echo "🚀 使用方法:" + echo " 在x86_64系统: ./\"$OUTPUT_FILE\"" + echo " 在ARM系统: qemu-x86_64-static -L . ./\"$OUTPUT_FILE\"" + echo "" + echo "📁 用户数据目录:" + echo " $HOME/.local/share/$APP_NAME/" + echo "" + echo "🔧 调试模式:" + echo " DEBUG=1 ./\"$OUTPUT_FILE\" [参数]" + echo "" + echo "🔄 QEMU运行助手脚本:" + cat > "$(dirname "$OUTPUT_FILE")/run-with-qemu.sh" <<'EOF2' +#!/bin/bash +# QEMU运行助手 +APP="$1" +shift +qemu-x86_64-static -L . "$APP" "$@" +EOF2 + chmod +x "$(dirname "$OUTPUT_FILE")/run-with-qemu.sh" + echo " 已创建: $(dirname "$OUTPUT_FILE")/run-with-qemu.sh" + echo " 使用: ./run-with-qemu.sh \"$OUTPUT_FILE\" [参数]" + + # 清理 + rm -rf AppDir +} + +# 运行 +main "$@" diff --git a/lci/extra/qemu_run_appimage/ls.AppImage b/lci/extra/qemu_run_appimage/ls.AppImage new file mode 100644 index 0000000..0453892 Binary files /dev/null and b/lci/extra/qemu_run_appimage/ls.AppImage differ diff --git a/lci/extra/qemu_run_appimage/pmcd.AppImage b/lci/extra/qemu_run_appimage/pmcd.AppImage new file mode 100644 index 0000000..1d4e056 Binary files /dev/null and b/lci/extra/qemu_run_appimage/pmcd.AppImage differ diff --git a/lci/extra/qemu_run_appimage/qemu_run2.sh b/lci/extra/qemu_run_appimage/qemu_run2.sh new file mode 100644 index 0000000..555a3a5 --- /dev/null +++ b/lci/extra/qemu_run_appimage/qemu_run2.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# qemu_run_proper.sh + +APPIMAGE="$1" +shift + +if [[ ! -f "$APPIMAGE" ]]; then + echo "错误: 文件不存在: $APPIMAGE" >&2 + exit 1 +fi + +echo "=== 运行AppImage ===" +echo "文件: $(basename "$APPIMAGE")" + +# 创建临时目录 +TEMP_DIR=$(mktemp -d) +cp ${APPIMAGE} ${TEMP_DIR} +cd "$TEMP_DIR" + +# 提取AppImage +echo "提取AppImage..." +qemu-x86_64 "$APPIMAGE" --appimage-extract 2>/dev/null || { + echo "提取失败" >&2 + exit 1 +} + +cd squashfs-root +HERE="$PWD" + +echo "提取目录: $HERE" + +# 查找可执行文件(不输出额外信息) +find_executable() { + local dir="$1" + local app_name=$(basename "$APPIMAGE" .AppImage) + + # 1. 尝试与AppImage同名的程序 + if [[ -x "$dir/usr/bin/$app_name" ]]; then + echo "$dir/usr/bin/$app_name" + return 0 + fi + + # 2. 查找usr/bin下的第一个可执行文件 + if [[ -d "$dir/usr/bin" ]]; then + for prog in "$dir/usr/bin"/*; do + if [[ -x "$prog" ]]; then + echo "$prog" + return 0 + fi + done + fi + + # 3. 查找AppRun + if [[ -x "$dir/AppRun" ]]; then + echo "$dir/AppRun" + return 0 + fi + + return 1 +} + +# 静默查找可执行文件 +EXECUTABLE=$(find_executable "$HERE" 2>/dev/null) + +if [[ -z "$EXECUTABLE" ]] || [[ ! -f "$EXECUTABLE" ]]; then + echo "错误: 未找到可执行文件" >&2 + echo "目录内容:" >&2 + ls -la "$HERE" >&2 + if [[ -d "$HERE/usr/bin" ]]; then + echo "usr/bin内容:" >&2 + ls -la "$HERE/usr/bin" >&2 + fi + exit 1 +fi + +echo "可执行文件: $EXECUTABLE" +echo "文件类型: $(file -b "$EXECUTABLE" 2>/dev/null || echo "无法识别")" + +# 运行程序 +ARCH=$(uname -m) + +if [[ "$ARCH" == "x86_64" ]]; then + echo "原生x86_64系统,直接运行..." + exec "$EXECUTABLE" "$@" +else + echo "ARM系统 ($ARCH),使用QEMU..." + + # 确保lib64目录 + if [[ ! -d "$HERE/lib64" ]] && [[ -f "$HERE/usr/lib/ld-linux-x86-64.so.2" ]]; then + mkdir -p "$HERE/lib64" + cp "$HERE/usr/lib/ld-linux-x86-64.so.2" "$HERE/lib64/" 2>/dev/null + fi + + # 直接使用QEMU运行 + exec qemu-x86_64 -L "$HERE" "$EXECUTABLE" "$@" +fi diff --git a/lci/include/Crypto/AES_CBC.hpp b/lci/include/Crypto/AES_CBC.hpp new file mode 100644 index 0000000..b36caf8 --- /dev/null +++ b/lci/include/Crypto/AES_CBC.hpp @@ -0,0 +1,145 @@ +#include "Crypto_Basic.hpp" +#include +#include +#include +#include +#include +#include + + +#define CRYPTO_CHECK(condition, message) \ + if (!(condition)) { \ + throw std::runtime_error(message); \ + } +namespace qing { + class AES_CBC: public qing::Crypto_Basic { + public: + /* 构造函数 初始化一个随即的密钥和初始化向量 */ + AES_CBC() { + generate_key_iv(key, iv); + } + AES_CBC(std::vector &key, std::vector &iv) { + this->key = key; + this->iv = iv; + } + std::string get_key() { + return bytes_to_hex(key); + } + std::string get_iv() { + return bytes_to_hex(iv); + } + + std::string encrypt(std::string original_text) { + std::vector plaintext(original_text.begin(), original_text.end()); + std::vector ciphertext = aes_encrypt(plaintext, key, iv); + + // hex-bytes转换测试 + /*std::string hex = bytes_to_hex(ciphertext); + std::vector cipher2 = hex_to_bytes(hex); + print_bytes(ciphertext); + print_bytes(cipher2);*/ + + return bytes_to_hex(ciphertext); + } + + std::string decrypt(std::string cipher_hex) { + std::vector ciphertext = hex_to_bytes(cipher_hex); + std::vector decrypted = aes_decrypt(ciphertext, key, iv); + return std::string(decrypted.begin(), decrypted.end()); + } + + static void print_bytes(std::vector& bytes) { + for (unsigned char byte : bytes) { + std::cerr << std::setw(2) << static_cast(byte); + } + std::cerr << std::endl; + } + + private: + std::vector key; + std::vector iv; + // 生成随机密钥和IV + static void generate_key_iv(std::vector& key, + std::vector& iv) { + key.resize(32); // AES-256 需要 32 字节密钥 + iv.resize(16); // AES 块大小 16 字节(128-bit) + + // 生成随即密钥 + CRYPTO_CHECK(RAND_bytes(key.data(), key.size()) == 1, "密钥生成失败"); + + // 生成随即IV + CRYPTO_CHECK(RAND_bytes(iv.data(), iv.size()) == 1, "IV生成失败"); + } + + // AES-256-CBC 加密 + static std::vector aes_encrypt(const std::vector& plaintext, + const std::vector& key, + const std::vector& iv) { + // 创建上下文 + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + CRYPTO_CHECK(ctx != nullptr, "无法创建加密上下文"); + + // 初始化加密操作 + CRYPTO_CHECK(EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, + key.data(), iv.data()) , "加密初始化失败"); + + // 输出缓冲区 (密文可能比明文长一个块) + std::vector ciphertext(plaintext.size() + EVP_CIPHER_CTX_block_size(ctx)); + int len = 0; + int ciphertext_len = 0; + + // 提供明文数据 + CRYPTO_CHECK(EVP_EncryptUpdate(ctx, ciphertext.data(), &len, + plaintext.data(), plaintext.size()) == 1, "加载更新失败"); + ciphertext_len = len; + + // 完成加密(处理填充) + CRYPTO_CHECK(EVP_EncryptFinal_ex(ctx, ciphertext.data() + len, &len) == 1, "加密结束失败"); + ciphertext_len += len; + + // 调整到实际密文长度 + ciphertext.resize(ciphertext_len); + + // 处理上下文 + EVP_CIPHER_CTX_free(ctx); + + return ciphertext; + + } + + // AES-256-CBC + static std::vector aes_decrypt(const std::vector& ciphertext, + const std::vector& key, + const std::vector& iv) { + // 创建上下文 + EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new(); + CRYPTO_CHECK(ctx != nullptr, "无法创建解密上下文"); + + // 初始化解密操作 + CRYPTO_CHECK(EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), nullptr, + key.data(), iv.data()) == 1, "解密初始化失败"); + + // 输出缓冲区(明文可能比密文短,但最大为密文长度) + std::vector plaintext(ciphertext.size()); + int len = 0; + int plaintext_len = 0; + + // 提供密文数据 + CRYPTO_CHECK(EVP_DecryptUpdate(ctx, plaintext.data(), &len, + ciphertext.data(), ciphertext.size()) == 1, "解密更新失败"); + plaintext_len = len; + + // 完成解密(处理填充) + CRYPTO_CHECK(EVP_DecryptFinal_ex(ctx, plaintext.data() + len, &len) == 1, "解密结束失败"); + plaintext_len += len; + + // 调整到实际明文长度 + plaintext.resize(plaintext_len); + + // 清理上下文 + EVP_CIPHER_CTX_free(ctx); + + return plaintext; + } + }; +} diff --git a/lci/include/Crypto/Crypto_Basic.hpp b/lci/include/Crypto/Crypto_Basic.hpp new file mode 100644 index 0000000..c931570 --- /dev/null +++ b/lci/include/Crypto/Crypto_Basic.hpp @@ -0,0 +1,55 @@ +#pragma once +#include +#include +#include +namespace qing { + class Crypto_Basic { + public: + class CryptoExp: public std::runtime_error { + public: + CryptoExp(const std::string& msg): std::runtime_error(msg) { + ; + } + }; + protected: + /* 字节码转十六进制字符串 */ + static std::string bytes_to_hex(const std::vector& data) { + static const char hex_chars[] = "0123456789abcdef"; + std::string hex_string; + hex_string.reserve(data.size() * 2); + + for (unsigned char byte: data) { + hex_string.push_back(hex_chars[byte >> 4]); // 高4位 + hex_string.push_back(hex_chars[byte & 0x0F]); // 低4位 + } + + return hex_string; + } + + /* 十六进制字符串转字节码 */ + static std::vector hex_to_bytes(const std::string &hex) { + // 检查长度是否为偶数 + if (hex.size() % 2 != 0) { + throw std::invalid_argument("十六进制字符串长度必须为偶数"); + } + + std::vector bytes; + bytes.reserve(hex.size() / 2); + + auto char_to_nibble = [](char c) -> unsigned char { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); + if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); + throw std::invalid_argument("无效的十六进制字符:" + std::string(1, c)); + }; + + for (size_t i = 0; i < hex.size(); i += 2) { + unsigned char high = char_to_nibble(hex[i]); + unsigned char low = char_to_nibble(hex[i + 1]); + bytes.push_back((high << 4) | low); + } + + return bytes; + } + }; +} diff --git a/lci/include/Crypto/MyRSA.hpp b/lci/include/Crypto/MyRSA.hpp new file mode 100644 index 0000000..c59aa84 --- /dev/null +++ b/lci/include/Crypto/MyRSA.hpp @@ -0,0 +1,288 @@ +#pragma once +#include "Crypto_Basic.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +// 错误处理宏 +#define HANDLE_SSL_ERROR() { \ + char err_buf[512]; \ + ERR_error_string_n(ERR_get_error(), err_buf, sizeof(err_buf)); \ + std::cerr << "SSL error: " << err_buf << std::endl; \ +} +// 自定义删除器用于管理OpenSSL资源 +struct EVP_PKEY_deleter { + void operator()(EVP_PKEY* pkey) const { EVP_PKEY_free(pkey); } +}; +using EVP_PKEY_ptr = std::unique_ptr; + +struct EVP_PKEY_CTX_deleter { + void operator()(EVP_PKEY_CTX* ctx) const { EVP_PKEY_CTX_free(ctx); } +}; +using EVP_PKEY_CTX_ptr = std::unique_ptr; + +struct BIO_deleter { + void operator()(BIO* bio) const { BIO_free_all(bio); } +}; +using BIO_ptr = std::unique_ptr; + +namespace qing { + class MyRSA: public qing::Crypto_Basic { + public: + class Generator { + public: + Generator() { + key = generate_rsa_key(); + } + void save_pri_key(const std::string filename) { + if (!save_private_key(key.get(), filename)) { + throw Crypto_Basic::CryptoExp("保存私钥失败。"); + } + } + void save_pub_key(const std::string filename) { + if(!save_public_key(key.get(), filename)) { + throw Crypto_Basic::CryptoExp("保存公钥失败。"); + } + } + private: + EVP_PKEY_ptr key; + // 生成 RSA 密钥对 + + static EVP_PKEY_ptr generate_rsa_key(size_t key_bits = 2048) { + EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new_from_name(nullptr, "RSA", nullptr)); + if (!ctx) { + HANDLE_SSL_ERROR(); + return nullptr; + } + if (EVP_PKEY_keygen_init(ctx.get()) <= 0) { + HANDLE_SSL_ERROR(); + return nullptr; + } + + // 设置 RSA 密钥长度 + OSSL_PARAM params[] = { + OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &key_bits), + OSSL_PARAM_END + }; + + if (EVP_PKEY_CTX_set_params(ctx.get(), params) <= 0) { + HANDLE_SSL_ERROR(); + return nullptr; + } + + EVP_PKEY* pkey = nullptr; + if (EVP_PKEY_generate(ctx.get(), &pkey) <= 0) { + HANDLE_SSL_ERROR(); + return nullptr; + } + + return EVP_PKEY_ptr(pkey); + } + + // 保存私钥到文件 + static bool save_private_key(EVP_PKEY* pkey, const std::string& filename, + const char* password = nullptr) { + BIO_ptr bio(BIO_new_file(filename.c_str(), "wb")); + if (!bio) { + std::cerr << "Failed to open file: " << filename << std::endl; + return false; + } + + // 选择加密算法 + const EVP_CIPHER* cipher = password ? EVP_aes_256_cbc() : nullptr; + + int ret = PEM_write_bio_PrivateKey(bio.get(), pkey, cipher, + (unsigned char*) password, + password ? strlen(password) : 0, + nullptr, nullptr); + + if (ret != 1) { + HANDLE_SSL_ERROR(); + return false; + } + + return true; + } + + // 保存公钥到文件 + static bool save_public_key(EVP_PKEY* pkey, const std::string& filename) { + BIO_ptr bio(BIO_new_file(filename.c_str(), "wb")); + if (!bio) { + std::cerr << "Failed ot open file: " << filename << std::endl; + return false; + } + + int ret = PEM_write_bio_PUBKEY(bio.get(), pkey); + if (ret != 1) { + HANDLE_SSL_ERROR(); + return false; + } + + return true; + } + }; + + class Private_Key: Crypto_Basic { + public: + Private_Key(const std::string fullpath) { + if (!(pri_key = load_private_key(fullpath))) + throw Crypto_Basic::CryptoExp("读取私钥失败"); + } + std::string Decrypt(const std::string cipher_hex) { + std::vector ciphertext = hex_to_bytes(cipher_hex); + std::vector decrypted = rsa_decrypt(pri_key.get(), ciphertext); + if (decrypted.empty()) throw Crypto_Basic::CryptoExp("解密失败"); + return std::string(decrypted.begin(), decrypted.end()); + } + private: + EVP_PKEY_ptr pri_key; + // 从文件加载私钥 + EVP_PKEY_ptr load_private_key(const std::string& filename, + const char* password = nullptr) { + BIO_ptr bio(BIO_new_file(filename.c_str(), "rb")); + if (!bio) { + std::cerr << "Failed to open file: " << filename << std::endl; + return nullptr; + } + + // 密码回调函数,显示转换为函数指针类型 + pem_password_cb* callback = +[] (char *buf, int size, int rwflag, void * u) { + if (!u) return 0; + const char* pass = (const char*)u; + int len = strlen(pass); + if (len > size) len = size; + memcpy(buf, pass, len); + return len; + }; + pem_password_cb* cb = password ? nullptr : callback; + + EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio.get(), nullptr, cb, (void*)password); + if (!pkey) { + HANDLE_SSL_ERROR(); + return nullptr; + } + + return EVP_PKEY_ptr(pkey); + } + + // 使用私钥解密数据 + static std::vector rsa_decrypt(EVP_PKEY* private_key, + const std::vector& ciphertext) { + EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new(private_key, nullptr)); + if (!ctx) { + HANDLE_SSL_ERROR(); + return {}; + } + + if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + // 使用 OAEP 填充 + if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + // 获取输出缓冲区大小 + size_t outlen = 0; + if (EVP_PKEY_decrypt(ctx.get(), nullptr, &outlen, + ciphertext.data(), ciphertext.size()) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + // 执行解密 + std::vector plaintext(outlen); + if (EVP_PKEY_decrypt(ctx.get(), plaintext.data(), &outlen, + ciphertext.data(), ciphertext.size()) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + plaintext.resize(outlen); + return plaintext; + } + }; + + + class Public_Key: public Crypto_Basic { + public: + Public_Key(const std::string filename) { + if (!(pub_key = load_public_key(filename))) + throw Crypto_Basic::CryptoExp("读取公钥失败"); + } + std::string Encrypt(std::string original_text) { + std::vector plaintext(original_text.begin(), original_text.end()); + std::vector ciphertext = rsa_encrypt(pub_key.get(), plaintext); + if (ciphertext.empty()) throw Crypto_Basic::CryptoExp("加密失败"); + return bytes_to_hex(ciphertext); + } + private: + EVP_PKEY_ptr pub_key; + + // 从文件加载公钥 + static EVP_PKEY_ptr load_public_key(const std::string& filename) { + BIO_ptr bio(BIO_new_file(filename.c_str(), "rb")); + if (!bio) { + std::cerr << "Failed to open file: " << filename << std::endl; + return nullptr; + } + + EVP_PKEY* pkey = PEM_read_bio_PUBKEY(bio.get(), nullptr, nullptr, nullptr); + if (!pkey) { + HANDLE_SSL_ERROR(); + return nullptr; + } + + return EVP_PKEY_ptr(pkey); + } + + // 使用公钥加密数据 + static std::vector rsa_encrypt(EVP_PKEY* public_key, + const std::vector& plaintext) { + EVP_PKEY_CTX_ptr ctx(EVP_PKEY_CTX_new(public_key, nullptr)); + if (!ctx) { + HANDLE_SSL_ERROR(); + return {}; + } + + if (EVP_PKEY_encrypt_init(ctx.get()) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + // 使用 OAEP 填充 + if (EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_OAEP_PADDING) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + // 获取输出缓冲区大小 + size_t outlen =0 ; + if (EVP_PKEY_encrypt(ctx.get(), nullptr, &outlen, + plaintext.data(), plaintext.size()) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + // 执行加密 + std::vector ciphertext(outlen); + if (EVP_PKEY_encrypt(ctx.get(), ciphertext.data(), &outlen, + plaintext.data(), plaintext.size()) <= 0) { + HANDLE_SSL_ERROR(); + return {}; + } + + ciphertext.resize(outlen); + return ciphertext; + } + }; + }; +} diff --git a/lci/include/Dashun.h b/lci/include/Dashun.h new file mode 100644 index 0000000..e1ee3a2 --- /dev/null +++ b/lci/include/Dashun.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include "nn/Matrix.hh" +#include "nn/ILayer.hpp" +#include "nn/ILearnable.hpp" +#include "nn/ILayerFullyConnectted.hpp" +#include "nn/ILayerConvolutional.hpp" +#include "nn/NeuralNetwork.hpp" +#include "nn/ConvLayer.hpp" +#include "nn/PoolingLayer.hpp" +#include "nn/FlattenLayer.hpp" +#include "nn/NNBuilder.hpp" +#include "nn/CNNBuilder.hpp" +#include "nn/ImageLoader.hpp" diff --git a/lci/include/Dashun_linux.hpp b/lci/include/Dashun_linux.hpp new file mode 100644 index 0000000..41986c3 --- /dev/null +++ b/lci/include/Dashun_linux.hpp @@ -0,0 +1,44 @@ +#pragma once +/* + * # 安装工具 + * apt install i2c-tools libi2c-dev + * + * # 扫描设备 + * i2cdetect -y 1 + */ +#include "cn/中文化.hpp" + +/* 基本I2C */ +逻辑型 I2C_检查(); +空类型 I2C_初始化(常量 字符* 文件路径 = "/dev/i2c-1"); +空类型 I2C_清除(); +空类型 I2C_获取锁(); /* FIXME: 使用锁类 */ +空类型 I2C_释放锁(); +空类型 I2C_置地址(常量 无号8位整 地址); +空类型 I2C_写寄存器(无号8位整 寄存器, 无号8位整 值); +无号8位整 I2C_读寄存器(无号8位整 寄存器); + +/* PCA9685 */ +逻辑型 PCA9685_检查(); +空类型 PCA9685_初始化(); +空类型 PCA9685_设置PWM(无号8位整 通道, 无号16位整 导通值, 无号16位整 关断值); +空类型 PCA9685_调整角度(无号8位整 通道, 单精度小数 角度); + +/* + * MPU6050 + * 传感器数据 + */ +结构体 MPU6050_传感器数据 { + 有号16位整 加速度计_横, 加速度计_纵, 加速度计_竖; + 有号16位整 陀螺仪_横, 陀螺仪_纵, 陀螺仪_竖; +}; + +逻辑型 MPU6050_检查(); +空类型 MPU6050_初始化(); +MPU6050_传感器数据 MPU6050_读传感器(); /* FIXME: 输入结构体引用(或指针)会更快 */ +空类型 MPU6050_计算角度(常量 MPU6050_传感器数据& 数据, 单精度小数& 俯仰角, 单精度小数& 翻滚角); + + + +/* Robot */ +#include "hd/Robot.hpp" diff --git a/lci/include/cn/中文化.hpp b/lci/include/cn/中文化.hpp new file mode 100644 index 0000000..d5cdddd --- /dev/null +++ b/lci/include/cn/中文化.hpp @@ -0,0 +1,177 @@ + +//作者:简单 +//修改:qing +/* + * C++17支持了中文变量名,配合define预编译指令可以将代码中文化。 + * + * 在C语言中,变量名只能由字母、数字或是下划线组成。 + * 由于C++语言兼容C语言,最开始的C++是不能够使用多字节变量名的。 + * + * */ +#ifndef __中文模式 +#define __中文模式 +#include +/*保留字*/ +#define 使用 using +#define 命名空间 namespace +#define 取别名 typedef +#define 覆盖 override +#define 取内存大小 sizeof +#define 返回 return +#define 如果 if +#define 否则 else +#define 又或者 else if +#define 真 true +#define 假 false +//#define 且 and +//#define 或 or +#define 空类型 void +#define 常量 const +#define 有符号 signed +#define 无符号 unsigned +#define 文件 FILE +#define 文件结束 EOF +#define 类 class +#define 结构体 struct +#define 枚举类型 enum +#define 对象 this +#define 抛出异常 throw +#define 新建 new +//#define 新的 new +#define 删除 delete +#define 跳出 break +#define 继续 continue +#define 判断循环 while +#define 循环判断 do +#define 循环判断尾 while +#define 分支选择 switch +#define 支系 case +#define 缺省 default +#define 计次循环 for +#define 尝试 try +#define 获取异常 catch +#define 捕获异常 catch +#define 退出 exit +#define 公开的 public +#define 受保护的 protected +#define 私有的 private +#define 外部的 extern +#define 静态的 static +#define 虚拟的 virtual + +#define 有号8位整 int8_t +#define 无号8位整 uint8_t +#define 有号16位整 int16_t +#define 无号16位整 uint16_t +#define 有号32位整 int32_t +#define 无号32位整 uint32_t +#define 有号64位整 int64_t +#define 无号64位整 uint64_t + +#define 空的 NULL +#define 空指针 nullptr +#define 整数 int +#define 字符 char +#define 短整数 short +#define 长型 long +#define 超长型 long long +#define 单精度小数 float +#define 双精度小数 double +#define 长度单位 size_t +#define 布尔 bool +#define 逻辑型 bool +#define 可变类型 auto +#define 自动的 auto +#define 适应 auto +#define _文件 FILE +#define _文件结束 EOF +#define _读模式 "r" +#define _写模式 "w" +#define 模板 template +#define 类型名 typename +#define 默认的 default +#define 被删除 delete +#define 入口 main +#define 主函数 main +#define 或 || +#define 或者 || +#define 而且 && +#define 且 && +#define 等于 == +#define 大于等于 >= +#define 小于等于 <= +#define 大于 > +#define 小于 < +#define 不报错的 noexcept +#define 不转换的 explicit +#define 纯函数的 consteval +#define 预求值的 constexpr + +#define _加法重载 operator+ +#define _取下标重载 operator[] +#define _开始 begin +#define _结束 end +//----------------------------------------------------------- +//----------------------------------------------------------- +//基本单元 +#ifdef __cplusplus +#include + +命名空间 中文标准{ + +类 字符串 { +公开的: + /* 初始化为空字符串 */ + 字符串() { + 对象->s = ""; + } + /* 以字面量初始化 */ + 字符串(常量 字符* 源) { + 对象->s = 源; + } + /* 访问器 */ + 常量 字符* 取值() { + 返回 s.c_str(); + } + /* */ + 字符串& _加法重载(常量 字符* 乙方) { + 对象->s += 乙方; + 返回 *对象; + } + /* 字符串之间的连接 */ + 字符串& _加法重载(字符串& 乙) { + 对象->s += 乙.取值(); + 返回 *对象; + } +私有的: + std::string s; +}; + +类 标准输出{ +公开的: + 空类型 调试输出(常量 字符* 消息) { + std::cout << 消息; + } + 空类型 调试输出(字符串& 信) { + std::cout<< 信.取值(); + } +}; + +类 标准输入{ +公开的: + 字符串 取字符串(){ + std::string s; + std::cin >> s; + 返回 字符串(s.c_str()); + } + 整数 取整数() { + 整数 数; + std::cin >> 数; + 返回 数; + } +}; + + +} +#endif //__cplusplus +#endif //__中文模式 diff --git a/lci/include/cn/向量.hpp b/lci/include/cn/向量.hpp new file mode 100644 index 0000000..2380e08 --- /dev/null +++ b/lci/include/cn/向量.hpp @@ -0,0 +1,129 @@ +#pragma once +#include "中文化.hpp" +#include "异常.hpp" +命名空间 中文标准 { +模板 <类型名 类型1> +类 向量{ +公开的: + + /* 注意:当长度单位为0时,内部指针是空的 */ + 向量() { + 对象->指针 = 空指针; + 对象->容量 = 0; + } + /* 专门用于处理花括号初始化列表 */ + 向量(常量 std::initializer_list<类型1>& init = {}) { + 对象->指针 = 新建 类型1[init.size()] {空的}; + 对象->容量 = init.size(); + 长度单位 计数 = 0; + 计次循环(适应 & 东西: init) { + 对象->指针[计数++] = 东西; + } + } + + ~向量() { + 删除 对象->指针; + 对象->指针 = 空指针; + 对象->容量 = 0; + } + /*----------访问器----------*/ + 长度单位 取容量() { + 返回 对象->容量; + } + + 布尔 是否为空() { + 返回 对象->容量 等于 0; + } + + /*--------运算符重载--------*/ + 向量& _取下标重载( 常量 长度单位 下标 ) { + 如果(下标 < 0 或 下标 >= 对象->容量) + 抛出异常 下标越界{"向量", 对象->容量, 下标}; + 返回 对象->指针[下标]; + } + + /*--------可范围遍历--------*/ + 类型1* _开始() { + 返回 对象->指针; + } + + 类型1* _结束() { + 返回 对象->指针 + 对象->容量; + } + + /*----------变异器----------*/ + 空类型 插入元素(常量 长度单位 位置, 常量 向量& 媒介) { + + /* 越界检查 */ + 如果(位置 < 0 或 位置 > 对象->容量) + 抛出异常 下标越界{"向量元素插入", 对象->容量+1, 位置}; + + 适应 长度 = 取容量(); + 适应 新的 = 新建 类型1[长度 + 1] { 空的 }; + + /* 插入位置之前 */ + 计次循环(适应 计数 = 0; 计数 < 位置; ++计数) + 新的[计数] = 对象->指针[计数]; + + /* 执行插入 */ + 新的[位置] = 媒介; + + /* 插入位置之后 */ + 计次循环(适应 计数 = 位置 + 1; 计数 <= 长度; ++计数) + 新的[计数] = 对象->指针[计数 - 1]; + + 如果(对象->指针) 删除[] 对象->指针; /* 可能为空 */ + 对象->指针 = 新的; + } + + 空类型 追加元素(常量 向量& 媒介) { + 适应 长度 = 取容量(); + 适应 新的 = 新建 类型1[长度 +1] {空的}; + 计次循环(适应 计数 = 0; 计数 < 长度; ++计数) + 新的[计数] = 对象->指针[计数]; + 新的[长度] = 媒介; + 如果(对象->指针) 删除[] 指针; /* 可能为空 */ + 对象->指针 = 新的; + } + + 空类型 删除元素(常量 长度单位 位置) { + + /* 越界检查 */ + 如果(位置 < 0 或 位置 >= 对象->容量) + 抛出异常 下标越界{"向量元素插入", 对象->容量 + 1, 位置}; + + 适应 长度 = 取容量(); + 适应 新的 = (长度 等于 1) + ? 空指针 : 新建 类型1[长度 - 1] { 空的 }; + + /* 目标位置之前 */ + 计次循环(适应 计数 = 0; 计数 < 位置; ++计数) + 新的[计数] = 对象->指针[计数]; + + /* 目标位置之后 */ + 计次循环(适应 计数 = 位置; 计数 < 长度; ++计数) + 新的[计数] = 对象->指针[计数 + 1]; + + 删除[] 对象->指针; + 对象->指针 = 新的; + } + + + + /*----------------*/ + //类 迭代器{ + //公开的: + // 迭代器(常量 std::vector<类型1>::iterator& it) { + // this->it = it; + // } + //私有的: + // std::vector<类型1>::iterator it; + //}; + /*----------------*/ + + +私有的: + 类型1 *指针; + 长度单位 容量; +}; +} \ No newline at end of file diff --git a/lci/include/cn/异常.hpp b/lci/include/cn/异常.hpp new file mode 100644 index 0000000..79208bd --- /dev/null +++ b/lci/include/cn/异常.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "中文化.hpp" +命名空间 中文标准 { +类 标准异常 : 公开的 std::exception { +公开的: + 不转换的 标准异常(常量 字符* 信息): 信息(信息) {} + 常量 字符* what() 常量 不报错的 覆盖 { + 返回 信息; + } +私有的: + 常量 字符* 信息; +}; + +类 下标越界 : 公开的 标准异常{ +公开的: + 下标越界(常量 字符 * 提示, 常量 长度单位 标准值, 常量 长度单位 目前值) + : 标准异常(提示), 标准值(标准值), 目前值(目前值) { +}; + 长度单位 取标准值() { 返回 标准值; } + 长度单位 取目前值() { 返回 目前值; } +私有的: + 长度单位 标准值, 目前值; +}; +} \ No newline at end of file diff --git a/lci/include/cn/链串.hpp b/lci/include/cn/链串.hpp new file mode 100644 index 0000000..cd5a9ec --- /dev/null +++ b/lci/include/cn/链串.hpp @@ -0,0 +1,97 @@ +#pragma once +#include "中文化.hpp" +#include "异常.hpp" +#include "顺序表.hpp" +命名空间 中文标准 { +模板 <类型名 类型1, 长度单位 节点大小 = 64> +类 链串 { +公开的: + /* 初始化为空链串 */ + 链串() { + 对象->长度 = 0; + 对象->下一个 = 空指针; + 对象->上一个 = 空指针; + 对象->头 = 对象; /* 每一个子节点都记录同一个头结点 */ + 对象->尾 = 对象; /* 为了方便,只有头结点记录尾节点 */ + } + + 链串 (常量 std::initializer_list<类型1>& init = {}) + { + 计次循环(适应 & 东西: init) { + 插入(东西); + } + } + + /* + * 链式析构 + * + * 析构时,会递归析构所有节点。 + */ + ~链串() { + 删除[] 对象->下一个; + } + + 空类型 插入(常量 类型1& 元素) { + 链串 *暂时 = 对象->尾; + 如果(暂时->长度 等于 节点大小) + _推(); + 暂时->存储[暂时->长度++] = 元素; + } + + 长度单位 统计() { + 长度单位 总数 = 0; + 链串 *暂时 = 对象->头; + 判断循环(暂时 != 空指针) { + 总数 += 暂时->长度; + 暂时 = 暂时->下一个; + } + 返回 总数; + } + + /* + * 链串重组 + * + * 将链串重组为顺序表W + */ + 顺序表<类型1> 重组() { + 顺序表<类型1> 结果(统计()); + 链串 *暂时 = 对象->头; + 长度单位 计数 = 0; + 判断循环(暂时 != 空指针) { + 计次循环(适应 索引 = 0; 索引 < 暂时->长度; ++索引) { + 结果[计数++] = 暂时->存储[索引]; + } + 暂时 = 暂时->下一个; + } + 返回 结果; + } + + 类 链串异常: 公开的 标准异常{ + 公开的: + 链串异常(常量 字符* 消息) : 标准异常(消息) {} + }; +私有的: + 类型1 存储[节点大小]; + 长度单位 长度; /* 存储中的元素数量 */ + 链串 *下一个; + 链串 *上一个; + 链串 *头; + 链串 *尾; + + 空类型 _推() { + 链串*新的; + 尝试{ 新的 = 新建 链串(); } + 捕获异常 (std::exception& exp){ + 抛出异常 链串异常{"链串推失败"}; + } + _拼接节点(新的); + } + + 空类型 _拼接节点(链串* 新的) { + 对象->尾->下一个 = 新的; + 新的->上一个 = 对象->尾; + 对象->尾 = 新的; + 新的->头 = 对象; + } +}; +} \ No newline at end of file diff --git a/lci/include/cn/顺序表.hpp b/lci/include/cn/顺序表.hpp new file mode 100644 index 0000000..d8b55cc --- /dev/null +++ b/lci/include/cn/顺序表.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "中文化.hpp" +#include "异常.hpp" +命名空间 中文标准 { +模板<类型名 类型1> +类 顺序表 { +公开的: + 顺序表(长度单位 大小) { + 存储 = 新建 类型1[大小]; + 长度 = 大小; + } + ~顺序表() { + 删除[] 存储; + } + 类型1 _取下标重载(长度单位 下标) { + 如果(下标 >= 长度) + 抛出异常 顺序表异常{"下标超出范围"}; + 返回 存储[下标]; + } + 类 顺序表异常: 公开的 标准异常{ + 公开的: + 顺序表异常(常量 字符* 消息) : 标准异常(消息) {} + }; +私有的: + 类型1 *存储; + 长度单位 长度; +}; +} \ No newline at end of file diff --git a/lci/include/gui/GTK.hpp b/lci/include/gui/GTK.hpp new file mode 100644 index 0000000..7b93f7f --- /dev/null +++ b/lci/include/gui/GTK.hpp @@ -0,0 +1,560 @@ +#ifndef PMC_GUI_GTK_HPP +#define PMC_GUI_GTK_HPP + +/** + * @file GTK.hpp + * @brief GTK库入口封装 + * + * 提供GTK库的统一入口和简化接口,便于在pmc项目中使用GTK进行GUI开发。 + */ + +#include +#include +#include +#include +#include + +namespace pmc { +namespace gui { + +/** + * @class GTKApplication + * @brief GTK应用程序封装类 + * + * 封装GTK应用程序的初始化和运行逻辑,提供简化的API。 + */ +class GTKApplication { +public: + /** + * @brief 构造函数 + * @param app_id 应用程序ID + * @param app_name 应用程序名称 + */ + GTKApplication(const std::string& app_id, const std::string& app_name); + + /** + * @brief 析构函数 + */ + ~GTKApplication(); + + /** + * @brief 初始化GTK应用程序 + * @param argc 命令行参数数量 + * @param argv 命令行参数数组 + * @return 初始化是否成功 + */ + bool initialize(int argc, char** argv); + + /** + * @brief 运行应用程序 + * @return 应用程序退出码 + */ + int run(); + + /** + * @brief 获取GTK应用程序指针 + * @return GtkApplication指针 + */ + GtkApplication* get_app() const { return app_; } + + /** + * @brief 设置应用程序图标 + * @param icon_path 图标文件路径 + * @return 设置是否成功 + */ + bool set_icon(const std::string& icon_path); + + /** + * @brief 设置窗口默认大小 + * @param width 窗口宽度 + * @param height 窗口高度 + */ + void set_default_window_size(int width, int height); + +private: + std::string app_id_; + std::string app_name_; + GtkApplication* app_; + int default_width_; + int default_height_; +}; + +/** + * @class GTKWindow + * @brief GTK窗口封装类 + * + * 封装GTK窗口的创建和管理,提供简化的窗口操作接口。 + */ +class GTKWindow { +public: + /** + * @brief 构造函数 + * @param title 窗口标题 + * @param width 窗口宽度 + * @param height 窗口高度 + */ + GTKWindow(const std::string& title, int width = 800, int height = 600); + + /** + * @brief 析构函数 + */ + ~GTKWindow(); + + /** + * @brief 显示窗口 + */ + void show(); + + /** + * @brief 隐藏窗口 + */ + void hide(); + + /** + * @brief 设置窗口标题 + * @param title 新标题 + */ + void set_title(const std::string& title); + + /** + * @brief 获取窗口标题 + * @return 窗口标题 + */ + std::string get_title() const; + + /** + * @brief 设置窗口大小 + * @param width 宽度 + * @param height 高度 + */ + void set_size(int width, int height); + + /** + * @brief 获取窗口宽度 + * @return 窗口宽度 + */ + int get_width() const; + + /** + * @brief 获取窗口高度 + * @return 窗口高度 + */ + int get_height() const; + + /** + * @brief 获取GTK窗口指针 + * @return GtkWindow指针 + */ + GtkWindow* get_window() const { return window_; } + + /** + * @brief 设置关闭回调函数 + * @param callback 关闭回调函数 + */ + void set_close_callback(std::function callback); + + /** + * @brief 添加子控件 + * @param widget 要添加的控件 + */ + void add_widget(GtkWidget* widget); + + /** + * @brief 设置窗口位置居中 + */ + void center_on_screen(); + +private: + GtkWindow* window_; + GtkWidget* container_; + std::string title_; + int width_; + int height_; + std::function close_callback_; +}; + +/** + * @class GTKButton + * @brief GTK按钮封装类 + * + * 封装GTK按钮的创建和事件处理。 + */ +class GTKButton { +public: + /** + * @brief 构造函数 + * @param label 按钮标签 + */ + GTKButton(const std::string& label); + + /** + * @brief 析构函数 + */ + ~GTKButton(); + + /** + * @brief 设置点击回调函数 + * @param callback 点击回调函数 + */ + void set_click_callback(std::function callback); + + /** + * @brief 获取GTK按钮指针 + * @return GtkButton指针 + */ + GtkButton* get_button() const { return button_; } + + /** + * @brief 设置按钮标签 + * @param label 新标签 + */ + void set_label(const std::string& label); + + /** + * @brief 获取按钮标签 + * @return 按钮标签 + */ + std::string get_label() const; + + /** + * @brief 启用按钮 + */ + void enable(); + + /** + * @brief 禁用按钮 + */ + void disable(); + + /** + * @brief 设置按钮工具提示 + * @param tooltip 工具提示文本 + */ + void set_tooltip(const std::string& tooltip); + +private: + GtkButton* button_; + std::string label_; + std::function click_callback_; +}; + +/** + * @class GTKLabel + * @brief GTK标签封装类 + * + * 封装GTK标签的创建和文本管理。 + */ +class GTKLabel { +public: + /** + * @brief 构造函数 + * @param text 标签文本 + */ + GTKLabel(const std::string& text = ""); + + /** + * @brief 析构函数 + */ + ~GTKLabel(); + + /** + * @brief 设置标签文本 + * @param text 新文本 + */ + void set_text(const std::string& text); + + /** + * @brief 获取标签文本 + * @return 标签文本 + */ + std::string get_text() const; + + /** + * @brief 获取GTK标签指针 + * @return GtkLabel指针 + */ + GtkLabel* get_label() const { return label_; } + + /** + * @brief 设置文本对齐方式 + * @param xalign 水平对齐 (0.0=左对齐, 0.5=居中, 1.0=右对齐) + * @param yalign 垂直对齐 (0.0=顶部, 0.5=居中, 1.0=底部) + */ + void set_alignment(float xalign = 0.0f, float yalign = 0.5f); + + /** + * @brief 设置文本换行 + * @param wrap 是否换行 + */ + void set_wrap(bool wrap); + + /** + * @brief 设置选择模式 + * @param selectable 是否可选择 + */ + void set_selectable(bool selectable); + +private: + GtkLabel* label_; + std::string text_; +}; + +/** + * @class GTKEntry + * @brief GTK输入框封装类 + * + * 封装GTK输入框的创建和文本管理。 + */ +class GTKEntry { +public: + /** + * @brief 构造函数 + * @param placeholder 占位符文本 + */ + GTKEntry(const std::string& placeholder = ""); + + /** + * @brief 析构函数 + */ + ~GTKEntry(); + + /** + * @brief 获取输入文本 + * @return 输入文本 + */ + std::string get_text() const; + + /** + * @brief 设置输入文本 + * @param text 新文本 + */ + void set_text(const std::string& text); + + /** + * @brief 清空输入框 + */ + void clear(); + + /** + * @brief 获取GTK输入框指针 + * @return GtkEntry指针 + */ + GtkEntry* get_entry() const { return entry_; } + + /** + * @brief 设置占位符文本 + * @param placeholder 占位符文本 + */ + void set_placeholder(const std::string& placeholder); + + /** + * @brief 设置输入变化回调函数 + * @param callback 输入变化回调函数 + */ + void set_changed_callback(std::function callback); + + /** + * @brief 设置激活回调函数(回车键) + * @param callback 激活回调函数 + */ + void set_activate_callback(std::function callback); + + /** + * @brief 启用输入框 + */ + void enable(); + + /** + * @brief 禁用输入框 + */ + void disable(); + +private: + GtkEntry* entry_; + std::string placeholder_; + std::function changed_callback_; + std::function activate_callback_; +}; + +/** + * @class GTKTextView + * @brief GTK文本视图封装类 + * + * 封装GTK文本视图的创建和文本管理,支持多行文本编辑。 + */ +class GTKTextView { +public: + /** + * @brief 构造函数 + */ + GTKTextView(); + + /** + * @brief 析构函数 + */ + ~GTKTextView(); + + /** + * @brief 获取文本内容 + * @return 文本内容 + */ + std::string get_text() const; + + /** + * @brief 设置文本内容 + * @param text 新文本 + */ + void set_text(const std::string& text); + + /** + * @brief 追加文本 + * @param text 要追加的文本 + */ + void append_text(const std::string& text); + + /** + * @brief 清空文本 + */ + void clear(); + + /** + * @brief 获取GTK文本视图指针 + * @return GtkTextView指针 + */ + GtkTextView* get_text_view() const { return text_view_; } + + /** + * @brief 获取文本缓冲区 + * @return GtkTextBuffer指针 + */ + GtkTextBuffer* get_buffer() const { return buffer_; } + + /** + * @brief 设置只读模式 + * @param read_only 是否只读 + */ + void set_read_only(bool read_only); + + /** + * @brief 设置文本变化回调函数 + * @param callback 文本变化回调函数 + */ + void set_changed_callback(std::function callback); + + /** + * @brief 滚动到底部 + */ + void scroll_to_bottom(); + +private: + GtkTextView* text_view_; + GtkTextBuffer* buffer_; + std::function changed_callback_; +}; + +/** + * @class GTKBox + * @brief GTK盒子布局容器封装类 + * + * 封装GTK盒子布局容器的创建和子控件管理。 + */ +class GTKBox { +public: + /** + * @brief 构造函数 + * @param orientation 布局方向 (GTK_ORIENTATION_HORIZONTAL 或 GTK_ORIENTATION_VERTICAL) + * @param spacing 子控件间距 + */ + GTKBox(GtkOrientation orientation = GTK_ORIENTATION_VERTICAL, int spacing = 5); + + /** + * @brief 析构函数 + */ + ~GTKBox(); + + /** + * @brief 添加子控件 + * @param widget 要添加的控件 + * @param expand 是否扩展 + * @param fill 是否填充 + * @param padding 内边距 + */ + void add_widget(GtkWidget* widget, bool expand = false, bool fill = false, int padding = 0); + + /** + * @brief 获取GTK盒子指针 + * @return GtkBox指针 + */ + GtkBox* get_box() const { return box_; } + + /** + * @brief 设置间距 + * @param spacing 新间距 + */ + void set_spacing(int spacing); + + /** + * @brief 设置对齐方式 + * @param align 对齐方式 + */ + void set_alignment(GtkAlign align); + + /** + * @brief 设置均匀分配 + * @param homogeneous 是否均匀分配空间 + */ + void set_homogeneous(bool homogeneous); + +private: + GtkBox* box_; + GtkOrientation orientation_; + int spacing_; +}; + +/** + * @brief 初始化GTK库 + * @param argc 命令行参数数量指针 + * @param argv 命令行参数数组指针 + * @return 初始化是否成功 + */ +bool gtk_init(int* argc, char*** argv); + +/** + * @brief 运行GTK主循环 + */ +void gtk_main(); + +/** + * @brief 退出GTK主循环 + */ +void gtk_main_quit(); + +/** + * @brief 显示错误对话框 + * @param parent 父窗口 + * @param title 对话框标题 + * @param message 错误消息 + */ +void show_error_dialog(GtkWindow* parent, const std::string& title, const std::string& message); + +/** + * @brief 显示信息对话框 + * @param parent 父窗口 + * @param title 对话框标题 + * @param message 信息消息 + */ +void show_info_dialog(GtkWindow* parent, const std::string& title, const std::string& message); + +/** + * @brief 显示确认对话框 + * @param parent 父窗口 + * @param title 对话框标题 + * @param message 确认消息 + * @return 用户是否确认 + */ +bool show_confirm_dialog(GtkWindow* parent, const std::string& title, const std::string& message); + +} // namespace gui +} // namespace pmc + +#endif // PMC_GUI_GTK_HPP \ No newline at end of file diff --git a/lci/include/gui/GTK_impl.hpp b/lci/include/gui/GTK_impl.hpp new file mode 100644 index 0000000..4d57b38 --- /dev/null +++ b/lci/include/gui/GTK_impl.hpp @@ -0,0 +1,456 @@ +#ifndef PMC_GUI_GTK_IMPL_HPP +#define PMC_GUI_GTK_IMPL_HPP + +/** + * @file GTK_impl.hpp + * @brief GTK库封装实现模板 + * + * 提供GTK封装类的内联实现,便于头文件包含。 + */ + +#include "gui/GTK.hpp" +#include + +namespace pmc { +namespace gui { + +// GTKApplication 实现 +inline GTKApplication::GTKApplication(const std::string& app_id, const std::string& app_name) + : app_id_(app_id), app_name_(app_name), app_(nullptr), default_width_(800), default_height_(600) { +} + +inline GTKApplication::~GTKApplication() { + if (app_) { + g_object_unref(app_); + } +} + +inline bool GTKApplication::initialize(int argc, char** argv) { + app_ = gtk_application_new(app_id_.c_str(), G_APPLICATION_FLAGS_NONE); + if (!app_) { + std::cerr << "Failed to create GTK application: " << app_name_ << std::endl; + return false; + } + return true; +} + +inline int GTKApplication::run() { + if (!app_) { + std::cerr << "GTK application not initialized" << std::endl; + return -1; + } + return g_application_run(G_APPLICATION(app_), 0, nullptr); +} + +inline bool GTKApplication::set_icon(const std::string& icon_path) { + // 实现图标设置逻辑 + return true; +} + +inline void GTKApplication::set_default_window_size(int width, int height) { + default_width_ = width; + default_height_ = height; +} + +// GTKWindow 实现 +inline GTKWindow::GTKWindow(const std::string& title, int width, int height) + : title_(title), width_(width), height_(height), window_(nullptr), container_(nullptr) { + window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + if (window_) { + gtk_window_set_title(window_, title_.c_str()); + gtk_window_set_default_size(window_, width_, height_); + container_ = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_container_add(GTK_CONTAINER(window_), container_); + } +} + +inline GTKWindow::~GTKWindow() { + // GTK会自动管理窗口内存 +} + +inline void GTKWindow::show() { + if (window_) { + gtk_widget_show_all(GTK_WIDGET(window_)); + } +} + +inline void GTKWindow::hide() { + if (window_) { + gtk_widget_hide(GTK_WIDGET(window_)); + } +} + +inline void GTKWindow::set_title(const std::string& title) { + title_ = title; + if (window_) { + gtk_window_set_title(window_, title_.c_str()); + } +} + +inline std::string GTKWindow::get_title() const { + return title_; +} + +inline void GTKWindow::set_size(int width, int height) { + width_ = width; + height_ = height; + if (window_) { + gtk_window_resize(window_, width_, height_); + } +} + +inline int GTKWindow::get_width() const { + return width_; +} + +inline int GTKWindow::get_height() const { + return height_; +} + +inline void GTKWindow::set_close_callback(std::function callback) { + close_callback_ = callback; + if (window_) { + g_signal_connect(window_, "destroy", G_CALLBACK(+[](GtkWidget* widget, gpointer data) { + auto self = static_cast(data); + if (self && self->close_callback_) { + self->close_callback_(); + } + }), this); + } +} + +inline void GTKWindow::add_widget(GtkWidget* widget) { + if (container_ && widget) { + gtk_container_add(GTK_CONTAINER(container_), widget); + } +} + +inline void GTKWindow::center_on_screen() { + if (window_) { + gtk_window_set_position(window_, GTK_WIN_POS_CENTER); + } +} + +// GTKButton 实现 +inline GTKButton::GTKButton(const std::string& label) + : label_(label) { + button_ = GTK_BUTTON(gtk_button_new_with_label(label_.c_str())); +} + +inline GTKButton::~GTKButton() { + // GTK会自动管理按钮内存 +} + +inline void GTKButton::set_click_callback(std::function callback) { + click_callback_ = callback; + if (button_) { + g_signal_connect(button_, "clicked", G_CALLBACK(+[](GtkButton* button, gpointer data) { + auto self = static_cast(data); + if (self && self->click_callback_) { + self->click_callback_(); + } + }), this); + } +} + +inline void GTKButton::set_label(const std::string& label) { + label_ = label; + if (button_) { + gtk_button_set_label(button_, label_.c_str()); + } +} + +inline std::string GTKButton::get_label() const { + return label_; +} + +inline void GTKButton::enable() { + if (button_) { + gtk_widget_set_sensitive(GTK_WIDGET(button_), TRUE); + } +} + +inline void GTKButton::disable() { + if (button_) { + gtk_widget_set_sensitive(GTK_WIDGET(button_), FALSE); + } +} + +inline void GTKButton::set_tooltip(const std::string& tooltip) { + if (button_) { + gtk_widget_set_tooltip_text(GTK_WIDGET(button_), tooltip.c_str()); + } +} + +// GTKLabel 实现 +inline GTKLabel::GTKLabel(const std::string& text) + : text_(text) { + label_ = GTK_LABEL(gtk_label_new(text_.c_str())); +} + +inline GTKLabel::~GTKLabel() { + // GTK会自动管理标签内存 +} + +inline void GTKLabel::set_text(const std::string& text) { + text_ = text; + if (label_) { + gtk_label_set_text(label_, text_.c_str()); + } +} + +inline std::string GTKLabel::get_text() const { + return text_; +} + +inline void GTKLabel::set_alignment(float xalign, float yalign) { + if (label_) { + gtk_label_set_xalign(label_, xalign); + gtk_label_set_yalign(label_, yalign); + } +} + +inline void GTKLabel::set_wrap(bool wrap) { + if (label_) { + gtk_label_set_line_wrap(label_, wrap); + } +} + +inline void GTKLabel::set_selectable(bool selectable) { + if (label_) { + gtk_label_set_selectable(label_, selectable); + } +} + +// GTKEntry 实现 +inline GTKEntry::GTKEntry(const std::string& placeholder) + : placeholder_(placeholder) { + entry_ = GTK_ENTRY(gtk_entry_new()); + if (!placeholder_.empty()) { + gtk_entry_set_placeholder_text(entry_, placeholder_.c_str()); + } +} + +inline GTKEntry::~GTKEntry() { + // GTK会自动管理输入框内存 +} + +inline std::string GTKEntry::get_text() const { + if (entry_) { + const gchar* text = gtk_entry_get_text(entry_); + return text ? std::string(text) : ""; + } + return ""; +} + +inline void GTKEntry::set_text(const std::string& text) { + if (entry_) { + gtk_entry_set_text(entry_, text.c_str()); + } +} + +inline void GTKEntry::clear() { + if (entry_) { + gtk_entry_set_text(entry_, ""); + } +} + +inline void GTKEntry::set_placeholder(const std::string& placeholder) { + placeholder_ = placeholder; + if (entry_) { + gtk_entry_set_placeholder_text(entry_, placeholder_.c_str()); + } +} + +inline void GTKEntry::set_changed_callback(std::function callback) { + changed_callback_ = callback; + if (entry_) { + g_signal_connect(entry_, "changed", G_CALLBACK(+[](GtkEntry* entry, gpointer data) { + auto self = static_cast(data); + if (self && self->changed_callback_) { + self->changed_callback_(); + } + }), this); + } +} + +inline void GTKEntry::set_activate_callback(std::function callback) { + activate_callback_ = callback; + if (entry_) { + g_signal_connect(entry_, "activate", G_CALLBACK(+[](GtkEntry* entry, gpointer data) { + auto self = static_cast(data); + if (self && self->activate_callback_) { + self->activate_callback_(); + } + }), this); + } +} + +inline void GTKEntry::enable() { + if (entry_) { + gtk_widget_set_sensitive(GTK_WIDGET(entry_), TRUE); + } +} + +inline void GTKEntry::disable() { + if (entry_) { + gtk_widget_set_sensitive(GTK_WIDGET(entry_), FALSE); + } +} + +// GTKTextView 实现 +inline GTKTextView::GTKTextView() { + text_view_ = GTK_TEXT_VIEW(gtk_text_view_new()); + buffer_ = gtk_text_view_get_buffer(text_view_); +} + +inline GTKTextView::~GTKTextView() { + // GTK会自动管理文本视图内存 +} + +inline std::string GTKTextView::get_text() const { + if (buffer_) { + GtkTextIter start, end; + gtk_text_buffer_get_start_iter(buffer_, &start); + gtk_text_buffer_get_end_iter(buffer_, &end); + gchar* text = gtk_text_buffer_get_text(buffer_, &start, &end, FALSE); + std::string result(text ? text : ""); + g_free(text); + return result; + } + return ""; +} + +inline void GTKTextView::set_text(const std::string& text) { + if (buffer_) { + gtk_text_buffer_set_text(buffer_, text.c_str(), -1); + } +} + +inline void GTKTextView::append_text(const std::string& text) { + if (buffer_) { + GtkTextIter end; + gtk_text_buffer_get_end_iter(buffer_, &end); + gtk_text_buffer_insert(buffer_, &end, text.c_str(), -1); + } +} + +inline void GTKTextView::clear() { + if (buffer_) { + gtk_text_buffer_set_text(buffer_, "", -1); + } +} + +inline void GTKTextView::set_read_only(bool read_only) { + if (text_view_) { + gtk_text_view_set_editable(text_view_, !read_only); + } +} + +inline void GTKTextView::set_changed_callback(std::function callback) { + changed_callback_ = callback; + if (buffer_) { + g_signal_connect(buffer_, "changed", G_CALLBACK(+[](GtkTextBuffer* buffer, gpointer data) { + auto self = static_cast(data); + if (self && self->changed_callback_) { + self->changed_callback_(); + } + }), this); + } +} + +inline void GTKTextView::scroll_to_bottom() { + if (text_view_ && buffer_) { + GtkTextIter end; + gtk_text_buffer_get_end_iter(buffer_, &end); + gtk_text_view_scroll_to_iter(text_view_, &end, 0.0, FALSE, 0.0, 0.0); + } +} + +// GTKBox 实现 +inline GTKBox::GTKBox(GtkOrientation orientation, int spacing) + : orientation_(orientation), spacing_(spacing) { + box_ = GTK_BOX(gtk_box_new(orientation_, spacing_)); +} + +inline GTKBox::~GTKBox() { + // GTK会自动管理盒子内存 +} + +inline void GTKBox::add_widget(GtkWidget* widget, bool expand, bool fill, int padding) { + if (box_ && widget) { + gtk_box_pack_start(box_, widget, expand, fill, padding); + } +} + +inline void GTKBox::set_spacing(int spacing) { + spacing_ = spacing; + if (box_) { + gtk_box_set_spacing(box_, spacing_); + } +} + +inline void GTKBox::set_alignment(GtkAlign align) { + if (box_) { + gtk_widget_set_halign(GTK_WIDGET(box_), align); + gtk_widget_set_valign(GTK_WIDGET(box_), align); + } +} + +inline void GTKBox::set_homogeneous(bool homogeneous) { + if (box_) { + gtk_box_set_homogeneous(box_, homogeneous); + } +} + +// 全局函数实现 +inline bool gtk_init(int* argc, char*** argv) { + return gtk_init_check(argc, argv); +} + +inline void gtk_main() { + ::gtk_main(); +} + +inline void gtk_main_quit() { + ::gtk_main_quit(); +} + +inline void show_error_dialog(GtkWindow* parent, const std::string& title, const std::string& message) { + GtkWidget* dialog = gtk_message_dialog_new(parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", message.c_str()); + gtk_window_set_title(GTK_WINDOW(dialog), title.c_str()); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +inline void show_info_dialog(GtkWindow* parent, const std::string& title, const std::string& message) { + GtkWidget* dialog = gtk_message_dialog_new(parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s", message.c_str()); + gtk_window_set_title(GTK_WINDOW(dialog), title.c_str()); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +inline bool show_confirm_dialog(GtkWindow* parent, const std::string& title, const std::string& message) { + GtkWidget* dialog = gtk_message_dialog_new(parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_YES_NO, + "%s", message.c_str()); + gtk_window_set_title(GTK_WINDOW(dialog), title.c_str()); + gint response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return response == GTK_RESPONSE_YES; +} + +} // namespace gui +} // namespace pmc + +#endif // PMC_GUI_GTK_IMPL_HPP \ No newline at end of file diff --git a/lci/include/gui/README.md b/lci/include/gui/README.md new file mode 100644 index 0000000..1b57015 --- /dev/null +++ b/lci/include/gui/README.md @@ -0,0 +1,174 @@ +# PMC GUI 模块 - GTK 封装 + +## 概述 + +本模块提供了对GTK库的C++封装,简化在pmc项目中使用GTK进行GUI开发的过程。封装提供了面向对象的接口,隐藏了GTK的C语言细节。 + +## 文件结构 + +``` +include/gui/ +├── GTK.hpp # 主封装头文件(类声明) +├── GTK_impl.hpp # 内联实现文件 +├── gui.hpp # GUI模块主入口 +├── example.hpp # 使用示例 +└── README.md # 本文档 +``` + +## 主要类 + +### 1. GTKApplication +封装GTK应用程序的初始化和运行。 + +```cpp +pmc::gui::GTKApplication app("com.example.pmc", "PMC Application"); +app.initialize(argc, argv); +app.run(); +``` + +### 2. GTKWindow +封装GTK窗口的创建和管理。 + +```cpp +pmc::gui::GTKWindow window("My Window", 800, 600); +window.set_close_callback([]() { + std::cout << "Window closing" << std::endl; + gtk_main_quit(); +}); +window.show(); +``` + +### 3. GTKButton +封装GTK按钮的创建和事件处理。 + +```cpp +pmc::gui::GTKButton button("Click Me"); +button.set_click_callback([]() { + std::cout << "Button clicked!" << std::endl; +}); +``` + +### 4. GTKEntry +封装GTK输入框的创建和文本管理。 + +```cpp +pmc::gui::GTKEntry entry("Enter text here..."); +entry.set_activate_callback([]() { + std::string text = entry.get_text(); + std::cout << "Entered: " << text << std::endl; +}); +``` + +### 5. GTKTextView +封装GTK文本视图的创建和文本管理。 + +```cpp +pmc::gui::GTKTextView text_view; +text_view.set_read_only(true); +text_view.append_text("Hello, World!\n"); +``` + +### 6. GTKBox +封装GTK盒子布局容器的创建和子控件管理。 + +```cpp +pmc::gui::GTKBox vbox(GTK_ORIENTATION_VERTICAL, 5); +vbox.add_widget(GTK_WIDGET(button.get_button())); +vbox.add_widget(GTK_WIDGET(entry.get_entry())); +``` + +## 使用示例 + +### 简单聊天窗口 + +```cpp +#include "gui/example.hpp" + +int main(int argc, char** argv) { + pmc::gui::example::run_simple_chat_example(argc, argv); + return 0; +} +``` + +### 设置窗口 + +```cpp +#include "gui/example.hpp" + +int main(int argc, char** argv) { + pmc::gui::example::run_settings_example(argc, argv); + return 0; +} +``` + +## 编译要求 + +### 依赖项 +- GTK+ 3.0 或更高版本 +- C++11 或更高版本 + +### Ubuntu/Debian 安装依赖 +```bash +sudo apt-get install libgtk-3-dev +``` + +### Fedora/RHEL 安装依赖 +```bash +sudo dnf install gtk3-devel +``` + +### 编译命令示例 +```bash +g++ -std=c++11 -o myapp main.cpp `pkg-config --cflags --libs gtk+-3.0` +``` + +## 集成到pmc项目 + +### 1. 在CMakeLists.txt中添加 +```cmake +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK3 REQUIRED gtk+-3.0) + +include_directories(${GTK3_INCLUDE_DIRS}) +target_link_libraries(your_target ${GTK3_LIBRARIES}) +``` + +### 2. 使用封装类 +```cpp +#include "gui/GTK.hpp" + +// 使用pmc::gui命名空间中的类 +``` + +## 设计原则 + +1. **简化接口**:隐藏GTK的C语言细节,提供C++面向对象接口 +2. **资源管理**:使用RAII原则管理GTK对象生命周期 +3. **类型安全**:使用C++类型系统减少错误 +4. **可扩展性**:易于添加新的封装类 +5. **向后兼容**:保持与原生GTK API的互操作性 + +## 注意事项 + +1. **线程安全**:GTK不是线程安全的,所有GUI操作必须在主线程进行 +2. **内存管理**:GTK使用引用计数,封装类会自动处理引用 +3. **信号连接**:使用lambda表达式简化信号处理 +4. **错误处理**:提供基本的错误检查和对话框支持 + +## 扩展指南 + +要添加新的GTK控件封装: + +1. 在`GTK.hpp`中声明类 +2. 在`GTK_impl.hpp`中实现内联方法 +3. 提供构造函数、析构函数和主要方法 +4. 添加信号连接支持 +5. 更新示例和文档 + +## 许可证 + +本模块遵循pmc项目的整体许可证。 + +## 贡献 + +欢迎提交问题和拉取请求改进本模块。 \ No newline at end of file diff --git a/lci/include/gui/gui.hpp b/lci/include/gui/gui.hpp new file mode 100644 index 0000000..e8bdfb6 --- /dev/null +++ b/lci/include/gui/gui.hpp @@ -0,0 +1,100 @@ +#ifndef PMC_GUI_HPP +#define PMC_GUI_HPP + +/** + * @file gui.hpp + * @brief pmc项目GUI模块主入口 + * + * 提供GTK GUI模块的统一入口,简化GUI开发。 + */ + +#include "gui/GTK.hpp" + +namespace pmc { +namespace gui { + +/** + * @brief 初始化GUI模块 + * @param argc 命令行参数数量 + * @param argv 命令行参数数组 + * @return 初始化是否成功 + */ +bool init(int argc, char** argv); + +/** + * @brief 运行GUI主循环 + */ +void run(); + +/** + * @brief 退出GUI主循环 + */ +void quit(); + +/** + * @brief 创建主窗口 + * @param title 窗口标题 + * @param width 窗口宽度 + * @param height 窗口高度 + * @return 窗口指针 + */ +GTKWindow* create_main_window(const std::string& title = "PMC Application", + int width = 800, int height = 600); + +/** + * @brief 创建聊天窗口 + * @param parent 父窗口 + * @return 聊天窗口指针 + */ +GTKWindow* create_chat_window(GTKWindow* parent = nullptr); + +/** + * @brief 创建设置窗口 + * @param parent 父窗口 + * @return 设置窗口指针 + */ +GTKWindow* create_settings_window(GTKWindow* parent = nullptr); + +/** + * @brief 显示关于对话框 + * @param parent 父窗口 + */ +void show_about_dialog(GTKWindow* parent); + +/** + * @brief 显示状态栏 + * @param parent 父窗口 + * @param message 状态消息 + */ +void show_status_bar(GTKWindow* parent, const std::string& message); + +/** + * @brief 更新状态栏消息 + * @param message 新状态消息 + */ +void update_status_bar(const std::string& message); + +/** + * @brief 显示进度对话框 + * @param parent 父窗口 + * @param title 对话框标题 + * @param message 进度消息 + */ +void show_progress_dialog(GTKWindow* parent, const std::string& title, const std::string& message); + +/** + * @brief 更新进度对话框 + * @param progress 进度值 (0.0-1.0) + * @param message 进度消息 + */ +void update_progress_dialog(double progress, const std::string& message); + +/** + * @brief 关闭进度对话框 + */ +void close_progress_dialog(); + +} // namespace gui +} // namespace pmc + +#endif // PMC_GUI_HPP \ No newline at end of file diff --git a/lci/include/hd/Camera.h b/lci/include/hd/Camera.h new file mode 100644 index 0000000..459322b --- /dev/null +++ b/lci/include/hd/Camera.h @@ -0,0 +1,12 @@ +#pragma once + +/* Camera */ +#define cimg_display 0 /* 不显示图像,只保存 */ +#include "CImg.h" + +void Camera_init(int w, int h); +void Camera_close(); +bool Camera_is_open(); + +/* 在线程安全的情况下取得一帧图像 */ +cimg_library::CImg get_frame_from_camera(bool& flag); \ No newline at end of file diff --git a/lci/include/hd/Robot.hpp b/lci/include/hd/Robot.hpp new file mode 100644 index 0000000..9d68af2 --- /dev/null +++ b/lci/include/hd/Robot.hpp @@ -0,0 +1,241 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "cn/中文化.hpp" +#include "Dashun_linux.hpp" +命名空间 qing{ +类 伺服电机{ /* 180度舵机 */ +公开的: + + /* FIXME: min只能比max小 */ + 伺服电机(整数 通道, 单精度小数 上限=180, 单精度小数 下限=0, 逻辑型 逆向=false) + : 通道(通道), 上限(上限), 下限(下限), 逆向(逆向) {} + + /* 控制舵机运行至一个角度 */ + 空类型 转动至(单精度小数 角度) { + 角度 = std::min(上限, 角度); + 角度 = std::max(下限, 角度); + PCA9685_调整角度( + 通道, (逆向) ? 180 - 角度 : 角度 + ); + } + + /* FIXME: 返回最大值 */ + 单精度小数 取上限() { + 返回 上限; + } + + +私有的: + 整数 通道; /* 通道编号 */ + 单精度小数 上限; /* 角度上限 */ + 单精度小数 下限; /* 角度下限 */ + 逻辑型 逆向; /* 是否反向 */ +}; +} + +命名空间 qing { +类 ActParser{ /* 动作脚本解析器 */ +公开的: + + /* 解析标准输入中的动作脚本 */ + 空类型 fromStdin() { + 计数 = 0; + 清除所有(); + 解析(std::cin); + } + + /* 解析文件输入流中的动作脚本 */ + 空类型 fromFile(const std::string& 路径) { + 计数 = 0; + std::ifstream 文件(路径.c_str(), std::ios::in); + 如果 (!文件.is_open()) + 抛出异常 std::runtime_error("打开文件失败"); + 清除所有(); + 解析(文件); + 文件.close(); + } + + /* 解析字符串流中的动作脚本 */ + 空类型 fromStr(const std::string& 脚本) { + std::stringstream 流(脚本); + 计数 = 0; + 清除所有(); + 解析(流); + } + + /* 执行刚刚解析出来的机器人和动作 */ + 空类型 play() { + 如果 (机组.empty() || 矩阵.empty()) + 抛出异常 std::runtime_error("没动作或机组"); + 机器人扮演(机组, 矩阵); + } + + /* 获得机器人的最大值向量, FIXME: 把逻辑写在外面 */ + std::vector get() { + 适应 结果 = std::vector(); + 计次循环 (适应& 项目: this->机组) { + 结果.push_back(项目.取上限()); + } + /* 这个数组中包含机器人每个舵机的角度上限 */ + 返回 结果; + } + + /* 获取当前这一组动作 */ + std::vector now() { + 如果 (计数 >= 矩阵.size()) + 抛出异常 std::runtime_error("now finished"); + 返回 矩阵[计数]; + } + + /* 执行下一组动作 */ + 空类型 next() { + 如果 (计数 >= 矩阵.size()) + 抛出异常 std::runtime_error("没下一个动作了"); + 适应 临时向量 = 矩阵[计数++]; + 适应 临时矩阵 = std::vector> ({临时向量}); + 机器人扮演(机组, 临时矩阵); + } + + /* 输入下一个动作执行 */ + 空类型 next(std::vector& act) { + 计数++; + auto vv = std::vector> ({act}); + 机器人扮演(机组, vv); + } +private: + 字符 句[16] = {0}; /* FIXME: 这个栈有越界风险 */ + 整数 顶 = 0; + 整数 计数 = 0; + std::vector 数组; /* 临时使用 */ + std::vector> 矩阵; /* 解析出的整套动作 */ + std::vector<伺服电机> 机组; /* 机器人抽象 */ + 空类型 解析(std::istream& 源) { /* NOTE: 修改为非静态成员函数能够减少行数 FIXME: 改为使用C++风格的文件操作 */ + 清除临时(); + 字符 c = 0; + 布尔 end_flag = true; + 布尔 comment_flag = false; + 布尔 obj_flag = false; + 判断循环 (end_flag) { /* 255 for arm */ + end_flag = (bool)源.get(c); + //std::cout<= '0' && c <= '9') || c == '+' || c == '-') { /* 读取数字 */ + 句[顶++] = c; + std::cout< 0) { + 单精度小数 角度 = (单精度小数)atoi(句); + 数组.push_back(角度); + std::cout<<角度<{}; + } + } + + 空类型 递交机组() { + 如果 (!数组.empty()) { + std::cout << "接收到机组: " << 数组.size() << std::endl; + 机组 = 机组工厂(数组); + 数组 = std::vector{}; + } + } + + 空类型 清除临时() { + 句[0] = '\0'; + 顶 = 0; + 数组 = std::vector {}; + } + + 空类型 清除所有() { + 句[0] = '\0'; + 顶 = 0; + 数组 = std::vector {}; + 矩阵 = std::vector> {}; + 机组 = std::vector<伺服电机> {}; + } + + /* 机器人工厂,FIXME: 这里可以做成舵机工厂就可以了, */ + 静态的 std::vector<伺服电机> 机组工厂(const std::vector& 上限集) { + std::vector<伺服电机> 机组; + 计次循环 (整数 甲=0; 甲 < 上限集.size(); ++甲) + 机组.push_back( + 伺服电机(甲, std::abs(上限集[甲]), 0, (上限集[甲] >= 0) ? 假 : 真)); + 返回 机组; + } + + /* 机器人移动,输入一组舵机对象和一组目标角度 */ + 静态的 空类型 机器人行动(std::vector<伺服电机>& 机组, std::vector& 动作) { + 如果 (机组.size() + 1 != 动作.size()) + 抛出异常 std::runtime_error( + "动作与机组不符合, 我们有" + + std::to_string(机组.size()) + "和" + std::to_string(动作.size()) + ); + + /* FIXME: 随机下标以消除先后时间差 */ + 计次循环 (int 甲=0; 甲<机组.size(); ++甲) { + 机组[甲].转动至(动作[甲]); + } + /* 最后一组数据是毫秒延时 */ + 预求值的 整数 缩放 = 1000; + usleep(动作[动作.size()-1] * 缩放); + } + + /* 机器人整套动作 */ + 静态的 空类型 机器人扮演( + std::vector<伺服电机>& 机组, std::vector>& 动作集) + { + 计次循环 (适应 动作: 动作集) + 机器人行动(机组, 动作); + } +}; +} diff --git a/lci/include/hd/Serial.hpp b/lci/include/hd/Serial.hpp new file mode 100644 index 0000000..2c5dedc --- /dev/null +++ b/lci/include/hd/Serial.hpp @@ -0,0 +1,206 @@ +/* + * 这是cpp使用linux C手段读写串口的实现。 + * + * 作者在其中加入了“沟通”手段,这种手段主要是针对COPS设备。 + * + * COPS设备的通信手段主要是上位机问,下位机答,一问一答的形式。 + * + * (!)还未进行对于热插拔的支持。 + * + * 20250621 暂时不用了 + */ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace qing { + /* + * 串口类 + * + * 长连接的速度会更快 + */ + class Serial { + private: + /* 串口文件描述符 */ + int fd = 0; + public: + /* 输入设备文件地址,进行构造。打开后通常需要等待一下 */ + Serial(const std::string& path, double wait = 2) { + fd = open(path.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + if (fd == -1) { + throw DeviceOpenErroring(); + } + + + std::this_thread::sleep_for(std::chrono::milliseconds((long)(wait*1000))); /* 等待串口 */ + } + //释放 + ~Serial() { + if (fd != -1) close(fd); + } + + /* 设置串口 */ + void Set() { + struct termios options; + tcgetattr(fd, &options); + cfsetispeed(&options, B115200); /* 设置波特率 */ + cfsetospeed(&options, B115200); + options.c_cflag |= (CLOCAL | CREAD);// 启用接收和本地模式 + options.c_cflag &= ~PARENB;// 8位数据位,无校验,1位停止位 + options.c_cflag &= ~CSTOPB; + options.c_cflag &= ~CSIZE; + options.c_cflag |= CS8; + options.c_cflag &= ~CRTSCTS;// 禁用硬件流控 + options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);// 原始输入模式 + options.c_oflag &= ~OPOST;// 原始输出模式 + options.c_cc[VMIN] = 0;// 设置超时 - 1秒 + options.c_cc[VTIME] = 10; + tcsetattr(fd, TCSANOW, &options); + tcflush(fd, TCIOFLUSH); /* 清空缓冲区 */ + } + + /* 写数据 每次写之前清空缓冲区数据*/ + void Write(const std::string& msg) { + tcflush(fd, TCIOFLUSH); /* 清空缓冲区 */ + write(fd, msg.c_str(), msg.size()); + } + + /* 读数据 */ + std::string CircleRead() { + char buffer[1024] = {0}; + std::string ret = ""; + ssize_t n; + do { + n = read(fd, buffer, sizeof(buffer)); + if (n == -1 && ret == "") { + throw NoResponse(); + } else if (n == -1 && ret != "") { + return ret; + } else if (n == 0) { + return ret; + } else if (n > 0) { + buffer[n] = '\0'; + ret += buffer; + } + } while (true); + } + + /* 读数据 */ + std::string Read() { + char buffer[1024] = {0}; + std::string ret = ""; + ssize_t n; + n = read(fd, buffer, sizeof(buffer)); + if (n == -1 && ret == "") { + throw NoResponse(); + } else if (n > 0) { + buffer[n] = '\0'; + ret += buffer; + } + return ret; + } + + + /* 发送然后获取 */ + std::string Send_Wait_And_Get(const std::string& snd, double wait) { + Write(snd); + std::this_thread::sleep_for(std::chrono::milliseconds((long)(wait*1000))); + return Read(); + } + + /* 一问一答,尝试一定次数 */ + std::string Try_Comm(const std::string& snd, double wait, int times = 10, int drop_tail = 0) { + int num = 0; + while (true) { + try { + num ++; + if (num > times) break; + std::string msg = Send_Wait_And_Get(snd, wait); + DropTail(msg, drop_tail); + return msg; + } catch (qing::Serial::Serial_Error e) { + std::cerr << e.what() << std::endl; + } + } + throw NoResponse(); + } + + /* 去掉字符串末尾一定数量的字符 */ + static void DropTail(std::string& msg, int n) { + for (int i=0; i GetPorts() { + std::vector ports; + //Linux实现 + DIR *dir; + struct dirent *ent; + const std::regex serial_regex("(ttyS|ttyUSB|ttyACM)[0-9]+"); + if ((dir = opendir("/dev")) != NULL) { + while((ent = readdir(dir)) != NULL) { + std::string name = ent->d_name; + if (std::regex_match(name, serial_regex)) { + ports.push_back("/dev/"+name); + } + } + closedir(dir); + } + return ports; + } + + /* 以线程不安全的方式打印所有的串口 */ + static void UnsafePrintPorts() { + auto v = GetPorts(); + for (const auto& i: v) { + std::cout << i << std::endl; + } + } + + }; +} diff --git a/lci/include/hd/cpu.h b/lci/include/hd/cpu.h new file mode 100644 index 0000000..e887288 --- /dev/null +++ b/lci/include/hd/cpu.h @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include + +struct CpuData { + std::string cpu_name; + long user; + long nice; + long system; + long idle; + long iowait; + long irq; + long softirq; + long steal; + long guest; + long guest_nice; + + long total() const { + return user + nice + system + idle + iowait + irq + softirq + steal; + } + + long idle_total() const { + return idle + iowait; + } +}; + +class CpuMonitor { +private: + std::vector read_cpu_stats() { + std::vector stats; + std::ifstream file("/proc/stat"); + std::string line; + + while (std::getline(file, line)) { + if (line.substr(0, 3) == "cpu") { + std::istringstream iss(line); + CpuData data; + iss >> data.cpu_name >> data.user >> data.nice >> data.system + >> data.idle >> data.iowait >> data.irq >> data.softirq + >> data.steal >> data.guest >> data.guest_nice; + stats.push_back(data); + } + } + + return stats; + } + +public: + double get_cpu_usage() { + auto stats1 = read_cpu_stats(); + sleep(1); + auto stats2 = read_cpu_stats(); + + if (stats1.empty() || stats2.empty()) { + return -1.0; + } + + long total_diff = stats2[0].total() - stats1[0].total(); + long idle_diff = stats2[0].idle_total() - stats1[0].idle_total(); + + if (total_diff == 0) { + return 0.0; + } + + return 100.0 * (total_diff - idle_diff) / total_diff; + } + + std::vector get_per_cpu_usage() { + auto stats1 = read_cpu_stats(); + sleep(1); + auto stats2 = read_cpu_stats(); + + std::vector usages; + + for (size_t i = 1; i < stats1.size() && i < stats2.size(); i++) { + long total_diff = stats2[i].total() - stats1[1].total(); + long idle_diff = stats2[i].idle_total() - stats1[i].idle_total(); + + if (total_diff > 0) { + usages.push_back(100.0 * (total_diff - idle_diff) / total_diff); + } else { + usages.push_back(0.0); + } + } + + return usages; + } +}; + + diff --git a/lci/include/hd/mem.h b/lci/include/hd/mem.h new file mode 100644 index 0000000..15d718f --- /dev/null +++ b/lci/include/hd/mem.h @@ -0,0 +1,14 @@ +#ifndef HD_MEM_H +#define HD_MEM_H +#include +#include + +struct MemoryInfo { + long totalMemory; /* 总内存(bytes) */ + long freeMemory; /* 空闲内存 */ + long usedMemory; /* 已用内存 */ + double usageRate; /* 使用率(%) */ +}; + +MemoryInfo getMemoryUsageWithSysinfo(); +#endif diff --git a/lci/include/lci/Area.h b/lci/include/lci/Area.h new file mode 100644 index 0000000..8de0df0 --- /dev/null +++ b/lci/include/lci/Area.h @@ -0,0 +1,21 @@ +/* + * Area是某个形状上的一个区域,它没有自己的帧缓冲区 + * + * + */ + +#pragma once +#include "Drawable.h" +namespace qing { +class Area: public Drawable { +public: + /* Phase Plotting Method 相图法 */ + Area(Drawable *d, int w, int h, int x, int y, int rotate, int fontsize); + Color _get(int x, int y) override; /* 实现接口 */ + void _p(int x, int y, Color &clr) override; + virtual void flush(Drawable *n, bool border = false) override; + virtual void move(int x, int y); +protected: + Drawable *d; /* 持有的绘制主体 */ +}; +} diff --git a/lci/include/lci/Arguments.h b/lci/include/lci/Arguments.h new file mode 100644 index 0000000..6e22ce3 --- /dev/null +++ b/lci/include/lci/Arguments.h @@ -0,0 +1,72 @@ +#pragma once +#include +#include +namespace qing { + +/* + * C++ 的命令行 + */ + +class Arguments { +public: + Arguments(int argc, char **argv) { + for (int i=1; i 1 && item[0] == '-' && item[1] != '-') { + for (unsigned long j=1; j 2 && item[0] == '-' && item[1] == '-' && item[2] != '-') { + std::string arg = get_long_param_key(item); + size_t pos =arg.find('='); + if (pos == (long unsigned int)-1) { + std::cout << arg << std::endl; + m.insert(std::pair(arg, "")); + } else { + std::string k = arg.substr(0, pos); + std::string v = arg.substr(pos+1, arg.length()-pos-1); + std::cout << k << "=" << v << std::endl; + m.insert(std::pair(k, v)); + } + + } else { + throw WrongArgument(item); + } + + } + } + + std::map &get_m() { + return m; + } + std::map &get_mc() { + return mc; + } + + class WrongArgument: std::runtime_error { /* 错的参数 */ + public: + WrongArgument(std::string key): std::runtime_error(key) {} + }; + + private: + std::map m; + std::map mc; + + std::string get_long_param_key(std::string &s) { + return s.substr(2, s.length() -2); + } + +}; + +} diff --git a/lci/include/lci/CharShape.h b/lci/include/lci/CharShape.h new file mode 100644 index 0000000..78b4a7b --- /dev/null +++ b/lci/include/lci/CharShape.h @@ -0,0 +1,22 @@ +#pragma once +#include "lci/Shape.h" +#include "lci/字体绘制器.h" +namespace qing { +class CharShape: public Shape { +public: + CharShape(int w, int h, int x, int y, wchar_t wc) + : Shape(w, h, x, y), wc(wc), 绘制(w, h) {} + + virtual void Draw(Drawable &d, Color clr) override{ + int w = getw(); + int h = geth(); + int x = getx(); + int y = gety(); + 绘制.drawvfont(&d, x, y, wc, clr); + } + +private: + wchar_t wc; + 字体绘制器 绘制; +}; +} diff --git a/lci/include/lci/CmdArea.h b/lci/include/lci/CmdArea.h new file mode 100644 index 0000000..e348b88 --- /dev/null +++ b/lci/include/lci/CmdArea.h @@ -0,0 +1,30 @@ +#pragma once +#include "Area.h" +#include "InputBox.h" +#include +#include +namespace qing { +/* + * CmdArea(命令区域)是一种特殊的Area区域 + * + * 基层绘制方法我们已经在Area中实现了 + */ +class CmdArea: public Area { +public: + CmdArea(Drawable *d, int w, int h, int x, int y, int rotate =0, int fontsize=18, bool hasBox = false); + void Input(char c); + void ClearInput(); + virtual void print(char *utf8, int d=0); /* FIXME: d不知道是什么*/ + void update_input(); + void delete_input(); + void clearBox(); + std::string get_input_and_clear(); +private: + int x_f=0, y_f=0; + std::unique_ptr area; + std::mutex lock; + std::string input = ""; + void handle_ansi_code(char *buffer); + bool hasBox; +}; +} diff --git a/lci/include/lci/Color.h b/lci/include/lci/Color.h new file mode 100644 index 0000000..0d8702a --- /dev/null +++ b/lci/include/lci/Color.h @@ -0,0 +1,25 @@ +#pragma once +namespace qing { + +/* 32位色彩和16位色彩 */ +class Color{ +public: + unsigned char r=0,g=0,b=0; + Color(unsigned char r=0, unsigned char g=0, unsigned char b=0) { + this->r=r; + this->g=g; + this->b=b; + } +}; + +extern const Color black; +extern const Color white; +extern const Color green; +extern const Color blue; +extern const Color red; + +/* FIXME: 完成这个类定义 */ +class Color16 { + public: +}; +} diff --git a/lci/include/lci/CommonThread.h b/lci/include/lci/CommonThread.h new file mode 100644 index 0000000..9637bd0 --- /dev/null +++ b/lci/include/lci/CommonThread.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include +#include "fsm.h" +#include "ThreadInterface.h" +/* +@qing:包含一个简易的多线程控制机制。 +需要共享内存的变量和函数声明为全局变量(通常需要带锁), +线程中单独使用的变量和函数声明到属于它的命名空间中。 +每个线程的主函数包括了对其的流程控制代码。 +stop,setup,loop,clean函数中填入每个状态下的执行代码。 +其中需要用到的函数,又实现在后边。 +*/ + +namespace qing { +namespace lci{ + //线程的主函数 +//----------------------------------------------------------- +/*通常情况下,线程的主函数。*/ + + //前向声明脚本类型 + class CommonThread: public lci::Fsm, ThreadInterface { + //一个持有资源线程的状态机类型 + public: + //构造函数. + //没有必要输入打印机、脚本、线程的名字,放到全局变量 + CommonThread(std::string name); + //暂时删除复制构造函数 + CommonThread(CommonThread&) = delete; + //如果把析构函数放在这里,将会导致纯虚函数错误 + virtual ~CommonThread(); + + //对线程名字的设置 + void SetLabel(std::string name); + //对线程名字的获取 + std::string& GetLabel(); + //----------------------------------------------------------- + //等待线程启动完毕 + //线程启动失败返回失败。线程启动成功或者现程结束返回成功。 + // + //这个函数在某些情况下有可能会一直等待,直到循环结束 + bool WaitStart(unsigned long n); + + void WaitClose(); + + virtual void StopEvent() override; + virtual void WakeEvent() override; + virtual void LoopEvent() override; + virtual void ClearEvent() override; + + void thread_main(); + + private: + + //线程的名字 + std::string label; + //用来存放该子线程的标识符。 + std::thread *thread = NULL; + }; +} +} diff --git a/lci/include/lci/Drawable.h b/lci/include/lci/Drawable.h new file mode 100644 index 0000000..452a614 --- /dev/null +++ b/lci/include/lci/Drawable.h @@ -0,0 +1,89 @@ +/* + * 这个是个抽象类,子类实现抽象的内部接口后 + * + * 可以调用它已经写好的绘制方法。 + */ +#pragma once +#include "Rectangle.h" +#include "Color.h" +#include + +/* 用于文字的绘制 + * FIXME: 使用类封装 */ +extern unsigned char ttu[]; +extern int ttunumber; +extern unsigned char zzhi[]; +extern int zzhinumber; + +namespace qing { +class Drawable { +public: + /* 表示旋转方向 */ + enum class Rotate: char { + R_0 = 0, + R_90 = 1, + R_180 = 2, + R_270 = 3 + }; + + /* 非法的旋转模式 */ + class InvalidRotateMode: std::runtime_error { + public: + InvalidRotateMode(): std::runtime_error("Invalid rotate mode.") {} + }; + + /*====== attr 属性区(访问器) ======*/ + Drawable(int w, int h, int x, int y, int rotate, int fontsize); + virtual Rectangle get_size(); + virtual Rectangle get_pos(); + virtual void set_pos(Rectangle rect); + virtual Color get_color(int x, int y); + virtual void set_color(Color &color); + void FontSize(int fontsize); + int FontSize_get(); + virtual Color& getFontsColor(); + /*------ basic 基本 ------ + * 这些类需要由子类分别进行实现,但是子类不直接调用, + * 而是由抽象基类中实现的方法调用 */ + virtual Color _get(int x, int y) = 0; /* 获取像素点像素 */ + virtual void _p(int x, int y, Color &clr) = 0; /* 绘制像素点像素 */ + //virtual void _up(int x, int y, int w, int h, int level) = 0; /* FIXME: 不使用屏幕移动函数 */ + //virtual void _down(int x, int y, int w, int h, int level) = 0; + //virtual void _left(int x, int y, int w, int h, int level) = 0; + //virtual void _right(int x, int y, int w, int h, int level) = 0; + //virtual void _clear(int x, int y, int w, int h) = 0; /* FIXME: 实现该方法 */ + /*====== drawer 绘制 ====== + * 提供给子类和外部的绘制方法 */ + virtual void point(int x, int y, Color &clr); + virtual void line(int x1, int y1, int x2, int y2, Color &clr); + virtual void rectangle(int x, int y, int w, int h, Color &clr); + virtual void rectangle_fill(int x, int y, int w, int h, Color &clr); + virtual void flush(Drawable *n, bool border) = 0; + //virtual void clear(); /* 对于区域来说,清理可能较为复杂 */ + /*------ printer 打印 ------ + * 打印文字 + * + * 只实现了打印文字的基本方法 */ + void drawvfont(int x, int y, unsigned short z, Color &clr); + /*------ test 测试 ------ + * 绘制测试图案 */ + virtual void test(); /* 颜色测试 */ + +protected: + /*------ window ------ + * 窗口属性 */ + int w, h, x, y, rotate=0; + /*------ fonts lib ------ + * 文字库 */ + int font_w, font_h; + unsigned short *chss = (unsigned short *)zzhi; + unsigned char *vec = ttu; + int zn; + int vennum; + /* 绘制文字 */ + unsigned char *drawvect(int x, int y, unsigned char *vect, int width, int high, Color &clr); + /*------ printer ------*/ + Color clr = green; + //Color clr = white; +}; +} diff --git a/lci/include/lci/FrameBuf.h b/lci/include/lci/FrameBuf.h new file mode 100644 index 0000000..2534b73 --- /dev/null +++ b/lci/include/lci/FrameBuf.h @@ -0,0 +1,40 @@ +#pragma once +#include "Rectangle.h" +#include "Color.h" +#include "Drawable.h" +#include +#include +namespace qing{ +/* FIXME: 这个类的绘制点方法可能过于复杂 */ +class FrameBuf: public Drawable { /* 帧缓冲区类 */ +public: + FrameBuf(const char *path, int rotate, int fontsize); + FrameBuf(const FrameBuf&) = delete; /* 持有fd */ + ~FrameBuf(); + int get_bpp(); /* bits_per_pixel 像素比特 */ + virtual Color _get(int x, int y) override; + virtual void _p(int x, int y, Color &color) override; + virtual void flush(Drawable *d, bool border = false) override; + void clear(); /* FIXME: 也许把这个方法加到抽象父类中? */ + + class UnknowBPP: std::runtime_error { /* 未知标准的像素比特 */ + public: + UnknowBPP(): std::runtime_error("Unknow the number of Bits Per Pixel.") {} + }; + static const int _HEAD_LEN = 8; + +private: + int d = -1; + struct fb_var_screeninfo var_info; /* 可变参数 */ + struct fb_fix_screeninfo fix_info; /* 固定参数 */ + int x_over = 0; /* 横轴过量 */ + int line_jump = 0; /* 行跳 */ + char *buf = nullptr; /* 缓冲区指针 */ + + /* 根据像素比特的不同分情况讨论 */ + Color get16(__u32 x, __u32 y); + Color get32(__u32 x, __u32 y); + void p32(__u32 x, __u32 y, Color &color); + void p16(__u32 x, __u32 y, Color &color); +}; +} diff --git a/lci/include/lci/InputBox.h b/lci/include/lci/InputBox.h new file mode 100644 index 0000000..9d81b60 --- /dev/null +++ b/lci/include/lci/InputBox.h @@ -0,0 +1,9 @@ +#pragma once +#include "Area.h" +namespace qing { +class InputBox: public Area { /* 输入框 */ +public: + InputBox(Drawable *d, int w, int h, int x, int y, int rotate, int fontsize); + virtual void print(char *utf8, int line); +}; +} diff --git a/lci/include/lci/KeyboardEvent.h b/lci/include/lci/KeyboardEvent.h new file mode 100644 index 0000000..05f7488 --- /dev/null +++ b/lci/include/lci/KeyboardEvent.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include +#include +#include +//#define MAX 64 /* FIXME: 这个是不是没用了 */ +namespace qing { +class KeyboardEvent{ +public: + KeyboardEvent(); + ~KeyboardEvent(); + struct input_event get(); /* 获取键盘事件 */ + class NoEvent: std::runtime_error{ /* 键盘无事件异常 */ + public: + NoEvent(std::string s): std::runtime_error(s){} + }; +private: + std::map pool; + static bool is_event_with_number(const char *filename); + static void set_noblocking(int d); + int maxd(); + static void print(struct input_event ev); +}; +} diff --git a/lci/include/lci/PoolArea.h b/lci/include/lci/PoolArea.h new file mode 100644 index 0000000..faf6597 --- /dev/null +++ b/lci/include/lci/PoolArea.h @@ -0,0 +1,53 @@ +/* + * 控件池区域 + * + * 能够容纳别的控件,不需要重写flush()方法 + */ +#include +#include +#include "lci/Area.h" +#include "lci/Drawable.h" +namespace qing { + class PoolArea: public Area{ + public: + PoolArea(Drawable *d, int w, int h, int x, int y, int rotate, int fontsize) + :Area(d, w, h, x, y, rotate, fontsize) {}; + void add(const std::string& name, const std::shared_ptr& item) { + umap.insert({name, item}); + } + + /* 访问控件 */ + std::shared_ptr& operator[](const std::string& key) { + return umap.at(key); + } + + /* 访问控件 - const */ + const std::shared_ptr& operator[](const std::string& key) const { + return umap.at(key); + } + + /* 安全访问 - 不抛异常 */ + //std::shard_ptr get(const std::string& key) const {} + + /* 检查是否存在 */ + bool contains(const std::string& key) const { + return umap.find(key) != umap.end(); + } + + /* 获取控件数量 */ + size_t size() const { return umap.size(); } + + /* 迭代器支持 - 范围for循环 */ + std::unordered_map>::iterator begin() { return umap.begin(); } + std::unordered_map>::iterator end() { return umap.end(); } + + /* 迭代器支持 - const版本 */ + std::unordered_map>::const_iterator begin() const { return umap.begin(); } + std::unordered_map>::const_iterator end() const { return umap.end(); } + + /* FIXME: cbegin/cend 支持 */ + + private: + std::unordered_map> umap; + }; +} diff --git a/lci/include/lci/Rectangle.h b/lci/include/lci/Rectangle.h new file mode 100644 index 0000000..16158d4 --- /dev/null +++ b/lci/include/lci/Rectangle.h @@ -0,0 +1,14 @@ +#pragma once +namespace qing{ +class Rectangle{ /* 矩形类 */ +public: + int w=0; /* width */ + int h=0; /* height */ + int b=0; /* ? */ + Rectangle(int w=0, int h=0, int b=0) { + this->w=w; + this->h=h; + this->b=b; + } +}; +} diff --git a/lci/include/lci/Shape.h b/lci/include/lci/Shape.h new file mode 100644 index 0000000..0913236 --- /dev/null +++ b/lci/include/lci/Shape.h @@ -0,0 +1,43 @@ +#pragma once +#include "lci/Drawable.h" +#include "lci/Color.h" +namespace qing { + /* 【形状】 + * 抽象基类 */ + class Shape { + public: + Shape(int w, int h, int x, int y) + : w(w), h(h), x(x), y(y) {} + virtual void Draw(Drawable &d, Color clr) = 0; + int getw() { + return w; + } + void setw(int w) { + this->w = w; + } + + int geth() { + return h; + } + void seth(int h) { + this->h = h; + } + + int getx() { + return x; + } + void setx(int x) { + this->x = x; + } + + int gety() { + return y; + } + void sety(int y) { + this->y = y; + } + private: + int w, h; + int x, y; + }; +} diff --git a/lci/include/lci/ShapeArea.h b/lci/include/lci/ShapeArea.h new file mode 100644 index 0000000..72aaf12 --- /dev/null +++ b/lci/include/lci/ShapeArea.h @@ -0,0 +1,32 @@ +#pragma once +/* + * 形状区域 + */ +#include "lci/Area.h" +#include "lci/Shape.h" +#include "vector" +#include "memory" +namespace qing { +class ShapeArea: public Area { +public: + ShapeArea(Drawable *d, int w, int h, int x, int y, int rotate, int fontsize) + : Area(d, w, h, x, y, rotate, fontsize){} + size_t size() const { return list.size(); } + void add(const std::shared_ptr& item) { + list.push_back(item); + } + Shape& operator[](const size_t idx) { + return *(list[idx]); + } + const Shape& operator[](const size_t idx) const { + return *(list[idx]); + } + std::vector>::iterator begin() { return list.begin(); } + std::vector>::iterator end() { return list.end(); } + + std::vector>::const_iterator begin() const { return list.begin(); } + std::vector>::const_iterator end() const { return list.end(); } +private: + std::vector> list; +}; +} diff --git a/lci/include/lci/Term.h b/lci/include/lci/Term.h new file mode 100644 index 0000000..638fd06 --- /dev/null +++ b/lci/include/lci/Term.h @@ -0,0 +1,46 @@ +#pragma once +#include +#include +#include +#include +namespace qing { +class Term { +public: + /* 需要输入当前的控制台号(源头tty) */ + Term(int target_tty, int origin_tty) { + this->origin_tty = origin_tty; + chvt(target_tty); + HideCursor(target_tty); + } + ~Term(){ /* 切回源tty */ + chvt(origin_tty); + } +private: + int origin_tty; + static int open_tty(int num) { + char path[16] = {'\0'}; + snprintf(path, sizeof(path), "/dev/tty%d", num); + int d = open(path, O_WRONLY); + if (d == -1) + throw std::runtime_error(path); + else + return d; + } + static void HideCursor(int id) { + int d = open_tty(id); + const char *hide = "\033[?25l"; + if (write(d, hide, strlen(hide)) == -1){ + close(d); + throw std::runtime_error("term writting"); + } + close(d); + } + static void chvt(int id) { + char cmd[16] = {'\0'}; + snprintf(cmd, sizeof(cmd), "chvt %d", id); + int err = system(cmd); + if (err) + throw std::runtime_error("chvt"); + } +}; +} diff --git a/lci/include/lci/ThreadInterface.h b/lci/include/lci/ThreadInterface.h new file mode 100644 index 0000000..c488ff3 --- /dev/null +++ b/lci/include/lci/ThreadInterface.h @@ -0,0 +1,23 @@ +#pragma once +namespace qing { + + class ThreadInterface { + + public: + + //--------------------------------------------- + //程序睡眠阶段的操作函数。 + virtual void StopEvent() = 0; + //程序设置阶段的操作函数。 + virtual void WakeEvent() = 0; + //程序运行阶段的操作函数。 + virtual void LoopEvent() = 0; + //程序清理阶段的操作函数。 + virtual void ClearEvent() = 0; + + //可以将操作函数作为一种事件,可以从外界传入写好的事件函数, + //那么就需要将操作函数设定为静态函数 + + }; + +} diff --git a/lci/include/lci/ansi.h b/lci/include/lci/ansi.h new file mode 100644 index 0000000..d0c8758 --- /dev/null +++ b/lci/include/lci/ansi.h @@ -0,0 +1,15 @@ +#pragma once +#include +#include +namespace qing { +/* ANSI是WINDOWS操作系统默认的编码格式。 */ +class ansi{ +public: + static int size_gb18030(unsigned char *c, size_t maxLen); + static int size_gb2312(unsigned char first_byte); + class WrongLength: public std::runtime_error { /* 非法的长度 */ + public: + WrongLength(): std::runtime_error("") {} + }; +}; +} diff --git a/lci/include/lci/fsm.h b/lci/include/lci/fsm.h new file mode 100644 index 0000000..5067ccb --- /dev/null +++ b/lci/include/lci/fsm.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include +namespace qing{ +namespace lci{ + //用来存储状态的枚举类型 + enum Stat{ + SSHUT = -1, + SSTOP = 0, + SSTART = 1, + SRUNNING = 2 + };//Status + + class Fsm {//FiniteStateMachine有限状态机 + public: + //构造函数 + Fsm(); + //检查状态 + enum Stat chk(); + //改变状态 + void wake(); + void stop(); + void shut(); + void run(); + //protected: + //等待事件唤醒 + void suspend(); + private: + //锁类型,确保状态机线程安全 + std::mutex lock; + //条件变量,用来执行等待或者唤醒 + std::condition_variable cv; + //存放状态机的状态 + enum Stat stat; + };//StateMachine +}//lci +}//qing diff --git a/lci/include/lci/p_th.h b/lci/include/lci/p_th.h new file mode 100644 index 0000000..c145c57 --- /dev/null +++ b/lci/include/lci/p_th.h @@ -0,0 +1,160 @@ +#pragma once +#include "Area.h" +#include "CmdArea.h" +#include "CommonThread.h" +namespace qing { +namespace lci{ +/* PrintThread 打印线程 */ +class p_th: public CommonThread { +public: + /** + * 构造函数 传入要读取的控制台设备文件描述符,背景画布,以及命令行区域 + */ + p_th(std::string name, int masterfd, Drawable *back, CmdArea *font) + : CommonThread(name) { + this->masterfd = masterfd; + this->back = back; + this->font = font; + } + + /** + * 析构函数 关闭线程 + * + * 我在可控制线程中主要遇到的问题便是线程的自主终止, + * + * 在 Python 中似乎是只能实现可控制线程的手动退出的, + * + * 我在想是不是在cpp中也做成那样。 + * + * + * FIXME(20260108): 啥意思不懂 + */ + ~p_th(){ + + /* 使线程自主关闭 */ + if (this->chk() != lci::SSHUT){ + this->shut(); + } + + /* 等待线程退出 */ + this->WaitClose(); + + } + + /** + * 暂时删除复制构造函数,因为复制出一个与原来线程无关的空白线程似乎没有什么作用 + * + * 如果让两个变量引用同一个线程,会使得它们在结束的时候出现错误。 + */ + p_th(p_th&) = delete; + + + /** + * 线程睡眠阶段的操作函数,线程等待。 + * + * suspend() 方法似乎不太稳定,我还得再测试测试。 + */ + void StopEvent() override { + this->suspend(); + } + + /** + * 线程苏醒之后执行的操作,线程启动。 + * + * 我不知道为什么要等待1秒。 + */ + void WakeEvent() { + + /* 将文件描述符集合清零 */ + FD_ZERO(&read_fds); + + /* 清空缓存字符串 */ + output = ""; + + /* 设置完毕,线程进入运行态 */ + this->run(); + + } + + /** + * 线程运行阶段的循环体,线程运行。 + * + * 使用 SELECT 进行缓冲区的探测。 + */ + void LoopEvent() { + + /* 对可读集合进行清零 */ + //FD_ZERO(&read_fds); + + /* 设置可读集合 */ + //FD_SET(masterfd, &read_fds); + + /** + * 仅在集合中不存在控制台描述符时,才往其中添加该描述符 + * + * 在这个集合中,应该只会存在这一个文件描述符吧 + */ + if (!FD_ISSET(masterfd, &read_fds)) + FD_SET(masterfd, &read_fds); + + /* 设置超时时间 */ + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + + int ret = select(masterfd + 1, &read_fds, NULL, NULL, &timeout); + if (ret == -1) { + //throw std::runtime_error("select"); + //this->stop(); + return; /* qing(20260108): 为什么不停止 */ + } else if (ret == 0) { /* No data to read 无值可读 */ + if (output == "") return; /* 在空闲时进行打印*/ + font->print((char*)output.c_str(), 0); /* 按次为单位进行刷新应该可以提高效率 20260108(qing): ?*/ + back->flush(font, false); + output = ""; + } else { + if (FD_ISSET(masterfd, &read_fds)) { /* 有值可读 */ + nread = read(masterfd, buffer, sizeof(buffer)); + if (nread > 0) { + buffer[nread] = '\0'; + output += buffer; + } + } + } + + } + + /** + * 线程执行过后的清理函数,清理资源。 + * + * 什么也不做。我们在唤醒时并未申请资源。 + */ + void ClearEvent() { + ; + } + + +private: + + int masterfd; /* 对象中存储的要读取的控制台设备文件描述符。 */ + + Drawable *back; /* 对象中存储的背景画布指针 */ + + CmdArea *font; /* 对象中存储的命令行区域指针 */ + + std::string output; /* 从终端设备中读取的进程输出 */ + + //-------------------------------------------- + /* 下面的变量是为了提高速度,避免重复申请 */ + + fd_set read_fds; /* 文件描述符集合,用于存储 SELECT 返回的可读区域 */ + + struct timeval timeout; /* 时间结构体 用于传入 SELECT 函数的超时时间 */ + + ssize_t nread; /* 这一次从控制台中所读取大小 */ + + char buffer[1024]; /* 存储从控制台中读取字符的缓冲区,一次最多读这么多 */ + +}; + +} +} diff --git a/lci/include/lci/utf8.h b/lci/include/lci/utf8.h new file mode 100644 index 0000000..dae86bf --- /dev/null +++ b/lci/include/lci/utf8.h @@ -0,0 +1,8 @@ +#pragma once +namespace qing { +class utf8{ /* */ +public: + static int size(const unsigned char c); + static char *to_ansi(char *s); +}; +} diff --git a/lci/include/lci/图层区域.hpp b/lci/include/lci/图层区域.hpp new file mode 100644 index 0000000..0fdc3ce --- /dev/null +++ b/lci/include/lci/图层区域.hpp @@ -0,0 +1,114 @@ +/* 图层区域是能够绘制图片的区域类型 */ +#define cimg_display 0 +#define cimg_use_jpeg +#define cimg_use_png +#include +#include "cn/中文化.hpp" +#include "lci/Area.h" +使用 命名空间 cimg_library; +命名空间 qing { +类 图层区域: 公开的 Area { /* 图层区域 */ +公开的: + 图层区域(Drawable *d, int w, int h, int x, int y, int rotate, int fontsize, CImg& img) + : Area(d, w, h, x, y, rotate, fontsize) { + /* 储存图片,需要调用图片的构造函数 */ + this->img = img; + } + 空类型 涂写图像() { + 单精度小数 区域长宽比 = (float)w / h; + 单精度小数 图片长宽比 = (float)img.width() / img.height(); + /* 长宽比越大,代表图片越横向细长 + * 长宽比越小,代表图片越竖向细长 + * 长宽比为1时,图片为正方形 + * + * 图片长宽比较大时,取区域长 + * 图片长宽比较小时,取区域高 */ + 逻辑型 长为标准 = 图片长宽比 > 区域长宽比; + 如果(长为标准) { + auto fixed = scaleByWidth(this->img, this->w); + CImg gray = 转灰度图(fixed); + auto start = (int)(this->h - gray.height()) / 2; + for (int y = 0; y < gray.height(); ++y) { + for (int x = 0; x < gray.width(); ++x){ + auto xx = x; + auto yy = y + start; + auto clr1 = 颜色转换(gray(x, y), this->clr); + this->point(xx, yy, clr1); + } + } + } + 否则{ /* 以宽为标准 */ + auto fixed = scaleByHeight(this->img, this->h); + auto gray = 转灰度图(fixed); + auto start = (int)(this->w - gray.width()) / 2; + for (int y = 0; y < gray.height(); ++y) { + for (int x = 0; x < gray.width(); ++x){ + auto xx = x + start; + auto yy = y; + auto clr1 = 颜色转换(gray(x, y), this->clr); + this->point(xx, yy, clr1); + } + } + } + } +私有的: + CImg img; + /* 以长为标准缩放 */ + static CImg scaleByWidth(const CImg& src, int newWidth) { + /* 计算缩放比例 */ + float ratio = (float)newWidth / src.width(); + int newHeight = (int)(src.height() * ratio); + + /* 使用_resize方法进行缩放 */ + return src.get_resize(newWidth, newHeight, -100, -100, 5); + } + /* 以高为标准缩放 */ + static CImg scaleByHeight(const CImg& src, int newHeight) { + /* 计算缩放比例 */ + float ratio = (float)newHeight / src.height(); + int newWidth = (int)(src.width() * ratio); + + /* 计算_resize方法进行缩放 */ + return src.get_resize(newWidth, newHeight, -100, -100, 5); + } + /* 将灰度颜色转换为我们目前画笔的颜色 */ + 静态的 Color 颜色转换(无符号 字符 灰度, Color clr) { + 单精度小数 红 = (单精度小数)clr.r / 255; + 单精度小数 绿 = (单精度小数)clr.g / 255; + 单精度小数 蓝 = (单精度小数)clr.b / 255; + 自动的 结果 = Color(红* 灰度*255, 绿*灰度*255, 蓝*灰度*255); + 返回 结果; + } + + /* 将CImg对象转为灰度图 */ + 静态的 CImg 转灰度图(CImg& img) { + + if (img.spectrum() == 3) { + return img.get_normalize(0, 255).get_RGBtoXYZ().get_channel(1); + } + else if (img.spectrum() ==4) { + + auto rgb_img = t_4_to_3(img); + return rgb_img.get_RGBtoXYZ().get_channel(1); + } + else { + 抛出异常 std::runtime_error("没有对应通道数的算法"); + } + } + + /* 将4通道图片转为3通道 */ + 静态的 CImg t_4_to_3(CImg& img) { + // 创建RGB图像(3通道) + CImg rgb_img(img.width(), img.height(), 1, 3); + + cimg_forXY(rgb_img, x, y) { + rgb_img(x, y, 0, 0) = img(x, y, 0, 0); // R + rgb_img(x, y, 0, 1) = img(x, y, 0, 1); // G + rgb_img(x, y, 0, 2) = img(x, y, 0, 2); // B + // 忽略alpha通道 img(x, y, 0, 3) + } + + return rgb_img; + } +}; +} diff --git a/lci/include/lci/字体绘制器.h b/lci/include/lci/字体绘制器.h new file mode 100644 index 0000000..570e05b --- /dev/null +++ b/lci/include/lci/字体绘制器.h @@ -0,0 +1,121 @@ +/* + * 用于在可绘制对象上绘制中文文字 + * + * 绘制时将对象作为参数传入 + */ + +#include "cn/中文化.hpp" +#include "lci/Drawable.h" +/* 用于文字的绘制,只要不动就线程安全 */ +extern unsigned char ttu[]; +extern int ttunumber; +extern unsigned char zzhi[]; +extern int zzhinumber; + +命名空间 qing { +类 字体绘制器 { +私有的: + /*------ fonts lib ------ + * 文字库 */ + int font_w, font_h; + unsigned short *chss = (unsigned short *)zzhi; + unsigned char *vec = ttu; + int zn = zzhinumber; + int vennum = ttunumber; + + unsigned char *drawvect(Drawable* d, int x, int y, unsigned char *vect, int width, int high, Color &clr) + // x, y是左上角坐标,vect指向矢量图数据,width和high分别代表要绘制的图的宽和高(好像宽需要=高) + { + if (!vect) return nullptr; + int i = 0, j = 1; // 指向第一对数字 + unsigned char ix, iy; // 从数组取出的第一对坐标放在这 + double x1, y1;//, x2, y2; // 绘制直线的实数的坐标 + if (high == 0) high = width; // 调节高宽 + int ii1, jj1, ii2, jj2; // 最后算出的绘制直线的坐标 + int isend = 0; //是否到达曲线尾 + int isallend = 0; // 是否结束整个图像 + do { + ix = vect[i]; + iy = vect[j]; + isend = ix & 1; // 奇数代表曲线尾 + isallend = iy & 1; // 奇数代表整个图像结束 + if (isallend) { + i += 2; + break; // 整个图像结束返回 + } + if (isend) { // 如果这里曲线结束什么也不画进到下一条曲线 + i += 2; + j += 2; + continue; + } + ix /= 2; + iy /= 2; + x1 = ix; + y1 = iy; + x1 = width * x1 / 128.0; + y1 = high * y1 / 128.0; + ii1 = (int)(x1 + x); + jj1 = (int)(y1 + y); + int k; + for (k = 0; k < 100000; k++) { + //x2 = x1; + //y2 = y1; + ii2 = ii1; + jj2 = jj1; + i += 2; + j += 2; + ix = vect[i]; + iy = vect[j]; + isend = ix & 1; //奇数代表曲线尾 + isallend = iy & 1; //奇数代表整个图像结束 + ix /= 2; + iy /= 2; + x1 = ix; + y1 = iy; + x1 = width * x1 / 128.0; + y1 = high * y1 / 128.0; + ii1 = (int)(x1 + x); + jj1 = (int)(y1 + y); + d->line(ii1, jj1, ii2, jj2, clr); + if (isend || isallend) + break; + } + i += 2; //指向下一条曲线 + j += 2; + } while (!isallend); + return vect + i; + } + +公开的: + 字体绘制器(const int font_w, const int font_h) + : font_w(font_w), font_h(font_h) {} + + /* 绘制文字 */ + void drawvfont(Drawable* d, int x, int y, unsigned short z, Color &clr) { + int i, j, k, ii; + j = -1; + for (i = 0; i < zn; i++) { + if (chss[i] == z) { + j = i; + break; + } + } + if (j < 0) return; + k = 0; + for (i = 0; i < vennum; i++) { + if (k == j) + break; + for (ii =i; ii +#include +#include +#include +#include + +#include + +#include "net/HttpClient.hpp" + +namespace pmc::llm { + +class LLMClient { +public: + LLMClient(const std::string& api_key) : api_key_(api_key) {} + + // 流式请求(使用同步版本避免线程死锁) + void stream_request(const std::vector>& messages, + std::function callback) { + // 使用智能指针确保HttpClient在回调期间保持存活 + auto http_client = std::make_shared(); + + // 设置请求头 + http_client->set_header("Authorization: Bearer " + api_key_); + http_client->set_header("Content-Type: application/json"); + http_client->set_header("Accept: text/event-stream"); + + // 构建请求JSON + boost::json::object request; + request["model"] = "deepseek-chat"; + request["stream"] = true; + + // 构建消息数组,添加系统消息要求返回Markdown格式 + boost::json::array messages_array; + + // 添加系统消息,要求使用Markdown格式回复 + boost::json::object system_message; + system_message["role"] = "system"; + system_message["content"] = "请使用Markdown格式回复。使用**粗体**表示重要概念,*斜体*表示强调,`代码`表示代码片段,使用列表、标题等Markdown元素来组织内容。"; + messages_array.push_back(system_message); + + // 添加用户消息 + for (const auto& msg : messages) { + boost::json::object message_obj; + message_obj["role"] = msg.first; + message_obj["content"] = msg.second; + messages_array.push_back(message_obj); + } + request["messages"] = messages_array; + + // 转换为字符串 + std::string request_body = boost::json::serialize(request); + + // 创建包装回调,解析JSON并提取文本内容 + auto wrapped_callback = [callback](const std::string& json_str) { + try { + // 解析JSON + boost::json::value json_value = boost::json::parse(json_str); + + // 检查是否是有效的响应 + if (json_value.is_object()) { + const auto& obj = json_value.as_object(); + + // 检查是否有choices数组 + if (obj.contains("choices") && obj.at("choices").is_array()) { + const auto& choices = obj.at("choices").as_array(); + if (!choices.empty() && choices[0].is_object()) { + const auto& choice = choices[0].as_object(); + + // 检查是否有delta对象 + if (choice.contains("delta") && choice.at("delta").is_object()) { + const auto& delta = choice.at("delta").as_object(); + + // 检查是否有content字段 + if (delta.contains("content") && delta.at("content").is_string()) { + const std::string& content = delta.at("content").as_string().c_str(); + callback(content); + return; + } + } + } + } + } + + // 如果JSON解析失败或没有有效内容,发送原始字符串(用于调试) + callback("[" + json_str + "]"); + } catch (const std::exception& e) { + // JSON解析失败,发送原始字符串 + callback("[" + json_str + "]"); + } + }; + + // 发送POST请求 - 使用post_stream_sync方法 + http_client->post_stream_sync("https://api.deepseek.com/v1/chat/completions", request_body, wrapped_callback); + } + +private: + std::string api_key_; +}; + +} // namespace pmc::llm + +#endif // PMC_LLM_CLIENT_HPP \ No newline at end of file diff --git a/lci/include/llm/LLMWebSocketServer.hpp b/lci/include/llm/LLMWebSocketServer.hpp new file mode 100644 index 0000000..3a297b6 --- /dev/null +++ b/lci/include/llm/LLMWebSocketServer.hpp @@ -0,0 +1,133 @@ +#ifndef PMC_LLM_WEBSOCKET_SERVER_HPP +#define PMC_LLM_WEBSOCKET_SERVER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "LLMClient.hpp" +#include "net/WebSocketServer.hpp" + +namespace pmc::llm { + +class LLMWebSocketServer { +public: + LLMWebSocketServer(const std::string& api_key, unsigned short port = 8080) + : api_key_(api_key) + , port_(port) + , running_(false) { + + // 创建WebSocket服务器 + ws_server_ = std::make_unique(port); + } + + ~LLMWebSocketServer() { + stop(); + } + + void start() { + if (running_) { + return; + } + + std::cout << "启动LLM WebSocket服务器,端口: " << port_ << std::endl; + std::cout << "API密钥: " << (api_key_.empty() ? "未设置" : "已设置") << std::endl; + + // 设置WebSocket回调 + ws_server_->onConnect([this](const std::string& client_id, const std::string& remote_address) { + handle_connect(client_id, remote_address); + }); + + ws_server_->onMessage("/", [this](const std::string& client_id, + const std::string& message, + std::function send_callback) { + // 这里我们使用异步发送,所以忽略send_callback参数 + handle_message(client_id, message); + }); + + ws_server_->onDisconnect([this](const std::string& client_id) { + handle_disconnect(client_id); + }); + + // 启动WebSocket服务器 + ws_server_->start(); + + running_ = true; + + std::cout << "服务器已启动,等待客户端连接..." << std::endl; + std::cout << "按Ctrl+C停止服务器" << std::endl; + } + + void stop() { + if (!running_) { + return; + } + + std::cout << "正在停止服务器..." << std::endl; + ws_server_->stop(); + running_ = false; + } + + bool is_running() const { + return running_; + } + +private: + // 处理连接 + void handle_connect(const std::string& client_id, const std::string& remote_address) { + std::cout << "客户端连接: " << client_id << " (" << remote_address << ")" << std::endl; + + // 使用异步线程发送欢迎消息,确保客户端已准备好 + std::thread([this, client_id]() { + // 等待一小段时间,确保客户端连接完全建立 + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // 发送欢迎消息 + ws_server_->sendToClient(client_id, "欢迎连接到LLM WebSocket服务器!"); + ws_server_->sendToClient(client_id, "请发送您的消息,我将为您提供AI助手服务。"); + }).detach(); + } + + // 处理断开连接 + void handle_disconnect(const std::string& client_id) { + std::cout << "客户端断开: " << client_id << std::endl; + } + + // 处理消息 + void handle_message(const std::string& client_id, const std::string& message) { + std::cout << "收到来自客户端 " << client_id << " 的消息: " << message << std::endl; + + // 创建LLM客户端 + LLMClient llm_client(api_key_); + + // 构建消息历史 + std::vector> messages = { + {"user", message} + }; + + // 发送流式请求 + llm_client.stream_request(messages, [this, client_id](const std::string& chunk) { + // 将每个数据块发送给客户端 + ws_server_->sendToClient(client_id, chunk); + }); + + // 发送处理完成标记 + ws_server_->sendToClient(client_id, "[处理完成]"); + } + +private: + std::string api_key_; + unsigned short port_; + bool running_; + std::unique_ptr ws_server_; +}; + +} // namespace pmc::llm + +#endif // PMC_LLM_WEBSOCKET_SERVER_HPP \ No newline at end of file diff --git a/lci/include/logs/Logger.hpp b/lci/include/logs/Logger.hpp new file mode 100644 index 0000000..7d3baa0 --- /dev/null +++ b/lci/include/logs/Logger.hpp @@ -0,0 +1,107 @@ +/* 日志 */ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +enum class LogLevel { + DEBUG, + INFO, + WARNING, + ERROR, + CRITICAL +}; + +namespace qing { + /* + * 这是由Deepseek创作的,用于记录日志的类模块 + * 简化版本,只输出到控制台 + * + * 优化意见:改为存储日志文件 + */ + class Logger { + public: + //获取日志实例(单例模式) + static Logger& getInstance() { + static Logger instance; + return instance; + } + + //初始化日志系统 + void init(LogLevel minLogLevel = LogLevel::INFO, + bool consoleOutput = true) { + std::lock_guard lock(mutex_); + + if (initialized_) { + return; + } + + minLogLevel_ = minLogLevel; + consoleOutput_ = consoleOutput; + initialized_ = true; + } + + // 设置最低日志级别 + void setMinLogLevel(LogLevel level) { + std::lock_guard lock(mutex_); + minLogLevel_ = level; + } + + // 日志输出方法 + void log(LogLevel level, const std::string& message) { + if (level < minLogLevel_ || !consoleOutput_) { + return; + } + + auto now = std::chrono::system_clock::now(); + auto in_time_t = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast( + now.time_since_epoch()) % 1000; + + std::tm tm; + localtime_r(&in_time_t, &tm); + + std::stringstream ss; + ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") + << "." << std::setfill('0') << std::setw(3) << ms.count() + << " [" << logLevelToString(level) << "] " + << message; + + std::lock_guard lock(mutex_); + std::cout << ss.str() << std::endl; + } + + Logger(const Logger&) = delete; + Logger& operator=(const Logger&) = delete; + + private: + Logger() = default; + ~Logger() = default; + + std::string logLevelToString(LogLevel level) { + switch (level) { + case LogLevel::DEBUG: return "DEBUG"; + case LogLevel::INFO: return "INFO"; + case LogLevel::WARNING: return "WARNING"; + case LogLevel::ERROR: return "ERROR"; + case LogLevel::CRITICAL: return "CRITICAL"; + default: return "UNKNOWN"; + } + } + + std::mutex mutex_; + LogLevel minLogLevel_ = LogLevel::INFO; + bool consoleOutput_ = true; + bool initialized_ = false; + }; +} + +#define LOG_DEBUG(message) qing::Logger::getInstance().log(LogLevel::DEBUG, message) +#define LOG_INFO(message) qing::Logger::getInstance().log(LogLevel::INFO, message) +#define LOG_WARNING(message) qing::Logger::getInstance().log(LogLevel::WARNING, message) +#define LOG_ERROR(message) qing::Logger::getInstance().log(LogLevel::ERROR, message) +#define LOG_CRITICAL(message) qing::Logger::getInstance().log(LogLevel::CRITICAL, message) diff --git a/lci/include/net/Http.hpp b/lci/include/net/Http.hpp new file mode 100644 index 0000000..a06c613 --- /dev/null +++ b/lci/include/net/Http.hpp @@ -0,0 +1,82 @@ +#pragma once +#include // libcpp-httplib-dev +#include // +#include +#include // +#include +namespace fs = std::filesystem; +/* 这里的类型是HTTP服务器要设置的回调函数的类型 */ +using Handler = std::function; +namespace qing { +/* NOTE: 不要删除该类,这个抽象成能够方便重构 */ +class Http { /* 超文本传输协议(HTTP)服务器类 */ +public: + /* 初始化各个变量 */ + Http(std::string addr, int port): addr(addr), port(port) {} + + /* 运行服务器,失败抛出异常 */ + void run() { + //printAddr(); /* 在日志里打印更好 */ + if (!svr.listen(addr.c_str(), port)) + throw StartServerFailed(""); + } + + /* 终止服务器 */ + void stop() { svr.stop(); } + + + /* + * 设置路由和对应的处理函数 + * + * FIXME: 使用一个方法实现两个功能 + */ + void get (std::string path, Handler handler) { svr.Get(path, handler); } + void post(std::string path, Handler handler) { svr.Post(path, handler); } + + /* + * 打印地址 + * + * FIXME: 把这个函数的具体功能放到类的外部 + */ + std::string printAddr() { return std::string("pmcd now listenning on this address: http://") + addr + ":" + std::to_string(port); } + + /* 获取当前执行文件目录 */ + //static std::string getCurrentDirectory() { + // fs::path currentPath = fs::absolute(__FILE__); + // return currentPath.parent_path().string(); + //} + + // 读取文本文件的所有内容 + //static std::string readFile(const std::string& filePath) { + // std::ifstream file(filePath); // 创建一个输入文件流对象,用于读取文件 + // if (!file) { + // std::cerr << "无法打开文件:" << filePath << std::endl; + // return ""; + // } + // std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); /* 使用迭代器读取文件内容到字符串 */ + // file.close(); + // return content; + //} + + class Http_Error: public std::exception { /* HTTP 异常类 */ + private: + std::string message; + public: + explicit Http_Error(const std::string& msg): message(msg) {} + const char* what() const noexcept override { + return message.c_str(); + } + }; + + class StartServerFailed: public Http_Error { /* 开始服务失败 */ + public: + StartServerFailed(const std::string& msg): Http_Error(msg) {} + }; + + +private: + httplib::Server svr; /* 创建HTTP服务器对象(如果需要HTTPS,则使用SSLServer */ + std::string addr; /* 服务地址 */ + int port; /* 端口 */ +}; +} diff --git a/lci/include/net/HttpClient.hpp b/lci/include/net/HttpClient.hpp new file mode 100644 index 0000000..1c5b706 --- /dev/null +++ b/lci/include/net/HttpClient.hpp @@ -0,0 +1,151 @@ +#ifndef PMC_HTTP_CLIENT_HPP +#define PMC_HTTP_CLIENT_HPP + +#include +#include +#include +#include + +namespace pmc::net { + +class HttpClient { +public: + HttpClient() { + std::cout << "HttpClient构造函数: 开始初始化" << std::endl; + curl_ = curl_easy_init(); + if (!curl_) { + throw std::runtime_error("Failed to initialize CURL"); + } + std::cout << "HttpClient构造函数: 初始化完成" << std::endl; + } + + ~HttpClient() { + std::cout << "HttpClient析构函数: 开始清理" << std::endl; + if (curl_) { + curl_easy_cleanup(curl_); + } + if (headers_) { + curl_slist_free_all(headers_); + } + std::cout << "HttpClient析构函数: 清理完成" << std::endl; + } + + void set_header(const std::string& header) { + std::cout << "set_header: 添加header: " << header << std::endl; + headers_ = curl_slist_append(headers_, header.c_str()); + } + + // 同步流式请求 + void post_stream_sync(const std::string& url, const std::string& data, std::function callback) { + std::cout << "post_stream_sync: 开始发送流式请求到 " << url << std::endl; + + if (!curl_) { + throw std::runtime_error("CURL not initialized"); + } + + // 重置CURL句柄 + curl_easy_reset(curl_); + + // 设置URL + curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()); + + // 设置POST请求 + curl_easy_setopt(curl_, CURLOPT_POST, 1L); + curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, data.c_str()); + curl_easy_setopt(curl_, CURLOPT_POSTFIELDSIZE, data.size()); + + // 设置请求头 + curl_easy_setopt(curl_, CURLOPT_HTTPHEADER, headers_); + + // 设置流式回调函数 + std::string buffer; + auto data_pair = std::make_pair(&buffer, &callback); + std::cout << "post_stream_sync: 数据对创建完成" << std::endl; + + curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, stream_write_callback); + curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &data_pair); + + // 设置超时和连接选项 + curl_easy_setopt(curl_, CURLOPT_TIMEOUT, 30L); + curl_easy_setopt(curl_, CURLOPT_CONNECTTIMEOUT, 10L); + + // 执行请求 + std::cout << "post_stream_sync: 执行请求" << std::endl; + CURLcode res = curl_easy_perform(curl_); + std::cout << "post_stream_sync: 数据对清理完成" << std::endl; + + if (res != CURLE_OK) { + std::cout << "post_stream_sync: CURL错误: " << curl_easy_strerror(res) << std::endl; + throw std::runtime_error(std::string("CURL error: ") + curl_easy_strerror(res)); + } + + std::cout << "post_stream_sync: 请求成功" << std::endl; + } + +private: + CURL* curl_ = nullptr; + struct curl_slist* headers_ = nullptr; + + static size_t stream_write_callback(char* ptr, size_t size, size_t nmemb, void* userdata) { + // userdata指向一个std::pair*> + auto* data_pair = static_cast*>*>(userdata); + if (!data_pair || !data_pair->first || !data_pair->second) { + std::cout << "stream_write_callback: 无效的用户数据" << std::endl; + return 0; + } + + std::string& buffer = *(data_pair->first); + std::function& callback = *(data_pair->second); + size_t total_size = size * nmemb; + + std::cout << "stream_write_callback: 收到 " << total_size << " 字节数据" << std::endl; + + // 将数据追加到缓冲区 + buffer.append(ptr, total_size); + + // 打印原始数据(用于调试) + std::string raw_data(ptr, total_size); + std::cout << "stream_write_callback: 原始数据: " << raw_data << std::endl; + + // 处理流式数据(按行处理Server-Sent Events格式) + size_t pos = 0; + size_t newline_pos; + + while ((newline_pos = buffer.find('\n', pos)) != std::string::npos) { + std::string line = buffer.substr(pos, newline_pos - pos); + pos = newline_pos + 1; + + std::cout << "stream_write_callback: 处理行: " << line << std::endl; + + // 处理SSE格式的数据(以"data: "开头) + if (line.rfind("data: ", 0) == 0) { + std::string json_str = line.substr(6); + + if (json_str == "[DONE]") { + std::cout << "stream_write_callback: 收到 [DONE]" << std::endl; + callback("[[流式传输完成]]"); + continue; + } + + // 调用回调函数处理JSON数据 + std::cout << "stream_write_callback: 调用回调,数据长度: " << json_str.length() << std::endl; + callback(json_str); + } else if (!line.empty()) { + // 如果不是SSE格式,直接传递给回调(可能是错误消息) + std::cout << "stream_write_callback: 非SSE数据,直接传递: " << line << std::endl; + callback(line); + } + } + + // 移除已处理的数据 + if (pos > 0) { + buffer.erase(0, pos); + } + + return total_size; + } +}; + +} // namespace pmc::net + +#endif // PMC_HTTP_CLIENT_HPP \ No newline at end of file diff --git a/lci/include/net/HttpServer.hpp b/lci/include/net/HttpServer.hpp new file mode 100644 index 0000000..8c2a10f --- /dev/null +++ b/lci/include/net/HttpServer.hpp @@ -0,0 +1,193 @@ +#ifndef HTTPSERVER_HPP +#define HTTPSERVER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast = boost::beast; +namespace http = beast::http; +namespace asio = boost::asio; +using tcp = boost::asio::ip::tcp; + +namespace pmc { +namespace net { + +/** + * @brief HTTP请求处理器类型定义 + * + * 处理HTTP请求并返回响应 + */ +using HttpRequestHandler = std::function( + const http::request&, + const std::unordered_map&)>; + +/** + * @brief 中间件处理器类型定义 + * + * 用于处理请求链的中间件 + */ +using MiddlewareHandler = std::function&, + http::response&, + const std::unordered_map&)>; + +/** + * @brief HTTP服务器类(合并增强版) + * + * 基于boost::asio和boost::beast的异步HTTP服务器 + * 结合了原始版本的易用性和修复版本的功能完整性 + */ +class HttpServer { +public: + /** + * @brief 构造函数(监听所有接口) + * @param port 监听端口 + * @param threads 工作线程数 + */ + explicit HttpServer(unsigned short port, unsigned int threads = 1); + + /** + * @brief 构造函数(指定监听地址) + * @param address 监听IP地址(如 "0.0.0.0" 或 "127.0.0.1") + * @param port 监听端口 + * @param threads 工作线程数 + */ + explicit HttpServer(const std::string& address, unsigned short port, unsigned int threads = 1); + + /** + * @brief 析构函数 + */ + ~HttpServer(); + + /** + * @brief 启动服务器 + */ + void start(); + + /** + * @brief 停止服务器 + */ + void stop(); + + /** + * @brief 注册GET请求处理器 + * @param path 请求路径 + * @param handler 请求处理器 + */ + void get(const std::string& path, HttpRequestHandler handler); + + /** + * @brief 注册POST请求处理器 + * @param path 请求路径 + * @param handler 请求处理器 + */ + void post(const std::string& path, HttpRequestHandler handler); + + /** + * @brief 注册PUT请求处理器 + * @param path 请求路径 + * @param handler 请求处理器 + */ + void put(const std::string& path, HttpRequestHandler handler); + + /** + * @brief 注册DELETE请求处理器 + * @param path 请求路径 + * @param handler 请求处理器 + */ + void del(const std::string& path, HttpRequestHandler handler); + + /** + * @brief 注册中间件 + * @param middleware 中间件处理器 + */ + void use(MiddlewareHandler middleware); + + /** + * @brief 设置静态文件目录 + * @param path 静态文件目录路径 + */ + void setStaticDirectory(const std::string& path); + + /** + * @brief 获取服务器状态 + * @return 服务器是否正在运行 + */ + bool isRunning() const; + + /** + * @brief 获取服务器端口 + * @return 服务器监听端口 + */ + unsigned short getPort() const; + + /** + * @brief 获取服务器监听地址 + * @return 服务器监听地址 + */ + std::string getAddress() const; + + /** + * @brief 运行服务器(阻塞调用)- 从原始版本继承 + */ + void run(); + + /** + * @brief 显示服务器状态信息 - 从原始版本继承 + */ + void showStatus() const; + +private: + // 内部类声明 + class Session; + class Listener; + + // 服务器配置 + std::string address_; + unsigned short port_; + unsigned int threads_; + std::atomic running_{false}; + + // Boost.Asio上下文 + std::unique_ptr ioc_; + + // 网络组件 + std::shared_ptr listener_; + std::vector worker_threads_; + + // 路由表 + std::unordered_map get_handlers_; + std::unordered_map post_handlers_; + std::unordered_map put_handlers_; + std::unordered_map delete_handlers_; + + // 中间件链 + std::vector middlewares_; + + // 静态文件目录 + std::string static_directory_; + + // 内部方法 + std::unordered_map parseQueryParams(const std::string& query); + + // 请求处理 + http::response handleRequest(const http::request& req); +}; + +} // namespace net +} // namespace pmc + +#endif // HTTPSERVER_HPP \ No newline at end of file diff --git a/lci/include/net/WebSocketClient.hpp b/lci/include/net/WebSocketClient.hpp new file mode 100644 index 0000000..520711b --- /dev/null +++ b/lci/include/net/WebSocketClient.hpp @@ -0,0 +1,63 @@ +#ifndef PMC_NET_WEBSOCKET_CLIENT_HPP +#define PMC_NET_WEBSOCKET_CLIENT_HPP + +#include "WebSocketClientBase.hpp" + +namespace pmc { +namespace net { + +/** + * @brief 基于 Boost.Beast 的异步 WebSocket 客户端(非 SSL 版本) + */ +class WebSocketClient : public WebSocketClientBase { +public: + /** + * @brief 构造函数 + * @param host 服务器主机名或 IP 地址 + * @param port 服务器端口号 + * @param path WebSocket 路径(默认 "/") + */ + WebSocketClient(const std::string& host, const std::string& port, const std::string& path = "/"); + + /** + * @brief 析构函数 + */ + ~WebSocketClient(); + + // 实现 WebSocketClientBase 接口 + void setMessageCallback(MessageCallback callback) override; + void setErrorCallback(ErrorCallback callback) override; + void setConnectCallback(ConnectCallback callback) override; + void setCloseCallback(CloseCallback callback) override; + + bool connect(int timeout_ms = 5000) override; + void disconnect() override; + bool isConnected() const override; + + bool send(const std::string& message) override; + bool sendBinary(const void* data, size_t size) override; + + void setAutoReconnect(bool enable, int interval_ms = 3000) override; + void setHeartbeatInterval(int interval_ms = 30000) override; + + std::string getHost() const override; + std::string getPort() const override; + std::string getPath() const override; + + // SSL/TLS 相关(非 SSL 版本返回默认值) + bool isSecure() const override { return false; } + void setVerifyCertificate(bool verify) override { /* 忽略 */ } + void setCertificateFile(const std::string& cert_file) override { /* 忽略 */ } + void setPrivateKeyFile(const std::string& key_file) override { /* 忽略 */ } + void setCertificateAuthorityFile(const std::string& ca_file) override { /* 忽略 */ } + +private: + // 前向声明实现类 + class Impl; + std::unique_ptr impl_; +}; + +} // namespace net +} // namespace pmc + +#endif // PMC_NET_WEBSOCKET_CLIENT_HPP \ No newline at end of file diff --git a/lci/include/net/WebSocketClientBase.hpp b/lci/include/net/WebSocketClientBase.hpp new file mode 100644 index 0000000..b885893 --- /dev/null +++ b/lci/include/net/WebSocketClientBase.hpp @@ -0,0 +1,61 @@ +#ifndef PMC_NET_WEBSOCKET_CLIENT_BASE_HPP +#define PMC_NET_WEBSOCKET_CLIENT_BASE_HPP + +#include +#include +#include + +namespace pmc { +namespace net { + +/** + * @brief WebSocket 客户端基类 + * + * 定义所有 WebSocket 客户端的公共接口 + */ +class WebSocketClientBase { +public: + // 回调函数类型 + using MessageCallback = std::function; + using ErrorCallback = std::function; + using ConnectCallback = std::function; + using CloseCallback = std::function; + + virtual ~WebSocketClientBase() = default; + + // 回调函数设置 + virtual void setMessageCallback(MessageCallback callback) = 0; + virtual void setErrorCallback(ErrorCallback callback) = 0; + virtual void setConnectCallback(ConnectCallback callback) = 0; + virtual void setCloseCallback(CloseCallback callback) = 0; + + // 连接管理 + virtual bool connect(int timeout_ms = 5000) = 0; + virtual void disconnect() = 0; + virtual bool isConnected() const = 0; + + // 消息发送 + virtual bool send(const std::string& message) = 0; + virtual bool sendBinary(const void* data, size_t size) = 0; + + // 配置选项 + virtual void setAutoReconnect(bool enable, int interval_ms = 3000) = 0; + virtual void setHeartbeatInterval(int interval_ms = 30000) = 0; + + // 信息获取 + virtual std::string getHost() const = 0; + virtual std::string getPort() const = 0; + virtual std::string getPath() const = 0; + + // SSL/TLS 相关 + virtual bool isSecure() const = 0; + virtual void setVerifyCertificate(bool verify) = 0; + virtual void setCertificateFile(const std::string& cert_file) = 0; + virtual void setPrivateKeyFile(const std::string& key_file) = 0; + virtual void setCertificateAuthorityFile(const std::string& ca_file) = 0; +}; + +} // namespace net +} // namespace pmc + +#endif // PMC_NET_WEBSOCKET_CLIENT_BASE_HPP \ No newline at end of file diff --git a/lci/include/net/WebSocketClientSSL.hpp b/lci/include/net/WebSocketClientSSL.hpp new file mode 100644 index 0000000..cd7abe5 --- /dev/null +++ b/lci/include/net/WebSocketClientSSL.hpp @@ -0,0 +1,85 @@ +#ifndef PMC_NET_WEBSOCKET_CLIENT_SSL_HPP +#define PMC_NET_WEBSOCKET_CLIENT_SSL_HPP + +#include "WebSocketClientBase.hpp" +#include +#include + +namespace pmc { +namespace net { + +/** + * @brief 基于 Boost.Beast 的异步 WebSocket 客户端(SSL/TLS 版本) + * + * 支持安全的 WebSocket 连接(wss://) + */ +class WebSocketClientSSL : public WebSocketClientBase { +public: + /** + * @brief 构造函数 + * @param host 服务器主机名或 IP 地址 + * @param port 服务器端口号(通常为 443) + * @param path WebSocket 路径(默认 "/") + */ + WebSocketClientSSL(const std::string& host, const std::string& port, const std::string& path = "/"); + + /** + * @brief 析构函数 + */ + ~WebSocketClientSSL(); + + // 实现 WebSocketClientBase 接口 + void setMessageCallback(MessageCallback callback) override; + void setErrorCallback(ErrorCallback callback) override; + void setConnectCallback(ConnectCallback callback) override; + void setCloseCallback(CloseCallback callback) override; + + bool connect(int timeout_ms = 5000) override; + void disconnect() override; + bool isConnected() const override; + + bool send(const std::string& message) override; + bool sendBinary(const void* data, size_t size) override; + + void setAutoReconnect(bool enable, int interval_ms = 3000) override; + void setHeartbeatInterval(int interval_ms = 30000) override; + + std::string getHost() const override; + std::string getPort() const override; + std::string getPath() const override; + + // SSL/TLS 相关方法 + bool isSecure() const override { return true; } + void setVerifyCertificate(bool verify) override; + void setCertificateFile(const std::string& cert_file) override; + void setPrivateKeyFile(const std::string& key_file) override; + void setCertificateAuthorityFile(const std::string& ca_file) override; + + /** + * @brief 设置 SSL 上下文选项 + * @param options SSL 上下文选项 + */ + void setSSLContextOptions(long options); + + /** + * @brief 设置密码列表 + * @param ciphers 密码列表字符串 + */ + void setCiphers(const std::string& ciphers); + + /** + * @brief 设置 SNI 主机名 + * @param sni_hostname SNI 主机名 + */ + void setSNIHostname(const std::string& sni_hostname); + +private: + // 前向声明实现类 + class Impl; + std::unique_ptr impl_; +}; + +} // namespace net +} // namespace pmc + +#endif // PMC_NET_WEBSOCKET_CLIENT_SSL_HPP \ No newline at end of file diff --git a/lci/include/net/WebSocketServer.hpp b/lci/include/net/WebSocketServer.hpp new file mode 100644 index 0000000..660c6b3 --- /dev/null +++ b/lci/include/net/WebSocketServer.hpp @@ -0,0 +1,176 @@ +// WebSocketServer.hpp - WebSocket服务器头文件 +// 基于Boost.Beast和Boost.Asio + +#ifndef PMC_NET_WEBSOCKETSERVER_HPP +#define PMC_NET_WEBSOCKETSERVER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pmc::net { + +/** + * @brief WebSocket连接处理器类型定义 + * + * 处理WebSocket连接建立后的消息收发 + */ +using WebSocketMessageHandler = std::function sendCallback)>; + +/** + * @brief WebSocket连接回调类型定义 + */ +using WebSocketConnectHandler = std::function; + +/** + * @brief WebSocket断开连接回调类型定义 + */ +using WebSocketDisconnectHandler = std::function; + +/** + * @brief WebSocket服务器类 + * + * 基于Boost.Beast和Boost.Asio实现的WebSocket服务器 + */ +class WebSocketServer { +public: + /** + * @brief 构造函数 + * @param port 监听端口 + * @param threads 线程数(默认2) + */ + WebSocketServer(unsigned short port, unsigned int threads = 2); + + /** + * @brief 析构函数 + */ + ~WebSocketServer(); + + /** + * @brief 启动服务器 + */ + void start(); + + /** + * @brief 停止服务器 + */ + void stop(); + + /** + * @brief 注册消息处理器 + * @param path 路径(用于路由) + * @param handler 消息处理器 + */ + void onMessage(const std::string& path, WebSocketMessageHandler handler); + + /** + * @brief 注册连接处理器 + * @param handler 连接处理器 + */ + void onConnect(WebSocketConnectHandler handler); + + /** + * @brief 注册断开连接处理器 + * @param handler 断开连接处理器 + */ + void onDisconnect(WebSocketDisconnectHandler handler); + + /** + * @brief 向指定客户端发送消息 + * @param clientId 客户端ID + * @param message 消息内容 + * @return 是否发送成功 + */ + bool sendToClient(const std::string& clientId, const std::string& message); + + /** + * @brief 向所有客户端广播消息 + * @param message 消息内容 + * @return 成功发送的客户端数量 + */ + size_t broadcast(const std::string& message); + + /** + * @brief 断开指定客户端连接 + * @param clientId 客户端ID + */ + void disconnectClient(const std::string& clientId); + + /** + * @brief 获取当前连接的客户端数量 + * @return 客户端数量 + */ + size_t getClientCount() const; + + /** + * @brief 获取服务器是否正在运行 + * @return 运行状态 + */ + bool isRunning() const { return running_; } + + /** + * @brief 获取服务器监听端口 + * @return 端口号 + */ + unsigned short getPort() const { return port_; } + +private: + // 内部Session类 + class Session; + + // 内部Listener类 + class Listener; + + // 内部实现结构体 + struct Impl { + boost::asio::io_context ioc_; + std::shared_ptr listener_; + std::vector threads_; + }; + + // 服务器配置 + unsigned short port_; + unsigned int threads_; + std::atomic running_{false}; + + // 内部实现 + std::unique_ptr impl_; + + // 生成客户端ID + std::string generateClientId() const; + + // 添加客户端 + void addClient(const std::string& clientId, std::shared_ptr session); + + // 移除客户端 + void removeClient(const std::string& clientId); + + // 获取客户端Session + std::shared_ptr getClient(const std::string& clientId); + + // 回调函数 + std::unordered_map messageHandlers_; + WebSocketConnectHandler connectHandler_; + WebSocketDisconnectHandler disconnectHandler_; + + // 客户端管理 + mutable std::mutex clientsMutex_; + std::unordered_map> clients_; +}; + +} // namespace pmc::net + +#endif // PMC_NET_WEBSOCKETSERVER_HPP \ No newline at end of file diff --git a/lci/include/nn/CNNBuilder.hpp b/lci/include/nn/CNNBuilder.hpp new file mode 100644 index 0000000..a3b7972 --- /dev/null +++ b/lci/include/nn/CNNBuilder.hpp @@ -0,0 +1,141 @@ +#pragma once +#include +#include +#include +#include "../Dashun.h" + +// 卷积神经网络构建辅助类(整合卷积、池化、展平层) +class CNNBuilder { +private: + std::vector(const std::vector&, int, bool)>> forward_layers; + std::vector(const std::vector&, int)>> backward_layers; + std::vector> layer_shapes; + +public: + // 添加卷积层 + void add_conv_layer(ConvLayer& conv, int in_channels, int height, int width) { + conv.set_input_shape(height, width); + auto [out_height, out_width] = conv.get_output_shape(); + + forward_layers.push_back([&conv](const std::vector& input, int batch, bool train) { + return conv.forward(input, batch, train); + }); + + backward_layers.push_back([&conv](const std::vector& grad, int batch) { + auto a = conv.backward(grad, batch); + conv.update_parameters(0.3); + return a; + }); + + layer_shapes.push_back({"Conv", in_channels, out_height, out_width}); + } + + // 添加池化层 + void add_pool_layer(PoolingLayer& pool, int in_channels, int height, int width) { + pool.set_input_shape(in_channels, height, width); + auto [out_channels, out_height, out_width] = pool.get_output_shape(); + + forward_layers.push_back([&pool](const std::vector& input, int batch, bool train) { + return pool.forward(input, batch, train); + }); + + backward_layers.push_back([&pool](const std::vector& grad, int batch) { + return pool.backward(grad, batch); + }); + + layer_shapes.push_back({"Pool", out_channels, out_height, out_width}); + } + + // 添加展平层 + void add_flatten_layer(FlattenLayer& flatten, int in_channels, int height, int width) { + flatten.set_input_shape(in_channels, height, width); + int out_size = flatten.get_output_size(); + + forward_layers.push_back([&flatten](const std::vector& input, int batch, bool train) { + return flatten.forward(input, batch, train); + }); + + backward_layers.push_back([&flatten](const std::vector& grad, int batch) { + return flatten.backward(grad, batch); + }); + + layer_shapes.push_back({"Flatten", out_size, 1, 1}); + } + + // 前向传播(整个网络) + std::vector forward(const std::vector& input, int batch_size = 1, bool training = true) { + std::vector current = input; + + for (size_t i = 0; i < forward_layers.size(); i++) { + current = forward_layers[i](current, batch_size, training); + + if (current.empty()) { + std::cerr << "Error in layer " << i << " (" + << std::get<0>(layer_shapes[i]) << ")" << std::endl; + return std::vector(); + } + } + + return current; + } + + // 反向传播(整个网络) + std::vector backward(const std::vector& grad_output, int batch_size = 1) { + std::vector current_grad = grad_output; + + for (int i = backward_layers.size() - 1; i >= 0; i--) { + current_grad = backward_layers[i](current_grad, batch_size); + + if (current_grad.empty()) { + std::cerr << "Error in backward pass of layer " << i << " (" + << std::get<0>(layer_shapes[i]) << ")" << std::endl; + return std::vector(); + } + } + + return current_grad; + } + + // 打印网络结构 + void print_architecture() const { + std::cout << "CNN Architecture:" << std::endl; + std::cout << "=================" << std::endl; + + for (size_t i = 0; i < layer_shapes.size(); i++) { + auto [layer_type, channels, height, width] = layer_shapes[i]; + + if (layer_type == "Flatten") { + std::cout << "Layer " << i << ": " << layer_type + << " -> Output size: " << channels << std::endl; + } else { + std::cout << "Layer " << i << ": " << layer_type + << " -> Output shape: " << channels + << "x" << height << "x" << width << std::endl; + } + } + } +}; + +/* + +// 构建简单CNN +ConvLayer conv1(3, 16, 3, 1, 1); +PoolingLayer pool1(2, 2, 2); +ConvLayer conv2(16, 32, 3, 1, 1); +PoolingLayer pool2(2, 2, 2); +FlattenLayer flatten; + +// 使用CNN构建器 +CNNBuilder cnn; +cnn.add_conv_layer(conv1, 3, 32, 32); +cnn.add_pool_layer(pool1, 16, 32, 32); +cnn.add_conv_layer(conv2, 16, 16, 16); +cnn.add_pool_layer(pool2, 32, 16, 16); +cnn.add_flatten_layer(flatten, 32, 8, 8); + +// 执行前向传播 +auto output = cnn.forward(input_data, batch_size, true); + +*/ + + diff --git a/lci/include/nn/ConvLayer.hpp b/lci/include/nn/ConvLayer.hpp new file mode 100644 index 0000000..4921815 --- /dev/null +++ b/lci/include/nn/ConvLayer.hpp @@ -0,0 +1,562 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ConvLayer { +private: + // 参数 + int input_channels; + int output_channels; + int kernel_size; + int stride; + int padding; + int input_height; + int input_width; + int output_height; + int output_width; + + // Leaky ReLU参数 + float negative_slope; // Leaky ReLU的负斜率,通常为0.01 + + // 权重和偏置 + std::vector weights; // shape: [output_channels, input_channels, kernel_size, kernel_size] + std::vector bias; // shape: [output_channels] + + // 梯度和动量 + std::vector d_weights; // 权重梯度 + std::vector d_bias; // 偏置梯度 + std::vector weight_momentum; // 动量 + std::vector bias_momentum; // 偏置动量 + + // 中间变量缓存(用于反向传播) + std::vector col_buffer; // im2col后的矩阵 + std::vector input_cache; // 缓存的输入(用于计算输入梯度) + std::vector output_cache; // 缓存的输出(激活前) + std::vector activated_cache; // 激活后的输出缓存 + std::vector col_cache; // 缓存的col矩阵(用于权重梯度计算) + + // 辅助函数 + void im2col(const float* input, int batch_size); + void col2im(const float* col, float* im, int batch_size); + void sgemm(int M, int N, int K, + const float* A, const float* B, float* C, + bool transA = false, bool transB = false); + void sgemm_add(int M, int N, int K, + const float* A, const float* B, float* C, + float alpha = 1.0f, float beta = 1.0f, + bool transA = false, bool transB = false); + + // Leaky ReLU激活函数及其导数 + inline float leaky_relu(float x) const { + return x > 0 ? x : negative_slope * x; + } + + inline float leaky_relu_derivative(float x) const { + return x > 0 ? 1.0f : negative_slope; + } + + // 应用激活函数到整个张量 + void apply_leaky_relu(float* data, int size) { + for (int i = 0; i < size; i++) { + data[i] = leaky_relu(data[i]); + } + } + + // 计算激活函数的梯度 + void compute_activation_gradient(const float* pre_activation, float* gradient, int size) { + for (int i = 0; i < size; i++) { + gradient[i] *= leaky_relu_derivative(pre_activation[i]); + } + } + +public: + // 构造函数 - 添加negative_slope参数 + ConvLayer(int in_channels, int out_channels, + int kernel_size, int stride = 1, int padding = 0, + float negative_slope = 0.01f) + : input_channels(in_channels), + output_channels(out_channels), + kernel_size(kernel_size), + stride(stride), + padding(padding), + negative_slope(negative_slope) { + + // 初始化权重和偏置 + int weight_size = out_channels * in_channels * kernel_size * kernel_size; + weights.resize(weight_size); + d_weights.resize(weight_size, 0.0f); + weight_momentum.resize(weight_size, 0.0f); + + bias.resize(out_channels); + d_bias.resize(out_channels, 0.0f); + bias_momentum.resize(out_channels, 0.0f); + + // He初始化(适合ReLU激活函数) + float std_dev = sqrt(2.0f / (in_channels * kernel_size * kernel_size)); + std::default_random_engine generator; + std::normal_distribution distribution(0.0f, std_dev); + + for (int i = 0; i < weight_size; i++) { + weights[i] = distribution(generator); + } + + for (int i = 0; i < out_channels; i++) { + bias[i] = 0.1f; // 小的正偏置 + } + } + + // 设置输入尺寸(计算输出尺寸) + void set_input_shape(int height, int width) { + input_height = height; + input_width = width; + + output_height = (height + 2 * padding - kernel_size) / stride + 1; + output_width = (width + 2 * padding - kernel_size) / stride + 1; + + // 预分配缓冲区 + int col_height = input_channels * kernel_size * kernel_size; + int col_width = output_height * output_width; + col_buffer.resize(col_height * col_width); + + // 清空缓存 + input_cache.clear(); + output_cache.clear(); + activated_cache.clear(); + col_cache.clear(); + } + + // 前向传播 + std::vector forward(const std::vector& input, int batch_size = 1, bool training = true) { + // 计算输出大小 + int output_size = batch_size * output_channels * output_height * output_width; + std::vector output(output_size, 0.0f); + std::vector pre_activation(output_size, 0.0f); // 激活前的输出 + + // 如果训练模式,缓存输入 + if (training) { + input_cache = input; + } + + // 对batch中的每个样本进行处理 + for (int b = 0; b < batch_size; b++) { + const float* input_ptr = input.data() + b * input_channels * input_height * input_width; + + // 1. im2col转换 + im2col(input_ptr, 1); + + // 2. 矩阵乘法:weights * col_buffer + int M = output_channels; // 输出通道数 + int N = output_height * output_width; // 输出特征图大小 + int K = input_channels * kernel_size * kernel_size; // 卷积核展平大小 + + // 如果训练模式,缓存col矩阵 + if (training && b == 0) { + col_cache = col_buffer; + } + + // 临时存储矩阵乘法结果(激活前) + std::vector gemm_result(M * N, 0.0f); + sgemm(M, N, K, weights.data(), col_buffer.data(), gemm_result.data()); + + // 3. 加上偏置并存储到pre_activation + float* pre_activation_ptr = pre_activation.data() + b * output_channels * output_height * output_width; + float* output_ptr = output.data() + b * output_channels * output_height * output_width; + + for (int oc = 0; oc < output_channels; oc++) { + float bias_val = bias[oc]; + for (int i = 0; i < output_height * output_width; i++) { + float value = gemm_result[oc * N + i] + bias_val; + pre_activation_ptr[oc * output_height * output_width + i] = value; + + // 4. 应用Leaky ReLU激活函数 + output_ptr[oc * output_height * output_width + i] = leaky_relu(value); + } + } + } + + // 如果训练模式,缓存激活前和激活后的输出 + if (training) { + output_cache = pre_activation; // 缓存激活前的输出 + activated_cache = output; // 缓存激活后的输出 + } + + return output; // 返回激活后的输出 + } + + // 反向传播 + std::vector backward(const std::vector& grad_output, int batch_size = 1) { + // grad_output是激活函数后的梯度,需要先计算激活函数前的梯度 + std::vector grad_pre_activation(grad_output); + + // 计算激活函数的梯度:grad_pre_activation = grad_output * leaky_relu_derivative(pre_activation) + for (int b = 0; b < batch_size; b++) { + const float* pre_activation_ptr = output_cache.data() + b * output_channels * output_height * output_width; + float* grad_ptr = grad_pre_activation.data() + b * output_channels * output_height * output_width; + + for (int i = 0; i < output_channels * output_height * output_width; i++) { + grad_ptr[i] *= leaky_relu_derivative(pre_activation_ptr[i]); + } + } + + // 1. 计算偏置梯度: d_bias = sum(grad_pre_activation, axis=(0,2,3)) + std::fill(d_bias.begin(), d_bias.end(), 0.0f); + for (int b = 0; b < batch_size; b++) { + const float* grad_ptr = grad_pre_activation.data() + b * output_channels * output_height * output_width; + for (int oc = 0; oc < output_channels; oc++) { + float sum = 0.0f; + for (int i = 0; i < output_height * output_width; i++) { + sum += grad_ptr[oc * output_height * output_width + i]; + } + d_bias[oc] += sum; + } + } + + // 2. 计算权重梯度: d_weights = grad_pre_activation_col * col_cache^T + std::fill(d_weights.begin(), d_weights.end(), 0.0f); + + int M = output_channels; // 输出通道数 + int N = input_channels * kernel_size * kernel_size; // 卷积核展平大小 + int K = output_height * output_width; // 输出特征图大小 + + // 将grad_pre_activation reshape为矩阵 [output_channels, batch_size * output_height * output_width] + std::vector grad_pre_activation_mat(M * K * batch_size, 0.0f); + for (int b = 0; b < batch_size; b++) { + const float* grad_ptr = grad_pre_activation.data() + b * output_channels * output_height * output_width; + for (int oc = 0; oc < output_channels; oc++) { + for (int i = 0; i < output_height * output_width; i++) { + grad_pre_activation_mat[oc * (K * batch_size) + b * K + i] = + grad_ptr[oc * output_height * output_width + i]; + } + } + } + + // 扩展col_cache以匹配batch大小 + std::vector col_cache_batched(N * K * batch_size, 0.0f); + for (int b = 0; b < batch_size; b++) { + std::copy(col_cache.begin(), col_cache.end(), + col_cache_batched.begin() + b * N * K); + } + + // 矩阵乘法: d_weights = grad_pre_activation_mat * col_cache_batched^T + // grad_pre_activation_mat: [M, K*batch_size], col_cache_batched^T: [K*batch_size, N] + sgemm_add(M, N, K * batch_size, + grad_pre_activation_mat.data(), col_cache_batched.data(), d_weights.data(), + 1.0f, 0.0f, false, true); + + // 3. 计算输入梯度: d_input_col = weights^T * grad_pre_activation_mat + // 然后通过col2im将d_input_col转换为d_input + std::vector d_input(batch_size * input_channels * input_height * input_width, 0.0f); + + // 计算d_input_col + std::vector d_input_col(N * K * batch_size, 0.0f); + sgemm(N, K * batch_size, M, + weights.data(), grad_pre_activation_mat.data(), d_input_col.data(), + true, false); + + // 将d_input_col通过col2im转换回输入形状 + for (int b = 0; b < batch_size; b++) { + float* d_input_ptr = d_input.data() + b * input_channels * input_height * input_width; + col2im(d_input_col.data() + b * N * K, d_input_ptr, 1); + } + + return d_input; + } + + // 更新参数(使用SGD with momentum) + void update_parameters(float learning_rate = 0.01f, float momentum = 0.9f) { + // 更新权重 + for (size_t i = 0; i < weights.size(); i++) { + weight_momentum[i] = momentum * weight_momentum[i] - learning_rate * d_weights[i]; + weights[i] += weight_momentum[i]; + } + + // 更新偏置 + for (size_t i = 0; i < bias.size(); i++) { + bias_momentum[i] = momentum * bias_momentum[i] - learning_rate * d_bias[i]; + bias[i] += bias_momentum[i]; + } + + // 重置梯度(可选) + // std::fill(d_weights.begin(), d_weights.end(), 0.0f); + // std::fill(d_bias.begin(), d_bias.end(), 0.0f); + } + + // Adam优化器更新参数 + void update_parameters_adam(float learning_rate = 0.001f, + float beta1 = 0.9f, float beta2 = 0.999f, + float epsilon = 1e-8f, int t = 1) { + static std::vector m_weights(weights.size(), 0.0f); + static std::vector v_weights(weights.size(), 0.0f); + static std::vector m_bias(bias.size(), 0.0f); + static std::vector v_bias(bias.size(), 0.0f); + + // 更新权重的一阶矩和二阶矩估计 + for (size_t i = 0; i < weights.size(); i++) { + m_weights[i] = beta1 * m_weights[i] + (1 - beta1) * d_weights[i]; + v_weights[i] = beta2 * v_weights[i] + (1 - beta2) * d_weights[i] * d_weights[i]; + + // 偏差校正 + float m_hat = m_weights[i] / (1 - powf(beta1, t)); + float v_hat = v_weights[i] / (1 - powf(beta2, t)); + + // 更新权重 + weights[i] -= learning_rate * m_hat / (sqrtf(v_hat) + epsilon); + } + + // 更新偏置的一阶矩和二阶矩估计 + for (size_t i = 0; i < bias.size(); i++) { + m_bias[i] = beta1 * m_bias[i] + (1 - beta1) * d_bias[i]; + v_bias[i] = beta2 * v_bias[i] + (1 - beta2) * d_bias[i] * d_bias[i]; + + // 偏差校正 + float m_hat = m_bias[i] / (1 - powf(beta1, t)); + float v_hat = v_bias[i] / (1 - powf(beta2, t)); + + // 更新偏置 + bias[i] -= learning_rate * m_hat / (sqrtf(v_hat) + epsilon); + } + } + + // 获取参数 + const std::vector& get_weights() const { return weights; } + const std::vector& get_bias() const { return bias; } + const std::vector& get_weight_gradients() const { return d_weights; } + const std::vector& get_bias_gradients() const { return d_bias; } + + // 设置参数(用于加载预训练模型) + void set_weights(const std::vector& new_weights) { weights = new_weights; } + void set_bias(const std::vector& new_bias) { bias = new_bias; } + + // 设置Leaky ReLU参数 + void set_leaky_relu_slope(float slope) { negative_slope = slope; } + + // 获取输出尺寸 + std::tuple get_output_shape() const { + return std::make_tuple(output_height, output_width); + } + + // 梯度检查(用于调试) + float gradient_check(const std::vector& input, + const std::vector& grad_output, + int weight_idx, float epsilon = 1e-5f) { + // 保存原始权重 + float original_weight = weights[weight_idx]; + + // 计算f(x + epsilon) + weights[weight_idx] = original_weight + epsilon; + auto output_plus = forward(input, 1, false); + + // 计算f(x - epsilon) + weights[weight_idx] = original_weight - epsilon; + auto output_minus = forward(input, 1, false); + + // 恢复原始权重 + weights[weight_idx] = original_weight; + + // 计算数值梯度 + float numerical_grad = 0.0f; + for (size_t i = 0; i < output_plus.size(); i++) { + numerical_grad += grad_output[i] * (output_plus[i] - output_minus[i]) / (2 * epsilon); + } + + // 返回梯度差异 + return fabs(numerical_grad - d_weights[weight_idx]); + } +}; + +// im2col实现 - 将图像转换为矩阵 +void ConvLayer::im2col(const float* input, int batch_size) { + int col_height = input_channels * kernel_size * kernel_size; + int col_width = output_height * output_width; + + int input_h_padded = input_height + 2 * padding; + int input_w_padded = input_width + 2 * padding; + + // 创建填充后的输入(如果需要) + std::vector padded_input; + const float* input_data = input; + + if (padding > 0) { + padded_input.resize(input_channels * input_h_padded * input_w_padded, 0.0f); + for (int c = 0; c < input_channels; c++) { + for (int h = 0; h < input_height; h++) { + for (int w = 0; w < input_width; w++) { + int padded_idx = c * input_h_padded * input_w_padded + + (h + padding) * input_h_padded + (w + padding); + int orig_idx = c * input_height * input_width + h * input_width + w; + padded_input[padded_idx] = input[orig_idx]; + } + } + } + input_data = padded_input.data(); + } + + // 执行im2col + int col_idx = 0; + for (int c = 0; c < input_channels; c++) { + for (int kh = 0; kh < kernel_size; kh++) { + for (int kw = 0; kw < kernel_size; kw++) { + for (int h = 0; h < output_height; h++) { + for (int w = 0; w < output_width; w++) { + int input_h = h * stride + kh; + int input_w = w * stride + kw; + + int input_idx = c * input_h_padded * input_w_padded + + input_h * input_w_padded + input_w; + + col_buffer[col_idx++] = input_data[input_idx]; + } + } + } + } + } +} + +// col2im实现 - 将矩阵转换回图像(用于梯度传播) +void ConvLayer::col2im(const float* col, float* im, int batch_size) { + int col_height = input_channels * kernel_size * kernel_size; + int col_width = output_height * output_width; + + int input_h_padded = input_height + 2 * padding; + int input_w_padded = input_width + 2 * padding; + + // 创建填充后的图像缓冲区 + std::vector padded_im(input_channels * input_h_padded * input_w_padded, 0.0f); + + // 执行col2im + int col_idx = 0; + for (int c = 0; c < input_channels; c++) { + for (int kh = 0; kh < kernel_size; kh++) { + for (int kw = 0; kw < kernel_size; kw++) { + for (int h = 0; h < output_height; h++) { + for (int w = 0; w < output_width; w++) { + int input_h = h * stride + kh; + int input_w = w * stride + kw; + + int input_idx = c * input_h_padded * input_w_padded + + input_h * input_w_padded + input_w; + + padded_im[input_idx] += col[col_idx++]; + } + } + } + } + } + + // 去除padding,得到原始输入梯度 + if (padding > 0) { + for (int c = 0; c < input_channels; c++) { + for (int h = 0; h < input_height; h++) { + for (int w = 0; w < input_width; w++) { + int padded_idx = c * input_h_padded * input_w_padded + + (h + padding) * input_w_padded + (w + padding); + int orig_idx = c * input_height * input_width + h * input_width + w; + im[orig_idx] = padded_im[padded_idx]; + } + } + } + } else { + std::copy(padded_im.begin(), padded_im.end(), im); + } +} + +// 优化的矩阵乘法 +void ConvLayer::sgemm(int M, int N, int K, + const float* A, const float* B, float* C, + bool transA, bool transB) { + // 初始化输出为0 + std::memset(C, 0, M * N * sizeof(float)); + + // 调用带参数的版本 + sgemm_add(M, N, K, A, B, C, 1.0f, 0.0f, transA, transB); +} + +// 带参数的矩阵乘法(支持转置) +void ConvLayer::sgemm_add(int M, int N, int K, + const float* A, const float* B, float* C, + float alpha, float beta, + bool transA, bool transB) { + // 如果beta为0,清空C + if (beta == 0.0f) { + std::memset(C, 0, M * N * sizeof(float)); + } + + // 优化:使用循环展开和缓存友好的访问模式 + const int BLOCK_SIZE = 4; + + // 处理A转置的情况 + if (transA && !transB) { + // C = A^T * B + for (int i = 0; i < M; i++) { + for (int k = 0; k < K; k++) { + float a = A[k * M + i] * alpha; + if (a == 0.0f) continue; + + const float* B_ptr = B + k * N; + float* C_ptr = C + i * N; + + int j = 0; + for (; j <= N - BLOCK_SIZE; j += BLOCK_SIZE) { + C_ptr[j] += a * B_ptr[j]; + C_ptr[j + 1] += a * B_ptr[j + 1]; + C_ptr[j + 2] += a * B_ptr[j + 2]; + C_ptr[j + 3] += a * B_ptr[j + 3]; + } + for (; j < N; j++) { + C_ptr[j] += a * B_ptr[j]; + } + } + } + } else if (!transA && transB) { + // C = A * B^T + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + float sum = 0.0f; + for (int k = 0; k < K; k++) { + sum += A[i * K + k] * B[j * K + k]; + } + C[i * N + j] = beta * C[i * N + j] + alpha * sum; + } + } + } else if (transA && transB) { + // C = A^T * B^T = (B * A)^T + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + float sum = 0.0f; + for (int k = 0; k < K; k++) { + sum += A[k * M + i] * B[j * K + k]; + } + C[i * N + j] = beta * C[i * N + j] + alpha * sum; + } + } + } else { + // C = A * B + for (int i = 0; i < M; i++) { + for (int k = 0; k < K; k++) { + float a = A[i * K + k] * alpha; + if (a == 0.0f) continue; + + const float* B_ptr = B + k * N; + float* C_ptr = C + i * N; + + int j = 0; + for (; j <= N - BLOCK_SIZE; j += BLOCK_SIZE) { + C_ptr[j] += a * B_ptr[j]; + C_ptr[j + 1] += a * B_ptr[j + 1]; + C_ptr[j + 2] += a * B_ptr[j + 2]; + C_ptr[j + 3] += a * B_ptr[j + 3]; + } + for (; j < N; j++) { + C_ptr[j] += a * B_ptr[j]; + } + } + } + } +} \ No newline at end of file diff --git a/lci/include/nn/FlattenLayer.hpp b/lci/include/nn/FlattenLayer.hpp new file mode 100644 index 0000000..69084de --- /dev/null +++ b/lci/include/nn/FlattenLayer.hpp @@ -0,0 +1,366 @@ +#pragma once +#include +#include +#include +#include +#include +#include "ConvLayer.hpp" + +class FlattenLayer { +private: + // 输入输出尺寸 + int batch_size; + int input_channels; + int input_height; + int input_width; + int output_size; + + // 缓存输入形状(用于反向传播) + std::vector input_shape_cache; + std::vector input_cache; // 缓存输入数据(可选) + + // 辅助函数 + //void flatten_forward(const float* input, float* output); + //void flatten_backward(const float* grad_output, float* grad_input); + +public: + // 构造函数 + FlattenLayer() : batch_size(0), input_channels(0), + input_height(0), input_width(0), output_size(0) {} + + // 设置输入尺寸(自动计算输出尺寸) + void set_input_shape(int channels, int height, int width, int batch = 1) { + input_channels = channels; + input_height = height; + input_width = width; + batch_size = batch; + + // 计算输出大小 + output_size = channels * height * width; + + // 缓存输入形状 + input_shape_cache = {channels, height, width, batch}; + } + + // 设置输入尺寸(从卷积/池化层获取) + template + void set_input_shape(std::tuple shape_tuple) { + set_input_shape(std::get<0>(shape_tuple), + std::get<1>(shape_tuple), + std::get<2>(shape_tuple)); + } + + // 前向传播 + std::vector forward(const std::vector& input, int batch_size = 1, bool training = true) { + // 如果之前没有设置输入尺寸,自动推断 + if (input_channels == 0 && input_height == 0 && input_width == 0) { + // 这里假设输入是完整的batch数据,需要外部调用set_input_shape + // 或者根据输入大小推断(但不知道高度和宽度) + std::cerr << "Warning: Input shape not set for FlattenLayer. " + << "Please call set_input_shape() first." << std::endl; + return input; // 安全返回,但可能不正确 + } + + // 检查输入大小是否匹配 + int expected_input_size = batch_size * input_channels * input_height * input_width; + if (input.size() != static_cast(expected_input_size)) { + std::cerr << "Error: Input size mismatch in FlattenLayer. " + << "Expected: " << expected_input_size + << ", Got: " << input.size() << std::endl; + return std::vector(); + } + + // 如果训练模式,缓存输入形状 + if (training) { + this->batch_size = batch_size; + input_shape_cache = {input_channels, input_height, input_width, batch_size}; + input_cache = input; // 可选:缓存输入数据 + } + + // 计算输出大小 + int output_total_size = batch_size * output_size; + std::vector output(output_total_size, 0.0f); + + // 执行展平操作 + flatten_forward(input.data(), output.data()); + + return output; + } + + // 反向传播 + std::vector backward(const std::vector& grad_output, int batch_size = 1) { + // 检查梯度大小是否匹配 + int expected_grad_size = batch_size * output_size; + if (grad_output.size() != static_cast(expected_grad_size)) { + std::cerr << "Error: Gradient size mismatch in FlattenLayer. " + << "Expected: " << expected_grad_size + << ", Got: " << grad_output.size() << std::endl; + return std::vector(); + } + + // 恢复输入形状 + if (input_shape_cache.size() >= 4) { + input_channels = input_shape_cache[0]; + input_height = input_shape_cache[1]; + input_width = input_shape_cache[2]; + this->batch_size = input_shape_cache[3]; + } + + // 计算输入梯度大小 + int input_total_size = this->batch_size * input_channels * input_height * input_width; + std::vector grad_input(input_total_size, 0.0f); + + // 执行反向展平操作 + flatten_backward(grad_output.data(), grad_input.data()); + + return grad_input; + } + + // 获取输出尺寸 + int get_output_size() const { + return output_size; + } + + // 获取输出尺寸(返回元组) + std::tuple get_output_shape() const { + return std::make_tuple(output_size); + } + + // 获取输入尺寸 + std::tuple get_input_shape() const { + return std::make_tuple(input_channels, input_height, input_width); + } + + // 获取完整输入尺寸(包含批次) + std::tuple get_full_input_shape() const { + return std::make_tuple(input_channels, input_height, input_width, batch_size); + } + + // 打印层信息 + void print_info() const { + std::cout << "Flatten Layer Info:" << std::endl; + std::cout << " Input Shape: " << input_channels << "x" + << input_height << "x" << input_width; + if (batch_size > 0) { + std::cout << " (batch: " << batch_size << ")"; + } + std::cout << std::endl; + std::cout << " Output Size: " << output_size; + if (batch_size > 0) { + std::cout << " (total: " << batch_size * output_size << ")"; + } + std::cout << std::endl; + } + + // 重置层状态 + void reset() { + input_shape_cache.clear(); + input_cache.clear(); + batch_size = 0; + input_channels = 0; + input_height = 0; + input_width = 0; + output_size = 0; + } + + // 检查是否已初始化 + bool is_initialized() const { + return input_channels > 0 && input_height > 0 && input_width > 0; + } + +private: + // 展平前向传播实现 + void flatten_forward(const float* input, float* output) { + // 简单地将多维数据复制到一维数组 + int elements_per_sample = input_channels * input_height * input_width; + + for (int b = 0; b < batch_size; b++) { + const float* input_ptr = input + b * elements_per_sample; + float* output_ptr = output + b * output_size; + + // 直接内存复制 + std::copy(input_ptr, input_ptr + elements_per_sample, output_ptr); + + // 或者使用循环(等效) + /* + for (int i = 0; i < elements_per_sample; i++) { + output_ptr[i] = input_ptr[i]; + } + */ + } + } + + // 展平反向传播实现 + void flatten_backward(const float* grad_output, float* grad_input) { + // 反向传播只是将梯度重新整形为输入形状 + int elements_per_sample = input_channels * input_height * input_width; + + for (int b = 0; b < batch_size; b++) { + const float* grad_output_ptr = grad_output + b * output_size; + float* grad_input_ptr = grad_input + b * elements_per_sample; + + // 直接内存复制 + std::copy(grad_output_ptr, grad_output_ptr + elements_per_sample, grad_input_ptr); + + // 或者使用循环(等效) + /* + for (int i = 0; i < elements_per_sample; i++) { + grad_input_ptr[i] = grad_output_ptr[i]; + } + */ + } + } +}; + +// 动态展平层(自动推断输入形状) +class DynamicFlattenLayer { +private: + int batch_size; + int input_channels; + int input_height; + int input_width; + int output_size; + +public: + DynamicFlattenLayer() : batch_size(0), input_channels(0), + input_height(0), input_width(0), output_size(0) {} + + // 前向传播(自动推断形状) + std::vector forward(const std::vector& input, + std::tuple input_shape, + int batch_size = 1, + bool training = true) { + // 从元组获取输入形状 + input_channels = std::get<0>(input_shape); + input_height = std::get<1>(input_shape); + input_width = std::get<2>(input_shape); + this->batch_size = batch_size; + + // 验证输入大小 + int expected_size = batch_size * input_channels * input_height * input_width; + if (input.size() != static_cast(expected_size)) { + std::cerr << "Error: Input size mismatch in DynamicFlattenLayer. " + << "Expected: " << expected_size + << ", Got: " << input.size() + << " (shape: " << input_channels << "x" + << input_height << "x" << input_width + << ", batch: " << batch_size << ")" << std::endl; + return std::vector(); + } + + // 计算输出大小 + output_size = input_channels * input_height * input_width; + int total_output_size = batch_size * output_size; + std::vector output(total_output_size); + + // 执行展平 + const float* input_ptr = input.data(); + float* output_ptr = output.data(); + + int elements_per_sample = output_size; + for (int b = 0; b < batch_size; b++) { + std::copy(input_ptr, input_ptr + elements_per_sample, output_ptr); + input_ptr += elements_per_sample; + output_ptr += elements_per_sample; + } + + return output; + } + + // 反向传播 + std::vector backward(const std::vector& grad_output, int batch_size = 1) { + // 检查是否已初始化 + if (output_size == 0) { + std::cerr << "Error: DynamicFlattenLayer not initialized. " + << "Call forward() first." << std::endl; + return std::vector(); + } + + // 验证梯度大小 + int expected_grad_size = batch_size * output_size; + if (grad_output.size() != static_cast(expected_grad_size)) { + std::cerr << "Error: Gradient size mismatch in DynamicFlattenLayer. " + << "Expected: " << expected_grad_size + << ", Got: " << grad_output.size() << std::endl; + return std::vector(); + } + + // 恢复输入形状 + int total_input_size = batch_size * input_channels * input_height * input_width; + std::vector grad_input(total_input_size); + + // 执行反向展平 + const float* grad_output_ptr = grad_output.data(); + float* grad_input_ptr = grad_input.data(); + + int elements_per_sample = output_size; + for (int b = 0; b < batch_size; b++) { + std::copy(grad_output_ptr, grad_output_ptr + elements_per_sample, grad_input_ptr); + grad_output_ptr += elements_per_sample; + grad_input_ptr += elements_per_sample; + } + + return grad_input; + } + + // 获取输出尺寸 + int get_output_size() const { return output_size; } + + // 获取输入形状 + std::tuple get_input_shape() const { + return std::make_tuple(input_channels, input_height, input_width); + } +}; + +// 使用示例函数 +inline void flatten_layer_example() { + std::cout << "=== Flatten Layer Example ===" << std::endl; + + // 创建展平层 + FlattenLayer flatten; + + // 设置输入形状(例如从池化层获取的输出) + // 假设池化层输出:64通道,7x7特征图 + flatten.set_input_shape(64, 7, 7); + + // 创建模拟输入数据(batch_size=2) + int batch_size = 2; + std::vector input(2 * 64 * 7 * 7); + for (size_t i = 0; i < input.size(); i++) { + input[i] = static_cast(i) / 100.0f; + } + + // 前向传播 + std::cout << "Forward pass..." << std::endl; + auto output = flatten.forward(input, batch_size, true); + + std::cout << "Input size: " << input.size() << std::endl; + std::cout << "Output size: " << output.size() << std::endl; + std::cout << "Expected output size per sample: " << flatten.get_output_size() << std::endl; + + // 打印部分结果 + std::cout << "First 10 output values: "; + for (int i = 0; i < std::min(10, static_cast(output.size())); i++) { + std::cout << output[i] << " "; + } + std::cout << std::endl; + + // 创建模拟梯度(全为1) + std::vector grad_output(output.size(), 1.0f); + + // 反向传播 + std::cout << "Backward pass..." << std::endl; + auto grad_input = flatten.backward(grad_output, batch_size); + + std::cout << "Gradient input size: " << grad_input.size() << std::endl; + std::cout << "Expected gradient input size: " << 2 * 64 * 7 * 7 << std::endl; + + // 验证形状正确性 + auto [channels, height, width] = flatten.get_input_shape(); + std::cout << "Recovered input shape: " << channels + << "x" << height << "x" << width << std::endl; + + // 打印层信息 + flatten.print_info(); +} + diff --git a/lci/include/nn/ILayer.hpp b/lci/include/nn/ILayer.hpp new file mode 100644 index 0000000..295faf5 --- /dev/null +++ b/lci/include/nn/ILayer.hpp @@ -0,0 +1,66 @@ +#pragma once +#include +#include +/* FIXME: 设置为每层可调节的 */ +/* FIXME: 现在这个“接口”并未提供抽象函数 */ +constexpr float LEAKY_RELU_ALPHA = 0.01; +using f_t = float(*)(float); /* FIXME: 在qing::Thread附近已经定义了f_t标识符 */ + +/* 神经网络层接口 */ +class ILayer { +public: + + /* 激活函数枚举类 */ + enum class ActivationFunc { + None, ReLU, Leaky_ReLU, Sigmoid, Tanh + }; + + /* 获取类型名 */ + static const char* get_f_type(ActivationFunc& af); + + /* 通过类型名获取实体 */ + static ActivationFunc parse_ff_type(const std::string& name); + + + /* 向输出流存储模型 */ + virtual void save(std::ostream& out) = 0; + + /* 从输入流加载模型 + * FIXME: 这个方法我做成了工厂模式 + */ + //virtual void load(std::istream& in) = 0; + +protected: + + /* 获取函数对象 - 获取激活函数 */ + static f_t getf(ActivationFunc type); + + /* 获取函数对象 - 求激活函数导数 */ + static f_t getfdot(ActivationFunc type); + + /* ReLU 激活函数 */ + static float relu(float x); + + /* ReLU 导数 */ + static float relu_derivative(float x); + + /* + * leaky ReLU 激活函数 + * + * NOTE: alpha太小或者选择使用ReLU函数的情况下,会导致梯度消失 + * NOTE: Leaky ReLU 不会使梯度完全消失,但也会使它变得很小 + */ + static float leaky_relu(float x); + /* leaky ReLU 导数 */ + static float leaky_relu_derivative(float x); + + /* Sigmoid 激活函数 */ + static float sigmoid(float x); + /* Sigmoid 导数 */ + static float sigmoid_derivative(float x); + + /* Tanh 激活函数 */ + static float tanh(float x); + /* Tanh 导数 */ + static float tanh_derivative(float x); +}; diff --git a/lci/include/nn/ILayerConvolutional.hpp b/lci/include/nn/ILayerConvolutional.hpp new file mode 100644 index 0000000..3cfc5c4 --- /dev/null +++ b/lci/include/nn/ILayerConvolutional.hpp @@ -0,0 +1,3 @@ +#pragma once +#include "../Dashun.h" +class ILayerConvolutional: public ILayer, public ILearnable {}; \ No newline at end of file diff --git a/lci/include/nn/ILayerFullyConnectted.hpp b/lci/include/nn/ILayerFullyConnectted.hpp new file mode 100644 index 0000000..dafcfe3 --- /dev/null +++ b/lci/include/nn/ILayerFullyConnectted.hpp @@ -0,0 +1,10 @@ +#pragma once +#include "nn/ILayer.hpp" +#include "nn/ILearnable.hpp" +class ILayerFullyConnectted: public ILayer, public ILearnable { +public: + /* 正向传播,返回神经网络输出 */ + virtual std::vector forward(const std::vector& inputs) = 0; + /* 反向传播,返回上一层的误差,方便堆叠 */ + virtual std::vector backward(const std::vector& error) = 0; +}; diff --git a/lci/include/nn/ILearnable.hpp b/lci/include/nn/ILearnable.hpp new file mode 100644 index 0000000..b5d3013 --- /dev/null +++ b/lci/include/nn/ILearnable.hpp @@ -0,0 +1,5 @@ +#pragma once +class ILearnable { +public: + virtual void update(float discount) = 0; +}; \ No newline at end of file diff --git a/lci/include/nn/ImageLoader.hpp b/lci/include/nn/ImageLoader.hpp new file mode 100644 index 0000000..0e652f1 --- /dev/null +++ b/lci/include/nn/ImageLoader.hpp @@ -0,0 +1,523 @@ +#pragma once + +#define cimg_use_png /* -lpng */ +#define cimg_use_jpeg /* -ljpeg */ +#define cimg_display 0 // 禁用显示窗口,用于服务器环境 +#include "CImg.h" +#include +#include +#include +#include +#include +#include +#include +#include // 用于检查文件是否存在 +#include // 用于目录遍历 + +class ImageLoader { +private: + // 图像参数 + int target_channels; // 目标通道数(如RGB=3, 灰度=1) + int target_height; // 目标高度 + int target_width; // 目标宽度 + bool normalize_to_01; // 是否归一化到[0,1] + bool normalize_mean_std; // 是否使用均值标准差归一化 + float mean_val; // 均值(归一化用) + float std_val; // 标准差(归一化用) + bool auto_mean_std; // 是否自动计算均值标准差 + + // 预计算的均值和标准差(针对每个通道) + std::vector channel_means; + std::vector channel_stds; + + // 用于调试的verbose标志 + bool verbose; + + // 辅助函数:检查文件是否存在(POSIX兼容) + bool file_exists(const std::string& filename) { + struct stat buffer; + return (stat(filename.c_str(), &buffer) == 0); + } + + // 辅助函数:检查是否为普通文件 + bool is_regular_file(const std::string& path) { + struct stat path_stat; + if (stat(path.c_str(), &path_stat) != 0) { + return false; + } + return S_ISREG(path_stat.st_mode); + } + + // 辅助函数:获取文件扩展名 + std::string get_file_extension(const std::string& filename) { + size_t dot_pos = filename.find_last_of("."); + if (dot_pos == std::string::npos) { + return ""; + } + return filename.substr(dot_pos); + } + + // 辅助函数:转换为小写 + std::string to_lower(const std::string& str) { + std::string result = str; + std::transform(result.begin(), result.end(), result.begin(), ::tolower); + return result; + } + +public: + // 构造函数 + ImageLoader(int channels = 3, int height = 224, int width = 224, + bool norm_01 = true, bool norm_mean_std = false, + float mean = 0.0f, float std = 1.0f, bool auto_compute = false) + : target_channels(channels), + target_height(height), + target_width(width), + normalize_to_01(norm_01), + normalize_mean_std(norm_mean_std), + mean_val(mean), + std_val(std), + auto_mean_std(auto_compute), + verbose(false) { + + // 初始化通道统计量 + channel_means.resize(target_channels, 0.0f); + channel_stds.resize(target_channels, 1.0f); + } + + // 从文件加载单张图片 + std::vector load_image(const std::string& filepath, bool verbose = false) { + this->verbose = verbose; + + try { + // 检查文件是否存在 + if (!file_exists(filepath)) { + throw std::runtime_error("File not found: " + filepath); + } + + // 加载图像 + cimg_library::CImg img(filepath.c_str()); + + if (verbose) { + std::cout << "Loaded image: " << filepath << std::endl; + std::cout << "Original size: " << img.width() << "x" << img.height() + << "x" << img.spectrum() << std::endl; + } + + // 转换为目标格式并预处理 + return preprocess_image(img, verbose); + + } catch (const std::exception& e) { + std::cerr << "Error loading image " << filepath << ": " << e.what() << std::endl; + return {}; + } + } + + // 从CImg对象加载图片 + std::vector load_from_cimg(const cimg_library::CImg& input_img, bool verbose = false) { + this->verbose = verbose; + + try { + // 创建图像的副本(因为预处理函数可能会修改图像) + cimg_library::CImg img = input_img; + + if (verbose) { + std::cout << "Loading from CImg object" << std::endl; + std::cout << "Original size: " << img.width() << "x" << img.height() + << "x" << img.spectrum() << std::endl; + } + + // 检查图像是否为空 + if (img.is_empty()) { + throw std::runtime_error("Input CImg object is empty"); + } + + // 转换为目标格式并预处理 + return preprocess_image(img, verbose); + + } catch (const std::exception& e) { + std::cerr << "Error loading image from CImg object: " << e.what() << std::endl; + return {}; + } + } + + // 从CImg对象加载图片(移动语义版本) + std::vector load_from_cimg(cimg_library::CImg&& input_img, bool verbose = false) { + this->verbose = verbose; + + try { + // 直接使用移动过来的图像对象 + cimg_library::CImg img = std::move(input_img); + + if (verbose) { + std::cout << "Loading from CImg object (move semantics)" << std::endl; + std::cout << "Original size: " << img.width() << "x" << img.height() + << "x" << img.spectrum() << std::endl; + } + + // 检查图像是否为空 + if (img.is_empty()) { + throw std::runtime_error("Input CImg object is empty"); + } + + // 转换为目标格式并预处理 + return preprocess_image(img, verbose); + + } catch (const std::exception& e) { + std::cerr << "Error loading image from CImg object: " << e.what() << std::endl; + return {}; + } + } + + // 批量加载图片 + std::vector load_batch(const std::vector& filepaths, bool verbose = false) { + this->verbose = verbose; + + std::vector batch_data; + int loaded_count = 0; + + for (const auto& filepath : filepaths) { + auto img_data = load_image(filepath, verbose); + if (!img_data.empty()) { + if (batch_data.empty()) { + batch_data = img_data; + } else { + // 追加到batch数据中 + batch_data.insert(batch_data.end(), img_data.begin(), img_data.end()); + } + loaded_count++; + } + } + + if (verbose) { + std::cout << "Successfully loaded " << loaded_count << " images out of " + << filepaths.size() << std::endl; + } + + return batch_data; + } + + + // 从文件夹加载所有图片 + std::vector load_from_directory(const std::string& dir_path, + const std::vector& extensions = {".jpg", ".jpeg", ".png", ".bmp"}, + bool verbose = false) { + this->verbose = verbose; + + std::vector image_files; + + try { + // 打开目录 + DIR* dir = opendir(dir_path.c_str()); + if (!dir) { + throw std::runtime_error("Cannot open directory: " + dir_path); + } + + // 读取目录项 + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + std::string filename = entry->d_name; + + // 跳过"."和".." + if (filename == "." || filename == "..") { + continue; + } + + // 构建完整路径 + std::string full_path = dir_path; + if (dir_path.back() != '/') { + full_path += "/"; + } + full_path += filename; + + // 检查是否为普通文件 + if (is_regular_file(full_path)) { + // 检查文件扩展名 + std::string ext = get_file_extension(filename); + std::string ext_lower = to_lower(ext); + + // 检查是否在允许的扩展名列表中 + bool valid_extension = false; + for (const auto& allowed_ext : extensions) { + if (ext_lower == to_lower(allowed_ext)) { + valid_extension = true; + break; + } + } + + if (valid_extension) { + image_files.push_back(full_path); + } + } + } + + closedir(dir); + + if (verbose) { + std::cout << "Found " << image_files.size() << " images in directory: " + << dir_path << std::endl; + } + + return load_batch(image_files, verbose); + + } catch (const std::exception& e) { + std::cerr << "Error reading directory " << dir_path << ": " << e.what() << std::endl; + return {}; + } + } + + // 计算数据集统计量(用于归一化) + void compute_dataset_statistics(const std::vector& filepaths, + int max_images = 1000) { + std::cout << "Computing dataset statistics..." << std::endl; + + int num_images = std::min(static_cast(filepaths.size()), max_images); + std::vector> channel_sums(target_channels, std::vector()); + + // 采样计算 + for (int i = 0; i < num_images; i++) { + auto img_data = load_image(filepaths[i], false); + if (!img_data.empty()) { + // 计算每个通道的像素值 + int pixels_per_channel = target_height * target_width; + for (int c = 0; c < target_channels; c++) { + const float* channel_start = img_data.data() + c * pixels_per_channel; + channel_sums[c].insert(channel_sums[c].end(), + channel_start, + channel_start + pixels_per_channel); + } + } + + if (i % 100 == 0) { + std::cout << "Processed " << i << " images..." << std::endl; + } + } + + // 计算均值和标准差 + for (int c = 0; c < target_channels; c++) { + if (!channel_sums[c].empty()) { + // 计算均值 + float sum = std::accumulate(channel_sums[c].begin(), channel_sums[c].end(), 0.0f); + channel_means[c] = sum / channel_sums[c].size(); + + // 计算标准差 + float variance = 0.0f; + for (float val : channel_sums[c]) { + variance += (val - channel_means[c]) * (val - channel_means[c]); + } + variance /= channel_sums[c].size(); + channel_stds[c] = std::sqrt(variance); + + std::cout << "Channel " << c << ": mean = " << channel_means[c] + << ", std = " << channel_stds[c] << std::endl; + } + } + + std::cout << "Statistics computation completed." << std::endl; + } + + // 获取批次数(根据总像素数计算) + int get_batch_size(const std::vector& data) const { + int single_image_size = target_channels * target_height * target_width; + if (single_image_size == 0) return 0; + return data.size() / single_image_size; + } + + // 设置归一化参数 + void set_normalization_params(const std::vector& means, + const std::vector& stds) { + if (means.size() == target_channels && stds.size() == target_channels) { + channel_means = means; + channel_stds = stds; + } else { + std::cerr << "Error: Means and stds must have size " << target_channels << std::endl; + } + } + + // 获取归一化参数 + std::pair, std::vector> get_normalization_params() const { + return {channel_means, channel_stds}; + } + + // 显示图像信息(用于调试) + void display_image_info(const std::vector& image_data, int channels_to_show = 3) const { + int single_image_size = target_channels * target_height * target_width; + + std::cout << "Image data info:" << std::endl; + std::cout << " Dimensions: " << target_channels << " x " << target_height + << " x " << target_width << std::endl; + std::cout << " Total values: " << image_data.size() << std::endl; + + if (!image_data.empty()) { + // 计算统计信息 + float min_val = *std::min_element(image_data.begin(), image_data.end()); + float max_val = *std::max_element(image_data.begin(), image_data.end()); + float sum_val = std::accumulate(image_data.begin(), image_data.end(), 0.0f); + float mean_val = sum_val / image_data.size(); + + std::cout << " Min value: " << min_val << std::endl; + std::cout << " Max value: " << max_val << std::endl; + std::cout << " Mean value: " << mean_val << std::endl; + + // 显示每个通道的前几个像素 + int pixels_per_channel = target_height * target_width; + for (int c = 0; c < std::min(target_channels, channels_to_show); c++) { + std::cout << " Channel " << c << " (first 5 pixels): "; + for (int i = 0; i < std::min(5, pixels_per_channel); i++) { + std::cout << image_data[c * pixels_per_channel + i] << " "; + } + std::cout << std::endl; + } + } + } + + // 获取目标尺寸(公开访问器) + int get_target_height() const { return target_height; } + int get_target_width() const { return target_width; } + int get_target_channels() const { return target_channels; } + + // 设置verbose模式 + void set_verbose(bool v) { verbose = v; } + +private: + // 图像预处理主函数 + std::vector preprocess_image(cimg_library::CImg& img, bool verbose = false) { + // 1. 调整通道数 + adjust_channels(img); + + // 2. 调整尺寸 + resize_image(img); + + // 3. 转换为浮点数 + std::vector float_data = convert_to_float(img); + + // 4. 重新排列维度为 [channels, height, width] + std::vector reordered_data = reorder_dimensions(float_data, img); + + // 5. 归一化 + if (normalize_to_01) { + normalize_0_1(reordered_data); + } + + if (normalize_mean_std) { + normalize_mean_std_channels(reordered_data); + } + + if (verbose) { + std::cout << "Processed image size: " << target_channels << "x" + << target_height << "x" << target_width << std::endl; + } + + return reordered_data; + } + + // 调整通道数 + void adjust_channels(cimg_library::CImg& img) { + int current_channels = img.spectrum(); + + if (current_channels == 1 && target_channels == 3) { + // 灰度转RGB:复制单通道到三个通道 + cimg_library::CImg rgb_img(img.width(), img.height(), img.depth(), 3); + cimg_forXYZ(img, x, y, z) { + rgb_img(x, y, z, 0) = img(x, y, z, 0); // R + rgb_img(x, y, z, 1) = img(x, y, z, 0); // G + rgb_img(x, y, z, 2) = img(x, y, z, 0); // B + } + img = rgb_img; + + } else if (current_channels == 3 && target_channels == 1) { + // RGB转灰度:使用标准公式 + img = img.get_channel(0) * 0.299f + + img.get_channel(1) * 0.587f + + img.get_channel(2) * 0.114f; + + } else if (current_channels == 4 && target_channels == 3) { + // RGBA转RGB:移除alpha通道 + img.channels(0, 2); + + } else if (current_channels > target_channels) { + // 保留前target_channels个通道 + img.channels(0, target_channels - 1); + + } else if (current_channels < target_channels) { + // 重复最后一个通道来补足 + int channels_to_add = target_channels - current_channels; + for (int i = 0; i < channels_to_add; i++) { + img.append(img.get_channel(current_channels - 1), 'c'); + } + } + } + + // 调整图像尺寸 + void resize_image(cimg_library::CImg& img) { + if (img.width() != target_width || img.height() != target_height) { + if (verbose) { + std::cout << "Resizing from " << img.width() << "x" << img.height() + << " to " << target_width << "x" << target_height << std::endl; + } + + // 使用CImg的resize函数 + img.resize(target_width, target_height, -100, -100, 3); // 3 = 三次样条插值 + } + } + + // 转换为浮点数 + std::vector convert_to_float(const cimg_library::CImg& img) { + std::vector float_data; + float_data.reserve(img.width() * img.height() * img.spectrum()); + + cimg_forC(img, c) { + cimg_forXY(img, x, y) { + float_data.push_back(static_cast(img(x, y, 0, c))); + } + } + + return float_data; + } + + // 重新排列维度为 [channels, height, width] + std::vector reorder_dimensions(const std::vector& data, + const cimg_library::CImg& img) { + int channels = img.spectrum(); + int height = img.height(); + int width = img.width(); + + std::vector reordered(channels * height * width); + + // CImg默认布局: [width, height, depth, spectrum] + // 我们需要: [channels, height, width] + for (int c = 0; c < channels; c++) { + for (int h = 0; h < height; h++) { + for (int w = 0; w < width; w++) { + // CImg索引: (x, y, z, c) = (w, h, 0, c) + int src_idx = c * (height * width) + h * width + w; + int dst_idx = c * (height * width) + h * width + w; + reordered[dst_idx] = data[src_idx]; + } + } + } + + return reordered; + } + + // 归一化到[0,1] + void normalize_0_1(std::vector& data) { + for (auto& val : data) { + val /= 255.0f; + } + } + + // 使用均值标准差归一化(逐通道) + void normalize_mean_std_channels(std::vector& data) { + int pixels_per_channel = target_height * target_width; + + for (int c = 0; c < target_channels; c++) { + float mean = auto_mean_std ? channel_means[c] : mean_val; + float std = auto_mean_std ? channel_stds[c] : std_val; + + for (int i = 0; i < pixels_per_channel; i++) { + int idx = c * pixels_per_channel + i; + data[idx] = (data[idx] - mean) / std; + } + } + } +}; \ No newline at end of file diff --git a/lci/include/nn/Matrix.hh b/lci/include/nn/Matrix.hh new file mode 100644 index 0000000..8367cbc --- /dev/null +++ b/lci/include/nn/Matrix.hh @@ -0,0 +1,64 @@ +/* + + ___col___ +/ \ ++---------+ \ +| + + + + | | row - 第一维度 +| + + + + | | ++---------+ / + +*/ + +#pragma once +#include +#include +#include +#include +#include "cn/中文化.hpp" +命名空间 qing { +模板 <类型名 T> +/* 矩阵类 - 二维向量 (FIXME: 1.增加函数广播方法。2.增加+=操作符等)。3. 增加初始化方法*/ +类 Matrx { +公开的: + Matrx(); + Matrx(常量 长型 row, 常量 长型 col); /* 该构造函数用于从头开始构造 */ + Matrx(常量 长型 row, 常量 长型 col, 常量 std::vector& src); /* 该构造函数用于通过已有的vector进行构造 */ + const T& get(long row, long col) const; /* 访问器 - 访问矩阵元素 */ + T& witch(long row, long col); /* 访问器 - 访问矩阵元素 */ + const std::vector& get_data() const; /* 访问器 - 用于获取原始数据 */ + const long get_col() const; /* 获取列数 */ + const long get_row() const; /* 获取行数 */ + bool has_same_shape(const Matrx& other); /* 两个矩阵是否具有相同形状 */ + bool has_dot_shape(const Matrx& other); /* 具有矩阵乘法的形状(标准:A的列数与B的行数相等) */ + void assert_same_shape(const Matrx& other); /* 断言两个矩阵具有相同形状 */ + void assert_dot_shape(const Matrx& other); /* 断言两个矩阵具有点积前置形状 */ + Matrx operator+(const Matrx& other); /* 加法操作符重定义 - 矩阵加法 */ + Matrx operator+(T& item); /* 矩阵加法广播 */ + Matrx operator-(const Matrx& other); /* 操作符重载 - 矩阵减法 */ + Matrx operator-(T& item); /* 操作符重载 - 矩阵减法广播 */ + const Matrx operator*(const Matrx& other); /* 操作符重载 - 矩阵乘法 */ + Matrx operator*(T& item); /* 操作符重载 - 矩阵乘法广播 */ + Matrx operator/(T& item); /* 操作符重载 - 矩阵除法广播 */ + + /* 储存矩阵 */ + void save(std::ostream& out) { + out << row << " " << col; /* 储存形状 */ + for (const auto& item: arr) { /* 储存数据 */ + out << " "; + out << item; + } + } + + /* FIXME: 不写load()方法的原因是使用工厂模式较为方便 */ + + /* FIXME: 增加矩阵转置操作 */ + + /* FIXME: 添加广播以使得矩阵与向量相乘 */ + + /* FIXME: 增加元素对应乘积 */ + +private: + long row, col; + std::vector arr; /* 存储矩阵的张量 */ +}; +} diff --git a/lci/include/nn/MatrixCuda.cuh b/lci/include/nn/MatrixCuda.cuh new file mode 100644 index 0000000..b85fa47 --- /dev/null +++ b/lci/include/nn/MatrixCuda.cuh @@ -0,0 +1,199 @@ +/* + * MatrixCuda.cuh - CUDA加速的矩阵运算库 + * + * 基于现有的Matrx类设计,提供GPU加速的矩阵运算 + * 支持float和double类型的矩阵运算 + * + * 注意:使用CUDA需要安装NVIDIA CUDA Toolkit + */ + +#pragma once + +#ifdef __CUDACC__ +#define CUDA_HOST_DEVICE __host__ __device__ +#define CUDA_HOST __host__ +#define CUDA_DEVICE __device__ +#else +#define CUDA_HOST_DEVICE +#define CUDA_HOST +#define CUDA_DEVICE +#endif + +#include +#include +#include +#include +#include +#include + +namespace qing { + +// 前向声明 +template +class MatrixCuda; + +// CUDA内核函数声明 +namespace cuda_kernels { + +// 矩阵加法内核 +template +__global__ void matrix_add_kernel(const T* A, const T* B, T* C, + long rows, long cols, long total_elements); + +// 矩阵减法内核 +template +__global__ void matrix_sub_kernel(const T* A, const T* B, T* C, + long rows, long cols, long total_elements); + +// 矩阵标量乘法内核 +template +__global__ void matrix_scalar_mul_kernel(const T* A, T scalar, T* C, + long total_elements); + +// 矩阵标量加法内核 +template +__global__ void matrix_scalar_add_kernel(const T* A, T scalar, T* C, + long total_elements); + +// 矩阵转置内核 +template +__global__ void matrix_transpose_kernel(const T* A, T* C, + long rows, long cols); + +// 矩阵元素对应乘积内核 +template +__global__ void matrix_hadamard_kernel(const T* A, const T* B, T* C, + long total_elements); + +// 矩阵复制内核 +template +__global__ void matrix_copy_kernel(const T* src, T* dst, long total_elements); + +} // namespace cuda_kernels + +/** + * @brief CUDA加速的矩阵类 + * + * 这个类提供了GPU加速的矩阵运算,包括: + * - 矩阵加法、减法 + * - 标量运算 + * - 矩阵转置 + * - 元素对应乘积 + * - 矩阵乘法(使用cuBLAS) + */ +template +class MatrixCuda { +public: + // 构造函数和析构函数 + CUDA_HOST MatrixCuda(); + CUDA_HOST MatrixCuda(long rows, long cols); + CUDA_HOST MatrixCuda(long rows, long cols, const std::vector& data); + CUDA_HOST MatrixCuda(const MatrixCuda& other); + CUDA_HOST MatrixCuda(MatrixCuda&& other) noexcept; + CUDA_HOST ~MatrixCuda(); + + // 赋值运算符 + CUDA_HOST MatrixCuda& operator=(const MatrixCuda& other); + CUDA_HOST MatrixCuda& operator=(MatrixCuda&& other) noexcept; + + // 内存管理 + CUDA_HOST void allocate_device_memory(); + CUDA_HOST void free_device_memory(); + CUDA_HOST void copy_to_device(); + CUDA_HOST void copy_from_device(); + CUDA_HOST void sync_device_to_host(); + CUDA_HOST void sync_host_to_device(); + + // 访问器 + CUDA_HOST_DEVICE long get_rows() const { return rows_; } + CUDA_HOST_DEVICE long get_cols() const { return cols_; } + CUDA_HOST_DEVICE long get_total_elements() const { return rows_ * cols_; } + + CUDA_HOST const std::vector& get_host_data() const { return host_data_; } + CUDA_HOST T* get_device_data() const { return device_data_; } + + CUDA_HOST T get_element(long row, long col) const; + CUDA_HOST void set_element(long row, long col, T value); + + // 形状检查 + CUDA_HOST bool has_same_shape(const MatrixCuda& other) const; + CUDA_HOST bool has_dot_shape(const MatrixCuda& other) const; + CUDA_HOST void assert_same_shape(const MatrixCuda& other) const; + CUDA_HOST void assert_dot_shape(const MatrixCuda& other) const; + + // 矩阵运算(GPU加速) + CUDA_HOST MatrixCuda add(const MatrixCuda& other) const; + CUDA_HOST MatrixCuda subtract(const MatrixCuda& other) const; + CUDA_HOST MatrixCuda multiply_scalar(T scalar) const; + CUDA_HOST MatrixCuda add_scalar(T scalar) const; + CUDA_HOST MatrixCuda transpose() const; + CUDA_HOST MatrixCuda hadamard_product(const MatrixCuda& other) const; + + // 运算符重载 + CUDA_HOST MatrixCuda operator+(const MatrixCuda& other) const; + CUDA_HOST MatrixCuda operator+(T scalar) const; + CUDA_HOST MatrixCuda operator-(const MatrixCuda& other) const; + CUDA_HOST MatrixCuda operator-(T scalar) const; + CUDA_HOST MatrixCuda operator*(T scalar) const; + CUDA_HOST MatrixCuda operator/(T scalar) const; + + // 复合赋值运算符 + CUDA_HOST MatrixCuda& operator+=(const MatrixCuda& other); + CUDA_HOST MatrixCuda& operator+=(T scalar); + CUDA_HOST MatrixCuda& operator-=(const MatrixCuda& other); + CUDA_HOST MatrixCuda& operator-=(T scalar); + CUDA_HOST MatrixCuda& operator*=(T scalar); + CUDA_HOST MatrixCuda& operator/=(T scalar); + + // 矩阵乘法(使用cuBLAS) + CUDA_HOST MatrixCuda matmul(const MatrixCuda& other) const; + CUDA_HOST MatrixCuda operator*(const MatrixCuda& other) const; + + // 工具函数 + CUDA_HOST void print(const std::string& name = "") const; + CUDA_HOST void fill(T value); + CUDA_HOST void fill_random(T min = 0, T max = 1); + CUDA_HOST bool is_valid() const; + + // 静态工厂方法 + CUDA_HOST static MatrixCuda zeros(long rows, long cols); + CUDA_HOST static MatrixCuda ones(long rows, long cols); + CUDA_HOST static MatrixCuda identity(long size); + CUDA_HOST static MatrixCuda random(long rows, long cols, T min = 0, T max = 1); + + // 从现有Matrx类转换 + CUDA_HOST static MatrixCuda from_matrx(const class Matrx& mat); + CUDA_HOST class Matrx to_matrx() const; + +private: + long rows_; + long cols_; + std::vector host_data_; // 主机内存数据 + T* device_data_; // 设备内存数据 + bool device_allocated_; // 设备内存是否已分配 + bool host_modified_; // 主机数据是否已修改 + bool device_modified_; // 设备数据是否已修改 + + // 私有辅助函数 + CUDA_HOST void check_index(long row, long col) const; + CUDA_HOST void initialize_from_vector(const std::vector& data); + + // CUDA错误检查 + CUDA_HOST static void check_cuda_error(cudaError_t error, const char* file, int line); + + // 计算线程块和网格大小 + CUDA_HOST static dim3 get_block_size(long total_elements); + CUDA_HOST static dim3 get_grid_size(long total_elements, dim3 block_size); +}; + +// CUDA错误检查宏 +#define CHECK_CUDA_ERROR(err) (MatrixCuda::check_cuda_error(err, __FILE__, __LINE__)) + +// 显式实例化声明 +extern template class MatrixCuda; +extern template class MatrixCuda; + +} // namespace qing + +// 包含内联实现 +#include "MatrixCuda.inl.cuh" \ No newline at end of file diff --git a/lci/include/nn/MatrixCuda.inl.cuh b/lci/include/nn/MatrixCuda.inl.cuh new file mode 100644 index 0000000..f34ff5c --- /dev/null +++ b/lci/include/nn/MatrixCuda.inl.cuh @@ -0,0 +1,739 @@ +/* + * MatrixCuda.inl.cuh - MatrixCuda类的内联实现 + * 包含CUDA内核函数和模板成员函数的实现 + */ + +#ifndef MATRIX_CUDA_INL_CUH +#define MATRIX_CUDA_INL_CUH + +#include "MatrixCuda.cuh" +#include +#include +#include + +namespace qing { + +// ============================================================================ +// CUDA内核函数实现 +// ============================================================================ + +namespace cuda_kernels { + +// 矩阵加法内核 +template +__global__ void matrix_add_kernel(const T* A, const T* B, T* C, + long rows, long cols, long total_elements) { + long idx = blockIdx.x * blockDim.x + threadIdx.x; + long stride = blockDim.x * gridDim.x; + + for (long i = idx; i < total_elements; i += stride) { + C[i] = A[i] + B[i]; + } +} + +// 矩阵减法内核 +template +__global__ void matrix_sub_kernel(const T* A, const T* B, T* C, + long rows, long cols, long total_elements) { + long idx = blockIdx.x * blockDim.x + threadIdx.x; + long stride = blockDim.x * gridDim.x; + + for (long i = idx; i < total_elements; i += stride) { + C[i] = A[i] - B[i]; + } +} + +// 矩阵标量乘法内核 +template +__global__ void matrix_scalar_mul_kernel(const T* A, T scalar, T* C, + long total_elements) { + long idx = blockIdx.x * blockDim.x + threadIdx.x; + long stride = blockDim.x * gridDim.x; + + for (long i = idx; i < total_elements; i += stride) { + C[i] = A[i] * scalar; + } +} + +// 矩阵标量加法内核 +template +__global__ void matrix_scalar_add_kernel(const T* A, T scalar, T* C, + long total_elements) { + long idx = blockIdx.x * blockDim.x + threadIdx.x; + long stride = blockDim.x * gridDim.x; + + for (long i = idx; i < total_elements; i += stride) { + C[i] = A[i] + scalar; + } +} + +// 矩阵转置内核 +template +__global__ void matrix_transpose_kernel(const T* A, T* C, + long rows, long cols) { + long row = blockIdx.y * blockDim.y + threadIdx.y; + long col = blockIdx.x * blockDim.x + threadIdx.x; + + if (row < rows && col < cols) { + // A[row, col] -> C[col, row] + C[col * rows + row] = A[row * cols + col]; + } +} + +// 矩阵元素对应乘积内核 +template +__global__ void matrix_hadamard_kernel(const T* A, const T* B, T* C, + long total_elements) { + long idx = blockIdx.x * blockDim.x + threadIdx.x; + long stride = blockDim.x * gridDim.x; + + for (long i = idx; i < total_elements; i += stride) { + C[i] = A[i] * B[i]; + } +} + +// 矩阵复制内核 +template +__global__ void matrix_copy_kernel(const T* src, T* dst, long total_elements) { + long idx = blockIdx.x * blockDim.x + threadIdx.x; + long stride = blockDim.x * gridDim.x; + + for (long i = idx; i < total_elements; i += stride) { + dst[i] = src[i]; + } +} + +} // namespace cuda_kernels + +// ============================================================================ +// MatrixCuda类成员函数实现 +// ============================================================================ + +// 构造函数和析构函数 +template +CUDA_HOST MatrixCuda::MatrixCuda() + : rows_(0), cols_(0), device_data_(nullptr), + device_allocated_(false), host_modified_(false), device_modified_(false) {} + +template +CUDA_HOST MatrixCuda::MatrixCuda(long rows, long cols) + : rows_(rows), cols_(cols), device_data_(nullptr), + device_allocated_(false), host_modified_(false), device_modified_(false) { + if (rows <= 0 || cols <= 0) { + throw std::invalid_argument("Matrix dimensions must be positive"); + } + host_data_.resize(rows * cols, T(0)); +} + +template +CUDA_HOST MatrixCuda::MatrixCuda(long rows, long cols, const std::vector& data) + : rows_(rows), cols_(cols), device_data_(nullptr), + device_allocated_(false), host_modified_(false), device_modified_(false) { + initialize_from_vector(data); +} + +template +CUDA_HOST MatrixCuda::MatrixCuda(const MatrixCuda& other) + : rows_(other.rows_), cols_(other.cols_), + host_data_(other.host_data_), device_data_(nullptr), + device_allocated_(false), host_modified_(other.host_modified_), + device_modified_(false) { + if (other.device_allocated_) { + allocate_device_memory(); + copy_to_device(); + } +} + +template +CUDA_HOST MatrixCuda::MatrixCuda(MatrixCuda&& other) noexcept + : rows_(other.rows_), cols_(other.cols_), + host_data_(std::move(other.host_data_)), + device_data_(other.device_data_), + device_allocated_(other.device_allocated_), + host_modified_(other.host_modified_), + device_modified_(other.device_modified_) { + other.rows_ = 0; + other.cols_ = 0; + other.device_data_ = nullptr; + other.device_allocated_ = false; + other.host_modified_ = false; + other.device_modified_ = false; +} + +template +CUDA_HOST MatrixCuda::~MatrixCuda() { + free_device_memory(); +} + +// 赋值运算符 +template +CUDA_HOST MatrixCuda& MatrixCuda::operator=(const MatrixCuda& other) { + if (this != &other) { + free_device_memory(); + + rows_ = other.rows_; + cols_ = other.cols_; + host_data_ = other.host_data_; + host_modified_ = other.host_modified_; + device_modified_ = false; + + if (other.device_allocated_) { + allocate_device_memory(); + copy_to_device(); + } + } + return *this; +} + +template +CUDA_HOST MatrixCuda& MatrixCuda::operator=(MatrixCuda&& other) noexcept { + if (this != &other) { + free_device_memory(); + + rows_ = other.rows_; + cols_ = other.cols_; + host_data_ = std::move(other.host_data_); + device_data_ = other.device_data_; + device_allocated_ = other.device_allocated_; + host_modified_ = other.host_modified_; + device_modified_ = other.device_modified_; + + other.rows_ = 0; + other.cols_ = 0; + other.device_data_ = nullptr; + other.device_allocated_ = false; + other.host_modified_ = false; + other.device_modified_ = false; + } + return *this; +} + +// 内存管理函数 +template +CUDA_HOST void MatrixCuda::allocate_device_memory() { + if (device_allocated_ || get_total_elements() == 0) { + return; + } + + cudaError_t err = cudaMalloc(&device_data_, get_total_elements() * sizeof(T)); + CHECK_CUDA_ERROR(err); + device_allocated_ = true; + device_modified_ = false; +} + +template +CUDA_HOST void MatrixCuda::free_device_memory() { + if (device_allocated_ && device_data_ != nullptr) { + cudaError_t err = cudaFree(device_data_); + CHECK_CUDA_ERROR(err); + device_data_ = nullptr; + device_allocated_ = false; + device_modified_ = false; + } +} + +template +CUDA_HOST void MatrixCuda::copy_to_device() { + if (!device_allocated_) { + allocate_device_memory(); + } + + if (host_modified_ && get_total_elements() > 0) { + cudaError_t err = cudaMemcpy(device_data_, host_data_.data(), + get_total_elements() * sizeof(T), + cudaMemcpyHostToDevice); + CHECK_CUDA_ERROR(err); + host_modified_ = false; + device_modified_ = true; + } +} + +template +CUDA_HOST void MatrixCuda::copy_from_device() { + if (device_allocated_ && device_modified_ && get_total_elements() > 0) { + cudaError_t err = cudaMemcpy(host_data_.data(), device_data_, + get_total_elements() * sizeof(T), + cudaMemcpyDeviceToHost); + CHECK_CUDA_ERROR(err); + device_modified_ = false; + host_modified_ = true; + } +} + +template +CUDA_HOST void MatrixCuda::sync_device_to_host() { + copy_from_device(); +} + +template +CUDA_HOST void MatrixCuda::sync_host_to_device() { + copy_to_device(); +} + +// 访问器函数 +template +CUDA_HOST T MatrixCuda::get_element(long row, long col) const { + check_index(row, col); + return host_data_[row * cols_ + col]; +} + +template +CUDA_HOST void MatrixCuda::set_element(long row, long col, T value) { + check_index(row, col); + host_data_[row * cols_ + col] = value; + host_modified_ = true; +} + +// 形状检查函数 +template +CUDA_HOST bool MatrixCuda::has_same_shape(const MatrixCuda& other) const { + return rows_ == other.rows_ && cols_ == other.cols_; +} + +template +CUDA_HOST bool MatrixCuda::has_dot_shape(const MatrixCuda& other) const { + return cols_ == other.rows_; +} + +template +CUDA_HOST void MatrixCuda::assert_same_shape(const MatrixCuda& other) const { + if (!has_same_shape(other)) { + throw std::invalid_argument("Matrices must have the same shape"); + } +} + +template +CUDA_HOST void MatrixCuda::assert_dot_shape(const MatrixCuda& other) const { + if (!has_dot_shape(other)) { + throw std::invalid_argument("Matrices cannot be multiplied: cols of first != rows of second"); + } +} + +// 矩阵运算函数 +template +CUDA_HOST MatrixCuda MatrixCuda::add(const MatrixCuda& other) const { + assert_same_shape(other); + + MatrixCuda result(rows_, cols_); + + // 确保数据在设备上 + sync_host_to_device(); + other.sync_host_to_device(); + result.allocate_device_memory(); + + // 设置CUDA内核参数 + long total_elements = get_total_elements(); + dim3 block_size = get_block_size(total_elements); + dim3 grid_size = get_grid_size(total_elements, block_size); + + // 启动内核 + cuda_kernels::matrix_add_kernel<<>>( + device_data_, other.device_data_, result.device_data_, + rows_, cols_, total_elements + ); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::subtract(const MatrixCuda& other) const { + assert_same_shape(other); + + MatrixCuda result(rows_, cols_); + + // 确保数据在设备上 + sync_host_to_device(); + other.sync_host_to_device(); + result.allocate_device_memory(); + + // 设置CUDA内核参数 + long total_elements = get_total_elements(); + dim3 block_size = get_block_size(total_elements); + dim3 grid_size = get_grid_size(total_elements, block_size); + + // 启动内核 + cuda_kernels::matrix_sub_kernel<<>>( + device_data_, other.device_data_, result.device_data_, + rows_, cols_, total_elements + ); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::multiply_scalar(T scalar) const { + MatrixCuda result(rows_, cols_); + + // 确保数据在设备上 + sync_host_to_device(); + result.allocate_device_memory(); + + // 设置CUDA内核参数 + long total_elements = get_total_elements(); + dim3 block_size = get_block_size(total_elements); + dim3 grid_size = get_grid_size(total_elements, block_size); + + // 启动内核 + cuda_kernels::matrix_scalar_mul_kernel<<>>( + device_data_, scalar, result.device_data_, total_elements + ); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::add_scalar(T scalar) const { + MatrixCuda result(rows_, cols_); + + // 确保数据在设备上 + sync_host_to_device(); + result.allocate_device_memory(); + + // 设置CUDA内核参数 + long total_elements = get_total_elements(); + dim3 block_size = get_block_size(total_elements); + dim3 grid_size = get_grid_size(total_elements, block_size); + + // 启动内核 + cuda_kernels::matrix_scalar_add_kernel<<>>( + device_data_, scalar, result.device_data_, total_elements + ); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::transpose() const { + MatrixCuda result(cols_, rows_); + + // 确保数据在设备上 + sync_host_to_device(); + result.allocate_device_memory(); + + // 设置CUDA内核参数(2D网格用于转置) + dim3 block_size(16, 16); + dim3 grid_size((cols_ + block_size.x - 1) / block_size.x, + (rows_ + block_size.y - 1) / block_size.y); + + // 启动转置内核 + cuda_kernels::matrix_transpose_kernel<<>>( + device_data_, result.device_data_, rows_, cols_ + ); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::hadamard_product(const MatrixCuda& other) const { + assert_same_shape(other); + + MatrixCuda result(rows_, cols_); + + // 确保数据在设备上 + sync_host_to_device(); + other.sync_host_to_device(); + result.allocate_device_memory(); + + // 设置CUDA内核参数 + long total_elements = get_total_elements(); + dim3 block_size = get_block_size(total_elements); + dim3 grid_size = get_grid_size(total_elements, block_size); + + // 启动内核 + cuda_kernels::matrix_hadamard_kernel<<>>( + device_data_, other.device_data_, result.device_data_, total_elements + ); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +// 运算符重载 +template +CUDA_HOST MatrixCuda MatrixCuda::operator+(const MatrixCuda& other) const { + return add(other); +} + +template +CUDA_HOST MatrixCuda MatrixCuda::operator+(T scalar) const { + return add_scalar(scalar); +} + +template +CUDA_HOST MatrixCuda MatrixCuda::operator-(const MatrixCuda& other) const { + return subtract(other); +} + +template +CUDA_HOST MatrixCuda MatrixCuda::operator-(T scalar) const { + return add_scalar(-scalar); +} + +template +CUDA_HOST MatrixCuda MatrixCuda::operator*(T scalar) const { + return multiply_scalar(scalar); +} + +template +CUDA_HOST MatrixCuda MatrixCuda::operator/(T scalar) const { + if (scalar == T(0)) { + throw std::invalid_argument("Division by zero"); + } + return multiply_scalar(T(1) / scalar); +} + +// 复合赋值运算符 +template +CUDA_HOST MatrixCuda& MatrixCuda::operator+=(const MatrixCuda& other) { + *this = *this + other; + return *this; +} + +template +CUDA_HOST MatrixCuda& MatrixCuda::operator+=(T scalar) { + *this = *this + scalar; + return *this; +} + +template +CUDA_HOST MatrixCuda& MatrixCuda::operator-=(const MatrixCuda& other) { + *this = *this - other; + return *this; +} + +template +CUDA_HOST MatrixCuda& MatrixCuda::operator-=(T scalar) { + *this = *this - scalar; + return *this; +} + +template +CUDA_HOST MatrixCuda& MatrixCuda::operator*=(T scalar) { + *this = *this * scalar; + return *this; +} + +template +CUDA_HOST MatrixCuda& MatrixCuda::operator/=(T scalar) { + *this = *this / scalar; + return *this; +} + +// 矩阵乘法(基础实现,使用朴素算法) +template +CUDA_HOST MatrixCuda MatrixCuda::matmul(const MatrixCuda& other) const { + assert_dot_shape(other); + + MatrixCuda result(rows_, other.cols_); + + // 同步数据到主机(使用朴素算法在主机上计算) + sync_device_to_host(); + other.sync_device_to_host(); + + // 朴素矩阵乘法(O(n³)) + for (long i = 0; i < rows_; ++i) { + for (long j = 0; j < other.cols_; ++j) { + T sum = T(0); + for (long k = 0; k < cols_; ++k) { + sum += get_element(i, k) * other.get_element(k, j); + } + result.set_element(i, j, sum); + } + } + + // 标记结果已修改 + result.host_modified_ = true; + result.sync_host_to_device(); + + return result; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::operator*(const MatrixCuda& other) const { + return matmul(other); +} + +// 工具函数 +template +CUDA_HOST void MatrixCuda::print(const std::string& name) const { + sync_device_to_host(); + + if (!name.empty()) { + std::cout << name << " (" << rows_ << "x" << cols_ << "):" << std::endl; + } else { + std::cout << "Matrix (" << rows_ << "x" << cols_ << "):" << std::endl; + } + + for (long i = 0; i < rows_; ++i) { + std::cout << " ["; + for (long j = 0; j < cols_; ++j) { + std::cout << get_element(i, j); + if (j < cols_ - 1) std::cout << ", "; + } + std::cout << "]" << std::endl; + } +} + +template +CUDA_HOST void MatrixCuda::fill(T value) { + std::fill(host_data_.begin(), host_data_.end(), value); + host_modified_ = true; +} + +template +CUDA_HOST void MatrixCuda::fill_random(T min, T max) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_real_distribution dist(min, max); + + for (auto& val : host_data_) { + val = dist(gen); + } + host_modified_ = true; +} + +template +CUDA_HOST bool MatrixCuda::is_valid() const { + return rows_ > 0 && cols_ > 0 && !host_data_.empty(); +} + +// 静态工厂方法 +template +CUDA_HOST MatrixCuda MatrixCuda::zeros(long rows, long cols) { + MatrixCuda mat(rows, cols); + mat.fill(T(0)); + return mat; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::ones(long rows, long cols) { + MatrixCuda mat(rows, cols); + mat.fill(T(1)); + return mat; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::identity(long size) { + MatrixCuda mat(size, size); + mat.fill(T(0)); + for (long i = 0; i < size; ++i) { + mat.set_element(i, i, T(1)); + } + return mat; +} + +template +CUDA_HOST MatrixCuda MatrixCuda::random(long rows, long cols, T min, T max) { + MatrixCuda mat(rows, cols); + mat.fill_random(min, max); + return mat; +} + +// 从现有Matrx类转换 +template +CUDA_HOST MatrixCuda MatrixCuda::from_matrx(const class Matrx& mat) { + // 注意:这里假设Matrx类有get_row(), get_col(), get_data()方法 + long rows = mat.get_row(); + long cols = mat.get_col(); + const std::vector& data = mat.get_data(); + + return MatrixCuda(rows, cols, data); +} + +template +CUDA_HOST class Matrx MatrixCuda::to_matrx() const { + sync_device_to_host(); + + // 注意:这里假设Matrx类有相应的构造函数 + // 实际实现可能需要根据Matrx类的具体接口调整 + return class Matrx(rows_, cols_, host_data_); +} + +// 私有辅助函数 +template +CUDA_HOST void MatrixCuda::check_index(long row, long col) const { + if (row < 0 || row >= rows_ || col < 0 || col >= cols_) { + throw std::out_of_range("Matrix index out of range"); + } +} + +template +CUDA_HOST void MatrixCuda::initialize_from_vector(const std::vector& data) { + if (data.size() != static_cast(rows_ * cols_)) { + throw std::invalid_argument("Data size does not match matrix dimensions"); + } + host_data_ = data; + host_modified_ = true; +} + +// CUDA错误检查 +template +CUDA_HOST void MatrixCuda::check_cuda_error(cudaError_t error, const char* file, int line) { + if (error != cudaSuccess) { + std::cerr << "CUDA error at " << file << ":" << line << ": " + << cudaGetErrorString(error) << std::endl; + throw std::runtime_error("CUDA error occurred"); + } +} + +// 计算线程块和网格大小 +template +CUDA_HOST dim3 MatrixCuda::get_block_size(long total_elements) { + // 使用256个线程的块(CUDA的典型值) + const long max_threads_per_block = 256; + long threads = std::min(total_elements, max_threads_per_block); + return dim3(threads, 1, 1); +} + +template +CUDA_HOST dim3 MatrixCuda::get_grid_size(long total_elements, dim3 block_size) { + // 计算需要的块数 + long blocks = (total_elements + block_size.x - 1) / block_size.x; + // 限制最大块数(避免过多块) + const long max_blocks = 65535; + blocks = std::min(blocks, max_blocks); + return dim3(blocks, 1, 1); +} + +// 显式实例化 +template class MatrixCuda; +template class MatrixCuda; + +} // namespace qing + +#endif // MATRIX_CUDA_INL_CUH \ No newline at end of file diff --git a/lci/include/nn/NNBuilder.hpp b/lci/include/nn/NNBuilder.hpp new file mode 100644 index 0000000..949b62a --- /dev/null +++ b/lci/include/nn/NNBuilder.hpp @@ -0,0 +1,67 @@ +#pragma once +#include +#include +#include "nn/NeuralNetwork.hpp" +namespace qing { +class NNBuilder { /* 神经网络构建 */ +public: + void add(NeuralNetwork &layer); + + /* 获取变换层的形状 + * FIXME: 这个函数有必要吗 */ + std::vector> get_shape() const; + + /* 向标准输出打印形状 */ + void print_shape() const; + + /* 向输出流储存模型 */ + void save(std::ostream& out) { + for (auto& layer: nn) { + layer.save(out); + } + } + + /* 从输入流加载模型 */ + void load(std::istream& in) { + nn.clear(); + while(true) { + try{ + auto layer = NeuralNetwork::Load_in_Factory(in); + add(layer); + } + catch (std::runtime_error& e) { + break; + } + } + } + + /* + * 将一层非线性层分裂为两层,相当于插入一层神经元 + */ + //void fork(int index, long num, float rate) { + + /* + * 神经网络生长,增加第layer层,每层增加num个神经元 + * + * layer: 增加的层数 + * num: 增加的神经元数量 + * + * FIXME: 神经网络生长时应当冻结其它层(除了最后一层?)(learning_rate == 0) + */ + //void grow(int layer, int num) { + + /* 前向反馈 */ + std::vector forward(std::vector& r); + + /* 反向传播 */ + std::vector backward(std::vector& errs, float discount = 1.0); + + /* 计算误差 */ + std::vector cal_err(std::vector& r, std::vector& t); + + + +private: + std::vector nn; +}; +} diff --git a/lci/include/nn/NeuralNetwork.hpp b/lci/include/nn/NeuralNetwork.hpp new file mode 100644 index 0000000..b7ca19c --- /dev/null +++ b/lci/include/nn/NeuralNetwork.hpp @@ -0,0 +1,149 @@ +#pragma once +#include +#include "nn/Matrix.hh" +#include "nn/ILayerFullyConnectted.hpp" + +namespace qing { + +/* 人工神经网络 - 全连接层 */ +class NeuralNetwork: public ILayerFullyConnectted { +public: + + /* 构造函数 使用基本参数构造 + * FIXME: 只能输入已经存在的向量 */ + NeuralNetwork( + const long inputno, const long outputno, + const std::vector &weights, + const std::vector &bias, + const float learning_rate, + const ActivationFunc func_type + ); + + + /* 获取激活函数枚举类型 */ + const ActivationFunc& get_f() const { + return f_type; + } + + /* 获取学习率 */ + const float& get_lr () const { + return learning_rate; + } + + /* + * 获取输入层大小 + * + * FIXME: 优化掉这两个访问器,通过直接返回矩阵,获取层的形状 + */ + long get_inputno() const; + + /* 获取输出层大小 */ + long get_outputno() const; + + + /* 获取权重矩阵 */ + Matrx& get_weights(); + + /* 获取偏置矩阵 */ + Matrx& get_bias(); + + + /* 正态分布Xavier初始化 */ + static void xavierNormalInit(std::vector &weights, long fan_in, long fan_out); + + /* 均匀分布Xavier初始化函数 */ + static void xavierUniformInit(std::vector &weights, int fan_in, int fan_out); + + /* 工厂模式 通过形状构建全连接层 */ + static NeuralNetwork Create_in_Factory(const long inputno, const long outputno, float learning_rate, ActivationFunc func_type); + + /* 工厂模式 通过输入流读形状构建 */ + static NeuralNetwork Load_in_Factory(std::istream& in) { + std::string f_name; + if (!(in >> f_name)) + throw std::runtime_error("read out of lines"); + float learning_rate; + in >> learning_rate; + /*------------------*/ + size_t row, col; + in >> row; /* FIXME: 如果是负数会怎样 */ + in >> col; + auto weis = load_vec(in, row * col); + size_t rowb, colb; + in >> rowb >> colb; /* FIXME: 如果这里读错了,也要抛出异常 */ + auto bias = load_vec(in, col); + auto layer = NeuralNetwork( + row, col, weis, bias, learning_rate, ILayer::parse_ff_type(f_name)); + /*------------------*/ + return layer; + } + + static std::vector load_vec(std::istream& in, size_t length) { + std::vector data; + for (size_t i = 0; i < length; ++i) { + float item; + in >> item; + data.push_back(item); + } + return data; + } + + + /* 前向反馈 */ + std::vector forward(const std::vector& x) override; + + /* 反向传播 */ + std::vector backward(const std::vector& errors) override; + + /* + * 更新权重 + * + * 可以输入一个折扣系数 + */ + void update(float discount = 1.0); + + /* + * 神经网络层长大 + * + * 重新初始化权重矩阵,使用均匀分布初始化 + * + * num: 增加的神经元数量 + * flag: true为增加输入层,false为增加输出层 + */ + //void grow(int num, bool flag) { + + /* 输出神经网络到输出流 */ + void save(std::ostream& out) override { + out << get_f_type(f_type) << " "; + out << learning_rate << " "; + weights.save(out); out << " "; + bias.save(out); out << "\n"; + } + + /* 从输入流加载模型 + * FIXME: 只能从工厂模式中构造 */ + //void load(std::istream& in) override + + +private: + + /* 神经网络层规格 */ + long inputno, outputno; + + /* 权重与偏置矩阵 */ + Matrx weights; /* (outputs, inputs) */ + Matrx bias; /* (1, outputs) */ + + /* 学习率 */ + float learning_rate; + + /* 激活函数 */ + ActivationFunc f_type; + + /* 存储在类内部的上一次的输入,输出,和激活前输出 */ + Matrx prev_inputs, prev_raw_inputs, prev_outputs; + /* 存储本次学习的权重梯度以及偏置梯度 */ + Matrx weights_grad, bias_grad; + +}; +} diff --git a/lci/include/nn/PoolingLayer.hpp b/lci/include/nn/PoolingLayer.hpp new file mode 100644 index 0000000..966635c --- /dev/null +++ b/lci/include/nn/PoolingLayer.hpp @@ -0,0 +1,502 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +class PoolingLayer { +private: + // 池化类型枚举 + enum class PoolType { + MAX, + AVG + }; + + // 参数 + int pool_height; + int pool_width; + int stride; + int padding; + PoolType pool_type; + + // 输入输出尺寸 + int input_channels; + int input_height; + int input_width; + int output_height; + int output_width; + + // 中间变量缓存(用于反向传播) + std::vector max_idx_cache; // 最大池化时缓存最大值位置 + std::vector input_cache; // 缓存的输入 + std::vector output_cache; // 缓存的输出 + + // 辅助函数 + //void max_pool_forward(const float* input, float* output, int batch_size); + //void avg_pool_forward(const float* input, float* output, int batch_size); + //void max_pool_backward(const float* grad_output, float* grad_input, int batch_size); + //void avg_pool_backward(const float* grad_output, float* grad_input, int batch_size); + +public: + // 构造函数 + PoolingLayer(int pool_size, int stride = 2, int padding = 0, bool max_pool = true) + : pool_height(pool_size), + pool_width(pool_size), + stride(stride), + padding(padding), + pool_type(max_pool ? PoolType::MAX : PoolType::AVG) {} + + // 带不同高度和宽度的构造函数 + PoolingLayer(int pool_height, int pool_width, int stride = 2, int padding = 0, bool max_pool = true) + : pool_height(pool_height), + pool_width(pool_width), + stride(stride), + padding(padding), + pool_type(max_pool ? PoolType::MAX : PoolType::AVG) {} + + // 设置输入尺寸 + void set_input_shape(int channels, int height, int width) { + input_channels = channels; + input_height = height; + input_width = width; + + // 计算输出尺寸 + output_height = (height + 2 * padding - pool_height) / stride + 1; + output_width = (width + 2 * padding - pool_width) / stride + 1; + + // 清空缓存 + max_idx_cache.clear(); + input_cache.clear(); + output_cache.clear(); + } + + // 前向传播 + std::vector forward(const std::vector& input, int batch_size = 1, bool training = true) { + // 计算输出大小 + int output_size = batch_size * input_channels * output_height * output_width; + std::vector output(output_size, 0.0f); + + // 如果训练模式,缓存输入 + if (training) { + input_cache = input; + } + + // 根据池化类型选择前向传播函数 + if (pool_type == PoolType::MAX) { + max_pool_forward(input.data(), output.data(), batch_size); + } else { + avg_pool_forward(input.data(), output.data(), batch_size); + } + + // 如果训练模式,缓存输出 + if (training) { + output_cache = output; + } + + return output; + } + + // 反向传播 + std::vector backward(const std::vector& grad_output, int batch_size = 1) { + // 创建输入梯度 + std::vector grad_input(batch_size * input_channels * input_height * input_width, 0.0f); + + // 根据池化类型选择反向传播函数 + if (pool_type == PoolType::MAX) { + max_pool_backward(grad_output.data(), grad_input.data(), batch_size); + } else { + avg_pool_backward(grad_output.data(), grad_input.data(), batch_size); + } + + return grad_input; + } + + // 获取输出尺寸 + std::tuple get_output_shape() const { + return std::make_tuple(input_channels, output_height, output_width); + } + + // 获取参数信息 + void print_info() const { + std::cout << "Pooling Layer Info:" << std::endl; + std::cout << " Type: " << (pool_type == PoolType::MAX ? "Max Pooling" : "Average Pooling") << std::endl; + std::cout << " Pool Size: " << pool_height << "x" << pool_width << std::endl; + std::cout << " Stride: " << stride << std::endl; + std::cout << " Padding: " << padding << std::endl; + std::cout << " Input Shape: " << input_channels << "x" << input_height << "x" << input_width << std::endl; + std::cout << " Output Shape: " << input_channels << "x" << output_height << "x" << output_width << std::endl; + } + +private: + // 最大池化前向传播实现 + void max_pool_forward(const float* input, float* output, int batch_size) { + // 计算填充后的尺寸 + int padded_height = input_height + 2 * padding; + int padded_width = input_width + 2 * padding; + + // 清空最大值位置缓存 + max_idx_cache.clear(); + max_idx_cache.resize(batch_size * input_channels * output_height * output_width, -1); + + // 对每个批次、每个通道进行处理 + for (int b = 0; b < batch_size; b++) { + for (int c = 0; c < input_channels; c++) { + // 当前通道的输入和输出指针 + const float* input_ptr = input + b * input_channels * input_height * input_width + + c * input_height * input_width; + float* output_ptr = output + b * input_channels * output_height * output_width + + c * output_height * output_width; + int* max_idx_ptr = max_idx_cache.data() + b * input_channels * output_height * output_width + + c * output_height * output_width; + + // 对每个输出位置进行计算 + for (int oh = 0; oh < output_height; oh++) { + for (int ow = 0; ow < output_width; ow++) { + // 计算池化窗口的起始位置 + int start_h = oh * stride - padding; + int start_w = ow * stride - padding; + + // 计算池化窗口的结束位置 + int end_h = std::min(start_h + pool_height, padded_height); + int end_w = std::min(start_w + pool_width, padded_width); + + // 调整起始位置,确保不超出边界 + start_h = std::max(start_h, 0); + start_w = std::max(start_w, 0); + + // 在池化窗口内寻找最大值 + float max_val = -std::numeric_limits::max(); + int max_idx = -1; + + for (int ph = start_h; ph < end_h; ph++) { + for (int pw = start_w; pw < end_w; pw++) { + // 计算原始输入中的索引(考虑填充) + int orig_ph = ph - padding; + int orig_pw = pw - padding; + + // 检查是否在有效范围内 + if (orig_ph >= 0 && orig_ph < input_height && + orig_pw >= 0 && orig_pw < input_width) { + int idx = orig_ph * input_width + orig_pw; + float val = input_ptr[idx]; + + if (val > max_val) { + max_val = val; + max_idx = idx; + } + } + } + } + + // 存储输出和最大值位置 + output_ptr[oh * output_width + ow] = max_val; + max_idx_ptr[oh * output_width + ow] = max_idx; + } + } + } + } + } + + // 平均池化前向传播实现 + void avg_pool_forward(const float* input, float* output, int batch_size) { + // 计算填充后的尺寸 + int padded_height = input_height + 2 * padding; + int padded_width = input_width + 2 * padding; + + // 对每个批次、每个通道进行处理 + for (int b = 0; b < batch_size; b++) { + for (int c = 0; c < input_channels; c++) { + // 当前通道的输入和输出指针 + const float* input_ptr = input + b * input_channels * input_height * input_width + + c * input_height * input_width; + float* output_ptr = output + b * input_channels * output_height * output_width + + c * output_height * output_width; + + // 对每个输出位置进行计算 + for (int oh = 0; oh < output_height; oh++) { + for (int ow = 0; ow < output_width; ow++) { + // 计算池化窗口的起始位置 + int start_h = oh * stride - padding; + int start_w = ow * stride - padding; + + // 计算池化窗口的结束位置 + int end_h = std::min(start_h + pool_height, padded_height); + int end_w = std::min(start_w + pool_width, padded_width); + + // 调整起始位置,确保不超出边界 + start_h = std::max(start_h, 0); + start_w = std::max(start_w, 0); + + // 在池化窗口内计算平均值 + float sum = 0.0f; + int count = 0; + + for (int ph = start_h; ph < end_h; ph++) { + for (int pw = start_w; pw < end_w; pw++) { + // 计算原始输入中的索引(考虑填充) + int orig_ph = ph - padding; + int orig_pw = pw - padding; + + // 检查是否在有效范围内 + if (orig_ph >= 0 && orig_ph < input_height && + orig_pw >= 0 && orig_pw < input_width) { + int idx = orig_ph * input_width + orig_pw; + sum += input_ptr[idx]; + count++; + } + } + } + + // 计算平均值 + output_ptr[oh * output_width + ow] = (count > 0) ? sum / count : 0.0f; + } + } + } + } + } + + // 最大池化反向传播实现 + void max_pool_backward(const float* grad_output, float* grad_input, int batch_size) { + // 初始化输入梯度为0 + std::memset(grad_input, 0, batch_size * input_channels * input_height * input_width * sizeof(float)); + + // 对每个批次、每个通道进行处理 + for (int b = 0; b < batch_size; b++) { + for (int c = 0; c < input_channels; c++) { + // 当前通道的梯度指针 + const float* grad_output_ptr = grad_output + b * input_channels * output_height * output_width + + c * output_height * output_width; + float* grad_input_ptr = grad_input + b * input_channels * input_height * input_width + + c * input_height * input_width; + const int* max_idx_ptr = max_idx_cache.data() + b * input_channels * output_height * output_width + + c * output_height * output_width; + + // 对每个输出位置进行反向传播 + for (int oh = 0; oh < output_height; oh++) { + for (int ow = 0; ow < output_width; ow++) { + // 获取最大值位置索引 + int max_idx = max_idx_ptr[oh * output_width + ow]; + + // 如果最大值位置有效,将梯度传递到该位置 + if (max_idx >= 0) { + grad_input_ptr[max_idx] += grad_output_ptr[oh * output_width + ow]; + } + } + } + } + } + } + + // 平均池化反向传播实现 + void avg_pool_backward(const float* grad_output, float* grad_input, int batch_size) { + // 初始化输入梯度为0 + std::memset(grad_input, 0, batch_size * input_channels * input_height * input_width * sizeof(float)); + + // 计算填充后的尺寸 + int padded_height = input_height + 2 * padding; + int padded_width = input_width + 2 * padding; + + // 对每个批次、每个通道进行处理 + for (int b = 0; b < batch_size; b++) { + for (int c = 0; c < input_channels; c++) { + // 当前通道的梯度指针 + const float* grad_output_ptr = grad_output + b * input_channels * output_height * output_width + + c * output_height * output_width; + float* grad_input_ptr = grad_input + b * input_channels * input_height * input_width + + c * input_height * input_width; + + // 对每个输出位置进行反向传播 + for (int oh = 0; oh < output_height; oh++) { + for (int ow = 0; ow < output_width; ow++) { + // 计算池化窗口的起始位置 + int start_h = oh * stride - padding; + int start_w = ow * stride - padding; + + // 计算池化窗口的结束位置 + int end_h = std::min(start_h + pool_height, padded_height); + int end_w = std::min(start_w + pool_width, padded_width); + + // 调整起始位置,确保不超出边界 + start_h = std::max(start_h, 0); + start_w = std::max(start_w, 0); + + // 计算有效池化窗口的大小 + int count = 0; + for (int ph = start_h; ph < end_h; ph++) { + for (int pw = start_w; pw < end_w; pw++) { + // 计算原始输入中的索引(考虑填充) + int orig_ph = ph - padding; + int orig_pw = pw - padding; + + // 检查是否在有效范围内 + if (orig_ph >= 0 && orig_ph < input_height && + orig_pw >= 0 && orig_pw < input_width) { + count++; + } + } + } + + // 如果池化窗口内有有效元素,计算平均梯度 + if (count > 0) { + float avg_grad = grad_output_ptr[oh * output_width + ow] / count; + + // 将平均梯度分配到池化窗口内的每个位置 + for (int ph = start_h; ph < end_h; ph++) { + for (int pw = start_w; pw < end_w; pw++) { + // 计算原始输入中的索引(考虑填充) + int orig_ph = ph - padding; + int orig_pw = pw - padding; + + // 检查是否在有效范围内 + if (orig_ph >= 0 && orig_ph < input_height && + orig_pw >= 0 && orig_pw < input_width) { + int idx = orig_ph * input_width + orig_pw; + grad_input_ptr[idx] += avg_grad; + } + } + } + } + } + } + } + } + } +}; + +// 使用示例函数 +inline void pooling_layer_example() { + std::cout << "=== Pooling Layer Example ===" << std::endl; + + // 创建最大池化层 + PoolingLayer max_pool(2, 2, 0, true); // 2x2 最大池化,步长2,无填充 + max_pool.set_input_shape(3, 4, 4); // 3个通道,4x4输入 + + // 创建输入数据 + std::vector input(3 * 4 * 4); + for (int i = 0; i < 3 * 4 * 4; i++) { + input[i] = static_cast(i) / 10.0f; + } + + // 前向传播 + std::cout << "Forward pass..." << std::endl; + auto output = max_pool.forward(input, 1, true); + + // 获取输出形状 + auto [channels, height, width] = max_pool.get_output_shape(); + std::cout << "Output shape: " << channels << "x" << height << "x" << width << std::endl; + + // 打印输出 + std::cout << "Output values (first 10): "; + for (int i = 0; i < std::min(10, static_cast(output.size())); i++) { + std::cout << output[i] << " "; + } + std::cout << std::endl; + + // 创建梯度(假设全为1) + std::vector grad_output(output.size(), 1.0f); + + // 反向传播 + std::cout << "Backward pass..." << std::endl; + auto grad_input = max_pool.backward(grad_output, 1); + + std::cout << "Gradient input size: " << grad_input.size() << std::endl; + std::cout << "Gradient input values (first 10): "; + for (int i = 0; i < std::min(10, static_cast(grad_input.size())); i++) { + std::cout << grad_input[i] << " "; + } + std::cout << std::endl; + + // 打印层信息 + max_pool.print_info(); +} + +// 全局平均池化层(常用于CNN分类网络的最后) +class GlobalAveragePooling { +private: + int input_channels; + int input_height; + int input_width; + std::vector input_cache; + +public: + // 设置输入尺寸 + void set_input_shape(int channels, int height, int width) { + input_channels = channels; + input_height = height; + input_width = width; + } + + // 前向传播 + std::vector forward(const std::vector& input, int batch_size = 1, bool training = true) { + // 缓存输入(如果需要) + if (training) { + input_cache = input; + } + + // 计算输出大小:每个通道一个值 + int output_size = batch_size * input_channels; + std::vector output(output_size, 0.0f); + + // 对每个批次、每个通道计算平均值 + int spatial_size = input_height * input_width; + for (int b = 0; b < batch_size; b++) { + for (int c = 0; c < input_channels; c++) { + const float* input_ptr = input.data() + b * input_channels * spatial_size + c * spatial_size; + float sum = 0.0f; + + // 计算该通道所有空间位置的平均值 + for (int i = 0; i < spatial_size; i++) { + sum += input_ptr[i]; + } + + output[b * input_channels + c] = sum / spatial_size; + } + } + + return output; + } + + // 反向传播 + std::vector backward(const std::vector& grad_output, int batch_size = 1) { + // 创建输入梯度 + int spatial_size = input_height * input_width; + std::vector grad_input(batch_size * input_channels * spatial_size, 0.0f); + + // 对每个批次、每个通道分配梯度 + for (int b = 0; b < batch_size; b++) { + for (int c = 0; c < input_channels; c++) { + float grad = grad_output[b * input_channels + c] / spatial_size; + float* grad_input_ptr = grad_input.data() + b * input_channels * spatial_size + c * spatial_size; + + // 将梯度均匀分配到所有空间位置 + for (int i = 0; i < spatial_size; i++) { + grad_input_ptr[i] = grad; + } + } + } + + return grad_input; + } + + // 获取输出尺寸 + std::tuple get_output_shape() const { + return std::make_tuple(input_channels, 1); + } +}; + +/* + +// 创建池化层 +PoolingLayer pool(2, 2, 0, true); // 2x2最大池化,步长2,无填充 +pool.set_input_shape(64, 28, 28); // 64通道,28x28输入 + +// 前向传播 +auto output = pool.forward(input, batch_size, true); + +// 反向传播 +auto grad_input = pool.backward(grad_output, batch_size); + +*/ \ No newline at end of file diff --git a/lci/include/pmc/Modules.hpp b/lci/include/pmc/Modules.hpp new file mode 100644 index 0000000..dcfa83f --- /dev/null +++ b/lci/include/pmc/Modules.hpp @@ -0,0 +1,229 @@ +#pragma once +#include +#include +#include +#include +#include +namespace qing { +/* 子系统类 */ +class Modules { +public: + /* 传入子系统的路径 然后验证是否存在 */ + Modules(std::string& mods) { + this->home = mods; + if (!is_exist(this->home)) + throw SubsystemNotExist(mods); + } + + /* + * 获取子系统下某个模块的启动脚本路径 + * + * NOTE: 防注入检查是必须的 + */ + std::string GetInitp(std::string name) { + std::string ret = get_mod_init_path(name); + if (is_exist(ret)) { + return ret; + } + else { + throw InitScriptNotExist(ret); + } + } + + /* + * 列出子系统下的所有模块 + * + * 优化建议:做抽象层表示模块概念 + */ + std::vector ListAll() { + std::vector folders; + try { + for (const auto& entry: std::filesystem::directory_iterator(this->home)) + if (entry.is_directory()) + folders.push_back(entry.path().filename().string()); + } + catch(const std::filesystem::filesystem_error& e) { + ListModulesFailed(this->home, e.what()); + } + return folders; + } + + /* 在该子系统下创建一个初始模块 */ + void CrtMod(std::string &name) { + crt_mod_dir(name); + init_mod_dir(name); + init_mod_man(name); + grd_priv(name); + } + + /* 删除子系统下一个模块 */ + void DelMod(std::string &name) { + std::string fullpath = get_mod_path(name); + deleteDirectory(fullpath); + } + + /* 子系统异常模块 */ + class Mods_Exp: public std::runtime_error { + public: + explicit Mods_Exp(const std::string& msg): std::runtime_error(msg) { + ; + } + }; + + /* 子系统不存在异常 */ + class SubsystemNotExist: public Mods_Exp { + public: + explicit SubsystemNotExist(const std::string &name): Mods_Exp("Target subsystem " + name + " not exists.") { + ; + } + }; + + /* 启动脚本不存在异常 */ + class InitScriptNotExist: public Mods_Exp { + public: + explicit InitScriptNotExist(const std::string &name): Mods_Exp("Target init script " + name + " not exists") { + ; + } + }; + + /* 列举模块失败异常 */ + class ListModulesFailed: public Mods_Exp { + public: + explicit ListModulesFailed(const std::string &name, const std::string &reson): Mods_Exp("Error when read subsystem <" + name + "> , because " + reson) { + ; + } + }; + + /* 要创建的路径已经存在 */ + class AlreadyExist: public Mods_Exp { + public: + explicit AlreadyExist(const std::string &name): Mods_Exp(name) { + ; + } + }; + + /* 创建失败 */ + class CreateFailed: public Mods_Exp { + public: + explicit CreateFailed(const std::string &name): Mods_Exp(name) { + ; + } + }; + + /* 提升权限失败 */ + class GrandPrivilegesFailed: public Mods_Exp { + public: + explicit GrandPrivilegesFailed(const std::string &name): Mods_Exp(name) { + ; + } + }; + + /* 删除失败 */ + class DeleteFailed: public Mods_Exp { + public: + explicit DeleteFailed(const std::string &name): Mods_Exp(name) { + ; + } + }; + +private: + + /* 子系统的模块目录 */ + std::string home; + + /* 创建模块目录*/ + void crt_mod_dir(std::string name) { + std::string fullpath = get_mod_path(name); + if (is_exist(fullpath)) { + throw AlreadyExist(name); + } else { + std::filesystem::create_directory(fullpath); + } + } + + /* 初始化模块目录,创建启动脚本 */ + void init_mod_dir(std::string name) { + std::string fullpath = get_mod_init_path(name); + if (is_exist(fullpath)) { + throw AlreadyExist(name); + } + else { + std::ofstream outFile = std::ofstream(fullpath); + if (outFile) { + outFile << "#!/bin/bash\n"; + outFile << "cd \"$(dirname \"$0\")\" || exit\n\n"; + outFile << "exec echo hello!"; + } else { + throw CreateFailed(name); + } + } + } + + /* 初始化一个模块的手册(README.md)*/ + void init_mod_man(std::string name) { + std::string fullpath = get_mod_man_path(name); + if(is_exist(fullpath)) { + throw AlreadyExist(fullpath); + } + else { + std::ofstream outFile = std::ofstream(fullpath); + if (outFile) { + outFile << "# "; + outFile << name; + outFile << "\n"; + } else { + throw CreateFailed(name); + } + } + } + + /* 获取模块的路径 */ + std::string get_mod_path(std::string &name) { + return this->home + get_sep() + name; + } + + /* 获取模块的启动脚本路径 */ + std::string get_mod_init_path(std::string &name) { + return get_mod_path(name) + get_sep()+ "_run.sh"; + } + + /* 获取模块的手册路径 */ + std::string get_mod_man_path(std::string &name) { + return get_mod_path(name) + get_sep()+ "README.md"; + } + + /* 赋予一个文件755权限 */ + void grd_priv(std::string &name) { + std::string fullpath = get_mod_init_path(name); + if (chmod(fullpath.c_str(), 0755) == -1) { + throw GrandPrivilegesFailed("path"); + } + } + + /* 获取当前可执行程序所在目录 */ + static std::string get_curr() { + return std::filesystem::canonical("/proc/self/exe").parent_path().string(); + } + + /* 文件是否存在 */ + static bool is_exist(std::string &path) { + return std::filesystem::exists(path); + } + + /* 获取文件系统分隔符号 */ + static char get_sep() { + return std::filesystem::path::preferred_separator; + } + + /* 删除一整个文件夹 */ + static void deleteDirectory(const std::filesystem::path& path) { + try { /* 递归 */ + std::filesystem::remove_all(path) > 0; + } + catch (const std::filesystem::filesystem_error& e) { + throw DeleteFailed(e.what()); + } + } + +}; +} diff --git a/lci/include/th/Cv_wait.hpp b/lci/include/th/Cv_wait.hpp new file mode 100644 index 0000000..40886f6 --- /dev/null +++ b/lci/include/th/Cv_wait.hpp @@ -0,0 +1,38 @@ +/* + * 利用条件变量进行等待 + * + * FIXME: deepseek 认为有一个设计缺陷:它只能用于单次等待-唤醒的场景。 + * FIXME: 可能导致永久堵塞,应使用带超时的等待 + * FIXME: 使用标准库的 future/promise + */ + +#include +#include /* 也许将字段flag创建为原子变量 */ +#include +#include +namespace qing { +class Cv_wait { /* 用于等待的条件变量类,对同一个对象进行操作能够阻塞当前线程,或者唤醒被阻塞的线程 */ +private: + std::mutex mtx{}; /* 用于控制条件变量的锁 */ + std::condition_variable cv{}; + bool flag = false; /* 用于解锁条件变量的标志 */ +public: + + inline void Wait() /* 线程进入等待 */ + { + auto lock = std::unique_lock(mtx); + flag = false; + cv.wait(lock, [this] { return flag; }); + } + + inline void WakeCv() /* 唤醒线程 */ + { + { + std::lock_guard lcok(mtx); + flag = true; + } + cv.notify_all(); + } + +}; +} diff --git a/lci/include/th/Fsm.hpp b/lci/include/th/Fsm.hpp new file mode 100644 index 0000000..7e9cb28 --- /dev/null +++ b/lci/include/th/Fsm.hpp @@ -0,0 +1,75 @@ +/* + * 有限状态机(Finite State Machine,FSM) + */ + +#pragma once +#include /*上锁 使得有限状态机线程安全*/ +#include /*条件变量,使得子类能够等待状态的设置*/ +namespace qing { +/* +* FiniteStateMachine有限状态机 +* +* 每个数字代表一个状态 使用static_cast<>()之类的函数去赋值 +* FIXME: 之前用过一种使用回调函数处理的方式 +*/ +class Fsm { +public: + + /* 状态枚举类 */ + enum class Stat: int { + SHUT = -1, /* 关闭 */ + STOP = 0, /* 静止 */ + START = 1, /* 启动 */ + RUNNING = 2 /* 运行 */ + /* ... */ + };/*Stat*/ + + + /* 以STOP为初始状态 */ + Fsm() { set(Stat::STOP); } + + enum Stat check() { /* 检查当前的状态 */ + std::lock_guard lk(mtx); + return stat; + } /*check*/ + + + /* + * 在不上锁的情况下设置一个状态 + * 这里不能使用锁,因为我们还要在临界区里唤醒条件变量 + */ + void set_without_lock(Stat stat) { this->stat = stat; } + + /* 带锁的状态设置 但是该方法不唤醒条件变量 */ + void set_without_notify(Stat stat) { + std::lock_guard lk(mtx); + this->stat = stat; + } + + /* 带锁和条件唤醒的状态设置 */ + void set(Stat stat) { + { + std::lock_guard lk(mtx); + set_without_lock(stat); + ready = true; + } + cv.notify_all(); + } + +//protected: + + void suspend() { /* 阻塞线程,等待事件唤醒 */ + std::unique_lock lk(mtx); + ready = false; + cv.wait(lk, [this] { return ready; }); + }/*suspend */ + +private: + std::mutex mtx; /* 线程安全 */ + bool ready = false; /* 用于条件变量的阻塞唤醒 */ + std::condition_variable cv; /* 条件变量 阻塞/唤醒线程 */ + enum Stat stat; /* 状态机的状态变量 */ + +};//Fsm + +}//qing diff --git a/lci/include/th/ITask.hpp b/lci/include/th/ITask.hpp new file mode 100644 index 0000000..95b7616 --- /dev/null +++ b/lci/include/th/ITask.hpp @@ -0,0 +1,9 @@ +#pragma once +namespace qing{ +class ITask { /* 单个任务通用接口 */ +public: + virtual void start() = 0; /* 任务开始 */ + virtual void stop() = 0; /* 任务结束 */ + virtual bool isRunning() = 0; /* 是否在跑 */ +}; +} diff --git a/lci/include/th/Thread.hpp b/lci/include/th/Thread.hpp new file mode 100644 index 0000000..06ad6cb --- /dev/null +++ b/lci/include/th/Thread.hpp @@ -0,0 +1,183 @@ +/* 线程 + * + * + * 包含一个简易的多线程控制机制,需要共享的变量和函数声明为成员。 + * + * 线程主函数包括了流程控制,要使用需要实现其中的各个事件方法 + * + * 20250621: 从派生改为持有 + * + * NOTE: 在对象构造完之后应该激活 + */ + +#pragma once +#include +#include /* 内存管理 */ +#include /* 用于线程休息 */ +#include +#include +#include +#include "th/Fsm.hpp" /* 有限状态机 */ +namespace qing { +class Thread; +//using f_t = void(*)(Thread&); +using f_t = std::function; +class Thread { +public: + + /* 作为可变的函数,持有回调可能比继承更好 */ + Thread(f_t stop_callback, f_t wake_callback, f_t loop_callback, f_t clear_callback); + + /* + * 删除复制构造函数。 + * + * 因为持有线程类,不要轻举妄动。 + */ + Thread(const Thread&) = delete; + + + /* + * 虚析构函数 + * + * FIXME: 具体有什么用,忘了 + */ + virtual ~Thread() {} + + /*-----------------------------------*/ + /*-----------------------------------*/ + /* + * 检查状态的方法 + * + * NOTE: 做成虚函数,万一子类有特别要求呢 + * + * FIXME: 将检查器和变异器做成一个简单的回调函数 + */ + virtual Fsm::Stat check() { + return fsm.check(); + } + + /*-----------------------------------*/ + /*-----------------------------------*/ + /* 让线程能够阻塞直到新的状态被赋予的方法 */ + inline void suspend() { + fsm.suspend(); + } + + /*-----------------------------------*/ + /*-----------------------------------*/ + /* 状态改变的方法 - 变异器 */ + + /* + * 进入唤醒状态 + * + * 唤醒函数不可以进行该类中的锁操作,否则会造成死锁 + */ + virtual void wake() { + //{ + //std::lock_guard lk(mtx_th); + fsm.set(Fsm::Stat::START); + //ready = true; + //} + //cv.notify_all(); + } /* wake */ + + /* 进入静止状态 + * + * 上锁、唤醒阻塞的线程 + */ + virtual void stop() { + { + std::lock_guard lk(mtx_th); + fsm.set(Fsm::Stat::STOP); + ready = true; + } + /* 可能会出现多个线程在等待的情况 */ + cv.notify_all(); + }/* stop */ + + /* 进入关闭状态 */ + virtual void shut() { + { + std::lock_guard lk(mtx_th); + fsm.set(Fsm::Stat::SHUT); + ready = true; + } + cv.notify_all(); + } /*shut*/ + + /* 进入运行状态 */ + virtual void run() { + { + std::lock_guard lk(mtx_th); + fsm.set(Fsm::Stat::RUNNING); + ready = true; + } + cv.notify_all(); + }/*run*/ + + /*-----------------------------------*/ + /*-----------------------------------*/ + + /* + * 激活线程,申请线程对象 + * + * 该函数不能放在构造函数内,因为需要确保对象已经被构造了 + */ + void Activate() { + + /* 防止重复初始化 + * FIXME: 抛出异常?感觉也不太合适 */ + if (th) return; + + /* 申请线程资源 */ + th = std::make_unique(&Thread::main, this); + + } + + /* + * 尝试唤醒线程并等待它开始 据说该函数有问题可能导致异常 + */ + void WaitStart() { + std::unique_lock lk(mtx_th); /* 不进入临界区可能会造成死等,在唤醒过程非常短暂的情况下 */ + wake(); /* 这就是为什么wake()不可以获取临界区,否则会造成死锁 */ + ready = false; /* 这个临界区结束后,WakeEvent()中的run()会唤醒线程的堵塞 */ + cv.wait(lk, [this] { return ready; }); + } + + /* 等待线程关闭 */ + void WaitClose() { + shut(); + if (th->joinable()) + th->join(); + } + + /*-----------------------------------*/ + /* 线程主函数 */ + void main(); + +private: + + qing::Fsm fsm{}; /* 持有状态机类型 */ + + std::unique_ptr th; /* 持有线程类型 */ + + std::mutex mtx_th; /* 持有锁类型 */ + + /* + * 这里持有一个条件变量,用于阻塞以等待线程的关闭 + * + * 注意状态机中的cv是另一个变量 + */ + std::condition_variable cv; + + /* 辅助条件变量的逻辑型 */ + bool ready; + + /* 事件回调 */ + std::unique_ptr StopEvent; + std::unique_ptr WakeEvent; + std::unique_ptr LoopEvent; + std::unique_ptr ClearEvent; + +}; +} diff --git a/lci/include/tt/Mq.h b/lci/include/tt/Mq.h new file mode 100644 index 0000000..644a354 --- /dev/null +++ b/lci/include/tt/Mq.h @@ -0,0 +1,93 @@ +/* + * 目前是Message Queue 的发送端(不涉及创建消息队列) + * + * FIXME: 集成发送、接收和创建 + */ + +#pragma once +#include +#include +#include +#include + +namespace qing { +namespace bip = boost::interprocess; +using sf_t = std::function; /* success */ +using ef_t = std::function; /* error */ +class Mq { +public: + enum {CREATOR=0, USER=1}; + Mq(const std::string& name, int msglen, size_t msgcnt, int mode = USER) { + this->name = std::string("/") + name; + this->msglen = msglen; + this->msgcnt = msgcnt; + this->mode = mode; + switch (mode) { + case USER: + mqp = std::make_unique(bip::open_only, this->name.c_str()); + break; + case CREATOR: /* 由创建者创建消息队列 */ + bip::message_queue::remove(this->name.c_str()); + mqp = std::make_unique( + bip::create_only, this->name.c_str(), + msgcnt, msglen * sizeof(char) + ); + break; + } + } + + /* 创建者负责清理 */ + ~Mq() { + if (mode == CREATOR) + bip::message_queue::remove(name.c_str()); + } + + /* */ + Mq(const Mq&) = delete; + Mq& operator=(const Mq&) = delete; + + + /* 发送消息 */ + void send(std::string &msg) + { + if (msg.size() + 1 > msglen) /* over the len */ + throw std::length_error("Message queue Send Length over"); + + mqp->send(msg.c_str(), msg.size() + 1, 0); /* include \0 */ + } + + /* 尝试接收消息 */ + void recv(sf_t success, ef_t notyet) { + + auto data = std::make_unique(msglen); /* 接收缓冲区 */ + unsigned int priority; /* 优先级 */ + bip::message_queue::size_type recvd_size; + + try { /* try_receive()返回bool类型 */ + auto r = mqp->try_receive( + data.get(), msglen*sizeof(char), + recvd_size, priority + ); + + if (r) /* 成功接收到数据 */ + success(data.get()); + + else /* 没有收到数据 */ + notyet(); + } + + catch (std::exception &exp) { + std::cerr << "exception type: " << typeid(exp).name() << std::endl; + std::cerr << "exception message: " << exp.what() << std::endl; + } + } + +private: + + /* */ + std::unique_ptr mqp; + std::string name; + size_t msglen=0, msgcnt=0; + int mode; +}; +} diff --git a/lci/include/tt/Pipe.h b/lci/include/tt/Pipe.h new file mode 100644 index 0000000..89f2de8 --- /dev/null +++ b/lci/include/tt/Pipe.h @@ -0,0 +1,155 @@ +#pragma once +#include +#include +#include +#include /* open() */ +#include /* mkfifo() */ +#include + +namespace qing { +class Pipe{ /* 20260309(qing): 该类不会抛出异常 */ +public: + static const int CREATOR = 1; + static const int USER =2; + static const ssize_t PIPE_MAX_LEN = 2048; + Pipe(const std::string& path, int mode) + : fd(-1), isCreator(mode == CREATOR) { + std::string real_path = "/tmp/pst-"; + real_path += path; + fifo_path = real_path; + if (isCreator && mkfifo(fifo_path.c_str(), 0666) == -1 && errno != EEXIST) /* wr_wr_wr */ + perror("mkfifo"); /* 文件已存在是正常情况,其他错误才需要处理 */ + } + + ~Pipe() { + /* 如果打开了文件,则关闭文件 */ + if (fd != -1) close(fd); + /**********************/ + /* 如果管道由该对象创建,就要负责清理 */ + if (isCreator) unlink(fifo_path.c_str()); /* 创建者负责清理 */ + } + Pipe(const Pipe&) = delete; + Pipe& operator=(const Pipe&) = delete; + + /* 这里才是打开文件的指令 - 以读模式打开,可以非阻塞 */ + bool openForRead(bool nonblock = false) { + + /* 设置是否以非阻塞方式打开文件 */ + int flags = O_RDONLY; + if (nonblock) { + flags |= O_NONBLOCK; + } + + fd = open(fifo_path.c_str(), flags); + + if (fd == -1) { + perror("open for read"); + return false; + } + + else { + FD_ZERO(&read_fds); + FD_SET(fd, &read_fds); + if (fd > max_fd) max_fd = fd; + return true; + } + + } + + /* 以写模式打开文件 */ + bool openForWrite(/*bool nonblock = falsei*/) { + + /* 写入管道是不需要阻塞/非阻塞的? */ + int flags = O_WRONLY; + //if (nonblock) { + // flags |= O_NONBLOCK; + //} + fd = open(fifo_path.c_str(), flags); + if (fd == -1) { + perror("open for write"); + return false; + } + + else { + FD_ZERO(&write_fds); + FD_SET(fd, &write_fds); + if (fd > max_fd) max_fd = fd; + return true; + } + + } + + /* 写入管道,如果失败返回-1。成功返回写入的字符数。 */ + ssize_t writePipe(const std::string &data) { + if (fd == -1) { + std::cerr << "Pipe not opened for writing" << std::endl; + return -1; + } + else { + return write(fd, data.c_str(), data.size()); + } + } + + /* 将探测与读取解耦,使用者可以自行决定要不要阻塞 */ + bool waitForRead(int timeout_sec = 0, int timeout_usec = 0) { + + /* 如果文件没打开,等待是失败的 */ + if (fd == -1) return false; + + fd_set temp_fds = read_fds; + struct timeval timeout = {timeout_sec, timeout_usec}; + + int ret = select(max_fd + 1, &temp_fds, nullptr, nullptr, &timeout); + + if (ret == -1) { + perror("select"); + return false; + } + + else { + return ret > 0 && FD_ISSET(fd, &temp_fds); + } + } + + /* 读取数据到字符串,返回实际读取的字节数 */ + ssize_t readPipe(std::string *output) { + + if (fd == -1) { + std::cerr << "Pipe not opened for reading" << std::endl; + return -1; + } + + else + + { + + char buffer[PIPE_MAX_LEN]; + ssize_t n = read(fd, buffer, sizeof(buffer) - 1); + if (n >0) { + buffer[n] = '\0'; + *output = buffer; + } + + else if (n == 0) { + /* 管道写入端关闭 */ + *output = ""; + } + + else { + perror("read"); + } + + return n; + + } + } +private: + std::string fifo_path; + int fd; + bool isCreator; + fd_set read_fds; + fd_set write_fds; + fd_set except_fds; + int max_fd; +}; +} diff --git a/lci/init.txt b/lci/init.txt new file mode 100644 index 0000000..e9a89fa --- /dev/null +++ b/lci/init.txt @@ -0,0 +1,2 @@ +sleep 1000 +sleep 1000 diff --git a/lci/pmcd.service b/lci/pmcd.service new file mode 100644 index 0000000..50eddad --- /dev/null +++ b/lci/pmcd.service @@ -0,0 +1,10 @@ +[Unit] +Description=PMC Http Interfaces +After=network.target + +[Service] +User=qing +Group=qing +ExecStart=pmc -i /etc/pmc/init.txt --serve 5200 +[Install] +WantedBy=multi-user.target diff --git a/lci/src/facerec.py b/lci/src/facerec.py new file mode 100644 index 0000000..5aa25e2 --- /dev/null +++ b/lci/src/facerec.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +""" +扩展技能:人脸位置检测工具 +用于检测图像中的人脸并保存人脸位置坐标(百分比格式)到txt文件 +放置在 ~/.aibox/skills/face_position_detector.py +""" + +import os +import sys +import json +import argparse +import cv2 +import face_recognition +import numpy as np +from datetime import datetime +from typing import List, Optional + + +class FacePositionDetector: + """人脸位置检测工具(检测位置坐标并转换为百分比)""" + + def __init__(self): + # 不再使用.aibox文件夹,使用当前目录 + pass + + def _ensure_dirs(self, dir_path: str): + """确保目录存在""" + os.makedirs(dir_path, exist_ok=True) + + def detect_faces(self, image_path: str, save_coords: bool = True, output_file: Optional[str] = None) -> str: + """ + 检测图像中的人脸并保存位置坐标(百分比格式)到txt文件 + """ + try: + if not os.path.exists(image_path): + return f"❌ 错误:文件不存在 - {image_path}" + + # 使用OpenCV获取图像尺寸 + img_cv = cv2.imread(image_path) + if img_cv is None: + return f"❌ 错误:无法读取图像文件 - {image_path}" + + img_height, img_width = img_cv.shape[:2] + + # 使用face_recognition检测人脸 + image = face_recognition.load_image_file(image_path) + face_locations = face_recognition.face_locations(image) + + if not face_locations: + return "📭 未检测到人脸" + + results = [] + saved_coords = [] + + for i, (top, right, bottom, left) in enumerate(face_locations): + # 转换为百分比坐标 + top_pct = top / img_height + right_pct = right / img_width + bottom_pct = bottom / img_height + left_pct = left / img_width + + face_data = { + "index": i + 1, + "position_absolute": {"top": top, "right": right, "bottom": bottom, "left": left}, + "position_percentage": {"top": top_pct, "right": right_pct, "bottom": bottom_pct, "left": left_pct}, + "size_absolute": {"width": right - left, "height": bottom - top}, + "size_percentage": {"width": (right - left) / img_width, "height": (bottom - top) / img_height}, + "image_dimensions": {"width": img_width, "height": img_height} + } + + # 保存人脸坐标到txt文件(百分比格式) + if save_coords: + try: + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + + # 确定输出文件名 + if output_file: + coords_filename = output_file + else: + base_name = os.path.splitext(os.path.basename(image_path))[0] + coords_filename = f"{base_name}_faces_{timestamp}.txt" + + # 使用当前目录作为保存路径 + coords_filepath = coords_filename + + # 写入百分比坐标数据(保留6位小数) + with open(coords_filepath, 'a') as f: + # 格式:top right bottom left (百分比,空格分隔) + f.write(f"{top_pct:.6f} {right_pct:.6f} {bottom_pct:.6f} {left_pct:.6f}\n") + + saved_coords.append(coords_filename) + + face_data["coords_file"] = coords_filename + face_data["coords_path"] = coords_filepath + except Exception as e: + face_data["save_error"] = str(e) + + results.append(face_data) + + # 构建结果字符串 + result_str = f"✅ 检测到 {len(results)} 张人脸\n" + result_str += f"📏 图像尺寸: {img_width}x{img_height}\n\n" + + for face in results: + result_str += f"👤 人脸 #{face['index']}:\n" + result_str += f" 绝对坐标: top={face['position_absolute']['top']}, right={face['position_absolute']['right']}, " + result_str += f"bottom={face['position_absolute']['bottom']}, left={face['position_absolute']['left']}\n" + result_str += f" 百分比坐标: top={face['position_percentage']['top']:.3f}, right={face['position_percentage']['right']:.3f}, " + result_str += f"bottom={face['position_percentage']['bottom']:.3f}, left={face['position_percentage']['left']:.3f}\n" + result_str += f" 绝对尺寸: {face['size_absolute']['width']}x{face['size_absolute']['height']}\n" + result_str += f" 相对尺寸: {face['size_percentage']['width']:.3f}x{face['size_percentage']['height']:.3f}" + + if 'coords_file' in face: + result_str += f"\n 坐标已保存到: {face['coords_file']}" + + result_str += "\n\n" + + if saved_coords: + # 显示所有保存的坐标文件 + unique_files = list(set(saved_coords)) + result_str += f"📂 人脸坐标(百分比格式)已保存到当前目录:\n" + for filename in unique_files: + result_str += f" 📄 {filename}\n" + + return result_str + + except Exception as e: + return f"❌ 检测失败: {e}" + + +def main(): + """简化后的主函数 - 仅人脸位置检测(百分比坐标)""" + parser = argparse.ArgumentParser(description="人脸位置检测工具(检测坐标并转换为百分比)") + subparsers = parser.add_subparsers(dest="command", help="可用命令") + + # detect命令 + detect_parser = subparsers.add_parser("detect", help="检测图像中的人脸并保存百分比坐标") + detect_parser.add_argument("image_path", help="图片文件路径") + detect_parser.add_argument("--no-save", action="store_true", help="不保存坐标") + detect_parser.add_argument("--output", help="指定输出文件名(默认自动生成)") + + # 工具描述命令 + desc_parser = subparsers.add_parser("description", help="显示工具描述") + + args = parser.parse_args() + + if not args.command: + parser.print_help() + sys.exit(1) + + detector = FacePositionDetector() + + if args.command == "description": + desc = """人脸位置检测工具(百分比坐标) + +功能: +- 检测图像中的人脸 +- 将人脸位置坐标转换为百分比格式 +- 保存百分比坐标到txt文件(格式:top right bottom left,均为0-1之间的浮点数) + +坐标说明: +- top: 人脸顶部位置(占图像高度的比例,0=顶部,1=底部) +- right: 人脸右侧位置(占图像宽度的比例,0=左侧,1=右侧) +- bottom: 人脸底部位置(占图像高度的比例,0=顶部,1=底部) +- left: 人脸左侧位置(占图像宽度的比例,0=左侧,1=右侧) + +目录结构: +- 人脸坐标保存位置: 当前目录 + +使用示例: + facerec.py detect image.jpg # 检测人脸并保存百分比坐标到当前目录 + facerec.py detect image.jpg --no-save # 检测但不保存坐标 + facerec.py detect image.jpg --output my_coords.txt # 指定输出文件名""" + print(desc) + + elif args.command == "detect": + save_coords = not args.no_save + result = detector.detect_faces(args.image_path, save_coords, args.output) + print(result) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lci/src/hd/Camera.cpp b/lci/src/hd/Camera.cpp new file mode 100644 index 0000000..9a37f26 --- /dev/null +++ b/lci/src/hd/Camera.cpp @@ -0,0 +1,535 @@ +/* FIXME: 这个文件非混乱 */ +/* FIXME: 抽象一个服务器类 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hd/Camera.h" + +#define cimg_display 0 /* 不显示图像,只保存 */ +#include "CImg.h" +#include +using namespace cimg_library; + +/*-----------------------------------*/ +/* Camera */ +static const char* filename = "/dev/video0"; /* FIXME: 不一定 */ +static int width = -1; +static int height = -1; + +/* 为了在获取单帧中使用 */ +static struct v4l2_buffer buf; +static enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + +/*-----------------------------------*/ +/* 静态全局线程对象及相关同步原语 */ +static std::thread camera_thread; +static std::atomic camera_running{false}; +static std::mutex camera_mutex; + +/* device file */ +static int fd = -1; + + +/*-----------------------------------*/ +void Camera_check();/* check if this device support video capture (V4L2_CAP_VIDEO_CAPTURE) */ +void Camera_setVideoFormat(int w, int h);/* Set Video Format */ +void Camera_reqBuf();/* Request Camera Buffer */ +void Camera_setup(); /* mapping buffer and data collection loop */ +void Camera_unsetup(); + +/*-----------------------------------*/ +bool Camera_is_open() { + return fd >= 0; +} + +/* FIXME: 如果在集成操作中出现异常,应该释放资源 */ +void Camera_init(int w, int h) { + + if (Camera_is_open()) + throw std::runtime_error("Camera already opened."); + + fd = open(filename, O_RDWR); + if (fd < 0) + throw std::runtime_error( + "Failed to open device: " + std::string(strerror(errno)) + ); + + Camera_check(); + Camera_setVideoFormat(w, h); + Camera_reqBuf(); + Camera_setup(); +} + +/* */ +void Camera_close() { + Camera_unsetup(); + close(fd); + fd = -1; +} + + +void Camera_check() { + struct v4l2_capability cap; + if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { + throw std::runtime_error( + "VIDIOC_QUERYCAP failed: " + std::string(strerror(errno)) + ); + } + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + throw std::runtime_error("Device does not support video capture"); + } +} + + +/* FIXME: 将Camera_init()中的参数放在这里 */ +void Camera_setVideoFormat(int width, int height) { + struct v4l2_format fmt; + memset(&fmt, 0, sizeof(fmt)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = width; /* */ + fmt.fmt.pix.height = height; /* */ + fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; /* usually format: YUYV, MJPEG */ + fmt.fmt.pix.field = V4L2_FIELD_NONE; + if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) + throw std::runtime_error( + "VIDIOC_S_FMT failed: " + std::string(strerror(errno))); + ::width= width; + ::height= height; +} + + +void Camera_reqBuf() { + struct v4l2_requestbuffers req; + memset(&req, 0, sizeof(req)); + req.count = 4; /* the number of buffer */ + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; /* the mode of memory mapping */ + + if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) + throw std::runtime_error( + "VIDIOC_REQBUFS failed: " + std::string(strerror(errno))); + +} + +/*------------------------------------------------------------------------------*/ + +void Camera_setup() { + /* mapping buffer (It is needed to handle every buffer in loop) */ + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = 0; /* Index of the buffer */ + + /* 查询缓冲区信息 */ + if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) { + throw std::runtime_error("VIDIOC_QUERYBUF failed: " + std::string(strerror(errno))); + } + + /* 将缓冲区加入队列 */ + if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) { + throw std::runtime_error("VIDIOC_QBUF failed: " + std::string(strerror(errno))); + } + + /* 开始采集 */ + if (ioctl(fd, VIDIOC_STREAMON, &buf.type) < 0) { /* start collection */ + throw std::runtime_error("VIDIOC_STREAMON failed: " + std::string(strerror(errno))); + } + +} + +void Camera_unsetup() +{ + /* 停止采集流 */ + ioctl(fd, VIDIOC_STREAMOFF, &type); +} + + +/*------------------------------------------------------------------------------*/ +/* + * Convert YUYV frame to CImg object and return it + * + * translate out camera data to CImg format + * + * new version + * + * FIXME: 专门建个库 + */ +CImg YUYV_to_CImg(uint8_t* frameData, int width, int height) { + // 参数检查 + if (!frameData || width <= 0 || height <= 0) { + throw std::invalid_argument("Invalid parameters"); + } + + CImg img(width, height, 1, 3); + + // 使用指针提高效率 + uint8_t* src = frameData; + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x += 2) { + uint8_t Y0 = src[0]; + uint8_t U = src[1]; + uint8_t Y1 = src[2]; + uint8_t V = src[3]; + src += 4; + + // 使用更精确的系数 + int R0 = Y0 + ((V - 128) * 1402) / 1000; + int G0 = Y0 - ((U - 128) * 344) / 1000 - ((V - 128) * 714) / 1000; + int B0 = Y0 + ((U - 128) * 1772) / 1000; + + int R1 = Y1 + ((V - 128) * 1402) / 1000; + int G1 = Y1 - ((U - 128) * 344) / 1000 - ((V - 128) * 714) / 1000; + int B1 = Y1 + ((U - 128) * 1772) / 1000; + + // 范围限制 + R0 = std::max(0, std::min(255, R0)); + G0 = std::max(0, std::min(255, G0)); + B0 = std::max(0, std::min(255, B0)); + + R1 = std::max(0, std::min(255, R1)); + G1 = std::max(0, std::min(255, G1)); + B1 = std::max(0, std::min(255, B1)); + + // 设置像素 + img(x, y, 0, 0) = static_cast(R0); + img(x, y, 0, 1) = static_cast(G0); + img(x, y, 0, 2) = static_cast(B0); + + if (x + 1 < width) { + img(x + 1, y, 0, 0) = static_cast(R1); + img(x + 1, y, 0, 1) = static_cast(G1); + img(x + 1, y, 0, 2) = static_cast(B1); + } + } + } + + return img; +} + + +CImg get_frame_from_camera(bool& flag) { + + std::lock_guard lock(camera_mutex); + //if (!camera_running.load()) + // throw std::runtime_error("Camera not running"); + + /* Dequeue to get data */ + memset(&buf, 0, sizeof(buf)); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + + if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0) { + perror("dequeue failed"); + throw std::runtime_error("dequeue failed"); + } + + /* 获取当前缓冲区的数据指针 */ + uint8_t *frameData = static_cast(mmap(NULL, buf.length, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, buf.m.offset)); + + if (frameData == MAP_FAILED) { + ioctl(fd, VIDIOC_QBUF, &buf); + throw std::runtime_error("mmap failed in get_frame_from_camera"); + } + + /* process frameData */ + //std::cout << "Got length: " << buf.length << std::endl; + auto img = YUYV_to_CImg(frameData, width, height); + + /* 解除内存映射 */ + munmap(frameData, buf.length); + + if (ioctl(fd, VIDIOC_QBUF, &buf)<0){ /* join the queue again */ + perror("requeue failed"); + throw std::runtime_error("requeue failed"); + } + + + flag = camera_running.load(); /* 检查下一次是否需要退出 */ + return img; /* 返回图像 */ +} + + + +//CImg YUYV_to_CImg(uint8_t* frameData, int width, int height) { + // 创建CImg图像对象 (width, height, depth=1, spectrum=3 for RGB) +// CImg img(width, height, 1, 3); + + // 遍历图像的每一行和每一列 +// for (int y = 0; y < height; y++) { +// for (int x = 0; x < width; x += 2) { + // YUYV格式:每两个像素占用4个字节 +// int yuyv_index = (y * width + x) * 2; + + // 提取YUV值 +// uint8_t Y0 = frameData[yuyv_index]; +// uint8_t U = frameData[yuyv_index + 1]; +// uint8_t Y1 = frameData[yuyv_index + 2]; +// uint8_t V = frameData[yuyv_index + 3]; + + // 转换第一个像素(x, y) +// int R0 = Y0 + (V - 128) * 1.402; +// int G0 = Y0 - (U - 128) * 0.34414 - (V - 128) * 0.71414; +// int B0 = Y0 + (U - 128) * 1.772; + + // 转换第二个像素(x+1, y) +// int R1 = Y1 + (V - 128) * 1.402; +// int G1 = Y1 - (U - 128) * 0.34414 - (V - 128) * 0.71414; +// int B1 = Y1 + (U - 128) * 1.772; + + // 限制范围到0-255 +// R0 = std::max(0, std::min(255, R0)); +// G0 = std::max(0, std::min(255, G0)); +// B0 = std::max(0, std::min(255, B0)); + +// R1 = std::max(0, std::min(255, R1)); +// G1 = std::max(0, std::min(255, G1)); +// B1 = std::max(0, std::min(255, B1)); + + // 设置第一个像素值 +// img(x, y, 0, 0) = static_cast(R0); +// img(x, y, 0, 1) = static_cast(G0); +// img(x, y, 0, 2) = static_cast(B0); + + // 设置第二个像素值(如果在图像范围内) +// if (x + 1 < width) { +// img(x + 1, y, 0, 0) = static_cast(R1); +// img(x + 1, y, 0, 1) = static_cast(G1); +// img(x + 1, y, 0, 2) = static_cast(B1); +// } +// } +// } + +// return img; +//} + + + +/* + * Convert YUYV pixel at position (x, y) in frame to RGB + * YUYV format: [Y0 U0 Y1 V0] [Y2 U2 Y3 V2] ... + * Each 4 bytes contain 2 pixels (Y0,U0,V0 for pixel0, Y1,U0,V0 for pixel1) + */ +void YUYV_to_RGB(uint8_t* frameData, int width, int height, int x, int y, + uint8_t& r, uint8_t& g, uint8_t& b) { + // 计算像素在YUYV数据中的索引 + int pixel_index = y * width + x; + + // YUYV中每2个像素共享4字节:Y0 U Y1 V + int byte_offset = (pixel_index / 2) * 4; + + // 确定是第一个像素还是第二个像素 + bool is_first_pixel = (pixel_index % 2 == 0); + + uint8_t Y, U, V; + + if (is_first_pixel) { + // 第一个像素:Y0, U, V + Y = frameData[byte_offset]; // Y0 + U = frameData[byte_offset + 1]; // U + V = frameData[byte_offset + 3]; // V + } else { + // 第二个像素:Y1, U, V (与第一个像素共享U和V) + Y = frameData[byte_offset + 2]; // Y1 + U = frameData[byte_offset + 1]; // U (共享) + V = frameData[byte_offset + 3]; // V (共享) + } + + // YUV to RGB conversion formula (integer approximation) + // 注意:YUV值通常范围是Y:16-235, UV:16-240 + // 这里先转换为0-255范围 + int Y_adj = Y - 16; + int U_adj = U - 128; + int V_adj = V - 128; + + // 计算RGB值 + int R = (298 * Y_adj + 409 * V_adj + 128) >> 8; + int G = (298 * Y_adj - 100 * U_adj - 208 * V_adj + 128) >> 8; + int B = (298 * Y_adj + 516 * U_adj + 128) >> 8; + + // 限制范围到0-255 + r = (R < 0) ? 0 : ((R > 255) ? 255 : static_cast(R)); + g = (G < 0) ? 0 : ((G > 255) ? 255 : static_cast(G)); + b = (B < 0) ? 0 : ((B > 255) ? 255 : static_cast(B)); +} + +/* + * Convert YUYV frame to CImg object and save as image + * + * FIXME(20251229): 每次处理一个像素都要调用YUYV_to_RGB函数,重新计算索引和转换,而YUYV格式中每两个相邻像素共享U和V值 + * FIXME(20260324): 效率太慢 + */ +//bool save_YUYV_as_image(uint8_t* frameData, int width, int height, +// const char* filename, int frame_num = 0) { +// try { + // 创建CImg图像对象 (width, height, depth=1, spectrum=3 for RGB) +// CImg img(width, height, 1, 3); + + // 转换为RGB并填充到CImg +// for (int y = 0; y < height; y++) { +// for (int x = 0; x < width; x++) { +// uint8_t r, g, b; +// YUYV_to_RGB(frameData, width, height, x, y, r, g, b); + + // CImg存储顺序是平面:首先所有R,然后所有G,最后所有B + // 或者使用(x, y, 0, channel)访问 +// img(x, y, 0, 0) = r; // Red channel +// img(x, y, 0, 1) = g; // Green channel +// img(x, y, 0, 2) = b; // Blue channel +// } +// } + + // 生成带帧编号的文件名 +// char full_filename[256]; +// if (frame_num > 0) { +// snprintf(full_filename, sizeof(full_filename), +// "%s_frame%03d.bmp", filename, frame_num); +// } else { +// snprintf(full_filename, sizeof(full_filename), "%s.bmp", filename); +// } + + // 保存为BMP格式(也支持PNG、JPEG等) +// img.save(full_filename); +// std::cout << "Image saved as: " << full_filename << std::endl; + +// return true; +// } catch (CImgException& e) { +// std::cerr << "Error saving image: " << e.what() << std::endl; +// return false; +// } +//} + + + +/* + * 将CImg数据压缩成jpeg data + * + * FIXME: 具有性能问题 + */ +std::vector compress_to_jpeg(const CImg& image, int quality = 75) { + + // 检查图像的有效性 + if (image.width() == 0 || image.height() == 0) { + std::cerr << "Error: Invalid image dimensions!" << std::endl; + return std::vector(); + } + + // 检查频谱(通道数) + int channels = image.spectrum(); + + // CImg数据布局:默认是平面格式 [plane1, plane2, plane3] + // 但我们需要交错的RGB格式用于JPEG压缩 + + unsigned char* buffer = nullptr; + unsigned long buffer_size = 0; + + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_compress(&cinfo); + jpeg_mem_dest(&cinfo, &buffer, &buffer_size); + + int width = image.width(); + int height = image.height(); + + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = 3; // 总是使用3通道RGB + cinfo.in_color_space = JCS_RGB; + + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE); + + // 开始压缩 + jpeg_start_compress(&cinfo, TRUE); + + JSAMPROW row_pointer[1]; + std::vector row_buffer(width * 3); // 用于存储一行交错的RGB数据 + + // 处理每一行 + for (int y = 0; y < height; y++) { + // 将CImg的平面格式转换为交错的RGB格式 + if (channels == 3) { + // RGB图像:CImg存储为平面格式 [R平面, G平面, B平面] + for (int x = 0; x < width; x++) { + row_buffer[x * 3] = image(x, y, 0, 0); // R + row_buffer[x * 3 + 1] = image(x, y, 0, 1); // G + row_buffer[x * 3 + 2] = image(x, y, 0, 2); // B + } + } + else if (channels == 1) { + // 灰度图像:重复到三个通道 + for (int x = 0; x < width; x++) { + unsigned char gray = image(x, y, 0, 0); + row_buffer[x * 3] = gray; // R + row_buffer[x * 3 + 1] = gray; // G + row_buffer[x * 3 + 2] = gray; // B + } + } + else if (channels == 4) { + // RGBA图像:忽略Alpha通道 + for (int x = 0; x < width; x++) { + row_buffer[x * 3] = image(x, y, 0, 0); // R + row_buffer[x * 3 + 1] = image(x, y, 0, 1); // G + row_buffer[x * 3 + 2] = image(x, y, 0, 2); // B + // 忽略Alpha通道:image(x, y, 0, 3) + } + } + else { + // 其他通道数:使用前3个通道 + std::cout << "Warning: Using first 3 channels of " << channels << "-channel image" << std::endl; + for (int x = 0; x < width; x++) { + for (int c = 0; c < 3 && c < channels; c++) { + row_buffer[x * 3 + c] = image(x, y, 0, c); + } + // 如果通道数不足3,用0填充 + for (int c = channels; c < 3; c++) { + row_buffer[x * 3 + c] = 0; + } + } + } + + row_pointer[0] = row_buffer.data(); + jpeg_write_scanlines(&cinfo, row_pointer, 1); + + } + + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + // 将JPEG数据复制到vector + std::vector jpeg_data(buffer, buffer + buffer_size); + + // 释放libjpeg分配的内存 + free(buffer); + + // 验证JPEG数据 + if (jpeg_data.size() >= 2) { + bool has_soi = (jpeg_data[0] == 0xFF && jpeg_data[1] == 0xD8); + bool has_eoi = (jpeg_data.size() >= 2 && + jpeg_data[jpeg_data.size()-2] == 0xFF && + jpeg_data[jpeg_data.size()-1] == 0xD9); + + if (!has_soi || !has_eoi) { + std::cerr << "Warning: Generated JPEG may be corrupted!" << std::endl; + } + } + + return jpeg_data; +} \ No newline at end of file diff --git a/lci/src/hd/I2C.cpp b/lci/src/hd/I2C.cpp new file mode 100644 index 0000000..d5a12ef --- /dev/null +++ b/lci/src/hd/I2C.cpp @@ -0,0 +1,79 @@ +/* + * 该文件是i2c用户界面 + * + * NOTE: 以C++的方式处理异常可能会更好 + * FIXME: 包含询问方法以确定i2c设备的状态 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cn/中文化.hpp" + +静态的 整数 文件描述符 = -1; +static pthread_mutex_t mutex; /* FIXME: 这个锁我们只提供接口给外部使用? */ + +逻辑型 I2C_检查() { + 返回 !(文件描述符 < 0); +} + +空类型 I2C_初始化(常量 字符* 设备路径 = "/dev/i2c-1") { /* FIXME: 动态指定设备文件 */ + 如果 ((文件描述符 = open(设备路径, O_RDWR)) < 0) + 抛出异常 std::runtime_error( /* FIXME: 使用专用的异常类 */ + "Failed to open I2C bus: " + std::string(strerror(errno)) + ); +} + +空类型 I2C_清理() { + close(文件描述符); +} + +空类型 I2C_置地址(常量 uint8_t 地址) { + 如果 (ioctl(文件描述符, I2C_SLAVE, 地址) < 0) + 抛出异常 std::runtime_error( + "Failed to set I2C address: " + std::string(strerror(errno)) + ); +} + +空类型 I2C_写寄存器(无号8位整 寄存器, 无号8位整 值) { /* 写寄存器 */ + 无号8位整 缓冲区[] = {寄存器, 值}; + 如果 (write(文件描述符, 缓冲区, 2) != 2) + 抛出异常 std::runtime_error( + "I2C write error: " + std::string(strerror(errno)) + ); +} + +/* 读寄存器 */ +无号8位整 I2C_读寄存器(无号8位整 寄存器) { + + 无号8位整 值; + + 如果 (write(文件描述符, &寄存器, 1) != 1) + 抛出异常 std::runtime_error( + "I2C read error: " + std::string(strerror(errno)) + ); + + 如果 (read(文件描述符, &值, 1)!= 1) + 抛出异常 std::runtime_error( + "I2C read error: " + std::string(strerror(errno)) + ); + + 返回 值; + +} + + +/* 获取锁 */ +空类型 I2C_获取锁() { + pthread_mutex_lock(&mutex); /* 加锁 */ +} + +/* 释放锁 */ +空类型 I2C_释放锁() { + pthread_mutex_unlock(&mutex); /* 解锁 */ +} diff --git a/lci/src/hd/MPU6050.cpp b/lci/src/hd/MPU6050.cpp new file mode 100644 index 0000000..2d4121e --- /dev/null +++ b/lci/src/hd/MPU6050.cpp @@ -0,0 +1,104 @@ + +/* + * FIXME: 1. 传感器数据校准 + 2. 可采用卡尔曼滤波 + + FIXME: 采用类进行封装,因为可能需要一对 + */ +#include +#include +#include +#include +#include "cn/中文化.hpp" +#include "Dashun_linux.hpp" + +静态的 预求值的 无号8位整 MPU6050_默认地址 = 0x68; +静态的 预求值的 无号8位整 MPU6050_电源管理寄存器1 = 0x6B; +静态的 预求值的 无号8位整 MPU6050_电源管理_非睡眠模式 = 0x00; +静态的 预求值的 无号8位整 MPU6050_陀螺仪配置寄存器 = 0x1B; +静态的 预求值的 无号8位整 MPU6050_陀螺仪量程_正负500度每秒 = 0x08; +静态的 预求值的 无号8位整 MPU6050_陀螺仪横轴数据_高字节 = 0x43; /* x */ +静态的 预求值的 无号8位整 MPU6050_陀螺仪横轴数据_低字节 = 0x44; +静态的 预求值的 无号8位整 MPU6050_陀螺仪纵轴数据_高字节 = 0x45; /* y */ +静态的 预求值的 无号8位整 MPU6050_陀螺仪纵轴数据_低字节 = 0x46; +静态的 预求值的 无号8位整 MPU6050_陀螺仪竖轴数据_高字节 = 0x47; /* z */ +静态的 预求值的 无号8位整 MPU6050_陀螺仪竖轴数据_低字节 = 0x48; +静态的 预求值的 无号8位整 MPU6050_加速度计配置寄存器 = 0x1C; +静态的 预求值的 无号8位整 MPU6050_加速度计量程_正负8g = 0x10; +静态的 预求值的 无号8位整 MPU6050_加速度计横轴数据_高字节 = 0x3B; +静态的 预求值的 无号8位整 MPU6050_加速度计横轴数据_低字节 = 0x3C; +静态的 预求值的 无号8位整 MPU6050_加速度计纵轴数据_高字节 = 0x3D; +静态的 预求值的 无号8位整 MPU6050_加速度计纵轴数据_低字节 = 0x3E; +静态的 预求值的 无号8位整 MPU6050_加速度计竖轴数据_高字节 = 0x3F; +静态的 预求值的 无号8位整 MPU6050_加速度计竖轴数据_低字节 = 0x40; +静态的 逻辑型 启动标志 = 假; + +逻辑型 MPU6050_检查() { + I2C_获取锁(); + 布尔 临时 = 启动标志; + I2C_释放锁(); + 返回 临时; +} + +/* 初始化 MPU6050 */ +空类型 MPU6050_初始化() { + I2C_获取锁(); + I2C_置地址(MPU6050_默认地址); + I2C_写寄存器(MPU6050_电源管理寄存器1, MPU6050_电源管理_非睡眠模式); /* 退出睡眠 */ + I2C_写寄存器(MPU6050_陀螺仪配置寄存器, MPU6050_陀螺仪量程_正负500度每秒); /* ±500°/s */ + I2C_写寄存器(MPU6050_加速度计配置寄存器, MPU6050_加速度计量程_正负8g); /* ±8g */ + 启动标志 = 真; + I2C_释放锁(); + usleep(100000); /* 等待稳定 */ +} + +/* 读取 16 位传感器数据(带符号) */ +静态的 有号16位整 读16比特寄存器(无号8位整 寄存器高位, 无号8位整 寄存器低位) { + 返回 (I2C_读寄存器(寄存器高位) << 8) | I2C_读寄存器(寄存器低位); +} + +/* 获取原始MPU6050传感器数据 */ +MPU6050_传感器数据 MPU6050_读传感器() { + MPU6050_传感器数据 数据; + I2C_获取锁(); + I2C_置地址(MPU6050_默认地址); + 数据.加速度计_横 = 读16比特寄存器(MPU6050_加速度计横轴数据_高字节, MPU6050_加速度计横轴数据_低字节); + 数据.加速度计_纵 = 读16比特寄存器(MPU6050_加速度计纵轴数据_高字节, MPU6050_加速度计纵轴数据_低字节); + 数据.加速度计_竖 = 读16比特寄存器(MPU6050_加速度计竖轴数据_高字节, MPU6050_加速度计竖轴数据_低字节); + 数据.陀螺仪_横 = 读16比特寄存器(MPU6050_陀螺仪横轴数据_高字节, MPU6050_陀螺仪横轴数据_低字节); + 数据.陀螺仪_纵 = 读16比特寄存器(MPU6050_陀螺仪纵轴数据_高字节, MPU6050_陀螺仪纵轴数据_低字节); + 数据.陀螺仪_竖 = 读16比特寄存器(MPU6050_陀螺仪竖轴数据_高字节, MPU6050_陀螺仪竖轴数据_低字节); + I2C_释放锁(); + 返回 数据; +} + +/* FIXME: 当设备剧烈运动时(如加速度远大于重力),加速度计数据会包含运动加速度,此时角度计算可能不准确。实际应用中需结合陀螺仪数据(如互补滤波或卡尔曼滤波)来提高稳定性。 */ +/* FIXME: 适合静态测量或学习用途。如果需要实际应用,建议添加传感器融合算法 */ +空类型 MPU6050_计算角度(常量 MPU6050_传感器数据& 数据, 单精度小数& 俯仰角, 单精度小数& 翻滚角) { + /* - ±2g → 16384 LSB/g + - ±4g → 8192 LSB/g + - ±8g → 4096 LSB/g + - ±16g → 2048 LSB/g */ + 常量 单精度小数 比例 = 4096.0; /* 加速度数据转重力单位(±8g 量程 4096 LSB/g) */ + 单精度小数 横角 = 数据.加速度计_横 / 比例; + 单精度小数 纵角 = 数据.加速度计_纵 / 比例; + 单精度小数 竖角 = 数据.加速度计_竖 / 比例; + + /* 计算俯仰角(Pitch)和翻滚角(Roll) */ + 俯仰角 = atan2(-横角, sqrt(纵角 * 纵角 + 竖角 * 竖角)) * 180.0 / M_PI; + 翻滚角 = atan2(纵角, 竖角) * 180.0 / M_PI; +} + +#ifdef _TEST +/* TEST MAIN */ +整数 主函数() { + I2C_初始化(); + MPU6050_初始化(); + 判断循环 (1) { + MPU6050_传感器数据 数据 = MPU6050_读传感器(); + 单精度小数 俯仰角, 翻滚角; + MPU6050_计算角度(数据, 俯仰角, 翻滚角); + printf("俯仰角: %.2f\t翻滚角: %.2f\n"); + } +} +#endif diff --git a/lci/src/hd/PCA9685.cpp b/lci/src/hd/PCA9685.cpp new file mode 100644 index 0000000..040fdb3 --- /dev/null +++ b/lci/src/hd/PCA9685.cpp @@ -0,0 +1,57 @@ +/* PCA9685 舵机驱动板 */ +#include +#include +#include "cn/中文化.hpp" +#include "Dashun_linux.hpp" + +预求值的 无号8位整 PCA9685_地址 = 0x40; /* 7位地址 */ +静态的 逻辑型 启动标志 = 假; /* 启动标志 */ +逻辑型 PCA9685_检查() { + I2C_获取锁(); + 逻辑型 临时 = 启动标志; + I2C_释放锁(); + 返回 临时; +} +空类型 PCA9685_初始化() { + I2C_获取锁(); + I2C_置地址(PCA9685_地址); + I2C_写寄存器(0x00, 0x20); /* 开启AI(地址自增)和关闭SLEEP */ + 启动标志 = 真; + I2C_释放锁(); + usleep(5000); /* 等待振荡器启动 */ + + /* 设置PWM频率为50Hz(舵机标准周期20ms) */ + 预求值的 单精度小数 赫兹频率 = 50.0; + 单精度小数 prescale_val = 25000000.0 / (4096 * 赫兹频率) - 1; /* 25MHz主频 */ + 无号8位整 预分频值 = static_cast(prescale_val + 0.5); + + I2C_获取锁(); + I2C_写寄存器(0x00, 0x10); /* 进入SLEEP模式(允许改频率) */ + I2C_写寄存器(0xFE, 预分频值); /* 写入预分频值 */ + I2C_写寄存器(0x00, 0x20); /* 退出SLEEP */ + I2C_释放锁(); + usleep(5000); +} + +/* 设置指定通道的PWM信号(0-4095) */ +空类型 PCA9685_设置PWM(无号8位整 通道, 无号16位整 导通, 无号16位整 关断) { + 无号8位整 寄存器 = 0x06 + 4 * 通道; /* LED0 寄存器起始地址 */ + I2C_获取锁(); + I2C_置地址(PCA9685_地址); + I2C_写寄存器(寄存器, 导通 & 0xFF); + I2C_写寄存器(寄存器 + 1, 导通 >> 8); + I2C_写寄存器(寄存器 + 2, 关断 & 0xFF); + I2C_写寄存器(寄存器 + 3, 关断 >> 8); + I2C_释放锁(); +} + +/* + * 角度转PWM值(0°~180° → 0.5ms~2.5ms脉宽) + */ +空类型 PCA9685_调整角度(无号8位整 通道, 单精度小数 角度) { + 预求值的 单精度小数 最小脉冲 = 0.5; /* 0°对应0.5ms */ + 预求值的 单精度小数 最大脉冲 = 2.5; /* 180°对应2.5ms */ + 单精度小数 脉冲宽度 = 最小脉冲 + (最大脉冲 - 最小脉冲) * (角度 / 180.0); + 无号16位整 关断值 = static_cast(脉冲宽度 * 4096 / 20); /* 20ms 周期 */ + PCA9685_设置PWM(通道, 0, 关断值); /* ON=0, OFF=计算值 */ +} diff --git a/lci/src/hd/mem.cpp b/lci/src/hd/mem.cpp new file mode 100644 index 0000000..24f3c01 --- /dev/null +++ b/lci/src/hd/mem.cpp @@ -0,0 +1,21 @@ +#include "hd/mem.h" + +/* 通过SysInfo接口获取内存使用情况 失败会返回NULL */ +MemoryInfo getMemoryUsageWithSysinfo() { + MemoryInfo memInfo = {0}; + struct sysinfo si; + + if (sysinfo(&si) == 0) + { + memInfo.totalMemory = si.totalram * si.mem_unit; + memInfo.freeMemory = si.freeram * si.mem_unit; + memInfo.usedMemory = memInfo.totalMemory - memInfo.freeMemory; + + if (memInfo.totalMemory > 0) + memInfo.usageRate = 100.0 * memInfo.usedMemory / memInfo.totalMemory; + } + else + std::cerr << "sysinfo Call Failed" << std::endl; + + return memInfo; +} diff --git a/lci/src/labeled.py b/lci/src/labeled.py new file mode 100644 index 0000000..bd82f9e --- /dev/null +++ b/lci/src/labeled.py @@ -0,0 +1,590 @@ +#!/usr/bin/env python3 +""" +图片标注工具 +用于手动标注图像中的目标区域并保存位置坐标(百分比格式)到txt文件 +支持矩形框标注、预览、编辑和删除功能 +""" + +import os +import sys +import json +import tkinter as tk +from tkinter import ttk, filedialog, messagebox, simpledialog +from PIL import Image, ImageTk, ImageDraw +import cv2 +import numpy as np +from datetime import datetime +from typing import List, Optional, Tuple +import threading + + +class ImageAnnotationTool: + """图片标注工具 - 支持手动矩形框标注""" + + def __init__(self, root): + self.root = root + self.root.title("图片标注工具") + self.root.geometry("1200x800") + + # 数据存储 + self.current_image_path = None + self.current_image = None + self.image_pil = None + self.image_tk = None + self.zoom_factor = 1.0 + self.image_display = None + self.annotations = [] # 存储标注:[(x1, y1, x2, y2), ...] # 移除了label字段 + + # 标注状态 + self.drawing = False + self.start_x = None + self.start_y = None + self.current_rect = None + self.selected_annotation = -1 # 当前选中的标注索引 + self.drag_mode = False # 是否在拖拽模式 + self.drag_start = None # 拖拽起始点 + + # 缩放和平移 + self.offset_x = 0 + self.offset_y = 0 + self.pan_start_x = 0 + self.pan_start_y = 0 + self.panning = False + + # 创建UI + self.setup_ui() + + # 绑定事件 + self.setup_bindings() + + # 更新状态 + self.update_status() + + def setup_ui(self): + """设置用户界面""" + # 创建主框架 + main_frame = ttk.Frame(self.root) + main_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) + + # 左侧控制面板 + control_frame = ttk.Frame(main_frame, width=250) + control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 5)) + control_frame.pack_propagate(False) + + # 文件操作 + file_group = ttk.LabelFrame(control_frame, text="文件操作", padding=5) + file_group.pack(fill=tk.X, pady=(0, 10)) + + ttk.Button(file_group, text="打开图片", command=self.open_image).pack(fill=tk.X, pady=2) + ttk.Button(file_group, text="保存标注", command=self.save_annotations).pack(fill=tk.X, pady=2) + ttk.Button(file_group, text="加载标注", command=self.load_annotations).pack(fill=tk.X, pady=2) + + # 标注操作 + anno_group = ttk.LabelFrame(control_frame, text="标注操作", padding=5) + anno_group.pack(fill=tk.X, pady=(0, 10)) + + ttk.Button(anno_group, text="清除当前标注", command=self.clear_current_annotation).pack(fill=tk.X, pady=2) + ttk.Button(anno_group, text="删除所有标注", command=self.clear_all_annotations).pack(fill=tk.X, pady=2) + ttk.Button(anno_group, text="删除选中标注", command=self.delete_selected_annotation).pack(fill=tk.X, pady=2) + + # 标注列表 + list_group = ttk.LabelFrame(control_frame, text="标注列表", padding=5) + list_group.pack(fill=tk.BOTH, expand=True, pady=(0, 10)) + + # 创建列表框和滚动条 + list_frame = ttk.Frame(list_group) + list_frame.pack(fill=tk.BOTH, expand=True) + + self.annotation_listbox = tk.Listbox(list_frame, height=15) + scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.annotation_listbox.yview) + self.annotation_listbox.configure(yscrollcommand=scrollbar.set) + + self.annotation_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + + self.annotation_listbox.bind('<>', self.on_annotation_select) + + # 信息显示 + info_group = ttk.LabelFrame(control_frame, text="信息", padding=5) + info_group.pack(fill=tk.X) + + self.info_label = ttk.Label(info_group, text="未加载图片", wraplength=220) + self.info_label.pack(fill=tk.X, pady=2) + + self.status_label = ttk.Label(info_group, text="状态: 就绪", wraplength=220) + self.status_label.pack(fill=tk.X, pady=2) + + # 右侧画布区域 + canvas_frame = ttk.Frame(main_frame) + canvas_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) + + # 工具栏 + toolbar = ttk.Frame(canvas_frame) + toolbar.pack(fill=tk.X, pady=(0, 5)) + + ttk.Button(toolbar, text="放大", command=self.zoom_in).pack(side=tk.LEFT, padx=2) + ttk.Button(toolbar, text="缩小", command=self.zoom_out).pack(side=tk.LEFT, padx=2) + ttk.Button(toolbar, text="适应窗口", command=self.fit_to_window).pack(side=tk.LEFT, padx=2) + ttk.Button(toolbar, text="重置视图", command=self.reset_view).pack(side=tk.LEFT, padx=2) + + self.draw_mode_var = tk.BooleanVar(value=True) + ttk.Checkbutton(toolbar, text="绘制模式", variable=self.draw_mode_var).pack(side=tk.LEFT, padx=5) + + # 画布 + self.canvas = tk.Canvas(canvas_frame, bg='gray', cursor='cross') + self.canvas.pack(fill=tk.BOTH, expand=True) + + def setup_bindings(self): + """设置事件绑定""" + self.canvas.bind('', self.on_mouse_down) + self.canvas.bind('', self.on_mouse_move) + self.canvas.bind('', self.on_mouse_up) + self.canvas.bind('', self.on_pan_start) + self.canvas.bind('', self.on_pan_move) + self.canvas.bind('', self.on_pan_end) + self.root.bind('', lambda e: self.delete_selected_annotation()) + self.root.bind('', lambda e: self.save_annotations()) + self.root.bind('', lambda e: self.open_image()) + + def open_image(self): + """打开图片文件""" + file_path = filedialog.askopenfilename( + title="选择图片文件", + filetypes=[ + ("图片文件", "*.jpg *.jpeg *.png *.bmp *.tiff"), + ("所有文件", "*.*") + ] + ) + + if not file_path: + return + + try: + # 加载图片 + self.current_image_path = file_path + self.image_pil = Image.open(file_path) + + # 重置状态 + self.annotations = [] + self.selected_annotation = -1 + self.zoom_factor = 1.0 + self.offset_x = 0 + self.offset_y = 0 + + # 适应窗口 + self.fit_to_window() + + # 更新标注列表 + self.update_annotation_list() + + # 更新信息 + self.update_info() + self.update_status("图片已加载") + + except Exception as e: + messagebox.showerror("错误", f"无法加载图片: {e}") + + def fit_to_window(self): + """调整图片适应窗口""" + if not self.image_pil: + return + + canvas_width = self.canvas.winfo_width() + canvas_height = self.canvas.winfo_height() + + if canvas_width <= 1 or canvas_height <= 1: + canvas_width = 800 + canvas_height = 600 + + img_width, img_height = self.image_pil.size + + # 计算缩放比例 + scale_x = canvas_width / img_width + scale_y = canvas_height / img_height + self.zoom_factor = min(scale_x, scale_y) + + # 计算偏移量使图片居中 + scaled_width = img_width * self.zoom_factor + scaled_height = img_height * self.zoom_factor + self.offset_x = (canvas_width - scaled_width) / 2 + self.offset_y = (canvas_height - scaled_height) / 2 + + self.display_image() + + def reset_view(self): + """重置视图""" + self.zoom_factor = 1.0 + self.offset_x = 0 + self.offset_y = 0 + self.fit_to_window() + + def zoom_in(self): + """放大""" + self.zoom_factor *= 1.2 + self.display_image() + + def zoom_out(self): + """缩小""" + self.zoom_factor /= 1.2 + self.display_image() + + def display_image(self): + """显示图片""" + if not self.image_pil: + return + + # 缩放图片 + img_width, img_height = self.image_pil.size + new_width = int(img_width * self.zoom_factor) + new_height = int(img_height * self.zoom_factor) + + scaled_image = self.image_pil.resize((new_width, new_height), Image.Resampling.LANCZOS) + + # 转换为PhotoImage + self.image_tk = ImageTk.PhotoImage(scaled_image) + + # 清除画布 + self.canvas.delete("all") + + # 显示图片 + self.canvas.create_image(self.offset_x, self.offset_y, anchor=tk.NW, image=self.image_tk) + + # 绘制标注 + self.draw_annotations() + + def draw_annotations(self): + """绘制所有标注""" + if not self.image_pil: + return + + img_width, img_height = self.image_pil.size + + for idx, (x1, y1, x2, y2) in enumerate(self.annotations): + # 转换坐标 + canvas_x1 = x1 * self.zoom_factor + self.offset_x + canvas_y1 = y1 * self.zoom_factor + self.offset_y + canvas_x2 = x2 * self.zoom_factor + self.offset_x + canvas_y2 = y2 * self.zoom_factor + self.offset_y + + # 确定颜色 + if idx == self.selected_annotation: + color = "red" + width = 3 + else: + color = "blue" + width = 2 + + # 绘制矩形 + self.canvas.create_rectangle(canvas_x1, canvas_y1, canvas_x2, canvas_y2, + outline=color, width=width, tags=f"rect_{idx}") + + # 绘制序号 + self.canvas.create_text(canvas_x1 + 5, canvas_y1 + 15, + text=str(idx + 1), anchor=tk.NW, + fill=color, font=("Arial", 10, "bold"), + tags=f"label_{idx}") + + def canvas_to_image_coords(self, canvas_x, canvas_y): + """将画布坐标转换为图片坐标""" + img_x = (canvas_x - self.offset_x) / self.zoom_factor + img_y = (canvas_y - self.offset_y) / self.zoom_factor + return img_x, img_y + + def on_mouse_down(self, event): + """鼠标按下事件""" + if self.draw_mode_var.get(): + # 绘制模式 + img_x, img_y = self.canvas_to_image_coords(event.x, event.y) + if 0 <= img_x <= self.image_pil.size[0] and 0 <= img_y <= self.image_pil.size[1]: + self.drawing = True + self.start_x = img_x + self.start_y = img_y + else: + # 选择模式 - 查找最近的标注 + self.find_nearest_annotation(event.x, event.y) + + def find_nearest_annotation(self, canvas_x, canvas_y): + """查找最近的标注""" + if not self.annotations: + return + + min_dist = float('inf') + nearest_idx = -1 + + for idx, (x1, y1, x2, y2) in enumerate(self.annotations): + # 转换坐标 + cx1 = x1 * self.zoom_factor + self.offset_x + cy1 = y1 * self.zoom_factor + self.offset_y + cx2 = x2 * self.zoom_factor + self.offset_x + cy2 = y2 * self.zoom_factor + self.offset_y + + # 计算到矩形边界的距离 + if cx1 <= canvas_x <= cx2 and cy1 <= canvas_y <= cy2: + # 点在矩形内 + dist = 0 + else: + # 计算到最近边的距离 + dx = max(cx1 - canvas_x, 0, canvas_x - cx2) + dy = max(cy1 - canvas_y, 0, canvas_y - cy2) + dist = (dx**2 + dy**2)**0.5 + + if dist < min_dist: + min_dist = dist + nearest_idx = idx + + # 如果距离足够近,选中该标注 + if min_dist < 20: # 20像素阈值 + self.selected_annotation = nearest_idx + self.annotation_listbox.selection_clear(0, tk.END) + self.annotation_listbox.selection_set(nearest_idx) + self.annotation_listbox.see(nearest_idx) + self.display_image() + self.update_status(f"选中标注 #{nearest_idx + 1}") + + def on_mouse_move(self, event): + """鼠标移动事件""" + if self.drawing: + # 绘制临时矩形 + if self.current_rect: + self.canvas.delete(self.current_rect) + + img_x, img_y = self.canvas_to_image_coords(event.x, event.y) + canvas_x1 = self.start_x * self.zoom_factor + self.offset_x + canvas_y1 = self.start_y * self.zoom_factor + self.offset_y + canvas_x2 = img_x * self.zoom_factor + self.offset_x + canvas_y2 = img_y * self.zoom_factor + self.offset_y + + self.current_rect = self.canvas.create_rectangle( + canvas_x1, canvas_y1, canvas_x2, canvas_y2, + outline="green", width=2, dash=(5, 5) + ) + + def on_mouse_up(self, event): + """鼠标释放事件""" + if self.drawing: + # 完成绘制 + img_x, img_y = self.canvas_to_image_coords(event.x, event.y) + + # 确保坐标正确排序 + x1 = min(self.start_x, img_x) + y1 = min(self.start_y, img_y) + x2 = max(self.start_x, img_x) + y2 = max(self.start_y, img_y) + + # 检查矩形大小 + if x2 - x1 > 5 and y2 - y1 > 5: + # 添加标注(只保存坐标,不保存标签) + self.annotations.append((x1, y1, x2, y2)) + self.update_annotation_list() + self.display_image() + self.update_status(f"已添加标注 #{len(self.annotations)}") + else: + self.update_status("标注太小,已忽略") + + # 清理绘制状态 + self.drawing = False + if self.current_rect: + self.canvas.delete(self.current_rect) + self.current_rect = None + + def on_pan_start(self, event): + """开始平移""" + self.panning = True + self.pan_start_x = event.x + self.pan_start_y = event.y + + def on_pan_move(self, event): + """平移移动""" + if self.panning: + dx = event.x - self.pan_start_x + dy = event.y - self.pan_start_y + self.offset_x += dx + self.offset_y += dy + self.pan_start_x = event.x + self.pan_start_y = event.y + self.display_image() + + def on_pan_end(self, event): + """结束平移""" + self.panning = False + + def update_annotation_list(self): + """更新标注列表""" + self.annotation_listbox.delete(0, tk.END) + for idx, (x1, y1, x2, y2) in enumerate(self.annotations): + width = x2 - x1 + height = y2 - y1 + list_text = f"{idx + 1}. 矩形 ({width:.0f}x{height:.0f})" + self.annotation_listbox.insert(tk.END, list_text) + + def on_annotation_select(self, event): + """标注列表选择事件""" + selection = self.annotation_listbox.curselection() + if selection: + self.selected_annotation = selection[0] + self.display_image() + self.update_status(f"已选中标注 #{self.selected_annotation + 1}") + + def delete_selected_annotation(self): + """删除选中的标注""" + if self.selected_annotation >= 0 and self.selected_annotation < len(self.annotations): + del self.annotations[self.selected_annotation] + self.selected_annotation = -1 + self.update_annotation_list() + self.display_image() + self.update_status("已删除选中标注") + + def clear_current_annotation(self): + """清除当前标注""" + self.selected_annotation = -1 + self.display_image() + self.update_status("已清除选中状态") + + def clear_all_annotations(self): + """删除所有标注""" + if messagebox.askyesno("确认", "确定要删除所有标注吗?"): + self.annotations = [] + self.selected_annotation = -1 + self.update_annotation_list() + self.display_image() + self.update_status("已删除所有标注") + + def save_annotations(self): + """保存标注到文件(仅TXT格式,纯坐标,格式:top right bottom left)""" + if not self.current_image_path: + messagebox.showwarning("警告", "请先加载图片") + return + + if not self.annotations: + if not messagebox.askyesno("确认", "没有标注要保存,是否继续?"): + return + + try: + # 获取图像尺寸 + img_width, img_height = self.image_pil.size + + # 生成保存路径:图片文件名.txt(同目录下) + image_dir = os.path.dirname(self.current_image_path) + image_basename = os.path.splitext(os.path.basename(self.current_image_path))[0] + file_path = os.path.join(image_dir, f"{image_basename}.txt") + + # 保存标注(纯坐标格式,top right bottom left) + with open(file_path, 'w', encoding='utf-8') as f: + for x1, y1, x2, y2 in self.annotations: + # 转换为百分比坐标(top, right, bottom, left) + top_pct = y1 / img_height + right_pct = x2 / img_width + bottom_pct = y2 / img_height + left_pct = x1 / img_width + + # 写入坐标数据(保留6位小数,空格分隔) + f.write(f"{top_pct:.6f} {right_pct:.6f} {bottom_pct:.6f} {left_pct:.6f}\n") + + self.update_status(f"已保存 {len(self.annotations)} 个标注到 {os.path.basename(file_path)}") + messagebox.showinfo("成功", f"标注已保存到:\n{file_path}\n\n格式: top right bottom left (百分比坐标)") + + except Exception as e: + messagebox.showerror("错误", f"保存失败: {e}") + + def load_annotations(self): + """加载标注文件(TXT格式,纯坐标,格式:top right bottom left)""" + if not self.current_image_path: + messagebox.showwarning("警告", "请先加载图片") + return + + # 默认加载同目录下的同名txt文件 + image_dir = os.path.dirname(self.current_image_path) + image_basename = os.path.splitext(os.path.basename(self.current_image_path))[0] + default_file = os.path.join(image_dir, f"{image_basename}.txt") + + if os.path.exists(default_file): + file_path = default_file + else: + file_path = filedialog.askopenfilename( + title="选择标注文件", + initialdir=image_dir, + filetypes=[ + ("文本文件", "*.txt"), + ("所有文件", "*.*") + ] + ) + + if not file_path: + return + + try: + self.load_txt_annotations(file_path) + self.update_annotation_list() + self.display_image() + self.update_status(f"已加载 {len(self.annotations)} 个标注") + + except Exception as e: + messagebox.showerror("错误", f"加载失败: {e}") + + def load_txt_annotations(self, file_path): + """加载TXT格式的标注文件(纯坐标格式,top right bottom left)""" + self.annotations = [] + img_width, img_height = self.image_pil.size + + with open(file_path, 'r', encoding='utf-8') as f: + for line_num, line in enumerate(f, 1): + line = line.strip() + if not line: + continue + + parts = line.split() + if len(parts) == 4: + try: + top_pct = float(parts[0]) + right_pct = float(parts[1]) + bottom_pct = float(parts[2]) + left_pct = float(parts[3]) + + # 验证百分比坐标范围 + if all(0 <= v <= 1 for v in [top_pct, right_pct, bottom_pct, left_pct]): + # 转换为绝对坐标 + x1 = left_pct * img_width + y1 = top_pct * img_height + x2 = right_pct * img_width + y2 = bottom_pct * img_height + + self.annotations.append((x1, y1, x2, y2)) + else: + print(f"警告: 第{line_num}行坐标超出范围 [0,1]: {line}") + except ValueError as e: + print(f"警告: 第{line_num}行格式错误: {line}, 错误: {e}") + else: + print(f"警告: 第{line_num}行格式错误,需要4个坐标值: {line}") + + def update_info(self): + """更新信息显示""" + if self.current_image_path and self.image_pil: + img_width, img_height = self.image_pil.size + filename = os.path.basename(self.current_image_path) + self.info_label.config(text=f"图片: {filename}\n尺寸: {img_width}x{img_height}\n标注: {len(self.annotations)}个") + else: + self.info_label.config(text="未加载图片") + + def update_status(self, message=None): + """更新状态栏""" + if message: + self.status_label.config(text=f"状态: {message}") + else: + self.status_label.config(text="状态: 就绪") + + def update(self): + """更新界面""" + self.update_info() + self.root.after(1000, self.update) + + +def main(): + """主函数""" + root = tk.Tk() + app = ImageAnnotationTool(root) + app.update() + root.mainloop() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lci/src/lci/Area.cpp b/lci/src/lci/Area.cpp new file mode 100644 index 0000000..68a6df2 --- /dev/null +++ b/lci/src/lci/Area.cpp @@ -0,0 +1,79 @@ +#include +#include "lci/utf8.h" +#include "lci/ansi.h" +#include "lci/Drawable.h" +#include "lci/Area.h" +namespace qing { + + /* FIXME: 区域类持有可绘制类的引用 */ + Area::Area(Drawable *d, int w, int h, int x, int y, int rotate = 0, int fontsize=18) + :Drawable(w, h, x, y, rotate, fontsize) { + this->d = d; + } + + /* 获取持有可绘制对象的颜色 */ + Color Area::_get(int x, int y) { + return d->get_color(this->x + x, this->y + y); + } + + /* 绘制到持有可绘制对象 */ + void Area::_p(int x, int y, Color &clr) { + d->point(this->x + x, this->y + y, clr); + } + + /* 持有可绘制对象区域移动 */ +// void Area::_up(int x, int y, int w, int h, int level) { +// d->up(this->x + x, this->y + y, w, h, level); +// } +// +// void Area::_down(int x, int y, int w, int h, int level) { +// d->down(this->x + x, this->y + y, w, h, level); +// } +// +// void Area::_left(int x, int y, int w, int h, int level) { +// d->left(this->x + x, this->y + y, w, h, level); +// } +// +// void Area::_right(int x, int y, int w, int h, int level) { +// d->right(this->x + x, this->y + y, w, h, level); +// } + + /* 将另一个可绘制对象刷新到这里 */ + void Area::flush(Drawable *n, bool border) { + Rectangle size = n->get_size(); + Rectangle pos = n->get_pos(); + Color &clr = n->getFontsColor(); + if (border) { + rectangle(pos.w-1, pos.h-1, size.w+1, size.h+1, clr); + } + + /* FIXME: Area无需复制?如果是两块区域还是需要的 */ + Area *p = dynamic_cast(n); + if (p != nullptr) return; + + // too slow + // 太慢了 + for (int x = 0; x < size.w; ++x) { + for (int y = 0; y < size.h; ++y) { + Color color = n->get_color(x, y); + point(pos.w + x, pos.h + y, color); + } + } + } + + /* FIXME: 边界检查应该加在父类方法中 不超出边界 */ + /* FIXME: 将border写入成员中,如果有border连同它一起移动 */ + /* FIXME: rotate=1时不能正常移动 */ + void Area::move(int x, int y) { + // if (x >= 0) + // d->right(this->x, this->y, this->w+x, this->h, x); + // else if (x < 0) + // d->left(this->x+x, this->y, this->w-x, this->h, x); + // if (y >= 0) + // d->down(this->x+x, this->y, this->w, this->h+y, y); + // else if (y <0) + // d->up(this->x+x, this->y+y, this->w, this->h-y, y); + this->x += x; + this->y += y; + } +} diff --git a/lci/src/lci/CmdArea.cpp b/lci/src/lci/CmdArea.cpp new file mode 100644 index 0000000..a0bee90 --- /dev/null +++ b/lci/src/lci/CmdArea.cpp @@ -0,0 +1,219 @@ +/* + * FIXME: 现在输入框无法触底 + */ + +#include +#include +#include "lci/CmdArea.h" +#include "lci/utf8.h" +#include "lci/ansi.h" +constexpr static auto H = 2; +namespace qing { + /* FIXME(20260113): 将输入框做成大部分时候和输入行在同一行 */ + CmdArea::CmdArea(Drawable *d, int w, int h, int x, int y, int rotate, int fontsize, bool hasBox) + : Area(d, w, h, x, y, rotate, fontsize), hasBox(hasBox) { + //auto w_std = w - 2 * x; + auto w_std = 5 * fontsize; + auto w_tar = 5 * fontsize; + if (hasBox) { + area = std::make_unique(this, (w_tar < w_std) ? w_tar : w_std, H*fontsize, x, fontsize*2, rotate, fontsize); + } + } + + void CmdArea::Input(char c) { + std::unique_lock lck(this->lock); + this->input += c; + } + + void CmdArea::ClearInput() { + std::unique_lock lck(this->lock); + this->input = ""; + } + + void CmdArea::update_input() { + std::unique_lock lck(this->lock); + if (hasBox) + area->print((char*)this->input.c_str(), 0); + } + + void CmdArea::clearBox() { + std::unique_lock lck(this->lock); + auto clr = black; + if (hasBox){ + auto size = area->get_size(); + area->rectangle_fill(0, 0, size.w-1, size.h, clr); + } + } + + void CmdArea::delete_input() { + std::unique_lock lck(this->lock); + auto l = this->input.length(); + this->input = this->input.substr(0, l - 1); + } + + std::string CmdArea::get_input_and_clear() { + std::unique_lock lck(this->lock); + auto cur = this->input; + this->input = ""; + return cur; + } + + void CmdArea::print(char *utf8, int d) { + auto color = black; + auto fontsize = FontSize_get(); + auto half_f = fontsize / 2; + this->lock.lock(); + + auto subpos =(hasBox) ? area->get_pos() : Rectangle{0, 0}; + auto subsize = (hasBox) ? area->get_size() : Rectangle{0, 0}; + if (hasBox) + rectangle_fill(subpos.w-1, subpos.h-1, subsize.w+2, subsize.h+2, color); + char *ansi = utf8::to_ansi(utf8); + char *p = ansi; + Rectangle l = get_size(); + while (1) { + + //int size = ansi::size_gb18030((unsigned char*)p, 4); + /** + * 这个老的矢量字库应该是 GB2312 的 + */ + int size = ansi::size_gb2312(*(unsigned char *)p); + + if (*p == '\n') { + + x_f = 0; + y_f += fontsize; + + } else if (*p == '\0') { + + break; + + } else if (*p == '\t') { + + int n = x_f / half_f; + int m = 8 - n % 8; + x_f += m * half_f; + + } else if (*p == '\r') { + + ; + + } else if (*p == '\033') { + p++; + if (*p != '[' && *p != ']') continue; + + if (*p == ']') { + p++; + while (*p != '\007') { + p++; + } + } + + else if (*p == '[') { + p++; + int top = 0, t2 = 0; + char buffer[32], buf2[16]; + while((!(*p > 'a' && *p < 'z') && !(*p >'A' && *p < 'Z')) && (*p != '\0')) { + buffer[top++] = *(p++); + } + if (*p == '\0') break; + buffer[top++] = *p; + buffer[top] = '\0'; + //printf("%s\n", buffer); + int i = 0; + while (i <= top) { + if (buffer[i] == ';') { + buf2[t2] = '\0'; + handle_ansi_code(buf2); + buf2[0] = '\0'; + t2 = 0; + } else { + buf2[t2++] = buffer[i]; + } + i++; + } + buf2[t2] = '\0'; + handle_ansi_code(buf2); + } + + } else { // 正常的字 + + char c; + if (size == 1) { + c = *(p + 1); + *(p + 1) = '\0'; + } + drawvfont(x_f, y_f, *(unsigned short*)p, clr); + if (size == 1) { + *(p + 1) = c; + } + x_f += (size == 1) ? fontsize / 2 : fontsize; + + } + + if (x_f >= l.w - fontsize) { + + y_f += fontsize; + x_f = 0; + + } + + if (y_f >= l.h - (d + 3) * fontsize) { /* FIXME: d加上输入框高度 */ + + int level = (y_f % fontsize == 0) ? fontsize : y_f % fontsize; + y_f -= level; + up(0, 0, l.w, l.h - d * fontsize, level); + + } + + p += size; + + } + free(ansi); + if (hasBox) { + subpos.w = ((x_f + fontsize + subsize.w) > l.w - fontsize) ? l.w - fontsize - subsize.w : x_f + fontsize; + subpos.h = y_f + fontsize; + area->set_pos(subpos); + this->lock.unlock(); + this->update_input(); + flush(area.get(), true); + } + } + + void CmdArea::handle_ansi_code(char *buffer) { + static std::vector v; + std::string cur = buffer; + char c = '\0'; + v.push_back(cur); + if (!cur.empty() && std::isalpha((c = cur.back()))) { + for ( const auto& elem: v ) { + + if (elem == "32m") { + Color clr = green; + set_color(clr); + } else if (elem == "34m") { + Color clr = blue; + set_color(clr); + } else if (elem == "0m" || elem == "00m") { + Color clr = white; + set_color(clr); + } else if (elem == "1m" || elem == "01m") { + if (v[0] == "40") { + ; + } + + if (v[1] == "33") { + //Color clr = yellow; + //set_color(clr); + } + } + std::cout << elem << " "; + + } + v.clear(); + std::cout << std::endl; + } + + } + +} diff --git a/lci/src/lci/Color.cpp b/lci/src/lci/Color.cpp new file mode 100644 index 0000000..247a6bf --- /dev/null +++ b/lci/src/lci/Color.cpp @@ -0,0 +1,8 @@ +#include "lci/Color.h" +namespace qing { + const Color black=Color(0,0,0); + const Color white=Color(255,255,255); + const Color green=Color(0,255,0); + const Color blue =Color(0,0,255); + const Color red =Color(255,0,0); +} diff --git a/lci/src/lci/CommonThread.cpp b/lci/src/lci/CommonThread.cpp new file mode 100644 index 0000000..6c023ff --- /dev/null +++ b/lci/src/lci/CommonThread.cpp @@ -0,0 +1,102 @@ + +#include +#include "lci/CommonThread.h" +namespace qing { +namespace lci{ + void CommonThread::thread_main() { + + while (chk() != SSHUT) { + /*进入回字形循环,如果不是进入关闭态 + 内层循环会一直进行。*/ + + if (chk() == SSTOP){ + /*内层循环,静止状态*/ + StopEvent(); + } + + if (chk() == SSTART) { + /*由静止状态退出时,如果进入开始状态 + 则进入单次的设置操作*/ + WakeEvent(); + } + + if (chk() == SRUNNING) { + /*由设置阶段退出时,如果是运行状态,则发出提示*/ + } + + while (chk() == SRUNNING) { + //进入运行态 + LoopEvent(); + } + + /*循环末尾,进行一次清理 + 由于之前可能是由静止态直接切换到关闭工作 + 在清理时需要检查成员变量是否是被设置过的*/ + ClearEvent(); + } + + }//入口 + + CommonThread::CommonThread(std::string name) { + /*构造函数,完成数据域的设置。*/ + this->label = name; + //创建线程的函数 + this->thread = new std::thread(&CommonThread::thread_main, this); + } + + //清除线程 + //使线程自主退出的函数必须放到外面或者子类叶子上, + //否则会导致关闭时子类已经被释放,进而导致调用不了 + CommonThread::~CommonThread(){ + if (this->thread){ + delete this->thread;//删除线程类 + } + + } //销毁线程 + + + //----------------------------------------------------------- + //访问器函数 + + void CommonThread::SetLabel(std::string name) { + //对线程名字的设置 + this->label = name; + } + + std::string& CommonThread::GetLabel() { + //对线程名字的获取 + return this->label; + } + + //----------------------------------------------------------- + //等待线程启动完毕 + //线程启动失败返回失败。线程启动成功或者现程结束返回成功。 + bool CommonThread::WaitStart(unsigned long n) { + for(unsigned long i=0; ichk(); + if (stat == SSTOP) return false; + else if (stat == SRUNNING || stat == SSHUT) return true; + else if (stat == SSTART) usleep(1); + }//按次循环 + return false; + }//等线程开始 + + //等线程关闭 + void CommonThread::WaitClose() { + thread->join(); + } + //----------------------------------------------------------- + + void CommonThread::StopEvent(){ + this->suspend(); + } + void CommonThread::WakeEvent(){ + this->run(); + } + void CommonThread::LoopEvent(){ + usleep(10000); + } + void CommonThread::ClearEvent() { + } +}//lci +} diff --git a/lci/src/lci/Drawable.cpp b/lci/src/lci/Drawable.cpp new file mode 100644 index 0000000..827febc --- /dev/null +++ b/lci/src/lci/Drawable.cpp @@ -0,0 +1,359 @@ +#include +#include "lci/Drawable.h" +namespace qing { + + /* FIXME: 字体宽高分开传入 */ + Drawable::Drawable(int w, int h, int x, int y, int rotate, int fontsize) /* 构造可绘制对象 */ + : w(w), h(h), x(x), y(y), rotate(rotate), font_w(fontsize), font_h(fontsize) { + zn = zzhinumber; /* 初始化字库 */ + vennum = ttunumber; + } + + + Rectangle Drawable::get_size() { /* 获取表示尺寸的矩形 */ + if (rotate == 0 || rotate == 2) { + return Rectangle(w, h); + } else if (rotate == 1 || rotate == 3) { + return Rectangle(h, w); + } + throw Drawable::InvalidRotateMode(); + } + + Rectangle Drawable::get_pos() { /* 获取表示位置的矩形 */ + return Rectangle(x, y); + } + + void Drawable::set_pos(Rectangle rect) { /* 设置表示位置的矩形 */ + x = rect.w; + y= rect.h; + } + + Color Drawable::get_color(int x, int y) { /* 获取颜色 */ + + if (rotate == 0) + { + return _get(x, y); + } + + else if (rotate == 1) + { + return _get(y, h - x - 1); + } + + else if (rotate == 2) + { + return _get(w - x - 1, h - y - 1); + } + + else if (rotate == 3) + { + return _get(w - y - 1 , x); + } + + throw Drawable::InvalidRotateMode(); + } + + /* 设置颜色 */ + void Drawable::set_color(Color &color) { + this->clr = color; + } + + /* 设置字体大小 */ + void Drawable::FontSize(int fontsize) { + font_w = fontsize; + font_h = fontsize; + } + + /* 获取字体大小 */ + int Drawable::FontSize_get() { + return font_w; + } + + /* 获取字体颜色 */ + Color &Drawable::getFontsColor() { + return this->clr; + } + + + void Drawable::point(int x, int y, Color &clr) { /* 绘制点 */ + + if (rotate == 0) + { + _p(x, y, clr); + } + + else if (rotate == 1) + { + _p(y, h - x - 1, clr); + } + + else if (rotate == 2) + { + _p(w - x - 1, h - y - 1, clr); + } + + else if (rotate == 3) { + _p(w - y - 1 , x, clr); + } + + } + + void Drawable::line(int x1, int y1, int x2, int y2, Color &clr) /* 绘制线 */ + { + double t, dt; + double i, j; + i = x1; + j = y1; + if (std::fabs(x2 - x1) > std::fabs(y2 - y1)) + dt = 1 / (std::fabs(x2 - x1) * 2.0); + else + dt = 1 / (std::fabs(y2 - y1) * 2.0); + for (t = 0; t <= 1.0; t += dt) { + point((int)(i+0.5), (int)(j+0.5), clr); + i += dt * (x2 - x1); + j += dt * (y2 - y1); + } + } + + void Drawable::rectangle(int x, int y, int w, int h, Color &clr) /* 绘制矩形 */ + { + line(x, y, x+w, y, clr); + line(x+w, y, x+w, y+h, clr); + line(x+w, y+h, x, y+h, clr); + line(x, y+h, x, y, clr); + } + + void Drawable::rectangle_fill(int x, int y, int w, int h, Color &clr) /* 填充矩形 */ + { + for (int i = 0; i < h; ++i) + { + line(x, y+i, x+w, y+i, clr); + } + } + +// void Drawable::up(int x, int y, int w, int h, int level) /* 画面上移 */ +// { +// switch (rotate) +// { +// case 0: { +// _up(x, y, w, h, level); +// break; +// } +// case 1: { +// _left(y, x, h, w, level); +// break; +// } +// case 2: { +// _down(this->w - x - w, this->h - y - h, w, h, level); +// break; +// } +// case 3: { +// _right(this->w - y - h, x, h, w, level); +// break; +// } +// } +// } +// +// void Drawable::down(int x, int y, int w, int h, int level) /* 画面下移 */ +// { +// switch (rotate) +// { +// case 0: { +// _down(x, y, w, h, level); +// break; +// } +// case 1: { +// _right(y, x, h, w, level); +// break; +// } +// case 2: { +// _up(this->w - x - w, this->h - y - h, w, h, level); +// break; +// } +// case 3: { +// _left(this->w - y - h, x, h, w, level); +// break; +// } +// } +// } +// +// void Drawable::left(int x, int y, int w, int h, int level) /* 画面左移 */ +// { +// switch (rotate) +// { +// case 0: { +// _left(x, y, w, h, level); +// break; +// } +// case 1: { +// _down(y, x, h, w, level); +// break; +// } +// case 2: { +// _right(this->w - x - w, this-> h - y - h, w, h, level); +// break; +// } +// case 3: { +// _up(this->w - y - h, x, h, w, level); +// break; +// } +// } +// } +// +// void Drawable::right(int x, int y, int w, int h, int level) /* 画面右移 */ +// { +// switch (rotate) +// { +// case 0: { +// _right(x, y, w, h, level); +// break; +// } +// case 1: { +// _up(y, x, h, w, level); +// break; +// } +// case 2: { +// _left(this->w - x - w, this->h - y - h, w, h, level); +// break; +// } +// case 3: { +// _down(this->w - y - h, x, h, w, level); +// break; +// } +// } +// } + + /* FIXME: 单独放在一个文件里 */ + void Drawable::test() { /* 绘制测试图案 */ + + Rectangle size = get_size(); + Color base; + int k1 = -1; + + for (int y=0; y < size.h; ++y) { + Color cur = base; + int k2 = -1; + + for (int x=0; x < size.w; x++) { + + if (cur.r == 0) k2 = 1; + else if (cur.r == 255) k2 = -1; + + cur.r += k2; + cur.g += k2; + cur.b += k2; + + point(x, y, cur); + + } + + if (base.r == 0) k1 = 1; + else if (base.r == 255) k1 = -1; + + base.r += k1; + base.g += k1; + base.b += k1; + } + } + + /* 移动测试 */ +// void Drawable::test1() +// { +// Rectangle size = get_size(); +// up(0, 0, size.w, size.h, 10); +// down(0, 0, size.w, size.h, 5); +// left(0, 0, size.w, size.h, 10); +// right(0, 0, size.w, size.h, 5); +// } + + unsigned char *Drawable::drawvect(int x, int y, unsigned char *vect, int width, int high, Color &clr) + // x, y是左上角坐标,vect指向矢量图数据,width和high分别代表要绘制的图的宽和高(好像宽需要=高) + { + if (!vect) return nullptr; + int i = 0, j = 1; // 指向第一对数字 + unsigned char ix, iy; // 从数组取出的第一对坐标放在这 + double x1, y1;//, x2, y2; // 绘制直线的实数的坐标 + if (high == 0) high = width; // 调节高宽 + int ii1, jj1, ii2, jj2; // 最后算出的绘制直线的坐标 + int isend = 0; //是否到达曲线尾 + int isallend = 0; // 是否结束整个图像 + do { + ix = vect[i]; + iy = vect[j]; + isend = ix & 1; // 奇数代表曲线尾 + isallend = iy & 1; // 奇数代表整个图像结束 + if (isallend) { + i += 2; + break; // 整个图像结束返回 + } + if (isend) { // 如果这里曲线结束什么也不画进到下一条曲线 + i += 2; + j += 2; + continue; + } + ix /= 2; + iy /= 2; + x1 = ix; + y1 = iy; + x1 = width * x1 / 128.0; + y1 = high * y1 / 128.0; + ii1 = (int)(x1 + x); + jj1 = (int)(y1 + y); + int k; + for (k = 0; k < 100000; k++) { + //x2 = x1; + //y2 = y1; + ii2 = ii1; + jj2 = jj1; + i += 2; + j += 2; + ix = vect[i]; + iy = vect[j]; + isend = ix & 1; //奇数代表曲线尾 + isallend = iy & 1; //奇数代表整个图像结束 + ix /= 2; + iy /= 2; + x1 = ix; + y1 = iy; + x1 = width * x1 / 128.0; + y1 = high * y1 / 128.0; + ii1 = (int)(x1 + x); + jj1 = (int)(y1 + y); + line(ii1, jj1, ii2, jj2, clr); + if (isend || isallend) + break; + } + i += 2; //指向下一条曲线 + j += 2; + } while (!isallend); + return vect + i; + } + + void Drawable::drawvfont(int x, int y, unsigned short z, Color &clr) { + int i, j, k, ii; + j = -1; + for (i = 0; i < zn; i++) { + if (chss[i] == z) { + j = i; + break; + } + } + if (j < 0) return; + k = 0; + for (i = 0; i < vennum; i++) { + if (k == j) + break; + for (ii =i; ii +#include +#include +#include +#include +#include +#include +#include "lci/FrameBuf.h" +#include "lci/Area.h" +namespace qing { + + /* 这个构造函数太长,应该还可以再提炼一下 */ + FrameBuf::FrameBuf(const char *path, int rotate, int fontsize) + : Drawable(0, 0, 0, 0, rotate, fontsize) { + + //int open_dev(const char *path) + { + if (d != -1) { + throw std::runtime_error("Device already opening."); + } + + if ((d = open(path, O_RDWR)) == -1) { + throw std::runtime_error("Error openning framebuffer device"); + } + } + + //void init_info() + { + if (ioctl(d, FBIOGET_VSCREENINFO, &var_info) < 0) { + close(d); + d=-1; + throw std::runtime_error("Error reading screen variable information"); + } + + if (ioctl(d, FBIOGET_FSCREENINFO, &fix_info) < 0) { + close(d); + d=-1; + throw std::runtime_error("Error reading fixed information"); + } + } + + std::cout << "res:\t\t" << var_info.xres << "," << var_info.yres << std::endl; + std::cout << "res_virtual:\t" << var_info.xres_virtual << "," << var_info.yres_virtual << std::endl; + std::cout << "bpp:\t\t" << var_info.bits_per_pixel << std::endl; + + w = var_info.xres_virtual; + h = var_info.yres_virtual; + + + /* + * 不知道用不用虚拟尺寸,目前是用,在虚拟机上的效果不清楚。我在虚拟机上见过虚拟比实际小的。 + * + * 而我的机器人上则是虚拟尺寸比物理尺寸大。 + */ + //long v_size = (long)var_info.xres * var_info.yres * var_info.bits_per_pixel / 8; + long v_size = (long)var_info.xres_virtual * var_info.yres_virtual * var_info.bits_per_pixel / 8; + + long logic_size = (long)fix_info.smem_len; + int delta = logic_size - v_size; + // 如果实长大于虚长,那么就证明这个缓冲区存在过量 + double delta_x = (double)delta / var_info.xres; + double delta_y = (double)delta / var_info.yres; + double delta_bpp = (double)delta / var_info.bits_per_pixel; + + + std::cout << "virtual size:\t" << v_size << std::endl; + std::cout << "logic size:\t" << logic_size<< std::endl; + std::cout << "delta: \t" << delta<< std::endl; + std::cout << "delta x: \t" << delta_x<< std::endl; + std::cout << "delta y: \t" << delta_y<< std::endl; + std::cout << "delta bpp: \t" << delta_bpp<< std::endl; + if (delta == 0) { + // 如果实长和虚长是相等的,那么就证明这个缓冲区无过量 + x_over = 0; + } + + else if (delta > 0) { + + // 是否存在小数差距 + if (delta_y - (int)delta_y != 0) { + //close(d); + //d=-1; + //throw std::runtime_error("y_over"); + x_over = delta_y * 8 / var_info.bits_per_pixel; + } + else { + // 计算横轴过量 + x_over = delta_y * 8 / var_info.bits_per_pixel; + } + } + + // 计算行跳量 + line_jump = (var_info.xres_virtual + x_over) * var_info.bits_per_pixel / 8; + + + // + buf = (char*)mmap(buf, fix_info.smem_len, PROT_WRITE, MAP_SHARED, d, fix_info.smem_start); + if (buf == MAP_FAILED) { + close(d); + d=-1; + throw std::runtime_error("Failed mapping of the frame buffer to memory"); + } + + clear(); + } + + FrameBuf::~FrameBuf() { /* 析构函数 */ + clear(); + munmap(buf, fix_info.smem_len); + close(d); + } + + /* 获取像素比特 */ + int FrameBuf::get_bpp() { return var_info.bits_per_pixel; } + + /* 32位像素比特的绘制点 */ + void FrameBuf::p32(__u32 ux, __u32 uy, Color &color) + { + if (ux < 0 || ux >= var_info.xres_virtual + || uy < 0 || uy >= var_info.yres_virtual) + return; + char *p = buf + (uy * line_jump + ux * 4); + *p++ = color.b; + *p++ = color.g; + *p++ = color.r; + } + + /* 16位像素比特的绘制点 */ + void FrameBuf::p16(__u32 ux, __u32 uy, Color &color) { + if (ux < 0 || ux >= var_info.xres_virtual + || uy < 0 || uy >= var_info.yres_virtual) + return; + char *p = buf + (uy * line_jump + ux * 2); + uint16_t pixel_value = 0; + pixel_value |= (color.r >> 3) << 11; //5 + pixel_value |= (color.g >> 2) << 5; //6 + pixel_value |= (color.b >> 3); //5 + *reinterpret_cast(p) = pixel_value; + } + + /* 获取16像素比特时的像素颜色 */ + Color FrameBuf::get16(__u32 ux, __u32 uy) { + char *p = buf + uy * line_jump + ux * get_bpp() / 8; + unsigned char r = (*(short*)p >> 11) & 0x1F; + unsigned char g = (*(short*)p >> 5) & 0x3F; + unsigned char b = (*(short*)p) & 0x1F; + return Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2)); + } + + /* 获取32位像素比特时的像素颜色 */ + Color FrameBuf::get32(__u32 ux, __u32 uy) { + char *p = buf + uy * line_jump + ux * get_bpp() / 8; + unsigned char r = *(p++); + unsigned char g = *(p++); + unsigned char b = *(p++); + return Color(r, g, b); + } + + /* 覆盖获取点方法 */ + Color FrameBuf::_get(int x, int y) { + switch (get_bpp()) { + case 16: + return get16((__u32)x, (__u32)y); + case 32: + return get32((__u32)x, (__u32)y); + } + throw FrameBuf::UnknowBPP(); + } + + /* 覆盖绘制点方法 */ + void FrameBuf::_p(int x, int y, Color &clr) { + + int bpp = get_bpp(); + if (bpp == 16) { + p16((__u32)x, (__u32)y, clr); + } else if (bpp == 32) { + p32((__u32)x, (__u32)y, clr); + } + + } + + /* 覆盖上移方法 */ +// void FrameBuf::_up(int x, int y, int w, int h, int level){ +// int l = get_bpp() / 8; +// int oneline = w * l; +// char *s = buf + y * line_jump + x * l; +// char *d = s + level * line_jump; +// for (int _ = 0; _ < h - level; ++_) { +// memcpy(s, d, oneline); +// s += line_jump; +// d += line_jump; +// } +// for (int _ = 0; _ < level; ++_) { +// memset(s, 0, oneline); +// s += line_jump; +// } +// } +// +// /* 覆盖下移方法 */ +// void FrameBuf::_down(int x, int y, int w, int h, int level) { +// int l = get_bpp() / 8; +// int oneline = w * l; +// long d = level * line_jump; +// char *start = buf + y * line_jump + x * l; +// char *src = start + h * line_jump; +// char *dist = src - d; +// +// do { +// +// src -= line_jump; +// dist -= line_jump; +// memcpy(src, dist, oneline); +// +// } while(dist != start); +// +// do { +// +// src -= line_jump; +// memset(src, 0, oneline); +// +// } while (src != start); +// +// } +// +// /* 覆盖左移方法 */ +// void FrameBuf::_left(int x, int y, int w, int h, int level) { +// +// int l = get_bpp() / 8; +// int d = level * l; +// int length = (w - level) * l; +// char *start = buf + y * line_jump + x * l; +// char *src = start + h * line_jump; +// do { +// src -= line_jump; +// memcpy(src, src + d, length); +// memset(src + length, 0, d); +// } while (src != start); +// +// } +// +// /* 覆盖右移方法 */ +// /*!*/ +// void FrameBuf::_right(int x, int y, int w, int h, int level) { +// int l = get_bpp() / 8; +// int d = level * l; +// int length = (w - level) * l; +// char *start = buf + y * line_jump + x * l; +// char *p = start + h * line_jump; +// char *tmp = new char[length]; +// do { +// p -= line_jump; +// char *src = p + d; +// memcpy(tmp, p, length); +// memcpy(src, tmp, length); +// memset(p, 0, d); +// } while (p != start); +// delete[] tmp; +// } + + /* 清理方法 */ + void FrameBuf::clear() { + memset(buf, 0, fix_info.smem_len); + } + + /* 将一个别的可绘制区域刷新到这个上面,也许可以绘制标头 */ + void FrameBuf::flush(Drawable *n, bool border) { + Color &clr = n->getFontsColor(); + Rectangle size = n->get_size(); + Rectangle pos = n->get_pos(); + + if (border) { + rectangle(pos.w-1, pos.h-1, size.w+2-1, size.h+2-1, clr); + rectangle(pos.w-2, pos.h-2, size.w+4-1, size.h+4-1, clr); + rectangle_fill(pos.w-2, pos.h-_HEAD_LEN-2+1, size.w+4-1, _HEAD_LEN, clr); + } + + Area *p = dynamic_cast(n); + if (p != nullptr) return; + + // too slow 太慢 + for (int x = 0; x < size.w; ++x) { + for (int y = 0; y < size.h; ++y) { + Color color = n->get_color(x, y); + point(pos.w + x, pos.h + y, color); + } + } + } + +} diff --git a/lci/src/lci/InputBox.cpp b/lci/src/lci/InputBox.cpp new file mode 100644 index 0000000..d436fd8 --- /dev/null +++ b/lci/src/lci/InputBox.cpp @@ -0,0 +1,57 @@ +#include "lci/utf8.h" +#include "lci/ansi.h" +#include "lci/InputBox.h" +namespace qing { + InputBox::InputBox(Drawable *d, int w, int h, int x, int y, int rotate = 0, int fontsize=18): Area(d, w, h, x, y, rotate, fontsize) { + this->d = d; + } + + void InputBox::print(char *utf8, int _line) { + + char *ansi = utf8::to_ansi(utf8); + char *p = ansi; + int fontsize = FontSize_get(); + int x_f = 0, y_f = _line * fontsize; + Rectangle l = get_size(); + while (1) { + + //int size = ansi::size_gb18030((unsigned char*)p, 4); + + /* 这个汉字库应该是 GB2312 的 */ + int size = ansi::size_gb2312(*(unsigned char *)p); + + if (*p == '\0') { + + break; + + } else { // 正常的字 + + char c; + if (size == 1) { + c = *(p + 1); + *(p + 1) = '\0'; + } + + drawvfont(x_f, y_f, *(unsigned short*)p, clr); + + if (size == 1) { + *(p + 1) = c; + } + x_f += (size == 1) ? fontsize / 2 : fontsize; + + } + + if (x_f >= l.w - fontsize) { + + break; + + } + + p += size; + + } + free(ansi); + int y2 = y_f + fontsize-2; + line(x_f + 2, y2, x_f + fontsize - 4, y2, clr); + } +} diff --git a/lci/src/lci/KeyboardEvent.cpp b/lci/src/lci/KeyboardEvent.cpp new file mode 100644 index 0000000..2489f5d --- /dev/null +++ b/lci/src/lci/KeyboardEvent.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include +#include "lci/KeyboardEvent.h" +namespace qing { + /* FIXME: 划分代码块 */ + KeyboardEvent::KeyboardEvent() { + const char *path = "/dev/input"; + struct dirent *dir; + DIR *p = opendir(path); + if(p == NULL) throw std::runtime_error("opendir"); + while ((dir = readdir(p)) != NULL) { + if (!is_event_with_number(dir->d_name)) continue; + char full_name[257] = {'\0'}; + snprintf(full_name, sizeof(full_name), "%s/%s", path, dir->d_name); + struct stat buf; + if (stat(full_name, &buf) == -1) { + throw std::runtime_error("stat"); + } + + if(S_ISDIR(buf.st_mode)) continue; + + else if (pool.find(std::string(full_name)) == pool.end()){ + int d = open(full_name, O_RDONLY); + if (d == -1) { + ; + } else { + set_noblocking(d); + pool.insert(std::make_pair(std::string(full_name), d)); + } + } + } + closedir(p); + } + KeyboardEvent::~KeyboardEvent() { + std::map::iterator it; + for (it = pool.begin(); it != pool.end(); ++it) { + close(it->second); + } + } + + /* FIXME: 传入堵塞时间 */ + struct input_event KeyboardEvent::get() { + fd_set set; + FD_ZERO(&set); + for (auto it = pool.begin(); it != pool.end(); ++it) { + FD_SET(it->second, &set); + } + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 60000; + if (select(this->maxd()+1, &set, NULL, NULL, &timeout) == -1) { + throw std::runtime_error("select"); + } + + for (auto it = pool.begin(); it != pool.end(); ++it) { + if (it->second != -1 && FD_ISSET(it->second, &set)) { + struct input_event ev; + if (read(it->second, &ev, sizeof(ev)) == sizeof(ev)) { + return ev; + } + } + } + throw NoEvent(""); + } + bool KeyboardEvent::is_event_with_number(const char *filename) { + size_t len = strlen(filename); + if (len <= 5) return false; + + if (strncmp(filename, "event", 5) != 0) + return false; + + for (size_t i=5; isecond; + std::map::iterator it; + for (it = pool.begin(); it != pool.end(); ++it) + if (it->second > maxValue) + maxValue = it->second; + return maxValue; + } +} diff --git a/lci/src/lci/ansi.cpp b/lci/src/lci/ansi.cpp new file mode 100644 index 0000000..35ca0b0 --- /dev/null +++ b/lci/src/lci/ansi.cpp @@ -0,0 +1,22 @@ +#include "lci/ansi.h" +namespace qing{ + /* 这个函数并不完全 + int ansi::size_gb18030(unsigned char *p, size_t maxLen) { + if (*p < 0x80) { + return 1; + } else if ((*p > 0x81 && *p <= 0xFE) && + ((*(p+1) >= 0x40 && *(p+1) <= 0x7E) || (*(p+1) >= 0x80 && *(p+1) <= 0xFE))) { + return 2; + } else if (maxLen >= 4 && (*p == 0x90 || *p == 0x91 || *p == 0xE8 || *p == 0xE9 || + (*p >= 0x8E && *p <= 0xEF) || (*p >= 0xF8 && *p <= 0xFB)) && + (*(p+1) & 0xC0) == 0x80 && (*(p+2) & 0xC0) == 0x80 && (*(p+3) & 0xC0) == 0x80) { + return 4; //注意这里是简化判断 + } else { + throw ansi::WrongLength(); + } + } + */ + int ansi::size_gb2312(unsigned char first_byte) { + return (first_byte >= 0xA1 && first_byte <= 0xFE) ? 2 : 1; + } +} diff --git a/lci/src/lci/fsm.cpp b/lci/src/lci/fsm.cpp new file mode 100644 index 0000000..0669972 --- /dev/null +++ b/lci/src/lci/fsm.cpp @@ -0,0 +1,45 @@ + +#include"lci/fsm.h" +namespace qing{ +namespace lci{ + Fsm::Fsm(){ + this->stat = SSTOP; + } + + //------------------------------------------------------ + enum Stat Fsm::chk() { + std::unique_lock lck(this->lock); + return this->stat; + }//check + + void Fsm::suspend(){ + std::unique_lock lck(this->lock); + cv.wait(lck); + }//suspend + + //------------------------------------------------------- + void Fsm::wake() { + std::unique_lock lck(this->lock); + this->stat = SSTART; + cv.notify_one(); + }//wake + + void Fsm::stop() { + std::unique_lock lck(this->lock); + this->stat = SSTOP; + cv.notify_one(); + }//stop + + void Fsm::shut() { + std::unique_lock lck(this->lock); + this->stat = SSHUT; + cv.notify_one(); + }//close + + void Fsm::run() { + std::unique_lock lck(this->lock); + this->stat = SRUNNING; + cv.notify_one(); + }//run +}//lci +}//qing diff --git a/lci/src/lci/ku500.cpp b/lci/src/lci/ku500.cpp new file mode 100644 index 0000000..a8ef913 --- /dev/null +++ b/lci/src/lci/ku500.cpp @@ -0,0 +1,20697 @@ +unsigned char ttu[]={1,1,61,38,60,162,60,40,66,40,66,162,61,162,60,192,60,218,66,218, +66,192,61,193,62,16,21,76,102,18,61,77,10,94,119,94,10,164,119,164, +42,44,29,218,98,44,85,219,90,90,96,76,96,64,86,52,74,48,60,48, +46,52,30,70,30,86,36,100,42,108,54,118,72,130,92,150,98,160,100,180, +94,200,76,212,56,214,40,210,28,196,28,182,33,166,64,26,65,243,20,50, +14,62,12,66,10,72,8,86,8,98,12,116,16,122,24,130,36,130,46,122, +50,108,50,80,48,60,40,50,30,46,21,50,82,138,76,148,74,160,74,174, +74,186,78,202,84,210,94,214,104,212,112,202,116,186,116,158,110,138,100,130, +90,130,83,138,98,44,27,217,122,190,118,204,114,208,104,212,94,210,82,202, +64,176,44,142,32,108,28,82,30,62,40,50,50,46,62,48,70,58,72,72, +68,92,62,104,52,114,40,122,26,128,16,144,10,166,12,186,20,200,32,210, +44,214,58,210,70,200,82,180,88,164,92,144,93,122,74,122,113,123,16,76, +26,70,34,62,40,50,42,32,38,24,34,22,28,22,26,24,26,30,32,34, +36,38,40,36,30,24,30,30,36,28,34,24,37,35,112,238,100,226,88,212, +82,200,74,184,68,164,64,146,62,126,64,104,68,88,74,72,82,56,90,42, +98,32,106,24,115,17,12,16,28,32,42,52,50,66,58,84,62,100,64,122, +64,146,58,174,50,194,38,212,26,226,15,241,64,64,64,128,117,96,10,96, +64,128,11,162,62,192,64,128,117,161,12,126,119,126,66,66,67,187,28,194, +40,202,28,200,28,192,38,196,40,204,42,216,38,230,28,240,17,247,8,126, +119,127,32,218,32,190,20,196,20,210,32,218,44,212,44,198,34,192,20,206, +42,204,28,214,38,196,20,198,39,215,114,24,15,237,64,214,74,212,88,204, +96,192,102,182,106,166,110,148,110,130,108,108,104,86,98,72,88,58,80,50, +72,48,64,46,50,50,40,58,32,68,26,80,20,102,18,124,20,154,26,178, +36,196,50,210,65,215,30,62,54,60,64,52,65,212,30,212,101,213,28,92, +24,86,24,74,34,56,48,48,68,46,84,52,96,62,102,74,100,104,84,128, +74,138,62,150,24,192,16,212,104,212,111,175,30,88,26,74,32,56,48,48, +64,46,80,52,94,70,96,94,86,112,68,122,50,124,80,130,98,146,104,168, +100,190,88,206,76,212,60,214,44,212,36,208,30,204,26,190,29,171,86,44, +10,162,119,162,86,44,87,214,52,214,117,215,106,52,30,52,26,134,42,118, +52,112,78,112,96,126,104,150,102,182,86,208,60,214,34,208,26,192,29,169, +96,74,96,62,86,48,68,46,52,52,34,68,22,98,20,118,20,162,22,172, +30,190,42,206,56,214,76,214,96,202,108,182,108,150,102,132,86,116,72,112, +60,112,48,118,38,128,25,151,18,86,28,60,38,52,108,52,96,74,90,84, +78,108,70,128,62,152,57,219,68,128,88,116,100,104,108,88,108,76,102,64, +96,58,80,48,68,46,54,46,38,52,28,62,22,72,20,86,24,100,30,110, +40,118,52,124,76,132,88,138,96,144,104,154,108,166,108,182,102,196,94,204, +80,212,64,214,46,212,32,204,24,196,16,182,16,168,20,152,28,142,38,134, +53,125,102,84,100,98,96,116,90,128,74,144,58,148,42,146,30,138,20,122, +16,100,18,78,26,62,36,52,56,46,74,48,88,56,100,72,108,94,110,116, +108,136,106,158,98,182,82,204,70,210,54,214,40,212,30,202,29,185,72,102, +52,102,52,120,72,120,72,104,52,106,72,110,52,116,73,118,72,214,72,196, +52,196,52,214,72,214,66,196,64,214,60,196,58,214,54,196,55,215,54,106, +68,106,58,120,58,112,68,106,68,120,54,120,55,106,68,208,58,208,56,202, +66,198,64,212,54,212,54,196,68,196,68,216,57,243,106,42,22,128,107,213, +8,102,119,102,8,154,119,155,20,42,106,128,21,215,28,106,20,86,22,68, +36,52,56,44,72,44,92,50,104,62,108,84,104,104,100,110,94,118,62,142, +63,174,70,214,52,206,70,206,52,196,70,196,70,214,52,214,53,197,90,92, +84,80,74,78,64,84,56,96,48,114,44,136,44,158,50,170,58,174,68,170, +78,154,84,138,95,74,84,138,82,164,90,174,98,172,110,160,116,144,118,112, +116,84,104,62,92,52,74,46,52,50,28,72,16,106,14,136,20,170,34,196, +52,212,74,214,94,208,106,196,119,181,39,214,80,214,123,214,16,214,60,44, +105,214,34,148,87,148,2,214,39,215,4,212,72,212,88,210,100,204,110,194, +116,180,116,164,112,150,102,138,92,130,84,128,76,126,66,124,80,120,94,114, +104,104,108,90,108,76,102,62,92,54,82,50,68,48,9,48,24,212,25,48, +66,124,25,125,108,46,116,88,106,64,94,52,82,46,68,46,48,50,34,62, +26,74,18,88,14,108,10,126,12,142,14,164,18,180,26,194,36,204,44,210, +54,214,66,216,78,214,90,210,102,200,110,186,117,169,6,212,50,212,70,210, +86,202,100,190,108,174,112,158,116,138,114,112,110,88,102,72,88,58,74,52, +62,48,7,48,24,212,25,49,114,80,102,48,9,48,116,176,104,212,9,212, +24,48,25,212,24,124,89,124,88,96,89,155,120,80,106,48,9,48,6,212, +55,212,24,212,25,48,92,156,93,100,24,126,93,127,104,88,94,62,88,52, +74,48,56,48,40,56,26,72,18,90,14,110,10,132,12,150,16,170,20,182, +30,198,44,210,60,214,80,212,92,206,104,194,104,144,75,145,16,48,37,48, +92,48,113,48,16,212,37,212,92,212,113,212,26,48,27,212,102,48,103,212, +26,126,103,127,24,48,105,48,24,212,105,212,64,48,65,213,40,48,123,48, +82,48,82,210,78,226,70,236,62,240,50,244,34,244,22,238,18,232,15,221, +20,48,41,48,20,214,41,214,30,48,31,214,90,48,109,48,94,214,115,214, +30,146,101,48,104,214,57,111,18,48,47,48,16,214,104,214,113,194,32,214, +33,49,18,214,18,46,62,212,104,46,105,214,10,214,27,214,96,214,113,215, +22,214,22,46,106,208,107,48,10,214,35,214,94,48,119,49,66,214,78,212, +90,206,100,196,108,184,112,172,116,158,118,142,118,120,116,102,110,84,102,68, +94,58,86,52,76,48,66,46,52,48,40,56,30,66,20,86,14,106,12,122, +12,140,14,156,18,170,24,188,32,198,44,208,52,212,67,215,26,212,26,48, +74,48,88,52,100,58,108,68,112,76,114,86,114,98,108,112,102,120,94,126, +78,132,74,132,27,132,16,212,37,213,114,216,110,226,104,228,98,228,94,224, +88,216,84,204,78,188,72,174,66,170,54,168,44,170,38,178,36,186,36,194, +40,202,48,210,58,214,70,214,82,210,92,206,100,196,110,180,116,160,118,136, +116,108,108,82,100,66,90,56,78,48,62,46,50,48,36,56,28,68,18,84, +14,100,10,124,12,146,14,164,20,178,26,196,38,204,44,208,49,211,26,212, +26,48,66,48,78,50,90,54,98,58,104,66,108,76,108,88,106,102,100,112, +90,122,80,124,70,126,58,128,27,128,122,212,102,212,71,128,14,212,37,213, +102,48,104,84,98,68,90,56,80,50,68,46,56,46,42,48,28,58,20,68, +16,78,16,90,18,100,24,108,32,116,40,120,54,126,64,128,72,130,82,132, +90,136,98,142,104,150,108,162,110,174,108,186,100,200,94,206,78,214,70,214, +54,214,38,208,30,202,22,190,16,176,14,168,23,215,16,66,20,48,106,48, +113,68,62,48,63,212,40,212,87,213,22,48,22,178,24,192,28,200,34,206, +44,212,58,214,70,214,82,210,96,200,104,182,104,174,105,48,94,48,115,48, +12,48,31,49,12,48,31,48,96,48,117,48,20,48,60,214,107,49,4,48, +25,48,54,48,75,48,104,48,125,48,14,48,40,216,64,48,84,216,115,49, +18,48,41,48,92,48,113,48,14,212,37,212,94,212,115,212,28,48,105,212, +102,48,25,213,12,48,39,48,94,48,119,48,46,212,81,212,64,212,64,150, +25,48,64,150,107,49,24,66,34,48,108,48,18,214,94,214,109,193,112,20, +54,20,54,234,113,235,24,34,109,247,16,20,74,20,74,234,17,235,28,46, +64,20,99,47,0,252,127,253,22,14,73,37,120,192,120,200,118,206,112,212, +102,212,98,210,96,206,94,124,92,118,88,112,82,108,78,106,70,104,62,104, +50,106,38,110,30,116,26,122,24,128,23,136,96,144,82,146,66,148,52,152, +38,156,30,162,22,170,18,180,16,190,18,200,24,206,34,212,50,214,64,212, +78,206,97,195,8,48,26,46,27,214,26,150,34,134,42,122,48,116,56,112, +66,108,76,106,86,108,94,112,100,118,104,128,110,142,110,158,110,172,106,188, +96,204,82,212,66,214,50,212,40,206,34,198,27,185,100,138,102,128,100,120, +92,112,82,108,72,104,58,106,44,110,36,118,28,128,22,138,20,152,20,166, +20,178,24,188,30,198,42,208,52,214,72,216,86,212,98,204,104,194,111,183, +78,48,92,48,102,42,102,210,121,208,102,132,92,120,80,112,70,108,54,108, +40,112,30,122,26,132,20,146,20,160,20,174,24,192,34,202,46,212,60,214, +76,210,88,200,103,183,108,186,96,204,86,212,70,216,54,214,38,206,28,194, +20,180,18,166,20,148,26,132,34,120,46,110,60,104,70,104,82,108,98,118, +104,128,108,142,108,154,108,158,21,159,116,74,116,62,110,52,96,48,80,48, +70,52,62,56,54,64,50,74,51,212,34,212,67,212,14,106,101,107,40,166, +32,158,26,152,24,144,26,134,30,122,40,112,50,108,66,106,80,110,88,116, +98,110,108,108,119,108,88,116,94,124,96,136,96,148,92,160,82,170,70,174, +54,172,46,170,40,166,34,174,28,178,26,186,30,192,42,196,56,196,70,196, +80,198,90,200,102,204,108,210,110,220,108,232,100,240,94,246,84,250,68,250, +52,250,34,246,24,238,18,232,16,222,20,214,26,208,34,204,38,202,41,197, +16,48,18,48,26,46,30,40,31,212,16,212,45,212,30,132,48,114,62,108, +74,106,88,108,98,116,102,128,103,212,84,212,117,213,72,60,58,56,72,52, +58,46,72,46,72,62,58,62,59,46,40,106,50,106,64,100,65,214,40,214, +89,215,98,64,98,46,84,46,84,64,98,64,84,54,98,52,85,48,56,106, +80,106,90,102,90,214,88,230,80,240,70,246,56,250,48,250,38,248,30,242, +26,236,23,231,10,48,24,48,34,42,35,214,20,214,51,214,70,106,111,106, +92,106,35,172,80,212,121,212,100,212,61,145,26,48,50,46,64,40,65,214, +26,214,103,215,4,214,33,214,4,106,18,104,19,214,18,140,24,126,32,114, +40,108,50,106,58,108,64,112,66,120,67,214,52,214,81,214,94,214,127,214, +110,214,110,116,106,108,100,106,94,106,84,108,78,112,72,120,67,131,10,212, +43,212,10,106,26,106,27,210,26,122,44,116,64,110,76,106,84,106,90,114, +92,122,93,212,74,212,111,213,64,216,80,212,94,204,104,192,110,174,112,158, +108,140,100,124,90,112,76,106,64,104,52,106,38,112,28,122,22,132,16,146, +14,158,16,172,20,184,26,196,34,206,48,214,65,217,8,108,24,108,30,106, +31,250,8,250,53,250,30,134,38,126,46,118,52,112,64,108,74,108,92,112, +102,120,110,134,112,146,114,162,110,182,104,194,96,202,86,212,74,214,62,214, +50,212,38,202,31,193,74,250,119,250,98,250,99,110,98,188,90,198,80,206, +68,212,54,214,40,210,28,200,20,188,16,172,16,156,20,138,26,126,36,116, +50,108,68,106,80,110,88,118,99,129,10,212,81,212,44,212,44,102,32,106, +11,108,44,150,52,138,60,126,70,118,80,108,92,106,106,108,117,117,104,134, +96,120,86,110,76,106,64,106,44,108,34,116,28,126,28,136,32,142,40,148, +52,154,70,160,86,164,100,170,104,178,106,188,102,200,96,208,86,212,70,214, +50,212,34,204,26,192,23,181,18,106,99,106,54,66,54,186,54,194,58,202, +64,208,74,212,86,212,96,206,102,198,107,187,82,106,94,104,98,102,98,212, +106,208,121,204,12,106,22,106,30,102,30,186,32,198,36,206,44,210,56,212, +68,210,80,204,88,196,94,188,99,179,26,104,62,212,103,105,16,106,40,216, +64,106,84,214,115,105,22,106,51,106,84,106,113,106,14,214,41,214,86,212, +115,212,34,106,101,212,98,106,27,215,78,108,119,108,12,108,53,108,98,108, +54,234,48,244,40,246,30,248,21,248,30,108,67,199,20,138,30,114,38,106, +102,106,18,214,96,214,109,179,108,18,98,18,90,22,84,30,80,42,80,110, +76,120,70,124,62,126,56,128,64,130,72,134,76,140,80,150,80,156,80,210, +82,220,88,230,94,234,102,236,109,237,64,0,65,255,20,18,34,20,44,28, +48,38,48,104,50,112,54,118,60,122,74,128,60,132,52,138,48,148,48,210, +46,220,40,230,30,236,19,239,12,36,16,26,22,16,28,10,38,8,46,10, +52,12,56,18,80,42,86,46,92,48,100,46,108,40,114,30,119,19,1,1, +52,14,53,152,54,186,55,213,112,14,113,74,146,14,147,75,64,74,199,74, +54,130,189,130,120,14,83,190,168,14,133,191,76,14,128,112,183,14,72,112, +185,112,72,156,185,156,128,112,129,207,186,14,69,210,112,48,96,20,56,20, +36,44,36,78,56,98,98,98,112,76,113,48,204,120,164,120,144,144,144,178, +164,202,202,202,220,180,220,144,205,121,200,98,198,130,186,154,164,184,136,202, +100,206,68,192,52,158,66,124,100,102,140,84,156,58,148,28,124,14,94,22, +80,44,80,68,100,98,213,207,128,14,129,73,226,14,206,44,194,70,186,98, +184,122,184,150,188,178,196,202,208,226,225,251,30,14,46,36,56,54,66,80, +70,104,72,126,72,150,66,182,58,204,46,228,33,251,64,86,128,108,195,86, +88,162,128,108,169,160,128,108,129,39,66,126,191,126,128,66,129,189,36,206, +50,206,48,224,46,236,41,247,66,126,191,127,122,190,128,188,134,190,138,198, +136,206,126,208,118,202,118,194,123,188,136,194,123,204,120,190,135,205,174,14, +81,241,144,16,120,16,106,24,94,32,84,52,78,74,76,102,76,128,78,152, +84,172,92,186,104,198,118,204,136,204,154,196,166,182,174,162,178,142,180,122, +180,88,174,54,162,32,154,24,145,17,90,50,118,38,144,16,145,207,76,36, +102,20,134,16,156,24,166,36,172,52,174,66,170,80,160,98,148,112,126,128, +108,142,94,154,82,170,78,184,76,198,181,199,80,28,104,18,124,16,148,24, +158,38,164,58,160,78,150,92,134,102,116,104,92,108,130,110,154,118,166,134, +170,156,166,176,156,192,142,200,124,204,108,206,73,193,158,16,114,88,66,152, +197,152,158,16,159,207,172,20,96,20,90,100,110,98,138,100,158,112,170,134, +174,154,170,170,158,190,142,200,124,204,102,204,79,197,178,20,156,16,136,16, +116,26,100,42,90,60,82,88,80,108,82,150,88,176,102,194,118,204,146,202, +172,182,184,150,172,112,154,94,126,92,104,102,96,108,83,137,68,20,180,20, +164,50,148,80,134,110,124,136,118,158,112,186,107,207,130,104,144,100,162,90, +170,74,172,52,162,30,146,20,128,16,116,18,100,26,90,38,84,50,86,66, +88,76,96,88,110,98,118,102,134,106,152,110,166,120,176,134,178,146,178,164, +174,178,166,190,154,200,140,204,124,206,110,202,92,190,80,172,76,150,84,130, +96,116,110,110,131,105,174,82,168,100,160,114,148,124,136,128,120,128,108,126, +94,116,82,100,78,82,78,62,82,46,92,32,104,22,122,18,140,18,160,28, +166,40,172,54,178,76,178,100,176,128,172,152,164,172,152,190,134,202,118,206, +100,204,88,200,81,199,54,74,56,76,54,82,50,82,48,78,52,74,53,74, +52,194,58,194,58,200,56,204,50,204,48,200,48,196,53,195,50,70,58,70, +62,76,62,82,56,84,50,82,48,74,50,70,58,80,50,80,59,72,54,176, +35,241,184,70,82,128,185,181,66,100,191,100,66,152,191,153,72,70,174,128, +73,181,22,30,40,20,62,16,80,16,94,26,104,38,106,52,102,72,92,88, +76,102,66,112,60,120,58,132,60,146,63,152,58,192,66,194,66,200,56,202, +58,190,64,200,59,197,166,62,156,142,148,156,140,168,130,176,116,178,98,172, +86,158,80,138,82,112,92,88,112,70,130,66,144,70,152,74,162,88,156,136, +158,140,164,162,172,172,182,176,194,176,206,172,218,162,226,148,232,122,230,90, +220,60,196,34,168,20,144,16,120,16,90,24,64,42,46,64,34,92,30,122, +32,148,40,174,52,192,70,210,90,220,116,226,144,228,168,224,189,217,56,206, +128,16,201,204,82,140,175,141,84,20,84,200,118,202,146,198,166,188,180,172, +182,154,176,132,164,118,148,112,122,108,84,108,136,108,152,98,166,84,172,70, +170,54,164,36,150,26,134,20,85,21,196,26,180,20,164,16,144,18,124,22, +108,30,94,40,82,54,74,70,66,94,66,116,68,138,76,160,90,184,108,196, +132,204,158,204,178,200,197,197,66,18,66,200,82,200,110,200,138,198,156,188, +174,178,186,164,194,146,198,130,200,112,198,88,192,66,180,46,164,34,146,26, +130,22,112,18,67,19,176,20,90,20,90,202,181,202,90,110,171,111,180,20, +94,20,95,206,94,112,175,113,196,28,182,22,164,18,144,16,120,20,96,32, +84,40,72,58,62,74,58,94,58,118,60,142,68,162,78,178,92,190,104,198, +116,202,132,204,150,206,170,200,194,190,194,118,143,119,66,14,67,206,190,14, +191,208,66,110,189,111,102,20,155,20,102,200,155,200,128,20,129,201,142,14, +142,156,138,178,130,192,118,202,108,204,96,204,87,203,86,14,87,206,186,14, +86,104,189,207,96,14,96,202,183,203,44,206,44,14,128,196,212,14,213,207, +60,206,60,14,196,206,197,15,158,20,100,20,82,30,68,46,58,56,50,76, +44,88,44,140,50,154,60,170,72,182,84,194,98,200,160,200,190,178,204,154, +210,136,210,80,200,56,186,38,172,26,159,21,84,206,84,20,126,20,142,24, +156,26,166,34,174,46,180,60,180,74,176,90,168,104,160,114,140,122,130,126, +85,127,130,204,110,204,92,198,76,188,62,172,50,146,46,132,46,98,52,78, +58,60,66,44,82,32,98,22,104,18,156,18,178,32,194,46,204,66,210,90, +210,118,208,138,202,162,184,182,166,196,148,204,130,204,146,222,158,234,174,244, +180,248,194,252,225,251,82,206,82,20,134,20,152,24,164,32,174,46,176,56, +176,82,168,96,158,104,144,112,130,116,82,116,130,116,142,126,152,142,185,207, +174,24,158,20,150,18,124,18,112,22,104,26,92,36,86,42,86,78,96,88, +110,98,122,104,136,114,148,122,162,130,168,138,174,144,176,150,176,174,168,184, +156,196,138,204,120,206,108,206,92,200,79,193,66,20,191,20,128,20,129,209, +66,14,66,142,70,160,78,178,90,192,100,200,108,202,148,202,170,192,182,176, +186,156,190,138,191,15,58,14,124,206,199,15,18,14,72,206,130,14,182,206, +239,15,70,14,187,206,66,206,189,15,70,14,126,130,191,14,126,130,127,207, +68,20,184,20,68,200,195,201,234,20,196,20,196,246,233,247,80,14,173,239, +22,18,60,18,60,246,23,247,100,46,126,6,153,45,0,242,255,243,112,4, +143,47,86,88,104,78,118,74,132,72,144,74,156,80,164,90,168,96,168,102, +170,116,170,142,166,168,158,182,148,194,136,200,122,204,108,204,92,196,82,184, +80,166,86,150,100,140,110,136,170,126,171,207,78,4,78,206,78,132,90,100, +100,86,114,76,130,72,144,72,160,78,172,86,178,98,184,110,186,124,186,146, +182,166,174,182,164,194,148,202,134,206,120,204,108,198,96,188,84,174,79,133, +178,78,166,74,154,72,144,72,132,74,124,76,114,82,104,90,96,100,90,112, +86,126,86,142,90,162,96,180,106,190,116,198,128,204,146,206,162,202,179,197, +176,4,176,206,176,116,166,94,152,80,142,74,134,72,124,72,114,74,102,78, +86,88,80,100,72,120,70,136,70,152,72,166,78,180,88,192,98,200,108,202, +124,204,140,202,154,194,164,182,175,165,78,134,180,134,180,120,176,102,168,90, +158,80,146,74,134,72,124,72,114,76,104,80,94,88,86,98,82,108,78,124, +76,132,78,150,82,166,88,180,96,190,106,198,114,202,128,206,142,204,154,202, +166,196,179,191,172,8,164,6,156,6,146,8,138,14,134,18,130,26,126,32, +126,36,127,206,94,74,169,75,178,68,178,144,174,156,168,172,156,184,146,194, +132,198,116,200,100,192,86,180,80,164,78,152,76,130,80,104,82,88,90,76, +104,68,120,66,138,68,152,72,164,82,168,90,176,104,176,200,168,220,162,234, +150,246,138,250,122,252,100,252,82,248,73,243,82,2,82,206,82,134,92,96, +98,88,108,78,120,72,134,70,150,72,162,78,168,88,172,94,176,104,176,116, +177,207,132,18,138,18,138,26,132,26,132,18,137,24,138,18,135,24,76,74, +134,74,135,207,126,10,140,10,140,22,126,22,126,10,137,18,138,10,129,20, +76,68,134,68,134,204,132,218,128,228,122,240,114,246,108,250,100,254,90,254, +80,250,73,247,94,2,95,206,94,132,175,68,94,132,177,207,74,8,132,8, +133,207,42,68,42,206,42,124,46,110,50,100,54,92,60,84,68,78,74,76, +86,72,96,72,110,78,118,84,124,94,128,102,128,206,128,118,136,102,144,90, +154,80,164,74,182,72,190,74,198,76,206,84,212,92,216,102,216,108,217,207, +82,68,83,206,82,112,90,94,98,82,110,72,122,68,140,66,152,68,162,72, +170,80,178,92,180,100,181,207,112,74,152,74,164,82,176,96,184,116,186,124, +186,160,178,180,168,190,156,200,150,204,104,204,90,194,82,182,74,168,70,158, +70,118,78,100,88,86,100,78,113,75,78,70,79,254,78,110,86,96,102,78, +118,70,130,66,140,66,150,66,158,70,172,82,178,92,182,102,186,128,184,136, +182,146,176,156,172,174,162,184,154,190,140,196,126,196,116,194,102,186,90,168, +79,151,178,70,179,254,178,102,170,92,158,76,144,68,132,66,114,66,98,72, +88,82,76,98,70,122,68,140,72,160,78,172,88,182,98,190,112,196,130,196, +142,194,154,184,162,174,168,160,179,143,110,70,111,206,170,76,166,74,162,72, +154,72,146,74,138,78,132,84,126,92,118,106,111,121,164,80,154,76,140,72, +130,72,118,74,106,82,100,90,96,98,98,106,100,116,106,124,118,134,128,138, +142,144,152,152,160,162,162,172,160,182,156,194,150,198,142,202,130,204,118,204, +106,202,98,198,91,195,90,74,165,74,120,32,120,172,122,182,124,190,126,196, +134,202,142,204,146,204,154,202,165,201,78,70,78,158,80,170,84,180,90,188, +94,196,100,200,110,204,124,206,136,204,144,200,154,194,162,184,166,174,175,160, +174,68,175,207,76,70,126,204,181,71,46,70,84,206,130,68,168,206,211,71, +82,70,173,206,172,70,83,207,72,250,82,252,94,250,102,242,175,70,120,194, +73,71,78,74,174,74,82,200,181,201,230,18,224,20,218,22,214,24,210,28, +208,30,206,36,204,42,204,46,204,104,202,112,198,118,190,126,184,130,176,132, +186,136,192,140,198,146,200,152,202,160,202,216,204,224,208,232,212,240,218,244, +224,244,231,247,128,0,129,255,26,20,32,20,36,22,42,24,46,28,50,34, +52,42,52,48,54,54,54,98,54,104,56,112,60,118,64,122,68,126,80,132, +72,134,66,138,60,142,58,148,54,156,54,162,54,218,52,226,48,230,44,236, +38,242,32,244,27,245,2,0,253,1,12,86,14,70,22,58,32,52,40,48, +50,46,64,46,70,48,80,50,88,56,92,64,96,76,96,86,96,96,94,106, +86,116,80,122,72,130,62,136,56,144,52,152,50,160,49,168,44,202,52,202, +52,210,44,210,44,204,50,204,50,208,46,208,47,203,38,180,66,204,89,229, +92,204,90,198,88,190,82,184,76,178,70,176,62,176,56,178,50,180,46,184, +42,188,38,194,36,200,36,206,38,212,42,220,50,226,56,228,62,230,70,230, +78,226,86,220,90,212,93,205,20,138,36,138,36,158,20,158,20,140,34,142, +22,144,34,146,22,148,34,150,22,152,34,154,23,157,8,60,71,61,12,36, +48,72,83,37,24,56,32,56,32,66,24,66,24,56,31,64,72,56,80,56, +80,66,72,66,72,56,79,65,122,80,93,168,162,80,135,171,122,50,90,106, +49,148,102,86,182,86,131,154,94,134,130,154,161,179,0,154,255,155,76,142, +76,136,78,128,82,122,90,118,98,116,108,116,116,120,124,124,128,126,134,132, +140,136,148,138,156,138,164,136,172,132,178,126,180,118,181,111,30,36,31,254, +82,36,83,255,22,120,30,120,30,130,22,130,22,120,29,128,86,120,94,120, +94,130,86,130,86,120,93,128,148,120,156,120,156,130,148,130,148,120,155,129, +30,40,26,56,24,70,24,86,37,87,20,52,34,52,32,60,30,74,27,91, +32,42,24,64,22,82,35,82,66,42,58,66,56,82,71,83,20,50,36,50, +34,66,27,90,56,50,70,50,68,66,61,91,232,10,178,38,178,216,231,245, +24,12,78,38,78,216,27,245,226,8,166,126,227,247,30,8,90,126,31,247, +228,8,168,126,229,246,192,8,132,128,193,247,234,12,164,12,165,249,92,6, +92,242,25,243,230,36,230,14,166,14,166,240,184,240,184,36,231,37,92,14, +72,14,72,218,26,218,26,240,92,240,93,15,228,6,220,20,210,36,204,52, +200,70,196,94,194,114,194,132,194,152,198,174,202,194,208,212,218,230,222,238, +228,246,176,246,176,6,229,7,26,6,40,26,46,44,54,60,58,82,62,104, +62,126,62,146,58,168,56,184,52,204,46,216,36,232,28,248,80,248,80,6, +27,7,234,4,222,28,212,52,208,76,204,96,202,120,202,144,206,168,210,190, +216,208,226,230,234,250,176,250,176,4,232,4,176,20,220,32,178,48,208,56, +182,76,200,88,180,110,196,120,180,142,200,162,178,184,212,198,178,218,218,220, +176,240,229,249,20,4,28,16,34,28,38,42,44,58,50,84,52,108,54,128, +52,144,50,168,44,196,34,222,26,238,20,250,82,250,80,4,20,4,74,18, +38,30,72,52,54,72,70,94,60,114,72,126,60,150,76,160,52,180,76,194, +46,202,76,218,38,226,74,236,33,247,26,126,145,126,86,70,87,186,26,212, +145,213,132,84,39,180,36,82,135,179,80,80,92,80,92,94,80,94,80,80, +91,92,90,80,83,92,80,170,92,170,92,184,80,184,80,170,91,182,90,170, +83,182,26,132,145,133,118,64,136,64,136,84,118,84,118,64,135,80,134,64, +121,82,118,162,136,162,136,182,118,182,118,162,135,176,134,162,121,181,62,212, +130,14,193,215,62,16,126,216,195,17,200,38,66,38,150,140,60,252,207,253, +56,252,56,38,200,38,201,253,56,46,56,142,56,148,58,154,60,164,70,180, +78,190,86,196,98,200,112,204,136,204,160,200,182,186,194,168,198,152,198,146, +199,49,56,206,56,112,58,104,60,94,64,84,70,74,78,64,90,56,104,52, +118,50,132,50,144,50,158,54,166,58,178,64,186,72,192,82,196,90,198,98, +200,110,201,207,206,50,112,50,104,50,98,52,92,54,86,56,80,60,72,68, +68,76,64,82,60,92,58,102,58,112,56,128,60,146,62,156,68,168,72,174, +80,180,90,186,104,190,207,190,58,118,203,119,84,68,94,72,96,78,94,86, +92,88,86,92,78,90,74,84,72,78,76,72,84,68,84,88,74,78,94,80, +88,72,80,76,87,84,182,74,180,70,174,68,168,68,162,72,160,78,158,82, +160,84,162,88,166,92,168,92,176,92,182,86,184,82,184,76,182,74,160,82, +166,70,176,86,166,88,176,70,178,78,165,84,84,158,78,160,74,164,72,170, +72,174,74,178,78,180,80,182,88,182,92,180,96,176,98,168,94,162,90,160, +84,158,82,178,74,170,94,170,90,164,86,178,79,162,172,158,166,158,164,160, +160,166,160,172,160,176,162,180,168,182,176,182,182,176,184,172,180,162,174,158, +172,158,166,178,180,172,164,164,174,178,176,160,169,161,62,98,92,98,136,206, +189,3,128,46,129,200,52,202,205,203,146,0,29,238,224,0,105,239,166,48, +52,202,215,203,22,150,26,140,32,130,44,116,50,108,58,100,68,92,84,86, +96,82,108,78,124,78,140,76,158,80,168,84,180,88,190,94,200,102,208,110, +214,118,220,124,226,132,230,140,235,151,128,28,144,30,158,34,170,40,180,48, +190,54,198,62,204,72,208,84,212,98,216,112,216,120,212,140,204,158,194,176, +184,184,174,192,162,198,150,200,140,204,126,204,112,202,98,198,84,192,70,182, +58,170,50,152,44,138,42,124,40,112,44,94,50,76,58,66,64,56,80,44, +92,36,110,30,129,28,128,102,138,106,142,116,140,122,136,128,128,130,120,128, +116,124,112,116,114,108,120,102,127,100,126,100,129,126,114,116,141,116,120,108, +135,122,134,106,121,123,98,246,102,250,108,252,112,252,116,250,118,244,120,234, +124,222,124,206,126,190,126,174,128,150,128,120,130,94,130,74,134,54,136,46, +140,36,148,34,154,34,156,36,157,39,76,250,88,252,98,252,114,250,122,244, +126,236,128,226,128,42,130,30,136,20,140,14,148,8,156,4,162,4,170,4, +174,6,181,10,180,160,180,106,158,84,156,80,106,80,82,96,72,114,72,154, +90,176,104,186,156,186,181,161,44,90,213,90,44,126,213,126,44,160,213,161, +34,56,34,64,36,72,38,82,42,90,46,98,52,104,62,112,72,116,82,116, +92,114,104,108,124,94,136,82,148,70,162,64,174,60,194,64,202,70,208,76, +216,88,220,102,221,120,24,154,229,154,24,190,229,191,44,110,60,100,72,96, +102,96,124,102,140,108,154,114,184,114,213,96,44,150,64,138,68,134,76,132, +98,132,144,148,158,152,164,154,180,154,192,148,213,137,34,94,36,106,38,118, +42,126,48,138,56,146,70,152,78,152,90,152,100,148,116,140,124,130,134,120, +142,114,150,106,162,100,174,98,186,100,196,102,206,110,210,118,216,130,218,140, +220,148,221,157,206,76,198,72,188,74,180,78,174,82,166,88,160,96,154,102, +148,114,140,124,132,140,122,150,110,156,100,160,84,160,72,154,60,142,54,126, +54,108,58,94,64,86,74,78,84,74,96,72,108,74,118,80,128,88,134,98, +140,106,148,120,156,134,164,144,174,152,182,158,190,160,196,160,207,161,44,106, +213,106,42,144,213,144,190,40,65,211,212,58,46,124,213,194,164,40,93,211, +44,56,212,124,45,192,162,40,93,211,128,120,132,104,134,92,142,80,152,74, +166,70,180,72,192,80,200,92,202,104,204,120,202,136,194,152,182,162,170,168, +154,166,146,160,136,148,130,136,128,120,124,104,122,92,114,80,104,74,90,70, +76,72,66,82,56,94,52,106,52,120,54,134,60,152,70,160,84,166,96,166, +110,160,122,148,126,136,129,121,190,78,180,76,170,84,172,94,176,100,188,102, +198,94,196,82,190,78,176,100,182,76,196,92,172,84,186,98,191,80,72,74, +60,82,60,96,70,102,82,98,84,84,80,76,72,74,70,98,62,84,80,82, +62,96,78,94,75,78,126,170,118,174,114,182,116,192,122,198,130,198,138,194, +142,186,140,178,134,172,124,170,126,196,116,180,140,184,130,194,132,174,119,193, +142,78,142,74,140,68,136,66,132,64,126,62,122,64,116,68,114,72,114,78, +116,84,120,90,128,92,134,92,138,90,140,86,142,82,142,78,120,66,128,90, +134,66,116,82,141,78,86,174,84,166,78,160,70,160,62,162,58,170,58,176, +60,182,66,186,70,188,76,188,82,184,86,180,86,174,62,164,76,186,78,162, +60,180,85,174,184,158,174,162,170,170,172,180,178,186,186,186,194,184,198,174, +194,162,184,158,174,182,194,172,174,164,186,182,187,161,126,108,106,116,90,128, +80,148,78,166,82,184,94,198,102,206,116,210,132,212,148,208,164,200,174,186, +178,172,178,154,172,138,164,126,154,118,142,114,134,110,126,108,127,22,82,68, +104,52,126,22,148,48,173,67,126,128,142,128,156,120,170,110,176,94,178,78, +176,60,170,48,160,38,144,30,132,28,122,28,110,32,96,38,86,48,80,62, +78,76,80,92,84,102,94,114,108,124,126,128,127,218,86,182,171,183,78,72, +76,64,72,56,66,50,60,46,52,44,44,44,36,46,28,52,24,60,20,68, +20,78,24,84,30,94,38,98,48,100,58,98,68,94,76,84,79,73,36,42, +29,87,36,42,29,88,76,42,69,87,76,74,76,62,70,52,58,44,44,44, +34,48,26,56,20,66,20,76,24,84,30,92,40,100,52,100,66,94,74,84, +77,74,218,78,208,62,194,52,180,48,162,46,148,48,136,52,126,56,118,64, +112,74,104,90,100,104,98,120,98,138,100,152,104,162,108,176,114,186,124,198, +132,204,144,210,158,212,172,212,184,210,196,206,204,200,210,192,216,184,219,177, +168,26,152,22,134,20,120,20,110,24,100,30,92,40,86,52,86,62,88,72, +92,82,102,94,110,100,154,128,166,142,170,152,172,162,168,178,158,190,148,198, +140,200,126,202,114,200,100,198,79,190,128,0,129,237,56,178,86,178,100,170, +116,152,120,138,120,122,112,108,104,96,96,88,88,86,58,86,48,90,38,98, +28,108,24,116,24,144,32,158,40,166,46,174,57,178,16,76,37,96,126,78, +107,96,36,164,17,184,126,186,105,165,180,58,166,52,152,50,136,50,124,54, +112,60,102,70,96,82,90,94,86,108,86,126,88,138,94,152,100,162,110,172, +120,178,130,182,142,182,154,182,168,178,179,174,142,18,143,215,176,22,168,18, +162,18,152,16,144,16,136,18,128,22,124,26,120,28,114,36,110,44,108,52, +108,64,108,146,106,158,104,164,100,174,96,180,90,186,84,190,78,194,68,200, +185,200,70,112,157,113,2,94,4,116,10,136,20,148,32,152,44,146,50,136, +56,118,58,90,56,66,50,52,40,44,30,38,20,38,12,48,6,58,2,74, +3,92,109,34,115,38,132,42,31,216,128,112,120,114,108,126,96,146,94,160, +96,178,102,200,110,212,118,218,132,216,146,210,156,188,158,162,158,138,150,118, +138,110,125,112,252,164,250,142,244,128,236,116,220,110,206,112,200,126,194,152, +192,176,194,198,200,216,212,222,230,218,242,202,248,188,253,165,92,68,84,52, +76,44,64,40,52,40,40,46,30,54,24,60,24,72,28,84,36,92,46,98, +56,102,72,108,84,114,94,122,96,132,94,146,86,162,76,166,65,172,54,102, +42,104,34,110,28,118,24,126,22,134,24,142,28,152,34,158,42,162,56,170, +72,176,86,182,92,188,96,196,96,204,96,218,88,228,72,236,54,238,38,234, +28,228,22,222,19,209,134,42,134,216,12,42,13,218,250,210,169,210,170,134, +170,114,172,102,180,88,194,80,206,78,220,78,232,88,240,94,246,104,250,114, +252,130,252,138,248,158,244,168,238,176,228,182,208,188,198,182,182,166,174,152, +171,135,212,102,148,102,128,36,106,102,42,102,92,142,74,204,128,166,180,204, +160,142,213,103,222,98,34,98,184,210,128,30,70,208,222,100,95,140,128,32, +129,166,34,98,163,142,106,98,183,208,150,98,71,209,216,114,214,100,208,82, +202,68,188,52,176,40,162,34,150,32,138,28,124,26,116,28,106,30,96,32, +86,38,74,44,64,54,56,66,50,76,46,84,42,98,40,112,42,128,46,142, +54,160,66,176,76,186,92,194,110,200,128,202,146,200,164,194,178,186,194,172, +204,158,212,136,217,115,218,92,210,72,198,54,190,44,176,36,162,28,146,24, +130,22,112,24,96,28,80,36,66,44,58,54,50,66,42,82,38,98,36,112, +36,124,40,144,46,158,52,170,64,182,78,192,94,200,106,204,118,206,126,206, +146,204,164,198,180,190,192,182,204,168,212,152,218,134,222,114,218,100,216,90, +168,34,150,26,212,110,210,130,142,30,128,26,206,144,200,162,120,30,102,30, +190,168,180,184,92,36,84,40,168,184,158,194,78,44,70,50,146,194,136,200, +66,56,58,66,122,196,110,200,52,76,48,88,92,186,76,182,44,98,42,118, +61,171,178,148,186,130,188,108,184,88,172,74,158,60,142,56,126,54,108,58, +94,66,82,74,74,84,68,98,68,110,68,126,76,144,84,158,100,168,112,174, +130,176,148,172,166,160,179,148,214,90,208,74,198,58,188,48,166,34,146,28, +130,24,114,26,96,32,82,38,72,44,62,54,52,66,46,80,40,94,38,110, +38,122,40,134,46,148,50,158,60,174,74,186,86,194,98,198,110,202,130,204, +154,200,182,188,198,170,208,154,216,132,218,114,215,91,128,24,40,112,128,202, +218,114,129,25,224,112,128,18,32,112,126,208,224,112,208,114,128,32,116,38, +202,122,194,134,110,50,100,54,180,138,174,148,96,64,84,72,166,158,156,168, +76,80,68,86,142,172,140,184,66,96,56,102,132,186,124,196,47,113,224,26, +32,26,32,218,224,218,225,27,230,18,26,18,26,222,230,222,230,18,220,26, +32,26,32,34,220,34,220,40,32,40,32,56,222,56,222,62,34,62,34,72, +220,72,220,80,34,80,34,92,220,92,220,102,36,102,36,114,220,114,220,124, +38,124,38,138,218,138,218,152,36,152,36,162,218,162,218,172,36,172,36,184, +218,184,218,196,34,196,34,210,219,211,128,32,44,202,212,202,129,33,34,208, +220,208,128,18,34,208,48,198,198,198,198,180,68,180,68,162,176,162,176,140, +92,140,92,118,162,118,162,102,102,102,102,84,148,84,148,70,116,70,116,56, +134,56,134,42,127,43,132,84,37,180,36,84,135,180,80,84,90,84,90,94, +80,94,81,84,122,126,132,126,132,136,122,136,123,126,38,126,48,126,48,136, +38,136,39,126,80,170,90,170,90,180,80,180,81,171,0,116,255,116,190,70, +208,88,220,96,232,106,254,116,236,126,224,132,218,138,204,150,191,165,2,116, +255,116,66,68,58,78,44,90,24,104,14,110,0,116,4,118,14,122,20,126, +30,132,38,138,46,144,54,154,62,162,67,167,128,0,129,246,78,54,112,32, +128,0,144,30,177,55,128,244,129,0,176,180,146,212,128,244,108,210,79,181, +56,60,200,60,200,98,56,98,56,60,62,64,194,64,194,70,58,70,58,74, +194,74,194,82,60,82,60,88,194,88,194,92,61,92,54,142,202,142,202,182, +56,182,56,142,62,144,196,144,196,152,60,152,60,158,194,158,194,164,60,164, +60,170,196,170,196,174,59,175,26,8,88,128,29,248,62,8,124,128,63,249, +214,60,42,110,215,156,42,154,215,203,42,60,214,110,43,158,42,204,215,155, +26,36,27,180,26,36,60,36,61,174,26,154,61,154,88,26,132,26,110,94, +126,126,132,148,132,166,126,178,106,188,101,172,88,26,89,240,142,26,247,26, +216,26,216,214,210,222,190,226,179,216,152,72,153,162,152,72,186,72,187,162, +152,162,185,163,30,26,31,240,30,26,80,26,60,94,82,138,82,168,64,180, +51,172,96,30,241,30,212,30,212,218,198,228,184,230,169,220,118,86,119,158, +118,84,166,84,167,158,118,158,165,159,18,90,93,90,58,16,59,188,18,204, +95,180,164,12,110,74,213,66,186,32,231,80,132,84,99,134,114,108,225,108, +92,154,235,154,164,108,160,156,150,184,126,212,83,238,162,156,178,190,206,220, +233,237,14,74,91,74,56,12,56,222,50,232,34,236,25,226,16,150,87,120, +156,14,122,56,104,72,211,66,184,34,225,78,128,82,114,116,101,142,116,110, +221,110,88,158,233,158,162,110,162,156,154,180,136,206,114,224,89,236,162,158, +168,176,192,208,233,239,28,44,29,196,28,44,76,44,77,186,28,164,77,164, +90,52,235,52,132,14,133,90,184,12,185,90,118,104,138,148,160,182,190,206, +237,230,196,102,174,162,150,194,126,212,77,237,32,50,33,200,32,48,80,48, +81,190,32,168,79,168,160,14,106,74,213,64,186,32,229,78,132,82,99,132, +116,106,223,106,94,156,233,156,164,108,164,156,160,170,144,196,114,224,94,234, +79,230,164,158,176,178,192,198,218,222,228,228,247,227,110,14,145,42,18,56, +237,56,62,88,63,132,62,88,194,88,195,132,62,132,195,132,112,132,100,150, +88,162,66,178,19,200,80,168,80,234,133,200,220,144,155,186,134,150,154,186, +168,200,188,216,210,226,235,233,64,20,51,62,30,64,31,222,30,64,90,64, +91,212,30,124,89,124,30,192,89,192,168,12,169,72,116,26,116,72,223,72, +222,26,223,70,116,108,214,108,214,158,122,158,122,214,122,222,124,226,132,230, +208,230,218,228,228,222,239,201,124,8,157,30,60,40,243,40,60,40,60,160, +52,188,29,238,20,68,43,98,16,150,59,118,114,68,115,100,114,68,198,68, +199,100,114,100,199,100,86,128,87,162,86,128,136,128,137,162,86,162,137,162, +176,126,177,164,176,126,228,126,229,162,176,164,229,164,156,172,157,228,96,186, +96,232,221,226,224,186,225,249,18,42,241,42,94,10,95,66,164,8,165,62, +44,70,77,96,20,122,60,124,60,224,99,196,122,76,123,128,122,76,206,76, +207,124,122,102,205,102,122,128,207,128,136,136,102,166,93,174,112,158,224,158, +220,222,214,230,208,234,189,238,166,158,160,176,135,206,162,172,203,202,116,174, +116,220,187,221,52,12,38,58,21,90,38,56,97,56,16,122,97,122,66,56, +66,116,58,158,42,192,19,222,60,152,101,198,224,12,190,24,154,30,117,30, +104,66,243,66,168,28,169,126,166,66,142,94,124,112,111,120,170,66,180,80, +196,94,218,112,237,120,92,158,245,158,162,130,128,186,196,216,233,238,202,158, +194,180,174,204,154,218,132,228,97,239,20,58,239,58,96,12,97,92,164,14, +165,92,80,106,100,144,112,160,136,184,166,206,196,218,229,228,180,102,154,150, +118,192,78,216,33,237,16,40,107,40,60,40,56,64,48,92,34,118,19,136, +46,106,47,216,46,104,88,104,89,210,46,190,87,190,124,22,125,92,124,20, +213,20,212,20,213,90,124,92,213,92,124,58,211,58,110,122,237,122,104,160, +247,160,198,122,198,228,194,234,184,238,169,238,128,178,157,209,206,18,176,28, +136,32,84,36,45,36,62,52,83,74,116,48,141,74,202,40,173,84,32,86, +33,120,32,84,224,84,225,120,42,132,219,132,120,100,104,146,92,168,70,196, +27,230,94,166,190,166,178,184,144,214,120,226,73,242,106,184,142,208,168,218, +202,226,231,231,30,30,84,30,54,98,58,104,72,120,80,136,82,148,80,162, +76,174,68,180,53,186,30,30,31,242,116,16,149,50,208,14,175,68,92,68, +235,68,146,86,116,118,97,136,176,90,237,130,116,148,117,224,116,146,214,146, +215,224,82,226,245,226,150,148,151,226,182,146,183,225,16,48,121,48,46,10, +46,80,90,80,91,12,32,112,33,150,34,112,104,112,105,148,32,150,105,150, +12,184,123,184,68,82,69,244,168,12,191,38,132,52,133,86,132,52,234,52, +235,86,118,124,245,124,178,74,144,172,241,230,208,124,196,174,166,210,111,237, +72,12,48,52,19,84,56,40,229,40,64,64,213,64,34,92,194,92,194,164, +200,200,206,222,220,236,237,212,90,102,117,120,40,128,41,156,40,130,166,130, +167,156,26,174,181,174,102,138,72,198,171,236,138,176,114,212,80,230,41,241, +108,12,141,34,38,50,39,92,38,50,218,50,219,92,18,122,241,122,120,70, +76,162,219,234,176,122,154,172,108,214,29,239,70,12,50,66,17,118,54,56, +55,246,88,50,239,50,158,8,144,56,118,84,75,108,180,50,202,80,241,104, +108,112,109,182,108,110,216,110,217,180,108,146,215,146,108,180,217,180,160,78, +160,224,166,228,226,228,236,220,241,203,12,68,97,68,58,8,58,230,40,234, +25,224,16,154,91,122,158,8,183,36,114,54,115,90,114,54,230,54,231,88, +102,130,245,130,172,72,132,172,237,230,206,130,190,178,156,216,95,237,24,44, +25,218,24,44,78,44,79,212,26,116,77,116,24,190,77,190,150,10,175,36, +108,50,227,50,128,66,147,94,200,62,177,108,96,110,241,110,120,142,121,246, +120,140,212,140,213,244,122,182,211,182,122,224,211,225,58,18,58,66,209,66, +134,14,135,62,208,22,209,64,50,102,227,102,50,102,48,188,29,236,80,136, +217,136,64,180,241,180,146,136,147,247,38,38,38,168,30,206,17,238,38,36, +88,36,88,226,72,236,57,226,40,94,87,94,40,146,87,146,152,12,181,40, +114,58,115,86,114,56,228,56,229,88,102,130,245,130,170,74,132,174,202,208, +237,236,200,132,184,190,156,218,107,241,114,16,141,34,40,44,41,72,40,44, +216,44,217,72,24,86,233,86,122,60,80,112,217,148,174,86,158,106,126,132, +98,142,41,150,26,176,235,176,132,148,133,244,120,176,84,210,35,238,142,176, +154,194,182,214,225,233,44,34,44,168,19,236,44,34,94,34,94,224,82,236, +63,226,46,92,91,92,46,148,93,148,154,14,185,46,110,64,243,64,144,104, +144,194,113,242,144,106,200,106,200,228,228,230,240,218,243,195,52,24,53,98, +52,26,194,26,195,100,54,60,193,60,54,96,193,96,112,122,36,138,36,222, +115,186,144,128,145,242,146,130,216,130,216,208,181,215,60,44,61,92,64,44, +194,44,195,92,22,94,237,94,132,12,128,62,116,104,82,134,25,158,142,96, +164,120,184,136,233,158,64,160,65,222,66,158,192,158,193,224,19,222,18,224, +239,224,108,160,109,220,146,160,147,223,36,36,37,234,38,36,98,36,98,126, +158,126,158,36,218,36,219,230,36,206,217,207,24,44,137,44,34,84,125,84, +80,10,81,116,14,122,139,122,64,122,64,148,58,174,46,202,19,234,64,154, +120,154,106,216,86,224,69,212,172,12,152,68,131,108,154,68,241,68,208,70, +198,148,170,200,121,240,154,106,172,164,194,200,235,235,28,38,131,38,32,70, +125,70,14,96,137,96,80,10,81,92,66,98,64,132,50,156,27,182,66,122, +116,122,104,168,88,174,75,164,180,10,160,56,139,84,160,56,245,56,210,58, +206,88,192,126,172,150,141,168,160,80,174,120,202,148,239,166,60,184,29,240, +100,188,115,232,146,184,163,228,196,180,229,237,74,14,63,42,40,46,41,100, +42,44,110,44,111,98,42,98,109,98,42,72,107,72,20,130,125,130,74,108, +54,152,25,192,88,144,127,178,40,188,115,188,76,158,77,242,124,34,166,34, +166,226,148,232,131,222,132,78,149,120,130,162,165,138,184,34,228,34,228,226, +210,232,191,222,190,76,207,118,180,166,225,135,48,14,81,48,14,66,86,66, +60,108,19,146,62,108,63,242,102,102,79,138,62,130,109,162,222,26,170,42, +115,48,116,118,235,118,166,44,166,126,162,152,150,182,136,206,103,236,170,128, +182,160,198,190,212,210,237,231,64,10,17,116,44,54,45,246,68,46,151,46, +72,82,143,82,64,120,155,120,112,10,113,118,96,122,96,162,92,182,78,210, +65,224,98,154,138,154,132,208,122,216,103,208,184,8,151,104,164,70,241,70, +212,70,198,158,164,212,137,240,168,100,186,166,200,192,237,237,114,8,103,36, +54,40,55,160,56,38,198,38,199,160,72,96,181,96,124,54,125,148,82,62, +99,82,166,62,149,82,116,100,75,144,140,110,175,142,16,176,239,176,126,156, +110,196,90,220,27,242,132,178,150,200,178,222,231,241,56,12,57,246,30,70, +19,132,72,64,91,98,156,10,145,40,108,44,109,154,108,42,218,42,219,154, +124,98,201,98,162,54,163,150,132,62,143,84,192,62,181,84,158,106,129,146, +166,110,195,138,82,178,243,178,158,158,144,202,120,226,87,240,164,180,182,206, +212,230,237,239,40,16,73,46,18,80,55,110,24,228,63,142,154,6,145,32, +102,38,103,156,102,36,216,36,217,156,120,96,201,96,160,50,161,142,124,56, +141,78,194,56,177,80,154,100,121,142,162,104,193,132,72,170,245,170,158,148, +140,200,112,222,75,238,160,172,174,196,202,218,237,235,10,50,243,50,92,10, +93,82,162,10,163,82,48,98,200,98,200,162,51,162,124,98,125,162,48,98, +48,212,50,220,56,228,62,232,206,232,218,222,228,210,229,197,16,70,89,70, +56,12,56,228,46,236,25,226,16,154,89,118,104,28,105,90,104,26,156,26, +157,90,102,92,157,92,86,142,158,142,150,224,123,228,122,110,112,178,87,238, +188,48,189,174,224,12,224,220,220,228,212,232,196,232,189,225,18,74,105,74, +64,12,64,230,44,240,31,226,16,158,105,122,142,26,136,122,114,186,87,228, +182,20,182,56,190,122,208,182,237,229,30,40,31,188,30,40,82,40,83,176, +32,156,81,156,132,26,128,102,114,158,98,198,65,232,172,18,176,90,188,140, +208,196,235,229,32,36,33,184,32,34,80,34,81,180,34,160,79,160,116,34, +216,34,216,126,121,126,164,36,165,122,116,36,116,206,118,216,122,220,130,222, +214,222,222,218,230,210,235,191,74,18,23,86,52,48,131,48,80,48,101,88, +174,16,131,86,156,48,245,48,180,48,203,86,50,102,202,102,203,162,128,104, +129,160,54,164,203,164,52,102,52,210,54,220,58,226,62,228,72,230,196,230, +212,226,220,218,231,199,102,40,74,140,50,184,17,224,146,22,156,78,170,122, +188,162,214,202,235,225,120,10,155,36,60,50,237,50,60,50,60,148,50,194, +21,238,16,64,39,102,14,156,57,134,96,88,214,88,214,154,99,154,154,88, +155,154,94,88,94,212,98,220,104,224,112,226,206,226,220,222,228,216,239,189, +42,36,210,36,210,118,49,118,126,38,127,114,42,36,42,210,46,218,54,226, +66,228,200,228,214,224,222,212,231,187,16,74,93,74,16,162,95,120,60,14, +60,228,36,236,25,222,104,74,239,74,156,10,142,94,130,130,104,170,89,192, +138,120,206,120,194,156,168,192,142,212,89,238,134,124,152,166,162,182,180,204, +198,218,237,236,186,26,219,57,32,28,33,90,32,28,94,28,95,92,32,90, +93,90,66,90,67,204,66,132,109,132,30,118,31,210,12,218,97,198,108,74, +241,74,158,10,148,96,136,136,105,184,144,116,206,116,192,164,156,210,93,240, +142,140,158,176,180,202,237,238,188,26,217,55,12,44,127,44,46,10,46,80, +101,80,100,10,101,80,32,110,33,152,32,110,110,110,111,150,32,152,111,152, +12,188,131,188,70,80,71,244,144,34,226,34,226,124,147,124,184,34,185,122, +144,34,144,212,146,218,150,224,152,226,156,226,220,226,226,222,230,216,241,197, +16,68,101,68,18,156,101,116,62,8,62,230,42,236,31,224,122,34,222,34, +222,124,127,124,172,36,173,122,120,34,120,212,124,218,130,222,134,222,210,222, +218,218,226,210,237,191,18,46,117,46,26,84,107,84,12,124,119,124,70,10, +71,250,64,136,19,210,72,146,107,184,136,36,230,36,230,128,141,128,180,40, +181,124,136,34,136,212,138,222,142,228,150,234,210,234,222,232,230,224,241,203, +16,84,97,84,60,10,61,184,18,202,97,172,118,180,118,30,216,30,217,176, +164,68,162,140,160,166,146,194,126,216,89,238,178,182,239,237,32,26,221,26, +32,86,32,50,222,50,223,86,128,26,129,102,54,72,109,72,150,72,201,72, +52,90,109,90,150,90,201,90,24,122,135,122,54,104,54,146,112,146,113,106, +44,164,122,164,122,186,46,186,47,164,22,206,137,206,80,148,81,242,156,118, +156,178,152,198,144,220,127,242,156,118,216,118,216,226,196,236,183,224,158,150, +213,150,156,184,215,185,46,28,216,28,216,78,48,78,49,30,100,30,101,74, +158,32,157,72,46,122,211,122,20,162,239,162,128,88,129,162,126,168,50,228, +197,220,160,180,213,237,104,20,45,62,154,20,213,56,168,48,116,92,68,114, +17,128,92,52,128,82,158,98,188,108,239,120,70,130,192,130,192,174,73,174, +132,130,133,172,68,130,68,214,70,220,76,228,82,230,176,230,196,228,208,220, +223,197,120,14,95,62,50,68,51,240,50,68,206,68,207,238,52,136,205,136, +50,208,205,209,20,70,111,70,68,8,69,244,62,80,23,160,72,100,105,132, +176,8,161,58,130,62,230,62,231,238,128,64,129,244,130,136,229,136,130,210, +229,211,16,34,243,34,122,34,103,90,54,92,55,240,54,92,200,92,201,240, +56,154,199,154,56,214,199,215,14,74,89,74,56,12,56,232,38,240,27,226, +18,156,89,116,102,30,222,30,222,84,100,84,101,32,142,32,143,80,182,32, +183,80,100,126,225,126,160,96,161,166,86,166,243,166,158,172,102,230,207,222, +184,186,223,241,80,12,52,74,17,120,60,58,61,248,92,40,247,40,170,42, +149,98,118,100,119,244,118,98,220,98,221,242,118,156,219,156,118,218,219,219, +36,174,36,30,116,30,117,168,78,76,76,130,72,164,64,188,50,210,19,238, +86,180,121,212,168,8,154,72,133,120,154,72,245,72,212,72,208,102,200,140, +190,172,178,190,154,212,115,240,156,106,164,144,174,170,184,188,202,206,239,235, +108,22,70,32,29,38,72,32,72,158,66,184,54,208,27,238,28,92,113,92, +20,146,117,146,120,30,233,30,126,76,225,76,124,120,225,120,110,168,241,168, +174,30,175,245,100,24,66,34,23,38,14,90,107,90,62,36,63,244,58,104, +38,154,19,184,66,116,99,150,168,14,149,46,120,48,224,48,225,132,120,48, +120,136,223,136,122,90,223,90,170,50,170,94,166,112,154,146,137,174,92,184, +243,184,186,144,187,245,14,42,83,42,18,120,83,120,52,42,53,204,18,226, +95,182,110,14,133,46,82,64,163,64,94,90,132,148,159,204,140,66,138,120, +128,162,112,198,79,240,160,40,237,40,162,124,235,124,140,226,245,226,198,40, +199,225,12,46,95,46,12,120,89,120,14,218,95,182,52,48,53,198,108,78, +101,142,136,14,136,110,132,146,126,180,118,198,106,212,79,242,150,44,243,44, +152,130,239,130,138,226,247,226,194,44,195,225,12,72,79,72,10,158,71,130, +50,10,50,226,34,236,23,222,122,10,111,40,96,44,96,134,96,156,94,178, +90,198,82,218,73,234,98,42,140,42,140,224,126,234,111,222,78,122,147,122, +112,66,123,98,112,146,123,178,174,32,174,66,174,82,170,96,161,112,174,30, +214,30,214,82,214,92,216,96,220,100,241,100,172,130,184,166,192,184,204,202, +222,222,241,234,158,128,222,128,218,146,212,166,204,182,192,202,180,216,157,237, +14,72,101,72,62,8,62,228,56,236,36,240,23,230,14,158,101,120,220,20, +190,30,166,36,144,38,124,42,126,78,126,144,122,166,114,194,98,216,87,230, +126,102,218,102,206,136,196,164,182,186,164,206,144,222,117,238,144,102,152,130, +160,152,172,172,184,188,198,202,239,231,74,6,69,36,46,38,46,138,44,160, +38,192,34,206,21,234,46,38,102,38,102,218,96,230,82,232,69,220,10,122, +109,122,66,64,79,94,68,146,81,180,150,28,150,68,146,82,144,88,136,100, +127,108,150,26,200,26,200,88,202,90,206,94,212,96,239,92,122,124,212,124, +206,142,202,158,192,176,188,184,172,206,156,218,138,230,121,240,144,124,150,142, +160,166,168,180,184,200,198,210,214,224,239,237,54,28,23,114,78,26,117,106, +38,114,94,114,94,200,92,210,86,216,74,222,65,216,54,114,54,142,52,166, +46,190,36,210,21,230,114,30,239,30,174,30,167,76,136,190,136,78,216,78, +217,188,178,108,176,140,174,168,170,182,164,196,156,208,142,220,115,238,186,198, +237,237,14,72,107,72,60,8,61,242,56,80,46,114,32,142,19,168,64,96, +99,138,222,20,172,32,126,38,128,122,122,166,85,230,130,96,218,96,202,148, +190,172,172,200,121,236,146,96,160,144,174,174,198,198,239,231,46,26,46,130, +44,164,40,188,34,208,21,236,92,18,93,96,46,96,117,96,46,144,92,144, +93,238,230,22,206,30,184,34,166,34,138,36,138,134,136,160,132,182,126,198, +111,232,140,96,224,96,204,158,192,178,178,200,160,218,133,236,156,96,158,118, +166,144,178,170,188,188,202,206,239,239,16,74,99,74,60,12,60,230,52,238, +44,240,29,226,14,152,93,128,146,22,124,74,103,116,184,16,194,54,208,80, +239,112,122,108,206,106,206,212,198,224,184,230,165,220,148,110,146,148,138,182, +126,204,95,235,14,68,99,68,60,6,60,228,54,236,42,238,27,224,16,156, +91,122,104,104,235,104,94,160,245,160,170,4,171,244,110,36,141,78,226,32, +197,81,68,10,44,70,19,110,52,52,53,244,82,104,235,104,76,160,245,160, +158,6,159,242,90,32,125,74,214,28,185,79,40,18,61,44,18,56,85,56, +32,76,47,106,76,74,63,122,12,124,85,124,18,174,81,174,54,124,54,174, +52,186,42,216,25,240,154,28,140,34,120,36,98,38,98,130,96,160,90,190, +84,208,71,230,122,36,122,218,147,204,140,186,153,222,144,34,144,76,146,108, +148,144,154,166,160,190,175,220,180,14,203,38,162,54,233,54,170,72,187,100, +222,70,203,120,162,120,243,120,200,120,201,246,168,170,237,171,50,36,95,78, +206,30,165,78,34,104,229,104,20,162,241,162,130,8,131,249,38,60,186,60, +186,206,182,216,176,226,168,228,146,230,133,224,112,10,112,84,110,114,108,132, +102,152,94,174,84,194,72,206,50,224,27,238,58,106,44,142,21,174,204,112, +218,136,237,169,66,14,18,96,73,94,96,62,28,162,99,144,20,218,101,198, +110,34,141,76,228,32,197,82,112,106,231,106,104,164,241,164,172,8,173,247, +28,58,139,58,38,108,131,108,18,160,147,160,84,12,84,122,82,158,82,168, +78,186,72,202,62,218,41,242,162,244,162,36,224,36,196,108,212,124,224,144, +230,160,232,178,230,190,224,198,212,202,193,203,24,40,145,40,34,70,137,70, +22,102,149,102,84,10,84,104,76,122,66,136,56,148,44,154,31,164,164,142, +164,28,224,28,200,70,210,76,218,82,224,90,228,96,230,106,228,116,224,124, +208,128,197,118,66,226,66,164,202,164,202,208,198,218,186,226,173,214,134,134, +135,249,18,74,95,74,60,10,61,242,56,82,46,116,19,170,62,96,93,134, +98,60,167,62,100,112,165,112,88,162,169,162,132,10,132,134,126,178,124,192, +118,206,99,238,186,244,186,32,234,32,208,108,222,122,230,134,238,150,240,170, +238,190,228,198,209,191,12,72,95,72,58,10,59,242,56,74,34,138,17,172, +60,100,89,130,148,12,175,32,102,46,237,46,134,56,153,88,200,56,185,88, +110,118,110,92,230,92,231,118,154,102,183,126,102,138,239,138,146,138,146,160, +142,184,132,204,122,220,95,238,146,172,222,172,222,200,218,218,206,232,192,236, +177,223,38,28,38,164,34,180,26,208,15,236,38,26,88,26,88,220,78,234, +64,234,59,224,40,84,87,84,40,142,87,142,150,10,177,32,106,46,233,46, +134,58,151,82,198,56,183,84,114,122,114,92,228,92,229,120,154,108,175,130, +106,142,239,142,156,144,154,160,152,180,148,192,142,204,132,220,120,230,109,238, +154,178,216,178,212,214,210,224,202,234,192,238,173,231,72,16,20,96,71,96, +88,68,24,160,85,148,16,206,89,190,96,58,169,58,98,108,167,108,94,160, +171,160,134,12,134,124,132,144,130,172,120,200,108,220,93,238,182,242,182,32, +230,32,206,104,214,116,222,126,226,136,232,146,236,160,234,174,232,184,218,196, +201,191,16,74,91,74,56,12,57,246,52,88,19,168,58,100,85,134,100,46, +233,46,108,76,221,76,92,110,241,110,158,10,156,44,150,74,140,110,128,130, +112,146,96,160,83,170,178,110,188,124,198,136,210,146,220,154,241,162,118,164, +209,164,94,200,233,200,162,132,163,245,18,44,109,44,60,44,56,66,48,90, +38,108,28,124,19,136,46,218,46,108,94,108,95,212,48,190,93,190,154,10, +183,32,118,44,243,44,142,58,159,84,208,52,189,86,122,120,122,90,234,90, +235,120,158,106,187,132,110,140,245,140,162,140,162,156,158,180,154,196,146,208, +136,218,122,230,103,242,160,176,224,176,222,194,222,214,218,228,208,236,198,238, +177,229,34,140,34,68,108,68,108,140,37,140,72,12,73,198,16,210,113,190, +104,166,125,212,124,64,235,64,130,112,229,112,122,164,245,164,178,12,179,245, +66,12,44,58,23,86,46,54,103,54,28,100,103,100,20,148,107,148,64,100, +64,228,105,196,152,12,185,36,118,46,241,46,142,62,157,82,204,58,189,88, +122,124,122,94,234,94,235,120,160,106,189,132,112,142,247,142,162,144,162,166, +156,184,150,200,142,212,130,224,120,230,105,238,158,176,222,176,216,222,210,232, +200,236,192,236,183,231,82,12,54,72,17,126,56,66,57,244,142,12,169,34, +92,46,239,46,132,60,149,88,202,58,185,88,98,122,98,92,232,92,233,120, +148,108,171,130,82,140,247,140,144,142,144,166,136,192,124,212,110,226,85,238, +142,174,218,174,212,214,210,228,202,234,192,236,171,237,44,24,77,60,12,100, +60,100,60,222,99,184,148,14,177,36,96,48,237,48,132,62,147,84,198,60, +185,90,98,126,98,96,230,96,231,126,150,108,177,130,84,144,245,144,146,144, +144,172,140,190,134,204,128,214,120,222,97,238,144,176,216,176,210,220,206,228, +196,232,171,235,20,46,241,46,98,10,99,70,164,10,165,74,88,74,62,116, +27,148,78,94,206,94,204,132,200,170,198,180,194,182,175,186,74,174,156,174, +156,130,68,130,68,218,70,224,74,228,82,230,196,230,208,230,220,226,224,220, +233,199,18,232,30,202,36,178,38,154,40,126,40,28,90,28,90,220,84,226, +76,228,59,226,40,88,91,88,40,142,89,142,152,8,132,50,109,86,132,50, +228,50,228,152,224,164,218,170,206,176,195,176,128,146,184,146,184,96,126,96, +126,210,130,220,132,224,140,228,144,230,210,230,218,228,224,224,237,201,88,14, +60,64,25,108,70,50,210,50,210,146,208,156,202,164,196,170,165,174,64,152, +148,152,148,94,62,94,62,204,64,216,72,226,80,230,196,230,212,228,224,218, +235,195,114,14,145,36,20,46,239,46,76,60,54,92,25,122,58,88,59,170, +100,72,202,72,202,98,100,98,101,74,78,122,235,122,152,100,153,166,144,126, +114,146,83,158,156,128,225,160,110,166,70,200,29,224,92,182,92,234,135,208, +198,168,165,204,142,170,162,204,174,216,188,224,231,241,36,28,128,28,123,96, +40,64,123,64,16,96,155,96,88,98,88,230,80,234,59,232,32,122,61,150, +84,156,25,206,140,120,93,156,98,160,151,200,174,40,175,180,218,14,218,220, +212,228,206,230,183,229,16,36,237,36,92,8,93,64,164,8,165,62,34,66, +69,92,22,110,57,136,26,238,63,166,80,78,235,78,182,52,205,66,96,170, +96,102,212,102,213,168,98,126,209,126,98,148,209,148,148,58,149,166,74,188, +241,188,194,166,194,224,192,232,188,238,165,240,110,200,135,225,34,26,221,26, +34,94,34,54,222,54,223,96,130,26,131,110,54,80,109,80,54,102,107,102, +152,80,205,80,150,102,205,102,84,110,60,140,27,166,70,130,200,130,198,162, +194,180,188,190,172,192,169,188,72,184,150,184,150,156,70,156,70,210,72,216, +76,220,82,224,88,228,92,228,190,228,202,226,210,222,216,216,231,195,80,14, +52,74,17,122,56,72,57,242,112,30,210,30,210,92,114,92,115,32,82,134, +237,134,160,92,161,244,152,138,122,186,83,218,166,138,188,174,210,198,239,219, +74,12,52,64,21,104,58,56,59,162,106,26,210,26,210,66,106,66,107,26, +82,98,239,98,158,66,159,160,150,100,122,128,87,152,162,100,184,120,208,138, +235,152,50,186,217,186,134,154,135,226,28,228,241,229,56,16,40,64,19,102, +42,58,96,58,79,96,54,106,54,232,95,190,142,10,124,62,99,102,130,50, +222,50,222,152,220,162,212,168,195,170,132,152,178,152,178,94,128,94,128,216, +130,220,136,226,140,230,144,232,210,232,218,230,226,224,232,218,239,199,108,18, +143,44,34,102,34,56,226,56,227,100,56,98,203,98,60,156,199,156,16,226, +241,226,126,98,127,224,168,172,197,207,12,72,91,72,58,10,58,220,52,230, +44,232,36,234,29,230,16,156,95,118,148,10,126,56,97,92,130,50,220,50, +220,148,220,160,216,170,208,176,191,176,124,148,178,148,178,98,120,98,120,206, +122,214,124,220,132,226,134,228,214,228,224,224,228,220,237,199,14,72,103,72, +60,10,60,228,52,234,27,230,14,160,97,126,166,90,188,90,202,84,208,76, +212,30,122,30,123,246,124,122,216,122,206,158,194,186,176,208,145,234,146,122, +162,164,188,200,206,212,241,233,60,26,200,26,200,82,60,82,61,26,60,52, +199,52,36,112,219,112,96,88,97,142,160,88,161,140,14,144,243,144,94,144, +74,164,50,176,21,190,160,144,168,154,188,168,208,180,239,190,130,152,130,228, +124,238,101,238,76,174,101,192,46,228,127,200,134,194,207,232,174,174,145,201, +100,16,66,38,29,56,76,54,95,72,46,74,65,92,122,56,76,92,44,112, +21,122,78,90,90,102,104,120,112,134,114,164,112,196,108,218,96,230,84,236, +61,234,92,110,62,146,29,170,110,144,74,180,31,210,162,16,144,70,125,108, +146,68,230,68,230,204,222,220,202,232,169,234,148,122,191,169,62,14,40,52, +21,80,42,48,92,48,73,84,30,90,30,178,100,178,100,92,33,92,32,134, +97,134,66,94,67,174,16,224,115,212,164,14,146,58,121,90,146,58,222,58, +222,158,218,168,210,176,189,178,138,152,184,152,184,100,134,100,134,212,136,218, +142,226,150,230,218,230,226,226,241,205,32,62,23,122,92,58,65,88,60,150, +79,172,58,12,58,110,58,136,54,158,48,182,21,230,110,22,218,22,218,74, +110,74,111,22,110,48,217,48,94,104,231,104,140,86,141,132,188,84,189,132, +82,136,243,136,132,140,110,166,81,192,188,138,208,158,241,178,162,148,162,226, +158,230,152,234,135,236,124,168,143,186,158,194,97,220,200,170,181,194,166,190, +229,223,18,76,103,76,64,12,65,244,58,82,40,128,17,166,68,104,101,136, +98,38,241,38,178,38,158,96,138,132,122,158,93,186,192,110,220,144,241,176, +168,72,169,243,18,46,101,46,60,46,52,84,38,108,21,136,42,224,42,114, +88,114,89,216,44,190,87,190,172,12,159,38,124,44,224,44,224,132,124,132, +125,44,126,88,223,88,172,44,170,98,166,122,160,142,150,154,123,176,104,186, +245,186,178,152,179,247,104,12,105,148,154,12,155,148,28,42,99,42,158,40, +229,40,38,80,101,80,156,80,219,80,22,120,101,120,156,120,237,120,50,166, +40,200,27,222,120,158,147,184,190,168,212,190,231,210,90,162,90,214,92,222, +96,226,102,228,158,228,168,224,176,216,181,203,124,8,111,40,56,46,202,46, +202,132,56,132,57,46,58,86,199,86,130,48,124,94,122,108,102,138,65,166, +14,178,243,178,136,148,137,245,94,24,95,238,22,98,91,98,14,216,93,192, +152,16,152,208,152,214,154,218,160,224,172,226,176,226,210,226,222,224,230,214, +237,194,230,80,192,94,155,105,100,14,101,116,152,14,153,120,20,42,99,42, +28,72,97,72,18,100,99,100,228,42,155,42,218,70,155,70,236,98,155,98, +28,136,225,136,122,108,66,174,207,174,16,204,241,204,132,152,133,247,102,8, +103,96,26,40,99,40,16,96,101,78,156,6,156,78,156,84,158,86,162,90, +216,90,224,90,228,84,239,68,224,26,159,52,70,236,70,120,194,120,194,216, +192,224,186,230,178,232,159,236,72,150,191,150,72,184,191,185,62,168,62,36, +196,36,197,164,130,72,128,108,126,132,122,152,116,170,108,182,92,200,74,212, +56,220,25,230,144,172,229,231,68,10,46,54,17,86,46,56,111,56,28,96, +97,96,16,144,103,144,60,98,60,222,103,194,128,176,128,36,220,36,221,174, +172,74,172,140,170,162,166,180,158,194,146,208,134,220,122,228,109,238,186,182, +214,206,241,235,82,12,54,74,19,124,58,68,59,246,142,10,175,36,90,50, +237,50,120,70,145,106,204,66,181,114,80,120,249,120,112,244,112,158,216,158, +217,242,114,220,215,221,94,16,64,52,25,82,32,20,60,50,68,62,74,80, +80,102,84,124,84,146,82,180,80,198,70,214,58,222,33,228,78,102,46,140, +23,160,124,166,124,26,222,26,223,164,168,64,168,136,164,160,158,180,146,200, +136,214,103,236,180,186,212,212,239,239,98,12,72,52,43,80,76,46,182,46, +154,76,122,100,92,116,19,138,90,62,124,94,140,104,162,114,196,126,237,136, +64,246,64,144,196,144,197,242,66,184,195,184,66,224,195,224,128,144,129,223, +104,14,78,40,51,68,78,40,184,40,148,68,110,90,80,100,21,112,94,54, +120,76,144,86,170,94,200,100,239,104,70,110,194,110,194,168,70,168,71,110, +70,140,193,140,132,112,133,166,56,184,31,232,96,182,96,222,96,230,100,234, +106,236,136,238,162,236,176,232,182,224,185,212,128,178,155,206,192,184,231,221, +66,18,66,142,62,160,58,184,50,198,25,234,36,70,21,132,102,64,71,110, +66,158,103,200,152,14,181,40,112,52,235,52,134,72,157,108,210,68,187,120, +100,124,247,124,128,244,128,162,222,162,223,242,130,222,221,223,44,12,75,44, +14,62,88,62,80,80,64,102,48,122,30,138,17,150,56,116,57,242,98,106, +79,144,56,134,101,160,84,230,102,208,116,184,122,156,124,142,124,60,232,60, +223,88,176,12,177,120,126,122,216,122,206,146,198,164,184,186,168,206,150,218, +117,238,140,124,150,146,162,168,172,180,186,198,210,218,243,237,24,50,233,50, +124,10,110,50,100,64,88,80,72,92,62,98,21,118,152,50,164,66,174,78, +188,88,208,102,239,114,66,112,193,112,128,76,129,148,14,176,241,176,84,134, +84,190,78,210,64,224,52,234,31,244,176,136,177,245,20,48,239,48,88,12, +89,82,168,12,169,80,24,106,229,106,126,66,127,242,70,194,187,194,118,110, +72,168,23,208,134,112,156,140,178,162,200,178,237,201,28,70,233,70,130,10, +131,248,66,188,187,188,116,74,104,104,90,128,76,148,62,164,48,180,32,196, +21,206,140,72,152,100,164,126,178,148,190,166,208,182,235,203,78,20,52,60, +29,84,62,48,127,48,78,50,101,82,172,18,152,50,133,74,154,48,233,48, +176,48,199,80,26,110,229,110,128,80,129,242,76,190,183,190,120,114,102,142, +88,160,68,178,44,192,27,202,134,114,144,128,154,142,168,154,180,166,202,180, +233,197,56,26,56,58,216,58,217,20,136,12,137,56,20,240,30,230,38,218, +44,204,48,194,48,180,48,92,114,92,114,224,94,230,83,230,50,130,111,130, +50,170,113,170,154,94,154,174,148,198,142,216,127,240,156,92,220,92,220,230, +204,238,183,236,156,132,219,132,156,170,217,171,70,18,18,100,67,94,88,66, +26,162,87,150,18,214,83,194,74,242,92,218,100,194,106,162,106,28,146,28, +146,212,138,224,119,224,108,86,145,86,108,144,145,144,156,242,164,230,172,212, +178,192,182,166,182,28,226,28,226,228,210,232,197,228,184,84,225,84,184,144, +225,145,28,28,227,28,128,30,129,104,124,42,78,74,27,98,152,58,194,76, +235,98,60,120,60,166,56,196,44,218,25,238,60,120,204,120,204,230,194,236, +184,238,173,232,130,122,131,240,62,154,203,154,60,188,203,189,28,30,239,30, +102,30,94,50,74,72,52,92,21,112,82,68,198,68,198,112,80,112,81,68, +30,154,106,154,90,180,76,198,56,214,31,228,134,128,134,228,122,236,101,232, +138,144,152,168,176,192,204,210,237,224,218,134,192,152,172,162,155,171,34,36, +80,36,80,94,34,94,35,36,62,96,63,208,62,140,93,140,32,130,33,218, +20,224,87,202,110,22,110,60,224,60,225,18,166,12,167,58,80,240,90,228, +98,216,104,202,106,186,106,90,150,90,150,220,144,224,136,226,127,224,108,130, +149,130,108,168,149,168,160,240,172,220,178,200,182,164,182,88,230,88,230,226, +220,236,203,236,184,130,229,130,182,168,229,169,104,20,139,54,204,18,171,68, +82,74,231,74,74,134,237,134,128,76,128,142,124,168,116,188,99,210,184,76, +185,216,26,34,63,68,14,118,58,118,59,204,18,234,34,220,48,212,62,210, +80,220,98,226,120,232,154,236,188,236,239,233,84,34,231,34,116,62,202,62, +202,94,118,94,119,64,98,122,218,122,218,196,98,196,99,124,98,158,217,158, +156,124,157,194,28,26,69,62,12,110,52,110,53,208,22,228,40,216,52,210, +68,210,94,220,104,224,132,228,166,230,241,227,112,8,105,28,66,34,196,34, +196,100,64,100,65,36,66,56,195,56,66,78,195,78,56,122,208,122,208,168, +54,168,55,124,56,146,205,146,128,124,129,166,16,194,243,194,96,194,96,206, +94,218,84,226,72,236,51,242,172,194,173,245,46,32,46,226,111,194,46,108, +117,108,146,20,146,216,148,224,154,230,158,230,204,230,216,228,224,222,228,212, +235,190,218,76,182,102,149,119,46,30,130,30,130,70,44,70,45,30,12,98, +157,98,90,72,91,126,36,238,36,128,138,128,139,234,38,216,137,216,68,154, +110,154,110,190,68,190,69,154,176,244,176,34,228,34,198,110,204,116,216,126, +224,136,232,150,236,164,236,176,232,186,222,196,203,203,72,14,48,52,19,82, +50,50,129,50,78,50,101,82,168,12,148,48,127,78,148,50,239,50,182,50, +207,80,190,90,166,100,140,104,104,110,33,110,28,150,211,140,20,190,227,180, +112,110,112,222,114,228,120,232,128,236,204,236,218,234,226,226,237,203,78,14, +50,48,23,74,78,74,52,116,19,148,56,112,57,246,80,226,92,212,104,188, +114,164,116,126,118,112,118,54,228,54,215,84,170,10,171,118,120,120,212,120, +198,160,180,186,162,206,144,220,115,238,134,120,146,148,158,168,178,194,194,208, +206,216,241,235,26,34,125,34,32,72,117,72,78,36,79,108,32,122,119,104, +176,12,165,38,146,42,220,42,220,114,146,114,147,44,148,78,219,78,16,146, +245,146,96,146,80,172,66,186,46,202,21,216,80,180,206,180,207,242,80,180, +81,244,80,224,205,225,14,40,237,40,90,4,91,70,160,6,161,70,126,54, +115,78,46,84,202,84,202,146,48,146,49,84,172,92,126,114,75,128,80,94, +134,114,177,132,50,160,50,234,119,214,52,184,117,184,144,156,144,220,146,226, +150,230,154,232,210,232,220,230,226,224,232,218,237,202,216,168,147,197,14,40, +239,40,94,8,95,66,156,8,157,68,30,80,57,106,124,78,103,110,36,244, +36,126,122,126,122,212,120,218,114,224,97,222,76,72,77,226,60,154,49,194, +90,154,109,188,168,74,154,116,137,148,158,108,237,108,202,108,198,146,190,172, +178,194,170,204,154,222,131,238,160,138,168,160,178,182,190,200,206,216,235,239, +56,58,129,58,54,12,54,134,131,106,152,12,152,112,152,118,158,124,164,128, +208,128,216,126,224,122,228,116,233,100,226,40,155,72,14,176,243,176,130,140, +131,245,50,12,50,98,117,80,52,46,123,46,148,8,148,78,150,82,152,88, +158,92,212,92,222,88,229,68,220,32,184,46,151,54,16,124,239,124,78,126, +58,160,23,188,58,160,118,160,102,190,90,206,76,218,54,230,27,240,58,186, +83,208,144,126,144,218,146,222,148,226,154,230,208,230,220,226,226,220,235,198, +218,156,147,187,48,16,48,118,119,100,48,56,119,56,144,8,144,94,144,98, +146,102,148,108,154,112,208,112,216,110,222,106,228,98,231,82,216,28,182,48, +145,62,50,154,38,184,23,212,86,144,86,214,90,220,94,226,98,230,160,230, +172,228,180,224,184,218,188,210,191,196,106,124,137,148,178,132,146,170,122,192, +100,210,84,220,25,240,200,154,237,207,224,26,180,36,132,40,33,44,52,210, +52,102,206,102,206,190,202,198,196,202,171,204,126,40,127,245,118,12,155,36, +234,50,52,50,52,156,46,184,34,212,21,232,94,76,94,226,145,202,94,132, +147,132,166,72,166,216,168,226,172,230,178,232,212,232,222,228,228,224,239,206, +232,106,167,147,134,14,161,34,240,44,62,44,62,146,54,180,31,234,24,66, +43,102,18,158,59,130,98,74,214,74,214,142,100,142,101,76,100,110,213,110, +156,76,157,140,76,170,243,170,126,172,126,184,124,196,118,210,104,224,81,238, +184,170,185,241,38,68,39,246,52,20,81,60,106,42,220,42,220,228,212,236, +189,238,66,108,195,108,146,66,146,216,138,222,117,220,132,110,118,140,102,164, +92,178,67,203,26,34,55,76,136,30,103,76,60,132,47,186,98,132,115,176, +82,10,83,220,32,236,32,96,132,96,132,222,103,224,176,10,166,60,147,110, +164,68,239,68,208,70,206,106,200,136,192,166,176,200,141,242,162,116,170,152, +186,184,204,206,239,239,36,22,63,44,128,18,103,44,40,150,40,66,126,66, +126,122,122,132,103,138,82,10,83,144,66,84,53,118,96,80,117,112,176,8, +160,48,143,78,156,56,237,56,204,56,202,76,194,96,182,116,166,132,137,152, +160,80,176,106,192,120,206,130,235,142,20,178,241,178,96,154,92,182,86,202, +74,220,56,230,37,240,168,150,169,245,52,94,25,172,100,26,155,72,200,118, +235,176,196,34,170,106,140,148,106,180,76,202,27,224,94,72,94,212,96,220, +100,224,106,228,110,230,160,230,174,228,182,222,190,212,197,189,18,184,28,168, +38,144,42,120,44,96,44,36,110,36,110,98,47,98,52,234,52,142,112,142, +113,228,111,228,52,206,111,206,164,14,191,36,126,48,237,48,138,72,165,106, +216,64,191,114,122,120,247,120,126,172,239,172,182,120,183,247,18,140,34,118, +44,94,46,80,46,38,110,38,110,78,47,78,54,114,114,114,114,152,54,152, +55,114,164,16,189,36,128,46,231,46,148,60,167,90,216,58,193,90,126,96, +247,96,130,132,235,132,180,96,181,172,52,192,215,192,134,154,135,230,26,232, +239,233,22,120,38,96,44,80,46,34,116,34,116,64,45,64,54,94,112,94, +112,120,54,120,55,94,166,10,189,32,128,42,235,42,150,54,163,74,208,52, +193,76,124,80,245,80,132,108,237,108,182,82,183,134,68,242,68,146,202,146, +202,226,190,234,165,236,70,172,199,172,70,200,201,201,64,168,78,144,82,124, +88,82,88,34,136,34,136,90,89,90,94,130,136,130,136,192,94,192,95,130, +172,10,199,36,150,48,235,48,160,66,177,94,212,64,197,104,142,112,241,112, +152,158,233,158,188,112,189,218,28,24,63,60,10,112,50,112,51,204,18,230, +44,212,50,208,66,212,84,222,110,230,136,234,239,231,32,244,32,32,90,32, +58,104,72,122,80,134,84,148,84,160,82,176,74,180,53,188,116,20,116,128, +157,106,118,66,159,66,174,14,174,116,178,124,188,130,216,130,226,122,237,102, +226,40,177,80,104,178,219,178,158,140,159,220,86,226,237,227,16,46,107,46, +42,16,42,78,82,78,83,18,34,108,92,108,92,152,36,152,37,108,16,182, +105,182,64,80,65,244,138,18,120,66,101,96,122,60,123,244,146,36,237,36, +156,74,224,74,224,148,156,148,157,78,158,110,223,110,188,36,188,152,184,176, +176,196,162,214,145,234,150,162,162,182,178,202,200,218,231,231,92,74,212,72, +206,178,198,188,171,194,146,10,144,86,136,132,126,156,91,198,36,28,75,66, +14,110,58,110,59,202,22,226,58,202,74,208,96,220,110,228,132,230,182,230, +241,229,68,16,24,94,77,90,98,58,28,160,99,150,20,208,91,192,150,14, +181,42,82,230,104,196,114,166,120,136,122,110,122,54,222,54,222,98,125,98, +124,244,124,132,228,132,228,230,206,240,199,238,126,176,225,176,158,136,159,218, +192,134,193,219,30,178,30,32,98,32,99,172,66,66,66,162,58,188,44,214, +17,240,74,184,103,212,226,16,160,36,113,44,154,50,181,84,118,102,208,102, +194,134,174,162,141,202,104,238,116,218,128,204,134,204,148,210,164,220,190,226, +245,225,120,10,153,36,24,216,40,194,50,168,56,140,58,114,60,96,60,46, +214,46,214,92,63,92,72,244,72,132,222,132,222,230,212,236,193,236,74,176, +219,176,122,134,123,226,170,134,171,229,70,14,46,70,15,114,50,64,51,238, +88,28,241,28,102,66,220,66,220,144,102,144,103,68,104,104,219,104,160,30, +160,112,158,156,152,182,140,204,122,218,102,228,79,236,100,162,118,186,146,206, +188,222,239,233,104,12,139,40,26,54,229,54,106,56,107,130,152,56,153,128, +76,78,31,130,182,78,227,122,54,142,178,142,162,172,138,196,110,214,84,226, +41,242,80,142,94,162,110,178,132,198,162,210,190,222,229,231,100,12,141,56, +18,78,237,78,120,78,121,250,122,122,156,146,178,170,199,193,52,10,71,38, +16,52,107,52,32,74,47,102,84,70,65,114,14,122,99,122,60,122,60,174, +56,196,48,216,31,238,18,166,99,166,114,88,107,130,134,14,134,130,130,166, +120,196,110,212,91,234,176,12,199,36,150,52,241,52,162,72,179,102,222,68, +199,120,150,122,243,122,198,122,199,244,150,168,241,169,48,16,67,42,14,56, +105,56,34,76,47,110,84,72,65,122,14,126,105,126,20,170,99,170,64,126, +64,176,60,192,54,206,48,220,40,228,25,244,110,22,133,64,94,98,124,98, +124,224,157,196,180,12,197,38,146,54,237,54,166,72,179,106,220,68,199,118, +146,124,243,124,154,170,237,170,196,124,197,249,48,14,67,38,16,52,97,54, +36,68,51,104,80,68,65,116,14,122,97,122,18,168,91,168,58,122,58,174, +54,192,50,206,44,220,27,240,134,16,96,102,137,100,146,74,108,164,155,160, +92,210,157,206,180,10,199,36,158,52,237,52,170,68,185,104,222,68,203,118, +154,122,241,122,160,172,237,172,196,122,197,245,132,14,165,42,74,196,90,164, +96,132,96,106,96,52,210,52,210,92,99,92,108,212,108,122,218,122,218,202, +208,210,197,210,110,160,217,160,142,126,143,204,178,126,179,204,28,34,69,70, +8,116,52,116,53,208,18,230,38,218,52,212,70,216,90,222,108,228,134,234, +148,236,196,236,241,231,16,78,109,78,64,12,65,244,60,84,42,138,23,178, +68,108,103,142,114,36,225,36,104,100,241,100,170,102,170,230,156,236,139,236, +136,144,97,210,198,144,243,207,90,34,141,34,88,8,89,60,20,234,32,216, +38,196,42,172,42,154,42,64,148,64,139,86,56,106,129,94,92,76,90,116, +90,126,96,132,104,134,132,134,142,126,149,112,220,18,173,70,220,82,159,140, +230,134,197,174,196,174,151,204,52,240,68,220,76,204,78,194,78,164,120,164, +120,214,122,222,130,226,140,228,150,230,198,230,210,228,222,224,232,218,236,210, +243,191,20,232,28,216,34,192,38,166,38,146,38,28,84,28,84,226,64,232, +57,224,40,86,83,86,40,140,83,140,102,24,243,24,118,58,226,58,226,102, +118,102,119,58,154,28,155,100,190,26,191,100,112,132,233,132,102,164,245,164, +172,164,172,220,168,230,164,234,147,234,138,186,109,230,202,186,239,225,34,44, +225,44,48,80,213,80,18,120,241,120,128,10,129,118,116,120,102,142,84,160, +64,180,46,190,21,202,138,122,148,152,156,168,172,186,190,204,204,212,233,224, +214,138,167,180,94,154,94,236,149,205,36,24,63,46,130,22,101,50,36,128, +36,58,126,58,127,122,80,18,81,114,68,76,49,102,98,76,113,102,172,20, +141,74,156,48,235,48,208,48,194,78,178,98,145,120,160,70,174,88,190,104, +231,126,102,118,74,140,41,158,82,136,162,136,143,156,60,160,194,160,194,208, +62,208,63,160,64,184,191,184,130,162,131,206,18,230,235,231,38,26,67,46, +132,26,103,50,40,154,40,64,128,64,128,130,122,140,105,142,84,14,85,144, +66,84,53,120,98,82,111,108,176,12,156,58,143,80,158,56,239,56,208,56, +200,82,188,108,178,122,143,148,162,80,180,110,198,126,237,154,54,176,23,228, +122,164,151,192,194,176,239,220,88,170,88,216,90,226,96,232,108,234,154,234, +166,232,180,224,187,203,46,32,128,32,128,88,48,88,49,34,24,136,134,132, +130,206,122,218,114,224,93,224,82,102,78,156,74,180,64,204,54,216,29,240, +178,46,179,174,228,14,228,220,218,232,191,235,122,8,153,32,24,238,42,216, +50,184,56,132,56,42,239,42,18,70,39,108,12,160,53,132,144,50,127,70, +98,134,98,72,210,72,210,136,99,136,100,92,207,92,100,114,209,114,154,142, +138,156,112,170,69,188,152,146,164,156,180,164,204,174,241,184,186,178,117,204, +114,174,114,220,116,228,122,232,186,232,198,230,206,222,213,205,18,78,89,78, +60,14,61,244,56,92,38,144,21,180,62,104,93,132,98,80,163,80,132,14, +133,244,126,90,110,136,87,170,134,108,165,140,220,20,202,60,173,100,228,88, +204,126,186,146,169,162,238,154,212,194,194,212,157,239,34,18,63,52,12,70, +99,70,72,72,66,128,54,172,36,206,25,228,26,108,93,198,106,44,171,44, +96,90,241,90,148,104,149,216,116,122,117,222,150,148,179,148,92,234,181,210, +206,32,231,62,188,10,188,94,190,138,196,170,204,204,214,228,226,238,239,211, +36,20,67,50,20,82,53,110,52,134,25,228,66,104,147,104,114,12,115,102, +86,34,87,102,116,56,143,56,108,108,109,184,84,134,67,182,140,138,126,176, +100,206,63,228,146,32,241,32,194,32,187,70,160,182,160,72,226,72,227,180, +192,100,192,148,186,178,176,202,166,212,135,234,198,192,239,233,36,20,73,54, +18,88,61,118,26,234,65,156,138,10,169,38,92,88,92,52,230,52,231,84, +200,74,158,86,120,88,121,170,122,120,223,120,182,120,183,166,80,170,243,170, +136,194,85,242,174,190,229,235,112,10,141,38,32,90,32,52,220,52,221,88, +182,84,130,94,80,96,81,172,81,170,82,130,209,130,164,130,165,176,16,178, +239,178,102,196,35,242,150,198,221,243,14,70,85,70,18,156,89,112,60,12, +60,224,54,230,32,234,25,224,144,12,171,36,98,84,98,50,228,50,229,80, +204,74,160,88,122,90,123,168,122,120,225,120,184,120,185,166,82,172,243,172, +144,190,99,238,180,190,231,231,204,22,130,36,74,38,75,152,74,90,221,90, +164,90,165,152,14,156,243,156,104,174,31,240,150,176,231,231,26,42,59,82, +62,116,21,198,76,80,124,80,118,118,100,160,82,184,55,212,150,10,150,232, +124,240,113,224,220,54,167,110,152,82,168,120,188,154,208,182,239,213,18,74, +103,74,64,10,65,240,60,86,38,140,19,174,68,104,99,136,102,36,241,36, +118,240,118,94,226,94,226,220,218,230,208,232,193,224,172,38,172,98,164,130, +154,158,139,180,166,122,207,175,16,30,243,30,44,236,44,82,214,82,214,216, +206,228,194,234,171,218,130,34,128,80,124,108,116,138,96,164,69,188,122,114, +193,179,200,26,172,32,132,34,45,36,20,66,239,66,44,94,196,94,196,160, +45,160,18,126,245,126,128,36,129,244,118,164,98,182,74,202,48,216,21,228, +138,164,154,178,170,194,190,206,237,223,56,12,19,104,36,64,92,64,81,96, +52,104,52,222,93,184,122,16,149,50,206,14,179,66,110,72,235,72,96,140, +245,140,142,74,142,146,140,174,138,190,130,210,122,224,103,240,198,74,199,245, +34,74,25,126,62,12,62,136,56,166,46,196,23,230,106,56,67,100,60,148, +95,190,100,32,247,32,172,32,172,92,164,144,154,166,133,196,166,136,203,182, +114,238,114,92,224,92,224,226,214,232,204,236,189,223,128,10,159,34,22,66, +53,102,18,152,55,128,26,240,38,222,48,204,56,182,60,160,62,140,62,46, +243,46,82,88,245,88,94,244,94,134,224,134,224,220,220,228,208,236,200,236, +187,224,158,92,156,138,140,174,117,198,152,148,201,195,68,16,105,50,184,10, +149,60,30,68,229,68,18,144,237,144,94,70,94,156,90,180,84,194,74,214, +43,242,166,72,167,245,14,44,97,44,18,112,95,112,54,46,55,188,16,206, +93,178,82,236,96,224,102,210,110,194,114,176,116,154,118,132,118,52,228,52, +219,90,170,6,171,116,122,118,212,118,204,150,194,174,180,196,160,214,119,240, +134,120,148,154,168,186,190,206,206,218,241,233,16,42,237,42,90,8,91,66, +162,8,163,62,48,74,83,102,26,116,67,140,26,232,65,164,70,238,84,222, +96,206,102,188,108,154,108,96,220,96,211,118,162,68,163,142,110,144,204,144, +190,174,176,192,160,210,138,226,105,238,126,146,138,168,154,188,170,206,190,218, +233,237,14,68,89,68,16,156,91,112,58,12,58,230,36,236,27,224,220,16, +178,26,144,26,103,26,114,44,135,66,212,44,193,74,94,82,239,82,162,28, +163,130,150,84,138,102,124,118,106,134,83,148,168,86,180,100,194,114,212,126, +243,138,112,242,112,144,216,144,217,240,116,182,213,182,114,220,213,220,164,146, +165,217,14,68,93,68,18,158,97,120,62,10,62,232,46,244,29,228,190,24, +225,56,124,28,100,84,241,84,162,8,156,82,146,118,132,148,118,168,85,202, +146,126,210,126,200,154,188,178,168,202,146,220,107,238,140,138,156,166,170,184, +186,200,202,214,237,233,66,18,42,58,17,92,44,58,101,58,30,102,97,102, +16,152,103,152,58,102,58,230,93,204,108,76,235,76,162,12,163,246,120,190, +213,190,156,82,142,120,128,150,114,170,95,188,166,84,178,108,188,128,202,148, +216,164,239,183,34,20,79,52,18,82,61,112,22,234,65,144,68,234,86,208, +94,184,100,164,104,130,104,60,220,60,205,90,160,10,161,120,106,122,206,122, +196,148,184,174,176,186,162,204,142,218,122,230,97,240,122,124,130,138,138,154, +150,170,160,184,172,196,188,210,214,226,237,235,8,94,83,94,50,14,51,246, +76,46,237,46,98,164,98,74,216,74,217,160,100,108,213,108,100,138,213,138, +182,16,207,32,154,12,155,158,74,180,245,180,198,160,198,226,192,236,184,238, +161,228,114,196,143,221,18,48,143,48,80,8,81,80,30,114,30,86,134,86, +135,112,40,126,110,126,84,152,84,226,76,238,49,226,24,188,131,162,144,74, +228,70,220,214,212,224,204,230,175,220,180,8,180,86,176,122,170,156,162,180, +152,200,138,220,119,239,14,72,95,72,60,12,60,226,52,238,27,224,18,158, +93,126,100,42,239,42,114,158,114,74,218,74,219,158,116,104,217,104,116,134, +217,134,166,8,167,156,192,12,213,30,94,178,241,178,200,160,200,218,198,230, +190,236,169,228,124,196,151,219,68,16,46,54,19,90,44,60,115,60,32,104, +105,104,20,152,115,152,64,104,64,234,107,202,178,14,157,64,134,246,134,68, +232,68,233,242,134,140,231,140,134,216,231,217,82,12,54,54,21,84,66,42, +135,42,78,44,101,78,174,12,152,50,127,78,160,40,245,40,182,44,211,80, +44,90,91,116,26,136,69,156,36,238,91,168,160,76,147,104,116,246,116,110, +220,110,221,244,120,164,219,164,118,218,217,219,80,10,54,72,21,116,60,62, +61,248,164,10,151,58,114,242,114,66,226,66,227,240,116,140,225,140,118,212, +225,213,118,8,105,34,58,42,200,42,200,114,58,114,59,44,62,78,197,78, +42,224,42,152,218,152,218,194,216,204,212,212,204,214,185,206,124,124,125,245, +70,12,63,42,16,124,115,124,20,242,32,222,40,200,44,172,44,158,44,48, +106,48,106,222,102,234,90,240,73,226,66,72,83,102,64,144,79,174,188,14, +173,62,144,242,144,68,228,68,229,240,148,138,225,138,146,214,225,215,16,234, +28,208,34,180,38,156,38,138,38,26,88,26,88,224,82,230,74,236,59,220, +40,88,85,88,40,148,87,148,104,44,247,44,172,6,173,80,118,118,118,82, +234,82,235,118,134,118,204,118,178,148,178,226,170,236,143,224,104,168,247,169, +18,238,28,222,36,198,40,176,42,156,42,26,90,26,90,222,84,232,70,240, +64,234,59,224,46,84,87,84,46,138,87,138,108,42,241,42,124,158,124,70, +222,70,223,154,200,12,223,26,174,10,175,154,128,102,219,102,126,134,219,134, +108,178,247,178,204,158,204,230,194,240,175,228,140,196,163,217,32,28,67,54, +18,90,57,116,26,228,65,142,78,50,163,50,122,10,123,88,82,120,82,90, +156,90,157,116,90,130,142,130,122,152,122,228,106,242,85,228,72,188,159,170, +166,76,230,76,224,216,212,230,189,220,194,12,194,96,192,136,182,178,174,208, +153,241,34,26,79,58,18,88,65,118,22,238,69,150,160,12,145,62,104,244, +104,66,220,66,221,242,106,140,219,140,106,214,217,215,16,32,94,32,85,132, +40,56,32,134,110,134,100,212,88,228,66,230,55,216,12,188,87,174,214,14, +172,68,150,90,123,110,126,24,178,58,202,76,235,104,210,120,196,154,182,178, +170,198,148,220,117,238,144,124,152,150,162,170,176,186,190,202,204,214,218,222, +237,231,18,76,93,76,18,158,95,122,58,14,58,226,44,240,29,224,194,22, +221,44,98,58,241,58,164,10,165,230,112,242,112,96,222,96,222,224,208,238, +191,222,114,136,219,136,114,180,219,181,126,12,127,244,128,80,176,114,227,159, +32,198,32,46,76,46,77,188,34,166,73,166,94,58,239,58,196,16,221,40, +114,246,114,96,220,96,220,230,204,244,191,230,118,140,217,140,118,184,217,184, +166,12,167,231,60,12,91,44,14,60,106,60,82,98,58,124,19,156,72,112, +73,244,76,128,127,168,128,98,99,142,166,10,167,244,182,84,241,147,20,84, +95,84,58,20,59,176,16,194,97,166,160,10,151,38,122,82,212,82,212,44, +118,44,118,148,220,148,220,112,123,112,92,188,245,188,168,160,169,247,20,34, +241,34,150,36,132,72,116,94,94,120,74,140,52,156,23,172,130,80,131,242, +162,98,235,169,20,56,239,56,122,10,106,56,92,84,78,106,64,124,48,140, +25,160,78,218,78,116,210,116,210,186,208,196,204,204,198,206,184,210,169,194, +142,78,143,245,16,104,241,104,136,12,137,102,138,54,217,54,76,36,77,102, +138,114,139,198,90,136,45,182,218,136,192,174,170,196,146,212,118,224,84,232, +25,239,70,10,54,42,35,66,58,36,129,36,80,38,97,62,166,10,129,62, +150,34,237,34,182,34,199,58,176,66,191,78,82,84,235,84,102,168,102,106, +210,106,211,166,106,130,207,130,106,154,207,154,152,66,153,168,40,80,69,102, +26,120,59,140,30,234,71,164,76,188,245,188,194,172,194,224,186,238,176,240, +157,228,112,196,133,217,66,12,91,38,24,50,139,50,40,68,63,100,116,66, +93,112,10,116,147,116,40,242,40,154,120,154,121,234,42,212,119,212,164,248, +164,36,224,36,194,112,210,122,224,136,232,150,234,168,234,184,228,196,216,206, +202,210,187,195,34,66,23,124,78,66,99,102,60,10,61,242,96,58,243,58, +158,10,146,58,136,82,124,104,110,124,94,142,77,160,120,208,120,116,222,116, +222,194,204,206,191,190,170,84,171,245,18,70,79,70,12,158,79,120,56,12, +56,234,40,242,27,224,150,8,173,32,92,70,92,42,226,42,227,68,122,58, +108,84,89,108,112,80,150,80,136,110,120,130,102,148,81,160,102,118,113,128, +118,98,133,108,162,58,174,90,186,110,198,126,214,138,245,152,174,80,216,80, +197,116,130,138,199,138,98,170,229,170,162,172,162,228,148,244,137,228,126,190, +93,232,192,190,225,229,82,18,54,56,21,88,70,110,46,140,23,164,26,26, +52,50,60,66,70,90,74,110,76,136,76,164,74,194,68,220,54,230,37,234, +100,42,233,42,112,74,219,74,90,104,245,104,164,8,165,104,114,242,114,132, +216,132,216,230,206,242,194,246,183,230,118,164,211,164,118,196,213,197,28,44, +137,44,84,10,85,80,16,82,243,82,68,96,95,116,24,126,147,126,82,128, +72,150,56,174,42,186,21,204,62,166,62,234,103,204,134,146,113,172,92,154, +137,202,184,26,219,62,160,12,158,80,162,112,170,148,178,176,184,190,194,208, +206,224,220,236,228,238,243,210,212,108,196,154,186,178,174,202,158,220,137,239, +20,80,115,80,70,12,71,242,64,92,44,140,21,178,72,108,94,124,113,142, +128,80,247,80,202,12,202,232,180,242,163,224,196,84,178,126,162,154,142,178, +120,200,107,213,24,68,237,68,156,8,156,228,126,242,111,226,146,78,122,120, +92,154,64,178,31,201,34,172,34,36,116,36,117,170,76,72,74,130,72,166, +62,194,46,214,30,226,19,236,84,188,127,228,132,82,247,82,204,10,204,228, +176,244,165,228,198,96,176,138,158,168,131,197,22,222,22,36,78,36,79,208, +24,90,75,90,24,144,75,144,218,18,156,32,101,38,106,60,127,96,148,48, +167,78,212,50,191,94,24,194,77,194,96,122,237,122,162,88,163,244,156,130, +132,168,110,198,87,222,168,130,180,152,194,172,210,188,233,211,36,32,94,32, +94,90,38,90,39,34,70,94,71,196,36,126,37,206,72,138,107,138,12,216, +107,186,230,14,170,28,113,30,116,60,141,98,160,46,175,86,226,46,199,94, +112,130,239,130,168,96,169,242,162,136,144,170,126,194,105,218,174,138,198,172, +214,190,241,207,210,22,162,32,126,36,94,40,37,40,48,60,85,102,114,52, +141,84,210,50,161,106,22,134,237,134,130,104,131,244,124,142,88,180,64,198, +21,220,138,142,162,172,186,194,233,221,132,20,72,36,17,40,30,62,53,98, +64,48,85,84,128,48,107,94,12,124,141,124,82,94,83,242,78,132,60,168, +44,192,21,218,86,140,108,160,129,182,210,14,178,56,145,86,220,86,190,122, +151,154,232,154,200,194,172,214,133,239,20,44,237,44,92,12,93,70,166,10, +167,70,206,74,156,84,120,90,82,90,43,90,64,108,89,136,120,104,137,128, +196,98,175,138,18,156,241,156,130,134,131,246,116,160,84,194,60,212,27,230, +140,160,162,182,192,204,235,223,16,38,239,38,94,8,95,60,158,8,159,62, +74,60,54,88,31,112,62,82,118,82,100,110,78,134,58,152,21,172,48,120, +69,134,68,102,89,116,146,82,208,82,187,124,142,68,148,82,160,102,178,124, +198,142,233,164,88,138,173,138,58,170,205,170,130,170,130,228,108,242,99,226, +90,190,66,216,37,234,160,194,221,227,78,8,79,50,80,28,127,28,50,34, +23,78,40,52,112,52,96,70,76,88,56,100,25,114,52,70,75,86,146,28, +216,28,204,46,192,58,170,78,157,88,154,50,227,94,126,76,100,104,70,128, +46,140,21,152,124,82,142,98,166,116,196,130,237,144,114,114,141,128,72,188, +190,188,190,136,68,136,68,238,117,222,70,162,189,162,206,190,171,218,132,204, +215,241,118,8,52,66,86,64,138,62,189,56,156,22,207,70,18,100,241,100, +112,70,82,118,54,144,19,166,156,102,174,124,188,138,204,150,239,164,134,120, +98,148,65,168,158,144,112,184,73,202,190,166,138,214,96,230,45,239,48,34, +209,34,20,76,237,76,120,36,102,86,80,114,50,138,21,154,148,76,162,100, +184,120,235,148,70,140,186,140,186,182,72,182,73,142,130,104,131,220,38,232, +203,222,180,198,223,241,16,38,117,38,60,40,56,70,50,90,40,116,17,150, +52,90,104,90,100,130,92,166,78,194,58,212,21,236,50,136,83,168,120,94, +229,68,114,146,241,118,220,148,176,192,148,212,130,222,107,230,186,24,213,46, +156,8,158,86,168,142,180,186,198,212,220,238,236,236,239,199,50,8,51,240, +26,66,15,114,64,62,77,94,80,54,159,54,120,10,82,126,155,126,76,188, +153,166,122,82,123,236,232,22,174,40,174,158,166,190,156,210,145,228,176,106, +245,106,210,108,211,243,52,10,53,242,24,68,17,122,66,56,83,88,148,10, +106,64,203,54,180,26,221,68,82,92,239,92,156,66,130,108,108,128,77,148, +168,96,186,114,200,126,220,136,243,142,166,118,136,146,99,168,188,144,150,178, +105,202,216,166,164,212,130,226,89,239,34,64,23,128,112,54,75,94,72,156, +107,196,68,12,68,124,64,162,56,192,44,212,25,232,174,8,175,210,126,70, +126,222,152,218,219,212,222,66,223,239,16,46,241,46,92,12,93,76,168,10, +169,74,130,62,98,102,66,126,23,152,124,72,144,94,166,110,186,122,237,140, +132,190,152,192,162,188,172,182,174,168,176,138,80,138,80,218,84,228,92,232, +102,236,174,236,188,234,200,228,206,218,215,201,68,12,55,48,18,234,30,214, +38,188,40,166,40,152,40,52,94,52,94,220,82,236,61,224,12,130,99,130, +60,74,77,102,60,154,77,184,172,14,150,54,136,76,113,106,168,22,180,44, +198,66,214,86,239,102,176,182,198,180,206,172,206,116,138,116,138,212,142,222, +150,228,158,230,202,230,214,226,224,220,228,210,231,199,130,12,102,56,66,90, +19,118,126,24,146,48,180,76,204,90,239,104,136,176,164,176,178,172,182,162, +184,116,76,116,76,210,80,224,86,232,172,232,192,228,206,222,214,210,217,195, +42,26,83,58,18,90,57,116,74,146,33,232,152,12,126,68,85,116,152,20, +186,68,237,100,156,176,174,176,190,168,196,112,122,112,122,212,124,226,138,234, +196,234,210,222,221,201,16,38,241,38,96,10,97,66,162,8,163,62,42,242, +54,220,62,192,62,82,231,82,32,76,32,114,59,114,56,156,17,156,32,158, +28,196,23,222,200,52,219,68,178,58,180,98,182,138,186,172,206,214,226,236, +236,232,247,216,220,106,208,146,190,190,151,238,166,110,92,110,92,216,153,216, +128,112,129,144,94,146,156,146,156,178,95,178,130,178,131,213,12,68,95,68, +14,152,85,116,56,6,56,222,36,238,23,220,126,20,200,20,200,60,128,60, +129,20,106,88,144,88,144,122,104,122,105,90,178,88,222,88,222,122,174,122, +175,88,90,154,235,154,160,134,161,242,156,160,124,194,100,212,83,222,166,164, +180,184,204,202,237,221,20,44,41,74,94,48,79,76,100,28,123,68,14,100, +97,100,58,14,59,246,56,116,36,158,15,184,60,120,89,156,158,30,137,88, +152,58,231,58,186,12,187,104,126,104,243,104,156,136,218,136,218,192,156,192, +157,136,86,120,114,120,115,204,84,226,102,212,116,208,130,216,146,224,168,228, +241,229,18,70,91,70,58,12,59,244,56,92,42,128,19,166,62,98,89,128, +88,42,245,42,104,72,224,72,224,138,106,138,107,74,108,104,223,104,146,14, +147,136,182,10,183,138,116,244,116,164,212,164,213,244,118,196,211,196,118,226, +211,227,20,42,239,42,48,72,210,72,210,134,46,134,47,74,46,102,207,102, +100,18,101,130,156,14,157,132,60,246,60,160,196,160,197,244,64,194,193,194, +62,226,195,227,20,36,231,36,98,12,99,62,162,10,163,62,66,74,194,74, +194,146,62,146,63,76,66,110,191,110,16,186,241,186,130,150,131,241,18,232, +28,220,34,204,38,190,40,166,40,34,235,34,78,176,78,68,142,68,143,172, +110,94,110,154,106,184,92,210,63,236,124,184,153,220,178,74,179,186,216,52, +216,226,200,232,183,223,66,14,46,50,23,78,50,46,127,46,74,48,95,78, +168,12,133,68,150,44,233,44,176,44,199,76,22,98,235,98,126,74,127,246, +62,182,62,130,194,130,194,166,188,178,173,168,122,152,100,184,64,212,25,234, +130,150,148,174,172,196,233,225,74,12,50,72,21,116,54,62,55,244,92,174, +92,36,158,36,159,170,126,70,126,156,118,194,104,218,79,238,140,184,173,222, +192,40,193,182,230,12,230,224,208,240,189,229,20,236,38,214,48,190,52,154, +54,134,54,26,110,26,110,210,108,220,104,224,86,232,73,218,126,236,144,210, +150,176,152,156,152,26,210,26,210,216,206,226,196,236,173,222,14,112,247,113, +36,16,71,46,22,80,59,112,20,232,63,148,92,172,92,34,158,34,159,168, +122,70,122,136,118,164,110,192,92,214,69,234,134,178,171,220,188,40,189,180, +226,12,226,230,208,242,187,229,18,236,36,208,46,176,50,144,50,130,50,26, +214,26,214,68,53,68,80,110,221,110,64,152,239,152,136,160,84,228,203,218, +176,178,223,235,40,40,96,40,96,100,40,100,41,40,70,104,71,214,34,134, +35,220,72,150,105,150,18,230,109,208,128,16,159,44,214,14,191,52,120,58, +232,58,232,126,122,126,123,60,174,60,175,122,140,82,159,102,208,80,195,106, +130,244,130,156,220,156,221,244,130,188,219,188,130,224,219,225,14,72,89,72, +18,156,89,126,60,12,60,226,40,242,33,228,218,20,174,30,140,36,105,40, +98,78,243,78,162,34,163,216,142,118,110,126,111,244,114,168,147,168,182,122, +222,122,223,242,182,166,219,166,112,218,219,219,38,38,192,38,178,84,160,124, +138,156,114,180,80,206,31,230,62,40,70,68,80,94,96,124,112,148,138,176, +158,190,194,210,235,224,106,68,139,103,22,48,241,48,94,12,95,78,176,12, +177,76,26,100,239,100,130,68,110,110,88,140,62,166,21,196,72,138,73,244, +108,160,227,160,164,122,165,220,90,224,245,225,20,46,237,46,90,10,91,80, +166,10,167,80,122,70,104,90,78,112,44,134,23,144,124,72,140,88,158,100, +180,114,202,126,239,138,54,152,205,152,130,114,130,226,104,240,95,226,96,178, +68,208,41,226,160,178,223,225,24,50,233,50,130,12,131,110,124,54,106,72, +88,88,62,102,19,122,140,54,158,74,174,90,194,102,237,116,66,128,190,128, +190,196,62,196,63,128,66,162,187,162,18,230,235,231,16,46,103,46,60,48, +54,78,44,108,32,128,17,146,44,222,44,114,86,114,87,216,46,196,85,196, +114,52,239,52,170,8,171,116,164,58,144,86,126,104,107,120,176,60,190,82, +208,104,237,122,128,130,210,130,210,200,130,200,131,134,132,164,207,164,100,228, +237,229,14,72,85,72,14,150,83,110,52,14,52,226,32,240,23,224,84,46, +233,46,122,10,123,82,188,10,189,80,154,66,136,98,114,122,100,134,81,146, +152,78,172,100,192,118,214,132,237,140,98,156,221,156,156,126,156,224,140,240, +123,226,122,180,106,206,87,226,184,182,221,219,112,10,143,34,36,82,36,44, +222,44,223,78,76,56,54,88,29,110,62,80,120,80,100,110,80,128,52,146, +15,160,46,116,63,136,68,98,85,116,138,62,158,104,180,124,206,142,239,156, +150,80,198,80,177,116,92,136,169,136,48,168,213,168,128,168,128,230,114,244, +95,232,90,188,62,214,31,232,160,188,221,229,96,20,60,64,19,96,142,16, +170,52,202,76,235,94,66,76,180,76,174,126,160,142,141,130,112,80,106,108, +92,126,74,138,47,148,122,150,123,222,56,168,56,230,199,222,200,166,201,243, +78,18,107,44,182,16,161,48,38,56,225,56,132,56,124,98,114,132,92,160, +66,180,29,200,56,92,207,92,26,126,237,126,92,170,211,170,144,170,145,222, +52,228,235,229,46,22,79,58,14,100,60,100,60,228,103,192,148,16,177,38, +108,92,108,54,230,54,231,90,210,90,162,104,134,112,113,114,96,162,241,154, +162,108,162,216,166,224,174,228,206,232,226,226,239,203,12,68,101,68,16,158, +97,118,58,10,58,228,38,240,21,224,218,16,186,28,160,32,124,34,124,160, +118,184,110,208,100,226,91,238,126,100,241,100,190,102,191,246,162,142,231,191, +84,16,85,104,44,36,45,110,26,120,123,98,86,56,129,56,148,12,148,104, +150,110,156,114,164,116,206,116,216,112,224,104,227,86,218,38,155,68,18,154, +239,154,126,122,127,242,118,160,102,178,80,196,58,210,29,224,132,158,146,176, +168,194,194,210,231,221,94,12,60,36,25,52,120,48,72,92,19,116,42,68, +59,94,70,48,91,72,82,86,90,100,102,120,110,140,112,172,112,198,108,208, +96,222,84,228,59,232,92,106,56,144,25,162,108,138,52,194,27,210,130,80, +245,80,200,8,200,222,180,240,161,224,196,98,164,156,135,191,12,70,89,70, +14,154,89,118,58,10,58,222,48,236,23,226,142,10,103,58,124,36,182,36, +163,66,108,72,212,72,212,110,110,110,111,74,156,76,148,118,132,142,114,158, +83,174,174,110,174,146,176,154,178,158,186,158,212,158,226,156,234,144,237,132, +136,168,191,192,120,204,199,237,12,68,87,68,12,150,83,114,52,8,52,224, +32,240,19,222,148,10,104,64,199,52,178,28,217,68,82,92,235,92,154,64, +126,110,108,126,77,148,168,94,186,116,206,134,237,150,164,122,128,154,95,170, +184,148,144,180,97,204,214,170,164,210,130,226,87,241,32,64,98,64,98,136, +32,136,33,66,66,10,67,194,18,210,103,188,92,158,119,208,120,16,159,48, +214,12,179,56,130,60,222,60,222,146,130,146,131,60,132,102,221,102,174,62, +175,242,118,182,247,183,62,16,42,66,21,96,44,66,94,66,81,96,56,104, +56,228,95,196,148,12,132,40,117,58,136,40,194,40,175,72,116,76,220,76, +220,116,116,116,117,78,166,78,158,120,144,144,126,162,103,176,182,116,182,154, +182,160,188,164,194,166,224,166,230,162,236,154,239,138,142,172,201,196,130,208, +209,239,36,24,75,58,12,98,58,98,58,226,93,188,144,12,124,36,97,58, +128,36,184,36,163,70,104,72,216,72,216,112,106,112,107,74,158,74,150,112, +140,132,124,148,93,168,178,114,178,152,182,156,190,158,222,158,228,154,234,146, +239,132,140,166,193,190,126,206,162,220,203,239,58,16,16,96,63,94,88,56, +20,164,87,152,16,218,81,202,152,12,183,34,240,46,108,46,108,154,102,184, +96,214,81,240,140,76,224,76,224,152,140,152,141,78,142,114,221,114,180,78, +181,232,124,188,239,188,114,230,245,231,60,14,42,60,19,92,46,60,103,60, +30,102,95,102,16,148,105,148,60,104,60,222,97,186,154,16,183,40,110,52, +241,52,138,68,161,100,212,66,191,108,245,114,242,114,124,114,124,172,120,198, +110,222,97,241,118,16,149,38,46,52,225,52,88,66,117,100,182,66,159,104, +232,112,56,112,54,152,50,186,44,204,21,241,38,62,39,240,48,20,75,54, +102,34,218,34,218,220,192,236,185,222,90,60,113,88,164,60,147,92,78,98, +180,98,180,162,80,162,81,100,82,130,177,130,128,100,129,234,56,190,199,191, +50,16,77,34,12,44,125,44,26,68,116,68,116,132,26,132,27,70,52,88, +90,88,90,112,54,112,55,88,34,152,106,152,106,194,34,194,35,154,36,172, +105,172,12,224,123,212,132,32,237,32,182,34,173,70,144,188,144,76,218,76, +219,188,180,106,180,162,172,188,162,208,148,222,121,240,192,198,233,239,56,28, +198,28,198,102,56,102,57,30,58,66,195,66,42,240,42,136,216,136,217,240, +46,176,211,176,46,216,211,217,94,16,62,56,27,88,26,30,60,56,70,72, +76,96,80,128,82,160,78,198,74,216,60,232,35,220,74,106,52,136,25,166, +130,32,218,32,218,104,130,104,131,34,134,66,217,66,120,244,120,138,230,138, +231,244,122,178,227,178,122,220,227,221,62,14,63,172,22,84,99,84,18,190, +99,162,104,32,198,32,108,114,228,114,220,218,202,232,173,218,148,116,140,140, +130,158,114,178,81,202,186,118,180,154,164,184,144,210,103,239,50,28,97,58, +206,24,163,62,130,10,131,72,34,120,34,80,222,80,223,120,66,116,189,116, +22,160,235,160,112,166,46,228,185,218,158,182,207,237,62,20,93,46,188,16, +161,52,128,8,129,54,32,96,32,60,222,60,223,90,76,90,180,90,180,128, +76,128,77,92,54,228,54,164,202,164,202,216,186,228,167,216,130,138,131,243, +12,120,241,120,80,12,80,232,139,196,202,20,111,96,126,122,136,146,148,166, +164,184,176,194,200,212,235,227,74,14,46,68,19,108,56,52,57,246,100,20, +131,56,218,20,193,58,160,8,161,74,88,118,88,78,230,78,231,118,108,116, +207,116,76,156,241,156,148,166,94,230,205,214,184,180,231,233,16,244,30,218, +40,178,40,158,40,38,94,38,94,222,84,236,59,224,46,94,93,94,42,146, +91,146,118,40,210,40,126,116,232,116,218,226,200,238,177,226,160,120,150,144, +134,170,111,190,198,122,186,156,168,188,152,208,121,237,26,240,38,222,50,196, +54,166,56,144,56,44,233,45,26,34,55,76,138,32,109,76,80,10,81,92, +30,242,30,100,128,100,128,210,124,222,116,228,93,218,62,134,96,134,96,186, +62,186,63,134,178,12,162,74,143,112,164,74,239,74,208,76,206,122,196,164, +180,196,162,218,139,240,166,110,176,146,184,170,200,198,216,218,239,237,28,178, +28,66,110,66,111,174,32,112,107,112,32,158,107,158,68,10,69,246,124,34, +206,34,128,110,226,110,216,218,200,230,175,220,162,112,154,140,138,166,109,194, +196,114,190,146,176,176,154,204,121,233,32,192,32,36,80,36,81,188,34,160, +79,160,124,26,218,26,218,102,124,102,125,30,126,66,215,66,114,244,114,134, +226,134,227,242,116,176,223,176,118,218,221,219,80,12,54,70,21,114,58,66, +59,244,118,28,216,28,216,104,118,104,119,30,124,66,211,66,104,238,104,136, +226,136,227,236,108,176,223,176,110,218,223,219,30,54,115,54,74,8,75,96, +18,100,121,100,80,116,81,206,82,152,119,152,48,136,40,186,27,234,42,184, +66,204,106,222,160,224,239,224,122,28,220,28,216,80,204,98,185,88,170,30, +156,74,135,110,140,126,218,126,218,192,142,192,143,131,19,72,16,74,101,74, +20,152,95,120,62,14,62,226,52,240,31,226,170,10,171,170,134,62,113,144, +200,60,237,116,222,136,206,172,184,200,154,222,103,237,64,18,38,68,17,96, +44,58,111,58,30,102,101,102,16,152,103,152,60,104,60,226,107,186,170,16, +171,180,140,68,113,144,196,66,241,122,224,140,204,178,182,204,146,228,101,239, +20,42,143,42,84,6,85,74,42,80,124,80,124,148,42,148,43,82,44,114, +121,114,14,184,145,184,82,152,83,242,136,236,152,208,160,180,160,140,160,26, +226,26,226,220,216,230,187,220,164,82,223,82,164,136,223,137,28,38,66,38, +67,184,28,38,29,194,28,166,65,166,80,46,163,46,122,10,123,82,94,84, +148,84,148,150,92,150,93,86,96,116,145,116,80,184,161,184,118,154,119,242, +148,238,170,206,180,178,180,148,180,142,180,28,224,28,224,234,204,238,191,224, +182,92,223,92,182,152,223,153,30,22,63,46,18,86,55,110,18,230,57,152, +72,50,157,50,112,10,113,78,80,84,144,84,144,148,78,148,79,86,80,114, +141,114,60,184,159,184,112,152,113,242,146,236,164,208,174,180,176,148,176,34, +228,34,228,224,210,238,193,226,180,88,227,88,180,146,225,147,78,16,48,50, +81,78,138,18,110,50,139,76,204,16,172,50,201,76,54,90,200,90,200,150, +54,150,55,92,56,120,197,120,126,92,127,246,16,174,235,174,116,178,78,208, +23,234,134,178,158,200,184,212,202,220,235,229,26,200,26,44,74,44,75,190, +26,172,75,172,160,10,161,168,124,56,95,146,188,58,241,112,214,126,198,168, +180,194,156,216,136,224,87,239,30,60,21,126,104,54,69,92,60,14,60,136, +54,172,38,210,23,228,62,142,111,188,166,8,167,166,132,60,111,136,192,56, +239,114,218,124,190,174,164,200,130,222,89,233,22,56,229,56,122,12,56,130, +209,130,16,186,241,186,134,80,135,247,14,74,103,74,16,162,97,126,60,14, +60,228,38,240,29,228,126,72,127,220,178,10,179,218,178,102,237,102,92,222, +245,223,14,70,87,70,14,152,81,122,56,10,56,224,44,238,27,224,116,10, +137,36,88,50,169,50,124,54,96,106,151,96,144,72,159,108,100,242,100,128, +154,128,154,230,140,238,131,226,104,160,151,160,102,194,151,194,200,8,184,64, +169,96,180,74,243,74,218,76,210,146,196,190,173,232,176,108,186,146,200,180, +206,192,237,231,58,10,33,54,44,38,145,38,16,66,159,66,42,130,42,92, +140,92,140,120,128,130,117,118,90,10,91,132,176,26,177,98,214,10,214,112, +194,126,185,112,206,138,126,150,33,150,48,174,207,174,18,202,239,202,130,150, +130,234,110,244,93,229,72,12,21,76,72,78,19,142,54,100,55,242,82,88, +153,88,112,20,112,194,143,140,148,42,226,42,220,224,206,236,185,220,180,46, +180,98,176,138,168,176,152,204,127,233,24,34,61,56,14,94,49,118,18,232, +59,148,98,14,125,44,70,58,159,58,104,62,76,108,137,98,132,76,147,112, +82,246,82,132,144,132,144,236,126,244,117,232,84,164,141,164,84,196,141,196, +188,16,172,64,157,98,172,72,243,72,214,76,210,122,200,160,184,202,159,236, +170,106,178,144,190,174,204,196,235,229,16,74,81,74,56,12,57,238,54,92, +36,138,19,170,60,100,83,122,90,74,149,74,118,10,119,240,114,90,96,138, +81,166,122,102,149,134,166,242,166,30,226,30,194,106,216,124,232,148,234,166, +230,184,218,196,204,198,191,191,220,38,46,38,46,224,233,224,134,42,135,96, +48,100,202,100,202,154,51,154,134,156,135,221,18,238,36,212,46,180,52,146, +52,130,52,32,225,32,78,78,205,78,60,126,229,126,92,128,92,242,153,198, +140,128,148,154,162,178,182,200,206,218,235,234,208,146,171,185,130,18,131,118, +74,52,35,130,178,50,229,120,52,172,213,172,132,140,133,220,20,228,239,229, +64,26,204,26,204,80,66,80,67,28,70,54,201,54,18,228,38,202,50,174, +52,156,52,108,237,108,80,136,209,136,58,162,231,162,88,164,88,240,139,208, +140,164,150,182,160,194,176,208,188,216,241,238,200,176,177,205,34,68,19,126, +82,60,93,104,58,10,59,248,118,114,118,62,228,62,229,112,174,10,170,72, +166,110,160,136,148,166,130,196,87,236,184,118,184,216,186,226,190,230,194,230, +222,230,230,228,234,224,243,201,34,20,73,48,14,84,55,114,30,236,71,146, +94,80,94,32,222,32,223,78,78,240,98,224,112,204,120,182,124,166,126,154, +126,96,186,96,186,218,188,224,196,230,218,230,226,226,234,218,239,195,32,248, +32,32,82,32,58,102,70,116,80,132,86,146,88,162,86,174,80,180,74,186, +64,188,55,188,94,56,235,56,154,12,110,132,225,132,168,86,168,234,156,248, +137,230,134,170,95,222,198,172,235,219,26,54,115,54,74,6,75,96,16,98, +121,98,80,116,81,206,82,154,115,154,46,132,36,190,21,230,40,182,56,196, +70,206,84,214,102,220,124,224,142,224,239,224,176,8,154,48,140,68,121,86, +172,18,180,36,188,48,202,62,212,70,241,90,190,82,162,110,133,124,208,114, +176,142,139,162,228,146,178,182,131,203,44,16,77,50,14,68,94,68,76,98, +54,126,19,156,60,120,61,246,62,134,113,168,108,104,87,148,134,122,167,162, +118,84,247,84,200,12,200,228,178,240,155,229,16,66,83,66,18,154,89,122, +56,12,56,224,34,236,25,222,164,6,165,52,112,20,139,42,220,20,193,52, +98,88,98,58,232,58,233,86,128,82,198,82,198,110,130,110,131,84,216,126, +166,134,109,134,98,162,225,162,84,190,237,190,164,134,164,232,142,240,129,227, +102,24,64,38,25,44,16,92,107,92,66,40,67,244,60,110,32,172,21,186, +70,118,103,152,160,16,136,78,119,110,142,62,232,62,217,100,176,94,176,226, +158,240,141,228,142,140,128,176,105,206,202,138,243,201,12,90,83,90,50,20, +51,174,12,190,85,168,62,236,82,216,94,194,100,166,102,138,102,70,239,70, +108,122,148,122,142,188,130,200,117,188,194,24,225,50,168,14,168,70,172,94, +174,122,182,156,192,188,202,210,218,230,224,236,232,236,239,210,216,96,204,144, +194,168,180,194,170,208,139,237,16,76,97,76,58,12,59,246,54,92,32,144, +19,168,64,112,93,140,106,28,154,28,146,54,128,90,101,118,108,56,131,76, +180,18,188,46,196,64,204,82,218,96,239,116,220,26,191,48,236,56,207,78, +134,100,205,100,128,132,212,132,212,176,126,176,127,134,136,192,149,220,204,190, +185,224,96,230,243,231,16,236,32,220,42,202,50,172,52,144,52,62,235,62, +184,16,211,42,56,112,114,112,112,182,104,198,88,206,73,194,154,12,156,82, +162,122,170,160,180,186,192,206,208,224,222,236,228,236,241,204,212,96,200,136, +188,166,170,190,150,214,121,237,62,30,200,30,200,88,62,88,63,30,40,128, +219,128,52,172,207,172,24,222,239,222,130,130,131,221,208,20,146,30,116,32, +92,32,51,32,20,70,241,70,130,34,131,244,126,140,102,168,72,194,46,212, +23,228,134,140,148,158,168,176,184,190,198,200,237,218,90,86,91,158,36,112, +87,112,32,152,87,138,170,88,170,142,172,148,178,152,216,152,224,144,229,128, +218,100,175,119,102,20,62,32,23,38,18,88,111,88,64,34,65,240,60,102, +42,150,19,184,68,110,105,144,126,28,214,28,214,80,126,80,127,28,108,118, +237,118,114,164,227,164,170,120,171,216,96,220,245,221,78,16,21,70,78,64, +23,122,58,84,59,166,96,36,227,36,162,38,163,140,166,88,219,88,116,74, +117,142,82,144,237,144,52,180,25,230,126,162,153,196,196,172,239,216,94,174, +94,224,96,228,104,236,174,236,184,228,193,207,32,24,73,52,16,84,55,112, +24,230,69,154,88,28,140,28,130,58,116,80,100,102,77,126,92,54,117,74, +166,24,180,60,194,88,208,104,233,120,212,26,179,46,224,54,193,78,122,98, +187,98,110,134,200,134,200,176,110,176,111,136,118,190,139,218,192,188,173,220, +70,226,235,227,36,22,73,54,12,92,54,92,54,210,83,170,72,242,98,204, +106,164,106,62,241,62,110,112,150,112,148,158,146,182,140,196,132,200,123,192, +198,18,223,42,172,10,172,70,174,94,178,128,186,166,196,196,210,222,224,236, +228,236,243,208,222,90,198,164,174,200,141,239,40,28,202,28,130,72,130,220, +122,230,112,232,95,236,22,92,78,92,74,128,62,160,52,178,19,214,230,86, +181,124,168,104,180,136,188,160,210,190,233,212,94,92,169,92,169,92,96,130, +163,130,88,170,173,171,112,26,210,26,210,76,112,76,113,28,88,108,231,108, +100,146,221,146,80,186,237,186,158,110,159,182,32,22,71,58,14,102,60,102, +61,200,22,228,42,212,50,206,56,202,68,206,80,216,102,224,120,228,142,230, +226,230,241,219,14,28,92,28,85,122,38,46,34,126,104,126,102,166,98,214, +82,228,61,224,14,188,79,170,132,36,224,36,224,108,132,108,133,36,136,72, +219,72,174,4,175,106,118,138,245,138,152,142,144,174,220,174,212,216,210,228, +198,234,171,237,106,20,66,32,27,36,18,86,105,86,66,34,67,242,62,102, +34,160,21,180,70,114,101,146,122,64,147,122,228,64,201,126,122,28,237,28, +116,148,245,148,174,30,175,243,32,54,82,54,83,194,30,54,31,198,32,170, +81,170,154,18,128,64,103,100,132,62,233,62,116,114,198,114,166,148,144,174, +128,198,122,208,120,218,126,226,134,230,152,234,188,236,216,230,226,222,231,199, +124,14,157,38,22,238,40,220,50,198,56,174,60,148,60,50,245,50,22,70, +39,108,16,150,57,136,108,64,98,96,81,124,100,96,159,96,78,148,167,148, +128,98,124,158,120,182,108,204,79,234,122,170,161,214,182,238,182,90,226,90, +227,232,184,210,223,211,14,72,97,72,18,158,93,120,60,10,60,234,46,240, +29,228,114,50,229,50,172,8,173,94,102,98,245,98,104,144,241,144,204,112, +204,222,198,232,188,234,169,228,126,170,157,199,50,28,124,28,124,98,54,98, +54,28,54,62,121,62,16,128,147,128,90,130,91,208,92,168,137,168,56,150, +40,198,27,230,50,180,58,198,68,208,84,218,112,224,132,226,208,224,243,218, +226,62,171,102,164,18,164,166,166,174,174,182,206,182,216,180,229,159,34,28, +75,60,16,90,53,120,26,232,67,150,66,112,216,76,212,154,202,172,185,164, +158,12,159,196,104,32,104,200,108,218,112,226,122,230,212,230,224,222,239,197, +28,26,69,62,80,192,98,174,108,154,112,134,116,112,116,36,204,36,204,104, +121,104,164,134,225,190,12,112,56,112,57,196,22,228,34,216,54,204,66,206, +92,218,106,224,120,228,239,229,14,34,82,34,82,90,30,90,26,146,80,146, +74,226,62,238,44,238,29,228,94,110,218,76,212,164,202,176,191,168,168,10, +169,196,124,40,124,208,126,220,134,230,144,230,210,230,228,224,236,214,241,197, +14,36,84,36,79,128,38,60,34,136,102,136,98,226,90,234,61,230,16,200, +85,180,104,114,216,74,214,162,208,170,197,166,174,12,175,190,132,44,132,196, +136,218,142,226,146,228,208,228,222,222,230,216,239,197,16,34,127,34,42,38, +43,190,96,36,97,244,48,84,95,84,46,136,93,136,20,206,125,180,186,12, +187,216,148,72,149,216,188,90,231,90,118,218,245,219,132,12,133,94,70,30, +71,92,132,50,215,50,16,96,241,96,132,112,130,138,124,158,116,176,106,186, +79,206,128,150,189,198,52,120,52,226,201,224,210,118,211,247,88,12,72,52, +60,76,46,98,21,132,62,76,63,242,170,12,144,46,124,62,103,76,152,38, +220,38,200,66,186,84,172,98,152,108,105,130,146,68,171,92,194,106,160,146, +107,180,174,134,236,134,224,160,202,192,180,210,152,224,132,230,93,238,160,172, +187,199,18,232,38,216,50,196,58,172,64,144,68,122,68,110,68,32,206,32, +206,100,73,100,134,102,138,120,148,142,160,164,170,180,180,190,196,206,237,231, +48,52,209,52,16,104,241,104,128,8,129,100,104,106,104,144,102,164,96,184, +88,202,78,214,72,222,43,240,160,106,160,234,140,240,125,226,74,136,33,188, +184,136,229,191,14,60,103,60,62,10,63,106,16,110,92,110,88,142,80,166, +70,186,54,208,42,220,23,236,32,112,38,134,46,152,56,172,64,184,74,198, +88,208,102,218,120,222,144,224,162,226,239,226,102,32,150,32,150,192,134,204, +117,190,114,66,135,102,104,164,147,128,170,32,218,32,218,182,214,194,204,204, +181,190,174,68,193,100,168,154,215,123,212,22,162,32,126,34,104,36,60,36, +60,122,60,144,56,164,50,186,31,228,62,100,237,100,150,102,151,244,102,140, +221,193,36,64,23,128,68,14,68,140,64,166,54,196,46,214,31,236,106,58, +73,104,70,156,107,196,134,36,218,36,218,132,136,132,137,38,154,156,140,196, +115,236,188,154,239,237,108,14,147,42,18,56,237,56,114,64,54,132,191,124, +162,86,207,138,102,132,102,160,98,180,90,202,80,214,56,230,25,242,148,126, +148,222,152,232,162,236,208,236,220,232,226,222,235,203,28,40,67,74,20,210, +73,132,100,178,100,62,222,62,223,178,102,154,221,154,160,10,161,247,54,68, +202,68,202,146,54,146,55,70,126,12,127,216,28,228,207,216,180,180,229,241, +130,10,131,54,46,24,46,58,212,58,213,16,116,68,139,88,36,130,36,98, +222,98,223,130,60,130,199,130,26,164,229,164,128,164,128,224,126,230,122,238, +112,240,97,228,82,184,56,208,31,228,174,188,225,231,110,12,143,34,34,86, +34,46,220,46,221,84,150,70,185,96,28,114,225,114,114,64,110,112,104,140, +94,170,80,192,62,216,40,232,25,240,138,118,138,218,140,226,148,230,202,230, +214,226,224,218,230,208,231,194,196,138,160,176,124,204,95,221,14,74,97,74, +16,162,95,130,60,12,60,222,54,240,46,244,27,228,116,246,116,70,226,70, +227,244,118,140,225,140,118,220,223,220,170,10,171,217,16,30,129,30,32,240, +32,76,108,76,109,228,60,32,60,90,56,110,52,122,45,142,82,32,82,124, +84,130,86,134,90,136,92,136,96,136,103,132,36,176,105,176,36,214,105,214, +130,92,126,118,121,140,148,18,148,124,148,148,144,172,138,196,134,212,117,242, +158,96,173,132,182,26,183,230,194,92,209,134,224,12,225,241,26,212,26,36, +102,36,103,200,28,106,99,106,28,186,101,186,62,38,63,182,116,50,235,50, +122,88,227,88,110,124,243,124,162,10,160,96,156,124,146,152,134,180,105,220, +146,164,237,164,202,134,202,218,202,226,198,234,190,238,180,238,169,226,150,186, +177,213,30,26,88,26,88,84,32,84,33,28,60,86,61,196,28,120,29,206, +62,134,99,134,10,222,103,180,110,44,235,44,116,82,229,82,104,120,247,120, +164,6,162,64,158,92,152,122,142,152,134,174,103,218,142,164,241,164,206,132, +206,224,200,236,192,240,186,238,175,226,152,182,177,209,100,16,62,26,25,30, +18,82,109,82,64,30,65,242,60,96,40,152,19,186,66,106,101,144,92,238, +104,224,110,212,118,194,122,168,126,152,126,136,126,26,232,26,232,214,228,224, +222,230,206,232,195,230,144,74,209,74,176,40,177,108,140,112,217,112,156,144, +198,144,198,190,160,190,161,147,116,24,72,36,31,40,18,78,119,78,74,38, +75,158,70,88,48,116,25,140,78,92,113,120,140,42,129,96,218,42,199,90, +168,14,168,72,164,92,154,114,142,130,130,140,115,148,170,54,174,82,182,98, +190,114,202,126,227,148,52,174,25,230,88,170,88,222,92,228,96,232,170,232, +180,226,184,218,189,200,124,164,153,196,196,170,235,211,66,16,46,46,25,70, +50,44,119,44,68,46,87,72,158,16,142,44,129,64,144,42,231,42,170,42, +189,72,36,94,225,94,54,122,201,122,22,150,237,150,116,70,104,120,88,154, +74,174,56,190,27,212,82,184,223,184,172,162,172,230,166,242,152,242,137,230, +100,198,121,221,80,12,50,74,19,120,56,76,57,246,82,84,202,74,188,222, +190,226,200,230,212,232,226,230,230,224,236,218,241,194,140,12,138,130,132,158, +124,186,108,212,83,237,72,14,20,88,73,86,102,52,24,156,99,140,20,204, +99,186,84,240,102,220,110,202,118,180,120,156,120,146,120,26,222,26,222,216, +218,224,212,230,202,240,181,220,138,72,201,72,168,40,169,110,136,112,209,112, +148,144,192,144,192,188,150,188,151,147,28,224,28,40,70,40,71,216,30,92, +67,92,30,146,69,146,30,198,69,198,148,28,114,34,89,34,84,92,151,92, +118,36,119,244,114,108,102,146,85,180,122,120,149,152,170,72,157,122,234,64, +219,118,196,12,196,84,190,130,184,164,176,186,170,200,141,236,194,102,200,140, +208,174,218,198,243,235,38,36,211,36,46,122,195,122,210,36,202,46,195,216, +114,38,99,214,14,220,245,221,118,12,105,36,66,44,196,44,196,132,66,132, +67,46,68,74,195,74,68,102,193,102,18,166,239,166,158,140,189,158,126,140, +124,164,120,182,106,200,86,218,62,228,27,236,136,166,142,180,150,190,164,206, +178,216,194,224,229,237,50,18,93,50,20,74,96,74,76,110,50,138,21,160, +68,122,69,244,72,134,119,168,120,108,95,146,118,48,228,48,218,216,212,222, +181,230,168,52,166,78,164,112,160,138,156,162,146,186,136,204,126,218,105,239, +52,38,52,112,198,112,199,36,40,144,40,218,211,212,210,140,211,236,124,14, +125,211,18,72,87,72,58,12,59,246,54,84,38,130,21,174,62,98,87,130, +82,236,92,212,96,188,100,158,102,140,102,36,243,36,116,72,179,72,128,106, +166,106,166,156,130,156,131,108,124,172,137,200,168,170,157,210,108,226,185,208, +184,130,205,166,180,100,247,100,220,50,220,228,208,240,197,229,16,234,30,206, +34,180,38,142,40,124,40,30,231,30,56,72,143,72,70,110,126,110,126,158, +72,158,73,112,74,176,89,202,124,174,111,210,48,224,149,210,154,136,181,172, +148,100,243,100,204,48,204,226,198,236,190,242,165,227,36,30,92,30,92,90, +38,90,39,32,66,94,67,202,36,120,37,208,14,222,107,196,68,140,103,140, +104,38,239,38,144,10,145,68,196,8,197,68,116,84,203,84,168,60,169,114, +98,120,247,120,222,72,176,124,128,158,99,176,138,152,216,152,217,242,136,244, +137,152,138,186,215,186,138,224,213,225,64,16,40,60,15,92,42,60,97,60, +26,104,93,104,18,152,97,152,60,104,60,234,93,200,112,216,112,40,152,40, +153,200,114,104,151,104,114,154,149,154,96,228,171,194,168,78,232,74,228,220, +222,230,210,236,195,226,194,16,194,88,192,134,190,164,182,194,172,216,143,243, +72,14,48,66,23,98,52,58,100,58,77,114,26,120,102,120,103,236,32,162, +99,162,22,214,101,214,162,14,138,70,115,104,146,68,147,244,184,22,205,54, +150,68,239,68,148,116,233,116,146,164,231,164,146,220,241,220,192,70,193,219, +20,30,53,58,12,88,47,118,50,142,17,234,72,244,72,32,118,32,94,98, +100,108,108,120,114,136,114,150,114,160,110,168,104,174,91,176,176,12,148,60, +113,98,174,20,190,50,204,70,237,96,138,92,209,92,128,136,233,136,174,94, +174,220,162,234,139,224,144,166,111,216,196,162,231,211,30,244,30,30,88,30, +54,100,64,112,74,124,78,136,82,148,84,160,82,172,78,180,70,186,51,190, +156,12,126,66,81,102,154,20,174,50,198,72,239,94,110,104,209,104,98,148, +229,148,158,108,158,218,154,232,146,236,136,238,123,228,122,174,77,226,190,176, +233,219,26,50,121,50,78,10,79,118,74,54,52,84,21,112,82,64,115,82, +134,48,235,48,172,10,173,118,168,60,115,108,174,60,233,98,28,134,220,134, +209,152,130,136,131,220,132,176,211,176,82,158,58,206,23,242,72,186,82,202, +96,214,110,222,126,228,166,230,235,231,16,48,101,48,58,52,52,80,44,104, +32,124,19,142,46,218,46,114,90,114,91,210,48,186,89,186,130,32,130,106, +223,106,222,32,223,106,122,140,122,222,229,214,228,138,229,240,176,12,177,217, +74,12,50,70,19,120,48,74,49,246,88,34,115,68,68,100,98,100,90,224, +127,188,134,48,203,48,118,96,247,96,170,8,171,94,228,32,174,112,142,144, +117,166,146,246,146,136,218,136,219,240,148,176,217,176,146,218,217,219,44,30, +215,30,134,10,127,44,74,120,74,50,188,50,189,120,76,68,187,68,76,84, +187,84,76,104,187,104,28,122,233,122,24,142,125,142,76,126,77,158,134,142, +237,142,182,126,183,154,44,230,44,160,110,160,111,224,46,178,107,178,46,196, +109,196,46,212,109,212,16,236,123,228,148,226,148,160,216,160,217,226,150,176, +215,176,150,196,213,196,148,212,215,212,132,230,245,231,14,74,103,74,18,164, +97,122,62,12,62,230,52,240,29,230,144,14,177,34,92,44,243,44,160,50, +116,92,169,88,202,60,118,134,213,116,198,96,233,130,114,246,114,154,220,154, +221,242,114,190,219,190,116,226,219,226,166,156,167,225,66,14,19,88,48,44, +96,44,79,76,18,244,28,226,34,206,38,186,38,168,38,82,110,82,110,224, +104,238,89,230,42,124,109,124,40,164,109,164,74,84,75,216,222,150,146,150, +146,74,226,74,227,148,184,12,185,214,130,224,229,214,212,176,243,235,74,16, +54,86,25,142,64,66,120,66,106,134,90,176,66,208,29,238,58,116,74,158, +90,184,106,200,134,212,168,220,243,222,160,10,161,194,162,82,237,133,16,72, +91,72,20,154,85,122,58,12,58,226,50,238,27,226,160,10,161,72,106,30, +106,76,218,76,219,26,92,110,239,110,160,112,153,144,102,246,102,152,224,152, +224,226,212,240,197,230,140,156,141,228,180,154,181,227,70,22,70,132,64,164, +52,194,25,228,142,34,143,206,220,20,221,233,108,10,141,36,32,82,32,46, +226,46,227,80,104,62,76,82,47,98,144,64,201,94,34,112,221,112,74,126, +52,160,229,160,164,114,164,230,136,242,129,226,142,162,120,190,84,212,29,235, +16,70,91,70,56,10,57,246,52,86,38,128,19,162,58,102,89,128,144,10, +118,70,189,70,134,36,204,36,185,94,88,100,239,100,154,104,130,128,101,144, +144,116,156,130,166,148,172,168,176,192,174,216,164,230,146,238,135,226,158,138, +130,162,112,174,97,184,168,162,144,188,122,206,97,222,220,120,171,158,194,140, +206,170,220,196,241,219,86,14,58,72,23,122,58,74,59,242,96,60,227,60, +80,102,243,102,166,12,146,84,130,124,116,148,216,148,167,208,126,190,201,239, +72,16,57,40,16,234,30,212,36,188,40,162,40,152,40,48,100,48,100,216, +98,228,88,234,63,222,12,122,105,122,58,72,79,106,60,142,79,176,130,126, +142,108,148,92,150,76,150,32,202,32,202,108,204,114,214,116,245,116,140,242, +140,148,218,148,219,244,142,220,217,221,28,188,28,42,72,42,73,178,30,160, +69,160,162,14,163,66,108,26,108,72,218,72,219,26,92,106,241,106,162,108, +151,142,102,240,102,148,222,148,222,226,208,240,195,226,140,152,141,224,178,150, +179,225,200,98,50,98,50,52,200,52,201,100,38,212,38,134,210,134,211,206, +40,186,209,186,126,12,127,245,122,12,151,40,20,68,47,102,16,154,55,132, +24,234,44,208,52,194,56,178,58,158,60,146,60,48,241,48,154,62,122,106, +98,126,77,142,146,74,166,90,182,104,208,118,237,130,152,188,170,188,184,184, +186,176,192,138,110,138,110,216,112,222,114,230,118,234,196,234,206,230,212,224, +227,207,108,12,141,34,30,82,30,46,226,46,227,80,98,60,68,84,33,104, +152,58,219,100,124,80,107,106,54,246,54,114,202,114,203,242,54,224,201,224, +120,122,100,146,77,166,102,144,180,144,146,180,128,194,85,212,106,168,167,197, +22,190,22,66,88,66,88,174,76,184,73,176,56,14,57,244,150,8,175,28, +108,40,227,40,136,50,153,70,192,50,181,72,100,78,239,78,212,164,124,164, +124,104,212,104,213,164,128,134,209,134,166,106,167,226,112,194,227,194,98,226, +241,227,118,14,153,42,20,234,36,206,44,180,48,142,48,52,233,52,66,118, +225,118,142,70,143,248,136,122,106,172,92,190,59,220,148,120,166,152,194,184, +235,215,48,18,79,52,40,60,41,244,104,34,212,34,212,224,206,236,183,228, +68,78,156,78,149,140,96,96,92,144,178,144,176,190,174,200,164,208,141,210, +62,180,157,181,94,12,58,66,21,104,84,28,153,78,90,164,104,164,116,160, +122,154,128,104,58,104,58,210,60,218,66,222,128,222,136,218,146,210,149,198, +180,44,181,182,226,14,226,224,218,234,198,240,183,225,28,190,28,44,84,44, +85,180,30,160,83,160,152,10,134,70,109,122,136,68,226,68,209,112,162,96, +154,150,144,180,128,206,112,220,81,240,162,118,170,154,182,180,194,200,206,212, +235,237,30,62,21,130,62,8,62,74,60,126,56,162,48,194,25,230,104,48, +84,80,63,108,60,152,102,192,103,196,158,8,138,70,113,118,142,60,228,62, +209,106,166,94,164,128,160,156,152,178,140,200,120,220,95,240,164,132,174,156, +186,180,202,202,216,216,239,233,14,74,83,74,16,162,83,126,60,14,60,230, +40,242,25,228,220,26,176,34,136,36,101,38,94,76,241,76,90,126,245,126, +92,182,239,182,122,78,123,180,202,78,203,180,162,36,163,224,98,228,233,229, +62,16,44,62,17,100,46,62,101,62,30,106,99,106,16,150,103,150,60,108, +60,228,95,198,220,20,184,32,148,36,113,36,102,78,247,78,104,130,241,130, +100,182,247,182,134,80,135,180,214,80,215,180,176,36,177,226,106,230,241,231, +200,20,140,34,102,38,51,40,28,78,227,78,14,132,241,132,36,182,225,182, +74,80,75,180,184,80,185,180,126,38,127,224,40,228,213,229,32,38,227,38, +46,70,211,70,18,104,237,104,128,10,122,44,112,76,98,104,86,120,66,140, +19,174,158,108,172,126,188,144,202,154,241,172,76,248,76,144,178,144,179,244, +78,186,175,186,78,224,175,225,20,70,97,70,66,12,67,246,62,84,40,130, +19,170,68,94,97,128,102,42,229,42,108,70,225,70,98,102,241,102,170,12, +162,62,152,92,140,118,124,136,93,162,128,244,128,146,204,146,205,242,130,184, +203,184,130,222,201,222,182,104,200,130,214,144,239,161,14,34,123,34,30,234, +30,80,112,80,113,226,58,38,58,98,56,118,52,136,45,146,84,36,84,134, +88,140,105,138,34,174,111,174,34,212,109,212,166,14,193,38,128,50,243,50, +216,114,144,114,144,78,218,78,219,114,136,142,216,142,186,168,186,222,184,232, +176,240,166,240,153,228,126,186,245,187,22,192,36,166,44,140,48,118,50,86, +50,26,233,26,76,58,213,58,52,90,237,90,90,92,90,146,139,132,136,94, +146,108,158,122,178,136,200,146,235,158,202,100,175,128,78,244,78,172,196,172, +197,240,80,224,195,225,26,24,67,52,12,86,57,114,16,240,53,154,134,12, +167,36,76,54,241,54,204,118,100,118,100,82,202,82,203,116,88,146,198,146, +156,174,156,232,142,242,117,230,64,192,243,193,68,12,24,92,77,86,96,54, +30,158,97,146,16,222,103,198,110,58,235,60,118,90,118,156,214,156,215,90, +166,8,166,216,170,226,180,232,216,232,224,228,232,220,237,205,28,34,225,34, +44,54,211,54,26,76,231,76,126,14,114,46,102,68,86,88,66,102,19,122, +160,76,176,90,202,106,216,112,241,116,176,142,76,142,76,98,178,98,179,140, +80,122,175,122,114,198,40,198,40,170,114,170,115,196,78,154,79,224,28,236, +117,224,106,208,127,234,220,196,144,196,144,168,222,168,223,194,182,152,183,226, +140,234,221,224,210,206,237,235,26,28,78,28,79,96,36,46,57,62,26,88, +75,72,94,28,136,28,137,96,94,44,113,62,92,84,133,68,62,98,40,134, +19,162,48,124,49,244,86,100,105,118,56,128,145,128,56,158,141,158,56,186, +141,186,56,216,147,216,96,128,97,212,144,100,235,92,220,118,200,168,178,200, +158,220,135,238,198,32,225,66,176,12,176,96,178,130,182,164,192,190,210,220, +222,232,232,236,236,232,241,203,66,18,16,100,71,94,98,58,24,162,97,154, +18,218,97,200,162,12,163,66,162,38,235,38,214,144,120,144,120,72,214,72, +215,142,122,108,211,108,102,184,247,184,168,146,169,245,130,14,163,36,20,68, +39,100,16,154,53,132,240,48,60,48,60,138,54,176,46,206,31,242,130,66, +131,212,132,128,163,128,94,100,95,220,68,232,161,208,180,62,180,216,182,224, +186,228,190,230,218,230,224,226,230,222,237,206,232,100,183,139,14,46,241,46, +92,8,93,78,166,8,167,78,40,86,79,122,28,224,79,158,132,72,97,144, +116,106,216,106,203,142,160,126,154,158,144,180,136,194,122,206,108,218,77,236, +158,146,168,166,178,182,190,196,208,214,220,222,239,233,20,46,101,46,60,48, +48,94,36,118,21,140,44,220,44,108,82,108,83,208,44,190,81,190,122,20, +153,56,212,18,185,64,94,70,249,70,136,80,102,146,135,148,160,112,114,192, +94,222,157,208,144,176,163,214,202,88,164,156,207,154,228,118,164,232,229,218, +212,184,237,233,36,60,37,198,66,20,67,190,66,112,85,112,16,212,85,190, +100,20,100,218,127,196,102,112,127,112,160,16,136,68,119,90,180,24,205,54, +144,72,145,244,152,70,237,70,150,120,229,120,148,166,229,166,148,218,245,218, +184,72,185,217,104,22,68,38,29,44,14,94,117,94,68,38,69,144,38,238, +38,152,102,152,103,234,40,212,99,212,156,12,183,38,116,50,233,50,134,72, +159,106,210,68,189,116,108,120,245,120,174,122,175,244,118,172,239,173,80,12, +115,34,182,12,159,38,20,46,243,46,94,60,46,112,93,106,120,84,46,150, +121,142,112,120,127,156,58,178,29,234,182,60,140,114,187,110,212,88,146,154, +209,146,202,128,219,160,124,166,151,196,198,178,235,222,96,174,96,220,98,226, +102,230,108,232,160,232,168,230,176,224,182,216,185,205,36,24,81,46,24,104, +83,80,134,10,116,44,97,68,120,40,220,40,205,72,154,48,150,62,144,74, +134,88,120,102,104,110,83,118,152,56,160,68,168,78,182,92,196,102,219,116, +18,132,235,132,78,132,54,238,123,218,102,182,143,210,74,168,176,168,166,224, +166,230,170,236,178,236,210,236,218,230,226,222,231,199,36,20,71,58,10,102, +60,102,60,226,95,190,98,36,222,36,222,220,216,228,210,232,185,234,92,80, +201,80,178,182,116,182,116,122,180,122,181,183,88,22,89,200,40,62,41,214, +90,96,129,96,18,226,131,194,222,76,159,124,152,16,152,210,156,226,168,234, +212,234,222,226,228,216,237,187,22,52,157,52,44,152,44,90,144,90,144,142, +134,150,121,138,92,10,93,244,88,126,56,182,27,216,96,144,145,190,180,42, +181,178,222,8,222,214,218,226,212,230,202,232,183,235,38,166,38,24,104,24, +105,164,70,62,70,140,64,172,52,200,25,230,76,188,113,220,226,94,142,94, +142,20,224,20,225,94,142,58,223,58,164,102,146,130,125,150,150,130,240,130, +232,218,228,226,222,230,197,232,176,132,158,166,129,192,212,132,196,174,174,202, +137,237,30,44,77,80,18,196,87,138,138,8,122,64,97,108,124,62,226,62, +209,102,156,92,152,134,146,156,136,178,122,200,102,218,69,234,154,128,160,144, +168,162,178,178,186,190,196,200,216,218,235,231,12,38,109,38,38,38,39,192, +84,40,85,242,14,206,105,174,40,90,83,90,40,138,83,138,124,16,155,52, +212,16,179,62,214,130,128,130,128,70,214,70,215,128,124,164,107,220,162,142, +189,180,210,156,241,202,150,162,150,218,150,224,154,228,196,228,202,224,208,216, +211,203,16,42,239,42,100,8,101,72,162,8,163,72,76,64,56,98,29,126, +62,88,208,88,196,152,190,160,182,164,163,166,70,112,161,144,112,92,94,118, +84,128,41,156,164,90,126,142,114,152,65,180,56,194,25,236,120,172,147,200, +196,184,235,226,90,188,90,222,92,230,98,236,102,238,152,238,160,236,170,232, +178,224,185,211,122,10,105,48,38,246,38,56,220,56,221,244,42,222,217,222, +122,72,96,114,67,142,104,102,172,102,152,136,132,162,118,176,71,202,108,132, +140,158,175,191,94,16,64,70,31,108,72,56,222,56,212,210,208,224,200,230, +192,234,167,234,124,60,116,104,98,140,84,156,54,180,33,194,176,58,172,92, +162,126,144,166,122,194,100,212,88,220,55,238,74,106,177,183,74,16,70,98, +64,136,54,168,44,188,19,224,68,118,84,134,119,178,170,16,166,86,162,126, +154,156,140,184,122,210,99,236,170,104,180,140,190,162,204,192,216,210,237,229, +78,20,76,94,68,120,58,148,48,166,25,192,74,106,115,156,172,16,168,70, +162,112,154,140,142,164,134,176,122,186,101,200,172,86,180,116,192,146,208,170, +229,192,14,222,239,223,22,32,71,66,60,122,21,204,84,40,229,40,156,8, +152,46,148,68,140,96,122,122,108,138,71,164,92,74,213,74,70,106,239,106, +182,108,192,126,210,142,235,158,116,142,197,142,84,178,223,178,150,144,146,184, +138,202,122,220,104,230,83,240,146,192,211,239,24,38,43,76,104,36,85,72, +12,94,109,94,62,10,63,246,58,114,42,146,26,168,17,180,66,118,101,152, +134,218,134,30,216,30,217,220,136,92,215,92,136,156,213,156,100,224,247,225, +14,30,121,30,30,242,30,74,110,74,111,238,58,34,58,76,56,96,52,118, +43,144,82,34,82,132,105,132,32,178,109,178,32,218,109,218,128,52,229,52, +156,10,157,98,198,10,199,100,122,102,243,102,144,244,144,136,218,136,219,242, +144,178,217,178,146,224,215,225,66,10,48,46,23,76,52,40,127,40,164,8, +148,46,127,74,152,38,239,38,176,42,203,76,150,74,134,108,111,134,136,108, +229,108,78,46,99,78,58,76,81,100,18,112,111,112,58,114,58,152,54,172, +46,204,36,218,21,238,60,152,100,152,92,218,86,226,63,228,154,122,142,146, +125,166,146,140,221,140,174,144,168,182,164,198,152,214,134,228,111,238,178,182, +186,202,198,216,212,226,235,240,116,182,239,183,72,14,46,74,19,112,48,72, +49,246,210,98,110,98,110,30,210,30,211,98,162,102,163,214,164,154,225,154, +112,132,106,170,100,192,90,208,73,230,106,178,114,190,128,206,140,214,154,218, +174,224,241,225,82,94,36,94,36,32,84,32,85,96,62,96,63,196,64,136, +97,136,34,126,35,208,20,220,99,190,152,12,183,28,110,72,110,38,230,38, +231,70,150,56,126,78,103,92,180,56,229,88,212,132,126,132,126,100,216,100, +217,132,118,216,118,162,228,162,229,212,120,198,227,198,172,76,173,245,70,14, +46,52,23,76,56,38,127,38,84,40,97,60,168,12,129,60,150,36,237,36, +178,38,191,58,186,142,68,142,68,74,186,74,187,140,72,96,181,96,72,118, +183,118,18,164,237,164,106,144,82,178,68,192,58,200,25,222,166,166,178,182, +188,194,204,202,235,216,124,180,76,238,173,230,150,200,187,239,108,12,139,34, +30,80,30,46,224,46,225,78,94,60,64,82,35,100,152,60,219,98,190,136, +62,136,62,100,194,100,195,134,48,224,48,168,204,168,205,224,50,206,201,206, +126,70,127,249,18,72,91,72,18,156,91,110,58,8,58,224,52,232,42,238, +27,224,164,8,165,58,112,24,112,60,218,60,219,20,132,76,110,120,83,152, +112,122,113,244,160,78,183,98,120,110,233,110,120,146,225,146,118,182,225,182, +120,218,241,218,172,112,173,217,138,10,139,58,52,26,52,60,224,60,225,24, +80,74,56,120,25,156,60,116,61,244,122,74,157,96,70,108,229,108,70,146, +219,146,70,182,219,182,70,220,241,220,142,110,143,219,76,18,54,72,21,122, +56,72,57,244,164,8,165,60,104,20,104,66,224,66,225,22,124,80,104,120, +79,150,108,118,109,244,158,80,181,104,114,114,239,114,114,150,231,150,116,186, +231,186,116,222,245,222,168,116,169,221,16,228,28,202,36,178,38,148,40,130, +40,30,90,30,90,208,82,220,66,226,55,210,44,88,89,88,44,142,89,142, +168,10,146,46,131,66,154,36,208,36,193,72,100,240,118,210,124,182,128,150, +128,80,241,80,186,180,198,180,214,174,218,158,218,124,160,124,160,216,164,226, +168,228,174,230,220,230,232,224,241,205,128,10,157,32,22,58,35,98,14,154, +53,132,24,234,44,210,56,178,60,148,60,42,241,42,138,56,167,76,78,86, +229,86,124,100,110,136,91,164,116,122,147,146,194,100,182,128,165,156,186,120, +223,158,72,188,243,188,154,164,155,245,22,42,43,76,104,40,87,76,18,100, +105,100,66,12,67,242,62,112,40,160,19,188,68,118,99,154,156,16,187,40, +116,52,241,52,152,66,136,108,119,136,144,90,165,118,206,66,196,100,181,134, +198,96,229,134,102,174,245,174,172,142,173,243,34,28,73,56,18,88,53,112, +28,224,67,148,140,14,175,36,90,46,229,46,126,62,116,104,93,140,122,88, +151,114,194,62,182,98,165,130,184,90,229,132,80,170,245,170,158,140,159,245, +28,24,114,24,115,90,46,42,75,56,32,90,109,66,134,22,214,22,215,100, +146,42,177,58,210,66,141,88,118,94,143,110,26,122,233,122,96,132,47,180, +84,146,117,174,180,132,141,174,168,148,213,176,16,198,239,198,130,180,131,245, +18,78,113,78,70,12,71,244,64,92,48,134,21,172,74,104,109,136,124,82, +247,82,206,12,206,228,198,236,167,236,138,120,171,163,24,46,235,46,112,8, +90,72,76,100,52,130,25,156,66,114,67,240,114,90,216,90,176,130,176,226, +158,236,141,234,92,152,245,153,20,70,239,70,174,10,174,220,168,228,162,232, +129,236,68,112,107,159,20,52,101,52,62,54,50,96,40,116,17,146,46,222, +46,116,90,116,91,210,48,192,89,192,132,20,159,44,208,12,185,48,112,54, +235,54,114,92,229,92,104,130,245,130,170,56,166,92,156,132,138,174,118,198, +87,226,148,172,229,172,176,174,177,228,112,232,243,233,14,72,83,72,14,154, +75,128,50,12,50,228,42,232,25,234,206,86,108,86,108,26,208,26,209,86, +110,56,207,56,80,108,241,108,102,110,103,212,148,110,149,246,104,138,147,138, +104,174,147,174,84,220,169,196,160,138,218,138,210,164,202,186,188,206,163,232, +170,140,176,162,186,180,198,200,212,214,237,231,14,70,93,70,14,154,89,124, +58,10,58,224,48,234,33,236,126,14,153,42,206,10,185,46,106,52,235,52, +118,90,221,90,100,130,245,130,168,54,164,90,156,128,138,162,122,184,89,208, +140,168,229,168,114,224,243,224,178,170,179,223,16,70,97,70,18,160,93,124, +62,10,62,224,56,232,33,232,110,50,237,50,102,100,243,100,146,8,147,96, +202,10,203,96,122,242,122,136,220,136,221,240,126,176,217,176,124,222,219,223, +14,74,93,74,16,150,81,114,56,10,56,224,48,236,29,238,118,46,106,96, +89,136,112,84,139,118,210,42,198,94,179,130,202,86,233,118,158,10,159,222, +94,162,225,162,78,224,243,225,72,10,44,56,19,84,48,54,107,54,34,96, +95,96,20,150,105,150,64,98,64,228,105,200,120,52,239,52,150,8,151,100, +202,8,203,100,110,106,249,106,132,246,132,140,224,140,225,240,225,240,134,180, +223,180,134,222,223,223,14,68,97,68,18,156,91,114,60,8,60,224,48,234, +29,224,92,44,241,44,134,10,135,74,200,8,201,76,168,62,134,108,97,142, +166,74,190,102,222,122,241,132,130,132,207,132,122,244,122,166,214,166,215,242, +124,218,211,219,90,82,219,82,148,10,148,86,142,110,136,136,124,160,104,180, +83,196,160,134,219,190,32,24,71,72,12,112,54,112,55,200,18,224,38,210, +52,202,70,206,88,216,102,222,124,228,237,229,72,10,25,80,52,40,129,40, +76,40,95,74,172,10,141,62,236,42,155,42,180,44,203,78,130,64,86,108, +64,122,17,142,124,74,142,92,168,110,196,122,239,134,68,134,185,134,66,248, +66,168,190,168,191,246,70,224,185,225,128,12,159,32,22,64,41,98,16,156, +59,126,20,236,40,216,50,200,58,176,62,158,64,134,64,42,237,42,80,80, +243,80,122,56,123,106,194,106,195,56,158,96,134,120,116,136,108,142,77,158, +238,154,202,140,176,124,153,104,112,154,201,154,104,246,104,182,212,182,213,242, +106,224,213,225,10,68,101,68,14,156,109,116,60,10,60,228,42,238,27,224, +110,46,247,46,192,48,192,222,182,234,157,235,22,94,229,94,120,14,120,100, +114,138,96,174,64,208,27,238,122,96,134,128,144,150,158,172,178,192,196,210, +233,233,196,88,66,88,66,28,196,28,197,88,20,132,239,132,130,100,131,242, +118,136,96,166,70,190,25,218,134,134,156,160,178,184,202,200,233,219,22,32, +239,32,124,32,114,66,98,98,80,120,51,146,108,86,200,86,182,132,150,180, +110,208,68,224,29,232,108,130,155,165,78,18,50,70,19,112,54,64,55,242, +150,8,146,58,138,94,124,118,106,140,77,160,178,118,196,136,220,154,237,162, +86,50,233,50,92,78,221,78,78,112,241,112,156,132,156,218,154,228,150,236, +127,238,112,154,135,174,198,154,175,184,150,186,87,210,164,184,219,221,34,42, +143,42,90,14,91,68,16,70,241,70,136,146,42,146,42,94,136,94,137,142, +44,118,135,118,88,96,89,142,32,174,145,174,16,200,157,200,68,152,69,196, +110,148,111,198,68,212,27,242,98,212,127,230,190,26,211,50,168,14,168,88, +170,120,176,150,182,176,192,202,206,222,216,232,222,236,226,234,233,210,212,102, +200,160,180,198,162,220,137,243,16,52,241,52,72,10,73,88,130,12,131,86, +184,10,185,86,30,146,30,104,228,104,229,142,64,228,64,146,198,146,198,212, +174,220,161,210,130,118,131,243,16,36,111,36,60,38,44,100,21,144,52,88, +98,88,84,146,66,188,40,222,23,236,46,140,75,162,166,12,114,106,219,90, +192,52,239,108,126,246,126,144,216,144,217,242,126,218,213,219,88,14,58,72, +36,104,17,126,62,64,63,244,80,118,241,90,142,12,142,66,148,112,156,156, +168,186,186,212,208,228,222,232,230,228,239,202,176,26,211,67,98,12,64,44, +23,74,66,44,67,110,88,66,239,56,146,10,158,56,166,74,182,94,194,104, +206,114,218,120,224,120,230,118,239,94,70,200,70,126,190,126,191,198,132,146, +126,186,118,202,108,214,90,224,70,234,37,240,144,204,221,240,180,16,217,37, +94,14,56,54,25,78,64,46,65,126,86,68,239,56,146,8,156,60,170,84, +180,98,192,110,208,118,218,122,224,120,230,114,241,96,178,16,217,38,114,102, +149,132,20,142,241,142,120,146,104,164,80,180,60,194,25,206,84,182,84,236, +139,212,206,164,177,198,140,160,160,188,180,208,198,220,239,233,80,14,50,50, +23,72,76,80,50,120,21,152,58,108,59,244,110,52,225,52,166,8,167,98, +92,100,245,100,104,148,239,148,200,116,200,230,178,240,165,226,124,172,151,201, +24,28,63,62,12,112,56,112,57,204,18,232,40,216,54,208,70,212,88,220, +106,226,132,230,176,232,239,230,88,44,208,44,208,110,89,110,76,76,243,76, +150,10,150,196,144,206,138,210,123,200,90,132,121,146,80,184,147,160,218,128, +181,156,158,152,223,199,122,16,44,76,201,66,166,34,225,80,194,150,64,150, +64,104,194,104,195,148,54,184,25,230,120,168,151,196,202,180,237,224,90,178, +90,220,92,226,98,232,108,236,156,236,170,234,178,230,182,222,189,209,10,32, +115,32,38,188,39,34,90,244,91,32,40,82,89,82,40,134,89,134,16,202, +117,170,118,108,118,64,222,64,223,104,168,8,164,90,158,128,148,168,134,196, +111,232,178,114,178,210,178,218,180,224,186,230,218,230,228,226,234,220,239,201, +14,68,101,68,60,12,60,228,40,242,29,226,16,160,95,118,218,160,126,160, +126,32,220,32,221,158,130,98,217,98,98,220,245,221,28,236,48,220,60,200, +70,168,72,142,72,22,184,22,184,216,180,226,168,234,141,222,106,52,143,98, +12,122,243,123,72,14,109,42,182,10,153,54,200,144,60,144,60,60,202,60, +203,144,62,102,199,102,130,64,131,250,12,182,239,183,40,14,69,48,124,14, +95,60,130,144,40,144,40,70,132,70,133,142,42,108,129,108,84,74,85,244, +14,184,151,184,168,244,168,32,224,32,196,102,208,114,220,130,230,148,232,164, +232,174,226,184,214,192,193,197,16,68,87,68,18,154,89,122,60,10,60,230, +48,238,25,224,114,18,143,48,200,10,173,60,214,146,106,146,106,66,216,66, +217,144,110,106,213,106,160,68,161,246,84,184,241,185,18,228,32,202,38,176, +40,144,40,24,94,24,94,210,90,222,80,224,65,224,44,82,93,82,44,138, +91,138,220,164,136,164,136,24,222,24,223,164,140,94,217,94,112,220,243,221, +198,164,60,164,60,32,198,32,199,162,62,96,197,96,14,222,245,223,18,88, +48,54,73,10,58,40,229,40,64,68,217,68,38,96,194,96,194,134,194,166, +202,202,214,228,226,238,230,236,239,208,70,108,53,142,158,108,137,130,110,104, +102,128,90,142,72,154,33,170,102,130,175,166,70,166,51,206,152,172,135,194, +108,156,102,190,94,206,78,220,54,230,27,240,102,198,183,239,82,14,52,76, +21,122,58,72,59,244,216,164,114,164,114,38,216,38,217,162,118,102,211,102, +80,220,247,221,62,6,63,244,34,66,21,122,78,62,97,98,124,16,149,46, +206,10,181,56,216,148,114,148,114,62,218,62,219,146,118,108,215,108,164,66, +165,244,88,184,243,185,38,24,79,54,16,88,59,116,30,228,71,138,118,34, +105,76,216,30,189,70,156,8,154,60,148,78,134,96,116,112,91,126,152,72, +223,118,116,140,97,186,214,140,191,180,158,112,154,158,140,190,120,212,98,228, +79,236,154,152,166,178,180,196,198,216,210,224,235,235,32,18,67,58,14,94, +52,94,52,212,83,178,82,28,124,28,86,104,126,104,122,142,114,176,100,202, +84,220,69,236,86,134,104,176,120,196,132,208,146,216,162,222,178,224,239,224, +230,26,184,38,151,40,188,38,189,182,154,80,154,182,227,182,190,108,229,109, +18,32,80,32,80,90,34,90,30,144,78,144,74,202,70,220,62,228,27,230, +118,14,149,48,204,14,173,60,212,144,112,144,112,66,216,66,217,144,114,108, +211,108,162,70,163,244,92,184,241,185,30,28,220,28,209,54,126,34,127,100, +126,70,207,70,78,52,60,94,21,124,70,82,90,98,104,104,128,110,239,110, +204,184,62,184,62,144,202,144,203,182,130,126,131,216,32,226,207,218,194,196, +233,235,44,42,89,88,212,34,159,88,124,14,125,106,38,114,204,114,205,242, +34,216,203,216,48,164,199,165,18,72,97,70,18,152,91,122,62,12,62,232, +48,238,27,224,102,36,133,78,228,32,191,82,164,10,165,102,100,108,220,108, +221,244,96,220,217,220,102,162,217,163,58,20,93,52,200,16,167,54,130,10, +131,62,34,106,34,70,226,70,227,106,184,158,76,158,76,108,184,108,185,156, +104,162,104,174,100,190,92,206,74,220,58,228,25,238,148,162,148,218,154,230, +168,234,206,234,220,230,228,218,235,197,20,46,239,46,94,12,95,74,166,12, +167,74,48,82,83,104,28,124,65,142,32,228,81,160,100,90,190,90,114,144, +220,142,212,216,204,228,194,232,177,232,146,146,140,166,130,178,118,190,91,206, +184,148,178,172,166,194,152,208,113,237,16,78,103,78,66,10,67,246,60,86, +42,130,19,166,70,104,97,138,100,32,139,82,228,30,189,82,166,10,167,108, +104,112,226,112,227,246,112,166,223,166,102,224,221,225,32,46,212,46,202,208, +196,222,188,228,178,232,157,228,118,48,118,90,116,120,108,140,100,164,84,186, +62,210,31,237,62,16,62,224,58,230,52,236,44,242,29,226,18,74,95,74, +22,156,95,124,148,64,171,90,156,8,143,40,172,116,188,116,198,110,206,104, +210,46,120,46,120,142,228,142,220,222,212,234,198,242,175,226,144,158,145,208, +100,168,100,208,190,208,191,175,96,94,36,94,36,32,96,32,97,92,68,96, +69,204,72,140,103,140,34,126,35,214,18,226,105,200,224,22,188,34,168,36, +117,38,116,70,137,104,160,62,177,94,228,56,193,112,162,128,122,138,123,244, +156,176,125,176,188,134,224,134,225,242,186,176,223,176,124,222,221,223,72,12, +50,72,19,120,54,66,55,244,84,36,173,36,124,46,86,102,159,94,146,68, +171,110,88,146,167,146,130,112,131,204,84,214,175,198,192,52,193,174,232,12, +232,226,226,230,218,236,193,225,110,8,99,36,146,104,162,104,176,98,184,90, +188,40,58,40,58,134,218,134,208,218,204,228,172,242,161,228,88,62,125,90, +96,148,97,204,36,156,36,204,158,204,159,157,36,22,75,54,16,82,80,82, +68,108,54,128,21,162,64,126,101,154,60,124,61,246,106,48,233,48,114,84, +229,84,102,124,245,124,160,8,160,56,156,92,148,130,132,166,112,196,89,216, +142,164,243,164,208,134,208,214,204,230,190,238,177,228,152,186,171,207,60,70, +200,70,200,28,56,28,56,100,58,106,66,112,204,112,218,106,231,88,16,154, +239,154,186,130,186,218,186,226,182,232,166,240,143,230,70,174,113,209,20,30, +141,30,78,38,24,108,125,98,102,62,143,110,28,154,137,154,84,116,85,206, +20,220,143,206,172,44,173,172,220,12,220,220,216,234,198,240,183,225,96,26, +72,34,46,38,21,40,18,90,105,90,66,38,67,242,60,102,44,146,21,180, +70,110,101,148,228,20,172,34,115,38,118,60,137,100,156,50,175,90,226,50, +193,106,152,118,118,126,119,242,186,122,224,122,225,236,154,166,121,166,188,166, +223,166,120,214,223,215,56,14,57,246,32,70,19,122,74,58,93,102,158,40, +231,40,156,12,157,68,214,144,112,144,112,74,214,74,215,142,114,108,211,108, +80,182,247,182,166,148,167,247,108,18,139,48,200,14,175,52,80,60,235,60, +154,62,145,92,204,196,104,196,104,100,204,100,205,196,110,132,199,132,108,162, +201,162,26,28,63,66,14,106,54,106,55,198,20,226,34,214,54,202,64,204, +84,212,104,220,116,224,134,230,158,232,239,229,38,30,75,56,26,138,81,92, +134,16,99,74,114,54,222,54,203,78,154,58,146,88,132,110,116,122,91,140, +152,72,164,86,178,102,198,120,227,136,14,230,243,230,54,226,54,158,202,158, +203,228,104,160,105,226,152,160,153,229,72,14,27,72,78,72,23,140,54,116, +55,244,90,44,241,44,168,12,157,66,222,120,104,120,104,74,224,74,225,120, +144,76,145,118,182,76,183,118,84,152,241,152,106,182,79,224,154,166,179,194, +210,182,237,216,130,174,130,222,132,228,136,232,142,234,188,234,198,230,202,222, +207,213,78,18,25,74,82,80,21,152,58,112,59,242,206,94,112,94,112,28, +208,28,209,94,114,62,205,62,92,128,233,128,80,164,245,164,196,130,196,220, +190,230,182,240,161,230,122,186,149,211,74,14,57,64,36,238,36,70,106,70, +107,232,38,140,103,140,40,210,103,210,150,124,189,168,168,12,150,68,127,104, +152,70,222,70,220,216,212,230,198,236,175,239,90,92,34,92,34,30,92,30, +93,92,62,96,63,204,32,128,33,210,66,144,101,144,14,224,103,194,104,30, +150,30,144,54,134,76,122,98,104,116,95,124,108,60,131,76,178,18,186,48, +196,68,212,90,237,116,224,28,191,52,236,58,211,80,134,98,201,98,208,176, +130,176,130,132,212,132,213,176,134,190,153,220,208,190,189,222,98,228,245,229, +36,62,25,128,108,60,77,98,72,152,113,198,70,12,66,38,66,82,68,134, +64,160,56,186,46,208,25,228,106,40,243,40,186,42,186,218,184,226,174,230, +151,235,44,32,116,32,94,64,68,90,48,104,21,122,48,54,71,82,194,16, +159,42,216,40,177,68,140,20,154,46,166,68,184,84,202,96,243,110,72,100, +185,100,188,174,70,174,70,134,188,134,189,174,88,192,107,220,172,188,153,222, +28,228,233,229,66,6,46,44,23,76,54,36,127,36,78,40,93,70,166,6, +148,34,129,58,152,34,239,34,172,36,197,70,50,92,205,92,126,68,127,128, +14,132,245,132,32,166,229,166,174,144,174,222,172,232,162,238,141,236,78,182, +109,215,30,220,30,40,80,40,81,216,34,92,79,92,32,144,77,144,30,198, +77,198,98,34,150,34,136,70,120,94,95,118,106,56,127,76,218,30,191,54, +232,62,209,84,176,20,180,38,186,60,198,78,212,94,237,116,126,102,201,102, +206,176,122,176,122,134,206,134,207,176,130,194,149,220,200,192,185,222,92,228, +241,229,44,30,112,30,84,58,54,80,19,96,46,50,65,66,138,24,156,44, +180,64,206,76,243,88,184,20,167,48,216,36,195,68,86,70,175,70,194,124, +70,124,70,96,194,96,195,124,88,134,99,152,166,134,159,152,20,158,241,158, +18,238,40,236,60,230,76,222,84,210,88,198,88,180,162,180,162,202,162,222, +168,232,220,232,232,226,239,207,24,36,114,36,106,72,98,106,90,124,72,156, +52,178,27,204,36,72,68,108,92,138,123,184,154,240,154,30,224,30,190,104, +204,114,218,124,226,136,232,152,230,168,224,184,208,194,196,196,185,197,14,88, +97,88,58,16,59,180,18,198,97,170,212,98,126,98,126,30,214,30,215,98, +130,64,209,64,96,134,243,134,168,138,169,220,168,176,225,176,126,154,108,200, +77,236,118,182,126,200,140,214,158,224,176,228,239,233,78,14,54,68,21,116, +58,72,59,246,222,30,170,40,112,40,112,232,161,186,164,210,183,236,116,114, +241,114,176,42,176,100,178,132,188,168,204,208,222,230,228,232,234,230,241,201, +38,30,71,58,20,92,63,120,30,236,73,150,136,14,169,38,82,50,243,50, +116,62,141,88,198,58,175,92,98,246,98,98,224,98,224,220,220,230,210,236, +191,234,118,134,207,134,160,110,161,164,182,206,132,206,132,164,182,164,183,207, +34,28,73,70,14,110,58,110,59,198,22,224,38,212,54,204,60,204,72,208, +94,220,108,226,126,230,152,230,180,232,239,226,216,184,106,184,106,62,218,62, +219,184,108,118,215,118,160,10,161,181,102,20,80,28,44,34,21,36,10,84, +117,84,68,32,69,130,36,230,36,136,102,136,103,220,38,204,99,204,164,10, +144,76,119,126,148,74,235,74,202,80,196,118,182,162,164,192,142,216,117,236, +146,106,156,142,162,160,174,182,188,198,212,222,233,233,72,14,46,60,19,94, +52,50,127,50,68,54,95,92,170,12,150,52,133,80,152,50,243,50,176,50, +207,92,56,250,56,126,208,126,209,248,60,174,207,174,58,224,207,224,130,90, +131,223,20,26,46,44,66,72,78,100,84,142,82,180,76,210,64,228,48,236, +31,238,94,24,72,50,48,74,21,94,78,114,58,140,38,158,19,176,126,60, +115,134,222,56,197,124,164,10,164,110,158,152,146,184,128,214,91,242,164,118, +178,154,190,184,204,202,239,235,36,20,77,50,18,78,55,104,24,230,57,142, +142,12,116,50,91,74,124,42,204,42,176,78,136,108,81,130,128,62,158,90, +184,106,239,124,86,154,233,154,160,120,160,234,154,240,144,244,129,230,124,176, +104,204,79,224,186,180,231,219,36,28,120,28,121,104,118,76,35,96,54,42, +85,66,142,26,220,26,221,104,154,42,183,64,142,90,215,72,88,104,56,146, +27,172,70,134,71,244,132,104,163,122,78,134,229,134,78,164,219,164,78,192, +219,192,78,222,241,222,144,136,145,221,66,16,56,76,46,120,36,156,95,206, +18,78,88,78,84,118,76,152,62,188,23,232,150,10,177,36,96,48,245,48, +126,62,151,90,202,64,181,94,110,246,110,102,222,102,222,224,218,232,204,242, +187,228,126,138,207,138,166,112,167,166,190,204,190,166,142,166,142,204,191,205, +12,72,99,72,16,160,95,126,60,14,60,220,58,230,42,244,23,226,220,28, +176,42,152,44,118,46,118,230,161,186,120,112,239,112,176,44,176,114,186,162, +198,194,214,220,228,232,234,228,239,204,164,210,189,239,122,12,153,32,18,232, +30,218,46,190,52,158,54,144,54,44,233,44,218,76,156,88,92,92,92,228, +149,190,96,140,233,140,156,92,162,136,168,164,178,184,190,206,200,220,214,228, +226,230,230,226,237,210,144,218,173,243,14,84,93,84,54,14,55,180,14,200, +99,168,84,112,216,78,214,156,210,166,204,172,194,176,191,166,166,8,167,194, +120,24,120,208,122,222,126,228,136,230,210,230,224,226,232,218,237,201,22,42, +235,42,92,12,93,66,164,8,165,66,114,56,139,76,30,88,225,88,88,100, +111,118,168,98,151,120,32,162,32,128,224,128,225,164,68,226,68,166,192,166, +192,202,192,210,186,216,163,218,126,132,127,243,74,14,46,52,25,76,58,38, +133,38,78,40,99,72,172,12,135,72,156,38,243,38,178,38,201,68,46,88, +202,88,202,124,56,124,54,166,216,166,216,180,214,194,212,202,206,208,196,212, +169,214,132,92,133,244,122,172,98,192,74,206,50,216,27,225,112,14,141,38, +28,48,229,48,80,64,103,90,176,62,157,94,30,140,30,102,228,102,229,140, +60,220,60,146,196,146,196,194,196,206,188,212,165,216,126,118,127,249,78,12, +111,44,186,10,149,48,40,62,208,62,208,110,54,110,50,152,228,152,222,192, +218,204,206,206,187,208,126,156,100,182,68,208,33,230,134,66,135,249,32,30, +69,66,16,114,56,114,57,204,18,232,32,220,46,210,56,206,70,212,96,224, +112,230,134,234,156,234,235,234,112,18,141,44,194,16,169,48,86,56,208,56, +208,96,100,96,98,136,218,136,216,174,212,180,202,186,185,186,154,58,155,218, +150,142,120,174,102,186,87,197,68,24,20,108,75,102,100,64,28,176,101,156, +24,222,101,206,148,16,183,42,104,50,239,50,130,66,157,90,206,60,185,96, +110,136,110,104,232,104,233,134,124,226,124,146,220,146,220,212,216,218,210,220, +193,212,170,108,171,245,16,40,123,40,78,10,65,64,14,188,133,188,38,184, +38,72,108,72,109,186,38,100,107,100,40,130,107,130,38,158,107,158,62,202, +23,240,88,202,113,222,130,30,237,30,178,32,169,68,148,190,148,74,218,74, +219,188,182,100,182,136,180,166,174,190,158,220,131,238,188,198,241,239,60,12, +60,220,58,228,52,234,46,240,21,224,16,72,97,72,16,160,93,122,152,12, +185,40,84,238,92,226,104,202,110,168,112,146,112,52,241,52,176,66,177,154, +176,104,233,104,138,248,138,160,218,160,219,244,138,224,217,225,34,24,69,54, +18,84,57,112,30,232,65,144,84,40,235,40,164,10,155,66,106,184,106,72, +204,72,205,184,110,102,201,102,110,132,201,132,110,160,201,160,74,190,243,190, +134,204,79,240,174,204,229,239,16,44,103,44,58,50,44,92,19,130,44,218, +44,108,84,108,85,210,46,186,81,186,98,166,247,166,120,162,120,54,222,54, +223,164,122,110,221,110,154,10,155,162,188,8,189,162,152,184,93,236,186,184, +241,235,124,50,225,50,120,10,121,90,190,156,58,156,58,96,192,96,193,156, +58,186,23,236,90,188,109,232,140,186,163,228,198,182,231,235,10,170,245,170, +52,166,52,60,204,60,205,166,54,112,201,112,104,12,105,164,154,10,155,166, +104,188,64,218,25,240,150,188,227,241,18,44,111,44,26,72,105,72,10,102, +117,102,68,10,69,98,34,242,34,130,96,130,96,220,90,232,80,236,67,224, +36,158,93,158,36,188,93,188,160,14,181,36,130,82,130,50,222,50,223,80, +130,98,223,98,178,98,179,214,180,154,225,154,138,144,136,180,132,202,122,224, +111,240,136,192,146,206,162,218,186,226,206,228,239,229,22,54,101,54,18,112, +101,88,70,16,70,138,58,156,48,158,35,144,118,56,202,56,190,130,192,138, +198,144,200,146,218,146,226,144,232,138,239,118,158,12,154,66,146,100,130,126, +99,150,122,82,173,114,36,184,219,184,126,148,127,224,16,228,241,229,192,168, +38,168,38,56,194,56,195,166,40,110,191,110,114,8,114,214,116,222,122,228, +126,230,130,232,198,232,206,230,218,224,226,218,228,210,231,197,74,12,54,66, +21,116,56,66,57,244,104,238,104,36,228,36,229,236,108,120,225,120,166,38, +167,208,106,210,225,211,88,14,56,64,25,102,68,50,222,50,218,194,216,204, +212,216,204,226,190,230,178,232,155,234,168,188,62,188,62,92,168,92,169,188, +64,138,165,138,114,96,115,185,116,12,153,40,18,232,30,216,38,200,44,178, +48,144,48,52,229,52,136,68,137,150,138,108,235,108,82,244,82,158,204,158, +205,244,84,220,203,221,60,10,61,246,34,64,21,118,76,60,91,100,152,12, +179,36,84,238,98,218,104,192,110,158,110,152,110,48,241,48,174,64,175,154, +176,104,239,104,138,244,138,158,220,158,221,240,140,222,219,223,74,18,109,40, +176,16,149,46,32,50,229,50,198,160,58,160,58,80,200,80,201,158,108,54, +106,74,102,92,92,106,79,118,148,52,148,96,150,102,154,108,160,110,193,110, +62,134,197,134,22,188,235,188,122,172,108,202,90,218,56,232,27,238,128,190, +142,202,160,216,188,228,227,237,38,26,81,56,20,86,63,118,28,228,73,152, +140,16,169,46,100,90,100,58,222,58,223,88,102,106,223,106,158,108,159,218, +160,160,225,160,114,142,104,186,94,208,67,238,106,184,116,202,130,214,142,222, +166,228,237,229,16,226,26,204,34,166,38,130,38,30,124,30,124,72,41,72, +50,124,127,124,74,88,75,164,106,88,107,162,46,168,133,168,78,188,62,212, +47,232,96,188,123,220,134,112,146,98,154,80,158,58,158,28,204,28,204,82, +204,92,208,96,212,100,239,100,136,130,218,130,200,168,180,198,154,222,125,240, +150,130,160,156,170,178,186,200,204,216,237,237,16,42,105,42,60,42,56,68, +46,92,19,132,44,208,44,108,90,108,91,200,46,180,87,180,88,232,108,208, +116,188,120,166,122,138,122,24,230,24,230,228,208,238,193,224,144,70,209,70, +178,36,179,108,140,110,213,110,198,186,152,186,152,144,200,144,201,187,32,204, +32,38,86,38,87,194,34,170,85,170,106,32,222,32,222,128,220,174,218,202, +212,216,200,222,167,222,104,180,189,89,20,230,28,208,32,188,34,164,36,136, +36,30,116,30,116,206,114,212,112,218,108,222,94,232,83,216,50,70,99,70, +74,42,75,108,48,108,101,108,88,182,58,182,58,140,88,140,89,180,168,12, +148,62,129,96,148,70,149,240,190,12,211,50,156,64,241,64,154,112,233,112, +152,160,235,160,154,206,247,206,194,66,195,205,28,34,67,68,24,198,73,126, +66,236,82,216,94,190,102,158,106,126,106,26,224,26,224,216,220,224,210,238, +189,222,128,74,203,74,164,40,165,106,122,108,209,108,188,186,138,186,138,140, +190,140,191,185,36,38,208,38,200,200,194,212,180,226,155,210,42,194,161,83, +58,8,58,220,54,230,44,240,27,224,16,154,89,116,160,8,161,64,162,36, +231,36,212,142,116,142,116,70,212,70,213,140,118,106,211,106,16,68,95,68, +88,180,243,180,166,146,167,245,192,82,70,82,70,24,192,24,193,80,50,212, +50,126,212,126,212,188,210,200,198,214,175,200,130,84,131,245,64,12,46,54, +19,84,46,56,115,56,28,100,105,100,18,148,115,148,66,102,66,224,111,190, +154,14,140,72,117,116,144,66,224,66,224,204,214,228,200,238,169,226,146,120, +185,167,38,22,81,54,12,92,54,92,50,216,87,174,86,238,104,208,110,174, +114,140,114,24,230,24,230,214,218,232,195,220,130,68,209,68,170,36,171,104, +128,108,217,108,196,184,146,184,146,140,198,140,199,183,92,92,30,92,30,28, +94,28,95,92,66,96,67,202,32,124,33,210,66,138,105,138,14,226,103,190, +136,34,120,80,107,108,124,74,227,74,112,134,237,134,172,10,172,78,166,138, +150,186,128,216,97,242,168,136,184,176,196,200,216,224,235,241,98,22,70,46, +45,60,160,22,217,50,166,42,124,74,92,88,66,96,29,104,98,46,124,66, +154,82,196,94,237,98,132,92,102,114,78,124,53,136,110,112,182,112,146,138, +104,158,74,166,39,172,98,132,117,146,176,142,146,166,118,182,88,192,59,200, +150,164,210,164,192,186,170,204,142,220,100,232,64,236,43,238,120,196,143,215, +16,44,93,44,54,44,50,68,42,94,32,118,17,140,44,220,44,110,84,110, +85,210,46,186,83,186,100,52,239,52,124,16,124,122,229,122,160,8,160,88, +204,88,205,10,102,156,239,156,172,128,173,246,166,162,148,190,128,210,105,228, +176,162,188,182,200,198,210,208,239,231,88,132,24,132,24,66,90,66,91,132, +58,14,59,194,14,210,91,186,86,168,101,208,104,56,235,56,162,12,162,98, +202,98,203,8,126,20,126,130,227,130,104,160,237,160,172,136,173,248,166,164, +148,192,132,210,107,228,174,168,192,192,206,208,233,229,38,34,75,70,122,30, +110,70,93,102,114,66,219,66,164,12,164,78,160,110,158,136,142,164,120,186, +93,200,158,140,223,198,88,122,233,122,14,110,58,110,59,200,20,230,34,216, +54,202,60,202,76,214,98,224,124,230,168,232,239,231,30,20,69,52,12,96, +56,96,52,226,93,186,82,50,235,50,154,8,154,90,198,90,199,10,112,16, +112,122,223,122,86,156,235,156,160,132,161,244,152,158,136,182,122,202,104,220, +93,230,164,160,178,178,190,192,206,206,220,216,237,225,60,20,186,20,152,38, +122,50,90,58,55,58,88,32,130,42,207,62,26,74,116,74,104,88,80,106, +60,116,37,124,48,88,84,104,121,122,136,74,220,74,204,92,190,102,166,114, +137,124,185,104,150,92,223,124,26,168,26,136,228,136,229,170,14,230,243,230, +66,226,66,160,188,160,189,228,70,182,185,182,68,206,187,207,18,40,239,40, +140,40,140,228,116,238,93,219,30,226,30,34,88,34,89,218,32,88,87,88, +30,140,87,140,32,200,87,200,108,36,245,36,190,36,190,216,174,238,147,221, +30,192,30,40,84,40,85,184,30,156,83,156,108,38,245,38,186,38,186,224, +164,242,145,225,64,10,38,62,19,90,40,58,109,58,30,98,103,98,16,148, +113,148,64,98,64,236,113,186,122,44,243,44,196,44,196,228,174,242,151,225, +16,42,97,42,60,42,60,216,50,226,29,208,104,26,239,26,166,26,153,72, +116,190,116,78,212,78,213,188,162,108,162,150,156,176,146,200,130,218,93,238, +174,194,233,237,184,108,72,108,72,20,186,20,187,106,74,50,185,50,74,80, +185,80,42,80,42,140,108,140,109,240,16,174,107,174,58,174,56,198,50,216, +40,228,29,236,220,76,220,138,154,138,155,240,156,174,222,174,223,237,66,12, +42,58,21,88,44,56,109,56,30,100,103,100,18,148,111,148,64,100,64,236, +97,192,158,14,193,40,130,84,130,52,228,52,229,84,126,102,231,102,178,102, +179,222,178,160,231,160,138,140,132,194,118,218,99,240,134,190,142,204,154,216, +166,224,186,228,216,230,241,231,106,12,145,38,36,92,36,50,222,50,223,94, +56,104,203,104,128,104,129,220,130,158,217,158,74,136,66,172,56,196,38,220, +19,238,64,180,76,196,86,206,102,216,120,222,152,226,208,228,239,229,36,20, +79,56,10,96,58,96,56,232,105,168,100,38,247,38,190,38,190,216,174,236, +145,219,216,20,170,32,134,34,84,36,49,36,44,86,215,86,132,36,133,138, +16,140,241,140,126,150,54,230,193,212,156,164,211,237,16,52,241,52,110,8, +50,130,219,130,134,80,134,228,118,242,97,226,92,166,62,198,44,214,29,224, +168,168,231,219,102,12,68,60,39,92,74,54,112,90,148,114,184,132,239,146, +80,44,196,44,158,84,116,118,68,140,19,156,104,148,163,180,84,194,171,239, +26,38,233,38,96,12,97,56,160,10,161,56,192,60,162,68,124,72,82,74, +57,72,16,98,241,98,196,172,62,172,62,120,196,120,197,170,64,148,195,148, +38,202,219,202,130,72,131,228,22,228,235,229,56,12,57,246,34,68,17,128, +70,66,91,112,82,40,237,40,136,10,137,58,182,10,183,56,212,66,182,70, +158,72,124,74,103,72,92,94,245,94,214,170,106,170,106,118,216,118,217,168, +108,144,215,144,90,198,231,198,158,72,159,224,74,228,245,229,26,42,121,42, +16,106,127,106,70,116,24,204,109,190,86,140,121,208,124,78,224,74,218,214, +196,236,175,220,168,10,168,108,164,142,156,174,144,204,132,222,115,241,19,74, +18,74,97,74,62,10,63,242,58,84,40,132,17,174,66,108,95,140,102,56, +243,56,166,10,110,132,231,132,174,92,174,230,158,240,139,224,136,162,114,190, +93,210,200,164,241,211,76,14,52,74,19,124,54,70,55,244,104,242,104,32, +232,32,232,216,210,240,189,220,126,74,209,74,192,174,142,174,142,118,194,118, +195,173,54,12,55,248,28,70,15,128,74,64,91,106,114,242,114,36,228,36, +228,234,210,240,191,226,134,80,207,80,196,180,144,180,144,120,196,120,197,179, +30,42,63,80,22,206,71,126,78,54,239,54,154,10,92,132,102,130,225,130, +164,88,164,224,140,244,125,226,122,160,77,218,190,166,235,219,34,18,71,50, +20,82,59,110,28,232,59,144,94,240,94,28,220,28,220,220,202,236,181,218, +114,74,201,74,184,174,128,174,128,116,186,116,187,173,78,30,42,38,42,144, +75,128,134,10,121,44,158,136,98,136,98,46,158,46,159,136,100,90,157,90, +178,38,218,38,218,136,181,136,104,152,96,184,88,200,72,216,52,228,21,238, +156,152,156,220,158,226,164,228,170,230,204,230,216,228,224,222,230,210,235,201, +64,8,64,226,44,240,29,222,14,66,107,66,16,156,101,116,136,40,171,80, +120,102,161,140,98,176,243,160,202,8,203,245,68,36,127,70,54,84,113,118, +14,164,243,152,172,14,173,247,30,246,30,32,82,32,60,98,74,116,82,134, +86,150,86,166,76,176,66,184,49,172,104,56,223,56,160,10,161,100,88,104, +235,104,162,106,163,208,162,154,223,154,120,140,114,176,106,200,96,214,79,236, +114,174,124,190,136,204,156,216,180,224,208,226,239,225,24,34,227,34,192,142, +58,142,58,76,194,76,195,140,76,160,107,206,174,156,143,218,16,224,241,225, +84,26,227,26,208,116,96,116,96,66,208,66,209,114,112,130,135,170,190,128, +163,180,74,186,233,186,26,26,67,64,12,110,56,110,57,200,18,228,50,202, +56,200,64,204,78,212,96,220,118,226,134,228,170,230,208,228,241,227,122,14, +155,36,18,76,47,106,18,156,51,134,22,238,38,218,48,196,56,166,58,142, +58,48,239,48,80,82,229,82,208,164,98,164,98,118,208,118,209,164,110,178, +135,212,196,176,165,226,64,232,243,233,32,46,117,46,78,6,79,90,20,92, +155,92,140,32,114,74,90,102,68,124,46,142,19,162,56,236,56,134,130,134, +131,232,58,176,129,176,56,214,131,214,170,246,170,28,238,28,204,110,218,120, +230,134,238,150,242,164,240,180,232,192,214,204,195,189,76,8,77,68,76,34, +117,34,10,72,141,72,82,74,83,132,48,84,23,122,100,86,125,106,138,30, +214,30,204,56,194,76,176,98,148,116,117,130,148,30,152,48,158,62,164,74, +174,88,188,100,204,110,235,124,56,244,56,146,198,146,199,242,58,170,197,170, +56,198,197,198,56,224,197,225,28,36,223,36,48,64,199,64,126,8,127,94, +12,96,239,96,226,212,56,212,64,122,196,122,192,226,180,242,155,232,12,168, +241,168,104,136,145,156,108,180,145,201,40,40,28,90,17,118,68,12,69,244, +32,76,95,76,26,170,93,134,108,44,241,44,172,8,173,80,104,84,236,84, +223,122,128,102,157,122,112,130,143,150,96,170,249,170,176,102,174,144,168,174, +158,198,138,220,105,240,180,194,237,239,22,24,54,54,66,74,74,108,78,150, +78,182,76,210,70,226,58,236,46,242,31,226,98,20,17,94,72,104,19,172, +224,154,112,154,112,68,224,68,225,154,168,10,169,218,100,228,225,214,202,170, +241,237,32,24,73,60,12,100,58,100,54,234,93,192,92,40,235,40,162,6, +163,80,84,82,226,82,211,114,110,100,147,120,100,130,141,150,82,168,243,168, +170,94,168,142,162,176,150,200,126,222,99,240,178,188,231,235,14,80,87,80, +52,12,53,182,12,200,89,174,104,52,197,52,152,8,153,98,86,100,245,100, +222,30,200,68,170,104,138,130,93,158,120,246,120,140,210,140,211,242,122,180, +209,180,122,218,209,219,26,224,26,34,78,34,79,212,28,86,77,86,26,138, +79,138,26,196,77,196,112,50,189,50,158,12,159,92,96,96,239,96,216,32, +182,84,160,114,134,138,95,164,128,244,128,142,210,142,211,242,130,182,209,182, +130,222,209,223,36,164,36,30,100,30,101,152,70,68,68,124,66,152,58,182, +46,208,21,232,78,184,111,224,126,48,207,48,170,10,171,94,116,98,249,98, +226,30,202,76,178,108,146,142,111,172,144,246,144,140,220,140,221,242,148,182, +217,182,146,222,217,223,14,72,107,72,66,10,67,244,62,84,46,130,32,160, +19,182,68,104,103,142,116,98,237,98,176,12,177,218,102,220,247,221,60,14, +38,62,15,96,42,54,95,54,30,100,91,100,18,144,95,144,58,100,58,220, +89,178,150,12,187,34,78,240,96,218,102,198,110,170,112,146,112,48,243,48, +126,86,237,86,150,60,150,130,208,130,209,60,126,154,218,154,204,176,188,196, +162,218,138,230,113,240,144,156,152,174,162,190,178,206,196,218,218,228,237,235, +16,228,24,214,30,196,34,176,36,154,36,28,94,28,94,220,84,232,72,236, +61,220,40,88,91,88,38,142,93,142,120,98,237,98,178,10,179,216,112,218, +247,219,130,8,159,28,22,228,36,208,46,186,48,164,52,142,52,40,243,40, +68,80,233,80,108,52,108,122,190,122,191,50,78,148,196,148,178,174,156,196, +126,216,96,228,67,238,108,150,116,170,136,190,160,208,186,220,208,228,239,233, +30,28,71,58,20,84,61,112,26,232,57,142,62,238,76,222,82,206,88,190, +92,172,94,156,94,48,237,48,102,92,241,92,140,62,140,126,198,126,199,62, +144,12,171,38,114,156,206,156,194,176,182,190,168,206,150,216,132,226,109,236, +136,158,148,178,162,196,178,210,200,222,233,235,16,76,96,74,92,120,84,154, +70,182,46,210,21,228,62,12,52,94,38,148,64,164,105,198,156,14,191,46, +224,156,224,62,136,62,136,140,132,174,122,202,112,224,97,242,138,136,223,137, +62,8,40,62,23,96,44,56,111,56,18,120,117,120,70,56,70,124,66,154, +58,182,40,210,19,230,68,154,113,198,116,34,243,34,220,140,132,140,132,74, +222,74,223,140,134,162,159,206,212,160,183,222,100,228,245,229,62,14,38,60, +17,88,42,54,93,54,28,98,85,98,16,146,93,146,54,98,54,226,85,188, +152,16,112,34,113,244,96,188,151,166,114,76,149,76,114,124,147,124,154,102, +166,90,174,76,178,60,178,30,216,30,216,78,218,92,222,96,230,96,245,96, +156,126,226,126,212,164,196,190,174,216,145,236,166,126,176,158,184,178,200,202, +218,222,241,239,104,14,38,34,39,244,40,80,99,80,38,132,99,132,14,202, +109,176,112,102,122,96,132,86,136,74,140,58,140,26,198,26,198,80,198,86, +204,92,212,96,237,96,112,128,210,128,188,168,172,188,140,216,99,236,132,130, +144,152,156,174,170,190,188,206,208,220,237,233,54,36,73,78,128,36,111,78, +48,98,139,98,92,8,93,194,86,108,68,142,47,172,94,114,127,148,32,30, +32,210,125,210,230,16,204,24,176,30,154,34,154,136,150,172,142,202,134,220, +123,236,156,98,245,98,206,100,207,239,44,28,71,62,18,80,95,80,28,116, +45,176,84,110,61,196,12,212,93,194,168,10,169,70,116,26,116,74,220,74, +221,30,100,110,243,110,166,110,155,144,112,244,112,150,224,150,224,218,222,232, +212,240,193,228,148,152,149,220,184,150,185,221,62,14,12,100,63,94,88,60, +20,162,87,150,20,216,83,198,150,16,106,32,107,244,108,78,147,78,108,126, +147,126,88,204,155,172,148,104,158,92,164,80,168,68,170,56,170,28,208,28, +208,76,210,84,212,88,218,92,241,92,154,124,222,124,210,158,200,184,186,202, +166,220,143,236,170,124,176,148,182,166,190,182,202,198,218,216,241,231,18,84, +97,84,58,18,59,188,16,206,99,178,148,14,122,74,93,120,126,68,127,244, +172,16,207,50,134,70,241,70,134,118,233,118,134,166,233,166,134,216,245,216, +184,70,185,215,60,18,109,58,192,14,159,60,190,144,64,144,64,66,192,66, +193,142,104,146,104,166,100,180,92,202,78,214,31,240,154,144,154,208,156,216, +158,222,164,228,200,230,212,228,224,220,230,210,235,197,34,242,34,28,104,28, +70,98,84,112,94,126,102,140,104,156,98,166,88,178,70,188,55,174,166,12, +166,82,160,114,150,146,136,174,122,194,102,214,81,234,166,90,172,118,180,142, +188,158,196,176,206,192,218,208,237,227,24,50,104,50,100,78,94,108,84,138, +70,164,48,194,21,218,36,82,92,162,119,204,118,78,245,78,200,14,200,226, +182,240,163,222,136,114,165,167,8,86,73,86,44,18,45,176,10,192,81,172, +104,16,133,44,70,56,167,56,146,118,90,118,90,86,146,86,147,118,74,146, +146,146,120,172,120,220,116,234,108,244,89,228,76,206,159,178,196,12,180,68, +161,108,180,68,245,68,218,70,212,124,206,162,190,190,172,216,143,240,176,104, +184,146,198,182,218,212,243,237,30,206,30,40,74,40,75,196,30,172,73,172, +94,54,237,54,114,86,114,154,210,154,211,84,160,8,160,216,162,222,166,226, +172,230,176,232,212,232,222,228,226,224,237,205,92,92,92,28,30,28,30,94, +93,94,62,94,63,204,62,138,99,138,32,128,33,214,14,222,97,200,130,12, +155,34,204,12,185,40,104,46,243,46,220,156,120,158,120,72,220,72,221,156, +154,48,154,78,150,92,135,112,184,46,184,94,186,100,188,104,194,106,204,106, +219,102,122,130,219,130,100,184,249,184,204,160,204,224,200,232,194,242,167,230, +128,200,153,223,56,16,85,38,13,50,10,50,137,50,106,110,36,110,36,78, +108,78,109,108,24,136,104,136,74,164,74,220,72,230,60,238,41,226,16,194, +127,176,166,12,148,78,127,122,148,78,241,78,206,80,202,120,196,146,182,176, +164,198,138,220,107,238,148,114,158,146,168,166,188,192,208,212,237,235,12,50, +117,50,28,80,28,146,100,146,101,80,64,8,64,224,105,186,120,26,235,26, +178,28,165,72,140,186,140,78,216,78,217,182,176,100,176,150,172,172,160,198, +144,218,113,238,186,194,243,235,40,238,40,26,218,26,219,236,40,212,217,212, +60,74,197,74,78,94,78,140,174,140,175,94,124,42,124,168,124,172,126,176, +130,180,134,182,136,184,170,184,178,182,182,180,186,176,195,157,60,8,38,60, +19,92,40,56,103,56,28,102,99,102,18,144,101,144,60,102,60,226,109,182, +112,56,239,56,126,88,126,154,216,154,217,86,170,6,170,212,170,218,172,222, +176,224,178,226,180,230,218,230,222,228,228,224,230,222,239,201,224,16,184,26, +142,30,90,32,48,32,48,130,44,160,40,174,30,198,21,216,64,72,243,72, +152,38,139,106,88,244,88,112,208,112,209,238,90,148,207,148,90,180,207,180, +88,218,207,219,224,22,174,32,126,34,94,34,94,110,90,148,84,166,77,188, +94,72,239,72,172,44,161,96,212,200,126,200,126,104,212,104,213,200,128,136, +211,136,126,166,211,166,34,26,73,70,12,110,54,110,55,204,20,234,38,216, +48,206,54,202,62,204,72,210,88,218,110,226,140,230,174,232,239,231,58,8, +58,222,52,230,42,238,32,242,25,226,16,70,91,70,14,160,83,124,90,30, +144,30,138,54,132,72,120,90,99,116,102,54,151,102,160,30,216,30,206,62, +192,90,161,116,172,56,223,106,90,134,142,134,132,178,112,208,83,238,94,158, +149,204,146,240,168,224,184,206,200,180,210,150,212,134,159,134,164,134,170,156, +180,174,188,190,202,206,237,237,28,190,28,36,80,36,81,186,28,164,81,164, +164,10,136,50,103,74,144,38,210,38,198,62,180,84,156,108,132,124,109,134, +144,68,169,92,194,108,172,138,148,160,132,170,109,182,174,134,236,134,220,168, +200,190,174,214,136,230,93,238,160,174,185,203,124,12,92,50,76,66,49,84, +100,40,210,40,178,74,158,92,130,106,92,122,35,136,108,66,135,98,142,112, +106,154,86,170,51,192,118,142,220,142,204,168,184,188,148,214,100,232,35,240, +118,172,153,209,28,52,231,52,130,12,108,68,82,96,54,112,25,126,146,52, +158,70,176,88,200,104,235,118,26,150,237,150,172,110,172,224,150,242,127,226, +74,172,115,199,18,76,95,76,58,12,59,172,18,194,93,162,96,112,114,98, +124,80,126,56,126,26,192,26,192,96,194,102,210,106,235,92,96,140,233,140, +160,98,161,242,152,142,132,174,104,204,79,222,166,142,180,166,198,190,235,219, +68,10,57,40,36,146,36,44,94,44,94,228,82,240,63,226,38,78,93,78, +36,114,93,114,10,152,93,152,80,152,66,180,44,202,19,222,118,116,134,100, +142,80,144,68,144,30,200,30,200,102,228,102,237,98,112,144,241,144,174,100, +175,240,170,148,150,180,115,220,176,148,198,180,210,196,239,219,32,114,56,110, +74,96,84,76,88,64,88,24,170,24,170,92,174,96,180,102,225,106,16,148, +239,148,128,108,129,244,126,148,94,180,54,208,21,224,130,148,148,170,168,188, +194,204,237,223,96,90,96,26,34,26,34,92,95,92,68,94,69,198,70,134, +97,134,34,120,35,208,14,220,101,188,108,110,120,102,130,90,134,72,136,58, +136,28,194,28,194,88,196,100,204,104,214,104,237,102,104,142,239,142,164,100, +165,246,158,146,134,184,114,206,89,224,168,144,182,170,200,194,218,210,237,221, +76,12,67,44,18,238,28,226,34,208,42,180,44,168,44,50,102,50,102,230, +76,244,69,224,16,134,105,134,62,76,79,112,66,154,81,186,164,14,189,44, +132,96,132,54,232,54,233,94,224,126,161,164,156,100,156,212,160,220,164,226, +172,228,176,230,218,230,226,224,232,218,239,199,34,106,50,92,56,76,62,60, +62,26,120,26,120,80,122,88,130,90,151,90,22,138,151,138,88,90,89,242, +84,144,68,168,50,190,25,212,90,144,143,200,176,40,177,178,222,12,222,224, +192,238,181,221,64,14,65,248,36,64,21,122,80,62,97,94,98,44,239,44, +160,12,132,78,93,122,138,74,223,74,178,74,179,102,118,108,243,108,128,244, +128,134,218,134,218,226,206,242,185,230,130,164,217,164,130,194,217,195,40,170, +40,32,96,32,66,82,80,98,84,108,88,120,82,130,72,138,64,142,57,126, +102,50,237,50,160,16,126,70,97,100,126,162,126,80,212,80,212,158,202,166, +181,158,128,106,211,106,128,134,209,134,48,192,207,192,132,168,133,226,16,226, +235,227,88,140,28,140,28,74,88,74,89,138,58,16,59,194,14,210,93,188, +86,166,105,204,156,30,101,46,102,96,233,96,136,38,136,232,118,244,107,228, +104,166,165,138,178,12,178,108,180,140,188,184,200,208,212,226,222,236,228,236, +239,202,202,36,227,68,220,118,208,152,194,180,178,200,159,221,56,10,57,186, +26,66,26,192,85,182,86,62,87,210,154,20,126,34,99,42,98,88,237,88, +134,32,134,228,116,242,105,224,102,164,161,138,200,32,225,66,180,10,178,92, +180,124,184,150,188,178,202,212,220,236,224,240,234,228,243,208,222,122,190,188, +159,225,70,30,42,40,21,44,16,94,131,94,50,38,50,220,36,232,21,218, +20,160,73,130,110,36,129,68,90,10,90,102,92,140,96,162,102,192,110,212, +120,226,126,226,139,202,122,124,94,176,71,202,180,8,167,38,168,60,195,82, +182,108,202,106,214,98,218,84,220,42,148,42,148,142,234,142,228,204,218,224, +206,230,192,238,177,224,124,182,209,183,74,12,44,80,17,120,50,68,51,246, +152,32,116,46,89,50,72,96,245,96,202,32,231,68,120,46,120,220,112,232, +100,238,85,220,76,176,157,140,174,10,174,112,176,134,180,156,186,180,194,198, +204,218,216,232,224,236,232,238,238,228,243,210,224,118,198,170,176,198,145,225, +62,8,85,34,26,72,26,44,124,44,125,72,68,56,46,90,23,118,52,80, +110,80,96,102,82,120,54,144,19,166,56,108,127,160,46,236,46,168,104,168, +105,232,48,216,103,216,130,28,243,28,184,28,173,68,144,188,144,72,222,72, +223,188,184,94,184,148,176,182,164,208,142,228,121,242,192,198,239,239,40,28, +75,64,14,100,56,100,52,226,95,184,140,22,110,94,87,130,124,68,125,244, +232,72,194,114,168,138,143,154,180,18,180,216,180,224,184,230,188,232,216,232, +224,230,228,224,235,203,60,14,50,86,36,158,95,206,16,82,86,82,84,122, +72,164,52,200,21,230,158,26,103,44,102,94,241,94,134,34,134,224,118,236, +105,222,96,170,165,138,206,34,229,64,182,10,182,94,184,138,188,170,200,202, +216,226,226,234,232,232,239,206,222,120,196,180,157,223,28,30,223,30,20,134, +235,134,102,32,103,130,150,32,151,132,46,62,79,106,206,58,175,108,52,174, +19,228,118,156,153,188,198,168,241,216,88,166,88,216,88,224,90,228,94,232, +162,232,174,230,180,224,189,207,20,232,36,210,48,178,50,148,50,32,231,32, +144,164,158,164,176,162,188,156,194,148,196,142,200,86,100,86,100,208,102,216, +104,220,108,226,114,228,120,230,206,230,218,226,224,216,237,197,18,74,95,74, +16,162,89,124,60,16,60,226,50,238,27,226,80,236,94,216,104,190,110,158, +112,142,112,38,237,38,180,158,190,158,202,158,210,154,212,146,212,86,152,86, +152,214,154,218,156,226,162,230,188,232,210,230,224,226,230,216,235,205,30,28, +71,68,198,92,106,92,106,26,200,26,201,90,108,60,199,60,126,98,79,138, +100,120,218,120,214,192,208,204,194,210,185,198,158,122,144,148,121,168,148,140, +189,164,102,136,102,188,179,188,14,112,56,112,57,200,18,230,34,216,48,206, +52,202,60,202,70,210,82,218,104,226,126,230,144,230,241,229,66,64,66,26, +30,26,30,64,67,64,128,62,92,62,92,26,128,26,129,62,32,96,131,96, +14,128,147,128,64,130,56,162,120,162,116,202,110,210,98,218,88,220,67,222, +166,238,166,24,228,24,190,100,210,118,224,134,232,150,234,162,234,170,226,182, +200,194,185,183,56,20,34,70,15,110,38,66,88,66,75,100,52,108,52,232, +93,198,158,26,130,38,103,42,206,34,229,66,94,96,239,96,134,38,134,232, +118,240,105,226,94,174,167,138,184,12,182,96,184,128,190,170,206,204,220,228, +228,236,234,236,245,204,228,122,194,184,161,219,202,136,50,136,50,28,204,28, +205,134,68,68,185,68,128,42,118,80,106,98,92,112,75,122,118,82,177,114, +52,172,23,224,120,154,159,186,198,170,241,216,88,162,88,214,90,222,94,226, +102,230,136,232,164,228,178,224,184,216,189,201,16,30,239,30,120,30,93,90, +44,232,44,96,212,96,212,204,204,226,179,216,102,98,103,218,156,96,157,217, +92,20,92,132,88,162,76,190,62,208,46,220,21,236,162,18,162,204,164,214, +166,218,174,224,188,226,208,226,222,222,230,216,236,206,239,191,18,30,233,30, +20,190,239,176,72,30,73,186,178,32,179,240,74,84,177,84,74,132,177,133, +96,12,70,66,33,104,74,58,222,58,203,104,136,90,136,228,120,240,93,224, +88,124,62,176,35,208,178,134,229,199,62,18,44,66,19,104,44,66,96,66, +85,96,56,106,56,234,91,192,102,38,241,38,100,200,245,184,134,38,135,194, +208,38,209,244,138,90,205,90,138,140,205,141,32,18,71,50,16,82,59,110, +26,234,65,142,80,34,235,34,68,196,243,182,110,38,111,188,196,36,197,242, +112,84,195,84,110,136,195,137,40,52,217,52,20,200,237,201,12,54,231,54, +168,8,164,76,168,106,174,142,180,172,192,202,204,220,216,232,224,230,237,202, +190,14,211,38,42,82,135,82,30,110,147,110,46,202,46,138,136,138,137,200, +90,156,88,174,84,194,74,208,56,224,38,232,19,238,100,202,155,237,66,24, +28,82,237,82,120,12,110,76,94,128,70,166,23,210,160,20,203,58,96,124, +190,124,172,160,146,190,106,214,51,236,108,144,126,172,154,200,194,218,235,231, +210,78,48,78,48,28,210,28,211,76,100,28,101,76,156,28,157,76,52,98, +89,124,18,146,66,146,64,228,115,176,154,108,155,196,214,94,214,210,210,222, +204,226,194,230,169,223,68,12,44,48,19,78,50,40,127,40,76,40,97,72, +166,10,150,40,127,68,150,40,239,40,178,40,201,72,80,80,50,122,19,152, +58,110,59,244,82,142,235,118,168,80,205,102,136,82,142,136,150,162,168,196, +192,222,214,236,222,236,226,228,233,204,208,146,172,194,150,212,107,237,78,14, +52,68,17,118,54,62,55,246,80,100,233,76,140,10,138,48,142,100,148,138, +158,176,174,202,192,224,218,240,224,238,239,210,214,110,184,146,160,172,126,194, +87,210,174,24,213,51,210,24,158,36,112,44,72,46,33,48,102,62,141,98, +36,116,186,116,77,196,26,230,36,216,46,206,62,200,74,198,90,210,102,218, +120,224,148,228,186,230,233,231,48,14,77,52,42,62,43,240,108,36,218,36, +218,216,216,226,208,230,183,232,100,58,80,104,59,138,84,96,85,220,100,112, +199,104,134,54,134,108,140,138,150,168,162,188,182,208,188,208,201,184,160,62, +181,88,180,122,158,164,138,184,113,203,38,28,79,62,22,90,61,120,24,236, +73,156,92,66,225,66,78,128,241,128,156,14,157,126,154,138,92,232,207,216, +178,164,225,235,20,44,101,44,26,118,93,118,62,44,63,200,20,216,101,190, +110,64,229,64,164,12,165,126,100,126,241,126,168,136,108,232,215,218,186,172, +233,239,16,40,237,40,98,8,99,68,162,8,163,68,36,80,71,100,18,116, +53,138,20,234,55,162,214,72,146,82,87,86,68,122,237,122,108,96,123,118, +198,92,179,120,136,124,106,154,77,172,162,124,198,152,237,168,150,82,151,156, +96,246,96,170,202,170,203,244,96,230,201,230,96,200,201,200,148,172,149,229, +20,192,20,62,92,62,92,172,78,186,73,172,56,14,57,248,88,236,110,212, +124,180,128,144,128,34,196,34,196,216,196,222,198,226,202,230,214,230,226,228, +232,224,241,198,144,104,177,143,216,18,146,32,45,38,24,80,239,80,130,36, +131,126,66,52,97,76,200,42,173,78,116,84,74,118,25,142,142,82,178,112, +235,138,66,242,66,142,198,142,199,238,68,180,197,180,132,144,133,218,66,218, +197,219,110,24,66,32,23,38,12,88,119,88,74,32,75,134,36,52,53,74, +108,48,93,74,66,94,40,126,17,146,88,104,125,138,38,244,38,150,108,150, +109,242,40,186,107,186,74,150,75,220,38,224,107,224,124,34,166,34,166,224, +154,238,129,224,130,82,147,118,124,176,163,138,182,34,228,34,228,224,216,238, +191,224,186,80,207,116,182,176,225,133,22,58,101,58,66,14,67,146,62,62, +40,104,25,122,68,78,93,104,150,20,122,60,99,82,106,30,153,74,146,88, +118,122,97,140,112,94,153,134,160,56,231,56,194,12,195,144,190,62,172,96, +157,116,196,70,227,106,24,166,235,166,130,140,120,184,102,210,68,230,31,240, +136,166,148,188,166,206,202,226,231,239,14,38,109,38,62,38,50,84,17,132, +40,208,40,104,90,104,91,200,40,178,89,178,80,240,102,224,116,200,124,178, +126,160,128,144,128,32,202,32,202,220,204,228,208,232,218,232,226,232,232,228, +236,214,241,188,146,102,185,143,62,12,34,60,17,88,38,56,107,56,24,100, +101,100,12,146,109,146,56,100,56,226,97,196,90,242,110,222,122,188,126,160, +126,144,126,36,200,36,200,220,200,226,204,232,208,236,216,238,226,236,234,230, +236,226,243,208,144,108,183,147,66,16,46,46,23,72,50,40,145,40,16,92, +153,92,122,132,128,66,54,66,46,120,135,120,80,72,95,84,76,98,95,114, +178,12,162,48,143,74,164,44,235,44,210,44,202,72,194,92,178,108,145,126, +162,68,180,94,196,108,235,126,102,128,52,158,127,154,172,130,84,182,54,192, +187,178,170,160,207,196,128,184,128,230,120,240,95,226,80,198,58,220,33,236, +162,202,217,235,16,238,40,218,54,198,66,172,70,142,70,126,70,36,174,36, +174,216,176,224,180,228,184,230,190,230,218,230,228,224,234,212,241,180,96,98, +153,149,64,10,64,116,62,146,56,174,44,202,19,230,60,156,101,196,34,68, +28,100,21,130,102,62,69,100,106,30,241,30,168,30,161,72,128,190,128,80, +216,80,217,190,172,102,170,152,166,178,154,200,132,222,101,238,182,194,237,233, +214,24,60,38,60,132,52,174,40,206,25,234,68,100,196,100,188,122,174,146, +150,176,118,206,61,232,84,102,96,120,116,146,136,170,170,196,200,212,237,225, +222,26,164,34,110,36,110,92,108,124,102,156,85,186,114,84,206,84,196,122, +180,152,156,174,119,198,130,114,180,150,231,194,34,18,75,58,12,104,56,104, +57,204,24,232,44,212,50,204,60,206,80,216,106,226,148,230,237,227,18,48, +241,48,98,12,99,82,166,10,167,84,38,94,83,120,18,132,63,158,28,238, +91,180,168,176,184,174,196,172,204,162,206,106,124,106,124,212,126,218,130,226, +134,230,138,232,210,232,220,228,226,222,230,212,235,201,30,168,30,26,96,26, +97,164,62,60,62,126,58,162,52,184,42,202,28,216,15,226,70,180,93,206, +222,16,130,32,132,74,132,104,130,142,124,172,112,200,91,232,136,94,216,94, +212,116,206,140,188,180,162,212,127,240,144,94,154,126,164,152,178,178,200,204, +239,231,94,16,58,66,21,100,24,22,60,54,78,88,88,132,90,178,84,206, +74,224,60,232,33,232,80,106,21,172,168,142,190,144,210,136,216,118,216,94, +216,32,134,32,134,210,134,216,136,222,142,226,146,226,216,226,228,222,232,216, +241,195,58,12,36,70,19,104,42,60,98,60,85,94,52,92,52,222,87,182, +220,26,176,38,126,40,126,130,120,166,110,202,83,234,130,98,220,98,212,132, +200,164,178,198,154,222,123,240,142,98,152,128,162,154,172,176,190,200,216,222, +237,237,34,24,75,54,18,84,59,116,26,236,61,150,222,24,152,36,87,38, +140,56,169,90,86,108,204,108,113,196,66,228,80,212,92,202,102,196,112,196, +124,210,138,218,150,222,196,230,241,229,18,96,103,96,64,16,65,182,18,204, +107,176,150,12,193,52,98,68,245,68,156,68,156,102,152,142,140,180,122,206, +85,238,154,126,222,126,222,160,218,202,214,220,206,228,192,232,179,235,20,50, +235,50,92,12,93,82,172,10,173,82,120,74,149,100,16,112,241,112,102,112, +102,146,94,174,82,198,66,218,35,238,100,154,194,154,190,196,186,220,174,232, +145,225,112,12,151,42,20,62,241,62,104,64,104,100,100,138,90,176,66,206, +27,234,104,112,200,112,190,206,186,218,176,224,151,231,16,236,32,200,38,162, +40,118,40,30,94,30,94,220,86,230,74,234,59,220,42,88,93,88,40,144, +93,144,156,12,197,50,110,66,245,66,160,66,160,104,158,150,148,190,134,216, +113,242,160,120,226,120,222,204,218,224,204,236,175,223,112,14,155,40,18,234, +32,214,42,188,46,164,50,142,50,122,50,50,218,50,218,86,55,86,134,102, +173,124,64,136,247,136,128,136,126,164,122,192,102,218,73,240,126,172,210,172, +208,208,204,226,196,236,174,244,161,227,30,246,30,24,86,24,76,56,62,94, +76,112,84,130,88,148,88,164,82,176,66,186,60,188,51,174,150,10,185,48, +94,66,241,66,144,66,142,112,140,144,134,170,122,190,106,212,81,234,142,120, +216,120,212,212,208,222,198,230,186,236,167,223,66,12,38,154,111,204,14,78, +100,76,92,132,82,168,62,200,38,220,23,232,152,14,189,54,114,70,245,70, +156,70,154,140,146,182,132,214,105,244,156,122,218,122,214,216,210,226,202,236, +198,240,169,223,88,16,54,76,19,118,58,72,59,246,144,14,179,58,84,72, +247,72,148,74,146,130,142,160,132,186,116,210,85,240,146,130,222,130,216,214, +210,228,194,242,171,225,32,22,75,58,12,102,58,102,54,222,99,168,146,14, +181,48,92,70,245,70,146,72,146,122,138,158,126,192,110,216,89,242,146,126, +218,126,212,210,210,224,182,242,165,227,72,16,24,100,73,90,98,70,24,164, +109,148,18,212,109,194,154,12,189,52,110,66,241,66,152,66,148,144,138,182, +122,210,93,238,150,120,218,120,208,218,178,240,167,219,56,12,89,48,12,70, +125,70,58,72,58,124,56,152,50,182,36,210,19,232,58,116,108,116,104,204, +90,224,63,210,168,8,144,70,125,104,146,68,241,68,202,68,200,120,188,164, +160,204,111,238,144,112,160,156,172,174,190,196,212,218,237,233,26,46,243,46, +98,10,99,72,168,10,169,72,110,78,111,242,158,78,159,242,34,106,109,106, +40,148,107,148,26,194,107,194,160,108,233,108,158,146,223,146,158,196,243,197, +100,14,101,242,148,12,149,242,24,64,99,64,34,118,99,118,18,184,99,184, +148,62,227,62,148,116,221,116,148,184,235,185,32,196,32,44,74,44,75,184, +34,162,73,162,140,12,141,244,184,10,185,244,90,64,139,64,94,118,139,118, +88,178,139,178,186,62,235,62,186,118,231,118,184,178,243,179,8,34,154,34, +152,108,158,156,168,188,184,210,202,222,220,226,228,224,234,216,241,194,212,54, +160,114,225,159,16,236,30,210,36,182,38,146,38,32,92,32,92,226,74,238, +61,222,40,90,91,90,38,148,91,148,134,126,224,126,224,30,130,30,130,210, +132,220,136,226,142,230,154,230,216,230,226,226,232,216,241,190,178,30,179,125, +226,26,36,26,36,228,237,228,118,42,119,212,162,40,163,212,56,78,117,78, +66,122,117,122,54,168,117,168,162,78,225,78,162,122,217,122,162,168,229,169, +36,28,71,64,12,102,56,102,50,224,85,170,138,14,139,242,182,12,183,242, +86,64,137,64,92,120,137,120,96,178,137,178,184,62,241,62,182,120,231,120, +182,178,247,179,28,198,28,46,82,46,83,186,28,164,81,164,100,92,237,92, +160,12,160,92,154,134,142,166,128,192,106,218,77,238,160,108,174,150,184,172, +200,196,218,216,239,232,192,32,223,65,20,236,30,208,36,160,36,144,36,28, +84,28,84,226,70,238,55,222,36,88,83,88,36,148,83,148,104,60,245,60, +168,10,169,240,122,204,122,100,220,100,220,184,204,198,191,185,118,12,153,38, +16,234,30,216,38,190,44,168,44,52,237,52,132,64,124,116,110,158,92,186, +72,208,55,222,94,66,76,108,227,108,172,66,203,90,118,142,194,142,180,172, +158,200,126,222,87,240,120,146,134,168,152,188,180,208,239,233,36,26,81,54, +18,88,61,116,26,230,71,152,92,52,220,52,220,98,98,98,94,148,232,148, +232,172,230,194,214,208,201,192,138,10,138,160,132,184,120,210,102,228,83,238, +180,6,181,245,36,36,204,36,204,64,46,64,46,92,224,92,224,102,220,114, +202,124,189,112,104,6,104,74,100,98,90,112,70,126,52,136,23,142,154,8, +155,126,66,206,66,138,198,138,199,202,132,156,124,186,108,210,78,226,33,240, +140,198,225,237,22,52,235,52,98,12,99,76,158,12,159,78,102,90,62,132, +23,160,152,88,172,114,194,134,218,148,237,156,62,140,182,140,182,184,176,220, +160,238,131,224,110,140,106,168,98,188,86,206,66,224,41,237,12,30,125,30, +32,232,32,74,108,74,109,222,58,32,58,82,58,100,54,112,50,126,45,136, +84,30,84,130,105,130,34,168,105,168,32,206,107,206,162,20,140,80,123,112, +188,10,200,56,216,86,237,110,140,112,210,112,210,170,208,206,202,232,175,222, +166,112,164,152,156,184,142,210,115,239,32,194,32,46,80,46,81,188,34,164, +79,164,148,18,126,76,112,100,97,120,178,14,186,40,196,64,206,82,235,114, +118,112,204,112,200,216,188,232,163,220,146,112,146,140,144,160,136,182,124,204, +106,218,81,235,76,18,56,50,38,72,19,90,60,46,231,46,60,74,213,74, +36,100,198,100,196,140,196,170,200,204,208,224,216,232,224,236,232,234,236,224, +239,202,84,114,54,148,27,172,124,114,144,142,162,160,181,172,54,166,148,166, +144,226,130,240,109,226,88,166,86,182,80,198,70,212,54,226,29,239,96,20, +74,66,52,98,17,128,148,10,156,34,168,58,182,78,200,96,235,124,60,112, +182,112,178,190,176,208,166,222,136,236,127,218,106,112,104,140,98,168,84,196, +66,220,37,237,66,18,24,106,71,94,96,54,32,176,99,152,24,220,103,196, +148,22,138,56,126,86,114,110,101,126,184,18,192,46,202,70,218,90,245,120, +126,110,210,110,210,188,208,222,196,240,169,224,154,110,154,140,148,166,140,190, +126,214,95,243,12,90,95,90,58,12,59,182,16,204,103,168,136,16,175,56, +92,74,235,74,196,76,186,126,170,164,138,202,73,240,116,76,128,114,144,154, +174,194,233,237,20,54,119,54,76,12,77,136,74,56,54,90,21,120,78,68, +117,94,134,54,233,54,178,12,179,136,174,56,156,86,136,106,121,120,180,68, +231,110,80,146,59,194,200,142,177,184,132,134,124,168,114,192,98,210,72,228, +48,238,27,242,130,152,144,184,158,202,174,216,198,228,220,232,241,235,40,32, +75,64,12,94,53,122,30,238,71,146,130,24,108,80,92,104,77,126,168,16, +176,44,188,70,204,94,224,112,241,124,104,118,198,118,194,224,176,240,155,222, +134,118,132,152,126,184,112,208,100,222,79,239,24,32,45,72,108,30,91,72, +12,94,105,94,66,10,67,246,64,98,52,134,36,160,19,184,66,114,105,160, +158,20,142,62,130,88,105,118,182,12,188,38,196,56,204,70,216,88,241,116, +126,114,210,114,204,220,190,238,167,222,156,114,156,138,152,166,140,198,124,220, +103,235,26,58,231,58,130,10,114,58,98,82,80,104,52,124,17,142,144,58, +154,76,166,92,180,104,198,116,222,128,243,134,62,248,62,128,196,128,197,246, +62,178,195,178,64,230,195,230,126,130,127,229,74,14,48,78,17,130,54,64, +55,244,134,18,108,80,77,126,172,14,182,46,194,72,210,94,241,120,108,110, +202,110,196,218,180,238,159,220,136,112,136,142,130,174,122,196,106,216,85,235, +94,20,62,60,21,94,158,20,182,56,204,72,237,92,66,74,184,74,178,130, +172,138,158,144,143,130,114,74,110,100,98,120,80,136,57,146,56,172,27,228, +116,154,147,188,200,168,233,220,88,172,88,210,90,218,94,224,100,228,148,228, +164,226,176,218,178,210,183,201,56,8,57,244,32,60,21,116,76,58,93,100, +98,38,231,38,160,6,161,60,92,80,243,80,124,52,125,108,200,52,201,106, +108,198,108,120,216,120,217,192,162,142,158,176,152,196,136,214,116,226,95,236, +168,198,235,235,56,20,97,50,192,16,159,52,24,62,223,62,128,10,129,114, +114,64,90,88,66,104,31,120,144,62,154,76,172,88,188,98,225,114,42,140, +213,140,96,110,97,174,160,112,161,174,18,180,239,180,102,196,68,222,43,238, +158,196,221,233,32,62,223,62,46,116,213,116,16,168,241,168,126,10,127,247, +24,62,127,62,14,110,141,110,80,14,81,108,26,156,133,156,20,224,143,196, +80,122,81,206,138,84,241,84,198,8,198,222,182,238,157,224,142,128,173,167, +12,74,93,74,56,10,57,244,52,78,38,124,17,164,58,96,91,130,76,234, +94,204,102,176,108,138,108,116,108,30,206,30,204,96,204,140,206,182,210,208, +218,224,222,230,226,232,230,230,232,226,241,204,178,64,162,110,142,152,121,190, +122,78,189,177,92,136,26,136,26,66,92,66,93,134,58,10,59,194,14,208, +95,186,88,164,103,204,152,10,134,44,111,70,138,38,208,38,186,64,156,92, +134,102,109,114,144,56,170,80,190,92,214,100,241,108,116,134,225,134,122,166, +217,166,114,200,239,200,172,102,173,247,54,16,55,190,20,68,20,196,83,188, +84,68,85,216,156,10,132,46,111,68,140,36,210,36,192,56,168,80,138,100, +101,114,130,48,148,66,172,84,194,98,237,110,112,130,219,130,120,164,209,164, +102,198,229,198,162,102,163,245,68,14,44,58,19,88,46,56,101,56,28,100, +93,100,16,152,101,152,58,100,58,236,93,194,152,12,130,48,113,72,136,40, +208,40,182,72,150,96,128,110,103,116,140,62,162,78,184,94,212,104,239,112, +110,136,223,136,116,170,217,170,102,204,239,204,168,106,169,245,18,230,38,204, +48,178,56,140,56,116,56,30,196,30,196,72,194,102,196,140,200,174,206,198, +210,214,216,222,222,226,228,228,232,226,238,220,240,212,241,196,160,62,136,112, +116,144,92,170,67,194,78,76,134,130,156,156,181,183,118,10,149,34,16,236, +32,220,44,200,52,172,56,140,56,46,233,46,16,68,41,102,14,148,51,130, +58,244,74,228,84,208,92,178,92,158,92,80,202,80,198,112,198,146,200,178, +208,208,216,224,222,234,228,236,232,234,236,228,241,212,176,104,148,156,105,208, +112,114,150,156,185,205,60,12,60,118,58,148,50,184,36,214,19,236,32,66, +21,126,96,60,69,100,58,158,95,190,150,10,115,64,132,38,208,38,190,60, +156,90,128,106,91,118,138,58,166,84,190,98,216,110,239,116,106,134,223,134, +112,168,217,168,96,204,239,204,162,102,163,247,26,34,69,68,14,114,58,114, +59,206,24,232,54,214,62,212,74,216,94,224,116,230,154,232,208,232,241,228, +138,14,99,68,120,40,204,40,158,80,118,98,81,110,126,64,154,80,180,92, +212,100,237,104,98,126,213,126,104,154,207,154,88,186,227,186,154,104,155,217, +28,40,71,76,24,204,75,128,84,32,198,32,187,130,118,56,112,134,224,134, +216,206,210,216,202,224,182,230,155,234,76,178,195,179,58,20,16,110,55,104, +80,66,22,168,85,156,14,224,87,202,84,28,115,60,164,14,123,76,144,44, +210,44,194,70,162,94,125,112,154,62,174,82,190,92,220,104,239,110,78,112, +110,112,111,212,78,234,98,216,104,212,114,212,124,220,136,226,158,232,196,234, +239,230,136,126,225,126,140,156,219,156,132,188,231,188,178,100,179,219,28,26, +67,62,8,98,52,98,48,220,83,162,68,240,82,222,92,204,98,184,104,156, +104,132,104,80,102,32,206,32,202,78,200,120,204,162,210,200,222,230,226,234, +228,236,234,234,238,228,243,204,178,68,158,130,140,164,115,194,120,82,187,185, +34,44,221,44,48,78,205,78,24,110,235,110,124,10,120,50,110,88,88,122, +58,154,21,180,164,112,176,130,192,144,212,158,239,172,68,164,191,164,38,204, +221,204,128,128,129,249,16,232,34,212,46,184,52,156,52,120,52,30,200,30, +198,90,200,132,202,170,206,198,212,216,218,228,224,232,230,234,232,232,234,226, +241,202,76,78,168,78,158,108,144,136,122,162,98,184,67,204,86,114,134,150, +158,172,181,197,76,16,48,70,17,116,54,60,55,244,96,52,224,52,224,100, +100,100,96,146,238,146,234,176,228,202,220,210,207,210,140,8,140,160,134,186, +122,210,95,238,184,10,185,245,28,28,233,28,152,30,120,68,84,96,23,126, +130,56,131,134,154,76,243,124,62,244,62,150,202,150,203,244,62,220,201,221, +46,62,213,62,26,126,233,126,126,8,126,132,118,150,106,174,86,200,64,220, +25,240,128,134,142,160,158,182,178,204,204,222,235,237,16,36,145,36,36,142, +36,62,128,62,129,142,104,8,125,22,80,4,81,134,38,88,127,88,38,114, +127,114,64,136,91,148,14,160,145,160,66,160,64,180,56,198,42,218,23,238, +64,184,122,184,112,224,104,232,94,238,79,222,178,10,162,64,145,108,164,62, +239,62,212,64,210,100,204,136,192,168,182,188,160,212,137,234,162,100,172,136, +182,164,196,190,235,233,14,228,26,206,32,176,34,142,34,28,90,28,90,212, +86,224,72,232,57,218,36,84,89,84,36,144,89,144,118,62,231,62,104,120, +243,120,168,6,168,118,162,144,150,182,132,210,101,240,168,126,178,152,190,178, +202,198,216,214,239,235,78,18,28,30,28,168,57,158,38,86,51,116,60,50, +60,164,54,188,44,210,21,236,88,244,88,38,122,38,122,164,120,174,110,184, +97,172,96,92,113,120,232,16,188,28,162,32,139,34,140,54,159,84,172,46, +189,80,228,44,207,84,140,98,220,98,192,126,186,132,186,228,182,234,168,242, +149,226,136,154,245,155,12,76,95,76,58,12,58,230,46,242,25,226,14,162, +83,122,110,66,227,66,100,126,237,126,162,8,162,136,150,166,134,198,112,224, +87,242,166,134,176,162,190,188,214,216,235,235,62,8,62,228,42,244,27,224, +16,72,97,72,16,156,91,120,146,10,146,160,142,184,130,206,114,226,97,240, +188,6,189,244,102,50,224,50,224,100,112,100,108,150,236,150,234,190,230,200, +220,208,207,195,16,54,109,54,66,12,26,124,30,126,105,126,70,76,71,242, +16,190,105,170,110,32,241,32,212,102,134,102,134,64,214,64,215,102,122,242, +122,134,228,134,229,240,124,178,225,178,174,136,175,218,122,222,227,223,26,194, +26,64,96,64,96,176,84,186,79,172,62,10,63,242,112,30,241,30,212,102, +138,102,138,62,212,62,213,100,124,244,124,134,226,134,227,240,126,178,225,178, +176,136,177,218,126,218,225,219,74,12,48,60,21,92,60,40,235,40,66,66, +215,66,46,92,200,92,198,136,198,172,202,196,210,220,218,228,224,234,230,234, +232,228,237,206,32,130,162,130,162,158,48,158,44,186,172,186,170,202,164,218, +154,222,145,224,84,104,78,196,68,212,50,230,35,240,124,104,125,245,68,10, +46,52,23,80,56,36,127,36,74,38,95,72,164,8,127,74,148,36,239,36, +180,36,205,70,84,82,58,126,19,164,66,116,67,246,90,120,243,120,190,80, +190,226,176,242,153,228,108,150,141,179,82,12,54,72,19,120,56,72,57,244, +80,94,241,94,188,26,217,62,154,8,152,104,142,150,130,182,108,212,81,236, +154,102,174,150,196,184,216,208,239,229,72,12,46,70,15,118,52,64,53,248, +218,20,176,32,134,36,87,38,96,62,121,98,142,52,161,92,216,52,191,98, +92,114,214,114,166,146,162,152,162,226,138,242,129,228,76,172,247,173,18,238, +32,204,38,174,40,136,40,28,96,28,96,220,82,236,63,222,42,86,95,86, +40,144,95,144,168,86,196,84,208,76,212,56,214,28,136,28,137,246,152,228, +184,198,202,168,212,142,218,120,150,120,158,140,172,164,184,182,200,200,214,210, +241,227,40,20,81,52,20,78,65,110,28,228,77,144,224,18,188,26,150,30, +114,32,99,34,108,54,127,92,150,46,169,82,218,48,189,94,102,108,212,108, +188,132,166,144,166,230,146,240,127,224,86,166,243,167,36,24,81,54,18,88, +61,112,28,232,71,148,138,12,173,36,90,54,233,54,116,68,143,106,202,68, +175,116,76,122,243,122,106,246,106,162,210,162,211,244,108,222,209,223,40,16, +77,52,16,76,84,76,62,118,19,160,62,120,63,242,64,122,99,154,106,28, +247,28,218,100,134,100,134,60,218,60,219,98,120,242,120,134,232,134,233,240, +120,178,231,178,176,134,177,218,122,218,231,219,40,14,71,48,12,70,78,70, +52,112,17,148,54,110,55,244,56,134,91,168,90,116,71,144,136,12,112,62, +87,100,114,60,115,244,134,94,241,94,180,12,180,102,172,154,156,198,133,234, +180,106,190,146,200,176,216,208,235,230,200,34,231,69,32,54,204,54,204,100, +48,100,46,144,222,144,218,200,192,212,181,196,102,10,102,124,98,164,88,194, +62,222,27,242,154,10,155,245,18,56,243,56,54,246,54,94,208,94,208,224, +194,244,163,228,56,138,207,138,56,180,207,180,174,18,209,38,130,12,131,237, +16,74,99,74,18,158,89,122,60,14,60,232,38,240,27,224,108,40,225,40, +98,116,239,116,152,42,152,118,144,152,124,196,83,238,176,116,176,218,176,224, +180,226,188,230,196,232,206,232,218,230,226,226,230,220,237,201,14,58,105,58, +66,12,26,130,103,130,68,88,69,246,18,202,107,176,198,16,231,42,114,58, +245,58,122,246,122,96,224,96,224,234,208,244,197,228,124,138,223,138,124,180, +223,180,174,12,175,231,70,14,40,82,15,120,50,62,51,244,142,10,175,34, +240,46,94,46,94,156,86,190,69,226,156,58,132,106,107,138,136,100,137,244, +150,114,249,114,160,136,183,178,210,58,210,230,190,240,179,223,104,16,43,60, +152,18,217,56,176,48,122,88,70,108,15,120,92,48,138,84,166,98,208,112, +241,116,62,126,199,126,46,166,205,166,22,228,233,228,130,126,131,224,66,182, +97,214,192,184,161,215,94,14,68,40,35,58,90,44,122,74,152,90,194,102, +237,112,148,16,213,52,166,40,122,78,84,98,19,116,180,116,132,124,90,128, +68,128,68,174,64,196,39,232,70,166,223,166,156,166,157,239,16,240,28,216, +34,194,38,164,38,30,88,30,88,226,74,240,59,226,40,88,87,88,40,140, +85,140,106,60,243,60,198,14,221,40,124,244,124,98,224,98,224,228,212,242, +195,230,126,140,223,140,126,182,223,182,174,8,175,237,22,234,32,208,36,180, +40,156,40,30,84,30,84,226,66,238,55,222,42,90,83,90,42,144,83,144, +158,10,189,30,244,40,122,40,122,154,116,186,103,224,168,54,150,100,133,128, +156,88,157,242,172,110,247,110,218,56,218,226,198,238,187,222,178,136,199,169, +130,10,157,32,240,46,52,46,52,158,44,194,23,236,118,62,92,108,71,140, +100,98,101,246,118,112,243,112,200,60,200,228,180,240,163,224,134,146,167,179, +124,10,147,28,242,38,46,38,46,130,42,182,23,240,112,50,67,102,94,72, +95,136,114,78,239,78,200,50,200,124,184,134,173,120,136,94,165,112,76,244, +76,150,212,150,212,222,208,236,198,240,189,228,146,126,134,162,124,172,99,188, +136,160,189,188,144,180,124,206,101,224,134,194,187,221,28,60,135,60,16,108, +149,108,82,10,83,106,90,120,91,206,90,160,143,160,50,136,34,198,17,236, +38,178,58,198,82,212,114,224,150,228,202,228,243,226,168,8,169,202,180,84, +233,135,20,32,159,32,132,100,46,100,46,64,132,64,133,98,36,236,36,132, +142,132,143,234,36,174,141,174,36,214,141,214,88,134,89,212,178,42,179,178, +220,8,220,220,204,236,181,225,20,32,239,32,206,80,50,80,50,56,208,56, +209,80,102,34,103,76,156,32,157,78,72,94,44,124,25,140,78,134,48,166, +19,192,54,160,55,242,138,90,116,114,97,134,120,110,233,110,208,172,118,172, +118,132,208,132,209,170,120,152,207,152,138,176,114,198,91,210,122,192,208,192, +172,216,140,230,93,238,136,204,166,220,190,230,237,239,30,180,30,34,88,34, +89,176,60,64,60,142,54,182,40,214,17,242,70,186,95,222,110,46,171,46, +102,84,243,84,210,34,231,62,190,12,190,100,194,152,202,196,212,222,222,238, +228,240,234,238,238,232,241,212,150,94,151,218,150,144,177,144,120,120,121,230, +104,238,185,209,80,8,52,52,23,82,62,36,225,36,194,130,70,130,70,66, +196,66,197,128,70,96,195,96,96,138,70,168,43,190,80,158,182,158,164,180, +138,206,102,222,60,234,23,238,94,172,126,202,158,218,192,230,233,237,80,10, +50,80,21,122,58,62,59,246,86,40,239,40,184,10,211,28,102,156,102,70, +220,70,221,152,104,102,217,102,104,132,219,132,162,6,163,156,80,176,245,176, +200,156,200,232,186,244,167,228,122,194,149,219,88,14,60,72,44,98,19,128, +62,70,63,244,84,86,243,86,194,16,194,230,172,244,155,224,112,124,147,175, +118,8,103,36,62,164,62,40,194,40,194,78,67,78,62,110,198,110,198,148, +65,148,14,186,245,186,132,156,133,245,92,24,58,66,31,90,150,26,221,82, +76,92,98,136,118,162,144,188,188,218,237,236,172,86,142,150,108,192,68,218, +21,239,18,230,34,194,42,154,42,32,92,32,92,222,74,236,57,222,44,90, +91,90,44,142,91,142,146,10,124,50,105,76,130,40,241,40,218,130,132,130, +132,70,218,70,219,128,134,100,217,100,156,138,134,170,113,196,142,160,216,160, +188,198,160,220,109,238,142,182,176,208,198,222,241,235,100,12,62,58,31,84, +80,38,168,38,135,80,64,196,64,88,200,88,201,194,128,110,126,162,120,190, +96,216,72,228,39,240,140,198,227,239,108,12,145,36,34,82,34,46,222,46, +223,80,56,74,199,74,182,130,70,130,70,98,184,98,185,128,48,246,48,156, +206,156,207,244,50,192,205,192,48,224,205,224,128,156,129,223,46,16,91,54, +14,86,66,86,66,218,119,182,166,8,167,244,168,90,243,133,34,244,34,30, +86,30,62,102,72,118,82,138,82,158,78,176,64,186,51,176,138,14,110,72, +89,104,120,56,121,244,138,80,241,80,206,12,206,230,186,242,169,224,146,114, +173,159,72,14,54,112,42,154,82,186,115,216,20,76,112,72,104,124,96,158, +78,194,52,218,25,238,124,50,222,50,223,240,130,130,221,130,130,212,221,213, +62,18,22,104,71,96,92,64,28,168,95,154,18,224,99,204,100,46,239,46, +116,162,116,74,218,74,219,160,190,12,211,34,116,102,217,102,116,134,217,134, +168,14,169,162,100,180,245,180,200,156,200,234,188,244,169,230,132,194,159,223, +30,192,30,40,70,40,71,184,30,162,69,162,134,18,108,82,85,118,116,70, +117,240,128,84,241,84,204,14,204,226,172,238,163,220,144,120,173,157,28,200, +28,38,70,38,71,194,28,170,69,170,84,36,239,36,136,6,137,58,184,4, +185,58,208,122,108,122,108,72,208,72,209,120,108,96,207,96,126,130,104,158, +83,178,112,150,226,150,220,232,206,242,191,232,164,156,142,182,121,198,152,172, +197,198,106,170,106,216,191,217,26,198,26,38,66,38,67,188,26,170,65,170, +84,30,237,30,158,30,149,52,206,130,108,130,108,56,208,56,209,130,110,84, +207,84,110,108,207,108,80,172,239,156,180,140,193,154,132,140,142,182,154,204, +174,222,200,234,214,236,224,226,230,218,235,202,206,174,146,212,110,226,75,233, +30,24,71,62,12,102,56,102,56,232,91,192,144,10,179,40,94,54,243,54, +158,62,112,126,175,120,198,88,174,130,140,164,109,182,222,126,194,170,164,200, +136,220,107,236,176,188,233,239,22,38,100,38,100,116,34,116,34,216,101,164, +156,8,136,72,117,104,138,66,239,66,198,66,194,112,184,152,170,182,142,208, +114,224,85,236,134,110,146,144,158,166,180,192,206,214,237,233,16,76,81,76, +56,10,57,242,52,82,42,118,32,146,19,172,58,110,83,136,100,128,136,128, +136,34,96,34,96,210,139,174,128,144,147,192,98,80,135,80,160,30,239,30, +172,62,162,122,245,122,198,30,196,94,192,134,178,176,160,206,127,236,202,140, +202,214,202,222,204,224,208,226,212,230,220,230,226,230,234,224,241,205,70,14, +44,58,21,88,48,52,111,52,38,94,107,94,22,146,113,146,70,96,70,228, +119,184,118,36,245,36,178,36,179,138,178,90,229,90,136,70,130,142,228,142, +224,208,220,220,216,228,206,232,173,235,74,18,105,44,182,12,155,50,32,56, +227,56,54,92,203,92,34,128,225,128,128,56,129,126,16,226,241,226,54,224, +54,162,202,162,203,224,102,164,103,222,152,164,153,225,24,26,61,50,18,84, +57,110,18,228,59,152,82,130,126,130,126,36,78,36,78,208,123,180,110,146, +137,194,80,82,125,82,144,36,235,36,156,66,146,126,241,126,188,36,188,88, +184,126,176,162,158,196,123,242,194,142,194,230,200,234,208,236,218,236,228,232, +234,226,238,212,239,205,36,36,221,36,20,120,241,120,128,36,129,245,14,82, +245,82,76,12,77,244,186,10,187,238,78,146,185,146,78,218,185,219,16,78, +113,78,66,12,67,242,62,86,42,136,19,170,68,106,105,140,116,34,235,34, +114,132,247,132,178,34,179,245,18,74,93,74,62,10,63,246,58,88,40,140, +21,176,64,98,97,132,104,76,243,76,136,12,137,240,212,10,213,238,136,140, +211,140,136,210,211,211,66,12,40,56,17,82,48,44,123,44,72,44,93,82, +164,10,144,50,123,80,148,42,237,42,174,42,197,82,42,106,207,106,12,160, +239,160,124,106,125,247,70,224,92,236,102,226,102,32,50,32,50,156,44,190, +29,234,52,90,101,90,50,144,101,144,126,34,233,34,118,134,241,134,180,34, +181,245,28,58,121,58,18,100,127,100,76,8,77,98,48,136,34,194,21,232, +40,174,52,190,70,206,90,214,116,222,156,224,239,224,82,116,83,210,84,152, +127,152,134,40,227,40,128,122,237,122,180,40,181,209,228,50,48,50,48,110, +42,134,32,158,23,172,182,14,207,36,156,10,158,60,166,96,180,128,198,152, +210,162,220,164,226,160,237,134,212,76,176,132,145,164,64,80,141,80,128,146, +76,146,76,110,130,110,131,144,56,182,31,232,118,180,147,206,198,186,229,222, +86,180,86,220,86,228,88,232,94,234,108,236,128,238,152,236,160,236,168,230, +174,224,178,216,183,205,110,20,80,30,54,36,27,40,18,86,123,86,70,32, +71,240,66,94,48,142,32,168,21,184,72,110,113,146,130,32,241,32,122,128, +249,128,186,32,187,241,10,72,137,72,34,28,100,28,85,70,14,204,129,182, +46,72,47,196,104,72,105,244,48,112,103,112,48,154,103,154,172,10,150,70, +136,98,123,118,150,72,241,72,202,72,200,106,194,140,184,172,160,204,125,236, +148,108,164,148,180,178,200,200,237,227,60,12,81,34,24,42,117,42,42,56, +59,78,94,56,83,82,16,88,119,88,100,164,36,164,36,114,102,114,103,162, +38,138,101,138,16,192,119,192,68,164,69,246,162,12,144,38,125,60,148,32, +214,32,194,54,170,72,150,80,129,90,156,52,180,66,200,76,220,82,243,88, +144,96,217,96,122,122,239,122,176,96,177,120,136,208,136,146,212,146,213,204, +172,166,168,196,162,212,150,224,138,230,115,242,182,210,229,241,40,236,40,30, +214,30,214,222,194,230,175,214,172,58,144,106,128,130,106,152,71,182,78,68, +122,110,150,142,168,164,179,179,34,240,34,34,134,34,134,226,112,238,97,222, +108,68,88,128,59,176,56,72,90,126,113,176,178,46,179,176,220,14,220,220, +200,236,183,221,60,12,38,60,17,90,42,54,101,54,26,98,91,98,16,146, +99,146,56,98,56,228,95,182,118,242,118,34,224,34,224,226,204,240,187,224, +198,66,178,122,162,156,141,186,140,74,203,177,58,14,44,56,32,78,21,96, +40,64,127,64,78,64,79,220,16,128,139,128,38,156,38,226,117,220,118,152, +119,244,140,42,235,42,188,42,189,222,134,226,245,227,18,236,36,196,42,158, +42,28,100,28,100,224,82,236,67,220,44,86,99,86,44,140,99,140,122,42, +241,42,120,212,245,212,180,44,181,211,66,14,18,102,71,94,92,60,28,166, +93,146,12,212,95,194,114,242,114,32,226,32,226,220,208,238,187,222,196,62, +184,104,170,140,152,168,137,188,138,72,203,183,48,24,48,68,204,68,205,20, +124,10,125,66,44,244,44,100,212,100,212,226,190,240,173,226,172,120,136,158, +108,182,77,202,76,128,183,199,30,26,69,50,16,86,57,108,24,234,63,144, +80,52,229,52,70,100,239,100,126,14,127,98,180,14,181,98,128,102,112,130, +90,152,75,164,172,102,186,120,208,140,237,156,118,184,188,184,188,144,114,144, +114,212,116,218,126,224,140,228,158,230,184,228,202,224,212,214,219,203,18,80, +117,80,70,10,71,244,68,90,48,138,32,166,23,180,70,102,115,146,116,42, +239,42,108,218,247,218,178,42,179,217,74,14,52,46,35,70,58,40,133,40, +78,40,95,68,170,14,145,58,158,38,235,38,176,38,197,64,116,62,139,78, +20,88,239,88,186,136,70,136,70,108,188,108,189,136,46,244,46,162,212,162, +212,224,200,240,179,228,170,212,84,212,84,186,170,186,171,213,108,8,95,38, +196,110,60,110,60,42,198,42,199,108,60,76,197,76,20,140,235,140,118,112, +98,148,70,174,42,190,21,196,154,140,164,156,178,166,198,180,237,194,62,198, +197,198,128,156,129,247,110,12,141,34,18,46,239,46,182,108,70,108,70,74, +182,74,183,106,36,244,36,138,216,138,216,224,198,242,175,228,166,202,80,202, +80,168,168,168,169,201,106,12,143,30,18,38,239,38,186,82,66,82,66,60, +186,60,187,80,30,134,30,104,228,104,229,132,186,146,68,146,68,124,186,124, +187,144,60,246,60,168,196,168,196,230,176,242,163,228,62,190,195,190,62,210, +193,211,76,16,109,46,180,10,153,52,32,60,225,60,48,108,207,108,22,162, +235,162,130,60,131,160,62,184,33,242,100,188,113,230,142,186,163,228,188,184, +231,233,26,38,45,72,102,34,87,72,18,94,103,94,66,10,67,244,60,108, +38,152,19,178,68,116,95,146,128,18,155,44,206,12,179,56,110,62,235,62, +114,108,221,108,102,156,245,156,166,62,167,152,118,182,93,232,144,188,153,228, +176,188,187,226,202,178,233,229,58,12,58,234,44,244,27,226,18,76,91,76, +16,152,85,120,142,10,169,36,90,52,241,52,202,112,122,112,122,78,202,78, +203,110,102,244,102,140,228,140,228,218,220,236,193,226,186,204,138,204,138,168, +188,168,189,203,62,12,36,66,19,90,38,60,95,60,32,102,93,102,20,148, +97,148,58,102,58,228,95,188,146,12,183,36,100,48,243,48,210,112,130,112, +130,76,210,76,211,112,110,242,110,142,230,142,230,230,214,240,199,224,194,204, +146,204,146,170,196,170,197,205,100,24,58,36,27,38,22,90,113,90,66,34, +67,242,62,102,42,160,23,188,68,114,101,148,150,12,189,36,110,46,245,46, +210,110,140,110,140,72,212,72,213,108,118,244,118,138,236,138,236,230,210,242, +199,226,200,198,154,198,154,168,202,168,203,197,80,26,58,76,45,98,64,64, +213,64,16,122,243,122,132,10,133,120,66,244,66,162,190,162,191,242,68,222, +189,223,26,26,229,26,182,26,183,108,134,96,58,96,58,58,134,58,135,96, +12,124,245,124,190,124,190,230,164,242,145,222,138,196,54,196,54,156,138,156, +139,195,20,32,135,32,112,32,113,110,10,122,145,122,112,122,112,226,94,240, +83,224,80,194,36,194,36,154,82,154,83,192,78,94,38,94,38,60,80,60, +81,92,172,8,158,58,137,100,156,66,232,66,213,110,182,102,180,148,168,190, +152,218,133,240,182,142,190,172,202,194,218,214,237,235,12,70,91,70,56,10, +56,224,40,236,25,222,16,146,89,114,108,16,137,50,104,52,105,238,152,36, +226,36,226,226,212,240,189,220,160,54,144,82,125,108,148,76,196,76,186,98, +158,126,125,146,148,96,166,118,178,124,207,140,188,198,142,198,142,154,188,154, +189,199,24,96,221,76,142,24,179,52,192,114,154,160,114,190,78,210,43,224, +98,14,96,52,100,90,110,140,122,172,140,200,168,222,190,234,204,236,212,232, +216,226,225,201,82,18,50,68,23,98,72,36,123,82,38,102,107,102,44,236, +44,144,102,144,103,230,44,208,103,208,178,12,159,40,164,66,189,88,180,112, +194,112,208,108,216,100,218,90,218,48,140,48,140,150,234,150,228,212,220,224, +206,232,186,232,171,232,118,190,205,191,14,232,28,204,36,180,38,160,40,146, +40,24,90,24,90,218,76,236,57,220,40,86,89,86,40,142,91,142,164,8, +136,52,115,74,146,38,218,38,198,72,180,94,152,114,111,134,144,64,178,102, +202,120,241,136,132,242,132,148,216,148,217,240,132,216,215,217,124,16,161,36, +240,50,64,50,64,152,58,180,42,216,23,240,18,68,45,100,14,160,61,132, +124,62,104,108,89,132,110,98,233,98,108,138,196,138,138,180,120,196,110,212, +110,222,116,230,128,234,138,236,208,236,224,228,232,216,239,195,72,16,103,40, +30,78,30,48,154,48,155,78,38,86,145,86,38,120,145,120,20,150,161,150, +92,60,93,166,46,244,46,180,134,180,135,244,48,226,133,226,180,56,181,184, +222,22,222,228,202,242,185,225,28,46,231,46,88,10,88,80,170,80,171,12, +200,156,58,156,58,112,200,112,201,154,16,192,241,192,126,82,127,245,18,38, +239,38,96,8,97,58,160,8,161,58,192,124,62,124,62,66,192,66,193,122, +64,96,191,96,84,132,54,164,25,186,66,154,212,154,210,220,208,232,198,236, +183,238,132,162,106,188,83,206,120,174,175,202,60,180,60,218,169,219,18,72, +97,72,62,12,63,244,58,84,40,132,17,168,66,102,91,132,152,8,126,64, +107,94,136,44,214,44,196,74,178,94,158,114,130,134,99,148,142,68,164,94, +184,112,208,128,241,138,128,242,128,150,210,150,211,238,130,216,209,217,94,142, +24,142,24,64,96,64,97,142,60,10,61,198,12,218,97,194,88,170,109,212, +170,8,148,58,132,84,115,102,168,16,178,36,192,60,216,84,239,102,136,106, +215,106,132,244,132,152,218,152,219,242,134,216,217,217,36,58,37,242,46,16, +77,56,102,32,220,32,220,230,200,240,177,226,112,50,90,86,67,108,96,76, +168,76,140,106,112,126,57,148,100,96,126,116,146,124,197,142,168,204,88,204, +88,158,170,158,171,203,34,244,34,34,82,34,60,106,74,130,80,144,82,158, +82,172,76,188,66,196,51,178,98,32,239,32,208,100,124,100,124,64,208,64, +209,98,108,242,108,132,226,132,226,220,222,230,216,236,210,240,193,226,138,146, +155,170,128,186,207,186,194,144,166,188,167,233,62,14,38,68,17,102,42,58, +99,58,28,106,95,106,20,152,101,152,60,106,60,236,99,196,152,12,126,62, +107,90,136,46,208,46,186,84,154,116,109,144,140,68,172,102,188,116,239,140, +130,246,130,154,208,154,209,242,130,218,207,219,130,14,106,56,84,84,52,110, +21,130,124,26,146,54,168,78,198,100,237,122,130,92,131,249,102,14,74,62, +43,98,84,48,188,48,154,84,116,114,72,136,19,152,92,66,122,98,146,114, +184,132,235,146,74,246,74,156,188,156,189,244,74,224,187,225,62,16,18,104, +69,96,96,58,26,166,99,150,16,220,105,204,164,12,146,48,130,74,112,96, +91,118,160,24,170,44,188,68,206,88,239,112,120,110,209,110,126,242,126,154, +208,154,209,240,126,220,205,221,18,74,101,74,66,12,67,244,62,86,44,130, +21,168,68,96,101,134,130,122,216,122,216,32,124,32,124,242,171,200,126,78, +213,78,164,124,176,164,194,196,233,230,226,144,187,181,96,92,36,92,36,30, +96,30,97,90,16,224,111,194,70,94,71,204,34,122,35,216,70,140,109,140, +136,120,210,120,210,28,132,28,132,240,173,198,134,74,207,74,228,140,191,182, +168,122,176,154,188,186,202,206,235,237,20,50,113,50,22,90,109,90,14,124, +119,124,68,8,69,244,66,128,40,174,21,200,70,140,103,174,114,74,239,74, +110,144,243,144,152,10,152,150,146,178,134,206,122,224,105,240,204,8,205,245, +20,32,233,32,198,146,56,146,56,70,200,70,201,144,58,110,199,110,130,34, +130,160,124,180,114,202,92,218,58,230,25,238,66,164,90,182,118,200,154,216, +194,226,231,231,124,10,155,32,232,44,46,44,46,180,36,210,21,238,54,122, +247,122,70,84,204,84,204,160,71,160,140,58,140,100,136,144,128,182,110,208, +90,228,67,242,144,162,156,184,174,204,198,222,229,237,74,12,97,30,176,8, +159,32,26,38,229,38,44,62,211,62,18,84,233,84,128,40,129,82,54,92, +23,118,92,92,109,114,144,88,159,110,202,88,227,110,74,110,91,126,180,104, +161,128,34,132,221,132,46,154,207,154,30,178,225,178,130,132,131,176,18,200, +237,200,126,184,118,206,100,220,72,228,50,232,25,234,138,202,156,214,180,224, +206,228,233,233,14,82,95,82,54,12,55,172,14,190,97,160,88,26,239,26, +218,140,112,140,112,66,218,66,219,136,112,102,217,102,164,26,164,148,162,160, +160,176,156,184,148,198,134,212,112,226,75,238,104,164,126,184,140,196,170,212, +206,224,239,235,10,34,123,34,14,200,123,174,38,34,39,192,92,34,93,242, +38,82,93,82,38,134,91,134,138,66,130,104,121,130,226,62,193,118,172,10, +172,110,168,144,156,180,136,216,117,240,172,122,178,146,188,170,200,192,218,216, +239,233,20,72,101,72,66,12,67,244,62,76,44,124,21,164,68,96,99,128, +102,32,247,32,224,148,122,148,122,70,224,70,225,146,174,32,174,140,170,164, +162,190,144,212,124,226,101,238,122,166,136,182,158,202,190,218,239,232,122,106, +223,107,38,40,223,40,18,220,239,220,126,40,127,219,14,52,117,52,14,204, +111,176,62,52,63,186,158,10,130,78,107,116,136,64,239,64,202,66,198,108, +188,142,172,178,148,204,120,224,89,240,136,100,154,148,172,184,200,214,237,237, +18,58,113,58,20,202,115,174,68,58,69,186,110,82,226,76,222,212,210,234, +173,220,160,12,156,82,156,130,144,172,120,206,81,239,36,56,219,56,16,108, +233,108,92,12,93,106,164,12,165,106,94,108,78,132,56,154,21,176,154,108, +168,126,190,144,212,158,237,166,118,128,118,228,114,234,102,236,89,236,84,170, +68,198,51,220,144,172,169,218,176,162,213,219,20,50,229,50,156,18,187,38, +114,16,104,62,92,86,74,106,54,118,33,132,190,66,152,92,103,110,140,52, +140,104,144,110,150,114,162,116,190,116,204,112,212,102,219,92,40,156,217,156, +94,126,95,188,162,128,163,184,14,190,243,190,100,202,72,226,45,242,162,202, +213,239,76,14,50,70,34,100,19,120,54,62,55,244,86,78,237,78,130,20, +131,146,192,18,193,146,78,152,247,152,138,180,116,214,91,240,186,178,241,237, +20,156,119,156,104,156,78,188,54,212,25,232,50,154,50,50,120,50,120,228, +102,242,79,224,50,82,119,82,50,116,119,116,86,14,69,48,144,38,218,38, +218,96,162,96,158,148,226,148,222,198,216,218,208,228,198,232,173,237,96,28, +82,60,64,96,44,120,21,144,150,18,162,54,174,80,194,104,237,142,130,100, +98,166,58,224,185,208,158,160,203,231,106,16,137,40,34,90,34,50,224,50, +225,88,180,134,74,134,74,92,182,92,183,132,58,246,58,170,198,170,199,244, +58,222,197,223,38,34,194,34,194,90,56,90,52,146,208,146,204,176,196,202, +190,214,176,222,158,228,130,228,109,229,16,46,101,46,14,194,93,170,56,46, +57,178,140,96,169,148,66,240,88,224,108,198,118,162,122,122,122,32,192,32, +192,218,196,228,206,230,218,232,226,226,236,214,241,183,48,24,211,24,16,76, +239,76,128,24,129,74,24,130,100,130,86,164,70,188,48,208,21,224,128,90, +128,216,126,228,120,232,112,234,97,234,216,112,157,152,130,102,140,134,156,160, +176,182,204,206,233,221,14,74,91,74,56,10,56,230,38,242,21,226,16,158, +93,116,100,74,237,74,90,148,245,148,134,12,135,146,196,12,197,146,144,176, +87,242,180,176,233,233,44,30,211,30,14,78,245,78,130,30,131,76,66,192, +66,114,196,114,197,188,134,134,128,172,120,198,94,218,66,230,33,238,156,190, +233,233,30,84,227,84,16,160,243,160,92,20,93,158,170,20,171,158,108,178, +70,216,33,240,154,180,225,235,70,20,46,62,23,96,48,62,117,62,36,108, +107,108,18,158,117,158,70,108,70,238,111,198,160,14,138,70,119,102,142,60, +230,60,224,226,196,242,175,226,162,96,126,186,193,170,178,130,205,187,86,14, +58,70,25,108,68,52,216,52,206,232,180,240,161,222,112,90,82,142,48,192, +157,172,132,124,175,195,44,32,83,62,20,96,63,124,34,234,83,148,142,12, +116,70,93,104,120,60,226,60,226,204,210,236,163,226,150,94,104,192,181,166, +170,136,195,191,14,46,241,46,96,12,97,78,164,14,165,78,80,74,56,116, +25,152,62,104,218,104,218,178,212,218,194,240,155,226,156,200,68,200,68,142, +156,142,157,201,92,26,50,82,29,100,30,26,52,50,66,80,74,114,78,158, +78,190,76,212,62,236,33,226,72,120,44,158,25,176,150,14,122,64,95,96, +128,54,226,54,220,228,196,244,175,224,178,174,122,174,122,110,178,110,179,173, +16,80,95,80,56,10,57,168,14,188,93,160,222,24,176,34,112,38,112,120, +106,164,94,204,73,232,114,94,247,94,136,246,136,142,218,142,219,244,138,220, +217,221,18,76,105,76,68,12,69,244,64,82,42,136,21,168,72,102,105,136, +156,12,130,76,113,102,134,64,228,64,224,224,190,238,167,218,160,92,118,184, +193,168,174,130,203,187,42,178,42,36,110,36,111,172,76,72,76,134,68,184, +54,208,23,236,86,188,125,226,170,12,150,58,127,94,152,54,230,54,222,236, +198,242,185,224,170,90,134,182,197,162,184,126,209,187,58,8,38,58,19,88, +44,48,116,48,106,222,84,230,67,212,80,164,38,164,38,100,80,100,81,160, +178,12,154,50,133,70,160,40,224,40,204,76,180,102,160,116,139,126,158,70, +185,94,200,116,178,144,154,166,133,178,184,138,238,138,218,178,190,210,160,228, +123,238,164,178,193,205,16,36,239,36,128,4,129,58,198,94,62,94,62,64, +200,64,201,92,120,104,139,120,36,130,221,130,16,168,241,168,86,140,105,164, +176,138,157,166,32,200,225,200,128,168,129,247,18,48,239,48,100,10,101,78, +160,10,161,76,20,124,100,124,92,162,76,196,54,218,29,236,68,74,46,172, +113,216,116,116,241,116,174,74,175,158,134,246,134,162,216,162,217,242,134,220, +215,221,28,202,28,52,82,52,83,192,28,168,81,168,98,74,241,74,168,10, +169,144,116,244,116,148,216,148,217,242,116,218,215,219,76,14,48,54,25,76, +58,40,127,40,76,40,97,76,166,10,144,50,125,74,150,40,237,40,176,40, +197,74,30,114,103,114,74,80,74,236,50,244,37,228,26,180,99,152,232,92, +118,92,118,228,241,228,146,198,146,132,218,132,218,184,200,196,193,182,178,104, +179,215,74,14,52,72,21,122,54,70,55,244,86,74,247,74,162,8,163,132, +112,242,112,142,216,142,217,240,112,218,217,219,36,26,77,56,16,88,59,118, +30,234,75,144,84,74,245,74,164,10,165,140,110,246,110,144,216,144,217,244, +112,218,213,219,12,34,90,34,56,88,56,228,40,242,21,224,14,156,93,122, +216,18,188,28,154,34,116,36,116,116,112,154,104,190,79,236,152,34,152,230, +185,210,176,186,199,230,190,28,192,84,196,126,206,168,216,192,237,233,64,12, +48,96,34,152,101,206,14,80,94,76,86,128,74,164,56,200,23,236,108,72, +243,72,174,8,175,134,130,246,130,142,220,142,221,244,132,218,219,219,12,46, +135,46,76,10,77,80,24,86,127,86,106,154,36,154,36,114,108,114,109,152, +40,170,61,200,98,168,81,206,14,224,127,206,124,62,237,62,178,8,179,102, +124,108,218,108,206,142,188,178,160,208,115,238,142,108,152,138,166,166,188,196, +239,233,16,74,243,74,130,8,131,136,60,248,60,144,196,144,197,242,60,220, +197,221,200,90,58,90,58,48,200,48,201,88,130,10,131,124,24,134,205,126, +190,104,223,146,14,226,243,226,52,222,52,166,204,166,205,224,102,166,103,224, +154,166,155,225,30,126,30,92,226,92,227,124,68,90,68,20,188,20,189,88, +68,54,130,54,131,90,68,244,68,120,188,120,188,234,162,244,147,224,70,156, +187,156,70,188,187,189,90,20,62,54,33,80,162,20,225,68,134,54,96,106, +62,138,19,162,128,62,150,92,180,118,212,138,239,148,72,244,72,152,192,152, +193,242,72,218,191,219,16,236,32,204,34,176,38,148,38,32,88,32,88,226, +64,244,53,226,40,90,87,90,40,146,89,146,110,114,128,96,136,78,138,64, +138,30,194,30,194,92,200,96,206,102,245,100,108,132,210,132,190,172,162,206, +138,224,109,240,128,132,136,154,148,178,174,202,208,220,243,233,12,74,129,74, +70,10,71,126,34,228,34,130,104,130,105,218,34,200,103,200,162,8,146,70, +125,116,144,72,243,72,208,72,204,112,192,154,164,194,138,218,105,238,148,110, +158,144,176,174,198,202,239,231,126,32,38,32,38,162,32,202,19,234,92,148, +106,146,110,144,114,138,114,78,70,78,70,230,119,184,136,28,243,28,186,28, +179,66,148,186,148,74,222,74,223,184,184,96,184,142,178,178,162,208,144,226, +125,240,194,192,243,239,40,244,40,34,218,34,219,238,40,220,219,220,54,86, +195,86,130,48,131,126,170,182,88,182,88,132,170,132,171,181,116,10,157,34, +54,82,224,82,224,46,52,46,52,142,46,176,38,204,30,218,21,236,114,94, +88,132,67,156,140,98,175,116,96,122,97,248,102,128,241,128,102,160,229,160, +102,194,231,194,102,228,245,228,164,130,165,227,132,20,98,28,58,34,29,36, +18,86,145,86,84,30,85,132,42,234,42,140,126,140,127,230,44,208,125,208, +168,36,169,182,218,14,218,224,198,240,177,223,212,28,144,40,92,46,60,46, +62,106,58,150,50,184,38,214,21,240,122,44,122,152,120,186,112,236,165,212, +148,178,179,238,180,34,180,66,180,100,184,128,190,154,198,178,208,202,220,218, +235,237,128,88,48,88,48,32,128,32,129,86,32,238,32,122,144,122,144,220, +122,236,109,218,88,88,86,132,72,168,53,194,82,142,123,186,178,44,179,182, +220,14,220,224,198,242,181,225,108,14,139,36,32,78,32,46,218,46,219,76, +54,68,199,68,126,68,121,88,16,160,241,160,62,160,62,92,188,92,189,160, +62,114,187,114,62,136,187,136,84,160,60,184,40,196,19,206,170,160,182,172, +208,190,239,202,64,186,176,186,174,222,170,232,164,236,137,238,112,186,102,208, +88,224,70,236,55,243,62,10,62,232,40,244,27,224,16,68,101,68,16,156, +91,120,110,58,231,58,168,8,169,112,104,112,245,112,110,166,229,166,168,126, +169,222,94,224,245,225,40,12,71,46,14,64,78,64,56,104,21,146,56,104, +57,242,56,128,93,156,92,110,71,138,98,62,171,62,134,12,135,102,96,104, +179,104,100,154,171,154,134,116,135,202,82,214,181,198,200,8,201,242,210,92, +243,145,206,18,144,30,98,34,45,36,16,78,241,78,128,32,129,242,36,132, +87,132,28,184,87,168,92,102,93,190,228,116,171,138,172,102,168,158,170,172, +174,178,178,182,196,184,214,184,224,178,233,159,20,70,105,70,22,158,99,120, +64,10,64,228,46,244,31,226,220,92,128,92,128,28,220,28,221,90,106,140, +226,140,224,216,220,226,212,232,185,236,162,106,158,146,152,178,142,202,128,218, +97,239,30,62,15,124,74,58,93,100,54,12,55,246,98,36,206,36,188,66, +168,90,138,114,87,136,114,38,124,52,136,68,154,88,172,102,194,114,218,124, +239,132,102,166,231,166,164,130,165,222,82,226,243,227,20,74,93,74,66,12, +67,244,62,80,48,118,32,150,21,172,68,102,105,140,108,84,108,54,236,54, +237,82,148,12,187,42,134,134,214,134,214,94,128,94,129,244,130,170,226,170, +227,236,130,216,225,217,56,22,105,56,184,18,143,74,32,80,223,80,22,142, +233,142,124,80,122,142,112,172,94,196,62,220,29,236,130,142,140,162,150,180, +166,194,184,208,214,224,237,233,110,12,145,42,32,94,32,56,222,56,223,92, +78,136,182,136,182,96,72,96,73,246,74,174,196,174,197,242,72,220,195,221, +34,72,34,34,222,34,223,72,50,76,121,76,24,124,133,124,66,124,62,158, +58,186,44,210,23,232,100,124,100,206,102,216,104,220,110,224,116,226,196,226, +212,222,224,216,230,208,235,198,122,102,239,102,194,54,194,196,170,204,157,188, +142,126,165,159,16,42,92,42,82,90,70,130,48,164,21,194,28,74,99,180, +128,152,128,24,214,24,215,152,170,62,168,122,164,146,150,176,130,202,106,220, +83,236,180,140,180,216,180,222,184,228,190,230,204,232,216,230,226,224,239,205, +66,10,44,42,21,62,46,38,123,38,68,40,87,70,172,10,137,52,150,36, +235,36,176,36,197,68,116,56,143,78,36,122,36,88,224,88,225,122,74,148, +186,148,186,114,72,114,73,246,72,182,198,182,199,242,72,220,199,221,60,14, +40,66,19,104,44,58,86,58,77,94,54,104,54,240,95,192,154,14,183,40, +108,86,108,52,228,52,229,84,130,138,208,138,208,94,126,94,127,246,126,174, +220,174,221,242,126,220,219,221,48,12,32,62,21,84,34,58,95,58,12,112, +103,112,60,58,61,202,28,134,28,212,89,206,90,132,91,226,98,38,241,38, +142,8,143,56,192,6,193,56,154,102,116,102,116,68,154,68,155,100,220,100, +182,100,182,68,222,68,223,100,138,110,120,146,103,170,126,134,127,244,162,108, +183,126,134,136,237,136,134,168,229,168,134,196,229,196,134,226,245,226,176,136, +177,225,54,12,55,244,30,64,19,128,68,60,87,108,82,64,245,64,210,98, +108,98,108,28,210,28,211,96,158,28,159,96,102,198,102,128,214,128,215,198, +158,148,150,184,142,202,126,218,106,228,81,238,168,194,239,235,32,24,67,52, +18,88,57,112,22,232,57,150,76,42,241,42,126,12,127,58,182,10,183,58, +136,98,92,98,92,70,136,70,137,98,216,100,170,100,170,70,218,70,219,100, +114,108,90,148,67,176,98,134,99,244,146,108,169,126,106,136,233,136,106,164, +225,164,106,194,225,194,106,224,241,224,160,138,161,221,14,66,243,66,196,100, +60,100,62,32,198,32,199,98,130,34,127,98,58,200,58,134,196,134,197,196, +128,152,120,186,108,204,90,218,58,228,25,234,142,192,231,237,52,38,99,82, +212,30,165,84,132,10,133,106,18,110,241,110,102,112,100,152,92,178,82,194, +60,220,23,236,152,110,152,208,154,220,160,226,166,228,178,230,196,230,216,228, +226,220,232,208,237,193,118,16,153,44,234,62,52,62,52,140,48,172,38,208, +23,241,24,30,69,68,12,112,56,112,57,200,18,230,32,216,46,208,54,204, +64,208,76,216,94,222,116,230,130,232,239,232,136,22,100,70,77,96,80,32, +108,62,116,82,122,108,126,146,122,178,116,194,104,206,89,190,118,100,81,160, +134,46,235,46,144,114,225,114,136,194,237,194,182,46,183,193,16,42,95,42, +20,112,89,112,14,204,97,180,58,42,59,188,156,10,149,36,218,130,114,130, +114,44,216,44,217,130,116,84,215,84,164,44,158,132,146,166,128,196,104,220, +79,240,212,146,188,190,231,184,222,164,241,192,172,150,172,222,172,228,176,232, +184,236,196,236,212,236,226,230,232,222,237,215,22,62,103,62,14,120,111,120, +64,10,64,122,60,152,50,186,36,208,21,228,62,152,109,194,126,152,126,28, +214,28,215,148,172,62,168,120,166,150,156,174,140,198,120,220,89,238,182,142, +182,218,184,226,190,228,198,230,210,230,226,228,232,220,239,201,50,56,207,56, +26,110,231,110,126,12,127,108,46,166,213,166,126,124,127,222,20,224,235,225, +16,50,113,50,64,50,58,76,52,100,34,128,17,150,50,224,50,114,94,114, +95,216,50,194,93,194,122,62,237,62,112,118,241,118,176,12,177,116,122,172, +231,172,176,132,177,222,102,228,243,229,44,42,45,178,94,14,94,130,90,162, +82,186,72,204,52,222,33,236,114,40,218,40,219,226,122,118,215,118,112,200, +215,201,96,14,56,68,17,100,76,44,164,44,133,82,198,180,198,90,48,90, +48,180,199,180,50,134,197,134,122,90,122,208,124,220,128,226,134,230,142,232, +212,232,222,228,230,220,234,210,239,201,46,18,75,50,38,60,39,240,102,34, +220,36,220,226,196,240,181,224,74,88,185,88,62,122,197,122,128,56,129,120, +72,160,185,160,128,128,129,198,62,200,197,201,12,58,119,58,62,12,28,126, +117,126,70,84,71,242,14,192,121,166,102,88,202,82,196,202,198,216,204,222, +214,224,226,224,230,218,239,196,150,8,150,108,146,142,140,182,124,210,101,237, +114,10,103,38,196,124,52,124,52,46,198,46,199,124,54,82,197,82,120,48, +120,92,116,126,100,166,82,190,56,212,21,230,134,142,134,212,134,220,140,224, +146,226,150,226,210,226,222,222,230,210,237,196,182,138,156,190,205,182,196,160, +215,191,36,28,75,60,12,98,52,98,52,164,52,224,85,172,154,10,130,50, +109,70,138,40,202,40,181,78,240,84,108,84,108,162,104,188,94,216,79,242, +182,178,194,180,204,176,208,172,210,122,148,122,148,212,148,222,152,226,158,230, +168,234,210,234,226,230,230,222,239,201,40,32,114,32,100,66,82,90,52,116, +21,134,48,58,79,88,138,22,150,52,166,72,184,94,210,110,241,120,194,18, +153,52,212,48,177,78,74,114,189,114,38,162,217,162,126,114,122,166,114,186, +98,204,72,222,37,236,120,172,146,186,174,204,194,218,213,233,14,72,101,72, +58,10,59,244,56,76,40,128,19,166,60,104,97,142,112,60,235,60,100,114, +245,114,172,10,173,112,112,166,235,166,172,126,173,220,92,224,249,225,14,72, +105,72,62,10,63,244,58,82,36,140,19,168,62,102,101,138,240,32,122,32, +122,222,245,222,122,92,218,92,218,156,123,157,86,96,30,96,30,32,88,32, +89,96,60,98,61,208,30,126,31,218,14,228,95,198,62,146,99,146,154,12, +128,50,105,74,134,40,202,40,177,82,236,88,124,88,124,170,118,198,108,222, +93,242,188,184,202,182,210,178,214,172,214,126,158,126,158,216,160,226,164,232, +172,234,182,234,212,234,224,232,230,226,236,212,241,203,200,74,200,38,58,38, +58,74,199,74,128,10,129,100,12,106,247,106,60,204,60,138,198,138,199,198, +128,154,124,182,114,202,100,216,82,226,60,234,37,238,140,196,223,237,100,16, +82,46,60,72,38,92,21,104,90,36,153,80,52,100,135,100,32,144,157,144, +84,152,44,222,133,204,112,166,149,224,178,42,179,186,224,20,224,230,208,242, +179,227,14,60,109,60,72,18,20,132,107,132,72,90,73,246,18,194,109,174, +218,114,128,114,128,30,218,30,219,114,130,72,217,72,132,168,171,168,128,132, +128,232,171,208,188,128,188,224,190,230,196,234,208,236,224,234,232,228,236,218, +239,208,232,154,191,185,30,26,67,56,16,86,57,116,26,230,65,146,136,12, +175,38,80,48,245,48,122,68,83,106,188,66,231,102,156,80,106,138,197,126, +176,98,211,142,146,134,134,156,108,180,86,196,67,208,124,166,122,240,165,210, +158,152,174,182,188,202,212,222,233,232,226,154,183,189,16,78,101,78,62,14, +63,244,60,90,36,142,19,166,64,110,97,142,218,106,218,28,118,28,118,106, +217,106,118,66,217,66,118,128,118,238,161,206,118,164,165,164,184,124,184,220, +186,226,192,230,204,232,218,232,228,230,236,224,240,218,243,208,238,142,185,173, +62,14,36,62,17,90,40,56,105,56,32,98,99,98,18,150,107,150,60,100, +60,236,101,200,220,88,132,88,132,36,218,36,219,86,124,244,124,132,230,132, +230,230,212,244,197,230,176,100,172,148,162,180,139,208,172,156,211,201,38,242, +38,28,218,28,219,236,40,214,217,214,60,64,193,64,68,112,185,112,126,66, +127,176,56,178,201,178,154,128,179,159,202,114,54,114,54,32,202,32,203,112, +56,74,201,74,128,34,129,244,18,148,239,148,120,152,94,178,70,198,46,212, +21,224,136,152,154,172,174,190,200,208,237,223,112,12,145,34,22,44,235,44, +198,116,198,68,64,68,64,116,197,116,66,90,197,90,128,70,129,164,28,136, +233,136,104,138,76,158,52,168,27,178,154,148,231,172,112,160,64,202,25,224, +94,178,94,238,139,202,142,164,158,190,186,214,210,226,233,236,198,176,171,201, +36,26,73,64,12,106,56,106,57,196,18,224,32,210,46,204,58,202,76,210, +102,224,128,228,146,230,239,226,88,70,237,70,114,110,143,148,190,10,190,184, +172,204,151,191,24,204,24,52,74,52,75,194,24,174,73,174,158,10,146,46, +132,68,114,92,95,110,158,20,168,36,188,64,208,88,237,106,120,110,209,110, +118,244,118,156,208,156,209,240,118,222,207,223,62,12,97,36,20,50,147,50, +122,108,44,108,44,76,122,76,123,106,32,134,122,134,88,162,88,220,82,230, +70,236,51,224,24,190,139,174,160,246,160,36,224,36,192,116,214,136,226,156, +232,178,226,196,212,206,193,211,20,132,20,100,116,100,117,132,117,132,41,132, +38,98,38,30,98,30,99,98,40,64,72,64,73,98,40,246,40,128,96,128, +96,230,80,242,69,228,40,158,97,158,42,188,95,188,152,12,185,40,114,52, +241,52,170,60,132,120,185,116,210,84,170,138,146,160,127,176,224,126,202,160, +178,186,146,214,115,234,184,182,237,231,18,42,98,42,62,84,62,234,38,244, +27,228,18,156,95,116,150,16,183,42,106,56,239,56,154,66,116,122,161,120, +196,82,156,136,126,164,93,188,216,124,172,186,136,216,97,238,176,182,233,231, +34,24,71,52,18,86,55,116,22,236,57,152,126,12,100,62,73,94,108,50, +229,50,66,142,241,142,234,204,96,204,106,88,202,88,196,232,174,244,161,228, +140,102,165,130,138,158,163,191,82,14,50,58,19,84,66,40,235,40,66,68, +217,68,34,92,196,92,194,138,196,174,204,212,216,234,224,236,230,234,234,228, +239,210,94,102,115,124,28,132,177,132,94,140,54,172,113,170,140,156,100,184, +72,196,47,204,156,182,108,214,72,228,39,240,116,210,175,237,114,14,147,40, +20,56,241,56,118,66,64,118,145,114,178,84,130,134,96,158,70,170,41,180, +198,132,154,176,112,204,66,222,27,230,144,182,221,237,108,12,147,36,36,94, +36,50,224,50,225,94,58,84,203,84,52,116,209,116,16,148,241,148,130,62, +131,168,62,246,62,180,200,180,201,246,62,228,199,229,12,36,86,36,81,138, +40,58,34,140,100,140,94,220,82,230,62,242,53,226,16,194,77,180,160,16, +187,42,104,56,245,56,164,66,122,124,181,116,202,88,170,134,140,166,117,180, +222,130,190,174,152,210,109,238,182,184,231,231,12,34,123,34,32,242,32,78, +108,78,109,238,109,238,109,64,58,36,58,100,54,122,48,136,45,144,80,36, +80,130,86,134,103,132,34,174,105,174,34,214,105,214,122,78,241,78,148,16, +149,242,212,12,213,240,150,140,209,140,152,218,209,219,34,28,100,28,87,56, +18,58,137,58,20,156,131,140,50,60,51,150,110,60,111,166,52,90,109,90, +52,118,109,118,172,16,150,70,129,96,156,60,239,60,200,62,194,100,180,130, +160,146,139,158,152,88,174,120,196,138,220,148,235,154,192,180,229,218,116,172, +147,196,52,184,25,228,84,178,84,220,84,226,88,228,98,232,112,234,142,234, +158,230,168,224,172,214,177,203,14,70,149,70,50,12,51,230,116,12,117,220, +52,130,115,130,54,200,113,200,166,242,166,28,226,28,192,98,208,114,222,130, +230,148,232,160,228,176,218,188,191,193,20,44,123,44,74,10,75,74,108,148, +34,148,34,80,108,80,109,146,36,114,107,114,14,184,127,184,72,150,73,248, +128,56,243,56,130,98,229,98,126,142,230,142,226,196,216,214,197,202,172,12, +173,249,128,10,100,48,72,74,46,92,19,106,124,16,144,44,172,68,208,90, +237,104,112,66,141,90,62,110,174,110,131,158,62,248,62,166,194,166,195,244, +64,226,193,227,44,22,81,52,20,86,57,112,28,234,61,146,92,26,208,26, +158,64,158,188,138,202,129,186,112,72,141,106,110,162,155,124,206,68,168,116, +207,166,92,88,92,220,225,214,226,88,227,243,110,14,143,34,38,76,38,44, +224,44,225,76,58,76,207,76,64,108,201,108,22,136,239,136,100,56,101,134, +162,54,163,134,100,138,82,162,52,186,21,202,162,138,180,160,198,174,222,186, +243,194,108,168,167,194,84,202,173,241,42,34,188,34,130,74,130,180,118,196, +93,182,64,86,107,112,58,168,111,134,198,82,151,112,146,136,195,168,40,98, +40,224,215,218,218,100,219,243,26,204,26,48,64,48,65,186,65,186,26,170, +63,170,236,54,94,54,94,168,86,198,72,222,57,242,112,92,159,92,152,178, +116,178,116,126,152,126,153,178,194,16,215,40,174,8,174,56,174,92,176,134, +184,174,196,206,206,226,214,234,220,236,224,234,230,228,235,210,216,88,198,164, +182,192,160,212,131,231,34,80,34,28,222,28,223,78,110,48,61,90,144,48, +193,90,48,112,211,112,18,164,237,164,128,112,129,243,14,50,119,50,66,14, +67,78,98,152,30,152,30,84,98,84,99,152,32,116,95,116,12,184,113,184, +64,154,65,248,170,10,146,58,117,92,168,18,178,36,194,54,214,74,239,90, +116,108,158,108,158,232,146,246,127,232,120,128,137,156,110,210,157,168,172,108, +218,108,218,226,204,242,185,228,178,124,193,154,172,204,215,157,50,14,50,222, +40,238,19,224,12,72,79,72,12,154,77,122,234,54,98,54,98,110,90,142, +75,166,114,84,167,84,158,148,122,148,122,114,158,114,159,146,196,20,217,38, +176,12,176,56,178,78,182,102,190,132,204,152,218,162,228,164,232,160,234,154, +239,136,220,80,194,134,165,168,96,188,77,228,150,180,177,200,204,184,237,220, +124,174,124,216,124,222,128,228,132,230,138,230,174,230,184,228,188,224,194,218, +197,209,14,66,101,66,16,158,95,118,62,4,62,224,46,242,31,226,218,96, +124,96,124,22,218,22,219,96,124,58,217,58,110,130,233,130,100,176,243,176, +172,132,173,243,194,96,194,24,58,24,58,96,193,96,60,60,193,60,44,132, +213,132,16,174,239,174,130,134,131,241,50,12,51,240,26,68,15,122,66,68, +81,100,202,18,225,38,236,50,96,50,96,108,94,126,86,144,75,164,114,84, +165,84,158,146,116,146,116,112,158,112,159,146,174,10,176,62,182,94,192,124, +204,146,218,158,228,160,234,158,238,152,241,138,220,72,206,114,190,142,171,162, +98,178,77,228,202,180,235,220,146,166,167,194,126,174,126,216,128,224,134,228, +142,230,176,230,186,226,190,220,192,214,197,205,60,12,61,242,34,74,19,130, +80,66,97,106,220,98,126,98,126,28,220,28,221,96,128,64,219,64,112,132, +239,132,100,178,245,178,176,134,177,241,32,60,23,128,100,50,69,98,62,10, +62,116,56,156,40,204,21,236,58,160,97,200,218,98,124,98,124,28,220,28, +221,96,126,62,219,62,110,132,239,132,102,180,249,180,174,134,175,249,32,22, +81,54,18,82,65,114,22,230,73,148,98,30,231,30,86,130,243,130,164,32, +165,245,38,24,79,56,18,84,67,116,24,232,73,148,92,40,212,40,204,72, +194,108,170,152,140,184,114,206,77,232,116,42,124,76,136,110,154,146,176,178, +196,198,233,227,26,56,227,56,126,12,110,58,92,84,70,106,44,122,21,134, +142,56,158,78,180,98,208,114,237,128,44,146,194,142,188,212,182,224,166,230, +145,230,116,98,110,154,98,182,74,208,50,224,29,235,16,78,91,78,60,14, +61,246,56,90,36,142,17,172,64,106,99,138,138,16,177,52,102,68,239,68, +88,238,110,224,126,198,134,168,134,108,198,108,198,226,200,230,206,232,222,232, +234,230,238,224,243,205,68,12,55,44,16,234,26,212,34,180,36,138,36,50, +96,50,96,216,90,230,70,234,59,220,56,74,73,104,58,146,73,178,10,128, +93,128,152,14,191,48,112,66,241,66,110,242,130,220,142,190,144,166,144,106, +198,106,198,220,202,234,210,238,226,238,238,228,241,201,16,80,89,80,52,16, +53,170,14,188,85,158,146,12,167,32,86,42,235,42,206,90,110,90,110,62, +206,62,207,88,88,138,88,112,232,112,233,136,108,138,213,138,148,140,130,160, +112,172,93,180,140,154,152,164,162,178,168,196,170,212,168,228,160,236,150,242, +141,242,148,166,124,194,106,206,91,212,162,184,140,204,120,222,93,240,210,154, +167,182,186,170,194,192,206,212,218,222,235,233,26,190,26,46,66,46,67,184, +26,166,65,166,140,12,167,34,82,42,239,42,208,88,114,88,114,66,210,66, +211,88,90,132,90,110,236,110,237,132,108,134,217,134,164,136,148,146,120,158, +95,164,146,148,166,178,172,200,168,220,160,234,148,238,133,236,154,166,128,182, +108,192,93,196,166,186,122,212,85,226,212,154,171,178,194,166,198,186,210,206, +226,218,237,225,106,10,135,28,24,40,229,40,184,90,74,90,74,64,184,64, +185,88,34,150,34,114,224,114,225,146,56,140,203,140,114,144,94,158,70,170, +47,178,114,148,126,164,136,184,140,206,138,222,132,236,120,242,103,242,124,164, +74,198,43,210,132,188,96,212,41,242,194,156,139,186,160,176,174,196,194,216, +227,235,114,12,145,30,24,40,229,40,184,88,72,88,72,62,186,62,187,88, +32,144,32,112,222,112,223,146,178,130,132,140,100,144,61,146,52,174,193,164, +32,204,209,194,124,142,124,218,124,226,130,232,138,236,148,238,202,238,214,232, +220,224,229,203,30,52,143,52,92,12,93,94,18,100,155,100,46,132,27,184, +126,136,151,180,72,104,72,150,66,182,52,214,33,234,110,102,110,226,90,236, +79,222,196,196,210,194,222,190,230,180,230,166,226,148,218,134,210,122,202,114, +196,108,226,30,168,30,169,245,68,14,38,144,82,178,113,212,14,78,104,76, +96,132,86,162,68,188,48,210,23,230,118,36,220,36,176,92,176,222,162,240, +135,226,116,132,245,133,66,12,67,246,14,52,101,52,22,90,101,90,12,128, +111,128,60,136,42,172,28,194,15,208,70,144,105,180,218,20,156,38,115,44, +112,98,223,90,110,156,237,144,158,40,158,222,162,230,170,232,184,234,206,234, +224,230,234,222,238,214,241,203,190,84,68,84,68,28,190,28,191,82,16,120, +243,120,96,122,80,162,200,162,198,196,188,218,168,228,150,230,115,233,36,24, +77,52,16,84,57,110,28,230,71,146,120,28,102,68,89,92,108,60,223,60, +164,12,165,110,80,114,245,114,114,244,114,150,208,150,209,242,116,218,207,219, +30,198,30,38,74,38,75,192,32,164,73,164,94,38,243,38,206,40,206,226, +186,240,165,222,166,166,112,166,112,88,166,88,167,165,32,194,32,34,72,34, +73,186,32,164,71,164,208,92,116,92,116,24,208,24,209,90,118,58,205,58, +136,100,110,134,89,152,118,126,222,126,216,222,206,232,196,234,181,234,166,136, +129,194,156,156,203,188,112,148,110,212,191,213,20,46,245,46,98,10,99,76, +168,8,169,78,70,76,48,124,23,160,60,106,61,242,80,100,243,100,202,100, +202,218,200,230,186,236,163,238,154,186,100,186,100,140,156,140,157,185,20,48, +237,48,96,12,97,80,164,10,165,80,34,76,69,102,20,124,59,150,28,236, +65,176,80,96,241,96,158,186,104,186,104,136,158,136,159,184,200,96,200,228, +178,242,161,229,16,74,95,74,60,12,61,246,56,88,34,146,21,174,64,96, +101,136,146,14,187,44,102,58,245,58,164,70,120,128,177,124,202,96,170,142, +142,170,101,194,224,132,200,170,176,198,142,220,105,238,188,186,239,229,196,18, +132,34,100,36,47,36,14,102,231,102,126,36,127,242,118,106,94,142,70,168, +50,188,19,206,132,104,152,132,182,164,212,186,235,201,126,22,84,32,33,38, +20,92,139,92,84,34,85,244,80,102,56,146,27,184,88,118,129,152,154,218, +154,50,224,50,225,216,156,192,223,193,74,16,44,84,17,124,56,60,57,242, +86,46,247,46,210,46,210,222,190,240,167,224,162,162,104,162,104,98,162,98, +163,161,130,12,106,52,78,82,50,100,21,114,126,22,142,46,160,66,188,88, +214,104,239,114,70,112,191,112,68,246,68,156,196,156,197,244,70,224,195,225, +132,12,90,46,48,68,19,78,124,20,144,36,172,52,204,64,239,74,66,74, +191,74,188,142,68,142,68,106,188,106,189,140,14,232,241,232,56,230,56,172, +204,172,205,230,104,174,105,230,152,174,153,231,90,18,54,40,23,54,108,64, +64,96,19,118,36,68,55,98,68,52,83,80,66,94,88,128,94,160,94,200, +82,224,66,232,50,240,37,224,78,118,50,144,23,162,90,148,60,176,23,200, +158,14,140,50,123,78,144,42,212,42,194,76,166,104,138,124,111,136,148,68, +168,92,188,108,222,128,235,134,136,244,136,150,212,150,213,240,138,218,211,219, +50,18,79,48,36,48,37,242,98,34,218,34,218,224,202,238,183,230,110,56, +137,80,60,90,193,90,114,96,74,134,129,132,162,110,110,154,69,178,174,138, +144,170,110,196,69,216,140,176,183,209,30,22,73,52,16,84,61,114,26,234, +71,148,84,38,241,38,204,40,204,222,174,238,163,224,160,160,108,160,108,92, +162,92,163,161,38,22,79,52,24,80,63,112,22,228,69,142,96,238,96,30, +224,30,225,236,225,236,96,214,223,214,112,88,209,88,160,48,161,120,188,178, +130,178,130,126,188,126,189,177,26,56,117,56,76,10,77,98,16,100,119,100, +58,102,58,158,50,188,38,220,21,242,92,100,92,216,80,236,59,222,36,130, +19,178,102,130,121,164,128,52,231,52,180,8,181,92,128,98,241,98,164,98, +164,156,158,186,144,218,127,242,198,100,198,224,182,242,169,226,144,128,123,188, +212,132,241,183,46,16,83,46,16,74,84,74,64,108,40,134,21,152,62,114, +63,242,98,114,79,142,64,136,99,166,216,100,126,100,126,30,216,30,217,100, +126,66,215,66,146,110,107,150,126,134,234,134,226,222,216,240,195,228,176,148, +141,194,166,164,205,190,120,158,120,214,207,215,28,78,28,46,124,46,125,78, +78,12,54,88,38,114,17,142,46,106,47,246,74,70,95,90,54,104,133,104, +54,138,127,138,54,172,127,172,54,214,133,214,88,106,89,212,182,8,171,38, +192,116,214,116,226,108,226,46,152,46,152,146,236,146,232,224,222,236,191,230, +132,190,217,190,172,62,199,89,26,44,124,44,118,94,104,108,87,94,72,8, +66,62,56,82,42,98,25,110,224,94,158,94,158,36,224,36,225,94,70,206, +70,130,200,130,201,200,132,152,126,186,122,200,110,216,88,226,37,240,146,202, +237,239,30,204,30,44,70,44,71,194,30,172,71,172,214,108,104,108,104,32, +214,32,215,108,122,60,141,90,194,58,177,88,96,142,223,142,88,176,241,176, +158,32,159,176,108,194,85,240,140,198,151,234,176,194,187,230,204,192,233,233, +204,98,50,98,50,30,204,30,205,98,72,46,105,78,178,44,145,78,42,134, +215,134,16,174,241,174,128,30,129,172,56,190,25,238,94,190,115,234,146,186, +173,228,198,186,237,231,128,10,163,36,240,46,64,46,64,164,52,204,27,240, +20,78,49,106,20,158,59,136,104,148,204,148,204,76,98,76,98,240,149,204, +146,150,158,172,172,192,196,212,235,230,230,160,179,196,98,112,205,113,76,14, +44,56,21,76,88,66,46,116,19,142,58,104,59,246,120,126,212,126,212,28, +114,28,114,238,165,194,116,78,211,78,160,126,166,156,186,190,216,220,235,232, +232,142,181,177,94,24,56,68,38,82,19,94,20,26,60,66,72,90,80,116, +82,150,80,182,76,204,64,222,44,238,23,222,76,108,42,148,21,166,126,120, +210,120,210,28,120,28,120,240,167,192,120,74,211,74,162,120,170,152,192,194, +208,212,235,232,230,138,187,177,60,10,61,244,36,66,21,126,78,62,101,100, +124,122,214,122,214,28,118,28,118,238,169,190,118,74,213,74,162,122,172,154, +188,184,210,208,233,230,232,136,185,175,34,196,34,48,76,48,77,184,34,162, +75,162,142,12,177,40,92,50,245,50,214,116,118,116,118,82,214,82,215,116, +102,148,214,148,172,184,172,228,158,246,133,231,110,12,145,36,16,48,243,48, +192,120,62,120,62,78,192,78,193,118,27,152,24,152,200,152,132,188,132,228, +124,238,112,238,89,239,20,72,91,72,60,10,61,246,56,88,38,134,21,164, +62,98,93,132,100,42,237,42,140,10,141,82,192,8,193,80,96,84,247,84, +220,182,114,182,114,116,220,116,221,182,114,150,219,150,166,84,167,182,146,200, +93,240,180,202,233,239,66,18,40,58,25,78,70,82,44,124,19,154,52,114, +53,242,122,14,94,50,79,66,104,38,154,38,133,70,164,140,90,140,90,76, +164,76,165,140,92,108,163,108,128,76,129,140,74,176,181,176,126,150,114,202, +98,218,79,232,120,188,167,220,186,36,241,36,180,106,249,106,216,106,216,230, +194,242,177,229,60,8,61,244,34,66,19,126,80,58,97,104,100,30,239,30, +216,172,124,172,124,76,216,76,217,172,126,122,215,122,92,224,245,225,32,44, +227,44,120,10,46,86,211,86,18,116,239,116,130,56,131,138,40,168,109,222, +26,152,110,152,86,192,70,210,46,228,21,240,126,152,208,152,180,198,156,218, +117,238,140,152,148,172,166,196,188,214,237,235,34,198,34,44,78,44,79,184, +34,166,77,166,96,70,229,70,136,14,137,146,192,12,193,144,92,148,243,148, +136,172,106,212,75,238,182,172,233,235,34,70,21,138,64,18,64,124,58,168, +44,204,19,236,100,58,67,102,60,164,99,202,108,78,237,78,94,152,243,152, +142,18,143,150,198,16,199,152,152,176,126,212,95,240,184,180,239,241,104,148, +28,148,28,76,104,76,105,146,68,16,69,204,18,226,109,194,96,168,121,206, +124,44,233,44,116,226,243,226,180,44,181,227,30,28,65,56,18,94,55,116, +20,236,59,152,72,66,129,66,68,184,127,166,98,66,99,174,176,12,161,40, +164,66,189,86,182,114,194,114,206,110,212,104,214,98,216,46,144,46,144,146, +228,146,224,218,218,228,210,230,175,234,112,192,205,193,38,22,77,52,16,84, +55,112,28,228,67,140,90,70,231,70,80,142,241,142,128,14,129,140,192,10, +193,140,136,174,106,210,79,236,178,176,231,235,110,14,145,42,42,92,42,52, +218,52,219,90,18,116,239,116,124,72,88,152,62,180,27,208,138,142,72,240, +191,218,164,174,209,243,20,30,98,30,98,84,40,84,34,142,96,142,90,210, +84,222,74,228,58,230,39,230,174,16,122,224,219,198,194,122,231,231,70,18, +18,108,75,100,104,58,30,172,109,152,20,222,109,202,118,44,229,44,98,226, +241,226,172,46,173,225,28,188,28,40,66,40,67,182,28,162,67,162,122,18, +96,76,79,106,102,240,103,68,138,28,208,28,205,70,120,74,237,74,158,82, +125,140,142,112,225,112,118,160,235,160,180,114,166,180,148,208,125,230,174,162, +184,182,200,204,216,222,231,231,74,10,44,76,21,112,54,242,55,58,76,74, +241,74,108,28,194,28,183,74,120,88,102,122,89,140,108,112,217,112,80,160, +237,160,156,112,150,172,132,206,110,222,83,236,164,160,172,180,182,198,200,214, +220,226,237,237,24,30,54,66,62,90,68,114,70,150,70,180,64,218,54,230, +29,236,84,26,50,68,21,92,66,112,42,144,19,166,128,14,104,66,79,106, +108,244,109,58,146,32,216,32,211,76,126,78,247,78,160,90,142,126,127,142, +148,116,229,116,126,162,243,162,182,116,176,168,166,194,150,218,127,236,182,162, +192,190,208,210,222,224,239,233,34,188,34,38,74,38,75,182,75,182,34,160, +73,160,90,28,162,28,126,80,126,222,100,238,89,220,86,160,161,114,190,16, +190,218,192,226,196,230,204,232,218,230,226,222,235,207,236,34,46,34,46,110, +46,154,38,198,19,236,204,118,88,118,88,62,204,62,205,116,88,88,205,88, +76,144,198,144,146,178,146,224,140,234,126,236,111,236,60,190,243,191,72,12, +44,74,15,116,52,242,53,58,86,78,87,194,124,28,202,28,189,72,102,74, +243,74,138,86,120,128,111,144,224,110,131,110,104,164,239,164,172,110,164,174, +148,206,126,224,101,236,168,166,182,194,202,216,222,228,239,239,220,24,156,32, +122,34,54,34,54,136,44,184,23,224,244,90,57,90,94,240,94,142,206,142, +207,238,94,214,205,215,30,184,30,38,78,38,79,180,30,156,79,156,228,20, +172,32,116,36,101,36,106,64,141,108,222,58,191,108,92,134,245,134,166,34, +166,226,142,242,127,225,210,18,134,34,68,36,43,36,54,70,95,112,206,60, +165,114,12,134,245,134,136,36,136,226,118,242,89,225,94,12,66,62,35,94, +76,46,214,46,198,134,186,140,165,142,122,46,110,82,92,106,68,124,43,138, +166,46,162,78,148,108,132,128,110,142,89,152,52,172,27,226,120,162,155,196, +196,168,235,218,90,168,90,220,92,228,100,230,110,232,160,232,174,230,180,224, +184,216,189,203,16,36,89,36,20,108,81,108,18,204,83,174,52,36,53,186, +84,70,159,70,100,208,100,126,142,126,143,208,100,182,143,182,120,10,121,124, +196,228,210,228,220,226,224,220,224,28,176,28,176,158,172,186,160,212,147,232, +176,84,223,84,176,144,223,145,26,46,233,46,44,84,213,84,130,10,131,84, +34,152,34,116,226,116,227,154,56,156,83,196,204,154,171,200,16,226,239,226, +106,116,107,226,152,116,153,227,14,44,243,44,94,10,95,72,164,12,165,74, +42,232,42,156,108,156,109,222,109,222,42,206,109,206,16,116,129,116,76,80, +77,156,188,236,206,234,216,230,218,220,218,92,146,92,146,168,140,204,128,226, +113,242,146,132,219,132,146,176,219,177,16,66,133,66,38,220,38,124,110,124, +111,210,38,192,111,192,76,14,75,124,186,232,202,230,212,228,218,222,218,210, +218,30,146,30,146,168,138,194,130,220,113,242,146,90,219,90,146,146,219,147, +84,136,84,66,26,66,26,138,85,138,56,10,57,194,12,206,87,188,76,164, +93,208,96,74,163,74,132,12,133,126,108,214,108,132,152,132,153,210,108,194, +153,194,192,236,204,234,216,230,220,224,222,214,222,32,178,32,178,142,176,176, +170,202,151,240,178,92,223,92,178,154,223,155,86,24,44,74,19,94,22,28, +44,50,60,76,68,100,70,122,74,154,72,182,68,204,62,218,52,224,40,226, +31,226,68,114,48,138,34,152,15,166,220,26,168,34,118,40,118,142,112,172, +104,196,96,216,83,234,194,30,194,100,200,138,208,166,220,196,239,228,156,36, +150,228,187,206,176,180,197,223,14,102,93,102,56,12,57,246,18,44,35,82, +90,40,73,80,50,116,36,156,17,186,58,128,85,160,92,72,161,72,102,218, +102,130,148,130,149,212,102,194,147,194,126,16,127,130,196,232,210,232,220,228, +224,224,224,216,224,28,178,28,178,170,172,198,160,224,149,238,178,92,223,92, +178,154,225,155,30,26,71,50,20,88,59,112,22,226,61,148,72,70,155,70, +86,216,86,130,138,130,139,210,139,210,86,194,137,194,114,14,115,130,196,228, +212,228,218,224,224,220,224,214,224,28,174,28,174,158,168,184,156,210,139,234, +174,92,223,92,174,154,225,155,12,36,78,38,78,96,32,96,28,148,78,148, +70,216,64,224,50,230,40,230,27,230,220,26,182,36,156,40,138,42,120,44, +120,136,114,172,106,202,96,222,87,234,194,34,194,94,198,132,204,164,216,196, +226,218,233,230,154,40,154,68,152,124,150,166,148,186,140,224,187,210,174,186, +199,231,128,10,129,66,128,34,217,34,222,92,228,68,52,68,52,154,48,186, +38,216,29,238,74,112,207,98,130,78,128,124,130,130,136,136,150,138,176,138, +190,136,202,132,208,124,213,116,62,238,80,234,96,226,108,208,112,194,112,166, +174,166,174,216,174,222,176,228,182,232,192,234,208,234,218,232,224,228,230,220, +237,203,28,192,28,50,72,50,73,184,28,158,73,158,214,90,224,66,104,66, +104,172,94,204,88,216,78,228,69,238,216,36,159,36,158,66,159,12,120,110, +203,98,158,78,158,126,160,132,164,134,170,136,186,138,198,136,206,132,208,130, +219,118,108,240,130,220,140,202,142,190,142,166,188,166,188,220,192,224,196,228, +202,230,212,230,222,228,228,224,230,218,235,201,64,12,64,226,46,244,31,228, +16,74,101,74,22,158,99,120,154,16,187,44,222,156,222,64,130,64,130,148, +126,176,118,204,106,224,89,240,130,136,223,137,32,32,225,32,102,32,78,160, +173,160,92,94,182,94,169,218,16,222,239,223,44,24,85,58,20,84,65,116, +28,238,75,148,142,12,181,52,218,150,218,62,114,62,116,156,112,184,102,208, +88,230,77,242,116,134,219,135,100,12,153,44,214,158,214,62,68,62,68,158, +58,188,46,212,21,244,68,136,215,137,20,54,235,54,90,12,91,86,162,14, +163,86,104,96,52,148,21,172,74,246,75,128,216,108,134,176,105,192,146,94, +146,216,148,224,156,230,168,232,196,232,212,230,222,224,230,212,233,199,28,190, +28,38,72,38,73,186,28,158,73,158,138,12,106,72,89,92,124,148,125,42, +226,34,176,86,143,110,170,8,170,120,174,126,178,130,188,132,200,132,210,130, +218,126,224,120,231,108,88,176,241,176,160,142,161,245,94,18,70,54,42,84, +27,100,70,150,71,54,218,36,142,80,101,94,146,16,146,120,148,130,154,134, +164,136,208,136,220,134,228,126,232,116,237,104,24,180,245,180,134,144,135,245, +88,18,46,74,23,98,24,32,56,66,64,84,72,118,72,130,72,210,66,228, +54,234,38,242,31,226,18,174,48,142,71,112,100,138,100,100,238,100,239,136, +170,100,170,64,129,64,124,100,124,28,210,28,211,100,126,244,126,130,210,130, +210,232,192,244,177,226,126,162,211,162,126,194,211,195,32,20,73,52,18,82, +57,112,24,230,67,144,80,124,80,94,226,94,227,122,104,94,104,22,200,22, +201,94,156,94,156,56,105,56,104,242,104,124,202,124,202,224,188,242,167,228, +104,158,203,158,104,190,203,191,32,30,219,30,218,96,219,240,34,98,34,220, +219,214,178,174,72,174,72,72,178,72,179,174,72,120,179,120,124,72,125,175, +96,26,127,54,18,92,147,76,58,16,62,84,68,122,78,160,88,184,102,210, +116,224,124,230,136,234,142,232,155,200,130,112,110,152,90,180,66,204,31,230, +172,44,173,176,222,12,222,220,202,242,179,227,94,14,50,94,21,132,68,244, +69,66,226,62,172,122,132,156,97,176,148,14,148,210,150,222,156,228,164,228, +218,228,228,222,232,208,239,191,30,20,71,56,12,98,54,98,48,238,93,176, +220,18,148,34,109,36,86,84,243,84,166,30,167,140,118,244,118,142,216,142, +217,240,118,216,217,217,58,12,59,244,14,76,97,76,54,84,36,136,19,168, +60,108,91,138,222,130,114,130,114,48,222,48,223,130,164,12,145,46,114,90, +223,90,166,48,166,100,164,136,150,172,138,194,114,218,85,236,176,154,176,222, +178,228,182,232,186,236,194,236,220,236,224,234,230,230,234,224,238,220,241,214, +216,150,190,200,237,188,226,168,243,199,68,14,21,78,76,70,48,120,21,148, +54,248,55,112,100,242,100,34,222,34,223,240,100,216,223,216,182,162,136,162, +136,86,182,86,183,163,64,12,65,244,36,70,21,132,84,66,107,110,100,40, +243,40,178,40,170,74,146,120,128,146,91,184,168,244,169,78,190,116,239,183, +40,22,83,54,20,86,61,116,28,234,73,148,136,14,102,80,77,110,112,244, +113,62,160,20,193,56,120,66,239,66,120,118,229,118,120,168,229,168,120,220, +243,220,172,66,173,221,14,84,97,84,14,188,97,152,54,12,55,168,94,40, +243,40,178,40,142,126,112,170,81,198,164,244,165,76,186,108,241,185,18,44, +90,44,78,110,60,154,40,184,21,206,30,82,70,134,99,184,152,12,128,86, +107,122,210,110,224,70,135,70,164,98,158,152,144,184,116,216,83,238,162,124, +172,162,188,192,214,220,239,237,14,38,105,38,24,108,105,108,18,198,107,168, +64,38,65,182,114,38,237,38,176,38,164,92,144,136,124,168,93,204,168,246, +169,80,186,114,239,185,62,12,63,248,16,72,101,72,56,78,44,122,32,148, +19,168,66,102,101,140,106,28,237,28,218,174,124,174,124,76,218,76,219,174, +124,126,219,126,92,224,247,225,32,24,75,60,14,106,58,106,59,202,18,226, +38,214,50,206,58,206,72,208,86,214,102,220,132,226,200,226,218,224,239,220, +86,40,229,40,168,40,144,90,116,126,83,158,150,206,151,78,174,104,231,157, +70,14,18,94,69,92,92,60,24,158,89,148,14,206,89,186,226,20,186,26, +136,32,103,34,110,52,135,80,148,46,167,74,216,42,187,86,98,94,229,94, +94,128,239,128,148,94,138,140,122,178,98,206,73,230,110,238,142,224,172,204, +196,176,204,158,142,158,150,174,158,190,172,206,198,222,235,237,56,12,56,230, +38,242,23,226,14,70,91,70,16,150,87,116,146,10,126,48,105,76,132,40, +190,40,165,86,80,160,241,160,108,158,108,90,212,90,213,160,162,106,152,174, +142,192,116,220,85,238,160,162,176,192,196,218,231,239,202,78,54,78,54,42, +202,42,203,78,208,142,46,142,46,108,208,108,209,142,128,12,129,164,52,174, +21,226,122,174,149,200,194,170,239,214,84,172,84,220,86,226,92,230,108,232, +128,234,152,234,172,230,178,226,186,218,191,203,30,188,30,36,74,36,75,180, +30,156,75,156,148,8,122,48,107,66,132,36,194,36,169,80,86,156,243,156, +110,156,110,82,210,82,211,156,162,104,154,166,136,194,106,218,77,234,156,158, +174,182,194,204,214,220,233,231,18,66,35,104,128,14,157,36,238,46,60,46, +60,156,52,186,38,214,25,232,130,62,94,104,79,118,112,84,178,84,157,120, +70,178,245,178,104,178,104,122,210,122,211,178,156,138,146,188,130,210,104,228, +73,240,154,178,164,196,182,214,210,230,235,239,54,18,95,40,190,18,153,44, +34,54,221,54,18,88,239,88,130,12,112,66,86,102,60,124,23,148,154,88, +164,102,180,118,204,134,239,148,76,124,175,124,48,168,88,152,125,124,92,236, +110,238,124,234,140,220,142,204,138,178,128,158,116,148,107,138,122,158,88,180, +60,190,45,194,134,182,96,204,49,220,190,146,150,174,213,219,60,14,60,128, +56,158,48,184,36,208,15,234,32,72,21,130,94,62,63,98,56,158,95,198, +156,12,117,68,138,40,200,40,175,80,86,162,245,162,114,162,114,88,216,88, +217,162,166,106,156,176,138,208,118,226,89,242,164,162,182,194,204,218,237,239, +36,24,79,50,18,82,63,112,24,228,61,150,144,10,112,52,95,72,122,38, +194,38,163,82,74,158,241,158,100,158,100,88,210,88,211,158,156,104,148,168, +132,196,114,212,90,228,69,236,152,158,166,184,186,208,212,224,237,235,110,16, +143,38,32,92,32,50,222,50,223,90,204,88,58,88,58,232,223,232,58,136, +192,136,192,178,59,178,134,88,135,136,134,178,135,233,76,16,20,126,87,112, +114,62,28,216,119,198,98,152,131,224,126,54,220,52,216,208,204,228,184,236, +157,237,14,40,239,40,94,10,95,68,168,10,169,66,116,56,145,76,30,90, +229,90,212,132,64,132,65,90,76,150,68,190,52,216,21,238,126,152,127,236, +176,148,176,218,178,226,184,230,194,232,210,232,222,228,226,222,235,205,56,14, +57,244,28,66,19,124,70,62,87,100,86,46,239,46,130,12,131,74,194,12, +195,72,154,68,173,86,96,96,233,96,116,96,116,136,219,136,120,154,116,200, +106,218,85,238,158,156,159,234,196,150,196,226,198,230,206,234,218,234,230,232, +234,224,238,216,241,201,38,46,219,46,16,82,241,82,96,10,97,82,162,10, +163,82,200,188,60,188,60,116,200,116,201,188,128,82,129,188,60,150,201,150, +102,200,35,238,158,200,227,237,16,52,91,52,62,52,48,102,30,130,19,142, +44,218,44,114,82,114,83,212,44,190,83,190,102,46,235,46,90,90,245,90, +140,14,141,90,186,10,187,90,216,186,114,186,114,120,216,120,217,186,114,154, +217,154,164,90,165,186,144,200,120,226,95,240,186,202,233,239,92,142,32,142, +32,66,94,66,95,142,62,8,63,202,16,212,101,194,90,168,113,212,220,108, +126,108,126,42,220,42,221,108,172,10,155,42,126,74,221,74,114,146,233,146, +122,188,227,188,104,232,245,232,174,146,175,231,74,14,48,50,23,74,58,38, +131,38,76,38,93,58,168,14,144,48,125,66,154,36,241,36,176,36,195,66, +42,88,213,88,16,116,243,116,96,70,97,116,162,64,163,116,198,196,66,196, +66,142,198,142,199,196,199,196,66,168,199,168,132,116,133,196,104,208,68,228, +44,238,29,242,156,204,223,241,206,120,52,120,52,44,206,44,207,120,112,12, +99,44,52,82,207,82,34,150,225,150,44,188,213,188,18,230,239,230,130,150, +131,231,14,234,34,202,44,168,48,144,50,120,50,26,206,26,202,98,202,132, +204,162,206,196,216,220,222,232,228,236,232,234,241,210,168,126,84,126,84,68, +168,68,169,126,122,36,109,68,84,98,169,98,72,156,183,156,80,190,173,190, +58,226,191,226,126,156,127,227,56,246,57,14,30,72,17,128,78,66,95,110, +216,110,118,110,118,42,216,42,217,110,168,12,159,42,118,74,217,74,102,146, +239,146,112,188,225,188,86,232,245,232,166,146,167,233,20,232,42,202,54,176, +60,148,62,126,63,18,34,66,23,132,102,66,63,110,100,198,61,154,216,120, +120,120,120,48,216,48,217,120,166,12,155,48,120,82,217,82,98,152,237,152, +112,190,227,190,92,232,245,232,168,152,169,233,202,88,56,88,56,26,202,26, +203,88,56,56,203,56,22,150,235,150,130,96,131,148,56,102,95,132,198,102, +157,136,102,150,100,178,92,196,68,218,44,228,29,234,148,150,148,214,152,222, +158,226,172,228,196,226,210,224,222,220,228,206,231,199,56,242,57,10,26,196, +26,60,92,60,92,184,80,192,71,178,212,90,126,90,126,26,212,26,213,90, +126,58,213,58,106,150,239,150,168,98,169,150,116,106,143,132,222,104,195,134, +148,150,146,176,140,196,126,212,112,226,89,236,184,150,184,220,186,226,196,230, +220,230,226,226,230,220,234,210,239,203,58,16,59,244,30,68,19,122,74,64, +93,98,90,114,241,114,160,12,161,114,98,40,133,84,216,34,185,88,140,114, +140,146,136,176,126,200,116,214,91,236,180,114,180,214,182,220,188,224,196,226, +206,226,220,226,228,220,234,210,237,193,34,22,73,58,10,96,56,96,56,228, +87,178,86,44,239,44,128,10,129,76,192,8,193,76,148,66,173,86,80,96, +239,96,114,96,114,134,221,134,122,154,116,186,108,210,98,226,85,238,158,156, +159,238,196,152,196,232,212,234,226,230,232,222,239,211,22,54,241,54,90,10, +88,80,80,120,70,158,56,186,38,208,21,226,112,104,95,162,208,106,185,156, +152,74,148,142,138,178,116,206,90,224,63,236,150,142,160,168,184,200,214,220, +237,233,60,8,60,230,40,240,27,224,14,66,85,66,16,144,89,110,102,64, +102,26,220,26,221,64,94,82,231,82,156,44,100,142,225,136,88,182,241,182, +168,102,169,245,24,38,47,78,110,40,89,78,68,12,69,104,18,106,113,106, +52,106,52,160,42,196,19,228,84,106,84,214,115,160,124,68,124,30,234,30, +235,66,118,84,237,84,176,50,124,144,152,138,233,138,118,184,245,184,182,104, +183,247,64,16,19,74,64,76,36,124,15,146,42,114,43,244,120,14,121,70, +84,30,84,70,155,70,156,30,157,70,76,96,157,96,116,104,76,136,113,134, +136,120,76,170,143,166,134,148,155,176,116,168,116,230,104,244,95,228,94,188, +71,224,134,188,151,210,194,14,174,90,161,118,177,80,176,78,243,78,214,78, +210,120,202,160,182,200,149,236,174,124,184,164,198,196,216,216,241,237,30,68, +17,122,74,64,91,104,58,12,59,244,94,58,235,58,140,12,130,78,112,130, +81,172,172,80,166,152,154,186,126,216,91,236,168,136,178,164,196,198,218,220, +243,236,142,114,127,164,218,110,197,153,96,138,34,138,34,62,96,62,97,138, +66,12,67,198,16,212,97,190,86,166,105,210,126,242,126,34,226,34,227,240, +126,218,227,218,194,168,156,168,156,82,194,82,195,169,40,236,40,34,214,34, +215,232,40,208,213,208,164,154,90,154,90,82,164,82,165,155,60,18,28,30, +28,112,110,112,110,34,91,34,28,70,47,70,84,70,111,70,91,34,130,106, +144,90,150,72,150,24,202,24,202,80,202,90,208,94,220,94,239,90,16,150, +119,150,12,218,121,192,66,150,67,204,124,126,210,126,192,166,170,196,136,222, +93,240,140,126,148,156,164,186,186,208,206,220,235,233,32,66,19,128,76,62, +93,108,54,10,55,246,142,14,126,42,114,62,103,76,122,48,239,48,76,142, +245,142,152,102,175,126,150,158,173,184,238,204,110,204,124,84,212,84,206,228, +178,246,163,231,26,40,121,40,32,66,119,66,22,92,123,92,82,14,83,108, +136,40,233,40,140,64,227,64,134,92,237,92,178,14,179,106,46,120,206,120, +206,172,47,172,54,146,207,146,48,194,23,232,122,184,147,210,202,188,239,228, +90,186,90,224,90,230,96,232,108,234,158,234,168,232,174,228,178,222,183,207, +32,58,223,58,130,12,131,108,16,144,241,144,80,90,80,144,76,176,66,210, +39,242,180,88,181,245,22,42,235,42,198,128,60,128,60,72,198,72,199,128, +60,98,199,98,36,162,201,154,186,136,219,172,130,10,131,158,54,188,21,232, +120,172,149,202,198,188,239,224,88,174,88,220,90,228,96,230,102,232,158,232, +170,230,178,226,182,220,187,207,26,216,26,44,72,44,73,212,26,112,73,112, +26,186,73,186,136,14,102,74,87,92,116,50,231,50,148,102,177,130,146,162, +173,188,90,144,239,144,238,204,110,204,118,88,204,88,200,222,194,234,176,240, +161,227,36,172,36,32,98,32,99,168,68,70,68,106,66,142,60,178,46,206, +21,234,78,184,113,224,112,50,247,50,176,12,152,78,134,106,117,124,146,244, +146,96,222,96,222,224,218,234,206,236,195,236,146,138,223,138,146,176,223,177, +102,24,52,34,27,38,18,90,109,90,70,30,71,244,70,92,44,148,23,182, +70,110,105,144,120,24,120,74,230,74,231,20,174,8,175,74,162,86,128,148, +103,176,144,120,228,120,204,170,178,200,142,222,95,238,146,152,183,193,130,12, +76,72,17,110,122,22,156,58,194,84,237,104,66,108,185,108,22,154,225,154, +120,164,44,232,189,220,150,182,211,241,30,66,17,132,62,12,60,90,60,140, +50,192,23,242,96,48,61,98,100,200,59,156,166,8,138,68,116,94,93,114, +160,20,186,64,216,92,241,106,124,108,213,108,108,154,235,154,164,162,114,230, +211,218,184,186,227,237,40,16,83,52,24,78,67,114,26,230,71,142,230,36, +104,36,104,218,235,219,38,32,71,74,16,108,58,108,52,224,99,186,88,54, +235,54,98,100,221,100,84,146,226,146,224,198,218,206,210,208,191,210,158,14, +159,247,36,22,75,58,12,98,56,98,52,232,91,188,142,10,112,52,83,78, +118,44,235,44,84,142,243,142,148,102,173,126,148,160,173,186,236,202,114,202, +120,84,210,84,204,226,198,234,190,236,169,239,66,20,14,104,71,98,96,56, +28,168,99,156,16,228,97,202,168,14,134,74,97,112,162,26,180,54,202,80, +239,104,126,114,211,114,110,156,233,156,162,166,116,234,213,218,190,190,231,239, +14,40,239,40,90,10,91,68,166,10,167,68,32,120,32,82,224,82,225,120, +50,118,205,118,122,94,50,164,203,164,14,200,241,200,132,130,133,249,192,18, +138,28,72,34,44,34,44,138,121,102,44,76,231,76,134,28,138,54,144,82, +158,104,178,124,200,134,210,134,218,128,224,118,231,104,58,244,58,146,190,146, +191,242,58,184,191,184,58,222,191,223,60,6,32,148,72,176,101,202,8,72, +86,72,72,152,46,194,19,226,222,18,146,28,116,30,116,128,169,102,116,72, +241,72,174,24,182,78,190,98,204,118,218,126,228,126,232,122,243,106,122,244, +122,140,212,140,213,242,122,182,213,182,122,222,213,223,18,48,93,48,12,102, +99,102,58,112,18,196,89,182,72,146,97,198,156,12,137,46,210,136,114,136, +114,48,210,48,211,136,114,90,211,90,162,48,162,96,158,140,146,176,132,200, +110,222,81,242,170,150,170,226,172,230,178,234,188,236,196,236,216,236,228,230, +234,222,239,212,208,148,186,194,227,184,218,166,235,197,40,20,77,50,16,82, +61,108,34,222,75,138,98,66,98,28,226,28,227,66,88,84,235,84,156,44, +104,138,223,138,82,182,241,182,164,244,165,103,32,20,75,50,16,82,59,112, +26,236,69,150,208,106,102,106,102,28,208,28,209,106,102,70,209,70,100,126, +100,238,149,212,100,166,155,166,172,122,172,222,174,230,180,234,188,236,218,236, +226,232,232,226,239,210,224,148,173,177,56,14,85,40,18,82,18,50,120,50, +121,82,30,84,111,84,34,110,111,110,18,138,125,138,74,64,75,154,38,240, +38,166,112,166,113,238,38,216,113,216,166,22,135,74,192,24,231,62,180,66, +154,122,123,154,174,76,194,110,214,132,239,148,152,244,152,154,212,154,213,240, +152,218,213,219,34,20,85,48,18,78,63,106,26,230,81,148,218,18,154,32, +103,38,84,86,243,86,112,242,112,142,214,142,215,240,162,32,163,142,112,214, +213,215,72,14,48,70,17,116,52,64,53,244,112,66,93,136,224,66,187,128, +158,10,158,112,146,156,134,184,108,214,79,234,156,122,172,160,190,188,214,216, +241,237,64,66,50,110,39,138,204,62,165,124,126,12,122,98,114,138,98,172, +76,196,56,212,17,232,122,98,136,138,154,166,176,190,200,210,233,229,16,44, +241,44,92,10,93,70,166,10,167,72,36,84,62,106,78,126,86,154,88,184, +82,208,70,226,54,232,37,236,90,82,50,120,25,136,80,134,52,166,23,190, +100,136,233,136,158,82,158,136,150,168,136,198,120,218,91,238,158,142,168,166, +182,192,200,212,231,236,182,92,209,117,16,66,231,66,140,10,144,86,152,132, +162,170,180,204,194,220,206,228,212,232,218,232,220,230,233,202,110,158,46,158, +46,104,110,104,111,158,18,212,127,190,206,98,182,162,160,200,113,236,174,20, +207,49,12,54,233,54,172,18,201,42,142,12,146,64,154,96,166,130,186,150, +202,162,214,166,222,166,228,164,232,158,237,140,202,80,174,126,139,162,114,118, +44,118,44,86,114,86,115,118,18,160,131,140,50,190,21,240,114,166,141,202, +190,182,227,222,84,182,84,224,86,232,92,236,100,238,104,238,156,238,164,236, +172,230,176,224,181,209,44,24,225,24,40,90,40,50,228,50,229,88,132,24, +133,98,58,74,113,74,58,96,111,96,154,74,205,74,154,98,203,98,82,110, +50,150,25,176,66,132,67,246,124,110,161,128,74,136,227,136,74,164,217,164, +74,196,215,196,74,226,239,226,138,136,139,227,94,12,54,56,21,78,72,36, +73,112,216,26,162,56,105,72,146,10,146,84,146,94,154,98,166,100,172,100, +204,100,216,98,226,88,230,80,233,72,66,200,66,130,198,130,199,198,132,152, +122,186,114,204,98,216,74,228,41,236,148,196,227,235,44,14,83,48,16,74, +92,74,80,100,64,122,46,140,21,162,62,126,63,246,64,124,99,158,220,84, +126,84,126,28,220,28,221,84,118,244,118,122,232,122,232,230,214,240,199,224, +174,84,172,132,162,162,139,196,172,144,213,189,36,64,219,64,14,120,241,120, +52,146,52,228,203,220,202,146,203,244,126,12,127,225,14,80,97,80,12,182, +101,152,58,14,59,164,96,34,202,34,174,110,216,110,202,150,172,198,140,222, +107,236,130,34,130,78,128,114,122,154,108,186,88,208,61,232,142,112,154,154, +174,180,198,206,237,233,30,46,223,46,16,138,237,138,76,10,77,138,178,8, +179,138,76,74,179,74,76,104,179,104,88,138,76,160,48,186,19,200,166,138, +178,154,192,170,210,182,239,194,66,190,191,190,130,154,131,230,44,232,221,233, +64,244,65,12,14,76,111,76,62,76,40,132,17,170,64,102,101,140,88,236, +110,214,122,188,132,158,134,132,134,38,200,38,200,154,198,192,198,228,202,232, +212,232,222,232,232,228,234,220,236,212,239,199,26,210,26,40,96,40,97,208, +26,112,97,112,26,184,97,184,60,40,61,184,114,46,227,46,164,10,162,50, +154,70,138,86,119,96,160,56,221,94,110,114,237,114,206,114,206,218,200,234, +190,242,169,226,172,200,128,200,128,146,172,146,173,201,94,24,62,32,34,36, +21,36,18,84,95,84,58,34,59,244,58,92,32,154,19,174,58,104,93,146, +94,48,237,48,180,16,209,34,152,8,142,56,134,74,118,90,95,104,174,48, +174,76,174,82,180,88,188,88,200,90,216,88,226,86,232,80,239,66,118,96, +118,134,120,138,124,142,130,142,166,144,198,144,216,142,224,138,228,130,231,122, +212,108,152,116,119,120,120,244,120,166,216,166,217,240,120,196,217,196,120,222, +217,223,106,22,64,32,40,34,25,36,16,86,115,86,64,32,65,244,64,96, +38,152,19,182,64,110,107,146,220,128,134,128,134,30,222,30,223,128,154,154, +122,206,97,232,192,156,241,231,72,10,48,50,25,72,58,36,127,36,84,36, +101,64,162,10,140,46,125,66,148,36,239,36,180,36,197,58,34,92,225,92, +16,190,241,190,78,70,79,190,180,66,181,190,78,124,181,124,78,158,181,158, +102,202,68,226,43,240,158,204,213,239,18,226,28,202,36,146,36,26,90,26, +90,210,84,218,74,220,63,220,36,82,91,82,36,138,91,138,104,234,122,212, +130,194,136,156,138,136,138,28,198,28,198,212,202,220,210,224,220,224,226,224, +232,220,238,214,245,203,58,14,32,74,17,100,40,60,104,60,89,100,56,98, +56,222,103,172,102,240,116,228,124,216,134,190,140,160,142,146,142,34,204,34, +204,120,200,204,202,218,204,224,206,228,212,230,220,230,228,228,234,222,236,216, +241,197,26,32,67,60,12,112,56,112,57,208,20,232,32,220,44,212,52,210, +60,210,74,212,96,220,122,228,146,230,241,228,128,14,165,42,78,56,233,56, +132,56,132,108,130,132,124,160,116,182,106,196,101,204,176,56,176,188,172,198, +162,202,151,200,110,100,92,140,79,160,196,100,233,157,34,22,71,48,20,84, +59,110,20,232,59,148,114,12,101,42,138,102,84,102,84,44,138,44,139,102, +84,74,139,74,102,114,123,128,68,140,155,140,96,140,96,162,90,190,74,218, +61,232,96,170,140,170,136,208,130,218,120,220,109,220,188,12,168,76,149,120, +170,74,241,74,210,74,206,126,200,150,186,192,162,222,141,240,168,116,180,158, +192,188,210,210,233,235,32,20,73,58,12,98,56,98,54,212,93,160,84,236, +102,218,116,192,120,166,120,150,120,34,190,34,190,226,200,232,222,232,230,224, +234,216,237,201,26,54,98,54,92,104,78,148,56,182,23,216,38,92,103,182, +174,112,188,112,202,110,208,104,212,98,214,94,214,42,136,42,136,146,230,146, +228,212,220,228,208,236,194,238,177,236,112,190,209,190,158,62,183,86,168,10, +151,43,16,84,88,84,84,128,78,158,66,186,48,212,23,236,60,20,32,158, +101,210,236,40,118,40,118,226,245,226,216,166,216,96,154,96,154,168,217,168, +182,40,183,96,182,168,183,227,64,12,20,98,71,88,94,48,30,158,99,148, +16,210,101,186,210,60,132,60,132,18,210,18,211,60,98,92,243,92,94,210, +245,200,130,92,131,206,206,92,207,244,130,130,207,130,130,166,207,167,72,16, +18,102,75,96,96,64,26,166,101,150,20,218,101,196,102,42,239,42,112,72, +227,72,96,104,245,104,166,10,167,104,122,204,122,136,216,136,217,204,168,154, +162,194,152,212,130,228,110,236,89,240,176,204,235,239,18,58,237,58,126,12, +127,110,38,112,217,112,60,246,60,154,194,154,195,244,60,222,195,223,60,12, +61,246,16,74,103,74,60,80,38,144,19,174,60,94,97,136,100,34,208,34, +180,110,224,110,202,168,176,200,146,222,123,238,138,34,136,94,132,138,122,174, +108,198,87,226,136,92,148,124,162,158,178,182,210,216,239,235,16,50,113,50, +70,10,71,246,34,146,34,84,108,84,108,132,104,138,96,140,91,140,70,126, +50,162,17,206,70,146,101,182,122,48,239,48,176,8,177,246,140,148,140,84, +216,84,216,134,210,142,199,130,176,126,158,160,136,192,115,214,176,136,188,156, +214,190,239,215,12,56,113,56,68,14,30,132,111,132,16,196,121,172,76,86, +77,244,210,66,136,66,136,26,210,26,211,66,104,92,245,92,106,208,249,198, +136,92,137,206,208,92,209,242,136,130,209,130,136,164,209,165,70,12,40,56, +23,74,54,40,129,40,82,40,99,68,164,12,127,74,148,38,239,38,176,38, +191,68,32,96,111,96,36,126,105,126,24,158,117,158,76,72,77,248,72,160, +44,198,19,220,76,172,107,200,122,98,231,98,120,134,243,134,152,72,153,134, +198,74,199,134,136,248,136,164,214,164,215,246,136,196,213,196,136,230,215,231, +82,10,50,64,25,92,122,10,159,34,72,46,225,46,64,44,65,152,72,76, +211,76,70,104,211,104,72,134,231,134,136,46,137,134,22,166,243,166,134,146, +135,242,124,166,104,186,76,208,31,228,142,166,160,184,192,204,216,216,235,221, +36,32,188,32,140,106,198,106,170,160,130,200,53,236,94,32,94,74,88,108, +80,136,60,174,21,212,92,90,112,134,134,166,170,198,204,216,239,233,110,14, +72,58,25,94,80,48,166,48,147,80,56,86,200,86,200,154,55,154,60,118, +201,118,56,176,23,230,118,168,151,198,196,174,239,220,94,180,94,218,96,226, +102,232,110,234,122,236,140,236,156,234,170,232,180,224,184,216,187,209,120,16, +159,42,18,70,43,108,14,154,55,130,240,54,60,54,60,90,60,122,56,176, +44,210,21,242,126,68,108,104,83,134,110,104,219,104,76,158,241,158,156,104, +154,150,144,178,124,208,98,226,71,238,154,158,164,180,178,198,208,218,237,233, +32,18,73,46,16,78,59,104,18,228,59,142,84,32,194,32,164,108,208,108, +192,150,174,178,152,200,126,218,97,232,114,32,114,88,108,134,96,170,78,204, +51,228,132,108,144,144,158,172,180,198,208,216,235,229,38,136,112,136,112,30, +38,30,38,220,101,178,82,154,123,212,38,82,113,82,184,194,202,194,214,192, +216,184,218,176,218,36,156,36,157,247,12,74,78,74,72,142,54,182,19,220, +54,16,30,150,91,198,164,14,195,36,238,46,126,46,126,146,120,176,108,210, +83,238,94,78,119,108,86,158,127,132,164,70,143,128,154,98,229,98,140,150, +241,150,186,98,186,156,176,188,156,216,129,236,186,158,198,184,214,210,239,233, +68,18,18,94,77,90,96,64,26,158,99,150,16,210,95,184,98,34,204,34, +178,108,212,108,202,150,188,178,176,196,154,214,119,236,140,34,138,88,130,136, +116,178,100,208,77,232,144,122,158,154,172,176,188,196,208,212,235,229,56,10, +56,232,36,242,23,226,12,72,87,72,14,152,87,110,144,12,173,34,92,50, +231,50,120,66,138,84,154,98,180,112,212,126,241,132,198,50,186,68,166,94, +142,112,118,126,89,140,136,140,130,196,124,212,112,226,99,238,196,136,197,245, +20,236,52,214,72,190,82,164,86,134,86,34,170,34,170,216,176,224,186,230, +200,230,222,226,230,220,236,206,241,187,128,10,112,66,88,96,50,118,17,130, +120,40,134,62,154,82,178,100,210,114,239,122,36,22,95,40,28,78,93,62, +218,24,155,42,158,60,221,80,66,240,66,120,188,120,188,216,184,226,176,230, +155,232,66,154,189,154,66,186,189,187,38,32,196,32,196,108,52,108,52,202, +52,214,58,222,68,224,76,226,142,226,186,224,206,220,214,214,218,206,227,189, +20,44,241,44,100,12,101,68,164,12,165,70,74,68,44,104,21,124,60,86, +114,86,97,112,136,186,50,186,50,118,136,118,137,186,50,152,137,152,94,118, +95,186,34,228,149,218,180,90,181,190,220,70,220,224,216,232,208,236,189,241, +62,12,62,220,56,232,44,236,33,236,16,72,95,72,16,158,93,120,102,60, +239,60,170,10,171,112,104,114,214,114,204,144,188,174,158,204,126,224,91,238, +124,114,132,136,140,158,154,176,172,198,204,222,237,237,104,16,105,78,30,40, +105,40,22,74,105,64,152,12,152,62,154,68,162,70,178,70,206,68,218,64, +226,58,233,48,216,28,182,36,153,40,202,140,54,140,54,90,202,90,203,140, +54,114,203,114,126,90,127,140,36,166,223,166,92,140,93,190,16,192,243,192, +164,140,165,192,104,202,68,224,37,242,150,202,219,239,202,16,170,24,124,30, +82,32,51,32,18,70,235,70,128,30,129,124,114,70,94,92,70,110,42,128, +19,138,142,70,152,86,170,100,202,118,235,132,60,138,176,138,144,160,130,166, +130,236,104,244,87,230,20,186,235,187,82,14,46,80,17,120,62,244,63,52, +92,60,245,60,168,8,169,110,100,114,218,114,198,156,174,190,142,216,118,226, +97,236,124,114,132,134,140,154,152,172,166,186,188,204,218,220,241,229,82,12, +66,38,48,62,29,80,62,44,116,44,106,70,90,92,66,116,40,136,21,148, +68,68,91,88,44,90,67,114,142,20,152,54,168,82,184,102,212,124,237,138, +148,42,210,42,177,92,88,118,181,118,46,158,223,158,134,158,134,232,126,240, +118,242,103,242,90,184,58,206,27,226,166,184,223,227,82,14,107,40,24,50, +161,50,130,50,118,72,104,90,80,110,54,124,19,138,54,74,114,104,155,130, +68,138,68,180,60,204,48,224,31,236,122,136,123,238,182,44,183,180,224,12, +224,222,210,240,183,227,56,10,57,246,30,66,15,126,72,64,91,102,214,16, +176,26,136,30,109,32,96,68,233,68,162,28,163,118,158,68,138,90,110,112, +83,126,166,68,176,84,202,104,224,118,237,122,114,134,194,134,166,158,162,172, +162,222,160,230,152,236,146,238,133,238,86,178,239,179,34,26,77,60,16,92, +59,122,24,236,69,154,138,12,173,42,88,54,241,54,114,72,136,90,168,110, +204,124,241,134,202,54,194,72,180,86,164,102,146,114,114,132,83,142,134,140, +132,174,128,198,116,218,102,232,89,242,196,138,197,245,108,16,147,38,32,84, +32,48,220,48,221,84,72,70,73,144,18,146,133,146,72,104,123,104,76,146, +76,226,72,238,62,242,47,228,52,170,25,220,100,170,127,202,128,96,202,96, +194,134,180,170,160,200,134,222,107,240,148,96,150,118,156,150,166,174,182,196, +206,216,233,237,28,20,77,56,10,102,56,102,50,226,103,186,90,98,247,98, +168,8,169,249,36,26,79,66,8,104,60,104,58,222,103,188,104,38,212,38, +212,112,126,112,126,212,126,220,130,224,138,226,142,228,210,228,220,226,228,218, +232,210,237,195,38,122,96,122,96,36,36,36,36,222,99,174,80,148,113,192, +36,80,97,80,114,34,227,34,134,64,120,120,229,120,170,34,168,104,158,152, +144,186,120,218,93,242,182,140,182,218,184,230,190,232,194,234,218,234,224,232, +230,226,234,218,239,207,42,36,194,36,194,80,60,80,60,122,60,128,66,134, +72,136,78,136,184,136,200,134,212,130,218,122,220,116,225,102,50,168,25,228, +120,156,153,192,194,168,237,216,82,162,82,218,82,224,86,228,90,232,98,234, +156,234,166,232,174,226,180,220,184,214,189,203,56,182,80,178,86,170,86,152, +84,136,76,118,62,96,88,30,32,30,33,242,112,34,225,34,98,100,239,100, +164,100,164,210,162,224,156,230,144,232,129,232,132,146,110,186,93,208,194,148, +237,203,64,14,44,114,32,154,99,206,14,84,92,80,88,124,78,158,60,194, +38,218,21,234,108,62,237,62,112,116,212,116,198,152,180,182,152,206,122,224, +91,238,128,116,134,140,152,170,168,190,190,208,216,224,237,234,172,10,173,117, +64,20,40,66,16,100,69,94,90,62,22,164,95,150,16,220,97,200,134,40, +157,86,224,36,203,82,130,108,239,108,180,12,181,212,178,110,154,158,131,190, +180,124,235,182,114,38,114,230,243,231,72,20,22,104,79,102,108,58,36,162, +111,156,20,220,115,200,122,38,212,38,212,124,136,124,136,208,136,218,138,226, +142,230,148,234,154,236,158,236,200,236,210,234,222,228,226,220,233,203,28,36, +229,36,40,64,217,64,130,12,131,64,196,116,62,116,62,90,196,90,197,116, +14,150,241,150,78,128,103,148,176,124,149,150,28,180,122,180,120,224,114,232, +106,234,91,236,78,158,72,184,70,202,58,218,46,230,33,240,152,244,152,180, +210,180,211,240,152,220,211,221,60,8,61,242,18,74,91,74,60,78,40,132, +19,168,60,98,95,136,96,66,162,66,156,208,152,214,144,220,132,222,123,224, +124,12,122,66,122,96,120,126,116,158,108,184,98,208,83,232,188,226,188,54, +232,54,233,224,188,204,233,205,38,56,219,56,58,78,89,120,190,76,167,120, +20,136,233,136,128,12,128,74,126,108,120,148,102,180,80,204,54,222,29,236, +122,136,136,160,154,186,166,198,188,214,210,224,231,233,78,18,52,78,36,108, +19,126,56,246,57,76,98,58,229,58,82,112,245,112,162,10,163,112,94,166, +231,166,82,222,247,222,164,126,165,223,104,14,137,38,28,84,28,50,218,50, +219,84,50,84,197,84,34,140,64,128,88,112,108,96,123,84,96,106,114,120, +126,132,134,146,140,172,142,194,140,214,136,228,124,236,110,238,99,236,118,124, +84,154,58,170,35,182,134,156,112,180,88,198,56,214,31,226,200,110,137,150, +226,220,204,206,186,190,172,168,168,152,167,133,18,70,120,70,120,102,118,140, +114,206,110,212,106,220,94,222,83,222,72,12,72,70,70,104,66,138,60,170, +54,196,40,220,25,240,162,230,162,52,226,52,227,226,162,194,227,195,14,48, +241,48,92,16,93,82,166,12,167,82,40,98,213,98,124,64,124,100,124,130, +120,162,106,188,82,212,52,228,23,238,22,156,233,156,62,114,93,142,184,110, +155,144,232,236,196,222,172,206,152,190,136,170,125,157,20,54,117,54,14,136, +123,136,28,80,49,112,112,74,93,114,72,12,72,72,70,112,68,148,60,184, +44,212,21,238,68,156,115,208,120,32,241,32,140,188,140,82,220,82,221,184, +178,32,169,82,180,108,180,130,178,156,176,180,166,200,150,220,123,240,190,196, +239,237,16,34,235,34,210,110,44,110,44,66,210,66,211,110,100,34,101,110, +156,34,157,110,60,204,60,140,196,140,197,200,126,160,122,184,110,204,92,220, +66,230,42,236,23,238,138,198,227,239,46,170,46,24,214,24,215,166,46,88, +213,88,46,144,213,144,128,24,129,239,66,14,38,64,19,88,106,58,43,58, +30,102,97,102,18,148,107,148,62,102,62,228,103,198,126,184,126,34,230,34, +231,180,126,98,231,98,126,162,231,162,176,242,177,35,66,12,40,82,17,122, +50,242,51,58,92,244,92,26,144,26,144,82,93,82,140,134,93,134,144,184, +93,184,166,26,216,26,216,84,167,84,152,130,218,130,208,166,192,196,166,216, +133,238,166,130,168,150,182,180,204,210,222,224,239,233,90,30,54,36,21,40, +58,36,59,246,16,96,95,96,56,100,36,150,17,188,58,110,91,146,146,14, +187,38,108,80,108,50,230,50,231,82,124,84,213,84,164,84,150,104,136,116, +120,124,105,132,144,110,158,128,170,146,174,168,178,196,174,216,166,230,152,236, +138,238,133,238,158,130,122,164,91,182,170,158,144,182,118,204,91,220,224,100, +169,142,190,126,198,154,208,174,222,198,239,215,74,16,52,68,40,86,17,116, +52,246,53,72,158,10,142,46,124,74,102,96,79,116,154,20,164,42,182,62, +204,84,224,96,241,108,128,110,128,178,122,202,112,220,87,240,196,108,197,247, +24,44,120,44,116,90,114,100,110,108,102,110,92,110,85,108,74,8,70,56, +62,80,46,104,27,122,216,104,158,104,158,38,216,38,217,104,14,150,239,150, +126,118,127,244,118,152,92,180,72,196,50,210,25,222,132,152,148,168,168,186, +196,206,231,225,20,40,130,40,124,72,120,84,114,88,106,90,95,90,78,8, +72,48,64,70,48,90,27,108,224,84,160,84,160,32,224,32,225,84,88,132, +82,170,224,170,220,220,212,228,200,232,190,234,173,232,52,116,190,116,185,170, +30,202,195,203,12,78,82,76,76,144,58,194,19,234,58,14,30,160,91,202, +144,10,177,36,106,84,106,48,224,48,225,82,122,80,209,80,162,80,150,100, +126,120,103,136,140,108,160,138,172,158,174,182,174,208,168,226,156,234,137,236, +154,134,120,166,97,182,168,156,140,188,116,210,93,224,222,104,167,148,190,130, +196,150,202,168,212,188,224,204,237,215,20,36,115,36,60,36,56,70,44,106, +19,142,52,88,104,88,100,124,92,154,76,184,54,210,29,232,52,130,91,154, +226,20,190,30,154,36,129,36,116,118,247,118,178,34,179,245,106,12,139,36, +38,84,38,48,218,48,219,82,58,84,199,84,126,58,114,94,98,110,80,122, +57,132,116,92,199,128,18,142,239,142,190,142,190,220,188,226,184,232,176,236, +155,236,138,210,64,210,64,176,138,176,139,211,56,30,57,132,102,14,103,144, +164,14,146,60,121,110,148,60,235,60,174,88,211,132,12,228,247,228,52,228, +52,160,208,160,209,228,104,160,105,228,152,160,153,229,40,28,41,138,86,18, +87,144,106,38,210,38,180,80,144,110,103,130,130,38,138,58,154,82,180,104, +229,132,50,174,205,174,128,138,129,226,18,228,235,229,70,42,52,80,37,104, +176,42,219,94,130,10,131,114,12,154,241,154,128,120,120,166,112,186,92,206, +66,224,27,238,126,154,144,182,164,202,202,224,235,237,70,12,50,48,23,78, +54,40,127,40,76,40,97,76,168,12,148,52,129,76,154,40,241,40,176,40, +205,78,146,84,179,100,38,128,219,112,28,174,237,150,198,170,160,198,122,218, +84,230,41,236,108,88,106,126,116,168,132,194,158,220,196,236,216,240,224,236, +230,228,235,213,44,14,81,50,38,60,39,248,114,34,218,34,218,218,216,226, +214,230,210,236,185,238,166,188,90,188,90,90,166,90,167,188,90,140,167,141, +80,16,111,40,182,14,153,44,18,50,239,50,54,182,54,80,120,80,120,162, +118,168,114,174,108,176,97,178,54,110,121,110,54,138,121,138,162,84,163,148, +206,68,206,150,204,166,196,170,188,172,173,172,60,194,29,242,100,198,111,238, +146,194,161,234,194,190,229,237,72,16,101,42,176,12,147,46,26,52,231,52, +104,52,105,246,148,52,149,244,20,120,237,120,46,86,198,86,198,154,45,154, +102,156,80,182,54,206,38,216,25,226,150,156,166,176,186,198,210,212,233,225, +112,14,159,38,28,232,44,210,54,182,60,154,60,130,60,48,220,48,220,90, +61,90,102,246,102,122,222,122,222,226,218,236,208,238,187,240,102,158,223,158, +102,194,223,195,16,46,92,46,84,102,70,148,48,184,19,220,32,82,68,140, +99,206,172,210,126,236,126,30,210,30,210,124,127,124,126,80,211,80,162,124, +170,152,184,188,206,216,226,232,239,238,232,138,183,177,12,76,100,72,96,106, +90,138,82,166,68,190,48,212,21,234,64,10,32,152,121,210,118,32,239,32, +110,132,245,132,178,32,179,249,54,14,16,100,59,94,76,62,18,164,81,154, +16,218,79,200,200,18,225,46,238,62,96,62,96,102,98,130,94,186,88,218, +75,244,174,10,178,82,182,136,188,176,202,212,214,228,220,232,226,236,232,234, +234,230,236,222,239,210,220,92,208,146,200,174,184,200,145,234,112,102,167,102, +160,184,122,184,122,138,160,138,161,185,16,52,239,52,90,14,91,82,166,12, +167,80,204,166,56,166,56,112,204,112,205,164,130,68,131,220,28,230,209,214, +188,186,229,239,64,14,65,246,20,78,99,78,62,82,46,128,30,162,21,174, +64,110,99,142,166,14,148,58,124,90,101,112,164,24,176,50,196,78,216,94, +237,108,124,114,215,114,114,150,139,198,150,138,175,186,96,230,241,230,216,146, +185,231,18,44,237,44,126,8,127,248,200,146,54,146,54,78,202,78,203,146, +76,98,103,126,174,94,149,126,112,146,94,172,68,198,46,216,23,230,140,146, +154,168,176,190,202,208,233,223,16,44,91,44,54,44,40,96,15,142,40,220, +40,110,76,110,77,208,40,190,77,190,236,60,110,60,110,158,104,196,81,240, +204,18,225,42,182,12,182,70,188,132,196,180,208,218,218,234,224,240,228,238, +234,232,243,208,224,100,214,138,202,176,184,202,155,230,126,100,173,100,164,186, +134,186,134,136,166,136,167,187,16,38,101,38,66,38,52,80,36,116,17,140, +46,224,46,110,84,110,85,212,46,190,85,190,166,12,146,48,126,78,101,102, +160,22,180,50,196,70,214,86,239,100,124,104,209,104,118,148,139,198,154,130, +175,178,98,228,243,228,216,134,183,229,60,12,60,228,42,246,27,230,12,72, +91,72,18,158,89,122,102,54,237,54,160,12,116,142,231,142,102,96,174,96, +174,226,158,246,141,230,136,170,93,226,200,172,239,219,60,12,60,222,40,242, +25,224,14,72,97,72,14,158,97,130,162,12,144,58,128,82,110,102,93,116, +160,18,174,48,192,78,214,98,233,114,122,104,203,104,114,146,141,200,148,128, +169,184,210,134,183,220,92,226,237,227,74,10,48,50,23,80,54,42,131,42, +80,42,101,78,168,10,129,78,152,40,241,40,184,40,203,76,58,78,89,104, +50,110,51,246,108,94,214,94,214,226,208,240,194,248,177,230,162,208,98,208, +98,132,162,132,163,208,98,170,163,171,74,14,48,74,15,120,48,78,49,248, +152,10,132,54,102,84,73,108,148,18,166,44,188,70,212,88,237,100,108,110, +203,110,96,152,125,204,136,136,161,188,208,144,179,222,80,228,235,229,82,14, +111,38,176,14,155,42,22,48,237,48,54,158,54,74,126,74,126,138,112,158, +97,146,54,100,127,100,54,124,127,124,166,76,167,132,206,64,206,140,188,156, +175,142,38,174,204,174,202,196,200,218,188,230,172,234,151,234,112,174,110,192, +98,208,74,224,50,234,31,241,20,48,53,88,18,206,53,132,230,64,74,64, +74,108,76,142,74,172,68,198,58,220,43,240,188,20,213,44,164,10,162,60, +164,98,168,126,178,158,190,192,200,216,224,236,239,202,214,98,198,150,174,196, +135,230,96,104,149,104,142,194,100,194,100,138,142,138,143,195,22,40,231,40, +90,12,91,72,164,10,165,70,16,90,235,90,120,62,90,116,58,152,21,186, +76,134,77,242,110,124,200,124,170,154,170,220,156,242,135,230,96,172,243,173, +60,10,61,246,16,74,97,74,58,80,38,136,17,170,60,98,93,132,114,28, +115,128,146,12,147,142,196,12,176,68,161,94,180,60,241,60,188,92,219,134, +80,228,245,228,108,228,108,158,214,158,215,228,142,158,143,228,176,158,177,229, +52,30,53,106,98,16,99,108,162,14,150,44,123,84,150,44,231,44,172,68, +207,100,132,96,104,122,68,142,17,160,126,102,146,120,172,134,210,146,239,152, +68,152,189,152,52,188,205,188,28,230,233,230,130,152,131,230,78,202,103,220, +178,200,159,225,92,92,92,30,32,30,32,92,93,92,16,228,111,194,68,208, +69,92,30,124,31,220,68,144,103,144,152,10,154,62,156,102,164,144,172,174, +188,206,208,226,222,236,228,234,239,204,112,84,225,64,184,18,217,42,110,138, +235,110,224,142,172,192,144,208,113,225,36,172,36,34,102,34,103,168,70,72, +70,122,66,164,58,192,40,212,19,232,80,182,115,208,154,10,156,66,160,110, +166,156,178,196,190,218,206,230,216,236,226,238,230,236,239,210,120,88,225,70, +182,24,211,50,118,140,233,118,220,144,178,192,152,210,126,224,103,235,62,168, +62,28,194,28,195,168,124,58,122,104,116,150,98,186,72,208,44,222,19,232, +142,132,142,208,144,220,154,226,162,228,202,228,216,226,224,220,230,208,235,187, +62,12,38,62,17,92,40,58,93,58,28,102,89,102,18,148,93,148,56,102, +56,226,89,198,92,46,132,46,102,122,132,122,130,158,122,186,106,216,85,238, +100,156,108,184,120,204,136,216,156,226,176,230,204,232,239,232,186,12,187,216, +140,80,249,80,148,48,220,48,220,114,147,114,146,144,233,144,140,176,239,177, +66,12,46,46,19,80,52,38,127,38,76,38,99,66,158,12,142,48,125,74, +148,36,239,36,174,36,199,70,18,104,245,104,70,74,99,96,170,72,149,96, +48,246,48,134,118,134,118,226,114,234,102,236,85,236,48,164,119,164,48,194, +119,194,160,138,161,210,204,120,204,224,184,244,163,231,82,16,56,76,40,100, +21,124,60,72,61,242,126,40,112,92,99,122,118,76,229,76,90,144,247,144, +170,12,171,243,73,14,70,16,46,76,17,122,54,248,55,62,74,46,118,46, +84,122,114,122,112,160,102,200,92,218,77,240,80,154,92,182,112,206,128,220, +154,230,188,234,241,234,124,82,247,82,138,46,220,46,220,114,139,114,130,146, +233,146,126,178,239,178,180,8,181,217,16,236,30,210,34,184,36,160,36,48, +96,48,96,218,74,236,63,220,66,12,59,48,60,70,73,104,60,146,73,180, +12,126,97,126,136,162,136,32,212,32,213,160,176,60,176,84,174,120,166,160, +156,188,138,212,111,238,182,146,182,212,184,224,188,226,194,230,196,230,222,230, +230,228,238,218,241,201,96,14,62,66,25,102,88,28,161,78,48,96,143,96, +44,132,69,194,84,118,99,170,30,226,161,206,138,122,109,212,182,46,183,180, +228,16,228,228,206,242,189,227,64,16,40,72,19,106,46,62,98,62,83,98, +54,106,54,224,95,192,108,88,229,74,182,24,213,52,100,146,237,124,220,148, +170,196,142,214,109,230,152,12,156,104,162,146,172,188,188,214,208,232,218,236, +226,234,230,226,237,209,28,18,65,48,14,80,53,108,20,230,55,144,70,54, +151,54,108,10,88,72,68,122,149,122,64,190,145,164,112,76,113,240,230,24, +192,34,166,38,166,122,166,148,162,178,156,194,133,234,166,108,245,108,208,108, +209,243,26,22,57,52,14,84,49,110,20,226,55,146,76,170,76,36,136,36, +137,168,106,68,106,142,102,172,92,198,78,214,61,230,102,176,137,210,200,32, +223,54,152,94,233,80,148,140,237,126,222,152,186,192,137,232,180,12,180,142, +184,166,192,196,202,214,212,226,222,232,230,232,232,222,239,209,38,24,75,50, +20,86,63,114,28,234,69,142,98,12,125,46,94,52,95,242,182,184,130,184, +130,88,182,88,183,184,130,134,183,134,140,34,220,34,220,228,204,238,187,223, +18,44,74,44,40,114,82,114,78,150,66,186,50,214,25,238,32,150,56,186, +76,204,100,220,132,228,156,230,239,230,158,10,159,214,90,76,243,76,98,42, +210,42,210,112,103,112,98,146,221,146,88,178,233,179,78,14,54,66,17,118, +52,70,53,246,90,32,241,32,218,110,104,110,104,56,218,56,219,110,104,84, +219,84,160,56,161,110,78,132,245,132,220,204,100,204,100,152,220,152,221,204, +100,180,221,180,160,152,161,204,74,230,247,231,86,16,113,40,40,50,223,50, +180,12,151,50,54,84,207,84,32,118,229,118,132,50,133,118,20,156,237,156, +126,128,96,166,82,184,168,210,223,232,174,156,152,188,120,212,78,230,33,239, +24,50,59,92,18,180,61,136,76,12,77,242,154,14,132,50,103,80,136,46, +216,46,200,68,178,88,146,110,115,124,142,70,169,94,90,142,243,142,198,102, +198,222,178,242,155,226,120,162,155,197,30,36,63,62,88,12,89,138,24,118, +89,72,154,12,130,52,107,80,138,42,220,42,206,66,186,88,160,108,136,120, +111,126,140,70,177,94,134,136,134,222,118,242,103,226,26,162,104,162,82,192, +58,212,23,226,211,134,134,150,156,178,178,194,204,206,239,220,210,134,157,177, +32,24,77,56,14,90,63,124,28,238,79,156,96,44,237,44,84,222,245,222, +166,44,167,223,16,32,84,32,84,78,30,78,28,118,84,118,80,216,66,238, +35,224,14,160,65,160,42,134,43,194,12,202,65,190,102,30,235,30,212,104, +116,104,116,52,214,52,215,104,116,80,215,80,164,52,165,104,100,128,235,128, +216,206,114,206,114,152,216,152,217,206,114,178,217,178,164,152,165,206,92,230, +237,231,16,40,235,40,88,8,89,68,162,8,163,68,24,96,53,128,16,206, +61,164,76,78,77,246,142,64,122,96,99,118,130,84,212,84,178,120,129,148, +140,106,163,126,94,160,243,160,194,130,194,224,176,240,157,226,120,178,153,205, +36,32,67,56,30,112,85,82,88,12,89,132,158,12,132,52,109,76,140,40, +220,40,202,72,176,100,133,122,148,68,179,94,16,154,241,154,130,132,131,246, +124,154,96,184,66,206,27,222,132,154,144,172,164,188,192,204,231,219,36,32, +75,62,90,10,91,138,28,112,91,80,160,12,128,56,107,78,138,42,218,42, +204,68,182,98,154,116,131,126,144,68,181,96,20,162,239,162,130,138,124,162, +114,186,92,210,60,226,31,238,132,162,148,186,166,204,198,222,229,237,40,20, +73,58,14,96,58,96,52,220,95,186,88,70,239,70,80,140,245,140,134,10, +134,150,132,176,122,202,106,222,93,238,194,10,195,241,222,36,44,36,44,226, +231,226,194,66,142,78,98,82,98,148,88,176,69,202,98,120,221,120,164,120, +165,211,34,26,65,52,86,10,87,104,24,92,85,64,154,8,122,54,105,70, +130,104,168,86,196,62,214,38,135,38,144,58,175,80,14,116,241,116,54,246, +54,146,198,146,199,246,108,116,104,158,94,170,81,182,146,116,146,158,148,168, +156,172,164,174,199,172,64,202,187,202,54,230,199,231,46,186,56,186,68,182, +76,174,80,164,80,152,78,142,74,132,66,116,52,100,86,34,30,34,31,244, +146,12,120,50,101,74,128,40,202,40,174,78,144,102,118,116,97,126,134,60, +164,90,190,102,237,118,106,146,229,146,112,168,104,198,237,198,168,116,169,245, +18,42,239,42,92,12,93,68,166,10,167,66,72,66,44,118,23,144,62,194, +63,88,116,60,147,82,70,92,221,92,70,120,207,120,70,148,205,148,68,178, +229,178,134,92,135,178,56,202,25,242,90,202,105,240,140,200,157,238,188,196, +225,239,16,70,85,70,56,8,57,242,54,74,42,120,28,148,17,166,56,98, +87,130,120,10,121,96,84,98,161,98,152,52,121,52,124,116,124,210,110,226, +95,212,100,140,79,194,146,142,163,178,160,48,228,48,220,104,206,150,182,190, +139,232,176,48,178,98,188,154,208,194,241,233,18,46,103,46,58,46,50,82, +34,114,19,136,44,220,44,112,84,112,85,212,44,188,85,188,142,12,118,70, +95,102,122,190,123,60,132,58,239,58,132,94,225,94,132,132,225,132,132,172, +243,172,174,58,175,172,166,14,197,42,116,198,91,242,138,198,151,238,174,194, +191,232,210,192,239,237,84,14,54,64,36,90,21,104,68,186,69,44,126,14, +163,40,76,54,227,54,76,94,215,94,76,132,215,132,76,168,237,168,142,54, +143,168,56,194,23,240,100,194,113,234,152,190,169,228,204,186,239,235,16,228, +32,196,38,166,40,140,40,30,92,30,92,212,74,228,59,214,40,88,93,88, +40,144,93,144,158,10,185,42,112,58,243,58,158,80,113,124,190,80,237,120, +206,128,188,166,166,198,140,218,103,238,136,128,152,162,172,188,196,210,239,235, +102,14,143,46,20,58,239,58,94,78,62,110,37,132,160,76,219,120,84,118, +104,158,120,176,148,200,200,224,233,232,174,112,152,154,126,188,92,212,56,226, +27,237,66,14,95,44,14,58,141,58,66,82,48,108,27,130,100,82,137,120, +110,128,90,166,68,196,48,214,29,228,56,140,96,176,118,198,129,214,194,202, +208,200,224,194,232,178,230,160,220,138,206,122,190,108,222,32,160,32,161,247, +36,26,69,54,20,86,57,114,30,228,65,140,84,54,227,32,134,10,138,50, +152,78,176,104,202,120,216,126,222,124,226,116,231,98,210,56,162,96,130,112, +91,124,80,148,235,148,126,148,124,174,120,196,102,218,88,230,73,238,176,148, +176,214,176,226,180,230,190,230,208,230,222,226,226,218,233,205,14,24,88,24, +79,120,40,46,34,126,96,126,88,210,82,220,76,222,64,224,53,226,14,186, +73,166,218,14,186,24,158,28,115,30,108,74,239,74,168,26,164,70,156,96, +134,124,113,140,178,74,186,90,196,106,216,126,239,138,146,136,146,176,140,202, +122,224,103,236,202,138,203,239,60,10,48,90,32,154,105,208,10,78,90,76, +82,138,66,182,44,212,19,238,222,16,162,30,109,32,104,78,239,78,162,30, +160,76,148,104,128,130,101,152,174,78,186,104,210,128,241,146,142,136,140,192, +128,222,109,242,194,136,195,247,28,190,28,46,66,46,67,180,67,180,28,156, +67,156,224,18,182,26,83,30,100,44,129,64,144,40,163,60,208,36,183,68, +220,106,92,106,92,72,220,72,221,106,134,72,135,106,178,72,179,106,98,182, +150,182,150,130,96,130,96,230,147,212,132,198,161,226,96,156,149,156,166,142, +245,142,216,118,216,222,202,242,185,228,172,168,191,197,16,74,83,74,16,154, +85,120,60,12,60,232,44,244,27,226,102,24,125,54,142,12,165,44,212,12, +185,62,98,102,98,68,222,68,223,102,120,182,120,104,200,104,201,180,160,126, +156,158,150,182,144,198,126,214,89,236,174,172,174,216,176,226,182,228,206,228, +220,224,228,220,232,210,237,199,68,10,40,60,19,88,46,54,103,54,30,96, +99,96,18,146,107,146,64,96,64,224,103,192,156,14,191,46,116,56,239,56, +160,76,117,120,194,78,235,120,202,124,188,164,164,198,134,222,99,240,142,132, +156,170,178,196,206,216,237,233,54,16,40,60,25,96,42,58,109,58,14,124, +115,124,68,58,68,130,58,174,42,204,21,226,62,158,111,202,216,16,172,30, +119,32,108,78,241,78,168,30,160,86,142,118,117,144,180,78,196,106,218,126, +237,140,148,136,146,176,134,210,109,238,202,136,203,243,78,14,52,70,19,114, +56,244,57,66,84,56,235,36,214,56,180,84,136,108,89,120,138,8,142,50, +152,76,176,108,202,122,222,124,232,114,237,102,80,148,241,148,136,148,136,170, +132,192,116,216,85,236,178,148,178,212,178,224,184,228,196,230,208,230,222,226, +230,216,235,205,22,234,34,206,40,172,44,142,44,32,88,32,88,222,70,240, +55,224,44,84,89,84,44,140,89,140,106,60,173,60,102,118,179,118,138,12, +139,118,138,128,106,206,167,190,152,152,177,212,192,246,192,34,232,34,232,180, +232,192,228,198,220,200,211,201,86,26,54,66,32,86,21,98,20,34,46,60, +62,86,74,118,78,156,76,196,68,222,54,232,44,236,35,234,20,172,73,120, +136,12,173,46,90,60,241,60,138,82,95,134,182,84,225,130,190,130,176,166, +148,200,120,222,89,238,120,132,138,164,162,190,194,212,237,231,106,12,82,46, +60,70,35,88,88,38,184,38,151,78,32,238,54,212,68,178,70,166,70,84, +214,84,214,224,190,240,173,222,70,126,215,126,70,172,213,172,140,84,141,221, +70,14,46,68,21,104,46,68,94,68,79,104,58,114,58,230,101,192,144,16, +183,50,108,62,239,62,146,82,122,114,101,132,186,84,231,128,196,126,176,174, +140,214,93,240,128,134,148,174,180,206,237,237,56,12,16,96,61,92,78,60, +24,158,75,148,18,214,85,188,118,12,107,42,142,106,96,106,96,44,144,44, +145,106,96,74,145,74,106,116,129,132,82,144,163,144,110,144,104,188,92,218, +73,238,106,174,144,174,138,216,122,228,113,218,188,12,168,78,159,102,172,68, +245,68,214,68,210,124,200,170,180,206,145,240,174,98,176,128,184,160,202,198, +239,233,64,16,20,92,75,90,94,58,30,158,97,148,14,216,99,198,150,14, +183,46,106,58,237,58,152,74,103,134,186,78,233,126,134,122,144,158,162,190, +196,218,237,236,200,122,180,168,154,204,122,226,89,241,62,16,36,50,59,76, +104,16,82,50,103,76,146,14,124,48,147,74,146,144,40,144,40,88,146,88, +147,144,40,116,147,116,94,88,95,144,16,172,169,172,94,144,95,246,88,172, +56,208,21,232,94,182,132,204,161,222,186,42,187,186,222,12,222,224,210,242, +187,227,30,46,109,46,16,88,139,88,78,10,79,88,134,28,90,96,44,148, +19,168,36,126,110,126,90,148,90,220,76,240,53,224,30,198,137,168,176,12, +156,80,137,116,160,66,241,66,208,66,204,114,190,160,164,202,119,236,158,114, +178,172,200,202,239,229,14,30,115,30,26,240,26,74,100,74,101,236,52,30, +52,98,48,130,41,150,76,30,76,122,76,132,80,138,86,138,94,138,101,136, +26,178,101,178,26,214,101,214,126,52,201,52,118,90,239,90,170,10,171,90, +226,32,180,100,152,124,119,148,126,124,216,124,180,156,180,222,180,228,172,232, +155,234,124,172,241,173,12,60,105,60,62,14,38,102,24,128,105,128,70,86, +71,244,14,196,109,172,216,20,162,34,115,38,102,82,231,82,162,34,160,68, +152,102,140,124,107,150,172,82,178,98,190,114,212,134,233,146,144,142,142,186, +132,216,109,240,198,142,199,243,12,56,111,56,68,12,44,88,22,132,107,132, +72,88,73,244,16,200,117,172,156,14,191,48,120,60,239,60,160,80,121,130, +192,84,233,126,142,134,156,164,168,184,194,210,237,234,204,130,190,166,166,200, +140,222,101,237,38,204,38,48,92,48,93,196,93,196,38,172,93,172,214,12, +215,244,144,46,134,170,213,147,110,8,147,28,30,76,30,36,222,36,223,74, +108,54,70,78,45,90,146,56,207,84,86,82,53,132,72,106,201,106,16,146, +239,146,128,76,129,146,66,242,66,178,194,178,195,240,66,220,195,221,14,78, +95,78,16,160,93,126,58,14,58,228,38,244,25,228,218,108,118,108,118,34, +218,34,219,108,118,72,219,72,144,118,114,152,89,174,126,140,230,140,228,224, +222,232,216,236,197,238,172,152,154,184,137,200,164,166,201,194,114,170,114,216, +195,217,18,74,91,74,20,166,87,134,58,12,58,228,44,244,25,230,146,12, +177,36,100,50,231,50,120,68,147,98,198,66,173,112,102,112,225,112,84,154, +243,154,152,126,116,190,194,216,227,236,194,154,190,174,178,196,154,216,124,230, +95,239,44,14,44,114,115,90,44,54,117,54,144,10,144,92,148,100,152,106, +160,108,166,108,204,108,216,108,224,102,230,94,235,82,222,34,145,64,64,246, +64,146,194,146,195,246,122,110,109,146,64,186,195,186,64,226,195,227,96,22, +50,34,23,38,14,88,105,88,62,32,63,246,62,90,50,132,32,166,19,186, +62,108,105,148,106,58,243,58,114,110,231,110,172,12,173,110,128,244,128,152, +220,152,221,242,128,218,221,219,70,22,23,80,72,82,38,132,19,156,52,246, +53,114,84,60,171,60,78,104,175,104,130,12,131,104,82,156,171,156,74,214, +175,198,128,116,129,204,182,42,239,42,180,108,245,108,210,108,210,218,206,232, +192,238,175,239,26,244,26,30,94,30,56,102,66,114,78,132,88,150,88,166, +84,178,70,188,49,194,168,12,138,66,116,90,93,112,164,20,176,44,196,72, +210,86,241,106,138,112,138,158,132,188,122,214,95,238,196,112,197,245,32,38, +143,38,12,72,239,72,90,8,91,72,70,86,38,134,17,158,52,242,53,116, +88,86,107,110,58,120,143,120,60,152,139,152,58,182,137,182,58,214,145,214, +98,120,99,214,190,20,221,46,164,6,164,80,172,136,184,180,204,220,218,232, +226,236,232,236,236,228,241,211,30,66,127,66,18,120,139,120,82,16,83,120, +80,128,30,208,111,186,96,152,121,208,132,86,226,82,220,216,210,226,198,232, +179,232,172,14,170,114,160,166,144,206,115,241,16,50,241,50,96,12,97,88, +166,10,167,88,34,108,206,108,206,176,202,188,190,198,176,200,153,202,112,108, +113,245,16,76,99,76,68,12,69,242,68,82,40,142,23,172,68,98,105,136, +106,56,245,56,112,108,237,108,172,10,173,108,124,242,124,150,220,150,221,238, +124,212,219,213,30,62,231,62,130,8,131,168,128,62,106,90,78,118,52,136, +27,150,130,62,148,84,178,114,208,136,233,150,58,178,27,234,96,186,107,234, +146,182,161,232,190,174,229,235,16,70,95,70,18,160,85,126,60,12,60,230, +38,244,29,228,100,42,231,42,108,74,212,74,212,140,109,140,98,104,241,104, +166,12,167,226,166,176,225,176,122,166,110,206,100,224,87,238,114,196,130,212, +148,224,172,228,243,227,30,222,30,36,80,36,81,212,30,86,79,86,30,140, +81,140,30,194,81,194,98,38,231,38,106,70,212,70,212,138,107,138,96,104, +241,104,160,8,161,224,160,178,225,178,122,162,108,204,94,224,75,240,110,200, +120,210,136,220,172,226,204,228,239,227,44,22,73,56,16,72,103,72,26,106, +47,166,20,206,105,180,90,96,65,192,212,98,126,98,126,28,212,28,213,98, +126,64,213,64,146,108,126,138,103,156,132,130,230,130,230,204,226,226,218,232, +208,234,201,236,120,164,120,212,193,212,176,146,143,196,168,158,203,195,36,26, +81,54,18,86,65,114,30,228,79,152,94,60,243,60,166,12,167,110,102,110, +229,110,114,244,114,154,214,154,215,244,114,220,213,221,62,14,20,96,73,94, +94,56,34,160,99,150,18,224,99,198,110,62,243,62,116,116,229,116,172,12, +173,116,128,242,128,158,216,158,217,242,128,220,217,221,76,12,40,68,21,88, +60,40,114,40,91,74,28,242,42,212,48,176,48,78,124,78,124,234,112,242, +93,226,48,120,125,120,48,162,125,162,84,78,85,214,132,32,226,32,220,84, +214,92,204,94,193,94,172,32,174,56,168,76,154,98,143,108,166,112,143,164, +154,142,237,142,138,188,247,188,196,106,197,245,14,78,98,74,90,130,74,174, +48,204,21,224,60,14,42,130,34,152,103,204,96,226,243,226,132,226,132,32, +208,32,209,226,132,96,209,96,132,160,209,161,14,66,235,66,22,136,145,136, +58,84,58,162,50,200,27,236,106,86,107,214,152,10,152,86,162,142,178,190, +198,222,212,234,220,236,226,234,230,226,235,206,180,22,209,46,208,104,180,172, +158,204,121,237,18,36,241,36,94,6,95,58,160,8,161,54,26,94,109,94, +34,120,105,120,18,146,111,146,72,60,73,246,72,156,25,216,72,158,113,198, +118,92,233,92,112,130,243,130,150,60,151,130,200,58,201,130,136,244,136,156, +216,156,217,244,136,190,217,190,136,224,217,225,16,40,235,40,88,8,89,76, +168,6,169,76,134,68,100,106,70,126,23,146,126,78,150,102,180,118,214,132, +239,138,94,136,92,176,88,202,74,224,51,242,172,136,173,241,206,106,54,106, +54,20,206,20,207,106,54,62,207,62,128,20,129,106,100,106,78,136,52,156, +19,172,156,106,172,126,198,146,241,162,94,146,92,184,86,210,70,226,47,238, +174,144,175,241,82,12,48,86,19,122,60,248,61,62,98,52,235,52,86,102, +247,102,140,8,141,102,194,10,195,102,118,246,118,136,216,136,217,246,118,178, +217,178,118,224,217,225,128,10,96,60,70,86,42,106,19,120,126,14,138,36, +158,62,172,78,194,94,210,104,235,118,86,102,86,174,78,204,64,226,45,242, +164,102,165,249,126,12,163,34,238,48,64,48,64,154,52,196,23,238,20,66, +47,98,16,158,63,126,154,60,122,108,104,124,83,138,150,66,168,92,188,110, +214,126,237,132,124,136,124,164,120,190,114,212,96,230,81,242,188,134,189,245, +32,24,69,60,10,100,54,100,50,228,85,186,84,60,235,60,200,16,225,42, +176,10,176,56,184,136,196,188,222,234,224,234,228,230,239,192,222,104,206,158, +186,196,155,234,84,136,169,136,114,86,114,174,104,206,87,236,148,84,149,211, +20,232,36,204,46,172,48,140,48,26,220,26,220,72,49,72,86,244,86,122, +220,122,221,242,86,166,221,166,84,214,221,214,152,88,153,215,52,198,52,66, +206,66,206,172,204,186,200,188,188,190,175,192,128,10,129,245,78,10,46,58, +25,80,58,40,131,40,78,40,103,78,174,10,152,50,133,74,158,40,243,40, +182,40,207,76,18,238,32,224,44,200,48,182,50,164,50,98,102,98,102,216, +104,224,100,226,90,230,77,230,50,138,103,138,50,176,103,176,122,130,218,124, +212,212,206,224,192,232,175,236,166,78,164,142,160,170,150,204,119,241,214,28, +152,36,64,36,64,72,60,166,52,202,31,236,64,102,237,102,158,102,159,245, +126,18,100,56,70,84,44,102,19,116,122,24,140,46,162,68,194,90,237,110, +72,96,183,96,44,148,213,148,26,228,231,228,126,96,127,228,68,168,101,208, +190,166,159,209,124,8,102,46,78,76,48,104,19,122,120,14,136,40,152,62, +172,82,196,100,220,114,235,122,110,80,139,120,52,144,180,144,160,182,136,214, +113,241,30,26,69,56,20,90,59,118,26,236,65,144,74,86,243,86,154,10, +155,246,88,48,210,48,210,120,89,120,90,158,225,158,74,196,243,197,40,16, +69,52,14,70,74,70,48,114,17,146,52,244,53,108,52,124,87,160,86,114, +71,142,108,136,221,136,96,166,239,166,166,166,166,222,162,232,152,236,135,238, +136,186,89,228,188,184,231,224,92,50,153,50,128,12,129,116,126,50,110,80, +89,102,130,62,153,84,162,52,233,52,192,12,193,116,190,52,170,86,153,108, +192,56,208,76,226,94,239,101,40,24,41,104,86,14,87,108,102,32,208,32, +180,60,148,82,119,96,128,32,142,54,170,80,202,96,231,106,116,104,58,140, +125,138,172,112,58,176,203,168,172,144,221,182,130,172,130,218,130,232,122,238, +108,240,99,240,82,194,29,228,164,198,225,229,72,12,44,64,19,92,48,58, +113,58,32,102,105,102,18,150,113,150,66,102,66,226,107,192,220,108,136,108, +136,42,220,42,221,108,221,106,136,74,221,74,170,10,155,42,128,222,128,144, +230,144,230,200,226,212,214,216,205,218,178,108,179,247,78,12,46,84,19,122, +58,242,59,60,96,38,218,38,202,96,178,140,142,186,85,232,116,38,122,68, +134,112,158,154,178,184,208,212,241,237,32,28,73,66,12,106,56,106,52,232, +89,198,88,44,239,44,132,12,132,74,194,74,195,12,220,134,104,134,104,102, +220,102,221,134,96,162,231,162,102,198,227,198,84,230,243,230,162,74,163,231, +32,28,73,66,86,72,233,72,80,132,237,132,130,10,130,136,122,164,110,188, +95,206,184,10,185,212,18,228,32,216,44,210,50,208,60,208,70,212,80,218, +90,224,104,230,118,232,142,234,172,236,241,232,14,114,56,114,57,209,20,46, +135,46,54,14,54,78,106,78,107,10,118,150,40,150,40,108,120,108,121,148, +14,182,139,182,80,78,81,242,226,20,154,36,154,158,148,188,125,232,154,102, +243,102,204,102,205,241,34,26,225,26,16,102,239,102,50,48,77,84,204,46, +179,82,104,26,105,102,152,26,153,102,62,244,62,134,196,134,197,242,62,176, +197,176,62,220,197,221,22,50,119,50,76,8,77,118,76,54,52,90,21,120, +76,64,117,92,128,48,237,48,174,8,175,118,174,50,148,86,117,116,174,54, +188,72,208,88,239,102,48,136,205,136,24,170,235,170,76,190,48,214,23,230, +168,194,229,220,130,170,130,226,126,232,118,236,101,237,38,24,77,66,18,224, +30,214,44,206,52,200,58,200,68,204,84,212,108,222,130,226,239,224,12,106, +56,106,57,200,218,28,174,36,114,40,114,120,110,146,104,168,89,196,114,100, +239,100,182,100,183,205,64,12,64,134,56,180,44,208,23,234,34,66,23,130, +104,56,67,104,62,152,84,180,103,206,96,164,112,142,122,114,126,94,126,30, +216,30,216,82,127,82,176,82,186,114,202,134,218,150,239,162,146,144,199,176, +128,192,203,241,40,18,75,48,16,80,55,110,26,230,63,144,98,24,206,24, +206,86,101,86,106,54,205,54,84,144,84,114,230,114,231,144,102,142,196,142, +184,168,166,188,142,208,112,222,77,236,116,142,126,162,140,182,160,200,182,212, +216,224,239,231,16,190,42,166,56,142,64,116,66,98,66,32,200,32,200,90, +67,90,142,90,156,120,176,146,202,166,239,184,104,148,161,182,86,194,163,241, +22,36,112,36,86,74,66,96,46,110,29,122,80,80,137,120,26,146,127,146, +18,228,127,206,76,146,77,214,128,78,228,78,224,212,220,220,204,236,185,222, +176,10,176,96,172,142,162,182,146,212,121,243,18,48,157,48,68,14,69,78, +114,14,115,78,30,98,149,98,18,150,163,150,66,98,66,162,62,190,48,216, +27,240,118,98,119,236,180,44,181,176,224,12,224,220,220,228,212,232,202,234, +187,239,22,52,121,52,74,12,75,90,104,146,42,146,42,92,104,92,105,146, +58,146,58,172,54,192,46,210,34,222,19,238,86,146,86,222,127,178,134,52, +243,52,216,144,148,144,148,92,214,92,215,144,184,10,185,92,164,144,164,174, +154,200,138,220,113,236,196,144,196,226,208,232,224,232,234,224,240,210,241,203, +22,44,237,44,99,14,96,14,97,72,162,12,163,74,46,88,180,88,140,118, +96,136,66,144,31,150,220,156,131,124,54,170,199,170,22,226,237,226,128,170, +129,227,26,220,26,36,82,36,83,214,26,88,83,88,26,138,83,138,26,196, +83,196,104,40,229,40,114,72,219,72,96,102,243,102,166,8,167,102,124,242, +124,130,214,130,214,228,196,244,183,228,124,164,215,164,124,194,215,195,190,104, +66,104,66,28,190,28,191,104,191,104,66,66,191,66,36,242,36,136,110,136, +111,240,36,176,111,176,36,218,111,218,142,240,142,136,220,136,221,238,142,174, +221,174,142,218,221,219,62,14,38,56,21,74,46,46,96,46,75,84,102,172, +32,172,32,90,102,90,103,172,32,128,103,128,68,90,69,172,16,222,109,204, +154,14,187,44,112,58,245,58,214,148,140,148,140,94,214,94,215,148,176,148, +176,230,170,236,162,238,149,238,150,174,115,226,202,176,239,223,110,14,147,38, +18,54,241,54,192,142,64,142,64,90,192,90,193,142,132,142,132,234,124,240, +112,240,97,240,82,172,27,222,174,174,229,223,58,8,59,246,32,68,19,124, +80,62,97,100,148,12,183,40,100,52,241,52,210,146,122,146,122,92,210,92, +211,146,168,146,168,218,166,226,160,232,150,236,139,236,136,172,95,222,194,172, +235,215,18,40,41,78,96,36,77,76,12,96,99,96,62,8,63,248,58,100, +42,144,23,186,62,118,99,150,108,36,237,36,118,68,229,68,104,100,247,100, +172,4,173,100,124,248,124,130,220,130,220,222,218,236,208,240,195,240,124,164, +221,164,124,198,221,199,20,38,41,76,100,40,81,76,12,94,99,94,60,10, +61,244,58,104,44,140,30,164,17,184,60,112,99,156,112,30,239,30,222,144, +122,144,122,68,222,68,223,144,122,106,223,106,172,30,172,154,162,188,148,208, +122,224,91,236,122,164,156,202,184,216,218,226,239,231,74,18,24,100,83,96, +106,62,32,164,105,154,18,224,109,198,116,34,210,34,198,60,172,92,148,110, +111,130,176,88,237,128,122,154,229,154,104,226,245,226,174,154,175,227,30,72, +223,72,12,146,239,146,86,14,86,156,78,188,60,218,33,242,164,12,165,245, +22,36,139,36,66,14,67,52,102,16,103,52,52,50,36,70,21,88,42,62, +124,62,122,96,120,108,116,114,110,116,105,118,92,108,48,108,48,84,92,84, +93,108,168,18,156,46,139,72,158,44,233,44,202,44,200,66,192,86,176,102, +162,110,149,116,160,64,172,78,184,94,200,104,227,116,122,118,141,130,26,138, +237,138,54,160,203,160,56,180,203,180,60,244,60,202,196,202,197,244,60,228, +197,229,196,82,58,82,58,26,198,26,199,82,58,54,199,54,118,92,145,108, +16,116,243,116,194,176,60,176,60,142,194,142,195,176,132,176,132,224,128,232, +120,236,105,238,86,196,60,218,33,232,174,200,233,231,18,36,94,36,74,70, +48,96,23,114,66,78,111,110,20,138,105,138,20,220,111,194,66,138,67,206, +112,28,243,28,132,192,132,78,220,78,221,188,176,28,165,78,178,110,176,160, +168,190,154,208,128,226,105,238,186,198,233,237,18,44,113,44,28,76,107,76, +12,106,115,106,66,12,67,106,36,246,36,130,100,130,100,236,84,244,71,230, +36,160,101,160,36,190,101,190,160,14,142,52,119,84,148,44,202,44,179,84, +128,90,216,90,217,192,118,134,243,134,124,174,217,174,168,90,168,232,162,236, +154,238,141,239,14,80,81,80,50,16,51,180,12,194,87,170,140,14,167,32, +92,44,227,44,122,56,143,78,86,88,243,88,196,54,171,88,210,172,108,172, +108,114,212,114,213,172,108,142,213,142,138,172,134,194,124,212,104,228,67,240, +176,172,176,222,180,230,190,234,204,236,220,234,228,228,232,222,239,207,18,52, +139,52,62,16,63,82,102,14,103,86,56,90,34,122,17,140,42,112,122,112, +116,208,112,220,104,228,94,230,84,232,79,232,86,194,40,194,40,146,88,146, +89,194,174,20,156,64,133,102,152,72,243,72,210,72,206,128,194,168,176,200, +152,222,127,240,154,106,162,138,174,168,196,200,235,239,64,16,38,64,19,92, +42,60,99,60,26,108,87,108,14,152,97,152,56,108,56,226,97,194,142,14, +171,32,104,46,223,46,124,58,149,78,96,88,239,88,200,56,181,88,210,172, +118,172,118,114,210,114,211,172,118,142,211,142,144,172,142,192,134,210,120,226, +97,242,178,172,178,222,178,230,182,232,192,232,206,232,222,230,228,224,237,205, +74,14,46,50,21,72,76,76,48,120,21,148,56,246,57,110,98,30,202,30, +188,58,158,90,126,110,97,120,164,82,237,120,98,154,231,154,84,228,241,228, +164,154,165,229,126,16,165,38,240,50,62,50,62,112,60,164,54,194,44,220, +31,242,16,74,41,112,16,156,61,132,92,82,202,82,174,112,142,134,116,146, +85,158,160,124,241,162,96,178,219,178,76,232,237,232,158,178,159,233,40,20, +65,54,12,70,99,70,24,98,45,168,14,204,101,180,88,96,61,188,108,40, +233,40,118,72,223,72,102,102,245,102,168,10,169,102,122,246,122,128,216,128, +216,222,214,230,206,236,196,238,187,238,122,162,217,162,122,196,217,197,106,12, +143,32,34,42,223,42,18,82,241,82,78,56,99,82,176,52,155,82,196,170, +62,170,62,112,196,112,197,170,62,142,197,142,102,170,100,194,86,216,62,230, +42,238,21,242,154,170,154,218,156,228,164,232,176,234,204,234,218,230,228,222, +235,203,108,14,139,38,30,48,225,48,78,58,103,82,16,92,239,92,176,58, +149,92,188,164,66,164,66,122,188,122,189,164,106,164,104,184,98,202,90,210, +70,224,50,232,27,238,152,164,152,214,152,224,162,232,174,232,198,232,216,228, +224,218,231,201,24,36,69,68,24,202,61,122,136,8,108,54,81,88,120,36, +184,36,161,82,98,84,210,84,211,186,76,126,241,126,86,170,211,170,152,84, +152,210,150,222,142,230,132,232,105,233,34,74,23,136,64,12,64,126,58,174, +42,208,25,234,100,66,65,100,60,156,97,202,120,242,120,36,228,36,228,206, +226,218,222,226,216,230,208,230,193,232,192,166,152,166,152,88,192,88,193,167, +110,16,147,34,40,82,40,42,226,42,227,80,118,58,88,74,69,80,154,58, +201,82,20,126,243,126,52,96,204,96,204,154,53,154,112,96,102,144,82,178, +56,200,23,218,88,244,88,184,210,184,211,240,88,224,211,225,12,74,83,74, +16,146,81,122,52,12,52,224,38,244,23,228,146,32,104,40,81,44,80,98, +149,98,116,244,117,38,114,110,90,166,75,186,116,120,149,156,164,74,155,130, +232,72,211,126,190,10,190,126,182,174,166,212,143,236,190,132,198,160,204,184, +218,206,230,224,241,237,108,14,143,44,40,92,40,54,220,54,221,90,102,78, +62,112,38,126,29,132,154,82,227,132,44,152,182,148,178,224,180,232,190,236, +222,234,230,228,236,220,241,210,116,110,108,168,98,196,76,216,50,230,21,243, +78,16,24,98,91,90,114,58,38,162,115,148,28,220,117,192,146,40,140,168, +213,148,214,16,215,241,10,50,103,50,18,116,97,116,12,210,101,176,58,50, +59,190,150,12,130,80,109,132,136,66,188,66,166,144,140,192,114,216,85,236, +176,110,186,152,196,178,212,208,237,237,101,22,16,222,239,222,100,22,101,222, +154,20,155,222,30,68,101,68,36,120,101,120,30,172,101,172,154,68,229,68, +154,120,221,120,154,170,229,171,104,10,76,82,60,108,41,136,84,66,160,66, +134,136,106,176,70,210,21,238,136,128,158,162,182,194,206,214,233,231,100,12, +58,58,33,80,74,42,168,42,118,86,80,108,23,130,132,74,235,126,76,136, +53,184,194,130,177,178,130,114,122,162,114,182,96,204,68,220,23,236,124,150, +134,174,160,202,192,220,231,233,108,14,104,100,102,132,92,170,74,196,50,216, +23,234,34,88,178,80,168,212,170,220,174,226,182,228,198,228,214,228,228,224, +234,212,239,191,30,20,71,50,18,88,63,116,30,230,67,146,76,32,243,32, +98,240,98,78,220,78,221,238,98,178,221,178,98,216,221,216,138,32,138,84, +134,114,115,148,174,32,174,114,176,128,182,132,188,132,221,133,234,32,40,32, +40,146,36,186,19,228,104,160,133,198,120,184,72,220,72,62,118,62,118,142, +73,142,72,104,119,104,138,62,227,62,154,88,146,138,239,138,190,62,180,130, +164,176,144,206,115,236,188,152,188,210,188,220,194,224,204,228,212,228,222,226, +230,222,237,203,16,70,135,70,96,24,123,48,74,6,74,214,68,224,56,230, +39,230,18,98,47,128,14,186,75,138,118,96,75,136,124,180,75,146,172,10, +156,68,142,102,133,120,158,68,243,68,202,68,198,122,186,162,164,196,140,218, +113,238,154,114,166,158,190,198,214,216,239,231,44,28,45,236,96,230,96,40, +212,40,213,228,96,116,213,116,96,200,213,201,112,28,44,46,45,234,44,122, +105,122,146,46,210,46,211,230,154,122,211,122,44,206,211,207,116,18,76,32, +48,36,48,80,214,80,214,30,159,30,114,56,49,56,160,54,215,54,204,156, +54,156,54,104,204,104,205,156,205,156,54,130,205,130,132,104,133,156,32,184, +218,182,210,222,200,228,186,232,167,232,128,166,118,196,102,212,84,224,58,232, +35,239,72,16,50,66,23,106,58,50,122,50,106,92,84,124,56,146,21,164, +58,82,94,120,120,132,162,136,239,136,158,12,159,118,176,50,223,96,68,244, +68,164,190,164,191,242,68,220,191,221,64,16,89,44,10,60,131,60,112,142, +38,142,38,94,112,94,113,142,76,142,76,214,74,226,70,230,60,232,47,234, +46,166,19,214,102,168,127,200,196,36,225,72,130,96,239,96,168,10,168,100, +166,134,162,164,144,202,111,238,186,120,186,224,186,230,194,232,204,234,220,232, +230,228,234,218,239,205,120,16,161,42,20,74,47,106,238,52,64,52,64,114, +62,156,56,186,42,214,27,236,14,152,63,128,144,68,124,118,108,144,95,160, +130,108,192,108,176,148,156,180,136,198,108,218,71,234,166,166,182,192,202,214, +220,226,237,235,16,44,121,44,46,14,46,76,94,76,95,14,102,152,38,152, +38,106,102,106,103,152,16,184,115,184,68,76,69,244,154,14,136,52,115,82, +138,54,226,54,226,216,222,226,212,232,206,236,193,236,120,128,211,128,162,72, +163,228,128,90,145,114,202,86,179,112,160,132,146,164,132,186,121,204,162,148, +207,185,16,68,99,68,18,158,95,120,60,8,60,216,58,230,52,236,38,238, +33,238,148,8,126,60,95,98,132,52,228,52,222,210,218,222,208,230,198,232, +181,230,176,180,120,180,120,114,178,114,179,181,88,22,62,56,38,82,21,94, +26,26,54,54,70,82,78,118,82,158,80,188,76,210,70,224,58,232,50,234, +37,236,76,110,58,134,34,158,19,170,94,226,247,226,130,226,130,34,216,34, +217,226,130,98,217,98,130,162,217,163,128,12,161,34,18,68,39,106,238,48, +58,48,58,150,48,194,21,236,12,160,57,134,62,228,247,228,108,228,108,84, +206,84,207,228,108,130,207,130,108,178,207,179,24,230,44,196,52,162,54,136, +54,26,206,26,206,74,55,74,62,116,241,116,88,242,88,162,208,162,209,240, +88,216,209,216,146,86,147,163,18,34,94,34,89,134,48,54,42,136,108,136, +102,210,98,222,88,230,76,232,63,234,18,200,81,178,160,12,134,64,113,100, +142,52,228,52,224,212,220,224,210,230,196,232,183,232,184,168,142,168,142,104, +186,104,187,169,16,42,239,42,92,10,93,68,158,8,159,70,78,70,56,104, +31,128,66,94,216,94,216,212,210,224,200,230,190,232,171,234,42,156,193,156, +70,118,93,140,178,114,151,138,122,110,123,238,118,156,88,190,60,208,39,220, +122,168,181,207,20,232,42,194,50,158,52,130,52,28,206,28,206,74,53,74, +52,114,226,114,222,206,222,218,214,228,198,232,183,236,170,198,98,198,98,148, +170,148,171,199,24,190,24,40,76,40,77,182,24,158,77,158,70,224,243,224, +120,224,120,30,204,30,205,224,120,94,205,94,120,158,205,159,60,14,42,66, +23,98,46,60,113,60,14,130,121,130,72,60,72,140,58,186,21,236,68,160, +115,210,236,36,138,36,138,226,247,226,138,96,218,96,218,160,139,161,46,28, +81,66,108,16,137,56,28,84,231,84,202,18,159,84,104,84,84,110,58,132, +21,154,156,84,166,100,192,124,222,138,241,144,72,140,191,140,26,186,231,186, +130,112,131,245,40,20,85,52,16,84,57,114,30,234,77,148,84,222,245,222, +122,222,122,24,210,24,211,222,122,90,211,90,122,156,211,157,14,30,133,30, +16,130,129,112,110,138,111,30,48,30,49,124,48,62,111,62,48,90,111,90, +136,44,214,44,204,66,192,84,168,108,148,122,137,128,140,64,188,94,231,130, +186,138,134,146,88,150,47,152,100,166,62,186,40,194,25,198,106,194,72,216, +46,228,25,236,126,148,127,244,207,154,126,170,140,186,158,202,184,216,210,224, +237,230,208,156,153,197,14,68,103,68,18,156,99,120,62,10,62,230,46,244, +31,230,236,32,124,32,124,224,243,224,124,92,218,92,218,156,125,157,16,68, +101,68,18,158,95,118,62,6,62,220,46,238,31,224,84,222,102,198,112,178, +116,156,120,128,120,26,218,26,218,74,121,74,120,118,245,118,180,84,177,164, +136,244,136,164,224,164,225,242,136,222,225,223,224,36,46,36,46,222,235,222, +46,98,190,98,190,156,47,157,14,172,241,172,64,172,64,26,188,26,189,172, +64,62,189,62,64,98,189,98,64,134,189,134,98,186,60,216,27,238,152,190, +229,237,98,92,98,30,32,30,32,92,99,92,16,230,113,194,30,126,31,224, +68,92,69,210,68,142,109,142,236,30,134,30,134,228,243,228,134,94,218,94, +218,162,135,163,92,90,34,90,34,28,92,28,93,90,10,218,99,190,30,118, +31,210,64,90,65,200,64,134,107,134,92,234,114,198,124,160,126,130,126,26, +218,26,218,72,127,72,126,118,247,118,185,86,148,240,148,166,222,166,223,240, +148,220,223,220,182,86,183,167,64,8,36,60,17,88,106,52,43,52,30,96, +103,96,16,144,109,144,60,96,60,216,93,178,88,232,112,198,122,168,128,138, +128,24,220,24,220,78,129,78,144,242,144,164,222,164,223,240,144,224,221,224, +128,122,245,122,182,90,183,165,80,14,46,80,15,124,58,246,59,58,82,174, +245,174,116,174,116,28,208,28,209,174,116,66,209,66,116,100,209,100,116,138, +209,138,144,190,114,220,91,238,182,190,231,235,84,12,54,78,23,124,164,234, +192,232,210,228,216,220,218,210,220,52,69,52,158,178,80,178,80,112,158,112, +159,179,58,12,59,242,32,66,19,124,72,58,93,98,74,174,245,174,120,174, +120,28,206,28,207,174,120,62,207,62,120,100,207,100,120,138,207,138,138,188, +85,236,178,186,231,233,34,72,21,138,68,16,66,76,66,124,58,178,42,210, +21,238,106,56,67,108,60,166,109,212,238,36,130,36,130,226,243,226,130,98, +216,98,216,160,131,161,12,222,28,194,38,156,40,136,40,26,142,26,142,68, +41,68,41,68,164,114,41,114,64,234,64,158,138,158,139,230,64,214,139,214, +100,80,101,158,184,38,185,180,224,10,224,220,220,228,214,232,206,232,187,235, +62,8,62,224,42,242,29,226,16,68,101,68,18,156,93,120,214,74,130,74, +130,26,214,26,215,74,118,240,118,110,222,110,222,224,222,230,214,232,197,232, +118,146,223,146,118,184,223,185,98,76,38,76,38,34,98,34,99,76,32,246, +32,112,100,112,100,218,98,230,96,234,92,236,75,240,32,152,101,152,32,190, +101,190,160,68,191,88,180,118,200,114,210,110,212,102,214,42,136,42,136,144, +224,144,220,220,216,228,208,236,181,240,118,184,203,184,180,10,169,43,12,70, +92,70,88,126,80,162,62,194,44,216,23,234,64,10,52,70,34,146,101,202, +216,74,130,74,130,28,218,28,219,74,122,244,122,110,224,110,224,224,212,244, +187,228,122,148,225,148,122,186,225,187,72,12,42,84,15,124,50,246,51,70, +92,30,119,58,206,26,179,62,84,80,227,80,72,118,237,118,152,10,142,82, +126,122,104,150,75,176,240,172,206,150,192,134,181,118,154,198,170,196,178,194, +182,190,182,186,182,154,118,154,118,216,118,226,122,232,128,236,194,236,206,234, +212,226,218,216,221,205,52,16,95,46,190,16,153,46,36,62,223,62,14,98, +245,98,128,10,106,78,84,116,50,142,19,160,164,98,174,114,192,130,214,144, +241,156,72,248,72,136,186,136,187,244,72,166,187,166,72,196,187,196,72,228, +187,229,32,76,223,76,14,112,239,112,56,26,89,60,186,24,159,64,124,12, +112,80,96,120,74,142,46,164,19,182,238,172,198,154,176,136,166,124,159,112, +132,196,150,196,162,192,168,188,172,180,174,152,80,152,80,214,80,226,86,232, +92,236,174,236,188,234,196,228,209,203,96,56,24,162,97,148,66,16,22,96, +69,94,18,216,99,196,218,68,132,68,132,20,218,20,219,68,122,238,122,104, +224,104,224,214,222,228,212,230,191,234,122,142,225,142,122,180,225,181,54,8, +54,208,52,220,44,226,27,228,14,70,79,70,14,152,79,122,240,30,94,30, +94,144,92,172,86,200,78,218,69,234,116,50,135,78,108,92,173,92,168,46, +145,92,142,92,140,150,138,184,128,206,107,230,118,120,118,168,165,166,166,124, +165,184,202,48,188,90,175,118,218,126,230,94,187,94,198,124,194,168,180,202, +162,224,145,238,238,238,218,214,206,184,197,151,52,12,52,216,50,228,46,232, +27,236,14,68,81,68,16,154,79,106,144,84,96,84,96,26,144,26,145,84, +145,84,96,46,145,46,96,66,145,66,222,84,172,84,172,26,222,26,223,84, +172,46,223,46,172,64,223,64,118,92,94,122,73,142,106,182,107,110,152,90, +173,104,114,110,233,110,112,130,221,130,112,148,221,148,114,170,237,170,162,110, +163,170,78,188,200,188,178,206,150,222,124,230,81,238,236,238,196,234,164,226, +134,212,116,198,111,189,14,70,101,70,14,156,95,112,60,8,60,228,44,242, +25,228,111,62,96,130,243,130,110,64,212,64,209,130,158,10,158,70,156,108, +152,150,142,176,124,204,104,224,83,240,156,130,166,154,178,178,196,204,214,222, +237,237,18,62,93,62,16,154,91,118,60,6,60,218,40,238,29,222,80,224, +98,192,104,168,110,134,110,118,110,28,218,28,218,72,111,72,140,104,140,152, +218,152,219,102,228,174,229,244,130,174,130,228,229,224,178,86,179,225,66,14, +44,66,26,98,15,112,48,244,49,60,68,220,84,196,92,174,96,150,98,136, +98,28,216,28,216,72,99,72,130,104,130,150,216,150,217,102,228,172,229,242, +118,172,118,224,229,220,174,90,175,223,214,24,162,30,29,34,58,44,81,64, +112,40,135,64,216,106,36,106,36,74,216,74,217,106,194,42,165,74,98,74, +99,106,154,74,155,106,80,200,119,234,96,216,36,232,36,132,110,132,110,186, +37,186,110,158,37,158,126,148,243,148,200,118,200,216,198,228,192,234,182,236, +165,236,142,172,167,207,56,22,81,56,112,14,137,50,200,14,173,64,34,112, +34,72,224,72,225,112,74,186,74,112,186,112,187,184,124,138,118,180,108,202, +88,218,58,230,25,240,142,166,142,216,142,228,152,232,166,236,196,236,212,232, +222,226,228,216,233,199,24,40,65,80,22,220,63,130,76,132,241,132,86,60, +206,60,201,132,148,12,142,136,132,168,112,200,90,220,63,238,144,132,156,162, +172,188,196,212,233,233,36,28,69,66,12,102,54,102,52,220,91,180,84,140, +243,140,92,66,206,66,207,140,152,10,150,98,144,152,136,182,120,206,102,222, +83,238,156,140,166,168,178,192,200,216,233,237,59,16,92,46,34,162,101,150, +58,16,22,96,69,92,16,226,101,202,160,14,134,54,111,78,142,44,202,44, +175,90,236,202,230,218,222,228,210,232,144,232,132,230,124,224,122,212,122,96, +216,96,216,158,123,158,168,96,169,159,18,86,99,86,16,198,101,174,62,18, +63,184,152,14,130,68,103,104,172,234,196,234,212,228,222,218,224,202,228,62, +135,62,140,98,175,130,122,194,203,147,12,42,241,42,94,10,95,68,162,8, +163,68,46,244,46,82,212,82,213,242,168,104,124,112,81,116,64,142,193,142, +128,112,129,208,128,144,94,178,73,196,128,146,185,188,46,222,213,223,66,16, +40,70,21,98,48,56,119,56,32,104,107,104,22,150,117,150,66,104,66,228, +115,192,162,14,134,78,121,102,178,234,202,232,214,228,224,222,226,212,228,190, +230,164,230,60,145,60,144,106,185,136,128,188,211,149,38,72,38,28,224,28, +225,72,52,80,209,80,120,44,60,138,211,138,12,182,243,182,136,98,137,243, +18,74,245,74,48,32,202,32,202,120,43,120,104,32,102,84,88,130,72,158, +52,180,21,202,88,246,88,162,206,162,207,244,88,224,207,225,59,14,90,62, +91,212,26,62,26,192,91,186,58,14,59,188,194,40,235,84,166,14,142,56, +120,78,221,70,150,96,111,130,192,100,239,130,166,120,134,170,117,188,102,236, +130,230,162,216,186,194,202,168,212,146,151,146,152,170,164,190,180,208,200,220, +241,237,82,12,58,66,38,96,17,120,56,246,57,72,186,32,231,78,156,10, +104,76,217,64,138,92,87,136,190,92,237,130,158,118,128,158,93,188,84,236, +122,228,156,214,184,186,200,162,206,144,141,144,138,174,164,200,194,218,239,235, +50,20,77,58,16,72,103,72,28,104,51,166,14,210,107,192,88,94,65,198, +164,10,118,70,215,64,186,34,229,78,144,88,124,114,103,130,186,88,233,122, +162,112,134,152,113,178,142,142,206,142,190,176,174,198,148,218,126,230,103,238, +142,162,158,190,186,214,212,228,237,237,34,22,77,58,18,84,59,116,28,234, +69,150,182,34,225,82,152,10,96,76,209,64,136,92,89,134,176,92,227,132, +148,120,120,160,93,186,82,240,122,230,154,212,178,188,188,168,198,148,129,148, +132,172,156,194,188,218,235,237,30,30,124,30,124,116,29,116,16,74,149,74, +70,30,68,88,56,132,40,160,21,184,58,236,58,154,128,154,129,230,58,212, +127,212,172,244,172,32,228,32,206,114,220,130,230,146,236,166,234,186,224,198, +210,202,195,203,14,34,84,34,79,138,38,58,34,140,98,140,94,224,88,230, +78,236,63,238,14,198,79,180,190,38,231,78,170,16,122,78,221,68,152,92, +113,128,194,96,241,128,172,114,144,152,121,174,114,240,142,226,166,208,186,188, +202,162,208,146,151,146,238,238,202,222,174,202,154,178,141,157,28,184,28,46, +72,46,73,168,28,154,73,154,138,10,167,38,100,84,100,48,224,48,225,82, +146,62,124,96,110,114,97,128,80,184,122,164,156,140,186,108,198,86,133,86, +132,108,160,134,190,152,237,172,118,244,118,174,202,174,203,244,118,226,203,227, +32,214,32,52,70,52,71,206,32,184,71,184,116,12,116,80,114,126,108,170, +94,204,61,240,82,64,154,64,146,212,144,224,140,226,128,230,118,232,113,232, +184,234,184,54,224,54,225,230,184,202,225,203,12,104,241,104,112,8,113,104, +206,48,113,48,114,116,115,246,128,150,203,201,28,196,28,48,76,48,77,190, +28,168,77,168,154,12,130,52,105,80,94,138,128,130,154,114,182,84,210,44, +137,44,140,70,164,98,190,116,218,130,239,134,124,246,124,154,212,154,213,242, +124,220,213,221,34,34,225,34,18,120,243,120,90,34,90,122,88,148,80,174, +62,204,31,236,172,34,173,239,60,10,60,228,42,242,31,224,16,70,97,70, +18,158,93,122,118,12,118,112,161,80,118,50,163,50,184,6,184,90,186,98, +190,104,198,106,210,106,222,104,230,102,232,96,239,82,234,36,185,60,120,244, +120,140,218,140,219,242,120,180,219,180,120,220,219,221,56,8,57,244,12,70, +93,70,54,78,42,120,30,148,15,172,88,132,57,94,116,12,116,112,163,82, +162,52,117,52,186,8,186,92,188,100,192,104,202,106,222,106,230,102,236,98, +241,82,232,38,189,56,120,244,120,142,212,142,213,242,164,110,153,142,120,180, +213,180,120,220,213,221,32,24,32,78,118,78,119,24,72,10,73,78,22,110, +108,110,108,152,34,152,34,226,113,180,102,238,128,214,140,190,146,162,148,136, +148,36,198,36,198,210,200,222,206,226,214,228,226,226,230,222,232,218,241,199, +50,12,51,246,30,70,17,120,66,68,81,100,150,190,127,148,138,170,94,206, +94,32,136,32,136,122,95,122,94,78,137,78,156,32,239,32,194,32,194,80, +190,128,180,166,168,194,148,220,127,242,166,66,158,118,241,118,200,138,200,218, +200,224,204,230,212,232,222,232,232,230,236,224,241,201,26,34,137,34,18,118, +143,118,80,34,81,238,166,46,167,180,222,14,222,216,218,224,208,228,200,228, +187,231,16,88,91,88,18,202,91,176,54,16,55,186,90,54,239,54,80,156, +245,156,112,156,112,232,237,232,122,12,123,156,202,10,203,156,122,88,203,88, +122,122,203,122,158,168,129,208,186,172,221,205,16,50,147,50,10,150,153,150, +42,150,42,220,133,220,52,12,53,148,116,10,117,148,52,84,117,84,52,116, +117,116,82,168,57,202,104,168,133,196,134,82,230,78,224,212,220,222,212,226, +204,228,192,230,183,230,180,14,178,108,172,152,162,186,148,214,125,241,16,82, +105,82,16,196,109,160,62,14,63,176,152,10,144,40,136,72,122,102,109,124, +212,110,230,62,139,62,170,92,164,146,150,186,126,214,89,240,166,140,176,166, +192,194,212,216,239,235,16,44,113,44,62,44,52,84,38,114,19,140,46,222, +46,110,94,110,95,216,46,192,95,192,158,10,148,46,134,90,117,122,212,108, +226,66,143,66,168,98,166,138,158,174,140,204,114,224,93,240,234,232,208,210, +188,184,174,154,169,141,220,20,146,30,74,32,43,32,50,62,217,62,20,94, +245,94,22,184,52,164,80,136,100,112,116,80,131,30,84,242,84,126,202,126, +203,240,84,158,203,158,84,190,203,190,84,222,203,223,118,14,153,36,230,48, +52,48,52,164,44,202,25,238,242,110,53,110,142,56,142,226,138,238,124,242, +113,242,76,80,206,80,206,142,77,142,78,162,113,180,68,220,143,182,230,228, +202,214,174,190,156,170,143,152,210,156,171,187,52,10,53,244,32,68,24,104, +15,128,68,62,87,104,146,12,177,32,242,42,104,42,104,152,98,194,77,234, +246,104,105,104,122,74,214,74,214,136,123,136,166,48,166,224,162,232,154,236, +142,238,135,238,120,156,147,172,110,212,167,178,238,222,202,196,167,150,228,152, +193,183,10,96,97,96,58,14,59,250,16,40,41,74,92,36,73,70,14,186, +38,146,59,106,90,150,59,112,152,10,183,34,240,46,110,46,110,146,102,196, +81,232,246,106,111,106,170,52,170,222,170,230,166,236,160,238,141,240,126,76, +216,76,216,136,127,136,126,158,149,180,112,212,171,182,236,220,204,194,171,152, +228,156,197,185,12,72,101,72,14,158,99,120,58,14,58,226,36,242,25,228, +108,46,235,46,92,218,245,218,166,46,167,219,10,70,91,70,14,160,95,122, +60,10,60,224,40,244,27,228,142,14,175,48,104,66,235,66,86,238,108,224, +122,204,132,182,132,106,192,106,192,210,194,222,202,228,212,228,226,226,232,220, +232,216,239,197,36,74,25,132,64,10,64,72,62,98,62,140,56,174,42,206, +21,230,98,56,63,110,100,196,63,150,144,16,181,52,112,66,241,66,94,236, +116,218,126,206,134,188,136,176,136,108,198,108,198,206,200,220,206,226,216,228, +226,228,232,222,243,197,52,50,163,50,18,96,247,96,114,10,115,96,200,28, +134,106,76,162,19,204,224,136,105,136,134,136,120,180,194,180,184,222,176,232, +162,238,146,238,117,239,14,74,97,74,14,166,91,122,60,12,60,218,58,226, +52,232,44,236,34,236,29,236,110,48,191,48,92,96,245,96,154,10,155,96, +212,32,164,108,126,152,85,188,230,136,141,136,166,136,156,176,216,176,212,208, +206,226,196,232,176,232,161,233,36,68,23,130,67,12,66,12,64,66,64,110, +62,144,56,180,42,208,25,232,100,60,65,104,60,160,103,208,114,52,193,52, +98,96,245,96,156,10,157,96,230,30,168,110,132,144,93,172,232,136,143,136, +168,136,162,172,220,172,216,206,210,220,198,228,182,230,163,231,78,22,49,62, +212,48,61,48,16,76,243,76,130,16,131,74,192,126,62,126,62,98,192,98, +193,126,102,244,103,126,148,246,149,126,26,154,103,154,36,184,103,184,20,212, +103,212,148,156,229,156,148,184,221,184,148,212,237,213,108,12,143,48,18,64, +235,64,18,240,44,228,64,212,82,182,86,156,86,110,158,110,158,210,158,222, +166,228,176,230,198,230,210,228,220,222,228,212,233,193,12,84,93,84,52,14, +53,190,14,206,95,176,168,164,116,164,116,88,168,88,169,164,90,38,245,38, +210,38,210,226,204,232,196,236,175,239,16,50,237,50,90,12,91,84,162,12, +163,84,14,104,245,104,190,104,190,214,188,228,180,234,166,236,149,238,138,190, +60,190,60,142,138,142,139,191,16,70,101,70,60,8,61,240,14,172,36,138, +48,108,61,82,94,134,61,94,92,38,243,38,176,232,192,232,206,228,212,224, +216,212,217,38,174,162,120,162,120,94,172,94,173,163,14,72,101,72,60,10, +61,244,14,166,38,130,61,76,94,130,61,96,222,108,126,108,126,28,220,28, +221,108,126,70,221,70,170,28,171,244,102,144,243,144,90,220,118,202,144,178, +158,160,171,144,238,216,216,200,192,176,171,149,14,40,97,40,56,40,48,82, +36,112,15,144,38,216,38,112,80,112,81,216,38,190,81,190,112,46,229,46, +96,82,241,82,164,10,165,82,158,92,112,132,217,124,188,98,229,134,86,228, +245,228,112,228,112,158,218,158,219,228,146,228,147,158,182,228,183,159,108,108, +38,108,38,30,108,30,109,108,38,70,109,70,74,30,75,244,18,140,127,140, +20,212,44,190,58,168,73,146,118,192,75,154,126,30,241,30,144,192,144,80, +222,80,223,188,182,30,171,80,180,106,180,164,170,198,150,222,123,240,188,194, +239,237,106,22,72,30,27,34,18,88,119,88,70,244,71,30,18,188,50,140, +71,102,110,146,71,108,138,38,183,82,134,100,179,144,208,10,209,246,112,178, +247,159,26,48,231,48,42,84,209,84,126,8,127,84,34,158,34,118,224,118, +225,158,18,240,52,230,72,218,86,196,88,176,88,150,164,150,164,214,166,224, +172,228,178,230,212,230,220,228,226,222,234,216,239,203,26,198,26,46,68,46, +69,184,26,168,69,168,134,14,175,46,86,56,237,56,192,88,162,130,142,152, +120,174,96,188,77,198,148,66,102,128,167,122,216,126,180,174,158,196,130,220, +89,242,232,236,171,187,16,32,243,32,192,32,192,208,188,224,180,228,147,232, +132,160,60,160,60,84,132,84,133,161,42,22,81,52,16,84,57,110,22,232, +59,140,206,98,108,98,108,30,204,30,205,98,108,64,205,64,130,106,108,132, +88,150,75,160,190,238,204,236,218,230,220,222,222,132,109,132,158,146,140,178, +123,198,194,194,153,158,196,216,100,216,101,157,20,50,237,50,192,148,64,148, +64,94,192,94,193,148,128,94,129,10,20,240,48,232,74,220,92,202,102,180, +104,166,107,148,238,200,230,224,218,234,208,236,166,236,152,234,148,226,148,222, +149,149,68,12,101,44,16,58,149,58,32,182,56,164,76,144,92,126,106,104, +117,88,78,66,38,126,95,120,138,126,116,158,96,184,76,204,50,222,27,234, +142,224,99,182,176,188,177,42,186,238,200,238,210,236,218,228,220,220,221,11, +28,16,67,54,8,94,52,94,52,220,89,178,214,102,104,102,104,24,214,24, +215,102,104,66,213,66,160,24,161,242,84,140,239,140,88,222,106,206,124,186, +140,166,159,140,240,212,222,204,202,190,184,172,161,143,16,84,241,84,71,84, +70,84,71,24,134,84,135,8,212,40,135,40,162,236,182,236,192,232,196,228, +196,220,196,116,68,116,69,244,68,152,197,152,68,188,197,189,106,10,143,34, +32,80,32,44,220,44,221,80,40,124,68,102,86,84,109,54,20,174,72,160, +120,132,158,102,180,80,91,80,96,100,126,124,156,140,188,152,237,164,70,246, +70,170,186,170,187,244,70,224,187,225,36,196,36,44,78,44,79,186,36,164, +79,164,92,84,247,84,170,84,171,12,126,84,127,28,170,42,227,42,122,246, +122,116,216,116,216,212,212,228,206,236,187,240,122,150,217,150,122,184,217,185, +116,132,60,156,60,28,198,28,198,100,61,100,60,64,199,64,228,164,198,158, +174,148,148,130,134,112,129,100,216,110,163,138,48,188,205,188,18,230,237,230, +130,230,131,151,112,126,56,154,56,28,192,28,192,92,57,92,56,60,193,60, +216,160,190,154,160,140,134,120,115,92,204,108,151,132,56,176,25,226,118,156, +149,186,194,174,233,214,190,198,184,216,178,226,166,228,148,230,116,230,104,228, +92,226,88,220,89,169,14,98,93,98,16,198,99,172,52,186,53,22,134,16, +175,52,86,66,237,66,238,204,234,218,230,228,222,232,208,232,198,232,190,224, +188,218,188,110,128,110,130,154,126,176,116,206,98,224,79,239,30,206,30,54, +78,54,79,194,30,168,79,168,134,16,173,48,94,68,233,68,236,202,232,218, +228,228,222,234,218,236,202,236,190,236,184,230,182,222,182,112,126,112,126,176, +122,200,112,220,83,243,108,16,143,40,34,96,34,56,220,56,221,94,104,88, +74,114,52,130,35,140,150,88,225,138,52,156,207,156,18,228,237,228,130,156, +131,229,24,34,109,34,16,120,107,98,66,106,67,34,238,102,236,116,230,130, +222,134,212,134,200,134,194,132,190,124,190,114,192,28,126,28,126,82,120,110, +106,132,93,146,54,168,25,224,120,150,151,182,194,162,233,210,186,196,182,212, +176,224,164,228,104,228,94,226,90,222,88,212,89,165,36,234,50,234,66,230, +74,222,74,90,118,38,19,38,20,160,123,116,234,182,228,206,224,218,216,224, +208,226,172,226,164,224,160,218,160,212,161,15,18,70,97,70,20,156,93,118, +64,6,64,222,46,242,33,226,158,10,181,36,114,88,114,50,230,50,231,86, +154,84,130,114,109,136,186,86,227,130,118,152,227,152,96,222,243,222,170,152, +171,223,14,74,97,74,18,162,97,122,60,10,60,226,38,244,27,226,232,36, +114,36,114,224,245,224,208,68,196,100,182,134,160,164,137,192,136,78,182,130, +221,189,56,222,56,52,198,52,199,218,56,190,199,191,20,70,117,70,24,156, +113,116,74,12,74,222,54,240,39,224,142,228,142,50,220,50,221,224,142,196, +221,197,98,14,137,38,34,82,34,48,222,48,223,82,48,92,115,92,28,134, +121,134,20,242,44,222,56,198,62,172,64,154,65,134,238,196,232,216,226,226, +210,232,188,232,118,232,104,230,98,226,96,218,97,134,130,130,208,130,196,152, +182,170,166,184,146,200,123,212,136,156,182,182,213,202,160,66,161,130,208,96, +161,97,14,74,91,74,56,12,57,244,16,170,36,134,46,110,55,82,90,132, +57,96,102,72,241,72,116,244,116,142,214,142,215,242,116,218,213,218,166,10, +167,143,102,88,42,88,42,32,104,32,105,88,208,88,142,88,142,32,208,32, +209,88,158,108,189,124,20,142,229,142,128,102,120,136,114,166,100,190,82,208, +54,226,29,238,226,238,200,226,178,212,160,198,138,170,127,143,120,14,153,34, +38,82,38,46,226,46,227,78,114,58,88,74,61,84,150,58,205,82,22,236, +40,214,50,196,56,172,58,152,58,98,208,98,208,132,59,132,92,146,92,178, +204,178,205,146,220,190,221,242,78,190,78,228,221,224,144,142,145,227,14,44, +243,44,91,10,90,10,91,82,166,10,167,80,14,114,243,114,58,248,58,162, +196,162,197,244,58,222,197,222,128,74,129,163,14,34,125,34,30,244,30,84, +110,84,111,240,30,180,111,180,30,220,111,220,58,34,58,104,54,128,45,152, +84,34,84,130,86,140,90,142,111,142,152,26,142,64,129,90,230,62,145,62, +124,120,245,120,184,120,185,12,146,242,146,156,218,156,219,240,146,218,219,219, +124,12,161,36,238,48,50,48,50,142,42,182,34,210,21,232,68,92,225,92, +134,62,88,146,221,146,60,188,245,188,154,244,155,111,42,16,73,46,18,68, +82,68,56,110,17,146,58,244,59,108,92,160,59,128,94,108,73,138,146,16, +185,40,240,50,110,50,110,158,102,196,79,238,124,94,235,94,174,62,132,152, +237,152,118,190,247,190,186,112,187,247,24,52,233,52,124,10,98,62,68,92, +44,106,19,118,240,112,204,98,170,76,149,52,80,102,181,102,30,140,229,140, +120,240,146,240,168,238,180,228,190,180,78,180,91,141,14,80,85,80,14,204, +93,172,52,10,53,186,88,46,231,46,154,4,142,50,126,70,106,90,83,106, +232,100,208,90,182,68,167,46,114,102,197,102,82,140,233,140,146,236,174,234, +190,230,198,220,202,206,206,176,124,176,131,141,14,76,93,76,14,160,87,138, +58,14,58,222,42,246,25,228,98,50,235,50,162,10,144,58,126,90,108,108, +91,122,238,116,210,100,192,80,182,66,177,50,124,112,201,112,96,146,235,146, +148,236,172,236,188,232,198,224,200,218,204,180,130,180,141,147,82,92,30,92, +30,34,84,34,85,92,16,216,103,190,30,122,31,210,64,92,65,200,64,140, +97,140,104,44,229,44,160,10,144,60,124,88,99,110,236,100,212,88,190,70, +169,44,126,110,203,110,104,140,233,140,150,236,174,234,190,230,198,220,204,194, +204,176,138,176,149,141,18,236,32,208,36,178,36,158,36,32,90,32,90,222, +80,232,70,234,63,232,36,90,91,90,36,146,91,146,108,46,233,46,166,8, +160,48,148,72,138,86,124,98,109,110,238,102,216,92,202,78,188,62,179,46, +136,102,209,102,108,138,239,138,162,232,184,232,202,228,206,222,212,176,144,176, +153,139,14,88,97,88,14,198,101,170,54,184,55,14,96,134,245,134,106,66, +214,66,215,134,78,238,110,222,132,200,152,174,158,140,160,130,161,10,238,232, +206,212,182,186,166,160,159,143,64,12,42,50,19,78,48,42,125,42,96,76, +81,42,164,10,144,48,127,74,148,40,237,40,202,80,181,40,92,162,243,162, +106,110,202,110,203,162,152,76,148,168,134,194,118,214,87,236,232,234,196,216, +176,196,162,178,153,162,36,112,21,168,82,110,99,140,64,244,65,75,80,14, +56,66,34,98,15,120,52,246,53,72,158,10,142,42,126,68,100,96,77,118, +240,110,204,86,178,56,157,16,110,114,209,114,92,158,231,158,152,166,96,234, +207,218,180,188,227,241,34,64,19,122,80,60,95,102,58,244,59,8,90,136, +241,136,108,66,212,66,209,136,84,234,116,210,138,180,150,152,156,120,158,58, +159,8,236,234,214,218,192,198,176,170,161,137,118,12,149,34,36,80,36,46, +226,46,227,80,54,82,205,82,104,58,105,106,158,60,159,106,64,190,64,120, +196,120,197,190,20,234,54,228,80,220,100,208,112,194,122,168,127,138,234,198, +230,216,224,226,216,230,204,232,162,232,152,230,146,224,146,216,147,163,14,48, +129,48,24,84,125,84,74,84,75,10,24,116,117,116,14,150,129,150,44,174, +17,222,96,172,123,206,46,236,68,236,74,230,75,150,166,10,154,64,142,90, +131,110,210,106,224,64,155,64,118,238,136,226,150,208,162,186,168,166,172,142, +174,128,175,88,236,230,222,218,206,198,196,180,186,158,175,125,232,220,36,220, +36,28,225,28,66,70,209,70,74,118,199,118,54,178,219,178,136,70,137,179, +70,12,44,56,21,84,128,40,55,40,96,72,79,40,170,8,152,40,133,70, +242,40,155,40,202,72,183,40,224,88,50,88,50,226,235,226,76,120,209,120, +84,154,205,154,74,194,213,194,140,120,141,195,36,228,54,226,68,220,76,208, +78,194,80,170,78,130,74,90,54,52,29,26,86,22,52,68,23,94,18,172, +48,146,75,114,106,38,235,38,114,122,227,122,96,216,245,216,168,38,169,217, +66,248,67,12,22,78,99,78,18,168,44,134,67,92,96,134,67,98,240,32, +116,32,116,224,249,224,136,72,233,72,144,124,227,124,136,182,241,182,184,72, +185,183,20,50,125,50,20,154,40,128,56,100,71,50,54,222,54,112,102,112, +103,210,54,192,103,192,166,16,207,44,106,240,126,214,136,188,142,158,142,56, +245,57,30,214,30,30,84,30,85,208,30,82,85,82,30,134,85,134,30,186, +85,186,240,26,120,26,120,222,243,222,136,68,231,68,140,122,223,122,134,182, +231,182,180,68,181,183,32,212,32,40,86,40,87,206,32,112,85,112,32,182, +87,182,156,12,189,46,90,240,110,216,124,186,128,154,128,58,239,59,28,34, +71,72,20,198,73,130,204,114,104,114,104,30,204,30,205,114,60,234,90,220, +112,200,124,176,128,154,131,114,236,198,230,212,224,222,214,224,186,224,178,222, +174,218,172,210,173,115,48,32,215,32,22,94,239,94,120,228,160,226,176,222, +188,214,194,202,202,146,80,146,97,95,32,42,239,42,106,10,88,56,70,86, +48,108,23,124,110,74,91,112,202,72,179,104,146,58,142,88,134,110,118,126, +90,142,59,152,236,150,204,140,180,128,160,112,143,90,18,226,247,226,60,226, +60,168,206,168,207,226,110,226,111,168,158,226,159,169,50,22,50,60,218,60, +219,24,134,10,135,60,46,180,47,92,28,236,48,224,68,208,82,186,84,170, +90,132,93,80,110,100,216,100,217,236,118,154,217,154,108,212,217,213,110,12, +151,32,30,82,30,42,220,42,221,80,102,58,72,74,51,82,144,56,195,78, +28,116,107,116,16,156,111,156,22,234,40,220,54,202,66,180,68,160,70,134, +73,88,104,204,69,176,128,188,128,94,206,94,207,186,100,240,120,230,144,212, +158,192,162,172,169,116,238,208,236,222,226,232,216,236,202,236,186,236,180,232, +176,224,176,220,177,165,12,40,239,40,92,8,93,64,162,8,163,64,34,80, +112,80,92,110,54,146,19,166,44,100,71,130,138,72,152,96,172,120,190,134, +212,146,237,158,194,66,155,96,214,94,179,122,92,132,171,132,52,172,203,172, +124,132,118,176,112,194,96,210,82,222,62,232,45,242,140,198,190,222,221,243, +26,52,229,52,128,14,124,36,114,60,100,80,84,94,64,104,38,116,17,124, +142,52,150,66,168,84,186,96,206,104,224,112,241,116,76,116,195,116,36,154, +221,154,130,86,131,154,58,194,203,194,30,232,231,232,130,164,131,233,124,124, +34,124,34,50,124,50,125,124,74,14,53,50,34,86,125,86,78,50,78,94, +76,128,70,152,60,180,44,206,19,236,90,142,90,206,90,218,94,224,98,228, +108,230,118,232,200,232,216,230,226,224,230,216,236,208,239,200,124,142,104,196, +141,188,132,168,147,204,148,40,185,72,146,92,183,126,144,156,241,146,206,206, +207,23,74,14,52,64,17,122,52,244,53,68,214,130,102,130,102,44,214,44, +215,130,152,10,139,42,102,88,213,88,160,44,156,104,150,146,136,182,116,210, +79,238,164,146,164,220,166,228,174,234,186,236,208,236,222,234,230,226,241,210, +204,146,182,194,231,186,220,166,237,195,62,14,38,68,21,100,72,94,90,62, +41,62,52,106,52,222,93,194,216,78,114,78,114,42,216,42,217,78,82,110, +243,110,164,12,165,110,114,204,114,138,216,138,217,198,162,156,162,184,156,200, +144,214,126,226,108,234,91,240,178,198,237,239,30,72,17,128,74,64,91,108, +54,14,55,248,220,126,112,126,112,46,220,46,221,126,160,10,147,46,112,84, +221,84,168,46,162,130,158,150,146,176,130,200,112,220,87,238,170,146,170,216, +170,222,174,230,182,232,196,234,208,234,224,232,234,224,239,208,206,144,186,192, +231,182,218,158,237,193,40,24,79,54,20,88,61,116,30,232,71,154,212,72, +104,72,104,38,212,38,213,72,74,104,245,104,158,104,159,6,104,206,104,136, +214,136,215,198,160,156,154,178,146,198,134,214,114,226,89,238,170,190,235,235, +16,86,95,86,14,196,95,166,54,14,55,180,114,188,114,58,228,58,229,182, +114,110,229,110,114,162,229,162,172,244,173,9,198,110,62,110,62,28,198,28, +199,110,62,68,199,68,56,130,56,234,127,212,124,166,57,166,148,122,148,210, +150,222,156,226,168,230,188,232,212,230,224,226,230,218,234,210,239,194,218,146, +149,177,60,10,60,224,44,238,25,222,18,74,93,74,18,154,93,118,110,240, +110,32,226,32,227,238,110,218,227,218,126,92,209,92,166,200,167,48,124,166, +150,132,167,92,206,158,167,111,40,236,40,28,220,28,221,234,40,214,221,214, +62,86,197,86,128,196,129,44,64,172,96,142,129,96,190,164,129,101,14,68, +99,68,16,160,95,120,62,10,62,236,44,246,31,230,224,14,170,28,136,32, +111,34,102,88,245,88,126,244,126,142,222,142,223,240,172,142,173,28,126,220, +223,221,14,70,103,70,14,158,103,116,64,10,64,228,42,242,29,224,156,14, +185,46,240,60,128,60,128,160,122,190,110,216,91,243,126,12,155,36,240,44, +44,44,44,156,38,188,19,238,100,56,125,74,62,82,161,82,144,132,82,132, +82,106,144,106,145,132,62,158,142,158,112,180,112,224,110,232,106,236,98,238, +87,236,62,204,159,190,202,212,212,212,224,208,232,198,234,182,230,166,204,136, +228,78,180,78,181,249,50,16,85,48,40,242,41,60,104,36,218,36,218,222, +200,240,187,224,70,70,97,90,60,106,89,128,70,214,93,150,190,68,138,76, +109,76,102,112,203,112,178,202,122,202,122,152,178,152,179,202,150,152,151,75, +16,86,95,86,18,206,103,166,58,16,59,184,148,10,177,50,100,70,233,70, +126,104,151,196,84,228,241,228,210,96,177,229,14,72,93,72,60,12,60,232, +38,244,29,228,18,162,91,122,150,14,183,52,104,70,233,70,122,106,151,190, +96,222,245,222,208,94,175,223,32,194,32,46,68,46,69,182,32,160,69,160, +82,50,179,50,132,12,133,244,162,144,98,144,98,90,164,90,165,144,62,222, +94,196,133,146,172,200,133,158,194,184,195,56,188,232,210,232,220,230,224,226, +226,218,227,15,90,160,111,206,18,210,101,188,62,10,63,198,94,140,30,140, +30,66,94,66,95,140,116,52,235,52,108,100,245,100,150,8,151,100,198,8, +199,100,132,244,132,138,216,138,217,242,132,180,217,180,132,220,217,221,16,236, +32,208,38,184,40,166,40,32,94,32,94,216,92,228,88,232,80,232,69,234, +40,92,95,92,40,148,95,148,112,52,235,52,108,98,245,98,148,14,149,98, +198,12,199,98,136,244,136,132,218,132,219,242,136,176,219,176,136,220,219,221, +48,14,73,38,18,54,107,54,34,74,57,106,12,122,107,122,96,72,75,122, +18,164,107,164,66,122,66,174,62,192,56,212,42,228,29,238,114,48,237,48, +172,244,173,10,218,136,124,136,124,88,220,88,221,136,98,218,118,204,138,184, +173,142,238,214,218,202,202,184,173,141,28,194,28,52,68,52,69,186,28,164, +69,164,108,12,108,228,90,244,77,226,80,72,139,72,78,166,135,122,166,12, +199,52,146,72,239,72,152,104,175,190,126,228,243,228,218,102,183,229,12,40, +239,40,82,10,83,68,169,10,168,10,169,68,34,92,217,92,20,150,231,150, +126,248,127,60,68,108,97,136,184,108,155,138,20,226,50,212,82,188,121,150, +236,222,210,214,180,198,160,182,135,151,32,50,221,50,18,128,233,128,126,244, +127,10,58,70,97,112,154,112,189,68,21,220,20,220,58,198,82,176,125,128, +238,216,206,202,178,184,160,166,133,129,78,246,79,12,24,52,135,52,116,140, +42,140,42,90,116,90,117,140,18,216,52,182,79,144,120,196,79,158,174,14, +154,58,133,88,148,196,148,100,226,100,227,194,158,48,214,48,185,100,122,238, +154,224,170,208,178,196,182,176,189,128,196,200,241,237,14,42,239,42,93,14, +92,14,93,68,164,10,165,68,54,154,55,84,100,158,101,76,120,132,142,104, +159,74,146,100,229,100,170,122,199,148,16,228,241,228,48,228,48,172,202,172, +203,228,102,228,103,172,150,228,151,173,24,50,121,50,80,128,81,10,22,118, +44,100,60,80,81,50,118,94,81,62,132,48,239,48,178,128,179,10,124,110, +146,96,162,74,179,52,236,106,216,94,196,76,179,58,18,154,245,154,124,124, +94,168,78,186,174,210,233,236,180,154,166,176,148,196,124,214,94,228,64,236, +43,239,20,78,105,78,68,246,69,8,20,176,48,134,69,90,100,140,69,100, +158,64,125,24,118,82,239,82,216,20,185,82,126,142,229,142,108,224,243,225, +30,232,46,236,56,234,62,228,62,218,63,12,12,74,99,74,16,158,91,122, +114,76,239,76,118,20,153,62,212,16,179,76,120,138,225,138,102,222,241,223, +66,14,42,54,21,80,118,40,53,40,84,72,65,40,118,76,144,40,159,14, +232,40,145,40,190,74,169,40,154,80,119,138,224,106,141,106,164,122,193,148, +16,226,237,226,52,226,52,170,200,170,201,226,52,148,53,86,98,158,99,82, +102,170,103,226,150,170,151,227,42,240,43,62,44,20,77,56,180,232,194,230, +208,228,212,226,214,220,216,212,216,32,99,32,68,80,187,80,126,220,127,52, +96,120,111,138,156,122,143,138,172,150,82,150,82,106,172,106,173,148,66,206, +90,190,106,176,127,152,188,200,162,182,142,166,127,157,66,22,109,62,28,78, +225,78,182,16,145,78,56,138,199,138,18,216,239,217,34,24,69,50,20,84, +55,112,24,234,59,144,94,12,123,46,84,244,85,52,138,32,224,32,224,218, +206,242,189,226,154,230,155,50,104,74,209,74,126,120,141,138,184,118,171,138, +196,150,112,150,112,104,196,104,197,148,102,212,124,192,136,176,155,152,200,198, +155,163,30,26,61,58,12,90,48,90,44,212,75,168,90,238,91,50,104,18, +127,46,146,30,222,30,222,216,210,236,191,224,156,228,157,52,108,78,205,78, +192,158,118,158,118,106,192,106,193,158,132,124,141,142,180,120,169,142,110,212, +134,188,157,158,198,206,173,179,28,230,38,228,50,226,56,220,57,10,16,70, +91,70,18,156,85,122,110,92,111,18,146,98,147,10,192,8,178,46,159,76, +194,68,219,94,242,46,179,46,112,192,112,114,216,114,217,190,86,234,110,226, +132,210,150,186,154,158,159,136,236,200,230,222,220,228,204,228,182,228,176,216, +174,204,177,167,52,20,53,102,98,12,99,104,158,12,138,58,121,82,236,48, +145,48,166,70,217,102,62,196,62,124,192,124,193,194,122,140,116,174,104,198, +86,216,60,228,23,236,140,162,140,216,146,228,162,230,188,232,212,230,226,222, +233,203,46,248,47,16,24,72,15,130,54,60,71,88,108,248,109,14,68,56, +147,56,64,214,86,188,109,154,144,190,109,164,136,146,78,146,78,94,138,94, +139,146,182,12,168,48,151,76,162,190,162,90,226,90,227,186,142,238,164,226, +180,208,192,184,194,154,197,114,206,202,243,238,196,90,212,46,171,47,84,66, +26,160,85,152,16,216,85,200,64,18,22,100,67,96,108,100,109,20,144,102, +145,16,188,16,174,54,161,76,192,70,223,98,244,48,177,48,112,196,112,118, +210,118,211,194,78,240,104,230,128,216,142,196,152,172,159,138,236,204,232,218, +228,228,218,232,186,232,176,230,172,224,170,220,171,169,36,68,30,104,25,132, +18,236,38,214,52,188,60,160,64,128,66,96,67,8,104,56,67,98,104,202, +63,150,112,78,243,78,126,16,159,64,218,14,183,78,118,144,231,144,104,226, +247,227,40,34,81,64,16,96,59,120,26,236,69,154,106,130,107,32,142,142, +143,18,190,18,176,60,159,94,238,62,177,62,190,90,217,130,72,230,243,230, +104,230,104,160,218,160,219,230,178,160,179,230,142,160,143,231,10,52,101,52, +16,126,95,126,14,224,101,194,56,208,57,52,142,10,175,38,166,206,120,238, +120,50,210,50,210,132,121,132,120,92,211,92,234,236,212,224,194,206,178,186, +168,162,163,132,220,154,181,187,58,246,59,10,18,72,91,72,18,172,59,92, +90,134,59,94,114,12,141,40,144,164,169,214,156,188,106,220,106,54,154,54, +154,140,107,140,106,96,155,96,212,198,226,196,238,190,240,180,240,166,238,152, +232,142,226,130,212,112,238,36,190,36,191,247,22,24,38,36,54,52,70,76, +78,96,82,128,82,158,80,190,76,212,66,226,56,234,44,236,31,236,18,170, +52,146,79,114,92,20,60,60,46,76,19,96,146,14,183,42,166,204,120,232, +120,52,214,52,214,130,121,130,120,90,215,90,238,228,212,212,192,194,176,172, +168,150,163,130,226,146,187,185,124,10,153,34,244,40,46,40,46,144,40,186, +19,232,98,56,119,76,116,176,151,218,134,198,78,224,78,84,140,84,140,162, +79,162,174,248,174,78,228,78,200,138,214,152,228,168,232,186,232,196,228,206, +218,212,199,216,140,122,79,123,56,14,95,44,84,160,129,208,102,182,38,218, +38,52,114,52,114,140,39,140,38,96,115,96,158,244,158,34,218,34,184,112, +198,120,212,136,220,150,226,170,224,184,218,194,206,202,187,207,54,12,87,38, +82,152,119,198,98,174,36,212,36,50,106,50,106,136,37,136,36,94,107,94, +180,228,194,228,206,224,212,220,216,214,216,30,144,30,144,152,140,180,132,202, +120,220,103,238,144,88,217,88,144,146,217,147,38,26,87,54,18,82,63,112, +22,234,77,158,140,12,175,40,160,206,108,236,108,52,210,52,210,134,109,134, +108,94,211,94,234,228,218,220,200,208,190,198,176,180,164,156,160,146,155,134, +220,152,185,189,32,232,42,232,52,232,60,228,62,222,63,12,20,70,97,70, +18,160,89,122,106,50,235,50,146,14,147,82,198,12,199,82,108,132,108,100, +234,100,235,130,90,238,108,228,124,214,136,198,142,182,148,160,155,120,104,152, +212,150,208,214,204,222,200,228,192,230,188,230,167,233,20,44,237,44,94,10, +95,76,162,8,163,74,36,130,36,92,222,92,223,130,30,236,50,230,70,222, +88,208,102,192,112,172,116,154,121,112,48,154,190,154,186,204,184,216,176,226, +160,230,143,233,116,12,139,40,32,90,32,50,226,50,227,88,86,80,64,126, +49,152,210,118,71,118,136,248,137,68,18,178,241,179,40,56,169,56,10,106, +245,106,110,106,111,12,206,30,144,112,108,148,64,178,19,204,212,202,208,218, +200,228,184,230,118,230,106,230,100,228,96,220,97,138,200,148,97,187,80,12, +56,70,42,96,23,124,60,244,61,62,98,54,195,54,80,104,249,104,152,104, +153,12,222,30,180,94,146,134,114,162,79,184,236,196,234,208,230,218,220,226, +204,230,180,232,158,232,142,228,136,222,134,216,135,128,218,146,174,166,135,177, +60,14,50,82,34,156,64,176,99,210,14,78,92,76,84,130,74,168,54,198, +19,230,114,56,199,56,104,108,241,108,160,108,161,12,224,38,180,104,146,144, +101,180,230,200,226,216,218,228,202,234,182,236,158,236,146,232,144,226,145,136, +218,150,145,183,10,36,119,36,26,234,26,76,102,76,103,232,52,36,52,88, +50,108,48,122,37,144,76,36,76,118,76,128,82,130,103,130,26,170,103,170, +26,210,103,210,164,12,144,48,123,72,120,134,146,120,168,104,186,82,210,46, +147,46,148,66,166,84,190,106,216,120,239,130,140,244,140,148,210,148,211,244, +140,222,211,223,34,58,21,124,20,232,44,196,56,162,62,116,63,8,102,44, +63,96,104,202,61,144,156,8,132,56,113,88,138,42,212,42,196,72,166,106, +134,126,99,142,144,66,168,100,190,116,218,134,239,142,132,242,132,150,210,150, +211,240,132,218,211,219,36,24,75,56,22,84,59,116,26,230,73,150,88,48, +235,48,134,84,135,14,188,82,189,12,92,132,92,100,230,100,231,132,96,154, +208,150,202,216,196,226,186,232,163,234,148,118,144,160,132,196,108,222,81,239, +18,48,143,48,54,14,54,80,108,80,109,14,126,152,38,152,38,110,126,110, +127,152,12,184,141,184,80,80,81,244,134,78,228,76,222,204,220,212,214,218, +206,222,179,224,176,12,176,104,172,134,168,162,156,190,138,214,117,233,206,22, +156,32,114,36,84,36,60,36,48,122,231,122,94,234,112,234,126,230,130,226, +131,60,82,152,50,200,29,222,168,152,227,221,38,26,215,26,28,100,28,54, +226,54,227,98,128,26,129,122,50,82,103,82,50,108,105,108,150,80,203,80, +152,106,203,106,50,244,50,140,204,140,205,240,50,180,205,180,50,220,205,220, +128,140,129,221,68,12,42,66,19,90,94,60,47,60,30,104,95,104,22,150, +97,150,62,104,62,224,95,198,110,32,235,32,112,98,112,60,236,60,237,96, +172,132,173,32,126,90,155,90,122,118,155,118,188,90,217,90,188,118,223,118, +116,248,116,148,226,148,227,244,116,186,227,186,116,226,227,226,170,148,171,227, +18,34,239,34,96,8,97,56,162,10,163,56,38,68,219,68,34,128,34,94, +224,94,225,126,130,152,131,68,58,118,107,118,58,140,107,140,150,116,201,116, +150,140,201,140,56,246,56,168,204,168,205,246,56,198,205,198,56,230,205,230, +130,168,131,231,34,28,231,28,36,94,66,78,84,60,96,44,107,28,196,98, +86,98,86,58,196,58,197,98,24,132,127,132,20,196,38,184,52,170,64,154, +77,132,58,240,58,170,114,170,115,238,58,216,115,216,136,130,245,130,132,196, +156,176,168,160,187,130,162,240,162,168,226,168,227,236,162,216,227,217,208,90, +52,90,52,24,208,24,209,90,52,56,209,56,130,24,131,90,168,138,221,178, +198,162,46,172,177,108,134,128,54,126,113,96,130,168,130,222,126,232,118,236, +97,236,32,232,62,214,93,192,164,190,229,229,14,112,44,74,73,12,48,246, +49,66,200,104,104,104,104,32,200,32,201,104,104,68,201,68,148,104,149,32, +84,242,84,132,138,132,139,240,84,174,139,174,84,220,139,220,110,220,111,132, +164,238,164,132,224,132,225,238,164,174,225,174,164,222,225,222,194,132,195,223, +150,34,197,74,118,18,60,70,181,62,94,102,121,144,70,86,26,142,111,130, +196,106,229,148,178,84,138,142,213,130,48,184,209,184,18,232,241,232,126,232, +127,153,14,70,85,70,16,154,87,122,28,232,42,230,52,228,56,224,58,218, +59,10,100,28,227,28,162,124,163,28,98,94,98,56,228,56,229,94,114,84, +145,84,116,108,145,108,180,84,209,84,180,108,209,108,106,242,106,138,218,138, +219,240,106,178,219,178,106,218,219,218,162,218,163,139,20,236,32,208,40,184, +42,154,44,144,44,26,100,26,100,206,98,218,96,222,88,228,80,228,71,228, +44,86,101,86,44,142,101,142,120,76,230,72,224,210,220,222,210,226,200,228, +189,228,172,6,172,86,170,118,166,148,158,176,142,208,117,239,64,24,99,60, +192,22,153,62,24,80,231,80,126,136,127,10,26,136,58,124,90,106,123,80, +212,136,178,116,127,92,18,168,239,168,20,240,54,232,90,216,104,202,114,188, +118,172,123,144,230,236,200,228,180,220,162,206,144,188,131,169,40,22,81,54, +22,84,67,114,30,234,75,142,110,238,110,34,220,34,221,234,110,94,221,94, +110,150,221,150,110,208,221,209,14,76,89,76,58,244,59,12,18,166,44,122, +59,84,90,136,59,100,110,42,225,42,100,80,237,80,164,80,165,10,142,94, +109,130,188,96,229,126,162,114,134,154,103,182,98,236,126,228,148,216,174,196, +192,172,204,146,141,146,140,168,164,198,188,218,216,228,237,237,16,72,99,72, +64,240,65,12,18,166,42,126,65,74,92,122,65,92,224,86,114,86,114,28, +224,28,225,84,150,86,151,28,186,28,187,84,154,96,181,120,94,132,247,132, +90,236,110,226,126,212,140,194,146,176,153,132,174,228,192,230,202,226,208,222, +210,212,214,168,149,169,22,44,61,80,16,212,65,144,150,12,126,56,96,92, +63,118,242,108,208,92,176,64,143,26,130,88,167,124,112,188,181,246,82,144, +212,144,149,217,232,30,44,30,44,148,40,184,19,228,206,144,86,144,86,62, +204,62,205,144,86,102,205,102,70,178,223,178,54,222,239,222,146,222,147,63, +136,22,94,30,37,34,24,68,153,68,88,142,89,32,26,124,60,100,89,74, +134,110,89,76,172,32,173,110,186,134,208,132,214,128,216,116,217,16,16,162, +241,162,130,240,131,128,26,222,68,210,96,192,125,162,232,220,206,216,180,204, +164,192,148,180,135,163,132,20,92,30,60,34,39,36,22,68,149,68,90,122, +91,30,24,120,56,100,89,68,134,110,91,78,172,30,173,102,184,124,202,124, +212,122,216,118,218,112,219,18,78,132,52,166,39,180,212,160,59,160,24,200, +239,200,136,244,137,125,116,20,66,28,31,30,22,62,119,62,74,116,75,28, +22,112,48,92,75,64,108,92,75,70,166,12,131,64,182,108,200,104,210,100, +216,94,224,46,145,46,148,98,170,72,185,46,18,158,62,144,96,122,126,98, +146,116,166,130,196,144,220,152,239,156,94,240,112,238,122,234,126,228,127,126, +70,154,99,174,40,218,127,184,212,222,127,174,180,152,149,187,72,16,42,56, +29,70,130,44,53,44,94,74,75,44,170,14,146,50,139,60,240,42,155,42, +200,72,183,42,114,66,137,80,26,88,239,88,84,100,136,120,175,138,166,96, +118,126,83,140,62,104,62,150,196,150,197,102,48,244,48,176,212,176,212,220, +210,230,206,234,198,236,185,238,150,190,177,220,122,158,88,218,167,209,36,232, +48,230,62,226,70,218,74,194,78,162,78,136,76,110,74,90,68,70,56,54, +46,46,25,30,88,22,50,66,21,88,18,164,50,136,75,104,224,124,120,124, +120,28,226,28,227,124,227,124,120,74,227,74,108,170,235,170,90,224,245,224, +172,224,173,29,110,12,149,32,18,46,239,46,60,70,60,122,200,122,201,64, +174,58,124,90,89,106,86,66,140,86,179,104,48,246,48,156,216,156,216,216, +214,226,210,232,208,234,198,238,188,240,177,240,150,172,179,210,130,132,88,204, +167,197,30,24,69,52,20,84,57,106,28,228,59,146,138,16,167,36,80,48, +241,48,102,66,102,126,214,126,215,64,184,60,152,94,125,110,124,68,162,88, +191,110,92,244,92,156,226,156,226,220,222,230,218,234,210,236,195,238,159,134, +170,176,195,216,158,134,124,208,183,199,12,42,99,42,16,114,93,114,14,216, +95,188,56,42,57,198,220,126,120,126,120,26,220,26,221,126,120,76,221,76, +106,174,233,174,86,226,247,226,170,226,171,27,26,50,227,50,130,108,131,12, +18,116,56,102,88,82,121,50,238,112,198,98,172,82,141,50,24,174,231,174, +96,234,114,236,124,234,128,230,130,228,130,154,150,146,178,124,53,125,206,122, +50,122,50,32,206,32,207,122,50,78,207,78,38,170,221,170,12,222,243,222, +128,222,129,33,64,18,40,60,21,84,46,50,94,50,73,86,100,182,34,182, +34,94,100,94,101,182,34,136,101,136,67,94,66,94,67,182,18,226,70,218, +113,212,220,132,134,132,134,36,220,36,221,132,134,84,221,84,120,176,231,176, +112,228,243,228,176,228,177,37,58,18,97,50,20,72,108,72,80,114,48,144, +21,166,76,242,77,120,122,156,77,118,236,204,232,218,224,226,218,230,206,232, +194,232,176,230,166,226,162,216,162,210,163,15,14,46,241,46,92,76,93,8, +166,74,167,8,122,86,86,96,52,100,31,102,20,140,143,140,84,240,85,96, +24,218,54,186,85,148,130,194,104,172,85,158,168,188,169,96,174,232,190,232, +204,232,210,228,216,224,216,216,217,77,22,46,241,46,98,70,99,10,170,68, +171,12,48,86,198,84,194,116,186,124,178,126,155,128,128,60,116,100,108,112, +96,120,72,130,41,136,26,164,116,162,112,216,108,224,104,228,96,230,88,232, +75,232,78,138,72,178,64,200,46,222,25,238,136,162,222,160,216,212,210,224, +204,228,194,230,188,230,179,230,176,138,166,182,160,206,144,222,127,241,24,50, +237,50,206,142,58,142,58,88,204,88,205,142,22,238,56,232,84,224,104,212, +116,198,124,182,128,160,130,148,132,66,133,8,74,156,88,176,104,190,122,204, +150,216,182,226,237,233,22,24,235,24,206,114,52,114,52,62,206,62,207,114, +102,114,103,24,154,114,155,24,14,158,243,158,126,242,127,132,22,228,52,218, +82,200,127,166,234,222,202,212,176,200,154,184,131,159,14,30,243,30,40,238, +40,76,106,76,106,212,102,224,96,228,88,230,77,230,58,108,83,166,142,236, +142,76,210,76,210,206,212,220,208,226,202,230,192,230,183,232,162,108,187,167, +240,28,50,28,50,48,52,120,48,170,36,208,23,234,72,82,245,82,58,236, +80,224,100,204,114,184,122,162,128,136,131,82,162,232,186,230,194,228,200,220, +202,214,208,136,131,137,140,36,40,36,40,134,36,182,30,204,19,230,140,84, +41,84,50,230,64,210,72,188,78,164,82,130,83,84,92,224,108,220,118,216, +122,212,122,206,126,132,83,132,124,242,156,208,172,176,180,142,182,112,183,10, +182,230,200,230,210,228,218,222,222,210,222,202,228,78,149,85,20,42,111,42, +62,42,58,72,50,98,36,124,19,144,48,220,48,106,88,106,89,206,48,186, +87,186,220,24,168,34,136,36,120,120,243,120,146,236,166,236,176,232,176,226, +177,70,140,158,118,198,103,220,202,160,239,217,238,30,52,30,52,82,54,130, +52,166,44,198,23,230,74,102,212,102,210,200,206,214,198,220,184,224,155,228, +142,48,136,126,128,160,108,196,69,233,132,18,82,32,50,36,27,38,18,90, +147,90,88,242,89,30,24,190,62,144,89,102,136,150,110,126,89,108,168,184, +169,54,176,232,206,230,216,226,220,218,220,210,221,11,72,14,48,72,15,120, +54,246,55,64,88,30,237,30,222,118,98,118,98,68,222,68,223,118,140,118, +141,30,180,118,181,30,82,156,243,156,160,244,161,130,82,224,122,200,161,160, +238,220,212,206,190,190,176,176,161,161,68,12,44,76,17,118,52,246,53,56, +80,40,173,40,78,140,102,100,119,40,82,228,108,208,130,184,144,148,148,120, +152,94,107,94,102,138,135,168,184,182,185,56,188,236,204,236,216,232,220,230, +222,226,223,13,78,14,56,66,38,98,21,120,58,244,59,68,162,26,120,38, +89,44,82,98,173,98,130,236,131,36,80,184,108,148,131,108,164,156,131,116, +190,172,191,52,194,234,208,232,218,228,224,226,226,222,227,15,120,12,157,34, +244,46,56,46,56,162,52,188,40,220,29,236,16,76,41,112,14,154,49,132, +148,72,108,82,75,86,74,126,161,126,118,244,119,80,66,206,98,166,119,132, +156,180,119,142,180,198,181,88,184,238,204,236,216,232,220,228,221,65,102,24, +149,64,34,76,225,76,62,110,107,196,18,222,239,222,192,100,143,223,22,38, +47,74,102,34,79,74,10,96,109,96,64,244,65,8,16,184,36,158,65,114, +104,164,65,120,148,12,191,52,112,70,241,70,132,102,157,194,94,222,245,222, +214,96,179,223,36,20,79,54,18,78,63,110,20,232,61,142,240,36,100,36, +100,138,92,184,67,234,116,104,218,102,206,218,202,226,192,228,177,230,166,54, +166,108,162,136,158,162,146,186,126,214,109,233,12,78,239,78,92,236,112,236, +120,232,124,222,125,10,42,40,192,40,192,116,45,116,38,140,87,166,20,222, +125,170,234,220,212,212,190,202,162,182,125,146,212,136,155,175,36,80,208,76, +200,204,196,222,186,228,174,230,155,232,28,238,50,224,76,200,96,172,108,138, +114,106,116,72,117,13,10,44,89,44,16,118,89,118,16,214,87,188,54,44, +55,198,140,12,173,36,96,44,239,44,110,68,110,122,218,122,219,64,190,58, +154,90,131,108,132,62,197,106,102,246,102,156,226,156,226,222,224,230,220,232, +212,236,202,238,195,238,176,172,203,214,188,196,128,202,167,133,32,192,32,38, +76,38,77,184,32,156,77,156,218,124,112,124,112,32,220,32,221,124,112,78, +221,78,96,174,229,174,76,224,243,224,164,224,165,33,80,12,56,66,19,120, +56,244,57,70,84,34,245,34,96,240,96,88,224,88,224,210,222,222,218,228, +210,232,200,234,185,236,138,34,138,94,138,118,132,150,122,172,115,188,160,164, +139,126,180,34,180,98,176,138,168,170,159,190,210,182,179,133,12,36,117,36, +12,206,117,176,42,36,43,196,92,246,93,36,42,88,93,88,42,140,93,140, +128,16,161,54,114,74,233,74,216,12,185,66,110,140,237,140,114,240,136,218, +154,190,168,150,169,74,234,236,206,212,188,188,171,151,16,44,233,44,92,72, +93,10,162,72,163,10,38,74,69,102,24,236,34,224,42,216,50,212,62,210, +76,218,94,226,124,234,239,234,18,138,60,138,61,210,84,96,227,96,144,68, +126,106,102,142,217,142,80,180,233,180,160,216,161,113,36,28,67,72,18,228, +36,212,48,204,58,202,68,206,92,220,122,230,237,228,14,114,58,114,59,202, +86,52,227,52,218,116,98,116,112,96,128,62,149,14,86,162,231,162,160,214, +161,77,56,18,38,60,19,96,86,58,41,58,26,100,85,100,18,148,87,148, +82,188,52,218,53,100,152,14,181,32,242,44,102,44,102,156,100,180,96,206, +81,238,134,56,155,74,102,84,239,84,102,140,245,140,202,54,181,84,118,110, +218,110,218,168,119,168,148,246,149,84,182,244,183,84,110,230,130,208,149,178, +238,228,218,214,200,192,185,169,120,14,149,32,232,40,46,40,46,136,40,180, +30,210,19,230,102,54,127,72,62,78,233,78,180,48,161,78,242,138,47,138, +70,108,210,108,210,170,71,170,116,244,117,78,162,244,163,78,52,226,80,208, +117,174,236,222,204,208,184,194,163,175,56,248,57,8,16,126,33,66,76,54, +93,90,92,114,120,88,142,60,167,12,240,108,204,80,178,50,163,22,148,92, +177,124,134,188,195,242,102,146,212,146,163,213,26,32,69,64,16,94,55,122, +22,236,59,154,76,32,107,72,68,234,80,222,92,214,102,212,116,216,132,224, +148,230,243,232,68,120,102,120,103,212,118,54,231,54,224,122,128,122,148,78, +169,14,120,166,233,166,178,212,179,83,108,12,141,36,30,92,30,48,222,48, +223,90,104,70,74,98,33,124,144,70,223,118,58,228,58,140,200,140,200,200, +198,212,196,216,188,218,175,220,128,248,129,99,78,12,50,58,17,92,128,68, +73,24,38,90,117,90,28,136,49,180,60,118,77,160,22,218,129,188,114,120, +91,198,166,12,152,64,129,114,242,74,149,74,208,74,204,114,192,156,178,184, +144,214,111,234,236,232,190,198,172,166,160,136,155,103,58,234,74,232,84,226, +86,218,86,28,38,28,38,146,34,188,26,220,17,240,38,88,85,88,38,140, +87,140,170,8,146,52,124,80,105,100,238,96,206,70,182,42,165,18,124,108, +219,108,110,226,241,226,118,148,143,196,152,130,177,174,216,140,179,227,62,20, +38,68,17,98,96,66,41,66,26,110,89,110,14,156,95,156,92,194,58,222, +59,110,100,38,125,84,88,230,104,218,114,212,124,212,136,220,162,230,239,232, +94,130,118,130,119,212,134,56,235,56,228,126,140,126,156,98,183,22,138,168, +239,168,190,216,191,81,98,10,139,40,20,50,227,50,100,146,101,50,144,144, +145,50,74,80,46,114,27,134,166,80,221,124,52,158,38,194,25,220,116,154, +149,188,190,156,235,206,186,202,178,222,170,230,156,232,106,232,94,232,88,228, +84,220,85,163,30,58,26,96,19,124,18,228,36,206,48,184,56,158,60,128, +60,110,61,6,98,54,61,104,94,188,59,146,108,46,241,46,234,138,110,138, +124,112,142,68,165,6,142,234,160,232,168,228,172,224,172,90,101,90,138,164, +97,222,198,166,245,217,92,140,22,158,40,134,91,62,70,88,20,90,38,68, +69,16,22,216,89,190,100,54,231,54,230,144,114,144,138,96,171,12,134,238, +150,238,158,236,164,232,168,228,168,100,103,100,136,170,114,200,93,222,196,170, +235,223,24,46,47,82,102,42,83,86,16,102,111,102,64,248,65,10,18,194, +46,152,65,108,104,164,65,122,152,10,185,38,176,210,126,236,126,50,216,50, +216,132,127,132,126,92,217,92,236,230,206,210,180,174,165,132,226,154,193,191, +26,46,63,82,22,206,75,126,78,54,237,54,134,10,169,38,206,142,108,142, +108,88,206,88,207,142,126,170,100,200,77,220,194,172,233,218,128,236,144,236, +154,232,160,228,161,143,36,20,75,42,16,58,53,76,24,132,73,94,110,56, +85,88,208,62,235,92,92,28,198,28,194,98,190,106,186,112,180,114,159,116, +90,126,108,116,122,102,136,84,142,64,149,28,18,158,233,158,124,242,125,130, +24,228,56,214,88,192,125,160,232,220,204,212,170,198,152,186,125,163,42,20, +79,42,24,52,59,70,28,120,81,82,118,50,99,86,212,54,235,90,160,106, +176,104,184,100,190,94,198,32,99,32,98,114,116,106,134,90,144,72,150,52, +155,32,20,160,233,160,54,124,91,148,194,122,153,160,126,244,127,120,26,228, +58,216,84,200,104,182,123,160,228,224,198,216,176,204,150,184,129,161,106,16, +149,40,116,198,54,236,54,54,198,54,198,134,55,134,198,94,55,94,234,232, +208,224,176,208,146,186,130,164,113,134,218,146,159,195,20,32,241,32,46,238, +46,84,212,84,212,208,210,220,202,228,194,230,167,230,64,178,80,160,92,136, +98,106,103,32,128,148,99,110,124,190,142,164,152,134,156,106,160,60,161,32, +194,174,155,123,16,50,107,50,100,120,24,120,38,88,69,10,12,182,103,168, +68,244,69,74,110,42,241,42,116,244,116,90,224,90,224,214,224,224,220,228, +210,232,189,234,130,190,142,164,148,136,154,112,157,42,166,196,182,158,188,118, +193,42,152,124,177,168,214,180,189,127,200,80,58,80,58,30,200,30,201,80, +58,54,201,54,14,104,245,104,204,178,56,178,56,126,204,126,205,178,56,152, +205,152,38,204,221,204,20,230,239,230,130,230,131,127,24,212,24,42,78,42, +79,202,24,114,79,114,24,182,79,182,136,12,171,40,92,54,243,54,208,142, +120,142,120,92,208,92,209,142,136,238,152,236,164,234,166,226,167,142,134,168, +108,202,89,220,194,168,239,213,116,14,151,34,24,48,229,48,188,108,68,108, +68,74,188,74,189,108,32,172,32,136,224,136,225,172,232,208,228,222,222,232, +214,236,204,236,186,238,172,236,164,234,162,230,162,220,162,168,94,168,94,202, +88,212,72,228,52,236,33,243,34,22,75,54,138,10,175,38,84,52,245,52, +10,98,58,98,54,220,95,176,212,142,212,92,116,92,116,142,213,142,136,238, +148,238,158,236,164,228,165,142,132,170,114,200,95,228,196,170,239,217,10,74, +91,74,14,158,83,128,24,232,38,230,50,226,52,220,53,10,90,118,112,104, +132,88,146,68,156,38,163,10,104,70,129,90,94,48,235,48,238,116,222,110, +200,98,182,78,165,48,218,68,197,92,200,168,118,168,118,112,200,112,201,168, +118,140,201,140,134,232,144,232,154,230,158,226,159,168,126,190,100,216,85,228, +194,192,229,229,14,32,101,32,18,196,97,164,82,244,83,32,38,186,39,32, +38,80,83,80,38,130,83,130,104,232,122,214,140,192,148,166,150,140,151,50, +148,144,114,160,114,34,159,20,202,182,216,182,222,178,226,168,226,32,184,32, +185,245,76,12,54,62,17,120,54,242,55,64,94,48,239,48,166,10,162,32, +154,64,138,86,114,102,81,118,106,68,135,88,166,48,178,70,200,92,224,108, +243,114,220,68,199,90,208,172,118,172,118,110,208,110,209,172,118,142,209,142, +130,194,93,228,192,196,231,230,136,236,148,236,156,236,160,234,162,232,163,173, +124,12,163,38,24,68,51,106,22,240,46,212,60,180,66,150,66,48,245,48, +18,158,67,130,130,234,142,232,158,230,162,224,162,142,216,96,93,97,28,60, +17,126,20,228,36,204,48,178,56,146,58,110,59,10,90,60,59,100,90,184, +57,150,96,46,239,46,84,120,108,110,130,94,146,74,158,46,165,10,108,68, +135,88,238,118,216,108,196,92,178,70,161,46,220,64,195,90,204,174,120,174, +120,112,204,112,205,174,120,142,205,142,128,194,83,228,194,196,231,230,134,240, +146,238,156,238,162,232,163,175,110,12,145,30,32,78,32,40,224,40,225,76, +52,68,112,68,113,120,56,88,93,98,52,124,113,102,132,68,196,68,197,128, +142,84,173,92,144,116,197,102,134,114,94,140,52,160,19,172,236,174,206,166, +176,154,148,138,125,122,132,148,96,172,51,190,154,166,108,198,63,214,188,184, +124,224,55,243,30,28,73,60,22,228,38,214,48,206,64,204,76,210,98,220, +132,226,239,222,12,108,54,108,55,204,90,38,214,38,190,68,160,94,160,172, +158,184,148,188,134,190,127,191,36,24,69,50,14,84,53,108,26,228,63,142, +84,40,233,40,156,10,134,58,118,84,96,100,71,116,88,60,117,84,236,114, +206,98,180,76,162,56,155,40,214,64,191,84,198,174,106,174,106,104,198,104, +199,174,106,138,199,138,118,190,92,212,73,226,180,194,225,226,124,236,146,236, +152,230,153,175,84,230,108,230,122,228,130,222,130,98,172,70,202,36,35,37, +10,70,89,70,12,152,89,114,24,232,36,232,44,230,52,226,54,220,55,12, +216,84,104,84,104,26,216,26,217,84,104,56,217,56,158,84,159,26,96,140, +118,122,143,94,80,172,114,164,142,154,178,136,204,114,127,114,240,166,200,162, +178,156,129,132,112,244,112,182,210,182,211,240,112,222,211,223,16,88,36,62, +61,14,96,58,39,58,26,102,91,102,14,148,97,148,96,190,54,228,55,102, +108,46,237,46,100,120,126,106,146,88,160,68,166,46,167,12,240,116,220,106, +200,90,184,74,169,46,120,66,143,90,222,64,199,88,212,172,132,172,132,110, +212,110,213,172,132,142,213,142,148,242,160,240,166,236,172,230,173,172,140,196, +101,232,198,196,237,229,122,8,151,34,240,40,50,40,50,144,44,182,21,232, +70,66,136,66,137,116,80,80,109,94,70,122,137,98,150,66,212,66,213,130, +158,80,185,94,160,114,213,102,64,166,100,150,149,118,238,168,186,154,143,122, +152,150,108,180,77,194,176,170,130,200,95,214,210,186,150,222,85,243,20,36, +47,72,104,34,81,74,12,98,113,98,62,246,63,8,16,184,46,142,63,110, +100,154,63,112,132,36,181,80,128,100,173,142,100,182,247,160,204,246,205,7, +16,32,149,32,16,146,38,128,54,104,68,74,79,32,24,240,72,214,102,182, +120,144,126,114,128,84,65,84,64,130,109,168,172,180,173,40,180,234,196,234, +208,230,218,220,219,11,28,30,153,30,28,96,44,88,58,76,70,60,83,30, +36,134,66,126,90,116,116,94,128,78,136,62,71,62,172,102,173,30,182,126, +206,124,212,122,216,116,217,12,70,84,99,108,116,120,147,140,18,152,241,152, +22,212,56,200,88,182,123,152,138,210,90,232,93,180,232,232,204,226,176,212, +152,192,137,168,200,170,163,201,26,34,145,34,36,110,54,92,68,72,78,52, +85,34,28,176,54,168,76,156,98,138,116,112,124,92,128,76,67,76,66,108, +95,138,62,188,31,240,96,196,109,236,144,194,159,234,194,190,227,236,170,136, +171,40,182,170,204,166,210,164,216,156,217,17,134,84,135,12,84,32,49,82, +180,34,233,74,186,64,142,96,108,112,72,122,25,130,126,122,118,170,104,200, +80,224,41,238,44,156,208,150,202,210,196,222,182,228,172,230,163,231,26,28, +50,46,68,70,76,98,78,146,72,214,68,224,62,230,54,232,46,234,35,236, +82,18,50,64,21,90,20,166,77,108,104,52,237,52,96,102,245,102,144,102, +145,12,198,102,199,12,124,246,124,140,216,140,217,248,124,182,217,182,124,224, +217,225,12,44,89,44,20,116,87,116,12,210,85,190,54,44,55,198,82,80, +149,80,122,244,123,12,78,174,102,140,123,88,152,134,123,98,160,80,239,80, +188,244,189,8,140,198,164,156,189,94,238,192,210,146,189,91,20,70,113,70, +72,244,73,12,16,186,46,142,73,82,108,138,73,94,126,70,235,70,172,244, +173,12,98,194,134,152,173,84,242,194,212,156,173,83,18,40,103,40,18,130, +46,92,67,40,44,216,44,106,84,106,85,206,44,184,85,184,100,68,245,68, +116,20,147,50,222,20,195,54,170,124,171,10,106,114,130,102,169,68,236,114, +216,104,190,86,175,68,132,120,114,156,101,174,96,234,118,222,136,202,148,176, +154,146,121,146,116,180,139,196,206,242,207,118,174,146,239,146,176,160,170,192, +245,193,32,26,213,26,24,100,24,52,224,52,225,96,126,112,127,26,50,78, +105,78,50,102,105,102,148,78,201,78,148,100,203,100,18,146,115,146,80,244, +81,118,18,214,38,200,56,180,79,146,114,186,81,158,132,144,233,144,174,244, +175,116,112,216,134,200,154,176,175,148,236,214,214,198,190,170,175,147,34,206, +35,40,74,244,75,14,94,110,116,76,143,8,236,52,127,52,186,108,161,70, +118,242,118,128,216,128,217,240,118,212,217,212,168,212,169,129,84,16,44,78, +17,106,98,114,73,78,54,172,101,230,30,132,124,132,79,202,192,200,208,198, +222,194,232,184,236,168,234,158,228,148,218,134,210,126,190,110,230,30,158,30, +159,244,136,80,75,33,60,16,34,60,19,78,92,172,34,172,34,88,94,88, +95,172,34,130,95,130,64,88,65,172,64,88,86,46,45,46,16,214,107,204, +118,26,151,54,222,22,195,54,110,72,241,72,170,122,171,10,112,118,140,100, +169,72,234,110,212,102,194,90,179,72,110,170,130,144,143,120,98,240,120,226, +138,206,152,182,156,162,156,148,129,148,122,178,143,196,170,148,241,148,176,172, +176,196,243,196,208,242,209,119,32,22,73,56,16,84,55,116,20,230,57,150, +76,80,139,80,114,244,115,12,64,190,92,144,115,90,148,132,115,100,184,244, +185,12,238,78,161,78,134,200,154,168,185,106,234,192,208,152,185,97,20,40, +57,82,18,220,55,134,130,10,159,28,62,36,239,36,214,130,84,130,84,60, +216,60,217,130,178,106,120,106,120,84,178,84,179,106,82,156,221,156,62,182, +241,182,118,198,67,230,182,198,227,230,152,182,152,236,144,242,138,244,121,233, +80,18,48,58,23,82,62,122,63,40,210,20,172,30,103,36,86,70,241,70, +96,110,227,110,162,110,163,32,66,206,66,138,196,138,197,202,136,158,126,188, +110,208,82,224,35,236,144,204,227,237,110,12,145,40,28,50,231,50,24,142, +64,136,100,122,152,94,195,50,238,142,198,134,156,118,124,100,77,64,68,244, +68,156,190,156,191,242,68,220,191,221,12,72,99,72,28,234,44,232,52,228, +54,224,58,216,59,12,14,156,89,126,94,116,122,92,148,50,165,14,236,114, +210,94,190,72,174,48,161,26,152,84,177,120,126,186,195,236,106,140,212,140, +161,211,10,44,97,44,18,122,89,122,14,214,99,182,54,44,55,198,92,114, +116,92,132,70,146,48,159,14,238,108,214,94,196,76,174,50,157,24,148,94, +175,126,130,192,187,240,110,146,210,146,188,182,159,217,18,40,239,40,94,66, +95,12,168,62,169,12,50,82,209,82,24,112,233,112,132,112,133,56,32,154, +87,118,222,156,163,120,112,130,82,164,39,196,26,238,66,230,106,216,140,196, +176,154,93,154,234,230,190,222,158,214,126,198,101,173,36,28,223,28,34,94, +34,52,224,52,225,92,130,92,131,28,58,78,109,78,58,102,107,102,154,78, +203,78,156,100,203,100,134,100,96,132,64,150,21,166,238,156,194,146,150,126, +127,110,114,140,149,162,94,204,142,224,167,240,54,174,190,174,133,221,10,90, +119,90,38,30,39,90,72,10,73,90,114,48,73,48,27,118,108,120,109,238, +28,118,28,218,109,216,70,106,70,142,64,166,54,182,47,194,92,192,71,146, +120,112,142,82,164,42,173,8,238,102,206,78,188,54,171,20,164,92,193,122, +148,188,195,240,132,140,214,140,169,209,18,88,40,60,71,10,112,54,45,54, +30,98,99,98,14,148,109,148,110,192,62,226,63,98,108,110,138,78,156,48, +173,8,240,102,214,82,194,64,178,42,169,20,156,88,193,122,142,186,178,216, +199,240,118,144,218,144,173,209,74,10,52,58,34,86,19,106,52,248,53,62, +74,110,102,90,122,62,153,8,236,106,214,94,190,72,170,52,147,18,138,82, +169,122,116,182,154,212,183,240,88,138,206,138,155,211,28,18,53,56,16,72, +117,72,100,20,69,72,18,240,38,222,52,202,58,182,62,166,67,72,20,116, +99,116,12,164,117,164,168,16,146,68,130,90,109,114,240,112,216,98,192,76, +165,26,156,90,185,124,134,188,195,240,122,144,210,144,163,213,22,38,55,78, +22,212,57,118,84,40,217,40,72,78,233,78,148,78,149,6,74,136,123,90, +168,90,227,130,146,106,112,152,79,178,72,236,110,224,138,206,166,178,188,142, +121,142,234,230,202,222,168,208,138,184,121,161,40,36,202,36,202,106,41,106, +54,70,203,70,74,136,51,184,176,176,205,132,24,236,60,226,90,208,112,184, +122,160,133,116,234,234,196,222,164,204,142,180,125,157,48,186,62,186,72,182, +78,174,80,164,80,146,76,134,66,116,58,102,82,32,30,32,31,246,104,40, +223,40,90,80,239,80,164,80,165,8,138,94,99,136,184,96,229,134,156,116, +105,178,92,236,134,220,160,202,184,176,202,146,133,146,236,234,196,220,170,204, +156,192,139,165,27,76,94,74,95,218,26,76,26,202,95,194,60,24,61,198, +162,14,142,66,107,114,236,100,200,78,176,50,159,26,152,92,181,122,138,186, +191,238,114,144,212,144,167,213,72,16,44,64,19,98,114,72,65,32,58,78, +83,110,42,168,89,228,20,130,110,130,67,196,112,32,241,32,130,190,130,80, +218,80,219,186,174,32,161,80,102,240,128,226,150,206,164,186,172,166,177,104, +180,192,241,235,196,88,68,88,68,26,196,26,197,88,154,226,172,226,194,224, +204,214,210,130,39,132,30,232,66,220,92,196,110,168,116,140,123,97,16,116, +56,94,92,62,131,10,238,114,210,100,184,80,154,54,127,16,104,78,147,116, +80,186,161,240,124,214,152,186,190,140,47,141,32,22,69,54,16,86,57,116, +26,228,67,148,130,58,153,94,146,18,98,30,98,114,141,74,161,32,166,32, +226,32,222,94,216,106,208,108,195,110,184,32,178,76,168,102,149,124,104,246, +104,140,220,140,221,244,104,178,221,178,104,220,221,220,162,220,163,141,12,46, +91,46,16,118,85,118,14,212,95,186,52,198,53,46,134,14,169,46,96,54, +229,54,180,82,227,132,154,62,104,126,211,116,78,240,96,228,110,212,116,194, +120,176,123,144,156,242,157,146,240,210,234,228,228,234,222,236,212,236,202,236, +194,232,194,228,195,145,18,76,95,76,62,246,63,14,18,172,36,146,63,90, +94,136,63,104,162,90,141,60,154,18,130,30,114,36,114,108,149,74,172,36, +228,36,222,100,218,108,212,112,206,112,197,112,156,118,168,106,178,92,184,74, +189,36,116,246,116,140,222,140,223,244,116,182,223,182,116,224,223,224,170,224, +171,141,16,48,99,48,18,142,40,110,54,82,63,48,44,222,44,114,86,114, +87,216,44,192,85,192,142,14,181,42,114,54,237,54,188,82,233,130,214,114, +112,120,161,62,90,240,110,226,122,206,130,180,131,140,162,240,163,142,240,212, +234,228,228,232,220,234,212,234,204,232,198,228,199,139,18,98,36,76,52,44, +67,14,78,90,94,60,47,60,98,184,56,224,57,102,140,60,167,94,156,18, +114,34,114,116,153,78,164,34,228,34,224,96,222,106,214,112,206,112,199,112, +156,120,172,102,184,82,190,58,195,34,118,244,118,144,226,144,227,240,118,184, +227,184,118,222,227,222,172,222,173,145,82,60,113,96,110,18,76,26,40,28, +40,112,97,78,129,28,138,28,218,28,214,90,210,100,198,104,179,106,120,114, +138,102,150,86,158,60,161,28,52,246,52,132,208,132,209,242,52,176,209,176, +52,220,209,220,126,220,127,133,66,16,95,50,16,64,145,64,40,96,86,142, +135,206,22,222,52,202,74,180,98,146,108,110,117,64,170,174,171,52,186,234, +208,234,216,230,220,226,221,11,130,12,163,34,240,46,64,46,64,144,56,182, +44,210,29,230,24,60,45,96,18,154,65,124,126,96,149,124,146,66,100,78, +100,136,137,110,168,76,224,76,220,116,216,124,210,128,191,130,152,142,164,130, +174,118,178,106,185,76,96,244,96,158,218,158,219,240,96,192,219,192,96,224, +219,224,158,224,159,159,38,28,75,58,18,90,59,118,26,234,69,154,136,12, +169,40,90,52,233,52,176,80,225,128,144,60,100,120,205,110,74,238,92,224, +104,208,110,184,113,142,150,240,151,142,238,210,230,228,222,232,214,234,200,234, +194,232,192,228,193,143,16,76,101,76,62,244,63,12,18,162,42,126,63,78, +94,136,63,102,96,240,124,218,140,196,150,168,154,134,157,56,162,24,138,32, +118,36,118,164,153,148,204,188,218,186,228,182,228,172,228,34,186,34,187,245, +104,20,149,66,22,86,237,86,100,130,64,192,27,232,148,132,186,174,225,227, +158,26,205,62,20,78,237,78,110,14,110,90,104,124,94,158,76,188,54,216, +27,238,98,220,126,204,150,186,168,164,188,134,205,102,228,206,220,226,212,232, +200,234,180,236,160,234,148,230,148,220,149,79,162,12,189,32,30,116,54,106, +78,94,96,76,108,60,117,8,20,48,233,48,194,58,154,82,107,102,222,82, +216,94,208,102,200,106,184,108,168,108,156,108,148,106,146,102,147,48,20,132, +239,132,24,222,243,210,186,246,187,132,70,218,71,132,70,160,187,160,70,188, +187,189,32,192,32,50,78,50,79,184,32,162,79,162,178,24,211,56,64,236, +98,208,120,176,134,140,140,98,141,10,92,80,239,80,232,200,228,216,226,224, +222,228,216,230,210,232,200,232,188,232,180,232,174,230,172,228,168,224,169,98, +216,114,194,152,168,184,129,221,74,16,54,46,21,80,126,44,57,44,94,78, +77,44,130,78,150,52,171,16,238,44,157,44,200,74,181,44,26,120,233,120, +160,82,191,104,118,82,112,142,102,172,82,200,56,222,29,238,200,140,148,188, +95,216,228,200,226,212,222,222,212,230,202,232,148,232,144,230,142,228,143,135, +112,12,147,32,32,74,32,40,222,40,223,72,110,52,63,78,150,52,201,74, +58,198,72,196,82,188,86,180,84,170,80,154,74,146,68,140,62,134,82,94, +38,94,39,242,140,72,118,102,97,122,96,152,124,144,148,132,180,110,198,92, +129,92,236,146,198,140,168,128,135,106,126,152,205,152,122,164,99,196,216,180, +113,180,116,206,211,206,94,232,235,232,162,232,163,153,48,184,76,176,80,154, +74,134,64,120,50,104,78,34,30,34,31,246,138,14,110,56,91,80,84,112, +126,100,158,80,178,62,198,40,123,40,236,108,198,98,174,88,131,56,116,116, +201,116,116,132,93,190,218,154,109,154,112,190,209,190,82,232,231,232,158,232, +159,129,24,58,233,58,164,20,195,48,26,156,62,138,84,120,100,102,110,80, +114,64,121,14,200,78,158,104,126,122,101,134,228,116,218,134,210,142,198,144, +172,146,152,144,146,136,146,126,147,58,48,188,209,188,18,232,239,232,128,232, +129,151,14,74,91,74,16,156,93,118,30,234,44,232,54,228,58,222,59,14, +182,26,213,60,78,238,108,202,132,150,142,98,149,12,100,80,239,80,236,198, +230,218,224,224,218,228,202,230,182,230,172,228,166,222,171,96,132,212,154,196, +178,172,219,115,58,176,78,172,88,164,88,144,82,128,72,112,62,98,88,34, +34,34,35,248,92,82,233,82,180,26,209,58,144,14,138,104,128,152,112,194, +92,220,71,242,210,120,190,156,166,186,142,208,123,222,230,204,226,222,218,234, +206,238,190,238,168,238,162,230,162,224,163,105,20,72,93,72,64,244,65,10, +20,166,40,138,65,86,98,130,65,96,118,70,241,70,114,22,143,52,220,18, +193,52,170,132,171,8,116,126,144,100,169,70,240,122,212,112,192,94,175,70, +92,162,247,162,164,136,122,198,162,206,196,216,239,236,96,238,126,236,154,226, +180,208,198,186,213,163,62,28,91,58,28,72,227,72,192,24,165,72,128,126, +129,14,26,132,62,118,98,94,119,72,234,124,192,112,162,96,137,72,122,134, +76,186,144,206,221,236,18,158,237,158,34,236,66,232,102,220,142,198,158,180, +171,159,26,232,48,230,56,226,58,218,59,12,12,72,91,72,16,154,85,124, +102,76,233,76,164,134,165,12,110,26,133,56,212,26,191,56,102,132,130,112, +165,76,228,134,202,118,186,102,165,76,90,164,241,164,156,140,124,196,184,214, +227,236,94,236,126,232,154,222,176,208,184,192,199,165,74,14,54,48,33,74, +128,42,59,42,98,72,79,42,166,14,148,46,135,64,234,40,155,40,196,70, +177,40,32,110,227,110,126,146,127,70,66,80,99,96,182,76,157,96,46,160, +70,152,98,132,127,110,216,158,186,148,160,134,133,110,24,176,233,176,124,152, +82,200,142,212,213,236,40,238,84,232,132,214,156,196,175,177,32,16,69,46, +20,80,59,110,26,228,57,146,60,226,78,196,90,158,92,122,92,26,218,26, +218,62,93,62,240,96,93,96,166,228,167,96,114,240,114,130,222,130,222,216, +218,226,208,232,195,234,132,150,147,170,132,186,147,206,186,150,201,168,186,188, +201,209,48,176,70,168,76,146,72,124,66,110,54,98,78,28,28,28,29,240, +98,68,98,228,237,228,106,28,233,28,132,206,132,78,214,78,214,184,212,194, +202,198,189,198,144,162,158,142,166,116,170,92,172,60,173,28,200,154,171,99, +14,48,241,48,90,82,91,10,168,80,169,10,116,76,151,100,24,242,42,226, +56,200,62,174,62,112,204,112,205,180,62,162,205,163,24,240,48,216,62,188, +66,164,66,90,208,90,209,174,66,152,209,152,126,90,127,10,126,40,241,41, +16,234,32,204,38,172,40,160,40,84,110,84,111,180,40,156,111,156,72,84, +73,10,72,48,123,48,130,26,245,26,146,190,146,76,224,76,225,186,188,26, +171,76,108,240,132,230,158,212,174,194,180,176,184,134,187,104,242,238,193,201, +126,10,163,34,18,232,40,204,50,172,54,146,56,124,56,48,245,48,138,66, +173,90,68,242,86,222,98,198,104,176,106,158,106,104,220,104,221,180,220,158, +107,159,22,228,48,196,60,172,66,146,70,112,70,100,71,8,40,62,25,122, +112,46,71,92,104,190,67,152,160,12,193,42,90,242,112,218,126,188,132,160, +134,146,134,60,228,60,229,156,228,132,135,133,18,70,97,70,18,154,93,106, +34,232,52,230,60,226,62,216,63,8,76,238,90,222,100,194,108,164,110,142, +110,68,236,68,225,90,166,68,167,8,232,32,167,32,124,112,213,102,230,116, +224,126,216,134,204,136,168,134,166,130,167,80,124,174,224,172,222,206,218,224, +206,230,181,236,172,148,164,184,154,206,140,224,113,243,44,246,44,86,208,86, +209,244,43,226,44,226,209,226,120,86,121,10,120,42,219,42,164,104,124,160, +77,204,84,112,136,154,177,195,24,240,40,212,48,186,52,156,54,142,54,68, +230,68,219,94,132,68,133,12,132,36,223,36,74,110,205,100,222,116,220,124, +214,132,202,138,150,136,140,134,136,132,134,126,134,122,135,82,74,174,216,170, +208,220,206,228,198,234,192,234,165,236,74,240,96,232,116,214,132,188,141,147, +28,74,72,46,103,14,204,118,56,118,56,66,204,66,205,118,80,38,168,38, +149,66,56,92,205,92,126,118,127,66,16,144,243,144,66,242,66,170,196,170, +197,242,66,198,197,198,66,226,197,227,22,38,111,38,80,98,81,6,20,94, +60,66,81,48,116,72,81,50,140,36,235,36,178,96,179,6,134,82,179,42, +232,78,204,64,179,42,114,90,141,106,228,114,56,114,56,168,46,190,36,214, +21,232,56,142,208,142,208,170,59,170,108,114,109,170,158,114,159,170,134,222, +84,236,85,180,136,200,85,200,240,210,236,218,232,226,224,230,204,232,174,230, +162,230,156,226,156,222,157,178,218,192,157,203,16,38,103,38,16,132,38,104, +48,80,59,38,42,224,42,106,82,106,83,212,42,190,83,190,98,98,241,98, +202,98,210,24,113,24,116,60,205,60,136,234,152,232,160,230,164,224,165,98, +108,124,135,156,98,202,165,158,236,212,208,190,186,164,165,134,230,130,185,161, +28,24,217,24,26,88,26,50,220,50,221,84,124,106,125,24,46,74,103,74, +48,96,105,96,146,74,197,74,146,94,197,94,98,158,38,158,38,122,98,122, +99,158,18,232,109,212,38,176,39,226,72,158,73,218,72,186,97,186,156,108, +138,134,119,158,234,180,196,172,162,156,137,138,110,184,138,178,160,168,190,146, +208,128,145,128,136,244,136,192,206,192,207,244,136,226,207,227,90,88,30,88, +30,28,92,28,93,88,16,224,105,184,60,202,61,88,28,218,29,118,98,136, +61,136,156,12,136,50,113,78,106,136,142,120,180,90,198,68,212,40,143,40, +236,134,208,120,184,104,164,88,147,64,130,242,130,146,212,146,213,240,130,216, +213,217,34,176,34,34,98,34,99,174,99,174,66,68,66,140,60,176,50,204, +34,226,17,240,74,188,107,228,166,10,144,48,119,76,114,132,146,118,182,94, +198,74,220,38,153,38,146,68,174,94,198,114,222,124,241,130,136,246,136,150, +214,150,215,244,136,218,215,219,116,14,153,36,236,50,48,50,48,148,44,184, +32,216,21,240,48,136,216,136,216,88,49,88,106,136,107,58,158,136,159,58, +136,210,88,232,89,146,142,178,89,178,240,210,232,224,224,230,216,234,176,234, +166,230,162,226,163,146,230,160,196,176,163,189,28,22,59,52,14,82,49,114, +20,230,55,140,124,96,76,96,76,32,124,32,125,96,58,224,137,194,72,124, +73,218,104,96,105,204,104,146,133,146,176,12,156,58,143,80,160,62,182,94, +200,110,239,134,134,136,166,114,196,84,218,46,163,46,154,244,154,144,212,144, +213,242,154,216,213,217,40,16,75,50,16,72,82,72,50,120,17,154,56,244, +57,112,94,152,57,120,92,98,241,98,194,98,202,26,107,26,112,64,197,64, +130,232,144,234,156,232,162,224,162,216,163,98,104,122,131,156,92,206,163,158, +238,210,210,190,192,172,176,152,163,136,222,124,183,157,16,98,239,98,176,98, +188,24,61,24,68,60,181,60,94,232,108,232,120,230,124,226,126,216,127,98, +52,122,83,158,24,218,127,150,230,220,182,196,156,170,140,144,127,120,210,124, +155,167,62,194,92,188,96,176,94,162,90,144,80,128,64,108,90,32,36,32, +37,246,110,62,227,62,98,114,241,114,218,154,219,246,120,154,120,224,219,218, +168,12,169,221,18,34,70,34,71,106,24,104,71,80,24,54,45,68,86,34, +134,34,135,116,90,94,135,74,90,54,111,66,86,106,58,132,15,156,148,152, +79,112,90,136,64,162,37,178,108,158,78,188,37,208,132,178,88,214,43,240, +140,90,235,78,190,30,215,58,168,12,166,54,168,80,172,106,176,142,188,180, +198,202,208,220,216,228,220,232,224,232,230,230,241,204,220,110,196,158,174,190, +154,210,129,231,16,32,94,32,89,130,42,56,40,136,102,136,98,198,96,212, +90,220,84,222,72,226,55,228,16,188,81,172,150,14,193,48,102,242,118,222, +128,204,134,180,138,160,138,58,226,58,227,154,226,130,139,131,198,92,54,92, +54,26,198,26,199,92,36,242,36,136,216,136,217,238,36,214,217,215,68,14, +44,58,17,90,118,58,47,58,31,102,32,100,109,100,20,152,113,152,108,200, +68,226,69,100,220,102,136,102,136,34,220,34,221,102,128,244,128,148,230,148, +231,240,128,218,231,219,84,14,50,82,17,124,56,244,57,72,222,100,122,100, +122,36,222,36,223,100,112,242,112,142,234,142,235,240,112,218,235,219,52,20, +83,56,16,72,107,72,50,72,50,132,46,168,36,204,19,236,60,230,72,230, +86,226,92,216,96,176,98,120,51,122,152,14,126,70,105,98,240,50,137,50, +208,82,168,96,134,102,134,238,173,208,168,116,172,144,180,170,192,192,210,216, +237,238,224,126,181,169,22,232,36,212,42,186,46,154,46,30,220,30,220,60, +47,60,100,76,76,104,63,116,104,118,80,150,63,168,88,244,89,142,148,68, +132,92,115,112,232,86,137,86,214,154,132,154,132,110,216,110,217,154,132,132, +217,132,148,162,128,186,107,206,110,236,138,230,162,220,188,202,210,178,139,178, +144,194,170,210,192,222,220,232,235,235,18,226,34,202,42,176,46,142,48,120, +48,32,220,32,220,62,49,62,66,106,237,106,146,144,147,72,86,76,117,96, +204,76,177,96,72,154,96,144,116,130,141,106,232,148,212,144,190,134,170,122, +155,106,60,176,245,176,142,148,104,200,227,232,186,176,174,196,152,212,130,224, +100,232,69,237,65,16,94,62,30,158,85,152,62,16,24,92,75,92,16,212, +91,198,106,76,235,76,166,130,167,12,114,28,139,54,216,26,191,58,96,134, +136,108,165,76,232,130,194,106,169,76,96,162,243,162,160,136,128,192,227,236, +202,162,194,186,180,206,156,220,130,232,101,239,214,98,224,72,48,72,48,90, +48,122,48,148,44,180,36,208,21,236,68,116,203,104,212,122,208,134,202,142, +192,146,176,148,152,148,138,148,128,146,124,140,120,134,121,82,120,72,121,10, +120,34,215,34,86,172,61,230,130,164,167,196,198,170,237,216,114,178,114,224, +116,234,126,238,148,240,168,238,180,234,186,226,191,209,78,10,44,50,17,74, +228,34,61,34,68,60,205,60,32,88,200,88,196,130,200,164,202,190,210,218, +216,226,222,228,230,226,232,220,239,200,14,160,183,160,42,114,148,114,145,160, +50,138,145,138,74,236,92,236,100,234,104,230,104,226,105,160,44,172,69,192, +18,222,87,202,182,228,105,194,158,172,131,205,74,18,50,50,25,72,72,78, +42,120,19,142,52,244,53,110,84,78,245,78,94,44,208,44,208,114,95,114, +84,152,223,152,76,190,241,190,152,246,153,9,100,10,139,30,22,42,229,42, +28,66,61,98,32,160,71,116,210,62,177,98,186,118,223,154,158,68,88,146, +163,140,148,114,175,158,124,50,88,94,135,92,12,184,243,184,124,244,125,159, +36,30,73,60,20,82,57,114,32,234,63,154,60,242,76,220,86,192,92,166, +92,146,92,60,224,60,213,84,152,60,153,10,152,34,219,34,112,108,201,96, +154,74,154,128,156,136,164,140,184,140,198,138,208,132,214,124,217,116,122,174, +101,226,208,160,237,208,166,154,187,190,208,208,202,222,196,230,188,234,172,234, +156,234,150,230,148,222,149,163,96,60,30,160,97,148,70,18,20,94,75,90, +14,208,95,188,96,102,241,102,112,28,206,28,201,102,122,64,203,64,134,236, +148,236,158,234,162,230,164,226,165,102,112,126,143,156,96,212,163,166,225,124, +238,214,216,198,196,176,182,156,176,144,165,118,224,124,183,155,116,10,149,34, +18,46,237,46,24,128,48,108,73,78,184,82,229,122,100,142,101,46,158,140, +159,46,53,162,206,158,207,244,52,162,52,226,207,226,128,226,129,139,114,10, +147,36,28,46,237,46,78,72,27,112,186,72,231,106,106,118,107,46,154,118, +155,46,208,126,152,134,108,136,41,132,50,164,211,164,18,196,241,196,98,238, +116,238,128,236,132,232,133,137,110,12,149,38,28,50,239,50,102,122,103,50, +152,122,153,50,70,80,44,108,25,122,184,76,233,120,18,186,241,186,98,236, +112,236,122,236,130,232,132,226,132,172,186,138,59,139,32,26,65,56,14,82, +51,116,16,226,59,146,126,12,161,34,76,48,233,48,106,74,75,120,198,74, +231,114,130,124,131,48,176,124,177,48,70,154,243,154,152,244,153,128,68,222, +100,204,126,182,151,154,234,220,200,200,180,182,161,155,64,68,83,120,36,238, +68,212,92,184,104,150,108,122,109,48,120,18,74,30,40,34,40,172,103,148, +170,72,195,126,180,186,206,186,214,178,216,172,216,30,148,30,149,247,122,28, +82,38,23,44,14,98,143,98,38,238,38,150,116,150,117,236,38,214,117,214, +238,190,234,212,228,222,218,228,208,230,196,230,180,230,172,228,166,224,164,220, +164,214,165,18,78,148,79,39,16,68,93,68,16,150,89,116,34,232,46,230, +54,228,58,224,60,218,60,214,61,6,146,10,179,40,98,54,239,54,210,142, +122,142,122,90,210,90,211,142,138,234,154,234,162,230,164,226,166,218,167,142, +134,168,95,222,196,168,237,217,26,218,26,40,96,40,97,212,26,116,97,116, +26,190,97,190,60,190,61,40,168,14,136,60,115,80,112,138,140,126,168,110, +192,86,210,60,216,46,149,46,148,68,164,92,188,112,218,128,243,138,140,246, +140,152,218,152,219,244,140,222,219,223,14,66,103,66,18,154,103,126,30,236, +46,234,52,232,62,228,64,218,65,12,96,106,120,84,140,56,163,8,238,102, +208,82,184,58,174,44,159,14,226,198,222,212,216,222,208,226,202,228,174,230, +150,228,142,224,138,216,139,98,208,122,139,167,14,58,117,58,116,134,24,134, +73,16,14,202,119,168,72,244,73,90,102,108,130,80,150,46,167,12,234,102, +202,78,178,52,161,26,222,200,220,214,214,224,206,228,198,230,164,230,156,228, +148,226,146,222,144,216,145,98,208,122,145,161,80,16,48,82,19,120,56,244, +57,70,82,118,108,96,128,68,144,40,159,12,242,110,220,98,196,80,178,60, +155,20,222,194,218,214,212,224,204,226,194,228,180,228,154,228,142,226,134,220, +134,212,135,100,208,118,135,169,16,124,60,98,96,62,131,14,238,116,188,92, +152,62,125,24,204,194,200,212,194,226,186,230,178,234,166,236,102,236,90,232, +78,222,78,216,79,110,184,126,79,169,38,26,83,56,16,84,59,110,24,230, +75,152,78,110,108,84,132,50,149,12,230,102,202,88,172,60,145,20,218,190, +214,206,206,220,194,226,184,228,144,228,134,226,128,222,126,214,127,102,200,118, +127,173,98,160,28,166,99,64,62,24,16,104,75,98,18,226,105,200,162,16, +144,58,122,92,101,116,234,106,206,84,178,56,159,28,222,204,216,220,206,230, +198,234,190,236,156,236,144,232,138,228,136,220,137,108,204,126,137,175,30,26, +75,60,10,104,52,104,50,226,97,192,156,10,132,56,112,88,81,120,236,110, +200,86,172,58,149,24,220,204,214,218,208,224,200,228,196,230,152,230,144,228, +140,224,136,216,137,102,202,126,137,169,18,42,241,42,94,66,95,10,160,66, +161,10,214,126,50,126,50,82,212,82,213,126,104,126,105,82,154,126,155,82, +106,136,72,166,35,192,32,240,82,234,130,218,172,190,198,162,79,162,98,180, +133,215,94,126,30,126,30,56,94,56,95,126,17,196,86,152,109,196,16,196, +99,182,62,188,63,8,222,90,122,90,122,22,222,22,223,90,122,56,223,56, +174,90,175,22,200,140,237,176,206,104,128,170,223,162,160,98,126,128,181,126, +142,190,101,228,146,238,162,236,172,232,174,224,175,166,202,192,241,227,220,86, +44,86,44,26,220,26,221,86,102,86,103,26,160,86,161,26,108,100,78,142, +45,174,28,240,74,236,118,222,156,198,182,166,200,130,89,130,96,162,149,203, +30,26,69,70,20,232,36,216,50,208,58,206,70,210,94,222,124,228,194,228, +239,224,14,110,56,110,57,206,217,82,216,84,92,84,92,26,216,26,217,84, +132,84,133,26,172,84,173,26,84,158,118,126,145,92,98,202,134,194,172,174, +196,150,210,124,121,124,132,144,165,177,70,16,44,62,19,92,100,62,45,62, +28,102,101,102,18,148,111,148,66,102,66,224,103,196,228,92,118,92,118,32, +226,32,227,92,152,92,153,32,186,92,187,32,108,176,136,144,161,104,100,238, +156,220,202,182,226,136,143,136,146,164,183,199,80,10,52,50,23,82,136,42, +61,42,98,74,81,42,172,10,154,40,133,70,240,40,155,40,198,72,179,40, +208,130,52,130,52,84,208,84,209,130,102,130,103,84,154,130,155,84,108,138, +74,168,39,188,36,236,66,236,104,228,140,214,166,194,196,162,83,162,92,182, +137,215,40,50,34,130,94,130,88,210,86,218,82,222,76,224,57,226,16,184, +73,170,16,28,82,28,79,130,222,94,118,94,118,28,222,28,223,94,118,60, +223,60,168,94,169,28,200,140,233,176,220,164,122,170,209,108,160,94,126,132, +181,128,142,236,162,234,170,230,172,224,173,168,146,186,111,224,200,190,239,221, +36,18,75,48,14,70,82,70,58,116,19,154,58,244,59,118,94,162,59,126, +96,104,75,142,218,108,120,108,120,24,220,24,221,108,120,68,221,68,102,142, +241,142,168,244,169,24,92,220,118,202,142,174,167,142,238,218,216,200,194,178, +169,145,18,40,239,40,92,72,93,8,166,72,167,10,40,72,79,92,24,118, +61,138,28,232,71,158,136,60,95,124,90,166,136,146,176,118,200,88,119,88, +236,158,212,152,170,136,127,108,116,246,116,172,200,172,201,244,116,222,201,223, +44,20,81,54,16,82,57,112,26,238,65,152,92,94,124,54,145,12,80,144, +128,124,176,88,208,46,129,46,236,140,198,128,166,108,142,86,131,68,114,248, +114,156,204,156,205,246,114,222,205,223,14,194,75,178,40,56,32,140,100,140, +94,216,90,226,84,230,76,232,63,234,78,140,84,34,15,34,114,82,142,48, +163,12,116,144,152,122,188,88,214,44,145,44,236,134,208,122,182,102,151,70, +142,244,142,152,216,152,217,242,142,216,217,217,92,56,28,164,93,156,66,14, +20,96,71,92,16,220,97,200,104,90,126,60,153,10,98,146,142,122,184,84, +208,44,135,44,238,138,202,124,180,110,141,66,130,242,130,152,210,152,211,240, +130,216,211,217,12,76,100,72,82,156,58,196,21,230,64,14,34,152,107,216, +106,176,201,176,144,56,138,132,230,132,224,218,222,226,218,230,210,232,187,232, +112,32,210,32,207,133,120,12,147,34,232,44,44,44,44,126,40,182,21,230, +62,104,131,104,104,248,105,62,56,210,76,178,105,118,134,156,105,124,148,104, +229,104,178,248,179,60,124,210,150,174,179,112,236,204,216,182,200,160,179,119, +16,40,103,40,22,112,101,112,18,208,97,178,64,40,65,188,114,176,205,176, +164,230,188,230,212,224,222,216,226,202,230,132,134,132,139,50,118,26,208,26, +203,133,16,44,113,44,18,152,50,110,71,44,48,228,48,114,98,114,99,220, +48,198,99,198,116,184,207,184,190,236,212,234,222,226,226,220,232,138,140,138, +151,58,120,34,210,34,203,139,100,134,30,134,30,68,100,68,101,134,94,160, +115,212,16,212,103,186,64,196,65,12,118,180,203,180,178,236,202,232,218,226, +224,220,226,212,230,132,140,132,145,52,116,28,208,28,205,133,20,186,187,186, +168,234,190,234,204,230,210,226,216,218,226,138,70,138,81,54,42,32,186,32, +175,139,110,74,48,74,48,24,112,24,113,74,220,72,156,72,156,22,218,22, +219,72,22,198,185,198,172,234,196,232,212,228,220,220,220,214,224,164,74,164, +81,122,38,106,194,106,191,165,28,194,28,46,62,46,63,182,28,162,63,162, +140,14,175,36,54,240,76,210,88,172,92,136,92,46,239,46,106,104,157,104, +138,248,139,60,96,208,122,164,139,118,164,156,139,118,192,248,193,62,172,104, +239,104,154,208,172,172,193,112,236,206,218,182,193,123,34,186,34,34,82,34, +83,176,34,156,83,156,102,178,199,178,156,234,184,232,202,228,212,218,216,210, +222,136,120,136,131,54,102,28,206,28,193,137,12,90,93,90,12,208,95,184, +56,18,57,194,222,130,114,130,114,28,222,28,223,130,102,176,235,176,82,228, +249,228,166,228,167,28,114,78,223,79,36,34,222,34,197,80,76,66,117,92, +54,102,101,134,22,156,239,156,154,180,231,232,32,230,60,224,86,212,108,198, +124,180,138,148,147,55,30,40,225,40,48,74,209,74,18,114,243,114,130,114, +131,10,22,214,56,190,84,158,109,122,56,242,100,230,134,216,160,192,188,148, +102,148,112,168,132,192,158,214,190,224,239,237,36,42,217,42,26,76,224,76, +201,116,128,76,129,8,64,100,115,126,48,130,101,160,16,174,241,174,32,240, +68,230,98,212,122,192,134,166,143,92,148,196,229,239,18,226,32,212,46,206, +60,204,70,208,96,220,118,226,239,226,14,106,54,106,55,204,28,26,71,62, +82,40,239,40,82,190,102,172,122,136,134,84,137,40,158,188,174,188,192,184, +200,176,202,166,208,92,135,93,12,228,26,206,34,180,36,150,38,132,38,28, +88,28,88,216,82,228,72,230,63,230,38,88,89,88,38,142,89,142,144,12, +193,44,104,114,150,114,138,160,124,186,111,204,142,230,158,230,168,228,172,224, +174,218,174,62,119,62,240,200,218,176,200,146,175,80,228,90,195,129,28,226, +28,36,70,36,71,218,28,90,71,90,28,146,71,146,28,200,71,200,84,48, +243,48,134,74,135,10,184,74,185,10,84,90,241,90,104,244,104,128,222,128, +222,222,222,228,216,232,210,234,197,236,118,204,132,182,140,158,144,110,145,90, +162,182,143,156,160,210,172,186,180,158,184,108,187,90,206,196,181,155,18,110, +44,64,63,10,82,98,94,58,47,58,92,190,52,226,53,98,214,82,122,82, +122,24,214,24,215,82,122,54,213,54,228,146,106,146,106,108,228,108,229,146, +146,146,147,108,186,146,187,108,108,172,210,172,184,202,148,224,97,240,238,238, +186,224,152,202,129,173,112,14,145,36,24,50,235,50,74,76,29,116,230,116, +183,74,102,128,103,50,156,126,157,50,202,184,60,184,60,144,202,144,203,184, +29,234,188,198,233,242,28,234,215,224,128,228,129,121,34,24,71,52,18,88, +57,114,26,230,63,148,82,44,235,44,130,70,131,10,186,70,187,10,72,86, +245,86,90,244,90,122,224,122,224,216,222,226,216,232,206,234,197,236,108,196, +122,172,132,144,135,86,158,174,133,148,158,206,170,182,180,148,185,86,206,188, +179,157,14,38,239,38,192,108,62,108,62,62,194,62,195,108,62,86,195,86, +96,62,97,8,160,62,161,10,212,158,46,158,46,130,212,130,213,158,100,158, +101,130,154,158,155,130,24,238,74,232,120,220,152,202,176,182,49,182,236,232, +206,232,176,228,144,222,112,210,75,183,192,72,60,72,60,20,192,20,193,72, +60,46,193,46,212,140,38,140,38,100,212,100,213,140,96,140,97,100,152,140, +153,100,20,238,64,230,114,214,158,186,180,166,41,166,236,232,196,226,144,214, +104,196,84,184,71,167,32,66,17,122,76,56,91,90,56,240,57,8,212,78, +114,78,114,24,212,24,213,78,114,50,213,50,226,140,98,140,98,104,226,104, +227,140,142,140,143,104,184,140,185,104,88,234,128,226,158,212,188,186,206,166, +99,166,240,232,202,224,172,210,142,190,123,167,34,22,73,54,16,88,59,116, +22,228,69,146,206,76,106,76,106,20,206,20,207,76,106,48,207,48,222,138, +94,138,94,100,222,100,223,138,138,138,139,100,178,138,179,100,78,240,120,228, +158,208,190,178,198,164,91,164,236,236,208,230,178,220,146,200,119,165,36,28, +77,62,10,104,54,104,54,226,95,190,210,84,116,84,116,30,210,30,211,84, +116,54,211,54,226,144,102,144,102,108,226,108,227,144,144,108,145,144,184,108, +185,144,102,168,202,168,190,190,172,210,146,224,116,234,97,238,236,236,200,228, +174,214,156,202,138,182,131,169,16,52,239,52,92,86,93,12,168,86,169,12, +112,90,147,116,16,128,241,128,218,230,68,230,69,129,18,52,241,52,96,84, +97,18,162,82,163,14,34,88,67,110,20,134,55,158,32,238,75,170,140,94, +173,118,78,128,237,128,226,228,116,228,117,129,114,12,149,40,16,52,243,52, +208,92,58,92,59,52,64,248,64,122,196,122,197,244,64,156,197,156,64,190, +197,190,64,224,197,225,36,30,67,66,10,82,97,82,94,196,36,196,37,82, +166,200,116,234,116,32,216,32,216,86,117,86,116,142,241,142,240,204,238,222, +234,232,232,236,228,236,222,234,202,214,186,186,178,152,173,87,58,246,59,12, +34,62,17,130,74,60,99,106,146,16,185,58,98,70,245,70,238,220,130,220, +131,71,22,40,231,40,92,70,93,12,162,70,163,10,178,64,201,78,20,96, +235,96,18,156,48,144,78,122,108,94,129,62,38,174,219,174,46,240,66,228, +84,206,96,186,98,166,99,132,162,242,163,134,236,154,206,142,182,126,164,108, +157,97,22,24,50,54,68,84,78,122,80,172,70,220,48,234,33,238,84,24, +23,92,20,172,75,110,90,54,245,54,138,96,139,10,198,96,199,10,114,246, +114,116,224,116,225,242,114,220,225,220,114,170,225,170,168,220,169,117,22,42, +237,42,96,66,97,12,162,66,163,14,104,98,151,124,56,78,182,78,139,116, +26,134,222,134,203,174,140,134,140,214,140,226,134,234,124,236,110,238,97,236, +30,214,68,196,102,170,137,135,72,12,38,68,19,88,98,58,45,58,30,100, +101,100,18,148,105,148,62,100,62,228,101,196,110,56,245,56,148,96,149,10, +204,96,205,10,126,242,126,122,228,122,229,240,126,170,229,170,126,218,229,218, +178,218,179,123,200,24,138,38,82,44,39,48,32,104,203,92,14,160,231,146, +114,40,114,200,116,216,120,224,132,226,146,228,190,228,204,226,218,220,224,210, +231,197,104,58,155,92,52,28,192,28,135,78,28,104,226,104,207,148,28,206, +76,176,110,140,139,104,110,230,128,230,142,228,150,224,152,220,152,216,153,105, +60,12,40,54,19,90,98,54,41,54,26,98,93,98,16,146,99,146,60,98, +60,224,95,196,106,238,134,216,146,192,154,168,154,156,155,54,158,26,118,42, +118,168,155,144,186,244,186,36,224,36,224,180,216,194,203,183,38,234,70,212, +92,188,102,164,104,130,109,52,120,20,46,34,46,170,103,146,154,242,154,32, +216,32,216,162,216,178,212,186,204,190,181,195,16,50,241,50,88,88,89,10, +166,88,167,10,188,70,217,94,24,244,40,224,50,200,54,168,54,114,231,114, +238,200,232,220,224,236,218,236,208,236,194,230,176,216,162,194,152,164,144,134, +139,78,102,234,134,218,166,190,190,164,209,141,44,102,44,22,218,22,219,102, +70,52,193,52,70,84,193,84,60,242,60,122,198,122,199,242,60,156,199,156, +60,188,199,188,60,220,199,221,60,246,61,12,30,196,30,60,94,60,94,186, +79,180,120,104,120,24,226,24,227,102,142,56,205,56,140,88,205,88,132,244, +132,122,220,122,221,242,132,156,221,156,132,190,221,190,132,222,221,223,92,16, +56,36,21,48,20,118,70,90,107,60,64,50,85,76,32,68,57,96,42,234, +56,234,72,230,82,220,88,204,90,182,90,154,86,128,78,112,63,96,18,164, +52,140,79,114,18,202,54,178,89,148,210,144,124,144,124,54,210,54,211,144, +160,12,149,54,124,98,211,98,100,240,122,224,140,200,148,178,150,164,151,144, +238,202,232,220,224,230,208,232,182,232,183,145,88,48,119,90,110,22,42,38, +42,102,103,70,126,36,224,36,220,82,214,94,206,98,187,98,126,108,146,92, +160,74,166,56,171,36,64,200,64,124,198,124,199,200,28,240,66,230,98,216, +116,200,124,176,131,144,140,196,225,241,130,20,76,102,31,148,174,154,229,230, +184,66,70,216,211,207,14,42,113,42,22,112,99,112,16,212,111,182,62,42, +63,196,158,14,138,80,105,130,242,70,143,70,202,70,196,128,180,168,148,204, +93,238,234,234,204,218,178,188,158,156,143,97,16,78,111,78,66,244,67,10, +18,172,44,134,67,88,104,144,67,98,160,14,136,76,111,112,242,68,141,68, +142,96,154,140,178,182,208,214,239,230,206,68,202,108,190,146,164,186,136,210, +93,237,14,74,93,74,60,244,61,14,18,168,42,130,61,90,92,130,61,100, +138,12,120,60,97,92,236,50,125,50,88,146,247,146,244,204,116,204,126,86, +216,86,212,226,204,236,190,238,179,236,154,104,181,126,156,160,183,189,14,28, +115,28,28,240,28,76,102,76,103,236,28,176,103,176,28,214,103,214,54,28, +54,90,50,122,41,148,76,28,76,124,78,136,88,140,103,140,160,12,136,62, +121,86,240,52,143,52,116,146,245,146,180,232,198,232,208,230,212,222,214,218, +220,88,142,88,138,202,241,202,166,106,193,128,168,162,191,187,34,24,227,24, +32,86,32,50,226,50,227,86,130,106,131,24,54,74,107,74,54,96,109,96, +152,74,203,74,152,96,203,96,86,104,60,128,31,144,224,122,67,122,14,178, +245,178,226,210,60,210,70,146,200,146,196,224,186,232,174,234,159,236,118,154, +147,168,116,186,145,203,22,130,35,64,22,232,40,210,54,184,60,158,62,126, +63,12,100,62,63,114,102,190,63,148,100,42,235,42,128,12,128,112,204,112, +205,8,128,76,205,76,98,148,241,148,168,244,169,120,96,222,118,208,142,184, +169,150,236,220,216,204,196,182,169,149,38,22,83,50,16,86,61,114,28,232, +75,150,84,236,114,226,144,208,176,176,200,124,101,124,238,230,206,220,174,202, +146,178,132,152,123,124,96,102,112,92,120,78,126,62,126,24,190,24,190,86, +198,92,214,90,239,89,22,230,36,210,50,178,58,142,58,26,222,26,222,80, +59,80,142,26,143,80,92,246,92,116,218,116,219,244,92,150,219,150,92,182, +219,182,92,218,219,219,18,72,92,72,84,138,68,182,48,212,21,234,62,14, +36,148,97,198,96,46,237,46,130,12,130,114,204,114,205,10,130,78,205,78, +98,150,239,150,166,244,167,124,88,228,108,218,128,200,142,184,167,152,238,226, +220,216,202,200,184,180,167,153,66,14,44,58,19,90,104,60,45,60,32,100, +99,100,18,150,107,150,62,100,62,226,101,194,124,16,153,46,114,60,233,60, +208,14,177,60,118,92,225,92,106,126,241,126,168,126,169,60,114,168,233,168, +96,238,118,230,142,212,160,188,166,164,173,138,238,238,210,220,182,192,171,169, +92,10,62,54,25,94,238,42,71,42,14,142,245,142,152,238,168,238,182,236, +188,232,192,222,210,82,72,82,52,204,233,204,114,100,147,124,112,158,147,187, +70,10,103,38,34,50,221,50,178,8,149,50,48,88,207,88,20,126,237,126, +128,50,129,126,28,164,227,164,128,138,116,186,94,210,62,228,29,238,228,236, +200,226,172,210,146,186,133,165,30,206,30,44,84,44,85,196,30,110,85,110, +30,178,85,178,108,58,221,58,101,118,101,116,100,116,237,116,160,246,161,10, +84,220,112,196,138,162,161,126,238,210,216,192,188,160,161,123,104,14,141,34, +28,80,28,46,212,46,213,78,80,244,81,66,36,88,36,122,81,122,16,160, +81,160,22,232,34,216,40,194,41,160,110,102,213,102,98,140,223,140,160,246, +161,62,100,212,124,192,161,146,232,210,214,202,188,180,161,151,10,78,92,78, +88,124,76,168,58,198,19,230,92,198,32,146,65,14,112,58,229,58,106,116, +237,116,166,246,167,10,98,222,130,190,167,126,242,216,218,198,196,170,167,123, +18,82,88,78,82,126,72,168,52,200,25,226,86,200,34,154,65,16,78,238, +102,206,114,170,116,140,116,34,228,34,228,88,117,88,176,88,177,34,146,242, +146,120,224,120,225,240,146,154,225,154,146,186,225,186,146,220,225,221,52,18, +91,58,44,242,45,66,112,46,210,46,210,214,210,224,200,230,188,232,177,235, +46,20,83,58,42,244,43,64,106,40,216,40,216,208,212,224,204,228,190,230, +183,230,80,116,65,174,114,70,143,120,166,112,195,164,110,110,110,188,116,196, +134,198,146,196,158,190,165,173,80,16,52,78,21,122,58,246,59,66,116,22, +147,56,112,244,113,60,160,42,222,42,222,224,220,232,214,238,198,238,189,241, +14,40,241,40,92,70,93,8,160,66,161,10,44,214,44,90,100,90,101,208, +44,136,101,136,44,188,101,188,102,240,124,216,136,190,140,168,140,82,214,82, +214,212,212,224,206,226,181,230,140,126,215,126,140,166,215,167,18,40,235,40, +38,104,38,70,220,70,221,104,96,62,97,14,160,62,161,12,58,94,195,94, +38,120,213,120,40,158,76,146,96,134,115,120,96,236,112,234,126,230,134,220, +138,208,138,188,132,166,120,148,103,130,36,194,66,184,119,148,32,226,58,218, +98,198,133,172,194,136,135,168,226,222,204,210,184,194,174,182,159,157,14,76, +91,76,56,246,57,12,16,174,36,144,57,88,94,136,57,102,96,36,245,36, +144,60,145,10,190,60,191,8,108,98,108,66,232,66,233,96,128,94,211,94, +108,120,239,120,100,160,140,142,167,120,144,238,158,236,168,232,176,226,180,216, +182,204,178,182,174,168,168,160,151,134,102,194,134,178,163,154,100,224,140,204, +175,174,222,138,177,170,240,220,222,206,208,188,197,157,98,118,44,118,44,26, +100,26,101,118,44,72,101,72,110,148,124,130,136,104,138,90,138,22,210,22, +210,124,206,136,192,140,181,142,138,60,211,60,210,94,139,94,12,224,245,224, +52,224,52,164,204,164,205,224,100,224,101,164,150,224,151,165,68,18,42,62, +17,94,106,60,47,60,28,102,101,102,20,152,107,152,98,198,62,222,63,102, +92,228,247,228,116,34,206,34,176,60,176,114,174,126,166,130,158,132,149,132, +112,88,241,88,124,228,124,156,224,156,225,228,156,228,157,156,188,228,189,157, +28,230,46,230,60,224,74,206,80,186,80,154,78,122,72,96,66,78,48,52, +23,26,88,22,25,92,20,166,77,114,94,84,245,84,112,30,210,30,168,64, +168,112,166,122,160,128,148,128,135,128,80,226,247,226,114,226,114,152,220,152, +221,226,146,226,147,152,182,226,183,153,22,52,111,52,78,128,79,12,20,114, +79,60,116,92,79,66,144,52,233,52,178,126,179,12,122,112,146,92,179,54, +236,114,202,88,179,62,42,190,70,170,111,122,90,148,196,148,170,186,128,214, +92,230,47,238,100,172,143,203,22,92,231,92,44,30,186,30,126,70,126,120, +124,130,118,134,93,136,14,226,239,226,56,226,56,156,198,156,199,226,104,226, +105,156,148,226,149,157,28,224,28,36,78,36,79,216,28,90,79,90,28,140, +79,140,28,194,79,194,94,106,239,106,158,246,159,8,100,36,133,80,216,32, +183,78,94,200,124,166,157,108,238,204,196,164,161,107,12,34,109,34,28,234, +28,76,98,76,99,226,28,172,99,172,28,210,99,210,52,34,52,102,43,146, +76,34,76,138,99,138,108,232,118,220,124,214,134,212,140,212,148,218,162,226, +176,230,239,230,112,110,136,110,137,212,118,40,141,76,148,36,173,70,234,34, +215,72,152,96,239,96,194,212,195,12,152,180,174,146,195,102,236,174,195,107, +114,14,151,32,230,44,42,44,42,158,36,186,21,230,58,80,129,80,150,80, +229,80,100,134,101,56,184,132,185,56,58,122,80,106,101,86,128,112,101,86, +142,124,162,106,183,80,238,120,208,106,185,84,126,244,127,136,164,244,165,136, +52,214,127,214,66,186,127,186,58,156,127,156,164,158,229,158,164,186,221,186, +164,216,239,217,122,12,153,34,232,44,44,44,44,144,38,186,21,238,62,78, +125,78,148,78,229,78,104,130,105,56,64,122,84,106,105,82,134,104,105,86, +180,130,181,56,128,122,150,106,179,78,230,120,204,102,181,88,88,136,123,158, +202,130,171,158,60,174,237,174,146,244,147,128,56,234,96,212,141,174,234,230, +192,210,151,175,34,28,67,66,20,230,34,218,46,210,56,206,70,208,86,218, +106,226,126,230,241,228,12,114,56,114,57,206,76,94,235,94,154,212,155,10, +94,34,127,72,212,32,181,72,84,178,114,156,155,106,224,172,155,103,30,24, +65,58,12,100,50,100,46,228,85,178,82,232,88,222,100,212,118,212,134,222, +148,228,168,232,237,232,86,26,117,64,74,108,108,108,109,212,132,32,161,70, +224,30,199,72,128,96,233,96,180,210,181,12,130,178,160,142,181,104,224,174, +181,109,18,30,80,30,80,88,30,88,26,142,78,142,74,214,70,224,60,230, +54,232,35,232,148,14,124,72,99,108,214,108,232,66,129,66,138,138,103,206, +198,142,237,204,134,240,154,238,162,236,168,230,170,222,171,99,48,30,95,74, +204,30,163,82,24,106,237,106,130,246,131,10,22,210,66,180,131,110,234,206, +186,174,131,107,104,22,64,32,25,38,18,88,111,88,66,242,67,32,16,178, +65,110,98,138,67,110,92,184,121,116,140,20,183,60,210,122,243,174,144,58, +144,208,148,218,156,222,178,224,194,222,208,214,216,202,219,192,216,18,204,88, +180,146,154,180,126,204,91,227,216,18,160,30,39,36,50,54,73,84,114,50, +135,80,56,184,56,96,196,96,197,184,208,44,173,90,128,126,118,168,102,198, +70,220,23,236,146,156,146,214,148,228,160,234,212,234,224,226,237,205,36,22, +83,58,18,80,63,114,22,234,55,146,78,178,99,108,128,24,169,64,204,126, +237,178,210,28,198,78,174,132,138,178,73,230,132,72,132,202,132,218,138,224, +154,226,182,226,194,220,203,195,118,10,149,32,36,78,36,42,226,42,227,78, +70,76,45,116,118,56,145,78,200,82,235,114,24,148,76,136,132,108,183,64, +96,70,96,114,100,124,118,128,148,128,176,126,188,118,195,100,210,194,64,194, +64,158,210,158,211,194,190,208,233,242,36,232,213,226,134,228,135,139,112,14, +149,38,36,88,36,48,228,48,229,86,66,90,35,132,114,66,141,90,196,88, +235,126,176,70,126,124,76,150,29,164,92,82,92,132,96,144,122,148,152,146, +176,142,188,136,191,116,59,174,208,168,209,246,58,174,58,232,209,226,132,160, +133,229,36,62,36,30,222,30,223,60,186,104,68,104,68,54,188,54,189,104, +68,78,189,78,18,136,237,136,18,182,58,166,90,146,123,114,236,176,186,160, +155,136,66,230,66,172,192,172,192,220,180,226,161,214,128,244,129,151,20,74, +105,74,66,244,67,10,18,170,65,96,100,138,67,98,222,114,126,114,126,42, +222,42,223,114,164,10,153,42,118,226,118,154,232,154,232,210,216,224,201,208, +172,244,173,114,126,78,223,79,26,218,26,34,82,34,83,212,26,86,83,86, +26,140,83,140,26,196,83,196,166,206,118,230,118,24,220,24,220,84,119,84, +240,138,119,138,238,210,234,222,228,232,218,230,208,220,196,200,184,164,178,132, +177,85,75,18,102,64,32,166,103,150,72,18,22,98,79,96,24,220,101,202, +218,112,128,112,128,44,218,44,219,112,166,8,155,44,128,76,219,76,120,228, +120,146,230,146,230,198,228,210,226,214,216,216,206,218,199,218,170,246,171,121, +54,84,54,26,204,26,205,82,74,52,183,52,74,78,183,78,28,136,68,114, +105,78,208,166,56,166,56,130,208,130,209,166,154,130,166,102,83,102,24,238, +70,220,104,190,124,160,131,130,232,204,226,220,220,226,208,228,166,230,152,228, +144,224,140,220,141,167,206,148,58,148,58,90,206,90,207,148,22,94,70,58, +103,16,80,48,174,48,145,90,132,90,120,160,100,190,68,218,23,240,236,198, +228,220,216,232,194,236,152,234,142,224,142,216,143,149,76,14,50,52,19,82, +132,142,36,142,36,92,132,92,133,142,82,92,114,48,57,48,18,240,52,214, +68,184,76,148,81,92,98,142,98,212,100,226,110,232,122,234,206,234,220,232, +228,226,234,212,239,198,130,194,158,164,174,132,178,92,183,20,146,80,222,80, +218,160,218,174,210,182,200,184,185,185,14,82,88,78,80,140,62,188,46,212, +21,236,102,204,34,154,69,16,154,10,130,50,109,76,220,142,120,142,120,90, +220,90,221,142,166,90,198,44,135,44,94,238,124,218,146,186,160,156,173,90, +176,158,176,214,176,228,186,234,212,234,228,230,234,220,241,201,90,70,24,172, +91,162,64,22,22,112,69,104,20,220,93,206,94,40,243,40,112,246,112,88, +224,88,225,242,112,218,225,218,144,218,145,88,186,218,187,88,144,130,187,130, +144,172,187,172,158,88,169,41,16,36,243,36,46,238,46,82,208,82,209,238, +46,214,209,214,112,82,131,36,94,214,95,82,160,214,161,82,94,126,161,126, +94,166,161,167,12,62,243,62,88,98,89,12,164,98,165,12,52,244,52,118, +208,118,209,242,52,168,209,168,52,218,209,218,128,218,129,119,16,70,93,70, +20,156,91,118,32,234,50,234,58,230,60,220,61,12,96,50,245,50,136,92, +137,10,200,92,201,10,114,244,114,112,224,112,225,242,114,162,225,162,114,218, +225,218,168,218,169,113,30,232,30,40,82,40,83,218,30,88,83,88,30,142, +83,142,30,198,83,198,100,56,237,56,138,94,139,16,190,94,191,12,118,244, +118,114,216,114,217,242,118,162,217,162,118,218,217,218,166,218,167,115,16,42, +239,42,96,64,97,12,164,62,165,12,84,66,48,86,19,96,102,98,62,126, +19,152,38,108,53,130,64,94,79,114,44,236,82,228,94,210,98,182,92,154, +69,122,26,182,83,142,26,210,95,164,214,158,130,158,130,94,214,94,215,158, +154,68,141,94,130,126,213,126,100,240,126,226,144,206,152,182,157,158,238,206, +234,224,230,232,224,234,206,234,194,234,188,230,186,222,187,159,110,26,62,34, +21,36,16,88,123,88,70,238,71,34,18,184,71,102,108,156,71,110,122,142, +147,66,242,122,205,60,176,168,177,14,224,132,202,180,182,202,148,224,107,237, +30,22,63,52,16,86,51,114,24,222,61,142,80,218,80,34,124,34,125,210, +80,82,125,82,80,134,125,134,80,190,125,190,162,66,141,132,210,60,237,114, +188,152,189,10,224,124,208,176,182,204,154,222,117,237,116,14,149,34,238,48, +48,48,48,162,38,200,19,232,90,246,90,106,222,106,223,244,90,158,223,158, +90,216,223,216,154,216,155,65,106,206,32,148,63,12,14,76,88,76,82,142, +56,194,17,232,134,62,107,136,240,114,201,58,170,174,171,10,224,136,196,188, +170,212,138,228,103,241,16,34,241,34,92,60,93,6,162,60,163,6,208,112, +50,112,50,74,208,74,209,112,98,112,99,74,152,112,153,74,180,124,199,136, +224,148,50,148,48,192,38,220,25,240,58,176,99,202,208,164,174,194,142,216, +109,232,140,122,152,164,166,200,192,224,212,232,222,234,228,230,232,222,241,205, +30,32,235,32,72,76,55,138,206,76,175,138,130,32,130,102,116,158,92,194, +66,216,29,236,232,236,194,212,162,180,129,117,110,196,44,228,44,24,198,24, +198,80,45,80,44,134,223,134,228,198,226,214,220,226,210,230,200,228,192,226, +168,208,154,190,138,162,132,122,125,81,14,68,97,68,14,158,95,118,56,12, +56,228,42,242,27,226,160,206,118,232,118,26,218,26,218,84,119,84,234,136, +119,136,238,206,234,220,226,230,220,232,210,224,188,188,180,156,176,116,175,85, +12,216,247,216,54,216,54,40,206,40,207,216,104,216,105,40,154,216,155,41, +64,12,44,50,19,82,136,48,47,48,74,228,88,226,100,224,108,216,112,208, +118,84,46,84,38,196,141,196,66,102,93,124,62,156,87,178,178,10,156,72, +133,108,242,68,159,68,124,238,162,210,190,174,202,140,209,68,12,138,147,138, +236,228,204,204,178,172,166,144,157,107,30,66,19,122,74,66,91,102,58,244, +59,16,108,20,135,50,108,240,109,58,188,230,210,230,220,226,224,216,224,38, +149,38,148,70,173,92,126,104,205,104,128,202,148,186,164,166,178,134,185,104, +196,188,141,127,48,20,75,58,40,242,41,68,184,234,198,232,208,230,212,226, +214,220,214,216,214,38,105,38,174,150,82,150,82,96,176,96,177,150,164,168, +191,208,66,202,181,194,126,198,127,59,46,198,46,32,102,32,103,192,46,100, +103,100,46,170,103,170,108,236,130,208,140,188,144,164,146,152,146,26,226,26, +226,204,224,218,218,224,210,228,189,230,146,82,227,82,146,142,227,143,90,138, +30,138,30,66,92,66,93,138,84,164,101,210,16,208,95,190,60,198,61,12, +112,62,112,30,226,30,227,60,208,132,128,132,128,72,208,72,209,132,128,102, +209,102,156,146,179,162,102,172,243,172,154,190,128,220,99,242,186,194,237,233, +38,198,38,44,88,44,89,188,38,166,89,166,154,64,181,86,174,114,196,114, +210,108,214,96,216,92,216,42,128,42,128,148,230,148,226,218,218,230,200,236, +188,238,175,236,104,188,207,188,166,10,153,43,68,14,44,62,21,92,114,56, +47,56,34,102,103,102,20,148,113,148,66,102,66,234,111,200,174,12,142,64, +119,90,98,174,140,156,176,124,192,106,210,78,222,54,151,54,142,92,173,126, +150,246,150,150,232,150,233,240,150,222,233,223,118,14,76,64,39,92,26,170, +64,158,94,144,132,120,172,86,202,50,91,50,86,82,133,118,88,244,88,144, +212,144,213,242,88,220,213,221,126,10,88,54,52,84,17,102,120,18,140,42, +174,68,204,84,239,98,72,88,185,88,50,222,50,130,102,130,103,218,50,202, +103,202,144,248,144,126,204,126,204,190,202,202,198,206,188,208,175,209,22,18, +59,54,8,96,48,96,48,220,83,184,86,40,113,62,162,38,191,56,76,22, +140,22,141,88,72,94,141,68,158,22,216,22,217,100,166,82,217,66,150,84, +114,124,71,150,150,86,160,102,184,120,216,134,241,142,162,124,126,158,103,172, +184,148,152,180,109,202,214,170,164,210,138,222,97,237,12,70,91,70,16,158, +91,120,26,234,38,234,50,230,54,224,56,220,57,12,90,40,235,40,138,62, +139,10,186,62,187,8,212,142,114,142,114,78,212,78,213,142,114,108,213,108, +90,174,239,174,166,142,158,186,144,208,122,226,93,238,236,236,212,226,188,208, +176,194,165,175,18,36,235,36,190,112,58,112,58,62,190,62,191,112,58,88, +191,88,90,62,91,10,156,62,157,8,20,136,235,136,18,180,48,166,80,144, +105,112,238,176,210,168,188,158,161,136,156,152,118,160,93,162,60,182,187,182, +32,206,219,206,94,238,112,238,126,236,130,230,130,228,131,159,24,36,243,36, +96,58,97,12,168,58,169,14,126,52,151,68,230,76,48,76,48,168,40,206, +25,238,64,104,139,104,108,152,109,88,68,148,109,108,136,132,109,116,148,104, +231,104,180,150,181,88,138,150,181,106,236,142,181,110,62,166,235,166,58,224, +123,166,100,244,100,194,208,194,209,242,100,228,209,229,18,76,97,76,60,244, +61,12,16,170,61,82,94,136,61,98,100,46,243,46,144,68,145,14,190,68, +191,12,218,144,122,144,122,82,218,82,219,144,122,112,219,112,90,178,245,178, +94,238,130,222,152,200,169,154,238,238,190,212,167,179,18,236,34,198,40,150, +40,34,90,34,90,220,74,238,57,224,40,92,91,92,90,146,41,146,106,48, +245,48,150,68,151,14,196,66,197,14,218,140,126,140,126,80,218,80,219,140, +126,110,219,110,108,176,245,176,110,240,146,220,166,192,175,140,240,238,198,210, +173,177,122,12,157,34,22,238,42,194,48,154,48,46,239,46,64,80,133,80, +104,142,105,58,66,134,105,90,132,112,105,90,182,142,183,56,146,80,233,80, +134,134,183,90,238,130,183,88,64,158,239,158,54,222,141,158,106,246,106,188, +206,188,207,246,106,228,207,229,116,10,153,30,18,232,36,196,42,150,42,42, +233,42,60,74,131,74,102,130,103,50,58,120,103,84,132,104,103,82,142,74, +227,74,176,128,177,50,132,122,177,80,230,118,177,78,208,132,75,148,66,170, +221,170,56,198,235,198,146,140,146,240,130,246,117,233,118,16,149,34,20,238, +44,178,44,42,237,42,64,74,141,74,112,116,113,54,64,114,113,76,134,98, +113,82,150,74,231,74,184,114,185,52,152,108,183,74,236,110,185,78,204,178, +84,178,84,132,204,132,205,178,138,110,131,132,54,240,114,214,136,182,147,132, +84,154,205,154,238,212,222,236,160,236,161,178,196,186,176,212,215,206,220,216, +209,195,12,70,91,70,12,154,91,112,58,10,58,222,38,234,23,218,98,62, +237,62,108,114,223,114,166,240,167,8,86,208,134,164,165,114,240,208,198,172, +167,115,24,62,231,62,38,116,215,116,126,244,127,10,24,220,88,166,123,116, +232,214,166,168,135,117,24,44,237,44,96,64,97,12,162,62,163,12,198,144, +64,144,64,78,198,78,199,144,64,112,199,112,18,182,243,182,30,240,104,212, +137,156,232,238,160,208,139,183,206,78,50,78,50,28,206,28,207,78,74,42, +107,68,150,68,183,40,44,106,211,106,22,132,235,132,128,132,129,28,52,148, +21,182,90,148,111,174,146,144,167,172,206,144,235,174,46,194,213,194,20,228, +239,228,130,228,131,165,118,94,32,94,32,28,120,28,121,94,46,48,57,74, +102,50,89,74,24,126,127,126,14,160,133,156,74,158,75,28,36,182,17,228, +62,184,65,222,84,178,97,212,110,170,123,202,134,90,239,90,102,238,158,184, +172,118,173,10,236,230,186,160,173,96,190,26,223,67,28,26,71,58,14,88, +57,118,24,228,69,152,88,62,227,62,94,118,217,118,154,248,155,10,64,224, +118,180,155,124,232,218,182,172,155,129,36,24,73,52,16,90,55,114,26,224, +75,140,214,142,108,142,108,76,216,76,217,142,108,110,217,110,92,40,241,40, +138,60,139,8,186,60,187,6,82,174,243,174,82,240,136,210,161,154,234,238, +184,206,161,175,108,12,143,30,34,80,34,38,224,38,225,80,56,76,205,76, +196,158,62,158,62,104,198,104,199,158,62,132,199,132,104,96,105,50,156,96, +157,50,20,186,239,186,30,238,102,216,124,184,127,158,228,236,160,216,135,187, +56,182,76,176,90,156,84,126,66,100,88,32,38,32,39,240,104,32,241,32, +120,240,120,94,214,94,215,238,120,154,215,154,120,216,215,216,164,32,145,95, +28,26,65,62,10,92,50,92,46,218,83,176,76,46,239,46,116,12,116,116, +200,116,201,8,116,80,201,80,80,154,241,154,158,246,159,124,74,232,118,198, +159,154,240,226,188,192,159,155,164,36,217,88,120,12,44,80,197,70,32,156, +79,94,212,128,53,128,18,184,239,184,134,246,135,89,20,50,221,50,74,10, +74,118,178,118,179,10,74,84,179,84,16,154,235,154,126,246,127,128,20,230, +90,186,119,154,236,226,162,184,135,155,16,76,95,76,18,158,83,126,60,16, +60,232,44,244,29,224,88,118,245,118,172,236,212,226,216,40,122,40,114,198, +239,198,154,60,173,96,156,136,175,171,16,118,47,38,114,80,31,80,72,246, +73,14,18,182,115,140,120,102,237,102,100,224,245,224,176,224,177,13,100,18, +137,50,12,62,245,62,52,246,52,106,204,106,205,244,52,162,205,162,52,222, +205,222,128,222,129,107,98,208,30,150,69,14,16,78,90,76,74,158,25,236, +98,124,245,124,176,240,212,230,220,36,130,36,122,200,241,200,158,64,179,98, +160,142,179,177,12,112,245,112,230,196,50,196,68,24,202,24,190,228,147,234, +110,50,145,84,108,136,143,171,18,38,239,38,96,58,97,10,158,58,159,10, +190,120,64,120,64,66,190,66,191,120,64,92,191,92,18,146,235,146,18,196, +82,160,111,120,238,194,159,146,66,192,189,192,28,230,225,230,128,160,129,231, +18,36,241,36,92,56,93,8,160,56,161,8,192,116,60,116,60,62,192,62, +193,116,60,90,193,90,20,140,239,140,16,184,74,154,105,116,238,182,155,140, +70,242,70,166,182,166,183,242,70,194,183,194,70,222,183,223,16,36,241,36, +92,56,93,8,158,56,159,8,188,116,62,116,62,62,188,62,189,116,62,90, +189,90,20,144,239,144,16,188,72,160,109,116,240,182,194,168,167,144,66,232, +66,176,190,176,190,218,161,230,128,248,129,145,16,36,241,36,96,56,97,8, +160,56,161,6,192,116,66,116,66,64,192,64,193,116,66,90,193,90,20,142, +241,142,108,122,25,192,172,142,235,184,64,182,186,178,180,232,149,232,122,154, +104,210,45,241,20,38,239,38,100,58,101,10,162,58,163,10,194,120,66,120, +66,66,196,66,197,120,66,92,197,92,24,148,237,148,20,188,76,162,111,120, +236,190,186,168,167,148,116,164,116,234,85,234,80,186,45,228,140,190,171,226, +178,186,213,227,26,78,233,78,128,244,129,8,20,208,62,176,94,130,123,78, +234,206,192,172,160,130,133,79,62,238,62,32,194,32,195,232,62,90,195,90, +62,148,195,148,62,206,195,207,32,228,32,36,84,36,85,218,32,90,85,90, +32,146,85,146,32,202,85,202,108,44,225,44,98,88,239,88,164,88,165,6, +104,148,147,106,188,108,231,148,108,172,225,172,94,228,243,228,164,228,165,125, +20,112,41,34,118,76,31,76,18,166,119,136,74,244,75,12,160,14,119,118, +242,66,141,66,200,66,186,166,105,238,144,106,172,186,237,233,100,20,27,34, +16,88,107,88,68,246,69,26,18,174,69,98,98,134,69,106,224,92,124,92, +124,38,224,38,225,92,124,66,225,66,166,10,155,38,206,136,111,182,170,92, +171,152,142,110,107,148,198,108,241,140,220,160,119,214,238,188,174,224,109,239, +134,8,80,48,19,76,240,76,168,50,123,16,68,64,179,64,184,120,68,120, +68,90,184,90,185,120,202,138,114,146,43,148,44,172,209,172,22,198,235,198, +134,144,134,230,91,237,30,186,30,38,66,38,67,174,30,154,67,154,80,32, +152,32,142,212,117,218,60,228,90,192,104,148,115,32,80,88,147,88,80,140, +145,140,180,242,180,32,230,32,204,102,232,142,236,176,224,190,207,193,30,206, +30,56,82,56,83,196,30,172,83,172,118,244,118,70,226,70,226,234,214,242, +195,228,174,12,170,102,156,148,135,180,210,164,169,109,72,14,23,90,110,60, +41,60,32,102,101,102,18,150,105,150,64,102,64,224,109,196,128,242,128,74, +232,74,232,230,212,242,193,224,180,12,180,100,149,172,218,166,177,109,26,34, +128,34,128,216,106,226,91,210,28,86,127,86,26,136,129,136,24,226,64,182, +76,142,77,34,166,244,166,30,222,30,196,106,226,138,236,170,222,194,193,193, +56,14,32,150,89,188,14,74,84,74,66,178,21,230,88,36,156,36,148,222, +132,230,121,218,120,36,114,168,73,232,96,92,153,92,92,144,151,144,184,244, +184,36,232,36,202,102,236,148,236,182,220,200,203,191,63,16,92,54,28,164, +99,154,16,222,101,198,60,16,18,98,65,98,122,244,122,74,228,74,228,232, +206,240,193,226,178,14,172,120,137,172,208,170,175,107,68,14,21,90,224,40, +55,40,66,72,213,72,34,102,196,102,194,180,216,234,228,238,243,212,32,138, +138,138,128,168,164,168,156,222,122,234,105,220,28,236,70,198,79,139,34,38, +192,38,164,118,222,118,208,220,176,236,153,220,106,38,90,166,31,245,64,16, +32,156,97,202,12,82,94,80,80,162,27,232,104,40,206,40,194,120,228,120, +216,230,192,238,179,222,140,40,134,174,85,237,8,36,147,36,81,36,28,230, +28,94,132,94,132,220,110,228,103,214,78,36,63,94,64,198,65,94,98,198, +99,94,146,76,247,76,150,112,179,164,206,10,206,234,180,244,165,229,26,54, +233,54,128,12,90,88,19,136,140,54,184,98,241,126,74,114,183,114,38,158, +219,158,134,158,134,238,108,246,97,232,84,184,29,234,172,190,225,231,16,50, +237,50,129,12,46,240,46,94,210,94,210,228,184,240,169,222,128,12,121,94, +84,108,113,132,72,144,181,144,162,104,133,144,66,182,189,182,128,232,129,145, +204,106,50,106,50,26,206,26,207,106,50,66,207,66,207,66,126,106,127,26, +20,156,212,152,204,226,160,238,149,224,122,122,100,196,35,239,12,46,84,46, +60,152,19,204,26,82,97,180,142,12,97,108,126,240,127,48,168,14,201,52, +236,66,135,66,226,114,135,114,226,162,135,162,244,212,135,212,178,66,179,213, +24,32,231,32,200,72,52,72,52,52,200,52,201,72,30,124,30,90,224,90, +225,122,126,90,127,10,110,128,60,128,60,108,112,108,113,128,194,126,142,126, +142,108,194,108,195,126,40,146,213,146,48,166,209,166,20,186,239,186,90,132, +91,186,164,132,165,186,108,186,64,212,25,226,136,218,82,240,85,200,136,186, +154,210,233,240,200,196,173,217,14,70,95,70,18,158,87,118,58,12,58,232, +34,238,23,222,100,58,229,36,216,56,158,102,111,120,140,8,158,80,212,122, +230,116,225,90,94,146,237,146,142,146,128,208,89,236,182,146,182,226,222,228, +237,201,18,236,38,178,38,34,86,34,86,228,62,238,53,222,84,94,39,94, +84,144,39,144,150,14,189,48,104,62,247,62,134,88,211,180,142,184,205,82, +228,108,229,238,124,114,124,218,229,211,58,244,59,10,30,64,19,122,74,66, +91,102,146,12,179,46,96,58,245,58,218,90,219,242,218,222,110,226,111,96, +130,88,197,194,188,78,137,205,50,16,83,54,42,240,43,62,106,38,216,38, +216,228,194,238,181,222,108,58,137,86,62,98,197,98,128,232,129,98,80,206, +80,134,178,134,178,194,156,204,147,191,38,22,77,54,14,82,59,110,24,234, +57,148,210,146,96,146,96,76,210,76,211,146,146,76,147,8,146,40,231,40, +96,110,211,110,64,186,245,186,152,246,153,147,30,190,30,40,80,40,81,178, +30,156,81,156,76,228,114,162,114,30,212,30,212,88,115,88,236,204,220,228, +162,228,156,214,157,112,226,134,157,169,64,12,19,104,82,96,96,66,39,66, +52,104,52,230,95,196,228,22,111,42,116,70,139,104,156,56,177,90,226,56, +199,108,94,138,243,138,166,102,126,180,235,232,204,138,178,198,101,243,42,242, +42,66,212,66,212,228,188,240,163,224,128,12,128,92,106,154,71,186,182,178, +125,105,14,78,80,78,58,178,21,226,56,12,30,152,81,188,82,50,173,50, +154,136,98,136,98,84,154,84,155,136,126,246,127,12,76,220,127,150,160,182, +127,148,168,106,201,16,236,230,192,170,179,116,148,238,196,186,220,102,221,70, +246,68,183,69,74,14,22,86,115,78,88,40,125,92,40,240,40,112,108,112, +108,234,92,238,79,222,40,144,109,144,40,178,109,178,214,26,149,58,148,12, +148,104,204,104,223,76,148,120,148,226,210,226,233,200,218,142,149,175,12,78, +90,78,74,172,21,234,92,196,30,148,65,10,82,236,108,210,124,132,124,30, +214,30,214,90,125,90,162,112,162,218,164,228,176,234,220,234,232,224,239,204, +226,136,163,167,36,22,219,22,30,92,30,52,222,52,223,90,126,110,127,22, +50,78,107,78,148,78,203,78,50,100,107,100,148,100,203,100,104,122,54,130, +54,182,202,182,202,128,145,128,54,154,105,154,202,154,149,154,22,238,90,216, +103,182,150,182,150,218,160,228,216,230,230,220,237,201,72,12,19,126,54,248, +55,56,144,16,104,30,104,130,216,130,216,28,181,28,140,78,105,78,184,78, +217,78,80,236,130,188,139,130,242,188,228,224,178,222,179,131,34,28,71,54, +16,90,53,118,24,230,67,150,74,232,108,158,108,28,212,28,212,92,109,92, +236,196,224,226,160,228,150,214,151,114,228,130,151,165,20,242,58,162,58,28, +208,28,208,84,59,84,116,108,116,214,124,228,216,228,237,198,212,126,117,163, +12,74,91,74,16,154,87,120,56,12,56,228,40,240,21,224,158,154,112,204, +113,48,134,14,167,74,136,240,198,176,207,30,236,226,199,179,72,14,27,122, +54,246,55,58,140,12,89,112,210,106,226,64,115,64,164,92,164,228,144,244, +125,226,128,136,85,210,194,140,241,205,232,32,34,32,34,224,239,224,58,74, +225,74,106,100,107,46,168,100,169,46,52,120,231,120,58,168,106,138,141,92, +194,190,102,190,102,152,194,152,195,191,18,234,36,160,36,32,76,32,76,232, +62,238,51,224,36,88,77,88,36,144,77,144,90,54,245,54,242,206,232,236, +224,236,208,206,194,142,185,10,206,16,229,38,166,80,109,80,98,108,177,108, +106,198,106,136,168,136,169,196,98,232,118,218,134,194,139,152,180,230,149,199, +112,14,141,48,84,66,233,66,200,12,165,66,106,90,106,152,210,152,211,92, +114,210,146,176,156,132,157,66,26,28,65,64,22,230,42,214,66,208,96,220, +132,232,241,228,12,112,56,112,57,209,34,22,71,50,20,88,59,114,26,230, +63,152,82,30,138,30,138,76,90,76,88,120,138,120,138,226,114,240,99,228, +70,202,139,170,80,142,107,164,158,30,220,30,220,74,168,74,168,122,224,122, +224,232,200,242,181,228,164,140,191,164,160,202,223,175,16,40,239,40,36,70, +225,70,100,16,101,64,166,14,167,62,24,122,241,122,130,70,131,122,74,84, +75,122,130,96,211,96,68,134,68,176,226,176,226,200,218,228,194,236,177,236, +220,152,69,152,64,196,35,236,96,200,107,232,134,194,151,224,174,188,189,217, +16,72,113,72,18,160,105,120,66,10,66,234,44,244,31,228,126,246,126,134, +224,134,225,242,126,220,225,220,164,134,165,12,244,66,165,67,94,14,31,100, +232,50,69,50,16,180,243,180,216,108,68,108,69,180,142,246,143,51,20,36, +101,36,62,36,48,92,19,140,46,208,46,102,86,102,87,198,46,178,85,178, +82,234,116,164,116,26,224,26,224,68,117,68,124,110,237,110,122,150,243,150, +156,78,157,148,194,80,195,150,142,150,142,232,175,212,236,234,200,208,173,150, +224,168,195,195,14,70,73,70,14,146,77,112,54,8,54,228,34,240,23,224, +84,38,147,38,82,66,149,66,91,116,118,8,118,68,93,116,148,98,115,76, +160,36,229,36,158,66,237,66,160,116,190,72,191,6,238,116,191,72,80,134, +225,134,138,112,98,172,217,172,74,204,237,204,162,242,163,147,12,74,91,74, +18,162,91,130,58,14,58,228,40,242,23,228,158,12,122,74,85,104,234,100, +184,64,153,24,146,74,169,92,110,112,194,112,165,160,140,158,173,190,102,184, +85,228,208,178,237,216,132,180,132,224,136,236,168,238,192,232,201,213,124,12, +82,68,17,108,240,102,160,64,119,22,116,68,141,92,62,110,178,110,141,152, +28,222,55,168,118,160,141,192,192,172,227,214,84,160,84,220,92,232,170,232, +189,203,12,68,96,68,80,162,25,238,62,10,36,148,101,204,154,10,183,38, +170,202,130,232,130,50,218,50,218,132,131,132,238,230,178,172,169,132,226,152, +191,182,130,92,219,93,12,36,123,36,28,244,28,82,106,82,107,240,28,220, +107,220,28,182,107,182,56,36,56,110,41,152,80,36,80,140,107,144,154,12, +187,40,180,210,136,234,136,50,216,50,216,128,139,128,136,90,217,90,172,128, +190,190,237,232,228,148,191,185,148,116,176,104,182,48,64,48,64,148,212,148, +202,228,159,240,92,72,133,102,112,12,97,48,16,190,183,191,20,228,50,146, +50,28,214,28,214,70,51,70,70,122,118,122,63,214,144,86,144,226,111,232, +236,210,145,128,224,110,169,149,14,70,97,70,16,146,89,120,30,236,60,230, +61,14,220,126,118,126,118,34,220,34,221,126,118,78,221,78,100,176,231,176, +86,228,243,228,164,228,165,141,20,24,229,24,22,116,233,106,174,130,175,24, +70,24,71,114,70,54,175,54,70,84,175,84,22,144,104,144,76,196,21,238, +44,164,111,218,118,144,210,144,178,194,123,234,236,234,166,192,135,145,18,34, +241,34,96,56,97,10,164,54,165,10,42,124,100,124,100,152,40,152,40,72, +98,72,98,102,41,102,68,48,53,72,120,74,225,74,160,54,185,74,140,84, +157,102,112,114,235,114,202,84,181,114,118,138,225,138,170,160,171,114,58,172, +172,172,130,196,130,234,112,244,97,234,16,208,237,209,30,184,30,44,72,44, +73,176,30,156,73,156,88,100,243,100,118,100,119,26,168,100,169,8,222,52, +169,52,164,116,131,202,192,194,155,144,214,122,215,242,106,124,106,226,213,221, +62,14,17,96,100,56,41,56,32,96,97,96,20,144,95,144,60,96,60,224, +97,192,108,170,157,216,100,146,152,146,136,196,89,240,156,240,204,198,224,148, +174,148,192,200,243,236,100,30,237,30,96,120,245,110,202,132,203,30,132,30, +133,116,132,58,203,58,132,86,203,87,64,14,23,94,104,62,41,62,32,102, +99,102,18,148,103,148,60,102,60,224,97,192,214,132,122,132,122,44,216,44, +217,132,122,72,217,72,122,102,217,102,162,12,151,44,102,166,241,166,166,244, +167,142,92,232,126,210,165,166,238,228,206,208,175,167,32,22,73,50,20,80, +65,108,26,236,59,142,212,120,100,120,100,28,212,28,213,120,100,74,213,74, +84,168,225,168,68,224,243,224,156,224,157,137,84,16,27,88,60,154,61,46, +142,12,93,84,206,82,222,50,117,50,126,92,91,138,162,72,162,146,133,152, +186,92,231,134,54,174,21,226,116,162,149,196,192,164,237,208,186,200,176,226, +168,232,96,232,88,226,84,220,85,173,16,74,105,74,64,246,65,6,16,168, +65,90,100,142,65,102,158,12,191,48,124,100,124,62,236,62,237,96,112,130, +247,130,184,130,184,220,172,242,145,241,26,20,70,70,88,150,72,220,40,234, +29,222,90,20,23,92,18,166,79,110,150,10,183,40,114,94,114,54,230,54, +231,90,102,126,245,126,178,126,178,234,160,240,147,239,22,32,53,74,16,212, +47,128,78,10,78,72,84,80,126,80,143,60,134,28,79,54,152,30,226,30, +191,76,168,52,205,92,90,92,67,144,134,116,81,116,54,162,139,162,102,116, +92,188,53,236,122,208,95,172,142,104,236,104,221,136,158,136,152,192,140,218, +119,240,240,232,186,222,155,180,188,104,189,220,188,162,237,163,110,12,145,40, +36,98,36,54,220,54,221,96,22,134,235,134,134,134,134,234,106,246,97,243, +16,70,101,70,14,160,95,122,66,10,66,236,38,242,35,238,154,12,181,42, +122,94,122,58,230,58,231,94,108,130,243,130,144,240,176,234,177,131,36,28, +75,56,20,90,57,114,26,230,75,144,144,14,173,46,100,96,100,58,226,58, +227,96,88,130,239,130,166,130,166,240,130,236,127,233,74,36,39,124,210,76, +59,76,20,146,237,146,132,242,133,13,12,70,101,70,14,156,99,122,60,12, +60,234,29,228,88,226,243,226,108,42,216,42,209,226,154,42,141,226,110,128, +211,129,64,16,21,98,104,58,43,58,32,102,97,102,18,152,107,152,64,102, +64,230,103,194,102,232,245,232,118,46,222,46,215,232,164,46,147,232,118,132, +217,133,69,12,94,56,24,166,99,152,66,12,18,102,69,96,14,214,99,196, +86,226,243,226,112,44,218,44,205,226,156,44,139,226,104,128,211,129,18,236, +38,166,38,26,88,26,88,232,59,228,38,84,89,84,38,140,89,140,116,96, +116,50,228,50,229,94,174,8,152,98,105,158,138,116,138,226,177,194,174,94, +194,176,239,224,230,118,193,157,34,22,71,56,20,84,57,114,30,232,63,138, +88,92,88,52,220,52,221,90,154,10,126,114,81,170,120,122,120,232,167,198, +160,100,190,182,233,222,220,112,183,157,46,104,46,60,208,60,209,100,134,12, +98,118,21,178,80,134,80,234,131,198,124,112,162,190,235,236,202,124,155,173, +34,36,217,36,48,74,207,74,32,116,225,116,126,116,127,36,18,170,237,170, +94,134,84,206,41,240,168,244,169,135,16,76,98,76,80,166,21,236,58,16, +32,146,111,200,108,42,212,42,184,154,105,238,234,230,158,150,131,43,20,48, +112,48,82,104,31,140,80,12,48,84,115,112,126,126,184,86,212,38,131,38, +230,132,166,88,145,38,42,168,202,164,188,226,145,238,120,136,92,208,39,243, +18,54,114,54,84,124,25,154,78,14,48,96,119,128,132,42,218,42,186,106, +135,142,236,146,166,92,147,42,56,182,21,226,116,162,149,194,198,178,239,220, +239,220,88,170,88,226,92,232,102,234,164,234,178,226,185,211,18,88,243,88, +128,14,74,142,225,220,38,234,108,204,156,152,181,89,26,208,26,40,74,40, +75,200,26,108,75,108,26,180,75,180,224,22,99,36,104,52,127,82,146,48, +165,78,96,96,227,96,210,46,181,90,90,130,237,130,140,96,130,154,108,192, +69,228,104,238,156,214,182,188,198,162,127,162,236,236,186,218,154,194,137,177, +220,94,230,68,50,68,50,168,25,236,70,108,205,96,132,78,130,120,140,132, +200,132,218,126,223,112,130,68,131,12,130,38,225,38,60,196,247,196,222,232, +98,232,98,160,225,161,126,14,167,38,242,52,64,52,64,184,27,242,18,68, +45,108,14,160,65,130,80,158,245,158,226,98,114,98,114,224,231,225,16,70, +87,70,18,158,87,118,56,10,56,238,31,234,86,36,152,36,152,220,125,230, +88,88,153,88,84,144,153,144,116,36,116,144,96,204,77,226,182,246,182,34, +232,34,202,108,218,126,230,146,234,164,234,178,228,190,218,196,203,195,56,244, +57,12,18,124,37,64,72,56,83,88,98,26,229,26,100,92,100,56,228,56, +229,90,160,116,161,26,116,80,145,80,116,106,145,106,182,80,211,80,182,106, +211,106,84,132,245,132,104,240,104,160,222,160,222,236,207,242,162,132,153,160, +142,228,143,160,180,226,181,161,16,98,97,98,62,246,63,10,26,34,43,74, +100,34,81,76,22,180,63,114,94,154,63,112,112,28,233,28,112,96,112,58, +230,58,231,96,172,120,173,28,128,84,155,84,128,110,157,110,188,84,213,84, +188,110,213,110,102,134,245,134,116,242,116,164,224,164,224,240,207,244,166,134, +159,164,154,234,155,164,186,232,187,165,38,26,77,62,12,102,54,102,52,230, +91,200,84,112,243,112,94,48,239,48,132,84,133,10,196,84,197,12,84,178, +128,142,169,78,126,244,126,158,212,158,213,242,126,218,213,219,30,194,30,46, +74,46,75,182,30,160,75,160,152,26,93,40,90,96,239,96,90,168,155,140, +102,234,128,228,129,32,200,32,225,64,174,10,176,124,190,190,224,234,234,226, +241,206,218,118,184,192,153,221,124,34,30,34,30,204,129,204,110,62,80,136, +51,180,50,70,88,124,117,168,164,8,146,72,123,116,208,108,226,64,149,64, +174,94,160,184,140,214,115,236,238,234,200,200,169,127,126,218,34,218,34,40, +119,40,104,74,76,144,53,184,52,82,84,130,111,172,160,64,187,90,174,114, +210,106,218,42,136,42,136,150,232,150,224,226,183,238,168,12,157,42,118,188, +209,189,120,32,30,32,30,206,123,206,106,58,78,128,47,172,48,72,82,120, +111,168,116,104,144,72,144,24,198,24,198,88,220,96,243,92,116,126,212,126, +174,190,103,234,136,126,168,190,237,231,20,38,241,38,96,62,97,10,162,60, +163,10,68,244,69,62,26,92,109,92,28,124,105,124,18,156,115,156,22,218, +69,168,104,198,69,172,214,140,132,140,132,76,214,76,215,140,132,110,213,110, +124,244,124,170,228,170,228,238,199,240,194,184,211,216,140,208,203,200,172,204, +173,77,28,206,28,46,74,46,75,196,28,172,75,172,234,34,112,34,112,222, +243,222,134,76,186,136,219,186,208,62,168,150,133,193,70,10,46,72,19,118, +54,244,55,52,216,110,106,110,106,26,216,26,217,110,106,70,217,70,184,164, +205,198,118,194,197,186,160,190,161,26,94,242,94,142,226,142,226,232,199,245, +42,24,79,56,20,92,59,120,30,228,69,150,240,38,102,38,102,226,243,226, +210,68,170,152,131,196,132,78,186,140,219,189,30,206,30,56,70,56,71,198, +30,178,71,178,84,74,151,74,86,164,143,122,118,14,118,222,102,236,91,236, +166,242,166,72,224,72,225,240,166,212,225,212,166,140,225,140,198,16,183,73, +102,92,102,30,38,30,38,92,103,92,14,218,113,194,34,124,35,210,72,92, +73,202,72,140,115,140,152,36,142,148,103,236,188,20,194,122,208,182,237,237, +128,24,44,44,40,190,19,238,80,242,81,36,112,28,114,164,148,218,241,232, +236,148,226,176,176,182,148,174,148,44,222,44,222,114,149,114,182,114,183,45, +62,246,63,12,28,196,28,66,100,66,100,188,83,192,134,244,134,68,228,68, +229,240,134,142,229,142,134,216,229,216,180,14,155,69,62,248,63,12,34,66, +23,130,86,64,103,112,124,244,124,66,226,66,227,244,124,138,227,138,124,216, +227,216,178,14,159,67,26,34,117,34,32,72,111,72,20,110,119,110,70,110, +71,34,134,34,225,34,138,72,221,72,132,112,227,112,178,112,179,34,228,196, +212,230,66,230,52,216,52,142,188,142,188,184,53,184,120,184,121,143,14,66, +97,66,16,160,95,120,58,10,58,232,37,244,118,244,118,66,222,66,223,242, +118,138,223,138,118,216,223,216,168,12,149,67,16,74,89,74,14,156,85,122, +58,12,58,228,29,236,138,16,139,244,184,12,185,244,94,64,139,64,100,118, +139,118,84,176,139,176,238,64,185,64,228,118,185,118,244,174,185,175,18,234, +38,180,39,28,38,138,82,138,83,238,38,96,107,96,78,96,79,8,222,132, +124,132,124,46,220,46,221,132,124,90,221,90,170,10,153,46,176,46,172,108, +139,170,102,184,247,184,182,246,183,153,78,14,23,72,78,76,21,154,58,246, +59,102,138,246,139,12,182,244,183,12,84,62,139,62,90,118,139,118,80,182, +139,182,244,60,183,60,236,118,183,118,246,180,183,181,30,26,63,56,16,88, +53,116,28,226,57,146,134,26,73,38,72,94,143,94,68,148,147,148,110,32, +110,184,71,236,148,34,239,34,152,80,229,80,154,124,229,124,142,172,241,172, +192,242,193,35,34,30,75,58,18,86,61,118,20,232,63,152,214,24,94,42, +94,182,61,240,216,70,132,90,132,236,175,208,170,82,186,178,231,230,228,122, +185,157,24,46,91,46,62,114,63,10,20,108,63,52,94,86,63,56,152,14, +99,64,102,18,159,58,148,66,95,110,110,70,157,110,162,44,233,44,194,114, +195,8,160,94,195,52,232,92,195,54,18,128,241,128,124,110,74,154,23,180, +151,128,238,172,174,152,149,128,160,154,118,160,85,160,56,182,203,182,26,204, +231,204,132,158,132,228,122,240,103,239,34,28,75,58,16,86,55,116,24,234, +69,154,218,20,136,32,87,34,82,86,237,86,158,130,159,30,104,50,131,76, +208,44,183,80,78,140,120,120,159,88,234,138,188,112,161,86,102,244,102,146, +216,146,217,242,102,186,217,186,102,222,217,222,158,222,159,147,44,160,76,116, +76,46,192,46,192,148,167,152,16,98,241,98,110,60,149,80,108,114,147,134, +112,10,95,46,12,232,245,232,58,232,58,172,202,172,203,232,106,232,107,172, +154,232,155,173,26,146,50,102,50,40,108,40,108,140,83,144,12,88,109,88, +66,56,91,72,64,100,89,118,76,12,63,40,126,78,148,56,148,30,198,30, +198,64,239,64,136,86,208,86,168,126,127,144,152,94,192,128,239,142,22,158, +227,158,18,214,64,188,89,158,72,246,72,190,200,190,201,244,72,228,201,229, +28,214,28,30,84,30,85,208,28,84,85,84,28,136,85,136,28,192,85,192, +142,22,122,82,99,114,180,20,206,80,235,108,118,118,208,118,200,220,167,236, +146,118,136,196,93,233,28,210,28,36,98,36,99,202,28,108,99,108,28,182, +99,182,62,182,63,36,118,36,149,84,226,34,197,84,116,110,235,110,114,164, +243,164,172,240,173,9,32,40,59,80,140,38,115,82,32,110,147,110,24,160, +153,160,88,16,84,184,47,240,172,184,173,40,220,12,220,230,189,237,28,34, +53,72,116,36,93,76,20,94,119,94,18,142,119,142,74,12,68,168,25,230, +224,22,138,36,130,174,89,226,122,238,194,176,218,94,144,94,184,188,235,233, +205,26,14,158,243,158,204,26,68,40,69,158,68,94,223,94,160,158,161,94, +140,180,223,237,124,12,159,36,240,46,52,46,52,164,21,228,66,110,237,110, +134,60,116,180,55,240,174,66,205,94,216,136,123,224,162,124,162,228,176,234, +226,230,239,209,114,12,147,36,26,48,227,48,38,126,38,96,214,96,215,124, +76,62,105,88,170,60,153,90,114,112,145,132,22,144,233,144,102,144,84,206, +39,238,148,232,186,226,196,174,95,175,26,46,101,46,30,84,97,84,16,122, +103,122,66,244,67,10,18,200,67,130,98,174,67,140,156,12,183,36,114,46, +239,46,120,120,120,92,230,92,231,122,142,60,159,86,204,58,189,86,166,104, +187,128,108,140,243,140,154,140,146,200,101,234,180,238,206,234,222,176,153,177, +20,238,40,190,40,34,98,34,98,230,73,236,40,92,99,92,40,144,99,144, +120,38,149,86,230,36,201,86,118,110,241,110,114,162,247,162,176,244,177,15, +12,68,85,68,14,152,85,120,56,8,56,226,27,232,114,8,104,182,71,238, +86,84,142,80,142,222,152,228,222,226,241,200,162,74,220,74,220,182,199,188, +188,10,186,140,161,189,28,196,28,48,80,48,81,190,28,168,81,168,150,14, +103,96,192,182,216,172,220,56,127,56,234,206,224,232,176,238,126,234,122,216, +122,102,180,102,180,154,123,155,72,16,23,102,106,186,134,178,136,60,47,60, +156,198,142,224,74,228,50,218,50,104,98,104,98,156,51,156,178,190,179,52, +186,242,218,234,219,17,32,66,19,128,62,8,62,122,52,182,19,232,102,58, +63,106,100,198,59,154,154,8,119,82,190,180,220,168,224,50,135,50,236,204, +216,232,130,232,124,216,124,98,182,98,182,148,125,149,44,14,79,50,16,70, +86,70,54,122,19,150,64,242,65,110,64,132,109,162,106,102,83,144,152,14, +113,88,184,172,216,164,220,56,133,56,238,200,222,228,148,230,132,216,132,98, +180,98,180,148,133,149,98,98,40,98,40,32,100,32,101,98,14,226,111,206, +36,130,37,220,70,98,71,212,70,146,111,146,154,12,115,92,190,182,220,170, +224,52,135,52,238,202,224,230,148,234,128,220,128,98,182,98,182,154,129,155, +32,26,75,56,14,90,53,118,24,236,61,146,126,12,77,106,186,180,214,174, +216,54,105,54,236,198,226,228,174,238,110,228,110,102,168,102,168,156,111,157, +32,192,32,44,82,44,83,184,32,158,83,158,94,34,233,34,96,160,138,118, +179,34,160,202,161,76,184,102,231,154,80,220,241,221,22,244,36,196,36,40, +88,40,88,238,65,242,36,98,89,98,36,150,89,150,106,42,237,42,180,42, +156,108,109,166,186,104,237,160,166,206,167,82,104,224,245,225,14,82,91,82, +16,194,93,164,54,12,55,176,144,12,179,36,98,50,231,50,122,68,147,104, +86,118,245,118,204,66,179,110,116,246,116,154,214,154,215,244,116,222,213,223, +114,108,141,138,98,126,99,16,152,124,153,14,24,40,99,40,34,70,99,70, +20,100,99,100,226,40,153,40,219,68,218,68,153,68,236,100,153,100,18,148, +233,148,20,206,84,178,117,148,130,206,82,236,83,180,234,230,184,216,133,162, +206,166,167,199,32,176,32,34,100,34,101,170,66,66,66,162,52,206,21,240, +80,186,119,228,152,10,183,38,118,52,233,52,136,70,161,102,114,120,243,120, +210,64,183,114,138,248,138,156,220,156,221,240,138,220,221,221,32,250,32,34, +86,34,58,110,76,136,82,170,74,190,53,196,150,12,179,38,100,54,233,54, +90,120,243,120,122,74,149,106,206,68,183,114,118,248,118,158,218,158,219,244, +118,222,219,223,16,32,129,32,32,238,32,74,116,74,117,232,32,170,117,170, +32,208,117,208,60,32,60,118,47,152,84,32,84,116,86,132,94,136,117,130, +142,30,220,30,220,108,152,108,152,206,156,220,200,226,230,216,239,185,62,14, +42,78,15,122,46,244,47,70,62,232,88,170,88,30,208,30,208,172,220,220, +228,228,232,228,243,200,102,70,189,70,144,234,145,70,114,202,114,114,178,114, +178,196,167,201,32,24,69,52,20,86,59,116,30,238,67,152,80,54,241,54, +98,214,98,108,214,108,214,208,193,216,154,246,155,13,30,198,30,44,72,44, +73,188,30,162,73,162,92,38,231,38,158,66,159,10,86,84,245,84,120,112, +121,56,200,112,201,54,110,200,110,124,214,124,215,196,94,238,132,222,154,198, +163,144,174,198,235,235,98,20,58,64,17,94,144,18,184,64,237,92,62,74, +176,74,168,128,141,136,108,74,94,114,35,142,12,230,235,230,58,230,58,158, +190,158,191,230,102,230,103,158,146,230,147,159,17,36,16,36,103,36,16,126, +46,88,63,36,46,216,46,104,94,104,95,208,46,182,95,182,116,28,241,28, +108,148,245,148,176,244,177,28,116,64,147,118,228,60,201,121,16,68,97,68, +18,156,93,118,60,8,60,228,37,236,100,28,233,28,112,70,137,120,224,64, +199,120,88,148,245,148,166,242,167,29,112,8,143,28,20,40,239,40,74,98, +74,66,182,66,182,98,75,98,38,124,186,124,128,154,128,182,97,186,62,190, +29,238,98,202,111,236,148,196,163,232,194,184,227,231,26,18,63,50,14,84, +55,112,18,234,53,146,72,42,165,42,74,78,159,78,118,78,119,6,150,150, +86,150,86,108,150,108,151,150,88,166,107,200,64,222,161,206,144,164,125,206, +224,14,175,84,224,90,173,148,234,150,196,200,147,241,16,44,151,44,26,84, +141,84,84,84,85,8,122,152,48,152,48,112,122,112,123,152,20,222,141,206, +48,166,71,198,116,164,93,204,214,20,153,86,218,86,151,156,234,140,184,204, +129,241,16,42,241,42,90,72,91,12,168,66,169,10,36,72,71,100,18,236, +40,220,50,216,64,216,80,224,102,232,126,236,239,236,18,134,58,134,59,216, +130,58,89,110,78,138,140,122,200,80,113,80,236,134,174,120,109,86,96,148, +213,148,100,172,209,172,86,198,223,198,154,222,155,131,14,72,91,72,58,244, +59,12,14,162,36,126,59,78,88,132,59,100,78,236,98,196,106,154,106,30, +148,30,148,220,127,230,106,90,149,90,106,142,149,142,158,236,174,208,182,156, +182,30,228,30,228,236,207,242,182,88,229,88,182,142,229,143,16,46,93,46, +56,46,34,110,17,140,44,220,44,114,80,114,81,212,44,192,81,192,84,242, +112,174,112,32,152,32,152,226,127,230,112,92,153,92,112,150,153,150,162,240, +186,176,186,30,226,30,226,236,199,244,186,92,227,92,186,150,227,151,72,14, +46,50,23,74,132,40,55,40,96,74,81,40,170,14,137,66,240,40,155,40, +200,72,181,40,40,82,73,108,24,234,44,216,54,210,66,210,80,220,100,230, +120,234,134,236,237,234,18,136,58,136,59,210,130,72,95,110,78,142,124,132, +170,108,196,88,117,88,124,102,158,120,196,134,239,140,96,154,213,154,102,176, +209,176,90,202,225,202,154,224,155,135,16,236,30,206,36,158,36,30,76,30, +76,232,57,234,36,88,77,88,36,144,77,144,92,44,181,44,96,80,171,80, +134,80,135,10,158,148,110,148,110,110,158,110,159,148,94,216,175,202,108,164, +127,198,158,164,143,200,226,20,181,88,226,96,179,154,238,152,206,202,161,239, +16,232,36,202,44,170,46,138,46,28,108,28,108,220,77,228,46,86,107,86, +46,140,109,140,116,238,134,214,144,186,152,154,152,26,218,26,218,226,185,234, +152,84,219,84,152,140,219,141,18,226,32,196,40,152,40,34,70,34,70,214, +51,226,40,92,71,92,40,148,71,148,74,236,90,212,96,190,100,144,100,34, +130,34,130,218,111,230,100,90,131,90,100,146,131,146,186,112,210,108,220,102, +224,90,224,46,162,46,162,146,236,146,234,208,228,222,216,228,191,230,144,184, +217,184,180,66,201,88,192,12,173,47,14,72,91,72,14,146,83,118,54,10, +54,232,34,240,23,224,98,42,229,42,106,72,221,72,94,106,241,106,116,160, +203,160,94,196,231,196,162,246,163,128,160,10,154,72,138,116,112,146,81,168, +180,106,190,126,212,148,241,163,18,50,101,50,16,144,44,108,58,70,63,50, +46,220,46,118,90,118,91,212,46,194,91,194,118,18,151,48,108,62,235,62, +208,14,183,56,94,230,245,230,102,98,135,176,228,100,201,178,150,62,151,230, +186,62,187,231,14,94,95,94,52,12,53,198,14,212,99,188,94,38,241,38, +182,38,160,86,132,126,91,160,164,212,165,82,186,96,241,160,84,226,247,227, +18,52,109,52,62,52,54,88,40,120,19,146,48,228,48,118,92,118,93,216, +48,196,93,196,132,20,132,232,169,208,168,94,133,94,186,14,186,218,190,230, +200,232,226,232,236,224,238,214,241,200,238,72,187,119,44,26,221,26,36,86, +36,52,230,52,231,86,132,110,133,26,54,76,113,76,52,98,113,98,152,74, +211,74,152,98,209,98,24,210,36,194,46,176,50,156,52,124,112,124,112,154, +53,154,58,240,58,182,116,182,117,238,58,220,117,220,168,108,189,126,132,136, +229,136,128,174,233,174,134,206,223,206,180,174,181,244,148,146,165,164,206,146, +193,169,16,72,101,72,16,156,93,120,62,14,62,224,46,238,31,224,122,16, +122,218,161,200,122,92,163,92,180,12,180,224,212,228,228,224,234,214,237,190, +232,66,181,103,12,70,95,70,16,158,89,122,56,10,56,226,38,242,25,228, +80,226,100,200,110,170,114,138,114,56,226,56,215,94,108,240,138,226,166,204, +188,172,208,122,115,122,168,122,169,6,238,236,204,218,166,186,148,158,131,123, +18,122,34,104,44,88,48,72,48,32,114,32,114,72,51,72,114,138,60,138, +60,100,114,100,115,138,134,42,237,42,168,12,193,30,128,86,243,86,146,54, +167,78,212,54,197,80,132,120,237,120,184,154,185,86,40,170,204,170,200,216, +194,226,182,230,157,230,112,170,110,190,98,208,82,220,66,230,37,239,16,34, +109,34,22,76,103,76,12,118,111,118,66,118,67,34,124,32,223,32,130,74, +217,74,122,116,229,116,174,116,175,32,50,138,50,236,119,210,116,168,51,168, +144,132,144,222,150,230,164,234,192,234,216,232,224,226,230,218,232,208,235,204, +212,154,145,187,30,218,30,46,98,46,99,212,30,118,99,118,30,190,99,190, +62,190,63,46,134,14,134,222,169,208,170,92,135,92,188,14,188,212,188,224, +192,226,202,230,216,228,226,228,232,224,238,216,241,204,234,68,189,101,30,192, +30,42,74,42,75,178,30,162,75,162,216,132,112,132,112,42,216,42,217,132, +160,8,143,42,112,88,217,88,166,42,164,94,150,140,121,176,84,188,243,188, +184,244,185,147,18,232,32,208,42,132,42,26,88,26,88,234,63,230,42,82, +89,82,88,140,43,140,222,128,126,128,126,42,222,42,223,128,168,8,153,42, +126,86,223,86,176,44,174,100,160,140,141,164,108,180,245,180,186,242,187,145, +244,48,68,48,68,138,56,190,23,236,124,8,165,36,26,56,49,98,14,154, +69,120,60,238,86,210,102,170,102,94,224,94,215,122,102,144,212,144,190,180, +158,210,101,240,240,236,190,218,148,186,117,144,162,144,163,61,22,228,40,192, +50,136,50,52,214,52,201,90,50,116,198,116,174,158,130,208,63,240,234,232, +164,206,108,158,79,116,130,116,131,9,234,220,40,220,40,36,225,36,62,180, +86,160,104,118,105,36,212,142,208,154,200,162,188,164,170,164,162,160,158,154, +159,37,128,12,159,36,28,238,44,218,62,158,62,48,243,48,24,64,45,104, +16,150,63,134,82,78,239,78,82,156,120,134,162,98,177,78,180,114,243,154, +108,244,108,170,214,170,215,244,108,222,213,222,156,170,157,105,76,16,44,84, +17,124,52,246,53,68,68,190,86,158,98,112,98,40,144,40,144,104,99,104, +102,238,102,152,148,152,149,230,102,212,149,212,186,14,209,42,162,52,243,52, +172,74,187,110,156,126,251,126,224,68,203,126,162,180,243,180,200,246,201,127, +24,230,42,204,56,146,56,28,218,28,218,80,57,80,144,200,94,226,95,98, +146,146,95,146,234,208,228,226,222,234,200,236,180,236,170,230,166,222,167,98, +232,130,167,165,22,112,42,78,42,32,108,32,108,60,43,60,110,112,56,112, +56,86,110,86,111,112,164,14,187,30,128,40,237,40,122,76,241,76,152,54, +167,76,210,50,193,76,134,102,233,102,184,126,185,76,124,116,145,132,20,138, +245,138,56,160,209,160,56,182,209,182,66,242,66,202,200,202,201,240,66,228, +201,229,70,8,27,74,130,38,51,38,92,74,71,38,164,10,133,60,242,38, +147,38,198,70,177,38,120,70,145,86,22,218,40,198,56,160,56,92,204,92, +204,126,57,126,60,248,60,158,220,158,220,224,218,232,214,238,208,240,191,240, +60,196,221,196,114,236,115,158,164,234,165,159,78,14,48,84,17,128,58,248, +59,62,144,14,175,40,72,210,98,168,106,116,106,50,222,50,222,94,107,94, +112,246,112,132,230,132,230,226,228,232,224,236,203,240,112,176,231,176,152,224, +153,132,188,224,189,133,28,232,58,200,74,154,75,20,224,82,75,82,170,240, +170,140,75,140,154,82,155,13,14,194,71,178,52,238,70,236,78,232,84,226, +88,218,90,136,32,136,37,52,14,32,82,32,79,136,158,8,183,34,100,186, +116,162,126,132,126,46,220,46,220,92,127,92,128,244,128,132,228,132,228,216, +226,228,224,232,216,236,203,236,128,174,229,174,162,224,163,132,192,220,193,133, +12,32,119,32,110,102,26,102,26,66,110,66,111,102,54,102,55,32,80,102, +81,32,26,132,111,132,10,160,123,160,44,178,13,222,90,180,109,208,42,236, +54,234,60,234,66,230,70,222,71,160,104,240,122,214,138,158,138,32,212,32, +212,186,216,204,218,220,224,232,228,234,234,234,238,226,245,204,192,74,172,150, +147,200,150,84,182,146,199,193,34,18,75,48,18,84,63,110,26,228,71,146, +82,20,237,20,222,104,98,104,98,54,222,54,223,104,140,104,141,20,180,104, +181,20,102,134,219,134,82,166,241,166,126,186,81,230,190,188,235,226,136,234, +148,232,154,230,160,226,162,222,163,167,10,30,125,30,110,96,26,96,26,60, +112,60,113,96,52,30,53,96,80,30,81,96,22,128,113,128,10,154,127,154, +48,176,19,218,94,174,113,202,46,230,56,230,62,230,72,224,73,154,224,22, +182,34,142,40,142,164,132,202,111,234,192,186,211,222,200,202,174,220,175,36, +202,28,202,68,210,152,226,198,243,223,20,28,235,28,208,106,50,106,50,62, +208,62,209,106,102,106,103,28,154,106,155,28,54,140,207,140,18,172,239,172, +84,194,31,232,170,194,227,228,100,242,118,242,130,234,131,173,52,8,52,234, +23,222,18,70,81,70,14,148,73,122,80,28,105,66,164,26,141,68,110,126, +97,172,136,126,149,172,124,208,125,10,88,234,88,94,160,94,160,218,141,218, +198,8,184,72,169,112,244,68,187,68,182,122,194,168,210,202,239,232,158,238, +186,212,208,166,220,116,223,69,28,20,53,44,122,18,99,42,32,136,32,60, +122,60,122,124,111,124,78,130,79,8,62,76,45,110,88,78,107,104,170,10, +152,52,137,76,230,50,155,50,134,132,160,120,188,94,203,50,228,136,186,112, +157,72,56,246,56,148,188,148,189,244,56,176,189,176,56,202,189,202,56,228, +189,229,20,68,97,68,20,152,95,118,68,10,68,232,35,222,130,14,157,52, +112,68,239,68,214,12,181,62,104,134,243,134,148,68,148,150,136,198,105,236, +200,240,201,69,14,94,125,94,40,94,41,28,78,94,79,8,78,52,119,52, +76,178,77,110,48,130,21,184,118,130,98,178,68,212,21,236,124,28,245,28, +142,180,142,70,222,70,223,176,168,70,179,28,106,234,144,218,170,192,180,158, +185,98,188,192,241,235,104,18,62,56,19,78,146,18,184,52,237,78,68,70, +186,70,184,92,178,102,168,110,145,110,108,70,104,84,98,96,82,106,54,118, +33,124,66,200,66,132,194,132,195,200,26,236,68,230,98,218,118,198,133,154, +142,200,227,237,180,100,74,100,74,32,180,32,181,100,38,240,38,142,106,142, +107,238,38,214,107,214,148,240,148,140,222,140,223,236,148,214,223,215,12,28, +109,28,14,208,105,176,86,246,87,28,34,28,35,200,34,84,85,84,34,142, +85,142,218,110,126,110,126,40,218,40,219,110,126,76,219,76,172,110,173,8, +104,142,243,142,144,142,136,174,220,174,216,216,212,226,206,232,198,234,163,239, +12,156,247,156,208,20,142,28,70,30,71,156,218,84,71,84,166,156,167,84, +100,180,68,212,31,241,14,84,95,84,16,198,97,172,56,12,57,182,104,28, +231,28,112,62,141,122,220,58,189,126,96,150,245,150,170,242,171,29,18,46, +239,46,94,78,95,8,162,78,163,8,34,98,219,98,54,122,93,162,160,164, +203,118,14,184,243,184,128,246,129,99,16,48,237,48,94,80,95,12,160,80, +161,12,40,84,83,112,24,120,69,146,24,236,69,170,94,98,227,98,108,124, +131,164,210,122,185,166,84,184,241,184,160,246,161,99,32,26,219,26,14,148, +241,148,128,246,129,26,48,60,93,118,202,58,159,123,78,14,48,56,21,86, +62,134,63,38,214,18,146,32,97,34,82,74,243,74,96,116,223,116,158,116, +159,30,32,240,68,222,92,188,92,150,176,150,176,214,176,222,180,228,186,230, +222,228,228,224,232,218,239,201,30,22,59,50,108,16,83,66,18,72,125,72, +10,142,131,142,54,72,54,158,42,202,21,240,94,244,95,72,118,36,235,36, +150,36,138,226,181,194,160,120,187,162,146,86,204,86,198,216,200,226,204,230, +214,232,226,230,232,226,237,209,28,14,75,50,10,92,56,92,54,228,101,182, +96,24,233,24,86,148,245,148,100,62,137,118,224,62,189,124,166,246,167,25, +52,64,218,64,218,26,50,26,50,148,40,190,19,224,98,78,129,102,198,78, +173,110,72,118,237,118,64,166,247,166,120,118,120,174,108,208,90,228,77,238, +184,242,185,119,14,88,95,88,14,194,95,168,54,14,55,180,214,94,224,58, +114,58,114,144,102,192,73,230,114,124,208,124,188,178,142,222,105,242,130,124, +156,182,198,218,239,236,166,8,167,125,36,26,77,56,16,86,59,118,26,230, +71,148,114,24,92,82,241,82,154,8,144,98,112,166,75,210,234,232,180,202, +144,152,134,124,206,124,186,176,146,214,97,240,186,24,219,59,108,88,116,60, +36,60,36,154,30,196,19,220,36,118,108,118,90,170,47,226,116,208,57,140, +76,118,77,14,120,30,239,30,138,188,138,78,218,78,219,184,164,78,179,30, +180,104,176,164,160,204,111,236,186,194,241,233,50,22,87,46,32,60,71,78, +42,140,83,90,206,66,216,42,112,42,112,96,89,138,112,82,204,82,162,124, +129,140,132,82,150,106,184,128,225,138,166,12,167,82,16,164,239,164,118,142, +82,194,213,236,172,164,144,200,96,226,41,237,10,44,103,44,56,44,38,102, +15,138,40,216,40,108,88,108,89,200,40,186,89,186,220,90,230,56,124,56, +124,148,108,198,85,226,118,240,182,196,212,136,216,118,125,118,238,232,180,196, +154,152,141,118,174,118,175,7,32,216,32,60,82,60,83,204,56,14,45,60, +32,122,83,122,32,182,83,182,218,132,118,132,118,44,218,44,219,132,158,10, +143,44,118,88,219,88,168,44,162,144,126,208,81,240,172,146,172,216,174,226, +176,232,182,232,188,236,224,232,232,226,234,220,237,212,210,148,188,194,233,184, +222,168,241,197,22,224,38,212,52,204,70,204,84,214,110,224,150,228,202,226, +243,224,14,108,60,108,61,204,34,30,73,68,206,176,106,176,106,60,208,60, +209,176,152,16,139,60,106,114,209,115,26,40,47,76,110,38,91,76,18,100, +111,100,68,246,69,10,20,186,69,122,106,156,69,116,133,244,132,244,132,68, +226,68,227,242,132,138,227,138,132,214,227,214,178,12,163,69,68,16,95,40, +26,54,145,54,48,72,69,102,12,118,155,118,120,70,99,110,46,238,46,154, +126,154,127,232,46,212,127,212,176,180,177,40,222,12,222,236,199,225,18,68, +129,68,14,158,127,118,76,12,76,234,59,226,174,14,175,248,238,146,175,97, +70,14,46,56,17,90,100,60,45,60,28,100,97,100,16,150,103,150,60,100, +60,226,101,196,196,20,225,44,116,62,245,62,124,244,124,100,226,100,226,238, +207,232,176,234,177,10,124,144,227,144,124,184,227,185,88,14,48,86,21,120, +68,244,69,54,162,244,163,8,238,152,181,87,16,42,241,42,90,70,91,12, +162,70,163,10,18,94,239,94,186,60,209,80,52,244,52,124,204,124,204,236, +195,226,126,240,127,66,52,158,205,158,52,194,205,195,22,42,241,42,98,64, +99,12,160,64,161,8,72,60,50,96,27,116,188,236,220,226,220,80,61,80, +48,112,193,112,60,230,60,138,178,138,178,212,164,220,153,222,118,230,119,92, +148,92,167,102,60,166,179,166,60,194,179,195,16,40,235,40,88,70,89,12, +162,68,163,10,110,60,139,80,36,92,217,92,16,142,241,142,78,108,105,142, +176,106,151,142,60,242,60,172,196,172,197,242,60,222,197,223,20,46,241,46, +94,74,95,10,162,68,163,10,184,68,211,86,34,74,67,98,22,122,55,140, +28,238,63,168,78,98,237,98,96,244,96,126,210,126,210,236,199,228,152,238, +153,72,96,160,211,160,96,190,211,191,16,82,89,82,12,190,91,170,54,12, +55,178,188,20,223,48,86,60,245,60,106,242,106,98,220,98,220,238,197,232, +160,230,161,14,106,138,221,138,106,178,221,179,20,76,137,76,78,242,79,10, +16,182,79,94,124,146,79,96,168,244,169,10,182,80,243,141,34,244,34,28, +218,28,219,240,34,222,219,222,48,72,203,72,76,202,76,100,178,100,178,198, +163,192,152,42,179,60,126,200,127,40,76,132,179,132,76,160,179,161,72,14, +99,40,30,50,227,50,176,12,153,50,16,122,241,122,106,122,107,50,152,122, +153,50,52,70,77,100,206,68,181,104,66,242,66,154,192,154,193,242,66,224, +193,224,66,190,193,191,30,30,69,56,16,92,61,120,24,232,73,152,80,58, +243,58,188,20,217,44,102,246,102,98,218,98,218,238,203,232,160,234,161,10, +102,140,219,140,102,182,219,183,34,26,69,62,16,102,58,102,56,224,93,190, +114,12,143,40,86,50,239,50,204,10,177,50,78,120,245,120,142,120,143,50, +180,120,181,50,114,246,114,150,210,150,211,246,114,188,211,188,114,226,211,226, +94,70,121,104,220,66,199,105,26,212,26,38,72,38,73,204,26,110,73,110, +26,182,73,182,208,78,108,78,108,26,208,26,209,78,108,50,209,50,90,108, +225,108,84,136,237,136,134,136,135,86,178,136,179,84,90,178,135,136,234,178, +181,136,118,172,139,186,158,148,158,242,143,236,92,218,159,196,198,174,159,200, +220,224,165,197,30,22,67,50,14,88,51,112,22,226,61,148,210,76,94,76, +94,26,210,26,211,76,94,52,211,52,80,108,223,108,70,134,237,134,126,134, +127,84,180,134,181,84,70,184,110,160,131,134,238,176,196,160,173,134,152,150, +152,240,139,234,108,176,133,186,80,220,137,200,218,226,184,206,153,194,194,170, +163,197,20,52,141,52,14,162,147,162,50,162,51,10,112,162,113,10,50,88, +113,88,50,124,113,124,24,230,67,182,90,182,123,212,127,236,198,230,228,222, +228,24,164,24,164,156,150,202,127,236,164,82,229,82,164,138,229,139,20,52, +139,52,14,164,143,164,50,164,51,10,110,164,111,10,50,90,111,90,50,126, +111,126,20,234,63,184,90,184,123,212,178,12,154,80,133,116,218,108,230,68, +159,68,180,98,176,142,160,194,130,226,109,240,242,234,202,198,177,143,64,244, +65,12,18,72,99,72,16,174,65,86,98,136,65,102,94,30,247,30,114,244, +114,84,228,84,229,238,114,210,229,210,152,30,152,128,133,176,184,30,184,156, +229,157,190,18,213,38,230,52,40,52,40,172,17,238,54,140,155,140,98,140, +99,72,98,104,145,104,102,140,102,226,85,222,78,158,57,198,124,160,149,196, +216,96,180,190,141,232,162,6,166,122,192,204,226,240,237,219,32,38,225,38, +20,102,239,102,50,136,198,136,198,70,51,70,128,136,129,14,16,168,241,168, +124,142,74,196,221,232,174,168,140,206,92,228,37,237,18,138,237,88,110,18, +110,212,110,220,116,228,126,230,196,230,208,226,212,220,218,210,223,197,26,38, +65,76,18,204,63,126,74,40,233,40,66,102,243,102,82,134,204,134,204,74, +83,74,83,74,146,134,147,10,66,168,239,168,142,142,110,194,227,236,190,168, +144,216,69,241,36,22,71,54,18,86,57,114,26,230,63,146,86,44,235,44, +154,92,155,10,80,104,155,48,222,98,155,50,156,98,118,136,81,156,234,158, +178,134,151,106,156,136,156,238,139,232,108,160,135,182,86,216,157,190,198,162, +157,188,218,224,165,183,52,22,89,46,28,58,67,80,32,132,97,92,98,72, +227,52,150,10,150,116,214,116,229,88,18,156,237,156,128,246,129,118,28,230, +96,188,129,156,230,226,160,190,129,157,44,18,79,54,24,76,63,106,26,224, +73,134,80,80,153,72,112,14,112,184,153,138,148,42,226,42,212,230,193,222, +178,42,172,162,125,237,28,56,229,56,16,180,243,180,80,180,81,10,176,180, +177,10,80,136,177,136,80,94,177,94,106,196,33,238,152,194,227,233,20,74, +97,74,60,244,61,12,16,170,61,96,94,136,61,98,102,56,241,56,90,176, +247,176,134,176,135,14,204,176,205,14,134,96,205,96,134,136,205,136,148,192, +97,234,184,192,233,235,26,46,219,46,122,12,114,58,78,92,35,100,200,100, +115,60,12,122,241,122,188,122,188,238,169,228,132,206,58,206,58,156,132,156, +133,207,10,200,119,168,34,58,35,192,70,16,71,182,70,88,111,88,104,60, +239,60,112,120,210,120,190,170,154,208,120,224,89,236,136,120,140,144,152,170, +178,200,212,220,237,230,168,120,169,11,26,208,26,50,100,50,101,208,26,120, +101,120,26,184,101,184,66,184,67,50,126,62,227,62,118,118,237,118,176,118, +177,14,128,172,227,172,106,226,243,226,176,226,177,131,92,70,93,218,28,70, +28,198,93,196,58,16,59,196,108,46,231,46,172,12,164,62,144,84,119,96, +212,94,165,62,104,112,241,112,170,196,128,196,128,148,170,148,171,196,210,112, +210,238,187,231,58,234,84,220,84,32,34,32,34,178,15,234,34,88,85,88, +34,142,85,142,146,10,179,36,100,52,241,52,124,52,138,74,186,114,239,132, +202,52,182,88,144,120,101,138,142,136,140,200,109,242,196,242,197,139,104,12, +143,40,20,52,229,52,16,138,96,122,187,52,236,136,130,114,61,52,88,138, +84,194,66,224,41,240,168,242,169,141,48,14,77,48,16,66,103,66,50,66, +50,126,36,198,19,234,50,116,94,116,88,224,69,224,146,8,124,56,107,80, +240,42,133,42,116,88,237,88,108,184,243,184,154,200,105,244,186,200,235,238, +142,184,143,58,204,184,205,60,142,120,205,120,142,152,205,153,44,16,79,54, +16,78,88,78,66,116,21,160,62,246,63,120,102,158,65,118,228,22,174,36, +130,38,130,162,91,244,130,104,247,104,198,246,199,105,60,14,101,46,26,70, +108,70,70,122,25,158,78,240,79,114,122,154,79,114,154,240,154,36,222,36, +194,108,212,124,226,140,234,160,230,180,220,194,187,201,12,32,84,32,79,128, +40,50,36,136,96,136,90,234,69,228,14,194,77,176,112,48,233,48,174,10, +164,64,144,90,119,106,216,98,167,58,110,120,245,120,212,120,212,236,191,228, +176,196,134,196,134,152,176,152,177,197,30,58,125,58,22,100,133,100,80,100, +81,6,52,138,23,232,38,178,56,196,94,218,168,226,243,224,86,116,87,212, +128,154,87,154,128,36,216,36,216,96,150,96,150,170,158,182,204,184,222,176, +229,153,50,24,50,72,208,72,209,22,128,10,129,72,38,110,198,110,198,162, +50,162,50,206,50,222,60,228,82,232,196,232,212,226,222,214,231,199,96,14, +54,82,25,114,234,58,71,58,60,110,180,110,100,172,72,204,70,226,104,236, +206,232,230,216,237,193,130,14,96,62,50,102,15,122,234,122,190,98,152,64, +123,24,16,228,231,228,74,228,75,116,132,228,133,86,132,146,195,147,110,14, +163,38,74,110,216,110,216,56,72,56,72,152,48,212,31,232,100,246,100,154, +222,154,223,242,100,222,223,223,20,44,125,44,26,76,121,76,16,108,129,108, +76,142,77,12,134,36,220,36,208,128,187,124,170,36,160,96,127,132,20,166, +233,166,124,140,116,182,72,222,21,238,130,166,146,194,180,218,235,235,20,44, +105,44,62,44,48,104,21,144,48,224,48,112,88,112,89,218,48,190,89,190, +96,86,165,80,126,12,126,188,163,148,158,44,230,44,224,234,203,228,188,44, +188,150,170,204,141,241,106,74,48,74,48,26,108,26,109,74,208,72,150,72, +150,26,208,26,209,72,164,88,193,102,16,114,233,114,126,82,118,122,82,142, +15,152,130,114,156,134,241,158,46,238,46,162,106,162,107,236,46,216,107,216, +144,236,144,164,206,164,207,234,144,216,207,217,80,10,50,62,23,94,226,42, +63,42,70,80,213,80,38,120,188,120,188,188,204,222,228,238,241,211,28,34, +69,68,18,230,36,218,52,210,68,210,84,216,110,228,148,232,239,230,14,112, +58,112,59,210,126,14,112,58,89,94,228,56,115,56,108,100,186,100,134,146, +112,172,110,184,118,192,140,196,188,196,212,188,218,174,221,163,102,12,141,38, +24,50,233,50,112,60,54,118,191,104,160,72,209,122,14,162,243,162,90,128, +90,178,78,204,56,224,25,242,168,244,169,123,32,32,73,58,14,90,55,116, +28,232,75,152,130,16,108,62,85,94,230,48,117,48,114,86,215,86,96,126, +188,126,188,180,200,212,226,238,241,207,34,30,75,58,16,94,57,120,26,238, +67,152,138,18,169,54,88,72,235,72,108,110,143,200,76,226,243,226,170,226, +211,103,38,24,79,58,12,98,62,98,62,170,54,230,99,182,152,14,124,62, +93,98,240,56,131,56,114,110,204,110,158,154,134,184,122,210,132,232,192,234, +230,224,237,197,60,10,60,236,35,230,12,68,95,68,14,156,89,120,150,10, +124,66,99,100,180,98,218,44,135,44,154,110,108,126,109,244,182,126,224,126, +225,244,108,216,225,216,154,170,109,170,184,168,225,169,52,244,53,12,30,62, +15,122,74,58,91,92,158,12,126,80,83,120,156,20,180,66,239,114,114,114, +207,114,108,244,108,158,204,158,205,244,108,224,205,225,34,24,77,56,16,86, +57,118,28,232,69,152,158,8,126,66,77,108,156,14,182,60,237,102,110,110, +209,110,108,248,108,154,204,154,205,244,108,220,205,221,30,42,225,42,128,10, +104,60,53,86,114,44,193,84,30,136,30,96,224,96,225,134,88,118,43,172, +200,150,63,150,30,190,225,190,132,246,133,113,14,72,105,72,14,162,95,120, +66,12,66,236,45,228,218,22,158,38,113,42,102,122,243,122,172,244,173,37, +72,16,25,94,114,56,49,56,38,102,109,102,26,154,117,154,68,102,68,228, +113,196,226,28,162,44,123,46,112,130,245,130,178,244,179,41,68,14,38,72, +19,96,104,62,45,62,30,104,99,104,16,150,109,150,62,104,62,228,103,196, +110,134,132,106,140,74,140,36,198,36,198,116,243,116,132,244,132,150,208,150, +209,242,132,222,209,223,202,18,142,34,45,44,18,122,237,122,128,242,129,37, +26,30,69,64,20,226,36,214,48,206,70,208,96,224,134,230,239,226,14,108, +58,108,59,206,212,28,168,36,93,44,82,112,233,112,156,210,157,39,72,12, +27,76,124,44,51,44,90,78,71,44,168,10,137,60,236,44,147,44,200,78, +177,44,128,70,78,110,21,134,118,78,164,112,239,134,68,130,185,130,64,158, +87,198,116,150,133,186,28,226,225,226,180,152,137,227,82,14,52,74,19,118, +62,242,63,56,228,24,174,38,101,44,92,120,247,120,170,244,171,41,26,22, +61,54,10,94,48,94,44,212,81,166,106,12,135,40,80,50,235,50,200,10, +173,50,78,120,245,120,96,82,216,82,216,158,99,158,136,242,137,50,176,242, +177,50,76,226,112,192,137,160,238,226,206,198,177,159,16,48,131,48,112,150, +38,150,38,82,112,82,113,150,38,116,113,116,76,82,77,14,10,188,133,188, +76,248,77,150,166,12,152,58,127,106,240,58,153,58,144,104,208,104,162,176, +148,210,150,226,162,232,198,236,224,230,232,218,235,205,110,98,26,98,26,30, +110,30,111,98,38,52,55,78,94,50,81,78,22,134,117,134,13,166,10,168, +123,164,68,164,69,30,38,190,19,232,58,190,67,226,82,184,97,220,108,180, +127,214,178,8,154,74,123,116,238,106,210,80,177,18,166,94,195,126,134,152, +222,152,202,200,173,243,68,12,46,54,17,90,108,58,45,58,30,104,103,104, +16,152,107,152,66,104,66,228,109,198,114,92,227,70,116,144,235,116,122,228, +166,208,227,148,184,20,215,46,156,10,160,94,172,162,200,218,224,234,232,230, +239,203,70,14,46,60,19,92,106,60,49,60,32,102,101,102,18,152,109,152, +62,102,62,232,105,202,110,78,247,78,138,242,139,14,214,236,215,12,138,142, +215,142,138,210,215,211,76,14,109,44,16,56,241,56,182,10,155,56,48,244, +48,92,114,92,114,232,89,232,48,132,115,132,48,170,115,170,162,190,163,104, +206,78,206,240,183,233,36,18,73,50,16,78,53,110,28,228,63,138,84,40, +149,40,76,76,153,76,118,6,110,92,77,132,142,118,113,82,170,40,233,40, +172,74,239,74,194,6,190,82,176,104,155,130,236,132,208,108,193,78,108,246, +108,144,204,144,205,244,108,184,205,184,108,226,205,227,32,30,67,74,18,228, +34,212,48,206,64,208,78,218,104,228,130,232,237,232,12,114,54,114,55,206, +204,66,100,66,100,40,202,40,203,66,74,94,235,94,150,94,151,12,104,144, +200,144,200,116,104,116,104,202,204,202,204,170,105,171,34,20,81,48,16,84, +61,112,24,230,65,146,82,92,223,66,168,18,201,48,78,146,231,116,86,230, +142,208,215,144,140,6,140,70,144,126,156,168,176,210,198,234,212,238,224,236, +228,226,237,211,30,22,63,64,10,100,48,100,46,220,77,190,84,34,113,74, +76,234,86,220,94,214,104,212,116,216,126,222,146,226,172,230,241,230,68,118, +102,118,103,210,218,70,136,70,136,38,218,38,219,70,116,96,241,96,176,96, +177,8,142,146,214,146,214,118,142,118,142,202,220,202,220,170,143,171,26,46, +133,46,78,14,40,98,127,98,20,144,123,132,86,170,87,62,222,26,154,36, +154,78,148,120,129,158,238,84,155,84,200,170,201,84,48,194,207,194,16,232, +239,232,128,232,129,167,50,20,50,58,220,58,221,16,132,58,133,8,14,118, +141,118,48,240,49,86,112,234,113,80,48,162,113,162,48,212,113,212,174,76, +160,120,141,154,218,146,228,116,163,116,182,142,180,182,158,218,133,238,238,234, +214,218,192,188,183,163,98,14,72,72,31,124,190,104,212,60,79,60,132,88, +118,156,90,196,64,214,31,232,224,228,180,200,148,160,127,119,36,12,65,38, +16,50,143,50,16,118,149,118,26,84,126,84,126,152,25,152,58,242,59,50, +94,242,95,50,16,218,59,160,130,194,95,162,116,10,91,50,182,10,168,50, +145,100,208,100,228,68,161,68,176,98,170,160,148,208,117,238,238,232,202,198, +175,135,20,72,99,72,64,246,65,12,16,162,65,88,94,144,65,110,162,8, +128,72,95,110,236,104,188,66,157,18,160,176,180,174,194,160,196,110,126,110, +126,206,128,220,134,228,146,232,196,230,208,224,216,212,223,199,32,204,32,52, +78,52,79,194,32,170,79,170,160,14,126,78,93,114,238,114,208,96,182,68, +155,26,156,182,188,174,196,114,124,114,124,216,134,234,204,234,225,207,17,240, +66,236,92,238,94,224,94,34,36,34,36,168,19,242,36,90,95,90,36,144, +95,144,160,12,185,40,122,90,122,52,228,52,229,88,160,88,125,138,188,88, +227,132,124,158,229,158,112,226,245,226,176,226,177,159,70,20,103,48,32,58, +223,58,176,18,147,58,48,98,203,98,20,138,233,138,126,58,114,152,82,200, +21,238,144,138,144,226,156,232,216,232,237,199,16,84,87,84,16,194,87,170, +52,14,53,180,92,46,235,46,78,108,243,108,160,108,161,10,108,62,137,90, +212,60,189,94,104,246,104,138,220,138,221,244,104,224,221,224,182,194,138,194, +138,164,182,164,183,195,22,40,235,40,92,64,93,14,168,62,169,12,38,80, +217,80,16,124,241,124,128,124,129,54,68,90,95,112,186,92,161,118,54,244, +54,150,202,150,203,246,54,226,203,226,158,202,94,202,94,174,158,174,159,203, +18,28,78,28,78,86,28,86,24,138,76,138,70,214,52,228,31,216,204,70, +122,70,122,24,204,24,205,70,216,158,110,158,110,108,216,108,217,158,97,224, +204,180,233,232,96,224,223,212,164,216,165,83,60,18,60,238,40,242,29,228, +16,74,99,74,16,162,93,130,154,10,126,74,93,114,236,110,182,66,151,20, +158,178,190,172,194,112,124,112,124,214,130,230,202,230,221,203,58,246,59,10, +18,70,89,70,16,164,59,92,82,114,59,92,216,16,174,24,105,30,216,50, +107,56,228,72,99,80,154,26,154,92,162,104,224,104,239,84,138,118,118,124, +81,132,80,156,145,152,74,184,149,178,112,126,112,228,151,208,232,118,216,124, +159,134,158,158,231,154,156,188,241,180,190,130,190,226,202,232,232,230,245,207, +56,14,42,48,15,90,86,62,35,62,26,102,75,102,14,140,85,140,52,102, +52,224,81,196,146,24,118,34,87,40,118,34,119,244,84,92,147,92,80,180, +119,112,148,152,119,118,166,70,153,126,232,68,213,126,195,14,192,14,192,100, +182,166,164,202,141,236,238,236,214,202,187,137,62,12,89,38,12,50,137,50, +108,108,44,108,44,78,108,78,109,108,28,238,28,134,122,134,122,212,106,230, +93,222,90,198,56,198,56,162,92,162,93,198,134,106,214,106,206,140,194,172, +176,202,133,238,148,106,156,140,168,176,196,208,237,236,174,106,175,8,174,58, +235,59,62,246,63,12,36,68,23,122,80,64,99,102,114,28,143,64,232,26, +203,64,126,244,126,90,224,90,224,222,212,240,191,230,176,90,177,10,126,130, +225,130,126,174,225,175,16,76,91,76,60,242,61,10,18,164,44,128,61,92, +96,130,61,98,220,14,182,24,115,30,118,76,239,76,168,26,156,88,136,120, +99,150,180,76,192,102,214,124,243,142,146,140,144,184,134,212,111,240,200,240, +201,139,34,226,34,38,80,38,81,218,34,94,81,94,34,148,81,148,34,202, +81,202,138,14,114,72,93,102,120,192,121,60,164,16,193,44,232,60,129,60, +224,98,129,98,222,138,127,138,238,176,129,176,116,200,91,242,142,202,151,240, +176,202,187,234,206,192,233,238,174,60,175,177,204,18,148,28,45,32,22,78, +233,78,124,30,102,94,70,124,21,148,148,78,160,100,190,126,235,146,94,126, +90,176,80,206,45,240,168,246,169,131,74,14,46,78,19,122,54,240,55,62, +208,18,164,28,103,32,84,78,241,78,158,28,154,78,128,118,81,146,240,138, +200,122,180,102,161,78,134,138,130,202,97,238,190,240,191,135,18,44,103,44, +18,194,111,174,66,44,67,182,112,36,243,36,148,36,140,116,222,116,212,214, +198,230,147,233,14,44,121,44,46,12,46,76,98,76,99,10,108,152,32,152, +32,110,110,110,111,152,12,186,125,186,72,246,73,76,134,32,159,64,212,64, +237,28,142,244,142,88,228,88,228,232,218,238,199,226,184,88,185,10,142,134, +229,134,142,180,229,181,12,72,85,72,14,154,81,112,54,12,54,230,42,238, +23,224,212,16,170,26,99,32,214,50,101,56,226,72,93,82,236,84,226,100, +204,106,162,108,154,96,155,28,138,118,122,124,81,134,78,156,143,152,76,184, +145,180,114,126,114,232,153,206,228,120,208,126,149,132,156,160,229,156,152,186, +237,182,188,130,188,224,198,234,222,234,232,226,239,205,16,56,103,40,20,122, +60,100,105,62,44,12,52,58,74,98,98,118,108,118,119,98,16,142,117,142, +56,142,54,168,48,196,36,220,19,238,88,142,88,204,90,222,104,228,120,230, +202,230,224,222,236,212,241,196,122,28,162,28,162,182,150,198,133,186,128,62, +145,98,124,156,163,116,178,28,218,28,218,172,216,188,206,194,189,180,184,60, +201,96,178,144,219,109,98,68,99,218,28,66,28,198,99,190,62,12,63,192, +120,32,151,70,236,26,205,72,132,248,132,94,228,94,228,240,208,244,197,232, +178,94,179,8,132,184,229,184,132,138,229,139,78,16,48,84,17,130,58,244, +59,64,100,36,133,70,224,28,191,74,112,244,112,96,216,96,216,236,198,242, +181,226,162,96,163,12,112,140,217,140,112,182,217,183,118,16,155,34,40,78, +40,44,224,44,225,78,112,64,76,84,33,102,148,64,227,100,28,126,115,126, +24,218,127,198,72,126,73,208,122,118,239,118,156,118,148,166,222,166,216,214, +194,232,151,235,10,84,113,76,60,12,60,190,117,158,112,46,226,46,222,224, +202,232,181,220,158,46,156,122,140,176,79,235,16,48,241,48,98,84,99,12, +166,84,167,10,28,116,118,116,114,230,92,236,77,224,74,86,70,166,54,206, +27,240,158,236,158,110,218,110,219,234,158,206,219,207,14,220,243,220,70,220, +70,34,188,34,189,220,70,98,189,98,70,160,189,161,60,248,61,16,36,70, +23,124,78,66,99,104,104,64,225,64,92,126,241,126,162,126,163,12,162,134, +102,224,217,212,184,172,233,235,112,12,145,34,36,88,36,44,226,44,227,84, +110,64,55,98,148,64,203,98,22,146,117,136,66,110,66,224,117,184,126,120, +222,120,208,236,198,240,171,222,162,120,156,176,134,214,97,241,74,16,48,62, +21,92,112,62,51,62,34,104,103,104,20,154,113,154,66,104,66,232,109,194, +160,14,144,80,119,124,214,112,232,74,147,74,170,104,162,170,142,210,103,242, +240,236,208,212,184,180,167,141,72,12,40,82,13,120,52,244,53,60,98,24, +204,24,204,90,99,90,108,56,205,56,88,152,88,120,224,120,225,152,104,154, +190,154,164,194,132,216,79,236,236,232,190,220,148,194,119,155,104,10,143,38, +40,50,219,50,74,64,105,100,20,110,239,110,178,62,153,110,40,154,219,154, +86,182,31,230,170,182,225,228,130,110,130,240,114,244,95,231,30,42,227,42, +40,74,217,74,18,106,239,106,130,10,112,80,90,120,60,144,21,164,162,106, +178,124,206,144,239,160,172,134,124,140,81,142,48,174,213,174,128,244,129,140, +36,230,68,218,102,196,125,174,148,188,219,231,24,26,113,26,30,62,109,62, +18,100,103,100,70,26,71,100,134,26,229,26,138,60,225,60,140,98,237,98, +178,98,179,26,124,96,92,134,60,156,19,172,120,102,146,130,186,156,239,172, +112,140,137,164,52,180,170,180,117,239,16,48,155,48,60,12,60,74,116,74, +117,14,134,132,42,132,42,100,134,100,135,132,28,160,147,160,34,186,141,186, +24,226,143,212,88,74,89,216,148,84,230,82,222,230,208,238,187,222,180,12, +180,126,170,182,143,241,18,48,237,48,96,8,97,82,164,80,165,10,206,86, +138,96,60,100,62,170,56,200,31,238,234,144,63,144,170,144,171,241,16,70, +85,70,14,152,83,122,58,14,58,236,40,244,27,230,156,12,118,60,81,90, +152,18,186,52,239,82,146,56,167,70,114,80,213,80,108,96,108,142,212,142, +213,94,184,92,152,116,125,130,130,98,160,112,189,130,96,246,96,168,224,168, +224,220,220,234,193,238,158,148,124,210,187,200,174,182,197,213,132,10,90,52, +21,88,126,16,170,54,239,82,116,50,149,70,66,78,191,78,62,96,62,140, +200,140,201,94,172,88,122,114,85,126,88,90,140,110,181,130,48,246,48,170, +212,170,212,238,200,242,177,230,128,148,86,212,169,200,154,182,183,219,116,12, +153,36,36,86,36,48,226,48,227,86,70,246,71,64,34,102,51,138,20,190, +71,166,110,76,196,76,196,128,111,128,114,102,197,102,96,180,96,152,224,152, +225,180,110,178,192,178,162,212,132,228,99,240,122,178,154,210,192,228,233,237, +36,24,83,58,18,78,65,110,24,230,63,142,100,112,79,194,138,22,175,72, +200,96,237,174,132,68,132,218,140,226,182,228,190,220,203,201,38,42,221,42, +52,72,207,72,16,102,241,102,128,102,129,10,66,248,66,134,190,134,190,240, +165,232,66,166,191,166,66,196,191,197,12,60,111,60,62,12,28,136,109,136, +16,202,113,174,72,248,73,90,116,28,202,28,156,100,117,122,232,122,171,78, +122,154,229,154,110,222,245,222,176,222,177,155,72,6,38,62,19,88,224,38, +55,38,56,68,211,68,32,100,190,100,190,168,210,216,224,230,239,200,38,128, +132,128,72,164,27,174,168,170,105,146,44,190,161,190,18,228,183,228,104,228, +105,191,72,14,42,88,19,122,54,242,55,66,92,42,92,184,133,164,92,98, +131,98,126,32,247,32,152,190,152,78,226,78,227,188,186,32,175,78,186,102, +186,162,172,202,115,236,194,200,239,239,70,52,70,156,27,234,82,28,36,38, +36,158,71,138,104,134,152,134,152,26,102,26,102,212,147,186,134,158,161,210, +102,78,153,78,182,246,182,32,222,32,222,204,203,201,34,22,73,54,16,88, +55,118,26,230,69,142,88,42,229,42,96,74,219,74,72,104,245,104,156,104, +157,10,102,248,102,134,210,134,210,240,191,236,102,164,211,164,102,198,211,199, +20,36,143,36,68,58,69,16,102,58,103,16,52,58,19,102,104,130,124,124, +124,74,41,74,90,120,48,120,48,96,90,96,91,120,172,14,154,60,139,84, +234,46,161,46,162,74,194,112,235,132,206,46,190,92,147,132,194,136,102,148, +53,148,44,174,213,174,18,204,235,204,134,144,134,236,99,245,28,206,28,40, +80,40,81,200,28,178,81,178,28,108,81,108,104,40,229,40,114,70,219,70, +96,100,241,100,168,100,169,10,122,244,122,128,212,128,212,240,181,244,122,162, +213,162,122,196,213,197,70,12,48,56,19,88,234,34,61,34,66,58,217,58, +48,80,198,80,198,174,224,238,241,216,34,106,175,106,48,128,163,128,18,150, +187,150,102,148,103,92,58,244,58,168,150,168,150,236,131,244,58,188,149,188, +58,210,151,211,58,244,59,10,32,68,17,126,74,56,89,92,100,44,233,44, +114,74,221,74,90,104,245,104,164,104,165,6,116,246,116,134,216,134,216,238, +193,244,116,166,217,166,116,200,217,201,38,14,38,178,95,148,38,72,95,72, +94,28,239,28,114,190,114,78,210,78,211,188,160,28,149,78,164,106,142,204, +79,240,172,188,233,239,40,20,81,56,12,96,60,96,58,224,99,188,104,38, +233,38,114,70,223,70,88,100,247,100,168,100,169,8,120,244,120,130,216,130, +216,242,193,246,120,164,217,164,120,196,217,197,118,16,153,40,234,50,50,50, +50,178,23,236,70,120,227,120,144,68,134,166,61,240,230,234,172,186,141,121, +12,40,91,40,18,110,95,110,14,210,99,182,58,40,59,194,140,14,179,44, +96,54,245,54,210,146,124,146,124,92,210,92,211,146,138,174,89,228,200,172, +241,218,170,146,170,240,145,247,110,14,145,44,36,92,36,54,226,54,227,90, +104,76,70,108,31,132,150,82,229,126,40,154,212,154,196,238,169,244,126,110, +110,200,35,241,100,24,56,36,21,38,14,92,107,92,62,248,63,34,16,190, +63,108,104,158,63,112,132,58,121,134,224,58,195,126,170,10,170,100,148,186, +95,238,236,232,184,174,169,113,12,220,245,220,64,220,64,48,207,30,64,114, +221,114,160,220,161,115,16,218,149,192,42,210,42,44,139,22,42,94,145,94, +100,200,101,94,170,242,170,28,228,28,198,100,230,132,236,174,197,197,10,42, +97,42,16,114,91,114,12,206,95,176,54,188,55,42,90,72,237,72,102,98, +135,134,158,8,158,236,129,240,90,208,159,148,230,212,159,106,224,100,181,138, +182,20,215,51,26,66,231,66,94,246,128,238,129,10,166,18,201,44,46,104, +89,136,30,210,129,134,230,212,154,144,129,86,214,98,153,137,40,232,40,28, +216,28,217,228,40,208,217,208,128,50,106,132,69,176,186,172,117,99,66,16, +103,48,14,64,243,64,176,14,139,64,102,64,98,130,75,170,148,64,148,154, +197,154,50,248,50,102,204,102,205,244,50,188,203,188,50,224,205,225,40,22, +77,48,20,86,59,112,30,226,75,142,102,240,102,30,224,30,225,238,102,216, +225,216,162,58,154,134,127,182,202,174,161,99,28,56,115,56,20,100,125,100, +74,100,75,6,170,8,136,60,121,80,140,94,218,94,218,186,131,186,136,138, +219,138,48,136,36,192,19,232,40,176,56,196,78,212,106,222,130,226,243,224, +82,116,83,210,82,154,119,154,146,46,210,46,187,89,220,34,38,34,38,226, +235,226,186,54,136,144,63,202,74,68,164,150,203,199,94,138,26,138,26,66, +94,66,95,138,15,212,84,164,105,204,14,212,97,190,60,12,61,198,92,226, +247,226,132,226,132,28,212,28,213,226,132,92,213,92,132,158,213,159,44,244, +44,76,212,76,213,242,44,142,213,142,44,220,213,220,100,220,101,12,154,220, +155,13,12,146,103,146,40,146,40,46,102,46,102,236,75,230,74,12,57,46, +40,78,103,78,40,110,103,110,18,222,99,146,240,40,138,40,138,226,243,226, +218,68,190,146,161,196,164,72,227,191,16,228,50,170,50,26,210,26,210,72, +51,72,88,104,88,152,206,152,207,102,80,176,80,230,216,230,217,176,146,230, +147,91,44,56,38,138,104,138,96,238,63,244,16,202,81,182,84,138,90,32, +19,32,238,34,134,34,134,224,243,224,218,68,186,146,151,196,154,82,231,187, +44,20,81,46,24,58,61,82,34,136,89,88,224,30,114,30,114,122,227,122, +114,58,202,58,202,90,115,90,18,156,239,156,124,242,125,136,26,224,84,194, +119,156,230,220,150,182,131,157,10,30,137,30,12,204,137,174,44,194,45,30, +106,246,107,30,44,84,107,84,44,134,107,134,126,50,210,50,186,152,123,224, +144,50,158,146,235,229,26,34,139,34,24,128,139,114,52,124,53,34,116,136, +117,34,52,64,117,64,52,92,117,92,142,44,220,44,180,110,141,134,158,44, +180,104,233,134,16,164,235,164,118,140,78,190,209,236,170,164,120,218,35,239, +10,100,113,100,32,100,33,34,68,100,69,16,68,54,103,54,28,130,28,222, +99,212,98,238,99,130,68,116,47,198,86,190,61,146,224,16,172,28,117,30, +222,112,136,112,136,68,222,68,223,112,146,196,205,184,198,166,211,200,178,188, +179,26,128,240,128,144,232,144,232,232,209,237,26,54,105,54,20,96,113,96, +68,96,69,6,46,138,25,234,240,226,114,228,82,216,39,172,76,114,77,208, +108,152,77,152,108,26,189,26,108,178,185,160,132,172,133,26,170,206,171,26, +132,76,171,76,132,122,171,122,184,52,228,52,214,150,189,188,188,80,241,183, +42,68,215,68,16,134,239,134,128,134,129,12,150,168,215,240,120,144,50,232, +193,219,36,246,36,28,218,28,219,242,36,224,219,224,70,50,97,70,178,48, +151,74,64,84,191,84,54,114,201,114,128,40,106,118,51,162,146,114,164,138, +197,158,176,180,160,200,102,200,96,190,96,146,150,146,150,174,131,179,18,38, +135,38,60,52,61,8,106,52,107,8,70,94,36,94,36,66,70,66,71,94, +126,94,96,94,96,66,126,66,127,94,60,106,36,140,19,158,46,240,47,126, +82,104,101,120,56,130,135,130,54,158,129,158,56,184,129,184,56,212,137,212, +90,212,91,130,138,28,243,28,156,186,156,72,224,72,225,182,190,28,179,72, +192,98,192,158,176,206,135,242,198,198,239,239,16,72,101,72,64,244,65,8, +16,168,42,130,65,82,102,136,65,96,104,38,214,38,186,142,99,232,128,38, +158,148,235,231,12,32,115,32,30,240,30,76,102,76,103,228,30,172,103,172, +30,210,103,210,54,32,54,102,45,146,78,32,78,124,82,132,99,134,117,44, +126,44,241,44,144,74,145,12,202,74,203,12,174,62,121,134,170,68,233,134, +141,132,140,132,213,132,132,176,219,176,118,226,237,226,174,226,175,133,196,114, +56,114,56,40,196,40,197,114,108,8,91,40,56,78,197,78,14,156,92,156, +68,200,19,228,126,126,126,242,103,240,126,148,174,198,235,226,212,140,157,179, +126,14,74,76,17,112,236,108,158,64,121,22,54,108,197,108,60,166,189,166, +26,228,223,228,124,228,125,109,122,14,157,38,238,52,60,52,60,166,23,242, +16,72,43,104,14,154,61,128,158,60,118,104,79,132,152,68,188,104,241,128, +98,132,211,132,96,180,217,180,70,226,243,226,154,226,155,133,58,20,95,46, +186,18,155,50,34,64,219,64,14,98,239,98,128,10,106,82,70,124,17,158, +162,98,188,130,239,154,168,126,130,132,77,134,66,162,195,162,36,190,223,190, +132,132,132,240,101,239,22,94,227,94,162,30,203,68,126,10,122,102,106,144, +76,190,25,234,234,232,204,216,174,186,148,148,127,95,50,26,89,56,186,22, +155,58,38,76,223,76,16,118,241,118,128,10,112,84,86,128,54,154,17,172, +238,174,190,150,159,118,70,162,180,162,174,238,164,244,141,236,110,162,98,206, +45,245,26,52,108,52,100,102,82,158,54,194,25,218,44,94,78,134,119,186, +126,76,232,70,224,228,197,224,172,10,170,118,156,170,132,206,93,239,58,10, +38,56,21,84,104,54,41,54,12,110,115,110,31,140,104,142,105,216,30,140, +30,208,105,202,66,204,67,54,110,132,245,132,118,62,216,62,211,132,164,6, +164,134,150,182,130,212,97,242,238,236,208,212,182,178,163,143,28,66,17,130, +58,12,58,144,48,196,21,240,92,58,59,114,98,204,57,156,94,136,241,136, +110,64,210,64,211,136,158,6,158,138,144,182,120,212,85,240,234,238,202,210, +178,176,161,137,124,16,159,32,246,46,56,46,56,166,46,210,29,246,18,72, +37,110,14,156,57,130,74,80,150,80,138,126,121,124,112,58,98,110,75,134, +230,112,178,112,178,74,228,74,229,112,94,248,94,148,220,148,220,240,197,236, +160,124,146,166,113,190,200,184,151,156,158,182,117,226,194,218,149,193,28,60, +135,60,18,116,149,116,84,116,85,10,82,128,34,212,125,196,100,148,135,214, +164,244,164,34,226,34,226,202,201,199,20,56,119,56,12,104,123,104,50,104, +51,14,90,104,91,14,38,240,38,138,102,138,103,236,38,178,103,178,38,220, +103,220,164,64,191,88,182,112,216,104,220,46,144,46,144,148,232,148,228,224, +210,238,189,236,122,192,205,192,176,12,161,47,18,70,95,70,64,246,65,8, +20,160,65,86,94,122,65,96,110,90,110,52,232,52,233,90,176,12,138,100, +91,150,170,78,201,100,124,246,125,114,134,112,241,112,124,150,233,150,132,186, +233,186,132,224,245,224,182,224,183,113,16,44,109,44,60,44,48,94,19,136, +44,214,44,110,86,110,87,206,44,184,85,184,152,10,126,56,93,92,84,240, +120,188,120,82,224,82,224,236,193,230,138,36,202,36,175,82,120,120,225,120, +120,164,225,164,172,82,173,217,94,38,39,76,174,36,235,72,132,14,135,88, +188,62,90,110,21,124,132,100,159,118,70,244,71,114,76,128,229,128,76,160, +217,160,76,192,217,192,76,224,239,224,146,128,147,225,46,16,79,50,14,72, +82,72,48,128,17,156,58,246,59,112,98,158,59,130,98,108,73,138,96,80, +243,80,108,36,214,36,214,122,109,122,140,36,134,128,112,172,77,206,136,246, +136,162,220,162,221,244,136,220,221,221,14,72,135,72,28,30,112,30,112,112, +27,112,60,30,60,82,44,144,19,180,54,238,54,152,112,152,113,232,54,212, +113,212,146,14,177,48,152,62,243,62,224,12,197,56,142,120,235,120,130,176, +247,176,186,244,187,63,76,14,56,64,25,104,62,50,122,50,108,96,82,136, +35,176,52,110,81,136,70,78,103,104,128,86,233,86,196,28,225,62,172,12, +166,98,146,140,111,176,232,176,190,136,169,86,64,190,31,240,98,190,113,238, +148,186,173,230,200,184,237,233,32,74,25,140,60,12,60,136,48,192,23,240, +90,60,61,92,88,198,57,160,124,16,108,68,89,110,114,54,152,54,138,102, +118,134,95,160,120,80,139,92,104,108,123,124,152,84,237,84,182,14,176,110, +156,148,131,176,236,172,198,126,181,84,202,34,227,64,110,188,85,242,134,194, +147,234,170,194,187,234,198,182,231,235,12,162,245,162,58,244,58,60,202,60, +202,242,173,240,58,112,203,112,128,162,129,11,46,14,81,40,22,52,59,74, +28,134,81,86,96,52,194,44,188,114,198,126,218,124,228,114,231,98,146,8, +142,68,124,104,93,130,16,160,235,160,126,244,127,130,24,226,82,198,127,160, +228,222,166,194,127,161,58,14,85,38,18,46,129,46,66,94,34,94,34,70, +66,70,67,94,118,94,88,94,88,70,118,70,119,94,22,118,129,118,28,140, +123,140,16,164,133,164,54,164,55,100,94,164,95,100,66,170,42,194,17,212, +78,212,50,236,51,186,115,178,76,186,117,218,114,178,95,200,222,28,146,42, +146,160,138,202,117,242,200,32,200,110,212,174,237,230,174,38,174,116,172,188, +164,228,201,218,190,192,209,235,12,90,81,90,16,202,77,178,50,18,51,188, +136,12,167,30,78,40,235,40,140,90,100,90,100,64,140,64,141,90,216,90, +166,90,166,64,216,64,217,90,86,114,227,114,92,138,217,138,80,162,241,162, +128,162,129,96,178,162,179,96,146,162,124,188,75,220,122,190,122,238,167,214, +162,178,192,208,237,230,220,178,189,205,8,76,83,76,10,158,79,122,52,14, +52,240,25,234,136,14,169,32,82,40,237,40,144,90,102,90,102,62,144,62, +145,90,214,90,172,90,172,62,214,62,215,90,88,112,229,112,96,136,223,136, +76,162,241,162,132,162,133,96,184,162,185,96,78,218,132,186,153,162,164,216, +124,240,125,190,162,180,202,216,239,234,218,180,195,207,30,198,30,48,70,48, +71,192,30,174,71,174,142,10,171,30,84,38,239,38,144,92,102,92,102,62, +144,62,145,92,218,90,172,90,172,62,218,62,219,90,92,116,235,116,96,140, +225,140,84,166,245,166,134,166,135,96,182,166,183,96,80,216,122,194,153,166, +166,214,126,236,127,190,166,180,186,208,210,226,237,236,220,180,193,213,38,24, +77,60,12,98,60,98,58,226,99,184,88,222,243,222,152,222,153,16,152,92, +225,93,58,16,38,72,19,110,74,100,88,64,43,64,88,186,48,216,49,104, +104,60,227,44,206,66,160,108,109,130,228,104,216,130,204,132,168,100,148,68, +137,10,92,154,231,154,140,154,138,182,128,210,110,230,87,240,174,154,174,224, +184,230,222,230,234,222,241,203,12,72,91,72,14,158,91,122,58,12,58,240, +29,232,98,84,233,84,184,28,213,62,150,10,146,134,126,186,87,238,170,114, +170,218,180,232,220,232,230,220,239,201,94,58,32,160,91,150,68,14,22,96, +75,90,16,212,97,194,110,60,235,38,226,60,154,108,99,124,146,12,154,68, +186,114,212,132,222,130,237,104,100,152,239,152,142,152,134,194,116,220,79,238, +180,152,180,222,188,236,218,236,230,226,237,209,16,46,239,46,90,72,91,12, +166,70,167,14,26,92,227,92,124,62,78,112,27,148,192,160,74,160,74,120, +190,120,191,160,54,180,21,232,124,176,153,202,198,180,237,214,84,184,84,224, +98,238,162,238,178,228,187,207,18,60,105,60,18,124,99,92,70,12,70,168, +51,162,112,66,200,54,200,100,208,148,220,164,236,156,245,128,152,12,150,84, +134,128,101,168,120,96,167,134,58,190,21,236,92,188,109,234,144,182,163,226, +194,180,227,231,208,28,136,44,41,46,16,124,239,124,36,218,223,218,128,218, +129,45,80,14,48,88,21,124,60,242,61,62,96,62,227,62,80,214,245,215, +128,20,120,120,84,186,19,226,230,228,166,174,138,116,125,71,38,32,200,32, +188,118,160,126,149,118,80,52,57,100,130,32,126,60,114,90,94,114,66,134, +35,144,52,168,23,228,116,138,147,174,192,154,239,210,88,156,88,206,94,226, +158,226,178,218,187,195,16,50,111,50,24,90,105,90,14,132,110,132,108,174, +102,188,83,188,62,244,63,12,130,40,224,40,220,196,208,220,179,224,144,78, +133,142,176,40,174,118,158,176,113,231,82,14,48,86,19,120,58,246,59,66, +222,32,178,46,95,58,82,128,247,128,90,220,241,220,166,220,167,49,40,20, +91,66,12,100,58,100,54,218,99,180,164,14,162,84,154,138,140,174,120,204, +93,236,234,224,212,202,196,172,180,140,170,106,163,83,40,38,218,38,208,198, +194,220,161,224,138,38,134,94,122,140,104,174,76,202,33,226,78,82,47,159, +14,76,98,74,92,128,80,166,64,196,21,232,106,208,34,148,69,14,224,22, +160,36,117,40,114,120,245,120,116,224,235,224,176,224,177,35,110,66,34,170, +105,156,80,18,26,106,85,100,28,220,111,200,142,88,121,150,122,44,226,44, +222,210,210,232,183,236,174,44,174,122,160,180,140,212,109,241,18,74,101,74, +18,158,103,120,64,14,64,238,41,226,104,38,204,38,190,118,226,118,220,204, +210,226,169,230,142,38,140,122,132,174,114,206,85,239,76,12,46,88,19,126, +56,244,57,64,92,36,202,36,188,118,228,118,222,206,212,228,173,230,136,36, +136,112,120,176,81,235,54,232,54,40,200,40,201,228,54,120,201,120,54,204, +201,205,18,66,239,66,24,136,133,136,80,86,76,156,68,184,54,204,38,222, +25,234,180,20,211,48,148,12,148,88,156,138,172,192,198,230,212,238,224,234, +237,202,208,104,178,168,156,196,136,214,109,233,16,44,241,44,94,70,95,8, +164,70,165,8,24,86,235,86,14,208,243,196,184,246,185,86,76,86,77,204, +76,124,185,124,76,160,185,161,12,40,237,40,86,68,87,12,164,68,165,10, +112,58,141,78,36,124,36,90,220,90,221,122,92,104,47,144,158,104,207,136, +130,110,86,154,52,174,17,188,122,118,144,138,188,164,237,180,70,244,70,178, +186,178,187,242,70,224,187,225,18,50,235,50,96,78,97,12,160,78,161,12, +34,132,34,96,220,96,221,130,28,152,225,152,126,246,127,112,24,228,80,196, +104,172,125,152,232,222,186,204,154,178,133,153,12,36,125,36,102,102,38,102, +38,70,102,70,103,102,26,242,26,134,112,134,112,234,91,226,46,148,63,168, +42,184,97,184,88,150,75,176,70,228,71,184,220,152,140,152,140,74,220,74, +221,152,133,222,208,178,239,232,132,224,227,208,178,216,179,15,28,74,21,136, +20,236,42,202,52,158,54,112,57,16,86,64,57,100,92,200,55,150,148,14, +177,38,100,84,100,48,226,48,227,80,146,70,105,112,178,72,223,108,164,94, +134,140,93,170,240,164,194,140,176,124,159,104,122,244,122,170,206,170,207,242, +122,222,207,223,32,26,71,52,18,90,59,118,22,232,59,152,130,12,163,36, +90,84,90,50,218,50,219,82,134,72,91,114,174,74,215,110,158,96,120,138, +79,166,152,104,176,130,206,146,233,156,112,242,112,164,200,164,201,240,112,220, +201,221,112,14,145,36,36,90,36,48,218,48,219,88,100,68,53,112,152,70, +203,110,134,90,98,128,58,154,19,172,124,102,150,124,190,148,241,162,74,248, +74,168,186,168,187,246,74,222,187,223,88,66,20,164,89,152,16,210,93,196, +64,20,18,104,67,96,104,70,235,70,90,136,157,136,124,92,124,156,118,196, +91,238,190,20,219,48,162,12,166,94,176,152,192,198,212,226,220,232,228,228, +237,202,212,96,198,146,176,190,154,210,133,231,40,92,40,40,216,40,217,92, +26,232,50,222,74,202,90,174,94,134,94,100,160,100,160,204,164,220,172,224, +182,226,210,226,222,220,230,204,233,191,14,72,91,72,16,158,91,132,58,18, +58,238,35,228,144,48,187,70,112,28,208,28,173,62,98,74,236,74,217,108, +176,74,176,122,168,132,151,134,100,122,146,98,177,74,96,166,241,166,164,244, +165,144,90,226,124,206,165,170,238,226,198,206,165,171,49,34,106,58,143,76, +48,34,188,34,133,70,26,84,218,84,205,114,142,84,142,126,136,136,113,138, +36,136,84,120,135,84,18,164,235,164,128,244,129,148,24,228,64,212,96,190, +125,164,232,222,202,214,162,192,133,165,44,240,44,56,212,56,212,214,206,234, +185,238,134,14,116,78,77,128,182,122,119,74,130,118,104,172,73,202,178,192, +119,143,16,48,245,48,100,82,101,10,164,80,165,10,132,216,48,170,79,72, +20,114,120,114,106,168,78,208,23,238,158,232,158,104,218,104,219,230,158,204, +219,205,84,132,32,132,32,60,84,60,85,132,78,158,95,200,18,200,89,184, +58,190,59,8,106,26,229,26,168,110,169,26,108,94,108,56,228,56,229,92, +122,84,151,84,184,82,213,82,122,106,149,106,184,106,213,106,100,130,241,130, +112,246,112,160,222,160,222,240,207,244,156,160,165,130,148,228,149,160,184,226, +185,161,72,14,46,88,21,124,56,244,57,64,94,30,227,30,86,94,86,58, +232,58,233,96,158,110,159,30,106,84,139,84,178,86,211,86,106,110,139,110, +178,110,211,110,80,138,243,138,98,244,98,168,222,168,222,240,201,244,158,138, +149,168,138,236,139,168,178,234,179,169,14,38,82,38,56,92,56,238,29,244, +16,156,85,124,106,30,229,30,100,92,100,60,230,60,231,92,164,122,165,30, +116,84,147,84,182,84,213,84,118,110,149,110,182,110,213,110,90,138,245,138, +106,246,106,166,226,166,226,238,207,244,152,166,163,138,144,232,145,166,184,232, +185,167,20,78,116,76,104,140,74,196,23,236,78,16,42,152,121,216,148,230, +148,56,220,56,221,228,148,196,221,197,232,30,52,30,52,104,29,160,80,58, +209,58,52,88,229,88,92,88,92,152,143,132,138,88,160,120,198,140,233,152, +200,102,169,124,12,176,243,176,78,192,107,224,178,150,178,236,151,245,134,24, +23,48,30,64,49,100,66,56,83,90,132,48,99,102,20,120,118,120,80,148, +80,234,43,240,18,194,131,162,162,14,162,210,174,230,212,230,228,220,235,199, +44,28,83,60,18,88,61,116,24,232,71,148,72,94,241,94,156,16,104,150, +231,222,198,94,180,150,140,204,85,239,92,32,116,50,126,62,138,88,154,128, +178,166,212,206,237,226,18,226,52,202,76,172,96,136,114,94,123,61,48,16, +79,46,18,68,82,68,46,120,19,146,60,244,61,102,96,160,61,124,96,100, +75,138,240,28,114,28,114,152,87,230,140,58,229,58,114,88,245,88,152,88, +152,146,183,130,240,148,204,128,183,88,234,102,207,126,126,176,245,176,148,188, +171,212,206,148,206,236,181,245,12,58,119,58,68,12,26,134,115,134,16,202, +121,174,74,244,75,90,116,108,140,66,157,10,208,106,224,66,141,66,166,96, +166,146,154,192,132,218,111,236,236,232,204,206,182,176,167,139,32,242,32,24, +90,24,62,96,82,116,92,142,84,170,57,182,112,32,223,32,96,102,233,102, +142,102,138,172,114,212,73,236,182,102,182,212,192,230,218,230,230,220,239,201, +18,46,239,46,94,66,95,12,160,64,161,14,62,88,43,138,118,74,145,108, +182,82,215,126,94,88,94,126,100,138,162,138,172,124,177,112,36,178,19,232, +72,152,91,186,106,166,123,200,62,170,62,224,68,236,94,236,109,212,144,174, +131,230,180,152,199,188,214,162,241,210,164,170,164,226,176,236,202,236,212,226, +217,209,14,44,85,44,24,116,85,116,18,206,99,184,50,44,51,196,167,10, +116,28,116,72,218,72,219,24,164,10,165,72,100,108,243,108,114,242,114,148, +226,148,226,236,207,242,166,108,151,148,150,148,151,220,188,148,189,219,66,16, +36,64,17,88,106,54,43,54,28,100,97,100,18,148,107,148,62,100,62,220, +103,194,126,18,155,56,210,14,185,68,216,138,126,138,126,76,216,76,217,138, +90,240,116,226,136,210,146,190,150,168,151,138,190,138,190,230,200,240,228,240, +238,228,241,211,36,240,37,66,44,18,77,56,98,34,220,34,220,230,185,240, +70,82,189,82,78,132,181,132,62,190,195,190,130,190,131,83,40,22,79,52, +24,82,63,114,26,230,69,144,104,14,131,50,98,244,99,60,146,38,224,38, +224,212,216,238,191,242,120,84,201,84,124,136,195,136,116,190,205,190,158,190, +159,85,26,52,229,52,88,82,89,12,168,80,169,10,14,112,239,112,20,196, +54,174,86,140,110,110,127,78,78,246,78,158,198,158,199,242,78,218,199,219, +28,30,108,30,108,76,48,76,48,120,110,120,110,222,102,238,59,244,36,146, +77,162,30,204,103,176,132,30,214,30,214,76,144,76,144,120,218,120,218,226, +188,238,167,240,136,196,211,166,140,142,179,161,12,70,79,70,16,156,75,122, +50,10,50,238,29,230,80,46,161,46,74,92,159,92,104,92,105,10,138,92, +139,10,94,238,94,122,146,122,146,228,125,234,94,154,147,154,94,184,147,184, +154,108,174,78,186,44,197,10,242,72,179,72,174,110,184,148,200,188,222,216, +241,232,218,72,216,118,206,164,190,200,161,237,32,26,69,62,20,90,59,118, +28,236,63,148,76,34,243,34,92,242,92,90,220,90,221,238,92,212,221,212, +138,34,138,112,130,146,111,172,176,34,176,146,182,162,194,164,213,157,16,40, +239,40,96,68,97,8,160,62,161,10,38,246,38,86,90,86,62,138,74,150, +86,166,88,186,82,200,68,206,59,206,146,68,179,88,104,98,231,98,134,110, +159,130,208,106,187,134,88,242,104,222,112,196,116,178,116,142,241,143,20,232, +32,196,36,156,36,28,84,28,84,230,61,238,36,88,85,88,36,142,85,142, +220,120,122,120,122,26,220,26,221,120,122,74,221,74,172,120,173,26,126,162, +109,216,168,140,191,176,210,156,243,198,152,156,152,216,160,230,196,230,208,218, +213,199,58,16,36,54,17,74,94,172,30,172,30,86,94,86,95,172,42,44, +88,44,65,86,30,128,95,128,62,172,63,86,18,218,95,206,220,122,128,122, +128,30,218,30,219,122,128,76,219,76,174,122,175,30,124,164,109,222,160,140, +191,172,214,162,241,216,148,160,148,226,158,236,186,236,204,228,209,211,112,14, +143,34,30,80,30,44,222,44,223,80,50,78,201,78,60,110,195,110,22,140, +229,140,94,140,95,58,158,140,159,56,18,194,48,184,78,164,101,140,238,194, +204,180,174,162,155,140,66,196,185,196,30,232,223,232,126,232,127,157,110,10, +141,32,36,70,36,40,220,40,221,70,56,72,201,72,62,100,199,100,18,126, +241,126,96,126,97,54,162,126,163,52,16,180,48,166,78,142,91,126,242,172, +212,162,192,150,171,126,86,210,86,156,172,156,173,206,40,240,72,236,100,224, +120,204,135,176,146,210,223,241,32,44,221,44,50,124,203,124,14,210,241,211, +152,32,205,84,122,16,58,74,185,64,18,108,239,108,114,80,90,120,70,144, +44,162,19,178,236,178,202,162,178,142,164,126,155,108,74,154,177,154,64,194, +187,194,38,232,219,233,124,10,68,74,17,110,116,18,168,70,235,108,56,114, +97,158,188,110,153,162,18,184,229,184,124,248,125,79,18,56,125,56,13,96, +10,96,127,96,54,96,55,14,94,96,95,14,42,244,42,128,110,128,110,232, +85,238,42,158,111,158,42,190,111,190,174,10,146,84,131,114,238,72,153,72, +206,72,202,114,192,158,168,196,129,232,238,230,212,212,184,186,168,156,155,107, +62,32,194,32,156,58,112,76,59,84,82,48,152,66,199,84,34,98,120,98, +98,126,66,146,39,156,50,112,119,148,136,98,212,98,178,136,149,154,142,114, +229,152,18,176,237,176,130,244,131,152,24,230,74,208,125,176,234,228,180,210, +135,177,28,192,28,44,66,44,67,184,28,162,67,162,102,28,198,28,166,56, +134,72,99,78,122,40,207,78,82,94,142,94,126,126,89,152,98,108,143,144, +168,94,216,94,196,128,173,146,168,110,225,146,82,170,239,170,156,244,157,150, +76,228,118,202,149,170,236,226,218,218,184,192,165,171,32,48,223,48,54,74, +95,106,190,68,155,108,12,128,241,128,126,128,127,12,66,128,66,234,121,208, +230,232,194,218,158,194,132,162,119,128,210,146,155,189,16,74,97,74,16,156, +91,108,60,14,60,232,31,224,96,30,210,30,184,70,144,104,99,126,236,124, +192,112,154,88,130,60,117,30,150,44,167,64,210,180,110,180,110,142,210,142, +211,180,196,198,233,240,92,228,215,218,160,222,161,117,38,58,32,142,90,142, +82,238,59,242,10,192,69,178,14,34,80,34,75,142,102,34,208,34,188,70, +154,102,99,126,242,120,198,108,160,88,138,64,123,34,156,48,169,66,216,184, +124,184,124,144,214,144,215,184,202,198,233,242,106,232,217,222,168,226,169,115, +16,70,107,70,20,158,109,122,68,12,68,236,37,230,116,44,218,44,219,232, +124,122,219,122,114,204,219,205,14,74,90,72,80,134,62,182,21,226,60,10, +34,148,105,200,140,32,116,36,116,112,222,112,222,36,201,36,140,74,117,74, +196,74,223,74,104,146,208,146,186,182,158,208,132,222,99,236,236,232,208,224, +180,210,156,190,138,168,127,146,166,146,167,13,30,30,117,30,34,72,115,72, +26,114,115,114,145,30,144,28,233,28,142,70,227,70,144,112,239,112,74,114, +75,30,184,112,185,28,54,156,33,202,108,134,139,156,200,160,233,202,190,134, +122,192,25,232,90,148,90,214,98,228,164,228,180,218,191,197,104,16,72,56, +21,94,150,88,174,46,81,46,230,194,222,218,204,230,72,230,52,220,50,206, +50,94,198,94,198,154,51,154,124,154,125,95,35,26,36,28,71,52,16,90, +53,112,30,228,65,138,116,56,97,96,88,30,216,30,210,120,179,116,160,30, +156,74,142,102,118,126,91,140,76,224,243,224,116,224,117,158,168,224,169,136, +168,166,227,167,28,44,229,44,126,116,127,12,26,110,68,92,102,70,127,46, +234,108,208,100,178,88,150,68,127,46,18,144,109,144,78,246,79,108,18,218, +48,192,79,150,116,190,79,158,176,248,177,106,142,144,239,144,114,220,144,190, +177,146,238,218,210,194,179,145,72,16,42,84,23,112,52,246,53,64,112,14, +141,42,202,12,177,48,224,126,90,126,90,54,224,54,225,126,112,76,135,106, +200,74,177,104,158,126,159,54,102,246,102,156,210,156,211,244,102,190,211,190, +102,226,211,227,18,44,239,44,94,74,95,8,164,68,165,8,54,74,91,100, +26,114,61,138,32,230,75,156,128,104,99,168,200,102,235,148,162,190,163,80, +80,238,124,230,156,216,184,192,207,157,14,40,105,40,14,140,36,112,52,80, +63,40,44,216,44,108,90,108,91,210,44,186,91,186,170,166,171,10,140,56, +109,130,194,54,241,114,218,128,198,176,170,206,134,226,93,239,62,26,148,66, +211,106,192,16,122,72,88,92,47,108,22,134,235,134,130,92,130,238,112,242, +101,236,90,164,62,196,29,224,158,162,227,215,44,26,143,90,136,20,80,72, +31,102,22,128,155,128,92,90,92,240,72,244,61,236,62,160,25,212,114,158, +149,210,178,182,179,36,224,14,224,236,201,217,48,32,87,62,18,90,61,118, +28,234,69,142,160,176,161,14,122,72,91,140,190,68,233,122,210,140,184,190, +156,216,114,232,79,239,98,56,30,164,95,156,68,16,22,96,75,94,16,220, +105,196,164,170,165,16,134,60,103,138,196,62,239,130,216,140,190,188,162,216, +130,232,95,241,78,14,44,80,17,112,56,246,57,58,214,114,100,114,100,44, +214,44,215,114,126,58,189,98,188,52,127,102,124,126,77,160,148,10,135,44, +180,122,235,152,152,130,122,170,87,202,84,238,124,230,162,208,184,180,198,156, +135,156,138,178,168,208,206,224,239,235,28,196,28,42,78,42,79,190,28,170, +79,170,160,10,130,66,95,102,234,96,198,72,157,18,124,90,199,90,96,130, +229,130,112,246,112,168,210,168,211,246,112,226,211,226,160,168,161,91,74,10, +40,58,17,82,46,50,108,50,83,88,28,94,116,94,116,166,29,166,34,128, +117,128,170,10,148,72,131,98,238,62,155,62,132,168,160,152,184,126,196,100, +205,62,156,84,176,122,204,150,241,168,60,190,31,242,96,194,103,240,140,190, +159,238,184,180,223,239,80,14,46,58,25,78,134,44,59,44,98,78,81,44, +172,12,152,54,129,78,244,44,159,44,206,80,187,44,40,194,41,94,80,84, +80,174,64,210,31,242,102,100,239,100,116,218,116,138,216,138,216,216,195,220, +164,246,165,101,30,210,30,34,78,34,79,204,30,108,79,108,30,184,79,184, +96,26,241,26,112,242,112,82,218,82,219,238,112,210,219,210,150,26,150,114, +127,170,182,26,182,148,190,158,219,159,16,40,89,40,22,106,75,106,14,198, +85,176,56,40,57,184,90,122,245,122,82,238,106,186,106,28,144,28,144,230, +125,236,156,236,178,180,178,28,218,28,218,238,199,243,14,48,241,48,86,82, +87,14,164,82,165,10,58,244,58,158,198,158,199,242,58,224,199,224,122,72, +123,158,122,114,233,115,16,78,125,78,70,244,71,10,18,174,71,100,114,146, +71,104,212,18,176,66,137,98,224,88,184,134,143,166,238,148,188,206,125,237, +206,234,207,62,42,68,42,214,207,208,124,210,125,17,18,232,36,206,50,158, +50,32,86,32,86,226,63,232,94,240,122,174,122,32,156,32,156,232,133,238, +20,112,181,112,194,184,195,44,228,12,228,238,203,229,32,70,23,132,60,14, +60,132,50,184,21,234,92,58,61,102,88,184,59,144,144,14,179,38,76,230, +96,200,106,160,106,46,220,46,220,82,107,82,122,118,164,118,164,238,137,244, +128,138,143,168,116,202,161,180,180,118,228,118,228,238,201,242,186,138,203,164, +182,202,223,179,56,16,95,50,16,66,108,66,56,130,19,158,68,244,69,116, +118,174,69,132,118,110,89,148,212,22,174,68,135,98,224,92,180,134,137,164, +236,152,180,208,119,241,52,14,83,54,38,244,39,60,108,40,220,40,220,238, +189,244,134,74,112,140,67,188,194,176,121,117,32,246,32,30,82,30,60,102, +72,124,80,148,80,174,70,184,55,190,102,52,231,52,112,80,135,114,216,76, +193,116,94,136,239,136,166,10,166,102,154,164,126,210,85,240,236,238,206,218, +184,188,165,137,14,72,85,72,12,156,79,120,50,10,50,244,23,232,140,12, +171,34,78,46,243,46,218,138,102,138,102,70,220,70,221,138,186,116,134,116, +134,92,186,92,187,116,212,208,112,208,112,164,212,164,213,208,112,186,213,186, +74,232,245,233,32,174,32,32,92,32,93,166,62,66,62,150,52,194,19,232, +70,180,91,208,160,12,140,34,117,50,188,56,202,32,145,32,242,62,120,62, +120,152,110,198,89,236,170,72,143,96,200,70,231,94,174,88,197,104,128,114, +247,114,138,140,231,140,138,166,231,166,144,246,144,194,222,194,223,244,144,230, +223,231,16,238,28,200,32,164,32,30,78,30,78,238,59,242,32,86,79,86, +32,144,79,144,100,40,235,40,128,10,149,40,202,8,181,40,110,72,219,72, +98,104,233,104,92,154,245,154,118,122,137,146,206,120,191,146,164,146,165,40, +116,244,116,180,208,180,209,244,116,226,209,227,74,16,103,42,180,12,153,44, +28,50,225,50,46,82,211,82,28,114,225,114,14,156,237,156,70,126,93,150, +188,122,167,150,128,50,129,150,62,246,62,186,198,186,199,244,62,226,199,227, +36,26,81,60,18,88,63,120,26,234,69,150,222,242,223,74,106,74,106,218, +223,212,162,214,163,13,112,12,153,36,20,236,40,204,52,164,52,52,212,52, +212,92,53,92,70,126,130,126,130,238,95,246,76,150,103,168,64,204,125,180, +150,126,220,126,220,238,185,246,156,146,189,168,154,204,213,181,90,64,30,158, +83,150,62,16,22,94,73,92,18,218,93,198,128,12,149,36,98,48,231,48, +200,10,179,40,112,76,217,76,98,108,231,108,120,122,141,144,206,122,191,146, +92,154,243,154,166,146,167,48,118,244,118,182,210,182,211,242,118,224,211,225, +16,84,87,84,18,196,89,168,52,14,53,180,142,12,173,36,92,48,239,48, +122,62,145,84,194,60,177,92,102,244,102,98,224,98,224,240,195,246,146,116, +119,148,174,116,203,144,186,200,138,200,138,158,186,158,187,201,78,16,44,90, +17,118,56,248,57,64,138,12,106,76,83,102,244,56,117,56,98,130,220,124, +216,236,183,244,160,80,152,168,130,206,93,241,110,14,141,38,20,52,241,52, +80,66,109,90,176,62,155,94,48,246,48,100,208,100,208,242,179,250,112,118, +71,158,140,120,185,160,158,212,98,212,98,164,158,164,159,213,62,24,93,48, +130,10,131,52,188,18,167,52,28,94,28,58,226,58,227,92,180,118,74,118, +74,84,180,84,181,118,66,204,66,144,194,144,195,200,132,160,124,196,104,216, +70,230,35,238,146,198,233,237,30,218,30,52,80,52,81,212,30,122,81,122, +30,190,81,190,114,244,114,60,224,60,224,240,197,244,166,10,145,60,190,174, +148,174,148,104,192,104,193,175,18,224,239,224,116,224,117,18,116,100,217,101, +46,36,93,72,206,32,161,76,44,240,44,104,212,104,212,234,183,240,162,194, +96,194,96,142,162,142,163,194,126,104,127,13,34,98,34,60,224,60,225,96, +56,26,95,48,130,8,131,60,198,20,163,60,182,114,76,114,76,86,182,86, +183,114,118,124,149,142,20,150,239,150,20,210,66,194,100,170,121,150,136,210, +78,234,79,184,136,166,170,208,233,236,208,170,165,201,18,74,107,74,66,246, +67,14,18,168,67,100,102,146,67,106,130,246,130,94,232,94,232,236,207,244, +178,94,179,10,116,30,147,68,238,24,205,70,130,138,233,138,130,182,233,183, +14,68,99,68,20,160,97,122,64,8,64,244,37,230,124,246,124,92,222,92, +222,242,199,246,118,28,143,66,234,24,203,70,174,92,175,4,124,138,223,138, +124,182,223,183,100,24,56,36,23,38,16,90,109,90,66,246,67,34,16,190, +67,108,104,156,67,116,122,26,151,72,232,26,199,70,132,246,132,94,226,94, +226,240,199,246,176,94,177,8,132,138,227,138,132,178,227,179,32,66,19,128, +62,14,62,124,48,188,19,230,96,64,63,102,94,200,57,156,106,62,231,34, +216,60,162,104,105,126,146,10,152,58,166,88,186,112,214,128,224,126,237,110, +96,152,241,152,142,152,142,180,138,198,122,214,102,228,79,238,182,152,182,216, +194,234,218,234,232,224,239,209,14,48,241,48,100,82,101,12,166,82,167,12, +78,80,54,128,31,160,82,152,141,196,64,112,216,112,210,208,198,234,168,240, +149,229,98,14,62,80,33,110,74,62,216,62,212,202,204,224,180,234,145,236, +96,110,139,167,62,14,91,36,24,50,125,50,44,62,67,88,16,102,133,102, +108,62,85,102,42,246,42,136,110,136,111,238,42,176,111,176,42,216,111,216, +134,32,228,32,224,90,218,106,204,114,189,112,176,32,168,82,154,108,129,124, +148,244,148,138,220,138,221,244,148,216,221,217,80,58,52,108,29,138,128,174, +129,12,172,58,235,120,196,134,162,180,132,206,94,222,58,232,25,239,30,200, +30,48,76,48,77,188,30,168,77,168,114,242,114,94,214,94,214,228,208,240, +189,242,114,138,215,138,114,182,213,182,162,94,163,12,98,30,133,68,224,26, +189,69,26,26,132,26,126,88,122,100,116,104,110,108,93,106,76,26,64,76, +48,104,19,124,46,234,46,136,122,136,123,228,46,208,123,208,168,240,168,28, +232,28,200,106,220,128,234,156,234,186,220,200,197,203,104,54,34,164,107,152, +70,16,24,98,77,94,26,222,109,200,118,28,220,28,220,68,214,112,200,122, +185,118,162,28,158,68,144,98,117,124,132,242,132,148,226,148,227,240,132,218, +227,219,26,42,229,42,124,10,94,58,66,82,17,108,240,104,202,88,168,64, +151,42,78,90,161,90,22,124,233,124,126,124,127,64,82,244,82,158,190,158, +191,244,82,188,191,188,82,222,191,222,182,92,120,142,72,168,21,187,30,174, +30,34,94,34,95,170,62,68,62,140,54,188,38,216,17,238,72,184,107,228, +172,12,140,64,113,100,240,96,200,60,167,22,134,94,217,94,112,134,241,134, +174,134,174,212,168,230,158,236,143,238,144,158,115,206,198,160,237,213,100,144, +32,144,32,70,100,70,101,144,94,172,115,214,18,224,103,192,66,204,67,12, +156,16,181,42,124,92,124,56,224,56,225,90,152,96,152,208,160,232,214,232, +232,216,237,196,222,124,153,159,194,24,110,36,45,38,16,94,241,94,62,242, +62,150,192,150,193,238,62,216,193,216,126,148,127,35,132,10,82,66,19,104, +124,18,172,64,243,96,186,90,71,90,30,130,229,130,70,248,70,168,192,168, +193,244,70,226,193,226,132,168,133,91,26,56,125,56,12,102,129,102,76,102, +77,12,36,132,21,178,108,132,133,172,62,102,62,128,54,180,36,216,19,234, +98,102,98,226,75,236,170,12,150,86,135,118,238,74,155,74,112,238,152,212, +186,170,200,124,207,74,150,110,162,156,192,198,239,237,16,72,95,72,14,156, +83,124,58,12,58,236,29,222,98,28,233,28,98,122,241,114,204,136,205,28, +128,120,129,28,128,56,205,56,128,88,205,88,92,150,146,150,136,184,112,214, +85,236,102,170,153,210,160,150,224,150,208,188,176,222,143,238,172,164,190,198, +239,237,88,242,120,230,120,48,44,48,45,152,12,154,121,152,80,14,65,48, +44,82,121,82,44,116,121,116,20,230,70,196,111,152,136,86,245,86,204,12, +204,220,188,242,171,244,144,118,181,169,56,244,57,12,30,66,15,118,72,62, +93,98,92,30,233,30,84,118,241,112,200,136,201,30,124,28,125,116,124,58, +201,58,124,86,201,86,80,148,140,148,130,186,102,216,79,232,92,166,147,210, +156,148,220,148,206,186,178,216,141,238,162,148,174,178,188,200,218,218,247,231, +40,18,83,48,24,84,67,114,26,236,75,148,80,100,245,100,118,100,119,36, +164,100,165,6,164,50,225,50,166,116,167,194,130,134,95,190,224,134,196,180, +158,216,93,241,46,18,85,52,16,76,88,76,54,130,19,166,64,246,65,116, +106,160,65,120,112,104,233,104,92,226,247,226,170,226,171,13,36,18,73,56, +12,98,54,98,52,214,91,182,90,110,106,96,118,70,120,58,120,28,188,28, +188,92,198,96,231,94,92,128,198,128,182,168,142,208,85,238,238,230,182,208, +144,176,117,129,20,48,103,48,20,136,46,100,67,48,46,212,46,108,88,108, +89,206,46,186,89,186,122,188,122,60,226,60,227,186,174,246,175,10,122,110, +227,110,122,162,227,163,46,192,46,54,212,54,213,190,46,112,213,112,46,170, +213,170,128,244,129,9,36,200,36,54,78,54,79,194,36,172,79,172,114,186, +114,60,222,60,223,186,114,112,223,112,114,164,223,164,168,244,169,9,78,12, +42,88,19,120,58,244,59,56,104,190,104,68,230,68,231,188,104,116,231,116, +104,168,231,168,164,246,165,11,148,246,190,238,190,48,74,48,75,150,34,152, +191,152,122,12,105,48,74,82,191,82,74,116,191,116,230,112,146,178,82,210, +27,231,36,22,73,56,16,78,57,114,24,228,69,140,98,68,98,30,224,30, +225,66,136,54,114,80,93,102,172,58,215,94,82,128,239,128,156,244,157,86, +70,212,114,180,155,128,236,210,200,188,176,158,159,129,60,12,32,148,89,194, +14,74,90,72,82,130,62,184,19,224,230,28,122,28,122,126,112,186,87,230, +144,74,219,74,122,118,241,118,148,118,148,242,181,220,180,118,190,166,214,208, +241,230,226,144,199,177,96,62,28,164,101,154,24,222,103,200,70,18,26,100, +71,98,124,188,124,64,224,64,225,188,174,244,175,10,124,114,225,114,124,166, +225,167,42,18,79,54,16,74,88,74,46,136,19,158,60,244,61,118,98,154, +61,114,114,188,114,64,222,64,223,184,168,244,169,10,114,114,223,114,114,164, +223,165,36,30,75,58,16,88,55,118,26,232,67,154,90,106,90,70,224,70, +225,106,152,14,152,84,146,140,120,196,69,238,166,122,166,220,180,236,212,236, +232,224,239,205,104,10,145,40,32,88,32,52,226,52,227,86,54,210,54,100, +204,100,205,208,128,248,129,66,54,144,203,144,54,188,205,189,64,12,34,152, +101,206,14,78,90,78,84,142,58,198,25,230,152,12,181,36,110,84,110,50, +228,50,229,82,124,210,124,102,220,102,221,206,170,246,171,66,124,144,221,144, +124,186,221,187,32,48,225,48,12,152,243,152,72,152,73,10,180,152,181,8, +72,82,181,82,72,116,181,116,118,168,77,210,156,166,201,208,58,152,58,232, +223,233,38,108,39,22,88,110,89,8,110,102,152,86,188,56,208,28,107,28, +226,102,188,92,150,66,130,46,117,28,64,242,64,124,186,124,186,236,157,244, +66,160,187,160,64,196,187,197,38,68,21,126,82,72,101,110,62,244,63,14, +96,40,237,40,90,184,243,184,122,184,122,68,210,68,211,184,166,68,173,12, +144,200,97,240,178,202,231,240,122,98,211,98,122,126,211,126,122,154,211,155, +38,22,81,52,20,80,63,112,24,238,59,152,178,26,221,72,156,12,106,62, +203,54,84,94,237,94,152,68,118,122,77,154,234,160,200,140,165,94,160,124, +128,158,97,180,182,150,144,186,101,210,210,172,172,210,124,234,89,245,26,40, +239,40,44,78,223,78,132,78,133,10,26,242,48,218,58,188,62,158,62,112, +208,112,209,180,208,166,63,166,132,166,133,113,70,40,50,106,27,140,218,82, +59,82,54,150,207,150,20,224,241,224,130,224,131,17,38,36,17,96,110,72, +27,72,30,130,107,130,28,212,111,182,70,14,71,196,222,108,128,108,128,30, +222,30,223,108,128,70,223,70,176,106,177,30,112,152,232,148,228,206,214,224, +181,226,164,122,160,168,146,200,122,220,95,235,34,40,17,118,68,244,69,12, +104,76,27,76,18,168,101,132,136,34,124,88,111,118,234,78,127,78,122,146, +231,146,100,228,247,228,176,228,177,13,130,24,78,40,29,48,14,116,245,116, +24,234,54,216,74,194,86,164,90,136,91,36,176,242,177,15,94,60,26,162, +95,150,70,16,18,98,71,94,12,216,99,196,210,68,128,68,128,30,208,30, +209,68,216,178,114,178,114,102,214,102,215,178,114,142,215,142,236,204,230,222, +216,234,176,234,164,220,165,69,134,78,135,8,88,32,39,86,184,30,243,74, +186,60,124,98,74,116,17,128,78,244,78,116,206,116,207,240,78,150,207,150, +78,184,207,184,78,218,207,219,230,56,48,56,48,114,25,166,48,92,116,92, +116,110,110,132,94,136,75,132,178,18,205,40,142,18,152,76,172,122,204,154, +222,158,230,152,239,132,206,78,176,120,127,156,16,232,241,232,62,232,62,174, +196,174,197,232,104,232,105,174,148,232,149,175,144,26,80,36,37,40,18,72, +163,72,92,244,93,34,60,160,61,88,20,114,61,114,16,148,61,142,126,88, +126,138,132,152,150,154,165,130,162,108,127,116,22,220,93,158,158,204,93,154, +186,172,187,48,224,12,224,238,197,219,18,236,32,210,42,172,46,146,46,32, +94,32,94,224,82,240,69,242,46,90,95,90,46,148,95,148,140,32,117,118, +234,78,129,78,128,144,227,144,110,224,245,224,178,224,179,13,20,132,72,122, +146,78,184,32,35,32,238,126,160,110,100,70,67,32,52,164,199,164,20,220, +233,220,126,220,127,123,42,172,43,40,36,236,64,204,78,170,82,134,83,12, +106,36,239,36,122,202,122,94,222,94,222,198,203,204,172,244,173,37,42,104, +58,78,81,20,218,70,63,70,26,132,233,132,132,10,132,98,124,154,98,198, +29,244,230,236,180,210,129,133,28,24,50,48,62,72,70,100,74,134,74,166, +72,190,62,220,48,230,35,228,88,16,50,70,25,92,20,174,71,112,100,170, +101,52,130,16,130,162,118,206,97,240,150,32,245,32,192,244,193,32,160,200, +160,84,230,84,230,198,219,201,54,16,81,50,16,68,113,68,17,236,52,68, +52,130,42,186,17,236,52,118,92,118,92,198,88,236,61,242,160,10,136,62, +109,98,240,54,141,54,108,140,220,116,216,178,212,190,201,192,174,202,175,78, +136,98,136,210,140,234,218,234,236,222,243,203,28,22,73,56,16,82,61,110, +28,236,59,148,212,110,94,110,94,34,212,34,213,110,80,138,111,196,222,136, +191,196,64,228,243,228,94,72,213,72,132,228,133,120,172,228,173,121,34,22, +79,54,14,102,56,102,56,234,95,194,100,52,229,52,80,98,245,98,164,98, +165,8,88,146,239,146,120,166,153,202,200,114,200,242,171,247,216,130,216,36, +60,36,60,126,44,192,21,228,60,102,217,103,22,36,190,36,190,174,212,228, +222,238,232,234,241,208,164,64,84,80,29,84,154,168,40,168,40,122,156,122, +157,168,146,184,181,240,16,226,163,212,98,218,99,89,10,112,241,112,126,246, +127,13,26,34,241,34,26,164,66,132,88,100,117,34,84,238,84,116,204,116, +205,234,84,206,205,207,16,64,95,64,12,154,93,124,58,8,58,238,33,226, +158,6,124,66,91,100,154,14,190,62,239,102,116,108,211,108,112,240,112,150, +208,150,209,240,112,218,209,219,34,224,34,40,96,40,97,218,34,114,97,114, +34,196,97,196,132,114,159,162,112,80,243,80,198,12,198,232,161,241,80,14, +42,84,19,114,58,242,59,56,84,102,249,102,168,246,169,13,126,10,90,56, +62,78,17,100,122,16,158,54,235,96,110,60,139,84,116,208,70,242,70,96, +180,96,180,160,71,160,70,128,181,128,110,180,217,238,210,162,161,207,60,18, +36,84,21,110,82,100,96,66,45,66,92,192,58,228,59,104,220,148,120,148, +120,76,220,76,221,148,204,182,237,240,98,230,223,218,168,222,169,15,110,12, +145,38,34,86,34,48,220,48,221,84,70,80,117,110,48,116,97,144,20,164, +237,164,140,68,140,128,128,178,90,214,33,240,146,186,227,241,36,22,81,56, +10,98,58,98,58,216,97,176,214,124,122,124,122,30,214,30,215,124,150,162, +93,238,188,164,243,231,204,124,52,124,52,60,206,60,207,124,128,10,128,138, +112,194,70,222,19,236,68,142,104,186,152,212,198,224,239,227,92,16,70,72, +43,108,208,58,77,58,24,132,235,132,130,58,130,90,122,146,98,190,68,216, +27,232,224,230,176,202,148,164,135,133,76,16,40,96,19,128,56,244,57,62, +82,50,243,50,220,138,104,138,104,90,220,90,221,138,162,12,162,158,144,200, +85,238,118,156,138,188,182,218,239,235,50,70,216,70,216,26,50,26,50,110, +38,188,19,230,82,92,117,122,208,92,175,126,66,140,237,140,144,244,145,84, +58,222,104,186,145,142,236,216,192,190,145,141,43,54,42,56,36,134,102,134, +94,228,63,238,14,34,90,34,87,134,12,190,85,178,224,126,130,126,130,58, +224,58,225,126,176,8,176,138,166,192,142,220,113,240,128,144,152,180,180,206, +241,235,62,16,36,154,103,212,16,82,96,82,88,142,60,202,25,236,196,52, +237,110,172,12,120,102,225,92,132,244,132,142,214,142,215,242,132,218,215,219, +14,74,237,74,36,120,139,120,28,230,149,204,88,216,89,120,148,12,156,92, +168,156,192,214,208,232,220,238,234,226,241,206,182,24,213,55,48,32,209,32, +18,100,239,100,84,138,33,206,178,142,233,196,134,100,134,232,107,239,24,110, +237,110,36,224,223,224,130,224,131,21,14,98,245,98,58,28,58,228,233,228, +116,18,116,176,186,176,187,17,20,74,101,74,68,242,69,8,20,170,69,90, +104,140,69,100,108,58,245,58,148,12,183,46,176,240,177,58,126,208,126,110, +226,110,226,204,207,213,16,40,241,40,200,98,56,98,56,66,200,66,201,98, +14,156,245,156,36,128,206,128,207,204,36,186,207,186,128,8,128,240,93,247, +14,72,81,72,12,162,79,128,60,10,60,244,31,222,110,76,239,76,104,126, +161,126,88,222,167,194,132,126,133,204,176,10,176,104,184,162,198,206,212,228, +218,234,232,232,241,198,202,28,225,57,20,40,115,40,26,82,111,66,72,12, +72,112,51,104,218,16,136,30,136,74,131,96,136,58,235,58,188,110,189,58, +108,96,143,116,16,126,241,126,56,150,197,150,58,174,197,174,62,242,62,196, +190,196,191,240,62,224,191,225,26,26,67,60,16,226,42,208,62,208,112,230, +239,232,12,108,52,108,53,208,80,68,149,68,74,138,145,102,116,14,116,196, +89,184,230,22,162,34,162,130,137,198,162,92,241,92,204,92,205,213,20,46, +101,46,22,100,95,76,68,8,68,144,47,136,114,50,200,44,194,118,200,132, +222,132,234,122,239,104,116,76,167,106,156,8,150,72,132,108,97,134,22,166, +202,164,196,216,180,238,155,242,118,142,106,192,82,218,25,239,190,100,66,100, +66,26,190,26,191,100,66,62,191,62,14,132,239,132,70,158,48,210,25,240, +60,178,78,200,102,218,118,226,138,226,174,230,239,228,128,132,129,226,128,176, +209,177,32,198,32,46,72,46,73,188,32,168,73,168,100,42,193,42,88,72, +233,72,148,72,149,10,220,34,152,90,95,116,128,102,128,130,134,140,216,140, +235,124,212,96,164,112,129,118,118,246,118,164,212,164,213,244,118,196,213,196, +118,228,213,229,26,200,26,54,66,54,67,188,26,170,67,170,118,20,98,60, +83,80,158,48,105,48,136,82,119,48,190,16,172,62,159,86,238,48,179,48, +210,84,195,48,88,102,227,102,114,122,98,170,81,200,142,190,109,148,204,126, +184,180,173,200,228,190,197,152,72,230,239,230,152,230,153,103,34,26,69,62, +24,228,50,206,66,206,100,222,136,226,235,224,18,108,58,108,59,206,214,22, +142,36,95,40,76,80,237,80,204,190,110,190,110,126,204,126,205,190,154,126, +155,35,86,14,50,88,19,130,62,244,63,66,84,98,247,98,96,222,235,222, +164,222,165,15,80,18,44,92,19,122,58,244,59,64,102,58,229,58,86,104, +245,104,166,104,167,12,96,148,237,148,196,116,196,240,163,228,122,170,153,201, +96,26,52,32,25,36,70,246,71,30,30,62,51,90,112,56,93,88,18,108, +105,108,20,200,48,160,71,116,102,156,71,124,122,144,229,144,110,186,241,186, +174,242,175,108,116,114,148,98,186,70,212,30,117,30,240,108,190,94,160,70, +131,31,56,10,32,80,19,102,74,96,90,62,39,62,90,180,54,218,55,104, +148,10,124,70,101,106,168,248,169,70,122,214,122,118,218,118,218,206,199,210, +240,56,131,57,204,24,118,38,50,42,50,232,119,184,50,114,223,114,134,36, +134,96,140,136,160,190,180,218,192,226,206,232,220,230,224,218,229,199,108,14, +145,44,12,58,241,58,56,216,56,108,200,108,200,210,173,216,128,244,129,59, +34,56,21,118,76,52,93,86,60,244,61,12,108,56,225,56,90,102,245,102, +166,102,167,10,94,148,239,148,198,114,198,240,171,244,120,170,147,199,112,16, +149,44,32,92,32,54,226,54,227,92,52,90,205,90,114,98,48,144,187,138, +156,108,213,152,46,182,209,182,20,228,233,228,130,228,131,149,40,16,81,50, +16,76,92,76,48,134,19,158,60,240,61,118,102,156,61,118,124,154,124,26, +212,26,213,150,168,66,166,116,156,160,132,198,110,218,91,232,176,138,176,210, +180,222,194,228,218,228,232,218,239,197,30,24,69,62,12,98,54,98,54,230, +89,196,78,78,239,78,198,26,223,56,172,10,172,102,178,152,188,196,212,228, +224,236,232,228,239,208,86,124,159,124,90,226,167,200,126,124,127,213,84,242, +85,8,30,36,30,174,85,158,154,8,128,80,109,112,234,66,137,66,134,102, +152,152,174,186,204,216,233,232,104,236,138,206,156,188,176,152,192,104,199,67, +206,20,150,32,98,38,43,40,42,86,215,86,14,140,241,140,96,240,132,238, +133,35,74,12,107,48,16,60,241,60,184,12,147,60,128,60,115,98,66,248, +66,104,192,104,193,244,66,144,193,144,66,182,193,182,66,222,193,223,108,12, +143,36,36,94,36,50,220,50,221,92,20,124,239,124,168,72,168,236,131,244, +70,150,113,191,30,46,225,46,40,84,213,84,16,120,243,120,124,8,114,90, +92,140,62,186,23,218,92,164,231,164,182,132,182,238,147,244,104,184,133,213, +14,68,97,68,14,158,89,126,58,10,58,236,33,218,226,14,158,28,107,34, +118,52,139,80,160,42,175,74,104,126,104,96,230,96,231,126,218,48,191,88, +118,138,206,138,184,182,156,208,128,226,103,238,240,232,208,220,176,198,148,172, +138,154,135,139,84,14,46,68,19,94,58,160,59,52,126,12,163,40,224,54, +67,54,216,82,67,82,214,114,69,114,232,146,67,146,140,146,141,54,66,244, +66,174,198,174,199,242,66,224,199,225,214,20,114,32,45,30,58,52,87,88, +122,48,145,86,206,46,169,94,34,138,34,102,224,102,225,138,60,138,180,138, +148,178,110,208,70,226,27,236,228,234,198,228,158,214,120,188,98,166,85,139, +126,12,159,36,20,62,41,102,14,152,53,134,238,44,58,44,58,126,56,164, +46,206,25,240,122,70,92,76,92,138,218,138,218,74,187,74,122,106,93,106, +188,104,219,104,84,168,202,168,170,202,120,228,73,242,240,236,194,226,164,216, +130,192,115,168,154,168,155,59,68,12,109,42,184,10,149,48,202,120,56,120, +56,54,200,54,201,120,56,88,201,88,126,120,127,54,14,152,239,152,62,246, +62,182,196,182,197,242,62,226,197,227,20,40,239,40,96,66,97,8,166,62, +167,8,146,66,173,84,28,84,96,84,70,116,71,208,18,230,99,202,38,222, +39,132,70,150,105,150,108,94,231,94,158,94,120,140,205,134,182,110,215,144, +124,160,122,200,108,226,89,240,156,242,157,158,196,158,196,218,198,232,216,238, +232,230,241,213,16,74,103,74,66,246,67,12,18,172,67,92,98,140,67,106, +238,32,120,32,120,224,243,224,212,62,192,118,170,156,141,188,142,76,180,120, +204,154,221,185,16,78,99,78,60,246,61,12,16,174,40,132,61,84,94,138, +61,104,144,12,179,40,100,54,237,54,154,64,110,124,215,114,182,82,231,130, +126,144,120,194,108,218,87,236,160,236,161,146,196,144,196,220,202,236,210,238, +230,234,238,224,243,211,12,34,107,34,14,144,36,112,52,70,59,34,48,84, +88,84,84,132,66,176,46,202,19,224,72,156,45,134,138,24,113,90,228,62, +125,62,104,110,239,110,168,244,169,8,88,212,130,174,169,118,238,208,200,164, +169,111,12,70,101,70,18,154,93,118,62,10,62,242,35,222,112,30,208,30, +163,80,138,64,187,98,104,112,236,112,213,148,172,112,172,236,147,245,12,58, +103,58,64,16,20,134,95,134,14,196,97,180,62,244,63,84,160,14,126,62, +89,98,156,20,176,50,202,72,239,90,122,84,197,84,112,244,112,118,154,118, +154,240,139,244,112,154,155,154,112,190,155,190,182,206,183,120,216,104,216,240, +193,231,14,102,137,102,72,102,73,10,72,56,123,56,74,120,74,234,53,240, +48,148,19,210,102,148,129,190,134,38,218,38,202,118,172,186,115,232,236,230, +192,192,164,140,152,80,149,39,76,14,48,58,21,92,130,72,67,30,38,88, +111,88,18,130,125,130,38,242,38,168,108,168,109,240,38,220,109,220,74,168, +75,88,132,36,220,36,183,88,146,64,199,102,130,114,238,114,221,154,184,114, +184,240,157,247,34,22,67,50,18,90,51,116,20,226,53,152,66,98,153,98, +108,98,109,10,108,50,145,50,156,38,220,38,208,108,192,160,164,202,127,238, +232,230,200,190,178,140,168,88,167,38,112,114,112,224,91,228,60,198,89,138, +134,140,155,183,14,214,105,192,20,42,94,42,66,82,67,200,34,208,35,98, +100,128,67,128,144,12,177,40,106,54,233,54,182,82,223,126,154,62,114,118, +205,110,128,140,126,186,116,214,91,240,160,236,161,140,194,138,194,220,200,236, +220,236,232,230,237,211,36,68,204,68,191,138,24,138,222,138,220,184,212,200, +188,206,173,206,122,242,123,10,178,24,229,57,32,178,32,30,88,30,89,174, +60,66,60,152,52,194,40,214,23,240,68,186,101,220,108,40,229,40,104,80, +232,80,217,110,166,80,167,6,126,96,157,120,114,124,149,152,108,168,241,168, +176,94,172,168,154,204,134,222,109,238,180,188,235,237,54,14,89,38,16,48, +139,48,112,106,38,106,38,74,112,74,113,106,28,134,108,134,76,162,76,232, +49,240,18,190,123,176,134,126,185,172,126,78,206,76,206,136,210,184,218,226, +222,238,236,238,247,208,162,12,162,116,152,172,130,210,105,239,60,8,87,28, +18,36,143,36,114,88,44,88,44,60,112,60,113,88,28,110,106,110,78,134, +78,180,76,188,57,190,24,158,127,140,130,62,208,56,208,136,214,160,220,172, +228,174,238,170,249,146,142,94,183,132,172,10,168,72,162,106,150,138,121,180, +52,196,23,238,94,200,109,236,146,194,165,232,196,192,233,233,24,36,235,36, +210,92,50,92,50,62,210,62,211,92,94,62,95,8,160,62,161,8,54,120, +177,120,18,144,245,144,122,144,123,102,74,240,74,172,200,172,201,240,74,226, +201,226,74,198,201,198,214,106,114,166,23,196,106,92,107,62,156,92,157,63, +202,72,56,72,56,20,202,20,203,72,56,46,203,46,46,102,183,102,14,130, +243,130,126,130,127,78,76,242,76,162,194,162,195,242,76,194,195,194,76,224, +195,224,224,80,168,122,110,154,56,172,19,183,26,208,26,34,72,34,73,202, +26,108,73,108,26,180,73,180,218,58,104,58,104,22,216,22,217,58,142,58, +143,22,178,58,179,22,100,92,189,92,86,124,241,124,152,124,153,70,120,242, +120,158,208,158,209,240,120,190,209,190,120,222,209,222,216,78,158,138,112,172, +89,187,210,62,40,62,40,24,208,24,209,62,46,94,189,94,14,128,243,128, +122,128,123,70,228,84,134,140,74,160,19,172,72,244,72,160,198,160,199,242, +72,192,199,192,72,224,199,224,98,24,99,62,154,24,155,63,216,68,56,68, +56,26,216,26,217,68,108,68,109,26,162,68,163,26,86,76,58,112,27,140, +68,100,222,100,222,134,220,196,212,228,198,238,177,238,176,174,66,174,66,140, +176,140,177,174,162,186,189,220,46,218,177,206,120,210,121,113,198,18,138,28, +61,30,26,62,233,62,130,102,131,28,28,122,70,108,100,84,121,62,224,122, +172,94,131,72,132,108,92,140,52,158,19,170,122,114,152,136,200,156,243,164, +130,146,130,222,124,234,114,238,97,238,70,166,103,186,42,222,131,194,212,230, +168,206,131,190,184,166,145,197,112,18,40,38,40,104,206,104,206,34,147,34, +146,68,207,68,108,68,41,68,44,122,44,236,95,204,66,164,95,184,70,130, +97,148,122,120,122,230,163,202,142,132,171,150,140,166,171,184,190,118,190,160, +194,190,206,220,218,236,226,240,232,238,236,226,243,207,24,226,42,194,50,158, +52,128,52,28,218,28,218,58,53,58,210,78,146,88,81,88,206,142,96,142, +96,112,206,112,207,142,182,184,203,216,106,210,191,200,150,204,151,88,80,244, +80,170,226,170,226,238,195,245,24,84,229,84,164,24,201,60,126,244,127,12, +20,216,54,190,84,150,115,84,236,208,200,182,168,146,150,120,135,85,32,32, +69,70,20,222,48,206,62,206,76,214,94,224,112,230,124,232,241,230,12,110, +56,110,57,206,178,24,207,56,86,78,223,78,150,212,151,10,82,176,110,150, +151,90,220,166,180,120,151,91,18,76,93,76,60,242,61,10,18,164,44,118, +61,84,92,136,61,100,102,100,134,142,161,186,98,56,152,56,144,104,128,154, +83,206,166,112,191,158,166,76,247,76,216,12,216,232,183,241,20,50,239,50, +202,138,62,138,62,88,200,88,201,138,26,224,68,198,125,138,234,216,194,196, +166,170,141,138,130,246,131,13,178,14,211,42,230,58,46,58,46,158,38,198, +19,234,98,160,47,126,138,8,146,108,160,164,184,206,206,228,216,232,226,230, +239,198,114,218,148,196,188,146,211,103,42,122,43,26,90,128,91,18,108,112, +138,100,170,80,192,58,208,34,109,34,226,116,200,108,174,94,154,76,140,56, +125,34,118,126,145,142,38,154,219,154,16,226,239,226,76,174,107,212,178,170, +143,227,122,84,36,84,36,26,122,26,123,84,28,114,135,114,24,152,139,136, +36,58,123,58,80,26,81,142,136,80,230,80,215,112,184,80,184,154,165,160, +162,42,197,80,140,24,220,24,185,66,44,186,217,186,20,228,241,228,132,228, +133,153,120,12,149,38,236,50,50,50,50,132,46,180,21,236,68,106,229,106, +112,70,112,162,178,162,179,66,94,188,65,242,122,194,137,234,158,190,175,228, +194,184,227,235,36,26,55,54,130,22,105,52,22,72,139,72,80,124,81,10, +24,130,81,74,126,116,81,80,16,158,118,158,102,194,80,216,56,228,33,238, +76,132,46,190,121,218,178,10,160,70,139,102,242,76,159,76,124,238,160,212, +186,178,202,138,208,102,213,76,156,110,170,158,190,190,241,235,26,24,59,46, +14,88,51,112,28,230,59,148,72,48,161,48,148,132,82,132,82,82,148,82, +149,132,116,242,117,10,66,206,117,140,148,176,117,142,162,106,176,68,189,8, +218,104,230,68,179,68,190,100,188,150,180,184,166,210,145,236,240,234,220,210, +204,176,191,135,20,58,132,56,110,100,76,132,31,154,84,14,52,94,137,132, +222,132,160,132,160,46,222,46,223,132,56,174,33,230,118,152,153,188,198,168, +235,216,94,164,94,216,104,230,158,230,178,220,185,209,18,220,34,182,42,140, +42,28,138,28,138,74,43,74,64,210,64,122,142,122,142,204,125,208,102,242, +103,88,180,172,181,46,222,12,222,236,197,219,30,36,227,36,56,134,56,72, +204,72,204,130,179,134,116,72,127,36,106,122,107,72,152,122,153,72,20,156, +235,156,124,128,78,188,215,238,176,156,160,186,126,212,92,228,45,239,14,68, +83,68,16,156,85,114,56,10,56,238,29,208,146,8,177,30,94,40,235,40, +94,68,111,94,90,154,121,112,222,66,195,100,200,116,227,148,161,46,183,74, +176,116,191,154,180,74,128,148,183,136,162,48,128,96,165,94,86,180,245,180, +160,244,161,157,110,14,145,38,18,52,233,52,14,114,241,114,186,148,68,148, +68,82,186,82,187,148,20,214,58,196,103,156,136,206,88,238,91,168,134,160, +158,194,192,220,233,238,204,162,163,199,20,228,38,206,50,164,50,34,200,34, +200,188,167,192,124,34,124,200,128,220,146,224,210,224,226,216,237,194,50,84, +201,84,50,134,201,135,42,174,43,44,84,16,84,136,74,188,58,218,37,236, +120,194,120,68,222,68,222,168,220,188,197,194,170,246,171,11,16,78,101,78, +60,244,61,12,18,176,61,94,96,148,61,108,164,12,132,72,93,110,238,96, +188,60,161,22,222,102,113,102,112,158,221,158,96,226,239,226,164,226,165,103, +16,74,95,74,14,158,91,128,58,14,58,240,31,246,162,10,128,70,91,106, +158,18,184,60,210,82,241,102,112,104,215,104,114,160,217,160,92,224,237,224, +162,224,163,105,38,32,225,32,32,96,32,58,230,58,231,94,130,116,131,32, +52,82,111,82,52,102,111,102,154,80,211,80,156,102,211,102,26,148,115,148, +74,246,75,116,24,214,75,154,112,196,75,162,132,244,132,132,216,132,217,242, +132,158,217,158,132,188,217,188,132,220,217,221,24,42,104,42,98,96,84,138, +56,188,21,224,36,88,117,192,94,234,140,204,170,170,196,124,210,78,216,44, +121,44,138,44,146,92,162,140,178,176,206,208,237,233,28,48,233,48,131,10, +128,10,128,102,120,156,98,190,66,218,25,240,232,232,190,212,162,190,142,160, +125,126,106,62,72,94,37,114,46,68,107,110,44,130,101,174,100,124,47,174, +152,68,215,108,208,64,153,112,156,128,219,174,216,122,161,173,36,20,79,56, +12,96,56,96,56,222,93,178,140,14,112,70,83,108,166,16,199,52,122,242, +123,52,130,68,239,68,130,118,231,118,130,162,229,162,130,212,247,212,178,212, +179,69,130,12,130,232,95,238,26,78,96,78,72,144,50,176,21,204,228,202, +186,164,160,126,131,70,222,54,147,103,30,228,30,40,74,40,75,220,30,94, +75,94,30,146,75,146,30,202,75,202,214,22,152,32,99,36,92,70,235,70, +88,120,243,120,92,178,237,178,96,224,227,224,162,224,163,32,124,178,125,70, +202,178,203,71,106,18,58,32,21,36,14,86,109,86,66,242,67,30,16,182, +67,102,104,150,67,110,126,14,155,56,208,10,179,66,212,136,126,136,126,72, +212,72,213,136,96,232,120,218,142,188,148,162,149,136,184,136,184,212,196,230, +224,230,234,218,239,197,32,194,32,46,78,46,79,186,32,162,79,162,184,54, +223,116,150,16,100,112,213,100,66,236,98,218,124,188,132,154,135,108,236,198, +224,226,208,232,190,230,178,222,179,105,24,222,24,36,64,36,65,210,24,88, +65,88,24,140,65,140,24,194,65,194,222,18,152,30,91,32,106,48,131,76, +148,42,169,74,214,40,189,80,90,120,90,88,228,88,229,120,120,106,104,142, +83,172,74,238,108,208,134,172,142,134,109,134,102,166,125,184,154,132,225,132, +198,244,199,102,168,148,154,186,233,187,36,20,36,180,21,232,72,208,73,36, +104,224,105,14,120,26,241,26,140,186,140,74,218,74,219,182,164,74,181,26, +182,94,178,160,166,200,119,238,194,188,243,231,212,20,146,30,41,32,66,48, +95,78,118,44,143,76,198,42,173,84,34,126,34,90,224,90,225,126,82,106, +56,146,31,172,26,236,60,220,86,194,106,156,110,136,63,136,60,168,87,192, +130,134,215,134,142,148,132,190,229,190,180,244,181,109,38,20,79,60,12,98, +56,98,56,220,101,178,118,18,151,56,208,14,175,70,214,138,118,138,118,76, +212,76,213,138,86,238,110,224,134,200,144,172,145,138,238,204,226,232,190,232, +180,224,181,139,18,36,107,36,16,142,42,110,58,70,63,36,48,216,48,102, +94,102,95,206,48,178,95,178,118,24,241,24,134,192,134,78,222,78,223,190, +176,24,163,78,176,106,176,156,164,196,134,222,99,238,188,198,241,239,46,14, +73,48,130,14,101,56,20,62,149,62,28,234,52,212,74,174,84,134,85,62, +126,92,127,172,42,88,42,150,127,150,110,238,140,210,156,172,162,142,162,32, +222,32,222,226,187,238,162,86,223,86,162,140,223,141,28,74,17,140,58,14, +58,152,44,204,21,238,96,60,59,108,92,198,57,164,218,20,162,36,122,40, +116,124,237,124,172,72,172,240,149,244,134,156,114,198,93,228,204,158,239,223, +14,56,133,56,10,166,139,166,46,166,47,14,104,166,105,16,46,92,105,92, +46,128,105,128,56,188,19,236,82,186,113,214,226,26,186,36,154,40,154,162, +119,244,154,104,245,104,200,242,201,105,14,76,71,76,16,148,75,124,50,12, +50,236,21,224,68,176,161,176,96,176,97,16,140,176,141,16,76,62,161,62, +96,100,141,100,96,138,141,138,102,192,71,236,124,192,147,214,232,28,176,42, +176,172,153,238,244,104,177,104,214,104,215,245,28,194,28,48,62,48,63,186, +28,164,63,164,76,62,161,62,76,172,161,172,98,172,99,20,140,172,141,18, +98,98,141,98,98,136,141,136,106,190,69,228,126,186,145,212,232,26,176,44, +176,166,149,240,242,100,177,100,210,242,211,101,202,128,56,128,56,34,202,34, +203,128,56,80,203,80,130,128,131,34,50,168,21,228,114,148,153,188,200,166, +237,218,82,164,82,216,94,238,154,238,176,230,189,207,116,20,70,30,33,34, +18,88,135,88,80,244,81,28,22,178,81,98,120,144,81,108,190,26,118,208, +225,194,194,122,239,221,40,32,216,32,216,206,208,226,169,234,24,78,179,78, +150,180,60,180,60,126,150,126,151,181,118,60,42,186,115,178,82,18,34,112, +87,112,226,58,142,182,225,174,188,16,136,114,189,110,16,224,241,225,22,36, +231,36,74,36,66,84,48,122,25,154,61,96,60,96,112,96,102,148,78,190, +27,236,60,142,87,176,154,36,154,208,164,224,216,224,235,192,220,88,155,147, +12,140,117,140,44,140,44,30,113,30,102,66,45,66,102,102,45,102,84,164, +115,218,98,192,28,216,59,140,112,80,243,80,118,44,216,44,216,114,119,114, +170,240,171,8,122,152,227,152,116,188,235,189,48,52,209,52,16,104,241,104, +128,104,129,6,26,156,229,156,178,118,178,242,162,248,149,250,74,172,109,215, +108,84,42,84,42,30,108,30,109,84,32,240,32,122,118,122,118,236,99,238, +32,170,119,170,60,218,61,122,88,218,89,122,130,80,203,80,194,178,152,178, +152,122,194,122,195,178,134,34,226,34,226,230,195,237,40,230,40,44,212,44, +213,226,40,202,213,202,100,44,100,112,84,144,67,158,146,44,146,148,189,155, +78,14,40,92,17,120,60,242,61,54,102,36,230,36,230,234,193,242,92,82, +207,82,182,182,118,182,118,122,182,122,183,183,74,16,36,96,17,122,54,240, +55,62,106,46,106,200,157,146,138,14,173,76,134,236,174,208,194,184,202,152, +208,64,209,28,242,224,199,169,60,16,42,74,21,108,86,100,98,60,49,60, +54,110,54,228,101,192,112,84,209,84,190,186,130,186,130,126,188,126,189,186, +120,40,230,40,230,240,191,245,228,180,220,206,204,222,62,222,52,200,52,36, +200,36,200,116,53,117,16,74,105,74,62,244,63,10,18,168,63,82,100,140, +63,98,146,20,132,72,111,120,184,12,202,74,235,120,164,102,144,162,112,222, +213,208,188,170,231,235,80,8,64,60,27,94,120,70,75,28,168,10,150,66, +119,92,228,92,184,60,165,24,20,108,239,108,14,212,245,202,184,244,185,108, +74,208,75,108,74,140,185,140,74,172,185,173,76,16,72,76,27,134,118,108, +75,62,170,16,156,94,119,132,232,134,186,96,167,42,20,216,51,168,116,148, +153,182,194,164,237,212,84,162,84,210,88,228,106,232,160,232,178,222,187,201, +60,24,40,92,19,128,84,26,121,116,76,104,38,208,107,196,92,160,119,216, +124,32,243,32,144,192,144,82,220,82,221,190,170,82,183,32,182,112,182,164, +174,196,152,220,117,240,192,202,239,243,32,28,71,68,22,230,38,212,50,208, +66,208,94,224,116,232,243,230,14,108,58,108,59,208,106,18,143,50,204,18, +167,62,98,70,229,70,90,124,237,124,154,70,154,132,140,162,118,184,95,200, +222,200,186,162,155,135,106,14,147,42,38,96,38,56,218,56,219,96,22,126, +235,126,130,248,131,74,22,218,58,198,96,162,127,126,234,216,192,190,158,160, +137,127,42,24,71,66,12,100,56,100,56,224,95,178,138,18,116,78,87,132, +178,14,190,64,210,104,237,130,160,100,110,218,203,208,176,160,219,233,38,26, +81,62,12,100,60,100,60,222,91,180,138,60,181,82,104,26,210,26,165,74, +114,242,114,90,226,90,226,236,199,240,114,134,227,134,114,178,227,178,168,224, +169,91,10,76,89,76,16,162,89,124,54,12,54,240,27,228,138,28,108,40, +108,112,222,112,222,36,183,36,142,76,109,76,182,74,223,74,98,146,210,146, +188,188,150,218,95,240,120,146,140,178,178,212,239,234,162,146,163,11,14,240, +28,208,36,174,36,42,92,42,92,234,69,240,64,10,55,42,54,68,69,102, +10,130,93,130,56,152,71,188,154,26,126,36,126,114,226,114,226,36,195,36, +156,74,127,74,196,74,227,74,118,148,216,148,196,186,162,216,117,238,136,148, +154,182,184,212,239,236,176,148,177,11,12,68,77,68,14,148,73,102,50,10, +50,232,27,220,86,28,105,50,160,22,141,52,86,68,159,68,122,116,123,10, +82,118,123,68,152,106,123,74,76,144,148,144,134,178,110,206,75,226,118,122, +92,172,153,206,194,10,172,78,161,94,240,70,177,70,218,70,204,158,182,204, +145,236,174,100,190,170,214,212,237,237,24,188,24,52,62,52,63,182,24,162, +63,162,74,52,163,52,152,136,90,136,90,86,150,86,151,136,120,244,121,14, +66,216,121,142,154,182,121,154,190,16,176,88,165,114,220,106,236,70,181,70, +196,104,190,158,174,204,149,240,240,238,210,198,193,149,14,48,237,48,86,82, +87,10,166,82,167,8,30,118,184,114,176,228,135,240,118,72,112,152,84,200, +37,238,70,140,37,192,202,138,239,189,14,26,121,26,32,240,32,72,108,72, +109,236,32,176,109,176,32,212,109,212,60,26,60,92,56,118,45,156,82,26, +82,142,109,144,220,22,160,34,131,38,126,96,233,96,172,244,173,32,122,194, +173,110,236,196,173,115,70,10,36,82,17,112,54,246,55,50,130,18,91,68, +178,20,219,58,156,58,114,116,75,144,238,136,194,112,151,66,110,240,110,146, +204,146,205,238,110,214,205,215,32,40,223,40,48,70,211,70,18,98,239,98, +130,98,131,10,180,110,52,180,197,164,170,144,217,178,118,104,54,140,139,134, +130,172,130,238,105,246,92,194,35,230,160,192,221,227,24,32,61,66,18,230, +34,216,50,210,66,210,90,226,124,234,237,232,14,108,58,108,59,208,82,48, +231,48,214,130,100,130,100,86,212,86,213,130,154,218,155,10,84,196,122,168, +155,132,218,194,155,141,20,30,237,30,208,104,48,104,48,64,210,64,211,104, +102,104,103,30,158,104,159,30,16,162,241,162,130,244,131,120,64,124,97,150, +162,152,193,122,24,230,76,208,131,162,232,228,180,206,131,163,74,12,40,84, +15,120,52,242,53,60,88,30,239,30,224,104,100,104,100,64,224,64,225,104, +140,104,141,30,180,104,181,30,108,122,139,148,80,160,245,160,210,122,177,160, +160,244,161,118,86,224,161,162,236,224,161,165,40,14,63,46,18,58,135,58, +114,14,87,58,38,78,38,124,116,124,117,76,80,58,70,136,33,180,130,156, +148,128,154,104,154,32,214,32,214,156,191,162,154,74,215,74,214,114,155,114, +52,190,205,190,24,228,239,228,128,228,129,165,30,24,63,54,20,94,49,114, +24,232,59,156,80,18,103,52,66,72,161,72,146,20,117,72,146,92,147,176, +80,90,80,156,147,152,114,72,114,164,100,198,71,228,144,236,168,200,178,154, +178,36,226,36,226,236,193,242,178,98,227,98,226,152,179,153,112,14,145,40, +36,80,36,48,224,48,225,80,80,66,48,136,25,164,66,246,67,100,92,92, +233,92,112,244,112,132,214,132,215,244,112,174,215,174,112,222,215,222,160,92, +147,133,40,18,85,54,12,94,56,94,56,214,91,180,220,16,168,28,122,34, +122,132,114,182,89,236,122,98,245,98,188,98,189,244,158,136,235,189,12,78, +245,78,44,42,200,42,200,114,45,114,128,242,129,8,102,146,75,200,152,146, +185,198,54,132,54,166,48,202,23,240,208,130,209,243,10,32,119,32,28,242, +28,74,102,74,103,236,28,218,103,218,28,178,103,178,52,32,52,90,50,122, +39,150,78,32,78,132,103,134,174,10,126,70,219,56,194,30,231,70,158,86, +123,118,194,84,237,116,166,112,148,146,123,182,154,138,210,138,194,178,160,216, +125,240,144,152,164,186,194,216,237,239,16,44,245,44,96,74,97,8,164,74, +165,8,36,92,105,92,152,92,225,92,22,136,109,136,148,136,243,136,78,136, +78,236,51,242,52,158,21,210,98,158,121,190,154,164,119,220,206,162,239,212, +180,136,180,236,151,245,70,10,42,52,19,76,126,38,53,38,98,68,79,38, +166,8,129,64,236,38,147,38,200,66,179,38,192,162,66,162,66,80,194,80, +195,162,18,192,241,192,96,162,96,190,84,212,58,232,33,240,162,162,163,242, +66,108,195,108,66,134,195,135,198,72,198,30,62,30,62,72,199,72,210,162, +52,162,52,112,210,112,211,162,20,224,213,208,188,182,239,236,130,214,131,81, +34,244,34,28,90,28,58,104,80,128,92,148,88,180,59,192,100,44,233,44, +158,10,140,58,120,88,93,112,218,74,137,74,238,104,117,104,174,104,175,74, +124,246,124,136,214,136,214,240,189,246,124,168,215,168,124,200,215,201,32,246, +32,34,78,34,56,114,72,134,82,160,76,182,55,192,96,42,117,80,76,232, +90,220,106,214,118,214,128,224,144,230,162,232,245,230,78,114,112,114,113,214, +120,50,237,50,178,14,154,70,125,102,152,212,152,92,216,92,216,206,193,212, +152,128,217,128,152,160,217,161,96,58,22,156,93,146,72,14,24,92,73,90, +18,212,103,196,228,24,172,34,109,36,118,64,137,104,158,56,177,92,224,52, +195,104,98,136,245,136,166,100,126,180,239,232,206,136,196,172,164,208,132,224, +97,239,18,122,18,96,106,96,107,120,107,120,35,54,34,96,34,30,90,30, +91,96,34,60,62,60,63,96,38,242,38,126,84,126,84,240,69,242,38,158, +85,158,38,190,85,190,106,38,125,72,100,230,116,216,134,216,150,228,166,234, +239,230,112,126,126,126,127,216,130,44,239,44,182,14,162,58,131,92,160,70, +235,70,146,98,241,98,192,98,193,70,160,214,160,122,222,122,222,206,203,214, +160,148,223,148,160,174,223,175,16,48,93,48,64,48,46,96,19,134,48,216, +48,110,90,110,91,210,48,186,91,186,154,12,183,38,118,50,241,50,144,64, +132,106,115,136,166,118,139,84,206,64,192,110,179,132,230,128,201,90,108,166, +245,166,170,244,171,141,50,22,50,70,222,70,223,22,136,70,137,8,114,84, +84,134,49,172,32,238,88,230,134,212,170,184,196,150,210,118,95,118,102,152, +155,197,92,20,50,32,19,38,16,88,99,88,60,244,61,30,16,186,61,110, +92,146,61,114,100,44,239,44,220,132,114,132,114,70,220,70,221,132,208,142, +239,174,102,166,225,160,114,100,221,100,166,162,167,10,110,184,91,230,160,176, +181,198,210,186,241,222,136,182,136,220,144,234,186,234,198,222,203,211,18,234, +48,212,62,212,82,222,112,234,241,232,24,36,65,70,10,116,54,116,55,212, +98,20,137,52,76,66,235,66,194,16,161,66,146,66,120,94,87,110,120,204, +146,200,166,182,168,152,158,110,133,82,84,150,124,128,151,102,84,184,128,160, +163,132,210,88,163,122,224,180,194,154,165,133,28,238,28,34,72,34,48,98, +60,114,68,136,72,158,62,172,45,176,64,234,94,210,108,210,136,222,178,230, +239,228,100,210,100,116,77,116,86,40,105,78,130,14,161,44,116,58,235,58, +210,12,183,58,120,102,146,90,177,58,152,82,172,104,184,132,186,166,182,190, +164,200,149,200,116,142,148,124,173,104,120,176,152,160,183,132,226,88,183,124, +234,168,208,140,183,127,48,20,48,54,206,54,207,16,40,68,40,102,214,102, +215,66,126,102,127,10,44,134,211,134,14,164,243,164,82,188,29,230,170,188, +225,228,128,164,128,240,101,247,20,34,104,34,66,84,66,236,37,240,16,162, +103,112,132,84,122,148,105,188,202,84,224,132,239,186,172,14,172,230,137,237, +20,70,97,70,18,156,93,122,62,14,62,232,29,220,210,68,210,26,120,26, +120,68,211,68,112,190,112,100,220,100,221,186,166,122,166,158,160,186,142,210, +91,234,178,190,237,233,78,10,50,52,25,78,128,40,59,40,92,76,77,40, +166,10,146,52,129,74,238,40,153,40,200,74,179,40,44,98,194,98,195,194, +44,174,195,174,14,134,243,134,28,240,62,222,88,200,102,174,111,99,18,40, +237,40,84,66,85,12,172,66,173,10,114,54,139,72,12,82,245,82,24,134, +233,134,188,160,188,108,66,108,66,160,189,160,20,214,72,196,100,178,117,160, +138,216,82,238,83,190,136,176,156,198,184,216,214,226,237,232,214,170,169,207, +16,76,101,76,62,248,63,14,18,174,63,92,94,138,63,104,166,14,112,76, +223,66,186,32,235,78,156,90,115,126,194,92,239,122,170,114,138,156,107,182, +98,240,134,228,172,208,198,180,214,146,145,146,148,170,172,200,194,216,241,237, +28,202,28,52,72,52,73,192,28,172,73,172,154,10,94,78,209,66,180,34, +227,84,144,90,93,132,176,90,229,132,156,116,126,156,99,184,82,242,118,230, +150,212,178,184,200,148,133,148,136,170,162,202,196,222,237,237,84,62,20,156, +83,150,68,18,22,96,61,96,18,220,83,196,146,12,179,34,102,86,102,48, +224,48,225,74,134,72,110,110,87,138,114,246,115,108,140,92,243,92,152,242, +152,132,222,132,223,242,152,176,223,176,152,218,223,218,186,92,177,133,14,46, +99,46,22,118,95,118,18,210,101,182,58,46,59,194,120,194,120,98,216,98, +217,194,168,98,169,14,106,30,141,76,192,76,231,32,166,124,166,164,154,202, +126,224,91,238,176,196,233,243,38,44,219,44,34,116,34,78,222,78,223,112, +130,78,131,10,127,86,182,100,96,154,44,168,195,158,172,136,213,178,126,86, +64,130,149,122,90,190,35,232,164,190,227,224,128,162,128,240,101,245,66,18, +40,64,23,86,110,62,43,62,32,102,103,102,22,152,111,152,64,102,64,222, +103,194,128,196,128,94,216,94,217,194,172,94,173,12,112,32,147,70,230,32, +201,72,168,122,168,166,158,196,138,220,103,238,186,198,231,241,118,22,44,36, +44,154,17,232,44,80,104,80,104,148,45,148,230,26,184,36,144,40,144,162, +132,200,111,236,144,110,245,110,198,110,199,245,18,78,95,78,18,192,95,164, +58,176,59,12,222,94,222,26,122,26,122,94,223,94,122,60,223,60,96,124, +152,124,152,238,125,244,88,202,153,174,102,144,125,164,172,122,230,122,230,236, +205,242,176,144,199,164,172,200,231,171,78,12,42,88,17,122,52,246,53,68, +70,112,218,78,218,146,212,166,202,170,189,170,162,196,163,8,112,30,112,206, +118,228,218,228,234,216,241,197,108,12,141,42,34,94,34,54,220,54,221,92, +78,90,78,208,84,220,98,228,178,228,198,222,206,204,213,190,192,114,138,138, +102,148,79,155,12,80,88,78,78,148,68,178,50,204,21,232,62,14,34,148, +103,208,102,102,218,76,218,152,210,166,195,172,172,12,173,192,130,38,130,200, +132,218,144,228,212,228,230,222,243,199,16,86,93,86,14,194,95,168,54,18, +55,180,88,48,239,48,132,78,133,12,196,78,197,12,164,64,134,106,93,142, +236,132,200,116,180,98,159,72,126,134,205,134,116,246,116,168,214,168,215,242, +116,222,213,223,22,22,44,50,54,76,60,110,62,148,60,206,54,222,46,230, +33,232,20,94,56,52,75,22,20,162,46,130,61,112,78,54,157,54,148,138, +148,90,90,90,90,138,149,138,118,242,119,14,76,210,100,180,119,148,150,186, +119,150,192,12,176,52,163,76,208,84,220,46,179,46,174,186,174,90,228,90, +229,186,200,110,200,158,194,192,176,220,149,238,208,198,239,237,14,78,93,78, +12,164,83,126,58,14,58,236,31,226,92,32,131,64,84,226,108,206,126,206, +140,214,166,226,192,230,243,230,90,110,120,110,121,206,140,76,233,76,182,12, +182,88,176,132,164,162,145,190,228,186,206,146,181,107,92,94,92,32,40,32, +40,94,93,94,16,224,101,202,70,94,71,210,34,124,35,218,70,144,103,144, +220,86,220,26,132,26,132,86,221,86,132,56,221,56,108,120,164,120,164,238, +143,242,116,142,139,168,110,210,165,176,182,120,230,120,230,236,205,242,186,144, +207,170,182,206,231,179,88,92,88,32,34,32,34,92,89,92,16,226,101,196, +34,126,35,218,68,92,69,206,100,144,69,144,106,48,146,48,138,76,118,100, +97,116,170,8,170,126,139,132,236,116,206,90,190,68,171,30,230,32,189,64, +120,250,120,144,218,144,219,248,120,184,219,184,120,224,219,225,18,230,32,196, +40,154,40,26,90,26,90,234,67,236,40,84,91,84,40,140,91,140,180,12, +114,98,231,90,198,48,241,100,134,240,134,138,220,138,221,238,134,214,221,215, +16,50,241,50,88,10,89,82,168,8,169,82,124,72,40,138,211,132,162,94, +229,146,68,248,68,170,196,170,197,244,68,224,197,225,16,68,99,68,18,158, +95,122,62,8,62,236,35,224,168,10,108,98,225,92,190,48,239,108,122,244, +122,142,216,142,217,244,122,216,217,217,150,44,225,112,124,14,38,104,209,98, +62,246,62,146,198,146,199,242,62,220,199,221,26,40,227,40,42,74,209,74, +16,108,241,108,124,10,116,58,100,94,76,132,52,152,21,174,128,124,128,240, +105,246,74,156,103,174,40,218,129,182,180,152,129,186,218,220,139,180,160,108, +184,136,218,158,239,169,12,34,117,34,26,240,26,78,100,78,101,240,26,182, +101,182,26,218,101,218,52,34,52,92,50,130,43,154,76,34,76,140,101,142, +118,86,235,86,172,14,172,88,166,128,158,166,144,202,121,236,188,216,153,182, +238,230,210,200,194,168,180,124,173,91,24,82,233,82,128,10,124,90,112,134, +96,168,68,202,23,232,238,232,206,212,174,180,152,146,125,88,116,172,145,213, +20,56,233,56,126,12,114,66,96,94,64,122,27,144,236,138,204,126,178,108, +156,82,143,56,112,108,145,136,54,172,25,224,114,154,151,186,196,172,235,210, +90,174,90,218,98,236,158,236,174,228,183,209,38,28,85,62,18,92,65,120, +28,236,69,152,78,94,233,94,152,14,144,114,126,166,98,210,73,238,232,232, +204,204,182,172,164,134,149,94,136,186,165,221,14,86,95,86,14,200,97,178, +54,14,55,188,82,128,247,128,72,240,96,214,110,182,118,150,120,124,120,28, +208,28,208,236,175,242,148,60,177,105,10,72,73,72,14,152,77,122,50,12, +50,238,25,228,78,60,120,60,116,96,110,132,96,166,71,204,80,88,131,188, +168,14,144,80,127,108,152,244,153,62,186,20,207,48,158,62,235,62,160,114, +229,114,160,162,229,162,160,216,241,216,192,216,193,63,130,10,76,68,21,100, +124,16,178,68,237,94,114,54,145,84,60,98,172,98,137,132,66,210,66,142, +192,142,193,208,130,164,116,204,84,226,31,238,136,200,219,239,112,12,147,34, +18,68,39,102,240,46,54,46,54,172,29,234,12,158,55,132,70,96,114,96, +110,148,71,218,76,128,127,200,160,64,136,118,123,140,148,246,149,94,182,60, +205,84,242,98,157,98,236,134,157,134,236,174,157,174,246,216,157,216,194,216, +195,99,22,22,59,48,16,84,51,110,20,230,51,146,64,62,108,62,104,118, +84,170,55,210,64,96,102,154,119,194,156,10,134,72,117,98,142,238,143,52, +174,18,201,50,236,62,149,62,230,110,151,110,233,158,230,158,151,158,244,210, +151,210,190,210,191,63,16,88,99,88,18,196,105,168,60,16,61,182,110,38, +225,38,96,112,243,112,164,122,112,220,223,210,184,156,239,231,16,76,91,76, +58,248,59,12,16,168,44,124,59,92,90,132,59,102,148,12,177,32,82,42, +247,42,226,136,226,66,110,66,110,136,227,136,198,112,198,88,140,88,140,112, +199,112,214,208,214,160,120,160,120,208,213,208,120,184,213,184,82,232,249,233, +128,14,163,34,240,46,66,46,66,160,50,204,23,238,24,64,49,100,16,152, +67,122,114,78,99,116,212,78,187,104,154,62,150,104,122,138,87,152,224,152, +151,104,152,142,146,186,120,220,71,240,110,166,95,200,208,162,189,190,236,236, +184,216,149,171,34,24,75,56,20,86,61,118,26,232,71,150,84,28,241,28, +226,90,226,58,98,58,98,90,227,90,140,90,141,28,182,90,183,28,212,172, +212,118,104,118,104,172,213,172,104,146,213,146,76,200,243,200,160,244,161,173, +40,16,77,56,10,94,54,94,52,216,85,176,90,20,241,20,222,82,222,50, +102,50,102,82,223,82,142,82,143,20,180,82,181,20,210,164,210,110,110,110, +110,166,211,166,110,138,211,138,90,194,245,194,162,242,163,167,38,22,75,56, +12,92,60,92,54,226,93,198,122,36,105,78,130,136,105,160,218,138,195,158, +218,34,193,66,160,10,156,42,152,70,134,98,97,126,226,120,196,98,172,82, +153,68,160,110,156,148,150,180,134,206,112,226,89,242,234,234,208,220,186,202, +168,176,157,149,16,86,95,86,16,202,103,174,58,12,59,186,216,170,216,36, +124,36,124,172,217,172,124,106,217,106,82,228,243,229,104,28,52,42,17,48, +20,102,85,96,14,156,87,150,58,40,58,208,62,228,78,236,202,236,224,230, +241,208,124,38,119,74,130,130,117,168,212,124,195,152,216,34,191,62,162,12, +162,38,160,60,152,80,134,98,109,114,160,64,178,76,204,94,225,112,164,104, +162,132,160,154,152,174,138,188,109,208,224,198,190,172,161,155,42,18,81,50, +16,72,84,72,60,116,19,156,102,168,55,122,60,244,61,128,104,106,77,142, +220,168,220,34,128,34,128,168,219,168,128,100,221,100,98,224,245,225,14,46, +101,46,14,140,32,120,44,98,50,70,55,46,42,214,42,110,80,110,81,206, +42,186,81,186,169,12,118,22,118,68,220,68,221,20,168,68,169,12,96,106, +241,106,76,228,106,190,120,158,130,122,139,78,154,138,143,186,226,142,203,174, +178,118,174,166,162,200,142,220,115,236,236,236,216,222,200,206,186,182,177,147, +108,130,241,130,12,68,89,68,14,154,85,118,58,8,58,234,31,226,108,62, +108,30,224,30,225,64,144,56,105,102,180,58,217,100,160,244,161,86,80,216, +114,190,138,160,161,132,236,214,204,188,180,160,161,135,26,196,26,36,78,36, +79,190,26,166,79,166,78,238,144,188,182,134,206,62,212,34,101,34,236,234, +204,212,184,190,154,148,134,102,122,62,117,35,52,24,52,68,212,68,213,28, +134,68,135,14,20,104,233,104,18,198,70,150,101,68,108,136,93,186,52,238, +92,222,124,196,140,160,145,118,204,134,175,174,232,236,200,224,172,206,152,184, +143,157,38,26,85,60,24,92,71,118,30,238,73,154,102,36,196,36,118,112, +226,112,220,210,214,222,198,230,169,232,154,112,140,138,116,172,85,200,194,112, +184,140,166,178,138,210,103,241,16,84,83,84,16,188,83,164,50,16,51,174, +146,14,183,36,234,48,100,48,100,152,88,198,61,232,120,80,214,80,214,144, +121,144,110,110,245,110,122,246,122,176,218,176,219,244,122,226,219,226,168,58, +169,161,14,70,93,70,16,160,91,122,60,10,60,234,27,222,144,10,177,34, +238,46,106,46,106,152,81,222,116,108,245,108,128,78,214,78,214,140,129,140, +170,162,171,54,126,244,126,176,216,176,217,242,126,226,217,227,32,106,32,68, +226,68,227,104,126,68,127,10,62,28,95,54,194,24,169,60,182,148,182,102, +76,102,76,148,183,148,36,186,217,186,18,228,239,228,126,228,127,157,38,98, +38,64,226,64,227,98,130,64,131,8,60,22,95,50,200,16,169,48,190,132, +190,94,76,94,76,132,191,132,22,166,239,166,130,246,131,140,26,228,68,214, +98,194,129,166,232,224,194,214,162,198,131,167,18,234,34,192,38,142,38,32, +82,32,82,230,63,236,38,92,83,92,38,148,83,148,110,108,110,74,232,74, +233,108,116,24,147,54,220,24,189,58,168,74,169,10,206,146,206,106,132,106, +132,146,207,146,112,184,229,184,98,224,245,224,168,224,169,155,116,10,151,30, +234,44,46,44,46,158,38,198,23,234,60,110,243,110,72,78,202,78,202,144, +73,144,136,164,137,56,84,246,84,176,204,176,205,244,84,224,205,225,20,38, +45,70,96,34,79,74,14,94,101,94,60,244,61,8,16,184,61,116,92,152, +63,116,152,8,181,32,238,44,114,44,114,156,102,202,85,232,122,108,247,108, +134,76,218,76,218,142,135,142,174,162,175,54,136,244,136,178,220,178,221,244, +136,226,221,227,78,12,42,88,25,114,52,244,53,68,92,240,92,94,226,94, +226,236,199,242,158,94,159,8,100,32,127,72,218,30,187,74,184,186,184,136, +132,136,132,188,185,189,14,154,82,154,68,180,42,210,21,228,70,246,92,240, +92,48,38,48,39,154,66,14,53,48,92,80,39,80,92,116,39,116,130,244, +130,104,230,104,230,240,207,246,198,200,198,142,160,142,160,200,199,200,178,104, +179,12,118,36,153,82,238,36,201,89,38,30,77,66,16,92,57,120,28,226, +69,148,96,242,96,100,226,100,226,230,199,240,184,190,184,140,134,140,134,190, +185,190,158,100,159,10,96,34,131,72,190,74,223,33,20,54,107,54,16,100, +111,100,66,100,67,4,16,236,30,200,43,138,240,226,116,228,80,218,52,196, +37,174,72,116,73,210,104,152,73,152,122,206,122,84,220,84,220,198,197,206, +188,160,188,116,152,116,152,160,189,160,168,84,169,4,118,28,145,66,190,62, +221,21,36,24,75,46,16,64,55,84,28,146,81,90,96,32,186,32,122,74, +220,74,214,118,206,136,177,140,180,74,176,92,160,118,139,138,140,74,128,102, +112,120,95,132,76,156,59,194,194,156,169,186,130,150,118,190,92,214,56,230, +31,238,232,236,202,228,170,216,144,196,123,175,18,68,91,68,22,146,85,114, +60,10,60,234,33,218,140,12,95,92,134,74,107,118,92,140,205,140,192,100, +119,100,112,156,112,198,188,198,189,158,150,198,151,100,174,232,202,230,218,220, +222,200,224,54,117,55,34,22,77,54,16,84,59,110,24,230,69,152,90,46, +239,46,96,86,227,86,76,122,245,122,148,8,148,76,142,110,132,150,114,188, +85,220,134,164,239,164,202,136,202,238,171,244,142,182,169,211,34,20,73,48, +20,74,59,106,24,228,59,140,236,26,164,34,87,36,94,60,119,98,142,52, +167,94,188,104,225,52,136,118,92,126,93,240,138,166,93,166,175,166,172,122, +220,122,221,240,176,166,221,166,92,216,221,217,90,64,24,158,89,152,64,18, +18,94,73,88,16,210,89,194,156,12,132,52,109,80,102,128,150,108,190,72, +208,46,137,46,140,70,172,100,200,114,237,124,110,152,227,152,166,118,166,238, +139,246,132,178,91,226,192,182,229,221,18,42,241,42,94,66,95,8,164,68, +165,8,76,64,50,100,31,120,172,242,210,234,212,216,216,84,61,84,88,96, +59,138,180,118,73,118,34,156,199,156,64,174,64,206,182,206,183,174,122,206, +123,119,14,78,79,78,58,244,59,14,18,170,59,88,94,140,59,104,126,98, +109,66,142,16,142,158,134,198,116,222,99,242,184,14,184,216,190,228,202,230, +220,230,232,224,241,206,96,174,143,138,240,170,185,128,230,56,203,101,24,26, +65,66,18,232,34,218,46,212,66,212,76,216,102,226,132,232,243,228,12,112, +54,112,55,212,136,16,136,126,126,162,99,202,168,14,168,176,174,190,184,196, +208,196,222,192,230,182,233,170,86,54,115,90,80,148,137,112,218,50,189,94, +188,112,231,143,44,18,83,44,24,80,69,108,30,226,65,140,124,10,102,58, +85,84,180,234,218,222,222,190,220,50,107,50,124,68,97,118,190,90,113,90, +80,134,205,134,102,154,102,194,190,194,191,154,144,194,145,91,34,240,34,32, +86,32,54,100,74,128,82,148,82,174,70,182,55,186,132,12,104,62,85,86, +174,230,200,228,214,220,220,204,220,50,113,50,134,66,105,118,190,92,121,92, +92,136,205,136,112,156,112,194,190,194,191,154,150,194,151,93,40,20,85,62, +12,96,60,96,56,234,107,186,92,82,247,82,120,120,157,168,200,8,200,240, +167,249,28,48,229,48,124,12,100,66,78,86,48,104,21,116,236,112,210,102, +182,84,162,66,147,48,16,178,239,178,80,178,80,94,189,94,182,122,81,122, +184,148,81,148,108,186,52,232,193,224,158,196,213,241,38,46,19,118,108,78, +31,78,24,174,105,130,70,244,71,14,116,56,227,56,110,104,247,104,174,104, +175,10,116,146,241,146,128,168,159,200,164,234,194,232,204,220,205,117,18,36, +241,36,96,60,97,6,162,58,163,8,58,238,76,236,82,222,82,74,38,74, +38,166,32,206,21,238,38,120,83,120,38,162,83,162,116,70,137,88,210,70, +187,94,110,106,223,106,102,132,233,132,166,68,152,116,132,146,103,176,236,174, +208,160,194,142,191,132,138,242,160,240,164,232,165,146,124,172,141,190,104,222, +165,194,226,224,186,202,165,192,206,174,183,201,54,244,68,244,80,232,82,212, +82,32,40,32,40,144,36,190,15,240,40,90,83,90,40,146,83,146,102,60, +225,60,96,90,243,90,96,152,124,126,142,100,156,68,160,48,167,12,240,144, +218,134,200,118,186,102,179,90,118,22,135,48,210,20,187,60,140,148,134,178, +226,178,222,224,214,234,202,236,187,238,102,208,203,208,196,178,200,132,127,133, +126,10,165,32,242,46,64,46,64,148,54,196,29,236,20,62,49,104,16,156, +65,126,140,54,112,94,95,112,82,160,122,150,154,134,182,106,202,84,121,84, +126,100,148,120,174,138,206,150,245,158,138,158,197,188,118,194,205,233,56,22, +93,46,190,22,155,46,36,56,221,56,16,84,241,84,126,14,104,82,82,110, +50,134,17,150,234,146,204,134,176,114,153,84,114,98,141,116,70,126,187,126, +58,148,193,148,58,172,195,172,64,244,64,196,186,196,187,242,64,226,187,227, +18,80,105,80,66,248,67,12,20,174,67,96,100,142,67,106,130,16,155,46, +112,60,220,60,220,108,120,108,118,150,234,150,232,200,226,206,203,210,172,246, +173,60,206,12,179,60,94,224,134,196,173,155,48,100,132,100,132,28,48,28, +49,100,48,68,133,68,74,108,44,140,27,152,106,230,120,228,136,220,146,134, +51,134,32,194,58,176,76,156,87,134,34,232,62,220,86,196,104,168,119,134, +180,186,181,44,188,242,222,232,223,17,90,92,30,92,30,32,90,32,91,92, +18,228,101,194,32,126,33,222,64,92,65,206,64,138,103,138,214,100,214,28, +130,28,130,100,215,100,130,66,215,66,156,110,130,144,109,158,188,236,208,234, +226,224,228,214,228,140,135,140,118,198,142,180,158,160,169,140,114,236,146,226, +168,208,188,180,196,158,201,141,68,14,42,62,21,88,106,58,47,58,34,98, +101,98,24,144,107,144,66,98,66,212,107,178,130,16,159,46,118,58,224,58, +224,100,126,100,124,148,236,148,234,182,228,200,216,204,201,206,172,246,173,58, +208,10,185,58,96,232,132,204,173,157,8,68,91,68,16,154,85,116,20,220, +54,228,55,8,204,96,204,22,118,22,118,96,205,96,118,60,205,60,96,128, +237,128,80,234,100,216,112,194,121,152,114,186,130,200,148,212,158,218,194,224, +239,222,166,128,167,218,166,170,221,171,110,98,110,30,44,30,44,98,111,98, +44,64,111,64,14,130,125,130,50,152,19,230,38,180,54,202,74,216,102,226, +241,228,80,130,81,216,80,168,121,168,128,28,239,28,142,164,142,70,216,70, +217,164,124,202,144,194,160,180,172,160,176,140,178,116,181,90,188,164,229,200, +178,28,167,71,88,94,88,36,36,36,36,96,89,96,20,222,105,200,34,218, +35,130,68,208,69,96,68,144,103,144,156,12,179,36,104,48,235,48,114,132, +114,102,230,102,231,130,130,62,151,88,204,60,177,102,126,224,126,144,216,144, +216,202,210,216,202,218,191,218,170,244,171,103,28,200,28,50,70,50,71,190, +28,170,71,170,138,12,173,36,92,48,231,48,118,60,143,90,100,134,100,102, +228,102,229,134,192,58,169,102,110,228,110,150,210,150,210,220,196,224,185,222, +158,248,159,113,76,14,36,90,15,116,50,242,51,64,74,70,239,70,154,242, +155,8,100,182,207,182,68,192,96,164,114,138,132,104,147,70,236,188,212,164, +190,136,174,104,159,71,32,46,113,46,24,82,113,82,80,8,78,58,68,100, +50,124,25,148,110,128,71,94,136,46,219,46,136,80,235,80,176,8,168,88, +152,116,127,140,232,146,204,128,184,100,175,80,66,244,66,154,190,154,191,240, +66,186,191,186,66,220,191,221,28,188,28,40,66,40,67,178,28,156,67,156, +86,34,233,34,92,92,92,62,224,62,225,92,204,142,204,88,114,88,114,142, +205,142,114,116,205,116,158,142,159,88,158,62,159,8,86,166,218,166,205,184, +110,178,96,206,80,226,63,240,102,194,116,212,132,226,144,232,182,236,233,234, +156,232,157,166,156,198,221,199,58,244,59,10,32,72,17,126,80,62,97,104, +218,96,218,26,122,26,122,98,219,98,122,62,219,62,150,106,120,140,91,162, +188,232,218,228,228,214,232,132,129,132,160,132,152,156,132,180,103,200,198,132, +194,156,180,188,158,212,136,224,109,237,46,30,79,58,20,86,61,112,34,226, +71,146,90,66,212,66,212,108,106,108,104,150,224,150,222,186,216,202,204,204, +189,206,160,244,161,66,72,220,106,200,136,174,153,150,106,18,137,48,198,14, +157,67,44,16,71,44,24,58,132,58,132,102,40,102,36,146,142,146,142,188, +138,202,130,206,113,208,124,12,97,58,88,244,89,58,22,222,52,192,70,166, +83,146,180,176,181,36,224,10,224,214,220,230,189,237,20,230,38,194,50,128, +50,26,218,26,218,68,51,68,62,132,247,132,240,228,94,228,95,88,144,80, +144,188,200,188,201,83,44,32,213,32,24,104,229,104,128,32,128,70,122,116, +110,154,90,184,62,208,25,230,232,230,202,214,178,192,160,172,142,142,127,105, +34,18,79,42,16,82,59,110,26,230,69,148,94,26,213,26,74,74,235,74, +152,26,146,64,132,92,112,114,79,136,238,130,222,124,196,112,178,94,163,74, +144,118,144,226,138,232,123,234,116,152,85,210,168,156,195,208,198,144,233,205, +16,88,95,88,14,196,95,166,52,180,53,14,88,42,243,42,84,192,245,192, +120,192,120,72,208,72,209,192,166,10,161,72,120,102,209,102,120,132,209,132, +120,162,209,162,142,202,85,238,180,204,233,241,46,230,46,36,208,36,209,226, +46,118,209,118,46,200,209,200,126,200,127,37,104,26,60,38,27,40,12,96, +119,96,40,242,40,148,104,148,105,236,40,218,105,218,72,148,73,36,116,74, +245,74,148,242,149,16,216,240,217,12,148,136,217,136,148,214,217,215,62,244, +63,12,36,70,21,130,80,64,95,104,226,18,168,32,117,34,108,84,245,84, +128,240,128,142,220,142,221,238,128,216,221,216,174,142,175,33,96,24,54,34, +19,36,12,86,97,86,32,236,32,138,84,138,85,228,32,210,85,210,58,138, +59,32,116,30,225,30,106,74,239,74,104,136,132,116,152,88,160,58,167,30, +236,140,210,122,184,94,177,74,160,122,160,240,135,244,126,158,109,220,176,162, +201,220,202,152,233,215,20,234,34,192,38,148,38,30,82,30,82,232,59,238, +38,88,83,88,38,142,83,142,96,166,245,166,118,166,118,56,218,56,219,166, +150,166,151,12,184,166,185,12,150,184,101,236,180,188,233,236,118,110,219,111, +14,70,95,70,14,156,93,120,62,12,62,236,31,224,104,58,125,100,142,14, +142,156,132,200,93,240,88,168,143,130,184,12,184,212,190,228,198,230,224,230, +234,222,239,202,230,56,205,102,236,164,185,121,98,14,62,70,37,92,24,140, +92,122,148,86,184,44,79,44,88,62,128,102,186,126,239,136,48,162,205,162, +86,182,31,228,158,184,217,226,126,124,126,244,97,249,34,30,71,74,18,234, +36,216,50,206,64,206,78,214,108,226,134,228,239,228,56,206,56,114,13,114, +90,32,214,32,210,80,206,94,188,98,171,98,208,194,208,132,114,132,114,194, +209,194,88,118,114,104,134,80,142,54,145,33,28,222,28,32,78,32,79,214, +28,84,79,84,28,138,79,138,28,194,79,194,96,56,127,98,144,14,144,162, +136,190,118,214,93,236,96,164,145,128,178,12,178,208,182,220,192,224,224,224, +234,212,241,200,228,48,199,96,232,162,179,119,90,86,90,28,32,28,32,88, +91,88,16,222,99,190,32,120,33,216,66,88,67,202,102,132,67,132,150,16, +150,158,134,194,112,218,87,236,106,60,131,98,98,162,151,128,184,12,184,210, +188,224,200,230,224,230,236,218,238,208,239,192,230,164,185,124,232,56,203,101, +34,174,34,34,100,34,101,170,68,72,68,156,56,196,40,216,19,232,80,188, +117,222,138,244,138,128,224,128,225,238,138,214,225,214,172,128,173,8,244,64, +173,65,62,10,30,66,15,84,102,54,39,54,26,100,95,100,16,150,101,150, +58,100,58,226,101,196,134,32,120,90,113,108,228,76,125,76,106,136,241,136, +174,10,174,114,168,158,154,190,132,216,101,240,236,240,212,216,192,186,175,137, +26,190,26,64,98,64,98,186,83,190,62,246,63,10,134,246,134,130,224,130, +225,242,134,216,225,216,168,130,169,8,246,64,169,65,232,38,48,38,48,160, +38,200,21,234,74,102,245,102,164,102,164,236,133,243,30,192,30,34,86,34, +87,182,30,158,85,158,228,18,178,30,130,30,130,156,112,206,79,238,242,100, +131,100,190,244,191,101,34,66,21,130,22,238,48,206,64,164,66,130,67,12, +110,62,67,114,104,206,65,160,112,36,208,36,186,70,156,96,101,128,234,132, +171,84,112,158,229,158,92,228,241,228,168,228,169,159,36,22,85,52,18,82, +67,112,26,234,71,146,96,46,239,46,182,46,182,230,145,239,28,38,94,38, +44,116,98,116,88,166,62,206,23,238,46,144,68,192,98,216,132,224,239,224, +220,30,162,40,121,44,118,102,229,102,108,174,237,174,168,174,169,41,78,14, +48,78,19,122,56,248,57,62,138,12,171,38,82,48,241,48,208,108,208,74, +116,74,116,110,209,110,90,170,90,136,238,136,239,168,108,168,219,168,170,168, +170,240,139,247,114,14,143,34,28,42,231,42,186,102,186,70,66,70,66,102, +187,102,30,164,30,132,224,132,225,162,50,166,205,166,130,166,130,242,105,247, +122,10,153,32,232,44,44,44,44,170,38,206,21,236,68,88,116,88,82,146, +114,146,110,182,88,216,59,238,74,168,90,198,110,216,138,228,160,230,239,230, +224,76,174,84,139,88,134,134,231,134,130,188,235,188,182,188,183,85,12,70, +83,70,14,154,79,120,52,8,52,234,21,222,86,48,130,48,100,124,130,124, +122,174,106,210,77,236,90,152,112,202,148,222,237,228,220,28,149,44,144,102, +227,102,142,174,231,174,184,174,185,37,16,238,34,204,38,172,38,48,88,48, +88,236,65,242,12,126,89,126,66,14,51,48,54,74,69,104,56,142,69,174, +106,54,142,54,116,128,146,128,144,168,130,210,103,240,112,154,126,198,144,214, +172,222,241,226,226,32,186,40,161,44,160,106,235,106,158,180,237,180,196,180, +197,39,28,24,69,60,24,230,46,210,60,210,84,218,116,230,239,230,14,110, +52,110,53,210,84,28,202,28,155,66,122,50,173,76,96,206,96,84,214,84, +214,202,189,208,154,204,155,84,96,120,215,120,96,158,215,159,16,72,99,72, +60,242,61,12,16,168,42,124,61,78,98,138,61,96,120,240,120,30,234,30, +234,236,205,242,140,74,213,74,200,166,200,116,154,116,154,168,201,169,14,32, +117,32,30,232,30,78,102,78,103,226,30,208,103,208,30,174,103,174,54,32, +54,90,50,128,41,150,78,32,78,136,103,136,134,236,134,32,226,32,226,232, +201,240,148,80,211,80,198,176,198,122,158,122,158,176,199,177,26,224,26,40, +78,40,79,216,26,92,79,92,26,144,79,144,26,198,79,198,142,14,171,38, +100,48,227,48,94,88,243,88,128,58,145,88,190,58,177,88,210,174,210,112, +112,112,112,174,211,174,112,144,211,144,100,200,229,200,84,230,243,230,162,230, +163,113,38,238,38,30,218,30,218,230,183,238,62,76,197,76,166,176,166,120, +90,120,90,176,167,177,70,14,40,68,21,88,106,58,47,58,32,100,97,100, +22,150,107,150,64,100,64,226,103,198,124,242,124,32,230,32,230,234,197,242, +142,78,209,78,198,176,198,122,156,122,156,176,199,177,14,128,149,128,70,62, +95,98,26,234,44,198,50,158,50,30,118,30,118,220,87,228,218,16,180,58, +147,84,224,86,186,126,153,150,232,146,188,200,135,237,102,16,143,36,34,46, +221,46,16,86,241,86,74,56,103,80,176,52,149,84,200,170,200,114,60,114, +60,172,201,172,60,142,201,142,48,202,211,202,18,230,239,230,128,230,129,115, +14,72,95,72,56,246,57,8,18,172,40,130,57,82,88,138,57,96,104,24, +208,24,163,70,136,56,179,80,110,244,110,92,224,92,224,238,203,244,168,232, +169,92,110,136,225,136,110,180,225,181,62,10,62,236,29,228,20,72,97,72, +18,158,97,126,109,28,106,28,214,28,175,72,144,56,189,82,118,244,118,92, +226,92,226,240,205,244,172,230,173,92,118,136,227,136,118,178,227,179,74,8, +50,50,21,82,130,42,57,42,98,76,81,42,168,8,146,54,129,76,244,40, +153,40,202,74,183,40,52,246,52,94,214,94,214,242,183,246,78,126,187,126, +168,202,168,160,96,160,96,202,169,203,88,60,32,164,97,154,60,18,22,98, +71,94,16,222,99,200,148,12,183,48,102,62,239,62,158,70,110,132,219,126, +188,90,231,142,142,144,142,180,134,208,116,226,91,240,182,140,182,218,186,230, +198,234,222,234,234,228,239,203,130,12,163,36,242,44,64,44,64,160,52,196, +27,230,22,66,51,102,18,150,65,124,84,72,210,72,165,108,94,244,94,124, +222,124,222,242,195,246,156,236,157,124,94,160,223,160,94,194,223,194,128,90, +183,117,72,14,38,82,17,108,50,246,51,60,150,12,120,60,96,84,73,100, +236,90,212,82,186,64,164,42,147,18,112,92,195,92,90,246,90,122,142,122, +142,240,121,246,90,156,143,156,90,192,143,192,178,208,179,128,216,110,216,240, +189,247,58,12,58,244,29,230,14,74,95,74,14,164,87,130,102,108,120,92, +128,74,130,56,130,28,190,28,190,80,196,96,210,98,239,94,102,126,198,126, +182,172,152,206,124,224,93,236,238,232,198,220,176,206,148,182,132,156,119,127, +66,30,117,62,48,82,99,114,16,148,237,148,152,12,152,68,148,112,140,154, +120,184,94,208,66,224,33,236,156,180,235,235,26,30,63,64,18,230,48,210, +62,210,92,220,130,232,241,228,12,110,54,110,55,210,204,22,144,34,99,38, +82,68,233,68,156,110,157,32,82,122,124,96,151,68,228,112,186,94,157,68, +108,124,186,124,178,158,210,158,202,196,194,202,169,204,96,202,116,184,130,158, +139,125,38,240,38,104,90,104,90,26,166,26,166,104,216,104,217,240,38,212, +217,213,198,14,142,26,51,30,24,68,233,68,128,132,129,26,24,138,64,120, +92,96,117,68,230,130,196,116,164,94,139,68,32,238,62,224,82,200,90,148, +168,148,168,210,172,226,182,230,216,230,226,224,233,203,110,12,145,36,38,86, +38,46,220,46,221,82,106,68,74,98,45,120,150,70,213,110,28,150,233,150, +154,108,187,132,124,98,118,166,100,198,74,222,31,240,230,234,200,224,172,204, +150,180,135,151,36,244,36,32,220,32,221,240,36,220,221,220,110,46,84,82, +67,100,58,146,94,130,126,110,148,88,162,70,95,70,98,94,134,116,166,132, +197,142,110,140,155,164,96,172,165,203,74,16,46,58,23,78,76,74,46,118, +17,146,56,244,57,102,100,60,223,60,84,108,239,108,158,108,159,10,112,134, +102,184,77,232,240,224,160,222,134,206,105,174,162,222,163,108,162,158,219,159, +26,28,69,62,18,228,46,210,60,210,82,218,108,230,136,234,237,234,12,114, +54,114,55,210,156,14,128,54,102,80,77,96,236,88,204,74,176,52,149,24, +108,96,203,96,86,136,221,136,126,156,85,194,184,160,223,196,154,96,154,210, +127,217,36,24,81,58,20,86,61,118,18,232,61,152,150,12,108,76,75,104, +236,98,192,76,160,46,143,24,100,102,205,102,80,146,225,146,150,102,150,238, +119,246,110,176,69,230,180,178,223,223,18,228,42,186,52,134,52,24,216,24, +216,54,53,54,80,88,191,88,52,120,245,120,142,120,143,64,102,242,102,148, +208,148,209,242,102,182,209,182,102,218,209,218,220,74,142,134,65,171,40,100, +219,100,20,218,239,218,128,218,129,19,30,214,30,58,88,58,89,206,30,182, +89,182,106,104,235,104,90,224,245,224,166,224,167,13,94,14,60,58,25,88, +204,142,204,90,54,90,54,142,205,142,72,44,168,44,131,90,126,90,120,142, +110,170,86,204,54,226,25,240,166,168,199,200,138,142,138,216,140,230,154,240, +206,240,218,234,226,220,233,201,38,24,77,56,20,84,63,114,22,228,61,152, +98,24,98,70,218,70,219,24,158,70,159,10,76,106,241,106,94,242,94,148, +220,148,220,236,199,242,134,224,135,148,142,148,159,106,176,224,177,149,40,242, +40,32,216,32,217,240,40,220,217,220,60,94,197,94,142,46,142,194,109,200, +62,176,104,140,139,95,62,10,62,236,29,226,16,68,97,68,16,154,95,128, +146,12,114,72,93,102,120,244,121,62,172,14,199,48,134,68,237,68,134,118, +231,118,134,164,231,164,134,216,243,216,182,216,183,69,106,20,62,30,29,34, +16,66,121,66,70,126,71,30,16,132,44,108,71,68,116,112,71,78,22,236, +36,218,48,192,52,144,96,144,96,210,125,186,126,26,241,26,144,184,144,76, +220,76,221,184,122,236,152,218,174,194,182,160,183,106,196,196,241,232,170,76, +183,27,18,230,32,194,34,160,34,26,78,26,78,224,55,232,34,84,79,84, +34,138,79,138,98,24,131,62,90,226,110,212,126,212,144,222,162,226,239,226, +92,98,118,98,119,212,186,172,152,194,152,26,212,26,212,108,153,108,152,66, +213,66,178,130,229,194,236,122,199,155,92,138,92,68,24,68,24,140,93,140, +86,162,105,206,14,210,97,188,58,196,59,10,124,16,149,56,214,138,214,72, +124,72,124,138,213,138,210,10,181,72,148,138,148,166,140,200,118,228,91,242, +186,138,186,222,192,230,206,236,222,236,236,226,241,203,36,16,69,52,12,70, +78,70,70,94,50,122,19,154,58,244,59,112,98,166,59,136,94,114,71,144, +94,24,125,68,84,232,108,214,124,214,144,226,245,226,88,98,116,98,117,214, +186,170,152,192,152,26,216,26,216,108,153,108,152,70,217,70,178,126,237,192, +232,124,203,153,28,20,67,60,26,228,50,210,66,210,136,230,241,230,12,110, +56,110,57,210,156,174,106,196,106,26,202,26,202,110,107,110,106,68,203,68, +138,132,223,194,226,120,175,159,46,28,213,28,22,78,233,78,126,28,112,88, +90,116,56,140,21,160,238,150,204,138,176,118,145,78,70,242,70,148,188,148, +189,238,70,212,189,213,14,58,233,58,46,90,46,160,190,160,191,84,116,8, +116,208,120,226,132,230,208,230,220,222,228,208,233,191,20,144,36,116,42,88, +42,28,126,28,126,56,43,56,54,86,133,86,44,114,141,114,76,68,77,114, +110,68,111,114,78,124,45,152,104,122,131,138,148,70,156,58,158,48,158,28, +206,28,206,56,210,64,220,64,241,62,144,84,214,84,194,108,168,128,145,138, +240,138,226,136,208,130,192,122,174,108,164,94,157,84,72,244,72,154,198,154, +198,236,163,242,72,178,199,178,72,204,199,205,20,72,97,72,20,158,91,122, +62,12,62,236,33,226,148,14,122,66,99,100,236,56,127,56,94,148,218,114, +214,170,210,182,200,186,189,186,168,206,169,80,124,102,124,216,130,230,142,234, +210,234,224,226,233,203,14,72,101,72,16,160,95,118,62,12,62,238,27,226, +214,26,162,42,107,48,104,128,241,120,162,42,162,210,166,226,178,232,216,232, +230,222,237,199,16,234,28,206,34,168,34,30,88,30,88,228,59,236,34,90, +89,90,34,142,89,142,210,136,210,72,122,72,122,136,211,136,118,16,153,54, +210,16,177,72,148,136,148,162,142,190,124,218,99,240,182,136,182,214,188,230, +198,234,222,234,232,224,241,203,70,112,86,110,96,100,98,84,98,44,34,44, +34,144,112,144,108,216,102,230,90,236,69,238,14,196,91,182,56,62,73,86, +66,12,53,44,156,12,183,40,130,94,130,54,224,54,225,92,156,94,156,214, +158,228,168,236,216,236,230,226,241,200,218,124,157,165,32,248,32,30,90,30, +66,102,82,120,92,144,96,174,82,192,59,196,150,10,177,36,110,90,110,52, +226,52,227,90,144,90,144,214,150,232,164,236,210,236,230,226,237,200,216,124, +145,157,40,54,34,134,100,134,96,204,92,220,84,226,57,232,14,196,75,176, +16,32,88,32,81,134,108,92,233,92,164,10,164,104,158,146,146,180,128,212, +103,240,236,236,216,218,194,186,178,150,166,112,165,107,40,54,36,136,102,136, +98,220,86,232,59,234,14,198,83,176,14,32,88,32,85,136,154,14,175,38, +118,90,118,50,222,50,223,90,150,94,150,216,158,228,174,232,204,232,226,224, +237,198,214,116,151,161,50,12,51,244,12,74,77,74,16,170,51,96,76,132, +51,100,92,242,92,32,128,32,110,106,120,130,126,154,126,178,122,186,109,192, +140,52,243,52,188,16,166,68,135,114,162,242,162,100,222,100,222,236,201,242, +162,140,223,140,162,182,223,183,204,18,140,32,37,38,52,62,83,104,112,50, +139,90,206,48,167,106,16,136,243,136,124,100,80,176,233,230,182,136,168,166, +148,190,122,212,74,228,25,237,18,76,105,76,20,154,101,114,66,12,66,234, +33,224,98,40,243,40,88,174,112,150,130,124,144,94,154,62,159,40,134,242, +134,122,218,122,219,238,134,214,219,215,30,200,30,50,70,50,71,196,30,170, +71,170,219,22,218,24,146,34,93,36,88,74,235,74,80,130,243,130,88,180, +237,180,94,226,225,226,156,226,157,32,118,180,119,74,196,180,197,75,18,68, +95,68,18,154,95,122,64,10,64,238,31,226,154,14,183,42,112,86,112,52, +228,52,229,86,152,80,115,120,186,82,229,122,110,140,198,140,136,196,124,208, +122,220,130,228,144,232,178,232,212,230,228,220,237,197,28,192,28,48,78,48, +79,186,28,164,79,164,100,58,225,58,94,110,241,110,100,162,225,162,74,220, +247,220,160,8,161,110,160,134,161,221,102,138,102,68,32,68,32,138,103,138, +18,214,109,190,96,168,121,210,66,200,67,14,126,60,231,60,122,116,241,116, +178,116,179,12,124,174,231,174,100,228,245,228,178,228,179,145,34,28,79,60, +16,90,59,120,24,238,71,152,96,56,227,56,82,112,237,112,160,112,161,10, +96,170,227,170,72,226,247,226,160,226,161,139,62,14,36,146,101,198,14,76, +90,74,82,158,29,242,114,64,231,64,108,112,241,112,172,112,173,8,112,168, +229,168,92,222,245,222,172,222,173,137,14,34,229,34,84,34,52,228,139,196, +76,90,168,90,156,226,184,230,216,228,230,212,233,194,96,126,135,167,40,16, +73,50,16,66,86,66,60,110,19,152,58,246,59,114,102,162,59,134,98,108, +75,142,105,64,110,66,229,66,122,118,225,118,164,244,165,10,88,216,114,192, +138,162,165,126,234,212,214,196,196,174,165,123,26,32,229,32,24,118,58,104, +94,82,153,32,154,72,235,110,128,124,129,54,40,136,217,136,16,222,241,222, +70,222,71,162,128,222,129,136,128,178,197,179,74,16,50,80,21,120,24,218, +62,198,88,168,104,140,116,106,120,68,57,68,52,112,95,156,164,244,165,10, +236,150,192,108,165,89,20,42,101,42,90,132,90,86,36,86,36,132,91,132, +30,156,53,202,18,226,109,204,82,150,63,214,146,12,183,40,116,88,116,52, +226,52,227,88,146,70,122,134,113,156,98,242,126,220,146,186,158,146,162,104, +135,104,128,152,149,168,198,178,216,176,222,170,222,102,182,102,182,220,192,234, +222,234,234,220,237,209,112,14,149,38,22,50,239,50,74,72,27,114,188,70, +233,104,104,104,105,50,156,104,157,50,54,118,198,118,198,152,66,152,58,186, +212,186,204,224,188,234,156,236,141,237,40,28,73,58,20,84,57,118,24,232, +69,152,136,10,167,36,80,44,241,44,114,66,79,102,200,64,237,102,138,104, +139,44,178,104,179,44,92,118,214,118,214,152,102,152,100,190,220,190,212,224, +200,236,147,239,14,38,97,38,18,108,81,108,14,204,99,180,56,38,57,190, +122,36,221,36,114,106,235,106,138,106,138,154,130,190,110,216,71,240,182,106, +182,220,186,230,204,236,220,236,230,226,237,205,30,36,93,36,20,98,115,98, +52,98,52,144,48,182,32,210,23,224,86,98,86,210,119,178,118,30,245,30, +140,194,140,82,222,82,223,192,170,82,181,30,178,114,176,166,166,198,146,220, +105,240,186,200,243,239,26,80,178,68,166,200,168,216,178,226,210,226,224,218, +230,208,237,190,46,118,141,168,108,10,106,84,106,124,92,174,64,206,23,233, +28,70,19,136,58,14,56,158,48,192,21,236,88,70,59,108,96,202,57,164, +104,88,104,54,226,54,227,88,142,12,177,40,122,96,209,96,92,138,241,138, +148,138,144,172,138,200,122,220,89,238,186,138,186,216,190,228,200,232,230,228, +240,214,243,203,114,14,143,38,36,90,36,50,222,50,223,88,62,94,197,94, +30,138,229,138,104,138,102,166,96,194,78,216,52,228,25,236,152,138,152,214, +156,230,182,234,212,232,224,224,233,201,20,48,97,48,62,48,48,94,26,130, +19,140,46,220,46,112,86,112,87,210,46,188,87,188,146,14,185,40,112,88, +112,52,228,52,229,86,140,70,124,122,103,164,96,240,122,220,144,188,156,146, +158,104,131,104,124,156,147,172,202,178,218,174,218,100,180,100,180,224,194,234, +222,232,230,228,243,209,16,72,93,72,18,146,89,116,58,12,58,232,29,224, +154,8,134,42,109,70,220,138,220,86,114,86,114,138,221,138,174,84,196,40, +137,40,164,86,158,150,134,194,110,218,83,238,170,160,170,214,174,228,182,232, +212,232,226,228,230,216,237,195,26,208,26,46,76,46,77,198,26,108,77,108, +26,174,77,174,150,16,122,56,107,70,214,136,214,84,110,84,110,136,215,136, +172,84,194,44,131,44,164,84,156,144,140,188,112,218,79,238,168,152,168,214, +172,226,182,232,216,232,226,224,230,216,237,195,30,224,30,68,80,68,81,216, +30,130,81,130,30,194,81,194,60,20,45,68,140,12,169,38,108,92,108,50, +220,50,221,90,123,94,124,92,205,92,98,134,233,134,80,238,106,224,126,206, +136,182,140,160,141,134,236,200,232,218,224,230,208,232,194,232,180,226,180,206, +181,135,52,244,53,14,28,66,15,124,70,68,83,106,146,16,171,38,98,84, +98,52,224,52,225,84,124,74,104,128,81,166,80,236,108,216,128,188,140,152, +146,104,115,104,108,154,133,174,188,172,208,168,210,162,212,98,168,98,168,216, +172,228,184,232,218,232,230,222,237,207,108,12,143,36,36,88,36,44,222,44, +223,86,80,70,62,116,46,142,29,160,32,238,74,214,100,180,110,144,112,102, +69,102,62,154,99,178,164,170,184,170,194,164,198,150,198,98,140,98,140,204, +144,228,154,232,208,232,222,224,229,199,58,14,30,156,91,204,12,80,82,80, +76,142,66,176,46,202,21,228,108,90,108,54,224,54,225,90,148,14,179,38, +138,76,120,124,93,164,94,238,124,212,142,180,152,146,156,106,129,106,120,154, +141,176,194,180,206,176,214,166,214,106,174,106,174,214,182,228,190,234,212,234, +228,228,234,218,239,203,16,38,239,38,106,38,100,128,78,184,33,232,102,102, +198,102,190,200,180,220,162,226,139,229,18,240,30,210,40,136,40,32,82,32, +82,214,78,230,68,238,59,238,40,90,83,90,82,148,41,148,150,14,177,40, +108,86,108,50,228,50,229,84,134,80,116,136,101,164,106,236,132,204,146,172, +156,132,158,104,127,104,122,152,143,170,200,176,210,176,220,168,220,160,220,104, +182,104,182,214,184,228,192,232,200,232,220,232,232,226,241,211,32,28,77,60, +18,90,63,120,28,226,77,148,86,38,235,38,96,124,223,124,70,218,241,218, +156,218,157,39,26,38,225,38,44,124,205,124,16,214,241,214,126,214,127,39, +108,18,145,58,12,78,241,78,220,224,70,224,71,79,18,76,109,76,66,244, +67,12,20,176,46,130,67,86,104,144,67,106,104,40,239,40,114,122,229,122, +92,220,245,220,168,220,169,41,38,236,38,26,218,26,218,210,210,224,179,232, +58,66,92,118,121,172,110,64,94,114,59,184,134,68,166,124,197,184,188,62, +164,132,133,187,76,18,48,52,23,70,80,76,48,118,19,148,60,242,61,106, +140,14,179,50,96,66,241,66,108,136,229,136,90,222,247,222,168,222,169,67, +32,222,32,38,92,38,93,212,32,114,93,114,32,196,93,196,110,34,243,34, +114,124,237,124,98,226,249,226,176,226,177,35,56,16,87,44,18,60,129,60, +48,60,48,126,113,108,122,140,136,122,144,88,144,32,214,32,214,110,208,126, +200,132,187,134,144,62,215,62,214,92,145,92,34,154,219,154,48,190,207,190, +18,228,237,228,128,228,129,155,102,16,145,46,16,60,235,60,200,124,68,124, +69,60,54,166,23,222,118,152,149,188,194,166,237,208,86,160,86,212,86,226, +92,232,104,234,160,234,176,228,188,218,193,205,108,14,147,40,16,52,239,52, +212,104,64,104,65,52,18,146,241,146,124,112,78,178,150,196,225,232,176,146, +156,184,120,212,80,228,39,239,192,18,223,40,236,60,44,60,44,156,34,202, +17,242,60,98,153,98,168,10,170,118,180,176,198,218,212,230,226,234,234,230, +245,208,104,108,74,176,151,206,58,136,136,136,118,184,94,210,57,232,218,94, +200,152,176,200,141,235,50,20,50,52,210,52,211,18,128,52,129,14,108,72, +82,78,37,82,26,108,117,108,74,138,75,80,20,152,46,134,73,108,114,144, +75,112,20,174,110,174,84,206,62,222,25,238,74,158,44,198,101,226,222,154, +222,88,134,88,134,154,223,154,176,60,161,88,134,120,223,120,178,88,174,156, +160,186,138,216,113,238,178,166,178,220,184,230,194,234,214,234,228,230,239,214, +216,162,194,200,235,196,224,176,239,203,68,16,21,76,68,80,38,122,17,146, +48,244,49,110,90,26,90,76,152,76,153,26,120,12,121,76,70,106,157,106, +66,218,78,206,88,184,94,162,94,138,134,138,130,198,163,174,192,14,174,82, +157,118,176,110,184,156,206,202,241,232,244,74,179,74,218,74,218,104,212,146, +202,180,180,206,154,224,127,239,108,16,60,68,27,92,20,238,40,218,54,190, +58,164,58,94,237,94,82,46,176,46,155,94,158,180,176,180,188,176,194,164, +194,128,106,128,106,212,110,228,120,234,128,236,204,236,220,230,228,222,237,203, +32,58,223,58,50,102,209,102,24,146,224,146,218,194,210,206,200,210,171,212, +120,246,121,13,32,38,69,74,20,228,38,216,52,208,62,208,74,214,96,226, +122,232,148,236,237,236,12,110,58,110,59,208,80,58,223,58,92,98,215,98, +80,138,214,138,214,162,208,182,200,190,179,194,148,216,149,15,16,76,103,76, +64,244,65,12,18,172,46,126,65,82,98,136,65,100,160,8,138,50,121,70, +244,86,120,86,120,160,112,200,93,236,146,38,202,38,177,84,194,178,204,178, +214,172,216,164,216,126,158,126,158,212,160,222,168,228,176,230,210,230,222,228, +232,222,238,210,241,199,36,238,36,26,218,26,219,232,36,212,219,212,120,196, +121,40,60,70,193,70,70,102,181,102,58,134,184,134,182,160,176,170,162,174, +149,175,30,208,30,56,76,56,77,202,30,176,77,176,142,14,112,84,97,108, +118,246,119,68,164,16,195,54,128,70,237,70,128,122,225,122,126,172,227,172, +128,222,243,222,178,70,179,223,62,244,63,10,34,68,19,128,78,58,93,82, +146,12,114,78,89,114,122,244,123,66,166,20,199,52,130,72,237,72,130,118, +229,118,130,164,229,164,130,216,245,216,176,216,177,73,72,28,99,70,40,92, +218,90,206,204,202,226,188,234,159,238,138,146,169,180,140,18,132,110,114,158, +80,200,35,237,22,24,61,50,14,84,47,106,20,238,47,146,96,20,62,98, +103,94,118,62,70,160,121,154,58,212,123,194,162,14,140,72,117,114,144,244, +145,68,180,20,203,54,152,68,237,68,152,116,233,116,152,164,233,164,152,218, +245,218,188,218,189,69,94,54,26,168,97,158,66,14,18,100,69,96,16,224, +101,202,146,16,110,90,91,118,128,244,127,56,136,68,241,68,172,18,199,54, +136,118,231,118,136,168,229,168,136,220,245,220,182,220,183,69,16,38,239,38, +90,72,91,8,162,72,163,6,26,94,227,94,44,130,207,130,24,164,214,164, +212,194,204,210,169,214,124,242,125,63,18,38,239,38,96,62,97,10,164,56, +165,6,196,62,124,72,55,76,30,102,229,102,130,142,131,72,36,150,74,136, +108,116,127,102,228,148,184,136,156,118,141,102,16,174,241,174,124,148,84,196, +223,234,172,174,160,194,126,218,86,234,45,241,208,18,154,26,51,32,30,68, +233,68,132,122,133,28,30,128,70,110,100,90,125,68,232,128,200,116,168,94, +141,68,16,156,241,156,124,122,76,186,152,206,225,234,180,156,168,178,148,198, +120,218,78,230,41,235,78,14,40,88,17,118,56,242,57,58,86,60,235,60, +98,104,223,104,84,146,226,146,222,196,210,204,183,206,156,244,157,11,78,16, +48,80,21,116,58,242,59,62,86,90,228,82,218,204,210,222,198,226,173,230, +166,12,160,96,148,146,124,188,85,226,108,24,135,62,162,140,189,177,18,230, +38,200,48,162,52,120,52,32,214,32,214,74,53,74,200,92,128,108,81,112, +84,146,215,140,68,182,227,176,138,108,138,218,146,232,174,234,206,232,230,222, +237,203,102,68,30,160,95,154,74,18,24,96,79,96,20,214,101,200,110,56, +239,56,112,104,227,104,104,146,228,146,224,188,214,202,189,206,160,244,161,13, +44,60,207,60,22,114,229,114,124,246,125,6,24,224,68,186,94,154,119,114, +230,218,202,202,172,176,150,148,133,115,22,40,245,40,100,66,101,14,164,66, +165,12,16,222,32,198,40,172,46,138,46,82,132,82,132,114,47,114,66,140, +141,140,58,166,147,166,76,184,51,222,122,190,149,218,76,238,92,236,100,232, +102,222,103,166,156,152,179,182,150,126,245,126,168,236,188,234,200,228,204,216, +205,73,26,190,26,48,78,48,79,184,26,164,79,164,102,54,217,54,92,116, +231,116,158,244,159,10,74,220,114,188,136,158,159,124,238,210,210,192,188,168, +172,146,159,125,200,112,200,28,56,28,56,112,201,112,56,72,201,72,128,112, +129,28,18,144,241,144,66,144,66,238,125,204,122,144,126,162,140,184,168,208, +190,220,229,236,198,160,159,199,214,94,214,26,44,26,44,96,215,96,215,96, +44,60,213,60,126,96,127,26,60,240,60,126,202,126,202,214,200,224,186,230, +163,234,60,156,203,156,60,186,203,187,32,184,32,36,76,36,77,178,32,156, +77,156,212,104,212,22,118,22,118,104,213,104,118,64,213,64,164,104,165,22, +92,134,241,134,122,134,122,232,171,204,234,228,210,216,186,190,168,158,163,134, +218,158,187,187,106,20,60,30,31,34,20,70,115,70,72,112,73,28,20,122, +48,100,71,72,108,112,73,76,16,158,106,156,90,192,64,220,25,240,66,134, +44,190,99,220,220,130,220,42,130,42,130,128,221,128,172,10,161,42,178,42, +172,108,162,156,144,196,124,220,105,240,178,146,178,218,180,232,192,236,220,236, +232,228,239,214,212,144,192,192,233,184,224,168,241,198,130,84,221,85,76,14, +44,86,19,124,58,248,59,56,128,12,169,52,84,68,239,68,112,104,143,194, +76,218,249,218,172,218,203,95,36,22,77,52,18,86,61,114,28,226,77,146, +226,92,226,20,104,20,104,92,227,92,104,58,227,58,166,92,167,20,116,242, +116,120,220,120,220,218,212,230,197,232,116,154,221,154,116,188,221,189,44,26, +85,60,14,100,64,100,60,222,97,186,232,100,232,34,110,34,110,100,233,100, +110,68,233,68,172,100,173,34,118,244,118,134,222,134,222,240,197,244,118,164, +223,164,118,196,223,197,20,234,34,202,42,164,44,136,44,34,136,34,136,74, +45,74,66,110,141,110,58,144,153,144,82,172,55,216,126,172,155,212,106,144, +106,236,79,242,156,118,185,158,154,86,245,86,212,12,212,236,177,245,20,164, +36,138,42,112,44,80,44,30,134,30,134,60,45,60,64,86,137,86,56,114, +147,114,102,114,102,168,81,172,78,130,53,162,120,130,143,156,154,96,179,126, +144,74,245,74,204,18,204,164,171,170,54,186,27,236,118,174,141,204,194,182, +231,226,90,184,88,216,92,230,102,234,154,234,168,228,176,220,183,209,38,38, +206,38,200,126,194,144,182,152,145,156,14,218,241,218,110,218,111,39,124,14, +155,38,236,48,58,48,58,142,52,184,38,216,17,240,16,72,45,104,12,156, +59,132,204,142,204,76,98,76,98,142,205,142,98,110,205,110,56,232,245,232, +88,232,88,172,216,172,217,232,130,232,131,172,172,232,173,173,33,20,32,24, +75,56,16,84,59,112,18,236,61,148,202,110,202,30,100,30,100,110,203,110, +100,70,203,70,56,226,245,226,90,226,90,150,212,150,213,226,134,226,135,150, +172,226,173,151,96,138,96,66,28,66,28,138,97,138,92,158,115,200,14,210, +105,182,62,194,63,10,154,10,183,50,114,66,237,66,134,84,146,122,162,156, +190,190,237,230,204,66,194,130,170,180,140,210,101,237,102,12,145,50,20,64, +239,64,234,226,196,212,150,186,110,146,88,108,69,64,28,232,74,212,120,180, +144,146,164,110,181,65,52,16,85,54,38,246,39,56,112,38,218,38,218,240, +195,244,60,80,195,80,56,188,201,178,158,230,159,80,90,80,91,184,90,116, +159,116,90,148,159,149,98,60,30,158,105,144,68,16,22,94,75,92,14,212, +105,194,142,16,181,54,112,72,241,72,90,240,144,212,176,178,198,130,204,102, +207,72,242,234,190,202,160,166,140,116,131,73,32,202,32,54,76,54,77,194, +32,172,77,172,142,14,110,78,97,98,168,234,194,234,208,224,216,202,228,62, +121,62,108,222,148,184,176,136,186,96,191,62,98,166,128,132,148,94,159,63, +96,28,52,38,19,40,16,96,101,96,62,244,63,36,14,186,42,148,63,100, +98,156,63,116,148,12,120,52,101,74,112,148,218,148,218,80,115,80,118,114, +219,114,172,80,196,42,131,40,92,226,113,174,158,162,185,190,206,170,241,214, +138,172,138,212,142,230,162,234,186,232,196,224,203,211,108,16,143,40,28,52, +231,52,84,62,118,88,154,102,208,116,241,120,174,52,148,78,118,98,76,114, +21,128,174,124,46,192,197,180,168,154,213,194,120,112,62,154,137,144,130,186, +130,230,118,248,101,234,98,204,66,224,33,240,160,204,192,218,223,235,48,16, +83,50,38,246,39,56,108,38,216,38,216,212,210,232,200,234,183,234,160,174, +160,102,92,102,92,174,161,175,26,194,26,44,64,44,65,186,26,164,65,164, +136,16,106,56,81,80,172,14,198,52,239,78,156,46,110,102,193,92,176,68, +207,110,84,130,138,130,138,238,109,244,86,152,113,174,138,180,79,208,158,128, +214,128,214,236,185,242,162,150,185,174,156,206,213,177,100,14,60,56,19,84, +152,12,180,48,239,82,124,42,74,102,171,92,144,66,187,106,28,130,112,130, +112,240,83,246,44,152,75,176,24,216,95,190,130,130,212,130,212,240,185,244, +138,150,167,172,130,210,195,185,98,14,64,50,23,80,146,14,170,42,202,66, +237,80,122,44,72,98,171,90,142,62,187,104,18,126,233,126,76,126,58,230, +117,214,72,158,176,158,170,206,168,226,172,232,196,234,220,230,233,206,98,178, +143,209,14,72,95,72,14,158,83,118,56,12,56,236,29,216,100,28,127,76, +80,226,94,216,108,206,120,206,134,214,152,226,168,228,241,230,94,116,114,116, +115,206,146,104,171,152,140,78,239,78,204,14,204,206,173,211,98,140,98,66, +32,66,32,140,99,140,90,162,115,214,16,210,103,190,64,198,65,12,220,82, +220,30,138,30,138,82,221,82,130,244,130,126,230,126,230,238,207,242,178,82, +178,130,168,160,145,194,212,188,177,141,38,20,81,52,18,86,61,114,32,232, +73,138,212,78,212,24,116,24,116,78,213,78,102,240,102,120,228,120,228,216, +224,238,203,240,170,88,160,148,146,172,121,196,202,192,163,143,104,12,137,36, +30,80,30,48,220,48,221,78,100,66,39,102,150,64,219,94,186,136,186,98, +68,98,68,134,187,134,44,246,44,168,208,168,208,240,187,246,130,134,120,182, +73,218,120,182,177,215,120,28,72,40,31,44,14,90,239,90,80,40,80,236, +49,242,22,176,127,136,176,28,217,64,150,10,154,110,172,182,194,222,220,238, +239,208,210,114,174,178,144,206,111,233,14,50,123,50,104,148,104,86,32,86, +32,148,105,148,68,84,69,12,32,116,105,116,12,186,119,186,68,246,69,148, +174,10,150,58,121,94,172,16,194,50,237,88,146,98,177,126,136,136,167,168, +128,194,243,178,196,244,197,81,140,28,36,28,36,216,145,216,36,148,126,148, +126,90,37,90,88,28,89,90,88,148,89,216,172,244,173,8,192,84,239,155, +18,70,91,70,20,154,85,122,58,10,58,236,27,224,80,228,100,192,106,156, +108,122,108,30,220,30,220,68,109,68,122,102,235,102,198,116,231,158,166,110, +130,150,219,142,124,186,227,186,110,226,241,226,176,226,177,153,32,22,79,50, +12,88,61,114,26,228,75,148,222,20,150,34,105,36,84,110,241,110,160,32, +156,130,140,172,112,206,75,234,236,230,206,208,186,176,170,140,163,111,30,36, +229,36,16,222,241,222,130,222,131,36,78,62,56,132,29,176,110,162,69,100, +192,62,172,140,153,178,228,170,181,111,34,196,34,48,86,48,87,190,34,168, +85,168,176,114,194,112,210,100,212,48,128,48,128,146,228,146,222,220,212,234, +198,238,177,240,108,190,205,190,164,10,149,49,66,12,36,68,19,92,112,58, +45,58,32,104,103,104,18,154,111,154,64,104,64,228,105,200,174,110,194,108, +208,98,210,50,134,50,134,148,230,148,226,216,218,230,198,234,183,236,112,190, +203,190,168,8,151,51,134,110,156,108,176,100,182,88,184,48,60,48,60,142, +218,142,214,206,208,220,194,230,161,238,18,188,181,188,108,12,91,49,36,20, +77,52,20,86,61,114,28,234,69,146,92,36,223,36,70,96,241,96,132,96, +124,150,212,150,204,220,194,230,174,232,141,237,32,22,73,60,10,100,54,100, +50,228,91,186,88,34,233,34,84,222,245,222,158,222,159,34,118,72,102,130, +83,164,108,112,141,156,208,72,192,126,175,158,232,160,199,113,16,226,36,192, +46,160,50,108,50,26,214,26,214,66,51,66,70,100,233,100,184,116,221,154, +138,108,90,146,207,140,80,186,221,186,54,226,241,226,148,226,149,155,44,36, +219,36,22,108,239,108,239,108,122,36,114,126,96,166,68,204,31,232,142,108, +142,206,146,222,160,228,204,228,222,220,226,210,231,195,14,46,237,46,88,78, +89,10,158,78,159,12,46,96,207,96,24,148,229,148,116,96,110,152,96,186, +72,212,25,236,142,148,142,212,144,226,154,230,212,230,224,226,230,214,233,199, +18,74,97,74,62,244,63,12,20,168,46,122,61,86,94,140,63,104,104,32, +231,32,104,130,245,130,112,76,206,76,207,130,156,32,139,130,122,244,122,164, +214,164,215,242,122,224,215,225,32,30,221,30,18,124,241,124,50,74,188,74, +183,124,116,30,93,124,56,244,56,162,200,162,201,242,56,222,201,223,200,78, +200,28,62,28,62,78,201,78,44,114,213,114,22,160,237,160,132,114,120,168, +98,198,66,218,19,232,234,232,200,222,162,196,133,161,10,112,245,112,232,188, +52,188,66,34,202,34,192,220,180,228,166,232,155,234,134,34,128,124,116,178, +106,200,84,222,53,239,32,48,131,48,180,34,215,68,12,92,237,92,22,228, +153,206,50,126,51,222,94,104,95,214,140,150,95,150,154,12,154,110,162,156, +174,190,196,218,212,230,218,234,226,232,239,207,32,36,225,36,18,220,241,220, +118,36,95,220,48,116,188,116,181,221,16,72,97,72,18,160,93,132,58,14, +58,236,33,228,110,34,235,34,102,124,245,124,146,124,163,34,118,74,210,74, +211,124,126,242,126,158,218,158,219,242,126,222,217,223,92,8,62,66,27,104, +218,52,71,52,16,142,241,142,134,244,135,53,78,10,37,70,226,38,61,38, +20,118,237,118,50,80,223,80,76,118,77,38,110,118,111,38,148,118,149,38, +190,118,191,38,82,128,58,162,37,180,32,238,66,224,88,208,104,188,118,158, +63,158,62,178,95,198,140,154,229,154,146,166,140,198,233,198,188,244,189,129, +74,16,38,92,17,126,52,242,53,66,86,38,237,38,74,220,245,220,94,114, +208,114,203,220,120,220,151,39,72,12,40,86,17,118,50,244,51,64,130,8, +102,58,77,88,234,44,113,44,74,142,245,142,164,240,182,238,198,230,204,220, +206,84,112,84,108,202,235,202,144,156,169,184,144,96,169,125,18,88,99,88, +16,194,105,164,60,18,61,178,176,110,198,108,210,102,214,92,214,48,130,48, +130,146,234,146,228,218,220,228,210,234,179,238,86,196,201,196,166,12,149,49, +168,24,203,52,232,72,50,72,50,168,40,204,21,236,130,10,134,90,140,136, +156,180,186,216,212,230,222,234,228,230,237,206,200,100,174,156,150,186,99,229, +38,28,217,28,126,104,127,28,34,94,34,52,218,52,219,90,54,72,105,72, +54,94,105,94,146,72,197,72,148,96,197,96,102,106,68,132,45,144,24,174, +76,168,118,156,158,142,186,124,81,124,88,132,140,154,186,164,233,170,54,188, +190,184,188,210,184,222,174,230,143,236,114,166,110,198,98,216,82,226,64,232, +43,239,30,204,30,36,84,36,85,198,30,100,85,100,30,176,85,176,104,26, +233,26,98,124,245,124,114,70,208,70,205,124,144,124,161,26,120,242,120,156, +212,156,213,240,120,218,213,219,42,40,21,112,100,74,35,74,16,166,103,128, +70,242,71,12,148,16,120,72,99,100,172,232,194,228,212,220,220,204,226,66, +125,66,100,166,128,134,146,100,159,66,106,220,142,188,170,146,184,104,195,67, +90,14,62,78,29,122,154,234,184,232,202,224,212,212,214,188,216,58,73,58, +118,58,112,92,100,126,82,158,58,182,37,202,168,58,166,88,158,124,148,156, +134,184,114,208,77,239,104,10,76,56,43,88,18,144,54,134,88,120,122,102, +158,74,186,46,85,46,90,64,112,84,152,110,190,124,239,136,42,164,190,162, +186,190,180,220,172,230,158,234,137,236,120,128,116,174,106,196,94,210,72,226, +54,232,35,241,58,248,59,12,32,68,19,128,74,62,95,106,100,28,233,28, +105,74,90,126,245,126,104,74,208,74,209,126,142,126,157,28,122,244,122,164, +216,164,217,242,122,222,217,223,32,20,75,54,12,98,54,98,52,222,89,192, +208,72,208,26,110,26,110,72,209,72,96,108,225,108,78,154,239,154,156,108, +152,162,138,192,114,218,81,236,234,230,206,216,180,190,155,155,36,48,221,48, +14,98,245,98,92,98,93,12,168,98,169,8,68,244,68,134,194,134,195,240, +68,176,195,176,68,220,195,221,134,30,42,30,42,154,139,154,124,106,124,68, +70,68,70,106,125,106,96,68,97,30,96,154,97,106,232,122,230,136,220,146, +214,148,174,150,164,146,158,140,158,134,158,34,216,34,216,88,159,88,56,182, +25,238,96,188,113,234,148,184,167,228,202,180,235,235,20,78,115,78,68,246, +69,14,18,168,44,132,69,88,106,144,69,98,232,26,176,38,134,40,134,138, +128,172,114,206,91,238,248,108,135,108,198,246,199,109,16,30,237,30,102,30, +102,102,100,126,92,148,81,164,150,30,150,142,152,156,160,162,191,160,44,240, +44,92,212,92,213,238,44,208,213,209,22,36,97,36,62,36,50,88,19,142, +44,226,44,104,84,104,85,218,44,188,85,188,102,26,247,26,118,240,118,76, +226,76,227,238,118,208,227,208,152,26,152,116,146,144,137,166,188,26,188,156, +211,157,22,36,121,36,72,36,56,94,40,130,23,152,52,222,52,108,100,108, +101,218,52,196,101,196,178,16,152,88,123,134,116,234,158,208,188,178,210,144, +224,112,236,66,161,66,158,124,201,161,26,210,26,38,66,38,67,204,26,108, +67,108,26,180,67,180,80,74,151,74,116,242,117,10,80,172,117,94,150,136, +117,98,230,18,198,28,164,34,164,148,156,190,133,232,164,104,245,104,206,104, +207,243,26,196,26,46,70,46,71,186,26,164,71,164,86,40,233,40,98,72, +217,72,156,72,157,8,208,126,208,98,110,98,110,126,209,126,84,156,237,156, +130,136,141,156,188,134,175,156,110,246,110,184,210,184,211,244,110,226,211,227, +32,190,32,40,80,40,81,176,32,154,81,154,102,30,204,30,178,108,216,108, +198,154,166,200,140,218,109,234,132,30,132,88,120,144,104,180,86,204,61,224, +234,234,198,208,172,182,152,148,133,93,68,14,38,68,19,90,112,58,45,58, +30,102,101,102,18,150,109,150,62,102,62,230,107,202,218,102,218,28,134,28, +134,104,219,104,134,66,219,66,156,112,121,154,194,236,210,234,224,230,230,222, +234,138,135,138,124,198,142,184,160,164,175,138,126,238,162,216,184,190,196,162, +203,139,66,244,67,10,40,40,19,116,102,70,33,70,22,168,95,124,96,32, +247,32,114,236,114,90,226,90,227,234,114,212,227,212,152,32,152,114,150,140, +142,162,129,182,188,32,188,164,216,164,227,161,104,22,66,32,31,38,22,92, +95,92,118,100,239,100,68,242,69,32,24,182,69,104,100,140,69,106,126,20, +176,44,221,70,212,16,164,54,121,74,168,68,132,130,93,172,128,220,128,146, +220,146,220,212,195,218,170,244,171,117,194,146,194,48,66,48,66,146,195,146, +66,82,195,82,66,116,195,116,122,14,107,48,56,178,21,226,120,166,151,198, +196,178,235,222,90,174,90,214,92,224,98,234,154,234,168,230,178,220,183,203, +56,20,146,52,209,80,188,10,132,46,86,66,45,78,14,100,243,100,114,72, +82,126,56,154,23,176,72,226,72,142,202,142,202,220,177,226,134,246,135,115, +202,18,116,34,39,34,18,86,235,86,60,50,87,76,188,40,159,84,20,152, +58,136,92,110,117,86,232,146,204,138,172,122,154,106,135,86,124,146,125,32, +52,178,21,228,116,156,155,194,194,172,237,220,86,170,86,214,90,232,98,236, +156,236,168,232,182,222,189,207,16,228,32,200,36,154,36,30,80,30,80,230, +63,232,36,86,81,86,36,144,81,144,98,40,235,40,164,80,165,8,102,92, +165,48,224,88,165,48,162,86,134,120,99,144,240,138,200,124,178,112,159,92, +164,124,164,234,141,242,114,150,139,172,104,210,165,174,208,144,165,174,228,222, +171,171,110,12,74,78,29,126,26,234,94,212,152,172,194,110,208,62,83,62, +90,114,159,161,62,246,63,8,34,62,19,124,80,54,99,88,106,52,235,52, +98,100,245,100,144,100,145,12,198,100,199,8,122,244,122,136,216,136,217,244, +122,178,217,178,122,220,217,221,38,68,25,124,22,240,46,212,62,174,70,120, +71,14,106,60,71,102,92,188,67,152,214,148,214,48,124,48,124,148,213,148, +124,80,215,80,124,116,215,116,112,178,95,226,160,166,187,196,208,180,239,218, +138,174,138,218,140,230,148,238,176,238,188,236,196,228,203,210,164,12,153,49, +22,232,46,194,58,136,59,10,32,62,19,128,98,50,59,116,100,202,55,156, +128,20,178,44,225,70,216,12,162,52,119,76,96,100,245,100,170,66,142,120, +120,146,99,170,130,222,130,146,222,146,222,218,201,222,176,244,177,117,34,18, +75,46,20,78,63,110,20,236,59,148,228,20,154,32,91,32,96,48,117,78, +146,46,165,74,222,42,187,70,205,84,190,116,225,154,204,84,104,148,213,142, +144,76,100,110,165,108,70,178,243,178,154,146,146,188,130,212,102,228,71,238, +236,232,204,224,180,208,166,192,161,179,48,26,97,54,24,88,71,116,38,228, +91,156,152,12,128,84,101,126,94,236,126,228,164,206,194,172,216,126,228,64, +137,64,138,122,195,167,18,230,38,192,46,120,46,22,216,22,216,56,47,56, +146,122,147,70,74,78,127,94,68,124,127,114,220,74,169,96,170,114,227,126, +104,134,75,182,224,158,91,158,58,196,241,196,150,244,151,141,16,78,89,78, +54,244,55,12,14,174,55,96,82,132,55,102,148,102,148,48,102,48,102,102, +149,102,102,74,149,74,114,114,133,132,84,142,169,142,80,232,96,210,106,184, +110,158,111,142,110,168,152,168,144,218,138,224,121,226,194,12,178,80,161,122, +174,110,190,164,208,200,239,234,244,74,181,74,218,74,212,132,202,178,178,212, +155,242,130,12,117,49,24,50,227,50,156,12,189,36,114,6,104,64,88,92, +68,108,44,124,27,134,192,64,146,94,101,108,144,50,144,104,148,118,156,120, +194,120,208,116,225,92,110,124,137,146,14,158,241,158,28,218,64,200,94,174, +111,158,142,212,96,236,97,172,138,170,166,202,198,220,227,234,202,172,167,201, +124,8,157,30,242,40,50,40,50,154,40,196,23,226,66,84,239,84,110,52, +110,120,186,120,187,52,86,228,86,158,212,158,212,226,191,230,148,244,149,121, +40,38,212,38,206,220,155,230,76,76,131,114,40,180,179,133,14,78,92,78, +80,156,52,204,17,234,64,16,32,156,93,196,214,146,214,48,124,48,124,146, +215,146,124,80,213,80,124,114,213,114,164,14,149,48,116,180,87,226,162,166, +185,194,210,174,241,222,138,176,138,216,142,232,152,236,184,236,192,232,203,209, +24,40,233,40,34,72,221,72,128,72,129,10,196,130,196,98,60,98,60,130, +197,130,12,162,243,162,80,140,99,156,170,138,153,162,54,248,54,188,200,188, +201,246,54,230,201,231,66,14,34,74,21,88,108,60,43,60,28,102,101,102, +20,150,107,150,62,102,62,226,103,196,138,32,122,80,113,100,228,68,129,68, +108,128,241,128,174,128,175,14,150,128,150,166,138,204,122,226,97,240,186,128, +186,214,190,230,196,234,222,234,228,230,237,209,32,28,75,60,18,88,61,116, +26,228,69,150,116,32,100,78,89,102,218,66,105,66,76,124,233,124,156,124, +157,14,130,124,130,158,118,194,100,218,71,240,172,124,172,216,174,232,184,236, +214,236,224,228,233,207,216,24,142,34,31,42,190,60,64,146,201,138,174,108, +215,154,128,40,56,98,143,92,134,144,134,214,130,226,116,238,101,234,84,166, +31,222,164,164,227,217,36,244,36,28,86,28,62,104,74,120,82,140,84,166, +72,180,57,184,130,36,101,84,188,36,235,74,164,84,165,12,212,158,212,98, +116,98,116,160,213,160,116,128,213,128,213,128,165,178,166,160,166,218,160,232, +144,238,133,232,126,184,87,230,198,184,235,227,22,50,110,50,98,110,84,150, +58,188,25,222,40,94,111,200,184,34,219,68,116,100,239,84,216,118,186,168, +154,202,105,236,158,10,158,98,166,160,186,204,208,232,220,236,230,230,241,207, +100,66,34,166,99,156,70,20,22,102,81,96,22,220,103,198,122,238,122,44, +226,44,227,238,122,214,227,214,122,126,227,126,174,214,175,45,36,226,36,44, +82,44,83,220,36,96,83,96,36,148,83,148,36,200,83,200,146,16,175,36, +112,90,112,48,228,48,229,88,128,84,211,84,118,114,223,114,100,144,241,144, +168,162,169,60,126,244,126,176,216,176,217,242,126,222,217,223,106,138,106,68, +36,68,36,138,107,138,106,158,133,206,18,208,121,184,70,10,71,194,108,38, +243,38,170,38,171,242,242,148,171,101,226,28,38,28,38,224,239,224,202,150, +202,68,80,68,80,152,203,152,140,206,141,68,80,110,203,111,30,28,209,28, +26,88,26,54,216,54,217,86,122,112,123,28,44,76,97,76,44,98,97,98, +144,76,197,76,146,98,197,98,38,244,38,122,102,122,102,152,39,152,38,178, +105,178,38,208,111,208,124,122,198,122,198,150,125,150,130,174,194,174,172,202, +142,222,120,230,97,238,234,232,202,226,176,218,154,204,131,175,14,58,101,58, +68,14,26,132,107,132,18,198,109,176,70,248,71,86,144,14,185,38,116,84, +116,50,234,50,235,84,128,84,223,84,132,114,223,114,118,144,241,144,178,164, +179,60,136,246,136,178,220,178,221,244,136,220,221,221,30,218,30,36,70,36, +71,208,30,108,71,108,30,186,71,186,102,244,102,30,148,30,148,84,103,84, +162,30,216,30,216,86,163,86,234,234,194,202,170,156,163,122,126,236,166,216, +202,174,216,124,163,124,148,128,103,128,148,180,103,181,90,64,91,210,26,66, +26,198,91,190,56,16,57,194,108,56,225,56,114,82,139,120,210,80,191,118, +96,140,237,140,162,10,162,146,146,184,126,210,108,228,89,242,238,238,210,216, +186,188,165,141,78,12,42,80,17,114,54,244,55,60,94,56,233,56,80,136, +241,136,104,74,131,114,214,76,189,116,160,8,160,88,154,140,138,186,114,212, +83,238,236,236,210,216,188,190,174,166,161,137,24,24,58,64,76,112,78,184, +68,226,46,236,29,226,88,26,52,66,21,94,16,170,48,144,75,118,100,56, +233,56,96,140,241,140,112,82,135,124,212,82,191,122,164,10,164,70,158,144, +146,182,126,210,106,226,87,240,240,238,214,222,194,200,178,174,167,141,18,34, +237,34,122,240,123,34,152,92,217,157,244,34,46,34,46,154,34,200,19,230, +68,60,229,60,206,152,206,84,92,84,92,152,207,152,144,60,133,84,92,108, +207,108,92,130,207,130,126,162,90,192,63,208,60,238,90,234,134,222,176,198, +198,178,111,178,238,232,202,228,162,218,136,206,115,191,16,26,237,26,192,136, +192,58,62,58,62,136,193,136,106,58,119,26,62,84,193,84,192,110,63,110, +88,144,60,178,37,200,24,236,48,232,84,224,120,208,152,186,176,164,73,164, +228,230,202,228,154,216,110,196,89,181,34,196,34,36,84,36,85,190,34,170, +85,170,98,36,241,36,156,240,157,36,180,96,229,163,14,70,81,70,12,150, +77,120,52,12,52,230,21,222,146,26,120,36,98,40,98,142,90,184,71,220, +150,98,99,98,132,210,133,98,182,12,162,72,151,88,218,102,228,66,165,66, +186,86,180,162,168,192,152,216,129,236,236,234,216,210,200,178,183,135,56,12, +32,72,17,92,94,62,37,62,30,100,89,100,14,142,93,142,54,100,54,208, +83,186,164,32,130,36,108,38,108,150,100,190,88,222,75,238,164,90,109,90, +140,214,141,90,194,16,178,84,163,120,222,110,236,70,183,70,196,98,196,140, +184,182,166,212,154,226,141,240,240,238,226,222,208,188,197,141,80,26,58,76, +43,104,208,68,63,68,22,126,235,126,128,126,129,10,104,126,104,154,90,194, +66,218,46,230,25,238,152,126,152,208,156,226,170,234,210,234,226,222,233,201, +80,10,46,86,17,120,58,242,59,60,226,74,227,240,106,74,106,222,227,214, +164,10,165,219,66,14,38,56,17,78,112,172,112,86,34,86,34,174,113,174, +34,128,113,128,72,174,73,86,46,46,98,46,75,86,18,222,125,208,136,16, +167,50,124,70,241,70,216,14,187,70,132,122,229,122,124,178,245,178,180,246, +181,71,73,18,100,64,30,166,105,158,72,18,18,98,77,96,16,222,101,202, +222,28,150,42,115,46,100,122,245,122,170,242,171,39,226,54,48,54,48,166, +40,200,19,238,184,16,213,38,156,2,160,90,172,150,194,206,216,236,222,240, +226,236,243,206,212,94,196,158,172,198,137,230,68,102,143,102,132,198,132,142, +82,142,82,198,133,199,36,110,37,20,86,110,87,12,114,28,210,28,194,54, +178,72,150,90,113,106,130,28,138,48,154,68,182,90,231,110,64,204,64,124, +182,124,183,198,126,144,118,182,106,206,78,224,50,230,29,236,138,200,217,237, +74,14,25,80,68,82,38,130,19,154,54,244,55,106,128,18,100,70,87,92, +164,58,109,58,98,100,151,100,82,146,165,146,120,100,120,216,161,192,174,38, +241,38,174,102,247,102,212,102,212,224,206,234,171,235,20,234,34,212,40,180, +42,146,42,50,104,50,104,220,96,236,75,238,66,74,79,104,68,146,81,182, +160,18,189,54,14,128,105,128,76,16,61,50,118,68,243,68,200,170,235,230, +216,100,140,218,223,210,174,76,138,140,191,139,52,20,85,58,44,240,45,64, +104,40,216,40,216,228,183,236,66,108,195,108,132,224,133,62,70,192,98,164, +131,108,190,186,162,152,133,123,34,20,73,46,18,82,57,108,26,220,67,142, +86,36,124,36,86,110,124,110,116,174,92,206,69,230,86,134,112,190,130,208, +168,222,239,224,226,30,174,40,151,44,156,82,156,180,233,180,192,180,193,36, +192,108,231,109,14,38,84,38,84,96,32,96,30,148,86,148,82,210,72,232, +39,236,148,18,179,52,102,68,243,68,207,108,196,180,233,236,204,106,118,226, +221,216,160,76,120,144,179,141,12,82,82,80,78,136,60,192,19,236,58,12, +36,158,87,198,116,10,147,40,94,56,235,56,200,12,167,56,138,244,139,56, +174,244,175,56,106,90,210,90,210,158,105,158,94,124,241,124,78,226,112,196, +139,164,236,222,218,210,196,184,177,159,202,116,202,32,56,32,56,114,203,114, +56,72,203,72,50,142,79,196,212,138,173,194,14,226,239,226,104,126,105,226, +150,126,151,227,26,246,26,30,84,30,52,102,68,122,82,152,74,178,47,192, +152,14,124,68,83,110,148,20,172,54,204,84,237,102,112,110,203,110,86,230, +229,230,108,148,127,200,144,132,165,188,210,142,175,231,14,34,99,34,18,104, +95,104,14,204,99,174,56,34,57,188,122,154,122,24,208,24,209,150,164,56, +164,112,152,166,122,206,79,238,172,140,172,210,180,228,218,228,232,218,239,199, +12,52,129,52,28,244,28,94,120,94,120,234,101,240,72,92,73,12,50,110, +69,134,48,150,103,150,44,182,105,182,74,228,75,150,96,110,77,150,134,92, +231,92,176,12,176,108,172,158,158,204,137,238,238,232,216,206,188,158,177,122, +198,30,223,69,14,164,241,164,64,164,64,34,190,34,191,164,64,78,191,78, +64,120,191,120,154,180,217,238,110,174,36,230,193,217,18,236,32,196,36,152, +36,34,84,34,84,232,65,238,36,90,85,90,36,146,85,146,210,108,210,40, +122,40,122,108,211,108,122,74,211,74,160,6,149,40,166,108,166,236,145,242, +104,146,144,146,130,196,109,222,166,130,180,156,214,198,237,218,230,132,193,169, +58,12,36,66,15,96,80,92,92,58,41,58,48,100,48,226,93,192,158,10, +128,70,103,100,182,100,222,46,141,46,156,112,114,128,115,244,176,126,224,126, +225,238,114,216,225,216,158,172,115,172,180,170,225,171,78,14,103,34,30,44, +229,44,174,14,149,44,46,74,209,74,20,106,239,106,128,106,129,44,34,132, +73,160,22,218,81,190,130,118,112,152,93,174,194,174,210,142,117,142,148,156, +132,196,108,222,73,242,222,238,202,228,174,206,145,167,112,12,147,38,34,86, +34,48,220,48,221,86,82,72,62,114,51,130,192,104,69,104,129,64,20,146, +231,146,128,146,129,64,104,146,104,174,96,196,82,214,62,226,27,238,146,146, +146,212,150,228,158,234,204,234,216,230,224,216,229,199,32,244,32,32,88,32, +62,102,76,122,86,144,84,174,74,188,51,192,156,10,124,70,101,100,186,100, +218,48,137,48,156,112,110,126,111,244,174,124,222,124,223,242,156,172,111,172, +178,172,223,172,110,218,223,219,30,244,30,30,90,30,58,100,74,116,90,142, +86,170,72,180,53,184,166,204,118,232,118,34,206,34,206,124,119,124,118,80, +207,80,156,124,162,148,174,174,194,206,231,236,224,142,179,179,100,54,28,164, +95,152,66,16,20,96,73,94,16,224,105,198,178,26,215,52,108,94,225,76, +106,148,237,124,216,148,174,200,140,224,105,238,152,12,152,94,158,148,172,196, +186,220,212,240,224,240,239,211,18,76,111,76,68,242,69,12,18,168,69,86, +106,140,69,100,130,240,130,34,222,34,223,236,130,92,223,92,130,150,223,150, +130,210,223,211,242,30,40,30,40,130,34,190,19,232,58,98,133,98,94,240, +95,46,56,178,95,118,128,156,95,122,148,240,148,68,218,68,219,236,148,114, +219,114,148,158,219,158,148,206,219,207,62,12,34,66,19,88,94,52,43,52, +30,96,89,96,20,140,95,140,56,96,56,220,93,182,148,10,181,30,98,38, +245,38,156,86,156,60,116,60,116,86,157,86,228,86,228,60,182,60,182,88, +229,88,104,112,235,112,110,136,227,136,96,164,245,164,146,164,147,92,190,164, +191,94,92,216,126,200,146,184,165,164,174,214,132,238,135,194,174,178,186,198, +204,220,237,240,216,180,195,207,206,18,128,30,41,34,20,70,233,70,129,132, +128,132,129,30,20,146,64,122,94,96,117,70,236,138,204,126,172,104,150,84, +139,70,68,244,68,146,188,146,189,238,68,184,189,184,68,220,189,221,68,12, +44,52,21,82,130,38,55,38,96,72,79,38,164,12,142,54,129,76,242,38, +151,38,200,74,179,38,20,120,111,120,72,244,73,78,18,200,73,132,106,172, +73,138,130,242,130,94,214,94,215,242,130,212,213,212,130,170,215,170,130,132, +213,133,112,8,143,30,18,38,237,38,110,90,110,64,52,64,52,90,111,90, +202,90,202,62,144,62,144,90,203,90,36,116,219,116,50,140,207,140,18,168, +241,168,94,168,95,98,162,168,163,96,20,216,52,204,86,184,105,168,82,188, +82,236,133,210,132,182,156,204,186,220,235,232,196,182,167,209,36,22,73,52, +22,82,65,114,26,226,59,140,74,78,149,78,114,244,115,10,74,176,92,146, +113,78,146,140,115,100,162,242,162,30,226,30,227,238,162,212,225,212,162,150, +227,150,162,92,227,93,210,110,178,172,136,206,90,226,45,236,188,52,76,154, +189,148,134,12,58,94,147,91,30,18,57,48,16,66,113,66,104,16,73,66, +26,114,109,114,14,164,107,164,68,66,68,176,58,210,33,242,112,40,156,40, +156,234,131,242,128,164,157,140,120,88,143,116,174,38,224,38,224,236,199,242, +174,76,203,114,174,166,225,131,38,20,75,54,12,80,80,80,60,120,21,164, +58,246,59,124,98,158,61,120,122,18,155,52,108,66,235,66,210,14,179,66, +116,122,223,122,110,174,245,174,170,246,171,67,38,20,79,60,16,98,58,98, +56,224,91,190,112,16,149,52,92,66,239,66,208,12,171,66,98,116,227,116, +110,168,247,168,166,246,167,67,20,64,115,64,72,162,73,10,20,138,50,104, +73,74,110,114,73,76,212,144,212,28,130,28,130,146,213,146,130,68,213,68, +130,104,213,104,56,180,29,230,124,166,153,198,202,172,237,216,90,174,90,212, +92,226,108,236,156,236,176,232,188,220,195,205,32,202,32,60,80,60,81,194, +32,176,81,176,116,240,116,60,224,60,224,234,199,242,190,172,190,102,148,102, +148,172,191,172,166,10,149,61,102,12,147,38,26,48,229,48,186,114,186,80, +64,80,64,114,187,114,48,144,180,144,130,176,130,226,126,236,118,240,93,242, +18,188,239,189,12,44,97,44,16,178,95,152,54,164,55,44,96,22,241,22, +118,192,118,74,216,74,217,188,172,20,159,74,168,100,168,134,166,168,154,196, +126,220,83,238,174,192,235,241,36,52,219,52,16,102,237,102,90,102,91,12, +166,102,167,12,18,168,46,154,72,130,97,102,238,158,216,146,190,132,165,102, +206,200,200,216,186,230,104,230,88,226,82,212,82,142,174,142,174,184,83,185, +16,72,93,72,60,244,61,14,18,168,46,120,61,84,92,128,61,92,156,10, +126,44,107,56,222,112,222,74,116,74,116,112,223,112,134,36,196,36,173,74, +172,74,152,126,99,158,138,238,152,238,168,230,174,210,174,186,166,160,139,134, +90,194,126,176,155,150,98,224,136,204,169,172,220,134,169,168,192,152,200,176, +210,196,237,221,74,16,40,88,15,120,54,244,55,58,146,14,116,54,79,82, +220,114,220,76,106,76,106,114,221,114,128,38,192,38,169,76,162,76,154,114, +136,130,112,146,83,160,132,238,148,236,160,232,168,222,172,202,168,184,162,168, +152,152,142,142,131,132,80,196,108,184,128,168,149,148,78,226,102,216,130,200, +146,186,163,170,218,132,165,172,238,224,222,212,206,196,196,176,187,155,38,242, +38,68,212,68,212,236,177,240,98,16,71,68,160,180,160,120,90,120,90,180, +161,181,100,12,62,54,27,84,202,110,202,72,60,72,60,110,203,110,80,34, +156,34,136,72,112,120,80,140,54,150,33,156,98,128,114,138,130,154,138,178, +140,204,136,224,126,234,110,238,93,238,32,194,58,186,84,172,102,158,119,144, +28,232,58,222,94,202,118,182,135,168,190,130,135,166,230,224,208,212,188,192, +174,174,161,151,16,38,239,38,92,60,93,10,164,60,165,6,18,110,241,110, +48,138,194,138,194,78,49,78,130,246,131,52,64,156,58,204,46,226,33,240, +202,242,203,152,106,164,77,218,150,164,177,209,14,40,105,40,16,136,38,106, +54,70,59,40,44,216,44,104,92,104,93,210,44,184,93,184,122,20,153,62, +234,18,201,62,132,242,132,88,226,88,226,234,201,240,132,132,227,132,132,176, +227,176,178,88,179,7,32,24,223,24,26,92,26,50,228,50,229,90,128,100, +129,24,50,72,105,72,50,96,105,96,152,74,207,74,152,96,207,96,48,244, +48,146,210,146,210,238,173,244,126,146,127,110,58,112,101,136,210,110,159,136, +48,174,211,174,48,202,211,203,28,34,59,72,140,30,113,70,40,240,40,94, +130,94,130,232,103,240,84,94,85,14,40,134,131,134,40,174,131,174,174,180, +175,50,220,12,220,234,191,243,32,198,32,50,78,50,79,178,32,164,79,164, +108,48,189,48,92,94,235,94,152,94,153,12,124,130,204,130,174,158,174,220, +166,232,154,238,137,238,214,30,164,110,126,156,79,194,236,176,117,177,108,58, +108,26,38,26,38,58,109,58,212,58,212,26,140,26,140,58,213,58,18,82, +233,82,50,152,50,110,202,110,203,146,116,110,123,82,126,124,102,150,74,162, +48,166,21,170,136,144,239,174,40,242,40,184,106,184,107,240,40,224,107,224, +142,242,142,184,208,184,209,240,142,224,209,225,66,12,36,64,19,84,106,54, +43,54,28,98,99,98,16,146,105,146,60,98,60,230,103,190,116,28,145,64, +230,24,203,66,126,244,126,96,222,96,222,238,199,246,172,96,173,10,126,138, +223,138,126,182,223,183,38,28,77,56,18,86,59,114,32,230,77,142,108,32, +133,66,224,30,197,68,114,250,114,92,220,92,220,240,191,248,114,136,221,136, +114,180,221,180,166,92,167,13,106,14,147,36,32,88,32,48,224,48,225,86, +62,76,95,106,188,72,159,102,58,244,58,120,198,120,198,238,169,244,128,120, +129,62,58,158,197,158,58,192,199,193,34,22,77,52,20,80,61,114,30,236, +59,150,110,18,158,42,211,76,198,12,144,52,97,78,74,100,239,100,152,70, +112,138,77,174,120,246,120,130,206,130,206,242,179,246,120,164,207,164,120,196, +207,197,28,212,28,44,78,44,79,206,28,114,79,114,28,184,79,184,94,62, +225,32,214,56,156,98,103,122,136,8,146,64,170,102,206,122,222,122,233,108, +90,152,233,152,136,152,136,172,132,196,122,216,106,230,85,242,178,152,178,216, +180,230,188,236,212,236,222,230,231,209,66,80,50,138,23,194,184,84,233,190, +130,14,130,214,130,232,112,238,97,237,52,46,177,46,18,86,249,86,118,8, +119,84,48,124,180,124,138,160,138,240,109,248,26,178,237,178,212,26,126,102, +21,161,16,76,97,76,66,248,67,12,18,180,50,122,65,78,100,140,67,108, +110,62,243,62,150,16,185,50,156,80,109,124,194,82,237,120,206,128,184,172, +156,208,134,222,99,240,136,134,152,166,184,204,237,239,44,28,93,68,206,26, +161,72,54,242,54,94,204,94,204,232,167,240,54,138,205,138,54,180,205,180, +128,94,129,11,30,184,30,44,68,44,69,176,30,154,69,154,80,72,243,72, +154,242,155,8,94,40,210,40,210,104,93,104,132,142,117,200,172,140,199,194, +100,126,96,188,84,218,69,238,218,238,219,125,70,10,44,52,25,76,122,42, +51,42,96,78,79,42,168,10,125,74,238,40,147,40,204,76,185,40,198,94, +148,100,53,108,30,148,233,148,130,102,124,160,98,198,66,222,27,236,228,236, +198,220,168,198,148,174,135,149,52,14,85,48,16,60,127,60,54,88,19,136, +84,90,123,128,42,146,109,210,98,138,60,200,21,238,162,8,142,74,127,100, +238,70,145,70,110,242,148,216,178,178,194,136,202,98,209,70,238,232,206,212, +180,188,160,158,145,113,18,72,89,72,58,242,59,10,16,168,59,94,88,132, +61,96,124,144,125,10,92,40,159,40,100,76,157,76,100,112,157,112,168,32, +226,32,222,108,216,126,199,132,164,128,180,100,188,68,193,32,88,166,243,166, +90,236,118,224,140,204,152,182,161,136,238,236,208,224,186,206,164,178,161,167, +16,144,133,120,44,32,45,138,90,16,91,128,130,70,91,70,150,14,150,124, +154,136,164,144,218,144,228,128,233,108,226,44,151,86,56,174,203,174,24,226, +233,227,118,94,118,28,38,28,38,94,119,94,38,62,119,62,58,104,19,156, +90,234,110,228,126,208,128,126,41,126,82,140,57,190,74,158,103,186,36,160, +36,210,97,210,168,10,152,76,135,110,212,104,224,68,155,68,178,98,176,144, +170,176,154,210,131,240,240,238,216,212,196,178,177,135,92,148,92,70,26,70, +26,148,93,148,88,176,103,220,14,220,95,200,60,206,61,10,216,104,216,28, +130,28,130,104,217,104,130,66,217,66,146,114,118,150,107,158,196,238,216,232, +226,214,230,138,127,138,124,168,124,216,197,216,176,148,147,198,198,192,169,165, +12,50,123,50,42,14,42,84,96,84,97,16,104,158,104,116,28,116,28,156, +103,156,10,194,121,194,68,248,69,84,130,56,229,56,124,112,241,112,176,112, +177,12,128,172,227,172,108,226,247,226,176,224,177,129,8,88,77,88,44,246, +45,14,90,74,200,68,188,212,180,228,153,232,144,14,144,106,130,172,110,204, +75,238,104,116,81,174,216,120,241,179,16,74,93,74,12,160,91,122,60,16, +60,236,27,226,102,58,233,58,92,140,243,140,110,84,135,122,210,78,191,122, +162,12,162,98,156,148,142,186,118,216,89,236,236,238,206,214,182,182,163,141, +22,68,89,68,20,156,93,126,62,14,62,232,33,224,134,16,110,70,87,100, +120,148,121,48,168,18,189,40,130,54,233,54,130,82,225,82,130,108,225,108, +130,138,241,138,178,138,179,54,96,160,202,160,190,188,230,188,226,220,222,228, +210,236,183,236,146,160,146,176,138,196,124,214,104,228,85,239,28,28,137,28, +56,50,36,114,143,114,104,28,104,228,75,236,96,114,58,176,23,210,162,244, +162,28,224,28,190,102,212,122,228,152,224,184,192,194,185,191,82,10,50,58, +19,90,74,24,133,70,38,88,117,88,22,134,131,134,50,162,19,208,98,162, +131,204,78,88,78,236,53,242,130,168,245,160,202,242,203,10,140,34,183,84, +136,96,177,139,16,236,30,204,36,164,38,140,38,32,92,32,92,230,67,238, +38,90,93,90,38,146,93,146,114,74,208,74,204,232,175,240,164,10,164,102, +156,174,136,212,105,240,134,108,113,164,218,110,247,165,38,22,75,60,12,96, +54,96,50,222,89,172,106,12,106,110,155,88,158,50,107,50,178,8,178,86, +182,98,194,106,218,106,232,100,239,82,232,36,179,62,112,244,112,140,208,140, +209,240,112,180,209,180,112,222,209,222,162,110,151,141,36,68,36,30,222,30, +223,68,84,56,78,136,210,136,204,208,192,232,165,238,26,182,177,182,204,88, +83,89,18,74,93,74,62,244,63,14,18,168,61,92,88,132,63,98,102,66, +241,66,186,10,186,112,190,170,204,220,216,234,226,240,236,230,241,210,206,22, +229,46,104,134,173,134,122,86,122,146,114,178,102,208,89,228,154,206,155,89, +70,10,44,58,29,78,142,46,53,46,20,102,153,102,18,216,147,196,46,130, +47,210,92,46,93,202,92,144,139,144,168,244,168,42,226,42,226,182,220,200, +200,202,197,201,70,16,52,46,21,76,28,158,40,138,48,116,48,68,124,68, +124,146,111,150,86,144,87,68,90,68,108,38,57,38,48,94,125,94,124,118, +49,118,136,32,220,32,220,48,218,60,208,70,197,72,172,32,172,42,166,58, +147,80,168,82,149,114,232,98,159,98,140,126,241,126,192,154,193,80,200,198, +200,170,56,170,56,198,201,198,25,234,190,208,229,240,24,234,213,228,130,230, +131,149,50,246,51,16,26,68,19,122,58,74,73,106,108,12,81,70,76,234, +86,210,90,180,92,162,92,86,152,86,152,232,135,238,122,212,123,86,92,130, +153,130,92,170,153,170,120,84,136,44,95,44,162,32,228,32,224,82,205,86, +186,32,184,60,173,82,182,106,167,150,238,126,177,126,168,170,245,170,206,242, +207,97,32,20,71,52,14,86,59,116,24,236,73,154,66,94,245,94,236,226, +102,226,103,32,146,16,146,178,198,178,199,15,34,28,69,62,24,84,59,118, +28,230,61,146,90,70,90,34,222,34,223,68,124,60,118,140,214,140,210,212, +204,226,192,232,171,234,220,92,123,92,78,184,189,185,24,26,63,66,8,100, +46,100,46,218,83,182,94,146,94,50,150,50,150,240,125,244,68,148,149,148, +94,82,151,82,94,114,151,114,78,224,108,196,126,170,139,148,122,14,107,50, +164,86,251,86,172,118,195,160,216,14,216,236,189,243,24,234,40,202,48,168, +52,132,52,28,216,28,216,66,53,66,76,90,125,116,222,82,177,110,88,248, +88,130,218,130,218,240,189,248,150,130,151,78,88,162,219,162,88,196,219,197, +16,40,239,40,94,68,95,8,162,66,163,10,60,66,87,84,26,94,131,94, +16,140,139,140,46,108,69,130,110,108,91,140,28,172,133,172,52,188,23,224, +106,188,127,212,84,140,84,236,57,240,226,68,186,82,156,88,156,166,150,202, +127,238,156,134,243,134,204,134,205,243,20,50,243,50,94,84,95,12,164,84, +165,8,52,136,25,204,112,94,149,146,194,126,239,192,88,124,88,208,92,222, +102,230,156,230,174,226,182,212,187,193,66,16,36,70,19,90,110,62,43,62, +28,102,101,102,18,152,105,152,104,200,60,228,61,102,160,16,191,44,120,56, +237,56,138,74,161,110,108,124,247,124,214,72,187,124,114,176,239,176,176,246, +177,125,112,24,44,44,44,146,36,184,19,220,122,94,45,94,92,222,93,94, +162,10,146,74,119,122,212,106,226,62,151,62,174,94,172,144,158,184,138,212, +103,240,236,238,208,212,184,174,173,137,98,14,141,38,38,54,219,54,64,70, +101,108,16,122,241,122,182,66,145,122,30,174,227,174,128,246,129,123,60,14, +89,38,22,50,133,50,42,70,67,96,16,108,137,108,114,66,87,108,22,146, +135,146,80,108,80,234,59,238,52,168,23,216,102,170,125,200,228,18,156,42, +156,158,146,200,123,236,246,104,157,104,206,242,207,105,58,246,59,10,34,64, +17,122,78,60,101,102,228,20,172,30,126,34,126,160,114,204,89,240,244,102, +127,102,192,246,193,103,36,92,15,186,102,14,141,66,190,94,241,160,88,82, +88,204,94,226,108,232,154,232,174,222,184,206,191,181,80,14,50,74,17,118, +56,244,57,62,142,14,181,42,82,56,245,56,104,94,225,94,104,132,225,132, +110,246,110,170,214,170,215,244,110,222,213,223,12,208,135,194,32,204,32,64, +116,64,117,196,60,64,61,202,88,64,89,198,74,18,53,64,138,40,161,82, +230,38,209,82,136,114,237,114,132,172,245,172,186,242,187,11,198,100,198,26, +58,26,58,100,199,100,58,64,199,64,60,118,46,152,27,180,222,142,51,142, +58,180,209,180,16,226,239,226,130,226,131,109,20,232,32,196,38,140,38,28, +86,28,86,230,65,236,38,84,87,84,38,142,85,142,218,92,218,26,126,26, +126,94,219,94,126,60,219,60,132,112,111,166,236,134,125,134,122,176,227,176, +102,222,245,222,176,222,177,103,22,28,46,48,66,72,70,88,76,126,76,140, +76,196,72,212,60,228,35,234,90,16,56,60,25,92,20,166,73,114,222,98, +222,32,120,32,120,100,223,100,120,64,223,64,130,114,114,150,103,168,234,140, +119,140,120,180,225,180,92,226,245,226,174,226,175,113,58,244,59,14,34,66, +19,126,80,60,95,102,218,98,218,30,118,30,118,98,219,98,118,64,219,64, +126,116,101,170,232,140,115,140,118,182,223,182,90,226,245,226,170,226,171,109, +42,40,89,108,104,20,139,92,14,138,237,138,210,34,155,138,96,162,62,202, +27,230,144,162,219,227,16,32,151,32,12,114,157,114,60,32,60,132,56,166, +46,198,34,218,21,236,112,238,113,32,178,182,179,40,222,12,222,234,201,243, +32,36,145,36,20,90,153,90,64,36,64,90,58,118,40,144,31,154,110,36, +111,144,174,126,175,34,224,16,224,144,197,154,46,182,213,182,16,228,239,228, +130,228,131,147,22,34,147,34,14,118,153,118,58,34,58,122,52,178,40,212, +25,234,108,236,109,34,218,20,182,60,147,94,226,92,190,130,149,156,236,158, +192,202,137,233,28,34,147,34,20,116,151,116,66,34,66,130,62,168,54,196, +40,218,27,234,114,34,115,236,168,246,168,30,220,30,192,106,222,134,232,152, +234,170,232,192,199,205,82,16,52,52,23,78,92,74,54,124,21,158,64,244, +65,112,112,34,227,34,92,110,247,110,198,110,198,232,159,243,14,30,121,30, +30,244,30,80,110,80,111,238,30,180,111,180,30,218,111,218,58,30,58,96, +52,134,41,156,82,30,82,136,84,144,111,144,222,98,222,30,146,30,146,98, +223,98,146,64,223,64,150,114,136,154,125,176,234,142,141,142,144,180,229,180, +122,226,245,226,184,226,185,111,44,48,213,48,18,92,241,92,128,92,129,8, +50,148,209,148,76,108,105,140,174,104,143,148,32,192,229,192,130,246,131,149, +18,56,235,56,130,134,131,8,18,138,54,120,94,86,119,56,238,128,208,116, +160,80,143,56,66,246,66,154,194,154,195,242,66,220,195,221,62,244,63,12, +38,66,25,126,82,60,95,102,132,34,118,94,99,128,230,76,123,76,122,144, +225,144,102,224,239,224,174,224,175,11,12,82,92,80,82,152,60,204,21,240, +66,12,32,152,103,210,138,34,122,102,111,128,232,78,129,78,122,146,231,146, +108,226,245,226,178,226,179,13,188,118,188,30,62,30,62,118,189,118,16,236, +48,226,74,206,92,178,100,148,103,118,238,188,230,216,216,228,174,228,150,220, +151,119,38,84,38,214,213,208,214,236,215,80,54,38,136,114,185,170,172,26, +126,112,61,179,20,232,32,202,40,146,40,28,84,28,84,228,61,232,40,84, +85,84,40,136,85,136,146,4,122,62,103,90,182,228,210,224,226,212,230,50, +129,50,130,86,160,122,185,158,180,70,156,126,133,160,118,112,118,184,198,184, +199,107,90,8,56,64,27,98,156,232,202,228,216,212,222,46,69,46,60,98, +60,192,172,192,173,94,84,86,122,130,153,170,146,80,112,134,79,173,44,16, +85,52,20,76,65,110,22,232,75,142,102,74,102,224,221,216,222,244,223,74, +196,18,160,122,119,198,116,34,164,120,197,191,16,72,113,72,68,12,58,80, +46,124,21,168,82,120,42,216,107,200,88,162,119,220,154,16,124,74,97,110, +136,244,137,50,178,16,211,48,146,66,241,66,146,116,235,116,146,162,235,162, +146,212,247,212,190,212,191,67,80,14,34,66,121,60,100,34,131,70,48,186, +48,88,114,88,114,180,87,186,48,114,115,114,48,142,115,142,152,14,152,70, +162,84,208,84,220,78,231,60,216,28,153,54,152,96,152,156,164,174,212,174, +226,162,233,142,218,110,153,132,54,196,27,238,96,196,103,238,142,192,159,232, +192,190,227,237,78,12,46,86,17,124,56,244,57,64,80,76,239,76,156,244, +157,8,76,202,114,160,157,90,240,200,210,170,157,87,64,16,38,90,17,124, +50,246,51,60,82,202,83,80,144,12,122,56,105,78,98,124,126,116,152,100, +178,76,204,44,129,44,132,62,164,90,194,106,241,120,178,118,142,146,113,164, +198,146,162,176,119,198,222,178,176,212,142,230,105,241,76,10,105,38,26,50, +233,50,180,10,155,50,44,82,209,82,14,116,245,116,122,50,118,84,102,126, +76,158,52,178,19,196,84,152,198,152,197,226,68,188,197,188,32,228,243,228, +122,228,131,153,24,76,117,76,78,240,79,14,22,178,52,132,77,76,122,146, +79,100,102,38,243,38,162,38,154,116,226,116,218,202,208,226,188,232,167,233, +32,192,32,42,78,42,79,186,32,164,79,164,210,134,210,42,116,42,116,134, +211,134,116,72,211,72,116,102,211,102,162,8,149,42,94,176,237,176,160,146, +150,190,136,210,112,228,81,240,188,148,211,168,232,238,212,228,196,218,180,202, +167,177,68,12,36,68,17,88,108,58,45,58,28,100,101,100,18,150,109,150, +104,190,62,222,63,100,220,22,164,34,119,40,110,76,237,76,166,128,167,34, +106,126,132,112,167,78,238,124,204,110,167,78,122,140,198,140,188,178,222,178, +216,216,204,230,177,236,152,140,148,168,138,198,122,220,99,239,200,24,142,36, +47,44,26,80,229,80,126,134,127,38,24,146,62,130,121,80,230,136,188,124, +127,84,62,146,168,146,162,178,198,178,194,214,180,232,143,232,102,146,92,186, +72,216,37,241,48,16,85,48,20,66,90,66,66,104,21,148,64,246,65,108, +108,168,65,130,108,106,79,142,126,244,126,70,228,70,229,240,126,140,229,140, +126,216,229,216,176,216,177,9,90,54,28,158,93,150,68,12,20,92,67,90, +12,216,95,196,216,20,170,28,109,32,106,70,237,70,162,122,163,30,90,126, +124,104,157,70,238,124,206,108,169,70,112,138,194,138,182,172,216,172,210,220, +196,236,169,238,142,138,138,172,126,208,91,239,16,90,83,90,16,190,87,164, +52,18,53,174,218,88,228,62,102,62,102,152,92,200,69,240,154,62,155,10, +154,34,223,34,116,110,207,96,156,76,156,120,162,132,202,132,216,124,223,112, +118,164,141,202,224,160,203,200,102,230,243,230,158,230,159,150,188,230,189,149, +184,20,217,46,230,62,50,62,50,162,42,198,19,238,126,144,51,144,150,10, +158,110,162,144,180,200,202,228,212,236,226,232,239,202,210,112,168,178,142,202, +115,221,36,24,223,24,32,92,32,52,226,52,227,90,128,114,129,24,54,78, +107,78,54,102,107,102,150,78,203,78,150,100,203,100,16,130,241,130,50,240, +50,164,208,164,208,216,206,224,200,232,179,234,104,164,121,130,104,228,105,164, +154,226,155,165,218,92,230,70,54,70,54,154,48,196,27,240,132,70,133,12, +132,40,219,40,72,112,201,100,134,80,134,122,136,128,142,136,198,136,208,132, +214,122,221,112,78,162,103,202,218,160,193,202,58,232,245,232,122,232,123,148, +166,232,167,151,26,202,26,54,68,54,69,194,26,174,69,174,220,94,228,68, +100,68,100,166,94,204,77,240,116,108,207,92,158,76,158,114,160,124,168,130, +204,130,214,126,223,110,106,230,243,230,154,230,155,144,186,230,187,144,118,164, +139,208,230,160,207,208,152,68,152,12,152,38,223,39,78,18,50,52,27,72, +86,82,54,116,27,138,92,148,56,192,23,220,100,32,241,32,122,192,122,78, +218,78,219,190,158,78,171,32,168,106,168,140,162,176,144,202,120,224,89,240, +176,190,237,239,74,14,42,52,21,72,76,70,48,112,19,142,52,244,53,110, +156,10,126,62,104,86,79,106,240,102,206,80,174,50,151,22,106,102,207,102, +90,146,225,146,122,172,83,222,186,178,229,220,158,102,158,228,152,236,142,242, +133,243,34,26,75,58,10,98,54,98,52,222,99,186,136,10,112,72,89,108, +232,60,117,60,90,136,245,136,170,246,171,61,24,36,229,36,88,58,89,8, +162,58,163,10,116,50,141,66,16,76,243,76,174,84,54,144,205,132,178,110, +225,146,102,76,58,108,131,104,58,246,58,164,198,164,199,242,58,226,199,226, +58,194,199,194,126,226,127,165,14,30,123,30,30,236,30,76,106,76,107,230, +30,210,107,210,30,168,107,168,42,140,54,110,56,82,57,30,80,30,80,118, +84,130,107,130,226,68,227,238,136,72,136,220,227,216,144,28,182,112,209,184, +208,18,186,104,147,193,82,16,48,68,17,98,124,78,75,30,38,98,119,98, +20,144,135,144,52,168,19,218,100,166,131,202,78,98,78,218,76,228,68,236, +45,238,114,240,156,206,184,170,200,140,210,102,218,50,127,50,240,236,216,218, +194,194,174,158,158,114,152,80,147,51,10,84,104,78,104,180,104,212,108,222, +120,228,204,228,224,224,232,212,237,194,208,178,208,46,142,46,142,178,209,178, +142,108,209,108,60,12,60,124,50,176,38,208,19,241,120,12,157,36,244,46, +48,46,48,162,40,196,21,236,120,108,179,134,82,80,210,80,159,124,70,142, +236,142,215,182,158,142,158,214,154,230,142,236,125,237,110,12,139,32,16,44, +237,44,166,100,215,138,178,58,56,134,197,126,106,52,58,88,133,84,52,248, +52,160,204,160,205,244,52,194,205,194,52,228,205,228,130,228,131,161,56,242, +57,12,30,66,19,122,74,68,93,106,74,216,245,216,108,216,108,68,216,68, +217,216,164,14,139,68,144,216,145,68,180,216,181,69,86,10,54,68,139,100, +26,44,130,44,102,78,66,100,29,114,224,90,224,36,160,36,160,90,225,90, +176,144,231,186,190,112,78,180,209,172,122,108,64,146,137,144,96,200,37,236, +168,196,227,230,138,178,138,220,134,234,126,236,111,237,12,76,84,74,76,134, +60,178,42,202,19,220,60,8,30,144,97,196,104,28,228,28,219,52,132,56, +120,94,101,124,126,76,138,90,158,102,180,106,243,106,170,28,171,102,224,70, +171,70,124,242,124,134,216,134,216,216,212,228,204,234,185,234,124,164,217,164, +124,196,217,197,94,52,30,160,95,152,64,16,22,94,69,92,16,222,97,200, +116,50,197,50,96,100,243,100,162,100,163,10,134,246,134,142,214,142,215,242, +134,182,213,182,134,222,215,222,224,32,172,112,120,162,101,177,94,62,28,162, +91,152,68,14,20,96,71,94,18,216,95,196,102,46,233,46,98,84,228,84, +205,120,166,84,167,10,114,102,147,124,108,134,139,154,88,174,245,174,92,238, +138,214,162,182,168,152,177,100,178,192,229,237,18,52,127,52,74,8,32,126, +123,126,16,188,129,168,82,244,83,74,144,40,239,40,136,132,247,132,184,246, +185,41,32,198,32,48,76,48,77,190,32,168,77,168,140,14,173,42,104,82, +104,52,226,52,227,82,120,90,211,90,208,192,208,122,120,122,120,192,209,192, +120,158,209,158,80,230,241,231,110,16,145,38,34,94,34,48,224,48,225,92, +60,88,199,88,186,196,186,120,74,120,74,196,187,196,74,156,187,156,18,230, +239,231,16,110,239,110,66,110,66,26,194,26,195,110,66,54,195,54,66,82, +195,82,160,118,217,156,106,110,52,148,195,142,60,176,25,222,118,160,149,190, +192,172,233,212,90,168,90,204,94,220,104,228,154,228,170,224,178,214,185,201, +44,16,75,52,12,68,105,68,50,68,50,124,38,188,15,236,50,116,90,116, +84,208,78,220,70,226,57,228,148,10,126,58,97,98,242,50,131,50,120,96, +226,96,211,126,136,132,122,198,97,242,126,180,138,200,154,216,178,228,204,232, +245,232,174,96,175,226,230,156,175,157,110,16,149,52,20,66,237,66,164,166, +215,240,179,100,178,100,120,168,50,230,201,220,118,66,58,144,139,145,34,28, +69,70,18,228,32,214,52,206,64,206,80,216,106,226,130,230,235,228,12,112, +58,112,59,206,116,30,102,66,93,88,218,60,107,60,78,104,229,104,156,12, +157,104,92,200,110,186,126,164,132,142,137,104,222,162,218,178,210,188,198,196, +184,196,172,184,173,105,128,12,159,32,242,44,54,44,54,152,42,200,25,236, +18,68,37,104,16,150,55,128,144,182,144,114,84,114,84,182,145,182,84,148, +145,148,114,182,115,114,110,52,73,108,92,78,136,78,115,114,68,222,155,210, +162,60,183,92,156,108,239,108,226,58,201,108,162,146,233,146,158,188,243,188, +196,246,197,109,32,234,32,42,90,42,91,228,32,96,91,96,32,148,91,148, +32,206,91,206,150,14,185,56,104,68,247,68,211,104,196,178,239,238,208,104, +132,228,223,216,166,76,128,148,183,145,100,50,32,158,103,144,70,14,22,98, +73,94,20,214,105,196,152,10,130,66,109,100,136,54,228,54,224,200,220,218, +206,230,179,234,186,184,186,100,132,100,132,184,187,184,132,142,187,143,16,44, +121,44,48,14,48,78,92,78,93,14,102,150,102,110,36,110,36,150,103,150, +14,184,121,184,70,246,71,78,154,18,128,92,119,110,142,244,143,52,188,16, +188,212,196,230,206,236,214,236,226,228,230,216,235,200,224,60,194,120,163,163, +18,40,239,40,96,66,97,10,160,56,161,10,38,242,38,94,98,94,98,136, +39,136,70,60,49,94,38,174,100,174,101,238,38,220,101,220,162,68,185,86, +116,98,231,98,136,110,157,138,110,152,239,152,204,110,175,152,116,190,233,190, +172,246,173,153,50,22,91,62,110,12,143,58,34,122,34,80,224,80,225,120, +202,16,163,80,62,118,176,118,132,154,132,220,128,230,120,238,95,238,16,168, +241,169,108,16,141,48,38,104,38,60,216,60,217,104,100,98,78,174,54,210, +23,238,146,94,158,142,174,180,198,216,231,239,34,22,221,22,34,104,34,54, +222,54,223,102,126,130,127,22,54,82,107,82,54,112,107,112,150,82,203,82, +148,112,203,112,44,144,200,144,201,242,52,182,201,182,42,222,201,223,12,218, +245,218,52,218,52,64,204,64,205,218,120,14,91,64,104,218,105,64,152,218, +153,65,120,72,120,32,48,32,48,72,121,72,40,184,40,102,130,102,131,178, +84,122,80,172,68,198,46,218,21,230,88,186,127,210,140,80,226,78,222,192, +218,216,206,226,181,228,180,12,176,120,164,180,150,210,125,239,196,18,138,28, +51,32,16,58,239,58,198,134,198,84,60,84,60,134,199,134,80,94,109,122, +176,94,149,118,38,160,221,160,28,186,235,186,130,186,131,28,60,202,27,240, +96,202,113,240,148,200,167,236,196,198,231,235,78,12,23,78,84,70,48,116, +21,146,60,244,61,102,228,20,180,28,110,30,110,134,100,188,77,230,110,76, +245,76,138,244,138,114,222,114,223,240,138,146,223,146,138,180,223,180,138,216, +223,216,174,114,187,43,92,12,58,72,25,106,70,50,220,50,214,204,210,222, +196,236,167,240,156,198,156,100,68,100,68,198,157,198,68,146,157,147,36,26, +81,64,14,102,62,102,62,230,97,198,136,14,114,66,89,102,120,56,226,56, +222,206,218,228,210,236,187,236,182,190,182,104,120,104,120,190,183,190,120,146, +183,147,48,28,196,28,196,106,47,106,56,66,195,66,12,144,243,144,178,116, +178,212,174,226,168,232,162,234,141,236,66,168,111,205,42,56,40,130,102,130, +98,202,94,216,84,222,63,224,18,186,83,166,18,32,90,32,85,130,136,24, +136,162,130,190,122,214,109,234,178,218,179,34,218,236,219,17,38,18,73,66, +18,230,34,216,48,206,62,206,84,214,114,224,140,228,241,224,10,104,54,104, +55,206,122,20,84,108,108,148,121,190,168,20,132,110,152,146,169,190,212,24, +180,112,200,146,221,189,18,38,115,38,18,150,38,124,50,96,58,64,63,38, +22,232,50,210,66,190,80,162,90,130,94,94,53,94,50,140,79,162,154,12, +128,70,111,96,180,238,208,236,224,222,226,56,137,56,180,186,180,102,130,102, +130,186,181,186,130,144,181,145,30,16,71,50,12,82,55,114,24,232,67,150, +80,24,200,24,198,92,200,148,204,186,210,216,216,224,224,226,234,220,247,184, +84,112,171,112,126,238,127,25,42,16,77,54,16,90,58,90,58,214,99,166, +84,236,102,208,114,182,120,144,120,116,121,16,170,210,171,30,220,238,221,13, +30,20,73,62,8,102,52,102,52,230,93,186,84,32,192,32,192,100,196,164, +202,208,208,224,214,226,224,226,247,200,90,120,167,120,128,234,129,33,30,30, +61,68,22,228,32,216,48,206,62,206,76,212,98,222,128,228,239,226,12,108, +54,108,55,206,72,28,140,28,110,68,110,194,89,200,72,140,135,94,186,12, +186,198,161,204,156,72,137,160,210,70,231,153,36,24,75,64,20,228,36,216, +48,208,62,208,78,210,104,218,134,226,241,226,12,110,54,110,55,208,84,32, +198,32,198,118,204,160,208,180,216,190,222,190,230,184,241,162,90,104,175,104, +132,200,133,33,234,40,48,40,48,150,40,196,19,240,76,126,213,126,52,226, +243,226,144,226,145,66,176,154,211,201,14,66,97,66,18,154,97,122,60,10, +60,238,31,226,120,180,120,30,230,30,231,178,174,244,175,30,120,94,231,94, +120,156,231,157,26,34,121,34,50,58,28,114,125,114,92,34,92,236,67,242, +20,202,50,176,91,114,162,60,187,88,186,112,198,110,210,106,216,92,216,44, +140,44,140,136,230,136,228,210,222,228,212,236,191,234,112,182,209,182,172,10, +161,45,30,178,30,40,108,40,109,172,30,154,109,154,30,100,109,100,70,242, +71,40,162,62,187,88,172,114,188,112,204,106,212,94,212,42,142,42,142,146, +228,146,226,202,222,220,218,228,212,230,179,236,110,188,203,188,172,12,161,43, +30,188,30,36,80,36,81,178,30,156,81,156,110,32,239,32,134,50,116,118, +243,118,190,32,190,234,159,242,74,218,104,200,136,174,187,119,40,24,111,76, +216,20,130,96,131,241,16,46,239,46,94,74,95,14,158,74,159,12,44,94, +219,94,70,106,50,146,233,146,168,94,168,212,164,224,158,232,150,234,133,234, +26,230,82,206,157,147,38,32,225,32,82,56,52,114,237,114,168,32,168,234, +125,228,26,212,78,186,118,154,155,115,98,136,98,68,30,68,30,136,97,136, +18,204,101,180,90,162,113,198,67,16,64,16,65,188,118,34,237,34,152,58, +126,124,243,124,170,234,198,230,202,218,203,34,94,230,126,208,160,174,195,125, +50,20,50,60,218,60,219,24,136,60,137,14,234,90,52,90,52,152,44,200, +23,240,78,122,215,122,68,156,235,156,142,156,143,98,72,192,219,192,54,228, +243,228,140,228,141,167,62,18,21,82,68,82,40,126,19,152,50,242,51,114, +82,28,165,28,74,120,171,120,104,120,117,28,84,68,152,68,149,120,94,226, +94,152,152,152,153,220,94,202,153,202,176,34,235,34,174,100,245,100,210,100, +210,214,206,226,200,232,175,237,38,22,81,54,22,88,65,118,28,226,65,146, +234,34,100,34,100,158,90,194,71,232,122,84,221,84,108,126,233,126,166,126, +167,48,116,176,225,176,100,224,239,224,168,224,169,141,28,34,117,34,50,68, +34,112,119,112,88,34,88,214,84,226,80,232,61,234,22,204,48,174,89,112, +158,14,130,68,113,94,136,246,137,56,184,14,205,44,148,64,241,64,148,110, +235,110,148,156,233,156,148,208,243,208,188,208,189,65,30,190,30,40,74,40, +75,178,30,158,75,158,92,80,119,160,224,78,193,162,90,32,233,32,70,220, +245,220,138,220,139,32,176,220,177,33,26,36,231,36,18,220,235,220,36,86, +77,168,214,82,177,168,104,220,105,36,154,220,155,37,40,26,77,66,14,102, +58,102,58,212,99,166,104,32,239,32,198,32,198,210,194,224,188,232,159,236, +130,58,110,118,245,118,98,212,140,182,195,119,36,32,219,32,20,100,235,100, +70,100,71,54,130,100,131,32,130,66,203,66,70,108,62,168,222,168,218,208, +214,218,210,226,204,230,177,236,54,190,31,230,86,194,99,226,126,186,143,220, +166,182,185,210,68,134,209,135,32,194,32,46,78,46,79,186,32,166,79,166, +112,242,112,32,224,32,225,240,112,212,225,212,130,98,209,98,170,48,166,118, +156,148,135,180,206,172,167,117,36,246,37,66,46,16,75,56,102,36,218,36, +218,236,193,240,62,82,193,82,126,52,102,100,86,118,61,140,168,186,168,134, +88,134,88,186,169,186,88,160,169,160,126,110,126,200,128,208,136,218,170,218, +180,214,189,198,150,96,203,135,32,60,21,134,64,8,64,108,58,162,44,200, +23,232,100,54,65,102,102,188,61,148,118,242,118,26,228,26,229,238,118,212, +229,212,134,92,213,92,174,44,174,96,168,124,158,150,137,176,212,170,173,115, +32,22,73,54,14,86,57,114,24,236,65,154,86,46,235,46,152,6,136,58, +112,94,71,130,238,124,206,100,188,82,169,46,208,196,208,114,104,114,104,196, +209,196,104,154,209,154,156,80,156,212,158,228,166,236,208,236,224,234,237,215, +24,56,127,56,26,132,127,106,76,14,77,118,164,10,165,136,228,102,196,76, +165,54,14,228,243,228,52,228,52,158,202,158,203,228,104,228,105,158,148,228, +149,159,38,32,231,32,240,110,54,110,54,160,46,200,23,238,114,110,115,32, +160,110,161,32,54,58,87,90,218,56,187,91,18,34,103,34,16,124,38,98, +54,68,63,34,44,220,44,104,90,104,91,212,44,188,91,188,124,30,235,30, +106,122,247,122,146,30,146,146,134,190,116,218,95,238,200,30,201,243,90,138, +90,66,28,66,28,138,91,138,17,208,82,160,101,202,14,208,93,188,60,194, +61,8,100,34,138,34,116,112,140,112,134,170,118,208,89,240,106,150,122,184, +138,202,158,216,194,226,241,228,224,22,196,36,159,44,164,88,164,186,235,186, +196,186,197,36,196,106,231,107,54,20,54,70,208,70,209,20,130,70,131,8, +16,108,247,108,20,196,52,176,80,148,103,108,78,244,78,156,202,156,203,244, +78,218,203,219,30,32,98,32,48,108,96,108,88,146,74,182,50,208,27,228, +46,144,62,176,82,198,116,216,154,222,237,222,224,28,154,40,117,46,130,76, +130,174,233,174,172,38,173,174,172,104,225,105,104,12,143,40,16,52,241,52, +54,90,203,90,54,128,203,128,58,246,58,170,196,170,197,242,58,220,197,221, +60,10,85,34,26,42,121,42,48,56,69,80,126,92,36,92,38,154,32,200, +21,234,104,56,89,92,104,106,80,126,57,142,114,138,88,160,61,180,122,176, +90,208,53,232,130,30,241,30,146,186,146,78,218,78,219,184,174,78,181,30, +182,104,180,168,172,198,158,216,127,238,194,196,237,231,40,242,41,60,50,12, +79,52,102,30,216,30,216,218,214,230,200,234,185,234,124,52,98,90,79,112, +140,114,162,78,109,78,120,120,80,136,80,204,178,204,178,130,141,130,118,166, +81,166,142,164,179,165,76,32,55,76,206,28,173,66,128,8,122,64,108,90, +84,106,56,120,31,126,120,72,156,84,192,98,229,120,130,108,122,156,110,184, +92,204,58,222,19,236,72,140,51,182,204,136,173,172,124,148,138,172,164,198, +198,216,237,231,44,18,81,48,16,84,55,112,24,232,75,152,92,120,114,100, +120,82,122,64,122,26,198,26,198,82,200,98,206,102,243,98,118,242,118,134, +210,134,211,240,118,214,211,215,20,52,239,52,122,12,92,70,66,98,44,118, +19,136,158,52,166,70,188,96,216,116,239,130,186,188,186,108,68,108,68,188, +187,188,68,146,187,146,126,76,126,218,128,228,138,232,176,234,202,234,216,228, +226,214,233,203,14,74,89,74,14,158,83,128,58,18,58,238,27,228,90,52, +233,52,162,14,148,62,124,86,89,110,174,52,184,68,206,92,241,106,206,184, +110,184,110,118,206,118,207,184,110,150,207,150,156,84,156,214,160,228,168,232, +212,232,226,224,235,203,28,226,28,32,84,32,85,222,28,90,85,90,28,142, +85,142,28,202,85,202,168,202,120,234,120,30,208,30,208,120,121,120,120,76, +209,76,160,120,164,144,170,164,184,190,208,214,235,230,228,142,183,183,70,16, +42,52,23,72,74,74,46,114,19,146,56,242,57,102,102,26,147,58,92,82, +135,110,90,208,153,148,168,36,235,36,160,98,245,98,204,98,204,230,171,241, +32,26,71,54,18,88,63,116,26,236,69,146,130,10,167,34,88,80,88,44, +228,44,229,80,104,78,211,78,214,182,214,110,100,110,100,184,215,184,156,184, +157,78,100,146,215,146,134,198,81,242,174,198,235,235,14,68,109,68,18,118, +105,118,10,168,113,168,62,246,63,12,236,204,230,224,220,230,210,234,146,234, +136,230,130,220,130,92,216,92,216,154,131,154,154,12,136,54,113,88,170,92, +198,44,141,44,172,154,173,93,16,82,85,82,18,196,87,172,52,8,53,182, +238,26,102,26,102,228,243,228,214,110,214,52,142,52,142,110,213,110,142,82, +213,82,118,144,245,144,178,118,144,170,235,206,210,144,196,168,172,190,129,211, +16,40,237,40,96,8,96,72,160,72,161,8,76,80,77,178,22,110,77,110, +18,168,77,152,182,76,182,154,188,168,196,172,212,172,224,168,228,154,231,142, +226,90,183,116,148,158,148,104,106,104,106,158,149,158,66,192,31,240,104,196, +117,234,150,192,169,228,196,188,237,233,238,30,50,30,50,136,44,184,27,230, +174,60,209,90,70,112,231,112,140,48,140,116,132,154,116,182,94,208,63,234, +232,232,192,200,164,166,141,119,18,44,111,44,18,136,38,110,54,80,67,44, +44,212,44,106,90,106,91,206,44,184,91,184,126,162,126,30,214,30,215,160, +170,70,170,102,162,150,146,184,124,212,85,240,178,144,178,216,182,230,194,236, +216,236,226,230,237,205,234,28,46,28,46,134,40,174,21,222,104,44,82,98, +59,134,86,244,87,90,152,42,126,100,105,132,132,244,133,90,174,44,203,74, +140,90,235,90,140,132,227,132,140,170,227,170,140,216,237,216,184,216,185,91, +30,194,30,48,72,48,73,184,30,162,73,162,142,14,175,42,84,54,241,54, +106,94,219,94,106,132,219,132,112,246,112,170,212,170,213,244,112,222,213,223, +116,12,145,36,44,48,225,48,240,100,48,100,48,178,40,212,21,244,190,112, +126,142,83,158,202,148,142,182,81,200,222,182,156,220,69,240,88,58,117,90, +182,60,145,101,32,60,19,130,66,10,64,144,50,192,23,236,110,48,67,116, +96,202,63,150,162,10,136,68,111,102,188,104,220,48,147,48,160,114,116,132, +117,246,184,126,226,126,227,244,154,172,117,172,186,168,227,168,116,218,227,219, +104,14,139,38,32,84,32,50,222,50,223,84,188,134,188,78,68,78,68,136, +189,136,68,106,189,106,14,166,243,166,118,142,72,194,221,238,168,166,156,188, +136,208,112,220,76,232,29,239,38,24,71,60,12,100,50,100,50,218,81,170, +142,14,179,40,94,50,233,50,238,102,102,102,102,176,92,208,73,238,122,66, +149,92,202,62,173,102,204,118,160,142,127,152,216,150,174,178,127,194,234,184, +170,222,115,237,36,52,32,132,96,132,92,210,90,222,78,232,57,234,12,190, +73,178,160,12,130,72,95,108,236,100,200,80,176,52,157,22,124,106,211,106, +14,28,80,28,75,132,118,150,141,200,154,134,175,184,108,226,237,226,216,140, +187,227,16,36,111,36,56,36,56,58,40,108,19,148,18,232,44,208,68,174, +82,132,88,94,47,94,46,138,73,158,98,134,241,134,126,134,126,62,210,62, +211,134,168,8,168,140,152,178,124,210,87,238,240,232,210,210,188,178,169,137, +18,140,243,140,62,140,62,64,198,64,199,140,130,10,130,86,122,152,102,182, +72,210,21,238,234,232,208,220,176,198,148,168,131,141,18,80,243,80,68,80, +68,44,194,44,195,80,132,18,120,64,96,94,70,114,46,124,23,132,238,124, +210,118,182,108,166,94,153,80,156,162,174,160,186,156,190,146,192,126,74,126, +74,184,220,184,216,218,210,228,196,236,177,238,28,210,185,210,122,100,109,126, +102,142,137,163,102,20,58,34,19,38,16,94,105,94,64,244,65,34,18,186, +65,106,104,158,65,116,100,136,247,136,122,136,122,64,216,64,217,136,170,12, +170,82,166,120,156,160,140,188,120,210,89,230,236,232,208,210,188,184,172,154, +167,137,18,76,111,76,70,244,71,12,22,166,71,92,106,140,71,100,112,34, +206,34,132,114,230,114,224,200,220,214,210,224,177,230,94,190,126,170,146,144, +165,114,116,232,148,206,176,174,192,140,201,115,16,74,101,74,20,152,99,116, +62,12,62,236,35,244,108,36,204,36,122,116,226,116,220,204,214,222,198,230, +175,232,90,196,116,180,134,160,159,116,112,234,140,218,166,186,180,164,197,117, +82,14,46,90,19,126,60,244,61,62,118,16,153,50,94,66,239,66,210,14, +181,66,106,120,225,120,88,174,245,174,166,246,167,67,132,12,169,34,242,48, +70,48,70,156,60,198,35,240,26,68,51,100,22,160,69,132,96,84,200,84, +116,140,228,140,222,214,218,228,210,232,179,234,92,200,122,182,142,160,157,140, +98,238,132,224,162,200,182,172,197,141,28,66,227,66,44,122,211,122,16,178, +239,178,72,16,109,56,186,12,143,66,126,248,127,67,34,24,83,52,18,84, +67,112,30,230,73,148,96,66,239,66,108,118,223,118,88,172,243,172,166,246, +167,66,120,16,153,54,206,12,179,67,38,240,38,32,98,32,68,96,86,118, +96,140,96,160,86,174,72,180,57,176,124,240,124,38,218,38,219,236,124,120, +219,120,124,202,219,203,74,12,48,56,21,88,228,42,57,42,60,70,215,70, +38,96,198,96,198,112,196,152,200,194,210,222,220,234,228,238,232,236,243,210, +34,142,177,142,46,174,163,174,22,206,183,206,108,246,109,142,68,110,93,132, +154,108,125,143,74,16,42,86,21,116,58,244,59,52,152,28,112,40,112,198, +153,168,174,244,174,36,224,36,224,198,201,205,124,12,161,38,244,46,62,46, +62,154,54,194,23,238,24,66,45,104,16,150,63,124,116,70,145,98,82,106, +233,106,200,66,171,106,96,150,223,150,76,194,245,194,160,246,161,107,78,16, +113,40,40,52,219,52,176,14,153,52,54,86,205,86,28,120,231,120,126,52, +122,92,104,132,74,154,52,168,25,180,232,182,202,168,174,146,155,120,52,242, +76,230,92,206,96,194,97,156,168,246,169,157,14,72,105,72,64,248,65,12, +18,172,48,120,65,78,104,140,65,96,128,18,159,54,114,66,239,66,124,120, +227,120,104,174,247,174,176,248,177,66,212,12,183,67,36,26,71,58,18,88, +59,116,24,234,63,150,112,16,143,40,82,50,231,50,192,14,167,50,94,78, +223,78,78,108,237,108,156,108,157,50,142,118,175,136,108,144,158,144,158,240, +135,244,82,174,130,174,120,196,104,212,88,222,73,232,230,226,198,202,178,180, +166,162,159,152,222,146,177,177,36,32,65,72,18,226,30,216,44,208,58,208, +74,216,94,226,126,230,241,228,12,110,50,110,51,208,146,96,146,40,92,40, +92,96,147,96,92,68,147,68,120,12,113,40,106,106,127,122,74,130,157,130, +102,130,98,168,81,200,112,200,124,198,132,194,140,184,142,154,101,154,188,16, +174,80,157,112,174,114,231,196,236,72,179,72,154,206,184,180,200,154,206,126, +210,98,213,73,18,236,36,196,40,152,40,34,86,34,86,238,63,240,40,94, +85,94,40,152,87,152,104,36,241,36,222,118,222,74,122,74,122,118,223,118, +154,118,155,36,186,118,187,36,166,126,128,188,233,236,102,158,245,158,204,158, +188,192,168,216,138,230,113,239,10,72,96,70,90,118,78,160,56,198,19,234, +62,8,34,148,103,202,224,22,158,38,119,40,108,114,239,114,168,36,168,120, +158,164,140,196,120,216,93,238,236,234,208,206,190,180,169,125,14,38,99,38, +20,114,93,114,18,216,95,188,58,38,59,200,224,14,154,30,111,32,110,54, +133,84,150,46,173,80,226,40,191,92,134,96,99,144,220,118,121,118,88,160, +243,160,114,180,114,226,219,220,218,178,219,242,166,118,167,223,16,72,93,72, +18,156,93,118,62,14,62,238,35,230,216,16,156,30,105,36,102,62,127,88, +148,50,173,84,222,46,195,90,136,96,105,144,222,118,123,118,90,160,243,160, +220,176,221,242,114,178,114,228,219,220,166,224,167,119,28,60,221,30,200,54, +120,102,41,130,100,8,108,52,130,92,172,122,200,128,210,124,221,102,18,152, +239,152,100,152,100,174,90,202,72,220,52,232,29,244,152,152,152,220,154,228, +164,238,200,238,218,230,224,218,229,207,26,32,67,68,20,232,34,218,46,210, +60,210,76,216,106,230,134,236,241,232,10,110,52,110,53,210,214,20,160,30, +95,36,94,56,119,84,142,52,165,82,222,46,193,84,120,88,91,128,214,108, +107,108,76,146,235,146,109,160,212,160,213,216,108,160,108,202,213,196,156,198, +157,109,108,12,143,36,34,82,34,48,220,48,221,80,102,64,33,110,152,68, +223,110,102,96,59,146,198,124,81,124,18,166,237,166,59,184,202,184,203,246, +61,184,58,184,58,230,203,226,128,228,129,125,38,24,75,56,14,100,56,100, +54,226,89,196,218,18,144,34,101,38,98,62,127,92,146,50,169,84,224,46, +191,96,134,98,101,140,222,120,119,120,78,160,243,160,216,180,217,242,110,178, +110,230,217,226,162,226,163,121,12,86,88,82,80,140,72,172,50,204,23,228, +60,14,34,154,101,202,98,60,127,100,142,18,142,150,136,192,118,220,93,238, +96,166,143,136,178,14,178,206,182,220,188,226,226,226,236,218,243,202,230,52, +201,96,232,164,179,129,28,198,28,52,80,52,81,190,28,168,81,168,142,14, +175,46,96,58,241,58,144,80,107,122,184,78,233,118,130,128,152,168,186,202, +239,234,202,128,176,178,148,206,122,226,91,243,216,22,150,36,33,42,56,60, +77,102,116,54,139,98,204,52,173,100,110,110,52,122,53,242,148,122,206,122, +207,242,106,166,53,166,148,166,207,166,52,218,207,219,20,52,239,52,96,80, +97,18,164,78,165,14,108,104,38,184,105,176,76,82,34,136,79,136,32,230, +111,212,152,88,130,134,111,160,150,156,179,190,138,116,218,116,216,212,212,228, +202,234,173,239,18,26,237,26,208,108,208,60,48,60,48,108,207,108,100,26, +101,108,154,26,155,108,17,148,16,148,243,148,118,118,76,180,223,226,174,148, +164,170,148,190,122,208,82,222,37,231,28,46,47,80,102,46,85,82,16,110, +105,110,66,110,67,16,54,110,54,158,38,204,17,236,76,110,76,214,105,188, +110,30,162,30,163,104,118,46,141,62,110,92,163,72,176,30,228,30,229,102, +182,48,203,60,178,88,229,74,138,104,116,140,97,162,122,246,123,130,170,106, +191,122,136,132,239,132,136,162,229,162,136,194,229,194,136,224,245,224,180,224, +181,133,18,72,85,72,54,12,55,246,18,166,42,124,55,88,82,132,55,90, +86,30,171,30,82,196,167,178,146,244,147,30,106,190,107,30,106,80,147,80, +106,130,147,130,186,244,186,34,232,34,204,108,220,126,232,148,236,168,232,184, +220,190,209,195,28,192,28,192,28,48,64,48,65,178,28,158,65,158,80,40, +235,40,104,68,213,68,156,68,157,12,90,124,90,94,224,94,225,124,108,120, +205,120,200,182,200,146,110,146,110,182,201,182,76,232,239,232,116,198,137,220, +184,194,167,233,18,30,147,30,24,200,151,174,118,238,119,30,54,30,55,192, +54,82,119,82,54,132,119,132,168,238,168,28,228,28,194,96,212,112,224,130, +230,154,230,174,218,186,193,189,98,10,41,66,152,14,217,50,168,44,140,70, +110,92,76,110,46,120,17,126,90,48,112,70,140,88,172,102,208,114,239,120, +62,132,190,132,190,180,186,196,182,200,178,202,153,206,112,246,113,133,122,114, +122,30,34,30,34,114,123,114,34,74,123,74,20,156,133,156,18,210,137,192, +76,200,77,30,136,28,222,28,181,86,148,62,199,102,134,116,236,116,217,148, +184,116,184,212,182,224,172,232,145,233,24,44,63,82,24,216,79,138,157,12, +180,50,235,102,156,10,102,98,223,90,108,244,108,142,208,142,209,242,108,218, +209,219,12,122,206,78,202,156,200,166,194,174,169,182,132,14,133,196,64,52, +64,196,66,218,74,226,96,230,204,230,222,224,234,206,239,193,20,28,241,28, +68,198,68,78,198,78,199,190,130,28,119,78,132,106,130,158,120,190,100,210, +82,220,60,230,35,238,148,188,231,235,18,72,95,72,18,154,87,118,60,12, +60,214,58,224,52,232,29,236,152,10,179,36,96,50,241,50,130,68,100,136, +83,162,114,246,115,108,172,64,154,116,135,158,236,230,210,214,194,198,174,178, +162,158,149,130,160,98,218,98,214,126,208,154,194,178,174,204,158,220,133,238, +174,128,209,153,16,224,241,224,106,224,107,18,152,224,153,20,42,70,81,168, +216,74,171,169,28,198,28,44,84,44,85,190,28,168,85,168,104,98,241,98, +170,244,171,9,190,138,190,54,44,54,44,138,191,138,108,12,108,94,118,154, +136,188,162,214,186,228,198,234,208,234,218,224,227,200,198,158,130,200,84,216, +31,228,44,96,191,97,18,232,32,206,36,184,40,154,40,34,82,34,82,232, +59,236,40,88,83,88,40,142,83,142,152,10,179,38,100,48,243,48,136,62, +122,102,95,150,118,244,119,110,176,62,158,112,135,152,176,118,187,144,164,98, +218,98,212,124,202,152,184,184,158,208,135,226,238,224,208,206,182,182,164,158, +149,129,106,12,143,44,20,56,243,56,92,70,54,136,21,174,68,250,69,116, +146,70,118,128,89,166,120,150,134,174,154,194,180,212,208,230,233,240,132,102, +214,102,196,142,174,174,154,200,124,224,89,242,146,126,183,163,38,26,77,52, +20,80,65,110,26,236,59,140,138,12,173,40,86,52,239,52,124,68,90,136, +75,154,102,244,103,116,166,70,150,114,121,154,140,126,154,160,170,186,198,212, +229,230,154,102,216,102,208,134,190,168,166,202,144,218,123,230,168,128,199,153, +16,124,239,125,24,40,231,40,44,74,213,74,128,74,129,10,30,140,30,102, +226,102,227,140,52,130,205,130,188,188,188,156,64,156,64,188,189,188,14,230, +239,230,80,200,105,230,172,200,151,231,228,30,40,30,40,224,239,224,110,48, +84,92,67,112,212,78,93,78,68,132,227,132,144,78,142,136,134,156,114,180, +92,194,71,204,154,148,217,201,16,66,101,66,16,158,93,122,62,6,62,236, +27,226,208,62,208,20,132,20,132,62,209,62,102,92,245,92,96,208,247,198, +130,204,131,92,212,246,213,92,130,132,213,132,130,166,213,167,62,16,38,74, +17,104,102,66,45,66,32,108,101,108,20,150,103,150,64,108,64,230,103,202, +148,14,181,48,110,66,239,66,162,66,152,102,138,130,118,158,99,178,184,202, +144,232,145,120,176,88,180,122,190,156,208,188,241,222,230,104,191,155,80,14, +44,90,15,124,58,246,59,62,138,18,173,46,76,64,241,64,76,176,100,156, +122,122,149,64,176,190,134,228,135,100,164,90,170,124,184,160,208,192,239,216, +222,98,181,149,70,12,46,72,17,116,50,238,51,68,90,34,208,34,209,178, +84,154,209,154,72,96,247,96,140,34,140,104,134,158,124,182,108,206,77,237, +110,18,147,54,18,66,237,66,18,188,54,158,94,108,119,66,130,194,82,234, +83,124,136,92,142,118,152,148,170,180,192,204,212,218,237,234,210,98,159,159, +112,28,32,28,32,208,117,208,100,148,100,82,60,82,60,148,101,148,78,82, +79,28,78,208,79,148,130,28,239,28,134,182,134,76,212,76,213,180,158,76, +171,28,172,100,172,152,164,182,148,206,130,224,111,238,188,188,237,237,18,44, +227,44,38,76,194,76,194,110,42,110,42,146,218,146,214,172,210,178,204,182, +185,184,122,8,122,116,118,152,108,178,92,198,68,218,21,240,230,234,200,222, +174,206,150,186,121,149,30,32,69,74,18,230,36,214,46,210,60,210,76,218, +98,228,116,230,144,234,239,228,10,114,54,114,55,210,202,66,202,38,102,38, +102,66,203,66,74,94,233,94,150,94,151,8,102,176,102,120,202,120,203,172, +150,132,146,162,142,178,130,192,114,202,95,208,164,172,213,207,102,24,70,34, +25,40,14,90,113,90,66,242,67,36,18,190,40,154,67,98,102,152,67,110, +168,14,140,48,117,68,116,126,152,106,188,78,212,42,147,42,144,64,171,90, +198,102,156,148,119,180,104,238,148,222,186,198,210,176,236,134,171,134,158,170, +185,199,88,12,60,68,17,124,58,246,59,70,132,22,169,74,212,44,192,124, +170,170,150,194,120,218,91,238,110,64,124,114,140,148,164,180,190,202,241,231, +16,236,28,206,36,160,36,28,82,28,82,212,78,226,68,232,53,220,36,86, +83,86,36,140,83,140,102,42,243,42,106,76,216,76,216,110,116,110,114,146, +228,146,226,168,220,178,205,184,164,8,164,102,154,158,138,196,118,220,97,240, +236,238,208,222,188,196,176,170,169,147,45,14,42,14,42,70,44,82,50,90, +92,90,104,84,113,62,110,26,43,58,48,102,27,146,110,122,39,122,14,162, +121,162,72,122,70,168,60,196,44,218,25,236,104,208,69,176,129,28,148,54, +185,90,128,28,212,28,171,76,122,100,224,100,211,130,140,136,134,188,122,216, +105,236,134,186,146,204,162,220,178,224,237,226,176,100,177,222,228,158,177,159, +40,24,85,58,22,86,69,118,30,232,73,150,224,26,166,40,120,42,120,148, +112,192,85,236,238,104,121,104,186,242,187,105,110,16,149,38,36,92,36,52, +224,52,225,92,26,228,241,228,74,228,74,98,184,98,185,228,74,140,185,140, +74,184,185,185,12,78,88,78,80,134,70,174,48,204,23,228,60,14,34,150, +95,206,94,42,239,42,102,76,212,76,212,108,110,108,108,142,228,142,222,168, +216,178,199,180,162,10,162,120,152,168,140,194,116,220,85,240,234,240,206,220, +182,194,170,174,159,143,22,70,239,70,178,70,194,28,83,28,88,10,72,48, +185,48,26,122,119,122,78,174,79,80,38,88,59,106,116,90,95,112,22,170, +79,130,106,154,79,134,176,76,134,106,183,106,206,88,146,132,215,128,200,112, +227,140,176,164,177,130,152,146,125,166,194,148,227,170,14,200,243,200,98,180, +94,208,86,220,76,228,49,240,168,242,169,181,16,72,93,72,58,244,59,14, +16,170,42,124,59,78,84,138,59,102,104,46,225,46,162,10,158,56,148,72, +132,88,109,98,210,96,159,56,92,114,243,114,168,194,168,150,118,150,118,194, +169,194,208,114,208,238,181,245,104,136,104,66,36,66,36,136,105,136,98,154, +119,202,18,202,109,180,70,12,71,188,148,22,183,62,130,54,138,96,154,136, +178,178,208,212,239,234,216,40,202,114,184,162,162,192,132,218,99,241,78,12, +46,88,19,124,60,246,61,58,92,50,233,50,160,8,154,60,142,78,126,92, +103,102,214,98,155,62,82,114,247,114,210,114,210,218,208,230,204,236,175,240, +167,196,166,196,166,152,112,152,112,196,167,197,30,36,194,36,194,116,41,116, +38,74,38,200,40,216,56,228,188,228,204,220,214,206,221,191,26,38,178,38, +54,170,38,188,34,202,34,212,42,220,62,230,180,230,202,226,216,214,220,200, +225,175,158,34,215,86,122,14,48,80,197,72,80,90,58,126,43,144,202,118, +65,118,16,164,239,164,128,118,122,168,104,196,84,214,58,228,25,240,232,236, +190,222,164,204,146,188,131,165,98,52,151,114,48,20,48,224,111,148,208,20, +204,92,192,136,178,168,148,200,122,222,93,238,228,230,179,167,16,52,239,52, +90,90,91,12,160,90,161,12,38,112,166,112,102,162,76,182,60,196,50,208, +48,216,52,222,62,228,80,230,186,230,202,226,214,218,220,204,223,189,18,68, +97,68,18,158,95,116,60,12,60,232,31,222,152,26,116,40,116,196,155,166, +174,246,174,34,224,34,224,192,216,200,204,202,195,191,194,104,194,30,66,30, +66,104,195,104,66,68,195,68,96,114,64,148,29,174,174,238,188,236,202,232, +210,224,214,216,220,140,73,140,44,220,72,202,98,174,119,140,92,242,118,224, +144,194,160,170,173,141,186,74,186,28,68,28,68,74,187,74,232,188,228,204, +224,214,212,224,188,228,76,228,60,224,48,208,48,104,200,104,200,154,49,154, +49,156,124,154,125,105,98,62,99,216,28,64,28,192,99,186,62,12,63,188, +160,12,140,64,115,100,234,56,145,56,128,110,196,110,176,134,148,166,138,186, +130,200,130,212,136,222,148,226,182,230,210,226,228,222,234,210,239,191,82,12, +48,90,17,134,60,246,61,64,98,40,212,40,176,90,150,130,124,174,112,192, +110,206,114,218,126,222,150,224,188,224,216,222,230,216,234,208,241,185,72,14, +36,56,19,70,78,72,38,126,19,146,56,246,57,104,98,108,110,100,118,92, +124,82,130,72,130,66,130,26,192,26,192,80,194,88,196,94,200,98,212,100, +241,98,100,130,204,130,190,160,172,184,154,202,130,218,112,224,87,232,122,130, +136,162,152,184,176,206,200,220,243,233,16,244,30,216,36,184,38,166,38,34, +82,34,82,240,63,244,38,94,83,94,38,154,83,154,148,10,177,34,104,44, +231,44,137,52,98,78,245,78,138,54,153,78,196,52,183,78,216,156,216,104, +124,104,124,156,217,156,124,130,217,130,122,186,103,232,168,170,189,200,210,178, +243,218,148,180,148,218,150,232,162,238,188,238,204,228,209,215,30,34,67,66, +22,238,34,224,46,214,60,214,68,218,84,226,104,232,132,236,237,234,14,120, +52,120,53,214,138,16,106,58,79,86,212,128,212,86,102,86,102,130,213,130, +152,84,184,46,115,46,154,86,148,136,138,158,118,182,91,204,188,150,211,174, +166,140,166,190,168,204,176,208,208,208,220,202,231,183,40,12,40,66,42,76, +48,80,82,80,92,76,101,60,98,28,41,44,44,94,21,140,100,116,35,116, +16,158,105,158,64,116,60,166,52,192,38,212,17,230,100,216,59,178,116,44, +214,44,214,116,117,116,108,80,245,80,114,156,227,156,104,192,241,192,166,248, +167,9,122,10,157,36,234,44,60,44,60,146,54,182,42,212,23,240,18,64, +47,102,14,148,61,124,92,134,108,124,114,112,118,94,118,76,186,76,186,110, +188,122,194,126,204,128,237,128,82,156,196,156,170,188,138,212,104,230,69,242, +232,238,190,226,158,210,130,190,109,157,106,14,137,50,20,68,237,68,70,114, +21,184,190,116,239,180,108,68,108,134,94,186,76,210,39,238,162,68,162,238, +133,247,112,14,145,36,26,46,233,46,108,46,80,80,27,118,134,56,158,88, +188,108,237,126,206,58,163,90,140,100,86,122,87,72,56,244,56,142,206,142, +206,238,183,242,114,156,71,186,142,158,189,182,158,220,158,188,102,188,102,220, +159,221,102,14,141,36,32,46,217,46,14,86,237,86,74,54,101,78,172,52, +147,86,196,164,196,110,60,110,60,166,197,166,60,138,197,138,56,184,23,236, +118,174,149,204,194,180,235,222,86,180,86,220,88,230,96,236,168,236,182,230, +184,222,187,209,56,14,83,38,20,50,119,50,12,96,127,96,38,64,59,86, +98,60,79,96,14,140,50,122,75,96,50,236,70,234,82,226,88,204,88,184, +84,160,76,142,59,114,14,180,46,160,73,136,16,218,56,188,83,160,110,128, +83,154,122,194,87,164,128,112,142,94,148,76,152,60,152,28,196,28,196,86, +202,96,208,100,233,100,126,132,210,132,194,172,162,208,113,240,238,236,198,214, +166,186,150,162,139,133,56,244,57,14,30,70,17,126,78,66,99,112,102,44, +208,44,160,110,134,152,108,198,104,208,106,218,116,224,132,228,206,228,224,222, +232,208,239,187,104,22,147,68,52,46,82,108,118,156,170,198,235,232,200,38, +160,118,110,176,68,208,25,237,66,18,101,56,26,72,225,72,176,12,139,72, +98,92,29,150,146,96,217,140,14,230,239,230,60,230,60,154,196,154,197,230, +102,230,103,154,148,230,149,155,36,30,77,62,16,94,55,120,28,234,69,156, +112,18,143,52,136,92,85,144,178,94,237,142,90,72,235,72,202,16,167,72, +74,230,243,230,104,230,104,152,214,152,215,230,142,230,143,152,176,230,177,153, +42,26,85,66,12,104,56,104,54,224,95,188,116,12,116,80,118,96,122,100, +134,104,202,104,218,100,228,88,235,72,224,28,117,56,120,242,120,134,212,134, +213,238,120,176,213,176,120,218,213,219,36,22,77,58,12,90,58,90,58,216, +99,168,132,16,167,68,110,56,122,116,142,158,174,196,206,218,235,234,204,44, +196,94,180,140,148,192,114,222,81,241,28,24,69,60,10,106,54,106,52,224, +87,186,136,12,169,42,88,90,88,54,226,54,227,88,76,230,245,230,118,230, +118,94,198,94,199,230,118,138,199,138,118,182,199,183,34,20,73,56,10,96, +56,96,54,220,85,194,88,24,202,24,178,56,146,86,116,104,81,118,236,108, +204,100,170,84,134,58,109,24,100,140,221,140,90,182,237,182,160,242,161,103, +232,80,224,100,216,108,198,110,74,110,60,108,56,100,56,26,198,26,198,66, +57,66,16,162,241,162,90,128,90,176,82,200,68,220,52,232,37,242,176,246, +177,127,28,26,112,26,113,76,44,38,73,52,28,74,113,58,134,26,216,26, +217,78,154,38,181,52,136,68,217,56,204,138,204,92,52,92,52,140,205,140, +52,114,205,114,128,140,129,92,34,168,221,168,16,196,239,196,88,196,89,146, +168,196,169,146,102,206,27,238,156,206,231,239,26,32,110,32,111,112,46,52, +81,70,28,110,111,80,136,30,214,30,215,120,152,52,187,72,146,104,213,82, +118,116,149,140,34,150,227,150,74,166,101,206,20,226,239,226,184,160,143,227, +96,60,26,164,91,152,70,16,18,98,71,96,20,216,89,194,98,26,206,26, +192,52,172,76,142,96,91,118,240,114,202,104,166,84,140,60,119,26,106,148, +227,148,96,188,243,188,166,244,167,109,16,50,243,50,94,78,95,12,168,76, +169,12,44,244,44,92,214,92,215,242,44,222,215,222,68,134,189,134,130,102, +122,152,108,176,71,202,192,198,121,155,16,40,241,40,94,66,95,10,164,66, +165,8,44,242,44,84,102,84,78,132,94,146,104,164,100,186,92,194,69,196, +102,240,126,212,136,184,136,84,216,84,216,232,187,242,136,124,217,124,136,168, +217,169,42,238,42,30,212,30,213,234,42,212,213,212,62,96,193,96,124,46, +120,108,106,140,69,182,182,180,144,136,121,111,120,16,80,26,38,30,38,164, +25,234,38,58,106,58,106,120,39,120,38,88,107,88,38,156,110,156,104,198, +98,208,92,216,63,220,124,104,142,86,148,66,150,54,150,24,204,24,204,78, +206,90,218,94,243,94,126,130,214,130,198,160,180,184,158,206,138,220,111,234, +238,232,212,220,188,204,166,178,152,148,145,131,110,14,143,38,34,46,221,46, +12,108,243,108,70,62,105,96,176,58,145,108,64,248,64,142,190,142,191,246, +64,184,191,184,64,224,191,225,42,242,42,28,104,28,68,94,82,110,94,126, +100,144,100,158,92,170,80,176,63,180,98,240,118,216,132,184,136,152,136,30, +220,30,220,234,187,242,136,88,221,88,136,146,221,147,14,80,86,76,82,130, +74,166,54,198,21,234,60,12,32,150,97,200,116,244,116,28,224,28,225,242, +116,214,225,214,130,98,209,98,168,50,168,112,164,140,154,166,141,186,206,176, +169,117,26,196,26,46,76,46,77,186,26,164,77,164,160,10,136,68,116,92, +97,110,238,108,204,82,180,54,159,16,150,96,179,130,106,148,208,148,153,243, +70,12,38,72,19,94,112,62,47,62,30,104,103,104,20,152,113,152,64,104, +64,236,109,204,176,206,130,236,130,32,212,32,212,126,131,126,130,80,213,80, +238,236,212,212,192,190,176,158,167,126,232,144,189,179,42,30,81,58,22,88, +63,116,32,226,75,146,218,22,142,34,99,34,98,58,125,94,146,52,169,86, +216,48,187,98,220,106,154,116,101,116,90,164,241,164,94,222,231,222,162,222, +163,115,108,12,145,36,34,88,34,48,222,48,223,86,56,78,205,78,198,186, +198,112,56,112,56,186,199,186,128,186,129,78,102,206,29,242,56,148,199,148, +158,204,231,239,60,16,36,78,17,104,84,98,98,64,43,64,58,104,58,212, +97,172,150,8,132,78,111,116,210,104,220,64,137,64,167,92,164,92,164,126, +156,166,140,196,120,218,93,238,240,234,206,208,184,180,165,135,16,92,245,92, +42,34,198,34,199,178,34,154,199,154,100,34,100,94,96,134,82,180,56,212, +23,239,30,32,130,32,130,90,48,90,42,146,132,146,130,198,126,210,118,220, +100,226,55,228,208,10,209,241,34,246,34,34,90,34,58,104,74,120,84,136, +90,154,86,176,76,186,55,190,146,14,116,60,95,84,110,148,214,148,214,82, +113,82,112,114,213,114,166,82,192,46,127,46,110,180,81,228,154,162,179,194, +206,176,241,218,136,174,136,220,136,236,142,238,178,238,190,232,198,222,199,209, +122,18,80,32,40,38,40,204,119,176,40,106,113,106,148,246,148,40,222,40, +222,200,191,209,16,46,239,46,88,78,89,10,164,76,165,8,14,158,243,158, +64,158,64,98,194,98,195,158,130,66,130,116,118,170,96,198,76,214,31,240, +234,234,206,224,178,206,158,188,135,159,20,72,85,72,56,244,57,12,18,166, +57,94,84,120,57,90,100,104,100,30,150,30,151,100,126,48,124,88,114,116, +99,136,134,106,159,124,178,104,178,30,226,30,227,100,204,48,202,82,194,110, +181,126,206,110,227,130,86,160,245,160,156,138,122,188,227,236,198,160,180,188, +154,214,120,228,93,239,46,100,46,26,110,26,111,98,80,48,78,88,66,114, +37,138,90,102,119,122,144,98,144,26,210,26,211,96,180,46,178,74,172,104, +157,126,188,104,227,138,16,162,241,162,120,134,76,188,223,234,168,162,160,178, +144,196,122,212,76,228,35,235,124,12,151,32,230,40,48,40,48,166,40,202, +23,236,98,50,70,84,59,96,84,138,85,68,136,48,99,94,120,130,121,66, +166,48,189,60,134,68,231,68,134,88,225,88,134,108,225,108,134,128,237,128, +174,178,188,178,198,172,200,150,92,150,92,196,228,196,226,226,220,232,203,238, +64,220,195,220,176,128,177,68,122,136,113,150,126,164,157,183,116,14,149,48, +232,58,48,58,48,172,36,210,19,240,76,126,119,194,122,94,157,166,56,226, +239,226,212,98,155,227,84,56,30,164,81,152,66,16,24,100,63,98,16,212, +87,198,104,104,104,26,152,26,153,104,128,48,126,94,120,114,97,138,154,130, +127,100,178,104,178,26,226,26,227,104,202,50,198,100,194,114,173,138,232,140, +199,102,86,166,247,166,158,138,122,190,231,236,202,166,190,186,164,212,126,230, +93,237,18,48,237,48,94,78,95,12,160,78,161,12,34,130,34,94,220,94, +221,126,58,130,195,130,50,176,205,176,22,232,235,232,124,232,125,130,160,190, +195,217,26,44,229,44,94,74,95,12,160,74,161,8,32,132,32,92,224,92, +225,130,196,178,196,134,62,134,62,178,197,178,178,190,231,238,32,230,211,220, +130,224,131,103,24,40,231,40,88,66,89,8,164,66,165,6,26,118,26,80, +228,80,229,118,180,146,180,110,74,110,74,146,181,146,58,248,58,180,198,180, +199,244,58,226,199,227,18,50,239,50,92,82,93,14,160,80,161,12,38,136, +38,98,220,98,221,134,80,136,63,184,186,130,169,176,130,114,122,166,108,192, +78,218,50,230,25,238,228,236,204,228,176,214,154,196,138,178,125,153,88,142, +88,66,26,66,26,142,89,142,84,168,105,216,14,218,97,198,58,206,59,14, +208,70,208,28,126,28,126,70,209,70,216,184,216,104,120,104,120,184,217,184, +120,144,217,144,164,70,164,218,168,228,176,236,186,238,210,238,224,234,232,226, +239,205,26,28,71,62,20,228,34,216,48,208,60,208,76,212,92,222,120,230, +148,232,235,228,12,110,54,110,55,208,148,24,104,44,104,176,151,150,168,210, +168,34,220,34,220,178,195,185,114,12,149,28,16,36,237,36,204,62,58,62, +59,36,190,110,190,84,60,84,60,110,191,110,14,238,26,224,34,204,36,194, +36,134,70,134,70,236,55,242,36,164,71,164,36,192,71,192,98,200,98,134, +144,134,145,198,120,154,120,184,114,206,106,222,91,236,128,206,143,220,144,242, +156,230,164,216,168,200,170,188,170,134,208,134,208,222,208,232,216,238,224,238, +232,232,241,212,178,172,193,197,34,34,184,34,172,76,214,76,210,126,206,136, +200,142,179,144,84,34,84,48,80,74,70,102,52,126,27,144,80,76,146,76, +134,104,114,128,98,140,81,148,160,146,97,100,12,228,243,228,54,228,54,168, +202,168,203,228,104,228,105,168,152,228,153,169,130,76,130,22,42,22,42,76, +131,76,42,50,131,50,76,84,95,100,16,108,159,108,128,168,128,136,46,136, +46,168,129,168,60,186,25,224,108,186,139,212,88,168,88,236,61,242,216,14, +182,54,153,80,220,84,186,120,157,146,230,148,192,196,141,237,42,12,42,62, +46,74,52,80,94,80,104,76,110,70,117,58,108,30,43,40,110,104,62,112, +31,114,18,148,121,148,70,244,71,112,18,218,71,156,116,200,71,162,122,28, +243,28,138,188,138,80,222,80,223,186,164,80,179,28,178,110,178,142,174,170, +166,198,146,218,119,238,186,194,241,239,12,48,97,48,14,138,32,118,44,100, +52,76,59,48,40,218,40,110,82,110,83,210,40,190,83,190,102,30,241,30, +220,146,220,68,124,68,124,146,221,146,124,108,221,108,172,30,172,152,162,186, +144,212,114,230,87,240,120,168,154,206,188,224,239,235,30,216,30,42,76,42, +77,206,30,112,77,112,30,184,77,184,90,142,239,142,162,12,162,106,152,158, +130,196,104,220,79,236,230,238,208,218,186,190,174,166,163,142,114,142,114,68, +210,68,211,143,32,202,32,50,70,50,71,192,32,174,71,174,148,54,98,160, +153,152,78,216,157,196,128,10,90,96,129,94,194,10,180,58,155,108,180,238, +204,234,218,228,224,222,230,70,177,70,172,116,201,171,16,74,97,74,18,158, +95,122,60,12,60,238,31,226,88,236,104,214,114,186,116,160,116,32,222,32, +222,236,199,238,166,232,167,32,116,96,223,96,116,154,223,155,74,18,42,88, +15,122,54,244,55,64,82,236,100,206,108,172,110,156,110,34,222,34,222,234, +193,240,164,226,165,34,110,98,223,98,110,154,223,155,18,242,28,210,32,182, +34,156,34,32,76,32,76,238,55,242,34,90,77,90,34,146,77,146,146,10, +175,34,90,46,245,46,125,58,140,142,130,186,116,216,97,240,140,92,94,166, +135,160,124,58,92,120,125,114,176,58,154,116,143,132,164,248,165,90,196,64, +213,88,172,98,239,98,172,138,237,138,172,178,235,178,172,220,245,220,200,220, +201,99,132,12,165,34,22,64,43,102,244,44,64,44,66,136,62,180,33,234, +16,152,67,126,84,234,100,202,104,170,106,152,106,84,222,84,222,232,197,240, +164,228,165,84,106,130,223,130,104,174,223,175,120,14,155,32,230,44,46,44, +46,168,38,204,19,242,60,98,243,98,74,72,212,72,212,122,75,122,84,246, +84,148,216,148,216,240,191,246,84,174,217,174,84,202,217,202,146,242,147,53, +112,12,145,38,14,50,237,50,96,142,86,190,66,216,23,238,100,88,36,172, +91,166,72,64,30,122,75,120,148,64,120,114,103,132,132,246,133,96,172,68, +193,90,140,100,233,100,140,138,225,138,140,176,225,176,140,220,237,220,180,220, +181,101,92,84,92,26,34,26,34,84,93,84,20,222,105,184,32,118,33,214, +66,84,67,200,104,132,67,132,117,24,144,48,185,76,116,24,206,24,171,66, +126,242,126,86,226,86,226,232,203,240,126,132,227,132,126,176,227,176,174,224, +175,87,96,138,96,66,30,66,30,138,97,138,86,168,111,210,65,8,14,214, +97,190,64,198,65,8,150,56,191,84,114,28,220,28,179,74,130,242,130,90, +228,90,228,238,203,244,176,228,177,90,130,134,229,134,130,178,229,179,28,206, +28,66,76,66,77,196,28,176,77,176,132,16,187,46,104,66,166,66,166,238, +137,244,92,118,140,118,134,148,120,178,102,198,85,216,238,210,202,170,184,140, +167,96,226,90,183,133,30,26,77,58,14,86,57,118,24,234,65,154,74,116, +130,116,124,148,110,174,94,198,69,218,122,14,183,48,94,68,158,68,158,238, +131,244,234,206,200,168,178,132,159,90,228,92,179,129,34,20,77,52,16,84, +63,112,22,228,69,146,126,48,173,82,92,24,210,24,157,70,104,240,104,90, +224,90,224,236,199,242,162,230,163,90,104,136,225,136,104,180,225,181,90,14, +157,46,20,124,90,122,72,168,50,198,21,222,50,76,130,76,130,242,101,248, +236,214,188,180,160,146,142,114,131,84,218,88,155,135,98,44,139,66,30,30, +186,30,131,62,52,162,52,70,206,70,206,160,181,166,128,156,129,70,52,102, +207,102,52,132,207,132,56,178,25,226,116,166,149,196,196,176,235,214,88,170, +88,212,94,232,162,232,180,222,189,201,104,48,159,68,36,32,192,32,149,62, +60,160,60,74,212,74,213,158,60,102,213,102,60,130,213,130,134,152,135,74, +26,180,218,176,214,216,206,226,188,232,163,232,126,156,114,194,88,218,60,232, +31,241,26,238,48,208,56,172,58,144,58,26,218,26,218,230,185,238,138,220, +139,26,58,90,219,90,58,146,219,147,35,68,220,68,221,240,34,68,34,224, +221,218,128,220,129,12,92,140,113,188,106,76,52,180,105,168,88,32,50,110, +91,104,182,140,203,188,194,78,144,176,193,168,180,32,144,110,179,109,72,14, +38,94,15,128,52,246,53,62,70,86,235,86,140,8,140,104,132,152,118,186, +96,216,79,234,164,112,164,206,168,224,180,230,220,230,236,222,241,198,174,26, +211,61,70,16,42,74,19,104,56,160,57,44,92,46,93,134,156,12,130,70, +109,96,240,56,139,56,142,74,154,100,178,128,212,148,239,156,198,56,196,78, +180,110,162,130,134,146,95,162,60,180,25,228,122,172,155,202,198,180,239,220, +92,182,92,220,94,230,98,236,164,236,182,230,187,207,58,246,59,12,28,66, +17,130,76,68,95,112,106,90,233,90,156,10,156,94,150,132,140,168,120,202, +85,236,174,114,174,214,178,230,186,234,218,234,232,224,239,200,186,30,217,63, +156,22,201,54,26,84,229,84,120,6,120,94,114,134,104,168,82,200,58,218, +27,238,146,96,146,204,152,222,166,230,208,230,226,220,237,191,42,244,42,76, +214,76,215,240,42,146,215,146,42,218,215,218,128,218,129,13,32,228,32,60, +120,60,121,218,32,126,121,126,32,196,121,196,76,196,77,8,158,246,158,34, +224,34,188,104,206,118,224,138,230,158,226,182,210,196,187,199,70,16,38,70, +19,90,112,64,45,64,30,102,101,102,20,152,111,152,64,102,64,232,105,200, +130,246,130,78,230,78,231,240,130,142,231,142,130,216,231,216,180,216,181,11, +28,22,54,46,70,70,82,104,84,142,84,186,78,212,66,230,45,234,88,18, +50,66,21,90,20,166,60,130,81,102,102,84,241,84,196,26,225,56,160,8, +160,98,150,156,132,196,93,240,180,114,180,220,184,232,192,238,220,238,232,232, +238,220,243,205,34,32,77,64,16,94,61,124,34,232,73,140,104,242,104,76, +224,76,225,240,104,142,225,142,104,214,225,214,162,214,163,13,28,28,63,56, +18,84,53,114,24,230,57,142,92,22,119,54,70,66,149,66,98,66,96,118, +90,168,74,210,57,236,98,116,136,116,132,208,124,224,114,226,99,226,182,16, +162,72,145,100,242,60,167,60,163,100,162,100,220,100,196,140,196,224,192,236, +167,242,150,158,245,159,20,40,237,40,54,244,54,86,204,86,205,240,54,180, +205,180,54,222,205,222,110,40,110,94,102,122,92,138,77,154,150,40,150,130, +156,142,164,142,205,143,18,48,239,48,118,8,100,64,80,96,56,122,25,144, +84,242,84,92,190,92,190,238,161,244,84,134,191,134,84,176,191,177,20,58, +235,58,116,8,102,84,84,130,58,164,23,200,48,238,94,218,132,194,164,154, +188,106,98,106,112,140,128,168,158,196,198,218,237,233,18,68,241,68,128,12, +118,58,100,98,74,140,23,186,80,240,80,130,196,130,197,238,80,212,197,213, +88,12,52,82,21,124,62,240,63,62,96,66,245,66,166,12,142,86,118,134, +85,178,134,236,134,130,220,130,221,234,134,212,221,213,110,26,58,36,25,38, +70,246,71,34,30,58,49,88,106,54,89,88,16,108,113,108,18,196,44,162, +69,108,106,162,71,118,126,244,126,70,224,70,225,238,126,214,225,214,176,214, +177,12,126,138,225,139,36,22,75,58,10,96,52,96,50,218,91,186,218,18, +144,30,107,32,88,70,233,70,158,120,159,28,88,128,140,84,155,70,236,122, +200,102,169,70,106,134,194,134,184,170,214,170,208,216,204,224,196,228,167,230, +140,134,140,148,132,186,118,216,91,241,36,42,192,42,166,102,134,150,84,200, +25,238,232,232,196,216,156,190,120,154,88,104,61,43,98,144,119,206,114,62, +32,198,113,186,76,18,30,108,87,104,130,80,230,76,220,208,214,224,200,232, +171,234,174,12,172,92,166,140,158,174,140,206,107,241,30,26,75,64,20,230, +34,220,52,210,64,210,78,216,104,226,132,232,243,230,10,106,58,106,59,210, +100,30,223,30,82,112,243,112,164,30,164,188,158,198,146,204,125,205,30,30, +61,60,18,88,51,118,22,232,57,144,92,22,121,58,62,72,151,72,94,72, +94,124,90,170,76,204,57,234,98,228,112,226,122,220,132,206,136,120,95,120, +190,18,176,60,162,86,145,108,240,108,214,84,194,50,187,30,170,120,213,156, +162,180,227,229,38,32,221,32,16,118,241,118,90,224,122,238,130,234,132,222, +133,33,46,34,211,34,26,86,233,86,102,132,114,132,126,128,132,120,133,34, +14,226,243,226,56,226,56,154,200,154,201,226,104,226,105,154,152,226,153,155, +14,76,85,76,52,246,53,14,14,164,53,104,82,138,53,104,160,8,128,60, +102,84,85,98,238,94,208,76,188,60,155,16,122,86,199,86,104,246,104,118, +152,118,152,238,135,242,104,154,153,154,104,190,153,190,184,206,185,122,216,112, +216,242,193,247,220,82,232,60,48,60,48,164,38,206,25,240,130,8,131,60, +220,34,131,34,70,88,205,80,130,68,130,102,134,108,150,110,192,110,206,104, +217,92,204,154,204,128,90,128,90,154,205,154,70,176,227,176,60,200,239,200, +144,176,140,202,124,218,102,230,76,238,57,242,238,238,208,236,182,230,158,216, +143,201,200,86,200,24,60,24,60,86,201,86,60,56,201,56,44,168,44,114, +218,114,218,158,212,166,197,166,166,124,187,158,70,148,179,144,128,146,129,24, +56,180,25,228,122,164,153,198,206,184,237,228,92,170,92,214,92,224,98,228, +108,232,164,232,180,228,182,220,187,201,12,174,245,174,86,24,48,38,55,174, +84,82,51,82,82,122,53,122,172,38,208,38,203,174,176,82,205,82,174,124, +205,124,90,44,167,44,134,12,98,90,165,90,96,124,165,124,132,158,133,62, +104,192,29,238,156,190,227,241,130,12,94,60,62,88,21,112,124,20,150,50, +182,76,239,102,66,104,191,104,40,156,217,156,86,180,31,234,166,184,231,222, +130,104,130,238,101,247,130,10,82,68,19,110,122,18,174,68,239,100,80,82, +179,82,52,246,52,114,122,114,122,238,99,244,52,148,123,148,52,182,123,182, +166,120,167,204,208,110,208,240,177,249,18,236,30,224,44,210,58,210,72,218, +104,228,132,232,241,230,10,116,50,116,51,210,18,30,63,66,152,10,118,54, +75,84,146,18,180,52,235,78,112,72,189,72,90,208,90,102,146,102,146,202, +127,208,90,130,147,130,90,158,147,158,178,102,179,178,210,92,210,204,185,211, +106,12,66,64,29,96,18,228,239,228,200,184,200,100,60,100,60,186,201,186, +60,140,201,140,128,186,129,100,78,48,168,48,133,101,52,244,53,10,28,60, +17,120,66,54,83,78,156,10,118,68,79,106,152,18,184,60,241,92,118,84, +195,84,96,244,96,114,144,114,144,238,123,242,178,204,179,116,96,148,145,148, +96,186,145,186,210,104,210,240,185,245,34,22,77,54,16,84,59,112,24,230, +65,152,154,6,120,60,75,96,150,14,178,54,231,88,114,86,197,86,92,246, +92,120,144,120,144,242,127,246,92,156,145,156,92,190,145,190,178,206,179,124, +216,110,216,240,189,247,36,20,77,52,18,88,57,116,26,238,71,150,140,12, +108,62,81,94,218,180,218,90,106,90,106,180,219,180,106,134,219,134,158,180, +159,90,164,90,188,46,119,46,72,226,243,227,36,242,36,32,86,32,60,102, +72,122,82,148,82,170,59,188,212,108,212,32,118,32,118,108,213,108,118,68, +213,68,186,162,205,202,126,196,197,186,162,190,163,32,108,240,108,140,224,140, +224,236,201,245,92,48,149,96,52,24,190,24,131,78,18,106,226,106,209,146, +132,106,132,236,101,241,12,80,90,78,78,156,56,204,25,236,60,12,34,154, +103,202,212,74,212,30,122,30,122,76,213,76,112,110,223,110,102,158,235,158, +164,110,160,172,146,198,124,220,95,240,238,236,206,216,182,190,163,159,16,28, +241,28,46,232,46,76,212,76,212,226,181,232,128,226,129,28,74,100,107,138, +68,150,103,188,152,146,187,186,152,98,189,137,83,12,80,12,72,114,210,114, +202,196,194,218,182,226,160,232,135,234,76,54,233,54,22,170,179,171,104,60, +105,220,34,62,34,198,105,190,68,12,69,194,155,14,152,14,142,124,224,124, +216,212,208,224,198,228,186,232,165,234,148,64,241,64,122,172,201,173,210,18, +138,30,39,36,194,114,194,70,58,70,58,112,195,112,40,246,40,148,216,148, +216,236,187,244,160,168,189,210,66,202,177,190,124,196,125,33,102,16,145,46, +32,92,32,56,224,56,225,92,56,100,203,100,16,154,241,154,134,100,134,242, +103,249,34,26,79,62,10,100,60,100,58,226,97,188,96,34,231,34,88,130, +245,130,104,74,206,74,205,130,134,130,147,34,118,244,118,164,216,164,217,242, +118,222,217,223,28,30,116,30,116,206,112,222,88,236,55,224,36,72,83,114, +32,174,115,128,136,28,218,28,218,206,198,234,157,222,144,70,187,112,136,172, +219,131,28,36,223,36,46,116,207,116,16,216,241,216,158,144,205,184,124,36, +125,217,14,90,89,90,12,198,91,178,52,186,53,14,192,16,221,46,84,66, +239,66,144,160,144,108,100,108,100,158,145,158,72,210,157,196,220,96,202,148, +180,196,158,220,139,240,166,10,168,86,180,156,198,208,222,232,230,232,241,207, +16,48,239,48,88,82,89,16,164,82,165,14,46,100,205,100,16,158,239,158, +130,100,130,240,110,246,99,233,14,50,151,50,80,8,62,68,23,124,54,238, +54,90,124,90,124,230,103,236,54,130,125,130,54,170,125,170,168,248,168,32, +230,32,200,106,220,124,236,150,238,178,226,190,199,199,30,190,30,36,82,36, +83,182,30,160,83,160,108,32,231,32,102,120,245,120,172,32,172,236,144,244, +131,225,26,26,69,62,16,230,32,216,48,210,62,210,90,220,122,230,241,228, +12,108,54,108,55,210,208,94,208,28,104,28,104,94,209,94,96,204,96,124, +216,124,216,202,195,208,180,142,199,172,116,168,189,160,154,162,155,28,104,60, +209,61,28,208,28,44,68,44,69,198,28,174,69,174,156,8,124,56,83,94, +152,14,172,42,208,72,239,90,112,86,205,86,98,246,98,120,144,120,144,242, +127,244,98,156,145,156,98,190,145,190,180,210,181,122,212,110,212,240,193,245, +86,64,87,216,26,62,26,194,85,188,54,190,55,14,148,22,109,66,184,22, +223,60,170,64,146,104,107,144,236,138,216,126,192,106,167,74,126,242,126,148, +204,148,205,240,126,216,205,217,72,24,42,64,23,82,76,80,50,118,19,150, +54,246,55,114,122,18,89,70,162,50,103,50,80,104,171,104,76,222,169,190, +94,214,95,138,130,202,131,50,130,148,167,148,184,244,184,40,230,40,230,208, +207,199,128,14,92,46,50,72,19,86,120,22,146,44,184,66,237,82,78,68, +167,68,54,178,54,96,120,96,120,174,101,178,54,122,121,122,54,148,121,148, +160,96,161,156,200,86,200,170,179,176,58,194,25,236,118,182,147,210,196,190, +229,226,86,188,86,228,86,234,96,238,156,238,174,234,180,224,185,211,62,24, +21,78,88,24,127,68,78,68,54,108,17,142,130,130,69,82,48,238,48,146, +106,146,107,228,48,210,107,210,172,10,154,72,135,106,212,108,224,70,157,70, +176,104,176,146,162,190,148,214,119,242,176,146,190,180,208,206,232,228,241,233, +28,26,48,50,64,78,72,124,76,164,74,200,66,224,54,228,37,230,78,24, +44,70,19,98,18,166,69,106,110,22,129,64,86,96,120,96,116,206,153,162, +210,30,231,60,142,84,241,84,186,10,186,96,180,148,166,190,127,238,238,232, +214,188,192,122,187,99,110,8,147,32,18,44,241,44,117,54,166,60,211,102, +116,52,60,98,199,90,66,242,66,122,196,122,196,236,171,242,66,154,197,154, +66,188,197,189,54,20,95,54,112,14,141,50,20,70,241,70,202,12,161,70, +18,134,50,120,80,98,105,70,240,128,208,114,176,92,159,70,118,88,143,112, +66,120,199,120,70,144,191,144,66,168,197,168,72,246,72,194,188,194,189,246, +72,226,189,227,32,22,77,54,16,80,61,112,20,236,65,154,136,22,97,72, +182,22,225,62,160,60,130,112,83,148,240,140,202,122,155,72,110,244,110,152, +202,152,203,240,110,220,203,221,112,10,149,32,32,82,32,42,224,42,225,80, +186,138,186,74,68,74,68,138,187,138,42,248,42,168,214,168,214,242,183,246, +162,182,183,216,74,210,173,200,130,204,131,74,68,106,187,107,38,12,75,44, +14,70,76,70,62,100,17,146,54,240,55,108,94,168,55,126,98,102,69,140, +148,18,109,66,182,20,227,66,172,62,136,110,99,142,242,138,206,120,163,76, +128,240,128,150,206,150,207,238,128,214,207,215,36,62,75,96,18,30,90,30, +57,80,12,110,108,110,93,142,62,110,62,238,33,244,114,26,243,26,132,190, +132,74,218,74,219,188,176,26,163,74,174,104,174,156,168,188,154,212,134,226, +107,240,186,194,239,237,32,62,65,98,18,32,86,32,55,84,12,112,92,112, +81,140,56,112,56,230,33,238,150,12,124,46,95,76,222,112,222,74,118,74, +118,112,223,112,168,74,192,38,131,38,170,74,158,112,148,126,120,146,95,160, +138,238,158,236,172,226,176,202,172,176,160,154,143,132,94,194,132,172,155,148, +92,226,136,202,171,174,222,132,169,170,236,218,218,202,204,184,191,155,42,50, +34,134,104,134,94,234,67,240,16,192,81,172,14,28,94,28,83,134,114,32, +214,32,212,74,202,116,182,162,156,196,117,234,238,232,202,200,178,166,154,116, +144,72,139,33,78,18,54,52,27,78,26,122,56,114,82,96,106,68,118,44, +61,44,66,68,93,84,174,68,188,68,200,66,206,56,208,36,148,36,148,78, +148,90,152,96,162,98,204,98,216,96,226,86,235,68,158,160,168,160,180,154, +186,142,188,132,188,124,72,124,72,180,218,180,216,200,212,220,204,232,194,236, +173,238,104,142,141,160,122,94,109,124,32,214,185,215,36,26,75,62,20,88, +59,118,26,232,69,144,99,22,95,20,96,22,96,154,90,190,78,216,65,234, +114,52,141,92,196,48,173,94,112,114,205,114,158,236,159,18,110,198,136,162, +159,114,202,192,159,128,222,240,223,23,30,76,30,34,220,34,221,74,118,46, +80,80,37,106,86,76,166,76,143,108,60,110,200,110,200,152,60,152,61,110, +128,110,120,164,96,196,62,220,27,236,170,166,201,202,142,152,142,214,144,222, +154,226,216,226,228,216,237,203,44,36,211,36,18,100,237,100,100,100,96,152, +78,196,54,216,23,234,154,100,154,206,156,216,164,224,188,226,218,222,232,204, +239,189,14,86,91,86,16,200,97,168,52,186,53,12,96,34,233,34,216,174, +216,80,122,80,122,174,217,174,122,126,217,126,90,224,247,225,49,42,50,42, +207,42,20,80,239,80,128,80,129,8,194,150,194,110,66,110,66,152,195,152, +108,152,86,176,54,200,21,216,86,176,86,238,133,208,134,164,150,186,170,202, +194,218,235,232,214,162,173,203,238,28,54,28,54,142,44,186,23,232,210,148, +210,72,94,72,94,148,211,148,94,110,211,110,148,36,133,72,112,172,69,222, +186,176,237,220,152,148,152,238,123,245,12,64,89,64,14,152,81,112,54,10, +54,230,23,220,216,14,152,28,95,34,104,48,125,76,144,44,163,72,98,90, +225,90,206,40,177,90,90,122,233,122,138,90,128,140,114,174,98,198,77,218, +124,152,200,152,186,180,156,210,132,224,109,236,134,170,164,200,194,216,237,231, +16,56,101,56,66,12,26,118,99,118,20,182,101,164,66,84,67,244,112,40, +229,40,98,78,241,78,168,78,169,8,212,142,212,104,124,104,124,142,213,142, +158,142,136,174,99,204,142,164,142,232,181,204,174,156,186,182,212,210,241,226, +222,156,195,191,40,240,40,30,218,30,219,236,40,218,217,218,76,68,183,68, +62,106,197,106,112,106,110,134,102,158,86,176,65,188,146,106,146,166,152,182, +162,186,180,186,190,180,197,155,194,76,194,28,70,28,70,76,195,76,58,194, +58,112,204,112,205,192,132,132,120,178,106,200,90,216,58,228,33,236,144,188, +231,233,36,244,36,32,216,32,217,242,36,218,217,218,170,90,84,90,84,58, +170,58,171,90,80,174,80,114,176,114,177,172,128,132,122,164,110,180,96,190, +78,198,63,200,140,168,170,186,193,203,22,30,50,52,64,74,70,104,72,146, +72,200,60,226,44,230,33,230,84,24,23,94,16,168,71,110,100,42,227,42, +163,10,88,78,241,78,162,78,163,10,210,148,210,106,116,106,116,148,211,148, +90,206,114,192,136,172,153,148,178,204,136,234,137,174,168,148,186,188,212,214, +241,230,226,164,189,191,32,24,79,54,18,88,61,118,18,236,61,148,244,32, +98,32,98,138,86,200,63,238,218,152,218,76,130,76,130,152,219,152,130,114, +219,114,174,152,174,240,147,244,140,176,105,228,200,180,241,224,178,40,157,77, +90,58,20,162,87,148,62,14,20,90,69,88,18,218,85,194,146,8,122,68, +199,68,136,36,210,36,191,98,96,98,239,98,100,146,167,98,140,118,152,130, +168,152,176,184,174,218,162,236,139,238,96,182,132,162,159,138,88,222,136,194, +171,166,220,122,171,156,236,220,206,184,191,145,26,22,69,58,20,228,34,216, +50,206,62,206,88,218,116,228,178,230,243,226,12,104,56,104,57,206,100,32, +213,32,80,94,229,94,84,200,112,178,126,148,130,124,131,94,174,94,174,180, +178,190,186,194,214,194,222,186,231,173,14,48,241,48,92,80,93,14,162,80, +163,14,70,80,50,132,23,168,26,240,58,224,86,198,104,166,118,110,61,110, +62,152,97,178,232,200,226,222,214,230,158,230,148,222,148,102,212,102,212,138, +210,166,202,176,196,180,177,183,238,34,54,34,54,150,23,232,212,114,212,66, +92,66,92,114,213,114,140,42,131,66,92,90,213,90,116,132,71,166,178,134, +231,168,152,114,152,160,125,164,88,188,65,234,144,178,167,208,202,184,239,228, +118,190,118,220,120,232,126,236,178,236,188,230,197,211,72,14,50,68,27,100, +24,158,66,140,94,112,110,78,116,44,61,44,64,80,95,108,174,102,194,100, +206,92,210,76,212,40,146,40,146,116,150,134,156,142,166,144,210,144,224,138, +233,118,58,176,33,228,118,152,149,182,200,172,233,216,94,166,94,218,100,230, +114,232,164,232,178,226,189,207,146,12,177,36,30,244,30,32,80,32,54,108, +68,126,80,146,82,170,72,184,53,186,100,94,100,48,222,48,223,94,122,90, +203,90,92,132,231,132,142,132,142,166,136,186,124,212,106,228,83,240,178,132, +178,216,184,230,192,234,218,234,230,224,239,201,46,222,46,50,206,50,207,222, +162,124,47,124,46,200,207,201,76,12,22,96,89,92,112,58,38,162,113,148, +22,218,117,194,162,10,138,78,117,114,150,118,191,170,174,232,206,230,222,216, +224,194,224,64,145,65,26,58,115,58,16,102,117,102,76,102,77,12,48,136, +34,204,23,232,42,170,60,198,80,212,104,220,144,226,239,224,78,116,79,210, +78,154,115,154,160,146,132,168,132,62,233,62,174,10,174,70,178,112,186,146, +198,172,212,188,220,188,231,164,152,196,188,148,219,90,196,22,223,45,90,92, +90,30,30,30,30,92,91,92,14,226,107,182,64,200,65,92,28,218,29,122, +104,144,65,144,212,18,160,32,111,34,104,112,233,112,162,32,162,122,150,156, +136,188,116,212,85,232,234,234,204,206,182,172,163,127,74,16,44,70,21,96, +118,60,51,60,34,104,111,104,20,150,119,150,110,190,68,224,69,104,108,238, +128,210,138,178,142,152,142,34,222,34,222,234,193,240,142,90,223,90,142,144, +223,145,14,142,241,142,204,20,132,32,66,36,67,142,220,80,67,80,156,142, +157,80,210,174,211,242,54,168,54,224,209,220,132,222,133,155,206,142,206,42, +54,42,54,142,207,142,126,12,109,42,72,88,187,88,130,128,131,54,84,56, +115,72,178,54,153,74,78,126,125,88,180,124,131,88,14,166,243,166,134,240, +166,240,186,232,194,218,196,196,78,196,87,167,24,242,52,206,62,178,68,148, +70,130,70,32,194,32,194,232,155,240,70,92,195,92,68,150,195,151,52,244, +53,8,30,66,15,126,74,62,93,112,114,12,147,54,212,138,212,72,120,72, +120,138,213,138,206,10,179,72,82,240,116,222,134,198,140,174,145,138,184,138, +184,212,188,228,198,232,224,232,232,226,241,207,50,12,81,46,36,244,37,54, +118,34,220,34,220,218,214,240,189,246,92,56,115,84,172,144,172,96,82,96, +82,144,173,144,164,56,139,96,112,144,110,172,98,194,82,208,65,216,144,144, +144,198,146,208,154,212,158,212,180,212,186,206,190,200,195,189,70,240,71,8, +20,48,107,48,26,86,101,86,14,124,107,124,18,204,71,138,116,174,71,138, +132,38,229,38,130,110,239,110,179,122,196,164,237,230,178,124,130,222,223,209, +54,36,207,36,18,108,239,108,160,160,217,228,130,116,54,220,197,207,122,72, +122,28,46,28,46,72,123,72,40,188,40,102,130,102,131,182,84,124,80,166, +70,192,50,212,23,230,92,188,141,222,166,244,166,32,220,32,188,106,206,120, +222,140,230,160,230,180,220,194,195,201,90,14,54,76,27,108,68,54,216,54, +216,104,212,206,206,220,190,230,170,232,145,222,82,98,147,128,52,194,179,161, +34,240,34,30,90,30,60,98,78,118,92,142,90,174,78,186,59,184,210,68, +210,30,124,30,124,68,211,68,120,188,120,100,216,100,217,186,166,124,166,156, +160,180,144,204,122,222,97,236,182,190,237,231,126,12,48,112,197,102,152,48, +215,124,104,108,104,146,94,182,68,216,23,236,154,104,154,208,158,224,172,230, +214,230,228,220,237,191,36,28,75,70,18,228,34,216,50,206,62,206,78,214, +104,224,146,230,239,226,14,114,56,114,57,206,98,40,221,40,80,98,237,98, +147,108,180,136,217,200,144,108,92,190,203,177,12,38,241,38,94,64,95,8, +160,66,161,8,94,102,28,186,91,176,68,68,24,130,71,130,22,232,89,210, +208,136,208,80,126,80,126,138,209,138,126,108,209,108,86,230,243,230,112,230, +112,164,220,164,221,230,148,230,149,164,186,230,187,165,12,30,123,30,30,244, +30,78,112,78,113,240,30,214,113,214,30,176,113,176,58,30,58,90,54,118, +45,148,82,30,82,122,88,132,94,136,113,138,136,30,231,30,128,106,243,106, +194,160,239,232,178,114,136,220,223,209,207,74,204,74,204,24,58,24,58,76, +205,76,34,134,34,100,224,100,225,132,54,132,207,132,122,110,58,168,209,168, +18,198,241,198,134,240,135,148,58,50,205,51,60,18,85,44,22,54,123,54, +42,70,61,96,14,110,131,110,102,68,81,110,40,242,40,140,106,140,107,236, +40,180,107,180,40,218,107,218,162,14,138,70,125,90,146,102,181,128,128,182, +205,150,142,62,224,62,224,206,218,226,206,234,177,235,34,30,178,30,166,72, +216,72,212,112,206,130,196,132,187,134,100,30,100,48,92,70,78,94,54,114, +29,130,76,116,166,116,126,152,126,212,124,224,120,232,106,236,91,236,14,172, +239,173,228,30,38,30,38,224,237,224,140,208,141,44,84,174,84,88,204,88, +204,154,198,162,194,168,175,175,18,40,101,40,20,142,32,120,42,98,52,70, +57,40,44,212,44,104,86,104,87,202,44,182,85,182,242,26,116,26,116,226, +247,226,186,208,187,42,148,176,148,80,220,80,220,172,205,177,34,52,176,48, +174,106,178,114,188,116,214,116,224,112,231,94,110,10,104,60,92,92,68,114, +35,130,16,152,237,152,76,180,29,232,168,180,223,222,126,112,126,236,99,243, +28,50,129,50,12,88,241,88,78,10,79,88,182,28,217,64,156,12,156,102, +160,138,172,174,190,208,210,228,220,236,228,236,234,230,241,206,212,118,192,164, +166,198,142,216,121,232,18,136,139,136,78,242,79,104,20,212,54,174,79,138, +122,190,79,155,28,58,133,58,14,104,239,104,80,104,81,14,182,34,219,70, +152,12,154,112,160,148,176,190,196,222,212,238,220,238,228,232,235,208,210,126, +182,184,160,206,131,234,46,236,46,148,112,148,113,230,46,212,113,213,110,16, +143,40,36,96,36,56,218,56,219,92,78,106,57,162,202,104,167,152,128,72, +122,138,112,172,88,204,62,222,29,238,232,236,192,216,162,192,142,170,123,137, +112,12,143,36,36,82,36,46,222,46,223,82,108,62,141,84,50,92,207,92, +16,146,239,146,30,194,221,194,128,248,129,146,74,110,107,146,176,106,151,147, +34,44,143,44,12,78,239,78,94,8,95,78,190,24,221,50,165,8,162,8, +162,86,168,136,178,174,196,208,210,228,218,234,222,232,237,208,212,102,198,144, +174,188,152,210,131,228,28,116,143,116,80,86,42,160,135,160,24,208,143,190, +90,244,91,133,24,28,241,28,14,158,247,158,62,240,62,70,202,70,202,232, +175,240,62,114,203,114,130,28,131,159,24,54,237,54,130,14,106,70,82,106, +52,136,19,158,66,246,67,106,94,138,223,138,82,220,237,220,156,220,157,81, +36,210,36,60,84,60,85,206,36,180,85,180,122,246,122,62,222,62,223,242, +168,12,153,62,122,114,223,114,122,166,223,166,122,218,223,219,16,76,79,76, +14,152,83,108,54,12,54,238,23,226,102,22,83,60,146,46,91,46,92,74, +143,74,122,74,123,12,84,134,98,114,108,92,111,74,128,74,128,118,155,100, +176,22,157,62,168,74,241,74,234,46,165,46,196,74,197,12,154,130,170,114, +180,96,185,74,206,74,206,108,210,118,218,124,226,122,238,118,245,102,106,208, +106,144,210,144,211,204,158,158,152,194,138,216,116,230,87,240,166,198,233,239, +14,46,127,46,68,12,34,94,125,94,22,138,121,120,80,154,81,62,218,20, +178,30,146,36,146,96,140,122,123,152,234,76,147,76,194,150,195,76,62,250, +62,168,198,168,199,246,62,200,199,200,62,230,199,231,52,14,31,60,118,42, +41,42,152,16,129,62,230,42,143,42,16,76,111,76,147,76,146,76,243,76, +78,76,79,8,178,76,179,10,18,134,38,122,54,104,62,92,67,76,124,96, +90,118,91,76,122,126,148,112,162,94,167,76,186,76,186,112,190,118,200,122, +220,122,228,118,236,110,241,100,64,210,64,140,196,140,197,204,128,158,124,182, +114,202,98,218,70,230,37,240,138,200,225,241,34,180,34,32,96,32,97,172, +64,62,64,168,54,202,38,220,21,236,74,184,101,214,168,12,203,38,240,52, +132,52,132,166,124,204,103,240,150,124,233,124,136,224,245,224,190,224,191,71, +18,230,32,198,38,168,38,146,38,28,88,28,88,224,65,230,38,84,89,84, +38,140,89,140,162,12,195,38,244,50,124,50,124,144,120,182,110,216,99,236, +150,126,237,126,134,222,245,222,188,222,189,69,24,44,235,44,94,64,95,12, +162,64,163,10,36,82,223,82,34,130,56,120,95,82,66,112,116,112,94,140, +66,158,35,164,66,130,81,146,152,82,152,138,154,146,162,152,176,154,204,154, +214,148,227,132,204,102,153,130,20,188,239,188,98,164,98,188,92,204,74,224, +58,232,39,240,170,242,171,165,30,36,67,72,20,228,30,220,42,212,48,208, +64,208,74,212,94,224,116,230,239,228,12,116,54,116,55,208,72,46,233,46, +216,124,216,70,94,70,94,124,217,124,94,98,217,98,132,124,133,16,172,124, +173,16,204,204,204,148,104,148,104,204,205,204,104,176,205,177,22,36,43,74, +96,38,79,74,16,92,99,92,60,244,61,8,18,176,61,110,96,146,61,104, +104,36,245,36,224,134,224,66,114,66,114,134,225,134,114,100,225,100,150,134, +151,8,184,134,185,8,124,244,124,160,214,160,215,242,124,192,213,192,124,226, +213,227,50,26,83,62,214,24,179,62,18,80,243,80,110,80,111,10,154,80, +155,12,51,110,212,244,213,110,50,110,50,226,213,226,84,92,117,122,176,90, +151,124,76,134,189,134,68,172,195,172,132,212,133,135,16,40,239,40,92,60, +93,12,164,62,165,12,36,78,77,106,20,118,63,146,26,236,61,168,198,104, +198,74,108,74,108,104,199,104,138,156,138,128,92,128,92,156,139,156,216,156, +216,128,168,128,168,156,217,156,74,184,237,184,152,246,153,162,68,236,100,218, +130,194,139,184,234,232,198,216,176,198,165,185,22,46,235,46,62,124,62,78, +198,78,199,126,130,152,131,12,20,172,46,160,72,144,100,122,131,88,238,164, +212,156,186,140,156,118,131,88,108,164,165,188,84,200,181,237,196,112,196,28, +58,28,58,112,197,112,58,72,197,72,12,156,241,156,128,240,129,113,34,22, +75,54,14,88,55,118,20,232,65,146,198,62,198,22,114,22,114,62,199,62, +222,130,222,90,172,90,172,130,223,130,142,130,142,90,92,90,92,130,143,130, +76,164,239,164,156,246,157,144,80,226,157,172,234,222,190,200,157,167,20,126, +72,116,124,96,168,66,192,36,35,36,238,120,194,112,156,102,114,82,82,58, +63,36,112,48,139,68,196,188,196,148,66,148,66,188,197,188,182,200,223,240, +38,234,205,224,130,226,131,117,92,82,92,22,36,22,36,82,93,82,14,212, +101,184,66,82,67,194,98,132,67,132,34,204,35,116,204,60,204,20,136,20, +136,60,205,60,156,122,156,86,116,86,116,122,157,122,224,124,224,88,180,88, +180,124,225,124,98,158,241,158,166,244,167,136,90,220,130,198,167,158,238,218, +212,206,190,186,167,159,32,190,32,40,74,40,75,184,32,166,75,166,200,56, +200,18,126,18,126,56,201,56,148,120,148,82,104,82,104,120,149,120,222,120, +222,82,176,82,176,120,223,120,90,152,241,152,162,244,163,130,80,222,122,194, +161,152,236,218,194,190,163,153,36,28,71,70,15,110,20,228,32,218,54,208, +68,208,82,218,104,228,126,232,239,232,14,110,60,110,61,208,120,32,108,66, +93,88,212,60,113,60,80,106,235,106,160,106,161,12,202,196,202,140,116,140, +116,196,203,197,200,120,200,44,58,44,58,120,201,120,58,80,201,80,16,178, +239,162,102,134,102,218,104,224,110,230,124,234,200,234,220,222,229,202,114,10, +95,45,34,62,23,128,68,8,68,120,60,176,44,212,25,238,106,52,69,104, +108,196,65,154,112,98,235,98,92,220,245,220,174,220,175,9,28,64,19,126, +58,8,58,152,46,192,34,218,25,234,102,56,59,108,92,198,59,154,202,60, +202,22,132,22,132,60,203,60,150,124,150,88,106,88,106,124,149,124,222,124, +222,88,178,88,178,124,223,124,88,160,241,160,164,244,165,138,90,226,120,206, +148,182,165,166,236,220,206,202,184,182,167,161,28,42,233,42,50,70,207,70, +18,100,241,100,128,100,129,8,62,198,62,132,194,132,195,194,128,152,120,188, +108,206,88,220,60,232,29,242,144,198,221,241,16,64,97,64,18,158,81,110, +62,8,62,234,29,220,94,28,210,28,186,60,164,84,136,104,97,122,238,112, +210,106,186,96,160,82,134,58,115,28,108,144,221,144,96,186,239,186,164,244, +165,113,42,178,42,32,126,32,127,174,84,68,84,132,78,174,64,202,46,220, +23,236,94,184,145,226,174,180,175,32,224,10,224,236,191,245,42,18,81,48, +16,78,59,108,20,224,65,144,90,26,202,26,178,56,148,82,118,100,92,112, +83,118,234,110,204,102,170,88,140,64,122,42,111,26,100,138,217,138,82,178, +235,178,156,242,157,105,32,174,32,34,90,34,91,172,60,70,60,134,56,176, +42,208,17,240,70,182,99,212,104,66,239,66,194,18,219,46,104,138,163,138, +134,90,134,152,128,190,116,216,99,238,174,8,174,86,180,130,190,180,204,214, +216,230,224,234,230,232,232,226,237,200,222,94,202,150,180,188,160,210,141,227, +84,14,56,66,25,100,228,52,65,52,92,156,93,52,202,92,93,92,216,130, +93,130,56,176,23,228,118,156,155,190,194,170,239,220,88,172,88,216,90,230, +100,236,162,236,180,228,184,220,189,207,16,86,85,86,20,192,91,168,54,178, +55,16,118,16,147,42,228,118,228,52,104,52,104,118,229,118,206,10,183,52, +122,74,143,100,204,72,183,98,164,118,165,52,116,246,116,150,218,150,219,242, +116,186,219,186,116,222,219,223,36,66,21,120,80,62,91,104,60,246,61,10, +230,116,230,48,114,48,114,116,231,116,126,10,157,36,216,6,183,48,134,68, +153,94,208,66,191,94,172,116,173,48,122,242,122,146,218,146,219,240,122,224, +219,224,122,184,219,185,66,18,105,46,188,14,159,50,68,80,101,108,188,80, +157,108,218,128,218,58,40,58,40,128,219,128,130,128,131,58,62,248,62,160, +194,160,195,246,62,194,195,194,62,228,195,229,32,170,32,36,92,36,93,166, +62,74,62,156,48,196,34,214,17,230,74,180,105,226,230,122,230,56,122,56, +122,122,231,122,174,122,175,56,138,74,159,102,210,74,191,100,126,16,155,42, +216,14,187,56,130,248,130,154,220,154,221,246,130,190,221,190,130,228,221,229, +18,76,131,76,18,164,121,120,78,14,78,236,45,242,162,12,162,210,166,224, +174,230,214,230,226,220,235,193,28,206,28,54,68,54,69,194,28,172,69,172, +90,56,227,56,156,118,157,14,88,126,155,58,230,124,190,100,157,58,200,200, +200,134,114,134,114,200,201,200,114,166,201,166,78,234,235,235,34,26,75,56, +22,88,61,120,28,238,63,156,86,54,229,54,150,118,151,12,76,130,108,104, +130,82,149,56,232,118,190,94,168,74,151,56,200,198,200,130,104,130,104,198, +201,198,104,164,201,164,72,230,241,231,20,74,133,74,76,244,77,12,20,174, +54,128,77,80,118,138,77,96,162,14,162,212,166,228,180,234,220,234,236,224, +241,205,12,56,133,56,78,14,26,128,127,128,18,198,129,168,78,244,79,82, +160,16,160,210,168,226,182,232,210,232,226,222,235,199,62,16,36,66,19,88, +90,58,41,58,28,102,85,102,16,148,91,148,54,102,54,220,89,190,106,172, +106,40,164,40,165,168,136,70,136,140,130,180,118,208,95,234,146,180,179,220, +194,46,195,182,222,16,222,236,193,245,52,16,81,54,40,240,41,58,108,36, +216,36,216,232,183,240,178,164,178,84,78,84,78,164,179,164,78,122,179,122, +128,230,129,85,32,228,32,38,90,38,91,212,32,198,91,198,32,144,91,144, +32,90,91,90,224,24,162,40,111,46,150,54,177,90,96,228,108,218,118,210, +136,210,152,220,170,228,241,228,112,108,208,108,160,172,125,211,16,76,89,76, +54,240,55,12,16,168,38,128,55,90,82,138,55,100,82,238,98,214,108,182, +110,164,110,34,144,34,144,228,125,236,158,236,170,214,178,188,180,154,180,34, +218,34,218,238,195,242,90,122,245,123,18,74,97,74,66,246,67,12,18,170, +67,94,100,134,67,102,152,14,185,38,112,84,112,50,232,50,233,84,154,66, +115,106,182,74,229,104,162,96,132,138,103,168,246,130,141,130,168,248,169,130, +234,166,169,166,240,206,169,207,30,198,30,50,82,50,83,188,30,166,83,166, +152,10,124,76,103,108,238,72,129,72,154,246,155,72,154,126,223,126,154,180, +233,181,96,8,62,76,23,126,244,58,73,58,116,246,117,58,218,120,117,120, +234,178,117,179,38,68,21,132,70,12,70,114,60,174,21,232,110,58,71,102, +106,206,65,156,162,12,142,62,111,110,246,72,139,72,158,246,159,72,230,128, +159,128,240,178,159,179,36,16,79,52,12,96,64,96,64,220,105,178,156,8, +140,48,101,110,244,64,131,64,156,242,157,64,228,120,157,120,238,176,157,177, +18,74,93,74,20,158,85,126,58,8,58,240,29,226,146,8,175,32,90,44, +241,44,104,244,104,96,226,96,226,236,199,242,122,132,205,132,124,58,147,82, +202,56,175,96,190,202,190,162,138,162,138,202,191,202,162,162,163,105,114,12, +145,34,30,44,233,44,80,60,116,82,154,100,198,110,237,114,18,120,58,114, +98,104,136,88,166,64,185,44,58,132,207,132,56,244,56,168,210,168,210,238, +189,244,110,168,111,230,158,230,159,168,118,168,133,133,110,16,149,42,40,94, +40,56,222,56,223,92,194,98,114,106,61,108,22,170,237,154,226,204,216,228, +208,232,198,236,138,236,126,232,124,224,125,107,108,16,141,38,28,90,28,48, +224,48,225,90,98,66,47,110,142,66,195,96,116,88,80,132,33,166,222,120, +93,120,110,246,111,120,206,158,111,158,208,198,111,199,78,12,44,86,15,118, +54,244,55,66,90,40,237,40,98,70,227,70,76,102,243,102,160,102,161,10, +108,204,108,132,216,132,217,202,158,150,158,184,148,204,130,220,110,230,79,240, +172,200,235,239,104,10,135,34,32,78,32,44,222,44,223,76,46,78,203,78, +48,106,201,106,22,136,231,136,96,136,97,54,158,136,159,56,16,188,46,174, +74,156,91,136,242,186,216,178,184,160,161,136,60,182,191,182,130,152,130,244, +105,250,100,202,66,222,37,236,154,202,213,239,24,224,24,44,74,44,75,216, +24,96,75,96,24,148,75,148,24,198,75,198,150,14,105,56,238,68,108,68, +108,166,98,208,81,238,176,68,192,36,127,36,156,80,127,104,196,80,225,102, +162,94,185,110,116,118,245,118,128,144,223,144,128,170,223,170,134,244,134,196, +214,196,215,244,134,228,215,229,106,24,50,38,17,44,18,100,109,90,12,156, +115,146,236,202,226,222,214,226,162,228,92,228,68,222,62,206,63,36,206,184, +206,110,130,110,130,184,207,184,162,110,163,12,228,64,163,65,108,12,74,36, +25,60,240,62,50,62,50,148,44,188,34,210,21,232,50,114,247,114,116,72, +79,98,174,72,217,96,136,86,167,104,162,62,180,32,81,32,82,140,217,140, +82,166,219,166,90,244,90,194,210,194,211,244,90,228,211,229,26,38,51,76, +112,38,93,80,18,104,123,104,70,246,71,10,20,192,50,148,71,106,108,160, +71,120,130,246,130,132,224,132,225,244,130,218,225,218,166,132,167,8,244,66, +167,67,38,24,91,58,20,86,71,118,30,234,79,154,110,246,110,134,218,134, +219,244,110,220,219,220,156,134,157,12,156,66,239,67,142,14,179,32,32,56, +211,40,20,94,233,74,188,96,134,124,90,136,47,140,104,10,106,52,120,88, +148,120,178,140,202,148,214,148,224,142,233,126,12,230,245,230,56,230,56,166, +202,166,203,230,106,230,107,166,152,230,153,167,12,58,117,58,68,14,28,124, +119,124,16,194,119,174,74,246,75,84,228,20,182,32,138,38,138,154,126,204, +107,240,242,104,139,104,196,246,197,105,16,62,107,62,72,14,32,134,107,134, +22,194,107,174,74,246,75,90,94,232,110,204,120,172,124,148,124,32,222,32, +222,72,125,72,226,112,125,112,238,152,125,152,160,86,161,152,198,88,199,152, +152,152,152,234,183,210,176,152,182,170,190,188,206,210,239,232,224,168,199,197, +48,18,48,54,214,54,215,14,130,8,131,54,18,98,131,98,78,70,30,152, +129,152,20,200,131,182,86,242,87,118,224,80,190,88,152,92,152,162,144,196, +113,234,238,136,153,136,200,242,201,137,18,230,40,186,48,144,48,26,212,26, +212,66,49,66,66,104,217,104,54,146,235,146,110,146,111,78,168,146,169,78, +90,146,90,234,141,202,136,146,146,168,158,184,182,204,239,232,206,164,175,199, +26,38,229,38,94,62,95,12,160,58,161,10,24,78,123,78,38,242,38,112, +108,112,109,236,38,220,109,220,38,192,109,192,62,78,62,132,55,168,82,78, +82,158,109,158,150,62,134,106,123,124,142,194,143,84,174,58,191,78,226,90, +149,90,150,120,221,120,150,150,221,150,150,180,233,180,182,180,183,90,136,200, +123,234,156,204,165,238,184,198,197,234,208,194,229,235,16,72,107,72,66,244, +67,10,18,174,50,120,67,80,100,130,67,96,188,16,217,46,126,86,231,70, +130,138,243,114,224,144,200,172,172,198,140,218,107,228,158,8,158,82,164,136, +178,188,196,218,216,232,226,234,234,232,241,205,52,244,52,132,194,132,195,242, +52,218,195,218,120,132,121,12,120,64,229,65,30,226,30,122,100,122,101,216, +30,198,101,198,182,28,215,64,108,98,233,88,212,116,194,154,166,190,144,210, +119,226,152,10,152,60,154,100,164,152,184,196,210,226,220,232,230,230,234,218, +237,198,60,122,61,16,60,66,119,67,48,18,73,60,16,72,113,72,28,106, +51,174,16,210,109,182,94,94,69,192,126,244,126,130,222,130,223,242,126,216, +223,216,166,130,167,8,166,66,241,67,32,28,73,58,18,90,63,118,24,236, +65,154,82,54,235,54,76,154,241,154,102,154,102,230,233,230,152,172,121,206, +180,172,215,204,114,154,115,16,196,154,197,14,114,88,197,88,114,118,197,119, +94,52,34,162,101,150,62,18,22,98,71,92,22,220,103,192,150,12,185,42, +118,88,118,52,226,52,227,86,116,104,227,104,136,142,122,202,97,242,130,174, +146,198,160,212,174,222,194,226,243,228,174,104,175,220,174,158,229,159,16,72, +99,72,62,248,63,8,18,170,46,126,63,84,98,134,63,102,154,12,183,36, +112,48,235,48,104,90,243,90,138,58,161,90,204,56,185,90,216,172,216,114, +126,114,126,172,217,172,126,142,217,142,94,202,249,202,174,246,175,173,104,12, +143,34,36,46,227,46,14,92,245,92,80,58,105,82,178,56,149,92,198,176, +198,120,60,120,60,176,199,176,60,148,199,148,16,208,239,208,130,248,131,177, +76,12,95,34,28,44,145,44,16,88,151,88,52,58,71,78,124,56,101,88, +128,168,128,114,42,114,42,168,129,168,42,140,129,140,14,198,153,198,86,246, +87,168,218,22,190,62,161,94,224,88,194,126,155,158,230,156,190,202,133,241, +14,36,78,36,78,92,32,92,28,148,82,148,74,226,68,232,58,236,37,236, +212,30,180,68,155,94,96,122,233,122,128,14,128,236,171,206,166,122,170,150, +182,180,206,208,233,229,36,94,36,58,224,58,225,92,62,20,99,46,132,8, +133,58,198,16,163,58,184,112,184,82,80,82,80,112,185,112,200,126,142,134, +45,138,50,164,205,164,18,190,239,190,96,236,116,236,124,232,132,224,133,137, +26,28,61,54,14,92,53,116,24,236,57,158,68,30,116,30,116,90,76,90, +76,148,114,148,114,230,79,242,120,122,237,122,152,14,152,230,189,202,220,32, +177,92,180,122,188,156,200,188,220,216,235,227,34,24,75,54,18,86,59,114, +20,226,65,148,134,10,167,36,92,46,227,46,70,90,243,90,118,60,141,90, +190,58,167,90,200,172,200,114,104,114,104,172,201,172,104,142,201,142,70,202, +237,202,154,244,155,173,18,74,99,74,60,246,61,12,16,176,40,136,61,88, +96,138,61,92,112,74,239,74,178,10,178,118,168,174,142,204,116,224,91,236, +122,102,140,144,156,174,178,200,208,222,239,237,22,64,235,64,140,10,140,108, +126,166,104,198,78,216,52,228,29,236,58,92,76,122,100,152,134,184,170,204, +202,218,233,227,20,188,20,64,88,64,88,182,75,186,54,248,55,12,104,114, +239,114,134,8,134,232,175,196,214,22,167,88,166,114,172,138,184,164,196,186, +214,204,239,223,32,178,32,32,98,32,99,172,64,56,64,168,54,196,36,218, +19,238,78,186,111,226,110,114,239,114,140,10,140,232,179,204,210,22,169,90, +240,220,218,206,198,184,182,152,173,115,80,14,46,88,17,130,58,244,59,64, +86,76,239,76,172,12,172,126,164,168,142,200,120,218,89,234,114,106,126,140, +144,168,172,196,208,218,237,231,18,232,34,196,42,150,42,30,88,30,88,232, +67,242,42,88,89,88,42,142,89,142,104,118,239,118,134,12,134,234,181,202, +216,24,184,70,163,94,166,118,176,146,188,176,212,206,235,225,126,16,153,34, +238,46,60,46,60,160,54,190,42,218,31,238,22,64,41,102,18,158,61,130, +136,56,159,70,86,80,223,80,76,112,245,112,124,92,135,112,186,90,171,112, +208,188,208,136,102,136,102,188,209,188,102,162,209,162,74,214,239,214,156,248, +157,189,32,248,32,34,80,34,58,108,70,124,76,140,80,152,80,168,74,176, +55,180,142,14,173,34,94,46,225,46,80,88,241,88,122,58,143,88,190,54, +173,88,210,178,210,114,108,114,108,178,211,178,108,146,211,146,80,206,241,206, +162,248,163,179,16,68,101,68,18,156,93,118,62,8,62,232,33,224,108,28, +222,28,220,92,214,106,204,112,181,116,158,28,156,58,146,90,134,110,117,126, +120,244,120,144,220,144,221,240,120,216,221,217,28,210,28,34,84,34,85,202, +28,104,85,104,28,180,85,180,104,24,218,24,216,90,210,104,204,110,179,114, +156,24,156,46,152,78,136,104,107,124,124,240,124,146,220,146,221,238,124,216, +221,217,20,74,113,74,20,162,105,122,72,12,72,232,37,222,108,94,233,84, +212,116,180,166,152,194,130,212,103,228,182,32,211,62,154,12,154,116,160,150, +174,192,196,218,210,230,218,230,228,222,237,201,46,26,89,60,26,88,67,116, +38,228,83,146,100,30,220,30,216,96,208,110,194,114,183,116,150,30,146,56, +140,82,124,108,103,122,116,246,116,146,220,146,221,244,116,220,221,221,32,56, +129,56,22,98,141,98,82,96,83,10,48,134,44,170,36,204,27,232,240,228, +138,228,104,224,78,216,56,200,43,182,86,114,87,216,86,154,133,154,136,38, +178,96,227,180,220,26,188,100,162,146,135,185,94,164,94,30,44,30,44,164, +95,164,44,96,95,96,114,28,222,28,220,60,218,74,210,82,200,86,189,90, +162,28,160,48,152,66,140,82,128,94,117,102,218,158,218,110,136,110,136,158, +219,158,62,186,27,236,96,190,113,236,146,186,167,230,190,182,233,231,216,64, +216,24,48,24,48,64,217,64,102,64,103,24,158,64,159,24,198,174,198,118, +62,118,62,174,199,174,62,146,199,146,124,118,125,64,124,90,225,90,14,204, +243,204,130,248,131,175,42,58,89,104,110,16,110,148,96,186,74,208,48,222, +25,232,26,164,111,130,152,16,152,208,156,220,162,226,174,228,212,230,228,222, +237,196,222,58,169,108,166,128,225,169,64,12,89,34,45,82,22,120,34,104, +40,92,44,84,44,40,114,40,114,82,45,82,166,12,146,48,131,66,158,58, +176,74,196,88,218,96,233,100,238,40,151,40,208,40,200,56,188,72,172,86, +149,98,54,114,196,114,196,162,55,162,24,138,239,138,48,188,219,188,30,214, +231,214,128,246,129,97,40,36,214,36,210,94,204,108,192,114,176,118,153,118, +120,36,118,58,108,82,92,102,70,116,48,124,23,132,70,244,70,152,208,152, +209,242,70,218,209,219,24,30,65,62,18,228,30,220,38,214,44,212,58,212, +68,216,92,222,114,230,239,228,12,112,50,112,51,212,134,14,167,36,232,48, +94,48,94,124,84,160,69,186,102,100,231,100,136,66,136,140,188,140,189,66, +120,164,97,204,140,172,147,206,172,166,183,202,200,162,225,201,16,62,105,62, +18,152,105,112,64,8,64,232,39,238,224,18,178,26,130,30,130,136,124,174, +106,212,87,234,130,98,243,98,196,240,197,99,20,48,119,48,24,104,117,78, +76,12,76,136,62,144,45,146,218,22,174,30,138,34,138,94,134,118,124,138, +115,150,240,80,139,80,194,154,195,80,60,244,60,170,200,170,201,244,60,224, +201,225,18,46,109,46,18,92,103,72,68,10,68,124,43,132,122,46,196,46, +198,84,200,106,206,118,210,120,220,120,230,108,237,88,158,8,156,54,150,76, +138,96,122,108,101,122,118,72,167,102,202,186,202,150,50,150,50,186,203,186, +24,232,213,220,192,200,231,238,126,122,127,225,14,58,89,58,62,12,26,130, +87,130,14,192,91,174,62,246,63,86,116,14,141,40,96,54,167,54,142,74, +159,112,124,54,98,106,153,98,104,242,104,128,152,128,152,238,133,242,104,160, +153,160,104,192,153,192,198,12,188,54,171,96,240,70,183,70,178,104,186,142, +196,170,210,202,239,234,216,70,216,104,212,142,202,174,188,204,165,237,54,52, +199,52,20,100,245,100,126,100,127,8,228,42,144,112,80,148,19,172,88,246, +88,144,198,144,199,244,88,182,199,182,88,224,199,225,64,18,38,70,19,92, +104,60,45,60,32,104,97,104,22,148,105,148,62,104,62,230,101,202,120,56, +197,56,110,100,243,100,164,100,165,12,224,36,176,112,124,158,93,178,138,246, +138,140,218,140,219,244,138,178,219,178,138,220,219,221,22,44,243,44,92,72, +93,12,168,72,169,12,118,60,143,80,228,88,50,88,52,146,52,170,42,204, +25,234,70,134,237,134,114,104,114,176,180,176,181,102,96,194,67,240,120,200, +139,234,160,198,177,234,198,192,231,237,34,28,71,66,20,230,36,218,52,210, +64,210,78,214,106,226,132,230,239,226,16,110,58,110,59,210,136,14,173,44, +90,64,233,64,106,100,168,146,219,196,188,64,186,88,174,126,146,160,116,180, +83,195,36,22,77,56,18,88,59,118,18,236,61,148,72,78,147,78,76,166, +143,122,110,10,110,236,79,224,228,16,194,28,162,34,162,162,152,196,135,228, +162,100,247,100,206,238,207,101,10,42,95,42,14,110,89,110,16,208,97,178, +54,42,55,192,164,12,140,60,101,102,234,100,206,82,184,60,159,24,174,92, +144,122,115,142,196,130,166,162,127,188,222,164,164,216,97,237,20,50,147,50, +12,150,149,150,52,148,53,10,114,150,115,10,52,82,115,82,52,114,115,114, +38,150,38,224,139,224,80,164,55,200,100,164,127,196,158,46,187,80,148,102, +183,136,142,178,245,164,208,244,209,11,32,42,225,42,16,190,243,190,68,190, +68,74,186,74,187,190,122,74,129,10,100,202,33,240,148,200,223,238,68,104, +187,104,68,132,187,132,68,162,187,163,14,32,123,32,116,128,116,72,28,72, +28,128,117,128,56,128,57,32,86,128,87,32,22,174,121,174,12,232,119,214, +72,144,73,220,142,32,237,32,156,32,136,230,179,204,164,124,185,160,150,88, +206,88,200,218,202,224,208,230,220,232,232,230,238,222,243,211,22,40,121,40, +18,138,38,114,54,86,69,40,50,222,50,108,100,108,101,216,50,192,101,192, +136,240,136,130,224,130,225,240,136,216,225,216,172,130,173,16,172,64,245,65, +18,36,91,36,72,70,99,114,62,44,26,106,87,98,18,146,91,146,16,226, +101,200,58,110,59,212,120,40,231,40,126,70,227,70,112,102,239,102,170,10, +152,86,134,124,110,150,91,168,182,102,190,118,204,138,226,156,241,162,186,130, +141,140,112,170,221,170,166,246,167,136,100,230,134,206,167,172,230,228,181,191, +60,196,60,92,204,92,205,194,239,48,124,12,125,92,124,48,239,48,130,120, +130,150,124,178,110,200,80,220,52,230,29,238,142,194,231,237,72,12,46,62, +21,88,120,58,51,58,34,100,111,100,18,148,121,148,70,100,70,228,121,194, +120,106,245,106,182,244,183,13,84,18,48,88,21,122,62,244,63,64,116,186, +116,86,218,86,219,182,156,86,157,12,242,44,157,44,164,114,164,162,162,188, +146,210,126,224,101,238,184,192,243,237,20,72,111,72,66,242,67,8,18,174, +48,126,67,82,110,138,67,100,126,104,126,68,232,68,233,104,174,8,174,94, +168,134,150,182,126,214,105,236,188,114,188,228,196,232,220,236,234,230,240,218, +243,199,126,12,161,36,22,66,45,106,240,48,64,48,66,130,62,172,52,206, +31,238,16,158,65,124,158,62,130,102,104,124,87,134,150,72,168,90,192,108, +218,120,239,126,170,116,132,148,101,168,194,146,154,182,109,204,226,172,186,206, +146,226,85,241,34,26,77,66,12,102,56,102,54,226,95,184,162,12,140,60, +118,88,93,108,236,100,206,84,178,54,157,24,174,92,146,120,115,144,200,126, +168,158,131,184,230,162,180,206,103,239,38,22,221,22,32,88,32,48,228,48, +229,84,126,108,127,22,54,74,107,74,152,74,209,74,54,98,105,98,154,98, +209,98,224,120,52,120,52,188,31,232,228,174,53,174,76,146,209,146,90,174, +90,234,137,212,228,234,200,230,168,216,148,196,135,174,206,184,167,213,12,74, +93,74,12,162,91,122,54,8,54,236,25,226,228,28,110,28,110,48,112,96, +110,150,100,190,81,226,136,74,213,74,238,118,121,118,140,118,140,232,181,208, +236,228,210,206,188,180,176,144,171,118,226,140,187,175,62,16,36,72,19,94, +106,58,45,58,32,98,101,98,20,146,107,146,64,98,64,224,101,198,106,188, +249,188,104,38,241,38,130,188,130,70,218,70,219,188,164,70,165,10,130,100, +219,100,130,128,219,128,130,158,219,158,154,202,101,238,186,200,243,239,34,246, +34,32,84,32,62,106,74,122,82,142,86,158,82,174,70,182,55,184,98,50, +235,50,158,12,116,124,227,124,98,184,239,184,172,244,173,81,14,38,239,38, +96,60,97,10,160,56,161,10,54,74,178,74,130,104,130,162,111,168,28,110, +100,110,82,136,62,152,40,164,23,174,130,108,152,130,182,148,212,158,237,162, +218,92,157,132,66,184,191,184,60,200,31,242,98,202,111,240,146,200,165,236, +198,196,233,235,14,70,93,70,18,158,89,116,60,10,60,238,29,228,144,12, +118,62,97,90,110,88,216,88,217,190,104,130,245,130,102,174,217,174,172,88, +194,44,129,44,132,238,146,238,158,234,162,228,164,218,165,89,28,222,28,38, +76,38,77,220,28,92,77,92,28,142,77,142,28,196,77,196,150,12,118,52, +95,72,108,84,216,84,217,188,104,168,217,168,94,126,241,126,128,236,144,236, +156,232,160,222,161,84,168,84,194,44,125,45,82,20,50,60,25,82,88,74, +54,124,21,156,60,244,61,118,100,36,239,36,84,222,245,222,122,222,123,106, +172,222,173,36,172,118,229,119,20,26,46,50,64,78,74,114,76,164,74,204, +62,228,48,232,35,234,86,26,52,66,21,96,20,166,50,140,71,110,150,12, +120,54,91,84,108,86,220,86,221,192,104,174,221,174,94,128,247,128,172,86, +194,42,131,42,130,240,150,238,160,232,162,218,163,87,96,12,68,52,31,90, +50,86,200,86,201,188,14,130,243,130,46,172,201,172,140,86,170,38,81,38, +128,84,128,216,126,228,120,236,108,238,93,241,60,244,61,10,30,64,19,124, +80,62,97,102,98,34,239,34,82,226,245,226,120,226,121,106,170,226,171,34, +170,122,229,123,28,38,141,38,128,96,128,64,46,64,46,96,129,96,88,142, +89,6,26,144,89,96,122,126,89,96,174,8,158,52,145,78,238,44,163,44, +164,68,174,86,188,104,210,122,237,134,140,136,162,126,182,110,198,90,206,68, +213,44,48,156,223,156,24,228,239,228,78,228,79,178,136,228,137,156,136,188, +203,189,14,70,93,70,14,160,91,124,56,12,56,232,27,222,104,28,202,28, +160,70,160,200,139,206,93,94,92,92,134,92,126,128,114,156,83,188,238,186, +206,158,186,124,161,80,222,78,183,114,82,224,239,225,30,34,229,34,14,222, +243,222,68,222,69,90,134,222,135,34,210,116,135,117,18,38,137,38,14,208, +133,182,82,38,83,192,38,88,39,202,126,116,83,116,166,8,148,54,127,102, +240,68,145,68,144,102,160,156,186,192,235,226,96,232,128,216,162,192,186,154, +198,108,203,69,60,246,61,10,26,192,26,70,96,70,96,184,81,188,132,188, +132,92,216,92,217,186,166,92,167,12,240,44,167,44,174,116,172,158,166,188, +152,208,132,226,107,238,186,196,241,237,122,14,161,44,236,54,62,54,62,102, +62,152,54,196,42,222,27,244,18,76,47,112,18,164,63,132,84,96,229,96, +66,230,243,230,158,230,159,96,158,156,223,156,106,230,107,137,38,20,71,56, +26,74,143,74,130,16,91,74,20,134,149,134,82,74,82,138,72,168,56,200, +38,220,23,230,138,210,81,144,164,244,164,34,230,34,192,108,216,126,234,150, +236,174,230,192,214,204,193,205,38,18,75,60,14,98,54,98,50,234,91,182, +94,34,239,34,78,226,243,226,120,226,121,96,168,226,169,34,228,120,169,121, +14,52,241,52,88,84,89,16,164,84,165,16,114,76,143,104,28,230,44,216, +64,206,82,206,118,222,140,230,154,230,239,230,40,122,194,122,79,207,16,76, +95,76,58,244,59,14,18,176,59,100,90,136,59,98,106,60,235,60,112,118, +214,118,194,162,160,200,126,222,95,232,238,232,198,216,160,184,138,146,125,118, +170,118,171,9,26,66,229,66,48,120,186,120,156,162,122,196,84,216,58,226, +29,236,232,230,190,220,148,200,108,170,88,144,75,120,128,120,129,13,30,196, +30,48,80,48,81,188,30,168,79,168,92,60,237,60,98,120,212,120,194,158, +172,190,132,220,89,240,238,232,198,214,164,190,142,162,123,120,164,120,165,9, +88,148,88,62,26,62,26,148,89,148,15,216,80,168,101,206,14,216,91,190, +58,10,59,200,136,10,116,62,107,82,102,126,173,126,172,58,119,58,140,58, +140,136,130,180,114,210,98,228,83,244,168,210,137,158,190,236,190,56,232,56, +233,232,190,208,233,209,74,10,44,74,25,100,134,58,53,58,18,132,145,132, +90,58,86,146,70,188,50,216,25,240,132,210,83,156,160,236,160,58,226,58, +227,230,160,204,227,205,16,238,30,200,36,160,36,28,90,28,90,232,61,238, +36,88,91,88,36,140,91,140,108,60,243,60,112,116,218,116,200,160,174,190, +138,220,107,236,238,234,196,210,164,182,144,146,131,116,174,116,175,9,12,234, +26,206,36,170,36,24,88,24,88,228,61,234,36,84,89,84,36,140,89,140, +132,6,132,82,134,96,144,102,214,102,226,96,232,86,239,70,226,28,133,54, +128,242,128,136,220,136,221,240,128,176,221,176,128,218,221,219,34,20,79,56, +18,82,65,116,30,232,81,148,84,100,243,100,164,244,165,9,104,22,141,62, +34,86,198,86,71,194,22,224,38,206,50,196,60,194,74,196,96,210,130,220, +239,221,67,16,102,52,30,166,111,148,18,222,111,196,66,16,22,100,73,96, +210,136,210,32,132,32,132,136,211,136,154,162,105,242,184,160,237,237,10,26, +119,26,14,202,121,166,38,26,39,192,92,242,93,26,38,80,93,80,38,128, +91,128,216,128,216,30,136,30,136,128,217,128,160,160,113,232,194,156,239,233, +32,50,227,50,14,228,241,228,72,228,72,90,186,90,187,228,72,124,187,124, +72,156,187,156,72,190,187,190,122,90,129,13,18,76,95,76,62,246,63,14, +20,166,63,90,90,136,63,96,96,48,237,48,88,226,245,226,124,226,124,82, +210,82,211,226,124,188,211,188,124,154,211,154,124,118,211,118,162,82,169,13, +16,44,91,44,58,44,52,84,36,122,17,148,18,238,56,206,74,178,86,146, +96,96,51,96,46,140,79,164,116,50,239,50,86,226,247,226,128,226,128,84, +210,84,211,226,128,190,211,190,128,154,211,154,128,120,211,120,168,84,179,13, +12,68,91,68,16,154,87,118,58,12,58,232,23,224,146,12,146,98,138,154, +120,198,85,236,114,126,167,172,112,78,198,78,198,136,202,182,210,224,212,236, +218,238,226,236,241,209,70,16,38,90,17,120,52,244,53,60,82,48,235,48, +72,224,245,224,106,224,106,84,204,84,205,224,106,118,205,118,106,154,205,154, +106,190,205,190,152,84,159,11,80,14,44,86,19,124,56,244,57,64,90,38, +243,38,186,66,239,126,152,46,96,114,219,106,94,168,233,168,76,228,247,228, +162,228,163,125,14,210,103,174,14,92,101,92,60,18,61,190,68,228,245,228, +124,228,125,58,178,228,179,12,178,104,233,105,18,70,105,70,16,158,93,118, +62,14,62,236,31,226,134,12,134,82,134,94,142,102,214,102,230,94,239,72, +222,30,135,58,124,244,124,138,220,138,221,244,124,180,221,180,124,224,221,225, +16,226,241,226,66,74,67,226,138,16,139,226,216,102,139,103,96,94,96,34, +34,34,34,94,97,94,16,232,111,198,32,130,33,224,68,94,69,212,106,148, +69,148,92,228,245,228,136,228,137,72,184,228,185,10,184,100,237,101,194,126, +194,36,66,36,66,126,195,126,100,154,27,238,154,154,233,235,50,14,50,82, +54,98,66,106,200,106,218,94,225,70,204,34,51,60,54,244,54,140,200,140, +201,242,54,180,201,180,54,220,201,221,98,54,24,160,97,152,64,16,18,94, +71,92,18,212,101,196,220,22,160,34,122,36,122,224,163,194,122,114,235,114, +170,34,170,98,178,142,190,200,208,226,214,232,220,232,228,224,237,203,24,56, +237,56,46,110,215,110,130,110,131,10,52,160,29,224,116,138,151,182,188,150, +231,206,92,156,92,208,94,222,100,226,162,226,178,220,185,201,18,44,103,44, +20,86,101,68,70,10,70,114,45,104,124,44,202,38,202,68,206,94,210,106, +216,112,222,110,237,88,160,8,154,56,140,88,124,100,105,114,122,64,173,96, +202,122,116,132,39,132,50,162,209,162,18,192,237,192,130,132,130,218,126,232, +112,238,101,241,14,68,79,68,98,80,161,80,92,132,167,132,16,148,87,110, +58,10,58,230,29,224,92,24,113,58,156,18,129,80,124,80,124,140,118,174, +104,202,83,226,162,206,125,148,180,240,180,34,228,34,200,102,218,120,234,142, +238,170,228,192,201,187,30,36,229,36,118,46,58,112,189,106,158,64,203,124, +50,164,211,164,18,222,241,222,128,222,129,125,12,38,133,38,90,68,127,118, +66,48,28,110,115,104,20,156,123,156,16,226,125,196,72,118,73,208,174,12, +160,58,141,102,144,116,164,158,188,194,212,214,239,230,238,78,153,78,106,238, +146,214,174,184,192,144,200,104,203,79,212,66,212,28,46,28,46,66,213,66, +98,66,99,28,156,66,157,28,26,96,233,96,16,224,239,224,62,224,62,124, +194,124,195,224,62,198,195,198,62,174,195,174,62,148,195,148,110,124,129,77, +66,242,67,10,30,184,30,62,102,62,102,178,87,182,216,140,216,32,140,32, +140,140,217,140,162,160,101,230,188,162,237,231,96,64,97,210,28,66,28,190, +97,184,60,14,61,186,116,52,225,52,108,96,245,96,168,96,169,6,116,144, +237,144,132,162,159,196,198,110,198,236,167,247,58,20,29,80,152,58,39,58, +18,104,157,104,44,224,44,144,142,144,142,214,119,218,92,240,93,12,180,174, +181,48,224,16,224,234,191,241,68,14,46,54,33,70,136,48,51,48,20,88, +143,88,26,146,58,126,76,108,86,86,93,48,130,134,106,114,90,102,83,96, +218,120,218,46,158,46,158,120,219,120,72,248,72,150,192,150,193,244,72,226, +193,226,72,188,193,189,100,32,62,40,27,44,20,96,101,96,64,244,65,40, +20,192,65,110,104,160,65,118,134,36,126,76,115,110,126,138,237,138,228,76, +127,76,170,12,170,142,156,182,138,206,107,238,234,234,212,216,190,188,169,149, +104,24,62,34,25,36,16,86,105,86,66,240,67,34,18,184,67,106,100,154, +67,108,146,14,128,76,99,122,126,242,127,80,172,16,203,52,140,64,241,64, +138,112,235,112,140,160,235,160,138,210,247,210,186,210,187,65,214,20,134,34, +52,38,52,140,40,188,23,222,66,74,241,74,100,198,100,116,210,116,211,196, +140,116,151,48,154,140,150,178,138,202,118,218,94,230,69,236,168,192,241,237, +120,12,80,50,41,74,32,122,82,118,130,102,180,72,204,44,89,44,120,60, +149,90,80,78,109,108,74,138,55,188,200,126,171,174,132,118,126,168,116,194, +98,208,70,222,50,230,25,236,234,230,202,222,168,204,146,184,129,159,126,12, +157,32,240,46,58,46,58,158,52,200,29,240,16,156,59,126,20,66,39,102, +86,86,223,86,76,128,245,128,154,128,155,56,86,166,241,166,110,184,145,216, +200,140,200,242,167,249,32,26,71,56,20,84,59,114,24,230,67,146,92,50, +241,50,116,82,117,8,156,82,157,10,198,82,199,8,86,134,86,100,232,100, +233,132,110,222,110,142,210,142,210,216,189,220,158,244,159,101,36,28,81,58, +18,90,63,120,32,236,77,154,159,14,184,48,237,106,160,14,98,100,223,90, +108,246,108,144,210,144,211,244,108,218,211,219,102,14,143,38,34,84,34,48, +216,48,217,84,108,66,61,90,138,64,195,88,34,106,217,106,158,124,207,160, +112,114,62,158,189,148,48,188,205,188,16,228,235,228,126,228,127,153,44,170, +44,66,212,66,213,166,44,148,213,148,128,244,129,11,198,106,198,50,58,50, +58,106,199,106,128,138,129,12,12,222,243,222,54,222,54,154,200,154,201,222, +100,222,101,154,150,222,151,155,124,150,125,14,202,116,202,58,48,58,48,116, +203,116,52,162,21,226,118,160,157,188,192,160,239,210,88,166,88,216,90,228, +102,236,158,236,172,228,187,197,70,16,38,66,19,92,112,58,45,58,30,102, +103,102,20,154,111,154,66,102,66,226,111,198,182,244,183,12,134,186,134,70, +234,70,235,182,134,160,235,161,110,16,145,42,16,54,239,54,198,126,198,86, +56,86,56,126,199,126,130,146,131,66,112,148,58,194,21,212,136,206,94,232, +95,166,136,152,156,184,186,208,237,232,206,146,163,187,92,64,28,172,93,158, +62,24,18,108,69,104,16,226,103,206,154,14,130,66,105,100,142,82,162,108, +188,126,216,140,237,146,106,152,136,138,160,118,186,86,204,52,139,52,144,160, +199,184,130,202,211,237,116,20,66,34,29,36,18,90,113,90,70,242,71,34, +20,178,71,102,106,144,71,104,130,176,130,66,228,66,229,176,130,154,229,154, +178,242,179,9,16,230,32,194,36,148,36,30,88,30,88,228,65,234,36,142, +89,142,36,86,89,86,124,174,124,62,226,62,227,168,124,148,227,148,176,242, +177,9,202,18,144,30,45,38,14,68,241,68,48,194,213,194,18,228,239,228, +130,228,131,32,200,164,200,96,58,96,58,164,201,164,58,130,201,131,84,10, +52,82,21,124,62,244,63,60,164,244,165,10,106,174,106,72,226,72,227,174, +106,152,227,153,132,14,112,66,88,88,58,106,35,116,128,24,138,46,154,68, +178,86,227,112,80,118,70,176,50,208,21,236,72,164,127,206,170,114,164,164, +156,196,134,224,115,240,236,234,208,212,180,178,169,143,16,130,245,130,26,240, +52,216,66,188,72,142,72,50,190,50,190,234,149,244,108,74,153,104,102,156, +151,184,126,8,111,51,24,238,40,210,50,170,52,142,52,30,218,30,218,238, +185,244,80,80,189,80,70,118,199,118,132,118,133,46,174,196,174,152,92,152, +92,196,175,197,46,76,29,150,78,20,78,116,70,170,52,204,31,230,96,90, +123,128,144,232,145,26,164,90,193,130,216,238,217,19,42,18,81,50,22,80, +65,110,30,232,67,146,96,88,85,138,116,22,118,120,116,160,104,196,92,218, +75,236,134,92,155,134,166,226,167,30,186,88,207,134,220,240,221,19,42,18, +81,56,14,98,58,98,58,220,99,180,144,10,122,60,91,104,108,104,216,104, +217,240,112,154,217,154,106,210,217,210,172,104,198,50,129,51,22,34,74,34, +74,92,36,92,34,148,74,148,72,222,62,232,33,236,94,48,113,88,168,46, +149,88,94,110,165,110,132,242,133,12,92,200,133,122,166,170,133,122,172,32, +224,32,224,92,182,92,180,148,226,148,226,194,222,222,216,230,206,234,183,237, +14,60,113,60,70,16,32,132,115,132,22,198,115,170,76,242,77,90,132,242, +132,72,228,72,229,238,132,212,229,212,132,138,229,138,180,212,181,11,16,232, +32,194,36,156,36,128,36,30,98,30,98,228,75,236,36,86,99,86,36,144, +99,144,118,84,245,84,134,124,165,166,202,10,202,230,167,243,44,26,196,26, +196,88,45,88,54,56,197,56,24,156,24,120,230,120,231,156,126,244,127,120, +58,224,58,156,196,156,196,208,188,218,174,220,165,221,100,86,100,32,40,32, +40,86,101,86,210,84,210,32,146,32,146,84,211,84,24,236,48,224,70,206, +82,182,86,158,86,122,158,122,158,212,162,226,174,232,202,232,216,228,224,220, +233,199,64,10,40,66,21,92,32,98,98,98,99,222,34,146,99,146,32,204, +99,204,78,98,96,52,47,52,100,238,116,220,128,194,132,164,134,138,134,58, +230,58,219,92,142,122,216,122,208,160,188,194,166,218,133,240,242,236,218,224, +194,204,170,176,158,144,153,122,180,122,181,9,110,10,147,34,28,94,28,50, +228,50,229,92,52,244,52,108,204,108,205,244,52,160,205,160,52,216,205,216, +130,216,131,69,22,158,44,138,60,108,68,80,68,30,198,30,198,74,69,74, +236,146,206,136,178,118,158,96,143,74,184,194,184,128,76,128,76,194,185,194, +76,160,185,160,28,226,237,227,34,56,30,142,86,142,82,220,76,228,62,232, +51,232,12,194,69,180,10,32,70,32,65,142,88,26,167,26,180,40,222,40, +212,72,196,94,189,102,174,60,233,112,152,124,153,26,88,116,169,102,106,26, +107,112,106,54,153,54,106,80,153,80,212,124,152,136,109,142,164,244,165,134, +144,160,103,186,148,188,101,224,238,224,208,206,184,186,165,162,228,148,183,183, +12,44,99,44,16,114,93,114,10,204,95,174,56,44,57,186,134,30,111,94, +226,68,121,68,104,120,243,120,170,244,171,10,92,216,122,190,148,156,171,120, +238,208,212,184,192,158,171,121,14,76,97,76,56,244,57,12,16,170,57,94, +90,144,57,102,132,36,105,100,224,72,119,72,100,124,237,124,166,244,167,10, +88,212,118,188,146,160,167,132,238,210,206,182,186,156,167,127,92,142,92,68, +26,68,26,142,93,142,86,160,105,196,14,210,97,178,60,12,61,192,140,30, +113,94,230,66,125,66,110,118,241,118,172,246,173,10,96,222,130,188,150,156, +173,118,240,216,210,186,188,152,173,119,80,28,60,74,43,100,212,66,65,66, +20,122,235,122,130,242,131,10,24,214,58,192,92,160,123,122,230,208,200,194, +168,166,148,138,139,123,28,20,52,48,66,70,72,90,74,124,76,166,74,194, +68,216,56,226,42,230,35,232,88,20,50,62,21,88,18,162,50,134,73,106, +114,48,195,48,94,96,245,96,158,96,159,8,224,34,192,78,164,108,132,134, +93,164,128,244,128,140,212,140,213,244,128,180,213,180,128,220,213,221,34,22, +77,60,10,100,54,100,50,228,97,196,220,36,192,78,168,106,142,128,116,150, +79,170,104,50,195,50,82,98,243,98,154,98,155,8,120,248,120,144,210,144, +211,246,120,186,211,186,120,226,211,227,32,24,71,56,10,98,48,98,48,216, +83,172,122,32,97,96,216,66,109,66,88,116,233,116,162,242,163,12,90,214, +118,186,140,154,161,116,232,212,206,186,184,154,163,117,26,28,63,60,18,230, +34,218,46,210,60,210,74,216,100,226,132,230,239,228,12,114,52,114,53,210, +78,32,231,32,156,40,116,76,83,98,122,70,136,82,152,98,162,120,168,154, +166,178,156,194,142,202,127,204,80,146,118,124,149,96,86,184,126,162,163,130, +212,72,163,118,226,164,165,123,74,12,54,64,21,116,130,82,43,82,68,240, +69,82,178,12,148,88,117,138,246,82,153,82,160,232,182,232,196,228,202,212, +203,83,30,70,19,134,62,12,62,76,60,138,46,194,25,234,100,56,63,102, +102,198,59,146,220,150,220,70,116,70,116,150,221,150,204,172,241,234,102,226, +225,210,166,216,167,11,44,42,187,42,14,76,245,76,126,76,127,10,222,30, +144,88,102,108,50,126,19,134,196,176,196,112,76,112,76,176,197,176,76,142, +197,142,60,196,31,242,100,200,119,238,152,196,173,238,204,194,237,239,14,68, +99,68,18,160,99,120,64,12,64,240,25,226,122,68,239,68,144,18,185,52, +130,140,229,140,98,228,243,228,170,228,171,69,30,222,30,34,72,34,73,212, +30,88,73,88,30,142,73,142,30,196,73,196,66,238,88,212,98,180,102,136, +102,22,216,22,216,56,103,56,220,74,180,82,121,82,216,142,216,106,132,106, +132,142,217,142,122,244,122,166,226,166,226,218,224,230,210,236,197,236,190,180, +207,210,138,204,199,196,170,198,171,83,28,188,28,34,66,34,67,182,28,164, +67,164,60,226,82,196,94,164,98,130,98,22,220,22,220,54,99,54,228,76, +182,80,119,80,216,140,216,104,126,104,126,140,217,140,188,176,205,210,134,204, +197,198,170,200,171,80,114,240,114,164,224,164,224,216,222,228,212,232,197,235, +110,18,147,56,30,70,229,70,50,140,211,140,20,224,241,224,130,224,131,71, +26,42,231,42,90,70,91,10,168,68,169,10,56,86,181,86,16,124,243,124, +126,124,127,58,210,70,160,112,98,152,25,184,80,244,80,158,194,158,195,242, +80,188,195,188,80,224,195,225,14,76,103,76,66,244,67,10,18,172,67,88, +104,142,67,104,146,18,187,52,124,72,241,72,134,142,231,142,96,226,249,226, +176,226,177,73,18,206,131,182,44,200,44,34,104,34,105,186,44,88,105,88, +44,140,105,140,120,80,226,76,222,208,216,222,206,228,181,228,170,12,170,110, +162,150,148,186,128,212,103,241,100,154,100,74,26,74,26,154,101,154,92,178, +113,218,18,228,105,204,64,214,65,12,154,10,187,50,116,66,237,66,126,140, +227,140,116,226,245,226,174,226,175,67,36,180,36,32,102,32,103,176,68,64, +68,142,60,190,40,222,21,242,80,188,113,234,156,12,187,46,132,108,132,58, +230,58,231,108,118,218,243,219,66,14,36,68,17,88,106,58,43,58,28,98, +99,98,16,148,103,148,60,98,60,224,99,186,118,50,241,50,120,88,231,88, +108,126,247,126,170,12,166,62,158,110,148,148,126,190,105,216,150,168,245,168, +210,138,210,218,208,228,204,234,179,238,152,186,177,217,68,18,44,62,21,98, +124,50,53,50,94,92,71,50,168,16,144,64,127,90,240,48,153,48,202,90, +179,48,30,120,113,120,24,222,109,196,68,208,69,120,88,244,114,220,130,188, +134,156,134,108,192,108,192,210,196,224,204,230,224,230,234,224,245,196,148,152, +173,187,84,14,46,88,17,122,60,246,61,62,132,18,171,54,86,76,243,76, +102,144,231,144,80,228,247,228,162,228,163,77,34,28,77,58,16,94,59,124, +24,234,71,152,138,16,173,52,90,72,237,72,96,140,227,140,76,226,245,226, +162,226,163,73,40,12,77,48,14,72,82,72,48,128,19,154,58,242,59,112, +100,148,61,110,218,118,218,30,118,30,118,118,219,118,146,118,146,142,138,174, +124,204,83,234,184,118,184,208,188,222,202,226,222,226,232,220,241,201,40,56, +38,138,106,138,104,208,100,220,92,230,63,236,16,202,81,178,158,12,185,48, +118,60,239,60,130,134,231,134,120,220,243,220,180,220,181,60,16,32,88,32, +85,139,14,72,99,72,16,160,95,118,60,16,60,238,29,228,214,22,168,36, +120,42,120,170,108,202,89,230,158,238,159,38,236,230,216,194,202,154,194,108, +192,72,193,31,220,32,160,40,62,44,62,134,52,190,21,240,126,242,127,40, +234,234,210,206,190,164,182,118,180,72,181,39,14,76,89,76,14,158,87,122, +54,12,54,238,21,226,216,142,216,54,102,54,102,142,217,142,102,98,217,98, +154,10,154,100,164,164,184,208,214,234,224,236,232,228,237,212,216,156,176,196, +138,218,99,231,42,50,219,50,18,100,243,100,128,8,84,150,184,150,139,216, +68,188,191,239,20,44,107,44,66,44,52,84,21,136,46,222,46,112,92,112, +93,210,46,188,93,188,118,56,231,56,108,98,245,98,172,8,140,140,218,140, +171,208,134,182,207,235,16,60,109,60,138,186,213,236,70,14,30,134,117,134, +20,202,123,170,74,244,75,88,130,58,227,58,110,100,241,100,172,12,142,146, +216,146,179,213,18,70,91,70,20,154,91,122,60,12,60,232,27,222,156,92, +144,106,114,106,106,98,106,32,146,32,146,68,107,68,232,90,216,108,190,108, +178,98,178,32,222,32,222,68,179,68,98,140,231,140,86,178,243,178,140,178, +141,120,188,178,189,120,146,196,95,242,182,198,233,237,32,178,32,36,90,36, +91,174,60,72,60,158,48,196,36,214,15,236,68,188,99,228,116,16,147,42, +102,54,241,54,202,12,169,54,108,86,214,86,214,156,109,156,104,120,245,120, +142,244,143,54,176,246,177,54,102,208,143,156,238,222,208,196,181,157,72,16, +50,50,25,78,126,40,57,40,80,74,67,40,162,14,142,46,123,68,230,40, +147,40,188,68,169,40,104,62,68,106,179,106,88,84,186,84,171,132,22,134, +237,134,36,172,70,164,94,154,125,134,108,144,136,168,146,196,144,220,134,234, +116,236,101,236,32,202,58,198,90,184,125,158,32,232,74,220,114,200,141,184, +204,150,143,184,230,226,206,220,186,206,161,175,16,76,103,76,62,244,63,8, +16,170,46,114,63,82,96,138,63,102,154,12,191,42,244,54,120,54,120,152, +114,198,91,240,142,130,235,130,126,228,249,228,188,228,189,73,114,16,151,46, +234,58,48,58,48,78,48,150,40,200,21,240,74,138,221,138,54,228,241,228, +144,228,145,79,38,32,69,60,94,124,95,18,28,110,95,78,112,50,235,50, +124,102,223,102,168,102,169,14,114,118,141,138,20,146,231,146,24,206,58,198, +86,180,112,160,123,146,138,212,88,236,89,180,134,168,162,200,196,218,231,232, +200,168,173,205,22,60,71,100,22,210,67,138,86,244,87,8,106,84,241,84, +170,12,132,154,237,230,204,84,200,120,186,160,160,198,138,216,111,233,14,72, +81,72,14,152,89,122,58,6,58,236,25,228,144,8,167,30,104,40,225,40, +100,78,245,78,130,52,143,78,194,52,181,78,218,166,218,104,112,104,112,166, +219,166,112,134,219,134,90,196,231,196,84,224,245,224,162,224,163,105,24,54, +61,100,16,192,61,136,84,244,85,12,98,96,247,96,108,218,233,218,170,218, +171,15,24,58,55,102,16,200,63,140,78,246,79,10,102,94,245,94,94,234, +122,208,144,172,158,132,164,90,165,14,234,230,212,204,194,174,178,134,165,94, +194,34,225,71,16,74,101,74,62,242,63,12,16,170,44,128,63,92,98,140, +63,104,146,12,130,56,111,94,126,244,127,64,170,20,201,54,242,70,135,70, +232,116,135,116,230,166,135,166,244,216,135,216,182,216,183,71,64,14,38,64, +21,90,102,60,41,60,30,102,91,102,20,150,103,150,62,102,62,226,103,196, +146,14,122,76,103,104,131,246,122,246,123,74,168,26,201,56,134,74,239,74, +136,118,229,118,138,166,229,166,138,216,247,216,182,216,183,75,26,32,69,66, +22,230,34,220,50,208,64,208,82,214,108,226,130,230,239,228,12,112,56,112, +57,208,110,98,208,98,208,52,110,52,110,196,214,196,214,140,111,140,152,12, +137,53,26,38,131,38,32,60,121,60,14,84,131,84,76,84,77,10,18,150, +40,134,52,114,59,84,82,134,96,132,108,130,112,122,114,106,55,106,168,12, +150,56,139,74,234,48,155,48,156,74,172,98,194,114,241,132,132,132,158,122, +178,110,192,94,200,74,203,48,62,210,62,150,190,150,191,208,128,170,116,200, +98,220,72,232,31,240,134,204,219,239,38,160,38,26,104,26,76,64,94,80, +102,100,94,116,78,120,67,120,86,150,114,138,134,118,152,94,160,68,167,14, +230,152,212,140,192,122,176,92,163,54,56,184,205,184,20,226,235,226,128,226, +129,149,59,16,80,60,22,154,83,144,58,18,24,94,61,90,14,210,89,184, +88,30,148,30,136,64,118,92,83,118,100,48,143,112,166,30,222,30,210,60, +188,92,165,114,172,52,225,112,90,134,146,134,140,156,130,182,114,204,75,236, +102,152,145,216,164,132,222,132,212,166,196,194,174,216,143,238,172,132,180,158, +188,188,206,212,237,235,38,24,75,60,12,96,54,96,54,226,85,188,136,16, +171,44,90,52,239,52,210,120,210,82,114,82,114,120,211,120,102,146,200,146, +168,172,168,226,160,236,152,238,135,240,100,190,245,191,26,40,61,74,20,208, +73,138,126,12,96,74,59,116,100,246,101,64,158,14,191,48,116,62,239,62, +116,112,225,112,116,164,225,164,116,216,245,216,172,216,173,63,16,70,97,70, +18,156,93,118,60,10,60,234,27,224,212,94,212,26,118,26,118,94,213,94, +122,130,108,188,81,232,114,162,120,188,140,208,170,224,239,226,166,94,167,220, +166,152,229,153,12,70,97,70,16,160,93,122,62,12,62,236,29,226,120,24, +120,104,216,104,217,26,113,142,220,138,221,244,112,142,112,220,221,216,166,218, +167,9,204,146,204,74,60,74,60,146,205,146,60,108,205,108,16,186,241,186, +130,242,131,146,126,10,127,74,230,40,127,41,200,132,200,68,56,68,56,132, +201,132,56,100,201,100,120,68,121,8,228,38,121,38,16,166,237,166,128,244, +129,142,28,230,76,208,114,180,129,166,234,232,196,220,162,200,131,167,12,38, +93,38,18,108,89,108,14,202,95,176,56,38,57,186,110,24,233,24,166,34, +109,90,130,68,150,88,172,122,176,158,174,196,166,220,148,230,129,232,156,98, +134,122,114,138,95,152,106,116,133,158,174,136,152,156,128,180,99,200,172,124, +227,72,190,106,198,134,212,168,237,201,20,46,241,46,92,78,93,12,170,80, +171,12,62,86,62,140,200,140,201,86,44,162,44,222,213,222,212,164,213,244, +130,222,131,73,14,32,135,32,34,238,34,78,118,78,119,232,34,172,119,172, +34,212,119,212,62,32,62,90,60,116,56,134,51,144,90,32,90,122,92,132, +98,134,119,134,172,12,152,74,139,102,148,118,189,168,156,64,224,64,224,216, +212,230,196,234,181,235,28,186,28,44,70,44,71,178,28,156,71,156,90,28, +233,28,160,38,116,82,91,100,122,74,148,98,162,128,168,160,168,202,158,228, +138,236,123,236,148,102,122,130,89,154,106,116,131,148,164,138,138,162,114,180, +83,200,222,74,161,124,182,108,192,138,208,172,235,201,74,20,109,42,34,52, +227,52,178,18,149,52,46,80,215,80,22,108,237,108,126,52,118,82,94,120, +66,146,25,174,80,244,80,136,198,136,199,242,80,166,199,166,80,194,199,194, +80,224,199,225,34,66,21,128,66,10,66,126,60,166,48,200,23,236,110,204, +63,148,108,56,67,122,158,10,138,76,115,116,142,122,181,170,176,236,198,234, +216,222,220,208,224,66,143,67,36,26,77,56,18,88,57,120,28,232,67,140, +218,152,218,70,100,70,100,152,219,152,196,176,237,238,80,226,221,216,158,220, +159,13,66,18,103,54,18,66,241,66,186,14,139,66,102,184,119,222,118,114, +36,230,113,210,84,82,36,154,93,150,181,80,198,186,221,238,212,116,130,232, +209,214,180,80,134,158,187,153,34,26,73,58,26,134,83,84,134,12,112,56, +97,76,200,80,216,50,117,50,82,132,108,124,134,108,148,88,159,50,232,136, +204,126,180,104,155,70,64,244,64,158,190,158,191,242,64,218,191,219,30,24, +75,50,22,118,77,82,136,10,110,48,95,64,202,70,220,40,117,40,94,112, +122,96,140,76,152,54,157,40,228,116,204,104,178,84,153,56,64,206,64,128, +192,128,193,200,128,146,120,184,102,210,66,230,37,242,134,198,221,241,32,28, +73,52,28,118,79,82,136,10,114,46,97,66,202,72,218,42,117,42,86,124, +116,112,138,92,150,68,157,42,220,128,198,114,176,94,158,76,151,66,16,156, +237,156,118,128,80,190,225,232,42,238,86,230,126,216,160,184,179,157,34,30, +75,56,20,88,65,116,24,232,61,152,104,20,139,58,74,72,241,72,202,16, +165,72,132,184,151,218,146,114,84,222,145,206,120,88,84,152,127,148,208,190, +231,238,218,118,158,230,219,216,194,84,156,156,199,155,34,18,79,48,20,80, +63,110,30,230,67,146,120,12,90,66,125,108,168,12,142,62,171,102,222,12, +190,64,229,100,96,244,96,124,224,124,225,242,96,220,225,220,96,172,225,173, +10,36,106,36,66,80,66,212,60,226,48,228,27,228,14,156,93,118,156,10, +132,82,113,120,240,72,137,72,134,102,144,136,158,168,178,196,206,216,237,234, +96,236,126,222,152,204,172,180,190,142,198,104,201,73,22,100,127,74,82,14, +83,84,126,42,83,42,40,28,41,94,150,8,150,94,204,94,220,90,228,80, +233,66,208,28,151,58,166,142,207,178,168,110,66,174,193,166,114,96,60,134, +129,132,82,194,31,230,160,196,215,228,124,170,124,218,122,230,114,234,93,237, +76,16,52,76,17,126,54,244,55,72,100,34,218,34,166,90,166,222,164,230, +156,234,133,236,88,124,247,125,20,44,43,74,108,44,85,76,12,98,115,98, +62,246,63,12,16,186,38,158,63,110,102,158,63,118,118,30,226,30,174,94, +174,218,174,230,164,236,141,240,104,126,245,127,34,28,73,52,18,92,57,114, +32,226,65,152,140,14,175,38,92,82,92,50,224,50,225,82,140,70,169,86, +96,96,223,96,80,152,243,152,116,116,141,142,198,110,173,152,90,192,231,192, +158,242,159,153,44,28,202,28,130,88,130,210,126,224,116,234,91,236,18,118, +239,119,54,244,54,58,204,58,205,242,54,110,205,110,54,158,205,158,54,212, +205,212,116,14,97,59,38,22,75,52,22,86,63,112,30,226,71,146,90,40, +231,40,100,68,223,68,82,100,241,100,162,100,163,8,112,202,112,132,214,132, +215,200,160,148,160,172,154,192,140,210,120,222,98,232,77,238,172,200,235,237, +108,14,147,40,36,92,36,50,224,50,225,92,14,156,245,156,56,96,178,96, +132,132,132,228,114,238,85,243,18,82,141,82,138,22,50,22,51,82,124,42, +51,42,122,62,51,62,100,82,117,108,62,82,42,110,111,98,216,16,182,32, +149,46,220,44,184,64,155,72,232,72,188,94,145,102,124,110,145,122,38,162, +38,128,222,128,223,160,66,154,195,154,40,180,225,180,134,180,134,220,134,228, +130,232,122,236,105,238,32,230,95,200,166,198,225,231,18,76,103,76,62,244, +63,12,20,166,40,138,63,86,96,140,63,96,154,14,187,44,122,88,122,56, +236,56,237,86,134,98,223,98,112,140,247,140,146,174,109,222,208,178,243,220, +178,140,178,216,176,228,172,234,162,236,149,239,92,94,92,32,34,32,34,94, +93,94,20,224,103,190,68,94,69,204,34,120,35,218,102,140,69,140,156,12, +185,36,120,84,120,52,232,52,233,84,134,98,221,98,124,142,239,142,176,142, +176,240,147,246,146,174,103,228,202,176,237,225,110,16,147,40,38,94,38,52, +224,52,225,90,66,98,197,98,26,146,237,146,92,174,33,228,174,178,231,224, +134,146,134,242,103,249,90,54,32,162,99,150,20,220,97,196,60,14,22,94, +71,88,146,12,179,42,114,86,114,54,228,54,229,86,128,100,217,100,108,140, +239,140,140,174,105,226,200,172,235,218,174,140,174,240,145,245,74,20,109,54, +194,132,194,70,66,70,66,132,195,132,56,164,29,222,114,150,147,184,192,160, +231,210,94,162,94,220,94,230,106,234,154,234,172,226,185,202,180,10,137,71, +98,62,28,158,95,152,70,16,18,94,75,92,14,212,87,194,130,14,124,144, +108,192,79,232,156,162,127,112,188,14,184,116,164,186,131,238,236,228,202,162, +185,103,74,12,50,62,21,102,40,96,124,96,125,230,42,148,125,148,32,204, +125,204,90,96,112,48,59,48,166,244,166,32,222,32,196,108,216,128,230,152, +232,174,226,194,210,202,189,201,44,52,219,52,20,98,241,98,130,98,131,8, +66,144,50,198,23,236,58,172,78,196,98,212,122,222,140,222,241,226,130,116, +131,222,216,160,131,161,28,42,229,42,46,74,213,74,20,110,239,110,128,10, +116,62,100,100,72,140,23,178,238,168,202,150,180,132,163,110,78,144,183,144, +54,182,213,182,130,144,120,192,102,214,76,230,45,242,140,200,219,239,12,74, +87,74,14,148,81,118,50,12,50,238,23,228,98,46,229,46,108,76,215,76, +96,102,235,102,164,14,152,66,136,108,108,138,85,156,236,152,206,136,186,118, +177,102,124,140,191,140,98,176,223,176,160,140,154,178,144,202,124,222,99,236, +228,232,153,183,104,22,56,34,23,38,16,88,111,88,64,244,65,32,18,184, +65,104,106,152,65,112,96,224,247,224,138,224,138,30,216,30,217,224,138,90, +217,90,138,154,217,155,198,100,198,32,62,32,62,100,199,100,70,140,50,198, +21,232,60,172,74,196,100,216,124,224,138,224,241,230,130,224,131,100,130,156, +215,157,106,10,141,40,28,50,231,50,90,68,74,104,45,144,122,132,77,98, +188,68,162,116,143,142,222,140,171,102,14,180,243,180,128,248,129,153,54,18, +83,50,20,68,107,68,52,68,52,140,42,190,17,234,52,118,98,118,98,170, +92,218,82,232,65,236,156,14,128,66,111,94,238,56,135,56,152,76,134,116, +121,134,228,104,141,104,112,158,241,158,176,104,174,164,164,184,148,208,103,240, +236,236,212,216,192,192,175,163,46,12,83,44,12,72,90,72,68,108,40,138, +19,158,62,244,63,114,108,154,65,114,92,224,249,224,134,224,134,26,212,26, +213,224,134,152,213,152,134,90,213,91,42,24,81,62,12,100,58,100,58,224, +99,176,92,228,247,228,130,228,130,34,212,34,213,228,130,94,213,94,130,160, +213,161,32,242,32,34,86,34,62,98,78,116,88,134,92,154,88,168,74,176, +57,180,90,220,239,220,124,220,124,32,208,32,209,220,124,92,209,92,124,152, +209,153,100,56,34,168,109,156,66,16,22,102,75,98,20,228,105,202,100,226, +243,226,132,226,132,34,210,34,211,226,132,98,211,98,132,156,211,157,74,12, +44,64,21,88,120,56,51,56,34,98,111,98,22,148,115,148,70,98,70,224, +115,194,134,240,134,132,226,132,227,238,134,216,227,216,174,132,175,12,174,68, +245,69,78,12,44,48,23,66,126,34,59,34,82,34,97,54,160,12,144,34, +123,54,234,34,147,34,188,52,177,34,196,124,196,60,58,60,58,124,197,124, +58,82,197,82,58,102,197,102,12,144,243,144,18,184,52,168,76,150,99,124, +238,180,212,172,192,160,175,144,166,176,215,206,158,156,80,200,193,194,116,148, +76,176,127,174,92,210,43,238,154,210,207,236,130,198,130,226,126,234,120,238, +107,239,26,196,26,36,60,36,61,180,26,160,61,160,80,88,159,70,96,22, +97,82,128,8,129,74,154,40,129,40,176,8,176,68,180,78,188,86,224,86, +232,80,239,62,228,24,177,52,144,84,112,114,83,136,78,240,94,220,104,196, +106,184,106,134,214,134,214,238,193,242,106,164,215,164,214,194,107,194,156,228, +157,134,158,134,182,106,121,107,12,34,117,34,28,236,28,78,108,78,109,234, +28,212,109,212,28,176,109,176,40,152,50,132,54,110,54,94,55,34,80,34, +80,120,82,130,88,134,109,136,166,12,195,40,126,54,241,54,162,70,131,136, +176,120,155,88,216,70,189,132,236,134,209,88,122,166,247,166,184,244,185,145, +198,80,198,24,60,24,60,80,199,80,60,50,199,50,12,104,243,104,116,242, +117,104,26,214,139,194,54,104,55,208,54,138,117,138,54,168,117,168,130,138, +212,138,196,170,168,208,135,230,230,230,198,212,170,186,141,139,212,78,212,26, +44,26,44,78,213,78,98,78,99,26,154,78,155,26,102,240,103,92,152,242, +153,92,28,120,103,120,34,156,103,156,18,194,103,194,228,118,153,118,216,156, +153,156,234,194,153,195,76,14,105,38,26,48,235,48,182,12,157,48,206,158, +206,78,60,78,60,158,207,158,60,130,207,130,116,48,114,82,106,98,92,108, +83,110,150,48,150,92,152,100,158,104,185,104,20,184,241,184,76,194,115,220, +180,158,180,238,147,245,24,34,67,66,20,230,38,218,50,214,62,214,82,216, +112,226,124,230,239,232,16,112,54,112,55,214,82,44,233,44,104,16,135,38, +198,14,175,44,216,148,216,74,94,74,94,148,217,148,94,122,217,122,140,44, +138,66,136,84,128,96,113,108,168,44,168,104,197,102,76,172,241,172,108,182, +133,202,192,148,192,212,161,221,30,226,30,50,90,50,91,214,30,118,91,118, +30,188,91,188,158,8,138,56,109,110,244,70,133,70,152,246,153,70,226,130, +153,130,234,180,153,181,24,68,235,68,120,18,108,78,92,124,74,156,54,184, +23,214,212,138,93,138,50,224,245,224,146,224,147,139,90,12,64,64,17,130, +62,244,63,70,92,68,243,68,158,10,142,80,122,138,87,194,134,130,231,130, +100,224,247,224,180,224,181,131,20,70,109,70,68,246,69,10,18,168,69,98, +106,132,69,96,156,10,132,72,111,102,246,72,133,72,160,246,161,72,230,124, +161,124,238,178,161,179,62,14,40,74,15,116,44,244,45,64,68,68,147,68, +80,216,80,126,132,126,133,210,80,188,133,188,108,126,109,12,190,14,172,78, +153,108,238,72,175,72,134,236,168,212,192,180,204,146,210,114,213,72,164,116, +172,152,186,176,204,204,241,235,80,12,50,78,23,114,60,244,61,60,152,10, +122,80,93,116,244,70,127,70,154,246,155,70,230,128,155,128,240,182,155,183, +38,170,219,170,18,226,241,226,130,226,131,18,74,40,48,112,25,144,104,130, +63,76,192,34,172,102,153,138,228,136,181,77,118,16,153,38,234,52,44,52, +44,98,44,144,40,184,32,218,17,244,72,178,223,178,54,228,241,228,144,228, +145,66,102,80,82,130,67,154,126,142,91,110,196,78,163,150,224,144,183,111, +36,30,217,30,16,100,239,100,130,100,130,234,99,241,16,32,239,32,90,32, +90,134,80,168,60,198,21,224,172,230,173,33,18,46,229,46,98,46,98,82, +98,118,92,158,78,190,56,216,27,236,156,46,156,208,158,224,170,232,212,232, +224,222,235,197,16,36,241,36,64,62,50,138,206,138,200,212,190,224,170,230, +155,230,126,138,127,36,126,84,207,85,14,88,243,88,80,16,81,238,180,236, +181,12,80,206,181,207,18,108,241,108,24,232,48,210,66,178,74,140,75,22, +134,228,135,28,198,244,199,19,32,36,227,36,24,168,62,144,98,112,130,74, +155,36,126,204,127,80,154,94,225,158,24,224,237,225,24,36,225,36,16,220, +241,220,196,172,196,74,58,74,58,172,197,172,58,122,197,123,44,30,186,30, +126,76,126,204,103,206,234,184,190,158,150,116,127,78,216,74,159,122,26,92, +96,92,90,122,74,150,48,174,25,190,22,222,237,223,24,30,227,30,188,102, +188,60,60,60,60,102,189,102,36,238,36,134,216,134,216,230,183,236,82,146, +111,170,58,182,189,182,164,146,133,182,126,238,127,183,28,30,235,30,128,108, +129,30,24,96,60,80,96,62,129,38,148,56,235,94,76,100,46,184,123,222, +18,142,110,142,98,182,72,212,31,240,134,122,216,122,182,154,182,240,153,244, +120,174,243,175,26,32,225,32,24,126,231,126,16,228,241,228,124,228,125,32, +98,98,98,60,40,60,40,98,99,98,214,98,214,60,154,60,154,98,213,98, +96,198,96,156,38,156,38,198,97,198,214,196,214,156,156,156,156,196,213,197, +124,242,125,15,196,110,196,28,54,28,54,110,197,110,54,68,197,68,36,238, +36,144,216,144,216,232,181,242,160,162,189,204,66,196,175,186,122,28,123,191, +126,16,126,138,120,172,102,202,63,237,66,26,66,196,72,216,88,220,192,220, +216,204,225,168,202,60,67,131,202,20,136,36,41,46,20,140,235,122,124,38, +124,210,126,224,138,232,204,232,214,224,223,203,196,18,122,36,45,48,14,116, +235,116,26,236,60,218,94,186,116,150,126,116,127,36,230,234,202,216,172,194, +146,158,127,117,52,36,207,108,186,22,124,72,88,92,41,112,172,126,144,166, +112,196,76,216,25,236,80,126,100,154,126,180,154,200,200,220,233,231,204,20, +148,32,98,38,58,40,58,132,50,172,38,206,23,232,58,82,237,82,234,194, +228,216,210,232,126,232,112,228,104,218,104,120,192,120,192,166,188,180,184,190, +163,195,202,24,132,38,46,42,46,230,111,182,46,112,221,112,112,204,145,236, +228,208,226,224,218,232,210,232,198,226,168,196,148,162,138,124,134,84,135,39, +40,248,40,52,212,52,213,246,40,224,213,224,76,86,132,142,175,194,172,78, +124,146,71,198,108,8,93,53,46,28,46,164,38,204,17,240,198,18,198,214, +200,228,210,230,226,230,234,224,241,206,150,86,177,120,160,46,74,114,167,108, +126,16,76,70,131,68,82,238,82,138,158,138,158,232,135,238,82,164,159,164, +82,192,159,193,58,14,58,104,52,168,38,212,21,242,18,86,98,82,98,204, +100,218,112,228,124,228,222,228,236,216,243,202,140,16,161,46,114,60,239,60, +208,16,187,60,214,196,214,90,136,90,136,196,215,196,136,126,213,126,136,160, +215,160,178,60,173,91,60,14,44,48,19,82,112,56,39,56,10,146,127,146, +68,234,84,232,94,226,98,220,102,94,42,94,38,202,123,202,60,110,77,130, +58,164,77,184,156,12,187,42,122,54,241,54,194,86,229,124,174,64,128,122, +219,114,142,142,142,196,134,220,115,242,174,236,175,142,206,140,206,216,208,230, +214,232,230,232,243,215,216,72,216,30,40,30,40,72,217,72,100,72,101,30, +158,72,159,30,108,6,95,30,46,104,213,104,16,134,241,134,128,134,129,80, +40,174,217,174,76,146,107,174,174,144,147,174,24,204,233,204,130,246,131,175, +32,24,89,40,110,16,110,32,108,54,102,68,88,78,74,86,60,90,44,94, +17,96,24,64,105,60,146,16,146,76,148,84,156,90,212,90,226,80,233,64, +212,28,147,40,206,68,147,54,18,118,117,118,30,142,117,142,80,94,81,142, +143,126,138,126,237,126,136,162,214,162,196,194,168,216,127,238,148,162,162,188, +186,212,212,228,237,234,178,162,179,98,120,192,120,164,38,164,38,192,121,192, +16,232,127,220,52,200,63,226,108,198,93,225,104,100,141,149,42,30,182,30, +128,66,128,202,103,208,92,166,92,82,40,82,40,166,93,166,148,78,208,78, +194,124,174,162,149,192,154,108,223,186,18,224,239,225,34,34,180,34,172,56, +232,56,228,76,224,84,220,88,201,92,22,104,48,94,68,80,86,56,95,34, +178,146,178,72,88,72,88,146,179,146,88,96,179,96,88,120,179,120,54,118, +54,170,116,170,117,246,28,194,117,194,38,242,54,234,64,224,70,214,72,206, +75,194,212,114,212,168,152,168,153,246,152,194,216,194,217,239,14,114,190,70, +186,148,180,162,168,164,153,164,80,24,80,190,80,210,90,218,98,220,204,220, +222,214,230,202,235,183,32,238,32,130,110,130,111,236,32,212,111,212,68,14, +69,130,132,68,69,68,158,14,158,210,160,224,168,230,176,230,218,230,230,218, +239,191,38,30,221,30,16,96,241,96,90,96,90,132,84,168,74,192,56,214, +29,232,170,240,171,97,26,142,231,142,14,184,243,184,126,246,127,12,76,142, +77,32,18,80,77,80,174,142,175,30,174,78,241,79,28,50,235,50,40,130, +40,88,216,88,217,130,128,88,129,10,62,122,178,122,132,154,132,216,128,234, +118,238,93,240,20,174,241,175,34,42,231,42,66,60,97,88,196,60,167,92, +16,108,245,108,130,108,131,8,56,248,56,140,208,140,209,246,56,226,209,226, +168,200,168,166,96,166,96,200,169,201,12,74,91,74,32,228,32,128,74,128, +75,222,32,198,75,198,52,128,53,14,106,240,106,26,146,26,146,84,107,84, +146,130,107,130,146,178,107,178,168,26,218,26,218,88,169,88,166,124,220,124, +210,164,198,190,180,210,147,234,170,124,178,152,186,176,204,202,237,231,238,38, +52,38,52,162,40,204,25,238,152,60,146,118,140,150,118,190,94,218,69,238, +234,232,210,216,190,194,166,160,147,115,245,26,18,228,36,198,46,162,48,128, +48,24,245,24,70,76,233,76,140,40,88,136,227,136,62,178,247,178,156,240, +157,95,238,26,46,26,46,146,40,182,21,230,70,72,227,72,62,112,243,112, +116,112,117,40,178,112,179,40,94,242,94,144,198,144,199,240,94,182,199,182, +94,220,199,221,234,30,42,30,42,156,34,198,23,230,66,72,233,72,174,44, +203,58,148,40,130,82,106,100,84,114,63,122,238,120,210,112,182,100,164,84, +153,72,88,212,88,126,212,126,213,210,88,160,213,160,88,194,213,194,148,246, +149,127,238,28,44,28,44,152,34,208,19,236,74,50,97,80,56,94,149,94, +142,48,117,94,72,116,72,172,140,172,141,122,106,94,106,134,102,178,96,200, +82,218,65,234,186,46,174,82,157,120,214,124,226,94,169,94,184,124,180,164, +172,190,152,216,123,238,236,236,210,212,196,186,183,155,240,32,40,32,40,142, +36,182,17,232,56,82,157,82,54,174,159,174,92,188,55,232,116,186,141,216, +82,174,83,48,132,174,133,48,82,114,133,114,82,142,133,142,228,58,200,66, +172,68,172,168,162,210,145,242,172,116,247,116,210,244,211,117,238,26,46,26, +46,158,38,196,21,238,70,68,229,68,176,40,205,56,146,36,136,76,120,92, +96,104,75,108,228,106,208,102,182,94,164,80,153,68,60,124,241,124,84,242, +84,152,218,152,219,242,84,224,219,224,146,124,135,152,122,224,123,152,180,224, +181,152,122,176,181,176,125,200,122,200,181,201,236,34,50,34,50,160,42,196, +25,230,110,46,88,70,67,92,92,146,93,68,148,46,122,78,107,94,122,150, +123,78,172,46,195,62,136,72,237,72,136,94,229,94,136,118,229,118,136,142, +241,142,178,142,179,72,90,212,90,162,208,162,209,210,148,178,140,202,130,216, +116,226,92,236,73,240,162,204,231,239,220,32,40,32,40,226,231,227,224,32, +32,32,32,222,231,222,192,164,192,86,84,86,84,164,193,165,230,30,34,30, +34,224,239,224,54,74,143,74,96,42,68,122,141,122,56,164,143,152,104,90, +105,210,158,90,202,86,198,178,198,192,204,196,212,196,224,188,231,168,172,42, +170,110,160,154,148,178,129,203,224,30,32,30,32,224,233,224,48,110,235,110, +200,86,200,60,74,60,74,86,201,86,134,110,135,40,82,186,82,136,194,136, +195,182,136,148,128,174,116,188,94,200,65,208,146,176,213,211,226,26,36,26, +36,226,235,226,120,34,153,54,52,188,68,158,74,128,76,112,76,62,198,62, +198,92,77,92,90,208,90,120,208,120,208,202,187,208,90,156,209,156,128,190, +129,120,166,188,167,121,116,36,32,36,32,208,121,208,106,152,106,88,56,88, +56,152,107,152,82,208,83,152,136,40,243,40,140,68,235,68,120,96,251,96, +140,200,140,124,226,124,227,200,182,142,180,182,174,200,158,218,121,238,194,204, +241,238,184,12,185,96,82,88,83,37,26,62,129,62,12,108,145,108,78,108, +79,12,26,154,129,154,16,218,141,194,80,120,81,204,166,242,167,12,184,92, +239,155,44,246,44,86,208,86,209,244,44,224,209,224,44,132,154,132,154,180, +45,180,116,84,117,10,116,44,225,45,150,186,151,42,212,14,212,212,210,224, +202,230,175,231,26,46,88,132,131,202,122,20,98,108,70,162,25,216,168,174, +169,52,220,14,220,206,218,222,212,228,187,233,70,18,46,78,21,116,92,222, +108,222,124,216,134,192,144,64,53,64,26,176,60,134,76,98,85,64,44,216, +70,188,92,154,106,116,117,64,180,186,181,44,220,14,220,208,218,224,206,232, +183,235,24,40,112,40,88,78,64,100,27,126,144,124,83,82,26,148,131,148, +18,226,141,202,78,148,79,212,170,178,171,34,222,14,222,234,195,243,26,48, +141,48,86,12,78,58,60,82,38,98,23,108,146,100,81,54,56,104,119,104, +22,138,145,138,66,138,58,174,122,174,120,216,114,228,104,232,77,236,178,182, +179,36,224,14,224,236,191,243,38,32,38,76,142,76,143,32,90,76,91,12, +90,86,60,134,29,166,30,236,74,212,114,176,140,122,69,122,72,154,103,186, +178,184,179,50,220,14,220,232,193,241,38,26,38,80,140,80,141,28,86,80, +87,14,32,112,130,112,130,156,40,156,40,228,147,194,174,176,175,56,218,10, +218,236,181,243,18,50,149,50,84,244,85,10,134,136,134,84,34,84,34,136, +135,136,20,210,54,180,85,138,136,196,85,154,178,180,179,44,226,10,226,234, +185,225,28,46,145,46,88,12,80,56,70,72,56,86,43,94,96,64,135,94, +16,112,157,112,126,112,126,228,97,238,92,192,92,140,36,140,36,192,93,192, +176,174,177,40,220,12,220,236,189,243,46,36,37,80,134,44,115,74,88,16, +88,60,80,82,68,100,27,126,136,122,83,78,46,142,29,186,134,144,113,174, +86,118,80,172,70,196,52,218,25,238,138,226,79,176,168,182,169,46,218,14, +218,236,185,243,76,20,107,40,34,90,34,52,152,52,153,88,64,74,44,128, +21,164,20,234,48,210,66,184,76,154,82,108,53,108,148,200,104,226,104,102, +140,102,140,156,136,166,130,170,121,172,180,184,181,48,220,18,220,238,177,227, +22,44,173,44,76,66,77,12,124,66,125,10,22,232,34,204,42,174,44,154, +44,84,84,84,84,218,61,226,44,120,85,120,84,158,45,158,90,236,104,210, +112,184,114,150,114,84,154,84,154,232,133,238,114,120,155,120,114,158,155,158, +190,182,191,46,226,12,226,238,191,229,18,28,159,28,146,100,146,56,34,56, +34,100,147,100,72,100,73,28,108,100,109,28,38,130,143,130,18,162,161,162, +60,182,25,218,118,184,151,220,90,162,90,238,69,242,182,178,183,38,224,12, +224,236,189,227,168,24,40,24,40,144,36,182,19,228,62,42,83,72,54,90, +117,90,112,40,93,90,112,120,113,188,64,118,64,174,113,168,88,90,88,176, +76,206,53,238,142,42,129,102,132,92,168,92,159,120,144,128,144,142,138,180, +124,210,101,236,174,222,141,170,190,176,191,42,228,10,228,230,191,225,72,14, +42,76,25,102,48,182,49,66,98,20,121,48,66,58,157,58,62,94,149,94, +60,130,149,130,60,168,159,168,104,166,105,58,49,194,40,208,23,238,70,196, +85,232,106,194,119,228,140,190,161,228,180,190,181,42,224,8,224,238,195,231, +20,40,169,40,76,48,77,10,124,52,125,10,64,60,40,100,23,122,92,60, +115,76,48,162,49,86,68,82,161,82,62,106,155,106,62,130,153,130,62,152, +169,152,34,176,138,176,104,210,68,228,27,236,58,188,153,230,184,188,185,48, +228,12,228,232,187,226,108,152,109,83,138,100,138,32,44,32,44,100,139,100, +44,54,139,54,44,76,139,76,84,10,75,32,150,168,150,118,30,118,30,168, +149,168,30,142,151,142,88,168,89,118,16,190,165,190,68,190,68,204,60,218, +48,232,29,242,118,246,119,190,182,176,183,44,226,10,226,236,187,227,38,238, +38,24,216,24,216,230,177,237,38,244,38,32,218,32,218,236,181,242,82,52, +115,84,58,96,199,96,170,52,139,96,112,106,139,128,68,140,191,140,90,140, +90,186,179,187,102,18,62,86,21,130,74,240,75,67,84,14,50,74,19,118, +62,244,63,54,100,42,249,42,194,42,194,236,155,245,80,20,46,90,21,126, +56,242,57,72,78,232,102,208,114,180,118,142,118,34,190,34,190,210,194,224, +202,230,224,230,232,226,236,210,237,197,92,12,52,92,21,126,68,244,69,62, +98,80,228,80,220,228,181,238,158,12,158,84,154,134,142,178,126,208,97,239, +82,16,48,84,21,120,64,244,65,54,96,50,237,50,106,130,227,130,84,220, +247,221,80,14,46,82,19,118,58,246,59,58,150,12,114,74,79,114,244,56, +125,56,112,112,208,112,174,146,148,174,130,194,120,210,120,220,126,228,138,232, +152,234,206,234,224,228,236,218,241,191,84,14,44,90,21,124,58,244,59,62, +172,14,132,86,83,146,202,72,98,218,225,210,196,152,239,237,80,10,48,82, +21,116,58,244,59,60,120,80,103,148,104,40,220,40,220,196,212,220,192,228, +173,230,164,40,164,106,156,154,138,196,89,235,74,14,40,90,21,118,56,246, +57,54,240,36,102,36,102,226,247,226,210,64,178,138,127,192,130,76,227,187, +74,14,40,88,17,124,52,244,53,62,104,30,104,230,157,204,156,104,105,104, +178,18,178,206,182,224,190,230,220,230,232,222,241,198,234,72,179,121,80,14, +42,90,19,122,54,242,55,66,96,32,233,32,122,58,104,112,247,112,82,214, +124,186,158,152,191,112,194,32,194,234,167,243,68,14,38,90,17,126,52,244, +53,58,84,34,237,34,166,204,106,230,125,34,136,128,165,168,240,196,234,218, +226,228,212,232,200,230,186,224,192,86,121,87,76,14,44,86,23,116,56,240, +57,60,132,16,114,74,95,112,82,140,245,140,228,58,121,58,162,242,163,59, +84,14,46,88,15,126,60,246,61,60,84,118,245,118,130,8,130,234,173,200, +218,24,163,94,236,234,210,210,190,182,174,150,167,119,74,14,42,80,15,118, +54,244,55,56,156,8,132,56,106,88,77,114,242,106,216,92,188,68,151,20, +158,178,176,178,188,174,194,164,194,112,120,112,120,208,122,224,134,234,202,234, +216,226,225,205,82,14,44,86,19,116,58,242,59,62,136,16,173,54,86,70, +237,70,80,232,100,222,120,198,126,168,126,152,126,110,190,110,190,206,192,222, +202,230,222,230,232,224,236,212,239,201,78,12,46,90,23,128,58,244,59,60, +144,16,179,52,98,116,98,64,228,64,229,116,84,214,245,215,78,14,46,84, +21,118,58,242,59,60,106,32,219,32,90,86,235,86,80,142,243,142,158,100, +118,182,231,230,92,234,126,226,160,212,186,184,196,160,203,143,74,12,42,82, +17,120,54,240,55,56,78,110,247,110,154,110,155,10,154,54,227,54,152,240, +153,126,176,152,225,199,72,10,40,80,19,114,54,244,55,52,94,196,95,64, +160,12,136,80,115,112,242,70,141,70,100,232,138,212,166,188,186,158,200,112, +207,70,144,100,160,156,188,196,241,235,76,16,40,84,19,116,56,242,57,54, +124,30,97,110,228,72,111,72,80,134,239,134,164,14,164,80,160,138,146,176, +126,204,89,236,234,236,210,216,188,190,174,162,161,135,74,12,44,82,23,114, +54,248,55,58,134,10,110,68,81,104,180,234,200,234,214,230,224,220,224,52, +119,52,180,182,180,106,112,106,112,182,181,183,72,12,40,88,15,124,54,246, +55,58,138,8,114,62,91,92,84,156,140,128,188,84,210,44,123,44,126,74, +168,110,200,134,241,152,138,160,197,186,126,204,199,241,78,14,44,80,15,118, +54,244,55,62,140,16,171,52,96,104,96,64,226,64,227,104,134,96,134,214, +136,226,146,234,216,234,232,226,236,214,241,196,220,120,135,167,78,12,40,86, +17,116,56,246,57,58,76,236,94,210,106,176,110,138,110,30,210,30,210,92, +111,92,148,110,148,206,152,220,158,230,172,232,206,232,222,226,232,214,235,202, +216,138,149,171,74,14,42,90,21,122,54,242,55,62,78,72,148,68,146,204, +142,216,130,224,119,228,110,16,110,94,106,152,96,198,77,234,182,236,182,56, +226,56,227,230,182,206,227,207,82,16,42,92,23,118,60,248,61,60,92,58, +247,58,98,110,237,110,168,110,169,8,118,246,118,152,220,152,221,244,118,218, +221,219,78,16,46,84,23,120,58,242,59,58,90,36,241,36,82,192,247,176, +204,240,205,36,120,36,121,188,120,86,205,86,120,132,205,133,84,18,50,88, +27,118,62,244,63,66,86,60,245,60,164,14,134,84,89,142,126,244,126,102, +210,102,210,236,187,242,126,142,211,142,126,180,211,181,80,16,46,82,19,118, +60,246,61,56,86,52,237,52,160,14,140,68,112,96,85,116,236,114,210,100, +186,76,173,52,118,110,203,110,84,146,237,146,140,146,134,180,206,180,202,210, +196,226,184,234,149,237,70,14,36,88,13,122,48,244,49,60,210,100,210,30, +102,30,102,100,211,100,112,120,112,156,106,192,94,216,75,238,152,234,153,122, +198,120,198,212,200,224,210,232,222,232,234,224,236,212,239,199,72,14,40,84, +17,118,50,246,51,62,120,28,100,74,89,94,220,66,105,66,82,118,233,118, +156,248,157,8,76,212,102,194,128,166,157,124,236,210,216,196,194,174,176,148, +157,121,78,14,42,82,19,112,54,240,55,60,138,22,83,102,174,20,190,54, +210,78,239,98,110,240,110,98,202,98,202,236,177,240,110,136,203,136,110,176, +203,177,74,14,38,82,19,108,50,244,51,62,82,56,111,98,132,12,132,138, +126,174,110,208,79,236,72,162,133,130,174,10,174,218,182,230,222,230,232,222, +241,194,224,54,193,100,230,166,175,127,78,16,44,88,19,122,58,244,59,58, +140,16,173,40,86,52,239,52,116,70,134,88,150,102,172,116,208,128,239,136, +84,142,122,130,144,118,170,98,192,72,203,52,96,238,120,224,130,210,134,186, +139,146,196,242,197,145,72,16,40,88,17,118,52,246,53,62,138,16,175,44, +82,54,239,54,138,76,95,120,184,76,225,112,126,124,140,154,152,172,172,196, +198,216,237,238,192,122,176,160,154,194,126,216,89,237,74,12,46,74,17,118, +56,244,57,52,96,96,96,52,222,52,223,96,160,10,148,66,134,104,110,140, +81,174,164,198,124,232,125,122,160,98,170,134,184,170,208,202,237,226,222,120, +183,165,78,12,42,86,21,116,54,246,55,62,157,14,182,32,235,86,158,14, +92,76,219,70,120,94,85,158,234,130,103,130,80,180,245,180,162,246,163,91, +74,12,46,78,17,118,56,246,57,54,96,50,237,50,100,90,227,90,82,126, +247,126,84,224,120,188,138,154,152,108,158,58,163,8,138,164,239,164,146,184, +169,212,204,140,204,240,175,247,78,16,42,84,21,112,58,244,59,56,96,36, +241,36,244,120,108,120,108,168,102,206,81,238,100,62,125,92,230,58,205,94, +146,120,147,36,184,120,185,37,68,14,36,86,17,114,50,248,51,58,80,32, +249,32,92,240,92,76,144,76,144,232,121,238,110,116,125,160,174,240,174,78, +230,78,230,230,205,234,192,110,211,159,82,12,48,82,23,116,58,242,59,66, +82,72,239,72,188,24,219,50,158,12,158,236,125,240,96,98,131,136,82,198, +159,144,230,212,196,176,176,134,159,92,226,100,179,139,76,14,46,80,19,118, +60,246,61,52,222,126,222,24,106,24,106,126,223,126,106,76,223,76,92,170, +233,170,82,224,245,224,164,224,165,25,78,12,40,88,19,118,54,248,55,62, +212,88,212,28,108,28,108,88,213,88,92,122,233,122,80,168,243,168,160,122, +158,154,148,186,130,212,114,224,89,238,238,238,220,230,196,212,178,194,163,169, +80,18,46,82,21,112,58,242,59,62,222,118,222,44,102,44,102,118,223,118, +102,80,223,80,162,118,163,12,82,140,245,140,138,140,126,178,212,178,206,218, +200,228,194,234,184,234,165,237,78,12,44,84,17,120,60,244,61,50,144,54, +187,84,102,30,210,30,171,72,110,244,110,90,230,90,230,240,205,246,168,234, +169,90,110,136,231,136,110,180,231,181,78,12,46,88,17,130,60,248,61,54, +184,36,237,80,158,10,104,78,219,66,126,88,95,148,224,114,115,114,84,164, +241,164,162,114,158,174,142,208,116,230,95,242,240,242,208,224,184,202,163,165, +70,10,38,90,15,120,50,246,51,60,86,46,229,46,94,76,221,76,74,108, +241,108,152,10,144,62,136,94,120,124,94,150,67,170,174,108,192,134,212,152, +239,168,108,160,199,160,86,196,229,196,154,246,155,129,74,14,38,88,19,114, +52,248,53,60,94,44,231,44,102,74,221,74,78,108,245,108,160,108,161,8, +108,248,108,138,210,138,210,242,181,248,108,168,211,168,108,198,211,199,80,16, +48,82,21,118,60,244,61,56,92,52,241,52,134,86,135,14,198,86,199,8, +84,112,247,112,164,74,136,130,112,158,85,180,124,246,124,154,214,154,215,242, +124,214,215,215,78,12,42,88,19,118,56,244,57,60,136,244,137,12,182,244, +183,12,76,62,137,62,78,120,137,120,74,182,137,182,244,62,183,62,238,120, +183,120,246,182,183,183,78,12,44,78,21,110,56,246,57,58,214,148,214,72, +100,72,100,148,215,148,100,110,215,110,152,72,153,8,152,36,233,36,76,186, +245,186,158,244,159,149,68,14,36,88,17,122,52,246,53,54,86,200,87,62, +150,8,124,54,107,74,106,122,138,110,166,90,192,66,206,40,135,40,142,60, +164,84,190,100,245,120,192,124,219,148,104,166,239,166,166,126,162,178,148,208, +105,238,228,238,161,187,72,14,36,92,15,120,52,246,53,58,218,112,218,24, +102,24,102,112,219,112,78,144,241,144,158,244,159,24,102,68,219,68,84,220, +114,202,136,174,159,148,240,216,216,204,190,182,159,145,76,14,40,88,17,120, +54,244,55,62,214,16,176,26,107,30,88,68,243,68,160,116,161,28,88,126, +122,106,159,70,238,122,202,104,180,82,165,68,76,156,247,156,158,130,120,188, +239,232,92,240,124,232,152,220,182,192,203,157,72,12,40,82,19,116,54,246, +55,52,226,140,226,40,100,40,100,140,227,140,100,90,227,90,152,8,139,40, +162,40,160,96,146,134,136,152,107,172,80,184,247,184,172,246,173,153,76,14, +44,86,19,118,56,246,57,58,80,234,98,204,104,166,108,118,108,28,228,28, +228,236,197,242,126,72,207,72,124,114,213,114,166,114,167,44,196,194,196,146, +136,146,136,194,197,195,74,10,40,86,19,118,52,244,53,58,146,12,179,36, +92,82,92,48,232,48,233,82,116,242,116,92,210,92,210,130,117,130,220,238, +220,170,117,170,116,216,221,217,72,14,42,88,19,124,52,246,53,64,142,14, +179,40,98,92,98,52,228,52,229,92,138,82,95,130,176,84,223,126,100,154, +227,154,84,224,247,224,160,224,161,155,74,16,40,90,19,118,54,244,55,58, +76,228,96,202,106,166,110,128,110,30,220,30,220,78,111,78,248,124,111,124, +130,244,130,166,220,166,221,242,130,224,221,224,174,166,175,91,76,14,44,90, +19,122,56,246,57,64,90,42,233,42,160,8,161,70,76,84,249,84,122,110, +123,56,200,108,201,54,104,196,104,124,216,124,217,194,160,142,156,178,144,200, +124,220,89,236,176,190,239,235,76,16,42,90,17,128,54,244,55,66,242,34, +96,34,96,228,247,228,220,122,220,58,132,58,132,122,221,122,132,90,221,90, +112,148,243,148,174,126,144,172,225,202,124,208,150,200,180,186,196,168,209,149, +74,12,44,82,19,118,56,246,57,52,108,12,108,110,151,86,154,50,109,50, +176,8,176,90,180,100,186,108,222,108,234,96,239,78,226,32,177,60,114,244, +114,144,212,144,213,242,114,184,213,184,114,226,213,226,156,112,147,145,82,14, +48,82,19,116,62,242,63,56,224,104,224,26,114,26,114,104,225,104,114,68, +225,68,136,112,110,144,85,166,200,234,220,232,230,226,234,206,236,136,117,136, +108,170,108,216,191,216,172,150,135,200,196,194,165,163,78,14,42,86,19,116, +56,246,57,60,57,60,216,116,216,26,110,26,110,116,217,116,110,68,217,68, +162,116,163,26,86,142,241,142,116,142,116,238,161,206,158,142,166,164,176,184, +200,212,239,236,216,160,185,195,76,12,42,86,17,118,54,244,55,60,134,14, +104,68,83,90,186,148,210,146,222,134,228,46,117,46,120,78,195,122,94,126, +120,112,142,86,155,46,108,158,136,142,160,120,182,88,190,60,193,46,102,178, +81,226,160,158,179,192,216,168,245,210,132,174,132,216,134,230,146,234,182,234, +196,224,203,209,70,12,38,78,17,110,50,244,51,54,104,24,125,50,212,20, +191,48,84,66,239,66,160,112,161,10,80,126,116,108,142,84,161,66,236,120, +210,112,184,94,161,66,74,162,245,162,158,134,118,194,233,234,88,238,118,234, +150,222,180,200,194,182,207,163,84,14,46,86,17,120,58,244,59,64,106,36, +137,62,222,28,189,64,92,114,92,76,230,76,231,112,160,76,161,8,206,164, +206,110,116,110,116,164,207,164,90,238,114,230,132,212,142,192,147,164,176,164, +176,216,180,228,188,234,224,234,236,226,243,207,74,14,40,88,19,118,54,246, +55,58,142,12,171,40,94,88,94,52,228,52,229,88,204,82,156,92,118,96, +119,180,74,180,245,180,118,130,227,130,180,180,181,130,138,196,87,240,174,198, +229,239,72,16,40,90,19,122,50,244,51,70,74,60,120,60,114,110,102,154, +71,210,126,198,75,92,172,20,142,96,127,126,150,244,151,76,194,20,213,52, +162,68,239,68,162,114,235,114,164,162,235,162,162,214,245,214,200,214,201,69, +70,16,34,90,15,118,50,244,51,58,124,16,100,58,77,84,78,138,120,106, +138,82,152,44,109,44,114,68,137,82,98,88,117,108,174,26,182,56,192,80, +210,104,241,128,180,44,226,44,205,94,118,120,209,120,90,154,239,154,124,182, +85,230,196,180,237,226,164,154,164,222,160,230,152,236,135,239,70,12,40,82, +17,110,54,246,55,52,80,40,237,40,92,68,223,68,156,68,157,8,214,124, +214,90,104,90,104,124,215,124,72,154,245,154,124,132,139,154,188,132,179,154, +104,242,104,182,216,182,217,240,104,224,217,225,66,18,36,90,15,122,50,242, +51,60,76,52,169,52,104,70,105,14,138,70,139,14,96,92,69,138,112,228, +134,224,150,212,154,198,154,106,89,106,126,190,126,138,88,138,88,190,127,190, +198,12,180,78,167,116,244,70,185,70,178,112,190,154,210,196,243,236,154,236, +178,218,196,192,210,158,218,118,221,71,68,14,40,90,17,126,54,244,55,54, +84,28,147,28,94,46,88,72,149,72,124,28,116,78,104,104,77,132,132,72, +132,120,149,110,167,28,172,26,235,26,172,46,168,72,243,72,202,26,196,78, +182,108,161,130,210,72,210,112,214,124,222,126,234,124,240,118,243,104,114,244, +114,148,214,148,215,242,114,186,215,186,114,224,215,225,76,18,42,84,19,114, +56,242,57,60,130,20,100,74,75,108,154,20,185,46,104,184,105,66,118,62, +231,62,118,98,223,98,118,136,221,136,118,174,237,174,106,200,83,240,142,200, +151,238,178,196,189,232,212,192,237,236,170,174,171,63,66,14,38,86,19,122, +48,242,49,62,94,22,121,48,64,62,157,62,140,144,140,94,80,94,80,144, +141,144,110,144,110,230,91,236,88,160,69,208,130,162,149,194,150,84,237,84, +182,10,182,96,180,130,176,166,162,206,139,238,206,28,229,60,204,100,204,208, +206,224,212,230,226,230,234,220,239,207,70,14,38,90,17,120,54,246,55,52, +138,12,167,36,86,44,231,44,70,82,249,82,126,56,141,82,194,54,181,82, +218,172,218,110,98,110,98,172,219,172,98,140,219,140,86,200,231,200,72,230, +249,230,158,230,159,111,76,20,42,82,15,116,52,246,53,64,220,74,220,30, +100,30,100,74,221,74,140,74,141,30,178,74,179,30,80,98,237,98,210,154, +210,122,106,122,106,154,211,154,78,210,118,190,142,170,155,154,166,210,128,232, +129,182,168,172,182,194,200,216,235,238,222,170,191,203,72,20,42,92,19,128, +52,248,53,70,152,12,120,40,95,54,72,236,86,210,94,180,96,162,96,68, +239,68,176,68,196,36,125,36,150,78,119,100,188,78,223,98,166,92,185,108, +108,118,247,118,124,142,225,142,124,168,225,168,130,246,130,194,216,194,217,246, +130,230,217,231,132,16,78,80,21,120,238,116,200,98,164,72,127,26,50,130, +209,130,26,230,231,230,128,230,129,131,128,18,84,66,52,84,19,100,236,90, +202,80,158,58,123,26,26,128,94,128,74,170,50,196,27,216,126,76,126,212, +124,224,116,232,95,232,226,212,190,194,160,166,138,132,127,110,202,112,149,149, +132,14,96,60,60,90,17,116,234,104,202,90,170,70,144,48,125,26,64,106, +191,106,36,156,217,156,80,178,25,230,164,180,223,228,128,156,128,220,124,234, +114,240,91,241,130,14,96,58,60,88,21,114,238,106,204,94,170,72,146,54, +121,26,70,102,187,102,56,146,89,208,110,130,131,190,24,230,229,230,194,126, +143,231,70,20,50,72,23,110,102,92,59,52,68,114,50,178,21,224,102,202, +61,148,94,228,247,228,130,228,130,36,214,36,215,228,130,100,215,100,130,158, +215,159,130,10,88,48,48,72,19,84,238,86,202,74,158,48,125,16,82,68, +165,68,86,136,86,92,46,92,46,136,85,136,148,134,148,90,106,90,106,134, +149,134,210,134,210,92,168,92,168,134,211,134,48,246,48,156,206,156,206,220, +206,230,194,238,177,240,100,234,101,156,148,234,149,156,48,196,207,197,104,14, +124,26,146,48,178,76,212,94,239,108,18,112,62,90,94,68,131,32,30,136, +98,136,86,168,68,194,50,210,27,226,130,82,130,238,99,244,230,220,198,204, +170,180,148,150,131,116,208,118,153,155,98,18,132,28,146,40,162,62,188,88, +231,104,26,108,54,96,82,78,106,54,123,26,62,108,93,138,190,108,163,138, +26,152,231,152,126,244,127,90,26,230,60,212,90,190,127,156,228,226,200,216, +172,198,127,161,94,22,72,64,46,100,19,126,150,14,164,48,182,74,210,98, +237,118,70,92,183,92,104,92,82,152,188,152,184,184,178,218,168,230,152,234, +140,236,125,237,128,84,122,100,108,108,70,108,56,102,52,88,52,30,108,30, +108,70,53,70,226,86,222,98,210,108,172,108,158,104,152,90,152,28,210,28, +210,70,153,70,44,140,213,140,16,180,243,180,92,120,93,180,164,120,165,180, +106,198,43,240,156,196,221,239,54,18,83,46,110,14,135,44,30,94,30,62, +220,62,221,92,196,14,163,62,50,94,203,94,16,120,239,120,90,120,91,74, +162,120,163,72,196,202,196,148,60,148,60,202,197,202,60,174,197,174,126,202, +127,120,100,212,39,240,148,212,219,239,10,66,111,66,30,18,51,48,94,18, +73,66,32,238,32,108,92,108,93,236,32,142,93,142,32,174,93,174,32,214, +93,214,64,66,55,108,130,74,239,74,188,12,188,86,194,162,206,218,214,230, +220,236,228,232,239,208,204,30,231,56,228,104,204,176,180,208,151,238,166,166, +166,112,126,112,126,166,167,166,112,204,175,195,20,22,45,50,94,142,94,66, +22,66,22,142,95,142,22,104,95,104,92,18,63,66,10,176,107,176,58,242, +59,66,92,234,110,208,120,176,124,144,124,32,218,32,218,68,125,68,140,110, +229,110,132,150,237,150,164,150,165,80,202,150,203,82,154,150,154,230,187,210, +180,150,188,174,208,208,237,232,228,164,201,193,86,14,117,38,20,44,241,44, +176,12,147,44,28,142,95,124,46,70,47,136,74,58,75,128,98,90,75,90, +154,138,154,70,110,70,110,138,155,138,110,92,155,92,110,114,155,114,234,120, +226,136,218,138,186,138,182,130,182,72,216,72,216,108,183,108,96,148,31,178, +162,148,227,182,128,154,94,184,49,208,26,238,78,232,120,220,160,194,176,180, +101,180,106,196,144,218,176,228,231,237,98,20,68,76,48,100,29,122,156,234, +186,234,208,226,222,204,224,190,226,66,75,67,82,12,52,58,21,94,184,236, +202,234,216,228,222,216,226,44,63,44,52,84,197,84,144,58,171,74,64,226, +64,116,178,116,178,218,149,224,64,146,179,146,64,178,179,178,118,226,119,61, +78,10,50,58,17,96,176,236,194,236,212,230,218,214,220,50,57,50,98,62, +127,82,42,90,185,90,50,118,175,118,52,146,173,146,170,210,170,170,54,170, +54,210,171,211,78,12,54,56,21,94,164,236,192,234,208,228,214,216,218,46, +61,46,56,76,183,76,158,124,158,98,68,98,68,124,159,124,170,210,170,152, +56,152,56,210,171,210,112,210,113,152,56,180,171,181,164,92,184,90,198,78, +202,46,60,46,60,120,222,120,220,150,212,160,187,166,20,238,50,228,70,214, +82,196,84,182,84,156,158,156,158,218,160,230,172,234,216,234,226,226,235,202, +122,10,109,46,96,68,139,91,14,240,32,212,44,176,50,138,50,34,198,34, +198,66,198,154,202,196,210,226,220,238,226,240,236,230,241,208,68,74,183,74, +72,168,94,138,108,106,117,74,70,232,102,216,136,186,154,156,166,120,103,120, +104,148,137,185,46,32,46,132,208,132,208,32,152,32,152,88,102,88,102,32, +47,32,18,234,48,228,72,214,90,196,98,172,100,152,101,132,154,132,154,216, +158,230,168,234,220,234,228,226,237,197,102,70,141,104,14,120,237,121,108,14, +139,38,22,52,231,52,102,68,45,112,156,72,213,114,129,94,156,118,197,160, +126,92,68,152,181,144,26,236,52,230,82,214,98,188,105,148,232,200,226,220, +218,230,204,232,166,232,156,228,152,216,153,147,112,12,147,32,22,42,231,42, +184,96,184,68,74,68,74,96,185,96,32,156,32,122,222,122,223,154,186,142, +140,152,59,156,24,196,223,184,218,208,212,226,202,234,190,236,144,236,132,234, +122,222,123,155,110,14,149,38,24,48,241,48,100,62,70,86,37,108,166,62, +231,104,131,82,152,100,203,142,130,82,74,136,185,128,26,206,72,184,106,156, +127,132,146,212,94,232,95,166,142,152,154,180,180,208,200,220,231,236,210,156, +169,195,106,12,145,38,18,46,235,46,102,86,132,106,138,116,138,146,130,156, +120,158,113,158,46,72,180,72,133,104,26,112,212,112,197,146,30,160,72,146, +104,130,127,112,14,214,60,202,96,182,123,168,144,214,82,234,83,190,140,172, +156,194,182,212,208,224,237,232,198,168,167,201,110,10,143,36,18,48,231,48, +24,82,111,82,22,120,113,110,74,58,74,150,47,156,122,84,200,80,196,128, +200,140,214,142,228,140,237,120,128,104,173,136,166,58,158,90,142,124,117,144, +110,156,78,184,21,218,138,208,90,236,89,176,136,154,146,180,168,204,200,222, +231,232,202,158,161,195,114,14,147,38,26,48,237,48,76,74,27,116,186,74, +237,110,104,112,105,48,160,112,161,48,50,244,50,134,214,134,214,238,181,244, +134,108,122,144,102,164,81,178,180,172,123,140,134,166,87,216,178,210,121,181, +108,16,143,40,18,50,239,50,116,66,58,78,58,138,202,138,202,78,147,78, +116,108,59,108,152,106,203,106,120,152,82,178,48,196,25,206,136,210,84,236, +85,178,144,158,158,182,180,208,202,224,235,236,208,160,173,197,108,14,137,34, +16,44,235,44,202,138,202,70,50,70,50,140,203,140,164,116,164,92,88,92, +88,116,165,116,48,162,205,162,18,184,239,184,92,202,25,240,164,200,235,230, +132,184,132,226,126,240,116,244,101,245,110,14,145,32,12,40,237,40,58,40, +58,66,205,66,196,114,196,90,58,90,58,114,197,114,18,244,30,224,38,198, +38,140,80,140,80,238,57,244,38,168,81,168,38,194,81,194,92,156,144,156, +132,194,114,222,97,240,124,130,102,190,145,218,142,246,158,224,166,198,166,138, +206,138,206,216,208,232,216,236,230,234,238,228,241,214,176,172,195,197,112,12, +149,30,14,40,239,40,58,40,58,66,205,66,196,114,196,88,60,88,60,114, +197,114,14,244,26,226,34,206,38,194,38,140,78,140,78,236,57,244,38,166, +79,166,38,194,79,194,146,200,151,220,94,226,149,214,126,124,127,218,148,186, +148,152,102,152,102,186,149,186,142,244,162,224,168,202,170,180,170,140,206,140, +206,218,208,228,216,232,226,232,234,228,243,216,180,176,197,199,112,10,147,26, +14,38,239,38,56,38,56,66,207,66,194,110,194,88,56,88,56,110,195,110, +18,238,30,222,38,200,38,138,78,138,78,238,57,242,38,166,79,166,38,192, +79,192,96,122,115,142,92,152,155,152,146,126,127,152,96,176,149,176,90,202, +155,202,122,240,123,152,180,168,195,194,144,240,160,214,168,188,168,176,168,136, +206,136,206,218,208,230,220,232,232,232,241,209,28,54,65,98,30,206,95,121, +28,38,67,84,20,214,73,124,82,32,233,32,72,224,243,224,132,32,106,160, +191,160,120,90,200,90,183,225,28,38,67,78,22,204,63,136,74,34,177,34, +116,34,110,78,96,114,83,136,70,230,104,206,126,178,140,142,144,116,148,92, +107,92,98,138,131,166,182,178,183,62,226,16,226,230,185,239,34,34,71,68, +24,204,63,114,122,30,108,80,99,108,220,72,113,72,82,128,239,128,162,128, +163,12,66,236,100,220,124,192,136,160,141,128,234,202,232,220,224,230,206,232, +188,230,180,226,180,214,181,129,16,42,47,78,18,216,51,124,96,240,97,14, +62,74,131,74,56,180,97,94,130,150,97,100,166,26,152,80,133,122,194,18, +202,70,218,106,235,126,200,154,231,232,184,104,148,218,219,207,32,148,32,104, +222,104,223,149,30,72,30,28,216,28,217,68,52,68,191,68,26,124,62,116, +92,102,114,86,133,68,94,230,112,230,130,224,140,210,144,190,142,166,138,146, +126,124,114,108,103,94,22,174,54,162,96,138,123,120,56,136,93,168,24,218, +54,204,88,182,120,158,137,144,206,90,137,142,230,212,212,202,190,182,176,162, +166,144,157,129,40,72,40,28,222,28,223,72,190,132,190,62,72,62,72,132, +191,132,72,96,191,96,110,146,149,166,16,174,241,174,108,194,37,238,152,192, +223,233,36,24,83,58,14,96,70,96,70,220,123,193,38,22,81,62,10,100, +54,100,54,222,101,184,102,34,233,34,94,126,247,126,168,242,169,35,40,18, +79,56,12,98,56,98,56,226,101,174,106,44,233,44,100,212,243,212,170,212, +171,45,50,26,79,62,14,100,58,100,56,222,95,182,228,68,229,238,114,72, +114,222,229,212,170,12,171,217,40,20,83,60,12,96,54,96,54,220,91,182, +236,32,110,32,110,220,245,220,214,58,184,130,139,194,142,74,184,122,227,181, +40,26,83,64,12,100,58,100,58,216,97,178,238,32,116,32,116,224,245,224, +116,156,216,156,216,96,117,97,36,22,81,60,10,100,56,100,56,220,95,184, +112,238,112,68,230,68,230,232,203,240,170,8,170,72,168,102,160,136,137,170, +210,164,169,103,36,20,75,58,14,98,56,98,56,222,93,184,92,76,241,76, +118,244,118,142,216,142,217,242,118,218,217,218,162,142,163,13,32,18,75,52, +12,96,58,96,58,218,97,182,166,160,166,82,116,82,116,160,167,160,92,32, +245,32,210,32,210,232,173,243,42,16,77,54,10,98,54,98,54,214,89,166, +220,20,164,34,114,40,114,220,163,180,114,108,239,108,156,210,183,238,174,32, +176,88,182,146,190,182,202,208,210,222,216,226,222,228,230,226,241,201,38,18, +79,54,16,98,58,98,58,220,95,180,96,32,220,32,214,94,206,106,194,112, +179,112,90,130,110,118,130,102,144,80,154,54,159,32,122,242,122,140,218,140, +219,240,122,214,219,215,40,24,77,60,14,98,58,98,58,214,89,178,112,36, +112,104,218,104,219,32,224,140,225,244,106,138,106,222,225,218,166,10,167,221, +44,20,81,64,14,100,56,100,56,212,93,178,192,58,239,118,164,14,100,110, +223,100,118,244,118,148,214,148,215,244,118,222,213,223,34,24,77,52,14,98, +58,98,52,224,93,196,238,30,110,30,110,222,245,222,126,68,229,68,136,122, +225,122,126,184,233,184,178,184,179,69,44,20,83,60,12,94,54,94,54,212, +91,162,98,54,231,54,104,90,223,90,92,126,237,126,162,242,163,10,88,212, +126,182,163,136,234,210,208,192,186,166,163,129,36,24,79,62,12,104,58,104, +58,226,97,178,104,58,227,58,92,112,239,112,162,112,163,10,106,166,231,166, +90,228,243,228,164,226,165,129,34,28,67,66,10,104,50,104,50,220,91,182, +88,58,239,58,102,110,229,110,164,110,165,12,120,244,120,154,212,154,213,242, +120,220,213,221,40,18,69,58,14,94,52,94,52,224,93,188,86,54,239,54, +142,10,122,94,91,162,142,110,127,162,220,110,199,164,172,78,172,132,162,178, +144,206,130,222,105,238,232,238,208,218,188,194,174,162,169,149,28,18,69,54, +10,94,54,94,54,218,93,188,120,30,110,78,97,106,82,126,241,126,222,70, +113,70,160,126,161,10,82,234,104,222,124,206,134,180,140,156,141,126,184,126, +184,210,186,228,198,232,222,232,232,226,235,203,44,18,83,58,10,92,54,92, +54,206,85,162,224,22,172,32,116,38,116,146,108,188,85,226,244,92,117,92, +146,240,146,142,220,142,221,240,146,214,221,215,30,22,67,58,10,96,50,96, +46,228,93,182,158,10,126,64,89,102,236,96,204,74,176,50,155,18,110,98, +213,98,104,154,217,154,92,220,235,220,160,220,161,99,34,28,73,62,14,106, +58,106,58,226,93,198,144,12,122,50,89,92,110,90,220,90,221,190,106,172, +221,172,96,130,245,130,126,238,146,236,158,230,162,222,163,90,170,90,194,42, +129,43,42,18,75,54,14,96,58,96,58,214,89,186,104,64,104,26,226,26, +227,64,98,82,227,82,160,44,108,140,227,140,106,178,241,178,168,242,169,103, +36,20,71,62,10,102,56,102,56,222,93,200,90,36,146,36,146,232,111,242, +94,78,119,116,88,174,147,146,164,36,228,36,228,208,224,226,210,236,189,238, +172,78,201,116,168,174,229,141,36,22,73,56,16,94,58,94,58,224,97,178, +106,26,135,62,232,22,201,64,120,244,120,92,218,92,218,238,193,244,168,92, +169,8,120,134,219,134,120,176,219,177,38,28,71,64,12,102,52,102,52,220, +93,182,124,26,101,98,226,64,113,64,86,118,241,118,164,118,165,12,120,246, +120,158,210,158,211,242,120,222,211,223,40,20,75,60,14,100,54,100,54,230, +93,196,92,30,108,52,124,82,130,114,134,140,134,204,126,222,114,230,99,234, +140,12,120,52,87,90,84,170,108,144,129,112,146,40,239,40,154,126,231,126, +142,220,243,220,194,220,195,41,40,26,77,64,6,100,54,100,54,228,91,186, +189,36,188,34,231,76,160,10,112,72,219,64,128,88,93,140,222,112,113,112, +92,162,239,162,166,112,162,160,152,192,128,220,97,238,240,236,216,222,192,202, +163,163,20,24,55,56,10,94,48,94,48,206,79,166,66,28,181,28,74,202, +171,176,146,244,147,28,96,28,97,194,96,84,147,84,96,136,147,136,164,54, +226,54,220,110,206,150,188,188,165,220,238,218,210,182,194,144,184,104,181,73, +24,24,63,50,10,94,48,94,48,214,79,176,78,30,231,30,76,102,104,84, +140,56,163,30,124,68,140,84,160,118,164,140,168,172,168,198,158,224,140,234, +117,236,82,152,110,134,130,112,145,94,98,114,123,148,80,206,132,164,161,124, +220,72,161,124,236,196,208,160,194,128,183,105,34,26,69,66,14,104,54,104, +54,224,95,192,210,14,168,24,107,28,88,64,235,64,160,106,161,26,88,120, +122,102,161,66,236,118,206,102,182,84,163,66,80,154,245,154,154,128,118,180, +237,232,200,154,190,174,176,196,156,212,124,228,99,237,38,20,77,66,14,98, +56,98,56,216,93,178,140,46,108,54,108,154,222,154,222,50,191,50,140,102, +109,102,188,100,223,100,164,10,164,92,162,130,154,174,130,210,104,226,79,240, +236,238,208,216,188,188,171,155,34,22,75,56,10,96,52,96,52,216,85,176, +156,14,126,66,83,112,234,100,196,76,168,46,151,24,146,70,173,94,108,112, +202,112,177,152,108,174,89,224,140,148,169,178,204,170,237,208,136,172,136,210, +136,224,150,234,172,234,188,228,201,211,38,24,83,64,12,98,60,98,60,220, +95,184,152,14,128,60,95,102,182,102,222,46,137,46,154,114,114,128,115,244, +154,166,115,166,186,124,228,124,229,240,190,166,229,166,114,214,229,215,40,20, +81,60,14,96,60,96,60,208,91,178,148,14,181,40,100,52,237,52,136,70, +105,140,160,126,131,84,206,66,181,134,228,138,199,92,100,168,243,168,168,244, +169,147,36,26,69,62,12,100,56,100,56,216,89,182,92,50,239,50,80,150, +245,150,112,150,112,228,233,228,164,170,135,206,190,170,217,206,126,150,127,12, +202,150,203,10,126,82,203,82,126,114,203,115,36,24,71,64,10,102,52,102, +52,212,93,172,90,48,241,48,164,244,165,8,218,144,218,82,110,82,110,144, +219,144,130,100,145,126,198,100,183,126,92,224,118,204,142,176,165,146,232,218, +208,200,186,176,165,145,40,24,75,62,6,96,50,96,48,206,81,164,228,86, +236,64,102,64,102,160,92,202,75,234,120,104,211,98,160,76,158,116,162,124, +176,134,192,134,214,132,224,124,229,112,223,34,158,64,159,6,158,34,223,34, +110,192,247,192,226,158,138,158,138,228,229,229,38,22,79,58,14,100,60,100, +60,220,97,188,212,100,212,28,114,28,114,100,213,100,136,110,114,140,93,156, +186,238,210,234,222,222,226,130,123,130,116,164,116,212,191,212,168,146,139,194, +196,192,159,162,114,64,213,65,38,24,71,64,10,102,50,102,50,218,93,182, +140,74,140,26,98,26,98,74,141,74,216,72,216,26,168,26,168,72,217,72, +92,104,221,104,76,138,241,138,132,138,122,174,208,174,202,214,196,224,184,228, +168,232,145,237,38,22,67,58,10,98,46,98,46,220,77,186,152,14,112,60, +71,94,238,92,200,74,172,54,145,24,110,76,185,76,94,242,94,108,142,108, +142,234,125,240,94,144,143,144,94,180,143,180,178,198,179,116,214,100,214,236, +183,241,40,22,77,58,12,102,54,102,54,210,91,166,220,18,160,30,97,34, +112,50,131,82,152,44,165,74,218,44,197,80,100,94,231,94,88,130,239,130, +84,222,110,196,134,164,146,132,155,94,110,240,142,226,168,208,194,182,208,160, +137,160,140,178,156,200,178,218,212,230,239,239,40,22,79,60,12,104,56,104, +56,226,91,186,142,12,177,38,100,50,231,50,84,112,245,112,126,68,153,98, +202,62,179,112,118,244,118,142,212,142,213,240,118,180,213,180,118,218,213,219, +38,26,75,64,14,100,52,100,48,222,91,180,140,14,171,36,94,46,233,46, +124,58,149,92,94,134,94,100,232,100,233,134,198,58,175,100,114,224,114,146, +214,146,214,216,189,222,160,244,161,115,36,28,75,64,10,104,54,104,54,224, +89,182,90,28,121,52,86,126,121,84,168,12,143,62,210,74,224,50,151,50, +176,66,160,106,140,126,117,140,236,138,214,128,196,112,173,76,110,246,110,160, +210,160,211,246,110,228,211,229,34,20,73,50,4,90,50,88,50,202,81,170, +146,10,177,36,68,230,92,192,104,150,106,122,106,52,226,52,226,94,109,94, +118,242,118,130,234,130,234,236,211,244,118,176,235,176,156,220,157,130,194,218, +195,131,32,24,71,60,12,98,58,98,58,226,89,194,86,40,239,40,138,66, +139,8,188,66,189,8,214,140,214,78,108,78,108,140,215,140,108,110,213,110, +102,174,243,174,88,238,118,228,138,210,152,192,158,174,163,140,234,238,208,226, +188,208,174,190,165,175,38,24,67,58,10,100,48,100,48,218,83,176,104,28, +129,60,216,24,193,54,94,116,94,78,228,78,229,116,160,78,161,12,204,160, +204,110,122,110,122,160,205,160,82,238,108,228,130,208,140,188,143,160,178,160, +178,220,180,228,188,236,216,236,228,228,237,207,36,20,75,62,10,100,56,100, +56,210,89,174,222,90,222,24,104,24,104,90,223,90,104,56,223,56,162,90, +163,24,136,102,93,136,184,100,233,136,152,120,128,164,103,192,90,236,124,224, +156,208,184,182,202,148,139,148,234,232,200,222,176,208,156,188,135,157,38,24, +77,66,14,104,54,104,54,216,89,174,112,18,145,54,210,12,185,56,96,70, +237,70,142,90,116,122,95,140,180,90,237,136,90,228,245,228,116,228,116,152, +218,152,219,228,148,228,149,152,184,228,185,153,38,22,75,60,12,100,56,100, +56,220,89,184,108,52,91,100,142,14,175,42,212,54,239,98,210,20,172,72, +144,98,99,126,138,44,138,104,142,120,152,124,188,124,202,116,207,98,86,226, +245,226,110,226,110,156,224,156,225,226,146,226,147,156,186,226,187,157,40,28, +73,66,14,100,56,100,56,224,89,190,144,14,179,40,90,50,241,50,104,242, +104,102,224,102,224,238,193,244,126,66,147,94,204,62,179,102,124,132,203,132, +188,204,188,164,136,164,136,204,189,204,160,164,161,109,36,22,71,60,14,100, +52,100,52,214,83,174,118,14,149,36,208,10,185,36,94,46,245,46,104,158, +104,72,160,72,160,154,143,158,104,96,161,96,104,122,161,122,190,126,191,74, +224,64,224,152,203,158,104,176,222,176,216,224,206,232,198,236,183,236,152,176, +148,198,136,216,120,226,95,239,34,18,69,56,10,90,48,90,48,218,81,178, +82,22,149,22,168,22,233,22,90,42,86,70,151,70,120,22,118,52,108,84, +92,108,73,128,124,70,124,120,153,98,172,38,168,70,237,70,198,22,196,62, +188,86,174,108,155,126,202,70,202,104,204,114,212,122,224,122,234,116,241,104, +104,240,104,148,206,148,207,240,104,182,207,182,104,218,207,219,44,22,79,60, +14,96,54,96,54,218,91,180,134,12,106,68,81,108,116,182,117,50,162,14, +189,42,124,58,231,58,124,94,223,94,124,132,221,132,124,172,237,172,172,172, +173,58,114,200,91,238,142,198,149,236,172,196,185,234,206,192,235,235,38,22, +79,62,12,100,56,100,56,216,89,180,136,44,181,60,100,22,200,22,167,54, +92,66,228,66,217,98,92,118,122,104,142,92,169,66,146,120,164,118,168,114, +172,104,173,66,106,244,106,140,224,140,224,238,207,242,154,156,125,182,176,156, +207,182,188,224,188,184,142,184,142,224,189,225,30,24,53,70,10,100,40,100, +40,226,65,194,66,46,163,46,78,236,78,88,152,88,152,224,135,228,98,104, +109,126,92,142,139,142,132,106,117,142,90,172,139,172,114,218,115,142,114,88, +115,12,168,86,243,86,220,30,235,66,198,10,198,94,196,132,186,180,174,214, +157,244,236,240,210,178,199,119,34,28,69,58,12,94,54,94,54,206,79,180, +148,14,124,38,107,50,242,66,100,66,100,166,88,208,69,240,154,74,123,98, +196,74,225,96,164,88,189,104,108,114,245,114,124,138,225,138,122,164,223,164, +176,66,196,34,129,34,130,242,130,188,216,188,217,240,130,222,217,223,28,26, +57,64,6,106,44,106,44,230,71,204,64,92,241,92,210,32,227,68,186,12, +186,104,188,144,194,176,202,208,216,230,222,232,228,232,236,228,241,206,222,122, +212,160,200,188,180,216,159,240,106,16,94,54,81,78,122,60,101,38,152,18, +144,56,131,80,168,72,147,46,78,226,167,212,108,102,109,220,138,102,139,216, +72,128,109,128,72,158,109,158,80,186,109,186,172,126,139,126,172,156,139,156, +172,186,139,187,142,244,142,36,224,36,224,162,222,174,218,180,212,182,185,183, +60,32,180,32,132,60,132,112,109,118,30,62,100,62,78,88,54,106,21,122, +160,64,172,84,194,102,235,120,218,58,183,92,38,136,219,136,152,202,170,202, +178,200,182,186,186,162,68,162,68,210,70,222,80,230,200,230,212,220,217,207, +78,194,94,194,112,186,122,170,122,150,114,130,102,118,90,108,82,98,116,24, +46,24,47,241,54,184,68,182,82,174,88,154,86,136,78,120,56,98,86,30, +28,30,29,240,98,36,235,36,88,228,112,210,130,182,136,148,138,114,139,36, +236,196,232,208,226,218,216,222,194,222,188,218,186,210,187,37,62,188,80,188, +92,178,94,152,86,130,74,116,66,102,94,32,36,32,37,242,222,28,184,36, +115,42,100,120,241,120,170,242,171,39,54,178,70,174,80,160,80,138,74,122, +60,98,86,32,32,32,33,244,98,74,233,74,94,144,243,144,132,12,132,158, +126,186,116,210,91,238,188,242,189,13,54,186,74,182,84,172,88,160,84,144, +74,124,56,102,84,28,28,28,29,240,214,20,168,30,124,34,124,118,114,168, +100,200,79,228,132,94,216,94,196,156,164,200,117,234,142,94,152,130,170,172, +200,208,237,231,52,194,68,192,84,182,92,164,90,142,76,124,56,104,86,30, +28,30,29,242,118,240,118,130,214,130,215,236,118,214,215,214,162,130,163,14, +162,68,241,69,52,190,74,188,90,178,94,158,88,136,72,118,56,104,92,28, +32,28,33,246,154,12,126,68,103,106,234,68,127,68,150,246,151,68,220,122, +151,122,230,178,151,179,52,184,66,182,76,178,82,162,80,142,76,124,66,114, +56,100,82,28,30,28,31,246,214,88,226,50,114,50,114,134,110,172,94,204, +73,230,124,114,208,114,198,150,186,176,164,206,140,222,115,236,234,236,204,220, +174,198,156,172,142,144,133,114,168,114,169,9,56,188,70,186,86,178,92,160, +88,138,76,120,60,102,92,34,34,34,35,244,114,34,202,34,188,56,174,72, +148,94,101,118,236,122,165,80,108,150,225,150,90,224,241,224,164,224,165,151, +56,190,72,190,84,182,92,168,90,150,84,136,76,120,64,110,86,36,32,36, +33,244,148,14,185,44,100,54,243,54,200,86,154,148,109,186,160,62,118,122, +177,116,220,128,178,186,142,214,103,236,236,232,185,181,60,180,74,180,84,174, +90,160,88,144,82,124,74,112,62,96,90,26,40,26,41,238,92,98,241,98, +122,98,123,42,166,98,167,6,222,52,167,52,166,196,167,112,134,128,109,180, +224,134,206,166,182,194,154,214,130,226,103,237,52,180,70,178,82,164,84,150, +80,132,68,112,58,98,82,30,30,30,31,240,210,116,210,28,112,28,112,116, +211,116,112,72,211,72,100,170,225,170,80,224,239,224,160,224,161,135,52,170, +66,166,78,158,82,146,78,128,72,118,54,96,76,32,32,32,33,240,92,30, +175,30,74,206,167,178,150,242,151,30,106,30,107,196,106,82,149,82,106,134, +149,134,162,48,222,48,216,102,202,154,184,194,165,222,240,222,220,200,196,164, +182,124,174,80,173,49,52,182,66,180,76,172,80,160,78,138,70,118,60,100, +84,32,34,32,35,238,210,24,164,32,107,38,92,76,229,76,88,128,241,128, +90,184,231,184,96,226,223,226,158,226,159,34,120,184,121,76,198,184,199,77, +48,190,66,190,80,182,86,164,84,144,76,130,56,104,82,36,26,36,27,246, +220,132,220,46,112,46,112,132,221,132,112,90,221,90,166,46,166,96,164,112, +158,126,152,140,117,168,94,184,241,184,178,246,179,146,158,14,139,47,52,188, +70,186,80,174,84,156,82,134,74,118,58,100,86,28,32,28,33,242,214,110, +214,26,116,26,116,110,213,110,116,68,215,68,164,110,165,26,98,142,239,142, +120,142,120,232,163,208,162,142,168,166,182,190,200,210,233,230,218,166,191,199, +56,190,74,188,86,178,90,156,84,138,74,120,60,106,86,32,32,32,33,244, +214,110,214,44,116,44,116,110,215,110,116,78,213,78,162,10,147,44,104,144, +229,144,110,184,219,184,86,228,239,228,164,228,165,145,48,194,66,190,78,178, +82,162,80,146,74,132,68,118,54,102,80,30,30,30,31,246,214,130,214,42, +108,42,108,130,215,130,108,88,215,88,160,42,160,92,154,142,146,164,130,194, +106,218,73,242,166,150,166,216,170,230,180,236,216,236,228,230,237,210,218,162, +239,192,204,144,184,192,231,184,152,10,137,43,48,172,72,166,78,154,76,130, +66,112,52,94,80,26,30,26,31,240,216,78,216,24,106,24,106,78,217,78, +106,50,217,50,123,88,147,106,140,140,155,178,146,106,96,168,147,162,122,88, +96,128,127,126,214,136,229,172,218,104,168,164,223,160,192,88,162,128,199,124, +104,190,79,234,136,192,147,234,174,188,187,228,210,184,235,227,26,36,127,36, +14,122,135,122,80,236,81,36,154,244,154,28,222,28,184,106,208,122,228,142, +232,158,230,182,212,194,189,199,20,40,129,40,20,192,121,166,72,176,73,40, +152,242,152,34,218,34,190,104,204,116,218,130,228,148,230,168,224,184,206,194, +181,197,72,12,103,40,140,56,50,56,50,122,44,174,25,222,162,242,162,36, +226,36,192,106,210,120,228,138,236,154,236,174,228,188,212,198,191,199,56,16, +89,50,14,68,135,68,48,68,48,190,133,190,154,242,154,32,224,32,194,104, +210,118,226,134,236,156,236,178,222,190,206,196,191,199,80,106,96,106,108,100, +114,92,114,48,42,48,42,140,128,140,124,210,122,220,114,226,91,226,18,190, +99,180,80,12,67,48,166,246,166,42,224,42,196,118,210,132,224,148,230,164, +230,188,222,204,206,210,191,211,64,14,95,50,18,68,143,68,62,68,62,112, +58,144,50,180,38,206,25,228,76,222,94,222,108,214,112,202,116,118,63,118, +164,246,164,34,222,34,192,112,214,134,224,148,230,162,230,178,224,190,208,200, +187,203,16,32,149,32,34,242,34,88,130,88,130,234,101,240,82,32,82,92, +76,124,70,154,55,186,116,178,79,116,168,244,168,28,228,28,198,96,222,122, +230,138,238,158,236,178,226,192,210,196,195,197,26,28,139,28,24,138,50,114, +72,84,88,56,103,28,102,88,137,138,82,176,83,66,26,204,137,182,162,244, +162,26,220,26,184,100,206,116,224,136,232,154,230,172,218,184,187,191,70,222, +71,12,20,84,71,84,18,190,71,180,110,12,110,204,149,178,110,84,151,84, +166,242,166,26,226,26,194,104,206,116,220,130,228,146,232,166,226,186,212,194, +191,197,16,212,153,198,70,14,71,206,108,16,109,202,26,62,49,164,146,62, +125,168,172,246,172,28,226,28,198,104,214,122,230,142,234,158,230,180,218,190, +197,195,132,24,36,42,36,222,81,180,74,208,99,238,36,108,145,108,88,34, +92,144,108,200,122,222,132,222,138,218,149,194,166,242,166,30,226,30,196,102, +212,116,220,130,230,146,234,164,230,184,220,194,193,201,81,14,98,52,141,108, +80,14,30,100,125,92,40,234,40,136,114,136,115,230,40,208,115,208,158,244, +158,30,220,30,190,106,206,120,220,138,230,156,230,174,226,188,210,200,189,207, +30,54,139,54,38,78,61,114,126,76,105,116,20,134,149,134,84,12,84,90, +80,146,66,188,42,216,23,230,138,216,79,148,166,244,166,36,228,36,196,108, +218,124,230,144,238,166,230,188,216,200,195,203,18,32,145,32,77,42,104,58, +145,110,76,40,30,106,133,96,28,152,135,152,20,218,143,204,80,114,81,210, +164,240,164,28,224,28,198,100,218,120,230,138,236,156,232,174,222,186,206,196, +191,199,56,30,42,74,31,94,140,64,47,64,20,114,149,114,90,242,91,10, +24,202,56,168,91,122,138,176,91,128,162,244,162,30,228,30,190,108,212,124, +226,140,234,156,236,176,224,190,210,196,193,201,94,18,56,74,19,106,148,94, +85,34,48,100,133,100,26,140,151,140,104,174,143,230,86,148,38,222,127,210, +168,242,168,34,230,34,200,104,218,118,232,140,238,160,232,182,216,194,199,197, +34,22,141,78,130,16,80,58,37,84,22,114,153,114,90,78,66,138,44,174, +21,204,118,174,147,226,108,132,58,218,137,208,170,244,170,28,226,28,200,100, +214,116,222,130,230,144,232,158,232,174,224,188,210,194,197,197,60,12,38,68, +19,102,84,230,100,230,114,226,124,216,128,200,128,56,45,56,88,184,88,100, +38,100,38,184,89,184,38,142,89,142,164,246,164,34,226,34,192,112,212,128, +224,144,230,160,232,174,230,190,218,200,204,204,191,205,28,62,28,26,130,26, +131,62,22,78,141,78,76,44,36,134,139,134,18,194,137,178,84,242,85,98, +160,242,160,26,222,26,188,100,208,116,224,134,232,150,232,170,226,184,214,194, +202,198,189,199,16,26,155,26,32,226,32,66,74,66,74,220,57,226,42,110, +61,152,102,226,102,66,144,66,144,220,123,226,112,108,129,154,174,242,174,24, +228,24,194,104,206,116,222,134,228,148,232,164,230,180,220,192,204,196,193,197, +124,80,124,26,38,26,38,80,125,80,22,118,141,118,28,160,133,160,18,212, +137,202,80,118,81,206,164,242,164,24,224,24,190,98,206,114,222,130,230,148, +232,168,226,184,214,194,189,197,56,30,42,66,27,90,141,58,140,60,47,60, +14,114,149,114,90,114,91,12,46,238,46,150,120,150,121,236,46,212,121,212, +164,244,164,32,226,32,190,108,210,128,224,148,226,162,226,180,216,194,200,200, +185,201,46,16,139,68,124,12,82,46,35,72,16,96,155,96,88,64,54,118, +21,154,46,214,46,136,134,136,134,206,113,210,90,244,91,110,170,244,170,26, +226,26,196,104,212,120,226,138,232,152,236,168,230,182,220,192,208,194,199,195, +130,24,82,34,21,38,30,60,49,90,72,52,89,84,132,52,105,94,20,110, +128,110,82,144,82,208,80,222,76,228,70,232,47,234,18,184,139,162,162,244, +162,30,226,30,190,106,208,118,222,134,230,150,234,168,228,186,214,196,191,199, +130,134,130,46,40,46,40,134,131,134,40,90,131,90,88,46,88,94,78,118, +64,146,41,166,80,12,63,46,12,178,147,178,92,146,93,242,164,244,164,36, +228,36,194,104,212,124,226,144,232,156,236,174,232,188,218,196,191,201,48,34, +33,76,138,34,117,68,50,136,37,178,140,134,119,168,84,12,80,66,74,86, +62,102,27,124,140,116,81,70,88,114,84,150,78,184,62,210,25,238,150,222, +83,164,166,246,166,36,226,36,198,104,212,118,226,132,234,148,236,172,224,190, +210,196,193,201,146,26,34,26,34,212,149,212,132,108,132,54,66,54,66,108, +133,108,66,80,133,80,46,140,149,140,100,114,68,160,141,192,52,196,74,190, +94,180,110,166,125,140,168,242,168,26,226,26,198,106,208,116,224,136,232,158, +234,176,226,192,210,200,191,203,18,28,157,28,138,116,138,62,34,62,34,116, +139,116,70,116,71,28,104,116,105,28,28,160,147,160,22,214,147,198,86,204, +87,130,176,244,176,28,228,28,200,102,214,116,226,138,232,158,230,182,216,194, +193,197,28,28,145,28,16,94,153,94,50,94,51,50,90,94,91,28,90,60, +135,60,53,108,50,108,50,154,144,154,140,206,134,216,126,222,118,224,107,226, +38,174,25,218,58,180,65,210,84,174,91,204,110,170,121,194,50,126,137,126, +176,246,176,26,224,26,196,108,212,120,226,138,232,158,236,176,224,194,210,198, +197,201,16,44,155,44,60,14,60,72,116,72,117,12,138,130,138,98,40,98, +40,130,139,130,24,154,153,154,32,182,139,182,20,222,147,210,88,214,89,72, +174,244,174,34,230,34,198,114,212,128,226,146,232,168,232,186,224,200,210,204, +195,205,72,14,95,38,28,46,147,46,50,58,71,78,16,88,153,88,122,58, +101,88,132,166,132,114,42,114,42,166,133,166,42,138,133,138,14,192,155,192, +86,240,87,166,172,242,172,38,230,38,200,102,212,116,224,134,230,150,234,166, +230,184,220,192,206,194,197,195,136,16,92,28,35,34,46,50,65,68,16,78, +153,78,128,42,105,78,18,138,48,120,68,100,85,78,104,92,149,124,88,124, +89,30,42,236,42,138,134,138,135,230,42,174,135,174,42,210,135,210,88,210, +89,138,170,244,170,32,228,32,196,108,216,124,230,142,238,160,236,180,224,196, +210,200,195,203,47,18,24,50,147,50,46,16,73,50,120,14,97,50,34,78, +133,78,24,104,147,104,12,148,151,148,42,120,59,148,122,116,101,148,84,50, +85,148,42,240,42,178,124,178,125,236,42,218,125,218,166,242,166,36,228,36, +194,112,212,124,226,140,232,156,234,174,230,186,218,196,191,203,22,28,111,28, +24,110,109,100,90,122,91,28,46,106,47,28,46,54,91,54,46,78,91,78, +110,44,156,44,148,78,132,100,115,116,114,66,165,110,146,128,96,140,37,142, +100,242,101,140,66,156,35,192,82,184,33,232,156,222,101,170,150,150,121,188, +184,244,184,30,232,30,210,100,224,120,234,142,238,168,230,186,218,190,207,193, +28,34,147,34,28,98,28,62,148,62,149,98,88,130,89,34,42,90,75,90, +40,114,75,114,102,88,135,88,102,114,135,114,32,236,32,142,56,142,57,230, +32,212,55,212,76,234,76,142,98,142,99,228,76,212,99,212,120,236,120,142, +142,142,143,228,120,212,143,212,176,244,176,30,226,30,198,108,216,124,228,142, +236,160,236,176,228,190,216,196,199,199,32,24,32,110,152,110,153,26,90,16, +91,110,60,110,61,26,122,110,123,26,44,48,77,48,46,68,75,68,44,88, +77,88,104,48,137,48,104,68,137,68,104,88,137,88,18,134,165,134,136,184, +136,156,46,156,46,184,137,184,56,196,71,216,24,230,159,216,124,194,107,220, +182,242,182,32,232,32,206,98,218,112,224,126,230,142,236,158,230,180,214,186, +203,189,108,16,70,78,29,126,60,106,216,106,217,248,62,164,217,164,52,222, +217,222,156,106,188,54,85,55,94,14,64,56,27,88,16,164,243,164,60,164, +60,94,196,94,197,164,126,94,158,46,73,46,126,112,122,164,108,190,90,212, +58,228,23,240,236,238,204,228,174,214,148,194,123,165,16,34,131,34,60,34, +60,76,58,114,52,154,42,188,17,224,60,94,114,94,114,126,110,192,104,206, +92,210,71,212,174,8,174,74,172,112,166,150,156,188,138,218,113,238,136,72, +226,72,220,196,218,210,212,220,200,224,181,227,62,16,38,68,19,98,80,172, +80,110,36,110,36,172,81,172,42,60,118,60,118,178,118,200,114,214,104,222, +90,224,71,226,140,78,228,78,224,204,220,220,216,230,189,234,176,10,176,92, +174,138,168,172,156,202,123,243,24,30,122,30,120,90,116,104,108,110,96,112, +89,112,68,30,68,38,66,62,58,86,50,104,40,116,25,130,44,238,44,144, +118,144,119,228,44,210,119,210,178,8,178,84,178,118,172,160,162,192,150,218, +131,238,140,62,230,62,228,122,226,178,226,202,224,218,218,226,210,230,187,231, +54,14,95,46,16,60,135,60,108,90,74,134,29,176,70,68,36,114,89,114, +122,130,80,184,27,228,90,174,121,204,172,8,170,114,160,170,142,206,111,240, +128,82,224,80,216,218,208,228,179,231,26,46,120,44,116,84,110,98,98,102, +89,102,76,12,70,62,58,86,27,112,216,94,216,36,154,36,154,94,217,94, +16,128,243,128,190,128,190,238,161,244,134,202,134,160,62,160,62,202,135,203, +34,30,118,30,90,60,90,122,59,130,20,80,127,80,18,222,141,210,42,218, +42,146,128,146,129,210,70,216,71,146,98,212,99,146,184,8,184,120,180,164, +168,202,143,244,147,74,156,74,226,74,220,200,218,218,210,224,202,228,185,229, +32,98,32,32,132,32,133,98,50,60,111,60,50,86,111,86,46,240,46,120, +118,120,119,240,46,152,119,152,46,184,119,184,46,216,119,216,154,78,228,72, +224,196,222,210,216,218,210,220,195,224,184,14,182,124,176,166,166,198,152,220, +141,235,28,48,108,48,108,78,102,96,81,102,68,12,62,60,50,84,40,96, +27,106,16,140,60,140,60,208,54,220,45,222,42,116,34,194,19,228,82,140, +114,140,114,226,101,232,96,116,88,194,73,236,216,118,216,30,136,30,136,118, +217,118,136,74,217,74,176,118,177,30,142,158,135,194,176,138,199,180,214,156, +235,200,160,150,160,214,160,224,162,230,172,236,196,236,204,226,213,207,92,30, +50,36,50,120,200,120,200,34,159,34,94,78,51,78,160,76,201,76,44,154, +190,154,136,204,82,228,23,240,74,154,94,178,120,200,154,216,202,230,237,236, +124,154,125,13,32,54,25,98,57,20,54,20,54,84,50,112,40,132,23,154, +84,134,53,102,76,52,71,86,114,16,137,34,92,44,157,44,102,66,149,66, +104,88,151,88,148,142,148,114,104,114,104,142,149,142,198,18,198,86,188,112, +169,144,236,142,195,96,174,50,169,88,232,40,209,76,46,166,184,166,138,210, +90,230,27,238,76,166,100,192,126,212,162,226,231,233,110,84,110,26,44,26, +44,84,111,84,44,46,111,46,44,66,111,66,80,94,54,118,23,140,58,180, +59,114,212,82,212,26,146,26,146,82,213,82,146,66,213,66,146,46,213,46, +122,90,147,108,72,114,227,114,72,134,217,134,72,154,217,154,72,174,235,174, +140,174,141,114,46,194,192,194,118,226,62,238,25,240,236,236,198,236,158,230, +120,218,81,195,16,32,86,32,50,110,96,110,92,154,80,190,62,208,21,232, +40,132,48,160,64,188,86,208,114,220,154,224,241,225,210,236,211,24,48,26, +48,218,211,219,218,240,219,56,38,56,38,224,219,218,128,14,128,202,105,208, +54,76,104,76,94,122,59,172,192,164,146,92,129,68,196,62,153,99,38,28, +38,132,206,132,207,32,168,22,108,82,61,110,74,28,181,110,58,56,87,76, +104,14,133,34,164,56,189,78,116,96,139,118,62,146,62,210,64,224,74,232, +82,232,198,232,212,226,218,218,225,196,194,154,63,197,156,118,225,228,132,26, +40,220,209,205,121,12,160,36,213,92,122,12,52,92,199,78,14,150,245,150, +94,104,90,168,84,192,66,218,33,242,172,248,173,103,152,30,205,76,118,12, +60,72,185,62,20,102,239,102,114,76,84,118,54,144,21,164,236,158,198,136, +159,102,66,248,66,144,194,144,195,248,66,184,195,184,66,228,195,228,130,228, +131,145,20,38,88,38,70,72,48,100,19,126,110,120,69,76,28,142,105,142, +16,220,109,198,68,206,69,142,152,14,185,38,114,50,239,50,198,80,233,120, +174,58,124,116,221,108,138,130,138,184,130,210,101,242,168,230,169,140,206,134, +206,222,210,234,220,240,234,236,243,207,100,22,58,68,23,96,152,18,178,54, +204,74,237,92,64,78,186,78,180,124,172,136,158,142,147,140,46,180,211,180, +22,228,235,228,114,78,104,110,80,134,49,146,126,140,127,229,34,38,223,38, +20,128,237,128,50,62,77,104,208,58,177,104,102,128,103,38,152,128,153,38, +48,178,209,178,20,228,239,228,130,228,131,141,86,18,50,68,21,96,62,156, +63,52,92,76,233,58,182,22,213,46,218,82,158,120,105,136,144,14,154,78, +174,124,208,152,220,156,228,152,239,126,44,178,223,178,20,226,241,226,132,226, +133,147,60,10,91,32,18,40,141,40,114,86,114,62,48,62,48,86,115,86, +30,108,110,108,82,126,82,162,78,172,70,176,57,178,26,154,125,134,132,60, +208,60,208,82,208,108,210,132,216,150,220,162,226,162,243,130,138,88,183,130, +171,12,168,10,168,62,164,84,156,118,127,160,34,198,215,198,14,232,241,232, +126,232,127,181,22,34,133,34,114,100,114,54,38,54,38,100,115,100,38,76, +115,76,12,122,139,122,38,134,38,158,119,158,118,132,119,166,76,158,77,10, +136,78,148,72,154,62,156,32,202,32,202,56,206,66,216,70,235,68,140,90, +210,90,192,120,172,140,143,158,238,156,208,146,188,134,170,120,151,90,44,192, +207,192,20,228,233,228,130,228,131,177,110,18,141,36,20,48,237,48,77,56, +96,128,70,158,33,180,98,74,38,136,93,132,78,56,34,98,77,94,148,58, +130,86,109,108,132,168,133,84,168,60,193,78,228,86,139,86,220,110,141,110, +220,136,141,136,230,162,139,162,178,162,179,86,48,198,205,198,20,228,237,228, +124,228,125,185,32,92,32,60,142,60,143,92,82,12,83,60,124,38,83,38, +48,84,125,84,70,94,33,112,104,92,143,108,90,98,60,126,21,146,144,136, +83,106,148,44,218,44,212,68,200,96,186,122,162,146,155,152,232,158,206,140, +190,122,178,104,168,76,161,44,116,168,116,134,54,134,54,168,117,168,44,198, +211,198,18,230,243,230,132,230,133,167,16,84,99,84,18,196,107,162,58,178, +59,12,110,30,235,30,100,114,245,114,178,30,178,238,147,243,16,90,95,90, +18,202,103,176,58,188,59,14,120,38,227,38,110,98,243,98,152,98,140,154, +218,154,210,212,204,226,190,232,151,235,16,88,93,88,16,202,99,176,56,186, +57,20,154,14,122,76,93,114,234,62,131,62,114,114,198,114,166,152,146,176, +130,198,124,212,122,222,128,230,142,234,212,234,226,226,237,197,10,88,97,88, +12,198,97,168,54,180,55,16,118,20,118,138,114,178,102,208,79,238,166,220, +167,32,216,242,217,13,20,84,101,84,20,194,103,160,60,14,61,176,156,14, +189,46,240,62,122,62,122,148,118,180,104,216,79,241,16,94,101,94,16,204, +103,174,60,14,61,188,110,30,214,30,214,116,124,116,124,204,126,218,136,226, +168,228,208,228,226,220,237,199,16,94,103,94,18,202,105,174,62,14,63,186, +236,196,228,214,214,226,144,226,130,222,124,206,124,32,214,32,214,116,125,117, +16,80,97,80,14,188,99,162,56,12,57,174,244,36,116,36,116,136,106,188, +77,234,132,102,226,102,220,208,216,220,208,230,181,234,176,52,176,132,166,176, +150,210,121,241,20,80,101,80,18,196,105,170,60,12,61,182,232,24,170,36, +126,38,126,154,110,206,83,238,242,106,127,106,192,246,193,107,16,84,97,84, +14,184,99,162,56,12,57,172,220,18,168,30,120,32,120,130,108,178,71,228, +128,92,214,92,204,130,186,172,166,198,140,220,113,236,140,112,152,144,162,164, +186,192,206,212,237,231,16,88,89,88,16,196,99,168,56,14,57,182,98,76, +243,76,130,242,131,12,208,240,209,10,130,138,209,138,130,214,209,215,16,90, +97,90,18,200,101,168,56,16,57,184,112,78,239,78,188,20,219,56,150,12, +150,100,140,148,122,190,104,212,79,236,218,114,190,160,158,198,137,216,174,98, +174,216,178,228,188,236,216,236,237,205,20,94,105,94,20,206,105,176,62,16, +63,190,124,244,124,134,224,134,225,242,124,222,225,222,168,134,169,12,168,68, +243,69,18,82,95,82,16,188,99,166,58,12,59,176,222,174,222,90,116,90, +116,158,108,184,92,216,65,242,116,152,223,152,162,90,163,10,162,48,243,49, +18,80,97,80,16,190,101,168,58,10,59,178,226,20,172,30,122,34,122,144, +112,190,85,232,122,104,243,104,156,140,233,186,186,244,187,105,16,86,93,86, +12,196,95,168,54,18,55,180,220,22,166,34,112,38,112,222,159,184,154,212, +181,234,112,112,239,112,168,34,168,68,172,100,176,136,180,168,190,190,202,210, +218,226,222,230,226,230,234,222,241,201,18,94,95,94,16,220,109,184,62,22, +63,200,146,14,185,46,110,102,110,60,224,60,225,102,144,92,144,210,148,224, +158,234,206,234,224,224,233,204,218,118,145,165,8,80,93,80,14,186,91,160, +50,10,51,174,66,238,90,212,108,174,114,122,114,28,214,28,214,88,115,88, +152,110,152,210,154,224,164,232,214,232,226,226,232,214,237,196,226,132,153,165, +12,82,95,82,14,200,93,166,54,12,55,182,76,118,245,118,238,198,112,198, +120,32,216,32,208,210,204,228,198,236,186,238,173,240,150,56,183,94,148,142, +179,175,16,84,85,84,14,196,89,170,52,14,53,182,136,146,161,194,154,62, +90,200,155,184,130,20,88,106,135,102,166,82,232,82,224,202,220,222,210,230, +177,234,192,12,192,96,188,142,178,178,160,210,131,243,12,90,85,90,16,202, +95,176,52,18,53,188,82,38,231,38,74,224,241,224,136,224,137,38,176,224, +177,38,98,100,117,162,220,96,193,163,16,92,97,92,18,208,99,176,58,12, +59,190,102,28,239,28,192,56,231,118,162,36,116,106,215,96,116,162,233,162, +92,226,243,226,168,226,169,121,16,78,93,78,16,190,93,160,56,12,57,174, +110,242,110,32,228,32,228,236,197,244,132,78,207,78,196,176,196,118,144,118, +144,176,197,177,16,90,101,90,20,202,103,174,60,14,61,188,114,22,114,70, +224,70,225,20,168,8,169,70,116,104,218,104,218,154,120,154,120,208,122,222, +134,228,210,228,226,224,234,214,239,201,20,82,87,82,14,190,89,170,56,14, +57,178,82,32,130,32,92,112,128,112,120,158,106,192,84,216,59,234,94,134, +112,174,136,206,168,224,243,226,230,26,178,40,149,46,156,80,156,182,235,182, +190,182,191,36,230,110,191,111,14,92,101,92,18,206,97,172,58,188,59,12, +116,240,116,58,228,58,228,234,201,240,196,178,196,102,148,102,148,178,197,178, +168,14,149,59,16,86,95,86,14,196,93,170,58,180,59,12,140,16,175,44, +90,62,245,62,222,112,223,242,110,114,110,224,223,220,130,94,205,188,198,82, +174,142,137,197,20,86,99,86,20,202,101,166,60,184,61,16,156,14,187,42, +100,56,247,56,228,130,182,190,144,220,103,238,234,240,183,190,202,92,160,152, +113,190,166,64,120,126,181,123,18,90,103,90,16,204,105,176,62,12,63,188, +172,202,124,230,124,28,222,28,222,122,125,122,124,76,223,76,236,236,204,210, +186,182,176,154,169,122,236,142,187,179,18,92,97,92,18,208,99,182,60,12, +61,194,218,84,218,28,120,28,120,84,219,84,98,124,237,124,120,170,209,170, +94,226,243,226,168,226,169,125,14,90,83,90,14,208,87,180,54,14,55,190, +100,226,100,40,148,40,149,218,100,118,149,118,100,196,149,196,160,84,247,84, +168,118,191,164,216,12,216,236,183,245,16,82,91,82,16,198,89,170,56,14, +57,182,214,82,214,26,118,26,118,82,215,82,106,242,106,120,228,120,228,234, +197,240,168,82,168,122,162,148,148,172,123,198,202,190,165,143,18,94,97,94, +18,204,99,178,60,14,61,190,214,70,214,28,120,28,120,70,215,70,116,196, +116,104,224,104,225,192,168,128,166,164,162,190,150,210,132,224,110,232,93,238, +180,196,237,239,16,86,101,86,14,202,103,176,60,16,61,186,230,18,174,28, +103,34,114,58,139,104,156,48,177,92,98,132,245,132,226,48,205,84,120,160, +155,194,200,110,200,238,173,245,12,94,87,94,16,210,97,182,52,14,53,198, +138,12,169,38,100,88,100,50,228,50,229,84,118,92,205,92,94,138,235,138, +138,138,138,158,134,184,122,204,112,218,96,230,83,240,178,138,178,214,182,228, +192,236,214,236,226,230,237,207,16,90,93,90,14,204,101,172,56,20,57,188, +88,46,241,46,72,230,245,230,120,230,120,80,208,80,209,230,170,12,161,80, +120,116,209,116,120,154,209,154,120,192,209,193,14,90,91,90,14,208,95,182, +52,12,53,194,92,48,233,48,166,10,148,58,126,86,91,112,176,48,190,70, +216,94,239,108,210,188,210,116,114,116,114,188,211,188,160,82,160,216,164,228, +174,234,212,234,226,226,239,204,114,152,211,153,16,96,97,96,18,206,95,176, +60,20,61,190,208,100,208,30,116,30,116,100,209,100,116,64,209,64,146,108, +126,134,101,158,184,234,200,232,214,226,222,216,224,202,226,136,125,136,100,206, +124,190,144,170,154,150,163,136,194,136,184,170,166,198,144,220,124,236,115,241, +18,78,91,78,20,188,97,152,59,10,56,10,57,170,220,128,220,40,112,40, +112,128,221,128,166,40,166,58,166,86,162,112,154,130,140,146,113,164,166,6, +149,40,112,84,221,84,88,180,247,180,178,240,179,141,18,84,91,84,14,198, +93,172,56,16,57,182,158,14,138,54,116,84,89,108,156,20,172,46,188,64, +210,82,237,96,150,72,179,96,112,116,208,116,175,160,114,182,89,230,144,158, +175,186,206,176,235,216,136,176,136,220,140,232,146,238,182,238,198,230,203,211, +18,90,93,90,16,198,89,174,58,14,59,182,78,234,94,206,104,172,108,138, +108,110,108,34,150,34,150,226,125,232,108,92,151,92,108,146,151,146,158,240, +174,210,180,176,182,134,182,32,228,32,228,238,201,244,228,146,183,146,228,90, +183,91,14,84,89,84,55,18,16,190,97,162,53,18,54,18,55,176,148,12, +120,48,103,68,216,138,216,84,106,84,106,138,217,138,170,84,196,42,125,42, +160,84,156,142,144,174,118,206,96,224,69,240,194,164,219,188,166,154,166,218, +168,232,180,238,216,238,228,228,234,220,237,205,16,84,95,84,18,200,97,174, +58,12,59,186,118,82,216,82,216,24,119,24,122,52,217,52,104,136,104,110, +232,110,233,132,122,218,122,144,218,144,218,194,214,206,206,212,195,214,168,242, +169,111,16,84,89,84,16,200,93,174,56,14,57,186,102,78,245,78,108,40, +212,40,212,118,113,118,160,6,160,238,137,242,98,140,135,162,92,216,161,164, +232,218,202,194,180,166,161,132,222,136,179,163,16,84,87,84,16,192,87,166, +52,12,53,178,68,232,92,198,102,164,108,116,108,30,224,30,224,72,109,72, +140,104,140,154,222,154,223,104,230,174,231,242,130,174,130,228,231,222,178,90, +179,225,14,86,91,86,14,196,89,168,54,16,55,180,90,52,239,52,160,14, +160,92,204,92,205,10,120,18,120,122,233,122,98,156,239,156,166,244,167,132, +88,222,124,202,167,160,236,222,206,202,167,163,16,86,93,86,14,194,99,168, +56,14,57,180,96,32,243,32,220,132,220,76,110,76,110,132,221,132,144,132, +145,32,182,132,183,32,114,180,219,180,82,228,245,228,164,228,165,147,16,86, +91,86,18,200,97,174,56,16,57,186,224,84,224,30,110,30,110,84,225,84, +150,84,151,30,186,84,187,30,150,96,179,116,96,128,245,128,154,128,146,184, +130,212,97,238,150,164,220,164,212,220,206,230,198,234,177,237,16,80,81,80, +14,190,91,164,54,16,55,176,124,14,98,76,77,112,106,244,107,56,124,74, +241,74,144,30,210,30,205,74,158,84,127,138,230,114,141,114,122,160,243,160, +182,114,178,168,168,194,150,216,129,236,238,236,212,216,194,192,181,163,18,88, +89,88,18,200,87,176,54,16,55,186,90,32,241,32,212,94,212,58,120,58, +120,94,213,94,104,240,104,126,230,126,230,236,205,240,134,140,157,164,122,176, +211,176,196,140,171,176,166,230,167,177,18,86,97,86,20,200,91,172,56,12, +57,186,240,28,112,28,112,156,102,194,83,232,222,140,222,72,142,72,142,140, +223,140,142,104,223,104,186,36,171,72,154,166,125,220,208,168,237,216,184,140, +184,240,159,245,14,84,85,84,16,194,87,164,50,12,51,178,210,76,210,22, +112,22,112,76,211,76,112,50,211,50,230,142,230,104,94,104,94,142,231,142, +140,142,141,104,184,142,185,104,110,168,204,168,182,192,148,218,112,230,77,238, +118,168,136,192,164,216,198,228,239,237,14,88,91,88,14,198,89,176,54,20, +55,186,146,12,179,36,236,44,108,44,108,162,100,198,85,230,114,98,243,98, +126,74,220,74,220,124,127,124,132,244,132,146,224,146,224,238,203,244,178,242, +179,50,132,174,225,174,132,198,225,199,14,80,83,80,16,188,83,174,52,12, +53,180,88,18,121,40,82,54,113,74,90,134,113,90,146,50,135,90,224,54, +239,98,132,30,208,30,206,108,202,120,196,124,179,126,174,30,174,52,166,86, +150,112,140,122,127,130,96,158,221,158,156,242,157,142,80,226,116,200,151,158, +234,224,194,200,161,159,16,78,91,78,16,184,91,162,56,12,57,172,70,234, +90,204,102,176,108,144,110,122,110,26,224,26,224,60,111,60,126,78,157,94, +124,128,159,112,178,74,179,120,230,76,199,96,234,130,201,112,146,140,125,178, +180,244,181,144,228,164,133,164,114,198,243,199,243,210,24,38,137,38,36,56, +127,56,82,56,83,18,26,132,36,118,40,98,40,74,120,74,120,100,41,100, +82,100,83,74,146,56,154,50,156,40,158,28,200,28,200,54,229,54,144,72, +208,72,182,94,143,110,148,84,231,112,194,120,122,124,59,124,34,146,221,146, +18,184,58,176,86,162,117,146,236,182,196,172,164,162,141,146,130,166,131,124, +66,242,66,180,190,180,191,242,66,204,191,204,66,226,191,227,18,34,121,34, +28,56,113,56,76,56,77,16,114,94,114,74,38,74,38,94,115,94,44,104, +55,116,96,100,85,116,16,126,70,120,123,114,146,48,241,48,152,74,216,74, +200,98,184,112,164,122,141,128,158,74,166,92,180,106,200,124,237,136,182,74, +183,16,200,186,200,146,56,146,56,186,201,186,56,168,201,168,110,130,101,146, +130,146,124,174,112,192,94,202,63,208,16,218,239,218,142,246,143,203,14,46, +117,46,28,68,113,68,72,68,73,14,130,28,149,62,132,138,153,96,178,14, +161,80,216,82,224,52,169,52,190,70,184,108,176,126,166,140,151,154,234,148, +212,126,189,86,26,118,26,94,116,94,117,116,44,118,101,118,102,176,102,144, +42,144,42,176,103,176,46,192,59,216,20,230,111,220,98,188,81,222,144,180, +131,226,164,174,164,222,166,230,174,236,196,236,208,230,212,218,213,212,176,152, +195,184,216,178,237,219,14,62,239,62,92,112,93,12,166,112,167,13,12,48, +241,48,88,74,89,12,160,74,161,12,40,124,176,118,168,212,172,222,184,228, +212,228,224,222,230,212,237,196,118,72,110,142,94,180,70,206,29,233,16,52, +243,52,94,80,95,14,162,78,163,16,40,98,174,98,158,150,216,150,208,210, +204,222,192,230,159,232,92,98,92,118,86,160,76,188,58,210,27,235,18,54, +237,54,86,92,87,14,166,94,167,14,44,140,207,140,16,224,241,224,126,224, +127,87,22,46,235,46,96,78,97,10,162,78,163,10,210,84,140,96,45,100, +20,160,241,160,130,246,131,97,16,50,239,50,88,80,89,10,168,78,169,10, +38,98,180,98,158,142,202,144,176,178,142,206,106,224,59,238,104,144,120,168, +138,190,164,208,188,220,239,236,18,228,48,208,72,176,84,142,91,99,14,50, +239,50,88,90,89,14,164,88,165,12,34,120,184,120,176,210,178,224,184,234, +194,236,222,236,236,226,241,204,112,92,104,152,90,190,72,210,48,226,21,236, +56,162,135,199,18,46,241,46,94,68,95,10,162,68,163,10,44,90,194,90, +194,128,60,128,56,168,212,168,208,200,202,222,188,232,162,238,137,239,16,52, +239,52,92,70,93,16,156,70,157,16,40,96,196,96,196,148,54,148,54,208, +56,218,62,226,78,230,198,230,216,226,226,218,230,206,233,191,14,46,241,46, +90,68,91,10,160,68,161,10,212,126,182,178,148,208,102,226,33,236,182,92, +50,172,189,166,126,70,60,116,145,115,18,50,239,50,88,82,89,12,166,84, +167,12,48,110,203,110,32,152,227,152,128,70,126,130,122,160,112,186,94,204, +72,218,27,236,230,234,196,220,164,200,142,178,127,153,20,48,241,48,98,74, +99,8,162,72,163,10,50,100,211,100,24,146,235,146,104,146,104,176,98,194, +84,216,52,230,23,238,160,146,160,208,162,224,172,228,186,228,218,228,230,222, +236,212,239,197,20,48,245,48,94,72,95,10,164,72,165,8,48,104,207,104, +14,152,245,152,158,172,219,238,114,156,52,228,199,217,18,42,239,42,90,70, +91,12,162,68,163,10,14,98,243,98,58,224,58,136,202,136,202,220,179,224, +126,244,127,63,16,46,241,46,92,76,93,10,164,76,165,10,28,102,229,102, +48,146,178,146,144,188,100,218,50,234,27,238,78,146,98,174,134,204,178,222, +208,228,235,232,126,146,127,67,18,40,245,40,98,62,99,8,164,60,165,8, +236,90,54,90,54,174,44,206,29,240,82,142,212,138,210,210,204,226,190,232, +163,234,138,102,138,158,130,188,116,212,100,226,79,241,16,46,241,46,94,66, +95,14,166,64,167,12,226,90,58,90,58,150,50,198,29,244,154,190,174,186, +186,178,190,164,190,126,102,126,102,208,106,224,120,230,202,230,216,226,226,216, +233,199,16,52,243,52,220,100,48,100,48,234,231,234,48,140,194,140,194,188, +49,188,90,70,91,10,162,70,163,11,12,46,241,46,92,66,93,10,159,64, +160,64,161,8,52,90,52,234,127,200,124,134,53,134,150,92,150,210,154,222, +172,230,206,230,224,222,228,212,233,194,220,108,151,155,26,50,245,50,94,84, +95,16,176,82,177,14,22,228,247,228,74,228,75,114,142,228,143,82,142,140, +225,141,16,52,239,52,88,84,89,14,164,84,165,12,46,242,46,114,208,114, +208,236,173,240,130,76,126,120,118,152,100,174,77,194,178,186,123,139,12,46, +235,46,90,70,91,10,158,68,159,10,60,182,60,94,188,94,189,178,124,120, +118,160,104,190,82,210,52,226,19,238,142,158,142,218,146,228,158,232,208,232, +224,226,232,212,235,197,20,44,233,44,96,62,97,10,160,64,161,8,12,144, +235,144,84,84,84,232,135,204,180,74,115,128,132,144,144,168,170,196,200,216, +233,229,16,48,241,48,92,70,93,14,164,68,165,10,81,92,78,90,78,120, +72,166,58,198,38,222,19,240,124,192,77,138,170,92,164,140,152,176,136,208, +109,238,234,236,214,216,194,190,178,158,167,125,14,42,239,42,88,8,89,78, +162,6,163,76,128,62,104,92,72,118,40,136,19,148,240,140,202,130,168,110, +136,84,121,70,112,114,147,144,56,168,184,168,162,202,123,245,20,50,239,50, +100,72,101,18,166,70,167,16,82,84,52,122,27,148,158,236,188,234,200,222, +206,200,212,112,61,112,40,198,72,178,100,148,114,124,123,112,56,238,88,224, +120,200,144,170,160,138,171,113,16,44,237,44,88,60,89,10,158,62,159,8, +86,84,39,154,184,150,206,102,75,102,124,122,114,170,98,196,74,216,44,230, +27,238,230,234,208,226,176,208,148,182,121,141,18,42,239,42,92,56,93,8, +158,54,159,8,202,74,122,84,52,88,52,234,129,206,52,144,233,144,138,82, +142,120,148,168,168,208,196,234,210,240,216,238,222,234,235,203,16,46,241,46, +90,64,91,12,162,62,163,12,34,142,62,132,82,114,86,86,168,86,168,114, +170,124,180,134,198,134,229,132,52,158,178,158,154,184,108,214,58,230,29,238, +230,236,196,232,162,224,134,210,108,190,92,172,83,159,20,50,233,50,86,80, +87,12,164,80,165,10,112,72,145,96,14,120,237,120,120,120,121,244,200,196, +121,155,20,50,237,50,92,90,93,12,164,88,165,12,118,70,147,100,34,156, +34,114,224,114,225,154,24,226,237,227,20,40,235,40,86,56,87,10,160,58, +161,8,24,92,114,92,76,130,76,232,45,240,20,180,135,146,162,90,162,196, +164,218,174,226,186,228,212,228,222,222,230,212,235,199,14,48,241,48,94,78, +95,14,162,76,163,12,120,88,143,132,58,96,58,214,121,158,200,84,200,104, +196,150,186,190,154,214,118,230,99,236,232,228,191,183,18,48,231,48,88,76, +89,12,162,78,163,10,24,100,227,100,46,142,207,142,126,244,127,68,20,220, +56,204,94,174,125,144,238,218,212,208,180,192,150,166,131,143,16,48,241,48, +90,72,91,12,166,70,167,12,16,110,241,110,72,246,73,90,186,244,187,90, +72,162,187,162,72,222,187,223,18,54,237,54,96,84,97,14,162,84,163,12, +28,106,231,106,148,106,124,130,98,154,66,176,29,194,156,140,229,186,16,230, +241,230,132,230,133,123,22,46,237,46,94,76,95,10,162,72,163,8,32,114, +229,114,124,70,114,130,100,166,80,196,54,220,27,238,146,114,146,208,148,224, +160,230,206,230,224,222,228,212,231,198,202,138,158,180,130,198,97,216,178,80, +199,99,18,44,237,44,86,68,87,12,160,68,161,12,16,110,239,110,164,78, +191,100,118,64,102,120,84,156,62,182,42,200,23,218,228,234,198,226,160,212, +130,194,106,168,92,148,186,148,162,182,140,206,116,220,90,232,59,241,14,42, +241,42,90,74,91,12,162,72,163,10,56,246,56,92,200,92,201,246,56,134, +201,134,56,178,201,178,56,224,201,225,16,52,241,52,92,84,93,14,162,82, +163,12,16,230,243,230,70,230,70,102,190,102,191,230,70,144,191,144,70,188, +191,189,16,40,239,40,92,66,93,10,160,66,161,8,60,246,60,94,196,94, +196,236,167,244,14,182,245,182,60,138,197,138,124,182,125,63,16,44,241,44, +90,66,91,10,158,64,159,8,48,244,48,90,212,90,212,234,183,242,160,190, +160,132,94,132,94,190,161,191,18,46,241,46,96,62,97,10,164,62,165,10, +78,76,46,126,19,156,62,244,63,100,78,134,237,134,88,222,227,222,156,222, +157,89,14,44,241,44,90,60,91,10,162,60,163,10,84,78,44,136,23,158, +66,244,67,104,90,118,247,118,190,76,190,238,157,244,108,152,149,185,14,44, +243,44,88,76,89,8,168,76,169,8,134,64,76,120,21,152,126,72,148,94, +182,118,241,142,116,114,151,140,48,160,192,160,131,214,94,192,165,241,16,44, +239,44,90,70,91,10,166,70,167,8,154,140,174,138,186,130,192,88,68,88, +68,166,222,166,218,214,212,228,198,236,171,238,26,206,187,206,124,60,113,88, +94,112,137,139,16,44,237,44,90,70,91,10,166,70,167,10,110,82,40,98, +40,214,119,190,110,142,41,142,144,244,144,98,214,98,214,184,210,198,198,202, +183,205,14,44,243,44,90,72,91,8,162,72,163,8,108,82,52,98,52,178, +109,158,110,106,108,174,96,198,80,214,35,242,150,244,150,92,212,92,212,166, +210,178,200,186,179,191,20,52,235,52,94,82,95,16,164,84,165,16,34,136, +34,100,218,100,219,134,50,162,201,162,24,228,231,228,128,228,129,117,14,44, +239,44,98,68,99,14,164,68,165,10,34,126,34,86,222,86,223,124,58,120, +180,120,182,174,188,206,198,224,206,232,214,234,224,228,241,200,46,176,169,176, +108,242,109,121,14,42,239,42,94,60,95,12,162,60,163,10,58,122,200,122, +200,78,58,78,58,234,135,210,222,162,59,162,144,122,150,158,158,188,172,210, +186,228,202,238,218,236,233,209,16,48,243,48,98,76,99,10,166,76,167,12, +34,92,206,92,200,128,190,138,180,142,167,142,28,168,64,156,88,136,106,112, +117,92,70,246,70,170,204,170,205,242,70,224,205,225,24,44,233,44,94,76, +95,10,166,76,167,10,14,94,243,94,48,246,48,136,208,136,209,244,48,220, +209,220,106,94,106,150,100,172,86,184,67,196,150,94,150,168,152,178,156,182, +164,184,189,187,12,40,245,40,92,62,93,10,164,60,165,8,24,78,237,78, +38,106,206,106,206,136,52,136,42,166,220,166,218,180,212,190,202,196,191,196, +130,54,130,140,122,174,104,204,82,220,58,230,25,242,238,240,210,234,186,222, +160,206,144,186,133,167,16,40,241,40,94,56,95,8,162,56,163,6,26,100, +225,80,202,98,124,128,80,138,41,142,102,72,120,110,152,138,182,148,200,150, +214,146,223,126,20,170,237,170,28,238,50,232,72,222,90,206,98,188,103,170, +152,170,152,216,154,226,164,230,184,232,208,232,222,228,228,220,233,207,16,44, +239,44,92,64,93,14,160,60,161,10,56,72,56,152,123,128,120,96,57,96, +150,70,150,136,156,148,168,152,218,152,228,140,231,122,212,80,151,110,16,186, +241,186,128,244,129,149,14,52,241,52,96,72,97,12,160,70,161,8,20,230, +141,198,96,208,97,94,52,222,53,114,96,134,139,134,158,92,158,208,162,220, +168,224,178,226,218,226,232,222,236,210,241,194,224,110,159,155,16,46,243,46, +94,76,95,10,166,74,167,10,192,136,192,94,70,94,70,136,193,136,52,248, +52,172,214,172,215,244,52,224,213,225,18,44,241,44,94,72,95,12,162,72, +163,12,50,246,50,90,214,90,214,236,183,244,76,122,189,122,166,198,166,156, +98,156,98,198,167,199,12,44,243,44,90,78,91,12,166,78,167,10,48,244, +48,94,208,94,209,242,48,214,209,214,158,174,158,130,94,130,94,174,159,175, +18,40,239,40,92,68,93,8,166,68,167,8,72,72,45,124,206,98,59,98, +22,140,235,140,130,244,131,60,24,216,54,206,84,186,110,160,129,140,232,214, +194,198,162,176,131,141,14,46,243,46,92,74,93,14,160,74,161,14,218,80, +148,92,103,92,104,144,227,144,100,202,233,202,164,202,165,90,20,94,68,94, +40,148,84,148,78,174,70,200,52,220,21,240,34,166,56,198,84,220,118,232, +148,236,239,235,20,40,229,40,94,56,95,8,156,56,157,8,200,74,112,84, +49,84,18,120,235,120,20,180,50,170,80,152,102,130,114,106,121,84,238,170, +204,162,172,148,154,132,147,120,94,158,90,196,80,220,51,244,170,246,171,163, +22,46,245,46,96,72,97,10,170,70,171,10,88,76,52,126,25,158,66,244, +67,110,84,130,237,130,84,236,110,220,132,196,144,168,148,138,152,116,153,78, +232,232,200,208,178,180,164,154,157,130,184,82,217,111,16,50,241,50,96,72, +97,12,162,72,163,12,78,82,48,134,19,168,62,244,63,110,212,92,176,100, +103,108,76,158,239,158,88,226,225,226,152,226,153,103,16,44,239,44,98,68, +99,12,162,68,163,10,76,76,27,126,84,120,19,186,66,246,67,138,110,90, +219,90,98,138,245,138,154,236,172,236,184,230,188,220,189,139,16,46,241,46, +90,76,91,12,168,74,169,10,136,66,94,110,60,130,19,150,238,146,196,128, +156,102,129,76,66,138,191,138,62,180,197,180,34,232,227,232,130,232,131,139, +20,46,239,46,92,72,93,12,166,72,167,10,130,60,102,92,68,114,25,136, +124,68,150,90,188,110,237,126,72,132,187,132,36,170,221,170,110,176,62,230, +187,218,166,190,209,243,22,48,241,48,94,74,95,14,162,78,163,14,74,82, +50,122,21,150,164,238,184,238,202,232,208,216,212,102,63,102,154,208,154,134, +76,134,76,208,155,208,76,172,155,173,20,46,245,46,94,68,95,14,170,70, +171,12,128,66,84,96,49,118,20,174,82,160,138,136,196,92,93,92,90,116, +127,140,82,244,82,162,208,162,209,240,82,220,209,221,18,42,237,42,92,68, +93,10,164,68,165,10,114,58,147,76,24,88,229,88,76,102,114,126,158,144, +208,154,241,158,20,162,54,158,92,150,120,138,150,118,179,88,42,240,64,230, +88,210,96,182,101,158,172,242,173,163,16,46,243,46,92,78,93,10,166,76, +167,10,116,62,145,90,22,102,235,102,96,118,39,162,164,118,223,156,90,154, +146,202,194,228,231,240,168,144,128,196,92,220,35,241,14,42,237,42,88,62, +89,8,152,62,153,8,20,90,227,90,108,60,139,82,150,114,211,154,110,100, +54,154,197,146,24,240,50,230,76,216,92,198,98,174,101,152,232,200,226,222, +210,230,168,230,156,224,152,208,153,149,16,48,241,48,96,82,97,10,162,80, +163,10,42,82,81,108,26,128,67,152,32,240,79,172,94,104,223,104,82,224, +241,224,160,224,161,105,18,44,239,44,94,68,95,10,160,68,161,10,36,116, +36,84,220,84,221,116,84,106,47,164,200,140,65,140,16,186,241,186,128,246, +129,97,16,46,235,46,90,70,91,12,160,70,161,12,34,122,34,90,218,90, +219,122,30,146,96,146,84,178,66,198,44,214,19,226,128,106,128,240,101,244, +236,222,204,208,176,188,154,162,129,122,204,124,157,165,16,42,241,42,96,66, +97,8,162,66,163,10,44,84,200,84,200,144,45,144,54,114,201,114,12,180, +243,180,174,156,174,220,172,230,166,236,140,242,135,242,68,190,107,219,14,44, +241,44,92,68,93,10,162,68,163,10,54,154,192,154,192,82,54,82,54,232, +123,202,54,118,193,118,230,232,198,222,170,210,138,182,119,154,212,166,165,205, +16,42,239,42,94,70,95,10,160,70,161,10,20,212,46,190,60,164,70,140, +70,86,194,86,194,128,71,128,238,200,208,184,182,162,161,128,100,162,167,190, +82,200,177,237,12,44,241,44,94,72,95,10,162,70,163,12,36,82,216,82, +197,128,78,98,123,128,62,134,105,160,12,176,243,176,154,100,148,140,142,166, +134,190,110,212,78,226,43,232,150,194,223,239,14,42,241,42,92,68,93,8, +164,70,165,8,30,90,110,90,78,126,78,240,51,244,18,186,111,148,180,78, +180,234,155,242,144,118,117,204,204,118,237,197,16,48,241,48,94,76,95,10, +162,76,163,10,110,114,34,190,113,178,28,234,115,214,76,78,30,136,87,136, +130,100,227,100,122,226,243,226,180,226,181,101,16,44,237,44,94,66,95,14, +162,66,163,12,106,98,28,180,111,162,70,70,26,126,81,124,22,228,109,208, +124,110,239,110,128,138,157,176,200,64,200,236,169,243,16,40,239,40,96,60, +97,8,160,60,161,6,18,118,97,118,20,206,107,180,64,68,65,190,140,66, +122,116,105,144,206,142,220,102,129,102,160,124,158,166,146,192,130,212,91,236, +230,236,206,220,184,196,168,170,161,149,18,44,241,44,90,68,91,12,166,68, +167,10,26,82,229,82,38,156,38,118,216,118,217,154,128,60,129,118,64,146, +174,146,132,172,132,220,130,230,122,236,95,238,16,188,239,189,14,46,241,46, +92,76,93,8,162,78,163,8,40,234,40,96,96,96,97,228,40,150,97,150, +40,210,97,210,120,118,245,118,200,70,200,214,196,224,184,234,157,234,136,146, +169,185,18,42,239,42,92,64,93,8,166,62,167,8,190,120,190,78,66,78, +66,120,191,120,44,244,44,154,216,154,216,218,212,230,202,236,179,236,128,120, +126,162,118,182,104,198,73,216,182,212,125,173,16,38,239,38,92,64,93,8, +158,60,159,8,198,66,148,74,53,76,24,106,231,106,126,146,127,76,24,164, +56,154,92,132,121,106,232,152,198,142,162,130,131,106,64,160,166,160,158,186, +204,186,196,216,184,228,170,232,149,232,34,238,62,230,84,212,100,186,105,161, +20,42,237,42,94,66,95,10,164,64,165,6,126,78,84,86,47,88,18,126, +237,126,26,188,135,162,88,86,88,220,84,230,70,238,55,238,180,80,209,106, +208,146,174,194,119,228,152,70,156,140,168,182,182,210,206,234,212,238,220,238, +235,209,16,42,243,42,96,58,97,10,168,60,169,8,82,64,58,92,33,116, +226,82,69,82,16,156,243,156,228,204,62,204,72,110,204,110,198,220,186,234, +170,238,149,238,120,124,143,142,116,168,145,191,18,46,243,46,96,74,97,10, +166,72,167,10,76,78,48,134,21,172,58,244,59,114,96,202,97,108,156,76, +134,124,113,158,238,114,141,114,140,142,156,172,180,198,212,222,237,234,96,236, +134,220,164,196,184,168,194,138,199,115,18,48,245,48,98,74,99,10,166,74, +167,10,80,78,56,120,19,158,58,246,59,116,136,82,169,110,88,120,233,120, +110,142,141,202,76,226,245,226,204,136,167,227,22,40,241,40,86,72,87,10, +172,70,173,8,126,60,84,104,44,132,17,140,122,66,138,82,176,110,239,132, +84,124,171,124,44,160,215,160,84,186,37,226,164,188,219,224,130,124,130,216, +126,228,116,236,97,237,18,44,239,44,88,10,89,72,160,72,161,8,128,64, +84,108,19,142,238,140,186,122,148,98,121,72,72,132,181,132,66,162,91,210, +114,146,131,196,22,232,231,232,188,158,155,233,16,42,241,42,94,64,95,14, +160,62,161,10,208,68,144,80,41,86,52,98,73,124,114,96,135,122,206,94, +169,128,44,138,192,138,132,174,132,216,128,226,114,236,97,236,16,186,243,187, +24,42,239,42,92,68,93,10,164,64,165,10,206,70,130,84,45,88,62,102, +85,136,126,96,143,126,202,96,173,136,14,156,245,156,118,130,80,190,231,232, +178,156,168,180,136,214,92,230,39,239,16,44,239,44,94,60,95,14,162,58, +163,12,188,74,221,102,34,76,62,98,76,118,88,152,88,206,82,224,72,232, +45,236,88,80,50,116,19,138,18,198,56,166,83,138,104,122,239,122,162,80, +162,128,154,168,144,198,126,222,105,240,180,144,180,212,186,226,196,234,220,234, +232,226,238,216,239,201,18,46,241,46,92,66,93,8,168,64,169,8,36,80, +66,104,80,126,88,154,88,200,82,218,70,230,52,236,39,236,26,192,85,142, +28,136,89,88,124,106,113,166,218,102,189,152,160,86,160,136,154,176,136,206, +118,226,97,242,232,238,206,224,184,200,166,170,159,149,18,38,241,38,92,68, +93,12,166,68,167,8,114,62,145,82,40,92,215,92,72,110,101,138,18,146, +241,146,176,108,149,146,34,190,223,190,130,244,131,147,16,40,239,40,90,68, +91,10,168,68,169,10,114,56,143,80,38,128,38,90,220,90,221,126,60,124, +193,124,28,158,235,158,22,238,48,232,76,224,96,202,106,180,109,158,154,158, +154,216,158,228,174,234,214,234,226,226,230,216,233,201,14,46,241,46,94,76, +95,12,168,76,169,12,116,64,147,82,116,206,58,236,58,96,192,96,192,160, +59,160,58,128,193,128,234,238,196,226,158,206,134,180,123,160,216,170,171,213, +22,40,235,40,96,66,97,8,166,64,167,6,36,112,36,80,224,80,225,110, +121,86,104,132,137,148,156,146,168,146,180,142,188,130,188,114,76,114,76,174, +212,174,212,190,210,202,208,216,196,230,180,234,159,238,32,208,173,208,120,86, +105,115,14,42,239,42,92,68,93,10,158,68,159,8,92,104,28,178,97,168, +66,70,26,126,73,126,18,228,101,206,106,102,233,102,120,130,120,182,208,182, +209,130,164,80,164,212,168,224,182,234,214,234,228,226,234,216,237,203,18,34, +241,34,90,58,91,10,164,58,165,8,38,76,221,76,50,100,209,100,16,126, +243,126,128,126,129,52,64,246,64,152,198,152,198,222,196,230,188,238,167,238, +64,178,199,178,64,206,199,207,18,42,239,42,94,62,95,14,156,62,157,10, +36,90,219,90,16,182,241,182,76,182,77,68,178,182,179,64,76,120,179,120, +76,150,179,150,102,198,76,220,39,240,152,198,223,239,18,40,237,40,94,70, +95,10,166,68,167,8,20,110,107,110,64,240,65,62,18,204,44,164,65,122, +98,166,65,136,214,76,170,86,130,92,130,154,126,184,114,212,97,236,238,138, +131,138,186,240,187,139,20,44,241,44,96,74,97,12,162,74,163,12,16,116, +107,116,66,244,67,66,18,200,44,170,67,126,96,176,67,138,150,84,103,154, +178,80,194,116,214,140,239,158,182,164,225,234,164,134,116,224,213,219,18,40, +18,40,239,40,94,14,94,74,166,74,167,12,206,140,206,98,60,98,60,140, +207,140,38,170,223,170,52,196,213,196,14,228,243,228,130,228,131,75,26,40, +233,40,92,68,93,12,166,66,167,10,124,58,94,104,62,134,19,158,20,88, +239,88,236,150,204,136,172,114,149,88,86,128,173,128,54,162,205,162,84,182, +37,226,164,186,217,224,130,162,130,220,126,228,116,236,97,237,22,40,235,40, +92,58,93,14,166,58,167,12,38,76,223,76,50,100,192,100,192,152,51,152, +22,126,233,126,126,54,127,152,24,180,233,180,124,158,84,200,223,234,174,180, +148,212,116,228,74,236,39,237,14,44,243,44,90,72,91,12,156,70,157,12, +178,76,209,100,14,110,97,110,20,178,95,154,60,68,60,226,58,234,48,238, +33,238,144,90,128,150,110,186,87,220,116,112,241,112,136,146,202,146,194,172, +178,196,158,218,130,230,107,238,140,162,152,186,172,206,202,226,237,239,14,44, +237,44,92,70,93,10,162,70,163,10,14,144,127,144,64,144,65,70,64,106, +117,106,46,168,19,212,96,172,125,210,70,144,70,222,68,230,58,238,45,238, +136,98,216,98,204,138,188,172,162,202,123,234,236,232,210,218,184,190,168,168, +154,138,147,99,12,38,243,38,94,58,95,8,162,56,163,8,198,132,198,72, +62,72,62,132,199,132,62,102,199,102,46,246,46,160,216,160,217,244,46,228, +217,228,46,196,217,197,14,42,239,42,94,66,95,8,160,64,161,8,32,210, +32,108,102,108,102,188,100,198,94,204,87,204,68,244,69,66,140,244,140,148, +216,148,217,240,140,216,217,216,172,148,173,78,172,102,235,103,16,40,241,40, +90,64,91,8,170,64,171,6,96,82,56,88,56,164,204,164,204,86,163,86, +164,122,205,122,94,122,57,122,130,62,126,136,118,176,96,204,66,224,23,240, +234,238,204,228,166,208,144,184,133,165,16,44,243,44,98,62,99,8,164,62, +165,10,80,74,48,122,25,152,62,244,63,102,118,70,153,98,70,110,227,110, +70,148,217,148,70,188,217,188,70,224,235,224,144,224,145,111,16,42,239,42, +96,70,97,6,162,70,163,8,200,152,200,86,54,86,54,152,201,152,54,120, +201,120,122,56,113,84,130,86,126,132,114,158,94,170,72,178,53,182,14,196, +245,196,148,242,149,165,14,38,239,38,94,62,95,8,162,64,163,8,18,238, +36,208,42,170,44,138,44,80,100,80,100,220,98,232,88,238,69,238,44,122, +101,122,44,162,101,162,170,124,200,122,210,114,214,80,136,80,137,246,136,150, +216,150,200,190,155,234,156,162,188,206,239,235,14,40,231,40,88,56,89,10, +158,58,159,8,116,56,74,92,31,118,198,164,198,118,60,118,60,164,199,164, +136,118,168,82,87,82,126,118,118,168,104,190,84,208,56,226,25,238,172,178, +203,208,142,178,142,216,144,228,156,236,210,236,222,230,230,218,233,205,16,44, +241,44,90,60,91,12,164,64,165,10,116,66,70,102,27,126,160,126,188,92, +85,92,114,134,54,142,55,242,154,140,212,140,213,242,112,180,55,180,154,180, +213,180,54,220,213,221,18,42,235,42,90,72,91,12,168,72,169,10,118,58, +147,82,26,92,229,92,94,106,49,166,120,156,79,126,178,108,141,160,216,160, +165,126,14,190,241,190,130,244,131,169,24,42,235,42,92,68,93,8,160,68, +161,8,48,74,79,98,18,110,115,110,62,110,62,136,56,168,48,196,36,220, +25,236,58,154,100,154,98,212,94,224,84,230,71,230,178,76,125,152,232,148, +196,120,171,88,160,150,199,178,146,196,215,231,16,44,239,44,88,68,89,12, +158,68,159,12,46,72,83,104,20,120,63,148,34,232,85,150,84,230,241,230, +120,230,120,86,206,86,207,230,120,130,207,130,120,178,207,179,18,44,245,44, +94,68,95,10,168,68,169,10,118,62,151,78,44,118,44,92,220,92,221,116, +24,134,243,134,22,204,68,176,90,154,107,134,80,244,80,176,202,176,203,242, +80,220,203,221,16,42,239,42,94,68,95,8,160,66,161,8,118,56,137,76, +36,124,36,84,226,84,227,122,72,246,72,116,182,116,182,152,73,152,72,184, +200,184,201,244,72,226,201,227,18,40,241,40,90,68,91,10,164,68,165,10, +116,56,141,76,44,116,44,86,216,86,217,114,82,100,56,144,27,176,26,236, +66,218,98,186,112,152,116,132,65,132,62,168,91,194,168,186,186,184,196,172, +200,126,140,126,140,206,142,220,150,230,206,230,222,226,228,216,231,203,26,42, +237,42,96,66,97,10,164,66,165,10,36,116,36,80,226,80,227,116,168,142, +221,180,186,104,62,172,199,164,134,86,70,130,149,124,92,192,35,226,172,192, +231,224,134,168,134,220,126,232,118,236,103,237,14,42,241,42,94,66,95,12, +160,64,161,12,20,82,100,82,62,122,62,216,58,230,50,236,33,236,16,178, +103,146,220,70,168,80,122,84,122,150,114,192,85,238,180,190,201,236,158,82, +152,234,189,210,196,76,196,112,202,152,210,190,239,233,16,40,241,40,92,66, +93,10,156,64,157,8,78,80,164,80,128,116,128,186,126,194,118,200,107,200, +72,110,103,134,60,180,113,154,182,108,155,138,182,184,129,148,214,244,215,92, +40,96,40,226,213,223,14,40,239,40,90,60,91,10,162,64,163,10,26,82, +121,82,36,108,113,108,28,136,125,136,76,168,77,74,136,82,216,82,212,138, +208,148,196,154,185,156,166,82,162,114,154,134,138,148,125,158,20,186,235,186, +124,176,116,200,98,222,64,236,29,240,126,186,138,204,162,222,190,234,233,241, +16,40,239,40,98,62,99,10,160,62,161,8,28,102,121,102,16,138,129,138, +72,138,73,76,26,178,123,178,24,228,129,210,74,154,75,218,136,112,243,112, +200,66,200,210,196,226,182,236,165,236,142,140,169,175,16,38,239,38,102,64, +103,10,156,62,157,8,32,84,221,84,16,172,243,172,62,172,62,232,223,232, +120,186,81,212,152,186,197,212,76,172,77,56,182,172,183,58,76,114,183,114, +76,140,181,141,12,46,241,46,90,72,91,12,160,74,161,12,16,114,109,114, +66,244,67,70,18,198,67,132,104,180,67,140,126,244,126,86,216,86,217,244, +126,130,217,130,126,176,217,176,126,222,217,223,16,44,243,44,92,74,93,14, +156,64,157,12,226,98,46,98,46,168,38,202,17,234,188,72,215,88,70,128, +147,128,64,162,136,162,126,184,112,204,92,220,69,232,104,136,82,188,133,220, +160,80,164,122,172,160,188,200,202,220,220,236,228,236,243,204,208,130,194,168, +172,202,152,224,137,239,16,42,243,42,96,68,97,10,158,62,159,8,200,60, +223,80,234,94,50,94,50,146,46,184,36,210,17,236,82,198,82,122,144,122, +145,194,114,140,114,176,104,204,88,222,67,232,142,222,109,194,176,68,176,116, +180,162,190,196,198,218,210,232,216,236,222,236,228,236,243,206,220,122,204,164, +180,206,145,241,12,44,241,44,90,60,91,10,162,58,163,12,48,58,48,146, +121,120,48,92,123,92,144,68,144,120,146,128,158,138,210,138,224,132,230,120, +233,106,212,78,145,106,66,244,66,162,188,162,189,242,66,194,189,194,66,226, +189,226,122,136,113,163,14,38,243,38,92,56,93,12,160,56,161,10,188,100, +188,72,64,72,64,100,189,100,24,124,233,124,14,212,241,202,188,246,189,124, +64,124,65,210,64,152,189,152,64,178,189,179,20,38,239,38,94,54,95,8, +164,56,165,6,194,108,194,78,64,78,64,108,195,108,14,134,245,134,126,134, +127,54,64,210,64,158,196,158,197,206,130,170,114,202,100,218,74,232,29,238, +136,206,227,241,20,40,241,40,94,62,95,10,164,62,165,8,192,148,192,76, +66,76,66,148,193,148,66,112,193,112,128,148,129,76,52,174,27,224,116,166, +145,196,198,172,235,212,86,168,86,218,90,228,104,236,160,236,174,228,182,218, +185,205,12,40,241,40,90,62,91,10,164,60,165,10,110,106,110,74,50,74, +50,106,111,106,206,104,206,72,144,72,144,104,207,104,44,134,213,134,18,162, +243,162,82,162,78,190,192,190,186,218,182,226,164,238,97,239,22,42,241,42, +98,68,99,10,166,68,167,10,80,66,48,118,17,154,62,246,63,96,208,128, +208,86,108,86,108,128,209,128,78,162,245,162,158,244,159,128,86,228,130,192, +155,162,240,222,212,208,188,190,165,163,14,46,237,46,92,78,93,10,166,76, +167,8,32,232,32,106,86,106,87,228,32,208,87,208,32,154,85,154,64,72, +47,106,236,202,230,216,220,230,206,236,148,236,136,232,126,224,124,212,124,98, +210,98,210,164,125,164,164,164,165,99,16,36,243,36,90,60,91,10,166,62, +167,8,116,50,139,68,26,78,237,78,192,130,192,100,68,100,68,130,193,130, +36,190,36,154,226,154,227,188,58,182,203,182,98,238,120,238,134,234,140,222, +141,183,22,44,239,44,96,68,97,12,168,68,169,12,30,104,227,104,66,70, +99,94,198,72,163,96,130,132,131,62,38,152,66,142,94,128,121,104,224,152, +190,142,158,122,139,104,20,172,239,172,120,148,82,196,223,236,40,236,76,234, +112,226,156,202,181,173,14,44,239,44,92,72,93,8,160,70,161,8,38,70, +79,98,22,112,63,138,22,236,59,162,214,76,150,86,102,88,102,132,94,184, +67,242,210,106,130,122,130,232,167,204,162,116,170,154,186,192,210,220,233,238, +220,136,181,177,18,40,241,40,92,66,93,8,164,66,165,8,118,58,143,76, +36,122,36,86,222,86,223,122,56,112,201,112,186,204,186,142,72,142,72,204, +187,204,30,234,231,234,72,174,187,175,12,40,241,40,90,62,91,8,162,60, +163,8,40,246,40,80,108,80,108,120,41,120,40,162,107,162,40,204,113,204, +132,126,208,126,208,78,135,78,124,160,210,160,194,190,168,216,138,232,103,242, +234,238,204,228,180,216,162,196,141,161,16,40,241,40,92,58,93,12,162,56, +163,10,42,78,217,78,58,102,201,102,26,126,235,126,126,58,114,108,90,136, +56,160,21,178,238,176,210,164,186,146,167,126,164,144,126,154,91,154,64,184, +197,184,128,244,129,154,48,236,90,216,112,198,127,184,216,234,178,212,131,185, +16,34,235,34,90,50,91,10,164,50,165,8,46,66,173,66,16,90,245,90, +122,90,123,52,198,50,148,86,108,108,62,126,21,136,80,118,78,134,80,144, +92,150,184,150,202,146,212,140,217,130,208,104,81,134,68,242,68,174,196,174, +197,240,68,200,197,200,68,228,197,229,18,40,233,40,158,56,159,8,96,56, +97,8,212,72,50,72,50,146,46,178,27,230,70,96,203,96,50,120,233,120, +88,120,88,166,133,152,234,166,188,156,160,142,137,120,200,128,177,148,58,190, +233,190,178,168,178,222,176,232,162,240,147,240,92,204,127,229,14,36,241,36, +188,108,188,62,66,62,66,108,189,108,66,86,189,86,100,50,101,14,156,50, +157,14,18,132,241,132,18,182,52,166,82,144,115,108,238,178,206,166,184,154, +155,132,84,174,76,196,202,196,200,224,198,232,188,238,167,238,80,160,166,160, +165,196,34,220,173,221,18,40,237,40,94,60,95,8,160,60,161,8,194,160, +194,74,58,74,58,160,195,160,80,106,175,106,128,86,122,118,112,132,85,146, +170,142,123,118,52,178,25,228,118,178,153,198,200,178,233,218,84,176,84,216, +90,228,106,234,160,234,176,226,182,216,185,205,16,40,243,40,94,66,95,10, +166,66,167,10,136,60,163,86,74,68,50,112,17,156,58,246,59,98,90,94, +231,94,78,142,245,142,120,106,141,142,200,106,175,142,110,246,110,176,210,176, +211,244,110,222,211,223,22,42,237,42,88,64,89,14,172,62,173,14,112,68, +68,92,27,108,146,64,190,90,233,104,146,102,193,136,128,88,66,134,175,124, +26,156,108,156,108,226,102,234,92,238,79,238,26,224,109,200,142,172,175,188, +134,156,216,156,216,220,212,228,200,236,187,236,132,218,217,196,36,176,71,189, +20,36,237,36,90,66,91,12,164,64,165,10,114,56,143,78,16,82,241,82, +182,138,182,110,72,110,72,138,183,138,44,244,44,162,212,162,212,216,208,228, +198,234,185,236,166,214,166,186,88,186,88,214,167,215,18,40,241,40,94,66, +95,8,170,66,171,8,122,56,145,74,230,84,66,84,66,150,60,186,31,234, +24,98,49,128,16,168,67,146,122,98,102,136,87,152,208,126,109,126,78,166, +231,166,82,238,114,220,140,192,150,158,155,126,234,230,198,214,172,192,151,167, +10,44,245,44,90,72,91,12,160,70,161,14,112,60,141,78,18,88,237,88, +62,102,62,148,192,148,193,102,92,102,173,134,166,98,85,136,46,244,46,174, +212,174,212,222,208,234,196,240,185,240,152,188,181,222,128,148,88,220,165,207, +18,40,237,40,92,64,93,12,166,62,167,10,114,54,145,72,44,82,219,82, +40,142,40,118,220,118,221,144,84,92,103,118,172,90,149,118,114,130,149,148, +22,158,239,158,102,158,102,172,98,194,84,214,60,228,41,238,100,186,200,186, +196,218,190,228,178,236,151,237,16,38,237,38,98,50,99,10,154,48,155,10, +72,60,103,82,181,58,28,90,229,90,178,56,151,90,18,146,237,146,48,120, +204,120,204,174,49,174,104,246,105,90,146,246,147,90,28,238,62,214,99,174, +224,236,198,222,178,206,160,188,151,175,20,40,245,40,98,62,99,8,166,60, +167,8,26,108,141,108,48,62,71,94,122,64,93,108,49,126,124,124,125,190, +46,126,46,176,125,172,24,240,50,226,70,202,82,176,89,108,112,238,138,216, +154,184,158,146,158,82,222,82,222,210,218,224,210,230,189,230,158,126,223,126, +156,170,223,171,20,40,241,40,94,70,95,10,166,64,167,8,132,68,163,84, +46,76,81,102,24,120,61,146,30,236,73,172,152,208,104,238,104,94,206,94, +206,154,105,154,206,124,105,124,215,172,148,154,172,190,202,218,229,232,214,172, +183,201,24,42,231,42,98,68,99,12,162,68,163,10,38,122,38,86,216,86, +217,122,124,100,90,130,58,146,31,160,124,100,152,118,184,136,233,152,76,146, +181,146,58,182,205,182,34,228,227,228,74,198,101,216,180,196,157,228,130,146, +131,229,18,36,245,36,96,60,97,10,164,60,165,8,46,106,85,130,30,76, +102,76,73,122,14,134,114,134,103,172,70,134,70,218,66,228,56,236,45,236, +126,76,239,76,140,202,140,116,218,116,219,200,168,116,177,76,182,138,180,176, +172,202,154,222,117,240,188,208,237,239,10,42,235,42,90,60,91,10,156,58, +157,8,20,96,133,96,78,78,79,246,114,160,114,124,38,124,38,158,115,158, +18,228,44,208,79,164,116,204,79,172,168,70,150,118,135,146,206,142,216,106, +155,106,174,128,166,174,152,204,130,226,107,240,236,238,212,222,194,200,180,174, +171,151,20,44,239,44,94,58,95,14,160,56,161,12,200,106,200,74,56,74, +56,106,201,106,152,74,153,106,104,74,105,106,34,154,34,128,224,128,225,154, +54,154,205,154,126,224,60,238,87,154,106,196,141,214,80,178,174,178,166,212, +166,224,168,232,182,236,212,236,222,230,228,220,231,209,14,40,241,40,94,62, +95,12,164,62,165,12,84,76,46,92,46,160,85,140,176,80,212,80,212,154, +177,154,152,148,152,88,100,88,100,148,153,148,132,60,117,88,100,118,153,118, +104,168,94,202,76,220,52,232,23,240,154,166,154,214,156,224,168,232,212,232, +228,222,237,201,16,36,241,36,96,60,97,8,166,54,167,6,92,128,241,128, +126,74,127,128,168,70,169,128,168,92,229,92,72,66,52,92,21,120,84,110, +64,136,21,178,56,244,57,144,126,154,114,198,91,236,240,226,172,222,142,210, +119,184,170,142,171,220,226,174,171,175,16,44,241,44,94,58,95,12,162,58, +163,12,80,76,54,110,21,136,126,118,77,82,166,76,144,120,133,138,232,114, +149,114,54,128,109,128,28,228,133,206,118,152,101,212,70,148,87,182,36,160, +61,196,148,138,164,172,188,202,210,222,235,236,120,240,148,224,170,204,188,176, +198,148,203,115,14,40,243,40,92,58,93,8,160,56,161,8,48,66,87,94, +16,106,115,106,56,106,56,136,50,178,40,206,21,240,54,146,100,146,92,208, +86,222,74,230,61,230,146,66,136,92,115,124,228,92,137,92,156,108,142,140, +127,160,222,134,147,134,112,176,239,176,176,134,172,172,166,188,154,208,136,224, +113,238,234,236,206,222,186,198,175,177,20,38,239,38,94,62,95,8,160,62, +161,8,50,68,75,94,44,240,45,102,102,80,212,80,212,220,208,230,200,236, +183,236,102,102,82,130,61,156,84,228,85,126,124,98,153,114,186,124,97,124, +178,150,97,150,180,178,97,178,190,208,97,208,136,208,137,125,22,36,233,36, +94,54,95,12,158,54,159,10,44,60,83,82,28,88,65,108,30,156,85,118, +222,70,112,70,112,146,223,146,112,118,200,118,200,94,113,94,22,178,235,178, +128,244,129,162,30,234,62,222,92,204,121,178,230,230,196,220,168,206,137,179, +14,36,239,36,92,62,93,10,164,60,165,8,116,54,143,72,34,118,34,84, +222,84,223,114,56,120,103,120,32,158,113,158,68,158,66,188,58,212,44,230, +27,246,98,158,98,212,102,226,122,236,198,236,222,230,232,218,237,204,142,152, +200,152,180,184,162,200,127,216,142,172,209,204,162,152,163,100,162,120,201,121, +20,40,243,40,92,64,93,6,166,60,167,6,118,56,145,74,36,114,36,84, +222,84,223,106,86,96,52,142,27,168,62,246,63,130,100,118,205,118,112,246, +112,156,204,156,205,246,112,190,205,190,112,224,205,224,156,118,145,157,18,34, +237,34,92,48,93,8,166,48,167,6,38,68,110,68,111,116,52,84,71,92, +146,82,165,88,42,124,111,100,136,68,206,68,207,128,158,112,207,100,128,112, +96,138,70,154,38,168,19,174,122,118,148,134,180,148,241,162,134,146,98,172, +55,192,162,164,116,198,63,216,196,182,158,212,106,232,51,241,16,44,241,44, +88,60,89,14,168,60,169,14,32,76,221,76,196,150,196,100,60,100,60,150, +197,150,60,126,197,126,188,158,223,188,32,178,205,174,126,174,127,60,50,200, +23,236,122,192,147,214,198,196,237,228,88,190,88,220,88,228,100,238,156,238, +172,230,185,209,18,38,239,38,90,54,91,8,162,54,163,6,28,70,229,70, +210,124,210,96,46,96,46,124,211,124,102,124,103,70,156,124,157,70,192,190, +192,146,64,146,64,190,193,190,64,168,193,168,16,216,241,216,130,248,131,191, +22,42,243,42,100,64,101,12,168,64,169,12,240,80,44,80,44,158,40,190, +21,234,76,94,95,116,62,124,145,124,132,94,113,124,132,142,133,198,74,142, +74,188,133,180,102,124,102,170,98,200,82,222,67,240,178,92,164,132,151,162, +210,154,218,126,167,126,180,144,168,192,150,218,121,242,236,238,210,216,192,194, +177,165,14,46,241,46,92,66,93,10,160,66,161,10,126,88,21,88,84,88, +62,112,21,136,56,114,70,128,82,148,88,176,88,200,82,216,70,232,56,236, +41,236,20,174,46,158,73,134,18,208,54,188,85,164,122,116,85,146,106,130, +114,162,130,198,146,212,174,224,206,228,239,230,158,86,141,130,232,98,155,98, +154,138,227,138,142,184,237,184,188,184,189,69,16,36,239,36,94,50,95,10, +162,48,163,10,188,106,188,62,66,62,66,106,189,106,66,86,189,86,14,130, +239,130,112,244,113,130,24,214,137,204,52,130,53,210,52,156,113,156,52,182, +111,182,132,156,214,156,188,194,160,220,139,236,230,230,204,220,174,196,156,176, +147,157,22,40,239,40,156,54,157,10,92,54,93,10,118,100,118,74,48,74, +48,100,119,100,14,124,243,124,14,214,149,196,120,242,121,124,46,208,47,124, +46,150,121,150,46,178,121,178,192,70,217,96,154,74,154,104,160,144,172,178, +188,210,208,228,222,236,228,232,239,210,210,140,192,178,170,208,143,229,16,36, +239,36,204,98,204,64,56,64,56,98,205,98,106,98,107,64,156,98,157,64, +98,64,99,10,160,64,161,10,32,158,32,122,226,122,227,156,68,246,68,146, +188,146,189,244,68,172,189,172,68,200,189,200,68,226,189,227,16,38,239,38, +200,70,116,76,41,76,92,56,93,10,164,52,165,10,18,116,237,116,126,148, +127,76,76,90,93,116,180,84,157,116,18,174,54,160,90,140,117,116,236,172, +192,156,164,142,135,116,66,244,66,160,188,160,189,242,66,194,189,194,66,226, +189,226,126,226,127,161,18,42,241,42,86,64,87,8,168,66,169,10,46,68, +69,90,115,66,116,164,116,102,40,102,40,164,117,164,40,134,117,134,114,64, +89,102,16,198,127,198,78,244,79,102,120,242,142,218,152,186,152,154,152,90, +221,76,244,138,153,138,202,246,203,139,22,40,237,40,98,58,99,10,162,56, +163,10,122,166,239,166,154,166,155,78,198,166,199,76,126,110,229,110,16,164, +103,164,92,182,117,216,162,188,123,238,186,186,229,234,70,164,34,226,107,204, +116,80,46,80,47,164,110,108,47,108,110,134,47,135,98,230,243,230,154,230, +155,86,190,230,191,84,110,106,155,106,114,144,155,144,114,182,155,182,232,106, +191,106,228,144,191,144,228,182,191,182,16,42,241,42,94,60,95,10,158,60, +159,10,22,82,111,82,28,168,52,132,65,82,26,238,58,216,76,188,90,158, +94,126,55,126,54,160,81,179,16,38,239,38,94,52,95,12,158,52,159,12, +200,98,200,64,52,64,52,98,201,98,100,98,101,64,150,98,151,64,34,152, +34,122,224,122,225,152,50,148,209,148,38,194,68,176,95,148,24,238,60,232, +100,206,122,176,69,176,70,194,87,214,148,148,148,216,150,224,162,236,208,236, +222,228,226,220,231,204,212,170,149,191,20,38,241,38,92,54,93,8,164,52, +165,8,70,68,29,116,70,120,42,154,17,178,56,242,57,138,93,76,90,76, +90,114,154,114,155,76,122,114,123,60,82,140,151,140,82,226,96,206,100,190, +100,168,138,168,138,214,165,190,196,60,169,136,242,102,183,102,176,140,184,166, +196,192,214,212,241,230,146,238,174,220,192,200,206,170,214,134,215,103,16,40, +16,40,239,40,90,62,91,12,166,64,167,14,114,54,143,70,40,80,215,80, +20,108,235,108,90,90,101,108,168,88,157,108,190,182,190,132,66,132,66,182, +191,182,66,158,191,158,62,198,25,240,124,194,149,218,196,198,237,232,92,196, +92,222,92,232,102,240,158,240,174,234,182,224,187,213,16,40,237,40,90,64, +91,10,162,64,163,10,112,56,141,74,20,82,233,82,98,174,84,204,66,224, +46,236,29,242,98,118,30,188,93,184,70,94,30,138,77,140,170,98,193,118, +148,94,126,130,105,156,132,246,133,120,140,128,231,128,140,160,225,160,142,190, +225,190,140,224,241,224,184,224,185,129,16,42,241,42,94,62,95,12,162,62, +163,12,22,108,139,108,82,140,83,76,38,72,61,92,120,70,97,108,26,150, +79,108,120,142,83,114,22,172,114,170,98,200,70,222,44,232,23,240,78,152, +46,198,117,226,172,70,150,124,135,150,156,136,166,166,180,194,200,216,235,240, +238,106,159,106,130,240,158,222,180,200,196,172,204,144,207,107,18,42,239,42, +94,68,95,12,168,62,169,10,170,66,193,86,130,96,233,96,20,208,38,174, +44,146,46,134,46,88,108,88,108,134,47,134,56,242,56,170,110,170,111,238, +56,222,111,222,144,112,167,138,122,152,247,152,214,110,185,152,130,194,235,194, +182,246,183,153,20,36,237,36,96,60,97,6,164,58,165,8,16,108,90,108, +82,152,64,192,40,218,23,232,68,60,36,162,87,206,226,72,116,72,116,168, +108,200,87,238,136,98,221,98,124,122,241,122,148,122,148,164,179,152,178,122, +188,138,202,154,224,162,237,166,226,132,201,150,128,184,243,184,204,166,204,222, +200,232,194,238,179,238,144,200,167,223,20,34,237,34,96,48,97,12,160,48, +161,10,34,62,223,62,50,80,205,80,128,80,129,46,192,122,192,100,62,100, +62,122,193,122,34,168,34,142,224,142,225,164,56,162,207,162,115,162,146,170, +189,194,116,162,60,190,171,184,40,208,217,208,26,228,231,228,128,228,129,189, +16,36,239,36,94,52,95,10,164,52,165,8,38,62,217,62,36,124,36,90, +220,90,221,122,124,142,125,62,56,112,107,112,58,134,107,134,150,112,199,112, +148,132,199,132,24,156,235,156,50,242,50,186,214,186,214,240,189,244,106,236, +107,186,130,156,123,186,158,234,159,187,18,34,235,34,94,50,95,12,160,50, +161,12,200,54,126,64,49,66,12,88,241,88,198,146,198,112,60,112,60,146, +199,146,88,122,105,146,170,120,151,146,34,172,221,172,16,196,237,196,54,208, +31,238,96,210,115,236,152,208,175,236,208,208,233,238,128,196,129,65,22,38, +241,38,96,64,97,10,168,64,169,12,70,64,46,96,21,120,118,180,118,118, +42,118,42,180,119,180,42,148,119,148,80,180,81,118,82,118,104,88,53,88, +26,226,125,216,148,72,171,96,134,112,239,112,216,68,189,112,140,150,229,150, +136,192,245,192,186,244,187,113,16,38,239,38,86,56,87,14,164,56,165,12, +108,50,133,64,32,70,223,70,180,112,180,90,70,90,70,112,181,112,32,176, +32,130,222,130,222,174,207,178,184,170,184,148,70,148,70,170,185,170,36,192, +223,192,126,242,127,170,22,234,54,228,84,214,104,202,115,192,236,232,202,226, +166,214,152,204,141,193,14,38,239,38,90,54,91,8,154,54,155,8,108,62, +66,68,35,70,26,96,117,96,74,148,75,68,20,138,50,120,75,100,106,124, +75,102,156,58,142,86,123,110,184,142,202,138,212,126,218,80,145,80,148,132, +164,118,176,100,185,80,128,126,100,150,68,168,40,178,19,184,122,132,136,148, +166,164,202,176,241,182,126,160,126,244,103,248,72,180,95,196,172,182,155,198, +40,228,127,204,206,230,127,201,16,36,241,36,96,54,97,10,158,54,159,12, +48,64,209,64,34,122,34,88,222,88,223,122,126,128,127,64,56,108,107,108, +56,126,107,126,150,106,201,106,150,126,201,126,124,136,145,148,80,136,52,166, +23,190,66,244,67,152,74,156,221,156,74,178,211,178,72,202,213,202,74,228, +231,228,134,228,135,157,18,32,237,32,94,50,95,8,162,46,163,6,30,62, +65,94,18,232,36,218,48,208,62,208,74,216,92,226,122,230,239,230,14,126, +56,126,57,208,214,98,220,82,92,82,92,148,88,172,79,198,152,82,153,50, +152,60,209,60,108,106,199,98,154,88,154,108,156,116,166,120,196,120,208,114, +215,108,110,138,229,138,110,162,132,156,150,144,159,138,146,146,160,158,170,168, +176,182,178,194,172,206,164,210,151,214,108,190,132,180,161,160,110,210,138,198, +173,176,226,198,196,178,169,166,210,148,187,173,14,40,241,40,94,62,95,8, +166,62,167,8,62,66,42,96,19,118,74,114,40,156,17,180,50,246,51,144, +164,170,164,112,96,112,96,170,165,170,96,140,165,140,130,170,131,112,120,58, +100,84,83,98,130,112,146,84,101,84,78,198,177,198,130,180,120,212,104,228, +87,242,168,238,123,206,182,80,239,80,180,132,245,132,214,132,214,238,191,243, +16,34,241,34,98,50,99,8,160,48,161,6,62,48,38,74,25,86,134,64, +49,64,14,106,141,106,132,130,44,130,48,84,122,84,117,138,76,90,95,100, +72,112,93,124,172,46,156,76,141,100,234,72,161,72,161,88,162,90,174,106, +190,124,210,132,235,140,142,136,162,128,176,118,194,104,213,72,172,168,217,198, +174,144,48,194,195,184,108,140,60,162,127,162,130,190,130,238,109,240,90,204, +35,234,162,208,225,235,16,32,239,32,96,56,97,8,162,46,163,10,164,54, +183,66,69,46,40,102,102,102,102,74,40,74,40,152,102,152,102,126,41,126, +68,48,53,74,122,76,229,76,114,112,235,112,144,88,159,102,204,84,185,112, +124,138,225,138,172,166,173,112,16,182,239,182,128,246,129,156,16,232,52,224, +86,208,123,182,238,230,206,222,174,210,158,200,137,183,16,36,237,36,92,56, +93,12,164,56,165,10,120,48,139,62,228,72,44,72,44,174,36,208,23,236, +58,102,133,102,98,148,99,82,58,146,99,104,126,130,99,112,144,100,231,100, +182,148,183,80,138,144,183,104,234,140,214,128,183,104,122,242,123,152,160,244, +161,150,58,168,123,168,62,192,123,192,52,216,123,216,230,166,161,166,222,190, +161,190,236,214,161,215,14,112,241,112,86,16,86,144,76,186,60,208,44,222, +23,232,168,242,169,15,108,12,145,38,26,48,231,48,70,74,35,124,186,76, +225,118,108,48,108,62,104,92,96,114,82,130,69,142,130,132,144,130,154,126, +156,118,157,48,18,176,241,176,96,146,92,186,84,208,72,224,54,234,39,242, +174,248,175,145,26,50,231,50,128,10,112,58,96,80,72,98,48,112,21,120, +238,116,212,110,188,98,166,82,152,66,143,50,78,122,76,160,74,186,66,216, +41,242,128,238,129,122,186,244,187,121,20,52,233,52,122,14,88,68,58,96, +19,118,240,116,208,104,174,84,145,52,204,106,52,106,52,230,225,230,90,132, +193,208,182,126,122,184,79,211,26,46,235,46,128,12,100,58,76,78,21,104, +238,102,186,82,158,64,147,46,36,110,219,110,14,210,241,202,74,206,75,110, +180,244,181,110,74,144,181,144,74,174,181,175,110,16,149,44,20,56,241,56, +70,82,29,128,70,150,86,138,96,122,100,100,105,56,184,84,229,124,136,136, +158,134,159,56,20,172,237,172,126,144,118,188,98,210,68,226,21,236,240,234, +202,228,176,218,152,200,131,173,212,16,146,28,88,32,39,32,50,50,79,78, +118,46,143,70,204,40,177,74,172,120,215,158,182,88,46,154,197,144,120,72, +52,112,141,108,18,178,235,178,130,156,112,194,80,220,25,236,230,234,192,226, +160,212,138,194,127,179,106,136,107,16,50,24,50,58,107,58,28,92,107,92, +38,138,54,120,65,92,120,58,235,58,130,114,225,114,176,114,177,14,22,162, +231,162,126,136,114,180,94,206,60,224,29,238,228,234,198,226,166,208,144,186, +131,163,22,52,125,52,76,14,70,54,48,88,17,110,120,100,71,54,46,106, +105,106,16,138,123,138,58,138,50,174,106,174,104,216,100,224,92,230,65,232, +166,14,144,62,131,82,198,170,218,166,226,156,226,50,153,50,240,200,228,226, +216,232,160,232,148,228,142,218,142,98,186,98,186,144,143,145,18,84,235,84, +122,18,122,86,120,120,110,156,94,186,68,212,25,234,234,198,230,220,222,232, +212,236,172,236,160,232,154,222,155,85,16,72,117,72,60,14,60,92,56,148, +46,188,19,234,88,72,88,202,90,222,102,232,204,232,224,226,234,214,239,198, +160,16,138,70,115,102,142,112,175,148,178,196,200,196,212,186,218,172,220,58, +145,59,18,72,113,72,58,10,58,92,54,142,48,184,36,212,19,238,90,72, +90,204,92,222,110,234,212,234,228,224,241,200,172,10,152,56,132,82,111,104, +238,100,204,70,169,18,116,210,134,190,142,166,148,134,149,92,194,90,195,211, +18,72,97,72,55,6,52,6,52,112,46,166,36,208,17,236,76,72,76,208, +78,226,90,232,206,232,224,228,239,210,112,112,113,20,144,118,145,12,194,14, +176,60,159,86,240,52,181,52,194,74,219,110,92,196,239,196,112,196,112,134, +214,134,215,196,146,196,147,134,180,196,181,135,16,76,113,76,16,162,105,122, +64,18,64,222,62,232,58,236,35,237,18,72,97,72,20,154,97,120,64,16, +64,232,31,224,122,238,123,62,122,26,153,60,168,42,220,42,220,208,218,220, +208,228,183,229,16,76,97,76,18,160,93,124,60,14,60,238,27,224,110,62, +225,62,98,108,241,108,130,192,209,240,170,12,136,152,212,152,171,217,18,72, +93,72,18,154,91,120,62,12,62,234,27,224,114,190,114,60,222,60,223,188, +114,114,223,114,114,168,223,168,168,246,169,11,14,72,97,72,16,158,91,128, +62,14,62,236,31,226,140,18,112,90,93,116,122,242,123,66,148,80,241,80, +154,114,177,160,210,14,210,236,177,227,14,74,93,74,16,158,95,118,62,8, +62,232,25,224,188,46,227,90,168,8,108,82,211,74,92,144,245,144,140,98, +140,154,136,186,122,212,95,238,194,242,195,95,16,72,85,72,14,160,81,134, +54,14,54,238,25,228,134,152,151,196,129,22,146,78,82,188,145,180,128,22, +82,110,127,108,160,74,228,74,224,204,218,222,202,228,185,228,186,12,186,78, +182,142,170,186,127,235,16,76,97,76,16,158,97,126,62,14,62,240,29,230, +104,58,241,58,114,110,231,110,172,110,173,10,126,246,126,154,220,154,221,242, +126,220,221,221,12,70,91,70,16,154,93,114,54,8,54,232,23,224,212,16, +160,30,109,34,98,80,233,80,94,146,126,118,142,96,154,68,161,30,238,144, +206,126,186,106,171,80,130,134,130,172,126,196,114,216,91,236,190,240,191,139, +16,70,95,70,20,154,99,124,62,14,62,232,29,222,132,14,112,58,135,98, +180,16,160,58,181,98,228,14,208,58,233,98,156,104,132,144,103,178,98,236, +138,224,176,204,208,172,226,130,141,130,142,166,181,199,14,72,105,72,16,160, +101,118,60,8,60,240,29,230,210,76,210,26,124,26,124,76,211,76,238,206, +228,226,214,236,134,236,118,226,118,110,220,110,220,164,119,164,168,164,169,111, +12,74,97,74,14,156,91,118,62,12,62,236,27,224,220,20,166,34,107,42, +114,66,139,106,156,58,173,96,224,52,197,94,100,130,245,130,116,156,149,190, +198,104,198,236,165,245,12,70,91,70,14,156,93,130,58,12,58,238,25,226, +96,74,243,74,108,30,216,30,216,116,109,116,154,30,152,82,144,124,130,152, +104,180,83,196,134,240,134,152,220,152,221,240,134,218,221,219,12,70,85,70, +14,146,83,110,52,12,52,236,23,222,98,30,209,30,92,78,233,78,78,140, +104,124,126,102,142,74,151,30,234,134,206,124,180,104,161,78,114,156,81,214, +144,122,144,236,121,242,168,160,195,214,196,150,229,209,10,74,79,74,16,156, +77,122,50,12,50,238,21,228,78,30,161,30,72,198,165,176,98,30,99,190, +142,244,143,30,98,82,143,82,98,134,143,134,180,244,180,36,228,36,202,112, +220,134,230,152,234,172,228,190,203,201,14,76,93,76,14,160,91,132,58,12, +58,240,25,226,238,32,112,32,112,142,106,188,83,234,130,82,229,82,120,124, +239,124,178,124,179,48,128,178,229,178,112,228,245,228,178,228,179,139,12,76, +89,76,14,168,81,108,54,14,54,238,21,226,92,54,239,54,154,14,146,44, +136,70,122,96,100,120,83,136,172,54,184,76,206,106,239,128,122,110,197,110, +94,148,225,148,158,148,158,240,131,244,122,174,83,220,190,178,231,219,16,74, +95,74,14,158,89,136,58,14,58,240,29,228,108,44,231,44,168,12,160,60, +146,82,113,106,218,102,163,56,98,120,247,120,212,120,212,236,181,244,172,198, +172,152,122,152,122,198,173,199,14,70,93,70,18,160,91,122,58,12,58,236, +29,226,108,244,108,30,226,30,227,242,108,220,227,220,126,68,207,68,132,120, +201,120,182,136,199,162,124,178,209,178,164,178,165,69,14,70,95,70,16,158, +95,124,58,8,58,236,27,226,222,134,222,44,118,44,118,134,223,134,118,90, +223,90,170,44,170,74,164,110,148,146,115,174,88,186,243,186,182,246,183,146, +164,8,147,45,20,70,97,70,22,152,99,120,66,10,66,236,31,226,136,12, +114,64,91,96,110,94,129,122,192,92,169,124,98,142,203,142,148,236,149,74, +88,208,124,176,149,146,190,194,149,154,118,54,222,54,220,212,216,228,202,234, +183,237,16,78,97,78,16,162,95,134,60,14,60,240,33,228,154,14,183,40, +112,50,233,50,132,70,159,106,102,122,247,122,210,66,183,122,126,244,126,156, +218,156,219,244,126,224,219,225,18,68,95,68,20,156,93,122,60,10,60,234, +29,224,154,10,181,32,80,230,102,198,114,154,114,46,222,46,222,92,115,92, +122,142,243,142,174,102,172,162,154,198,119,236,240,232,206,204,186,170,177,142, +202,106,225,125,24,70,101,70,18,154,99,116,66,10,66,238,33,226,158,10, +185,34,86,230,104,204,114,168,118,132,118,44,228,44,228,82,119,82,148,244, +148,114,228,114,228,240,203,244,148,152,229,152,148,184,229,185,16,76,85,76, +18,160,85,126,60,12,60,238,29,226,90,66,243,66,210,100,214,30,120,30, +116,100,211,100,162,100,167,30,114,202,114,128,214,128,215,200,162,150,158,184, +144,208,124,226,89,242,170,202,237,239,12,76,89,76,16,160,87,120,54,14, +54,236,25,226,84,56,243,56,150,12,150,98,198,98,199,14,114,20,114,128, +235,128,84,160,241,160,162,242,163,128,84,224,112,208,134,184,153,160,236,222, +212,210,192,194,165,161,14,76,95,76,14,154,89,110,58,14,58,236,21,226, +100,58,235,58,162,122,163,14,90,136,126,104,163,60,238,128,200,102,163,58, +208,202,208,136,118,136,118,202,209,202,118,168,209,168,86,232,237,233,12,76, +85,76,12,162,85,132,52,12,52,242,27,232,238,30,102,30,102,228,247,228, +218,112,218,58,138,58,138,112,219,112,138,84,219,84,118,146,243,146,178,122, +144,176,231,210,212,146,200,172,172,196,127,213,12,72,75,72,14,154,77,122, +50,10,50,236,21,224,116,14,94,62,73,94,148,54,99,54,88,100,139,100, +78,144,151,144,148,182,110,212,111,100,188,10,168,80,149,116,212,112,230,70, +173,70,190,96,188,146,182,178,162,212,135,238,238,236,218,210,202,182,189,145, +10,70,83,70,14,158,79,132,48,16,48,240,21,226,154,12,132,48,104,78, +77,98,240,92,214,78,184,58,149,20,118,84,197,84,96,240,96,118,144,118, +144,234,125,240,96,156,145,156,96,192,145,192,180,202,181,122,216,108,216,236, +187,241,10,68,89,68,16,154,81,114,50,12,50,238,23,228,136,14,165,36, +96,50,223,50,122,68,145,100,92,116,241,116,200,66,179,116,118,246,118,148, +208,148,209,242,118,184,209,184,118,220,209,221,14,70,93,70,16,164,95,120, +60,12,60,240,31,232,146,14,175,36,106,76,106,46,226,46,227,76,122,84, +211,84,212,190,212,120,122,120,122,190,213,190,122,154,213,154,94,226,243,227, +12,70,95,70,16,158,89,116,56,14,56,238,29,228,80,226,100,186,108,136, +108,30,218,30,218,66,109,66,138,82,161,108,124,120,233,120,212,82,185,120, +116,170,243,170,118,240,138,218,152,192,154,162,155,120,200,240,201,121,16,74, +91,74,14,162,81,126,58,10,58,236,27,226,102,32,146,32,140,60,122,98, +97,124,100,58,127,86,166,18,176,52,194,84,241,126,214,18,177,50,230,46, +191,78,122,120,205,120,96,168,233,168,158,120,158,166,152,192,134,216,114,230, +95,238,222,236,157,177,12,74,89,74,14,158,85,124,52,14,52,238,21,226, +96,96,239,96,194,96,206,36,131,36,136,12,118,68,199,68,92,148,124,132, +146,112,161,96,138,236,156,236,168,226,174,208,172,188,170,168,164,152,156,138, +141,118,92,184,126,162,155,136,90,222,122,204,167,160,218,120,165,152,234,216, +210,192,187,139,14,72,91,72,14,154,91,128,56,10,56,234,25,224,222,90, +230,64,114,64,114,164,102,204,89,230,164,64,165,8,164,34,225,34,126,104, +207,94,164,76,164,118,166,128,180,132,208,132,222,126,231,112,168,148,197,178, +140,172,127,220,218,168,241,212,162,170,162,212,166,226,174,230,202,230,206,222, +213,209,14,72,97,72,16,160,93,132,58,14,58,236,27,224,220,134,220,30, +114,30,114,134,221,134,132,66,203,66,168,42,160,82,137,114,172,84,197,114, +106,168,89,222,156,150,181,180,134,166,134,216,136,226,150,232,184,232,194,226, +205,208,208,168,239,215,12,78,81,78,50,14,50,240,17,228,16,156,75,118, +222,22,160,34,96,40,96,160,88,204,71,236,224,120,230,96,126,96,126,186, +116,216,101,238,170,96,171,42,170,68,229,68,144,126,205,122,172,104,174,136, +176,146,186,152,200,152,214,148,221,134,130,240,144,228,156,208,158,190,158,174, +202,174,202,226,206,238,218,240,232,236,239,217,14,74,85,74,14,158,83,132, +54,14,54,240,27,230,120,16,143,42,198,12,179,42,92,52,239,52,102,82, +220,82,220,152,103,152,90,116,243,116,142,244,143,52,178,244,179,52,90,226, +116,200,143,162,238,226,214,204,200,184,181,153,16,74,77,74,16,154,79,118, +52,12,52,210,44,222,21,232,90,18,115,48,82,68,173,68,160,18,131,68, +99,92,154,94,155,180,96,94,94,160,155,156,126,68,126,116,124,160,120,182, +110,208,83,234,144,238,166,212,180,178,186,150,188,114,188,38,228,38,228,236, +205,242,228,94,189,94,228,150,187,151,18,74,91,74,16,158,85,120,56,6, +56,236,31,246,72,236,92,204,102,170,106,122,106,26,224,26,224,68,107,68, +122,114,233,114,112,154,247,154,152,154,153,80,198,154,199,80,136,154,136,236, +179,218,168,154,172,172,180,190,202,214,243,234,222,168,189,199,16,76,81,76, +18,152,83,118,54,12,54,238,21,224,86,28,142,28,142,72,102,72,98,116, +144,116,144,212,142,224,132,232,109,232,86,138,115,162,78,196,145,170,160,28, +222,28,222,72,178,72,174,116,226,116,226,202,222,220,206,230,185,230,166,138, +193,162,162,196,227,167,12,72,85,72,16,162,89,124,54,12,54,238,25,226, +104,24,198,24,160,60,105,80,118,42,211,76,88,94,150,94,122,134,97,154, +100,112,145,144,162,94,224,94,206,124,179,150,170,112,229,148,82,168,243,168, +160,244,161,148,88,226,124,204,159,168,238,222,206,208,182,190,161,169,18,74, +97,74,20,158,97,132,62,12,62,236,33,226,224,88,224,26,120,26,120,88, +225,88,120,56,225,56,168,88,169,26,204,148,235,180,214,114,110,176,219,164, +174,88,122,134,187,130,148,234,162,234,172,228,173,170,140,190,101,226,200,192, +237,223,16,74,83,74,18,154,83,116,54,12,54,236,25,226,98,108,98,30, +148,30,149,108,124,52,124,88,118,110,106,132,93,144,130,114,149,130,176,108, +176,30,228,30,229,108,202,50,202,86,196,112,184,132,175,142,210,116,233,146, +84,164,243,164,156,140,120,194,235,232,200,164,190,184,172,202,140,222,95,235, +12,76,87,76,14,162,89,116,56,14,56,212,54,224,44,234,29,234,146,14, +179,40,238,52,102,52,102,162,94,196,77,232,112,106,239,106,146,64,146,158, +200,158,201,66,134,186,111,238,156,192,165,234,184,188,197,228,212,184,241,233, +12,72,71,72,12,158,77,126,50,10,50,236,21,226,76,68,161,68,84,28, +136,28,127,68,78,204,159,178,140,244,141,68,96,68,97,198,96,108,141,108, +96,146,141,146,192,12,174,78,155,116,240,68,179,68,220,68,218,116,210,156, +194,190,172,220,155,236,182,98,184,130,194,164,204,186,222,214,239,237,12,70, +87,70,16,154,85,122,54,8,54,234,21,226,84,26,144,26,145,106,98,46, +115,70,88,100,145,80,160,26,222,26,223,114,174,44,191,68,166,96,223,78, +114,242,114,144,206,144,207,240,114,180,207,180,114,220,207,220,156,116,141,145, +14,74,79,74,14,156,79,128,52,14,52,236,23,228,80,66,149,66,82,108, +145,108,112,108,113,12,92,224,92,140,132,140,133,218,92,202,133,202,144,34, +241,34,160,188,160,82,222,82,223,186,192,106,192,152,186,184,170,218,141,242, +204,196,239,236,192,34,185,83,12,74,87,74,16,156,83,120,52,14,52,240, +23,228,220,116,220,64,104,64,104,116,221,116,104,90,221,90,162,116,163,64, +142,16,110,44,85,58,166,64,184,36,121,36,80,140,243,140,114,246,114,164, +210,164,211,242,114,196,211,196,114,226,211,227,16,72,91,72,18,160,93,120, +56,12,56,238,27,230,120,14,149,36,94,46,239,46,204,12,179,46,216,154, +216,74,112,74,112,154,217,154,112,130,217,130,148,46,148,82,144,100,131,114, +176,46,176,90,178,102,186,106,201,108,90,182,243,182,120,194,147,218,198,162, +198,238,173,245,18,70,85,70,16,158,91,122,62,6,62,234,31,224,150,8, +181,28,102,72,102,38,232,38,233,72,146,56,95,94,182,56,237,92,216,132, +216,102,120,102,120,132,217,132,110,216,110,162,226,162,227,216,110,198,227,198, +166,244,167,73,10,74,73,74,14,156,71,116,46,12,46,234,15,226,74,50, +149,50,138,152,138,82,86,82,86,152,139,152,84,116,139,116,70,188,149,188, +112,242,113,152,112,82,113,12,192,14,168,70,151,98,236,96,210,68,187,28, +162,104,223,104,150,158,233,158,190,242,191,105,14,78,91,78,16,164,89,138, +58,16,58,238,29,228,222,74,222,30,112,30,112,74,223,74,148,74,149,30, +184,74,185,30,94,100,243,100,216,154,216,126,120,126,120,154,217,154,80,208, +118,190,144,168,157,154,170,214,132,236,133,180,174,166,186,192,204,212,237,232, +226,168,193,199,10,76,81,76,14,156,77,118,48,14,48,240,17,228,68,222, +84,188,92,152,96,108,96,44,142,44,142,100,97,100,104,232,104,142,144,142, +145,230,104,212,145,212,176,16,211,44,160,56,239,56,152,120,245,120,166,74, +185,104,224,70,201,120,162,170,237,170,198,242,199,121,16,74,95,74,16,156, +91,110,62,12,62,240,33,230,208,100,208,36,116,36,116,100,209,100,116,58, +209,58,116,78,209,78,156,10,145,36,222,168,222,122,104,122,104,168,223,168, +104,146,223,146,164,168,165,122,82,190,247,190,140,190,136,216,110,234,95,240, +196,244,197,191,14,72,89,72,16,152,89,114,58,12,58,232,23,224,92,26, +154,26,155,98,98,46,129,62,94,94,155,76,166,28,220,28,221,104,174,46, +199,58,170,88,221,72,132,104,98,152,77,172,156,104,181,124,116,242,117,128, +122,132,237,132,124,162,227,162,124,190,225,190,122,222,243,222,174,222,175,133, +14,78,81,78,14,154,85,116,52,12,52,236,21,224,102,24,225,24,96,88, +96,54,228,54,229,88,112,78,147,78,112,102,147,102,180,76,215,76,182,100, +215,100,164,108,165,24,130,112,98,154,79,174,112,244,113,136,152,114,181,134, +113,142,120,140,237,140,120,168,225,168,118,196,225,196,120,224,245,224,172,224, +173,141,12,74,81,74,12,148,81,114,50,12,50,228,25,242,130,10,102,38, +85,52,162,34,109,34,138,52,121,34,194,12,176,36,163,50,238,34,181,34, +208,52,191,34,212,120,212,62,106,62,106,120,213,120,106,82,213,82,106,100, +213,100,76,140,239,140,142,126,110,156,81,174,184,140,206,158,237,174,155,148, +196,182,223,208,184,164,104,204,209,194,154,148,118,176,159,176,162,200,162,240, +143,246,132,212,83,238,184,212,231,239,14,66,81,66,14,160,79,122,52,10, +52,238,29,244,90,26,237,26,214,66,214,46,108,46,108,66,213,66,92,114, +92,84,234,84,235,112,150,122,150,102,110,102,110,122,151,122,212,122,212,100, +170,100,170,122,213,122,98,142,229,142,104,162,225,162,84,182,243,182,136,182, +137,122,188,182,189,122,78,222,104,212,126,198,139,182,166,216,128,238,129,196, +160,182,170,198,182,212,204,224,241,238,216,192,187,214,160,84,161,9,20,122, +229,84,146,34,189,62,100,16,104,68,114,120,130,164,148,194,170,214,188,228, +202,232,210,232,216,226,223,201,24,66,233,66,190,24,217,48,158,12,166,112, +176,160,188,198,198,216,208,228,214,232,222,232,228,224,237,202,40,146,21,210, +80,106,103,160,128,140,155,198,68,136,68,216,72,228,90,232,106,232,122,220, +125,203,14,66,239,66,188,24,219,50,166,8,168,86,174,146,186,198,202,228, +212,238,218,240,224,236,237,212,12,116,155,116,54,242,55,80,120,242,121,82, +54,164,121,164,54,216,121,217,30,30,99,96,94,18,56,72,23,104,16,136, +103,136,66,96,66,240,45,242,44,160,21,210,110,124,171,124,108,222,177,196, +140,124,141,208,108,76,239,76,206,26,229,54,180,10,184,98,192,160,206,214, +216,232,222,236,230,236,241,208,84,164,105,195,36,196,36,40,94,40,95,194, +36,164,95,164,156,244,157,14,234,154,157,75,34,214,34,48,88,48,89,200, +34,178,89,178,214,60,160,108,111,142,140,14,140,204,146,220,164,230,206,230, +224,216,231,189,28,184,28,34,72,34,73,178,28,154,73,154,70,232,96,208, +112,180,118,142,120,116,120,28,186,28,186,218,188,228,196,230,220,230,228,226, +232,212,233,199,34,188,34,32,94,32,95,182,34,158,95,158,148,244,148,30, +222,30,222,164,220,176,208,186,177,187,32,184,32,34,86,34,87,174,32,152, +85,152,108,34,222,34,222,180,220,198,216,212,200,218,177,218,158,34,158,90, +150,142,136,178,114,206,79,227,36,208,36,60,90,60,91,198,36,178,91,178, +108,78,220,74,220,196,218,212,210,224,198,228,177,228,158,10,158,80,154,134, +146,168,132,200,112,222,91,243,24,190,24,44,70,44,71,184,24,162,71,162, +218,24,176,32,97,40,88,132,233,122,156,34,156,208,158,222,166,230,182,234, +214,234,230,228,234,218,237,205,36,202,36,50,86,50,87,192,36,166,85,166, +100,24,153,84,234,26,168,102,169,245,36,202,36,48,84,48,85,198,36,174, +85,174,202,164,237,236,208,82,104,228,223,208,168,18,108,128,177,125,28,202, +28,46,78,46,79,196,28,172,79,172,102,72,229,72,94,134,243,134,164,12, +164,104,158,154,138,194,112,220,85,238,236,236,208,212,190,192,161,137,34,194, +34,46,80,46,81,180,34,160,81,160,104,34,219,34,94,114,231,114,152,34, +150,86,144,134,128,174,102,206,67,234,174,114,174,210,176,224,182,230,194,232, +216,232,230,224,232,210,233,195,26,198,26,50,70,50,71,190,26,168,71,168, +84,56,235,56,128,94,129,16,184,92,185,16,96,112,198,112,156,152,134,174, +116,198,110,210,112,222,120,230,142,232,192,232,210,228,222,218,227,195,26,204, +26,52,70,52,71,196,26,174,71,174,90,82,233,82,150,12,150,86,142,134, +130,170,110,202,75,238,140,194,175,228,232,234,204,200,180,162,166,120,151,83, +34,188,34,44,78,44,79,178,34,160,79,160,240,36,114,36,114,146,106,182, +92,212,73,238,132,102,220,102,218,196,216,208,212,220,204,226,179,230,172,56, +172,104,168,144,160,180,146,208,121,239,32,190,32,46,74,46,75,178,32,156, +75,156,236,36,108,36,108,158,100,198,73,238,184,156,196,156,212,152,216,134, +216,84,152,84,152,204,154,218,164,226,180,230,218,230,232,220,239,195,34,208, +34,52,80,52,81,204,34,180,81,180,114,16,114,228,155,206,160,98,115,98, +176,12,176,212,178,222,186,230,196,236,220,236,230,228,239,202,230,76,177,115, +32,186,32,32,86,32,87,180,32,158,87,158,124,176,124,26,218,26,219,176, +166,70,166,148,158,178,140,204,101,238,180,184,237,239,188,94,188,22,66,22, +66,94,189,94,38,240,38,132,216,132,216,208,214,224,202,232,181,232,126,94, +124,134,110,168,92,188,69,202,184,200,119,151,22,206,22,54,70,54,71,200, +22,172,71,172,108,98,91,182,148,16,185,58,202,100,233,170,142,64,142,204, +144,220,160,232,192,232,210,218,213,193,30,206,30,44,76,44,77,198,30,174, +77,174,96,28,166,28,166,80,116,80,114,144,174,144,168,196,162,214,148,222, +121,226,220,14,221,239,30,202,30,56,74,56,75,194,30,172,75,172,234,30, +108,30,108,224,241,224,140,180,140,82,214,82,214,174,201,176,176,210,177,47, +26,198,26,44,76,44,77,190,26,168,77,168,92,102,239,102,150,102,151,6, +220,50,151,50,152,122,153,242,178,150,227,201,34,188,34,28,78,28,79,178, +34,158,79,158,116,172,116,20,222,20,223,168,116,84,223,84,116,150,223,150, +168,242,169,21,28,188,28,42,72,42,73,182,28,158,73,158,214,18,162,32, +108,38,108,130,100,178,84,214,65,242,149,34,174,178,195,230,150,34,150,220, +185,208,234,238,212,198,200,148,192,94,189,27,30,196,30,42,76,42,77,190, +30,160,77,160,164,10,136,72,99,114,162,16,184,60,202,84,241,114,154,82, +181,120,130,186,195,240,106,138,212,138,163,213,26,212,26,46,74,46,75,204, +26,178,75,178,144,10,118,56,93,94,90,156,140,128,182,90,206,46,125,46, +130,74,156,104,182,124,241,152,138,160,195,184,120,202,199,241,32,200,32,52, +86,52,87,188,32,168,87,168,152,14,183,44,118,98,118,60,230,60,231,98, +108,130,243,130,174,130,174,238,147,245,34,196,34,48,84,48,85,184,34,162, +85,162,120,28,120,104,218,104,219,26,118,142,118,224,223,218,222,136,223,246, +170,12,171,221,24,204,24,52,62,52,63,200,24,176,63,176,76,72,140,72, +136,130,114,188,75,236,118,12,86,156,149,196,150,52,222,52,218,96,208,138, +192,176,168,210,141,240,164,82,172,120,184,156,200,192,235,233,28,208,28,52, +66,52,67,202,28,178,67,178,134,150,153,196,144,76,88,196,145,178,124,16, +86,108,131,106,162,86,226,86,220,208,218,220,208,230,187,230,190,12,188,120, +180,168,162,212,141,241,24,206,24,52,60,52,61,196,24,178,61,178,146,68, +80,192,143,182,124,18,80,112,125,108,226,74,160,190,233,180,204,22,158,114, +207,106,70,224,241,225,28,206,28,48,72,48,73,196,28,164,73,164,242,228, +108,228,108,34,239,34,122,74,227,74,130,128,221,128,122,190,229,190,174,190, +175,75,30,194,30,42,82,42,83,186,30,162,83,162,102,58,245,58,108,112, +235,112,168,112,169,8,120,244,120,156,216,156,217,242,120,222,217,223,26,198, +26,42,68,42,69,192,26,168,69,168,86,28,243,28,102,240,102,82,222,82, +223,236,102,214,223,214,142,28,142,98,138,136,123,168,180,28,180,142,180,154, +190,160,223,161,26,202,26,56,72,56,73,190,26,170,73,170,90,68,241,68, +146,12,136,84,122,132,104,170,75,210,150,118,139,168,176,92,176,150,168,178, +154,204,130,226,103,242,240,238,214,222,196,198,182,170,177,150,224,120,187,177, +26,202,26,50,68,50,69,194,26,172,69,172,92,30,123,72,90,234,100,220, +110,214,120,214,140,222,160,228,237,226,82,108,112,108,113,214,138,76,229,76, +176,12,176,94,168,134,154,172,135,198,226,194,175,109,32,186,32,38,70,38, +71,182,32,160,71,160,88,34,173,34,122,34,122,50,116,76,108,108,91,138, +72,236,98,216,126,184,144,142,154,88,115,88,110,136,137,158,180,178,181,50, +218,12,218,232,181,239,30,190,30,48,70,48,71,180,30,156,71,156,88,44, +241,44,94,76,212,76,212,110,104,110,102,146,224,146,222,164,220,174,204,182, +195,182,154,10,154,100,148,140,134,180,108,214,73,238,234,236,202,218,178,190, +155,147,28,188,28,44,74,44,75,180,28,158,75,158,94,58,225,32,210,54, +176,88,136,112,101,122,136,12,152,68,178,104,208,122,218,124,222,122,231,100, +90,150,237,150,70,238,92,228,114,210,130,184,134,166,137,150,174,148,174,212, +176,222,182,230,196,236,214,236,228,222,233,203,30,186,30,44,74,44,75,178, +30,156,75,156,118,14,118,124,163,104,162,60,119,60,182,10,182,108,184,118, +194,124,202,126,220,126,230,116,237,98,234,42,183,70,92,172,241,172,162,244, +163,137,30,196,30,50,72,50,73,188,30,160,73,160,86,232,167,208,102,64, +103,224,136,20,137,216,170,100,137,100,186,14,186,212,190,224,200,234,220,234, +236,228,241,206,232,62,187,109,28,202,28,46,70,46,71,196,28,170,71,170, +88,116,237,116,154,116,155,14,98,36,131,88,214,34,183,90,132,116,132,142, +126,174,116,198,98,222,77,240,176,116,176,210,178,226,190,236,216,236,226,230, +235,207,30,192,30,46,78,46,79,188,30,160,79,160,112,24,112,76,224,76, +225,20,170,76,171,10,152,90,122,136,99,162,86,232,126,224,162,208,194,180, +214,146,222,122,133,122,138,154,179,195,24,204,24,50,62,50,63,194,24,172, +63,172,124,18,98,90,79,124,104,244,105,76,124,78,235,78,176,246,177,12, +124,198,154,148,177,90,232,192,177,89,22,200,22,46,60,46,61,192,20,172, +61,172,122,14,92,92,75,120,104,242,105,62,134,42,218,42,219,168,124,92, +245,92,130,146,219,146,130,238,152,208,162,178,166,152,171,43,28,206,28,48, +70,48,71,200,28,176,71,176,220,28,172,38,104,46,104,172,94,206,73,240, +224,66,186,78,140,86,140,238,185,204,238,224,212,202,194,176,182,144,173,80, +232,116,185,149,30,212,30,42,74,42,75,200,30,176,75,176,162,12,134,66, +93,112,160,18,178,52,210,86,239,104,126,100,201,100,96,146,231,146,159,154, +182,176,225,238,158,154,110,226,207,217,24,208,24,46,70,46,71,198,24,178, +71,178,94,112,112,96,120,76,124,48,122,30,186,30,186,84,190,94,200,100, +225,102,86,142,231,142,154,98,155,244,76,222,104,200,126,176,147,142,230,220, +204,200,180,172,161,143,22,200,22,50,74,50,75,190,20,170,75,170,136,16, +171,46,88,58,237,58,118,58,126,74,142,96,172,116,208,130,235,134,198,58, +184,78,166,100,144,116,118,128,91,134,130,140,128,176,118,206,104,224,87,238, +192,144,193,245,30,194,30,48,80,48,81,184,30,164,81,164,124,18,151,52, +106,64,237,64,210,12,183,64,114,120,225,120,98,174,245,174,168,246,169,65, +26,188,26,44,70,44,71,180,26,156,71,156,98,34,129,82,214,30,183,82, +86,110,239,110,154,244,155,12,66,210,102,176,138,134,155,112,236,206,196,170, +155,113,28,206,28,56,70,56,71,200,28,176,71,176,142,16,173,46,98,92, +98,60,228,60,229,92,206,92,172,102,105,114,86,166,239,152,158,104,158,212, +160,222,166,230,182,234,206,234,224,228,235,207,30,210,30,54,70,54,71,204, +30,180,71,180,102,102,102,58,218,58,219,102,164,12,146,92,116,148,93,178, +172,204,130,232,131,122,164,102,170,142,186,182,204,210,231,236,222,124,183,169, +28,196,28,40,76,40,77,190,28,164,77,164,162,210,116,232,116,32,208,32, +208,124,117,124,116,78,209,78,158,124,164,154,180,186,200,212,237,236,228,142, +179,181,32,214,32,46,78,46,79,206,32,176,79,176,194,44,233,84,164,14, +104,80,217,68,132,96,116,126,99,154,232,130,115,130,92,180,243,180,168,246, +169,87,34,194,34,42,76,42,77,182,34,160,77,160,98,42,233,42,104,74, +223,74,90,110,239,110,162,10,163,110,152,118,124,154,97,180,90,238,142,216, +186,176,202,144,133,144,140,164,158,194,188,214,237,235,30,190,30,50,72,50, +73,174,30,158,73,158,112,140,83,198,196,142,235,198,100,52,227,52,88,100, +243,100,160,100,161,10,138,100,138,144,130,182,110,218,83,238,182,100,182,234, +155,239,32,192,32,40,74,40,75,184,32,162,75,162,98,46,237,46,140,78, +141,10,192,76,193,8,102,126,102,96,236,96,237,126,108,148,214,144,210,204, +206,222,194,228,167,232,156,114,152,156,146,182,130,210,112,226,93,241,28,180, +28,38,76,38,77,168,28,148,77,148,96,26,239,26,218,138,218,62,114,62, +114,138,219,138,114,100,219,100,166,26,166,142,162,170,150,200,122,222,83,238, +108,160,128,182,160,206,198,222,235,231,30,186,30,44,80,44,81,180,30,156, +81,156,98,26,229,26,94,122,243,122,136,122,153,26,106,70,204,70,197,122, +118,244,118,156,210,156,211,242,118,218,211,219,28,200,28,54,68,54,69,190, +28,168,69,168,82,72,151,72,84,152,149,120,116,12,116,238,89,228,230,26, +196,34,164,36,164,160,158,198,135,234,242,98,165,98,206,238,207,99,32,188, +32,46,78,46,79,178,32,156,79,156,94,24,135,64,222,20,191,66,114,188, +114,88,216,88,217,186,162,88,163,10,162,112,160,174,148,196,132,214,91,240, +180,192,231,235,30,196,30,48,80,48,81,190,30,168,81,168,212,122,212,42, +112,42,112,122,213,122,112,80,213,80,160,12,145,42,94,182,235,166,142,140, +142,212,144,228,154,234,176,240,204,240,218,234,226,226,231,213,24,200,24,48, +66,48,67,192,24,168,67,168,114,20,168,46,223,76,210,16,156,52,105,76, +86,104,239,104,158,76,130,124,85,174,122,224,122,148,218,148,218,220,199,226, +170,242,171,117,26,202,26,54,68,54,69,198,26,176,69,176,118,46,104,100, +87,142,138,130,109,90,206,48,196,96,181,140,238,132,199,88,92,168,227,168, +76,228,241,228,158,228,159,15,30,186,30,34,72,34,73,180,30,156,73,156, +140,152,163,196,150,176,102,204,102,26,150,26,150,130,103,130,102,76,149,76, +184,242,184,24,224,24,224,198,203,203,28,198,28,44,68,44,69,186,28,168, +69,168,86,42,229,42,94,74,217,74,82,108,237,108,154,12,146,60,136,100, +116,134,87,164,238,160,212,146,194,132,179,108,116,160,199,160,82,198,231,198, +156,246,157,127,30,186,30,42,70,42,71,180,30,160,71,160,90,42,231,42, +96,72,225,72,86,106,239,106,160,106,161,10,114,208,114,134,212,134,213,202, +162,154,162,168,158,188,148,206,132,220,104,232,79,238,176,204,239,239,24,204, +24,52,66,52,67,200,24,172,67,172,86,50,237,50,132,78,133,16,190,76, +191,16,84,118,243,118,164,80,136,138,114,166,89,192,126,242,126,162,214,162, +215,240,126,220,215,221,26,194,26,52,72,52,73,186,26,164,73,164,86,52, +237,52,130,96,131,12,188,94,189,10,108,242,108,114,214,114,215,238,108,166, +215,166,108,216,213,216,158,216,159,115,24,198,24,54,60,54,61,184,24,172, +61,172,76,78,147,78,112,242,113,16,66,204,84,172,113,102,144,140,113,98, +156,76,235,76,186,242,187,16,136,200,162,156,187,92,234,198,208,146,187,85, +30,194,30,40,62,40,63,182,30,164,63,164,80,58,145,58,116,10,82,132, +149,132,72,202,147,170,116,92,117,242,164,58,233,58,146,104,237,104,162,194, +217,234,198,8,168,148,224,148,185,211,30,196,30,38,76,38,77,188,30,166, +77,166,76,240,96,208,104,178,110,142,110,32,226,32,226,236,195,242,128,80, +207,80,124,118,211,118,166,118,167,44,192,200,192,150,140,150,140,200,193,201, +32,204,32,48,74,48,75,196,32,172,75,172,134,12,110,64,91,90,176,232, +198,228,218,220,222,204,222,50,119,50,134,72,109,120,194,94,125,94,90,136, +207,136,112,154,112,194,190,194,191,154,150,194,151,95,24,190,24,48,68,48, +69,184,24,164,69,164,132,14,112,56,89,86,182,146,196,146,210,142,216,132, +218,124,222,46,119,46,154,46,144,74,128,96,99,124,188,46,182,72,166,104, +142,134,111,154,98,176,79,220,152,158,173,190,210,170,233,208,126,174,126,212, +128,222,134,230,142,232,176,232,194,222,201,211,28,196,28,50,74,50,75,184, +28,162,75,162,144,16,173,40,98,54,233,54,136,66,122,106,103,142,156,120, +129,92,198,68,184,108,167,138,220,132,189,100,92,174,239,174,162,248,163,149, +30,192,30,56,72,56,73,184,30,160,73,160,142,14,171,38,96,52,227,52, +118,68,145,94,92,110,237,110,200,64,167,110,84,154,243,154,152,124,112,186, +170,204,233,232,198,154,182,182,154,212,118,228,91,239,28,190,28,42,68,42, +69,180,28,156,69,156,146,12,175,34,84,46,241,46,188,62,223,102,148,54, +102,98,209,88,112,248,112,124,206,124,206,240,181,246,112,156,207,156,112,192, +207,193,34,192,34,42,78,42,79,184,34,160,79,160,120,38,103,80,214,36, +191,70,158,10,156,50,148,82,132,102,101,126,224,114,155,64,118,138,103,182, +218,142,193,176,158,112,152,174,130,206,108,224,77,234,230,234,200,220,176,198, +155,161,26,194,26,46,66,46,67,180,26,164,67,164,82,28,115,64,82,88, +111,120,68,232,99,146,210,84,226,50,134,50,134,134,128,180,101,240,142,114, +214,114,202,162,174,206,133,240,154,134,164,166,186,198,237,230,176,114,177,9, +26,206,26,54,70,54,71,198,26,174,71,174,146,14,173,42,102,88,102,54, +226,54,227,88,104,104,225,104,120,140,104,192,75,236,236,228,198,228,160,224, +128,206,109,184,162,222,163,104,162,156,225,157,30,196,30,38,66,38,67,186, +30,164,67,164,110,8,133,38,128,160,157,206,140,186,96,216,96,48,148,48, +148,138,97,138,96,92,149,92,178,244,178,30,228,30,200,114,218,136,230,158, +232,184,224,198,203,205,32,182,32,46,74,46,75,176,32,154,75,154,144,12, +177,38,62,232,84,214,100,186,108,154,110,132,110,50,218,50,218,94,111,94, +116,148,239,148,192,110,219,134,166,106,162,168,150,198,130,222,109,240,232,238, +200,210,180,182,165,149,30,174,30,34,62,34,63,170,30,148,63,148,52,220, +72,190,84,158,90,118,90,28,160,28,160,72,91,72,104,206,104,120,162,120, +162,204,151,208,132,236,133,88,192,176,193,46,220,16,220,232,193,239,24,184, +24,32,68,32,69,174,24,148,69,148,86,24,144,24,130,68,95,108,98,50, +147,98,162,26,216,26,202,68,159,114,224,104,171,50,86,130,140,130,134,166, +112,202,81,230,96,156,147,208,158,130,218,130,210,168,186,204,147,234,230,232, +208,216,184,186,174,156,169,131,26,190,26,44,68,44,69,176,26,156,69,156, +88,48,231,48,152,10,152,88,198,88,199,8,112,18,112,116,225,116,92,154, +231,154,162,244,163,128,84,226,114,204,140,178,157,154,234,222,204,202,182,178, +167,155,24,200,24,48,64,48,65,194,24,172,65,172,80,46,237,46,128,68, +129,12,186,68,187,10,160,66,122,112,83,144,232,136,208,124,180,102,157,74, +118,136,199,136,112,244,112,170,206,170,207,242,112,224,207,225,32,200,32,46, +72,46,73,190,32,170,73,170,88,50,243,50,104,244,104,94,224,94,224,238, +195,244,132,110,153,134,122,146,203,146,186,106,169,146,118,180,209,180,162,232, +163,146,158,94,159,11,26,188,26,36,68,36,69,178,26,158,69,158,238,30, +100,30,100,134,90,188,65,238,216,138,216,62,128,62,128,138,217,138,128,100, +217,100,114,180,231,180,98,224,241,224,172,224,173,63,22,206,22,56,62,56, +63,196,20,174,63,174,84,54,237,54,156,14,134,66,114,96,87,122,232,114, +206,98,184,74,173,54,114,116,203,116,96,152,223,152,158,152,159,82,104,194, +217,194,76,232,237,232,158,232,159,163,26,188,26,48,68,48,69,186,26,162, +69,162,104,16,104,114,155,94,150,56,105,56,172,10,172,96,176,104,186,112, +212,112,228,106,237,88,228,36,173,66,112,244,112,142,206,142,207,242,112,182, +207,182,112,222,207,222,152,112,139,143,30,190,30,36,74,36,75,182,214,102, +214,26,114,26,114,102,213,102,114,64,215,64,104,242,104,136,226,136,226,212, +224,224,214,230,197,230,190,158,207,196,126,194,201,182,30,158,75,158,162,186, +163,27,30,186,30,42,82,42,83,180,30,158,83,158,232,96,232,24,118,24, +118,96,233,96,172,96,173,24,118,62,233,62,124,244,124,126,224,126,224,236, +195,244,124,160,225,160,124,196,225,197,28,190,28,50,62,50,63,172,28,156, +63,156,148,28,112,38,79,44,76,94,143,94,114,242,115,38,68,192,92,156, +115,110,144,152,115,114,162,68,153,122,228,66,209,118,188,12,188,120,180,168, +164,202,137,232,234,230,208,196,192,144,189,127,30,192,30,48,74,48,75,186, +30,160,75,160,140,30,106,42,106,114,222,114,222,38,181,38,142,74,107,74, +182,74,223,74,90,148,210,148,182,192,146,220,87,238,118,148,134,174,158,200, +192,222,237,236,162,148,163,9,28,200,28,46,76,46,77,192,28,166,77,166, +148,8,177,34,102,48,237,48,128,66,147,100,92,112,249,112,206,60,183,112, +124,246,124,144,216,144,217,244,124,224,217,224,124,182,217,183,112,14,139,32, +30,42,225,42,30,114,30,82,224,82,225,114,84,56,111,82,174,54,151,82, +60,162,60,114,192,114,192,138,190,150,176,158,165,158,124,168,125,82,52,248, +52,182,196,182,197,246,52,226,197,227,30,196,30,50,76,50,77,184,30,162, +77,162,120,18,149,44,94,58,229,58,200,16,171,58,102,94,219,94,88,130, +241,130,150,58,150,70,144,108,132,146,112,178,94,198,67,218,218,172,123,172, +98,228,235,228,168,228,169,173,28,202,28,46,72,46,73,198,28,166,73,166, +98,68,233,68,110,22,135,52,216,22,197,54,164,126,165,10,94,124,128,104, +148,88,165,72,236,122,210,112,188,94,165,70,90,160,243,160,156,138,120,192, +229,236,204,160,194,184,176,208,150,222,122,230,91,237,56,20,83,52,114,14, +139,48,36,108,36,68,220,68,221,104,196,14,163,68,82,86,66,120,55,138, +18,154,239,154,206,116,69,116,128,154,129,80,64,248,64,182,196,182,197,244, +64,224,197,225,30,190,30,38,70,38,71,178,30,160,71,160,62,238,80,220, +94,194,100,162,102,120,102,28,220,28,220,64,103,64,118,98,239,98,196,112, +229,154,168,106,132,150,215,140,118,188,231,188,106,230,241,230,174,230,175,157, +26,204,26,52,68,52,69,198,26,176,69,176,136,10,116,72,193,72,82,102, +241,102,186,102,200,40,127,40,92,152,126,134,167,102,140,124,154,140,164,156, +172,178,174,204,170,226,156,236,133,240,94,188,126,172,159,148,90,224,120,212, +146,194,171,176,218,126,169,164,234,224,216,204,206,182,200,162,197,145,24,206, +24,46,62,46,63,196,24,174,63,174,86,40,227,40,96,70,221,70,78,104, +237,104,156,10,150,50,142,80,120,118,102,134,79,154,236,152,212,140,190,120, +179,104,188,136,146,144,117,144,92,174,213,174,154,244,155,144,80,228,106,214, +128,194,145,174,224,222,177,189,26,200,26,50,64,50,65,190,26,172,65,172, +80,48,153,48,82,84,145,84,78,122,157,122,116,122,117,12,60,232,78,216, +92,188,100,154,103,122,100,156,146,156,140,210,136,218,124,224,107,224,182,16, +164,78,147,108,238,72,167,72,170,110,178,154,190,190,214,220,235,234,210,72, +206,120,196,166,180,198,164,220,143,241,32,202,32,48,74,48,75,190,32,172, +75,172,94,42,227,42,102,72,217,72,88,100,239,100,162,100,163,8,198,138, +229,178,198,112,102,178,215,162,146,106,108,138,163,134,164,170,164,238,141,244, +130,188,93,232,194,186,233,225,24,200,24,46,58,46,59,192,24,170,59,170, +84,58,139,58,74,102,167,102,114,102,115,10,160,40,138,88,112,126,73,164, +100,238,100,144,148,144,149,236,100,180,149,180,100,218,149,218,182,246,182,32, +230,32,204,104,218,120,230,140,236,162,230,180,203,193,30,198,30,50,72,50, +73,188,30,168,73,168,100,48,219,48,88,82,233,82,156,82,157,14,176,104, +217,142,148,92,104,136,201,128,72,232,239,232,102,232,102,164,210,164,211,232, +138,232,139,164,174,232,175,165,30,194,30,46,70,46,71,182,30,162,71,162, +90,30,229,30,88,118,237,118,120,118,121,30,199,118,198,138,199,30,120,60, +199,60,120,88,199,88,88,152,140,152,134,172,128,188,114,208,96,224,77,236, +100,172,153,216,160,152,218,152,210,174,200,194,182,216,162,230,143,240,166,152, +172,172,182,194,200,214,220,232,235,241,24,206,24,52,62,52,63,196,24,178, +63,178,80,42,237,42,136,58,137,12,184,58,185,14,122,70,90,130,75,154, +102,240,103,108,124,96,245,96,210,96,210,232,183,240,174,188,174,130,138,130, +138,188,175,189,28,198,28,48,74,48,75,182,28,160,75,160,94,40,235,40, +90,186,239,186,122,186,122,70,208,70,209,186,122,100,209,100,122,130,209,130, +122,158,209,158,156,70,167,12,140,200,91,238,180,206,231,237,28,188,28,52, +70,52,71,186,28,162,71,162,84,42,233,42,102,104,102,72,220,72,221,104, +164,72,165,12,196,140,229,176,196,108,102,168,213,158,162,82,112,130,161,128, +164,164,164,236,143,242,132,186,89,230,194,190,235,223,34,190,34,46,74,46, +75,180,34,158,75,158,94,34,239,34,206,98,206,62,118,62,118,98,207,98, +104,242,104,128,226,128,226,236,199,244,132,144,151,170,120,182,205,182,188,144, +165,182,162,232,163,183,32,184,32,44,76,44,77,174,32,150,77,150,90,26, +237,26,208,132,208,56,114,56,114,132,209,132,114,82,209,82,114,108,209,108, +140,140,116,178,85,206,90,240,118,234,152,220,186,190,204,162,127,162,134,180, +148,200,166,214,188,228,212,236,235,240,160,26,157,57,28,192,28,38,66,38, +67,182,28,162,67,162,212,136,212,26,100,26,100,136,213,136,114,70,197,70, +158,40,154,76,140,100,119,120,190,116,153,80,98,164,69,220,144,150,177,190, +202,154,239,206,124,166,124,210,126,222,140,232,176,232,194,224,199,205,24,200, +24,48,70,48,71,192,24,172,71,172,206,106,206,42,108,42,108,106,207,106, +108,74,207,74,86,146,231,146,152,118,130,160,108,184,87,202,236,198,210,184, +188,164,177,146,114,202,205,202,158,246,159,164,146,10,135,43,24,194,24,50, +68,50,69,184,24,162,69,162,140,16,91,60,180,18,225,60,126,50,144,68, +166,84,194,94,239,102,184,48,160,68,138,84,108,98,85,106,150,98,122,118, +93,136,84,174,118,166,152,154,180,136,200,120,123,118,110,126,141,156,180,154, +146,180,105,200,78,236,104,236,138,232,174,220,200,202,220,182,143,182,130,188, +163,225,28,194,28,44,72,44,73,188,28,170,73,170,222,20,174,28,101,34, +112,50,133,78,152,44,169,74,100,116,100,90,232,90,233,114,214,44,185,90, +102,128,223,128,148,98,134,146,116,180,77,218,106,238,138,228,160,216,184,192, +206,162,127,162,136,180,154,200,176,216,206,230,233,241,26,206,26,46,66,46, +67,194,26,176,67,176,108,20,145,56,86,70,235,70,206,12,171,70,140,86, +89,142,176,90,235,136,78,226,241,226,114,226,114,146,208,146,209,226,144,226, +145,146,176,226,177,147,22,206,22,54,64,54,65,198,20,174,65,174,86,16, +111,40,76,62,167,62,146,16,127,62,154,86,155,186,92,84,92,172,155,164, +122,62,122,126,122,178,106,212,77,240,142,240,164,216,180,188,184,154,184,30, +226,30,226,238,201,246,184,94,227,94,184,156,227,157,26,198,26,52,62,52, +63,190,26,174,63,174,86,24,119,52,78,86,109,108,74,230,103,154,162,16, +140,56,117,92,238,52,145,52,116,144,243,144,162,108,187,130,162,164,187,186, +240,202,132,202,142,90,220,90,210,212,208,222,200,232,188,236,177,237,24,194, +24,38,64,38,65,190,24,164,65,164,86,20,119,56,78,224,88,214,96,208, +100,206,118,206,136,216,152,222,241,222,78,102,108,102,109,206,150,44,193,72, +126,24,212,24,177,60,138,196,138,80,220,80,220,196,201,200,138,116,221,116, +138,152,221,152,180,196,181,81,30,198,30,46,74,46,75,188,30,166,75,166, +88,100,239,100,108,30,108,66,216,66,217,24,160,12,161,100,214,176,214,136, +110,136,110,176,213,176,202,192,233,234,82,226,217,214,160,218,161,113,20,156, +77,148,78,52,24,120,75,116,58,14,18,74,61,72,98,46,163,46,132,14, +90,98,161,98,90,136,163,136,204,16,172,76,211,76,228,50,176,120,227,118, +168,154,235,154,62,244,62,178,194,178,195,246,62,224,195,224,130,166,131,65, +24,192,24,54,58,54,59,184,24,164,59,164,78,54,167,54,102,12,102,86, +144,86,145,10,150,162,150,116,86,116,86,162,151,162,78,190,153,190,120,246, +121,84,162,88,228,88,224,212,220,226,206,232,195,232,194,16,194,108,192,146, +184,172,174,198,145,237,32,188,32,44,70,44,71,180,32,158,71,158,84,42, +237,42,218,138,218,70,98,70,98,138,219,138,98,104,217,104,140,138,141,12, +178,138,179,12,116,244,116,164,208,164,209,244,116,196,209,196,116,228,209,229, +28,200,28,44,72,44,73,190,28,172,73,172,88,28,237,28,218,112,218,62, +102,62,102,112,219,112,138,112,139,28,180,112,181,28,102,144,217,144,90,174, +239,174,122,196,85,234,192,198,235,230,162,174,162,242,139,247,22,210,22,52, +62,52,63,198,22,178,63,178,202,20,223,46,234,60,90,60,90,156,82,200, +69,238,104,148,171,148,134,148,135,76,134,110,169,110,118,168,103,216,154,172, +171,198,140,148,140,228,121,236,174,8,174,60,178,90,182,122,192,168,204,206, +216,226,222,236,230,236,239,208,220,94,210,136,202,162,190,194,159,241,30,200, +30,40,64,40,65,190,30,172,63,172,94,104,94,26,142,26,143,102,118,44, +118,80,114,106,102,130,89,144,126,106,149,124,170,104,170,26,220,26,221,104, +194,46,194,74,190,98,182,120,169,134,202,112,229,136,78,162,241,162,152,134, +112,194,231,232,196,162,184,186,164,210,124,230,85,241,30,186,30,40,70,40, +71,178,30,154,71,154,104,16,104,56,218,56,219,14,158,56,159,8,74,236, +90,208,98,176,100,160,100,88,144,88,144,226,125,230,100,126,145,126,100,166, +145,166,156,238,168,210,176,182,178,160,178,86,224,86,224,236,203,242,178,126, +225,126,178,168,225,169,30,204,30,52,66,52,67,186,30,166,67,166,96,14, +119,46,80,62,141,62,60,236,82,204,96,166,101,62,98,114,130,114,124,226, +101,232,176,10,158,66,143,96,238,58,161,58,178,76,151,140,228,110,165,110, +144,162,239,162,190,110,184,174,168,208,141,240,234,238,208,208,187,163,30,200, +30,54,70,54,71,188,30,162,71,162,140,14,165,36,86,52,241,52,102,248, +102,102,218,102,218,240,189,244,122,66,145,88,192,66,173,102,118,136,201,136, +186,202,186,166,134,166,134,202,187,202,156,166,157,103,26,208,26,48,70,48, +71,202,26,180,71,180,142,16,167,38,100,78,100,48,224,48,225,78,108,90, +95,132,142,66,161,88,210,94,235,130,194,74,162,114,132,142,93,164,130,88, +130,132,132,144,144,152,180,152,196,142,203,124,216,176,217,244,110,178,110,232, +217,222,164,228,165,165,26,194,26,40,66,40,67,188,26,164,67,164,80,46, +175,46,86,80,167,80,126,80,127,10,156,146,156,108,98,108,98,146,157,146, +98,164,113,198,78,226,171,208,152,162,133,216,230,24,183,86,230,94,181,156, +234,158,161,243,24,188,24,40,62,40,63,180,24,160,63,160,238,30,92,30, +92,156,84,194,67,236,114,50,131,76,106,92,169,92,164,48,143,92,166,122, +167,186,116,120,116,174,167,170,142,92,142,166,140,182,128,210,109,234,200,48, +177,112,222,122,230,94,185,94,198,124,192,178,180,206,151,242,238,236,214,210, +195,163,28,200,28,44,70,44,71,186,28,164,71,164,84,42,231,42,158,12, +144,56,124,84,87,116,94,64,123,84,164,42,178,70,206,98,237,114,220,60, +191,80,204,172,204,106,114,106,114,172,205,172,114,138,205,138,158,172,158,242, +137,246,126,188,85,230,186,192,229,229,30,194,30,48,70,48,71,186,30,168, +71,168,94,32,123,58,218,30,199,60,84,78,241,78,144,78,145,14,178,78, +179,12,96,120,229,120,118,92,145,120,196,88,169,120,100,150,225,150,84,180, +239,180,158,120,158,162,154,188,130,216,87,240,232,240,202,230,180,214,157,183, +30,204,30,46,66,46,67,188,30,168,67,168,208,82,208,28,106,28,106,82, +209,82,106,54,209,54,78,106,241,106,148,246,149,106,80,222,169,194,102,214, +103,106,102,136,149,136,102,168,149,168,162,138,220,138,208,176,190,208,167,232, +170,138,174,158,186,184,206,210,237,231,36,194,36,46,82,46,83,184,36,162, +83,162,142,12,118,66,97,98,124,188,125,54,164,14,197,38,228,54,133,54, +132,92,217,92,132,132,219,132,132,168,235,168,174,168,175,54,118,198,97,236, +142,196,149,232,178,194,189,230,212,190,231,235,26,200,26,42,70,42,71,192, +26,170,71,170,102,162,102,40,218,40,219,162,152,10,139,40,124,62,141,84, +196,62,177,88,120,98,203,98,160,146,161,56,120,142,161,100,196,138,161,106, +86,180,239,180,158,162,146,196,124,220,85,240,234,236,204,224,178,204,161,181, +26,202,26,54,68,54,69,192,26,174,69,174,154,14,124,50,81,80,236,76, +182,50,147,22,142,58,167,74,106,82,209,82,104,98,104,142,206,142,207,96, +128,96,187,130,176,94,146,118,123,132,98,246,98,172,216,172,216,240,189,246, +168,186,191,216,156,152,122,210,181,203,34,196,34,44,72,44,73,188,34,166, +73,166,222,122,222,66,108,66,108,122,223,122,108,94,223,94,162,122,163,66, +146,8,122,40,107,54,168,66,188,38,125,38,86,146,243,146,118,246,118,174, +212,174,213,244,118,200,213,200,118,230,213,231,32,190,32,44,76,44,77,180, +32,162,77,162,226,122,226,52,106,52,106,122,227,122,122,14,151,40,208,12, +175,52,126,72,149,100,206,74,185,102,166,122,167,52,116,248,116,152,216,152, +217,246,116,188,217,188,116,226,217,227,26,198,26,46,70,46,71,194,26,170, +71,170,90,32,144,32,128,78,112,100,89,122,94,58,125,82,166,18,182,56, +200,88,233,116,212,22,183,52,234,46,199,82,124,96,197,96,202,174,202,132, +118,132,118,174,203,174,120,186,139,212,80,226,239,226,196,188,173,227,24,200, +24,50,66,50,67,194,24,172,67,172,82,38,241,38,130,60,131,10,188,60, +189,10,148,54,169,72,84,80,235,80,204,132,204,104,116,104,116,132,205,132, +94,242,94,154,226,154,226,234,197,242,184,212,184,182,130,182,130,212,185,213, +28,200,28,52,70,52,71,190,28,170,71,170,86,52,149,52,124,120,125,14, +82,112,125,56,150,88,125,62,162,52,235,52,192,120,193,14,150,112,193,56, +238,110,193,64,102,136,217,136,86,166,237,166,124,188,81,226,188,190,227,226, +160,166,160,240,135,245,28,182,28,48,68,48,69,178,28,156,69,156,218,76, +226,54,96,54,96,156,88,186,72,212,59,230,223,30,154,54,155,8,222,30, +155,30,116,84,201,76,150,60,150,92,150,98,156,102,200,104,212,100,219,90, +114,122,237,122,168,122,156,138,134,154,117,162,150,142,164,158,174,176,178,198, +178,216,170,230,156,236,145,236,106,198,138,180,163,158,102,226,138,208,173,176, +212,140,175,174,234,220,212,198,202,180,193,159,30,196,30,50,72,50,73,184, +30,164,73,164,144,10,169,30,94,44,227,44,88,82,239,82,124,52,145,82, +194,50,173,82,208,164,208,110,112,110,112,164,209,164,112,136,209,136,108,184, +83,228,156,176,177,202,204,180,239,222,134,182,134,216,136,228,148,238,178,238, +192,230,199,213,26,196,26,46,68,46,69,186,26,170,69,170,140,14,167,36, +98,72,98,46,226,46,227,72,106,84,219,84,110,112,213,112,88,144,235,144, +138,144,139,60,182,144,183,60,136,144,108,182,83,202,182,144,206,176,237,196, +116,196,207,196,86,234,233,234,160,234,161,163,26,198,26,40,62,40,63,182, +26,158,63,158,64,224,82,184,92,138,94,116,94,34,140,34,140,100,95,100, +102,240,102,144,142,144,143,240,102,216,143,216,172,16,201,40,156,54,235,54, +164,74,185,104,152,122,239,122,220,70,197,122,158,170,233,170,194,242,195,123, +28,188,28,44,70,44,71,178,28,158,71,158,98,28,225,28,100,96,100,58, +226,58,227,96,160,118,161,28,114,82,143,82,114,104,143,104,178,80,207,80, +178,104,209,104,84,132,239,132,104,242,104,164,220,164,220,240,201,244,162,132, +153,164,144,226,145,164,180,226,181,165,26,200,26,44,64,44,65,192,26,170, +65,170,142,14,169,34,96,68,96,46,226,46,227,70,132,60,106,96,89,112, +84,158,122,136,144,110,154,86,115,86,120,102,137,118,102,120,117,138,172,66, +180,100,200,132,231,156,194,122,218,84,179,84,130,138,195,138,98,172,225,172, +124,196,75,232,188,198,233,232,162,172,162,240,137,245,30,194,30,42,68,42, +69,186,30,164,69,164,104,20,223,20,96,84,96,50,230,50,231,84,164,102, +165,20,114,74,147,74,114,98,147,98,184,72,215,72,184,96,215,96,130,108, +100,148,83,168,114,242,115,132,156,110,181,128,120,136,237,136,120,164,225,164, +120,192,227,192,120,222,245,222,174,222,175,137,26,194,26,44,60,44,61,178, +26,160,61,160,74,30,235,30,210,68,210,48,98,48,98,68,211,68,78,116, +78,86,230,86,231,114,144,122,144,102,102,102,102,122,145,122,208,122,208,102, +166,102,166,122,209,122,84,140,225,140,88,160,219,160,76,180,237,180,128,180, +129,122,154,84,155,8,182,180,183,122,66,220,104,202,133,180,158,218,116,238, +117,194,228,236,196,226,176,214,158,196,149,180,204,190,177,215,38,242,38,34, +212,34,213,238,38,216,213,217,44,244,44,32,218,32,219,242,44,218,219,218, +62,122,197,122,80,68,166,68,130,106,130,196,105,205,40,242,40,32,216,32, +217,236,40,216,217,216,56,96,197,96,122,48,88,138,187,186,66,192,118,172, +146,140,156,114,159,97,40,238,40,30,218,30,219,234,40,210,219,210,132,48, +94,92,59,118,126,54,148,82,176,100,197,112,102,106,102,164,106,178,122,184, +160,184,176,174,183,154,164,118,103,145,36,244,36,28,220,28,221,244,36,220, +221,220,108,46,86,86,61,114,150,188,166,186,178,178,180,160,180,76,93,76, +98,190,128,160,144,126,159,76,68,168,98,138,114,108,123,77,38,244,38,26, +220,26,221,244,38,224,221,224,130,40,98,84,59,118,122,50,156,90,197,120, +112,92,137,118,72,138,160,138,125,188,86,168,153,203,40,238,40,28,218,28, +219,236,40,214,219,214,62,70,195,70,128,44,100,90,63,128,96,196,96,100, +168,100,168,188,147,196,96,128,169,128,96,156,169,157,36,242,36,30,216,30, +217,238,36,216,217,216,66,58,185,58,73,90,56,122,199,122,102,122,117,58, +72,88,164,88,161,122,168,184,168,150,84,150,84,184,169,185,38,242,38,28, +214,28,215,242,38,220,213,220,70,62,183,62,74,86,177,86,54,108,199,108, +124,108,125,38,86,206,86,130,166,130,166,202,141,206,86,152,167,152,86,176, +167,177,38,238,38,28,220,28,221,238,38,218,221,218,70,66,185,66,56,94, +201,94,128,94,129,40,70,138,187,138,92,108,109,128,164,108,143,138,60,168, +199,168,128,204,129,139,36,244,36,30,218,30,219,240,36,222,219,222,180,80, +180,54,74,54,74,80,181,80,110,80,111,54,146,80,147,54,52,102,203,102, +172,148,172,124,82,124,82,148,173,148,56,188,102,168,127,148,136,186,102,200, +103,168,136,164,195,200,190,156,159,179,64,242,65,12,30,186,30,66,98,66, +98,184,81,188,116,56,233,56,118,102,221,102,112,144,228,144,224,188,218,200, +204,204,187,204,162,246,163,11,28,186,28,64,96,64,96,178,81,184,60,242, +61,10,138,30,126,80,115,102,230,72,129,72,114,134,239,134,172,10,168,146, +148,190,124,218,97,238,236,238,210,212,190,182,171,135,58,244,59,10,28,192, +28,68,92,68,92,184,77,188,92,230,116,190,124,152,126,130,126,58,226,58, +213,92,134,122,214,122,192,176,166,210,123,240,236,236,192,210,164,182,141,122, +176,122,177,11,16,46,110,46,92,80,66,110,23,132,76,10,44,78,111,110, +126,32,212,32,192,72,166,98,131,118,232,126,200,112,166,82,141,32,54,226, +54,152,194,152,194,198,190,208,182,216,172,218,159,218,122,246,123,129,26,184, +26,66,92,66,92,184,77,188,58,246,59,14,110,52,239,52,118,86,227,86, +106,118,243,118,168,12,158,92,144,138,120,182,101,208,144,184,167,212,140,162, +239,162,204,132,204,240,177,245,28,192,28,64,92,64,92,184,81,190,60,244, +61,14,114,42,235,42,124,68,227,68,106,98,245,98,172,98,173,8,130,200, +130,124,220,124,221,196,178,140,174,186,162,210,136,228,111,238,188,206,239,239, +56,244,57,8,26,188,26,68,88,68,88,182,75,184,114,244,114,30,226,30, +227,240,114,218,227,218,132,68,209,68,134,116,205,116,132,180,209,180,184,134, +203,162,166,180,167,69,60,246,61,12,26,194,26,64,94,64,94,186,79,192, +156,12,128,74,111,94,136,246,137,58,180,14,205,48,142,66,237,66,144,116, +227,116,142,166,227,166,144,214,245,214,184,212,185,67,60,244,61,8,28,182, +28,66,90,66,90,178,77,182,82,234,106,196,116,158,116,30,218,30,218,68, +117,68,130,100,231,100,200,116,231,156,174,108,134,146,223,146,130,186,225,186, +118,226,241,226,178,226,179,159,60,244,61,10,28,188,28,62,94,62,94,182, +79,186,216,78,216,26,130,26,130,78,217,78,130,52,217,52,226,142,226,104, +120,104,120,142,227,142,156,142,157,104,192,142,193,104,118,168,210,168,196,194, +150,226,105,236,136,168,156,196,192,224,239,235,28,190,28,66,88,66,88,186, +77,190,58,246,59,10,152,10,179,32,108,46,227,46,100,88,243,88,134,60, +155,78,196,56,179,88,208,170,208,114,122,114,122,170,209,170,122,142,209,142, +100,200,243,200,166,246,167,171,26,184,26,66,90,66,90,180,75,184,58,242, +59,12,114,28,135,54,226,28,205,56,106,70,233,70,152,70,153,12,184,70, +185,12,134,82,157,104,202,82,181,108,112,114,229,114,118,144,217,144,106,174, +239,174,102,236,144,210,166,174,167,114,172,174,198,210,233,233,26,188,26,62, +88,62,88,180,75,184,56,246,57,12,216,14,184,24,111,30,120,46,143,68, +102,82,241,82,212,40,185,82,166,130,167,26,102,138,167,84,240,134,196,110, +167,82,120,248,120,144,214,144,215,244,120,184,213,184,120,224,213,224,166,224, +167,145,50,18,50,60,210,60,211,18,132,60,133,10,28,98,178,98,146,140, +202,140,170,184,67,242,102,142,122,180,233,240,88,98,82,156,27,223,94,60, +95,220,26,58,26,198,95,198,60,16,61,198,114,36,218,36,218,114,130,114, +130,210,132,222,148,232,202,232,230,220,235,197,96,206,97,60,28,60,28,194, +97,194,60,194,61,10,118,34,239,34,112,124,243,124,150,34,150,178,111,238, +206,244,207,35,94,208,95,70,26,68,26,190,95,190,58,190,59,16,108,62, +231,62,112,118,206,118,196,162,144,218,89,232,132,118,142,160,184,210,237,230, +166,118,167,11,92,216,93,64,26,68,26,200,93,200,60,200,61,12,238,34, +124,34,124,226,245,226,220,58,202,112,174,162,137,200,146,66,184,116,225,199, +98,200,99,54,30,56,30,188,99,188,62,188,63,14,114,32,229,32,146,54, +132,116,243,116,200,32,200,236,167,244,186,116,164,162,132,198,91,225,96,208, +97,60,28,58,28,192,97,192,60,192,61,12,134,162,134,28,212,28,213,160, +174,56,168,148,140,204,97,238,182,136,182,216,188,228,200,236,216,236,230,230, +238,218,239,201,202,20,142,32,45,36,18,76,233,76,126,34,116,66,84,110, +21,148,146,76,172,112,235,146,194,152,195,242,58,154,58,224,195,224,124,224, +125,119,50,20,50,66,204,66,205,18,126,66,127,10,128,74,90,114,58,138, +19,158,122,80,160,116,198,138,237,152,112,124,147,154,60,172,178,172,137,241, +50,20,50,60,208,60,209,16,126,12,127,60,20,238,52,178,52,96,194,96, +194,180,216,232,230,232,241,210,84,124,148,182,175,216,162,114,122,172,73,219, +48,22,48,60,198,60,199,20,122,12,123,60,224,200,216,218,198,230,84,230, +56,224,48,200,48,98,196,98,196,156,49,156,122,156,123,99,92,216,93,62, +24,62,24,198,93,198,58,198,59,16,106,76,241,76,130,242,130,140,220,140, +221,242,130,214,221,214,172,140,173,11,50,26,50,68,206,68,207,26,130,68, +131,10,12,104,245,104,188,104,188,214,186,226,180,236,174,238,149,238,138,192, +138,138,58,138,58,192,139,193,54,24,54,62,208,62,209,22,132,62,133,18, +22,106,235,106,116,70,60,162,213,162,90,186,37,236,172,188,229,228,138,124, +138,218,136,228,130,236,126,236,111,237,94,56,95,206,30,58,30,190,95,190, +62,190,63,12,126,182,126,36,222,36,223,184,126,162,223,162,126,98,223,98, +176,246,177,37,96,66,97,218,28,68,28,202,97,202,62,202,63,16,132,242, +132,72,222,72,223,240,132,138,223,138,132,216,223,216,178,216,179,13,96,12, +50,66,21,86,62,138,63,54,236,66,93,66,182,18,217,44,142,10,152,58, +176,104,214,132,226,132,232,122,241,108,208,154,209,244,56,156,56,222,209,222, +132,222,133,123,96,216,97,66,30,66,30,198,97,198,62,198,63,18,150,12, +130,68,113,94,184,172,184,110,134,110,134,172,185,172,136,54,224,54,224,210, +220,222,210,230,196,234,177,235,46,16,46,60,216,60,217,16,132,60,133,8, +120,84,78,96,44,100,44,174,107,154,110,114,108,154,102,182,80,212,31,238, +160,244,160,98,220,98,220,172,218,182,210,188,202,190,187,191,88,64,89,210, +26,68,26,196,89,196,54,196,55,14,170,202,120,230,120,28,214,28,214,84, +121,84,120,136,235,136,174,84,182,154,196,198,212,226,220,228,232,222,239,193, +90,212,91,66,28,64,28,196,91,196,58,196,59,10,100,28,210,28,180,66, +144,94,109,114,122,28,148,68,188,96,235,112,114,142,219,142,106,186,235,186, +162,244,163,109,88,216,89,60,26,62,26,200,89,200,56,200,57,12,118,240, +118,34,220,34,220,234,189,242,136,78,199,78,188,180,188,118,146,118,146,180, +189,181,84,214,85,58,24,58,24,198,85,198,54,198,55,14,212,20,174,32, +115,38,100,80,231,80,162,34,156,84,136,120,109,148,170,80,200,122,233,142, +142,138,140,180,124,218,101,240,196,244,197,141,94,216,95,62,30,62,30,200, +95,200,60,200,61,14,148,12,128,66,111,94,134,52,226,52,226,210,222,220, +214,230,200,234,175,234,184,184,184,100,130,100,130,184,185,184,130,140,185,141, +96,208,97,60,28,62,28,192,97,192,62,192,63,16,152,14,130,54,115,74, +114,88,218,88,219,196,172,88,192,42,139,42,104,128,243,128,112,174,219,174, +164,88,164,218,162,226,154,236,138,240,131,241,84,214,85,56,24,56,24,198, +85,198,54,198,55,12,100,50,235,50,142,78,143,10,190,78,191,12,108,132, +108,96,226,96,227,132,116,148,212,148,204,216,202,224,196,230,184,236,173,236, +160,112,154,172,134,210,101,239,88,196,89,64,28,60,28,186,89,186,56,186, +57,16,102,56,229,56,94,132,241,132,164,242,165,8,118,76,141,112,214,76, +189,112,80,216,124,184,165,134,236,214,192,176,165,135,46,20,46,58,208,58, +209,14,126,58,127,8,16,116,101,116,62,244,63,72,16,200,40,166,63,118, +88,176,63,140,144,82,122,122,99,154,172,72,186,110,208,138,235,158,180,162, +219,236,158,128,114,226,207,219,82,210,83,70,22,70,22,196,83,196,50,196, +51,24,102,50,229,50,164,12,152,58,128,84,97,110,170,50,186,74,208,94, +235,108,212,184,212,116,120,116,120,184,213,184,120,148,213,148,162,84,162,212, +164,220,172,230,190,234,212,234,224,228,228,218,233,205,38,26,38,60,216,60, +217,20,126,60,127,12,44,244,44,92,210,92,211,242,44,220,211,220,62,124, +189,124,166,192,166,154,86,154,86,192,167,192,124,154,125,105,94,66,95,218, +32,66,32,200,95,200,62,200,63,14,132,20,186,52,221,78,208,12,156,60, +119,80,108,100,245,100,172,72,140,128,109,164,144,242,144,128,214,128,214,236, +193,242,144,160,213,160,144,190,213,191,88,210,89,66,24,66,24,196,89,196, +54,196,55,16,144,12,177,36,102,48,235,48,212,114,212,76,122,76,122,114, +213,114,104,188,241,188,114,142,208,142,170,172,170,238,141,243,94,68,95,216, +30,70,30,202,95,202,62,202,63,20,152,14,179,42,122,92,122,54,228,54, +229,92,158,90,121,128,184,88,223,126,120,158,229,158,110,226,239,226,170,226, +171,159,86,200,87,62,26,64,26,190,85,190,54,190,55,10,84,230,108,194, +116,150,116,24,220,24,220,68,117,68,144,100,144,150,220,150,221,102,228,168, +229,244,136,168,136,228,229,228,180,228,181,85,82,208,83,64,24,66,24,194, +83,194,52,194,53,12,92,48,231,48,138,78,139,12,188,78,189,12,110,124, +110,94,220,94,221,124,104,146,223,146,160,244,161,108,90,224,124,198,161,152, +232,226,204,202,163,147,90,216,91,68,24,60,24,196,91,196,54,196,55,16, +108,30,241,30,224,122,224,68,120,68,120,122,225,122,154,122,155,30,188,122, +189,30,102,160,243,160,166,130,132,190,233,236,206,160,186,198,158,222,109,241, +48,14,48,56,210,56,211,14,130,56,131,10,184,64,209,82,236,92,44,92, +44,166,36,200,19,232,62,122,145,122,60,158,130,158,116,188,92,212,63,228, +102,132,78,184,135,212,206,120,174,192,137,234,156,62,162,120,176,174,210,222, +220,234,226,232,234,224,239,203,46,18,46,56,206,56,207,14,126,56,127,8, +196,160,196,86,58,86,58,160,197,160,126,160,127,86,58,122,197,122,52,178, +25,226,120,172,149,200,198,178,235,216,88,176,88,214,90,228,102,232,170,232, +182,224,189,205,46,14,46,54,206,54,207,16,122,54,123,8,198,156,198,88, +52,88,52,156,199,156,52,120,199,120,104,60,91,88,120,88,120,128,114,166, +86,198,50,220,21,234,138,156,138,210,140,224,154,232,214,232,228,224,239,202, +194,176,217,210,182,166,156,206,209,199,54,16,54,56,210,56,211,14,130,56, +131,10,18,120,72,98,131,56,240,120,186,104,146,78,131,56,78,104,175,104, +50,242,50,136,120,136,120,234,93,242,50,164,121,164,50,194,121,194,160,208, +161,136,204,130,204,236,175,245,90,62,91,200,30,66,30,192,91,192,60,192, +61,16,130,16,157,42,207,12,106,54,235,54,206,12,181,54,166,54,162,108, +134,168,81,216,116,92,225,92,102,128,241,128,216,168,137,168,106,228,237,228, +172,228,173,169,88,210,89,70,24,68,24,196,89,196,56,196,57,18,116,24, +147,54,218,20,193,56,106,72,237,72,168,132,169,10,106,128,136,104,167,72, +234,128,200,108,171,72,102,162,243,162,158,136,128,190,235,236,200,162,184,196, +158,222,101,239,88,208,89,68,26,64,26,196,89,196,56,196,57,14,122,16, +153,58,102,68,243,68,216,14,183,68,142,184,163,224,156,112,100,228,155,206, +138,78,102,152,137,152,216,188,237,238,224,118,168,232,229,218,202,78,168,156, +203,157,90,204,91,60,26,58,26,190,91,190,58,190,59,12,94,232,112,196, +118,148,118,28,224,28,224,82,119,82,174,82,175,28,144,242,144,114,226,114, +227,240,144,148,227,148,144,184,227,184,144,220,227,221,82,196,83,60,24,62, +24,184,83,184,52,184,53,14,218,16,170,26,107,30,98,66,239,66,160,242, +161,26,130,154,131,86,100,106,131,106,100,146,131,136,190,84,190,134,194,142, +204,148,214,148,222,140,227,130,224,98,191,116,84,216,122,186,161,140,234,214, +198,188,161,147,48,24,48,56,210,56,211,24,128,56,129,16,16,88,241,88, +118,62,145,82,186,138,186,114,68,114,68,138,187,138,40,242,40,164,216,164, +216,220,214,228,210,232,198,238,183,238,170,218,170,186,82,186,82,218,171,219, +78,204,79,62,18,62,18,194,79,194,50,194,51,20,98,28,135,40,98,82, +137,62,224,24,189,48,200,64,237,82,164,8,154,60,132,98,97,122,234,122, +184,84,159,42,126,246,126,122,204,122,204,240,179,246,126,186,205,186,126,154, +205,155,88,212,89,58,28,60,28,196,89,196,58,196,59,14,156,12,183,34, +108,44,227,44,100,84,241,84,134,56,153,76,200,56,181,84,210,166,210,110, +122,110,122,166,211,166,122,138,211,138,102,196,243,196,170,244,171,167,84,216, +85,60,26,64,26,198,85,198,54,198,55,18,112,26,141,54,214,22,185,54, +102,70,239,70,162,126,163,8,102,122,132,100,163,72,234,118,196,98,169,70, +132,124,114,156,101,174,90,238,124,214,144,178,150,148,121,148,116,180,133,196, +166,152,241,152,170,168,164,192,247,192,202,244,203,121,86,210,87,58,24,60, +24,196,87,196,54,196,55,18,102,30,156,30,136,86,103,120,106,60,137,82, +178,20,200,78,237,114,218,22,187,40,232,50,201,74,142,90,199,90,210,164, +210,122,124,122,124,164,211,164,130,182,157,210,94,226,239,226,206,184,181,227, +220,66,221,246,32,62,32,226,221,226,126,226,127,8,44,44,113,44,80,44, +60,80,49,94,66,72,76,90,84,114,86,182,80,194,70,200,61,202,46,138, +64,116,77,92,48,176,68,148,85,128,108,72,85,112,114,156,85,120,146,42, +209,42,176,42,158,78,143,94,162,70,182,110,182,178,176,194,164,198,155,198, +142,132,160,112,175,92,144,168,166,144,183,126,202,70,181,108,208,156,183,117, +52,20,52,54,216,54,217,22,134,54,135,10,46,68,46,102,50,112,60,116, +102,116,112,112,119,98,116,78,47,94,52,124,33,164,114,144,45,144,18,178, +123,178,26,240,56,218,76,178,81,144,108,212,73,186,160,100,193,124,136,82, +212,82,183,116,124,132,226,132,217,154,148,158,130,210,111,240,234,228,170,224, +137,196,178,224,179,132,178,180,237,181,44,12,44,48,212,48,213,12,128,48, +129,8,24,82,125,82,18,196,129,196,44,196,44,108,110,108,111,196,72,108, +79,58,44,130,111,130,44,154,111,154,44,176,111,176,60,208,25,238,90,206, +115,226,138,78,235,78,146,202,146,112,212,112,213,202,166,112,179,78,180,132, +180,188,154,226,125,242,186,206,233,237,154,20,102,70,57,98,178,66,118,126, +53,172,134,242,135,111,72,14,46,48,21,72,76,74,48,118,21,148,58,242, +59,104,146,12,183,52,94,68,241,68,144,68,144,134,136,178,118,210,89,234, +144,124,218,124,216,200,210,218,194,226,169,231,78,20,48,56,23,80,84,78, +54,122,17,154,60,244,61,116,82,226,243,226,124,226,124,38,210,38,211,226, +124,98,211,98,124,160,211,161,72,16,48,46,23,72,76,72,48,114,21,146, +58,242,59,100,138,12,114,62,93,96,176,184,176,94,118,94,118,184,177,184, +118,136,177,136,120,48,228,48,228,202,224,218,214,226,200,230,177,231,76,16, +48,50,23,74,80,72,50,116,19,148,62,242,63,100,118,14,149,52,96,66, +239,66,208,12,177,66,108,118,225,118,90,170,247,170,166,244,167,67,74,18, +46,58,25,80,84,68,52,122,23,156,60,244,61,110,196,90,227,136,202,44, +102,126,211,114,160,18,110,72,167,72,134,138,112,174,89,196,86,238,132,224, +178,192,200,154,125,154,128,168,148,200,174,218,237,237,74,20,50,50,25,76, +78,80,48,122,17,150,58,244,59,110,94,56,221,56,108,84,133,112,204,82, +185,114,84,132,235,132,158,242,159,10,84,218,120,186,153,132,234,216,196,186, +161,133,76,10,48,46,27,64,82,66,48,116,23,140,60,240,61,98,86,102, +245,102,126,102,127,38,170,102,171,6,170,54,231,54,118,130,112,182,85,230, +240,224,194,224,148,210,115,160,168,214,169,102,168,150,233,151,72,14,46,48, +27,68,76,80,46,124,21,148,54,248,55,112,100,32,137,78,226,28,195,78, +102,246,102,100,228,100,228,218,226,226,220,232,206,236,195,236,190,190,190,140, +138,140,138,190,191,190,162,100,163,9,72,20,44,56,23,76,78,76,46,122, +19,152,58,242,59,106,222,110,222,40,114,40,114,110,223,110,114,76,223,76, +96,146,237,146,108,188,223,188,86,228,247,228,166,228,167,146,164,10,145,41, +80,12,48,52,23,74,82,68,50,118,21,152,60,244,61,104,220,16,174,28, +103,36,108,58,129,88,152,48,173,80,224,40,189,94,136,94,114,130,103,146, +224,116,125,116,80,160,245,160,222,244,223,178,112,178,112,228,223,228,166,228, +167,117,68,14,40,58,21,80,66,80,42,116,17,150,46,246,47,112,84,30, +84,74,146,74,147,30,114,74,115,14,80,102,145,102,74,132,149,132,78,164, +149,164,68,206,157,206,114,206,115,132,194,16,174,84,157,118,174,114,192,182, +237,234,242,78,177,78,216,78,204,154,178,206,147,237,70,14,44,52,21,76, +72,76,40,122,17,150,50,244,51,108,144,108,144,48,88,48,88,108,145,108, +88,78,145,78,122,16,103,48,102,116,125,134,70,144,161,144,98,144,96,182, +69,232,114,222,130,220,140,208,144,172,99,172,190,14,170,82,151,122,242,76, +173,76,172,112,184,164,206,206,237,238,144,240,176,204,202,156,215,77,66,18, +44,58,25,84,66,88,40,130,19,154,50,242,51,114,116,104,116,28,86,28, +86,104,117,104,86,54,117,54,86,78,117,78,176,106,176,28,140,28,140,106, +177,106,140,54,177,54,140,78,177,78,110,118,71,166,94,234,95,136,130,116, +143,132,102,138,177,138,102,164,173,164,102,188,173,188,102,214,181,214,134,212, +135,138,188,36,237,36,186,102,247,102,212,102,212,238,183,245,174,24,114,70, +61,96,184,90,134,130,79,160,214,144,140,198,55,229,124,18,80,68,29,102, +46,24,82,52,98,82,108,124,106,198,90,222,72,230,49,230,30,174,72,146, +105,109,86,20,50,72,23,98,28,28,62,68,72,100,74,196,66,222,50,230, +37,228,20,174,52,136,73,108,93,82,92,82,196,82,196,208,198,220,204,228, +214,228,228,224,238,216,243,202,148,14,148,54,142,124,128,184,89,237,88,18, +50,70,25,98,24,28,58,66,76,108,78,190,72,218,58,228,44,228,37,230, +18,174,48,142,75,104,102,38,231,38,94,120,243,120,166,244,167,39,92,20, +54,72,25,100,30,30,66,64,80,94,88,124,84,194,76,220,66,228,52,230, +39,230,22,176,54,140,83,102,162,14,191,48,244,60,130,60,130,160,122,196, +101,241,82,20,50,66,21,96,28,28,62,66,72,90,78,124,78,206,72,222, +60,232,39,236,18,176,54,134,75,100,134,56,124,136,230,136,226,216,220,228, +210,234,198,236,189,236,98,184,203,184,104,34,204,34,201,137,88,26,50,78, +19,108,22,38,62,76,74,116,78,176,74,220,56,236,37,238,72,112,52,148, +23,186,90,226,245,226,104,42,218,42,209,226,108,124,213,124,142,226,157,43, +82,20,50,66,17,98,22,30,48,58,66,90,76,140,74,182,68,214,56,228, +35,230,18,176,69,104,190,54,233,116,160,16,106,106,219,100,92,236,122,210, +138,170,140,140,141,104,232,198,228,222,214,230,190,228,180,208,181,103,90,18, +50,68,21,96,26,20,56,50,74,84,80,134,76,214,64,226,43,234,18,172, +50,140,77,102,116,180,116,34,222,34,223,174,116,154,223,154,116,92,223,92, +170,244,171,35,22,30,54,58,66,80,74,112,72,210,58,230,35,236,72,108, +44,146,19,170,82,24,50,68,23,94,146,12,120,62,95,94,194,178,216,174, +224,162,224,52,127,52,238,198,230,220,208,232,146,234,128,226,122,202,122,96, +178,96,178,146,123,147,80,20,48,62,21,88,26,28,60,64,70,94,76,130, +70,216,54,228,33,228,20,172,52,136,73,110,98,50,218,50,218,98,104,98, +104,150,230,150,230,206,209,212,92,238,122,212,138,178,142,144,143,10,180,244, +181,7,26,22,54,42,78,82,84,122,82,208,74,226,52,234,35,236,98,18, +56,68,25,94,82,110,54,142,25,170,96,82,243,82,182,14,182,120,188,174, +202,216,216,232,224,236,230,232,241,202,204,32,229,60,222,108,208,158,182,202, +151,236,102,150,169,150,136,102,136,162,132,190,118,220,103,237,82,24,48,66, +19,90,24,26,56,60,70,96,74,126,72,214,54,228,35,236,16,170,46,140, +73,112,158,10,136,56,114,80,93,102,152,22,174,50,200,78,239,100,112,110, +207,110,94,156,235,156,186,184,229,240,150,164,98,232,211,219,94,22,58,68, +29,96,28,30,66,64,80,96,90,142,84,214,66,230,39,236,82,110,52,150, +23,176,154,14,187,40,118,92,118,54,228,54,229,90,106,126,245,126,130,148, +163,184,198,78,198,236,161,245,78,18,52,62,21,98,18,28,52,64,60,86, +66,108,70,148,66,212,50,230,27,234,20,168,48,138,67,114,88,36,152,36, +114,92,114,234,91,242,84,154,143,116,164,82,158,142,143,190,214,82,241,188, +192,14,192,234,167,241,82,20,52,64,19,102,22,36,56,72,70,98,76,132, +74,214,60,232,41,236,20,180,73,112,114,22,114,128,161,104,160,64,115,64, +180,14,180,110,184,122,196,130,220,130,232,122,239,102,230,38,181,76,106,174, +227,174,92,226,243,226,164,226,165,139,90,20,50,62,23,88,22,28,58,60, +70,82,76,120,74,206,60,224,35,230,20,164,50,136,75,110,212,72,212,26, +128,26,128,72,213,72,118,240,118,110,222,110,222,232,197,238,118,144,223,144, +118,180,223,181,20,30,46,56,64,88,74,128,74,202,58,224,31,232,86,26, +52,66,21,94,20,168,48,140,71,110,172,26,138,36,99,46,90,96,173,96, +134,240,135,36,94,180,118,140,135,100,168,146,135,114,190,174,191,56,226,18, +226,232,197,241,24,36,54,66,68,94,74,136,74,202,66,224,52,232,37,234, +18,180,50,140,69,108,16,102,50,68,83,20,162,18,130,76,95,110,238,112, +196,80,157,28,118,110,209,110,102,154,235,154,132,174,97,230,190,172,233,228, +164,110,164,240,141,245,90,20,58,58,21,92,24,26,52,54,64,86,70,128, +68,210,56,230,42,234,33,236,16,164,46,136,69,114,160,12,128,64,89,106, +156,18,184,62,239,102,114,102,213,102,104,138,133,190,152,126,169,188,90,228, +239,228,212,132,175,229,86,16,50,68,23,96,24,32,56,62,70,90,76,128, +74,212,62,226,50,230,39,230,72,104,50,140,23,174,152,14,183,46,100,56, +245,56,118,94,227,94,118,132,227,132,124,240,124,168,222,168,223,240,124,220, +223,221,84,16,48,70,19,96,22,28,52,60,66,86,72,108,76,182,68,216, +50,228,38,230,33,230,18,174,50,134,71,104,167,12,186,36,233,78,166,12, +108,70,215,62,150,86,103,126,182,86,233,124,158,114,132,156,107,184,146,162, +164,194,190,216,235,236,102,234,158,210,192,174,206,138,145,139,84,16,52,62, +23,90,26,22,62,56,74,94,74,210,62,228,48,232,31,232,20,170,50,140, +75,106,100,48,227,48,166,10,156,58,138,80,111,98,210,96,157,54,92,116, +239,116,204,116,204,238,179,242,166,196,166,148,112,148,112,196,167,197,78,24, +44,68,21,92,20,32,48,58,62,84,68,106,72,184,66,218,48,232,25,234, +208,110,208,30,108,30,108,110,209,110,108,72,209,72,92,146,237,146,160,244, +161,30,88,222,122,192,155,146,238,226,202,198,163,146,20,168,44,144,69,115, +90,16,52,62,23,90,26,22,58,54,74,84,82,132,78,200,70,222,54,230, +35,232,20,166,52,138,77,102,228,90,228,26,118,26,118,90,229,90,154,90, +155,26,188,90,189,26,162,100,136,136,107,164,96,234,158,212,196,184,228,130, +143,130,146,154,181,195,82,24,50,64,19,94,24,28,56,62,68,92,74,128, +72,194,58,222,46,228,31,230,18,168,46,138,71,106,160,16,114,38,114,130, +218,130,218,32,179,32,159,82,150,82,115,82,182,80,219,80,146,130,146,148, +138,190,110,228,89,242,180,130,180,212,184,226,202,234,216,234,232,222,239,203, +86,22,54,60,21,92,20,22,54,60,70,98,78,148,76,184,68,214,58,228, +33,234,18,166,48,136,73,108,164,12,134,60,95,100,160,18,184,54,212,80, +241,96,122,92,203,92,100,130,231,130,114,244,114,168,212,168,213,246,114,224, +213,224,162,168,163,93,22,22,56,56,70,90,78,132,74,208,60,226,44,234, +31,236,88,16,58,54,23,88,18,164,54,134,75,114,144,12,179,40,98,52, +237,52,138,66,124,106,105,144,160,122,131,94,200,66,190,104,165,146,230,140, +191,104,92,180,247,180,164,244,165,155,80,22,46,72,23,98,24,30,56,64, +62,94,66,204,60,222,48,234,38,236,29,236,20,170,44,142,63,114,92,38, +130,38,130,96,92,96,92,146,124,146,122,216,120,224,110,230,95,232,184,14, +168,60,149,100,214,102,232,60,169,60,190,94,190,238,165,244,166,136,143,202, +212,134,239,203,84,26,48,70,23,92,24,30,60,66,66,94,72,164,64,216, +54,224,40,228,33,228,20,160,44,134,67,106,84,74,161,74,102,216,102,130, +146,130,147,210,102,194,147,194,124,130,125,18,146,238,164,214,174,182,178,150, +178,28,228,28,228,234,205,240,178,88,229,88,178,148,229,149,82,20,54,60, +19,96,20,34,56,60,68,86,74,126,74,216,68,226,54,238,39,240,18,178, +46,144,71,102,94,48,235,48,160,110,161,12,94,112,128,84,161,50,238,112, +200,88,161,50,212,196,212,126,114,126,114,196,213,196,114,162,213,162,88,228, +241,229,84,20,46,68,19,94,22,24,56,56,68,84,74,130,70,208,60,224, +44,232,31,232,18,164,50,134,71,106,218,110,218,28,114,28,114,110,219,110, +114,70,219,70,166,110,167,28,94,140,239,140,120,140,120,238,165,202,160,140, +176,184,204,216,239,238,218,162,185,195,84,24,50,72,21,96,26,30,56,56, +70,88,78,130,74,218,64,228,54,232,41,234,16,166,52,136,75,110,230,102, +230,30,114,30,114,102,231,102,114,66,231,66,172,102,173,30,122,244,122,130, +222,130,222,238,193,242,122,160,223,160,122,196,223,197,92,20,58,62,21,92, +24,24,52,46,70,74,78,108,82,142,78,202,68,224,54,232,33,236,20,172, +52,146,79,114,90,240,106,214,112,186,116,156,116,30,230,30,230,76,117,76, +172,76,173,30,144,242,144,110,226,110,227,242,144,144,227,144,144,180,227,180, +144,216,227,217,84,14,46,66,19,92,24,26,58,58,70,84,74,130,72,200, +64,220,52,230,38,232,31,230,18,166,50,130,71,102,138,46,177,68,112,24, +200,24,165,60,92,74,230,74,211,104,98,122,140,102,169,74,146,126,160,126, +172,122,174,108,175,74,92,158,233,158,160,244,161,138,90,218,130,190,159,158, +240,222,200,198,161,159,92,26,58,62,21,92,28,22,58,58,70,92,76,122, +78,192,74,210,62,224,50,228,37,230,20,170,52,142,75,116,142,12,177,38, +96,48,235,48,88,88,245,88,126,60,147,88,202,56,183,88,216,174,216,114, +114,114,114,174,217,174,114,144,217,144,90,202,247,202,166,246,167,175,88,22, +54,66,23,98,24,34,56,66,68,90,76,116,78,150,74,212,62,226,48,232, +35,232,20,174,52,136,73,106,148,16,183,40,102,48,233,48,92,90,245,90, +130,60,153,90,202,60,183,90,220,170,220,114,118,114,118,170,221,170,118,142, +221,142,148,170,148,184,142,204,128,222,101,238,184,170,184,218,186,228,196,234, +222,234,236,222,239,207,76,22,48,56,19,82,18,22,48,56,62,94,68,136, +60,190,52,208,38,218,19,220,16,154,63,102,63,238,242,30,98,30,98,144, +88,196,63,238,118,48,135,78,112,92,177,92,170,46,151,92,170,120,171,186, +122,118,122,170,171,166,144,92,144,150,138,184,124,212,107,232,206,46,179,116, +222,120,232,94,189,94,200,124,198,168,186,204,161,238,240,238,222,210,206,170, +201,135,86,24,54,64,21,94,28,26,52,52,64,76,68,110,66,206,58,224, +42,232,29,230,16,168,44,140,69,112,94,46,237,46,166,12,146,60,128,82, +87,114,100,64,127,84,170,46,184,70,194,86,218,100,241,110,222,62,197,88, +206,168,206,102,120,102,120,168,207,168,120,134,207,134,132,186,89,224,190,194, +233,226,164,168,164,240,141,247,72,18,50,52,21,88,22,34,46,62,58,84, +62,110,62,212,54,226,40,230,33,230,20,164,42,134,61,100,120,14,98,54, +79,80,80,236,94,206,96,174,96,84,156,84,156,230,137,236,124,212,125,84, +96,130,157,130,96,170,157,170,126,84,144,44,105,44,170,28,232,28,232,54, +230,80,224,86,211,90,174,92,190,66,195,28,184,112,175,158,240,138,179,138, +170,180,247,180,208,240,209,105,78,16,60,46,40,72,21,94,22,30,54,60, +64,80,72,112,72,208,62,226,46,232,33,232,20,170,48,134,69,100,222,22, +158,30,101,34,92,62,243,62,104,154,231,154,92,180,245,180,228,132,228,86, +110,86,110,132,229,132,130,100,147,118,204,100,189,120,166,178,167,30,120,200, +95,238,146,200,157,238,178,198,187,234,210,194,237,239,86,18,50,64,21,88, +24,24,54,52,66,76,74,100,78,122,78,200,68,224,48,234,29,236,20,166, +54,140,77,112,94,40,245,40,136,58,137,8,198,58,199,10,152,102,152,70, +108,70,108,102,153,102,226,102,226,70,182,70,182,102,227,102,132,112,114,144, +95,164,162,110,189,130,120,248,121,132,121,142,128,142,239,142,128,170,227,170, +128,198,227,198,128,226,245,226,176,226,177,143,72,14,52,84,23,134,26,222, +58,200,88,164,104,114,110,68,59,68,58,124,91,156,132,72,239,72,144,94, +134,162,243,162,190,240,191,11,106,108,106,30,30,30,30,108,107,108,12,138, +125,138,68,244,69,30,18,206,44,182,69,148,110,186,69,144,30,70,107,70, +178,14,154,46,129,68,132,122,168,104,202,68,218,42,159,42,156,66,181,92, +206,100,164,144,133,168,116,232,152,222,190,198,218,168,234,132,177,132,166,172, +191,197,58,16,40,78,19,120,24,226,54,198,74,160,82,112,86,68,45,68, +42,118,75,146,168,14,134,68,101,102,234,98,194,70,163,26,152,70,179,94, +174,210,124,234,124,102,206,102,206,164,125,164,124,134,207,134,160,180,231,236, +224,168,191,205,128,16,88,40,51,54,36,86,94,82,152,62,198,36,95,36, +90,54,113,74,32,136,32,102,224,102,225,136,124,84,141,102,56,130,199,130, +196,204,196,154,56,154,56,204,197,204,56,180,197,180,128,204,129,130,104,216, +62,234,31,242,152,218,227,241,104,16,78,84,43,134,36,228,116,178,164,122, +188,70,85,70,70,96,116,158,170,198,231,229,72,18,50,74,21,112,114,108, +132,66,55,66,78,92,78,230,129,195,70,18,44,70,19,102,90,98,108,64, +49,64,58,104,58,230,91,198,116,34,202,34,126,114,228,114,222,202,212,222, +194,232,171,236,160,114,144,146,105,186,196,114,168,178,111,237,58,10,36,70, +17,102,82,94,100,60,41,60,54,100,54,226,99,184,116,60,235,60,124,92, +124,166,214,166,215,92,168,10,168,212,170,224,180,232,214,232,232,220,237,199, +58,12,38,72,19,108,82,100,92,62,43,62,54,104,54,224,105,192,152,10, +130,62,111,98,234,50,137,50,134,88,227,88,120,122,204,122,204,152,204,180, +206,204,212,224,220,234,228,232,239,209,58,16,38,72,21,104,86,100,100,64, +43,64,52,108,52,228,99,192,222,28,162,46,121,48,100,126,243,126,108,224, +233,224,170,224,171,45,64,18,40,68,19,100,88,92,102,64,45,64,56,104, +56,214,101,182,222,28,160,38,115,40,100,116,235,116,162,38,162,118,154,162, +136,198,95,236,232,230,204,202,178,164,163,117,66,12,44,62,19,98,82,92, +102,58,47,58,56,104,56,222,99,194,152,10,132,68,109,100,244,58,137,58, +112,130,222,130,218,214,210,228,196,234,183,234,166,80,162,148,148,192,126,216, +99,237,62,18,40,68,19,104,82,106,98,64,43,64,54,112,54,234,99,192, +194,54,243,112,172,14,114,106,231,98,128,244,128,146,220,146,221,240,128,216, +221,217,62,14,36,76,19,104,78,102,96,68,41,68,56,110,56,228,97,188, +120,244,120,62,232,62,232,236,205,242,198,176,198,106,154,106,154,176,199,176, +168,12,147,63,62,18,38,74,21,104,78,98,92,68,43,68,56,104,56,226, +95,192,110,50,241,50,110,124,110,86,230,86,231,122,168,86,169,12,126,122, +202,122,172,154,172,224,168,236,154,238,139,238,102,174,245,175,60,16,40,70, +19,102,80,94,96,62,45,62,52,106,52,224,89,198,162,12,138,64,97,110, +236,98,192,70,157,26,116,110,219,110,100,154,231,154,132,182,95,230,196,180, +231,224,164,110,164,238,139,245,58,16,38,68,17,102,84,92,98,56,45,56, +52,100,52,224,91,190,218,114,218,32,122,32,122,114,219,114,122,72,219,72, +118,132,118,234,163,210,162,166,119,166,184,128,184,220,188,228,200,236,220,236, +234,226,241,208,236,150,185,173,52,14,34,66,13,100,76,98,92,58,39,58, +48,82,48,228,95,196,106,46,235,46,168,120,169,12,96,118,142,84,169,54, +240,116,202,92,169,54,214,204,214,134,122,134,122,204,215,204,122,166,215,166, +92,230,247,231,62,12,38,66,19,96,80,86,90,58,43,58,54,98,54,224, +99,184,148,28,114,38,114,114,226,114,226,36,191,36,146,76,115,76,192,76, +227,76,104,146,214,146,180,194,140,222,101,236,130,146,152,186,198,218,237,236, +168,10,169,147,62,16,38,70,19,102,76,96,90,62,43,62,54,104,54,228, +93,200,100,46,237,46,140,68,141,12,190,68,191,12,218,146,218,80,114,80, +114,146,219,146,114,114,219,114,94,180,241,180,166,146,160,188,138,218,91,240, +236,238,196,218,163,181,58,18,34,78,17,110,80,98,92,64,41,64,52,104, +52,220,93,186,128,16,153,46,106,58,237,58,206,16,185,58,112,94,225,94, +98,124,241,124,162,58,162,78,152,134,130,182,95,222,144,154,218,154,215,234, +112,234,245,234,162,234,171,154,136,190,215,191,54,16,36,74,19,108,84,94, +92,64,41,64,56,104,56,224,93,188,98,46,241,46,134,14,134,74,198,74, +199,12,218,140,218,102,114,102,114,140,219,140,100,168,229,168,106,198,225,198, +92,228,241,228,164,228,165,75,52,14,32,76,19,104,68,94,76,64,37,64, +50,102,50,224,81,186,90,52,163,52,88,94,163,94,110,94,111,14,140,94, +141,12,100,240,100,124,150,124,150,232,131,238,100,156,151,156,100,186,151,186, +196,14,180,76,163,114,240,68,183,68,180,106,186,148,204,194,239,230,164,234, +188,202,208,150,217,69,56,14,34,70,21,94,74,98,86,64,37,64,52,102, +52,228,89,202,160,90,150,104,142,108,122,108,112,104,110,94,110,32,152,32, +152,70,111,70,238,90,230,104,218,108,198,108,188,106,182,96,182,32,224,32, +224,70,183,70,96,146,237,146,82,182,245,182,140,182,141,120,192,182,193,118, +146,198,89,240,184,200,239,239,54,16,36,80,17,116,70,94,82,62,41,62, +48,106,48,220,83,172,94,32,237,32,214,70,214,50,116,50,116,70,215,70, +94,114,94,88,236,88,237,114,166,88,167,6,152,126,152,106,116,106,116,126, +153,126,214,126,214,106,178,106,178,126,213,126,98,146,233,146,104,166,227,166, +90,186,247,186,82,224,122,208,151,186,132,202,132,240,175,224,176,186,190,208, +214,228,241,240,224,196,199,214,142,186,143,126,188,186,189,127,124,14,163,40, +238,52,52,52,52,156,44,188,23,238,108,72,108,204,112,220,124,228,208,228, +220,218,229,190,202,102,109,149,118,16,157,40,236,52,48,52,48,168,40,200, +25,238,80,88,217,88,66,142,235,142,142,88,138,154,114,200,65,240,65,240, +168,142,168,218,172,230,182,236,214,236,228,224,235,205,116,16,153,40,238,52, +48,52,48,162,36,216,21,240,64,102,231,102,84,144,202,144,176,180,124,218, +69,240,104,144,132,184,174,218,233,238,148,68,149,145,124,14,157,36,238,46, +50,46,50,178,40,210,23,238,116,58,90,100,67,122,184,176,200,174,210,164, +212,84,101,84,238,198,228,216,204,228,126,228,102,226,94,208,94,122,162,122, +162,162,95,163,112,16,149,38,226,50,38,50,38,170,30,210,11,244,106,70, +82,114,55,154,82,246,83,114,108,114,225,114,164,246,165,66,102,216,134,176, +165,116,234,206,208,184,165,123,120,12,155,38,232,50,46,50,46,160,34,200, +21,228,96,66,125,94,70,108,225,108,186,64,159,108,78,152,215,152,58,196, +239,196,144,246,145,109,126,16,159,38,242,50,50,50,50,164,40,204,21,240, +66,88,237,88,110,62,110,116,190,116,191,60,58,242,80,220,92,194,96,146, +204,146,204,182,95,182,154,182,168,202,200,226,237,241,120,16,151,36,234,46, +44,46,44,174,38,206,21,234,64,86,231,86,146,58,110,110,65,144,238,132, +196,114,169,86,202,196,202,134,92,134,92,196,203,196,92,164,203,164,146,106, +146,222,150,234,166,240,210,240,226,228,231,211,120,12,147,34,230,46,44,46, +44,176,34,210,17,236,118,76,84,88,84,164,208,164,208,84,167,84,124,122, +85,122,164,122,209,122,144,62,138,170,116,204,94,224,61,240,236,238,202,224, +170,196,149,165,122,10,161,32,238,42,44,42,44,172,34,208,23,236,212,150, +212,80,88,80,88,150,213,150,136,54,123,80,152,80,146,130,134,156,95,182, +58,194,245,194,162,244,163,166,88,116,213,117,120,12,157,30,236,42,42,42, +42,170,34,204,21,240,52,96,243,96,66,70,200,70,200,124,67,124,136,54, +130,102,108,138,61,164,178,124,190,138,218,156,239,164,88,208,88,152,196,152, +197,206,142,168,130,204,98,228,61,242,154,202,223,241,128,16,161,38,238,48, +46,48,46,162,36,200,21,240,64,90,143,90,70,116,139,116,60,146,147,146, +106,146,107,62,92,146,92,162,88,194,74,222,61,240,92,176,132,176,128,224, +120,232,99,238,186,66,166,114,153,138,240,110,171,110,172,138,180,168,202,202, +237,236,212,110,210,142,206,168,186,206,151,237,130,12,159,34,238,46,46,46, +46,158,36,200,23,232,66,78,235,78,114,56,114,104,186,104,187,56,216,156, +216,126,86,126,86,156,217,156,74,180,229,180,80,204,221,204,60,230,245,230, +150,230,151,105,130,14,161,34,238,44,50,44,50,156,42,200,25,236,214,116, +214,68,90,68,90,116,213,116,80,140,223,140,68,164,237,164,152,164,153,68, +114,174,69,210,184,174,237,202,100,204,201,204,62,236,241,236,152,236,153,178, +90,92,215,93,128,12,157,34,240,44,46,44,46,168,34,208,21,234,98,56, +80,86,67,108,56,234,70,208,76,186,76,114,138,114,138,236,117,242,110,114, +126,84,83,84,76,152,139,152,76,186,139,186,108,218,109,114,154,76,226,76, +224,98,220,112,208,118,197,120,184,76,178,96,166,112,155,126,198,242,199,136, +172,136,155,180,236,160,163,160,152,196,245,197,126,14,157,30,238,38,46,38, +46,158,38,192,21,232,126,50,151,62,62,70,241,70,216,152,216,90,82,90, +82,152,217,152,180,132,180,110,118,110,118,132,181,132,80,174,219,174,58,196, +245,196,108,208,61,242,184,212,233,240,150,196,150,228,148,236,142,240,136,240, +121,241,122,10,155,28,236,40,40,40,40,170,32,202,19,230,90,50,72,80, +53,102,80,146,81,66,126,50,108,80,93,96,120,146,121,60,160,46,185,62, +128,70,229,70,128,92,219,92,128,112,219,112,128,134,235,134,170,134,171,70, +80,242,80,158,204,158,204,238,179,244,80,182,205,182,80,206,205,207,36,62, +17,120,82,60,103,96,64,240,65,13,62,242,63,12,36,66,21,126,76,64, +99,108,102,36,224,36,224,156,218,218,200,226,179,228,150,36,150,138,138,178, +122,206,97,231,62,240,63,14,36,68,25,128,76,70,99,112,108,80,243,80, +122,118,147,162,196,12,196,232,159,241,58,244,59,12,32,70,17,128,78,64, +101,96,222,20,164,30,101,34,94,120,245,120,166,244,167,31,54,242,55,16, +30,72,19,130,68,68,85,94,100,32,233,32,92,114,243,114,162,32,156,116, +140,174,114,210,85,236,176,128,176,210,178,224,190,232,220,232,234,216,239,197, +60,244,61,16,36,68,19,126,74,70,97,100,96,62,243,62,104,112,214,112, +198,150,172,190,136,218,95,234,168,112,169,12,238,234,184,204,152,170,132,132, +125,113,58,246,59,12,30,68,17,128,74,66,93,106,238,34,114,34,114,226, +245,226,142,64,182,126,221,202,210,54,180,140,137,207,60,242,61,12,36,66, +17,128,84,64,101,102,120,172,120,64,230,64,231,170,120,152,231,152,176,244, +177,9,60,244,61,10,28,64,19,118,82,60,95,96,148,10,132,64,113,104, +234,58,135,58,96,140,247,140,176,244,177,59,56,242,57,10,30,64,19,118, +76,56,91,80,88,104,118,62,139,14,236,44,127,44,122,84,219,84,100,124, +198,124,198,196,206,220,218,234,226,234,243,207,60,242,61,12,30,66,17,128, +82,62,99,94,90,120,239,120,134,12,134,230,175,204,216,28,165,94,168,120, +186,168,216,204,237,223,54,246,55,10,28,64,15,120,76,58,93,92,160,8, +132,64,93,116,234,112,184,70,157,20,156,176,176,174,190,166,194,146,196,112, +122,112,122,210,126,220,138,230,198,230,212,220,219,197,58,244,59,12,30,60, +15,126,72,60,93,90,92,122,116,92,132,60,147,20,178,16,184,48,200,84, +239,124,186,160,225,230,162,114,108,218,211,209,58,244,59,16,32,72,19,128, +78,72,95,108,146,14,175,50,96,66,243,66,160,240,161,66,228,168,161,125, +58,242,59,12,32,72,19,128,98,102,79,64,100,36,218,36,211,222,82,222, +245,222,102,124,215,124,132,222,149,37,58,248,59,14,32,62,19,126,78,58, +97,104,104,76,243,76,118,242,118,142,216,142,217,240,118,214,217,214,168,142, +169,13,56,244,57,14,32,62,17,124,70,60,91,96,96,76,235,76,184,26, +217,54,160,244,161,10,84,208,118,164,155,76,236,208,206,170,163,77,58,244, +59,10,28,64,19,122,80,64,97,104,102,30,235,30,88,144,247,144,170,244, +171,30,118,64,141,120,196,118,223,63,58,246,59,10,32,60,21,126,78,58, +95,98,212,176,212,34,120,34,120,176,213,176,120,104,213,104,88,226,245,227, +58,246,59,12,34,64,19,124,76,62,93,100,84,146,243,146,114,146,114,70, +216,70,217,146,164,12,164,82,158,152,138,188,112,218,89,236,234,234,206,216, +182,188,163,147,62,240,63,12,32,70,21,126,74,60,97,92,158,14,130,76, +101,118,244,64,137,64,160,240,161,64,160,120,233,120,160,174,239,175,54,246, +55,12,28,66,17,124,78,60,93,106,74,236,102,198,114,160,116,136,116,30, +212,30,212,92,117,92,154,116,154,216,158,230,174,236,214,236,230,224,237,206, +228,134,155,171,60,242,61,12,34,64,21,126,74,58,93,92,96,54,218,54, +218,100,110,100,106,148,230,148,228,188,224,194,210,204,203,204,144,12,144,114, +140,164,130,194,110,216,89,232,184,242,185,13,54,242,55,12,28,72,19,130, +68,64,91,98,102,28,222,28,218,92,214,106,198,112,181,112,94,122,116,108, +134,88,144,62,149,28,120,242,120,138,216,138,217,240,120,218,217,219,60,244, +61,10,34,66,19,128,72,62,95,94,100,30,210,30,198,62,178,84,146,106, +95,122,116,30,134,66,168,94,208,112,241,120,106,150,233,150,94,192,243,192, +168,120,169,245,60,244,61,14,32,68,19,130,76,58,97,92,188,54,239,112, +164,12,112,108,223,96,120,244,120,148,218,148,219,240,120,220,219,221,54,244, +55,12,32,68,19,126,72,62,87,92,92,50,157,50,80,110,161,110,132,146, +155,194,118,120,88,196,149,182,154,80,226,78,222,212,214,226,189,230,184,12, +184,130,176,178,143,239,30,68,19,126,70,68,87,102,56,244,57,14,236,34, +104,34,104,160,96,196,77,234,122,112,241,112,198,62,223,90,174,50,174,124, +166,168,154,198,136,220,117,236,236,236,214,216,196,190,175,135,58,242,59,12, +34,64,21,120,74,60,89,100,104,170,104,38,164,38,165,166,134,70,132,152, +120,196,98,222,83,234,142,174,173,214,196,184,197,48,226,12,226,236,191,243, +60,246,61,10,30,66,17,124,78,62,95,104,110,24,110,78,222,78,223,24, +164,8,165,78,108,112,214,112,214,156,116,156,116,206,118,220,134,232,210,232, +232,218,239,199,58,242,59,12,34,60,17,118,76,54,91,84,144,14,120,68, +93,108,182,194,182,100,118,100,118,194,183,194,118,146,183,146,180,234,200,232, +216,226,224,202,228,58,125,59,56,244,57,8,32,66,17,122,76,66,95,108, +142,10,105,78,90,142,140,118,186,76,208,44,125,44,134,62,164,102,204,130, +237,140,118,242,118,150,208,150,209,240,118,216,209,217,32,68,19,124,76,68, +95,108,58,246,59,10,108,68,108,32,226,32,227,68,104,90,233,90,164,50, +102,144,227,144,90,182,245,182,170,108,171,245,56,244,57,10,30,66,17,122, +74,62,89,100,98,48,239,48,108,124,108,88,226,88,227,124,166,88,167,10, +124,120,198,120,170,154,170,220,166,230,150,238,135,238,92,172,245,173,54,244, +55,12,28,70,19,126,76,66,93,104,96,54,243,54,220,140,220,92,110,92, +110,140,221,140,164,244,165,12,92,222,126,192,163,140,236,220,200,188,165,141, +56,244,57,8,32,68,19,128,72,68,89,102,106,126,107,30,138,138,139,14, +156,32,220,32,210,68,190,104,161,126,166,32,174,64,198,100,237,124,96,176, +223,176,82,228,239,228,158,228,159,141,56,246,57,10,30,70,17,126,74,64, +93,106,220,128,220,30,114,30,114,128,221,128,114,80,221,80,100,178,233,178, +84,228,243,228,166,228,167,31,58,242,59,12,30,64,21,124,72,58,91,94, +108,242,108,28,226,28,227,238,108,218,227,218,168,200,169,48,126,90,207,90, +128,168,169,100,206,164,169,109,60,242,61,10,36,62,17,126,76,60,95,94, +216,74,216,26,122,26,122,74,217,74,238,192,236,206,228,218,212,224,132,224, +114,222,112,202,112,102,224,102,224,156,113,156,168,156,169,103,56,244,57,6, +28,62,19,128,78,60,93,102,126,8,159,42,106,56,218,56,218,100,114,100, +114,144,232,144,228,186,222,198,210,204,199,204,168,244,169,56,210,8,183,56, +88,224,120,204,144,180,169,147,58,244,59,10,34,66,17,122,80,62,95,104, +192,34,237,80,166,12,118,74,223,68,152,90,103,130,190,92,235,124,164,120, +134,154,103,182,144,170,172,204,204,226,237,238,104,240,142,224,180,194,212,144, +143,145,58,244,59,12,34,72,19,132,76,68,91,104,248,228,112,228,112,32, +243,32,134,74,237,74,126,134,241,134,180,46,176,140,166,170,129,206,188,160, +231,204,138,92,155,118,220,88,207,119,60,244,61,12,32,72,17,132,80,68, +99,110,102,46,233,46,102,90,247,90,166,90,167,10,122,104,149,136,102,146, +235,146,204,102,177,146,92,186,245,186,166,244,167,147,56,244,57,14,32,68, +17,126,72,68,85,108,138,242,139,12,182,242,183,12,90,66,139,66,94,122, +139,122,84,182,139,182,240,62,183,62,236,120,183,120,240,182,183,183,58,242, +59,12,32,68,21,126,72,62,91,94,104,32,139,72,226,28,195,74,106,242, +106,92,228,92,228,214,226,226,210,234,197,236,166,12,167,92,194,194,194,130, +140,130,140,194,195,195,54,244,55,12,30,70,19,120,72,68,89,108,104,240, +104,32,220,32,220,232,191,238,132,56,153,84,104,100,221,100,194,50,169,100, +150,110,171,132,122,142,205,142,142,142,142,190,199,191,58,244,59,16,30,66, +19,130,78,64,93,108,86,236,108,202,116,154,116,30,228,30,228,234,193,242, +136,76,207,76,132,116,213,116,170,116,171,44,194,190,194,146,144,146,144,190, +195,191,56,242,57,14,32,64,21,120,72,66,87,98,142,12,118,52,97,76, +180,150,196,150,208,146,214,128,220,48,121,48,158,48,148,72,126,96,101,116, +192,48,178,84,150,124,111,152,102,172,83,222,152,152,173,186,212,170,235,214, +130,170,130,214,132,224,144,232,180,232,194,220,199,205,62,244,63,12,30,74, +19,130,82,70,97,110,150,12,183,40,100,50,241,50,140,64,128,104,109,138, +166,120,133,90,204,62,190,104,175,136,230,126,195,96,86,170,247,170,168,244, +169,147,58,242,59,12,34,68,19,124,76,66,95,104,208,108,208,28,114,28, +114,108,209,108,114,70,209,70,78,222,245,222,104,222,104,146,218,146,219,222, +140,222,141,146,180,222,181,147,36,68,21,126,74,70,91,96,60,244,61,14, +220,78,220,44,110,44,110,78,221,78,98,108,235,108,162,108,163,12,114,202, +114,136,214,136,215,200,166,154,160,186,148,210,122,226,99,236,176,204,231,237, +34,66,19,122,78,68,95,102,60,242,61,12,152,74,152,26,106,26,106,74, +153,74,222,72,222,26,178,26,178,72,223,72,108,108,225,108,90,140,245,140, +144,140,136,176,216,176,210,216,200,228,180,232,149,233,60,242,61,12,34,64, +19,118,74,56,91,88,226,80,226,28,108,28,108,80,227,80,148,80,149,28, +184,80,185,28,146,94,181,118,88,128,247,128,148,128,142,178,126,204,87,236, +174,234,192,234,204,228,210,216,216,164,145,165,58,244,59,16,32,66,19,132, +72,62,91,92,110,24,110,74,222,74,223,24,166,74,167,12,90,108,245,108, +106,242,106,148,222,148,222,238,201,244,150,148,163,108,144,230,145,148,182,226, +183,149,52,244,53,10,28,64,21,124,64,54,83,74,152,30,112,38,81,40, +80,92,151,92,118,242,119,38,74,184,119,102,154,158,119,114,168,72,161,126, +232,70,219,124,194,12,194,112,184,168,164,210,143,236,238,238,216,204,202,162, +193,127,16,128,33,78,76,70,93,112,58,248,59,12,96,68,114,50,133,10, +236,38,121,38,206,132,206,70,120,70,120,132,207,132,136,140,118,172,91,198, +92,242,130,230,166,212,188,190,206,160,125,160,130,178,156,208,182,224,237,242, +120,100,207,101,58,246,59,12,32,60,17,124,68,58,87,76,104,40,233,40, +112,66,227,66,92,92,245,92,166,92,167,8,198,146,237,186,206,114,98,178, +217,166,160,100,112,132,175,132,134,188,95,230,196,190,229,228,138,238,158,236, +166,234,168,224,169,173,56,246,57,16,30,68,17,134,68,66,91,98,128,14, +149,40,96,52,239,52,204,10,181,52,110,82,218,82,218,154,111,154,90,118, +245,118,148,246,149,52,180,246,181,52,92,222,114,202,149,160,236,222,204,190, +181,159,54,244,55,10,30,62,17,118,64,66,85,100,148,12,181,32,82,232, +94,206,104,156,104,40,237,40,110,98,247,98,124,124,222,124,222,72,123,72, +128,244,128,148,224,148,224,234,203,240,128,176,225,176,128,202,225,202,174,240, +175,55,56,242,57,12,34,66,17,122,74,56,91,92,218,78,218,22,112,22, +112,78,219,78,112,52,219,52,148,88,179,106,84,114,247,114,216,174,216,142, +116,142,116,174,217,174,168,174,168,240,145,242,132,194,87,232,200,196,243,231, +58,244,59,16,34,70,19,130,76,64,91,94,140,16,116,82,89,130,122,196, +123,66,170,18,195,48,234,60,133,60,224,100,131,100,224,140,133,140,240,180, +131,180,176,180,177,60,120,204,97,240,144,202,157,236,180,200,195,234,214,196, +239,237,54,246,55,12,32,76,21,126,70,66,85,100,142,12,171,34,94,42, +229,42,124,54,141,72,84,80,243,80,194,50,175,80,216,168,216,106,104,106, +104,168,217,168,104,138,217,138,92,198,229,198,80,228,245,228,158,228,159,107, +54,242,55,16,30,72,15,132,66,68,89,90,90,54,151,54,174,54,235,54, +126,118,127,14,90,114,110,88,127,60,154,90,127,66,196,118,197,16,158,112, +180,86,197,58,234,104,197,54,96,136,224,136,213,168,124,158,106,208,83,238, +238,234,178,232,148,222,115,186,162,136,163,226,220,182,163,183,56,248,57,10, +32,70,19,126,74,64,87,100,144,10,171,34,86,40,241,40,190,110,190,86, +134,86,134,110,191,110,222,132,222,64,106,64,106,132,223,132,100,156,223,156, +86,182,245,182,130,196,89,234,190,200,237,234,164,182,164,242,141,247,54,244, +55,10,32,62,17,120,70,56,85,88,84,34,245,34,136,52,137,8,188,52, +189,10,220,98,220,64,106,64,106,98,221,98,144,98,145,64,180,98,181,64, +90,154,90,122,232,122,233,152,114,242,114,146,208,146,209,242,114,174,209,174, +114,200,209,200,114,224,209,225,48,30,211,30,26,82,233,82,122,30,108,94, +88,116,56,136,23,154,240,144,206,134,168,110,143,82,88,152,41,210,146,152, +173,206,178,142,217,206,122,112,122,238,93,247,36,160,36,34,84,34,66,76, +80,88,86,104,88,124,80,136,68,136,59,134,100,36,229,36,162,16,136,50, +99,76,212,56,127,56,116,78,229,78,170,78,171,56,124,146,124,96,208,96, +208,158,187,162,124,118,209,118,124,136,209,136,122,148,78,172,23,188,234,184, +176,174,123,148,90,190,49,232,146,200,169,234,176,188,207,234,126,172,126,234, +99,241,54,18,81,56,44,240,45,64,72,132,185,132,104,38,212,38,212,232, +179,239,44,240,45,52,64,12,91,50,112,36,216,36,216,232,181,240,76,88, +183,88,86,132,173,132,72,180,191,181,42,20,73,54,42,240,43,64,98,30, +214,30,214,232,187,238,68,86,183,86,76,118,173,118,64,148,180,148,178,174, +174,186,164,192,149,194,122,222,123,59,40,238,41,64,46,20,77,52,96,30, +218,30,218,228,191,234,68,94,191,94,130,58,106,120,67,176,150,156,179,204, +142,118,96,200,167,187,50,20,83,58,42,242,43,60,104,38,216,38,216,230, +185,238,106,64,135,92,64,104,195,104,90,128,144,164,187,202,158,104,138,154, +110,186,69,209,38,240,39,46,52,14,91,54,108,34,218,34,218,234,179,238, +114,56,141,84,62,94,195,94,70,208,88,190,96,174,98,160,98,128,154,128, +154,190,158,202,168,204,184,204,190,196,197,175,46,20,75,52,40,240,41,62, +96,30,218,30,218,230,191,236,74,70,97,96,64,198,76,188,84,184,96,184, +106,192,124,200,191,200,62,124,88,124,89,184,110,100,189,100,144,60,142,112, +128,146,113,168,182,168,143,113,48,20,81,58,42,242,43,62,104,38,214,38, +214,234,183,240,164,122,164,82,90,82,90,122,165,122,176,198,176,152,80,152, +80,198,177,199,42,238,43,62,44,18,77,50,96,32,218,32,218,232,189,238, +176,196,176,72,80,72,80,196,177,196,94,114,163,114,126,178,127,88,96,164, +127,124,162,162,127,119,52,22,77,58,38,240,39,64,108,38,216,38,216,234, +187,240,106,56,82,84,57,108,172,172,172,110,78,110,78,172,173,172,124,110, +146,78,89,78,78,142,173,142,122,110,122,194,124,204,134,212,170,212,182,204, +191,187,48,18,77,54,40,242,41,66,100,34,216,34,216,230,187,238,110,54, +137,76,124,188,80,206,80,84,170,84,170,144,81,144,80,114,171,114,114,160, +183,208,180,152,147,183,38,238,39,64,52,14,79,52,100,34,220,34,220,238, +185,244,162,60,183,76,62,88,195,88,138,52,142,112,152,164,174,204,182,208, +188,206,199,176,180,116,154,182,123,220,118,158,118,118,72,118,72,158,119,158, +60,194,125,187,50,18,77,54,42,242,43,64,104,36,220,36,220,234,185,240, +168,120,168,70,88,70,88,120,169,120,168,96,89,96,180,204,180,146,82,146, +82,204,181,204,82,174,181,175,42,22,75,52,40,240,41,64,100,32,214,32, +214,232,189,240,112,68,82,82,82,142,170,142,170,80,141,80,112,112,83,112, +140,112,171,112,110,142,110,156,102,182,86,200,63,214,140,142,140,190,140,198, +146,202,178,202,190,192,193,179,52,16,77,52,40,244,41,68,102,34,220,34, +220,238,195,244,180,62,136,70,71,70,78,86,99,112,116,84,135,108,68,158, +68,124,190,124,191,156,174,84,147,124,88,152,164,152,128,200,102,214,73,228, +96,170,138,194,177,221,44,20,77,50,40,242,41,62,102,34,216,34,216,232, +193,238,172,68,122,74,82,78,82,142,123,128,82,108,187,108,132,74,140,114, +154,138,170,150,182,152,186,144,191,128,162,214,162,156,88,156,88,214,163,214, +88,184,163,185,52,16,79,50,38,242,39,66,108,34,220,34,220,234,191,242, +78,66,103,92,58,104,131,104,58,216,72,194,80,160,83,104,82,140,118,140, +114,188,106,208,98,212,89,212,162,60,150,96,125,128,206,132,182,110,164,84, +159,72,150,134,179,160,144,178,183,211,42,20,73,54,38,242,39,66,98,34, +214,34,214,232,195,238,148,148,171,158,170,136,170,68,84,68,84,136,171,136, +84,92,171,92,84,114,171,114,66,168,189,168,124,136,124,172,114,190,92,208, +71,220,178,222,144,194,121,179,40,22,71,54,40,240,41,66,96,34,216,34, +216,230,195,236,74,76,118,76,100,110,65,142,76,96,97,112,138,62,146,90, +166,120,195,138,172,68,147,92,192,84,163,114,160,132,95,132,72,166,185,166, +126,132,122,178,110,196,96,208,73,220,172,218,125,171,38,240,39,52,50,20, +81,48,102,36,218,36,218,230,189,238,76,76,179,76,64,100,191,100,124,100, +125,54,128,100,80,138,167,138,152,114,173,146,60,208,197,208,80,208,80,162, +174,162,175,208,110,208,111,162,142,208,143,163,52,16,79,48,40,246,41,64, +106,32,216,32,216,240,189,248,114,200,75,226,140,198,177,224,68,68,189,68, +60,182,197,182,88,182,88,92,168,92,169,182,88,114,169,114,88,136,169,136, +88,158,169,158,124,92,129,47,56,14,81,48,38,238,39,64,110,30,220,30, +220,230,189,238,68,64,87,86,54,98,133,98,124,58,105,98,68,122,68,164, +126,164,127,124,98,98,98,130,96,172,84,202,63,224,162,56,156,80,145,114, +188,124,196,94,153,94,166,118,160,168,150,190,132,210,113,224,198,204,180,178, +163,155,48,20,77,50,38,244,39,64,104,34,218,34,218,238,191,242,54,100, +133,100,56,194,129,194,114,232,115,100,74,194,75,100,64,70,108,70,109,100, +74,164,115,164,74,132,115,132,160,58,146,110,133,138,202,100,149,100,148,138, +197,200,178,100,176,138,166,176,148,200,135,219,148,236,149,14,78,56,117,102, +74,174,149,121,180,242,181,18,98,24,98,90,181,90,56,146,181,146,112,146, +112,162,110,182,94,206,74,222,51,235,94,246,95,14,44,28,44,98,95,98, +18,140,95,140,52,140,52,158,50,190,38,214,21,232,186,32,219,64,114,102, +239,84,210,114,186,162,156,200,123,228,150,10,150,72,158,126,168,166,188,200, +210,222,220,228,228,228,236,216,243,195,60,22,101,56,38,82,83,116,50,234, +95,147,36,22,75,50,24,86,57,112,32,228,77,146,140,12,114,64,85,104, +232,56,119,56,104,112,192,112,152,158,130,188,120,210,122,224,140,232,180,234, +210,230,224,218,231,199,36,24,77,52,24,90,65,116,24,232,75,146,236,192, +230,210,212,226,130,226,112,224,104,202,104,40,204,40,204,124,105,125,40,24, +77,52,22,86,59,114,32,230,69,144,144,64,163,108,90,40,210,40,202,88, +184,130,156,178,118,210,77,234,236,234,208,218,176,192,148,160,132,132,118,92, +107,41,44,28,77,60,26,82,59,114,28,220,65,144,154,240,155,12,94,66, +227,66,98,116,217,116,80,168,239,169,36,20,75,50,16,82,59,110,24,228, +69,142,102,32,223,32,84,104,239,104,136,104,136,128,132,164,122,190,106,208, +90,222,69,234,178,104,178,206,182,220,188,228,220,228,232,224,236,212,239,199, +44,26,79,56,14,88,53,114,22,230,71,144,82,78,231,78,154,244,155,12, +74,202,108,162,132,122,153,78,234,198,214,178,194,154,176,124,157,81,36,28, +75,56,24,88,59,114,32,226,79,148,88,32,239,32,110,74,110,154,219,154, +160,154,161,32,160,88,220,88,218,196,212,218,200,228,180,230,157,233,34,20, +69,54,16,86,53,112,30,224,69,150,84,54,229,54,100,88,100,152,208,152, +209,88,234,196,230,216,224,226,208,228,172,228,160,226,154,212,155,9,36,24, +77,50,18,82,67,110,24,228,71,146,108,234,108,36,216,36,217,234,108,114, +217,114,108,200,217,201,36,26,75,52,18,82,61,110,26,232,73,150,96,232, +96,46,224,46,225,230,96,208,225,208,204,124,97,125,38,28,79,58,24,88, +63,120,28,230,77,154,136,14,173,56,82,76,237,76,150,244,151,76,222,168, +151,129,30,28,71,58,14,90,57,118,24,230,65,154,126,12,163,50,84,68, +227,68,108,68,118,98,132,132,150,166,180,196,210,216,233,226,194,68,188,100, +180,136,164,164,142,192,120,210,92,226,73,237,28,30,65,58,14,90,55,114, +24,234,67,154,126,20,163,48,76,62,233,62,64,234,92,220,108,202,118,180, +120,164,120,104,186,104,186,226,190,232,200,236,218,236,228,230,234,218,237,203, +38,30,77,58,26,94,65,124,32,236,73,152,106,34,129,66,78,92,220,92, +216,204,210,220,200,228,175,230,164,16,150,108,140,152,120,190,98,214,73,236, +162,144,189,181,28,22,65,46,18,82,55,108,20,232,61,146,84,242,84,36, +138,36,110,104,122,122,134,140,136,162,132,178,120,186,109,188,144,78,226,76, +220,202,218,218,210,228,200,230,187,232,128,236,152,206,168,174,178,136,180,106, +181,15,34,30,73,56,16,90,53,116,28,228,71,148,78,78,243,78,118,240, +119,16,202,238,203,16,118,142,203,142,118,214,203,215,36,22,75,54,16,82, +55,112,24,230,69,150,184,22,213,52,78,80,237,80,152,242,153,12,78,194, +112,154,153,88,232,190,194,150,153,83,38,26,71,54,22,88,57,116,22,234, +59,146,170,28,205,58,68,76,231,76,130,14,126,88,112,160,90,206,59,238, +210,110,180,152,142,188,113,210,160,76,160,206,162,222,174,232,216,232,230,218, +235,203,46,24,85,56,28,80,67,114,26,222,69,146,64,242,90,216,114,172, +114,90,220,90,221,172,114,152,221,152,158,90,159,8,158,44,241,45,32,28, +73,58,14,86,55,114,26,232,61,158,72,140,241,140,100,140,100,70,208,70, +209,140,152,12,152,102,142,168,116,204,73,236,232,234,194,208,155,141,36,18, +73,56,18,84,55,112,30,232,61,138,94,240,94,36,222,36,223,236,94,210, +223,210,138,36,138,110,132,142,113,168,176,36,176,136,178,146,184,154,223,155, +36,26,77,56,18,82,61,110,28,228,69,146,140,16,112,70,87,100,238,60, +119,60,82,148,210,118,210,160,204,180,196,186,185,188,160,206,161,76,116,102, +116,208,120,224,140,232,208,232,228,220,237,201,36,26,73,52,14,90,53,114, +22,228,65,148,152,12,118,68,75,112,232,108,196,82,149,20,138,80,165,112, +88,134,208,134,151,208,114,182,185,235,38,20,79,50,24,80,63,110,28,224, +67,144,154,18,96,36,96,166,143,142,142,48,142,164,132,190,112,214,87,234, +180,240,180,34,224,34,224,186,203,193,42,16,77,50,20,74,57,104,24,234, +59,144,212,22,154,30,106,34,100,116,233,116,126,148,75,218,188,150,237,212, +162,60,162,236,137,243,38,32,75,60,24,96,61,124,34,238,77,152,140,16, +169,52,88,68,237,68,194,180,227,240,202,104,104,230,215,220,152,74,106,140, +175,141,38,26,75,62,16,86,57,120,30,230,73,144,100,40,131,80,222,34, +193,80,96,110,235,110,86,166,241,166,162,248,163,9,40,30,81,58,18,90, +63,118,32,238,81,154,142,16,173,44,100,98,100,58,226,58,227,98,132,94, +132,210,136,226,152,234,206,234,228,222,233,202,216,124,133,159,32,22,71,54, +20,80,61,110,24,228,65,144,82,30,140,30,140,82,92,82,92,140,136,140, +136,178,132,206,126,218,112,224,90,226,85,226,206,146,237,230,198,18,158,216, +225,199,34,26,75,56,18,88,59,112,26,222,71,152,150,192,104,224,104,24, +214,24,214,82,105,82,104,134,237,134,164,82,164,100,168,140,178,180,200,218, +212,228,224,230,230,222,237,203,34,28,75,54,18,92,55,118,24,232,63,152, +96,30,200,30,176,64,148,90,93,120,164,76,229,116,90,142,223,142,74,220, +243,220,156,220,157,143,38,26,77,56,20,84,57,112,30,226,71,150,92,32, +239,32,212,172,212,78,112,78,112,172,213,172,82,222,245,222,115,124,112,124, +213,125,36,32,69,56,20,94,55,120,34,230,69,156,82,58,237,58,150,12, +122,88,81,142,122,244,122,104,210,104,210,238,185,244,122,144,211,144,122,184, +211,185,28,28,69,54,16,88,57,116,20,230,59,154,70,32,165,32,114,32, +106,74,77,140,72,234,110,200,140,146,150,90,101,90,98,138,131,164,182,182, +183,50,220,12,220,234,185,241,30,22,69,54,14,84,49,112,18,226,67,150, +88,52,221,52,98,78,121,110,206,74,183,112,78,132,229,132,154,10,154,70, +148,140,132,184,110,210,73,240,230,236,194,204,174,176,149,137,42,26,77,60, +22,88,57,118,26,228,63,146,100,192,100,86,206,86,207,188,146,86,147,8, +146,42,235,42,152,112,148,164,138,196,112,220,75,236,168,186,235,235,38,22, +77,46,22,78,61,106,22,222,69,146,94,236,94,28,222,28,223,236,94,214, +223,214,112,90,207,90,160,48,158,110,144,150,117,184,204,178,157,119,38,20, +77,48,24,80,65,108,26,222,71,144,96,240,96,26,222,26,223,236,96,214, +223,214,184,156,184,76,132,76,132,156,185,157,34,26,71,56,12,88,51,116, +24,232,67,150,118,24,102,68,85,96,220,64,105,64,78,116,233,116,156,244, +157,8,72,214,106,190,132,158,157,118,238,210,208,190,182,160,157,119,44,30, +85,58,26,92,65,118,32,230,75,146,110,238,110,62,216,62,217,236,110,108, +217,108,110,158,217,158,110,210,217,210,158,16,141,63,42,32,77,62,24,92, +59,120,28,232,73,148,66,224,243,224,100,224,100,78,214,78,215,224,138,224, +139,78,174,224,175,78,150,18,119,79,34,26,75,60,14,90,53,118,20,236, +63,154,150,14,122,70,71,114,146,24,172,60,202,90,229,106,102,114,201,114, +84,158,221,158,174,188,219,240,142,166,90,232,201,221,36,20,71,48,20,84, +63,108,24,226,63,144,86,58,115,98,222,54,195,100,134,14,134,150,124,192, +104,218,79,236,80,170,135,130,174,12,174,210,182,230,196,236,214,236,228,224, +235,208,228,162,175,125,40,24,77,56,20,84,63,116,28,230,73,150,132,10, +108,66,85,98,182,236,202,232,220,228,224,218,224,204,224,52,115,52,174,184, +174,98,114,98,114,184,175,184,114,140,175,141,36,22,77,52,18,82,59,112, +26,226,69,144,140,10,116,46,95,72,80,114,126,104,170,82,204,40,121,40, +132,58,154,84,182,98,239,112,98,138,223,138,106,158,92,192,233,192,164,246, +165,113,32,26,67,52,20,88,55,112,26,236,55,150,102,22,125,54,68,70, +165,70,78,98,120,152,157,204,138,70,134,118,116,170,65,222,182,182,183,44, +222,10,222,240,195,247,32,20,67,48,22,88,55,112,24,224,61,154,88,24, +125,54,66,96,106,96,102,218,145,184,174,12,156,66,139,96,234,60,159,60, +188,244,189,60,132,140,245,141,38,22,81,52,18,86,61,112,24,226,65,148, +98,26,206,26,206,106,99,106,108,66,207,66,84,152,239,152,190,120,190,208, +186,224,166,232,147,234,114,170,145,201,32,28,69,54,20,86,59,114,26,230, +63,146,68,76,136,72,128,152,108,200,73,236,110,18,80,164,147,218,166,230, +166,56,220,56,221,230,166,200,221,201,34,24,73,54,18,88,53,116,22,226, +61,154,84,48,233,48,214,142,214,86,96,86,96,142,215,142,154,244,155,8, +66,224,112,190,153,142,236,212,196,186,157,143,34,20,73,50,16,84,59,108, +30,228,71,140,94,28,227,28,84,118,243,118,100,70,206,70,201,118,136,118, +147,28,112,242,112,158,210,158,211,242,112,222,211,223,34,30,69,56,16,88, +51,114,22,226,67,144,86,50,221,50,94,76,123,112,202,72,173,114,78,132, +233,132,148,244,149,16,66,216,100,190,126,158,149,132,232,210,202,190,170,154, +155,133,36,22,67,50,18,80,53,108,20,228,57,142,84,240,84,28,224,28, +225,236,84,216,225,216,106,72,199,72,110,102,189,102,102,136,196,136,194,160, +190,174,184,178,171,180,146,202,147,47,42,20,77,52,16,82,53,112,26,232, +63,140,212,96,212,28,112,28,112,96,213,96,112,132,102,184,71,232,236,230, +166,226,136,216,103,184,162,96,163,224,228,148,163,149,44,20,81,50,18,86, +59,116,34,228,71,142,210,74,210,28,120,28,120,74,211,74,110,244,110,108, +222,108,222,240,195,246,110,144,223,144,110,184,223,185,32,22,69,52,16,86, +55,112,22,236,49,150,94,24,94,72,216,72,217,20,152,72,153,6,148,84, +110,126,71,158,236,154,176,118,147,88,132,130,161,158,90,178,196,178,153,243, +30,18,75,46,20,82,61,112,26,228,65,146,78,148,243,148,114,148,114,36, +168,30,217,20,114,84,229,84,180,148,181,84,134,172,79,234,178,174,231,231, +38,24,79,56,18,84,61,118,22,236,63,150,104,20,160,46,209,74,200,12, +146,52,99,76,78,104,239,104,154,72,120,134,77,184,118,222,118,148,216,148, +216,218,193,222,164,246,165,121,34,26,73,50,16,84,55,110,20,234,61,146, +140,16,110,54,75,80,214,142,214,88,96,88,96,142,213,142,160,88,186,48, +115,48,66,236,106,212,132,182,146,152,155,88,166,156,166,216,170,230,186,236, +210,236,228,224,237,205,32,24,69,54,18,90,55,118,22,232,67,152,134,16, +165,42,94,96,94,52,216,52,217,94,114,94,197,94,88,138,229,138,132,138, +130,166,122,194,100,222,71,238,170,138,170,216,176,228,194,234,214,234,230,220, +235,205,36,32,75,60,16,92,57,122,20,238,63,148,96,46,193,46,76,98, +239,98,220,36,174,100,128,142,85,172,152,98,153,10,114,248,114,144,206,144, +207,246,114,182,207,182,114,224,207,225,32,24,67,54,18,84,59,110,22,234, +57,144,82,52,237,52,70,174,241,174,116,174,117,14,196,174,197,12,116,92, +197,92,116,132,197,132,134,194,81,238,176,192,231,235,34,20,73,50,18,80, +55,112,18,232,53,144,70,78,149,78,108,242,109,12,62,186,109,98,142,136, +109,100,230,24,164,42,164,140,156,182,131,226,244,104,165,104,204,242,205,105, +34,28,63,58,16,88,47,110,24,232,47,146,64,78,137,78,98,242,99,14, +58,174,99,98,128,152,99,112,168,26,154,84,133,130,194,18,204,78,235,130, +190,158,225,232,176,106,140,220,215,213,36,26,75,54,18,88,61,114,26,234, +61,152,90,42,229,42,86,82,224,82,203,116,156,82,157,10,108,100,141,120, +102,130,135,150,78,168,239,168,162,98,158,174,136,204,110,224,85,238,172,192, +225,237,28,22,63,50,16,86,53,114,24,228,63,148,78,28,231,28,78,104, +120,76,165,28,120,232,144,228,162,210,168,178,164,134,150,98,127,70,96,116, +123,152,84,150,120,120,149,96,76,200,124,172,163,134,222,74,163,124,232,198, +204,162,185,107,36,22,73,60,16,82,53,116,20,230,63,140,214,116,214,34, +100,34,100,116,215,116,154,116,155,34,100,72,215,72,76,154,241,154,70,238, +96,226,116,200,122,178,127,154,190,242,191,155,32,20,71,52,10,82,53,110, +18,234,51,146,194,70,194,32,96,32,96,70,195,70,206,180,206,106,80,106, +80,180,207,180,142,70,142,218,144,234,160,240,206,240,224,228,231,206,80,144, +207,145,36,34,73,64,14,96,49,120,24,236,67,150,146,18,120,66,75,116, +144,24,166,58,198,88,237,112,104,104,195,104,86,156,219,156,92,180,119,208, +210,176,183,214,70,228,233,228,148,228,149,105,32,26,63,54,16,86,51,114, +20,218,57,144,56,230,72,208,78,178,82,140,82,28,122,28,122,210,114,230, +99,232,82,92,123,92,82,146,123,146,234,194,228,216,212,224,166,226,156,220, +154,204,154,28,224,28,224,122,155,122,188,122,189,29,40,24,79,52,18,82, +59,112,30,222,73,134,146,12,175,42,102,84,102,54,228,54,229,84,116,100, +215,100,96,140,235,140,84,220,129,172,200,172,235,218,164,140,164,242,133,247, +32,30,65,54,18,92,53,118,28,232,61,148,132,10,165,40,84,88,84,52, +230,52,231,88,108,204,108,108,214,108,215,204,108,148,215,148,108,186,213,186, +160,250,161,65,36,28,73,54,20,92,59,114,30,236,71,146,142,14,173,36, +94,86,94,52,234,52,235,84,118,244,118,92,208,92,208,134,119,134,220,238, +220,172,119,172,118,218,221,219,34,26,69,58,10,92,49,120,24,230,63,150, +76,102,237,102,198,102,202,30,99,30,100,66,199,66,92,132,123,154,154,102, +154,238,127,244,70,212,155,162,232,218,200,196,178,172,155,138,218,128,175,165, +26,22,63,50,14,80,53,110,22,228,49,148,54,216,72,174,80,132,80,30, +156,30,156,74,81,74,96,206,96,120,158,120,158,202,147,208,124,242,125,88, +190,176,191,42,224,12,224,236,197,241,36,18,71,48,16,80,57,104,30,228, +65,146,80,52,239,52,148,10,148,88,194,88,195,10,106,14,106,120,225,120, +82,158,239,158,156,242,157,120,76,224,110,204,151,158,234,222,204,206,182,188, +157,159,40,24,75,58,18,84,57,114,26,224,71,146,88,32,231,32,212,132, +212,70,100,70,100,132,213,132,136,132,137,32,174,132,175,32,92,178,221,178, +72,224,243,224,152,224,153,147,28,28,71,56,16,90,55,114,22,232,67,146, +76,32,245,32,94,242,94,82,216,82,217,240,152,32,137,82,94,214,217,214, +134,212,135,82,178,214,179,82,134,124,179,124,134,166,179,167,30,34,63,54, +18,90,47,108,22,228,57,148,142,22,98,36,75,40,70,92,141,92,110,244, +111,32,64,186,88,152,111,106,140,146,111,108,160,74,153,120,226,70,209,120, +186,12,186,76,182,130,178,162,164,194,133,232,234,230,204,182,192,138,185,107, +36,28,73,56,18,84,59,116,24,232,67,152,134,26,98,38,98,116,220,116, +220,36,189,36,134,78,99,78,184,74,221,74,86,152,204,152,184,180,146,212, +114,226,79,236,114,152,134,178,164,210,208,228,237,236,156,152,157,11,32,28, +79,58,18,90,63,120,24,238,69,154,212,112,212,46,104,46,104,112,213,112, +105,78,104,80,213,80,88,150,229,150,98,190,219,190,78,234,241,234,160,234, +161,150,148,8,131,47,26,30,63,56,14,94,51,116,18,238,49,144,114,14, +86,58,57,90,144,62,105,28,76,94,147,94,66,140,155,140,90,164,55,212, +132,162,157,194,86,240,104,238,114,230,115,94,160,50,220,50,216,100,206,146, +186,192,160,220,137,238,238,232,208,200,184,154,172,102,167,51,34,26,71,56, +16,88,55,116,60,144,29,230,126,20,98,64,75,92,174,18,188,46,212,72, +233,88,106,70,194,70,190,106,188,118,176,126,159,130,136,70,134,94,122,114, +106,126,91,136,62,224,239,224,90,224,90,154,208,154,209,224,130,224,131,154, +168,224,169,155,28,26,63,56,18,92,51,120,22,232,63,156,100,20,133,52, +73,64,82,64,227,64,202,16,167,64,90,244,90,100,142,100,142,236,117,240, +90,178,143,178,90,138,143,138,178,200,179,108,216,90,216,234,181,243,36,30, +75,62,16,90,59,120,26,232,69,152,140,16,169,40,96,82,96,54,226,54, +227,80,108,92,213,92,208,196,208,126,110,126,110,196,209,196,110,160,209,160, +76,230,239,231,38,30,73,56,18,92,57,122,26,232,63,150,64,232,82,204, +90,174,94,144,94,32,218,32,218,68,95,68,112,100,231,100,190,116,225,154, +164,108,126,148,211,142,118,186,229,186,102,230,241,230,172,230,173,153,36,22, +73,52,18,84,55,112,30,228,67,144,70,228,88,198,100,154,100,28,226,28, +226,84,101,84,166,84,167,28,132,244,132,116,222,116,223,244,132,150,223,150, +132,184,223,184,132,222,223,223,26,24,59,54,20,82,51,110,22,226,53,144, +98,244,99,10,64,68,129,68,66,114,125,114,62,160,131,160,172,12,156,52, +131,96,232,196,230,216,224,224,214,230,164,230,154,224,150,202,150,90,218,90, +218,158,151,158,184,158,185,90,184,90,204,44,159,45,28,28,61,54,12,88, +47,112,16,232,43,146,80,44,217,44,82,76,211,76,68,106,229,106,148,14, +134,86,112,122,90,144,67,164,172,106,192,130,214,148,235,160,180,140,144,144, +109,144,78,176,217,176,144,246,145,144,70,228,102,210,139,176,210,226,167,193, +30,24,73,56,18,88,63,116,20,232,63,152,94,48,213,48,78,82,237,82, +154,82,155,8,149,90,178,108,227,144,150,90,94,140,215,134,66,230,243,230, +210,230,210,166,96,166,97,230,136,230,137,166,174,230,175,167,32,24,69,54, +12,78,51,108,24,224,61,138,80,30,223,30,76,120,229,120,190,140,191,30, +108,120,109,30,108,58,191,58,108,88,191,88,72,154,136,154,130,176,112,206, +84,226,69,236,84,168,137,214,128,238,162,222,194,192,208,168,214,154,156,154, +166,180,190,212,218,228,237,235,32,24,69,52,18,90,55,116,30,230,65,148, +82,42,227,42,122,70,123,12,182,62,183,10,74,98,237,98,184,74,207,86, +146,66,120,114,83,150,232,142,206,130,175,98,90,168,225,168,130,130,130,170, +122,200,110,218,85,238,184,240,185,133,26,26,67,52,20,84,57,108,26,232, +65,144,78,52,241,52,132,80,133,14,184,80,185,14,88,122,88,96,226,96, +227,122,90,136,225,136,100,176,213,176,182,194,217,210,74,228,241,228,156,228, +157,137,30,24,67,54,18,92,51,116,30,232,61,146,178,14,203,32,82,44, +229,44,96,158,96,72,206,72,207,158,96,104,207,104,96,134,207,134,150,164, +151,12,70,180,237,180,188,160,188,238,159,244,114,194,143,221,32,18,73,50, +18,78,57,108,62,142,27,224,82,28,231,28,216,114,216,68,90,68,90,114, +217,114,174,114,175,28,134,114,135,28,76,154,237,154,152,240,153,126,68,220, +114,194,153,158,232,218,186,190,153,155,38,22,77,58,24,88,55,114,26,222, +65,148,60,236,88,190,100,134,100,32,231,32,214,60,125,60,108,90,233,90, +134,90,134,144,167,130,162,90,176,110,206,134,233,144,216,104,191,120,108,170, +241,170,196,146,196,222,190,234,176,238,163,238,132,186,155,213,32,28,71,58, +20,92,55,120,30,232,59,154,210,98,210,24,102,24,102,98,211,98,102,62, +211,62,76,128,144,128,144,234,109,242,68,218,129,188,84,146,109,176,162,128, +230,128,230,236,199,242,172,146,195,174,164,212,215,185,34,20,71,50,18,78, +53,104,22,228,59,140,88,238,88,26,224,26,225,240,88,220,225,220,108,58, +207,58,164,58,142,80,109,104,140,82,152,100,162,122,166,160,160,190,146,198, +137,198,108,144,155,104,110,182,138,160,163,134,198,86,163,130,204,168,165,129, +34,28,71,62,18,84,51,116,18,232,61,146,116,18,98,54,77,90,154,48, +101,48,130,82,115,48,190,16,172,56,155,80,240,48,177,48,216,82,195,48, +200,88,148,104,79,114,82,150,209,138,68,194,225,178,234,208,230,224,218,236, +194,238,160,236,148,226,146,210,147,105,30,28,77,62,16,88,57,118,22,232, +67,146,202,132,202,44,106,44,106,132,203,132,152,10,141,44,106,72,203,72, +106,100,203,100,184,146,207,164,78,176,237,176,150,142,140,188,124,210,108,224, +71,238,228,238,200,228,180,212,164,196,155,177,34,28,67,56,16,90,53,118, +24,232,69,148,134,20,91,58,176,22,225,54,124,54,148,78,178,96,237,112, +186,52,160,74,132,92,75,112,94,124,215,124,92,166,221,166,104,184,131,210, +206,182,181,212,76,226,239,226,154,226,155,125,28,34,63,60,20,96,55,118, +28,230,59,150,142,18,175,36,232,50,92,50,92,168,67,236,116,86,214,86, +214,144,117,144,102,114,241,114,166,162,167,64,124,244,124,178,218,178,219,242, +124,222,219,223,38,24,79,56,20,86,59,116,28,228,69,152,144,10,175,32, +94,44,237,44,100,120,100,94,228,94,229,120,128,58,149,94,202,58,183,94, +150,104,173,130,84,140,245,140,142,140,138,180,128,202,106,224,81,238,172,236, +194,236,206,228,214,212,216,178,141,179,28,28,63,52,18,92,59,118,20,238, +67,150,84,62,84,30,226,30,227,64,204,134,204,68,106,68,106,134,205,134, +138,146,169,168,74,180,243,180,136,198,81,238,178,200,235,238,106,100,205,101, +40,24,75,52,20,84,55,112,24,224,71,146,90,46,231,46,72,88,243,88, +132,88,133,12,184,88,185,10,216,182,216,120,104,120,104,182,217,182,104,150, +217,150,158,182,159,88,136,198,85,240,180,200,233,239,36,24,73,54,20,92, +55,116,34,230,71,148,94,40,229,40,92,110,92,78,230,78,231,110,138,78, +139,12,186,78,187,10,198,136,229,174,159,88,216,162,120,162,203,110,158,88, +110,130,169,130,160,162,160,238,135,242,124,188,81,224,194,188,231,229,34,22, +67,50,18,84,53,114,20,236,59,142,80,40,235,40,122,66,123,10,186,64, +187,10,86,80,210,80,210,136,89,136,72,108,243,108,154,242,155,54,98,156, +94,190,84,218,65,244,132,166,109,220,170,168,195,210,212,154,213,245,30,22, +53,40,16,82,43,102,20,228,55,142,70,52,133,52,156,52,229,52,104,138, +105,12,64,116,105,66,132,92,105,66,184,138,185,12,140,112,185,58,234,110, +210,92,185,60,74,160,233,160,146,128,106,190,225,234,186,160,172,188,146,216, +112,228,79,239,32,22,63,46,20,84,55,110,30,232,69,150,82,42,239,42, +220,134,220,74,94,74,94,134,221,134,136,134,137,12,178,134,179,10,94,102, +221,102,108,244,108,162,210,162,211,242,108,194,211,194,108,226,211,227,36,24, +69,54,18,82,55,116,62,148,29,226,62,236,80,206,92,166,92,62,226,62, +217,84,152,62,153,8,152,34,221,34,110,100,201,88,152,72,152,106,156,114, +166,118,200,118,212,112,221,102,218,134,176,140,117,140,124,158,145,178,212,156, +193,178,102,188,241,188,140,238,158,238,168,232,170,222,171,141,40,24,77,50, +20,90,57,112,32,224,73,142,216,90,216,24,98,24,98,90,217,90,98,56, +217,56,158,90,159,24,198,136,229,182,201,108,216,164,94,164,201,110,150,98, +100,130,163,130,158,164,158,236,135,240,126,192,81,226,190,190,233,227,30,28, +71,54,16,84,57,108,20,232,59,140,210,78,210,46,96,46,96,78,211,78, +218,144,218,106,88,106,88,144,219,144,154,160,155,14,90,184,61,224,140,180, +167,198,202,176,235,214,120,176,120,214,122,230,134,238,166,238,186,228,197,213, +24,30,59,62,8,98,35,120,14,230,45,138,58,100,88,62,113,14,152,62, +107,28,82,92,129,92,68,132,89,182,96,116,113,158,54,218,153,202,142,128, +109,208,188,14,168,74,151,104,244,70,171,70,168,112,180,152,194,186,214,210, +239,236,134,238,160,222,192,194,206,154,218,96,221,71,28,34,53,60,18,92, +51,122,50,146,17,232,74,30,94,54,110,88,114,136,116,168,114,200,104,224, +77,232,74,168,113,118,130,32,77,94,138,156,168,130,192,102,225,46,154,244, +154,142,214,142,215,242,154,180,215,180,154,220,215,220,142,58,195,58,131,106, +136,106,237,106,174,14,175,107,30,32,65,54,14,88,39,110,46,130,17,224, +74,18,94,44,106,74,108,126,108,176,108,206,100,222,94,230,84,232,69,236, +130,24,96,68,67,94,66,178,109,128,136,50,233,50,182,10,176,54,166,72, +139,94,221,96,178,50,225,90,123,114,128,114,243,114,214,114,214,238,185,244, +178,188,178,142,142,142,142,188,179,189,36,26,69,52,20,86,53,110,56,140, +27,222,142,14,173,38,238,50,92,50,92,140,82,194,61,236,92,134,222,134, +222,92,93,92,136,134,137,62,180,134,181,62,120,150,120,234,161,212,162,180, +121,180,180,148,180,222,182,232,188,236,214,236,228,220,233,202,224,166,181,187, +32,24,59,48,18,82,51,112,18,232,53,142,84,16,111,48,60,72,129,72, +92,72,92,106,88,146,82,182,68,210,47,238,92,118,126,118,116,234,95,238, +178,14,162,54,143,90,238,60,159,60,154,104,222,104,213,136,156,146,148,200, +133,244,236,234,202,230,168,206,153,178,184,216,185,104,184,162,225,163,28,24, +61,48,16,86,53,116,24,234,53,148,58,76,151,76,78,32,128,32,113,76, +60,216,157,190,126,244,127,76,78,76,79,210,126,118,79,118,126,162,79,162, +150,116,172,64,185,12,242,76,167,76,168,112,176,152,194,186,214,214,241,232, +212,76,212,106,206,144,194,178,174,206,149,233,20,28,47,58,12,88,49,116, +20,228,51,144,70,50,163,50,74,88,155,88,172,82,243,82,114,88,115,14, +144,156,144,118,84,118,84,156,145,156,174,114,193,158,82,168,103,200,62,222, +161,214,142,170,119,216,214,12,214,238,181,243,26,26,57,48,22,90,57,112, +20,222,61,138,74,58,157,58,68,172,155,172,100,186,65,226,114,190,137,214, +94,172,95,18,138,172,139,16,94,96,139,96,94,134,139,134,150,236,168,206, +176,166,176,38,204,34,229,26,238,98,177,98,210,240,211,99,30,32,59,62, +12,94,47,122,26,234,61,148,80,48,139,48,114,118,115,12,72,112,94,88, +115,54,142,88,115,58,162,46,233,46,190,118,191,10,150,110,172,80,191,50, +238,110,216,92,191,48,100,246,100,136,202,136,202,242,177,246,100,166,203,166, +100,198,203,199,28,30,67,58,24,90,61,116,22,232,57,138,134,20,104,30, +79,34,72,88,141,88,110,242,111,28,72,174,96,134,111,102,140,146,111,112, +144,38,169,74,232,32,213,74,158,244,158,94,224,94,224,238,203,242,158,136, +225,136,158,178,225,178,191,94,190,94,191,13,32,28,67,54,16,96,55,122, +24,236,63,160,88,48,215,48,70,86,239,86,132,16,161,38,118,56,135,86, +184,58,163,84,206,172,206,112,96,112,96,172,207,172,96,142,207,142,78,200, +223,200,62,230,241,230,150,230,151,113,34,24,65,48,18,82,55,104,24,218, +57,138,54,226,76,192,82,160,88,114,88,24,216,24,216,50,89,50,124,74, +200,74,166,94,166,136,147,138,108,106,227,106,100,150,154,150,126,174,126,240, +109,244,94,208,145,190,174,150,220,150,196,174,196,236,177,240,164,188,241,189, +186,12,170,52,159,78,30,30,53,50,20,90,45,110,18,226,51,160,72,56, +149,56,140,140,140,94,82,94,82,140,141,140,110,246,111,12,62,210,88,180, +111,148,138,190,111,160,166,192,166,90,226,90,227,190,196,112,196,154,190,192, +168,220,143,238,204,204,235,238,196,90,214,42,175,43,24,24,59,48,16,86, +53,108,22,234,53,146,74,230,74,44,116,44,117,224,74,96,117,96,74,150, +117,150,74,206,117,206,170,14,154,56,131,98,186,26,209,54,150,242,151,62, +158,68,239,68,158,118,231,118,160,166,231,166,160,216,245,216,194,216,195,69, +32,28,67,56,14,90,53,116,24,234,59,144,216,106,216,46,92,46,92,106, +217,106,132,106,133,16,172,106,173,16,76,134,235,134,92,76,217,76,208,186, +208,158,104,158,104,186,209,186,68,230,239,230,110,200,139,222,194,196,169,231, +32,26,69,54,18,92,55,120,20,228,63,156,56,240,74,220,86,188,90,158, +90,62,233,62,138,12,120,32,95,50,170,62,186,32,121,32,148,76,121,100, +190,76,217,98,160,90,183,106,98,116,239,116,112,140,215,140,112,166,215,166, +118,242,118,192,208,192,209,242,118,226,209,227,30,28,67,50,16,94,55,116, +30,234,73,148,134,12,169,30,78,40,241,40,218,130,218,66,94,66,94,130, +219,130,184,110,184,88,128,88,128,110,185,110,208,208,208,156,106,156,106,208, +209,208,106,180,209,180,68,230,245,231,30,26,65,52,18,90,53,112,26,222, +63,138,142,14,173,34,236,44,90,44,90,160,78,200,61,234,124,54,145,76, +96,86,237,86,96,140,239,140,106,112,214,112,214,166,109,166,194,52,175,86, +142,244,143,86,174,242,175,86,94,230,116,206,143,166,230,226,204,204,175,167, +32,24,65,54,14,86,49,110,20,224,59,148,82,28,225,28,82,94,82,58, +222,58,223,94,152,120,153,28,102,84,131,84,102,110,131,110,172,84,203,84, +172,110,203,110,70,136,233,136,84,242,84,164,216,164,216,238,195,244,140,164, +151,136,128,230,129,164,170,226,171,165,26,30,67,60,14,90,51,116,20,230, +57,154,106,18,88,80,61,128,88,244,89,80,106,80,235,80,154,80,155,18, +184,80,185,18,120,36,141,66,224,34,199,62,110,120,227,120,136,92,159,120, +204,90,183,120,116,150,221,150,106,182,233,182,170,120,168,168,160,196,144,216, +124,232,113,240,232,238,210,228,190,210,173,183,30,26,69,54,14,88,55,116, +20,242,53,152,206,104,206,34,96,34,96,104,207,104,96,58,207,58,96,82, +207,82,142,8,131,34,218,174,218,128,84,128,84,174,219,174,150,174,151,128, +58,198,243,198,126,198,126,210,120,222,106,234,88,242,79,244,186,246,187,198, +84,150,219,151,34,28,67,58,20,92,55,122,24,240,57,156,136,12,161,32, +80,40,239,40,202,88,202,64,106,64,106,88,203,88,78,138,78,112,228,112, +229,138,96,138,207,138,80,176,114,164,153,138,134,150,146,164,158,180,164,196, +166,214,164,226,158,234,148,240,135,242,76,208,106,196,149,166,82,238,114,224, +138,206,161,184,214,156,161,182,230,236,210,220,198,206,190,190,183,173,34,24, +67,50,20,92,53,116,28,226,63,144,82,28,144,28,145,88,94,44,115,58, +82,90,145,66,162,26,220,26,221,102,172,42,187,56,164,80,221,66,124,98, +108,130,83,162,110,244,111,126,158,96,181,114,116,122,231,122,118,154,221,154, +118,186,219,186,118,218,239,218,168,218,169,123,30,20,53,36,20,86,47,106, +16,232,53,156,68,46,143,46,122,144,122,80,72,80,72,144,123,144,72,114, +123,114,98,80,99,10,56,184,135,184,94,246,95,144,188,14,172,50,143,86, +186,22,198,48,218,74,239,90,136,106,168,106,168,240,145,244,138,132,153,160, +124,214,169,174,186,106,218,106,218,240,193,242,186,136,201,162,184,200,219,171, +22,32,59,56,12,94,49,116,16,238,53,150,90,48,76,78,65,96,82,68, +146,68,124,102,100,122,71,136,90,88,115,110,114,68,115,14,138,38,115,38, +156,48,222,48,210,72,200,86,180,106,151,120,160,48,168,66,178,82,194,100, +237,124,60,232,241,232,128,232,129,128,168,232,169,130,72,154,129,154,74,180, +129,180,76,206,129,206,230,154,169,154,224,176,169,176,224,200,169,201,12,34, +47,60,8,90,41,116,14,224,45,142,58,42,233,42,80,42,80,68,219,68, +128,12,159,30,198,116,198,90,92,90,92,116,199,116,52,236,68,204,68,140, +102,140,102,236,83,238,68,194,103,194,68,166,103,166,116,156,156,156,152,182, +140,212,124,228,121,234,142,128,122,190,157,214,158,240,174,218,178,188,178,138, +208,138,208,228,214,234,222,236,232,230,241,206,186,170,203,205,30,26,63,52, +16,84,51,112,20,232,55,144,148,12,118,44,88,68,61,86,144,18,166,42, +194,62,237,82,106,74,191,74,110,138,110,102,82,102,82,138,111,138,160,136, +160,102,132,102,132,136,161,136,212,136,212,100,184,100,184,136,213,136,82,244, +82,160,214,160,214,238,193,242,82,194,213,194,126,230,127,160,168,230,169,161, +30,28,63,56,16,94,57,120,28,234,59,152,78,58,235,58,156,98,157,14, +100,24,133,44,206,22,181,48,74,108,104,94,136,74,157,58,240,104,210,96, +180,78,157,58,210,156,210,110,98,110,98,156,211,156,156,156,157,110,98,134, +211,134,88,178,233,178,70,202,243,202,128,202,129,156,184,202,185,156,136,208, +77,238,180,210,233,237,26,26,53,54,15,86,12,90,33,114,18,220,45,144, +132,80,132,28,76,28,76,80,133,80,76,54,133,54,94,90,113,104,58,114, +145,114,132,174,132,140,78,140,78,174,133,174,104,174,104,238,83,242,80,192, +57,224,124,190,141,212,152,30,233,30,160,184,160,76,220,76,221,184,186,76, +191,30,190,98,190,160,186,192,172,214,145,238,196,204,241,241,30,28,61,46, +18,90,47,110,20,228,55,160,84,30,223,30,84,90,84,54,222,54,223,90, +154,104,155,30,102,76,137,76,102,98,137,98,170,76,207,76,170,98,205,98, +66,128,157,128,90,112,90,148,136,148,137,110,144,188,144,166,80,166,80,188, +145,188,62,210,161,210,114,244,115,148,148,238,162,224,170,208,174,182,174,124, +220,124,220,238,199,242,174,188,221,188,174,158,221,159,102,78,143,110,32,164, +32,122,224,122,225,165,104,18,147,44,38,98,38,58,218,58,219,96,38,124, +176,124,168,210,170,222,174,228,180,234,210,234,226,228,230,220,237,200,110,80, +110,136,104,166,94,190,80,208,64,222,23,241,112,10,147,36,44,84,44,50, +222,50,223,84,28,104,243,104,116,104,102,132,78,160,46,186,25,200,84,244, +84,160,206,160,207,244,84,222,207,223,110,14,143,40,36,94,36,50,222,50, +223,92,56,122,31,182,110,76,141,114,198,138,233,186,90,114,90,214,92,226, +106,234,164,234,184,222,193,200,196,90,156,144,118,178,72,206,23,227,112,12, +149,32,42,74,42,44,226,44,227,74,28,92,241,92,118,58,96,102,72,132, +48,154,27,166,84,244,84,122,202,122,202,238,175,244,84,158,203,158,84,194, +203,195,108,14,145,34,36,82,36,44,218,44,219,82,200,82,60,82,60,134, +54,174,42,208,21,234,84,116,193,116,218,146,69,146,96,146,96,234,147,210, +138,146,144,164,156,186,178,206,198,220,231,230,196,168,167,197,116,16,143,36, +36,78,36,48,220,48,221,80,70,74,39,116,122,60,147,82,194,78,223,112, +94,64,94,94,96,106,110,114,150,114,168,106,175,94,58,244,58,138,198,138, +198,238,173,244,130,244,131,138,58,168,199,168,58,200,199,201,106,12,141,30, +36,74,36,40,218,40,219,72,54,70,201,70,58,92,199,92,26,116,227,116, +98,116,99,50,160,116,161,50,18,170,54,156,84,136,107,116,238,164,204,152, +180,138,155,116,82,162,78,188,204,188,204,204,200,222,188,234,176,238,161,240, +168,188,172,146,77,146,40,216,175,217,114,14,147,32,34,72,34,44,226,44, +227,70,52,76,207,76,58,100,201,100,22,124,239,124,98,124,99,58,162,124, +163,54,18,174,50,162,78,142,93,124,240,170,214,160,194,150,180,138,167,124, +168,146,134,154,79,156,60,180,199,180,30,204,233,204,130,154,130,242,107,247, +118,14,151,32,36,68,36,44,228,44,229,64,94,246,95,70,50,84,50,126, +95,126,24,160,95,160,56,160,56,178,54,198,46,216,29,236,120,78,217,78, +112,150,239,150,152,150,163,78,126,112,202,112,203,150,136,246,136,178,210,178, +211,246,136,226,211,227,104,10,137,28,30,76,30,40,220,40,221,76,52,76, +205,76,122,54,108,86,86,110,56,128,25,140,52,94,81,112,136,76,152,92, +172,112,198,124,233,136,206,94,183,116,72,180,72,126,178,126,178,180,73,180, +72,154,179,154,130,180,130,240,105,248,84,200,39,236,172,202,219,235,110,14, +145,32,34,70,34,40,222,40,223,68,54,76,201,76,58,100,199,100,22,124, +235,124,98,124,99,54,158,124,159,54,18,176,50,162,74,144,93,124,238,174, +210,166,182,148,159,124,116,136,141,154,60,164,193,164,32,216,58,208,82,194, +100,182,119,164,140,210,96,234,97,186,142,176,160,204,180,220,223,236,192,180, +165,207,110,14,145,30,32,74,32,42,222,42,223,74,194,96,194,66,60,66, +60,96,195,96,104,96,105,66,148,96,149,66,16,122,239,122,188,174,188,146, +66,146,66,174,189,174,22,222,58,212,92,198,119,174,140,212,86,238,87,202, +146,188,168,212,198,228,237,238,206,184,171,213,110,10,139,30,36,72,36,38, +222,38,223,72,56,66,203,66,60,90,195,90,18,114,239,114,98,114,99,50, +158,114,159,50,18,164,50,154,74,138,101,114,236,164,206,154,184,144,153,114, +182,174,182,142,74,142,74,174,183,174,80,188,58,216,21,244,236,230,124,232, +90,224,67,206,126,232,127,174,126,202,203,203,106,12,141,30,36,70,36,40, +220,40,221,68,58,66,199,66,62,88,195,88,22,112,235,112,102,112,103,40, +160,112,161,40,114,120,139,130,16,162,48,150,72,134,95,112,238,160,210,146, +190,132,169,112,72,138,189,138,66,160,191,160,66,180,191,180,68,240,68,200, +188,200,189,238,68,226,189,227,26,20,73,60,240,230,88,230,68,206,56,206, +21,234,14,108,62,108,63,207,87,228,20,226,50,202,62,202,88,228,239,228, +28,26,67,64,12,108,56,108,57,202,84,32,223,32,116,54,98,106,229,106, +186,32,186,198,157,206,88,182,124,160,150,136,175,107,24,226,50,204,64,204, +90,232,237,232,46,20,77,58,12,104,58,104,59,204,132,12,108,64,89,90, +224,52,115,52,82,122,239,122,158,212,159,53,20,226,46,206,60,206,84,232, +239,232,32,22,67,66,12,106,54,106,55,206,96,202,96,30,216,30,216,198, +187,202,178,152,178,76,130,76,130,152,179,153,22,232,48,210,62,210,90,232, +239,232,14,106,54,106,55,210,40,26,75,66,138,14,112,72,81,116,236,62, +119,62,144,212,145,62,222,110,145,110,224,154,145,155,22,240,52,212,64,212, +90,238,239,238,12,114,58,114,59,212,36,28,71,68,130,16,100,70,81,94, +232,54,111,54,80,142,210,100,206,144,200,158,192,162,183,162,158,178,159,68, +112,88,112,172,112,186,118,196,134,204,200,204,218,196,226,182,231,171,24,236, +52,210,62,210,90,236,237,236,14,114,58,114,59,210,32,30,71,68,142,14, +110,70,89,100,204,94,222,58,117,58,158,84,158,200,131,206,122,114,87,180, +188,116,229,179,22,226,48,206,62,206,94,236,241,236,12,110,54,110,55,206, +32,34,63,72,84,64,146,64,144,176,140,188,132,194,119,196,110,12,110,110, +102,150,94,176,81,196,218,184,218,50,178,50,178,184,219,185,26,232,48,208, +60,208,88,230,241,230,16,108,54,108,55,208,30,28,69,64,92,26,196,26, +168,60,138,84,83,112,238,116,161,68,98,130,219,130,82,194,235,194,160,194, +161,131,16,224,48,204,60,204,84,230,239,230,14,106,54,106,55,204,40,20, +71,60,182,50,229,100,156,14,90,92,213,84,204,190,204,124,104,124,104,190, +205,191,20,232,48,212,58,212,78,234,241,234,12,108,52,108,53,212,32,26, +69,66,216,24,162,34,106,38,106,118,98,158,79,190,106,84,239,84,212,192, +212,124,132,124,132,192,213,193,18,236,48,210,62,210,90,238,237,238,12,112, +54,112,55,210,24,32,67,68,130,12,112,46,93,72,78,108,126,96,166,76, +200,40,117,40,122,56,164,86,196,98,235,108,100,132,219,132,112,148,104,178, +227,178,162,218,163,101,28,240,50,214,60,214,82,236,239,236,12,112,56,112, +57,214,36,30,73,70,182,14,213,40,84,52,237,52,100,210,100,84,212,84, +212,204,187,210,154,202,155,10,100,118,213,118,100,156,213,157,18,232,48,208, +58,208,72,232,239,232,10,106,52,106,53,208,24,26,63,62,72,32,235,32, +88,200,88,74,136,74,136,196,115,200,100,104,121,146,164,202,164,74,216,74, +216,200,195,206,178,104,203,149,18,230,46,208,56,208,78,236,237,236,10,112, +54,112,55,208,38,28,65,68,80,62,227,62,176,26,207,44,152,14,152,206, +127,210,94,88,121,118,210,84,185,120,76,176,153,128,224,182,153,119,18,232, +48,208,60,208,78,234,241,234,12,106,54,106,55,208,26,30,69,68,84,20, +123,62,220,16,181,54,102,206,102,80,208,80,208,200,181,206,102,118,209,118, +154,80,155,8,102,158,209,159,28,28,65,64,18,234,46,212,60,212,80,236, +241,236,14,112,52,112,53,212,144,28,118,56,100,70,77,86,82,20,106,38, +120,68,124,112,124,154,120,182,108,196,85,198,68,152,123,98,160,56,153,112, +230,60,209,110,188,14,188,92,182,136,172,166,137,208,234,204,185,127,18,238, +48,216,60,216,88,238,245,238,10,114,54,114,55,216,22,28,65,62,180,32, +225,76,150,10,94,70,209,60,132,80,79,122,176,80,227,118,148,102,112,142, +87,166,100,208,150,188,184,156,198,128,127,128,132,154,178,176,225,209,16,238, +48,212,62,212,92,238,241,238,14,116,54,116,55,212,30,28,69,68,102,44, +207,44,86,88,227,88,156,88,157,10,132,98,87,140,180,102,225,132,106,148, +207,148,86,196,233,196,158,196,159,117,18,226,46,208,56,208,80,232,241,232, +36,22,71,58,12,108,52,108,53,208,206,18,146,30,101,32,90,62,223,62, +156,106,157,28,88,114,126,88,157,62,230,112,192,88,157,66,80,142,237,142, +148,126,116,170,217,206,190,142,182,162,154,190,122,204,91,209,18,230,50,206, +64,206,82,234,239,234,14,112,56,112,57,206,32,30,69,68,140,14,167,36, +86,80,86,50,222,50,223,78,110,156,206,156,206,198,110,198,110,84,196,84, +196,124,111,125,22,230,50,206,60,206,76,228,90,232,237,232,28,22,67,62, +12,112,56,112,57,206,74,92,237,92,88,24,202,24,199,92,96,56,199,56, +152,92,152,202,125,210,92,112,123,140,80,182,153,146,215,110,222,188,190,162, +153,136,212,110,179,155,18,230,48,210,58,210,78,234,239,234,14,114,54,114, +55,210,36,26,69,68,98,26,98,70,204,70,205,26,152,70,153,16,72,100, +237,100,94,212,94,134,210,134,210,204,195,210,136,208,137,134,172,208,173,134, +142,134,149,101,22,228,48,208,62,208,80,234,239,234,12,112,56,112,57,208, +38,28,75,66,210,104,210,42,104,42,104,104,211,104,104,74,211,74,150,14, +141,42,88,132,227,132,98,164,217,164,82,198,235,198,156,198,157,133,22,238, +50,214,62,214,80,236,241,236,14,118,56,118,57,212,28,30,63,68,112,16, +139,44,76,56,235,56,200,12,169,56,214,202,214,90,100,90,100,202,213,202, +100,166,215,166,138,56,138,100,136,118,128,138,123,146,168,56,168,112,170,124, +176,130,194,132,215,127,26,236,50,214,66,214,88,236,237,236,30,32,69,66, +14,116,58,116,59,212,98,208,98,32,146,32,146,80,99,80,98,122,147,122, +98,164,149,164,166,30,212,30,212,80,169,80,164,114,214,114,206,144,190,170, +174,188,143,208,164,142,198,176,225,207,16,232,48,210,60,210,78,234,241,234, +14,110,54,110,55,210,28,26,67,68,82,46,155,46,88,76,151,76,76,110, +159,110,120,110,121,12,74,198,92,182,102,154,109,110,104,138,146,138,144,166, +140,182,134,188,126,190,115,190,190,14,176,64,165,88,242,66,177,66,212,66, +208,96,204,128,194,158,176,182,153,210,174,110,229,203,18,226,46,208,56,208, +78,232,239,232,10,108,52,108,53,208,38,28,71,68,82,44,223,44,92,68, +213,68,74,96,233,96,130,96,131,14,178,96,179,12,104,216,104,120,206,120, +206,208,183,212,74,180,237,180,154,180,155,96,104,148,207,149,206,88,206,32, +106,32,106,88,207,88,106,60,207,60,78,114,140,114,140,204,117,210,88,132, +113,154,78,186,141,160,158,114,220,114,220,204,193,212,168,132,191,152,156,182, +221,158,30,34,71,76,16,116,54,116,55,208,24,234,48,208,60,208,74,234, +241,235,138,16,90,34,90,98,135,68,122,48,145,82,158,32,214,32,214,82, +208,94,200,98,187,100,174,32,174,52,168,78,143,108,206,198,206,126,96,126, +96,198,207,198,96,162,207,162,148,198,149,126,30,26,67,62,12,224,38,202, +52,202,68,228,233,228,8,106,44,106,45,203,208,76,208,26,106,26,106,76, +209,76,106,50,209,50,126,90,104,120,77,146,156,90,181,108,104,210,105,120, +228,114,115,114,112,142,219,142,112,168,219,168,112,194,231,194,164,194,165,114, +32,26,75,62,14,112,56,112,57,208,24,230,50,208,62,208,82,230,239,231, +98,28,131,52,208,24,177,54,82,70,229,70,152,114,153,16,78,112,116,94, +153,70,226,110,153,70,116,116,96,146,81,164,102,138,138,138,126,174,93,210, +102,166,119,182,156,140,225,140,162,154,158,182,231,182,194,114,195,212,26,32, +65,70,24,230,48,210,60,210,74,234,235,234,18,114,54,114,55,211,220,68, +226,56,88,56,88,152,75,196,102,84,199,78,144,56,145,10,144,34,225,34, +144,62,144,90,146,100,160,102,200,102,221,94,102,124,233,124,106,156,132,144, +163,124,146,134,162,148,174,164,180,180,178,202,166,212,149,214,104,182,136,166, +163,150,104,210,142,192,175,168,208,140,177,164,228,198,206,178,181,162,26,28, +61,68,18,232,42,210,56,210,80,234,241,234,14,108,48,108,49,211,30,22, +59,46,110,14,90,52,67,76,76,200,86,162,86,78,146,78,146,206,123,212, +116,78,136,42,97,42,114,190,115,78,86,116,147,116,86,154,147,154,162,30, +226,30,226,54,222,70,218,78,206,82,201,82,188,30,186,50,182,66,176,74, +169,82,176,104,165,146,232,128,171,128,160,162,241,162,200,214,201,98,18,228, +46,208,56,208,72,234,237,234,14,106,52,106,53,209,18,52,47,78,11,112, +18,236,42,212,54,212,76,238,237,238,10,112,48,112,49,212,130,20,98,36, +67,52,136,62,106,84,69,106,98,54,117,76,74,70,91,90,100,88,112,102, +122,120,124,142,124,168,120,184,110,194,94,198,87,200,70,138,96,124,117,112, +70,166,98,152,123,134,212,122,212,46,154,46,154,122,213,122,154,82,213,82, +178,12,165,46,168,122,168,134,164,160,156,182,146,198,135,208,194,122,194,188, +196,198,204,202,220,200,230,190,233,175,15,114,20,232,48,212,60,212,94,236, +239,236,26,34,59,64,14,114,54,114,55,212,88,58,88,38,224,38,225,56, +128,12,165,32,136,54,91,78,174,54,215,78,84,98,223,98,124,76,141,98, +182,74,167,98,84,138,112,124,147,98,132,110,146,120,158,132,164,146,166,158, +168,178,166,192,158,200,144,206,129,208,84,172,118,152,153,126,86,200,128,180, +165,148,220,114,175,146,162,140,182,152,198,164,229,191,32,30,67,66,16,232, +40,216,54,216,70,240,235,240,8,114,48,114,49,216,106,14,90,38,109,52, +152,14,138,34,157,50,200,14,186,34,205,50,204,122,204,74,90,74,90,122, +205,122,110,84,185,112,176,82,109,112,84,138,84,214,119,200,98,144,111,154, +96,170,111,180,138,138,138,216,177,200,154,146,169,156,150,170,167,180,196,138, +196,166,200,188,206,202,212,210,218,210,222,208,231,191,34,42,210,42,211,238, +50,132,211,132,34,220,211,221,22,42,117,42,30,74,115,74,16,108,115,108, +79,132,78,124,79,12,138,42,231,42,140,74,227,74,136,108,241,108,176,122, +177,12,42,144,198,144,199,242,52,182,199,182,42,220,199,221,18,104,237,104, +100,12,64,72,171,72,84,40,182,40,161,104,34,152,72,138,114,118,133,104, +102,124,120,142,136,162,144,186,144,210,138,228,124,238,105,240,40,190,84,172, +121,144,28,230,82,208,139,168,188,130,137,164,228,224,198,206,174,176,159,151, +14,94,239,94,96,12,74,50,60,66,175,66,166,94,184,36,83,36,34,116, +34,232,69,204,34,156,57,156,106,108,89,146,78,174,161,174,152,130,97,130, +74,238,100,222,114,202,124,174,125,130,156,232,121,186,182,110,182,212,184,226, +194,232,216,232,230,224,239,200,226,126,183,163,16,238,34,204,44,164,48,126, +48,32,210,32,210,78,49,78,72,144,190,138,188,210,192,224,200,228,222,228, +232,224,238,214,243,202,130,96,130,160,118,194,98,218,65,241,24,234,40,194, +44,154,44,30,116,30,116,104,45,104,242,228,196,226,154,220,122,200,100,168, +86,132,81,104,218,106,218,28,152,28,152,106,219,106,166,126,137,186,198,126, +237,185,26,228,42,196,50,156,52,120,52,32,216,32,216,70,53,70,108,92, +84,114,69,128,106,134,86,158,61,180,90,244,91,154,116,116,237,116,122,154, +210,154,202,176,188,194,164,216,140,228,115,236,234,236,204,224,182,210,162,194, +146,172,135,154,174,154,175,85,20,230,34,202,44,162,46,134,46,24,218,24, +218,62,47,62,76,246,76,96,122,96,100,140,112,154,120,164,122,182,114,198, +106,202,95,204,138,96,247,96,218,96,218,236,189,242,182,182,182,134,146,134, +146,182,183,183,20,232,38,200,48,156,50,130,50,24,216,24,216,56,51,56, +66,110,233,110,90,78,180,78,148,96,148,122,146,128,138,132,123,130,68,156, +124,156,104,176,104,238,85,242,62,204,121,190,152,154,208,154,184,174,184,240, +163,244,146,190,243,191,24,222,40,184,46,152,50,114,50,22,214,22,214,62, +51,62,104,76,67,120,110,116,86,150,61,176,90,240,91,144,112,142,235,142, +142,142,143,88,178,142,179,74,178,104,225,104,142,164,128,204,113,232,134,186, +146,200,158,212,178,222,202,226,241,228,178,162,179,222,178,186,223,187,46,58, +214,58,214,22,46,22,46,136,38,186,23,230,102,76,80,102,63,120,108,118, +82,154,57,180,90,242,91,144,122,114,235,114,172,152,173,74,130,78,149,102, +214,80,191,114,120,154,173,118,232,154,206,140,175,114,114,180,239,180,116,238, +148,232,174,220,194,202,209,180,170,158,142,204,231,235,46,56,216,56,216,26, +46,26,46,156,36,198,21,230,70,88,227,88,110,68,131,88,188,66,171,88, +82,112,211,112,58,130,239,130,150,152,151,88,60,164,143,164,68,186,137,186, +58,208,145,208,80,144,93,164,128,142,111,164,76,240,94,228,102,212,107,164, +156,164,239,164,162,186,231,186,156,208,243,208,174,144,187,164,220,142,203,164, +198,242,199,165,14,30,78,30,78,92,32,92,30,146,80,146,76,214,74,226, +64,232,56,234,35,234,102,30,204,30,186,62,168,86,136,110,110,120,91,128, +234,134,165,88,106,154,221,154,96,228,243,228,168,228,169,155,16,48,112,48, +100,66,82,90,58,106,34,114,17,118,80,16,46,72,119,104,130,38,216,38, +204,60,188,78,162,96,135,110,236,110,208,100,188,90,170,76,156,60,143,38, +46,128,192,128,192,160,54,160,50,188,200,188,196,216,186,234,172,240,147,243, +14,30,80,30,80,88,30,88,28,140,82,140,72,222,64,232,52,236,35,236, +100,30,239,30,94,190,243,180,204,246,205,30,130,186,131,30,130,84,205,84, +130,136,205,137,16,56,118,56,118,98,30,98,26,142,122,142,120,200,107,206, +58,14,58,156,50,190,36,216,21,236,90,240,91,16,180,14,154,58,135,82, +150,154,226,154,226,94,150,94,150,214,152,224,164,232,216,232,230,224,236,214, +239,200,188,154,188,94,214,50,161,51,20,32,72,32,72,96,32,96,32,148, +74,148,70,212,68,224,60,228,48,230,37,230,94,36,167,36,108,230,108,88, +154,88,155,226,108,144,155,144,108,202,155,202,124,88,137,36,176,32,226,32, +226,94,184,94,184,148,228,148,228,210,222,222,208,228,193,231,26,34,74,34, +74,60,36,60,36,82,74,82,74,94,68,104,58,108,48,108,37,108,90,64, +163,64,128,110,129,22,90,102,127,64,160,98,129,70,158,34,143,52,94,30, +111,50,172,34,218,34,218,56,180,56,180,80,220,80,220,92,216,102,206,106, +193,106,20,126,239,126,188,168,188,146,66,146,66,168,189,168,46,242,46,190, +212,190,212,238,191,242,72,216,187,216,104,200,113,216,156,200,145,216,130,240, +131,217,124,244,125,14,42,34,42,138,211,138,210,164,211,45,14,78,102,78, +94,140,84,172,66,202,27,240,66,12,40,154,123,216,148,120,189,172,158,10, +142,74,121,120,176,238,204,236,218,228,224,216,228,66,145,67,14,86,104,84, +96,134,86,170,66,196,44,218,21,234,68,18,38,156,115,210,120,38,216,38, +216,116,138,116,138,200,140,216,150,226,164,230,204,230,222,226,232,212,235,197, +12,74,94,72,86,130,64,182,46,206,27,228,62,12,30,150,103,200,110,34, +235,34,104,124,241,124,146,34,146,138,138,182,124,212,103,240,200,244,201,35, +16,76,94,72,90,116,82,148,64,186,46,208,25,226,64,16,28,152,97,198, +114,36,225,36,106,112,237,112,160,36,160,56,156,92,152,132,144,168,122,204, +104,222,89,238,180,112,180,210,182,222,190,226,202,230,220,230,232,224,236,212, +237,197,14,84,90,82,86,126,78,160,62,196,40,222,21,238,62,14,30,154, +103,210,244,224,124,224,124,34,239,34,140,78,192,136,227,186,214,68,184,140, +143,193,12,82,90,80,82,134,74,170,58,198,40,214,21,232,64,16,30,154, +99,206,126,16,126,226,161,200,126,94,163,94,180,14,180,208,182,218,194,226, +208,226,226,224,232,210,233,192,232,70,181,109,12,78,94,76,86,128,74,162, +54,198,36,216,21,232,104,210,32,154,67,14,168,12,148,66,128,96,103,124, +236,122,202,92,180,56,165,24,160,92,187,130,114,150,216,150,159,245,18,76, +96,74,88,124,72,166,54,196,23,226,102,194,36,148,69,16,176,244,177,12, +228,46,166,60,130,60,126,126,230,126,226,194,216,200,199,198,98,226,138,184, +177,127,18,80,96,80,86,142,64,192,27,230,98,200,38,154,75,18,122,26, +141,62,112,88,222,86,216,208,210,226,190,234,175,220,174,140,195,176,176,16, +166,108,146,174,93,237,12,78,90,76,84,132,60,196,23,238,100,202,28,152, +67,18,92,228,245,228,112,40,212,40,209,228,142,228,155,40,106,124,211,125, +14,78,94,74,84,138,54,202,25,234,96,208,32,154,71,16,115,34,136,62, +183,98,114,34,212,34,169,88,104,104,234,104,225,142,174,104,174,236,145,243, +12,82,92,80,84,138,58,196,21,232,98,208,28,154,67,14,150,18,181,74, +132,48,132,198,175,142,212,34,212,120,206,162,182,208,139,238,238,232,201,177, +16,78,96,78,88,136,60,198,23,236,100,202,34,150,71,16,220,166,220,36, +130,36,130,166,221,166,130,100,221,100,100,228,245,229,14,76,96,74,90,130, +66,194,27,236,102,206,36,154,69,14,124,246,124,74,224,74,225,244,124,142, +225,142,124,218,225,218,176,218,177,13,14,82,82,80,74,136,48,194,15,224, +88,204,26,154,67,18,92,118,247,118,84,240,104,206,114,162,114,34,150,34, +150,226,125,232,160,240,176,204,182,152,182,34,218,34,218,232,193,241,114,10, +141,34,32,48,223,48,74,62,101,92,22,104,233,104,176,62,153,104,12,152, +243,152,122,120,72,186,219,232,174,152,158,182,112,220,39,239,14,86,90,86, +82,136,64,188,21,232,94,210,36,156,67,18,102,40,231,40,104,104,129,166, +226,96,199,164,92,226,243,226,142,226,143,40,184,226,185,41,14,80,88,78, +82,134,62,186,23,228,92,204,30,152,65,14,104,60,231,36,218,60,170,98, +113,122,142,12,154,64,180,112,202,128,216,130,226,120,233,104,98,154,239,154, +88,240,116,228,134,210,144,182,145,154,236,206,234,222,224,230,192,230,182,226, +183,155,16,78,86,76,80,136,62,188,23,230,94,198,30,148,61,14,136,36, +124,80,113,104,228,72,127,72,100,122,239,122,168,244,169,10,94,222,130,186, +152,152,169,122,236,220,202,182,184,148,171,123,110,14,143,36,28,52,229,52, +102,124,103,52,152,126,153,52,70,80,25,120,184,78,229,116,16,156,239,156, +124,124,72,188,146,204,223,232,34,236,84,228,134,208,160,184,179,157,14,78, +90,78,84,138,60,194,23,236,94,202,30,150,69,14,156,14,185,46,108,60, +241,60,150,82,115,126,194,84,231,122,138,130,150,162,172,192,202,218,237,236, +200,134,172,180,142,208,116,224,91,235,16,74,94,72,88,128,62,184,23,222, +98,206,40,150,71,14,130,16,157,50,110,70,239,70,216,14,181,70,102,136, +247,136,104,238,130,210,144,172,146,142,147,70,202,244,203,71,14,84,90,80, +80,148,56,202,25,238,100,214,34,162,65,14,144,16,181,48,116,94,116,62, +228,62,229,94,212,90,156,108,117,114,104,168,243,154,166,106,166,216,172,230, +186,236,216,236,230,228,239,207,12,80,90,80,82,142,58,194,19,234,90,204, +32,152,63,18,220,130,220,32,118,32,118,130,221,130,118,82,221,82,108,174, +229,174,92,228,241,228,168,228,169,33,16,78,92,78,84,142,56,200,21,232, +102,204,34,154,65,16,224,118,224,44,124,44,124,118,225,118,124,82,225,82, +172,118,173,12,102,146,245,146,152,146,142,180,218,180,214,218,210,228,198,236, +173,239,16,78,92,78,80,158,60,194,23,232,98,206,32,148,69,14,216,86, +216,32,126,32,126,86,217,86,116,244,116,128,224,128,224,238,199,242,172,86, +168,140,154,176,135,200,206,196,167,149,16,76,80,74,72,146,54,190,25,230, +88,202,28,148,61,12,108,240,109,56,110,18,133,46,152,34,224,34,224,232, +197,240,128,98,205,98,166,212,167,58,126,180,167,104,204,168,167,109,58,16, +93,42,34,48,69,68,40,128,83,84,158,98,159,10,124,36,107,88,196,38, +233,80,202,82,158,112,93,126,16,160,241,160,120,134,80,192,215,230,40,236, +90,228,132,212,156,184,169,161,14,72,92,72,86,130,68,186,21,232,96,202, +32,152,69,10,128,14,159,44,110,60,220,60,220,102,122,102,120,148,232,148, +232,184,228,200,218,206,199,208,170,246,171,60,210,12,179,60,90,230,136,194, +171,153,16,78,86,78,78,148,58,194,23,228,94,194,34,152,65,16,120,70, +222,70,222,30,120,30,120,156,110,204,89,238,226,90,190,100,139,104,132,142, +231,134,132,178,241,168,176,102,176,214,180,226,192,232,216,232,232,222,241,209, +14,72,78,70,68,144,48,188,17,222,80,196,30,146,57,12,122,186,136,182, +142,164,138,140,120,104,140,30,100,30,101,244,154,30,245,30,220,30,220,232, +187,238,162,166,162,86,192,86,192,166,163,167,18,84,94,84,80,162,56,200, +25,228,106,202,38,154,67,16,112,40,235,40,120,72,223,72,104,102,245,102, +166,102,167,10,128,242,128,132,214,132,214,238,189,242,128,164,215,164,128,198, +215,199,12,82,86,82,78,148,52,198,21,230,92,210,32,154,61,16,104,50, +229,50,114,86,219,86,98,126,241,126,164,126,165,14,100,188,142,150,157,126, +172,208,132,236,133,158,170,142,192,194,235,234,224,142,189,183,14,78,84,76, +78,142,56,194,25,230,92,204,32,152,59,14,102,40,237,40,112,72,216,72, +216,136,115,136,98,102,245,102,130,160,112,210,89,240,244,224,186,224,146,214, +119,196,166,8,167,218,166,174,229,175,16,70,92,70,82,142,60,190,23,230, +94,206,32,140,67,8,216,104,216,28,132,28,132,104,217,104,132,66,217,66, +118,244,118,138,224,138,225,242,118,178,225,178,118,218,225,219,12,80,88,78, +76,160,50,208,21,238,96,218,32,158,61,12,218,138,218,48,116,48,116,138, +219,138,116,92,219,92,168,48,166,92,160,126,148,152,127,178,102,188,243,188, +184,248,185,148,162,8,147,49,14,78,84,76,76,142,56,188,21,226,88,204, +26,152,57,16,118,16,149,48,218,148,218,64,114,64,114,148,219,148,206,14, +173,64,114,104,219,104,96,184,243,184,166,248,167,65,16,46,110,46,86,84, +56,108,17,120,116,100,40,72,77,14,132,104,172,88,200,62,216,34,129,34, +230,112,188,96,156,64,139,34,48,242,48,138,202,138,202,240,175,244,126,114, +114,148,98,164,79,176,172,176,121,138,126,170,104,200,77,218,168,216,117,187, +12,80,90,80,84,138,64,188,25,234,92,200,34,150,65,18,210,116,210,30, +122,30,122,116,211,116,122,72,211,72,84,232,245,232,114,232,114,154,218,154, +219,232,148,232,149,154,182,232,183,155,16,80,88,80,80,148,60,188,21,224, +92,192,36,150,63,14,218,16,160,30,105,32,110,52,131,80,154,48,171,74, +104,92,229,92,216,46,183,92,96,126,237,126,146,92,144,134,128,172,108,204, +81,228,116,240,154,222,190,188,208,156,137,156,144,176,172,204,204,222,237,233, +12,78,94,78,84,142,60,190,25,232,104,206,36,152,71,16,154,14,185,36, +102,46,247,46,212,110,212,72,136,72,136,110,213,110,110,170,110,138,232,138, +233,170,128,172,217,172,178,172,178,242,149,249,52,50,85,70,32,30,108,30, +75,64,20,74,118,74,109,98,84,70,84,136,65,142,24,128,54,104,83,74, +162,14,152,46,135,74,234,54,149,54,152,78,176,104,202,120,235,130,132,136, +160,120,186,92,203,54,20,162,237,162,118,138,80,190,215,236,34,238,88,228, +132,210,179,163,10,80,80,80,72,148,52,194,19,230,86,192,28,150,57,14, +100,46,227,46,108,74,225,74,96,106,241,106,138,106,139,8,192,106,193,8, +118,244,118,134,214,134,214,238,189,244,96,200,243,200,118,166,215,166,166,200, +167,107,8,76,80,76,74,136,50,190,17,228,94,200,26,148,57,10,100,40, +235,40,144,62,145,8,192,62,193,10,214,140,214,76,116,76,116,140,213,140, +116,108,215,108,92,174,237,174,88,238,118,228,144,208,158,186,167,140,234,236, +202,216,182,196,167,175,12,82,88,78,84,136,66,188,23,240,96,202,30,156, +63,16,220,128,220,44,116,44,116,128,221,128,136,68,205,108,194,60,139,112, +160,12,145,44,118,142,118,234,169,216,164,178,119,178,186,144,186,222,188,232, +200,238,224,236,234,226,239,212,230,160,187,187,14,76,88,72,76,140,54,192, +25,226,92,194,32,148,63,14,228,18,166,28,107,32,120,50,141,72,162,44, +181,72,110,116,110,88,230,88,231,114,220,42,195,88,108,132,235,132,162,100, +136,172,89,228,124,236,164,218,196,188,214,162,141,162,154,174,174,200,202,220, +239,233,12,82,84,80,76,146,54,198,19,238,94,210,30,156,61,12,152,16, +183,42,110,88,110,58,226,58,227,88,94,184,245,184,208,82,172,94,130,98, +131,184,130,134,229,134,188,184,189,134,152,202,99,240,186,202,235,241,12,74, +84,72,78,140,56,190,19,232,92,200,28,150,63,12,100,96,245,96,118,24, +118,62,226,62,227,20,172,96,173,12,222,182,222,136,116,136,116,182,223,182, +214,198,239,236,100,228,227,218,172,222,173,111,34,36,123,36,18,64,127,64, +80,120,81,6,24,108,50,92,81,64,120,100,81,72,166,8,154,44,137,68, +238,44,155,44,160,60,178,86,206,106,233,116,136,116,170,102,198,72,213,44, +228,134,50,134,50,178,40,214,29,236,64,178,235,178,142,142,94,198,223,238, +66,234,104,230,142,218,170,194,187,179,16,80,84,80,78,140,58,190,23,230, +88,200,34,156,61,16,104,28,231,28,100,92,237,92,126,92,127,46,170,92, +171,28,170,58,219,58,122,104,116,154,232,154,226,216,218,228,204,232,195,234, +112,176,97,224,136,178,143,216,162,176,175,208,190,172,205,204,226,124,121,125, +16,78,86,76,78,134,58,194,29,236,96,202,30,156,61,14,106,48,237,48, +116,68,143,92,218,66,195,94,98,108,245,108,168,108,169,10,116,244,116,138, +222,138,223,242,116,224,223,224,194,196,194,162,144,162,144,196,195,197,14,76, +90,74,80,142,56,190,21,224,94,198,32,144,67,10,98,26,239,26,224,102, +224,58,114,58,114,102,225,102,152,102,153,26,188,102,189,26,118,132,223,132, +98,162,243,162,136,188,101,228,198,190,233,224,170,162,170,240,147,247,18,84, +88,82,78,148,56,198,25,228,96,202,34,150,65,14,118,20,145,46,106,92, +106,60,234,60,235,92,172,60,173,8,224,20,197,60,206,130,206,88,134,88, +134,130,207,130,118,222,118,160,228,160,228,202,224,210,218,212,210,216,201,210, +170,244,171,131,14,76,88,74,76,152,52,196,23,224,98,200,30,150,61,12, +222,90,222,26,118,26,118,90,223,90,118,58,223,58,170,90,171,26,198,146, +235,180,206,108,110,176,221,166,162,100,118,134,169,134,168,172,168,240,145,244, +138,194,95,232,194,192,237,229,12,84,84,82,68,166,48,204,21,234,84,198, +26,152,57,16,146,14,179,38,106,46,231,46,98,86,241,86,130,60,151,84, +204,56,187,86,216,174,216,114,118,114,118,174,217,174,118,142,217,142,96,202, +243,202,166,246,167,175,12,80,88,78,78,160,54,204,23,234,94,204,30,154, +59,14,96,44,243,44,112,74,227,74,164,74,165,12,216,128,216,96,122,96, +122,128,217,128,94,162,243,162,138,138,149,162,198,138,185,162,120,244,120,188, +220,188,221,242,120,222,221,223,14,76,84,74,70,150,48,198,23,232,58,16, +28,150,95,196,146,12,179,36,90,46,243,46,226,134,226,68,108,68,108,134, +227,134,196,114,196,90,138,90,138,114,197,114,218,208,218,158,118,158,118,208, +219,208,118,184,219,184,88,234,245,235,44,66,114,66,114,30,44,30,44,78, +25,124,116,130,116,94,54,94,54,130,117,130,164,12,189,32,130,40,235,40, +128,80,245,80,136,114,235,114,184,144,185,80,150,54,167,80,210,50,195,80, +24,164,241,164,176,164,168,182,142,210,104,230,72,236,47,238,132,138,82,194, +229,239,92,110,92,30,36,30,36,110,93,110,36,70,93,70,66,110,67,30, +24,150,92,150,90,202,84,214,72,222,63,218,62,120,54,176,42,208,27,234, +104,82,148,82,134,164,118,206,95,240,152,208,108,156,133,22,226,112,226,30, +166,30,166,112,227,112,166,70,227,70,196,112,197,30,154,152,230,148,222,218, +216,228,204,232,191,228,192,122,188,162,178,198,162,222,145,241,14,80,82,80, +72,156,50,202,21,236,86,188,28,152,59,14,154,12,183,32,240,46,108,46, +108,166,96,208,81,234,124,84,173,84,152,144,153,56,124,128,153,88,174,116, +153,92,186,84,237,84,208,142,209,56,176,134,207,84,238,132,209,86,166,152, +131,188,206,190,237,236,202,160,134,228,225,219,16,74,80,72,72,134,54,188, +27,224,80,188,32,144,61,12,110,22,223,22,102,88,102,52,232,52,233,88, +166,110,167,22,118,76,149,76,118,100,149,100,184,76,217,76,184,100,217,100, +92,140,153,140,124,242,125,114,84,208,125,148,148,182,125,150,170,240,170,128, +224,128,225,240,170,156,225,156,170,186,225,186,170,220,225,221,42,30,180,30, +168,72,218,72,214,114,210,124,198,132,179,130,30,128,62,116,88,90,102,62, +111,30,136,120,136,232,103,240,84,156,31,214,180,162,231,213,122,88,123,14, +84,36,60,68,33,94,164,36,213,88,20,126,229,126,124,98,96,142,68,164, +42,180,21,190,234,182,200,172,166,154,141,126,126,146,126,242,99,244,92,174, +49,228,154,176,203,225,220,20,144,34,37,34,54,54,83,94,120,50,141,90, +40,110,214,110,132,150,132,218,126,230,114,236,95,232,14,172,245,172,208,50, +163,111,14,48,114,48,98,76,72,104,46,118,21,126,110,114,44,82,81,12, +130,36,214,36,202,62,184,86,154,110,125,124,148,36,154,62,172,86,202,112, +235,128,18,186,237,186,48,142,186,142,130,170,130,224,124,236,110,242,97,237, +18,44,243,44,86,12,117,34,180,12,149,44,104,104,125,134,114,76,42,130, +117,124,84,52,40,94,91,94,204,104,223,136,210,74,144,128,213,122,182,54, +140,92,189,92,40,154,186,154,134,180,134,232,122,242,106,244,95,236,18,194, +241,195,48,34,200,34,134,90,134,206,130,222,114,232,99,226,28,150,237,107, +36,32,196,32,128,90,128,218,120,232,102,238,89,230,54,88,86,116,118,134, +162,152,198,162,231,169,16,34,104,34,62,82,62,220,58,230,44,238,33,232, +16,156,101,122,156,14,126,60,105,88,190,180,206,180,220,172,224,158,224,58, +129,58,236,206,230,224,214,234,148,234,134,230,126,212,126,100,180,100,180,152, +127,153,40,56,34,132,104,132,96,218,88,232,70,236,61,228,14,188,83,172, +84,132,94,28,15,28,110,222,245,222,140,222,140,28,214,28,215,222,140,92, +215,92,140,152,215,153,44,54,36,136,106,136,98,212,94,228,82,234,65,226, +16,196,85,176,18,30,90,30,83,136,132,236,132,36,226,36,227,236,132,210, +227,210,164,36,164,118,160,148,145,176,190,36,190,140,192,148,202,156,227,157, +40,54,32,134,94,134,88,212,82,224,66,232,51,222,14,186,73,176,16,30, +82,30,75,134,152,16,124,76,103,108,134,240,135,56,148,82,245,82,158,116, +179,154,210,14,210,208,204,226,190,236,177,227,52,50,46,134,110,134,104,216, +98,230,84,234,73,228,20,188,85,178,26,30,98,30,93,134,168,10,138,72, +119,96,132,110,226,110,227,242,136,160,227,160,130,212,227,212,176,110,212,50, +151,51,38,54,34,132,94,132,88,206,82,222,66,232,53,226,14,186,73,172, +110,26,206,26,170,74,146,92,105,114,14,32,80,32,77,132,238,110,194,96, +154,70,134,46,123,26,118,144,225,144,106,184,241,184,166,244,167,111,20,48, +116,44,98,74,66,104,29,120,120,112,46,76,85,14,132,36,218,36,188,82, +164,100,139,118,234,114,198,100,172,78,156,56,145,36,80,152,72,186,220,186, +216,220,208,232,186,240,173,236,40,134,190,134,185,186,16,214,179,215,44,56, +36,134,110,134,106,202,100,220,80,232,63,230,18,194,87,176,16,34,96,34, +91,134,202,54,235,116,178,14,128,108,225,100,146,240,146,142,220,142,221,240, +146,218,221,219,44,50,36,132,98,132,90,208,84,226,72,232,57,230,16,188, +75,174,20,30,88,30,79,132,106,56,233,38,214,60,164,98,117,114,144,10, +160,66,184,104,208,122,220,124,228,116,237,98,112,146,233,146,148,146,148,166, +144,196,136,212,118,228,105,238,180,146,180,214,184,226,196,234,220,234,234,222, +239,207,40,52,36,134,100,134,96,204,88,224,74,230,57,228,18,188,79,172, +18,32,86,32,83,134,146,16,126,58,105,88,136,138,137,38,226,32,190,72, +157,100,178,12,178,108,182,120,190,128,212,128,224,124,233,102,114,172,243,172, +170,242,171,141,38,48,36,126,100,126,96,208,90,224,74,232,63,226,16,184, +81,168,14,26,88,26,81,126,134,14,161,48,114,64,241,64,218,12,189,64, +114,140,243,140,154,64,154,150,146,186,134,214,117,238,202,242,203,65,20,28, +80,28,77,132,42,48,36,132,90,132,86,206,80,224,68,230,53,228,18,188, +71,174,104,30,243,30,118,236,118,68,160,68,160,234,143,240,132,112,141,162, +184,234,184,66,226,66,226,232,209,238,202,110,209,161,38,54,34,134,94,134, +92,210,86,224,70,232,59,228,18,194,73,178,106,52,237,52,110,170,243,170, +136,170,137,14,206,170,207,12,136,90,207,90,136,130,207,130,18,30,82,30, +77,134,154,190,109,240,186,190,235,235,34,60,26,138,90,138,82,210,76,224, +56,234,41,228,14,190,71,176,12,34,86,34,73,138,216,102,216,28,122,28, +122,102,217,102,122,68,217,68,108,142,237,142,168,244,169,28,98,222,132,188, +165,142,236,220,208,196,188,172,173,143,42,56,36,134,98,134,94,212,90,226, +72,232,63,226,16,190,81,172,154,12,126,72,105,106,182,12,205,44,136,242, +137,54,142,64,239,64,144,114,229,114,144,162,229,162,144,212,245,212,186,212, +187,64,16,34,86,34,83,135,36,54,32,132,96,132,90,210,84,226,64,232, +53,228,16,186,75,172,12,30,86,30,79,132,192,34,227,68,172,14,128,66, +213,56,108,96,239,96,172,70,148,116,113,150,236,152,206,130,185,96,174,130, +152,158,131,178,196,154,166,182,135,206,222,174,180,212,123,239,34,138,34,32, +84,32,64,64,72,72,82,82,86,90,84,102,72,110,61,110,90,68,239,68, +122,30,123,68,164,18,165,68,164,38,219,38,166,102,167,68,134,84,109,108, +218,82,184,108,146,124,97,132,78,164,74,186,208,186,206,222,200,232,184,238, +165,236,28,214,181,214,52,148,182,148,177,187,64,44,93,66,32,24,116,24, +81,56,20,70,126,70,115,96,88,70,88,120,67,126,20,116,56,96,85,70, +172,10,152,46,137,58,238,44,153,44,158,60,184,96,239,120,208,44,194,76, +168,104,135,122,44,140,194,140,185,186,84,158,78,186,222,186,220,214,212,232, +190,240,179,236,30,216,187,217,24,30,127,30,32,54,121,54,14,78,139,78, +78,78,79,8,66,78,58,112,40,132,25,146,88,130,100,130,116,124,124,104, +61,104,168,10,148,48,135,64,236,44,151,44,158,64,174,94,206,120,231,134, +208,44,200,72,188,94,168,116,141,132,86,164,78,190,226,190,222,220,214,232, +198,238,181,234,28,216,189,216,54,150,194,150,189,191,46,52,44,132,98,132, +94,214,88,228,76,236,63,232,24,32,88,32,83,132,18,188,79,176,146,50, +167,88,162,20,120,34,120,104,159,72,174,30,228,30,228,92,224,106,214,114, +203,110,192,30,192,60,186,84,172,108,163,118,128,242,128,134,220,134,221,240, +128,174,221,174,128,218,221,218,174,218,175,135,42,58,36,138,92,138,88,212, +80,226,68,236,55,230,16,188,73,176,16,38,82,38,77,138,154,12,183,34, +122,82,224,82,224,44,122,44,122,170,114,204,99,238,136,116,172,116,172,238, +149,244,138,138,155,160,136,204,173,170,186,114,228,114,228,236,205,242,188,136, +207,162,188,198,229,167,42,54,38,134,94,134,90,210,84,222,68,228,53,224, +18,188,73,176,18,32,78,32,75,134,100,28,243,28,220,62,220,104,118,104, +118,62,221,62,152,104,153,28,186,104,187,28,120,136,223,136,108,166,243,166, +138,186,107,228,200,188,231,226,172,166,172,238,145,245,34,58,30,134,92,134, +84,216,76,226,64,232,51,228,14,188,71,172,14,34,84,34,77,134,220,154, +220,46,124,46,124,154,221,154,172,58,152,88,139,102,162,102,201,134,146,138, +170,124,188,102,202,84,157,84,168,14,153,46,120,184,105,224,162,166,187,194, +210,178,241,214,146,182,146,220,148,230,158,238,184,238,202,228,207,211,32,50, +30,128,82,128,76,208,66,224,52,232,43,226,16,180,63,168,16,26,74,26, +69,128,90,228,108,184,112,140,112,22,224,22,224,54,113,54,138,76,210,76, +182,98,182,140,165,142,130,110,235,110,128,154,168,154,148,176,148,238,133,242, +120,200,171,188,188,152,230,152,208,180,208,236,191,242,180,194,243,195,42,56, +38,138,96,138,92,216,86,226,66,234,57,230,16,190,77,182,18,34,82,34, +79,138,148,12,149,72,104,34,149,34,100,68,149,58,184,12,184,52,188,62, +198,66,218,66,230,56,235,44,228,20,185,40,218,136,218,84,124,84,124,136, +219,136,124,110,219,110,170,136,171,84,114,166,231,166,104,194,245,194,146,194, +147,144,194,194,195,144,158,206,115,240,188,204,233,239,38,54,34,138,84,138, +80,216,74,232,62,240,53,234,12,194,65,180,16,36,74,36,69,138,152,12, +177,32,94,38,239,38,152,90,152,60,110,60,110,90,153,90,220,88,220,60, +176,60,176,88,221,88,100,116,233,116,106,138,227,138,96,162,243,162,140,162, +141,90,188,162,189,88,100,216,134,194,163,162,172,212,138,234,139,190,172,176, +190,202,210,218,243,232,226,176,191,201,112,70,34,174,117,162,26,226,117,210, +86,24,32,110,83,109,104,58,24,162,103,154,68,16,18,94,77,94,16,222, +107,200,124,34,231,34,108,120,245,120,180,34,180,236,147,243,102,58,28,160, +105,152,20,226,111,198,68,16,16,100,71,100,114,88,245,88,132,124,165,166, +202,12,202,236,169,243,20,220,99,200,98,54,24,168,95,156,66,18,14,100, +67,100,152,14,126,70,109,96,232,58,133,58,116,114,196,114,164,146,142,172, +126,196,124,212,128,224,144,234,212,234,228,222,237,197,100,60,26,166,103,152, +16,214,101,196,68,20,14,98,73,98,108,80,204,74,204,128,208,202,216,228, +222,238,226,238,238,232,247,208,118,126,171,170,152,12,152,94,146,138,134,180, +116,210,91,237,20,218,105,198,104,62,26,164,103,154,74,20,20,104,73,104, +158,18,193,48,240,60,130,60,130,178,120,210,103,243,77,20,24,228,115,200, +106,66,26,168,105,158,76,20,18,106,75,106,124,40,223,40,108,118,237,118, +190,172,237,238,172,126,122,232,221,219,24,224,91,198,84,68,26,170,89,154, +62,24,18,98,67,98,116,22,116,226,155,196,116,98,159,98,176,16,176,208, +180,222,188,228,216,228,232,210,237,184,224,62,177,121,16,228,103,210,98,62, +22,174,99,164,68,22,18,104,69,104,142,64,179,98,110,34,216,34,167,86, +96,108,232,108,219,142,170,108,170,238,137,245,69,24,18,228,103,208,96,62, +26,170,99,160,68,26,18,106,67,106,98,86,245,86,134,20,135,246,206,244, +207,20,134,150,207,150,134,218,207,219,22,222,107,198,102,56,22,168,97,158, +68,24,16,102,69,102,102,98,245,98,130,38,130,228,239,228,168,24,168,184, +208,184,209,25,20,218,97,200,96,66,26,172,99,160,66,24,18,104,69,104, +110,80,237,80,186,30,217,58,158,16,148,110,124,180,93,232,128,240,164,214, +198,174,214,122,156,122,160,144,166,168,186,196,214,224,239,239,22,218,101,198, +98,56,30,156,103,152,70,12,20,94,73,94,120,108,218,108,219,244,122,156, +219,156,112,218,219,218,158,10,126,74,101,110,174,108,202,54,139,55,18,214, +97,196,94,58,28,162,91,152,66,16,24,94,71,94,104,50,222,50,222,100, +110,100,108,148,234,148,228,196,205,208,84,242,118,222,140,190,146,154,147,12, +184,244,185,11,22,230,95,206,92,60,30,170,95,158,62,20,24,100,69,100, +120,28,120,110,214,110,215,28,222,142,223,246,112,144,112,226,223,226,166,226, +167,17,22,228,105,202,100,50,28,166,103,158,62,18,18,94,73,94,190,50, +239,108,172,16,114,100,227,94,132,246,132,144,216,144,217,240,132,216,217,217, +18,224,97,204,94,64,24,168,95,160,68,24,20,102,69,102,102,52,233,52, +166,14,142,72,103,114,232,114,202,90,181,52,130,104,203,104,104,142,231,142, +148,142,142,180,206,180,200,220,194,232,176,236,163,229,18,218,95,200,92,72, +24,166,91,158,74,18,24,100,71,100,144,14,101,58,152,66,118,110,93,138, +124,236,125,102,164,36,233,36,154,108,241,108,206,108,206,230,175,239,16,220, +95,200,86,68,20,164,89,154,66,18,16,96,65,96,144,14,122,50,107,70, +136,64,168,92,198,104,239,116,88,122,126,110,158,90,182,66,198,42,129,42, +108,146,229,146,124,162,118,198,239,198,168,244,169,115,16,216,95,200,96,60, +20,164,93,154,72,14,20,96,69,96,96,30,241,30,220,142,220,66,116,66, +116,142,221,142,116,106,221,106,168,30,168,148,160,184,142,212,120,226,95,238, +114,162,136,186,168,212,204,224,237,229,20,226,103,204,92,70,28,172,101,160, +70,26,20,104,71,104,112,30,143,70,230,30,201,70,124,242,124,92,222,92, +222,236,197,240,124,136,223,136,124,178,223,178,172,92,173,15,22,214,93,190, +88,56,28,158,89,152,62,14,16,94,65,94,104,56,212,56,212,100,114,100, +114,146,226,146,220,188,212,202,202,204,193,200,162,244,163,56,120,14,151,40, +200,10,177,56,88,228,118,204,140,180,163,149,16,218,97,196,94,60,22,160, +95,152,68,16,16,96,67,96,108,44,225,44,98,82,239,82,164,82,165,8, +144,96,99,136,184,96,231,130,162,114,134,156,107,184,98,238,136,224,176,198, +196,168,206,146,143,146,146,166,168,198,196,218,237,237,16,214,97,196,92,58, +28,162,97,154,68,14,20,92,71,92,108,50,233,50,166,14,162,56,150,76, +128,90,109,100,218,98,163,52,92,116,245,116,210,116,210,238,181,246,174,198, +174,152,122,152,122,198,175,199,16,222,93,202,86,68,28,164,91,156,64,18, +18,98,67,98,144,240,145,12,184,244,185,10,98,64,145,64,100,118,145,118, +96,178,145,178,238,62,185,62,234,118,185,118,242,178,185,179,18,218,97,200, +94,62,24,168,97,158,68,22,18,102,67,102,114,32,143,72,230,34,199,76, +116,238,116,94,224,94,224,230,191,238,168,94,169,14,194,186,194,128,146,128, +146,186,195,187,14,224,95,204,90,62,24,170,93,158,64,18,16,100,67,100, +218,112,218,26,114,26,114,112,219,112,114,70,219,70,114,126,114,234,163,212, +114,168,163,168,180,128,180,218,184,230,196,236,216,236,232,222,237,204,230,142, +181,181,18,220,89,200,84,68,20,172,85,158,64,20,18,106,61,106,224,26, +174,34,95,38,100,78,235,78,88,128,243,128,92,174,241,174,102,228,233,228, +166,228,167,34,124,174,125,78,206,174,207,79,18,218,91,196,90,64,22,158, +89,152,66,16,22,94,69,94,220,16,168,28,103,32,112,52,135,80,148,48, +171,76,98,130,98,100,226,100,227,130,214,48,183,100,110,140,200,140,168,194, +144,212,95,240,234,234,194,220,162,200,142,176,126,146,123,141,16,216,95,200, +86,62,24,156,91,146,62,16,18,96,63,96,130,14,110,68,95,96,98,156, +126,132,152,90,162,54,117,54,114,86,136,122,164,132,239,136,190,118,191,12, +202,50,235,94,124,240,124,162,214,162,215,238,124,218,213,219,16,210,91,196, +84,54,20,154,83,144,58,16,18,92,61,92,108,26,133,56,210,24,183,58, +100,76,229,76,86,108,239,108,158,10,148,90,122,136,87,168,236,168,204,144, +175,108,164,200,182,198,192,188,192,152,128,152,128,214,132,226,148,236,194,236, +214,224,219,207,26,226,109,202,102,62,68,118,30,166,105,158,70,22,20,100, +79,100,156,16,187,44,124,86,124,54,230,54,231,84,136,244,136,98,216,98, +216,140,137,140,224,240,224,176,137,176,136,220,225,221,22,226,101,206,92,66, +58,122,28,172,97,162,68,22,20,104,69,104,142,18,112,74,147,118,182,20, +156,72,185,114,224,22,200,74,233,114,122,244,122,136,222,136,223,242,122,220, +223,220,122,178,223,178,174,220,175,137,18,224,89,208,94,68,58,124,26,166, +93,156,70,22,20,104,71,104,98,48,235,48,138,12,138,82,196,82,197,12, +220,156,220,112,114,112,114,156,221,156,94,186,243,186,166,244,167,83,18,218, +87,196,74,78,54,116,22,160,73,150,64,20,22,94,65,94,86,70,147,70, +118,240,119,14,78,170,102,128,119,78,144,134,119,92,164,232,164,32,226,32, +227,230,164,88,227,88,164,142,227,142,164,204,227,205,16,224,99,202,98,62, +66,116,24,172,97,160,68,22,20,106,71,106,218,100,218,30,128,30,128,100, +219,100,128,66,219,66,102,136,239,136,136,160,120,206,97,242,236,232,168,228, +146,212,136,196,129,186,174,136,175,228,228,178,175,179,16,206,79,188,78,68, +52,116,22,152,81,148,64,12,28,90,67,90,98,218,98,32,140,32,141,208, +98,82,141,82,98,132,141,132,98,186,141,186,196,10,197,162,174,60,157,130, +216,58,239,114,232,126,216,168,192,200,166,220,127,239,18,218,99,200,94,60, +58,118,26,164,95,154,68,16,20,100,69,100,94,106,243,106,168,106,169,12, +220,76,220,40,118,40,118,76,221,76,120,200,120,132,218,132,219,198,168,152, +164,188,152,210,132,226,105,240,180,206,233,237,16,218,91,202,92,62,56,122, +28,164,93,156,68,18,20,102,69,102,216,132,216,26,118,26,118,132,217,132, +168,132,169,26,118,78,217,78,118,174,97,226,162,146,187,178,210,162,239,198, +146,170,146,216,148,228,162,234,194,234,204,222,207,205,18,224,85,208,80,68, +52,126,20,174,85,162,64,18,20,104,63,104,124,20,100,90,79,126,112,244, +113,58,134,38,237,38,222,156,222,78,142,78,142,156,223,156,142,118,223,118, +182,38,182,166,178,194,160,220,133,238,146,174,164,202,186,220,212,228,237,233, +14,210,85,194,84,52,50,114,20,154,87,144,58,14,14,88,63,88,130,12, +112,58,81,112,108,244,109,68,128,78,241,78,150,34,208,34,199,78,158,92, +148,120,135,140,228,122,149,122,128,166,241,166,184,122,180,168,164,206,133,240, +236,240,210,214,194,192,181,167,14,220,89,196,86,60,52,120,22,162,87,154, +62,20,14,100,63,100,96,32,127,70,80,238,108,216,118,216,132,236,243,236, +80,114,114,114,115,216,152,100,216,100,216,54,152,54,152,198,220,198,220,142, +153,142,186,14,173,55,12,220,101,198,90,58,58,116,24,166,97,156,66,16, +20,100,67,100,168,114,110,134,110,24,216,24,216,58,111,58,110,88,237,88, +240,110,236,126,230,132,222,134,204,126,184,102,171,58,120,242,120,152,216,152, +217,238,120,188,217,188,120,220,217,221,18,214,95,198,90,62,60,112,26,158, +95,148,70,16,22,94,71,94,100,34,235,34,92,112,245,112,110,56,129,92, +226,54,207,94,150,112,151,34,184,112,185,34,120,246,120,146,214,146,215,242, +120,184,213,184,120,224,213,225,16,226,89,208,94,56,62,122,28,172,97,156, +66,20,26,96,75,96,104,44,239,44,90,188,245,188,126,188,126,74,210,74, +211,188,166,74,177,10,126,104,211,104,126,132,211,132,126,160,211,160,146,202, +99,240,186,202,233,241,18,208,87,196,94,58,60,116,26,158,93,148,68,16, +20,94,73,94,232,28,114,28,114,134,106,184,81,234,132,58,223,58,122,88, +237,88,146,88,146,140,177,126,236,144,206,132,184,104,177,88,228,104,201,122, +126,172,241,172,142,186,159,218,200,144,200,222,196,234,182,240,169,237,20,216, +93,198,90,62,58,120,26,164,91,152,66,16,20,96,71,96,144,12,175,40, +100,50,241,50,210,112,210,80,128,80,128,112,211,112,110,242,110,142,224,142, +224,240,197,244,190,200,190,170,142,170,142,200,191,201,18,220,93,202,92,68, +60,120,26,166,91,156,70,24,22,102,71,102,150,16,181,38,100,48,243,48, +120,72,120,122,224,122,225,74,142,68,203,104,200,64,141,104,114,242,114,154, +228,154,228,236,203,242,184,172,207,212,170,130,144,202,197,195,24,220,95,198, +94,68,58,122,26,162,91,156,68,18,20,92,77,92,120,22,153,54,106,74, +235,74,206,16,175,74,146,92,97,140,186,96,237,136,88,232,243,232,118,232, +118,150,216,150,217,232,150,232,151,150,182,232,183,151,84,68,52,122,20,168, +89,158,14,218,89,202,66,22,16,104,63,104,118,16,147,44,94,56,239,56, +208,18,179,56,88,120,241,120,102,152,214,152,214,88,105,88,142,244,143,56, +180,244,181,56,86,228,120,190,143,152,234,226,204,192,181,153,18,214,93,202, +86,62,56,118,24,158,89,152,66,12,18,96,69,96,146,12,177,36,106,88, +106,48,228,48,229,86,206,74,162,82,126,86,127,170,92,170,243,170,126,122, +227,122,184,170,185,122,146,186,89,240,184,190,237,237,16,212,93,198,88,60, +56,116,24,162,89,154,64,14,16,96,67,96,94,28,239,28,224,106,224,60, +110,60,110,106,225,106,146,28,147,106,184,28,185,106,110,138,223,138,96,168, +241,168,130,194,85,232,196,194,243,228,166,168,166,238,141,245,22,226,99,202, +96,54,62,114,28,164,95,152,66,14,20,94,73,94,216,78,216,20,126,20, +126,78,217,78,126,50,217,50,226,140,226,100,110,100,110,140,227,140,148,140, +149,100,186,140,187,100,112,164,210,164,184,194,150,222,124,232,99,238,234,238, +202,228,178,214,150,190,131,165,20,216,97,198,96,64,56,126,26,166,97,154, +70,20,22,100,73,100,222,88,222,24,120,24,120,88,223,88,120,58,223,58, +172,88,173,24,202,146,235,182,208,114,160,148,118,176,223,168,168,96,120,138, +175,138,172,172,172,236,147,244,138,192,99,230,198,194,235,227,16,214,89,198, +90,68,60,118,26,164,85,154,70,16,44,60,18,96,73,96,94,28,150,28, +151,102,102,50,127,68,94,100,151,80,168,28,218,28,219,116,170,50,197,66, +168,92,219,76,162,104,124,136,93,156,158,108,178,128,208,146,237,156,168,140, +134,166,103,182,190,162,148,192,103,212,212,184,160,222,103,245,16,206,87,190, +88,62,58,112,26,160,89,148,64,18,20,92,69,92,122,14,98,46,121,72, +166,16,144,44,169,70,212,14,192,40,215,68,210,144,210,84,106,84,106,144, +211,144,106,116,211,116,92,172,233,172,156,244,157,84,78,232,124,204,157,180, +236,224,194,208,157,177,20,224,81,204,72,74,48,126,26,170,79,158,58,24, +40,66,20,104,57,104,80,62,155,62,84,108,149,108,118,108,119,14,96,230, +96,140,138,140,139,224,96,204,139,204,150,34,235,34,166,188,166,80,220,80, +221,186,190,34,183,80,196,104,194,172,184,202,166,224,151,240,204,196,237,237, +14,216,91,198,86,54,52,114,20,162,87,152,58,18,38,56,14,94,63,94, +96,46,231,46,164,12,152,60,136,84,112,104,81,118,104,70,127,92,236,116, +208,100,184,80,163,46,222,64,197,90,204,170,204,106,122,106,122,170,205,170, +122,138,205,138,130,188,91,232,192,194,233,226,164,170,164,240,137,245,24,210, +95,196,88,62,60,110,28,158,93,150,62,12,44,54,18,92,71,92,120,14, +145,40,222,118,222,50,108,50,108,118,223,118,164,118,165,50,204,10,179,50, +126,70,147,96,202,70,185,96,120,242,120,148,212,148,213,240,120,182,213,182, +120,218,213,219,18,212,97,198,98,60,62,116,26,160,95,152,74,18,50,58, +20,96,75,96,106,28,239,28,218,104,218,54,120,54,120,104,219,104,120,78, +219,78,166,104,167,54,96,128,243,128,220,204,220,152,114,152,114,204,221,204, +114,178,221,178,168,204,169,152,92,228,243,229,16,220,91,198,84,68,50,124, +18,170,85,160,62,16,42,58,14,102,63,102,90,38,123,78,222,72,222,42, +138,42,138,72,223,72,120,98,243,98,180,98,181,8,84,238,104,216,116,216, +128,236,239,236,78,124,110,124,111,216,144,150,218,150,218,120,144,120,144,204, +224,204,224,174,145,175,16,218,95,198,96,60,56,122,24,164,91,154,70,20, +44,66,16,102,69,102,206,60,206,26,130,26,130,60,207,60,152,130,152,90, +110,90,110,130,153,130,222,128,222,90,178,90,178,128,223,128,98,166,237,166, +166,244,167,144,92,228,128,204,165,168,234,226,200,204,167,169,18,214,95,192, +88,62,54,122,22,166,91,158,70,14,42,66,16,102,65,102,224,66,224,24, +110,24,110,66,225,66,150,66,151,24,184,66,185,24,96,94,241,94,214,154, +214,122,118,122,118,154,215,154,92,216,128,192,150,172,165,154,180,212,136,232, +137,184,227,170,176,170,186,190,206,212,239,234,226,170,193,197,16,220,93,202, +82,68,54,120,22,168,89,154,68,18,48,60,20,102,63,102,112,22,101,58, +156,46,105,46,98,76,163,76,134,76,135,12,96,124,112,110,120,90,123,76, +142,76,142,114,169,100,182,22,171,58,232,46,175,46,172,76,239,76,204,76, +205,14,172,124,186,102,191,76,240,98,232,112,224,116,212,114,212,100,213,76, +120,204,120,136,210,136,211,204,96,242,130,226,154,206,164,182,169,158,174,208, +231,239,170,162,217,232,178,72,114,150,46,220,199,206,130,22,94,76,60,120, +139,121,18,130,235,130,126,10,126,68,132,134,152,188,194,232,208,238,220,232, +226,220,227,200,198,146,174,188,127,236,174,108,195,120,40,240,40,160,114,160, +115,234,40,190,115,190,40,220,115,220,76,220,77,160,101,42,92,76,109,110, +100,42,68,78,40,104,101,94,76,16,34,60,83,60,204,76,221,106,210,40, +182,72,148,100,213,94,188,18,146,60,193,61,82,22,34,128,89,230,144,26, +102,126,157,228,212,24,164,124,225,227,78,16,40,72,81,112,140,16,106,68, +141,110,208,16,174,66,217,110,54,244,54,128,200,128,201,244,54,176,201,176, +54,220,201,220,126,220,127,129,68,18,42,52,79,74,130,18,104,50,139,72, +190,16,164,46,207,72,188,120,188,88,52,88,52,120,189,120,228,196,220,218, +198,228,68,228,46,224,40,208,40,146,200,146,200,182,41,182,122,182,123,147, +14,42,101,42,20,114,97,114,20,210,115,180,60,42,61,196,114,36,241,36, +186,36,186,232,155,239,12,44,99,44,16,112,95,112,14,198,101,176,56,44, +57,186,76,234,110,204,124,166,128,124,128,32,190,32,190,212,196,224,210,232, +224,232,236,220,239,201,16,48,95,48,20,118,91,118,18,206,97,186,56,48, +57,196,102,50,241,50,112,94,225,94,100,138,228,138,226,190,224,204,208,210, +199,206,166,242,167,13,14,40,97,40,16,110,87,110,16,206,93,178,52,40, +53,192,146,16,136,52,120,84,99,118,178,16,188,52,212,88,237,116,118,110, +202,110,198,214,194,224,178,232,161,226,144,110,142,152,136,182,112,212,79,233, +12,50,101,50,16,118,99,118,18,202,101,186,58,50,59,194,142,16,175,50, +96,70,239,70,232,232,198,210,162,172,144,136,132,104,127,70,96,230,134,210, +162,184,178,154,190,120,201,71,14,42,103,42,18,116,99,116,16,210,105,188, +60,42,61,198,112,34,241,34,116,120,233,120,196,150,227,190,102,222,245,222, +172,222,173,35,12,40,95,40,20,108,91,108,18,206,99,178,58,40,59,190, +108,32,245,32,214,32,214,236,183,240,172,162,172,88,122,88,122,162,173,163, +14,46,103,46,16,120,97,120,16,212,99,184,58,46,59,198,90,82,239,82, +178,26,215,58,142,14,142,94,134,144,112,196,73,240,212,108,186,162,154,202, +125,222,166,98,166,216,174,228,188,236,220,236,232,220,237,205,18,42,109,42, +22,110,105,110,18,208,105,184,62,42,63,196,124,244,124,132,220,132,221,244, +124,216,221,216,164,12,165,132,242,70,165,71,16,44,97,44,22,114,89,114, +18,204,97,174,58,44,59,188,140,16,110,74,91,100,120,244,121,56,136,110, +237,102,194,46,225,76,174,14,176,114,194,194,208,226,214,230,222,230,230,222, +239,205,18,48,107,48,24,118,101,118,18,218,101,192,64,48,65,202,124,244, +124,68,224,68,225,242,174,14,157,68,124,140,225,140,124,216,225,217,16,44, +101,44,20,116,95,116,20,210,99,186,60,44,61,198,160,198,118,234,118,34, +216,34,216,92,119,92,118,144,239,144,168,92,176,152,190,196,200,218,210,230, +218,234,226,234,234,224,239,207,16,50,91,50,22,120,85,120,16,214,83,184, +56,50,57,196,90,72,154,72,154,212,148,226,136,232,119,228,120,14,116,134, +102,192,65,240,184,236,184,60,224,60,225,234,184,208,225,209,16,38,101,38, +24,108,95,108,22,204,103,172,60,38,61,188,110,32,239,32,100,192,241,180, +210,242,211,32,132,32,133,188,132,82,211,82,132,132,211,133,20,40,101,40, +24,112,99,112,22,212,101,184,64,40,65,196,108,70,233,70,100,144,241,144, +142,144,143,14,196,144,197,12,152,172,99,238,188,170,233,231,16,42,97,42, +24,110,95,110,22,206,99,178,62,42,63,190,108,32,239,32,124,192,124,80, +218,80,219,186,172,32,161,80,172,104,172,144,166,168,156,194,138,214,108,230, +93,238,178,194,239,233,16,36,81,36,20,106,79,106,20,200,79,164,50,36, +51,180,90,28,163,28,138,28,138,232,111,240,106,48,94,114,165,114,72,204, +108,162,133,114,182,244,182,32,230,32,204,108,220,126,232,148,232,172,222,186, +205,189,12,46,97,46,16,116,91,116,16,200,97,182,54,46,55,190,140,14, +116,48,91,76,150,66,122,106,85,146,124,242,125,104,158,38,239,38,150,108, +243,108,206,108,206,234,177,241,14,38,89,38,18,112,85,112,18,210,87,188, +52,38,53,198,94,58,119,102,142,14,142,162,124,206,81,238,88,164,143,130, +182,12,182,216,186,228,198,234,212,234,228,230,239,206,228,54,203,102,228,168, +183,125,16,44,95,44,20,112,89,112,14,204,93,178,54,44,55,188,150,12, +124,56,99,88,90,144,152,114,188,80,210,50,129,50,136,70,166,104,202,126, +239,140,120,244,120,156,210,156,211,244,120,222,211,223,88,12,54,56,25,80, +204,76,218,48,61,48,96,78,64,106,33,126,162,82,223,114,134,48,134,126, +107,132,40,146,223,146,54,182,207,182,22,228,239,228,162,194,197,216,128,228, +129,147,18,40,95,40,22,112,93,112,18,210,95,186,58,40,59,196,110,60, +110,26,232,26,233,58,106,78,235,78,164,42,116,132,229,132,98,174,243,174, +174,238,175,99,16,46,87,46,22,116,79,116,22,208,93,180,54,46,55,194, +98,32,121,76,84,228,112,210,120,210,130,230,235,230,88,122,116,122,117,210, +130,50,235,50,184,18,140,118,227,118,134,164,233,164,188,216,189,81,14,40, +89,40,18,114,85,114,16,214,91,186,52,40,53,200,98,52,235,52,98,172, +243,172,128,172,129,12,204,172,205,10,128,92,205,92,128,132,205,132,140,190, +93,242,178,192,231,239,18,46,89,46,22,114,85,114,14,216,95,190,56,46, +57,202,96,50,239,50,132,80,133,16,190,80,191,14,84,166,243,166,114,166, +114,106,208,106,209,166,162,76,154,172,134,202,110,224,79,240,232,242,200,222, +174,196,157,167,18,36,95,36,22,110,89,110,18,208,95,180,58,36,59,192, +112,42,231,42,168,6,156,56,138,78,111,92,214,92,159,50,100,108,245,108, +208,108,208,236,177,244,170,190,170,144,116,144,116,190,171,191,16,44,93,44, +20,112,85,112,14,208,87,180,54,44,55,190,220,92,232,68,110,68,110,166, +98,206,73,240,162,68,163,10,162,38,225,38,124,114,209,102,160,80,160,128, +162,140,172,144,198,144,212,138,223,122,114,240,134,220,144,198,146,170,192,170, +192,218,194,228,208,238,218,238,232,228,241,209,14,44,99,44,20,116,93,116, +16,214,97,188,58,44,59,200,216,114,216,34,120,34,120,114,217,114,120,74, +217,74,116,134,116,234,157,216,160,168,117,168,180,132,180,218,184,232,198,236, +220,236,236,228,239,206,232,156,181,183,12,48,97,48,18,116,91,116,14,202, +99,182,56,48,57,192,124,30,117,76,216,32,199,70,168,14,162,56,148,84, +130,102,107,116,226,114,159,68,126,138,115,180,214,142,201,178,162,108,156,172, +142,198,118,220,91,236,238,234,210,218,186,192,168,164,161,143,12,46,93,46, +16,116,91,116,16,198,95,180,56,46,57,188,148,16,179,40,110,82,110,50, +230,50,231,84,128,86,213,86,102,132,241,132,138,162,97,224,198,164,241,220, +174,132,174,238,147,245,18,46,89,46,22,120,87,120,18,208,85,186,56,46, +57,194,144,14,173,42,104,88,104,54,226,54,227,90,132,76,112,124,87,162, +86,240,112,218,130,194,144,160,150,126,150,108,119,108,110,156,137,180,236,206, +230,224,220,236,192,236,180,230,174,210,174,106,214,106,214,180,197,185,12,40, +89,40,16,108,87,108,16,198,95,176,52,40,53,186,104,66,104,26,228,26, +229,66,148,54,101,104,176,56,227,102,92,136,241,136,162,240,163,90,80,216, +116,190,138,164,159,136,236,214,206,192,182,166,163,137,16,42,99,42,22,114, +95,114,14,206,95,184,58,42,59,194,84,230,104,206,114,174,116,136,116,30, +222,30,222,76,117,76,126,120,243,120,140,246,140,164,222,164,223,242,140,222, +223,222,176,164,177,85,20,44,95,44,24,112,91,112,18,206,103,182,58,44, +59,194,110,106,110,28,230,28,231,106,132,62,207,62,132,96,207,96,118,244, +118,124,216,124,217,242,118,160,217,160,118,192,217,192,118,226,217,227,10,38, +89,38,14,108,87,108,14,208,89,188,50,38,51,198,162,12,126,58,87,90, +236,84,188,58,155,22,122,82,199,82,104,242,104,116,152,116,152,238,135,242, +104,154,153,154,104,188,153,188,184,208,185,120,218,110,218,238,193,247,16,46, +93,46,18,114,89,114,20,196,95,180,56,46,57,188,226,20,164,32,105,34, +118,50,135,78,160,46,175,74,102,92,233,92,218,44,193,92,96,132,239,132, +158,100,140,152,118,190,87,224,112,238,160,220,192,192,210,162,140,162,164,194, +188,218,237,237,18,36,91,36,24,108,89,108,16,202,85,176,58,36,59,186, +108,244,108,28,152,28,152,82,109,82,108,130,151,130,108,182,159,182,162,122, +228,122,210,172,186,208,147,238,236,232,200,198,186,176,176,144,173,122,172,28, +224,28,224,84,173,85,18,36,105,36,22,108,99,108,20,204,103,180,60,36, +61,190,138,14,108,64,139,104,180,14,152,60,181,94,226,14,198,58,235,102, +116,246,116,128,226,128,227,242,116,220,227,220,142,152,205,198,196,146,143,202, +168,102,161,129,16,38,85,38,18,106,79,106,16,196,87,172,52,38,53,182, +218,18,160,28,101,32,108,52,125,76,152,46,169,72,96,116,96,92,226,92, +227,116,98,130,223,130,142,100,128,154,112,188,79,220,108,236,148,220,184,190, +202,160,126,160,146,188,184,218,237,234,210,40,183,93,10,42,93,42,14,112, +87,112,12,198,91,174,50,42,51,184,148,10,183,32,240,42,110,42,110,160, +79,232,118,106,245,106,132,76,218,76,218,138,133,138,174,162,175,58,136,242, +136,174,218,174,219,242,136,220,219,221,16,48,85,48,20,120,85,120,18,212, +85,184,54,48,55,196,90,44,241,44,128,14,128,74,196,74,197,12,222,138, +222,104,110,104,110,138,223,138,100,166,231,166,106,196,225,196,90,228,245,228, +164,228,165,75,16,42,83,42,22,110,81,110,18,208,93,186,56,42,57,196, +102,44,225,44,88,84,243,84,138,84,139,12,188,84,189,10,216,186,216,116, +110,116,110,186,217,186,110,150,217,150,162,186,163,84,140,200,89,238,178,200, +227,239,20,44,85,44,24,114,83,114,18,210,89,192,56,44,57,200,100,116, +100,30,150,30,151,116,126,50,124,96,112,128,95,144,130,120,153,136,176,118, +176,32,224,32,225,116,202,52,200,90,192,120,173,142,206,122,231,146,80,170, +243,170,150,148,114,198,227,236,94,238,126,232,154,220,180,198,197,171,12,46, +91,46,18,114,85,114,14,202,95,182,52,46,53,190,112,18,112,58,230,58, +231,20,172,58,173,8,136,74,110,118,85,146,120,244,121,102,162,76,193,98, +128,108,239,108,128,144,229,144,128,182,229,182,128,218,245,218,178,218,179,109, +12,48,97,48,14,116,93,116,16,200,95,180,54,48,55,188,216,158,216,52, +112,52,112,158,217,158,160,12,145,52,166,62,139,106,138,138,160,128,180,110, +190,86,153,86,154,108,193,138,114,182,91,228,160,170,175,198,212,178,237,218, +138,180,138,218,140,228,148,238,182,238,200,224,205,209,14,48,79,48,18,120, +75,120,16,214,75,196,48,48,49,204,92,18,117,48,78,66,143,66,100,66, +100,136,92,190,69,236,100,112,134,112,128,198,126,210,120,216,103,222,178,14, +160,60,141,94,242,52,165,52,156,92,230,92,221,118,166,130,158,188,139,242, +242,234,196,228,172,208,159,188,194,92,195,224,230,154,195,155,14,44,87,44, +18,112,85,112,20,206,89,176,50,44,51,192,144,10,171,32,102,40,227,40, +86,88,245,88,122,58,149,80,198,56,177,88,214,174,214,116,114,116,114,174, +215,174,114,142,213,142,88,202,243,202,162,248,163,175,14,40,95,40,18,108, +87,108,18,206,87,180,56,40,57,190,92,74,241,74,106,32,131,56,220,28, +201,58,148,74,149,14,182,74,183,10,126,88,147,110,104,116,229,116,200,84, +179,116,112,148,221,148,98,180,239,180,166,116,156,186,128,218,93,240,234,238, +200,222,176,200,161,181,12,44,87,44,16,114,83,114,16,212,87,190,50,44, +51,202,108,50,85,90,96,134,132,108,156,70,97,70,108,88,129,110,128,70, +129,12,128,40,161,40,172,40,230,40,208,76,182,98,163,110,176,70,237,112, +120,136,141,158,92,170,241,170,216,134,185,170,162,246,163,122,86,234,114,218, +138,194,157,170,236,232,206,210,180,186,167,171,16,42,91,42,18,118,85,118, +14,208,83,190,54,42,55,198,218,74,226,56,102,56,102,172,94,206,75,236, +154,56,155,8,154,30,223,30,116,88,199,80,152,64,152,92,154,102,166,108, +202,108,218,98,225,88,122,126,229,126,118,162,140,148,165,126,150,140,166,154, +180,176,184,198,184,218,178,232,164,236,153,238,116,196,144,178,167,156,114,228, +152,206,181,176,220,140,179,172,234,222,214,194,197,159,12,40,77,40,14,114, +75,114,12,210,77,186,48,40,49,196,140,96,140,36,94,36,94,96,141,96, +66,232,149,208,88,124,89,224,120,96,121,216,120,150,149,150,190,14,168,58, +153,82,144,138,176,118,204,86,226,50,175,50,172,72,190,104,216,126,243,142, +164,246,164,152,218,152,219,244,164,222,219,223,20,126,36,100,44,76,44,28, +108,28,108,68,45,68,110,134,110,98,52,98,52,134,111,134,164,14,189,36, +126,46,233,46,146,60,165,82,122,90,243,90,210,58,191,90,130,122,235,122, +180,148,181,90,42,162,219,162,58,194,203,194,20,228,239,228,128,228,129,162, +166,206,191,221,12,44,79,44,16,114,77,114,14,200,85,180,48,44,49,188, +106,20,89,60,156,44,97,44,84,74,159,74,126,74,127,8,88,126,104,106, +119,74,138,74,138,112,163,100,182,20,172,48,165,60,234,44,175,44,168,74, +241,74,170,120,182,106,191,74,202,74,203,10,212,74,212,102,214,112,220,116, +230,116,238,110,241,98,112,202,112,132,210,132,211,202,162,156,156,186,142,210, +114,228,89,240,170,204,233,239,20,160,20,126,232,126,233,158,74,20,40,28, +41,126,72,58,41,58,72,88,41,88,94,126,94,24,162,24,163,126,112,46, +145,46,140,100,140,70,114,70,114,100,141,100,180,26,212,26,213,126,182,58, +213,58,182,86,213,86,42,150,215,150,54,186,205,186,22,228,233,228,162,200, +193,218,128,228,129,151,116,96,116,26,44,26,44,96,117,96,44,62,117,62, +18,130,127,130,50,148,38,194,19,228,42,176,62,204,96,224,241,232,82,130, +83,216,126,172,83,172,132,48,235,48,138,92,221,92,132,134,228,134,222,174, +216,184,204,188,195,184,176,212,177,15,14,56,105,56,24,92,95,92,14,134, +96,134,96,200,79,204,56,246,57,12,210,108,210,30,134,30,134,108,211,108, +134,68,211,68,100,230,245,230,124,230,124,146,220,146,221,230,156,230,157,146, +186,230,187,147,18,46,107,46,26,92,99,92,16,136,102,136,102,178,96,190, +82,194,77,186,62,246,63,8,232,22,170,32,119,34,124,66,143,104,166,56, +181,90,224,56,195,108,156,122,128,128,129,242,192,126,228,126,229,240,158,168, +129,168,196,168,229,168,128,216,229,217,18,72,105,72,68,244,69,12,18,172, +46,126,69,78,102,138,69,100,98,46,241,46,144,46,144,146,130,196,93,234, +188,46,188,206,192,222,204,228,224,228,234,220,239,201,16,74,117,74,70,244, +71,10,18,176,48,130,71,82,116,146,71,98,160,10,136,82,117,114,148,116, +195,170,178,236,198,234,216,228,224,216,230,66,143,67,18,74,113,74,68,244, +69,12,18,170,48,122,69,78,100,142,69,102,114,42,218,42,218,116,126,116, +126,202,130,220,146,228,204,228,224,224,234,214,239,195,16,70,101,70,62,246, +63,10,18,170,42,130,63,80,100,140,63,104,150,62,175,98,98,34,218,34, +200,118,160,186,95,234,234,232,174,184,140,124,122,70,117,35,12,78,95,78, +56,244,57,16,18,176,42,134,57,84,88,146,57,104,125,54,122,52,118,138, +230,138,228,216,224,228,204,236,183,234,86,184,209,184,94,34,202,34,197,139, +18,74,101,74,66,244,67,12,18,172,48,124,67,78,100,134,67,96,242,36, +118,36,118,164,87,232,136,102,224,100,218,206,212,220,198,230,181,226,176,54, +172,142,156,196,123,241,20,76,107,76,68,244,69,12,20,172,46,132,69,90, +104,134,69,94,124,14,124,224,169,198,124,92,167,92,184,10,184,206,186,220, +202,230,222,230,234,220,241,202,234,68,185,103,18,72,105,72,66,244,67,10, +20,166,46,126,67,88,98,142,67,106,164,162,165,12,132,56,107,126,198,54, +239,116,96,238,160,208,192,172,219,137,24,54,231,54,132,116,133,8,18,134, +68,108,102,78,125,54,238,124,194,106,160,80,135,54,68,246,68,134,194,134, +195,242,68,178,195,178,68,222,195,223,14,74,105,74,60,246,61,12,14,168, +42,128,61,88,98,142,61,96,120,244,120,72,226,72,226,216,222,234,206,238, +193,232,174,14,172,88,162,136,137,174,214,172,190,134,169,105,14,72,101,72, +62,246,63,12,18,168,46,120,63,78,100,138,63,94,122,164,122,30,214,30, +215,162,166,60,162,128,148,172,122,208,87,232,178,142,178,218,182,230,194,238, +218,238,230,230,239,203,16,70,109,70,66,244,67,10,20,166,48,118,67,78, +98,132,67,96,154,10,138,62,115,108,238,60,141,60,112,142,245,142,180,244, +181,61,16,72,107,72,66,246,67,12,18,178,48,124,67,76,100,144,67,98, +104,118,241,118,136,12,136,232,179,200,214,22,165,92,236,224,198,188,176,150, +167,119,16,74,101,74,60,246,61,8,16,176,46,124,61,84,94,130,61,94, +126,18,126,136,110,194,89,236,158,174,127,126,192,16,192,112,182,166,164,206, +143,236,238,232,210,174,193,115,100,70,141,92,160,94,180,92,190,86,196,42, +62,42,62,122,224,122,218,176,212,188,202,194,189,194,112,8,99,42,28,168, +197,168,124,246,125,134,30,234,72,212,104,188,125,168,226,236,184,218,152,192, +133,169,18,72,101,72,64,242,65,12,20,170,48,124,65,86,104,142,65,102, +152,16,191,54,110,70,245,70,158,70,158,132,146,174,124,210,99,236,158,124, +226,124,222,212,216,230,200,236,181,231,16,74,109,74,64,242,65,12,18,170, +50,120,65,86,98,142,65,102,240,196,230,218,214,230,148,230,134,222,128,204, +128,34,224,34,224,126,129,126,176,126,177,35,20,72,103,72,64,244,65,10, +18,168,50,118,65,78,98,138,65,104,134,58,185,100,110,28,208,28,165,82, +104,110,234,110,217,146,170,110,170,238,137,245,28,44,229,44,128,112,129,10, +22,108,64,92,98,68,125,44,238,106,190,86,160,66,137,44,56,128,201,128, +28,166,233,166,90,188,58,216,31,236,172,188,227,236,132,166,132,222,126,234, +114,240,103,235,16,72,103,72,62,242,63,12,16,172,46,120,63,82,102,142, +63,96,94,50,245,50,138,88,139,10,190,88,191,10,108,112,224,112,220,178, +216,194,198,202,183,194,150,244,151,113,20,72,109,72,68,244,69,12,20,166, +48,122,69,76,100,126,69,98,106,38,245,38,90,176,126,132,150,80,161,38, +140,236,140,116,224,116,225,232,140,208,225,209,18,74,99,74,62,242,63,14, +16,166,44,124,63,80,100,130,63,92,116,70,243,70,190,20,221,52,150,12, +150,116,130,182,87,236,222,104,194,154,170,184,141,210,176,92,176,212,180,226, +190,232,218,232,232,222,241,203,20,74,99,74,62,242,63,12,16,168,46,124, +63,84,94,136,63,92,240,38,114,38,114,228,247,228,168,50,154,100,137,132, +134,204,176,166,198,122,204,90,157,90,232,200,191,139,22,72,103,72,66,242, +67,14,20,168,48,122,67,86,96,134,67,100,108,30,241,30,120,70,143,118, +226,66,201,120,98,156,245,156,170,242,171,31,22,70,107,70,66,246,67,14, +20,174,52,122,67,82,98,138,67,96,226,170,226,90,126,90,126,176,114,216, +95,246,126,148,227,148,168,90,169,8,168,46,245,47,18,74,101,74,64,240, +65,10,20,168,50,120,65,84,98,132,65,96,118,172,118,26,226,26,227,172, +172,242,173,26,118,88,227,88,118,152,227,153,18,70,105,70,68,242,69,12, +20,166,50,118,69,78,102,144,69,98,216,86,216,30,130,30,130,86,217,86, +110,120,245,120,148,120,142,162,222,162,216,214,210,226,196,232,165,233,18,72, +101,72,60,248,61,12,16,172,44,124,61,80,94,138,61,100,122,244,122,72, +228,72,229,244,122,216,229,216,122,140,229,140,176,216,177,13,18,72,105,72, +64,242,65,14,20,166,46,122,65,82,98,136,65,92,216,130,216,38,128,38, +128,130,217,130,148,158,122,200,93,236,188,164,239,231,18,70,105,70,66,246, +67,10,20,162,48,122,67,78,98,134,67,102,226,18,174,32,128,38,128,152, +114,194,93,236,242,92,129,92,188,246,189,92,152,132,239,191,22,74,95,74, +60,242,61,10,20,170,44,126,61,88,94,140,61,98,222,20,166,32,116,38, +116,164,108,196,89,230,240,74,117,74,182,182,198,180,210,172,214,112,148,112, +148,208,152,220,164,228,218,228,230,222,239,203,14,72,95,72,60,244,61,14, +20,166,42,128,61,86,92,138,61,104,156,14,138,54,118,84,97,110,236,110, +204,88,176,58,155,22,150,82,171,114,124,182,187,238,104,134,208,134,157,211, +20,72,103,72,68,242,69,12,20,168,46,126,69,82,102,144,69,100,152,12, +130,66,107,100,188,176,188,110,128,110,128,176,189,176,186,236,212,236,220,230, +226,216,232,56,135,57,16,72,101,72,62,242,63,12,18,172,42,134,63,84, +100,132,63,100,226,22,166,36,120,42,120,228,171,180,162,210,189,238,120,110, +239,110,240,198,238,224,232,232,222,232,212,220,192,174,178,116,177,35,20,78, +105,78,66,242,67,12,18,172,44,128,67,84,100,136,67,104,226,24,178,32, +132,36,118,124,245,124,178,68,178,236,145,242,140,158,95,212,202,156,245,213, +18,74,105,74,68,244,69,12,20,168,44,132,69,82,108,142,69,102,158,12, +187,40,122,92,122,54,230,54,231,90,148,96,148,212,152,226,164,232,220,232, +230,222,239,198,224,122,149,155,20,72,109,72,66,246,67,12,22,174,46,130, +67,84,98,122,67,94,108,34,212,34,196,68,172,94,140,118,109,140,242,130, +196,112,152,78,117,34,108,168,229,168,88,228,245,228,168,228,169,131,18,78, +99,78,66,244,67,12,18,180,44,134,67,82,102,148,67,108,114,54,191,54, +102,96,247,96,160,96,161,12,224,24,182,96,134,154,89,196,238,136,149,136, +170,136,162,180,222,180,218,208,210,226,192,236,159,237,18,74,105,74,64,242, +65,14,16,178,44,132,65,82,96,142,65,104,104,52,193,52,94,102,245,102, +154,102,155,10,224,28,176,102,130,154,87,184,136,128,136,208,140,222,160,230, +216,230,230,220,237,196,224,144,137,181,20,70,89,70,60,244,61,12,20,166, +44,124,61,80,92,130,61,98,100,36,237,36,90,222,247,222,148,222,149,36, +182,222,183,36,104,82,133,174,196,168,227,79,20,76,99,76,62,244,63,14, +16,176,44,134,63,86,94,134,63,102,108,60,233,34,220,58,162,100,115,122, +144,10,158,60,168,84,200,116,220,124,230,120,239,102,102,152,239,152,92,240, +122,224,140,200,146,178,147,152,186,152,186,218,190,228,200,234,220,234,236,226, +239,209,18,68,99,68,62,246,63,10,16,166,46,118,63,76,94,136,63,98, +98,28,239,28,161,40,192,72,229,120,160,40,110,112,217,104,108,164,225,164, +92,226,243,226,166,226,167,125,16,70,105,70,66,248,67,14,20,166,46,128, +67,80,98,140,67,102,126,186,126,88,220,88,221,184,166,88,167,12,166,46, +245,46,174,120,172,168,160,198,136,222,103,240,190,194,239,239,18,76,101,76, +62,244,63,12,18,176,44,126,61,88,96,140,63,102,102,114,237,114,164,114, +165,12,104,38,137,84,186,88,221,32,140,114,140,160,132,190,116,216,93,238, +182,114,182,212,184,224,192,230,222,230,234,222,241,201,18,66,93,66,58,242, +59,8,18,162,44,116,59,72,92,132,59,92,114,22,114,76,224,76,225,20, +166,10,167,76,102,110,218,110,218,154,118,154,118,210,120,222,134,232,220,232, +234,214,239,201,16,74,89,74,56,244,57,12,16,164,40,122,57,86,82,136, +57,104,222,32,184,44,149,48,150,108,233,108,146,180,237,180,190,180,191,42, +84,42,124,42,100,120,134,120,130,160,114,200,83,236,98,156,114,190,134,212, +174,226,241,231,22,72,99,72,64,246,65,12,22,164,46,124,65,82,102,130, +65,92,222,16,178,28,117,36,104,88,245,88,124,246,124,144,218,144,219,244, +124,216,219,216,170,144,171,39,20,70,105,70,66,242,67,14,18,170,48,124, +67,84,98,134,67,92,164,34,120,48,121,240,120,130,159,130,194,48,228,48, +229,236,120,212,229,212,190,128,229,129,18,66,91,66,60,240,61,10,18,160, +44,118,61,78,90,132,61,100,134,10,114,62,97,90,126,140,127,32,220,38, +182,72,149,92,178,10,178,114,182,124,194,128,222,128,234,116,237,96,94,174, +239,174,162,240,163,139,18,74,89,74,18,170,42,128,57,88,58,14,59,244, +84,128,59,96,140,16,120,48,105,68,142,82,116,122,87,156,122,242,123,114, +160,34,233,34,154,102,247,102,212,102,212,238,181,243,18,72,101,72,56,246, +57,12,18,172,44,122,57,84,90,136,57,96,166,12,138,66,101,110,240,102, +188,60,165,20,124,110,211,110,106,154,235,154,196,186,229,238,164,162,114,232, +215,217,74,14,52,58,29,88,36,138,80,112,106,78,114,50,57,50,58,80, +85,106,130,48,227,48,148,68,144,98,229,98,188,134,189,14,18,152,239,152, +130,242,131,120,20,222,64,204,100,178,131,154,236,216,202,202,164,182,131,153, +116,12,147,36,26,48,233,48,72,78,33,122,186,78,229,114,106,130,107,48, +158,130,159,48,24,156,237,156,130,244,131,134,30,224,90,192,131,156,230,222, +172,194,131,157,54,20,91,48,40,66,215,66,182,24,151,66,18,108,239,108, +126,16,108,82,76,126,23,156,236,156,188,136,161,108,52,160,201,160,124,240, +125,126,38,224,82,202,125,164,214,220,180,200,145,185,18,72,103,72,68,12, +69,242,20,166,48,124,69,76,100,140,69,106,158,14,191,44,122,90,122,58, +236,58,237,88,114,126,247,126,176,74,138,174,190,198,241,230,108,238,160,220, +192,184,215,127,24,74,101,74,70,242,71,10,22,170,48,130,71,82,102,138, +71,94,110,82,133,116,180,78,205,112,98,36,156,36,156,228,119,236,94,176, +157,148,172,36,230,36,230,232,197,238,174,168,231,139,18,54,113,54,134,54, +235,54,74,128,75,14,176,126,177,14,24,120,52,90,75,56,114,92,75,66, +120,118,154,88,177,58,232,110,200,86,177,58,28,238,64,220,84,188,84,148, +170,148,170,216,176,230,194,236,218,236,230,222,233,203,16,76,99,76,62,246, +63,16,14,176,44,132,63,88,96,144,63,104,134,26,122,74,111,102,226,68, +125,68,102,120,245,120,172,120,173,12,124,244,124,158,216,158,217,242,124,222, +217,223,20,78,109,78,66,244,67,14,18,180,46,134,67,90,104,136,67,98, +226,18,168,32,113,40,124,60,139,94,164,52,175,84,222,50,195,94,118,114, +216,114,180,150,180,212,178,226,162,238,147,234,102,166,247,167,16,74,95,74, +64,244,65,14,16,178,44,130,65,84,98,142,65,106,154,12,128,50,115,70, +88,240,114,202,122,164,122,86,224,86,224,238,199,244,172,222,173,86,122,126, +225,126,224,170,123,170,172,86,204,44,133,45,16,76,99,76,60,240,61,8, +18,176,40,134,61,88,94,142,61,102,152,8,181,36,108,50,233,50,128,68, +151,104,102,118,245,118,106,174,237,174,168,240,169,118,206,68,179,119,24,74, +93,74,58,246,59,14,18,164,42,124,59,90,90,136,59,100,100,32,135,58, +92,94,125,116,98,222,135,146,162,54,145,118,212,54,239,106,190,150,191,14, +228,132,202,180,170,210,129,235,18,70,95,70,62,246,63,12,18,164,46,120, +63,86,94,138,63,104,104,30,218,30,218,108,107,108,116,68,219,68,126,146, +111,182,166,122,158,188,134,218,95,238,234,236,196,208,174,176,165,140,218,150, +185,193,18,74,101,74,60,244,61,14,20,174,44,122,61,78,94,136,61,96, +118,52,199,52,104,100,245,100,164,100,165,14,228,32,182,100,132,144,85,178, +132,242,132,142,218,142,219,242,132,182,219,182,132,222,219,223,26,46,117,46, +78,116,79,12,20,114,54,84,79,50,116,86,79,62,138,46,235,46,178,118, +179,12,130,102,156,80,179,52,236,104,179,64,108,114,62,152,19,174,146,118, +192,154,237,174,72,166,180,166,176,216,168,234,154,240,141,234,36,236,74,220, +96,192,109,167,22,76,97,76,64,244,65,10,22,160,46,124,65,86,94,134, +65,104,114,42,233,42,112,78,238,78,227,118,170,78,171,8,132,102,161,122, +116,134,145,150,100,174,243,174,186,96,180,160,152,210,103,236,188,200,239,233, +24,46,135,46,82,18,40,90,129,90,32,130,125,116,86,156,87,62,218,22, +186,34,158,38,158,96,137,142,238,80,159,80,202,156,203,80,30,176,233,176, +130,156,131,244,28,236,82,210,123,176,230,230,172,204,139,177,18,74,95,74, +60,244,61,14,18,170,44,130,61,88,94,138,61,96,220,146,220,74,118,74, +118,146,221,146,118,110,221,110,162,74,163,10,162,38,237,38,94,184,249,184, +170,244,171,147,20,74,105,74,66,242,67,10,20,174,48,126,67,84,102,138, +67,94,230,90,230,30,122,30,122,90,231,90,158,90,159,30,194,90,195,30, +166,104,136,146,107,174,104,236,168,214,212,172,228,134,145,134,150,164,183,201, +18,80,89,80,56,242,57,12,20,178,40,138,57,94,84,144,57,106,220,22, +158,36,111,38,100,78,233,78,98,128,245,128,102,178,241,178,110,228,233,228, +168,228,169,34,132,178,133,78,208,178,209,79,20,72,99,72,64,244,65,8, +18,170,46,130,65,84,98,138,65,100,152,12,181,40,108,56,245,56,216,148, +216,94,126,94,126,148,217,148,138,176,101,222,204,176,237,220,172,148,172,240, +145,247,18,76,101,76,62,246,63,14,16,172,44,130,63,88,96,136,63,102, +150,16,181,38,104,52,243,52,214,118,214,82,128,82,128,118,215,118,116,146, +212,146,174,172,174,224,166,240,152,242,145,238,96,188,247,189,16,76,83,76, +54,240,55,14,18,164,38,124,55,84,80,138,55,106,82,44,118,44,94,124, +120,124,118,172,102,210,77,232,92,154,102,188,126,214,154,226,241,230,128,78, +243,78,136,46,216,46,216,110,139,110,136,144,223,144,132,178,239,178,174,212, +175,15,18,74,93,74,62,244,63,16,20,164,46,122,63,82,92,126,63,92, +108,78,243,78,110,40,214,40,214,120,113,120,104,144,127,160,162,14,162,218, +156,232,144,238,135,232,238,212,204,188,178,156,163,124,230,138,189,168,92,206, +163,167,20,72,101,72,60,246,61,12,20,170,44,128,61,82,98,140,61,100, +84,230,102,204,116,168,120,130,120,26,222,26,222,78,121,78,128,122,247,122, +140,246,140,166,226,166,227,242,140,226,227,226,182,166,183,87,14,72,79,72, +56,244,57,18,18,166,44,122,57,84,84,134,57,98,96,50,229,50,104,82, +217,82,88,110,235,110,156,16,150,74,130,120,93,158,234,162,212,152,188,132, +175,110,120,148,191,148,94,180,223,180,158,148,152,196,130,224,91,236,170,200, +227,239,20,74,93,74,64,244,65,10,22,172,48,124,65,80,96,136,65,102, +100,50,241,50,90,158,243,158,114,158,114,232,235,232,126,158,127,10,206,158, +207,10,126,86,207,86,126,122,207,122,160,178,137,212,194,178,225,209,18,72, +93,72,58,244,59,14,18,158,42,118,59,82,86,130,59,96,92,46,239,46, +100,240,100,92,224,92,224,232,199,240,160,92,161,12,130,106,147,130,122,142, +201,142,186,104,165,142,120,180,205,180,162,226,163,143,16,66,91,66,56,242, +57,10,18,164,42,122,57,78,86,134,57,96,104,48,231,48,164,102,165,10, +96,112,132,84,163,48,236,112,192,82,167,48,206,188,206,120,120,120,120,188, +207,188,120,152,207,152,96,224,237,225,16,76,95,76,60,244,61,14,16,174, +42,126,61,80,92,140,61,102,102,46,241,46,224,146,224,78,118,78,118,146, +225,146,136,98,153,122,202,98,191,124,172,242,173,12,94,222,136,188,169,146, +238,212,200,182,175,147,20,72,91,72,58,242,59,12,16,166,40,128,59,84, +90,134,59,96,110,96,111,24,146,100,147,16,196,14,178,58,165,82,242,48, +183,48,198,70,219,96,114,190,114,118,214,118,215,188,158,142,148,184,128,218, +89,236,174,172,174,220,178,230,188,236,222,236,236,220,239,201,16,70,103,70, +62,244,63,12,18,168,44,126,63,80,98,140,63,104,210,66,210,26,126,26, +126,66,211,66,94,98,243,98,94,212,245,202,208,244,209,98,126,98,127,210, +126,132,209,132,126,168,209,169,20,68,105,68,64,244,65,12,20,168,46,118, +65,72,94,126,65,90,212,96,212,30,130,30,130,96,213,96,112,238,112,130, +154,130,155,238,112,210,155,210,184,238,184,132,230,132,231,238,184,210,231,211, +58,14,40,48,27,64,114,38,47,38,22,80,125,80,78,38,78,80,72,100, +54,126,31,140,116,130,75,96,228,28,142,28,142,128,235,128,142,92,218,92, +218,64,143,64,14,166,233,166,128,240,129,140,26,228,70,210,102,188,125,166, +232,224,186,210,154,188,135,167,18,80,89,80,56,244,57,18,16,170,42,126, +57,92,88,134,57,100,154,28,114,38,89,46,120,242,121,36,90,96,149,96, +78,176,106,138,121,106,158,158,121,116,170,74,161,120,230,64,217,114,190,18, +190,132,172,192,145,232,234,230,206,182,191,133,16,78,91,78,58,244,59,14, +18,172,42,132,59,90,88,136,59,102,154,18,108,32,109,242,84,202,155,176, +146,78,109,78,142,126,109,126,236,230,196,198,178,164,166,126,222,126,204,172, +178,208,145,236,156,100,172,74,176,52,176,28,212,28,212,86,220,94,243,91, +18,78,99,78,62,244,63,14,18,178,46,126,63,84,92,150,84,130,63,104, +102,30,131,72,92,236,114,214,126,214,138,234,243,234,92,112,120,112,121,212, +158,104,220,104,220,56,158,56,158,196,224,196,224,142,159,142,186,14,173,57, +18,72,103,72,64,246,65,14,16,172,44,128,65,82,96,138,65,102,104,52, +233,52,146,16,179,40,126,74,147,102,102,116,237,116,210,70,181,116,104,156, +231,156,130,180,93,230,198,182,237,228,166,116,166,224,162,236,148,242,137,237, +20,76,93,76,60,242,61,12,18,170,44,126,61,84,94,140,61,100,114,16, +141,50,112,54,113,242,160,34,232,34,232,234,203,240,194,126,194,82,146,82, +146,126,195,126,202,198,202,156,142,156,142,198,203,199,22,78,103,78,66,244, +67,14,20,176,46,136,67,90,96,132,67,96,136,18,159,40,110,54,239,54, +208,16,183,54,118,92,225,92,112,126,237,126,168,54,160,116,132,166,91,208, +228,170,135,170,116,228,243,228,182,228,183,171,18,72,89,72,58,246,59,12, +18,162,44,120,59,82,88,128,59,92,108,28,137,68,154,16,169,62,100,86, +241,86,222,24,187,86,84,154,120,122,141,86,236,148,204,122,181,86,116,148, +207,148,90,192,235,192,162,244,163,109,16,74,85,74,58,244,59,14,16,172, +38,134,59,82,92,142,59,102,144,12,177,38,102,80,102,52,232,52,233,78, +122,88,213,88,216,192,216,120,120,120,120,192,217,192,217,192,120,156,217,156, +86,224,249,225,20,74,101,74,62,244,63,12,18,172,42,128,63,82,94,134, +63,96,84,222,106,178,116,128,116,32,230,32,230,84,117,84,174,84,175,32, +140,242,140,120,228,120,229,240,140,152,229,152,140,184,229,184,140,222,229,223, +16,72,99,72,60,242,61,10,20,160,44,122,61,80,92,120,61,92,102,24, +202,24,194,60,228,60,222,126,216,138,206,146,195,142,136,24,134,72,120,112, +93,148,146,80,188,80,172,112,141,140,152,102,187,130,84,226,245,226,112,226, +112,164,220,164,221,226,148,226,149,164,182,226,183,165,20,74,91,74,58,246, +59,14,18,170,44,124,59,84,86,132,59,104,96,40,233,40,104,72,221,72, +92,102,241,102,164,12,152,78,126,120,91,154,240,146,210,130,183,102,192,130, +162,138,129,142,104,170,231,170,166,244,167,138,98,224,132,202,167,170,230,222, +167,173,18,76,89,76,58,242,59,14,20,172,40,132,59,86,86,134,59,98, +238,34,104,34,104,226,245,226,158,204,159,50,190,204,191,52,120,80,159,80, +124,122,159,122,120,166,159,166,232,78,191,78,228,120,191,120,236,166,191,167, +20,72,105,72,66,246,67,12,20,166,48,124,67,84,92,134,67,102,222,92, +222,26,124,26,124,92,223,92,124,60,223,60,104,122,154,122,154,238,125,244, +110,150,123,168,88,208,155,178,174,124,230,124,230,238,201,246,178,146,197,166, +176,202,231,173,22,74,91,74,64,244,65,12,18,166,44,130,65,84,94,138, +65,106,166,18,193,40,142,18,116,68,93,98,124,160,125,54,132,54,239,54, +132,86,231,86,130,114,229,114,132,144,237,144,178,144,179,54,92,188,245,188, +172,244,173,161,18,78,87,78,56,240,57,14,16,162,38,122,57,84,84,124, +57,96,104,144,104,48,156,48,156,230,127,238,82,144,157,144,130,14,119,48, +104,80,157,80,103,110,104,110,157,110,78,218,120,180,143,144,174,114,191,148, +174,80,245,80,214,12,214,234,187,243,18,70,101,70,62,244,63,12,18,166, +40,124,63,80,92,134,63,98,216,96,216,38,120,38,120,96,217,96,120,66, +217,66,156,10,141,38,110,132,229,132,160,104,122,164,87,198,238,192,196,162, +175,132,116,196,209,196,162,246,163,157,20,68,95,68,64,246,65,12,20,166, +46,120,65,78,92,134,65,100,146,14,179,38,96,50,237,50,94,110,243,110, +214,140,214,78,120,78,120,140,215,140,156,148,122,186,87,212,182,216,134,236, +135,172,178,160,200,202,237,234,230,160,197,195,20,74,99,74,62,244,63,14, +20,174,46,130,63,88,94,132,63,98,148,14,181,42,102,52,243,52,210,116, +210,82,132,82,132,116,211,116,112,244,112,146,230,146,230,238,205,244,196,206, +196,174,144,174,144,206,197,207,48,16,71,38,22,52,139,52,118,14,97,52, +44,72,44,112,118,112,119,72,86,52,78,112,47,156,132,140,152,112,158,76, +158,30,216,30,216,144,193,150,158,64,217,64,216,96,155,96,24,174,229,174, +126,240,127,154,26,230,70,212,100,192,119,174,228,232,190,216,160,196,141,175, +18,78,89,78,64,246,65,12,20,172,48,128,65,88,96,136,65,102,146,14, +177,38,104,86,104,52,228,52,229,84,92,174,245,174,142,196,95,240,186,198, +237,236,204,76,164,88,128,92,129,174,128,124,229,124,188,174,189,125,16,76, +85,76,60,246,61,12,20,164,42,122,61,84,94,134,61,102,142,14,171,36, +102,84,102,52,224,52,225,82,142,70,103,110,184,72,225,106,166,96,128,138, +87,162,160,104,200,140,241,160,122,246,122,168,208,168,209,242,122,222,209,223, +20,74,95,74,60,242,61,14,20,170,42,130,61,84,86,144,61,108,94,28, +119,66,80,104,108,104,108,220,141,188,142,54,211,54,132,94,245,94,182,94, +183,12,234,42,186,104,125,154,162,242,162,134,222,134,223,236,162,174,223,174, +162,218,223,219,16,74,93,74,58,242,59,18,20,166,44,124,59,82,86,134, +59,100,82,230,102,188,106,140,106,28,228,28,228,68,107,68,136,242,136,134, +232,134,232,240,209,244,136,166,233,166,136,198,233,198,182,134,183,84,130,92, +155,116,230,90,207,121,16,78,95,78,60,244,61,14,16,174,40,132,61,90, +90,142,61,106,90,44,241,44,134,14,134,74,200,74,201,14,220,134,220,102, +110,102,110,134,221,134,102,162,231,162,108,196,223,196,86,228,241,228,166,228, +167,75,16,70,89,70,58,246,59,12,18,168,38,126,59,82,90,134,59,100, +98,46,233,46,114,68,135,90,212,62,193,92,94,108,245,108,164,108,165,10, +108,244,108,138,222,138,223,244,108,228,223,228,186,200,186,166,144,166,144,200, +187,201,20,70,87,70,58,244,59,10,18,156,42,120,59,80,88,126,59,96, +214,20,237,38,242,58,104,58,104,172,98,200,81,232,188,10,190,82,196,148, +204,190,222,228,230,232,236,224,241,206,232,94,220,142,194,198,163,236,118,134, +181,134,146,134,147,74,146,104,177,104,150,134,150,222,131,226,128,158,119,200, +168,160,183,189,22,74,87,74,60,244,61,14,18,164,42,126,61,84,94,132, +61,100,106,28,229,28,102,82,102,52,236,52,237,80,166,110,167,28,122,76, +151,76,116,100,151,100,186,74,219,74,184,98,221,98,116,128,225,128,98,156, +249,156,144,156,136,182,214,182,210,210,204,226,190,232,169,233,16,74,81,74, +52,240,53,10,18,174,40,122,53,86,82,138,53,108,106,24,139,52,218,20, +197,54,98,106,98,72,230,72,231,106,162,72,163,10,208,146,208,102,122,102, +122,146,209,146,102,186,231,186,82,224,245,224,162,224,163,161,88,26,56,56, +29,76,46,26,72,56,82,76,86,108,84,136,72,148,55,148,28,124,56,100, +83,76,118,48,197,48,102,70,239,70,162,70,163,18,226,36,164,84,107,114, +210,144,210,98,134,98,134,144,211,144,134,122,211,122,22,176,231,176,122,244, +123,156,26,234,76,210,113,176,230,230,168,204,135,177,18,78,79,78,54,246, +55,16,18,168,38,130,55,88,82,140,55,104,128,16,106,54,93,68,176,48, +197,80,182,110,203,138,72,234,94,196,100,158,100,86,164,86,164,236,143,242, +130,84,156,48,111,48,130,216,131,86,100,126,165,126,164,168,99,168,180,170, +247,158,220,246,221,15,20,74,75,74,58,240,59,14,16,162,40,124,59,82, +86,122,59,92,94,72,165,72,126,72,140,28,97,28,80,210,165,188,146,240, +147,72,104,72,105,202,104,114,147,114,104,154,147,154,198,14,186,62,161,114, +242,72,183,72,166,228,206,172,218,114,221,72,180,106,192,146,208,188,241,227, +22,72,77,72,92,62,143,62,56,246,57,12,18,162,40,124,57,84,82,130, +57,108,86,102,147,102,94,148,86,194,75,232,88,182,110,208,146,226,192,230, +243,228,116,102,117,14,118,102,119,210,118,148,147,148,212,30,235,50,234,72, +160,72,160,174,181,148,190,12,194,118,202,164,212,194,218,200,222,200,228,194, +235,174,226,94,204,154,175,201,182,14,168,54,157,76,54,56,38,82,17,96, +106,142,120,142,128,134,134,76,45,76,92,132,92,100,44,100,44,132,93,132, +22,42,147,42,70,60,71,12,110,58,111,12,242,48,171,48,154,138,182,118, +206,84,217,48,236,136,173,82,22,172,237,172,128,242,129,154,22,230,66,214, +96,192,121,172,236,228,196,216,160,192,141,173,28,36,229,36,200,80,200,56, +54,56,54,80,201,80,32,130,32,100,228,100,229,128,128,100,129,14,56,120, +205,120,20,154,60,146,96,132,117,120,190,164,190,140,72,140,72,164,191,164, +30,190,229,190,130,240,131,174,24,236,84,214,121,190,234,232,182,216,141,191, +16,72,83,72,54,246,55,14,18,164,42,116,55,82,82,132,55,96,74,230, +90,196,98,154,98,30,241,30,120,50,135,76,112,92,173,92,168,46,149,92, +172,124,173,178,124,120,124,168,173,166,146,92,146,152,140,186,113,226,204,46, +194,80,181,108,224,114,234,90,189,90,200,118,200,158,192,188,172,216,149,236, +240,226,216,198,201,165,20,72,99,72,66,244,67,14,20,174,48,120,67,80, +98,138,67,96,140,14,116,72,97,102,126,188,127,50,168,18,197,40,134,56, +239,56,136,96,227,96,136,134,229,134,134,174,247,174,180,174,181,56,128,204, +97,236,156,204,167,238,188,198,201,232,220,194,241,239,16,64,81,64,56,242, +57,10,18,160,42,110,57,70,82,132,57,88,156,10,120,52,83,82,144,50, +169,68,238,76,192,52,151,16,110,78,211,78,106,94,106,140,212,140,213,94, +128,94,191,126,184,88,154,112,127,128,94,244,94,170,224,170,224,240,201,246, +163,140,178,184,201,216,160,140,124,212,191,203,18,76,97,76,62,246,63,12, +20,178,44,134,63,92,90,126,63,100,154,12,132,38,111,54,224,120,224,66, +114,66,114,120,225,120,168,120,169,66,114,94,225,94,86,146,247,146,168,66, +192,36,135,36,120,246,120,174,214,174,215,244,120,200,213,200,120,228,215,229, +16,74,93,74,58,244,59,14,16,170,44,122,59,86,92,134,59,98,92,48, +239,48,122,16,147,38,204,14,177,48,222,160,222,74,110,74,110,160,223,160, +148,48,148,76,144,94,136,106,131,112,178,48,178,94,180,104,186,108,203,108, +110,132,223,132,86,184,243,184,116,198,143,224,202,166,202,238,167,249,18,70, +95,70,60,244,61,14,18,172,42,122,61,78,92,128,61,92,82,232,102,196, +112,152,112,28,228,28,228,60,113,60,182,74,183,122,130,78,161,90,130,124, +161,110,236,76,201,92,206,108,239,124,150,138,140,160,131,176,232,158,141,158, +120,196,247,196,184,242,185,135,22,74,91,74,64,244,65,14,22,172,46,124, +65,78,94,134,65,98,113,28,146,44,184,66,184,112,165,116,110,28,210,28, +171,58,106,66,236,66,221,92,108,110,146,90,175,66,114,242,114,130,232,130, +232,236,205,242,156,142,133,168,184,142,215,168,198,208,198,174,146,174,146,208, +199,209,14,76,75,76,50,244,51,16,16,170,36,126,51,86,78,134,51,102, +121,26,70,208,129,196,132,72,108,120,78,162,127,156,120,26,100,66,78,100, +119,100,175,14,136,98,243,98,198,98,218,40,165,40,172,16,154,68,209,68, +136,136,158,122,185,98,156,238,176,236,188,226,192,204,190,176,184,146,165,116, +130,178,156,160,179,138,128,218,162,194,189,168,232,118,187,154,238,216,216,178, +205,143,18,78,87,78,60,242,61,12,20,168,42,130,61,88,92,134,61,104, +108,26,225,26,102,88,102,58,230,58,231,88,166,130,167,26,120,88,149,88, +116,114,149,114,182,86,215,86,184,114,217,114,112,242,112,152,218,152,219,240, +112,184,219,184,112,222,219,222,166,222,167,153,18,72,95,72,60,246,61,12, +18,172,40,130,61,84,94,132,61,92,80,238,102,200,112,164,112,64,245,64, +156,12,132,36,113,48,178,64,202,34,135,34,162,74,137,96,200,76,231,96, +174,92,193,106,112,114,247,114,134,140,227,140,132,166,227,166,138,246,138,192, +222,192,223,244,138,226,223,227,18,70,91,70,58,244,59,12,18,164,40,124, +59,80,86,132,59,98,190,110,190,84,144,84,144,110,191,110,222,132,222,62, +112,62,112,132,223,132,156,10,181,30,94,38,243,38,116,156,215,156,88,182, +241,182,130,202,91,232,192,204,231,230,164,182,164,242,141,249,22,140,42,112, +50,82,50,34,118,34,118,66,51,66,114,142,114,98,58,98,58,142,115,142, +168,14,195,34,140,46,237,46,158,58,173,78,134,88,241,88,214,58,199,88, +142,122,231,122,186,152,187,88,24,172,235,172,128,242,129,150,24,234,62,218, +98,194,125,172,234,228,196,214,158,192,139,173,14,78,87,78,54,244,55,14, +16,174,36,146,55,88,82,142,55,104,146,18,177,40,104,78,104,50,232,50, +233,78,138,68,116,102,95,126,92,162,126,144,152,112,160,90,125,90,118,98, +145,122,102,116,127,142,180,72,188,108,208,136,241,156,202,128,224,92,185,92, +144,138,193,138,116,170,225,170,138,188,99,232,202,192,237,228,172,170,172,240, +147,245,40,16,63,42,14,60,145,60,114,16,87,60,36,238,36,96,124,96, +125,228,66,60,66,122,53,164,94,60,94,150,125,150,36,184,125,184,36,218, +125,218,142,92,239,92,200,30,225,58,176,12,176,118,168,172,154,210,137,240, +236,230,206,190,188,144,177,93,28,42,131,42,38,68,121,68,24,94,129,94, +80,94,81,18,30,156,52,138,62,118,69,94,80,150,92,148,108,142,112,132, +114,118,63,118,172,18,152,60,137,82,234,60,153,60,158,90,231,138,140,138, +180,118,202,90,213,60,164,150,191,164,22,176,231,176,126,152,120,186,98,210, +68,228,31,240,228,238,188,224,160,204,139,177,20,38,119,38,22,152,44,114, +58,76,67,38,24,232,62,206,90,158,100,96,51,96,50,144,85,166,122,112, +136,98,150,72,150,28,202,28,202,84,208,98,218,102,243,98,130,130,212,130, +192,174,158,210,103,236,236,236,178,204,154,172,137,131,20,34,117,34,26,144, +48,108,62,68,67,34,26,232,68,196,96,138,104,88,57,88,54,136,89,154, +104,228,243,228,138,228,138,26,214,26,215,228,138,92,215,92,138,156,213,157, +18,40,107,40,24,140,48,102,63,40,30,232,58,204,82,158,92,96,51,96, +48,138,79,164,146,14,124,56,107,82,240,50,129,50,126,82,202,82,128,138, +222,138,218,230,187,242,100,194,136,172,167,138,110,232,158,202,201,139,16,38, +113,38,20,148,46,108,61,38,28,232,58,206,90,150,96,94,51,94,50,140, +83,162,168,12,146,62,117,98,232,96,196,66,167,20,180,90,156,122,129,146, +204,128,170,168,135,194,228,166,184,212,119,243,18,34,107,34,22,140,44,106, +56,70,61,34,24,222,68,176,90,126,94,88,51,88,50,130,79,152,212,70, +212,26,130,26,130,70,213,70,120,186,120,100,218,100,219,182,170,120,170,160, +154,200,124,224,93,236,182,190,235,233,18,46,115,46,20,152,40,122,54,78, +59,46,26,236,62,198,88,150,94,96,49,96,50,142,79,164,168,18,144,68, +111,106,236,104,194,70,163,32,126,116,213,116,116,160,139,206,152,140,173,186, +100,236,239,236,214,152,175,237,16,36,103,36,60,36,48,100,21,148,20,230, +56,202,90,156,98,92,51,92,50,136,85,162,228,18,176,32,123,38,122,62, +141,94,162,54,179,84,224,50,197,96,118,112,222,112,176,146,176,238,151,246, +110,166,241,167,16,42,101,42,56,42,44,102,21,146,24,230,60,192,82,142, +88,94,47,94,46,138,77,156,118,16,149,48,222,146,222,66,118,66,118,146, +223,146,118,108,223,108,214,16,183,66,96,180,241,180,168,242,169,67,16,30, +89,30,118,24,218,24,170,72,170,202,147,208,88,226,243,226,54,30,44,94, +25,140,30,230,62,190,80,144,86,84,47,84,46,134,75,156,144,164,144,82, +112,82,112,164,145,164,190,80,226,80,216,136,191,184,192,110,235,179,18,44, +91,44,21,146,20,144,42,112,52,78,57,44,24,232,52,206,78,154,88,96, +47,96,46,140,73,164,152,14,179,38,110,86,110,56,230,56,231,88,98,174, +245,174,132,174,132,92,170,88,203,78,132,124,223,124,188,174,189,124,142,198, +91,242,182,198,231,239,16,46,85,46,110,40,241,40,20,154,42,118,52,82, +57,46,28,236,64,192,84,146,88,96,49,96,46,144,77,164,118,68,227,68, +112,124,112,98,232,98,233,122,130,124,217,124,214,186,214,152,134,152,134,186, +215,186,136,202,153,220,98,232,245,232,208,198,189,232,172,68,173,13,20,56, +119,56,76,14,34,124,115,124,24,184,121,166,82,244,83,80,144,84,133,144, +142,44,230,44,222,210,220,224,204,232,189,230,182,44,176,134,160,186,119,241, +16,54,105,54,66,14,26,126,105,126,14,192,105,166,70,244,71,80,98,234, +116,198,124,144,124,38,237,38,236,200,232,218,220,230,180,230,168,226,160,204, +160,84,214,84,214,140,210,154,198,160,185,157,16,54,113,54,72,12,30,126, +113,126,22,194,113,166,76,246,77,88,134,242,134,142,220,142,221,240,134,218, +221,218,122,74,233,74,178,142,179,13,16,60,101,60,62,14,20,132,107,132, +16,198,109,178,72,246,73,88,114,44,245,44,214,44,214,240,185,244,176,164, +176,98,132,98,132,164,177,165,16,56,115,56,72,14,20,130,111,130,20,200, +111,174,70,242,71,88,94,240,124,204,134,154,134,88,226,88,227,166,134,148, +227,148,174,88,175,10,174,46,241,47,18,54,117,54,72,12,28,128,115,128, +22,194,113,174,76,246,77,88,218,136,218,36,136,36,136,136,219,136,158,164, +117,236,192,162,237,233,14,56,115,56,68,16,30,130,111,130,20,202,117,172, +76,242,77,88,142,34,132,80,119,108,226,76,135,76,132,134,227,134,174,14, +174,140,158,182,136,216,109,238,236,234,208,208,188,170,175,135,20,54,119,54, +74,16,32,130,105,130,22,194,113,174,78,244,79,92,168,10,140,72,111,108, +164,18,196,68,237,104,180,92,154,118,135,136,200,130,168,160,139,186,228,168, +178,216,121,239,14,54,111,54,64,14,30,130,101,130,20,200,115,174,72,246, +73,86,226,22,182,36,125,44,132,68,153,110,230,64,199,114,122,136,241,136, +178,38,178,240,149,245,14,56,109,56,62,14,28,130,103,130,16,198,109,174, +72,90,73,244,224,22,182,34,134,42,124,124,239,124,178,70,178,236,147,242, +144,154,103,218,202,156,241,211,22,56,119,56,72,14,34,124,113,124,24,188, +121,172,78,246,79,84,126,32,226,32,224,94,220,108,208,116,193,114,172,32, +168,68,158,98,139,120,142,244,142,146,226,146,227,242,142,216,227,217,12,58, +95,58,114,74,235,74,66,16,26,130,95,130,120,122,169,122,18,196,107,174, +70,246,71,94,104,216,175,194,142,122,143,204,204,26,223,50,178,10,180,98, +194,184,216,228,222,230,230,224,239,205,14,62,107,62,66,16,24,132,99,132, +18,202,99,178,68,246,69,94,108,32,233,32,190,74,229,124,166,42,124,120, +217,110,128,168,219,168,96,226,243,226,168,130,169,227,12,62,109,62,56,18, +30,134,105,134,20,198,99,182,74,88,75,242,174,18,144,72,109,108,232,100, +196,72,169,28,126,112,219,112,126,170,221,170,110,230,237,230,174,230,175,113, +16,56,105,56,66,14,28,128,95,128,20,196,111,172,70,246,71,92,164,12, +140,54,117,82,126,132,166,108,194,76,212,44,147,44,148,70,178,102,208,120, +237,134,138,246,138,152,216,152,217,244,138,220,217,221,12,62,101,62,60,16, +16,132,97,132,14,194,99,172,64,244,65,86,92,34,233,34,100,208,181,168, +162,244,163,34,118,34,119,198,118,88,163,88,118,134,163,134,200,62,200,206, +202,218,210,222,224,222,234,216,241,195,30,40,111,40,16,70,109,70,142,38, +225,38,142,70,237,70,76,14,70,80,58,100,40,110,23,118,98,104,69,84, +176,14,174,46,168,84,145,110,176,70,190,92,216,110,237,118,36,138,213,138, +114,120,60,176,203,176,20,206,237,206,130,246,131,153,18,56,101,56,66,14, +28,130,99,130,20,196,101,172,70,244,71,82,118,240,118,30,224,30,224,234, +199,240,144,50,165,74,136,92,209,92,200,52,179,92,158,106,183,124,134,136, +209,136,154,136,154,184,201,185,18,58,99,58,70,16,28,128,83,128,18,188, +95,166,70,244,71,88,104,30,156,30,148,66,132,92,109,112,122,60,159,104, +182,110,208,72,218,48,222,30,177,30,180,54,229,108,108,134,148,134,144,168, +128,202,97,236,118,152,159,208,172,134,222,134,208,174,188,208,155,240,236,234, +206,208,188,182,173,135,16,56,101,56,74,14,26,132,105,132,20,198,103,172, +70,242,71,88,138,16,112,74,141,112,178,18,154,70,183,108,222,18,192,68, +227,108,122,242,122,130,222,130,223,242,122,174,223,174,122,222,223,222,172,222, +173,131,18,58,99,58,64,12,26,130,99,130,18,194,97,174,68,248,69,86, +108,42,231,42,116,74,219,74,100,106,241,106,166,10,160,76,138,120,99,150, +190,106,210,132,241,150,132,146,205,146,112,178,229,178,168,146,160,194,138,224, +109,242,222,236,161,193,14,54,99,54,68,14,20,128,99,128,14,190,97,168, +66,242,67,82,150,14,183,34,236,46,114,46,114,172,104,204,87,232,114,88, +224,88,224,132,115,132,150,132,151,60,186,132,187,60,143,148,140,148,140,236, +173,218,170,180,141,180,186,148,186,216,188,226,198,234,224,234,234,226,241,210, +232,166,187,185,12,58,103,58,60,14,30,128,101,128,16,196,101,168,70,242, +71,84,126,22,151,50,220,20,197,50,116,66,233,66,114,114,144,92,169,66, +172,128,173,12,234,116,200,94,175,66,138,120,126,160,111,184,108,240,138,210, +154,178,160,150,131,150,128,178,147,192,174,148,235,148,206,242,207,122,178,164, +174,198,241,199,26,40,227,40,202,114,202,64,50,64,50,114,203,114,12,138, +239,138,124,160,125,12,56,242,56,172,196,172,197,242,56,220,197,220,50,88, +203,89,146,20,185,46,36,80,215,60,20,134,237,112,42,224,122,196,199,142, +117,10,114,10,122,108,132,162,156,208,194,234,210,236,224,228,233,201,84,16, +54,64,21,104,76,30,106,54,129,76,84,170,98,170,108,166,112,152,112,108, +48,108,48,212,50,224,62,232,108,232,120,224,127,204,130,98,241,86,196,34, +221,64,170,14,172,102,180,168,192,204,208,230,220,238,226,238,232,232,239,208, +218,112,196,168,172,206,137,241,22,34,229,34,190,136,190,62,58,62,58,136, +191,136,58,86,191,86,58,112,191,112,16,182,237,158,154,146,177,164,101,146, +96,146,120,190,146,222,186,242,206,242,226,234,233,212,124,34,113,62,202,180, +138,220,80,232,35,235,18,52,139,52,120,154,120,90,38,90,38,154,121,154, +38,122,121,122,16,190,143,190,80,246,81,154,80,90,81,14,188,36,215,70, +134,106,237,90,216,118,198,160,174,198,133,234,162,16,164,94,174,150,190,198, +216,228,222,232,230,226,239,209,112,66,112,28,44,28,44,66,113,66,12,94, +241,94,24,216,141,184,112,244,113,94,44,94,45,210,44,128,113,128,44,164, +113,164,194,34,219,66,156,12,160,108,168,160,186,202,208,226,222,234,230,232, +241,206,212,118,188,176,164,210,141,231,14,48,143,48,8,148,147,148,34,148, +34,218,129,218,76,164,53,200,100,164,123,198,46,148,47,12,112,148,113,12, +46,80,113,80,46,114,113,114,192,30,215,60,132,96,235,80,214,114,192,164, +168,202,135,238,164,12,164,80,170,136,190,190,212,224,222,230,228,228,232,218, +239,199,120,94,120,32,38,32,38,94,121,94,38,62,121,62,46,112,23,168, +130,138,35,138,40,174,125,174,26,230,131,206,82,106,83,216,132,234,170,202, +194,164,213,124,190,30,217,68,132,108,237,92,160,14,164,108,174,176,192,214, +212,236,224,238,232,230,239,213,26,34,120,34,106,68,140,68,136,118,134,128, +122,134,115,132,56,34,54,72,40,114,19,142,66,82,100,82,86,116,59,142, +66,100,101,134,148,94,241,86,216,112,200,162,180,200,145,236,196,30,223,64, +172,12,172,102,182,172,200,216,212,232,220,236,228,234,237,210,14,228,149,212, +38,226,38,158,132,158,133,214,68,158,69,220,98,158,99,219,20,36,137,36, +14,112,133,112,144,94,241,86,26,58,43,86,130,56,111,88,62,112,63,36, +96,112,97,36,38,242,38,140,116,140,117,238,38,218,117,218,38,180,117,180, +198,34,223,64,220,116,198,166,166,208,137,236,170,14,172,104,184,180,204,228, +216,238,226,238,232,228,237,211,194,14,213,38,236,50,72,50,72,184,49,242, +32,50,32,106,73,106,16,142,73,142,38,142,34,192,19,228,166,8,170,98, +184,164,214,216,226,232,236,230,238,214,239,200,214,90,206,148,184,200,149,238, +154,92,100,92,100,206,163,206,100,130,154,130,154,162,101,162,132,206,133,162, +130,130,131,93,102,36,28,36,28,208,113,208,52,72,78,114,105,166,102,68, +80,126,49,178,120,30,231,30,146,30,128,230,169,204,158,128,177,164,236,202, +232,220,222,230,210,230,200,228,194,212,204,90,141,91,78,16,52,70,23,110, +128,84,73,32,66,84,89,108,32,130,112,130,73,202,42,172,99,230,118,34, +239,34,158,34,136,232,181,210,162,136,185,164,238,216,236,230,226,238,210,238, +202,232,208,90,153,91,46,16,69,40,14,56,107,56,32,72,49,102,8,118, +115,118,94,72,71,118,30,240,30,154,98,154,99,232,30,210,99,210,116,36, +231,36,142,36,134,230,175,202,158,126,179,166,238,198,232,220,222,232,204,232, +200,226,196,212,202,94,141,95,20,32,133,32,28,56,123,56,74,56,75,8, +114,100,114,76,36,76,36,100,115,100,20,136,123,130,48,110,61,132,100,108, +85,132,210,14,176,36,145,52,220,54,184,78,145,94,232,90,190,118,143,138, +14,156,239,156,82,156,60,238,121,226,108,204,143,226,234,206,226,226,212,234, +182,234,172,230,172,214,176,186,75,187,114,130,114,64,26,64,26,130,115,130, +42,84,57,108,98,82,83,112,72,130,73,64,32,18,57,46,108,14,75,64, +36,242,36,158,104,158,105,240,36,192,105,192,36,226,105,226,130,42,239,42, +154,42,136,230,177,206,164,130,185,168,240,212,236,226,226,236,216,236,208,230, +204,218,210,90,151,91,20,122,36,104,48,76,48,30,114,30,114,64,49,64, +114,126,114,88,56,88,56,126,115,126,136,42,233,42,164,16,187,34,154,54, +169,72,128,80,241,80,210,52,191,80,138,110,233,110,184,136,185,80,16,152, +239,152,80,152,62,232,121,224,114,198,155,218,234,208,232,220,220,232,192,232, +180,230,178,216,180,184,75,185,60,112,190,112,170,158,134,196,88,218,27,228, +126,112,127,14,220,60,127,60,84,126,106,160,130,188,160,208,200,224,235,231, +36,58,170,54,166,106,170,116,182,122,220,122,230,112,235,96,104,14,96,84, +66,118,23,136,58,244,58,146,194,146,195,242,58,186,195,186,58,222,195,223, +200,98,200,26,54,26,54,98,201,98,54,64,201,64,30,152,180,150,176,214, +178,228,188,236,224,236,232,224,237,208,108,112,100,182,76,212,21,239,30,210, +30,32,82,32,83,208,30,110,83,110,30,184,83,184,108,26,235,26,98,118, +243,118,172,238,173,27,192,94,192,26,62,26,62,94,193,94,62,58,193,58, +32,126,221,126,18,168,239,168,128,126,118,186,78,218,21,236,234,232,188,218, +158,200,127,169,198,90,198,24,62,24,62,90,199,90,62,56,199,56,50,120, +211,120,18,158,239,158,160,178,213,236,116,164,50,226,193,215,200,94,200,24, +58,24,58,94,201,94,58,60,201,60,18,136,239,136,130,238,131,110,24,216, +80,184,108,156,125,136,234,212,178,182,152,156,137,137,200,90,200,30,58,30, +58,90,201,90,58,60,201,60,230,122,46,122,46,196,25,242,138,136,128,182, +102,214,63,240,228,234,194,218,160,188,135,157,34,206,34,38,88,38,89,196, +34,102,89,102,34,174,89,174,218,20,172,32,132,36,132,146,120,194,91,232, +242,104,133,104,194,240,195,105,32,210,32,40,84,40,85,212,32,110,85,110, +32,186,85,186,148,14,126,68,105,106,140,108,173,132,116,196,199,152,176,236, +192,240,216,230,224,208,226,58,131,59,200,100,200,24,56,24,56,100,201,100, +56,62,201,62,72,140,51,186,210,140,181,178,130,118,118,172,100,204,68,224, +25,238,230,234,182,214,152,192,136,168,127,139,204,94,204,26,62,26,62,94, +205,94,62,60,205,60,88,104,58,138,29,160,132,142,110,170,87,188,170,186, +123,156,62,156,62,206,177,206,166,230,194,232,210,222,216,202,218,126,69,127, +74,14,54,54,35,82,68,66,86,94,112,114,154,126,239,132,28,142,68,124, +112,86,132,46,59,46,168,110,169,16,222,82,169,48,66,244,66,148,190,148, +191,242,66,188,191,188,66,226,191,227,200,88,200,30,56,30,56,88,201,88, +56,60,201,60,100,112,76,120,46,126,46,188,109,170,110,138,106,188,86,212, +41,236,152,242,152,118,216,118,216,184,212,194,200,204,183,201,204,98,204,30, +52,30,52,98,205,98,52,66,205,66,104,112,143,134,30,144,227,144,70,164, +113,212,14,226,243,226,190,160,145,227,60,16,117,46,30,66,90,66,90,236, +63,242,14,114,60,114,54,156,40,194,21,216,238,222,190,212,152,192,134,172, +114,144,91,94,140,84,105,122,220,168,220,36,160,36,160,168,221,168,160,102, +221,103,26,204,26,34,80,34,81,198,26,104,81,104,26,178,81,178,80,232, +102,202,118,158,118,26,210,26,210,90,119,90,154,110,154,206,158,222,172,230, +216,230,232,218,239,204,226,132,155,167,48,44,177,44,18,74,239,74,206,32, +150,74,92,100,25,118,122,16,123,74,212,118,204,132,188,138,102,138,90,136, +82,124,83,102,184,100,138,110,83,116,60,244,60,162,204,162,205,242,60,196, +205,196,60,228,205,229,208,90,208,30,66,30,66,90,209,90,66,58,209,58, +174,102,195,120,236,132,48,132,48,182,36,218,25,240,74,210,94,214,108,200, +112,164,49,164,200,152,174,196,146,222,115,238,238,210,230,226,220,230,204,228, +178,208,156,172,150,150,143,105,24,214,24,44,70,44,71,210,24,116,71,116, +24,188,71,188,132,16,110,62,89,90,116,144,117,50,222,36,178,80,137,104, +174,14,174,116,178,128,188,134,218,134,230,120,233,106,86,180,239,180,156,244, +157,141,202,94,202,28,52,28,52,94,203,94,52,60,203,60,36,116,79,144, +220,114,181,148,108,110,108,154,98,190,66,218,21,234,24,182,105,168,148,108, +148,210,154,224,170,230,220,230,232,218,235,200,218,190,149,159,204,80,204,22, +60,22,60,80,205,80,60,50,205,50,112,90,139,108,46,142,46,118,216,118, +217,140,26,162,233,162,122,134,76,194,140,206,227,234,180,162,156,200,108,226, +37,241,28,210,28,38,74,38,75,208,28,110,75,110,28,184,75,184,104,58, +104,26,226,26,227,56,94,82,237,82,158,38,108,136,229,136,92,180,243,180, +168,240,169,99,26,216,26,40,76,40,77,212,26,116,77,116,26,190,77,190, +194,16,219,36,98,50,239,50,118,244,118,90,220,90,220,238,197,246,166,232, +167,8,118,138,221,138,118,180,221,181,28,210,28,40,74,40,75,208,28,114, +75,114,28,186,75,186,162,12,126,62,91,92,234,88,188,58,157,20,150,66, +175,88,108,104,206,104,163,152,116,244,116,162,208,162,209,242,116,222,209,223, +198,80,198,24,50,24,50,80,199,80,50,52,199,52,80,90,46,124,23,140, +16,180,62,166,104,138,126,112,59,112,50,120,88,148,154,160,243,162,160,146, +161,96,222,132,161,112,62,244,62,184,192,184,193,242,62,224,193,225,30,218, +30,44,76,44,77,210,30,116,77,116,30,188,77,188,152,20,177,38,102,82, +102,52,226,52,227,80,120,90,209,90,210,196,210,124,118,124,118,196,211,196, +118,160,211,160,88,232,239,233,28,216,28,38,72,38,73,212,28,110,73,110, +28,188,73,188,98,30,146,30,134,80,110,114,93,132,100,62,129,86,172,20, +182,66,204,102,235,130,214,26,183,60,232,56,199,90,122,118,201,118,96,166, +235,166,160,118,156,178,146,200,126,220,97,240,230,240,186,202,157,179,30,204, +30,36,74,36,75,194,30,106,75,106,30,178,75,178,224,14,160,24,101,26, +114,46,137,72,156,40,169,70,100,114,100,84,230,84,231,110,216,38,181,84, +106,126,221,126,156,96,128,164,97,202,98,238,146,218,184,186,204,156,133,156, +232,232,182,214,146,182,133,161,26,214,26,44,72,44,73,210,26,114,73,114, +26,186,73,186,102,58,102,30,230,30,231,58,216,130,216,68,118,68,118,130, +217,130,118,100,217,100,152,144,179,162,96,172,241,172,146,196,93,238,188,196, +235,239,26,210,26,44,66,44,67,196,26,112,67,112,26,180,67,180,106,16, +127,44,80,56,163,56,146,116,146,84,92,84,92,116,147,116,80,144,140,144, +118,166,118,234,95,238,80,202,153,176,194,14,180,60,163,102,238,68,177,68, +168,112,186,168,206,204,233,232,140,238,182,198,202,152,211,69,26,210,26,36, +72,36,73,208,26,110,73,110,26,184,73,184,212,18,154,28,111,32,90,60, +237,60,220,128,220,86,112,86,112,128,221,128,98,156,229,156,92,184,239,184, +112,206,81,238,140,208,151,240,176,204,187,236,212,202,237,238,130,102,141,118, +198,100,181,128,166,184,167,27,32,212,32,42,76,42,77,202,32,182,77,182, +32,106,77,106,104,48,127,62,96,92,135,80,176,46,195,60,168,86,205,76, +94,26,152,26,153,100,170,26,222,26,223,104,132,104,110,144,95,162,166,106, +185,122,118,244,119,130,126,134,233,134,126,162,219,162,126,192,221,192,126,222, +241,222,172,222,173,135,24,206,24,44,62,44,63,206,24,180,63,180,24,114, +63,114,112,12,135,36,82,48,227,48,190,12,169,48,92,74,215,74,80,100, +229,100,154,100,155,48,194,116,213,128,78,146,233,146,148,118,118,126,95,126, +90,186,157,186,124,186,125,126,80,174,102,164,123,146,152,170,125,152,112,186, +106,210,140,210,136,228,128,236,102,242,91,238,172,114,178,180,196,218,216,238, +224,238,232,230,237,214,214,162,184,210,155,237,194,64,194,24,58,24,58,64, +195,64,58,44,195,44,110,70,131,78,16,86,239,86,110,126,110,104,52,104, +52,126,111,126,204,126,204,104,138,104,138,126,205,126,30,146,223,146,44,166, +209,166,16,186,241,186,96,186,97,126,158,186,159,126,22,224,78,206,109,186, +134,218,80,238,81,204,228,238,174,220,152,204,135,186,196,198,173,217,46,42, +211,42,128,68,129,8,18,90,241,90,80,110,81,62,174,110,175,60,56,202, +56,124,198,124,199,200,130,152,116,200,92,220,35,238,138,196,221,239,20,52, +237,52,118,18,118,82,184,82,185,20,60,24,60,110,217,110,62,202,62,138, +192,138,193,198,128,156,116,196,90,218,31,236,144,198,221,239,34,166,34,28, +102,28,103,162,68,68,64,152,48,196,21,228,78,174,111,206,216,114,216,24, +138,24,138,114,217,114,108,234,136,212,154,188,160,154,161,114,192,114,192,208, +196,224,212,228,228,228,236,216,241,199,36,182,36,36,106,36,107,180,70,68, +66,162,56,200,23,240,80,186,117,228,196,48,239,112,174,16,126,98,229,98, +142,242,142,142,216,142,217,240,142,216,217,217,16,46,107,46,20,90,99,72, +64,12,64,124,41,128,122,50,198,50,200,88,206,114,212,122,218,122,230,112, +237,94,116,76,169,104,154,14,154,62,142,88,122,108,99,122,64,202,64,142, +192,142,193,202,128,164,110,208,78,228,35,240,146,206,221,241,22,108,137,86, +50,36,51,102,90,14,91,94,90,50,135,50,158,10,158,88,160,100,174,104, +218,104,228,92,233,74,220,32,159,60,64,200,64,128,196,128,197,194,132,152, +118,190,98,214,35,236,148,202,225,237,30,174,30,42,92,42,93,174,60,80, +60,162,50,202,25,240,68,190,99,218,150,18,185,44,108,54,235,54,222,132, +174,192,113,238,234,234,179,186,206,86,162,146,115,182,166,62,124,116,185,117, +28,176,28,32,92,32,93,174,58,72,58,148,48,194,17,238,74,188,105,228, +106,164,124,124,132,88,132,32,212,32,212,88,133,88,184,88,204,126,237,160, +150,138,193,166,138,188,203,237,32,174,32,30,98,30,99,170,62,68,62,150, +54,188,17,236,96,206,61,164,234,32,130,32,130,156,120,198,103,234,150,78, +221,78,140,124,237,124,157,124,154,124,154,238,189,214,183,124,236,234,200,198, +184,158,181,124,226,150,197,181,38,44,221,44,66,58,95,84,24,94,229,94, +128,124,129,14,182,58,155,94,18,148,60,132,88,112,105,94,236,144,192,128, +166,112,149,94,66,202,66,142,190,142,191,198,126,156,112,200,80,224,35,240, +140,200,223,237,30,168,30,36,94,36,95,168,62,74,62,164,44,208,23,236, +70,186,103,224,110,70,237,70,192,26,217,52,118,100,137,132,166,12,166,232, +141,242,106,186,167,148,232,206,192,158,176,126,167,100,220,98,185,141,34,38, +223,38,82,50,49,92,108,90,73,62,186,50,155,90,208,90,179,62,30,138, +30,108,228,108,229,136,128,108,129,10,66,200,66,138,192,138,193,200,130,160, +118,200,90,224,39,240,144,204,221,237,34,176,34,36,96,36,97,174,66,66, +66,146,56,190,19,234,72,182,103,220,138,30,127,74,220,36,209,74,138,138, +127,180,222,140,211,180,174,16,166,70,154,92,115,120,228,116,167,74,172,110, +168,172,160,194,140,218,111,240,240,236,204,208,171,151,34,162,34,28,96,28, +97,158,64,66,64,154,48,198,21,230,76,184,109,220,196,12,217,28,112,38, +239,38,126,156,126,68,222,68,223,148,172,152,173,8,126,98,223,98,126,128, +223,128,110,176,249,176,204,154,204,240,183,246,146,194,165,213,24,220,24,118, +90,118,91,216,24,198,91,198,54,118,55,16,54,64,107,64,130,156,130,34, +214,34,215,156,174,68,168,136,156,186,130,216,97,238,182,144,182,220,186,230, +196,234,218,234,234,224,239,205,28,32,28,82,108,82,109,30,68,82,69,14, +26,112,100,112,100,158,34,158,34,230,105,192,138,152,138,30,212,30,213,148, +172,62,168,154,146,198,101,240,182,144,182,216,184,226,198,234,220,234,234,220, +235,199,20,34,117,34,18,214,121,188,70,34,71,200,40,68,32,114,17,162, +54,152,35,104,108,68,87,158,122,146,101,102,142,156,142,24,218,24,219,154, +182,60,178,144,154,196,105,236,190,144,190,216,194,226,202,232,222,232,234,220, +239,205,26,48,119,48,20,82,120,82,111,116,72,82,73,12,36,104,63,126, +28,132,55,154,18,172,129,172,82,102,76,172,58,204,21,236,110,218,73,182, +144,160,144,32,218,32,219,158,178,60,174,150,150,200,113,242,188,134,188,216, +194,232,206,236,218,236,236,222,241,199,82,10,48,56,19,86,136,72,77,20, +48,72,115,72,32,232,32,102,70,102,70,230,55,232,32,134,71,134,32,170, +71,170,96,190,97,108,124,94,124,220,101,228,156,162,156,30,220,30,221,158, +186,56,180,158,158,206,129,240,194,152,194,226,198,236,210,238,230,238,238,226, +241,209,16,48,123,48,24,74,119,74,12,100,133,100,50,100,51,16,92,100, +93,14,12,188,135,188,34,240,34,128,110,128,110,230,87,240,34,158,111,158, +72,188,73,100,148,158,148,34,220,34,221,158,182,66,180,148,164,198,129,238, +196,146,196,216,200,226,208,228,226,228,238,216,243,203,12,42,127,42,48,14, +48,68,100,68,101,12,112,126,112,94,34,94,34,126,113,126,26,154,121,154, +30,182,117,182,20,222,127,204,74,68,75,212,146,156,146,30,220,30,221,154, +178,62,176,150,160,198,119,242,190,154,190,218,194,232,200,236,220,236,236,222, +243,203,126,80,132,60,32,60,32,154,15,222,72,60,73,8,72,30,129,30, +48,94,111,82,76,70,76,106,80,114,110,116,122,108,127,98,42,222,135,200, +46,150,61,184,130,148,113,180,72,132,73,214,98,130,99,208,152,154,152,30, +220,30,221,152,186,68,180,160,162,202,129,238,198,150,198,220,202,232,208,232, +230,232,238,222,239,209,78,16,48,62,19,90,60,126,61,42,84,74,233,56, +172,18,201,40,130,14,152,78,188,116,216,124,226,122,232,114,231,96,88,112, +70,144,51,168,202,148,69,148,24,192,231,192,130,248,131,107,28,28,90,28, +90,60,38,60,38,88,92,88,90,108,84,124,70,134,41,136,210,56,210,26, +134,26,134,56,211,56,220,106,220,78,120,78,120,106,221,106,212,120,231,144, +108,138,221,132,172,134,173,56,68,150,51,186,212,174,57,174,16,210,239,210, +130,244,131,159,52,38,34,88,19,114,82,242,83,14,124,76,39,76,28,174, +121,132,148,12,148,212,154,222,164,228,218,228,232,214,237,194,230,62,149,133, +38,42,28,88,17,120,22,182,103,130,70,10,71,242,98,80,31,80,220,22, +176,34,111,42,114,98,231,92,104,158,239,148,240,198,236,214,224,228,186,228, +172,224,166,208,167,35,34,48,28,86,17,114,100,78,31,78,18,170,103,138, +68,242,69,16,122,74,243,74,132,242,132,140,220,140,221,242,132,218,221,218, +174,140,175,13,66,244,67,10,34,42,19,118,98,74,29,74,16,166,91,130, +110,30,227,30,120,72,206,72,205,122,110,122,243,122,144,122,159,30,126,242, +126,156,208,156,209,240,126,220,209,221,38,40,30,86,19,112,70,242,71,12, +98,76,33,76,22,174,93,136,114,120,241,120,140,38,126,74,117,98,226,66, +131,66,174,120,175,12,132,242,132,154,216,154,217,238,132,220,217,221,66,242, +67,12,34,40,21,116,104,78,29,78,16,166,89,130,106,116,245,116,110,46, +231,46,168,12,166,54,156,76,140,86,121,98,222,96,167,54,212,116,212,220, +210,230,196,236,179,234,176,196,176,148,120,148,120,196,177,197,34,38,15,112, +64,242,65,12,96,78,25,78,16,174,97,140,88,178,243,178,118,178,118,26, +214,26,215,178,118,66,213,66,118,104,215,104,118,142,213,142,146,198,99,240, +186,196,235,239,56,242,57,12,26,36,20,84,15,104,88,74,23,74,14,170, +77,120,88,46,124,46,100,122,126,122,116,178,100,208,81,228,84,150,110,198, +144,222,172,228,239,228,144,40,216,40,216,108,145,108,138,72,237,72,144,142, +219,142,138,174,227,174,178,210,179,13,68,244,69,16,38,40,28,92,19,116, +100,78,33,78,18,168,97,130,92,200,114,164,122,130,122,44,222,44,222,92, +123,92,150,14,181,34,126,244,126,130,228,130,228,218,224,232,208,240,197,232, +126,176,229,176,162,216,163,130,194,216,195,131,38,42,30,92,21,120,68,244, +69,12,100,82,33,82,20,166,87,132,146,12,177,38,96,48,241,48,206,112, +206,78,130,78,130,112,207,112,110,244,110,142,226,142,226,238,199,246,190,204, +190,170,144,170,144,204,191,205,76,110,77,10,22,36,117,36,36,64,115,64, +22,92,123,92,138,28,216,28,210,86,204,96,192,102,177,104,166,28,162,62, +156,86,146,102,139,106,206,122,142,130,37,132,38,160,217,160,16,186,239,186, +92,238,112,236,124,232,130,222,131,131,52,16,85,38,28,44,59,64,34,114, +79,82,126,32,99,68,198,30,237,64,208,68,164,94,128,102,101,104,160,76, +161,10,208,114,148,128,45,136,50,160,215,160,22,192,241,192,104,240,124,238, +136,234,138,224,139,129,86,20,46,28,17,32,18,82,85,82,12,140,93,140, +24,232,44,204,54,168,56,134,57,28,112,24,102,68,85,110,134,22,165,102, +98,110,146,110,142,216,121,222,80,216,94,202,104,182,110,166,115,110,230,16, +194,22,163,26,170,82,239,82,162,140,245,140,172,230,190,228,202,220,204,206, +205,21,92,24,50,36,21,40,22,90,85,90,14,140,89,140,24,236,48,202, +58,170,58,140,59,34,230,18,188,30,161,36,176,88,239,88,172,138,243,138, +174,238,194,236,200,232,201,26,130,18,112,74,91,116,170,114,123,42,108,114, +151,114,108,224,108,146,152,146,153,226,108,204,153,205,18,126,34,96,40,70, +40,32,106,32,106,66,41,66,110,126,110,94,48,94,48,126,111,126,162,10, +185,28,126,38,227,38,122,76,239,76,148,52,163,76,202,50,187,76,130,108, +227,108,176,132,177,76,216,142,144,150,31,154,52,178,207,178,16,202,241,202, +96,236,110,242,124,240,136,230,137,151,46,36,171,36,18,66,239,66,122,66, +123,12,200,24,128,76,72,96,25,108,218,102,208,114,186,118,108,118,100,112, +96,106,97,88,192,84,97,100,196,136,128,144,37,146,36,176,205,168,22,206, +217,196,234,208,228,222,218,230,136,230,124,224,122,212,123,145,104,22,68,36, +19,44,20,98,99,92,14,154,101,146,234,202,226,224,206,232,90,232,72,228, +62,212,63,38,190,38,233,80,174,14,118,70,217,66,142,90,132,122,121,144, +224,118,135,118,114,164,237,164,174,216,175,85,192,14,132,26,43,30,54,56, +201,50,26,84,227,74,224,88,220,100,208,106,132,106,124,98,122,88,123,26, +100,124,64,134,23,140,25,170,22,170,103,166,14,200,107,196,118,224,64,240, +65,134,216,124,162,136,121,142,126,168,217,162,126,196,233,194,234,216,232,230, +222,238,210,240,186,240,178,234,174,226,175,135,72,24,40,34,17,38,14,100, +77,96,12,154,75,146,240,198,232,218,212,228,70,228,54,220,50,200,51,32, +82,44,116,44,96,100,122,100,118,146,100,188,85,204,92,130,106,158,122,178, +140,190,150,196,221,196,130,70,239,70,136,40,210,40,210,100,141,100,140,130, +215,130,136,158,223,158,174,178,175,17,94,34,121,70,80,12,38,66,111,58, +16,98,119,98,78,76,54,116,21,152,98,112,139,134,92,128,66,152,39,170, +108,154,76,180,41,204,124,184,80,218,29,238,220,22,174,34,127,40,140,100, +227,94,129,158,134,158,235,152,234,206,226,222,214,228,178,228,174,222,168,210, +169,35,90,14,54,54,15,86,142,74,81,26,56,76,109,76,34,242,34,106, +72,106,72,240,57,242,34,142,73,142,34,180,73,180,100,112,101,202,126,96, +126,240,103,244,224,20,194,34,147,50,152,110,229,104,146,160,237,154,238,208, +230,226,220,234,198,234,186,230,184,206,185,37,40,30,57,48,134,26,117,46, +40,132,40,66,128,66,128,128,115,136,86,66,87,16,106,114,106,88,68,88, +68,114,107,114,178,16,164,50,151,80,238,50,165,50,170,80,202,108,233,128, +154,124,186,104,202,82,215,50,194,138,140,150,49,154,44,180,207,174,28,204, +209,198,232,214,220,228,204,232,138,232,126,228,122,220,123,151,94,26,58,36, +19,44,18,100,89,96,14,162,89,158,238,200,230,220,220,228,204,230,76,230, +64,224,56,204,57,36,156,12,132,36,113,50,220,110,220,62,114,62,114,110, +221,110,114,86,221,86,168,110,169,62,172,62,192,36,133,36,94,134,241,134, +208,206,208,158,124,158,124,206,209,206,124,184,209,185,94,24,48,38,17,44, +16,100,87,96,14,162,97,156,234,202,228,222,212,230,80,230,66,224,58,210, +59,36,128,18,153,40,102,54,231,54,202,14,177,54,110,68,131,94,220,68, +201,96,100,110,239,110,148,110,149,54,180,110,181,54,210,200,210,136,124,136, +124,200,211,200,124,168,211,169,66,100,66,22,30,22,30,100,67,100,30,74, +67,74,30,48,67,48,134,100,134,22,96,22,96,100,135,100,96,48,135,48, +96,74,135,74,54,112,34,146,17,170,44,242,45,130,82,110,101,124,52,136, +137,136,52,164,133,164,52,194,133,194,52,222,147,222,222,16,184,32,151,40, +152,100,233,92,148,156,237,148,238,202,234,222,224,230,200,230,194,224,188,206, +189,30,92,222,93,137,78,14,48,66,19,102,234,48,61,48,66,78,209,78, +236,210,230,228,222,236,212,232,202,218,192,178,190,112,41,112,100,130,92,184, +72,212,33,233,78,16,52,64,19,100,230,48,63,48,68,76,207,76,42,104, +186,104,186,166,196,206,216,230,226,232,234,224,237,210,126,242,127,122,68,122, +68,166,62,196,46,220,23,239,78,14,52,60,21,94,236,46,61,46,64,74, +211,74,40,102,194,102,194,142,198,182,204,214,214,230,224,236,230,232,237,212, +160,142,161,244,52,136,52,230,161,224,106,226,107,119,76,14,50,60,21,98, +232,46,59,46,62,76,209,76,36,106,194,106,194,188,220,236,228,236,234,226, +237,210,66,126,62,182,50,216,23,240,112,238,113,132,158,242,159,125,80,12, +50,60,21,90,72,66,209,66,226,38,65,38,40,96,194,96,194,194,202,222, +210,236,218,238,226,234,239,206,96,104,66,132,39,154,28,192,74,180,124,154, +152,130,71,130,76,142,112,166,142,178,175,184,96,190,129,202,70,216,149,237, +76,12,48,56,21,88,232,44,57,44,66,70,215,70,42,98,196,98,196,176, +202,202,210,226,220,236,232,234,241,216,34,130,173,130,40,158,63,202,162,152, +141,204,22,234,183,234,86,234,87,130,120,130,121,235,66,14,46,56,21,90, +224,38,55,38,60,64,213,64,38,92,194,92,194,178,198,198,212,226,228,234, +236,226,241,210,42,242,42,122,160,122,161,240,42,224,161,224,60,158,145,158, +102,134,96,174,86,192,67,208,142,202,99,169,70,14,44,58,23,84,234,40, +55,40,66,66,219,66,38,90,198,90,198,172,204,206,216,236,224,238,234,234, +239,214,26,126,177,126,152,186,152,156,54,156,54,186,153,186,26,240,52,234, +74,214,87,186,124,186,124,224,126,234,136,238,164,238,174,230,181,216,103,102, +100,102,101,157,70,12,46,58,21,88,226,40,57,40,64,66,211,66,40,92, +192,92,192,142,196,188,210,222,224,234,234,230,241,208,152,162,152,118,54,118, +54,162,153,162,54,142,153,142,12,234,199,234,44,234,44,188,166,188,167,234, +82,234,83,188,124,234,125,189,102,12,78,94,53,142,204,66,89,66,94,92, +98,130,110,156,138,196,174,218,207,230,166,66,160,124,144,164,116,200,78,220, +45,235,16,54,125,54,114,138,114,92,30,92,30,138,115,138,72,244,73,12, +18,214,48,184,73,146,120,198,73,148,168,12,148,80,131,118,236,70,153,70, +154,108,176,178,206,212,237,236,118,238,164,200,192,154,202,116,209,71,110,108, +110,48,40,48,40,108,111,108,40,78,111,78,74,16,57,48,62,120,91,138, +18,148,133,148,20,238,40,220,54,194,61,148,78,236,94,234,104,228,108,216, +112,180,57,180,168,18,148,86,131,124,242,78,151,78,158,110,166,152,188,196, +235,234,124,236,170,202,198,154,211,79,38,22,38,168,30,204,19,230,38,94, +101,94,82,94,83,14,38,140,82,140,83,230,112,46,239,46,116,86,230,86, +219,122,128,106,157,124,114,134,141,148,102,170,241,170,176,98,170,180,150,210, +111,236,186,194,227,232,170,84,171,7,40,22,40,172,36,194,17,232,40,90, +101,90,80,90,81,10,40,136,80,136,81,238,100,52,239,52,162,10,162,90, +204,90,205,8,124,18,124,120,235,120,104,158,243,158,166,244,167,128,102,222, +136,198,165,158,236,224,196,194,171,159,34,30,34,180,30,212,19,234,72,224, +72,136,35,136,34,94,91,94,70,94,71,16,90,240,104,206,110,154,110,40, +222,40,222,76,111,76,146,14,173,32,120,108,243,108,202,86,227,96,176,238, +177,92,130,244,130,138,224,138,224,238,207,242,130,164,225,164,130,196,225,197, +214,18,140,30,45,34,62,52,81,72,118,48,135,68,40,90,225,90,208,40, +169,90,26,126,239,126,114,90,102,140,80,176,58,198,25,222,62,236,104,228, +152,204,194,158,91,158,104,176,136,202,172,220,233,233,116,22,68,32,23,36, +30,58,43,104,60,54,71,94,102,54,91,90,14,138,107,138,86,112,86,210, +80,222,70,226,55,224,36,160,53,192,216,84,228,62,126,62,126,164,118,200, +97,240,170,62,171,10,220,36,171,36,142,102,205,98,168,76,168,120,176,134, +190,138,208,138,218,126,223,114,130,240,148,220,156,190,156,162,196,162,196,220, +200,234,208,236,220,236,230,226,233,213,20,234,38,210,48,176,52,138,52,28, +122,28,122,236,91,242,52,88,123,88,122,148,53,148,168,190,169,40,220,16, +220,234,189,243,24,236,36,206,44,162,44,32,92,32,92,234,69,240,44,92, +93,92,44,150,93,150,122,36,227,36,114,98,241,98,160,98,148,156,224,156, +220,214,214,226,204,234,173,239,20,232,36,206,44,174,44,30,98,30,98,232, +69,238,44,92,99,92,44,148,99,148,216,24,168,62,123,88,220,82,176,126, +125,156,230,140,182,192,123,231,112,16,143,36,16,50,241,50,54,50,54,92, +207,92,64,242,64,122,194,122,194,238,165,246,64,156,195,156,64,186,195,187, +18,228,32,192,40,152,40,28,82,28,82,230,63,234,40,84,83,84,40,140, +83,140,104,74,239,74,98,146,245,146,104,234,124,212,144,166,145,10,198,242, +199,13,18,232,34,194,40,156,40,28,92,28,92,226,67,234,40,84,93,84, +40,140,93,140,122,34,225,34,110,106,237,106,104,238,138,204,152,158,153,106, +192,106,192,214,196,226,204,232,226,232,236,220,239,205,16,232,32,192,38,154, +38,32,86,32,86,232,63,236,38,88,87,88,38,144,85,144,110,92,237,92, +166,14,162,110,140,178,103,238,154,190,181,226,234,232,194,182,163,103,18,240, +32,206,40,164,40,32,90,32,90,238,65,246,108,66,243,66,110,164,132,134, +154,86,175,18,198,162,239,234,186,114,126,226,225,210,40,92,91,92,40,148, +91,149,18,236,32,204,40,156,40,30,86,30,86,232,61,240,40,90,85,90, +40,142,87,142,108,54,235,54,122,84,122,158,212,158,213,82,166,10,166,212, +170,226,180,234,220,234,232,222,239,205,18,238,36,200,40,162,40,36,92,36, +92,240,69,248,128,244,128,70,230,70,230,234,203,242,178,12,178,84,168,128, +151,172,208,166,175,100,40,92,93,92,40,150,93,151,66,16,138,44,211,76, +186,8,112,56,45,80,20,100,243,100,118,70,78,130,25,178,88,242,88,132, +196,132,196,236,169,244,88,162,197,162,88,194,197,195,20,238,34,206,38,162, +38,34,92,34,92,234,63,240,38,92,93,92,38,152,93,152,154,14,132,82, +113,122,202,108,222,72,137,72,164,98,158,168,138,208,111,240,236,234,200,208, +178,174,163,127,18,230,32,204,42,154,42,32,92,32,92,224,65,232,42,144, +93,144,42,88,93,88,104,78,239,78,158,14,154,102,136,180,99,240,224,112, +198,160,166,196,143,214,178,98,178,214,180,228,192,234,226,234,238,224,243,206, +190,20,219,59,18,236,30,202,36,156,36,30,82,30,82,234,63,240,36,142, +83,142,36,88,83,88,98,54,239,54,162,16,108,130,229,130,140,164,109,228, +198,164,237,220,172,88,172,238,147,247,18,238,34,208,40,154,40,32,92,32, +92,236,69,240,40,144,93,144,40,88,93,88,110,116,243,116,164,246,165,14, +164,58,229,58,228,192,165,141,24,238,34,208,38,160,38,34,92,34,92,232, +67,238,38,148,93,148,38,92,93,92,112,244,126,218,134,172,134,90,220,90, +221,160,134,144,221,144,170,90,171,12,170,44,237,45,22,236,34,206,44,162, +44,28,98,28,98,236,71,242,44,142,99,142,44,86,99,86,130,180,130,34, +230,34,231,178,180,244,181,34,130,98,231,98,130,160,231,161,20,232,34,202, +40,154,40,32,88,32,88,238,65,242,40,144,89,144,40,86,89,86,120,186, +120,62,228,62,229,182,120,166,229,166,120,112,229,112,174,246,175,13,210,100, +210,36,40,36,40,100,211,100,40,68,211,68,124,100,125,8,52,242,52,130, +196,130,196,236,167,242,52,162,197,162,52,192,197,193,18,238,34,204,40,164, +40,34,92,34,92,236,65,244,40,154,93,154,40,94,93,94,160,18,132,78, +109,112,244,64,139,64,158,244,159,64,158,122,231,122,158,172,233,173,18,238, +32,206,38,160,38,34,84,34,84,236,59,242,38,146,85,146,38,90,85,90, +220,20,168,34,122,40,122,174,103,232,158,36,158,220,193,202,184,182,205,228, +236,226,216,180,204,140,200,82,199,27,18,232,34,194,38,154,38,32,84,32, +84,236,61,240,38,88,85,88,38,144,85,144,168,16,138,60,99,96,164,22, +196,68,239,98,178,88,148,116,113,140,202,124,170,152,127,180,222,164,170,204, +115,235,20,234,34,208,46,158,46,32,102,32,102,238,71,244,46,142,103,142, +46,88,103,88,164,10,146,52,121,90,190,176,190,108,142,108,142,176,191,176, +186,236,208,234,224,228,228,212,230,56,145,57,16,234,30,200,34,152,34,30, +88,30,88,230,61,236,34,144,89,144,34,88,89,88,218,20,168,34,124,36, +124,216,165,174,162,206,187,230,124,110,235,110,178,32,180,124,190,174,212,216, +228,228,234,224,241,203,20,236,36,194,38,158,38,30,90,30,90,234,67,242, +38,148,91,148,38,90,91,90,116,30,214,30,188,70,158,102,115,128,238,130, +179,82,118,158,229,158,108,230,241,230,172,230,173,159,18,236,30,212,38,162, +38,34,86,34,86,230,65,238,38,146,85,146,38,92,87,92,114,44,143,88, +220,38,189,92,102,114,235,114,164,114,165,12,102,240,122,222,136,196,140,172, +143,114,236,206,228,222,218,230,198,230,188,226,182,216,183,115,14,228,28,198, +36,154,36,30,82,30,82,230,63,236,36,142,83,142,36,90,83,90,116,236, +116,30,224,30,224,232,197,238,136,76,207,76,194,166,194,118,146,118,146,166, +195,167,20,228,34,198,40,160,40,26,88,26,88,230,63,236,40,140,89,140, +40,84,89,84,122,236,122,28,230,28,231,234,122,210,231,210,140,94,211,94, +178,46,176,114,164,148,145,180,174,120,211,173,16,232,32,200,38,154,38,26, +82,26,82,234,61,238,38,140,83,140,38,86,83,86,172,10,150,58,128,84, +105,108,238,98,212,80,188,52,169,18,132,110,213,110,114,154,235,154,200,186, +237,238,166,166,120,230,221,219,24,238,32,216,40,168,40,30,90,30,90,240, +67,242,40,146,91,146,40,88,91,88,124,32,176,62,229,102,212,22,166,70, +119,106,108,136,243,136,142,162,117,218,200,166,237,214,174,104,174,238,149,245, +16,236,30,210,38,166,38,34,88,34,88,236,65,240,38,152,89,152,38,96, +89,96,154,16,181,40,108,52,237,52,226,130,172,196,113,234,234,234,185,182, +210,86,166,144,119,182,172,62,126,118,187,117,18,228,32,202,40,158,40,32, +90,32,90,226,61,232,40,142,91,142,40,88,91,88,130,18,157,48,110,72, +239,72,212,16,177,72,110,140,241,140,148,72,148,148,142,190,128,216,111,236, +200,240,201,73,18,234,32,206,38,164,38,32,90,32,90,228,65,234,38,144, +91,144,38,90,91,90,130,18,161,52,118,70,233,70,218,18,181,70,114,138, +235,138,170,70,170,142,158,182,138,212,115,232,176,138,188,176,206,206,237,239, +14,230,28,200,34,160,34,30,78,30,78,234,57,238,34,144,79,144,34,88, +79,88,104,40,137,86,222,32,191,88,98,110,237,110,164,242,165,12,104,198, +134,162,165,112,234,198,196,160,165,111,16,230,28,200,36,160,36,30,82,30, +82,228,61,236,36,140,83,140,36,86,83,86,102,28,225,28,106,98,144,60, +167,28,132,72,152,92,168,114,176,146,176,198,166,220,146,232,129,236,108,148, +132,126,157,100,110,194,142,166,173,130,226,78,173,128,234,202,210,164,191,113, +18,242,32,212,38,176,38,28,82,28,82,238,59,244,38,148,83,148,38,90, +83,90,216,84,216,26,128,26,128,84,217,84,116,244,116,126,228,126,228,236, +205,242,174,84,170,134,160,166,139,196,208,190,169,147,18,238,30,210,40,164, +40,34,86,34,86,234,65,240,40,146,87,146,40,92,85,92,134,44,124,84, +107,124,154,118,125,84,216,44,202,96,187,126,238,120,207,80,116,166,227,166, +110,222,239,222,172,222,173,17,20,238,32,208,40,158,40,32,90,32,90,238, +67,242,40,146,91,146,40,92,91,92,230,20,170,30,113,32,120,60,143,94, +164,52,179,86,226,48,199,94,116,110,216,110,176,140,176,238,145,246,114,166, +239,167,18,236,32,202,38,174,38,34,84,34,84,232,63,238,38,92,85,92, +38,144,85,144,150,10,175,36,112,88,112,50,224,50,225,88,132,98,205,98, +105,138,112,136,231,136,146,136,144,182,134,210,114,230,105,240,182,136,182,216, +184,226,196,234,218,234,230,228,241,209,18,234,30,206,38,164,38,30,76,30, +76,232,57,240,38,144,77,144,38,90,77,90,100,238,110,200,114,154,114,30, +224,30,224,82,115,82,132,136,160,136,154,178,133,222,180,100,180,240,161,246, +238,218,208,180,190,146,181,124,230,122,199,159,20,236,32,212,42,164,42,34, +86,34,86,238,67,242,42,154,87,154,42,94,87,94,116,42,233,42,126,74, +223,74,110,104,243,104,130,242,130,134,220,134,220,240,197,244,130,196,221,196, +130,166,221,166,174,104,175,11,18,240,32,210,38,158,38,36,84,36,84,236, +63,240,38,146,85,146,38,92,85,92,104,52,231,52,106,110,138,82,154,56, +167,12,176,52,190,74,218,96,239,106,214,192,214,116,122,116,122,192,213,192, +168,84,168,218,172,230,182,238,214,238,230,226,237,210,122,156,213,157,24,232, +36,204,42,166,42,32,92,32,92,230,69,238,42,146,93,146,42,90,93,90, +152,238,153,14,110,62,153,62,114,120,153,120,110,176,153,176,194,238,195,14, +242,62,195,62,234,118,195,118,242,176,195,177,18,228,32,198,40,162,40,32, +84,32,84,226,57,232,40,144,85,144,40,90,85,90,144,30,120,36,120,144, +222,144,222,40,197,40,144,90,121,90,194,90,223,90,168,12,168,144,166,158, +146,198,126,218,101,236,168,152,186,182,210,214,239,237,24,238,36,206,40,166, +40,32,82,32,82,238,65,244,40,146,83,146,40,92,83,92,148,16,177,40, +116,84,116,54,226,54,227,84,126,98,215,98,110,142,235,142,140,174,109,226, +202,176,233,222,172,142,172,240,147,245,18,226,30,200,38,162,38,32,90,32, +90,228,67,234,38,148,91,148,38,90,91,90,158,10,181,34,118,78,118,48, +228,48,229,78,116,104,227,104,136,140,132,178,107,242,128,190,144,210,164,224, +190,230,241,230,174,104,175,226,228,158,175,159,18,238,32,208,36,168,36,32, +80,32,80,238,57,244,36,146,81,146,36,90,81,90,98,46,132,46,104,120, +130,120,128,166,116,212,103,240,102,152,118,192,142,218,172,228,241,232,140,78, +247,78,152,46,222,46,222,114,149,114,148,146,231,146,144,176,239,176,184,216, +185,11,16,234,28,202,36,156,36,28,78,28,78,234,55,240,36,84,79,84, +36,142,79,142,104,44,229,44,108,76,219,76,98,106,233,106,98,152,136,122, +156,74,165,10,236,158,214,144,196,126,185,106,126,146,197,146,100,182,225,182, +160,146,156,186,146,210,122,228,101,238,178,204,233,239,18,234,32,206,40,168, +40,34,82,34,82,236,65,240,40,148,83,148,40,92,83,92,102,50,243,50, +118,242,118,92,224,92,224,236,203,244,168,92,169,12,142,108,159,130,136,146, +205,146,194,106,175,146,136,182,207,182,166,232,167,147,20,238,34,204,38,162, +38,32,84,32,84,236,61,242,38,148,85,148,38,92,85,92,104,34,243,34, +118,246,118,90,230,90,231,240,158,90,173,34,118,222,231,222,154,222,155,90, +194,222,195,90,154,132,195,132,154,176,195,177,20,232,32,204,38,164,38,26, +82,26,82,230,59,236,212,102,212,26,130,26,130,102,213,102,130,62,213,62, +102,224,241,224,122,224,122,138,222,138,223,224,156,224,157,138,188,224,189,138, +38,84,83,84,38,140,83,141,22,230,36,194,44,158,44,26,86,26,86,226, +65,230,44,136,85,136,44,80,85,80,156,68,156,24,116,24,116,68,157,68, +226,66,226,22,186,22,186,66,227,66,112,100,233,100,108,134,241,134,150,134, +144,170,220,170,214,206,210,218,200,226,165,227,18,234,32,200,36,160,36,30, +78,30,78,232,57,238,36,144,79,144,36,88,79,88,164,12,132,60,97,92, +238,90,196,62,159,20,128,88,203,88,110,240,110,116,154,116,154,238,139,240, +110,188,155,188,110,156,155,156,184,204,185,120,220,106,220,234,197,239,18,238, +32,206,38,164,38,32,80,32,80,238,57,242,38,90,81,90,38,146,81,146, +102,110,235,110,102,162,128,138,150,102,158,66,163,12,110,28,133,54,206,26, +181,62,106,74,225,74,190,110,206,140,237,162,112,176,217,176,100,226,235,226, +162,226,163,135,18,230,30,200,36,148,36,24,76,24,76,226,53,232,36,136, +77,136,36,80,77,80,112,16,133,40,214,16,191,44,98,94,235,94,100,132, +136,98,150,72,160,38,167,8,100,60,229,60,188,94,204,112,239,134,98,154, +231,154,158,118,124,184,172,202,223,228,196,154,184,182,158,210,130,222,101,231, +20,230,32,204,38,160,38,32,84,32,84,232,67,234,38,142,85,142,38,88, +85,88,104,28,237,28,210,94,210,58,130,58,130,94,211,94,118,236,118,126, +228,126,228,230,203,234,140,178,207,178,170,230,171,178,200,144,177,178,144,146, +169,169,50,16,75,34,22,46,113,46,58,46,58,76,50,98,34,120,21,132, +74,124,92,122,100,116,104,102,104,78,59,78,154,12,136,48,123,64,232,40, +141,40,218,58,170,66,144,68,144,122,179,114,176,66,184,90,204,114,235,132, +226,78,197,102,64,244,64,146,194,146,194,240,167,244,64,174,195,174,64,202, +195,203,18,236,32,202,38,158,38,34,82,34,82,232,59,240,38,146,83,146, +38,92,83,92,152,14,179,36,110,82,110,50,228,50,229,82,102,170,239,170, +132,170,132,90,172,86,209,80,132,122,225,122,190,170,191,122,148,196,107,236, +188,196,233,229,18,234,30,208,36,172,36,32,78,32,78,232,57,238,36,144, +79,144,36,90,79,90,110,24,135,54,214,20,187,54,104,74,231,74,98,104, +241,104,164,10,158,76,140,114,101,154,186,104,206,130,243,152,122,154,143,172, +166,120,166,238,139,244,102,212,167,176,166,170,233,216,210,152,185,183,16,238, +28,208,34,174,34,36,78,36,78,238,55,242,34,94,79,94,34,150,79,150, +148,14,179,36,104,76,104,48,230,48,231,74,158,60,125,84,182,60,211,80, +104,102,233,102,197,118,194,120,221,156,154,108,114,150,209,140,110,186,227,186, +102,226,239,226,168,226,169,155,20,236,32,204,38,168,38,34,84,34,84,236, +59,242,38,148,85,148,38,94,85,94,152,14,179,34,108,44,239,44,136,56, +157,74,110,104,110,82,236,82,237,106,206,54,189,82,128,156,128,114,218,114, +218,138,212,152,204,156,197,150,174,164,175,82,124,242,124,178,218,178,219,244, +124,226,219,227,16,230,30,196,36,160,36,26,76,26,76,228,53,234,36,138, +77,138,36,82,77,82,88,42,167,42,92,78,159,78,126,78,127,8,162,58, +241,58,148,150,148,106,104,106,104,150,149,150,98,170,115,198,92,220,157,208, +130,212,149,164,162,104,226,104,210,162,184,202,145,238,238,232,218,206,192,164, +180,132,175,104,198,104,199,9,14,232,26,206,34,162,34,30,76,30,76,234, +55,240,34,146,77,146,34,88,77,88,94,32,243,32,104,88,104,60,230,60, +231,88,146,60,147,8,192,60,193,8,126,88,209,88,100,114,237,114,104,152, +136,138,167,114,150,128,166,146,178,168,180,188,180,214,170,228,158,234,139,236, +104,186,138,168,165,146,104,218,146,194,177,168,222,134,179,166,198,152,204,176, +220,198,241,219,16,234,30,206,36,158,36,28,82,28,82,232,59,238,36,144, +83,144,36,88,81,88,202,60,202,22,130,22,130,60,203,60,154,126,154,90, +112,90,112,126,155,126,222,126,222,90,180,90,180,126,223,126,100,162,239,162, +166,242,167,140,102,222,140,194,167,164,236,218,200,194,169,163,16,242,32,210, +38,166,38,34,82,34,82,242,61,246,100,42,245,42,154,14,175,32,226,140, +226,68,114,68,114,140,227,140,196,118,196,92,144,92,144,118,197,118,218,210, +218,162,122,162,122,210,219,210,122,186,219,186,38,92,83,92,38,144,83,144, +98,232,245,233,16,230,28,200,34,164,34,32,74,32,74,226,55,232,34,146, +75,146,34,90,75,90,154,12,177,28,240,40,108,40,108,170,100,204,89,240, +142,56,161,72,209,52,114,82,237,82,114,138,241,138,126,110,216,110,216,168, +127,168,208,52,189,82,154,240,155,82,184,240,185,82,114,226,136,200,155,170, +236,224,208,198,187,169,18,232,30,198,34,154,34,34,80,34,80,232,59,238, +34,86,81,86,34,144,81,144,118,24,147,52,220,24,199,54,104,68,243,68, +172,124,173,12,106,116,140,94,169,68,236,116,202,96,175,68,132,124,116,154, +101,174,100,236,132,210,148,178,154,148,119,148,174,148,237,148,176,168,172,194, +243,194,116,184,139,198,208,242,209,123,46,18,46,126,114,126,114,210,98,226, +84,230,69,230,118,62,47,62,14,184,93,176,164,12,152,52,123,106,206,108, +222,68,145,68,170,94,166,156,148,198,121,238,232,234,202,200,182,164,169,119, +38,18,121,66,108,14,68,50,27,72,16,98,121,98,76,72,52,118,17,156, +44,210,44,142,122,142,122,186,118,200,106,202,101,196,80,242,81,116,168,12, +160,56,143,100,212,110,230,66,157,66,176,104,176,146,166,186,142,216,119,238, +238,234,204,200,184,162,177,141,20,46,123,46,74,12,68,54,56,78,31,98, +82,66,113,96,12,116,133,116,108,116,108,234,77,242,74,192,74,150,32,150, +32,192,75,192,172,10,158,52,137,98,210,110,226,70,151,70,178,100,178,136, +170,174,152,214,127,240,236,234,208,208,188,176,177,141,124,22,86,34,25,38, +16,74,137,74,56,102,32,116,33,234,96,112,118,112,119,224,32,206,119,206, +76,206,77,36,32,160,57,160,98,158,119,158,176,12,166,54,141,106,210,108, +230,66,161,66,178,100,174,152,158,200,127,238,234,234,210,210,190,170,177,125, +62,12,85,38,26,52,125,52,46,70,63,100,16,114,131,114,104,68,83,114, +40,238,40,142,108,142,109,222,40,178,109,178,40,212,109,212,164,14,154,52, +135,96,208,108,226,66,149,66,176,102,172,156,160,194,136,222,121,238,232,236, +212,212,188,174,175,125,78,12,50,46,19,72,132,56,71,20,48,64,111,64, +114,118,114,88,38,88,38,118,115,118,18,144,64,144,64,228,37,236,24,160, +41,178,18,206,65,186,82,144,126,144,126,214,116,224,102,226,91,226,80,202, +127,180,170,14,152,80,137,114,212,100,228,70,157,70,180,100,178,152,162,204, +131,242,86,158,103,174,236,236,210,204,190,172,179,141,18,232,36,202,42,158, +42,34,124,34,124,142,132,184,144,206,168,222,206,234,224,230,234,218,239,208, +60,72,84,126,111,194,98,64,82,134,57,192,178,18,162,52,141,84,196,158, +210,154,220,142,222,58,159,58,232,168,226,184,218,190,202,192,178,192,166,188, +160,178,160,90,194,90,194,132,161,133,40,20,67,52,14,74,93,74,24,102, +41,156,14,204,91,186,80,98,53,194,74,240,98,210,112,168,112,30,210,30, +210,162,216,202,226,230,232,232,238,228,247,206,128,74,164,136,197,202,182,68, +160,146,123,211,18,234,28,208,36,166,36,32,108,32,108,138,116,186,130,210, +156,224,188,230,222,224,243,204,48,86,74,128,97,176,88,72,70,136,47,184, +128,154,239,154,172,166,147,198,198,164,225,192,150,154,150,30,210,30,211,154, +150,62,211,62,150,92,211,92,150,122,211,123,14,232,28,204,34,172,34,34, +104,34,104,148,110,186,118,208,142,224,174,234,208,232,230,224,243,206,46,86, +68,120,93,168,88,74,68,142,47,188,156,34,134,44,134,104,218,104,218,40, +197,40,158,72,135,72,198,72,219,72,126,132,216,132,184,176,143,206,152,148, +186,174,217,202,176,132,177,11,18,58,113,58,82,28,99,42,62,18,60,66, +46,92,21,112,104,102,61,68,14,156,57,156,58,124,71,138,40,120,40,176, +34,202,21,236,66,200,41,170,78,156,121,156,110,124,121,136,94,116,90,178, +82,208,69,232,112,194,93,168,104,240,122,220,136,184,138,156,138,32,212,32, +212,162,216,200,222,228,228,234,236,228,243,208,150,84,176,134,199,198,188,70, +178,140,147,215,18,226,30,198,38,156,38,30,112,30,112,168,118,194,134,216, +164,232,214,238,234,234,241,222,50,78,78,136,103,206,90,72,76,142,45,212, +152,34,139,70,228,38,213,64,184,14,182,58,176,76,160,92,137,104,236,102, +181,64,134,128,127,160,158,112,158,146,152,174,139,194,178,122,169,140,164,166, +179,186,196,138,189,160,240,130,225,156,212,114,212,150,208,174,200,190,190,202, +185,204,218,176,239,203,54,110,74,100,92,84,100,66,102,28,162,28,162,90, +166,98,178,102,198,102,213,94,66,130,178,130,146,176,110,206,47,234,84,130, +100,158,120,186,148,210,186,224,217,229,14,38,137,38,30,62,123,62,80,62, +81,12,26,108,26,84,130,84,131,108,48,108,109,108,28,130,114,130,114,158, +38,158,38,186,114,186,114,208,108,224,94,232,78,236,59,234,146,104,156,86, +160,58,160,30,206,30,206,88,210,96,220,98,239,94,138,126,218,126,202,166, +174,208,131,236,234,236,194,206,170,178,151,127,26,44,135,44,38,72,125,72, +82,72,83,12,22,122,22,100,130,100,131,120,30,134,131,134,82,114,42,172, +125,172,22,210,133,198,84,242,85,148,148,104,160,86,164,62,164,30,210,30, +210,90,214,98,220,102,239,102,144,130,218,130,204,170,184,202,152,224,127,238, +152,130,162,164,178,190,200,214,235,235,14,36,137,36,30,62,123,62,80,62, +81,12,24,108,24,86,126,86,127,108,46,108,105,108,72,108,48,134,25,148, +22,236,36,218,40,202,40,156,122,156,122,238,103,244,80,234,81,156,88,156, +102,132,51,132,40,180,123,180,40,204,123,204,148,116,160,92,162,72,162,32, +204,32,204,88,208,98,218,102,241,102,138,130,212,130,200,170,176,208,145,232, +152,130,160,154,174,182,198,208,237,237,96,132,97,16,24,46,97,46,28,78, +97,78,18,110,97,110,150,132,151,14,150,46,229,46,150,76,219,76,150,108, +233,108,114,118,135,142,18,154,229,154,230,234,178,226,126,208,94,184,71,154, +20,238,74,232,118,216,156,186,179,155,106,12,137,32,22,44,231,44,22,110, +64,104,120,86,158,62,181,44,234,102,186,98,146,92,100,72,67,44,60,118, +58,158,48,206,27,240,202,118,203,244,66,226,187,226,114,226,115,112,146,226, +147,112,76,136,115,136,80,164,115,164,80,192,115,192,184,136,147,136,178,164, +147,164,178,192,147,193,40,18,65,48,20,64,83,64,34,108,60,148,83,200, +24,228,50,190,68,138,75,64,106,240,107,52,108,18,135,50,156,34,230,34, +230,234,203,240,124,72,209,72,168,222,169,58,202,146,202,98,132,98,132,146, +203,146,145,114,144,116,153,132,186,112,181,130,126,204,169,152,208,194,169,161, +46,22,81,54,14,74,117,74,22,238,46,198,54,152,58,108,59,74,58,126, +100,126,96,214,92,224,82,232,71,234,176,18,150,80,121,114,172,30,186,58, +206,88,239,114,158,130,203,160,136,188,211,233,50,18,79,50,16,68,101,68, +54,68,54,138,48,178,36,214,27,234,54,116,92,116,90,216,84,226,74,234, +59,236,156,14,134,60,113,86,238,52,141,52,118,104,235,104,126,224,126,140, +222,140,222,196,220,208,214,216,199,220,174,246,175,69,48,20,75,52,18,74, +101,74,50,74,50,152,40,202,25,236,50,120,90,120,86,212,82,224,74,230, +61,232,156,16,136,58,119,82,238,52,141,52,210,80,158,94,119,102,118,138, +225,126,114,184,233,172,164,94,164,220,166,230,178,238,220,238,236,222,239,207, +50,18,79,46,20,66,101,66,146,12,128,56,107,92,50,66,50,144,40,192, +21,238,50,118,90,118,88,226,63,236,238,44,135,44,108,240,128,214,138,182, +138,86,210,86,210,214,208,226,194,236,181,236,166,104,181,136,108,156,241,157, +48,18,75,52,14,70,97,70,148,14,130,60,109,96,48,70,48,156,40,198, +21,234,48,116,92,116,88,202,84,218,76,224,63,228,144,86,132,118,121,142, +228,116,135,116,128,164,223,164,106,224,243,224,178,224,179,72,236,52,135,53, +50,18,79,48,16,68,95,68,52,68,52,134,46,176,23,238,52,114,90,114, +86,210,82,224,72,232,61,234,154,16,130,60,107,88,238,54,135,54,100,238, +118,212,132,166,132,90,218,90,218,130,133,130,164,148,164,218,168,228,178,234, +226,234,236,220,237,206,220,160,165,191,46,18,73,48,16,66,91,66,48,66, +48,136,40,184,21,240,48,114,86,114,80,236,59,242,146,12,126,52,109,72, +234,46,131,46,154,60,181,80,110,92,231,92,192,110,225,142,164,98,126,138, +211,130,134,156,128,204,105,240,168,156,169,238,200,154,200,222,204,232,212,236, +230,236,238,226,241,211,46,18,71,50,14,66,87,66,50,66,50,146,42,192, +21,238,50,116,86,116,84,214,80,226,72,232,57,236,108,132,243,132,142,14, +122,56,105,82,234,48,127,48,124,82,225,82,176,60,162,96,131,120,214,118, +167,90,208,132,208,220,204,230,194,238,181,238,176,202,176,162,124,162,124,202, +177,203,34,68,25,134,68,16,68,132,60,180,46,212,25,236,104,64,69,108, +114,38,196,38,116,112,226,112,220,208,212,224,202,230,179,234,194,112,180,162, +160,200,127,232,156,112,144,146,130,164,113,178,102,206,67,159,32,74,19,138, +62,14,62,146,52,190,21,232,112,58,231,58,92,74,63,106,110,198,63,148, +114,102,217,102,98,146,224,146,220,194,216,204,206,210,191,210,162,244,163,9, +28,72,21,132,89,66,60,12,60,142,50,192,19,236,98,204,59,158,88,66, +61,92,110,54,231,54,112,92,112,158,210,158,211,92,160,10,160,210,164,222, +176,230,218,230,232,216,237,201,66,18,66,146,56,194,27,238,34,70,21,132, +162,16,140,68,116,98,93,116,102,64,67,100,104,198,63,162,234,108,198,84, +174,54,161,24,174,178,190,178,200,170,200,114,130,114,130,208,132,224,146,232, +210,232,226,218,231,201,32,70,19,126,58,18,58,154,48,194,21,232,98,66, +59,114,96,204,57,164,94,40,239,40,152,40,138,98,120,136,93,164,136,240, +136,118,216,118,217,234,136,210,217,211,28,66,19,126,62,16,62,152,50,194, +23,234,92,70,63,108,118,62,141,110,60,166,97,200,222,60,197,110,228,22, +182,32,107,36,100,138,243,138,134,240,172,234,173,33,34,72,23,136,64,12, +64,158,50,200,25,238,92,80,65,114,106,198,65,156,152,16,181,46,112,60, +241,60,118,138,227,138,100,228,243,228,172,228,173,61,38,72,23,128,66,14, +66,144,56,188,27,234,102,56,67,108,107,200,106,200,67,150,156,14,187,50, +124,62,245,62,204,180,233,232,210,112,122,224,221,212,174,72,122,138,187,141, +162,36,221,84,118,16,44,80,203,72,194,146,194,104,56,104,56,146,195,146, +62,164,43,198,206,164,185,196,126,158,104,198,70,222,23,238,124,162,142,188, +174,214,235,237,30,68,19,130,58,14,58,140,50,188,25,232,86,48,59,94, +94,212,55,168,98,176,241,176,142,18,112,76,95,98,124,146,125,52,226,48, +192,76,147,106,180,18,180,120,184,134,196,138,222,138,232,126,237,110,164,242, +165,149,28,72,19,130,62,12,62,164,52,206,27,240,92,56,63,106,96,218, +63,170,130,18,159,52,116,64,239,64,214,12,187,64,118,120,227,120,104,172, +245,172,172,244,173,65,32,66,19,126,56,14,56,146,44,200,25,234,86,54, +57,98,88,204,55,162,100,30,227,30,88,124,245,124,110,74,204,74,205,124, +148,30,137,124,122,242,122,160,210,160,211,240,122,220,211,221,32,70,19,128, +60,18,60,146,48,194,27,236,90,50,61,90,94,204,57,160,162,12,132,66, +93,110,156,24,182,60,239,104,146,78,173,98,112,116,202,116,171,166,216,242, +216,166,118,166,119,242,118,222,217,223,30,78,19,136,60,12,60,146,50,196, +29,236,84,60,61,100,90,204,59,158,110,242,111,60,108,24,139,54,152,36, +228,36,228,236,199,244,138,126,131,174,190,126,207,170,160,76,183,96,160,114, +160,190,162,200,180,202,188,200,195,189,34,72,21,126,64,16,64,142,48,198, +25,236,92,60,65,106,90,214,57,170,112,196,241,196,214,158,214,80,118,80, +118,158,215,158,118,118,215,118,168,246,169,158,164,80,165,10,164,46,229,47, +66,30,47,74,124,8,122,42,116,68,100,86,84,98,58,108,27,118,228,120, +176,100,148,78,132,58,123,42,200,30,157,84,40,150,33,186,72,124,68,178, +54,210,21,238,100,212,67,182,104,140,69,168,138,148,125,184,168,122,166,164, +158,196,138,222,117,240,230,240,204,220,182,192,167,160,216,152,187,197,32,64, +19,120,56,12,56,146,46,192,23,226,84,48,57,102,78,198,55,158,92,78, +161,78,102,212,102,130,148,130,149,212,102,194,149,194,126,130,127,10,154,236, +168,214,182,166,182,28,228,28,228,238,203,242,182,92,229,92,182,156,229,157, +34,68,21,126,60,16,60,146,48,192,23,238,94,66,61,106,100,194,59,156, +222,100,222,26,120,26,120,100,223,100,120,66,223,66,146,120,179,140,102,150, +237,150,84,228,245,228,130,172,155,210,206,172,179,229,30,66,21,124,58,14, +58,150,52,190,29,234,94,56,59,116,100,204,59,152,216,108,216,28,122,28, +122,108,217,108,122,68,217,68,168,108,169,28,98,138,241,138,130,138,130,234, +173,208,238,232,208,212,176,174,167,138,222,158,191,191,56,14,56,132,46,182, +21,230,30,70,19,128,82,56,57,94,86,174,55,138,108,244,108,30,153,18, +92,202,151,174,108,78,147,78,108,128,141,128,158,102,174,82,178,62,178,28, +216,28,216,94,241,98,162,126,224,126,212,166,184,208,149,236,240,234,210,212, +188,184,176,156,169,127,72,20,44,72,21,102,54,148,55,56,204,66,204,28, +104,28,104,66,205,66,78,98,235,98,154,144,155,66,128,150,118,186,98,212, +74,224,48,234,23,238,76,166,53,200,80,144,118,126,153,98,226,148,155,98, +230,238,194,228,162,208,125,168,200,164,177,191,58,18,58,150,50,192,27,234, +30,78,21,130,84,66,59,104,146,20,179,42,108,90,108,56,230,56,231,88, +128,90,209,90,212,196,212,124,122,124,122,196,213,196,122,158,213,158,96,198, +57,160,90,232,243,233,58,16,58,150,52,186,36,216,21,232,34,70,21,124, +92,68,59,116,86,190,57,156,80,228,96,204,108,172,114,142,114,46,222,46, +222,90,115,90,144,12,179,34,126,242,126,126,230,126,230,236,207,242,126,170, +231,170,158,216,159,126,192,216,193,127,28,74,19,128,52,16,52,154,40,200, +21,234,86,70,53,108,90,36,119,70,84,192,51,162,78,232,98,212,112,212, +124,234,239,234,76,116,106,116,107,212,190,178,146,198,146,30,220,30,220,110, +147,110,146,70,221,70,176,132,239,194,232,124,205,159,28,70,21,126,56,16, +56,142,46,194,23,232,88,66,57,112,94,200,55,158,154,26,112,38,112,110, +159,82,146,62,167,94,170,36,230,36,228,98,226,108,218,114,201,116,166,120, +182,100,190,70,191,36,120,242,120,140,222,140,223,240,120,180,223,180,120,218, +223,218,172,218,173,141,28,66,21,130,56,14,56,148,40,196,19,234,92,64, +57,102,92,194,53,160,208,80,208,24,116,24,116,80,209,80,116,52,209,52, +224,142,224,106,102,106,102,142,225,142,142,142,143,106,184,142,185,106,110,168, +208,168,176,204,138,224,91,236,128,168,146,196,196,224,237,237,20,128,33,70, +56,16,56,146,44,194,21,234,94,70,57,104,88,196,53,162,142,14,171,34, +99,46,102,46,235,46,130,62,147,84,110,242,110,96,226,96,226,236,199,242, +152,116,129,138,180,118,209,142,194,202,194,158,142,158,142,202,195,202,202,60, +179,97,18,142,32,112,36,84,36,26,126,26,126,48,37,48,62,72,123,72, +56,98,133,98,94,98,94,136,90,142,82,144,75,144,70,116,51,140,118,118, +137,132,146,60,243,60,154,82,175,102,202,12,202,132,190,140,169,140,68,164, +53,194,204,162,173,186,124,148,118,184,100,206,66,226,25,238,236,232,198,224, +166,210,142,188,123,161,32,68,25,122,58,16,58,138,48,184,23,230,94,64, +59,104,98,194,57,152,98,32,156,32,155,104,112,52,133,72,98,110,155,82, +176,32,230,32,231,116,182,52,201,68,178,100,231,78,122,242,122,142,214,142, +215,242,122,182,215,182,122,222,213,222,170,120,159,143,28,70,21,130,56,14, +56,152,44,200,19,234,90,62,57,98,84,198,55,164,112,156,112,46,222,46, +223,156,156,10,143,46,130,100,203,100,134,66,147,80,198,66,189,80,131,142, +133,140,166,142,167,66,134,138,167,100,198,136,183,118,102,180,239,180,162,160, +156,198,134,220,87,240,230,236,198,222,174,200,163,181,54,12,54,146,44,188, +19,230,28,74,19,126,90,62,55,92,220,18,176,26,103,32,96,84,233,84, +164,138,165,42,122,54,137,72,210,46,185,84,90,190,55,152,112,244,112,156, +212,156,213,242,112,224,213,224,112,190,213,190,164,224,165,156,84,136,122,118, +165,84,234,134,196,112,165,85,24,74,17,122,52,12,52,160,46,192,32,218, +19,240,76,68,53,98,88,42,109,76,82,196,51,166,80,230,98,214,112,214, +126,234,239,234,76,116,106,116,107,214,138,16,159,44,122,60,237,60,210,16, +183,60,124,98,179,60,156,76,172,96,182,118,188,140,188,170,184,188,176,198, +153,202,126,136,175,104,128,176,160,154,185,132,224,88,183,118,228,164,187,135, +22,32,115,32,137,32,136,32,227,32,26,70,62,48,79,32,56,52,74,68, +84,90,86,112,82,128,72,136,60,138,57,138,26,102,50,88,71,68,30,130, +62,108,83,88,110,62,83,84,110,110,87,82,138,68,168,46,185,32,162,50, +180,70,188,92,188,118,180,134,163,138,136,96,160,80,177,66,136,122,166,106, +187,88,218,58,185,80,226,116,197,74,74,160,53,196,200,150,175,186,124,142, +114,186,88,210,58,226,25,236,226,236,194,224,156,204,134,180,123,159,52,14, +52,152,44,192,21,234,24,66,15,126,84,60,53,110,82,196,51,162,220,16, +146,28,93,30,108,46,125,64,152,42,167,60,224,110,224,76,104,76,104,110, +225,110,142,110,143,76,184,110,185,76,138,204,163,228,146,214,104,234,104,138, +156,138,156,186,105,186,104,162,157,162,178,158,245,158,216,130,216,238,193,242, +182,178,195,198,214,36,189,77,24,110,24,92,228,92,229,112,90,92,90,4, +166,4,167,92,108,22,141,22,108,46,140,46,140,70,108,70,109,46,32,92, +32,20,69,14,64,44,33,44,62,66,33,66,222,92,222,14,189,14,192,44, +223,44,194,64,223,64,40,118,109,118,134,118,211,118,78,150,79,110,170,150, +171,110,14,168,239,168,44,146,79,118,106,148,79,118,136,146,171,118,216,146, +171,118,92,160,56,192,19,210,160,168,198,196,237,214,96,192,73,212,130,182, +116,212,96,226,66,236,45,242,118,210,207,238,168,198,151,221,58,176,27,234, +94,184,109,230,148,180,165,224,198,178,231,233,34,42,223,42,54,72,209,72, +24,104,239,104,122,10,108,78,76,134,29,178,90,134,229,134,180,112,180,178, +174,184,151,186,106,152,125,172,56,196,27,240,94,202,105,238,146,202,163,236, +196,196,233,237,94,158,94,34,38,34,38,158,95,158,148,14,128,56,109,88, +178,166,198,162,212,154,218,132,222,50,133,50,178,138,178,86,134,86,134,138, +179,138,56,192,27,238,96,194,111,236,144,190,167,230,37,98,38,96,95,96, +202,186,233,235,22,38,231,38,40,64,213,64,126,64,127,14,192,112,192,88, +58,88,58,112,193,112,14,138,237,138,86,118,99,138,164,120,149,138,192,188, +192,162,56,162,56,188,193,188,54,204,27,238,94,206,107,234,144,204,159,234, +192,202,219,237,114,10,149,32,22,234,40,204,50,156,52,130,52,46,216,46, +216,88,53,88,178,104,207,130,68,146,239,146,142,102,138,156,122,190,94,220, +61,238,150,146,166,182,200,218,235,235,118,16,155,38,20,232,36,204,48,166, +48,52,216,52,216,94,49,94,114,114,157,140,86,144,137,170,66,196,245,188, +186,246,187,111,118,16,155,36,26,232,46,210,60,170,60,48,216,48,216,90, +61,90,94,240,94,124,224,124,224,232,197,240,182,202,182,158,130,158,130,202, +183,203,114,14,149,34,22,238,46,190,52,142,52,44,210,44,210,74,53,74, +198,128,198,100,92,100,92,128,199,128,236,202,230,220,212,232,106,232,90,228, +80,212,80,154,212,154,212,190,81,190,146,190,147,155,112,16,147,36,22,236, +44,200,50,160,50,46,216,46,216,88,51,88,128,244,129,102,168,244,169,102, +70,132,129,132,74,166,129,166,64,206,129,206,168,132,233,132,168,166,227,166, +168,206,243,207,56,16,97,50,28,72,110,72,92,108,62,138,23,166,82,242, +83,118,126,164,83,137,52,10,85,48,18,68,94,68,76,100,50,134,19,154, +66,242,67,114,112,152,69,110,238,198,232,218,212,232,160,232,144,228,132,210, +132,38,218,38,218,118,133,119,48,16,79,46,16,70,86,70,70,102,50,130, +19,158,64,244,65,112,102,152,65,120,108,38,229,38,100,112,239,112,168,38, +168,118,154,170,132,204,101,234,234,234,208,202,184,164,169,121,46,18,89,52, +16,82,90,82,72,116,50,138,19,160,64,242,65,124,104,156,65,134,92,224, +243,224,126,224,127,68,178,224,179,12,178,96,231,97,40,18,75,54,12,80, +74,80,64,106,46,132,17,160,58,244,59,118,94,160,59,128,102,68,223,68, +96,132,237,132,160,132,161,12,182,168,229,236,160,140,100,230,215,219,44,16, +81,48,20,76,86,76,70,112,48,136,21,158,62,244,63,120,102,156,63,126, +110,70,247,70,126,242,126,144,224,144,225,240,126,214,225,214,174,144,175,11, +44,18,75,46,14,68,86,68,70,100,48,128,21,156,62,240,63,110,98,150, +63,120,114,68,239,68,184,22,215,50,160,14,148,100,126,164,97,210,236,228, +200,206,164,166,143,118,112,234,152,212,190,170,214,114,145,115,48,18,83,44, +12,70,96,70,76,102,50,132,19,156,68,242,69,112,108,156,69,122,158,16, +142,56,113,110,244,66,139,66,162,240,163,66,162,122,233,122,162,172,237,173, +42,18,79,50,18,78,82,78,64,112,44,138,17,160,56,242,57,122,98,152, +63,116,150,16,136,52,109,108,214,98,228,62,133,62,170,94,170,236,137,240, +140,136,99,200,196,138,239,197,46,16,75,48,16,72,80,72,70,108,44,140, +25,156,58,240,59,124,96,156,61,122,220,20,166,34,118,40,118,220,165,188, +118,108,235,108,176,32,176,90,182,156,196,200,210,226,224,232,234,226,241,202, +168,216,183,239,48,16,83,52,18,80,88,80,54,132,21,158,66,242,67,116, +98,156,67,124,112,34,224,34,224,232,195,240,116,78,201,78,182,180,182,120, +124,120,124,180,183,181,54,18,89,50,20,78,86,78,58,124,21,158,68,246, +69,110,100,150,69,118,124,196,124,92,218,92,219,190,162,92,163,12,162,48, +243,48,170,122,166,176,148,210,126,226,97,240,184,192,239,241,48,16,77,44, +16,66,86,66,66,108,48,132,21,156,62,242,63,112,100,142,63,116,112,56, +127,88,234,56,213,104,148,18,148,160,136,204,103,238,106,178,149,140,184,18, +184,218,190,228,202,232,226,232,234,226,239,204,236,174,185,127,96,54,233,54, +92,172,243,172,150,188,91,238,186,188,239,236,128,172,129,12,198,172,199,10, +128,90,199,90,128,128,199,128,38,16,73,52,18,80,78,80,62,116,46,136, +19,160,58,244,59,120,98,152,63,117,46,16,77,50,16,74,82,74,54,122, +19,158,64,246,65,104,96,142,65,114,116,12,145,48,218,148,218,66,116,66, +116,148,219,148,116,108,219,108,202,10,165,66,164,246,165,66,90,186,245,187, +40,20,75,40,14,70,78,70,66,106,42,136,21,158,56,244,57,120,92,154, +59,116,126,138,127,14,94,44,159,44,100,74,155,74,94,106,161,106,168,42, +224,42,220,122,214,130,199,134,168,130,186,82,191,42,96,168,233,168,162,142, +158,180,138,210,101,236,232,236,204,220,180,200,161,169,46,18,79,44,14,68, +86,68,72,98,46,130,23,156,62,242,63,112,96,148,63,120,130,20,155,50, +110,66,237,66,214,20,187,66,118,114,225,114,104,164,239,164,172,164,173,66, +130,188,101,236,154,190,161,236,184,188,195,232,214,184,239,237,40,14,77,52, +18,72,84,72,72,102,50,132,21,158,60,242,61,118,92,142,65,116,100,40, +239,40,112,70,229,70,166,70,167,8,218,124,218,94,118,94,118,124,219,124, +94,156,243,156,136,134,151,156,196,134,183,156,118,242,118,184,218,184,219,240, +118,222,219,223,42,18,73,42,16,70,80,70,68,100,46,132,23,158,62,244, +63,110,94,136,63,110,146,12,179,32,96,42,241,42,158,90,158,64,114,64, +114,90,159,90,224,90,224,64,180,64,180,90,225,90,102,118,235,118,112,142, +227,142,94,168,243,168,144,168,145,100,190,168,191,100,90,212,126,194,157,168, +176,212,136,234,137,184,180,178,202,210,237,234,224,180,199,203,24,40,231,40, +122,136,123,40,198,110,123,70,52,164,25,222,114,148,147,180,190,164,235,208, +88,162,88,216,90,228,100,234,158,234,176,222,181,201,26,110,237,110,124,110, +125,10,124,50,203,50,52,154,25,218,120,136,153,174,198,154,231,210,88,148, +88,208,92,222,106,230,166,230,188,216,193,197,22,30,102,30,94,68,68,108, +21,142,36,58,74,94,115,134,118,46,237,46,126,78,157,108,200,10,200,122, +196,136,186,142,165,142,50,168,25,224,116,154,145,186,198,168,231,214,88,166, +88,212,92,226,106,230,156,230,178,214,185,197,18,50,121,50,26,82,115,82, +14,114,127,114,72,154,73,14,134,38,214,38,214,126,210,144,200,152,183,154, +164,38,164,70,152,116,127,150,50,180,25,230,120,168,143,198,198,182,233,218, +82,172,82,216,86,228,100,236,162,236,178,222,181,207,46,44,207,44,28,76, +225,76,126,76,127,12,40,114,209,114,22,150,235,150,126,96,127,150,54,182, +25,226,118,166,151,196,200,176,233,220,88,172,88,216,90,226,102,234,166,234, +184,222,189,209,16,24,241,24,52,144,52,64,208,64,208,134,200,142,181,144, +102,132,103,64,154,132,155,64,106,64,123,24,52,170,23,222,118,152,147,182, +196,168,233,212,84,164,84,214,88,226,98,232,162,232,178,220,183,201,76,16, +48,58,19,84,58,142,59,42,54,172,29,222,214,20,148,34,99,36,86,78, +243,78,96,126,225,126,158,126,159,32,118,148,149,180,200,164,235,214,84,166, +84,210,86,224,100,232,164,232,182,220,189,197,52,176,21,230,126,164,149,192, +198,172,235,222,90,166,90,220,92,232,104,240,164,240,178,224,183,204,20,142, +235,142,48,100,209,100,32,58,227,58,74,20,101,44,180,16,151,58,130,58, +131,143,58,168,27,220,122,148,149,178,194,166,231,212,96,166,96,208,100,222, +112,228,162,228,180,216,187,196,36,28,77,56,30,140,79,92,138,16,122,44, +99,76,206,88,222,54,115,54,158,54,152,84,136,110,116,126,93,140,226,146, +200,128,176,104,157,73,34,38,225,38,48,70,205,70,126,70,127,8,30,132, +30,98,224,98,225,132,28,170,58,166,78,156,86,146,86,128,162,128,162,154, +164,164,174,166,206,166,223,150,56,188,27,230,114,166,137,198,198,188,229,228, +88,182,88,220,92,228,106,234,158,234,168,224,177,207,66,16,27,62,76,58, +48,94,19,120,52,160,53,88,104,28,139,50,98,70,131,86,94,144,147,108, +162,34,227,34,158,80,237,80,202,80,202,146,188,152,171,148,50,186,21,226, +120,160,149,190,196,176,235,216,86,176,86,212,90,224,100,230,164,230,178,222, +185,199,82,136,40,154,40,28,118,28,118,62,41,62,40,98,133,98,84,62, +90,108,98,134,110,154,120,156,130,148,135,128,176,14,158,58,139,86,238,54, +161,54,162,82,182,120,208,146,235,162,206,54,202,88,190,118,170,144,149,162, +52,180,21,228,118,174,147,200,194,178,237,222,82,172,82,216,88,228,100,234, +160,234,176,224,183,201,226,30,36,30,36,164,235,164,54,60,221,60,102,40, +103,74,162,40,163,74,52,94,223,94,134,74,100,112,67,138,190,144,190,114, +102,114,102,144,191,144,54,184,27,226,128,180,147,202,196,182,233,216,88,182, +88,216,90,228,100,232,162,232,178,222,183,207,106,18,62,28,33,32,20,66, +123,66,108,146,108,102,38,102,38,146,109,146,72,102,73,26,216,144,216,46, +142,46,142,144,217,144,168,46,179,14,142,78,217,78,142,112,217,112,120,162, +151,190,52,178,27,224,196,172,233,222,88,174,88,218,94,230,108,234,158,234, +178,222,187,201,66,16,95,34,20,44,133,44,120,92,120,68,44,68,44,92, +121,92,24,114,116,114,84,134,84,164,80,174,72,178,59,178,24,150,139,142, +180,18,166,52,145,90,240,64,161,64,166,88,182,126,206,152,235,170,210,64, +206,98,194,128,172,152,147,170,46,188,21,232,120,176,143,204,198,182,235,222, +86,188,86,216,88,228,98,236,160,236,178,222,181,207,16,60,85,60,56,162, +57,16,20,128,57,72,82,108,57,78,91,30,88,78,158,78,153,104,106,50, +137,78,90,32,158,32,127,68,130,78,130,156,111,160,82,138,131,78,166,56, +235,56,198,158,199,14,158,134,180,104,199,60,238,132,212,96,199,62,54,184, +29,232,130,174,155,198,196,178,237,220,88,178,88,216,92,228,106,236,162,236, +178,224,187,205,38,30,65,46,22,70,53,88,30,168,63,118,86,42,225,42, +128,60,129,16,182,58,183,16,74,72,235,72,94,170,94,102,218,102,218,168, +197,174,134,72,130,112,120,138,113,152,150,136,131,114,174,72,170,116,164,140, +153,162,198,146,173,112,126,176,151,202,54,190,25,234,204,194,233,228,90,186, +90,222,94,234,104,238,162,238,180,226,187,211,62,14,77,28,26,38,115,38, +48,50,61,64,18,74,119,74,94,46,79,74,102,136,102,94,38,94,38,136, +103,136,38,114,103,114,18,156,115,156,72,184,73,136,160,14,146,34,131,46, +128,68,178,50,202,30,151,30,156,42,202,62,235,70,144,72,207,72,120,96, +231,96,174,96,175,72,140,160,140,114,210,114,211,158,174,128,172,148,162,166, +139,182,186,162,227,180,56,196,35,230,120,188,143,208,188,194,225,222,90,192, +90,218,94,228,108,234,160,234,174,226,181,211,14,104,241,104,48,60,200,60, +201,168,50,146,201,146,124,242,125,15,16,80,239,80,48,42,198,42,198,116, +49,116,42,152,211,152,26,194,231,194,126,244,127,11,26,48,102,48,80,82, +54,110,23,128,130,12,130,104,126,120,118,124,103,126,234,126,192,102,154,68, +131,32,224,36,159,72,58,244,58,148,196,148,197,242,58,188,197,188,58,224, +197,225,50,26,73,76,112,20,135,76,32,132,32,94,216,94,217,134,128,112, +128,238,95,242,44,146,102,146,84,186,58,212,19,230,234,226,200,214,166,192, +140,164,129,144,192,138,155,178,204,26,167,95,26,48,102,48,78,84,48,104, +25,114,130,12,130,118,107,124,130,38,152,64,184,90,229,110,198,34,167,74, +14,156,54,156,46,184,30,214,19,226,74,124,74,236,55,242,74,162,115,200, +112,138,85,172,124,156,158,156,146,192,115,228,180,120,180,238,155,242,234,226, +206,200,188,172,181,152,224,140,195,181,14,40,109,40,14,140,36,106,61,40, +42,212,42,108,94,108,95,204,42,184,95,184,86,238,114,206,130,158,130,32, +194,32,194,216,200,228,214,230,230,224,239,205,16,36,107,36,16,130,44,94, +63,36,46,220,46,104,96,104,97,218,46,192,97,192,120,30,233,30,112,116, +243,116,174,238,175,31,20,36,107,36,16,132,50,92,67,36,46,216,46,100, +94,100,95,208,46,184,95,184,126,32,208,32,130,112,230,112,220,216,206,230, +175,236,114,180,144,150,161,112,118,230,158,196,184,152,197,113,32,38,223,38, +48,70,205,70,16,100,235,100,28,136,229,136,128,136,129,12,110,140,70,178, +25,208,80,244,80,176,200,176,201,244,80,224,201,225,20,42,95,42,18,132, +40,102,54,72,59,42,46,218,46,108,90,108,91,214,46,188,91,188,114,54, +235,54,172,12,122,132,229,132,108,178,243,178,174,242,175,85,18,40,95,40, +14,140,40,102,59,40,42,226,42,110,84,110,85,218,42,192,85,192,110,56, +235,56,118,90,118,162,216,162,217,90,166,8,166,212,168,224,178,230,218,230, +230,222,237,197,18,34,105,34,18,144,46,100,69,34,46,220,46,108,96,108, +97,212,46,192,97,192,122,26,237,26,144,50,130,114,245,114,120,216,158,174, +195,114,206,26,206,236,177,241,22,40,109,40,20,138,44,106,65,40,48,218, +48,106,96,106,97,210,48,190,97,190,222,20,174,30,134,34,134,168,122,200, +105,232,134,104,245,104,194,104,195,243,16,44,101,44,64,44,52,90,34,122, +15,148,44,220,44,108,92,108,93,214,44,192,91,192,218,24,172,36,125,42, +152,58,175,88,114,110,206,110,131,204,106,240,122,206,138,208,148,234,241,235, +12,38,93,38,54,38,40,90,15,138,38,216,38,106,82,106,83,210,38,188, +83,188,90,240,110,202,116,164,116,26,204,26,204,182,210,216,220,230,228,232, +238,220,243,212,134,76,160,128,187,192,124,202,158,136,179,59,16,40,109,40, +18,146,50,96,67,40,44,226,44,110,92,110,93,222,44,198,93,198,116,68, +225,68,112,130,237,130,172,130,173,16,192,178,233,230,172,136,122,228,213,207, +18,46,91,46,18,138,46,96,61,46,48,214,48,110,90,110,91,208,48,188, +91,188,112,50,239,50,138,86,139,10,190,84,191,10,130,110,148,158,180,198, +237,232,202,104,182,154,150,198,89,241,20,36,99,36,42,208,42,104,88,104, +89,198,42,184,89,184,16,126,48,84,65,36,86,232,104,212,122,156,122,28, +235,28,140,74,241,74,174,74,174,110,168,164,154,204,125,236,172,130,218,130, +214,214,208,226,192,232,179,237,164,18,191,38,28,50,225,50,118,14,112,64, +96,92,68,114,33,124,102,116,160,94,197,68,146,50,146,108,148,118,162,124, +196,124,212,114,221,96,16,148,239,148,92,156,58,188,25,208,74,242,74,184, +196,184,197,242,74,228,197,229,20,44,105,44,62,44,50,96,21,146,46,224, +46,116,94,116,95,218,46,198,95,198,148,12,128,64,113,92,242,58,133,58, +156,246,157,58,156,116,227,116,156,178,233,179,18,48,105,48,66,48,50,98, +21,142,46,226,46,120,92,120,93,216,46,194,93,194,174,16,148,62,115,98, +238,98,200,70,171,22,122,124,223,124,112,228,239,228,172,228,173,125,18,38, +97,38,58,38,48,88,19,140,44,224,44,106,88,106,89,226,44,196,89,196, +222,26,166,34,124,36,124,228,165,184,168,212,181,240,124,108,235,108,172,34, +174,118,188,178,204,214,220,234,226,238,232,236,243,213,16,48,109,48,66,48, +52,102,19,154,48,218,48,112,92,112,93,212,48,192,93,192,158,18,181,52, +118,74,233,74,138,108,155,194,104,230,241,230,212,104,179,231,18,42,99,42, +68,42,48,104,21,146,48,228,48,116,94,116,95,222,48,200,95,200,158,14, +181,34,122,90,122,52,230,52,231,88,154,96,154,204,154,220,166,228,216,228, +230,218,239,202,222,124,155,149,86,48,19,48,60,48,44,96,19,134,44,218, +44,110,84,110,85,212,44,188,85,188,114,46,222,46,222,96,116,96,116,148, +236,148,230,198,218,204,209,204,188,244,189,10,152,12,152,162,142,194,126,218, +103,241,14,40,83,40,54,40,42,94,19,142,46,208,46,108,80,108,81,206, +46,186,81,186,104,34,177,34,102,120,179,120,122,34,122,164,114,200,93,236, +156,34,157,236,198,42,199,184,230,16,230,232,199,239,20,46,89,46,56,46, +46,96,19,146,44,222,44,112,82,112,83,216,44,194,83,194,106,54,245,54, +140,90,141,16,164,82,187,110,200,90,201,12,106,124,247,124,132,124,132,228, +233,229,16,46,91,46,60,46,40,98,13,140,40,216,40,110,84,110,85,208, +40,190,85,190,112,52,229,52,118,80,137,112,216,74,191,114,106,134,237,134, +164,10,164,134,140,192,118,218,91,240,236,234,200,202,182,172,165,135,18,46, +95,46,58,46,44,92,17,130,44,212,44,110,82,110,83,208,44,184,83,184, +112,56,231,34,112,122,172,94,217,58,142,8,152,56,172,94,196,114,216,120, +226,118,237,98,106,146,239,146,142,146,138,190,118,220,81,240,184,146,184,214, +188,226,198,232,222,232,234,222,239,205,28,116,135,96,50,112,51,38,90,102, +91,12,132,58,91,58,154,14,154,96,158,108,168,114,212,114,224,106,233,84, +216,36,155,68,18,140,239,140,105,140,22,212,68,188,107,140,78,244,78,178, +202,178,203,244,78,224,203,225,22,38,103,38,24,132,54,90,69,38,50,210, +50,108,92,108,93,206,50,184,93,184,126,238,126,28,230,28,230,228,199,236, +146,72,209,72,198,170,198,116,158,116,158,170,199,171,22,52,107,52,20,150, +46,114,69,52,50,228,50,118,94,118,95,224,50,198,95,198,128,242,128,56, +226,56,227,240,128,218,227,218,174,14,153,56,150,90,180,132,207,186,200,78, +182,128,153,185,16,50,103,50,18,152,46,108,63,50,46,228,46,120,90,120, +91,228,46,206,91,206,156,16,132,66,109,92,112,146,162,118,196,84,214,54, +139,54,143,76,144,78,180,112,241,142,134,242,134,152,212,152,213,242,134,222, +213,223,14,46,83,46,12,142,40,102,59,46,42,222,42,114,74,114,75,220, +42,194,75,194,156,36,126,44,105,46,94,98,241,98,100,174,161,142,132,42, +132,238,107,244,180,14,180,98,184,150,196,200,216,230,226,238,236,232,243,208, +222,122,200,168,157,228,204,36,229,69,18,42,89,42,16,130,44,98,63,42, +42,210,42,108,82,108,83,206,42,184,83,184,110,42,235,42,116,70,225,70, +104,100,239,100,120,202,120,130,214,130,215,200,168,100,169,8,164,148,162,186, +152,208,134,226,110,236,93,242,178,202,231,237,20,46,111,46,20,140,50,96, +67,46,50,222,50,110,98,110,99,210,50,186,99,186,156,14,134,68,117,92, +186,16,207,48,140,246,141,56,148,70,241,70,148,118,235,118,148,166,235,166, +148,216,245,216,190,216,191,71,16,46,97,46,14,148,46,102,63,46,118,56, +231,56,44,230,44,118,88,118,89,224,44,202,89,202,110,120,241,120,154,14, +177,42,130,72,155,104,208,70,181,120,130,242,130,156,210,156,211,242,130,220, +211,221,18,46,97,46,18,136,46,100,65,46,46,216,46,112,88,112,89,206, +46,188,89,188,158,16,183,42,120,84,120,52,230,52,231,82,120,104,227,104, +136,144,132,184,122,210,104,228,93,238,132,184,146,204,166,220,194,224,241,226, +176,104,177,220,176,156,227,157,16,42,101,42,16,140,44,96,63,42,44,222, +44,114,84,114,85,222,44,198,85,198,188,36,225,72,162,14,120,68,209,56, +104,102,233,102,168,76,138,120,109,152,236,150,208,136,179,102,172,134,146,160, +119,180,194,156,160,186,125,208,218,182,166,220,115,241,18,38,89,38,16,134, +46,88,61,38,44,218,44,104,82,104,83,212,44,192,83,192,110,40,233,40, +118,70,219,70,102,98,237,98,104,166,241,166,166,98,167,10,230,208,120,208, +124,122,210,122,208,222,202,232,184,238,167,244,152,138,179,154,148,182,175,199, +22,40,111,40,20,130,50,94,71,40,48,214,48,104,94,104,95,206,48,184, +95,184,222,98,222,24,134,24,134,98,223,98,134,62,223,62,158,104,136,132, +115,150,200,234,218,232,228,226,234,220,236,208,236,130,139,130,186,140,157,186, +214,184,179,156,132,160,132,210,207,211,20,44,99,44,20,138,50,92,67,44, +50,212,50,110,92,110,93,204,50,188,93,188,158,10,181,30,122,42,239,42, +140,58,159,82,118,126,118,98,234,98,235,128,206,58,185,98,132,220,132,146, +220,146,220,196,216,208,208,212,197,214,174,244,175,113,16,40,89,40,18,146, +46,106,65,40,46,228,46,114,86,114,87,222,46,200,87,200,110,86,110,52, +230,52,231,86,144,14,175,42,128,86,213,86,214,196,214,120,126,120,126,196, +215,196,126,158,213,158,102,232,245,233,18,38,101,38,20,140,40,108,59,38, +50,224,50,106,90,106,91,212,50,194,91,194,102,228,118,198,124,144,124,52, +222,52,222,94,125,94,148,16,185,42,138,244,138,132,230,132,230,238,207,242, +138,174,231,174,168,218,169,132,199,218,200,218,201,133,16,40,95,40,16,142, +42,100,57,40,44,216,44,110,80,110,81,212,44,190,81,190,134,16,116,56, +97,84,106,136,136,108,152,74,160,50,121,50,122,82,141,96,182,50,241,50, +180,70,176,98,243,98,208,130,209,16,104,154,237,154,168,240,169,124,100,226, +138,194,169,154,240,222,202,194,169,155,18,42,89,42,110,46,237,46,20,148, +44,108,61,42,44,230,44,112,84,112,85,228,44,204,85,204,144,62,107,96, +190,62,235,92,190,100,225,132,168,80,124,130,207,118,162,136,132,174,105,198, +180,214,138,236,139,166,180,156,194,190,208,210,237,232,224,154,195,188,146,10, +177,35,18,42,105,42,18,140,38,116,50,88,63,42,46,208,46,102,84,102, +85,202,46,182,85,182,120,20,206,20,170,52,117,76,134,38,180,54,219,72, +100,90,158,90,140,118,109,150,106,110,153,138,178,88,228,88,210,120,191,140, +180,106,231,138,108,166,245,166,166,142,167,244,90,226,130,204,165,166,236,222, +206,206,167,167,26,38,135,38,38,64,125,64,82,64,83,12,20,162,38,140, +44,114,44,90,122,90,122,122,43,122,84,122,85,90,62,158,223,158,152,60, +160,44,160,24,204,24,204,52,218,58,235,56,146,80,214,80,196,110,166,128, +151,134,240,140,198,126,170,106,153,80,24,216,58,202,84,180,101,158,78,242, +78,188,200,188,201,240,78,224,201,225,14,44,89,44,118,60,137,74,114,20, +137,42,112,136,137,94,16,152,38,120,52,86,61,44,44,224,44,116,82,116, +83,222,44,200,83,200,236,30,158,30,158,130,243,130,158,98,222,98,222,62, +159,62,106,166,243,166,174,246,175,142,106,228,144,202,173,166,240,222,202,198, +175,167,16,40,91,40,20,144,44,102,59,40,46,228,46,114,82,114,83,218, +46,200,83,200,116,20,141,44,96,58,173,58,158,114,158,82,112,82,112,114, +159,114,102,142,152,142,134,162,134,236,109,242,104,190,165,176,200,20,190,68, +175,126,244,80,189,80,186,102,192,142,202,174,220,208,245,238,224,80,222,130, +210,174,194,208,163,239,16,42,85,42,14,136,40,98,59,42,34,216,34,108, +80,108,81,210,34,188,81,188,106,26,156,26,138,72,103,112,106,52,133,76, +182,18,194,66,214,94,239,114,226,26,191,50,240,58,207,82,134,102,195,102, +208,174,208,134,126,134,126,174,209,174,96,230,239,230,132,194,151,230,200,190, +179,231,20,40,95,40,112,24,243,24,18,136,44,98,65,40,48,216,48,100, +84,100,85,206,48,186,85,186,106,124,249,124,222,100,222,50,124,50,124,100, +223,100,124,76,223,76,174,100,175,50,224,204,224,150,124,150,124,204,225,204, +124,178,225,178,174,204,175,150,100,232,247,233,18,40,81,40,104,40,243,40, +16,140,42,98,55,40,38,216,38,102,70,102,71,216,38,190,71,190,128,66, +99,114,98,162,126,140,150,108,158,86,117,86,124,106,141,120,106,128,125,140, +172,70,186,100,202,126,241,158,180,84,224,84,203,124,152,138,183,138,120,170, +221,170,170,170,170,238,145,244,138,190,97,228,198,194,237,230,142,52,143,10, +192,50,193,9,14,40,85,40,112,38,241,38,16,146,38,116,50,82,57,40, +42,222,42,110,80,110,81,218,42,196,81,196,108,94,108,68,228,68,229,94, +132,96,203,96,146,68,147,12,189,68,188,68,189,12,102,120,233,120,110,158, +140,142,167,120,146,138,162,156,172,176,176,202,174,224,166,236,154,240,143,240, +104,194,136,176,161,156,104,226,144,204,173,180,220,142,171,172,236,226,218,210, +204,190,193,161,14,48,79,48,16,144,38,100,51,48,38,220,38,112,72,112, +73,218,38,198,73,198,94,40,239,40,140,58,141,14,184,56,185,16,92,78, +117,96,92,118,117,134,90,236,115,164,130,84,241,84,140,164,140,106,222,106, +223,164,182,164,183,68,204,62,225,74,140,124,223,124,140,150,223,150,124,186, +243,186,210,172,210,234,185,238,146,200,167,221,128,14,70,56,17,76,236,70, +164,50,119,22,68,68,185,68,192,124,192,94,64,94,64,124,193,124,22,164, +231,164,148,136,183,152,114,136,100,186,72,216,25,242,138,164,138,222,142,230, +158,236,202,236,220,222,225,204,184,178,126,212,93,227,18,82,237,82,104,82, +105,14,152,82,153,14,48,28,83,62,208,22,179,62,60,98,95,122,192,98, +163,124,52,246,52,138,206,138,206,240,175,244,128,242,129,94,104,156,71,212, +144,160,185,209,12,74,117,74,138,70,239,70,58,74,59,12,86,74,87,14, +22,28,41,54,122,26,105,56,30,240,30,130,112,130,112,236,97,240,30,90, +51,114,108,92,85,130,72,238,73,82,54,156,45,202,86,156,99,198,174,10, +162,116,131,190,200,26,223,50,164,114,216,114,202,168,174,204,137,232,164,134, +176,170,200,206,233,235,16,76,123,76,132,62,241,62,58,76,59,12,86,76, +87,16,24,28,41,54,124,28,105,58,32,90,51,114,114,92,99,114,32,240, +32,130,118,130,118,238,99,242,56,154,47,200,90,158,101,200,72,242,73,84, +208,24,229,42,146,242,146,96,228,96,228,236,211,240,188,240,189,10,146,138, +229,138,146,176,229,177,28,224,28,34,88,34,89,216,28,196,89,196,28,142, +89,142,28,88,89,88,112,26,231,26,102,112,245,112,176,26,176,238,147,245, +30,226,30,32,80,32,81,220,30,86,81,86,30,138,81,138,30,192,81,192, +102,32,241,32,114,72,110,146,219,146,158,146,159,32,158,86,220,86,216,204, +204,230,169,237,30,238,30,38,90,38,91,230,30,212,91,212,30,152,91,152, +30,98,91,98,236,34,126,34,126,230,243,230,214,64,188,132,147,188,146,76, +194,136,229,185,26,230,26,36,80,36,81,222,26,200,81,200,26,146,81,146, +26,90,81,90,100,58,235,58,114,94,114,160,212,160,213,92,162,10,162,212, +164,226,176,232,214,232,228,220,233,199,28,226,28,36,82,36,83,226,28,200, +83,200,28,146,83,146,28,92,83,92,104,138,124,86,135,54,168,166,169,14, +198,54,239,116,214,126,192,178,156,212,105,237,28,228,28,40,82,40,83,220, +28,94,83,94,28,146,83,146,28,202,83,202,112,106,112,68,226,68,227,104, +162,12,162,114,144,176,95,240,182,110,182,218,186,228,198,234,222,234,232,226, +239,209,72,16,52,56,33,78,224,46,59,46,56,78,207,78,18,110,241,110, +132,110,133,10,60,246,60,138,202,138,203,244,60,168,203,168,60,198,203,198, +60,228,203,229,76,12,50,54,29,80,22,136,70,114,102,80,120,42,59,42, +56,80,81,102,180,78,198,76,206,68,206,32,146,32,146,98,150,108,162,116, +214,116,226,108,237,90,58,246,58,142,200,142,201,246,58,168,201,168,58,200, +201,200,58,228,201,229,30,234,30,40,86,40,87,228,30,94,87,94,30,148, +85,148,30,206,87,206,186,52,237,104,170,14,112,100,223,92,128,242,128,140, +214,140,215,240,128,216,213,217,34,228,34,38,88,38,89,218,34,202,89,202, +34,148,89,148,34,92,89,92,116,56,225,56,102,106,239,106,168,106,169,8, +114,164,225,164,102,226,239,226,168,226,169,123,32,228,32,38,76,38,77,218, +33,202,32,204,77,204,32,148,77,148,32,94,77,94,90,234,167,210,110,56, +111,226,140,24,141,218,168,98,141,98,182,16,182,222,190,232,228,232,243,206, +228,66,183,109,28,226,28,38,84,38,85,220,28,92,85,92,28,146,85,146, +28,200,85,200,164,10,138,56,113,80,102,136,160,108,196,78,218,46,145,46, +140,78,169,98,196,106,154,150,109,180,104,238,168,214,210,178,234,140,163,140, +150,172,181,203,30,226,30,34,84,34,85,220,30,88,85,88,30,142,85,142, +30,200,85,200,165,14,190,44,227,84,164,16,110,74,213,70,134,98,120,132, +103,152,100,178,239,178,170,244,171,86,224,126,125,127,26,224,26,42,72,42, +73,212,26,196,73,196,26,144,73,144,26,92,73,92,94,48,221,48,106,74, +131,108,206,68,185,108,90,128,229,128,158,246,159,10,86,216,126,174,157,130, +234,210,202,188,159,129,28,230,28,36,82,36,83,220,28,206,83,206,28,148, +83,148,28,92,83,92,160,12,128,66,91,100,156,20,174,50,202,76,237,96, +118,100,205,100,108,140,131,192,152,130,167,180,98,226,233,226,210,130,173,227, +28,226,28,36,80,36,81,218,28,90,81,90,28,146,81,146,28,200,81,200, +122,16,151,44,104,58,216,58,216,102,120,102,114,148,228,148,226,196,220,206, +208,212,197,212,168,244,169,58,206,12,181,58,92,230,136,190,163,149,28,228, +28,38,80,38,81,224,28,202,81,202,28,146,81,146,28,92,81,92,190,46, +229,86,166,14,110,76,213,70,142,94,99,132,188,98,237,132,154,116,130,160, +105,190,98,238,154,216,192,176,210,144,141,144,142,164,166,198,194,220,235,239, +28,220,28,36,76,36,77,206,28,88,77,88,28,140,77,140,28,192,77,192, +236,34,112,34,112,168,83,238,132,86,223,86,122,130,237,130,126,180,231,180, +110,226,243,226,176,50,177,130,176,144,177,227,28,220,28,40,80,40,81,210, +28,90,81,90,28,142,81,142,28,192,81,192,154,16,116,32,116,134,214,134, +214,34,175,34,150,84,117,84,174,84,215,84,86,240,124,212,142,176,143,134, +180,134,180,214,184,226,196,232,218,232,232,222,239,199,30,230,30,40,80,40, +81,224,30,204,81,204,30,150,81,150,30,94,81,94,144,16,126,60,99,100, +172,18,199,52,124,244,125,66,132,70,237,70,132,118,229,118,132,166,229,166, +132,218,243,218,178,218,179,71,32,234,32,36,84,36,85,224,32,206,85,206, +32,150,85,150,32,94,85,94,216,134,216,46,118,46,118,134,217,134,118,92, +217,92,166,46,164,106,154,142,119,174,100,186,243,186,186,246,187,152,158,10, +143,47,30,94,30,56,222,56,223,92,118,56,119,8,118,30,209,30,56,80, +199,80,40,122,83,98,170,98,207,118,130,80,92,124,58,148,19,166,236,162, +200,150,158,126,123,90,68,248,68,142,186,142,187,246,68,170,187,170,68,200, +187,200,68,228,187,229,28,222,28,36,76,36,77,218,28,88,77,88,28,142, +77,142,140,30,110,40,110,114,222,114,222,40,187,40,110,76,139,76,222,74, +193,74,102,148,208,148,188,184,148,218,97,236,234,234,186,216,152,190,123,148, +166,148,167,10,28,198,77,199,30,226,30,34,76,34,77,222,30,200,77,200, +30,144,77,144,30,90,77,90,106,28,152,28,144,58,122,96,97,122,104,52, +135,74,170,14,182,54,206,90,237,118,216,18,181,44,236,44,199,74,124,118, +207,118,102,166,233,166,102,236,136,216,154,194,164,146,169,118,230,234,159,181, +65,46,22,70,124,70,113,100,64,46,95,70,34,26,114,26,81,58,20,124, +58,98,85,70,66,130,84,126,88,118,89,70,174,10,158,50,143,76,238,44, +161,44,162,74,184,102,208,116,237,128,128,126,170,108,196,76,213,44,60,248, +60,146,194,146,195,246,60,174,195,174,60,202,195,202,60,230,195,231,26,226, +26,40,72,40,73,216,26,94,73,94,26,144,73,144,26,200,73,200,104,40, +219,40,94,74,233,74,160,74,161,10,182,92,223,132,156,84,104,130,209,120, +86,228,245,228,114,228,114,158,214,158,215,228,148,228,149,158,182,228,183,159, +28,222,28,36,76,36,77,216,28,198,77,198,28,144,77,144,28,90,77,90, +102,58,102,30,224,30,225,58,206,128,206,68,118,68,118,128,207,128,118,98, +207,98,148,142,177,160,94,170,237,170,144,190,91,234,176,190,227,233,28,222, +28,32,76,32,77,216,28,88,77,88,28,140,77,140,28,196,77,196,94,26, +239,26,220,104,220,62,110,62,110,104,221,104,146,104,147,26,182,104,183,26, +112,136,217,136,94,166,241,166,130,184,97,228,194,186,231,224,166,166,166,218, +160,232,141,233,28,226,28,42,76,42,77,222,28,202,77,202,28,146,77,146, +28,94,77,94,108,28,135,58,214,26,189,58,100,106,100,76,224,76,225,104, +160,76,161,10,196,154,196,110,126,110,126,154,197,154,106,188,217,188,88,228, +237,228,158,228,159,163,28,222,28,40,68,40,69,208,28,192,69,192,28,138, +69,138,28,92,69,92,80,72,163,72,90,30,136,30,127,72,86,218,161,198, +98,72,99,214,146,72,147,246,98,160,147,160,98,112,147,112,196,12,184,68, +161,120,158,232,190,190,206,142,213,78,236,76,181,76,236,230,206,198,188,156, +177,113,30,224,30,42,76,42,77,222,30,198,77,198,30,146,77,146,30,96, +77,96,114,26,141,52,210,22,185,50,96,66,231,66,96,116,124,102,144,84, +163,66,162,120,163,14,230,112,200,98,165,66,130,120,112,158,97,180,96,240, +126,216,146,176,152,144,121,144,118,178,139,192,166,146,233,146,176,166,168,196, +237,196,200,242,201,121,18,36,127,36,32,56,127,56,120,100,120,78,40,78, +40,100,121,100,24,136,131,126,52,110,69,130,108,108,95,130,136,44,237,44, +138,72,216,72,194,100,168,120,145,134,234,134,198,120,168,100,149,72,182,72, +183,14,78,56,79,16,58,244,58,150,200,150,201,242,58,176,201,176,58,200, +201,200,58,224,201,225,24,216,24,42,104,42,105,210,24,188,105,188,24,114, +105,114,64,188,65,42,120,40,241,40,186,40,186,236,149,243,200,108,200,24, +52,24,52,108,201,108,124,108,125,24,52,66,201,66,16,146,241,146,28,238, +70,220,90,188,95,146,170,240,171,147,26,212,26,40,106,40,107,208,26,112, +107,112,26,186,107,186,120,92,235,92,108,234,146,192,164,146,170,92,171,10, +232,234,198,190,169,106,64,186,65,40,192,38,225,69,26,222,26,44,102,44, +103,216,26,194,103,194,26,116,103,116,162,10,146,64,121,118,238,74,143,74, +106,238,160,204,188,166,202,124,207,74,238,236,194,206,166,168,149,108,62,194, +63,45,28,212,28,44,100,44,101,206,28,112,101,112,28,186,101,186,62,186, +63,44,94,234,118,202,134,148,134,40,184,34,229,28,140,102,216,102,202,154, +180,198,127,240,238,236,196,208,172,170,149,103,24,202,24,38,98,38,99,202, +24,178,99,178,24,106,99,106,62,178,63,38,168,14,146,62,119,98,234,102, +198,76,163,30,182,94,154,122,125,144,200,130,168,164,131,190,224,160,174,206, +101,235,20,84,84,54,137,12,238,80,184,62,127,20,78,70,177,70,54,102, +205,102,82,118,25,152,170,120,229,142,130,102,130,128,118,140,105,140,56,246, +56,162,200,162,201,244,56,230,201,230,56,196,201,196,128,230,129,163,28,218, +28,44,90,44,91,208,28,114,91,114,28,186,91,186,58,186,59,44,148,14, +181,42,114,90,114,54,226,54,227,88,138,78,122,130,103,168,90,238,120,218, +146,184,158,142,160,106,131,106,124,148,145,184,236,208,230,228,218,238,198,238, +188,236,184,218,184,102,218,102,218,180,206,184,201,181,26,222,26,44,84,44, +85,218,26,122,85,122,26,198,85,198,56,198,57,44,146,14,175,32,112,44, +227,44,98,86,239,86,132,56,155,76,200,54,179,86,214,172,214,114,116,114, +116,172,215,172,108,200,227,200,96,232,243,232,166,232,167,114,116,142,213,143, +208,84,208,32,50,32,50,84,209,84,102,84,103,32,156,84,157,32,24,122, +233,122,26,202,76,180,112,152,139,122,124,244,125,138,158,156,225,205,208,84, +208,30,44,30,44,84,209,84,100,84,101,30,154,84,155,30,24,122,225,122, +14,224,239,224,68,224,69,152,130,224,131,122,130,168,207,169,210,80,210,24, +46,24,46,80,211,80,156,80,157,24,102,80,103,24,14,130,243,130,56,244, +56,172,198,172,199,242,56,222,199,222,128,172,129,97,212,68,212,26,44,26, +44,68,213,68,100,68,101,26,156,68,157,26,112,78,137,92,14,102,243,102, +54,130,205,130,56,156,205,156,58,242,58,184,200,184,201,242,58,222,201,223, +206,68,206,24,40,24,40,68,207,68,152,68,153,24,98,68,99,24,99,24, +24,100,233,100,114,78,84,116,56,138,21,158,230,150,194,132,155,100,186,198, +186,140,62,140,62,198,187,198,62,170,187,170,122,114,122,228,126,232,140,236, +198,236,212,224,219,209,212,70,212,30,48,30,48,70,213,70,156,70,157,30, +100,70,101,30,52,104,205,104,24,134,235,134,130,134,131,80,168,148,209,186, +110,144,62,180,193,172,50,200,31,240,92,202,103,240,142,200,159,238,194,198, +227,239,216,66,216,26,42,26,42,66,217,66,100,66,101,26,158,66,159,26, +12,98,239,98,44,244,44,128,206,128,206,214,204,226,192,234,177,232,86,140, +109,160,66,170,183,170,126,76,121,128,158,140,139,170,62,200,187,200,122,234, +123,171,210,62,210,24,42,24,42,62,211,62,154,62,155,24,98,62,99,24, +60,246,61,78,36,110,25,164,76,106,91,134,138,80,112,126,87,160,164,80, +191,104,120,244,121,112,130,114,229,114,130,150,223,150,130,184,223,184,130,222, +239,222,176,222,177,115,214,66,214,30,40,30,40,66,215,66,100,66,101,30, +158,66,159,30,22,102,133,102,60,80,60,130,112,130,113,80,128,184,128,154, +38,154,38,184,129,184,18,210,137,210,84,246,85,130,164,112,158,162,228,162, +226,216,222,224,208,232,187,234,140,94,210,94,207,162,144,196,209,197,208,60, +208,28,40,28,40,60,209,60,152,60,153,28,96,60,97,28,76,70,105,88, +216,140,216,98,34,98,34,140,217,140,170,68,139,98,126,140,127,98,66,108, +99,130,186,104,153,128,54,242,54,170,196,170,197,242,54,228,197,228,54,198, +197,199,42,50,217,50,20,90,237,90,130,90,131,12,121,98,160,112,223,154, +122,98,50,148,201,140,18,230,241,230,62,230,62,174,196,174,197,230,152,230, +153,174,108,230,109,175,92,22,48,34,49,144,74,68,49,68,74,106,49,106, +168,30,216,30,211,144,178,66,215,66,176,106,211,106,130,20,130,142,111,148, +84,58,110,58,100,96,83,126,164,120,131,62,166,48,145,84,16,226,241,226, +54,226,54,168,204,168,205,226,106,226,107,168,152,226,153,169,36,24,57,50, +22,70,115,70,100,20,75,70,58,88,23,130,86,92,111,116,22,226,117,212, +36,222,36,144,102,144,103,212,58,144,59,220,80,144,81,216,224,74,224,30, +132,30,132,74,225,74,164,74,165,30,192,74,193,30,156,82,134,114,115,134, +198,172,198,138,134,138,134,172,199,172,186,184,203,216,126,210,195,200,166,120, +167,202,192,236,208,238,218,232,224,214,224,108,139,109,70,20,48,68,23,102, +126,60,53,60,40,108,117,108,24,150,129,150,78,108,78,230,123,207,74,16, +46,66,19,98,120,62,49,62,36,106,107,106,20,152,123,152,70,106,70,224, +113,190,154,16,154,210,158,224,172,232,218,232,234,214,239,195,62,16,40,62, +23,92,116,58,45,58,32,102,111,102,18,150,119,150,66,102,66,226,111,192, +130,48,220,48,176,112,140,178,130,206,130,218,134,228,154,236,200,236,224,232, +234,216,241,203,68,16,42,68,23,96,122,66,45,66,36,108,117,108,22,152, +129,152,70,108,70,228,117,186,166,246,167,12,180,88,210,126,235,165,80,18, +52,68,25,106,136,56,61,56,46,100,125,100,24,146,139,146,78,100,78,224, +135,194,170,180,171,50,222,20,222,214,216,230,200,236,179,237,74,16,44,62, +19,92,122,58,49,58,32,104,119,104,22,148,125,148,72,104,72,226,121,192, +132,44,236,44,188,96,188,214,182,228,174,230,153,237,66,18,38,68,21,92, +112,60,45,60,30,102,101,102,20,152,111,152,64,102,64,228,109,190,118,100, +231,100,106,222,245,222,176,222,177,13,72,14,44,60,21,88,110,54,49,54, +38,94,101,94,18,144,113,144,62,94,62,216,103,186,103,186,132,26,132,152, +122,194,95,236,176,222,177,34,220,240,221,23,74,14,50,64,27,96,126,58, +55,58,42,104,111,104,26,148,123,148,74,104,74,228,119,188,212,18,174,62, +133,92,220,90,186,124,145,152,226,154,182,204,125,237,68,20,44,72,23,104, +106,62,51,62,103,108,38,108,103,108,24,152,111,152,66,108,66,226,107,200, +126,240,127,68,126,24,157,60,172,46,230,46,230,232,205,239,62,12,34,66, +17,90,28,104,93,104,98,58,39,58,14,148,105,148,60,104,60,228,101,192, +104,46,218,46,206,118,174,180,107,240,234,236,184,194,146,132,123,46,160,68, +177,107,68,16,40,68,23,92,102,62,45,62,32,106,97,106,22,152,105,152, +64,106,64,228,105,188,106,90,245,90,170,14,134,156,188,194,239,234,112,236, +154,212,194,164,213,91,58,14,36,64,19,84,32,98,101,98,18,148,105,148, +102,56,41,56,62,98,62,226,103,200,116,40,243,40,110,176,146,132,170,86, +185,40,172,242,173,80,190,112,218,144,241,179,72,18,44,66,17,94,108,64, +47,64,30,106,95,106,16,152,111,152,60,106,60,224,97,188,108,92,235,92, +164,14,164,98,154,140,136,182,91,238,150,188,181,226,236,234,200,186,180,146, +165,99,64,16,44,68,19,102,98,60,49,60,36,100,95,100,24,142,103,142, +62,100,62,228,105,206,238,34,126,34,126,224,241,224,126,90,214,90,214,158, +127,159,68,14,46,60,19,100,106,56,49,56,36,102,99,102,16,148,107,148, +62,102,62,218,95,186,226,28,180,36,132,40,132,148,120,190,91,238,140,98, +220,98,200,162,166,210,127,240,236,236,198,206,168,164,147,99,62,12,36,62, +17,88,100,56,41,56,28,100,95,100,18,150,95,150,58,100,58,228,103,196, +162,10,140,74,103,120,234,112,206,90,180,58,161,20,154,100,181,130,110,154, +208,154,188,198,161,239,68,16,44,58,21,86,108,56,47,56,34,100,101,100, +22,148,109,148,64,100,64,226,103,196,154,16,197,56,118,72,247,72,100,238, +136,202,156,156,158,114,159,72,184,232,206,230,216,222,220,206,222,126,159,127, +66,12,44,56,19,82,32,98,95,98,16,148,105,148,102,54,47,54,60,98, +60,224,97,198,114,64,235,64,146,14,177,50,88,240,116,218,134,182,136,158, +136,106,194,106,194,218,200,228,208,234,226,234,234,228,239,207,68,16,40,72, +17,104,112,62,47,62,34,108,103,108,16,150,115,150,62,108,62,228,101,202, +100,178,243,158,200,240,201,14,130,42,175,86,126,102,171,143,64,18,40,68, +17,94,34,104,99,104,104,62,45,62,18,148,105,148,62,104,62,222,105,190, +136,66,125,132,224,66,205,128,172,16,172,126,158,176,136,208,107,240,234,234, +208,204,186,164,173,123,64,14,40,62,19,90,34,100,99,100,18,148,107,148, +60,100,60,224,103,192,108,58,43,58,238,198,234,220,222,228,200,230,144,230, +136,228,132,214,132,38,220,38,220,126,133,126,176,126,177,39,70,16,44,64, +21,90,108,60,49,60,36,104,109,104,18,156,115,156,66,104,66,228,105,200, +118,42,235,42,122,126,225,126,104,228,245,228,172,228,173,42,200,154,231,197, +68,16,46,66,21,102,116,60,51,60,38,102,107,102,24,152,117,152,68,102, +68,226,111,190,122,40,241,40,104,226,247,226,142,226,143,106,188,226,189,40, +238,120,189,121,66,14,40,60,19,86,36,100,101,100,104,58,43,58,20,148, +107,148,62,100,62,228,101,198,114,76,245,76,132,244,132,144,220,144,221,244, +132,220,221,220,176,144,177,13,66,18,40,64,19,92,98,62,45,62,36,104, +95,104,20,154,101,154,62,104,62,232,105,196,106,40,247,40,178,170,178,92, +128,92,128,170,179,170,218,40,218,236,185,243,66,14,40,60,21,86,102,58, +43,58,32,100,97,100,16,144,109,144,60,100,60,224,101,190,238,34,128,34, +128,228,245,228,220,172,220,90,164,90,164,172,221,173,58,16,40,68,21,102, +90,64,43,64,38,108,91,108,18,154,97,154,60,108,60,240,99,214,110,68, +239,68,168,16,136,92,97,136,130,222,130,120,220,120,220,198,216,210,204,214, +197,208,174,246,175,81,66,12,42,58,19,86,108,58,45,58,30,100,101,100, +16,148,107,148,60,100,60,226,103,198,114,76,243,76,188,24,221,56,162,12, +154,88,136,136,109,178,104,236,150,216,190,174,212,120,143,120,234,232,196,208, +168,174,143,121,64,16,48,52,17,98,102,62,43,62,36,108,99,108,18,154, +105,154,58,108,58,232,99,200,198,22,229,52,242,76,120,76,120,220,161,186, +172,12,174,108,186,182,206,226,218,236,224,236,232,230,239,206,224,102,200,172, +178,206,151,239,70,12,48,60,19,90,110,58,51,58,39,104,38,102,105,102, +18,150,113,150,66,102,66,226,105,200,136,240,136,36,222,36,223,236,136,94, +223,94,136,148,223,148,136,210,223,211,68,16,38,64,17,90,106,60,43,60, +36,106,101,106,20,156,107,156,62,106,62,236,101,206,104,228,247,228,224,176, +224,40,134,40,134,176,225,176,134,108,225,109,64,16,44,54,21,88,104,62, +39,62,32,106,99,106,20,152,105,152,64,106,64,226,99,200,122,238,122,42, +226,42,227,236,122,212,227,212,122,124,227,124,174,212,175,43,62,16,38,64, +19,86,108,58,43,58,36,100,99,100,20,152,109,152,62,100,62,224,99,198, +226,26,178,34,140,38,120,124,243,124,144,162,115,218,182,72,182,214,180,224, +170,234,149,236,208,160,239,219,62,14,38,60,17,86,100,56,43,56,32,100, +101,100,20,146,105,146,62,100,62,226,101,198,144,12,187,46,122,58,243,58, +128,214,128,110,224,110,224,208,201,214,172,244,173,59,66,14,42,64,21,92, +38,100,101,100,102,54,49,54,18,144,105,144,149,40,60,100,60,226,99,190, +156,16,187,50,122,62,245,62,198,168,235,236,210,96,120,224,223,214,168,72, +126,138,181,139,68,16,42,62,21,84,104,56,47,56,38,100,101,100,24,146, +111,146,66,100,66,226,113,194,158,16,183,40,126,88,126,54,226,54,227,86, +154,94,154,214,158,224,166,232,224,232,234,220,239,200,220,126,155,161,68,16, +40,66,21,92,106,62,45,62,38,104,97,104,20,152,99,152,62,104,62,224, +91,200,128,120,113,186,142,24,181,60,208,126,239,182,150,66,150,212,154,224, +164,232,194,232,206,220,213,200,212,26,190,122,154,182,97,239,62,12,42,62, +19,98,108,54,47,54,38,102,103,102,18,146,107,146,58,102,58,220,97,186, +96,236,120,194,128,152,128,34,220,34,220,90,129,90,162,114,162,218,164,228, +174,232,222,232,234,224,243,206,228,138,163,171,64,14,38,62,19,84,102,56, +43,56,34,102,97,102,16,148,103,148,56,102,56,216,93,186,94,230,118,192, +126,154,126,58,230,58,221,92,126,122,214,122,198,174,170,210,127,238,178,122, +179,8,148,144,172,188,198,214,235,237,60,14,36,62,17,86,100,58,39,58, +34,100,95,100,16,150,101,150,60,100,60,230,89,204,108,32,200,32,172,72, +136,102,99,120,234,114,180,96,146,66,123,32,120,150,219,150,100,188,239,188, +162,244,163,113,66,16,40,62,17,94,102,60,43,60,36,102,97,102,16,150, +103,150,60,102,60,226,105,202,119,54,124,54,195,54,120,98,243,98,158,98, +159,14,222,28,170,112,109,176,232,138,147,138,170,138,162,180,216,180,214,204, +210,222,200,232,188,236,163,237,70,16,42,64,21,90,104,60,47,60,128,60, +203,60,38,98,97,98,20,148,105,148,66,98,66,228,103,196,108,110,243,110, +160,110,161,14,224,40,162,128,101,174,230,204,222,226,206,236,162,236,152,230, +148,220,149,140,222,148,149,187,66,20,40,66,19,94,102,62,45,62,40,104, +99,104,20,150,107,150,66,104,66,230,101,196,110,36,241,36,118,188,247,178, +136,36,137,186,214,244,215,36,136,84,213,84,136,130,213,131,74,12,44,64, +19,88,104,58,49,58,36,100,99,100,18,152,103,152,60,100,60,236,105,202, +128,54,247,54,172,10,146,80,103,130,142,242,142,100,220,100,220,240,195,242, +142,140,221,140,142,182,221,183,56,14,32,68,13,94,96,58,39,58,32,98, +91,98,22,144,99,144,56,98,56,220,95,190,86,238,106,208,118,170,118,70, +243,70,210,30,231,52,118,116,160,116,158,190,152,198,144,202,133,198,192,12, +192,154,200,198,216,232,224,238,232,236,238,224,239,206,226,104,202,178,174,216, +151,237,56,12,36,54,11,84,104,58,33,58,28,98,93,98,16,148,99,148, +56,98,56,224,99,194,128,54,233,54,122,82,141,114,214,80,197,116,108,136, +239,136,172,10,172,140,156,188,136,216,103,242,234,236,212,216,188,178,173,137, +54,14,36,54,11,86,94,58,35,58,28,102,93,102,16,148,93,148,58,102, +58,224,99,194,114,152,241,152,114,60,233,40,110,124,164,102,219,62,144,10, +150,58,176,98,210,124,224,122,235,102,146,152,146,186,130,218,101,242,188,152, +188,220,194,232,206,236,226,236,238,222,241,209,57,16,50,14,36,60,13,94, +90,60,37,60,34,100,87,100,22,144,91,144,56,100,56,218,91,184,100,34, +171,34,120,58,108,118,173,118,150,34,150,238,123,240,96,210,126,168,149,132, +190,242,190,34,232,34,212,110,224,126,236,148,240,166,238,186,224,196,209,201, +66,16,48,52,21,84,100,60,41,60,38,104,99,104,18,148,103,148,62,104, +62,224,97,188,112,34,143,82,232,34,199,78,110,110,222,110,223,240,118,162, +223,162,108,220,223,220,170,110,171,13,65,14,58,12,42,52,15,94,104,58, +41,58,34,100,97,100,20,146,105,146,62,100,62,230,99,196,220,88,220,30, +136,30,136,88,221,88,120,220,120,130,232,130,232,212,207,218,176,242,177,89, +60,16,40,58,17,90,98,60,41,60,36,100,93,100,22,144,99,144,60,100, +60,224,97,192,114,242,114,34,228,34,229,242,114,212,229,212,132,98,213,98, +170,52,170,110,158,154,137,184,206,180,188,140,171,109,56,14,34,58,13,86, +100,64,31,64,30,108,99,108,18,154,103,154,62,108,62,232,103,200,120,28, +120,76,222,76,223,28,168,76,169,12,120,112,216,112,216,162,126,162,126,222, +132,232,148,238,216,238,230,228,237,207,54,12,32,60,11,84,102,56,35,56, +30,96,95,96,16,142,101,142,58,96,58,222,93,184,138,32,113,88,224,68, +123,68,110,120,239,120,170,246,171,10,104,218,146,166,171,120,234,212,196,166, +171,121,50,16,30,60,11,86,78,60,33,60,100,52,134,52,104,128,136,128, +130,172,118,204,83,240,26,100,83,100,18,148,87,148,54,100,54,226,85,194, +98,158,118,200,138,218,166,226,239,232,226,32,184,40,153,44,152,104,233,104, +148,182,241,182,192,182,193,39,54,16,34,68,13,102,104,68,35,68,32,110, +95,110,18,156,95,156,60,110,60,234,99,200,222,30,168,40,121,44,120,94, +229,94,116,144,247,144,172,144,173,40,194,182,231,236,170,152,122,232,219,221, +54,14,32,66,15,92,100,60,35,60,32,102,95,102,20,148,103,148,62,102, +62,226,99,198,144,16,128,52,105,86,134,142,135,42,224,34,188,72,153,102, +180,10,180,116,184,128,194,132,222,132,232,118,235,102,106,174,243,174,168,244, +169,143,62,14,38,60,11,92,112,62,37,62,30,102,95,102,20,150,99,150, +66,102,66,228,107,196,170,12,148,58,115,102,240,94,202,66,167,20,130,106, +219,106,126,160,219,160,108,228,243,228,172,228,173,107,60,12,40,54,13,84, +98,58,39,58,32,100,85,100,18,150,97,150,60,100,60,228,101,196,166,12, +140,70,105,106,236,110,200,78,180,48,163,22,132,110,199,110,128,242,128,146, +212,146,213,242,128,216,213,217,56,12,40,52,17,88,100,56,39,56,34,98, +95,98,18,144,101,144,60,98,60,222,93,184,128,26,180,56,225,92,210,18, +168,60,121,92,108,128,243,128,170,92,170,236,141,242,136,158,109,218,200,158, +233,217,54,12,38,56,13,92,92,54,39,54,34,98,89,98,20,146,93,146, +58,98,58,224,93,188,108,64,131,100,146,16,146,150,132,194,95,240,110,162, +147,132,182,14,182,214,184,222,194,230,220,230,234,222,241,202,222,58,197,102, +222,166,183,127,60,12,42,50,11,82,108,54,41,54,28,96,103,96,22,142, +105,142,60,96,60,222,101,192,164,12,140,52,107,80,128,86,218,86,219,192, +114,126,247,126,120,172,219,172,176,86,206,40,149,40,166,86,166,224,162,234, +156,238,137,239,56,12,38,50,15,80,94,58,33,58,28,102,97,102,14,146, +101,146,60,102,60,224,99,194,158,12,134,54,111,80,238,198,232,218,218,228, +144,228,134,224,130,208,130,88,226,88,226,152,131,152,178,152,179,88,184,88, +206,40,143,41,58,10,40,48,15,82,98,50,41,50,112,66,241,66,32,98, +99,98,18,148,105,148,62,98,62,230,103,198,150,14,185,48,163,72,192,94, +235,140,162,72,118,134,221,124,98,240,128,218,146,182,149,130,240,206,236,222, +218,234,196,234,188,230,189,129,50,14,38,58,11,100,92,62,37,62,32,102, +87,102,20,148,97,148,58,102,58,228,95,200,100,26,129,60,100,86,121,116, +98,238,123,152,140,34,214,34,158,108,232,108,228,220,222,232,208,236,189,238, +138,186,170,144,181,108,140,232,178,200,198,158,211,109,62,16,44,58,15,94, +104,62,43,62,32,104,97,104,20,154,103,154,62,104,62,228,105,198,156,22, +195,50,130,96,130,62,230,62,231,96,114,134,245,134,178,80,142,178,241,236, +110,240,148,230,188,200,209,135,60,12,40,54,15,88,96,60,37,60,30,104, +89,104,16,154,91,154,54,104,54,228,91,200,94,82,158,82,150,148,126,202, +87,240,166,210,110,158,135,20,186,242,186,62,230,62,231,238,186,214,231,215, +62,14,44,60,13,96,100,60,45,60,36,104,93,104,18,152,101,152,64,104, +64,222,103,194,108,50,243,50,148,84,149,14,194,84,195,14,116,134,116,104, +232,104,233,136,130,152,212,152,208,210,204,226,192,232,173,236,94,236,126,218, +146,192,156,164,163,119,56,14,38,54,15,90,98,52,41,52,32,98,93,98, +22,144,95,144,58,98,58,224,93,188,122,50,233,50,116,78,139,110,216,74, +191,114,104,126,243,126,96,214,128,182,152,148,165,126,242,208,202,176,182,148, +175,126,166,244,167,13,52,12,34,58,11,86,90,56,35,56,28,102,85,102, +16,150,89,150,54,102,54,230,83,204,110,144,101,192,130,96,149,126,160,140, +179,184,130,140,130,214,134,224,140,230,150,230,158,220,163,204,98,76,239,76, +180,14,186,124,200,190,218,228,228,234,234,228,241,200,206,26,225,55,56,14, +38,62,13,92,98,62,39,62,30,104,95,104,18,152,99,152,56,104,56,228, +93,198,116,130,117,24,146,136,147,18,166,122,204,84,222,48,228,34,165,34, +174,34,182,68,204,104,239,130,112,174,223,174,94,228,241,228,164,138,165,229, +66,12,46,62,17,98,110,62,47,62,40,106,109,106,24,148,113,148,66,106, +66,228,105,194,220,90,220,34,136,34,136,90,221,90,116,126,241,126,124,170, +235,170,110,228,245,228,176,228,177,127,64,12,38,60,15,84,96,60,39,60, +30,102,99,102,18,148,105,148,62,102,62,230,103,200,222,130,222,32,120,32, +120,130,223,130,120,82,223,82,110,174,231,174,98,228,243,228,172,228,173,33, +56,12,36,56,15,86,104,56,37,56,30,100,95,100,16,148,101,148,58,100, +58,226,101,196,140,36,130,66,117,94,228,64,133,64,108,120,243,120,176,120, +177,12,134,244,134,158,216,158,217,242,134,224,217,225,52,10,34,56,11,92, +88,60,33,60,28,100,85,100,14,144,97,144,96,84,241,84,54,100,54,226, +85,198,150,28,124,36,101,40,128,36,128,236,103,240,90,174,161,134,174,10, +174,90,182,152,200,200,218,224,228,228,238,220,243,202,220,114,196,172,155,226, +202,28,229,63,58,14,38,58,13,88,104,60,39,60,34,100,97,100,22,148, +103,148,62,100,62,228,101,196,142,42,128,84,113,126,154,118,129,84,216,42, +208,82,195,120,240,118,209,78,118,164,229,164,104,222,247,222,172,222,173,11, +60,12,42,58,15,94,100,58,43,58,36,102,99,102,20,146,105,146,64,102, +64,228,109,208,120,136,243,136,230,20,166,34,111,38,128,64,139,106,168,58, +175,98,224,50,203,94,138,164,165,196,208,120,208,234,177,241,58,10,38,54, +13,86,92,56,39,56,30,100,91,100,16,146,97,146,58,100,58,222,95,188, +156,14,185,40,116,56,239,56,190,86,225,130,168,62,118,120,211,112,136,144, +132,194,120,218,103,238,168,242,169,142,202,142,202,220,206,228,216,236,224,236, +232,230,241,213,60,10,38,58,13,86,94,60,37,60,32,100,89,100,20,150, +93,150,58,100,58,228,91,202,113,20,112,242,113,60,112,18,141,52,162,40, +228,40,228,238,203,242,136,86,205,86,134,140,207,140,154,86,154,146,148,180, +135,208,184,212,185,87,60,14,40,56,17,90,94,60,39,60,32,104,91,104, +22,148,93,148,58,104,58,228,93,198,112,242,113,60,114,22,135,48,160,42, +228,42,228,236,199,242,192,188,192,92,146,92,146,188,193,188,146,138,193,139, +54,16,36,56,13,90,104,58,37,58,32,102,99,102,20,158,109,158,62,102, +62,236,103,202,154,16,185,38,174,214,132,238,132,54,220,54,220,138,133,138, +132,94,221,94,234,236,208,214,188,182,175,138,228,162,197,193,52,10,36,56, +13,92,96,56,37,56,34,100,93,100,18,142,89,142,58,100,58,222,97,188, +116,30,216,30,216,92,117,92,124,60,217,60,110,148,110,120,228,120,229,148, +130,152,202,152,178,192,144,218,99,238,236,238,202,226,174,210,150,186,131,153, +56,14,38,58,15,86,98,58,39,58,32,102,91,102,18,146,101,146,58,102, +58,216,93,186,92,234,112,200,124,154,124,32,222,32,222,76,125,76,124,112, +232,112,232,228,199,240,198,194,198,146,150,146,150,194,199,195,54,12,34,60, +13,88,30,102,81,102,84,60,35,60,16,148,87,148,52,102,52,216,85,190, +102,240,102,38,142,38,126,100,140,122,146,144,144,168,134,182,125,184,164,38, +249,38,226,38,226,232,195,238,198,164,198,88,166,88,166,164,199,165,56,16, +38,62,13,100,98,64,39,64,34,102,87,102,20,146,97,146,62,102,62,226, +103,202,108,104,243,104,114,40,231,40,118,72,225,72,168,104,169,12,130,242, +130,132,214,132,214,240,185,242,130,166,215,166,130,198,213,199,54,14,34,62, +11,88,94,62,35,62,28,102,87,102,18,148,95,148,62,102,62,224,95,200, +114,50,237,50,140,86,141,12,196,86,197,10,108,110,245,110,166,78,136,138, +107,174,134,240,134,156,212,156,213,238,134,216,213,217,52,10,34,56,11,88, +30,100,83,100,90,58,33,58,16,146,95,146,54,100,54,224,85,196,110,48, +235,48,162,10,148,66,124,96,101,116,238,110,210,96,188,74,173,48,124,122, +211,122,164,154,165,82,106,178,235,178,132,146,130,188,118,212,95,236,200,142, +201,243,60,10,38,56,13,84,104,56,39,56,32,98,97,98,20,146,93,146, +62,98,62,228,105,196,212,96,212,28,128,28,128,96,213,96,128,62,213,62, +108,128,235,128,106,164,245,164,130,182,159,212,200,128,200,236,173,243,58,14, +36,68,15,98,98,68,37,68,32,110,91,110,22,152,95,152,58,110,58,230, +95,184,222,114,222,32,122,32,122,114,223,114,122,72,223,72,170,244,171,32, +114,146,245,146,96,230,142,186,167,146,238,230,208,200,192,172,181,147,56,12, +34,60,13,86,102,60,35,60,30,100,95,100,18,150,99,150,62,100,62,232, +103,204,218,112,218,30,126,30,126,112,219,112,126,72,219,72,126,132,126,234, +167,210,126,170,165,170,188,130,188,220,194,232,206,238,226,238,236,226,243,210, +236,154,189,179,54,14,38,60,13,96,98,62,39,62,34,102,95,102,18,150, +101,150,60,102,60,234,97,200,118,244,118,36,228,36,229,240,118,220,229,220, +140,88,207,88,198,180,198,132,148,132,148,180,199,180,170,132,171,59,116,80, +134,48,147,14,56,12,38,60,15,96,42,100,91,100,100,60,39,60,123,130, +190,156,210,160,222,154,230,58,129,58,122,130,154,92,169,58,26,146,99,146, +66,100,66,222,95,206,110,228,127,184,168,164,185,192,222,188,241,222,152,176, +152,220,158,230,168,236,194,236,204,226,209,210,138,156,170,122,188,94,203,59, +56,10,36,62,13,94,96,62,37,62,120,54,233,54,32,104,91,104,112,120, +245,120,154,14,187,42,132,72,155,106,212,70,179,120,18,150,101,150,60,104, +60,230,101,198,132,244,132,158,214,158,215,240,132,218,215,219,50,14,36,60, +13,98,90,58,39,58,116,72,229,72,84,100,35,100,106,106,241,106,20,142, +87,142,110,148,146,104,160,54,169,14,116,24,137,50,212,26,197,54,238,158, +212,136,189,106,172,198,184,196,194,188,194,148,138,148,138,208,142,224,156,234, +210,234,222,224,231,204,60,100,60,226,101,203,52,18,42,56,9,108,102,58, +43,58,134,32,123,70,34,102,95,102,112,120,152,92,168,54,175,16,226,118, +163,72,220,36,205,74,132,140,117,182,22,146,109,146,65,102,102,238,136,218, +162,182,168,144,169,110,95,206,92,216,62,226,63,102,240,236,214,222,190,200, +174,172,167,156,220,144,207,179,138,18,108,74,139,114,180,20,152,72,183,110, +228,18,198,72,233,110,120,242,120,132,222,132,223,240,120,174,223,174,120,220, +223,220,170,220,171,132,56,12,38,58,17,88,92,60,37,60,36,102,91,102, +24,144,101,144,60,102,60,224,97,193,102,40,155,40,104,72,153,72,102,110, +155,110,174,34,224,34,220,104,216,114,207,118,190,34,186,82,182,104,177,120, +126,140,127,12,50,10,34,50,11,88,80,52,35,52,80,96,35,96,82,144, +21,144,92,166,239,166,92,196,56,224,57,96,96,236,124,222,148,198,160,166, +163,142,236,236,204,220,180,200,161,167,60,12,40,54,13,84,104,56,39,56, +32,98,97,98,20,150,101,150,60,98,60,224,99,196,124,12,124,110,165,94, +124,56,165,56,188,12,188,98,196,108,210,112,226,112,234,102,241,88,236,40, +189,58,124,244,124,144,216,144,217,244,124,184,217,184,124,222,217,222,166,118, +159,145,58,8,34,56,11,82,102,58,33,58,26,102,99,102,14,150,107,150, +220,126,220,30,124,30,124,126,221,126,124,78,221,78,172,126,173,30,124,170, +103,226,164,144,193,184,216,162,247,210,150,170,150,218,156,232,170,236,200,236, +212,224,217,206,58,102,58,232,95,195,22,148,95,148,114,144,247,144,32,102, +95,102,116,108,231,108,156,76,156,28,116,28,116,76,157,76,224,76,224,28, +180,28,180,78,225,78,144,144,138,180,218,180,214,212,210,224,196,232,165,234, +62,102,62,228,101,196,58,10,36,58,15,86,92,60,37,61,148,116,116,126, +117,246,190,120,220,120,221,242,116,218,221,218,220,22,174,30,107,34,54,14, +40,56,13,98,96,54,41,54,92,102,37,102,100,80,245,80,24,148,91,148, +58,102,58,232,91,202,169,218,170,218,171,30,117,168,116,168,149,168,188,166, +221,167,120,142,210,142,186,182,164,204,136,222,95,238,236,234,206,224,178,208, +154,186,140,166,131,142,168,142,169,6,146,26,118,32,118,108,222,108,222,30, +193,30,194,70,223,70,144,72,119,72,54,6,36,54,11,94,98,54,37,54, +90,98,35,98,94,144,17,144,56,98,56,224,97,193,54,14,36,54,15,88, +96,54,37,54,30,96,89,96,22,142,95,142,58,96,58,214,89,180,222,18, +164,30,115,34,120,54,137,78,158,50,175,74,110,92,233,92,212,44,185,92, +102,124,241,124,82,228,116,202,140,160,148,120,151,92,116,238,152,226,192,192, +214,154,143,154,236,238,198,222,168,196,141,161,58,8,32,62,13,86,94,62, +33,62,30,106,93,106,14,152,101,152,58,106,58,232,89,212,152,10,185,36, +102,48,239,48,216,130,216,80,128,80,128,130,217,130,92,188,132,168,167,130, +178,206,142,234,143,158,176,154,188,182,204,206,235,236,230,148,193,187,58,10, +32,54,15,74,104,54,33,54,32,98,99,98,16,146,99,146,60,98,60,232, +99,204,120,28,147,58,220,26,191,58,110,76,239,76,170,126,171,12,112,128, +150,100,171,80,234,126,212,114,192,96,175,76,108,164,241,164,166,140,134,194, +231,234,204,164,194,190,172,218,140,232,107,241,66,12,44,54,17,90,90,54, +45,54,26,100,95,100,18,146,95,146,60,100,60,226,95,200,128,244,129,16, +98,64,117,96,88,174,129,132,188,14,172,50,149,86,162,126,196,104,220,76, +232,50,173,50,174,78,203,96,142,146,249,146,214,112,214,236,183,240,162,162, +181,195,54,16,38,56,17,88,88,62,35,62,32,102,81,102,22,146,85,146, +58,102,58,222,95,194,100,38,218,38,218,70,104,70,104,100,232,100,230,118, +222,128,207,132,110,142,134,118,144,96,147,16,182,136,183,14,120,212,120,152, +214,152,215,210,98,240,130,230,154,212,166,188,169,168,174,208,225,241,54,14, +36,54,13,84,96,58,35,58,28,100,93,100,16,150,99,150,58,100,58,224, +91,190,98,234,112,204,122,154,122,34,224,34,224,84,123,84,174,84,175,34, +148,244,148,120,226,120,227,246,148,156,227,156,148,188,227,188,148,222,227,223, +48,12,34,50,9,88,88,56,31,56,28,98,85,98,14,144,91,144,54,98, +54,224,87,198,98,42,229,42,212,144,212,80,112,80,112,144,213,144,140,80, +141,12,184,80,185,12,112,110,213,110,94,178,239,178,98,240,134,222,156,200, +164,174,165,144,232,238,204,226,180,206,165,179,64,10,40,58,15,90,102,60, +39,60,32,104,99,104,22,150,103,150,62,104,62,228,101,200,104,32,241,32, +212,98,212,62,134,62,134,98,213,98,118,242,118,130,228,130,228,236,205,242, +148,150,161,170,197,150,140,184,203,184,196,150,177,184,172,230,173,185,56,10, +38,56,17,88,98,56,39,56,34,100,99,100,24,146,105,146,64,100,64,226, +105,190,142,14,120,56,101,82,126,148,127,44,166,16,195,34,134,48,239,48, +134,76,231,76,134,104,233,104,136,132,245,132,118,158,214,158,202,188,234,188, +230,212,224,222,212,230,198,234,183,234,94,238,120,224,144,194,157,158,182,132, +183,49,58,14,34,64,13,88,90,64,35,64,28,104,89,104,16,152,95,152, +58,104,58,224,93,196,168,14,136,54,101,82,162,20,192,52,239,78,136,70, +195,70,208,122,208,92,130,92,130,122,209,122,216,138,164,146,115,146,118,172, +223,172,106,196,237,196,140,240,160,238,168,232,172,224,173,147,54,14,32,62, +11,90,92,62,33,62,30,102,87,102,18,148,95,148,58,102,58,224,99,192, +144,56,163,88,158,20,114,38,114,108,153,72,172,30,230,30,230,84,228,102, +220,108,207,108,162,116,178,100,188,80,194,48,193,30,122,242,122,136,226,136, +227,242,122,178,227,178,122,222,227,222,172,222,173,137,58,12,38,56,13,90, +96,58,37,58,30,104,95,104,18,150,97,150,58,104,58,228,99,188,122,24, +151,56,102,72,245,72,210,16,177,72,152,90,103,130,182,92,241,132,92,230, +245,230,122,230,122,146,220,146,221,230,154,230,155,146,186,230,187,147,56,8, +30,62,13,84,90,60,33,60,32,102,89,102,18,148,95,148,56,102,56,228, +97,198,148,16,183,34,116,74,116,50,228,50,229,74,126,88,217,88,114,134, +146,120,168,102,181,88,152,116,168,130,180,156,184,184,184,212,172,234,145,238, +170,134,146,154,111,176,180,166,146,194,109,218,226,118,179,150,202,136,214,182, +237,221,52,12,34,60,15,90,92,60,37,60,34,102,95,102,22,148,101,148, +60,102,60,226,105,196,146,16,185,36,112,82,112,50,228,50,229,82,100,176, +243,176,206,76,166,88,132,92,133,176,132,126,229,126,192,176,193,126,150,196, +95,242,184,198,235,241,60,8,38,54,15,82,96,54,39,54,32,96,95,96, +20,144,99,144,60,96,60,218,99,190,102,24,239,24,222,100,222,58,118,58, +118,100,223,100,154,100,155,24,188,100,189,24,120,132,221,132,108,164,243,164, +168,164,168,238,145,244,140,186,93,228,196,188,237,229,56,16,32,62,13,82, +94,60,35,60,28,104,91,104,18,152,97,152,58,104,58,232,93,204,114,24, +145,56,220,26,195,56,108,114,108,78,232,78,233,114,168,78,169,14,204,150, +204,110,134,110,134,150,205,150,114,188,225,188,98,228,243,228,166,228,167,161, +60,12,36,56,13,80,104,56,37,56,30,100,99,100,20,150,105,150,62,100, +62,228,105,196,220,78,220,24,138,24,138,78,221,78,138,50,221,50,230,138, +230,106,122,106,122,138,231,138,156,138,157,106,194,138,195,106,126,164,212,164, +196,190,174,212,142,228,111,238,238,234,198,220,168,200,139,165,62,12,44,60, +13,98,98,58,45,58,38,100,93,100,26,144,101,144,66,100,66,222,103,196, +220,88,220,26,124,26,124,88,221,88,124,56,221,56,172,88,173,26,206,144, +237,176,206,110,128,170,223,162,166,96,118,134,175,134,172,168,172,234,149,240, +140,190,101,228,200,192,239,227,56,8,36,60,13,88,94,58,37,58,26,100, +89,100,16,148,95,148,56,100,56,222,87,196,156,10,185,30,240,42,110,42, +110,162,106,198,91,238,110,96,249,96,130,70,220,70,220,122,131,122,132,244, +132,148,226,148,226,238,203,242,132,172,227,172,132,200,227,200,178,240,179,43, +52,12,32,62,13,88,80,62,33,62,28,104,81,104,18,152,83,152,52,104, +52,222,77,194,104,20,127,50,92,68,145,68,108,68,106,162,98,200,75,238, +106,116,136,116,130,236,113,240,180,14,162,68,145,98,238,62,165,62,182,84, +168,116,155,142,230,112,173,112,154,162,241,162,194,112,192,166,176,208,149,240, +234,236,212,208,200,186,193,169,48,12,32,58,9,90,91,56,88,58,33,58, +30,98,81,98,18,146,91,146,56,98,56,228,87,206,110,24,131,54,90,76, +155,76,112,76,112,172,102,212,87,242,112,120,144,120,140,230,119,234,194,18, +174,72,155,100,242,58,181,58,168,102,232,102,223,138,176,136,168,190,151,242, +170,176,182,206,212,228,243,232,198,102,199,218,234,168,199,169,56,12,36,60, +15,90,96,66,33,66,106,46,245,46,150,12,183,36,34,102,95,102,20,150, +99,150,62,102,62,226,99,202,116,242,116,100,226,100,226,236,201,240,132,64, +153,90,206,60,183,100,136,132,205,132,198,200,198,164,148,164,148,200,199,200, +170,164,171,109,60,8,36,56,11,84,92,56,37,56,30,98,93,98,16,146, +101,146,62,98,62,224,95,196,100,26,237,26,226,88,226,58,114,58,114,88, +227,88,152,88,153,26,188,88,189,26,218,174,218,116,122,116,122,174,219,174, +122,146,219,146,108,204,239,204,170,244,171,175,48,12,30,58,11,84,82,56, +33,56,24,98,77,98,14,144,81,144,50,98,50,216,77,196,238,34,98,34, +98,166,92,206,75,240,118,50,135,78,114,96,171,96,168,50,147,96,122,122, +122,176,169,172,168,188,169,126,144,96,144,178,132,206,111,232,202,48,192,82, +179,110,220,122,228,94,189,94,194,122,194,170,178,208,151,238,236,232,210,204, +195,171,64,16,44,64,17,98,92,62,45,62,90,104,35,104,24,148,99,148, +60,104,60,222,93,198,106,32,127,60,222,34,201,60,96,82,241,82,148,82, +149,14,182,82,183,12,104,124,229,124,132,94,153,116,206,92,183,124,114,156, +221,156,100,180,241,180,164,124,162,184,146,210,124,228,99,238,226,238,200,224, +178,204,163,185,56,18,38,60,15,92,94,60,39,60,34,104,89,104,24,150, +95,150,60,104,60,224,99,198,156,14,138,32,115,56,222,118,222,64,116,64, +116,118,223,118,116,92,223,92,168,118,169,64,168,64,190,34,137,34,102,144, +243,144,126,242,126,170,212,170,213,242,126,198,213,198,126,226,213,227,50,12, +30,60,11,88,74,60,31,60,28,102,79,102,20,146,77,146,54,102,54,226, +81,204,112,16,135,44,96,58,163,58,146,116,146,88,102,88,102,116,147,116, +96,144,152,144,126,168,126,238,105,244,98,194,163,180,194,12,184,58,165,104, +240,72,179,72,178,112,186,150,200,186,226,222,237,234,152,238,178,212,204,172, +214,120,217,73,56,12,34,58,13,86,88,58,35,58,30,102,85,102,20,150, +91,150,54,102,54,226,89,200,110,18,135,48,106,242,107,60,156,40,226,40, +226,236,199,242,124,86,207,86,164,232,165,58,200,156,200,110,128,110,128,156, +201,156,142,124,153,144,186,124,175,142,124,212,165,160,202,206,165,169,58,6, +38,52,17,82,90,52,39,52,86,94,35,94,22,138,93,138,60,94,60,218, +101,194,126,10,151,34,104,46,237,46,206,8,183,46,108,70,131,94,222,64, +207,96,96,112,241,112,148,112,149,46,182,112,183,46,124,242,124,142,210,142, +211,242,124,180,211,180,124,218,211,219,54,8,30,56,11,82,88,58,31,58, +30,100,85,100,18,146,91,146,56,100,56,228,91,202,144,10,181,28,106,70, +106,44,234,44,235,70,146,56,103,96,184,56,237,90,216,132,216,102,118,102, +118,132,217,132,110,214,110,162,228,162,229,214,166,244,167,72,110,196,229,197, +52,14,32,62,11,90,92,62,33,62,32,104,83,104,18,150,85,150,58,104, +58,222,95,198,92,32,132,32,132,92,104,92,104,148,130,148,126,218,118,232, +99,230,218,80,218,32,166,32,166,80,219,80,226,164,226,116,158,116,158,164, +227,164,216,186,241,236,148,226,229,214,190,80,191,219,54,14,34,58,13,84, +90,56,37,56,30,102,85,102,22,150,93,150,58,102,58,222,97,196,106,34, +156,34,140,82,101,128,112,60,139,82,176,24,194,74,216,102,235,122,222,28, +189,56,236,60,205,86,146,100,195,100,210,176,210,134,126,134,126,176,211,176, +104,232,239,232,134,194,155,220,204,190,183,233,52,16,30,62,9,86,96,62, +31,62,30,104,87,104,18,150,97,150,60,104,60,226,97,202,104,40,241,40, +146,14,147,60,198,12,199,60,132,64,114,96,99,116,126,168,127,76,164,60, +185,78,134,86,233,86,132,110,225,110,132,134,225,134,132,158,241,158,241,158, +176,158,177,86,116,178,212,178,184,206,148,226,103,238,234,236,194,226,152,202, +133,179,54,12,36,54,15,84,92,54,37,54,34,96,89,96,18,140,91,140, +60,96,60,218,97,188,220,76,220,28,114,28,114,76,221,76,150,76,151,28, +184,76,185,28,106,126,145,86,124,108,228,108,224,208,220,222,210,236,187,236, +190,174,190,140,120,140,120,174,191,174,182,186,205,216,106,212,195,204,154,206, +155,121,54,12,32,60,13,82,90,60,33,60,28,100,87,100,16,146,93,146, +58,100,58,220,95,182,156,16,187,30,114,44,231,44,102,84,241,84,134,56, +153,76,204,54,185,84,218,158,218,108,126,108,126,158,219,158,126,134,219,134, +118,180,101,228,160,172,185,194,214,180,243,222,142,180,142,218,146,232,154,236, +186,236,202,226,209,213,54,14,32,62,13,86,86,60,33,60,28,102,85,102, +16,146,89,146,58,102,58,226,95,198,148,16,179,34,108,72,108,46,232,46, +233,70,138,60,99,116,99,166,96,164,128,138,150,110,160,84,121,84,130,102, +145,114,114,122,129,136,174,68,186,100,196,120,218,142,239,156,180,82,220,82, +201,122,144,140,193,140,114,176,225,176,170,176,170,242,147,248,138,194,103,238, +194,196,233,237,54,12,34,60,13,90,88,60,35,60,32,102,87,102,18,148, +91,148,60,102,60,216,83,198,158,10,183,32,242,40,114,40,114,168,102,210, +91,234,114,74,230,74,230,106,115,106,154,50,155,106,190,106,191,50,142,114, +142,178,171,166,142,142,169,142,194,114,194,166,200,178,206,180,226,180,234,170, +239,158,238,128,195,142,140,200,119,240,162,204,167,240,188,202,199,234,216,196, +237,237,56,10,40,54,13,94,98,52,43,52,220,18,168,30,121,34,244,62, +113,62,36,100,95,100,22,144,101,144,62,100,62,222,97,190,222,160,222,94, +124,94,124,160,223,160,116,194,229,194,98,228,243,228,124,126,223,126,172,228, +173,31,54,12,38,58,23,86,106,58,39,58,24,126,109,126,28,230,52,198, +66,158,72,110,73,58,106,200,69,148,120,30,178,30,178,82,136,82,132,144, +176,144,172,208,168,218,158,228,131,228,222,238,223,13,48,18,38,64,17,104, +98,64,39,64,14,134,101,134,64,64,62,138,54,180,42,210,23,234,100,200, +61,158,138,40,109,124,154,120,125,82,212,44,189,128,236,124,203,82,110,166, +227,166,98,228,239,228,168,228,169,11,50,12,40,52,25,90,104,54,41,54, +16,122,111,122,68,54,64,128,52,178,25,222,110,200,63,138,146,12,124,62, +99,102,132,240,133,46,172,14,199,44,132,60,241,60,132,110,233,110,132,158, +231,158,132,208,245,208,186,208,187,61,96,26,68,34,29,38,22,96,105,96, +68,244,69,34,16,188,46,152,69,108,100,152,69,116,128,24,128,224,165,198, +166,94,129,94,186,16,186,212,194,228,206,230,222,230,236,218,241,196,238,70, +187,121,108,20,68,30,25,36,22,90,103,90,70,244,71,30,18,178,48,136, +71,98,104,146,71,110,232,42,174,54,126,58,122,124,232,124,228,182,226,192, +218,198,201,198,176,244,177,12,102,208,142,174,177,131,92,24,62,34,21,38, +16,94,95,94,60,246,61,34,14,184,40,148,61,112,94,154,61,116,102,62, +233,62,108,120,221,120,164,246,165,12,88,214,128,178,165,126,234,212,206,190, +165,127,100,26,68,36,29,40,24,94,103,94,68,244,69,36,22,184,48,144, +69,102,100,148,69,110,196,24,221,56,114,80,233,80,168,246,169,12,100,196, +140,144,169,86,230,192,196,148,169,93,104,16,66,26,29,34,20,84,107,84, +68,242,69,26,22,182,69,102,100,144,69,110,218,94,218,30,134,30,134,94, +219,94,122,240,122,138,230,138,231,238,122,208,231,209,100,28,68,36,27,42, +22,92,109,92,70,244,71,36,18,184,46,148,71,102,100,152,71,118,114,60, +239,60,186,22,213,44,162,12,162,66,148,102,119,134,182,60,182,122,184,130, +194,134,226,134,234,122,241,104,222,162,223,242,124,160,124,228,223,224,170,144, +171,227,98,28,60,36,23,38,16,92,105,92,62,244,63,36,22,188,46,150, +63,114,96,150,63,108,226,18,170,30,115,34,120,56,145,88,160,50,179,78, +224,44,199,88,118,108,220,108,176,144,176,222,172,232,160,236,145,234,106,166, +245,167,100,24,64,34,27,36,18,88,101,88,66,244,67,34,20,182,48,140, +67,94,100,142,67,108,152,14,183,38,166,210,120,236,120,50,214,50,214,126, +121,126,120,90,213,90,234,232,206,210,180,174,163,126,230,148,189,187,98,28, +66,38,27,46,16,90,107,90,66,244,67,38,20,188,48,144,67,96,100,144, +67,112,114,144,239,144,218,110,218,32,130,32,130,110,219,110,172,244,173,32, +102,224,136,198,173,150,238,222,208,196,173,150,130,72,219,73,98,22,64,32, +25,38,14,90,95,90,64,240,65,32,20,182,44,144,65,100,102,148,65,110, +166,10,140,56,109,90,238,86,194,56,161,18,154,68,185,90,118,114,204,114, +177,156,112,178,95,226,148,152,177,188,210,170,239,212,138,174,138,216,140,226, +152,232,186,232,198,224,205,209,90,24,60,32,19,36,16,90,101,90,60,248, +61,32,16,180,44,140,61,98,94,146,61,110,102,48,235,48,92,190,245,190, +126,190,126,80,212,80,213,190,170,80,171,16,126,106,213,106,126,132,213,132, +126,160,213,160,146,208,101,242,184,206,231,241,94,24,60,32,21,40,16,94, +99,94,60,246,61,32,18,182,42,144,61,102,92,144,61,114,222,94,222,28, +118,28,118,94,223,94,118,62,223,62,166,94,167,28,146,106,111,136,186,108, +233,134,158,126,140,156,103,194,92,236,156,216,190,184,206,156,141,156,142,178, +182,212,241,235,88,26,60,32,25,34,18,88,95,88,60,248,61,32,16,180, +44,136,61,98,88,146,61,114,102,46,233,46,118,64,139,92,210,62,193,94, +92,108,245,108,164,106,165,8,112,246,112,142,222,142,223,244,186,200,186,168, +144,168,144,200,187,200,112,228,223,229,112,22,78,30,29,36,18,66,131,66, +78,106,79,30,18,118,54,96,79,72,126,104,79,70,80,114,48,140,17,158, +124,152,75,120,44,162,61,178,116,164,101,180,80,146,80,242,55,246,28,212, +81,192,128,216,81,186,144,240,144,136,226,136,227,240,144,218,227,218,180,136, +181,8,180,72,247,73,102,28,66,36,29,38,16,80,115,80,68,130,69,36, +18,136,48,106,69,80,112,126,69,88,40,234,40,146,100,146,101,226,40,178, +101,178,40,214,101,214,146,12,134,40,115,62,238,40,135,40,218,130,218,70, +136,70,136,130,219,130,136,100,219,100,158,138,140,158,119,178,110,238,160,218, +194,188,212,160,139,160,148,176,178,206,208,224,239,233,78,22,52,30,17,36, +16,90,85,90,52,246,53,30,12,184,36,140,53,100,80,146,53,108,146,12, +171,32,88,42,235,42,144,90,144,66,104,66,104,90,145,90,216,90,216,64, +170,64,170,90,217,90,94,116,229,116,100,140,217,140,84,164,239,164,134,164, +135,90,180,164,181,90,82,210,122,190,151,164,168,212,128,238,129,184,166,178, +188,206,233,238,214,178,189,207,32,220,32,66,88,66,89,204,32,124,89,124, +32,186,89,186,64,18,49,66,222,26,174,36,130,40,130,120,124,170,108,210, +91,236,234,236,202,210,172,174,156,140,142,102,220,102,212,134,202,160,182,194, +156,220,125,241,28,216,28,58,84,58,85,206,28,120,85,120,28,184,85,184, +54,14,41,58,156,14,183,46,106,60,237,60,144,80,109,124,192,82,229,120, +134,132,148,166,168,196,200,218,233,234,198,134,180,174,154,206,120,224,85,239, +34,218,34,64,88,64,89,208,34,194,89,194,34,126,89,126,64,20,49,64, +140,30,130,66,115,98,234,66,131,66,108,122,245,122,178,122,179,8,134,248, +134,162,220,162,221,244,134,222,221,223,16,54,117,54,68,132,69,14,16,116, +46,90,69,62,104,98,69,72,228,22,184,28,138,34,136,84,122,110,99,128, +238,76,139,76,192,134,193,76,56,244,56,154,200,154,201,242,56,190,201,190, +56,228,201,228,132,122,123,155,28,222,28,70,76,70,77,216,28,194,77,194, +28,128,77,128,218,24,162,32,109,36,162,134,163,32,120,54,141,76,92,86, +239,86,212,46,189,86,94,146,128,122,163,88,232,142,200,124,163,90,116,246, +116,148,212,148,213,242,116,186,213,186,116,224,213,224,166,224,167,149,128,22, +74,40,40,46,40,154,34,198,25,232,102,184,119,230,108,204,74,222,75,40, +240,232,198,230,158,218,132,194,118,152,112,106,111,28,154,38,146,68,135,100, +228,68,147,68,130,116,241,116,154,188,174,160,184,132,186,100,187,18,232,188, +185,135,18,56,117,56,72,20,58,70,38,94,19,110,114,104,88,74,71,56, +46,108,95,108,14,140,119,140,54,140,48,174,96,176,92,206,82,224,68,230, +51,232,220,24,178,34,138,40,138,146,128,196,105,238,188,188,205,230,170,36, +170,226,195,206,200,30,206,130,218,190,241,239,84,52,147,82,28,32,190,32, +131,74,46,240,46,88,206,88,206,228,177,238,177,238,126,232,127,88,46,132, +207,132,46,176,207,177,16,78,96,72,90,200,123,158,56,16,56,104,48,162, +23,218,162,66,187,88,186,112,204,110,216,102,220,86,220,44,140,44,140,146, +230,146,228,212,222,226,204,236,185,238,118,190,207,190,176,12,163,45,140,14, +175,32,22,66,229,38,82,14,114,48,146,70,188,86,218,90,230,88,234,82, +239,70,92,126,125,144,146,150,168,148,178,136,184,104,62,104,62,174,220,174, +214,216,206,228,196,234,169,238,26,210,185,210,98,74,87,105,42,12,42,98, +48,106,96,106,109,80,106,28,43,66,12,164,117,164,66,244,67,124,182,116, +200,114,208,108,212,94,216,38,136,38,136,146,230,146,224,216,218,228,200,238, +181,232,108,192,203,192,170,10,161,38,162,64,185,93,28,98,28,62,110,62, +111,98,68,16,60,128,46,180,21,224,78,116,78,208,115,164,188,110,208,108, +222,94,222,40,140,40,140,140,234,140,226,212,212,232,183,236,118,188,207,188, +168,60,191,88,178,10,169,41,18,72,117,72,40,230,40,134,98,134,99,230, +40,208,99,208,72,134,73,12,158,70,187,92,180,116,206,114,214,100,214,46, +136,46,136,148,228,148,224,216,216,234,181,238,118,190,207,190,172,12,155,47, +18,64,131,64,78,20,34,134,127,134,84,90,84,216,76,232,57,232,54,160, +21,220,108,160,133,212,188,120,210,118,220,104,220,52,150,52,150,148,232,148, +230,212,222,230,189,234,138,184,211,184,182,14,165,52,170,70,197,95,18,236, +32,210,40,174,44,88,112,88,113,170,112,152,43,152,72,88,73,12,72,48, +125,48,170,66,195,88,190,112,214,110,222,96,222,46,148,46,148,144,234,144, +230,212,220,232,187,238,120,188,209,188,182,10,169,47,58,18,38,66,21,96, +70,176,70,112,36,112,36,176,71,176,60,232,88,230,102,214,102,68,37,68, +168,68,189,90,182,116,204,116,216,102,216,48,144,48,144,148,230,148,230,214, +218,232,187,238,122,188,211,188,176,14,161,49,112,30,80,38,36,44,36,218, +71,188,66,214,89,230,36,112,125,112,80,38,80,118,88,178,104,218,116,224, +129,208,120,184,207,184,160,68,187,88,180,114,202,110,214,98,214,44,138,44, +138,146,228,146,224,216,210,232,183,236,176,10,161,45,77,24,108,40,40,90, +103,90,76,24,36,60,81,60,206,34,136,90,215,90,170,20,126,56,179,56, +28,110,229,110,158,172,176,170,186,160,186,136,64,136,64,190,210,190,206,224, +196,236,171,236,28,216,175,216,114,110,105,136,96,150,135,173,14,44,133,44, +30,238,30,90,122,90,122,218,116,234,95,234,76,44,63,90,60,204,61,90, +90,206,91,90,186,114,208,114,218,100,218,46,156,46,156,146,230,146,226,212, +218,234,189,234,140,186,211,186,176,68,199,90,184,12,173,47,20,44,107,44, +18,86,109,74,72,12,72,104,66,116,45,116,126,50,198,48,198,96,206,112, +220,116,237,98,162,10,156,64,148,88,123,112,126,74,179,104,160,164,180,164, +190,154,190,134,64,134,64,186,220,186,216,224,208,236,185,236,182,216,23,216, +102,152,135,168,102,110,89,135,96,26,62,36,17,44,12,90,109,90,32,242, +32,142,94,142,95,238,32,212,95,212,62,142,63,36,156,70,177,90,184,110, +208,110,214,92,214,44,130,44,130,144,228,144,226,212,218,234,187,234,108,192, +203,192,170,10,157,45,62,18,48,60,15,114,48,238,49,60,68,70,139,70, +104,240,105,12,66,164,90,122,105,74,136,140,105,90,178,64,197,86,190,108, +212,108,220,96,220,42,154,42,154,142,234,142,230,212,216,230,191,230,130,186, +211,186,182,12,169,43,112,16,141,36,32,48,229,48,100,102,101,48,156,100, +157,48,72,70,33,112,186,72,231,104,104,140,137,160,157,160,156,158,176,158, +182,144,182,122,76,122,76,182,212,182,206,220,194,236,163,236,176,210,33,210, +128,94,113,123,18,48,133,48,28,114,28,84,122,84,123,114,76,84,77,16, +38,126,102,126,76,156,76,222,68,234,47,234,22,192,117,166,174,70,197,92, +190,112,210,112,220,98,220,46,148,46,148,146,230,146,226,218,218,232,189,232, +118,188,205,188,184,10,173,47,12,38,137,38,38,122,53,160,102,120,117,158, +26,238,26,76,66,76,66,220,60,232,49,232,92,238,92,76,130,76,130,222, +122,232,111,232,180,64,197,86,186,110,208,110,218,98,218,46,160,46,160,150, +230,150,228,220,218,238,185,238,146,188,211,188,184,12,171,47,48,32,36,66, +21,92,118,66,37,66,14,122,123,122,78,122,79,12,40,240,40,156,104,156, +105,236,40,216,105,216,166,62,191,84,184,112,204,112,214,102,214,42,142,42, +142,146,228,146,224,220,212,236,183,236,124,190,209,190,172,10,159,43,64,28, +27,76,94,32,127,64,80,72,52,114,21,146,128,130,73,84,46,238,46,146, +112,146,113,238,46,218,113,218,172,72,193,94,186,120,206,120,218,108,218,50, +148,50,148,146,232,146,230,214,222,228,193,228,128,186,213,186,176,14,165,51, +24,28,53,56,28,238,29,70,66,38,124,38,124,228,116,236,97,236,50,108, +103,108,74,210,75,70,42,180,60,148,75,114,104,168,75,126,180,70,199,94, +190,120,214,120,222,102,222,48,156,48,156,146,230,146,228,212,218,232,191,232, +140,188,211,188,184,14,175,49,34,14,55,44,18,60,114,60,114,102,32,102, +32,148,118,148,118,194,108,210,93,210,72,246,73,60,102,16,77,60,20,220, +46,190,73,148,168,64,195,86,184,116,212,116,220,102,220,46,148,46,148,148, +236,148,232,220,224,234,195,234,134,194,211,194,178,12,165,47,32,48,85,48, +118,40,135,62,20,86,135,86,18,218,95,198,38,212,39,122,66,204,67,100, +66,142,91,142,100,18,100,116,108,182,118,220,130,230,140,226,147,212,132,188, +207,188,170,66,193,90,182,114,208,114,218,96,218,46,150,46,150,146,230,146, +226,220,214,236,185,236,182,14,171,47,14,58,135,58,52,96,53,14,98,94, +99,16,34,238,34,116,114,116,115,236,34,212,115,212,34,164,115,164,74,212, +75,116,188,118,210,118,222,104,222,48,152,48,152,148,234,148,230,218,220,234, +191,234,132,188,213,188,172,68,197,94,186,14,169,49,20,50,133,50,80,14, +70,54,50,82,23,102,90,66,131,94,114,172,114,110,40,110,40,172,115,172, +76,82,76,230,119,206,172,62,193,86,186,110,204,110,216,94,216,44,152,44, +152,148,234,148,230,210,216,232,183,232,208,186,133,186,184,12,171,44,40,140, +115,141,112,128,112,50,34,50,34,128,113,128,72,18,61,50,72,50,70,124, +62,144,48,160,33,170,12,186,123,186,90,146,91,242,136,196,207,196,34,90, +113,90,172,74,185,102,184,124,204,124,212,112,212,50,146,50,146,148,230,148, +226,218,216,232,191,232,174,18,169,51,56,14,83,36,20,46,127,46,110,106, +110,74,46,74,46,106,111,106,30,138,104,138,76,166,76,228,66,240,45,240, +22,204,117,176,122,192,213,192,166,64,193,90,186,116,206,116,214,104,214,46, +144,46,144,146,230,146,228,220,218,236,187,236,174,12,159,47,12,76,79,76, +28,222,28,134,66,134,67,210,28,198,67,198,46,134,47,16,68,236,88,198, +92,162,92,34,130,34,130,220,124,232,109,232,92,92,131,92,92,148,131,148, +182,62,197,90,188,114,210,114,220,102,220,44,160,44,160,146,230,146,228,218, +216,234,191,234,212,186,149,186,192,12,181,45,58,80,58,38,26,38,26,80, +59,80,114,78,114,36,82,36,82,78,115,78,32,108,113,108,14,140,123,140, +56,140,52,174,102,174,100,214,88,230,74,234,57,234,162,64,185,86,180,110, +204,104,214,92,214,42,140,42,140,144,230,144,228,212,218,230,179,230,120,184, +207,184,170,12,157,43,44,18,73,48,18,68,139,68,122,20,91,68,66,180, +79,208,76,108,24,222,73,200,58,80,26,146,59,146,122,188,141,226,134,118, +82,228,131,208,116,82,84,152,119,152,176,68,193,90,142,190,207,190,186,114, +208,114,216,96,216,48,156,48,156,148,230,148,226,214,220,226,206,236,183,236, +184,14,167,49,20,220,32,192,40,158,40,30,132,30,132,76,41,76,90,76, +91,30,64,234,64,108,130,108,131,232,64,142,131,142,64,176,131,176,64,212, +131,212,180,68,205,92,146,186,217,186,194,118,216,118,224,104,224,46,162,46, +162,146,236,146,232,218,222,236,195,236,192,12,177,47,22,70,126,70,115,98, +68,46,95,68,34,28,120,28,85,58,88,70,88,108,84,120,63,120,20,122, +56,100,87,70,174,12,160,44,143,68,240,44,161,44,160,66,176,88,200,108, +235,124,142,120,170,104,194,80,213,44,96,156,129,172,28,218,169,218,150,168, +168,168,178,154,178,138,66,138,66,190,210,190,206,214,196,234,165,242,116,110, +105,139,116,22,72,34,27,40,28,64,51,90,66,54,81,82,122,52,95,94, +52,96,42,118,27,142,118,118,43,118,14,158,127,158,116,176,117,240,38,174, +38,226,117,220,76,118,77,222,136,186,209,186,166,60,187,86,182,110,206,110, +216,90,216,44,146,44,146,144,230,144,224,212,216,234,179,234,172,12,159,45, +44,18,69,44,118,16,91,50,26,60,143,60,36,90,128,90,128,152,35,152, +24,120,147,120,66,244,67,60,98,244,99,60,24,220,50,186,67,156,134,208, +99,168,140,190,217,190,184,68,201,92,192,118,214,118,224,104,224,48,162,48, +162,150,238,150,232,220,220,238,195,238,186,12,175,49,30,106,30,34,74,34, +75,104,94,104,94,32,138,32,139,102,52,54,50,100,31,144,60,114,83,130, +116,54,114,96,99,140,124,118,145,138,18,166,147,166,78,144,50,194,137,234, +114,166,98,198,64,224,29,242,184,66,201,94,132,188,211,188,192,118,210,118, +224,104,224,42,164,42,164,148,230,148,230,214,216,232,187,232,194,12,181,43, +70,14,99,38,138,52,40,52,40,158,34,194,19,230,40,104,137,104,76,68, +76,152,116,152,117,68,66,184,47,226,80,188,93,222,102,180,117,218,124,178, +143,216,144,192,215,192,176,68,199,88,186,118,210,118,220,100,220,46,156,46, +156,152,232,152,230,216,216,234,185,234,184,12,171,47,22,36,66,36,67,108, +88,36,126,36,127,114,28,56,43,72,22,102,67,78,86,52,101,68,84,92, +127,76,86,106,50,138,19,154,78,112,141,148,90,138,66,160,37,180,108,160, +72,188,35,208,122,182,80,220,39,240,140,192,213,192,180,64,199,92,188,122, +212,122,222,104,222,42,160,42,160,148,234,148,230,220,224,236,195,236,188,12, +175,43,20,48,135,48,84,14,70,66,52,90,21,114,32,64,57,84,134,110, +71,62,120,62,103,84,114,164,114,108,42,108,42,164,115,164,42,136,115,136, +58,188,25,224,104,190,129,222,80,164,80,238,59,242,174,64,193,88,130,186, +211,186,184,112,208,112,218,94,218,44,152,44,152,146,232,146,226,216,214,234, +187,234,182,12,171,45,58,14,46,48,17,90,48,172,49,42,82,22,103,40, +48,56,133,56,54,88,127,88,54,120,127,120,54,156,135,156,90,156,91,56, +40,188,23,230,64,190,71,220,92,184,99,214,116,178,129,210,144,190,213,190, +176,70,193,96,188,120,208,120,220,106,220,48,154,48,154,154,232,154,228,220, +216,234,193,234,184,10,173,49,70,18,93,34,26,42,139,42,118,86,118,64, +48,64,48,86,119,86,54,100,25,126,104,96,121,112,82,86,82,122,61,120, +134,60,231,60,198,22,217,42,172,18,168,66,156,100,133,122,184,74,184,110, +194,120,222,120,230,110,233,96,104,158,137,174,38,220,185,220,160,172,176,172, +186,160,186,142,66,142,66,192,214,192,210,222,200,238,177,238,106,118,93,143, +27,30,14,68,122,68,109,96,56,48,87,64,26,30,104,30,79,60,80,68, +80,116,59,116,18,120,54,94,81,68,30,238,30,134,116,134,116,230,91,238, +62,148,47,166,82,148,99,166,90,204,90,174,56,174,56,204,91,204,166,64, +185,88,134,184,205,184,182,112,198,112,212,100,212,44,144,44,144,140,224,140, +224,214,212,234,181,234,178,12,165,45,18,196,71,182,54,70,67,92,56,114, +78,114,86,100,86,50,34,50,34,142,92,142,88,220,80,236,53,236,60,16, +55,50,106,44,243,44,152,62,153,14,198,62,199,16,140,66,122,100,103,126, +174,60,187,76,132,166,133,82,138,86,237,86,138,112,229,112,140,136,229,136, +140,158,243,158,184,158,185,86,116,180,214,180,190,206,156,226,111,236,138,190, +170,212,204,226,243,233,100,62,100,32,38,32,38,62,101,62,24,126,105,108, +68,62,69,116,38,78,39,122,98,86,69,86,152,20,117,60,136,40,204,40, +168,68,144,80,111,92,144,54,180,76,237,92,200,120,200,96,134,96,134,120, +201,120,90,160,135,176,32,216,179,216,158,176,174,176,186,156,186,144,66,144, +66,192,212,192,206,224,194,238,167,238,116,124,107,145,20,44,147,44,66,58, +67,14,110,58,111,14,72,102,72,74,38,74,38,102,73,102,136,102,136,72, +100,72,100,102,137,102,84,112,103,128,66,114,40,146,21,166,50,242,51,134, +140,136,59,136,58,166,131,166,58,192,131,192,58,222,141,222,142,188,213,188, +182,72,203,92,196,118,214,118,224,104,224,46,166,46,166,148,232,148,230,222, +218,238,193,238,194,12,179,46,94,222,95,137,124,18,165,46,242,60,70,60, +70,162,58,202,33,236,22,74,51,110,20,162,71,135,130,12,157,40,234,52, +64,52,64,166,52,202,27,234,22,68,39,104,18,154,65,128,86,110,243,110, +170,110,170,220,160,236,139,237,124,14,163,38,242,50,72,50,72,160,58,202, +35,238,26,74,51,106,20,154,73,126,92,98,224,98,224,176,216,194,183,194, +146,98,147,247,120,14,155,38,236,50,62,50,62,148,50,192,25,234,18,64, +41,100,14,152,63,124,82,94,239,94,134,94,130,160,108,204,75,240,132,142, +210,142,204,212,190,234,157,235,130,14,159,36,22,70,37,106,240,52,60,52, +60,160,50,198,27,234,14,158,61,136,220,244,221,96,94,104,94,222,221,222, +156,222,157,69,130,12,163,36,242,46,62,46,62,156,54,198,33,240,22,70, +45,108,20,158,63,128,234,82,102,82,102,164,92,202,75,236,118,136,220,136, +218,216,208,236,187,236,110,238,136,216,154,186,162,152,165,97,128,12,163,32, +240,44,62,44,62,154,50,206,29,240,22,66,45,100,18,156,63,132,172,70, +203,94,84,114,233,114,142,60,140,126,134,164,116,200,71,238,168,114,168,214, +172,226,184,232,218,232,232,218,237,201,130,10,163,32,240,44,62,44,62,152, +50,196,27,238,20,64,37,106,14,158,63,136,76,110,245,110,112,66,113,246, +198,64,199,246,112,160,199,160,112,220,199,221,236,52,64,52,64,166,52,204, +35,238,22,68,43,106,18,156,65,134,82,90,243,90,208,90,208,218,198,234, +175,234,166,190,166,130,110,130,110,190,167,190,124,16,159,41,122,16,157,40, +236,54,60,54,60,164,50,204,29,242,20,72,45,104,16,162,61,138,204,182, +204,92,106,92,106,182,205,182,106,136,205,136,70,226,243,227,130,16,165,38, +242,52,66,52,66,164,54,208,31,238,24,72,49,100,22,158,67,134,132,68, +110,112,89,142,236,102,115,102,144,242,145,102,228,144,145,144,232,186,145,187, +126,12,161,32,242,46,62,46,62,144,48,194,25,236,18,66,41,98,16,158, +63,126,128,60,104,104,83,136,186,192,206,192,216,174,216,94,111,94,240,198, +230,222,210,232,134,232,114,218,114,126,172,126,172,170,115,171,128,14,161,42, +238,52,62,52,62,156,48,202,29,240,18,68,43,100,18,150,63,126,134,70, +167,96,84,108,233,108,90,162,227,162,68,226,243,226,158,226,159,109,128,14, +163,38,240,50,60,50,60,168,46,212,31,242,24,70,43,102,18,162,61,134, +142,66,173,86,82,96,241,96,188,188,231,240,200,134,94,232,215,222,156,104, +100,162,169,163,130,12,165,38,244,48,58,48,58,152,44,204,23,244,18,68, +41,104,12,158,59,134,78,106,142,106,136,220,122,238,105,238,104,64,104,150, +88,202,61,242,176,244,176,94,222,94,223,242,176,218,223,219,132,10,161,38, +242,50,62,50,62,156,50,200,25,238,20,70,47,108,18,160,63,138,86,84, +229,84,70,228,243,228,138,228,139,84,176,228,177,84,90,120,102,158,111,196, +218,116,195,197,124,14,157,36,238,48,58,48,58,160,46,198,25,236,16,70, +41,102,14,154,59,132,76,84,235,84,78,112,206,112,206,140,92,140,92,168, +222,168,220,186,214,202,201,202,148,58,144,174,124,204,100,226,69,240,236,236, +202,224,172,208,143,179,122,14,159,36,238,50,60,50,60,162,46,204,21,238, +22,70,43,108,14,156,61,134,82,96,241,96,88,142,229,142,154,142,155,66, +92,176,71,230,150,160,175,196,206,166,241,216,124,168,124,222,130,234,142,238, +182,238,196,226,203,209,130,10,167,32,246,44,62,44,62,162,48,204,27,240, +16,64,41,104,12,156,63,126,94,88,231,88,132,112,133,60,186,112,187,60, +90,156,90,130,234,130,235,154,100,170,206,166,204,220,194,236,167,236,148,144, +138,188,116,220,79,241,130,12,165,36,238,48,62,48,62,150,52,202,27,240, +20,68,43,100,18,160,63,132,82,148,237,148,86,78,225,78,98,112,198,112, +197,148,136,78,127,148,108,242,108,178,210,178,211,240,108,222,211,223,128,14, +157,36,242,48,58,48,58,164,46,208,25,240,24,72,47,102,18,152,59,126, +110,82,100,124,83,160,136,144,103,114,206,82,194,120,177,152,232,146,197,116, +92,178,221,178,72,230,237,230,154,230,155,71,130,12,163,34,242,46,58,46, +58,158,50,200,29,244,22,68,45,100,16,154,59,126,88,72,119,100,94,244, +95,112,134,86,224,86,224,222,212,236,193,236,114,138,201,138,156,230,157,108, +112,198,157,148,200,192,157,151,122,14,157,38,238,50,58,50,58,172,46,206, +27,236,24,68,35,108,16,156,59,130,94,78,125,102,80,118,107,140,70,228, +113,160,134,154,151,104,204,102,237,142,220,160,190,204,156,226,109,242,178,182, +179,69,134,12,167,34,244,46,60,46,60,172,48,208,31,238,20,62,45,94, +14,154,61,126,84,80,233,80,92,128,136,104,161,80,136,104,152,126,168,162, +170,202,160,228,144,236,131,236,88,176,128,148,151,126,104,142,129,174,80,222, +134,184,165,152,214,102,163,148,238,220,216,198,202,166,193,121,122,14,153,36, +238,48,60,48,60,162,48,198,25,232,24,62,43,100,14,156,61,130,132,244, +133,68,174,242,175,66,80,102,133,102,82,146,133,146,74,190,133,190,234,104, +175,104,228,146,175,146,240,192,175,193,130,14,163,36,26,70,43,106,242,48, +62,48,62,164,50,208,35,234,18,156,63,130,98,244,98,82,224,82,225,244, +98,224,225,224,118,122,203,122,186,194,186,154,134,154,134,194,187,194,160,154, +161,95,132,12,167,32,24,62,45,98,236,44,60,44,60,156,50,202,35,232, +20,148,61,124,210,64,156,70,99,72,86,100,229,100,156,140,157,70,84,144, +128,122,157,100,232,144,196,128,176,114,159,100,78,170,235,170,144,140,112,196, +223,236,192,170,176,194,144,218,110,228,87,235,124,16,155,40,240,50,58,50, +58,182,46,214,29,244,20,68,43,106,14,160,59,138,154,62,154,138,148,176, +126,208,102,228,77,240,236,238,202,220,174,196,153,158,126,92,92,100,92,166, +218,166,218,92,177,92,126,130,93,130,178,130,219,131,128,16,159,40,22,70, +43,108,244,52,60,52,60,156,50,200,29,240,18,154,61,130,98,72,123,96, +82,108,143,108,102,108,100,154,92,198,67,236,100,146,136,146,132,222,124,232, +107,232,190,68,172,108,153,134,230,136,206,116,185,80,176,154,219,182,162,196, +225,233,132,12,163,36,242,48,60,48,60,160,52,196,31,238,20,70,43,100, +14,156,61,128,70,200,247,200,108,62,135,88,218,168,218,100,100,100,100,168, +219,168,100,134,219,134,174,100,201,58,158,246,159,101,124,10,157,32,244,44, +54,44,54,176,42,208,25,240,20,80,43,110,18,158,55,130,74,84,169,84, +190,80,191,186,226,62,226,224,210,238,187,238,152,156,152,118,88,118,88,156, +153,156,118,248,119,56,62,222,96,196,119,168,162,208,119,173,130,14,161,38, +238,48,60,48,60,148,48,200,27,240,22,66,41,102,18,154,61,126,88,86, +221,86,78,136,231,136,100,102,119,124,190,104,173,136,152,58,152,88,134,136, +112,162,81,186,236,184,204,166,173,136,102,192,207,192,153,162,70,234,239,234, +152,162,153,235,132,12,165,32,240,44,58,44,58,168,46,208,31,238,24,68, +43,102,18,156,59,132,116,64,96,114,73,150,98,242,99,108,122,110,237,110, +140,74,204,74,197,110,152,120,129,164,222,144,141,144,117,184,120,184,239,184, +176,144,176,184,158,218,127,240,176,184,192,214,218,232,235,237,134,12,167,34, +238,48,64,48,64,162,52,206,35,238,24,68,45,104,20,158,65,130,118,62, +139,86,88,94,231,94,196,60,175,94,96,126,219,126,82,156,239,156,156,94, +144,142,116,190,77,230,216,186,121,186,104,232,235,232,168,232,169,187,134,16, +165,36,242,48,60,48,60,154,48,206,33,238,156,142,157,60,102,70,131,88, +208,68,185,88,82,104,231,104,84,146,120,130,151,104,232,148,196,132,161,104, +76,172,239,172,152,148,112,200,225,236,82,236,116,230,150,218,176,198,195,172, +20,68,45,102,16,154,61,131,122,10,155,30,236,42,58,42,58,154,44,202, +25,236,22,68,41,100,16,148,59,122,90,240,90,74,136,74,136,120,91,120, +90,156,141,156,90,190,141,190,166,74,216,74,216,118,165,118,154,154,218,154, +202,190,176,216,145,234,166,170,184,198,210,218,239,229,126,14,157,32,232,42, +60,42,60,154,46,198,23,232,22,62,41,96,16,148,61,118,84,70,202,70, +178,96,152,114,122,128,79,138,234,132,188,128,140,110,95,70,140,80,157,96, +204,192,204,158,94,158,94,192,205,192,196,210,227,242,151,142,70,234,209,224, +150,142,151,227,122,16,153,40,18,74,41,110,238,48,52,48,52,178,42,212, +27,238,16,158,53,140,108,168,109,70,76,92,143,92,76,118,141,118,142,146, +75,146,160,84,220,84,216,156,210,166,191,166,182,84,180,116,174,138,166,154, +153,168,90,190,67,232,212,184,237,226,152,184,167,208,124,186,124,222,126,232, +138,236,182,236,190,228,199,211,134,14,171,34,240,46,64,46,64,158,50,200, +31,234,24,66,47,98,20,152,65,126,86,84,237,84,130,96,131,64,186,96, +187,64,214,168,214,118,102,118,102,168,215,168,102,142,213,142,76,194,241,194, +80,236,114,228,140,210,152,186,155,168,232,238,200,226,168,208,153,187,126,16, +155,32,238,44,58,44,58,166,50,202,29,240,22,72,41,108,16,150,59,134, +70,238,88,202,94,162,94,88,138,88,138,216,132,232,115,232,82,146,139,146, +118,58,105,88,110,106,123,130,110,170,123,194,161,130,162,126,174,104,174,76, +208,76,208,110,214,120,243,120,160,150,216,150,208,180,188,210,161,234,236,236, +208,216,188,194,176,170,169,151,234,40,60,40,60,138,52,190,25,236,22,60, +39,98,16,150,61,124,130,10,159,32,154,60,154,82,142,108,120,130,98,140, +77,148,240,148,216,136,192,122,172,102,155,82,94,62,123,76,86,106,121,98, +214,60,189,76,194,98,227,106,104,244,104,142,208,142,208,224,202,238,181,238, +104,172,209,172,104,200,209,201,126,12,157,32,236,44,60,44,60,150,52,196, +29,236,20,74,45,110,20,152,61,132,236,114,61,114,82,84,221,84,122,114, +123,56,178,114,179,56,206,202,206,142,96,142,96,202,207,202,96,172,207,172, +150,202,151,114,130,214,71,240,176,212,237,241,126,14,161,34,240,44,60,44, +60,154,48,198,25,232,20,72,43,102,18,150,61,128,84,74,233,74,220,136, +220,100,96,100,96,136,221,136,136,136,137,74,180,136,181,74,98,162,221,162, +76,188,243,188,156,188,156,226,148,240,129,240,76,238,113,208,190,208,227,237, +130,12,165,30,236,40,62,40,62,158,50,202,31,238,24,66,45,98,18,154, +63,124,212,118,212,66,100,66,100,118,213,118,100,92,213,92,158,118,159,66, +196,162,231,196,196,140,92,190,215,182,144,124,104,154,165,154,158,186,158,226, +150,238,131,238,118,206,75,238,186,206,237,233,132,12,161,34,242,44,58,44, +58,170,46,212,33,236,22,66,43,102,18,154,59,130,94,126,94,72,142,72, +143,124,172,124,172,72,222,72,223,124,118,88,118,118,106,142,85,160,114,126, +143,146,196,88,196,118,190,138,171,156,204,134,231,158,72,182,241,182,148,156, +116,202,229,240,192,182,174,204,148,226,112,236,79,241,124,14,161,34,236,46, +58,46,58,146,48,194,27,238,122,60,100,90,75,112,76,162,108,142,136,114, +152,84,105,84,94,118,111,138,112,100,131,120,170,68,180,100,200,128,237,154, +196,120,222,82,177,82,124,142,191,142,94,178,223,178,120,198,75,236,190,196, +231,230,160,178,160,224,152,240,135,240,20,70,37,104,16,154,59,131,234,46, +58,46,58,162,48,202,31,238,20,70,45,100,16,152,59,130,122,16,153,36, +84,242,84,78,128,78,104,132,118,146,124,160,124,178,116,188,103,192,170,56, +154,82,137,104,240,128,200,118,174,104,155,84,134,130,168,120,196,102,218,78, +157,78,152,142,221,142,158,156,150,178,139,196,236,176,153,176,148,204,229,204, +128,232,245,232,186,232,187,153,118,16,151,36,234,50,54,50,54,160,42,206, +21,242,16,72,37,108,12,156,55,128,80,248,80,80,122,80,100,136,116,152, +124,170,124,180,114,192,99,196,164,62,150,90,129,120,144,114,220,114,220,168, +143,168,148,140,221,140,138,196,123,236,182,182,199,204,220,188,241,220,162,188, +162,224,166,234,176,240,198,240,212,232,217,218,190,114,208,86,153,87,128,12, +161,32,236,42,58,42,58,162,44,208,27,238,20,64,41,98,16,152,59,124, +82,68,140,68,141,124,160,68,218,68,219,130,92,84,111,100,86,124,141,108, +170,82,189,98,162,118,219,104,156,126,112,152,77,164,146,132,188,156,235,168, +156,156,124,174,93,186,182,178,144,198,103,212,210,196,156,224,89,241,122,12, +155,36,242,44,54,44,54,164,42,208,23,240,136,66,157,96,16,74,39,110, +12,158,55,136,70,86,123,86,78,148,117,148,66,212,131,198,96,204,97,86, +122,110,177,110,126,132,179,204,160,110,156,146,146,186,130,218,113,240,180,90, +241,90,184,154,237,154,168,226,245,226,208,226,209,91,124,10,153,32,244,40, +50,40,50,176,40,210,21,238,22,70,43,102,16,152,51,126,72,86,151,86, +142,162,142,120,78,120,78,162,143,162,110,246,111,60,60,220,86,196,111,162, +142,204,111,176,192,58,178,82,159,108,166,200,166,122,228,122,229,200,198,122, +218,84,177,84,196,142,196,180,184,212,164,230,147,240,206,204,243,239,242,44, +58,44,58,174,48,206,31,236,82,108,239,108,140,54,163,70,134,12,163,32, +90,76,223,76,124,90,139,108,188,88,179,108,208,178,208,130,104,130,104,178, +209,178,104,156,209,156,92,196,69,232,152,192,169,214,210,196,241,226,24,68, +45,98,18,148,59,128,122,196,122,220,126,230,134,236,182,236,192,228,199,211, +122,14,157,30,236,40,56,40,56,146,46,196,25,240,24,70,37,102,16,152, +57,126,60,230,76,204,84,166,84,72,148,72,148,98,85,98,84,142,155,142, +158,178,83,178,110,178,111,124,138,178,139,124,88,232,115,196,136,196,153,222, +166,132,178,110,178,70,212,70,212,108,216,122,226,124,241,124,160,238,192,208, +216,172,220,150,167,150,234,234,212,216,192,190,175,151,130,12,159,32,236,44, +56,44,56,158,42,196,21,228,18,74,39,104,16,148,57,126,62,212,82,176, +90,140,90,78,140,78,140,126,91,126,100,238,100,162,140,162,141,232,100,214, +141,214,180,56,201,76,160,86,237,86,164,104,183,128,148,140,245,140,218,102, +201,140,162,186,231,186,194,244,195,141,130,16,159,32,236,44,54,44,54,166, +42,204,27,234,20,70,33,106,14,158,53,136,70,84,145,84,156,74,243,74, +60,200,157,200,84,200,84,110,138,110,139,200,104,110,111,58,84,132,139,132, +84,156,139,156,84,178,139,178,96,214,61,242,122,212,141,232,170,198,170,110, +226,110,227,196,190,110,201,74,198,132,198,190,190,218,165,244,208,212,243,241, +128,12,159,32,238,42,60,42,60,152,52,196,35,236,22,70,43,100,18,148, +61,122,89,130,140,130,140,60,94,60,94,130,141,130,94,84,141,84,94,108, +141,108,220,130,220,60,172,60,172,130,221,130,172,84,221,84,172,106,221,106, +158,142,175,152,116,140,73,190,108,160,233,160,108,184,223,184,108,208,223,208, +100,246,101,158,108,230,241,230,166,230,167,161,42,24,73,52,18,68,97,68, +32,94,47,162,20,210,97,190,86,92,57,200,100,30,160,30,160,214,148,230, +125,230,98,164,161,136,118,66,137,104,182,30,226,30,226,214,216,230,195,230, +186,70,207,98,184,162,227,131,52,16,75,46,18,66,101,66,28,104,49,164, +18,200,105,180,92,96,61,190,116,48,237,48,220,138,220,90,126,90,126,138, +221,138,172,244,173,10,98,220,140,184,173,138,238,216,198,178,173,139,98,12, +141,34,32,78,32,48,234,48,235,76,112,68,78,90,43,104,152,68,223,102, +116,100,82,142,47,170,28,232,72,232,112,220,158,194,188,162,208,130,93,130, +102,162,143,203,110,14,143,32,26,84,26,44,226,44,227,82,108,58,84,76, +59,88,144,58,189,86,46,106,196,106,196,142,58,142,58,180,210,180,202,220, +184,232,162,238,139,239,100,10,139,32,24,76,24,42,228,42,229,74,104,60, +43,92,144,62,207,90,20,116,225,116,50,140,50,182,188,182,189,140,120,84, +120,214,124,226,142,232,206,232,220,218,231,199,108,18,149,38,32,78,32,50, +228,50,229,78,114,66,55,94,146,68,207,92,206,106,118,114,51,114,110,128, +145,144,40,154,198,154,71,208,22,220,40,206,58,202,80,212,116,228,233,229, +110,12,145,36,28,86,28,46,230,46,231,86,108,64,53,94,146,66,205,102, +98,176,119,216,110,122,34,214,113,204,76,106,32,154,83,154,122,146,218,140, +212,218,198,234,171,234,168,102,166,152,156,194,142,216,119,241,106,18,143,38, +24,84,24,48,224,48,225,82,100,66,39,102,142,66,203,96,38,122,83,146, +206,116,165,146,102,100,102,174,92,202,66,224,23,240,30,188,103,164,146,96, +146,212,152,228,166,232,214,232,226,222,235,200,212,188,147,161,108,20,143,36, +22,78,22,46,230,46,231,78,102,60,49,92,156,60,207,84,64,96,197,96, +34,128,212,128,195,158,130,128,131,70,80,136,109,152,56,156,89,174,24,184, +239,184,138,144,124,194,100,218,68,230,29,238,144,206,188,224,225,245,110,16, +145,36,28,84,28,44,228,44,229,82,104,54,65,76,146,56,191,74,190,144, +190,90,62,90,62,144,191,144,62,118,191,118,24,170,227,170,128,242,129,90, +28,228,68,212,129,170,230,226,190,216,156,196,129,171,108,16,145,34,28,72, +28,44,230,44,231,72,100,60,45,88,150,60,211,88,128,70,78,106,19,132, +240,122,188,114,148,98,119,76,76,118,175,118,52,244,52,146,126,146,126,228, +120,234,99,234,52,174,127,174,52,202,127,202,166,206,167,144,208,136,208,220, +200,234,179,235,112,14,145,36,26,82,26,48,230,48,231,80,104,60,53,88, +152,62,203,90,116,78,143,98,40,110,221,110,14,146,239,146,82,122,109,146, +180,118,153,146,70,248,70,174,190,174,191,246,70,200,191,200,70,228,191,229, +110,16,145,34,32,72,32,44,226,44,227,72,108,60,51,86,148,60,209,88, +78,90,99,104,38,112,223,112,178,90,163,112,128,146,129,78,28,156,70,146, +129,116,230,156,184,146,129,118,22,178,237,178,118,154,84,202,223,234,38,238, +90,234,134,218,183,179,110,18,145,38,30,86,30,46,226,46,227,84,114,64, +57,88,144,62,191,88,114,98,82,104,42,108,42,190,34,220,23,240,73,106, +88,184,103,230,72,106,72,226,97,212,98,120,119,202,212,96,176,104,138,108, +138,194,128,226,117,242,184,184,203,238,164,106,164,228,195,214,192,102,200,160, +212,200,235,239,48,20,89,56,16,76,102,76,82,112,50,144,13,170,72,244, +73,122,118,178,92,152,73,138,122,110,95,155,52,16,77,48,18,66,94,66, +70,104,48,132,19,156,68,242,69,108,110,164,69,130,110,98,85,142,112,44, +214,44,200,118,168,176,103,232,234,232,180,188,142,124,132,82,127,44,158,70, +181,107,46,16,79,50,14,70,84,70,60,112,17,154,60,242,61,112,102,168, +61,134,98,110,75,144,120,242,120,66,224,66,224,224,210,236,193,236,172,12, +172,70,166,118,152,154,141,170,208,164,169,113,52,12,81,50,18,70,94,70, +66,114,19,152,66,242,67,114,112,174,67,124,112,100,83,140,226,24,172,40, +111,48,114,122,245,122,116,222,235,222,174,222,175,41,48,14,79,44,18,64, +88,64,58,110,21,152,62,240,63,104,98,170,63,132,92,116,77,146,168,14, +140,72,105,114,238,112,202,80,165,24,158,88,185,122,118,144,214,144,163,239, +54,14,83,48,16,66,94,66,64,110,21,152,66,242,67,106,112,164,67,126, +110,100,81,138,112,132,247,132,118,64,216,64,217,132,162,10,162,132,148,174, +126,210,95,238,234,236,198,204,176,172,161,141,50,16,77,50,16,68,88,68, +60,112,17,154,62,244,63,110,104,168,63,132,108,104,77,144,120,38,149,84, +228,38,201,88,122,112,237,112,118,170,245,170,178,248,179,15,52,16,79,50, +18,72,88,72,66,114,23,160,66,244,67,114,108,168,67,136,104,112,81,146, +118,32,147,84,226,34,199,86,122,112,224,112,225,242,116,218,225,218,126,162, +225,162,178,112,179,13,46,18,77,48,14,70,80,70,56,108,19,152,56,240, +57,108,96,170,57,132,88,116,73,148,166,18,138,70,103,112,234,110,192,76, +163,28,128,106,203,106,124,240,124,144,210,144,211,238,124,216,211,217,48,18, +75,48,18,66,88,66,56,116,19,150,56,242,57,114,96,166,57,132,98,106, +75,146,154,14,138,48,109,90,102,146,148,126,182,96,210,50,137,50,136,74, +162,106,190,126,239,144,130,242,130,156,208,156,209,238,130,216,209,217,40,18, +75,50,14,72,82,72,60,110,19,152,62,242,63,108,98,154,63,128,98,102, +79,138,168,208,122,234,122,32,210,32,210,124,123,124,122,80,211,80,158,124, +168,162,188,200,233,236,222,150,183,189,36,16,65,50,12,68,76,68,48,114, +13,146,48,242,49,114,88,170,49,136,80,116,61,146,92,26,121,72,90,114, +118,114,119,210,86,232,110,210,122,210,138,236,239,236,132,50,235,50,180,12, +144,118,233,118,134,164,239,164,190,212,191,73,44,18,77,46,18,66,90,66, +64,112,21,160,66,240,67,112,102,166,67,132,104,100,81,144,222,90,222,30, +128,30,128,90,223,90,112,130,241,130,122,178,229,178,104,226,245,226,176,226, +177,131,50,16,81,46,16,66,84,66,58,112,19,150,60,242,61,110,94,166, +61,136,90,116,73,146,166,12,134,62,95,102,236,108,190,74,159,24,120,104, +205,104,116,140,137,196,152,124,173,172,92,226,237,226,208,130,173,227,44,18, +73,46,16,72,78,72,54,110,21,146,54,240,55,110,88,160,55,124,88,110, +69,138,112,238,113,60,116,18,141,50,168,36,232,36,232,210,224,228,197,228, +198,180,198,84,144,84,144,180,199,180,144,132,199,133,44,16,73,46,16,72, +76,72,56,108,21,148,58,246,59,108,92,158,59,130,94,104,73,142,104,48, +231,48,112,84,219,84,102,124,241,124,166,124,167,10,90,194,122,172,144,146, +159,124,180,210,136,236,137,156,236,232,210,208,186,172,177,144,224,144,193,179, +40,16,71,48,12,66,80,66,52,112,17,148,52,240,53,112,86,152,53,126, +90,112,71,138,106,52,197,52,96,98,241,98,156,98,157,10,224,36,152,126, +83,176,126,240,126,140,216,140,217,238,126,178,217,178,126,216,217,217,46,16, +77,46,18,66,92,66,62,110,21,152,66,242,67,106,100,166,67,130,106,108, +81,144,220,94,220,24,132,24,132,94,221,94,132,60,221,60,158,106,119,154, +188,232,216,232,230,214,232,132,137,132,116,196,150,170,168,144,175,132,114,232, +176,192,207,133,44,22,77,54,16,78,80,78,56,118,19,156,56,244,57,118, +100,168,57,130,98,106,75,146,222,134,222,46,120,46,120,134,223,134,120,92, +223,92,134,174,160,134,168,92,171,46,158,10,141,46,92,188,247,188,190,244, +191,149,44,16,75,48,16,68,80,68,58,112,23,158,60,242,61,108,100,164, +61,128,96,104,79,142,92,234,114,190,120,150,120,32,224,32,224,76,121,76, +242,126,121,126,142,242,142,166,226,166,227,240,142,218,227,218,182,166,183,93, +48,16,75,48,16,66,78,66,50,116,17,156,54,242,55,110,88,164,55,132, +88,112,69,144,96,32,154,32,140,74,107,116,110,54,155,110,178,34,224,34, +212,72,194,100,175,118,178,58,225,116,96,134,150,134,132,188,89,240,106,162, +157,218,172,136,224,136,208,186,186,216,159,242,172,136,184,174,202,208,241,239, +44,16,77,48,18,68,86,68,58,108,19,146,58,242,59,108,98,168,59,122, +102,100,73,138,100,48,241,48,136,80,137,12,200,80,201,12,168,64,148,100, +126,122,101,142,238,138,208,122,180,98,163,74,132,138,205,138,128,242,128,172, +210,172,211,242,128,220,211,221,42,18,73,46,18,68,86,68,60,110,19,152, +62,242,63,108,104,160,63,130,100,108,79,140,154,104,155,14,104,48,155,48, +104,92,155,80,192,16,192,82,196,92,206,96,226,96,236,88,241,72,236,34, +193,56,132,240,132,122,218,122,218,218,208,234,189,234,132,156,219,156,132,186, +219,187,42,16,71,52,14,72,70,72,50,108,19,146,54,242,55,102,90,168, +55,138,90,116,67,146,134,14,112,58,87,100,116,242,117,52,216,90,216,34, +154,34,154,90,217,90,132,132,239,132,184,242,185,90,132,216,160,178,185,132, +242,212,208,176,185,133,36,18,73,52,14,74,82,74,58,118,21,158,56,244, +57,120,94,170,57,134,96,110,71,146,104,72,239,72,120,24,147,56,222,24, +197,52,170,126,171,10,110,134,142,108,171,72,236,128,198,102,173,72,106,158, +247,158,168,132,132,192,241,236,102,238,152,228,184,206,198,182,207,159,44,20, +79,52,14,72,84,72,60,112,21,156,60,242,61,114,94,168,61,130,98,108, +75,144,82,228,102,200,120,132,120,54,222,54,222,98,121,98,148,14,183,40, +126,242,126,134,230,134,230,218,224,232,201,232,162,216,163,134,196,216,197,134, +126,178,231,179,40,16,71,50,16,70,82,70,52,114,17,152,54,244,55,112, +94,164,55,134,92,112,71,144,112,128,113,26,148,140,149,12,196,14,178,66, +161,94,240,60,181,60,192,90,221,130,82,228,247,228,112,228,112,158,220,158, +221,228,148,228,149,158,184,228,185,159,42,16,73,50,16,66,80,66,58,106, +19,152,54,244,55,112,94,162,55,128,92,108,71,140,76,232,102,192,110,154, +112,128,112,34,178,30,231,20,222,108,230,88,142,88,142,154,132,196,111,236, +174,88,175,42,174,62,231,62,154,120,211,116,180,100,180,132,188,146,216,146, +229,126,142,236,158,220,168,198,168,174,200,174,200,226,212,230,226,230,241,211, +42,16,73,44,16,66,80,66,58,108,19,152,60,242,61,108,100,160,61,124, +94,108,77,138,96,28,154,28,155,108,110,50,133,70,106,100,155,88,180,28, +228,28,229,114,180,48,203,68,176,100,229,82,130,242,130,140,218,140,219,238, +130,218,219,218,130,180,219,180,168,114,159,141,38,16,69,46,16,68,72,68, +52,110,19,148,52,244,53,112,86,168,53,134,84,110,63,144,88,32,128,32, +128,92,98,92,98,146,124,146,120,216,112,230,85,230,220,80,220,30,162,30, +162,80,221,80,228,166,228,118,154,118,154,166,229,166,216,182,241,232,138,226, +231,216,190,220,191,93,44,22,75,52,18,76,80,76,56,118,21,158,56,244, +57,120,88,168,57,138,94,112,69,148,112,32,225,32,108,92,108,58,228,58, +229,92,166,116,167,32,126,82,151,82,126,108,151,108,188,82,211,82,186,108, +209,108,100,134,237,134,114,242,114,164,224,164,224,224,216,238,205,238,152,228, +153,164,186,228,187,164,168,134,157,165,36,20,63,52,12,74,72,74,52,120, +19,158,54,240,55,120,84,154,55,128,88,106,69,138,84,44,133,44,112,106, +113,16,88,90,113,48,134,78,113,58,140,26,171,56,172,24,141,60,140,72, +175,102,134,102,169,72,180,44,233,44,204,106,205,14,180,90,205,50,234,86, +205,56,96,126,235,126,154,108,122,148,83,176,238,166,208,152,185,126,192,148, +158,152,131,154,118,176,213,176,96,200,237,200,166,152,166,220,160,236,139,237, +32,40,224,40,195,92,76,96,62,174,44,214,27,238,236,228,162,226,132,220, +94,196,65,164,128,40,129,216,214,132,129,133,32,32,218,32,209,54,74,52, +54,94,23,122,240,108,148,108,96,100,63,76,132,32,133,104,210,72,133,72, +66,244,66,136,198,136,198,218,184,238,161,238,66,166,199,166,66,196,199,197, +24,66,24,34,108,34,109,66,18,92,117,92,72,50,30,138,115,138,18,198, +113,178,74,244,75,110,106,238,126,206,134,160,134,52,230,52,221,88,134,114, +222,114,202,166,176,208,139,238,238,232,202,204,178,174,164,144,159,114,178,114, +179,7,71,14,84,40,117,76,70,14,32,76,105,64,50,90,17,124,84,90, +115,118,62,120,46,144,29,172,26,232,60,210,86,176,98,146,47,146,52,168, +103,202,98,238,120,206,136,142,136,60,226,60,215,90,136,126,218,126,198,176, +172,210,135,240,236,232,196,206,168,168,151,126,178,126,179,11,48,62,81,88, +20,30,100,30,67,76,12,98,108,98,97,136,68,98,68,216,56,232,41,232, +18,182,46,146,69,106,174,10,154,66,123,114,168,96,189,128,238,108,206,76, +186,46,171,18,124,152,216,152,194,200,165,239,36,50,215,50,44,90,203,90, +20,130,233,130,126,242,127,10,24,216,58,198,88,170,117,130,232,212,192,192, +160,164,139,131,20,58,109,58,28,94,105,94,18,132,105,132,126,132,247,132, +68,244,69,12,20,210,69,138,110,188,69,148,118,38,228,38,178,96,178,218, +166,240,141,241,22,52,113,52,28,86,109,86,16,122,117,122,70,244,71,12, +18,206,46,170,71,122,104,178,71,142,120,142,151,68,206,66,241,126,178,170, +179,8,222,142,200,184,176,210,148,226,103,239,24,56,115,56,32,92,109,92, +20,130,117,130,72,242,73,12,22,208,48,176,73,130,110,184,73,140,138,242, +138,26,218,26,218,98,139,98,138,144,226,144,227,238,138,214,227,215,18,54, +107,54,28,92,99,92,16,126,111,126,64,248,65,12,18,212,48,172,65,132, +100,186,65,152,174,10,146,68,113,108,240,102,200,66,171,18,136,110,215,110, +136,244,136,154,214,154,215,242,136,220,213,221,24,48,91,48,114,48,239,48, +28,86,95,86,18,124,99,124,66,246,67,8,20,200,48,164,67,126,98,174, +67,140,148,74,149,12,196,76,197,10,118,128,118,98,234,98,235,130,120,150, +214,150,210,210,198,228,165,228,158,116,158,150,154,178,138,206,116,226,97,239, +18,58,101,58,28,94,99,94,16,130,107,130,60,246,61,10,20,210,46,174, +61,138,100,180,61,140,118,34,147,72,230,32,199,76,124,244,124,102,230,102, +230,224,222,236,205,236,198,194,198,134,154,134,154,194,199,194,176,102,177,11, +18,56,105,56,26,92,99,92,16,126,105,126,62,244,63,10,20,204,46,168, +63,136,102,176,63,136,222,98,222,24,132,24,132,98,223,98,132,60,223,60, +122,242,122,132,232,132,232,224,220,234,201,234,194,154,213,196,138,190,205,178, +174,24,175,183,20,52,97,52,28,86,93,86,14,120,97,120,62,244,63,14, +16,202,42,168,63,126,90,176,63,144,108,74,235,74,122,28,147,56,218,24, +195,54,170,128,171,12,110,132,140,108,171,74,236,126,204,108,171,74,104,164, +241,164,168,138,134,196,235,232,102,238,148,226,186,200,209,165,26,52,99,52, +112,38,231,38,30,86,95,86,16,124,107,124,104,104,243,104,118,72,225,72, +144,104,145,12,196,104,197,10,64,246,65,14,16,202,42,170,65,134,98,172, +65,146,128,242,128,134,214,134,214,222,202,238,187,238,102,196,241,196,128,164, +213,164,170,196,171,105,230,24,116,24,116,154,104,204,97,228,16,58,95,58, +24,90,91,90,12,128,95,128,60,242,61,12,18,208,42,172,61,132,92,174, +61,140,140,56,219,56,116,86,239,86,150,86,150,144,181,130,238,144,210,130, +194,112,181,86,232,102,205,122,130,172,243,172,206,150,206,222,198,236,179,236, +150,188,167,215,156,12,181,32,236,46,116,46,116,140,108,188,89,226,22,54, +95,54,30,86,93,86,16,118,99,118,62,246,63,12,18,196,44,160,63,126, +92,168,63,132,133,86,126,86,171,86,192,84,239,84,134,164,239,164,210,142, +211,58,184,138,211,84,246,132,224,110,211,84,152,142,153,58,124,134,153,90, +174,116,153,94,118,214,148,194,173,164,146,244,146,194,218,194,219,244,146,230, +219,231,44,38,165,38,18,62,235,62,118,62,119,16,200,26,114,74,60,94, +21,104,92,84,92,110,96,114,112,120,192,120,204,114,213,100,186,82,140,92, +93,98,26,142,229,142,160,154,197,182,102,148,54,176,181,170,36,202,221,202, +16,228,241,228,126,228,127,181,16,28,123,28,130,36,241,36,16,200,127,176, +100,240,101,28,46,28,47,192,46,80,101,80,46,130,101,130,192,36,192,212, +184,230,159,231,18,34,115,34,90,244,91,34,16,200,111,182,42,34,43,194, +108,158,245,158,42,88,91,88,42,136,91,136,134,240,134,54,222,54,222,214, +214,234,193,234,134,102,223,102,176,158,177,11,12,34,115,34,14,196,113,168, +92,242,93,34,36,34,37,188,36,84,93,84,36,132,93,132,156,94,179,124, +164,10,140,74,105,118,234,116,196,80,163,18,115,142,132,180,199,234,114,144, +212,144,169,209,16,36,121,36,20,204,125,184,98,244,99,36,42,36,43,198, +42,88,99,88,42,140,99,140,166,14,193,40,134,94,134,56,232,56,233,92, +124,120,245,120,184,120,184,222,172,238,155,239,218,14,172,26,131,34,14,30, +105,30,18,202,113,176,90,244,91,30,136,244,136,140,220,140,221,242,136,216, +221,216,112,82,243,82,174,140,175,26,40,30,41,196,40,82,91,82,40,132, +91,133,85,242,14,32,111,32,14,198,109,178,84,242,85,32,130,198,130,130, +216,130,217,198,108,102,243,102,130,40,130,74,218,74,218,40,131,40,40,32, +41,192,40,82,85,82,40,132,85,132,174,102,175,10,174,152,174,186,164,206, +134,228,113,234,186,200,231,237,26,28,127,28,34,48,119,48,18,72,133,72, +78,72,79,8,24,124,46,108,58,88,63,72,56,94,118,94,112,116,87,116, +168,12,158,40,143,64,240,40,159,40,162,62,176,84,194,102,214,112,233,116, +144,120,166,112,182,100,196,84,204,64,211,40,26,138,231,138,14,218,241,212, +186,246,187,138,72,216,73,138,72,164,187,164,72,188,187,189,22,28,235,28, +212,96,212,56,42,56,42,96,213,96,102,96,103,28,156,96,157,28,198,178, +198,122,58,122,58,178,199,178,58,148,199,148,12,202,243,202,128,244,129,179, +20,34,99,34,12,120,107,120,62,234,63,34,110,26,243,26,124,184,124,78, +216,78,217,182,156,78,173,26,168,106,168,168,160,194,134,218,95,236,234,238, +181,195,104,24,68,38,38,44,38,160,30,198,19,226,112,100,39,100,82,232, +83,100,120,34,239,34,134,190,134,76,216,76,217,190,176,34,165,76,176,102, +176,172,166,196,140,222,111,240,188,194,239,243,50,16,83,52,18,70,121,70, +24,228,38,206,46,178,46,110,94,110,94,208,121,180,144,188,144,78,224,78, +225,186,116,30,245,30,182,30,169,78,182,106,182,176,170,202,144,222,117,236, +192,194,243,237,16,58,119,58,22,104,113,104,70,104,71,12,36,238,36,144, +96,144,97,226,36,208,97,208,118,30,241,30,138,190,138,76,218,76,219,186, +168,76,179,30,176,98,176,180,164,206,146,222,113,240,186,196,235,237,74,16, +46,72,17,104,118,78,67,32,118,30,239,30,140,186,140,80,216,80,217,186, +178,30,165,80,36,102,107,102,38,228,38,140,104,140,105,226,38,206,105,206, +178,108,178,178,162,206,140,224,125,236,190,196,237,237,46,12,46,72,48,82, +62,88,98,88,116,78,123,58,116,28,47,40,128,32,245,32,16,130,52,130, +38,184,21,216,76,102,76,218,62,232,49,232,124,202,77,132,122,116,89,148, +144,188,144,76,224,76,225,186,178,76,187,32,180,100,180,170,166,206,119,236, +192,196,237,237,54,16,91,42,18,58,131,58,122,124,92,170,70,194,25,226, +102,86,72,130,54,150,27,174,72,66,34,114,81,114,88,176,127,210,128,34, +239,34,140,188,140,84,220,84,221,184,186,34,169,84,180,108,180,182,162,210, +140,226,121,238,190,196,235,237,78,12,52,58,21,94,118,66,71,26,68,66, +93,88,38,106,108,106,71,144,44,236,44,160,104,160,105,224,44,210,105,210, +122,34,245,34,142,196,142,84,222,84,223,192,164,84,179,34,184,108,184,176, +160,210,117,240,186,196,241,239,62,70,62,26,30,26,30,70,63,70,120,70, +120,28,88,28,88,70,121,70,26,104,123,104,12,136,129,136,56,136,48,170, +106,170,98,218,82,230,53,230,142,28,235,28,146,186,146,76,224,76,225,186, +170,76,187,28,184,106,184,180,164,210,138,226,117,236,194,194,235,235,38,28, +38,74,112,74,113,28,132,34,239,34,74,12,75,74,16,108,123,108,148,190, +148,84,220,84,221,188,32,236,32,146,116,146,116,214,114,226,106,232,95,232, +66,146,75,108,62,220,63,146,88,218,89,146,184,110,184,182,174,204,156,224, +135,238,194,198,235,236,170,84,185,35,22,28,123,28,136,28,243,28,24,118, +129,104,152,182,152,74,224,74,225,182,188,28,175,74,48,28,49,114,108,128, +109,28,48,54,109,54,48,80,109,80,18,142,60,142,52,178,38,202,17,226, +26,162,63,206,78,142,116,142,108,178,88,208,65,232,80,166,121,216,188,102, +188,168,178,198,158,220,131,242,200,196,241,237,12,48,125,48,52,72,53,14, +94,72,95,14,16,90,131,90,134,28,239,28,152,182,152,74,222,74,223,184, +28,242,28,128,120,128,120,218,114,232,95,232,60,90,60,134,52,166,43,196, +74,178,57,148,92,90,92,132,88,166,75,208,112,190,91,156,186,104,186,178, +168,210,135,238,196,194,239,236,184,28,173,75,36,26,106,26,80,54,39,74, +48,38,111,74,130,24,241,24,16,90,66,90,54,118,40,136,29,146,28,106, +69,136,88,90,124,90,112,116,91,140,86,106,131,138,14,162,15,162,14,164, +127,164,148,190,148,70,222,70,223,188,76,244,77,146,20,222,77,168,122,206, +77,174,174,70,185,24,184,96,184,168,172,206,131,240,198,200,239,239,150,180, +150,76,222,76,223,178,128,118,15,118,112,82,112,26,32,26,32,82,113,82, +32,56,113,56,60,92,87,108,110,176,110,144,38,144,38,176,111,176,48,196, +19,232,98,200,125,222,76,176,76,224,64,238,53,238,186,102,186,174,172,206, +139,238,202,192,241,232,134,26,239,26,182,26,173,77,16,134,131,134,28,26, +125,26,137,28,138,26,239,26,28,92,28,58,124,58,125,94,150,196,150,78, +220,78,221,194,174,78,189,26,76,114,77,26,43,82,48,82,63,82,36,106, +61,106,96,82,97,82,96,82,107,82,98,108,113,108,30,244,30,162,118,162, +118,226,110,238,95,238,76,134,71,162,58,222,59,162,86,222,87,162,184,102, +184,184,168,212,154,226,137,242,194,204,239,239,14,70,119,70,72,70,73,18, +72,44,109,44,42,70,43,32,122,32,239,32,140,106,140,60,218,60,219,104, +168,60,177,32,46,84,29,110,106,86,82,110,54,124,21,130,72,70,73,114, +181,72,180,80,180,100,170,114,152,120,135,124,190,110,229,128,200,188,200,140, +56,140,56,188,201,188,110,120,101,140,56,164,201,164,134,140,130,166,116,190, +98,202,75,212,14,218,241,218,144,248,145,195,210,130,228,88,44,88,44,184, +36,210,19,236,128,88,129,10,128,48,217,48,68,162,207,150,132,108,132,212, +136,224,150,232,210,232,226,220,231,201,214,84,222,62,42,62,42,172,34,206, +17,236,66,102,195,92,120,74,120,116,124,124,138,128,194,128,206,118,215,102, +122,62,123,8,122,32,209,32,60,162,233,162,116,138,149,156,58,236,96,228, +132,214,162,190,185,162,230,234,192,228,158,220,124,200,91,163,112,138,112,70, +32,70,32,138,113,138,102,166,125,210,20,216,115,190,72,18,73,200,158,14, +158,212,164,228,180,234,212,234,228,218,233,191,102,136,102,68,30,68,30,136, +103,136,96,158,115,206,14,208,105,184,66,14,67,194,110,238,126,220,142,174, +142,32,202,32,202,212,204,224,212,230,224,230,236,216,243,183,20,38,237,38, +26,130,58,116,76,100,92,76,101,38,166,122,184,122,200,114,204,96,204,74, +93,74,200,190,200,152,54,152,54,190,201,190,190,202,229,240,34,230,211,222, +126,116,127,225,14,44,123,44,52,44,52,156,38,198,21,234,90,44,90,202, +92,218,104,228,212,228,230,222,241,206,212,152,235,194,114,194,225,176,220,128, +220,72,130,72,130,128,221,128,174,18,175,185,106,140,106,66,30,66,30,140, +107,140,98,168,117,218,16,208,109,194,70,12,71,198,162,10,142,62,125,96, +240,56,147,56,138,110,214,110,188,138,166,172,152,198,146,214,150,224,164,228, +200,230,222,224,232,212,237,199,102,146,102,72,32,72,32,146,103,146,98,178, +119,222,16,226,109,202,68,14,69,210,162,18,191,48,124,66,243,66,144,66, +144,224,237,225,94,142,94,72,30,72,30,142,95,142,90,170,113,212,16,212, +103,194,64,14,65,200,122,70,229,70,112,136,239,136,98,238,134,212,158,178, +172,132,176,96,177,12,236,238,210,218,190,188,173,137,98,142,98,68,30,68, +30,142,99,142,90,172,111,212,16,212,101,194,64,14,65,202,132,16,132,226, +169,204,132,100,165,100,186,12,186,212,190,224,202,232,222,232,232,220,237,202, +232,78,187,115,90,140,90,70,24,70,24,140,91,140,84,172,101,214,18,216, +93,194,56,16,57,204,124,244,124,68,226,68,226,216,222,226,212,236,197,236, +174,12,174,94,168,124,158,148,141,176,206,166,171,115,94,134,94,62,28,62, +28,134,95,134,90,160,111,200,16,206,101,182,60,10,61,192,130,148,130,30, +212,30,213,144,168,66,168,128,158,168,138,202,120,224,103,238,180,140,180,214, +184,224,198,230,222,230,232,220,241,201,98,150,98,78,30,78,30,150,99,150, +94,180,121,226,16,224,107,206,62,20,63,214,214,24,160,38,109,46,122,100, +217,94,120,158,229,148,158,38,158,214,162,228,174,236,218,236,228,226,237,203, +90,146,90,70,28,70,28,146,91,146,86,172,105,212,16,212,97,196,58,14, +59,202,168,14,140,70,113,110,238,104,208,84,182,54,165,24,142,110,142,154, +136,190,122,220,105,238,200,242,201,111,100,148,100,72,30,72,30,148,101,148, +96,174,111,226,16,222,103,204,64,18,65,212,120,132,146,88,165,28,188,22, +200,64,218,98,241,126,196,164,229,238,180,108,136,228,219,219,98,144,98,74, +30,74,30,144,99,144,96,176,119,224,18,218,109,204,64,14,65,210,120,174, +239,156,134,36,173,70,128,98,167,134,202,244,203,13,94,134,94,60,30,60, +30,134,95,134,94,164,113,204,63,14,20,208,103,186,62,14,63,196,114,28, +174,28,174,82,128,82,128,138,176,138,172,206,166,218,152,228,131,228,220,240, +221,13,50,22,50,62,208,62,209,24,16,96,239,96,126,96,127,12,202,178, +202,138,52,138,52,178,203,178,186,194,227,238,22,224,207,216,126,220,127,107, +120,82,243,82,100,144,100,72,32,72,32,144,101,144,96,170,119,214,142,244, +143,16,16,214,109,196,66,18,67,202,210,240,211,16,142,142,211,142,142,214, +211,215,126,78,239,78,102,142,102,72,36,72,36,142,103,142,98,168,121,216, +140,242,140,144,220,144,221,238,140,216,221,216,20,214,111,196,68,14,69,202, +178,144,179,13,102,142,102,64,34,64,34,142,103,142,94,168,115,222,20,218, +105,200,66,8,67,206,180,162,180,88,138,88,138,162,181,162,110,38,243,38, +212,38,212,216,208,228,198,236,181,237,92,236,110,208,120,182,124,156,124,40, +239,40,94,132,94,66,30,66,30,132,95,132,82,160,97,194,18,202,91,180, +60,12,61,188,144,88,243,88,172,88,172,148,160,194,140,224,125,240,172,136, +222,136,216,216,212,228,198,236,187,237,132,242,132,74,228,74,229,240,132,214, +229,214,180,214,181,10,132,142,229,142,90,176,111,218,20,218,101,198,98,146, +98,76,32,76,32,146,99,146,66,14,67,205,92,140,92,68,30,68,30,140, +93,140,86,168,107,212,16,210,97,194,60,14,61,200,110,166,241,166,132,242, +132,62,220,62,220,214,214,230,204,238,189,238,132,114,221,114,174,166,175,11, +100,142,100,70,28,70,28,142,101,142,98,170,119,210,16,212,107,188,64,14, +65,198,158,12,142,52,117,92,159,244,240,72,131,72,158,246,159,72,224,126, +159,126,234,182,159,183,106,140,106,66,30,66,30,140,107,140,100,164,121,210, +20,218,113,194,66,12,67,204,116,226,243,226,146,226,146,42,223,26,232,108, +147,108,198,226,199,109,92,140,92,70,30,70,30,140,93,140,140,186,197,240, +114,142,214,142,171,214,170,10,148,64,113,102,238,104,204,78,165,26,158,90, +189,122,92,166,111,212,16,212,101,188,60,12,61,201,92,136,92,68,26,68, +26,136,93,136,88,168,109,210,16,214,97,188,58,10,59,200,114,166,227,166, +102,228,241,228,106,30,214,30,186,72,154,106,115,128,238,124,186,102,152,74, +123,30,170,228,171,125,92,148,92,70,34,70,34,148,93,148,86,178,101,220, +22,218,95,200,62,18,63,206,152,164,169,204,164,84,120,198,161,186,144,26, +116,118,151,118,166,76,228,76,224,212,216,230,195,230,150,238,174,206,188,168, +194,124,194,106,195,15,20,30,109,30,16,108,105,80,64,30,65,92,102,116, +120,100,130,80,132,70,132,26,196,26,196,102,200,114,226,114,239,90,150,62, +173,92,208,184,208,142,46,142,46,184,209,184,200,200,233,238,24,226,219,222, +126,112,127,223,90,142,90,68,32,68,32,142,91,142,112,136,237,136,114,52, +229,52,88,166,107,208,18,210,99,192,60,10,61,198,120,78,141,112,214,76, +187,114,164,8,164,144,152,180,130,214,97,242,232,236,206,210,186,180,165,137, +114,62,229,32,214,62,186,86,158,104,125,120,110,150,233,150,146,8,156,60, +180,106,208,128,220,128,228,124,233,106,84,240,114,224,140,196,148,172,151,150, +182,150,182,214,188,228,226,228,239,208,88,164,107,202,16,212,99,186,62,10, +63,198,94,134,94,64,32,64,32,134,95,135,188,70,221,122,88,168,111,210, +92,140,92,68,28,68,28,140,93,140,18,216,101,192,58,12,59,204,106,30, +233,30,162,38,118,118,211,108,114,166,223,166,94,228,243,228,166,228,167,123, +88,136,88,64,30,64,30,136,89,136,90,168,99,214,20,208,95,196,58,12, +59,200,116,160,117,52,104,238,122,218,134,192,140,168,141,16,160,32,239,32, +166,202,166,84,224,84,224,184,216,194,209,194,194,244,195,33,92,136,92,68, +34,68,34,134,93,134,90,166,105,206,22,208,99,188,62,16,63,196,124,240, +124,66,226,66,227,238,124,216,227,216,124,136,227,136,156,216,157,16,190,216, +191,15,86,142,86,68,28,68,28,142,87,142,108,150,118,182,138,208,160,224, +200,228,239,226,100,52,138,52,112,126,142,126,138,166,132,192,114,220,93,242, +80,172,95,210,16,216,87,192,56,14,57,202,222,28,192,36,155,40,156,104, +229,104,156,178,233,178,192,178,193,37,98,148,98,76,32,76,32,148,99,148, +92,180,109,224,18,222,99,202,64,18,65,210,214,22,172,32,125,36,112,90, +243,90,132,242,132,146,218,146,219,242,132,220,219,220,172,146,173,33,94,140, +94,68,34,68,34,140,95,140,90,168,109,216,14,212,101,198,64,14,65,202, +154,14,185,40,108,52,237,52,114,138,148,122,178,96,192,72,201,52,240,134, +210,124,186,112,160,94,140,70,133,52,110,236,136,218,148,186,153,140,198,242, +199,139,98,140,98,66,28,66,28,140,99,140,92,166,119,204,14,212,105,188, +62,12,63,198,158,12,187,42,110,58,237,58,154,80,119,120,188,80,231,116, +140,130,152,160,174,196,204,218,235,236,202,126,186,162,162,196,138,216,103,237, +96,136,96,68,34,68,34,136,97,136,118,62,235,62,90,168,113,214,16,210, +101,190,112,172,239,172,120,116,233,116,174,244,175,62,126,18,153,48,208,12, +183,62,64,14,65,199,96,136,96,66,34,66,34,136,97,136,88,164,109,204, +20,206,99,186,64,14,65,194,192,38,231,86,168,12,120,74,217,68,140,100, +113,156,224,128,127,128,110,176,243,176,176,244,177,89,232,32,48,32,48,138, +38,188,21,236,76,64,207,64,48,92,239,92,92,92,92,144,139,126,236,150, +208,144,178,132,156,114,141,92,208,102,181,130,212,198,212,168,74,168,74,198, +213,198,200,208,241,240,60,232,221,226,142,140,143,229,22,46,113,46,26,96, +109,78,74,14,74,120,70,132,60,136,53,136,220,26,180,34,142,36,142,86, +132,108,119,126,240,76,143,76,192,130,193,76,202,188,202,156,56,156,56,188, +203,188,188,204,227,240,28,234,209,224,130,132,131,229,100,144,100,72,32,72, +32,144,101,144,64,10,65,204,94,170,117,216,20,218,105,192,120,28,149,62, +230,22,205,66,136,244,136,90,224,90,224,220,220,232,212,238,197,238,136,134, +225,134,136,176,225,176,178,90,179,9,98,136,98,66,28,66,28,136,99,136, +94,160,113,204,18,206,103,186,62,12,63,194,216,78,216,30,130,30,130,78, +217,78,120,116,227,116,114,160,239,160,100,238,128,222,152,198,164,172,168,154, +173,116,234,236,208,216,186,188,169,161,90,136,90,66,30,66,30,136,91,136, +88,162,103,210,16,206,95,190,60,14,61,196,172,20,132,30,103,34,108,90, +175,90,140,240,141,28,108,164,126,128,141,92,168,146,141,108,192,178,193,52, +222,14,222,212,218,228,210,230,197,231,92,138,92,66,32,66,32,138,93,138, +88,162,105,198,18,208,99,184,60,10,61,194,166,10,138,60,109,94,234,90, +192,58,163,18,124,100,211,100,110,148,229,148,138,178,97,228,196,180,239,222, +168,100,168,222,164,230,156,238,141,239,92,132,92,66,28,66,28,132,93,132, +84,162,103,204,14,210,95,186,58,12,59,196,220,22,170,34,113,38,120,62, +137,96,164,52,175,88,224,54,197,100,118,114,218,114,176,152,176,220,174,230, +164,238,145,238,110,172,243,173,90,138,90,68,30,68,30,138,91,138,84,160, +105,198,14,202,97,184,58,14,59,192,122,12,145,38,108,54,227,54,196,12, +167,54,114,96,217,96,106,136,231,136,86,236,114,218,138,190,152,156,160,112, +160,88,161,54,174,152,174,216,178,228,190,234,224,234,234,220,239,203,94,136, +94,66,32,66,32,136,95,136,90,164,115,204,20,208,105,188,62,12,63,198, +114,40,233,40,124,72,223,72,110,102,245,102,132,242,132,132,220,132,220,218, +212,232,200,236,187,236,132,162,221,162,132,192,221,192,172,102,173,9,96,138, +96,68,30,68,30,138,97,138,86,170,99,210,16,210,93,192,62,18,63,198, +112,58,239,58,108,176,245,176,140,176,141,16,208,176,209,16,140,96,209,96, +140,136,209,136,152,196,99,242,190,198,231,241,82,136,82,62,28,62,28,136, +83,136,78,168,97,210,14,208,87,188,54,12,55,196,98,68,155,68,128,244, +129,10,94,160,112,124,129,68,152,126,129,94,224,20,170,38,170,162,164,202, +147,232,240,104,171,104,208,242,209,105,86,146,86,72,26,72,26,146,87,146, +84,176,101,222,18,222,93,198,56,16,57,208,152,164,152,110,116,110,116,164, +153,164,116,210,167,194,104,70,237,70,202,24,223,50,174,12,174,74,180,130, +194,194,210,228,218,236,226,238,232,230,237,212,220,108,204,162,182,204,153,241, +102,134,103,16,154,134,155,16,26,44,103,44,34,76,103,76,20,108,103,108, +230,46,155,46,222,76,155,76,238,110,155,110,198,190,198,154,52,154,52,190, +199,190,188,202,223,240,24,230,209,224,126,122,127,227,92,138,92,64,28,64, +28,138,93,138,86,162,109,196,14,208,99,184,60,12,61,194,224,106,224,26, +128,26,128,106,225,106,128,66,225,66,110,142,245,142,176,244,177,26,100,222, +132,200,156,172,177,144,236,218,212,200,194,174,177,143,88,138,88,68,30,68, +30,138,89,138,82,164,97,208,14,206,91,190,58,14,59,196,118,240,118,32, +226,32,227,242,118,220,227,220,140,74,207,74,140,118,201,118,140,178,207,178, +168,178,169,74,188,140,201,163,94,142,94,66,30,66,30,142,95,142,92,172, +111,216,18,218,99,194,60,12,61,204,220,100,220,28,132,28,132,100,221,100, +132,64,221,64,158,110,138,136,115,154,194,236,214,236,228,226,234,210,236,136, +139,136,124,196,150,176,168,154,175,136,128,238,160,218,188,184,198,164,209,137, +92,140,92,68,28,68,28,140,93,140,84,172,105,218,16,212,93,194,60,14, +61,200,224,134,224,44,126,44,126,134,225,134,177,44,176,44,174,88,164,136, +135,172,108,186,243,186,184,244,185,150,126,90,225,90,170,10,151,45,88,140, +88,64,26,64,26,140,89,140,82,166,101,208,14,212,93,192,56,14,57,200, +98,238,114,208,124,158,124,30,222,30,222,214,216,234,191,234,146,112,201,112, +146,76,199,76,172,44,173,112,190,194,190,142,152,142,152,194,191,195,92,138, +92,66,30,66,30,138,93,138,84,166,105,212,16,212,95,192,60,12,61,200, +112,26,137,56,216,24,187,56,112,72,225,72,108,106,235,106,102,170,124,152, +142,128,156,94,162,68,167,12,238,166,216,150,194,130,181,106,168,200,182,200, +196,186,198,148,138,148,138,226,146,240,206,240,218,228,225,211,90,138,90,68, +28,68,28,138,91,138,86,166,101,206,16,208,95,188,58,12,59,196,152,16, +179,36,114,86,114,54,226,54,227,86,102,158,130,114,145,74,92,240,118,222, +142,188,154,158,160,128,162,106,135,106,124,154,147,174,198,176,210,176,218,162, +218,102,182,102,182,220,186,230,198,236,226,236,234,224,239,211,84,142,84,68, +28,68,28,142,85,142,78,174,95,214,16,220,87,194,56,14,57,204,122,10, +141,34,144,178,165,224,154,202,114,226,114,48,158,48,158,150,115,150,114,100, +159,100,184,246,184,32,228,32,206,120,226,148,234,172,232,190,218,200,207,205, +92,138,92,70,30,70,30,138,93,138,86,166,101,206,16,212,95,190,60,14, +61,200,108,84,239,84,116,30,210,30,174,60,174,118,170,130,164,134,143,134, +92,228,245,228,120,228,120,154,218,154,219,228,152,228,153,154,184,228,185,155, +92,146,92,80,30,80,30,146,93,146,88,172,111,216,18,218,99,194,60,16, +61,204,115,52,114,54,235,54,122,84,223,84,110,114,241,114,174,18,170,68, +160,104,140,136,111,162,194,114,204,134,222,152,241,164,140,244,140,154,208,154, +209,242,140,190,209,190,140,224,209,225,90,136,90,64,32,64,32,136,91,136, +82,162,101,196,14,206,95,184,60,8,61,192,106,48,241,48,146,74,147,8, +194,74,195,8,114,124,114,92,226,92,227,124,108,146,231,146,170,110,171,244, +90,222,126,196,150,168,167,146,234,222,208,202,188,176,173,147,88,140,88,70, +30,70,30,140,89,140,86,166,101,210,22,210,95,196,58,14,59,202,102,50, +241,50,118,242,118,94,226,94,226,212,222,226,212,234,197,234,168,94,169,10, +142,112,159,134,136,148,207,148,194,108,171,148,134,182,209,182,170,230,171,149, +92,138,92,66,28,66,28,138,93,138,86,162,103,206,18,206,95,186,60,10, +61,194,108,28,237,28,210,96,210,62,132,62,132,96,211,96,122,240,122,128, +224,128,225,236,122,168,225,168,122,214,225,214,174,214,175,129,90,146,90,70, +28,70,28,146,91,146,82,168,101,208,16,218,93,190,58,14,59,202,104,50, +235,50,106,110,132,90,148,68,164,36,175,14,238,104,214,90,196,70,183,50, +126,116,215,116,114,148,229,148,172,148,173,82,122,192,213,192,100,228,239,228, +172,228,173,163,86,144,86,74,26,74,26,144,85,144,82,180,95,220,16,220, +89,200,58,14,59,206,164,18,132,30,103,36,102,88,169,88,134,240,135,30, +94,170,116,136,135,96,166,146,135,110,166,50,195,76,172,104,197,132,160,166, +245,150,216,238,217,13,94,138,94,66,30,66,30,138,95,138,88,166,109,210, +16,210,99,192,64,10,65,198,152,12,134,48,111,78,238,40,139,40,218,130, +218,68,138,68,138,130,219,130,138,98,219,98,156,138,138,168,119,194,148,182, +184,218,237,240,100,242,146,228,190,196,214,162,143,163,90,138,90,62,28,62, +28,138,91,138,84,162,103,202,16,206,95,186,58,10,59,194,110,144,214,144, +186,186,150,220,105,240,236,238,194,222,166,196,142,162,133,144,144,26,120,36, +120,112,222,112,222,32,191,32,170,144,171,8,148,72,121,72,194,72,223,73, +88,134,88,66,28,66,28,134,89,134,82,160,99,204,14,206,91,186,58,14, +59,194,164,10,134,56,103,90,236,86,194,54,163,14,128,82,203,82,116,240, +116,112,158,112,158,222,152,234,141,234,116,146,159,146,116,184,159,184,186,202, +187,116,218,102,218,218,208,236,193,237,84,132,84,60,30,60,30,132,85,132, +76,158,93,190,12,200,87,180,56,8,57,186,110,12,135,46,98,60,157,60, +118,60,118,130,112,170,96,208,75,234,118,112,148,112,144,208,138,220,128,228, +115,228,190,10,174,56,155,92,242,54,177,54,172,94,228,94,198,130,198,224, +186,238,173,238,162,154,243,155,96,142,96,70,34,70,34,142,97,142,88,170, +113,210,16,218,103,194,64,10,65,204,120,22,149,56,222,22,193,58,116,74, +239,74,170,132,171,10,116,134,148,106,171,76,236,126,204,104,175,74,110,162, +243,162,168,138,138,198,241,232,106,240,144,232,176,216,200,194,213,163,92,138, +92,68,32,68,32,138,93,138,82,164,103,208,16,210,95,190,60,12,61,198, +126,16,159,42,106,60,245,60,218,14,181,60,122,244,122,96,222,96,223,242, +122,222,223,222,122,186,223,186,158,60,158,100,154,130,143,158,188,60,188,138, +190,148,198,154,223,155,94,130,94,66,28,66,28,130,95,130,86,156,105,190, +18,196,97,178,60,12,61,184,154,12,181,40,84,224,108,190,118,156,124,124, +124,52,218,52,218,96,125,96,126,242,126,130,226,130,226,220,222,232,212,240, +203,240,160,218,161,130,190,218,191,130,126,174,227,175,58,52,89,76,34,32, +116,32,77,66,18,76,124,76,111,106,82,76,82,122,78,134,68,140,61,140, +22,130,58,100,81,76,172,22,154,60,139,82,236,54,159,54,158,80,176,106, +196,124,233,140,150,136,172,124,190,102,200,82,209,54,194,194,194,160,56,160, +56,194,195,194,188,208,223,240,24,230,207,226,126,228,127,127,88,134,88,66, +26,66,26,134,89,134,84,166,105,208,12,210,97,192,56,10,57,200,110,44, +229,44,118,72,215,72,104,102,237,102,102,152,132,126,152,98,166,54,175,8, +236,156,208,132,189,102,190,132,166,138,139,142,116,172,225,172,168,244,169,138, +110,230,142,206,169,172,230,228,169,177,26,34,131,34,34,58,125,58,16,80, +137,80,82,80,83,12,20,148,44,136,60,116,66,94,67,80,64,102,118,102, +118,118,112,130,100,136,83,136,170,12,150,52,137,68,236,46,155,46,158,66, +170,90,192,112,216,124,235,132,140,130,170,114,190,92,200,66,205,46,198,190, +198,158,60,158,60,190,199,190,184,204,219,240,26,230,205,224,126,138,127,227, +84,140,84,66,28,66,28,140,85,140,80,166,101,208,16,210,95,194,56,10, +57,200,102,44,237,44,144,68,145,8,190,68,191,8,98,84,245,84,118,240, +118,120,228,120,228,216,224,226,214,232,197,232,154,84,154,114,150,144,133,190, +168,168,151,140,188,84,188,120,186,140,174,178,163,206,214,188,185,147,90,130, +90,62,30,62,30,130,91,130,82,160,97,198,14,194,89,180,60,16,61,184, +104,40,235,40,140,62,141,14,192,62,193,12,196,72,217,84,102,96,239,96, +160,66,132,118,101,150,238,146,204,126,179,96,108,170,225,170,142,134,142,176, +132,206,105,238,192,240,193,137,94,138,94,66,30,66,30,138,95,138,88,164, +109,206,16,210,99,186,60,12,61,196,108,40,237,40,148,60,149,8,190,60, +191,6,212,138,212,72,130,72,130,138,213,138,130,106,213,106,110,172,239,172, +100,236,134,224,156,202,168,170,169,146,232,236,206,218,188,198,173,173,92,130, +92,62,32,62,32,130,93,130,86,154,101,196,18,196,93,178,62,10,63,184, +240,24,126,24,126,140,116,184,95,230,226,142,226,68,152,68,152,142,227,142, +152,106,227,106,190,32,177,68,190,142,190,222,184,234,172,238,163,238,160,172, +133,220,214,172,239,217,90,140,90,64,28,64,28,140,91,140,80,160,103,200, +16,206,97,190,58,16,59,196,210,148,210,46,126,46,126,148,211,148,126,80, +211,80,126,114,211,114,118,184,97,230,158,164,183,196,210,178,239,218,140,178, +140,226,142,236,152,240,188,240,200,230,207,214,164,14,155,47,84,146,84,74, +26,74,26,146,85,146,82,176,95,214,14,216,89,198,54,16,55,204,150,16, +181,40,98,50,239,50,122,72,122,124,218,124,219,72,144,68,199,108,194,66, +143,106,114,244,114,156,222,156,222,220,218,232,206,238,191,238,182,176,201,208, +172,132,142,198,195,199,84,134,84,62,28,62,28,134,85,134,82,162,97,204, +18,210,91,190,56,12,57,198,158,12,187,38,90,240,102,218,114,182,118,146, +118,48,243,48,118,114,245,114,134,84,220,84,220,144,135,144,180,164,181,62, +140,244,140,178,220,178,221,244,140,222,221,223,82,144,82,72,26,72,26,144, +83,144,84,174,103,218,18,216,93,196,56,16,57,204,156,14,179,36,112,46, +233,46,114,126,114,94,230,94,231,124,138,62,159,94,208,60,185,94,158,110, +185,134,102,144,243,144,154,144,154,184,146,204,130,222,107,242,174,236,190,236, +206,226,212,208,212,174,155,175,28,38,123,38,16,66,131,66,38,82,23,114, +108,88,131,112,64,66,62,90,56,114,50,130,33,144,94,66,94,122,90,134, +82,136,75,136,78,66,79,10,174,10,156,56,137,84,236,50,161,50,162,70, +174,90,198,114,220,126,237,132,144,132,170,118,190,98,206,74,213,50,194,194, +194,156,62,156,62,194,195,194,190,208,225,242,26,232,209,226,126,134,127,229, +92,136,92,66,26,66,26,136,93,136,88,160,109,200,14,202,99,184,58,14, +59,192,108,48,235,48,106,90,245,90,152,90,153,14,194,90,195,16,218,184, +218,124,126,124,126,184,219,184,126,152,219,152,174,184,175,90,148,202,99,240, +190,202,239,241,92,132,92,62,28,62,28,132,93,132,88,158,109,202,16,206, +101,186,58,8,59,196,102,38,243,38,224,136,224,68,118,68,118,136,225,136, +118,102,225,102,154,136,155,8,188,136,189,8,130,244,130,164,212,164,213,244, +130,226,213,226,130,194,213,195,90,134,90,62,30,62,30,134,91,134,88,160, +103,204,18,202,97,184,60,12,61,190,110,30,241,30,226,106,226,62,124,62, +124,106,227,106,158,106,159,30,192,106,193,30,126,136,225,136,108,166,243,166, +176,166,176,224,170,234,162,238,151,238,144,186,113,226,200,190,237,229,86,150, +86,74,28,74,28,150,85,150,82,176,109,212,16,220,95,194,56,16,57,206, +110,114,110,78,228,78,229,112,206,152,206,112,136,112,136,152,207,152,168,78, +169,12,112,30,141,60,216,24,189,60,114,190,229,190,100,230,245,230,168,230, +169,163,90,140,90,74,28,74,28,140,91,140,80,168,99,200,14,208,91,188, +58,18,59,196,216,24,166,32,111,38,122,56,143,76,212,52,189,76,108,92, +231,92,166,146,167,32,108,146,148,114,167,92,232,142,202,124,167,92,122,182, +103,230,160,158,185,184,206,172,237,212,148,174,148,218,152,228,162,234,186,234, +200,226,207,211,88,142,88,70,24,70,24,142,89,142,76,170,97,208,14,216, +87,190,56,12,57,200,154,10,128,38,111,58,222,112,222,70,120,70,120,112, +223,112,174,70,198,34,135,34,166,70,166,112,132,142,109,154,150,126,164,146, +178,168,178,186,178,214,166,232,152,240,135,242,110,192,142,170,165,148,98,232, +146,202,179,174,222,132,177,164,238,224,216,202,202,176,195,153,106,14,78,48, +51,70,22,112,72,104,120,88,160,62,178,42,85,42,236,110,186,102,144,90, +112,70,81,46,116,106,153,116,104,128,153,138,106,194,106,158,38,158,38,194, +107,194,100,208,117,238,22,232,109,224,74,126,75,226,220,194,220,158,140,158, +140,194,221,194,212,206,231,238,130,230,221,224,180,128,181,227,92,138,92,64, +30,64,30,138,93,138,88,168,101,216,16,206,95,192,60,14,61,198,156,10, +179,34,116,44,229,44,108,84,239,84,138,58,157,84,200,54,181,84,216,172, +216,110,128,110,128,172,217,172,128,142,217,142,112,200,239,200,172,244,173,173, +90,136,90,68,30,68,30,136,91,136,80,162,97,208,16,204,89,186,58,14, +59,192,152,10,177,30,104,44,237,44,104,72,121,100,104,152,131,120,224,66, +205,98,204,118,231,150,180,120,197,154,186,82,138,140,189,140,164,54,138,98, +173,98,102,180,241,180,168,242,169,155,100,48,137,66,52,32,186,32,133,62, +30,70,214,70,201,98,26,116,82,100,127,70,132,70,132,116,126,126,109,126, +112,190,112,154,40,154,40,190,113,190,104,206,121,238,18,232,111,220,76,118, +77,224,220,188,220,152,146,152,146,188,221,188,216,204,237,238,132,230,225,220, +182,116,183,225,82,140,82,66,30,66,30,140,83,140,78,170,91,216,14,212, +85,198,56,12,57,202,92,46,179,46,102,78,171,78,162,144,162,108,112,108, +112,144,163,144,136,78,137,10,110,164,121,200,104,220,177,206,160,162,143,212, +230,24,208,60,183,92,230,96,208,126,185,156,236,158,202,204,159,241,84,140, +84,68,30,68,30,140,85,140,82,162,97,204,14,204,91,188,56,18,57,194, +102,46,235,46,216,130,216,74,116,74,116,130,217,130,202,142,223,172,108,162, +213,160,164,14,165,160,118,186,95,236,162,176,181,202,208,186,237,222,138,180, +138,220,142,232,154,238,186,238,200,228,207,216,116,102,217,103,92,136,92,68, +28,68,28,136,93,136,82,164,105,210,12,210,95,190,60,14,61,198,222,16, +180,24,113,30,110,82,233,82,170,130,171,26,126,46,147,68,212,42,189,82, +106,136,140,108,163,82,238,134,210,116,190,98,177,82,122,244,122,146,218,146, +219,244,122,184,219,184,122,222,219,222,168,222,169,147,88,146,88,72,26,72, +26,146,89,146,86,176,101,224,16,218,93,202,56,16,57,208,132,16,155,40, +214,12,191,42,106,54,233,54,122,82,221,82,110,110,233,110,102,152,243,152, +170,152,171,54,130,128,147,152,212,126,195,152,128,246,128,182,216,182,217,246, +128,226,217,227,86,128,86,66,30,66,30,128,85,128,80,156,97,200,12,204, +89,180,58,12,59,188,96,40,235,40,142,56,143,10,190,56,191,10,130,58, +99,102,122,166,123,72,162,56,181,74,128,82,229,82,128,106,221,106,128,130, +221,130,130,154,235,154,174,154,175,82,104,178,204,178,174,206,142,224,116,234, +87,240,234,236,204,228,178,220,152,204,127,179,92,140,92,68,28,68,28,140, +93,140,84,172,101,210,12,212,93,196,58,12,59,202,104,34,239,34,116,94, +116,62,228,62,229,94,152,62,153,10,192,62,193,8,136,90,205,90,114,116, +229,116,112,158,140,146,158,130,173,116,152,136,166,152,176,170,178,194,176,216, +174,230,162,236,145,238,114,192,142,176,167,154,116,222,148,204,177,176,222,138, +175,166,236,222,216,198,204,178,195,155,84,136,84,66,28,66,28,136,85,136, +82,164,93,202,15,204,16,204,89,186,56,14,57,194,154,12,128,36,105,50, +238,62,116,62,116,146,110,192,83,238,178,62,198,34,131,34,164,74,137,96, +198,76,227,96,174,90,193,104,130,114,245,114,136,140,227,140,136,164,225,164, +142,244,142,190,220,190,221,244,142,226,221,227,78,138,78,66,24,66,24,138, +79,138,74,164,89,202,12,206,81,186,50,14,51,194,152,12,183,38,240,48, +108,48,108,166,100,202,81,236,140,62,161,80,116,90,235,90,208,60,189,90, +116,142,241,142,128,116,218,116,218,168,129,168,160,242,161,90,188,242,189,90, +116,228,140,198,161,168,236,224,216,206,193,169,86,130,86,62,28,62,28,130, +87,130,80,158,97,200,16,202,91,186,56,10,57,192,98,38,241,38,146,54, +147,8,186,54,187,8,222,110,222,70,116,70,116,110,223,110,148,110,149,70, +184,110,185,70,196,124,219,140,240,148,118,148,118,196,108,220,97,240,126,178, +155,198,220,170,190,204,149,232,170,122,172,156,182,188,198,216,218,232,228,236, +236,230,241,209,14,76,239,76,88,14,68,54,187,54,180,76,194,32,79,32, +34,98,60,96,90,90,111,82,106,76,120,88,130,100,136,112,138,130,134,142, +126,148,116,150,101,146,36,120,70,114,125,94,20,146,78,136,135,110,200,86, +135,110,230,146,200,134,174,118,157,102,108,198,108,172,36,172,36,198,109,198, +100,210,119,238,20,230,109,224,74,148,75,226,216,198,216,172,140,172,140,198, +217,198,206,210,231,240,132,230,219,224,178,142,179,227,36,24,229,24,62,46, +200,46,200,66,62,66,63,46,32,114,32,86,224,86,225,112,54,108,203,108, +186,130,84,130,84,156,186,156,187,130,46,176,46,200,112,200,112,176,47,176, +148,174,148,198,216,198,216,174,149,174,108,210,125,238,24,230,121,230,214,210, +233,238,140,230,227,230,78,160,79,230,178,158,179,230,128,16,129,86,36,154, +62,142,84,126,103,109,126,116,235,116,128,136,227,136,128,156,227,156,128,178, +241,178,134,100,99,136,120,186,121,114,164,94,185,110,112,96,154,96,154,26, +112,26,113,96,112,50,155,50,112,74,155,74,182,94,182,26,224,26,224,94, +183,94,182,48,225,48,182,74,225,74,170,178,171,116,104,192,204,192,178,212, +140,230,95,240,238,238,202,236,172,226,146,208,131,192,86,136,86,64,30,64, +30,136,85,136,78,164,95,210,16,210,87,192,58,18,59,199,88,14,66,66, +43,98,212,56,71,56,16,124,241,124,58,150,58,224,201,224,200,244,201,152, +130,224,131,57,44,96,44,22,110,22,111,94,78,42,78,82,66,104,48,120, +25,132,86,98,115,122,144,96,144,22,212,22,213,94,178,42,178,84,166,106, +150,120,137,128,190,94,231,126,76,122,58,148,43,164,210,146,61,146,12,178, +243,178,202,188,203,242,52,192,52,232,203,222,130,146,131,227,22,36,129,36, +30,62,123,62,76,62,77,8,18,154,32,132,36,122,36,86,116,86,116,118, +37,118,76,118,77,86,138,76,156,56,156,26,204,26,204,70,239,64,236,146, +204,140,178,126,158,108,146,90,216,90,192,116,164,134,135,144,82,136,64,160, +49,176,208,162,65,162,14,194,243,194,56,216,56,236,201,232,200,244,201,216, +128,234,129,163,42,18,34,62,23,92,92,60,37,60,12,116,101,116,88,216, +89,142,28,142,28,210,89,202,58,60,59,204,88,242,102,222,116,180,116,58, +230,58,221,80,164,58,165,8,164,30,227,30,130,96,209,86,164,68,164,102, +166,112,176,116,206,116,216,108,225,96,226,136,176,142,137,144,142,158,161,176, +220,154,203,176,128,188,243,188,184,142,184,224,176,242,159,243,104,24,60,38, +23,46,16,98,107,98,36,242,36,148,94,148,95,238,36,218,95,218,68,148, +69,36,222,26,170,36,130,40,130,230,173,198,130,116,235,116,180,34,182,124, +194,186,212,222,224,232,230,234,236,228,241,211,72,20,50,68,23,110,128,64, +53,64,98,108,79,64,170,20,152,68,127,116,240,64,155,64,204,110,177,64, +54,152,211,152,22,224,237,225,74,12,48,54,23,82,124,44,55,44,94,76, +75,44,164,10,140,60,123,80,236,42,151,42,190,76,173,42,44,106,221,106, +16,160,243,160,132,106,132,220,124,236,99,237,80,16,54,56,29,82,126,48, +61,48,94,78,77,48,174,12,152,52,133,78,240,46,157,46,202,76,181,46, +38,104,178,104,158,146,202,146,178,182,142,210,104,228,67,238,88,104,80,154, +60,194,21,232,104,148,120,178,142,200,180,222,239,239,78,12,54,54,29,84, +132,44,61,44,109,78,104,76,87,44,174,12,137,78,238,42,159,42,210,78, +185,42,82,124,76,162,224,162,218,220,210,232,192,240,167,240,32,202,189,202, +182,162,186,100,45,101,76,16,52,54,27,82,130,48,57,48,96,78,83,48, +172,14,154,54,135,78,240,46,159,46,200,80,183,46,38,102,227,102,38,236, +64,220,84,194,92,162,93,102,176,244,177,102,20,164,243,165,72,12,46,54, +21,78,124,46,53,46,94,78,77,46,174,10,150,50,131,74,240,46,155,46, +198,76,181,46,64,186,64,98,194,98,195,182,128,120,128,150,116,186,90,212, +60,228,25,238,142,160,142,212,146,226,160,234,210,234,230,220,235,201,76,16, +48,58,21,86,130,46,59,46,96,78,79,46,172,14,154,52,131,80,242,46, +159,46,198,76,185,46,216,98,128,108,68,108,68,146,56,190,25,238,126,244, +127,108,232,230,206,204,186,158,180,128,179,103,74,18,48,54,21,82,124,48, +55,48,93,80,90,76,73,48,168,16,147,56,238,46,153,46,192,66,179,46, +130,76,131,244,190,92,128,100,50,106,46,150,212,150,208,198,200,212,188,216, +175,216,32,226,70,206,104,178,131,153,80,12,54,52,27,84,128,48,59,48, +88,70,77,48,174,14,152,52,135,78,242,48,157,48,204,82,183,48,96,92, +60,132,31,154,160,232,186,232,200,222,208,208,216,114,77,114,46,204,82,180, +110,148,129,114,62,240,100,222,136,192,160,148,173,115,70,14,50,52,25,82, +118,46,55,46,96,82,73,46,164,12,142,54,125,80,244,44,149,44,198,74, +175,44,28,108,125,108,24,220,127,192,76,108,77,204,154,248,154,100,220,100, +194,144,216,160,230,178,232,198,216,214,189,217,74,12,50,52,27,84,122,44, +57,44,96,68,79,44,172,12,148,50,135,66,242,44,153,44,196,66,181,44, +224,90,52,90,52,230,233,230,188,194,188,126,96,126,96,194,189,195,68,18, +50,56,27,84,122,46,57,46,90,78,73,46,168,18,144,60,129,82,234,46, +155,46,200,78,179,46,198,186,198,104,62,104,62,186,199,186,62,144,199,144, +18,226,241,227,70,18,48,62,23,98,128,50,57,50,102,90,83,50,172,18, +145,76,240,48,159,48,206,92,187,48,76,98,54,134,35,160,226,130,59,130, +58,174,213,174,22,226,239,226,132,226,133,101,74,10,50,48,27,74,122,38, +57,38,98,66,77,38,166,10,146,50,125,76,238,38,153,38,202,74,175,38, +88,80,58,118,23,148,236,104,71,104,112,242,113,104,208,146,113,146,212,194, +113,195,76,10,48,54,23,84,128,48,53,48,106,72,85,48,136,76,156,46, +175,10,242,46,157,46,200,78,181,46,80,80,54,124,27,156,164,236,194,236, +212,222,216,104,67,104,154,196,154,142,76,142,76,196,155,197,76,14,46,72, +21,102,124,62,53,62,96,96,77,62,118,104,143,128,176,10,154,56,135,84, +238,60,153,60,206,106,181,60,38,138,225,138,70,156,107,212,20,228,243,228, +182,154,147,229,78,16,54,52,23,82,126,46,59,46,94,70,77,46,132,68, +171,16,242,46,149,46,188,70,169,46,44,94,212,94,212,216,204,230,190,240, +173,240,28,126,183,126,152,206,152,162,60,162,60,206,153,207,72,14,46,54, +19,80,124,48,51,48,90,70,77,48,132,72,152,50,177,16,240,46,157,46, +194,72,181,46,38,96,204,96,202,122,196,138,182,144,174,146,161,146,34,166, +60,158,86,142,104,122,119,96,70,248,70,170,200,170,201,248,70,222,201,223, +74,16,48,60,25,88,124,54,53,54,102,88,83,54,172,14,150,60,131,86, +242,52,155,52,200,90,181,52,158,240,158,114,216,114,217,238,158,212,217,212, +32,120,120,120,114,210,108,224,94,228,79,228,72,84,72,126,68,160,56,198, +38,226,25,243,72,16,44,56,23,78,122,46,53,46,94,76,77,46,170,14, +144,52,127,72,238,46,149,46,178,46,199,76,48,86,75,112,96,120,210,112, +204,180,198,196,186,200,171,200,98,200,122,180,138,154,146,126,149,82,20,138, +66,138,67,210,30,238,60,210,72,210,90,234,237,235,76,14,52,54,25,84, +128,48,57,48,90,72,79,48,142,68,160,38,175,12,242,46,157,46,208,80, +187,46,166,96,219,144,118,78,52,134,199,126,70,244,70,166,196,166,197,242, +70,222,197,223,76,14,50,54,25,82,128,50,53,50,104,82,85,50,176,12, +158,50,139,78,244,52,159,52,204,80,187,52,26,118,127,118,34,186,119,158, +84,92,84,224,72,240,51,240,150,232,150,106,220,106,221,226,150,206,221,207, +138,68,158,44,175,16,148,88,148,146,154,156,174,160,210,160,224,150,231,132, +212,96,149,124,240,44,159,44,198,76,185,44,74,16,50,52,25,82,134,46, +55,46,98,78,83,46,54,82,54,160,123,140,54,114,117,114,18,194,239,194, +128,244,129,169,74,14,50,54,27,82,126,46,57,46,94,72,79,46,80,94, +63,130,212,110,75,110,172,10,145,58,240,44,155,44,205,82,204,82,185,44, +28,152,237,152,136,152,137,82,32,238,64,228,92,208,108,180,113,152,156,152, +156,218,160,230,178,238,206,238,226,226,233,207,72,12,48,50,21,76,120,44, +53,44,90,72,75,44,168,12,144,50,125,74,238,42,151,42,192,74,177,42, +32,98,88,98,44,150,94,150,80,184,60,214,23,240,42,172,64,200,92,220, +130,228,237,228,214,92,160,102,113,104,124,132,124,186,223,186,166,186,167,102, +218,138,167,139,172,18,149,60,236,50,157,50,204,88,171,50,70,18,42,62, +21,88,122,52,51,52,92,84,69,52,126,78,78,128,19,158,236,152,206,142, +172,124,142,104,123,84,70,142,185,142,64,188,197,188,28,232,227,232,128,232, +129,143,80,12,52,48,23,72,126,42,59,42,88,64,79,42,172,12,152,46, +139,62,240,40,157,40,196,72,181,40,110,74,76,100,47,118,90,90,176,90, +145,124,60,124,206,124,207,210,22,158,243,158,58,196,207,196,134,124,134,224, +126,236,101,241,72,12,48,52,21,82,120,46,53,46,90,80,69,46,164,8, +146,50,127,76,152,82,132,124,113,154,238,46,149,46,198,80,175,46,24,128, +105,128,26,222,97,192,68,86,69,204,146,134,181,154,120,196,203,166,138,110, +222,110,222,204,214,226,194,236,169,237,72,16,48,56,27,82,126,44,57,44, +92,78,75,44,168,16,148,54,127,80,238,44,155,44,194,78,177,44,38,102, +221,102,74,120,56,164,35,202,104,182,67,138,188,120,168,168,151,202,218,192, +198,166,179,144,24,230,237,230,130,230,131,103,78,12,50,46,31,66,126,38, +57,38,92,60,81,38,169,12,168,14,154,40,139,58,240,38,155,38,194,62, +183,38,34,86,233,86,202,172,202,114,58,114,58,172,203,172,132,86,132,144, +126,188,108,214,60,232,21,238,68,182,128,222,186,232,239,234,58,142,203,143, +76,12,52,50,27,78,134,44,57,44,98,76,81,44,174,12,135,70,238,42, +155,42,200,72,181,42,26,116,101,116,24,184,101,154,68,72,68,222,60,236, +50,242,37,242,232,196,230,212,216,230,142,230,130,226,124,210,124,94,216,94, +216,156,125,156,168,156,169,95,70,14,48,52,21,84,128,40,55,40,100,76, +79,40,172,12,145,58,242,38,157,38,202,66,179,38,56,90,103,112,206,86, +157,116,56,248,56,128,202,128,202,222,198,234,186,240,169,240,56,160,203,160, +56,196,203,196,128,128,129,79,72,10,50,50,25,82,128,44,55,44,80,44, +103,78,74,86,50,136,27,172,172,8,152,48,129,80,244,42,157,42,204,78, +183,42,158,80,138,126,117,158,98,206,99,118,238,118,143,118,148,142,162,176, +186,204,214,226,237,238,96,240,130,228,156,208,182,182,194,152,201,118,62,246, +63,113,72,10,50,42,23,66,130,32,59,32,94,50,83,32,16,124,241,124, +126,56,127,124,144,44,175,8,240,32,157,32,196,50,183,32,214,74,47,74, +56,98,205,98,60,244,60,148,196,148,196,222,190,236,176,240,167,240,60,176, +197,176,60,204,197,205,70,10,44,48,21,74,128,34,53,34,90,56,81,34, +164,12,152,36,139,54,238,36,153,36,190,56,181,36,40,78,223,78,54,104, +205,104,18,130,243,130,128,130,129,64,68,212,68,158,190,158,191,210,34,242, +74,236,104,220,122,198,133,172,144,208,223,241,70,14,50,52,21,84,126,46, +55,46,90,68,77,46,166,16,148,48,133,68,194,70,179,46,242,46,151,46, +224,92,46,92,46,232,233,232,72,126,215,126,94,140,117,162,180,138,163,160, +68,170,227,170,141,112,138,112,138,170,130,188,104,208,77,216,152,188,205,209, +78,14,56,50,29,80,126,46,61,46,100,76,85,46,166,12,152,44,135,66, +238,44,153,44,188,72,179,44,66,96,175,96,24,128,239,128,128,86,129,128, +210,84,164,124,122,150,84,166,27,188,80,246,80,164,196,164,197,246,80,196, +197,196,80,226,197,227,78,16,54,54,27,84,124,48,59,48,92,66,83,48, +172,14,150,52,129,78,238,48,155,48,192,72,179,48,44,100,227,100,98,84, +99,124,172,78,173,124,26,142,243,142,128,122,88,164,54,190,27,206,82,246, +82,176,206,176,207,246,82,224,207,225,82,14,58,52,25,80,132,44,65,44, +102,74,85,44,176,14,150,54,129,74,199,68,232,44,159,44,196,68,177,44, +20,124,93,124,24,190,103,162,70,82,70,228,58,240,45,240,114,128,243,128, +142,88,143,242,206,90,207,242,142,168,207,168,142,218,207,219,74,16,52,50, +25,78,128,40,59,40,98,70,81,40,168,14,152,48,139,68,238,42,157,42, +194,66,179,42,112,88,210,88,188,110,158,134,126,148,105,158,234,152,202,144, +176,132,154,118,125,88,24,110,105,110,24,174,93,144,66,74,66,230,52,238, +37,238,116,176,213,176,98,204,229,204,166,152,167,245,68,16,42,54,15,78, +128,46,49,46,92,74,75,46,166,16,144,54,127,74,238,44,151,44,196,74, +181,44,198,152,198,88,56,88,56,152,199,152,56,120,199,120,124,152,125,88, +14,182,239,182,88,182,84,204,74,222,60,232,44,236,33,238,174,242,175,183, +78,10,56,48,27,74,126,40,61,40,174,10,152,44,127,72,236,40,157,40, +202,74,183,40,102,70,87,40,200,170,200,106,60,106,60,170,201,170,60,138, +201,138,18,202,239,202,128,246,129,106,72,78,105,102,176,72,143,107,76,16, +56,48,29,76,122,50,55,50,90,80,73,50,170,16,152,50,137,72,234,50, +153,50,188,80,173,50,112,76,139,96,42,138,42,104,220,104,221,136,112,124, +78,146,43,166,154,124,225,170,70,172,191,172,26,228,233,228,130,228,131,173, +66,18,46,48,19,74,126,46,49,46,74,46,89,76,114,70,135,94,168,16, +152,46,135,68,240,48,153,48,198,78,183,48,40,136,40,102,216,102,217,136, +84,112,62,152,33,186,20,238,58,230,92,212,112,178,120,142,69,142,68,174, +101,196,174,198,186,198,198,186,198,138,148,138,148,220,154,232,166,238,216,238, +230,224,235,205,76,10,50,46,23,72,130,38,57,38,96,66,83,38,174,10, +158,38,143,56,242,38,161,38,200,66,183,38,18,118,247,118,44,88,200,88, +200,144,45,144,130,244,131,74,62,160,56,196,44,224,27,242,102,168,75,220, +152,168,181,214,204,246,205,159,76,12,54,50,29,78,130,42,61,42,98,76, +81,42,172,10,154,50,133,78,242,42,159,42,212,68,187,42,192,76,211,92, +232,102,50,102,50,182,42,210,21,242,72,134,147,134,142,202,142,166,80,166, +80,202,143,202,166,68,170,120,178,170,198,212,218,236,228,238,238,234,243,214, +218,134,198,178,174,210,145,239,72,12,50,46,25,72,126,38,57,38,96,66, +81,38,170,12,152,42,139,56,240,38,157,38,198,64,181,38,196,108,196,82, +66,82,66,108,197,108,18,134,243,134,128,134,129,64,68,212,68,160,194,160, +195,210,123,176,122,174,122,202,114,214,98,224,70,234,37,242,142,210,217,245, +76,14,50,52,27,78,128,42,59,42,90,72,71,42,142,56,156,40,173,14, +238,40,157,40,196,72,173,40,202,148,202,96,58,96,58,148,203,148,58,124, +203,124,118,72,109,96,38,174,219,174,50,204,211,204,22,232,243,232,130,232, +131,175,74,14,50,48,23,72,130,38,59,38,168,12,154,40,137,64,102,68, +85,38,238,38,157,38,200,66,185,38,68,72,40,120,19,148,52,244,53,102, +76,116,243,116,104,82,200,82,193,116,116,126,102,152,87,168,218,150,105,150, +74,186,243,186,158,150,158,186,148,206,132,222,110,232,87,238,240,238,208,228, +184,214,159,187,70,14,50,44,29,70,122,36,57,36,166,14,148,40,129,64, +238,36,153,36,90,60,77,36,196,66,181,36,40,88,219,88,50,110,209,110, +18,134,235,134,96,134,97,70,162,134,163,66,64,242,64,158,198,158,198,222, +194,234,178,240,163,240,18,204,239,204,64,180,199,180,130,204,131,135,72,14, +46,58,27,86,126,44,55,44,96,74,79,44,170,16,152,48,133,72,242,44, +155,44,196,72,179,44,224,90,48,90,48,234,235,234,120,112,121,210,158,112, +159,210,70,124,121,124,72,154,121,154,70,186,121,186,158,124,213,124,158,154, +207,154,158,186,217,187,78,14,48,50,23,70,124,38,59,38,100,66,85,38, +162,12,146,44,129,66,238,36,151,36,198,64,183,36,40,80,227,80,206,150, +206,110,58,110,58,150,207,150,106,150,107,80,156,148,157,80,22,180,241,180, +132,242,133,150,28,238,84,214,133,180,236,236,176,210,133,181,66,12,46,48, +21,74,122,44,51,44,88,74,73,44,164,12,146,46,133,64,232,42,149,42, +196,74,179,42,202,148,202,92,54,92,54,148,203,148,114,66,103,92,88,102, +175,138,170,100,114,126,75,136,50,172,50,234,121,212,114,184,51,184,144,170, +144,216,148,226,160,232,214,232,228,218,235,202,214,168,145,195,70,14,46,46, +21,70,126,36,55,36,98,62,83,36,166,12,150,38,129,62,238,34,153,34, +194,56,183,34,212,66,142,76,76,78,46,78,46,164,36,204,23,234,208,144, +216,126,78,126,78,186,70,214,55,240,102,160,183,150,134,138,134,166,138,174, +148,176,186,176,198,172,209,166,208,102,137,102,136,126,137,88,90,240,104,232, +114,222,118,214,118,198,182,198,182,220,186,230,196,234,216,234,232,224,239,205, +64,14,44,46,21,70,122,44,47,44,84,64,69,44,164,12,144,46,125,68, +230,40,149,40,196,68,179,40,24,98,131,98,116,162,116,126,44,126,44,162, +117,162,78,240,79,72,24,226,60,190,79,162,118,206,79,168,170,68,156,108, +137,140,208,146,222,108,157,108,174,126,174,140,166,176,148,210,117,238,236,232, +210,210,188,182,173,153,72,8,46,48,19,76,118,38,53,38,90,60,77,38, +162,6,142,44,127,60,238,36,147,36,186,60,171,36,208,118,208,84,54,84, +54,118,209,118,104,118,105,84,156,118,157,84,228,154,56,154,56,196,44,218, +23,236,62,186,101,206,170,128,193,144,140,118,150,160,166,200,188,226,212,238, +224,238,230,232,237,210,202,172,158,210,136,222,113,233,74,14,44,56,27,76, +122,42,55,42,96,70,81,42,174,12,154,44,137,62,242,42,157,42,198,72, +183,42,74,84,48,92,48,168,75,158,178,92,208,92,208,164,179,164,152,162, +152,98,98,98,98,162,153,162,98,130,153,130,128,72,113,98,102,178,92,210, +78,222,54,232,33,238,148,180,148,218,152,228,162,236,214,236,226,226,233,211, +78,14,52,48,29,74,128,42,59,42,98,68,85,42,174,12,158,40,141,60, +238,40,159,40,198,68,181,40,116,66,143,82,230,90,52,90,52,166,46,202, +31,238,52,122,206,122,206,154,53,154,106,154,107,90,156,154,157,90,90,176, +90,236,141,220,141,192,138,192,91,192,164,176,164,226,172,234,182,236,216,236, +228,226,233,210,212,178,165,201,78,14,48,52,25,74,126,42,57,42,96,66, +83,42,168,12,146,46,131,68,238,40,151,40,194,66,179,40,40,88,40,224, +119,224,60,88,73,118,128,90,111,118,54,132,129,132,92,206,93,74,58,192, +93,140,126,182,93,148,228,76,186,82,150,86,150,172,142,210,125,242,148,132, +239,132,198,132,199,245,68,16,44,50,21,70,124,42,51,42,96,66,83,42, +168,14,148,46,133,64,238,40,155,40,196,62,179,40,122,152,58,166,58,78, +192,78,192,128,59,128,58,104,193,104,234,176,192,166,152,148,127,128,206,130, +175,156,16,228,243,228,58,228,58,186,204,186,205,228,108,228,109,186,154,228, +155,187,78,12,50,42,21,66,128,36,57,36,96,58,83,36,172,10,154,38, +135,58,242,34,159,34,198,58,185,34,36,70,235,70,212,122,212,94,56,94, +56,122,213,122,106,122,107,70,158,122,159,70,198,188,198,144,70,144,70,188, +199,188,70,166,199,166,24,210,243,210,134,246,135,189,66,14,40,50,21,68, +122,38,51,38,88,58,75,38,164,10,142,44,125,62,236,36,149,36,192,60, +179,36,44,74,115,74,44,88,38,108,121,108,26,154,56,138,70,118,76,100, +79,74,92,108,92,146,129,132,144,74,225,74,146,88,144,106,233,106,126,158, +152,144,172,124,180,96,185,74,196,106,196,146,202,154,224,154,232,146,239,132, +64,248,64,172,194,172,195,244,64,200,195,200,64,230,195,231,68,18,46,48, +23,72,126,40,55,40,88,62,73,40,166,16,152,40,135,60,234,40,155,40, +194,62,179,40,44,78,112,78,90,108,62,130,19,150,46,102,69,122,140,72, +164,104,194,126,233,148,186,74,161,98,208,92,185,116,84,128,175,128,186,186, +186,156,70,156,70,186,187,186,16,228,233,228,82,196,103,220,172,196,149,229, +66,12,42,52,21,80,126,40,51,40,98,70,79,40,164,10,144,50,127,74, +238,38,151,38,206,70,187,38,24,102,123,102,16,190,119,190,48,190,49,80, +104,190,105,80,48,130,105,130,48,158,105,158,60,204,27,238,84,204,107,226, +118,240,134,216,142,188,144,172,144,106,226,106,219,130,144,152,218,152,204,184, +180,216,149,238,236,234,208,222,182,200,166,176,157,152,182,152,183,73,74,14, +50,54,29,76,128,40,61,40,102,70,85,40,170,12,150,48,131,72,242,38, +157,38,204,68,191,38,28,98,127,98,78,244,79,74,114,164,114,130,44,130, +44,164,115,164,22,224,52,202,79,172,120,208,96,190,79,176,170,66,154,96, +135,118,144,198,144,126,222,126,223,196,190,126,208,86,161,86,161,86,184,144, +184,186,174,206,154,226,131,238,232,234,199,205,80,14,52,52,27,76,130,42, +61,42,104,70,87,42,170,14,152,46,139,62,238,40,157,40,194,66,177,40, +26,110,89,110,28,174,89,150,68,72,68,224,60,236,43,236,138,100,159,128, +152,76,110,90,110,144,151,118,168,84,220,84,218,130,212,142,197,142,168,142, +182,114,187,84,116,242,116,166,216,166,217,242,116,194,217,194,116,226,217,226, +166,226,167,167,98,36,50,44,50,144,200,144,200,40,153,40,126,10,126,146, +116,176,88,208,58,226,23,242,232,234,198,222,164,198,140,166,127,144,100,94, +51,94,150,92,201,93,116,20,54,36,54,120,202,120,202,30,141,30,114,76, +55,76,142,76,203,76,18,164,241,164,94,142,94,184,84,214,66,230,41,240, +172,242,173,143,32,40,225,40,48,72,211,72,24,102,239,102,130,10,108,80, +70,130,17,170,114,136,68,148,69,244,238,166,200,146,174,122,159,102,140,144, +190,144,191,242,68,218,191,218,112,180,69,180,142,180,191,181,112,24,54,38, +54,110,200,110,200,34,139,34,112,72,55,72,146,72,201,72,94,120,58,152, +31,174,174,236,200,236,214,224,220,148,65,148,70,182,47,228,96,182,109,220, +136,178,151,212,174,170,191,205,196,128,196,46,58,46,58,128,197,128,104,46, +119,14,58,72,197,72,58,100,197,100,14,170,241,170,128,246,129,144,18,236, +84,202,123,170,232,236,196,218,166,200,135,171,75,20,16,222,137,194,114,198, +114,60,36,60,37,216,64,60,65,208,90,60,91,204,114,228,245,228,132,36, +220,36,215,228,138,122,217,122,72,20,55,60,160,228,171,37,22,236,38,192, +44,164,44,52,102,52,102,216,96,232,75,232,68,74,83,108,66,156,79,190, +16,132,103,132,124,222,243,222,132,50,239,50,182,222,183,50,76,18,61,53, +24,236,38,198,44,166,44,48,106,48,106,210,100,230,77,230,74,14,59,48, +16,128,107,128,66,74,81,102,66,148,85,176,228,238,229,76,146,74,146,214, +229,208,186,16,187,211,18,236,34,204,40,168,40,54,100,54,100,218,92,232, +75,232,12,130,101,130,66,16,55,54,60,78,81,108,60,156,81,184,122,234, +152,210,186,162,202,118,210,78,217,48,150,20,185,60,138,64,148,112,166,152, +186,186,210,212,237,233,18,238,36,206,44,166,44,50,100,50,100,220,94,234, +82,240,71,240,14,132,101,132,66,72,75,106,64,158,77,192,74,16,67,50, +134,20,134,232,173,212,168,104,135,104,192,24,192,218,196,230,210,236,226,236, +239,216,232,78,193,121,18,236,34,202,40,168,40,48,94,48,94,226,88,236, +76,240,67,240,60,158,71,192,58,76,71,108,12,132,95,132,126,176,126,72, +226,72,227,174,126,156,227,156,176,244,177,14,68,16,59,49,18,238,34,200, +40,158,40,52,98,52,98,210,94,226,82,234,69,234,10,132,99,132,70,14, +57,52,58,76,77,106,60,152,75,182,224,28,182,38,136,46,136,154,128,206, +113,240,138,238,166,216,190,186,210,146,218,100,137,100,238,236,208,212,180,178, +162,136,157,101,20,242,36,212,42,176,42,50,102,50,102,216,98,230,88,236, +79,236,70,14,59,50,64,74,77,106,66,152,81,180,12,132,103,132,162,16, +197,52,124,72,245,72,162,72,162,148,154,190,140,220,123,242,162,128,226,128, +226,188,222,218,208,232,194,236,181,237,22,240,38,204,44,156,44,54,100,54, +100,218,96,230,84,236,73,236,66,76,79,106,66,150,81,180,16,128,101,128, +74,16,55,54,118,44,245,44,216,44,216,212,212,228,202,236,183,236,182,170, +182,88,140,88,140,170,183,171,18,238,34,204,40,164,40,48,100,48,100,216, +94,228,86,232,77,232,66,150,81,186,62,68,75,108,14,130,101,130,68,12, +55,48,122,242,138,212,146,178,146,92,228,92,229,164,146,148,229,148,180,92, +181,12,246,48,181,49,20,236,34,204,42,162,42,50,100,50,100,214,94,228, +82,234,71,234,62,74,77,104,68,148,79,180,14,126,101,126,72,16,57,50, +138,242,138,72,228,72,229,242,138,142,229,142,138,212,229,212,184,212,185,11, +22,238,36,208,44,176,44,54,102,54,102,214,98,226,86,234,77,234,14,130, +103,130,64,156,85,186,66,80,85,104,70,16,57,54,158,16,142,72,123,112, +242,66,145,66,166,244,167,66,238,122,167,122,238,174,167,175,20,236,36,200, +44,156,44,50,90,50,90,218,84,232,78,236,65,236,68,14,59,50,16,130, +91,130,58,74,71,106,58,154,69,188,110,40,241,40,120,244,120,88,224,88, +225,240,120,216,225,216,158,40,158,110,154,148,145,178,190,40,190,164,225,165, +20,238,34,206,40,170,40,48,100,48,100,220,96,230,84,238,71,238,12,124, +101,124,68,10,53,48,60,72,77,102,64,148,79,182,136,244,136,92,230,92, +230,220,226,232,212,238,201,238,136,136,231,136,136,184,231,184,126,32,155,68, +232,30,203,70,180,92,181,11,20,236,32,206,38,170,38,50,90,50,90,218, +86,230,76,238,63,238,12,126,91,126,66,14,59,50,58,74,69,104,60,152, +71,186,106,236,118,206,124,172,124,32,220,32,220,74,125,74,224,96,188,104, +145,110,144,146,223,142,138,182,233,176,182,106,182,220,186,230,198,234,222,234, +234,220,237,207,20,242,32,210,38,170,38,54,92,54,92,224,86,236,76,240, +67,240,58,78,75,108,58,158,73,186,12,132,93,132,64,16,53,54,112,84, +241,84,120,32,218,32,176,62,176,114,174,124,164,130,151,130,110,230,247,230, +128,230,128,154,222,154,223,230,160,230,161,154,192,230,193,155,20,236,32,206, +38,168,38,48,90,48,90,212,86,228,74,232,63,232,68,16,59,48,58,72, +69,104,12,126,91,126,58,150,71,186,114,58,241,58,134,18,155,42,208,16, +185,58,134,242,134,98,212,98,213,240,134,140,213,140,134,178,213,178,134,218, +213,218,172,58,167,99,22,236,34,208,40,178,40,48,92,48,92,228,84,238, +69,238,16,132,93,132,60,72,71,104,60,156,73,190,70,16,61,48,114,50, +245,50,228,132,228,72,122,72,122,132,229,132,156,132,157,14,192,132,193,16, +132,244,132,160,222,160,223,242,132,192,223,192,132,224,223,225,18,238,32,208, +38,176,38,54,90,54,90,224,82,238,67,238,16,132,91,132,58,76,73,104, +58,156,71,184,66,16,55,54,114,90,241,90,114,50,233,50,156,16,181,38, +140,58,157,90,206,58,185,90,218,176,218,116,128,116,128,176,219,176,128,146, +219,146,116,206,235,206,108,236,243,236,176,236,177,117,16,240,26,214,36,180, +36,56,88,56,88,222,78,238,61,238,58,80,67,104,56,158,69,186,10,132, +89,132,64,16,51,56,106,42,239,42,148,60,149,12,192,60,193,14,116,100, +116,74,230,74,231,100,140,102,205,102,106,130,241,130,112,162,146,150,166,138, +177,130,156,146,172,162,180,184,182,218,178,234,168,240,155,240,218,144,177,172, +238,224,218,206,206,182,197,158,116,192,142,180,171,160,114,228,146,210,179,185, +134,12,82,60,46,80,19,92,238,86,196,74,158,50,127,20,114,58,147,82, +58,98,186,98,151,132,106,126,141,148,26,158,233,158,24,210,68,196,100,176, +123,158,134,208,90,234,91,182,142,176,174,208,204,226,237,234,200,178,169,205, +164,84,182,82,196,72,198,38,68,38,68,104,226,104,222,122,212,134,200,138, +187,138,104,58,139,84,122,10,109,38,112,122,135,144,24,154,229,154,22,218, +68,196,100,174,123,154,126,210,84,238,85,186,146,166,162,194,186,216,231,236, +190,166,167,197,20,44,118,44,112,92,106,102,96,106,83,106,72,12,66,60, +52,90,25,118,216,98,216,36,152,36,152,98,217,98,118,114,145,132,20,142, +239,142,20,214,74,182,100,158,113,142,134,202,90,234,91,168,140,158,156,184, +186,210,237,230,204,160,169,195,160,12,195,32,28,44,229,44,126,118,127,10, +50,66,91,80,30,114,127,86,196,58,142,88,219,114,98,122,147,142,18,152, +239,152,20,218,60,200,96,174,113,152,236,224,202,214,168,194,148,172,139,152, +146,208,92,232,93,178,206,166,173,197,48,20,87,42,28,52,59,70,38,124, +81,74,130,34,109,82,164,82,165,12,202,32,237,72,208,72,170,96,134,108, +85,116,124,124,147,138,20,146,235,146,26,210,64,198,106,170,125,146,136,208, +92,230,93,180,228,232,190,216,162,196,139,162,198,168,167,199,24,120,38,102, +46,80,46,32,112,32,112,68,47,68,112,126,112,96,58,96,58,126,113,126, +162,12,185,32,128,40,227,40,124,82,239,82,150,56,165,82,206,50,189,82, +132,112,227,112,180,144,181,82,128,128,147,152,28,160,235,160,32,222,80,198, +110,176,127,160,138,214,96,234,97,186,138,176,160,200,186,218,227,236,200,176, +169,207,30,18,51,52,12,70,107,70,98,14,69,70,24,116,105,116,12,162, +111,162,62,70,62,172,56,200,44,226,31,242,220,28,166,38,128,40,128,222, +167,186,128,112,235,112,168,210,189,240,172,38,176,80,182,132,194,182,212,222, +222,228,232,224,239,201,30,18,53,50,20,70,117,70,24,114,111,114,18,160, +119,160,74,70,103,18,70,70,70,168,62,196,48,220,27,238,124,34,210,34, +190,68,170,92,123,128,234,128,181,82,130,150,225,150,110,222,239,222,178,222, +179,151,30,18,55,54,18,72,103,72,100,16,73,72,24,112,99,112,14,154, +107,154,64,72,64,130,60,168,48,202,21,238,194,32,235,80,174,14,122,74, +223,68,150,88,111,132,188,88,237,132,162,114,138,154,113,180,148,164,166,192, +190,214,237,238,100,236,138,222,172,202,198,166,212,140,147,141,32,18,55,50, +22,66,107,66,96,18,73,66,28,114,101,114,20,162,105,162,66,66,66,168, +54,208,31,238,216,100,216,32,132,32,132,100,217,100,132,66,217,66,154,110, +132,134,111,150,126,162,126,212,199,212,174,146,147,190,202,190,167,158,196,230, +218,230,228,216,230,130,137,131,18,70,103,70,28,24,51,54,92,20,69,70, +24,112,87,112,14,158,101,158,60,70,60,160,48,200,36,220,21,236,124,26, +124,66,218,66,219,26,170,66,171,10,108,108,243,108,142,76,130,142,116,182, +96,210,77,230,154,138,143,188,224,138,209,176,180,122,180,154,170,188,154,212, +138,226,119,240,234,234,212,212,194,188,181,155,34,46,229,46,82,16,107,38, +176,16,149,46,48,70,213,70,22,96,241,96,130,96,131,46,20,146,245,146, +120,114,74,120,43,122,20,180,54,162,77,146,142,174,101,146,88,174,89,118, +42,184,127,184,70,184,66,206,112,206,104,228,92,238,57,238,184,110,209,132, +150,108,162,168,180,206,210,236,224,238,230,230,237,210,130,238,166,212,188,188, +205,163,24,40,43,72,102,34,87,74,18,96,103,96,62,244,63,10,20,180, +46,144,63,104,98,156,63,116,222,242,223,64,122,68,122,220,223,210,172,214, +173,13,24,40,45,72,106,34,91,74,18,94,111,94,66,246,67,12,18,184, +46,150,67,108,104,158,67,116,162,14,146,72,125,114,242,70,149,70,144,110, +162,154,188,194,237,236,102,236,144,212,170,188,190,150,200,116,209,71,16,102, +103,102,62,242,63,10,24,44,41,80,100,40,85,78,18,186,42,152,63,106, +98,158,63,116,236,190,230,216,218,226,144,226,134,222,126,208,126,32,220,32, +220,118,127,118,174,118,175,33,22,92,101,92,26,38,45,72,102,36,87,70, +64,242,65,12,20,176,48,138,65,100,94,144,65,112,98,226,118,184,124,142, +128,110,128,30,245,30,244,78,129,78,136,230,158,200,170,168,174,134,175,78, +174,126,226,126,218,214,210,226,185,227,54,20,54,54,206,54,207,16,46,78, +46,110,218,110,219,74,128,110,129,12,196,132,163,154,60,134,93,154,126,244, +127,134,18,166,241,166,24,232,66,214,98,192,127,170,230,232,192,216,158,194, +127,167,122,240,122,90,222,90,223,238,106,32,243,32,156,32,156,106,154,136, +148,160,139,176,190,32,190,148,194,160,202,164,223,164,122,212,223,212,16,96, +99,96,62,244,63,12,26,36,45,72,94,40,81,74,18,184,44,142,63,102, +94,154,63,117,124,246,125,132,34,30,77,54,20,108,89,86,132,14,116,42, +97,70,206,74,218,40,119,40,162,54,154,82,142,98,124,108,106,114,89,118, +226,120,157,78,56,130,91,156,192,128,161,156,18,168,237,168,24,234,62,218, +98,194,125,168,230,234,194,222,154,196,125,169,52,44,36,70,21,88,22,130, +72,112,102,86,116,64,41,64,82,64,83,12,116,32,83,32,58,82,79,106, +138,32,216,32,190,76,164,96,125,114,144,62,194,88,233,116,18,168,237,168, +60,134,89,158,188,130,161,168,124,242,125,126,22,232,70,210,100,188,125,168, +230,230,174,208,138,184,125,169,232,24,196,134,239,230,188,20,158,134,197,236, +94,146,147,146,18,236,50,208,64,176,70,146,41,146,50,126,36,154,19,180, +96,168,88,196,155,196,124,244,125,122,26,64,147,64,84,126,85,12,28,114, +58,92,85,64,138,106,85,64,40,22,63,46,134,20,111,50,42,176,57,191, +154,12,185,40,122,86,122,52,230,52,231,86,140,98,213,98,114,142,241,142, +142,168,107,220,204,170,241,216,178,142,178,218,176,230,164,240,149,240,102,96, +19,96,62,242,63,10,20,36,41,72,100,36,83,74,16,184,48,136,63,96, +94,148,63,113,190,30,223,66,162,14,122,62,209,52,106,96,239,96,84,96, +11,96,162,70,130,118,93,154,87,132,56,246,57,14,234,154,198,126,175,96, +168,122,140,154,111,176,190,150,154,184,117,208,222,170,168,214,105,240,18,42, +39,76,98,34,77,72,18,184,44,140,57,104,88,132,57,107,58,246,59,10, +20,40,41,70,94,36,75,72,12,90,93,90,16,178,40,136,59,96,86,148, +59,116,134,22,114,80,91,120,116,244,117,74,138,80,237,80,154,36,214,36, +205,80,168,92,160,120,147,146,226,120,161,120,136,164,241,164,190,120,190,164, +182,194,145,238,232,234,206,196,191,165,16,102,99,102,62,244,63,12,26,42, +41,76,98,42,81,76,16,182,44,142,63,102,94,158,63,124,140,12,124,50, +105,82,104,138,146,106,170,50,125,50,124,80,160,116,206,128,241,130,196,110, +197,12,206,52,239,76,124,244,124,154,214,154,215,244,124,190,215,190,124,224, +215,225,128,24,155,60,102,76,243,76,212,18,183,76,146,184,155,234,218,192, +239,238,160,118,104,222,151,222,228,124,180,224,231,224,142,88,112,148,143,148, +206,88,178,156,213,156,98,38,79,80,22,40,43,78,18,100,101,100,62,242, +63,14,20,186,42,154,63,104,90,156,63,123,108,26,234,26,225,52,138,52, +109,120,130,72,146,92,184,110,243,108,172,26,173,102,210,62,173,62,126,244, +126,136,218,136,218,218,210,236,193,236,126,162,219,162,126,194,219,194,18,92, +97,92,60,242,61,10,24,38,41,72,98,36,83,72,16,176,40,142,61,96, +92,148,61,115,150,42,187,66,124,24,206,24,179,60,112,70,230,70,219,102, +110,118,148,98,177,70,156,120,176,120,184,108,185,70,110,156,239,156,168,242, +169,134,102,218,142,190,169,158,238,214,200,188,169,156,14,100,103,100,62,240, +63,12,22,42,45,78,100,40,81,78,18,184,42,150,63,106,94,152,63,115, +214,130,214,42,122,42,122,130,213,130,164,8,155,42,122,72,213,72,122,102, +213,102,98,176,241,176,194,146,221,162,164,142,164,176,148,202,126,220,101,234, +236,232,196,208,169,176,60,244,61,12,16,92,101,92,96,36,81,72,22,40, +43,74,20,180,42,146,61,98,94,146,61,117,94,28,134,28,134,86,106,86, +106,140,134,140,134,188,126,224,118,232,101,232,214,188,239,228,150,222,227,210, +216,78,216,28,166,28,166,78,217,78,224,164,224,116,160,116,160,164,225,164, +190,78,191,214,24,40,41,74,94,44,79,76,20,98,89,98,56,244,57,12, +24,182,42,146,57,108,82,154,57,119,110,194,50,228,50,28,188,28,188,122, +51,122,50,76,189,76,222,230,158,198,124,162,107,122,208,138,143,181,86,96, +111,122,100,114,42,128,42,28,102,28,102,84,43,84,42,56,103,56,124,28, +223,28,140,50,132,76,225,76,172,28,172,76,150,114,119,136,182,90,182,120, +188,128,200,132,220,132,228,120,231,106,190,202,190,150,60,150,60,202,191,202, +60,176,191,176,18,228,239,229,104,120,104,24,29,24,40,48,69,78,28,114, +105,88,128,24,206,24,207,124,136,44,167,72,128,102,207,80,18,166,239,166, +90,132,90,176,78,208,37,238,172,240,173,131,124,236,144,236,156,228,156,34, +111,34,180,34,228,34,228,222,216,236,195,236,184,74,203,114,178,178,229,134, +118,82,139,124,106,192,157,148,74,16,46,64,17,102,104,66,67,32,58,84, +85,116,40,174,85,232,18,136,104,136,61,199,134,14,78,54,17,76,124,22, +168,52,237,70,66,70,189,70,186,124,186,98,62,98,62,124,187,124,29,152, +28,152,108,152,108,228,98,242,81,242,44,170,71,192,32,226,109,196,134,152, +208,152,208,230,188,242,175,242,142,168,171,190,134,220,209,191,44,36,187,36, +18,64,239,64,122,64,123,12,214,22,154,64,96,90,29,108,78,136,78,92, +192,92,192,136,79,136,78,112,193,112,28,164,112,164,112,226,100,240,83,240, +36,180,73,194,26,224,95,208,134,164,218,164,218,220,210,236,187,236,142,178, +181,192,132,218,203,207,102,112,103,12,150,112,151,12,26,42,103,42,38,72, +103,72,20,100,103,100,150,42,227,42,150,70,215,70,150,100,235,100,26,138, +108,138,108,232,96,240,81,240,130,138,208,138,208,222,198,238,181,238,38,156, +69,180,28,224,109,180,136,154,163,180,130,222,209,179,44,134,44,68,120,68, +120,124,110,134,97,134,44,112,121,112,44,90,121,90,188,132,200,132,210,122, +211,62,160,124,161,68,18,42,239,42,76,16,107,36,180,12,153,36,24,156, +114,156,114,224,102,238,87,238,138,156,220,156,220,224,210,240,191,240,40,174, +69,192,24,222,97,204,148,172,177,188,138,218,201,201,58,18,87,46,18,202, +34,166,40,134,40,58,112,58,112,98,41,98,46,242,46,130,122,130,122,220, +118,232,99,232,46,174,123,174,72,216,73,130,98,210,99,130,136,76,155,116, +130,34,172,34,172,220,164,232,149,232,138,166,173,138,192,34,232,34,232,218, +224,232,207,232,196,74,209,114,190,164,233,129,20,26,119,26,128,36,166,36, +166,228,154,238,143,238,188,36,224,36,224,220,212,234,197,234,188,76,205,112, +186,166,225,134,130,78,149,114,132,170,167,142,104,98,104,60,44,60,44,98, +105,98,32,242,32,128,118,128,118,222,112,234,104,238,93,238,54,144,69,164, +94,144,77,180,56,180,97,180,76,226,77,181,136,126,30,126,30,30,137,30, +66,50,51,70,58,60,121,60,50,84,123,84,92,60,88,86,70,106,57,116, +122,110,89,86,154,58,160,46,160,34,204,34,204,58,235,58,146,78,210,78, +196,102,174,120,149,134,230,134,206,124,176,102,157,78,28,150,108,150,108,222, +98,236,81,236,42,170,69,184,26,230,93,192,134,150,210,150,210,224,200,238, +177,238,140,164,167,184,132,224,191,189,166,112,207,162,188,142,54,142,163,54, +112,92,68,92,123,20,126,142,126,226,116,238,101,238,94,178,45,228,162,176, +221,227,18,44,105,44,18,88,101,74,68,10,68,110,60,122,41,122,120,54, +202,48,206,92,212,112,222,116,234,106,241,86,112,112,140,94,154,68,158,40, +161,12,120,74,167,108,118,126,76,154,131,154,174,132,66,184,201,184,172,160, +217,196,136,184,136,222,130,232,122,238,111,238,96,204,33,238,168,206,233,237, +36,32,219,32,20,108,239,108,76,108,77,8,180,108,181,6,76,58,181,58, +76,82,181,82,18,160,68,134,99,108,238,154,188,130,167,108,164,160,207,188, +164,132,120,164,66,192,191,178,124,118,84,154,135,154,132,186,132,220,130,232, +118,238,109,238,92,202,47,236,164,200,215,231,64,16,91,36,20,140,38,108, +40,94,40,48,114,48,114,86,41,86,160,12,146,50,131,76,232,46,149,46, +160,64,194,100,237,120,136,114,182,92,211,46,166,150,211,188,170,122,50,182, +191,172,114,102,66,142,127,142,130,178,130,222,124,236,116,242,103,242,88,198, +33,232,164,198,223,231,112,24,72,34,33,40,32,60,51,86,68,54,83,82, +120,54,97,92,56,96,40,120,27,140,116,116,45,116,14,158,125,158,114,174, +115,242,40,178,40,222,115,218,76,116,77,218,224,20,137,40,178,48,140,100, +193,98,216,68,146,150,225,144,206,120,235,156,184,146,184,224,178,238,157,238, +158,176,133,218,208,176,239,217,38,30,219,30,54,44,203,44,28,62,233,62, +130,62,131,16,192,114,192,76,70,76,70,114,193,114,28,96,235,96,122,80, +145,94,122,96,141,112,26,200,133,200,50,200,50,132,116,132,117,200,50,148, +117,148,50,166,117,166,50,182,117,182,218,124,174,134,137,136,210,172,231,200, +212,146,146,198,223,188,180,138,144,166,191,162,82,200,82,238,76,240,67,240, +60,214,35,236,102,212,121,230,160,212,137,234,202,208,227,230,184,194,184,234, +178,238,167,239,16,40,127,40,26,74,119,74,10,108,131,108,74,108,75,8, +70,118,46,156,21,184,18,242,74,210,94,182,110,146,55,146,54,170,105,216, +138,58,221,58,128,118,231,118,176,8,176,124,158,180,107,238,232,236,192,174, +177,125,18,48,117,48,68,130,69,12,42,62,25,102,50,94,37,76,100,62, +87,94,114,94,97,72,20,138,69,98,110,132,69,94,64,136,27,188,30,238, +64,216,88,180,96,160,49,160,58,182,101,226,162,20,146,60,129,90,188,238, +214,238,228,226,232,60,149,60,130,134,211,134,170,218,171,78,144,94,153,118, +204,94,191,120,122,198,171,140,208,188,171,149,26,56,123,56,14,100,133,100, +76,100,77,8,46,136,38,190,21,238,40,178,64,204,96,222,152,228,241,226, +80,118,81,212,80,156,127,156,210,204,211,10,152,40,152,152,211,143,28,58, +117,58,18,100,125,100,76,100,77,8,48,134,38,190,19,236,40,184,72,212, +114,224,241,224,80,212,81,116,120,154,81,154,110,186,243,186,144,186,144,32, +210,32,211,186,144,134,211,134,144,82,211,83,28,56,99,56,18,98,103,98, +66,98,67,10,42,136,32,190,17,230,36,176,56,200,86,220,122,226,241,230, +70,112,71,206,70,156,103,156,112,28,183,28,110,124,134,78,145,28,114,198, +152,150,164,110,168,78,135,78,134,118,157,134,192,158,193,44,222,14,222,178, +220,192,210,200,193,201,28,56,99,56,18,98,103,98,66,98,67,8,42,138, +32,190,17,230,34,176,52,196,84,218,122,226,241,228,68,112,69,206,100,154, +69,154,112,32,139,66,106,180,135,108,184,14,170,62,153,96,216,94,230,58, +173,58,187,90,184,90,184,134,172,164,150,192,133,208,230,202,185,135,26,60, +91,60,20,102,95,102,62,102,63,10,44,142,34,194,19,236,69,118,36,180, +62,208,94,226,132,232,241,230,66,118,67,210,106,158,67,158,114,22,103,58, +158,44,109,44,100,72,163,72,136,72,137,10,104,114,116,100,125,72,146,72, +146,106,167,92,182,20,171,58,234,44,177,44,174,70,243,70,204,70,205,10, +172,114,186,92,191,70,214,70,214,98,220,106,228,106,238,102,243,92,124,178, +124,128,212,128,213,180,166,142,166,166,154,190,111,212,178,178,229,213,26,54, +121,54,16,98,127,98,76,98,77,12,60,98,60,136,52,188,23,234,38,126, +17,182,92,98,92,220,82,230,69,230,102,128,127,168,140,242,140,28,216,28, +212,64,206,78,196,84,181,84,140,116,220,116,202,174,157,230,158,116,180,176, +233,235,32,54,117,54,20,100,117,100,78,98,79,10,40,128,27,188,110,126, +123,150,66,100,66,140,56,198,29,238,94,100,94,220,82,232,69,232,130,50, +203,50,124,98,245,98,170,98,171,8,228,36,172,122,113,182,146,246,146,140, +220,140,221,242,146,176,221,176,146,220,221,221,16,36,119,36,102,140,102,76, +32,76,32,140,103,140,34,162,49,198,20,230,125,206,98,158,73,218,132,48, +237,48,120,228,241,228,184,48,185,229,22,34,125,34,110,128,110,78,40,78, +40,128,111,128,40,148,59,188,16,220,129,200,106,148,85,208,128,62,239,62, +132,118,216,118,192,178,119,238,142,118,168,178,235,240,182,118,183,13,16,34, +127,34,138,44,245,44,192,44,192,214,188,226,176,232,157,232,32,236,32,78, +114,78,115,228,32,208,115,208,32,172,115,172,60,34,60,94,56,124,47,148, +86,34,86,126,94,136,115,137,16,30,131,30,144,36,239,36,34,242,34,78, +120,78,121,234,34,172,121,172,34,216,121,216,66,30,66,78,62,114,49,146, +90,30,90,126,96,136,100,138,121,138,136,126,245,126,188,244,189,37,16,32, +129,32,30,238,30,76,114,76,115,232,30,208,115,208,30,170,115,170,58,32, +58,80,56,120,45,152,84,32,84,124,88,134,115,134,134,84,245,84,208,12, +208,218,202,230,194,236,177,236,146,124,177,165,14,32,123,32,28,240,28,78, +110,78,111,236,28,176,111,176,28,214,111,214,56,32,56,84,54,120,47,150, +82,32,82,126,88,136,111,136,122,100,222,74,220,160,218,176,212,180,203,180, +182,200,183,12,148,36,148,212,154,228,170,232,216,232,228,226,236,212,237,197, +12,36,123,36,32,240,32,78,114,78,115,236,32,180,115,180,32,216,115,216, +58,36,58,84,56,124,49,148,84,36,84,128,88,138,115,138,132,78,247,78, +148,240,148,140,224,140,225,236,148,218,225,218,186,140,187,19,14,32,121,32, +28,240,28,76,108,76,109,238,28,214,109,214,28,180,109,180,56,32,56,82, +52,122,43,154,80,32,80,132,84,140,109,140,164,14,144,70,125,106,242,68, +147,68,170,240,171,68,234,118,171,118,236,170,171,171,14,34,117,34,30,240, +30,78,104,78,105,238,30,182,105,182,30,216,105,216,56,34,56,82,52,126, +45,156,80,34,80,136,84,146,105,146,156,18,193,42,132,92,132,56,232,56, +233,92,162,92,162,210,166,224,180,228,218,228,230,220,234,210,237,198,224,116, +163,155,14,32,117,32,28,242,28,76,102,76,103,238,28,180,103,180,28,214, +103,214,54,32,54,92,50,124,43,156,78,32,78,130,84,140,103,140,146,28, +138,68,123,100,232,66,139,66,120,118,241,118,180,118,181,14,162,118,162,156, +152,200,123,234,194,118,194,222,196,228,206,232,224,232,234,222,239,205,18,34, +131,34,34,246,34,76,112,76,113,238,34,176,113,176,34,216,113,216,62,34, +62,80,58,120,49,150,86,34,86,128,90,140,96,142,113,142,176,14,150,60, +127,90,130,156,182,118,224,54,155,54,156,82,185,112,158,246,158,140,226,140, +227,242,158,216,227,217,14,34,127,34,34,238,34,80,112,80,113,232,34,178, +113,178,34,216,113,216,60,34,60,94,58,124,49,156,84,34,84,128,88,140, +96,144,113,144,144,14,144,84,154,100,174,104,214,104,230,90,237,72,224,32, +145,60,144,242,144,134,220,134,221,240,144,176,221,176,144,218,221,219,16,30, +125,30,32,238,32,74,108,74,109,228,32,174,109,174,32,212,109,212,58,30, +58,80,56,118,47,152,82,30,82,124,86,136,96,140,109,140,136,18,237,18, +136,52,157,88,234,46,219,84,122,242,138,204,142,176,142,102,241,102,170,102, +171,18,198,102,199,19,14,28,111,28,118,40,245,40,28,238,28,74,100,74, +101,236,28,176,101,176,28,210,101,210,52,28,52,100,43,148,76,28,76,130, +78,138,86,140,101,140,128,238,128,68,164,68,164,214,162,228,156,232,149,232, +138,120,155,156,190,238,190,68,228,68,228,216,222,230,209,230,200,122,215,159, +12,28,117,28,28,234,28,74,106,74,107,234,28,176,107,176,28,212,107,212, +54,28,54,118,43,154,78,28,78,126,82,138,107,138,218,86,218,26,140,26, +140,86,219,86,122,120,235,120,126,168,227,168,122,220,245,220,178,220,179,121, +14,30,113,30,28,240,28,76,102,76,103,238,28,180,103,180,28,218,103,218, +52,30,52,88,52,124,43,154,78,30,78,124,82,136,88,140,103,140,176,16, +150,62,121,100,236,92,200,66,171,24,142,98,213,98,124,138,233,138,148,164, +121,218,204,164,233,214,176,98,176,216,172,226,162,232,153,233,12,32,117,32, +28,238,28,76,106,76,107,236,28,212,107,212,28,174,107,174,52,32,52,100, +50,128,41,150,76,32,76,124,78,134,84,136,107,136,230,18,180,28,133,32, +128,60,147,100,170,52,185,86,234,52,203,100,122,140,243,140,206,112,206,216, +202,228,192,234,179,234,144,158,169,193,12,32,119,32,28,238,28,78,106,78, +107,232,28,172,107,172,28,208,107,208,54,32,54,92,50,120,43,146,80,32, +80,102,80,122,84,132,90,136,107,136,220,102,220,30,136,30,136,102,221,102, +136,66,221,66,136,132,136,234,173,214,174,166,137,166,192,128,192,220,200,232, +210,238,224,238,230,230,239,208,234,148,193,187,16,40,117,40,32,242,32,82, +106,82,107,240,32,220,107,220,32,180,107,180,56,40,56,108,47,154,80,40, +80,130,84,140,107,140,160,18,189,44,126,54,229,54,142,72,163,104,120,120, +239,120,212,70,189,120,144,240,144,156,218,156,219,240,144,216,219,217,14,32, +113,32,28,232,28,80,96,80,97,226,28,206,97,206,28,170,97,170,52,32, +52,94,48,120,39,144,74,32,74,124,78,134,97,134,112,76,169,76,120,212, +120,130,160,130,161,208,120,190,161,190,142,130,143,16,156,238,178,200,184,156, +184,32,224,32,224,216,220,228,212,234,201,234,184,154,225,154,184,96,225,97, +16,32,121,32,32,238,32,78,112,78,113,222,32,168,113,168,32,206,113,206, +60,32,60,100,54,126,45,142,84,32,84,122,90,134,113,134,218,100,218,26, +144,26,144,100,219,100,144,62,219,62,126,132,239,132,144,158,138,204,124,226, +109,242,140,196,154,212,174,226,239,228,180,226,181,132,224,174,181,175,16,36, +121,36,130,24,230,24,219,52,28,238,28,78,106,78,107,240,28,212,107,212, +28,174,107,174,58,36,58,92,52,122,45,144,80,36,80,120,82,130,90,136, +107,136,154,56,140,96,125,120,234,112,188,110,160,98,145,82,180,104,181,24, +226,70,181,70,142,242,142,138,220,138,220,220,214,234,193,234,142,168,221,168, +142,200,221,201,14,36,111,36,26,240,26,80,102,80,103,238,26,220,103,220, +26,182,103,182,52,36,52,110,41,156,76,36,76,132,82,140,103,140,120,48, +239,48,178,18,152,66,119,104,152,124,152,80,218,80,218,124,153,124,118,228, +243,228,138,228,138,158,222,158,223,228,166,228,167,158,194,228,195,159,18,36, +115,36,32,240,32,78,104,78,105,220,32,212,105,212,32,174,105,174,58,36, +58,108,47,150,80,36,80,120,86,134,105,134,166,14,193,36,234,46,134,46, +134,176,109,236,134,102,243,102,146,76,218,76,218,134,147,134,182,152,183,56, +152,242,152,166,220,166,221,240,152,218,221,219,10,28,105,28,24,238,24,76, +98,76,99,232,24,212,99,212,24,178,99,178,48,28,48,110,39,152,72,28, +72,128,80,140,99,140,117,26,116,26,166,26,167,92,122,46,143,62,114,94, +167,76,182,26,226,26,227,98,186,42,207,56,182,82,227,64,180,94,150,120, +117,142,174,100,200,124,237,142,182,134,154,158,127,174,202,156,168,182,131,200, +226,180,178,212,125,233,12,34,111,34,28,240,28,76,104,76,105,224,28,208, +105,208,28,168,105,168,54,34,54,90,45,144,78,34,78,120,86,132,105,132, +124,30,139,52,224,24,205,50,118,72,233,72,156,72,157,12,188,72,189,12, +144,82,165,102,122,114,229,114,204,80,185,114,128,144,225,144,120,174,237,174, +172,114,172,174,146,216,117,240,234,236,190,204,173,175,14,32,121,32,28,232, +28,74,106,74,107,224,28,208,107,208,28,170,107,170,54,32,54,112,43,146, +78,32,78,126,86,136,107,136,156,18,138,66,117,102,178,16,201,42,142,184, +143,58,236,58,149,58,228,94,149,94,228,132,149,132,240,168,149,168,188,168, +189,58,138,196,123,236,160,198,169,230,188,196,197,226,216,188,239,231,10,34, +105,34,22,242,22,80,94,80,95,242,22,222,95,222,22,182,95,182,48,34, +48,104,37,158,68,34,68,136,76,146,95,146,160,16,183,38,114,48,229,48, +194,58,225,86,164,48,128,82,215,76,142,96,136,124,117,148,174,96,175,140, +206,94,206,130,212,140,218,142,228,142,241,124,110,230,241,230,130,230,130,162, +216,162,217,230,158,230,159,162,186,230,187,163,12,32,111,32,26,240,26,78, +98,78,99,238,26,180,99,180,26,218,99,218,52,32,52,116,41,154,74,32, +74,134,80,144,99,144,222,88,228,66,130,66,130,168,113,230,144,98,203,92, +168,66,169,12,168,40,229,40,172,66,172,102,180,112,208,112,221,100,142,136, +237,136,190,136,176,150,145,164,174,150,186,170,194,192,196,214,192,228,182,238, +169,238,184,166,145,194,190,188,164,210,137,226,224,150,191,178,206,164,214,198, +237,229,14,36,109,36,28,246,28,84,100,84,101,242,28,186,101,186,28,220, +101,220,52,36,52,112,43,160,74,36,74,140,82,150,101,150,126,102,126,44, +226,44,226,102,127,102,126,74,227,74,158,102,159,12,190,102,191,12,112,128, +243,128,134,186,134,152,218,152,218,186,135,186,142,200,159,224,112,234,245,234, +208,198,187,235,12,32,109,32,26,236,26,78,96,78,97,226,26,210,97,210, +26,170,97,170,48,32,48,104,39,146,70,32,70,122,76,132,97,132,220,20, +172,28,125,32,110,56,241,56,224,134,224,82,130,82,130,134,225,134,146,96, +157,118,206,94,191,118,118,162,231,162,112,188,243,188,176,188,177,28,130,204, +115,240,152,204,163,232,182,204,197,232,212,202,239,237,24,34,231,34,34,108, +78,84,112,56,133,34,96,70,120,94,138,122,142,160,140,198,126,224,104,230, +91,232,28,160,76,134,123,98,28,208,92,176,139,134,208,70,178,94,137,118, +232,202,190,164,161,105,24,242,24,82,100,82,101,238,24,218,101,218,58,82, +59,12,114,46,59,46,38,110,89,188,78,102,45,198,124,54,239,54,142,16, +167,44,220,16,197,54,130,92,229,92,116,126,243,126,178,54,174,108,152,158, +115,204,230,168,147,168,124,226,241,226,186,226,187,169,24,26,239,26,102,26, +98,52,82,80,58,94,31,106,94,60,206,60,200,82,190,92,174,94,161,94, +196,152,196,116,62,116,62,152,197,152,72,168,52,208,27,238,60,192,94,212, +132,224,237,224,132,152,133,224,224,186,133,187,26,32,111,32,18,100,111,78, +70,32,71,88,102,118,122,98,132,74,132,24,192,24,192,102,220,102,234,92, +241,78,152,58,171,86,194,160,194,126,62,126,62,160,195,160,76,178,62,212, +48,228,23,240,70,196,94,218,120,228,164,232,241,228,128,160,129,228,212,192, +129,193,20,46,119,46,20,94,113,74,78,12,78,108,72,120,56,126,45,126, +218,18,178,26,140,32,140,64,134,96,115,126,236,72,141,72,196,126,197,72, +190,172,190,142,68,142,68,172,191,172,80,190,50,220,19,240,68,202,96,222, +136,236,239,234,128,232,129,172,206,204,131,205,190,14,207,30,230,42,44,42, +44,92,25,136,162,12,172,64,196,114,216,138,224,142,230,138,239,116,210,64, +184,106,159,132,56,90,159,90,100,90,101,54,100,68,145,68,78,106,53,128, +122,106,145,122,104,90,104,126,96,132,85,132,194,174,194,148,66,148,66,174, +195,174,72,192,56,218,33,240,64,204,90,224,126,236,182,238,237,234,126,174, +127,236,208,204,127,205,34,24,55,44,116,22,101,44,32,130,32,58,122,58, +123,128,76,124,77,14,58,76,47,106,94,78,101,108,168,14,152,52,139,74, +232,46,155,46,158,72,190,104,227,126,206,46,194,76,172,104,143,120,190,172, +190,140,60,140,60,172,191,172,78,188,58,220,25,242,68,206,96,222,144,232, +237,228,126,228,127,172,212,198,127,199,104,94,104,34,38,34,38,94,105,94, +16,228,121,200,38,222,39,126,74,212,75,94,74,148,121,148,162,14,144,66, +121,116,144,122,181,170,178,228,204,228,216,220,222,194,222,62,147,63,98,94, +98,34,38,34,38,94,99,94,14,224,105,198,34,130,35,218,70,94,71,206, +106,144,71,144,122,32,208,32,184,116,220,116,198,174,170,210,129,240,150,122, +162,158,180,190,208,220,237,238,142,32,142,88,134,156,120,200,91,239,98,92, +98,32,40,32,40,92,99,92,18,222,109,202,36,122,37,216,72,92,73,208, +108,142,73,142,120,30,237,30,108,118,245,118,104,234,134,204,146,170,152,116, +153,30,202,240,203,31,98,92,98,32,34,32,34,92,99,92,14,226,109,192, +32,132,33,218,68,92,69,204,106,142,69,142,120,70,227,70,114,130,239,130, +174,16,174,134,156,182,130,214,95,240,232,234,198,200,178,160,173,141,100,92, +100,36,40,36,40,92,101,92,20,228,117,200,38,124,39,222,72,92,73,212, +110,146,73,146,174,14,146,70,111,112,242,100,200,64,173,20,172,178,194,178, +206,166,210,148,210,112,142,112,142,216,146,228,158,234,212,234,228,218,235,205, +98,88,98,30,34,30,34,88,99,88,18,220,113,196,36,122,37,214,68,88, +69,206,110,132,69,132,118,36,243,36,102,164,130,136,154,86,169,36,144,240, +144,120,222,120,223,236,144,214,223,215,96,90,96,30,38,30,38,90,97,90, +14,228,107,202,32,126,33,222,68,90,69,212,102,146,69,146,148,12,128,70, +99,120,130,244,131,66,148,78,245,78,206,12,206,218,202,230,194,234,179,234, +160,114,177,161,82,86,82,30,34,30,34,86,83,86,14,214,91,190,30,122, +31,208,60,86,61,198,92,136,61,136,86,114,247,114,86,234,106,204,112,168, +114,140,114,30,150,30,150,212,144,224,129,224,160,232,174,202,182,164,182,30, +218,30,218,218,210,228,197,229,98,92,98,32,36,32,36,92,99,92,18,226, +105,202,36,126,37,222,70,92,71,210,108,142,71,142,226,20,178,32,136,36, +130,122,243,122,148,148,113,220,204,150,237,212,178,56,178,218,174,230,164,236, +151,237,98,96,98,34,34,34,34,96,99,96,16,228,117,194,32,130,33,222, +70,96,71,208,158,14,185,42,130,96,130,56,224,56,225,96,154,100,154,212, +158,226,170,234,210,234,228,222,239,198,222,126,155,156,112,146,71,147,90,94, +90,34,44,34,44,94,91,94,18,214,93,196,68,200,69,94,38,208,39,120, +110,66,164,66,156,216,148,230,136,238,127,238,130,14,130,92,122,162,110,200, +79,240,68,140,103,140,190,234,190,56,228,56,229,232,190,210,229,211,86,90, +86,32,30,32,30,90,87,90,16,228,89,190,28,130,29,220,62,90,63,202, +96,142,63,142,84,230,112,198,124,160,126,140,126,54,228,54,219,90,126,126, +216,126,198,176,162,212,121,236,234,236,190,210,162,174,141,126,174,126,175,11, +96,94,96,32,38,32,38,94,97,94,22,222,111,204,36,130,37,218,72,94, +73,210,200,64,239,118,174,16,116,108,225,100,134,240,134,144,216,144,217,236, +134,218,217,219,96,98,96,36,38,36,38,98,97,98,16,230,111,206,34,132, +35,224,72,98,73,214,106,150,73,150,122,60,229,60,114,112,243,112,174,112, +175,12,124,168,229,168,112,226,245,226,174,226,175,125,88,90,88,30,32,30, +32,90,89,90,12,228,103,188,30,124,31,218,64,90,65,204,100,134,65,134, +108,62,227,36,122,124,162,108,194,82,215,62,142,12,152,66,180,110,202,126, +222,126,228,116,233,106,106,152,237,152,146,152,144,182,134,208,118,222,98,232, +81,240,182,152,182,222,188,230,226,230,234,220,239,205,92,92,92,30,36,30, +36,92,93,92,16,224,105,202,34,124,35,220,68,92,69,210,100,142,69,142, +126,14,126,128,169,110,164,62,127,62,184,10,184,116,190,126,220,126,232,118, +237,102,232,42,185,68,98,168,245,168,168,242,169,137,92,94,92,34,36,34, +36,94,93,94,16,220,105,198,34,128,35,214,68,94,69,206,102,148,69,148, +138,28,124,76,111,104,230,70,127,70,100,124,243,124,172,10,173,124,150,124, +150,164,130,210,97,238,188,124,188,224,194,236,204,238,226,238,234,226,239,207, +92,92,92,30,32,30,32,92,93,92,12,220,103,202,32,128,33,214,66,92, +67,208,104,142,67,142,116,28,137,70,230,22,186,36,153,38,150,112,241,112, +192,212,193,36,98,116,132,116,133,212,108,232,126,212,136,212,156,220,176,230, +241,231,90,92,90,34,32,34,32,92,91,92,14,228,103,196,30,128,31,220, +64,92,65,208,98,138,67,138,144,12,179,42,106,54,237,54,132,72,166,108, +200,128,233,140,112,142,154,122,186,84,205,54,144,142,144,190,136,220,113,242, +198,244,199,145,98,92,98,34,38,34,38,92,99,92,14,226,113,198,72,92, +73,208,32,130,33,220,158,12,187,44,118,62,239,62,156,82,117,130,196,84, +239,126,144,126,160,168,188,204,237,238,202,130,178,180,152,210,113,237,92,96, +92,34,34,34,34,96,93,96,24,232,103,198,32,132,33,228,66,96,67,212, +102,144,67,144,152,14,181,38,172,208,126,236,126,50,214,50,214,134,127,134, +126,90,215,90,168,134,178,176,202,212,233,238,222,156,189,191,94,94,94,30, +38,30,38,94,95,94,16,224,101,198,34,124,35,216,70,94,71,206,106,148, +71,148,118,24,218,24,218,74,126,74,126,114,132,126,148,134,208,134,228,120, +233,102,124,178,107,228,166,148,189,180,216,168,241,208,148,168,148,216,152,230, +164,236,196,236,208,224,211,211,92,94,92,34,34,34,34,94,93,94,18,224, +99,196,32,128,33,218,68,94,69,206,104,140,69,140,214,140,214,72,124,72, +124,140,215,140,124,104,215,104,104,182,243,182,168,246,169,140,166,72,167,10, +230,38,167,39,86,82,86,26,32,26,32,82,85,82,14,222,103,186,30,120, +31,214,62,82,63,200,98,134,63,134,216,102,216,22,122,22,122,102,217,102, +122,62,217,62,168,244,169,22,108,144,243,144,100,220,140,184,169,144,238,212, +198,178,175,145,86,88,86,34,38,34,38,88,87,88,18,218,97,196,64,88, +65,202,34,128,35,212,64,144,93,144,126,10,116,70,101,108,100,132,173,132, +166,62,119,62,94,240,124,196,136,146,141,62,168,216,135,156,186,234,186,54, +228,54,229,234,186,210,229,211,94,90,94,30,38,30,38,90,95,90,14,216, +97,192,68,90,69,200,34,122,35,208,104,142,69,142,228,20,176,30,122,36, +122,150,110,200,95,236,242,78,123,78,146,194,146,114,224,114,225,194,186,44, +181,114,184,138,184,176,164,216,135,240,194,198,235,237,92,92,92,34,38,34, +38,92,93,92,16,220,97,194,34,122,35,212,68,92,69,202,102,144,69,144, +158,14,187,40,244,54,122,54,122,140,108,198,87,234,144,244,144,152,220,152, +221,242,144,220,221,220,180,152,181,68,242,108,181,109,98,96,98,34,36,34, +36,96,99,96,16,226,107,200,32,134,33,220,68,96,69,210,106,148,69,148, +154,14,183,44,118,54,235,54,108,118,245,118,138,72,157,102,210,68,189,118, +132,242,132,154,216,154,217,240,132,218,217,219,88,90,88,24,38,24,38,90, +89,90,18,214,101,192,34,124,35,208,66,90,67,200,98,136,67,136,96,126, +175,126,108,14,127,58,102,76,171,76,164,16,139,76,136,76,136,138,118,196, +85,232,172,202,133,150,190,244,190,28,234,28,210,112,224,132,238,160,238,188, +222,198,207,199,82,94,82,34,34,34,34,94,83,94,16,228,91,210,60,94, +61,216,34,126,35,222,60,148,89,148,136,80,243,80,150,48,222,48,222,114, +149,114,148,146,231,146,142,178,237,178,186,214,187,12,96,44,126,44,102,120, +134,120,124,186,108,218,89,236,100,144,104,178,120,206,148,228,239,233,88,94, +88,36,40,36,40,94,89,94,16,220,103,198,34,126,35,214,66,94,67,206, +98,148,67,148,104,52,241,52,166,14,166,88,204,88,205,12,130,18,130,120, +235,120,108,158,243,158,174,132,175,242,102,226,144,192,167,158,236,222,202,190, +181,159,96,90,96,30,38,30,38,90,97,90,18,226,103,194,38,124,39,218, +68,90,69,206,100,136,69,136,128,26,128,74,226,74,227,22,176,8,177,74, +110,106,243,106,124,244,124,144,232,144,232,220,226,232,216,238,201,238,158,224, +159,144,192,222,193,144,176,106,165,145,84,88,84,30,30,30,30,88,85,88, +16,230,99,198,32,126,33,222,62,88,63,210,100,140,63,140,218,16,166,26, +117,28,98,60,241,60,222,160,222,90,122,90,122,160,223,160,122,126,223,126, +116,194,231,194,98,226,245,226,172,226,173,27,92,88,92,26,36,26,36,88, +93,88,16,220,103,198,32,122,33,214,68,88,69,206,100,140,69,140,226,18, +174,28,119,30,218,110,218,68,128,68,128,110,219,110,118,242,118,144,230,144, +230,220,224,232,210,238,199,238,198,170,213,206,142,198,205,188,174,28,175,193, +82,92,82,32,30,32,30,92,83,92,14,222,89,194,30,124,31,216,58,92, +59,204,96,138,59,138,150,8,177,30,236,44,112,44,112,160,100,204,81,240, +126,86,233,86,154,56,154,118,200,118,201,56,124,146,208,146,186,190,160,216, +119,242,238,232,210,224,184,206,158,178,141,147,90,102,90,42,36,42,36,102, +91,102,14,220,99,198,34,130,35,212,68,102,69,204,96,148,69,148,134,18, +161,48,112,58,235,58,208,18,183,58,116,94,223,94,106,132,245,132,168,58, +164,102,138,174,83,232,140,172,227,172,114,232,243,232,178,232,179,173,94,92, +94,32,36,32,36,92,95,92,18,216,101,192,36,124,37,210,68,92,69,200, +106,138,69,138,150,14,183,40,82,222,104,196,116,168,122,146,122,48,222,48, +222,96,123,96,124,240,124,132,232,132,232,222,224,234,212,238,201,238,160,216, +161,132,194,216,195,132,124,176,233,177,90,92,90,32,34,32,34,92,91,92, +12,222,101,192,32,122,33,214,66,92,67,202,100,142,67,142,148,46,191,70, +118,26,208,26,175,60,108,74,228,74,213,104,102,120,140,100,167,74,178,74, +178,112,174,122,162,128,147,128,104,160,241,160,164,244,165,140,92,226,130,198, +165,160,238,224,202,198,165,161,88,84,88,26,28,26,28,84,89,84,16,220, +95,190,28,124,29,214,60,84,61,202,60,132,95,132,108,20,233,20,106,116, +239,116,202,134,203,20,136,116,137,20,136,54,203,54,136,84,203,84,104,146, +152,146,142,180,130,202,95,232,114,174,161,210,174,146,222,146,214,178,194,212, +153,238,176,146,184,178,202,210,237,237,84,92,84,32,36,32,36,92,85,92, +18,224,95,202,36,124,37,218,66,92,67,210,66,142,85,142,102,46,237,46, +146,14,147,66,188,12,189,68,100,82,245,82,110,242,110,118,224,118,224,220, +222,230,214,236,197,236,150,82,150,122,142,156,125,192,162,174,145,146,190,82, +190,122,182,164,161,206,210,194,185,153,86,96,86,36,32,36,32,96,85,96, +16,222,91,198,32,126,33,216,64,96,65,206,218,16,162,30,109,34,112,52, +131,78,160,44,173,68,224,40,199,72,200,120,227,152,206,90,166,122,118,148, +219,142,164,76,118,110,181,110,100,178,235,178,160,154,160,178,142,210,116,228, +89,240,234,238,196,218,165,178,64,138,99,139,84,92,84,32,36,32,36,92, +85,92,18,222,93,200,32,124,33,218,62,92,63,208,96,144,63,144,244,30, +114,30,114,128,106,196,89,238,126,66,189,66,176,148,176,102,138,102,138,148, +177,148,134,166,145,196,120,222,189,208,172,166,155,214,192,134,205,168,188,94, +247,94,220,46,220,224,214,234,204,238,191,239,78,92,78,32,34,32,34,92, +79,92,16,216,83,192,30,118,31,210,58,92,59,200,86,138,59,138,238,30, +102,30,102,168,92,208,75,238,122,50,139,76,116,92,169,92,166,48,149,92, +168,118,169,182,124,118,124,170,169,166,146,92,146,176,132,210,113,232,202,46, +192,76,175,112,218,126,228,92,185,92,196,120,196,156,182,196,164,220,145,236, +236,238,212,206,197,157,88,90,88,32,32,32,32,90,89,90,20,222,99,192, +32,126,33,216,62,90,63,204,100,138,63,138,102,74,239,74,110,32,133,60, +222,26,205,56,152,14,153,74,184,10,185,74,112,116,229,116,122,146,221,146, +108,178,235,178,132,88,153,116,206,84,185,116,168,116,168,178,152,204,126,224, +103,236,230,236,190,210,169,179,92,92,92,32,36,32,36,92,93,92,16,224, +103,200,34,128,35,218,66,92,67,210,98,148,67,148,218,14,166,26,115,28, +128,44,145,66,108,76,239,76,214,38,191,76,168,130,169,26,106,132,140,106, +161,76,234,134,202,110,179,76,124,242,124,146,216,146,217,242,124,186,217,186, +124,222,217,222,168,222,169,147,76,96,76,34,28,34,28,96,77,96,14,212, +77,196,28,124,29,208,54,96,55,200,84,140,55,140,112,18,131,46,90,60, +159,60,146,142,146,96,102,96,102,142,147,142,100,172,79,212,142,166,151,188, +124,142,124,214,116,228,97,228,158,84,235,84,212,28,225,56,184,12,184,122, +174,184,141,240,202,104,202,212,204,224,214,230,226,230,236,214,241,199,92,86, +92,26,36,26,36,86,93,86,14,218,97,192,32,114,33,210,64,86,65,202, +100,138,65,138,226,70,226,24,124,24,124,70,227,70,158,70,159,24,192,70, +193,24,142,80,122,108,105,124,198,232,216,232,224,226,232,208,232,106,125,106, +198,168,198,136,122,136,122,168,199,168,188,182,207,212,108,208,199,200,158,114, +159,203,88,96,88,36,42,36,42,96,89,96,24,222,99,194,40,124,41,214, +68,96,69,204,94,144,69,144,102,36,239,36,146,60,147,12,190,60,191,10, +112,66,135,90,112,244,113,100,156,76,226,76,226,214,222,228,210,236,199,236, +170,94,185,112,154,92,136,120,123,140,144,222,145,108,206,122,151,122,200,148, +153,148,200,172,145,172,208,198,145,198,176,198,177,123,88,92,88,34,36,34, +36,92,89,92,18,228,93,208,36,128,37,222,66,92,67,214,94,148,67,148, +158,10,187,32,238,42,116,42,116,168,95,232,222,120,222,68,146,68,146,120, +223,120,134,144,233,144,126,170,241,170,184,170,185,68,164,180,129,202,208,178, +239,204,144,206,225,206,122,232,241,232,146,94,223,94,184,182,185,233,86,94, +86,36,34,36,34,94,85,94,14,230,97,206,30,130,31,224,62,94,63,214, +94,152,63,152,136,16,112,46,137,72,182,16,158,46,181,70,224,16,202,44, +227,70,218,132,218,82,114,82,114,132,219,132,138,96,199,120,194,92,139,122, +132,154,149,172,130,184,149,200,180,160,199,176,178,190,195,204,116,148,116,234, +147,220,164,146,164,236,201,220,212,148,212,194,220,228,228,240,234,238,243,217, +82,94,82,34,32,34,32,94,83,94,16,224,97,202,32,124,33,218,60,94, +61,210,96,148,61,148,114,24,101,60,152,46,107,46,184,22,173,62,232,48, +179,48,98,76,159,76,180,76,239,76,134,76,135,12,202,76,203,10,96,120, +112,104,120,88,121,76,142,76,142,114,169,98,174,120,190,94,191,76,212,76, +212,102,216,114,230,114,238,108,241,98,122,202,122,134,210,134,211,202,166,156, +166,198,150,218,128,226,99,236,176,206,231,237,74,96,74,36,32,36,32,96, +75,96,16,224,91,204,30,128,31,218,58,96,59,212,88,154,59,154,98,50, +91,88,114,16,114,74,108,106,91,140,132,56,115,74,130,126,111,96,144,14, +165,32,132,44,187,44,140,64,181,64,140,84,181,84,176,138,176,104,144,104, +144,138,177,138,198,48,193,86,240,50,229,82,216,16,216,66,210,96,191,136, +238,136,213,92,102,160,206,160,182,190,142,218,93,240,236,236,196,224,158,202, +136,176,125,161,166,18,122,38,78,50,53,56,198,52,148,82,106,102,47,122, +86,70,107,100,140,50,159,74,128,92,152,116,166,138,176,172,174,202,164,222, +144,234,126,236,117,234,54,170,110,146,149,114,54,220,112,190,167,143,92,16, +60,36,23,50,112,56,76,88,25,122,42,68,61,96,74,52,89,74,68,94, +90,116,104,146,108,182,102,212,90,228,72,232,59,232,26,166,62,142,85,112, +30,208,70,176,101,140,122,28,222,28,220,92,212,110,202,116,185,116,162,28, +162,66,146,102,123,124,142,244,142,144,226,144,227,242,142,218,227,219,78,18, +50,40,21,60,104,46,64,84,23,114,38,70,57,88,68,48,85,64,64,84, +80,108,92,140,94,176,90,210,80,228,68,234,53,232,24,162,58,138,81,114, +26,208,60,182,93,148,112,32,243,32,130,240,130,86,216,86,217,240,130,212, +217,212,130,148,217,148,176,32,161,85,78,18,50,44,21,62,102,46,68,80, +23,110,36,72,55,88,66,48,83,62,60,86,74,102,86,130,90,160,88,202, +78,222,62,232,49,232,22,162,54,136,79,112,24,206,60,174,87,144,142,20, +120,70,95,112,122,244,123,66,140,82,241,82,188,244,189,12,142,194,170,136, +187,82,232,190,208,138,191,83,76,20,44,46,17,62,100,56,62,90,23,114, +34,74,55,94,64,48,85,68,62,92,78,118,88,144,90,172,88,200,80,222, +66,234,47,236,74,114,50,142,21,164,88,152,58,184,25,210,104,42,239,42, +144,68,145,12,194,68,195,12,218,144,218,84,122,84,122,144,219,144,122,114, +219,114,106,178,241,178,168,158,168,180,152,206,130,226,103,238,234,238,200,218, +180,196,169,179,86,22,52,42,21,56,100,62,66,94,21,124,64,58,81,78, +36,76,55,100,62,96,82,124,94,152,96,192,88,222,70,232,47,236,76,118, +50,148,25,168,92,150,60,182,25,208,220,126,220,46,126,46,126,126,221,126, +150,64,199,104,194,62,149,110,168,12,153,46,126,140,126,230,161,212,164,172, +127,172,182,140,182,230,212,232,230,224,239,202,228,156,183,189,74,12,46,54, +17,84,22,240,38,208,42,188,42,82,126,82,126,216,122,228,114,236,101,236, +42,124,127,124,42,166,127,166,84,216,85,82,82,82,114,40,57,40,152,38, +187,76,148,96,185,138,140,174,243,160,212,12,213,247,64,14,38,56,19,78, +20,236,34,198,38,164,38,88,104,88,104,220,100,232,92,236,81,236,38,134, +105,134,36,174,105,174,70,220,70,88,92,48,45,48,118,134,241,134,172,16, +172,140,158,188,123,234,232,234,200,194,173,134,128,68,212,68,209,135,68,14, +46,52,23,78,24,234,40,186,44,164,44,86,106,86,106,220,102,228,94,232, +83,232,44,130,107,130,44,168,107,168,72,212,72,84,90,48,49,48,160,14, +142,52,121,78,238,46,147,46,140,82,210,82,140,136,230,136,228,212,222,224, +208,232,191,232,126,190,152,168,175,136,132,230,172,200,192,170,203,137,62,16, +38,58,17,82,16,240,32,204,38,156,38,84,100,84,100,218,96,228,88,232, +79,232,68,208,68,84,90,46,47,46,38,126,101,126,38,166,101,166,112,240, +130,200,134,156,134,46,182,40,223,32,188,192,203,234,170,42,162,228,195,214, +202,36,202,80,204,130,210,176,237,235,20,96,131,78,44,26,45,90,86,14, +87,84,127,44,126,44,87,44,154,14,154,78,160,90,174,96,210,96,228,84, +237,64,220,30,155,54,108,94,68,122,25,140,28,240,52,210,58,192,58,144, +206,144,206,214,202,228,190,234,171,234,128,234,128,144,158,118,77,118,58,172, +207,172,206,198,59,199,60,14,40,50,19,76,18,238,32,206,42,164,42,82, +108,82,108,210,104,220,96,224,89,224,74,210,74,82,96,40,47,40,42,120, +109,120,108,164,43,164,128,40,155,88,230,40,207,88,124,112,241,112,178,112, +179,12,160,112,160,154,152,188,136,218,119,238,192,112,192,216,194,226,202,230, +226,230,238,220,243,197,66,12,42,50,19,78,20,234,32,198,38,178,38,86, +104,86,104,216,100,228,92,234,81,234,38,170,105,170,38,130,105,130,70,216, +70,86,90,46,45,46,116,52,239,52,222,134,222,88,138,88,138,134,223,134, +178,10,179,242,122,216,156,178,179,134,236,212,212,188,188,156,179,135,62,18, +38,56,17,78,18,236,34,198,38,184,38,88,98,88,98,226,90,236,82,240, +77,240,70,220,71,88,38,134,99,134,38,176,99,176,66,88,86,48,45,48, +124,24,155,58,218,156,218,76,130,76,130,156,219,156,130,116,219,116,114,188, +241,188,174,244,175,76,212,16,185,77,10,98,135,78,40,28,41,92,86,18, +87,84,132,48,87,48,156,14,156,80,162,90,178,96,222,96,234,84,241,68, +228,26,157,54,112,94,147,114,14,124,251,124,52,148,209,148,54,172,209,172, +60,242,60,198,204,198,205,238,60,226,205,227,26,36,127,36,32,58,121,58, +78,58,79,14,18,124,36,108,36,78,116,78,116,102,37,102,78,102,79,78, +140,56,150,54,162,44,162,28,206,28,206,42,208,50,220,54,239,54,142,70, +216,70,190,98,147,120,154,70,172,90,202,108,239,118,110,116,139,132,20,142, +239,142,54,160,205,160,52,182,207,182,60,240,60,204,198,204,199,242,60,228, +199,229,18,44,121,44,30,72,115,72,14,100,125,100,68,100,69,12,38,238, +38,128,102,128,102,218,98,228,90,234,75,234,38,158,103,158,38,188,103,188, +142,158,142,34,220,34,221,158,180,68,180,126,170,174,148,212,123,236,190,148, +190,220,194,230,204,236,220,236,234,224,239,207,38,28,219,28,34,102,34,56, +222,56,223,98,126,116,127,28,54,82,103,82,54,108,105,108,146,82,199,82, +146,108,199,108,42,134,209,134,16,162,237,162,92,162,82,192,194,192,190,212, +182,228,168,236,123,237,44,30,219,30,36,94,36,58,224,58,225,94,58,82, +107,82,58,108,109,108,152,82,201,82,150,108,203,108,130,114,131,30,228,136, +54,136,54,176,46,210,25,236,74,180,206,178,200,220,196,228,182,234,167,234, +136,148,130,188,108,216,67,239,40,28,219,28,34,104,34,58,224,58,225,104, +112,130,145,148,54,90,107,90,54,114,107,114,152,88,205,88,152,114,203,114, +130,116,131,28,20,154,241,154,86,168,116,198,160,220,235,232,178,154,158,184, +120,216,74,232,23,239,38,26,217,26,32,94,32,54,222,54,223,90,56,78, +105,78,56,100,105,100,148,78,199,78,148,100,199,100,204,122,156,130,105,132, +124,108,125,26,102,164,219,164,98,200,223,200,158,200,159,130,24,132,76,132, +40,170,82,170,72,200,50,224,21,240,38,188,66,212,98,226,140,232,233,231, +34,26,225,26,30,88,30,54,228,54,229,88,54,76,109,76,54,98,109,98, +152,76,205,76,152,100,203,100,116,104,149,122,130,88,131,26,20,130,235,130, +76,138,126,160,182,172,239,176,188,130,148,156,94,172,17,180,90,182,86,212, +76,228,62,236,43,244,176,184,177,245,36,24,223,24,32,84,32,52,226,52, +227,82,52,74,111,74,52,98,109,98,146,74,207,74,146,100,207,100,126,108, +127,24,38,116,71,138,30,152,61,172,32,236,85,176,90,136,235,136,112,232, +112,168,216,168,216,214,208,224,187,224,162,244,163,125,36,24,223,24,30,88, +30,50,228,50,229,88,50,80,105,80,50,104,105,104,154,78,209,78,152,102, +209,102,128,112,129,24,102,238,103,122,154,240,155,120,24,144,103,144,38,176, +103,176,20,204,103,204,232,144,155,144,220,174,155,174,238,206,155,207,40,32, +217,32,34,92,34,56,224,56,225,92,58,76,107,76,56,100,105,100,154,76, +201,76,152,98,201,98,112,104,137,116,126,88,127,32,36,124,217,124,18,154, +239,154,80,132,113,148,172,132,145,148,26,182,233,182,114,164,76,204,219,236, +176,182,154,208,122,226,84,236,39,241,36,30,219,30,32,84,32,54,222,54, +223,84,129,106,128,102,129,30,50,76,109,76,50,98,109,98,148,76,205,76, +150,96,205,96,40,114,71,136,24,148,57,168,34,236,81,170,216,114,156,122, +99,124,110,136,129,156,148,132,163,154,208,128,187,152,214,160,154,168,107,168, +84,200,233,200,100,230,221,230,160,230,161,169,38,28,223,28,34,86,34,52, +224,52,225,86,130,100,131,28,54,72,107,72,56,94,109,94,152,74,203,74, +154,94,203,94,50,112,81,132,18,148,60,148,56,228,87,206,208,156,208,114, +118,114,118,156,209,156,118,136,209,136,92,192,116,176,135,156,192,240,206,240, +218,230,222,216,222,176,117,176,114,190,114,224,181,224,164,180,150,200,135,212, +192,210,161,189,38,26,219,26,30,88,30,50,222,50,223,88,52,72,103,72, +52,92,103,92,150,72,201,72,148,92,201,92,128,98,129,26,24,122,131,122, +12,146,137,146,54,146,55,106,98,146,99,108,40,242,40,166,114,166,114,230, +108,238,91,238,40,186,115,186,40,208,115,208,164,106,152,142,137,168,232,134, +157,134,158,160,174,186,198,210,237,232,130,232,164,210,190,178,205,135,40,30, +217,30,36,92,36,56,224,56,225,92,128,98,129,30,56,76,109,76,56,98, +109,98,150,76,203,76,150,98,203,98,70,104,50,116,25,126,100,120,66,142, +27,162,66,120,77,136,40,134,51,148,66,142,80,164,88,184,90,204,84,222, +72,232,60,234,49,236,28,190,54,176,77,158,28,216,60,200,87,180,212,176, +212,120,118,120,118,176,213,176,118,148,213,148,108,204,221,204,96,232,239,232, +164,232,165,121,10,92,133,92,44,32,45,92,80,12,81,92,122,54,81,54, +116,120,117,238,34,118,34,222,117,218,76,108,68,150,51,190,98,186,71,148, +166,12,166,202,170,220,180,226,216,226,228,218,239,196,224,56,184,112,137,155, +12,100,123,100,70,100,71,14,34,100,35,34,110,54,71,54,106,126,107,246, +28,130,28,228,107,220,70,116,62,156,47,194,92,188,67,146,120,224,243,224, +144,224,144,28,218,28,219,224,144,94,219,94,144,158,219,159,8,90,125,90, +40,90,41,36,72,90,73,12,72,48,119,48,112,120,113,238,32,118,32,226, +113,220,74,108,64,154,49,190,90,184,69,136,162,14,146,66,123,108,182,188, +206,188,222,168,222,56,149,56,238,202,230,228,220,232,174,232,158,226,152,212, +152,98,190,98,190,152,153,153,14,94,133,94,44,94,45,32,80,94,81,14, +80,54,121,54,112,120,113,244,36,118,36,224,113,220,74,110,66,156,53,188, +92,186,69,148,132,30,230,30,228,92,224,108,214,114,195,114,140,120,160,96, +170,68,175,30,154,242,154,150,228,150,229,240,154,218,229,219,12,98,115,98, +70,98,71,14,34,98,35,34,108,58,71,58,102,124,103,242,30,126,30,224, +103,220,68,114,58,156,47,192,86,188,61,150,124,232,185,208,136,60,137,226, +162,12,163,216,186,106,163,106,200,12,200,228,218,228,232,222,237,206,234,76, +201,123,12,96,125,96,40,96,41,34,78,96,79,16,116,52,79,52,112,124, +113,234,32,122,32,220,113,214,72,114,60,156,47,192,94,186,65,142,184,210, +144,236,144,32,214,32,214,124,145,124,144,80,213,80,174,124,184,168,206,204, +235,232,232,142,191,179,12,100,119,100,72,100,73,12,112,52,73,52,36,100, +37,34,106,138,107,240,32,136,32,224,107,218,74,116,64,166,49,202,92,188, +69,150,126,28,237,28,122,124,247,124,132,74,218,74,215,124,178,28,165,124, +146,242,146,156,222,156,223,240,146,218,223,219,10,94,125,94,74,94,75,10, +36,94,37,30,108,122,109,226,32,126,32,214,109,206,74,110,62,158,47,192, +94,180,69,138,220,96,220,26,146,26,146,96,221,96,150,138,144,186,119,238, +142,190,164,212,192,224,241,226,184,96,185,220,234,148,185,149,12,98,117,98, +74,98,75,16,110,58,75,58,44,98,45,36,102,118,103,230,36,118,36,220, +103,216,68,112,62,156,49,194,88,188,65,140,112,240,128,194,134,138,134,32, +222,32,222,72,135,72,134,104,239,104,208,120,237,158,182,112,150,152,225,142, +152,186,229,186,140,230,243,230,190,230,191,161,178,66,178,28,54,28,54,66, +179,66,196,178,196,98,36,98,36,178,197,178,36,138,197,138,116,66,116,206, +122,222,142,228,204,228,220,216,231,195,40,30,207,30,28,58,219,58,18,96, +56,94,92,76,109,58,150,58,150,80,162,88,218,88,235,68,184,130,184,106, +72,106,72,130,185,130,200,200,200,154,52,154,52,200,201,200,52,178,201,178, +124,130,124,216,128,226,144,232,214,232,230,224,239,203,112,48,112,28,36,28, +36,48,113,48,214,48,214,26,142,26,142,48,215,48,204,98,204,64,52,64, +52,98,205,98,52,82,205,82,126,98,127,64,12,118,241,118,186,156,186,136, +62,136,62,156,187,156,202,214,202,176,44,176,44,214,203,214,44,194,203,194, +124,156,124,226,130,236,152,240,216,240,228,232,237,217,88,20,58,70,19,114, +66,244,67,56,120,26,153,56,74,72,229,72,76,120,217,120,76,168,221,168, +74,216,239,216,146,216,147,73,90,16,56,62,25,92,128,18,161,40,66,162, +67,50,74,52,231,52,74,84,217,84,74,114,217,114,74,144,235,144,142,144, +143,52,16,186,241,186,132,244,133,159,84,14,56,56,25,88,62,152,63,48, +128,12,161,36,70,50,233,50,70,80,221,80,72,110,219,110,72,140,235,140, +146,140,147,50,38,166,178,166,170,192,218,192,210,216,198,228,186,232,159,232, +100,166,94,194,82,214,60,226,31,239,14,220,109,194,36,212,36,40,80,40, +81,200,36,92,81,92,36,144,81,144,142,14,122,72,99,112,128,242,129,58, +166,22,197,52,134,68,239,68,136,116,229,116,134,168,231,168,134,216,243,216, +182,216,183,69,64,12,46,60,25,92,18,152,64,118,90,84,102,54,51,54, +50,86,86,108,117,130,50,228,50,142,98,142,99,224,50,202,99,202,158,12, +138,60,111,100,182,18,207,54,136,244,137,62,144,70,241,70,144,116,231,116, +144,164,231,164,144,214,245,214,190,214,191,71,110,106,110,26,46,26,46,106, +111,106,46,52,111,52,46,78,111,78,218,106,218,26,150,26,150,106,219,106, +150,52,219,52,150,78,219,78,124,114,149,132,76,116,50,146,25,168,58,244, +59,138,230,140,67,140,66,168,217,168,66,198,219,198,66,224,239,224,138,224, +139,141,50,14,36,68,19,114,42,242,43,50,106,66,49,66,68,28,91,54, +50,118,105,118,50,166,103,166,50,218,107,218,78,218,79,66,112,26,137,58, +100,92,128,92,128,214,155,192,182,18,162,68,143,110,168,242,169,52,202,26, +223,52,176,68,243,68,178,118,237,118,178,166,237,166,178,218,245,218,208,218, +209,69,22,38,103,38,18,104,101,90,62,38,63,96,84,116,112,98,126,74, +130,28,192,28,192,96,198,110,208,114,226,114,234,104,239,86,148,52,171,102, +134,110,96,142,60,158,21,170,240,166,182,148,150,132,127,116,74,160,187,160, +48,186,213,186,32,228,229,228,76,198,95,228,184,196,167,228,130,160,131,229, +114,16,143,36,26,48,233,48,98,104,99,48,156,104,157,48,72,74,31,112, +178,72,227,104,128,96,80,136,44,154,19,164,238,156,180,140,148,124,121,102, +72,154,187,154,50,184,207,184,28,230,229,230,70,196,93,218,186,196,157,230, +128,230,129,155,44,20,87,40,28,52,67,68,30,114,91,82,212,24,166,32, +115,36,100,66,233,66,168,32,168,66,154,84,128,100,97,110,172,90,225,122, +134,116,78,150,29,168,232,166,162,150,123,124,70,164,179,164,48,190,207,190, +30,230,227,230,70,202,95,224,180,200,157,230,126,164,127,231,28,40,129,40, +76,14,38,74,125,74,30,110,123,96,84,128,85,52,216,20,180,28,150,30, +150,76,143,106,236,64,151,64,196,126,197,64,130,112,74,152,23,172,124,116, +166,146,233,166,80,162,181,162,58,190,207,190,32,228,227,228,134,228,135,162, +84,202,105,220,176,202,157,221,56,48,87,64,20,68,122,68,115,94,30,32, +108,32,79,60,26,112,54,94,83,68,84,68,84,114,78,122,68,126,61,126, +168,22,154,56,141,74,234,54,157,54,156,78,192,100,225,124,208,54,198,84, +180,104,155,118,128,110,78,148,27,170,122,114,162,140,231,164,72,160,183,160, +50,188,205,188,32,228,227,228,74,198,99,220,182,196,155,228,126,160,127,229, +34,34,129,34,36,54,121,54,18,74,129,74,82,74,83,12,28,130,58,110, +73,74,78,122,96,120,114,92,67,92,166,16,152,50,139,70,234,46,155,46, +158,76,192,94,223,122,146,118,178,102,198,78,211,46,130,120,78,152,29,172, +230,168,162,150,121,126,70,168,183,168,50,190,207,190,32,228,227,228,72,204, +93,224,180,200,161,228,126,168,127,229,44,24,75,42,28,60,59,74,40,132, +77,92,140,12,165,32,88,38,225,38,144,38,104,74,199,64,178,48,211,72, +118,86,110,114,87,128,154,122,155,84,190,84,190,118,196,124,212,124,231,104, +132,122,80,156,21,176,240,166,166,152,123,130,74,168,183,168,50,196,211,196, +32,232,231,232,80,206,101,224,182,204,169,222,130,168,131,233,20,114,38,86, +44,68,44,26,114,26,114,60,45,60,112,118,112,84,50,84,50,118,113,118, +164,16,189,30,132,38,231,38,151,50,128,76,241,76,150,50,167,76,210,50, +197,76,138,104,229,104,182,76,183,130,136,118,70,156,19,174,238,168,174,152, +127,124,72,164,181,164,50,190,209,190,34,228,225,228,130,228,131,164,80,204, +97,228,180,202,163,229,132,14,74,56,23,78,126,20,176,50,233,70,84,60, +177,60,50,84,203,84,36,118,221,118,78,94,95,110,174,94,157,118,128,118, +129,60,80,124,48,156,17,176,74,130,117,156,46,164,105,164,32,190,117,190, +44,202,59,220,104,202,91,216,24,236,113,224,74,164,75,228,174,124,146,152, +117,176,170,128,196,148,239,166,144,164,207,164,128,190,225,190,138,200,155,218, +120,230,235,230,208,204,191,230,172,230,173,165,56,10,38,44,19,68,102,168, +102,82,30,82,30,168,103,168,72,82,92,40,41,40,30,126,103,126,66,168, +67,82,14,220,111,200,190,28,221,64,118,86,237,86,162,10,162,94,154,156, +132,200,101,234,180,116,180,214,188,226,198,230,220,230,230,218,237,199,66,10, +42,50,21,74,102,170,102,86,34,86,34,170,103,170,34,128,103,128,68,170, +68,86,90,42,49,42,18,220,115,198,152,16,189,56,114,68,245,68,160,68, +160,114,152,168,128,212,97,238,178,230,198,230,210,224,218,204,218,122,161,123, +68,14,42,56,23,78,104,172,104,92,34,92,34,172,105,172,34,134,105,134, +68,172,68,92,96,48,49,48,16,220,113,208,196,30,223,54,122,74,241,74, +172,12,164,98,152,144,123,196,238,230,204,204,176,162,164,118,226,118,202,174, +172,208,125,233,58,12,40,50,23,74,102,172,102,86,34,86,34,172,103,172, +34,128,103,128,68,172,69,86,16,218,113,206,70,86,90,44,45,44,120,32, +237,32,128,68,153,110,228,66,207,110,118,140,245,140,178,238,179,33,60,8, +40,48,21,72,76,76,94,40,45,40,108,166,108,82,36,82,36,166,109,166, +36,122,109,122,70,166,71,82,18,216,119,196,140,238,140,128,224,128,225,236, +140,216,225,216,174,128,175,8,174,64,245,65,62,14,40,50,21,74,74,78, +94,44,45,44,102,168,102,84,36,84,36,168,103,168,36,124,103,124,70,168, +71,84,18,218,115,200,243,42,102,240,126,210,136,170,136,86,226,86,227,166, +136,146,227,146,174,86,175,10,244,44,175,45,60,12,38,52,17,78,82,78, +100,44,43,44,112,176,112,84,36,84,36,176,113,176,36,126,113,126,72,176, +73,84,16,226,121,210,218,18,178,30,133,34,130,96,233,96,178,242,179,30, +126,192,156,148,179,98,234,188,206,154,179,101,64,14,44,52,21,80,72,88, +94,52,45,52,98,180,98,94,36,94,36,180,99,180,36,134,99,134,68,180, +69,94,22,224,111,212,160,16,138,72,113,118,140,240,141,70,158,86,245,86, +170,124,187,160,216,14,216,222,210,230,187,231,50,24,77,56,108,16,135,50, +34,104,34,72,218,72,219,102,196,16,165,72,108,84,72,114,37,132,140,132, +162,110,79,110,202,198,202,140,56,140,56,198,203,198,56,170,203,170,130,198, +131,140,16,228,241,229,66,14,44,56,19,84,76,88,98,52,47,52,104,178, +104,94,38,94,38,178,105,178,38,136,105,136,72,178,73,94,24,222,115,210, +198,64,241,122,180,18,128,110,223,98,140,242,140,146,222,146,223,242,140,216, +223,217,62,16,40,56,21,78,74,82,92,50,45,50,104,176,104,90,36,90, +36,176,105,176,36,132,105,132,70,176,71,90,20,222,115,204,122,66,229,66, +120,118,241,118,174,118,175,16,122,172,229,172,100,228,245,228,174,228,175,133, +64,14,40,58,21,82,76,88,98,50,47,50,108,184,108,94,40,94,40,184, +109,184,40,138,109,138,74,184,75,94,22,230,125,210,120,58,245,58,130,112, +237,112,182,112,183,12,144,244,144,154,224,154,225,242,144,220,225,221,62,16, +38,60,21,82,72,84,92,52,45,52,98,180,98,92,36,92,36,180,99,180, +36,136,99,136,68,180,69,92,20,224,109,212,112,60,243,60,174,14,152,88, +115,142,146,242,146,100,220,100,220,218,216,232,208,236,197,236,146,142,221,142, +146,182,221,183,68,18,44,60,25,84,76,88,96,54,49,54,108,176,108,96, +40,96,40,176,109,176,40,136,109,136,74,176,75,96,26,222,117,210,120,34, +247,34,134,238,134,88,228,88,228,216,222,232,203,232,172,88,181,34,166,208, +167,88,198,208,199,89,64,10,42,54,19,82,72,80,92,44,49,44,106,168, +106,88,38,88,38,168,107,168,38,128,107,128,72,168,73,88,18,216,121,200, +156,8,185,36,112,46,245,46,238,130,194,112,162,86,137,46,122,132,164,108, +196,72,207,46,116,238,140,212,152,178,153,136,202,242,203,137,62,18,40,58, +19,84,106,176,106,92,38,92,38,176,107,176,38,134,107,134,72,176,73,92, +76,84,92,50,47,50,20,222,119,202,146,16,179,44,106,60,239,60,152,78, +123,120,190,78,227,116,140,130,156,166,186,200,239,232,200,124,176,180,146,214, +97,239,60,22,97,46,190,18,155,44,36,58,225,58,20,88,243,88,18,148, +58,128,86,102,110,68,133,12,240,140,202,124,178,106,159,88,122,98,100,122, +81,138,144,140,158,120,103,120,192,202,192,146,74,146,74,202,193,202,134,202, +135,146,74,174,193,174,28,230,233,231,58,14,38,50,21,72,66,80,84,46, +41,46,100,174,100,86,34,86,34,174,101,174,34,128,101,128,66,174,67,86, +18,220,109,206,118,32,212,32,212,108,117,108,124,70,213,70,114,152,243,152, +130,172,159,198,198,126,198,220,194,232,178,238,163,239,52,14,34,48,19,70, +70,76,84,44,39,44,102,172,102,82,28,82,28,172,103,172,29,130,28,130, +103,130,66,172,67,82,18,222,113,200,112,30,237,30,222,146,222,72,136,72, +136,146,223,146,136,110,223,110,178,30,178,152,164,194,136,220,103,238,128,164, +158,192,196,212,241,225,58,14,36,56,19,78,92,174,92,90,36,90,36,174, +93,174,36,132,93,132,64,174,65,90,66,82,84,46,43,46,22,224,103,206, +104,34,245,34,122,240,122,78,160,78,160,222,154,234,141,234,134,124,147,168, +188,240,188,78,232,78,232,218,228,228,222,234,211,234,198,120,219,165,56,18, +38,52,21,72,64,84,76,48,41,48,90,178,90,90,30,90,30,178,91,178, +60,178,61,90,30,130,91,130,14,222,99,206,104,34,131,76,140,56,239,56, +174,16,152,122,231,122,142,168,237,168,188,212,189,80,104,118,126,118,127,214, +98,234,120,216,130,214,170,234,239,235,58,20,38,58,21,82,66,88,84,54, +41,54,98,174,98,94,30,94,30,174,99,174,30,134,99,134,64,174,65,94, +14,224,103,208,126,132,127,34,156,140,157,14,172,38,226,38,216,78,198,112, +177,132,184,58,194,88,214,112,239,132,120,180,233,180,108,230,245,230,176,230, +177,151,66,16,42,54,23,76,68,80,84,52,45,52,92,168,92,88,34,88, +34,168,93,168,34,128,93,128,64,168,65,88,18,222,103,204,122,218,122,48, +158,48,159,218,122,194,159,194,172,82,241,82,174,118,193,170,214,14,214,216, +208,232,196,238,173,238,122,116,159,117,58,16,36,50,17,72,66,80,82,46, +39,46,98,170,98,86,32,86,32,170,99,170,32,128,99,128,66,170,67,86, +20,222,105,202,160,16,138,54,119,76,150,72,182,104,239,130,116,130,146,118, +184,82,212,48,143,48,116,156,235,156,142,178,113,226,202,184,239,220,174,126, +174,222,168,236,162,240,147,241,60,16,40,56,21,86,74,84,90,52,43,52, +104,178,104,92,40,92,40,178,105,178,72,178,73,92,40,136,105,136,26,226, +111,206,218,20,170,34,121,42,206,120,233,158,210,68,138,150,221,142,172,44, +136,102,181,100,148,178,117,228,206,180,239,224,182,146,182,222,178,232,166,236, +155,237,48,18,83,40,24,46,59,66,30,118,83,76,126,30,99,70,200,30, +239,72,208,68,156,92,107,102,158,76,159,14,92,106,60,140,31,162,152,140, +166,122,77,122,202,202,202,148,66,148,66,202,203,202,20,228,239,228,66,174, +203,174,134,148,135,203,62,16,44,54,23,84,72,90,92,54,45,54,96,182, +96,98,34,98,34,182,97,182,34,140,97,140,64,182,65,98,16,228,105,216, +156,16,183,42,122,86,122,56,228,56,229,88,130,100,219,100,114,142,241,142, +156,142,156,164,152,194,136,220,109,240,192,142,192,218,196,230,206,238,224,238, +236,226,239,213,62,12,42,50,23,72,70,78,88,44,47,44,94,170,94,86, +36,86,36,170,95,170,66,170,67,86,36,128,95,128,20,218,103,206,148,158, +173,216,160,192,122,214,122,32,162,32,162,132,123,132,122,82,163,82,190,244, +190,32,228,32,228,188,218,198,207,199,56,16,34,54,19,74,70,80,90,44, +41,44,100,172,100,86,30,86,30,172,101,172,30,128,101,128,66,172,67,86, +20,226,111,208,118,44,233,44,130,74,223,74,114,104,245,104,174,104,175,10, +136,242,136,132,216,132,216,224,210,236,200,240,191,240,136,164,217,164,136,194, +217,195,58,14,36,50,17,76,66,82,86,48,39,48,98,174,98,88,32,88, +32,174,99,174,32,130,99,130,64,174,65,88,16,224,107,204,120,46,223,46, +112,82,239,82,170,82,171,12,148,94,117,130,188,96,229,126,166,116,140,156, +121,180,150,170,178,202,237,236,148,146,208,146,190,182,150,218,101,239,56,12, +36,54,15,82,64,82,78,52,39,52,90,174,90,90,34,90,34,174,91,174, +34,130,91,130,62,174,63,90,22,226,93,210,96,32,189,32,106,204,183,186, +162,244,163,32,122,32,123,200,122,90,163,90,122,140,163,140,176,54,224,54, +220,142,185,230,238,230,202,164,192,100,191,55,62,14,38,52,17,76,68,80, +88,46,45,46,96,176,96,88,32,88,32,176,97,176,64,176,65,88,32,126, +97,126,14,224,109,212,154,242,155,10,194,242,195,10,108,58,155,58,114,114, +155,114,110,174,155,174,238,58,195,58,234,114,195,114,240,176,195,177,66,18, +44,56,23,84,74,92,94,54,47,54,102,180,102,98,36,98,36,180,103,180, +36,138,103,138,68,180,69,98,20,226,115,210,222,108,222,32,134,32,134,108, +223,108,134,72,223,72,134,126,134,232,175,214,174,166,135,166,194,126,194,224, +202,236,210,240,224,240,234,228,239,216,236,154,195,181,62,16,48,44,23,76, +72,80,92,46,49,46,106,168,106,86,38,86,38,168,107,168,72,168,73,86, +38,126,107,126,24,220,117,206,220,104,220,28,144,28,144,104,221,104,144,64, +221,64,138,244,138,136,230,136,231,242,138,174,231,174,138,218,231,219,64,18, +40,58,19,84,70,86,90,54,45,54,100,176,100,94,36,94,36,176,101,176, +36,134,101,134,68,176,69,94,26,224,111,208,128,240,128,36,232,36,233,238, +128,216,233,216,146,88,215,88,204,182,204,130,160,130,160,182,205,182,182,130, +183,55,58,16,38,52,19,76,68,82,84,50,41,50,100,172,100,88,30,88, +30,172,101,172,30,128,101,128,62,172,63,88,16,222,107,200,162,20,128,38, +128,128,222,128,222,36,185,36,162,80,129,80,186,80,223,80,158,128,158,154, +146,200,126,224,105,236,190,128,190,216,194,228,206,234,226,234,236,218,239,201, +60,14,40,52,15,84,70,86,86,50,43,50,94,178,94,92,34,92,34,178, +95,178,34,134,95,134,64,178,65,92,18,226,103,210,174,14,144,66,117,100, +236,94,198,64,169,24,164,74,189,94,132,114,212,114,193,156,128,182,111,230, +162,154,189,182,216,174,241,214,156,180,156,224,160,232,172,238,198,238,208,226, +215,211,58,12,38,48,19,76,72,78,90,44,41,44,98,170,98,84,34,84, +34,170,99,170,34,126,99,126,66,170,67,84,24,212,101,202,102,236,122,198, +132,146,132,30,226,30,226,212,222,226,210,232,191,232,154,78,205,78,148,114, +211,114,178,114,179,48,198,194,198,146,158,146,158,194,199,195,60,18,40,56, +19,84,68,90,86,56,41,56,98,176,98,98,34,98,34,176,99,176,81,176, +66,176,67,98,34,138,99,138,20,226,105,212,112,34,212,34,212,216,214,228, +222,236,230,234,241,204,190,220,175,184,184,62,150,68,117,70,180,166,180,108, +124,108,124,166,181,166,116,222,183,202,152,68,153,211,64,14,42,50,19,74, +68,80,90,50,45,50,98,172,98,86,34,86,34,172,99,172,34,130,99,130, +66,172,67,86,24,222,109,204,152,16,122,76,153,116,190,18,164,72,195,112, +232,20,204,70,239,110,130,242,130,132,226,132,227,242,130,220,227,220,130,176, +227,176,178,220,179,133,66,16,44,56,17,90,70,90,90,56,45,56,96,182, +96,96,36,96,36,182,97,182,36,140,97,140,66,182,67,96,20,228,109,214, +120,46,233,46,172,76,173,12,114,90,243,90,144,114,145,64,202,112,203,64, +132,200,132,128,218,128,219,200,176,146,176,188,164,216,140,232,123,238,190,202, +237,239,58,14,36,50,15,76,64,80,86,46,41,46,94,172,94,88,30,88, +30,172,95,172,30,128,95,128,62,172,63,88,14,220,105,202,102,54,239,54, +130,16,130,122,229,122,164,12,164,90,202,90,203,10,112,158,241,158,172,242, +173,134,102,228,142,194,173,158,238,220,198,194,173,159,60,16,40,52,19,82, +70,88,88,50,43,50,98,174,98,94,34,94,34,174,99,174,34,132,99,132, +66,174,67,94,20,226,117,208,160,76,160,24,120,24,120,76,161,76,228,76, +228,26,186,26,186,76,229,76,126,108,229,108,112,140,247,140,164,140,154,174, +222,174,216,212,206,228,192,236,161,237,54,14,34,52,17,74,60,84,78,48, +37,48,88,172,88,90,28,90,28,172,89,172,58,172,59,90,28,130,89,130, +18,226,95,208,156,26,128,34,99,40,102,90,159,90,132,240,133,34,94,188, +133,112,164,154,133,114,178,68,169,122,238,60,219,110,200,12,200,144,182,194, +157,236,240,232,216,188,201,143,62,10,40,50,19,74,72,76,90,40,47,40, +100,170,100,84,36,84,36,170,101,170,68,170,69,84,36,124,101,124,22,218, +105,204,154,10,136,46,119,72,238,36,141,36,216,126,216,68,138,68,138,126, +217,126,138,98,217,98,158,140,138,170,119,192,156,178,182,210,237,238,112,236, +164,218,216,160,145,161,66,14,44,52,19,82,72,90,94,52,47,52,100,180, +100,96,34,96,34,180,101,180,68,180,69,96,34,138,101,138,16,226,111,212, +222,126,222,52,132,52,132,126,223,126,132,90,223,90,172,14,159,52,118,154, +239,154,126,192,227,192,112,232,241,232,178,232,179,155,64,14,42,50,21,74, +70,82,90,50,43,50,100,174,100,90,34,90,34,174,101,174,34,132,101,132, +68,174,69,90,20,224,111,210,108,190,124,162,132,122,132,46,220,46,220,94, +133,94,156,14,185,36,140,244,140,134,230,134,230,224,226,234,216,240,207,240, +140,176,231,176,170,218,171,134,200,218,201,135,72,16,48,56,19,84,76,92, +94,58,47,58,104,184,104,98,38,98,38,184,105,184,74,184,75,98,38,142, +105,142,26,228,117,216,124,34,220,34,204,70,184,90,156,108,123,120,130,54, +156,80,188,100,218,112,245,118,162,48,183,68,220,188,220,146,138,146,138,188, +221,188,212,206,241,238,124,232,227,222,178,116,179,227,28,36,133,36,34,56, +127,56,20,76,133,76,76,76,77,14,68,76,62,96,48,118,21,132,62,96, +118,96,116,108,108,120,96,120,75,120,176,16,160,48,143,72,240,48,161,48, +164,70,180,92,202,110,239,126,140,122,176,108,200,82,217,48,36,158,70,144, +93,124,138,154,154,140,77,140,202,204,202,160,60,160,60,204,203,204,60,182, +203,182,130,204,131,160,24,228,237,229,56,10,34,50,19,72,66,76,84,42, +41,42,92,172,92,82,32,82,32,172,93,172,32,126,93,126,62,172,63,82, +20,222,109,204,112,40,199,40,104,68,241,68,160,68,161,8,220,28,190,64, +156,86,109,112,138,96,138,128,144,134,158,138,216,138,232,126,239,114,222,94, +139,114,132,242,132,162,216,162,217,240,132,194,217,194,132,226,217,227,60,14, +40,54,17,82,72,86,94,50,45,50,100,178,100,94,32,94,32,178,101,178, +66,178,67,94,32,136,101,136,16,228,105,212,222,94,222,28,132,28,132,94, +223,94,132,60,223,60,116,124,164,124,164,220,160,232,152,238,137,238,124,150, +147,170,118,206,165,184,182,124,230,124,230,218,224,232,205,232,184,148,205,168, +184,202,231,173,60,14,42,52,25,76,70,82,88,46,47,46,98,170,98,88, +34,88,34,170,99,170,68,170,69,88,34,130,99,130,22,220,105,204,226,94, +226,30,122,30,122,94,227,94,190,94,191,30,158,94,159,30,174,242,175,102, +150,124,121,160,114,222,155,174,198,122,235,160,196,172,241,219,60,16,42,50, +17,82,70,84,86,50,43,50,98,178,98,90,34,90,34,178,99,178,34,134, +99,134,66,178,67,90,18,228,109,210,234,22,178,34,115,38,124,58,143,92, +168,52,185,88,230,48,203,100,152,98,140,126,125,146,230,120,143,120,116,166, +247,166,133,184,228,186,229,244,132,184,132,226,229,222,180,224,181,121,54,14, +36,50,15,76,64,78,82,46,39,46,90,176,90,84,32,84,32,176,91,176, +32,128,91,128,62,176,63,84,20,222,103,206,96,48,185,48,124,16,124,80, +160,80,161,18,168,154,168,110,112,110,112,154,169,154,104,184,175,184,140,242, +141,80,174,82,232,80,226,208,222,220,212,226,195,226,200,14,200,112,190,174, +163,233,62,14,42,44,19,72,72,76,90,40,47,40,104,166,104,82,34,82, +34,166,105,166,34,124,105,124,70,166,71,82,20,212,109,196,112,30,243,30, +228,104,228,62,130,62,130,104,229,104,162,104,163,30,194,104,195,30,128,138, +229,138,116,168,245,168,148,190,105,228,202,188,243,226,178,168,178,222,172,236, +151,237,60,14,40,48,17,76,64,82,86,48,41,48,96,170,96,88,34,88, +34,170,97,170,64,170,65,88,34,128,97,128,22,226,109,204,114,34,233,34, +116,94,116,64,236,64,237,92,130,98,159,98,130,122,159,122,192,96,223,96, +192,122,223,122,174,140,175,34,120,154,224,154,225,244,122,190,225,190,118,226, +225,227,56,12,34,56,15,80,66,82,86,46,39,46,92,174,92,88,32,88, +32,174,93,174,32,128,93,128,62,174,63,88,22,224,101,206,220,76,220,22, +132,22,132,76,221,76,132,50,221,50,232,140,232,102,118,102,118,140,233,140, +154,140,155,102,192,140,193,102,120,164,216,164,174,210,132,230,103,238,238,238, +192,222,158,194,139,165,64,14,46,42,31,60,142,38,51,38,12,86,153,86, +120,130,130,58,54,58,48,114,143,114,78,96,95,108,78,68,97,80,178,16, +162,48,145,68,236,46,165,46,162,50,178,84,210,112,237,126,154,126,186,102, +204,70,211,46,86,126,62,154,41,174,148,158,162,144,71,144,200,206,200,164, +66,164,66,206,201,206,66,184,201,184,132,206,133,164,24,228,239,229,56,14, +36,52,17,80,66,82,82,50,39,50,90,172,90,90,34,90,34,172,91,172, +60,172,61,90,34,130,91,130,16,220,95,206,156,14,183,34,240,44,118,44, +118,168,99,236,132,96,247,96,136,70,224,70,224,120,137,120,144,242,144,148, +226,148,226,228,218,238,205,238,144,174,227,174,144,198,227,198,184,236,185,53, +50,12,30,50,15,74,56,80,72,46,35,46,78,172,78,86,28,86,28,172, +79,172,28,130,79,130,54,172,55,86,14,214,85,200,238,34,106,34,106,172, +81,238,124,54,141,80,120,96,175,96,170,52,153,96,130,120,130,174,173,170, +174,186,175,124,150,96,150,166,140,204,121,232,204,50,194,82,181,116,220,116, +228,94,189,94,200,122,200,162,184,202,155,238,240,230,216,198,201,163,58,14, +40,46,21,72,68,78,86,46,41,46,94,174,94,84,32,84,32,174,95,174, +62,174,63,84,32,130,95,130,18,224,107,208,138,18,159,38,114,46,237,46, +237,46,208,14,189,46,122,78,225,78,112,108,237,108,108,154,245,154,130,122, +149,146,214,122,199,154,174,154,175,46,132,248,132,184,216,184,217,246,132,228, +217,229,56,12,36,50,17,74,64,78,82,44,41,44,90,172,90,84,30,84, +30,172,91,172,62,172,63,84,30,128,91,128,18,224,101,208,134,14,159,38, +106,48,239,48,206,12,185,48,216,156,216,78,120,78,120,156,217,156,120,132, +217,132,156,48,156,78,152,100,143,116,184,48,184,100,186,110,217,110,104,184, +243,184,134,196,159,218,204,156,204,222,200,232,188,238,175,239,54,14,34,54, +13,82,64,84,82,50,37,50,90,180,90,92,30,92,30,180,91,180,60,180, +61,92,30,134,91,134,18,226,103,208,224,106,224,42,120,42,120,106,225,106, +120,74,225,74,154,106,155,8,188,106,189,10,106,130,239,130,216,186,216,156, +128,156,128,186,217,186,136,200,155,222,102,234,243,234,208,198,185,235,14,44, +129,44,46,12,46,78,98,78,99,10,110,156,110,110,32,110,32,156,111,156, +10,188,127,188,70,244,71,78,224,168,224,36,148,36,148,168,225,168,148,102, +225,102,112,228,245,229,14,44,119,44,44,16,44,76,92,76,93,12,104,148, +104,108,32,108,32,148,105,148,12,182,119,182,64,244,65,76,118,142,243,142, +136,142,136,62,218,62,219,142,180,12,180,80,170,148,146,196,107,238,234,238, +202,198,182,160,175,143,12,44,107,44,40,10,40,78,84,78,85,10,96,150, +96,110,28,110,28,150,97,150,10,182,111,182,62,242,63,78,118,42,137,76, +110,108,136,108,137,210,104,230,132,210,140,210,164,224,196,228,243,224,150,66, +235,66,190,10,190,72,182,126,172,154,157,184,230,182,210,138,189,97,14,48, +115,48,42,10,42,78,88,78,89,8,102,152,102,110,28,110,28,152,103,152, +14,186,119,186,64,242,65,78,220,20,168,30,129,34,114,84,239,84,178,38, +160,102,140,122,119,138,236,136,206,118,187,84,152,134,144,196,117,232,202,238, +203,137,16,52,113,52,42,12,42,82,84,82,85,14,96,158,96,114,30,114, +30,158,97,158,14,190,115,190,62,242,63,82,158,18,130,64,105,88,218,152, +218,94,132,94,132,152,219,152,172,94,200,54,139,54,172,94,168,158,148,210, +111,238,186,152,186,222,190,232,200,236,226,236,232,224,237,207,16,48,111,48, +44,14,44,80,86,80,87,16,98,154,98,116,34,116,34,154,99,154,14,188, +113,188,64,242,65,80,122,40,237,40,152,68,153,14,196,66,197,14,114,104, +237,104,172,76,146,124,117,166,140,242,141,132,162,136,224,136,198,166,198,220, +196,230,190,234,173,234,156,182,241,183,16,46,119,46,46,14,46,78,94,78, +95,14,104,152,104,112,32,112,32,152,105,152,14,184,117,184,68,240,69,78, +158,14,136,54,115,78,138,52,228,52,228,210,220,224,210,230,187,230,150,68, +173,88,118,96,213,96,128,122,203,122,128,144,203,144,194,206,194,168,134,168, +134,206,195,207,12,46,117,46,44,12,44,78,92,78,93,12,106,152,106,112, +30,112,30,152,107,152,12,188,121,188,68,242,69,78,156,42,191,64,126,24, +210,24,177,54,120,72,232,72,213,104,128,114,156,96,181,72,182,72,182,120, +174,128,159,128,120,160,239,160,172,142,173,244,114,220,146,192,173,160,234,216, +206,198,173,161,12,48,107,48,38,14,38,78,88,78,89,10,96,150,96,106, +30,106,30,150,97,150,8,182,105,182,62,244,63,78,116,40,231,40,122,68, +221,68,110,98,243,98,148,98,149,12,192,98,193,10,126,242,126,130,214,130, +214,220,212,232,204,238,189,238,108,194,243,194,126,162,215,162,170,194,171,99, +16,46,111,46,44,14,44,78,88,78,89,12,98,154,98,110,32,110,32,154, +99,154,12,184,115,184,66,246,67,78,122,40,233,40,112,84,243,84,152,84, +153,10,198,84,199,10,148,94,130,118,113,136,132,244,132,116,224,116,224,224, +218,236,201,236,176,238,177,116,132,152,225,152,132,186,225,187,20,122,20,94, +110,94,111,120,36,94,36,28,92,28,93,94,36,58,68,58,69,94,36,244, +36,128,94,128,94,220,88,234,71,234,36,160,95,160,36,188,95,188,178,12, +158,68,131,104,236,102,198,66,175,22,154,114,152,182,123,232,206,242,207,113, +20,120,20,94,114,94,115,118,38,94,38,24,100,24,101,94,70,94,70,58, +39,58,38,242,38,128,100,128,100,218,94,234,77,234,38,188,101,188,38,156, +101,156,136,102,156,68,156,24,204,24,204,76,210,90,218,94,239,94,132,124, +212,124,194,176,162,210,129,232,148,124,156,152,174,186,198,210,233,235,22,126, +22,98,122,98,123,124,38,98,38,30,104,30,105,98,72,98,72,62,39,62, +42,242,42,126,100,126,100,222,94,236,77,236,42,158,101,158,42,192,101,192, +124,72,243,72,144,240,144,144,218,144,219,240,144,216,219,216,180,144,181,13, +20,120,20,98,122,98,123,120,38,98,38,30,104,30,105,98,72,98,72,64, +39,64,40,246,40,128,102,128,102,222,96,238,79,238,40,160,103,160,40,190, +103,190,166,66,189,88,190,112,204,112,216,96,216,46,148,46,148,144,232,144, +232,216,218,234,189,234,124,188,207,188,182,12,167,47,20,124,20,94,114,94, +115,124,36,94,36,28,98,28,99,94,68,94,68,58,37,58,40,240,40,124, +96,124,96,220,88,232,75,232,40,154,97,154,40,186,97,186,172,210,191,232, +218,20,172,32,138,32,138,226,173,190,234,108,139,108,240,200,236,220,228,226, +216,224,196,186,186,126,184,102,185,31,18,120,18,92,118,92,119,120,40,92, +40,24,98,24,99,92,70,92,70,54,41,54,38,238,38,120,98,120,98,222, +88,234,71,234,38,188,99,188,38,156,99,156,230,18,184,28,144,32,144,148, +134,190,115,228,242,84,145,84,162,240,162,136,226,136,227,238,162,214,227,215, +18,126,18,94,110,94,111,124,32,94,32,26,94,26,95,94,66,94,66,58, +33,58,36,242,36,124,92,124,92,222,82,236,69,236,36,156,93,156,36,188, +93,188,158,12,136,56,121,78,140,46,210,46,190,84,154,118,113,142,146,72, +168,98,196,120,237,140,138,242,138,152,212,152,213,240,138,216,213,217,20,118, +20,92,108,92,109,118,38,92,38,26,94,26,95,92,66,92,66,56,39,56, +40,238,40,120,90,120,90,218,84,230,67,230,40,152,91,152,40,180,91,180, +212,100,212,26,136,26,136,100,213,100,136,64,213,64,112,134,237,134,172,236, +173,26,108,210,148,170,173,134,232,206,200,176,173,135,24,126,24,96,114,96, +115,126,40,96,40,30,100,30,101,96,72,96,72,64,41,64,40,244,40,126, +94,126,94,224,86,236,69,236,40,190,95,190,40,160,95,160,224,136,224,48, +138,48,138,136,225,136,138,94,225,94,180,48,180,94,172,136,141,174,172,14, +155,48,110,190,243,190,190,244,191,155,22,122,22,94,112,94,113,118,42,94, +42,24,98,24,99,94,72,94,72,54,43,54,42,242,42,120,94,120,94,220, +84,234,71,234,42,154,95,154,42,186,95,186,132,24,153,52,222,24,199,54, +118,70,241,70,176,132,177,12,122,130,177,78,232,126,202,102,177,76,110,162, +241,162,170,136,134,192,182,210,231,232,206,162,198,186,178,212,148,228,115,237, +20,122,20,96,104,96,105,122,36,96,36,28,88,28,89,96,60,96,60,64, +37,64,36,244,36,126,88,126,88,224,82,236,63,236,36,190,89,190,36,160, +89,160,156,14,187,34,118,76,118,44,230,44,231,76,164,58,146,90,127,114, +114,162,166,140,196,112,212,88,149,88,152,110,182,136,212,150,241,160,134,242, +134,170,210,170,211,244,134,224,211,225,18,124,18,98,104,98,105,124,36,98, +36,30,88,30,89,98,58,98,58,64,37,64,36,244,36,126,86,126,86,222, +78,236,63,236,36,192,87,192,36,162,85,162,158,16,183,34,116,70,116,44, +228,44,229,70,120,86,233,86,154,110,155,58,196,110,197,58,134,194,134,124, +216,124,217,188,176,144,164,190,146,216,113,236,184,176,184,222,190,236,218,236, +232,224,239,211,20,122,20,98,104,98,105,120,38,98,38,28,90,28,91,98, +64,98,64,62,39,62,38,240,38,126,90,126,90,220,82,238,71,238,38,158, +91,158,38,190,91,190,156,14,185,36,118,78,118,48,230,48,231,76,108,174, +241,174,212,72,174,82,140,86,141,174,228,120,141,120,190,174,191,120,156,192, +113,236,190,190,231,237,18,122,18,98,104,98,105,124,36,98,36,30,86,30, +87,98,60,98,60,64,37,64,36,242,36,128,88,128,88,228,76,238,65,238, +36,192,89,192,36,160,89,160,224,72,224,26,120,26,120,72,225,72,156,72, +157,26,190,72,191,26,148,84,126,122,109,144,194,236,218,236,230,218,230,112, +135,112,198,176,198,146,128,146,128,176,199,176,194,188,213,218,112,212,205,206, +164,208,165,123,124,130,124,48,36,48,36,130,125,130,74,12,61,48,80,48, +80,130,66,176,44,214,21,236,36,88,125,88,86,148,86,218,94,230,114,236, +218,236,230,222,237,206,130,170,149,204,122,148,98,198,143,198,146,62,231,62, +142,106,237,106,186,216,187,12,146,162,187,112,232,164,204,138,187,111,98,130, +98,50,28,50,28,130,99,130,66,50,66,130,54,178,36,212,17,236,78,146, +78,208,84,224,104,232,218,232,232,220,239,198,118,176,127,206,106,152,92,194, +123,194,28,92,99,92,64,16,43,50,186,20,215,42,116,62,235,62,161,10, +158,10,158,64,146,118,127,160,138,214,172,184,198,138,206,98,153,98,146,120, +188,160,217,201,232,36,46,36,46,140,27,228,66,74,229,74,172,50,199,64, +146,48,130,84,102,104,65,118,232,118,186,102,164,90,151,74,206,180,206,126, +88,126,88,180,207,180,88,154,207,154,146,126,144,154,140,180,116,210,88,228, +63,236,160,180,160,224,164,234,176,238,218,238,230,226,235,212,204,200,213,220, +194,190,176,214,209,214,142,98,127,127,102,126,102,46,32,46,32,126,103,126, +66,14,51,46,68,46,68,126,54,178,21,234,76,144,76,210,82,224,98,230, +214,230,228,222,239,204,112,172,121,196,100,150,94,190,117,190,32,86,103,86, +118,36,235,36,134,202,134,78,222,78,222,176,218,192,203,192,160,36,160,78, +158,120,147,160,176,134,161,108,192,36,192,82,190,120,175,168,212,152,191,117, +102,130,102,48,28,48,28,130,103,130,28,92,103,92,66,12,41,48,64,48, +64,92,62,130,54,176,21,230,76,146,76,212,82,226,104,232,208,232,226,226, +241,200,114,174,125,204,106,148,92,198,119,192,122,24,155,52,230,24,199,54, +140,210,140,74,218,74,218,184,212,200,193,200,140,152,219,152,140,112,219,112, +176,74,177,11,104,122,104,42,30,42,30,122,105,122,66,10,55,42,68,42, +68,86,66,122,50,186,17,230,30,80,105,80,78,136,78,206,84,218,100,226, +218,226,234,212,241,194,114,164,123,188,106,144,88,184,119,180,134,198,134,28, +218,28,218,180,212,190,193,190,156,48,169,70,134,88,219,88,196,48,179,88, +168,96,181,112,150,120,205,120,162,120,162,160,203,161,98,130,98,50,30,50, +30,130,99,130,30,90,99,90,62,14,47,50,62,50,62,98,60,146,46,196, +21,232,74,150,74,216,78,228,96,234,216,234,226,228,239,214,101,152,108,174, +119,202,100,152,86,200,115,192,154,14,185,32,114,44,239,44,148,58,207,92, +200,58,151,92,134,66,134,110,226,110,227,66,130,216,130,138,226,138,226,194, +218,210,201,210,188,156,209,186,178,120,154,182,201,175,90,124,72,186,48,214, +23,232,88,52,28,158,81,154,62,18,22,96,63,96,160,14,126,68,89,106, +148,66,173,84,156,18,184,62,212,86,237,98,168,210,120,232,120,100,202,100, +202,160,121,160,120,130,203,130,160,180,233,232,222,164,193,203,236,34,48,34, +48,152,40,194,25,232,176,48,199,60,70,72,231,72,146,48,146,72,112,104, +77,120,222,118,143,76,152,106,112,136,71,156,236,152,182,138,145,112,142,134, +155,148,160,224,102,238,102,156,198,156,198,200,103,200,102,178,199,178,152,208, +229,236,222,200,191,221,28,36,119,36,70,36,54,68,29,92,32,126,66,114, +90,86,100,66,57,66,58,88,77,102,168,16,142,48,113,72,238,70,194,48, +165,22,172,54,152,72,133,82,190,68,168,84,147,100,210,80,186,104,157,122, +128,100,74,142,19,164,236,156,158,130,123,104,118,132,141,144,112,222,66,236, +66,150,186,150,186,194,67,194,66,172,187,172,110,204,211,238,194,200,163,221, +98,52,98,28,36,28,36,52,99,52,18,74,113,74,54,74,46,94,98,94, +94,118,84,128,61,128,220,68,226,52,134,52,134,84,124,104,115,116,170,18, +170,82,178,88,206,88,221,80,144,78,205,68,152,126,160,114,160,104,198,104, +198,132,220,132,229,118,170,34,225,34,130,124,76,154,17,168,236,158,174,154, +121,130,114,148,135,160,136,224,68,238,68,166,188,166,188,202,69,202,68,184, +189,184,134,210,223,240,210,202,183,227,120,18,145,30,24,38,233,38,106,98, +76,128,33,146,100,66,40,112,93,112,74,50,38,80,79,80,148,48,134,70, +117,92,138,136,139,64,172,50,187,62,144,70,227,70,144,90,223,90,144,112, +221,112,144,130,233,130,182,130,183,70,120,128,74,158,27,176,120,126,178,160, +235,172,116,150,137,162,116,230,64,240,64,170,186,170,186,206,65,206,64,188, +187,188,116,214,211,240,202,208,173,229,140,32,46,32,47,156,12,156,149,156, +132,76,47,76,130,114,47,114,216,20,182,58,151,84,220,82,186,116,157,142, +234,138,192,192,141,234,108,180,139,214,76,164,36,220,125,201,16,96,135,96, +126,28,46,28,47,96,120,52,47,52,120,74,47,74,102,108,129,132,72,96, +36,132,117,122,214,18,178,36,145,48,220,58,184,76,151,90,230,92,188,116, +147,132,22,156,235,156,100,156,100,178,88,212,58,230,25,240,150,156,150,220, +158,232,176,234,206,234,222,228,230,216,233,205,129,26,14,94,133,94,44,94, +44,26,129,26,116,50,45,50,116,72,45,72,55,94,118,126,101,100,54,94, +30,126,111,114,214,18,174,34,139,44,218,50,184,66,147,78,230,84,186,102, +143,110,202,126,158,140,45,148,30,178,211,166,16,206,233,194,120,144,120,218, +124,228,138,236,212,236,222,232,235,217,129,24,12,94,135,94,128,24,44,24, +45,94,118,48,45,48,118,70,45,70,100,98,115,122,56,94,32,126,109,112, +216,16,176,34,139,44,220,52,182,68,147,78,230,82,192,100,145,112,16,198, +243,198,56,236,56,146,206,146,206,218,200,232,186,236,175,236,130,198,131,122, +56,172,207,173,133,24,14,90,137,90,132,24,44,24,45,90,122,46,45,46, +124,68,45,68,100,96,119,126,58,90,32,122,109,110,216,16,178,34,141,44, +222,52,182,70,147,78,232,86,192,104,147,116,30,140,206,140,202,156,190,166, +165,166,22,188,66,174,107,140,60,242,60,186,204,186,205,242,60,222,205,223, +14,90,137,90,98,94,111,122,132,24,42,24,43,90,120,48,43,48,122,68, +43,68,56,90,32,122,107,114,218,16,174,36,139,46,226,46,184,68,147,78, +236,80,198,100,151,112,22,146,235,146,42,172,217,172,130,172,131,116,54,244, +54,198,206,198,207,244,54,228,207,229,18,98,145,98,108,102,127,134,138,26, +54,26,55,98,128,52,55,52,128,74,55,74,68,98,40,132,117,118,220,18, +180,40,149,50,226,56,188,76,153,88,232,96,192,114,147,124,24,232,133,210, +50,154,51,226,92,140,93,218,138,172,93,172,158,140,158,216,162,228,176,232, +214,232,224,226,233,212,222,158,159,183,133,22,12,92,143,92,108,98,123,126, +56,92,34,118,115,112,132,22,46,22,47,92,124,44,47,44,124,66,47,66, +212,14,174,32,141,42,220,50,182,66,145,76,230,82,188,100,145,114,76,126, +46,158,19,178,54,244,55,152,78,152,235,152,154,240,155,124,78,220,118,192, +155,156,232,218,194,192,155,157,12,82,129,82,90,88,109,110,56,82,28,108, +99,100,122,24,38,24,39,82,110,42,39,42,110,60,39,60,208,16,170,32, +135,40,220,46,182,62,143,72,232,74,190,92,141,104,62,116,87,132,180,114, +157,134,38,140,213,140,12,164,233,164,126,112,100,156,66,186,17,210,232,206, +192,192,153,164,150,218,162,214,172,204,172,190,78,190,78,220,80,232,98,240, +174,240,186,236,199,219,14,86,137,86,98,94,119,120,66,86,36,118,109,110, +128,22,44,22,45,86,118,46,45,46,118,68,45,68,218,18,178,36,141,46, +222,50,186,70,149,82,232,84,188,106,143,116,106,134,74,140,31,142,18,166, +127,166,78,244,79,140,24,228,54,198,79,166,116,212,79,182,148,146,137,186, +222,146,209,186,178,128,178,164,166,200,148,220,125,234,234,234,210,218,192,194, +179,167,14,84,135,84,134,18,48,18,49,84,98,88,113,110,58,84,38,110, +103,98,122,42,49,42,122,62,49,62,216,14,178,32,143,42,222,44,182,62, +147,72,232,76,188,90,145,100,126,110,149,120,38,158,38,130,222,130,223,156, +16,204,241,204,98,216,66,232,37,240,164,212,221,240,190,144,124,152,76,154, +77,204,76,176,207,176,166,176,167,205,135,24,20,78,141,78,134,24,52,24, +53,78,126,44,53,44,124,64,53,64,106,78,123,102,64,78,44,100,117,94, +212,22,178,36,145,42,218,50,182,62,149,68,230,76,190,90,145,98,204,140, +204,116,62,116,62,140,205,140,154,140,155,116,112,140,113,116,20,156,239,156, +194,198,194,174,70,174,70,198,195,198,34,226,80,214,117,198,142,224,88,236, +89,210,146,198,164,216,194,230,225,238,210,196,179,223,129,24,10,80,135,80, +128,24,44,24,45,80,100,84,115,104,58,80,36,102,107,94,44,44,117,44, +44,62,117,62,212,24,176,36,141,46,216,52,182,64,149,72,236,76,186,92, +143,98,72,108,50,118,75,134,136,104,116,120,143,134,204,102,184,118,205,130, +204,174,204,140,48,140,48,174,205,174,90,146,175,170,80,168,171,148,78,186, +101,196,70,206,93,216,154,188,179,196,148,204,173,214,48,186,48,236,109,224, +128,186,128,236,181,224,194,184,198,212,206,228,216,236,226,234,235,221,120,12, +151,34,236,46,46,46,46,170,23,236,64,86,129,86,150,86,221,86,100,156, +101,56,64,142,86,118,99,86,130,118,101,94,180,154,181,56,140,142,162,116, +181,86,230,146,198,112,181,86,190,186,231,240,132,152,73,200,166,166,86,234, +215,221,124,14,153,32,234,42,44,42,44,172,36,208,21,238,66,76,133,76, +154,74,233,74,110,128,111,54,64,122,88,102,111,76,132,102,111,84,182,126, +183,50,136,120,162,100,183,74,238,122,204,100,183,74,206,134,142,148,75,150, +72,176,221,170,58,204,237,198,140,148,140,222,146,234,158,240,208,240,222,236, +229,223,120,14,155,34,240,44,48,44,48,160,38,200,25,230,64,78,137,78, +156,78,231,78,108,130,109,56,64,126,86,106,109,78,134,110,109,90,153,120, +188,130,189,54,150,120,172,100,189,78,236,120,210,104,189,78,192,170,229,200, +182,146,84,196,213,188,142,130,94,166,143,166,150,192,150,228,146,236,129,236, +114,208,67,236,182,210,231,237,122,10,149,30,228,38,44,38,44,170,36,206, +21,236,44,72,212,72,212,102,45,102,104,102,105,38,158,102,159,38,86,110, +86,166,133,154,134,130,87,130,215,118,160,110,160,146,164,158,176,162,218,162, +226,156,233,140,214,118,161,134,62,242,88,228,102,206,104,184,172,184,172,218, +176,228,186,234,218,234,226,228,235,209,112,14,143,36,232,44,40,44,40,168, +32,202,19,230,40,68,214,68,214,94,41,94,104,94,105,44,160,94,161,44, +82,100,82,146,145,136,136,118,83,118,164,100,164,126,168,138,180,142,210,142, +226,136,235,118,214,110,165,120,200,158,140,166,85,166,56,190,229,190,142,244, +143,166,54,236,102,216,143,190,236,232,190,220,143,191,106,14,139,34,226,46, +42,46,42,166,32,200,21,224,62,176,223,176,124,152,149,166,68,202,207,202, +48,228,231,228,138,228,139,176,42,70,212,70,212,98,43,98,100,98,101,46, +156,98,157,46,80,106,80,152,143,140,80,124,137,124,160,106,160,134,162,146, +172,152,212,152,224,144,231,128,210,116,161,129,112,16,143,38,232,46,42,46, +42,152,34,190,19,232,42,70,212,70,212,96,43,96,102,96,103,46,158,96, +159,46,82,102,82,150,141,142,134,120,83,120,160,102,160,132,164,142,176,146, +214,146,228,138,237,122,216,114,161,124,92,162,111,182,56,190,233,190,140,246, +141,156,194,160,169,190,52,236,100,218,141,190,230,236,178,218,141,191,64,16, +85,36,124,48,32,48,32,172,26,204,15,226,146,52,229,52,32,86,124,86, +124,130,33,130,64,130,65,58,94,130,95,58,56,142,56,226,79,208,56,172, +77,172,100,140,100,222,137,198,100,160,129,160,140,172,243,172,160,172,161,12, +214,172,215,14,160,88,213,88,160,130,213,130,172,186,137,240,202,190,239,235, +112,10,147,30,234,38,42,38,42,160,36,190,25,220,42,62,216,62,216,86, +43,86,104,38,105,86,158,38,159,84,82,92,82,140,141,128,82,110,137,110, +166,92,166,124,172,134,182,138,212,138,228,132,237,116,214,102,167,116,152,138, +102,164,59,180,238,176,188,168,141,144,100,174,185,174,74,198,219,198,54,228, +241,228,100,206,111,228,194,204,175,228,144,228,145,175,128,12,155,30,238,38, +44,38,44,150,38,182,19,220,44,58,218,58,218,78,45,78,102,78,103,38, +158,78,159,38,82,78,82,124,135,116,132,100,83,100,160,78,160,116,164,122, +174,124,218,124,230,118,239,108,220,92,161,102,52,198,126,198,100,216,51,232, +114,234,128,234,140,228,140,144,74,144,75,198,74,162,141,162,74,178,141,178, +108,126,101,144,152,158,245,158,168,176,183,202,210,136,210,218,204,230,196,234, +187,235,58,18,81,40,116,52,32,52,32,168,26,198,17,222,32,90,112,90, +112,132,33,132,60,132,61,62,86,132,87,64,53,144,52,152,52,220,63,214, +52,172,65,172,86,152,86,226,109,210,86,172,105,172,136,28,157,48,214,24, +197,48,124,64,237,64,176,126,177,10,130,112,156,90,177,64,234,114,204,94, +177,64,142,128,128,166,115,188,122,242,146,212,160,174,162,152,135,152,134,180, +151,196,182,152,237,152,184,170,182,198,241,198,206,244,207,125,92,20,54,52, +19,74,62,90,63,46,84,62,239,52,140,18,160,64,182,86,212,100,226,98, +232,90,237,76,174,22,207,40,200,146,200,104,62,104,62,146,201,146,84,118, +105,134,174,118,153,136,46,174,213,174,26,198,235,198,132,198,133,104,58,212, +25,242,92,212,111,240,146,212,167,240,198,210,233,239,122,108,122,36,38,36, +38,108,123,108,50,56,65,86,106,56,93,88,32,138,127,138,22,176,133,168, +38,194,19,238,58,196,63,236,84,192,95,228,108,184,127,222,78,170,79,36, +152,36,152,112,224,112,225,36,149,136,226,138,227,246,148,136,148,226,227,220, +188,222,189,15,102,108,102,32,36,32,36,108,103,108,28,138,109,138,24,172, +115,168,68,170,69,32,44,56,57,88,92,56,79,86,40,196,29,238,58,198, +61,232,80,194,89,228,100,190,119,224,158,148,169,190,160,80,120,188,163,168, +146,24,120,106,151,106,176,78,228,78,224,214,218,224,210,228,201,228,196,14, +196,120,182,192,149,241,120,102,120,34,32,34,32,102,121,102,44,56,63,80, +104,54,91,84,30,134,125,134,18,170,129,162,34,190,19,232,56,190,65,228, +82,188,93,222,104,180,123,216,76,166,77,34,136,54,241,54,142,110,233,110, +184,110,185,12,150,244,150,150,220,150,221,242,150,216,221,217,116,104,116,34, +36,34,36,104,117,104,50,56,63,86,100,54,91,84,30,136,121,136,20,172, +129,164,78,168,79,34,38,186,21,238,60,190,65,228,82,186,93,226,106,180, +123,220,182,10,160,50,135,80,132,128,174,106,206,78,230,50,161,50,164,74, +185,96,194,110,170,148,145,178,130,240,180,218,212,184,234,138,179,138,174,170, +201,195,110,102,110,28,34,28,34,102,111,102,24,136,115,136,20,168,117,168, +72,168,73,28,48,46,55,78,94,50,85,84,34,188,17,234,56,188,61,226, +78,184,91,222,102,182,121,218,200,40,233,74,178,14,132,68,219,60,158,88, +125,124,194,90,239,120,178,106,154,144,133,168,160,166,176,194,204,216,239,230, +128,236,172,208,202,170,216,138,159,139,112,94,112,30,32,30,32,94,113,94, +44,54,57,76,96,50,85,72,26,128,119,128,12,160,123,160,72,160,73,30, +34,184,21,232,56,186,61,224,82,184,91,220,108,178,121,208,132,40,237,40, +132,78,232,78,223,110,138,98,167,116,134,130,163,148,130,172,245,172,176,78, +177,8,184,100,180,172,162,206,144,224,121,238,196,190,235,237,110,24,74,30, +37,34,24,58,115,58,160,18,146,46,137,62,78,98,79,30,26,98,79,58, +114,92,79,66,148,42,222,42,216,76,206,90,198,94,187,94,136,96,164,76, +176,56,183,42,194,154,194,112,60,112,60,154,195,154,82,124,103,142,170,124, +151,142,42,176,207,176,22,200,227,200,126,200,127,112,50,212,25,240,92,216, +107,240,142,212,161,240,194,212,227,239,118,100,118,32,34,32,34,100,119,100, +48,52,63,78,102,52,91,78,30,134,123,134,18,170,129,162,76,166,77,32, +34,188,17,232,58,190,67,228,82,186,97,220,108,180,121,206,170,14,191,42, +130,56,243,56,220,144,220,94,148,94,148,144,221,144,154,176,119,232,206,176, +239,224,182,144,182,232,176,240,155,241,106,102,106,28,34,28,34,102,107,102, +46,52,57,82,96,52,83,86,26,134,113,134,18,170,115,164,70,166,71,28, +34,186,21,236,56,188,61,228,80,184,89,224,104,180,121,218,198,40,229,72, +180,14,132,68,219,62,122,100,243,100,178,76,150,120,123,148,240,152,208,128, +191,100,186,130,164,150,139,168,208,154,178,180,141,200,228,180,184,212,133,239, +118,102,118,32,34,32,34,102,119,102,48,56,63,82,102,56,91,82,30,134, +123,134,18,168,129,162,74,164,75,32,34,190,19,228,56,190,67,224,84,184, +99,218,112,180,129,214,168,14,193,40,136,52,237,52,152,70,171,96,130,110, +245,110,216,68,199,110,150,242,150,144,218,144,219,242,150,182,219,182,148,222, +219,223,56,22,24,30,24,100,116,100,116,30,83,30,58,66,25,66,82,64, +117,64,28,120,28,230,55,208,70,118,70,230,101,210,42,132,59,148,40,166, +57,184,82,134,99,152,84,168,101,186,110,118,112,180,114,214,120,226,124,226, +132,220,137,206,168,22,154,70,133,110,196,16,210,64,241,112,142,114,218,114, +214,212,210,226,200,232,187,232,170,114,166,174,145,237,68,24,34,32,34,102, +122,102,122,32,91,32,68,66,35,66,90,66,123,66,48,134,65,148,46,168, +63,180,32,118,32,234,59,210,78,118,78,230,107,210,92,134,107,152,92,172, +109,186,118,118,118,166,120,208,126,228,134,230,138,224,143,214,154,242,154,64, +226,64,227,238,154,218,227,218,154,134,227,134,190,218,191,11,54,18,20,32, +20,100,112,100,112,28,79,28,56,64,21,64,78,64,113,64,40,130,55,146, +40,166,55,182,28,118,28,230,57,206,70,118,70,230,99,210,82,134,95,152, +82,170,97,186,110,118,108,174,114,212,120,232,139,210,134,24,233,24,136,70, +214,70,211,118,132,118,243,118,158,118,173,24,152,240,152,154,218,154,219,240, +152,218,219,219,60,20,30,28,30,98,112,98,112,28,81,28,62,62,31,62, +82,62,113,62,30,116,30,228,57,208,46,132,59,150,44,166,57,182,70,118, +70,234,99,210,88,136,99,154,84,172,97,188,110,116,110,174,112,210,116,230, +124,232,135,208,218,82,218,24,146,24,146,82,219,82,146,54,219,54,170,90, +189,108,134,140,134,114,226,114,227,142,124,162,237,162,182,126,152,190,186,210, +227,238,140,236,172,222,196,196,211,163,54,22,24,32,24,102,108,102,108,30, +81,30,52,66,25,66,78,66,109,66,26,120,26,234,53,210,40,132,55,152, +40,170,53,186,66,120,66,236,93,214,80,136,93,156,80,176,95,192,106,116, +104,176,106,214,112,234,118,234,131,210,224,20,174,32,127,34,136,54,151,78, +170,46,183,70,222,46,199,82,204,122,223,156,204,96,134,148,215,140,172,80, +134,112,181,112,126,180,229,180,180,156,164,210,139,240,226,238,192,204,181,181, +100,98,100,42,40,42,40,98,101,98,40,62,101,62,40,80,101,80,68,18, +63,42,112,162,112,118,32,118,32,162,113,162,32,140,113,140,72,162,73,118, +10,186,127,186,54,186,48,212,36,228,19,238,92,244,93,186,160,20,160,130, +146,190,115,232,126,86,206,86,202,220,206,232,224,232,237,211,116,100,116,36, +38,36,38,100,117,100,38,56,117,56,38,78,117,78,72,10,59,36,126,164, +126,122,32,122,32,164,127,164,32,142,127,142,80,164,81,122,12,186,149,186, +60,186,60,200,50,220,29,242,104,244,105,186,142,36,235,36,142,134,243,134, +188,244,189,37,106,100,106,42,44,42,44,100,107,100,44,60,107,60,44,80, +107,80,72,16,65,42,116,162,116,120,34,120,34,162,117,162,34,142,117,142, +74,162,75,120,14,188,131,188,56,188,50,218,38,230,27,240,96,242,97,188, +124,54,233,54,178,122,179,14,130,114,154,88,179,54,236,114,198,84,179,54, +216,198,216,136,146,136,146,198,217,198,146,168,217,168,122,230,245,231,44,80, +80,74,98,38,100,38,101,216,212,216,212,196,196,196,196,216,212,216,204,196, +196,216,212,206,198,204,206,216,208,200,196,200,208,212,210,198,206,198,200,198, +200,212,206,202,204,212,198,212,199,199,52,94,56,70,74,52,98,44,122,48, +142,64,148,86,142,110,126,130,104,142,82,156,62,170,52,186,46,200,46,210, +155,210,218,216,218,198,202,198,202,216,218,216,208,198,204,214,214,204,206,204, +212,212,214,200,204,200,204,210,208,214,214,212,216,206,216,202,204,202,206,212, +208,206,212,212,210,202,204,200,217,201,52,86,54,66,66,52,78,46,96,42, +116,44,130,52,140,62,144,76,142,90,136,106,124,114,108,120,90,120,88,122, +118,124,136,134,150,150,152,166,146,186,136,200,120,208,102,212,88,212,70,208, +56,198,48,186,44,176,45,166,218,216,218,196,202,196,202,216,218,216,214,196, +210,216,208,196,206,216,205,197,154,166,36,166,122,44,123,216,222,216,222,196, +206,196,206,216,222,216,218,196,214,216,212,196,208,216,209,197,146,44,66,44, +52,124,70,112,88,108,104,108,122,112,136,120,144,136,148,152,148,168,144,184, +134,200,118,208,96,212,76,210,60,204,52,192,48,182,45,170,202,196,218,196, +218,218,202,218,202,196,218,200,202,206,218,208,202,212,219,215,146,78,142,66, +134,52,120,44,106,42,92,44,80,48,68,56,60,66,54,80,50,94,46,112, +44,130,46,148,48,164,54,180,58,188,66,200,74,208,86,212,98,212,112,212, +126,208,138,198,146,186,148,174,150,160,148,146,144,134,138,124,128,116,116,112, +104,110,92,110,78,114,70,120,62,130,56,138,52,144,48,152,47,158,218,216, +218,196,202,196,202,216,218,216,216,196,214,216,210,196,208,216,206,196,204,216, +205,197,40,46,144,46,128,76,116,92,102,116,92,138,86,156,80,172,76,186, +74,194,72,208,73,216,216,216,216,196,200,196,200,216,216,216,212,196,210,216, +208,196,206,216,204,196,203,217,96,120,118,118,132,110,138,98,140,88,140,78, +138,64,134,58,128,52,122,50,116,46,106,44,96,44,84,44,78,46,70,50, +62,56,58,60,56,66,54,68,52,80,52,86,54,96,60,104,66,112,74,116, +84,120,94,120,110,124,122,128,132,132,138,138,146,148,148,158,148,174,144,186, +140,194,134,200,122,208,112,210,102,212,92,214,80,212,70,206,60,202,54,192, +48,184,46,174,46,160,50,148,54,140,58,134,66,130,76,124,84,122,95,120, +218,216,218,196,200,196,200,216,219,216,202,200,212,200,212,210,206,212,204,202, +208,202,208,210,202,208,212,206,214,212,216,200,202,214,202,198,213,199,48,178, +54,196,64,206,76,210,94,212,112,208,126,198,140,182,146,160,150,132,148,100, +142,76,134,62,124,52,108,44,90,44,72,48,56,58,48,78,44,92,46,106, +50,120,58,132,68,140,82,146,100,146,116,142,128,132,138,116,142,102,145,88, +202,196,218,196,218,216,202,216,202,196,218,200,202,204,218,206,202,210,218,212, +203,215,22,78,52,74,66,60,78,40,79,218,200,144,200,104,194,72,184,52, +168,44,150,44,134,54,124,72,120,94,118,114,118,136,118,154,122,174,124,188, +134,202,142,208,152,214,166,212,186,200,196,180,200,160,201,144,232,216,232,196, +216,196,216,216,232,216,228,196,224,216,220,196,219,217,22,78,52,72,64,62, +76,38,77,216,120,78,146,72,164,62,176,40,177,216,234,216,218,216,218,196, +234,196,234,216,230,196,228,216,226,196,222,216,220,196,219,217,18,78,42,74, +58,66,66,54,74,38,75,216,236,216,236,196,220,196,220,216,236,216,230,196, +228,216,224,196,222,216,221,198,198,212,102,212,102,194,114,178,136,158,158,144, +180,132,198,114,206,90,202,70,188,52,168,44,146,46,128,52,116,66,110,78, +111,97,238,216,238,196,220,196,220,216,238,216,232,196,230,216,226,196,224,216, +221,196,98,166,104,188,114,200,128,210,144,214,166,212,188,204,202,188,206,168, +202,148,194,136,180,130,168,124,140,124,168,122,190,108,200,92,200,72,192,56, +178,48,158,44,140,44,124,52,114,64,106,74,107,88,18,78,42,74,60,64, +74,38,75,217,236,216,236,198,220,198,220,216,237,216,230,198,232,212,226,212, +224,208,228,204,224,202,222,210,232,204,228,200,233,200,182,216,182,44,96,164, +215,164,72,216,72,38,58,66,38,74,19,79,236,216,236,196,220,196,220,216, +236,216,230,196,230,216,226,196,224,216,221,196,202,44,120,44,108,126,126,114, +146,106,166,108,188,116,200,132,204,150,204,172,198,192,182,204,164,212,146,212, +126,208,112,196,104,182,103,170,72,216,72,38,64,56,48,70,30,76,19,77, +236,216,236,196,220,196,220,216,236,216,232,196,228,216,224,196,222,216,223,196, +18,78,52,72,62,60,74,40,75,216,202,78,196,60,184,48,166,42,146,42, +126,54,112,72,108,90,102,116,102,142,106,164,110,182,124,200,144,210,166,212, +190,202,202,184,206,160,202,132,186,116,162,110,140,112,122,124,110,142,105,153, +236,216,236,196,220,196,220,216,236,216,230,198,226,216,222,198,223,216,18,78, +48,72,62,58,74,38,75,218,96,46,204,46,180,82,160,116,144,152,136,182, +130,204,131,219,236,216,236,196,220,196,220,216,236,216,232,196,230,216,226,196, +224,216,222,196,223,216,154,122,176,118,194,100,198,82,194,62,184,50,166,44, +148,44,132,46,118,58,108,74,110,90,116,104,128,114,140,120,162,122,188,130, +200,146,206,164,202,184,192,200,176,210,156,212,136,210,116,200,106,184,102,164, +108,142,124,126,136,122,153,120,72,216,72,38,56,66,40,72,19,77,238,216, +238,196,220,196,220,216,238,216,232,196,230,216,226,196,224,216,221,196,104,178, +104,184,108,196,118,204,132,212,154,214,174,206,186,196,198,176,204,160,206,144, +206,124,204,96,196,72,178,50,160,44,138,44,118,52,106,68,102,86,102,104, +106,120,116,134,130,142,146,146,166,144,182,134,194,120,198,104,198,88,199,80, +72,216,72,38,60,62,48,70,32,74,19,75,236,218,236,196,218,196,218,216, +236,216,230,196,228,216,224,196,222,216,219,196,202,144,202,104,198,78,190,60, +180,48,176,46,172,42,158,42,140,48,130,62,126,78,122,94,120,106,120,134, +120,156,124,174,128,188,136,202,142,210,152,212,166,212,182,206,192,192,198,176, +200,160,203,142,110,212,26,212,26,194,36,176,52,158,66,146,82,136,90,126, +100,116,106,100,106,84,102,68,96,56,82,48,66,44,52,48,38,60,34,72, +30,84,31,97,78,78,104,76,122,64,134,38,135,216,206,8,222,34,234,60, +242,80,246,104,246,122,246,144,244,166,238,188,230,204,222,222,214,234,207,246, +50,10,32,38,20,66,12,90,10,108,10,132,12,158,16,178,22,198,30,216, +40,232,51,247,206,10,222,34,232,56,244,88,248,108,248,140,244,164,238,186, +228,210,220,226,207,246,50,10,34,34,22,58,16,78,12,92,12,118,10,146, +14,174,24,198,32,218,51,246,82,94,82,88,86,68,96,56,110,48,124,44, +144,46,162,52,172,62,178,72,178,78,178,98,172,114,162,126,146,138,126,148, +108,160,92,172,84,180,78,192,78,200,78,212,187,213,206,10,224,36,234,60, +242,84,246,108,248,118,248,140,244,166,236,192,224,218,207,246,50,10,30,42, +18,68,12,92,10,104,10,126,10,146,12,168,20,194,30,212,51,246,80,86, +80,78,88,62,102,48,118,44,140,44,160,50,172,62,174,76,172,94,160,112, +146,116,114,120,130,122,164,130,178,146,180,156,180,178,166,200,152,208,132,214, +110,210,90,202,80,190,76,172,77,165,206,10,228,46,242,82,246,108,246,148, +240,180,230,206,218,230,207,246,50,10,30,40,16,74,10,104,10,126,10,152, +16,180,26,206,38,228,49,246,180,166,60,166,148,40,149,217,206,10,230,52, +244,92,248,114,248,138,242,172,230,206,220,226,207,246,50,10,30,40,14,82, +8,118,8,132,10,160,18,186,28,208,40,232,51,246,176,44,96,44,80,128, +96,116,118,106,134,106,160,114,176,132,180,154,178,176,168,194,148,208,124,212, +102,206,86,196,78,180,77,169,206,10,220,32,234,56,242,84,246,108,246,130, +244,162,238,188,224,216,214,232,207,246,50,10,30,38,18,66,10,94,10,106, +10,132,12,166,18,190,28,212,40,230,51,246,176,78,176,72,168,58,154,48, +138,42,122,44,104,52,92,62,82,84,76,104,76,122,76,146,78,166,88,188, +96,200,112,210,132,212,156,208,170,196,178,180,180,156,174,132,160,118,138,110, +118,112,100,120,88,136,82,150,79,161,206,10,224,38,236,60,242,86,246,102, +246,152,242,174,232,200,218,224,207,246,50,10,32,38,20,62,12,88,10,108, +8,116,8,142,12,168,20,190,28,210,38,228,51,246,70,46,180,46,148,94, +130,126,116,156,108,184,104,204,105,217,172,72,172,86,166,104,154,116,138,120, +126,120,104,126,88,134,80,146,78,156,78,174,84,192,96,204,114,212,132,212, +154,208,170,198,178,186,180,174,180,156,172,142,162,132,152,126,144,122,134,120, +110,118,96,112,86,98,82,88,82,76,90,58,100,50,118,44,136,44,152,48, +164,56,170,64,173,72,206,10,226,42,240,74,246,104,248,110,248,146,242,170, +234,198,222,220,207,246,50,10,34,32,24,52,16,76,10,100,10,118,10,140, +12,166,18,188,28,212,40,230,51,247,206,10,222,36,234,58,242,84,246,100, +246,110,246,144,242,172,236,194,224,220,207,246,50,10,32,36,20,60,14,82, +10,104,8,116,8,144,12,168,20,190,30,212,49,246,78,176,78,182,84,192, +92,202,102,210,114,212,132,212,146,208,162,194,174,174,178,158,180,136,180,112, +178,94,172,74,162,56,146,48,136,44,116,44,94,52,82,64,78,76,76,84, +76,106,82,122,92,134,104,142,116,146,134,146,152,140,164,126,174,108,177,91, +206,244,226,212,240,182,246,150,246,114,242,82,232,54,218,30,207,8,50,10, +34,36,22,60,14,86,10,114,10,146,16,178,24,204,38,226,51,246,176,212, +196,208,208,186,216,156,216,112,212,78,202,58,188,44,166,42,148,56,138,78, +136,98,134,118,134,144,136,170,142,190,152,204,166,212,177,212,92,216,92,38, +84,58,72,70,58,74,39,75,206,244,228,210,240,174,246,142,246,104,238,72, +224,40,207,10,50,10,30,40,16,76,10,108,8,134,10,160,18,186,28,208, +49,244,90,216,90,38,82,58,66,72,50,76,37,78,188,216,188,38,182,56, +170,70,156,74,142,76,135,77,48,244,28,210,14,172,8,132,12,98,20,66, +32,38,51,10,206,10,228,48,242,84,248,128,242,170,232,204,207,246,32,78, +68,68,76,58,86,40,87,216,118,94,124,72,132,56,148,48,170,44,190,50, +204,66,210,90,206,110,192,126,178,138,156,150,136,166,122,180,118,194,116,210, +215,211,48,10,26,50,12,90,10,134,16,182,26,206,49,244,206,244,228,212, +240,176,248,136,246,98,234,60,218,26,207,10,84,216,84,38,76,66,60,76, +33,78,118,88,122,66,136,52,156,44,178,46,200,54,210,68,212,88,202,108, +184,120,154,122,186,124,208,138,216,156,216,180,204,200,182,210,154,214,132,208, +118,194,114,180,113,167,206,8,222,34,236,64,244,96,248,124,246,154,240,176, +232,198,222,220,207,244,50,10,30,40,18,70,10,102,8,128,10,154,16,178, +26,206,34,224,51,246,84,216,84,38,74,60,64,70,48,76,31,78,226,166, +106,166,194,44,195,217,206,10,222,36,236,66,242,90,246,124,246,154,238,184, +226,210,214,232,207,246,204,44,134,44,120,126,134,114,158,106,186,110,206,124, +216,146,214,172,202,196,186,208,162,212,142,208,124,198,116,184,115,170,84,216, +84,38,76,58,62,70,40,76,35,76,50,10,36,34,26,52,18,68,12,86, +8,110,8,138,12,162,16,182,24,204,32,218,42,232,51,247,206,10,222,34, +236,64,244,100,248,134,242,174,230,204,216,228,207,246,50,244,28,210,16,176, +10,148,8,112,16,80,26,48,36,28,51,10,84,216,84,40,74,64,58,74, +39,76,214,78,208,60,196,50,180,44,156,44,136,56,126,72,118,94,116,112, +114,138,114,156,122,180,128,196,144,206,158,212,178,212,200,202,214,186,218,164, +212,132,198,116,178,108,152,110,136,122,124,144,120,156,119,167,50,10,26,48, +14,82,8,120,10,156,18,184,28,212,40,234,51,246,206,244,226,214,240,178, +248,136,246,100,238,68,220,34,207,10,84,216,84,38,70,66,54,74,31,78, +110,46,208,46,178,94,160,136,148,172,140,202,141,217,206,244,228,210,242,172, +248,126,244,88,234,58,220,30,207,10,50,10,26,48,14,82,10,114,10,152, +16,182,30,212,51,246,84,216,84,38,70,66,58,72,31,78,166,120,174,120, +194,114,206,96,210,80,206,60,192,48,170,42,148,46,128,56,120,76,124,94, +134,110,148,116,166,120,196,126,210,142,218,162,216,182,206,200,184,210,156,212, +132,204,118,188,114,162,120,142,130,130,146,124,167,121,50,10,26,48,16,82, +10,120,10,158,18,188,30,218,51,246,206,246,226,210,242,172,246,136,246,98, +236,66,224,38,207,10,84,216,84,38,72,60,58,76,40,80,31,80,114,176, +120,190,132,206,152,212,176,212,192,204,202,192,210,176,214,162,218,140,218,116, +216,90,208,72,196,54,176,46,160,44,142,48,126,58,116,74,114,94,116,116, +126,132,142,142,164,146,180,142,196,134,206,120,210,110,212,92,211,77,50,10, +30,40,18,66,12,92,8,114,8,142,12,164,20,190,30,214,49,246,206,10, +220,30,232,56,242,84,246,108,246,142,242,168,236,194,224,218,205,246,124,210, +50,210,50,192,56,176,64,166,80,148,96,136,110,120,114,104,116,84,114,64, +104,50,92,44,74,46,60,56,52,72,50,84,49,96,136,104,138,80,142,64, +150,52,162,44,178,42,192,48,200,60,206,78,210,100,212,130,210,154,208,172, +204,190,196,206,182,212,168,214,156,208,144,196,136,174,134,148,134,128,134,110, +137,101,224,50,212,38,194,24,168,12,144,6,126,4,100,8,74,18,56,28, +42,40,30,52,20,68,12,88,8,104,4,120,6,138,8,156,12,170,20,186, +26,198,34,208,46,220,60,230,72,236,88,242,102,246,118,250,134,250,154,246, +172,242,188,234,208,222,220,210,234,190,242,172,246,156,250,140,250,128,248,112, +244,94,240,78,234,66,228,58,225,50,132,216,132,38,124,58,112,70,81,79, +224,50,212,38,194,24,168,12,144,6,126,4,100,8,74,18,56,28,42,40, +30,52,20,68,12,88,8,104,4,120,6,138,8,156,12,170,20,186,26,198, +34,208,46,220,60,230,72,236,88,242,102,246,118,250,134,250,154,246,172,242, +188,234,208,222,220,210,234,190,242,172,246,156,250,140,250,128,248,112,244,94, +240,78,234,66,228,58,225,50,219,60,82,94,82,88,90,68,104,52,122,46, +144,46,162,54,174,66,180,80,178,98,172,118,154,132,134,144,116,156,98,166, +88,180,78,192,76,202,76,210,187,211,224,50,212,38,194,24,168,12,144,6, +126,4,100,8,74,18,56,28,42,40,30,52,20,68,12,88,8,104,4,120, +6,138,8,156,12,170,20,186,26,198,34,208,46,220,60,230,72,236,88,242, +102,246,118,250,134,250,154,246,172,242,188,234,208,222,220,210,234,190,242,172, +246,156,250,140,250,128,248,112,244,94,240,78,234,66,228,58,225,50,80,88, +80,84,84,68,94,54,110,46,132,44,150,46,164,54,172,66,174,76,174,92, +168,102,160,112,150,116,140,118,124,120,116,122,140,122,158,128,170,136,178,146, +180,162,178,182,168,198,152,208,134,212,114,212,96,206,84,196,76,180,74,172, +75,165,181,166,224,50,212,38,194,24,168,12,144,6,126,4,100,8,74,18, +56,28,42,40,30,52,20,68,12,88,8,104,4,120,6,138,8,156,12,170, +20,186,26,198,34,208,46,220,60,230,72,236,88,242,102,246,118,250,134,250, +154,246,172,242,188,234,208,222,220,210,234,190,242,172,246,156,250,140,250,128, +248,112,244,94,240,78,234,66,228,58,225,50,180,166,60,166,148,40,149,217, +224,50,212,38,194,24,168,12,144,6,126,4,100,8,74,18,56,28,42,40, +30,52,20,68,12,88,8,104,4,120,6,138,8,156,12,170,20,186,26,198, +34,208,46,220,60,230,72,236,88,242,102,246,118,250,134,250,154,246,172,242, +188,234,208,222,220,210,234,190,242,172,246,156,250,140,250,128,248,112,244,94, +240,78,234,66,228,58,225,50,178,44,96,44,82,124,94,116,108,110,122,106, +138,108,156,112,166,120,172,132,180,146,180,164,174,184,164,198,152,206,138,210, +124,212,112,210,98,204,86,196,78,182,76,174,77,169,224,50,212,38,194,24, +168,12,144,6,126,4,100,8,74,18,56,28,42,40,30,52,20,68,12,88, +8,104,4,120,6,138,8,156,12,170,20,186,26,198,34,208,46,220,60,230, +72,236,88,242,102,246,118,250,134,250,154,246,172,242,188,234,208,222,220,210, +234,190,242,172,246,156,250,140,250,128,248,112,244,94,240,78,234,66,228,58, +225,50,176,78,176,74,168,58,152,46,136,42,122,44,110,48,96,56,88,68, +82,82,78,98,78,110,76,128,76,142,76,156,78,168,82,180,88,192,96,200, +110,208,124,212,142,212,156,206,168,198,174,188,178,178,180,164,180,148,176,134, +166,122,156,114,144,112,136,110,126,110,112,112,100,120,90,134,84,146,82,158, +80,166,81,173,224,50,212,38,194,24,168,12,144,6,126,4,100,8,74,18, +56,28,42,40,30,52,20,68,12,88,8,104,4,120,6,138,8,156,12,170, +20,186,26,198,34,208,46,220,60,230,72,236,88,242,102,246,118,250,134,250, +154,246,172,242,188,234,208,222,220,210,234,190,242,172,246,156,250,140,250,128, +248,112,244,94,240,78,234,66,228,58,225,50,70,46,178,46,160,72,148,90, +138,108,132,126,124,140,116,156,112,170,110,182,106,194,104,204,105,217,224,50, +212,38,194,24,168,12,144,6,126,4,100,8,74,18,56,28,42,40,30,52, +20,68,12,88,8,104,4,120,6,138,8,156,12,170,20,186,26,198,34,208, +46,220,60,230,72,236,88,242,102,246,118,250,134,250,154,246,172,242,188,234, +208,222,220,210,234,190,242,172,246,156,250,140,250,128,248,112,244,94,240,78, +234,66,228,58,225,50,126,120,136,120,156,114,164,106,170,92,174,78,170,66, +162,56,154,48,142,44,128,42,114,44,100,50,90,60,84,72,82,82,84,96, +90,104,98,112,104,116,114,118,120,120,126,120,142,120,158,128,172,140,178,152, +180,164,178,178,174,190,164,202,152,208,140,210,124,212,106,210,94,204,86,194, +78,184,76,168,76,158,82,140,94,132,102,124,114,122,123,121,224,50,212,38, +194,24,168,12,144,6,126,4,100,8,74,18,56,28,42,40,30,52,20,68, +12,88,8,104,4,120,6,138,8,156,12,170,20,186,26,198,34,208,46,220, +60,230,72,236,88,242,102,246,118,250,134,250,154,246,172,242,188,234,208,222, +220,210,234,190,242,172,246,156,250,140,250,128,248,112,244,94,240,78,234,66, +228,58,225,50,78,176,78,182,84,192,90,202,98,208,108,210,120,212,134,212, +150,206,162,194,172,176,178,152,180,132,180,110,176,92,172,76,166,62,158,52, +148,46,136,44,120,42,106,46,94,52,84,62,78,74,76,90,76,104,80,120, +88,134,100,142,116,146,132,146,146,142,158,134,166,120,172,108,174,92,175,85, +224,50,212,38,194,24,168,12,144,6,126,4,100,8,74,18,56,28,42,40, +30,52,20,68,12,88,8,104,4,120,6,138,8,156,12,170,20,186,26,198, +34,208,46,220,60,230,72,236,88,242,102,246,118,250,134,250,154,246,172,242, +188,234,208,222,220,210,234,190,242,172,246,156,250,140,250,128,248,112,244,94, +240,78,234,66,228,58,225,50,90,216,90,38,78,64,58,76,37,78,214,122, +212,94,208,76,202,60,194,50,180,44,170,42,156,46,146,56,140,68,136,78, +134,90,132,104,132,122,132,138,132,156,136,174,138,188,146,202,156,210,166,212, +178,214,190,208,202,196,210,176,212,156,214,138,215,123,42,14,26,38,18,56, +14,76,10,94,8,114,8,134,10,156,14,182,20,202,26,218,34,232,41,244, +212,14,224,32,232,50,238,64,242,80,246,100,248,116,248,134,248,148,244,164, +240,182,236,202,228,218,220,232,215,244,38,128,213,129,42,14,26,38,18,56, +14,76,10,94,8,114,8,134,10,156,14,182,20,202,26,218,34,232,41,244, +212,14,224,32,232,50,238,64,242,80,246,100,248,116,248,134,248,148,244,164, +240,182,236,202,228,218,220,232,215,244,60,68,197,68,38,186,223,187,42,14, +26,38,18,56,14,76,10,94,8,114,8,134,10,156,14,182,20,202,26,218, +34,232,41,244,212,14,224,32,232,50,238,64,242,80,246,100,248,116,248,134, +248,148,244,164,240,182,236,202,228,218,220,232,215,244,52,58,201,58,60,128, +193,128,38,200,219,201,42,14,26,38,18,56,14,76,10,94,8,114,8,134, +10,156,14,182,20,202,26,218,34,232,41,244,212,14,224,32,232,50,238,64, +242,80,246,100,248,116,248,134,248,148,244,164,240,182,236,202,228,218,220,232, +215,244,52,214,52,52,206,52,207,214,52,188,207,188,108,52,108,110,104,130, +96,142,84,152,75,158,144,52,144,138,146,148,156,154,170,154,178,146,185,125, +42,14,26,38,18,56,14,76,10,94,8,114,8,134,10,156,14,182,20,202, +26,218,34,232,41,244,212,14,224,32,232,50,238,64,242,80,246,100,248,116, +248,134,248,148,244,164,240,182,236,202,228,218,220,232,215,244,46,56,197,56, +44,204,209,204,58,120,164,120,163,204,124,56,85,205,42,14,26,38,18,56, +14,76,10,94,8,114,8,134,10,156,14,182,20,202,26,218,34,232,41,244, +212,14,224,32,232,50,238,64,242,80,246,100,248,116,248,134,248,148,244,164, +240,182,236,202,228,218,220,232,215,244,42,88,209,88,126,88,127,36,96,126, +72,174,47,210,154,126,178,172,213,207,42,14,26,38,18,56,14,76,10,94, +8,114,8,134,10,156,14,182,20,202,26,218,34,232,41,244,212,14,224,32, +232,50,238,64,242,80,246,100,248,116,248,134,248,148,244,164,240,182,236,202, +228,218,220,232,215,244,110,36,110,188,112,200,122,208,174,208,188,202,198,186, +201,168,36,132,213,101,42,14,26,38,18,56,14,76,10,94,8,114,8,134, +10,156,14,182,20,202,26,218,34,232,41,244,212,14,224,32,232,50,238,64, +242,80,246,100,248,116,248,134,248,148,244,164,240,182,236,202,228,218,220,232, +215,244,102,56,92,122,76,160,62,184,47,202,138,52,156,52,158,94,166,134, +178,164,192,184,207,203,42,14,26,38,18,56,14,76,10,94,8,114,8,134, +10,156,14,182,20,202,26,218,34,232,41,244,212,14,224,32,232,50,238,64, +242,80,246,100,248,116,248,134,248,148,244,164,240,182,236,202,228,218,220,232, +215,244,58,96,160,96,150,184,152,198,164,208,194,208,208,194,213,176,118,30, +118,98,110,126,100,156,80,184,47,213,42,14,26,38,18,56,14,76,10,94, +8,114,8,134,10,156,14,182,20,202,26,218,34,232,41,244,212,14,224,32, +232,50,238,64,242,80,246,100,248,116,248,134,248,148,244,164,240,182,236,202, +228,218,220,232,215,244,30,114,219,114,124,232,125,25,128,42,129,217,96,42, +97,216,160,42,161,217,64,42,65,216,126,216,127,42,190,42,191,217,38,42, +39,216,82,42,148,216,217,43,60,42,128,216,195,43,40,42,106,216,173,42, +216,42,217,217,16,42,82,216,149,42,184,42,185,216,240,42,241,217,8,42, +76,216,143,42,166,42,167,216,204,42,205,216,242,42,243,217,44,42,45,216, +90,42,211,216,206,42,87,217,70,42,191,216,66,216,185,43,50,42,169,216, +44,216,165,42,212,42,213,217,20,42,141,216,136,42,17,216,182,216,183,42, +238,42,239,217,58,106,112,106,169,96,118,66,108,128,104,170,117,224,158,120, +140,168,118,198,92,220,70,228,56,226,50,216,50,200,58,178,78,156,96,146, +122,136,148,134,174,140,194,154,204,174,204,200,188,222,157,243,36,72,68,74, +100,72,132,66,177,58,112,20,102,88,100,116,100,148,104,182,113,216,160,86, +148,132,134,162,118,182,94,206,68,222,54,224,42,222,34,214,32,196,36,178, +48,156,66,136,86,124,110,114,132,108,152,104,174,108,194,116,208,128,220,144, +224,162,222,180,216,198,202,214,182,226,161,239,46,96,48,130,52,152,60,182, +70,202,80,214,88,218,92,218,98,218,104,214,127,192,172,106,194,138,211,173, +26,52,28,92,34,130,40,162,52,188,64,204,74,214,84,214,94,210,104,200, +125,178,184,72,210,114,233,159,114,62,144,74,171,80,80,138,84,138,92,136, +116,128,136,120,150,120,164,124,170,132,176,146,176,164,174,180,166,200,154,220, +142,232,127,245,110,16,146,30,181,38,66,110,72,108,86,104,102,98,120,92, +136,88,152,86,168,88,178,96,186,106,188,118,190,134,188,154,184,176,174,196, +160,218,144,234,131,249,112,68,138,80,163,90,66,134,108,130,154,122,118,162, +92,194,74,216,57,238,206,234,186,238,174,238,164,238,156,234,152,228,148,216, +146,202,144,186,144,180,142,174,138,172,132,172,120,172,109,175,106,20,136,34, +167,46,52,104,160,86,98,158,41,232,224,226,190,230,172,230,162,226,156,216, +154,208,146,174,144,164,140,158,132,154,124,154,116,154,104,156,97,161,54,118, +94,118,137,110,102,72,100,126,100,184,100,224,100,236,94,236,80,234,66,228, +56,220,52,210,50,204,52,198,60,188,76,176,98,164,118,158,140,152,156,152, +172,156,184,162,190,170,194,180,192,192,186,206,176,216,160,224,148,228,139,230, +170,100,209,125,30,88,68,88,104,82,137,74,90,28,90,92,90,130,90,154, +90,180,92,208,92,224,90,230,84,232,76,230,64,228,46,218,36,204,34,196, +36,186,42,176,52,166,66,158,88,146,106,136,120,132,132,128,146,126,160,126, +176,126,190,132,202,140,208,148,210,160,208,174,202,192,194,200,180,208,160,216, +146,220,133,222,176,58,227,87,184,56,216,88,243,126,20,104,74,96,108,92, +136,92,146,94,152,98,156,102,156,112,152,144,144,178,138,196,130,206,118,214, +108,218,83,218,96,30,84,100,54,170,23,213,212,16,237,40,190,38,215,64, +162,62,188,92,213,130,26,110,30,112,46,106,68,102,96,96,118,92,138,92, +150,98,154,110,152,132,142,188,134,204,126,212,116,218,110,218,85,218,98,30, +82,112,60,162,27,221,74,68,122,58,175,40,62,118,108,114,168,102,207,90, +106,16,142,94,197,178,148,236,116,236,90,230,70,222,56,206,52,192,54,180, +60,170,76,162,96,156,120,156,138,158,158,162,174,168,197,179,198,4,227,34, +168,20,199,52,144,42,108,56,78,64,41,70,174,90,118,110,80,116,33,120, +78,16,92,52,124,112,172,176,140,164,104,158,78,156,56,160,40,170,32,180, +30,192,34,206,46,220,66,230,86,234,125,239,158,22,98,110,90,120,86,130, +86,134,92,144,110,168,126,190,163,247,124,20,58,118,54,126,52,130,52,134, +54,138,56,142,135,246,178,44,205,68,152,70,181,95,44,30,44,34,44,42, +40,52,36,82,32,120,32,142,32,158,36,178,42,196,46,210,54,228,71,164, +108,96,140,100,170,98,198,94,229,88,176,28,180,60,180,82,182,108,180,140, +178,168,170,192,154,216,135,239,26,26,26,34,24,44,20,68,16,96,14,116, +14,138,16,160,20,184,24,202,30,214,38,230,46,188,57,160,90,96,126,98, +150,96,176,94,211,86,154,26,156,40,158,56,158,78,160,98,160,132,156,164, +148,190,132,218,113,236,194,26,221,50,216,4,245,29,72,44,98,52,118,54, +142,54,168,50,183,48,46,178,62,194,80,204,102,212,128,212,154,212,182,210, +213,207,48,46,78,52,108,54,136,52,157,48,212,44,239,66,186,70,215,92, +16,178,32,194,54,206,80,212,112,212,152,210,189,207,54,94,84,92,112,88, +148,82,191,68,118,24,130,56,156,100,178,134,202,168,164,150,134,144,108,142, +84,144,68,150,60,160,54,172,54,186,60,202,74,214,92,222,114,226,155,229, +198,6,227,28,174,30,203,54,28,94,56,94,84,90,112,86,138,80,175,70, +92,26,106,58,122,90,142,116,156,138,178,168,148,154,124,144,98,140,78,142, +60,144,44,152,34,164,30,178,34,192,42,206,56,218,76,224,94,226,131,231, +64,20,66,28,66,36,64,76,66,118,66,184,68,204,76,218,88,228,110,232, +134,232,156,222,199,195,176,30,205,52,152,56,181,78,58,22,58,188,62,204, +70,218,82,228,98,232,116,232,136,228,154,222,166,212,195,191,26,70,124,64, +235,64,142,8,142,100,142,146,136,166,126,176,112,182,98,180,88,168,82,148, +82,132,86,118,98,108,112,100,126,100,138,106,144,118,150,132,150,154,148,178, +140,200,132,212,99,247,212,14,237,34,194,30,219,52,20,80,122,74,231,74, +138,18,138,154,130,178,116,190,96,190,84,180,78,164,78,142,84,126,94,116, +108,112,120,110,130,114,140,124,144,136,146,150,146,164,144,182,140,198,134,214, +126,224,91,255,16,112,130,100,243,96,82,46,82,184,88,204,100,214,122,220, +168,220,207,214,178,28,178,124,174,146,168,160,162,166,154,166,143,165,196,46, +225,68,220,20,249,44,6,116,120,102,229,98,68,46,68,136,70,180,72,200, +78,210,88,216,98,220,193,220,158,30,158,104,152,156,146,166,140,168,132,168, +123,169,74,34,101,78,36,142,96,122,140,112,184,102,228,102,180,114,150,132, +128,152,120,170,116,188,120,204,128,218,140,226,152,230,195,238,188,26,127,115, +222,6,247,30,196,28,221,54,50,34,77,78,10,140,96,116,140,106,172,102, +204,102,160,112,134,128,112,144,98,162,92,178,92,192,96,206,104,218,124,228, +171,238,162,26,105,115,36,80,76,80,108,78,153,68,110,20,82,128,33,232, +146,114,184,112,219,114,130,216,180,224,233,223,26,80,84,82,143,72,98,22, +72,128,21,234,134,118,174,114,207,118,116,218,164,224,219,222,216,28,243,50, +190,54,217,77,30,74,82,76,169,62,96,18,74,176,102,150,128,132,156,126, +186,130,208,144,218,164,216,186,202,210,180,224,146,232,115,237,212,14,241,40, +190,34,217,60,14,78,76,80,155,66,86,18,72,106,66,178,90,154,118,134, +144,124,174,126,200,140,212,162,210,188,194,210,174,224,150,232,130,236,109,237, +42,134,98,112,138,100,162,98,188,102,206,118,216,136,216,154,210,176,198,192, +182,204,164,212,125,225,18,104,90,76,128,66,158,60,192,64,216,74,228,90, +238,104,240,124,238,146,232,164,214,184,190,200,164,208,127,221,220,4,249,26, +194,28,221,48,14,104,90,76,124,66,156,64,186,70,208,82,222,100,226,118, +228,144,218,168,202,186,178,198,156,208,105,221,34,80,126,56,230,36,174,50, +152,72,132,98,116,128,114,154,116,178,126,198,140,212,154,222,174,226,207,231, +226,54,247,78,196,74,221,100,12,82,112,54,196,36,150,52,130,70,112,96, +102,124,98,148,100,170,108,190,122,208,140,220,154,224,191,227,186,68,104,108, +78,126,60,146,52,162,50,182,52,196,56,208,64,214,78,222,92,226,108,228, +130,228,193,224,74,22,94,60,111,105,178,36,203,66,204,20,227,48,166,70, +82,108,58,126,42,144,32,160,30,180,34,200,46,214,60,224,80,228,104,230, +173,224,56,20,72,56,91,103,184,62,210,82,231,100,40,78,94,74,149,62, +104,16,92,72,68,134,31,194,160,96,164,190,160,214,152,230,134,238,116,238, +102,234,92,222,90,206,96,194,110,184,126,178,144,180,164,182,180,186,194,192, +225,211,50,32,34,98,34,132,36,170,40,196,48,210,60,228,75,174,112,62, +162,54,213,58,98,176,122,194,152,204,180,204,231,199,30,66,46,102,62,130, +80,152,113,182,132,22,126,96,112,142,90,180,70,202,50,214,34,216,22,210, +18,192,18,168,26,144,38,124,52,108,70,90,88,78,106,70,126,66,150,64, +174,68,194,76,210,90,222,112,226,140,224,164,214,188,196,212,180,224,162,230, +146,230,132,228,120,220,118,206,120,194,126,188,138,182,154,180,170,180,184,184, +196,188,243,215,78,18,72,66,68,108,68,158,70,198,73,234,10,100,42,94, +74,82,96,70,78,102,60,130,44,160,18,206,50,164,68,140,88,120,106,102, +132,84,158,68,182,64,200,72,208,84,214,100,218,138,214,166,204,192,188,210, +172,220,150,222,132,216,122,202,122,184,134,172,150,166,170,164,186,168,202,174, +214,180,247,203,164,226,200,202,226,176,238,142,238,114,230,88,216,66,192,50, +174,42,144,38,118,40,86,50,58,66,42,84,28,104,20,130,16,158,22,180, +34,200,52,210,68,214,88,206,102,186,118,150,136,96,147,39,52,22,36,74, +30,108,28,140,28,170,34,198,40,216,48,236,67,178,92,86,128,90,158,90, +186,88,223,82,174,28,176,160,176,188,172,208,160,222,142,228,122,230,104,224, +94,212,90,196,96,180,112,172,128,168,148,168,164,172,188,180,235,207,216,10, +243,34,194,28,221,52,40,24,22,88,16,124,16,160,18,186,26,218,38,238, +55,180,80,86,144,90,211,82,160,28,164,186,158,208,146,222,128,230,110,230, +92,224,82,212,80,196,84,182,94,174,108,168,124,168,142,168,166,174,184,182, +223,207,38,32,26,74,18,108,16,136,14,162,18,192,22,212,28,228,36,244, +55,186,76,92,132,96,209,88,158,34,162,182,160,206,148,226,132,236,114,236, +96,232,82,222,78,208,80,194,90,182,104,176,124,174,148,176,168,182,180,186, +221,212,242,38,240,26,234,20,228,16,224,16,218,16,212,16,206,18,202,20, +200,26,198,30,196,34,196,42,198,50,204,58,210,60,218,62,228,60,236,56, +240,52,244,44,243,37,20,56,54,52,78,44,106,30,84,54,68,74,54,94, +44,118,38,138,36,154,36,168,38,182,44,198,50,208,60,218,70,224,82,228, +100,230,116,228,136,222,150,210,162,198,172,180,176,156,178,134,178,36,192,68, +204,88,231,127,6,56,44,50,90,30,58,64,36,98,24,132,20,166,28,198, +50,222,80,230,104,226,130,212,146,196,158,172,162,142,162,100,162,36,188,90, +217,126,200,30,227,60,222,10,249,39,8,56,46,50,92,32,62,62,50,80, +36,102,28,124,24,146,24,172,26,192,34,208,48,220,64,228,80,230,102,228, +124,218,142,204,158,176,164,144,162,38,190,88,217,126,246,44,244,30,236,22, +226,20,216,20,208,24,202,32,200,44,202,54,208,60,216,66,228,66,238,62, +246,54,246,46,247,45,100,32,126,46,147,62,196,138,224,166,247,194,8,156, +18,182,32,202,40,204,46,204,77,178,106,92,108,104,112,120,120,138,144,184, +146,196,146,204,140,214,128,218,99,217,100,32,124,46,147,62,194,52,221,82, +222,34,249,64,196,138,224,166,247,196,8,156,18,180,28,196,34,202,40,202, +50,200,77,178,106,94,106,98,108,108,126,148,140,174,146,184,148,198,144,208, +140,216,132,220,120,220,99,217,100,32,124,46,147,62,8,156,18,182,30,198, +36,202,44,204,52,200,77,178,196,138,224,166,247,196,108,92,108,96,110,110, +130,156,136,170,142,182,146,192,146,206,142,216,138,220,130,222,101,220,244,68, +244,60,240,52,234,46,226,44,220,42,206,46,200,52,196,60,194,66,194,68, +196,78,200,86,208,92,216,94,218,94,228,92,238,88,244,80,246,70,245,69, +18,136,76,80,86,74,96,70,104,70,112,74,114,76,146,104,188,134,247,167, +206,34,235,56,182,58,211,80,20,154,66,110,76,100,82,94,88,90,92,90, +98,88,104,90,110,92,118,98,156,128,192,152,245,185,20,154,44,132,60,114, +74,100,86,92,94,90,102,88,112,92,120,100,158,130,190,152,247,184,226,60, +224,48,220,42,216,38,210,36,206,34,198,34,188,36,182,42,178,50,176,56, +176,66,178,74,186,78,192,84,204,84,216,80,224,72,226,66,226,60,227,59, +50,24,34,80,28,126,28,164,30,192,50,238,65,182,100,38,128,42,152,40, +180,38,205,34,94,102,132,104,158,104,186,102,219,96,168,38,168,106,174,158, +176,180,174,196,170,210,162,222,150,226,136,228,120,226,106,220,98,210,96,196, +100,184,112,176,126,170,140,168,162,170,182,176,202,182,237,207,32,20,18,70, +12,104,10,128,10,144,10,168,14,192,18,208,32,232,47,178,226,28,249,56, +204,46,225,74,82,34,110,38,138,36,164,34,187,30,76,100,104,102,126,102, +152,100,174,98,201,94,152,34,152,98,152,118,154,140,156,164,156,186,152,206, +142,220,128,224,114,224,96,222,86,214,80,202,80,186,88,176,102,168,120,166, +136,166,158,170,178,178,219,203,30,22,14,88,10,124,10,150,12,184,18,206, +32,236,47,180,80,38,104,40,126,40,152,40,187,34,74,102,128,104,172,100, +199,96,152,40,152,104,152,128,156,168,156,194,152,208,142,222,126,228,110,226, +94,224,82,216,78,202,80,188,88,178,104,170,116,168,138,170,156,174,180,182, +219,206,248,62,246,50,242,44,236,40,228,38,220,40,210,46,204,58,206,68, +208,76,216,82,228,82,240,80,248,72,250,64,249,59,64,62,124,66,189,60, +66,118,124,122,191,114,204,220,172,198,146,186,120,180,92,180,68,186,58,196, +54,208,56,220,66,230,84,236,106,234,128,230,140,218,142,198,140,182,136,102, +137,19,70,48,116,38,152,34,136,62,80,166,62,194,48,206,32,208,20,200, +16,186,20,166,30,148,46,134,66,124,84,120,96,116,110,118,128,122,182,148, +241,188,204,86,194,132,182,166,162,196,123,235,184,56,235,86,20,72,72,72, +125,66,78,18,78,148,74,166,66,182,56,188,44,190,32,186,26,170,24,150, +26,134,32,120,46,112,62,112,70,120,74,128,70,192,72,210,84,226,98,232, +164,232,182,224,194,208,203,171,40,54,74,120,135,190,154,24,152,66,144,102, +130,142,108,178,88,200,66,214,46,216,30,208,22,188,24,166,32,142,46,124, +58,110,78,98,102,84,118,78,142,72,164,72,190,78,210,88,222,102,228,114, +232,132,234,152,230,174,220,192,202,208,182,220,164,228,155,233,62,66,96,76, +157,80,50,132,88,144,153,150,116,14,96,110,90,164,90,198,100,222,118,236, +144,238,170,234,190,222,200,206,202,182,198,162,181,125,108,72,141,94,62,96, +100,160,133,236,40,160,92,134,132,114,160,104,188,100,208,108,214,118,218,136, +214,152,198,164,176,170,143,173,108,26,145,54,52,56,98,140,137,228,20,138, +90,100,142,78,176,68,202,66,222,72,234,82,242,96,240,116,228,134,206,146, +180,152,149,157,52,80,48,134,50,172,60,218,60,170,80,134,106,110,126,102, +154,98,174,102,196,118,206,138,206,164,196,190,178,202,160,208,140,210,122,202, +103,174,110,238,138,198,146,166,146,118,137,65,34,40,30,112,32,154,44,218, +38,162,46,138,66,112,84,92,106,78,134,68,166,66,196,74,214,90,226,110, +228,134,222,162,204,186,182,198,158,200,138,198,118,188,104,178,93,164,138,24, +148,74,150,118,146,152,142,178,132,202,107,241,132,66,134,118,138,176,136,204, +132,218,120,228,100,232,80,230,68,218,62,204,68,190,76,182,92,178,114,178, +130,182,144,186,197,220,196,108,166,114,135,119,132,24,134,98,140,164,138,196, +132,214,118,228,102,232,80,234,60,226,48,214,44,198,48,184,60,172,76,164, +98,164,124,168,152,180,186,198,217,218,212,74,178,80,135,85,80,16,110,30, +135,42,60,66,52,144,52,174,72,154,100,132,124,122,146,120,168,120,184,126, +198,138,204,152,206,176,198,198,182,214,156,226,119,237,76,24,68,64,66,110, +68,132,82,172,101,118,176,24,188,84,188,122,184,156,176,186,160,216,137,243, +56,50,108,44,158,32,132,66,98,110,50,156,90,124,130,112,164,112,188,124, +202,142,204,168,198,194,184,210,166,220,146,226,120,226,100,222,86,208,84,192, +92,176,110,168,130,168,146,178,156,194,171,217,82,22,76,96,72,162,75,238, +14,106,60,96,98,76,80,102,48,156,16,210,56,158,82,128,106,104,130,82, +152,70,170,68,184,76,190,82,188,92,186,114,178,160,176,184,174,204,178,214, +186,220,198,222,212,218,249,189,68,48,116,40,166,26,138,66,84,132,32,182, +90,136,132,116,162,110,192,116,210,126,220,144,226,172,220,194,204,214,182,230, +166,234,137,239,98,62,92,136,90,186,95,242,50,124,84,114,118,100,88,144, +66,174,48,208,74,172,98,146,120,132,146,120,170,118,194,124,206,140,210,162, +206,182,194,202,180,214,149,229,90,14,86,68,82,116,82,166,87,238,30,92, +88,74,116,60,76,116,26,198,58,158,80,134,104,114,136,94,166,88,192,88, +210,94,224,108,232,130,232,152,224,174,208,192,190,206,151,223,62,46,112,38, +154,26,138,64,110,154,88,202,68,222,50,228,40,224,32,208,32,188,36,164, +46,144,62,124,84,110,106,102,130,96,156,94,180,98,202,110,216,126,224,144, +226,160,224,182,216,200,202,216,180,226,154,230,134,226,122,216,116,202,118,190, +126,180,138,176,154,176,168,182,178,192,186,208,193,221,72,40,136,32,164,24, +136,50,96,88,54,130,96,98,124,84,148,78,166,78,180,80,192,88,200,98, +202,110,200,124,192,138,178,148,162,154,148,156,132,156,116,152,108,150,102,144, +98,138,98,130,102,122,114,118,130,116,144,124,146,136,142,148,134,154,116,158, +86,166,62,178,44,196,24,232,54,206,76,196,94,198,106,208,112,220,118,238, +130,208,142,190,156,182,170,178,184,178,198,182,208,192,218,204,226,216,233,229, +46,62,102,60,155,50,114,14,78,102,60,132,38,172,68,134,88,114,106,106, +120,104,132,106,140,110,146,118,150,128,154,138,156,150,156,164,156,180,156,192, +155,202,188,232,162,236,138,236,114,236,94,230,84,222,78,210,78,196,82,184, +90,174,104,166,122,154,140,146,188,128,223,121,128,24,72,126,36,188,20,230, +48,182,68,154,88,136,102,128,116,122,134,124,138,132,142,140,148,202,152,216, +156,226,164,232,174,232,190,228,243,181,40,88,204,88,151,152,116,124,112,160, +94,198,59,233,16,52,228,52,192,100,151,134,118,96,112,136,100,168,80,204, +45,239,188,64,148,116,108,146,61,172,148,244,149,117,206,26,164,76,124,108, +84,136,43,160,152,244,153,87,56,172,56,108,196,108,176,164,156,196,136,218, +103,242,126,108,127,63,36,150,36,70,222,70,204,118,182,162,150,200,99,242, +126,70,127,17,60,100,197,100,44,208,213,208,128,208,129,101,44,62,217,62, +22,196,233,196,128,196,129,63,50,116,213,116,152,64,152,216,148,228,132,236, +115,236,136,116,124,142,106,166,84,188,51,211,30,88,235,88,158,24,158,216, +152,228,136,236,115,236,134,88,120,118,100,146,74,170,52,186,29,203,34,82, +220,82,212,194,206,210,198,220,184,224,172,224,149,224,128,28,128,84,120,118, +108,150,90,178,70,198,33,229,212,10,237,32,188,32,213,54,22,86,196,86, +190,186,186,202,178,218,166,224,156,224,121,224,110,24,108,88,104,112,96,142, +76,176,54,202,23,231,38,86,205,70,22,158,235,134,140,242,113,19,204,6, +229,26,182,26,207,50,40,98,191,76,26,168,229,136,146,242,111,27,128,20, +98,72,72,102,37,134,104,66,216,66,194,116,172,150,138,186,104,210,65,233, +208,8,233,28,184,30,211,54,110,24,78,80,56,106,25,136,84,72,190,72, +164,130,130,178,90,214,41,245,104,24,80,82,52,120,25,152,244,92,75,92, +168,92,158,142,136,182,110,212,77,239,214,6,239,26,190,26,217,50,100,28, +70,98,25,152,236,92,75,92,80,234,108,212,136,176,154,136,161,93,48,60, +200,60,201,218,48,196,201,197,206,8,229,28,180,30,203,54,24,76,178,76, +179,220,24,202,179,203,12,94,247,94,84,172,85,26,174,24,174,98,174,130, +168,160,152,192,130,218,103,243,222,12,247,32,198,34,225,58,4,92,241,92, +78,172,79,22,168,22,168,98,166,138,154,170,136,198,116,220,89,243,64,36, +115,68,28,96,79,130,42,224,106,192,158,158,202,124,231,99,190,42,221,62, +166,64,195,88,236,112,190,146,146,172,106,194,37,222,24,100,71,134,64,36, +113,73,56,50,196,50,172,98,136,144,96,180,31,220,226,220,147,135,220,6, +245,28,196,30,225,54,40,60,178,60,156,108,132,138,102,166,68,194,17,224, +208,220,129,143,20,116,226,74,208,102,165,158,96,24,96,184,98,200,116,218, +227,219,214,14,243,36,192,36,223,60,12,120,214,90,147,172,82,30,82,190, +84,208,98,220,112,222,219,223,40,52,87,114,216,48,190,104,168,140,138,174, +108,202,71,229,206,6,237,26,186,32,217,52,24,62,65,114,186,60,154,130, +124,172,94,202,51,233,128,18,100,70,72,104,43,134,58,238,108,210,146,172, +180,124,210,56,109,56,102,118,159,153,212,6,239,32,186,24,215,52,106,22, +68,90,27,134,80,68,186,68,144,148,94,200,31,238,76,122,135,159,196,28, +162,42,120,50,90,54,53,54,142,46,142,128,132,162,118,188,94,216,65,240, +16,120,241,121,226,24,249,50,206,46,229,72,176,34,134,46,98,52,68,54, +41,54,2,120,229,120,128,48,128,120,124,144,114,166,100,190,82,210,45,239, +54,98,73,142,114,84,129,126,202,88,176,148,142,190,118,212,87,233,34,60, +57,118,108,44,127,102,222,56,194,118,160,164,122,198,73,229,222,12,247,32, +200,36,227,56,16,66,41,120,86,48,111,102,196,62,170,120,142,160,114,188, +84,210,47,233,60,42,193,42,22,114,235,114,134,114,132,144,124,172,112,192, +94,210,74,230,57,243,216,12,243,36,192,36,223,60,44,46,173,46,10,110, +219,110,122,110,122,130,118,152,110,176,100,194,84,210,66,222,49,235,94,240, +95,22,114,100,142,122,169,147,166,16,193,40,142,42,171,68,74,238,75,18, +94,98,124,120,151,143,16,98,239,98,135,98,134,28,134,98,132,130,122,162, +110,188,94,208,61,239,58,62,197,62,28,194,229,195,70,50,212,50,184,102, +158,140,132,168,106,188,78,206,39,228,82,102,134,136,172,164,205,189,50,76, +190,76,170,102,144,126,122,140,92,158,66,172,23,190,140,238,141,130,180,134, +233,172,140,76,141,27,196,42,170,98,148,136,116,172,90,196,55,221,88,70, +56,132,13,186,174,68,210,122,243,179,216,18,243,42,194,44,221,68,90,78, +56,130,11,174,164,76,200,124,237,177,90,84,56,136,11,180,164,84,202,132, +237,182,248,38,246,26,240,18,232,16,224,14,216,16,208,20,202,28,200,38, +200,46,204,54,212,60,222,64,234,60,244,54,248,46,249,39,60,36,60,186, +62,198,72,210,90,212,211,212,186,88,124,114,61,131,190,18,217,40,166,42, +195,68,46,36,46,186,48,196,54,206,68,212,197,212,172,88,120,110,47,131, +46,36,46,180,48,198,56,208,76,214,197,214,172,88,116,112,47,130,218,40, +214,24,204,18,190,16,176,20,168,32,168,46,174,56,184,62,196,66,208,62, +216,52,219,41,36,60,206,60,176,122,144,164,106,196,55,227,210,10,239,34, +190,32,217,56,14,68,184,68,158,124,128,166,100,192,68,214,33,233,14,68, +184,68,156,124,140,152,104,188,72,212,33,232,238,32,232,16,222,10,210,10, +196,14,190,24,188,36,190,48,198,54,210,58,224,56,236,46,239,31,16,144, +58,114,88,88,96,82,106,84,116,90,146,120,178,142,214,164,241,181,200,30, +227,54,176,56,205,80,14,144,54,118,78,96,90,86,94,82,100,80,108,84, +116,90,146,118,176,140,208,160,241,181,16,146,72,102,90,88,94,84,100,82, +108,82,114,90,144,118,184,146,210,162,241,178,226,50,222,36,214,30,204,28, +190,30,180,36,176,48,178,60,184,70,192,76,206,76,218,70,224,60,227,51, +24,88,229,88,70,134,48,168,21,198,182,136,210,166,235,196,128,28,128,202, +126,212,120,222,106,226,89,227,210,14,237,38,212,62,189,38,24,88,227,88, +128,28,128,198,124,212,118,222,106,226,91,226,72,134,48,168,21,196,180,134, +206,164,233,197,242,40,238,24,230,16,220,14,208,16,198,22,194,34,192,46, +198,56,210,62,224,62,236,56,240,48,243,40,26,88,227,88,128,28,128,202, +124,214,116,222,106,226,91,226,72,134,48,168,21,198,178,136,206,164,233,195, +16,66,224,66,160,138,119,174,78,138,116,174,153,211,98,30,169,62,80,102, +155,136,70,182,177,233,166,122,202,162,237,208,20,206,213,178,122,40,96,118, +59,201,98,94,146,122,205,164,206,38,178,100,134,160,94,196,51,225,46,54, +205,54,22,128,235,128,116,54,116,188,118,202,126,212,140,216,217,217,94,68, +125,240,34,136,218,104,167,177,12,114,240,68,175,158,86,26,131,239,38,206, +219,206,68,106,164,106,157,207,16,196,241,196,48,60,180,60,167,197,64,96, +182,96,183,232,66,154,183,154,66,210,183,211,50,56,196,56,197,222,50,128, +197,128,50,204,197,205,54,38,203,38,30,102,212,102,182,156,156,186,126,210, +81,237,78,162,79,30,174,24,174,120,168,164,156,196,136,222,115,247,72,50, +72,108,66,140,56,168,40,188,17,212,140,44,140,206,198,170,245,129,52,48, +52,210,130,174,174,146,219,113,58,218,58,68,198,68,199,218,58,194,199,195, +60,156,60,88,194,88,180,150,158,190,138,214,111,239,46,134,46,44,210,44, +194,116,170,172,146,202,113,235,32,76,221,76,12,164,243,164,66,164,67,76, +156,246,157,19,48,52,206,52,178,88,149,118,18,204,239,204,126,204,127,107, +40,52,208,52,192,108,170,154,140,188,116,206,86,220,51,232,38,116,187,117, +40,52,87,94,40,216,126,174,176,138,227,97,214,8,239,28,194,28,221,52, +20,150,20,72,206,72,186,132,162,174,136,204,91,240,112,72,113,19,54,114, +202,114,198,188,190,212,182,222,166,226,147,226,134,72,126,126,114,160,98,188, +78,208,53,229,104,72,88,110,70,138,41,172,218,126,79,126,84,242,108,224, +130,200,148,168,154,144,159,127,12,216,80,42,151,216,36,156,125,157,32,210, +32,48,64,48,82,50,100,54,112,64,116,76,116,88,114,100,104,112,94,118, +78,124,32,124,74,126,100,132,118,142,124,154,124,168,124,180,114,196,102,204, +86,210,33,211,110,48,32,48,33,217,12,210,76,42,144,210,13,211,114,48, +32,48,32,210,119,210,106,126,33,127,16,48,130,48,16,210,141,211,32,216, +33,42,146,216,147,42,32,124,147,125,172,130,168,98,158,74,138,56,114,48, +92,46,68,50,46,62,32,82,24,104,22,124,24,148,28,164,34,178,46,194, +62,206,76,210,94,212,114,210,136,204,154,190,164,170,168,154,172,140,173,126, +64,128,131,129,30,42,31,217,32,216,33,42,126,42,33,148,132,216,61,117, +10,216,76,42,143,217,30,216,30,48,42,48,112,216,182,42,190,42,191,217, +30,216,30,42,156,216,157,43,16,48,115,48,24,128,103,128,10,210,121,211, +172,128,166,88,148,64,128,52,106,46,80,46,60,54,44,66,34,78,26,98, +22,116,22,138,26,160,34,178,48,196,64,206,88,212,110,212,134,206,154,190, +166,164,172,142,173,127,30,216,30,50,148,50,149,217,32,216,32,48,72,48, +86,50,100,54,112,62,118,72,122,84,122,102,118,118,104,132,90,138,74,140, +33,141,116,48,14,48,76,124,10,210,123,211,4,48,131,48,66,216,67,49, +70,216,70,142,11,42,128,42,71,143,96,218,97,40,114,70,78,70,64,72, +50,76,42,82,30,94,26,106,24,118,22,132,24,144,30,158,38,170,50,178, +64,184,128,184,144,178,158,162,166,146,168,126,166,106,158,92,146,80,130,72, +113,71,16,42,137,216,12,216,131,43,98,216,99,42,28,42,28,108,32,124, +40,136,52,146,66,152,80,156,116,156,138,152,154,142,164,128,168,114,168,106, +169,43,14,210,84,210,66,196,48,182,36,164,26,146,24,132,24,114,26,96, +30,80,42,66,58,54,72,48,92,46,114,46,134,52,144,60,154,70,162,82, +166,94,168,108,168,124,168,138,162,156,152,172,142,184,128,196,108,210,179,211, +136,92,96,192,82,208,66,214,50,212,34,202,24,182,20,160,20,142,26,120, +38,104,50,98,62,94,76,94,88,98,98,108,104,118,110,136,118,178,122,200, +126,206,132,212,138,212,147,213,28,254,28,92,30,76,36,58,46,48,58,42, +70,42,84,44,96,54,102,66,104,78,102,92,96,106,86,112,58,122,78,124, +90,130,104,138,112,152,114,166,112,184,108,198,96,208,82,214,70,214,58,212, +48,206,36,198,29,191,58,254,64,218,74,200,100,152,108,132,112,116,115,92, +0,96,12,96,20,100,28,114,67,217,122,42,32,42,106,102,116,118,124,136, +126,158,124,178,116,194,106,204,92,210,78,212,62,212,40,204,32,196,26,182, +22,168,22,152,24,136,32,122,44,108,56,100,72,96,95,93,92,116,86,106, +78,98,70,96,60,94,52,94,42,96,34,100,28,108,24,116,24,124,26,134, +30,138,40,144,46,146,78,152,48,154,36,158,26,166,22,176,20,186,24,194, +30,204,38,210,48,212,58,214,70,212,76,210,84,204,99,189,28,42,102,42, +80,62,64,84,42,114,28,138,22,158,20,170,20,184,28,198,40,206,54,208, +68,212,76,212,86,216,96,222,98,234,93,255,10,96,24,96,30,100,32,116, +33,216,32,134,42,116,48,108,56,100,68,96,78,94,88,94,96,96,104,102, +110,108,112,116,114,124,114,130,115,255,24,128,124,128,124,104,120,86,114,68, +104,56,92,46,78,42,62,42,48,48,38,58,30,74,26,88,24,106,20,122, +22,142,24,162,28,178,34,190,40,200,54,208,68,214,84,212,100,204,112,190, +120,168,124,148,124,140,125,129,28,92,28,190,30,200,34,206,40,212,59,213, +28,216,29,92,106,90,29,168,108,216,55,143,20,42,30,40,40,42,46,48, +50,56,68,102,90,160,104,200,114,210,122,210,127,210,12,216,69,105,28,254, +29,92,138,210,126,210,120,208,116,198,116,186,117,90,116,156,104,190,94,204, +80,212,70,212,54,210,42,202,36,190,30,174,29,161,0,96,8,94,16,96, +20,98,24,104,30,118,48,164,62,216,96,160,108,124,113,91,24,42,94,42, +70,50,52,58,44,66,40,76,38,88,40,96,50,104,60,110,90,116,68,124, +54,130,42,136,32,144,24,156,20,170,20,180,24,190,28,196,36,204,46,208, +60,210,72,212,84,214,92,220,96,228,98,236,94,244,93,255,126,160,126,146, +124,126,118,114,110,106,98,98,86,94,74,94,62,94,48,98,38,106,28,116, +22,134,20,144,20,158,22,168,24,180,32,194,42,204,56,210,66,212,78,212, +96,210,110,200,118,190,124,172,127,161,6,102,10,98,20,96,149,96,32,216, +44,156,47,96,114,96,114,196,116,204,122,212,130,212,143,213,28,254,28,144, +32,130,34,120,38,110,46,102,56,96,68,94,76,94,92,96,104,104,114,114, +118,122,122,134,126,148,124,166,122,184,114,198,104,206,92,212,80,212,68,212, +58,208,46,204,40,200,29,187,140,96,80,96,62,96,46,102,34,114,24,128, +20,144,20,158,20,168,24,180,28,188,32,196,38,204,46,208,56,212,70,212, +86,210,98,204,108,192,114,178,116,162,116,148,112,130,108,118,102,110,98,104, +93,97,4,100,10,96,14,96,109,96,54,96,54,188,56,200,58,206,64,212, +70,214,87,215,26,92,26,168,28,178,32,188,40,200,50,208,62,212,74,212, +88,210,98,206,106,200,114,190,118,182,120,170,122,160,122,152,122,142,120,130, +118,116,114,108,109,91,88,254,88,124,90,112,94,104,100,98,110,96,120,94, +132,96,140,102,144,110,148,118,152,126,156,140,156,152,156,164,152,178,144,192, +134,202,124,208,112,210,100,212,92,212,76,214,60,210,48,206,36,200,28,188, +24,174,22,160,20,144,24,128,30,116,38,108,46,100,56,96,65,97,18,254, +115,92,112,254,24,100,18,96,12,96,8,94,5,95,92,254,93,50,28,90, +28,164,30,180,36,192,44,202,56,208,70,212,86,214,106,214,120,210,134,206, +146,196,152,188,158,178,160,158,161,91,34,90,26,120,24,142,20,162,22,176, +26,190,36,204,48,212,62,212,74,210,84,204,94,190,100,164,101,130,164,92, +168,106,172,122,174,136,176,146,178,158,176,168,174,180,172,194,162,204,154,210, +142,214,134,214,126,212,120,210,116,206,110,200,106,192,104,184,102,176,101,167, +12,216,82,42,153,216,36,154,127,155,110,48,32,48,32,210,72,210,88,208, +102,204,112,194,118,182,120,168,118,156,116,144,108,134,98,130,84,126,70,124, +33,125,32,210,32,48,64,48,88,50,100,56,112,64,114,76,116,86,114,100, +106,110,94,118,74,124,33,124,32,210,72,210,92,210,108,202,124,186,128,168, +126,154,118,142,104,134,94,130,75,125,110,48,30,48,31,217,10,254,10,210, +156,210,157,254,140,210,140,48,58,48,52,130,40,170,19,211,114,48,32,48, +32,210,119,210,106,126,33,127,40,32,40,50,52,50,52,32,40,32,52,36, +40,40,52,44,40,48,53,50,88,32,88,50,100,50,100,32,88,32,100,36, +88,40,100,42,88,46,101,50,114,74,30,74,30,210,119,210,106,140,31,141, +108,216,109,42,16,42,36,80,50,106,60,116,72,124,88,128,108,130,128,128, +148,122,162,108,180,82,201,42,14,216,69,122,202,216,149,123,26,82,30,66, +42,54,54,48,66,44,78,46,92,50,102,56,108,66,112,76,112,86,110,100, +104,110,94,118,86,122,56,128,84,132,104,140,112,150,116,160,116,180,110,196, +94,208,78,212,62,212,46,208,36,202,28,194,24,184,23,175,30,42,30,216, +156,42,157,217,30,68,30,216,156,68,157,216,56,16,56,22,58,32,60,38, +68,46,78,48,90,50,102,48,114,46,122,40,128,34,130,30,131,17,32,216, +33,42,124,42,84,108,76,116,64,124,52,128,33,128,128,216,69,121,2,212, +8,212,20,210,28,206,34,196,38,186,46,148,48,112,54,48,138,48,139,217, +30,216,30,42,110,216,190,42,191,217,32,216,33,42,146,216,147,42,32,124, +147,125,172,134,172,120,166,92,156,72,146,60,130,52,112,46,100,46,84,46, +68,50,52,58,38,72,28,90,24,104,22,118,22,136,24,150,26,166,32,178, +40,190,52,200,60,206,72,210,80,210,84,212,90,212,102,212,114,210,130,206, +146,196,158,182,166,166,170,152,173,133,30,216,30,48,148,48,149,217,32,216, +32,50,72,50,78,50,92,52,102,56,112,64,116,70,120,80,122,90,122,98, +120,108,116,120,106,130,98,134,88,138,78,140,74,140,33,141,144,78,136,64, +124,54,110,48,94,44,78,46,66,50,52,56,42,66,32,80,28,94,26,110, +24,124,24,144,28,160,34,176,40,190,50,200,64,208,78,212,96,212,112,208, +126,202,136,192,147,177,4,48,129,48,66,216,67,49,132,42,66,184,58,194, +48,204,38,210,28,212,24,212,11,212,10,42,77,163,96,216,97,42,88,184, +104,184,118,184,136,182,148,176,156,166,164,156,168,144,168,132,168,118,164,104, +158,92,150,82,138,76,126,72,116,70,106,70,104,70,88,70,74,70,60,72, +48,78,38,86,32,94,26,106,24,118,24,126,22,136,26,146,28,156,34,164, +42,172,50,180,58,182,68,184,76,184,91,185,16,42,137,216,130,42,11,217, +166,254,166,210,30,210,31,42,148,210,149,43,132,216,133,42,28,42,28,106, +30,118,32,128,34,134,38,140,44,146,48,148,54,152,62,154,72,156,78,154, +84,154,92,152,100,150,110,146,116,142,133,133,30,42,30,210,202,210,203,42, +116,210,117,43,30,42,30,210,222,210,223,254,118,210,119,42,204,210,205,43, +4,48,62,48,62,210,112,210,126,208,138,204,152,192,158,174,156,158,150,142, +138,132,124,126,108,124,63,125,30,42,30,210,74,210,92,208,108,200,116,186, +118,172,116,148,108,136,96,130,84,126,80,126,31,126,164,216,165,43,30,42, +30,210,70,210,94,208,112,196,122,174,120,152,110,138,96,130,82,126,76,126, +31,127,26,78,36,62,48,52,66,46,82,46,98,48,110,56,120,66,126,78, +132,96,136,112,136,138,132,162,124,184,114,198,102,206,84,212,64,212,46,206, +34,196,23,176,66,126,137,127,88,126,88,148,92,168,102,186,116,202,130,208, +148,212,168,212,190,204,204,192,218,170,224,148,226,130,224,106,218,86,208,68, +194,56,178,48,166,46,148,46,132,48,116,56,102,70,96,86,92,100,88,110, +89,126,30,216,31,42,30,126,89,127,114,216,114,48,68,48,54,50,40,56, +32,62,26,72,22,82,22,94,24,104,28,114,36,122,44,128,52,132,60,134, +68,136,115,136,18,216,71,137,100,216,100,130,98,116,94,104,84,98,72,94, +62,94,52,94,40,98,34,100,30,108,26,114,25,118,100,146,86,146,72,146, +56,148,42,152,30,158,24,168,20,178,20,184,20,190,24,198,30,206,38,212, +50,214,56,212,70,210,80,204,90,194,101,175,124,40,88,48,62,52,48,58, +36,70,28,84,22,110,22,130,22,152,26,180,38,202,56,212,78,214,94,210, +106,202,116,190,122,174,124,158,124,140,118,120,108,106,98,100,88,96,78,94, +68,94,56,98,44,106,34,120,26,136,23,145,28,210,28,96,54,96,76,98, +90,102,96,110,98,120,96,130,92,138,84,144,74,148,28,150,68,154,88,158, +100,162,106,172,108,184,104,196,96,204,88,208,78,210,70,210,29,211,28,216, +28,96,89,97,8,254,8,212,118,212,119,254,102,212,102,96,46,96,40,140, +34,166,28,188,15,213,112,188,98,204,82,212,66,212,54,210,38,202,26,188, +22,170,20,154,22,132,28,118,36,104,54,94,74,94,88,98,100,108,106,116, +112,132,112,140,112,148,21,149,86,52,86,70,98,70,98,52,87,52,88,54, +96,56,88,60,94,64,88,68,98,66,86,56,98,56,92,70,93,52,36,52, +36,72,50,72,50,52,36,52,38,72,42,52,44,72,46,52,48,72,36,68, +50,62,36,58,50,56,37,52,112,188,100,204,86,210,70,212,54,210,42,206, +34,198,26,186,22,176,20,160,20,150,22,134,26,118,36,106,46,98,60,94, +76,94,90,98,100,106,106,116,110,126,112,136,112,140,112,150,21,151,90,216, +91,92,12,90,42,134,48,142,56,146,66,152,76,154,82,154,90,154,104,152, +116,150,126,144,134,136,165,90,12,216,57,148,166,216,121,149,22,122,24,110, +32,102,42,96,52,94,64,94,76,96,86,104,92,114,92,124,88,136,78,142, +70,148,50,152,68,154,84,160,92,166,96,178,96,190,88,204,76,212,60,214, +48,214,38,210,30,204,22,196,19,183,28,90,28,216,118,90,119,217,28,92, +28,216,116,90,117,216,40,38,44,50,52,62,64,68,78,68,92,62,102,50, +105,39,28,216,29,90,102,90,74,136,68,142,64,146,56,150,48,152,40,152, +29,152,104,216,61,149,2,212,8,212,18,212,32,202,38,186,40,172,52,96, +102,96,103,217,26,216,26,90,84,216,144,92,145,217,28,216,29,90,116,216, +117,90,28,152,117,153,126,162,126,146,124,132,118,118,106,102,92,96,76,94, +64,94,48,98,36,108,26,122,22,138,20,156,24,178,30,192,42,204,52,210, +66,212,82,212,104,206,118,190,124,172,127,161,28,216,28,96,116,96,117,217, +28,254,29,90,28,152,34,124,46,108,58,98,74,94,86,94,104,100,116,112, +124,128,126,146,126,168,120,190,106,204,86,212,66,212,50,206,38,190,30,170, +29,161,102,122,96,104,86,98,74,94,62,94,46,98,36,104,30,114,22,128, +20,144,20,158,22,176,28,192,38,206,50,212,64,212,82,210,98,200,105,185, +2,96,99,96,50,216,51,97,110,92,56,228,46,244,38,252,28,254,9,254, +8,90,61,219,84,254,85,36,84,214,94,212,112,210,134,198,148,174,150,148, +144,124,134,108,118,98,104,96,92,94,76,94,58,96,44,102,32,112,24,128, +20,142,20,164,26,184,36,198,50,208,66,212,85,213,14,90,103,216,98,90, +11,217,130,254,130,212,28,212,29,90,116,92,117,213,110,216,111,90,26,90, +26,128,26,144,32,154,40,162,50,166,68,166,80,162,92,158,111,147,28,90, +28,210,170,210,171,92,100,92,101,211,186,254,186,212,28,212,29,90,100,90, +101,212,172,90,173,213,2,96,56,96,56,210,86,210,100,210,118,204,124,186, +124,172,120,162,110,156,102,152,92,152,57,153,142,216,143,90,28,92,28,210, +62,210,80,210,98,202,104,182,98,162,78,152,70,152,29,153,28,92,28,210, +66,210,78,208,96,202,102,186,102,172,94,160,80,152,68,152,60,150,29,151, +16,180,24,200,38,210,56,214,76,210,90,194,96,176,98,162,98,142,94,120, +84,106,74,96,62,94,46,94,32,98,24,108,20,116,19,124,38,152,99,153, +28,216,29,90,28,152,72,152,74,128,80,114,86,106,98,98,110,94,126,94, +142,96,154,102,162,112,168,126,170,142,172,160,168,176,162,192,148,208,132,212, +114,214,96,208,82,196,76,178,72,162,73,153,98,216,98,96,62,96,44,98, +28,108,22,120,22,132,28,144,40,154,54,158,99,158,18,216,69,159,34,60, +97,60,24,118,34,102,44,96,54,94,68,94,80,96,90,102,96,110,100,120, +100,130,101,216,100,146,84,146,60,148,40,152,26,162,20,176,20,188,24,200, +32,208,44,214,54,212,70,210,78,204,88,196,101,179,82,38,51,74,26,118, +30,106,36,100,46,96,58,94,72,94,82,98,92,102,96,110,100,118,100,134, +101,218,100,146,82,146,60,148,42,152,26,160,20,172,20,184,20,198,32,208, +44,212,58,212,70,208,80,204,88,196,101,177,30,36,64,74,101,36,26,118, +30,106,38,98,48,94,60,94,72,94,84,96,92,102,96,112,100,124,101,216, +100,146,84,146,60,146,40,152,26,160,20,176,20,186,22,198,30,206,38,210, +50,212,60,212,70,210,78,206,86,200,90,192,101,173,44,38,77,74,26,118, +28,108,34,102,44,96,50,94,60,94,68,94,82,98,92,102,96,108,98,112, +100,118,100,124,100,126,100,132,101,216,100,148,74,148,64,148,54,148,42,152, +32,156,24,164,18,174,18,186,22,198,28,204,34,208,46,212,56,212,64,212, +76,208,84,200,90,194,101,181,36,60,99,60,112,188,102,202,88,208,72,212, +56,210,38,202,28,190,20,174,18,158,20,140,24,122,34,110,44,100,62,94, +82,94,94,102,104,112,110,126,112,138,112,142,112,150,19,151,88,38,57,74, +112,188,100,202,84,212,66,214,54,212,40,206,30,196,24,182,20,166,20,152, +22,136,26,118,36,104,46,98,60,94,74,94,86,98,98,104,104,114,108,122, +112,134,112,142,112,150,21,151,34,36,68,74,103,36,112,188,100,204,86,210, +70,212,56,212,42,206,30,196,24,182,20,166,20,152,20,136,26,120,36,106, +48,98,60,94,74,94,88,98,96,102,104,112,108,122,112,134,112,142,110,150, +21,151,44,38,77,74,112,188,98,204,84,210,66,212,50,210,36,202,26,190, +22,174,20,154,22,134,26,118,34,108,46,98,60,94,76,94,92,98,102,108, +108,120,112,132,114,144,114,150,21,151,0,60,61,60,28,216,29,91,52,38, +19,74,28,216,29,91,2,44,30,74,63,38,28,90,29,217,6,38,37,74, +28,90,29,217,42,60,105,60,126,160,126,146,124,128,118,118,112,108,100,100, +84,94,70,94,52,96,38,106,26,118,22,138,20,154,22,172,30,190,38,202, +48,208,62,212,80,212,100,206,114,196,124,176,127,159,94,38,61,74,126,160, +126,146,124,130,118,116,108,104,94,96,76,94,56,96,40,104,28,118,22,136, +20,154,20,166,26,182,34,196,44,204,56,210,72,214,88,212,106,202,120,190, +126,174,127,157,40,36,74,74,109,36,126,160,126,146,122,126,114,110,104,100, +92,96,78,94,64,94,52,96,40,102,30,114,24,128,22,140,20,154,22,166, +24,178,32,192,42,204,54,210,70,212,86,210,102,204,114,194,122,184,126,170, +127,159,48,38,81,74,126,160,126,146,122,128,116,114,104,102,92,98,78,94, +62,96,48,98,36,108,28,120,22,134,20,148,22,160,24,178,28,188,34,198, +42,204,54,210,68,212,82,212,98,208,112,200,120,184,126,170,127,157,40,60, +101,60,112,92,113,216,26,90,26,170,30,188,34,198,42,206,54,212,66,214, +78,212,90,206,100,196,102,190,113,171,92,38,59,74,112,92,113,216,26,92, +26,174,30,190,38,204,54,212,72,212,88,208,98,198,104,188,113,177,36,38, +70,74,105,38,112,92,113,216,28,92,28,174,30,190,36,204,52,210,68,212, +82,212,94,204,102,190,113,173,48,38,81,74,112,92,113,216,28,90,28,174, +30,194,42,208,60,214,80,212,96,200,113,177,40,32,101,32,40,56,48,56, +48,70,40,70,41,56,40,62,48,62,40,68,46,56,40,58,47,70,88,72, +98,72,98,56,88,56,88,72,92,62,90,58,96,58,94,66,92,70,92,72, +98,66,88,62,93,56,112,92,113,216,26,92,26,174,30,188,36,200,48,210, +62,212,78,212,90,204,100,194,113,177,93,12,92,12,61,40,40,62,50,62, +50,72,38,72,38,62,42,72,44,62,50,68,44,72,41,62,92,72,92,62, +100,62,100,72,92,72,92,66,94,68,98,64,96,72,94,62,100,68,97,72, +112,90,113,216,28,90,28,170,30,192,38,204,52,212,66,214,76,210,90,206, +98,198,102,190,113,173,36,12,72,40,105,12,52,70,52,54,40,54,40,70, +52,70,48,54,44,70,42,54,49,70,100,70,100,54,90,54,90,70,100,70, +94,54,90,64,96,70,96,54,100,60,91,64,112,90,113,216,28,90,28,172, +30,188,34,200,44,208,54,212,66,212,80,210,92,204,102,192,113,177,48,12, +83,40,102,72,102,60,88,60,88,70,102,70,94,60,90,70,100,64,89,64, +40,60,52,60,52,72,40,72,40,60,50,72,50,60,46,72,40,68,53,66, +112,90,113,216,28,92,28,170,28,188,32,196,44,208,58,214,72,212,86,208, +96,200,102,190,113,177,88,54,88,70,100,70,100,54,90,54,90,70,96,54, +97,70,52,72,52,54,40,54,40,70,52,70,46,54,44,70,40,62,53,58, +112,90,113,216,26,92,26,174,30,190,36,204,46,210,64,212,82,208,94,202, +102,192,113,175,32,74,68,40,103,74,112,188,96,206,80,212,56,212,36,202, +24,182,20,166,20,156,20,144,24,124,34,110,46,100,58,96,74,94,92,98, +102,110,110,122,112,138,112,144,112,150,21,151,78,28,38,90,214,90,204,202, +198,218,190,226,182,228,149,229,82,22,46,78,202,78,174,144,126,192,47,226, +62,122,146,180,207,227,50,218,50,42,206,42,207,219,216,50,46,50,46,212, +217,213,78,30,44,90,212,90,206,204,198,222,188,228,176,230,149,230,40,226, +68,200,96,164,114,128,127,91,34,86,223,86,164,148,217,228,136,28,98,132, +48,220,197,197,46,30,162,30,132,100,204,100,196,188,188,206,174,218,154,224, +127,225,80,28,44,90,212,90,204,200,198,218,190,226,178,230,147,230,148,28, +132,102,114,144,94,178,68,204,41,227,102,30,58,134,105,226,196,28,152,134, +199,227,34,40,221,40,104,40,74,116,194,116,184,186,180,202,172,212,158,216, +140,220,111,221,220,38,72,38,72,118,62,172,39,229,190,234,191,24,66,34, +66,172,191,141,166,30,84,134,177,229,34,38,223,38,128,230,129,39,50,48, +50,136,206,136,207,46,34,218,223,218,128,218,129,27,156,24,106,66,55,94, +210,66,130,136,45,186,136,234,137,131,58,32,210,32,210,112,76,112,72,154, +60,194,41,227,204,218,204,36,52,36,52,218,205,218,98,100,157,153,38,34, +212,34,208,122,204,138,200,144,192,148,184,148,157,148,98,234,99,35,34,72, +223,72,122,24,70,138,198,138,186,178,166,204,135,233,166,148,198,194,219,230, +126,28,86,134,38,218,199,195,128,238,128,118,49,32,216,34,129,119,34,40, +223,40,136,40,136,116,118,116,102,118,90,122,76,128,70,134,62,144,58,156, +56,168,58,180,64,196,74,206,86,214,98,220,110,222,122,222,134,222,152,220, +168,212,182,200,188,190,198,176,207,159,34,68,223,68,134,20,134,126,114,128, +94,132,80,140,70,148,64,164,60,180,64,194,70,208,82,218,92,224,104,228, +118,228,136,228,154,224,172,216,186,204,194,194,198,180,201,173,34,94,223,94, +168,164,169,26,82,28,82,208,84,216,90,224,96,224,209,225,34,32,223,32, +76,32,54,114,204,114,196,176,181,226,152,32,144,92,120,156,92,192,47,227, +38,58,132,34,146,96,174,156,215,221,178,154,221,224,192,60,116,146,40,216, +201,192,114,28,40,114,153,107,50,36,196,36,174,98,150,136,104,182,39,218, +54,94,138,148,213,217,36,34,180,34,159,126,90,34,58,126,216,126,194,186, +155,233,78,32,36,112,212,112,198,174,173,235,34,82,223,82,132,26,124,76, +112,128,98,158,72,194,39,228,136,82,136,206,138,216,150,224,213,225,142,34, +100,124,40,216,217,217,80,28,80,108,78,150,68,184,56,206,43,230,148,26, +148,196,150,210,164,222,219,223,16,126,241,127,48,38,142,136,211,218,202,36, +162,100,120,148,45,219,50,38,50,214,204,214,205,37,0,118,255,119,0,118, +255,118,0,110,255,110,1,124,0,126,255,127,128,0,129,245,118,0,119,244, +134,0,135,244,126,0,127,245,14,118,69,118,100,118,155,118,186,118,241,119, +14,110,69,110,14,126,69,126,14,118,69,118,100,110,155,110,100,126,155,126, +103,118,100,118,155,118,186,110,241,110,187,124,186,126,241,126,186,118,241,119, +126,4,127,58,126,90,127,144,126,176,127,231,118,4,119,58,118,90,119,144, +118,176,119,230,126,4,127,58,126,90,127,144,126,176,127,230,134,4,135,58, +134,90,135,144,134,176,135,231,12,118,51,118,76,118,115,118,140,118,179,118, +204,118,243,119,12,110,51,110,76,110,115,110,140,110,179,110,204,110,243,110, +12,126,51,126,76,126,115,126,141,124,140,126,179,126,204,126,243,126,12,118, +51,118,76,118,115,118,140,118,179,118,204,118,243,119,126,2,127,40,126,66, +127,104,126,130,127,168,126,194,127,233,118,2,119,40,118,66,119,104,118,130, +119,168,118,194,119,232,126,2,127,40,126,66,127,104,126,130,127,168,126,194, +127,232,134,2,135,40,134,66,135,104,134,130,135,168,134,194,135,233,128,244, +128,118,255,119,128,244,128,110,255,110,128,118,255,118,128,126,255,127,120,118, +255,118,120,118,121,244,128,118,129,244,136,118,137,245,254,110,120,110,121,244, +128,244,128,118,255,118,254,126,136,126,137,245,0,118,128,118,129,245,128,244, +128,110,1,110,0,118,129,118,0,126,129,127,0,118,134,118,135,244,126,244, +127,118,117,244,118,244,119,119,0,110,136,110,137,244,128,244,128,118,1,118, +120,244,120,126,1,127,128,0,128,118,255,119,128,0,128,126,255,126,128,118, +255,118,128,110,255,111,254,118,120,118,121,0,128,118,129,0,136,118,137,1, +120,0,120,126,255,126,128,0,128,118,255,118,136,0,136,110,255,111,0,118, +128,118,129,1,128,0,128,126,1,126,0,118,129,118,128,110,1,111,0,118, +136,118,137,0,128,118,129,0,120,118,121,1,0,124,136,124,137,0,0,116, +128,116,129,0,0,108,120,108,121,1,128,244,129,0,128,118,255,119,128,244, +129,0,128,112,255,112,128,120,255,120,128,128,255,129,128,244,129,0,128,118, +255,118,136,118,137,0,120,114,121,1,126,0,127,244,254,118,127,118,118,244, +119,120,134,244,135,119,120,244,121,0,128,244,129,0,136,244,137,0,136,118, +255,119,254,110,134,110,135,0,254,118,126,118,127,0,254,126,118,126,119,0, +126,244,127,127,120,244,120,112,255,112,128,244,128,120,255,120,136,244,136,128, +255,128,128,112,129,1,134,244,135,0,124,244,125,0,116,244,117,0,254,112, +135,112,254,120,135,120,254,128,135,129,128,244,129,0,0,118,129,119,128,244, +129,0,128,110,1,110,128,118,1,118,128,126,1,127,128,244,129,0,136,0, +137,114,120,0,121,114,0,118,129,119,128,0,129,244,0,118,129,118,120,244, +121,118,136,244,137,121,120,244,121,0,128,244,129,0,136,244,137,0,0,118, +121,119,128,244,129,0,0,124,129,124,128,116,1,116,128,108,1,108,120,108, +121,0,136,124,137,1,128,0,129,244,136,244,137,104,120,244,121,104,120,110, +1,110,120,118,1,118,120,126,1,127,134,244,135,0,126,244,127,0,118,244, +119,0,118,126,1,126,118,118,1,118,118,110,1,111,0,118,255,118,128,244, +129,119,254,118,1,118,0,126,135,126,0,110,135,110,128,244,129,127,0,118, +255,118,122,110,255,110,122,126,255,126,128,244,129,127,0,110,255,110,0,118, +255,118,0,126,255,126,128,244,129,127,0,118,255,118,120,244,121,118,128,244, +129,118,136,244,137,119,254,118,1,118,0,110,143,110,0,126,143,126,136,126, +137,244,128,126,129,244,120,126,121,245,0,118,255,118,114,110,255,110,114,126, +255,126,136,244,137,126,128,244,129,126,120,244,121,127,254,110,1,110,254,118, +1,118,254,126,1,126,120,244,121,126,128,244,129,126,136,244,137,127,0,118, +255,118,128,118,129,1,254,118,1,118,132,110,1,110,132,126,1,126,128,0, +129,111,0,118,255,118,122,126,255,126,122,110,255,110,128,0,129,111,0,110, +255,110,0,118,255,118,0,126,255,126,128,110,129,1,0,118,255,118,120,118, +121,0,128,118,129,0,136,118,137,1,254,118,1,118,142,110,1,110,142,126, +1,126,120,110,121,0,128,110,129,0,136,110,137,1,0,118,255,118,114,126, +255,126,114,110,255,110,120,110,121,0,128,110,129,0,136,110,137,1,0,110, +255,110,0,118,255,118,0,126,255,126,120,110,121,0,128,110,129,0,136,110, +137,1,0,118,255,118,128,244,129,1,128,244,129,0,254,118,1,118,128,110, +1,110,128,126,1,127,128,244,129,0,0,118,255,118,128,110,255,110,128,126, +255,127,128,244,129,2,0,110,255,110,0,118,255,118,0,126,255,127,0,118, +255,118,128,244,129,0,120,118,121,0,136,118,137,1,0,118,255,118,128,0, +129,244,136,244,137,118,120,244,121,119,0,118,255,118,120,244,121,0,128,244, +129,0,136,244,137,1,128,244,129,0,254,118,1,118,136,118,137,0,120,118, +121,0,128,126,1,126,120,110,1,111,0,118,255,118,128,244,129,0,120,118, +121,0,136,118,137,0,136,110,255,110,128,126,255,127,128,0,129,244,254,118, +1,118,136,244,137,118,120,244,121,118,128,110,1,110,120,126,1,127,0,118, +255,118,128,0,129,244,120,118,121,244,136,118,137,244,128,110,255,110,136,126, +255,127,128,244,129,0,0,110,255,110,0,118,255,118,0,126,255,126,136,110, +137,0,120,110,121,1,128,0,129,244,0,110,255,110,0,118,255,118,0,126, +255,126,120,126,121,244,136,126,137,245,254,118,1,118,120,244,121,0,128,244, +129,0,136,244,137,0,120,110,1,110,120,126,1,127,0,118,255,118,120,244, +121,0,128,244,129,0,136,244,137,0,136,110,255,110,136,126,255,127,0,110, +255,110,0,118,255,118,0,126,255,126,120,244,121,0,128,244,129,0,136,244, +137,1,66,176,56,172,48,164,46,152,48,144,54,138,64,132,74,130,86,128, +96,128,106,130,114,138,122,148,122,156,120,168,116,176,104,184,90,190,76,192, +62,192,46,188,32,180,24,172,16,162,14,154,14,138,18,126,24,118,34,106, +44,96,58,88,72,82,84,72,92,64,98,58,102,50,100,40,98,34,90,30, +80,30,74,34,68,44,66,58,66,74,68,90,74,112,80,142,82,162,90,186, +92,202,94,218,92,234,84,244,72,246,58,246,48,242,44,238,40,232,40,222, +44,216,52,214,60,216,66,222,64,230,58,236,52,238,49,241,10,192,32,190, +50,182,68,170,82,154,90,138,94,122,96,106,92,90,88,80,74,72,60,66, +46,68,32,72,22,84,18,100,20,110,26,118,34,122,44,120,50,114,50,104, +48,98,44,92,40,90,32,90,26,92,20,98,42,96,22,106,44,106,28,112, +44,112,30,118,43,116,112,92,106,88,108,82,112,80,116,80,120,84,116,92, +112,88,118,86,110,90,114,92,110,84,114,82,120,88,116,92,113,84,118,128, +116,118,108,120,106,124,108,130,116,130,118,126,118,124,108,124,114,126,116,120, +110,128,112,120,117,129,132,250,156,248,178,236,190,212,200,202,202,196,202,180, +204,170,208,158,210,152,214,144,212,132,210,124,210,118,210,104,210,86,212,68, +206,52,194,34,178,18,154,8,132,4,98,6,72,20,56,34,48,48,46,52, +44,66,46,82,48,92,48,102,46,116,42,116,44,132,44,146,48,156,52,162, +50,188,54,202,62,214,72,220,76,226,84,232,92,242,104,244,114,248,126,250, +135,250,48,84,58,66,72,54,92,42,110,36,136,36,156,38,174,44,188,54, +200,70,206,82,209,90,68,44,88,26,116,16,143,14,116,30,136,24,152,20, +173,22,162,36,178,32,191,38,60,216,34,222,25,226,192,210,214,218,239,224, +196,124,188,122,172,116,158,118,152,120,154,122,164,126,176,132,186,130,199,124, +110,120,90,116,76,118,62,120,72,124,84,128,94,130,104,126,111,122,90,210, +110,220,126,220,144,222,160,216,170,212,166,208,146,206,126,204,106,206,91,208, +110,168,138,166,152,170,146,174,118,174,110,172,111,168,68,90,88,84,104,90, +113,96,152,90,178,84,190,90,199,100,168,118,169,126,172,118,173,128,176,120, +175,126,86,118,87,126,90,118,90,124,92,118,95,126,90,208,116,210,136,212, +148,212,169,213}; +unsigned char zzhi[]={32,0,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0, +42,0,43,0,44,0,45,0,46,0,47,0,48,0,49,0,50,0,51,0, +52,0,53,0,54,0,55,0,56,0,57,0,58,0,59,0,60,0,61,0, +62,0,63,0,64,0,65,0,66,0,67,0,68,0,69,0,70,0,71,0, +72,0,73,0,74,0,75,0,76,0,77,0,78,0,79,0,80,0,81,0, +82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,91,0, +92,0,93,0,94,0,95,0,96,0,97,0,98,0,99,0,100,0,101,0, +102,0,103,0,104,0,105,0,106,0,107,0,108,0,109,0,110,0,111,0, +112,0,113,0,114,0,115,0,116,0,117,0,118,0,119,0,120,0,121,0, +122,0,123,0,124,0,125,0,126,0,163,160,163,161,163,162,163,163,163,164, +163,165,163,166,163,167,163,168,163,169,163,170,163,171,163,172,163,173,163,174, +163,175,163,176,163,177,163,178,163,179,163,180,163,181,163,182,163,183,163,184, +163,185,163,186,163,187,163,188,163,189,163,190,163,191,163,192,163,193,163,194, +163,195,163,196,163,197,163,198,163,199,163,200,163,201,163,202,163,203,163,204, +163,205,163,206,163,207,163,208,163,209,163,210,163,211,163,212,163,213,163,214, +163,215,163,216,163,217,163,218,163,219,163,220,163,221,163,222,163,223,163,224, +163,225,163,226,163,227,163,228,163,229,163,230,163,231,163,232,163,233,163,234, +163,235,163,236,163,237,163,238,163,239,163,240,163,241,163,242,163,243,163,244, +163,245,163,246,163,247,163,248,163,249,163,250,163,251,163,252,163,253,163,254, +163,255,161,162,161,163,161,164,161,165,161,166,161,167,161,168,161,169,161,170, +161,171,161,172,161,173,161,174,161,175,161,176,161,177,161,178,161,179,161,180, +161,181,161,182,161,184,161,185,161,186,161,187,161,188,161,189,161,190,161,191, +161,192,161,193,161,194,161,195,161,196,161,197,161,198,161,199,161,200,161,201, +161,202,161,203,161,204,161,205,161,206,161,207,161,208,161,209,161,210,161,211, +161,212,161,213,161,214,161,215,161,216,161,217,161,218,161,219,161,222,161,223, +161,224,161,225,161,226,161,227,161,228,161,229,161,230,161,231,161,232,161,233, +161,234,161,235,161,236,161,237,161,238,161,239,161,240,161,241,161,242,161,243, +161,244,161,245,161,246,161,247,161,248,161,249,161,250,161,251,161,252,161,253, +161,254,161,183,161,220,161,221,176,161,176,162,176,163,176,164,176,165,176,166, +176,167,176,168,176,169,176,170,176,171,176,172,176,173,176,174,176,175,176,176, +176,177,176,178,176,179,176,180,176,181,176,182,176,183,176,184,176,185,176,186, +176,187,176,188,176,189,176,190,176,191,176,192,176,193,176,194,176,195,176,196, +176,197,176,198,176,199,176,200,176,201,176,202,176,203,176,204,176,205,176,206, +176,207,176,208,176,209,176,210,176,211,176,212,176,213,176,214,176,215,176,216, +176,217,176,218,176,219,176,220,176,221,176,222,176,223,176,224,176,225,176,226, +176,227,176,228,176,229,176,230,176,231,176,232,176,233,176,234,176,235,176,236, +176,237,176,238,176,239,176,240,176,241,176,242,176,243,176,244,176,245,176,246, +176,247,176,248,176,249,176,250,176,251,176,252,176,253,176,254,177,161,177,162, +177,163,177,164,177,165,177,166,177,167,177,168,177,169,177,170,177,171,177,172, +177,173,177,174,177,175,177,176,177,177,177,178,177,179,177,180,177,181,177,182, +177,183,177,184,177,185,177,186,177,187,177,188,177,189,177,190,177,191,177,192, +177,193,177,194,177,195,177,196,177,197,177,198,177,199,177,200,177,201,177,202, +177,203,177,204,177,205,177,206,177,207,177,208,177,209,177,210,177,211,177,212, +177,213,177,214,177,215,177,216,177,217,177,218,177,219,177,220,177,221,177,222, +177,223,177,224,177,225,177,226,177,227,177,228,177,229,177,230,177,231,177,232, +177,233,177,234,177,235,177,236,177,237,177,238,177,239,177,240,177,241,177,242, +177,243,177,244,177,245,177,246,177,247,177,248,177,249,177,250,177,251,177,252, +177,253,177,254,178,161,178,162,178,163,178,164,178,165,178,166,178,167,178,168, +178,169,178,170,178,171,178,172,178,173,178,174,178,175,178,176,178,177,178,178, +178,179,178,180,178,181,178,182,178,183,178,184,178,185,178,186,178,187,178,188, +178,189,178,190,178,191,178,192,178,193,178,194,178,195,178,196,178,197,178,198, +178,199,178,200,178,201,178,202,178,203,178,204,178,205,178,206,178,207,178,208, +178,209,178,210,178,211,178,212,178,213,178,214,178,215,178,216,178,217,178,218, +178,219,178,220,178,221,178,222,178,223,178,224,178,225,178,226,178,227,178,228, +178,229,178,230,178,231,178,232,178,233,178,234,178,235,178,236,178,237,178,238, +178,239,178,240,178,241,178,242,178,243,178,244,178,245,178,246,178,247,178,248, +178,249,178,250,178,251,178,252,178,253,178,254,179,161,179,162,179,163,179,164, +179,165,179,166,179,167,179,168,179,169,179,170,179,171,179,172,179,173,179,174, +179,175,179,176,179,177,179,178,179,179,179,180,179,181,179,182,179,183,179,184, +179,185,179,186,179,187,179,188,179,189,179,190,179,191,179,192,179,193,179,194, +179,195,179,196,179,197,179,198,179,199,179,200,179,201,179,202,179,203,179,204, +179,205,179,206,179,207,179,208,179,209,179,210,179,211,179,212,179,213,179,214, +179,215,179,216,179,217,179,218,179,219,179,220,179,221,179,222,179,223,179,224, +179,225,179,226,179,227,179,228,179,229,179,230,179,231,179,232,179,233,179,234, +179,235,179,236,179,237,179,238,179,239,179,240,179,241,179,242,179,243,179,244, +179,245,179,246,179,247,179,248,179,249,179,250,179,251,179,252,179,253,179,254, +180,161,180,162,180,163,180,164,180,165,180,166,180,167,180,168,180,169,180,170, +180,171,180,172,180,173,180,174,180,175,180,176,180,177,180,178,180,179,180,180, +180,181,180,182,180,183,180,184,180,185,180,186,180,187,180,188,180,189,180,190, +180,191,180,192,180,193,180,194,180,195,180,196,180,197,180,198,180,199,180,200, +180,201,180,202,180,203,180,204,180,205,180,206,180,207,180,208,180,209,180,210, +180,211,180,212,180,213,180,214,180,215,180,216,180,217,180,218,180,219,180,220, +180,221,180,222,180,223,180,224,180,225,180,226,180,227,180,228,180,229,180,230, +180,231,180,232,180,233,180,234,180,235,180,236,180,237,180,238,180,239,180,240, +180,241,180,242,180,243,180,244,180,245,180,246,180,247,180,248,180,249,180,250, +180,251,180,252,180,253,180,254,181,161,181,162,181,163,181,164,181,165,181,166, +181,167,181,168,181,169,181,170,181,171,181,172,181,173,181,174,181,175,181,176, +181,177,181,178,181,179,181,180,181,181,181,182,181,183,181,184,181,185,181,186, +181,187,181,188,181,189,181,190,181,191,181,192,181,193,181,194,181,195,181,196, +181,197,181,198,181,199,181,200,181,201,181,202,181,203,181,204,181,205,181,206, +181,207,181,208,181,209,181,210,181,211,181,212,181,213,181,214,181,215,181,216, +181,217,181,218,181,219,181,220,181,221,181,222,181,223,181,224,181,225,181,226, +181,227,181,228,181,229,181,230,181,231,181,232,181,233,181,234,181,235,181,236, +181,237,181,238,181,239,181,240,181,241,181,242,181,243,181,244,181,245,181,246, +181,247,181,248,181,249,181,250,181,251,181,252,181,253,181,254,182,161,182,162, +182,163,182,164,182,165,182,166,182,167,182,168,182,169,182,170,182,171,182,172, +182,173,182,174,182,175,182,176,182,177,182,178,182,179,182,180,182,181,182,182, +182,183,182,184,182,185,182,186,182,187,182,188,182,189,182,190,182,191,182,192, +182,193,182,194,182,195,182,196,182,197,182,198,182,199,182,200,182,201,182,202, +182,204,182,205,182,206,182,207,182,203,182,208,182,209,182,210,182,211,182,212, +182,213,182,214,182,215,182,216,182,217,182,218,182,219,182,220,182,221,182,222, +182,223,182,224,182,225,182,226,182,227,182,228,182,229,182,230,182,231,182,232, +182,233,182,234,182,235,182,236,182,237,182,238,182,239,182,240,182,241,182,242, +182,243,182,244,182,245,182,246,182,247,182,248,182,249,182,250,182,251,182,252, +182,253,182,254,183,161,183,162,183,163,183,164,183,165,183,166,183,167,183,168, +183,169,183,170,183,171,183,172,183,173,183,174,183,175,183,176,183,177,183,178, +183,179,183,180,183,181,183,182,183,183,183,184,183,185,183,186,183,187,183,188, +183,189,183,190,183,191,183,192,183,193,183,194,183,195,183,196,183,197,183,198, +183,199,183,200,183,201,183,202,183,203,183,204,183,205,183,206,183,207,183,208, +183,209,183,210,183,211,183,212,183,213,183,214,183,215,183,216,183,217,183,218, +183,219,183,220,183,221,183,222,183,223,183,224,183,225,183,226,183,227,183,228, +183,229,183,230,183,231,183,232,183,233,183,234,183,235,183,236,183,237,183,238, +183,239,183,240,183,241,183,242,183,243,183,244,183,245,183,246,183,247,183,248, +183,249,183,250,183,251,183,252,183,253,183,254,184,161,184,162,184,163,184,164, +184,165,184,166,184,167,184,168,184,169,184,170,184,171,184,172,184,173,184,174, +184,175,184,176,184,177,184,178,184,179,184,180,184,181,184,182,184,183,184,184, +184,185,184,186,184,187,184,188,184,189,184,190,184,191,184,192,184,193,184,194, +184,195,184,196,184,197,184,198,184,199,184,200,184,201,184,202,184,203,184,204, +184,205,184,206,184,207,184,208,184,209,184,210,184,211,184,212,184,213,184,214, +184,215,184,216,184,217,184,218,184,219,184,220,184,221,184,222,184,223,184,224, +184,225,184,226,184,227,184,228,184,229,184,230,184,231,184,232,184,233,184,234, +184,235,184,236,184,237,184,238,184,239,184,240,184,241,184,242,184,243,184,244, +184,245,184,246,184,247,184,248,184,249,184,250,184,251,184,252,184,253,184,254, +185,161,185,162,185,163,185,164,185,165,185,166,185,167,185,168,185,169,185,170, +185,171,185,172,185,173,185,174,185,175,185,176,185,177,185,178,185,179,185,180, +185,181,185,182,185,183,185,184,185,185,185,186,185,187,185,188,185,189,185,190, +185,191,185,192,185,193,185,194,185,195,185,196,185,197,185,198,185,199,185,200, +185,201,185,202,185,203,185,204,185,205,185,206,185,207,185,208,185,209,185,210, +185,211,185,212,185,213,185,214,185,215,185,216,185,217,185,218,185,219,185,220, +185,221,185,222,185,223,185,224,185,225,185,226,185,227,185,228,185,229,185,230, +185,231,185,232,185,233,185,234,185,235,185,236,185,237,185,238,185,239,185,240, +185,241,185,242,185,243,185,244,185,245,185,246,185,247,185,248,185,250,185,251, +185,252,185,253,185,254,185,249,186,161,186,162,186,163,186,164,186,165,186,166, +186,167,186,168,186,169,186,170,186,171,186,172,186,173,186,174,186,175,186,176, +186,177,186,178,186,179,186,180,186,181,186,182,186,183,186,184,186,185,186,186, +186,187,186,188,186,189,186,190,186,191,186,192,186,193,186,194,186,195,186,196, +186,197,186,198,186,199,186,200,186,201,186,202,186,203,186,204,186,205,186,206, +186,207,186,208,186,209,186,210,186,211,186,212,186,213,186,214,186,215,186,216, +186,217,186,218,186,219,186,220,186,221,186,222,186,223,186,224,186,225,186,226, +186,227,186,228,186,229,186,230,186,231,186,232,186,233,186,234,186,235,186,236, +186,237,186,238,186,239,186,240,186,241,186,242,186,243,186,244,186,245,186,246, +186,247,186,248,186,249,186,250,186,251,186,252,186,253,186,254,187,161,187,162, +187,163,187,164,187,165,187,166,187,167,187,168,187,169,187,170,187,171,187,172, +187,173,187,174,187,175,187,176,187,177,187,178,187,179,187,180,187,181,187,182, +187,183,187,184,187,185,187,186,187,187,187,188,187,189,187,190,187,191,187,192, +187,193,187,194,187,195,187,196,187,197,187,198,187,199,187,200,187,201,187,202, +187,203,187,204,187,205,187,206,187,207,187,208,187,209,187,210,187,211,187,212, +187,213,187,214,187,215,187,216,187,217,187,218,187,219,187,220,187,221,187,222, +187,223,187,224,187,225,187,226,187,227,187,228,187,229,187,230,187,231,187,232, +187,233,187,234,187,235,187,236,187,237,187,238,187,239,187,240,187,241,187,242, +187,243,187,244,187,245,187,246,187,247,187,248,187,249,187,250,187,251,187,252, +187,253,187,254,188,161,188,162,188,163,188,164,188,165,188,166,188,167,188,169, +188,168,188,170,188,171,188,172,188,173,188,174,188,175,188,176,188,177,188,178, +188,179,188,180,188,181,188,182,188,183,188,184,188,185,188,186,188,187,188,188, +188,189,188,190,188,191,188,192,188,193,188,194,188,195,188,197,188,198,188,199, +188,200,188,201,188,202,188,203,188,204,188,205,188,206,188,207,188,208,188,209, +188,210,188,211,188,212,188,213,188,214,188,215,188,216,188,217,188,218,188,219, +188,220,188,221,188,222,188,223,188,196,188,224,188,225,188,226,188,227,188,228, +188,229,188,230,188,231,188,232,188,233,188,234,188,235,188,236,188,237,188,238, +188,239,188,240,188,241,188,242,188,243,188,244,188,245,188,246,188,247,188,248, +188,249,188,250,188,251,188,252,188,253,188,254,189,161,189,162,189,163,189,164, +189,165,189,166,189,167,189,168,189,169,189,170,189,171,189,172,189,173,189,174, +189,175,189,176,189,177,189,178,189,179,189,180,189,181,189,182,189,183,189,184, +189,185,189,186,189,187,189,188,189,189,189,190,189,191,189,192,189,193,189,194, +189,195,189,196,189,197,189,198,189,199,189,200,189,201,189,202,189,203,189,204, +189,205,189,206,189,207,189,208,189,209,189,210,189,211,189,212,189,213,189,214, +189,215,189,216,189,217,189,218,189,219,189,220,189,221,189,222,189,223,189,224, +189,225,189,226,189,227,189,228,189,229,189,230,189,231,189,232,189,233,189,234, +189,235,189,236,189,237,189,238,189,239,189,240,189,241,189,242,189,243,189,244, +189,245,189,246,189,247,189,248,189,249,189,250,189,251,189,252,189,253,189,254, +190,161,190,162,190,163,190,164,190,165,190,166,190,167,190,168,190,169,190,170, +190,171,190,172,190,173,190,174,190,175,190,176,190,177,190,178,190,179,190,180, +190,181,190,182,190,183,190,184,190,185,190,186,190,187,190,188,190,189,190,190, +190,191,190,192,190,193,190,194,190,195,190,196,190,197,190,198,190,199,190,200, +190,201,190,202,190,203,190,204,190,205,190,206,190,207,190,208,190,209,190,210, +190,211,190,212,190,213,190,214,190,215,190,216,190,217,190,218,190,219,190,220, +190,221,190,222,190,223,190,224,190,225,190,226,190,227,190,228,190,229,190,230, +190,231,190,232,190,233,190,234,190,235,190,236,190,237,190,238,190,239,190,240, +190,241,190,242,190,243,190,244,190,245,190,246,190,247,190,248,190,249,190,250, +190,251,190,252,190,253,190,254,191,161,191,162,191,163,191,164,191,165,191,166, +191,167,191,168,191,169,191,170,191,171,191,172,191,173,191,174,191,175,191,176, +191,177,191,178,191,179,191,180,191,181,191,182,191,183,191,184,191,185,191,187, +191,188,191,189,191,190,191,191,191,186,191,192,191,193,191,194,191,195,191,196, +191,197,191,198,191,199,191,200,191,201,191,202,191,203,191,204,191,206,191,207, +191,205,191,208,191,209,191,210,191,211,191,212,191,213,191,214,191,215,191,216, +191,217,191,218,191,219,191,220,191,221,191,222,191,223,191,224,191,225,191,226, +191,227,191,228,191,229,191,230,191,231,191,232,191,233,191,234,191,235,191,236, +191,237,191,238,191,239,191,240,191,241,191,242,191,243,191,244,191,245,191,246, +191,247,191,248,191,249,191,250,191,251,191,252,191,253,191,254,192,161,192,162, +192,163,192,164,192,165,192,166,192,167,192,168,192,169,192,170,192,171,192,172, +192,173,192,174,192,175,192,176,192,177,192,178,192,179,192,180,192,181,192,182, +192,183,192,184,192,185,192,186,192,187,192,188,192,189,192,190,192,191,192,192, +192,193,192,194,192,195,192,196,192,197,192,198,192,199,192,200,192,201,192,202, +192,203,192,204,192,205,192,206,192,207,192,208,192,209,192,210,192,211,192,212, +192,213,192,214,192,215,192,216,192,217,192,218,192,219,192,220,192,221,192,222, +192,223,192,224,192,225,192,226,192,227,192,228,192,229,192,230,192,231,192,232, +192,233,192,234,192,235,192,236,192,237,192,238,192,239,192,240,192,241,192,242, +192,243,192,244,192,245,192,246,192,247,192,248,192,249,192,250,192,251,192,252, +192,253,192,254,193,161,193,162,193,163,193,164,193,165,193,166,193,167,193,168, +193,169,193,170,193,171,193,172,193,173,193,174,193,175,193,176,193,177,193,178, +193,179,193,180,193,181,193,182,193,183,193,184,193,185,193,186,193,187,193,188, +193,189,193,190,193,191,193,192,193,193,193,194,193,195,193,196,193,197,193,198, +193,199,193,200,193,201,193,202,193,203,193,204,193,205,193,206,193,207,193,208, +193,209,193,210,193,211,193,212,193,213,193,214,193,215,193,216,193,217,193,218, +193,219,193,220,193,221,193,222,193,223,193,224,193,225,193,226,193,227,193,228, +193,229,193,230,193,231,193,232,193,233,193,234,193,235,193,236,193,237,193,238, +193,239,193,240,193,241,193,242,193,243,193,244,193,245,193,246,193,247,193,248, +193,249,193,250,193,251,193,252,193,253,193,254,194,161,194,162,194,163,194,164, +194,165,194,166,194,167,194,168,194,169,194,170,194,171,194,172,194,173,194,174, +194,175,194,176,194,177,194,178,194,179,194,180,194,181,194,182,194,183,194,184, +194,185,194,186,194,187,194,188,194,189,194,190,194,191,194,192,194,193,194,194, +194,195,194,196,194,197,194,198,194,199,194,200,194,201,194,202,194,203,194,204, +194,205,194,206,194,207,194,208,194,209,194,210,194,211,194,212,194,213,194,214, +194,215,194,216,194,217,194,218,194,219,194,220,194,221,194,222,194,223,194,224, +194,225,194,226,194,227,194,228,194,229,194,230,194,231,194,232,194,233,194,234, +194,235,194,236,194,237,194,238,194,239,194,240,194,241,194,242,194,243,194,244, +194,245,194,246,194,247,194,248,194,249,194,250,194,251,194,252,194,253,194,254, +195,161,195,162,195,163,195,164,195,165,195,166,195,167,195,168,195,169,195,170, +195,171,195,172,195,173,195,174,195,175,195,176,195,177,195,178,195,179,195,180, +195,181,195,182,195,183,195,184,195,185,195,186,195,187,195,188,195,189,195,190, +195,191,195,192,195,193,195,194,195,195,195,196,195,197,195,198,195,199,195,200, +195,201,195,202,195,203,195,204,195,205,195,206,195,207,195,208,195,209,195,210, +195,211,195,212,195,213,195,214,195,215,195,216,195,217,195,218,195,219,195,220, +195,221,195,222,195,223,195,224,195,225,195,226,195,227,195,228,195,229,195,230, +195,231,195,232,195,233,195,234,195,235,195,236,195,237,195,238,195,239,195,240, +195,241,195,242,195,243,195,244,195,245,195,246,195,247,195,248,195,249,195,250, +195,251,195,252,195,253,195,254,196,161,196,162,196,163,196,164,196,165,196,166, +196,167,196,168,196,169,196,170,196,171,196,172,196,173,196,174,196,175,196,176, +196,177,196,178,196,179,196,180,196,181,196,182,196,183,196,184,196,185,196,186, +196,187,196,188,196,189,196,190,196,191,196,192,196,193,196,194,196,195,196,196, +196,197,196,198,196,199,196,200,196,201,196,202,196,203,196,204,196,205,196,206, +196,207,196,208,196,209,196,210,196,211,196,212,196,213,196,214,196,215,196,216, +196,217,196,218,196,219,196,220,196,221,196,222,196,223,196,224,196,225,196,226, +196,227,196,228,196,229,196,230,196,231,196,232,196,233,196,234,196,235,196,236, +196,237,196,238,196,239,196,240,196,241,196,242,196,243,196,244,196,245,196,246, +196,247,196,248,196,249,196,250,196,251,196,252,196,253,196,254,197,161,197,162, +197,163,197,164,197,165,197,166,197,167,197,168,197,169,197,170,197,171,197,172, +197,173,197,174,197,175,197,176,197,177,197,178,197,179,197,180,197,181,197,182, +197,183,197,184,197,185,197,186,197,187,197,188,197,189,197,190,197,191,197,192, +197,193,197,194,197,195,197,196,197,197,197,198,197,199,197,200,197,201,197,202, +197,203,197,204,197,205,197,206,197,207,197,208,197,209,197,210,197,211,197,212, +197,213,197,214,197,215,197,216,197,217,197,218,197,219,197,220,197,221,197,222, +197,223,197,224,197,225,197,226,197,227,197,228,197,229,197,230,197,231,197,232, +197,233,197,234,197,235,197,236,197,237,197,238,197,239,197,240,197,241,197,242, +197,243,197,244,197,245,197,246,197,247,197,248,197,249,197,250,197,251,197,252, +197,253,197,254,198,161,198,162,198,163,198,164,198,165,198,166,198,167,198,168, +198,169,198,170,198,171,198,172,198,173,198,174,198,175,198,176,198,177,198,178, +198,179,198,180,198,181,198,182,198,183,198,184,198,185,198,186,198,187,198,188, +198,189,198,190,198,191,198,192,198,193,198,194,198,195,198,196,198,197,198,198, +198,199,198,200,198,201,198,202,198,203,198,204,198,205,198,206,198,207,198,208, +198,209,198,210,198,211,198,212,198,213,198,214,198,215,198,216,198,217,198,218, +198,219,198,220,198,221,198,222,198,223,198,224,198,225,198,226,198,227,198,228, +198,229,198,230,198,231,198,232,198,233,198,234,198,235,198,236,198,237,198,238, +198,239,198,240,198,241,198,242,198,243,198,244,198,245,198,246,198,247,198,248, +198,249,198,250,198,251,198,252,198,253,198,254,199,161,199,162,199,163,199,164, +199,165,199,166,199,167,199,168,199,169,199,170,199,171,199,172,199,173,199,174, +199,175,199,176,199,177,199,178,199,179,199,180,199,181,199,182,199,183,199,184, +199,185,199,186,199,187,199,188,199,189,199,190,199,191,199,192,199,193,199,194, +199,195,199,196,199,197,199,198,199,199,199,200,199,201,199,202,199,203,199,204, +199,205,199,206,199,207,199,208,199,209,199,210,199,211,199,212,199,213,199,214, +199,215,199,216,199,217,199,218,199,219,199,220,199,221,199,222,199,223,199,224, +199,225,199,226,199,227,199,228,199,229,199,230,199,231,199,232,199,233,199,234, +199,235,199,236,199,237,199,238,199,239,199,240,199,241,199,242,199,243,199,244, +199,245,199,246,199,247,199,248,199,249,199,250,199,251,199,252,199,253,199,254, +200,161,200,162,200,163,200,164,200,165,200,166,200,167,200,168,200,169,200,170, +200,171,200,172,200,173,200,174,200,175,200,176,200,177,200,178,200,179,200,180, +200,181,200,182,200,183,200,184,200,185,200,186,200,187,200,188,200,189,200,190, +200,191,200,192,200,193,200,194,200,195,200,196,200,197,200,198,200,199,200,200, +200,201,200,202,200,203,200,204,200,205,200,206,200,207,200,208,200,209,200,210, +200,211,200,212,200,213,200,214,200,215,200,216,200,217,200,218,200,219,200,220, +200,221,200,222,200,223,200,224,200,225,200,226,200,227,200,228,200,229,200,230, +200,231,200,232,200,233,200,234,200,235,200,236,200,237,200,238,200,239,200,240, +200,241,200,242,200,243,200,244,200,245,200,246,200,247,200,248,200,249,200,250, +200,251,200,252,200,253,200,254,201,161,201,162,201,163,201,164,201,165,201,166, +201,167,201,168,201,169,201,170,201,171,201,172,201,173,201,174,201,175,201,176, +201,177,201,178,201,179,201,180,201,181,201,182,201,183,201,184,201,185,201,186, +201,187,201,188,201,189,201,190,201,191,201,192,201,193,201,194,201,195,201,196, +201,197,201,198,201,199,201,200,201,201,201,202,201,203,201,204,201,205,201,206, +201,207,201,208,201,209,201,210,201,211,201,212,201,213,201,214,201,215,201,216, +201,217,201,218,201,219,201,220,201,221,201,222,201,223,201,224,201,225,201,226, +201,227,201,228,201,229,201,230,201,231,201,232,201,233,201,234,201,235,201,236, +201,237,201,238,201,239,201,240,201,241,201,242,201,243,201,244,201,245,201,246, +201,247,201,248,201,249,201,250,201,251,201,252,201,253,201,254,202,161,202,162, +202,163,202,164,202,165,202,166,202,167,202,168,202,169,202,170,202,171,202,172, +202,173,202,174,202,175,202,176,202,177,202,178,202,179,202,180,202,181,202,182, +202,183,202,184,202,185,202,186,202,187,202,188,202,189,202,190,202,191,202,192, +202,193,202,194,202,195,202,196,202,197,202,198,202,199,202,200,202,201,202,202, +202,203,202,204,202,205,202,206,202,207,202,208,202,209,202,210,202,211,202,212, +202,213,202,214,202,215,202,216,202,217,202,218,202,219,202,220,202,221,202,222, +202,223,202,224,202,225,202,226,202,227,202,228,202,229,202,230,202,231,202,232, +202,233,202,234,202,235,202,236,202,237,202,238,202,239,202,240,202,241,202,242, +202,243,202,244,202,245,202,246,202,247,202,248,202,249,202,250,202,251,202,252, +202,253,202,254,203,161,203,162,203,163,203,164,203,165,203,166,203,167,203,168, +203,169,203,170,203,171,203,172,203,173,203,174,203,175,203,176,203,177,203,178, +203,179,203,180,203,181,203,182,203,183,203,184,203,185,203,186,203,187,203,188, +203,189,203,190,203,191,203,192,203,193,203,194,203,195,203,196,203,197,203,198, +203,199,203,200,203,201,203,202,203,203,203,204,203,205,203,206,203,207,203,208, +203,209,203,210,203,211,203,212,203,213,203,214,203,215,203,216,203,217,203,218, +203,219,203,220,203,221,203,222,203,223,203,224,203,225,203,226,203,227,203,228, +203,229,203,230,203,231,203,232,203,233,203,234,203,235,203,236,203,237,203,238, +203,239,203,240,203,241,203,242,203,243,203,244,203,245,203,246,203,247,203,248, +203,249,203,250,203,251,203,252,203,253,203,254,204,161,204,162,204,163,204,164, +204,165,204,166,204,167,204,168,204,169,204,170,204,171,204,172,204,173,204,174, +204,175,204,176,204,177,204,178,204,179,204,180,204,181,204,182,204,183,204,184, +204,185,204,186,204,187,204,188,204,189,204,190,204,191,204,192,204,193,204,194, +204,195,204,196,204,197,204,198,204,199,204,200,204,201,204,202,204,203,204,204, +204,205,204,206,204,207,204,208,204,209,204,210,204,211,204,212,204,213,204,214, +204,215,204,216,204,217,204,218,204,219,204,220,204,221,204,222,204,223,204,224, +204,225,204,226,204,227,204,228,204,229,204,230,204,231,204,232,204,233,204,234, +204,235,204,236,204,237,204,238,204,239,204,240,204,241,204,242,204,243,204,244, +204,245,204,246,204,247,204,248,204,249,204,250,204,251,204,252,204,253,204,254, +205,161,205,162,205,163,205,164,205,165,205,166,205,167,205,168,205,169,205,170, +205,171,205,172,205,173,205,174,205,175,205,176,205,177,205,178,205,179,205,180, +205,181,205,182,205,183,205,184,205,185,205,186,205,187,205,188,205,189,205,190, +205,191,205,192,205,193,205,194,205,195,205,196,205,197,205,198,205,199,205,200, +205,201,205,202,205,203,205,204,205,205,205,206,205,207,205,208,205,209,205,210, +205,211,205,212,205,213,205,214,205,215,205,216,205,217,205,218,205,219,205,220, +205,221,205,222,205,223,205,224,205,225,205,226,205,227,205,228,205,229,205,230, +205,231,205,232,205,233,205,234,205,235,205,236,205,237,205,238,205,239,205,240, +205,241,205,242,205,243,205,244,205,245,205,246,205,247,205,248,205,249,205,250, +205,251,205,252,205,253,205,254,206,161,206,162,206,163,206,164,206,165,206,166, +206,167,206,168,206,169,206,170,206,171,206,172,206,173,206,174,206,175,206,176, +206,177,206,178,206,179,206,180,206,181,206,182,206,183,206,184,206,185,206,186, +206,187,206,188,206,189,206,190,206,191,206,192,206,193,206,194,206,195,206,196, +206,197,206,198,206,199,206,200,206,201,206,202,206,203,206,204,206,205,206,206, +206,207,206,208,206,209,206,210,206,211,206,212,206,213,206,214,206,215,206,216, +206,217,206,218,206,219,206,220,206,221,206,222,206,223,206,224,206,225,206,226, +206,227,206,228,206,229,206,230,206,231,206,232,206,233,206,234,206,235,206,236, +206,237,206,238,206,239,206,240,206,241,206,242,206,243,206,244,206,245,206,246, +206,247,206,248,206,249,206,250,206,251,206,252,206,253,206,254,207,161,207,162, +207,163,207,164,207,165,207,166,207,167,207,168,207,169,207,170,207,171,207,172, +207,173,207,174,207,175,207,176,207,177,207,178,207,179,207,180,207,181,207,182, +207,183,207,184,207,185,207,186,207,187,207,188,207,189,207,190,207,191,207,192, +207,193,207,194,207,195,207,196,207,197,207,198,207,199,207,200,207,201,207,202, +207,203,207,204,207,205,207,206,207,207,207,208,207,209,207,210,207,211,207,212, +207,213,207,214,207,215,207,216,207,217,207,218,207,219,207,220,207,221,207,222, +207,223,207,224,207,225,207,226,207,227,207,228,207,229,207,230,207,231,207,232, +207,233,207,234,207,235,207,236,207,237,207,238,207,239,207,240,207,241,207,242, +207,243,207,244,207,245,207,246,207,247,207,248,207,249,207,250,207,251,207,252, +207,253,207,254,208,161,208,162,208,163,208,164,208,165,208,166,208,167,208,168, +208,169,208,170,208,171,208,172,208,173,208,174,208,175,208,176,208,177,208,178, +208,179,208,180,208,181,208,182,208,183,208,184,208,185,208,186,208,187,208,188, +208,189,208,190,208,191,208,192,208,193,208,194,208,195,208,196,208,197,208,198, +208,199,208,200,208,201,208,202,208,203,208,204,208,205,208,206,208,207,208,208, +208,209,208,210,208,211,208,212,208,213,208,214,208,215,208,216,208,217,208,218, +208,219,208,220,208,221,208,222,208,223,208,224,208,225,208,226,208,227,208,228, +208,229,208,230,208,231,208,232,208,233,208,234,208,235,208,236,208,237,208,238, +208,239,208,240,208,241,208,242,208,243,208,244,208,245,208,246,208,247,208,248, +208,249,208,250,208,251,208,252,208,253,208,254,209,161,209,162,209,163,209,164, +209,165,209,166,209,167,209,168,209,169,209,170,209,171,209,172,209,173,209,174, +209,175,209,176,209,177,209,178,209,179,209,180,209,181,209,182,209,183,209,184, +209,185,209,186,209,187,209,188,209,189,209,190,209,191,209,192,209,193,209,194, +209,195,209,196,209,197,209,198,209,199,209,200,209,201,209,202,209,203,209,204, +209,205,209,206,209,207,209,208,209,209,209,210,209,211,209,212,209,213,209,214, +209,215,209,216,209,217,209,218,209,219,209,220,209,221,209,222,209,223,209,224, +209,225,209,226,209,227,209,228,209,229,209,230,209,231,209,232,209,233,209,234, +209,235,209,236,209,237,209,238,209,239,209,240,209,241,209,242,209,243,209,244, +209,245,209,246,209,247,209,248,209,249,209,250,209,251,209,252,209,253,209,254, +210,161,210,162,210,163,210,164,210,165,210,166,210,167,210,168,210,169,210,170, +210,171,210,172,210,173,210,174,210,175,210,176,210,177,210,178,210,179,210,180, +210,181,210,182,210,183,210,184,210,185,210,186,210,187,210,188,210,189,210,190, +210,191,210,192,210,193,210,194,210,195,210,196,210,197,210,198,210,199,210,200, +210,201,210,202,210,203,210,204,210,205,210,206,210,207,210,208,210,209,210,210, +210,211,210,212,210,213,210,214,210,215,210,216,210,217,210,218,210,219,210,220, +210,221,210,222,210,223,210,224,210,225,210,226,210,227,210,228,210,229,210,230, +210,231,210,232,210,233,210,234,210,235,210,236,210,237,210,238,210,239,210,240, +210,241,210,242,210,243,210,244,210,245,210,246,210,247,210,248,210,249,210,250, +210,251,210,252,210,253,210,254,211,161,211,162,211,163,211,164,211,165,211,166, +211,167,211,168,211,169,211,170,211,171,211,172,211,173,211,174,211,175,211,176, +211,177,211,178,211,179,211,180,211,181,211,182,211,183,211,184,211,185,211,186, +211,187,211,188,211,189,211,190,211,191,211,192,211,193,211,194,211,195,211,196, +211,197,211,198,211,199,211,200,211,201,211,202,211,203,211,204,211,205,211,206, +211,207,211,208,211,209,211,210,211,211,211,212,211,213,211,214,211,215,211,216, +211,217,211,218,211,219,211,220,211,221,211,222,211,223,211,224,211,225,211,226, +211,227,211,228,211,229,211,230,211,231,211,232,211,233,211,234,211,235,211,236, +211,237,211,238,211,239,211,240,211,241,211,242,211,243,211,244,211,245,211,246, +211,247,211,248,211,249,211,250,211,251,211,252,211,253,211,254,212,161,212,162, +212,163,212,164,212,165,212,166,212,167,212,168,212,169,212,170,212,171,212,172, +212,173,212,174,212,175,212,176,212,177,212,178,212,179,212,180,212,181,212,182, +212,183,212,184,212,185,212,186,212,187,212,188,212,189,212,190,212,191,212,192, +212,193,212,194,212,195,212,196,212,197,212,198,212,199,212,200,212,201,212,202, +212,203,212,204,212,205,212,206,212,207,212,208,212,209,212,210,212,211,212,212, +212,213,212,214,212,215,212,216,212,217,212,218,212,219,212,220,212,221,212,222, +212,223,212,224,212,225,212,226,212,227,212,228,212,229,212,230,212,231,212,232, +212,233,212,234,212,235,212,236,212,237,212,238,212,239,212,240,212,241,212,242, +212,243,212,244,212,245,212,246,212,247,212,248,212,249,212,250,212,251,212,252, +212,253,212,254,213,161,213,162,213,163,213,164,213,165,213,166,213,167,213,168, +213,169,213,170,213,171,213,172,213,173,213,174,213,175,213,176,213,177,213,178, +213,179,213,180,213,181,213,182,213,183,213,184,213,185,213,186,213,187,213,188, +213,189,213,190,213,191,213,192,213,193,213,194,213,195,213,197,213,198,213,199, +213,196,213,200,213,201,213,202,213,203,213,204,213,205,213,206,213,207,213,208, +213,209,213,210,213,211,213,212,213,213,213,214,213,215,213,216,213,217,213,218, +213,219,213,220,213,221,213,222,213,223,213,224,213,225,213,226,213,227,213,228, +213,229,213,230,213,231,213,232,213,233,213,234,213,235,213,236,213,237,213,238, +213,239,213,240,213,241,213,242,213,243,213,244,213,245,213,246,213,247,213,248, +213,249,213,250,213,251,213,252,213,253,213,254,214,161,214,162,214,163,214,164, +214,165,214,166,214,167,214,168,214,169,214,170,214,171,214,172,214,173,214,174, +214,175,214,176,214,177,214,178,214,179,214,180,214,181,214,182,214,183,214,184, +214,185,214,186,214,187,214,188,214,189,214,190,214,191,214,192,214,193,214,194, +214,195,214,196,214,197,214,198,214,199,214,200,214,201,214,202,214,203,214,204, +214,205,214,206,214,207,214,208,214,209,214,210,214,211,214,212,214,213,214,214, +214,215,214,216,214,217,214,218,214,219,214,220,214,221,214,222,214,223,214,224, +214,225,214,226,214,227,214,228,214,229,214,230,214,231,214,232,214,233,214,234, +214,235,214,236,214,237,214,238,214,239,214,240,214,241,214,242,214,243,214,244, +214,245,214,246,214,247,214,248,214,249,214,250,214,251,214,252,214,253,214,254, +215,161,215,162,215,163,215,164,215,165,215,166,215,167,215,168,215,169,215,170, +215,171,215,172,215,173,215,174,215,175,215,176,215,177,215,178,215,179,215,180, +215,181,215,182,215,183,215,184,215,185,215,186,215,187,215,188,215,189,215,190, +215,191,215,192,215,193,215,194,215,195,215,196,215,197,215,198,215,199,215,200, +215,201,215,202,215,203,215,204,215,205,215,206,215,207,215,208,215,209,215,210, +215,211,215,212,215,213,215,214,215,215,215,216,215,217,215,218,215,219,215,220, +215,221,215,222,215,223,215,224,215,225,215,226,215,227,215,228,215,229,215,230, +215,231,215,232,215,233,215,234,215,235,215,236,215,237,215,238,215,239,215,240, +215,241,215,242,215,243,215,244,215,245,215,246,215,247,215,248,215,249,216,161, +216,162,216,163,216,164,216,165,216,166,216,167,216,168,216,169,216,170,216,171, +216,172,216,173,216,174,216,175,216,176,216,177,216,178,216,179,216,180,216,181, +216,182,216,183,216,184,216,185,216,186,216,187,216,188,216,189,216,190,216,191, +216,192,216,193,216,194,216,195,216,196,216,197,216,198,216,199,216,200,216,201, +216,202,216,203,216,204,216,205,216,206,216,207,216,208,216,209,216,210,216,211, +216,212,216,213,216,214,216,215,216,216,216,217,216,218,216,219,216,220,216,221, +216,222,216,223,216,224,216,225,216,226,216,227,216,228,216,229,216,230,216,231, +216,232,216,233,216,234,216,235,216,236,216,237,216,238,216,239,216,240,216,241, +216,242,216,243,216,244,216,245,216,246,216,247,216,248,216,249,216,250,216,251, +216,252,216,253,216,254,217,161,217,162,217,163,217,164,217,165,217,166,217,167, +217,168,217,169,217,170,217,171,217,172,217,173,217,174,217,175,217,176,217,177, +217,178,217,179,217,180,217,181,217,182,217,183,217,184,217,185,217,186,217,187, +217,188,217,189,217,190,217,191,217,192,217,193,217,194,217,195,217,196,217,197, +217,198,217,199,217,200,217,201,217,202,217,203,217,204,217,205,217,206,217,207, +217,208,217,209,217,210,217,211,217,212,217,213,217,214,217,215,217,216,217,217, +217,218,217,219,217,220,217,221,217,222,217,223,217,224,217,225,217,226,217,227, +217,228,217,229,217,230,217,231,217,232,217,233,217,234,217,235,217,236,217,237, +217,238,217,239,217,240,217,241,217,242,217,243,217,244,217,245,217,246,217,247, +217,248,217,249,217,250,217,251,217,252,217,253,217,254,218,161,218,162,218,163, +218,164,218,165,218,166,218,167,218,168,218,169,218,170,218,171,218,172,218,173, +218,174,218,175,218,176,218,177,218,178,218,179,218,180,218,181,218,182,218,183, +218,184,218,185,218,186,218,187,218,188,218,189,218,190,218,191,218,192,218,193, +218,194,218,195,218,196,218,197,218,198,218,199,218,200,218,201,218,202,218,203, +218,204,218,205,218,206,218,207,218,208,218,209,218,210,218,211,218,212,218,213, +218,214,218,215,218,216,218,217,218,218,218,219,218,220,218,221,218,222,218,223, +218,224,218,225,218,226,218,227,218,228,218,229,218,230,218,231,218,232,218,233, +218,234,218,235,218,236,218,237,218,238,218,239,218,240,218,241,218,242,218,243, +218,244,218,245,218,246,218,247,218,248,218,249,218,250,218,251,218,252,218,253, +218,254,219,161,219,162,219,163,219,164,219,165,219,166,219,167,219,168,219,169, +219,170,219,171,219,172,219,173,219,174,219,175,219,176,219,177,219,178,219,179, +219,180,219,181,219,182,219,183,219,184,219,185,219,186,219,187,219,188,219,189, +219,190,219,191,219,192,219,193,219,194,219,195,219,196,219,197,219,198,219,199, +219,200,219,201,219,202,219,203,219,204,219,205,219,206,219,207,219,208,219,209, +219,210,219,211,219,212,219,213,219,214,219,215,219,216,219,217,219,218,219,219, +219,220,219,221,219,222,219,223,219,224,219,225,219,226,219,227,219,228,219,229, +219,230,219,231,219,232,219,233,219,234,219,235,219,236,219,237,219,238,219,239, +219,240,219,241,219,242,219,243,219,244,219,245,219,246,219,247,219,248,219,249, +219,250,219,251,219,252,219,253,219,254,220,161,220,162,220,163,220,164,220,165, +220,166,220,167,220,168,220,169,220,170,220,171,220,172,220,173,220,174,220,175, +220,176,220,177,220,178,220,179,220,180,220,181,220,182,220,183,220,184,220,185, +220,186,220,187,220,188,220,189,220,190,220,191,220,192,220,193,220,194,220,195, +220,196,220,197,220,198,220,199,220,200,220,201,220,202,220,203,220,204,220,205, +220,206,220,207,220,208,220,209,220,210,220,211,220,212,220,213,220,214,220,215, +220,216,220,217,220,218,220,219,220,220,220,221,220,222,220,223,220,224,220,225, +220,226,220,227,220,228,220,229,220,230,220,231,220,232,220,233,220,234,220,235, +220,236,220,237,220,238,220,239,220,240,220,241,220,242,220,243,220,244,220,245, +220,246,220,247,220,248,220,249,220,250,220,251,220,252,220,253,220,254,221,161, +221,162,221,163,221,164,221,165,221,166,221,167,221,168,221,169,221,170,221,171, +221,172,221,173,221,174,221,175,221,176,221,177,221,178,221,179,221,180,221,181, +221,182,221,183,221,184,221,185,221,186,221,187,221,188,221,189,221,190,221,191, +221,192,221,193,221,194,221,195,221,196,221,197,221,198,221,199,221,200,221,201, +221,202,221,203,221,204,221,205,221,206,221,207,221,208,221,209,221,210,221,211, +221,212,221,213,221,214,221,215,221,216,221,217,221,218,221,219,221,220,221,221, +221,222,221,223,221,224,221,225,221,226,221,227,221,228,221,229,221,230,221,231, +221,232,221,233,221,234,221,235,221,236,221,237,221,238,221,239,221,240,221,241, +221,242,221,243,221,244,221,245,221,246,221,247,221,248,221,249,221,250,221,251, +221,252,221,253,221,254,222,161,222,162,222,163,222,164,222,165,222,166,222,167, +222,168,222,169,222,170,222,171,222,172,222,173,222,174,222,175,222,176,222,177, +222,178,222,179,222,180,222,181,222,182,222,183,222,184,222,185,222,186,222,187, +222,188,222,189,222,190,222,191,222,192,222,193,222,194,222,195,222,196,222,197, +222,198,222,199,222,200,222,201,222,202,222,203,222,204,222,205,222,206,222,207, +222,208,222,209,222,210,222,211,222,212,222,213,222,214,222,215,222,216,222,217, +222,218,222,219,222,220,222,221,222,222,222,223,222,224,222,225,222,226,222,227, +222,228,222,229,222,230,222,231,222,232,222,233,222,234,222,235,222,236,222,237, +222,238,222,239,222,240,222,241,222,242,222,243,222,244,222,245,222,246,222,247, +222,248,222,249,222,250,222,251,222,252,222,253,222,254,223,161,223,162,223,163, +223,164,223,165,223,166,223,167,223,168,223,169,223,170,223,171,223,172,223,173, +223,174,223,175,223,176,223,177,223,178,223,179,223,180,223,181,223,182,223,183, +223,184,223,185,223,186,223,187,223,188,223,189,223,190,223,191,223,192,223,193, +223,194,223,195,223,196,223,197,223,198,223,199,223,200,223,201,223,202,223,203, +223,204,223,205,223,206,223,207,223,208,223,209,223,210,223,211,223,212,223,213, +223,214,223,215,223,216,223,217,223,218,223,219,223,220,223,221,223,222,223,223, +223,224,223,225,223,226,223,227,223,228,223,229,223,230,223,231,223,232,223,233, +223,234,223,235,223,236,223,237,223,238,223,239,223,240,223,241,223,242,223,243, +223,244,223,245,223,246,223,247,223,248,223,249,223,250,223,251,223,252,223,253, +223,254,224,161,224,162,224,163,224,164,224,165,224,166,224,167,224,168,224,169, +224,170,224,171,224,172,224,173,224,174,224,175,224,176,224,177,224,178,224,179, +224,180,224,181,224,182,224,183,224,184,224,185,224,186,224,187,224,188,224,189, +224,190,224,191,224,192,224,193,224,194,224,195,224,196,224,197,224,198,224,199, +224,200,224,201,224,202,224,203,224,204,224,205,224,206,224,207,224,208,224,209, +224,210,224,211,224,212,224,213,224,214,224,215,224,216,224,217,224,218,224,219, +224,220,224,221,224,222,224,223,224,224,224,225,224,226,224,227,224,228,224,229, +224,230,224,231,224,232,224,233,224,234,224,235,224,236,224,237,224,238,224,239, +224,240,224,241,224,242,224,243,224,244,224,245,224,246,224,247,224,248,224,249, +224,250,224,251,224,252,224,253,224,254,225,161,225,162,225,163,225,164,225,165, +225,166,225,167,225,168,225,169,225,170,225,171,225,172,225,173,225,174,225,175, +225,176,225,177,225,178,225,179,225,180,225,181,225,182,225,183,225,184,225,185, +225,186,225,187,225,188,225,189,225,190,225,191,225,192,225,193,225,194,225,195, +225,196,225,197,225,198,225,199,225,200,225,201,225,202,225,203,225,204,225,205, +225,206,225,207,225,208,225,209,225,210,225,211,225,212,225,213,225,214,225,215, +225,216,225,217,225,218,225,219,225,220,225,221,225,222,225,223,225,224,225,225, +225,226,225,227,225,228,225,229,225,230,225,231,225,232,225,233,225,234,225,235, +225,236,225,237,225,238,225,239,225,240,225,241,225,242,225,243,225,244,225,245, +225,246,225,247,225,248,225,249,225,250,225,251,225,252,225,253,225,254,226,161, +226,162,226,163,226,164,226,165,226,166,226,167,226,168,226,169,226,170,226,171, +226,172,226,173,226,174,226,175,226,176,226,177,226,178,226,179,226,180,226,181, +226,182,226,183,226,184,226,185,226,186,226,187,226,188,226,189,226,190,226,191, +226,192,226,193,226,194,226,195,226,196,226,197,226,198,226,199,226,200,226,201, +226,202,226,203,226,204,226,205,226,206,226,207,226,208,226,209,226,210,226,211, +226,212,226,213,226,214,226,215,226,216,226,217,226,218,226,219,226,220,226,221, +226,222,226,223,226,224,226,225,226,226,226,227,226,228,226,229,226,230,226,231, +226,232,226,233,226,234,226,235,226,236,226,237,226,238,226,239,226,240,226,241, +226,242,226,243,226,244,226,245,226,246,226,247,226,248,226,249,226,250,226,251, +226,252,226,253,226,254,227,161,227,162,227,163,227,164,227,165,227,166,227,167, +227,168,227,169,227,170,227,171,227,172,227,173,227,174,227,175,227,176,227,177, +227,178,227,179,227,180,227,181,227,182,227,183,227,184,227,185,227,186,227,187, +227,188,227,189,227,190,227,191,227,192,227,193,227,194,227,195,227,196,227,197, +227,198,227,199,227,200,227,201,227,202,227,203,227,204,227,205,227,206,227,207, +227,208,227,209,227,210,227,211,227,212,227,213,227,214,227,215,227,216,227,217, +227,218,227,219,227,220,227,221,227,222,227,223,227,224,227,225,227,226,227,227, +227,228,227,229,227,230,227,231,227,232,227,233,227,234,227,235,227,236,227,237, +227,238,227,239,227,240,227,241,227,242,227,243,227,244,227,245,227,246,227,247, +227,248,227,249,227,250,227,251,227,252,227,253,227,254,228,161,228,162,228,163, +228,164,228,165,228,166,228,167,228,168,228,169,228,170,228,171,228,172,228,173, +228,174,228,175,228,176,228,177,228,178,228,179,228,180,228,181,228,182,228,183, +228,184,228,185,228,186,228,187,228,188,228,189,228,190,228,191,228,192,228,193, +228,194,228,195,228,196,228,197,228,198,228,199,228,200,228,201,228,202,228,203, +228,204,228,205,228,206,228,207,228,208,228,209,228,210,228,211,228,212,228,213, +228,214,228,215,228,216,228,217,228,218,228,219,228,220,228,221,228,222,228,223, +228,224,228,225,228,226,228,227,228,228,228,229,228,230,228,231,228,232,228,233, +228,234,228,235,228,236,228,237,228,238,228,239,228,240,228,241,228,242,228,243, +228,244,228,245,228,246,228,247,228,248,228,249,228,250,228,251,228,252,228,253, +228,254,229,161,229,162,229,163,229,164,229,165,229,166,229,167,229,168,229,169, +229,170,229,171,229,172,229,173,229,174,229,175,229,176,229,177,229,178,229,179, +229,180,229,181,229,182,229,183,229,184,229,185,229,186,229,187,229,188,229,189, +229,190,229,191,229,192,229,193,229,194,229,195,229,196,229,197,229,198,229,199, +229,200,229,201,229,202,229,203,229,204,229,205,229,206,229,207,229,208,229,209, +229,210,229,211,229,212,229,213,229,214,229,215,229,216,229,217,229,218,229,219, +229,220,229,221,229,222,229,223,229,224,229,225,229,226,229,227,229,228,229,229, +229,230,229,231,229,232,229,233,229,234,229,235,229,236,229,237,229,238,229,239, +229,240,229,241,229,242,229,243,229,244,229,245,229,246,229,247,229,248,229,249, +229,250,229,251,229,252,229,253,229,254,230,161,230,162,230,163,230,164,230,165, +230,166,230,167,230,168,230,169,230,170,230,171,230,172,230,173,230,174,230,175, +230,176,230,177,230,178,230,179,230,180,230,181,230,182,230,183,230,184,230,185, +230,186,230,187,230,188,230,189,230,190,230,191,230,192,230,193,230,194,230,195, +230,196,230,197,230,198,230,199,230,200,230,201,230,202,230,203,230,204,230,205, +230,206,230,207,230,208,230,209,230,210,230,211,230,212,230,213,230,214,230,215, +230,216,230,217,230,218,230,219,230,220,230,221,230,222,230,223,230,224,230,225, +230,226,230,227,230,228,230,229,230,230,230,231,230,232,230,233,230,234,230,235, +230,236,230,237,230,238,230,239,230,240,230,241,230,242,230,243,230,244,230,245, +230,246,230,247,230,248,230,249,230,250,230,251,230,252,230,253,230,254,231,161, +231,162,231,163,231,164,231,165,231,166,231,167,231,168,231,169,231,170,231,171, +231,172,231,173,231,174,231,175,231,176,231,177,231,178,231,179,231,180,231,181, +231,182,231,183,231,184,231,185,231,186,231,187,231,188,231,189,231,190,231,191, +231,192,231,193,231,194,231,195,231,196,231,197,231,198,231,199,231,200,231,201, +231,202,231,203,231,204,231,205,231,206,231,207,231,208,231,209,231,210,231,211, +231,212,231,213,231,214,231,215,231,216,231,217,231,218,231,219,231,220,231,221, +231,222,231,223,231,224,231,225,231,226,231,227,231,228,231,229,231,230,231,231, +231,232,231,233,231,234,231,235,231,236,231,237,231,238,231,239,231,240,231,241, +231,242,231,243,231,244,231,245,231,246,231,247,231,248,231,249,231,250,231,251, +231,252,231,253,231,254,232,161,232,162,232,163,232,164,232,165,232,166,232,167, +232,168,232,169,232,170,232,171,232,172,232,173,232,174,232,175,232,176,232,177, +232,178,232,179,232,180,232,181,232,182,232,183,232,184,232,185,232,186,232,187, +232,188,232,189,232,190,232,191,232,192,232,193,232,194,232,195,232,196,232,197, +232,198,232,199,232,200,232,201,232,202,232,203,232,204,232,205,232,206,232,207, +232,208,232,209,232,210,232,211,232,212,232,213,232,214,232,215,232,216,232,217, +232,218,232,219,232,220,232,221,232,222,232,223,232,224,232,225,232,226,232,227, +232,228,232,229,232,230,232,231,232,232,232,233,232,234,232,235,232,236,232,237, +232,238,232,239,232,240,232,241,232,242,232,243,232,244,232,245,232,246,232,247, +232,248,232,249,232,250,232,251,232,252,232,253,232,254,233,161,233,162,233,163, +233,164,233,165,233,166,233,167,233,168,233,169,233,170,233,171,233,172,233,173, +233,174,233,175,233,176,233,177,233,178,233,179,233,180,233,181,233,182,233,183, +233,184,233,185,233,186,233,187,233,188,233,189,233,190,233,191,233,192,233,193, +233,194,233,195,233,196,233,197,233,198,233,199,233,200,233,201,233,202,233,203, +233,204,233,205,233,206,233,207,233,208,233,209,233,210,233,211,233,212,233,213, +233,214,233,215,233,216,233,217,233,218,233,219,233,220,233,221,233,222,233,223, +233,224,233,225,233,226,233,227,233,228,233,229,233,230,233,231,233,232,233,233, +233,234,233,235,233,236,233,237,233,238,233,239,233,240,233,241,233,242,233,243, +233,244,233,245,233,246,233,247,233,248,233,249,233,250,233,251,233,252,233,253, +233,254,234,161,234,162,234,163,234,164,234,165,234,166,234,167,234,168,234,169, +234,170,234,171,234,172,234,173,234,174,234,175,234,176,234,177,234,178,234,179, +234,180,234,181,234,182,234,183,234,184,234,185,234,186,234,187,234,188,234,189, +234,190,234,191,234,192,234,193,234,194,234,195,234,196,234,197,234,198,234,199, +234,200,234,201,234,202,234,203,234,204,234,205,234,206,234,207,234,208,234,209, +234,210,234,211,234,212,234,213,234,214,234,215,234,216,234,217,234,218,234,219, +234,220,234,221,234,222,234,223,234,224,234,225,234,226,234,227,234,228,234,229, +234,230,234,231,234,232,234,233,234,234,234,235,234,236,234,237,234,238,234,239, +234,240,234,241,234,242,234,243,234,244,234,245,234,246,234,247,234,248,234,249, +234,250,234,251,234,252,234,253,234,254,235,161,235,162,235,163,235,164,235,165, +235,166,235,167,235,168,235,169,235,170,235,171,235,172,235,173,235,174,235,175, +235,176,235,177,235,178,235,179,235,180,235,181,235,182,235,183,235,184,235,185, +235,186,235,187,235,188,235,189,235,190,235,191,235,192,235,193,235,194,235,195, +235,196,235,197,235,198,235,199,235,200,235,201,235,202,235,203,235,204,235,205, +235,206,235,207,235,208,235,209,235,210,235,211,235,212,235,213,235,214,235,215, +235,216,235,217,235,218,235,219,235,220,235,221,235,222,235,223,235,224,235,225, +235,226,235,227,235,228,235,229,235,230,235,231,235,232,235,233,235,234,235,235, +235,236,235,237,235,238,235,239,235,240,235,241,235,242,235,243,235,244,235,245, +235,246,235,247,235,248,235,249,235,250,235,251,235,252,235,253,235,254,236,161, +236,162,236,163,236,164,236,165,236,166,236,167,236,168,236,169,236,170,236,171, +236,172,236,173,236,174,236,175,236,176,236,177,236,178,236,179,236,180,236,181, +236,182,236,183,236,184,236,185,236,186,236,187,236,188,236,189,236,190,236,191, +236,192,236,193,236,194,236,195,236,196,236,197,236,198,236,199,236,200,236,201, +236,202,236,203,236,204,236,205,236,206,236,207,236,208,236,209,236,210,236,211, +236,212,236,213,236,214,236,215,236,216,236,217,236,218,236,219,236,220,236,221, +236,222,236,223,236,224,236,225,236,226,236,227,236,228,236,229,236,230,236,231, +236,232,236,233,236,234,236,235,236,236,236,237,236,238,236,239,236,240,236,241, +236,242,236,243,236,244,236,245,236,246,236,247,236,248,236,249,236,250,236,251, +236,252,236,253,236,254,237,161,237,162,237,163,237,164,237,165,237,166,237,167, +237,168,237,169,237,170,237,171,237,172,237,173,237,174,237,175,237,176,237,177, +237,178,237,179,237,180,237,181,237,182,237,183,237,184,237,185,237,186,237,187, +237,188,237,189,237,190,237,191,237,192,237,193,237,194,237,195,237,196,237,197, +237,198,237,199,237,200,237,201,237,202,237,203,237,204,237,205,237,206,237,207, +237,208,237,209,237,210,237,211,237,212,237,213,237,214,237,215,237,216,237,217, +237,218,237,219,237,220,237,221,237,222,237,223,237,224,237,225,237,226,237,227, +237,228,237,229,237,230,237,231,237,232,237,233,237,234,237,235,237,236,237,237, +237,238,237,239,237,240,237,241,237,242,237,243,237,244,237,245,237,246,237,247, +237,248,237,249,237,250,237,251,237,252,237,253,237,254,238,161,238,162,238,163, +238,164,238,165,238,166,238,167,238,168,238,169,238,170,238,171,238,172,238,173, +238,174,238,175,238,176,238,177,238,178,238,179,238,180,238,181,238,182,238,183, +238,184,238,185,238,186,238,187,238,188,238,189,238,190,238,191,238,192,238,193, +238,194,238,195,238,196,238,197,238,198,238,199,238,200,238,201,238,202,238,203, +238,204,238,205,238,206,238,207,238,208,238,209,238,210,238,211,238,212,238,213, +238,214,238,215,238,216,238,217,238,218,238,219,238,220,238,221,238,222,238,223, +238,224,238,225,238,226,238,227,238,228,238,229,238,230,238,231,238,232,238,233, +238,234,238,235,238,236,238,237,238,238,238,239,238,240,238,241,238,242,238,243, +238,244,238,245,238,246,238,247,238,248,238,249,238,250,238,251,238,252,238,253, +238,254,239,161,239,162,239,163,239,164,239,165,239,166,239,167,239,168,239,169, +239,170,239,171,239,172,239,173,239,174,239,175,239,176,239,177,239,178,239,179, +239,180,239,181,239,182,239,183,239,184,239,185,239,186,239,187,239,188,239,189, +239,190,239,191,239,192,239,193,239,194,239,195,239,196,239,197,239,198,239,199, +239,200,239,201,239,202,239,203,239,204,239,205,239,206,239,207,239,208,239,209, +239,210,239,211,239,212,239,213,239,214,239,215,239,216,239,217,239,218,239,219, +239,220,239,221,239,222,239,223,239,224,239,225,239,226,239,227,239,228,239,229, +239,230,239,231,239,232,239,233,239,234,239,235,239,236,239,237,239,238,239,239, +239,240,239,241,239,242,239,243,239,244,239,245,239,246,239,247,239,248,239,249, +239,250,239,251,239,252,239,253,239,254,240,161,240,162,240,163,240,164,240,165, +240,166,240,167,240,168,240,169,240,170,240,171,240,172,240,173,240,174,240,175, +240,176,240,177,240,178,240,179,240,180,240,181,240,182,240,183,240,184,240,185, +240,186,240,187,240,188,240,189,240,190,240,191,240,192,240,193,240,194,240,195, +240,196,240,197,240,198,240,199,240,200,240,201,240,202,240,203,240,204,240,205, +240,206,240,207,240,208,240,209,240,210,240,211,240,212,240,213,240,214,240,215, +240,216,240,217,240,218,240,219,240,220,240,221,240,222,240,223,240,224,240,225, +240,226,240,227,240,228,240,229,240,230,240,231,240,232,240,233,240,234,240,235, +240,236,240,237,240,238,240,239,240,240,240,241,240,242,240,243,240,244,240,245, +240,246,240,247,240,248,240,249,240,250,240,251,240,252,240,253,240,254,241,161, +241,162,241,163,241,164,241,165,241,166,241,167,241,168,241,169,241,170,241,171, +241,172,241,173,241,174,241,175,241,176,241,177,241,178,241,179,241,180,241,181, +241,182,241,183,241,184,241,185,241,186,241,187,241,188,241,189,241,190,241,191, +241,192,241,193,241,194,241,195,241,196,241,197,241,198,241,199,241,200,241,201, +241,202,241,203,241,204,241,205,241,206,241,207,241,208,241,209,241,210,241,211, +241,212,241,213,241,214,241,215,241,216,241,217,241,218,241,219,241,220,241,221, +241,222,241,223,241,224,241,225,241,226,241,227,241,228,241,229,241,230,241,231, +241,232,241,233,241,234,241,235,241,236,241,237,241,238,241,239,241,240,241,241, +241,242,241,243,241,244,241,245,241,246,241,247,241,248,241,249,241,250,241,251, +241,252,241,253,241,254,242,161,242,162,242,163,242,164,242,165,242,166,242,167, +242,168,242,169,242,170,242,171,242,172,242,173,242,174,242,175,242,176,242,177, +242,178,242,179,242,180,242,181,242,182,242,183,242,184,242,185,242,186,242,187, +242,188,242,189,242,190,242,191,242,192,242,193,242,194,242,195,242,196,242,197, +242,198,242,199,242,200,242,201,242,202,242,203,242,204,242,205,242,206,242,207, +242,208,242,209,242,210,242,211,242,212,242,213,242,214,242,215,242,216,242,217, +242,218,242,219,242,220,242,221,242,222,242,223,242,224,242,225,242,226,242,227, +242,228,242,229,242,230,242,231,242,232,242,233,242,234,242,235,242,236,242,237, +242,238,242,239,242,240,242,241,242,242,242,243,242,244,242,245,242,246,242,247, +242,248,242,249,242,250,242,251,242,252,242,253,242,254,243,161,243,162,243,163, +243,164,243,165,243,166,243,167,243,168,243,169,243,170,243,171,243,172,243,173, +243,174,243,175,243,176,243,177,243,178,243,179,243,180,243,181,243,182,243,183, +243,184,243,185,243,186,243,187,243,188,243,189,243,190,243,191,243,192,243,193, +243,194,243,195,243,196,243,197,243,198,243,199,243,200,243,201,243,202,243,203, +243,204,243,205,243,206,243,207,243,208,243,209,243,210,243,211,243,212,243,213, +243,214,243,215,243,216,243,217,243,218,243,219,243,220,243,221,243,222,243,223, +243,224,243,225,243,226,243,227,243,228,243,229,243,230,243,231,243,232,243,233, +243,234,243,235,243,236,243,237,243,238,243,239,243,240,243,241,243,242,243,243, +243,244,243,245,243,246,243,247,243,248,243,249,243,250,243,251,243,252,243,253, +243,254,244,161,244,162,244,163,244,164,244,165,244,166,244,167,244,168,244,169, +244,170,244,171,244,172,244,173,244,174,244,175,244,176,244,177,244,178,244,179, +244,180,244,181,244,182,244,183,244,184,244,185,244,186,244,187,244,188,244,189, +244,190,244,191,244,192,244,193,244,194,244,195,244,196,244,197,244,198,244,199, +244,200,244,201,244,202,244,203,244,204,244,205,244,206,244,207,244,208,244,209, +244,210,244,211,244,212,244,213,244,214,244,215,244,216,244,217,244,218,244,219, +244,220,244,221,244,222,244,223,244,224,244,225,244,226,244,227,244,228,244,229, +244,230,244,231,244,232,244,233,244,234,244,235,244,236,244,237,244,238,244,239, +244,240,244,241,244,242,244,243,244,244,244,245,244,246,244,247,244,248,244,249, +244,250,244,251,244,252,244,253,244,254,245,161,245,162,245,163,245,164,245,165, +245,166,245,167,245,168,245,169,245,170,245,171,245,172,245,173,245,174,245,175, +245,176,245,177,245,178,245,179,245,180,245,181,245,182,245,183,245,184,245,185, +245,186,245,187,245,188,245,189,245,190,245,191,245,192,245,193,245,194,245,195, +245,196,245,197,245,198,245,199,245,200,245,201,245,202,245,203,245,204,245,205, +245,206,245,207,245,208,245,209,245,210,245,211,245,212,245,213,245,214,245,215, +245,216,245,217,245,218,245,219,245,220,245,221,245,222,245,223,245,224,245,225, +245,226,245,227,245,228,245,229,245,230,245,231,245,232,245,233,245,234,245,235, +245,236,245,237,245,238,245,239,245,240,245,241,245,242,245,243,245,244,245,245, +245,246,245,247,245,248,245,249,245,250,245,251,245,252,245,253,245,254,246,161, +246,162,246,163,246,164,246,165,246,166,246,167,246,168,246,169,246,170,246,171, +246,172,246,173,246,174,246,175,246,176,246,177,246,178,246,179,246,180,246,181, +246,182,246,183,246,184,246,185,246,186,246,187,246,188,246,189,246,190,246,191, +246,192,246,193,246,194,246,195,246,196,246,197,246,198,246,199,246,200,246,201, +246,202,246,203,246,204,246,205,246,206,246,207,246,208,246,209,246,210,246,211, +246,212,246,213,246,214,246,215,246,216,246,217,246,218,246,219,246,220,246,221, +246,222,246,223,246,224,246,225,246,226,246,227,246,228,246,229,246,230,246,231, +246,232,246,233,246,234,246,235,246,236,246,237,246,238,246,239,246,240,246,241, +246,242,246,243,246,244,246,245,246,246,246,247,246,248,246,249,246,250,246,251, +246,252,246,253,246,254,247,161,247,162,247,163,247,164,247,165,247,166,247,167, +247,168,247,169,247,170,247,171,247,172,247,173,247,174,247,175,247,176,247,177, +247,178,247,179,247,180,247,181,247,182,247,183,247,184,247,185,247,186,247,187, +247,188,247,189,247,190,247,191,247,192,247,193,247,194,247,195,247,196,247,197, +247,198,247,199,247,200,247,201,247,202,247,203,247,204,247,205,247,206,247,207, +247,208,247,209,247,210,247,211,247,212,247,213,247,214,247,215,247,216,247,217, +247,218,247,219,247,220,247,221,247,222,247,223,247,224,247,225,247,226,247,227, +247,228,247,229,247,230,247,231,247,232,247,233,247,234,247,235,247,236,247,237, +247,238,247,239,247,240,247,241,247,242,247,243,247,244,247,245,247,246,247,247, +247,248,247,249,247,250,247,251,247,252,247,253,247,254,162,177,162,178,162,179, +162,180,162,181,162,182,162,183,162,184,162,185,162,186,162,187,162,188,162,189, +162,190,162,191,162,192,162,193,162,194,162,195,162,196,162,197,162,198,162,199, +162,200,162,201,162,202,162,203,162,204,162,205,162,206,162,207,162,208,162,209, +162,210,162,211,162,212,162,213,162,214,162,215,162,216,162,217,162,218,162,219, +162,220,162,221,162,222,162,223,162,224,162,225,162,226,162,229,162,230,162,231, +162,232,162,233,162,234,162,235,162,236,162,237,162,238,162,241,162,242,162,243, +162,244,162,245,162,246,162,247,162,248,162,249,162,250,162,251,162,252,164,161, +164,162,164,163,164,164,164,165,164,166,164,167,164,168,164,169,164,170,164,171, +164,172,164,173,164,174,164,175,164,176,164,177,164,178,164,179,164,180,164,181, +164,182,164,183,164,184,164,185,164,186,164,187,164,188,164,189,164,190,164,191, +164,192,164,193,164,194,164,195,164,196,164,197,164,198,164,199,164,200,164,201, +164,202,164,203,164,204,164,205,164,206,164,207,164,208,164,209,164,210,164,211, +164,212,164,213,164,214,164,215,164,216,164,217,164,218,164,219,164,220,164,221, +164,222,164,223,164,224,164,225,164,226,164,227,164,228,164,229,164,230,164,231, +164,232,164,233,164,234,164,235,164,236,164,237,164,238,164,239,164,240,164,241, +164,242,164,243,165,161,165,162,165,163,165,164,165,165,165,166,165,167,165,168, +165,169,165,170,165,171,165,172,165,173,165,174,165,175,165,176,165,177,165,178, +165,179,165,180,165,181,165,182,165,183,165,184,165,185,165,186,165,187,165,188, +165,189,165,190,165,191,165,192,165,193,165,194,165,195,165,196,165,197,165,198, +165,199,165,200,165,201,165,202,165,203,165,204,165,205,165,206,165,207,165,208, +165,209,165,210,165,211,165,212,165,213,165,214,165,215,165,216,165,217,165,218, +165,219,165,220,165,221,165,222,165,223,165,224,165,225,165,226,165,227,165,228, +165,229,165,230,165,231,165,232,165,233,165,234,165,235,165,236,165,237,165,238, +165,239,165,240,165,241,165,242,165,243,165,244,165,245,165,246,166,161,166,162, +166,163,166,164,166,165,166,166,166,167,166,168,166,169,166,170,166,171,166,172, +166,173,166,174,166,175,166,176,166,177,166,178,166,179,166,180,166,181,166,182, +166,183,166,184,166,193,166,194,166,195,166,196,166,197,166,198,166,199,166,200, +166,201,166,202,166,203,166,204,166,205,166,206,166,207,166,208,166,209,166,210, +166,211,166,212,166,213,166,214,166,215,166,216,167,161,167,162,167,163,167,164, +167,165,167,166,167,167,167,168,167,169,167,170,167,171,167,172,167,173,167,174, +167,175,167,176,167,177,167,178,167,179,167,180,167,181,167,182,167,183,167,184, +167,185,167,186,167,187,167,188,167,189,167,190,167,191,167,192,167,193,167,209, +167,210,167,211,167,212,167,213,167,214,167,215,167,216,167,217,167,218,167,219, +167,220,167,221,167,222,167,223,167,224,167,225,167,226,167,227,167,228,167,229, +167,230,167,231,167,232,167,233,167,234,167,235,167,236,167,237,167,238,167,239, +167,240,167,241,168,161,168,162,168,163,168,164,168,165,168,166,168,167,168,168, +168,169,168,170,168,171,168,172,168,173,168,174,168,175,168,176,168,177,168,178, +168,179,168,180,168,181,168,182,168,183,168,184,168,185,168,186,168,197,168,198, +168,199,168,200,168,201,168,202,168,203,168,204,168,205,168,206,168,207,168,208, +168,209,168,210,168,211,168,212,168,213,168,214,168,215,168,216,168,217,168,218, +168,219,168,220,168,221,168,222,168,223,168,224,168,225,168,226,168,227,168,228, +168,229,168,230,168,231,168,232,168,233,169,164,169,165,169,166,169,167,169,168, +169,169,169,170,169,171,169,172,169,173,169,174,169,175,169,176,169,177,169,178, +169,179,169,180,169,181,169,182,169,183,169,184,169,185,169,186,169,187,169,188, +169,189,169,190,169,191,169,192,169,193,169,194,169,195,169,196,169,197,169,198, +169,199,169,200,169,201,169,202,169,203,169,204,169,205,169,206,169,207,169,208, +169,209,169,210,169,211,169,212,169,213,169,214,169,215,169,216,169,217,169,218, +169,219,169,220,169,221,169,222,169,223,169,224,169,225,169,226,169,227,169,228, +169,229,169,230,169,231,169,232,169,233,169,234,169,235,169,236,169,237,169,238, +169,239,248,160,248,161,248,162}; +int ttunumber = sizeof(ttu); +int zzhinumber = sizeof(zzhi) / 2; + diff --git a/lci/src/lci/utf8.cpp b/lci/src/lci/utf8.cpp new file mode 100644 index 0000000..1369d06 --- /dev/null +++ b/lci/src/lci/utf8.cpp @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include "lci/utf8.h" +namespace qing { + int utf8::size(const unsigned char c) { + if ((c >> 7) == 0){ + // 0xxxxxxx + return 1; + } else if ((c >> 5) == 0b110) { + // 110xxxxx 10xxxxxx + return 2; + } else if ((c >> 4) == 0b1110) { + // 1110xxxx 10xxxxxx 10xxxxxx + return 3; + } else if ((c >> 3) == 0b11110) { + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + return 4; + } else { + return 0; + } + } + char *utf8::to_ansi(char *utf8String) { + //@20231120:楠舍科技刘仁 + //@20240528,qing:输出字符串的长度不确定 + iconv_t ic; + ic = iconv_open("GB18030", "UTF-8"); + if (ic == (iconv_t)-1){ + perror("iconv_open"); + return NULL; + } + //设置输出字符串的大小为2倍输入 + size_t InputLength = strlen(utf8String); + size_t OutputLength = InputLength * 2; + + char *ansiString = (char*)malloc(OutputLength); + if (ansiString == NULL) { + perror("malloc"); + iconv_close(ic); + return NULL; + } + + char *InputBuffer = (char*)utf8String; + char *OutputBuffer = ansiString; + + size_t result = iconv(ic, &InputBuffer, &InputLength, &OutputBuffer, &OutputLength); + if (result == (size_t)-1) { + perror("iconv"); + free(ansiString); + iconv_close(ic); + return NULL; + } + + iconv_close(ic); + + *OutputBuffer = '\0'; + return ansiString; + } +} diff --git a/lci/src/main.cpp b/lci/src/main.cpp new file mode 100644 index 0000000..ec7fa75 --- /dev/null +++ b/lci/src/main.cpp @@ -0,0 +1,1118 @@ +/* =============================================== + * 通用子系统、进程机器、进程托管服务 + * + * + * 【主函数文件】 + * + * 直接子系统调用,或者启动一个pmc子系统。 + * =============================================== + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 注册信号以优雅退出 */ +#include +#include +#include +#include +#include +#include +#include /* 解析命令行参数 */ +#include +#include +#include "boost/property_tree/json_parser.hpp" +#include "net/HttpServer.hpp" +#include "logs/Logger.hpp" +#include "th/Thread.hpp" +#include "th/Cv_wait.hpp" +#include "th/ITask.hpp" +#include "tt/Mq.h" +#include "tt/Pipe.h" + +/* 中文模式 Chinese Mode */ +#include "cn/中文化.hpp" + +/* 静态区 - 存放全局变量 */ +static const char *PMC_VERSION = "0.0.8"; /* 版本号 */ +static const size_t MSGLEN = 2048; /* 单条消息的长度 */ +static const size_t MSGCNT = 100; /* 消息条数 */ + +using namespace qing; +namespace po = boost::program_options; + + +void pmc_init(po::variables_map&); /* 初始化pmc并行机器 */ +void pmc_serve(po::variables_map&); /* pmc的http伺服器模式 */ +void parse_self_init_list(std::string&); /* 解析自启动列表文件 */ +void parse_data_from_mq(std::string&); /* 解析消息队列收到的消息 */ +std::string send_start_and_recv_pipe(const std::string& name_mq, const std::string& exec); /* 发送启动命令并且接收回复 */ +std::string send_list_and_recv_pipe(const std::string& name_mq); /* 发送启动命令并且接收回复 */ +std::string send_kill_and_recv_pipe(const std::string& name_mq, const int kill); /* 发送删除命令并且接收回复 */ + + +//------------------------------------------------------------- +//------------------------------------------------------------- +namespace qing { + +/* 子进程任务 */ +class ProcessTask: public ITask { +public: + + /* 输入一个字符串(要执行的命令),构造子进程任务(但是并没有执行起来) */ + ProcessTask(std::string cmd): cmd(cmd) {} + + /* 任务是否在运行中 */ + bool isRunning() override { return p && p->running(); } + + /* 启动任务 */ + void start() override { + if (!isRunning()) this->p = std::make_unique(cmd); } + + /* 终止该任务(并且重置子进程指针) */ + void stop() override { + if (isRunning()) { + p->terminate(); + } + p.reset(); + } + + /* 获取该任务(子进程)的命令 */ + std::string check() { return this->cmd; } + + /* 获取该子进程的pid(进程编号) */ + pid_t pid() { return p->id(); } + +private: + std::unique_ptr p; /* 子进程指针 */ + std::string cmd; /* 该进程执行的命令 */ +}; + +} + + +//------------------------------------------------------------- +//------------------------------------------------------------- +namespace qing { + + +/* + * TRANSMIT TASK 通信任务 + * (创建一个通信伺服器,它收到消息就执行回调) + */ +class Tttask: public ITask { +public: + +/* msglen: 单条消息的长度 + * msgcnt: 消息伺服长度 + * callback: 回调函数 */ +Tttask(const size_t msglen, size_t msgcnt, const sf_t callback) +: msglen(msglen), msgcnt(msgcnt) { + this->callback = std::make_unique(callback); + init_thread(); +} + +/* 启动该通信伺服任务 */ +void start() override { + if (!this->isRunning()){ + th->Activate(); + th->WaitStart(); /* TODO: add timeout 增加超时 */ + } +} + +/* 终止这个通信伺服任务 */ +void stop() override { th->WaitClose(); } + +/* 该任务是否在运行 + * + * FIXME: 对START状态的处理还应该考虑 */ +bool isRunning() override { + auto stat = th->check(); + return !(stat == Fsm::Stat::STOP + || stat == Fsm::Stat::SHUT); +} + + +private: +std::unique_ptr th; /* 可控线程指针 */ +std::unique_ptr callback; /* 回调行为(接收之后)指针 */ +std::unique_ptr mq; /* 消息队列指针 */ +size_t msglen=0, msgcnt=0; /* 消息的缓存规格 */ +std::string name; /* 消息队列名(进程号) */ + + + + +/* 获取当前进程编号,用于设置消息队列的名字 */ +std::string get_pid_str() { return std::to_string(getpid()); } + +/* 初始化通信伺服线程 */ +void init_thread() { + + + this->th = std::make_unique ( + + /* stop callback 静止事件 */ + [](Thread& th) -> void { + th.suspend(); + }, + + /* start callback 唤醒事件 */ + [this](Thread& th) -> void { + name = get_pid_str(); + mq = std::make_unique (name, msglen, msgcnt, Mq::CREATOR); + th.run(); + }, + + /* loop callback 循环事件 */ + [this](Thread& th) -> void { + + /* TODO: 作为参数传入延时 */ + mq->recv(*callback, []() { usleep(10000); }); + }, + + /* clean callback 清理事件 */ + [this] (Thread& th) -> void { + mq.reset(); + } + + ); + + +} + + + +}; +} + + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +Cv_wait cv = Cv_wait(); /* 条件变量的等待机制(让主程序等待中断信号) */ + +auto taskPool = std::vector>{}; /* 底层任务池 - !!! 非子进程 !!! */ + + + +namespace qing { + + + +/* process pool 进程池 - 这个池子只放子进程 */ +class PPool { +public: + + + /* CREATE PROCESS - 创建进程 + * + * cmd: 启动命令 */ + void crtp(const std::string& cmd) try { + auto pt = std::make_shared(cmd); + pt->start(); + pool.push_back(pt); + } + + catch (boost::process::process_error &exp) { + std::cerr << "Failed to execute this command: " << cmd << std::endl; + } + + + /* CLEAR 清理 - 删除所有已经停下的进程 */ + void clr() { + auto it = --pool.end(); + for (; it != pool.begin(); --it) + if (!(*it)-> isRunning()) { + auto tmp= it; + it++; + pool.erase(tmp); /* 自动释放 */ + } + + if (pool.size() > 0 && !(*it)->isRunning()) + pool.erase(it); /* 如果end() == begin(),此步将会试图删除哨兵 */ + } + + + /* 获取进程池的大小 */ + size_t size() { return pool.size(); } + + + /* 删除一个进程,需要输入进程的下标。 FIXME: 似乎不太自然 */ + void kill(int idx) { + auto it = pool.begin(); + int i = 0; + for (; i < idx && it != pool.end(); ++i, ++it); + + /* 如果找到了目标(计数器没有指向尾节点) */ + if (it != pool.end()) { + (*it)->stop(); + pool.erase(it); + } + } + + /* 取下标运算符重载 - 取元素对象 */ + ProcessTask& operator[](const size_t idx) { + auto it = pool.begin(); + for (int i = 0; i < idx; ++it, ++i) + if (it == pool.end()) + throw std::out_of_range("PPool::operator[]"); + return **it; + } + + /* TODO: begin()、end() + * ...... */ + +private: + + /* 进程任务的容器 */ + std::list> pool{}; + +}; +} + +PPool ppool; /* 用于存放子进程的进程池 */ + + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +namespace qing { + + + +/* 只用于该处的pmc子进程操作 */ +namespace pmc_mtd { + +/* 列举出所有子进程,包含序号、pid、执行命令。 + * + * { + * "pipe": "", + * "type": "list", + * } + * + */ +static auto list() -> std::string { + boost::json::array processes; + + for (int i = 0; i < ppool.size(); ++i) { + processes.push_back({ + {"index", i}, + {"pid", ppool[i].pid()}, + {"status", ppool[i].check()} + }); + } + + return boost::json::serialize(processes); +} + +/* 删除一个子进程,需要提供pid + * + * { + * "pipe": "", + * "type": "kill", + * "kill": + * } + * + */ +static auto kill(const int pid) -> bool { + for (int i=0; i", + * "type": "exec", + * "exec": "" + * } + * + */ +static auto exec(const std::string& cmd) -> bool try { + ppool.clr(); + ppool.crtp(cmd); + return true; +} + +catch(std::exception& exp) { + return false; +} + + +} +} + + + +/*==============================================================*/ +/* 这些是尚未整理的工具 */ + +/* json字符串转boost.ptree + * FIXME: 这个方法好像在ProcessManagerService进程托管服务中集成了*/ +boost::property_tree::ptree parseJsonToPtree(const std::string& jsonStr) { + boost::property_tree::ptree pt; + try { + std::stringstream ss(jsonStr); + boost::property_tree::read_json(ss, pt); + } catch (const boost::property_tree::json_parser_error& e) { + // 解析失败处理 + std::cerr << "JSON parse error: " << e.what() << std::endl; + } + return pt; +} + +/* url 解码 */ +static std::string url_decode(const std::string& str) { + std::string result; + std::istringstream iss(str); + char ch; + + while (iss.get(ch)) { + if (ch == '%') { + int hex; + if (iss >> std::hex >> hex) { + result += static_cast(hex); + } + } else if (ch == '+') { + result += ' '; + } else { + result += ch; + } + } + return result; +} + + +/* ============================================================== */ +namespace qing { +/** + * @brief 进程托管服务类 + * + * 提供进程的列表、执行和终止功能 + */ +class ProcessManagerService { +public: + /** + * @brief 构造函数 + * @param server HTTP服务器引用 + */ + explicit ProcessManagerService(pmc::net::HttpServer& server); + + /** + * @brief 注册所有进程管理相关的路由 + */ + void registerRoutes(); + +private: + pmc::net::HttpServer& server_; + + /** + * @brief 解析请求体中的JSON数据 + * @param body 请求体字符串 + * @return JSON解析后的属性树 + */ + boost::property_tree::ptree parseJsonBody(const std::string& body); + + /** + * @brief 构建JSON响应 + * @param success 是否成功 + * @param message 消息 + * @param data 附加数据 + * @return JSON字符串 + */ + std::string buildJsonResponse(bool success, const std::string& message, + const boost::property_tree::ptree& data = boost::property_tree::ptree()); + + /** + * @brief 从请求中提取target参数 + * @param params 查询参数 + * @return target值(空字符串表示本机) + */ + std::string getTarget(const std::unordered_map& params); + + /** + * @brief 从请求中提取exec参数 + * @param params 查询参数 + * @return 要执行的指令 + */ + std::string getExecCommand(const std::unordered_map& params); + + /** + * @brief 从请求中提取kill参数 + * @param params 查询参数 + * @return 目标进程号 + */ + int getPid(const std::unordered_map& params); + + // POST方法处理器 + http::response handleList( + const http::request& req, + const std::unordered_map& params); + + http::response handleExec( + const http::request& req, + const std::unordered_map& params); + + http::response handleKill( + const http::request& req, + const std::unordered_map& params); + + // 内部实现函数(留空) + std::string listProcesses(const std::string& target); + std::string execCommand(const std::string& command, const std::string& target); + bool killProcess(int pid, const std::string& target); +}; + + +ProcessManagerService::ProcessManagerService(pmc::net::HttpServer& server) + : server_(server) { +} + +void ProcessManagerService::registerRoutes() { + // 注册POST路由 + server_.post("/list", [this](const auto& req, const auto& params) { + return this->handleList(req, params); + }); + + server_.post("/exec", [this](const auto& req, const auto& params) { + return this->handleExec(req, params); + }); + + server_.post("/kill", [this](const auto& req, const auto& params) { + return this->handleKill(req, params); + }); +} + +boost::property_tree::ptree ProcessManagerService::parseJsonBody(const std::string& body) { + boost::property_tree::ptree pt; + try { + std::stringstream ss(body); + boost::property_tree::read_json(ss, pt); + } catch (...) { + // JSON解析失败,返回空树 + } + return pt; +} + +std::string ProcessManagerService::buildJsonResponse(bool success, const std::string& message, + const boost::property_tree::ptree& data) { + boost::property_tree::ptree response; + response.put("success", success); + response.put("message", message); + if (!data.empty()) { + response.add_child("data", data); + } + + std::stringstream ss; + boost::property_tree::write_json(ss, response); + return ss.str(); +} + +std::string ProcessManagerService::getTarget(const std::unordered_map& params) { + auto it = params.find("target"); + if (it != params.end()) { + return url_decode(it->second); // <--- 这里 + } + return ""; +} + +std::string ProcessManagerService::getExecCommand(const std::unordered_map& params) { + auto it = params.find("command"); + if (it != params.end()) { + return url_decode(it->second); // <--- 这里 + } + return ""; +} + +int ProcessManagerService::getPid(const std::unordered_map& params) { + auto it = params.find("pid"); + if (it != params.end()) { + std::string decoded = url_decode(it->second); // <--- 这里 + return std::stoi(decoded); + } + return -1; +} + +http::response ProcessManagerService::handleList( + const http::request& req, + const std::unordered_map& params) { + + http::response res; + res.version(req.version()); + res.set(http::field::content_type, "application/json"); + + try { + std::string target = getTarget(params); + + std::string result = listProcesses(target); + boost::property_tree::ptree data = parseJsonToPtree(result); + + res.result(http::status::ok); + res.body() = buildJsonResponse(true, "Process list retrieved successfully", data); + } catch (const std::exception& e) { + res.result(http::status::internal_server_error); + res.body() = buildJsonResponse(false, std::string("Error: ") + e.what()); + } + + res.prepare_payload(); + return res; +} + +http::response ProcessManagerService::handleExec( + const http::request& req, + const std::unordered_map& params) { + + http::response res; + res.version(req.version()); + res.set(http::field::content_type, "application/json"); + + try { + std::string target = getTarget(params); + std::string command = getExecCommand(params); + + if (command.empty()) { + // 尝试从POST body中获取command + auto body_json = parseJsonBody(req.body()); + command = body_json.get("command", ""); + } + + if (command.empty()) { + res.result(http::status::bad_request); + res.body() = buildJsonResponse(false, "Missing required parameter: command"); + res.prepare_payload(); + return res; + } + + // TODO: 实现命令执行逻辑 + std::string result = execCommand(command, target); + + boost::property_tree::ptree data; + data.put("command", command); + data.put("output", result); + + res.result(http::status::ok); + res.body() = buildJsonResponse(true, "Command executed successfully", data); + } catch (const std::exception& e) { + res.result(http::status::internal_server_error); + res.body() = buildJsonResponse(false, std::string("Error: ") + e.what()); + } + + res.prepare_payload(); + return res; +} + +http::response ProcessManagerService::handleKill( + const http::request& req, + const std::unordered_map& params) { + + http::response res; + res.version(req.version()); + res.set(http::field::content_type, "application/json"); + + try { + std::string target = getTarget(params); + int pid = getPid(params); + + if (pid <= 0 && !req.body().empty()) { + // 尝试从POST body中获取pid + auto body_json = parseJsonBody(req.body()); + pid = body_json.get("pid", -1); + } + + if (pid <= 0) { + res.result(http::status::bad_request); + res.body() = buildJsonResponse(false, "Missing or invalid parameter: pid"); + res.prepare_payload(); + return res; + } + + bool success = killProcess(pid, target); + + if (success) { + boost::property_tree::ptree data; + data.put("pid", pid); + res.result(http::status::ok); + res.body() = buildJsonResponse(true, "Process terminated successfully", data); + } else { + res.result(http::status::internal_server_error); + res.body() = buildJsonResponse(false, "Failed to terminate process"); + } + } catch (const std::exception& e) { + res.result(http::status::internal_server_error); + res.body() = buildJsonResponse(false, std::string("Error: ") + e.what()); + } + + res.prepare_payload(); + return res; +} + +// 如果target为空,在本机执行 +// 否则在目标服务器执行 +std::string ProcessManagerService::listProcesses(const std::string& target) +{ + if (target == "") + return pmc_mtd::list(); + else { + return send_list_and_recv_pipe(target); + } +} + +std::string ProcessManagerService::execCommand(const std::string& command, const std::string& target) +{ + if (target == "") + return pmc_mtd::exec(command) ? "OK" :"ERR"; + else { + return send_start_and_recv_pipe(target, command); /* 发送启动命令并且接收回复 */ + } +} + +bool ProcessManagerService::killProcess(int pid, const std::string& target) +{ + if (target == "") + return pmc_mtd::kill(pid); + else + return send_kill_and_recv_pipe(target, pid) == "OK"; +} +} + + +std::unique_ptr server; +/*-------------------------------------------------------------------------*/ + + +/* 捕获中断信号,结束线程并且退出 */ +void signalHandler(int signum) +{ + LOG_INFO("收到终止信号,准备停止服务器..."); + cv.WakeCv(); /* 唤醒条件信号即关闭程序 */ + if (server) + server->stop(); /* TODO: 封装成ITask */ +} + +/*---------------- SIGNAL ACTION ----------------*/ +// +/* 对信号的响应行为 TODO: 我应该系统地学习一下这个库 */ +void set_signal_action() { + + /* 该结构体用于描述信号的处理方式 */ + struct sigaction sa; + + + /* 绑定处理函数 */ + sa.sa_handler = signalHandler; + + /* + * 清空并初始化一个信号掩码集 --------------> 用于指定哪些信号在当前或即将执行的信号处理函数期间应该被阻塞(位掩码) + * “在执行这个信号处理函数时,除了当前正在处理的信号外,还希望临时阻塞其他某些信号” + * 不阻塞其他信号 + * 确保在执行期间没有其他特定的信号会被阻塞 + * 防止处理过程中被其他信号中断 + */ + sigemptyset(&sa.sa_mask); + + /* + * 用于设置信号处理函数的行为特性。 + * 0 - 默认选项 + * SA_NODEFER - 表示在执行信号处理函数时不允许其他信号被阻塞 + * SA_RESETHAND - 在信号处理函数返回后,将信号的处理方式重置为默认 + * SA_NOCLDSTOP - 对于子进程发送的停止信号,父进程不会停止。 + * SA_NOCLDWAIT - 父进程在等待等待子进程终止时不会因为子进程发送信号而收到通知 + * SA_SIGINFO - 使用扩展的信号信息,信号处理函数接收三个参数而不是一个 + */ + sa.sa_flags = 0; + + /* 注册信号 */ + sigaction(SIGINT, &sa, nullptr); /* Ctrl + C */ + sigaction(SIGTERM, &sa, nullptr); /* kill 或 systemctl stop */ + +} + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +/* 入口函数 */ +int main(int argc, char** argv) { + + /*------------------------------*/ + /* 设置信号行为*/ + set_signal_action(); + + /*------------------------------*/ + /* 解析命令行参数 */ + po::options_description desc("pmc subsystem start options"); + desc.add_options() /* 定义选项 */ + ("help,h", "display help message") /* 帮助菜单 */ + ("version,v", "display version message") /* 显示版本 */ + /******** 子系统调用模式 *********/ + ("send,s", po::value(), "send a message to pmc sys") /* 输入目标pid */ + ("exec", po::value(), "message body") /* 启动一个进程 */ + ("list", "list process all run") /* 列出运行中的进程 */ + ("kill", po::value(), "kill a process") /* 杀死一个进程 */ + /********* 子系统服务模式 ********/ + ("init,i", po::value(), "self-init list") /* 输入自启动列表 */ + ("serve", po::value(), "Run as http server"); /* 启用http伺服器 */ + + /* 参数变量映射关系 */ + po::variables_map vm; + + try { /* 开始解析 */ + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + if (vm.count("help")) { /* 获取帮助页面 */ + std::cout << desc << std::endl; + return 0; + } + if (vm.count("version")) { /* 获取版本信息 */ + std::cout << PMC_VERSION << std::endl; + return 0; + } + } + + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + std::cerr << "using --help to check options message" << std::endl; + throw e; + } + + /*----------------------------------------*/ + /* 初始化OpenSSL */ + //OpenSSL_add_all_algorithms(); + //ERR_load_crypto_strings(); + + if ( vm.count("send") && vm.count("exec")) { + auto send = vm["send"].as(); + auto exec = vm["exec"].as (); + auto msg = send_start_and_recv_pipe(send, exec); + std::cout << msg << std::endl; + return 0; + } + + else if ( vm.count("send") && vm.count("list")){ + auto send = vm["send"].as (); + auto msg = send_list_and_recv_pipe(send); + std::cout << msg << std::endl; + return 0; + } + + else if (vm.count("send") && vm.count("kill")) { + auto send = vm["send"].as (); + auto kill = vm["kill"].as(); + auto msg = send_kill_and_recv_pipe(send, kill); + std::cout << msg << std::endl; + return 0; + } + + /* 初始化日志模块 */ + Logger::getInstance().init(LogLevel::DEBUG, true); + + + /* 列表自启动 */ + if (vm.count("init")){ + std::string path = vm["init"].as(); + parse_self_init_list(path); + } + + + /**********************************************/ + + /* TODO: 抽象出来 */ + if (vm.count("serve")) + pmc_serve(vm); + + else if (!vm.count("serve")) { + /* pmc初始化函数 */ + pmc_init(vm); + + /* 清理 OpenSSL 资源 */ + //EVP_cleanup(); + //ERR_free_strings(); + + + /* + * 等待 + * + * 触发器在信号处理那里 + */ + cv.Wait(); + + /* 主线程被唤醒 */ + for (auto& task: taskPool) { + task->stop(); + } + } +} + + + + +/*-----------------------------------------------------------------------------*/ +/* 初始化子系统 */ +void pmc_init(po::variables_map& vm) { + + /*-------------------*/ + auto ttt = std::make_shared (MSGLEN, MSGCNT, + [](const char *data) { /* 处理收到的数据 */ + auto json_str = std::string(data); + parse_data_from_mq(json_str); + }); + ttt->start(); + taskPool.push_back(ttt); +} + +/* http伺服器模式(只监听本地)TODO: 集成为ITask */ +void pmc_serve(po::variables_map& vm) +{ + int port = vm["serve"].as(); + server = std::make_unique("127.0.0.1", port, 4); + ProcessManagerService pmService(*server); + pmService.registerRoutes(); + server->start(); + + std::cout << "Process Manager Service running on port " << port << std::endl; + std::cout << "Available endpoints:" << std::endl; + std::cout << " POST /list?target=optional" << std::endl; + std::cout << " POST /exec?command=ls&target=optional" << std::endl; + std::cout << " POST /kill?pid=1234&target=optional" << std::endl; + + server->run(); +} + +/* 解析自启动列表、添加自启动项 */ +void parse_self_init_list(std::string &path) +try { + + std::ifstream file(path); + if (!file.is_open()) { + std::cerr << "Failed to open self-init list" << std::endl; + return; + } + + std::string row = ""; + char ch; + while (file.get(ch)) + + if (ch == '\n') { + + auto pos = row.find("#"); + if (pos != -1) + row = row.substr(0, pos); + if (row != "") { + ppool.clr(); + ppool.crtp(row); + row = ""; + } + } + + else row += ch; + +} + +catch (std::exception &exp) { + std::cerr << "Exception at: parse_self_init_list()" << std::endl; + std::cerr << "Exception type: " << typeid(exp).name() << std::endl; + std::cerr << "Exception info: " << exp.what() << std::endl; +} + + +/* 解析从消息队列中接收到的数据,运行在服务端 */ +void parse_data_from_mq(std::string& json_str) +try { + boost::json::value jv = boost::json::parse(json_str); + std::string namepipe = jv.at("pipe").as_string().c_str(); + std::string typ = jv.at("type").as_string().c_str(); + auto pipe = Pipe(namepipe, Pipe::USER); + pipe.openForWrite(); + + + if (typ == "list") { + auto msg = pmc_mtd::list(); + pipe.writePipe(msg); + return; + } + + else if (typ == "kill") { + int trg = jv.at("kill").as_int64(); + auto flag = pmc_mtd::kill(trg); + std::string msg = flag ? "OK" : "Nope"; + pipe.writePipe(msg); + return; + } + + else if (typ == "exec"){ + std::string cmd = jv.at("exec").as_string().c_str(); + std::string msg = (pmc_mtd::exec(cmd)) ? "OK" : "ERR"; + pipe.writePipe(msg); + return; + } +} + +catch (std::exception &exp) { + std::cerr << "Exception at: parse_data_from_mq()" << std::endl; + std::cerr << "Exception type: " << typeid(exp).name() << std::endl; + std::cerr << "Exception info: " << exp.what() << std::endl; +} + + + + +/*-----------------------------------------------------------------------------*/ +/*-----------------------------------------------------------------------------*/ +/* 子系统调用 TODO: 使用非boost.variables_map参数 */ + + +/* 向pmc的消息队列发送启动命令并且从管道接收回复 */ +std::string send_start_and_recv_pipe(const std::string& name_mq, const std::string& exec) +try { + + auto name_pipe = std::to_string(getpid()); + auto mq = Mq(name_mq, 2048, 100, Mq::USER); /* 放在这里避免管道文件的残留 */ + + boost::json::object obj; + obj["pipe"] = name_pipe; + obj["type"] = "exec"; + obj["exec"] = exec; + auto jsonstr = boost::json::serialize(obj); + + + auto pipe = Pipe(name_pipe, Pipe::CREATOR); /* FIXME: 创建管道文件到/tmp下面 */ + if (!pipe.openForRead(true)) { + std::cerr << "Failed to open pipe" << std::endl; + return "ERR"; + } + + mq.send(jsonstr); + if (!pipe.waitForRead(1, 0)) { + std::cerr << "Pipe Read Timeout" << std::endl; + return "ERR"; + } + + std::string res = ""; + if (pipe.readPipe(&res) < 0) { + std::cerr << "Failed to read pipe" << std::endl; + return "ERR"; + } + + return res; +} + +//catch (boost::interprocess::interprocess_exception &exp) { +// std::cerr << "Target Pmc Is Not Found" << std::endl; +// return 1; +//} + +catch (std::exception &exp) { + std::cerr << "Exception at: send_start_and_recv_pipe()" << std::endl; + std::cerr << "Exception type: " << typeid(exp).name() << std::endl; + std::cerr << "Exception info: " << exp.what() << std::endl; + return "ERR"; +} + + + + +/* 向目标子系统发送列举命令并收集结果 */ +std::string send_list_and_recv_pipe(const std::string& name_mq) +try { + + auto name_pipe = std::to_string(getpid()); + auto mq = Mq(name_mq, 2048, 100, Mq::USER); + + boost::json::object obj; + obj["pipe"] = name_pipe; + obj["type"] = "list"; + auto jsonstr = boost::json::serialize(obj); + auto pipe = Pipe(name_pipe, Pipe::CREATOR); + + if (!pipe.openForRead(true)) { + std::cerr << "Failed to open pipe" << std::endl; + return "ERR"; + } + + + mq.send(jsonstr); + if (!pipe.waitForRead(1, 0)) { + std::cerr << "Pipe Read Timeout" << std::endl; + return "ERR"; + } + + std::string res = ""; + if (pipe.readPipe(&res) < 0) { + std::cerr << "Failed to read pipe" << std::endl; + return "ERR"; + } + + + return res; + +} + +//catch (boost::interprocess::interprocess_exception &exp) { +// std::cerr << "Target Pmc Is Not Found" << std::endl; +// return 1; +//} + +catch (std::exception &exp) { + std::cerr << "Exception at: send_list_and_recv_pipe()" << std::endl; + std::cerr << "Exception type: " << typeid(exp).name() << std::endl; + std::cerr << "Exception info: " << exp.what() << std::endl; + return "ERR"; +} + + + +/* 删除操作调用 */ +std::string send_kill_and_recv_pipe(const std::string& name_mq, const int kill) +try{ + + auto name_pipe = std::to_string(getpid()); + auto mq = Mq(name_mq, 2048, 100, Mq::USER); + + boost::json::object obj; + obj["pipe"] = name_pipe; + obj["type"] = "kill"; + obj["kill"] = kill; + auto jsonstr = boost::json::serialize(obj); + + auto pipe = Pipe(name_pipe, Pipe::CREATOR); + if (!pipe.openForRead(true)) { + std::cerr << "Failed to open pipe" << std::endl; + return "ERR"; + } + + mq.send(jsonstr); + if (!pipe.waitForRead(1, 0)) { + std::cerr << "Pipe Read Timeout" << std::endl; + return "ERR"; + } + + std::string res = ""; + if (pipe.readPipe(&res) < 0) { + std::cerr << "Failed to read pipe" << std::endl; + return "ERR"; + } + else return res; + +} + +/* 没有打开目标子系统的消息队列时,会触发这个异常 + * 但是实际上这里捕获的是进程间通信通用异常 */ +//catch (boost::interprocess::interprocess_exception &exp) { +// std::cerr << "Target Pmc Is Not Found" << std::endl; +// return 1; +//} + +/* 这些函数抛出异常后可能导致管道文件残留 */ +catch (std::exception &exp) { + std::cerr << "Exception at: send_kill_and_recv_pipe()" << std::endl; + std::cerr << "Exception type: " << typeid(exp).name() << std::endl; + std::cerr << "Exception info: " << exp.what() << std::endl; + return "ERR"; +} diff --git a/lci/src/mainAgent.cpp b/lci/src/mainAgent.cpp new file mode 100644 index 0000000..0daf605 --- /dev/null +++ b/lci/src/mainAgent.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "net/HttpClient.hpp" +#include "net/WebSocketServer.hpp" +#include "llm/LLMClient.hpp" +#include "llm/LLMWebSocketServer.hpp" + +// 全局变量用于信号处理 +std::atomic g_running{true}; + +// 从文件读取API密钥 +std::string read_api_key_from_file(const std::string& filepath) { + std::ifstream file(filepath); + if (!file.is_open()) { + throw std::runtime_error("无法打开密钥文件: " + filepath); + } + + std::string api_key; + std::getline(file, api_key); + + // 去除可能的空白字符 + api_key.erase(0, api_key.find_first_not_of(" \t\n\r\f\v")); + api_key.erase(api_key.find_last_not_of(" \t\n\r\f\v") + 1); + + if (api_key.empty()) { + throw std::runtime_error("密钥文件为空: " + filepath); + } + + return api_key; +} + +int main(int argc, char* argv[]) { + // 解析命令行参数 + std::string api_key; + unsigned short port = 8080; + std::string key_file_path = std::string(getenv("HOME")) + "/.cert/deepseek.key"; + + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "--key-file" && i + 1 < argc) { + key_file_path = argv[++i]; + } else if (arg == "--port" && i + 1 < argc) { + port = static_cast(std::stoi(argv[++i])); + } else if (arg == "--help") { + std::cout << "用法: " << argv[0] << " [--key-file <密钥文件路径>] [--port <端口号>]" << std::endl; + std::cout << "默认密钥文件路径: ~/.cert/deepseek.key" << std::endl; + return 0; + } + } + + try { + // 从文件读取API密钥 + std::cout << "正在从文件加载API密钥: " << key_file_path << std::endl; + api_key = read_api_key_from_file(key_file_path); + std::cout << "API密钥加载成功" << std::endl; + } catch (const std::exception& e) { + std::cerr << "错误: " << e.what() << std::endl; + std::cerr << "请确保密钥文件存在且包含有效的API密钥" << std::endl; + std::cerr << "默认路径: ~/.cert/deepseek.key" << std::endl; + std::cerr << "或使用 --key-file 参数指定其他路径" << std::endl; + return 1; + } + + // 创建并启动服务器 + pmc::llm::LLMWebSocketServer server(api_key, port); + + // 设置信号处理 + signal(SIGINT, [](int) { + g_running = false; + }); + + try { + server.start(); + + // 主循环,等待信号 + while (g_running) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + + // 停止服务器 + server.stop(); + + } catch (const std::exception& e) { + std::cerr << "服务器错误: " << e.what() << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/lci/src/mainAgentFrontend.cpp b/lci/src/mainAgentFrontend.cpp new file mode 100644 index 0000000..2cfcb0d --- /dev/null +++ b/lci/src/mainAgentFrontend.cpp @@ -0,0 +1,582 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast = boost::beast; +namespace http = beast::http; +namespace websocket = beast::websocket; +namespace net = boost::asio; +namespace ssl = net::ssl; +using tcp = boost::asio::ip::tcp; + +// 获取 MIME 类型 +std::string get_mime_type(const std::string& path) { + if (path.ends_with(".html") || path.ends_with(".htm")) return "text/html"; + if (path.ends_with(".css")) return "text/css"; + if (path.ends_with(".js")) return "application/javascript"; + if (path.ends_with(".json")) return "application/json"; + if (path.ends_with(".png")) return "image/png"; + if (path.ends_with(".jpg") || path.ends_with(".jpeg")) return "image/jpeg"; + if (path.ends_with(".gif")) return "image/gif"; + if (path.ends_with(".svg")) return "image/svg+xml"; + if (path.ends_with(".ico")) return "image/x-icon"; + return "text/plain"; +} + +// 读取文件内容 +std::string read_file(const std::string& path) { + try { + std::ifstream file(path, std::ios::binary); + if (!file) return ""; + + std::string content; + file.seekg(0, std::ios::end); + content.resize(file.tellg()); + file.seekg(0, std::ios::beg); + file.read(&content[0], content.size()); + return content; + } catch (...) { + return ""; + } +} + +// WebSocket 客户端,用于连接LLM后端 +class WebSocketClient : public std::enable_shared_from_this { +public: + WebSocketClient(net::io_context& ioc, const std::string& host, const std::string& port) + : resolver_(net::make_strand(ioc)) + , ws_(net::make_strand(ioc)) + , host_(host) + , port_(port) + , connected_(false) {} + + void connect() { + resolver_.async_resolve(host_, port_, + beast::bind_front_handler(&WebSocketClient::on_resolve, shared_from_this())); + } + + void send(const std::string& message) { + if (!connected_) { + std::cerr << "Cannot send: not connected to backend" << std::endl; + return; + } + + // 将消息放入队列 + { + std::lock_guard lock(queue_mutex_); + send_queue_.push(message); + } + + // 如果当前没有在发送,开始发送 + if (!sending_) { + send_next(); + } + } + + void set_message_handler(std::function handler) { + message_handler_ = handler; + } + + bool is_connected() const { return connected_; } + +private: + + void on_resolve(beast::error_code ec, tcp::resolver::results_type results) { + if (ec) { + std::cerr << "Resolve error: " << ec.message() << std::endl; + return; + } + + beast::get_lowest_layer(ws_).async_connect(results, + beast::bind_front_handler(&WebSocketClient::on_connect, shared_from_this())); + } + + void on_connect(beast::error_code ec, tcp::resolver::results_type::endpoint_type) { + if (ec) { + std::cerr << "Connect error: " << ec.message() << std::endl; + return; + } + + ws_.async_handshake(host_, "/", + beast::bind_front_handler(&WebSocketClient::on_handshake, shared_from_this())); + } + + void on_handshake(beast::error_code ec) { + if (ec) { + std::cerr << "Handshake error: " << ec.message() << std::endl; + return; + } + + std::cout << "Connected to LLM backend at " << host_ << ":" << port_ << std::endl; + connected_ = true; + + // 开始接收消息 + do_read(); + + // 发送欢迎消息 + send_welcome(); + } + + void send_welcome() { + std::string welcome_msg = R"({"type": "welcome", "message": "Connected to PMC LLM Backend"})"; + send(welcome_msg); + } + + void do_read() { + ws_.async_read(buffer_, + beast::bind_front_handler(&WebSocketClient::on_read, shared_from_this())); + } + + void on_read(beast::error_code ec, std::size_t bytes_transferred) { + if (ec == websocket::error::closed) { + std::cout << "WebSocket connection closed" << std::endl; + connected_ = false; + return; + } + + if (ec) { + std::cerr << "Read error: " << ec.message() << std::endl; + connected_ = false; + return; + } + + std::string message = beast::buffers_to_string(buffer_.data()); + buffer_.consume(buffer_.size()); + + // 处理接收到的消息 + if (message_handler_) { + message_handler_(message); + } + + // 继续读取 + do_read(); + } + + void send_next() { + std::lock_guard lock(queue_mutex_); + + if (send_queue_.empty()) { + sending_ = false; + return; + } + + sending_ = true; + std::string message = send_queue_.front(); + send_queue_.pop(); + + ws_.async_write(net::buffer(message), + beast::bind_front_handler(&WebSocketClient::on_write, shared_from_this())); + } + + void on_write(beast::error_code ec, std::size_t bytes_transferred) { + if (ec) { + std::cerr << "Write error: " << ec.message() << std::endl; + connected_ = false; + return; + } + + // 发送下一个消息 + send_next(); + } + + tcp::resolver resolver_; + websocket::stream ws_; + beast::flat_buffer buffer_; + std::string host_; + std::string port_; + std::atomic connected_; + + std::queue send_queue_; + std::mutex queue_mutex_; + std::atomic sending_{false}; + + std::function message_handler_; +}; + +// HTTP 请求处理器 +class HttpSession : public std::enable_shared_from_this { +public: + HttpSession(tcp::socket socket, const std::string& static_dir, + std::shared_ptr ws_client) + : socket_(std::move(socket)), static_dir_(static_dir), ws_client_(ws_client) {} + + void start() { + read_request(); + } + +private: + void read_request() { + auto self = shared_from_this(); + + http::async_read(socket_, buffer_, request_, + [self](beast::error_code ec, std::size_t bytes_transferred) { + if (!ec) { + self->process_request(); + } + }); + } + + void process_request() { + response_.version(request_.version()); + response_.keep_alive(false); + + // 检查是否为 WebSocket 升级请求 + if (websocket::is_upgrade(request_)) { + handle_websocket_upgrade(); + return; + } + + // 只处理 GET 请求 + if (request_.method() != http::verb::get) { + response_.result(http::status::bad_request); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "Invalid method\n"; + write_response(); + return; + } + + // 获取请求路径 + std::string target = request_.target(); + if (target.empty() || target == "/") { + target = "/llm_chat.html"; // 默认加载聊天界面 + } + + // 防止路径遍历攻击 + if (target.find("..") != std::string::npos) { + response_.result(http::status::forbidden); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "Forbidden\n"; + write_response(); + return; + } + + // 构建文件路径 + std::string file_path = static_dir_ + target; + + // 读取文件 + std::string content = read_file(file_path); + + if (content.empty()) { + // 文件不存在,返回 404 + if (target == "/llm_chat.html") { + // 如果聊天界面不存在,返回默认页面 + response_.result(http::status::ok); + response_.set(http::field::content_type, "text/html"); + response_.body() = "

PMC LLM Chat Interface

Chat interface not found. Please check static directory.

"; + } else { + response_.result(http::status::not_found); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "File not found: " + target + "\n"; + } + } else { + // 文件存在,返回内容 + response_.result(http::status::ok); + response_.set(http::field::content_type, get_mime_type(file_path)); + response_.body() = content; + } + + write_response(); + } + + void handle_websocket_upgrade() { + try { + // 创建 WebSocket 会话 + auto ws = std::make_shared>(std::move(socket_)); + + // 接受 WebSocket 握手 + ws->async_accept(request_, + [self = shared_from_this(), ws](beast::error_code ec) { + if (!ec) { + self->handle_websocket_session(ws); + } + }); + } catch (const std::exception& e) { + std::cerr << "WebSocket upgrade error: " << e.what() << std::endl; + } + } + + void handle_websocket_session(std::shared_ptr> ws) { + std::cout << "New WebSocket connection established" << std::endl; + + // 发送欢迎消息 + std::string welcome_msg = R"({"type": "welcome", "message": "Welcome to PMC LLM Chat Interface!"})"; + ws->write(net::buffer(welcome_msg)); + + // 开始读取消息 + do_websocket_read(ws); + } + + void do_websocket_read(std::shared_ptr> ws) { + auto buffer = std::make_shared(); + + ws->async_read(*buffer, + [self = shared_from_this(), ws, buffer](beast::error_code ec, std::size_t bytes_transferred) { + if (ec == websocket::error::closed) { + std::cout << "WebSocket connection closed by client" << std::endl; + return; + } + + if (ec) { + std::cerr << "WebSocket read error: " << ec.message() << std::endl; + return; + } + + // 处理接收到的消息 + std::string message = beast::buffers_to_string(buffer->data()); + self->handle_websocket_message(ws, message); + + // 继续读取 + self->do_websocket_read(ws); + }); + } + + void handle_websocket_message(std::shared_ptr> ws, + const std::string& message) { + try { + std::cout << "Received WebSocket message: " << message << std::endl; + + // 解析 JSON 消息 + // 这里简化处理,实际应该使用 JSON 库 + if (message.find("\"type\":\"hello\"") != std::string::npos || + message.find("hello") != std::string::npos) { + // 发送欢迎消息 + std::string response = R"({"type": "welcome", "message": "Hello! I'm PMC LLM Assistant. How can I help you today?"})"; + ws->write(net::buffer(response)); + } else if (message.find("\"type\":\"message\"") != std::string::npos || + message.find("\"type\":\"chat\"") != std::string::npos) { + // 聊天消息,转发到 LLM 后端 + if (ws_client_ && ws_client_->is_connected()) { + // 发送思考指示 + std::string thinking_msg = R"({"type": "thinking"})"; + ws->write(net::buffer(thinking_msg)); + + // 转发到 LLM 后端 + ws_client_->send(message); + + // 设置消息处理器,将后端响应转发回客户端 + ws_client_->set_message_handler([this, ws](const std::string& backend_response) { + // 将后端响应转发给 WebSocket 客户端 + std::string response = R"({"type": "response", "content": ")" + + escape_json(backend_response) + "\"}"; + ws->write(net::buffer(response)); + }); + } else { + // LLM 后端未连接,返回模拟响应 + std::string response = R"({"type": "response", "content": "LLM backend is not connected. This is a simulated response."})"; + ws->write(net::buffer(response)); + } + } else if (message.find("\"type\":\"change_model\"") != std::string::npos) { + // 处理模型切换请求 + std::string response = R"({"type": "system", "message": "Model change request received"})"; + ws->write(net::buffer(response)); + } else { + // 默认处理:直接回复 + std::string response = R"({"type": "response", "content": "I received your message: )" + + escape_json(message) + "\"}"; + ws->write(net::buffer(response)); + } + } catch (const std::exception& e) { + std::cerr << "Error handling WebSocket message: " << e.what() << std::endl; + std::string error_msg = R"({"type": "error", "message": "Error processing message"})"; + ws->write(net::buffer(error_msg)); + } + } + + std::string escape_json(const std::string& input) { + std::string output; + output.reserve(input.length()); + + for (char c : input) { + switch (c) { + case '"': output += "\\\""; break; + case '\\': output += "\\\\"; break; + case '\b': output += "\\b"; break; + case '\f': output += "\\f"; break; + case '\n': output += "\\n"; break; + case '\r': output += "\\r"; break; + case '\t': output += "\\t"; break; + default: output += c; break; + } + } + + return output; + } + + void write_response() { + auto self = shared_from_this(); + + response_.content_length(response_.body().size()); + + http::async_write(socket_, response_, + [self](beast::error_code ec, std::size_t bytes_transferred) { + // 连接关闭后自动清理 + }); + } + + tcp::socket socket_; + beast::flat_buffer buffer_; + http::request request_; + http::response response_; + std::string static_dir_; + std::shared_ptr ws_client_; +}; + +// HTTP 服务器 +class HttpServer { +public: + HttpServer(net::io_context& ioc, tcp::endpoint endpoint, + const std::string& static_dir, const std::string& backend_host, + const std::string& backend_port) + : acceptor_(ioc) + , static_dir_(static_dir) + , backend_host_(backend_host) + , backend_port_(backend_port) { + + beast::error_code ec; + + // 打开 acceptor + acceptor_.open(endpoint.protocol(), ec); + if (ec) { + std::cerr << "Open error: " << ec.message() << std::endl; + return; + } + + // 设置地址重用 + acceptor_.set_option(net::socket_base::reuse_address(true), ec); + if (ec) { + std::cerr << "Set option error: " << ec.message() << std::endl; + return; + } + + // 绑定到地址 + acceptor_.bind(endpoint, ec); + if (ec) { + std::cerr << "Bind error: " << ec.message() << std::endl; + return; + } + + // 开始监听 + acceptor_.listen(net::socket_base::max_listen_connections, ec); + if (ec) { + std::cerr << "Listen error: " << ec.message() << std::endl; + return; + } + + std::cout << "HTTP server listening on " << endpoint.address().to_string() + << ":" << endpoint.port() << std::endl; + + // 创建 WebSocket 客户端连接到 LLM 后端 + ws_client_ = std::make_shared(ioc, backend_host_, backend_port_); + + // 尝试连接到后端 + std::cout << "Connecting to LLM backend at " << backend_host_ << ":" << backend_port_ << std::endl; + ws_client_->connect(); + + // 开始接受连接 + do_accept(); + } + +private: + void do_accept() { + acceptor_.async_accept( + [this](beast::error_code ec, tcp::socket socket) { + if (!ec) { + std::make_shared(std::move(socket), static_dir_, ws_client_)->start(); + } + + // 继续接受新连接 + do_accept(); + }); + } + + tcp::acceptor acceptor_; + std::string static_dir_; + std::string backend_host_; + std::string backend_port_; + std::shared_ptr ws_client_; +}; + +int main(int argc, char* argv[]) { + try { + // 默认配置 + std::string host = "0.0.0.0"; + unsigned short port = 8080; + std::string static_dir = "./static"; + std::string backend_host = "localhost"; + std::string backend_port = "8081"; + + // 解析命令行参数 + for (int i = 1; i < argc; ++i) { + std::string arg = argv[i]; + if (arg == "--host" && i + 1 < argc) { + host = argv[++i]; + } else if (arg == "--port" && i + 1 < argc) { + port = static_cast(std::stoi(argv[++i])); + } else if (arg == "--static" && i + 1 < argc) { + static_dir = argv[++i]; + } else if (arg == "--backend-host" && i + 1 < argc) { + backend_host = argv[++i]; + } else if (arg == "--backend-port" && i + 1 < argc) { + backend_port = argv[++i]; + } else if (arg == "--help") { + std::cout << "Usage: " << argv[0] << " [options]\n" + << "Options:\n" + << " --host
HTTP server host (default: 0.0.0.0)\n" + << " --port HTTP server port (default: 8080)\n" + << " --static Static files directory (default: ./static)\n" + << " --backend-host LLM backend host (default: localhost)\n" + << " --backend-port LLM backend port (default: 8081)\n" + << " --help Show this help message\n"; + return 0; + } + } + + // 检查静态目录 + if (!std::filesystem::exists(static_dir)) { + std::cout << "Static directory '" << static_dir << "' does not exist. Creating it..." << std::endl; + std::filesystem::create_directories(static_dir); + + // 创建默认的 llm_chat.html 文件 + std::string chat_html_path = static_dir + "/llm_chat.html"; + if (!std::filesystem::exists(chat_html_path)) { + std::cout << "Creating default chat interface..." << std::endl; + // 这里可以添加默认的 HTML 内容 + } + } + + std::cout << "PMC LLM Frontend Server\n"; + std::cout << "=======================\n"; + std::cout << "HTTP Server: " << host << ":" << port << "\n"; + std::cout << "Static Directory: " << static_dir << "\n"; + std::cout << "LLM Backend: " << backend_host << ":" << backend_port << "\n"; + std::cout << "==============================\n\n"; + + // 创建 I/O 上下文 + net::io_context ioc; + + // 创建 HTTP 服务器 + tcp::endpoint endpoint(net::ip::make_address(host), port); + HttpServer server(ioc, endpoint, static_dir, backend_host, backend_port); + + // 运行 I/O 上下文 + ioc.run(); + + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/lci/src/mainCamera.cpp b/lci/src/mainCamera.cpp new file mode 100644 index 0000000..54d2200 --- /dev/null +++ b/lci/src/mainCamera.cpp @@ -0,0 +1,16 @@ +#include +#include "hd/Camera.h" + +int main() { + + Camera_init(640, 480); + + std::string imgpath = std::to_string(time(NULL)) + ".jpeg"; + std::string txtpath =std::to_string(time(NULL)) + ".txt"; + + bool flag; + auto img = get_frame_from_camera(flag); + img.save(imgpath.c_str()); + + Camera_close(); +} \ No newline at end of file diff --git a/lci/src/mainCameraClient.py b/lci/src/mainCameraClient.py new file mode 100644 index 0000000..63e45fb --- /dev/null +++ b/lci/src/mainCameraClient.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +相机客户端Python实现 +功能:连接服务器接收YUYV格式视频流,转换为RGB并显示 +""" + +import socket +import cv2 +import numpy as np +import sys + + +def main(): + if len(sys.argv) != 3: + print(f"Usage: {sys.argv[0]} ") + return 1 + + server_ip = sys.argv[1] + port = int(sys.argv[2]) + + # 创建TCP套接字 + sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + try: + # 连接到服务器 + sockfd.connect((server_ip, port)) + print(f"Connected to server: {server_ip}:{port}") + + # 图像参数 + WIDTH = 640 + HEIGHT = 480 + FRAME_BUFFER_SIZE = WIDTH * HEIGHT * 2 # YUYV格式:640x480,每个像素2字节 + + # OpenCV窗口 + cv2.namedWindow("Camera Stream", cv2.WINDOW_AUTOSIZE) + + frame_count = 0 + while True: + # 接收帧数据 + frame_buffer = b'' + while len(frame_buffer) < FRAME_BUFFER_SIZE: + data = sockfd.recv(FRAME_BUFFER_SIZE - len(frame_buffer)) + if not data: + print("Server closed connection") + return 0 + frame_buffer += data + + print(f"Frame {frame_count + 1} received: {len(frame_buffer)} bytes") + frame_count += 1 + + # 使用OpenCV处理YUYV帧 + yuyv_frame = np.frombuffer(frame_buffer, dtype=np.uint8).reshape((HEIGHT, WIDTH, 2)) + rgb_frame = cv2.cvtColor(yuyv_frame, cv2.COLOR_YUV2BGR_YUYV) + + # 显示帧 + cv2.imshow("Camera Stream", rgb_frame) + + # 等待1ms,允许窗口刷新,同时检查是否按下ESC键退出 + if cv2.waitKey(1) == 27: + print("ESC key pressed, exiting...") + break + + except Exception as e: + print(f"Error: {e}") + return 1 + finally: + # 清理资源 + sockfd.close() + cv2.destroyAllWindows() + print("Client exiting") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/lci/src/mainCompressedCameraClient.py b/lci/src/mainCompressedCameraClient.py new file mode 100644 index 0000000..b4dc28c --- /dev/null +++ b/lci/src/mainCompressedCameraClient.py @@ -0,0 +1,229 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +压缩相机客户端Python实现 +功能:连接服务器接收JPEG压缩视频流,解码并显示 +""" + +import socket +import cv2 +import numpy as np +import sys +import time +from PIL import Image +import io + + +def main(): + print("Starting Compressed Camera Client...") + + if len(sys.argv) != 3: + print(f"Usage: {sys.argv[0]} ") + return 1 + + server_ip = sys.argv[1] + port = int(sys.argv[2]) + + print(f"Configuration: Server IP={server_ip}, Port={port}") + + # 创建TCP套接字 + print("Creating TCP socket...") + sockfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + # 设置套接字超时 + sockfd.settimeout(5.0) + print("TCP socket created successfully") + + try: + # 连接到服务器 + print(f"Connecting to server {server_ip}:{port}...") + sockfd.connect((server_ip, port)) + print(f"Connected to server: {server_ip}:{port}") + + # 关闭超时,改为非阻塞模式 + sockfd.setblocking(True) + print("Socket set to blocking mode") + + # OpenCV窗口 + print("Creating OpenCV window...") + # 尝试使用不同的窗口参数 + cv2.namedWindow("Compressed Camera Stream", cv2.WINDOW_GUI_NORMAL) + # 设置固定的窗口大小 + cv2.resizeWindow("Compressed Camera Stream", 640, 480) + # 确保窗口大小是固定的 + cv2.setWindowProperty("Compressed Camera Stream", cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_KEEPRATIO) + cv2.setWindowProperty("Compressed Camera Stream", cv2.WND_PROP_AUTOSIZE, cv2.WINDOW_AUTOSIZE) + + # 显示初始信息 + info_frame = np.zeros((480, 640, 3), dtype=np.uint8) + cv2.putText(info_frame, "Connecting to server...", (50, 240), + cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) + cv2.imshow("Compressed Camera Stream", info_frame) + cv2.waitKey(100) + + frame_count = 0 + buffer = b'' # 用于累积数据的缓冲区 + total_bytes_received = 0 + jpeg_found_count = 0 + + # 上次收到数据的时间 + last_receive_time = time.time() + + while True: + try: + # 接收数据 + data = sockfd.recv(8192) + if not data: + print("Server closed connection") + return 0 + + last_receive_time = time.time() + total_bytes_received += len(data) + print(f"Received {len(data)} bytes, total: {total_bytes_received} bytes") + + # 将新数据添加到缓冲区 + buffer += data + + # 仅保留最近的500KB数据,防止内存溢出 + if len(buffer) > 500 * 1024: + print(f"Buffer size exceeded 500KB, trimming to 500KB") + buffer = buffer[-500 * 1024:] + + # 检查缓冲区中是否有JPEG标记 + has_jpeg = b'\xff\xd8' in buffer + print(f"Buffer contains JPEG SOI: {has_jpeg}, buffer size: {len(buffer)}") + + # JPEG文件格式标记 + JPEG_START = b'\xff\xd8' # SOI (Start of Image) + JPEG_END = b'\xff\xd9' # EOI (End of Image) + + # 查找所有完整的JPEG帧 + while True: + # 查找JPEG开始标记 + start_idx = buffer.find(JPEG_START) + if start_idx == -1: + # 没有找到开始标记 + print(f"No JPEG SOI found, buffer size: {len(buffer)}") + # 清空大部分缓冲区,只保留末尾可能包含部分JPEG头的数据 + if len(buffer) > 1024: + buffer = buffer[-1024:] + print(f"Trimmed buffer to {len(buffer)} bytes") + break + + # 查找当前开始标记后的结束标记 + end_idx = buffer.find(JPEG_END, start_idx + 2) + if end_idx == -1: + # 没有找到完整的结束标记 + print(f"Found JPEG SOI but no EOI, buffer size from SOI: {len(buffer) - start_idx}") + # 保留从开始标记到缓冲区末尾的数据 + buffer = buffer[start_idx:] + break + + # 提取完整的JPEG帧(包括结束标记) + jpeg_frame = buffer[start_idx:end_idx + 2] + jpeg_found_count += 1 + print(f"Extracted JPEG frame {jpeg_found_count}, size: {len(jpeg_frame)} bytes") + + # 从缓冲区中移除已处理的JPEG帧 + buffer = buffer[end_idx + 2:] + print(f"Buffer remaining after extraction: {len(buffer)} bytes") + + # 只处理合理大小的JPEG帧(1KB到500KB) + if 1024 <= len(jpeg_frame) <= 500 * 1024: + try: + # 使用PIL库来解码和显示图像 + image_stream = io.BytesIO(jpeg_frame) + pil_image = Image.open(image_stream) + + if pil_image is not None: + # 解码成功,显示帧 + frame_count += 1 + print(f"Frame {frame_count} decoded successfully, size: {pil_image.width}x{pil_image.height}") + + # 转换为OpenCV格式 + opencv_image = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) + + # 检查图像是否有重复的模式 + # 从截图来看,图像被分割成了3x3的网格 + # 这可能是因为图像高度是正常的3倍 + if opencv_image.shape[0] == 1440 and opencv_image.shape[1] == 640: + # 高度是1440,是正常的3倍 + # 只显示图像的前480行 + fixed_image = opencv_image[:480, :, :] + cv2.imshow("Compressed Camera Stream", fixed_image) + print(f"Fixed frame by cropping to 640x480") + elif opencv_image.shape[0] == 640 and opencv_image.shape[1] == 1920: + # 宽度是1920,是正常的3倍 + # 只显示图像的前640列 + fixed_image = opencv_image[:, :640, :] + cv2.imshow("Compressed Camera Stream", fixed_image) + print(f"Fixed frame by cropping to 640x480") + else: + # 直接显示原始大小的图像 + cv2.imshow("Compressed Camera Stream", opencv_image) + + # 只在显示新帧后调用一次waitKey,确保图像刷新 + key = cv2.waitKey(1) + if key == 27: + print("ESC key pressed, exiting...") + return 1 + else: + print(f"Failed to decode JPEG frame {jpeg_found_count}") + except Exception as e: + print(f"Error decoding JPEG frame {jpeg_found_count}: {e}") + # 尝试使用OpenCV的方式解码 + try: + np_data = np.frombuffer(jpeg_frame, dtype=np.uint8) + frame = cv2.imdecode(np_data, cv2.IMREAD_COLOR) + if frame is not None: + frame_count += 1 + print(f"Frame {frame_count} decoded with OpenCV, size: {frame.shape[1]}x{frame.shape[0]}") + # 检查是否是3x3网格 + if frame.shape[0] > 480 and frame.shape[1] == 640: + # 只显示前480行 + cv2.imshow("Compressed Camera Stream", frame[:480, :, :]) + else: + cv2.imshow("Compressed Camera Stream", frame) + key = cv2.waitKey(1) + if key == 27: + print("ESC key pressed, exiting...") + return 1 + except Exception as e2: + print(f"Failed with OpenCV too: {e2}") + else: + print(f"Invalid JPEG frame size: {len(jpeg_frame)} bytes, skipped") + + except socket.timeout: + print("Socket timeout, no data received") + except Exception as e: + print(f"Error in receive loop: {e}") + + # 检查连接是否超时 + if time.time() - last_receive_time > 10: + print("Connection timeout: No data received for 10 seconds") + return 1 + + # 检查是否按下ESC键退出 + key = cv2.waitKey(1) + if key == 27: + print("ESC key pressed, exiting...") + break + + except socket.timeout as e: + print(f"Connection timeout: {e}") + return 1 + except Exception as e: + print(f"Error: {e}") + return 1 + finally: + # 清理资源 + print("Cleaning up resources...") + sockfd.close() + cv2.destroyAllWindows() + print(f"Client exiting. Total bytes received: {total_bytes_received}, JPEG frames found: {jpeg_found_count}, Successful frames: {frame_count}") + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/lci/src/mainDashunFront.cpp b/lci/src/mainDashunFront.cpp new file mode 100644 index 0000000..8fcae77 --- /dev/null +++ b/lci/src/mainDashunFront.cpp @@ -0,0 +1,287 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast = boost::beast; +namespace http = beast::http; +namespace net = boost::asio; +using tcp = boost::asio::ip::tcp; +namespace fs = std::filesystem; + +// 获取MIME类型 +std::string get_mime_type(const std::string& path) { + if (path.ends_with(".html") || path.ends_with(".htm")) return "text/html"; + if (path.ends_with(".css")) return "text/css"; + if (path.ends_with(".js")) return "application/javascript"; + if (path.ends_with(".json")) return "application/json"; + if (path.ends_with(".png")) return "image/png"; + if (path.ends_with(".jpg") || path.ends_with(".jpeg")) return "image/jpeg"; + if (path.ends_with(".gif")) return "image/gif"; + if (path.ends_with(".svg")) return "image/svg+xml"; + if (path.ends_with(".txt")) return "text/plain"; + if (path.ends_with(".ico")) return "image/x-icon"; + return "application/octet-stream"; +} + +// 读取文件内容 +std::string read_file(const std::string& path) { + std::ifstream file(path, std::ios::binary); + if (!file.is_open()) { + std::cerr << "无法打开文件: " << path << std::endl; + return ""; + } + + std::stringstream buffer; + buffer << file.rdbuf(); + return buffer.str(); +} + +// 处理HTTP请求 +class http_connection : public std::enable_shared_from_this { +public: + http_connection(tcp::socket socket, const std::string& static_dir) + : socket_(std::move(socket)), static_dir_(static_dir) {} + + void start() { + read_request(); + } + +private: + void read_request() { + auto self = shared_from_this(); + + http::async_read(socket_, buffer_, request_, + [self](beast::error_code ec, std::size_t bytes_transferred) { + if (!ec) { + self->process_request(); + } + }); + } + + void process_request() { + response_.version(request_.version()); + response_.keep_alive(false); + + std::string target = std::string(request_.target()); + + // 防止路径遍历攻击 + if (target.find("..") != std::string::npos) { + response_.result(http::status::forbidden); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "禁止访问"; + send_response(); + return; + } + + // 处理根路径 + if (target == "/" || target == "/index.html") { + serve_file("dashun_index.html"); + return; + } + + // 处理健康检查 + if (target == "/health") { + response_.result(http::status::ok); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "大顺脚本前端服务运行正常"; + send_response(); + return; + } + + // 处理API请求 + if (target.starts_with("/api/")) { + handle_api_request(target); + return; + } + + // 处理静态文件 + serve_file(target.substr(1)); // 移除开头的'/' + } + + void handle_api_request(const std::string& target) { + response_.result(http::status::ok); + response_.set(http::field::content_type, "application/json"); + + if (target == "/api/status") { + response_.body() = R"({ + "status": "running", + "version": "1.0.0", + "uptime": "0", + "requests_served": 0 + })"; + } else if (target == "/api/info") { + response_.body() = R"({ + "name": "大顺脚本前端服务", + "description": "为pmc项目提供Web界面", + "author": "大顺", + "repository": "https://github.com/your-repo/pmc" + })"; + } else { + response_.result(http::status::not_found); + response_.set(http::field::content_type, "application/json"); + response_.body() = R"({"error": "API endpoint not found"})"; + } + + send_response(); + } + + void serve_file(const std::string& filename) { + std::string filepath = static_dir_ + "/" + filename; + + // 安全检查:确保文件在静态目录内 + fs::path requested_path = fs::absolute(filepath); + fs::path static_path = fs::absolute(static_dir_); + + if (!fs::equivalent(requested_path.parent_path(), static_path) && + !requested_path.string().starts_with(static_path.string() + "/")) { + response_.result(http::status::forbidden); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "禁止访问"; + send_response(); + return; + } + + if (!fs::exists(filepath)) { + response_.result(http::status::not_found); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "文件不存在: " + filename; + send_response(); + return; + } + + std::string content = read_file(filepath); + if (content.empty()) { + response_.result(http::status::internal_server_error); + response_.set(http::field::content_type, "text/plain"); + response_.body() = "读取文件失败"; + send_response(); + return; + } + + response_.result(http::status::ok); + response_.set(http::field::content_type, get_mime_type(filename)); + response_.body() = content; + send_response(); + } + + void send_response() { + auto self = shared_from_this(); + + response_.content_length(response_.body().size()); + + http::async_write(socket_, response_, + [self](beast::error_code ec, std::size_t) { + self->socket_.shutdown(tcp::socket::shutdown_send, ec); + }); + } + + tcp::socket socket_; + beast::flat_buffer buffer_{8192}; + http::request request_; + http::response response_; + std::string static_dir_; +}; + +// HTTP服务器 +class http_server { +public: + http_server(net::io_context& ioc, tcp::endpoint endpoint, const std::string& static_dir) + : acceptor_(ioc), static_dir_(static_dir) { + beast::error_code ec; + + // 打开acceptor + acceptor_.open(endpoint.protocol(), ec); + if (ec) { + throw beast::system_error{ec}; + } + + // 设置地址重用 + acceptor_.set_option(net::socket_base::reuse_address(true), ec); + if (ec) { + throw beast::system_error{ec}; + } + + // 绑定到端点 + acceptor_.bind(endpoint, ec); + if (ec) { + throw beast::system_error{ec}; + } + + // 开始监听 + acceptor_.listen(net::socket_base::max_listen_connections, ec); + if (ec) { + throw beast::system_error{ec}; + } + } + + void start_accept() { + acceptor_.async_accept( + [this](beast::error_code ec, tcp::socket socket) { + if (!ec) { + std::make_shared(std::move(socket), static_dir_)->start(); + } + start_accept(); + }); + } + +private: + tcp::acceptor acceptor_; + std::string static_dir_; +}; + +int main() { + try { + // 静态文件目录 + std::string static_dir = "static"; + + // 确保静态目录存在 + if (!fs::exists(static_dir)) { + std::cerr << "警告: 静态目录 '" << static_dir << "' 不存在" << std::endl; + if (!fs::create_directory(static_dir)) { + std::cerr << "错误: 无法创建静态目录" << std::endl; + return 1; + } + } + + // 检查主页文件是否存在 + std::string homepage = static_dir + "/dashun_index.html"; + if (!fs::exists(homepage)) { + std::cerr << "警告: 主页文件 '" << homepage << "' 不存在" << std::endl; + std::cerr << "请确保 dashun_index.html 文件在 static/ 目录中" << std::endl; + } + + // 创建IO上下文 + net::io_context ioc{1}; + + // 创建服务器端点(监听所有地址的8080端口) + tcp::endpoint endpoint{tcp::v4(), 8080}; + + // 创建HTTP服务器 + http_server server{ioc, endpoint, static_dir}; + server.start_accept(); + + // 显示启动信息 + std::cout << "==========================================" << std::endl; + std::cout << "大顺脚本前端服务已启动" << std::endl; + std::cout << "监听地址: http://0.0.0.0:8080" << std::endl; + std::cout << "静态文件目录: " << static_dir << std::endl; + std::cout << "按 Ctrl+C 停止服务" << std::endl; + std::cout << "==========================================" << std::endl; + + ioc.run(); + + } catch (const std::exception& e) { + std::cerr << "错误: " << e.what() << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/lci/src/mainGui.cpp b/lci/src/mainGui.cpp new file mode 100644 index 0000000..abebedd --- /dev/null +++ b/lci/src/mainGui.cpp @@ -0,0 +1,410 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "llm/LLMClient.hpp" + +namespace pmc::gui::example { + +// 带缓冲区的Markdown转换器,累积整个响应并处理Markdown +class BufferedMarkdownConverter { +private: + std::string buffer; // 累积原始Markdown文本 + std::string last_processed; // 上次处理的Pango标记 + +public: + BufferedMarkdownConverter() {} + + // 重置状态 + void reset() { + buffer.clear(); + last_processed.clear(); + } + + // 添加新的Markdown块到缓冲区 + void append_chunk(const std::string& chunk) { + buffer += chunk; + } + + // 获取当前缓冲区的内容 + std::string get_buffer() const { + return buffer; + } + + // 处理整个缓冲区并返回Pango标记 + std::string process_buffer() { + std::string result = buffer; + + // 1. 首先转义HTML特殊字符 + result = std::regex_replace(result, std::regex("&"), "&"); + result = std::regex_replace(result, std::regex("<"), "<"); + result = std::regex_replace(result, std::regex(">"), ">"); + + // 2. 转换粗斜体:***text*** -> text + // 先处理粗斜体,确保正确嵌套 + std::regex bold_italic_regex("\\*\\*\\*(.*?)\\*\\*\\*"); + result = std::regex_replace(result, bold_italic_regex, "$1"); + + // 3. 转换粗体:**text** -> text(但排除已经是粗斜体的部分) + std::regex bold_regex("\\*\\*(?!\\*)(.*?)\\*\\*"); + result = std::regex_replace(result, bold_regex, "$1"); + + // 4. 转换斜体:*text* -> text(但排除已经是粗体或粗斜体的部分) + std::regex italic_regex("\\*(?!\\*)(.*?)\\*"); + result = std::regex_replace(result, italic_regex, "$1"); + + // 5. 转换内联代码:`code` -> code (使用标签而不是) + std::regex code_regex("`(.*?)`"); + result = std::regex_replace(result, code_regex, "$1"); + + // 6. 转换标题:# 标题 -> 标题 + std::regex h1_regex("^#\\s+(.*?)$", std::regex::multiline); + result = std::regex_replace(result, h1_regex, "$1\n"); + + std::regex h2_regex("^##\\s+(.*?)$", std::regex::multiline); + result = std::regex_replace(result, h2_regex, "$1\n"); + + std::regex h3_regex("^###\\s+(.*?)$", std::regex::multiline); + result = std::regex_replace(result, h3_regex, "$1\n"); + + // 7. 转换无序列表:* item -> • item + std::regex ul_regex("^\\*\\s+(.*?)$", std::regex::multiline); + result = std::regex_replace(result, ul_regex, "• $1\n"); + + // 8. 转换有序列表:1. item -> 1. item + std::regex ol_regex("^\\d+\\.\\s+(.*?)$", std::regex::multiline); + // 保持原样,只是确保有换行 + result = std::regex_replace(result, ol_regex, "$&\n"); + + // 9. 转换引用:> text -> text + std::regex blockquote_regex("^>\\s+(.*?)$", std::regex::multiline); + result = std::regex_replace(result, blockquote_regex, "$1\n"); + + // 10. 转换链接:[text](url) -> text (Pango不支持标签,所以只显示文本) + std::regex link_regex("\\[(.*?)\\]\\((.*?)\\)"); + result = std::regex_replace(result, link_regex, "$1"); + + // 11. 转换图片:![alt](url) -> [图片: alt] (Pango不支持图片,所以显示替代文本) + std::regex image_regex("!\\[(.*?)\\]\\((.*?)\\)"); + result = std::regex_replace(result, image_regex, "[图片: $1]"); + + // 重要修复:Pango标记语言使用 \n 表示换行,而不是
+ // 不要转换换行符,保持原样 + + last_processed = result; + return result; + } + + // 获取上次处理的结果 + std::string get_last_processed() const { + return last_processed; + } +}; + +/** + * @brief 简单的聊天窗口类 + */ +class SimpleChatWindow { +private: + GtkTextMark* current_response_start_mark; // 标记当前响应的开始位置 + +public: + SimpleChatWindow() : current_response_start_mark(nullptr) { + // 创建主窗口 + window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + gtk_window_set_title(window, "PMC Chat"); + gtk_window_set_default_size(window, 800, 600); + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), nullptr); + + // 创建主垂直布局 + GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_container_add(GTK_CONTAINER(window), vbox); + + // 创建滚动窗口和文本视图(用于显示聊天记录) + GtkWidget* scrolled_window = gtk_scrolled_window_new(nullptr, nullptr); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0); + + text_view = GTK_TEXT_VIEW(gtk_text_view_new()); + gtk_text_view_set_editable(text_view, FALSE); + gtk_text_view_set_cursor_visible(text_view, FALSE); + gtk_text_view_set_wrap_mode(text_view, GTK_WRAP_WORD_CHAR); + gtk_container_add(GTK_CONTAINER(scrolled_window), GTK_WIDGET(text_view)); + + // 设置文本视图的边距 + gtk_text_view_set_left_margin(text_view, 10); + gtk_text_view_set_right_margin(text_view, 10); + gtk_text_view_set_top_margin(text_view, 10); + gtk_text_view_set_bottom_margin(text_view, 10); + + // 创建输入区域的水平布局 + GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + // 创建输入框 + entry = GTK_ENTRY(gtk_entry_new()); + gtk_entry_set_placeholder_text(entry, "输入消息..."); + gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(entry), TRUE, TRUE, 0); + + // 创建发送按钮 + send_button = GTK_BUTTON(gtk_button_new_with_label("发送")); + gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(send_button), FALSE, FALSE, 0); + + // 连接信号 + g_signal_connect(send_button, "clicked", G_CALLBACK(on_send_clicked), this); + g_signal_connect(entry, "activate", G_CALLBACK(on_entry_activate), this); + + // 初始化LLM客户端 + std::string api_key; + const char* env_key = std::getenv("DEEPSEEK_API_KEY"); + if (env_key && env_key[0] != '\0') { + api_key = env_key; + } else { + // 尝试从文件读取 + std::string key_file = std::string(std::getenv("HOME")) + "/.cert/deepseek.key"; + std::ifstream file(key_file); + if (file.is_open()) { + std::getline(file, api_key); + file.close(); + } else { + api_key = ""; // 使用空密钥,会在使用时出错 + } + } + + llm_client = std::make_unique(api_key); + markdown_converter = std::make_unique(); + } + + // 使用带缓冲区的Markdown转换器进行转换 + std::string markdown_to_pango(const std::string& markdown) { + // 将新块添加到缓冲区 + markdown_converter->append_chunk(markdown); + + // 处理整个缓冲区 + std::string result = markdown_converter->process_buffer(); + + return result; + } + + void show() { + gtk_widget_show_all(GTK_WIDGET(window)); + } + + void append_message(const std::string& message) { + GtkTextBuffer* buffer = gtk_text_view_get_buffer(text_view); + GtkTextIter end; + gtk_text_buffer_get_end_iter(buffer, &end); + + // 用户消息不需要Markdown转换,直接显示 + gtk_text_buffer_insert(buffer, &end, message.c_str(), -1); + gtk_text_buffer_insert(buffer, &end, "\n", -1); + + // 滚动到底部 + GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment( + GTK_SCROLLED_WINDOW(gtk_widget_get_parent(GTK_WIDGET(text_view)))); + gtk_adjustment_set_value(adj, gtk_adjustment_get_upper(adj)); + } + + void append_stream_chunk(const std::string& chunk) { + GtkTextBuffer* buffer = gtk_text_view_get_buffer(text_view); + + // 如果这是响应的第一个块,创建一个标记来跟踪开始位置 + if (current_response_start_mark == nullptr) { + GtkTextIter end; + gtk_text_buffer_get_end_iter(buffer, &end); + + // 添加助手前缀 + gtk_text_buffer_insert(buffer, &end, "Assistant: ", -1); + + // 在助手前缀后创建标记 + gtk_text_buffer_get_end_iter(buffer, &end); + current_response_start_mark = gtk_text_buffer_create_mark(buffer, "current_response_start", &end, TRUE); + } + + // 获取当前响应的开始位置 + GtkTextIter start_iter; + gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, current_response_start_mark); + + // 获取缓冲区的结束位置 + GtkTextIter end_iter; + gtk_text_buffer_get_end_iter(buffer, &end_iter); + + // 删除当前响应区域(从标记位置到缓冲区末尾) + gtk_text_buffer_delete(buffer, &start_iter, &end_iter); + + // 在处理后的位置插入新的内容 + gtk_text_buffer_get_iter_at_mark(buffer, &start_iter, current_response_start_mark); + + // 关键修复:插入整个累积的缓冲区内容,而不仅仅是当前的chunk + // 首先,将新chunk添加到缓冲区 + markdown_converter->append_chunk(chunk); + + // 然后处理整个缓冲区 + std::string processed_buffer = markdown_converter->process_buffer(); + + // 插入处理后的整个缓冲区内容 + if (!processed_buffer.empty()) { + gtk_text_buffer_insert_markup(buffer, &start_iter, processed_buffer.c_str(), -1); + } + + // 滚动到底部 + GtkAdjustment* adj = gtk_scrolled_window_get_vadjustment( + GTK_SCROLLED_WINDOW(gtk_widget_get_parent(GTK_WIDGET(text_view)))); + gtk_adjustment_set_value(adj, gtk_adjustment_get_upper(adj)); + + // 累积当前响应 + current_response += chunk; + } + + void finish_response() { + // 将完整的响应添加到聊天历史 + if (!current_response.empty()) { + chat_history.push_back({"assistant", current_response}); + current_response.clear(); + } + + // 重置Markdown转换器 + markdown_converter->reset(); + + // 清除当前响应标记 + if (current_response_start_mark != nullptr) { + GtkTextBuffer* buffer = gtk_text_view_get_buffer(text_view); + gtk_text_buffer_delete_mark(buffer, current_response_start_mark); + current_response_start_mark = nullptr; + } + + // 添加换行符 + GtkTextBuffer* buffer = gtk_text_view_get_buffer(text_view); + GtkTextIter end; + gtk_text_buffer_get_end_iter(buffer, &end); + gtk_text_buffer_insert(buffer, &end, "\n", -1); + } + + std::string get_input_text() { + const char* text = gtk_entry_get_text(entry); + return text ? std::string(text) : ""; + } + + void clear_input() { + gtk_entry_set_text(entry, ""); + } + + void send_to_llm(const std::string& user_message) { + // 将用户消息添加到聊天历史 + chat_history.push_back({"user", user_message}); + + // 创建流式回调函数 + auto stream_callback = [this](const std::string& chunk) { + // 关键修复:简化完成标记检查 + // 只检查明确的完成标记,避免误判 + if (chunk == "[[PMC_STREAM_COMPLETE]]" || chunk == "[流式传输完成]]") { + std::cout << "DEBUG: Detected completion marker" << std::endl; + // 流式传输完成,在主线程中调用finish_response + g_idle_add([](gpointer data) -> gboolean { + auto* self = static_cast(data); + self->finish_response(); + return FALSE; // 只执行一次 + }, this); + return; // 重要:直接返回,不显示这个字符串 + } + + // 使用g_idle_add在主线程中更新UI + g_idle_add([](gpointer data) -> gboolean { + auto* chunk_data = static_cast*>(data); + chunk_data->first->append_stream_chunk(chunk_data->second); + delete chunk_data; + return FALSE; // 只执行一次 + }, new std::pair(this, chunk)); + }; + + // 在新线程中发送流式请求(避免阻塞主线程) + std::thread([this, stream_callback]() { + try { + llm_client->stream_request(chat_history, stream_callback); + } catch (const std::exception& e) { + // 错误处理:在主线程中显示错误消息 + g_idle_add([](gpointer data) -> gboolean { + auto* error_data = static_cast*>(data); + error_data->first->append_message("错误: " + error_data->second); + delete error_data; + return FALSE; // 只执行一次 + }, new std::pair(this, e.what())); + } + }).detach(); // 分离线程,让它独立运行 + } + +private: + static void on_send_clicked(GtkButton* button, gpointer user_data) { + auto* self = static_cast(user_data); + std::string text = self->get_input_text(); + if (!text.empty()) { + // 用户消息不需要Markdown转换,直接显示 + self->append_message("You: " + text); + self->clear_input(); + self->send_to_llm(text); + } + } + + static void on_entry_activate(GtkEntry* entry, gpointer user_data) { + auto* self = static_cast(user_data); + std::string text = self->get_input_text(); + if (!text.empty()) { + // 用户消息不需要Markdown转换,直接显示 + self->append_message("You: " + text); + self->clear_input(); + self->send_to_llm(text); + } + } + + GtkWindow* window; + GtkTextView* text_view; + GtkEntry* entry; + GtkButton* send_button; + + std::unique_ptr llm_client; + std::unique_ptr markdown_converter; + std::vector> chat_history; + std::string current_response; +}; + +/** + * @brief 运行简单的聊天窗口示例 + */ +void run_simple_chat_example() { + // 标准GTK的gtk_init返回void,不是bool + gtk_init(nullptr, nullptr); + + SimpleChatWindow window; + window.show(); + + gtk_main(); +} + +} // namespace pmc::gui::example + +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cerr << "用法: " << argv[0] << " " << std::endl; + std::cerr << "命令: chat - 运行聊天窗口" << std::endl; + return 1; + } + + std::string command = argv[1]; + + if (command == "chat") { + pmc::gui::example::run_simple_chat_example(); + } else { + std::cerr << "未知命令: " << command << std::endl; + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/lci/src/mainLci.cpp b/lci/src/mainLci.cpp new file mode 100644 index 0000000..7271f33 --- /dev/null +++ b/lci/src/mainLci.cpp @@ -0,0 +1,740 @@ +/* + * 并发机器(进程托管) + * + * FIXME: 尽量使用大众的库(boost) + */ +#include +#include +#include +#include +#include +#include /* 注册信号以优雅退出 */ +#include +#include +#include +#include +#include "logs/Logger.hpp" +#include "th/Thread.hpp" /* 可控线程类 */ +#include "th/Cv_wait.hpp" /* 通过条件变量进行等待 */ +#include "th/ITask.hpp" +#include "lci/Term.h" +#include "lci/Rectangle.h" +#include "lci/Drawable.h" +#include "lci/FrameBuf.h" +#include "lci/PoolArea.h" +#include "lci/ShapeArea.h" +#include "lci/CharShape.h" +#include "lci/Color.h" +#include "lci/图层区域.hpp" +#include "hd/mem.h" +#include "hd/cpu.h" + +/* lci 临时 */ +#include "lci/p_th.h" + +/* 中文模式 Chinese Mode */ +#include "cn/中文化.hpp" +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +namespace po = boost::program_options; + +/* 版本号 */ +static const char *PMC_VERSION = "0.4.x"; +/* 条件变量的等待机制让主程序能够等待中断信号的产生 */ +qing::Cv_wait cv = qing::Cv_wait(); + + + + + + +/* 捕获中断信号,结束线程并且退出 */ +void signalHandler(int signum) +{ + LOG_INFO("收到终止信号,准备停止服务器..."); + cv.WakeCv(); /* 唤醒条件信号即关闭程序 */ +} + +/*----SIGNAL ACTION----*/ +// +/* 对信号的响应行为 */ +void set_signal_action() { + + /* 该结构体用于描述信号的处理方式 */ + struct sigaction sa; + + + /* 绑定处理函数 */ + sa.sa_handler = signalHandler; + + /* + * 清空并初始化一个信号掩码集 --------------> 用于指定哪些信号在当前或即将执行的信号处理函数期间应该被阻塞(位掩码) + * “在执行这个信号处理函数时,除了当前正在处理的信号外,还希望临时阻塞其他某些信号” + * 不阻塞其他信号 + * 确保在执行期间没有其他特定的信号会被阻塞 + * 防止处理过程中被其他信号中断 + */ + sigemptyset(&sa.sa_mask); + + /* + * 用于设置信号处理函数的行为特性。 + * 0 - 默认选项 + * SA_NODEFER - 表示在执行信号处理函数时不允许其他信号被阻塞 + * SA_RESETHAND - 在信号处理函数返回后,将信号的处理方式重置为默认 + * SA_NOCLDSTOP - 对于子进程发送的停止信号,父进程不会停止。 + * SA_NOCLDWAIT - 父进程在等待等待子进程终止时不会因为子进程发送信号而收到通知 + * SA_SIGINFO - 使用扩展的信号信息,信号处理函数接收三个参数而不是一个 + */ + sa.sa_flags = 0; + + /* 注册信号 */ + sigaction(SIGINT, &sa, nullptr); /* Ctrl + C */ + sigaction(SIGTERM, &sa, nullptr); /* kill 或 systemctl stop */ + +} + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ + +#define TARGET_TTY 8 /* FIXME: 目标端口设置为参数传入 */ +#define ORIGIN_TTY 1 +namespace qing { +class LciTask: public ITask{ +public: + LciTask(/*const std::string& cmd, const int masterfd, const int command_pipe_send, */const int rotate, const int fontsize) + : /*exec_cmd(cmd), masterfd(masterfd), command_pipe_send(command_pipe_send),*/ + rotate(rotate), fontsize(fontsize) { + /* 初始化线程 */ + init_thread(); + } + + /* 停止线程 */ + void stop() override { + th->WaitClose(); + } + + /* 唤醒线程 */ + void start() override{ + th->Activate(); /* 对于已经关闭的进程 */ + th->WaitStart(); + } + + /* 线程是否在运行 */ + bool isRunning() override { + auto stat = th->check(); + return stat == Fsm::Stat::START; + } + +private: + + std::string exec_cmd; + //int command_pipe_send; + //int masterfd; + + int rotate; + int fontsize; + bool shift = false; + + std::unique_ptr th; /* 持有线程类 */ + std::unique_ptr term; /* 终端代理 */ + std::unique_ptr fb; + //std::unique_ptr kbe; + //std::unique_ptr printTask; + std::unique_ptr poolArea; /* 持有控件池 */ + //std::shared_ptr cmd; + int table_w; + int table_h; + std::shared_ptr tableArea; + std::vector cpu_vec; + std::vector mem_vec; + + + /* + * 设置终端的大小 + * + * 传入一个控制台设备文件的文件描述符,以及你要设定的行列值 + */ + //void set_terminal_size(int fd, int rows, int cols) { + // struct winsize sz = { .ws_row = (unsigned short)rows, .ws_col = (unsigned short)cols }; + // if (ioctl(fd, TIOCSWINSZ, &sz) == -1) { + // throw std::runtime_error("ioctl"); + // } + //} + + /*---------------------*/ + void init_thread(); + +}; +} + + +int lci_init(po::variables_map&); + +/* 任务池 */ +auto taskPool = std::vector>{}; + + +/* 入口函数 */ +int main(int argc, char** argv) { + + /*------------------------------*/ + /* 设置信号行为*/ + set_signal_action(); + + /*------------------------------*/ + /* 解析命令行参数 */ + po::options_description desc("pmc subsystem start options"); + desc.add_options() /* 定义选项 */ + ("help,h", "display help message") + ("version,v", "display version message") + ("lci", "run lci task") + /*****************/ + //("exec", po::value(), "lci module run commandline") + ("rotate", po::value()->default_value(0), "lci module rotate mode(0~3)") + ("fontsize", po::value()->default_value(18), "lci module fontsize option"); + + /* 参数变量映射关系 */ + po::variables_map vm; + + try { /* 开始解析 */ + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + if (vm.count("help")) { + std::cout << desc << std::endl; + return 0; + } + if (vm.count("version")) { + std::cout << PMC_VERSION << std::endl; + return 0; + } + } + + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + std::cerr << "using --help to check options message" << std::endl; + throw e; + } + + + + /* LINUX CHINESE INTERF */ + if (vm.count("lci")) { + + if (!(vm.count("rotate") && vm.count("fontsize")/* && vm.count("exec")*/)) + throw std::runtime_error( + "您进入了lci模块,请输入以下选项 --rotate, --fontsize"); + + lci_init(vm); + } + + /* + * 等待 + * + * 触发器在信号处理那里 + */ + cv.Wait(); + + /* 主线程被唤醒 */ + for (auto& task: taskPool) { + task->stop(); + } +} + + +/* 初始化PMC并发机器 */ +int lci_init(po::variables_map& vm) { + + //int masterfd; /* 控制台文件描述符 */ + /* 在运行到多线程之前,进行fork() */ + //if ((masterfd = posix_openpt(O_RDWR)) == -1) { /* 打开一个新的虚拟控制台 */ + // throw std::runtime_error("posix_openpt"); + //} + + /*--------------------------------------------------*/ + /* 创建两个管道:一个用于发送命令,一个用于接收输出 */ + //int command_pipe[2]; /* [0] 是读端,[1] 是写端 */ + //if (pipe(command_pipe) == -1) + // throw std::runtime_error( + // "pipe:" + std::string(strerror(errno)) + // ); + /* 创建成功 */ + /*--------------------------------------------------*/ + +// if (grantpt(masterfd) != 0 || unlockpt(masterfd) != 0) { /* 解锁虚拟控制台? */ +// close(masterfd); +// throw std::runtime_error("grantpt/unlockpt"); /* FIXME: 输出错误字符串 */ +// } + +// char *slave_name = ptsname(masterfd); /* 获取虚拟控制台pty的名字 */ +// if (slave_name == NULL) { +// close(masterfd); +// throw std::runtime_error("ptsname"); +// } + +// LOG_INFO( +// std::string("新的虚拟终端运行在 ") + slave_name +// ); + + + + + /* Fork中间子进程 */ +// pid_t pid = fork(); + + /* pid为-1通常意味着分叉失败 */ +// if (pid == -1) +// throw std::runtime_error( +// std::string("fork") + std::string(strerror(errno)) +// ); + + /* 如果pid为0表示这是子进程 */ +// else if (pid == 0) { +// LOG_INFO("LCI subprocess is running..."); +// close(command_pipe[1]); /* 关闭管道写端 */ +// int slavefd = open(slave_name, O_RDWR); +// if (slavefd == -1) +// throw std::runtime_error( +// std::string("open slave pty") + std::string(strerror(errno)) +// ); + + //runIntermediateProcess(command_pipe[0], slavefd); +// int command_pipe_read = command_pipe[0]; +// char buffer[1024]; +// ssize_t nread; +// while (true) { +// memset(buffer, 0, sizeof(buffer)); /* 清空缓冲区 */ +// nread = read(command_pipe_read, buffer, sizeof(buffer) - 1); /* 从命令管道读取数据 */ +// if (nread <= 0) break; /* 没有数据可读,退出循环 */ + + /* 查找命令的结束位置 */ + /* FIXME: 更换结束符号,这样我们可以运行一整个脚本 */ +// char* end_of_cmd = strchr(buffer, '\n'); +// if (end_of_cmd != nullptr) +// *end_of_cmd = '\0'; +// else +// continue; /* 没找到结束符号,继续读取 */ + + /* 检查是否受到结束信号 */ +// if (strcmp(buffer, "END") == 0) +// break; + + /* 输入输出重定向 */ +// if (dup2(slavefd, STDIN_FILENO) != STDIN_FILENO +// || dup2(slavefd, STDOUT_FILENO) != STDOUT_FILENO +// || dup2(slavefd, STDERR_FILENO) != STDERR_FILENO) +// throw std::runtime_error( +// std::string("dup2") // + +// ); + + /* ?*/ +// if (slavefd > STDERR_FILENO) +// close(slavefd); + + /* 执行命令 */ +// execlp("/bin/sh", "/bin/sh", "-c", buffer, nullptr); + + /* 如果能运行到这里表示进程切换异常 */ +// throw std::runtime_error( +// std::string("execlp") // + +// ); + +// } + +// close(command_pipe[0]); +// _exit(0); +// } + + /* 返回其他正数表示这是主进程 */ +// else { + +// LOG_INFO("LCI main thread is running..."); + + + + auto lciTask = std::make_shared( +// vm["exec"].as(), +// masterfd, command_pipe[1], + vm["rotate"].as(), + vm["fontsize"].as() + ); + lciTask->start(); + taskPool.push_back(lciTask); + + + /* 等待中间子进程终止 */ +// waitpid(pid, nullptr, 0); + + /* 将管道移动到分支外面 */ +// close(command_pipe[0]); // 关闭读端 +// close(command_pipe[1]); + +// close(masterfd); /* 关闭虚拟终端 */ + +// } + + return 0; +} + +namespace qing { + + void LciTask::init_thread() { + + /* 静止事件 */ + f_t StopEvent = [](Thread& th) { + th.suspend(); + }; + + /* 启动事件 */ + f_t StartEvent = [this] (Thread& th) { + + this->term = std::make_unique(TARGET_TTY, ORIGIN_TTY); + this->fb = std::make_unique("/dev/fb0", rotate, fontsize); + //this->kbe = std::make_unique(); + + Rectangle rect = fb->get_size(); /* 屏幕大小 */ + //set_terminal_size(masterfd, rect.h / (fontsize/2), rect.w / (fontsize/2) - 1); + + + //int cmd_margin_left = 50; + //int cmd_margin_top = 50; + //int cmd_w = (rect.w - 3*50) * 0.7; + //int cmd_h = (rect.h - 2*50) * 1.0; + + //int log_margin_left = 50 * 2 + cmd_w; + //int log_margin_top = 50; + //int log_w = (rect.w - 3 * 50) * 0.3; + //int log_h = (rect.h - 3 * 50) / 2; + + //int video_margin_left = 50 * 2 + cmd_w; /* 位置 */ + //int video_margin_top = log_margin_top + log_h + 50; + //int video_w = (rect.w - 3 * 50) * 0.3;/* 大小 */ + //int video_h = (rect.h - 3 * 50) / 2; + // + int top_margin_left = 10; + int top_margin_top = 10; + int top_w = rect.w - 2 * 10; + int top_h = 40; + + int main_margin_left = 10; + int main_margin_top = 10 + top_margin_top + top_h; + int main_w = rect.w - 2 * 10; + int main_h = rect.h - 4 * 10 - 2 * 40; + + int bottom_margin_left = 10; + int bottom_margin_top = 10 + main_margin_top + main_h; + int bottom_w = rect.w - 2 * 10; + int bottom_h = 40; + + + /* 容器区域 */ + poolArea = std::make_unique(fb.get(), rect.w, rect.h, 0, 0, rotate, fontsize); + + auto topArea = std::make_shared(poolArea.get(), top_w, top_h, top_margin_left, top_margin_top, rotate, fontsize); + poolArea->add("top", topArea); + //poolArea->flush(topArea.get(), true); + //auto topClr = green; + //topArea->rectangle_fill(0, 0, top_w, top_h, topClr); + + /* 顶部内容1 */ + auto topCtt_1 = std::make_shared (topArea.get(), top_w -10, top_h -10, 5, 5, rotate, fontsize); + topArea->add("content1", topCtt_1); + + /* 第一个字 */ + auto tctt1_c1 = std::make_shared(top_h-10, top_h-10, 0, 0, 'C'); + tctt1_c1->Draw(*topCtt_1, red); + /* 第二个字 */ + auto tctt1_c2 = std::make_shared(top_h-10, top_h-10, top_h-10, 0, 'P'); + tctt1_c2->Draw(*topCtt_1, red); + /* 第三个字 */ + auto tctt1_c3 = std::make_shared(top_h-10, top_h-10, 2*(top_h-10), 0, 'U'); + tctt1_c3->Draw(*topCtt_1, red); + + + auto bottomArea = std::make_shared(poolArea.get(), bottom_w, bottom_h, bottom_margin_left, bottom_margin_top, rotate, fontsize); + poolArea->add("bottom", bottomArea); + //poolArea->flush(bottomArea.get(), true); + //auto bottomClr = green; + //bottomArea->rectangle_fill(0, 0, bottom_w, bottom_h, bottomClr); + + auto mainArea = std::make_shared(poolArea.get(), main_w, main_h, main_margin_left, main_margin_top, rotate, fontsize); + poolArea->add("main", mainArea); + poolArea->flush(mainArea.get(), false); + auto mainClr = green; + mainArea->line(20, 20, 20, main_h-20, mainClr); + mainArea->line(21, 20, 21, main_h-20, mainClr); + mainArea->line(20, main_h-18, main_w-20, main_h-18, mainClr); + mainArea->line(20, main_h-19, main_w-20, main_h-19, mainClr); + + table_w = main_w - 41; + table_h = main_h - 39; + tableArea = std::make_shared (mainArea.get(), table_w, table_h, 22, 20, rotate, fontsize); + mainArea->add("table", tableArea); + mainArea->flush(tableArea.get(), false); + + /* NOTE: 子进程收到命令会执行 */ + //write(command_pipe_send, exec_cmd.c_str(), exec_cmd.size()); + //const char* sig = "\n"; + //write(command_pipe_send, sig, strlen(sig)); + + //this->printTask = std::make_unique( /* 创建打印线程 */ + // "Printer", + // masterfd, + // fb.get(), + // cmd.get() + //); + //printTask->wake(); + //printTask->WaitStart(10000); /* FIXME: 使用新版的线程类 */ + + th.run(); + }; + + + f_t LoopEvent = [this](Thread& th) { + + //try { + + // struct input_event ev = kbe->get(); /* 获取输入事件 */ + // std::cout << "Key Press:\t"; + // std::cout << ev.code << "," << ev.value << std::endl; + + // if (ev.type == EV_KEY && ev.value == 1 && ev.code == 1) + // { /* ESC 退出键 */ + // th.stop(); + // } + + // else if (ev.type == EV_KEY && ev.value == 1 && ev.code == 14) + // { /* DELETE 删除键 */ + //cmd->delete_input(); + //cmd->clearBox(); + //cmd->update_input(); + // } + + // else if (ev.type == EV_KEY && ev.value == 1 && ev.code == 28) + // { /* ENTER 回车 */ + //auto input = cmd->get_input_and_clear(); + //cmd->clearBox(); + //cmd->update_input(); + //if (input == "") { + // input = "\n"; + //} + //const char *msg = input.c_str(); + //write(masterfd, msg, input.length()); + // } + + // else if (ev.type == EV_KEY && ev.code == 42) + // { /* Shift */ + // shift = (ev.value) ? true : false; + // } + + // else if (ev.type == EV_KEY && ev.value == 1) + // { /* 其他有效按键 */ + + // char c = '\0'; /* 功能变换 */ + // switch (ev.code) { + // case 2: + // c = (shift) ? '!' : '1'; + // break; + // case 3: + // c = (shift) ? '@' : '2'; + // break; + // case 4: + // c = (shift) ? '#' : '3'; + // break; + // case 5: + // c = (shift) ? '$' : '4'; + // break; + // case 6: + // c = (shift) ? '%' : '5'; + // break; + // case 7: + // c = (shift) ? '^' : '6'; + // break; + // case 8: + // c = (shift) ? '&' : '7'; + // break; + // case 9: + // c = (shift) ? '*' : '8'; + // break; + // case 10: + // c = (shift) ? '(' : '9'; + // break; + // case 11: + // c = (shift) ? ')' : '0'; + // break; + // case KEY_A: + // c = (shift) ? 'A' : 'a'; + // break; + // case KEY_B: + // c = (shift) ? 'B' : 'b'; + // break; + // case KEY_C: + // c = (shift) ? 'C' : 'c'; + // break; + // case KEY_D: + // c = (shift) ? 'D' : 'd'; + // break; + // case KEY_E: + // c = (shift) ? 'E' : 'e'; + // break; + // case KEY_F: + // c = (shift) ? 'F' : 'f'; + // break; + // case KEY_G: + // c = (shift) ? 'G' : 'g'; + // break; + // case KEY_H: + // c = (shift) ? 'H' : 'h'; + // break; + // case KEY_I: + // c = (shift) ? 'I' : 'i'; + // break; + // case KEY_J: + // c = (shift) ? 'J' : 'j'; + // break; + // case KEY_K: + // c = (shift) ? 'K' : 'k'; + // break; + // case KEY_L: + // c = (shift) ? 'L' : 'l'; + // break; + // case KEY_M: + // c = (shift) ? 'M' : 'm'; + // break; + // case KEY_N: + // c = (shift) ? 'N' : 'n'; + // break; + // case KEY_O: + // c = (shift) ? 'O' : 'o'; + // break; + // case KEY_P: + // c = (shift) ? 'P' : 'p'; + // break; + // case KEY_Q: + // c = (shift) ? 'Q' : 'q'; + // break; + // case KEY_R: + // c = (shift) ? 'R' : 'r'; + // break; + // case KEY_S: + // c = (shift) ? 'S' : 's'; + // break; + // case KEY_T: + // c = (shift) ? 'T' : 't'; + // break; + // case KEY_U: + // c = (shift) ? 'U' : 'u'; + // break; + // case KEY_V: + // c = (shift) ? 'V' : 'v'; + // break; + // case KEY_W: + // c = (shift) ? 'W' : 'w'; + // break; + // case KEY_X: + // c = (shift) ? 'X' : 'x'; + // break; + // case KEY_Y: + // c = (shift) ? 'Y' : 'y'; + // break; + // case KEY_Z: + // c = (shift) ? 'Z' : 'z'; + // break; + // case KEY_SPACE: + // c = ' '; + // break; + // case 51: + // c = (shift) ? '<' : ','; + // break; + // case 52: + // c = (shift) ? '>' : '.'; + // break; + // case 53: + // c = (shift) ? '?' : '/'; + // break; + // case 12: + // c = (shift) ? '_' : '-'; + // break; + // case 43: + // c = (shift) ? '|' : '\\'; + // break; + + // } + + // if (c != '\0') /* 如果点击了有效按键 */ + // { + //cmd->Input(c); + //cmd->clearBox(); + //cmd->update_input(); + // } + + // } else if (ev.type == EV_REL && ev.code == REL_X) { /* 这两个是鼠标移动事件 */ + // std::cout << "X:\t\t" << ev.value << std::endl; + // } else if (ev.type == EV_REL && ev.code == REL_Y) { + // std::cout << "Y:\t\t" << ev.value << std::endl; + // } + + //} catch( KeyboardEvent::NoEvent _ ) { + // ; + //} + + + MemoryInfo mem = getMemoryUsageWithSysinfo(); + mem_vec.push_back(mem.usageRate); + if (mem_vec.size() > 40) { + mem_vec.erase(mem_vec.begin()); + } + + CpuMonitor monitor; + double cpu_usage = monitor.get_cpu_usage(); + cpu_vec.push_back(cpu_usage); + if (cpu_vec.size() > 40) { + cpu_vec.erase(cpu_vec.begin()); + } + + + auto bg = black; + tableArea->rectangle_fill(0, 0, table_w, table_h, bg); + + float single_w = (float)(table_w-1) / 40.0; + float single_h = (float)(table_h-1) / 100.0; + + for (int i = 0; i < mem_vec.size() - 1; ++i) { + int x0 = i * single_w; + int y0 = (100.0 - mem_vec[i]) * single_h; + int x1 = x0 + single_w; + int y1 = (100.0 - mem_vec[i+1]) * single_h; + auto fg = blue; + tableArea->line(x0, y0, x1, y1, fg); + } + + for (int i = 0; i < cpu_vec.size() - 1; ++i) { + int x0 = i * single_w; + int y0 = (100.0 - cpu_vec[i]) * single_h; + int x1 = x0 + single_w; + int y1 = (100.0 - cpu_vec[i+1]) * single_h; + auto fg = red; + tableArea->line(x0, y0, x1, y1, fg); + } + + + usleep(1000000); + }; + + + f_t ClearEvent = [this](Thread& th) + { + //printTask.reset(); + //cmd.reset(); + poolArea.reset(); + tableArea.reset(); + term.reset(); + }; + + this->th = std::make_unique( + StopEvent, StartEvent, LoopEvent, ClearEvent + ); + + + + } +} diff --git a/lci/src/mainMybot.cpp b/lci/src/mainMybot.cpp new file mode 100644 index 0000000..aec6506 --- /dev/null +++ b/lci/src/mainMybot.cpp @@ -0,0 +1,526 @@ +/* + * 并发机器(进程托管) + * + * FIXME: 尽量使用大众的库(boost) + */ +#define HTTPLIB_COMPILE /* 无SSL需求,优先选这个;有SSL需求替换为 #define HTTPLIB_OPENSSL_SUPPORT */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 注册信号以优雅退出 */ +#include +#include "logs/Logger.hpp" +#include "th/Thread.hpp" /* 可控线程类 */ +#include "th/Cv_wait.hpp" /* 通过条件变量进行等待 */ +#include "th/ITask.hpp" +#include "nn/NNBuilder.hpp" +#include "hd/Robot.hpp" + +/* lci 临时 */ +#include "lci/p_th.h" + +/* 中文模式 Chinese Mode */ +#include "cn/中文化.hpp" +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +namespace po = boost::program_options; + +/* 版本号 */ +static const char *PMC_VERSION = "0.4.x"; +/* 条件变量的等待机制让主程序能够等待中断信号的产生 */ +qing::Cv_wait cv = qing::Cv_wait(); + + +/* + * Http Server Task + * 超文本传输服务器任务 + */ +namespace qing{ +class HttpTask: public qing::ITask { +public: + /* 调用回调函数,设置http服务器 */ + HttpTask(const std::string& addr, const int port, std::function f) + : http_addr(addr), http_port(port), callback(f) { + + init_thread(); + } + + /* 任务不可复制 */ + HttpTask(const HttpTask& ) = delete; + + /* 关闭线程、关闭服务 */ + ~HttpTask() { + if (http) http->stop(); + if (th) th->WaitClose(); + } + + + /* 从外部停止任务 */ + void stop() override { + if (http) http->stop(); + th->WaitClose(); + } + + /* 唤醒线程 */ + void start() override { + th->Activate(); /* 对于已关闭的线程 */ + th->WaitStart(); + } + + /* 是否在运行 */ + bool isRunning() override { + auto stat = th->check(); + return stat == Fsm::Stat::START + || stat == Fsm::Stat::RUNNING; + } +private: + std::unique_ptr th; + std::function callback; + std::unique_ptr http; + std::string http_addr; + int http_port; + + /* 初始化线程 */ + void init_thread(); +}; //HttpTask +} // qing + + +namespace qing{ +static const std::string ADDR = std::string{"127.0.0.1"}; /* 只监听本机 */ +static const int PORT = 9203; +using nnl = NeuralNetwork; +class ParserTask: public HttpTask { /* 动作解析器 */ +public: + ParserTask(); + ParserTask(const ParserTask&) = delete; + + /* 解析器异常 */ + class ParserException: public std::exception{ + protected: + std::string message; + public: + explicit ParserException(const std::string& msg): message(msg) {} + const char* what() const noexcept override { + return message.c_str(); + } + }; + + /* 没有消息体异常 */ + class NoRequestBodyException: public ParserException { + public: + NoRequestBodyException(const std::string& msg): ParserException(msg) {} + }; + +private: + NNBuilder nn; + std::mutex mtx; + std::vector>> pool; /* 角度数据 - 样品池 */ + std::vector> averages; /* 角度数据 - 平均值 */ + /* 归一化 */ + static float normalize_pitch(float pitch) { + return (pitch + 180) / (2 * 180); /* FIXME: 方向反了 */ + } + /* 归一化 */ + static float normalize_roll(float roll) { + return (roll + 180) / (2 * 180); /* 观测值 */ + } + /* 计算误差 */ + static float calc_err(float nor_pitch, float pitch1) { + + return (nor_pitch > 0) /* 计算误差 */ + ? ((pitch1 > 0) ? nor_pitch - pitch1 : nor_pitch + pitch1 ) + : ((pitch1 < 0) ? pitch1 - nor_pitch : -(nor_pitch + pitch1)); + } + /* FIXME: 使用类封装采样数据 */ + static std::vector> calc_aves(std::vector>>& samples) { + std::vector> a_r{}; /* actions of average result FIXME: 长度必须一致 */ + for (const std::vector>& onetim: samples) { /* one time */ + auto first_action = onetim[0]; + std::vector grp_r(first_action.size()); /* group of averate result */ + for (const std::vector& action: onetim) { + for (size_t i_nora = 0; i_nora < action.size(); ++i_nora) { /* item of normalized angle*/ + grp_r[i_nora] += action[i_nora]; + } + } + auto length = onetim.size(); + for (auto& i_r: grp_r) { /* item of average result */ + i_r /= length; + } + a_r.push_back(grp_r); + } + return a_r; + } + + /* 利用神经网络推理微调角度 */ + std::vector> run_infer( + std::string script, float infer_freq, float train_discount, std::vector>& averages); +}; +} + + + +/* 捕获中断信号,结束线程并且退出 */ +void signalHandler(int signum) +{ + LOG_INFO("收到终止信号,准备停止服务器..."); + cv.WakeCv(); /* 唤醒条件信号即关闭程序 */ +} + +/*----SIGNAL ACTION----*/ +// +/* 对信号的响应行为 */ +void set_signal_action() { + + /* 该结构体用于描述信号的处理方式 */ + struct sigaction sa; + + + /* 绑定处理函数 */ + sa.sa_handler = signalHandler; + + /* + * 清空并初始化一个信号掩码集 --------------> 用于指定哪些信号在当前或即将执行的信号处理函数期间应该被阻塞(位掩码) + * “在执行这个信号处理函数时,除了当前正在处理的信号外,还希望临时阻塞其他某些信号” + * 不阻塞其他信号 + * 确保在执行期间没有其他特定的信号会被阻塞 + * 防止处理过程中被其他信号中断 + */ + sigemptyset(&sa.sa_mask); + + /* + * 用于设置信号处理函数的行为特性。 + * 0 - 默认选项 + * SA_NODEFER - 表示在执行信号处理函数时不允许其他信号被阻塞 + * SA_RESETHAND - 在信号处理函数返回后,将信号的处理方式重置为默认 + * SA_NOCLDSTOP - 对于子进程发送的停止信号,父进程不会停止。 + * SA_NOCLDWAIT - 父进程在等待等待子进程终止时不会因为子进程发送信号而收到通知 + * SA_SIGINFO - 使用扩展的信号信息,信号处理函数接收三个参数而不是一个 + */ + sa.sa_flags = 0; + + /* 注册信号 */ + sigaction(SIGINT, &sa, nullptr); /* Ctrl + C */ + sigaction(SIGTERM, &sa, nullptr); /* kill 或 systemctl stop */ + +} + +/*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*/ +/* 初始化pmc并行机器 */ +int pmc_init(po::variables_map&); + +/* 任务池 */ +auto taskPool = std::vector>{}; + +/*----------------------------------------*/ + +/* FIXME: 它们没有清理 + * FIXME: 传入路径、地址 */ +void try_start_i2c_and_camera() +try { + I2C_初始化(); + PCA9685_初始化(); + MPU6050_初始化(); + + /* 初始化相机 */ + Camera_init(640, 480); + Camera_check(); + Camera_setVideoFormat(); + Camera_reqBuf(); + Camera_setup(); + //Camera_run(); +} +catch (std::runtime_error& exp) +{ + std::cout << exp.what() << std::endl; +} + +/* 入口函数 */ +int main(int argc, char** argv) { + + /*------------------------------*/ + /* 设置信号行为*/ + set_signal_action(); + + /*------------------------------*/ + /* 解析命令行参数 */ + po::options_description desc("pmc subsystem start options"); + desc.add_options() /* 定义选项 */ + ("help,h", "display help message") + ("version,v", "display version message") + ("mybot", "run mybot task"); + + /* 参数变量映射关系 */ + po::variables_map vm; + + try { /* 开始解析 */ + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + if (vm.count("help")) { /* 获取帮助页面 */ + std::cout << desc << std::endl; + return 0; + } + if (vm.count("version")) { /* 获取版本信息 */ + std::cout << PMC_VERSION << std::endl; + return 0; + } + } + + catch (const std::exception& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + std::cerr << "using --help to check options message" << std::endl; + throw e; + } + + /*----------------------------------------*/ + if (vm.count("mybot")) { + try_start_i2c_and_camera(); /* 启动硬件模组 FIXME: 没有释放资源 */ + auto task = std::make_shared(); + task->start(); + taskPool.push_back(task); + } + + + + /* + * 等待 + * + * 触发器在信号处理那里 + */ + cv.Wait(); + + /* 主线程被唤醒 */ + for (auto& task: taskPool) { + task->stop(); + } +} + + +namespace qing { + +/* 构造函数,主要是需要传入一个http构造回调 */ +ParserTask::ParserTask(): HttpTask(ADDR, PORT, [this](Http& http) { + + + /* FIXME: 传入模型路径 */ + const char* target = "../public/models/1.txt"; + if (std::filesystem::exists(target)) { + std::cout << "load model data from file..." << std::endl; + std::ifstream file; + file.open(target); + nn.load(file); + file.close(); + } + else { /* FIXME: 单独放在一个函数里 */ + std::cout << "create model data rand..." << std::endl; + + auto layer1 = nnl::Create_in_Factory(18, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer2 = nnl::Create_in_Factory(36, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer3 = nnl::Create_in_Factory(36, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer4 = nnl::Create_in_Factory(36, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer5 = nnl::Create_in_Factory(36, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer6 = nnl::Create_in_Factory(36, 16, 0.01, nnl::ActivationFunc::Sigmoid); + + nn.add(layer1); + nn.add(layer2); + nn.add(layer3); + nn.add(layer4); + nn.add(layer5); + nn.add(layer6); + + /* 储存模型 */ + std::ofstream file; + file.open("../public/models/1.txt"); + if (!file) { + std::cout << "Open Model failed" << std::endl; + } + else { + nn.save(file); + file.close(); + } + } + + nn.print_shape(); + + + /* FIXME:当消息体为空时抛出异常即可 */ + http.post("/api/v1/mybot-sample", [this](const httplib::Request& req, httplib::Response& res) { + try{ + if (req.body.empty()) + throw NoRequestBodyException("/api/v1/mybot-sample"); + mtx.lock(); + auto r = run_infer(req.body, 0.0, 0.0, averages); /* 推理结果无效化 */ + pool.push_back(r); + averages = calc_aves(pool); + mtx.unlock(); + res.set_content("OK", "text/plain"); + } + catch (NoRequestBodyException& exp) { + res.set_content("no request body", "text/plain"); + res.status =400; + } + catch (std::exception& exp) { + res.set_content(exp.what(), "text/plain"); + res.status =400; + } + + }); + + /* FIXME: 需要先取得模板数据 */ + http.post("/api/v1/mybot-nn", [this](const httplib::Request& req, httplib::Response& res) { + try{ + if (req.body.empty()) + throw NoRequestBodyException("/api/v1/mybot-nn"); + mtx.lock(); + auto r =run_infer(req.body, 0.1, 10.0, averages); + for (auto& v: r) { /* 输出运行结果 */ + std::cout << "("; + for (auto& i: v) { + std::cout << i; + std::cout << ","; + } + std::cout << ")\t"; + std::cout << std::endl; + } + mtx.unlock(); + res.set_content("OK", "text/plain"); + } + catch (NoRequestBodyException& exp) { + res.set_content("no request body", "text/plain"); + res.status =400; + } + catch (std::exception& exp) { + res.set_content(exp.what(), "text/plain"); + res.status =400; + } + }); + +}) {} + +/*--------------------------------------------------------------------*/ +/*--------------------------------------------------------------------*/ +/* 神经网络推理 */ +std::vector> ParserTask::run_infer(std::string script, float infer_freq, float train_discount, std::vector>& averages) { + auto parser = ActParser(); + parser.fromStr(script); + auto bot = parser.get(); + auto res = std::vector>{}; + auto all_count = 0; + while (true) { + try{ + std::cout << "------------------------------"<< std::endl; + MPU6050_传感器数据 data = MPU6050_读传感器(); + float pitch, roll; + MPU6050_计算角度(data, pitch, roll); + auto nor_pitch = normalize_pitch(pitch); + auto nor_roll = normalize_roll(roll); + auto act = parser.now(); /* 获取一个动作 */ + auto x = std::vector(); /* 创建输入 */ + x.push_back(nor_pitch); + x.push_back(nor_roll); + auto i{0}; + for (; i < act.size()-1; ++i) { /* 跳过了延时数值 */ + float a; + if (bot[i] == 0) { a = 0; } /* 空舵机位 */ + else { a = (float)act[i] / bot[i]; } + x.push_back(a); + } + auto x1 = x; + auto o = nn.forward(x1); /* 前向反馈 */ + auto j{2}; + auto new_act = std::vector (); + unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::mt19937 generator(seed); + std::uniform_real_distribution distribution(-0.5, 0.5); // 1-100 均匀分布 + for (; j http=std::make_unique(http_addr, http_port); + + this->callback(*http); + + if (th.check() == Fsm::Stat::START) { /* 只跑一次 */ + th.run(); /* 标记为启动 */ + http->run(); /* 这个会堵塞线程以进行监听 */ + } + + /* HTTP服务器异常关闭 */ + if (th.check() == Fsm::Stat::RUNNING) { + th.stop(); + } + + + }; + + f_t LoopEvent = [](Thread& _) { + throw std::runtime_error("Task not support this Event"); + }; + + f_t ClearEvent = [this](Thread& _) { + if (this->http) + this->http.reset(); /* */ + }; + + th = std::make_unique (StopEvent, WakeEvent, LoopEvent, ClearEvent); + } + +} diff --git a/lci/src/mainNn.cpp b/lci/src/mainNn.cpp new file mode 100644 index 0000000..125cc11 --- /dev/null +++ b/lci/src/mainNn.cpp @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include +#include +#include +//#include +#include "hd/Camera.h" +#include "nn/ImageLoader.hpp" +#include "nn/ConvLayer.hpp" +#include "nn/PoolingLayer.hpp" +#include "nn/FlattenLayer.hpp" +#include "nn/CNNBuilder.hpp" +#include "nn/NNBuilder.hpp" +#include "nn/NeuralNetwork.hpp" + +using namespace qing; + + +// 定义颜色用于不同的人脸框 +const unsigned char colors[][3] = { + {255, 0, 0}, // 红色 + {0, 255, 0}, // 绿色 + {0, 0, 255}, // 蓝色 + {255, 255, 0}, // 黄色 + {255, 0, 255} // 紫色 +}; + +void take_a_photo(const char* path); +int run_facerec(const char* in, const char* out); + +// 主函数 +int main(int argc, char* argv[]) { + + ImageLoader image_loader(3, 480, 640, true, false); + + ConvLayer conv1(3, 16, 3, 1, 1); + PoolingLayer pool1(2, 2, 2, 0, true); + ConvLayer conv2(16, 32, 3, 1, 1); + PoolingLayer pool2(2, 2, 2, 0, true); + ConvLayer conv3(32, 64, 3, 1, 1); + PoolingLayer pool3(2, 2, 2, 0, true); + ConvLayer conv4(64, 128, 3, 1, 1); + PoolingLayer pool4(2, 2, 2, 0, true); + ConvLayer conv5(128, 256, 3, 1, 1); + PoolingLayer pool5(2, 2, 2, 0, true); + ConvLayer conv6(256, 512, 3, 1, 1); + PoolingLayer pool6(2, 2, 2, 0, true); + FlattenLayer flatten; + + CNNBuilder cnn; + int in_channels = 3; + int in_h = 480; + int in_w = 640; + int batch_size = 1; + + cnn.add_conv_layer(conv1, in_channels, in_h, in_w); + cnn.add_pool_layer(pool1, 16, in_h, in_w); + cnn.add_conv_layer(conv2, 16, in_h/2, in_w/2); + cnn.add_pool_layer(pool2, 32, in_h/2, in_w/2); + cnn.add_conv_layer(conv3, 32, in_h/4, in_w/4); + cnn.add_pool_layer(pool3, 64, in_h/4, in_w/4); + cnn.add_conv_layer(conv4, 64, in_h/8, in_w/8); + cnn.add_pool_layer(pool4, 128, in_h/8, in_w/8); + cnn.add_conv_layer(conv5, 128, in_h/16, in_w/16); + cnn.add_pool_layer(pool5, 256, in_h/16, in_w/16); + cnn.add_conv_layer(conv6, 256, in_h/32, in_w/32); + cnn.add_pool_layer(pool6, 512, in_h/32, in_w/32); + cnn.add_flatten_layer(flatten, 512, 7, 10); + + cnn.print_architecture(); + + NNBuilder nn; + using nnl = NeuralNetwork; + + auto layer0 = nnl::Create_in_Factory(15360, 6500,0.5, nnl::ActivationFunc::Leaky_ReLU); + auto layer1 = nnl::Create_in_Factory(6500, 1500, 0.45, nnl::ActivationFunc::Leaky_ReLU); + auto layer2 = nnl::Create_in_Factory(1500, 300, 0.40, nnl::ActivationFunc::Leaky_ReLU); + auto layer3 = nnl::Create_in_Factory(300, 70, 0.35, nnl::ActivationFunc::Leaky_ReLU); + auto layer4 = nnl::Create_in_Factory(70, 5, 0.30, nnl::ActivationFunc::Sigmoid); + + nn.add(layer0); + nn.add(layer1); + nn.add(layer2); + nn.add(layer3); + nn.add(layer4); + + nn.print_shape(); + + + //Camera_init(640, 480); + bool flag = true; + while (flag) { + + + //std::string imgpath = std::string("./dataSet/" + std::to_string(time(NULL)) + ".jpeg"); + //std::string txtpath =std::string("./dataSet/" + std::to_string(time(NULL)) + ".txt"); + + //bool flag; + //auto img = get_frame_from_camera(flag); + //img.save(imgpath.c_str()); + + //if (run_facerec(imgpath.c_str(), txtpath.c_str())) + // throw std::runtime_error("facerec"); + + std::string data_root = "./dataSet"; + namespace fs = std::filesystem; + for (const auto& entry : fs::recursive_directory_iterator(data_root)) { + if (!fs::is_regular_file(entry.status())) + continue; + + std::string basename = entry.path().stem().string(); + std::string txtpath = data_root + "/" + basename + ".txt"; + std::string imgpath = data_root + "/" + basename+".jpeg"; + auto img = cimg_library::CImg(imgpath.c_str()); + + auto image_data = image_loader.load_from_cimg(img, true); + if (image_data.empty()) { + std::cerr << "Failed to load image!" << std::endl; + break; + } + + /* 前向传播 */ + auto output = cnn.forward(image_data, batch_size, true); + if (!output.empty()) { + std::cout << "Forward pass successful!" << std::endl; + std::cout << "Input size: " << image_data.size() << std::endl; + std::cout << "Output size: " << output.size() << std::endl; + + // 计算输出统计信息 + float sum = 0.0f, max_val = output[0], min_val = output[0]; + for (float val : output) { + sum += val; + if (val > max_val) max_val = val; + if (val < min_val) min_val = val; + } + + std::cout << "Output statistics:" << std::endl; + std::cout << " Mean: " << sum / output.size() << std::endl; + std::cout << " Min: " << min_val << std::endl; + std::cout << " Max: " << max_val << std::endl; + } + + std::vector t(5); + std::ifstream file(txtpath); + if (!file) t[0] = 0; + else { + t[0] = 1; + for (int i=0; i<5; ++i) { + file >> t[i+1]; + std::cout << t[i+1] << " "; + } + } + std::cout<< std::endl; + auto r = nn.forward(output); + auto y = nn.cal_err(r, t); + + /* 不存在人脸时,位置信息不计入 */ + if (t[0] == 0) + for (int i =1; i< 5; i++) + y[i]= 0; + else { + for (auto i: y) { + std::cout << i << " "; + } + std::cout << std::endl; + + auto fix_img = img.draw_rectangle(t[4]*640,t[1]*480, t[2]*640,t[3]*480, colors[1], 1, ~0U); /* 抽象为函数 */ + fix_img = fix_img.draw_rectangle(r[4]*640,r[1]*480, r[2]*640,r[3]*480, colors[0], 1, ~0U); + std::string respath = "./resSet/" + basename+".jpeg"; + fix_img.save(respath.c_str()); + } + y = nn.backward(y); + y = cnn.backward(y); + } + } + + //Camera_close(); +} + +int run_facerec(const char* in, const char* out) { + auto cmd = std::string("python tools/facerec.py detect "); + cmd += in; + cmd += " --output "; + cmd += out; + return system(cmd.c_str()); +} \ No newline at end of file diff --git a/lci/src/mainParser.cpp b/lci/src/mainParser.cpp new file mode 100644 index 0000000..9c3a48f --- /dev/null +++ b/lci/src/mainParser.cpp @@ -0,0 +1,17 @@ +/* + * 该文件可以解析动作脚本(.bot)并且将角度映射到动作上 。 + * + * FIXME: 改为可以启动http服务器进行监听 + */ + +#include "Dashun.h" +#include "Dashun_linux.hpp" + +auto parser = qing::ActParser(); +int main(int argc, char** argv) { /* argc >= 1 */ + I2C_init(); + PCA9685_init(); + parser.fromStdin(); + //parser.fromStr(argv[1]); + parser.play(); +} diff --git a/lci/src/mainParserNn.cpp b/lci/src/mainParserNn.cpp new file mode 100644 index 0000000..a910e61 --- /dev/null +++ b/lci/src/mainParserNn.cpp @@ -0,0 +1,253 @@ +#include "Dashun.h" +#include "Dashun_linux.hpp" +#include "test_nn_20251207_0.hpp" +#include "test_nn_20251219_0.hpp" +#include +#include + + + +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +/* +* 适用于机器人的DRL(深度强化学习) +* +* 【方案1】 +* 蜘蛛机器人拥有10个舵机(4只胳膊、4只腿、2个摄像云台),它还有2个陀螺仪参数。 +* 将舵机目前的位置+陀螺仪参数传递给神经网络,输出10个舵机的概率值 +* 将概率值加上一个0~1之间的随机因子,获取最终输出 +* +* 每个舵机180度,即 10 * 180 = 1800 个参数 +* +* 【方案2】 +* +* 将蜘蛛机器人当前的陀螺仪读数,以及下一个动作的参数传递给模型 +* +* 教师数据根据下一个动作的陀螺仪偏差决定 +*/ + +float normalize_pitch(float pitch) { + return (pitch+3.14) / (2*3.14); +} + +float normalize_roll(float roll) { + return (roll+0.28) / (2* 0.28); /*观测值*/ +} + +int main() { + + I2C_init(); + PCA9685_init(); + MPU6050_init(); + + /* 初始化相机 */ + //Camera_init(640, 480); + //Camera_check(); + //Camera_setVideoFormat(); + //Camera_reqBuf(); + //Camera_setup(); + //Camera_run(); + + + /* 创建归一化器 */ + //ImageLoader image_loader(3, 64, 64, true, false); + + // 创建网络组件 + //ConvLayer conv1(3, 8, 3, 1, 1); // 输入3通道,输出16通道,3x3卷积,padding=1 + //PoolingLayer pool1(2, 2, 2, 0, true); // 2x2最大池化,步长2 + //ConvLayer conv2(8, 16, 3, 1, 1); // 输入3通道,输出16通道,3x3卷积,padding=1 + //PoolingLayer pool2(2, 2, 2, 0, true); // 2x2最大池化,步长2 + //ConvLayer conv3(16, 32, 3, 1, 1); // 输入16通道,输出32通道 + //PoolingLayer pool3(2, 2, 2, 0, true); // 2x2最大池化,步长2 + //ConvLayer conv4(32, 64, 3, 1, 1); // 输入16通道,输出32通道 + //PoolingLayer pool4(2, 2, 2, 0, true); // 2x2最大池化,步长2 + //ConvLayer conv5(64, 128, 3, 1, 1); // 输入16通道,输出32通道 + //PoolingLayer pool5(2, 2, 2, 0, true); // 2x2最大池化,步长2 + //ConvLayer conv6(128, 256, 3, 1, 1); // 输入16通道,输出32通道 + //PoolingLayer pool6(2, 2, 2, 0, true); // 2x2最大池化,步长2 + //FlattenLayer flatten; // 展平层 + + // 使用CNN构建器 + //CNNBuilder cnn; + + // 定义输入尺寸 + //int input_channels = 3; + //int input_height = 64; + //int input_width = 64; + //int batch_size = 1; + + // 构建网络 + //cnn.add_conv_layer(conv1, input_channels, input_height, input_width); + //cnn.add_pool_layer(pool1, 8, input_height, input_width); // 卷积后尺寸不变(因padding=1) + //cnn.add_conv_layer(conv2, 8, input_height/2, input_width/2); // 池化后尺寸减半 + //cnn.add_pool_layer(pool2, 16, input_height/2, input_width/2); + //cnn.add_conv_layer(conv3, 16, input_height/4, input_width/4); // 池化后尺寸减半 + //cnn.add_pool_layer(pool3, 32, input_height/4, input_width/4); + //cnn.add_conv_layer(conv4, 32, input_height/8, input_width/8); // 池化后尺寸减半 + //cnn.add_pool_layer(pool4, 64, input_height/8, input_width/8); + //cnn.add_conv_layer(conv5, 64, input_height/16, input_width/16); // 池化后尺寸减半 + //cnn.add_pool_layer(pool5, 128, input_height/16, input_width/16); + //cnn.add_conv_layer(conv6, 128, input_height/32, input_width/32); // 池化后尺寸减半 + //cnn.add_pool_layer(pool6, 256, input_height/32, input_width/32); + //cnn.add_flatten_layer(flatten, 256, input_height/64, input_width/64); + + // 打印网络结构 + //cnn.print_architecture(); + + qing::NNBuilder nn; + using nnl = NeuralNetwork; + //auto layer1 = nnl::Create_in_Factory(256, 512, 0.01, nnl::ActivationFunc::Sigmoid); + //auto layer2 = nnl::Create_in_Factory(512, 256, 0.01, nnl::ActivationFunc::Sigmoid); + //auto layer3 = nnl::Create_in_Factory(256, 100, 0.01, nnl::ActivationFunc::Sigmoid); + //auto layer4 = nnl::Create_in_Factory(100, 10, 0.01, nnl::ActivationFunc::Sigmoid); + //nn.add(layer1); + //nn.add(layer2); + //nn.add(layer3); + //nn.add(layer4); + + auto layer1 = nnl::Create_in_Factory(18, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer2 = nnl::Create_in_Factory(36, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer3 = nnl::Create_in_Factory(36, 36, 0.01, nnl::ActivationFunc::Leaky_ReLU); + auto layer4 = nnl::Create_in_Factory(36, 16, 0.01, nnl::ActivationFunc::Sigmoid); + + nn.add(layer1); + nn.add(layer2); + nn.add(layer3); + nn.add(layer4); + nn.print_shape(); + + + auto parser = qing::ActParser(); + parser.fromStdin(); + auto bot = parser.get(); + while (true) { + try{ + std::cout << "-----------------------" << std::endl; + MPU6050_SensorData data = MPU6050_readSensorData(); + float pitch, roll; + MPU6050_calAngle(data, pitch, roll); + printf("pitch: %.2f\troll: %.2f\n"); + + /* 获取一个动作 */ + auto act = parser.now(); + auto x = std::vector(); + auto nor_pitch = normalize_pitch(pitch); + auto nor_roll = normalize_roll(roll); + x.push_back(nor_pitch); + x.push_back(nor_roll); + auto i{0}; + for (; i < act.size()-1; ++i) { + float a; + if (bot[i] == 0) { /* 空舵机位 */ + a = 0; + } + else { + a = (float)act[i] / bot[i]; + } + x.push_back(a); + std::cout << a << ","; + } + std::cout << std::endl; + + /* 前向反馈 */ + auto x1 = x; + auto o = nn.forward(x1); + //auto count1{0} + //for (auto& item: o) { + // x[count1] += x[count1] * o * 2 * 0.1; /* 10% */ + // count++; + //} + auto j{2}; + auto new_act = std::vector(); + for (; j (); + //err.push_back(); + //nor_pitch > 0) /* 计算误差 */ + // ? ((pitch1 > 0) ? nor_pitch - pitch1 : nor_pitch + pitch1 ) + // : ((pitch1 < 0) ? pitch1 - nor_pitch : -(nor_pitch + pitch1)); + + auto count3{0}; + for (auto& item: o) { + item *= err[count3++]; + } + + nn.backward(err); + + } + + catch(std::runtime_error& exp) + { + std::cout << exp.what() << std::endl; + break; + } + } + + //bool flag = true; + //while (flag) { + + //auto img = get_frame_from_camera(flag); + //auto image_data = image_loader.load_from_cimg(img, true); + //if (image_data.empty()) { + // std::cerr << "Failed to load image!" << std::endl; + // break; + //} + + /* 前向传播 */ + //auto output = cnn.forward(image_data, batch_size, true); + //if (!output.empty()) { + // std::cout << "Forward pass successful!" << std::endl; + // std::cout << "Input size: " << image_data.size() << std::endl; + // std::cout << "Output size: " << output.size() << std::endl; + + // 计算输出统计信息 + // float sum = 0.0f, max_val = output[0], min_val = output[0]; + // for (float val : output) { + // sum += val; + // if (val > max_val) max_val = val; + // if (val < min_val) min_val = val; + // } + + // std::cout << "Output statistics:" << std::endl; + // std::cout << " Mean: " << sum / output.size() << std::endl; + // std::cout << " Min: " << min_val << std::endl; + // std::cout << " Max: " << max_val << std::endl; + //} + + //std::vector t(16); + //auto r = nn.forward(output); + //auto y = nn.cal_err(r, t); + + //for (auto i: y) { + // std::cout << i << " "; + //} + //std::cout << std::endl; + + //y = nn.backward(y); + //y = cnn.backward(y); + + //std::this_thread::sleep_for(std::chrono::microseconds(10)); + + + //} + + //Camera_stop(); + //Camera_unsetup(); + return 0; +} diff --git a/lci/src/net/HttpServer.cpp b/lci/src/net/HttpServer.cpp new file mode 100644 index 0000000..d6fd7ee --- /dev/null +++ b/lci/src/net/HttpServer.cpp @@ -0,0 +1,417 @@ +#include "net/HttpServer.hpp" +#include +#include +#include + +namespace pmc { +namespace net { + +// Session类 - 处理单个HTTP连接 +class HttpServer::Session : public std::enable_shared_from_this { +public: + Session(tcp::socket&& socket, HttpServer* server) + : socket_(std::move(socket)), server_(server) { + } + + void run() { + doRead(); + } + +private: + void doRead() { + auto self = shared_from_this(); + http::async_read(socket_, buffer_, request_, + [this, self](beast::error_code ec, std::size_t) { + if (!ec) { + processRequest(); + } else if (ec != http::error::end_of_stream) { + // 错误处理 + } + }); + } + + void processRequest() { + try { + // 创建响应对象 + auto response = std::make_shared>( + server_->handleRequest(request_) + ); + doWrite(response); + } catch (const std::exception& e) { + std::cerr << "Error processing request: " << e.what() << std::endl; + // 发送错误响应 + auto error_response = std::make_shared>(); + error_response->version(request_.version()); + error_response->result(http::status::internal_server_error); + error_response->set(http::field::content_type, "text/plain"); + error_response->body() = "500 Internal Server Error\n"; + error_response->prepare_payload(); + doWrite(error_response); + } + } + + void doWrite(std::shared_ptr> response) { + auto self = shared_from_this(); + http::async_write(socket_, *response, + [this, self, response](beast::error_code ec, std::size_t) { + if (!ec) { + // 检查是否需要保持连接 + if (!response->keep_alive()) { + socket_.shutdown(tcp::socket::shutdown_send, ec); + } + } + // 继续读取下一个请求 + doRead(); + }); + } + + tcp::socket socket_; + beast::flat_buffer buffer_; + http::request request_; + HttpServer* server_; +}; + +// Listener类 - 接受新连接 +class HttpServer::Listener : public std::enable_shared_from_this { +public: + Listener(asio::io_context& ioc, tcp::endpoint endpoint, HttpServer* server) + : ioc_(ioc), acceptor_(ioc), server_(server) { + beast::error_code ec; + acceptor_.open(endpoint.protocol(), ec); + if (!ec) { + acceptor_.set_option(asio::socket_base::reuse_address(true), ec); + acceptor_.bind(endpoint, ec); + if (!ec) { + acceptor_.listen(asio::socket_base::max_listen_connections, ec); + } + } + if (ec) { + std::cerr << "Listener error: " << ec.message() << std::endl; + } + } + + void run() { + if (acceptor_.is_open()) { + doAccept(); + } + } + +private: + void doAccept() { + acceptor_.async_accept( + [this, self = shared_from_this()](beast::error_code ec, tcp::socket socket) { + if (!ec) { + std::make_shared(std::move(socket), server_)->run(); + } + doAccept(); + }); + } + + asio::io_context& ioc_; + tcp::acceptor acceptor_; + HttpServer* server_; +}; + +// HttpServer实现 - 新构造函数(监听所有接口) +HttpServer::HttpServer(unsigned short port, unsigned int threads) + : address_("0.0.0.0"), port_(port), threads_(threads), + ioc_(std::make_unique(threads)) { + if (!ioc_) { + throw std::runtime_error("Failed to create io_context"); + } +} + +// HttpServer实现 - 新构造函数(指定监听地址) +HttpServer::HttpServer(const std::string& address, unsigned short port, unsigned int threads) + : address_(address), port_(port), threads_(threads), + ioc_(std::make_unique(threads)) { + if (!ioc_) { + throw std::runtime_error("Failed to create io_context"); + } +} + +HttpServer::~HttpServer() { + stop(); +} + +void HttpServer::start() { + if (running_) { + return; + } + + try { + // 创建端点(使用指定的地址和端口) + asio::ip::address ip_address = asio::ip::make_address(address_); + tcp::endpoint endpoint(ip_address, port_); + + // 创建监听器 + listener_ = std::make_shared(*ioc_, endpoint, this); + if (!listener_) { + throw std::runtime_error("Failed to create listener"); + } + listener_->run(); + + running_ = true; + + // 启动工作线程 + for (unsigned int i = 0; i < threads_; ++i) { + worker_threads_.emplace_back([this]() { + try { + ioc_->run(); + } catch (const std::exception& e) { + std::cerr << "Thread exception: " << e.what() << std::endl; + } + }); + } + + std::cout << "HTTP Server started on " << address_ << ":" << port_ + << " with " << threads_ << " threads" << std::endl; + } catch (const std::exception& e) { + std::cerr << "Failed to start server: " << e.what() << std::endl; + running_ = false; + } +} + +void HttpServer::stop() { + if (!running_) { + return; + } + + running_ = false; + + if (ioc_) { + ioc_->stop(); + } + + for (auto& thread : worker_threads_) { + if (thread.joinable()) { + thread.join(); + } + } + worker_threads_.clear(); + + std::cout << "HTTP Server stopped" << std::endl; +} + +void HttpServer::get(const std::string& path, HttpRequestHandler handler) { + get_handlers_[path] = handler; +} + +void HttpServer::post(const std::string& path, HttpRequestHandler handler) { + post_handlers_[path] = handler; +} + +void HttpServer::put(const std::string& path, HttpRequestHandler handler) { + put_handlers_[path] = handler; +} + +void HttpServer::del(const std::string& path, HttpRequestHandler handler) { + delete_handlers_[path] = handler; +} + +void HttpServer::use(MiddlewareHandler middleware) { + middlewares_.push_back(middleware); +} + +void HttpServer::setStaticDirectory(const std::string& path) { + static_directory_ = path; +} + +bool HttpServer::isRunning() const { + return running_; +} + +unsigned short HttpServer::getPort() const { + return port_; +} + +std::string HttpServer::getAddress() const { + return address_; +} + +void HttpServer::run() { + start(); + if (ioc_) { + ioc_->run(); + } +} + +void HttpServer::showStatus() const { + std::cout << "=== HTTP Server Status ===" << std::endl; + std::cout << "Address: " << address_ << std::endl; + std::cout << "Port: " << port_ << std::endl; + std::cout << "Threads: " << threads_ << std::endl; + std::cout << "Running: " << (running_ ? "Yes" : "No") << std::endl; + std::cout << "Static Directory: " << (static_directory_.empty() ? "Not set" : static_directory_) << std::endl; + std::cout << "Registered Routes:" << std::endl; + std::cout << " GET: " << get_handlers_.size() << " handler(s)" << std::endl; + for (const auto& [path, _] : get_handlers_) { + std::cout << " GET " << path << std::endl; + } + std::cout << " POST: " << post_handlers_.size() << " handler(s)" << std::endl; + for (const auto& [path, _] : post_handlers_) { + std::cout << " POST " << path << std::endl; + } + std::cout << " PUT: " << put_handlers_.size() << " handler(s)" << std::endl; + for (const auto& [path, _] : put_handlers_) { + std::cout << " PUT " << path << std::endl; + } + std::cout << " DELETE: " << delete_handlers_.size() << " handler(s)" << std::endl; + for (const auto& [path, _] : delete_handlers_) { + std::cout << " DELETE " << path << std::endl; + } + std::cout << "Middlewares: " << middlewares_.size() << std::endl; + std::cout << "==========================" << std::endl; +} + +std::unordered_map HttpServer::parseQueryParams(const std::string& query) { + std::unordered_map params; + + if (query.empty()) { + return params; + } + + std::vector pairs; + boost::split(pairs, query, boost::is_any_of("&")); + + for (const auto& pair : pairs) { + std::vector key_value; + boost::split(key_value, pair, boost::is_any_of("=")); + + if (key_value.size() == 2) { + params[key_value[0]] = key_value[1]; + } else if (key_value.size() == 1) { + params[key_value[0]] = ""; + } + } + + return params; +} + +http::response HttpServer::handleRequest(const http::request& req) { + // 将 target() 转换为字符串 + std::string target_path = std::string(req.target().data(), req.target().size()); + std::string query_string; + + // 分离路径和查询参数 + auto query_pos = target_path.find('?'); + if (query_pos != std::string::npos) { + query_string = target_path.substr(query_pos + 1); + target_path = target_path.substr(0, query_pos); + } + + // 解析查询参数 + auto query_params = parseQueryParams(query_string); + + // 准备响应对象 + http::response response; + response.version(req.version()); + response.set(http::field::server, "Boost.Beast HttpServer"); + response.set(http::field::content_type, "text/plain"); + response.keep_alive(req.keep_alive()); + + // 执行中间件链 + bool middleware_handled = false; + for (const auto& middleware : middlewares_) { + if (!middleware(req, response, query_params)) { + middleware_handled = true; + break; + } + } + + // 如果中间件处理了请求,直接返回 + if (middleware_handled) { + response.prepare_payload(); + return response; + } + + // 查找路由处理器 + HttpRequestHandler handler = nullptr; + + switch (req.method()) { + case http::verb::get: { + auto it = get_handlers_.find(target_path); + if (it != get_handlers_.end()) { + handler = it->second; + } + break; + } + case http::verb::post: { + auto it = post_handlers_.find(target_path); + if (it != post_handlers_.end()) { + handler = it->second; + } + break; + } + case http::verb::put: { + auto it = put_handlers_.find(target_path); + if (it != put_handlers_.end()) { + handler = it->second; + } + break; + } + case http::verb::delete_: { + auto it = delete_handlers_.find(target_path); + if (it != delete_handlers_.end()) { + handler = it->second; + } + break; + } + default: + break; + } + + // 处理静态文件 + if (!handler && !static_directory_.empty()) { + std::string file_path = static_directory_ + target_path; + std::ifstream file(file_path, std::ios::binary); + + if (file.is_open()) { + std::stringstream buffer; + buffer << file.rdbuf(); + response.result(http::status::ok); + response.body() = buffer.str(); + + // 根据文件扩展名设置Content-Type + if (boost::algorithm::ends_with(file_path, ".html")) { + response.set(http::field::content_type, "text/html"); + } else if (boost::algorithm::ends_with(file_path, ".css")) { + response.set(http::field::content_type, "text/css"); + } else if (boost::algorithm::ends_with(file_path, ".js")) { + response.set(http::field::content_type, "application/javascript"); + } else if (boost::algorithm::ends_with(file_path, ".json")) { + response.set(http::field::content_type, "application/json"); + } else if (boost::algorithm::ends_with(file_path, ".png")) { + response.set(http::field::content_type, "image/png"); + } else if (boost::algorithm::ends_with(file_path, ".jpg") || + boost::algorithm::ends_with(file_path, ".jpeg")) { + response.set(http::field::content_type, "image/jpeg"); + } + + response.prepare_payload(); + return response; + } + } + + // 如果找到处理器,调用它 + if (handler) { + try { + return handler(req, query_params); + } catch (const std::exception& e) { + std::cerr << "Handler exception: " << e.what() << std::endl; + response.result(http::status::internal_server_error); + response.body() = "500 Internal Server Error\n"; + response.prepare_payload(); + return response; + } + } + + // 404 Not Found + response.result(http::status::not_found); + response.body() = "404 Not Found\n"; + response.prepare_payload(); + return response; +} + +} // namespace net +} // namespace pmc \ No newline at end of file diff --git a/lci/src/net/WebSocketClient.cpp b/lci/src/net/WebSocketClient.cpp new file mode 100644 index 0000000..0781ae9 --- /dev/null +++ b/lci/src/net/WebSocketClient.cpp @@ -0,0 +1,386 @@ +#include "net/WebSocketClient.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pmc { +namespace net { + +namespace beast = boost::beast; +namespace asio = boost::asio; +using tcp = asio::ip::tcp; + +// 内部实现结构体 +struct WebSocketClient::Impl { + // 配置参数 + std::string host; + std::string port; + std::string path; + + // Boost 对象 + asio::io_context ioc; + tcp::resolver resolver; + beast::websocket::stream ws; + + // 线程管理 + std::thread io_thread; + std::atomic running{false}; + + // 回调函数 + WebSocketClientBase::MessageCallback message_callback; + WebSocketClientBase::ErrorCallback error_callback; + WebSocketClientBase::ConnectCallback connect_callback; + WebSocketClientBase::CloseCallback close_callback; + + // 消息队列 + std::queue send_queue; + std::mutex queue_mutex; + std::condition_variable queue_cv; + std::atomic sending{false}; + + // 状态标志 + std::atomic connected{false}; + std::atomic connecting{false}; + std::atomic stopping{false}; + + // 配置选项 + bool auto_reconnect{false}; + int reconnect_interval_ms{3000}; + int heartbeat_interval_ms{30000}; + + // 构造函数 + Impl(const std::string& host, const std::string& port, const std::string& path) + : host(host) + , port(port) + , path(path) + , resolver(asio::make_strand(ioc)) + , ws(asio::make_strand(ioc)) + { + } + + // 析构函数 + ~Impl() { + stop(); + } + + // 启动IO线程 + void start() { + if (!running) { + running = true; + io_thread = std::thread([this]() { + while (running) { + try { + ioc.run(); + break; + } catch (const std::exception& e) { + std::cerr << "IO上下文异常: " << e.what() << std::endl; + } + } + }); + } + } + + // 停止IO线程 + void stop() { + running = false; + stopping = true; + + if (io_thread.joinable()) { + ioc.stop(); + io_thread.join(); + } + } + + // 执行连接 + void doConnect() { + if (connecting || connected) { + return; + } + + connecting = true; + connected = false; + + // 解析主机名 + resolver.async_resolve(host, port, + [this](beast::error_code ec, tcp::resolver::results_type results) { + onResolve(ec, results); + }); + } + + // 解析完成回调 + void onResolve(beast::error_code ec, tcp::resolver::results_type results) { + if (ec) { + onError("解析失败: " + ec.message()); + return; + } + + // 连接到解析出的端点 + beast::get_lowest_layer(ws).async_connect(results, + [this](beast::error_code ec, tcp::resolver::results_type::endpoint_type) { + onConnect(ec); + }); + } + + // 连接完成回调 + void onConnect(beast::error_code ec) { + if (ec) { + onError("连接失败: " + ec.message()); + return; + } + + // 设置WebSocket选项 + ws.set_option(beast::websocket::stream_base::timeout::suggested( + beast::role_type::client)); + + // 执行WebSocket握手 + ws.async_handshake(host, path, + [this](beast::error_code ec) { + onHandshake(ec); + }); + } + + // 握手完成回调 + void onHandshake(beast::error_code ec) { + connecting = false; + + if (ec) { + onError("握手失败: " + ec.message()); + return; + } + + connected = true; + + // 调用连接成功回调 + if (connect_callback) { + connect_callback(true); + } + + // 开始读取消息 + doRead(); + + // 开始发送队列中的消息 + doSend(); + } + + // 读取消息 + void doRead() { + if (!connected) { + return; + } + + ws.async_read(buffer, + [this](beast::error_code ec, std::size_t bytes_transferred) { + onRead(ec, bytes_transferred); + }); + } + + // 读取完成回调 + void onRead(beast::error_code ec, std::size_t bytes_transferred) { + if (ec) { + if (ec == beast::websocket::error::closed) { + // 正常关闭 + onClose(); + } else { + onError("读取失败: " + ec.message()); + } + return; + } + + // 处理接收到的消息 + std::string message = beast::buffers_to_string(buffer.data()); + buffer.consume(bytes_transferred); + + if (message_callback) { + message_callback(message); + } + + // 继续读取 + doRead(); + } + + // 发送消息 + void doSend() { + if (!connected || sending) { + return; + } + + std::unique_lock lock(queue_mutex); + if (send_queue.empty()) { + return; + } + + sending = true; + std::string message = std::move(send_queue.front()); + send_queue.pop(); + lock.unlock(); + + ws.async_write(asio::buffer(message), + [this](beast::error_code ec, std::size_t bytes_transferred) { + onWrite(ec, bytes_transferred); + }); + } + + // 写入完成回调 + void onWrite(beast::error_code ec, std::size_t bytes_transferred) { + sending = false; + + if (ec) { + onError("写入失败: " + ec.message()); + return; + } + + // 继续发送队列中的消息 + doSend(); + } + + // 错误处理 + void onError(const std::string& error) { + connecting = false; + connected = false; + + std::cerr << "WebSocket错误: " << error << std::endl; + + if (error_callback) { + error_callback(error); + } + + // 自动重连 + if (auto_reconnect && !stopping) { + std::this_thread::sleep_for(std::chrono::milliseconds(reconnect_interval_ms)); + asio::post(ioc, [this]() { doConnect(); }); + } + } + + // 连接关闭 + void onClose() { + connected = false; + + if (close_callback) { + close_callback(); + } + + // 自动重连 + if (auto_reconnect && !stopping) { + std::this_thread::sleep_for(std::chrono::milliseconds(reconnect_interval_ms)); + asio::post(ioc, [this]() { doConnect(); }); + } + } + +private: + beast::flat_buffer buffer; +}; + +// WebSocketClient 实现 +WebSocketClient::WebSocketClient(const std::string& host, const std::string& port, const std::string& path) + : impl_(std::make_unique(host, port, path)) +{ + impl_->start(); +} + +WebSocketClient::~WebSocketClient() { + disconnect(); +} + +void WebSocketClient::setMessageCallback(MessageCallback callback) { + impl_->message_callback = callback; +} + +void WebSocketClient::setErrorCallback(ErrorCallback callback) { + impl_->error_callback = callback; +} + +void WebSocketClient::setConnectCallback(ConnectCallback callback) { + impl_->connect_callback = callback; +} + +void WebSocketClient::setCloseCallback(CloseCallback callback) { + impl_->close_callback = callback; +} + +bool WebSocketClient::connect(int timeout_ms) { + if (impl_->connecting || impl_->connected) { + return false; + } + + impl_->doConnect(); + return true; +} + +void WebSocketClient::disconnect() { + if (!impl_->connected && !impl_->connecting) { + return; + } + + impl_->stopping = true; + + asio::post(impl_->ioc, [this]() { + beast::error_code ec; + impl_->ws.close(beast::websocket::close_code::normal, ec); + impl_->connected = false; + impl_->connecting = false; + }); +} + +bool WebSocketClient::isConnected() const { + return impl_->connected; +} + +bool WebSocketClient::send(const std::string& message) { + if (!impl_->connected) { + return false; + } + + { + std::lock_guard lock(impl_->queue_mutex); + impl_->send_queue.push(message); + } + + impl_->queue_cv.notify_one(); + asio::post(impl_->ioc, [this]() { impl_->doSend(); }); + + return true; +} + +bool WebSocketClient::sendBinary(const void* data, size_t size) { + if (!impl_->connected) { + return false; + } + + std::string message(static_cast(data), size); + return send(message); +} + +void WebSocketClient::setAutoReconnect(bool enable, int interval_ms) { + impl_->auto_reconnect = enable; + impl_->reconnect_interval_ms = interval_ms; +} + +void WebSocketClient::setHeartbeatInterval(int interval_ms) { + impl_->heartbeat_interval_ms = interval_ms; +} + +std::string WebSocketClient::getHost() const { + return impl_->host; +} + +std::string WebSocketClient::getPort() const { + return impl_->port; +} + +std::string WebSocketClient::getPath() const { + return impl_->path; +} + +} // namespace net +} // namespace pmc \ No newline at end of file diff --git a/lci/src/net/WebSocketClientSSL.cpp b/lci/src/net/WebSocketClientSSL.cpp new file mode 100644 index 0000000..16d5f22 --- /dev/null +++ b/lci/src/net/WebSocketClientSSL.cpp @@ -0,0 +1,620 @@ +#include "net/WebSocketClientSSL.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pmc { +namespace net { + +namespace beast = boost::beast; +namespace asio = boost::asio; +namespace ssl = asio::ssl; +using tcp = asio::ip::tcp; +using websocket = beast::websocket::stream>; + +// 内部实现结构体 +struct WebSocketClientSSL::Impl { + // 配置参数 + std::string host; + std::string port; + std::string path; + + // SSL 配置 + bool verify_certificate{true}; + std::string cert_file; + std::string key_file; + std::string ca_file; + std::string ciphers; + std::string sni_hostname; + long ssl_options{ssl::context::default_workarounds | + ssl::context::no_sslv2 | + ssl::context::no_sslv3}; + + // Boost 对象 + asio::io_context ioc; + ssl::context ssl_ctx{ssl::context::tlsv12_client}; + tcp::resolver resolver; + websocket ws; + asio::steady_timer heartbeat_timer; + asio::steady_timer reconnect_timer; + + // 回调函数 + MessageCallback message_callback; + ErrorCallback error_callback; + ConnectCallback connect_callback; + CloseCallback close_callback; + + // 状态管理 + std::atomic connected{false}; + std::atomic connecting{false}; + std::atomic stopping{false}; + std::atomic auto_reconnect{false}; + std::atomic reconnect_interval{3000}; + std::atomic heartbeat_interval{30000}; + + // 消息队列 + struct QueuedMessage { + std::string data; + bool is_binary; + }; + std::queue send_queue; + std::mutex queue_mutex; + std::condition_variable queue_cv; + std::atomic writing{false}; + + // 接收缓冲区 + beast::flat_buffer read_buffer; + + // 线程 + std::thread io_thread; + + Impl(const std::string& h, const std::string& p, const std::string& pt) + : host(h) + , port(p) + , path(pt) + , resolver(asio::make_strand(ioc)) + , ws(asio::make_strand(ioc), ssl_ctx) + , heartbeat_timer(asio::make_strand(ioc)) + , reconnect_timer(asio::make_strand(ioc)) { + + // 配置 SSL 上下文 + configureSSLContext(); + } + + ~Impl() { + stopping = true; + if (io_thread.joinable()) { + ioc.stop(); + io_thread.join(); + } + } + + void configureSSLContext() { + try { + // 设置 SSL 选项 + ssl_ctx.set_options(ssl_options); + + // 设置密码列表 + if (!ciphers.empty()) { + SSL_CTX_set_cipher_list(ssl_ctx.native_handle(), ciphers.c_str()); + } + + // 加载证书文件 + if (!cert_file.empty()) { + ssl_ctx.use_certificate_file(cert_file, ssl::context::pem); + } + + // 加载私钥文件 + if (!key_file.empty()) { + ssl_ctx.use_private_key_file(key_file, ssl::context::pem); + } + + // 加载 CA 证书 + if (!ca_file.empty()) { + ssl_ctx.load_verify_file(ca_file); + } else { + // 使用系统默认的 CA 证书 + ssl_ctx.set_default_verify_paths(); + } + + // 设置验证模式 + if (verify_certificate) { + ssl_ctx.set_verify_mode(ssl::verify_peer | ssl::verify_fail_if_no_peer_cert); + } else { + ssl_ctx.set_verify_mode(ssl::verify_none); + } + + } catch (const std::exception& e) { + std::cerr << "SSL 上下文配置错误: " << e.what() << std::endl; + } + } + + void setSNI() { + // 设置 SNI 主机名 + if (!sni_hostname.empty()) { + if (!SSL_set_tlsext_host_name(ws.next_layer().native_handle(), sni_hostname.c_str())) { + beast::error_code ec{static_cast(::ERR_get_error()), asio::error::get_ssl_category()}; + throw beast::system_error{ec}; + } + } else if (!host.empty()) { + // 使用主机名作为 SNI + if (!SSL_set_tlsext_host_name(ws.next_layer().native_handle(), host.c_str())) { + beast::error_code ec{static_cast(::ERR_get_error()), asio::error::get_ssl_category()}; + throw beast::system_error{ec}; + } + } + } +}; + +// 构造函数 +WebSocketClientSSL::WebSocketClientSSL(const std::string& host, const std::string& port, const std::string& path) + : impl_(std::make_unique(host, port, path)) { +} + +// 析构函数 +WebSocketClientSSL::~WebSocketClientSSL() { + disconnect(); +} + +// 回调函数设置 +void WebSocketClientSSL::setMessageCallback(MessageCallback callback) { + impl_->message_callback = std::move(callback); +} + +void WebSocketClientSSL::setErrorCallback(ErrorCallback callback) { + impl_->error_callback = std::move(callback); +} + +void WebSocketClientSSL::setConnectCallback(ConnectCallback callback) { + impl_->connect_callback = std::move(callback); +} + +void WebSocketClientSSL::setCloseCallback(CloseCallback callback) { + impl_->close_callback = std::move(callback); +} + +// SSL/TLS 配置 +void WebSocketClientSSL::setVerifyCertificate(bool verify) { + impl_->verify_certificate = verify; + impl_->configureSSLContext(); +} + +void WebSocketClientSSL::setCertificateFile(const std::string& cert_file) { + impl_->cert_file = cert_file; + impl_->configureSSLContext(); +} + +void WebSocketClientSSL::setPrivateKeyFile(const std::string& key_file) { + impl_->key_file = key_file; + impl_->configureSSLContext(); +} + +void WebSocketClientSSL::setCertificateAuthorityFile(const std::string& ca_file) { + impl_->ca_file = ca_file; + impl_->configureSSLContext(); +} + +void WebSocketClientSSL::setSSLContextOptions(long options) { + impl_->ssl_options = options; + impl_->configureSSLContext(); +} + +void WebSocketClientSSL::setCiphers(const std::string& ciphers) { + impl_->ciphers = ciphers; + impl_->configureSSLContext(); +} + +void WebSocketClientSSL::setSNIHostname(const std::string& sni_hostname) { + impl_->sni_hostname = sni_hostname; +} + +// 连接函数 +bool WebSocketClientSSL::connect(int timeout_ms) { + if (impl_->connecting || impl_->connected) { + return false; + } + + impl_->connecting = true; + impl_->stopping = false; + + // 启动 IO 线程 + if (!impl_->io_thread.joinable()) { + impl_->io_thread = std::thread([this]() { + try { + impl_->ioc.run(); + } catch (const std::exception& e) { + if (impl_->error_callback) { + impl_->error_callback(std::string("IO context error: ") + e.what()); + } + } + }); + } + + // 异步连接 + asio::post(impl_->ioc, [this]() { + try { + impl_->setSNI(); + doConnect(); + } catch (const std::exception& e) { + handleError("SSL setup failed", beast::error_code{}, e.what()); + } + }); + + // 等待连接完成 + auto start = std::chrono::steady_clock::now(); + while (impl_->connecting && !impl_->stopping) { + if (timeout_ms > 0) { + auto now = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(now - start).count(); + if (elapsed > timeout_ms) { + impl_->connecting = false; + if (impl_->error_callback) { + impl_->error_callback("Connection timeout"); + } + return false; + } + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + return impl_->connected; +} + +// 私有连接方法 +void WebSocketClientSSL::doConnect() { + impl_->resolver.async_resolve( + impl_->host, + impl_->port, + [this](beast::error_code ec, tcp::resolver::results_type results) { + onResolve(ec, std::move(results)); + }); +} + +void WebSocketClientSSL::onResolve(beast::error_code ec, tcp::resolver::results_type results) { + if (ec) { + handleError("Resolve failed", ec); + return; + } + + // 设置超时 + beast::get_lowest_layer(impl_->ws).expires_after(std::chrono::seconds(30)); + + // 异步连接 + beast::get_lowest_layer(impl_->ws).async_connect( + results, + [this](beast::error_code ec, tcp::resolver::results_type::endpoint_type endpoint) { + onConnect(ec, endpoint); + }); +} + +void WebSocketClientSSL::onConnect(beast::error_code ec, tcp::resolver::results_type::endpoint_type endpoint) { + if (ec) { + handleError("Connect failed", ec); + return; + } + + // SSL 握手 + impl_->ws.next_layer().async_handshake( + ssl::stream_base::client, + [this](beast::error_code ec) { + onSSLHandshake(ec); + }); +} + +void WebSocketClientSSL::onSSLHandshake(beast::error_code ec) { + if (ec) { + handleError("SSL handshake failed", ec); + return; + } + + // 关闭 TCP 超时设置 + beast::get_lowest_layer(impl_->ws).expires_never(); + + // 设置 WebSocket 选项 + impl_->ws.set_option(websocket::stream_base::timeout::suggested(beast::role_type::client)); + impl_->ws.read_message_max(10 * 1024 * 1024); // 10MB 限制 + + // WebSocket 握手 + impl_->ws.async_handshake( + impl_->host + ":" + impl_->port, + impl_->path, + [this](beast::error_code ec) { + onHandshake(ec); + }); +} + +void WebSocketClientSSL::onHandshake(beast::error_code ec) { + impl_->connecting = false; + + if (ec) { + handleError("WebSocket handshake failed", ec); + return; + } + + impl_->connected = true; + + // 开始读取消息 + doRead(); + + // 开始心跳 + if (impl_->heartbeat_interval > 0) { + startHeartbeat(); + } + + // 通知连接成功 + if (impl_->connect_callback) { + impl_->connect_callback(true); + } + + // 检查是否有待发送的消息 + if (hasMessages()) { + doWrite(); + } +} + +// 断开连接 +void WebSocketClientSSL::disconnect() { + impl_->stopping = true; + impl_->auto_reconnect = false; + + if (impl_->connected) { + asio::post(impl_->ioc, [this]() { + beast::error_code ec; + impl_->ws.close(websocket::close_code::normal, ec); + if (ec && impl_->error_callback) { + impl_->error_callback("Error closing WebSocket: " + ec.message()); + } + impl_->connected = false; + stopHeartbeat(); + + if (impl_->close_callback) { + impl_->close_callback(); + } + }); + } +} + +// 发送消息 +bool WebSocketClientSSL::send(const std::string& message) { + return pushMessage(message, false); +} + +bool WebSocketClientSSL::sendBinary(const void* data, size_t size) { + std::string message(static_cast(data), size); + return pushMessage(message, true); +} + +// 状态检查 +bool WebSocketClientSSL::isConnected() const { + return impl_->connected; +} + +std::string WebSocketClientSSL::getHost() const { + return impl_->host; +} + +std::string WebSocketClientSSL::getPort() const { + return impl_->port; +} + +std::string WebSocketClientSSL::getPath() const { + return impl_->path; +} + +// 自动重连和心跳设置 +void WebSocketClientSSL::setAutoReconnect(bool enable, int interval_ms) { + impl_->auto_reconnect = enable; + impl_->reconnect_interval = interval_ms; +} + +void WebSocketClientSSL::setHeartbeatInterval(int interval_ms) { + impl_->heartbeat_interval = interval_ms; + if (impl_->connected && interval_ms > 0) { + startHeartbeat(); + } +} + +// ============ 私有方法实现 ============ + +void WebSocketClientSSL::doRead() { + impl_->ws.async_read( + impl_->read_buffer, + [this](beast::error_code ec, std::size_t bytes_transferred) { + onRead(ec, bytes_transferred); + }); +} + +void WebSocketClientSSL::onRead(beast::error_code ec, std::size_t bytes_transferred) { + if (ec) { + if (ec == websocket::error::closed) { + // 正常关闭 + impl_->connected = false; + stopHeartbeat(); + + if (impl_->close_callback) { + impl_->close_callback(); + } + + // 自动重连 + if (impl_->auto_reconnect && !impl_->stopping) { + impl_->reconnect_timer.expires_after(std::chrono::milliseconds(impl_->reconnect_interval)); + impl_->reconnect_timer.async_wait( + [this](beast::error_code ec) { + if (!ec && !impl_->stopping) { + doConnect(); + } + }); + } + } else { + handleError("Read failed", ec); + } + return; + } + + // 处理接收到的消息 + if (impl_->message_callback) { + std::string message = beast::buffers_to_string(impl_->read_buffer.data()); + impl_->message_callback(message); + } + + // 清空缓冲区并继续读取 + impl_->read_buffer.consume(bytes_transferred); + doRead(); +} + +void WebSocketClientSSL::doWrite() { + if (impl_->writing || !hasMessages()) { + return; + } + + impl_->writing = true; + auto message = popMessage(); + + impl_->ws.async_write( + asio::buffer(message.first), + [this, is_binary = message.second](beast::error_code ec, std::size_t bytes_transferred) { + impl_->writing = false; + onWrite(ec, bytes_transferred); + + // 如果是二进制消息,设置二进制模式 + if (!ec && is_binary) { + impl_->ws.binary(true); + } else if (!ec) { + impl_->ws.text(true); + } + }); +} + +void WebSocketClientSSL::onWrite(beast::error_code ec, std::size_t bytes_transferred) { + (void)bytes_transferred; // 消除未使用参数警告 + + if (ec) { + handleError("Write failed", ec); + return; + } + + // 继续发送队列中的下一条消息 + if (hasMessages()) { + doWrite(); + } +} + +void WebSocketClientSSL::handleError(const std::string& message, beast::error_code ec, const std::string& extra) { + std::string error_msg = message; + if (ec) { + error_msg += ": " + ec.message(); + } + if (!extra.empty()) { + error_msg += " (" + extra + ")"; + } + + impl_->connecting = false; + impl_->connected = false; + stopHeartbeat(); + + if (impl_->error_callback) { + impl_->error_callback(error_msg); + } + + if (impl_->connect_callback) { + impl_->connect_callback(false); + } + + // 自动重连 + if (impl_->auto_reconnect && !impl_->stopping) { + impl_->reconnect_timer.expires_after(std::chrono::milliseconds(impl_->reconnect_interval)); + impl_->reconnect_timer.async_wait( + [this](beast::error_code ec) { + if (!ec && !impl_->stopping) { + doConnect(); + } + }); + } +} + +void WebSocketClientSSL::startHeartbeat() { + if (impl_->heartbeat_interval <= 0) { + return; + } + + impl_->heartbeat_timer.expires_after(std::chrono::milliseconds(impl_->heartbeat_interval)); + impl_->heartbeat_timer.async_wait( + [this](beast::error_code ec) { + heartbeatTimerCallback(ec); + }); +} + +void WebSocketClientSSL::stopHeartbeat() { + beast::error_code ec; + impl_->heartbeat_timer.cancel(ec); +} + +void WebSocketClientSSL::heartbeatTimerCallback(beast::error_code ec) { + if (ec || impl_->stopping || !impl_->connected) { + return; + } + + // 发送 ping 消息 + beast::error_code ping_ec; + impl_->ws.ping(beast::websocket::ping_data{}, ping_ec); + + if (ping_ec) { + handleError("Heartbeat ping failed", ping_ec); + return; + } + + // 重新设置定时器 + startHeartbeat(); +} + +// 线程安全队列操作 +bool WebSocketClientSSL::pushMessage(const std::string& message, bool is_binary) { + if (!impl_->connected || impl_->stopping) { + return false; + } + + { + std::lock_guard lock(impl_->queue_mutex); + impl_->send_queue.push({message, is_binary}); + } + + impl_->queue_cv.notify_one(); + + // 触发写入 + asio::post(impl_->ioc, [this]() { + if (!impl_->writing && hasMessages()) { + doWrite(); + } + }); + + return true; +} + +std::pair WebSocketClientSSL::popMessage() { + std::lock_guard lock(impl_->queue_mutex); + if (impl_->send_queue.empty()) { + return {"", false}; + } + + auto msg = std::move(impl_->send_queue.front()); + impl_->send_queue.pop(); + return {std::move(msg.data), msg.is_binary}; +} + +bool WebSocketClientSSL::hasMessages() const { + std::lock_guard lock(impl_->queue_mutex); + return !impl_->send_queue.empty(); +} + +} // namespace net +} // namespace pmc \ No newline at end of file diff --git a/lci/src/net/WebSocketServer.cpp b/lci/src/net/WebSocketServer.cpp new file mode 100644 index 0000000..78c4582 --- /dev/null +++ b/lci/src/net/WebSocketServer.cpp @@ -0,0 +1,382 @@ +// WebSocketServer.cpp - WebSocket服务器实现 +// 基于Boost.Beast和Boost.Asio + +#include "net/WebSocketServer.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast = boost::beast; +namespace websocket = beast::websocket; +namespace asio = boost::asio; +using tcp = asio::ip::tcp; + +namespace pmc::net { + +// 内部Session类实现 +class WebSocketServer::Session : public std::enable_shared_from_this { +public: + Session(tcp::socket socket, WebSocketServer* server) + : ws_(std::move(socket)) + , server_(server) { + + // 获取远程地址 + auto endpoint = ws_.next_layer().socket().remote_endpoint(); + remoteAddress_ = endpoint.address().to_string() + ":" + std::to_string(endpoint.port()); + } + + void start() { + // 生成客户端ID + if (server_) { + clientId_ = server_->generateClientId(); + } else { + // 如果server为空,使用默认ID + static std::atomic counter{0}; + clientId_ = "client_" + std::to_string(++counter); + } + + // 异步接受WebSocket握手 + ws_.async_accept( + beast::bind_front_handler( + &Session::onAccept, + shared_from_this())); + } + + void send(const std::string& message) { + // 将消息添加到发送队列 + bool write_in_progress = !sendQueue_.empty(); + sendQueue_.push_back(message); + + if (!write_in_progress) { + // 开始异步写入 + doWrite(); + } + } + + const std::string& getClientId() const { return clientId_; } + const std::string& getRemoteAddress() const { return remoteAddress_; } + +private: + websocket::stream ws_; + beast::flat_buffer buffer_; + std::deque sendQueue_; + WebSocketServer* server_; + std::string clientId_; + std::string remoteAddress_; + + void onAccept(beast::error_code ec) { + if (ec) { + std::cerr << "WebSocket accept error: " << ec.message() << std::endl; + return; + } + + // 添加到服务器客户端列表 + if (server_) { + server_->addClient(clientId_, shared_from_this()); + + // 调用连接处理器 + if (server_->connectHandler_) { + server_->connectHandler_(clientId_, remoteAddress_); + } + } + + // 开始读取消息 + doRead(); + } + + void doRead() { + // 异步读取消息 + ws_.async_read( + buffer_, + beast::bind_front_handler( + &Session::onRead, + shared_from_this())); + } + + void onRead(beast::error_code ec, std::size_t bytes_transferred) { + if (ec == websocket::error::closed) { + // 正常关闭 + if (server_) { + server_->removeClient(clientId_); + if (server_->disconnectHandler_) { + server_->disconnectHandler_(clientId_); + } + } + return; + } + + if (ec) { + std::cerr << "WebSocket read error: " << ec.message() << std::endl; + if (server_) { + server_->removeClient(clientId_); + if (server_->disconnectHandler_) { + server_->disconnectHandler_(clientId_); + } + } + return; + } + + // 处理接收到的消息 + std::string message = beast::buffers_to_string(buffer_.data()); + buffer_.consume(bytes_transferred); + + if (server_) { + // 查找消息处理器 + for (const auto& handler : server_->messageHandlers_) { + // 这里可以添加路径匹配逻辑 + handler.second(clientId_, message, [this](const std::string& response) { + send(response); + }); + } + } + + // 继续读取 + doRead(); + } + + void doWrite() { + if (sendQueue_.empty()) { + return; + } + + // 获取队列中的第一条消息 + auto message = sendQueue_.front(); + + // 异步写入消息 + ws_.async_write( + asio::buffer(message), + beast::bind_front_handler( + &Session::onWrite, + shared_from_this())); + } + + void onWrite(beast::error_code ec, std::size_t bytes_transferred) { + if (ec) { + std::cerr << "WebSocket write error: " << ec.message() << std::endl; + if (server_) { + server_->removeClient(clientId_); + if (server_->disconnectHandler_) { + server_->disconnectHandler_(clientId_); + } + } + return; + } + + // 移除已发送的消息 + sendQueue_.pop_front(); + + // 继续发送队列中的下一条消息 + if (!sendQueue_.empty()) { + doWrite(); + } + } +}; + +// 内部Listener类实现 +class WebSocketServer::Listener : public std::enable_shared_from_this { +public: + static std::shared_ptr create(asio::io_context& ioc, tcp::endpoint endpoint, WebSocketServer* server) { + return std::shared_ptr(new Listener(ioc, endpoint, server)); + } + + void run() { + if (!acceptor_.is_open()) { + throw std::runtime_error("Acceptor is not open"); + } + + doAccept(); + } + +private: + Listener(asio::io_context& ioc, tcp::endpoint endpoint, WebSocketServer* server) + : ioc_(ioc) + , acceptor_(asio::make_strand(ioc)) + , server_(server) { + + beast::error_code ec; + + // 打开acceptor + acceptor_.open(endpoint.protocol(), ec); + if (ec) { + std::cerr << "Failed to open acceptor: " << ec.message() << std::endl; + throw std::runtime_error("Failed to open acceptor: " + ec.message()); + } + + // 设置地址重用 + acceptor_.set_option(asio::socket_base::reuse_address(true), ec); + if (ec) { + std::cerr << "Failed to set reuse address: " << ec.message() << std::endl; + throw std::runtime_error("Failed to set reuse address: " + ec.message()); + } + + // 绑定到端点 + acceptor_.bind(endpoint, ec); + if (ec) { + std::cerr << "Failed to bind to endpoint: " << ec.message() << std::endl; + throw std::runtime_error("Failed to bind to endpoint: " + ec.message()); + } + + // 开始监听 + acceptor_.listen(asio::socket_base::max_listen_connections, ec); + if (ec) { + std::cerr << "Failed to listen: " << ec.message() << std::endl; + throw std::runtime_error("Failed to listen: " + ec.message()); + } + } + + void doAccept() { + acceptor_.async_accept( + asio::make_strand(ioc_), + beast::bind_front_handler( + &Listener::onAccept, + shared_from_this())); + } + + void onAccept(beast::error_code ec, tcp::socket socket) { + if (ec) { + std::cerr << "Accept error: " << ec.message() << std::endl; + } else { + // 创建新的Session处理连接 + std::make_shared(std::move(socket), server_)->start(); + } + + // 继续接受新的连接 + doAccept(); + } + + asio::io_context& ioc_; + tcp::acceptor acceptor_; + WebSocketServer* server_; +}; + +WebSocketServer::WebSocketServer(unsigned short port, unsigned int threads) + : port_(port) + , threads_(threads) + , impl_(std::make_unique()) {} + +WebSocketServer::~WebSocketServer() { + stop(); +} + +void WebSocketServer::start() { + if (running_) { + return; + } + + // 创建监听器 + tcp::endpoint endpoint(tcp::v4(), port_); + impl_->listener_ = Listener::create(impl_->ioc_, endpoint, this); + + // 启动监听器 + impl_->listener_->run(); + + // 启动工作线程 + for (unsigned int i = 0; i < threads_; ++i) { + impl_->threads_.emplace_back([this]() { + impl_->ioc_.run(); + }); + } + + running_ = true; + std::cout << "WebSocketServer started on port " << port_ << " with " << threads_ << " threads" << std::endl; +} + +void WebSocketServer::stop() { + if (!running_) { + return; + } + + // 停止io_context + impl_->ioc_.stop(); + + // 等待所有线程结束 + for (auto& thread : impl_->threads_) { + if (thread.joinable()) { + thread.join(); + } + } + + impl_->threads_.clear(); + running_ = false; + std::cout << "WebSocketServer stopped" << std::endl; +} + +void WebSocketServer::onMessage(const std::string& path, WebSocketMessageHandler handler) { + messageHandlers_[path] = std::move(handler); +} + +void WebSocketServer::onConnect(WebSocketConnectHandler handler) { + connectHandler_ = std::move(handler); +} + +void WebSocketServer::onDisconnect(WebSocketDisconnectHandler handler) { + disconnectHandler_ = std::move(handler); +} + +bool WebSocketServer::sendToClient(const std::string& clientId, const std::string& message) { + std::lock_guard lock(clientsMutex_); + auto it = clients_.find(clientId); + if (it != clients_.end()) { + it->second->send(message); + return true; + } + return false; +} + +size_t WebSocketServer::broadcast(const std::string& message) { + std::lock_guard lock(clientsMutex_); + size_t count = 0; + for (auto& pair : clients_) { + pair.second->send(message); + count++; + } + return count; +} + +void WebSocketServer::disconnectClient(const std::string& clientId) { + std::lock_guard lock(clientsMutex_); + auto it = clients_.find(clientId); + if (it != clients_.end()) { + // 这里应该关闭WebSocket连接 + // 目前只是从列表中移除 + clients_.erase(it); + } +} + +size_t WebSocketServer::getClientCount() const { + std::lock_guard lock(clientsMutex_); + return clients_.size(); +} + +std::string WebSocketServer::generateClientId() const { + static std::atomic counter{0}; + return "client_" + std::to_string(++counter); +} + +void WebSocketServer::addClient(const std::string& clientId, std::shared_ptr session) { + std::lock_guard lock(clientsMutex_); + clients_[clientId] = session; +} + +void WebSocketServer::removeClient(const std::string& clientId) { + std::lock_guard lock(clientsMutex_); + clients_.erase(clientId); +} + +std::shared_ptr WebSocketServer::getClient(const std::string& clientId) { + std::lock_guard lock(clientsMutex_); + auto it = clients_.find(clientId); + if (it != clients_.end()) { + return it->second; + } + return nullptr; +} + +} // namespace pmc::net \ No newline at end of file diff --git a/lci/src/nn/ILayer.cpp b/lci/src/nn/ILayer.cpp new file mode 100644 index 0000000..72c0e76 --- /dev/null +++ b/lci/src/nn/ILayer.cpp @@ -0,0 +1,85 @@ +#include "nn/ILayer.hpp" +#include + +/* 获取函数对象 - 获取激活函数 */ +f_t ILayer::getf(ActivationFunc type) { + switch (type) { + case ActivationFunc::ReLU: + return relu; + case ActivationFunc::Leaky_ReLU: + return leaky_relu; + case ActivationFunc::Sigmoid: + return sigmoid; + case ActivationFunc::Tanh: + return tanh; + default: + throw std::invalid_argument("ActivationFunc function does not support."); + } +} + +/* 获取函数对象 - 求激活函数导数 */ +f_t ILayer::getfdot(ActivationFunc type) { + switch (type) { + case ActivationFunc::ReLU: + return relu_derivative; + case ActivationFunc::Leaky_ReLU: + return leaky_relu_derivative; + case ActivationFunc::Sigmoid: + return sigmoid_derivative; + case ActivationFunc::Tanh: + return tanh_derivative; + default: + throw std::invalid_argument("ActivationFunc Derivative does not support."); + } +} + const char* ILayer::get_f_type(ActivationFunc& af) { + switch (af) { + case ActivationFunc::Sigmoid: + return "Sigmoid"; + case ActivationFunc::ReLU: + return "ReLU"; + case ActivationFunc::Leaky_ReLU: + return "Leaky_ReLU"; + } + throw std::runtime_error("What activation function"); + } + + ILayer::ActivationFunc ILayer::parse_ff_type(const std::string& name) { + if(name == "Sigmoid") { + return ActivationFunc::Sigmoid; + } else if (name == "ReLU") { + return ActivationFunc::ReLU; + } else if (name == "Leaky_ReLU") { + return ActivationFunc::Leaky_ReLU; + } else { + throw std::runtime_error("What activation function"); + } + } + +/* ReLU 激活函数 */ +float ILayer::relu(float x) { return (x > 0.0) ? x : 0.0; } + +/* ReLU 导数 */ +float ILayer::relu_derivative(float x) { return (x > 0) ? 1: 0; } + +/* + * leaky ReLU 激活函数 + * + * NOTE: alpha太小或者选择使用ReLU函数的情况下,会导致梯度消失 + * NOTE: Leaky ReLU 不会使梯度完全消失,但也会使它变得很小 + */ +float ILayer::leaky_relu(float x) { return (x > 0) ? x : LEAKY_RELU_ALPHA * x; } +/* leaky ReLU 导数 */ +float ILayer::leaky_relu_derivative(float x) { return (x > 0) ? 1.0f : LEAKY_RELU_ALPHA; } +/* Sigmoid 激活函数 */ +float ILayer::sigmoid(float x) { return 1.0 / (1.0 + std::exp(-x)); } +/* Sigmoid 导数 */ +float ILayer::sigmoid_derivative(float x) +{ + double s = sigmoid(x); + return s * (1.0 - s); +} +/* Tanh 激活函数 */ +float ILayer::tanh(float x) { return std::tanh(x); } +/* Tanh 导数 */ +float ILayer::tanh_derivative(float x) { return 1.0f - x * x; } diff --git a/lci/src/nn/Matrix.cpp b/lci/src/nn/Matrix.cpp new file mode 100644 index 0000000..8f03563 --- /dev/null +++ b/lci/src/nn/Matrix.cpp @@ -0,0 +1,144 @@ +#include "nn/Matrix.hh" +namespace qing { + + template + Matrx::Matrx(): row(0), col(0) {} + + template + Matrx::Matrx(const long row, const long col) + : row(row), col(col) { /* 该构造函数用于从头开始构造 */ + arr = std::vector(col * row); + } + + template + Matrx::Matrx(const long row, const long col, const std::vector& src) + : row(row), col(col) { /* 该构造函数用于通过已有的vector进行构造 */ + arr = src; + } + + template + const T& Matrx::get(long row, long col) const { /* 访问器 - 访问矩阵元素 */ + return arr[col * this->row + row]; + } + + template + T& Matrx::witch(long row, long col) { /* 访问器 - 访问矩阵元素 */ + return arr[col * this->row + row]; + } + + template + const std::vector& Matrx::get_data() const{ /* 访问器 - 用于获取原始数据 */ + return arr; + } + + template + const long Matrx::get_col() const { /* 获取列数 */ + return col; + } + + template + const long Matrx::get_row() const { /* 获取行数 */ + return row; + } + + template + bool Matrx::has_same_shape(const Matrx& other) { /* 两个矩阵是否具有相同形状 */ + return other.get_col() == this->get_col() || other.get_row() == this->get_row(); + } + + template + bool Matrx::has_dot_shape(const Matrx& other) { /* 具有矩阵乘法的形状 */ + return this->get_col() == other.get_row(); + } + + template + void Matrx::assert_same_shape(const Matrx& other) { /* 断言两个矩阵具有相同形状 */ + if (!has_same_shape(other)) + throw std::invalid_argument("The shapes of matrix are not same."); + } + + template + void Matrx::assert_dot_shape(const Matrx& other) { /* 断言两个矩阵具有点积前置形状 */ + if (!has_dot_shape(other)) { + throw std::invalid_argument("The shapes of matrix can not be dot."); + } + } + + template + Matrx Matrx::operator+(const Matrx& other) { /* 加法操作符重定义 - 矩阵加法 */ + assert_same_shape(other); /* 检查两个矩阵形状是否一致 */ + std::vector v0 = this->get_data(); + std::vector vec = other.get_data(); + for (auto it = v0.begin(), it_or = vec.begin(); it != v0.end(); ++it, ++it_or ) { + *it += *it_or; + } + return Matrx{this->get_row(), this->get_col(), v0}; + } + + template + Matrx Matrx::operator+(T& item) { /* 矩阵加法广播 */ + auto matrix = *this; + for (auto it = arr.begin(); it != arr.end(); ++it) { + *it += item; + } + return matrix; + } + + template + Matrx Matrx::operator-(const Matrx& other) { /* 操作符重载 - 矩阵减法 */ + assert_same_shape(other); /* 检查两个矩阵形状是否一致 */ + std::vector v0 = this->get_data(); + std::vector vec = other.get_data(); + for (auto it = v0.begin(), it_or = vec.begin(); it != v0.end(); ++it, ++it_or ) { + *it -= *it_or; + } + return Matrx{this->get_row(), this->get_col(), v0}; + } + + template + Matrx Matrx::operator-(T& item) { /* 操作符重载 - 矩阵减法广播 */ + auto matrix = *this; + for (auto it = arr.begin(); it != arr.end(); ++it) { + *it -= item; + } + return matrix; + } + + template + const Matrx Matrx::operator*(const Matrx& other) { /* 操作符重载 - 矩阵乘法 */ + assert_dot_shape(other); /* 它们的形状是否能够点积 */ + auto matrix = Matrx(this->get_row(), other.get_col()); + for (long i=0; iget_row(); ++i) {/* 点积运算 */ + for (long j=0; jget_col(); ++k) { + sum += this->get(i, k) * other.get(k, j); + } + matrix.witch(i, j) = sum; + } + } + return matrix; + } + + template + Matrx Matrx::operator*(T& item) { /* 操作符重载 - 矩阵乘法广播 */ + std::vector vec = this->get_data(); + for (auto it = vec.begin(); it != vec.end(); ++it) { + *it *= item; + } + return Matrx{this->get_row(), this->get_col(), vec}; + } + + template + Matrx Matrx::operator/(T& item) { /* 操作符重载 - 矩阵除法广播 */ + std::vector vec = this->get_data(); + for (auto it = vec.begin(); it != vec.end(); ++it) { + *it /= item; + } + return Matrx(this->get_row(), this->get_col(), vec); + } + + template class Matrx; /* 显式实例化 */ + template class Matrx; + +} diff --git a/lci/src/nn/MatrixCuda.cu b/lci/src/nn/MatrixCuda.cu new file mode 100644 index 0000000..30f1b4b --- /dev/null +++ b/lci/src/nn/MatrixCuda.cu @@ -0,0 +1,396 @@ +/* + * MatrixCuda.cu - MatrixCuda类的CUDA实现文件 + * + * 这个文件包含MatrixCuda类的具体实现和CUDA内核的显式实例化 + * 注意:这个文件需要使用nvcc编译器编译 + */ + +#include "nn/MatrixCuda.cuh" +#include "nn/Matrix.hh" // 用于与现有Matrx类交互 + +namespace qing { + +// ============================================================================ +// 显式实例化CUDA内核函数 +// ============================================================================ + +namespace cuda_kernels { + +// float类型内核显式实例化 +template __global__ void matrix_add_kernel( + const float* A, const float* B, float* C, + long rows, long cols, long total_elements); + +template __global__ void matrix_sub_kernel( + const float* A, const float* B, float* C, + long rows, long cols, long total_elements); + +template __global__ void matrix_scalar_mul_kernel( + const float* A, float scalar, float* C, long total_elements); + +template __global__ void matrix_scalar_add_kernel( + const float* A, float scalar, float* C, long total_elements); + +template __global__ void matrix_transpose_kernel( + const float* A, float* C, long rows, long cols); + +template __global__ void matrix_hadamard_kernel( + const float* A, const float* B, float* C, long total_elements); + +template __global__ void matrix_copy_kernel( + const float* src, float* dst, long total_elements); + +// double类型内核显式实例化 +template __global__ void matrix_add_kernel( + const double* A, const double* B, double* C, + long rows, long cols, long total_elements); + +template __global__ void matrix_sub_kernel( + const double* A, const double* B, double* C, + long rows, long cols, long total_elements); + +template __global__ void matrix_scalar_mul_kernel( + const double* A, double scalar, double* C, long total_elements); + +template __global__ void matrix_scalar_add_kernel( + const double* A, double scalar, double* C, long total_elements); + +template __global__ void matrix_transpose_kernel( + const double* A, double* C, long rows, long cols); + +template __global__ void matrix_hadamard_kernel( + const double* A, const double* B, double* C, long total_elements); + +template __global__ void matrix_copy_kernel( + const double* src, double* dst, long total_elements); + +} // namespace cuda_kernels + +// ============================================================================ +// MatrixCuda类与现有Matrx类的交互实现 +// ============================================================================ + +// 从Matrx转换到MatrixCuda +template <> +CUDA_HOST MatrixCuda MatrixCuda::from_matrx(const Matrx& mat) { + long rows = mat.get_row(); + long cols = mat.get_col(); + const std::vector& data = mat.get_data(); + + return MatrixCuda(rows, cols, data); +} + +// 从MatrixCuda转换到Matrx +template <> +CUDA_HOST Matrx MatrixCuda::to_matrx() const { + sync_device_to_host(); + return Matrx(rows_, cols_, host_data_); +} + +// 从Matrx转换到MatrixCuda +template <> +CUDA_HOST MatrixCuda MatrixCuda::from_matrx(const Matrx& mat) { + long rows = mat.get_row(); + long cols = mat.get_col(); + const std::vector& data = mat.get_data(); + + return MatrixCuda(rows, cols, data); +} + +// 从MatrixCuda转换到Matrx +template <> +CUDA_HOST Matrx MatrixCuda::to_matrx() const { + sync_device_to_host(); + return Matrx(rows_, cols_, host_data_); +} + +// ============================================================================ +// 优化的矩阵乘法实现(使用共享内存) +// ============================================================================ + +/** + * @brief 使用共享内存优化的矩阵乘法内核 + * + * 这个内核使用平铺(tiling)技术来提高矩阵乘法的性能 + * 每个线程块计算输出矩阵的一个子块 + */ +template +__global__ void matrix_mul_optimized_kernel( + const T* A, const T* B, T* C, + long A_rows, long A_cols, long B_cols, + long tile_size) { + + // 共享内存声明 + extern __shared__ T shared_mem[]; + T* tile_A = shared_mem; + T* tile_B = &shared_mem[tile_size * tile_size]; + + // 线程块索引 + long block_row = blockIdx.y; + long block_col = blockIdx.x; + + // 线程索引 + long thread_row = threadIdx.y; + long thread_col = threadIdx.x; + + // 输出矩阵中的位置 + long row = block_row * tile_size + thread_row; + long col = block_col * tile_size + thread_col; + + T sum = T(0); + + // 遍历所有平铺 + for (long tile_idx = 0; tile_idx < (A_cols + tile_size - 1) / tile_size; ++tile_idx) { + // 从全局内存加载到共享内存 + long A_col = tile_idx * tile_size + thread_col; + long B_row = tile_idx * tile_size + thread_row; + + if (row < A_rows && A_col < A_cols) { + tile_A[thread_row * tile_size + thread_col] = A[row * A_cols + A_col]; + } else { + tile_A[thread_row * tile_size + thread_col] = T(0); + } + + if (B_row < A_cols && col < B_cols) { + tile_B[thread_row * tile_size + thread_col] = B[B_row * B_cols + col]; + } else { + tile_B[thread_row * tile_size + thread_col] = T(0); + } + + __syncthreads(); + + // 计算平铺内的点积 + for (long k = 0; k < tile_size; ++k) { + sum += tile_A[thread_row * tile_size + k] * tile_B[k * tile_size + thread_col]; + } + + __syncthreads(); + } + + // 将结果写回全局内存 + if (row < A_rows && col < B_cols) { + C[row * B_cols + col] = sum; + } +} + +// ============================================================================ +// 优化的矩阵乘法方法 +// ============================================================================ + +/** + * @brief 使用优化CUDA内核的矩阵乘法 + * + * 这个方法使用共享内存和平铺技术来加速矩阵乘法 + * 对于大矩阵,性能比朴素算法有显著提升 + */ +template +CUDA_HOST MatrixCuda MatrixCuda::matmul_optimized(const MatrixCuda& other) const { + assert_dot_shape(other); + + MatrixCuda result(rows_, other.cols_); + + // 确保数据在设备上 + sync_host_to_device(); + other.sync_host_to_device(); + result.allocate_device_memory(); + + // 设置平铺大小(典型值为16或32) + const long tile_size = 16; + + // 计算线程块和网格大小 + dim3 block_size(tile_size, tile_size); + dim3 grid_size((other.cols_ + tile_size - 1) / tile_size, + (rows_ + tile_size - 1) / tile_size); + + // 计算共享内存大小 + size_t shared_mem_size = 2 * tile_size * tile_size * sizeof(T); + + // 启动优化内核 + matrix_mul_optimized_kernel<<>>( + device_data_, other.device_data_, result.device_data_, + rows_, cols_, other.cols_, tile_size + ); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +// 显式实例化优化矩阵乘法 +template MatrixCuda MatrixCuda::matmul_optimized(const MatrixCuda& other) const; +template MatrixCuda MatrixCuda::matmul_optimized(const MatrixCuda& other) const; + +// ============================================================================ +// 使用cuBLAS的矩阵乘法(如果可用) +// ============================================================================ + +#ifdef HAVE_CUBLAS +#include + +template +CUDA_HOST MatrixCuda MatrixCuda::matmul_cublas(const MatrixCuda& other) const { + assert_dot_shape(other); + + MatrixCuda result(rows_, other.cols_); + + // 确保数据在设备上 + sync_host_to_device(); + other.sync_host_to_device(); + result.allocate_device_memory(); + + // 创建cuBLAS句柄 + cublasHandle_t handle; + cublasCreate(&handle); + + // 设置cuBLAS参数 + T alpha = T(1); + T beta = T(0); + + if constexpr (std::is_same_v) { + cublasSgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, + other.cols_, rows_, cols_, + &alpha, + other.device_data_, other.cols_, + device_data_, cols_, + &beta, + result.device_data_, other.cols_); + } else if constexpr (std::is_same_v) { + cublasDgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, + other.cols_, rows_, cols_, + &alpha, + other.device_data_, other.cols_, + device_data_, cols_, + &beta, + result.device_data_, other.cols_); + } + + // 销毁cuBLAS句柄 + cublasDestroy(handle); + + CHECK_CUDA_ERROR(cudaGetLastError()); + CHECK_CUDA_ERROR(cudaDeviceSynchronize()); + + result.device_modified_ = true; + result.sync_device_to_host(); + + return result; +} + +// 显式实例化cuBLAS矩阵乘法 +template MatrixCuda MatrixCuda::matmul_cublas(const MatrixCuda& other) const; +template MatrixCuda MatrixCuda::matmul_cublas(const MatrixCuda& other) const; + +#endif // HAVE_CUBLAS + +// ============================================================================ +// 测试函数 +// ============================================================================ + +/** + * @brief 测试MatrixCuda类的功能 + * + * 这个函数用于验证MatrixCuda类的正确性 + * 可以单独编译和运行进行测试 + */ +template +CUDA_HOST void test_matrix_cuda() { + std::cout << "Testing MatrixCuda<" << typeid(T).name() << ">..." << std::endl; + + try { + // 测试1:创建矩阵 + std::cout << "Test 1: Creating matrices..." << std::endl; + MatrixCuda A = MatrixCuda::zeros(3, 3); + MatrixCuda B = MatrixCuda::ones(3, 3); + MatrixCuda C = MatrixCuda::identity(3); + + A.print("A (zeros)"); + B.print("B (ones)"); + C.print("C (identity)"); + + // 测试2:矩阵加法 + std::cout << "\nTest 2: Matrix addition..." << std::endl; + MatrixCuda D = A + B; + D.print("D = A + B"); + + // 测试3:标量运算 + std::cout << "\nTest 3: Scalar operations..." << std::endl; + MatrixCuda E = B * T(2.5); + E.print("E = B * 2.5"); + + // 测试4:矩阵转置 + std::cout << "\nTest 4: Matrix transpose..." << std::endl; + MatrixCuda F(2, 3); + F.fill(T(1)); + F.print("F (2x3)"); + MatrixCuda FT = F.transpose(); + FT.print("F^T (3x2)"); + + // 测试5:元素对应乘积 + std::cout << "\nTest 5: Hadamard product..." << std::endl; + MatrixCuda G = MatrixCuda::random(2, 2, T(0), T(1)); + MatrixCuda H = MatrixCuda::random(2, 2, T(0), T(1)); + G.print("G"); + H.print("H"); + MatrixCuda I = G.hadamard_product(H); + I.print("G ⊙ H"); + + // 测试6:矩阵乘法 + std::cout << "\nTest 6: Matrix multiplication..." << std::endl; + MatrixCuda J(2, 3); + MatrixCuda K(3, 2); + J.fill(T(1)); + K.fill(T(2)); + J.print("J (2x3)"); + K.print("K (3x2)"); + MatrixCuda L = J * K; + L.print("J * K (2x2)"); + + std::cout << "All tests passed!" << std::endl; + + } catch (const std::exception& e) { + std::cerr << "Test failed: " << e.what() << std::endl; + } +} + +// 显式实例化测试函数 +template void test_matrix_cuda(); +template void test_matrix_cuda(); + +} // namespace qing + +// ============================================================================ +// 主测试程序(可选) +// ============================================================================ + +#ifdef TEST_MATRIX_CUDA + +int main() { + std::cout << "=== MatrixCuda Test Program ===" << std::endl; + + // 初始化CUDA + cudaError_t err = cudaSetDevice(0); + if (err != cudaSuccess) { + std::cerr << "Failed to set CUDA device: " << cudaGetErrorString(err) << std::endl; + return 1; + } + + // 测试float版本 + qing::test_matrix_cuda(); + + std::cout << "\n"; + + // 测试double版本 + qing::test_matrix_cuda(); + + // 重置CUDA设备 + cudaDeviceReset(); + + std::cout << "\n=== Test Program Finished ===" << std::endl; + return 0; +} + +#endif // TEST_MATRIX_CUDA \ No newline at end of file diff --git a/lci/src/nn/NNBuilder.cpp b/lci/src/nn/NNBuilder.cpp new file mode 100644 index 0000000..eb02849 --- /dev/null +++ b/lci/src/nn/NNBuilder.cpp @@ -0,0 +1,48 @@ +#include "nn/NNBuilder.hpp" +namespace qing { + + void NNBuilder::add(NeuralNetwork &layer) { nn.push_back(layer); } + + std::vector> NNBuilder::get_shape() const { + std::vector> shape; + for (long j = 0; j < nn.size(); ++j) { + shape.emplace_back(nn[j].get_inputno(), nn[j].get_outputno()); + } + return shape; + } + + void NNBuilder::print_shape() const { + auto shape = get_shape(); + for (const auto& p : shape) { + std::cout << p.first << " -> " << p.second << std::endl; + } + } + + /* 前向反馈 */ + std::vector NNBuilder::forward(std::vector& r) { + auto x = r; + for (long j=0; j< nn.size(); ++j) { + x = nn[j].forward(x); + } + return x; + } + + /* 反向传播 */ + std::vector NNBuilder::backward(std::vector& errs, float discount) { + auto e = errs; + for (long j=nn.size()-1; j>=0;--j) { + e = nn[j].backward(e); + nn[j].update(discount); + } + return e; + } + + /* 计算误差 */ + std::vector NNBuilder::cal_err(std::vector& r, std::vector& t) { + auto res = r; + for (long j=0; j &weights, + const std::vector &bias, + const float learning_rate, + const ActivationFunc func_type +): inputno(inputno), outputno(outputno), + weights(inputno, outputno, weights), bias( 1, outputno, bias), + learning_rate(learning_rate), + f_type(func_type) { + ;/* 进行形状检查 */ +} + +/* 获取输入层大小 */ +long NeuralNetwork::get_inputno() const { + return this->inputno; +} + +/* 获取输出层大小 */ +long NeuralNetwork::get_outputno() const { + return this->outputno; +} + +/* 获取权重 */ +Matrx& NeuralNetwork::get_weights() { + return this->weights; +} + +/* 获取偏置 */ +Matrx& NeuralNetwork::get_bias() { + return this->bias; +} + +/* 正态分布Xavier初始化 */ +void NeuralNetwork::xavierNormalInit(std::vector &weights, long fan_in, long fan_out) +{ + + /* 高质量的随机数生成器 */ + static std::mt19937 generator(std::random_device{}()); + + /* 计算标准差 */ + float sigma = std::sqrt(2.0f / (fan_in + fan_out)); + + /* 创建正态分布对象,均值为0,标准差为sigma */ + std::normal_distribution distribution(0.0f, sigma); + + /* 遍历权重矩阵,进行赋值 */ + long k=0; + for (long i=0; i &weights, int fan_in, int fan_out) +{ + /* 使用高质量的随机数生成器 */ + static std::mt19937 generator(std::random_device{}()); + + /* 计算区间范围:sqrt(2 / (fan_in + fan_out)) */ + float scale = std::sqrt(2.0f / (fan_in + fan_out)); + + /* 创建均匀分布对象,范围为[-scale, scale] */ + std::uniform_real_distribution distribution(-scale, scale); + + /* 遍历权重矩阵,进行赋值 */ + long k=0; + for (long i=0; i weights(inputno * outputno); + xavierUniformInit(weights, inputno, outputno); + std::vector bias(outputno); + NeuralNetwork layer(inputno, outputno, weights, bias, learning_rate, func_type); + return layer; /* FIXME: 使用移动语义 */ +} + + +/* 前向反馈 */ +std::vector NeuralNetwork::forward(const std::vector& x) + +{ + + + /* + * 矩阵乘法(点积) + * wi => weights inputs(column) + * wo => weights outputs(row) + * + * NOTE: 通常矩阵乘法是三层循环,这里我们用两层 + */ + //std::vector res(this->outputno); /* (1, outputs) */ + //for (long i=0; ioutputno; ++i) { + // long wo = i; + // float sum=0.0; + // for (long j=0, wi=wo; jinputno; ++j, wi+=this->outputno) { + // sum += x[j] * this->weights[wi]; + // } + // res[i]= sum; + //} + Matrxmx{1, this->inputno, x}; + + + /* + * 为输入进行备份 + * + * FIXME: 使用移动语义传入参数,并且储存 + */ + this->prev_inputs = mx; /* (1, inputs) */ + + + Matrxr = mx * this->weights; /* (1, outputs) */ + + /* 偏置操作 */ + //for (long i=0; ioutputno; ++i) { + // res[i]+=this->bias[i]; + //} + r = r + this->bias; + + /* + * 为原始计算结果进行备份 + */ + this->prev_raw_inputs = r; + + /* + * 使用ReLU激活函数 + * + * FIXME: 建立一个算法类 + */ + f_t f = getf(f_type); + + std::vector vec =r.get_data(); + for (long i=0; ioutputno; ++i) { + float& v = vec[i]; + v = f(v); + } + + r = Matrx(1, outputno, vec); + + /* + * 为输出进行备份 + */ + this->prev_outputs = r; + + + /* 返回前向反馈的结果。 (1, outputs) */ + return r.get_data(); +} + + +/* 反向传播 */ +std::vector NeuralNetwork::backward(const std::vector& errors) /* errors => (outputs, 1) */ + +{ + + /* 匹配激活导数 */ + f_t fdot = getfdot(f_type); + + std::vector vec = this->prev_raw_inputs.get_data(); + /* 将原始输出转化为导数 */ + for (long i=0; ioutputno; ++i) { + float& v = vec[i]; + v = errors[i] * fdot(v); + } + + /* 误差乘以导数 */ + //std::vector first(this->outputno); + //for (long i=0; ioutputno; ++i) { + // first[i] = errors[i] * this->prev_raw_inputs[i]; + //} + Matrx first{1, this->outputno, vec}; + + /* 更新权重梯度 => (errors * 导数) @ this->inputs => (1, outputs ) @ (inputs, 1) = (outputs, inputs) */ + //this->weights_grad = std::vector(this->outputno * this->inputno); + //long k = 0; + //for (long i=0; iinputno; ++i) { + // for (long j=0; joutputno; ++j) { + // this->weights_grad[k++] = first[j] * this->prev_inputs[i]; + // } + //} + Matrx mx {this->inputno, 1, this->prev_inputs.get_data()}; /* (inputs, 1) */ + this->weights_grad = mx * first; /* (inputs, 1) @ (1, outputs) => (inputs, outputs) */ + + /* + * 更新偏置梯度 + * + * NOTE: 在多批次情况下,应该沿着每一样本纵向求平均数 + */ + //this->bias_grad = std::vector(this->outputno); + //for (long i=0; ioutputno; ++i) { + // this->bias_grad[i] = first[i]; + //} + this->bias_grad = first; + + + /* + * 计算上一层的误差责任分担,然后返回 + * + * this->weights @ first => (outputs, inputs) @ (1, outputs) = (inputs, 1) + */ + //std::vector uplevel_errors(this->inputno); + //for (long i=0; iinputno; ++i) { + // long wii = i * this->outputno; /* 每一列的起始点 */ + // float sum = 0.0f; + // for (long j=0, wi=wii; j < this->outputno; ++j, ++wi) { + // sum += this->weights[wi] * first[j]; + // } + // uplevel_errors[i] = sum; + //} + Matrx first1{this->outputno, 1, first.get_data()}; + Matrx uplevel_errs = this->weights * first1; /* (inputs, outputs) @ (outputs, 1) */ + return uplevel_errs.get_data(); + + /* 使用移动语义返回上一层误差 */ + //return std::move(uplevel_errors); +} + +void NeuralNetwork::update(float discount) { + this->weights = this->weights + (this->weights_grad * this->learning_rate * discount); + this->bias = this->bias + (this->bias_grad * this->learning_rate * discount); +} +} diff --git a/lci/src/th/Thread.cpp b/lci/src/th/Thread.cpp new file mode 100644 index 0000000..35969d1 --- /dev/null +++ b/lci/src/th/Thread.cpp @@ -0,0 +1,48 @@ +#include "th/Thread.hpp" +namespace qing{ + + Thread::Thread(f_t stop_callback, f_t wake_callback, f_t loop_callback, f_t clear_callback) + { + StopEvent = std::make_unique(stop_callback); + WakeEvent = std::make_unique(wake_callback); + LoopEvent = std::make_unique(loop_callback); + ClearEvent = std::make_unique(clear_callback); + }; + + /* 线程主函数 */ + void Thread::main() { + + /* 回字形循环 */ + while (check() != Fsm::Stat::SHUT) { + + try { /* 异常只会使线程静止 */ + + + while (check() == Fsm::Stat::STOP) { + (*StopEvent)(*this); /* 静止状态 */ + } + + if (check() == Fsm::Stat::START) { + //(*ClearEvent)(*this); /* 在开始之前做一次清理 */ + (*WakeEvent)(*this); /* 开始事件 */ + } + + while (check() == Fsm::Stat::RUNNING) { + (*LoopEvent)(*this); /* 从设置阶段进入运行态 */ + } + + /* 清理事件 (记得检查成员变量有没有被设置) */ + (*ClearEvent)(*this); + + + } + + catch (std::exception& exp) { + std::cout << "Thread throw a exception: " << exp.what() << std::endl; + stop(); /* 因为这里的停止,线程在循环内抛出异常进程不会死亡,所以需要特别注意内存泄漏 */ + } + + } + } + +} diff --git a/pymsg/pymsg/__init__.py b/pymsg/pymsg/__init__.py index 502d5b3..94b8f6d 100644 --- a/pymsg/pymsg/__init__.py +++ b/pymsg/pymsg/__init__.py @@ -110,6 +110,8 @@ def recv( ) payload = _recv_exact(sock, length) return payload.decode("utf-8") + except UnicodeDecodeError: + raise ConnectionError("invalid UTF-8 payload") from None except _socket.timeout: raise TimeoutError( f"recv timed out after {timeout}s" @@ -457,8 +459,10 @@ class MsgServer: def _handle_client(self, s, socketlist, on_message): try: text = recv(s, timeout=self._recv_timeout) - except (ConnectionError, ConnectionResetError, OSError, TimeoutError): + except (ConnectionError, ConnectionResetError, OSError, + TimeoutError, UnicodeDecodeError): # TimeoutError: 客户端在超时时间内未发送完整消息(Slowloris 防护),关闭连接 + # UnicodeDecodeError: 防御性捕获,recv() 已包装为 ConnectionError,此处兜底 self._remove_client(s, socketlist) return addr = self._clients.get(s, ("unknown", 0)) diff --git a/redirect80/.gitignore b/redirect80/.gitignore new file mode 100644 index 0000000..461da01 --- /dev/null +++ b/redirect80/.gitignore @@ -0,0 +1,109 @@ +#prjs +*.bin +*.build +*.dist +*.onefile-build +nuitka-crash-report.xml + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/redirect80/README.md b/redirect80/README.md new file mode 100644 index 0000000..52dfbd6 --- /dev/null +++ b/redirect80/README.md @@ -0,0 +1,73 @@ +# redirect80 — HTTP→HTTPS 重定向服务 + +基于 Python 内置 `http.server` 的极简 HTTP 重定向服务,监听 80 端口,将所有 HTTP 请求重定向到 HTTPS (443),实现浏览器和搜索引擎友好的 HTTP→HTTPS 无缝升级。 + +## 设计 + +- **零 Web 框架依赖**:纯 Python 标准库 `http.server` + `ThreadingMixIn` 多线程并发 +- **智能重定向**:GET/HEAD → 301(搜索引擎友好永久重定向),POST/PUT/DELETE/PATCH → 308(保留方法和 body) +- **Host 保留**:读取请求 `Host` 头构造重定向 URL(剥离端口),回退用配置的监听地址 +- **日志集成**:通过 `log_client.py` 异步批量推送运行日志到 `db:8005` 的 Logs 表(fail-safe) +- **配置分层**:confs 强依赖 → 环境变量覆盖(`REDIRECT80_*`),confs 不可用时直接退出不做本地回退 + +## 配置 + +配置通过 confs 统一配置服务分发(`confs/configs/redirect80.ini`),启动时经 pymsg 阻塞等待拉取(retry_on_refused),confs 不可用时进程直接退出。环境变量优先级最高。 + +| 配置项 | 环境变量 | 默认值 | 说明 | +|--------|----------|--------|------| +| `host` | `REDIRECT80_HOST` | `0.0.0.0` | 监听地址 | +| `port` | `REDIRECT80_PORT` | `80` | 监听端口 | +| `redirect_port` | `REDIRECT80_REDIRECT_PORT` | `443` | 重定向目标 HTTPS 端口 | +| `redirect_code` | `REDIRECT80_REDIRECT_CODE` | `301` | 非 GET/HEAD 重定向状态码(308 vs 307) | + +## 安装 & 运行 + +```bash +cd redirect80 +bash _set.sh # 创建 venv 并安装依赖 +bash _run.sh # 运行(尝试自动设置 cap_net_bind_service) +``` + +## 端口权限 + +80 端口是 Linux 特权端口(<1024),需要 `CAP_NET_BIND_SERVICE` 能力或 root 权限。`_run.sh` 会自动尝试: + +```bash +sudo setcap 'cap_net_bind_service=+ep' venv/bin/python3 +``` + +如果 `setcap` 不可用或失败,建议使用 systemd 的 `AmbientCapabilities=CAP_NET_BIND_SERVICE`: + +```ini +[Service] +AmbientCapabilities=CAP_NET_BIND_SERVICE +ExecStart=/opt/micro_servers/redirect80/_run.sh +``` + +## 在 core 的 init.txt 中 + +``` +bash /opt/micro_servers/redirect80/_run.sh +``` + +建议放在 waf 之前: + +``` +bash /opt/micro_servers/db/_run.sh +bash /opt/micro_servers/confs/_run.sh +bash /opt/micro_servers/redirect80/_run.sh # ← 80→443 重定向 +bash /opt/micro_servers/waf/_run.sh +bash /opt/micro_servers/gateway/_run.sh +... +``` + +## 端口一览 + +| 端口 | 绑定地址 | 说明 | +|------|----------|------| +| 80 | 0.0.0.0 | HTTP 入口,301/308 → HTTPS :443 | + +## 许可证 + +MIT License diff --git a/redirect80/_run.sh b/redirect80/_run.sh new file mode 100755 index 0000000..d181884 --- /dev/null +++ b/redirect80/_run.sh @@ -0,0 +1,16 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +source venv/bin/activate + +# 80 端口是特权端口(<1024),需要 CAP_NET_BIND_SERVICE 能力 +# 尝试自动设置 cap(失败不阻塞,用户可手动 sudo 或用 systemd AmbientCapabilities) +_python_bin="$(readlink -f venv/bin/python3)" +if command -v setcap &>/dev/null; then + if sudo setcap 'cap_net_bind_service=+ep' "$_python_bin" 2>/dev/null; then + echo "[redirect80] 已为 $_python_bin 设置 cap_net_bind_service" + else + echo "[redirect80] ⚠ 无法设置 cap_net_bind_service,可能需要 root 运行" + fi +fi + +exec python3 redirect80.py diff --git a/redirect80/_set.sh b/redirect80/_set.sh new file mode 100755 index 0000000..c7a534e --- /dev/null +++ b/redirect80/_set.sh @@ -0,0 +1,5 @@ +#!/bin/bash +cd "$(dirname "$0")" || exit +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple diff --git a/redirect80/log_client.py b/redirect80/log_client.py new file mode 100644 index 0000000..8529be7 --- /dev/null +++ b/redirect80/log_client.py @@ -0,0 +1,158 @@ +""" +统一日志客户端 — redirect80 服务副本(基于 pymsg.AsyncRpcQueue)。 + +设计要点: + - 通过 pymsg RPC 调用 db execute 路由,逐条 INSERT 到 Logs 表 + - 异步非阻塞:内存队列 + 后台线程攒批推送,不拖慢业务 + - fail-safe:db 服务不可用时静默丢弃,绝不影响业务 + - 缓冲批量:队列满 50 条或超时 2 秒时自动 flush + - 时间戳:日志入队时即记录 ts(UTC ISO 格式),反映事件真实发生时间 + - 底层复用 pymsg.AsyncRpcQueue 通用队列基础设施 + +用法(与旧版完全兼容): + from log_client import logs + + logs.info("redirect80", "服务已启动") + logs.error("redirect80", "端口绑定失败", extra={"errno": 98}) + logs.push("redirect80", "WARNING", "confs 不可用,使用本地配置", + trace_id="startup", extra={"fallback": "redirect80.ini"}) +""" + +import json +import os as _os +import sys as _sys +import atexit +from datetime import datetime, timezone + +_sys.path.insert(0, _os.path.join(_os.path.dirname(__file__), "..")) +from pymsg import RpcClient, RpcError, AsyncRpcQueue # noqa: E402 + +# ── 配置 ────────────────────────────────────────────────────────────── + +_DBV2_ADDR = _os.environ.get('DB_HOST', '127.0.0.1') +_DBV2_PORT = int(_os.environ.get('DB_PORT', '8005')) + +_BATCH_SIZE = 50 +_FLUSH_INTERVAL = 2.0 +_TIMEOUT = 5 +_QUEUE_MAXSIZE = 10000 + + +def _safe_json(obj): + """安全序列化 extra 字段,不可序列化对象转为 repr 字符串。""" + try: + return json.dumps(obj, ensure_ascii=False, default=str) + except Exception: + return repr(obj) + + +def _now_iso(): + """生成当前 UTC 时间 ISO 字符串(入队时调用,保证时间戳准确)。""" + return datetime.now(timezone.utc).isoformat() + + +class LogClient: + """异步批量日志推送客户端(API 与旧版完全兼容)。""" + + def __init__(self, service_name: str = "log", + batch_size: int = _BATCH_SIZE, + flush_interval: float = _FLUSH_INTERVAL): + self._service_name = service_name + self._client = RpcClient( + _DBV2_ADDR, _DBV2_PORT, + service_name + "-log", + timeout=_TIMEOUT, + ) + self._queue = AsyncRpcQueue( + handler=self._send_batch, + batch_size=batch_size, + flush_interval=flush_interval, + max_queue_size=_QUEUE_MAXSIZE, + on_error=self._on_error, + ) + self._queue.start() + atexit.register(self.close) + + # ── 公开接口 ──────────────────────────────────────────────────────── + + def push(self, service: str, level: str, message: str, + trace_id: str = None, extra=None): + """推送一条日志(非阻塞,立即返回)。 + + 队列满时静默丢弃最旧条目再放入新条目,保证不阻塞业务线程、不导致 OOM。 + """ + entry = { + 'ts': _now_iso(), + 'service': service, + 'level': level, + 'message': message, + 'trace_id': trace_id, + 'extra': extra, + } + self._queue.put(entry) + + def debug(self, service: str, message: str, **kw): + self.push(service, 'DEBUG', message, **kw) + + def info(self, service: str, message: str, **kw): + self.push(service, 'INFO', message, **kw) + + def warning(self, service: str, message: str, **kw): + self.push(service, 'WARNING', message, **kw) + + def warn(self, service: str, message: str, **kw): + self.push(service, 'WARNING', message, **kw) + + def error(self, service: str, message: str, **kw): + self.push(service, 'ERROR', message, **kw) + + def critical(self, service: str, message: str, **kw): + self.push(service, 'CRITICAL', message, **kw) + + def flush(self): + """手动 flush 队列中剩余的日志。""" + self._queue.flush() + + def close(self): + """关闭客户端,flush 剩余日志。""" + self._queue.close() + + # ── 内部实现 ──────────────────────────────────────────────────────── + + def _send_batch(self, batch: list): + """后台线程回调:逐条 INSERT 到 db(网络错误放弃本批剩余)。""" + for entry in batch: + extra_val = entry.get("extra") + try: + extra_json = _safe_json(extra_val) if extra_val is not None else None + except Exception: + extra_json = None + payload = { + "action": "insert", + "table": "Logs", + "values": { + "ts": entry.get("ts", _now_iso()), + "service": entry.get("service"), + "level": entry.get("level"), + "message": entry.get("message"), + "trace_id": entry.get("trace_id"), + "extra": extra_json, + }, + } + try: + self._client.call("execute", payload, timeout=_TIMEOUT) + except RpcError as e: + print(f"[log_client] INSERT 失败: {e}", file=_sys.stderr) + except Exception as e: + print(f"[log_client] 发送失败(放弃本批剩余): {e}", file=_sys.stderr) + break + + def _on_error(self, e: Exception, batch: list): + """异常安全网:handler 外的异常也不会崩溃线程。""" + print(f"[log_client] _send_batch 异常(已捕获,线程继续运行): {e}", + file=_sys.stderr) + + +# ── 全局单例 ────────────────────────────────────────────────────────── + +logs = LogClient(service_name="redirect80") diff --git a/redirect80/redirect80.py b/redirect80/redirect80.py new file mode 100644 index 0000000..c231417 --- /dev/null +++ b/redirect80/redirect80.py @@ -0,0 +1,182 @@ +""" +redirect80 — HTTP 80 端口重定向服务。 + +监听 80 端口,所有 HTTP 请求返回 301/308 重定向到 HTTPS (443), +保留原始 Host 和路径。为搜索引擎和浏览器提供 HTTP→HTTPS 无缝升级。 + +技术选型:Python 内置 http.server + 多线程混合模式,无外部 Web 框架依赖。 + 日志通过 log_client 异步推送到 db 的 Logs 表(fail-safe)。 + +配置(两层加载): + 1. confs 强依赖拉取 redirect80.ini(retry_on_refused 阻塞等待) + 2. 环境变量覆盖(Docker/k8s 兼容) +confs 不可用时直接退出,不做本地回退。 +""" + +import configparser +import os +import sys as _sys +from http.server import HTTPServer, BaseHTTPRequestHandler +from socketserver import ThreadingMixIn + +# ── 路径设置 ────────────────────────────────────────────────────────── +_here = os.path.dirname(os.path.abspath(__file__)) +_sys.path.insert(0, os.path.join(_here, "..")) +from log_client import logs # noqa: E402 + +# ── 配置加载(confs 强依赖 → 环境变量覆盖)──────────────────────── +_config = { + "host": "0.0.0.0", + "port": 80, + "redirect_port": 443, + "redirect_code": 301, +} + +# 1. confs 强依赖拉取配置(阻塞等待 confs 就绪,失败则退出) +_sys.path.insert(0, os.path.join(_here, "..", "pymsg")) +from pymsg import RpcClient # noqa: E402 + +_confs_host = os.environ.get("CONFS_HOST", "127.0.0.1") +_confs_port = int(os.environ.get("CONFS_PORT", "8010")) +_confs_client = RpcClient( + _confs_host, _confs_port, "redirect80", + retry_on_refused=True, timeout=5, +) +_data = _confs_client.call("get", {"name": "redirect80.ini"}) +_ini_text = _data.get("content", "") +_ini = configparser.ConfigParser(interpolation=None) +_ini.read_string(_ini_text) + +_merge_map = { + ("server", "host"): "host", + ("server", "port"): "port", + ("server", "redirect_port"): "redirect_port", + ("server", "redirect_code"): "redirect_code", +} +for (sec, key), var in _merge_map.items(): + if _ini.has_option(sec, key): + val = _ini.get(sec, key) + _config[var] = type(_config[var])(val) +logs.info("redirect80", "配置已从 confs 加载") + +# 2. 环境变量最高优先级覆盖 +_env_map = { + "REDIRECT80_HOST": "host", + "REDIRECT80_PORT": ("port", int), + "REDIRECT80_REDIRECT_PORT": ("redirect_port", int), + "REDIRECT80_REDIRECT_CODE": ("redirect_code", int), +} +for env_var, mapping in _env_map.items(): + val = os.environ.get(env_var) + if val is not None: + if isinstance(mapping, tuple): + _config[mapping[0]] = mapping[1](val) + else: + _config[mapping] = val + +# ── 请求处理器 ────────────────────────────────────────────────────────── + + +class RedirectHandler(BaseHTTPRequestHandler): + """HTTP 请求处理器:将所有请求重定向到 HTTPS。 + + GET/HEAD → 301 (Moved Permanently),搜索引擎友好的永久重定向。 + POST/PUT/DELETE/PATCH → 308 (Permanent Redirect),保留请求方法和 body。 + """ + + server_version = "UniServe/redirect80" + sys_version = "" + + def _redirect(self, code: int): + """构造 HTTPS 重定向 URL 并返回。""" + host = self.headers.get("Host", "") + # 剥离端口号(如果客户端带了 :80) + hostname = host.split(":")[0] if host else _config["host"] + target_port = _config["redirect_port"] + # 标准 443 端口不显式写 :443 + if target_port == 443: + location = f"https://{hostname}{self.path}" + else: + location = f"https://{hostname}:{target_port}{self.path}" + + self.send_response(code) + self.send_header("Location", location) + self.send_header("Connection", "close") + self.send_header("Cache-Control", "max-age=31536000") + self.end_headers() + + # 日志:仅记录摘要(不刷屏) + logs.info("redirect80", + f"{code} {self.command} {host} → {location}") + + def do_GET(self): + self._redirect(301) + + def do_HEAD(self): + self._redirect(301) + + def do_POST(self): + self._redirect(308) + + def do_PUT(self): + self._redirect(308) + + def do_DELETE(self): + self._redirect(308) + + def do_PATCH(self): + self._redirect(308) + + def do_OPTIONS(self): + self.send_response(204) + self.send_header("Allow", "GET, HEAD, POST, PUT, DELETE, PATCH, OPTIONS") + self.send_header("Connection", "close") + self.end_headers() + + def log_message(self, format, *args): + """抑制默认的 stderr 日志(已通过 log_client 记录)。""" + pass + + +# ── 多线程 HTTP 服务器 ────────────────────────────────────────────────── + + +class ThreadingRedirectServer(ThreadingMixIn, HTTPServer): + """多线程混合 HTTP 服务器,处理并发连接。 + + ThreadingMixIn 为每个请求创建新线程,适合 redirect80 + 这种请求处理极快(无 I/O 阻塞)的场景。 + """ + daemon_threads = True + allow_reuse_address = True + + def handle_error(self, request, client_address): + """覆盖默认错误处理,异常写入 log_client 而非 stderr。""" + logs.error("redirect80", + f"处理 {client_address} 请求时异常", + extra={"client": str(client_address)}) + + +def main(): + host = _config["host"] + port = int(_config["port"]) + + server = ThreadingRedirectServer((host, port), RedirectHandler) + + logs.info("redirect80", + f"HTTP→HTTPS 重定向服务启动 " + f"http://{host}:{port} → https://*:{_config['redirect_port']}") + + print(f"[redirect80] 监听 http://{host}:{port} " + f"→ 重定向到 :{_config['redirect_port']}", file=_sys.stderr) + + try: + server.serve_forever() + except KeyboardInterrupt: + logs.info("redirect80", "收到 SIGINT,正在关闭...") + server.shutdown() + logs.info("redirect80", "服务已停止") + + +if __name__ == "__main__": + main() diff --git a/redirect80/requirements.txt b/redirect80/requirements.txt new file mode 100644 index 0000000..4d41e83 --- /dev/null +++ b/redirect80/requirements.txt @@ -0,0 +1 @@ +../pymsg diff --git a/static/_run.sh b/static/_run.sh index dc49454..ad6bd5c 100644 --- a/static/_run.sh +++ b/static/_run.sh @@ -2,4 +2,5 @@ cd "$(dirname "$0")" || exit source ./venv/bin/activate #exec ./fsys.bin 1>/dev/null +sleep 2 exec python3 ./fsys.py 1>/dev/null diff --git a/static/public/__view.html b/static/public/__view.html index c29f08e..8ae96b0 100644 --- a/static/public/__view.html +++ b/static/public/__view.html @@ -4,7 +4,7 @@ 树菜单 · 文件浏览 - +
@@ -47,7 +47,7 @@ 蜀ICP备2024107064号-2 - - + + diff --git a/static/public/aibox.html b/static/public/aibox.html index e8b01da..e7700c6 100644 --- a/static/public/aibox.html +++ b/static/public/aibox.html @@ -32,6 +32,7 @@
+ diff --git a/static/public/css/codeblock.css b/static/public/css/codeblock.css new file mode 100644 index 0000000..5344ee3 --- /dev/null +++ b/static/public/css/codeblock.css @@ -0,0 +1 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline} \ No newline at end of file diff --git a/static/public/css/index.css b/static/public/css/index.css index 73597f3..2b933e0 100644 --- a/static/public/css/index.css +++ b/static/public/css/index.css @@ -4,31 +4,177 @@ body { align-items: normal; } -/* ===== 头部 ===== */ +@media (prefers-reduced-motion: no-preference) { + html { scroll-behavior: smooth; } +} + +/* ===== 按钮 ===== */ +.btn { + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0.55rem 1.3rem; + font-size: 0.88rem; + font-weight: 600; + font-family: inherit; + border: 1px solid transparent; + border-radius: var(--radius-sm); + cursor: pointer; + text-decoration: none; + line-height: 1.4; + transition: opacity 0.15s, transform 0.1s, background 0.15s, border-color 0.15s; +} +.btn:active { transform: scale(0.96); } +.btn-primary { background: var(--accent); color: #fff; } +.btn-primary:hover { background: var(--accent-dark); opacity: 1; } +.btn-ghost { background: var(--accent-soft); color: var(--accent-dark); } +.btn-ghost:hover { border-color: var(--accent); opacity: 1; } +.btn-lg { padding: 0.7rem 1.9rem; font-size: 1rem; border-radius: var(--radius-md); } + +/* ===== 头部:悬浮毛玻璃导航(镜像 minimap/userpanel 风格) ===== */ .header { + position: sticky; + top: 0.75rem; + z-index: 100; display: flex; justify-content: space-between; align-items: center; + flex-wrap: wrap; + gap: 0.5rem; width: 100%; + max-width: 960px; + margin: 0 auto; + padding: 0.5rem 1rem; + border-radius: var(--radius-md); + background: rgba(253, 246, 238, 0.72); + border: 1px solid var(--border-light); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + box-shadow: var(--shadow-md); + transition: background 0.2s, border-color 0.2s; } +@media (prefers-color-scheme: dark) { + .header { + background: rgba(30, 23, 18, 0.72); + border-color: var(--border); + } +} + +.header h1 { + font-size: 1.15rem; + cursor: pointer; + user-select: none; + transition: color 0.15s; +} +.header h1:hover { color: var(--accent); } .right-group { display: flex; align-items: center; -} - -.right-group > img, -.right-group > b, -.right-group > button { - margin-left: 5px; - margin-right: 5px; + flex-wrap: wrap; + gap: 0.4rem; } #avatar { + width: 36px; + height: 36px; border-radius: 50%; + border: 1.5px solid var(--border); + object-fit: cover; } -/* ===== 网站简介 ===== */ +#name { + font-size: 0.88rem; + max-width: 120px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +/* ===== Hero 首屏 ===== */ +.hero { + position: relative; + text-align: center; + padding: 4rem 1rem 3rem; +} +.hero::before { + content: ""; + position: absolute; + inset: 0; + background: radial-gradient(ellipse 60% 50% at 50% 30%, var(--accent-glow), transparent 70%); + pointer-events: none; +} +.hero > * { position: relative; } +.hero-title { + font-size: clamp(1.8rem, 5vw, 2.6rem); + font-weight: 800; + line-height: 1.35; + letter-spacing: 0.02em; + margin-bottom: 0.75rem; +} +.accent-text { color: var(--accent); } +.hero-sub { + font-size: 1.05rem; + color: var(--fg-secondary); +} +.hero-actions { + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 0.75rem; + margin-top: 1.75rem; +} + +/* ===== 特性卡片 ===== */ +.section-title { + text-align: center; + margin-top: 3rem; +} +.features { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); + gap: 0.9rem; + width: 100%; + max-width: 960px; + margin: 0 auto; +} +.feature-card { + background: var(--card); + border: 1px solid var(--border-light); + border-radius: var(--radius-md); + padding: 1.4rem 1.25rem; + box-shadow: var(--shadow-sm); + transition: transform 0.18s, box-shadow 0.2s, border-color 0.2s; +} +.feature-card:hover { + transform: translateY(-3px); + border-color: var(--border); + box-shadow: var(--shadow-md); +} +.feature-icon { + display: flex; + align-items: center; + justify-content: center; + width: 38px; + height: 38px; + margin-bottom: 0.75rem; + border-radius: var(--radius-sm); + background: var(--accent-soft); + color: var(--accent-dark); +} +.feature-icon svg { width: 20px; height: 20px; } +.feature-card h3 { margin-bottom: 0.35rem; } +.feature-card p { + font-size: 0.86rem; + line-height: 1.65; + color: var(--fg-secondary); +} + +/* ===== 关于本站 ===== */ +.about { + text-align: center; + padding-bottom: 2rem; +} .site-intro { max-width: 640px; margin: 0 auto; @@ -36,3 +182,42 @@ body { line-height: 1.9; color: var(--fg-secondary); } +.quick-links { + display: flex; + justify-content: center; + flex-wrap: wrap; + gap: 1.25rem; + margin-top: 1.5rem; +} +.quick-links a { + font-size: 0.85rem; + color: var(--muted); + text-decoration: none; + transition: color 0.15s; +} +.quick-links a:hover { color: var(--accent); } + +/* ===== 入场动画 ===== */ +@keyframes fade-up { + from { opacity: 0; transform: translateY(12px); } + to { opacity: 1; transform: none; } +} +@media (prefers-reduced-motion: no-preference) { + .hero > *, .feature-card, .about { animation: fade-up 0.5s ease both; } + .hero-sub { animation-delay: 0.08s; } + .hero-actions { animation-delay: 0.16s; } + .feature-card:nth-child(2) { animation-delay: 0.06s; } + .feature-card:nth-child(3) { animation-delay: 0.12s; } + .feature-card:nth-child(4) { animation-delay: 0.18s; } +} + +/* ===== 响应式 ===== */ +@media (max-width: 480px) { + .header { top: 0.5rem; padding: 0.45rem 0.75rem; } + .header h1 { font-size: 1rem; } + #name { max-width: 72px; } + .hero { padding: 2.5rem 0.5rem 2rem; } + .hero-sub { font-size: 0.95rem; } + .hero-actions { flex-direction: column; align-items: stretch; } + .section-title { margin-top: 2rem; } +} diff --git a/static/public/dnfs.html b/static/public/dnfs.html index b9a8a99..085acca 100644 --- a/static/public/dnfs.html +++ b/static/public/dnfs.html @@ -6,9 +6,14 @@ 树状笔记 +
+
@@ -36,7 +41,9 @@
- + + + diff --git a/static/public/index.html b/static/public/index.html index e2b1eff..7b5e1e8 100644 --- a/static/public/index.html +++ b/static/public/index.html @@ -1,35 +1,92 @@ - + + + + + - DNFS 欢迎来到树状笔记 + DNFS 树状笔记 — 让知识自然成体系
-

DNFS 树状笔记

-
- 头像加载失败 - DNFS - - - - -
+

DNFS 树状笔记

+
-
-

关于本站

-

- DNFS 树状笔记是一个以树状结构组织内容的笔记社区:每个节点都可以生长出子节点, - 像树枝一样层层延展,让知识自然成体系。支持 Markdown 文本、链接卡片、图片与文件分享, - 注册登录后即可创建属于你自己的知识树。 -

-
+ +
+
+

让知识像树一样
自然生长

+

每个节点都可以生长出子节点,像树枝一样层层延展

+
+ + 了解更多 +
+
+ +
+

为什么选择树状笔记

+
+
+ +

树状结构组织

+

每个节点都能生长出子节点,像树枝般层层延展,让零散的想法自然汇聚成体系。

+
+
+ +

Markdown 写作

+

原生支持 Markdown 渲染,代码块、引用、列表一应俱全,专注内容本身。

+
+
+ +

多媒体分享

+

链接卡片、图片直显、文件下载,多种内容形态一站承载,分享更自由。

+
+
+ +

深色模式

+

跟随系统偏好自动切换明暗主题,日夜皆宜的舒适阅读体验。

+
+
+
+ +
+

关于本站

+

+ DNFS 树状笔记是一个以树状结构组织内容的笔记社区:每个节点都可以生长出子节点, + 像树枝一样层层延展,让知识自然成体系。支持 Markdown 文本、链接卡片、图片与文件分享, + 注册登录后即可创建属于你自己的知识树。 +

+ +
+
+ - + 蜀ICP备2024107064号-2 + + + - \ No newline at end of file + diff --git a/static/public/js/aibox.js b/static/public/js/aibox.js index 5b72e15..c9d1717 100644 --- a/static/public/js/aibox.js +++ b/static/public/js/aibox.js @@ -3,8 +3,8 @@ * aibox Web 客户端 · 移动端版(经 gateway WS 反向代理,仅管理员可用) * 协议与 BotOps/aibox client.py 完全兼容: * 发送:{"type":"message","content":...} / {"type":"command","command":"/..."} / {"type":"interrupt",...} - * 接收:chunk(增量片段) / reasoning_start / reasoning / reasoning_end / complete / - * line(过程行) / task_process / task_status / task_error / task_added / + * 接收:chunk(增量片段) / reasoning_start / reasoning / reasoning_end / ai_break / + * complete / line(过程行) / task_process / task_status / task_error / task_added / * dialogue_ended / dialogue_reset / interrupt_ack / error / info / * command_result / connection_ack / notification / pong * ============================================================ */ @@ -152,6 +152,8 @@ function endReasoning() { reasoningHead.textContent = '💭 思考过程(' + reasoningText.length + ' 字符,点击折叠/展开)'; reasoningBody.classList.add('folded'); /* 结束后默认折叠,避免占屏 */ } + /* 清除引用(DOM元素保留显示),下一轮 reasoning_start 创建新的思考区域 */ + reasoningBox = null; reasoningHead = null; reasoningBody = null; reasoningText = ''; } function abortReasoning() { /* 用户中断:更新思考区域标签为已中断,保留已展示内容 */ @@ -162,6 +164,16 @@ function abortReasoning() { reasoningHead.textContent = '🛑 思考已中断'; } } + /* 清除引用,DOM元素保留显示 */ + reasoningBox = null; reasoningHead = null; reasoningBody = null; reasoningText = ''; +} + +/* ---------- AI 文本分段(工具调用时 breakAi,后续 chunk 创建新气泡) ---------- */ +function breakAi() { + if (aiBubble) { + aiBubble.classList.remove('streaming'); + aiBubble = null; aiText = ''; + } } /* ---------- 连接状态 ---------- */ @@ -242,11 +254,14 @@ function routeMessage(data) { appendReasoning(content); } else if (t === 'reasoning_end') { endReasoning(); + } else if (t === 'ai_break') { + /* 工具调用前分段:结束当前AI文本段(保留已显示内容),后续chunk创建新气泡 */ + breakAi(); } else if (t === 'line') { - /* 过程行:工具调用提示 / 工具输出 → 任务面板;助手前缀 / 思考提示聊天区已有承载,跳过 */ + /* 过程行:工具调用提示 / 工具输出 → 任务面板;助手前缀 / 思考提示等聊天区已有承载,跳过 */ const stripped = content.trim(); if (!stripped) return; - if (/^(💬 助手|💬 Assistant|🤔 思考中|🤔 Thinking|🤔 深度思考中)/.test(stripped)) return; + if (/^(💬 助手|💬 Assistant|🤔 思考中|🤔 Thinking|🤔 深度思考中|🤔 分析工具结果|🤔 Analyzing|🔧 需要调用工具|🔧 Need to call)/.test(stripped)) return; addTaskLine(stripped); } else if (t === 'complete') { finishAi(content); @@ -290,7 +305,8 @@ function routeMessage(data) { } else if (t === 'notification') { addSystem('🔔 ' + content); } else if (content) { - appendAi(content); /* 未知类型兜底:按 AI 增量处理(与 BotOps 一致) */ + /* 未知消息类型不追加到AI聊天区(避免非AI内容污染回复),记入任务面板 */ + addTaskLine('[未知消息 type=' + t + '] ' + content.slice(0, 200)); } } diff --git a/static/public/js/dnfs.js b/static/public/js/dnfs.js index 2589c4f..099e644 100644 --- a/static/public/js/dnfs.js +++ b/static/public/js/dnfs.js @@ -6,8 +6,8 @@ */ async function getNode(id) { try { - obj = { "pid": id } - jsonBody = JSON.stringify(obj) + const obj = { "pid": id } + const jsonBody = JSON.stringify(obj) console.log(jsonBody) const res = await fetch('/get_notes', { method: 'POST', @@ -19,7 +19,7 @@ async function getNode(id) { }); const responseText = await res.text(); - // WAF 拦截:弹提示并中止,不能落入 catch(其会误跳登录页) + // WAF 拦截:弹提示并中止,不能落入 catch(其会向上抛出) if (window.WafTip && WafTip.isBlocked(res, responseText)) { alert(WafTip.MESSAGE); return; @@ -34,7 +34,7 @@ async function getNode(id) { } if (res.status === 401) { - // 凭证失效(过期或网关重启),跳转重新登录 + // 凭证失效(过期或网关重启),仅此一种情况跳转重新登录 location.href = '/login.html'; return; } @@ -53,10 +53,12 @@ async function getNode(id) { //} } catch (err) { - // 获取节点失败(非 JSON 响应 / HTTP 错误 / 网络异常),统一跳转登录页 + // 非 401 失败(网络异常 / 5xx / 非 JSON 响应):提示真实原因并向上抛出, + // 调用方 .then(load_notes/loadMap) 不再执行,当前页面内容保持不变; + // 不再把任意错误误判为凭证失效而跳登录页 console.error('获取节点请求异常:', err); - location.href = '/login.html'; - } finally { + alert(err.message || '获取节点失败,请检查网络后重试'); + throw err; } } @@ -414,8 +416,17 @@ function renderMarkdown(element, content) { /* Markdown渲染 */ - const md = window.markdownit(); - element.innerHTML = md.render(content, {html: false}); + const md = window.markdownit({ + html: false, + highlight: function(code, lang) { + if (lang && hljs.getLanguage(lang)) { + return `
${hljs.highlight(code, {language: lang}).value}
` + } else { + return `
${md.utils.escapeHtml(code)}
` + } + } + }); + element.innerHTML = md.render(content); } /* ===== by qing — 特殊节点(管理员专属)===== @@ -982,6 +993,14 @@ function renderUserPanel() { userpanel.appendChild(fold); if (!userpanel_expand || !current_user.login) return; + let back_to_index = document.createElement("div"); + back_to_index.className = "tag"; + back_to_index.textContent = "回到主页"; + back_to_index.addEventListener("click", () => { + window.location.href = "/"; + }) + userpanel.appendChild(back_to_index); + let name_tag = document.createElement("div"); name_tag.className = "tag no-hover"; name_tag.textContent = current_user.user; diff --git a/static/public/js/highlight_11_9_0.js b/static/public/js/highlight_11_9_0.js new file mode 100644 index 0000000..5d699ae --- /dev/null +++ b/static/public/js/highlight_11_9_0.js @@ -0,0 +1,1213 @@ +/*! + Highlight.js v11.9.0 (git: f47103d4f1) + (c) 2006-2023 undefined and other contributors + License: BSD-3-Clause + */ +var hljs=function(){"use strict";function e(n){ +return n instanceof Map?n.clear=n.delete=n.set=()=>{ +throw Error("map is read-only")}:n instanceof Set&&(n.add=n.clear=n.delete=()=>{ +throw Error("set is read-only") +}),Object.freeze(n),Object.getOwnPropertyNames(n).forEach((t=>{ +const a=n[t],i=typeof a;"object"!==i&&"function"!==i||Object.isFrozen(a)||e(a) +})),n}class n{constructor(e){ +void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} +ignoreMatch(){this.isMatchIgnored=!0}}function t(e){ +return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") +}function a(e,...n){const t=Object.create(null);for(const n in e)t[n]=e[n] +;return n.forEach((e=>{for(const n in e)t[n]=e[n]})),t}const i=e=>!!e.scope +;class r{constructor(e,n){ +this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ +this.buffer+=t(e)}openNode(e){if(!i(e))return;const n=((e,{prefix:n})=>{ +if(e.startsWith("language:"))return e.replace("language:","language-") +;if(e.includes(".")){const t=e.split(".") +;return[`${n}${t.shift()}`,...t.map(((e,n)=>`${e}${"_".repeat(n+1)}`))].join(" ") +}return`${n}${e}`})(e.scope,{prefix:this.classPrefix});this.span(n)} +closeNode(e){i(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ +this.buffer+=``}}const s=(e={})=>{const n={children:[]} +;return Object.assign(n,e),n};class o{constructor(){ +this.rootNode=s(),this.stack=[this.rootNode]}get top(){ +return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ +this.top.children.push(e)}openNode(e){const n=s({scope:e}) +;this.add(n),this.stack.push(n)}closeNode(){ +if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ +for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} +walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ +return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), +n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ +"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ +o._collapse(e)})))}}class l extends o{constructor(e){super(),this.options=e} +addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ +this.closeNode()}__addSublanguage(e,n){const t=e.root +;n&&(t.scope="language:"+n),this.add(t)}toHTML(){ +return new r(this,this.options).value()}finalize(){ +return this.closeAllNodes(),!0}}function c(e){ +return e?"string"==typeof e?e:e.source:null}function d(e){return b("(?=",e,")")} +function g(e){return b("(?:",e,")*")}function u(e){return b("(?:",e,")?")} +function b(...e){return e.map((e=>c(e))).join("")}function m(...e){const n=(e=>{ +const n=e[e.length-1] +;return"object"==typeof n&&n.constructor===Object?(e.splice(e.length-1,1),n):{} +})(e);return"("+(n.capture?"":"?:")+e.map((e=>c(e))).join("|")+")"} +function p(e){return RegExp(e.toString()+"|").exec("").length-1} +const _=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ +;function h(e,{joinWith:n}){let t=0;return e.map((e=>{t+=1;const n=t +;let a=c(e),i="";for(;a.length>0;){const e=_.exec(a);if(!e){i+=a;break} +i+=a.substring(0,e.index), +a=a.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?i+="\\"+(Number(e[1])+n):(i+=e[0], +"("===e[0]&&t++)}return i})).map((e=>`(${e})`)).join(n)} +const f="[a-zA-Z]\\w*",E="[a-zA-Z_]\\w*",y="\\b\\d+(\\.\\d+)?",N="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",v={ +begin:"\\\\[\\s\\S]",relevance:0},O={scope:"string",begin:"'",end:"'", +illegal:"\\n",contains:[v]},k={scope:"string",begin:'"',end:'"',illegal:"\\n", +contains:[v]},x=(e,n,t={})=>{const i=a({scope:"comment",begin:e,end:n, +contains:[]},t);i.contains.push({scope:"doctag", +begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", +end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) +;const r=m("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) +;return i.contains.push({begin:b(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),i +},M=x("//","$"),S=x("/\\*","\\*/"),A=x("#","$");var C=Object.freeze({ +__proto__:null,APOS_STRING_MODE:O,BACKSLASH_ESCAPE:v,BINARY_NUMBER_MODE:{ +scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:x, +C_BLOCK_COMMENT_MODE:S,C_LINE_COMMENT_MODE:M,C_NUMBER_MODE:{scope:"number", +begin:N,relevance:0},C_NUMBER_RE:N,END_SAME_AS_BEGIN:e=>Object.assign(e,{ +"on:begin":(e,n)=>{n.data._beginMatch=e[1]},"on:end":(e,n)=>{ +n.data._beginMatch!==e[1]&&n.ignoreMatch()}}),HASH_COMMENT_MODE:A,IDENT_RE:f, +MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+E,relevance:0}, +NUMBER_MODE:{scope:"number",begin:y,relevance:0},NUMBER_RE:y, +PHRASAL_WORDS_MODE:{ +begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ +},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, +end:/\/[gimuy]*/,contains:[v,{begin:/\[/,end:/\]/,relevance:0,contains:[v]}]}, +RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", +SHEBANG:(e={})=>{const n=/^#![ ]*\// +;return e.binary&&(e.begin=b(n,/.*\b/,e.binary,/\b.*/)),a({scope:"meta",begin:n, +end:/$/,relevance:0,"on:begin":(e,n)=>{0!==e.index&&n.ignoreMatch()}},e)}, +TITLE_MODE:{scope:"title",begin:f,relevance:0},UNDERSCORE_IDENT_RE:E, +UNDERSCORE_TITLE_MODE:{scope:"title",begin:E,relevance:0}});function T(e,n){ +"."===e.input[e.index-1]&&n.ignoreMatch()}function R(e,n){ +void 0!==e.className&&(e.scope=e.className,delete e.className)}function D(e,n){ +n&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", +e.__beforeBegin=T,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, +void 0===e.relevance&&(e.relevance=0))}function I(e,n){ +Array.isArray(e.illegal)&&(e.illegal=m(...e.illegal))}function L(e,n){ +if(e.match){ +if(e.begin||e.end)throw Error("begin & end are not supported with match") +;e.begin=e.match,delete e.match}}function B(e,n){ +void 0===e.relevance&&(e.relevance=1)}const $=(e,n)=>{if(!e.beforeMatch)return +;if(e.starts)throw Error("beforeMatch cannot be used with starts") +;const t=Object.assign({},e);Object.keys(e).forEach((n=>{delete e[n] +})),e.keywords=t.keywords,e.begin=b(t.beforeMatch,d(t.begin)),e.starts={ +relevance:0,contains:[Object.assign(t,{endsParent:!0})] +},e.relevance=0,delete t.beforeMatch +},z=["of","and","for","in","not","or","if","then","parent","list","value"],F="keyword" +;function U(e,n,t=F){const a=Object.create(null) +;return"string"==typeof e?i(t,e.split(" ")):Array.isArray(e)?i(t,e):Object.keys(e).forEach((t=>{ +Object.assign(a,U(e[t],n,t))})),a;function i(e,t){ +n&&(t=t.map((e=>e.toLowerCase()))),t.forEach((n=>{const t=n.split("|") +;a[t[0]]=[e,j(t[0],t[1])]}))}}function j(e,n){ +return n?Number(n):(e=>z.includes(e.toLowerCase()))(e)?0:1}const P={},K=e=>{ +console.error(e)},H=(e,...n)=>{console.log("WARN: "+e,...n)},q=(e,n)=>{ +P[`${e}/${n}`]||(console.log(`Deprecated as of ${e}. ${n}`),P[`${e}/${n}`]=!0) +},G=Error();function Z(e,n,{key:t}){let a=0;const i=e[t],r={},s={} +;for(let e=1;e<=n.length;e++)s[e+a]=i[e],r[e+a]=!0,a+=p(n[e-1]) +;e[t]=s,e[t]._emit=r,e[t]._multi=!0}function W(e){(e=>{ +e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, +delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ +_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope +}),(e=>{if(Array.isArray(e.begin)){ +if(e.skip||e.excludeBegin||e.returnBegin)throw K("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), +G +;if("object"!=typeof e.beginScope||null===e.beginScope)throw K("beginScope must be object"), +G;Z(e,e.begin,{key:"beginScope"}),e.begin=h(e.begin,{joinWith:""})}})(e),(e=>{ +if(Array.isArray(e.end)){ +if(e.skip||e.excludeEnd||e.returnEnd)throw K("skip, excludeEnd, returnEnd not compatible with endScope: {}"), +G +;if("object"!=typeof e.endScope||null===e.endScope)throw K("endScope must be object"), +G;Z(e,e.end,{key:"endScope"}),e.end=h(e.end,{joinWith:""})}})(e)}function Q(e){ +function n(n,t){ +return RegExp(c(n),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(t?"g":"")) +}class t{constructor(){ +this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} +addRule(e,n){ +n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), +this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) +;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(h(e,{joinWith:"|" +}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex +;const n=this.matcherRe.exec(e);if(!n)return null +;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),a=this.matchIndexes[t] +;return n.splice(0,t),Object.assign(n,a)}}class i{constructor(){ +this.rules=[],this.multiRegexes=[], +this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ +if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t +;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), +n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ +return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ +this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ +const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex +;let t=n.exec(e) +;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ +const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} +return t&&(this.regexIndex+=t.position+1, +this.regexIndex===this.count&&this.considerAll()),t}} +if(e.compilerExtensions||(e.compilerExtensions=[]), +e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") +;return e.classNameAliases=a(e.classNameAliases||{}),function t(r,s){const o=r +;if(r.isCompiled)return o +;[R,L,W,$].forEach((e=>e(r,s))),e.compilerExtensions.forEach((e=>e(r,s))), +r.__beforeBegin=null,[D,I,B].forEach((e=>e(r,s))),r.isCompiled=!0;let l=null +;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), +l=r.keywords.$pattern, +delete r.keywords.$pattern),l=l||/\w+/,r.keywords&&(r.keywords=U(r.keywords,e.case_insensitive)), +o.keywordPatternRe=n(l,!0), +s&&(r.begin||(r.begin=/\B|\b/),o.beginRe=n(o.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), +r.end&&(o.endRe=n(o.end)), +o.terminatorEnd=c(o.end)||"",r.endsWithParent&&s.terminatorEnd&&(o.terminatorEnd+=(r.end?"|":"")+s.terminatorEnd)), +r.illegal&&(o.illegalRe=n(r.illegal)), +r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((n=>a(e,{ +variants:null},n)))),e.cachedVariants?e.cachedVariants:X(e)?a(e,{ +starts:e.starts?a(e.starts):null +}):Object.isFrozen(e)?a(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{t(e,o) +})),r.starts&&t(r.starts,s),o.matcher=(e=>{const n=new i +;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" +}))),e.terminatorEnd&&n.addRule(e.terminatorEnd,{type:"end" +}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n})(o),o}(e)}function X(e){ +return!!e&&(e.endsWithParent||X(e.starts))}class V extends Error{ +constructor(e,n){super(e),this.name="HTMLInjectionError",this.html=n}} +const J=t,Y=a,ee=Symbol("nomatch"),ne=t=>{ +const a=Object.create(null),i=Object.create(null),r=[];let s=!0 +;const o="Could not find the language '{}', did you forget to load/include a language module?",c={ +disableAutodetect:!0,name:"Plain text",contains:[]};let p={ +ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, +languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", +cssSelector:"pre code",languages:null,__emitter:l};function _(e){ +return p.noHighlightRe.test(e)}function h(e,n,t){let a="",i="" +;"object"==typeof n?(a=e, +t=n.ignoreIllegals,i=n.language):(q("10.7.0","highlight(lang, code, ...args) has been deprecated."), +q("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), +i=e,a=n),void 0===t&&(t=!0);const r={code:a,language:i};x("before:highlight",r) +;const s=r.result?r.result:f(r.language,r.code,t) +;return s.code=r.code,x("after:highlight",s),s}function f(e,t,i,r){ +const l=Object.create(null);function c(){if(!x.keywords)return void S.addText(A) +;let e=0;x.keywordPatternRe.lastIndex=0;let n=x.keywordPatternRe.exec(A),t="" +;for(;n;){t+=A.substring(e,n.index) +;const i=w.case_insensitive?n[0].toLowerCase():n[0],r=(a=i,x.keywords[a]);if(r){ +const[e,a]=r +;if(S.addText(t),t="",l[i]=(l[i]||0)+1,l[i]<=7&&(C+=a),e.startsWith("_"))t+=n[0];else{ +const t=w.classNameAliases[e]||e;g(n[0],t)}}else t+=n[0] +;e=x.keywordPatternRe.lastIndex,n=x.keywordPatternRe.exec(A)}var a +;t+=A.substring(e),S.addText(t)}function d(){null!=x.subLanguage?(()=>{ +if(""===A)return;let e=null;if("string"==typeof x.subLanguage){ +if(!a[x.subLanguage])return void S.addText(A) +;e=f(x.subLanguage,A,!0,M[x.subLanguage]),M[x.subLanguage]=e._top +}else e=E(A,x.subLanguage.length?x.subLanguage:null) +;x.relevance>0&&(C+=e.relevance),S.__addSublanguage(e._emitter,e.language) +})():c(),A=""}function g(e,n){ +""!==e&&(S.startScope(n),S.addText(e),S.endScope())}function u(e,n){let t=1 +;const a=n.length-1;for(;t<=a;){if(!e._emit[t]){t++;continue} +const a=w.classNameAliases[e[t]]||e[t],i=n[t];a?g(i,a):(A=i,c(),A=""),t++}} +function b(e,n){ +return e.scope&&"string"==typeof e.scope&&S.openNode(w.classNameAliases[e.scope]||e.scope), +e.beginScope&&(e.beginScope._wrap?(g(A,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), +A=""):e.beginScope._multi&&(u(e.beginScope,n),A="")),x=Object.create(e,{parent:{ +value:x}}),x}function m(e,t,a){let i=((e,n)=>{const t=e&&e.exec(n) +;return t&&0===t.index})(e.endRe,a);if(i){if(e["on:end"]){const a=new n(e) +;e["on:end"](t,a),a.isMatchIgnored&&(i=!1)}if(i){ +for(;e.endsParent&&e.parent;)e=e.parent;return e}} +if(e.endsWithParent)return m(e.parent,t,a)}function _(e){ +return 0===x.matcher.regexIndex?(A+=e[0],1):(D=!0,0)}function h(e){ +const n=e[0],a=t.substring(e.index),i=m(x,e,a);if(!i)return ee;const r=x +;x.endScope&&x.endScope._wrap?(d(), +g(n,x.endScope._wrap)):x.endScope&&x.endScope._multi?(d(), +u(x.endScope,e)):r.skip?A+=n:(r.returnEnd||r.excludeEnd||(A+=n), +d(),r.excludeEnd&&(A=n));do{ +x.scope&&S.closeNode(),x.skip||x.subLanguage||(C+=x.relevance),x=x.parent +}while(x!==i.parent);return i.starts&&b(i.starts,e),r.returnEnd?0:n.length} +let y={};function N(a,r){const o=r&&r[0];if(A+=a,null==o)return d(),0 +;if("begin"===y.type&&"end"===r.type&&y.index===r.index&&""===o){ +if(A+=t.slice(r.index,r.index+1),!s){const n=Error(`0 width match regex (${e})`) +;throw n.languageName=e,n.badRule=y.rule,n}return 1} +if(y=r,"begin"===r.type)return(e=>{ +const t=e[0],a=e.rule,i=new n(a),r=[a.__beforeBegin,a["on:begin"]] +;for(const n of r)if(n&&(n(e,i),i.isMatchIgnored))return _(t) +;return a.skip?A+=t:(a.excludeBegin&&(A+=t), +d(),a.returnBegin||a.excludeBegin||(A=t)),b(a,e),a.returnBegin?0:t.length})(r) +;if("illegal"===r.type&&!i){ +const e=Error('Illegal lexeme "'+o+'" for mode "'+(x.scope||"")+'"') +;throw e.mode=x,e}if("end"===r.type){const e=h(r);if(e!==ee)return e} +if("illegal"===r.type&&""===o)return 1 +;if(R>1e5&&R>3*r.index)throw Error("potential infinite loop, way more iterations than matches") +;return A+=o,o.length}const w=v(e) +;if(!w)throw K(o.replace("{}",e)),Error('Unknown language: "'+e+'"') +;const O=Q(w);let k="",x=r||O;const M={},S=new p.__emitter(p);(()=>{const e=[] +;for(let n=x;n!==w;n=n.parent)n.scope&&e.unshift(n.scope) +;e.forEach((e=>S.openNode(e)))})();let A="",C=0,T=0,R=0,D=!1;try{ +if(w.__emitTokens)w.__emitTokens(t,S);else{for(x.matcher.considerAll();;){ +R++,D?D=!1:x.matcher.considerAll(),x.matcher.lastIndex=T +;const e=x.matcher.exec(t);if(!e)break;const n=N(t.substring(T,e.index),e) +;T=e.index+n}N(t.substring(T))}return S.finalize(),k=S.toHTML(),{language:e, +value:k,relevance:C,illegal:!1,_emitter:S,_top:x}}catch(n){ +if(n.message&&n.message.includes("Illegal"))return{language:e,value:J(t), +illegal:!0,relevance:0,_illegalBy:{message:n.message,index:T, +context:t.slice(T-100,T+100),mode:n.mode,resultSoFar:k},_emitter:S};if(s)return{ +language:e,value:J(t),illegal:!1,relevance:0,errorRaised:n,_emitter:S,_top:x} +;throw n}}function E(e,n){n=n||p.languages||Object.keys(a);const t=(e=>{ +const n={value:J(e),illegal:!1,relevance:0,_top:c,_emitter:new p.__emitter(p)} +;return n._emitter.addText(e),n})(e),i=n.filter(v).filter(k).map((n=>f(n,e,!1))) +;i.unshift(t);const r=i.sort(((e,n)=>{ +if(e.relevance!==n.relevance)return n.relevance-e.relevance +;if(e.language&&n.language){if(v(e.language).supersetOf===n.language)return 1 +;if(v(n.language).supersetOf===e.language)return-1}return 0})),[s,o]=r,l=s +;return l.secondBest=o,l}function y(e){let n=null;const t=(e=>{ +let n=e.className+" ";n+=e.parentNode?e.parentNode.className:"" +;const t=p.languageDetectRe.exec(n);if(t){const n=v(t[1]) +;return n||(H(o.replace("{}",t[1])), +H("Falling back to no-highlight mode for this block.",e)),n?t[1]:"no-highlight"} +return n.split(/\s+/).find((e=>_(e)||v(e)))})(e);if(_(t))return +;if(x("before:highlightElement",{el:e,language:t +}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) +;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), +console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), +console.warn("The element with unescaped HTML:"), +console.warn(e)),p.throwUnescapedHTML))throw new V("One of your code blocks includes unescaped HTML.",e.innerHTML) +;n=e;const a=n.textContent,r=t?h(a,{language:t,ignoreIllegals:!0}):E(a) +;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,n,t)=>{const a=n&&i[n]||t +;e.classList.add("hljs"),e.classList.add("language-"+a) +})(e,t,r.language),e.result={language:r.language,re:r.relevance, +relevance:r.relevance},r.secondBest&&(e.secondBest={ +language:r.secondBest.language,relevance:r.secondBest.relevance +}),x("after:highlightElement",{el:e,result:r,text:a})}let N=!1;function w(){ +"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(y):N=!0 +}function v(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} +function O(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ +i[e.toLowerCase()]=n}))}function k(e){const n=v(e) +;return n&&!n.disableAutodetect}function x(e,n){const t=e;r.forEach((e=>{ +e[t]&&e[t](n)}))} +"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{ +N&&w()}),!1),Object.assign(t,{highlight:h,highlightAuto:E,highlightAll:w, +highlightElement:y, +highlightBlock:e=>(q("10.7.0","highlightBlock will be removed entirely in v12.0"), +q("10.7.0","Please use highlightElement now."),y(e)),configure:e=>{p=Y(p,e)}, +initHighlighting:()=>{ +w(),q("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, +initHighlightingOnLoad:()=>{ +w(),q("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") +},registerLanguage:(e,n)=>{let i=null;try{i=n(t)}catch(n){ +if(K("Language definition for '{}' could not be registered.".replace("{}",e)), +!s)throw n;K(n),i=c} +i.name||(i.name=e),a[e]=i,i.rawDefinition=n.bind(null,t),i.aliases&&O(i.aliases,{ +languageName:e})},unregisterLanguage:e=>{delete a[e] +;for(const n of Object.keys(i))i[n]===e&&delete i[n]}, +listLanguages:()=>Object.keys(a),getLanguage:v,registerAliases:O, +autoDetection:k,inherit:Y,addPlugin:e=>{(e=>{ +e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=n=>{ +e["before:highlightBlock"](Object.assign({block:n.el},n)) +}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=n=>{ +e["after:highlightBlock"](Object.assign({block:n.el},n))})})(e),r.push(e)}, +removePlugin:e=>{const n=r.indexOf(e);-1!==n&&r.splice(n,1)}}),t.debugMode=()=>{ +s=!1},t.safeMode=()=>{s=!0},t.versionString="11.9.0",t.regex={concat:b, +lookahead:d,either:m,optional:u,anyNumberOfTimes:g} +;for(const n in C)"object"==typeof C[n]&&e(C[n]);return Object.assign(t,C),t +},te=ne({});te.newInstance=()=>ne({});var ae=te;const ie=e=>({IMPORTANT:{ +scope:"meta",begin:"!important"},BLOCK_COMMENT:e.C_BLOCK_COMMENT_MODE,HEXCOLOR:{ +scope:"number",begin:/#(([0-9a-fA-F]{3,4})|(([0-9a-fA-F]{2}){3,4}))\b/}, +FUNCTION_DISPATCH:{className:"built_in",begin:/[\w-]+(?=\()/}, +ATTRIBUTE_SELECTOR_MODE:{scope:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", +contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},CSS_NUMBER_MODE:{ +scope:"number", +begin:e.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", +relevance:0},CSS_VARIABLE:{className:"attr",begin:/--[A-Za-z_][A-Za-z0-9_-]*/} +}),re=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","main","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],se=["any-hover","any-pointer","aspect-ratio","color","color-gamut","color-index","device-aspect-ratio","device-height","device-width","display-mode","forced-colors","grid","height","hover","inverted-colors","monochrome","orientation","overflow-block","overflow-inline","pointer","prefers-color-scheme","prefers-contrast","prefers-reduced-motion","prefers-reduced-transparency","resolution","scan","scripting","update","width","min-width","max-width","min-height","max-height"],oe=["active","any-link","blank","checked","current","default","defined","dir","disabled","drop","empty","enabled","first","first-child","first-of-type","fullscreen","future","focus","focus-visible","focus-within","has","host","host-context","hover","indeterminate","in-range","invalid","is","lang","last-child","last-of-type","left","link","local-link","not","nth-child","nth-col","nth-last-child","nth-last-col","nth-last-of-type","nth-of-type","only-child","only-of-type","optional","out-of-range","past","placeholder-shown","read-only","read-write","required","right","root","scope","target","target-within","user-invalid","valid","visited","where"],le=["after","backdrop","before","cue","cue-region","first-letter","first-line","grammar-error","marker","part","placeholder","selection","slotted","spelling-error"],ce=["align-content","align-items","align-self","all","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","backface-visibility","background","background-attachment","background-blend-mode","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","block-size","border","border-block","border-block-color","border-block-end","border-block-end-color","border-block-end-style","border-block-end-width","border-block-start","border-block-start-color","border-block-start-style","border-block-start-width","border-block-style","border-block-width","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-inline","border-inline-color","border-inline-end","border-inline-end-color","border-inline-end-style","border-inline-end-width","border-inline-start","border-inline-start-color","border-inline-start-style","border-inline-start-width","border-inline-style","border-inline-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","caret-color","clear","clip","clip-path","clip-rule","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","contain","content","content-visibility","counter-increment","counter-reset","cue","cue-after","cue-before","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","flow","font","font-display","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-smoothing","font-stretch","font-style","font-synthesis","font-variant","font-variant-caps","font-variant-east-asian","font-variant-ligatures","font-variant-numeric","font-variant-position","font-variation-settings","font-weight","gap","glyph-orientation-vertical","grid","grid-area","grid-auto-columns","grid-auto-flow","grid-auto-rows","grid-column","grid-column-end","grid-column-start","grid-gap","grid-row","grid-row-end","grid-row-start","grid-template","grid-template-areas","grid-template-columns","grid-template-rows","hanging-punctuation","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inline-size","isolation","justify-content","left","letter-spacing","line-break","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-block","margin-block-end","margin-block-start","margin-bottom","margin-inline","margin-inline-end","margin-inline-start","margin-left","margin-right","margin-top","marks","mask","mask-border","mask-border-mode","mask-border-outset","mask-border-repeat","mask-border-slice","mask-border-source","mask-border-width","mask-clip","mask-composite","mask-image","mask-mode","mask-origin","mask-position","mask-repeat","mask-size","mask-type","max-block-size","max-height","max-inline-size","max-width","min-block-size","min-height","min-inline-size","min-width","mix-blend-mode","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-block","padding-block-end","padding-block-start","padding-bottom","padding-inline","padding-inline-end","padding-inline-start","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","pause","pause-after","pause-before","perspective","perspective-origin","pointer-events","position","quotes","resize","rest","rest-after","rest-before","right","row-gap","scroll-margin","scroll-margin-block","scroll-margin-block-end","scroll-margin-block-start","scroll-margin-bottom","scroll-margin-inline","scroll-margin-inline-end","scroll-margin-inline-start","scroll-margin-left","scroll-margin-right","scroll-margin-top","scroll-padding","scroll-padding-block","scroll-padding-block-end","scroll-padding-block-start","scroll-padding-bottom","scroll-padding-inline","scroll-padding-inline-end","scroll-padding-inline-start","scroll-padding-left","scroll-padding-right","scroll-padding-top","scroll-snap-align","scroll-snap-stop","scroll-snap-type","scrollbar-color","scrollbar-gutter","scrollbar-width","shape-image-threshold","shape-margin","shape-outside","speak","speak-as","src","tab-size","table-layout","text-align","text-align-all","text-align-last","text-combine-upright","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-emphasis","text-emphasis-color","text-emphasis-position","text-emphasis-style","text-indent","text-justify","text-orientation","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-box","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","voice-balance","voice-duration","voice-family","voice-pitch","voice-range","voice-rate","voice-stress","voice-volume","white-space","widows","width","will-change","word-break","word-spacing","word-wrap","writing-mode","z-index"].reverse(),de=oe.concat(le) +;var ge="[0-9](_*[0-9])*",ue=`\\.(${ge})`,be="[0-9a-fA-F](_*[0-9a-fA-F])*",me={ +className:"number",variants:[{ +begin:`(\\b(${ge})((${ue})|\\.)?|(${ue}))[eE][+-]?(${ge})[fFdD]?\\b`},{ +begin:`\\b(${ge})((${ue})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{ +begin:`(${ue})[fFdD]?\\b`},{begin:`\\b(${ge})[fFdD]\\b`},{ +begin:`\\b0[xX]((${be})\\.?|(${be})?\\.(${be}))[pP][+-]?(${ge})[fFdD]?\\b`},{ +begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${be})[lL]?\\b`},{ +begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], +relevance:0};function pe(e,n,t){return-1===t?"":e.replace(n,(a=>pe(e,n,t-1)))} +const _e="[A-Za-z$_][0-9A-Za-z$_]*",he=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],fe=["true","false","null","undefined","NaN","Infinity"],Ee=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],ye=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],Ne=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],we=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],ve=[].concat(Ne,Ee,ye) +;function Oe(e){const n=e.regex,t=_e,a={begin:/<[A-Za-z0-9\\._:-]+/, +end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ +const t=e[0].length+e.index,a=e.input[t] +;if("<"===a||","===a)return void n.ignoreMatch();let i +;">"===a&&(((e,{after:n})=>{const t="",M={ +match:[/const|var|let/,/\s+/,t,/\s*/,/=\s*/,/(async\s*)?/,n.lookahead(x)], +keywords:"async",className:{1:"keyword",3:"title.function"},contains:[f]} +;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:i,exports:{ +PARAMS_CONTAINS:h,CLASS_REFERENCE:y},illegal:/#(?![$_A-z])/, +contains:[e.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ +label:"use_strict",className:"meta",relevance:10, +begin:/^\s*['"]use (strict|asm)['"]/ +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,d,g,u,b,m,{match:/\$\d+/},l,y,{ +className:"attr",begin:t+n.lookahead(":"),relevance:0},M,{ +begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", +keywords:"return throw case",relevance:0,contains:[m,e.REGEXP_MODE,{ +className:"function",begin:x,returnBegin:!0,end:"\\s*=>",contains:[{ +className:"params",variants:[{begin:e.UNDERSCORE_IDENT_RE,relevance:0},{ +className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0, +excludeEnd:!0,keywords:i,contains:h}]}]},{begin:/,/,relevance:0},{match:/\s+/, +relevance:0},{variants:[{begin:"<>",end:""},{ +match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:a.begin, +"on:begin":a.isTrulyOpeningTag,end:a.end}],subLanguage:"xml",contains:[{ +begin:a.begin,end:a.end,skip:!0,contains:["self"]}]}]},N,{ +beginKeywords:"while if switch catch for"},{ +begin:"\\b(?!function)"+e.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", +returnBegin:!0,label:"func.def",contains:[f,e.inherit(e.TITLE_MODE,{begin:t, +className:"title.function"})]},{match:/\.\.\./,relevance:0},O,{match:"\\$"+t, +relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, +contains:[f]},w,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, +className:"variable.constant"},E,k,{match:/\$[(.]/}]}} +const ke=e=>b(/\b/,e,/\w$/.test(e)?/\b/:/\B/),xe=["Protocol","Type"].map(ke),Me=["init","self"].map(ke),Se=["Any","Self"],Ae=["actor","any","associatedtype","async","await",/as\?/,/as!/,"as","borrowing","break","case","catch","class","consume","consuming","continue","convenience","copy","default","defer","deinit","didSet","distributed","do","dynamic","each","else","enum","extension","fallthrough",/fileprivate\(set\)/,"fileprivate","final","for","func","get","guard","if","import","indirect","infix",/init\?/,/init!/,"inout",/internal\(set\)/,"internal","in","is","isolated","nonisolated","lazy","let","macro","mutating","nonmutating",/open\(set\)/,"open","operator","optional","override","postfix","precedencegroup","prefix",/private\(set\)/,"private","protocol",/public\(set\)/,"public","repeat","required","rethrows","return","set","some","static","struct","subscript","super","switch","throws","throw",/try\?/,/try!/,"try","typealias",/unowned\(safe\)/,/unowned\(unsafe\)/,"unowned","var","weak","where","while","willSet"],Ce=["false","nil","true"],Te=["assignment","associativity","higherThan","left","lowerThan","none","right"],Re=["#colorLiteral","#column","#dsohandle","#else","#elseif","#endif","#error","#file","#fileID","#fileLiteral","#filePath","#function","#if","#imageLiteral","#keyPath","#line","#selector","#sourceLocation","#warning"],De=["abs","all","any","assert","assertionFailure","debugPrint","dump","fatalError","getVaList","isKnownUniquelyReferenced","max","min","numericCast","pointwiseMax","pointwiseMin","precondition","preconditionFailure","print","readLine","repeatElement","sequence","stride","swap","swift_unboxFromSwiftValueWithType","transcode","type","unsafeBitCast","unsafeDowncast","withExtendedLifetime","withUnsafeMutablePointer","withUnsafePointer","withVaList","withoutActuallyEscaping","zip"],Ie=m(/[/=\-+!*%<>&|^~?]/,/[\u00A1-\u00A7]/,/[\u00A9\u00AB]/,/[\u00AC\u00AE]/,/[\u00B0\u00B1]/,/[\u00B6\u00BB\u00BF\u00D7\u00F7]/,/[\u2016-\u2017]/,/[\u2020-\u2027]/,/[\u2030-\u203E]/,/[\u2041-\u2053]/,/[\u2055-\u205E]/,/[\u2190-\u23FF]/,/[\u2500-\u2775]/,/[\u2794-\u2BFF]/,/[\u2E00-\u2E7F]/,/[\u3001-\u3003]/,/[\u3008-\u3020]/,/[\u3030]/),Le=m(Ie,/[\u0300-\u036F]/,/[\u1DC0-\u1DFF]/,/[\u20D0-\u20FF]/,/[\uFE00-\uFE0F]/,/[\uFE20-\uFE2F]/),Be=b(Ie,Le,"*"),$e=m(/[a-zA-Z_]/,/[\u00A8\u00AA\u00AD\u00AF\u00B2-\u00B5\u00B7-\u00BA]/,/[\u00BC-\u00BE\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF]/,/[\u0100-\u02FF\u0370-\u167F\u1681-\u180D\u180F-\u1DBF]/,/[\u1E00-\u1FFF]/,/[\u200B-\u200D\u202A-\u202E\u203F-\u2040\u2054\u2060-\u206F]/,/[\u2070-\u20CF\u2100-\u218F\u2460-\u24FF\u2776-\u2793]/,/[\u2C00-\u2DFF\u2E80-\u2FFF]/,/[\u3004-\u3007\u3021-\u302F\u3031-\u303F\u3040-\uD7FF]/,/[\uF900-\uFD3D\uFD40-\uFDCF\uFDF0-\uFE1F\uFE30-\uFE44]/,/[\uFE47-\uFEFE\uFF00-\uFFFD]/),ze=m($e,/\d/,/[\u0300-\u036F\u1DC0-\u1DFF\u20D0-\u20FF\uFE20-\uFE2F]/),Fe=b($e,ze,"*"),Ue=b(/[A-Z]/,ze,"*"),je=["attached","autoclosure",b(/convention\(/,m("swift","block","c"),/\)/),"discardableResult","dynamicCallable","dynamicMemberLookup","escaping","freestanding","frozen","GKInspectable","IBAction","IBDesignable","IBInspectable","IBOutlet","IBSegueAction","inlinable","main","nonobjc","NSApplicationMain","NSCopying","NSManaged",b(/objc\(/,Fe,/\)/),"objc","objcMembers","propertyWrapper","requires_stored_property_inits","resultBuilder","Sendable","testable","UIApplicationMain","unchecked","unknown","usableFromInline","warn_unqualified_access"],Pe=["iOS","iOSApplicationExtension","macOS","macOSApplicationExtension","macCatalyst","macCatalystApplicationExtension","watchOS","watchOSApplicationExtension","tvOS","tvOSApplicationExtension","swift"] +;var Ke=Object.freeze({__proto__:null,grmr_bash:e=>{const n=e.regex,t={},a={ +begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[t]}]} +;Object.assign(t,{className:"variable",variants:[{ +begin:n.concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},a]});const i={ +className:"subst",begin:/\$\(/,end:/\)/,contains:[e.BACKSLASH_ESCAPE]},r={ +begin:/<<-?\s*(?=\w+)/,starts:{contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/, +end:/(\w+)/,className:"string"})]}},s={className:"string",begin:/"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,t,i]};i.contains.push(s);const o={begin:/\$?\(\(/, +end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,t] +},l=e.SHEBANG({binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10 +}),c={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, +contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ +name:"Bash",aliases:["sh"],keywords:{$pattern:/\b[a-z][a-z0-9._-]+\b/, +keyword:["if","then","else","elif","fi","for","while","until","in","do","done","case","esac","function","select"], +literal:["true","false"], +built_in:["break","cd","continue","eval","exec","exit","export","getopts","hash","pwd","readonly","return","shift","test","times","trap","umask","unset","alias","bind","builtin","caller","command","declare","echo","enable","help","let","local","logout","mapfile","printf","read","readarray","source","type","typeset","ulimit","unalias","set","shopt","autoload","bg","bindkey","bye","cap","chdir","clone","comparguments","compcall","compctl","compdescribe","compfiles","compgroups","compquote","comptags","comptry","compvalues","dirs","disable","disown","echotc","echoti","emulate","fc","fg","float","functions","getcap","getln","history","integer","jobs","kill","limit","log","noglob","popd","print","pushd","pushln","rehash","sched","setcap","setopt","stat","suspend","ttyctl","unfunction","unhash","unlimit","unsetopt","vared","wait","whence","where","which","zcompile","zformat","zftp","zle","zmodload","zparseopts","zprof","zpty","zregexparse","zsocket","zstyle","ztcp","chcon","chgrp","chown","chmod","cp","dd","df","dir","dircolors","ln","ls","mkdir","mkfifo","mknod","mktemp","mv","realpath","rm","rmdir","shred","sync","touch","truncate","vdir","b2sum","base32","base64","cat","cksum","comm","csplit","cut","expand","fmt","fold","head","join","md5sum","nl","numfmt","od","paste","ptx","pr","sha1sum","sha224sum","sha256sum","sha384sum","sha512sum","shuf","sort","split","sum","tac","tail","tr","tsort","unexpand","uniq","wc","arch","basename","chroot","date","dirname","du","echo","env","expr","factor","groups","hostid","id","link","logname","nice","nohup","nproc","pathchk","pinky","printenv","printf","pwd","readlink","runcon","seq","sleep","stat","stdbuf","stty","tee","test","timeout","tty","uname","unlink","uptime","users","who","whoami","yes"] +},contains:[l,e.SHEBANG(),c,o,e.HASH_COMMENT_MODE,r,{match:/(\/[a-z._-]+)+/},s,{ +match:/\\"/},{className:"string",begin:/'/,end:/'/},{match:/\\'/},t]}}, +grmr_c:e=>{const n=e.regex,t=e.COMMENT("//","$",{contains:[{begin:/\\\n/}] +}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ +className:"type",variants:[{begin:"\\b[a-z\\d_]*_t\\b"},{ +match:/\batomic_[a-z]{3,6}\b/}]},o={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ +className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 +},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ +keyword:["asm","auto","break","case","continue","default","do","else","enum","extern","for","fortran","goto","if","inline","register","restrict","return","sizeof","struct","switch","typedef","union","volatile","while","_Alignas","_Alignof","_Atomic","_Generic","_Noreturn","_Static_assert","_Thread_local","alignas","alignof","noreturn","static_assert","thread_local","_Pragma"], +type:["float","double","signed","unsigned","int","short","long","char","void","_Bool","_Complex","_Imaginary","_Decimal32","_Decimal64","_Decimal128","const","static","complex","bool","imaginary"], +literal:"true false NULL", +built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr" +},b=[c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],m={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:u,contains:b.concat([{begin:/\(/,end:/\)/,keywords:u, +contains:b.concat(["self"]),relevance:0}]),relevance:0},p={ +begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ +begin:g,returnBegin:!0,contains:[e.inherit(d,{className:"title.function"})], +relevance:0},{relevance:0,match:/,/},{className:"params",begin:/\(/,end:/\)/, +keywords:u,relevance:0,contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/, +end:/\)/,keywords:u,relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s] +}]},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C",aliases:["h"],keywords:u, +disableAutodetect:!0,illegal:"=]/,contains:[{ +beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{preprocessor:c, +strings:o,keywords:u}}},grmr_cpp:e=>{const n=e.regex,t=e.COMMENT("//","$",{ +contains:[{begin:/\\\n/}] +}),a="decltype\\(auto\\)",i="[a-zA-Z_]\\w*::",r="(?!struct)("+a+"|"+n.optional(i)+"[a-zA-Z_]\\w*"+n.optional("<[^<>]+>")+")",s={ +className:"type",begin:"\\b[a-z\\d_]*_t\\b"},o={className:"string",variants:[{ +begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{ +begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", +end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ +begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},l={ +className:"number",variants:[{begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)" +},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ +keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" +},contains:[{begin:/\\\n/,relevance:0},e.inherit(o,{className:"string"}),{ +className:"string",begin:/<.*?>/},t,e.C_BLOCK_COMMENT_MODE]},d={ +className:"title",begin:n.optional(i)+e.IDENT_RE,relevance:0 +},g=n.optional(i)+e.IDENT_RE+"\\s*\\(",u={ +type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"], +keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"], +literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"], +_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"] +},b={className:"function.dispatch",relevance:0,keywords:{ +_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"] +}, +begin:n.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,n.lookahead(/(<[^<>]+>|)\s*\(/)) +},m=[b,c,s,t,e.C_BLOCK_COMMENT_MODE,l,o],p={variants:[{begin:/=/,end:/;/},{ +begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}], +keywords:u,contains:m.concat([{begin:/\(/,end:/\)/,keywords:u, +contains:m.concat(["self"]),relevance:0}]),relevance:0},_={className:"function", +begin:"("+r+"[\\*&\\s]+)+"+g,returnBegin:!0,end:/[{;=]/,excludeEnd:!0, +keywords:u,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:a,keywords:u,relevance:0},{ +begin:g,returnBegin:!0,contains:[d],relevance:0},{begin:/::/,relevance:0},{ +begin:/:/,endsWithParent:!0,contains:[o,l]},{relevance:0,match:/,/},{ +className:"params",begin:/\(/,end:/\)/,keywords:u,relevance:0, +contains:[t,e.C_BLOCK_COMMENT_MODE,o,l,s,{begin:/\(/,end:/\)/,keywords:u, +relevance:0,contains:["self",t,e.C_BLOCK_COMMENT_MODE,o,l,s]}] +},s,t,e.C_BLOCK_COMMENT_MODE,c]};return{name:"C++", +aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:u,illegal:"",keywords:u,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:u},{ +match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/], +className:{1:"keyword",3:"title.class"}}])}},grmr_csharp:e=>{const n={ +keyword:["abstract","as","base","break","case","catch","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","scoped","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value|0","var","when","where","with","yield"]), +built_in:["bool","byte","char","decimal","delegate","double","dynamic","enum","float","int","long","nint","nuint","object","sbyte","short","string","ulong","uint","ushort"], +literal:["default","false","null","true"]},t=e.inherit(e.TITLE_MODE,{ +begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ +begin:"\\b(0b[01']+)"},{ +begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ +begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" +}],relevance:0},i={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] +},r=e.inherit(i,{illegal:/\n/}),s={className:"subst",begin:/\{/,end:/\}/, +keywords:n},o=e.inherit(s,{illegal:/\n/}),l={className:"string",begin:/\$"/, +end:'"',illegal:/\n/,contains:[{begin:/\{\{/},{begin:/\}\}/ +},e.BACKSLASH_ESCAPE,o]},c={className:"string",begin:/\$@"/,end:'"',contains:[{ +begin:/\{\{/},{begin:/\}\}/},{begin:'""'},s]},d=e.inherit(c,{illegal:/\n/, +contains:[{begin:/\{\{/},{begin:/\}\}/},{begin:'""'},o]}) +;s.contains=[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], +o.contains=[d,l,r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ +illegal:/\n/})];const g={variants:[c,l,i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] +},u={begin:"<",end:">",contains:[{beginKeywords:"in out"},t] +},b=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",m={ +begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], +keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, +contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ +begin:"\x3c!--|--\x3e"},{begin:""}]}] +}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", +end:"$",keywords:{ +keyword:"if else elif endif define undef warning error line region endregion pragma checksum" +}},g,a,{beginKeywords:"class interface",relevance:0,end:/[{;=]/, +illegal:/[^\s:,]/,contains:[{beginKeywords:"where class" +},t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", +relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"record",relevance:0,end:/[{;=]/,illegal:/[^\s:]/, +contains:[t,u,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", +begin:"^\\s*\\[(?=[\\w])",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ +className:"string",begin:/"/,end:/"/}]},{ +beginKeywords:"new return throw await else",relevance:0},{className:"function", +begin:"("+b+"\\s+)+"+e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ +beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial", +relevance:0},{begin:e.IDENT_RE+"\\s*(<[^=]+>\\s*)?\\(",returnBegin:!0, +contains:[e.TITLE_MODE,u],relevance:0},{match:/\(\)/},{className:"params", +begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, +contains:[g,a,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},m]}},grmr_css:e=>{ +const n=e.regex,t=ie(e),a=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE];return{ +name:"CSS",case_insensitive:!0,illegal:/[=|'\$]/,keywords:{ +keyframePosition:"from to"},classNameAliases:{keyframePosition:"selector-tag"}, +contains:[t.BLOCK_COMMENT,{begin:/-(webkit|moz|ms|o)-(?=[a-z])/ +},t.CSS_NUMBER_MODE,{className:"selector-id",begin:/#[A-Za-z0-9_-]+/,relevance:0 +},{className:"selector-class",begin:"\\.[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0 +},t.ATTRIBUTE_SELECTOR_MODE,{className:"selector-pseudo",variants:[{ +begin:":("+oe.join("|")+")"},{begin:":(:)?("+le.join("|")+")"}] +},t.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b"},{ +begin:/:/,end:/[;}{]/, +contains:[t.BLOCK_COMMENT,t.HEXCOLOR,t.IMPORTANT,t.CSS_NUMBER_MODE,...a,{ +begin:/(url|data-uri)\(/,end:/\)/,relevance:0,keywords:{built_in:"url data-uri" +},contains:[...a,{className:"string",begin:/[^)]/,endsWithParent:!0, +excludeEnd:!0}]},t.FUNCTION_DISPATCH]},{begin:n.lookahead(/@/),end:"[{;]", +relevance:0,illegal:/:/,contains:[{className:"keyword",begin:/@-?\w[\w]*(-\w+)*/ +},{begin:/\s/,endsWithParent:!0,excludeEnd:!0,relevance:0,keywords:{ +$pattern:/[a-z-]+/,keyword:"and or not only",attribute:se.join(" ")},contains:[{ +begin:/[a-z-]+(?=:)/,className:"attribute"},...a,t.CSS_NUMBER_MODE]}]},{ +className:"selector-tag",begin:"\\b("+re.join("|")+")\\b"}]}},grmr_diff:e=>{ +const n=e.regex;return{name:"Diff",aliases:["patch"],contains:[{ +className:"meta",relevance:10, +match:n.either(/^@@ +-\d+,\d+ +\+\d+,\d+ +@@/,/^\*\*\* +\d+,\d+ +\*\*\*\*$/,/^--- +\d+,\d+ +----$/) +},{className:"comment",variants:[{ +begin:n.either(/Index: /,/^index/,/={3,}/,/^-{3}/,/^\*{3} /,/^\+{3}/,/^diff --git/), +end:/$/},{match:/^\*{15}$/}]},{className:"addition",begin:/^\+/,end:/$/},{ +className:"deletion",begin:/^-/,end:/$/},{className:"addition",begin:/^!/, +end:/$/}]}},grmr_go:e=>{const n={ +keyword:["break","case","chan","const","continue","default","defer","else","fallthrough","for","func","go","goto","if","import","interface","map","package","range","return","select","struct","switch","type","var"], +type:["bool","byte","complex64","complex128","error","float32","float64","int8","int16","int32","int64","string","uint8","uint16","uint32","uint64","int","uint","uintptr","rune"], +literal:["true","false","iota","nil"], +built_in:["append","cap","close","complex","copy","imag","len","make","new","panic","print","println","real","recover","delete"] +};return{name:"Go",aliases:["golang"],keywords:n,illegal:"{const n=e.regex;return{name:"GraphQL",aliases:["gql"], +case_insensitive:!0,disableAutodetect:!1,keywords:{ +keyword:["query","mutation","subscription","type","input","schema","directive","interface","union","scalar","fragment","enum","on"], +literal:["true","false","null"]}, +contains:[e.HASH_COMMENT_MODE,e.QUOTE_STRING_MODE,e.NUMBER_MODE,{ +scope:"punctuation",match:/[.]{3}/,relevance:0},{scope:"punctuation", +begin:/[\!\(\)\:\=\[\]\{\|\}]{1}/,relevance:0},{scope:"variable",begin:/\$/, +end:/\W/,excludeEnd:!0,relevance:0},{scope:"meta",match:/@\w+/,excludeEnd:!0},{ +scope:"symbol",begin:n.concat(/[_A-Za-z][_0-9A-Za-z]*/,n.lookahead(/\s*:/)), +relevance:0}],illegal:[/[;<']/,/BEGIN/]}},grmr_ini:e=>{const n=e.regex,t={ +className:"number",relevance:0,variants:[{begin:/([+-]+)?[\d]+_[\d_]+/},{ +begin:e.NUMBER_RE}]},a=e.COMMENT();a.variants=[{begin:/;/,end:/$/},{begin:/#/, +end:/$/}];const i={className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{ +begin:/\$\{(.*?)\}/}]},r={className:"literal", +begin:/\bon|off|true|false|yes|no\b/},s={className:"string", +contains:[e.BACKSLASH_ESCAPE],variants:[{begin:"'''",end:"'''",relevance:10},{ +begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"'},{begin:"'",end:"'"}] +},o={begin:/\[/,end:/\]/,contains:[a,r,i,s,t,"self"],relevance:0 +},l=n.either(/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/);return{ +name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, +contains:[a,{className:"section",begin:/\[+/,end:/\]+/},{ +begin:n.concat(l,"(\\s*\\.\\s*",l,")*",n.lookahead(/\s*=\s*[^#\s]/)), +className:"attr",starts:{end:/$/,contains:[a,o,r,i,s,t]}}]}},grmr_java:e=>{ +const n=e.regex,t="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",a=t+pe("(?:<"+t+"~~~(?:\\s*,\\s*"+t+"~~~)*>)?",/~~~/g,2),i={ +keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits"], +literal:["false","true","null"], +type:["char","boolean","long","float","int","byte","short","double"], +built_in:["super","this"]},r={className:"meta",begin:"@"+t,contains:[{ +begin:/\(/,end:/\)/,contains:["self"]}]},s={className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} +;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, +relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ +begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, +className:"string",contains:[e.BACKSLASH_ESCAPE] +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ +match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,t],className:{ +1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ +begin:[n.concat(/(?!else)/,t),/\s+/,t,/\s+/,/=(?!=)/],className:{1:"type", +3:"variable",5:"operator"}},{begin:[/record/,/\s+/,t],className:{1:"keyword", +3:"title.class"},contains:[s,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ +beginKeywords:"new throw return else",relevance:0},{ +begin:["(?:"+a+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ +2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, +end:/\)/,keywords:i,relevance:0, +contains:[r,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,me,e.C_BLOCK_COMMENT_MODE] +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},me,r]}},grmr_javascript:Oe, +grmr_json:e=>{const n=["true","false","null"],t={scope:"literal", +beginKeywords:n.join(" ")};return{name:"JSON",keywords:{literal:n},contains:[{ +className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{ +match:/[{}[\],:]/,className:"punctuation",relevance:0 +},e.QUOTE_STRING_MODE,t,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], +illegal:"\\S"}},grmr_kotlin:e=>{const n={ +keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", +built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", +literal:"true false null"},t={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" +},a={className:"subst",begin:/\$\{/,end:/\}/,contains:[e.C_NUMBER_MODE]},i={ +className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},r={className:"string", +variants:[{begin:'"""',end:'"""(?=[^"])',contains:[i,a]},{begin:"'",end:"'", +illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, +contains:[e.BACKSLASH_ESCAPE,i,a]}]};a.contains.push(r);const s={ +className:"meta", +begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" +},o={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, +end:/\)/,contains:[e.inherit(r,{className:"string"}),"self"]}] +},l=me,c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),d={ +variants:[{className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/, +contains:[]}]},g=d;return g.variants[1].contains=[d],d.variants[1].contains=[g], +{name:"Kotlin",aliases:["kt","kts"],keywords:n, +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{className:"doctag", +begin:"@[A-Za-z]+"}]}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", +begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", +begin:/@\w+/}]}},t,s,o,{className:"function",beginKeywords:"fun",end:"[(]|$", +returnBegin:!0,excludeEnd:!0,keywords:n,relevance:5,contains:[{ +begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, +contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, +keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, +endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, +endsWithParent:!0,contains:[d,e.C_LINE_COMMENT_MODE,c],relevance:0 +},e.C_LINE_COMMENT_MODE,c,s,o,r,e.C_NUMBER_MODE]},c]},{ +begin:[/class|interface|trait/,/\s+/,e.UNDERSCORE_IDENT_RE],beginScope:{ +3:"title.class"},keywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, +illegal:"extends implements",contains:[{ +beginKeywords:"public protected internal private constructor" +},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, +excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,){\s]|$/, +excludeBegin:!0,returnEnd:!0},s,o]},r,{className:"meta",begin:"^#!/usr/bin/env", +end:"$",illegal:"\n"},l]}},grmr_less:e=>{ +const n=ie(e),t=de,a="[\\w-]+",i="("+a+"|@\\{"+a+"\\})",r=[],s=[],o=e=>({ +className:"string",begin:"~?"+e+".*?"+e}),l=(e,n,t)=>({className:e,begin:n, +relevance:t}),c={$pattern:/[a-z-]+/,keyword:"and or not only", +attribute:se.join(" ")},d={begin:"\\(",end:"\\)",contains:s,keywords:c, +relevance:0} +;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,o("'"),o('"'),n.CSS_NUMBER_MODE,{ +begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", +excludeEnd:!0} +},n.HEXCOLOR,d,l("variable","@@?"+a,10),l("variable","@\\{"+a+"\\}"),l("built_in","~?`[^`]*?`"),{ +className:"attribute",begin:a+"\\s*:",end:":",returnBegin:!0,excludeEnd:!0 +},n.IMPORTANT,{beginKeywords:"and not"},n.FUNCTION_DISPATCH);const g=s.concat({ +begin:/\{/,end:/\}/,contains:r}),u={beginKeywords:"when",endsWithParent:!0, +contains:[{beginKeywords:"and not"}].concat(s)},b={begin:i+"\\s*:", +returnBegin:!0,end:/[;}]/,relevance:0,contains:[{begin:/-(webkit|moz|ms|o)-/ +},n.CSS_VARIABLE,{className:"attribute",begin:"\\b("+ce.join("|")+")\\b", +end:/(?=:)/,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s}}] +},m={className:"keyword", +begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", +starts:{end:"[;{}]",keywords:c,returnEnd:!0,contains:s,relevance:0}},p={ +className:"variable",variants:[{begin:"@"+a+"\\s*:",relevance:15},{begin:"@"+a +}],starts:{end:"[;}]",returnEnd:!0,contains:g}},_={variants:[{ +begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:i,end:/\{/}],returnBegin:!0, +returnEnd:!0,illegal:"[<='$\"]",relevance:0, +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,u,l("keyword","all\\b"),l("variable","@\\{"+a+"\\}"),{ +begin:"\\b("+re.join("|")+")\\b",className:"selector-tag" +},n.CSS_NUMBER_MODE,l("selector-tag",i,0),l("selector-id","#"+i),l("selector-class","\\."+i,0),l("selector-tag","&",0),n.ATTRIBUTE_SELECTOR_MODE,{ +className:"selector-pseudo",begin:":("+oe.join("|")+")"},{ +className:"selector-pseudo",begin:":(:)?("+le.join("|")+")"},{begin:/\(/, +end:/\)/,relevance:0,contains:g},{begin:"!important"},n.FUNCTION_DISPATCH]},h={ +begin:a+":(:)?"+`(${t.join("|")})`,returnBegin:!0,contains:[_]} +;return r.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,m,p,h,b,_,u,n.FUNCTION_DISPATCH), +{name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:r}}, +grmr_lua:e=>{const n="\\[=*\\[",t="\\]=*\\]",a={begin:n,end:t,contains:["self"] +},i=[e.COMMENT("--(?!"+n+")","$"),e.COMMENT("--"+n,t,{contains:[a],relevance:10 +})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, +literal:"true false nil", +keyword:"and break do else elseif end for goto if in local not or repeat return then until while", +built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" +},contains:i.concat([{className:"function",beginKeywords:"function",end:"\\)", +contains:[e.inherit(e.TITLE_MODE,{ +begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", +begin:"\\(",endsWithParent:!0,contains:i}].concat(i) +},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", +begin:n,end:t,contains:[a],relevance:5}])}},grmr_makefile:e=>{const n={ +className:"variable",variants:[{begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\$[@%{ +const n={begin:/<\/?[A-Za-z_]/,end:">",subLanguage:"xml",relevance:0},t={ +variants:[{begin:/\[.+?\]\[.*?\]/,relevance:0},{ +begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, +relevance:2},{ +begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), +relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ +begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ +},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, +returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", +excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", +end:"\\]",excludeBegin:!0,excludeEnd:!0}]},a={className:"strong",contains:[], +variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] +},i={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ +begin:/_(?![_\s])/,end:/_/,relevance:0}]},r=e.inherit(a,{contains:[] +}),s=e.inherit(i,{contains:[]});a.contains.push(s),i.contains.push(r) +;let o=[n,t];return[a,i,r,s].forEach((e=>{e.contains=e.contains.concat(o) +})),o=o.concat(a,i),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ +className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:o},{ +begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", +contains:o}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", +end:"\\s+",excludeEnd:!0},a,i,{className:"quote",begin:"^>\\s+",contains:o, +end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ +begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ +begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", +contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ +begin:"^[-\\*]{3,}",end:"$"},t,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ +className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ +className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}},grmr_objectivec:e=>{ +const n=/[a-zA-Z@][a-zA-Z0-9_]*/,t={$pattern:n, +keyword:["@interface","@class","@protocol","@implementation"]};return{ +name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], +keywords:{"variable.language":["this","super"],$pattern:n, +keyword:["while","export","sizeof","typedef","const","struct","for","union","volatile","static","mutable","if","do","return","goto","enum","else","break","extern","asm","case","default","register","explicit","typename","switch","continue","inline","readonly","assign","readwrite","self","@synchronized","id","typeof","nonatomic","IBOutlet","IBAction","strong","weak","copy","in","out","inout","bycopy","byref","oneway","__strong","__weak","__block","__autoreleasing","@private","@protected","@public","@try","@property","@end","@throw","@catch","@finally","@autoreleasepool","@synthesize","@dynamic","@selector","@optional","@required","@encode","@package","@import","@defs","@compatibility_alias","__bridge","__bridge_transfer","__bridge_retained","__bridge_retain","__covariant","__contravariant","__kindof","_Nonnull","_Nullable","_Null_unspecified","__FUNCTION__","__PRETTY_FUNCTION__","__attribute__","getter","setter","retain","unsafe_unretained","nonnull","nullable","null_unspecified","null_resettable","class","instancetype","NS_DESIGNATED_INITIALIZER","NS_UNAVAILABLE","NS_REQUIRES_SUPER","NS_RETURNS_INNER_POINTER","NS_INLINE","NS_AVAILABLE","NS_DEPRECATED","NS_ENUM","NS_OPTIONS","NS_SWIFT_UNAVAILABLE","NS_ASSUME_NONNULL_BEGIN","NS_ASSUME_NONNULL_END","NS_REFINED_FOR_SWIFT","NS_SWIFT_NAME","NS_SWIFT_NOTHROW","NS_DURING","NS_HANDLER","NS_ENDHANDLER","NS_VALUERETURN","NS_VOIDRETURN"], +literal:["false","true","FALSE","TRUE","nil","YES","NO","NULL"], +built_in:["dispatch_once_t","dispatch_queue_t","dispatch_sync","dispatch_async","dispatch_once"], +type:["int","float","char","unsigned","signed","short","long","double","wchar_t","unichar","void","bool","BOOL","id|0","_Bool"] +},illegal:"/,end:/$/,illegal:"\\n" +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"class", +begin:"("+t.keyword.join("|")+")\\b",end:/(\{|$)/,excludeEnd:!0,keywords:t, +contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"\\."+e.UNDERSCORE_IDENT_RE, +relevance:0}]}},grmr_perl:e=>{const n=e.regex,t=/[dualxmsipngr]{0,12}/,a={ +$pattern:/[\w.]+/, +keyword:"abs accept alarm and atan2 bind binmode bless break caller chdir chmod chomp chop chown chr chroot close closedir connect continue cos crypt dbmclose dbmopen defined delete die do dump each else elsif endgrent endhostent endnetent endprotoent endpwent endservent eof eval exec exists exit exp fcntl fileno flock for foreach fork format formline getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent getlogin getnetbyaddr getnetbyname getnetent getpeername getpgrp getpriority getprotobyname getprotobynumber getprotoent getpwent getpwnam getpwuid getservbyname getservbyport getservent getsockname getsockopt given glob gmtime goto grep gt hex if index int ioctl join keys kill last lc lcfirst length link listen local localtime log lstat lt ma map mkdir msgctl msgget msgrcv msgsnd my ne next no not oct open opendir or ord our pack package pipe pop pos print printf prototype push q|0 qq quotemeta qw qx rand read readdir readline readlink readpipe recv redo ref rename require reset return reverse rewinddir rindex rmdir say scalar seek seekdir select semctl semget semop send setgrent sethostent setnetent setpgrp setpriority setprotoent setpwent setservent setsockopt shift shmctl shmget shmread shmwrite shutdown sin sleep socket socketpair sort splice split sprintf sqrt srand stat state study sub substr symlink syscall sysopen sysread sysseek system syswrite tell telldir tie tied time times tr truncate uc ucfirst umask undef unless unlink unpack unshift untie until use utime values vec wait waitpid wantarray warn when while write x|0 xor y|0" +},i={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:a},r={begin:/->\{/, +end:/\}/},s={variants:[{begin:/\$\d/},{ +begin:n.concat(/[$%@](\^\w\b|#\w+(::\w+)*|\{\w+\}|\w+(::\w*)*)/,"(?![A-Za-z])(?![@$%])") +},{begin:/[$%@][^\s\w{]/,relevance:0}] +},o=[e.BACKSLASH_ESCAPE,i,s],l=[/!/,/\//,/\|/,/\?/,/'/,/"/,/#/],c=(e,a,i="\\1")=>{ +const r="\\1"===i?i:n.concat(i,a) +;return n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,r,/(?:\\.|[^\\\/])*?/,i,t) +},d=(e,a,i)=>n.concat(n.concat("(?:",e,")"),a,/(?:\\.|[^\\\/])*?/,i,t),g=[s,e.HASH_COMMENT_MODE,e.COMMENT(/^=\w/,/=cut/,{ +endsWithParent:!0}),r,{className:"string",contains:o,variants:[{ +begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", +end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ +begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*<",end:">", +relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", +contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", +contains:[e.BACKSLASH_ESCAPE]},{begin:/\{\w+\}/,relevance:0},{ +begin:"-?\\w+\\s*=>",relevance:0}]},{className:"number", +begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", +relevance:0},{ +begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", +keywords:"split return print reverse grep",relevance:0, +contains:[e.HASH_COMMENT_MODE,{className:"regexp",variants:[{ +begin:c("s|tr|y",n.either(...l,{capture:!0}))},{begin:c("s|tr|y","\\(","\\)")},{ +begin:c("s|tr|y","\\[","\\]")},{begin:c("s|tr|y","\\{","\\}")}],relevance:2},{ +className:"regexp",variants:[{begin:/(m|qr)\/\//,relevance:0},{ +begin:d("(?:m|qr)?",/\//,/\//)},{begin:d("m|qr",n.either(...l,{capture:!0 +}),/\1/)},{begin:d("m|qr",/\(/,/\)/)},{begin:d("m|qr",/\[/,/\]/)},{ +begin:d("m|qr",/\{/,/\}/)}]}]},{className:"function",beginKeywords:"sub", +end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ +begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", +subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] +}];return i.contains=g,r.contains=g,{name:"Perl",aliases:["pl","pm"],keywords:a, +contains:g}},grmr_php:e=>{ +const n=e.regex,t=/(?![A-Za-z0-9])(?![$])/,a=n.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,t),i=n.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,t),r={ +scope:"variable",match:"\\$+"+a},s={scope:"subst",variants:[{begin:/\$\w+/},{ +begin:/\{\$/,end:/\}/}]},o=e.inherit(e.APOS_STRING_MODE,{illegal:null +}),l="[ \t\n]",c={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ +illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(s)}),o,{ +begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, +contains:e.QUOTE_STRING_MODE.contains.concat(s),"on:begin":(e,n)=>{ +n.data._beginMatch=e[1]||e[2]},"on:end":(e,n)=>{ +n.data._beginMatch!==e[1]&&n.ignoreMatch()}},e.END_SAME_AS_BEGIN({ +begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},d={scope:"number",variants:[{ +begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ +begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ +begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" +}],relevance:0 +},g=["false","null","true"],u=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],b=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],m={ +keyword:u,literal:(e=>{const n=[];return e.forEach((e=>{ +n.push(e),e.toLowerCase()===e?n.push(e.toUpperCase()):n.push(e.toLowerCase()) +})),n})(g),built_in:b},p=e=>e.map((e=>e.replace(/\|\d+$/,""))),_={variants:[{ +match:[/new/,n.concat(l,"+"),n.concat("(?!",p(b).join("\\b|"),"\\b)"),i],scope:{ +1:"keyword",4:"title.class"}}]},h=n.concat(a,"\\b(?!\\()"),f={variants:[{ +match:[n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{2:"variable.constant" +}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ +match:[i,n.concat(/::/,n.lookahead(/(?!class\b)/)),h],scope:{1:"title.class", +3:"variable.constant"}},{match:[i,n.concat("::",n.lookahead(/(?!class\b)/))], +scope:{1:"title.class"}},{match:[i,/::/,/class/],scope:{1:"title.class", +3:"variable.language"}}]},E={scope:"attr", +match:n.concat(a,n.lookahead(":"),n.lookahead(/(?!::)/))},y={relevance:0, +begin:/\(/,end:/\)/,keywords:m,contains:[E,r,f,e.C_BLOCK_COMMENT_MODE,c,d,_] +},N={relevance:0, +match:[/\b/,n.concat("(?!fn\\b|function\\b|",p(u).join("\\b|"),"|",p(b).join("\\b|"),"\\b)"),a,n.concat(l,"*"),n.lookahead(/(?=\()/)], +scope:{3:"title.function.invoke"},contains:[y]};y.contains.push(N) +;const w=[E,f,e.C_BLOCK_COMMENT_MODE,c,d,_];return{case_insensitive:!1, +keywords:m,contains:[{begin:n.concat(/#\[\s*/,i),beginScope:"meta",end:/]/, +endScope:"meta",keywords:{literal:g,keyword:["new","array"]},contains:[{ +begin:/\[/,end:/]/,keywords:{literal:g,keyword:["new","array"]}, +contains:["self",...w]},...w,{scope:"meta",match:i}] +},e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{contains:[{ +scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, +keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, +contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ +begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ +begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},r,N,f,{ +match:[/const/,/\s/,a],scope:{1:"keyword",3:"variable.constant"}},_,{ +scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, +excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" +},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", +begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:m, +contains:["self",r,f,e.C_BLOCK_COMMENT_MODE,c,d]}]},{scope:"class",variants:[{ +beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", +illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ +beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ +beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, +contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ +beginKeywords:"use",relevance:0,end:";",contains:[{ +match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},c,d]} +},grmr_php_template:e=>({name:"PHP template",subLanguage:"xml",contains:[{ +begin:/<\?(php|=)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*", +end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 +},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null, +skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null, +contains:null,skip:!0})]}]}),grmr_plaintext:e=>({name:"Plain text", +aliases:["text","txt"],disableAutodetect:!0}),grmr_python:e=>{ +const n=e.regex,t=/[\p{XID_Start}_]\p{XID_Continue}*/u,a=["and","as","assert","async","await","break","case","class","continue","def","del","elif","else","except","finally","for","from","global","if","import","in","is","lambda","match","nonlocal|10","not","or","pass","raise","return","try","while","with","yield"],i={ +$pattern:/[A-Za-z]\w+|__\w+__/,keyword:a, +built_in:["__import__","abs","all","any","ascii","bin","bool","breakpoint","bytearray","bytes","callable","chr","classmethod","compile","complex","delattr","dict","dir","divmod","enumerate","eval","exec","filter","float","format","frozenset","getattr","globals","hasattr","hash","help","hex","id","input","int","isinstance","issubclass","iter","len","list","locals","map","max","memoryview","min","next","object","oct","open","ord","pow","print","property","range","repr","reversed","round","set","setattr","slice","sorted","staticmethod","str","sum","super","tuple","type","vars","zip"], +literal:["__debug__","Ellipsis","False","None","NotImplemented","True"], +type:["Any","Callable","Coroutine","Dict","List","Literal","Generic","Optional","Sequence","Set","Tuple","Type","Union"] +},r={className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, +end:/\}/,keywords:i,illegal:/#/},o={begin:/\{\{/,relevance:0},l={ +className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, +contains:[e.BACKSLASH_ESCAPE,r],relevance:10},{ +begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, +contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, +end:/"""/,contains:[e.BACKSLASH_ESCAPE,r,o,s]},{begin:/([uU]|[rR])'/,end:/'/, +relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ +begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, +end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, +contains:[e.BACKSLASH_ESCAPE,o,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, +contains:[e.BACKSLASH_ESCAPE,o,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] +},c="[0-9](_?[0-9])*",d=`(\\b(${c}))?\\.(${c})|\\b(${c})\\.`,g="\\b|"+a.join("|"),u={ +className:"number",relevance:0,variants:[{ +begin:`(\\b(${c})|(${d}))[eE][+-]?(${c})[jJ]?(?=${g})`},{begin:`(${d})[jJ]?`},{ +begin:`\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${g})`},{ +begin:`\\b0[bB](_?[01])+[lL]?(?=${g})`},{begin:`\\b0[oO](_?[0-7])+[lL]?(?=${g})` +},{begin:`\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${g})`},{begin:`\\b(${c})[jJ](?=${g})` +}]},b={className:"comment",begin:n.lookahead(/# type:/),end:/$/,keywords:i, +contains:[{begin:/# type:/},{begin:/#/,end:/\b\B/,endsWithParent:!0}]},m={ +className:"params",variants:[{className:"",begin:/\(\s*\)/,skip:!0},{begin:/\(/, +end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:i, +contains:["self",r,u,l,e.HASH_COMMENT_MODE]}]};return s.contains=[l,u,r],{ +name:"Python",aliases:["py","gyp","ipython"],unicodeRegex:!0,keywords:i, +illegal:/(<\/|\?)|=>/,contains:[r,u,{begin:/\bself\b/},{beginKeywords:"if", +relevance:0},l,b,e.HASH_COMMENT_MODE,{match:[/\bdef/,/\s+/,t],scope:{ +1:"keyword",3:"title.function"},contains:[m]},{variants:[{ +match:[/\bclass/,/\s+/,t,/\s*/,/\(\s*/,t,/\s*\)/]},{match:[/\bclass/,/\s+/,t]}], +scope:{1:"keyword",3:"title.class",6:"title.class.inherited"}},{ +className:"meta",begin:/^[\t ]*@/,end:/(?=#)|$/,contains:[u,m,l]}]}}, +grmr_python_repl:e=>({aliases:["pycon"],contains:[{className:"meta.prompt", +starts:{end:/ |$/,starts:{end:"$",subLanguage:"python"}},variants:[{ +begin:/^>>>(?=[ ]|$)/},{begin:/^\.\.\.(?=[ ]|$)/}]}]}),grmr_r:e=>{ +const n=e.regex,t=/(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/,a=n.either(/0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,/0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,/(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/),i=/[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/,r=n.either(/[()]/,/[{}]/,/\[\[/,/[[\]]/,/\\/,/,/) +;return{name:"R",keywords:{$pattern:t, +keyword:"function if in break next repeat else for while", +literal:"NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10", +built_in:"LETTERS letters month.abb month.name pi T F abs acos acosh all any anyNA Arg as.call as.character as.complex as.double as.environment as.integer as.logical as.null.default as.numeric as.raw asin asinh atan atanh attr attributes baseenv browser c call ceiling class Conj cos cosh cospi cummax cummin cumprod cumsum digamma dim dimnames emptyenv exp expression floor forceAndCall gamma gc.time globalenv Im interactive invisible is.array is.atomic is.call is.character is.complex is.double is.environment is.expression is.finite is.function is.infinite is.integer is.language is.list is.logical is.matrix is.na is.name is.nan is.null is.numeric is.object is.pairlist is.raw is.recursive is.single is.symbol lazyLoadDBfetch length lgamma list log max min missing Mod names nargs nzchar oldClass on.exit pos.to.env proc.time prod quote range Re rep retracemem return round seq_along seq_len seq.int sign signif sin sinh sinpi sqrt standardGeneric substitute sum switch tan tanh tanpi tracemem trigamma trunc unclass untracemem UseMethod xtfrm" +},contains:[e.COMMENT(/#'/,/$/,{contains:[{scope:"doctag",match:/@examples/, +starts:{end:n.lookahead(n.either(/\n^#'\s*(?=@[a-zA-Z]+)/,/\n^(?!#')/)), +endsParent:!0}},{scope:"doctag",begin:"@param",end:/$/,contains:[{ +scope:"variable",variants:[{match:t},{match:/`(?:\\.|[^`\\])+`/}],endsParent:!0 +}]},{scope:"doctag",match:/@[a-zA-Z]+/},{scope:"keyword",match:/\\[a-zA-Z]+/}] +}),e.HASH_COMMENT_MODE,{scope:"string",contains:[e.BACKSLASH_ESCAPE], +variants:[e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\(/,end:/\)(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\{/,end:/\}(-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]"(-*)\[/,end:/\](-*)"/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\(/,end:/\)(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\{/,end:/\}(-*)'/ +}),e.END_SAME_AS_BEGIN({begin:/[rR]'(-*)\[/,end:/\](-*)'/}),{begin:'"',end:'"', +relevance:0},{begin:"'",end:"'",relevance:0}]},{relevance:0,variants:[{scope:{ +1:"operator",2:"number"},match:[i,a]},{scope:{1:"operator",2:"number"}, +match:[/%[^%]*%/,a]},{scope:{1:"punctuation",2:"number"},match:[r,a]},{scope:{ +2:"number"},match:[/[^a-zA-Z0-9._]|^/,a]}]},{scope:{3:"operator"}, +match:[t,/\s+/,/<-/,/\s+/]},{scope:"operator",relevance:0,variants:[{match:i},{ +match:/%[^%]*%/}]},{scope:"punctuation",relevance:0,match:r},{begin:"`",end:"`", +contains:[{begin:/\\./}]}]}},grmr_ruby:e=>{ +const n=e.regex,t="([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)",a=n.either(/\b([A-Z]+[a-z0-9]+)+/,/\b([A-Z]+[a-z0-9]+)+[A-Z]+/),i=n.concat(a,/(::\w+)*/),r={ +"variable.constant":["__FILE__","__LINE__","__ENCODING__"], +"variable.language":["self","super"], +keyword:["alias","and","begin","BEGIN","break","case","class","defined","do","else","elsif","end","END","ensure","for","if","in","module","next","not","or","redo","require","rescue","retry","return","then","undef","unless","until","when","while","yield","include","extend","prepend","public","private","protected","raise","throw"], +built_in:["proc","lambda","attr_accessor","attr_reader","attr_writer","define_method","private_constant","module_function"], +literal:["true","false","nil"]},s={className:"doctag",begin:"@[A-Za-z]+"},o={ +begin:"#<",end:">"},l=[e.COMMENT("#","$",{contains:[s] +}),e.COMMENT("^=begin","^=end",{contains:[s],relevance:10 +}),e.COMMENT("^__END__",e.MATCH_NOTHING_RE)],c={className:"subst",begin:/#\{/, +end:/\}/,keywords:r},d={className:"string",contains:[e.BACKSLASH_ESCAPE,c], +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ +begin:/%[qQwWx]?\(/,end:/\)/},{begin:/%[qQwWx]?\[/,end:/\]/},{ +begin:/%[qQwWx]?\{/,end:/\}/},{begin:/%[qQwWx]?/},{begin:/%[qQwWx]?\//, +end:/\//},{begin:/%[qQwWx]?%/,end:/%/},{begin:/%[qQwWx]?-/,end:/-/},{ +begin:/%[qQwWx]?\|/,end:/\|/},{begin:/\B\?(\\\d{1,3})/},{ +begin:/\B\?(\\x[A-Fa-f0-9]{1,2})/},{begin:/\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/},{ +begin:/\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/},{ +begin:/\B\?\\(c|C-)[\x20-\x7e]/},{begin:/\B\?\\?\S/},{ +begin:n.concat(/<<[-~]?'?/,n.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)), +contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, +contains:[e.BACKSLASH_ESCAPE,c]})]}]},g="[0-9](_?[0-9])*",u={className:"number", +relevance:0,variants:[{ +begin:`\\b([1-9](_?[0-9])*|0)(\\.(${g}))?([eE][+-]?(${g})|r)?i?\\b`},{ +begin:"\\b0[dD][0-9](_?[0-9])*r?i?\\b"},{begin:"\\b0[bB][0-1](_?[0-1])*r?i?\\b" +},{begin:"\\b0[oO][0-7](_?[0-7])*r?i?\\b"},{ +begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b"},{ +begin:"\\b0(_?[0-7])+r?i?\\b"}]},b={variants:[{match:/\(\)/},{ +className:"params",begin:/\(/,end:/(?=\))/,excludeBegin:!0,endsParent:!0, +keywords:r}]},m=[d,{variants:[{match:[/class\s+/,i,/\s+<\s+/,i]},{ +match:[/\b(class|module)\s+/,i]}],scope:{2:"title.class", +4:"title.class.inherited"},keywords:r},{match:[/(include|extend)\s+/,i],scope:{ +2:"title.class"},keywords:r},{relevance:0,match:[i,/\.new[. (]/],scope:{ +1:"title.class"}},{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, +className:"variable.constant"},{relevance:0,match:a,scope:"title.class"},{ +match:[/def/,/\s+/,t],scope:{1:"keyword",3:"title.function"},contains:[b]},{ +begin:e.IDENT_RE+"::"},{className:"symbol", +begin:e.UNDERSCORE_IDENT_RE+"(!|\\?)?:",relevance:0},{className:"symbol", +begin:":(?!\\s)",contains:[d,{begin:t}],relevance:0},u,{className:"variable", +begin:"(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])(?![A-Za-z])(?![@$?'])"},{ +className:"params",begin:/\|/,end:/\|/,excludeBegin:!0,excludeEnd:!0, +relevance:0,keywords:r},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", +keywords:"unless",contains:[{className:"regexp",contains:[e.BACKSLASH_ESCAPE,c], +illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*"},{begin:/%r\{/,end:/\}[a-z]*/},{ +begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!",end:"![a-z]*"},{begin:"%r\\[", +end:"\\][a-z]*"}]}].concat(o,l),relevance:0}].concat(o,l) +;c.contains=m,b.contains=m;const p=[{begin:/^\s*=>/,starts:{end:"$",contains:m} +},{className:"meta.prompt", +begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]|(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>)(?=[ ])", +starts:{end:"$",keywords:r,contains:m}}];return l.unshift(o),{name:"Ruby", +aliases:["rb","gemspec","podspec","thor","irb"],keywords:r,illegal:/\/\*/, +contains:[e.SHEBANG({binary:"ruby"})].concat(p).concat(l).concat(m)}}, +grmr_rust:e=>{const n=e.regex,t={className:"title.function.invoke",relevance:0, +begin:n.concat(/\b/,/(?!let|for|while|if|else|match\b)/,e.IDENT_RE,n.lookahead(/\s*\(/)) +},a="([ui](8|16|32|64|128|size)|f(32|64))?",i=["drop ","Copy","Send","Sized","Sync","Drop","Fn","FnMut","FnOnce","ToOwned","Clone","Debug","PartialEq","PartialOrd","Eq","Ord","AsRef","AsMut","Into","From","Default","Iterator","Extend","IntoIterator","DoubleEndedIterator","ExactSizeIterator","SliceConcatExt","ToString","assert!","assert_eq!","bitflags!","bytes!","cfg!","col!","concat!","concat_idents!","debug_assert!","debug_assert_eq!","env!","eprintln!","panic!","file!","format!","format_args!","include_bytes!","include_str!","line!","local_data_key!","module_path!","option_env!","print!","println!","select!","stringify!","try!","unimplemented!","unreachable!","vec!","write!","writeln!","macro_rules!","assert_ne!","debug_assert_ne!"],r=["i8","i16","i32","i64","i128","isize","u8","u16","u32","u64","u128","usize","f32","f64","str","char","bool","Box","Option","Result","String","Vec"] +;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?",type:r, +keyword:["abstract","as","async","await","become","box","break","const","continue","crate","do","dyn","else","enum","extern","false","final","fn","for","if","impl","in","let","loop","macro","match","mod","move","mut","override","priv","pub","ref","return","self","Self","static","struct","super","trait","true","try","type","typeof","unsafe","unsized","use","virtual","where","while","yield"], +literal:["true","false","Some","None","Ok","Err"],built_in:i},illegal:""},t]}}, +grmr_scss:e=>{const n=ie(e),t=le,a=oe,i="@[a-z-]+",r={className:"variable", +begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b",relevance:0};return{name:"SCSS", +case_insensitive:!0,illegal:"[=/|']", +contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,n.CSS_NUMBER_MODE,{ +className:"selector-id",begin:"#[A-Za-z0-9_-]+",relevance:0},{ +className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0 +},n.ATTRIBUTE_SELECTOR_MODE,{className:"selector-tag", +begin:"\\b("+re.join("|")+")\\b",relevance:0},{className:"selector-pseudo", +begin:":("+a.join("|")+")"},{className:"selector-pseudo", +begin:":(:)?("+t.join("|")+")"},r,{begin:/\(/,end:/\)/, +contains:[n.CSS_NUMBER_MODE]},n.CSS_VARIABLE,{className:"attribute", +begin:"\\b("+ce.join("|")+")\\b"},{ +begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" +},{begin:/:/,end:/[;}{]/,relevance:0, +contains:[n.BLOCK_COMMENT,r,n.HEXCOLOR,n.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.IMPORTANT,n.FUNCTION_DISPATCH] +},{begin:"@(page|font-face)",keywords:{$pattern:i,keyword:"@page @font-face"}},{ +begin:"@",end:"[{;]",returnBegin:!0,keywords:{$pattern:/[a-z-]+/, +keyword:"and or not only",attribute:se.join(" ")},contains:[{begin:i, +className:"keyword"},{begin:/[a-z-]+(?=:)/,className:"attribute" +},r,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,n.HEXCOLOR,n.CSS_NUMBER_MODE] +},n.FUNCTION_DISPATCH]}},grmr_shell:e=>({name:"Shell Session", +aliases:["console","shellsession"],contains:[{className:"meta.prompt", +begin:/^\s{0,3}[/~\w\d[\]()@-]*[>%$#][ ]?/,starts:{end:/[^\\](?=\s*$)/, +subLanguage:"bash"}}]}),grmr_sql:e=>{ +const n=e.regex,t=e.COMMENT("--","$"),a=["true","false","unknown"],i=["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"],r=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],s=["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"],o=r,l=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!r.includes(e))),c={ +begin:n.concat(/\b/,n.either(...o),/\s*\(/),relevance:0,keywords:{built_in:o}} +;return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ +$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:n,when:t}={})=>{const a=t +;return n=n||[],e.map((e=>e.match(/\|\d+$/)||n.includes(e)?e:a(e)?e+"|0":e)) +})(l,{when:e=>e.length<3}),literal:a,type:i, +built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] +},contains:[{begin:n.either(...s),relevance:0,keywords:{$pattern:/[\w\.]+/, +keyword:l.concat(s),literal:a,type:i}},{className:"type", +begin:n.either("double precision","large object","with timezone","without timezone") +},c,{className:"variable",begin:/@[a-z0-9][a-z0-9_]*/},{className:"string", +variants:[{begin:/'/,end:/'/,contains:[{begin:/''/}]}]},{begin:/"/,end:/"/, +contains:[{begin:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{ +className:"operator",begin:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, +relevance:0}]}},grmr_swift:e=>{const n={match:/\s+/,relevance:0 +},t=e.COMMENT("/\\*","\\*/",{contains:["self"]}),a=[e.C_LINE_COMMENT_MODE,t],i={ +match:[/\./,m(...xe,...Me)],className:{2:"keyword"}},r={match:b(/\./,m(...Ae)), +relevance:0},s=Ae.filter((e=>"string"==typeof e)).concat(["_|0"]),o={variants:[{ +className:"keyword", +match:m(...Ae.filter((e=>"string"!=typeof e)).concat(Se).map(ke),...Me)}]},l={ +$pattern:m(/\b\w+/,/#\w+/),keyword:s.concat(Re),literal:Ce},c=[i,r,o],g=[{ +match:b(/\./,m(...De)),relevance:0},{className:"built_in", +match:b(/\b/,m(...De),/(?=\()/)}],u={match:/->/,relevance:0},p=[u,{ +className:"operator",relevance:0,variants:[{match:Be},{match:`\\.(\\.|${Le})+`}] +}],_="([0-9]_*)+",h="([0-9a-fA-F]_*)+",f={className:"number",relevance:0, +variants:[{match:`\\b(${_})(\\.(${_}))?([eE][+-]?(${_}))?\\b`},{ +match:`\\b0x(${h})(\\.(${h}))?([pP][+-]?(${_}))?\\b`},{match:/\b0o([0-7]_*)+\b/ +},{match:/\b0b([01]_*)+\b/}]},E=(e="")=>({className:"subst",variants:[{ +match:b(/\\/,e,/[0\\tnr"']/)},{match:b(/\\/,e,/u\{[0-9a-fA-F]{1,8}\}/)}] +}),y=(e="")=>({className:"subst",match:b(/\\/,e,/[\t ]*(?:[\r\n]|\r\n)/) +}),N=(e="")=>({className:"subst",label:"interpol",begin:b(/\\/,e,/\(/),end:/\)/ +}),w=(e="")=>({begin:b(e,/"""/),end:b(/"""/,e),contains:[E(e),y(e),N(e)] +}),v=(e="")=>({begin:b(e,/"/),end:b(/"/,e),contains:[E(e),N(e)]}),O={ +className:"string", +variants:[w(),w("#"),w("##"),w("###"),v(),v("#"),v("##"),v("###")] +},k=[e.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0, +contains:[e.BACKSLASH_ESCAPE]}],x={begin:/\/[^\s](?=[^/\n]*\/)/,end:/\//, +contains:k},M=e=>{const n=b(e,/\//),t=b(/\//,e);return{begin:n,end:t, +contains:[...k,{scope:"comment",begin:`#(?!.*${t})`,end:/$/}]}},S={ +scope:"regexp",variants:[M("###"),M("##"),M("#"),x]},A={match:b(/`/,Fe,/`/) +},C=[A,{className:"variable",match:/\$\d+/},{className:"variable", +match:`\\$${ze}+`}],T=[{match:/(@|#(un)?)available/,scope:"keyword",starts:{ +contains:[{begin:/\(/,end:/\)/,keywords:Pe,contains:[...p,f,O]}]}},{ +scope:"keyword",match:b(/@/,m(...je))},{scope:"meta",match:b(/@/,Fe)}],R={ +match:d(/\b[A-Z]/),relevance:0,contains:[{className:"type", +match:b(/(AV|CA|CF|CG|CI|CL|CM|CN|CT|MK|MP|MTK|MTL|NS|SCN|SK|UI|WK|XC)/,ze,"+") +},{className:"type",match:Ue,relevance:0},{match:/[?!]+/,relevance:0},{ +match:/\.\.\./,relevance:0},{match:b(/\s+&\s+/,d(Ue)),relevance:0}]},D={ +begin://,keywords:l,contains:[...a,...c,...T,u,R]};R.contains.push(D) +;const I={begin:/\(/,end:/\)/,relevance:0,keywords:l,contains:["self",{ +match:b(Fe,/\s*:/),keywords:"_|0",relevance:0 +},...a,S,...c,...g,...p,f,O,...C,...T,R]},L={begin://, +keywords:"repeat each",contains:[...a,R]},B={begin:/\(/,end:/\)/,keywords:l, +contains:[{begin:m(d(b(Fe,/\s*:/)),d(b(Fe,/\s+/,Fe,/\s*:/))),end:/:/, +relevance:0,contains:[{className:"keyword",match:/\b_\b/},{className:"params", +match:Fe}]},...a,...c,...p,f,O,...T,R,I],endsParent:!0,illegal:/["']/},$={ +match:[/(func|macro)/,/\s+/,m(A.match,Fe,Be)],className:{1:"keyword", +3:"title.function"},contains:[L,B,n],illegal:[/\[/,/%/]},z={ +match:[/\b(?:subscript|init[?!]?)/,/\s*(?=[<(])/],className:{1:"keyword"}, +contains:[L,B,n],illegal:/\[|%/},F={match:[/operator/,/\s+/,Be],className:{ +1:"keyword",3:"title"}},U={begin:[/precedencegroup/,/\s+/,Ue],className:{ +1:"keyword",3:"title"},contains:[R],keywords:[...Te,...Ce],end:/}/} +;for(const e of O.variants){const n=e.contains.find((e=>"interpol"===e.label)) +;n.keywords=l;const t=[...c,...g,...p,f,O,...C];n.contains=[...t,{begin:/\(/, +end:/\)/,contains:["self",...t]}]}return{name:"Swift",keywords:l, +contains:[...a,$,z,{beginKeywords:"struct protocol class extension enum actor", +end:"\\{",excludeEnd:!0,keywords:l,contains:[e.inherit(e.TITLE_MODE,{ +className:"title.class",begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/}),...c] +},F,U,{beginKeywords:"import",end:/$/,contains:[...a],relevance:0 +},S,...c,...g,...p,f,O,...C,...T,R,I]}},grmr_typescript:e=>{ +const n=Oe(e),t=_e,a=["any","void","number","boolean","string","object","never","symbol","bigint","unknown"],i={ +beginKeywords:"namespace",end:/\{/,excludeEnd:!0, +contains:[n.exports.CLASS_REFERENCE]},r={beginKeywords:"interface",end:/\{/, +excludeEnd:!0,keywords:{keyword:"interface extends",built_in:a}, +contains:[n.exports.CLASS_REFERENCE]},s={$pattern:_e, +keyword:he.concat(["type","namespace","interface","public","private","protected","implements","declare","abstract","readonly","enum","override"]), +literal:fe,built_in:ve.concat(a),"variable.language":we},o={className:"meta", +begin:"@"+t},l=(e,n,t)=>{const a=e.contains.findIndex((e=>e.label===n)) +;if(-1===a)throw Error("can not find mode to replace");e.contains.splice(a,1,t)} +;return Object.assign(n.keywords,s), +n.exports.PARAMS_CONTAINS.push(o),n.contains=n.contains.concat([o,i,r]), +l(n,"shebang",e.SHEBANG()),l(n,"use_strict",{className:"meta",relevance:10, +begin:/^\s*['"]use strict['"]/ +}),n.contains.find((e=>"func.def"===e.label)).relevance=0,Object.assign(n,{ +name:"TypeScript",aliases:["ts","tsx","mts","cts"]}),n},grmr_vbnet:e=>{ +const n=e.regex,t=/\d{1,2}\/\d{1,2}\/\d{4}/,a=/\d{4}-\d{1,2}-\d{1,2}/,i=/(\d|1[012])(:\d+){0,2} *(AM|PM)/,r=/\d{1,2}(:\d{1,2}){1,2}/,s={ +className:"literal",variants:[{begin:n.concat(/# */,n.either(a,t),/ *#/)},{ +begin:n.concat(/# */,r,/ *#/)},{begin:n.concat(/# */,i,/ *#/)},{ +begin:n.concat(/# */,n.either(a,t),/ +/,n.either(i,r),/ *#/)}] +},o=e.COMMENT(/'''/,/$/,{contains:[{className:"doctag",begin:/<\/?/,end:/>/}] +}),l=e.COMMENT(null,/$/,{variants:[{begin:/'/},{begin:/([\t ]|^)REM(?=\s)/}]}) +;return{name:"Visual Basic .NET",aliases:["vb"],case_insensitive:!0, +classNameAliases:{label:"symbol"},keywords:{ +keyword:"addhandler alias aggregate ansi as async assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into iterator join key let lib loop me mid module mustinherit mustoverride mybase myclass namespace narrowing new next notinheritable notoverridable of off on operator option optional order overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly yield", +built_in:"addressof and andalso await directcast gettype getxmlnamespace is isfalse isnot istrue like mod nameof new not or orelse trycast typeof xor cbool cbyte cchar cdate cdbl cdec cint clng cobj csbyte cshort csng cstr cuint culng cushort", +type:"boolean byte char date decimal double integer long object sbyte short single string uinteger ulong ushort", +literal:"true false nothing"}, +illegal:"//|\\{|\\}|endif|gosub|variant|wend|^\\$ ",contains:[{ +className:"string",begin:/"(""|[^/n])"C\b/},{className:"string",begin:/"/, +end:/"/,illegal:/\n/,contains:[{begin:/""/}]},s,{className:"number",relevance:0, +variants:[{begin:/\b\d[\d_]*((\.[\d_]+(E[+-]?[\d_]+)?)|(E[+-]?[\d_]+))[RFD@!#]?/ +},{begin:/\b\d[\d_]*((U?[SIL])|[%&])?/},{begin:/&H[\dA-F_]+((U?[SIL])|[%&])?/},{ +begin:/&O[0-7_]+((U?[SIL])|[%&])?/},{begin:/&B[01_]+((U?[SIL])|[%&])?/}]},{ +className:"label",begin:/^\w+:/},o,l,{className:"meta", +begin:/[\t ]*#(const|disable|else|elseif|enable|end|externalsource|if|region)\b/, +end:/$/,keywords:{ +keyword:"const disable else elseif enable end externalsource if region then"}, +contains:[l]}]}},grmr_wasm:e=>{e.regex;const n=e.COMMENT(/\(;/,/;\)/) +;return n.contains.push("self"),{name:"WebAssembly",keywords:{$pattern:/[\w.]+/, +keyword:["anyfunc","block","br","br_if","br_table","call","call_indirect","data","drop","elem","else","end","export","func","global.get","global.set","local.get","local.set","local.tee","get_global","get_local","global","if","import","local","loop","memory","memory.grow","memory.size","module","mut","nop","offset","param","result","return","select","set_global","set_local","start","table","tee_local","then","type","unreachable"] +},contains:[e.COMMENT(/;;/,/$/),n,{match:[/(?:offset|align)/,/\s*/,/=/], +className:{1:"keyword",3:"operator"}},{className:"variable",begin:/\$[\w_]+/},{ +match:/(\((?!;)|\))+/,className:"punctuation",relevance:0},{ +begin:[/(?:func|call|call_indirect)/,/\s+/,/\$[^\s)]+/],className:{1:"keyword", +3:"title.function"}},e.QUOTE_STRING_MODE,{match:/(i32|i64|f32|f64)(?!\.)/, +className:"type"},{className:"keyword", +match:/\b(f32|f64|i32|i64)(?:\.(?:abs|add|and|ceil|clz|const|convert_[su]\/i(?:32|64)|copysign|ctz|demote\/f64|div(?:_[su])?|eqz?|extend_[su]\/i32|floor|ge(?:_[su])?|gt(?:_[su])?|le(?:_[su])?|load(?:(?:8|16|32)_[su])?|lt(?:_[su])?|max|min|mul|nearest|neg?|or|popcnt|promote\/f32|reinterpret\/[fi](?:32|64)|rem_[su]|rot[lr]|shl|shr_[su]|store(?:8|16|32)?|sqrt|sub|trunc(?:_[su]\/f(?:32|64))?|wrap\/i64|xor))\b/ +},{className:"number",relevance:0, +match:/[+-]?\b(?:\d(?:_?\d)*(?:\.\d(?:_?\d)*)?(?:[eE][+-]?\d(?:_?\d)*)?|0x[\da-fA-F](?:_?[\da-fA-F])*(?:\.[\da-fA-F](?:_?[\da-fA-D])*)?(?:[pP][+-]?\d(?:_?\d)*)?)\b|\binf\b|\bnan(?::0x[\da-fA-F](?:_?[\da-fA-D])*)?\b/ +}]}},grmr_xml:e=>{ +const n=e.regex,t=n.concat(/[\p{L}_]/u,n.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),a={ +className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},i={begin:/\s/, +contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] +},r=e.inherit(i,{begin:/\(/,end:/\)/}),s=e.inherit(e.APOS_STRING_MODE,{ +className:"string"}),o=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),l={ +endsWithParent:!0,illegal:/`]+/}]}]}]};return{ +name:"HTML, XML", +aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], +case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin://,relevance:10,contains:[i,o,s,r,{begin:/\[/,end:/\]/,contains:[{ +className:"meta",begin://,contains:[i,r,o,s]}]}] +},e.COMMENT(//,{relevance:10}),{begin://, +relevance:10},a,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, +relevance:10,contains:[o]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"style"},contains:[l],starts:{ +end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", +begin:/)/,end:/>/,keywords:{name:"script"},contains:[l],starts:{ +end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ +className:"tag",begin:/<>|<\/>/},{className:"tag", +begin:n.concat(//,/>/,/\s/)))), +end:/\/?>/,contains:[{className:"name",begin:t,relevance:0,starts:l}]},{ +className:"tag",begin:n.concat(/<\//,n.lookahead(n.concat(t,/>/))),contains:[{ +className:"name",begin:t,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]} +},grmr_yaml:e=>{ +const n="true false yes no null",t="[\\w#;/?:@&=+$,.~*'()[\\]]+",a={ +className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ +},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", +variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},i=e.inherit(a,{ +variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),r={ +end:",",endsWithParent:!0,excludeEnd:!0,keywords:n,relevance:0},s={begin:/\{/, +end:/\}/,contains:[r],illegal:"\\n",relevance:0},o={begin:"\\[",end:"\\]", +contains:[r],illegal:"\\n",relevance:0},l=[{className:"attr",variants:[{ +begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{ +begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$", +relevance:10},{className:"string", +begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{ +begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, +relevance:0},{className:"type",begin:"!\\w+!"+t},{className:"type", +begin:"!<"+t+">"},{className:"type",begin:"!"+t},{className:"type",begin:"!!"+t +},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", +begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)", +relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ +className:"number", +begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" +},{className:"number",begin:e.C_NUMBER_RE+"\\b",relevance:0},s,o,a],c=[...l] +;return c.pop(),c.push(i),r.contains=c,{name:"YAML",case_insensitive:!0, +aliases:["yml"],contains:l}}});const He=ae;for(const e of Object.keys(Ke)){ +const n=e.replace("grmr_","").replace("_","-");He.registerLanguage(n,Ke[e])} +return He}() +;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); \ No newline at end of file diff --git a/static/public/js/index.js b/static/public/js/index.js index 15c6706..bb560ed 100644 --- a/static/public/js/index.js +++ b/static/public/js/index.js @@ -1,16 +1,30 @@ /* index.js — 社区首页逻辑 * * 登录态检测:POST /whoami(HttpOnly q4_token Cookie 自动携带,JS 不经手 Token) - * 已登录:显示用户名与"进入笔记/退出"按钮;未登录:显示"登录/注册" + * 已登录:显示头像/用户名与"进入笔记/退出"按钮,首屏 CTA 指向笔记页 + * 未登录:显示"登录/注册",首屏 CTA 指向登录页 */ (function () { 'use strict'; const nameEl = document.getElementById('name'); + const avatarEl = document.getElementById('avatar'); const enterBtn = document.getElementById('enterBtn'); const logoutBtn = document.getElementById('logoutBtn'); const loginBtn = document.getElementById('loginBtn'); const registerBtn = document.getElementById('registerBtn'); + const ctaBtn = document.getElementById('ctaBtn'); + const logoEl = document.getElementById('logo'); + + let loggedIn = false; + + function go(url) { window.location.href = url; } + + logoEl.addEventListener('click', () => go('index.html')); + enterBtn.addEventListener('click', () => go('dnfs.html')); + loginBtn.addEventListener('click', () => go('login.html')); + registerBtn.addEventListener('click', () => go('register.html')); + ctaBtn.addEventListener('click', () => go(loggedIn ? 'dnfs.html' : 'login.html')); async function checkLogin() { try { @@ -18,11 +32,15 @@ if (!res.ok) return; const data = await res.json(); if (data && data.login && data.user) { + loggedIn = true; nameEl.textContent = String(data.user); + nameEl.style.display = ''; + avatarEl.style.display = ''; enterBtn.style.display = ''; logoutBtn.style.display = ''; loginBtn.style.display = 'none'; registerBtn.style.display = 'none'; + ctaBtn.textContent = '进入我的知识树'; } } catch (e) { console.warn('index: 登录态检测失败', e.message); diff --git a/static/public/js/token_manager.js b/static/public/js/token_manager.js index 48c0f1e..5224484 100644 --- a/static/public/js/token_manager.js +++ b/static/public/js/token_manager.js @@ -26,8 +26,9 @@ async function estimateExpiry() { const data = await res.json(); if (!data.login) return false; - // 优先 iat(首次签发时间,刷新不变),回退 created_at(兼容旧 Token) - const issueStr = data.iat || data.created_at; + // 优先 created_at(刷新时更新),回退 iat(兼容旧 Token) + // 网关以 created_at + keep_time 判定令牌有效性,iat 刷新后不变,不能用于估算过期 + const issueStr = data.created_at || data.iat; const keepTime = data.keep_time; if (!issueStr || !keepTime) return false;